summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore8
-rw-r--r--BUGS.txt6
-rw-r--r--CMakeLists.txt108
-rw-r--r--DEBUG.txt8
-rw-r--r--README.txt85
-rw-r--r--angdos.cfg634
-rw-r--r--changes.old6027
-rw-r--r--changes.txt198
-rw-r--r--credits.txt67
-rw-r--r--debian/NEWS.Debian111
-rw-r--r--debian/README.debian12
-rwxr-xr-xdebian/Tome.sh70
-rw-r--r--debian/Xresources166
-rw-r--r--debian/changelog735
-rw-r--r--debian/compat1
-rw-r--r--debian/control59
-rw-r--r--debian/copyright98
-rw-r--r--debian/patches/0001-debcherry-fixup-patch.patch80
-rw-r--r--debian/patches/0002-Fix-code-which-needed-a-32-bit-int-to-not-use-int-lo.patch58
-rw-r--r--debian/patches/0003-debian-cmake-fixes-Change-install-paths-to-FHS-compl.patch63
-rw-r--r--debian/patches/series4
-rwxr-xr-xdebian/postinst253
-rwxr-xr-xdebian/postrm175
-rwxr-xr-xdebian/preinst103
-rwxr-xr-xdebian/prerm133
-rwxr-xr-xdebian/rules87
-rw-r--r--debian/source/format1
-rw-r--r--debian/tome.docs3
-rw-r--r--debian/tome.menu90
-rw-r--r--debian/watch5
-rw-r--r--lib/CMakeLists.txt25
-rw-r--r--lib/apex/.cvsignore1
-rw-r--r--lib/apex/delete.me1
-rw-r--r--lib/cmov/delete.me1
-rw-r--r--lib/core/auto.lua859
-rw-r--r--lib/core/building.lua15
-rw-r--r--lib/core/crpt_aux.lua182
-rw-r--r--lib/core/dungeon.lua55
-rw-r--r--lib/core/gen_idx.lua261
-rw-r--r--lib/core/gods.lua40
-rw-r--r--lib/core/help.lua141
-rw-r--r--lib/core/init.lua83
-rw-r--r--lib/core/load.lua37
-rw-r--r--lib/core/load2.lua56
-rw-r--r--lib/core/mimc_aux.lua96
-rw-r--r--lib/core/monsters.lua16
-rw-r--r--lib/core/objects.lua45
-rw-r--r--lib/core/player.lua135
-rw-r--r--lib/core/quests.lua57
-rw-r--r--lib/core/s_aux.lua716
-rw-r--r--lib/core/stores.lua32
-rw-r--r--lib/core/util.lua158
-rw-r--r--lib/core/xml.lua375
-rw-r--r--lib/data/.cvsignore2
-rw-r--r--lib/data/delete.me0
-rw-r--r--lib/dngn/dun1.142
-rw-r--r--lib/dngn/dun10.03
-rw-r--r--lib/dngn/dun11.202
-rw-r--r--lib/dngn/dun11.222
-rw-r--r--lib/dngn/dun17.155
-rw-r--r--lib/dngn/dun18.02
-rw-r--r--lib/dngn/dun18.12
-rw-r--r--lib/dngn/dun19.115
-rw-r--r--lib/dngn/dun2.312
-rw-r--r--lib/dngn/dun22.102
-rw-r--r--lib/dngn/dun22.55
-rw-r--r--lib/dngn/dun24.03
-rw-r--r--lib/dngn/dun29.156
-rw-r--r--lib/dngn/dun3.185
-rw-r--r--lib/dngn/dun3.285
-rw-r--r--lib/dngn/dun3.35
-rw-r--r--lib/dngn/dun5.03
-rw-r--r--lib/dngn/dun5.1414
-rw-r--r--lib/dngn/dun6.03
-rw-r--r--lib/edit/a_info.txt2889
-rw-r--r--lib/edit/ab_info.txt118
-rw-r--r--lib/edit/al_info.txt2097
-rw-r--r--lib/edit/ba_info.txt283
-rw-r--r--lib/edit/between.map71
-rw-r--r--lib/edit/d_info.txt512
-rw-r--r--lib/edit/dragons.map43
-rw-r--r--lib/edit/e_info.txt2210
-rw-r--r--lib/edit/evil.map52
-rw-r--r--lib/edit/f_info.txt941
-rw-r--r--lib/edit/fireprof.map60
-rw-r--r--lib/edit/haunted.map49
-rw-r--r--lib/edit/k_info.txt6418
-rw-r--r--lib/edit/library.map62
-rw-r--r--lib/edit/maeglin.map85
-rw-r--r--lib/edit/misc.txt91
-rw-r--r--lib/edit/nirnaeth.map64
-rw-r--r--lib/edit/numenor.txt80
-rw-r--r--lib/edit/ow_info.txt447
-rw-r--r--lib/edit/p_info.txt1974
-rw-r--r--lib/edit/qrand1.map32
-rw-r--r--lib/edit/qrand10.map36
-rw-r--r--lib/edit/qrand11.map36
-rw-r--r--lib/edit/qrand12.map36
-rw-r--r--lib/edit/qrand14.map37
-rw-r--r--lib/edit/qrand5.map27
-rw-r--r--lib/edit/qrand6.map37
-rw-r--r--lib/edit/qrand7.map35
-rw-r--r--lib/edit/r_info.txt18978
-rw-r--r--lib/edit/ra_info.txt1927
-rw-r--r--lib/edit/re_info.txt183
-rw-r--r--lib/edit/readme.txt96
-rw-r--r--lib/edit/s_crypt.map109
-rw-r--r--lib/edit/s_death.map104
-rw-r--r--lib/edit/s_doom.map226
-rwxr-xr-xlib/edit/s_factory.map238
-rw-r--r--lib/edit/s_gates.map117
-rw-r--r--lib/edit/s_info.txt546
-rw-r--r--lib/edit/s_name.map110
-rw-r--r--lib/edit/s_orc.map109
-rwxr-xr-xlib/edit/s_ship.map239
-rw-r--r--lib/edit/set_info.txt77
-rw-r--r--lib/edit/special.txt67
-rw-r--r--lib/edit/spiders.map66
-rw-r--r--lib/edit/st_info.txt744
-rw-r--r--lib/edit/t_basic.txt80
-rw-r--r--lib/edit/t_bree.txt131
-rw-r--r--lib/edit/t_d_bree.txt101
-rw-r--r--lib/edit/t_d_gond.txt118
-rw-r--r--lib/edit/t_d_khaz.txt87
-rw-r--r--lib/edit/t_d_lori.txt101
-rw-r--r--lib/edit/t_d_mina.txt91
-rw-r--r--lib/edit/t_gondol.txt219
-rw-r--r--lib/edit/t_info.txt41
-rw-r--r--lib/edit/t_khazad.txt105
-rw-r--r--lib/edit/t_lorien.txt162
-rw-r--r--lib/edit/t_minas.txt144
-rw-r--r--lib/edit/t_pref.txt111
-rw-r--r--lib/edit/thieves.map70
-rw-r--r--lib/edit/thrain.map35
-rw-r--r--lib/edit/tr_info.txt817
-rw-r--r--lib/edit/trolls.map58
-rw-r--r--lib/edit/v_info.txt2287
-rw-r--r--lib/edit/volcano.txt83
-rw-r--r--lib/edit/w_info.txt120
-rw-r--r--lib/edit/wf_info.txt170
-rw-r--r--lib/edit/wights.map82
-rw-r--r--lib/edit/wolves.map55
-rw-r--r--lib/file/book-0.txt86
-rw-r--r--lib/file/book-1.txt83
-rw-r--r--lib/file/book-10.txt250
-rw-r--r--lib/file/book-101.txt4
-rw-r--r--lib/file/book-102.txt4
-rw-r--r--lib/file/book-103.txt6
-rw-r--r--lib/file/book-104.txt6
-rw-r--r--lib/file/book-105.txt7
-rw-r--r--lib/file/book-106.txt5
-rw-r--r--lib/file/book-107.txt6
-rw-r--r--lib/file/book-11.txt250
-rw-r--r--lib/file/book-12.txt250
-rw-r--r--lib/file/book-13.txt250
-rw-r--r--lib/file/book-14.txt250
-rw-r--r--lib/file/book-15.txt250
-rw-r--r--lib/file/book-16.txt250
-rw-r--r--lib/file/book-17.txt250
-rw-r--r--lib/file/book-18.txt250
-rw-r--r--lib/file/book-19.txt250
-rw-r--r--lib/file/book-2.txt90
-rw-r--r--lib/file/book-20.txt139
-rw-r--r--lib/file/book-200.txt5
-rw-r--r--lib/file/book-201.txt5
-rw-r--r--lib/file/book-202.txt5
-rw-r--r--lib/file/book-203.txt5
-rw-r--r--lib/file/book-4.txt11
-rw-r--r--lib/file/book-6.txt263
-rw-r--r--lib/file/book-7.txt141
-rw-r--r--lib/file/book-8.txt47
-rw-r--r--lib/file/book-9.txt240
-rw-r--r--lib/file/bravado.txt106
-rw-r--r--lib/file/chainswd.txt8
-rw-r--r--lib/file/dam_huge.txt9
-rw-r--r--lib/file/dam_lots.txt21
-rw-r--r--lib/file/dam_med.txt25
-rw-r--r--lib/file/dam_none.txt24
-rw-r--r--lib/file/dam_xxx.txt11
-rw-r--r--lib/file/dead.txt24
-rw-r--r--lib/file/death.txt351
-rw-r--r--lib/file/elvish.txt218
-rw-r--r--lib/file/error.txt67
-rw-r--r--lib/file/mondeath.txt334
-rw-r--r--lib/file/monfear.txt63
-rw-r--r--lib/file/monspeak.txt361
-rw-r--r--lib/file/news.txt24
-rw-r--r--lib/file/news2.txt24
-rw-r--r--lib/file/rart_f.txt86
-rw-r--r--lib/file/rart_s.txt87
-rw-r--r--lib/file/readme!36
-rw-r--r--lib/file/rumors.txt201
-rw-r--r--lib/file/sample.txt5
-rw-r--r--lib/file/sfail.txt34
-rw-r--r--lib/file/silly.txt301
-rw-r--r--lib/file/smeagol.txt29
-rw-r--r--lib/file/smeagolr.txt5
-rw-r--r--lib/file/speakpet.txt53
-rw-r--r--lib/file/timefun.txt92
-rw-r--r--lib/file/timenorm.txt83
-rw-r--r--lib/help/TANG.txt134
-rw-r--r--lib/help/ability.txt115
-rw-r--r--lib/help/advanced.hlp15
-rw-r--r--lib/help/attack.txt148
-rw-r--r--lib/help/automat.txt504
-rw-r--r--lib/help/birth.txt593
-rw-r--r--lib/help/bldg.txt59
-rw-r--r--lib/help/c_alchem.txt135
-rw-r--r--lib/help/c_archer.txt68
-rw-r--r--lib/help/c_assass.txt58
-rw-r--r--lib/help/c_axemas.txt51
-rw-r--r--lib/help/c_bard.txt69
-rw-r--r--lib/help/c_demono.txt54
-rw-r--r--lib/help/c_druid.txt55
-rw-r--r--lib/help/c_geoman.txt59
-rw-r--r--lib/help/c_hafted.txt54
-rw-r--r--lib/help/c_lorema.txt54
-rw-r--r--lib/help/c_mage.txt67
-rw-r--r--lib/help/c_merch.txt29
-rw-r--r--lib/help/c_mimic.txt53
-rw-r--r--lib/help/c_mindcr.txt57
-rw-r--r--lib/help/c_monk.txt87
-rw-r--r--lib/help/c_necro.txt80
-rw-r--r--lib/help/c_palad.txt49
-rw-r--r--lib/help/c_polear.txt52
-rw-r--r--lib/help/c_posses.txt70
-rw-r--r--lib/help/c_pr_drk.txt57
-rw-r--r--lib/help/c_pr_eru.txt55
-rw-r--r--lib/help/c_pr_man.txt54
-rw-r--r--lib/help/c_priest.txt13
-rw-r--r--lib/help/c_ranger.txt55
-rw-r--r--lib/help/c_rogue.txt62
-rw-r--r--lib/help/c_runecr.txt110
-rw-r--r--lib/help/c_sorcer.txt68
-rw-r--r--lib/help/c_summon.txt80
-rw-r--r--lib/help/c_swordm.txt52
-rw-r--r--lib/help/c_symbia.txt68
-rw-r--r--lib/help/c_thaum.txt84
-rw-r--r--lib/help/c_unbel.txt65
-rw-r--r--lib/help/c_warper.txt60
-rw-r--r--lib/help/c_warrio.txt54
-rw-r--r--lib/help/command.txt1251
-rw-r--r--lib/help/corspoil.txt136
-rw-r--r--lib/help/debug.txt275
-rw-r--r--lib/help/def.aux3
-rw-r--r--lib/help/defines.txt639
-rw-r--r--lib/help/dungeon.txt706
-rw-r--r--lib/help/dunspoil.txt173
-rw-r--r--lib/help/essences.txt219
-rw-r--r--lib/help/experien.hlp28
-rw-r--r--lib/help/explore.hlp16
-rw-r--r--lib/help/fatespoi.txt28
-rw-r--r--lib/help/foot.aux4
-rw-r--r--lib/help/g_eru.txt65
-rw-r--r--lib/help/g_manwe.txt62
-rw-r--r--lib/help/g_melkor.txt64
-rw-r--r--lib/help/g_tulkas.txt45
-rw-r--r--lib/help/g_yavann.txt62
-rw-r--r--lib/help/gambling.txt29
-rw-r--r--lib/help/general.txt39
-rw-r--r--lib/help/gods.txt38
-rw-r--r--lib/help/head.aux10
-rw-r--r--lib/help/help.hlp33
-rw-r--r--lib/help/index.txt592
-rw-r--r--lib/help/inscrip.txt65
-rw-r--r--lib/help/lua.hlp34
-rw-r--r--lib/help/lua_gf.txt45
-rw-r--r--lib/help/lua_intr.txt133
-rw-r--r--lib/help/lua_mon.txt535
-rw-r--r--lib/help/lua_play.txt1225
-rw-r--r--lib/help/lua_pow.txt266
-rw-r--r--lib/help/lua_ques.txt299
-rw-r--r--lib/help/lua_skil.txt342
-rw-r--r--lib/help/lua_spel.txt2150
-rw-r--r--lib/help/lua_util.txt898
-rw-r--r--lib/help/luckspoi.txt112
-rw-r--r--lib/help/m_air.txt42
-rw-r--r--lib/help/m_convey.txt71
-rw-r--r--lib/help/m_demono.txt44
-rw-r--r--lib/help/m_divin.txt37
-rw-r--r--lib/help/m_earth.txt35
-rw-r--r--lib/help/m_fire.txt49
-rw-r--r--lib/help/m_geoman.txt75
-rw-r--r--lib/help/m_mana.txt39
-rw-r--r--lib/help/m_meta.txt75
-rw-r--r--lib/help/m_mimic.txt33
-rw-r--r--lib/help/m_mind.txt49
-rw-r--r--lib/help/m_mindcr.txt54
-rw-r--r--lib/help/m_music.txt77
-rw-r--r--lib/help/m_nature.txt53
-rw-r--r--lib/help/m_necrom.txt35
-rw-r--r--lib/help/m_symbio.txt50
-rw-r--r--lib/help/m_tempo.txt41
-rw-r--r--lib/help/m_thaum.txt31
-rw-r--r--lib/help/m_udun.txt35
-rw-r--r--lib/help/m_water.txt33
-rw-r--r--lib/help/macrofaq.txt2356
-rw-r--r--lib/help/magic.hlp41
-rw-r--r--lib/help/magic.txt143
-rw-r--r--lib/help/newbie.hlp16
-rw-r--r--lib/help/option.txt698
-rw-r--r--lib/help/r_beorn.txt33
-rw-r--r--lib/help/r_deathm.txt33
-rw-r--r--lib/help/r_drkelf.txt33
-rw-r--r--lib/help/r_dunad.txt32
-rw-r--r--lib/help/r_dwarf.txt39
-rw-r--r--lib/help/r_elf.txt32
-rw-r--r--lib/help/r_ent.txt39
-rw-r--r--lib/help/r_gnome.txt36
-rw-r--r--lib/help/r_hafelf.txt31
-rw-r--r--lib/help/r_hafogr.txt31
-rw-r--r--lib/help/r_hielf.txt34
-rw-r--r--lib/help/r_hobbit.txt37
-rw-r--r--lib/help/r_human.txt23
-rw-r--r--lib/help/r_kobold.txt31
-rw-r--r--lib/help/r_maia.txt22
-rw-r--r--lib/help/r_orc.txt35
-rw-r--r--lib/help/r_pettyd.txt30
-rw-r--r--lib/help/r_rohank.txt33
-rw-r--r--lib/help/r_thlord.txt32
-rw-r--r--lib/help/r_troll.txt34
-rw-r--r--lib/help/r_wodelf.txt37
-rw-r--r--lib/help/r_yeek.txt30
-rw-r--r--lib/help/rm_barb.txt38
-rw-r--r--lib/help/rm_class.txt14
-rw-r--r--lib/help/rm_herm.txt36
-rw-r--r--lib/help/rm_lsoul.txt26
-rw-r--r--lib/help/rm_skel.txt40
-rw-r--r--lib/help/rm_spec.txt44
-rw-r--r--lib/help/rm_vamp.txt32
-rw-r--r--lib/help/rm_zomb.txt39
-rw-r--r--lib/help/skills.txt539
-rw-r--r--lib/help/spoil_faq.txt73
-rw-r--r--lib/help/spoiler.hlp18
-rw-r--r--lib/help/tome_faq.txt373
-rw-r--r--lib/help/version.txt354
-rw-r--r--lib/help/whattome.txt30
-rw-r--r--lib/help/wishing.txt24
-rw-r--r--lib/info/delete.me1
-rw-r--r--lib/mods/.cvsignore1
-rw-r--r--lib/mods/mods_aux.lua185
-rw-r--r--lib/mods/modules.lua5
-rw-r--r--lib/mods/theme/apex/delete.me1
-rw-r--r--lib/mods/theme/changelog.txt73
-rw-r--r--lib/mods/theme/core/auto.lua859
-rw-r--r--lib/mods/theme/core/building.lua15
-rw-r--r--lib/mods/theme/core/crpt_aux.lua182
-rw-r--r--lib/mods/theme/core/dungeon.lua55
-rw-r--r--lib/mods/theme/core/gen_idx.lua261
-rw-r--r--lib/mods/theme/core/gods.lua40
-rw-r--r--lib/mods/theme/core/help.lua141
-rw-r--r--lib/mods/theme/core/init.lua83
-rw-r--r--lib/mods/theme/core/load.lua37
-rw-r--r--lib/mods/theme/core/load2.lua56
-rw-r--r--lib/mods/theme/core/mimc_aux.lua96
-rw-r--r--lib/mods/theme/core/monsters.lua16
-rw-r--r--lib/mods/theme/core/objects.lua45
-rw-r--r--lib/mods/theme/core/player.lua135
-rw-r--r--lib/mods/theme/core/quests.lua57
-rw-r--r--lib/mods/theme/core/s_aux.lua716
-rw-r--r--lib/mods/theme/core/stores.lua32
-rw-r--r--lib/mods/theme/core/util.lua158
-rw-r--r--lib/mods/theme/core/xml.lua375
-rw-r--r--lib/mods/theme/data/delete.me0
-rw-r--r--lib/mods/theme/dngn/dun1.142
-rw-r--r--lib/mods/theme/dngn/dun1.222
-rw-r--r--lib/mods/theme/dngn/dun10.03
-rw-r--r--lib/mods/theme/dngn/dun11.202
-rw-r--r--lib/mods/theme/dngn/dun11.222
-rw-r--r--lib/mods/theme/dngn/dun17.155
-rw-r--r--lib/mods/theme/dngn/dun18.02
-rw-r--r--lib/mods/theme/dngn/dun18.12
-rw-r--r--lib/mods/theme/dngn/dun19.115
-rw-r--r--lib/mods/theme/dngn/dun2.312
-rw-r--r--lib/mods/theme/dngn/dun20.15
-rw-r--r--lib/mods/theme/dngn/dun22.102
-rw-r--r--lib/mods/theme/dngn/dun22.205
-rw-r--r--lib/mods/theme/dngn/dun22.55
-rw-r--r--lib/mods/theme/dngn/dun24.03
-rw-r--r--lib/mods/theme/dngn/dun29.156
-rw-r--r--lib/mods/theme/dngn/dun3.185
-rw-r--r--lib/mods/theme/dngn/dun3.285
-rw-r--r--lib/mods/theme/dngn/dun3.35
-rw-r--r--lib/mods/theme/dngn/dun36.55
-rw-r--r--lib/mods/theme/dngn/dun39.09
-rw-r--r--lib/mods/theme/dngn/dun4.92
-rw-r--r--lib/mods/theme/dngn/dun40.09
-rw-r--r--lib/mods/theme/dngn/dun5.03
-rw-r--r--lib/mods/theme/dngn/dun5.1414
-rw-r--r--lib/mods/theme/dngn/dun6.03
-rw-r--r--lib/mods/theme/edit/a_info.txt3359
-rw-r--r--lib/mods/theme/edit/ab_info.txt109
-rw-r--r--lib/mods/theme/edit/al_info.txt12
-rw-r--r--lib/mods/theme/edit/ba_info.txt310
-rw-r--r--lib/mods/theme/edit/between.map71
-rw-r--r--lib/mods/theme/edit/d_info.txt701
-rw-r--r--lib/mods/theme/edit/dragons.map43
-rw-r--r--lib/mods/theme/edit/e_info.txt3007
-rw-r--r--lib/mods/theme/edit/evil.map52
-rw-r--r--lib/mods/theme/edit/f_info.txt1245
-rw-r--r--lib/mods/theme/edit/fireprof.map60
-rw-r--r--lib/mods/theme/edit/haunted.map49
-rw-r--r--lib/mods/theme/edit/k_info.txt6865
-rw-r--r--lib/mods/theme/edit/library.map62
-rw-r--r--lib/mods/theme/edit/maeglin.map85
-rw-r--r--lib/mods/theme/edit/misc.txt91
-rw-r--r--lib/mods/theme/edit/nirnaeth.map64
-rw-r--r--lib/mods/theme/edit/numenor.txt80
-rw-r--r--lib/mods/theme/edit/ow_info.txt1419
-rw-r--r--lib/mods/theme/edit/p_info.txt2855
-rw-r--r--lib/mods/theme/edit/qrand1.map32
-rw-r--r--lib/mods/theme/edit/qrand10.map36
-rw-r--r--lib/mods/theme/edit/qrand11.map36
-rw-r--r--lib/mods/theme/edit/qrand12.map36
-rw-r--r--lib/mods/theme/edit/qrand14.map37
-rw-r--r--lib/mods/theme/edit/qrand5.map27
-rw-r--r--lib/mods/theme/edit/qrand6.map37
-rw-r--r--lib/mods/theme/edit/qrand7.map35
-rw-r--r--lib/mods/theme/edit/r_info.txt19013
-rw-r--r--lib/mods/theme/edit/ra_info.txt1985
-rw-r--r--lib/mods/theme/edit/re_info.txt183
-rw-r--r--lib/mods/theme/edit/readme.txt96
-rw-r--r--lib/mods/theme/edit/s_bilbo.map58
-rw-r--r--lib/mods/theme/edit/s_bridge.map104
-rw-r--r--lib/mods/theme/edit/s_crypt.map109
-rw-r--r--lib/mods/theme/edit/s_death.map104
-rw-r--r--lib/mods/theme/edit/s_doom.map226
-rw-r--r--lib/mods/theme/edit/s_factory.map238
-rw-r--r--lib/mods/theme/edit/s_gates.map117
-rw-r--r--lib/mods/theme/edit/s_info.txt542
-rw-r--r--lib/mods/theme/edit/s_name.map110
-rw-r--r--lib/mods/theme/edit/s_orc.map109
-rw-r--r--lib/mods/theme/edit/s_orthanc.map99
-rw-r--r--lib/mods/theme/edit/s_ship.map239
-rw-r--r--lib/mods/theme/edit/s_smaug.map78
-rw-r--r--lib/mods/theme/edit/s_thorin.map47
-rw-r--r--lib/mods/theme/edit/set_info.txt254
-rw-r--r--lib/mods/theme/edit/special.txt67
-rw-r--r--lib/mods/theme/edit/spiders.map66
-rw-r--r--lib/mods/theme/edit/st_info.txt1157
-rw-r--r--lib/mods/theme/edit/t_basic.txt66
-rw-r--r--lib/mods/theme/edit/t_beorn.txt108
-rw-r--r--lib/mods/theme/edit/t_bree.txt137
-rw-r--r--lib/mods/theme/edit/t_cerin.txt98
-rw-r--r--lib/mods/theme/edit/t_d_beorn.txt75
-rw-r--r--lib/mods/theme/edit/t_d_bree.txt91
-rw-r--r--lib/mods/theme/edit/t_d_cerin.txt75
-rw-r--r--lib/mods/theme/edit/t_d_dale.txt75
-rw-r--r--lib/mods/theme/edit/t_d_edoras.txt75
-rw-r--r--lib/mods/theme/edit/t_d_esga.txt75
-rw-r--r--lib/mods/theme/edit/t_d_gond.txt100
-rw-r--r--lib/mods/theme/edit/t_d_helm.txt75
-rw-r--r--lib/mods/theme/edit/t_d_henn.txt75
-rw-r--r--lib/mods/theme/edit/t_d_hobb.txt75
-rw-r--r--lib/mods/theme/edit/t_d_imlad.txt75
-rw-r--r--lib/mods/theme/edit/t_d_khaz.txt79
-rw-r--r--lib/mods/theme/edit/t_d_lori.txt75
-rw-r--r--lib/mods/theme/edit/t_d_mina.txt79
-rw-r--r--lib/mods/theme/edit/t_d_osgili.txt78
-rw-r--r--lib/mods/theme/edit/t_d_pelar.txt78
-rw-r--r--lib/mods/theme/edit/t_d_thrand.txt75
-rw-r--r--lib/mods/theme/edit/t_dale.txt96
-rw-r--r--lib/mods/theme/edit/t_edoras.txt117
-rw-r--r--lib/mods/theme/edit/t_esga.txt105
-rw-r--r--lib/mods/theme/edit/t_gondol.txt219
-rw-r--r--lib/mods/theme/edit/t_helm.txt73
-rw-r--r--lib/mods/theme/edit/t_henn.txt96
-rw-r--r--lib/mods/theme/edit/t_hobb.txt108
-rw-r--r--lib/mods/theme/edit/t_imlad.txt90
-rw-r--r--lib/mods/theme/edit/t_info.txt125
-rw-r--r--lib/mods/theme/edit/t_khazad.txt114
-rw-r--r--lib/mods/theme/edit/t_lorien.txt185
-rw-r--r--lib/mods/theme/edit/t_minas.txt141
-rw-r--r--lib/mods/theme/edit/t_osgili.txt136
-rw-r--r--lib/mods/theme/edit/t_pelar.txt105
-rw-r--r--lib/mods/theme/edit/t_pref.txt145
-rw-r--r--lib/mods/theme/edit/t_thrand.txt103
-rw-r--r--lib/mods/theme/edit/thieves.map64
-rw-r--r--lib/mods/theme/edit/thrain.map35
-rw-r--r--lib/mods/theme/edit/tr_info.txt817
-rw-r--r--lib/mods/theme/edit/trolls.map58
-rw-r--r--lib/mods/theme/edit/v_info.txt2287
-rw-r--r--lib/mods/theme/edit/volcano.txt83
-rw-r--r--lib/mods/theme/edit/w_info.txt141
-rw-r--r--lib/mods/theme/edit/wf_info.txt394
-rw-r--r--lib/mods/theme/edit/wights.map82
-rw-r--r--lib/mods/theme/edit/wolves.map55
-rw-r--r--lib/mods/theme/file/book-0.txt86
-rw-r--r--lib/mods/theme/file/book-1.txt83
-rw-r--r--lib/mods/theme/file/book-10.txt75
-rw-r--r--lib/mods/theme/file/book-101.txt4
-rw-r--r--lib/mods/theme/file/book-102.txt4
-rw-r--r--lib/mods/theme/file/book-103.txt6
-rw-r--r--lib/mods/theme/file/book-104.txt6
-rw-r--r--lib/mods/theme/file/book-105.txt7
-rw-r--r--lib/mods/theme/file/book-106.txt5
-rw-r--r--lib/mods/theme/file/book-107.txt6
-rw-r--r--lib/mods/theme/file/book-11.txt51
-rw-r--r--lib/mods/theme/file/book-12.txt68
-rw-r--r--lib/mods/theme/file/book-13.txt54
-rw-r--r--lib/mods/theme/file/book-14.txt55
-rw-r--r--lib/mods/theme/file/book-15.txt68
-rw-r--r--lib/mods/theme/file/book-16.txt43
-rw-r--r--lib/mods/theme/file/book-17.txt47
-rw-r--r--lib/mods/theme/file/book-18.txt55
-rw-r--r--lib/mods/theme/file/book-19.txt47
-rw-r--r--lib/mods/theme/file/book-2.txt90
-rw-r--r--lib/mods/theme/file/book-20.txt192
-rw-r--r--lib/mods/theme/file/book-200.txt5
-rw-r--r--lib/mods/theme/file/book-201.txt5
-rw-r--r--lib/mods/theme/file/book-202.txt5
-rw-r--r--lib/mods/theme/file/book-203.txt5
-rw-r--r--lib/mods/theme/file/book-204.txt5
-rw-r--r--lib/mods/theme/file/book-205.txt5
-rw-r--r--lib/mods/theme/file/book-206.txt5
-rw-r--r--lib/mods/theme/file/book-207.txt5
-rw-r--r--lib/mods/theme/file/book-208.txt5
-rw-r--r--lib/mods/theme/file/book-209.txt5
-rw-r--r--lib/mods/theme/file/book-210.txt5
-rw-r--r--lib/mods/theme/file/book-211.txt5
-rw-r--r--lib/mods/theme/file/book-212.txt5
-rw-r--r--lib/mods/theme/file/book-213.txt5
-rw-r--r--lib/mods/theme/file/book-214.txt5
-rw-r--r--lib/mods/theme/file/book-215.txt5
-rw-r--r--lib/mods/theme/file/book-216.txt5
-rw-r--r--lib/mods/theme/file/book-22.txt56
-rw-r--r--lib/mods/theme/file/book-23.txt81
-rw-r--r--lib/mods/theme/file/book-24.txt59
-rw-r--r--lib/mods/theme/file/book-25.txt98
-rw-r--r--lib/mods/theme/file/book-26.txt56
-rw-r--r--lib/mods/theme/file/book-27.txt75
-rw-r--r--lib/mods/theme/file/book-28.txt102
-rw-r--r--lib/mods/theme/file/book-29.txt75
-rw-r--r--lib/mods/theme/file/book-30.txt58
-rw-r--r--lib/mods/theme/file/book-31.txt63
-rw-r--r--lib/mods/theme/file/book-32.txt37
-rw-r--r--lib/mods/theme/file/book-33.txt21
-rw-r--r--lib/mods/theme/file/book-4.txt11
-rw-r--r--lib/mods/theme/file/book-6.txt171
-rw-r--r--lib/mods/theme/file/book-7.txt83
-rw-r--r--lib/mods/theme/file/book-8.txt101
-rw-r--r--lib/mods/theme/file/book-9.txt99
-rw-r--r--lib/mods/theme/file/bravado.txt105
-rw-r--r--lib/mods/theme/file/chainswd.txt8
-rw-r--r--lib/mods/theme/file/dam_huge.txt9
-rw-r--r--lib/mods/theme/file/dam_lots.txt21
-rw-r--r--lib/mods/theme/file/dam_med.txt25
-rw-r--r--lib/mods/theme/file/dam_none.txt24
-rw-r--r--lib/mods/theme/file/dam_xxx.txt11
-rw-r--r--lib/mods/theme/file/dead.txt24
-rw-r--r--lib/mods/theme/file/death.txt351
-rw-r--r--lib/mods/theme/file/elvish.txt218
-rw-r--r--lib/mods/theme/file/error.txt67
-rw-r--r--lib/mods/theme/file/mondeath.txt334
-rw-r--r--lib/mods/theme/file/monfear.txt63
-rw-r--r--lib/mods/theme/file/monspeak.txt517
-rw-r--r--lib/mods/theme/file/news.txt23
-rw-r--r--lib/mods/theme/file/news2.txt23
-rw-r--r--lib/mods/theme/file/rart_f.txt86
-rw-r--r--lib/mods/theme/file/rart_s.txt87
-rw-r--r--lib/mods/theme/file/readme!36
-rw-r--r--lib/mods/theme/file/rumors.txt201
-rw-r--r--lib/mods/theme/file/sample.txt5
-rw-r--r--lib/mods/theme/file/sfail.txt34
-rw-r--r--lib/mods/theme/file/silly.txt301
-rw-r--r--lib/mods/theme/file/smeagol.txt29
-rw-r--r--lib/mods/theme/file/smeagolr.txt5
-rw-r--r--lib/mods/theme/file/speakpet.txt53
-rw-r--r--lib/mods/theme/file/timefun.txt92
-rw-r--r--lib/mods/theme/file/timenorm.txt83
-rw-r--r--lib/mods/theme/help/ability.txt115
-rw-r--r--lib/mods/theme/help/advanced.hlp15
-rw-r--r--lib/mods/theme/help/attack.txt148
-rw-r--r--lib/mods/theme/help/automat.txt504
-rw-r--r--lib/mods/theme/help/birth.txt659
-rw-r--r--lib/mods/theme/help/c_alchem.txt135
-rw-r--r--lib/mods/theme/help/c_archer.txt68
-rw-r--r--lib/mods/theme/help/c_ascet.txt46
-rw-r--r--lib/mods/theme/help/c_assass.txt58
-rw-r--r--lib/mods/theme/help/c_axemas.txt51
-rw-r--r--lib/mods/theme/help/c_bard.txt69
-rw-r--r--lib/mods/theme/help/c_clairv.txt47
-rw-r--r--lib/mods/theme/help/c_demono.txt54
-rw-r--r--lib/mods/theme/help/c_druid.txt55
-rw-r--r--lib/mods/theme/help/c_geoman.txt59
-rw-r--r--lib/mods/theme/help/c_hafted.txt54
-rw-r--r--lib/mods/theme/help/c_lorema.txt54
-rw-r--r--lib/mods/theme/help/c_mage.txt67
-rw-r--r--lib/mods/theme/help/c_mercen.txt49
-rw-r--r--lib/mods/theme/help/c_merch.txt29
-rw-r--r--lib/mods/theme/help/c_mimic.txt53
-rw-r--r--lib/mods/theme/help/c_mindcr.txt57
-rw-r--r--lib/mods/theme/help/c_monk.txt87
-rw-r--r--lib/mods/theme/help/c_necro.txt80
-rw-r--r--lib/mods/theme/help/c_pacif.txt10
-rw-r--r--lib/mods/theme/help/c_palad.txt49
-rw-r--r--lib/mods/theme/help/c_peacemag.txt46
-rw-r--r--lib/mods/theme/help/c_polear.txt52
-rw-r--r--lib/mods/theme/help/c_posses.txt70
-rw-r--r--lib/mods/theme/help/c_pr_drk.txt57
-rw-r--r--lib/mods/theme/help/c_pr_eru.txt55
-rw-r--r--lib/mods/theme/help/c_pr_man.txt54
-rw-r--r--lib/mods/theme/help/c_pr_mand.txt49
-rw-r--r--lib/mods/theme/help/c_pr_ulmo.txt50
-rw-r--r--lib/mods/theme/help/c_pr_varda.txt50
-rw-r--r--lib/mods/theme/help/c_priest.txt17
-rw-r--r--lib/mods/theme/help/c_ranger.txt56
-rw-r--r--lib/mods/theme/help/c_rogue.txt62
-rw-r--r--lib/mods/theme/help/c_runecr.txt110
-rw-r--r--lib/mods/theme/help/c_sniper.txt50
-rw-r--r--lib/mods/theme/help/c_sorcer.txt68
-rw-r--r--lib/mods/theme/help/c_stonewr.txt50
-rw-r--r--lib/mods/theme/help/c_summon.txt80
-rw-r--r--lib/mods/theme/help/c_swordm.txt52
-rw-r--r--lib/mods/theme/help/c_symbia.txt68
-rw-r--r--lib/mods/theme/help/c_thaum.txt84
-rw-r--r--lib/mods/theme/help/c_trapper.txt46
-rw-r--r--lib/mods/theme/help/c_unbel.txt65
-rw-r--r--lib/mods/theme/help/c_wainrid.txt49
-rw-r--r--lib/mods/theme/help/c_warper.txt60
-rw-r--r--lib/mods/theme/help/c_warrio.txt54
-rw-r--r--lib/mods/theme/help/command.txt1251
-rw-r--r--lib/mods/theme/help/corspoil.txt136
-rw-r--r--lib/mods/theme/help/debug.txt278
-rw-r--r--lib/mods/theme/help/def.aux3
-rw-r--r--lib/mods/theme/help/defines.txt639
-rw-r--r--lib/mods/theme/help/dungeon.txt703
-rw-r--r--lib/mods/theme/help/dunspoil.txt173
-rw-r--r--lib/mods/theme/help/essences.txt219
-rw-r--r--lib/mods/theme/help/experien.hlp28
-rw-r--r--lib/mods/theme/help/explore.hlp16
-rw-r--r--lib/mods/theme/help/fatespoi.txt28
-rw-r--r--lib/mods/theme/help/foot.aux4
-rw-r--r--lib/mods/theme/help/g_aule.txt61
-rw-r--r--lib/mods/theme/help/g_eru.txt65
-rw-r--r--lib/mods/theme/help/g_mandos.txt56
-rw-r--r--lib/mods/theme/help/g_manwe.txt62
-rw-r--r--lib/mods/theme/help/g_melkor.txt65
-rw-r--r--lib/mods/theme/help/g_tulkas.txt45
-rw-r--r--lib/mods/theme/help/g_ulmo.txt58
-rw-r--r--lib/mods/theme/help/g_varda.txt54
-rw-r--r--lib/mods/theme/help/g_yavann.txt62
-rw-r--r--lib/mods/theme/help/gambling.txt29
-rw-r--r--lib/mods/theme/help/general.txt39
-rw-r--r--lib/mods/theme/help/gods.txt42
-rw-r--r--lib/mods/theme/help/head.aux10
-rw-r--r--lib/mods/theme/help/help.hlp33
-rw-r--r--lib/mods/theme/help/index.txt636
-rw-r--r--lib/mods/theme/help/inscrip.txt65
-rw-r--r--lib/mods/theme/help/lua.hlp34
-rw-r--r--lib/mods/theme/help/lua_gf.txt45
-rw-r--r--lib/mods/theme/help/lua_intr.txt133
-rw-r--r--lib/mods/theme/help/lua_mon.txt535
-rw-r--r--lib/mods/theme/help/lua_play.txt1225
-rw-r--r--lib/mods/theme/help/lua_pow.txt266
-rw-r--r--lib/mods/theme/help/lua_ques.txt299
-rw-r--r--lib/mods/theme/help/lua_skil.txt342
-rw-r--r--lib/mods/theme/help/lua_spel.txt2150
-rw-r--r--lib/mods/theme/help/lua_util.txt898
-rw-r--r--lib/mods/theme/help/luckspoi.txt129
-rw-r--r--lib/mods/theme/help/m_air.txt42
-rw-r--r--lib/mods/theme/help/m_convey.txt71
-rw-r--r--lib/mods/theme/help/m_demono.txt44
-rw-r--r--lib/mods/theme/help/m_divin.txt38
-rw-r--r--lib/mods/theme/help/m_earth.txt35
-rw-r--r--lib/mods/theme/help/m_fire.txt53
-rw-r--r--lib/mods/theme/help/m_geoman.txt75
-rw-r--r--lib/mods/theme/help/m_mana.txt40
-rw-r--r--lib/mods/theme/help/m_meta.txt75
-rw-r--r--lib/mods/theme/help/m_mimic.txt33
-rw-r--r--lib/mods/theme/help/m_mind.txt49
-rw-r--r--lib/mods/theme/help/m_mindcr.txt54
-rw-r--r--lib/mods/theme/help/m_music.txt77
-rw-r--r--lib/mods/theme/help/m_nature.txt54
-rw-r--r--lib/mods/theme/help/m_necrom.txt35
-rw-r--r--lib/mods/theme/help/m_symbio.txt50
-rw-r--r--lib/mods/theme/help/m_tempo.txt42
-rw-r--r--lib/mods/theme/help/m_thaum.txt31
-rw-r--r--lib/mods/theme/help/m_udun.txt35
-rw-r--r--lib/mods/theme/help/m_water.txt34
-rw-r--r--lib/mods/theme/help/macrofaq.txt2360
-rw-r--r--lib/mods/theme/help/magic.hlp41
-rw-r--r--lib/mods/theme/help/magic.txt143
-rw-r--r--lib/mods/theme/help/newbie.hlp16
-rw-r--r--lib/mods/theme/help/option.txt697
-rw-r--r--lib/mods/theme/help/r_beorn.txt33
-rw-r--r--lib/mods/theme/help/r_demon.txt31
-rw-r--r--lib/mods/theme/help/r_dragon.txt33
-rw-r--r--lib/mods/theme/help/r_drkelf.txt33
-rw-r--r--lib/mods/theme/help/r_druadan.txt32
-rw-r--r--lib/mods/theme/help/r_dunad.txt32
-rw-r--r--lib/mods/theme/help/r_dwarf.txt39
-rw-r--r--lib/mods/theme/help/r_eagle.txt32
-rw-r--r--lib/mods/theme/help/r_easterl.txt34
-rw-r--r--lib/mods/theme/help/r_elf.txt32
-rw-r--r--lib/mods/theme/help/r_ent.txt39
-rw-r--r--lib/mods/theme/help/r_gnome.txt36
-rw-r--r--lib/mods/theme/help/r_hafelf.txt31
-rw-r--r--lib/mods/theme/help/r_hafogr.txt31
-rw-r--r--lib/mods/theme/help/r_hielf.txt34
-rw-r--r--lib/mods/theme/help/r_hobbit.txt39
-rw-r--r--lib/mods/theme/help/r_human.txt23
-rw-r--r--lib/mods/theme/help/r_maia.txt20
-rw-r--r--lib/mods/theme/help/r_orc.txt35
-rw-r--r--lib/mods/theme/help/r_pettyd.txt30
-rw-r--r--lib/mods/theme/help/r_rohank.txt33
-rw-r--r--lib/mods/theme/help/r_troll.txt34
-rw-r--r--lib/mods/theme/help/r_wodelf.txt37
-rw-r--r--lib/mods/theme/help/r_yeek.txt30
-rw-r--r--lib/mods/theme/help/rm_adanrog.txt31
-rw-r--r--lib/mods/theme/help/rm_aewrog.txt35
-rw-r--r--lib/mods/theme/help/rm_barb.txt38
-rw-r--r--lib/mods/theme/help/rm_black.txt31
-rw-r--r--lib/mods/theme/help/rm_blue.txt31
-rw-r--r--lib/mods/theme/help/rm_cabrog.txt35
-rw-r--r--lib/mods/theme/help/rm_class.txt14
-rw-r--r--lib/mods/theme/help/rm_drarog.txt34
-rw-r--r--lib/mods/theme/help/rm_ether.txt32
-rw-r--r--lib/mods/theme/help/rm_green.txt30
-rw-r--r--lib/mods/theme/help/rm_herm.txt36
-rw-r--r--lib/mods/theme/help/rm_hurog.txt27
-rw-r--r--lib/mods/theme/help/rm_limrog.txt33
-rw-r--r--lib/mods/theme/help/rm_lsoul.txt26
-rw-r--r--lib/mods/theme/help/rm_lygrog.txt27
-rw-r--r--lib/mods/theme/help/rm_narrog.txt34
-rw-r--r--lib/mods/theme/help/rm_rawrog.txt30
-rw-r--r--lib/mods/theme/help/rm_red.txt30
-rw-r--r--lib/mods/theme/help/rm_sarnrog.txt30
-rw-r--r--lib/mods/theme/help/rm_skel.txt40
-rw-r--r--lib/mods/theme/help/rm_spec.txt44
-rw-r--r--lib/mods/theme/help/rm_vamp.txt32
-rw-r--r--lib/mods/theme/help/rm_white.txt32
-rw-r--r--lib/mods/theme/help/rm_zomb.txt39
-rw-r--r--lib/mods/theme/help/skills.txt539
-rw-r--r--lib/mods/theme/help/spoil_faq.txt63
-rw-r--r--lib/mods/theme/help/spoiler.hlp18
-rw-r--r--lib/mods/theme/help/tome_faq.txt381
-rw-r--r--lib/mods/theme/help/version.txt354
-rw-r--r--lib/mods/theme/help/whattome.txt30
-rw-r--r--lib/mods/theme/help/wishing.txt24
-rw-r--r--lib/mods/theme/module.lua48
-rw-r--r--lib/mods/theme/note/delete.me1
-rw-r--r--lib/mods/theme/permission.txt3
-rw-r--r--lib/mods/theme/pref/422color.prf909
-rw-r--r--lib/mods/theme/pref/colors.prf53
-rw-r--r--lib/mods/theme/pref/font-ami.prf28
-rw-r--r--lib/mods/theme/pref/font-dos.prf8
-rw-r--r--lib/mods/theme/pref/font-ibm.prf365
-rw-r--r--lib/mods/theme/pref/font-mac.new110
-rw-r--r--lib/mods/theme/pref/font-mac.prf18
-rw-r--r--lib/mods/theme/pref/font-win.prf304
-rw-r--r--lib/mods/theme/pref/font-x11.prf22
-rw-r--r--lib/mods/theme/pref/font-xxx.prf472
-rw-r--r--lib/mods/theme/pref/font.prf60
-rw-r--r--lib/mods/theme/pref/graf-ami.prf64
-rw-r--r--lib/mods/theme/pref/graf-dos.prf15
-rw-r--r--lib/mods/theme/pref/graf-ibm.prf6237
-rw-r--r--lib/mods/theme/pref/graf-iso.prf5963
-rw-r--r--lib/mods/theme/pref/graf-mac.prf15
-rw-r--r--lib/mods/theme/pref/graf-new.prf6934
-rw-r--r--lib/mods/theme/pref/graf-sdl.prf37
-rw-r--r--lib/mods/theme/pref/graf-win.prf16
-rw-r--r--lib/mods/theme/pref/graf-x11.prf37
-rw-r--r--lib/mods/theme/pref/graf-xxx.prf3267
-rw-r--r--lib/mods/theme/pref/graf.prf51
-rw-r--r--lib/mods/theme/pref/pref-acn.prf24
-rw-r--r--lib/mods/theme/pref/pref-ami.prf7
-rw-r--r--lib/mods/theme/pref/pref-emx.prf19
-rw-r--r--lib/mods/theme/pref/pref-gcu.prf70
-rw-r--r--lib/mods/theme/pref/pref-mac.prf243
-rw-r--r--lib/mods/theme/pref/pref-sdl.prf144
-rw-r--r--lib/mods/theme/pref/pref-win.prf534
-rw-r--r--lib/mods/theme/pref/pref-x11.prf413
-rw-r--r--lib/mods/theme/pref/pref.prf311
-rw-r--r--lib/mods/theme/pref/trap-xxx.prf428
-rw-r--r--lib/mods/theme/pref/user.prf50
-rw-r--r--lib/mods/theme/pref/xtra-gcu.prf34
-rw-r--r--lib/mods/theme/pref/xtra-new.prf63
-rw-r--r--lib/mods/theme/pref/xtra-xxx.prf137
-rw-r--r--lib/mods/theme/save/delete.me1
-rw-r--r--lib/mods/theme/scpt/bounty.lua90
-rw-r--r--lib/mods/theme/scpt/corrupt.lua1089
-rw-r--r--lib/mods/theme/scpt/drunk.lua21
-rw-r--r--lib/mods/theme/scpt/fireprof.lua415
-rw-r--r--lib/mods/theme/scpt/god.lua812
-rw-r--r--lib/mods/theme/scpt/gods.lua26
-rw-r--r--lib/mods/theme/scpt/gods_new.lua454
-rw-r--r--lib/mods/theme/scpt/gondolin.lua63
-rw-r--r--lib/mods/theme/scpt/help.lua445
-rw-r--r--lib/mods/theme/scpt/init.lua56
-rw-r--r--lib/mods/theme/scpt/intro.lua43
-rw-r--r--lib/mods/theme/scpt/joke.lua31
-rw-r--r--lib/mods/theme/scpt/library.lua439
-rw-r--r--lib/mods/theme/scpt/mimic.lua419
-rw-r--r--lib/mods/theme/scpt/misc.lua213
-rw-r--r--lib/mods/theme/scpt/mkeys.lua95
-rw-r--r--lib/mods/theme/scpt/monsters.lua182
-rw-r--r--lib/mods/theme/scpt/player.lua196
-rw-r--r--lib/mods/theme/scpt/powers.lua61
-rw-r--r--lib/mods/theme/scpt/s_air.lua193
-rw-r--r--lib/mods/theme/scpt/s_aule.lua222
-rw-r--r--lib/mods/theme/scpt/s_convey.lua226
-rw-r--r--lib/mods/theme/scpt/s_demon.lua337
-rw-r--r--lib/mods/theme/scpt/s_divin.lua230
-rw-r--r--lib/mods/theme/scpt/s_earth.lua184
-rw-r--r--lib/mods/theme/scpt/s_eru.lua130
-rw-r--r--lib/mods/theme/scpt/s_fire.lua227
-rw-r--r--lib/mods/theme/scpt/s_geom.lua656
-rw-r--r--lib/mods/theme/scpt/s_mana.lua132
-rw-r--r--lib/mods/theme/scpt/s_mandos.lua186
-rw-r--r--lib/mods/theme/scpt/s_manwe.lua144
-rw-r--r--lib/mods/theme/scpt/s_melkor.lua154
-rw-r--r--lib/mods/theme/scpt/s_meta.lua287
-rw-r--r--lib/mods/theme/scpt/s_mind.lua132
-rw-r--r--lib/mods/theme/scpt/s_music.lua443
-rw-r--r--lib/mods/theme/scpt/s_nature.lua184
-rw-r--r--lib/mods/theme/scpt/s_stick.lua494
-rw-r--r--lib/mods/theme/scpt/s_tempo.lua162
-rw-r--r--lib/mods/theme/scpt/s_tulkas.lua81
-rw-r--r--lib/mods/theme/scpt/s_udun.lua180
-rw-r--r--lib/mods/theme/scpt/s_ulmo.lua147
-rw-r--r--lib/mods/theme/scpt/s_varda.lua140
-rw-r--r--lib/mods/theme/scpt/s_water.lua154
-rw-r--r--lib/mods/theme/scpt/s_yavann.lua157
-rw-r--r--lib/mods/theme/scpt/spells.lua627
-rw-r--r--lib/mods/theme/scpt/stores.lua161
-rw-r--r--lib/mods/theme/theme.txt313
-rw-r--r--lib/mods/theme/user/all.prf520
-rw-r--r--lib/mods/theme/user/automat.atm667
-rw-r--r--lib/mods/theme/user/fierce.atm761
-rw-r--r--lib/module.lua36
-rw-r--r--lib/note/delete.me1
-rw-r--r--lib/patch/.cvsignore1
-rw-r--r--lib/patch/delete.me1
-rw-r--r--lib/pref/422color.prf909
-rw-r--r--lib/pref/colors.prf53
-rw-r--r--lib/pref/font-ami.prf28
-rw-r--r--lib/pref/font-dos.prf8
-rw-r--r--lib/pref/font-mac.new108
-rw-r--r--lib/pref/font-mac.prf18
-rw-r--r--lib/pref/font-win.prf301
-rw-r--r--lib/pref/font-x11.prf22
-rw-r--r--lib/pref/font-xxx.prf472
-rw-r--r--lib/pref/font.prf60
-rw-r--r--lib/pref/graf-ami.prf64
-rw-r--r--lib/pref/graf-dos.prf15
-rw-r--r--lib/pref/graf-iso.prf6878
-rw-r--r--lib/pref/graf-mac.prf15
-rw-r--r--lib/pref/graf-new.prf6847
-rw-r--r--lib/pref/graf-sdl.prf37
-rw-r--r--lib/pref/graf-win.prf16
-rw-r--r--lib/pref/graf-x11.prf37
-rw-r--r--lib/pref/graf-xxx.prf6348
-rw-r--r--lib/pref/graf.prf51
-rw-r--r--lib/pref/pref-acn.prf24
-rw-r--r--lib/pref/pref-ami.prf7
-rw-r--r--lib/pref/pref-emx.prf19
-rw-r--r--lib/pref/pref-gcu.prf70
-rw-r--r--lib/pref/pref-iso.prf118
-rw-r--r--lib/pref/pref-mac.prf243
-rw-r--r--lib/pref/pref-sdl.prf144
-rw-r--r--lib/pref/pref-win.prf534
-rw-r--r--lib/pref/pref-x11.prf413
-rw-r--r--lib/pref/pref.prf311
-rw-r--r--lib/pref/trap-iso.prf429
-rw-r--r--lib/pref/trap-xxx.prf428
-rw-r--r--lib/pref/user.prf50
-rw-r--r--lib/pref/xtra-gcu.prf34
-rw-r--r--lib/pref/xtra-new.prf1128
-rw-r--r--lib/pref/xtra-xxx.prf137
-rw-r--r--lib/save/delete.me1
-rw-r--r--lib/scpt/.cvsignore1
-rw-r--r--lib/scpt/bounty.lua90
-rw-r--r--lib/scpt/corrupt.lua433
-rw-r--r--lib/scpt/drunk.lua21
-rw-r--r--lib/scpt/fireprof.lua415
-rw-r--r--lib/scpt/god.lua640
-rw-r--r--lib/scpt/gods.lua26
-rw-r--r--lib/scpt/help.lua411
-rw-r--r--lib/scpt/init.lua46
-rw-r--r--lib/scpt/intro.lua39
-rw-r--r--lib/scpt/joke.lua31
-rw-r--r--lib/scpt/library.lua436
-rw-r--r--lib/scpt/mimic.lua419
-rw-r--r--lib/scpt/mkeys.lua95
-rw-r--r--lib/scpt/player.lua76
-rw-r--r--lib/scpt/powers.lua61
-rw-r--r--lib/scpt/s_air.lua193
-rw-r--r--lib/scpt/s_convey.lua227
-rw-r--r--lib/scpt/s_demon.lua337
-rw-r--r--lib/scpt/s_divin.lua230
-rw-r--r--lib/scpt/s_earth.lua184
-rw-r--r--lib/scpt/s_eru.lua130
-rw-r--r--lib/scpt/s_fire.lua227
-rw-r--r--lib/scpt/s_geom.lua656
-rw-r--r--lib/scpt/s_mana.lua132
-rw-r--r--lib/scpt/s_manwe.lua144
-rw-r--r--lib/scpt/s_melkor.lua154
-rw-r--r--lib/scpt/s_meta.lua287
-rw-r--r--lib/scpt/s_mind.lua132
-rw-r--r--lib/scpt/s_music.lua443
-rw-r--r--lib/scpt/s_nature.lua152
-rw-r--r--lib/scpt/s_stick.lua444
-rw-r--r--lib/scpt/s_tempo.lua162
-rw-r--r--lib/scpt/s_tulkas.lua81
-rw-r--r--lib/scpt/s_udun.lua180
-rw-r--r--lib/scpt/s_water.lua154
-rw-r--r--lib/scpt/s_yavann.lua157
-rw-r--r--lib/scpt/spells.lua475
-rw-r--r--lib/scpt/stores.lua132
-rw-r--r--lib/user/automat.atm0
-rw-r--r--lib/user/delete.me1
-rw-r--r--lib/xtra/ang16.bdf5017
-rw-r--r--lib/xtra/angband.fntbin0 -> 4096 bytes
-rw-r--r--lib/xtra/font/10X20.FONbin0 -> 8704 bytes
-rw-r--r--lib/xtra/font/12X24.FONbin0 -> 9728 bytes
-rw-r--r--lib/xtra/font/5X8.FONbin0 -> 4608 bytes
-rw-r--r--lib/xtra/font/6X10.FONbin0 -> 4608 bytes
-rw-r--r--lib/xtra/font/6X12.FONbin0 -> 5120 bytes
-rw-r--r--lib/xtra/font/6X13.FONbin0 -> 5120 bytes
-rw-r--r--lib/xtra/font/6X13B.FONbin0 -> 5120 bytes
-rw-r--r--lib/xtra/font/6X9.FONbin0 -> 4608 bytes
-rw-r--r--lib/xtra/font/7X13.FONbin0 -> 5120 bytes
-rw-r--r--lib/xtra/font/7X13B.FONbin0 -> 5120 bytes
-rw-r--r--lib/xtra/font/8X13.FONbin0 -> 5120 bytes
-rw-r--r--lib/xtra/font/8X13B.FONbin0 -> 5120 bytes
-rw-r--r--lib/xtra/font/9X15.FONbin0 -> 7168 bytes
-rw-r--r--lib/xtra/font/9X15B.FONbin0 -> 7168 bytes
-rw-r--r--lib/xtra/font/VeraMono.ttfbin0 -> 49224 bytes
-rw-r--r--lib/xtra/font/XM10X17.FNTbin0 -> 3286 bytes
-rw-r--r--lib/xtra/font/XM10X17B.FNTbin0 -> 3286 bytes
-rw-r--r--lib/xtra/font/XM12X20.FNTbin0 -> 3856 bytes
-rw-r--r--lib/xtra/font/XM12X20B.FNTbin0 -> 3856 bytes
-rw-r--r--lib/xtra/font/XM16X25.FNTbin0 -> 4806 bytes
-rw-r--r--lib/xtra/font/XM16X25B.FNTbin0 -> 4806 bytes
-rw-r--r--lib/xtra/font/XM5X8.FNTbin0 -> 1679 bytes
-rw-r--r--lib/xtra/font/XM6X12.FNTbin0 -> 2061 bytes
-rw-r--r--lib/xtra/font/XM6X12B.FNTbin0 -> 2059 bytes
-rw-r--r--lib/xtra/font/XM8X16B.FNTbin0 -> 2439 bytes
-rw-r--r--lib/xtra/font/xm4x6.fntbin0 -> 1489 bytes
-rw-r--r--lib/xtra/font/xm8x13.fntbin0 -> 2156 bytes
-rw-r--r--lib/xtra/font/xm8x13b.fntbin0 -> 2154 bytes
-rw-r--r--lib/xtra/font/xm8x16.fntbin0 -> 2441 bytes
-rw-r--r--lib/xtra/graf/16x16.bmpbin0 -> 1164238 bytes
-rw-r--r--lib/xtra/graf/16x16.pngbin0 -> 210021 bytes
-rw-r--r--lib/xtra/graf/8x8.bmpbin0 -> 203830 bytes
-rw-r--r--lib/xtra/graf/8x8.pngbin0 -> 44451 bytes
-rw-r--r--lib/xtra/graf/mask.bmpbin0 -> 1164342 bytes
-rw-r--r--lib/xtra/graf/tome-128.pngbin0 -> 45589 bytes
-rw-r--r--lib/xtra/music/delete.me1
-rw-r--r--lib/xtra/sound/Sound.cfg79
-rw-r--r--lib/xtra/sound/readme.txt33
-rw-r--r--src/.cvsignore8
-rw-r--r--src/CMakeLists.txt72
-rw-r--r--src/ENGLISH.txt35
-rw-r--r--src/angband.h110
-rw-r--r--src/angband.icobin0 -> 766 bytes
-rw-r--r--src/angband.rc132
-rw-r--r--src/birth.c3825
-rw-r--r--src/bldg.c2198
-rw-r--r--src/carbon/Angband.icnsbin0 -> 66668 bytes
-rw-r--r--src/carbon/Carbon.r1568
-rw-r--r--src/carbon/Data.icnsbin0 -> 36416 bytes
-rw-r--r--src/carbon/Edit.icnsbin0 -> 35735 bytes
-rw-r--r--src/carbon/Image-DS_Storebin0 -> 6148 bytes
-rw-r--r--src/carbon/Info.plist39
-rw-r--r--src/carbon/Save.icnsbin0 -> 43952 bytes
-rwxr-xr-xsrc/carbon/getversion2
-rw-r--r--src/cave.c5055
-rw-r--r--src/cmd1.c5125
-rw-r--r--src/cmd2.c5107
-rw-r--r--src/cmd3.c2331
-rw-r--r--src/cmd4.c4658
-rw-r--r--src/cmd5.c2562
-rw-r--r--src/cmd6.c7731
-rw-r--r--src/cmd7.c7652
-rw-r--r--src/cmovie.c496
-rw-r--r--src/config.h314
-rw-r--r--src/defines.h4695
-rw-r--r--src/dungeon.c5664
-rw-r--r--src/dungeon.pkg1607
-rw-r--r--src/externs.h1851
-rw-r--r--src/files.c6058
-rw-r--r--src/gen_evol.c156
-rw-r--r--src/gen_maze.c294
-rw-r--r--src/generate.c8890
-rw-r--r--src/gods.c139
-rw-r--r--src/h-basic.h25
-rw-r--r--src/h-config.h274
-rw-r--r--src/h-define.h111
-rw-r--r--src/h-system.h138
-rw-r--r--src/h-type.h178
-rw-r--r--src/help.c23
-rw-r--r--src/init1.c11819
-rw-r--r--src/init2.c2918
-rw-r--r--src/iso/.cvsignore1
-rw-r--r--src/lauxlib.h100
-rw-r--r--src/levels.c234
-rw-r--r--src/loadsave.c3288
-rw-r--r--src/lua/.cvsignore2
-rw-r--r--src/lua/.gitignore2
-rw-r--r--src/lua/CMakeLists.txt11
-rw-r--r--src/lua/array.lua203
-rw-r--r--src/lua/basic.lua190
-rw-r--r--src/lua/class.lua85
-rw-r--r--src/lua/clean.lua74
-rw-r--r--src/lua/code.lua73
-rw-r--r--src/lua/container.lua311
-rw-r--r--src/lua/declaration.lua399
-rw-r--r--src/lua/define.lua72
-rw-r--r--src/lua/doit.lua73
-rw-r--r--src/lua/enumerate.lua93
-rw-r--r--src/lua/feature.lua72
-rw-r--r--src/lua/function.lua317
-rw-r--r--src/lua/lapi.c499
-rw-r--r--src/lua/lapi.h17
-rw-r--r--src/lua/lauxlib.c216
-rw-r--r--src/lua/lauxlib.h100
-rw-r--r--src/lua/lbaselib.c651
-rw-r--r--src/lua/lcode.c701
-rw-r--r--src/lua/lcode.h70
-rw-r--r--src/lua/ldblib.c188
-rw-r--r--src/lua/ldebug.c466
-rw-r--r--src/lua/ldebug.h21
-rw-r--r--src/lua/ldo.c385
-rw-r--r--src/lua/ldo.h33
-rw-r--r--src/lua/lfunc.c109
-rw-r--r--src/lua/lfunc.h24
-rw-r--r--src/lua/lgc.c353
-rw-r--r--src/lua/lgc.h18
-rw-r--r--src/lua/liolib.c710
-rw-r--r--src/lua/llex.c411
-rw-r--r--src/lua/llex.h72
-rw-r--r--src/lua/llimits.h205
-rw-r--r--src/lua/lmem.c150
-rw-r--r--src/lua/lmem.h42
-rw-r--r--src/lua/lobject.c125
-rw-r--r--src/lua/lobject.h204
-rw-r--r--src/lua/lopcodes.h168
-rw-r--r--src/lua/lparser.c1129
-rw-r--r--src/lua/lparser.h60
-rw-r--r--src/lua/lstate.c121
-rw-r--r--src/lua/lstate.h77
-rw-r--r--src/lua/lstring.c155
-rw-r--r--src/lua/lstring.h37
-rw-r--r--src/lua/lstrlib.c621
-rw-r--r--src/lua/ltable.c303
-rw-r--r--src/lua/ltable.h34
-rw-r--r--src/lua/ltests.c543
-rw-r--r--src/lua/ltm.c163
-rw-r--r--src/lua/ltm.h59
-rw-r--r--src/lua/lua.h248
-rw-r--r--src/lua/lua2c.lua29
-rw-r--r--src/lua/luadebug.h46
-rw-r--r--src/lua/lualib.h34
-rw-r--r--src/lua/lundump.c244
-rw-r--r--src/lua/lundump.h35
-rw-r--r--src/lua/lvm.c710
-rw-r--r--src/lua/lvm.h32
-rw-r--r--src/lua/lzio.c84
-rw-r--r--src/lua/lzio.h53
-rw-r--r--src/lua/module.lua69
-rw-r--r--src/lua/operator.lua111
-rw-r--r--src/lua/package.lua222
-rw-r--r--src/lua/print.h55
-rw-r--r--src/lua/tolua.c149
-rw-r--r--src/lua/tolua.h127
-rw-r--r--src/lua/tolua_bd.c214
-rw-r--r--src/lua/tolua_eh.c66
-rw-r--r--src/lua/tolua_eh.h24
-rw-r--r--src/lua/tolua_gp.c197
-rw-r--r--src/lua/tolua_lb.c160
-rw-r--r--src/lua/tolua_rg.c243
-rw-r--r--src/lua/tolua_rg.h22
-rw-r--r--src/lua/tolua_tm.c585
-rw-r--r--src/lua/tolua_tm.h32
-rw-r--r--src/lua/tolua_tt.c316
-rw-r--r--src/lua/tolua_tt.h31
-rw-r--r--src/lua/tolualua.c2975
-rw-r--r--src/lua/tolualua.h2713
-rw-r--r--src/lua/tolualua.pkg21
-rw-r--r--src/lua/typedef.lua59
-rw-r--r--src/lua/variable.lua192
-rw-r--r--src/lua/verbatim.lua77
-rw-r--r--src/lua_bind.c691
-rwxr-xr-xsrc/maid-x11.c855
-rw-r--r--src/main-crb.c6402
-rw-r--r--src/main-gcu.c1222
-rw-r--r--src/main-gtk2.c5026
-rw-r--r--src/main-sdl.c2253
-rw-r--r--src/main-sla.c455
-rw-r--r--src/main-win.c4368
-rw-r--r--src/main-x11.c3210
-rw-r--r--src/main-xaw.c1888
-rw-r--r--src/main-xxx.c785
-rw-r--r--src/main.c691
-rw-r--r--src/melee1.c3065
-rw-r--r--src/melee2.c7591
-rw-r--r--src/modules.c274
-rw-r--r--src/monster.pkg2324
-rw-r--r--src/monster1.c1908
-rw-r--r--src/monster2.c4054
-rw-r--r--src/monster3.c706
-rw-r--r--src/notes.c188
-rw-r--r--src/object.pkg1169
-rw-r--r--src/object1.c6669
-rw-r--r--src/object2.c6617
-rw-r--r--src/player.pkg3519
-rw-r--r--src/player_c.pkg1060
-rw-r--r--src/plots.c473
-rw-r--r--src/plots.h48
-rw-r--r--src/powers.c1388
-rw-r--r--src/q_betwen.c188
-rw-r--r--src/q_dragons.c150
-rw-r--r--src/q_eol.c195
-rw-r--r--src/q_evil.c117
-rw-r--r--src/q_haunted.c147
-rw-r--r--src/q_hobbit.c195
-rw-r--r--src/q_invas.c201
-rw-r--r--src/q_main.c176
-rw-r--r--src/q_narsil.c108
-rw-r--r--src/q_nazgul.c116
-rw-r--r--src/q_nirna.c109
-rw-r--r--src/q_one.c354
-rw-r--r--src/q_poison.c238
-rw-r--r--src/q_rand.c465
-rw-r--r--src/q_shroom.c293
-rw-r--r--src/q_spider.c108
-rw-r--r--src/q_thief.c172
-rw-r--r--src/q_thrain.c230
-rw-r--r--src/q_troll.c178
-rw-r--r--src/q_ultrae.c11
-rw-r--r--src/q_ultrag.c276
-rw-r--r--src/q_wight.c156
-rw-r--r--src/q_wolves.c130
-rwxr-xr-xsrc/quest.pkg170
-rw-r--r--src/randart.c476
-rw-r--r--src/readdib.c342
-rw-r--r--src/readdib.h21
-rw-r--r--src/script.c535
-rw-r--r--src/skills.c1661
-rw-r--r--src/spells.pkg2448
-rw-r--r--src/spells1.c9327
-rw-r--r--src/spells2.c8076
-rw-r--r--src/squeltch.c553
-rw-r--r--src/status.c773
-rw-r--r--src/store.c4458
-rw-r--r--src/tables.c4792
-rw-r--r--src/traps.c3169
-rw-r--r--src/types.h2522
-rw-r--r--src/util.c4479
-rw-r--r--src/util.pkg2683
-rw-r--r--src/variable.c1604
-rw-r--r--src/wild.c1275
-rw-r--r--src/wizard1.c2756
-rw-r--r--src/wizard2.c1950
-rw-r--r--src/xtra1.c4772
-rw-r--r--src/xtra2.c6158
-rw-r--r--src/z-form.c831
-rw-r--r--src/z-form.h54
-rw-r--r--src/z-rand.c355
-rw-r--r--src/z-rand.h96
-rw-r--r--src/z-term.c2776
-rw-r--r--src/z-term.h343
-rw-r--r--src/z-util.c234
-rw-r--r--src/z-util.h91
-rw-r--r--src/z-virt.c187
-rw-r--r--src/z-virt.h168
-rw-r--r--src/z_pack.pkg398
-rw-r--r--tome.ini94
1170 files changed, 517139 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..d7793155
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+*.o
+*.~*
+*.#*
+CMakeFiles
+CMakeCache.txt
+cmake_install.cmake
+install_manifest.txt
+Makefile
diff --git a/BUGS.txt b/BUGS.txt
new file mode 100644
index 00000000..9a88aaed
--- /dev/null
+++ b/BUGS.txt
@@ -0,0 +1,6 @@
+Known Bugs:
+===========
+
+- If you save the game during the Thieves Quest in Bree, it will not be able to load.
+- Under Linux the X11 front-end does not work properly when NumLock is on.
+- Using modules: Automatizer save (+ note save, etc.) don't autocreate the module directory in the save directory hierarchy...
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..72cd53ec
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,108 @@
+# Project definition.
+PROJECT (tome2)
+CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
+
+# We want a readable feature summary.
+INCLUDE(FeatureSummary)
+
+# Default flags.
+IF(CMAKE_COMPILER_IS_GNUCC)
+ # Let's set sensible options.
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -Wall -Wno-unused-value")
+ SET(CMAKE_C_FLAGS_RELEASE "-O2")
+ SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+ENDIF()
+
+# Add definitions.
+ADD_DEFINITIONS(-DUSE_PRECISE_CMOVIE)
+
+#
+# X11 support (OPTIONAL)
+#
+FIND_PACKAGE(X11)
+IF(X11_FOUND)
+ # Add X11 flags/options
+ ADD_DEFINITIONS(-DUSE_X11)
+ INCLUDE_DIRECTORIES(${X11_INCLUDE_DIR})
+ SET(LIBS ${LIBS} ${X11_LIBRARIES})
+ENDIF()
+
+#
+# GTK2 support (OPTIONAL)
+#
+FIND_PACKAGE(GTK2)
+IF(GTK2_FOUND)
+ # Add GTK flags/options
+ ADD_DEFINITIONS(-DUSE_GTK2)
+ INCLUDE_DIRECTORIES(${GTK2_INCLUDE_DIRS})
+ SET(LIBS ${LIBS} ${GTK2_LIBRARIES})
+ENDIF()
+
+#
+# SDL support (OPTIONAL)
+#
+FIND_PACKAGE(SDL)
+IF(SDL_FOUND)
+ # This is a bit roundabout, but we're working around
+ # the FindSDL_* scripts not respecting the REQUIRED
+ # flag.
+ #
+ # the SDL port also requires SDL_image and SDL_ttf
+ FIND_PACKAGE(SDL_image)
+ FIND_PACKAGE(SDL_ttf)
+ IF(SDLIMAGE_FOUND AND SDLTTF_FOUND)
+ # Add SDL flags/options
+ ADD_DEFINITIONS(-DUSE_SDL)
+ INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR} ${SDLIMAGE_INCLUDE_DIR} ${SDLTTF_INCLUDE_DIR})
+ SET(LIBS ${LIBS} ${SDLIMAGE_LIBRARY} ${SDLTTF_LIBRARY} ${SDL_LIBRARY} m)
+ ELSE()
+ # Let user know that (and why) we haven't enabled SDL.
+ IF(SDLIMAGE_FOUND)
+ MESSAGE(STATUS "Found SDL and SDL_image, but not SDL_ttf!")
+ ELSEIF(SDLTTF_FOUND)
+ MESSAGE(STATUS "Found SDL and SDL_ttf, but not SDL_image!")
+ ELSE()
+ MESSAGE(STATUS "Found SDL, but not SDL_image nor SDL_ttf!")
+ ENDIF()
+ # add info about finding but not enabling SDL
+ SET_FEATURE_INFO(SDL "not enabled")
+ ENDIF()
+ENDIF()
+
+#
+# Curses support (OPTIONAL)
+#
+FIND_PACKAGE(Curses)
+IF(CURSES_FOUND)
+ # Add Curses flags/options
+ ADD_DEFINITIONS(-DUSE_GCU)
+ INCLUDE_DIRECTORIES(${CURSES_INCLUDE_DIR})
+ SET(LIBS ${LIBS} ${CURSES_LIBRARIES})
+ENDIF()
+
+#
+# Windows support
+#
+if(WIN32)
+ # Add Windows flags/options
+ ADD_DEFINITIONS(-DWINDOWS)
+ SET(EXECUTABLE_OPTIONS WIN32)
+ SET(LIBS ${LIBS} winmm wsock32)
+endif(WIN32)
+
+#
+# Set the path for loading the library bits.
+#
+IF(SYSTEM_INSTALL)
+ SET(DEFAULT_PATH "/var/games/tome")
+ELSE()
+ SET(DEFAULT_PATH "./lib")
+ENDIF()
+ADD_DEFINITIONS(-DDEFAULT_PATH="${DEFAULT_PATH}")
+
+# Print out a summary of features.
+PRINT_ENABLED_FEATURES()
+
+# Add the source subdirectory.
+ADD_SUBDIRECTORY (src)
+ADD_SUBDIRECTORY (lib)
diff --git a/DEBUG.txt b/DEBUG.txt
new file mode 100644
index 00000000..f7146c28
--- /dev/null
+++ b/DEBUG.txt
@@ -0,0 +1,8 @@
+Debugging
+=========
+
+To turn on Debug mode when compiling run cmake with the
+
+ -DCMAKE_BUILD_TYPE=Debug
+
+parameter.
diff --git a/README.txt b/README.txt
new file mode 100644
index 00000000..1e0ad583
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,85 @@
+Using the CMake build system
+============================
+
+There are basically two options for how to run ToME once built.
+
+
+
+Option #1 : Run ToME from the build directory
+=============================================
+
+Simply run the commands below.
+
+ $ cmake .
+ $ make
+
+You should now be able to run
+
+ $ ./src/tome
+
+to start ToME.
+
+This is currently the recommended option.
+
+
+
+Option #2: Run ToME from a system install location
+==================================================
+
+Run
+
+ $ cmake -DSYSTEM_INSTALL:BOOL=true .
+ $ make
+ $ sudo make install
+
+You can now run ToME from anywhere.
+
+You can also use DESTDIR when installing to a different location
+(useful with e.g. stow or when building distribution packages).
+
+
+Compiling on Ubuntu
+===================
+
+If you're having trouble compiling on an Ubuntu install you are
+probably missing the
+
+ build-essential
+
+package.
+
+Each frontend requires the additional packages listed below:
+
+ X11: libx11-dev
+ SDL: libsdl-image1.2-dev, libsdl-ttf2.0-dev
+ ncurses: libncurses5-dev
+
+
+Compiling on OpenBSD
+====================
+
+As of February 2010, the OpenBSD package cmake-2.4.8p2 is too old for
+building ToME. You may need to compile a newer version of CMake.
+
+If you have X11, then a bug in CMake may cause a linker error when
+linking the 'tome' executable. As a workaround, set the environment
+variable LDFLAGS=-L/usr/X11R6/lib when running CMake. Example:
+
+ $ env LDFLAGS=-L/usr/X11R6/lib cmake .
+ $ make
+
+The SDL frontend also requires these packages: sdl-image, sdl-ttf
+
+
+Compiling on Windows using MinGW
+================================
+
+(See http://www.mingw.org/)
+
+The source MUST be unpacked in a directory without spaces in the
+name.
+
+To compile on Windows using MinGW, use the commands
+
+ $ cmake -G "MinGW Makefiles"
+ $ mingw32-make
diff --git a/angdos.cfg b/angdos.cfg
new file mode 100644
index 00000000..d541b389
--- /dev/null
+++ b/angdos.cfg
@@ -0,0 +1,634 @@
+# File: angdos.cfg
+
+#
+# This file contains configuration data for Angband when compiled
+# (and run) with the "main-dos.c" file.
+#
+# It may also contain configuration data for the Allegro library,
+# which should (perhaps) precede the Angband configuration data.
+#
+
+
+#
+# Optional: graphics driver (Allegro)
+#
+# 1 = VGA mode 13h 2 = Mode-X
+# 3 = VESA 1.x 4 = VBE 2.0 (banked)
+# 5 = VBE 2.0 (linear) 6 = VBE/AF
+# 7 = Xtended mode 8 = ATI 18800/28800
+# 9 = ATI mach64 10 = Cirrus 64xx
+# 11 = Cirrus 54xx 12 = Paradise
+# 13 = S3 14 = Trident
+# 15 = Tseng ET3000 16 = Tseng ET4000
+# 17 = Video-7
+#
+### gfx_card =
+
+########### Sound-support settings ##########
+
+[sound]
+# Section containing sound configuration information, using the variables:
+# digi_card = x
+# Sets the driver to use for playing samples, where x is one of the values:
+# 0 = none 1 = SB (autodetect breed)
+# 2 = SB 1.0 3 = SB 1.5
+# 4 = SB 2.0 5 = SB Pro
+# 6 = SB16 7 = GUS (unfinished)
+
+# midi_card = x
+# Sets the driver to use for MIDI music, where x is one of the values:
+# 0 = none 1 = Adlib (autodetect OPL version)
+# 2 = OPL2 3 = Dual OPL2 (SB Pro-1)
+# 4 = OPL3 5 = SB MIDI interface
+# 6 = MPU-401 7 = GUS (unfinished)
+# 8 = DIGMID 9 = AWE32
+
+# digi_voices = x
+# Specifies the minimum number of voices to reserve for use by the digital
+# sound driver. How many are possible depends on the driver.
+
+# midi_voices = x
+# Specifies the minimum number of voices to reserve for use by the MIDI sound
+# driver. How many are possible depends on the driver.
+
+# flip_pan = x
+# Toggling this between 0 and 1 reverses the left/right panning of samples,
+# which might be needed because some SB cards get the stereo image the
+# wrong way round.
+
+# sb_port = x
+# Sets the port address of the SB (this is usually 220).
+
+# sb_dma = x
+# Sets the DMA channel for the SB (this is usually 1).
+
+# sb_irq = x
+# Sets the IRQ for the SB (this is usually 7).
+
+# sb_freq = x
+# Sets the sample frequency, which defaults to 16129. Possible values are:
+# 11906 - works with any SB
+# 16129 - works with any SB
+# 22727 - on SB 2.0 and above
+# 45454 - only on SB 2.0 or SB16 (not the stereo SB Pro driver)
+
+# fm_port = x
+# Sets the port address of the OPL synth (this is usually 388).
+
+# mpu_port = x
+# Sets the port address of the MPU-401 MIDI interface (this is usually 330).
+
+
+# Volume Settings:
+digi_volume = 0
+midi_volume = 0
+
+########### General Angband settings ##########
+
+[Angband]
+Graphics = 0
+Sound = 0
+
+Resolution = 2
+
+########### Screen Resolution 640 x 480 ##########
+
+[Mode-1]
+screen_wid = 640
+screen_hgt = 480
+
+Description =
+
+bitmap_wid = 8
+bitmap_hgt = 8
+
+bitmap_file = 8x8.gif
+
+num_windows = 3
+
+[Term-1-0]
+
+x = 0
+y = 0
+
+cols = 80
+rows = 24
+
+tile_wid = 8
+tile_hgt = 13
+
+font_wid = 8
+font_hgt = 13
+
+font_file = xm8x13b.fnt
+
+[Term-1-1]
+
+x = 0
+y = 336
+
+cols = 80
+rows = 24
+
+tile_wid = 4
+tile_hgt = 6
+
+font_wid = 4
+font_hgt = 6
+
+font_file = xm4x6.fnt
+
+[Term-1-2]
+
+x = 320
+y = 336
+
+cols = 80
+rows = 24
+
+tile_wid = 4
+tile_hgt = 6
+
+font_wid = 4
+font_hgt = 6
+
+font_file = xm4x6.fnt
+
+
+########### Screen Resolution 640 x 480 ##########
+
+[Mode-2]
+screen_wid = 640
+screen_hgt = 480
+
+Description = with new graphics
+
+bitmap_wid = 16
+bitmap_hgt = 16
+
+bitmap_file = 16x16.gif
+
+graf-mode = new
+
+num_windows = 3
+
+[Term-2-0]
+
+x = 0
+y = 0
+
+cols = 80
+rows = 24
+
+tile_wid = 8
+tile_hgt = 13
+
+font_wid = 8
+font_hgt = 13
+
+font_file = xm8x13b.fnt
+
+[Term-2-1]
+
+x = 0
+y = 336
+
+cols = 80
+rows = 24
+
+tile_wid = 4
+tile_hgt = 6
+
+font_wid = 4
+font_hgt = 6
+
+font_file = xm4x6.fnt
+
+[Term-2-2]
+
+x = 320
+y = 336
+
+cols = 80
+rows = 24
+
+tile_wid = 4
+tile_hgt = 6
+
+font_wid = 4
+font_hgt = 6
+
+font_file = xm4x6.fnt
+
+
+########## Screen Resolution 800 x 600 ##########
+
+[Mode-3]
+screen_wid = 800
+screen_hgt = 600
+
+Description =
+
+bitmap_wid = 8
+bitmap_hgt = 8
+
+bitmap_file = 8x8.gif
+
+num_windows = 3
+
+[Term-3-0]
+
+x = 0
+y = 0
+
+cols = 80
+rows = 24
+
+tile_wid = 10
+tile_hgt = 17
+
+font_wid = 10
+font_hgt = 17
+
+font_file = xm10x17.fnt
+
+[Term-3-1]
+
+x = 0
+y = 408
+
+cols = 80
+rows = 24
+
+tile_wid = 5
+tile_hgt = 8
+
+font_wid = 5
+font_hgt = 8
+
+font_file = xm5x8.fnt
+
+[Term-3-2]
+
+x = 400
+y = 408
+
+cols = 80
+rows = 24
+
+tile_wid = 5
+tile_hgt = 8
+
+font_wid = 5
+font_hgt = 8
+
+font_file = xm5x8.fnt
+
+
+########## Screen Resolution 800 x 600 ##########
+
+[Mode-4]
+screen_wid = 800
+screen_hgt = 600
+
+Description = with new graphics
+
+bitmap_wid = 16
+bitmap_hgt = 16
+
+bitmap_file = 16x16.gif
+
+graf-mode = new
+
+num_windows = 3
+
+[Term-4-0]
+
+x = 0
+y = 0
+
+cols = 80
+rows = 24
+
+tile_wid = 10
+tile_hgt = 17
+
+font_wid = 10
+font_hgt = 17
+
+font_file = xm10x17.fnt
+
+[Term-4-1]
+
+x = 0
+y = 408
+
+cols = 80
+rows = 24
+
+tile_wid = 5
+tile_hgt = 8
+
+font_wid = 5
+font_hgt = 8
+
+font_file = xm5x8.fnt
+
+[Term-4-2]
+
+x = 400
+y = 408
+
+cols = 80
+rows = 24
+
+tile_wid = 5
+tile_hgt = 8
+
+font_wid = 5
+font_hgt = 8
+
+font_file = xm5x8.fnt
+
+
+########## Screen Resolution 1024 x 768 ##########
+
+[Mode-5]
+screen_wid = 1024
+screen_hgt = 768
+
+Description =
+
+bitmap_wid = 8
+bitmap_hgt = 8
+
+bitmap_file = 8x8.gif
+
+num_windows = 3
+
+[Term-5-0]
+
+x = 0
+y = 0
+
+cols = 80
+rows = 24
+
+tile_wid = 12
+tile_hgt = 20
+
+font_wid = 12
+font_hgt = 20
+
+font_file = xm12x20.fnt
+
+[Term-5-1]
+
+x = 0
+y = 480
+
+cols = 80
+rows = 24
+
+tile_wid = 6
+tile_hgt = 12
+
+font_wid = 6
+font_hgt = 12
+
+font_file = xm6x12.fnt
+
+[Term-5-2]
+
+x = 481
+y = 480
+
+cols = 80
+rows = 24
+
+tile_wid = 6
+tile_hgt = 12
+
+font_wid = 6
+font_hgt = 12
+
+font_file = xm6x12.fnt
+
+
+########## Screen Resolution 1024 x 768 ##########
+
+[Mode-6]
+screen_wid = 1024
+screen_hgt = 768
+
+Description = with new graphics
+
+bitmap_wid = 16
+bitmap_hgt = 16
+
+bitmap_file = 16x16.gif
+
+graf-mode = new
+
+num_windows = 3
+
+[Term-6-0]
+
+x = 0
+y = 0
+
+cols = 80
+rows = 24
+
+tile_wid = 12
+tile_hgt = 20
+
+font_wid = 12
+font_hgt = 20
+
+font_file = xm12x20.fnt
+
+[Term-6-1]
+
+x = 0
+y = 480
+
+cols = 80
+rows = 24
+
+tile_wid = 6
+tile_hgt = 12
+
+font_wid = 6
+font_hgt = 12
+
+font_file = xm6x12.fnt
+
+[Term-6-2]
+
+x = 481
+y = 480
+
+cols = 80
+rows = 24
+
+tile_wid = 6
+tile_hgt = 12
+
+font_wid = 6
+font_hgt = 12
+
+font_file = xm6x12.fnt
+
+
+########## Screen Resolution 1280 x 1024 ##########
+
+[Mode-7]
+screen_wid = 1280
+screen_hgt = 1024
+
+Description =
+
+bitmap_wid = 8
+bitmap_hgt = 8
+
+bitmap_file = 8x8.gif
+
+num_windows = 3
+
+[Term-7-0]
+
+x = 0
+y = 0
+
+cols = 80
+rows = 24
+
+tile_wid = 16
+tile_hgt = 25
+
+font_wid = 16
+font_hgt = 25
+
+font_file = xm16x25.fnt
+
+[Term-7-1]
+
+x = 0
+y = 610
+
+cols = 80
+rows = 24
+
+tile_wid = 8
+tile_hgt = 16
+
+font_wid = 8
+font_hgt = 16
+
+font_file = xm8x16.fnt
+
+[Term-7-2]
+
+x = 640
+y = 610
+
+cols = 80
+rows = 24
+
+tile_wid = 8
+tile_hgt = 16
+
+font_wid = 8
+font_hgt = 16
+
+font_file = xm8x16.fnt
+
+
+########## Screen Resolution 1280 x 1024 ##########
+
+[Mode-8]
+screen_wid = 1280
+screen_hgt = 1024
+
+Description = with new graphics
+
+bitmap_wid = 16
+bitmap_hgt = 16
+
+bitmap_file = 16x16.gif
+
+graf-mode = new
+
+num_windows = 3
+
+[Term-8-0]
+
+x = 0
+y = 0
+
+cols = 80
+rows = 24
+
+tile_wid = 16
+tile_hgt = 25
+
+font_wid = 16
+font_hgt = 25
+
+font_file = xm16x25.fnt
+
+[Term-8-1]
+
+x = 0
+y = 610
+
+cols = 80
+rows = 24
+
+tile_wid = 8
+tile_hgt = 16
+
+font_wid = 8
+font_hgt = 16
+
+font_file = xm8x16.fnt
+
+[Term-8-2]
+
+x = 640
+y = 610
+
+cols = 80
+rows = 24
+
+tile_wid = 8
+tile_hgt = 16
+
+font_wid = 8
+font_hgt = 16
+
+font_file = xm8x16.fnt
+
+########### Background settings ##########
+
+[Background]
+# Background-0 : Standard background
+# Background-1 : inven/equip
+# Background-2 : equip/inven
+# Background-3 : player (basic)
+# Background-4 : player (extra)
+# Background-5 : XXX
+# Background-6 : XXX
+# Background-7 : messages
+# Background-8 : overhead view
+# Background-9 : monster recall
+# Background-10 : object recall
+# Background-11 : XXX
+# Background-12 : snap-shot
+# Background-13 : XXX
+# Background-14 : XXX
+# Background-15 : borg messages
+# Background-16 : borg status
+
+Background-0 = backgrnd.gif
diff --git a/changes.old b/changes.old
new file mode 100644
index 00000000..dabf85a0
--- /dev/null
+++ b/changes.old
@@ -0,0 +1,6027 @@
+24/10/1998 - PernAngband 2.9.9a
+- Added the DragonRider from the Anne McCaffrey's Books, masters of
+ teleportation.
+- The CTRL+l key leaves the game without saving
+- Added the Tanker point, like the mana point, but can only be refilled
+ by eating the Firestone (for DragonRiders)
+- Added the RohanKnight race, fast and wise
+- Added the Ent race, can grow trees, but slow
+- Removed some races from Zangband which were not enough tolkienian...
+- Added the BeastMaster class which can summon pets
+- Added the Blood of Life
+- DragonRider now can choose to breathe a bolt, a beam or a ball
+- Added the Unique level patch from Glenn Vanzanden
+- Added the Mage Staves , with new ego items:
+ -of Mana : multiply your max mana
+ -of Spell : Increase your spell power
+ -of Mana & Spell : try to find !:)
+ -of Power : Activate for some spell, they carry 2 spells
+ All the ego mage staves have a penalty to damage and to hit
+- Added The Mage Staff of Gandalf, extremely powerful but even rarer than
+ the One Ring !
+- Added the boots of jumping activatable for phase door every 10+d10 turns
+- Added Helm of the Dwarves and of the Noldor
+- Beastmasters' pets now give kill experience to the player
+- Added the Alchemist class which use power batteries to convert magic item
+- New unique level : Treasure room at level 11
+- Replaced the Trump Hound from the Trump realm by the Trump Home spell, which
+ allows the player to access to her/his home from everywhere in the dungeon
+- Added the new artifact The Ring of F'lar, which belonged to F'lar the
+ powerful DragonRider
+
+26/10/1998
+- Added potions of Mutation
+- Warrior-Mage now can choose Sorcery instead of Arcane
+- Invisibility, Potion of Invisibility, Ring of Invisibility and
+ The One Ring now has invisibility like in the Lord Of The Rings !!!
+- Added the parchments from Kamband
+
+30/10/1998
+- Ported PernAngband to the new Zangband 2.2.0
+- Added the mimic class
+- Some Zangband bugs are fixed
+- The DragonRider can now only teleport on known terrain, because they must
+ mentally show the destination to their dragons but to do this they MUST
+ have seen the destination before (like in the Anne McCaffrey books) !
+- The Ringwraiths are back!
+- Some uniques like Bert, Tom, Bill are back, while others (Gandalf, Fangorn)
+ are gone!
+- Morgoth and Sauron are back as the final quests
+
+01/11/1998 - PernAngband 3.0.0
+- All reference to Zangband have been removed
+- Added monster corpses
+- Added the Beastmaster Shanty for the beastmaster, the Mimic Tower for the
+ Mimic, and the Weaver Tower, where you can ask for corpse quests
+- The corpse quests require you to bring back to the weaver some corpse,
+ head,... of a kind of monster, and you'll get a reward, like maybe
+ the full knowledge about this monster, or some armor made with the corpse
+ (maybe dragon scale mail for dragon, ...)
+- Added susceptibility to fire, for the Ents! They take twice more damage from
+ fire, but it's hopefully cancelled by resist fire.
+- Changed some artifacts / unique monsters to be more pernish
+- Added a new armor type : the DragonRider flying suit[9,+0] resist fire/cold
+- New monster flag : PET , the monster is your pet when it's created
+- Added the army man which use the PET flag will be used to give you an army
+ in some future quest.
+
+03/11/1998
+- The exe file is now pernang.exe(in the dos version)
+- Replaced the AMBERITE monster flag by the DRAGONRIDER flag
+- Some Unique will have the PET flag so they will help you !
+- All the Amberite are now gone and replaced by DragonRiders or uniques
+ (with some of them friendly)
+- Can sell the Mage staves in the Weapon smith and Magic shop.
+- Now when an alchemist tries to extract a power from an item, if he can't
+ it won't show up again in the extractable list the next time
+- The DragonRider must eat more because of their dragon
+- The Troll Fortress quest
+- Added The Battle of the five armies quest !!!
+
+05/11/1998
+- Nature spell : Stop breeders
+- New ego item sword of life, it multiplies your max hitpoints
+- Now some Mimic forms give you bonuses to blows per round like the Vala:
+ +5 blows !!!
+- Added a new Unique : The Philosophy Teacher !
+- Pink horrors are replaced with 2 Blue horrors when they die
+- Bloodletters of Khorne drop a blade of chaos when they die
+- Absorb light mutation bug fixed (I think)
+- Vampires and vampire mimics no longer can get food in the inns.
+- Renamed the artifacts with their real names
+- Replaced the pattern by the Straight Road (idea from GSN-Band)
+- Replaced the pattern weapons with weapons of Valinor (idea from GSN-Band)
+- Player and monsters can't pass through the trees (unless they can fly:)
+- When a Dragonrider dies he drops some firestones
+- Added the Whip of Gothmog, which can be dropped by Gothmog when killed
+- Begin to add a new feature : the between
+- Add a great description of the Ents and the Rohan's Knights from Akhronath
+
+07/11/1998
+- The between is fully implemented now.
+- The dimension door spell is replaced by the between gate.
+ It put a between gate at the player position and at the destination
+ location. And when you walk on the between you are transported on the other
+ between gate. But the between is SO cold that when you are in you lose some
+ hp even if resistant or immune to cold! Only the dragonrider can go between
+ without taking damage.
+- Stole the Stone of Lore from Oangband ! :)
+- Monsters can't use the between now because of a bug
+- Now you can eat corpses and temporarily gain some of the powers of monsters!
+- Raise Death replaces Terror in the death realm, cast it on a monster corpse
+ on the floor and the monster is brought back to life!
+
+09/11/1998
+- Added the boomerang, the player wears them instead of the bow and with the 'f'
+ command (like for the bow) can throw them but them come back ... if they don't
+ break !
+- Add 2 boomerang artifacts
+- Add another dragonrider artifact belonging to Mardra
+- Add The Anchor of Space-Time, it prevents disruption of the space-time
+ continuum
+
+11/11/1998
+- Add the carry slot in the equipment, to wield monsters that can't move :)
+- Fixed a bug that prevented dragonriders from being summoned
+- Add a Neuter sex (for the neuter players) :-)
+- Add the Death Mold race (stolen from Kamband) :-)
+
+13/11/1998
+- Add in spell description the bonus of mage staves
+- Add the scroll of summon never-moving pet for wielding them !:)
+- When a monster is wielded it can attack monsters when you attack
+ It can sometimes attack the wielder too, because he/she is not in perfect
+ symbiosis
+- Muar the balrog is back and will drop Calris when killed
+- Add the Symbiotic realm, like a life realm for your monster
+- Add the Symbiant class which can be in perfect symbiosis with their monster
+
+15/11/1998
+- The number of artifacts is now 132
+- Add some spells to the symbiotic realm
+- Add a spell to use the spells of the monster you wear
+- Add a light-speed (nearly stop time) spell
+- Finished the Symbiotic realm, only two books because they can use their
+ monster's powers.
+
+18/11/1998
+- Warriors can now spread their attacks after level 34
+- The experience factor of the races can now be > than 255
+- The DragonRider need more experience to advance (+220%) because it's a REALLY
+ powerful race.
+- Monsters can now use the between but if they are not immune to cold they
+ will lose some hp
+- Added a health bar for the monster you are carrying ( MH xxxxx/xxxxx )
+- Added sanity (from Kamband) ( the line SN xxxxx/xxxxx in the window)
+- Stolen the aquatic monsters from Kamband
+- Add the Gods from Kamband and GSNBand
+- The Philosophy Teacher now causes insanity !:)
+- Now only the Symbiants can carry monsters in their inventory, in fact they
+ act like "living-books" !:)
+- Add the Tactics from ADOM. You can change the tactic in the Character window
+- Add a new town unique : Mathilde, the science student, she is in my class
+ and giggles all the time, don't kill her ! :)
+- Fixed bug : The carried monster cannot absorb damage done by itself !
+- The Battle of the five armies now has a reward (The Arkenstone)
+
+20/11/1998 - PernAngband 3.0.2
+- Now there will be some between gates randomly placed in the levels
+- If you are in great favor with your god they can resurrect you
+
+22/11/1998
+- Add Random artifacts from Kamband - They are junk items which can be
+ activated every few turns and their activation is chosen randomly
+- Fixed (I think) a bug in the unique levels
+- Add a flooded level type (enable those levels in the PernAngband options)
+ to make the aquatic monsters more useful
+- Gandalf and Fangorn are back as Friendly uniques
+- Changed the Necklace of the Dwarves into The Nauglamir to be more
+ Tolkien-like
+- Changed The Serpent of the Chaos into Dark God, Mighty Coder from Hell :)
+- Reworked the corpse system (stolen from Rangband), now they all have
+ different weights based on the monster weight. You can hack up the corpse
+ with 'h' and cure it with 'K'.
+
+24/11/1998
+- Add a new Unique : The Physics Teacher !
+- Changed the Town layout of Gondolin with the one made by Akhronath
+ with 2 quests : Hunt for Eol and Maeglin's Mine
+- Add a new Unique : Eol the Dark Elf
+- Stole the silly messages when you hit a monster from Kamband
+
+26/11/1998
+- Add a scroll of Craftmanship to enchant weapon's pval.
+- The first 300 monsters have received a weight
+- Add a new spell type : Identify, now you can have a Ball of identification !
+- Add a new set of object flags (mainly unused now) :-)
+- Add a NEVER_BLOW flag for object
+- Add the NEVER_BLOW flag to The Mage Staff of Gandalf to rebalance it.
+- Add a new ego item weapon : of Nothing (with the NEVER_BLOW flag) !! :)
+
+29/11/1998
+- Add a Harper (bard) class !!! they use music books and most
+ of their spells are prolonged in time, ex: you cast a hiding song,
+ and for each turn you lose some mana (breath) while the effect (invisibility)
+ continues. If you start singing another song the old one is stopped.
+ There is also a spell which costs no mana which is used to stop singing.
+- Stolen the *Defender* ego-item from Pziband
+- Stolen the Spectral ego-item from Pziband
+
+01/12/1998
+- Added musical instruments : you wear them in the bow slot and you can
+ activate them for a song. The longer the song lasts the longer it'll be
+ charging, you can stop the song by activating it when it sing.
+- Finished the Harpers
+- Now the Harper mana stat is Charisma !
+- New Artifact : The Palantir of Minas Tirith, which can be activated for
+ the list of the uniques of the level !
+- Added 3 new artifacts : The Harp of Master Robinton, The Drum of Piemur,
+ The Flute of Menolly
+- Added the Micro$oft quest at Minas Anor
+- Changed the niceness description of the gods
+- The Harper and ONLY the harper can use a musical instrument without any
+ chance of failure.
+- The wilderness size is now taken from misc.txt
+- All the monsters have a weight now ... pfff, it was a lot of work !:)
+- The Alchemists are easier to play
+- Add the Vapor quest at Minas Anor
+- Add the Rebellion in Gondolin(from Akhronath) quest at Gondolin
+
+02/12/1998 - PernAngband 3.0.4
+- Changed certain god realm name on the suggestion of Akhronath
+- Add the bounties list like in Kamband (OK, ok, stolen from Kamband) :)
+- Add the Fire-lizards, they are friendly
+- New roguelike command : 'i' for hack up corpse, 'I' for curing meat, 'C'
+ for Sacrificing at altars
+
+05/12/1998
+- Add the Power Mage class, like the Corrupted in Kamband, with 100 randomly
+ generated attack spells
+- Corrected the character generation bug !!!! Thanks to Tim Baker for the fix
+- Corrected the segmentation fault bug for the object 653. Thanks to Tim baker
+- Corrected the files.c bug in get_line(). Thanks to Tim baker
+- Add the GF_DESTRUCTION type of attack to allow Power Mage to have destruction
+- Changed the names of the songs, Thanks to Akhronath
+
+07/12/1998
+- Add the Eggs, some monsters (only Firelizards for the moment) can be found
+ as eggs and will hatch after a certain amount of time based on the monster
+ weight, you can also stop the development by "activating" them ('A' key),
+ or resume the development by activating them an other time.
+- Add the last of the Gondolin's quest from Akhronath :
+ Invasion of Gondolin (Danger level 90, with some funny stuff like Gothmog,
+ Muar,..., some Great hell wyrms) !!!
+- Fixed a bug which made it so when you drop your wielded monster you also
+ drop Nothing if you are not a Symbiant
+- You can imprint some monsters (Firelizards for now), when it has
+ been given an imprint it will follow you on each levels. They may not
+ appear on a certain level but they will be back for the next. To
+ imprint a monster you must find an egg, carry it on you and when it'll
+ hatch you'll give it the imprint
+- The Harper will begin the game with a Blue Firelizard egg
+
+09/12/1998
+- The Black market now generate items based on your level
+- Add a new shop : The Pet Shop where you can find some eggs
+
+12/12/1998
+- Your godly favor will go down when they resurrect you
+- Repaired a stupid bug : I haven't coded the Satisfy Hunger effect of the
+ Symbiant class !:)
+- Add the easy floor feature !!!
+- Add an always small dungeon option
+- The scrolls of Artifact Creation can now be used on rings and amulets
+
+15/12/1998
+- The One Ring is now "just" heavy cursed !:)
+- Add 3 new vaults
+
+18/12/1998
+- Add the fate : you can be fated to meet some monsters or to find an object
+ on a certain level or ..... to DIE (very rare). You don't know your
+ fate until a soothsayer or a scroll of divination shows it to you. You
+also get a feeling when entering a level where you will meet your fate.
+ In the future there will be more fates, like finding a great vault, an
+ artifact or even, as Murazor the Witch-King of Angmar, to never die by the
+ hands of a mortal !:)
+- Changed Trump Weapon to Dragon Weapon
+- Smeagol will now drop ......... A ring of invisibility (because the One Ring
+ would be a little too powerful :)
+
+23/12/1998
+- Replaced the Amber notation in the player characteristics by the old one
+ from Vanilla Angband
+- When the player is on a tree he can be hit by a monster for half
+ normal damage
+- Paladin and Priests are given a religion at the beginning
+- In the wizard spoiler creation (A + ") you can chose to make a spoiler for
+ batteries
+- The random artifacts now have a charging time (no more mass genocide every
+ turn)
+- Add a Soothsayer at Bree
+- Add the batteries of extra life, you can now make a sword of Life !
+
+25/12/1998
+- The Alchemists are now better fighters, equal to the rangers
+- New extremely powerful power for the Alchemist (level 30 and higher) :
+ Artifact creation !
+ They just have to chose the flags, the name and to suffer the bad side effect
+ like curse equipment, permanent stat loss, high failure rate and ..... they
+ have their artifact ! But they can't give it an activation !
+ They can also add some bad flags (like cursed, drain exp, ...) to reduce the
+ chance of failure. Merry Christmas ! :)
+- Add the Runecrafter class, they use runes instead of books (see birth.txt)
+- Cleaned the Alchemist's code
+
+27/12/1998 - PernAngband 3.0.7
+- Added (.... stolen from Sangband) the Pick of Erebor. It can be activated for
+ passing through secret passages in the walls.
+- The Potion of *Enlightenment* now show every grid of the dungeon, like the
+ debug command 'u', I just think it's more beautiful :)
+- WOOOOOOOH I'm sorry there was a BIG bug in the PernAngband 3.0.7 release.
+ The game was sometimes hanging without any solution to stop it !
+ After some hours of debugging I've found it, it resulted from the correction
+ of the bug of the glyph of warding! Now everything works (I hope)
+- Change the titles of the Runecrafter with the proposition of Jonathan R Lewis
+- Add TANG, The Angband Newbie Guide made by Chris Weisiger
+ (jmartin@inreach.com) It's in the help directory
+
+29/12/1998
+- Fixed a bug which allowed beastmasters to sing when they summon pets!
+- Fixed the bug in the Fate screen
+- Some cosmetic changes in the r_info.txt and birth.txt with the help of
+ Chris Weisiger (jmartin@inreach.com)
+- Add new ego-items for the musical instrument and the horn, there were
+ suggested by Akhronath
+- New sentence to say for the speaking unique pets
+- 4 new musical instrument artifacts from Akhronath and I'm happy to declare
+ there is 143 artifacts in PernAngband!
+- Added, .... stolen, 5 new artifact from Angband/64
+
+31/12/1998
+- Add the quiver slot to wield your ammo
+- A scroll of remove curse have 1 chance into (55-level) to reverse the curse
+ effect ie: a ring of speed (-2) can become a ring of speed (+2)
+
+01/01/1999
+- Add a new monster flag : MORTAL, which means that the monster is a mortal
+ being. It's used for the new fate : Never to die by the hand of a mortal
+ being. The orcs are considered mortal, but I'm not sure, it's not mentioned
+ in the silmarillion or the Lord of The Rings, the trolls are immortals along
+ with the dragons, BUT the Dragonriders are mortal and Dark God (Yes, let your
+ joy explode!) :-). But well, don't be afraid your preferred monsters
+ (Morgoth and Sauron) are immortals :-)
+ PS: If someone thinks that a monster should or not be mortal just email me
+ because I'm not certain for some (ok, ok a lot of) monsters
+
+03/01/1999
+- Add the ring of precognition which work as if the player had activated the
+ cheat mode (peek into object, monster, vault creation). There is no need
+ to say it's very rare :-)
+- Add the black breath concept from Tolkien. Beware now the weapons of morgul
+ they confer the black breath! The undead can also give it.
+
+05/01/1999
+- Changed the harpers ranking names, some racial histories with the ones from
+ Akhronath
+- The One Ring is now A LOT more powerful, because at the time you find it
+ you already have one or two immunities, your stats are near the max, plus
+ some other things that made it less useful. Now it confers 5 blows, mana x5
+ spell power x5, after all Sauron has put the most part of his power in it.
+ I also plan to change the activation.
+- Add 2 wand artifacts, The Wand of Stone to Mud of Thrain and the Wand of
+ Fire Balls of Mithrandir, they can be recharged at will and will never be
+ destroyed, for this purpose the new RECHARGE flags has been used (note :
+ it works only for the artifacts)
+
+07/01/1999
+- The runecaster is a little more playable at low levels and starts with a
+ Rune [Arrow] and a Rune [Fire]
+
+10/01/1999
+- The Chaos Warriors now get chaos resistance at level 25
+- The Maia mimics get +7 speed, the Vala mimics get +15 speed
+- Updated the Rebellion in Gondolin and Hunt for Eol quests with the help of
+ Akhronath (zzhou22876@aol.com)
+
+13/01/1999
+- Reimplemented the old magic system from vanilla to complement the new one
+ The old mage and priest are come back as the Wizard and the Prior
+
+17/01/1999
+- Add susceptibilities to fire, cold, acid, lightning, poison for the monsters.
+ ie: Now a white dragon will take a x3 damage from a fire attack.
+ Thanks to Jerome Wojcik <Jerome.Wojcik@lmcp.jussieu.fr> for his help.
+- Add the pets command (press P) from Zangband 2.2.3
+- Changed the Trump realm into the Dragon Realm (mainly just name changes)
+
+19/01/1999
+- Changed the activation of the One Ring
+- The One Ring is now Permanently cursed
+- The One Ring is no longer aggravating because of it's new summoning ability
+- It's now possible to run through the grass
+
+21/01/1999
+- Add the persistent dungeon option at birth
+- When a breeder multiplies it have a 7/100 chance of mutating into an other
+ monster. (in general a worse one) This would prevent monster farming abuse :)
+
+24/01/1999
+- NEW : the body changing feature! with a new class to use it. Your spirit
+ can leave your body to go into another one but while your spirit is alone
+ your max hp is of 1. When in the corpse of a monster your first blows are
+ the monster's one and you can use it's magical power. Your life is also
+ changed by the monster's one and you gain all it's abilities and resistances
+ while losing those of your real race because you have left your body.
+- Add a lot of new vaults mainly from Weisiger <jmartin@inreach.com>
+
+28/01/1999
+- Death Molds now can teleport onto store entrances
+- A new randart activation that fires light after absorbing the ambient one
+
+05/02/1999
+- Changed the Roguelike commands. Now ^G to sacrifice, $ to hack up a corpse
+ ^O to Cure meat
+- Updated the command.txt file
+- Add the AB's gfx for the weapon/armor
+- Multiple dungeons : The old levels 1-33 are now in the Mirkwood forest with
+ trees and grass, 34-66 are the Land of Mordor with mountain, wall and dirt
+ 67-127 are the Dungeon of Angband with wall and normal floor and occasionally
+ flooded levels (if chosen in the options).
+ The ability to levitate is now a GREAT advantage in the Mirkwood forest !
+ You can reach Mirkwood from Menegroth, Mordor from Minas Anor and Angband
+ from Gondolin. In the vanilla town there are three stairs.
+ When you take a staircase down in the last level of a dungeon you arrive back
+ in town.
+
+07/02/1999 - PernAngband 3.0.9
+- X in the roguelike mode for the pet commands
+- Updated the magic.txt file with the new classes
+
+09/02/1999
+- Updated version.txt, modified dungeon.txt
+- Shelob is now a little bit more powerful in order to make her the quest
+ monster of the last Mirkwood level.
+- The Vanilla books are now sellable in the magic shop/temple and the bookstore
+
+13/02/1999
+- New class : the Sorcerer, they can't wield any weapon useless it's a Mage
+ Staff and without it they are the WORST fighters of the game even bare-handed.
+ But to compensate this they are the BEST magical class : the can use any
+ book of any realm without having to learn the spell, but they also don't
+ gain any experience from casting a spell.
+- Added the susceptibilities flags to the monsters.
+
+15/02/1999
+- Stolen the exploring system (like the tactic one) from Angband/64
+- Fix the bug of vanilla town, now the vanilla town flag is saved
+- Ents are rebalanced, they have a -9 speed penalty
+- Tweaked the Troll Fortress quest to make it less easy
+
+21/02/1999
+- Corrected some bugs in the town files. The crashing wilderness bug
+ seem to be gone.
+
+23/02/1999
+- Fixed the bug of the traps. No more grey "invisible traps" on a level
+ covered with grass, same for the dirt
+- Updated the Gondolin town and quest with the Akhronath's ones
+- Enabled the S-lang support
+- A new script directory is in lib, it contain a file script.sl which indicate
+ every S-lang script files that must be loaded
+- Add the event's gestion to the slang script. An event is produced in certain
+ conditions (like a keypress,...) and a script can put an handle on it to have
+ a function called each time the event happens. I've made a stupid example
+ that use the key 'y' to shout at the monsters.
+ PS: Take a look at slang.txt in the help directory
+- Add the load/save function to the script
+
+24/02/1999 - PernAngband 3.1.0
+
+26/02/1999
+- I've finally successfully compiled Python. So the S-Lang support is replaced
+ with the python one. The 'y' key and the thieves quest are there too.
+- Stolen and modified intro.py from Pangband
+- The random quest bug is fixed (maybe :) ). I say maybe because as for the
+ wilderness one it doesn't happens by me so I can't test it :(
+- Today one of my dream have become true! With the help of a python script
+ I've made a new quest for the DragonRiders that can be given at the Weyr
+ of Arda in Menegroth. You enter forest area and the only thing you can use
+ is the flame of your dragon(no magic, no wands, ...). And you need to
+ destroy every thread while saving at least 50% of the trees, and your own
+ flame can consume them!
+
+28/02/1999
+- Yeah, the wilderness bug is now gone. And a minor bug which looks like the
+ the wilderness one is gone too. It happened when you try under certain
+ conditions to go in the wilderness with an imprinted pet.
+- Fixed the random quest bug
+- Fixed the inventory bug that when picking up an object said you have foo
+ in slot r and reorder it after that o the letter is no more r. I know it was
+ really annoying but well it's now gone :)
+- The undead races now start at night
+
+02/03/1999
+- The spectres can now pass through trees and mountains
+- A new dungeon type at Bree: The Upper reaches of Galgals(level 1-10) !
+- Changed the code for the different dungeon types. Now it's a lot easier to
+ add a new dungeon type. I'll maybe make a d_info.txt to define the dungeon
+ types
+- Add a new dungeon: The Volcano, you reach it by going to the north east of
+ Minas Anor. Level 30-45
+
+05/03/1999
+- Spectres can't pass through trees because trees are pure and natural
+ things :)
+- New dungeon type: The Hell !!! Level 500 to 530, Yes 530 ! With a little
+ present for you at the bottom... if you manage to survive :) I can just
+ said one more thing: don't go there with your level 1 character :)
+ You can reach it near the volcano hole.
+- Now fire balls can burn the trees
+- Invisibility now consume a lot of food
+- Fixed a strange bug with the pool of deep water... It was possible to
+ sacrifice at and to worship (before the crash:) one :). Thanks to Steve Dice
+- Add a very nasty surprise at level 1.... Moldoux, the defenceless mold with
+ 1 hp no powers, can't move, can't attack... Oh and if it's killed there just
+ one Great Wyrm of Power which can be summoned to avenge it !
+
+07/03/1999
+- The look command doesn't stop anymore on the trees, grass, ...
+
+07/03/1999 - PernAngband 3.1.2
+
+13/03/1999
+- Sorcerors have now a bad pseudo-id
+- Sorcerors have now a -25% penalty of hp
+- Add a scroll of deincarnation
+- Add the possibility to engrave the floor with some magic words found in some
+ parchments. The words are in Adunaic(Numeronean), Quenya, Sindarin or any
+ other tongues of Middle Earth. But the parchment also give useless words
+ with the useful ones, so you have to try different combinations.
+- No more "human" sex when randomly chosen
+
+16/03/1999
+- Mathilde will say the right sentences now
+- Fixed a bug in melee2.c which could produce an x and an y out of the limits
+- Disabled the engraving command for now because it's too unbalancing...
+- If you pray while low on hitpoints (< 20%) your god will do something to help
+ you, like summoning pets, curing wounds, killing enemies...
+
+19/03/1999
+- There is now a minimum level needed to enter some dungeons, to prevent
+ gaining great objects easily
+- Fixed the OLD bug of the pink horrors, now only 2 blue horrors
+ will be summoned
+- Fixed a bug with the tiles for the non unique DragonRiders
+
+21/03/1999
+- The Dragon realm users receive some experience for the kills of their pets
+- The Palantir of Minas Tirith now can teleport you next to the quest monster
+ but it'll take more time to recharge
+- Fixed the possessor's number of blows bug. Also the town uniques corpses (
+ Maggot, Martti, Mathilde) can't be used to attack because their attack is
+ moan with no damage
+- Added a faq (see pern_faq.txt)
+- Added a new monster ally, the Dolphiner. They came from the planet Pern
+ and can summon dragonriders, their friends. They are men riding dolphins
+
+******************** Attempts to rebalance the game **************************
+- Changed the xp modifiers of the new races in an attempt to make them more
+ balanced. Thanks to Shawn Cheng <mfighter@hotmail.com>
+- Invulnerability, Wraith Form and Life Multiplier now consume a *lot* of food
+- RohanKnight's gain less speed at each levels
+- Sound attacks of the harpers are less likely to stun...
+- IMPORTANT NOTE: At the character birth if you choose a forbidden class for
+ your race, you'll be considered as a cheater and the game won't be scored.
+ It's mainly to prevent the too powerful combination of Deathmold Mimic or
+ Deathmold Possessor. The characters made before the next release won't be
+ affected by that
+- Some more attempts that I don't remember :)
+- Changed the Mana and life multipliers, now mage staff of mana(100%) will
+ ADD 100% of mana to your max mana and not multiply it by 100 :)
+******************************************************************************
+
+23/03/1999
+- Replaced Menegroth by the new Lothlorien skilfully made by Akhronath
+ (zzhou22876@aol.com), with 2 new quests + The Battle of the Five Armies +
+ (only for DragonRiders) The Fight against a Threadfall
+ Thanks again Akhronath !
+- Deathmolds can now enter wilderness
+- Radically changed the score calculation, in the future it'll serve to choose
+ which characters must be turned into monsters. Note that the old score files
+ are compatible but the old scores mean nothing with the new system
+
+26/03/1999
+- Changed some aspect of the python implementation to make it more portable
+- The usleep python function may react strangely
+- When you pick up the same type of ammo that you wield in your quiver it
+ automatically combine with it
+- The specials levels are now restricted to a certain depth AND a certain
+ dungeon type
+- The number of collected bounties now count for the final score
+- Add a new option to not pick up monster's corpses. It's yes by default.
+ I've made it to avoid losing good characters by auto picking up a great
+ wyrm of power corpse and getting -500 speed !
+
+28/03/1999
+- Reimplemented the player ghosts, but in a different way. First the bone files
+ are a lot more complex to include more aspects of the dead character. Second,
+ only the best characters are allowed to become ghosts when they die, or commit
+ suicide, it's based on their final score. In the bone directory there is a new
+ file which held the name of the bone files that the player want to be used.
+ To add a bone file, put it in the bone directory, add it to the bones.txt file
+ and increment the number of bone file in the same file.
+ When a game is loaded it looks for this file, try to find some unallocated
+ ghosts and modify r_info with the new info from the ghost. When this is done
+the bone file is not used anymore because all the info is saved in the
+ player savefile. The race/class characteristics are not fully handled now.
+- Now even with a Mage Staff the Sorcerors have a penalty of -10 to hit/dam
+- A Vampire can now wield the Phial of Undeath without being scorched, while
+ all the other light artifacts scorch them
+
+30/03/1999
+- The Arcane Zap spell now works correctly
+- Updated the FAQ with the help of Leon Marrick
+- Updated magic.txt with the help of Leon Marrick
+- WOH ! Impressive ! Great work indeed ! Well, Andreas Koch has made a
+ powerful graphic editor for PernAngband !!!! And it has also drew some new
+ tiles! The editor is really impressive, you load the graphic file, the prf
+ file and you can assign a tile to every monsters/objects/... you want, just
+ with a click ! It can even scan the *_info.txt to search for new things that
+ are not in the current prf file and to add them !
+ You just need a big screen resolution(1152x864x16bits works for me)
+ Thanks for the great work Andreas(akoch@rbg.informatik.tu-darmstadt.de) !
+- The Archer class as suggested by Mike Hommel <jamul@hamumu.com>. They gain
+ some extra shot and might with levels and can also create ammo with rubble
+ and junks.
+
+05/04/1999
+- Fixed a bug in the Weyr of Arda at Lothlorien
+- Add the artifact's descriptions made by ... well I don't have his/her name.
+ Anyway, great work.
+- The rings of teleportation can now be activated but they'll be destroyed in
+ the process. It's like a last chance option :)
+
+08/04/1999
+- The uniques used in the special levels are no longer shown as killed in the
+ list and can only be created in the special level.
+ Note : This will only affect the new characters.
+- Fixed : When a Power Mage spell fails it is not cast anyway.
+- Wall creation works for Power Mage
+- Divia wrote some missing artifact descriptions
+
+12/04/1999
+- Reimplemented the engraving feature. There are some parchments in the
+ dungeon which contain Adunaic/Quenya/Sindarin/... words you can use to
+ engrave the floor with 'x'(']' in the roguelike keyset). You must read them
+ before engraving even if you know the words from your last game. Also the
+ inscription is magical and so needs some mana to work. So there is a new
+ and unique feature : each grid in the dungeon have some mana on it's own.
+ You can sense the mana of one grid by pressing 'X'('[' in the roguelike
+ keyset), but this is not very precise nor easy, it's based on the magical
+ ability. When an inscription is used it decrease the grid's mana and when
+ there is not enough mana the inscription don't work anymore. The maximum
+ mana of each grid is 255. i.e.: when you engrave the protection inscription
+ which use 8 mana on a grid with 80 mana, a monster won't be able to walk on
+ it for 80/8=10 turns, but well, this can save your life !
+ Note : There are not a lot of inscriptions, if you have some ideas, don't
+ hesitate, email me !
+
+14/04/1999
+- Changes in the r_info for the HAS_EGG flag as suggested by Akhronath
+- Bloodletters of Khorne only have a 20% chance of dropping Blade of Chaos
+
+17/04/1999
+- Raal's Tomes of Destruction have a 20% chance of dropping a Raal's Tome of
+ Destruction
+- Symbiants are more likely to receive the grow molds mutation
+
+20/04/1999
+- Quest monsters can not be pets or breeders
+- Can now place Trees(T), Mountain(M), Shallow & Deep lava(l, L) and
+ Shallow & Deep water(w, W) in the special levels
+- Add a new dungeon type: The lost city of Numenor which is mainly composed
+ of water and which can be found to the west of Bree
+********************* IMPORTANT *************************
+- The savefile from the old versions of PernAngband are no longer compatible
+ with the new one. It's mainly due to the new magic system but also some other
+ changes. I'm sorry but this would be hard to write a converter since all
+ the realm change (they have more spells) and so the books too and also the
+ way to remember which spells are known, forgotten, tried...
+*********************************************************
+
+22/04/1999
+- Some new graphics from Andreas Koch
+- Fixed the wilderness generation bug which sometimes hung the computer when
+ trying to go on a wilderness border
+- The features(in f_info.txt) have some flags now. This allows me to create 2
+ new types of wall: The Glass walls which you can see through but that you
+ can't pass and the Illusion walls that you can pass but not see through
+- The screen is now correctly redrawn when leaving/entering a body
+- Add the Wands of Wall Creation
+- Death Mold powers have moved to the activation command('U')
+
+24/04/1999
+- Your are no longer crushed when flying over trees/mountain without being a
+ DragonRider
+- The Vanilla feelings are back
+
+26/04/1999
+- All the spellbooks are now placed on the top of the inventory.
+- The Sorcerors can now use the Wizard and Prior books
+- The new magic system is ready. I'm just waiting for Akhronath and Shawn
+ Cheng. And now adding a new realm or an old fashioned magic system is
+ performed the same way and easily
+- Add the Illusionists from Kangband. Someone has asked for them so... :)
+
+28/04/1999
+- Finished the Valarin Realm
+- Between gates are now allowed in the vaults. To place them place 2 times a
+ number from 0 to 7. I.e.(from weisiger <jmartin@inreach.com>):
+ D:XXXXXXXXXXXXXXXXXXXXXXXXX
+ D:#,,,,,X&...@X..**&X....9X
+ D:#...&1X.,,,2X..**&X3...9X
+ D:#...&.X1,,,.X2.**3X....9X
+ D:#,,,,,X&...@X..**&X....9X
+ D:XXXXXXXXXXXXXXXXXXXXXXXXX
+ But BEWARE ! You MUST put the 2 occurrences of the number, no check are done
+ so it'll surely crash or bug if not ! You've been warmed.
+- You can now walk over the water with a Valarin spell
+
+30/04/1999
+- A monster on a between gate when the player is using the other is teleported
+ to the player location
+- Add some Between vaults from weisiger
+- Added the Sigaldry realm
+- The Rings and Amulets are now allowed to be random artifacts
+- You can use the between gates in the special levels via the numbers 4,5,6,7,
+ 8,9,0
+- Alchemists MUST wear gloves (no cesti nor gauntlets) in order to do alchemy.
+ They also begin the game with some gloves
+- Add a Potion of Learning which allow you to learn one more spell than you
+ normally can. No need to say that they are very rare
+- The more you learn spells in a realm the more efficient with that realm
+ you are
+
+02/05/1999
+- Implemented the Nether Realm
+
+09/05/1999
+- Magical stair at the bottom of each dungeon
+- Reworked the imprinted pet system, now it will work lot better
+- Add the scrolls of spell which can cast a spell like a book. They must be
+ created by the Sigaldry magic, they can't be randomly generated
+- Updated the Sigaldry realm
+- Added Staves of Wishing! You can wish for objects, monsters, spells but
+ NOT FOR ARTIFACTS nor for staves of wishing
+- Flying monsters can now pass over trees and mountains
+
+11/05/1999
+- The game will ask you to choose ammo from your inventory if your quiver is
+ empty
+
+26/05/1999
+- Add the Crusade Realm
+- Add some new inscriptions
+- It's now possible to add up to 32 realms
+
+03/06/1999
+- Wraith form is less powerful since it's not so rare. Now damage is only
+ divided by 5 and armor raised by 50
+
+05/06/1999
+- Add the speaking patch from Matt Graham. Just edit the monspeak.txt file
+ to add new entries. And don't hesitate to send me what you've added !
+
+11/06/1999
+- There are fewer gods and each god has one or two preferred races and if one of
+ this race pray to him they gain better benefits. Also the praying effects
+ are more differentiated (based on the different gods)
+- Add the 'only once' quest type
+- It's harder to please your deity
+- The Nazguls are MUCH more powerful (ideas from Akhronath):
+ ******** Quote from Akhronath mail ********
+ All weapons which are not ego-items cannot harm them, and will be destroyed if
+ the character hits a Nazgul with it. Ego-items which have slay evil or slay
+ undead can harm them, but each hit has a 25% chance of destroying the weapon.
+ Other ego-items can't damage them, and have the same 25% chance of
+ destruction. An artifact weapon will be able to hit them only if the weapon
+ has slay evil or undead, but the weapon will be hit with disenchantment every
+ time it connects (but this is negated with disenchantment resistance on the
+ character). And even these artifacts can be destroyed, although there's only a
+ 5% chance. Other artifacts, of course, can't damage the Nazgul, and still have
+ the 5% destruction chance.
+
+ When a character does any damage to a Nazgul or is damaged by a Nazgul, he has
+ a 25% chance of being afflicted by the Black Breath. Thenceforth the character
+ will slowly be drained of experience and sanity. The character can stay alive
+ by using restoring and curing potions, but to cure the Black Breath he must
+ either drink a Potion of Life or eat (a new item) Athelas Leaf. (Athelas isn't
+ really eaten, of course, but I can't think of another simple way to implement
+ it.)
+
+ This will really make the player think twice before going up to a Nazgul, and
+ makes it very useful to carry spare weapons.
+ *******************************************
+ So if you encounter a Nazgul .... RUN AWAY !
+- Sensing the grid's mana is now done by pressing 'x' key to engrave the floor
+ The X key is free for some new function (maybe for the new riding system)
+
+17/06/1999
+- When browsing the spells while being a Power Mage there are no more bugs
+ when pressing escape
+- Removed the forbidden race/class combination feature. But it's always
+ possible to recompile PernAngband with it with the FORBID_BAD_COMBINAISON
+ define(in config.h)
+- New god : The RNG
+
+19/06/1999
+- The priest/prior/paladin's god is now chosen dependent on their race
+- I have enough of hunting those damn ghost bug which makes them unable to
+ move. So it's now a feature ! They don't move because they are GREAT
+ adventurers who now just want to stand there to find peace :)
+ Hey, fixing bugs is easy this way :))
+
+22/06/1999
+- When 'A'ctivating the first screen showed is the equipment and no more the
+ inventory
+- Some new gfx drew by Andreas Koch
+
+06/07/1999
+- You can place object kind in the special levels instead of artifacts by
+ using 1000+k_idx as the number instead of just the artifact index
+
+17/07/1999
+- Add the Yeek race, but not as in Zangband. It's the one from Drangband.
+ I was thinking of a race who advance even quicker than the humans in levels
+ since a long time and I've found it !
+ So they suffer lots of disadvantages but need less exp than the other
+races, i.e.: When a DragonRider comes to level 2 a Yeek can already be at
+ level 7 !!
+- Added the FLY attribute, it allows you to fly over trees and mountains
+ because it's no longer possible with the levitation one. It's also a lot
+ rarer since it's POWERFUL in Galgals and Mirkwood. DragonRiders have it
+ by default. There is also a change in the features flags, CAN_LEVITATE
+ means that you can just avoid them by floating over it (like a pit,
+ water, ...) and CAN_FLY means that you must have the FLY flag to cross it.
+
+19/07/1999
+- The monster's drop are now created at the same time as the monster is
+ created. First it disallows scumming of monster drops. And the most
+ important thing is that it will allow me to add the new ability of stealing
+ objects from monsters (everyone will be able to do it, but only Rogue will
+ be excellent at it). For the point of view of the player there is no change.
+ It may produce some strange object disappearance in the late game since
+ all the objects are generated with the dungeon. And thus it may need to
+ increment the maximum size of o_list in misc.txt. If such problems shows
+ up, email me.
+- Press 'Z'('[' in roguelike mode) to STEAL an item from a monster. The
+ success rate is based on your dexterity, the fact that you are or aren't
+ a Rogue (being one makes it easier), the weight of the object to steal and
+ the base level of the monster. A Rogue will also gain some experience
+ if he/she succeeds. This made them more Rogue and less Warriors.
+
+22/07/199
+- Add more graphics from Andreas Koch along with a new version of the editor
+
+26/07/1999
+- The resurrection effect of the gods is now harder to get and decreases a lot
+ more your grace. It was ... well ... too powerful for the cost of some
+ crappy artifacts
+- Finished the Magery realm created by Chris Weisiger (jmartin@inreach.com)
+
+03/08/1999
+- I've finally fixed it ! You know, this ugly bug that disallows the darkening
+ of the grass & mud tiles when they have been lit.
+
+18/08/1999
+- Yeah ! It's done! The new magic system is finished (I will add Spirit Realm
+ later). The final form is 4 Major Realms : Valarin, Nether, Magery, Shadow
+ and 4 Minor Realms : Crusade, Tribal, Sigaldry, Illusion.
+ The only problem is be that it could be unbalanced, especially the
+ Shadow realm since I've created it :)
+ Anyway it should be great. There are still a lot of old spells but some new
+ coloured funny spells for you to discover, as Control the Ring, Infuse Amulet,
+ Scribe Scroll, Doppleganger, Volcano Flow, Tidal Wave, and a lot of others!
+ The max number of spells a character can learn depends on his class. But
+ generally the player can learn fewer spells than the total number of spells he
+ has in all the books he can read.
+ I want to thank Akhronath (who has the first idea and who write some realms),
+ Shawn Cheng, Chris Weisiger and DSCreamer<DSCreamer@aol.com> for their great
+ help.
+- Moldoux can not appear at any other level than level 1
+
+21/08/1999
+- A new version of the Tile Editor plus a full set of graphs (expect the books)!
+- Moved the dungeon types definitions from tables.c to a new info file in the
+ lib directory: d_info.txt
+ It allows you to add new dungeon types easily.
+ There is also a brand new feature: You can specify which monster flags that
+ are NEEDED for a monster to be generated in the dungeon.
+ There is also an addition of dungeon flags. Here is the structure:
+ N:<index>:<name>
+ D:<long name>
+ W:<min depth>:<min depth>:<min player level>:<next dungeon>:<flags mode>:<min alloc>:<max alloc chance>
+ L:<floor1>:<%1>:<floor2>:<%2>:<floor3>:<%3>
+ A:<wall1>:<%1>:<wall2>:<%2>:<wall3>:<%3>:<outer wall>:<inner wall>
+ F:<flags>
+ M:<monster flags>
+ S:<monster spells>
+- The quest rewards are always good
+- I've finally found and fixed the Mirkwood Spiders Quest
+
+24/08/1999
+- Add the MAZE flag to the dungeon type flag list, which instead of a normal
+ dungeon generate a full big maze ! And it's EVIL ! Note that there will be
+ no rooms and no vaults generated, just a plain evil maze
+ The algorithm is from <Pierre.Bru@spotimage.fr> on rec.games.roguelike.development
+- Note about the dungeons : A dungeon can't have more than 40 levels
+- You can use SMALLEST, SMALL and BIG as dungeon flags to specify the level's
+ size
+- 6 new dungeon types: a Graveyard, an Illusory Castle, an Orc cave, a Maze
+ a Dragon's Lair and A Forest with specific gfxs and monsters restrictions
+- Some new gfx form Andreas Koch mostly to add more flavor to the towns
+
+29/08/1999
+- You can add a guardian and a guardian artifact to each dungeons types with
+ the following flags: FINAL_ARTIFACT_artifact_number and
+ FINAL_GUARDIAN_guardian_number
+
+29/08/1999 - PernAngband 4.0.0
+
+01/09/1999
+- Fixed the max_dlv non allocation error
+- Fixed the Tribal realm spell descriptions
+
+01/09/1999 - PernAngband 4.0.0b
+- New dungeon type, the Netherworld with Muar and the Wand of Fireball of
+ Mithrandir at the bottom
+- You can't gain a fate before being level 10
+- Some cosmetic changes suggested by Akhronath
+- A new Artifact by Akhronath, The Long Sword of Murazor 4d5, so ... the next
+ time you see a long sword 4d5, beware ...
+
+05/09/1999
+- Add a feature flag to allow running
+- Fixed the Chaos Warriors bug (they were unable to use magic !)
+- Fixed the Chaos Realm descriptions
+- You can't rest on a between gate
+- You can now steal from stores. But beware of the consequences if you fail...
+- Fixed a bug in that when recalling to the town the player was sometimes
+ placed in the upper left corner
+
+08/09/1999
+- Fixed a bug that disallowed the creation of entrances to some vaults
+
+14/09/1999
+- Fixed the Dragon Tower bug
+- Add minimum player level to the random dungeons
+- Add shafts, you can use them do go up/down for up to 4 levels(but you can't
+ ignore quest levels). Original patch from Static Chaos. Idea from GSN
+- Add a dungeon flags to forbid generation of doors
+
+27/09/1999
+- Some tweaks to the possessor code as written by Static Chaos i.e:
+ You must possess a monster that is able to open to door to do so. The
+ same applies to bashing. Your sex is modified by your body. Lots of tweaks
+ to the spells that can be used...
+- The racial power of the Dwarves is now the same as The Pick of Erebor
+ activation: they can find hidden passage in the walls
+- There is 1 chance in 10 that the level is an magical level, which means that
+ each grid will contain more mana than a normal level.
+- Add some new sentences to the monsters sentence lists
+
+04/10/1999
+- Began to add the Druid class. But it's TOTALLY different from the other
+ variant's Druids. They make intense use of the mana flow from within the
+ earth and the elements, thus their spells can regenerate the mana they have
+ used by pumping it from the floor, like the Tunnel spell which will blink
+ the player and will try to absorb enough mana form the grid he/she lands on.
+ They can also (and they are the only to be able to do that) regenerate the
+ mana flow of the earth. They also can use enhanced attack types called
+ Druidic Bolt/Beam/Ball that can follow a mana flow laid by the player.
+- The Druids can sense precisely the amount of mana of a grid
+
+08/10/1999
+- Added some revised graphics by Andreas Koch
+- Added the code provided by Alexey Guzeev(aga@russia.crosswinds.net) to
+ compile PernAngband under OS/2 with EMX
+- It's finally fixed ! the damn bug that was crashing the game when leaving
+ a town on certain system (Mac and Windows) ! this will never happen again !
+
+27/10/1999
+- Finished the Druid class. They have 40 spells (8 * 5 books). The spells that
+ activate Mana Runes is not active for now, but it will in a near future.
+- Add a slightly modified Tom Morton fake artifact patch (it won't print {} at
+ the end)
+
+30/10/1999
+- You can inscribe an object with !! to notify the player when it's recharged
+- Lots of bug fixes thanks to Lothar Lange <100644.2004@compuserve.com>
+- Lots of new ideas thanks to Lothar Lange <100644.2004@compuserve.com>
+
+30/10/1999 - PernAngband 4.0.1
+- "Foolish mortal! Thou hast not pleased me! I'll doom your game with the new
+ horrible DG curse !"
+ Yes I've done it, the DG curse is even worse than the TY one. One of it's
+ most perverse feature is that it can replicate itself to contaminate sane
+ objects that can't be cured. Also if you remove the curse of a DG cursed
+ object, it will recurse itself automatically !
+ Beware of the horrible Long Sword of Murazor because it carries the ancient
+ morgothian curse !
+ Oh, there are also some monsters that give the DG Curse when dying ... but
+ I'll let you find whose they are by yourself :-<|> (Dark God makes an evil
+ smile). I can just say one thing : you should *REALLY* *NOT* kill Mathilde...
+ But do not worry she's got much more HP, so you can't kill her anymore :)
+
+01/11/1999
+- Add the Rod of Home Summoning, which acts like the old dragon spells
+ "Call Home"
+
+08/11/1999
+- Drastically reduced the recharging time of the Dragon Scale mails in order
+ to render them useful.
+- Added a new weapon ego-item: of Spinning, which will make you spin around
+ in order to hit every monster around you. Note that you'll only get one
+ blow for each monsters whatever your normal number of blow is.
+- Added (ok stolen) the question in the GSNband FAQ about wrists hurting (it can
+ be useful, so everyone should know)
+- Rogues and monks gain more and more stealth as they gain levels (SBF)
+- Added some sentences for the Dwarves (in monspeak.txt)
+- Added the support of two-handed weapons (from GSN). Thus there are weapons
+ that can be handled with two or one hand (but with one hand it halves the
+ damage). A 2 handed weapon can't be wielded with a shield.
+- Added the random character name generation from Cthangband
+- Added rivers (water & lava) from the Steven Fuerst fractal patch. Note that
+ you have to add WATER_RIVER, LAVA_RIVER, WATER_RIVERS or LVA_RIVERS to a
+ dungeon to have some rivers generated (actually in Mordor(lava), Dragon lair
+ (Lava) and Forest(Multiple Water))
+- Updated generate.c to the Steven Fuerst fractal patch room generator (using
+ room_alloc), in order to implement the remaining part of the patch easier.
+ But I'm still having problems adapting it to my extended dungeon generator.
+- Ahah ! I've resolved the problem !! there are now fractal rooms (15%, can be
+ always enabled by specifying the CAVE flag), now the orc caves looks great
+
+10/11/1999
+- Added the Caverns(enabled via the CAVERN flag)
+- Hell has been moved down, it now begins at level 666! :)
+
+12/11/1999
+- Add the Static Chaos persistent dungeon patch that save every level of a
+ dungeon (which has the PERSISTENT flag) on disk and reload it instead of
+ regenerating a new level.
+- Add the Outer World dungeon type (this is an entrance to a place of an
+ incredible stability). It use the PERSISTENT flag and thus will be saved.
+ Only level 50 characters can go there to prevent abuse(like have an old
+ ultra powerful character and a new one and going into the Outer World to
+ exchange some stuff). And yes the saved dungeons are the same for EVERY
+ characters. But to add ... err ... variety, I've put it from level 300 to
+ 305, I've put it to have at least 30 monsters from the beginning AND to have
+ an higher monster generation rate(1/60 instead of 1/160 !), thus you'll
+ NEVER get bored there :)
+- Implemented the much more complex trap system from Angband/64 thanks to the
+ patch made by Static Chaos. There is 169 traps (see tr_info.txt).
+ Beware that on average the traps are deadlier...
+- It comes along with a new feature for stat system: temporary stat drain,
+ it's cool
+
+14/11/1999
+- Renamed Power Batteries to Essences
+- The DG_CURSE can put the NEVER_BLOW flag on a weapon ... sadistic !!!
+
+16/11/1999
+- DSMs now have been granted the FLY flag
+
+19/11/1999
+- The monster memory now colors some important things about the monster (like
+ resists, speed, ...)
+- Fixed a wand of wishing bug, that made them sometimes NOT use a charge
+- Moved the special level DeathWatch to the Orc Cave
+- Moved the special level Treasure Room to the Maze so people are forced
+ to play those dungeons if they want the artifacts
+- Random quests will only occurs on PRINCIPAL dungeons (the one created by
+ splitting the vanilla dungeon into 4 smaller ones, Galgals, Mirkwood,
+ Mordor and Angband itself)
+- To prevent too many YASD from the DG curse of Mathilde she has now been
+ granted 22500 hp, but as usual she can't attack :))
+- Fixed a bug that disabled the guardian at the bottom of some dungeons
+
+25/11/1999
+- Added main-gcu from Angband/64 to allow larger screens
+- Added the new note command that dumps to a file from "Tom Morton"
+ <tmorton@yikesstation.freeserve.co.uk>
+
+27/11/1999
+- Added funny time message from Z
+- Added object experience as suggested by Ceilti <Ceilti@aol.com>
+- Fixed a bug when the magestaves were cursed
+
+29/11/1999
+- Added the small trees (along with a new feature flag: SUPPORT_LIGHT) to
+ replace the walls in the Forest and Mirkwood
+- Some new gfx from Andreas, and the town of Bree with the new tiles
+
+02/12/1999
+- Add 4 dungeons by variaz@hotmail.com: Vanilla Dungeon(only from Vanilla Town,
+ The Small Water Cave, The Sacred Land Of Mountains(if you don't fly ...
+ do not even plan on going there),
+ The Wild Land Of Kurukar(It sure looks great)
+
+04/12/1999
+- New dungeon flags: HOT and COLD that affect object decay
+- Add YA*IF (Yet Another *_info File): wt_info.txt
+ It defines wilderness features *, allowing a better wilderness map. Since
+ it now defines nearly everything a wilderness need to have, the map itself
+ only have to be an array of feature and seed, thus allowing a much bigger
+ wilderness. I also plan to have a Omega wilderness mode where you can have
+ an overview of the wilderness to travel quicker (but time will pass much
+ quicker too:)
+ The structure of w_info is also changed, it's uglier but well .... :)
+ The wilderness size must be EXACTLY the same as the size defined in misc.txt.
+
+06/12/1999
+- Scrolls of Reset Recall are now WORKING !!!!!
+- The new wilderness mode is done ! When you reach the border of a wilderness
+ screen you go to the small scale wilderness map, where you can see all
+ the wilderness map with the towns/dungeons/... A lot of commands are
+ disabled there and moving takes MUCH more time, so beware of the food !
+ You can enter the big scale mode by pressing > (this allow you to enter towns)
+ NOTE: The Death Molds CAN'T reach the small scale mode because their
+ erratic movements are impossible to handle in such a scale.
+ BEWARE: Your imprinted pets WON'T follow you in the wilderness !!!
+
+11/12/1999
+- Add wilderness encounters
+- Add Oangband rod/wand stacking
+- Amulets of the Serpent from Sadi Khan <sadik@christa.unh.edu>:
+ Resist Poison, Dexterity, some AC and Poison breathing
+
+12/12/1999 - PernAngband 4.0.5
+
+18/12/1999
+- Updated the makefiles and renamed object3.c to traps.c
+- Add 5 new essences from Sadi Khan: Force, Darkness, Lightning, Mana and
+ Knowledge
+- Fixed the bug that was placing the player at the town entrance when
+ leaving a building
+
+20/12/1999
+- Add the tool slot. It's actually only used to wield a shovel/pick but I've
+ some plans for it
+- You can only dig walls if you use a shovel/pick in your tool slot
+
+24/12/1999
+- Removed the player ghosts, well in fact made them a compile-time option(see
+ config.h)
+
+26/12/1999
+- Added the Necromancer class. But again not quite the same as you've seen
+ before. They can't be killed as easily as the other class. In fact when
+ their HP comes to 0 they don't die but become undead for a while. While
+ being undead their HP is replaced by DP(Death Points) that have a max
+ inferior to the max HP and that are slowly decreasing(1 DP less each turn).
+ They can use all the healing spells/potions/... but this won't stop them
+ from being reduced again. The only way for them to come back in the world
+ of the living is to kill 2 * player_level monsters.
+
+01/01/2000
+- Happy New Year !
+
+02/01/2000
+- Add a new curse(as suggested by LucFrench@aol.com). When a weapon has this
+ curse and that the wielder attacks a monster with it, it can clone it !
+ And it's REALLY REALLY annoying, especially when fighting some kinds of
+ wyrms :)
+
+10/01/2000
+- Finally fixed the flags shown on the character display.
+- The quit without save command(CTRL + L) is now a compile time option disabled
+ by default
+- The Necromancer class now has 5 spells (used the same way as the mindcrafter
+ powers)
+
+17/01/2000
+- Power gained by levelling artifacts has been reduced
+- New unique monster: The Greater Lag Monster... beware :)
+- AHAHHAHAH ! I got it ! the wilderness bug that made the game crash when
+ entering a town is fixed ! And the wilderness system has been greatly
+ improved.
+ Now to switch the wilderness mode, just press < or >.
+ Everything should now works properly
+
+16/02/2000
+- Each Nazgul will now drop his Ring of Power. They are randomly generated
+ and thus they don't appear in a_info.txt. They always give invisibility,
+ life draining and are heavy cursed.
+
+21/02/2000
+- Changed the format of w_info.txt again, it's much more readable now.
+ I also added a additional parameter to the W lines of wf_info to define
+ which letter will be used in w_info.txt
+- 60x20, this is the scale of the new wilderness, it tries to looks like
+ the 3rd age middle earth map. Thus some dungeons leaved the towns they
+ were used to be to join their "real" place on the map. Only the Upper
+ Reaches of Galgals are still reachable from Bree.
+
+24/03/2000
+- Added a small hack from Static chaos to allow running faster with the
+ overhead map enabled.
+
+24/03/2000 - PernAngband 4.0.6
+- Possessors now have a MUCH better pseudo id, equal to warrior's one
+
+06/04/2000
+- Changed the wilderness map with the one provided by Gwidon S. Naskrent
+ (naskrent@artemida.amu.edu.pl). It's bigger, it's better :)
+- Fixed a bug with the chasm opening inscription
+
+08/04/2000
+- Fixed a bug with the staff of wishing
+- Druids can now pass through trees
+- Stairs are now noticed again (when you see one it will stay on your screen
+ even when out of torch radius)
+
+10/04/2000
+- When a Necromancer turns into an undead he/she/it gets cured of everything
+
+05/05/2000
+- MAYBE fixed the damn wild bug ... again ? oh please GREAT RNG help me !
+
+08/05/2000
+- Added the Notes patch from Chris Kern. That allows you to get a .txt file
+ recording great events in your life, your notes, ...
+ Very useful I think
+
+11/05/2000
+- Fixed the artifact wands stacking bug
+- Removed the Netherworld dungeon
+- Added the Moria dungeon, it's not random and can be found in ... the moria
+ mountain chain :) There is Muar waiting you at the bottom, guarding the
+ Quarterstaff of Olorin
+- Waldern, the king of water is back, and he is the final monster of the
+ small water cave, guarding a the Trident of Ulmo. But beware it is more
+ powerful than in vanilla
+- Dungeon guardians and dungeon guarding's artifacts can only be generated
+ in their respective dungeons
+- Removed rumors that were still Zangbandish and some others I didn't like :)
+
+14/05/2000
+- The MONSTER_PERCENT_ flag can be added to some dungeons to specify the
+ amount of monsters that are affected by the dungeon specific restrictions
+- Random dungeons now appear on the overhead wilderness view
+- COULD IT BE !!!!!! yes it could !!!! thanks to Tom Demuyt that sent me a
+ savefile where he wasn't able to learn spells, I may have finally fixed the
+ dreaded spell bug !!!! I say may because I'm waiting for some fellow
+ mac user to compile it to see if it really fixes the bug.
+- IT WASN'T ! but now it *IS* !!!!
+ That was an other bug. And now Gob, the great Gob, the powerful Gob,
+ found the dreaded mac spell bug !!! thanks Gob !!!!
+- Changed the price for Runes/Essences to be more accurate
+- Changed some uniques in r_info to their former vanilla glory
+- The look command can now show the trap's types
+
+18/05/2000
+- Fixed some typos(thanks whimsy)
+- Began to add the Body parts system to allow more rings, weapons,
+ everything, depending on your current corpse (dragons will have more rings,
+ mariliths 2 weapons, ...)
+- If your corpse allows the use of more than one weapon, you can use them :)
+ let see a Sorceror using Ringil AND Gandalf ! :) well first he has to find
+ the rare scroll to change body and then to find a corpse that allows 2
+ weapons
+- Changed color of shafts (brown now) because they were hardly visible
+- Flying no longer allows passing over mountains, you MUST have a Climbing Set
+
+22/05/2000
+- Fast autoroller as a birth option
+- E'x'amining books in stores now browses them if your class can read them
+- Add a bookstore to Lothlorien town
+
+26/05/2000
+- When in battle rage(berserk) and using the ascii mode the screen goes all
+ red (as it is white for invulnerability and black for wraithform)
+- r_info is modified to give all monsters some inventory slots. the format is
+ E:weapon:torso:arms:finger:head:legs
+
+27/05/2000 - PernAngband 4.0.7
+- add a new dir to lib, DNGN which contain the definition of the LEVELS
+ not the dungeons. one file for each level named dun$dungeon$.$level$
+ In it you can have some declarations, like B:dungeontype which will
+ create a stairway to an other dungeon, thus allowing to have "branches"
+ in the dungeons.
+ L:dungeontype and L:level specify which is the "father" dungeon and at which
+ level the stair appear.
+ S:ext means to save the level(and thus to reload it) in the player.ext file
+ so allowing the use of persistent levels(the persistent dungeons option
+ is gone)
+
+29/05/2000
+- Necromancers can use the Nether realm in addition to their old set of
+ powers(now accessible through 'U')
+
+01/06/2000
+- Boomerangs of spinning are no longer allowed (that was silly)
+- Increased the rarity of the ULTIMATE artifacts (Magestaff of Gandalf,
+ Longsword of Eru, Seeker Bolt/Xbow of the Elves)
+- Fixed the displaying of attributes under the 'C'haracter display
+
+-04/06/2000
+- Players can now choose which kinds of monsters they don't want in their game
+ at birth (wipe all Pern monsters, all Cth, monsters, joke monsters, ..)
+ Note that monsters in fixed quests are not affected.
+ Thanks Static Chaos.
+- In the Maze you can no longer remember anything, that means everything you
+ see is what it's in your light radius ! MUAHAHHAH, I'm *NASTY*
+- Archers now get a better chance of not breaking their ammo as they
+ advance levels
+
+08/06/2000
+- Note taking bug should be fixed
+- Fixed a bug with the incarnation code
+
+11/06/2000
+- Added the Orc Barracks special level (level 35 of Moria) from
+ Chris Weisiger (jmartin@inreach.com)
+- The maze is now guarded by The Baby Minotaur who is holding The Steel
+ helm of Hammerhand
+- The graveyard is guarded by Vecna holding Doomcaller
+- You can now use the 'l'ook command in the small wilderness view
+***********IMPORTANT************
+- Between gates are no longer automatic, you must press > while standing on
+ one to activate it
+********************************
+
+16/06/2000
+- Revised the Adventurer's guide thanks to Chris Weisiger(jmartin@inreach.com)
+- You can no more recall from a quest
+- You can no longer target pets
+- Re-enabled the "Control the rings" spells of the Shadow realm
+- Between gates are now purple +
+
+02/07/2000
+- Only priest-like characters can use the Valarin realm
+- Removed all the references to Logrus
+- Tunnelling rubble will place the standard floor of the current dungeon and
+ not the floor feature
+- Grow trees no longer crashes when used near the dungeon edge
+
+05/07/2000
+- Fixed the character dump resistances
+- When a full character dump is requested (upon death) the self-knowledge
+ screen is used instead of the grid of abilities, that looks better :)
+- Fixed a bug in the placement of stairs which sometimes led to a stairway
+ to another dungeon when not requested
+- Fixed the bug that generated 'unknown' grids
+- Should now compile (nearly) without any warnings
+- Fixed the mountain bug that hung the game when entering mountain chains
+ in the wilderness
+
+07/07/2000
+- Some more monsters from Angband/64 and some more work on r_info from
+ Static Chaos. That brings the number of monsters to ... 1023 !
+- Damage taken from going between is divided by (ac / 50) + 1
+ So between 0 and 49 ac it's full damage, between 50 and 99 it's half
+ damage and so on
+- Greater Hell Beasts now have .. 1 hp :)
+
+11/07/2000
+- Add the Unbeliever class, they are anti magicians. Great warriors, they
+ have the worst magic device skill of all the classes, they continuously
+ generate an anti-summoning field around them disabling monsters from
+ summoning. The radius of the field increase with levels. After level 20
+ they can also disrupt the magic continuum, thus getting the same effects
+ as Anti-Magic, Anti-Tele and The Stone of Lore(nobody on the level can
+ teleport)
+
+13/07/2000
+- Add an option to auto tunnel walls when bumping into them.
+ NOTE that it'll ALWAYS take a turn then, so beware...
+- Really fixed the note taking bug (ok stole the fix from Zangband :) )
+- Changed the object description so now it's "Smeagol's Corpse" instead of
+ "The Smeagol's Corpse"
+
+13/07/2000 - PernAngband 4.0.9
+
+29/07/2000
+- Orc Barrack's between doors are fixed
+- God favor is reinitialized upon birth
+- Added the Daemologist class along with a brand new realm and lots of new
+ cool effects(try making all your pets explode ! :)
+ All made by Static Chaos
+
+31/07/2000
+- Fixed lots of compilation warnings thanks to Static Chaos
+- Added the random vaults and crypt vaults from Zangband with the help of
+ Static Chaos
+- Fixed some bugs pointed out by Bablos
+- The Ray Rune now relay make a beam and not a pseudo bolt
+
+03/08/2000
+- 2 handed weapons wielded with a shield now really restrict your fighting
+ abilities (I forgot to add the code before) :)
+- Possessors can't leave their body while they wear cursed items
+- Word of Destruction is no longer allowed in quests
+- Add a fate spoiler created by Dustin Ragan
+- Removed the old new player ghosts implementation
+- Added the new old player ghost implementation (stolen from Drangband)
+- Rod system have been totally reworked. Now you can find "base" rods without
+ power (rods of nothing) with a certain quality (wooden, iron, ...) on which
+ depends the amount of mana they contain. You can also find rod tips which
+ contain the real spells but cannot be activated alone. You must attach (with
+ the 'z' command) a rod tip to a base rod before using it. The spells of the
+ different rod tips need different amounts of mana (so illumination is less
+ mana-hungry than healing) :). You can also have base rods ego-items (artifacts
+ soon) that can decrease the mana cost of the spell, increase the capacity
+ of the rod, decrease the time needed to zap the rod, ...
+ Oh BTW, you should be eager to get an Adamantite Rod of Healing of the
+ Istari :)
+ Now rods will hopefully be useful.
+ Note that you have to identify the base rod to get the mana indicator
+- Note files are now playername.nte instead of playername.txt
+So if you want your note file to be carried to the next version you'd better
+ rename it :)
+- Fixed a bug that prevented Azog from being generated at the bottom of the Orc
+ Caves
+
+07/08/2000
+****************** IMPORTANT *****************
+- Removed the Python support because it was slowing the game, adding
+ weight to the executable (and thus to the archive), was mainly unused,
+ and was never present in some ports
+**********************************************
+
+09/08/2000
+- Unbelievers are now much better at perception, and actually become even
+ better as they go up levels
+- Fixed several bugs thanks to Iain McFall
+- Reset recall is now much nicer to use thanks to Iain (again :)
+- When a character is infected by the Black Breath it is show in the char
+ screen & dump
+
+15/08/2000
+- Cursed mage staves should no longer crash the game when identified
+- A Marilith can now drop it's corpse when killed
+- Add the gods spoiler made by Dustin Ragan
+- Fixed a bug that could eventually crash the game when looking at the quests
+ screen
+- Fixed a bug in the random junk artifacts that made them cure fear when said to
+ cure confusion
+- Add the squelch patch from Iain McFall
+- Boomerangs are now pseudo-id'd
+
+19/08/2000
+- The *thanc artifact daggers are less common because they are so powerful
+
+24/08/2000
+- The Midas Touch 30k gold limit has been removed (suggestion from Chris)
+- Fixed (ok ok Iain fixed :) ) several trap related bugs
+- Squelch now use the pseudo-id thanks to Iain
+- Pseudo-id inscriptions are no longer part of the real inscription of an object
+ and thus ... it's better :)
+- Tribal spell "Life Drain" now reduces your stat permanently 30% of the time
+ and the other 70% it can be cured via restore stats pots. The damage is now
+ always 50d50 and is no longer affected by mage staves of spell
+- Tribal spell "Meditate" no longer hastes/heals you
+ (it still heals your sanity) and the glyphs' radius have been decreased
+- Add the Trap of Acquirement that will give a great object and then mutate
+ into an other trap. It can never be identified and the color varies.
+ Idea from Iain
+- When casting charm upon monsters only the non-pet ones will be affected
+- Elder Aranea HP reduced
+- Small trees are burned by fire
+- Randomly activated mutations are no longer activated in the overview
+ wilderness
+- Ghoulkings are now z instead of p
+- Thrown potions now give xp when killing by a ball effect
+- Scrolls of reincarnation have been removed now you can only find scrolls of
+ deincarnation. To reincarnate into a new body 'U'se the appropriate power
+- Recharging is now useful again
+- Breeders should be a BIT slower
+- Reduced mutation chance of breeders from 7% to 3%
+
+03/09/2000
+- New, unified store/building code
+
+08/09/2000
+- Add quest plots. Feature 75, 76, 77, 78 are now permanent walls but used
+ as quest plot info holders. Before the new building code quest info was
+ stored in the building feature but now all stores/buildings use the same
+ feature(74) and the "special" value defines them.
+- Add semi-random towns. Now if the ' ' (space) character is used in the town
+ definition this grid will be replaced by the feature calculated by the
+ plasma generator as if it was a normal wilderness screen. So the forest of
+ Lothlorien is plasma generated and not fixed. It add variety and consistency
+ with the rest of the wilderness
+- All towns are now updated to the new store/building code
+- Removed the "you are being crushed" bug when going in the overview map thanks
+ to Iain McFall (as usual :) )
+
+10/09/2000
+- When you use a 2 handed weapon and press 'e' the equipment list will show
+ the weapon(and some info) in the shield slot too
+- Monsters can't have fewer arms than weapons
+- Mimics have been upgraded. They now have 5 powers. First is to use books of
+ lore as before. Second is invisibility. The other ones are Mimicries.
+ There are 3 mimicries, legs mimicry, wall mimicry and arms mimicry.
+ Legs and arms mimicry will "create" a new body part (or some) for a certain
+ duration. Wall mimicry will make the caster able to walk in walls (he becomes
+ a wall) but ONLY in walls .. not on floor .. so beware with this one
+
+27/09/2000
+- For your god to resurrect you need 3 times more grace and your grace
+ will drop to -100000
+
+30/09/2000
+- Add exploding ammos (bolt, arrows, shots) thanks to a patch by Static Chaos
+
+13/10/2000
+- Add some patches from Kusunose Toru <kusunose@hcn.zaq.ne.jp>
+- Neuters get a weight & height
+
+13/10/2000 - PernAngband 4.1.2
+
+14/10/2000
+- Building doors can't be erased
+
+28/10/2000
+- Fixed a bug in the rod system when attaching form the floor
+- Added fountains that you can quaff from ('H' in normal mode, 'V' in roguelike
+ mode, yeah I know it was for version number .. but .. mhh who is using it ?:)
+ Thanks to Static Chaos for the patch
+- You can fill empty options with fountains(thanks static chaos)
+- Added the Iain McFall Show Monster patch to show all viewable monsters
+
+08/11/2000
+- Fixed numerous bugs
+- Fixed the st_info & ba_info files thanks to Kusunose Toru
+
+16/11/2000
+- Godly blasts can't be reflected anymore, so beware, puny mortal !!! :)
+- Added a whole bunch of new floor features (ice, mud, sand, sandwalls, ...)
+ thanks to Static Chaos.
+- More spell effect will affect the dungeon, for example, fire will melt ice,
+ nether will kill trees, fire will create ash, cold will freeze water, ...
+ thanks to Static Chaos again :)
+- Cleaned up the feature code again (that was a REALLY messy part of angband...
+ and especially of Zangband)
+- Note: Sandwalls can be dug WITHOUT any digging tools
+- Teleport scrolls/staves are back in the shops
+- Mages, Wizards and Sorcerors now only get a wand of fire bolt at birth
+- Finally fixed the Alchemists extracting powers
+- Fixed numerous bugs thanks to KUSUNOSE Toru
+- Desert and Glacier wilderness features now really look like desert &
+ glacier :)
+
+18/11/2000
+- Debug commands are allowed in the overview map, but beware, do not create
+ objects & monsters there ...
+- The wilderness map is no longer fully known, you have to explore it
+- New wild.c file to support all wilderness functions
+- Maps can be found to reveal some places of the wilderness
+
+27/11/2000
+- Exp gaining weapons will gain levels way slower
+- Ring & Amulet random artifacts will only be "Ring of foo" and not
+ "Ring of Slow digestion of foo"
+
+30/11/2000
+- Level gaining Artifacts have been significantly toned down
+- Sauron lost his chances to drop The One Ring
+- Blood of Life potions & Staves of Wishing are more rare
+- Your god wont always resurrect you even if you have enough piety
+- When leaving corpses, Possessor equipment will be dropped to floor
+ to prevent their form being "lost"
+- Sandworm lair, a new dungeon
+- Staves of wishing now only have 1 charge
+
+12/12/2000
+- A patch to the alchemist patch from KUSUNOSE Toru, they should now work
+ perfectly
+- h-system.h fixed so it should compile fine on Linux
+
+29/12/2000
+- New r_info.txt with the HAS_LITE flag, thanks to Static Chaos :)
+- Now some monsters can have a light around them
+
+03/01/2001
+- Phial of Galadriel and Phial of Undeath now use the same symbol(yellow ~)
+
+06/01/2001
+- Fates now show up in the character dump (thanks Kusunose)
+- Scrolls of Divination are more friendly now (thanks Kusunose)
+- Artifacts in monster inventories not yet seen are not shown in the
+ artifact list (thanks Kusunose)
+
+08/01/2001
+- Zweihanders are now 2-handed weapons(as they always should have been :) )
+
+11/01/2001
+- Ego Rods are now "xxx rod of egoname of power" and not
+ "xxx rod of power of egoname"
+- Fixed some typos(parchEment, NumeRoNean, ...)
+- Fixed a bug with junk randarts
+
+18/01/2001
+- Gods now need more sacrifices
+- Disabled the monster lite feature right now because it's HORRIBLY buggy
+- The Sandworm Queen will now drop the Sandworm armour when killed
+
+03/02/2001
+- Now you can separate a dungeon entrance from a dungeon exit on the
+ wilderness map using the WILD_ix_iy__ox_oy flag in d_info.txt.
+ ix, iy are the coordinates on the wilderness map of the entrance.
+ ox, oy are the coordinates of the exit.
+ Note that each of them(entrance and exit) must have a physical entrance
+ on the wilderness map(that is a line in w_info.txt).
+ When you use the entrance to enter you get to the first level but when you
+ use the exit to enter you get to the last level.
+ So now you can have dungeons that create shortcuts in the map.
+ Or even allow to go in previously unreachable places(like now the dungeon
+ of Moria allows you to reach a secret valley in the Mountains of the Moria
+ which allow getting to some other dungeons)
+- Fixed a bug with fountains (yeah, fountains of the Blood of Life were quite
+ unbalancing :)
+- Priests can't use Tribal magic anymore
+- Mages can't use Crusade & Illusion Magic anymore
+- Rogues can't use Crusade anymore
+
+05/02/2001
+- Found why under certain circumstances forbidden objects could still be
+ generated (and that's also fixed now :) )
+- Dungeons & Monsters can now have object themes (yeah I know, I stole that
+ from Zangband, though the dungeon theme was in my head for long, but
+ when I steal I do admit it ...)
+ For example The Sandworm lair is really full of magical items, while the
+ Orc Caves are more on the side of the weapons & armors. And the Dragon Lair
+ is filled with ... oh well everything :) and so on.
+ So it's now really worth to get out of the 4 basic dungeons and see the
+ wild world!
+ All dungeons are done with the themes, it could take a bit longer for
+ the (1031) monsters... :)
+ NOTE: Dragon Scale Mails are considered TREASURES
+
+07/02/2001
+- Ego Monsters, yes like Ego items but for monsters. New file re_info.txt
+ defines all possible ego monsters types (skeletons, zombie, ...). It can
+ modify, the flags, spells, level, speed, ac, ... of the monster that is
+ turned into an ego monster.
+ This will increase the randomness of the game, increase the number of
+ monsters from 1031 to .. a lot... :)
+ There are not much ego monsters right now, so feel free to submit them
+
+09/02/2001
+- Sorcerors can't use much armor
+- Beastmasters have been give access to the Tribal realm, the Beastmaster's
+ powers are now available through the 'U' key
+- Player Raise death spells will now really create an undead. For example
+ you cast raise death upon a kobold corpse and you can get a Skeleton Kobold,
+ or a Zombie or a Spectre one. New Undead types will be added later. And I'm
+ open to ideas naturally
+- Narya activation is now Healing (500)
+- Nenya activation is now Healing (800)
+- Vilya activation is now Healing (900) and cures Black Breath
+- Daemonologists can now wield their books (in the weapon slot). When used this
+ way, spells are cast in 1/3 of a turn otherwise it takes 5 turns
+
+11/02/2001
+- Specialized ESP, like Orc ESP, Troll ESP, Dragon ESP, ...
+ They are less rare than full esp, but full esp is more rare
+- Fixed a Runecrafter bug which could crash the game if no second rune was
+ selected
+
+11/02/2001 - PernAngband 4.1.5
+
+11/02/2001
+- Ents get nearly no sustenance from eating
+
+15/02/2001
+- Center player option
+- Alchemist artifact creation now requires player level magic essences to
+ work. The stats are permanently reduced upon failure (as it always meant to
+ be). You PERMANENTLY lose 100 max hp when trying to create an artifact.
+ This should reduce the number of mad alchemists :)
+- Dark Swords as a new item type. They generate an antimagic field of 50%
+ minus the sum of the enchantment (a +5+5 one will only do 40%) on a
+ 5 tile radius (also minus the enchantment)
+- Unbelievers now generate a (player level)% antimagic field on a distance of
+ (player level / 10)
+- An antimagic field disables any form of magic on the user, and can prevent
+ monsters from casting spells (not breathing). A 50% antimagic field will have
+ a 50% chance of stopping a spell
+
+18/02/2001
+- Normal Artifacts. Normal Artifacts are artifacts found directly in k_info
+ that doesn't require a place in a_info. That allow strange artifacts, like
+ wands, rods, staff (those were possible already but ugly), ... and even
+ food
+- The Rod Tip of Home Summoning is now a Normal Artifact
+- The Greater Ration of Health is the first (very rare) food artifact !
+ When eaten it provide +70 hp permanently
+- The Potion of the Blood of Life is now a Normal Artifact
+- Invulnerability can no longer appear in fountains
+- The Ring of Precognition is now a Normal Artifact
+- The Ring of Wraithform is now a Normal Artifact
+- The Scroll of Deincarnation is now a Normal Artifact
+- Hell is now the Nether Realm
+- Fixed a bug that created stairs at bottoms of dungeons
+- Extra blows can only be provided by things in the weapon slots
+- The Scroll of Mass Resurrection
+- Renamed Warrior-Mage to Warlock
+
+20/02/2001
+- The Wand of Stone to Mud of Thrain and The Wand of Fireball of Gandalf
+ got the EASY_USE flag, allowing them to be used even by unskilled
+ characters
+- As does the Stone of lore
+
+23/02/2001
+- Fixed a bug that allowed people in quests to use the '<' key to get to the
+ wilderness timescale
+- Fixed a quest bug that allowed players to regenerate the quest many times
+- The Control the Three shadow spell is now much much more effective, since
+ it removes black breath and DG_CURSE. The only little annoying thing is that
+ it requires that player to wear the *THREE* rings. And that can only be
+ accomplished with either the Possessor class (though they CAN'T cast the
+ spell -- no hope for them) or The Scroll of Deincarnation
+
+10/03/2001
+- Monks can choose which spell to learn
+- Fixed a bug with limited ESP description
+- Fixed a bug in Possessor titles
+
+09/04/2001
+- DeathMolds can now teleport onto stores & such (all features that are
+ considered floor by the game)
+- Objects cannot be dropped on traps anymore
+- The Sandworm Queen no longer appears multiple times
+- Harpers wont crash at the start anymore
+- Panic saves will use the playername.pnc filename (thanks Improv)
+- Symbiants can't hypnotize monsters that aren't pets anymore
+
+15/04/2001
+- Add an old patch from SC which allows dungeons to project an attack every
+ few turns. For example a player in the Nether Realm will be hurt by nether
+ every 3 turns for a damage of 10d10.
+ The syntax is(up to 4 lines):
+ E:<dice>d<sides>:<frequency>:<attack type>
+- Volcano now does 2d10 damage each 10 turns, beware scrolls on the floor :)
+- Lost Ruins of Numenor does 1d1 acid damage each turn (water will RUST you)
+- Cirith Ungol will poison you every 20 turns for 4d4
+- Illusory Castle will confuse you every 6 turns for 6d2
+- Small Water Cave does 1d1 acid damage each 20 turns (water will RUST you)
+- Nether Realm is unlightable (as is the Maze) and always empty levels
+- Nether Realm is now guarded by Tik'srvzllat who guards the Ring of Phasing
+ a powerful ring that allow wraithform and immunity to nether
+
+16/04/2001
+- New Race system, Now you select a race AND a race modifier at birth.
+ For example you choose to be a human vampire, or a dwarf skeleton, ...
+ Then some modifiers apply (stats, skills, extra powers, ...). Note that
+ all races can't use all race modifiers
+- New race modifier, Barbarian, the old barbarian race is gone
+- New race, the Wood Elf from CathAngband, masters of the bow, with 1 extra
+ might and 1 more if they use bow and are high level enough
+- Extra Might can now be > 1
+- Penalty for priests using non blessed swords/axes/polearms is now (-15,-15)
+- New weapon category: Axes
+- Add Weaponmaster class from Gumband, trained into one weapon category, being
+ great with it but bad with anything else
+
+18/04/2001
+- Aranruth is a broad sword, 15lb, 3d5
+- Fixed lots of spelling errors/typos thanks to Improv
+- Add a new birth option: Astral (ghosts from Kamband, name from Gumband)
+ It enforces vanilla town and makes you start at level 98, you can't recall
+ and need to reach town
+- Trap doors can't appear at the last level of dungeons or in non dungeons
+- The concept of non-dungeon places: some "dungeons" got the FLAT flag
+ meaning they are ... flat, like a forest
+- The concept of Towers, going up instead of down
+- Updated birth.txt to take in account the race modifiers
+- Wood Elves can go through trees
+- Ammo similar to the one in your quiver will always be picked up
+
+20/04/2001
+- The death fate is way different now. When the player enters level he is
+ fated to die on he gets teleported to a special level in a special dungeon.
+ the level is empty, small and full of really out of depth monsters. Recall,
+ genocide, ... are forbidden. There are no stairs, the only way to leave it is
+ to kill every single monster of the level. Then the player is teleported
+ back to town. Chance of surviving are *LOW* but not nonexistent :)
+- The knowledge rune will now probe monsters
+- Runecrafters are now playable (new damage formula) even at low levels !
+ Now lets hope they are not TOO powerful :)
+- Runecrafters upgraded. They can now:
+ 1) Cast a spell on the fly (as before)
+2) Cast a runespell they memorized before (can memorize up to 100)
+ 3) Cast it from a carved runestone (uses 75% mana and does NOT need the
+ runes to be present in the inventory, but consumes the runes during
+ creation and it must be carried around to be used)
+- Mormegil is now a Darksword and is quite nice
+- Lesser & Greater Krakens now drop corpses
+
+24/04/2001
+- Add random towns in the dungeons. There can be up to 4 towns per dungeons.
+ Not all dungeons (well should say places) can hold towns. Random town shops
+ are took from the possible shops in st_info.txt with the RANDOM flag
+- Stores in st_info.txt got flags
+- When carving a Runestone the involved runes are destroyed
+- Random towns can have different shapes, from vanilla one to hidden one
+ (the stores are placed randomly on the level, without any buildings)
+- When the player is invisible and does not have see invisible the @ symbol
+ disappears
+- Cannot locate undetected traps by simply 'l'ooking around
+- Mariliths cannot use boots
+
+26/04/2001
+- The player is no longer "teleported away" when leaving some buildings
+- Level gaining artifacts rarity have been increased
+- Death Ray will actually kill the player
+- Removed traps of death ray (now that death ray insta-kills)
+- Recharged wands/staves cannot be extracted anymore
+- Wraithform no longer reduces damage
+- New hp formula for Possessors
+- Some sentences for the DarkGod monster to say, based on #angband :)
+
+28/04/2001
+- *WARNING*, squelch list has to be checked upon importing an old savefile
+- Every item can provides blows since Alchemists can't create that many arts
+ now
+- Wielding a mage staff (even non ego ones) will provide with a decrease of 20%
+ of the casting speed (using 80 energy instead of 100)
+- Add makefile.bcc thanks to Arch
+
+29/04/2001
+- Some Spelling/Grammar fixes in lib/help/ -- Improv
+- Levelling artifacts will now use a new scheme:
+ There are now groups of abilities (the Fire realm, the Cold Realm and so on)
+ Whenever a weapon goes up a level, it gets to either:
+ 1. become enchanted by +2/+1
+ 2. gain another attribute from a group it already has.
+ 3. gain +1 to hit, and a point.
+ when a weapon gains a certain number of points, it might buy access to a new
+ group. Note that some groups can contain good AND bad abilities
+- Pet shop now sells scrolls of summon never moving pets
+- Lots of fixes (ammo weight, god flags, ...) thanks to Kusunose Toru
+- Towers deactivated for the time begin
+- Rods considered good
+
+01/05/2001 - PernAngband 4.2.2
+- Force attacks will pull away monsters (from Dr)
+- Fist of Force is now a force attack
+- Unbelievers can now detect traps at level 25 and destroy them at level 35
+ Press 'm'
+
+03/05/2001
+- GoI no longer protects from insanity
+- Colored messages
+- Artifact creation results in a 40hp loss
+
+05/05/2001
+- Hermit subrace, magic adepts weaker physically but have more mana reserves
+- Use upx for exe compression of the DOS version in makefile
+
+07/05/2001
+- Fixed makefile difficulties in makefile.org, and uncommented one of
+ the safer sets of CFLAGS/LIBS in that file as a good default -- Improv
+- Fixed some other spelling problems, notably in cmd7.c -- Improv
+
+13/05/2001
+- Reworked the old (ugly) activatable mutations, race powers, ... system to a
+ new unified one. Race, subrace, class powers are defined in the tables in
+ tables.c. Now the new system will allow for artifacts to grant powers, it
+ also allow intrinsic powers (i.e. you quaff The Potion of Blinking
+ and from now on you can blink at will)
+- There is a 2% chance of gaining the grow mold mutation when eating a slime
+ mold
+- Priests gets the curse detection power
+- Oops the Sandworm Queen wasn't confusion resistant :)
+- Added various granted powers to various artifacts and ego items
+- Sorceror allowed spellbooks are now in tables.c (Mrealm_choice)
+- Changed the install rule to do something sensible on Unix. Changed config.h
+ to suit. Default dir for lib is now /usr/lib/games/pernband/
+ Hopefully this won't make too many people angry -- Improv
+
+15/05/2001
+- New GFX by Andreas Koch
+- Fixed some entries in a_info
+- Monster memory now tells people when they're facing a Nazgul (Kevin W Thomas)
+- Fixed a bug in dungeon town generation (Kevin W Thomas)
+
+16/05/2001
+- Added makefile.WHICH, fixed up my earlier patches to add a real install
+ rule - Improv
+- Pseudo id now works for potions, scrolls, wands, staves and rods. Magicians
+are better at pseudo id-ing those than warriors (SC)
+- Can only use one ultimate artifact at a time (not that it really
+ matters given that no-one will ever find one :) )
+- Fixed a bug preventing The Baby Minotaur from being generated if it was
+ already generated for a previous character using the same savefile
+
+17/05/2001
+- Upgraded to latest z-term code
+- Illusory castle got a guardian, The Glass Golem (a NASTY thing) hoarding
+ The Helm of Knowledge, which auto ids every item you walk onto and activates
+ for insanity + *id*
+- Crushed all oriental items(nearly) of the game, they just doesn't fit the
+ general theme
+- Gigantic dungeons (flag DOUBLE) from SC
+- Ice lair as a Gigantic dungeon from SC
+- Dragon Lair is gigantic now
+- Between gates travelling damage is now /2
+
+18/05/2001
+- Checked in an EXTREMELY raw and broken version of my z-term changes that
+ produce cmovie files. It's disabled by default, if you want to play with
+ it, play with z-term.c ... Until I incorporate a cmovie player into
+ Pernangband, you can use the one I wrote for MY roguelike MoLD, available
+ at http://www.sourceforge.net/projects/mold/ . Little plug there. -- Improv
+
+21/05/2001
+- Moria WILL have downstairs at the bottom
+
+24/05/2001
+- New quest code ! Quests are no longer in *_info.txt files but are able to do
+ many new things, and the code is less ugly than it was :)
+- Random Quests refitted to use new quest code, now each level with a random
+ quest will have a vault with the monsters you need to kill inside, and a
+ princess that is held prisoner (your goal being to save her)
+- Refitted Thieves quest
+- New Bree quest, The Lost Hobbit ! save Merton !!
+- New key, 'y' to give items to monsters
+- Elven vampires no longer get resist lite, that was silly AND unbalancing
+- Artifact arrows wont come in piles anymore
+
+26/05/2001
+- Removed Wizard & prior classes, Mages & Priests can now use their realms
+- Refitted Crusade realm, some new (fun) spells
+- cmovie changes to make it work better. Should have it all cleaned up and
+ portable very soon. -- Improv
+- Updated pern_faq -- Improv
+- Power mages start with a 2d4 spells
+- Fixed a bug which made random artifacts destroyed by auto-squelch. --
+ Kusunose
+- Changed spellbooks colors to be more .. accurate
+- Add the Spirit realm, taking the place that was designed for it a long time
+ ago, the one that tribal used until now, between Valarin and Shadow.
+ Tribal is not removed, but it can only be used by some nature-like classes
+ (like beastmasters, rangers, ...). Some spell names & spellbooks names are
+ took from psiband Psionicists
+
+28/05/2001
+- disturb_move option off by default
+- Bree town totally redesigned by Mynstral to be more accurate the LoTR
+ description of it and to be more .. beautiful :)
+- New quest in Bree after the hobbit one, The Trolls Glade
+- Dark Horseman quest required level raised to 35
+- Massive updates to tables.c, fixed spelling of several spells, renamed a
+ few, fixed spelling of several lvl-specific class names, renamed a few.
+ Also working on maintainability for race/class restriction code in same
+ file. -- Improv
+- Entirely replaced TANG.txt with new stuff I wrote -- Improv
+- Permanent wraithform no more do the "You feel opaque" every few turns
+- Recoded the passwall() function to be... less ugly and less buggy
+- Archers learn to protect their arrows from fire as they advance levels
+- The Toris Mejistos guarded by Ar-Pharazon the Golden at the bottom of
+ the lost ruins of Numenor
+- Fixed random artifacts activation bug
+
+30/05/2001
+- Spell lists are now colored
+- Spell descriptions when browsing
+- Half magery spells descriptions done by Parak
+- The potion of learning is a k_info artifact now
+- Added color to seen unique list, quests list and a few others
+
+31/05/2001
+- Descriptions added to first five Shadow books (Shaun "arch" Sides)
+- Nazguls lost the DG_CURSE upon death
+- The Spiders of Mirkwood quest is the first Lothlorien quest
+- Magestaff of power now increases spell power while magestaff of spell
+ holds 2 spells (switching their previous behaviors)
+- New ego item system, externalized everything, it's half based on Matthias
+ Kurzke patch
+- Rewrote e_info.txt for the new ego system, the rarity should look like the
+ same
+- Bows of Numenor & Lothlorien as new ego items
+- DSM can be ego
+- some new ego & tweaks to existing egos
+- 3 new light types: Everburning torches, Dwarven lanterns and Feanorian
+ lamps
+- New ego lights: of Brightness, of *Brightness*, of Illumination, of Boldness,
+ of the Shadows, of Infravision, of the Eternal Eye
+- The Phial of Galadriel is now level 20 rarity 10, the ego lights & other
+ perm lights should be enough until then
+- Ego light: of Fading, will make non-permanent the permanent lights :)
+
+01/06/2001
+- Add auto curse
+- The One Ring will not be cursed when generated but will have the auto_curse
+ flag, so it is possible to use it and take it off for VERY brief periods...
+ but if it becomes cursed while you're wearing it .. you're stuck with it
+- The same applies for the Toris Mejistos (except that it's not permacursed)
+- Moved options around
+- No more books of lore, they are now Cloaks of Mimicry (and can be ego items
+ or randart)
+- Monsters that can suicide cannot be random quest monsters
+- Alchemist artifact creation totally changed. It now takes player level
+ essences of magic and 1 hp to "imbue" a normal non-artifact, non-ego item
+ into a pseudo artifact.
+ You will then wield/wear it and it'll gain some xp when you do
+ (reducing the amount you gain)
+ When you think you have enough xp, you finalize it (actually select the
+ flags that now cost xp) with the xp it has and the pval you choose.
+- Did more spelling updates on this file -- Improv :)
+- Finished moving the class-race combos in tables.c to a cleaner
+ format -- Improv
+
+02/06/2001
+- Copied Vanilla random artifacts name generator
+- Random ring & amulets are now "The Ring of foo"
+- Lights can be random artifacts
+- Described all Valarin spells
+- All non spellbook spells (Mindcrafters, necromancers, mimics) got a
+ description
+- All harper songs described
+- DragonRiders will learn to fly at level 17 (but they always can levitate),
+that's an old Divia suggestion
+- Magestaves of Spell still carry 2 spells, but they are randomly generated
+ using the runespell (magic of the Runecrafters) system
+- First draft of monsters gaining xp & levels
+- Magestaff of Mana & Power renamed to Magestaff of Wizardry (suggested by JLE)
+
+03/06/2001
+- Beginning work on unifying the load/save code to make
+ maintenance easier -- Improv
+- load2.c and save.c are now one file, loadsave.c ... Will now be working on
+ moving them to using unified functions so this code will be easier to
+ maintain. -- Improv
+- Reworked monster AI. A monster can now be enemy, neutral(oriented toward
+ player or monster or full neutral), friendly, pet or companion(will follow
+ you on other levels)
+- Pets (and other friends) will be less stupid
+
+04/06/2001
+- You can now assign a target to a pet
+- The Phial will now have a similar effect to song of morning (tribal)
+- The number of companions killed is taken into account in the score
+- New quest at Lothlorien, the poisoned water, with an unique reward,
+ a DSM of elvenkind (cannot be generated under normal circumstances)
+- Renamed Nibelungs to Petty Dwarves
+- New curse, you cannot drop the item
+
+06/06/2001
+- Multiple messages will show up as only one message with a multiplier
+- New Minas Anor layout (MUCH BIGGER) by Mynstral
+- Fixed the princess not appearing (she WAS there but got killed)
+
+08/06/2001
+- Fixed Mormegil (it was possible to use it with magic)
+- Companions stay even if you use the overview wilderness mode
+- Some monsters will tease the player but always stay out of melee range
+- A new pet command to make them forget their target
+- New ego type for heavy armors (Dwarven) with + to STR and maybe CON
+- Ammo & diggers doesn't add the tohit/todam to your total
+- Herbal healing at Gondolin will cure black breath
+- New store type: Master Archer
+- Rings can be ego objects now
+- Scrolls can be ego now (Fireproof)
+- Wands & Staffs (except of wishing) can be ego item: of Plenty
+
+10/06/2001
+- Possessor now have mana (based on INT) and use it to cast the spells of the
+ monster they are using
+
+12/06/2001
+- Deathmolds can now use the overview wilderness map but the travel time is
+ higher and there is a chance to not blink right and move onto an undesired
+ square
+- Changed Summon Cyberdemon to Summon High Demon (with the incoming new JLE
+ demons it'll be nasty)
+- Added Possessor monsters, they'll hunt corpses and incarnate into them !!
+ Now you must fear even dead monsters
+- The Phial of Undeath now has a radius of 5
+- Unique monsters list is now sorted (but Morgoth is always at the bottom)
+- Add monster traps from PsiAngband. Rogues can now set them (with the powers
+ menu, 'U' key)
+ Direct quote from Psiband change file:
+ Rogues can set traps for monsters. This requires a "trapping kit" as a trigger
+ and something to "load" the trap with.
+ All scrolls, potions, wands, staffs and rods can be used (with the appropriate
+ trigger) as traps to confuse, poison, teleport, genocide, ... unwary monsters.
+ But standing next to a trap with area effects will hurt the player, too.
+ There are also traps that shoot ammo: hidden catapults, bows and xbows.
+
+ Some monsters can disarm traps, and a monster that has disarmed one of your
+ traps will learn how to disarm all of them...
+
+ Ammo Traps can have (+hit,+dam) just like bows. They can also be enchanted.
+ All traps can have a [+AC] showing how hard it is to disarm it.
+ There are also ego and artifact traps.
+- Add the ego & artifacts trap kits from PsiAngband
+
+15/06/2001
+- Hallucination monster attack (JLE will use it for the review of r_info)
+- You can use up to 5 R_CHAR_x flags in the F: line or re_info.txt to specify
+ races to which the ego powers are available
+- Crusade realm described
+- The Star of Elendil now has a light radius of 4
+
+17/06/2001
+- The dungeon info file (d_info) now allows more than one monster generation
+ rule. The R: line specifies the percent of monsters affected by the rule
+ and the mode of the rule(AND, NAND, OR, NOR). So it is now possible to
+ have 60% of orcs, 30% of trolls and 10% dragons
+- New dungeon in Mirkwood, Dol Guldur !
+- Sorcerors cannot use Valarin (prayers should not be available to mages) and
+ Tribal (instead they get Spirit)
+- Fixed some misspellings in lib/help/ -- Kusunose
+
+18/06/2001
+- Auto pickup option now defaults to false
+- Fixed bugs with the cursed ego items
+- Described the remaining Magery spells
+
+19/06/2001
+- Point based character generation
+
+20/06/2001
+- Finish cmovie support !
+- Added an interface to cmovie (press | key in both normal or roguelike set)
+ It asks for a name (it will add the extension itself) and then if you wish
+ to play or record it.
+ The cmovie files (.cmv) are located in lib/cmov, note that they quickly
+ become huge and so you REALLY should compress them before sending to friends
+- Fixed a bug that prevented mutations from being correctly cleaned
+
+21/06/2001
+- Special artifacts can be placed anywhere in a_info, they just need the
+ INSTA_ART flag
+- Emptying lite warnings should work now
+- Added new quest, not found in a castle.. I won't say anything more :)
+
+23/06/2001
+- Added 2 new dungeon flags:
+ LIFE_LEVEL will generate levels with a cellular automaton algorithm (looks
+ like a game of life)
+ EVOLVE will make a LIFE_LEVEL be continuously parsed by the cellular
+ automaton algorithm while the player moves, resulting in a living effect
+- New dungeon: The Heart of the Earth, branching on level 25 of Mirkwood
+ it uses the evolving algorithm :)
+- Added the new Minas Anor (one map screen total). Fully functional
+ (except for the random terrain via the plasma generator *hint,
+ hint -> DG*) --Mynstral
+- Moved the rarity of the Phial of Undeath to the one of Galadriel
+- Add Death Orb monster as suggested by Prfnoff a long time ago.
+ They only move when in LOS. They multiply (quickly) and can hit to parasite
+ which will make a new death orb spawns out of you later
+- Fixed a bug in cmovie that messed up the recording when the user specified
+ different char than the normal ones
+- Loadsave work is now pretty much complete. Barring the addition of
+ transparent compression, which might happen later, there shouldn't be any
+ reason why savefile compatibility should ever break again. -- Improv
+
+24/06/2001
+- Several bugfixes -- Kusunose
+ Player's symbol was never displayed if VARIABLE_PLAYER_GRAPH or
+ USE_GRAPHICS was #undef'ed
+ Eating a corpse sometimes crashed the game.
+ Stealing from a monster sometimes crashed the game.
+ Nether immunity won't work if player had nether resistance.
+ and some minor bugfixes.
+- Birth classes selection is now more user friendly
+
+27/06/2001
+- D: line enabled in k_info.txt
+- Added ingame information about the different objects kind one can find
+ It is accessed via the observe key ('I' in original keyset)
+
+28/06/2001
+- Add back the Eol quest at Gondolin, but it's now dynamically created
+ (the level layout and trap places are random)
+
+30/06/2001
+- Reimplemented Nirnaeth Arnoediad quest at Gondolin, but with a different
+ reward
+- Add a spoiler menu to the help menu, thanks to Dawnmist
+- Fixed a bug; Steal Item Trap sometimes crashed the game. -- Kusunose
+- Working on rewriting more documents in lib/help/ -- Improv
+
+03/07/2001
+- Fixed a long-lived bug with power mages. This greatly affects play-balance
+ with them -- no longer will the cost of many of their high level spells
+ be merely 1 mana. Also, removed some of their effects that never really
+ worked anyhow. -- Improv
+
+07/07/2001
+- Some more misspellings on this file are fixed. -- Kusunose
+
+11/07/2001
+- Cannot add essences to artifacts
+- Object descriptions are added in the character dump
+- Notes are saved in lib/note
+- Priests and paladins begins with 10 times more grace with their god
+
+12/07/2001
+- Rods with rod tips attached sells for higher price
+- Down shafts cannot get you out of a dungeon
+- Cannot enter water and such in overview mode when too burdened
+- The no_pickup_corpse option changed to prompt_pickup_heavy which will ask
+ a confirmation before picking up objects that might slow you
+- Add an menu to the option screen to dump/load options to a pref file
+- Fixed a bug with dungeon guardians being generated more than once
+
+13/07/2001
+- Unique list is now in 2 columns
+- Race selection screen made more user friendly with race desc
+
+14/07/2001
+- Reworked the spell system
+ Now each spell got a level that you increase as you learn it more and more.
+ The higher the spell level is the more damage it does, the more time it
+ lasts and such.
+ Also each class have a specific max on the number of levels they can achieve
+ in each spells. This should help the high mage class since they get twice the
+ max level of mages. Also illusionists gets more than mages.
+ Also note that sometimes one more level wont change anything while 2 or 3
+ more WILL change. And lastly some spells are not affected by levels at all
+ One last thing, sorcerors cannot learn spells and thus cannot increase their
+ spell level which will always be 1
+- Player races now have inherent body parts, so a deathmold cannot use
+ headgear or boots but can wear more rings
+- New DarkGod sentences by Static Chaos
+- Fortune cookie by SC
+
+15/07/2001
+- The more you known a spell the faster it is to cast
+- Every class can now choose which spell/prayer to learn
+- Began reworking the spell bonuses(from spell levels or mage staves) to a much
+smoother distribution, so if a point if used it WILL have impact. Done the
+ Valarin Realm
+- Done Magery Realm
+- Done Symbiotic Realm
+- Done Music Realm
+- Done Shadow Realm
+
+16/07/2001
+- Done Chaos Realm
+- Ingame contextual help(on by default, can be turned off in the options)
+ Only few stuff got help right now, but that'll be extended
+
+17/07/2001
+- Spell list with levels included in the character dump
+- Updated docs thanks to Dawnmist
+
+18/07/2001
+- Hypertext help system, use up/down/space/- to scroll, left/right to move
+ between links and enter to activate a link
+- Race mods selection screen upgraded
+- The k_info artifacts will have a name again(was a stupid bug)
+- Done Nether Realm
+- Unified savefile loading screen. Now when the game is started it presents
+ a screen allowing to create new characters or to load/destroy existing ones
+
+19/07/2001
+- No more breeders in poisoned quest
+- Add an option to show exp needed for next level instead of total exp
+- Objects with the temporary flag will be destroyed when it's timeout
+becomes 0, allowing spells to summon fiery blades and such
+- Valarin Realm got a spell to create a temporary Holy Avenger
+
+20/07/2001
+- Created a cygwin makefile (makefile.cyg) for Windows -- Dawnmist
+- Split spoiler help files into true spoilers and newbie help files -- Dawnmist
+- Continued minor edits of help files. -- Dawnmist
+- Possessors reworked again
+ Now they get between 1 and 20 mana based on the spell rate of the monster.
+ When you cast a spell the failure rate is determined based on the player
+ level, player wisdom, monster level and spell difficulty. If the spell
+ fails it is still cast but you lose a few mana. If it succeeds you don't
+ lose mana. If it takes you below 0 mana you are forced to leave your corpse.
+- Done Spirit Realm
+- Done Tribal Realm
+
+22/07/2001
+- fixed a bug in project_meteor() that crashed the game. -- Kusunose
+- Updated option.txt for exp_need option. -- Dawnmist.
+- Continued edits on help files. -- Dawnmist.
+- Done Crusade Realm
+- Rewrote bldg.txt for Pern 4.x.x. -- Dawnmist.
+
+23/07/2001
+- Redone help file colour scheme to allow orange/yellow hyperlinks -- Dawnmist.
+- Continued edits on help files -- Dawnmist.
+- Spell checked tables.c -- Dawnmist.
+- Spell checked this file :-) -- Dawnmist.
+- Updated features and objects in dungeon.txt help file. -- Dawnmist.
+- JLE reworked the monster list, some monsters are gone, some monsters are
+ changed and some are new
+- Along with r_info JLE also modified d_info, big thanks to him
+- No more quest for shelob in mirkwood(she guards cirith ungol now)
+ Instead you must hunt the necromancer that is said to lurk in dol guldur
+- As long as sauron his alive the nazguls cannot be permanently slain
+- Attacking a nazgul no longer destroy artifacts(well it can, but the chance
+ is 1 in 1000)
+- Done Daemon and Sigaldry realms
+
+24/07/2001
+- SURPRISE!! I did something (but what it was is a surprise too) -- Mynstral
+- Added debug 'B' command, changes body -- Improv
+- Added colours and hyperlinks throughout command.txt -- Dawnmist
+- Updated most command descriptions in command.txt -- Dawnmist
+- Minor updates to some other help files -- Dawnmist
+
+25/07/2001
+- Massive merges from my internal cvs tree of loadsave.c
+ Hooked experimental bzlib integration in an #ifdef
+ Gutted the old 'encryption' code
+ Hoping to gut RLE if bzlib changes work out
+ Added nice sentinel function -- Improv
+- Fixed class selection screen bugs, fixed savefile manager so it will work
+ with unix. -- Improv
+
+26/07/2001
+- Added a quest map for Gondolin. -- Mynstral
+- Gondolon last quest: Invasion of Gondolin !
+- Upgraded max suport to the new birth interface thanks to pelpel
+- Several fixes thanks to pelpel
+- Add an option to use either the new r_info coloring scheme(based on V one)
+ or the old one(based on Z)
+
+28/07/2001
+- Fixed a lock problem with global.svg on multiuser system thanks to pelpel
+- Done Magic Realm
+- Done Druidisic Realm
+
+30/07/2001
+- One can press 4 (left arrow) in class selection to get back to meta-class
+ selection
+
+02/08/2001
+- Updated several *_info files thanks to JLE, new arts, ego, objects, ego
+ monsters
+- Fixed a bug in ego monsters, now they works perfectly :)
+
+03/08/2001
+- Done Illusion Realm
+- Added macrofaq.txt to help system -- Dawnmist.
+- Updated/fixed a few problems in the help files, and linked in new macro FAQ -- Dawnmist.
+- Increased chance for player ghost to appear
+- No more ego monsters in town
+- Spectre subrace can only use 1 ring
+- Made bree and gondolin finally use the plasma generator, and added two terrain
+ features. -- Mynstral
+
+04/08/2001
+- Fixed a bug with ego monster generation that inversed ego rarities, thus
+ explaining the incredible numbre of spectres running around
+
+05/08/2001
+- Fixed the orc level in the moria
+- Bladeturner is now an UNTIMATE artifact, but can be activated for invulnerability
+- Major rewrite of magic and class help files -- Dawnmist.
+- Fixed a bug with saving/loading while doing invasion of ogondolin quest
+
+07/08/2001
+- Fixed Tribal realm
+- Major rewrite of race modifier help files -- Dawnmist.
+- Spellchecked this file - Improv
+- Reintroduced water hounds - Improv
+- Major rewrite of race help files -- Dawnmist
+- Graphics for shop doors -- Kusunose
+- With help of Antimatter, squashed item bugs related to negative pvals and
+ the signedness of some functions. -- Improv
+- Done Prayer Realm
+
+09/08/2001
+- Fixed a bug with evolving dungeon when saved/loaded
+- Only the quest monsters counts for quest, not clones, not normaly generated
+ ones
+- undead ego monsters cannot be mortal
+- Monster ego name can appear before or after the monster name(:B or :A at the
+ end of the W: line)
+- Object ego name can appear before or after the object name(B or A on the X:
+ line)
+- Fixed a long-lived item-pickup bug -- Improv
+
+10/08/2001
+- Ego monsters will be drawn in gfx mode
+- Add a birth menu to select the god to worship, druids are forced to get
+ Yavanna, priests and paladins are forced to have a god, others can choose
+ to be atheist
+- No more multiple artifact arrows
+- Continued edits on the help files -- Dawnmist
+- Completed the spell descriptions for the Shadow Realm -- Dawnmist
+- Vampiric weapons can be sold again
+- Staff & Wand of nothing of plenty cannot exist
+- Staff of wishing CAN be of plenty
+
+11/08/2001
+- fixed a bug with esp and flags5 not being saved thanks to kevin w.thomas
+- fixed a bug in nirnaeth quest
+- Reduced sorceror hp penality to -10%
+- Removed the screen coloration when berserk/wraith/goi
+
+12/08/2001
+- Fixed invasion of gondolin quest
+- Fixed lightning res amu
+- Add the Merchant class(thanks static chaos), they can get loans(watch out if
+ you dont pay back quickly) and request items at the merchant guild.
+ they can appraise items, identify items, warp items in chests. They get
+ an object based ESP(see monsters carrying objects) at higher levels, they
+ constantly detect objects around them and they can use portable holes
+ to get a bigger inventory(but items in it weights more)
+
+13/08/2001
+- Fixed font-ibm thanks to pelpel
+- Merchants gets the midas touch
+- Vanilla town option removed. Astral mode now make the player start in the
+ Halls of Mandos(levels 1-98) which do not have any entrance from the
+ wilderness(or any dungeons). When they get out they are in the wilderness
+ and can start playing normaly. And uniques cannot be generated in the halls
+ of mandos
+
+14/08/2001
+- Updated font-ibm and font-win thanks to pelpel
+- When selecting the number of random quests, * will get a random number
+- Score list now shows the subrace, but it breaks the compatibility with old
+ ones
+- Reduced xp needed by monsters to gain levels
+- Ego items are wishable now. i.e you can ask for "fiery dagger"
+- Updated font-ibm and font-win thanks to pelpel
+
+14/08/2001
+- Added the map for a new quest. -- Mynstral
+- Finished the Last Alliance quest
+- Number of companion a player can have at max depends of the class
+ necro gets 1 + (plev / 10), beastmasters 4 + (plev / 10, harpers 5
+ all others 2
+
+16/08/2001
+- Fixed ambushes
+- Added merchant help
+- updated mac suport thanks to pelpel
+- Reduced by about 6mb the memory req
+- Hidden towns are generable
+- Fixed a bug with weapon specialty at birth -- Kusunose
+- New item ability, some rare rings can add %(based on pval) to the chance
+ of getting a critical hit
+- Objects can now shimmer(ATTR_MULTI), but only base types (k_info) can have
+ the flag
+- Features can now shimmer, note that this can be slow. Please report if it
+ is unbearable on your machine(you can also disabled the avoid_other option)
+- Reduced memory footprint again
+- Reworked the 'U' power menu to be more nicer and intuitive while still
+ allowing macros. Each powers gets a fixed number that can be used as a
+ prefix to the command to bypass the menu. For example teleport is 5 so
+ to directly get teleport one can always do 05U
+
+17/08/2001
+- Described Chaos realm
+- Described Nether realm
+- Described Sigaldry realm
+- described Spirit realm
+- Fixed a bug with random quests
+- Fixed a bug in note taking, thanks to pelpel
+- Fixed the interact with visuals menu thanks to pelpel(the fix is not even
+ in vanilla yet :)
+- Fixed cmovie recording
+- Merchants can request ego items(same interface as wishes)
+- Towns in dungeons now get townpeople in it ... leveled townpeople
+- Eggs are now , instead of o
+
+17/08/2001 - PernAngband 5.0.0 aka "Mirmidonic Carbonizer"
+- Birth options now appear in the normal option screen, but as read only
+
+18/08/2001
+- Special levels reworked
+- Volcano is now Mount Doom and is found on level 65 of Mordor
+- fixed help system crash thanks to pelpel
+
+21/08/2001
+- fixed the hypnotic gaze bug
+- reduced between gates damage
+- daemon books can be enchanted
+
+19/08/2001
+- Beginning work on a new, better status screen. For now, it's assigned
+ to the debugging menu as the 'A' command. -- Improv
+- fatespoil.txt changed to fatespoi.txt
+- rogues get some shots for their trapkit at birth
+- Cannot dismiss the princess anymore
+
+23/08/2001
+- Fixed the special levels, thanks to mynstral
+- Described Daemon realm
+
+23/08/2001 - PernAngband 5.0.0b aka "Mirmidonic Carbonizer II"
+- Default pref files are in lib/pref
+- Random quests are disabled when using ironman_room
+- Add auto_more option -- beware it can be very dangerous
+
+24/08/2001
+- Increased general store price limit
+- Trapkits added to squelch list
+- Fixed a bug when displaying some k_info artifacts
+- Wand of Gandalf and Thrain are now k_info artifacts
+- Fixed 2 bugs with rogue traps
+
+25/08/2001
+- Necromancers can turn pets into companions
+
+26/08/2001
+- Special levels are no more fully known
+- Fixed fountain bug; shape of XXX did not take effect -- Kusunose
+- Described Illusion and Tribal realm spells -- Dawnmist.
+
+27/08/2001
+- Fixed bug with scrollable list of powers
+- Added Magical diggers, they grant stone to mud power
+- Added the Corrupted subrace gaining corruptions as they level thanks to
+ Luc French
+- Changed mutations to corruptions
+- Dragonriders are no more considered evil
+
+28/08/2001
+- Fixed some cmovie bugs
+- Fixed *godness* song on non artifacts
+- Greatly increased herbal healing price in gondolin, since it cures black
+ breath
+- Fixed bug with store item creation -- Kusunose
+
+29/08/2001
+- Totaly rewrote the random artifact system. It now use an external ra_info
+ file to define what power the artifact will get. The format is very similar
+ to e_info(expect it doesnt include the 5 flags sets). Each entry define for
+ which tval/sval it can be applied. Then when the game wants to create a
+ randart it simply defines a number of powers to grab and randomly pick up
+ the powers from ra_info(following the restriction, rarity and levels).
+ This allow a totaly change of the randarts if needed, an easy addition of
+ new powers, ...
+
+30/08/2001
+- Hidden doors are now hidden, in mirkwood they will look like trees, in
+ barrow downs they will be mountains or trees, and so on
+- Beastmasters can turn a pet into a companion
+
+31/08/2001
+- Half elf lost the str penality
+- Half orcs and half Trolls or now Orcs and Trolls
+- Saved levels are deleted when a new character is created
+- Renamed Holy Advangers to weapons of Aman, thanks to Timo Pietila for the
+ idea
+- Cannot reset recall to Mount Doom
+- The game time is now counted with the elven calendar (reckoning of Imladris)
+ (It isnt PERFECT, every 12 years it should have years of 368 days, but I
+ dont think many will get upset :)
+ A year is 365 days, with 6 months (Tuile, Laire, Yavie, Quelle, Hrive and
+ Coire), 3 middle days(Enderi) and one starting(Yestare) and one ending
+ (Mettare) day.
+ The game begins the 43rd Yavie the year 2890 of the third age, note that it
+ is the birthday of Bilbo :)
+- Note files (mainly) use the elven calendar to record things
+
+02/09/2001
+- Fixed several bugs (runespell deletion, ego wand and staff stacking etc)
+ thanks to oops -- Kusunose
+
+03/09/2001
+- Changed the 'Lev xxx' thing to a 3 letter name corresponding to the current
+ place(dungeon, orc cave, ..)
+- Enabled f_info D: line with an index(0 is general desc, 1 is to (forbid)
+ tunneling)
+- Changed the way total weight is calculed thanks to Kieron Dunbar
+- One can edit his background history at birth :)
+- Lich ego monsters can use the base monster powers
+- Raise death can bring a lich
+
+04/09/2001
+- Enabled E: line in f_info(same format as d_info)
+- F: lines enabled in lib/dngn files, they specify flags for the level
+- Fixed a bug with special level generation
+- Add bleeding and poisoning monster effects from EyAngband
+- The One Ring quest
+
+05/09/2001
+- Fixed the crashing bug after level 100 in angband
+- Gave Sauron 30% chances to drop The One if it is not already created
+- Code now allows bi-ego objects, thoght they are impossible to generate yet.
+ It will allow additing weapon/armors qulities(crude, broken, ..) easily
+- Add a quick start option that let you use the same char as you previous one.
+ Everything is the same execpt life rating
+
+06/09/2001
+- Abort menu in the Windows version is now compile option, disabled by
+ default. -- Kusunose
+
+07/09/2001
+- When a new day comes the game tells the player(at midnight)
+- Drain hp and mana are cumulative
+- Fixed file existence function for dumb systems :)
+
+07/09/2001 - PernAngband 5.0.1 aka "Brunswik Disipator"
+
+09/09/2001
+[B]- Turns in scores are based upon the start of the game not of the year
+[M]- Mimic are REALLY mimics, they can look like any object and appears as
+ objects when looked at. And they got an emperor
+[I]- Enhanced realm selection menu
+[B]- Farmer maggot shows up in the unique list
+[M]- Monster vs monster damage is now x3 to shorten fights
+
+10/09/2001
+[P]- Changed the boring Half-Giants race to the much more interresting
+ Beorning race. Descandant of beorn they can all shapeshift into a powerful
+ bear form at will. In bear form you cannot use weapons, gloves, shields
+ and boots. But you get powerful stunning/slowing/wounding attacks
+ (claw, bite, swat, hug) and innate blows. You also get bonuses and minuses
+ to some stats and to to hit, to dam and speed
+
+12/09/2001
+[O]- One Ring cannot be dropped by traps
+[G]- Implemented luck, an invisible stat which can only be approximately known
+ via self knowledge spell/potion. It affects quite a few dice rolls.
+ Each race gets a luck modifier, for most it is 0, but some gets penalities
+ or bonuses(hobbits are a lucky bunch).
+ Some objects also can grant luck
+
+14/09/2001
+[D]- The graveyard will now project a raise death spell on all bodies, meaning
+ you'll have to kill a monster, and destroy its body before it get raised
+ back in the form of a skeleton, spectre, lich, ...
+ PS: MOUHAHAHAHHAHA
+
+15/09/2001
+[B]- Bugfixes -- Kusunose
+ A message "XXXX blocking your way" was displayed when you went through
+ some walls or trees.
+ Hidden doors remained hidden if they were detected by spells, or if they
+ were opened by monsters and then closed. Thanks to kobayasi.
+ and some minor fixes.
+
+16/09/2001
+[m]- Implemented lua scripting language! More on that on the to-be docs
+ You need to get lua3.2 to make it work.
+[m]- Integrated lua3.2 source into the source, no more need for external
+ librairie
+[M]- Fixed store lockup bug thanks to Kusunose toru
+[I]- Partial 8x8 tile update -- Dawnmist.
+[m]- Cygwin makefile update -- Dawnmist.
+[P]- Externalized player races and histories
+
+17/09/2001
+[P]- Elves cannot be vampire anymore
+[P]- Hobbits get intrinsinc xtra might with slings at lvl 25
+[P]- Extended the possibilities of the player races file, it is now possible to
+ select what flags will be applied at what level and for what pval(if
+ revelant)
+[B]- Fixed non connected stairs on quests, thanks to luc french
+[I]- Removed screen dump/load commands, redundant with cmovie, and frees to keys
+[I]- Y( ( in roguelike keyset) key to chat with monsters
+[G]- Changed the way to get the lost hobbit quest
+[B]- Fixed a bug with eat magic corruption
+
+18/09/2001
+[G]- System shock when thrown out of one's body while wzearing cursed items
+[G]- Set the joke/Z/cth monsters off by default
+[P]- Externalized subraces to p_info
+[M]- No more joke mosters as quests
+[m]- Integrated an automatic help file converter(creates html files), command
+ line option -h
+
+28/09/2001
+[m]- makefile.org now supports Lua, uses Improv's installation rule
+ in all cases, it also understands make depend as well.
+ Read it, make necessary changes for your system, then make depend
+ followed by make.
+[B]- validate_bg() referenced a null pointer.
+[m]- CodeWarrior project file for the Mac port supports Lua.
+[m]- main-xxx.c for the Mac is now in sync with my Vanilla port -- pelpel
+
+29/09/2001
+[B]- Fixed herbal healing price
+[I]- 16x16 bmp/mask added to the cvs
+[G]- Cth/Z/Joke monsters options appears in char dump
+[B]- Fixed Crusade spell book browsing bug (Bug list #33) -- pelpel
+[B]- Fixed a bug; the first harper book was never sold in the bookstore
+ (Bug list #15) -- Kusunose
+
+30/09/2001
+[G]- Increased min player level for some dugneons
+[I]- Message can be multi colored
+[m]- Yesterday I got OS 10.1 and found that it fixed the new window
+ position bug (search for (_ _#) in main-crb.c), so I conditionalised
+ the workaround -- pelpel
+[B]- Fixed the combined rod pricing (Bug list #30) -- pelpel
+[B]- Typo in files.c: cht_monsters -> cth_monsters. Replaced non-ASCII
+ 0xa0's in angdos.cfg with 0x20 (i.e. space) -- pelpel
+
+01/10/2001
+[B]- Monks and Bear form didn't have combat messages -- since many lines
+ in the current flavoured messages mention weapons, I introduced a
+ hack to temporarily disable flavored_attacks for them, then just
+ process messages as usual, and restore the flag later (Bug list
+ #44 and #53) -- pelpel
+
+02/10/2001
+[B]- The trap/door destruction spell didn't destroy doors (Bug list #25) --
+ use of floor_type[rand_int(100)] results in a 'natural' terrain,
+ but isn't compatible with digging etc. Do they need fixing too? -- pelpel
+[m]- The main window resist resizing in the Windows port, like the Mac
+ ones (Arcum's problem, future Bug list #74 and #75) -- pelpel
+
+07/10/2001
+[B]- Fixed PowerMage mana consumption bug (Bug list #114) thanks to krosky
+ -- pelpel
+
+08/10/2001
+[B]- Fixed light source stacking bug (Bug list #7) -- Kusunose
+
+21/10/2001
+[M]- Add NO_CUT to some monsters
+
+22/10/2001
+[I]- Colors to news.txt
+
+25/10/2001
+[M]- Added gamma correction function taken from V2.9.x in util.c, since
+ new X11 file requires it, so does my main-gtk.c, ready to be submitted
+ -- pelpel
+[G]- Cannot use overhead wild map if being recalled
+
+26/10/2001
+[B]- Fixed long-lived dragonrider bug (xtra1.c), Darkgod please check to see
+ if the behavior is as you want it -- Improv
+
+27/10/2001
+[P]- Externalized classes to p_info.txt
+[P]- Externalized meta classes to p_info.txt
+
+28/10/2001
+[B]- Fixed display of race/subrace/class flags
+[I]- Add some color to the identify screen
+[I]- Ignore Acid, elec, fire and cold are merged in identify screen
+[I]- Inventory/equipment letter are color-coded when *identified*
+[O]- Item sets ! Some artifacts are working together. If you wear them
+ at the same time you get bonus powers. You can get partial bonuses i.e:
+ You have 2 artifacts of 3 artifacts set, you will get some bonuses for
+ them but not all.
+[M]- Add NO_CUT flag to monsters needing it thanks to
+ Runescrye
+
+01/11/2001
+[B]- Changed king to the actual winner name in the quest dump
+
+03/11/2001
+[m]- Upgraded to lua4
+[m]- It is now possible to define new magic powers(ala mindcrafter, necro, ..
+ powers) with a small lua script
+[O]- New item set the Dragon Slayer
+[m]- New gtk port thanks to pelpel !
+[m]- Mac makefile equivalent is updated, now with lua4 for all targets -- pelpel
+[m]- src/lauxlib.h is synchronised with src/lua/lauxlib.h -- pelpel
+[m]- LUA_NUM_TYPE in makefile.org is removed because src/lua/llimits.h now
+ has correct (read integer :-) default -- pelpel
+
+04/11/2001
+[M]- All dragons now shimmer, according to their breath types(took from LM's 4GAI)
+ That is also thanks to the neat info editor of static chaos :)
+[m]- Change my email adress to darkgod@pernangband.net, adds ideas@pernangband.net
+ and bugs@pernangband.net thanks to Tom Le
+[I]- Added gamma correction subcommand to "Interact with colours", and
+ updated main-gtk.c and maid-x11.c to work with that (they formerly
+ used an environment variable for this). Also added gamma correction
+ support to main-ibm.c and main-dos.c. CAVEAT: tiles don't react to
+ changes in gamma immediately, for performance reasons -- pelpel
+
+05/11/2001
+[m]- Removed notice of sf_extra value from savefile load code. We probably should
+ make the spot where it loads it a ls_skip and remove that older family of
+ versioning variables -- Improv
+[m]- Took a stab at code to make a dynamically allocated loadsave section. It's
+ not called because it needs support code that presumably DG will write.
+ With any luck it'll be sufficient to do the job -- Improv
+[I]- Updates to experimental new status screen -- Improv
+[B]- Fixed a bug that caused all monsters drop inappropriate things. Hydras now
+ just drop money again. Yay. -- Improv
+
+06/11/2001
+[m]- Added an automatic nice changelog generator based on changes.txt. To all people
+ with cvs access, please use the new format for changes.txt.
+ It is activated with the -c flag: pernangband -c changes.txt changes.nice
+
+07/11/2001
+[P]- It is possible to define player power(under the U menu) with lua scripts
+ (and thats easy :)
+
+09/11/2001
+[B]- (IBM, DOS, GTK) gamma_val is reset as well as old_gamma_val
+ when invalid values are specified, ensuring correct reaction -- pelpel
+[B]- File-Save was never active in the Gtk port -- pelpel
+[m]- gamma correction for Windows port. I'm too lazy to save it in preferences,
+ though. May be redundant since many drivers provide similar functions
+ -- pelpel
+[G]- Flat places no more have stairs, they have ways to next/previous areas that
+ are always placed on the edge of the level
+[D]- Level borders are now of the same type as the level walls, no more forest
+ surrounded by granite walls
+[B]- Haste Monster cannot haste as much as before
+[I]- Pets infight wont disturb the player anymore if disturb_other is off
+ (it is by default). In combinaison with auto_more it will totaly ignore
+ pet messages
+[O]- New item set, The Trinity
+[m]- Lua-ified item types(can add new ones with simple lua script)
+
+10/11/2001
+[m]- Added Gtk entries in the system pref files, also enabled new graphics
+ for X11/Gtk ports -- pelpel
+[I]- The target prompt will indicate if the targetted monster is a quest
+ monster or not
+
+12/11/2001
+[m]- Updated main-xaw.c to that from the same version as main-x11.c
+ i.e. 2.9.2. It now reacts pref colours and has graphics mode
+ (doesn't work with 8bpp though). CAVEAT: main-x11.c and main-xaw.c
+ should free unused colours after allocating new one. -- pelpel
+[G]- Troll galde quest only available at night
+[G]- Genocide is forbiden in the last alliance quest
+[G]- Invasion of gondolin quest will wait the end of the current quest to be
+ generated
+
+13/11/2001
+[m]- Variable savefile ! Lua scripts(or C scripts(quests)) can now add stuff
+ to the savefile without ever breaking the compatibility !
+ See an example ofthat in test.lua
+[B]- SPECIAL_GENE objects were generated out of context -- pelpel
+[B]- Inappropriate monsters could be assigned to randquests in
+ rare occasions. CAVEAT: it now uses an infinite loop to
+ avoid illegal choices! -- pelpel
+
+14/11/2001
+[G]- New quest, try cahtting with maggot instead of killing him, you murderer !
+[m]- Re-implemented object allocation table caching -- pelpel
+
+15/11/2001
+[B]- Inserted /* Paranoia */ code in kind_is_theme() to prevent "(Nothing)"
+ from generated due to missing drop theme in r_info. Player ghosts
+ had this behaviour as far as I know -- pelpel
+[m]- Changed the rand quest reward generation to make it compatible with
+ yesterday's fix -- pelpel
+[O]- Added new ego rod, of simplicity, thanks to Runescyre for the idea
+[m]- Max number of classes, races, subraces and realms is now 64
+
+16/11/2001
+[I]- Stole the death screen of KaMband, much nicer :)
+[P]- Removed the astral option. It is replaced by a subrace, Lostsoul, they
+ have intrinsinc wraithform(until they get back to the surface), start
+ with some identify scrolls and have all levels enlightened
+[B]- The find artefact fate was able to grant SPECIAL_GENE artefacts -- pelpel
+
+17/11/2001
+[D]- Dragon Lair renamed to Erebor, the misty mountains
+[P]- Rogues gets level/3% more changes of critical hits
+[D]- The wilderness "borders" are now Ekkaia, the Encircling Sea
+[I]- I ran out of keys, so I added an extended command mode. Press '#' (')' in
+ roguelike command mode) to acess to it. You can then enter the command
+ name or a shortcut if the command have one(usualy a command have a 1
+ letter name and a complete name). You can also press ? or help to get
+ the list of commands
+[I]- The time command is avaiable again for roguelike command set in the form
+ of the t/time extended command
+[I]- D/html-dump extended command to take an html screenshot
+[I]- Quest list is now ordered by danger level
+
+18/11/2001
+[B]- Attempting to go down shaft gave the message "I see no down staircase
+ here", thanks to Kevin W. Thomas -- pelpel
+
+19/11/2001
+[G]- Reduced the Spirit Realm Project Force spell radius as it increase levels
+[B]- Entering Nether Realm crashed the game, thanks to M.Itakura
+ -- Kusunose
+[B]- Polymorphing monsters in the wall crashed the game, thanks to to
+ M.Itakura -- Kusunose
+[B]- Sometimes random quest appeared on deep(dlv>98) Angband -- Kusunose
+[B]- Cursed EASY_KNOW items were not squelched -- Kusunose
+[B]- Replaced all checks against RF1_QUESTOR to MFLAG_QUEST -- Kusunose
+[B]- Shafts were not detected by detect stair spell -- Kusunose
+
+20/11/2001
+[G]- Traps have been tweaked down to be a bit less deadly, thanks Runescrye
+[P]- Summoner class! Thanks to Luc French for the idea and quite a bit of
+ the code
+[I]- New splash screen made by Jans
+
+21/11/2001
+[B]- Mathilde was allowed to use wepaon(when possessed)
+[I]- Finished all spells description, thanks to Runescrye
+
+22/11/2001
+[m]- Quests are lua-ified
+[m]- flush() is called before *that* DragonRider question, to prevent
+ catastrophic(?) accidents, taken from Kusunose's Japanese version
+ -- pelpel
+
+25/11/2001
+[B]- (GTK)Widget instance names should have begun with lowercase letters
+ -- pelpel
+[B]- (makefile)LUA_NUM_TYPE macro removed (see my 3/11/2001 mod
+ for makefile.org) -- pelpel
+[D]- Museum(Mathon-house) added to Bree thanks to Kusunose
+
+27/11/2001
+[I]- Added an option to allow the @ to turn into a number when health
+ drops. ideas from Mangband/PernMangband
+
+28/11/2001
+[m]- ANGBAND_DIR_USER is moved to ~/.pernangband on multiuser systems
+ (Unix, GNU/Linux), according to DG's preference, and against the
+ V/Z way... IMPORTANT NOTE FOR 422color USERS: please move
+ 422color.prf to lib/pref directory -- pelpel
+
+30/11/2001
+[B]- I forgot to give Tom Demuyt credits for the Unbelievers idea.
+
+01/12/2001
+[m]- Updated makefile.bcc. It now supports lua4. -- Kusunose
+[B]- The broken sword quest generates the real reward, thanks
+ Dawnmist
+[m]- Windows port now saves gamma_val in .INI file. -- Kusunose
+
+03/12/2001
+[M]- Rejoice ! no more nazguls as random quests
+
+04/12/2001
+[m]- Some patches from Kieron, thanks
+[I]- Kieron save squelch patch, modified to not save from chars to chars
+ it can just be used to dump suqelch to a .prf file and load it
+
+05/12/2001
+[P]- New class from Luc French, the Blade, weaponless fighter able to dodge
+ melee & some spells
+
+07/12/2001
+[B]- One could steal guardians' artefacts and reenter level to
+ obtain multiple copies (buglist??) -- pelpel
+[B]- Fates could be lost during level regeneration (auto_scum and/or
+ too many objects/monsters) -- pelpel
+[B]- (GTK)Fixed terribly stupid menu crash bug -- pelpel
+[B]- Climbing sets can now be pluralized thanks to John Q. Smith
+
+10/12/2001
+[I]- No more annoying infighting monster messages when turning disturb_other
+ off
+
+11/12/2001
+[B]- Randquests and special levels must be immune to all types of level
+ regeneration now -- pelpel
+
+12/12/2001
+[B]- Fixed alchemist art creation bug that allowed to use 4x exp
+
+13/12/2001
+[M]- Krakens lost their 6 ring slots, the tentacles are too big to put
+ rings on them ;)
+[B]- Bashed down doors weren't revealed -- pelpel
+[B]- The Phial and other activatable items didn't have (charging) message
+ -- pelpel
+[B]- There were extra spaces after names of unique corpses -- pelpel
+
+14/12/2001
+[B]- Detected traps should prevent running now -- pelpel
+[B]- The easy disarm code used easy_disarm and always_pickup flags in a very
+ strange way, resulting in undesirable pickup behaviours -- pelpel
+[B]- "Grass with flowers" shouldn't disturb running now -- pelpel
+
+15/12/2001
+[B]- Entrances to vaults used dungeon-themed terrain features,
+ sometimes making it impossible to dig them through -- pelpel
+[B]- DG's 27/11 mod is conditionalised to avoid doing so in the graphics
+ modes, because it hardcoded characters and breaks the graphics support
+ -- pelpel
+[B]- Mimic features are cleared when overwritten by streamers, to
+ avoid, say, tree-looking deep water -- pelpel
+
+16/12/2001
+[I]- Added overlay graphics for ego monsters, player subraces and traps
+ -- Kusunose
+[I]- Added 'search by name' feature to '/' command. -- Kusunose
+
+17/12/2001
+[I]- Player now drops out of the overhead wilderness view when becoming hungry/
+ emptying lite
+[B]- Change in spell stat did not affect Mana/Spells if spell stat were
+ not INT/WIS/CHR, thanks to kobayasi-san. -- Kusunose
+[B]- Change in WIS did not affect Sanity Points if WIS was not spell stat.
+ -- Kusunose
+[B]- Costs of Symbiontic power were not displayed in first page, thanks to
+ kobayasi-san. -- Kusunose
+[B]- Symbiontic power, scare and blind, was misordered, thanks to
+ kobayasi-san. -- Kusunose
+
+18/12/2001
+[I]- Graphics overlay for the three X11 ports (untested). It requires
+ USE_TRANSPARENCY and USE_EGO_GRAPHICS. USE_TRANSPARENCY was ugly,
+ but this... -- pelpel
+[I]- Graphics overlay for the two Macintosh ports, again, untested -- pelpel
+[I]- Add ra_info.txt (randart generator info file) thanks to Runescrye
+
+19/12/2001
+[I]- Graphics overlay for the DOS port (USE_DOS). Also fixed a bug in
+ the overlay support in the Mac ports. I removed always_pict
+ code from the GTK+ port, because it's really slow, judging from
+ the graphics performance on the Mac ports which use the mode
+ to support tile width/height customisation -- pelpel
+[B]- Left good_item_flag for special levels, but adjusted rating boost
+ a bit, because later fixes made +50 boost unnecessary
+ Also toned down the rating boost for randquests -- pelpel
+[D]- New quest in Dol Guldur
+
+21/12/2001
+[B]- Fixed the very old artefact generation bug (present in
+ Angband 2.7.8 -- 2.8.2) that forced "special artefacts" to be
+ generated in the a_info.txt order. It is really problematic
+ in Pern because of the depth of the Phial -- pelpel
+
+22/12/2001
+[B]- A Beorning's father was a Storm Giant sometime, and A Petty-Dwarve
+ was one of several children of a Nibelung. -- Kusunose
+
+23/12/2001
+[B]- Fixed a bug that allowed to throw items with CURSE_NO_DROP.
+ -- Kusunose
+[m]- Added spell spoiler creation in wizard mode. -- Kusunose
+
+24/12/2001
+[m]- (Mac)Eliminated busy waits in CheckEvents and TERM_XTRA_DELAY.
+ It works well on my machine, but I left the original code using
+ "#if 1/0" just in case -- pelpel
+[I]- Player now drops out of overhead wilderness view if a vampire and it's
+ daylight
+
+25/12/2001
+[B]- Reintroduced OoD restriction on randquest monsters (until dlev 49)
+ -- pelpel
+[B]- a fix for RNG problem with 64-bit machines, taken from V(?) -- pelpel
+
+27/12/2001
+[I]- Basic IRC facilities! 3 new extended commands: C to connect
+ D to disconnect and : to chat. Highly experimental.
+[B]- Find artefact fate could cause permanent loss of artefacts. The code
+ now tries to create a randart when there are no good choices instead
+ of always defaults to the Phial -- pelpel
+[B]- Randquests sometimes requested players to kill slain uniques,
+ making it impossible to continue the game -- pelpel
+[B]- (Carbon)Removed the dialogue indicating errors in AEProcessAppleEvent,
+ because an r.g.r.a post pointed out that this can be quite annoying
+ and Apple says they should generally be ignored -- pelpel
+[I]- DOS support for the irc client, needs libsocket:
+ http://www.phekda.freeserve.co.uk/richdawe/lsck/lsck.htm
+[O]- Updated ra_info, thanks to Runescrye !
+[I]- X11 Support for the IRC client.
+
+29/12/2001
+[G]- a New randquest type !
+[B]- Companions cannot be hurt by the player anymore
+
+30/12/2001
+[B]- Reduced all force spells because of the side effects of force attacks
+[M]- Monster breathing/casting force attacks will bounce the player.
+ Just like player's force attacks bounce monsters :)
+[M]- Fixed the IRC client some more.
+
+01/01/2001 - PernAngband 5.1.0 aka "Into the Fire"
+
+2002/02/19
+[B]- Normal (non-vampire) races didn't get mana regenerated at Inn -- pelpel
+[B]- The Mathom house acted like a normal shop when selling. -- Kusunose
+[B]- '-s' crashed the game. Thanks kobayashi for the fix -- pelpel
+[O]- Combining rod and rod tip now considers rod's cheapness flag.
+ -- Kusunose
+[B]- Beastmaster Shanty overpayed a bounty if monster's corpses are stacked.
+ -- Kusunose
+[B]- The random text code left files open in many error cases -- pelpel
+
+2002/02/20
+[B]- WeaponMasters were not restricted with their weapons. -- Kusunose
+[B]- Info text of 'disrupt mind' was described as 'dam'. -- Kusunose
+[B]- Fixed the "automatic ego filter" bug in the squeltch filter -- pelpel
+
+2002/02/26
+[B]- The polymorph random effect could crash the game. Thanks Kevin W.
+ Thomas for the detailed analysis of the problem -- pelpel
+[B]- Stat draining effect of Black breath could crash the game. Thanks
+ Kevin W. Thomas again for the patch -- pelpel
+[B]- With easy_disarm set, players were totally safe from detected traps,
+ whatever messages might say -- pelpel
+[B]- Ego graphics code is now only active when and only when 16x16 tiles
+ are selected -- pelpel
+[B]- Quest entrances/exits now require players to type '>'/'<' commands
+ to move in/out -- pelpel
+[m]- Shimmering terrain features no longer shimmer while running/resting,
+ to make them more bearable on slower machines and slow I/O systems
+ like GCU -- pelpel
+[I]- Incorporated the hopefully improved running code from the CVS version.
+ It uses CAN_RUN and DONT_NOTICE_RUNNING flags for non-conditional
+ checks (i.e. not controlled by the disturbance flags or requiring
+ immunity), so that most running problem can be fixed by editing
+ f_info.txt -- pelpel
+
+2002/02/27
+[B]- Many room walls didn't have the CAVE_ROOM flag set -- pelpel
+[m]- The tunnel code (ordinary one) now performs double check for
+ feat_wall_outer and CAVE_ROOM, so it is safe to use any terrain
+ features for outer wall, including those identical to fill_type.
+ Note: These two changes have very significant effect on the Sacred
+ Land of Mountains. I'm not 100% sure if this is what DG intended,
+ but I believe so reading flags given to it in d_info.txt -- pelpel
+[D]- There should be less not-at-all secret "secret" doors.
+ This does *not* mean that ancient prob, but those mountains enbedded in
+ plain wall in Barrow-Downs, for example -- pelpel
+[I]- Inven/equip/item choice in subwindows now clears to the bottom of screen,
+ to avoid glitches and in accordance with the way it worked -- pelpel
+[I]- Identify and *Identify* don't list known/fully known items in
+ object selection -- pelpel
+[m]- Depth/field name area is now 13 character long, so that names like
+ "shallow water" will fit, and "Lothlorien" is not truncated in GCU.
+ Also added short dungeon name prefix to the depth-in-feet mode -- pelpel
+
+2002/2/28
+[B]- Dungeon town generation could crash the game. Thanks Mogami
+ for the analysis of the problem -- pelpel
+
+1/03/2002
+[B]- Supplied missing suid code in 1) savefile removal action in the startup
+ screen, 2) time table lookup, 3) dungeon savefile removal, and
+ 4) bone file removal. Thanks kobayasi for the patch -- pelpel
+[B]- Less platform-dependent savefile processing code for the game start
+ menu, thanks again for kobayasi. It now uses files.c utility routines
+ for building appropriate savefile names -- pelpel
+[B]- Magical branding of weapon/ammo, when successful, now sets enchanted
+ item's discount rate to 100%, so that one can no longer make vast
+ profit or easily gain his/her deity's favour. Code adopted from
+ T.o.M.E. 2.0.0 CVS -- pelpel
+
+03/03/2002
+[P]- Give Ents scrolls of satisfy hunger instead of some food. -- Kusunose
+[M]- Added a command to dismiss companions in the pet menu. Code adopted
+ from T.o.M.E. 2.0.0 CVS -- Kusunose
+
+04/03/2002
+[B]- '/' in item selection didn't update screen correctly -- pelpel
+[m]- Moved auto-squelch code from process_player() to process_world() -- pelpel
+
+05/03/2002
+[m]- CAVE_TRDT wasn't cleared when a trap is disarmed, which had some
+ subtle effects and forced coders to double check c_ptr->info and
+ c_ptr->t_idx in various places -- pelpel
+
+06/03/2002
+[B]- Level generation could cause infinite loop in the Sacred Land of
+ Mountains -- pelpel
+[B]- Player ghosts were disabled in a way causing special feeling on
+ every level -- pelpel
+[m]- Changed repeated message code to V-CVS one -- pelpel
+[m]- Added another graphics mode variable called graphics_mode :),
+ somewhat like use_graphics in ZAngband, but it doesn't
+ require any changes to main-xxx.c. It's set within reset_visuals()
+ and used by map_info(), so that it doesn't have to do streq()
+ each time it is called -- pelpel
+[B]- Took 64-bit safe RNG from Vanilla -- pelpel
+
+11/04/2002
+[B]- Gave SPECIAL_GENE flags to the k_info.txt entries of SPECIAL_GENE
+ special artefacts -- pelpel
+
+20/04/2002
+[B]- Player is now guaranteed to have initialive after entering a level.
+ Thanks Joseph William Dixon for the patch -- pelpel
+
+22/04/2002
+[m]- Renamed 422colors.prf to 422color.prf, to make it fit with the 8.3 naming
+ convention -- pelpel
+
+24/04/2002
+[m]- Add support for multiline comments in lua: --[[ ... ]]
+
+28/04/2002
+[B]- Fixed a bug that caused gods start casting nasty effects when player's
+ grace becomes negative. It should have been -60000. -- Kusunose
+[D]- The inn in Bree is now The Prancing Pony. -- Kusunose
+[m]- Improved lua interface for defining new 'm' keys, magic powers, quests, ...
+
+05/05/2002 - T.o.M.E. 1.0.0 aka "Between the Darkness and the Light"
+
+02/1/2002
+[m]- (Mac, Carbon)Graphics mode performance improvement. When a user
+ chooses a fixed width font (as is almost always the case) and
+ doesn't change tile width & height, the higher_pict method is
+ used instead of *very* slow and inefficient always_pict to
+ draw things -- pelpel
+
+04/1/2002
+[B]- Normal (non-vampire) races didn't get mana regenerated at Inn -- pelpel
+[B]- Fixed the monster casting at other monsters but targetting you bug
+
+11/01/2002
+[B]- Sacrificing wands now decreases charges
+
+12/1/2002
+[B]- The random text code left files open in many error cases -- pelpel
+[m]- The prf file loader always searches for the user directory first,
+ then the pref directory if it can't find it there, so that user
+ can override the system defaults keeping the distributed files
+ intact. This also simpifies the pref loading codes in several
+ places -- pelpel
+
+13/01/2002
+[B]- Fixed more running problems (FEAT_SAND and FEAT_ASH) -- pelpel
+[B]- Some routines called malloc/free instead of C_MAKE/C_FREE in
+ the vault generation -- pelpel
+[B]- One wrong sign in the fractal cave code (vertical average) -- pelpel
+[B]- Fixed the store info file thanks to wrabhit23
+
+14/01/2002
+[B]- Ego items had extra spaces in their names -- pelpel
+[B]- (XAW)Terminals used wrong names. USE_EGO_GRAPHICS didn't even
+ compile -- pelpel
+[I]- IRC code for the XAW port. Caveat: it causes a linker error
+ if you USE_X11 and USE_XAW at the same time... -- pelpel
+[m]- the html help file converter now gets it's header and footer
+ from head.aux and foot.aux in lib/help to help website
+ designer adapt the generated files to whatever they want
+
+19/01/2002
+[B]- The Mathom house acted like a normal shop when selling. -- Kusunose
+[I]- Removed hard-coded direction keys in the skills menu -- pelpel
+[B]- Many room walls didn't have the CAVE_ROOM flag set -- pelpel
+[B]- More running problem (small trees in Mirkwood) -- pelpel
+
+20/01/2002
+[B]- final artifacts were not generated if they are k_info artifacts.
+ -- Kusunose
+[B]- Fixed get_com interface for lua
+
+22/01/2002
+[B]- Squelch on sense now destroys {good} items if it's told
+ "destroy good", but only when the "strong" pseudo-ID is in
+ effect. Doing so for the "weak" method would be too dangerous -- pelpel
+[m]- The running code now uses DONT_NOTICE_RUNNING and CAN_RUN terrain
+ feature flags for non-conditional checks, i.e. everything but doors,
+ stairs and alike, and those requiring levitation or immunity -- pelpel
+
+23/01/2002
+[m]- Included the lua tutorials by Fearof4s
+
+24/01/2002
+[m]- Replaced the field of view code with that from Angband 2.8.3--
+ -- pelpel
+[I]- view_special_lite and view_granite_lite that work with non-white
+ terrains (for ASCII mode only, already done for 16x16 tiles) -- pelpel
+
+25/01/2002
+[B]- '-s' crashed the game. Thanks kobayashi for the fix -- pelpel
+[B]- Doors are remembered, so that they work better with easy_open.
+ The easy_open code now performs checks for the perennially hard-to-handle
+ feature mimic field -- pelpel
+
+27/01/2002
+[D]- A fair number of dungeon guardians lost their defined artifact drop
+ and got a randart drop instead. The removed arts are back top normal
+ behavior(can be found)
+[I]- Inven/equip/item choice in subwindows now clears to the bottom of screen,
+ to avoid glitches and in accordance with the way it worked -- pelpel
+[I]- Identify and *Identify* don't list known/fully known items in
+ object selection -- pelpel
+
+29/01/2002
+[B]- monster_carry() could cause permanant artefact loss. A similar code
+ in quests and guardian artefact generation are also fixed -- pelpel
+[D]- There should be less not-at-all secret "secret" doors.
+ This does *not* mean that ancient prob, but those mountains enbedded in
+ plain wall in Barrow-Downs, for example -- pelpel
+
+20/01/2002
+[D]- Some spells can now stay in effect for a while, like a cloud of poison
+ will stay in place and poison everything passing in it
+[P]- Changed the magic system, it now uses schools of magic instead of
+ realms. A school contains much less spells than a realm. Each spell
+ is unique and dont make others redundant. Also all spells tries to stay
+ usefull for the whole game, by increasing in power and effects with levels.
+ A spell can be assigned to more than more school, in which case all the
+ schools need to be raised to obtain more power. All spells are implemented
+ in lua, to make it easy to tweak them.
+ All spells arent coded yet but my plans are for those schools:
+ Mana, Fire, Water, Air, Earth, Mind, Conveyance, Meta, Temporal,
+ Divination, Nature and Nether
+ It may change somewhat but thats the general idea :)
+ Books are not specific to a school, they can contain any spell from any
+ schools, it is even imaginable to have randomly created books
+
+01/2/2002
+[D]- Streamers use small tress instead of trees, a la KAngband and
+ variants that borrowed it's code. And they should look more like
+ streamers in most dungeons -- pelpel
+[D]- Neither player or monsters can see through, breath, or cast spells
+ over small trees, that are outer wall in Mirkwood -- arena levels
+ were too nasty otherwise... -- pelpel
+
+02/2/2002
+[m]- los, player's field of view, and spell/breath projection now all use
+ FF1_NO_VISION for the sake of consistency (in addition to the wall
+ check in case of spell/breath projection) -- pelpel
+[M]- Added a command to dismiss companions in the pet menu
+
+03/2/2002
+[D]- Moved wiz_dark() implementing the maze level from move_player() to
+ process_player(), so that a spellcaster can no longer do magic mapping--
+ detect monsters--detect traps then casting teleport as often as s/he
+ wishes to make things incredibly easy. Because of my laziness detected
+ traps aren't displayed if they are out of sight. This would require
+ tremendous hack. Anyway, don't worry, they are still remembered -- pelpel
+[I]- Auto-squelch menu now accepts ^R as an alternative to ^S, to be nice
+ for those who USE_GCU. Thanks Skylar Thompson for the problem report
+ -- pelpel
+[m]- CAVE_TRDT wasn't cleared when a trap is disarmed, which had some
+ subtle effects and forced coders to double check c_ptr->info and
+ c_ptr->t_idx in various places -- pelpel
+
+06/02/2002
+[B]- Do not drop from wild if player were not in wild mode in previous turn;
+ it put player in wrong place and could crash the game. -- Kusunose
+[B]- Summoning monsters from totems could crash the game. -- Kusunose
+[B]- The Heavy Crossbow of the Elves was 'the ultimate armor' in the
+ fully identified description. -- Kusunose
+
+07/02/2002
+[m]- Added FF1_DOOR flag to open doors for lightning effects in map_info()
+ and have the trap creation code explicitly avoid them, because traps
+ have and should never been performance bottlenecks -- pelpel
+
+08/02/2002
+[m]- Some process_world() sections (most notably monster generation and
+ lingering spell effects) are conditionalised so that they don't run
+ in the overhead map -- pelpel
+[D]- Added a dungeon flag that prevents generation of streamers, and
+ gave it to those with water/lava rivers and places like Numenor
+ and the Sacred Land of Mountains. Maze and evolving levels don't
+ require this. Also made lava deeper (dlev 34 or below). Trees can
+ appear on any flat levels. And eliminated undesirable calls to
+ the RNG in the streamer code -- pelpel
+[m]- Changed all the signed (!) flags I was able to find to unsigned, because
+ they don't make any sense. Savefile code should be modified as well
+ if we ever care for savefile portability -- pelpel
+[m]- The tunnel code (ordinary one) now performs double check for
+ feat_wall_outer and CAVE_ROOM (which was added a couple of weeks ago),
+ so it is safe to use any terrain features for outer wall, including
+ those identical to fill_type -- pelpel
+
+09/02/2002
+[D]- Rewrote place_new_way() so that it doesn't create unconnected dungeon
+ sections, destroy outer walls of rooms, or dig room corners -- pelpel
+[I]- Hopefully finished special lighting effects. Now it works this way
+ (with all lighting effects options on):
+ Perma-lit grids and lit walls/doors within sight, and remembered important
+ features = f_info colours, Perma-lit floors and walls/doors out of
+ sight = darker colours, torch-lit "boring" floor = yellow, torch-lit
+ grids out-of-sight = dark grey, blindness = B&W -- pelpel
+[D]- Angband dungeon now adjusts monster levels to the dungeon level.
+ The monsters here will have a minimun level in the range of:
+ level / 2 to level. So at level 67 the lowest monster you can encounter
+ will be level 33. This means that if a white icky thing is generated
+ it will be a level 33 white icky thing. If the base monster level is higher
+ then nothing is adjusted.
+
+11/02/2002
+[m]- (Temporary note) Separated staying effect handling code from
+ process_world() and made it a function, so that it can be called in
+ any place with in dungeon() [can be activated by #define pelpel :)]
+ I temporarily placed it after process_player(), but we have to spend
+ some time testing this, seeking for the best turn structure -- pelpel
+[m]- Auto-squelch is performed *before* a player turn, just before the
+ pack overflow code to prevent some interface problems. This means
+ that squelching occurs as the very last action of a player turn,
+ after monster drops or even after pseudo-ID, so that you don't have to
+ press extra space to squelch items. Another possible arrangement
+ would be within process_world(), right after sensing -- pelpel
+
+12/02/2002
+[B]- Fixed a bug in the hook code that may or may not be the cause of
+ various quest-related bugs -- pelpel
+[D]- Altars now have CAN_RUN flag, so that you no longer see the
+ message "You cannot run in that direction" when trying to run
+ across them -- pelpel
+[m]- Added flush() before all the quest questions to prevent accidental
+ loss/declination/acceptance of quest rewards/quests, also added
+ very important flush_failure and flush() to the lua interface and
+ put that in the spell failure code, so that spells can be macroed
+ safely -- pelpel
+[B]- Fixed a bug in the 6 monster randquest thanks to Louis-Frederic Michaud
+
+13/02/2002
+[O]- Elvish waybread renamed to lembas, thanks to nimloth
+[I]- Because I find detection no longer works on panels, added DTrap status
+ line as well as a new disturbance option disturb_detect. Also removed
+ hardcoded row/column positions in the status line code, in preparation
+ for big-screen support -- pelpel
+
+16/02/2002
+[I]- Added scrolling target/look code, which is bastardised :) form of
+ Z and V ones -- pelpel
+[m]- Depth/field name area is now 13 character long, so that names like
+ "shallow water" will fit, and "Lothlorien" is not truncated in GCU.
+ Also added short dungeon name prefix to the depth-in-feet mode -- pelpel
+[m]- Because map_info() is the #1 bottleneck routine and because I felt
+ hack_map_info_default is incredibly ugly :(, I removed
+ hack_map_info_default and added specialised version of map_info()
+ for use by cmovie and the HTML screen shot saver -- pelpel
+[B]- Fixed the "automatic ego filter" bug in the squeltch filter -- pelpel
+[I]- Big screen is sort of working now, but main-xxx.c (have
+ to remove restrinction on size of the PernAngband window) and
+ cmovie are still needing upgrade -- pelpel
+
+17/02/2002
+[B]- Made panel_bound() more paranoid about the current dungeon size,
+ to prevent many big screen-related crashes -- pelpel
+
+18/02/2002
+[m]- Added 8x8 graphics support to trap display code -- pelpel
+[m]- Added another graphics mode variable called graphics_mode :),
+ somewhat like use_graphics in ZAngband, but it doesn't
+ require any changes to main-xxx.c. It's set within reset_visuals()
+ and used by map_info(), so that it doesn't have to do streq()
+ each time it is called -- pelpel
+
+19/02/2002
+[m]- Added term resize hooks so that one doesn't have to hit the redraw
+ key and alike when s/he resizes windows. Hooked functions are placed
+ in xtra2.c, because they are only related to big screen support
+ and other panel related codes are there. Don't like the way stuffs
+ are initialised -- assumption about max number of terms, setting terms
+ package hooks from within the upper layer codes -- but the existing
+ implementations do it this way, and the "right" way requires changes
+ to main-xxx.c, which I'm too lazy to do... -- pelpel
+[I]- Big screen support for X11 and XAW ports (already done for Gtk, Mac
+ and Windows ports). Also added an option -o to force the use of 8x8
+ tiles in graphics mode. Say "-g -- -o" to activate it. And please note
+ that because of the way transparency effect is implemented in
+ X11/XAW/Gtk ports, it is available even with 8x8 tiles -- pelpel
+
+20/02/2002
+[B]- Beastmaster Shanty overpayed a bounty if monster's corpses are stacked.
+ -- Kusunose
+[O]- Combining rod and rod tip now considers rod's cheapness flag.
+ -- Kusunose
+
+22/02/2002
+[M]- Restored monster light code, modeled after Steven Fuerst's implementation
+ insteand of APW one this time, but without his support for multiple radii.
+ -- pelpel
+[M]- Made monster light a run-time option. CAVEAT: It'll cause display
+ weirdness when you turn this option from ON to OFF while playing.
+ Save/Restart or entering new level will fix the problem.
+ Should call forget_mon_lite() when the game detects it... -- pelpel
+[M]- monster lite option is on by default
+
+23/02/2002
+[B]- A failure in disarming traps using easy-disarm caused another attempt
+ at disarming traps (because it calls move_player_aux which calls
+ do_cmd_disarm_aux which calls move_player_aux...), growing call
+ stack infinitely. It's dangerous, and, in fact, players were totally
+ safe from traps (messages said "You set off...", but traps were never
+ activated) -- pelpel
+[B]- Black breath could crash the game (it's really evil, isn't it :)
+ Thanks Kevin W. Thomas for the patch -- pelpel
+[m]- Ego graphics code now only tries to use graphics overlays for
+ monsters and players if and only if 16x16 tiles are used -- pelpel
+[B]- map_info() had problem with walls mimicking floors -- pelpel
+[m]- Shimmering terrain features no longer shimmer while running or resting
+ to make themselves somewhat more bearable on slower machines -- pelpel
+
+24/02/2002
+[m]- Updated lighting effect code so that it works the same as rr9's Angband
+ versions. Also removed hardcoded IBM pseudo graphics code points, so that
+ if anyone is ever interested in updating its font & prf files, s/he
+ can do so freely without editing the source code.
+ And map_info / map_info_default is now fully aware of c_ptr->mimic,
+ so that map edges will not have strange lighting effects etc.,
+ hopefully -- pelpel
+
+26/02/2002
+[B]- Polymorphing random effect of Chaos Warriors could crash the game.
+ Special thanks for Kevin W. Thomas for the detailed analysis
+ of the problem -- pelpel
+[I]- Moving onto quest entrance/exit no longer causes annoying automatic
+ stair movements. You have to tell the game '>' or '<' to enter/leave
+ -- pelpel
+[m]- Renamed see_wall() in cmd1.c to see_obstacle() also added a grid-based
+ version of the function to be used by run_test(), so that those who have
+ immunity and/or levitation can run over lava fields, deep water etc.
+ -- pelpel
+[O]- There are 2 kinds of spellbooks for the magic schools, the ones that
+ are named "a Spellbook of foo" where foo is a randomly choosen spell
+ (selection is based on the dungeon level)
+ and other names that are fixed books
+
+27/02/2002
+[O]- School spellbooks can be fireproof ego items
+[B]- Dungeon town generation could crash the game. Thanks Mogami
+ for the analysis of the problem -- pelpel
+
+01/03/2002
+[B]- Supplied missing suid code in 1) savefile removal action in the startup
+ screen, 2) dungeon savefile removal, and 3) bone file removal.
+ Thanks kobayasi for the patch -- pelpel
+[m]- Less platform-dependent savefile processing code for the game start
+ menu, thanks again for kobayasi. It now uses files.c utility routines
+ for building appropriate savefile names -- pelpel
+
+03/03/2002
+[B]- Special level names wherent corrently displayed if the N: line was the
+ first of the file in lib/dngn
+
+03/03/2002
+[m]- Added initialization code to add SPECIAL_GENE flag to final guardians
+ and their artifacts (and DROP_RANDART if there are no final artifacts).
+ -- Kusunose
+[D]- Put yet another fractal code (unlike the others it's quite simple)
+ in the level filler generator, and added a F: parameter in d_info.txt
+ to control its behaviour. Its syntax is FILL_METHOD_#, where # is
+ 0: use the first filler w/o calling RNG (for Angband, Mirkwood etc.),
+ 1: the same as the previous versions (default), 2: slightly smoothed,
+ 3: more smoothed, or 4: max smoothing (initial step of 8 grids) -- pelpel
+
+04/03/2002
+[B]- '/' in item selection didn't update screen correctly -- pelpel
+[m]- Moved squelch-on-sense code from process_player() to process_world()
+ -- pelpel
+
+04/03/2002
+[P]- High intelligence increase mana regeneration rate
+
+06/03/2002
+[B]- Level generation could cause infinite loop in the Sacred Land of
+ Mountains -- pelpel
+[m]- Changed repeated message code to V-CVS one -- pelpel
+[B]- Player ghosts were disabled in a way causing special feeling on
+ every level -- pelpel
+
+07/03/2002
+[m]- Trap display now uses x_attr/x_char of FEAT_TRAP (f_info N:17)
+ 1) if a trap is set on a "boring" terrain in the ASCII mode, where
+ only x_char is used and attr is taken from tr_info.txt XXX XXX XXX
+ or 2) if attr/char for a trap is not defined in prf files in the
+ graphics modes -- pelpel
+[m]- Removed FAKE_VER_*, because it has been quite long since we lost savefile
+ compatibility with Angband 2.8.1 and info.txt files can be updated
+ by sed/perl/whatever script in a snap -- pelpel
+[B]- Took 64-bit safe RNG from Vanilla -- pelpel
+
+08/03/2002
+[m]- To accommodate the practice of not upgrading version stamp of info.txt
+ files at each release (never done in V-based variants, but common among
+ Z-based ones for historical reasons), version stamp checks against game
+ data files in lib/edit is made a compile time option
+ (VERIFY_VERSION_STAMP), off by default. With this option off, version
+ stamp checks for the binary files are still performed and they always
+ have version signature of the game, not those specified by the V: lines
+ -- pelpel
+[B]- Wide light radius worked in the small scale wilderness map,
+ where it should have been WILDERNESS_SEE_RADIUS -- pelpel
+
+10/03/2002
+[m]- Upgraded the lua bitlib so it can handle stuff like bor(1, 2, 4, 8)
+
+11/03/2002
+[M]- Confusion, stunning, charming now works on uniques(those that dont have the
+ corresponding resistance)
+
+24/03/2002
+[I]- Stats can now be displayed in a linear mode(from 3 to 37) instead of
+ 3 to 18/***, the option is off by default
+
+25/03/2002
+[D]- No more shafts in the halls of mandos
+[m]- Block comments( --[[...]] ) in Lua enabled
+
+27/03/2002
+[D]- Tweaked the door code a bit so that some doors are much harder
+ to find -- pelpel
+[I]- Added recall depth subcommand to the knowledge menu -- pelpel
+
+03/04/2002
+[I]- Removed the flavoured_attack option and made most 'silly' messages
+ off by default. They are now controlled by 'insanity roll', which is
+ d100 roll against (max_sanity - current_sanity) * 100 / max_sanity.
+ The same roll is also used to determine if the game should use
+ silly monster descriptions (in addition to the hallucination
+ effects) -- pelpel
+
+04/04/2002
+[I]- The skill interface no longer asks question whenever you increase skills.
+ Changes to skill values are made permanent if the player confirms them
+ when s/he leave the skill menu, otherwise, they are simply ignored
+ -- pelpel
+[P]- The skill system is ready ! Some small tweakings are needed, but it is
+ mostly ready. Each level you gain a few skill points that you can spend
+ on various skills(like combat, weaponmastery, magic, ...). Most actions
+ are now tied to skills.
+[P]- Classes revamped as more or less skill templates. Classes now can have
+ specializations which allow starting with somewhat different skill set.
+[B]- Since streamers can create unconnected dungeon sections, the code for
+ it is moved after stair and player allocation -- pelpel
+[m]- Reorganised the linkage order of makefile.org a bit, so that similar
+ files are grouped together, also frequently called files are not coupled
+ together with rarely used ones. This *might* help on-demand-paging memory
+ manager a bit -- pelpel
+[m]- Changed all occurances of " ?" in strings to "? ". --takkaria
+
+08/04/2002
+[B]- Some player_type fields and corresponding lua interface definitions
+ were of different types. Fix thanks to rr9. -- pelpel
+
+09/04/2002
+[I]- Bigtile patch for windows, x11 and mac ports thanks to Takeshi Mogami
+
+11/04/2002
+[B]- Gave SPECIAL_GENE flags to the k_info.txt entries of SPECIAL_GENE
+ special artefacts -- pelpel
+
+15/04/2002
+[M]- Revision of the conf/stun/sleep resists for uniques thanks to Runescrye
+
+18/04/2002
+[G]- The adventurer quest reward is now either the adventurer or some skills
+[I]- Asks for a last screenshot upon death
+
+20/04/2002
+[I]- You can now dump a frame of a cmovie as an html screenshot(while playing
+ the movie)
+[P]- New god system, each god will be much more different from all others.
+ Altars are less vital. There are less gods.
+[m]- Renamed inappropriately called global array 'town' to 'town_info', also
+ moved some boolean town_type members into 'flags', in order to support
+ dungeon town information subcommand of do_cmd_knowledge -- pelpel
+[m]- Commented out or moved many local variables causing 'unused' warnings,
+ because of badly placed if 0's -- pelpel
+[B]- Player is now guaranteed to have initialive after entering a level.
+ Thanks Joseph William Dixon for the patch -- pelpel
+[I]- The commands for skills and spells are swapped. Please use 'G' to learn/
+ check skills and '$' ('\$' in roguelike) to learn spells.
+
+22/04/2002
+[m]- Renamed 422colors.prf to 422color.prf, to make it fit with the 8.3 naming
+ convention -- pelpel
+
+23/04/2002
+[O]- Bound the wands & staves damage/power to the Magic skill, attack wands
+ should actually be usefull now
+
+25/04/2002
+[P]- Magic skill now allows you to copy spells from books into various
+ objects. Not all objects can contain spells naturally, but most object
+ of the Magi can, and all mage staves
+[P]- Spectres loses HP while in walls, it was too abusable(and in fact, I never
+ planned to remove it)
+
+28/04/2002
+[D]- The inn in Bree is now The Prancing Pony. -- Kusunose
+
+01/05/2002
+[D]- Small levels cannot generate full levels anymore
+[I]- The prompt to cast a spell now understand to press @, which will ask for
+ a spell name, it'll look all books and cast it if you can.
+ It EASES macros, a macro will now look like:
+ 02m@Manathrust\r*t
+[I]- Message recall now understands bigscreen thanks to pav
+[I]- Help now understands bigscreen thanks to pav
+[I]- Skill screen now understands bigscreen thanks to pav
+[I]- No more pickup prompt with autopickup when inventory is full, thanks to pav
+
+03/05/2002
+[B]- The skill increase/decrease code was unable to detect underflow -- pelpel
+
+06/05/2002
+[P]- Made running commands exempt from do_nothing processing, because this
+ can be abusable and makes no sense -- you could, for example, hold down
+ movment keys when following Eru and use running when following other
+ deities -- pelpel
+[I]- Took big screen code for horizontal scrolling of message recalls
+ from Vanilla -- pelpel
+[I]- You can navigate through option menus with roguelike_keys -- in fact,
+ I didn't know users of the original keyset can go up before I play
+ the latest V and see its code... Taken from Vanilla CVS -- pelpel
+[m]- Entirely removed function definining macros from script.c, because
+ it can confuse some compilers (a lcc case was reported), and some
+ preprocessor reports syntax error for missing macro arguments -- pelpel
+[I]- Added big screen support for GCU -- pelpel
+
+12/05/2002
+[m]- Some, if not all, command line options are documented -- pelpel
+[B]- Full map command displayed only half of current dungeon level when
+ bigtile mode is used. Thanks for Takeshi Mogami for tha patch
+ -- Kusunose
+
+19/05/2002
+[m]- 1) Slightly reorganised menus in the Mac ports, because there were so
+ many of them on the menu bar. 2) added a switch (-b) to the GCU port
+ to select multiple terms or one big screen. 3) the GTK port issued
+ huge number of fatal warnings if the graphics mode was turned on and off.
+ 4) Compiled latest V CVS with main-gtk.c in T.o.M.E. and fixed some
+ portability problems. -- pelpel
+[P]- Pseudo-id is now bound to the Combat skill(for weapons/armors) and the
+ Magic skill(potions, ...)
+[P]- It is now possible to press @ at the 'm' key prompt to select a skill action
+ by it's full name. Thus allowing unbreakable macro:
+ m@Cast a spell\r@Manathrust\r*t
+[I]- The skill screen cannot be abused to get more skills anymore
+
+27/05/2002
+[P]- New god Melkor Bauglir
+[P]- Weaponmastery, Archery and Barehand skills increase Combat skill much more
+
+02/06/2002
+[B]- Various spell effects that polymorph monsters could crash the game.
+ -- Kusunose
+[B]- Compare weapons command miscalculated muliplying bonus. -- Kusunose
+
+12/06/2002
+[P]- Deathmold fetch ability pickups gold and objects(if autopickup is set) thanks
+ to "kenderband" <kenderband@hotmail.com>
+[m]- Exported cur_hgt and cur_wid to lua by request of Fearof4s. (takkaria)
+
+14/02/2002
+[m]- Updated the lua help files thanks to Fearof4s and Chris Hadgis
+
+17/06/2002
+[B]- Fixed junk artifacts and music instruments stacking bug in stores
+ -- Kusunose
+
+03/07/2002
+[M]- Monsters drop stolen gold when killed
+
+04/07/2002
+[B]- Capped max number of extra blows at 2 when the limit_blow flag is set
+ in two places -- pelpel
+
+09/07/2002
+[B]- Cancelling a scroll of reset recall didn't work. -- Kusunose
+[O]- Reset recall now lists all the dungeons a player has visited and
+ additionally allow a player to select by name. -- Kusunose
+
+13/07/2002
+[O]- Enabled the generation of double ego items. An item cannot get 2 prefix
+ or 2 suffix, it will always be a prefix and a suffix
+
+14/07/2002
+[P]- New bounty quest available at the beastmaster shanty! Bring back a corpse
+ and get some monster-lore skill and the ability to learn corpse-preservation
+ skill if you couldn't already
+
+15/07/2002
+[P]- Replaced first necromancy spell with Horrify from the old Nether realm and
+ the third spell with absorb soul, provides some health upon monster death
+
+16/07/2002
+[m]- Updated lua_ques.txt to fix some misinformation. -- fearoffours
+
+17/07/2002
+[B]- One was able to have another entry in the score file for a dead/retired
+ character by loading him/her with the -w option, then answering 'n' to
+ the wizard mode confirmation. Bug report and fix (for Angband 3.0.1, but
+ applicable for all variants) by Hallvard B. Furuseth, Takeshi Mogami and
+ Robert Ruehlmann -- pelpel
+
+22/07/2002
+[m]- More lua documentation fixes, particularly adding square brackets to field
+ names on lines that would allow this without mucking up colour formatting.
+ -- fearoffours
+
+23/07/2002 - T.o.M.E 2.0.0 aka "Point of No Return"
+
+24/07/2002
+[m]- The splash screen now shows "Tales of Middle Earth" or "Troubles of Middle
+ Earth" randomly. Thanks to Scott Holder for the idea and some code.
+ (takkaria)
+[m]- makefile.org now defaultds to ./lib for the lib directory
+[m]- makefile.org is now makefile.std
+[B]- Fixed a silly bug preventing Polearm masstery from wroking
+
+26/07/2002
+[B]- In multiuser installations, notes and cmovie were written under the lib
+ directory using the game's permission, making them inaccessible by
+ the player. I moved them to ~/.tome. Note: This means that a coder
+ shouldn't grab permission before opening files in these directories
+ -- pelpel
+[B]- There are still inappropriate (and even unbalanced!!!) calls to
+ safe_setuid_grab() and safe_setuid_drop() in the game. Thanks Neil
+ for pointing out those in the macro save commands. There are so many
+ places that I have to look at, but I'm trying... -- pelpel
+[I]- Better (hopefully) object identification screen
+
+28/07/2002
+[m]- Added safe_setuid_grab/safe_setuid_drop to all the functions that
+ access files in the lib directory. I did so even for the game
+ initialisation, knowing that it's very unorthodox. This is because
+ I found some of them in the init[12].c. There's no other sure ways
+ to keep them from messing multiuser installations. -- pelpel
+[m]- Added makefile.dos, which is a copy of makefile (now), in order to
+ prevent overwriting accidents. Ideally, 'makefile' should be in the
+ .cvsignore, so that every developper can feel at ease with his/her
+ own preferred environment -- pelpel
+
+01/08/2002
+[P]- New corruption system, savefiles are compatibles but you will loose
+ all your corruptions.
+ Most corruptions now have a good and a bad effect. Some corruptions
+ depends of others, it means that you can only get them when you have
+ the ones they depend of(i.e: Balrog Form need Balrog Wings, Balrog
+ Aura and balrog Strength to work). Some corruptions can be mutualy
+ exclusive. The list of corruption is totaly rewrote. They are more
+ in-theme now.
+[B]- Perma curse cannot happen on randarts anymore
+
+02/08/2002
+[B]- Player could not pick up items from home if he did not have enough
+ gold. -- Kusunose
+[B]- Traps of wasting wand dont mess up wands
+[B]- Dragon helms get resistances
+
+03/08/2002
+[B]- No races were allowed to be loremasters
+[B]- Fixed a bug in Character classes allowed, tahnks to Alex Wilkins
+[m]- Added Melkor to the gods docs.
+[B]- Spells cannot be cast while blinded or confused(execpt for a few)
+[G]- Wielding the One Ring has some ... disadvantages now ...
+[B]- Poor Melkor didnt had his altar generated in dungeons, while he is the
+ only god for a use of an altar
+
+05/08/2002
+[m]- Improved the adventurer guide and added a section for macros to it
+[P]- All Udun spells are no more multi-school spells
+[P]- Reorganized the skill tree to remove the Misc skill tree. Alchemy is now
+ under Magic, Antimagic is in Combat and Music in Spirituality
+
+07/08/2002
+[B]- Fixed the -1 activation power of some mage staves of spell
+[G]- Troll Glade/Wight Grave selection is now (usualy) based on the
+ Combat/Magic skills level
+
+08/08/2002
+[I]- The game asks confirmation before learning a skill that can exclude an
+ already known one
+[I]- When 'I'nspecting(or upon *id*) a fully *id* weapon/ammo the game will
+ tell you the damage it would do if you used it(idea from Ey)
+
+10/08/2002
+[I]- 'U' power menu is now usable with repeat key 'n'
+
+11/08/2002
+[G]- The chance for combat item pseudo-ID now improves exponentially,
+ just like V Warriors (combat skill 0 == plev 0, maxed == plev 50),
+ while that for magic items improves slowly, just like V Rangers
+ and Mages but with higher success rate (more than ten times as
+ frequent as V Rangers) -- pelpel
+
+12/08/2002
+[B]- Added missing spell frequency to Fire golem. -- Kusunose
+[B]- Symbiant cannot pickup a hypnotized pet from a pile. Thanks to kobayasi
+ for the patch. -- Kusunose
+[P]- Give Ents scrolls of satisfy hunger instead of some food. -- Kusunose
+[B]- Stats more than 18/220 were displayed incorrectly if linear_stats was ON.
+ -- Kusunose
+
+13/08/2002
+[m]- Made chg_to_txt in files.c conditional, so that it won't be included in
+ Windows, Mac and RISCOS ports (they don't call the function, so it has
+ been dead code) -- pelpel
+[D]- Since Tome generated small levels once in three times when requested,
+ which I think is too often, and in Z and Ey the chance is 1/5 and 1/10
+ respectively, I lowered the chance to 1/6 -- pelpel
+[B]- The small_level option had the same effect as always_small_levels
+ -- pelpel
+[O]- Removed CURSE_NO_DROP from ego items. Players want new curses, and when
+ they get them they complain...
+
+14/08/2002
+[I]- Added avoid_shimmer efficiency option to suppress shimmering of terrain
+ features, because I have had problems with them on really big screens
+ -- pelpel
+[P]- Increased the modifier of the masteries for warriors
+[P]- New Warrior subclass, the Demonologist, spell enhanced warriors. They
+ use the new Demon school and the renewed Demonblades, Demonshields and
+ Demonhorns. Their spells enhance their fighting potential. They can either
+ be seen as a force of good, fighting against demons with their own powers
+ or as a force of evil fighting to bring corruption to the world.
+[P]- Sorcerors begin with a robe instead of a dagger
+[I]- Easy close is now slightly more intelligent in their handling of
+ broken doors -- pelpel
+
+15/08/2002
+[O]- Ring/Amulet of Spell, cheap, early objects that can contain a spell
+[B]- Exploding ammo dont stack with normal ammo
+
+16/08/2002
+[B]- Ammo creation is bound to Arechery skill instead of player level
+[B]- Fixed a bug in related skills, when one increased a skills sometimes the
+ related skills didnt increased
+
+17/08/2002
+[m]- Do not grab/drop permissions twice. Thanks to kobayasi for the patch.
+ -- Kusunose
+
+18/08/2002
+[B]- Temporal stat drain no longer cancels normal stat drain. -- Kusunose
+
+19/08/2002
+[O]- Temple will now stock random spells from god schools, Magic Shop will
+ only stock non god spells and bookstore will contain both
+[O]- Stores buyable list is now lua defined
+[B]- The amount of mana in each grid was always magical level. -- Kusunose
+[P]- Changed the formula to calc the player HP when using possession so that
+ a higher possession skill will be prefered
+
+20/08/2002
+[B]- Extracted essences overwrote a weapon slot when inventry was full.
+ -- Kusunose
+
+21/08/2002
+[I]- Ingame contextual help is on by default(it was before, but it was bugged..)
+ It is now proccessed by lua, file help.lua and should be much easier to
+ add new sections to than before. So all feel free :)
+[G]- Added town of Khazad-Dum (where 'exit' from Moria was) with nice Mining
+ supply shop. -- fearoffours
+
+23/08/2002
+[I]- Contextual help for the birth screens too. Press ? when over a race,
+ class, ... and it'll bring the specific help for it
+[M]- Monster ego wont start awake
+[P]- lost Souls now have see invisible, I know I'm far too nice :)
+[I]- Contexual help to skill screen, press ?
+[I]- Easy macro recorder! Just press $ and press a normal key sequence!
+
+26/08/2002
+[m]- Removed the autosquelch to replace it with a new Automatizer that should
+ be much more powerful. It lacks a gui, but that should soon change :)
+
+28/08/2002
+[I]- The new Automatizer got a GUI :) It should be quite easy to grasp, you
+ define rules to match and action to take. But it does allow very complex
+ rules.
+
+27/08/2002
+[m]- Added updated class help documents. Removed extraneous ones. Amended
+ links in birth.txt to reflect changes. Added appropriate entries to
+ help.lua for contextual class help at birth. Thanks to Mef. -- fearoffours
+[m]- More contextual help: races and god selection at birth, rod tips, rods and
+ trapping kits. -- feaoffours
+
+29/08/2002
+[G]- Added new god quest. Given at random time by your god, you have to retrieve
+ a piece of a relic generated at a random level of a randomly places dungeon.
+ More than one of these quests may be given (currently up to 4), though only
+ if you complete previous quests. The relic is only generated once in each
+ dungeon, so look carefully for it. Diving won't help you. -- fearoffours
+
+31/08/2002
+[P]- New Water spell: Vapor, it create a low damage wide radius short lasting
+ cloud of water. It is designed to be a cheap attack spell for annoying
+ critters. Beware, random spellbooks & inscribed objects spells will "morph"
+ to other ones, sorry, unavoidable
+
+03/09/2002
+[B]- Fix mushrooms stacking for the maggot quest
+[m]- Fix birth.txt crash -- fearoffours
+
+04/09/2002
+[O]- Scythes of Slicing are now vorpal, rarer and deeper
+
+05/09/2002
+[G]- Added the fireproofing quest. Visit the Mage tower in lothlorien to get the
+ quest, bring back something for the mage, get books fireproofed in return.
+ -- fearoffours
+
+08/09/2002
+[I]- Updated the forgotten IBM pseudographics, based on my unknown work for
+ Pern 4.1.2. Also added an X11 BDF file so that it can be used on
+ the three X ports -- copy graf-ibm.prf to font-x11.prf in your user
+ directory (i.e. ~/.tome) and set the font of main window to the font
+ made from lib/xtra/ang16.bdf. Instruction for installing new X fonts
+ should be found in the bdftopcf, mkfontdir and xset man pages.
+ -- pelpel
+
+10/09/2002
+[I]- Current location(town, level, ...) is show in orange when about to recall
+
+17/09/2002
+[m]- Updated skill docs, thanks to lemming
+[m]- More minor help file updates. thanks mef and Chris Hadgis
+
+21/09/2002
+[P]- Mindcrafters gets esp even after level 40
+
+22/09/2002
+[I]- You can press $ at object destruction prompt to automaticaly create a new rule
+ for the Automatizer about the object being destroyed
+[B]- Casting "Disperse Magic" when spell level is 20 or more produced a lua
+ error. -- Kusunose
+[m]- Reformatted the makefile.WHICH file. Do we really need this file anymore?
+ other variants get by without it, I don't really think it's needed...
+ (takkaria)
+[m]- Reformatted the todo list, removed some entries which have been done.
+ Also added a section for stuff which I will do (one day). (takkaria)
+[m]- I've reformatted and reorganized a fair bit of notes.c; I've made stuff
+ less hacky and made the function which writes notes to file use
+ my_fputs()... Also replaced some hardcoded buffer sizes with sizeof().
+ (takkaria)
+[m]- Removed hardcoded buffer sizes in wizard1.c. (takkaria)
+
+23/09/2002
+[M]- Farmer maggot quest provides a better reward, thanks to Revanant Morituri
+ and Wil Hunt for the idea
+
+25/09/2002
+[B]- The centre player option failed to do so while running. Thanks Neil
+ Stevens for the patch. -- pelpel
+[B]- Random Artifact arrows should now stack properly. -- wilh
+[B]- Mindcrafters lost their ESP at level 40. Now they have it permanently
+ at that level. (p_info.txt) -- wilh
+[B]- Above bug was supposed to be skill level 40, not clvl 40. Fixed. :)
+
+28/09/2002
+[I]- Macro-patch from Mogami, now the macro prf files are portable between Windows,
+ X11 and Mac. It also shows readable triggers like: \[shift-F1] and such
+
+29/09/2002
+[m]- Added .cvsignore to the src directory to prevent makefile overwriting
+ accidents from happening. Currently it excludes makefile (developers
+ are expected to update platform-specific makefile if s/he indents to
+ make permanent changes to them), tome, tolua, TOME.EXE and TOLUA.EXE.
+ -- pelpel
+
+01/10/2002
+[G]- Alchemy totaly changed! Thanks to John Gilmore for the patch! It has now entered
+ cvs to begin being tested and "balanced" ;)
+
+05/10/2002
+[P]- Symbiotic power changed to be bookless
+
+06/10/2002
+[P]- Available skills to leanr via random quests are defined in s_info.txt
+[P]- Trying to mimic when already mimiced(with the skill) will turn you back to
+ normal form
+[O]- All objects now have a description, thanks to Konijn
+ When identifying an item you can then press 'I'nspect to check it. It si most
+ usefull for scrolls & such, they tell you what exactly they will do
+[B]- Fixed a bug that made mage staves very costy
+
+07/10/2002
+[I]- Replaced font-ibm.prf, graf-ibm.prf, font-win.prf and font-mac.new (a
+ font-mac.prf replacement that has IBM-like pseudographics definitions)
+ with program-generated ones, hopefully up-to-date with recent changes
+ in info.txt files -- pelpel
+
+11/10/2002
+[I]- Unusable skills do not show anymore on the skill screen
+
+17/10/2002
+[I]- New option to not have the equipment/inventory windows move items around
+ when a prompt ask for an item. Thanks to John Gilmore
+[B]- Fix a bug of wands in store
+[B]- Fix an old spelling error: "droped" not "dropped" -- Neil
+
+18/10/2002
+[O]- Behold! The new Grand Scheme For Wands, Staves and Rods!;)
+ Now all sticks in the game use the same system as the spells. The unified
+ spell system could we say ;)
+ What does it changes? sticks should now be usefull, jsut as spells are.
+ For example a wand of manathrust is not to be laughed at.
+ Hw does it work? 'I'nspect the stick you want to know about you'll see
+ he details, each stick gets a spell and a base level. The base level
+ means the spell will be cast at that level if you have 0 in the
+ Magic Device skill. If you have Magic Device it increases the level.
+ Works a bit like Spell-power for the spells.
+ Also the distinction of wands/staves is tenuous now, wands are attack
+ stuff and staves not but wands can sometimes NOT be targeted spells
+
+20/10/2002
+[P]- Yavanna Kementari as a new Vala, protectress of nature. Along with her
+ priests, the Druids
+
+21/10/2002
+[m]- Updated symbiant helpfiles including full list of their new bookless spells
+ in m_symbio.txt -- fearoffours
+
+23/10/2002
+[I]- Recording cmovies is now working on a microsecond timeframe, much better looking
+ Let's just hope that silly systems know gettimeofday()
+
+26/10/2002
+[m]- Introduced a performance measure for process_world_hook, which I suspect
+ is causing slow movement problems in the reduced map mode. Please read
+ the comment in process_world() [in dungeon.c] for alternative solutions.
+ -- pelpel
+
+27/10/2002
+[m]- Changed every instance of "essense" to the correctly-spelled "essence".
+ Update your macros. -- neil
+[M]- Changed "The Balrog of Moria" to "Durin's Bane". Less of a mouthful, and more
+ in-theme -- fearoffours
+[M]- added the "spirits". They are the inhabitants of the void. They're nasty.
+ -- fearoffours
+
+28/10/2002
+[P]- Typo in Druid description: Kemenari -> Kementari. --fearoffours
+[B]- Fixed bug where ironman_rooms would give you the number of random quests
+ you played last time, instead of zero. -- neil
+
+29/10/2002
+[D]- Added SPIRIT flag to The Void, so that Spirits are actually generated there now
+ -- fearoffours
+
+02/11/2002
+[P]- Subraces can now have skill mods
+[P]- Spells bound to two or more schools now require at least one point in
+ each of the schools to be used
+[m]- Trimmed down the size of chardumps(removed uselessness from object
+ descriptions)
+
+05/11/2002
+[I]- Obvious object flags will show up when 'I'nspecting items when they are
+ only identified(no more need for *id*). Obvious flags are like acid
+ resisatnce on an armor of resist acid and such
+
+06/11/2002
+[P]- New skill, Stunning-blows, a haftedmastery subskill, just like critical
+ hits is a subskill of swordmasery. It requires a hafted weapon > 5 lb
+[O]- Activations are now a_info/k_info/e_info definable with a: lines
+ You can do a:HARDCORE=NAME where NAME is an activation name
+ that is hardcoded in the C source.
+ Or a:SPELL=Name where Name is a "spell" name as defined in the unified
+ spell system(the first defined spell(index 0) cannot be used this way
+
+07/11/2002
+[B]- Allow non-artifact, non-ego items with activations be activated. -- neil
+[I]- Cause of death is now shown in chardumps
+
+08/11/2002
+[m]- Added descriptions to Totems, removed redundant need to identify them.
+ -- neil
+[G]- Yavanna's followers now have a God quest. -- fearoffours
+[m]- Help docs for Yavanna and Druids, thanks Mef and Massimiliano Marangio.
+ -- fearoffours
+
+09/11/2002
+[M]- Only gain exp from pet kills, not from every monsters, when using Monster
+ Lore skill
+
+10/11/2002
+[m]- Yes, more help updates. In tome_faq.txt and TANG.txt I added links to
+ skills.txt, magic.txt, birth.txt and gods.txt where appropriate. Removed
+ two references to Pern that got missed in tome_faq.txt.Added a
+ c_priest.txt file for contextual help at birth when choosing a main class.
+ Corrected typo in r_info (SPirit became Spirit). -- fearoffours
+
+11/11/2002
+[I]- CTRL+] to save an html screenshot anytime(ie: to preserve the current
+ message)
+[P]- Necromancers start with corpse preservation skill
+
+13/11/2002
+[B]- Don't let the Maggot sling be generated randomly. -- neil
+
+15/11/2002
+[m]- Added a new TERM_XTRA call, TERM_XTRA_GET_DELAY which should return the
+ time in microseconds. What time exactly isnt meaningfull but it must be
+ usable to compute the length of time an action takes.
+[I]- Thanks to the new TERM_XTRA_GET_DELAY the cmovie code is now cleaner
+ and should work fine:) Windows and unix platforms should now be able
+ of microsecond resolution cmovies!
+[m]- Made all the socket code into z-sock.[ch] and wrapped it into a
+ virtualizing layer so that the rest of the code can use it independantly
+ of the implementation. Currently unix and windows sockets are supported.
+
+16/11/2002
+[B]- Prevent the automatizer from treating "good" bows as "average" -- neil
+[B]- Prevent earthquake damage for characters with wraithform, and prevent
+ some of the damage for characters with semi-wraithform -- neil
+[B]- Fix spelling of Book of Teleportation -- neil
+
+17/11/2002
+[P]- New Meta/Conveyance Spell: Tracker, it will track the last teleportation
+ that happened on the level and teleport you to its destination
+
+18/11/2002
+[G]- The Old Mage in Lothlorien will now fireproof staves or scrolls as well as
+ books, making it profitable for non-spellcasters. Currently he has enough
+ errr 'fireproofing material' for 3 books or 4 staves or 12 scrolls, or a
+ combination of these. Check fireprof.lua for the code. -- fearoffours
+[I]- Skills that have sub-skills in which you do not (and cannot) have points
+ no longer display the redundant +/- sign. thanks lemming for the code.
+ -- fearoffours
+[m]- Lots and lots of itsy-witsy help file updates. Stunning-blows, other
+ references to Pern, more links to other files... -- fearoffours
+
+19/11/2002
+[m]- Compress the grid in the character dump, eliminating blank lines and only
+ showing lines without '+'s for the resistances and sustains page -- neil
+[m]- Show the Mathom-house contents in the character dump -- neil
+
+21/11/2002
+[O]- When 'I'nspecting objects you'll know how you found them
+[B]- Magelock cannot override permanent walls(or walls for taht matter) and works
+ only in LOS
+
+22/11/2002
+[O]- 3 new artifacts of Gothmog, regrouped in an item set
+[m]- Cleaned up the notes code a little. (takkaria)
+[P]- Summon skill doesnt caerte drops for partial summons
+[P]- Summon skill doesnt work in an antimagic field
+
+23/11/2002
+[B]- Automatizer should not treat enchanted ammo and tools as average, either.
+ -- neil
+[B]- Fixed the bug that allowed to use unallowed gods
+[P]- Lost souls start with many satisfy hunger scrolls, I'm really too nice...
+[M]- Themed townspeople! In Lothlorien and GOndolin you find elven people and
+ dwarven in Khazad-dum
+
+24/11/2002
+[m]- Display in the dump how interesting items were found -- neil
+[B]- Two-handed artifact weapons now act as such -- neil
+[O]- Darksword antimagic field now scales on the antimagic skill
+ So using one with 0 in the skill is not worth much
+[m]- DESTDIR support in makefile.std -- neil
+
+25/11/2002
+[B]- Don't mark items as store bought until they are bought -- neil
+[O]- Distinguish stolen items from bought items -- neil
+[m]- main-net.c display module which redirects display over the z-sock layer
+ and thus over any ip network to allow to create very lightweight terminals
+ to play ToME everywhere. This is still experimental
+[B]- Don't show Gondolin twice in the dump -- neil
+[O]- Cut down the price of Spectral weapon given their .. usefullness
+[I]- Fixed the bug that told you you could buy more items than you really could.
+ At least when using auto_haggle. Poor sods that dont use it shall burn
+ in hell
+[I]- Damage info is displayed for items that are only identified
+
+26/11/2002
+[G]- OK the god quest is a little easier now, as you're told the dungeon is to
+ the north/south and east/west of you. -- fearoffours
+[G]- Having autosquelch on will now not affect the essence in the fireproof
+ quest. And the mage gives a warning about the fact it may be easy to
+ destroy it too. -- fearoffours
+[B]- Fixed the incredible townspeople generation rate
+[B]- String fixes from lemming -- neil
+[B]- Don't print discomfort messages when examining and comparing weapons -- neil
+[I]- new <state> function to the automatizer to detect identified state
+[I]- Automatizer rules are automatically apply upon exit of the screen or
+ autogeneration of a rule with the 'k' command
+
+28/11/2002
+[B]- Add experimental support to the automatizer for marking "bad" rings and
+ amulets -- neil
+[m]- Distinguish average, disarmed, and empty chests in the automatizer -- neil
+[B]- Let summoners summon again (patch by masmarangio) -- neil
+[B]- Remove duplicate warning of an empty quiver (patch by masmarangio) -- neil
+
+29/11/2002
+[O]- Let Demonshields and Demonhorns be treated as armor -- neil
+[m]- Can include string terminators in help file tags i.e:
+ *****foo.txt*7[see:\] it works;)]
+[m]- Can save screenshots to help file format, this is only usefull to
+ documentation writters and thus the option only appears when wizard mode
+ is activated. It uses the new verbatim mode &&&&& at the line beginning
+
+01/12/2002
+[m]- The helpfile typo corrections just keep coming! Added Udun school help,
+ and demonologist school help, thanks Mef and masmarangio. -- fearoffours
+[m]- Some more spelling errors corrected. Updated warriors skills in the
+ help files -- masmarangio
+
+02/12/2002
+[m]- Skill updates for more character classes in the help files. -- masmarangio
+[m]- Automatizer tutorial added. -- fearoffours
+[G]- God quest relic is now inscribed to prevent automatizer 'accidents'
+ -- fearoffours
+
+02/12/2002
+[O]- Wands/staves are now described this way: a wand of foo[bonus|max]
+ Bonus is the bonus spell levels you get, and max is the limit of spell
+ levels for that wand. It means even if you have Magic Device at level 50
+ you cannot get a level 50 spell from a wand with max 30. Naturally the
+ max(and bonus) increase with the depth you find the wand/staff :)
+[P]- Players in monster form can now use barehanded combat, instead of
+ reverting to monster attacks. -- neil
+[O]- Fix and reduce the wand and staff pricing -- neil
+[B]- Make the automatizer work independently of the player's body -- neil
+
+03/12/2002
+[m]- Clean out some unused variables and some other valid warnings -- neil
+[B]- Don't spoil things in the dump -- neil
+
+04/12/2002
+[m]- Updates of the character races help files -- masmarangio
+
+05/12/2002
+[B]- Maiar can't choose a god anymore -- masmarangio
+[I]- Added a message if you don't have powers but press 'U' -- masmarangio
+
+06/12/2002
+[B]- Staves are properly fireproofed now. -- fearoffours
+[m]- God quest gets more clues to the location, and they're printed in the
+ 'Ctrl-Q'uest screen. I'm too nice. -- fearoffours
+
+07/12/2002
+[I]- Added the extended command #quest (or #Q for short) to get quest list
+ because some prts catch the CTRL+Q combo
+[m]- Added contextual help for wands/staves, also added a section in the help
+ about it. --fearoffours
+[m]- Some small help file updates (Muar becomes Durin's Bane) -- masmarangio
+[m]- Added full mindcrafting spell info in the same form as other schools of
+ magic. Removed help on the Music skill, as this will not be included for
+ 2.1.0. Added some other help stuff. -- fearoffours
+
+08/12/2002
+[B]- Correct Damage/Round display for bare and bear combat. -- neil
+[m]- Help now has an alphabetical index! -- fearoffours
+[B]- Melkor wants you to sacrifice corpses, not raw meat -- neil
+
+09/12/2002
+[B]- Fixed an off-by-one error in loadsave.c that caused savefile corruption
+ if the number of monsters or objects saved was maximal -- masmarangio
+[m]- Removed help on the Druidistic skill since Druids are normal Priests now.
+ Minor changes to the skill example to match human warriors.
+ Updated Option help file, some other minor changes -- masmarangio
+[O]- Allow Wooden Rods to be sold at the Magic Shop -- neil
+
+10/12/2002
+[B]- Corrected the price of enchanted boomerangs and instruments. -- masmarangio
+[B]- Corrected the used multiplier while 'I'nspecting ammo.
+ Fixed the damage of throwing items / boomerangs -- masmarangio
+
+11/12/2002
+[I]- 'Compare weapons' works only with melee weapons, item selection changed.
+ Expanded the description of a god at birth. -- masmarangio
+
+12/12/2002
+[m]- Removed Tank Points and firestones. -- neil
+[m]- Removed PERNANGBAND monster flag and renamed as many Pern monsters,
+ artifacts, and other references as I could find -- neil
+[M]- Firebirds (formerly firelizards) and Thunderlords are B, not d and D
+ -- neil
+[B]- Fix some artifact activations -- neil
+[B]- Fixed (temporarily) item activation and description. Some items could
+ activate for the unified activation, and display the other activation, so
+ further changes are needed. -- masmarangio
+[I]- Removed the silly 'You are shooting with a flute' message. -- masmarangio
+
+13/12/2002
+[m]- Renamed instruments in luckspoi.txt, comment changes -- masmarangio
+[I]- Added OBJ_FOUND_SELFMADE for items that were created by the player.
+ Alchemist should also use it (not changed yet). Replaced the plain
+ description "in the Town" for items fond on the surface -- masmarangio
+
+14/12/2002
+[O]- Monster traps are disarmed by GF_KILL_TRAP and GF_KILL_DOOR -- masmarangio
+[m]- The description of ACT_DEST_DOOR includes traps, better description of
+ deactivating music instruments. -- masmarangio
+[M]- Increase Thunderlord rarities -- neil
+
+14/12/2002 -- T.o.M.E 2.1.0 aka "No Surrender, No Retreat"
+
+14/12/2002
+[B]- Artifact spoiler was messed up
+
+15/12/2002
+[m]- some small help files updates (Melkor, GoI, races) -- masmarangio
+[B]- some Orc Cave crashes fixed -- masmarangio
+
+16/12/2002
+[B]- Fixed the Mushroom Quest: mushrooms are taken before creating the rewards,
+ and these are created even with a full inventory -- masmarangio
+[B]- Grammar fix for breathing messages -- neil
+[B]- Changed order of level feelings, removed unused feelings. -- masmarangio
+[B]- A Rod of Drain Life is needed for vampiric artifacts instead of the Wand.
+ Renamed one ego light of Boldness (now of Fearlessness). -- masmarangio
+[m]- Updated and reformatted the essence spoiler. -- masmarangio
+
+18/12/2002
+[O]- Removed the double pval for Mana-items (40%)(+2). The description of
+ Mana and Life items is now with percents. -- masmarangio
+[m]- Small updates to m_demono.txt -- fearoffours
+[m]- Added mindcraft in magic.txt and a paragraph in m_mindcr.txt -- masmarangio
+
+19/12/2002
+[B]- Adjusted the melee damage shown in the status screen. -- masmarangio
+[B]- Spelling errors corrected. Thanks to markrax -- masmarangio
+[B]- Fixed bashing the trigger doors in the Thieves Quest -- masmarangio
+[B]- Allow Amulets of the Magi and *Defender* weapons to be sold -- neil
+[B]- Fix alchemist creation of ego staves, etc. (patch from "oops") -- neil
+[B]- Don't let gold into the inventory -- neil
+[B]- Temple doesn't want unblessed edged weapons -- neil
+[B]- Properly handle obvious flags on non-*ID*d objects (fixes things like
+ resistances grid and selling Blessed weapons in the temple) -- neil
+[B]- Squelch at different times, to avoid destroying the wrong items -- neil
+
+20/12/2002
+[m]- Removed some compiler warnings. Thanks to markrax -- masmarangio
+[I]- Work / fixes in spoiler creation (items, essences, menu) -- masmarangio
+[B]- Automatizer: <symbol> works with graphic modes -- masmarangio
+[B]- Fixed pval3 for artifact staves and wands in apply_magic -- masmarangio
+[m]- Corrected some typos and some comments. Thanks to markrax -- masmarangio
+[m]- Spell description edit -- neil
+[B]- Exclusive skill fix (patch by markrax) -- neil
+[B]- Yet more copyediting by markrax -- neil
+
+21/12/2002
+[m]- Corrected most of the typos found by vrak. -- masmarangio
+[B]- Fixed a display bug when passing through walls, thanks jup
+[B]- Copyediting of lib/edit/* -- markrax
+[B]- Copyediting of monster description books (lib/file/book-1[0-9].txt)
+ -- markrax
+[B]- Copyediting of misc. files in lib/file/ -- markrax
+[B]- Copyediting of most files in lib/help/ -- markrax
+[B]- Copyediting and description tweaks to tables.c -- markrax
+[B]- More minor copyediting -- markrax
+[m]- Minor externs.h code cleanup, remove dups -- markrax
+[B]- Let keypad 5 key work in X11 target -- markrax
+[I]- Add columns, tweak UI in character info sheet -- markrax
+[I]- Updated the artifact spoiler creation -- masmarangio
+[m]- Corrected some errors in a_info.txt -- masmarangio
+[B]- Display the arm slot when not wearing a two-handed weapon -- neil
+[I]- Cleaned up some code in the character info sheet -- masmarangio
+[B]- Fix drop message for junk artifacts (patch by jup) -- neil
+
+22/12/2002
+[m]- Copyediting of lib/edit/k_info.txt -- markrax
+[m]- Copyediting of lib/edit/al_info.txt -- markrax
+[m]- Added ENGLISH.txt file with ToME textual conventions -- markrax
+[m]- Standardized on "Middle-earth" spelling -- markrax
+[m]- More grammatical fixes (mostly "it's") -- markrax
+[m]- Removal of many Americanisms, grammatical fixes -- markrax
+[O]- Centered Map around Minas Anor -- masmarangio
+[I]- Allowed the user to abort when asked to engrave on a grid. Also, don't
+ let the player engrave on a grid with no mana. Thanks to Pav of
+ angband.~.cz for this patch. -- takkaria
+[m]- Updated and relocated style guide -- markrax
+[O]- CURSED two items with HEAVY_CURSE, thanks jup -- markrax
+[O]- CURSED Ring of Durin (had HEAVY_CURSE), thanks jup -- markrax
+[B]- Let *Identify* of your pack work the same as an individual *Identify*
+ for the purposes of alchemists -- neil
+
+23/12/2002
+[I]- Updated the broken spell spoiler creation (works for the bookless powers).
+ LUA schools should be added -- masmarangio
+[m]- Parchment titles capitalised. Spacing of artifacts and some americanisms
+ and errors in a_info.txt, tables.c, and other files corrected.
+ -- masmarangio
+
+24/12/2002
+[O]- Added description from Sangband to the Shield of Gil-Galad -- masmarangio
+[B]- tried to prevent printing of alchemy items in spell spoiler -- masmarangio
+[B]- Fixed two alchemy bugs: Same sval for Rings of Critical Hits and the Ring
+ of Durin. Corrected the sval of Rings of Constitution -- masmarangio
+
+25/12/2002 - Mery xmass!
+[P]- Boulder throwing skill :) For Ents .. Don't get used to it as I don't know
+ if I'll let it in
+[B]- Destruction cannot kill quest monsters
+[B]- The lost temple (god quest) dungeon really cannot be generated in
+ inaccessible places now. -- fearoffours
+[I]- Unidentified objects are marked in slate(the inventory letter)
+
+26/12/2002
+[m]- Updated the skill gain in skills.txt, corrected some spelling errors.
+ Added Boulder-throwing to the help files -- masmarangio
+
+27/12/2002
+[B]- Fixed note file problem under windows -- masmarangio
+[m]- Corrected some americanisms and spelling errors -- masmarangio
+[B]- Fixed an alchemy error with fireproofed staves, removed tabs from c_prt
+ calls -- masmarangio
+
+28/12/2002
+[P]- Added dynamic subrace. This means that "things" in the game can somewhat
+ change your subrace. This is used by the 3 new Vampire corruptions, which
+ when combined will permanently turn you into a full blown Vampire.
+ The Vampire subrace has been removed, it might come back as a template for
+ the corruptions, or not. All others undead subrace will have the same
+ fate. This means that soon you'll be able to turn into an undead rather
+ than start as one. The penalties will be tweaked too so we don't end up
+ with every char being an undead.
+[B]- Fixed a branding bug that allowed to modify artifacts and ego-items.
+ -- Kusunose
+[m]- Updated corruption_spoiler_generation (includes index tags, don't show the
+ Lose message for not removable corruptions) and corspoil.txt -- masmarangio
+
+29/12/2002
+[I]- Stores/homes inventory letters are colored just like inventory/equipment
+ thanks to Pav
+[m]- Music system performance improvement -- neil
+[m]- Added help on pets to dungeon.txt and some clarification about Spell-power
+ affecting only the 11 primary schools of magic. -- fearoffours
+[m]- Added to Spell-power the other affected Schools (Udun, Demonology, Gods),
+ as well as naming Sorcery in the Udun School help file -- masmarangio
+
+30/12/2002
+[O]- init1.c: added two times OBJ_FOUND_SPECIAL -- masmarangio
+[m]- al_info.txt: removed double acid essences in amulet of resistance, grouped
+ entries for ring of extra attacks, renamed some entries -- masmarangio
+[m]- wizard1.c: Added IS_CVS to header, create artifacts at 25, not 35, added
+ index in Essence Spoiler. essences.txt: new spoiler file -- masmarangio
+[m]- cmd1.c: removed a compiler warning. caves.c: simplified a test -- masmarangio
+[m]- Info on spell-power and multi-school-spell interaction, typo fix in
+ m_mindcr.txt -- fearoffours
+
+31/12/2002
+[B]- object2.c: Initialised Artifacts with LEVELS in apply_magic -- masmarangio
+[O]- generate.c: OBJ_FOUND_MONSTER for final artifacts / objects -- masmarangio
+[B]- al_info.txt: Svals of Ring of Sustain Con and Dex exchanged -- masmarangio
+
+01/01/2003 - Happy new year !!!
+[B]- store.c: Fixed bug with prices of wands, indentation -- masmarangio
+[I]- Better fountain command interface. -- Kusunose
+[B]- al_info.txt: Added Ammo of slay animal. Amulet of regeneration with new
+ sval. Ego Weapons of Life added -- masmarangio
+
+02/01/2003
+[B]- find_ignore_stairs, set or unset, failed to handle some quest related
+ stairs properly. -- pelpel
+[B]- cmd7.c: Fixed bug with TR4_ART_EXP not set correctly -- masmarangio
+[O]- cmd7.c: Added OBJ_FOUND_SELFMADE for created items/artifacts -- masmarangio
+[B]- Don't allow a change from weapon combat if a cursed weapon is wielded
+ -- neil
+[m]- wizard1.c: Changed position of IS_CVS, added double ego items in essence
+ spoiler. essences.txt: reflects this -- masmarangio
+
+03/01/2003
+[B]- wizard2.c: Some bound checks to prevent crashes -- masmarangio
+[B]- cmd7.c: Fixed reduced capacity of ego rods -- masmarangio
+[B]- object1.c: Added a "It cannot be destroyed" msg in place of "it has blah%
+ chance of breaking upon hit" for artifact ammo. thanks lemming for fix
+ -- fearoffours
+
+04/01/2003
+[O]- e_info.txt: Added indestructible and cursed amulets to simplify alchemy
+ -- masmarangio
+[B]- cmd7.c: Allow creation of artifacts from single ego items; don't change
+ artifacts and double ego items if you don't wish to create an artifact.
+ Simplified amulet handling and other code fragments -- masmarangio
+[m]- QUITING-> QUITTING, COMBINAISON->COMBINATION: two cases of typos
+ that I've long been aware of... -- pelpel
+[D]- Changed the marker(#172) to look like open floor(#1) -- masmarangio
+[B]- Updated Amulets and Rings in defines.h / defines.txt -- masmarangio
+[B]- al_info.txt: Amulet of Adornment without pval. cmd7.c: skill >= 25
+ needed to create artifacts, not > 25 -- masmarangio
+[B]- Warning about leaving a trap detected zone don't cost energy -- masmarangio
+
+05/01/2003
+[m]- First update of commands.txt -- masmarangio
+[B]- spells2.c, self_knowledge(): f4 through esp were not initialised before
+ referenced. -- pelpel
+[B]- cmd7.c, extern.h: changed the variable "tocreate" in alchemist_items_check()
+ from bool to int -- masmarangio
+[B]- xtra1.c, apply_flags(): Added bounds checks for antimagic. -- pelpel
+[B]- xtra1.c, apply_flags(): changed the type of bit field variables from s32b
+ to u32b, for obvious reasons. -- pelpel
+[G]- Princess now offer 3 reward and the player selects one
+
+06/01/2003
+[B]- cmd7.c: Fixing three bugs in Alchemy: Extracting from double ego items and
+ from stacks of staves, as well as generating all leeched empty items.
+ Problems may still arise when you leech a stack of objects from the floor
+ and essences get dropped over them. Boomerangs can be enchanted now.
+ -- masmarangio
+[B]- generate.c: Moved the room creating loop (fix from 15/12). Something better
+ should be used than this brute force method -- masmarangio
+[B]- Minor spelling and grammar fix -- neil
+[B]- Changed the type of dungeon_flags to u32b, as in types.h -- masmarangio
+[B]- cmd7.c: Instruments can be enchanted now. -- masmarangio
+[G]- Applied the Artifact Activation patch -- masmarangio
+[B]- Fix activations -- neil
+[G]- Alchemists can no longer make artifacts granting Precognition or Immunity
+ to Nether -- neil
+[B]- Avoid some bad periods in monster descriptions -- neil
+
+07/01/2003
+[P]- p_info.txt: Updated, compacted history-chart. Trolls, Orcs, Elves with new
+ entries, some other small changes. Deleted the unused races -- masmarangio
+[m]- Added Activations to essence spoiler, new help file created -- masmarangio
+[B]- Reset the pval of extracted rings and amulets, prevent creation of cursed
+ empty items -- masmarangio
+[B]- Make ego staves / wands of nothing extractable, disallow empowering of ego
+ items / artifacts that are not wearable (e.g. staves) -- masmarangio
+
+08/01/2003
+[I]- squeltch.c: Ask for overwriting rules file and display saving message in the
+ same box -- masmarangio
+
+10/01/2003
+[m]- Added a (conservative and preliminary) port to OS X + gcc + makefile.
+ The four *.icns files are faithful conversions of the traditional Angband
+ icons that have long been used by Mac ports, even before Ben.
+ makefile.std itself is not updated. Please read comments in main-crb.c.
+ -- pelpel
+[m]- Module support. It means that people can write ToME "modules" which will
+ go in lib/mods and contain "variants" that use the same game engine but
+ different lib/foo files. The module selection screen only appears when
+ the game detects more than one module. The new -Mfoo command line option
+ allows to bypass module selection
+[m]- 'Death' Message of a Nazgul: Choose pronoun 'she' or 'he' according to the
+ sex -- masmarangio
+[G]- God quest wont trigger for Lost Souls until they reach the surface
+[m]- Turn off some ToME things when using a non-ToME module -- neil
+[B]- Fix the monster description messages even better -- neil
+[B]- Better honor the NO_TARGET flag -- neil
+[M]- Give Farmer Maggot the NO_TARGET flag -- neil
+[B]- Fixed (hopefully) the wrong activation bug -- masmarangio
+[m]- (Mac, Carbon) Modernised file system interface (currently only turned on
+ for Mach-O Carbon port), improved Mach-O Carbon support, incorporated my
+ 32x32 tiles support code for V3.0.2, and more gcc porting note -- pelpel
+[m]- Let the player see which game module he selected in the character
+ selection screen -- neil
+
+11/01/2003
+[B]- Fixed one wrong sval in al_info.txt -- masmarangio
+[m]- Added makefile and some auxiliary files for developer CD gcc compilation
+ of Carbon port -- pelpel
+[m]- (OS X Carbon) Changed the format of graphics tiles from PICT in the
+ resource fork to plain PNG files, only for gcc compilation at the moment
+ -- pelpel
+
+12/01/2003
+[B]- Alchemy: The song of music instruments, the type of explosive ammo and
+ the level of sticks are not changed by enchanting / leeching the items.
+ -- masmarangio
+[m]- Expanded the description of Antimagic, small index updates -- masmarangio
+[I]- wizard2.c: Initialised the lua command (^A >) with the help file index
+ generation -- masmarangio
+[m]- (OS X Carbon) Cleaned up my recent updates. It's fairly stable now.
+ To do: move to .nib based menu/dialogues, pulling sound out of resource
+ fork, and better sound code. -- pelpel
+[B]- cmd7.c: Allow extraction of the charges of Sticks of Plenty -- masmarangio
+
+13/01/2003
+[m]- preliminary SCANDIR support for gcu, gtk, xaw borrowed from x11 -- neil
+
+14/01/2003
+[m]- Modules can control the number of levels over the player level a skill
+ may have allocated now, using max_skill_overage. -- neil
+[m]- HOOK_FIRE added -- neil
+[m]- Changed the help files about vampires; classes, races etc. are listed
+ in alphabetical order in birth.txt -- masmarangio
+[m]- Races & subraces get a starting object list in p_info, less hacks in birth.c
+[I]- Automatizer can now be used to auto-inscribe items, thanks to jepler
+[I]- Automatizer can now display rules in a more english like maner, xml mode
+ is also available, switch by pressing 'x', thanks to jepler
+
+15/01/2003
+[G]- Summoner can extract totems from skeletons / carapaces. -- masmarangio
+[B]- Trap of Wasting Wands (affects also Staves) change the Wand/Staff to the of
+ nothing type. Deleted SV_WAND(STAFF)_NASTY_WAND(STAFF), since in the new
+ stick system the worthless sticks don't have the first svals -- masmarangio
+[B]- Fixed a fountain filling bug, simplified the item_tester -- masmarangio
+
+16/01/2003
+[B]- (Mac, OS X) Tilewidth/height code ceased to work because menu API started
+ to return Unicode crap instead of holy ASCII -- pelpel
+
+17/01/2003
+[m]- HOOK_EAT added -- neil
+[O]- New artifact: The Sling of the Thain -- neil
+
+18/01/2003
+[B]- empty chests are generated as known (i.e. they were opened) -- masmarangio
+[B]- do_cmd_rest flushes input if the player can't do so for some reasons
+ and flush_failure is set.
+ Note: flush() doesn't seem to work as it used to do... Any changes have
+ been made to inkey, or some code touches its various control variables?
+ -- pelpel
+[m]- (Gtk) Added support for the "bigtile" mode. Please start the game with
+ "tome -- -w" if you don't like to see horrible glitches... This is not
+ Gtk-specific problem by the way. Scrolling the map and hitting ^R fixes
+ it too, if you prefer menu command -- pelpel
+[G]- Trees are now passable by wraith beings. Monsters that fly will pass trees.
+ Dead small trees will be dead small trees. Monsters tunneling will also
+ destroy trees
+[P]- Extra HP bonus(from quest, melkor, ...) is applied before sorcery penality
+
+19/01/2003
+[B]- (Gtk) Fixed problems with wide tile mode when it is used with backing
+ store. Seems more like the problem is in z-term (it only updates every
+ two columns of the dungeon map...), but it works now -- pelpel
+[B]- (Mac) The asynchronous sound player unlocked and released sound data
+ without confirming its completion. Wrote an alternative implementation
+ that holds data until a channel it is played is reused, to avoid using
+ interrupt-time code (which is quite complicated business in 68K).
+ Because this means that a fairly large amount of data can be locked in
+ memory for a long time, I reduced number of channels used to
+ 4 in Classic and 8 for Carbon -- pelpel
+
+20/01/2003
+[G]- Trees/grass can only grow one some terrains(yes that DO exclude lava;)
+[I]- z) slot is hidden until needed -- thanks to Scott Bigham
+[I]- Some cosmetic changes and improvements to char dumps -- thanks to Scott Bigham
+
+21/01/2003
+[B]- Monster traps: Changed the code so that the new wands and staves are
+ functional in device monster traps. This is commented out with #if 0 since
+ the code must be tested. Perhaps a lua solution is better ? -- masmarangio
+
+22/01/2003
+[B]- Deathmolds could use their racial power without spending a turn!
+[B]- 'U' powers didn't remove Disruption Shield
+[m]- (Mac, Windows) Added an in-game menu command to view current scoreboard.
+ Taken from the latest [V] (Win port only there), minus the use of
+ display_scores_aux, which I regard first-degree Mega-Hack -- pelpel
+[G]- Wielding the One Ring now has real disadvantages, you've been warned :)
+ What ? I didn't mention what disadvantages ? Oh yes, I didn't.
+[G]- Bump required level and difficulty rating of Minas Anor quest, as the
+ trees changes have made it just a little harder. -- neil
+
+23/01/2003
+[I]- Hopeless attempts to dig will be noticed to the player -- thanks to jepler
+[B]- Potions of Cure Water are no more extractable by Alchemy
+
+25/01/2003
+[P]- Bard class is back(was called Harper before) with a new Music skill.
+ Instruments carries the spells, and they work a bit like Psi foci in
+ psiband. An instrument (+2) can only play songs that are marked (I) or
+ (II) not (III) or (IV)
+[B]- Ordered the music songs according to the needed pval, then level.
+ Fixed the svals of artifact instruments, changing the Flute to a Harp.
+ Added a better description of Bards. Please check it ! -- masmarangio
+
+26/01/2003
+[B]- An Alchemist can now fireproof spellbooks -- masmarangio
+[m]- Bard and Music docs are done. Please check em. -- fearoffours
+[B]- A possessor (the creature, not the class) can only possess whole
+ corpses and skeletons, not pieces of meat -- masmarangio
+
+27/01/2003
+[B]- Make wielding more than one demonshield (or demonsword I suppose) work
+ -- neil
+
+28/01/2003
+[B]- Possession something while encumbered to the point of having 0 mana
+ allowed free use of body spells without failure
+[P]- Mana is now function of the Magic skill and either INT or WIS, whichever
+ is higher
+
+30/01/2003
+[B]- Possibly the relic in the god quest couldn't have been generated.
+ Wasn't me honest guv. -- fearoffours
+[G]- The lost temples for god quests now have harder monsters to make the piety
+ gain rather more substantial and obvious I hope. Deeper monsters appear
+ as player clvl increases. -- fearoffours
+[m]- Help file corrections on Music skill. -- fearoffours
+
+01/02/2003
+[B]- Some menus exits when 'e' was hit on some comapilation.
+ Note: '\e' for escape is compiler dependant extension so do not
+ use it. Thanks kobayasi for fix. -- Kusunose
+[B]- All known staves and wands are displayed as 'Globe of Light' in
+ the Known Object list. Thanks kobayasi for fix. -- Kusunose
+
+08/02/2003
+[m]- Make HOOK_QUAFF take an o_ptr, and let HOOK_EAT return the identify success
+ -- neil
+
+12/02/2003
+[I]- Useless but fun, when a wield monster takes damage instead of you
+ the monster will be named. If you named it(with the #foo inscription)
+
+16/02/2003
+[B]- Chaging the melee style did not update bonuses. Thanks to kobayasi for
+ the patch. -- Kusunose
+[B]- <sval> in automatizer worked even when the player was not aware of
+ the object. It was possible to use this as a free ID. Thanks to
+ kobayasi for the patch. -- Kusunose
+
+24/02/2003
+[B]- Cancelling the reward skill sellection could crash the game. -- Kusunose
+
+26/02/2003
+[I]- Boomerangs now display damage with 'I'nspecting, thanks to Scott Bigham
+
+27/02/2003
+[B]- Inspecting or Identifying something shouldn't infect you with the
+ Black Breath -- neil
+
+28/02/2003
+[I]- Genocide and genocide like effects that require monster race now allow
+ targetting of a monster to select the race. Gfx users can now correctly
+ genocide :)
+
+01/03/2003
+[I]- d/s and g/p work in both home & stores. Pfft.
+
+02/03/2003
+[m]- Fixed a typo in The Dragon Helm of Turin Turambar -- WeZ
+[G]- Fixed the teleport-level ability of Deathmolds, so they
+ can teleport out of a dungeon, instead of getting a
+ message saying there's only air above them. -- WeZ
+
+04/03/2003
+[P]- Probability travel level teleport ability & teleport level spells
+ wont work in some dungeon
+
+05/03/2003
+[G]- A new quest! An ultra ending! "Falling Toward Apotheosis"
+ After banning Morgoth spirit in the Void, you can pursue him
+ there to forever end the darkness. But beware, it is more than
+ likely that you will die. But for the few that succeed, the fame
+ will be great!
+ Note: you can only do it if you choosed the way of Good and thus
+ destroyed the One Ring. An evil ultra ending is planned and will
+ come a bit latter.
+
+06/03/2003
+[P]- Dwarves get a bonus to axe mastery, as they rightfully should
+[O]- Cloak of Air. Generates an air bubble around you so you can breath.
+ Just in case you need it ..
+
+08/03/2003
+[G]- Another new quest! An old mage in Minas Anor needs help, too. -- neil
+
+12/03/2003
+[B]- Non-enemy monsters now won't hold up victory in the Spiders and Library
+ quests. -- neil
+[B]- Various Library quest fixes -- neil
+
+13/03/2003
+[O]- Lebohaum activation is now true to the original material..
+[P]- All mages start with 0.1 less mod to Sorcery. Specialists dont have sorcery.
+ Runecrafters dont iether, nor Alchemists. Thaumaturgists do.
+ Specialists also get a bit better Spell-power
+
+16/03/2003
+[I]- Only show enemies in the uniques list -- neil
+
+20/03/2003
+[m]- The various ?_info.txt files can now include otehr files with the <:file.txt
+ command. This allows people to split up too big files
+
+23/03/2003
+[I]- X11 port can now do text selection copy&paste with the mouse, thanks to kieron
+
+27/03/2003
+[B]- Mage staves, rod tips, and magic tomes are now "good" items. This should
+ fix the problem of Saruman, Sauron, and others dropping nothing but rods.
+ -- neil
+
+28/03/2003
+[I]- Show "ironman_rooms" setting in the character dump -- neil
+
+29/03/2003
+[P]- The adventurer quest skill reward will now only provide a modifier of 0.3
+ if you dont have the skill, but if you have it it will improve the modifier
+ by 0.1 if it is below 0.5
+[I]- Automatizer rules now have an module attribute, defaulting to "ToME". The
+ module name is case sensitive, as always. <rule module="ToME" name="Die"
+ type="destroy"> will only destroy items when you're playing the ToME
+ module. -- neil
+
+02/04/2003
+[B]- Fix grammar error pointed out by "JanaRaissa" -- neil
+[B]- Prevent instrument-wielders from firing things, as pointed out by
+ "Chudus" -- neil
+[B]- Those who can breathe water or don't need to breathe at all should not
+ drown in pools of water, as pointed out by "Zonk" -- neil
+[B]- Fix Rods of Simplicity for those who need it most, as pointed out by
+ "Zizzo" -- neil
+
+03/04/2003
+[O]- Dragon Scale Mail now has more options for egos and random artifacts
+ -- neil
+
+04/04/2003
+[B]- Fix god quest temple placement error pointed out by "Fringe Worthy"
+ -- neil
+
+05/04/2003
+[I]- Somewhat nicer char screen, thanks to lemmings(I think ;)
+[B]- No more (broken) pattern vaults -- neil
+
+08/04/2003
+[m]- Ability to add timers in lua
+[B]- Fix spelling: PARCHEMENT -> PARCHMENT. Automatizer rules and other scripts
+ that use PARCHEMENT will still work, though. -- neil
+
+09/04/2003
+[M]- Companions and pet uniques can now be killed
+
+11/04/2003
+[P]- Trolls cannot get the troll blood corruption
+[P]- At Monster lore skill level 12 one can turn a pet in a loyal companion.
+ Note that you are limited in companion number
+[P]- Reduced Necromancy spell failure damage
+
+12/04/2003
+[P]- Skill multipliers of Rogues and Assassins are higher now. -- neil
+[B]- Fixed alchemy making of xtra shots/might
+[P]- Some skills have more chances to be taugth than others by fumblefinger
+
+13/04/2003
+[P]- Melkor Curse spell autocast chance formula changed
+[O]- Wishing for dual ego items works
+
+14/04/2003
+[P]- Spellbinder spell will reveal more info about itself when cast while
+ already active
+[P]- Increase Mage's Weaponmastery Multiplier by 0.1 -- neil
+[P]- Experimentally double Barehanded Combat martial arts damage dice
+ to make Monks more attractive -- neil
+
+16/04/2003
+[O]- Goods stolen from stores now get a 100% discount. -- neil
+[P]- One can now steal from more places -- neil
+
+17/04/2003
+[B]- Everburning torches, Feanorian Lanterns, and Dwarven Lanterns of Fading
+ couldn't be filled -- neil
+[B]- The Crumpled Scroll of Mass Resurrection no longer revives special
+ monsters who won't ever appear again anyway. -- neil
+
+18/04/2003
+[B]- Gauntlets that contain spells no longer hinder spellcasters -- neil
+[I]- Some junk removed from the character resistances grid -- neil
+
+18/04/2003
+[G]- Bree house is not available from start anymore, you have to get it
+ as a reward from the thieves quest
+
+20/04/2003
+[G]- The Lothlorien and Gondolin homes aren't free anymore, either -- neil
+
+21/04/2003
+[G]- The Minas Anor and Khazad-dum homes must be won, too -- neil
+
+24/04/2003
+[I]- Reworked 16x16 gfx by P_laloli@hotmail.com
+
+25/04/2003
+[B]- Fix the case where some birth items wouldn't stack -- neil
+[B]- Disarming a trap on a stair should not destroy the stair -- neil
+
+26/04/2003
+[B]- Player invisibility shouldn't hinder monsters attacking targets other
+ than the player (patch by Jeff Epler) -- neil
+
+27/04/2003
+[B]- Mana and Life drains should not cause infinite rest loops -- neil
+
+28/04/2003
+[O]- Handmade items like arrows and totems are fully identified -- neil
+
+29/04/2003
+[m]- Max skills internaly increased to 200
+[G]- Random quest are now disabled when persistent dungeon levels are enabled.
+ -- neil
+
+30/04/2003
+[O]- The artifact that had aggravation and a stealth bonus no longer has
+ that useless stealth bonus -- neil
+[O]- It's now much harder for sentient weapons to get the Acid realm -- neil
+
+01/05/2003
+[I]- '+' command(alter terrain) wil ltry to open doors instead of tunneling
+ them
+
+02/05/2003
+[P]- Shots now pierce when they used to ricochet in random directions -- neil
+[P]- Piercing shots are now togglable -- neil
+[G]- Singing happy drunks will freely accept alcoholic beverages from you.
+ -- fearoffours
+[m]- Class helpfiles updated to reflect some changes in skill allocation.
+ -- fearoffours
+[I]- Turned on by default the linear stats display
+[m]- Chris Hadgis submitetd the first documented package of the ToME API!
+ More comming :)
+[I]- Maxxed stats now show a "!" in the character screen and dump, too -- neil
+[P]- If you play something experimental, it now shows up in the character
+ dump. Alchemists and Death Molds are marked as such for now -- neil
+[P]- Necromantic magic got a new spell: Necromantic Teeth
+
+05/05/2003
+[B]- Stone Prison spell would create floor where it shouldn't, possibly
+ trapping you in places like the Eol quest. -- neil
+
+06/05/2003
+[G]- Angband now blocks the magic of the Thunderlords' Nest -- neil
+[B]- Fix activation descriptions patch by Chris Hadgis -- neil
+
+09/05/2003
+[I]- ToME should try harder to use proper thematic flooring when appropriate
+ -- neil
+[B]- Stone Prison should not be able to turn walls into floors. -- neil
+
+11/05/2003
+[B]- Sound effects shouldn't give knowledge the player wouldn't otherwise
+ know (like the generation of the relic) -- neil
+
+12/05/2003
+[B]- Don't show silly chance to break for exploding ammo -- neil
+
+14/05/2003
+[m]- lib/patch directory to contains auto-loaded patches.
+ Each patch must be contained in it's own subdirectory and
+ must contain a patch.lua file with a patch_init() function in it
+ that must return the patch name and version
+
+16/05/2003
+[P]- Abilities. Abilities are like skills, but are booleans. That is
+ you either know them or not, there is no scale. One can learn
+ abilities by spending skill points in the abilitie screen(press 'N').
+ Abilities can have prerequisites to be meet before one can learn them.
+ (Like some can need a stat level, a skill level, ...)
+ Some classes get abilities for free at certain level. Like warriors
+ will get Spread-blows ability at level 25 for free(even if they dont
+ actually meet the prereqs).
+[P]- All classes now get 4 max blows. But there abilities that can increase
+ the max. Warriors gets them for free at birth, and other classes also
+ get some so they are not less powerful than before the change. This
+ will however help people create warrior-mages for example.
+[m]- Internal change: Magic Realms are gone. -- neil
+[I]- No more spell list window flag. It hadn't done anything since ToME 2.0
+ anyway -- neil
+[m]- Total savefile compatibility break. Hopefully we can do better from now
+ on -- neil
+
+21/05/2003
+[I]- The player now gets warned during race/class/subrace selection that a
+ class is experimental. -- neil
+
+23/05/2003
+[B]- Innate monster friendliness shoudln't take precedence over summoned pet
+ or companion status -- neil
+[B]- The Helm of Knowledge and Automatizer pickup now get along -- neil
+
+26/05/2003
+[m]- Initial helpfiles update for Abilities. -- fearoffours
+
+27/05/2003
+[I]- Princess quest reward selection is not cancelable
+
+28/05/2003
+[P]- New skill: Geomancy, works in combinaison with the 4 elemental skills
+ to produce various effects from the raw elements around teh caster
+ (grass, sand, ...). Elementalists becomes Geomancers now.
+ Thanks to Fubar Obfusco for the detailed idea
+[P]- Runecraft is not gainable from fumblefingers until it is reworked
+
+29/05/2003
+[m]- More help updates - Artifact Creation ability, plus addtions to FAQ and
+ skills.txt and others. Thanks to Michael Beatty for some suggestions.
+ -- fearoffours
+[I]- Autoroller now uses linear stats when requested
+[I]- Object window will now display the 'I'nspection of the last manipulated
+ item
+
+30/05/2003
+[B]- Resting ignores HP or SP if a drain on HP or SP is induced by an object
+[O]- Beat down the power of randart rings yet more -- neil
+
+31/05/2003
+[m]- Geomancy help. -- fearoffours
+[O]- heavy Xbows of Siegecraft, thanks to Fang
+
+01/06/2003
+[B]- The automatic drop from wilderness should no longer be abusable. No longer
+ can you hit < when you're hungry, cut, poisoned, or sensitive to light during
+ the day -- neil
+[P]- Far reaching attack ability. When using a long polearm you can attack monsters
+ 1 or even 2 grids away(at the cost of a reduced number of blows)
+ Idea taken from Adamant
+[O]- Ingeborg S. Norden's artifact bolts added -- neil
+[P]- Trapping is now an ability instead of a skill. Rogues, but not Assassins,
+ start with it -- neil
+[m]- Help updated to reflect new abilities. Deathmold question added to FAQ.
+ -- fearoffours
+
+06/06/2003
+[P]- Undead Form is now an ability
+[m]- Documentation for Undead Form added. -- fearoffours
+
+08/06/2003
+[m]- Added skill tests abilities to .prf files thanks to Scott Bigham
+[B]- Thaumaturgy attacks will travel more than one grid when not targeted
+ at a monster thanks to Scott Bigham
+[I]- Inscription and discount clauses for the automatizer thanks to Scott Bigham
+
+09/06/2003
+[O]- Boomerangs now have just a 1% chance to break, have their chance to hit
+ improved by Boomerang-mastery, get sold in shops, and are a bit less
+ rare -- neil
+
+10/06/2003
+[G]- The god quest is a (little) bit more forgiving about the direction the
+ dungeon lies in, and you also get an approximation of it's distance.
+ -- fearoffours
+
+11/06/2003
+[B]- Thaumaturgy spells could be too weak -- neil
+[B]- Demonologists couldn't use the Demon Summon spell -- fearoffours
+
+14/06/2003
+[P]- Thaumaturgy spell levels now range from 1-50 instead of 1-100, so now
+ one won't get spells with impossible failure rates, as suggested by
+ Jules Bean -- neil
+
+16/06/2003 -- T.o.M.E 2.2.0 aka "Born to the Purple"
+
+18/06/2003
+[B]- Fix manwe spell Avatar
+
+19/06/2003
+[B]- Silly silly bug in god quest fixed. -- fearoffours
+
+20/06/2003
+[B]- Mimics starts with a cloak
+[B]- Using the @ key in skill menu wont crash
+[B]- Cannot copy uncopiable spells
+[B]- Dripping Tread will put feats on the last grid, not the current one
+
+21/06/2003
+[m]- Clearer descriptions for spells which require more than one school
+ -- fearoffours
+[P]- Geomancer tweaks: Geyser's mana progression now matches its damage
+ progression. Geomancy now gives much larger bonuses to its child
+ skills, so Geomancers are now intended to max out the elements. -- neil
+
+22/06/2003
+[B]- Potions of Cure Water are inscribed for you to prevent mishaps with
+ the automatizer -- neil
+[B]- Don't let people travel with extra limbs, to prevent them losing
+ weapons by mistake -- neil
+[B]- Allow hypnosis of companions, make hypnosis failure messages more
+ useful - neil
+
+23/06/2003
+[m]- Mimicry help. Magic help now has it's own menu, other minor help
+ updates. -- fearoffours
+
+29/06/2003
+[m]- "Investing in the <foo> skill? You might be interested in the <bar>
+ ability." links in skills.txt --fearoffours
+[B]- God quest bug genuinely fixed now -- fearoffours
+[P]- Bear form will now starts at -5 speed but end at +5
+
+29/06/2003 -- T.o.M.E 2.2.1 aka "There All the Honor Lies"
+
+09/07/2003
+[B]- Prevent forbidden staves from being generated
+
+14/07/2003
+[B]- Really fix the God quest this time, we hope
+
+15/07/2003
+[m]- Mac OS X Module support
+[m]- Solaris compile workaround from Kevin W. Thomas
+
+16/07/2003
+[B]- Fix broken status in auto automatizer rules -- neil
+[m]- Valid XHTML in the HTML screenshots now -- neil
+
+17/07/2003
+[B]- HPUX support -- neil
+
+20/07/2003 -- T.o.M.E 2.2.2 aka 'And Now For a Word'
+
+20/07/2003
+[P]- No more involuntary corruptions
+
+02/08/2003
+[B]- Fixed crash on 'l'ook in rare conditions, thanks slappy0042
+[B]- Fixed inflation of ammo damage display, patch by 'Zizzo' -- neil
+
+05/08/2003
+[m]- Help updates - spectres lose hp when passing walls, thieves cannot shoot
+ arrows (very well), non-geomancer mages have a 0.00 modifier to Geomancy.
+ -- fearoffours
+[m]- Help updates - typo in rm_spec.txt and High-elves have good wisdom
+ -- fearoffours.
+
+08/08/2003
+[B]- Tulkas piety gains now match the documentation -- jules
+
+10/08/2003
+[m]- helpfiles - Clearer geomancy skill values for non-Geomancer Mages, a note
+ about effect of stealing from shops in skills.txt, and some FAQ additions
+ about FF and random quests. -- fearoffours
+
+13/08/2003
+[B]- Manwe, Eru, Yavanna, and Tulkas will not yet you start following them if you
+ are wearing the One -- neil
+
+24/08/2003
+[B]- Set number of charges correctly when a wand is stolen -- neil
+
+26/08/2003
+[m]- Scott Bigham's tome-autoabil.diff: Adds a new automatizer class
+ <ability>, which is true when you have the given ability -- neil
+
+27/08/2003
+[m]- Riscos support thanks to Antony Sidwell
+
+30/08/2003
+[m]- Savefiles are now stores in ~/.tome/save[/modulename] on multiuser systems
+[m]- Apply patches based on those from FreeBSD ports -- neil
+
+06/09/2003
+[O]- Beaked Axes, Battle Axes and Lochaber Axes are recognized as polearms
+ again. -- neil
+[O]- Misleading "polearm" description removed from non-polearm
+ Quarterstaff -- neil
+
+14/09/2003
+[m]- Added help for 'repeat last command' to command.txt. -- fearoffours
+
+15/09/2003
+[B]- Fixed autopickup of ammo crash under some circumstances
+[B]- Fix monster list mimic bug
+[B]- Tree Roots incorrect bonuses fixed
+[B]- Fixed incorrect display of some skill bonuses
+
+15/09/2003 -- T.o.M.E 2.2.3 aka 'The Quality of Mercy'
+
+22/09/2003
+[B]- Detect doors and traps displays as costing 3, not 5 now. -- fearoffours
+[B]- Maeglin quest reward wording altered (saves confusion for sorcerors).
+ -- fearoffours
+[I]- Adam Bolt's Tiles are now "New Tiles", as others have worked on them and
+ stuff. -- fearoffours
+
+25/09/2003
+[B]- Typos in One Ring parchment and Necromancy help fixed. -- fearoffours
+
+27/09/2003
+[B]- Typos in ultra-good ending, lost-sword quest rewards and flag description
+ fixed. -- fearoffours
+[O]- Restore spaces to artifact descriptions -- neil
+
+28/09/2003
+[B]- Axemasters now start with a Hatchet -- neil
+[B]- Fix "analyze monster" activation -- neil
+
+04/10/2003
+[B]- Fix library quest breakage of Melkor curses -- neil
+
+05/10/2003
+[B]- Fix failure rates for abilities in possessed bodies, patch by 'Slappy'
+ -- neil
+
+06/10/2003
+[B]- Monsters detected ONLY by telepathy were not removed from visible monsters
+ list after they had gone out of range. Thanks Slappy for fix. -- fearoffours
+[B]- Recharged junkarts would not always give a notification message. Thanks
+ Slappy for fix. -- fearoffours
+[O]- Changed descriptions of some junkart activations. -- fearoffours
+[B]- Completion of Necromancer quest could be triggered incorrectly.
+ -- fearoffours
+[D]- "The lava burns you", becomes "you move across the lava" to accomodate
+ IM_FIRE and flying characters. -- fearoffours
+
+07/10/2003
+[m]- Applied Ken Dubuc's patches to parsers to make them line ending independant
+[m]- Savefiles on multiuser systems are now in HOME/.tome/2.2/save, to comply
+ with the new 3.0.0 naming scheme that is coming.
+ People upgrading from 2.2.x to 2.2.4 should move their savefiles there
+
+08/10/2003
+[B]- Monsters don't appear to disappear for a turn if you polymorph them -- neil
+[m]- Setting module to "all" for an automatizer rule makes the rule apply
+ to all modules -- neil
+
+11/10/2003
+[B]- Flying semi-wraiths shouldn't be hurt by flying over trees -- neil
+
+13/10/2003
+[B]- Recalling to new lost temples could have crashed the game. -- fearoffours
+[B]- God quest directions could be grammatically incorrect. -- fearoffours
+
+23/10/2003
+[B]- Items containing spells should be browsable again -- neil
+[B]- Random artifact mimicry cloaks should now show up correctly -- neil
+[B]- Random artifacts that can contain spells will not come with
+ Globe of Light anymore -- neil
+[B]- Certain non-random artifacts that can contain spells will not come with
+ Globe of Light anymore, either -- neil
+[B]- Pack overflow/weapon disappearing bug fixed, with big thanks to Kevin
+ W. Thomas for telling me where to look -- neil
+[m]- Wizard mode is now turned off at birth -- neil
+[B]- Trap of Divine Wrath would benefit you -- neil
+[B]- Blood of Life would revive necromancers in undead form -- neil
+[B]- Hostile monsters won't get free kills of friendly monsters anymore -- neil
+
+28/10/2003
+[B]- Eggs work again -- neil
+[B]- Wishing for ego rods works -- neil
+
+29/10/2003
+[B]- Temples now accept blessed boomerangs -- neil
+[O]- Non-functioning artifact instrument activations removed -- neil
+[B]- If you learn anti-magic, you stop following any Valar -- neil
+[P]- Wood Elves and Hobbits weren't getting the extra might bonuses
+ they were entitled to -- neil
+[B]- typo in v_info.txt -- fearoffours
+[m]- Help updates: macros and macro recorder, dwarf racial ability, more on
+ dodging, link to m_mimic.txt from skills.txt, object inventory letter
+ colouring significance. -- fearoffours
+[B]- Old Mage's quest wouldn't always disappear from quest screen when fully
+ rewarded. -- fearoffours
+
+30/10/2003
+[m]- Helpfiles updated to reflect that corruptions are permanent and there is
+ no corrupted sub-race. --fearoffours
+
+03/11/2003
+[B]- No more shafts in certain places -- neil
+[B]- Percing shots will not grossly inflate in damage anymore -- neil
+[B]- No genocide in home quests -- neil
+
+11/11/2003
+[B]- Silent Switching can no longer take off permanently cursed items -- neil
+[B]- Fix memory error in command handling -- neil
+[B]- Hypnotizing and restoring levelled monsters now works correctly -- neil
+[B]- permanent_levels marked experimental because it is broken -- neil
+
+17/11/2003 -- T.o.M.E 2.2.4 aka 'A Bug's Life'
+
+19/11/2003
+[B]- Fix monster possessor crash -- neil
+[B]- Fix random quest skill requester -- neil
+
+20/11/2003
+[B]- Fix crash when picking up ammo into your quiver that can't be fired
+ with the launcher you are wielding -- neil
+
+22/11/2003
+[B]- God quest fix -- neil
+
+24/11/2003
+[B]- Disintegrating walls should not bother Yavanna -- neil
+
+01/12/2003
+[B]- Yet another try at fixing levelled carried monsters. Their attacks
+ are affected by their level now and their hitpoints are handled better.
+ I should have said this for the last release, but un-hypnotize any pets
+ before upgrading from 2.2.2. Otherwise compatibility is fine. -- neil
+
+05/12/2003
+[B]- Semi-wraiths should not be hurt by climbing over mountains -- neil
+
+08/12/2003
+[B]- Fixed Flame of Udun spell
+
+10/12/2003
+[B]- Diggers are not weapons and should not be displayed as such -- neil
+[O]- Some items that give damage bonuses will be more clear about it -- neil
+[M]- Drain attacks can't drain the one artifact wand, staff, or horn -- neil
+
+[V] T.o.M.E 2.2.5 aka "Death of a Bug"
+
+23/12/2003
+[B]- Prevent recall to Lost Temple before getting the quest -- neil
+
+01/01/2004
+[I]- Pressing Escape gets you out of the pet dismissal list -- neil
+
+03/01/2004
+[B]- Automatizer now accepts TV_TOTEM -- neil
+
+08/01/2004
+[m]- Helpfiles: bearform combat help, music typos, barbarian revisions.
+ -- fearoffours
+[B]- Some vaults incorrectly named -- fearoffours
+
+15/01/2004
+[B]- Wight quest crash fix by 'amaurea' -- neil
+
+16/01/2004
+[B]- God choosen at random was broken -- masmarangio
+
+18/01/2004
+[B]- Typo in q_one.c (or -> of)
+
+20/01/2004
+[B]- Don't use a turn when cancelling a possessor action -- neil
+
+21/01/2004
+[B] - summon_true crashed the game with a summon skill < 1 -- masmarangio
+[B] - test_object_wish: aware status is saved and restored -- masmarangio
+
+27/01/2004
+[m] - Typos in the description of arrows, shots, bolts; punctuation in the
+ mushroom quest -- masmarangio
+
+30/01/2004
+[m]- HOOK_CALC_BONUS_END hooks
+
+06/02/2004
+[m]- Helpfiles: corrected starting equipment of mindcrafters -- masmarangio
+
+07/02/2004
+[m] - Backport of old helpfile updates: no Geomancy for Alchemists and Rune-
+ crafters, updated luck spoiler, corruption spoiler in crpt_aux.lua, a
+ link in skills.txt, an example in automatizer.txt.
+ monsters3.c: changed 'golem' to 'creature', since the Mind Steal Spell
+ also allows to control a monster. -- masmarangio
+
+[m]- Typo (massage -> message) from the forum -- masmarangio
+[m]- Capitalisation in the names of junkarts -- masmarangio
+
+13/02/2004
+[m]- mindcraft_info: Corrected and expanded the info for mindcraft powers
+ -- masmarangio
+[m]- Small corrections in luck spoiler, description of Manwe's Blessing and
+ m_mimic.txt -- masmarangio
+
+19/02/2004
+[B]- God quest will no longer give inaccurate or misleading directions. It
+ also will now give directions from two static features, and an
+ approximate, relative distance from each of those points.
+ -- fearoffours
+
+[V] T.o.M.E 2.2.6 "Won't Get Fooled Again"
+
+27/02/2004
+[m]- Missing space in the description of Vecna -- masmarangio
+
+12/03/2004
+[B]- Eating some corpses produced a division by 0 error -- masmarangio
+
+15/03/2004
+[B]- Wearing an item of life (-100%) reduced the mhp to 0, causing a
+ division by 0 error in cave.c -- masmarangio
+
+16/03/2004
+[B]- Corrected the spell selection for monsters:
+ defines.h: Added RF6_S_ANIMALS in RF6_SUMMON_MASK.
+ melee2.c: Updated comments in monst_spell_monst and make_attack_spell.
+ Removed the spells RF4_MULTIPLY, RF4_S_ANIMAL, RF5_SCARE from spell_attack.
+ Corrected the spell numbers of RF6_TELE_AWAY and RF6_TELE_LEVEL in
+ spell_escape (formerly RF6_DARKNESS and RF6_TRAPS were used).
+ Corrected the spell numbers of RF6_TELE_TO, RF6_DARKNESS, RF6_TRAPS,
+ RF6_FORGET in spell_annoy (formerly RF6_RAISE_DEAD, RF6_S_BUG, RF6_S_RNG
+ were used).
+ Added RF4_S_ANIMAL and RF6_S_ANIMALS and limited the spell number to
+ 160 + 31 in spell_summon. -- masmarangio
+
+18/03/2004
+[O]- The activation of an items with the ACTIVATE_NO_WIELD flag is described
+ without the line "if it is being worn. " -- masmarangio
+[B]- Barad-dur doesn't exist, it is still Mordor. Corrected god quest directions
+ to reflect this. -- fearoffours
+
+20/03/2004
+[m]- Corrected some typos (mostly from the forum, thanks to Carg85)
+ s_yavann.lua: spell 'grow grass' description: 'a grass' -> on grass
+ q_haunted.c: cave -> building
+ a_info.txt: some missing spaces in the description of artifact bolts
+ corrupt.lua, corspoil.txt: 'teeth allows' -> 'teeth allow'
+ k_info.txt: missing space (Golden Horn of the Thunderlords)
+ s_stick.lua: 'a thunderlords' -> 'a thunderlord'
+ d_info.txt: 'the the land of Rhun' -> 'the land of Rhun'
+ -- masmarangio
+
+23/03/2004
+[B]- Fixed the speed of Bearform combat -- masmarangio
+[m]- Updated luck spoiler -- masmarangio
+
+26/03/2004
+[B]- Fix for Flame Imperishable from the forum -- masmarangio
+[B]- You should now receieve a message about failing the god quest at the
+ correct moment, and not when in a random dungeon. -- fearoffours
+[m]- The Old Mage's quest will erase from your quest screen when fully rewarded.
+ -- fearoffours
+
+29/03/2004
+[B]- Further measures taken to ensure god quest relic is created appropriately.
+ -- fearoffours
+[B]- Scumming for god quests (by losing and regaining xp) is now prevented.
+ -- fearoffours
+
+02/04/2004
+[m]- Backport of mostly old helpfile updates: wrong school in m_divin.txt,
+ comments in spells.lua, deleted hint about shoes in r_hobbit.txt,
+ ability.txt, ab_info.txt: updated Ammo-creation and Far-reaching attack,
+ c_axemas.txt: starting weapon is a hatchet,
+ magic.txt, skills.txt: Updated schools improved by Spell-power,
+ corspoil.txt: Updated the info about permanent corruptions,
+ birth.txt: removed corrupted subrace, vampires are a normal subrace,
+ m_air.txt: Updated description of Noxious Cloud -- masmarangio
+
+03/04/2004
+[B]- Fixed device trapkits loaded with rods -- masmarangio
+
+05/04/2004
+[B]- Exploding ammo used in trapkits will explode after hitting a monster.
+ -- masmarangio
+[m]- Corrected Alchemist, Assassin, Axemaster, Rogue helpfiles -- masmarangio
+
+08/04/2004
+[B]- Mage staves were without the WIELD_CAST flag -- masmarangio
+
+09/04/2004
+[G]- No more nuke traps -- neil
+
+21/04/2004
+[m]- skills.txt: Corrected information about Spell-power -- masmarangio
+
+02/05/2004
+[B]- Between quest crash fix, also for Thieves and Trolls quests -- masmarangio
+
+07/05/2004
+[m]- Capitalisation: Metal Boomerang, Lay of Protection.
+ r_pettyd.txt: magic items -> magically enchanted items -- masmarangio
+
+08/05/2004
+[B]- god.lua: The relic could be created in a wrong position -- masmarangio
+
+09/05/2004
+[O]- object1.c: Added descriptions for SENS_FIRE (thanks to Scott Bigham)
+ and IMMOVABLE, removed IM_NETHER from the resistances -- masmarangio
+
+10/05/2004
+[m]- bounty.lua: Added a period -- masmarangio
+[B]- cmd7.c: Preserve the spell stored in random spellbooks --masmarangio
+[O]- Show "to damage" and "to accuracy" messages for yet more confusing items
+ -- neil
+
+11/05/2004
+[B]- xtra1.c: Lucky characters (current luck > 0) don't get death fates;
+ fixed a typo in luckspoi.txt (from the forum) -- masmarangio
+[m]- spells2.c: Typo (vulerable -> vulnerable) -- masmarangio
+
+13/05/2004
+[m]- skills.txt: Fixed broken link -- masmarangio
+[B]- generate.c: Fixed arena levels by refilling the level -- masmarangio
+
+14/05/2004
+[m]- Added new help file for the debug commands -- iain_mac
+
+26/05/2004
+[B]- Correctly cap the spell levels of wands (patch by 'Sumendar') -- neil
+
+[V] T.o.M.E 2.2.7 aka "Stoke Me A Clipper"
+
+04/06/2004
+[P]- Class no longer influences the internal Angband 'skills' of Disarming,
+ Magic Devices, Saving Throw, Stealth, Searching, Perception, Hand-to-Hand
+ combat, Missile Combat, and Throwing. ToME skills instead have the same
+ effect for all classes. -- neil
+
+05/06/2004
+[G]- Added the new Mimic shapes and updated the old ones -- masmarangio
+
+07/06/2004
+[G]- Destroying items manually now takes no time -- neil
+
+10/06/2004
+[B]- dungeon.c: Light should consume fuel at a rate of 1 / turn -- masmarangio
+
+11/06/2004
+[P]- Water Bite no longer has a damage cap -- neil
+
+12/06/2004
+[B]- A store (e.g. the mathom house) can contain up to 255 items (in defines.h
+ STORE_INVEN_MAX limited the number of items to 24) (Note: the limit is
+ stored in a byte in loadsaves.c) -- masmarangio
+
+21/06/2004
+[m]- a_info.txt: Updated names of artifacts in the comments -- masmarangio
+
+23/06/2004
+[m]- object.pkg: Added psychometry() for easier mindcraft testing.
+
+24/06/2004
+[m]- birth.txt, index.txt : Corrected and added abbreviations
+ gen_idx.lua: removed non-existent file and sorted file list
+[G]- Added the spell Sterilize and Staves of Sterilization from ToME 3.0.0.
+[D]- Added the first new special level from ToME 3.0.0, Galleon in Helcaraxe
+ -- masmarangio
+
+02/07/2004
+[D]- Added the special level Factory in the Illusory Castle -- masmarangio
+
+04/07/2004
+[G]- Added the spell Inertia Control from ToME 3.0.0 -- masmarangio
+
+05/072004
+[m]- Updated luckspoiler -- masmarangio
+
+09/07/2004
+[m]- Typo in s_fire.lua, from the wiki -- masmarangio
+[m]- rm_skeleton.txt, rm_zombie.txt: They cannot restore life force, and zombies
+ are not resistant to nether -- masmarangio
+
+19/07/2004
+[P]- Except for infravision, all innate class or racial effects on skills are
+ gone. All skills have equal effect for all classes, and races now give
+ starting skill bonuses. -- Neil
+
+22/07/2004
+[B]- s_meta.lua: Inertia controlled spells are not casted in wilderness mode.
+ s_mana.lua: Inertia level of Disruption Shield is 9 (needed spell level 45)
+ m_meta.txt: Added a list of controllable spells -- masmarangio
+
+24/07/2004
+[P]- Mages are more geared toward a mix of Magic and Combat, while Sorcerors
+ have more options than pure Sorcery -- Neil
+
+26/07/2004
+[B]- p_info.txt: Archers and Rangers gain the missing Spirituality skill
+ p_info.txt: Removed the old Mimic Cloak (new cloak in player.lua)
+[m]- Helpfile updates for all character classes. -- masmarangio
+
+30/07/2004
+[B]- p_info.txt: Thunderlords start with Stealth -16.000 (from the wiki)
+[B]- cmd7.c: Fixed Alchemy recharging bug (thanks to Scott)
+[B]- al_info.txt: Removed the old Mimic Potions -- masmarangio
+[m]- util.pkg: Added lite_spot() and note_spot() for modules -- masmarangio
+
+31/07/2004
+[B]- monspeak.txt: Added some lines for Groo to fix a bug -- masmarangio
+[B]- files.c: Corrected display of Climb flag, immunity to Nether, negative
+ pvals < -9. Added Sentient, Clone, Spider ESP flags. -- masmarangio
+
+02/08/2004
+[m]- g_melkor.txt: Added fire resistance for worshippers of Melkor
+[B]- files.c: Added flags from the gods and spell schools to the character
+ screen. Added also flags from wielded symbiotes. -- masmarangio
+
+04/08/2004
+[m]- p_info.txt: Removed the useless skill Prayer for Maiar -- masmarangio
+[B]- cmd4.c: Quest list without random quests in DL > 98 -- masmarangio
+
+19/08/2004
+[m]- help file documentation restructuring, copying appropriate rewrites from
+ wiki. -- fearoffours
+
+20/08/2004
+[B]- randart.c: An item with pval > 0 (e.g. an Elven Cloak) can gain parts
+ with a max_pval = 0 (e.g. resistances and immunities) -- masmarangio
+
+24/08/2004
+[m]- Various minor changes to helpfiles, reflecting current changes to
+ documentaiton on the wiki. --fearoffours
+
+28/08/2004
+[O]- Removed portable holes as have been useless for as long as merchants have
+ been removed from game. --fearoffours
+
+30/08/2004
+[m]- k_info.txt: Fixed name of the commented out portable holes -- masmarangio
+
+14/09/2004
+[m]- Fixed some typographical errors, mostly from the wiki:
+ cmd1.c: [The monster] fall -> falls, deleted space (Bug # 80 from the wiki)
+ k_info.txt: Added & for Climbing sets (Bug # 81 from the wiki)
+ q_one.c: You felt -> You fell (Bug # 94 from the wiki)
+ monster2.c: It tries to breed but he fails: he -> it (Bug # 98 from the wiki)
+ bldg.c: Changed wording of the soothsayer (Bug # 106 from the wiki)
+ tables.c: Minor changes in the One Ring quest (Bug # 117 from the wiki)
+ q_invas.c: jumps out of the between -> appears, deleted spaces,
+ added single quotes in direct speech (Bug # 119 from the wiki)
+ q_between.c: Deleted space, changed comments -- masmarangio
+
+20/09/2004
+[m]- book-4.txt: Capitalised 'Ring' (Bug # 135 from the wiki) -- masmarangio
+[B]- ow_info.txt: missing C: lines reduced the purse to 0 -- masmarangio
+[B]- object1.c: don't wield bolts with instruments and pebbles with boomerangs
+ (Bug # 127 from the wiki) -- masmarangio
+
+21/09/2004
+[B]- object1.c: mention_use and describe_use list all available slots, check all
+ weapon weights and distinguish between instruments and bows (Bug # 87)
+ object1.c: Res Chaos implies Res Confusion (for the character screen)
+ xtra1.c: Magical breath implies Water breath (from the wiki) -- masmarangio
+
+23/09/2004
+[B]- Z and Cth monster options removed, as in ToME 3. This fixes, among other
+ things, the Death Orb issues. -- neil
+
+24/09/2004
+[m]- options.txt: Also removed the options from the help file -- masmarangio
+[B]- a_info.txt: Corrected two typos (Bugs # 140, 146 from the wiki)
+ k_info.txt: Changed description of Bastard Sword, added RES_CHAOS to the
+ known flags of a Blade of Chaos (it's mentioned in the description)
+ files.c: Terminated highscore strings with \0, changed total_points
+ slightly to prevent an overflow error (Bug # 139 from the wiki)
+ v_info.txt: Corrected the x size of vault 99 and 104 -- masmarangio
+
+28/09/2004
+[D]- dungeon.c: Level of the Death dungeon is the minimum level from d_info.txt
+[B]- dungeon.c: Set dungeon_type to wilderness when recalling out. This should
+ fix the various Moria recalling bugs (Bug # 95)
+[m]- cmd6.c: replaced the recall activation code by recall_player -- masmarangio
+[m]- monster1.c: missing spaces in description (Bug # 169) -- masmarangio
+
+
+29/09/2004
+[m]- Modules need to define three new variables to control the chance or
+ random artifact generation. random_artifact_weapon_chance,
+ random_artifact_armor_chance, random_artifact_jewelry_chance control
+ the chance for different types of items. -- neil
+
+30/09/2004
+[B]- spells2.c: Redraw trap status after passwall (Bug # 51)
+ store.c: Removed '))' when displaying a large store -- masmarangio
+
+01/10/2004
+[m]- mods_aux.lua: Added default values for random artifact generation;
+ updated the skill values -- masmarangio
+
+02/10/2004
+[B]- al_info.txt: removed recipe for Scroll of Spell (Bug # 179), added recipe
+ for Staff of Sterilisation (Bug # 77) -- masmarangio
+[m]- cmd6.c: protect evil -> protection from evil, s_stick.lua: town -> surface
+ q_betwen.c, q_invas.c: speak -> speaks (from the forum) -- masmarangio
+
+03/10/2004
+[m]- tr_info.txt: Spelling of Lite (Bug # 182), Armor, Paralyzing -- masmarangio
+[B]- cmd6.c: Added timeout for junkarts in the activation description (ugly fix)
+ tables.c: Replaced ACT_CURE_POISON by not used ACT_CURE_POIS -- masmarangio
+[B]- Once a god quest is failed, you will not receive any more god quests.
+ -- fearoffours
+[m]- The (Ctrl-Q) Quest screen now shows which number god quest you have been given
+ and an additional line in your character dump shows how many have been
+ successfully completed. -- fearoffours
+[m]- Help updates from the wiki - lots of it Maylith's work, esp FAQ updates.
+ -- fearoffours
+
+04/10/2004
+[m]- Corrected the description of the Disarm, Call the Elements and Channel
+ Elements spells (without changing the code) (Bug # 175) -- masmarangio
+
+08/10/2004
+[B]- bldg.c: Research item (Bug # 191) and research monster are now paid
+ correctly -- masmarangio
+[B]- spells2.c: Diggers cannot be enchanted with scrolls -- masmarangio
+[m]- tome-faq.txt, index.txt: Typo (Bug # 196) -- masmarangio
+
+10/10/2004
+[m]- s_info.txt: Antimagic: generates -> generate (Bug # 198) -- masmarangio
+[B]- files.c: Fixed displayed barehanded damage (Patch from Scott, Bug # 195)
+ -- masmarangio
+
+11/10/2004
+[m]- powers.c: replaced the recall power code by recall_player
+ q_troll.c: Fixed typos from the wiki (Bug # 208) -- masmarangio
+
+12/10/2004
+[m]- tables.c: Removed harpers and some other small changes (Bug # 212)
+ cmd6.c: Added "and" in the description of ACT_ROHAN (Bug # 213)
+ -- masmarangio
+
+13/10/2004
+[m]- m_demono.txt, s_demon.lua: armor -> armour class (Bug # 217)
+[O]- k_info.txt: Changed comments and descriptions of the items, mostly from
+ the wiki (Bug # 176) and added missing descriptions (IdeaArchive)
+ Added article (&) in the name of armours (Bug # 81),
+ The spelling of some item names was changed: Scroll of Enchant Armour,
+ *Enchant Armour*, Curse Armour, Summon Monsters, Basilard
+ Added COULD2H to the Claymore and MUST2H to the Espadon.
+[m]- dun3.18: description of DimGates: fills -> fill (Bug # 223)
+ -- masmarangio
+
+15/10/2004
+[B]- files.c: Remove / restore CAVE_VIEW before / after saving the game.
+ This solves a long standing bug with the lighting of the dungeon
+ since the temporary arrays that hold the position of the viewed
+ grids are not stored in the save file (Bug # 19). -- masmarangio
+
+16/10/2004
+[m]- init1.c: The parser adds missing spaces at the end of the
+ description of artifacts, like it did for objects. -- masmarangio
+[m]- Race, class and race modifier help files updates to reflect changes
+ in skill bonuses. -- fearoffours
+
+18/10/2004
+ Some changes to random artifact and scrolls of artifact creation
+ (See Bugs # 206, 222, 226 on the wiki):
+[m]- externs.h: Moved some functions listed under spells2.c to proper sections
+[m]- k_info.txt: Added "mundane" to the description of the scroll
+[B]- cmd6.c: the selection of artifactable items can be escaped now
+ randart.c: *ID* the object before listing the powers, some re-ordering
+[B]- spells2.c: Re-add diggers to item_tester_artifactable, and limit the
+ selection to normal items due to complains (no ego items or artifacts)
+[O]- ra_info.txt: Added a STR-increasing part without combat bonuses for diggers
+[B]- ra_info.txt: Fixed two W-lines with 4 entries and added a missing C-line
+[O]- e_info.txt: Diggers cannot be of Earthquakes anymore (there are combat boni
+ involved) - perhaps an own ego type should be added... -- masmarangio
+[m]- q_ultrag.c: Quest texts changed as reported in Bug # 210 -- masmarangio
+
+23/10/2004
+[B]- k_info.txt: Reduced throwing damage of totems to 1 -- masmarangio
+
+25/10/2004
+[P]- Priests disarm as well as Warriors do now -- neil
+[B]- st_info.txt: Fixed the changed item names in the stores (StatusReport3)
+[m]- spells.lua: Sorted the Conveyance spells by level (Bug # 233)
+ -- masmarangio
+[m]- Helpfiles reflect changes to skills (priest disarming and racial
+ spirituality update). -- fearoffours
+
+01/11/2004
+[m]- library.lua: Added OBJ_FOUND_REWARD to the tome (Bug # 237) -- masmarangio
+
+13/11/2004
+[B]- Fix for disappearing artifacts (especially guardian artifacts) during load / save
+ thanks to SimonSorc
+
+17/11/2004
+[O]- No more blessed boomerangs -- neil
+
+[V] T.o.M.E 2.3.0 aka "One more try to get Mages working"
+
+10/12/2004
+[B]- Fix loading and saving of skills, I hope. Unfortunately this breaks save
+ compatiability, though. The saves must be deleted again. -- Neil
+
+29/12/2004
+[B]- Fix negative skills -- Neil
+[B]- Don't use weaponmastery combat when weaponmastery skill is negative -- Neil
+
+[V] T.o.M.E 2.3.1 aka "2.3.0.1"
+
+2005/05/19
+[I]- If easy_disarm is off, don't trigger known traps while walking normally.
+ Added a new extended command "blunder" to let players trigger traps on
+ purpose. -- gwooledge
+[I]- Lots of documentation, spelling and grammar fixes, including:
+ * the now-outdated race/class ability tables, replaced with skill tables
+ * the missing documentation for the set of extended commands
+ * far too many others to mention here
+ -- gwooledge
+
+2005/05/20
+[I]- Added sanity and speed to the character screen (and hence the text dump).
+ Consolidated HP and SP into one line to make room. -- gwooledge
+
+2005/05/21
+[B]- Don't allow trap doors on quest levels or on chests. -- gwooledge
+[I]- Allow shopping to use the correct keys in roguelike mode. -- gwooledge
+
+2005/05/22
+[B]- Update view after high-powered globe of light. -- gwooledge
+
+2005/05/26
+[I]- Push a certain potion type a little deeper into the dungeon -- Neil
+[I]- Make piety display light blue when praying, to make it easier to tell
+ when you're praying. -- gwooledge
+
+2005/06/02
+[I]- Don't display ordinary resists when there's also an immunity to the same
+ element, in an object description. -- gwooledge
+[B]- Don't allow use of stairs (any < or > movement command) while rooted
+ to the floor (by the Yavanna spell). -- gwooledge
+
+2005/06/04
+[I]- Display the (colored) character for uniques in the Known Uniques list (~2).
+ -- gwooledge
+
+2005/06/05
+[I]- Add "Check abilities" extended command/macro. This gives roguelike keyset
+ players a way to access the ability screen other than "\N", although it's
+ still one more keystroke than "\N" is.... -- gwooledge
+
+2005/06/11
+[B]- Try again to keep traps from wrecking a certain plot element -- Neil
+
+2005/06/18
+[B]- Fix module file handling for multi-user installs. Now character sheets,
+ automatizer file, and the rest will be read and written in
+ ~/.tome/2.3/modulename as they should. -- Neil
+
+2005/06/19
+[B]- Try harder to save persistent levels when recalling out -- Neil
+[B]- Fix all sub-racial skill bonuses, along with Maia racial skill bonuses
+ -- Neil
+[O]- Prevent random artifact bolts from giving extra blows -- Neil
+
+2005/06/21
+[O]- Correct the types of certain artifact trap sets to match their weights
+ and descriptions. -- gwooledge
+
+2005/07/13
+[I]- Clean up some offensive messages, patch courtesy of 'The Fury' -- Neil
+
+2005/07/14
+[I]- Include the resistances grid on character sheets dumped on death.
+ This makes them consistent with the ones generated before death, and
+ is more informative and useful for post mortem analyses. -- gwooledge
+
+2005/07/15
+[P]- Warriors no longer get a secret special three bonus blows spread over the
+ 50 character levels. The three blows are now tied to Weaponmastery.
+
+ Module authors should adjust accordingly, or their warriors may get three
+ blows they didn't have before. -- Neil
+
+2005/07/16
+[O]- Potions of Cure Insanity were too cheap. -- gwooledge
+
+2005/07/24
+[I]- Examining a totem will recall the monster it summons -- Neil
+[I]- Examining a corpse will recall the monster it was -- Neil
+
+2005/07/27
+[V] T.o.M.E 2.3.2 aka "Unrealized Reality"
+
+28/07/2005
+[G]- Lost sword quest rewards always give a minimum skill modifier of 0.3.
+ -- gwooledge
+
+29/07/2005
+[D]- Edit one vault to open up some inaccessible rooms -- Neil
+
+11/08/2005
+[B]- Alchemy: disallow repowering double-ego items, unless the character has
+ the artifact creation ability. Based on patch by Andrey Egoshin.
+ -- gwooledge
+[B]- Lost sword quest skill reward probabilities were computed incorrectly.
+ Fix suggested by Dan Rosenberry. -- gwooledge
+[I]- Miscellaneous documentation, spelling and grammar fixes. -- gwooledge
+
+12/08/2005
+[B]- Don't let a player trick the Valar by getting drained and re-gaining
+ levels -- Neil
+[I]- Update AC display after fixing armor in the buildings. -- gwooledge
+
+16/08/2005
+[B]- Don't allow Runecraft and Thaumaturgy spells to go explode inside walls
+ and seep through -- Neil
+
+17/08/2005
+[I]- Fix damage display for Thaumaturgy ball spells. -- gwooledge
+[O]- Removed pointless slays, brands, and bonuses on Pick of Erebor -- Neil
+
+19/08/2005
+[B]- When consuming magic essences, don't stop prematurely. Based on patch
+ by Andrey Egoshin. -- gwooledge
+
+30/08/2005
+[B]- Upkeep cost for partial summons was not always charged. -- gwooledge
+
+05/09/2005
+[B]- Some staves were being generated with the wrong tval, causing several bugs
+ including (but not limited to) staves being unrechargeable. -- gwooledge
+
+11/09/2005
+[B]- Saving throw was not calculated correctly. -- gwooledge
+
+14/09/2005
+[P]- All new partial summon upkeep formula -- neil
+
+26/09/2005
+[B]- Disallow negative experience alchemy abuses. Based on patch by Andrey
+ Egoshin. -- gwooledge
+[O]- When examining books, demonology equipment and instruments in stores, show
+ both the object's powers and its spells. -- gwooledge
+[B]- Nonliving and undead pets won't be angered by lack of breathable air.
+ -- gwooledge
+[D]- A certain early trap should be less deadly (and appear a bit later).
+ -- gwooledge
+[I]- Honor exp_need option when displaying object experience. -- gwooledge
+
+27/09/2005
+[I]- Restored and updated some missing help files. -- gwooledge
+[G]- (Mass) Genocide damage is applied all at once to avoid bug #228.
+ -- gwooledge
+
+28/09/2005
+[B]- Don't use the "POSIX" setuid calls on Mac OS X, as they apparently break
+ compilation -- neil
+
+29/09/2005
+[O]- Junk should stack just like skeletons. Patch by StarweaverBlue.
+ -- gwooledge
+[M]- Kavlax should be many-headed. -- gwooledge
+
+14/10/2005
+[B]- Certain monster spells were hard-coded for the wrong number of equipment
+ slots. -- gwooledge
+
+18/10/2005
+[B]- Incorrect operator used in cave generation code. Effect unknown, but it
+ *might* possibly fix some of the Orc cave crashes.-- gwooledge
+
+26/10/2005
+[M]- Regular (non-Joke, non-Cth, non-Z) monsters should not breathe nuke,
+ because it has a side effect we don't want in ToME -- Neil
+
+29/10/2005
+[O]- Mac OS X builds now put all the game data into the bundle, storing all
+ user data in the user's Library (some preferences in
+ Library/Preferences/net.t-o-m-e.tome.plist, the rest in
+ Library/Application Support/ToME. -- Neil
+
+16/11/2005
+[I]- Handling of Command key modified in Mac OS X UI. It should be accessible
+ in macros now if it wasn't before -- Neil
+
+26/11/2005
+[B]- Don't allow uniques or quest monsters to just disappear to the move of
+ another monster -- Neil
+
+14/12/2005 - ToME 2.3.3 "Realized Unreality"
+
+15/10/2006
+[B]- Remove buggy trap of Stair Movement -- Neil
+
+12/12/2005
+[B]- Fix typo in one monster's flags - Iain
+
+31/1/2005
+[I]- Fix window position saving on Mac OS, patch by John Love-Jensen
+ -- Neil
+
+19/2/2005
+[B]- Fix word wrapping in character sheet, patch from "ZizzoTheInfinite"
+ -- Neil
+
+[V] T.o.M.E 2.3.4 aka "An Unexpected Party"
diff --git a/changes.txt b/changes.txt
new file mode 100644
index 00000000..d95e9b11
--- /dev/null
+++ b/changes.txt
@@ -0,0 +1,198 @@
+T.o.M.E 2.3.10 (ah)
+
+User Interface:
+
+- Always display list of selectable objects, i.e. remove the option of
+ pressing '*' to hide list.
+- GTK2: Allow running with Shift + arrow keys. (Thanks to Lord
+ Estraven.)
+- SDL fixes. (Thanks to Lord Estraven.)
+- System-wide character scores were removed. Use the ladder at
+ http://angband.oook.cz instead.
+- Panic saves are no longer created. Saving state when memory is
+ likely corrupted seems like a bad idea.
+- Remove long-obsolete front-ends.
+- Unix: Removed pointless and error-prone signal handling aimed at
+ preventing cheating.
+- Removed gamma correction.
+
+Game:
+
+- Killerbunnies: Character dump now lists companions.
+- Killerbunnies: Fix dodge messages.
+- Imported Theme 1.2.0 since this excellent module by Furiosity seems
+ to not be downloadable any more.
+- Further Thaumaturgy tweaks by Lord Estraven
+
+Build:
+
+- Setuid support REMOVED; do NOT install ToME as setuid!
+- Fixes for system installation. Thanks to 'darwin' for reporting.
+- Fix linking problem with the 'curses' front-end.
+- Add DEBUG.txt file for information on enabling debugging in builds.
+
+
+
+T.o.M.E 2.3.9 (ah)
+
+User Interface:
+
+- Always display list of selectable objects immediately
+ instead of requiring user to press '*'.
+- Fix display issues with extremely wide terminals.
+- Automatizer: Fix memory corruption issues.
+- Remove obsolete and pointless options.
+
+Game:
+
+- Items are now immediately pseudo-identified upon pickup.
+- Psycometry now always Identifies regardless of level.
+- Remove the need to instantly leave for a certain quest. Lots
+ of players would get caught out by this.
+- A few Mindcraft powers now scale with skill level. (Credit
+ for these goes to Lord Estraven.)
+- "Far reaching attack" now works for *all* polearms.
+- Fixes and tweaks for Thaumaturgy to make view/area spells less
+ overpowered and to make bolt/ball spells more useful. (Credit
+ goes to Lord Estraven.)
+
+T.o.M.E 2.3.8 (ah)
+
+Game:
+
+- Fix duration display for the Shapeshift Mimicry power. Thanks
+ to morchant for the fix.
+- Fix for creating "inventory" and "equipment" rules from the
+ Automatizer UI. Thanks to morchant for the fix.
+- Fix for Lua code which should hopefully get things working better
+ for OpenBSD users. Thanks to Kernigh for the patch.
+- Change "molten glass wall" to use a different internal code to
+ hopefully avoid clashes with modules such as Theme.
+- Removed the check on low fuel on your light source when traveling.
+ It doesn't make sense since you can already travel without any light
+ equipped.
+
+Build System:
+
+- Added support for building the GTK2 interface; only lightly tested.
+- Added support for building on Windows with MinGW. Thanks to wino45
+ for help with this.
+- Miscellaneous fixes to the CMake files. Thanks to Kernigh for
+ contributing these.
+
+T.o.M.E 2.3.7 (ah)
+
+- Remove item pval from antimagic field strength calculation since it
+ may be both non-zero and invisible (to the player).
+- Miscellaneous 64 bit fixes.
+- Fix Lua errors when hitting <ESC> while choosing spell.
+- Killerbunnies: Automatizer: Add patch which adds new <inventory/>
+ and <equipment/> rules.
+- Killerbunnies: Add "you do not know all your fate" to Fate menu
+ if you haven't been discovered all your fates.
+- Killerbunnies: Display a message if trying to activate Piercing Shots
+ without the necessary skill levels.
+
+T.o.M.E 2.3.6 (ah)
+
+- Don't generate impassable glass walls.
+- Mark *all* quest monsters properly.
+- Avoid generating up staircases in selected dungeons.
+- Mimicry cloaks of Abomination now aggravate properly.
+- Properly handle item set effects with certain traps.
+- Fix crash bug during character dumps.
+- Misc. Mimicry fixes.
+- Prevent immunities from Balrog Form persisting too long.
+- Fix for loading/saving on Linux distribution using Fortify.
+- Fix for module directory paths.
+- Fix miscellaneous problems on 64-bit platforms.
+- Princess room should now always be generated.
+- Extra Blows applies to barehand combat too.
+
+
+
+
+
+
+T.o.M.E 2.3.5 aka "Into the unknown" changes
+
+Interface changes:
+- The X11 and Xaw interfaces now save the dungeon and player when the
+ window is closed.
+- Fixed cpu churning bug that occurs when using certain window managers and
+ ToME is maximized.
+
+Gameplay changes:
+- Player speed now set correctly when Demon Hide corruption is enabled.
+- ToME now correctly sets various Balrog flags when player in Balrog form.
+- ToME now correctly sets the teleport flags when teleport corruption is
+ enabled.
+- ToME now uses the qrand7.map file when generating princess quests.
+- Bigs changes for generate.c to get it to produce the princess and thrain
+ rooms. Also code clean up of room geranation code.
+
+Object changes:
+- Slings of Buckland can now be generated.
+- Wiki Bug 510. Added the WIELD_CAST flag to all artifact instruments to
+ fix problems when casting spells.
+
+Misc changes:
+- Fixed small typo in the commands help file.
+- Added help for the Mathom House.
+- Fixed various compile time warnings in various files.
+- Added makefile support for main-gtk2.c in makefile.std
+- Values found in documentation for spectral race modifiers now match values
+ found in p_info.txt.
+- Wiki Bug 837. Removed references to old inscriptions handling code in
+ documentation.
+- Wiki Bug 564. Do not use the word 'restrict' as a variable name anymore.
+ It conflicts with keywords used by the Sun Studio Compiler.
+- Wiki Bug 517. Fixed incorrect descriptoin of artifacts in help files.
+- Changed description of Disarm spell to more accurately reflect what it
+ does.
+- ToME now correctly compiles main-gtk2.c on 64-bit machines.
+
+Bug fixes:
+- Wiki Bugs 841, 405, 360. Changes to get ToME to correctly build 64-bit
+ executables.
+- Applied killerbunnies patch to identify objects on grid before squelching.
+- Applied killer bunnies patch to keep the fate "you are fated to find
+ something special" from creating something special with an inappropriate
+ base object.
+- Applied killerbunnies patch stops symbiotes from gaining levels simply
+ by being hypnotized and released.
+- ToME now saves tim_fly, tim_poison, tim_regen and tim_regen_power.
+- Stores now display the inventory correctly after a purchase.
+- The race the legends display now works correctly with more than 10 dead
+ characters in history.
+- Characters are no longer generated with 0 mana points.
+- Wiki Bug 839. ToME no longer penalizes an object when it is not actually
+ cursed.
+- Wiki Bug 838. The melee style will now switch correctly from Bear to the
+ primary melee style when switching out of Bear form.
+- Wiki Bug 826. The inventory and equipment windows now update when the
+ player identifies the entire pack or uses the *Greater Identify* spell.
+- Wiki Bug 819. No more bogus level leaving messages.
+- Wiki Bug 722. ToME no longer crashes purple staircases have been trapped.
+- Wiki Bug 624. Ensure savefiles go to save and not scpt when using modules.
+- Wiki Bug 537. Partial fix of infinite loop during stair allocation on
+ small levels.
+- Wiki Bug 530. ToME no longer drops items inappropriately when changing
+ melee styles.
+- Wiki Bug 528. Character dumps now show the correct number of princess and
+ lost sword quests.
+- Wiki Bug 526. ToME no longer enters an infinite loop when fighting in
+ bare-hand combat sylte and bare-hand skill is < 1.
+- Wiki Bug 523. All types of recall check if the user really wants to leave
+ a unique level.
+- Wiki Bug 506. ToME no longer crashes attempting to drop non-existant
+ artifacts.
+- Wiki Bug 419. Use SKILL_BOULDER instead of SKILL_ARCHERY when throwing
+ a boulder.
+- Wiki Bug 411. Black breath no longer gets 3 chances to happen.
+- Wiki Bug 394 and 393. Inertia Control autocasting can no longer cast a
+ spell when antimagic field > 0 or when wielding a dark sword.
+- Wiki Bug 334. Companions are no longer saved in dungone save files.
+- Work around Mac OS 10.4.11 getlogin() bug - Neil
+- Wiki Bug 397. ToME no longer crashes on XP and Vista systems when viewing
+ quests or other info from the knowledge menu.
diff --git a/credits.txt b/credits.txt
new file mode 100644
index 00000000..96e8ef60
--- /dev/null
+++ b/credits.txt
@@ -0,0 +1,67 @@
+Credit list(lots are still not present here, if you think you should
+drop me a line please) in no particular order:
+
+- Chris Weisiger <chrisweisiger@hotmail.com>, lots and lots of stuff,
+ and mainly lots of vaults, a whole magic realm, some special levels,
+ TANG
+- Ceilti <Ceilti@aol.com>, idea of weapons gaining xp, comments, ideas,
+ lots of PernAngband related posts on rgra
+- Static Chaos <schaos@freemail.hu>, huge numbers of patches, ideas, ...
+- Improv <qc@apk.net>, spelling/grammar fixes, ideas, safer_panics patch,
+ some new monster and artifact descriptions, cmovie stuff, and lots
+ of things
+- Mynstral, new towns and more
+- Kusunose Toru <kusunose@hcn.zaq.ne.jp> for LOTS of bugfixes
+- Akhronath for the ideas of the magic system, new realms and much more
+ oh yeah the Nazguls :)
+- Jerome Wojcik <Jerome.Wojcik@lmcp.jussieu.fr> for monster susceptibilities
+- Andreas Koch(akoch@rbg.informatik.tu-darmstadt.de) for the tiles, the
+ graphic editor and surely more :)
+- Gob for the mac ports and a nasty bug fix
+- Iain McFall for bug fixes, auto squelch and more
+- Bablos for the amiga port
+- Arch for the windows port
+- Dawnmist for the new docs
+- Jonathan Ellis for the rework of the info files
+- Hansjoerg Malthaner for the Isometric engine
+- Pelpel for bugfixes and other mac things
+- Tom Le for the website hosting
+- Willam Tanksley for lots of useful comments, ideas and bitching ;)
+- Tom Demuyt for the unbeliever idea
+- Luc French for lots of ideas & code
+- Kieron for some patches
+- Runescrye for ra_info.txt and surely more :)
+- Fearof4s for lua patches, lua tutorial, quests and stuff.
+- Pav Lucistnik for some patches and hosting the CVS
+- Mef for the huge task of updating class and magic help documents for 2.x
+ and lots and lots of other help updates!
+- Erik J Brown for some changes to help docs.
+- vrak (Per-Arne Holtmon Akoe) for magic.txt
+- Kat B for other help updates.
+- Chris Hadgis for Luck spoiler, lua *.pkg help docs, and other help docs.
+- lemming for skills.txt and stuff
+- Paladin Rithe (Brian Ronk) for birth.txt
+- John Gilmore for alchemy improvements patch
+- Massimiliano Marangio for lots and lots of help updates, typo corrections,
+ bug fixes etc.
+- Neil Stevens <neil@hakubi.us> for making stable releases
+- Jeff Epler for automatizer improvements, and certainly more in the future ;)
+- Scott Bigham for some cool patches
+- Magua(magua@speakeasy.net) who wrote the java applet to play cmovies online
+- Maylith for lots of help with the documentation, especially on the wiki
+- Furiosity for some missing item descriptions
+- SimonSorc for bugfixes
+- Greg Wooledge <greg@wooledge.org> for still more bug fixes
+- Phillip Neiswanger for tons of bug fixes and mainly 2.3.5 and possibly 2.4.0
+
+- All that I forgot in the list, hit me a bit then email me to get added
+
+- All the friendly people of the ToME mailing list
+- All the friendly people of #angband
+
+- TeCGraf for the Lua scripting language(www.lua.org)
+- Reuben Thomas for the lua bitlib
+- Waldemar Celes for tolua(automatic wrapper generator for lua, like swig, but
+ this one actually works :)
+
+- J.R.R. Tolkien for the best fantasy ever !
diff --git a/debian/NEWS.Debian b/debian/NEWS.Debian
new file mode 100644
index 00000000..756269a0
--- /dev/null
+++ b/debian/NEWS.Debian
@@ -0,0 +1,111 @@
+tome (2.3.11-ah-2) unstable; urgency=low
+
+ T.o.M.E 2.3.10 (ah)
+
+ User Interface:
+
+ - Always display list of selectable objects, i.e. remove the option of
+ pressing '*' to hide list.
+ - GTK2: Allow running with Shift + arrow keys. (Thanks to Lord
+ Estraven.)
+ - SDL fixes. (Thanks to Lord Estraven.)
+ - System-wide character scores were removed. Use the ladder at
+ http://angband.oook.cz instead.
+ - Panic saves are no longer created. Saving state when memory is
+ likely corrupted seems like a bad idea.
+ - Remove long-obsolete front-ends.
+ - Unix: Removed pointless and error-prone signal handling aimed at
+ preventing cheating.
+ - Removed gamma correction.
+
+ Game:
+
+ - Killerbunnies: Character dump now lists companions.
+ - Killerbunnies: Fix dodge messages.
+ - Imported Theme 1.2.0 since this excellent module by Furiosity seems
+ to not be downloadable any more.
+ - Further Thaumaturgy tweaks by Lord Estraven
+
+ T.o.M.E 2.3.9 (ah)
+
+ User Interface:
+
+ - Always display list of selectable objects immediately
+ instead of requiring user to press '*'.
+ - Fix display issues with extremely wide terminals.
+ - Automatizer: Fix memory corruption issues.
+ - Remove obsolete and pointless options.
+
+ Game:
+
+ - Items are now immediately pseudo-identified upon pickup.
+ - Psycometry now always Identifies regardless of level.
+ - Remove the need to instantly leave for a certain quest. Lots
+ of players would get caught out by this.
+ - A few Mindcraft powers now scale with skill level. (Credit
+ for these goes to Lord Estraven.)
+ - "Far reaching attack" now works for *all* polearms.
+ - Fixes and tweaks for Thaumaturgy to make view/area spells less
+ overpowered and to make bolt/ball spells more useful. (Credit
+ goes to Lord Estraven.)
+
+ T.o.M.E 2.3.8 (ah)
+
+ Game:
+
+ - Fix duration display for the Shapeshift Mimicry power. Thanks
+ to morchant for the fix.
+ - Fix for creating "inventory" and "equipment" rules from the
+ Automatizer UI. Thanks to morchant for the fix.
+ - Fix for Lua code which should hopefully get things working better
+ for OpenBSD users. Thanks to Kernigh for the patch.
+ - Change "molten glass wall" to use a different internal code to
+ hopefully avoid clashes with modules such as Theme.
+ - Removed the check on low fuel on your light source when traveling.
+ It doesn't make sense since you can already travel without any light
+ equipped.
+
+ T.o.M.E 2.3.7 (ah)
+
+ - Remove item pval from antimagic field strength calculation since it
+ may be both non-zero and invisible (to the player).
+ - Miscellaneous 64 bit fixes.
+ - Fix Lua errors when hitting <ESC> while choosing spell.
+ - Killerbunnies: Automatizer: Add patch which adds new <inventory/>
+ and <equipment/> rules.
+ - Killerbunnies: Add "you do not know all your fate" to Fate menu
+ if you haven't been discovered all your fates.
+ - Killerbunnies: Display a message if trying to activate Piercing Shots
+ without the necessary skill levels.
+
+ T.o.M.E 2.3.6 (ah)
+
+ - Don't generate impassable glass walls.
+ - Mark *all* quest monsters properly.
+ - Avoid generating up staircases in selected dungeons.
+ - Mimicry cloaks of Abomination now aggravate properly.
+ - Properly handle item set effects with certain traps.
+ - Fix crash bug during character dumps.
+ - Misc. Mimicry fixes.
+ - Prevent immunities from Balrog Form persisting too long.
+ - Fix for loading/saving on Linux distribution using Fortify.
+ - Fix for module directory paths.
+ - Fix miscellaneous problems on 64-bit platforms.
+ - Princess room should now always be generated.
+ - Extra Blows applies to barehand combat too.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 14 May 2014 23:56:28 -0700
+
+tome (2.3.1-1) unstable; urgency=low
+
+ * Yet again, the save file format has changed incompatibly, requiring
+ that a new character be created from scratch.
+
+ -- Manoj Srivastava <srivasta@debian.org> Sun, 23 Jan 2005 10:57:26 -0600
+
+tome (2.3.0-1) unstable; urgency=low
+
+ * This version changed the save format, so older save files can not be
+ read by this version.
+
+ -- Manoj Srivastava <srivasta@debian.org> Sun, 23 Jan 2005 10:56:42 -0600
diff --git a/debian/README.debian b/debian/README.debian
new file mode 100644
index 00000000..a406ad64
--- /dev/null
+++ b/debian/README.debian
@@ -0,0 +1,12 @@
+This is the Debian GNU/Linux prepackaged version of the rogue-like game
+"Troubles on Middle Earth" (tome). Tome has been derived from Angband,
+which itself has been written by several generations of
+programmers over the years, and is derived from an earlier game called
+moria.
+
+This package was put together by Manoj Srivastava <srivasta@debian.org>,
+from sources retrieved from directories under
+<URL:ftp://clockwork.dementia.org/angband/Variant/ToME/>
+
+arch-tag: f25f6a43-5a92-4b97-8ecf-0439ecacd45e
+
diff --git a/debian/Tome.sh b/debian/Tome.sh
new file mode 100755
index 00000000..1db52c3d
--- /dev/null
+++ b/debian/Tome.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+# -*- Mode: Sh -*-
+# Tome.sh ---
+# Author : Manoj Srivastava ( srivasta@glaurung.green-gryphon.com )
+# Created On : Fri Aug 1 22:01:26 2003
+# Created On Node : glaurung.green-gryphon.com
+# Last Modified By : Manoj Srivastava
+# Last Modified On : Mon Nov 24 22:21:23 2003
+# Last Machine Used: glaurung.green-gryphon.com
+# Update Count : 2
+# Status : Unknown, Use with caution!
+# HISTORY :
+# Description :
+#
+# arch-tag: e93eb0c0-615f-490e-a30b-3b3c78d8bd91
+#
+
+# Describe attempt
+echo "Launching ToME..."
+sleep 2
+
+# Main window
+export ANGBAND_X11_FONT_0=9X15
+export ANGBAND_X11_AT_X_0=5
+export ANGBAND_X11_AT_Y_0=510
+
+# Message window
+export ANGBAND_X11_FONT_1=7x13
+export ANGBAND_X11_AT_X_1=5
+export ANGBAND_X11_AT_Y_1=22
+export ANGBAND_X11_ROWS_1=18
+
+# Inventory window
+export ANGBAND_X11_FONT_2=7x13
+export ANGBAND_X11_AT_X_2=635
+export ANGBAND_X11_AT_Y_2=182
+export ANGBAND_X11_ROWS_3=23
+
+# Equipment window
+export ANGBAND_X11_FONT_3=7x13
+export ANGBAND_X11_AT_X_3=635
+export ANGBAND_X11_AT_Y_3=22
+export ANGBAND_X11_ROWS_3=13
+
+# Monster recall window
+export ANGBAND_X11_FONT_4=6x9
+export ANGBAND_X11_AT_X_4=817
+export ANGBAND_X11_AT_Y_4=847
+export ANGBAND_X11_COLS_4=76
+export ANGBAND_X11_ROWS_4=11
+
+# Object recall window
+export ANGBAND_X11_FONT_5=6x9
+export ANGBAND_X11_AT_X_5=817
+export ANGBAND_X11_AT_Y_5=520
+export ANGBAND_X11_COLS_5=76
+export ANGBAND_X11_ROWS_5=15
+
+export ANGBAND_X11_FONT_6=6x9
+export ANGBAND_X11_FONT_7=6x9
+# Gamma correction
+export ANGBAND_X11_GAMMA=142
+
+# Launch Angband
+# Adam bolt
+tome -mxaw -- -s -n7 &
+#angband -mxaw -- -n7 &
+#angband -mx11 -- -n7 &
+#angband -mxpj -- -n7 &
+
diff --git a/debian/Xresources b/debian/Xresources
new file mode 100644
index 00000000..aad56304
--- /dev/null
+++ b/debian/Xresources
@@ -0,0 +1,166 @@
+
+ X Resources for ToME
+ = ========= === ====
+
+
+>I want to control the angband windows better, like give them automatic
+>placement on the screen, resize (the recall window is too large) and smaller
+>fonts.
+
+After you've built it, you have to configure your ~/.Xdefaults file to
+take advantage of the new functionality.
+
+My own X Resources look like this (on a 1152x900 screen):
+
+angband*angband*font: 12x24
+angband*angband*geometry: +0+-20
+angband*recall*font: 7x13
+angband*recall*geometry: 80x10+0+586
+angband*choice*font: 7x13
+angband*choice*geometry: -0-0
+
+For a smaller screen size, these are probably better
+
+angband*angband*font: 9x15
+angband*angband*geometry: +300+220
+angband*recall*font: 7x13
+angband*recall*geometry: 80x15+460+0
+angband*choice*font: 7x13
+angband*choice*geometry: +0+440
+angband*mirror*font: 7x13
+angband*mirror*geometry: 80x15+460+590
+angband*color6: #3070f0
+angband*color7: #907027
+angband*term-4*iconic: true
+angband*term-5*iconic: true
+angband*term-6*iconic: true
+angband*term-7*iconic: true
+
+You could also try modifying these:
+
+Angband*term-4.font (or geometry)
+Angband*term-5.font (or geometry)
+Angband*term-6.font (or geometry)
+Angband*term-7.font (or geometry)
+
+You'll almost certainly want to change the numbers to suit your taste,
+screen size, resolution, monitor darkness, etc. This just gives you an
+idea of the format.
+
+It's also possible to change the colors using X Resources, the
+standard colors would look like:
+
+angband*color0: #000000
+angband*color1: #ffffff
+angband*color2: #a6a6a6
+angband*color3: #ff6302
+angband*color4: #ca0808
+angband*color5: #008e18
+angband*color6: #0000e3
+angband*color7: #814007
+angband*color8: #6b6b6b
+angband*color9: #d6d6d6
+angband*color10: #5100c2
+angband*color11: #fdf105
+angband*color12: #ff9259
+angband*color13: #26cf17
+angband*color14: #02b2f2
+angband*color15: #b28b48
+
+And the newer colors look like:
+
+angband*color0: #000000
+angband*color1: #ffffff
+angband*color2: #d7d7d7
+angband*color3: #ff9200
+angband*color4: #ff0000
+angband*color5: #00cd00
+angband*color6: #0000fe
+angband*color7: #c86400
+angband*color8: #a3a3a3
+angband*color9: #ebebeb
+angband*color10: #a500ff
+angband*color11: #fffd00
+angband*color12: #ff00bc
+angband*color13: #00ff00
+angband*color14: #00c8ff
+angband*color15: #ffcc80
+
+Some older monochrome monitors have problem with white text on black
+background. The new code can handle the reverse situation if the user
+wants/needs this.
+
+The following X Resources gives black text on white background using
+Angband/Xaw. The other colors (2-15) isn't changed, since they're not
+used on a monochrome monitor.
+
+angband*color0: #ffffff
+angband*color1: #000000
+
+______________________________________________________________________
+Yet another example:
+angband*angband*font: 9x15
+angband*angband*geometry: +300+220
+
+angband*choice*font: 7x13
+angband*choice*geometry: +0+440
+
+angband*mirror*font: 7x13
+angband*mirror*geometry: 80x15+460+590
+
+angband*recall*font: 7x13
+angband*recall*geometry: 80x15+460+0
+
+angband*term-1*font: 7x13
+angband*term-1*geometry: 80x15+460+0
+
+angband*term-2*font: 7x13
+angband*term-2*geometry: +0+440
+
+angband*term-3*font: 7x13
+angband*term-3*geometry: 80x15+460+590
+
+angband*term-4*iconic: true
+angband*term-5*iconic: true
+angband*term-6*iconic: true
+angband*term-7*iconic: true
+
+angband*color0: #000000
+angband*color1: #ffffff
+angband*color2: #a6a6a6
+angband*color3: #ff6302
+angband*color4: #ca0808
+angband*color5: #008e18
+angband*color6: #0000e3
+angband*color7: #814007
+angband*color8: #6b6b6b
+angband*color9: #d6d6d6
+angband*color10: #5100c2
+angband*color11: #fdf105
+angband*color12: #ff9259
+angband*color13: #26cf17
+angband*color14: #02b2f2
+angband*color15: #b28b48
+______________________________________________________________________
+
+ Resources:
+
+Name Class RepType Default Value
+---- ----- ------- -------------
+background Background Pixel XtDefaultBackground
+border BorderColor Pixel XtDefaultForeground
+borderWidth BorderWidth Dimension 1
+cursor Cursor Cursor None
+cursorName Cursor String NULL
+destroyCallback Callback Pointer NULL
+height Height Dimension 0
+insensitiveBorder Insensitive Pixmap Gray
+mappedWhenManaged MappedWhenManaged Boolean True
+pointerColor Foreground Pixel XtDefaultForeground
+pointerColorBackground Background Pixel XtDefaultBackground
+sensitive Sensitive Boolean True
+width Width Dimension 0
+x Position Position 0
+y Position Position 0
+
+!arch-tag: 2d36068f-a924-402b-a411-cd91be556609
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 00000000..22735270
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,735 @@
+tome (2.3.11-ah-2) unstable; urgency=low
+
+ * Modified the install paths to deploy to the FHS compliant
+ /usr/games/tome and /var/games/tome, as we have always done
+ * This is a major change, and includes theming. Some of the options have
+ changed. Because of this, the manual page has been removed; there is a
+ command line help option and in game help until the manual page is
+ rewritten.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 14 May 2014 23:54:09 -0700
+
+tome (2.3.11-ah-1) unstable; urgency=low
+
+ * New upstream release, with minor bug fixes.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 14 May 2014 20:40:47 -0700
+
+tome (2.3.10-ah-1) unstable; urgency=low
+
+ * New upstream release
+ User Interface:
+ - Always display list of selectable objects, i.e. remove the option of
+ pressing '*' to hide list.
+ - GTK2: Allow running with Shift + arrow keys. (Thanks to Lord
+ Estraven.)
+ - SDL fixes. (Thanks to Lord Estraven.)
+ - System-wide character scores were removed. Use the ladder at
+ http://angband.oook.cz instead.
+ - Panic saves are no longer created. Saving state when memory is
+ likely corrupted seems like a bad idea.
+ - Remove long-obsolete front-ends.
+ - Unix: Removed pointless and error-prone signal handling aimed at
+ preventing cheating.
+ - Removed gamma correction.
+ Game:
+ - Killerbunnies: Character dump now lists companions.
+ - Killerbunnies: Fix dodge messages.
+ - Imported Theme 1.2.0 since this excellent module by Furiosity seems
+ to not be downloadable any more.
+ - Further Thaumaturgy tweaks by Lord Estraven
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 14 May 2014 20:29:54 -0700
+
+tome (2.3.9-ah-1) unstable; urgency=low
+
+ * New upstream release
+ User Interface:
+ - Always display list of selectable objects immediately
+ instead of requiring user to press '*'.
+ - Fix display issues with extremely wide terminals.
+ - Automatizer: Fix memory corruption issues.
+ - Remove obsolete and pointless options.
+ Game:
+ - Items are now immediately pseudo-identified upon pickup.
+ - Psycometry now always Identifies regardless of level.
+ - Remove the need to instantly leave for a certain quest. Lots
+ of players would get caught out by this.
+ - A few Mindcraft powers now scale with skill level. (Credit
+ for these goes to Lord Estraven.)
+ - "Far reaching attack" now works for *all* polearms.
+ - Fixes and tweaks for Thaumaturgy to make view/area spells less
+ overpowered and to make bolt/ball spells more useful. (Credit
+ goes to Lord Estraven.)
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 14 May 2014 20:29:27 -0700
+
+tome (2.3.8-ah-1) unstable; urgency=low
+
+ * New upstream release
+ Game:
+ - Fix duration display for the Shapeshift Mimicry power. Thanks
+ to morchant for the fix.
+ - Fix for creating "inventory" and "equipment" rules from the
+ Automatizer UI. Thanks to morchant for the fix.
+ - Fix for Lua code which should hopefully get things working better
+ for OpenBSD users. Thanks to Kernigh for the patch.
+ - Change "molten glass wall" to use a different internal code to
+ hopefully avoid clashes with modules such as Theme.
+ - Removed the check on low fuel on your light source when traveling.
+ It doesn't make sense since you can already travel without any light
+ equipped.
+ Build System:
+ - Added support for building the GTK2 interface; only lightly tested.
+ - Miscellaneous fixes to the CMake files. Thanks to Kernigh for
+ contributing these.
+ * Now that we are using cmake, undo changes we made to Makefile.std
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 14 May 2014 19:38:32 -0700
+
+tome (2.3.7-ah-1) unstable; urgency=low
+
+ * New upstream maintenance release
+ - Remove item pval from antimagic field strength calculation since it
+ may be both non-zero and invisible (to the player).
+ - Miscellaneous 64 bit fixes.
+ - Fix Lua errors when hitting <ESC> while choosing spell.
+ - Killerbunnies: Automatizer: Add patch which adds new <inventory/>
+ and <equipment/> rules.
+ - Killerbunnies: Add "you do not know all your fate" to Fate menu
+ if you haven't been discovered all your fates.
+ - Killerbunnies: Display a message if trying to activate Piercing Shots
+ without the necessary skill levels.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 14 May 2014 14:43:34 -0700
+
+tome (2.3.6-ah-1) unstable; urgency=medium
+
+ * Upstream development of version 2 has moved into maintenance mode,
+ with a new upstream git repository at:
+ git://gitorious.org/tome2/tome2.git
+ - Don't generate impassable glass walls.
+ - Mark *all* quest monsters properly.
+ - Avoid generating up staircases in selected dungeons.
+ - Mimicry cloaks of Abomination now aggravate properly.
+ - Properly handle item set effects with certain traps.
+ - Fix crash bug during character dumps.
+ - Misc. Mimicry fixes.
+ - Prevent immunities from Balrog Form persisting too long.
+ - Fix for loading/saving on Linux distribution using Fortify.
+ - Fix for module directory paths.
+ - Fix miscellaneous problems on 64-bit platforms.
+ - Princess room should now always be generated.
+ - Extra Blows applies to barehand combat too.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 14 May 2014 13:49:42 -0700
+
+tome (2.3.5-4) unstable; urgency=low
+
+ * On purge, get rid of /var/games/tome directory (and all the score
+ files) (Closes: #663525).
+ * Bug fix #663525: "unowned files after purge (policy 6.8, 10.8)", thanks to
+ Andreas Beckmann
+
+ -- Manoj Srivastava <srivasta@debian.org> Mon, 05 May 2014 10:49:34 -0700
+
+tome (2.3.5-3) unstable; urgency=low
+
+ * New bug fixing release.
+ * Bug fix: "FTBFS due to binutils-gold", thanks to Bhavani Shankar
+ R. Added -lm toi the linker line. (Closes: #607552).
+ * Bug fix: "depends on obsolete libmikmod2 on powerpc", thanks to Julien
+ Cristau. This is not a direct dependency, so rebuilding should fix it.
+ (Closes: #742598).
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 30 Apr 2014 21:50:57 -0700
+
+tome (2.3.5-2) unstable; urgency=low
+
+ * [f4042dd] Fix code which needed a 32 bit int to not use int/long
+ On amd64, but not on i386, tome produces LUA errors at various
+ times. The errors occur at savefile load, when wileding a weapon,
+ unweilding a weapon, and for other events. The same homedir, same
+ savefiles, same config, same etc., does not produce errors in the
+ 32bit build of the package.
+
+ The error seems to be that the type Number needs to be a 32bit wide
+ integer; and seems to be defined by default as an long, with an option
+ to define it as an int for amd64. However, for the 11 arches Debian
+ supports, this would lead to a morass of selecting architectures in
+ the makefile to override the type; a better solution is to use
+ stdint.h and use a type which is 32 bits wide by design: int32_t.
+
+ Bug fix: "frequent LUA errors on amd64, possibly influencing game
+ logic", thanks to jrodman@debbugs.spamportal.net</a>; The fix was
+ inspired by a different fix proposed by Daniel White.
+
+ This fixes the LUA errors, and (Closes: Bug#419825)
+ This is an important bug fix.
+
+ -- Manoj Srivastava <srivasta@debian.org> Tue, 21 Oct 2008 08:36:01 -0500
+
+tome (2.3.5-1) unstable; urgency=low
+
+ * New upstream release
+ Interface changes:
+ - The X11 and Xaw interfaces now save the dungeon and player when the
+ window is closed.
+ - Fixed cpu churning bug that occurs when using certain window managers and
+ ToME is maximized.
+ Gameplay changes:
+ - Player speed now set correctly when Demon Hide corruption is enabled.
+ - ToME now correctly sets various Balrog flags when player in Balrog form.
+ - ToME now correctly sets the teleport flags when teleport corruption is
+ enabled.
+ - ToME now uses the qrand7.map file when generating princess quests.
+ - Bigs changes for generate.c to get it to produce the princess and thrain
+ rooms. Also code clean up of room geranation code.
+ Object changes:
+ - Slings of Buckland can now be generated.
+ - Wiki Bug 510. Added the WIELD_CAST flag to all artifact instruments to
+ fix problems when casting spells.
+ Misc changes:
+ - Fixed small typo in the commands help file.
+ - Added help for the Mathom House.
+ - Fixed various compile time warnings in various files.
+ - Added makefile support for main-gtk2.c in makefile.std
+ - Values found in documentation for spectral race modifiers now match values
+ found in p_info.txt.
+ - Wiki Bug 837. Removed references to old inscriptions handling code in
+ documentation.
+ - Wiki Bug 564. Do not use the word 'restrict' as a variable name anymore.
+ It conflicts with keywords used by the Sun Studio Compiler.
+ - Wiki Bug 517. Fixed incorrect descriptoin of artifacts in help files.
+ - Changed description of Disarm spell to more accurately reflect what it
+ does.
+ - ToME now correctly compiles main-gtk2.c on 64-bit machines.
+ Bug fixes:
+ - Wiki Bugs 841, 405, 360. Changes to get ToME to correctly build 64-bit
+ executables.
+ - Applied killerbunnies patch to identify objects on grid before squelching.
+ - Applied killer bunnies patch to keep the fate "you are fated to find
+ something special" from creating something special with an inappropriate
+ base object.
+ - Applied killerbunnies patch stops symbiotes from gaining levels simply
+ by being hypnotized and released.
+ - ToME now saves tim_fly, tim_poison, tim_regen and tim_regen_power.
+ - Stores now display the inventory correctly after a purchase.
+ - The race the legends display now works correctly with more than 10 dead
+ characters in history.
+ - Characters are no longer generated with 0 mana points.
+ - Wiki Bug 839. ToME no longer penalizes an object when it is not actually
+ cursed.
+ - Wiki Bug 838. The melee style will now switch correctly from Bear to the
+ primary melee style when switching out of Bear form.
+ - Wiki Bug 826. The inventory and equipment windows now update when the
+ player identifies the entire pack or uses the *Greater Identify* spell.
+ - Wiki Bug 819. No more bogus level leaving messages.
+ - Wiki Bug 722. ToME no longer crashes purple staircases have been trapped.
+ - Wiki Bug 624. Ensure savefiles go to save and not scpt when using modules.
+ - Wiki Bug 537. Partial fix of infinite loop during stair allocation on
+ small levels.
+ - Wiki Bug 530. ToME no longer drops items inappropriately when changing
+ melee styles.
+ - Wiki Bug 528. Character dumps now show the correct number of princess and
+ lost sword quests.
+ - Wiki Bug 526. ToME no longer enters an infinite loop when fighting in
+ bare-hand combat sylte and bare-hand skill is < 1.
+ - Wiki Bug 523. All types of recall check if the user really wants to leave
+ a unique level.
+ - Wiki Bug 506. ToME no longer crashes attempting to drop non-existant
+ artifacts.
+ - Wiki Bug 419. Use SKILL_BOULDER instead of SKILL_ARCHERY when throwing
+ a boulder.
+ - Wiki Bug 411. Black breath no longer gets 3 chances to happen.
+ - Wiki Bug 394 and 393. Inertia Control autocasting can no longer cast a
+ spell when antimagic field > 0 or when wielding a dark sword.
+ - Wiki Bug 334. Companions are no longer saved in dungone save files.
+ - Work around Mac OS 10.4.11 getlogin() bug - Neil
+ - Wiki Bug 397. ToME no longer crashes on XP and Vista systems when viewing
+ quests or other info from the knowledge menu.
+ * Change the control file to reflect the repo change to git.
+ * Update the build depends to reflect the fact that we now also compile
+ the SDL version, which is the preferred back end.
+
+ -- Manoj Srivastava <srivasta@debian.org> Tue, 27 May 2008 17:35:12 -0500
+
+tome (2.3.4-2) unstable; urgency=low
+
+ * Added patch to allow saving games when playing optional modules. Patch
+ from Bob Vincent Closes: #428910
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 08 Feb 2008 00:38:49 -0600
+
+tome (2.3.4-1) unstable; urgency=low
+
+ * New upstream release
+ Interface changes:
+ - Fix window position saving on Mac OS, patch by John Love-Jensen
+ -- Neil
+ Bug fixes:
+ - Remove buggy trap of Stair Movement -- Neil
+ - Fix typo in one monster's flags - Iain
+ - Fix word wrapping in character sheet, patch from "ZizzoTheInfinite"
+ -- Neil
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 27 Oct 2006 09:58:27 -0500
+
+tome (2.3.3-3) unstable; urgency=low
+
+ * Updated copyright file.
+ * remove obsolete libxaw8-dev dependency
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 16 Jun 2006 08:49:48 -0500
+
+tome (2.3.3-2) unstable; urgency=low
+
+ * Updated build dependencies.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 8 Feb 2006 10:45:14 -0600
+
+tome (2.3.3-1) unstable; urgency=low
+
+ * New upstream release
+ Interface changes:
+ - Miscellaneous documentation, spelling and grammar fixes. -- gwooledge
+ - Update AC display after fixing armor in the buildings. -- gwooledge
+ - Fix damage display for Thaumaturgy ball spells. -- gwooledge
+ - Honor exp_need option when displaying object experience. -- gwooledge
+ - Restored and updated some missing help files. -- gwooledge
+ - Handling of Command key modified in Mac OS X UI. It should be accessible
+ in macros now if it wasn't before -- Neil
+ Gameplay changes:
+ - Lost sword quest rewards always give a minimum skill modifier of 0.3.
+ -- gwooledge
+ - (Mass) Genocide damage is applied all at once to avoid bug #228.
+ -- gwooledge
+ Monster changes:
+ - Kavlax should be many-headed. -- gwooledge
+ - Regular (non-Joke, non-Cth, non-Z) monsters should not breathe nuke,
+ because it has a side effect we don't want in ToME -- Neil
+ Object changes:
+ - Removed pointless slays, brands, and bonuses on Pick of Erebor -- Neil
+ - When examining books, demonology equipment and instruments in stores, show
+ both the object's powers and its spells. -- gwooledge
+ - Junk should stack just like skeletons. Patch by StarweaverBlue.
+ -- gwooledge
+ - Mac OS X builds now put all the game data into the bundle, storing all
+ user data in the user's Library (some preferences in
+ Library/Preferences/net.t-o-m-e.tome.plist, the rest in
+ Library/Application Support/ToME. -- Neil
+ Player changes:
+ - All new partial summon upkeep formula -- neil
+ Dungeon changes:
+ - Edit one vault to open up some inaccessible rooms -- Neil
+ - A certain early trap should be less deadly (and appear a bit later).
+ -- gwooledge
+ Bug fixes:
+ - Alchemy: disallow repowering double-ego items, unless the character has
+ the artifact creation ability. Based on patch by Andrey Egoshin.
+ -- gwooledge
+ - Lost sword quest skill reward probabilities were computed incorrectly.
+ Fix suggested by Dan Rosenberry. -- gwooledge
+ - Don't let a player trick the Valar by getting drained and re-gaining
+ levels -- Neil
+ - Don't allow Runecraft and Thaumaturgy spells to go explode inside walls
+ and seep through -- Neil
+ - When consuming magic essences, don't stop prematurely. Based on patch
+ by Andrey Egoshin. -- gwooledge
+ - Upkeep cost for partial summons was not always charged. -- gwooledge
+ - Some staves were being generated with the wrong tval, causing several bugs
+ including (but not limited to) staves being unrechargeable. -- gwooledge
+ - Saving throw was not calculated correctly. -- gwooledge
+ - Disallow negative experience alchemy abuses. Based on patch by Andrey
+ Egoshin. -- gwooledge
+ - Nonliving and undead pets won't be angered by lack of breathable air.
+ -- gwooledge
+ - Don't use the "POSIX" setuid calls on Mac OS X, as they apparently break
+ compilation -- neil
+ - Certain monster spells were hard-coded for the wrong number of equipment
+ slots. -- gwooledge
+ - Incorrect operator used in cave generation code. Effect unknown, but it
+ *might* possibly fix some of the Orc cave crashes.-- gwooledge
+ - Don't allow uniques or quest monsters to just disappear to the move of
+ another monster -- Neil
+ - Attempt to work around some crashes in the fractal cave generator -- Neil
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 30 Dec 2005 15:54:19 -0600
+
+tome (2.3.2-1) unstable; urgency=low
+
+ * New upstream release.
+ Interface changes:
+ - If easy_disarm is off, don't trigger known traps while walking normally.
+ Added a new extended command "blunder" to let players trigger traps on
+ purpose. -- gwooledge
+ - Lots of documentation, spelling and grammar fixes, including:
+ * the now-outdated race/class ability tables, replaced with skill tables
+ * the missing documentation for the set of extended commands
+ * far too many others to mention here
+ -- gwooledge
+ - Added sanity and speed to the character screen (and hence the text dump).
+ Consolidated HP and SP into one line to make room. -- gwooledge
+ - Allow shopping to use the correct keys in roguelike mode. -- gwooledge
+ - Push a certain potion type a little deeper into the dungeon -- Neil
+ - Make piety display light blue when praying, to make it easier to tell
+ when you're praying. -- gwooledge
+ - Don't display ordinary resists when there's also an immunity to the same
+ element, in an object description. -- gwooledge
+ - Display the (colored) character for uniques in the Known Uniques list (~2).
+ -- gwooledge
+ - Add "Check abilities" extended command/macro. This gives roguelike keyset
+ players a way to access the ability screen other than "\N", although it's
+ still one more keystroke than "\N" is.... -- gwooledge
+ - Clean up some offensive messages, patch courtesy of 'The Fury' -- Neil
+ - Include the resistances grid on character sheets dumped on death.
+ This makes them consistent with the ones generated before death, and
+ is more informative and useful for post mortem analyses. -- gwooledge
+ - Examining a totem will recall the monster it summons -- Neil
+ - Examining a corpse will recall the monster it was -- Neil
+
+ Object changes:
+ - Prevent random artifact bolts from giving extra blows -- Neil
+ - Correct the types of certain artifact trap sets to match their weights
+ and descriptions. -- gwooledge
+ - Potions of Cure Insanity were too cheap. -- gwooledge
+
+ Player changes:
+ - Warriors no longer get a secret special three bonus blows spread over the
+ 50 character levels. The three blows are now tied to Weaponmastery.
+ Module authors should adjust accordingly, or their warriors may get three
+ blows they didn't have before. -- Neil
+
+ Bug fixes:
+ - Don't allow trap doors on quest levels or on chests. -- gwooledge
+ - Update view after high-powered globe of light. -- gwooledge
+ - Don't allow use of stairs (any < or > movement command) while rooted
+ to the floor (by the Yavanna spell). -- gwooledge
+ - Try again to keep traps from wrecking a certain plot element -- Neil
+ - Fix module file handling for multi-user installs. Now character sheets,
+ automatizer file, and the rest will be read and written in
+ ~/.tome/2.3/modulename as they should. -- Neil
+ - Try harder to save persistent levels when recalling out -- Neil
+ - Fix all sub-racial skill bonuses, along with Maia racial skill bonuses
+ -- Neil
+ * Bug fix: "tome must be build against libxaw7", thanks to serge
+ (Closes: #305759).
+
+ -- Manoj Srivastava <srivasta@debian.org> Thu, 11 Aug 2005 15:03:52 -0500
+
+tome (2.3.1-1) unstable; urgency=low
+
+ * New upstream release.
+ - Fix loading and saving of skills, I hope. Unfortunately this breaks save
+ compatiability, though. The saves must be deleted again. -- Neil
+ - Fix negative skills -- Neil
+ - Don't use weaponmastery combat when weaponmastery skill is negative -- Neil
+
+ -- Manoj Srivastava <srivasta@debian.org> Sat, 22 Jan 2005 17:33:40 -0600
+
+tome (2.3.0-1) unstable; urgency=low
+
+ * New upstream release.
+
+ Gameplay changes:
+ - Added the new Mimic shapes and updated the old ones -- masmarangio
+ - Destroying items manually now takes no time -- neil
+ - Added the spell Sterilize and Staves of Sterilization from ToME 3.0.0.
+ - Added the spell Inertia Control from ToME 3.0.0 -- masmarangio
+
+ Object changes:
+ - Removed portable holes as have been useless for as long as merchants have
+ been removed from game. --fearoffours
+ - k_info.txt: Changed comments and descriptions of the items, mostly from
+ the wiki (Bug # 176) and added missing descriptions (IdeaArchive)
+ Added article (&) in the name of armours (Bug # 81),
+ The spelling of some item names was changed: Scroll of Enchant Armour,
+ *Enchant Armour*, Curse Armour, Summon Monsters, Basilard
+ Added COULD2H to the Claymore and MUST2H to the Espadon.
+ - ra_info.txt: Added a STR-increasing part without combat bonuses for diggers
+ - e_info.txt: Diggers cannot be of Earthquakes anymore (there are combat boni
+ involved) - perhaps an own ego type should be added... -- masmarangio
+ - No more blessed boomerangs -- neil
+
+ Player changes:
+ - Class no longer influences the internal Angband 'skills' of Disarming,
+ Magic Devices, Saving Throw, Stealth, Searching, Perception, Hand-to-Hand
+ combat, Missile Combat, and Throwing. ToME skills instead have the same
+ effect for all classes. -- neil
+ - Water Bite no longer has a damage cap -- neil
+ - Except for infravision, all innate class or racial effects on skills are
+ gone. All skills have equal effect for all classes, and races now give
+ starting skill bonuses. -- Neil
+ - Mages are more geared toward a mix of Magic and Combat, while Sorcerors
+ have more options than pure Sorcery -- Neil
+ - Priests disarm as well as Warriors do now -- neil
+
+ Misc changes:
+ - a_info.txt: Updated names of artifacts in the comments -- masmarangio
+ - object.pkg: Added psychometry() for easier mindcraft testing.
+ - birth.txt, index.txt : Corrected and added abbreviations
+ gen_idx.lua: removed non-existent file and sorted file list
+ - Updated luckspoiler -- masmarangio
+ - Typo in s_fire.lua, from the wiki -- masmarangio
+ - rm_skeleton.txt, rm_zombie.txt: They cannot restore life force, and zombies
+ are not resistant to nether -- masmarangio
+ - Helpfile updates for all character classes. -- masmarangio
+ - util.pkg: Added lite_spot() and note_spot() for modules -- masmarangio
+ - g_melkor.txt: Added fire resistance for worshippers of Melkor
+ - p_info.txt: Removed the useless skill Prayer for Maiar -- masmarangio
+ - help file documentation restructuring, copying appropriate rewrites from
+ wiki. -- fearoffours
+ - Various minor changes to helpfiles, reflecting current changes to
+ documentaiton on the wiki. --fearoffours
+ - k_info.txt: Fixed name of the commented out portable holes -- masmarangio
+ - Fixed some typographical errors, mostly from the wiki:
+ cmd1.c: [The monster] fall -> falls, deleted space (Bug # 80 from the wiki)
+ k_info.txt: Added & for Climbing sets (Bug # 81 from the wiki)
+ q_one.c: You felt -> You fell (Bug # 94 from the wiki)
+ monster2.c: It tries to breed but he fails: he -> it (Bug # 98 from the wiki)
+ bldg.c: Changed wording of the soothsayer (Bug # 106 from the wiki)
+ tables.c: Minor changes in the One Ring quest (Bug # 117 from the wiki)
+ q_invas.c: jumps out of the between -> appears, deleted spaces,
+ added single quotes in direct speech (Bug # 119 from the wiki)
+ q_between.c: Deleted space, changed comments -- masmarangio
+ - book-4.txt: Capitalised 'Ring' (Bug # 135 from the wiki) -- masmarangio
+ - options.txt: Also removed the options from the help file -- masmarangio
+ - cmd6.c: replaced the recall activation code by recall_player -- masmarangio
+ - monster1.c: missing spaces in description (Bug # 169) -- masmarangio
+ - Modules need to define three new variables to control the chance or
+ random artifact generation. random_artifact_weapon_chance,
+ random_artifact_armor_chance, random_artifact_jewelry_chance control
+ the chance for different types of items. -- neil
+ - mods_aux.lua: Added default values for random artifact generation;
+ updated the skill values -- masmarangio
+ - cmd6.c: protect evil -> protection from evil, s_stick.lua: town -> surface
+ q_betwen.c, q_invas.c: speak -> speaks (from the forum) -- masmarangio
+ - tr_info.txt: Spelling of Lite (Bug # 182), Armor, Paralyzing -- masmarangio
+ - The (Ctrl-Q) Quest screen now shows which number god quest you have been given
+ and an additional line in your character dump shows how many have been
+ successfully completed. -- fearoffours
+ - Help updates from the wiki - lots of it Maylith's work, esp FAQ updates.
+ -- fearoffours
+ - Corrected the description of the Disarm, Call the Elements and Channel
+ Elements spells (without changing the code) (Bug # 175) -- masmarangio
+ - tome-faq.txt, index.txt: Typo (Bug # 196) -- masmarangio
+ - s_info.txt: Antimagic: generates -> generate (Bug # 198) -- masmarangio
+ - powers.c: replaced the recall power code by recall_player
+ q_troll.c: Fixed typos from the wiki (Bug # 208) -- masmarangio
+ - tables.c: Removed harpers and some other small changes (Bug # 212)
+ cmd6.c: Added "and" in the description of ACT_ROHAN (Bug # 213)
+ -- masmarangio
+ - m_demono.txt, s_demon.lua: armor -> armour class (Bug # 217)
+ - dun3.18: description of DimGates: fills -> fill (Bug # 223)
+ -- masmarangio
+ - init1.c: The parser adds missing spaces at the end of the
+ description of artifacts, like it did for objects. -- masmarangio
+ - Race, class and race modifier help files updates to reflect changes
+ in skill bonuses. -- fearoffours
+ Some changes to random artifact and scrolls of artifact creation
+ (See Bugs # 206, 222, 226 on the wiki):
+ - externs.h: Moved some functions listed under spells2.c to proper sections
+ - k_info.txt: Added "mundane" to the description of the scroll
+ - q_ultrag.c: Quest texts changed as reported in Bug # 210 -- masmarangio
+ - spells.lua: Sorted the Conveyance spells by level (Bug # 233)
+ -- masmarangio
+ - Helpfiles reflect changes to skills (priest disarming and racial
+ spirituality update). -- fearoffours
+ - library.lua: Added OBJ_FOUND_REWARD to the tome (Bug # 237) -- masmarangio
+
+ Dungeon changes:
+ - Added the first new special level from ToME 3.0.0, Galleon in Helcaraxe
+ -- masmarangio
+ - Added the special level Factory in the Illusory Castle -- masmarangio
+ - dungeon.c: Level of the Death dungeon is the minimum level from d_info.txt
+
+ Bug fixes:
+ - dungeon.c: Light should consume fuel at a rate of 1 / turn -- masmarangio
+ - A store (e.g. the mathom house) can contain up to 255 items (in defines.h
+ STORE_INVEN_MAX limited the number of items to 24) (Note: the limit is
+ stored in a byte in loadsaves.c) -- masmarangio
+ - s_meta.lua: Inertia controlled spells are not casted in wilderness mode.
+ s_mana.lua: Inertia level of Disruption Shield is 9 (needed spell level 45)
+ m_meta.txt: Added a list of controllable spells -- masmarangio
+ - p_info.txt: Archers and Rangers gain the missing Spirituality skill
+ p_info.txt: Removed the old Mimic Cloak (new cloak in player.lua)
+ - p_info.txt: Thunderlords start with Stealth -16.000 (from the wiki)
+ - cmd7.c: Fixed Alchemy recharging bug (thanks to Scott)
+ - al_info.txt: Removed the old Mimic Potions -- masmarangio
+ - monspeak.txt: Added some lines for Groo to fix a bug -- masmarangio
+ - files.c: Corrected display of Climb flag, immunity to Nether, negative
+ pvals < -9. Added Sentient, Clone, Spider ESP flags. -- masmarangio
+ - files.c: Added flags from the gods and spell schools to the character
+ screen. Added also flags from wielded symbiotes. -- masmarangio
+ - cmd4.c: Quest list without random quests in DL > 98 -- masmarangio
+ - randart.c: An item with pval > 0 (e.g. an Elven Cloak) can gain parts
+ with a max_pval = 0 (e.g. resistances and immunities) -- masmarangio
+ - ow_info.txt: missing C: lines reduced the purse to 0 -- masmarangio
+ - object1.c: don't wield bolts with instruments and pebbles with boomerangs
+ (Bug # 127 from the wiki) -- masmarangio
+ - object1.c: mention_use and describe_use list all available slots, check all
+ weapon weights and distinguish between instruments and bows (Bug # 87)
+ object1.c: Res Chaos implies Res Confusion (for the character screen)
+ xtra1.c: Magical breath implies Water breath (from the wiki) -- masmarangio
+ - Z and Cth monster options removed, as in ToME 3. This fixes, among other
+ things, the Death Orb issues. -- neil
+ - a_info.txt: Corrected two typos (Bugs # 140, 146 from the wiki)
+ k_info.txt: Changed description of Bastard Sword, added RES_CHAOS to the
+ known flags of a Blade of Chaos (it's mentioned in the description)
+ files.c: Terminated highscore strings with \0, changed total_points
+ slightly to prevent an overflow error (Bug # 139 from the wiki)
+ v_info.txt: Corrected the x size of vault 99 and 104 -- masmarangio
+ - dungeon.c: Set dungeon_type to wilderness when recalling out. This should
+ fix the various Moria recalling bugs (Bug # 95)
+ - spells2.c: Redraw trap status after passwall (Bug # 51)
+ store.c: Removed '))' when displaying a large store -- masmarangio
+ - al_info.txt: removed recipe for Scroll of Spell (Bug # 179), added recipe
+ for Staff of Sterilisation (Bug # 77) -- masmarangio
+ - cmd6.c: Added timeout for junkarts in the activation description (ugly fix)
+ tables.c: Replaced ACT_CURE_POISON by not used ACT_CURE_POIS -- masmarangio
+ - Once a god quest is failed, you will not receive any more god quests.
+ -- fearoffours
+ - bldg.c: Research item (Bug # 191) and research monster are now paid
+ correctly -- masmarangio
+ - spells2.c: Diggers cannot be enchanted with scrolls -- masmarangio
+ - files.c: Fixed displayed barehanded damage (Patch from Scott, Bug # 195)
+ -- masmarangio
+ - files.c: Remove / restore CAVE_VIEW before / after saving the game.
+ This solves a long standing bug with the lighting of the dungeon
+ since the temporary arrays that hold the position of the viewed
+ grids are not stored in the save file (Bug # 19). -- masmarangio
+ - cmd6.c: the selection of artifactable items can be escaped now
+ randart.c: *ID* the object before listing the powers, some re-ordering
+ - spells2.c: Re-add diggers to item_tester_artifactable, and limit the
+ selection to normal items due to complains (no ego items or artifacts)
+ - ra_info.txt: Fixed two W-lines with 4 entries and added a missing C-line
+ - k_info.txt: Reduced throwing damage of totems to 1 -- masmarangio
+ - st_info.txt: Fixed the changed item names in the stores (StatusReport3)
+ - Fix for disappearing artifacts (especially guardian artifacts) during load / save
+ thanks to SimonSorc
+
+ -- Manoj Srivastava <srivasta@debian.org> Tue, 7 Dec 2004 19:22:40 -0600
+
+tome (2.2.7-1) unstable; urgency=low
+
+ * New upstream release. This is a bug fix release.
+
+ -- Manoj Srivastava <srivasta@debian.org> Sun, 13 Jun 2004 22:02:32 -0500
+
+tome (2.2.6-2) unstable; urgency=low
+
+ * Bug fix: "XSIisms in postinst, prerm; violates policy 10.4", thanks to
+ Clint Adams (Closes: #237959).
+
+ -- Manoj Srivastava <srivasta@debian.org> Sun, 14 Mar 2004 12:24:19 -0600
+
+tome (2.2.6-1) unstable; urgency=low
+
+ * New upstream release
+
+ Interfaces changes:
+ * Pressing Escape gets you out of the pet dismissal list -- neil
+
+ Misc changes:
+ * Helpfiles: bearform combat help, music typos, barbarian
+ revisions. -- fearoffours
+ * - Typos in the description of arrows, shots, bolts; punctuation in
+ the mushroom quest -- masmarangio
+ * HOOK_CALC_BONUS_END hooks
+ * Helpfiles: corrected starting equipment of mindcrafters -- masmarangio
+ * - Backport of old helpfile updates: no Geomancy for Alchemists and
+ Rune- crafters, updated luck spoiler, corruption spoiler in
+ crpt_aux.lua, a link in skills.txt, an example in
+ automatizer.txt. monsters3.c: changed 'golem' to 'creature', since the
+ Mind Steal Spell also allows to control a monster. -- masmarangio
+ * Typo (massage -> message) from the forum -- masmarangio
+ * Capitalisation in the names of junkarts -- masmarangio
+ * mindcraft_info: Corrected and expanded the info for mindcraft powers -- masmarangio
+ * Small corrections in luck spoiler, description of Manwe's Blessing
+ and m_mimic.txt -- masmarangio
+
+ Bug fixes:
+ * Prevent recall to Lost Temple before getting the quest -- neil
+ * Automatizer now accepts TV_TOTEM -- neil
+ * Some vaults incorrectly named -- fearoffours
+ * Wight quest crash fix by 'amaurea' -- neil
+ * God choosen at random was broken -- masmarangio
+ * Typo in q_one.c (or -> of)
+ * Don't use a turn when cancelling a possessor action -- neil
+ * - summon_true crashed the game with a summon skill < 1 -- masmarangio
+ * - test_object_wish: aware status is saved and restored -- masmarangio
+ * God quest will no longer give inaccurate or misleading
+ directions. It also will now give directions from two static features,
+ and an approximate, relative distance from each of those points. --
+ fearoffours
+
+ * Bug fix: "Error in /usr/lib/menu/tome", thanks to Philipp Kolmann
+ (Closes: #234871).
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 10 Mar 2004 23:45:55 -0600
+
+tome (2.2.5-1) unstable; urgency=low
+
+ * New upstream release
+ Monsters changes:
+ * Drain attacks can't drain the one artifact wand, staff, or horn -- neil
+
+ Objects changes:
+ * Some items that give damage bonuses will be more clear about it -- neil
+
+ Bug fixes:
+ * Fix monster possessor crash -- neil
+ * Fix random quest skill requester -- neil
+ * Fix crash when picking up ammo into your quiver that can't be
+ fired with the launcher you are wielding -- neil
+ * God quest fix -- neil
+ * Disintegrating walls should not bother Yavanna -- neil
+ * Yet another try at fixing levelled carried monsters. Their
+ attacks are affected by their level now and their hitpoints are
+ handled better. I should have said this for the last release,
+ but un-hypnotize any pets before upgrading from 2.2.2. Otherwise
+ compatibility is fine. -- neil
+ * Semi-wraiths should not be hurt by climbing over mountains -- neil
+ * Fixed Flame of Udun spell
+ * Diggers are not weapons and should not be displayed as such -- neil
+
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 24 Dec 2003 10:59:50 -0600
+
+tome (2.2.4-1) unstable; urgency=low
+
+ * New upstream Bugfix version.
+ * Redid the build system.
+
+ -- Manoj Srivastava <srivasta@debian.org> Mon, 24 Nov 2003 23:52:59 -0600
+
+tome (2.2.3-1) unstable; urgency=low
+
+ * New upstream Bugfix version.
+ * Fixed the menuentry for tome, quoting a " char. closes: Bug#207648
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 03 Oct 2003 10:58:24 -0500
+
+tome (2.2.2.0-CVS031001-1) unstable; urgency=low
+
+ * Fixed usage of chown root.root in the rules files.
+ * This is a major security update; hundreds of potential buffer
+ overflows (most of them not exploitable) have been fixed in this
+ version. At the request of upstream, this audit was done on the CVS
+ version.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 27 Aug 2003 02:05:02 -0500
+
+tome (2.2.2-2) unstable; urgency=low
+
+ * Added clarifications to the copyright file, after personal
+ communications from Dark God <darkgod@t-o-m-e.net>, the author of the
+ Tome variant.
+
+ -- Manoj Srivastava <srivasta@debian.org> Sat, 2 Aug 2003 13:59:46 -0500
+
+tome (2.2.2-1) unstable; urgency=low
+
+ * Initial Release.
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 1 Aug 2003 22:02:44 -0500
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 00000000..ec635144
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 00000000..65950528
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,59 @@
+Source: tome
+VCS-Git: git://anonscm.debian.org/users/srivasta/debian/tome.git
+VCS-Browser: http://anonscm.debian.org/gitweb/?p=users/srivasta/debian/tome.git;a=summary
+Section: non-free/games
+Priority: optional
+Maintainer: Manoj Srivastava <srivasta@debian.org>
+Build-Depends: libxaw7-dev, debhelper (>= 9.0.0),
+ libncurses5-dev | libncurses-dev | ncurses-dev,
+ libsdl1.2-dev | libsdl-dev, libsdl-mixer1.2-dev,
+ libsdl-gfx1.2-dev, libsdl-image1.2-dev, libsdl-ttf2.0-dev,
+ libsdl-net1.2-dev, dpkg-dev (>= 1.16.0), cmake
+Standards-Version: 3.9.5.0
+
+Package: tome
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: single-player text-based roguelike dungeon simulation game
+ Tome, short for Troubles of Middle Earth, is a single-player,
+ text-based, dungeon simulation derived from the game angband, which
+ in turn is derived from the older game Moria, which was in turn based
+ on Rogue. It is often described as a "roguelike" game because the
+ look and feel of the game is still quite similar to Rogue.
+ .
+ In tome, the player may choose from a number of races and classes
+ when creating a character, and then "run" that character over a
+ period of days, weeks, even months, attempting to win the game by
+ defeating Morgoth, who lurks somewhere in the depths of the dungeon.
+ .
+ The ultimate goal of the game is to develop a character strong enough
+ to defeat Morgoth, who resides on dungeon level 100. Upon doing so,
+ you will receive the exalted status of "winner" and your character may
+ retire.
+ .
+ The first main difference from Angband a new player to ToME will need
+ to be aware of is that it has implemented a skills based system where
+ instead of the adventurer automatically improving in their abilities
+ as they become more experienced, they get 5 skill points to spend on
+ their character's abilities and can therefore customise what type of
+ character they play. See the skills help file for details
+ .
+ The second major difference is that the main dungeon from Angband has
+ been split into 4 "dungeons", each of which cover a different
+ portion of the dungeon's levels. Note that not all of the places are
+ actually "dungeons" - some are caves, forests, etc.
+ .
+ The third main difference between Vanilla Angband and ToME is the
+ difference in character classes and races, as well as a very
+ different magic system. ToME also offers the player the ability to
+ undertake a series of quests. It is not required for any adventurer
+ to undertake the fixed quests, but they can result in some nice
+ rewards.
+ .
+ Morgoth was 'the Dark Enemy of Middle-Earth' during its First Age. He
+ was banished by the Valar (offspring of Eru, "god" of J.R.R.
+ Tolkien's world) at the end of the First Age and thus never appears
+ in The Lord of the Rings, set during the Third Age. Sauron, who does
+ figure into those tales, was the most powerful of his servants. Read
+ Tolkien's 'The Silmarillion' for more on the legends of Middle-Earth.
+ Angband is a reference to Morgoth's "prison of iron."
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 00000000..086e7192
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,98 @@
+This package was debianized by Manoj Srivastava <srivasta@debian.org>
+
+Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
+
+This software may be copied and distributed for educational, research,
+and not for profit purposes provided that this copyright and statement
+are included in all such copies. Other copyrights may also apply.
+
+
+All changes made by Ben Harrison, Robert Ruehlmann, and many other Angband
+developers are also available under the GNU GENERAL PUBLIC LICENSE.
+Note that this doesn't influence the current distribution, since parts of
+the source are still only available under the old Moria/Angband license.
+Until all parts of Angband are distributed under the GPL the only valid
+license remains the original Moria/Angband license.
+
+More information about Angband and the GPL can be found at:
+http://thangorodrim.angband.org/development/opensource.html
+
+
+
+ Copyright © 1989,1997, 1999,2001 James E. Wilson
+ Copyright © 1997,1989, 2001 Robert A. Koeneke]
+ Copyright © 1991,1993 Microsoft Corporation. All rights reserved
+ Copyright © 1997 Ben Harrison, and others
+ Copyright © 1997 Ekkehard Kraemer, and others
+ Copyright © 1997 Keith Randall, and others
+ Copyright © 1997 Peter Ammon
+ Copyright © 1997 Ron Anderson
+ Copyright © 1997 Skirmantas Kligys, and others
+ Copyright © 1997 Torbjorn Lindgren, and others
+ Copyright © 1999,2001-2003 Dark God
+ Copyright © 1989 Christopher J. Stuart]
+ Copyright © 1997, 2000-2001 Robert Ruehlmann
+ Copyright © 2001, 2002 Hansj�g Malthaner
+ Copyright © 2001 Andrew Sidwell
+ Copyright © 2001 Gregory Velichansky (hmaon@bumba.net)
+ Copyright © 2004 Ethan Stump <estump@seas.upenn.edu>
+ Copyright © 2003-2004 Neil Stevens <neil@hakubi.us>
+
+ This software may be copied and distributed for educational, research, and
+ not for profit purposes provided that this copyright and statement are
+ included in all such copies.
+
+ Note that these copyright messages apply to an ancient version
+ of Angband, as in, from pre-2.4.frog-knows days, and thus the
+ reference to "5.0" is rather misleading...
+
+ UNIX ANGBAND Version 5.0
+
+ Original copyright message follows.
+
+ ANGBAND Version 4.8 COPYRIGHT (c) Robert Alan Koeneke
+
+ I lovingly dedicate this game to hackers and adventurers
+ everywhere...
+
+ Designer and Programmer:
+ Robert Alan Koeneke
+ University of Oklahoma
+
+ Assistant Programmer:
+ Jimmey Wayne Todd
+ University of Oklahoma
+
+ Assistant Programmer:
+ Gary D. McAdoo
+ University of Oklahoma
+
+ UNIX Port:
+ James E. Wilson
+ UC Berkeley
+ wilson@ernie.Berkeley.EDU
+ ucbvax!ucbernie!wilson
+
+ ANGBAND may be copied and modified freely as long as the above
+ credits are retained. No one who-so-ever may sell or market
+ this software in any form without the expressed written consent
+ of the author Robert Alan Koeneke.
+
+ The Tome variant has been modified by Dark God <darkgod@t-o-m-e.net>,
+ and is available under the same terms as Angband.
+
+
+The Debian specific changes are © 1996-2009, Manoj Srivastava
+<srivasta@debian.org>, and distributed under the terms of the GNU
+General Public License, version 2.
+
+On Debian GNU/Linux systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL-2'.
+
+ A copy of the GNU General Public License is also available at
+ <URL:http://www.gnu.org/copyleft/gpl.html>. You may also obtain
+ it by writing to the Free Software Foundation, Inc., 51 Franklin
+ St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Manoj Srivastava <srivasta@debian.org>
+arch-tag: d4250e44-a0e0-4ee0-adb9-2bd74f6eeb27
diff --git a/debian/patches/0001-debcherry-fixup-patch.patch b/debian/patches/0001-debcherry-fixup-patch.patch
new file mode 100644
index 00000000..28c45ba4
--- /dev/null
+++ b/debian/patches/0001-debcherry-fixup-patch.patch
@@ -0,0 +1,80 @@
+From c1f79e5b7f2dc335983ba7df981b5d45170295fb Mon Sep 17 00:00:00 2001
+From: Manoj Srivastava <srivasta@golden-gryphon.com>
+Date: Wed, 14 May 2014 23:48:09 -0700
+Subject: [PATCH 1/3] debcherry fixup patch
+
+32318ec [master]: New upstream release
+ - no changes against upstream or conflicts
+786d26c [master]: New upstream release
+ - extra changes or conflicts
+36e907c [topic--debian]: FTBFS due to binutils-gold
+ - extra changes or conflicts
+1021e15 [master]: First phase of a ove to a new build system using dh.
+ - no changes against upstream or conflicts
+23433b4 Added the debian submodule.
+ - extra changes or conflicts
+b15c77f Reduce divergence from upstream, and move to sdl variant
+ - extra changes or conflicts
+815d966 Set the maintainewr address to be a debian role address
+ - no changes against upstream or conflicts
+a83a04d Fix typo in man page
+ - extra changes or conflicts
+a3d690b Revert the -m32 flags; use linux32 instead at run-time
+ - extra changes or conflicts
+79cab02 Build in 32bit mode
+ - extra changes or conflicts
+de0507e Fix initialization of directory for loading/saving games.
+ - extra changes or conflicts
+ae5a5b4 Really synch with upstream
+ - extra changes or conflicts
+a2f1a5c Added a manual page
+ - extra changes or conflicts
+18bd448 Changes to integrate tome into Debian
+ - extra changes or conflicts
+---
+ src/config.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/config.h b/src/config.h
+index 7c1cf1d..c9f460e 100644
+--- a/src/config.h
++++ b/src/config.h
+@@ -89,7 +89,7 @@
+ /*
+ * OPTION: Include "ncurses.h" instead of "curses.h" in "main-gcu.c"
+ */
+-/* #define USE_NCURSES */
++#define USE_NCURSES
+
+
+ /*
+@@ -226,7 +226,7 @@
+ * that file.
+ */
+ #ifndef DEFAULT_PATH
+-# define DEFAULT_PATH "./lib/"
++# define DEFAULT_PATH "/var/games/tome"
+ #endif
+
+
+@@ -261,7 +261,7 @@
+ /*
+ * OPTION: Person to bother if something goes wrong.
+ */
+-#define MAINTAINER "darkgod@t-o-m-e.net"
++#define MAINTAINER "tome@packages.debian.org"
+
+
+ /*
+@@ -282,7 +282,7 @@
+ /* ToME options: */
+
+ /* Should the player know his / her starting life rate? */
+-/* #define SHOW_LIFE_RATE */
++#define SHOW_LIFE_RATE
+
+ /* Allow hordes of 'similar' monsters */
+ #define MONSTER_HORDES
+--
+2.0.0.rc2
+
diff --git a/debian/patches/0002-Fix-code-which-needed-a-32-bit-int-to-not-use-int-lo.patch b/debian/patches/0002-Fix-code-which-needed-a-32-bit-int-to-not-use-int-lo.patch
new file mode 100644
index 00000000..3cc54503
--- /dev/null
+++ b/debian/patches/0002-Fix-code-which-needed-a-32-bit-int-to-not-use-int-lo.patch
@@ -0,0 +1,58 @@
+From 448e655d55608b18ed6e8e387d5f9c86356900c8 Mon Sep 17 00:00:00 2001
+From: Manoj Srivastava <srivasta@debian.org>
+Date: Tue, 21 Oct 2008 08:25:47 -0500
+Subject: [PATCH 2/3] Fix code which needed a 32 bit int to not use int/long
+
+On amd64, but not on i386, tome produces LUA errors at various
+times. The errors occur at savefile load, when wileding a weapon,
+unweilding a weapon, and for other events. The same homedir, same
+savefiles, same config, same etc., does not produce errors in the
+32bit build of the package.
+
+The error seems to be that the type Number needs to be a 32bit wide
+integer; and seems to be defined by default as an long, with an option
+to define it as an int for amd64. However, for the 11 arches Debian
+supports, this would lead to a morass of selecting architectures in
+the makefile to override the type; a better solution is to use
+stdint.h and use a type which is 32 bits wide by design: int32_t.
+
+This fixes the LUA errors, and Closes: Bug#419825
+
+Signed-off-by: Manoj Srivastava <srivasta@debian.org>
+---
+ src/lua/llimits.h | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/lua/llimits.h b/src/lua/llimits.h
+index 4b12450..39a1e0d 100644
+--- a/src/lua/llimits.h
++++ b/src/lua/llimits.h
+@@ -10,6 +10,7 @@
+
+ #include <limits.h>
+ #include <stddef.h>
++#include <stdint.h>
+
+
+
+@@ -36,7 +37,7 @@
+ ** GREP LUA_NUMBER to change that
+ */
+ #ifndef LUA_NUM_TYPE
+-#define LUA_NUM_TYPE long
++#define LUA_NUM_TYPE int32_t
+ #endif
+
+ typedef LUA_NUM_TYPE Number;
+@@ -50,7 +51,7 @@ typedef LUA_NUM_TYPE Number;
+
+
+
+-typedef unsigned long lint32; /* unsigned int with at least 32 bits */
++typedef int_least32_t lint32; /* unsigned int with at least 32 bits */
+
+
+ #define MAX_SIZET ((size_t)(~(size_t)0)-2)
+--
+2.0.0.rc2
+
diff --git a/debian/patches/0003-debian-cmake-fixes-Change-install-paths-to-FHS-compl.patch b/debian/patches/0003-debian-cmake-fixes-Change-install-paths-to-FHS-compl.patch
new file mode 100644
index 00000000..ab1799f1
--- /dev/null
+++ b/debian/patches/0003-debian-cmake-fixes-Change-install-paths-to-FHS-compl.patch
@@ -0,0 +1,63 @@
+From 1212be6727cfaa14760f0130cdea635c38fb523b Mon Sep 17 00:00:00 2001
+From: Manoj Srivastava <srivasta@golden-gryphon.com>
+Date: Wed, 14 May 2014 23:46:05 -0700
+Subject: [PATCH 3/3] [debian-cmake-fixes]: Change install paths to FHS
+ compliant games
+
+So the binary lives in /usr/games/tome, instead of /usr/bin/tome
+
+Signed-off-by: Manoj Srivastava <srivasta@golden-gryphon.com>
+---
+ CMakeLists.txt | 2 +-
+ src/CMakeLists.txt | 10 +++++-----
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 91512a6..72cd53e 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -94,7 +94,7 @@ endif(WIN32)
+ # Set the path for loading the library bits.
+ #
+ IF(SYSTEM_INSTALL)
+- SET(DEFAULT_PATH "${CMAKE_INSTALL_PREFIX}/lib/tome")
++ SET(DEFAULT_PATH "/var/games/tome")
+ ELSE()
+ SET(DEFAULT_PATH "./lib")
+ ENDIF()
+diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
+index e2e6264..932fef4 100644
+--- a/src/CMakeLists.txt
++++ b/src/CMakeLists.txt
+@@ -4,9 +4,9 @@ ADD_SUBDIRECTORY(lua)
+ SET(SRCS
+ main-gcu.c main-x11.c main-xaw.c main-sdl.c main-gtk2.c
+ z-rand.c z-util.c z-form.c z-virt.c z-term.c
+- variable.c tables.c plots.c util.c cave.c dungeon.c
+- melee1.c melee2.c modules.c
+- object1.c object2.c randart.c squeltch.c traps.c
++ variable.c tables.c plots.c util.c cave.c dungeon.c
++ melee1.c melee2.c modules.c
++ object1.c object2.c randart.c squeltch.c traps.c
+ monster1.c monster2.c monster3.c
+ xtra1.c xtra2.c skills.c powers.c gods.c
+ spells1.c spells2.c
+@@ -15,7 +15,7 @@ SET(SRCS
+ help.c
+ generate.c gen_maze.c gen_evol.c wild.c levels.c store.c bldg.c
+ cmovie.c
+- wizard2.c init2.c birth.c wizard1.c init1.c main.c
++ wizard2.c init2.c birth.c wizard1.c init1.c main.c
+ # Lua bits:
+ lua_bind.c script.c w_mnster.c w_player.c w_play_c.c w_z_pack.c
+ w_obj.c w_util.c w_spells.c w_quest.c w_dun.c
+@@ -68,5 +68,5 @@ TARGET_LINK_LIBRARIES(tome lua ${LIBS})
+
+ # Installation
+ INSTALL(TARGETS tome
+- RUNTIME DESTINATION bin
++ RUNTIME DESTINATION games
+ )
+--
+2.0.0.rc2
+
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 00000000..bb1818e2
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,4 @@
+# exported from git by git-debcherry
+0001-debcherry-fixup-patch.patch
+0002-Fix-code-which-needed-a-32-bit-int-to-not-use-int-lo.patch
+0003-debian-cmake-fixes-Change-install-paths-to-FHS-compl.patch
diff --git a/debian/postinst b/debian/postinst
new file mode 100755
index 00000000..50a53dec
--- /dev/null
+++ b/debian/postinst
@@ -0,0 +1,253 @@
+#! /bin/sh
+# -*- Mode: Sh -*-
+# postinst ---
+# Author : Manoj Srivastava ( srivasta@glaurung.green-gryphon.com )
+# Created On : Fri Nov 14 11:25:07 2003
+# Created On Node : glaurung.green-gryphon.com
+# Last Modified By : Manoj Srivastava
+# Last Modified On : Sun Mar 14 12:19:27 2004
+# Last Machine Used: glaurung.internal.golden-gryphon.com
+# Update Count : 16
+# Status : Unknown, Use with caution!
+# HISTORY :
+# Description :
+#
+# arch-tag: 5401e9ef-39cc-4aee-96a4-61dfb8f32cf7
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+
+# Abort if any command returns an error value
+set -e
+
+package_name=tome
+
+if [ -z "$package_name" ]; then
+ print >&2 "Internal Error. Please report a bug."
+ exit 1;
+fi
+
+# This script is called as the last step of the installation of the
+# package. All the package's files are in place, dpkg has already done
+# its automatic conffile handling, and all the packages we depend of
+# are already fully installed and configured.
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+#
+# quoting from the policy:
+# Any necessary prompting should almost always be confined to the
+# post-installation script, and should be protected with a conditional
+# so that unnecessary prompting doesn't happen if a package's
+# installation fails and the `postinst' is called with `abort-upgrade',
+# `abort-remove' or `abort-deconfigure'.
+
+# The following idempotent stuff doesn't generally need protecting
+# against being run in the abort-* cases.
+
+# Install info files into the dir file
+##: install-info --quiet --section "section pattern" "Section Title" \
+##: --description="Name of the document" /usr/info/${package_name}.info
+
+# Create stub directories under /usr/local
+##: if test ! -d /usr/local/lib/${package_name}; then
+##: if test ! -d /usr/local/lib; then
+##: if mkdir /usr/local/lib; then
+##: chown root.staff /usr/local/lib || true
+##: chmod 2775 /usr/local/lib || true
+##: fi
+##: fi
+##: if mkdir /usr/local/lib/${package_name}; then
+##: chown root.staff /usr/local/lib/${package_name} || true
+##: chmod 2775 /usr/local/lib/${package_name} || true
+##: fi
+##: fi
+
+# Arrange for a daemon to be started at system boot time
+##: update-rc.d ${package_name} default >/dev/null
+
+case "$1" in
+ configure)
+ # Configure this package. If the package must prompt the user for
+ # information, do it here.
+ # Install emacs lisp files
+ ##:if [ -x /usr/lib/emacsen-common/emacs-package-install ]; then
+ ##: /usr/lib/emacsen-common/emacs-package-install $package_name
+ ##:fi
+
+ for file in /var/games/${package_name}/edit/*.txt; do
+ base_file=$(basename $file .txt);
+ cp -f $file /var/games/${package_name}/data/${base_file}.raw;
+ done
+
+ if [ ! -e /var/lib/games/${package_name}/apex/scores.raw ]; then
+ touch /var/games/${package_name}/apex/scores.old
+ fi
+
+ if [ -d /var/lib/games/${package_name}/save ]; then
+ for file in $(find /var/lib/games/${package_name}/save/ -type f); do
+ if [ ! -f $file ]; then
+ continue;
+ fi
+ base=$(basename $file)
+ if [ "X$base" = "Xdelete.me" ]; then
+ continue;
+ fi
+ if [ -s /var/games/${package_name}/save/$base ]; then
+ mv -f $file /var/games/${package_name}/save/$base.old
+ else
+ mv -f $file /var/games/${package_name}/save/$base
+ fi
+ done
+ fi
+
+ # create a scores file if none exists
+ test ! -d /var/games/${package_name}/apex || touch /var/games/${package_name}/apex/scores.raw
+
+ # Clean up ownership
+ chown -R root:games /var/games/${package_name}/
+
+ # Make sure the game can write the files it needs to write to
+ test ! -d /var/games/${package_name}/user || chmod -R g+w /var/games/${package_name}/user
+ test ! -d /var/games/${package_name}/bone || chmod -R g+w /var/games/${package_name}/bone
+ test ! -d /var/games/${package_name}/save || chmod -R g+w /var/games/${package_name}/save
+ test ! -d /var/games/${package_name}/apex || chmod -R g+w /var/games/${package_name}/apex
+
+ # Activate menu-methods script
+ ##: chmod a+x /etc/menu-methods/${package_name}
+
+ # Update ld.so cache
+ ##: ldconfig
+
+ # Make our version of a program available
+ ##: update-alternatives \
+ ##: --install /usr/bin/program program /usr/bin/alternative 50 \
+ ##: --slave /usr/man/man1/program.1.gz program.1.gz \
+ ##: /usr/man/man1/alternative.1.gz
+
+ # Tell ucf that the file in /usr/share/foo is the latest
+ # maintainer version, and let it handle how to manage the real
+ # confuguration file in /etc. This is how a static configuration
+ # file can be handled:
+ ##:if which ucf >/dev/null 2>&1; then
+ ##: ucf /usr/share/${package_name}/configuration /etc/${package_name}.conf
+ ##:fi
+
+ ### We could also do this on the fly. The following is from Tore
+ ### Anderson:
+
+ #. /usr/share/debconf/confmodule
+
+ ### find out what the user answered.
+ # db_get foo/run_on_boot
+ # run_on_boot=$RET
+ # db_stop
+
+ ### safely create a temporary file to generate our suggested
+ ### configuration file.
+ # tempfile=`tempfile`
+ # cat << _eof > $tempfile
+ ### Configuration file for Foo.
+
+ ### this was answered by you, the user in a debconf dialogue
+ # RUNONBOOT=$run_on_boot
+
+ ### this was not, as it has a sane default value.
+ # COLOUROFSKY=blue
+
+ #_eof
+
+ ### Note that some versions of debconf do not release stdin, so
+ ### the following invocation of ucf may not work, since the stdin
+ ### is never coneected to ucfr.
+
+ ### now, invoke ucf, which will take care of the rest, and ask
+ ### the user if he wants to update his file, if it is modified.
+ #ucf $tempfile /etc/foo.conf
+
+ ### done! now we'll just clear up our cruft.
+ #rm -f $tempfile
+
+
+
+ # There are three sub-cases:
+ if test "${2+set}" != set; then
+ # We're being installed by an ancient dpkg which doesn't remember
+ # which version was most recently configured, or even whether
+ # there is a most recently configured version.
+ :
+
+ elif test -z "$2" || test "$2" = "<unknown>"; then
+ # The package has not ever been configured on this system, or was
+ # purged since it was last configured.
+ :
+
+ else
+ # Version $2 is the most recently configured version of this
+ # package.
+ :
+
+ fi ;;
+ abort-upgrade)
+ # Back out of an attempt to upgrade this package FROM THIS VERSION
+ # to version $2. Undo the effects of "prerm upgrade $2".
+ ##:
+
+ ;;
+ abort-remove)
+ if test "$2" != in-favour; then
+ echo "$0: undocumented call to \`postinst $*'" 1>&2
+ exit 0
+ fi
+ # Back out of an attempt to remove this package, which was due to
+ # a conflict with package $3 (version $4). Undo the effects of
+ # "prerm remove in-favour $3 $4".
+ :
+
+ ;;
+ abort-deconfigure)
+ if test "$2" != in-favour || test "$5" != removing; then
+ echo "$0: undocumented call to \`postinst $*'" 1>&2
+ exit 0
+ fi
+ # Back out of an attempt to deconfigure this package, which was
+ # due to package $6 (version $7) which we depend on being removed
+ # to make way for package $3 (version $4). Undo the effects of
+ # "prerm deconfigure in-favour $3 $4 removing $6 $7".
+ :
+
+ ;;
+ *) echo "$0: didn't understand being called with \`$1'" 1>&2
+ exit 0;;
+esac
+
+#DEBHELPER#
+
+# Install doc base documentation
+##:if which install-docs >/dev/null 2>&1; then
+##: if [ -e /usr/share/doc-base/${package_name} ]; then
+##: install-docs -i /usr/share/doc-base/${package_name}
+##: fi
+##:fi
+
+exit 0
diff --git a/debian/postrm b/debian/postrm
new file mode 100755
index 00000000..f813beec
--- /dev/null
+++ b/debian/postrm
@@ -0,0 +1,175 @@
+#! /bin/sh
+# -*- Mode: Sh -*-
+# postrm ---
+# Author : Manoj Srivastava ( srivasta@glaurung.green-gryphon.com )
+# Created On : Fri Nov 14 12:22:20 2003
+# Created On Node : glaurung.green-gryphon.com
+# Last Modified By : Manoj Srivastava
+# Last Modified On : Sat Nov 29 01:54:26 2003
+# Last Machine Used: glaurung.green-gryphon.com
+# Update Count : 10
+# Status : Unknown, Use with caution!
+# HISTORY :
+# Description :
+#
+# arch-tag: 56802d51-d980-4822-85c0-28fce19ed430
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+
+# Abort if any command returns an error value
+set -e
+
+package_name=tome
+
+if [ -z "$package_name" ]; then
+ print >&2 "Internal Error. Please report a bug."
+ exit 1;
+fi
+
+# This script is called twice during the removal of the package; once
+# after the removal of the package's files from the system, and as
+# the final step in the removal of this package, after the package's
+# conffiles have been removed.
+# summary of how this script can be called:
+# * <postrm> `remove'
+# * <postrm> `purge'
+# * <old-postrm> `upgrade' <new-version>
+# * <new-postrm> `failed-upgrade' <old-version>
+# * <new-postrm> `abort-install'
+# * <new-postrm> `abort-install' <old-version>
+# * <new-postrm> `abort-upgrade' <old-version>
+# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+case "$1" in
+ remove)
+ # This package is being removed, but its configuration has not yet
+ # been purged.
+ :
+
+ # Remove diversion
+ ##: dpkg-divert --package ${package_name} --remove --rename \
+ ##: --divert /usr/bin/other.real /usr/bin/other
+
+ # ldconfig is NOT needed during removal of a library, only during
+ # installation
+
+ ;;
+ purge)
+ # This package has previously been removed and is now having
+ # its configuration purged from the system.
+ ##:
+
+ # we mimic dpkg as closely as possible, so we remove configuration
+ # files with dpkg backup extensions too:
+ ### Some of the following is from Tore Anderson:
+ ##: for ext in '~' '%' .bak .dpkg-tmp .dpkg-new .dpkg-old .dpkg-dist; do
+ ##: rm -f /etc/${package_name}.conf$ext
+ ##: done
+
+ if [ -d /var/lib/games/${package_name}/ ]; then
+ rm -rf /var/lib/games/${package_name}/
+ fi
+ if [ -d "/var/games/${package_name}" ]; then
+ rm -rf "/var/games/${package_name}"
+ fi
+
+ # remove the configuration file itself
+ ##: rm -f /etc/${package_name}.conf
+
+ # and finally clear it out from the ucf database
+ ##: ucf --purge /etc/${package_name}.conf
+
+ # Remove symlinks from /etc/rc?.d
+ ##: update-rc.d ${package_name} remove >/dev/null
+
+ ##: if [ -e /usr/share/debconf/confmodule ]; then
+ ##: # Purge this package's data from the debconf database.
+ ##: . /usr/share/debconf/confmodule
+ ##: db_purge
+ ##: fi
+
+ # This package has previously been removed and is now having
+ # its configuration purged from the system.
+ ##: for flavour in emacs20 emacs21; do
+ ##: STARTDIR=/etc/$flavour/site-start.d;
+ ##: STARTFILE="${package_name}-init.el";
+ ##: if [ -e "$STARTDIR/20$STARTFILE" ]; then
+ ##: rm -f "$STARTDIR/20$STARTFILE"
+ ##: fi
+ ##: done
+
+ ;;
+ disappear)
+ if test "$2" != overwriter; then
+ echo "$0: undocumented call to \`postrm $*'" 1>&2
+ exit 0
+ fi
+ # This package has been completely overwritten by package $3
+ # (version $4). All our files are already gone from the system.
+ # This is a special case: neither "prerm remove" nor "postrm remove"
+ # have been called, because dpkg didn't know that this package would
+ # disappear until this stage.
+ ##:
+
+ ;;
+ upgrade)
+ # About to upgrade FROM THIS VERSION to version $2 of this package.
+ # "prerm upgrade" has been called for this version, and "preinst
+ # upgrade" has been called for the new version. Last chance to
+ # clean up.
+ ##:
+
+ ;;
+ failed-upgrade)
+ # About to upgrade from version $2 of this package TO THIS VERSION.
+ # "prerm upgrade" has been called for the old version, and "preinst
+ # upgrade" has been called for this version. This is only used if
+ # the previous version's "postrm upgrade" couldn't handle it and
+ # returned non-zero. (Fix old postrm bugs here.)
+ ##:
+
+ ;;
+ abort-install)
+ # Back out of an attempt to install this package. Undo the effects of
+ # "preinst install...". There are two sub-cases.
+ ##:
+
+ if test "${2+set}" = set; then
+ # When the install was attempted, version $2's configuration
+ # files were still on the system. Undo the effects of "preinst
+ # install $2".
+ :
+
+ else
+ # We were being installed from scratch. Undo the effects of
+ # "preinst install".
+ :
+
+ fi ;;
+ abort-upgrade)
+ # Back out of an attempt to upgrade this package from version $2
+ # TO THIS VERSION. Undo the effects of "preinst upgrade $2".
+ ##:
+
+ ;;
+ *) echo "$0: didn't understand being called with \`$1'" 1>&2
+ exit 0;;
+esac
+#DEBHELPER#
+exit 0
diff --git a/debian/preinst b/debian/preinst
new file mode 100755
index 00000000..482380f0
--- /dev/null
+++ b/debian/preinst
@@ -0,0 +1,103 @@
+#! /bin/sh
+# -*- Mode: Sh -*-
+# preinst ---
+# Author : Manoj Srivastava ( srivasta@glaurung.green-gryphon.com )
+# Created On : Fri Nov 14 12:12:04 2003
+# Created On Node : glaurung.green-gryphon.com
+# Last Modified By : Manoj Srivastava
+# Last Modified On : Sat Nov 29 01:53:45 2003
+# Last Machine Used: glaurung.green-gryphon.com
+# Update Count : 6
+# Status : Unknown, Use with caution!
+# HISTORY :
+# Description :
+#
+# arch-tag: d6a3672d-acb3-4f6c-9984-bad17d8ce0aa
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+
+
+# Abort if any command returns an error value
+set -e
+
+package_name=tome
+
+if [ -z "$package_name" ]; then
+ print >&2 "Internal Error. Please report a bug."
+ exit 1;
+fi
+
+
+
+# This script is called before this version of this package is installed.
+# When this script is called, the package's files have not been unpacked
+# yet.
+
+case "$1" in
+ install)
+ # About to install this package.
+ ##:
+ if [ -L /var/games/${package_name}/data ]; then
+ rm /var/games/${package_name}/data
+ fi
+
+ if [ -d /usr/lib/${package_name}/data ]; then
+ rm -rf /usr/lib/${package_name}/data
+ fi
+
+ # Add a diversion. This is one of the few things which may be done
+ # before installing any files from the package.
+ #: dpkg-divert --package foo --add --rename \
+ ##: --divert /usr/bin/other.real /usr/bin/other
+
+ # There are two sub-cases:
+ if test "${2+set}" = set; then
+ # The configuration files from version $2 of this package are
+ # still on the system.
+ :
+
+ else
+ # There is no existing configuration; install from scratch.
+ :
+
+ fi ;;
+ upgrade)
+ # About to upgrade this package from version $2 TO THIS VERSION.
+ # "prerm upgrade" has already been called for the old version of
+ # this package.
+ ##:
+ if [ -L /var/games/${package_name}/data ]; then
+ rm /var/games/${package_name}/data
+ fi
+
+ if [ -d /usr/lib/${package_name}/data ]; then
+ rm -rf /usr/lib/${package_name}/data
+ fi
+
+ ;;
+ abort-upgrade)
+ # Back out of an attempt to upgrade this package FROM THIS VERSION to
+ # version $2. Undo the effects of "postrm upgrade $2".
+ :
+
+ ;;
+ *) echo "$0: didn't understand being called with \`$1'" 1>&2
+ exit 0;;
+esac
+#DEBHELPER#
+
+exit 0
diff --git a/debian/prerm b/debian/prerm
new file mode 100755
index 00000000..d6b5bd27
--- /dev/null
+++ b/debian/prerm
@@ -0,0 +1,133 @@
+#! /bin/sh
+# -*- Mode: Sh -*-
+# prerm ---
+# Author : Manoj Srivastava ( srivasta@glaurung.green-gryphon.com )
+# Created On : Fri Nov 14 12:16:39 2003
+# Created On Node : glaurung.green-gryphon.com
+# Last Modified By : Manoj Srivastava
+# Last Modified On : Sun Mar 14 12:19:51 2004
+# Last Machine Used: glaurung.internal.golden-gryphon.com
+# Update Count : 11
+# Status : Unknown, Use with caution!
+# HISTORY :
+# Description :
+#
+# arch-tag: a4c1a888-137d-4800-98f8-93d0365422d8
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+
+# Abort if any command returns an error value
+set -e
+
+package_name=tome
+
+if [ -z "$package_name" ]; then
+ print >&2 "Internal Error. Please report a bug."
+ exit 1;
+fi
+
+
+# This script is called as the first step in removing the package from
+# the system. This includes cases where the user explicitly asked for
+# the package to be removed, upgrade, automatic removal due to conflicts,
+# and deconfiguration due to temporary removal of a depended-on package.
+
+# Info files should be uninstalled from the dir file in any case.
+##: install-info --quiet --remove /usr/info/${package_name}.info
+
+case "$1" in
+ remove)
+ # This package about to be removed.
+ ##:
+ if [ -L /usr/doc/$package_name ]; then
+ rm -f /usr/doc/$package_name
+ fi
+
+ # Remove package-specific directories from /usr/local. Don't try
+ # to remove standard directories such as /usr/local/lib.
+ ##: if test -d /usr/local/lib/${package_name}; then
+ ##: rmdir /usr/local/lib/${package_name} || true
+ ##: fi
+
+ # Deactivate menu-methods script.
+ ##: chmod a-x /etc/menu-methods/${package_name}
+
+ # Withdraw our version of a program.
+ ##: update-alternatives --remove program /usr/bin/alternative
+
+ # Get rid of the installed docs
+ ##: if which install-docs >/dev/null 2>&1; then
+ ##: install-docs -r $package_name
+ ##: fi
+
+ # Get rid of the byte compiled files
+ ##: if [ -x /usr/lib/emacsen-common/emacs-package-remove ]; then
+ ##: /usr/lib/emacsen-common/emacs-package-remove $package_name
+ ##: fi
+
+ if [ -L /usr/doc/$package_name ]; then
+ rm -f /usr/doc/$package_name
+ fi
+
+ # There are two sub-cases:
+ if test "${2+set}" = set; then
+ if test "$2" != in-favour; then
+ echo "$0: undocumented call to \`prerm $*'" 1>&2
+ exit 0
+ fi
+ # We are being removed because of a conflict with package $3
+ # (version $4), which is now being installed.
+ :
+
+ else
+ # The package is being removed in its own right.
+ :
+
+ fi ;;
+ deconfigure)
+ if test "$2" != in-favour || test "$5" != removing; then
+ echo "$0: undocumented call to \`prerm $*'" 1>&2
+ exit 0
+ fi
+ # Package $6 (version $7) which we depend on is being removed due
+ # to a conflict with package $3 (version $4), and this package is
+ # being deconfigured until $6 can be reinstalled.
+ :
+
+ ;;
+ upgrade)
+ # Prepare to upgrade FROM THIS VERSION of this package to version $2.
+ ##:
+
+ if [ -L /usr/doc/$package_name ]; then
+ rm -f /usr/doc/$package_name
+ fi
+
+ ;;
+ failed-upgrade)
+ # Prepare to upgrade from version $2 of this package TO THIS VERSION.
+ # This is only used if the old version's prerm couldn't handle it,
+ # and returned non-zero. (Fix old prerm bugs here.)
+ :
+
+ ;;
+ *) echo "$0: didn't understand being called with \`$1'" 1>&2
+ exit 0;;
+esac
+#DEBHELPER#
+
+exit 0
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 00000000..7e771906
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,87 @@
+#!/usr/bin/make -f
+# Uncomment this to turn on verbose mode.
+# export DH_VERBOSE=1
+package:=tome
+SRCTOP:= $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+INSTALL = install
+ifeq (,$(filter nostrip,$(DEB_BUILD_OPTIONS)))
+ INSTALL_PROGRAM += -s
+endif
+install_file = $(INSTALL) -p -o root -g root -m 644
+install_program = $(INSTALL) -p -o root -g root -m 755
+install_script = $(INSTALL) -p -o root -g root -m 755
+make_directory = $(INSTALL) -p -d -o root -g root -m 755
+PREFIX=/usr
+
+## libdir should be /var/lib/games/$(package)/
+LIBDIR = /var/games/$(package)
+BINDIR = $(PREFIX)/bin
+MANDIR = $(PREFIX)/share/man
+MAN1DIR = $(MANDIR)/man1
+MAN6DIR = $(MANDIR)/man6
+DOCDIR = $(PREFIX)/share/doc/$(package)
+INFODIR = $(PREFIX)/share/info
+
+TMPTOP = $(SRCTOP)/debian/$(package)
+PKG_LIBDIR = $(TMPTOP)/$(LIBDIR)
+PKG_BIN = $(TMPTOP)$(BINDIR)
+PKG_MANDIR = $(TMPTOP)$(MANDIR)
+PKG_DOC = $(TMPTOP)$(DOCDIR)
+PKG_INFO = $(TMPTOP)$(INFODIR)
+PKG_MENU = $(TMPTOP)$(PREFIX)/lib/menu
+PKG_DBASE = $(TMPTOP)$(PREFIX)/share/doc-base
+PKG_MAN = $(PKG_MANDIR)/man6
+PKG_MENUDIR= $(TMPTOP)$(PREFIX)/share/menu
+PKG_STATLIB= $(TMPTOP)$(PREFIX)/lib/$(package)
+
+DPKG_ARCH := dpkg-architecture
+export DEB_HOST_MULTIARCH := $(shell $(DPKG_ARCH) $(ha) -qDEB_HOST_MULTIARCH)
+
+%:
+ dh $@
+
+override_dh_auto_configure:
+ dh_auto_configure -- -DSYSTEM_INSTALL:BOOL=true
+
+override_dh_auto_build:
+ bash -n debian/postinst
+ bash -n debian/postrm
+ bash -n debian/prerm
+ bash -n debian/preinst
+ bash -n debian/Tome.sh
+
+override_dh_install:
+ $(make_directory) $(TMPTOP)/etc/$(package) $(PKG_STATLIB)
+ chmod 0644 $(PKG_LIBDIR)/edit/s_factory.map
+ chmod 0644 $(PKG_LIBDIR)/edit/s_ship.map
+ (cd $(PKG_LIBDIR); mv edit file pref $(TMPTOP)/etc/$(package); \
+ ln -s /etc/$(package)/edit . ; \
+ ln -s /etc/$(package)/file . ; \
+ ln -s /etc/$(package)/pref . ; )
+ (cd $(PKG_LIBDIR); mv help $(PKG_STATLIB); \
+ ln -s $(PREFIX)/lib/$(package)/help . ; )
+ for i in save/delete.me ; do \
+ mkdir -p $(PKG_LIBDIR)/save \
+ chmod 0644 $(PKG_LIBDIR)/$$i; \
+ done
+ rm -f $(PKG_LIBDIR)/apex/scores.raw
+ find $(PKG_LIBDIR) -type f -name .cvsignore -exec rm {} \;
+
+override_dh_fixperms:
+ dh_fixperms
+ chgrp -R games $(TMPTOP)/etc/$(package)/* $(PKG_STATLIB)/* $(PKG_LIBDIR) \
+ $(TMPTOP)/usr/games/tome
+ chmod g+ws $(PKG_LIBDIR)/data/
+ chmod g+s $(TMPTOP)/usr/games/tome
+
+override_dh_clean:
+ dh_clean
+ touch ./lib/apex/delete.me
+ touch ./lib/data/delete.me
+ touch ./lib/info/delete.me
+ touch ./lib/save/delete.me
+ touch ./lib/user/delete.me
+
+#Local variables:
+#mode: makefile
+#End:
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 00000000..163aaf8d
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/tome.docs b/debian/tome.docs
new file mode 100644
index 00000000..613091a0
--- /dev/null
+++ b/debian/tome.docs
@@ -0,0 +1,3 @@
+debian/README.debian
+debian/NEWS.Debian
+debian/Xresources
diff --git a/debian/tome.menu b/debian/tome.menu
new file mode 100644
index 00000000..b2e6f56e
--- /dev/null
+++ b/debian/tome.menu
@@ -0,0 +1,90 @@
+?package(tome):needs="text" section="Games/Adventure" title="Tome" \
+ longtitle="A single-player, text-based, dungeon simulation." \
+ description="Tome, short for Troubles of Middle Earth, is a single-player, \
+ text-based, dungeon simulation derived from the game angband, which \
+ in turn is derived from the older game Moria, which was in turn based \
+ on Rogue. It is often described as a \"roguelike\" game because the \
+ look and feel of the game is still quite similar to Rogue. \
+ \
+ In tome, the player may choose from a number of races and classes \
+ when creating a character, and then \"run\" that character over a \
+ period of days, weeks, even months, attempting to win the game by \
+ defeating Morgoth, who lurks somewhere in the depths of the dungeon. \
+ \
+ The ultimate goal of the game is to develop a character strong enough \
+ to defeat Morgoth, who resides on dungeon level 100. Upon doing so, \
+ you will receive the exalted status of \"winner\" and your character may \
+ retire. \
+ \
+ The first main difference from Angband a new player to ToME will need \
+ to be aware of is that it has implemented a skills based system where \
+ instead of the adventurer automatically improving in their abilities \
+ as they become more experienced, they get 5 skill points to spend on \
+ their character's abilities and can therefore customise what type of \
+ character they play. See the skills help file for details \
+ \
+ The second major difference is that the main dungeon from Angband has \
+ been split into 4 \"dungeons\", each of which cover a different \
+ portion of the dungeon's levels. Note that not all of the places are \
+ actually \"dungeons\" - some are caves, forests, etc. \
+ \
+ The third main difference between Vanilla Angband and ToME is the \
+ difference in character classes and races, as well as a very \
+ different magic system. ToME also offers the player the ability to \
+ undertake a series of quests. It is not required for any adventurer \
+ to undertake the fixed quests, but they can result in some nice \
+ rewards. \
+ \
+ Morgoth was 'the Dark Enemy of Middle-Earth' during its First Age. He \
+ was banished by the Valar (offspring of Eru, \"god\" of J.R.R. \
+ Tolkien's world) at the end of the First Age and thus never appears \
+ in The Lord of the Rings, set during the Third Age. Sauron, who does \
+ figure into those tales, was the most powerful of his servants. Read \
+ Tolkien's 'The Silmarillion' for more on the legends of Middle-Earth. \
+ Angband is a reference to Morgoth's \"prison of iron.\"" \
+ command="/usr/games/tome"
+?package(tome):needs="X11" section="Games/Adventure" title="Tome"\
+ longtitle="A single-player, text-based, dungeon simulation." \
+ description="Tome, short for Troubles of Middle Earth, is a single-player, \
+ text-based, dungeon simulation derived from the game angband, which \
+ in turn is derived from the older game Moria, which was in turn based \
+ on Rogue. It is often described as a \"roguelike\" game because the \
+ look and feel of the game is still quite similar to Rogue. \
+ \
+ In tome, the player may choose from a number of races and classes \
+ when creating a character, and then \"run\" that character over a \
+ period of days, weeks, even months, attempting to win the game by \
+ defeating Morgoth, who lurks somewhere in the depths of the dungeon. \
+ \
+ The ultimate goal of the game is to develop a character strong enough \
+ to defeat Morgoth, who resides on dungeon level 100. Upon doing so, \
+ you will receive the exalted status of \"winner\" and your character may \
+ retire. \
+ \
+ The first main difference from Angband a new player to ToME will need \
+ to be aware of is that it has implemented a skills based system where \
+ instead of the adventurer automatically improving in their abilities \
+ as they become more experienced, they get 5 skill points to spend on \
+ their character's abilities and can therefore customise what type of \
+ character they play. See the skills help file for details \
+ \
+ The second major difference is that the main dungeon from Angband has \
+ been split into 4 \"dungeons\", each of which cover a different \
+ portion of the dungeon's levels. Note that not all of the places are \
+ actually \"dungeons\" - some are caves, forests, etc. \
+ \
+ The third main difference between Vanilla Angband and ToME is the \
+ difference in character classes and races, as well as a very \
+ different magic system. ToME also offers the player the ability to \
+ undertake a series of quests. It is not required for any adventurer \
+ to undertake the fixed quests, but they can result in some nice \
+ rewards. \
+ \
+ Morgoth was 'the Dark Enemy of Middle-Earth' during its First Age. He \
+ was banished by the Valar (offspring of Eru, \"god\" of J.R.R. \
+ Tolkien's world) at the end of the First Age and thus never appears \
+ in The Lord of the Rings, set during the Third Age. Sauron, who does \
+ figure into those tales, was the most powerful of his servants. Read \
+ Tolkien's 'The Silmarillion' for more on the legends of Middle-Earth. \
+ Angband is a reference to Morgoth's \"prison of iron.\"" \
+ command="/usr/games/tome"
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 00000000..bbfe26ba
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,5 @@
+# format version number, currently 2; this line is compulsory!
+version=3
+
+opts="uversionmangle=s/(\d)(\d)(\d)/$1.$2.$3/g" http://t-o-m-e.net/dl/src/tome-(2.*)-src.tar.bz2
+
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100644
index 00000000..44d7d1ee
--- /dev/null
+++ b/lib/CMakeLists.txt
@@ -0,0 +1,25 @@
+INSTALL(FILES
+ module.lua
+ DESTINATION ${DEFAULT_PATH}
+)
+INSTALL(DIRECTORY
+ apex
+ cmov
+ core
+ data
+ dngn
+ edit
+ file
+ help
+ info
+ mods
+ note
+ pref
+ save
+ scpt
+ user
+ xtra
+ DESTINATION ${DEFAULT_PATH}
+ PATTERN "*.raw" EXCLUDE
+ PATTERN "delete.me" EXCLUDE
+ )
diff --git a/lib/apex/.cvsignore b/lib/apex/.cvsignore
new file mode 100644
index 00000000..dfa43964
--- /dev/null
+++ b/lib/apex/.cvsignore
@@ -0,0 +1 @@
+scores.raw
diff --git a/lib/apex/delete.me b/lib/apex/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/apex/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/cmov/delete.me b/lib/cmov/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/cmov/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/core/auto.lua b/lib/core/auto.lua
new file mode 100644
index 00000000..b758db52
--- /dev/null
+++ b/lib/core/auto.lua
@@ -0,0 +1,859 @@
+-- This file is the core of the Automatizer
+-- Please do not touch unless you know what you are doing
+
+__rules = {}
+__rules_max = 0
+
+rule_aux = {}
+
+-- Rule apply function, does .. nothing
+function auto_nothing(obj, item)
+ return
+end
+
+function auto_inscribe(obj, item, note)
+ if obj.note ~= 0 then return end
+ msg_print("<Auto-Inscribe {"..note.."}>")
+ obj.note = quark_add(note)
+ return TRUE
+end
+
+-- Rule apply function, pickup object
+function auto_pickup(obj, item)
+ if item >= 0 then return end
+ if inven_carry_okay(obj) == FALSE then return end
+ msg_print("<Auto-pickup>")
+ object_pickup(-item)
+ return TRUE
+end
+
+-- Rule apply function, destroy item
+function auto_destroy(obj, item)
+ -- be carefull to what we can destroy
+ -- Unaware things won't be destroyed.
+ if is_aware(obj) == FALSE then return end
+
+ -- Inscribed things won't be destroyed!
+ if obj.note ~= 0 then return end
+
+ -- Keep Artifacts -- they cannot be destroyed anyway
+ if is_artifact(obj) == TRUE then return end
+
+ -- Cannot destroy CURSE_NO_DROP objects
+ local f1, f2, f3, f4, f5, esp = object_flags(obj);
+ if band(f4, TR4_CURSE_NO_DROP) ~= 0 and band(obj.ident, IDENT_CURSED) then return end
+
+ msg_print("<Auto-destroy>")
+
+ -- Eliminate the item (from the pack)
+ if item >= 0 then
+ inven_item_increase(item, -obj.number)
+ inven_item_describe(item)
+ inven_item_optimize(item)
+ -- Eliminate the item (from the floor)
+ else
+ floor_item_increase(0 - item, -obj.number)
+ floor_item_describe(0 - item)
+ floor_item_optimize(0 - item)
+ end
+ return TRUE
+end
+
+-- Report the status of an object
+function object_status(obj)
+ local sense =
+ {
+ [SENSE_CURSED] = "bad",
+ [SENSE_WORTHLESS] = "very bad",
+ [SENSE_AVERAGE] = "average",
+ [SENSE_GOOD_LIGHT] = "good",
+ [SENSE_GOOD_HEAVY] = "good",
+ [SENSE_EXCELLENT] = "very good",
+ [SENSE_SPECIAL] = "special",
+ [SENSE_TERRIBLE] = "terrible",
+ }
+
+ if is_known(obj) == FALSE then
+ if sense[obj.sense] then
+ return sense[obj.sense]
+ else
+ return ""
+ end
+ else
+if nil then -- test
+ local osense = -1
+ local type = select_sense(obj, TRUE, TRUE)
+ if type == 1 then
+ osense = value_check_aux1(obj)
+ elseif type == 2 then
+ osense = value_check_aux1_magic(obj)
+ end
+print("type : "..type)
+ if sense[osense] then
+ print("sense: "..sense[osense])
+ return sense[osense]
+ else
+ print("sense: ")
+ return ""
+ end
+
+else -- the real one
+
+ local slot = wield_slot_ideal(obj, TRUE)
+
+ -- Arts items
+ if is_artifact(obj) == TRUE then
+ if band(obj.ident, IDENT_CURSED) == 0 then return "special"
+ else return "terrible" end
+ -- Ego items
+ elseif (obj.name2 > 0 or obj.name2b > 0) then
+ if band(obj.ident, IDENT_CURSED) == 0 then return "very good"
+ else return "very bad" end
+ -- weapon
+ elseif (slot == INVEN_WIELD) or (slot == INVEN_BOW) or (slot == INVEN_AMMO) or (slot == INVEN_TOOL) then
+ if obj.to_h + obj.to_d < 0 then
+ return "bad"
+ elseif obj.to_h + obj.to_d > 0 then
+ return "good"
+ else
+ return "average"
+ end
+ -- armor
+ elseif (slot >= INVEN_BODY) and (slot <= INVEN_FEET) then
+ if obj.to_a < 0 then
+ return "bad"
+ elseif obj.to_a > 0 then
+ return "good"
+ else
+ return "average"
+ end
+ -- ring
+ elseif slot == INVEN_RING then
+ if (obj.to_d + obj.to_h < 0) or (obj.to_a < 0) or (obj.pval < 0) then
+ return "bad"
+ else
+ return "average"
+ end
+ -- amulet
+ elseif slot == INVEN_NECK then
+ if (obj.pval < 0) then
+ return "bad"
+ else
+ return "average"
+ end
+ -- chests
+ elseif obj.tval == TV_CHEST then
+ if obj.pval == 0 then
+ return "empty"
+ elseif obj.pval < 0 then
+ return "disarmed"
+ else
+ return "average"
+ end
+ else
+ return "average"
+ end
+end
+ end
+end
+
+-- Recursive function to generate a rule function tree
+function gen_rule_fct(r)
+ -- It is a test rule (or, and, ...)
+ if r.label == "and" or r.label == "or" then
+ local i
+ local fct_tbl = {}
+ for i = 1, getn(r) do
+ if r[i].label ~= "comment" then
+ tinsert(fct_tbl, gen_rule_fct(r[i]))
+ end
+ end
+ if r.label == "and" then
+ return function(object)
+ local fcts = %fct_tbl
+ local i
+ for i = 1, getn(fcts) do
+ if not fcts[i](object) then return end
+ end
+ return TRUE
+ end
+ elseif r.label == "or" then
+ return function(object)
+ local fcts = %fct_tbl
+ local i
+ for i = 1, getn(fcts) do
+ if fcts[i](object) then return TRUE end
+ end
+ end
+ end
+ -- It is a condition rule (name, type, level, ...)
+ else
+ if r.label == "not" then
+ local f
+ if not r[1] then
+ f = function (object) return TRUE end
+ else
+ f = gen_rule_fct(r[1])
+ end
+ return function(object) return not %f(object) end
+ elseif r.label == "inventory" then
+ local f
+ if not r[1] then
+ f = function(object) return end
+ else
+ f = gen_rule_fct(r[1])
+ end
+ return function(object)
+ local i = 0
+ while i < INVEN_WIELD do
+ if %f(player.inventory(i)) then
+ return TRUE
+ end
+ i = i + 1
+ end
+ end
+ elseif r.label == "equipment" then
+ local f
+ if not r[1] then
+ f = function(object) return end
+ else
+ f = gen_rule_fct(r[1])
+ end
+ return function(object)
+ local i = INVEN_WIELD
+ while i < INVEN_TOTAL do
+ if %f(player.inventory(i)) then
+ return TRUE
+ end
+ i = i + 1
+ end
+ end
+ elseif r.label == "name" then
+ return function(object) if strlower(object_desc(object, -1, 0)) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "contain" then
+ return function(object) if strfind(strlower(object_desc(object, -1, 0)), strlower(%r[1])) then return TRUE end end
+ elseif r.label == "symbol" then
+ return function(object) if strchar(get_kind(object).d_char) == %r[1] then return TRUE end end
+ elseif r.label == "inscribed" then
+ return function(object) if object.note ~= 0 and strfind(strlower(quark_str(object.note)), strlower(%r[1])) then return TRUE end end
+ elseif r.label == "discount" then
+ local d1 = r.args.min
+ local d2 = r.args.max
+ if tonumber(d1) == nil then d1 = getglobal(d1) else d1 = tonumber(d1) end
+ if tonumber(d2) == nil then d2 = getglobal(d2) else d2 = tonumber(d2) end
+ return function(object) if is_aware(object) == TRUE and object.discount >= %d1 and object.discount <= %d2 then return TRUE end end
+ elseif r.label == "tval" then
+ local tv = r[1]
+ if tonumber(tv) == nil then tv = getglobal(tv) else tv = tonumber(tv) end
+ return function(object) if object.tval == %tv then return TRUE end end
+ elseif r.label == "sval" then
+ assert(r.args.min and r.args.max, "sval rule lacks min or max")
+ local sv1 = r.args.min
+ local sv2 = r.args.max
+ if tonumber(sv1) == nil then sv1 = getglobal(sv1) else sv1 = tonumber(sv1) end
+ if tonumber(sv2) == nil then sv2 = getglobal(sv2) else sv2 = tonumber(sv2) end
+ return function(object) if is_aware(object) == TRUE and object.sval >= %sv1 and object.sval <= %sv2 then return TRUE end end
+ elseif r.label == "status" then
+ return function(object) if object_status(object) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "state" then
+ if r[1] == "identified" then
+ return function(object) if is_known(object) == TRUE then return TRUE end end
+ else
+ return function(object) if is_known(object) == FALSE then return TRUE end end
+ end
+ elseif r.label == "race" then
+ return function(object) if strlower(get_race_name()) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "subrace" then
+ return function(object) if strlower(get_subrace_name()) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "class" then
+ return function(object) if strlower(get_class_name()) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "level" then
+ assert(r.args.min and r.args.max, "level rule lacks min or max")
+ return function(object) if player.lev >= tonumber(%r.args.min) and player.lev <= tonumber(%r.args.max) then return TRUE end end
+ elseif r.label == "skill" then
+ assert(r.args.min and r.args.max, "skill rule lacks min or max")
+ local s = find_skill_i(r[1])
+ assert(s ~= -1, "no skill "..r[1])
+ return function(object) if get_skill(%s) >= tonumber(%r.args.min) and get_skill(%s) <= tonumber(%r.args.max) then return TRUE end end
+ elseif r.label == "ability" then
+ local s = find_ability(r[1])
+ assert(s ~= -1, "no ability "..r[1])
+ return function(object) if has_ability(%s) == TRUE then return TRUE end end
+ end
+ end
+end
+
+function auto_inscribe_maker(inscription)
+ return function(...)
+ arg.n = arg.n + 1
+ arg[getn(arg)] = %inscription
+ return call(auto_inscribe, arg)
+ end
+end
+
+-- Generate a rule from a table
+function gen_full_rule(t)
+ -- only honor rules for this module
+ if not t.args.module then
+ t.args.module = "ToME"
+ end
+
+ if not ((t.args.module == "all") or (t.args.module == game_module)) then
+ return function() end
+ end
+
+ -- Check for which action to do
+ local apply_fct = auto_nothing
+ if t.args.type == "destroy" then apply_fct = auto_destroy
+ elseif t.args.type == "pickup" then apply_fct = auto_pickup
+ elseif t.args.type == "inscribe" then apply_fct = auto_inscribe_maker(t.args.inscription)
+ end
+
+ -- create the function tree
+ local rf
+ if t[1] then
+ rf = gen_rule_fct(t[1])
+ else
+ rf = function (object) end
+ end
+
+ -- create the final function
+ return function(...)
+ local rf = %rf
+ if rf(arg[1]) then
+ if call(%apply_fct, arg) == TRUE then return TRUE end
+ end
+ end
+end
+
+-- Create a function that checks for the rules(passed in xml form)
+function add_ruleset(s)
+ local tbl = xml:collect(s)
+ local i
+
+ -- Add all rules
+ for i = 1, getn(tbl) do
+ local t = tbl[i]
+
+ if t.label == "rule" then
+ -- Create the function tree
+ local fct = gen_full_rule(t)
+
+ -- Create the test function
+ __rules[__rules_max] =
+ {
+ ["table"] = t,
+ ["fct"] = fct
+ }
+ __rules_max = __rules_max + 1
+ end
+ end
+end
+
+-- Apply the current rules to an object
+-- call with at least (object, idx)
+function apply_rules(...)
+ local i
+ for i = 0, __rules_max - 1 do
+ if call(__rules[i].fct, arg) then return TRUE end
+ end
+ return FALSE
+end
+
+-- Clear the current rules
+function clean_ruleset()
+ __rules_max = 0
+ __rules = {}
+end
+
+------ helper fonctions for the GUI
+
+auto_aux = {}
+auto_aux.stack = { n = 0 }
+auto_aux.idx = 1
+auto_aux.rule = 1
+function auto_aux:go_right()
+ if auto_aux.rule[1] and type(auto_aux.rule[1]) == "table" then
+ tinsert(auto_aux.stack, auto_aux.idx)
+ tinsert(auto_aux.stack, auto_aux.rule)
+ auto_aux.rule = auto_aux.rule[1]
+ auto_aux.idx = 1
+ end
+end
+
+function auto_aux:go_left(sel)
+ local n = getn(auto_aux.stack)
+
+ if n > 0 then
+ auto_aux.idx = auto_aux.stack[n - 1]
+ auto_aux.rule = auto_aux.stack[n]
+ tremove(auto_aux.stack)
+ tremove(auto_aux.stack)
+ end
+end
+
+function auto_aux:go_down()
+ if getn(auto_aux.stack) > 1 then
+ if auto_aux.stack[getn(auto_aux.stack)][auto_aux.idx + 1] then
+ auto_aux.idx = auto_aux.idx + 1
+ auto_aux.rule = auto_aux.stack[getn(auto_aux.stack)][auto_aux.idx]
+ end
+ end
+end
+
+function auto_aux:go_up()
+ if getn(auto_aux.stack) > 1 then
+ if auto_aux.stack[getn(auto_aux.stack)][auto_aux.idx - 1] then
+ auto_aux.idx = auto_aux.idx - 1
+ auto_aux.rule = auto_aux.stack[getn(auto_aux.stack)][auto_aux.idx]
+ end
+ end
+end
+
+function auto_aux:scroll_up()
+ xml.write_off_y = xml.write_off_y - 1
+end
+
+function auto_aux:scroll_down()
+ xml.write_off_y = xml.write_off_y + 1
+end
+
+function auto_aux:scroll_left()
+ xml.write_off_x = xml.write_off_x + 1
+end
+
+function auto_aux:scroll_right()
+ xml.write_off_x = xml.write_off_x - 1
+end
+
+function auto_aux:adjust_current(sel)
+ if __rules_max == 0 then return end
+
+ xml.write_off_y = 0
+ xml.write_off_x = 0
+ auto_aux.idx = 1
+ auto_aux.stack = { n = 0 }
+ auto_aux.rule = __rules[sel].table
+end
+
+function auto_aux:move_up(sel)
+ if sel > 0 then
+ local u = __rules[sel - 1]
+ local d = __rules[sel]
+ __rules[sel - 1] = d
+ __rules[sel] = u
+ return sel - 1
+ end
+ return sel
+end
+
+function auto_aux:move_down(sel)
+ if sel < __rules_max - 1 then
+ local u = __rules[sel]
+ local d = __rules[sel + 1]
+ __rules[sel + 1] = u
+ __rules[sel] = d
+ return sel + 1
+ end
+ return sel
+end
+
+function auto_aux:new_rule(sel, nam, typ, arg)
+ local r
+
+
+ -- nam can also directly be the table itself
+ if type(nam) == "table" then
+ r =
+ {
+ ["table"] = nam,
+ ["fct"] = function (object) end
+ }
+ elseif typ == "inscribe" then
+ if arg == "" then
+ arg = input_box("Inscription?", 79)
+ end
+ r =
+ {
+ ["table"] =
+ {
+ label = "rule",
+ args = { name = nam, type = typ, inscription = arg, module = game_module },
+ },
+ ["fct"] = function (object) end
+ }
+ else
+ r =
+ {
+ ["table"] =
+ {
+ label = "rule",
+ args = { name = nam, type = typ, module = game_module },
+ },
+ ["fct"] = function (object) end
+ }
+ end
+ tinsert(__rules, sel, r)
+ __rules_max = __rules_max + 1
+end
+
+function auto_aux:rename_rule(sel, nam)
+ if sel >= 0 and sel < __rules_max then
+ __rules[sel].table.args.name = nam
+ end
+end
+
+function auto_aux:save_ruleset()
+ xml.write = xml.write_file
+
+ print_hook("clean_ruleset()\nadd_ruleset\n[[\n")
+ local i
+ for i = 0, __rules_max - 1 do
+ xml:print_xml(__rules[i].table, '')
+ end
+ print_hook("]]\n")
+
+ xml.write = xml.write_screen
+end
+
+function auto_aux:del_self(sel)
+ if auto_aux.rule.label == "rule" then
+ tremove(__rules, sel)
+ __rules_max = __rules_max - 1
+ return sel - 1
+ else
+ local idx = auto_aux.idx
+ auto_aux:go_left(sel)
+ tremove(auto_aux.rule, idx)
+ return sel
+ end
+end
+
+auto_aux.types_desc =
+{
+ ["and"] =
+ {
+ "Check is true if all rules within it are true",
+ xml:collect([[<and><foo1>...</foo1><foo2>...</foo2><foo3>...</foo3></and>]]),
+ function ()
+ return xml:collect("<and></and>")
+ end,
+ },
+ ["or"] =
+ {
+ "Check is true if at least one rule within it is true",
+ xml:collect([[<or><foo1>...</foo1><foo2>...</foo2><foo3>...</foo3></or>]]),
+ function ()
+ return xml:collect("<or></or>")
+ end,
+ },
+ ["not"] =
+ {
+ "Invert the result of its child rule",
+ xml:collect([[<not><foo1>...</foo1></not>]]),
+ function ()
+ return xml:collect("<not></not>")
+ end,
+ },
+ ["comment"] =
+ {
+ "Comments are meaningless",
+ xml:collect([[<comment>Comment explaining something</comment>]]),
+ function ()
+ local n = input_box("Comment?", 79)
+ if n == "" then return end
+ return xml:collect("<comment>"..n.."</comment>")
+ end,
+ },
+ ["name"] =
+ {
+ "Check is true if object name matches name",
+ xml:collect([[<name>potion of healing</name>]]),
+ function ()
+ local n = input_box("Object name to match?", 79)
+ if n == "" then return end
+ return xml:collect("<name>"..n.."</name>")
+ end,
+ },
+ ["contain"] =
+ {
+ "Check is true if object name contains word",
+ xml:collect([[<contain>healing</contain>]]),
+ function ()
+ local n = input_box("Word to find in object name?", 79)
+ if n == "" then return end
+ return xml:collect("<contain>"..n.."</contain>")
+ end,
+ },
+ ["inscribed"] =
+ {
+ "Check is true if object inscription contains word",
+ xml:collect([[<inscribed>=g</inscribed>]]),
+ function ()
+ local n = input_box("Word to find in object inscription?", 79)
+ if n == "" then return end
+ return xml:collect("<inscribed>"..n.."</inscribed>")
+ end,
+ },
+ ["discount"] =
+ {
+ "Check is true if object discount is between 2 values",
+ xml:collect([[<sval min='50' max='100'></sval>]]),
+ function ()
+ local s = "<discount "
+
+ local n = input_box("Min discount?", 79)
+ if n == "" then return end
+ s = s.."min='"..n.."' "
+
+ n = input_box("Max discount?", 79)
+ if n == "" then return end
+ s = s.."max='"..n.."'></discount>"
+ return xml:collect(s)
+ end,
+ },
+ ["symbol"] =
+ {
+ "Check is true if object symbol is ok",
+ xml:collect([[<symbol>!</symbol>]]),
+ function ()
+ local n = input_box("Symbol to match?", 1)
+ if n == "" then return end
+ return xml:collect("<symbol>"..n.."</symbol>")
+ end,
+ },
+ ["status"] =
+ {
+ "Check is true if object status is ok",
+ xml:collect([[<status>good</status>]]),
+ function ()
+ local n = msg_box("[t]errible, [v]ery bad, [b]ad, [a]verage, [G]ood, [V]ery good, [S]pecial?")
+ local t =
+ {
+ ["t"] = "terrible",
+ ["v"] = "very bad",
+ ["b"] = "bad",
+ ["a"] = "average",
+ ["G"] = "good",
+ ["V"] = "very good",
+ ["S"] = "special",
+ }
+ if not t[strchar(n)] then return end
+ return xml:collect("<status>"..t[strchar(n)].."</status>")
+ end,
+ },
+ ["state"] =
+ {
+ "Check is true if object is identified/unidentified",
+ xml:collect([[<state>identified</state>]]),
+ function ()
+ local n = msg_box("[i]dentified, [n]on identified?")
+ local t =
+ {
+ ["i"] = "identified",
+ ["n"] = "not identified",
+ }
+ if not t[strchar(n)] then return end
+ return xml:collect("<state>"..t[strchar(n)].."</state>")
+ end,
+ },
+ ["tval"] =
+ {
+ "Check is true if object tval(from k_info.txt) is ok",
+ xml:collect([[<tval>55</tval>]]),
+ function ()
+ local n = input_box("Tval to match?", 79)
+ if n == "" then return end
+ return xml:collect("<tval>"..n.."</tval>")
+ end,
+ },
+ ["sval"] =
+ {
+ {
+ "Check is true if object sval(from k_info.txt) is between",
+ "2 values",
+ },
+ xml:collect([[<sval min='0' max='100'></sval>]]),
+ function ()
+ local s = "<sval "
+
+ local n = input_box("Min sval?", 79)
+ if n == "" then return end
+ s = s.."min='"..n.."' "
+
+ n = input_box("Max sval?", 79)
+ if n == "" then return end
+ s = s.."max='"..n.."'></sval>"
+ return xml:collect(s)
+ end,
+ },
+ ["race"] =
+ {
+ "Check is true if player race is ok",
+ xml:collect([[<race>dunadan</race>]]),
+ function ()
+ local n = input_box("Player race to match?", 79)
+ if n == "" then return end
+ return xml:collect("<race>"..n.."</race>")
+ end,
+ },
+ ["subrace"] =
+ {
+ "Check is true if player subrace is ok",
+ xml:collect([[<subrace>vampire</subrace>]]),
+ function ()
+ local n = input_box("Player subrace to match?", 79)
+ if n == "" then return end
+ return xml:collect("<subrace>"..n.."</subrace>")
+ end,
+ },
+ ["class"] =
+ {
+ "Check is true if player class is ok",
+ xml:collect([[<class>sorceror</class>]]),
+ function ()
+ local n = input_box("Player class to match?", 79)
+ if n == "" then return end
+ return xml:collect("<class>"..n.."</class>")
+ end,
+ },
+ ["level"] =
+ {
+ "Check is true if player level is between 2 values",
+ xml:collect([[<level min='20' max='50'></level>]]),
+ function ()
+ local s = "<level "
+
+ local n = input_box("Min player level?", 79)
+ if n == "" then return end
+ s = s.."min='"..n.."' "
+
+ n = input_box("Max player level?", 79)
+ if n == "" then return end
+ s = s.."max='"..n.."'></level>"
+
+ return xml:collect(s)
+ end,
+ },
+ ["skill"] =
+ {
+ "Check is true if player skill level is between 2 values",
+ xml:collect([[<skill min='10' max='20'>Divination</skill>]]),
+ function ()
+ local s = "<skill "
+
+ local n = input_box("Min skill level?", 79)
+ if n == "" then return end
+ s = s.."min='"..n.."' "
+
+ n = input_box("Max skill level?", 79)
+ if n == "" then return end
+ s = s.."max='"..n.."'>"
+
+ n = input_box("Skill name?", 79)
+ if n == "" then return end
+ if find_skill_i(n) == -1 then return end
+ s = s..n.."</skill>"
+
+ return xml:collect(s)
+ end,
+ },
+ ["ability"] =
+ {
+ "Check is true if player has the ability",
+ xml:collect([[<ability>Ammo creation</ability>]]),
+ function()
+ local n = input_box("Ability name?", 79)
+ if n == "" then return end
+ if find_ability(n) == -1 then return end
+ return xml:collect("<ability>"..n.."</ability>")
+ end,
+ },
+ ["inventory"] =
+ {
+ {
+ "Check is true if something in player's inventory matches",
+ "the contained rule",
+ },
+ xml:collect([[<inventory><foo1>...</foo1></inventory>]]),
+ function ()
+ return xml:collect("<inventory></inventory>")
+ end,
+ },
+ ["equipment"] =
+ {
+ {
+ "Check is true if something in player's equipment matches",
+ "the contained rule",
+ },
+ xml:collect([[<equipment><foo1>...</foo1></equipment>]]),
+ function ()
+ return xml:collect("<equipment></equipment>")
+ end,
+ },
+}
+
+function auto_aux:display_desc(sel)
+ local d = auto_aux.types_desc[sel][1]
+ if type(d) == "string" then
+ c_prt(TERM_WHITE, d, 1, 17)
+ else
+ local k, e, i
+ i = 0
+ for k, e in d do
+ c_prt(TERM_WHITE, e, 1 + i, 17)
+ i = i + 1
+ end
+ end
+end
+
+function auto_aux:add_child(sel)
+ -- <rule> and <not> contain only one match
+ if (auto_aux.rule.label == "rule" or auto_aux.rule.label == "not") and auto_aux.rule[1] then return end
+ if (auto_aux.rule.label == "rule" or auto_aux.rule.label == "equipment") and auto_aux.rule[1] then return end
+ if (auto_aux.rule.label == "rule" or auto_aux.rule.label == "inventory") and auto_aux.rule[1] then return end
+
+ -- Only <and> and <or> can contain
+ if auto_aux.rule.label ~= "rule" and auto_aux.rule.label ~= "and" and auto_aux.rule.label ~= "or" and auto_aux.rule.label ~= "not" and auto_aux.rule.label ~= "equipment" and auto_aux.rule.label ~= "inventory" then return end
+
+ -- get it
+ local r = auto_aux.types_desc[sel][3]()
+ if not r then return end
+
+ -- Ok add it
+ tinsert(auto_aux.rule, r[1])
+end
+
+function auto_aux.regen_ruleset()
+ local i
+ for i = 0, __rules_max - 1 do
+ __rules[i].fct = gen_full_rule(__rules[i].table)
+ end
+end
+
+
+-- Easily add new rules
+function easy_add_rule(typ, mode, do_status, obj)
+ local detect_rule
+
+ if mode == "tval" then
+ detect_rule = "<tval>"..obj.tval.."</tval>"
+ elseif mode == "tsval" then
+ detect_rule = "<and><tval>"..obj.tval.."</tval><sval min='"..obj.sval.."' max='"..obj.sval.."'></sval></and>"
+ elseif mode == "name" then
+ detect_rule = "<name>"..strlower(object_desc(obj, -1, 0)).."</name>"
+ end
+
+ if do_status == TRUE then
+ local status = object_status(obj)
+ if status and not (status == "") then
+ detect_rule = "<and>"..detect_rule.."<status>"..status.."</status></and>"
+ end
+ end
+
+ local rule = "<rule module='"..game_module.."' name='"..typ.."' type='"..typ.."'>"..detect_rule.."</rule>"
+ auto_aux:new_rule(0, xml:collect(rule)[1], '')
+ auto_aux.regen_ruleset()
+ msg_print("Rule added. Please go to the Automatizer screen (press = then T)")
+ msg_print("to save the modified ruleset.")
+end
diff --git a/lib/core/building.lua b/lib/core/building.lua
new file mode 100644
index 00000000..8e88888a
--- /dev/null
+++ b/lib/core/building.lua
@@ -0,0 +1,15 @@
+__building_actions = {}
+
+function add_building_action(a)
+ assert(a.index, "No building action index")
+ assert(a.action, "No building action action")
+ __building_actions[a.index] = a.action
+end
+
+function __bact_activate(bact)
+ if __building_actions[bact] then
+ return __building_actions[bact]()
+ end
+end
+
+add_hook_script(HOOK_BUILDING_ACTION, "__bact_activate", "__bact_activate")
diff --git a/lib/core/crpt_aux.lua b/lib/core/crpt_aux.lua
new file mode 100644
index 00000000..97f8d4b6
--- /dev/null
+++ b/lib/core/crpt_aux.lua
@@ -0,0 +1,182 @@
+-- Core functions for corruptions
+
+__corruptions = {}
+__corruptions_max = 0
+__corruptions_callbacks_max = 0
+
+-- Get the corruption
+function player.corruption(c, set)
+ if set then
+ player.corruptions_aux[c + 1] = set
+ player.redraw = bor(player.redraw, PR_BASIC)
+ player.update = bor(player.update, PU_BONUS, PU_TORCH, PU_BODY, PU_POWERS)
+ if (set == TRUE) and (__corruptions[c].gain) then
+ __corruptions[c].gain()
+ end
+ if (set == FALSE) and (__corruptions[c].lose) then
+ __corruptions[c].lose()
+ end
+ else
+ return player.corruptions_aux[c + 1]
+ end
+end
+
+-- Test if we have that corruption
+-- We must:
+-- 1) have it or be willing to get it
+-- 2) have all its dependancies
+-- 3) have none of its opposing corruptions
+-- 4) pass the possible tests
+function test_depend_corrupt(corrupt, can_gain)
+ local i, c
+
+ if not can_gain then can_gain = FALSE end
+
+ if can_gain == TRUE then
+ if (player.corruption(corrupt) ~= FALSE) then
+ return FALSE
+ end
+ else
+ if (player.corruption(corrupt) ~= TRUE) then
+ return FALSE
+ end
+ end
+
+ for c, i in __corruptions[corrupt].depends do
+ if test_depend_corrupt(c) ~= TRUE then
+ return FALSE
+ end
+ end
+
+ for c, i in __corruptions[corrupt].oppose do
+ if test_depend_corrupt(c) ~= FALSE then
+ return FALSE
+ end
+ end
+
+ -- are we even allowed to get it?
+ if __corruptions[corrupt].can_gain and (not __corruptions[corrupt].can_gain()) then
+ return FALSE
+ end
+
+ return TRUE
+end
+
+-- Gain a new corruption
+function gain_corruption(group)
+ local i, max
+ local pos = {}
+
+ -- Get the list of all possible ones
+ max = 0
+ for i = 0, __corruptions_max - 1 do
+ if __corruptions[i].group == group and test_depend_corrupt(i, TRUE) == TRUE and __corruptions[i].random == TRUE and __corruptions[i].allow() then
+ pos[max] = i
+ max = max + 1
+ end
+ end
+
+ -- Ok now get one of them
+ if (max > 0) then
+ local ret = rand_int(max)
+
+ player.corruption(pos[ret], TRUE)
+ cmsg_print(TERM_L_RED, __corruptions[pos[ret]].get_text)
+
+ return pos[ret]
+ else
+ return -1
+ end
+end
+
+-- Lose an existing corruption
+function lose_corruption()
+ local i, max
+ local pos = {}
+
+ -- Get the list of all possible ones
+ max = 0
+ for i = 0, __corruptions_max - 1 do
+ if test_depend_corrupt(i) == TRUE and __corruptions[i].removable == TRUE then
+ pos[max] = i
+ max = max + 1
+ end
+ end
+
+ -- Ok now get one of them
+ if (max > 0) then
+ local ret = rand_int(max)
+
+ player.corruption(pos[ret], FALSE)
+ cmsg_print(TERM_L_RED, __corruptions[pos[ret]].lose_text)
+
+ -- Ok now lets see if it broke some dependancies
+ for i = 0, max - 1 do
+ if player.corruption(pos[i]) ~= test_depend_corrupt(pos[i]) then
+ player.corruption(pos[i], FALSE)
+ cmsg_print(TERM_L_RED, __corruptions[pos[i]].lose_text)
+ end
+ end
+
+ return pos[ret]
+ else
+ return -1
+ end
+end
+
+-- Lose all corruptions (for e.g. Potion of New Life)
+function lose_all_corruptions()
+ local i;
+ for i = 0, __corruptions_max - 1 do
+ lose_corruption()
+ end
+ return -1
+end
+
+-- Creates a new corruption
+function add_corruption(c)
+ assert(c.color, "No corruption color")
+ assert(c.name, "No corruption name")
+ assert(c.get_text, "No corruption get_text")
+ assert(c.lose_text, "No corruption lose_text")
+ assert(c.desc, "No corruption desc")
+ assert(c.hooks, "Nothing to do for corruption")
+ if not c.random then c.random = TRUE end
+ if not c.removable then c.removable = TRUE end
+ if not c.allow then c.allow = function() return not nil end end
+
+ if c.depends == nil then c.depends = {} end
+ if c.oppose == nil then c.oppose = {} end
+
+ -- We must make sure the other ones opposes too
+ local o, i
+ for o, i in c.oppose do
+ __corruptions[o].oppose[__corruptions_max] = TRUE
+ end
+
+ local index, h
+ for index, h in c.hooks do
+ add_hook_script(index, "__lua__corrupt_callback"..__corruptions_callbacks_max, "__lua__corrupt_callback"..__corruptions_callbacks_max)
+ setglobal("__lua__corrupt_callback"..__corruptions_callbacks_max,
+ function (...)
+ if test_depend_corrupt(%__corruptions_max) == TRUE then
+ return call(%h, arg)
+ end
+ end
+ )
+ __corruptions_callbacks_max = __corruptions_callbacks_max + 1
+ end
+
+ if type(c.desc) == "table" then
+ local new_desc = ""
+ for index, h in c.desc do
+ new_desc = new_desc..h.."\n"
+ end
+ c.desc = new_desc
+ end
+
+ __corruptions[__corruptions_max] = c
+ __corruptions_max = __corruptions_max + 1
+ return (__corruptions_max - 1)
+end
+
diff --git a/lib/core/dungeon.lua b/lib/core/dungeon.lua
new file mode 100644
index 00000000..d91d785b
--- /dev/null
+++ b/lib/core/dungeon.lua
@@ -0,0 +1,55 @@
+-- Internal lua file in charge of dungeon stuff
+
+function place_dungeon(y, x, d_idx)
+ if d_idx then
+ wild_map(y, x).entrance = 1000 + d_idx
+ else
+ wild_map(y, x).entrance = 0
+ end
+end
+
+function dungeon(d_idx)
+ return d_info[1 + d_idx]
+end
+
+function wild_feat(wild)
+ return wf_info[1 + wild.feat]
+end
+
+function explode_dir(dir)
+ return ddy[dir + 1], ddx[dir + 1]
+end
+
+function rotate_dir(dir, mov)
+ if mov > 0 then
+ if dir == 7 then dir = 8
+ elseif dir == 8 then dir = 9
+ elseif dir == 9 then dir = 6
+ elseif dir == 6 then dir = 3
+ elseif dir == 3 then dir = 2
+ elseif dir == 2 then dir = 1
+ elseif dir == 1 then dir = 4
+ elseif dir == 4 then dir = 7
+ end
+ elseif mov < 0 then
+ if dir == 7 then dir = 4
+ elseif dir == 4 then dir = 1
+ elseif dir == 1 then dir = 2
+ elseif dir == 2 then dir = 3
+ elseif dir == 3 then dir = 6
+ elseif dir == 6 then dir = 9
+ elseif dir == 9 then dir = 8
+ elseif dir == 8 then dir = 7
+ end
+ end
+
+ return dir
+end
+
+-- Place a trap for a specific level
+function place_trap(y, x, level)
+ local old_dun = dun_level
+ dun_level = level
+ %place_trap(y, x)
+ dun_level = old_dun
+end
diff --git a/lib/core/gen_idx.lua b/lib/core/gen_idx.lua
new file mode 100644
index 00000000..5f3af435
--- /dev/null
+++ b/lib/core/gen_idx.lua
@@ -0,0 +1,261 @@
+-- Place here the list of files to parse
+files =
+{
+ "birth.txt",
+ "experien.hlp",
+ "gods.txt",
+ "explore.hlp",
+ "newbie.hlp",
+ "advanced.hlp",
+ "help.hlp",
+ "general.txt",
+ "whattome.txt",
+ "dungeon.txt",
+ "spoiler.hlp",
+ "g_melkor.txt",
+ "skills.txt",
+ "c_bard.txt",
+ "c_druid.txt",
+ "c_lorema.txt",
+ "c_mage.txt",
+ "c_mimic.txt",
+ "c_mindcr.txt",
+ "c_monk.txt",
+ "c_palad.txt",
+ "c_posses.txt",
+ "c_pr_drk.txt",
+ "c_pr_eru.txt",
+ "c_pr_man.txt",
+ "c_symbia.txt",
+ "c_alchem.txt",
+ "c_archer.txt",
+ "c_assass.txt",
+ "c_axemas.txt",
+ "c_demono.txt",
+ "c_geoman.txt",
+ "c_hafted.txt",
+ "c_necro.txt",
+ "c_polear.txt",
+ "c_ranger.txt",
+ "c_rogue.txt",
+ "c_runecr.txt",
+ "c_sorcer.txt",
+ "c_swordm.txt",
+ "c_thaum.txt",
+ "c_unbel.txt",
+ "c_warper.txt",
+ "c_warrio.txt",
+ "m_meta.txt",
+ "rm_skel.txt",
+ "rm_zomb.txt",
+ "luckspoi.txt",
+ "m_air.txt",
+ "dunspoil.txt",
+ "g_eru.txt",
+ "g_manwe.txt",
+ "g_tulkas.txt",
+ "m_divin.txt",
+ "m_mimic.txt",
+ "m_water.txt",
+ "magic.txt",
+ "r_drkelf.txt",
+ "r_dwarf.txt",
+ "r_elf.txt",
+ "r_hielf.txt",
+ "r_hobbit.txt",
+ "r_pettyd.txt",
+ "r_wodelf.txt",
+ "rm_spec.txt",
+ "tome_faq.txt",
+ "ability.txt",
+ "automat.txt",
+ "c_summon.txt",
+ "command.txt",
+ "corspoil.txt",
+ "debug.txt",
+ "m_music.txt",
+ "rm_barb.txt",
+ "macrofaq.txt",
+ "m_necrom.txt",
+ "m_mindcr.txt",
+ "m_symbio.txt",
+ "m_thaum.txt",
+ "magic.hlp",
+ "m_convey.txt",
+ "m_fire.txt",
+ "m_mana.txt",
+ "m_mind.txt",
+ "m_nature.txt",
+ "m_tempo.txt",
+ "m_udun.txt",
+ "m_geoman.txt",
+ "essences.txt",
+ "r_ent.txt",
+ "g_yavann.txt",
+ "defines.txt",
+ "rm_vamp.txt",
+ "inscrip.txt",
+ "m_earth.txt",
+ "option.txt",
+ "attack.txt",
+ "version.txt",
+ "m_demono.txt",
+ "r_beorn.txt",
+ "r_deathm.txt",
+ "r_rohank.txt",
+ "r_hafogr.txt",
+ "r_human.txt",
+ "r_kobold.txt",
+ "r_maia.txt",
+ "r_orc.txt",
+ "r_thlord.txt",
+ "r_troll.txt",
+ "r_yeek.txt",
+ "rm_class.txt",
+ "rm_herm.txt",
+ "rm_lsoul.txt",
+ "wishing.txt",
+ "c_priest.txt",
+ "fatespoi.txt",
+ "gambling.txt",
+ "r_dunad.txt",
+ "r_gnome.txt",
+ "r_hafelf.txt",
+ "c_merch.txt",
+ "spoil_faq.txt",
+}
+
+out_file = "index.txt"
+
+index = {}
+
+function parse_file(file)
+ local fff = openfile(path_build(ANGBAND_DIR_HELP, file), "r")
+ local line
+
+ line = read(fff, "*l")
+ while line do
+ local i, j, anchor, name, subname = strfind(line, "~~~~~(%d+)|([%d%a -]+)|([%d%a -]+)")
+ if not i then
+ i, j, anchor, name = strfind(line, "~~~~~(%d+)|([%d%a -]+)")
+
+ subname = nil
+ end
+
+ if i then
+ if not index[name] then
+ index[name] = {}
+ end
+ if subname then
+ tinsert(index[name], { __name__ = subname, __file__ = file, __anchor__ = anchor})
+ else
+ tinsert(index[name], { __name__ = "__primary__", __file__ = file, __anchor__ = anchor})
+ end
+ end
+
+ line = read(fff, "*l")
+ end
+
+ closefile(fff)
+end
+
+function sort_fct(a, b)
+ local i, len
+
+ a = a.__name__
+ b = b.__name__
+
+ if strlen(a) > strlen(b) then len = strlen(b) else len = strlen(a) end
+
+ for i = 1, len do
+ local ac = strbyte(a, i)
+ local bc = strbyte(b, i)
+
+ if ac < bc then
+ return not nil
+ elseif ac > bc then
+ return nil
+ end
+ end
+ if strlen(a) > strlen(b) then return nil else return not nil end
+end
+
+function generate_index()
+ local k, e, index_list
+ for _, e in files do
+ parse_file(e)
+ end
+
+ index_list = {}
+ for k, e in index do
+ -- Ok either my sort function or lua sort function sucks ass ..
+ sort(e, sort_fct)
+ sort(e, sort_fct)
+ sort(e, sort_fct)
+ sort(e, sort_fct)
+ sort(e, sort_fct)
+ tinsert(index_list, {__name__= k, __table__ = e})
+ end
+
+ -- Ok either my sort function or lua sort function sucks ass ..
+ sort(index_list, sort_fct)
+ sort(index_list, sort_fct)
+ sort(index_list, sort_fct)
+ sort(index_list, sort_fct)
+ sort(index_list, sort_fct)
+ index = index_list
+end
+
+function out_link(fff, space, name, file, anchor)
+ write(fff, space.."*****"..file.."*"..anchor.."["..name.."]\n")
+end
+
+function print_index()
+ local i, j, c, new_c
+ local fff = openfile(path_build(ANGBAND_DIR_HELP, out_file), "w")
+
+ write(fff,
+[[|||||oy
+#####R /----------------------------------------\
+#####R < Help Index >
+#####R \----------------------------------------/
+
+This is the index of everything in the T.o.M.E. documentation.
+
+#####BHit a letter key to jump to the entries for that letter.
+
+Some entries in the index link to the same place as other entries. This is
+intentional, so that the information you want is easy to find.
+
+Don't forget you can browse the help from the *****help.hlp*02[Main menu].
+
+#####sSpotted a problem with the help files, or some content thats missing?
+#####sContact fearoffours@t-o-m-e.net .
+
+]])
+
+ c = ' '
+ for i = 1, getn(index) do
+ new_c = strbyte(index[i].__name__, 1)
+ if c ~= new_c then
+ c = new_c
+ write(fff, "~~~~~"..c.."\n")
+ write(fff, "*****/"..strchar(c)..out_file.."*"..c.."["..strchar(c).."]\n")
+ end
+ for j = 1, getn(index[i].__table__) do
+ if index[i].__table__[j].__name__ == "__primary__" then
+ out_link(fff, " ", index[i].__name__, index[i].__table__[j].__file__, index[i].__table__[j].__anchor__)
+ end
+ end
+ for j = 1, getn(index[i].__table__) do
+ if index[i].__table__[j].__name__ ~= "__primary__" then
+ out_link(fff, " ", index[i].__table__[j].__name__, index[i].__table__[j].__file__, index[i].__table__[j].__anchor__)
+ end
+ end
+ end
+ closefile(fff)
+end
+
+generate_index()
+
+print_index()
diff --git a/lib/core/gods.lua b/lib/core/gods.lua
new file mode 100644
index 00000000..77e0aad5
--- /dev/null
+++ b/lib/core/gods.lua
@@ -0,0 +1,40 @@
+-- Gods helper files
+
+-- Gods structs
+
+__gods_hook = {}
+__gods_callbacks = {}
+__gods_callbacks_max = 0
+
+function add_god(q)
+ local i, index, d, z, qq
+
+ assert(q.name, "No god name")
+ assert(q.desc, "No god desc")
+ assert(q.hooks, "No god hooks")
+
+ i = add_new_gods(q.name);
+
+ z = 0
+ for index, d in q.desc do
+ desc_god(i, z, d);
+ z = z + 1
+ end
+
+ __gods_hook[i] = q.hooks
+ for index, d in q.hooks do
+ add_hook_script(index, "__lua__gods_callback"..__gods_callbacks_max, "__lua__gods_callback"..__gods_callbacks_max)
+ setglobal("__lua__gods_callback"..__gods_callbacks_max, d)
+ __gods_callbacks_max = __gods_callbacks_max + 1
+ end
+ if q.data then
+ for index, d in q.data do
+ -- Besure it exists
+ setglobal(index, d)
+
+ -- Make it save & load
+ add_loadsave(index, d)
+ end
+ end
+ return i
+end
diff --git a/lib/core/help.lua b/lib/core/help.lua
new file mode 100644
index 00000000..a581fe63
--- /dev/null
+++ b/lib/core/help.lua
@@ -0,0 +1,141 @@
+-- Ingame contextual help
+
+-- We use our own hook list as to not overburn the hook proccessor
+-- with many hooks that would slow down things
+-- It would be very meaningless if the option is not even on
+__ingame_hooks = {}
+
+__ingame_help_max = 0
+
+function ingame_help(t, ...)
+ -- This function can also be used to call the callbacks
+ if type(t) == "string" then
+ local f = getglobal("__ingame_help_fct_"..t)
+ call(f, arg)
+ return
+ end
+
+ assert(t.desc or t.fct, "no ingame help desc/fct")
+ assert(t.hook or t.callback, "no ingame help hook/callback")
+ if t.hook then assert(t.event, "no ingame hepl event needed by hook") end
+
+ -- Set it to only trigger once
+ setglobal("__ingame_help_activated_"..__ingame_help_max, FALSE)
+ -- Save/load it
+ add_loadsave("__ingame_help_activated_"..__ingame_help_max, FALSE)
+
+ if t.hook then
+ -- If the hok list didnt exist yet, add it
+ if not __ingame_hooks[t.hook] then
+ -- Set it to empty, we'll fill it later
+ __ingame_hooks[t.hook] = {}
+ -- Add the global hook
+ add_hooks
+ {
+ [t.hook] = function (...)
+ if option_ingame_help ~= TRUE then return end
+ local k, e
+ for k, e in __ingame_hooks[%t.hook] do
+ if k ~= "n" then
+ call(e, arg)
+ end
+ end
+ end
+ }
+ end
+ if t.desc then
+ tinsert(__ingame_hooks[t.hook],
+ function (...)
+ local tbl = %t
+ if getglobal("__ingame_help_activated_"..%__ingame_help_max) == FALSE then
+ if call(tbl.event, arg) == TRUE then
+ local k, e
+ for k, e in tbl.desc do
+ msg_print(TERM_YELLOW, e)
+ end
+ setglobal("__ingame_help_activated_"..%__ingame_help_max, TRUE)
+ end
+ end
+ end
+ )
+ elseif t.fct then
+ tinsert(__ingame_hooks[t.hook],
+ function (...)
+ local tbl = %t
+ if getglobal("__ingame_help_activated_"..%__ingame_help_max) == FALSE then
+ if call(tbl.event, arg) == TRUE then
+ if tbl.fct() == TRUE then
+ setglobal("__ingame_help_activated_"..%__ingame_help_max, TRUE)
+ end
+ end
+ end
+ end
+ )
+ end
+ else
+ local no_test = FALSE
+ if t.no_test == TRUE then no_test = TRUE end
+ if t.desc then
+ setglobal
+ (
+ "__ingame_help_fct_"..(t.callback),
+ function (...)
+ local tbl = %t
+ if ((option_ingame_help == TRUE) or (%no_test == TRUE)) and (getglobal("__ingame_help_activated_"..%__ingame_help_max) == FALSE) then
+ local k, e
+ for k, e in tbl.desc do
+ msg_print(TERM_YELLOW, e)
+ end
+ setglobal("__ingame_help_activated_"..%__ingame_help_max, TRUE)
+ end
+ end
+ )
+ elseif t.fct then
+ setglobal
+ (
+ "__ingame_help_fct_"..(t.callback),
+ function (...)
+ local tbl = %t
+ if ((option_ingame_help == TRUE) or (%no_test == TRUE)) and (getglobal("__ingame_help_activated_"..%__ingame_help_max) == FALSE) then
+ if call(tbl.fct, arg) == TRUE then
+ setglobal("__ingame_help_activated_"..%__ingame_help_max, TRUE)
+ end
+ end
+ end
+ )
+ end
+ end
+
+ __ingame_help_max = __ingame_help_max + 1
+end
+
+-- Clean up the ingame help seen at birth
+add_hooks
+{
+ [HOOK_BIRTH_OBJECTS] = function()
+ local i
+ for i = 0, __ingame_help_max - 1 do
+ setglobal("__ingame_help_activated_"..i, FALSE)
+ end
+ end
+}
+
+function ingame_clean()
+ local i
+ for i = 0, __ingame_help_max - 1 do
+ setglobal("__ingame_help_activated_"..i, FALSE)
+ end
+end
+
+-- helper function, brings up a doc
+function ingame_help_doc(name, anchor)
+ -- Save screen
+ screen_save();
+
+ -- Peruse the help file
+ if not anchor then anchor = 0 end
+ show_file(name, 0, -anchor, 0)
+
+ -- Load screen
+ screen_load()
+end
diff --git a/lib/core/init.lua b/lib/core/init.lua
new file mode 100644
index 00000000..11b812d5
--- /dev/null
+++ b/lib/core/init.lua
@@ -0,0 +1,83 @@
+--
+-- This file is loaded at the initialisation of ToME
+-- Load the system functions
+--
+
+-- Name of globals to save
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "load.lua")
+
+-- Very thin xml parser(49 lines ;)
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "xml.lua")
+
+-- various vital helper code
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "util.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "player.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "objects.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "monsters.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "building.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "dungeon.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "s_aux.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "crpt_aux.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "mimc_aux.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "quests.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "gods.lua")
+
+-- Load the ingame contextual help
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "help.lua")
+
+-- let the store specific stuff happen!
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "stores.lua")
+
+--------------------------------------------------------------
+--------------------------------------------------------------
+--------------------------------------------------------------
+-------------Here we load the non vital scripts---------------
+-----------------------from lib/scpt--------------------------
+--------------------------------------------------------------
+--------------------------------------------------------------
+tome_dofile("init.lua")
+
+-- The dofile functions for each patch
+patch_dofile = {}
+
+-- Now load patches
+function load_patches()
+ scansubdir(ANGBAND_DIR_PATCH)
+ for i = 0, scansubdir_max - 1 do
+ if (scansubdir_result[i + 1] ~= ".") and (scansubdir_result[i + 1] ~= "..") then
+ local dir = path_build(ANGBAND_DIR_PATCH, scansubdir_result[i + 1])
+ local file = path_build(dir, "patch.lua")
+ if file_exist(file) == TRUE then
+ patch_init = nil
+ tome_dofile_anywhere(dir, "patch.lua", TRUE)
+ unset_safe_globals()
+ if patch_init == nil then
+ set_safe_globals()
+ quit("Patch in "..file.." did not include a patch_init() function")
+ else
+ set_safe_globals()
+
+ -- create the dofile function
+ patch_dofile[scansubdir_result[i + 1]] = function(f)
+ tome_dofile_anywhere(%dir, f, TRUE)
+ end
+
+ local name, version = patch_init()
+ if name == nil or version == nil then
+ quit("Patch in "..file.." did not return valid name or version.\nIt must return name, version")
+ end
+ patch_version(name, version)
+ end
+ end
+ end
+ end
+end
+load_patches()
+
+--------------------------------------------------------------
+--------------------------------------------------------------
+--------------------------------------------------------------
+--
+-- Do not thouch after this line
+--
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "load2.lua")
diff --git a/lib/core/load.lua b/lib/core/load.lua
new file mode 100644
index 00000000..9522ec91
--- /dev/null
+++ b/lib/core/load.lua
@@ -0,0 +1,37 @@
+-- Savefile stuff
+-- Do not meddle in the affairs of savefiles for they are subtle and quick to be become incompatible
+
+__loadsave_name = {}
+__loadsave_max = 0
+__loadsave_tmp = 0
+
+function add_loadsave(name, default)
+ assert(name, "No variable name to save")
+ assert(default, "No default value")
+
+ -- if it is a table we must create many entries
+ if type(default) == "table" then
+ for k, e in default do
+ add_loadsave(name.."."..k, e)
+ end
+ else
+ __loadsave_name[__loadsave_max] = { name = name, default = default }
+ __loadsave_max = __loadsave_max + 1
+ end
+end
+
+-- Example of how to save a table
+-- NOTE: { 1, 2, 3 } will NOT work, the key MUST be a string
+--[[
+add_loadsave("t",
+{
+ foo = 7,
+ tab = {
+ a = 1,
+ b = 2,
+ tab = {
+ a=1, b=2, c=3,
+ },
+ },
+})
+]]
diff --git a/lib/core/load2.lua b/lib/core/load2.lua
new file mode 100644
index 00000000..7e151d91
--- /dev/null
+++ b/lib/core/load2.lua
@@ -0,0 +1,56 @@
+-- Savefile helpers
+
+-- function called when a key in the variable part ofthe savefile is read
+-- if the key matches what we need, we use it, otehrwise just ignore it
+function __savefile_load(key, val)
+ local index, elem
+
+ for index, elem in __loadsave_name do
+ if (key == elem.name) then
+ dostring(elem.name.." = "..val)
+ end
+ end
+end
+
+-- called when the game is saved, can only save numbers
+-- assosiate a key with them to allow the loading code to recognize them
+function __savefile_save()
+ local index, elem
+ for index, elem in __loadsave_name do
+ dostring("__loadsave_tmp = "..elem.name)
+ save_number_key(elem.name, __loadsave_tmp);
+ end
+end
+
+register_savefile(__loadsave_max)
+add_hook_script(HOOK_LOAD_GAME, "__savefile_load", "__hook_load")
+add_hook_script(HOOK_SAVE_GAME, "__savefile_save", "__hook_save")
+
+-- Parse a flattened(i.e: foo.bar.zog) table path and recrate tables
+function reconstruct_table(name)
+ for i = 1, strlen(name) - 1 do
+ if strsub(name, i, i) == "." then
+ local tbl = strsub(name, 1, i - 1)
+
+ if dostring("return "..tbl) == nil then
+ dostring(tbl.."={}")
+ end
+ end
+ end
+end
+
+-- Automagically set unkown variables, otherwise the savefile code
+-- might get VERY upset
+do
+ local k, e
+ -- We need to be able to check for unknown globals
+ unset_safe_globals()
+ for k, e in __loadsave_name do
+ reconstruct_table(e.name)
+ if dostring("return "..(e.name)) == nil then
+ dostring((e.name).." = "..(e.default))
+ end
+ end
+ -- Now taht we did, we set it back, for it is usefull ;)
+ set_safe_globals()
+end
diff --git a/lib/core/mimc_aux.lua b/lib/core/mimc_aux.lua
new file mode 100644
index 00000000..cea1f4dc
--- /dev/null
+++ b/lib/core/mimc_aux.lua
@@ -0,0 +1,96 @@
+-- Mimic shapes helper file
+
+__mimics = {}
+__mimics_max = 1
+__mimics_names = {}
+
+function add_mimic_shape(t)
+ assert(t.name, "no mimic name")
+ assert(t.desc, "no mimic desc")
+ assert(t.calc, "no mimic calc")
+ assert(t.level, "no mimic level")
+ assert(t.duration, "no mimic duration")
+
+ if not t.limit then t.limit = 0 end
+
+ if not t.obj_name then
+ t.obj_name = t.name
+ end
+
+ t.show_name = '['..t.name..']'
+
+ -- if it needs hooks, add them
+ if t.hooks then
+ add_hooks(t.hooks)
+ end
+
+ -- Add it in a name to index hash table
+ __mimics_names[t.name] = __mimics_max
+
+ __mimics[__mimics_max] = t
+ __mimics_max = __mimics_max + 1
+end
+
+function resolve_mimic_name(name)
+ if __mimics_names[name] then
+ return __mimics_names[name]
+ else
+ return -1
+ end
+end
+
+function find_random_mimic_shape(level, limit, realm)
+ local mimic, tries
+
+ tries = 1000
+ while tries > 0 do
+ tries = tries - 1
+ mimic = rand_range(1, __mimics_max - 1)
+ if (not realm) or (__mimics[mimic].realm == realm) then
+ if limit >= __mimics[mimic].limit then
+ if (rand_int(__mimics[mimic].level * 3) < level) and (__mimics[mimic].rarity < 100) and (magik(100 - __mimics[mimic].rarity) == TRUE) then
+ break
+ end
+ end
+ end
+ end
+ if tries > 0 then
+ return mimic
+ else
+ return resolve_mimic_name("Abomination")
+ end
+end
+
+function get_mimic_info(mimic, info)
+ if not __mimics[mimic] then return 0 end
+ return __mimics[mimic][info]
+end
+
+function get_mimic_rand_dur(mimic)
+ return rand_range(__mimics[mimic].duration[1], __mimics[mimic].duration[2])
+end
+
+function calc_mimic(mimic)
+ return __mimics[mimic].calc()
+end
+
+function calc_mimic_power(mimic)
+ if __mimics[mimic].power then __mimics[mimic].power() end
+end
+
+--- Here comes the only vital shape
+
+add_mimic_shape
+{
+ ["name"] = "Abomination",
+ ["obj_name"] = "Abominable Cloak",
+ ["desc"] = "Abominations are failed experiments of powerful wizards.",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {20, 100},
+ ["calc"] = function ()
+ apply_flags(TR1_SPEED + TR1_STR + TR1_INT + TR1_WIS + TR1_DEX + TR1_CON + TR1_CHR, 0, 0, 0, 0, 0, -10)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_AGGRAVATE)
+ end,
+}
diff --git a/lib/core/monsters.lua b/lib/core/monsters.lua
new file mode 100644
index 00000000..ca2851a0
--- /dev/null
+++ b/lib/core/monsters.lua
@@ -0,0 +1,16 @@
+-- SYSTEM FILE
+--
+-- Monster stuff, do not touch
+--
+
+function summon_monster(y, x, lev, friend, typ)
+ if type(typ) == "number" then
+ if friend == TRUE then
+ return summon_specific_friendly(y, x, lev, typ, FALSE)
+ else
+ return summon_specific(y, x, lev, typ)
+ end
+ else
+ return summon_monster_aux(y, x, lev, friend, typ)
+ end
+end
diff --git a/lib/core/objects.lua b/lib/core/objects.lua
new file mode 100644
index 00000000..97320b82
--- /dev/null
+++ b/lib/core/objects.lua
@@ -0,0 +1,45 @@
+-- SYSTEM FILE
+--
+-- Lua object funtions
+--
+
+function create_object(tval, sval)
+ local obj = new_object()
+ object_prep(obj, lookup_kind(tval, sval))
+ return (obj)
+end
+
+function set_item_tester(tester)
+ if tolua.type(tester) == "number" then
+ lua_set_item_tester(tester, "")
+ end
+ if tolua.type(tester) == "string" then
+ lua_set_item_tester(0, tester)
+ end
+ if tolua.type(tester) == "function" then
+ __get_item_hook_default = tester
+ lua_set_item_tester(0, "__get_item_hook_default")
+ end
+end
+
+function create_artifact(a_idx)
+ local obj
+ local tval, sval
+
+ tval = a_info[a_idx + 1].tval
+ sval = a_info[a_idx + 1].sval
+ obj = create_object(tval, sval)
+ obj.name1 = a_idx
+ apply_magic(obj, -1, TRUE, TRUE, TRUE)
+
+ return (obj)
+end
+
+function get_kind(obj)
+ return k_info[obj.k_idx + 1]
+end
+
+function get_item(ask, deny, flags, mask)
+ set_item_tester(mask)
+ return get_item_aux(0, ask, deny, flags)
+end
diff --git a/lib/core/player.lua b/lib/core/player.lua
new file mode 100644
index 00000000..16878228
--- /dev/null
+++ b/lib/core/player.lua
@@ -0,0 +1,135 @@
+-- SYSTEM FILE
+--
+-- Lua player funtions
+--
+
+-- Gods
+function deity(i)
+ return deity_info[1 + i]
+end
+
+-------- skill stuff ---------
+
+-- Easy skill access
+function skill(i)
+ return s_info[i + 1]
+end
+
+-- Sart a lasting spell
+function player.start_lasting_spell(spl)
+ player.music_extra = -spl
+end
+
+-- stat mods
+function player.modify_stat(stat, inc)
+ player.stat_add[1 + stat] = player.stat_add[1 + stat] + inc
+end
+
+-- powers mods
+function player.add_power(pow)
+ player.powers[1 + pow] = TRUE
+end
+
+-- easier inventory access
+function player.inventory(i)
+ return player.inventory_real[i + 1]
+end
+
+-- modify mana
+-- returns TRUE if there is a pb
+function increase_mana(amt)
+ player.csp = player.csp + amt
+ player.redraw = bor(player.redraw, PR_MANA)
+ if (player.csp < 0) then
+ player.csp = 0
+ return TRUE
+ end
+ if (player.csp > player.msp) then
+ player.csp = player.msp
+ end
+ return FALSE
+end
+
+
+-- Return the coordinates of the player whether in wild or not
+function player.get_wild_coord()
+ if player.wild_mode == TRUE then
+ return player.py, player.px
+ else
+ return player.wilderness_y, player.wilderness_x
+ end
+end
+
+-- Create a new power
+__power_fct = {}
+function add_power(p)
+ local i
+
+ assert(p.name, "No power name!")
+ assert(p.desc, "No power desc!")
+ assert(p.desc_get, "No power desc get!")
+ assert(p.desc_lose, "No power desc lose!")
+ assert(p.stat, "No power stat!")
+ assert(p.level, "No power level!")
+ assert(p.cost, "No power cost!")
+ assert(p.fail, "No power fail!")
+ assert(p.power, "No power power!")
+
+ i = add_new_power(p.name, p.desc, p.desc_get, p.desc_lose, p.level, p.cost, p.stat, p.fail)
+ __power_fct[i] = p.power
+ return i
+end
+
+function __power_fct_activate(power)
+ if __power_fct[power] then
+ __power_fct[power]()
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+-- Register in the hook list
+add_hook_script(HOOK_ACTIVATE_POWER, "__power_fct_activate", "__power_fct_activate")
+
+
+--- Mkeys
+
+-- Create a new power
+__mkey_fct = {}
+function add_mkey(p)
+ local i
+
+ assert(p.mkey, "No mkey mkey!")
+ assert(p.fct, "No mkeey fct!")
+
+ __mkey_fct[p.mkey] = p.fct
+end
+
+function __mkey_fct_activate(power)
+ if __mkey_fct[power] then
+ __mkey_fct[power]()
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+-- Register in the hook list
+add_hook_script(HOOK_MKEY, "__mkey_fct_activate", "__mkey_fct_activate")
+
+
+-- Subraces
+function subrace(racem)
+ return race_mod_info[racem + 1]
+end
+
+function subrace_add_power(subrace, power)
+ for i = 1, 4 do
+ if subrace.powers[i] == -1 then
+ subrace.powers[i] = power
+ return not nil
+ end
+ end
+ return nil
+end
diff --git a/lib/core/quests.lua b/lib/core/quests.lua
new file mode 100644
index 00000000..dfe9db51
--- /dev/null
+++ b/lib/core/quests.lua
@@ -0,0 +1,57 @@
+-- Quest helper files
+
+-- Quest structs
+
+__quest_hook = {}
+__quest_callbacks = {}
+__quest_callbacks_max = 0
+__quest_dynamic_desc = {}
+
+function add_quest(q)
+ local i, index, d, z, qq
+
+ assert(q.global, "No quest global name")
+ assert(q.name, "No quest name")
+ assert(q.desc, "No quest desc")
+ assert(q.level, "No quest level")
+ assert(q.hooks, "No quest hooks")
+
+ i = new_quest(q.name);
+ setglobal(q.global, i)
+
+ -- Make it save & load
+ add_loadsave("quest("..q.global..").status", QUEST_STATUS_UNTAKEN)
+
+ if type(q.desc) == "table" then
+ z = 0
+ for index, d in q.desc do
+ quest_desc(i, z, d);
+ z = z + 1
+ end
+ else
+ __quest_dynamic_desc[i] = q.desc
+ quest(i).dynamic_desc = TRUE
+ end
+ quest(i).level = q.level
+ if not q.silent then
+ quest(i).silent = FALSE
+ else
+ quest(i).silent = q.silent
+ end
+ __quest_hook[i] = q.hooks
+ for index, d in q.hooks do
+ add_hook_script(index, "__lua__quest_callback"..__quest_callbacks_max, "__lua__quest_callback"..__quest_callbacks_max)
+ setglobal("__lua__quest_callback"..__quest_callbacks_max, d)
+ __quest_callbacks_max = __quest_callbacks_max + 1
+ end
+ if q.data then
+ for index, d in q.data do
+ -- Besure it exists
+ setglobal(index, d)
+
+ -- Make it save & load
+ add_loadsave(index, d)
+ end
+ end
+ return i
+end
diff --git a/lib/core/s_aux.lua b/lib/core/s_aux.lua
new file mode 100644
index 00000000..ec609b04
--- /dev/null
+++ b/lib/core/s_aux.lua
@@ -0,0 +1,716 @@
+-- Functions to help with spells, do not touch
+
+__schools = {}
+__schools_num = 0
+
+__tmp_spells = {}
+__tmp_spells_num = 0
+
+function add_school(s)
+ __schools[__schools_num] = s
+
+ __schools_num = __schools_num + 1
+ return (__schools_num - 1)
+end
+
+function finish_school(i)
+ local s
+
+ s = __schools[i]
+ assert(s.name, "No school name!")
+ assert(s.skill, "No school skill!")
+
+ -- Need hooks?
+ if s.hooks then
+ add_hooks(s.hooks)
+ end
+
+ new_school(i, s.name, s.skill)
+end
+
+function add_spell(s)
+ __tmp_spells[__tmp_spells_num] = s
+
+ __tmp_spells_num = __tmp_spells_num + 1
+ return (__tmp_spells_num - 1)
+end
+
+function finish_spell(must_i)
+ local i, s
+
+ s = __tmp_spells[must_i]
+ assert(s.name, "No spell name!")
+ assert(s.school, "No spell school!")
+ assert(s.level, "No spell level!")
+ assert(s.mana, "No spell mana!")
+ if not s.mana_max then s.mana_max = s.mana end
+ assert(s.fail, "No spell failure rate!")
+ assert(s.spell, "No spell function!")
+ if not s.info then s.info = function() return "" end end
+ assert(s.desc, "No spell desc!")
+ if not s.random then s.random = SKILL_MAGIC end
+ if s.lasting then
+ assert(type(s.lasting) == "function", "Spell lasting is not function")
+ end
+ if s.stick then
+ local k, e
+ for k, e in s.stick do
+ if type(k) == "table" then
+ assert(e.base_level, "Arg no stick base level")
+ assert(e.max_level, "Arg no stick max level")
+ end
+ end
+ end
+
+ i = new_spell(must_i, s.name)
+ assert(i == must_i, "ACK ! i != must_i ! please contact the maintainer")
+ if type(s.school) == "number" then __spell_school[i] = {s.school}
+ else __spell_school[i] = s.school end
+ spell(i).mana = s.mana
+ spell(i).mana_max = s.mana_max
+ spell(i).fail = s.fail
+ spell(i).skill_level = s.level
+ __spell_spell[i] = s.spell
+ __spell_info[i] = s.info
+ __spell_desc[i] = s.desc
+ return i
+end
+
+-- Creates the school books array
+__spell_spell = {}
+__spell_info = {}
+__spell_desc = {}
+__spell_school = {}
+school_book = {}
+
+-- Find a spell by name
+function find_spell(name)
+ local i
+
+ i = 0
+ while (i < __tmp_spells_num) do
+ if __tmp_spells[i].name == name then return i end
+ i = i + 1
+ end
+ return -1
+end
+
+-- Find if the school is under the influence of a god, returns nil or the level
+function get_god_level(sch)
+ if __schools[sch].gods[player.pgod] then
+ return (s_info[__schools[sch].gods[player.pgod].skill + 1].value * __schools[sch].gods[player.pgod].mul) / __schools[sch].gods[player.pgod].div
+ else
+ return nil
+ end
+end
+
+-- Change this fct if I want to switch to learnable spells
+function get_level_school(s, max, min)
+ local lvl, sch, index, num, bonus
+ local allow_spell_power = TRUE
+
+ lvl = 0
+ num = 0
+ bonus = 0
+
+ -- No max specified ? assume 50
+ if not max then
+ max = 50
+ end
+ if not min then
+ min = 1
+ end
+
+ -- Do we pass tests?
+ if __tmp_spells[s].depend then
+ if __tmp_spells[s].depend() ~= TRUE then
+ return min, "n/a"
+ end
+ end
+
+ for index, sch in __spell_school[s] do
+ local r, s, p, ok = 0, 0, 0, 0
+
+ -- Does it require we worship a specific god?
+ if __schools[sch].god then
+ if __schools[sch].god ~= player.pgod then
+ if min then return min, "n/a"
+ else return 1, "n/a" end
+ end
+ end
+
+ -- Take the basic skill value
+ r = s_info[(school(sch).skill) + 1].value
+
+ -- Do we pass tests?
+ if __schools[sch].depend then
+ if __schools[sch].depend() ~= TRUE then
+ return min, "n/a"
+ end
+ end
+
+ -- Are we under sorcery effect ?
+ if __schools[sch].sorcery then
+ s = s_info[SKILL_SORCERY + 1].value
+ end
+
+ -- Are we affected by spell power ?
+ -- All teh schools must allow it for it to work
+ if not __schools[sch].spell_power then
+ allow_spell_power = nil
+ end
+
+ -- Are we under a god effect ?
+ if __schools[sch].gods then
+ p = get_god_level(sch)
+ if not p then p = 0 end
+ end
+
+ -- Find the higher
+ ok = r
+ if ok < s then ok = s end
+ if ok < p then ok = p end
+
+ -- Do we need to add a special bonus ?
+ if __schools[sch].bonus_level then
+ bonus = bonus + (__schools[sch].bonus_level() * (SKILL_STEP / 10))
+ end
+
+ -- All schools must be non zero to be able to use it
+ if ok == 0 then return min, "n/a" end
+
+ -- Apply it
+ lvl = lvl + ok
+ num = num + 1
+ end
+
+ -- Add the Spellpower skill as a bonus
+ if allow_spell_power then
+ bonus = bonus + (get_skill_scale(SKILL_SPELL, 20) * (SKILL_STEP / 10))
+ end
+
+ -- Add bonus from objects
+ bonus = bonus + (player.to_s * (SKILL_STEP / 10))
+
+ -- / 10 because otherwise we can overflow a s32b and we can use a u32b because the value can be negative
+ -- The loss of information should be negligible since 1 skill = 1000 internally
+ lvl = (lvl / num) / 10
+ lvl = lua_get_level(s, lvl, max, min, bonus)
+
+ return lvl, nil
+end
+
+-- This is the function to use when casting through a stick
+function get_level_device(s, max, min)
+ local lvl
+
+ -- No max specified ? assume 50
+ if not max then
+ max = 50
+ end
+
+ lvl = s_info[SKILL_DEVICE + 1].value
+ lvl = lvl + (get_level_use_stick * SKILL_STEP)
+
+ -- Sticks are limited
+ if lvl - ((spell(s).skill_level + 1) * SKILL_STEP) >= get_level_max_stick * SKILL_STEP then
+ lvl = (get_level_max_stick + spell(s).skill_level - 1) * SKILL_STEP
+ end
+
+ -- / 10 because otherwise we can overflow a s32b and we can use a u32b because the value can be negative
+ -- The loss of information should be negligible since 1 skill = 1000 internally
+ lvl = lvl / 10
+ if not min then
+ lvl = lua_get_level(s, lvl, max, 1, 0)
+ else
+ lvl = lua_get_level(s, lvl, max, min, 0)
+ end
+
+ return lvl
+end
+
+-- The real get_level, works for schooled magic and for innate powers
+get_level_use_stick = -1
+get_level_max_stick = -1
+function get_level(s, max, min)
+ if type(s) == "number" then
+ -- Ahah shall we use Magic device instead ?
+ if get_level_use_stick > -1 then
+ return get_level_device(s, max, min)
+ else
+ local lvl, na = get_level_school(s, max, min)
+ return lvl
+ end
+ else
+ return get_level_power(s, max, min)
+ end
+end
+
+-- Can we cast the spell ?
+function is_ok_spell(s, obj)
+ if get_level(s, 50, 0) == 0 then return nil end
+ if __tmp_spells[s].pval and obj.pval < __tmp_spells[s].pval then return nil end
+ return 1
+end
+
+-- Get the amount of mana(or power) needed
+function get_mana(s)
+ return spell(s).mana + get_level(s, spell(s).mana_max - spell(s).mana, 0)
+end
+
+-- Return the amount of power(mana, piety, whatever) for the spell
+function get_power(s)
+ if check_affect(s, "piety", FALSE) then
+ return player.grace
+ else
+ return player.csp
+ end
+end
+
+-- Return the amount of power(mana, piety, whatever) for the spell
+function get_power_name(s)
+ if check_affect(s, "piety", FALSE) then
+ return "piety"
+ else
+ return "mana"
+ end
+end
+
+-- Get the level of a power
+function get_level_power(s, max, min)
+ if not max then max = 50 end
+ if not min then min = 1 end
+
+ return value_scale(s.get_current_level(), 50, max, min)
+end
+
+-- Changes the amount of power(mana, piety, whatever) for the spell
+function adjust_power(s, x)
+ if check_affect(s, "piety", FALSE) then
+ inc_piety(GOD_ALL, x)
+ else
+ increase_mana(x)
+ end
+end
+
+-- Get spell school name(s) as a /-separated string.
+function spell_school_name(s)
+ local xx, sch_str
+ xx = nil
+ sch_str = ""
+ for index, sch in __spell_school[s] do
+ if xx then
+ sch_str = sch_str.."/"..school(sch).name
+ else
+ xx = 1
+ sch_str = sch_str..school(sch).name
+ end
+ end
+ return sch_str
+end
+
+-- Print the book and the spells
+function print_book(book, spl, obj)
+ local x, y, index, sch, size, s
+
+ x = 0
+ y = 2
+ size = 0
+
+ -- Hack if the book is 255 it is a random book
+ if book == 255 then
+ school_book[book] = {spl}
+ end
+
+ -- Parse all spells
+ for index, s in school_book[book] do
+ local color = TERM_L_DARK
+ local lvl, na = get_level_school(s, 50, -50)
+ local xx, sch_str
+
+ if is_ok_spell(s, obj) then
+ if get_mana(s) > get_power(s) then color = TERM_ORANGE
+ else color = TERM_L_GREEN end
+ end
+
+ sch_str = spell_school_name(s)
+
+ if na then
+ c_prt(color, format("%c) %-20s%-16s %3s %4s %3d%s %s", size + strbyte("a"), spell(s).name, sch_str, na, get_mana(s), spell_chance(s), "%", __spell_info[s]()), y, x)
+ else
+ c_prt(color, format("%c) %-20s%-16s %3d %4s %3d%s %s", size + strbyte("a"), spell(s).name, sch_str, lvl, get_mana(s), spell_chance(s), "%", __spell_info[s]()), y, x)
+ end
+ y = y + 1
+ size = size + 1
+ end
+ prt(format(" %-20s%-16s Level Cost Fail Info", "Name", "School"), 1, x)
+ return y
+end
+
+-- Output the describtion when it is used as a spell
+function print_spell_desc(s, y)
+ local index, desc, x
+
+ x = 0
+
+ if type(__spell_desc[s]) == "string" then c_prt(TERM_L_BLUE, __spell_desc[s], y, x)
+ else
+ for index, desc in __spell_desc[s] do
+ c_prt(TERM_L_BLUE, desc, y, x)
+ y = y + 1
+ end
+ end
+ if check_affect(s, "piety", FALSE) then
+ c_prt(TERM_L_WHITE, "It uses piety to cast.", y, x)
+ y = y + 1
+ end
+ if not check_affect(s, "blind") then
+ c_prt(TERM_ORANGE, "It is castable even while blinded.", y, x)
+ y = y + 1
+ end
+ if not check_affect(s, "confusion") then
+ c_prt(TERM_ORANGE, "It is castable even while confused.", y, x)
+ y = y + 1
+ end
+end
+
+-- Output the desc when sued as a device
+function print_device_desc(s)
+ local index, desc
+
+ if type(__spell_desc[s]) == "string" then text_out(__spell_desc[s])
+ else
+ for index, desc in __spell_desc[s] do
+ text_out("\n" .. desc)
+ end
+ end
+end
+
+function book_spells_num(book)
+ local size, index, sch
+
+ size = 0
+
+ -- Hack if the book is 255 it is a random book
+ if book == 255 then
+ return 1
+ end
+
+ -- Parse all spells
+ for index, s in school_book[book] do
+ size = size + 1
+ end
+ return size
+end
+
+function spell_x(book, spl, s)
+ if book == 255 then
+ return spl
+ else
+ local i, x, val
+
+ i, val = next(school_book[book], nil)
+ x = 0
+ while x < s do
+ i, val = next(school_book[book], i)
+ x = x + 1
+ end
+ return val
+ end
+end
+
+function spell_in_book(book, spell)
+ local i, s
+
+ for i, s in school_book[book] do
+ if s == spell then return TRUE end
+ end
+ return FALSE
+end
+
+-- Returns spell chance of failure for spell
+function spell_chance(s)
+ local chance, s_ptr
+
+ s_ptr = spell(s)
+
+ -- Extract the base spell failure rate
+ if get_level_use_stick > -1 then
+ chance = lua_spell_device_chance(s_ptr.fail, get_level(s, 50), s_ptr.skill_level)
+ else
+ chance = lua_spell_chance(s_ptr.fail, get_level(s, 50), s_ptr.skill_level, get_mana(s), get_power(s), get_spell_stat(s))
+ end
+
+ -- Return the chance
+ return chance
+end
+
+function check_affect(s, name, default)
+ local s_ptr = __tmp_spells[s]
+ local a
+
+ if type(s_ptr[name]) == "number" then
+ a = s_ptr[name]
+ else
+ a = default
+ end
+ if a == FALSE then
+ return nil
+ else
+ return TRUE
+ end
+end
+
+-- Returns the stat to use for the spell, INT by default
+function get_spell_stat(s)
+ if not __tmp_spells[s].stat then return A_INT
+ else return __tmp_spells[s].stat end
+end
+
+function cast_school_spell(s, s_ptr, no_cost)
+ local use = FALSE
+
+ -- No magic
+ if (player.antimagic > 0) then
+ msg_print("Your anti-magic field disrupts any magic attempts.")
+ return
+ end
+
+ -- No magic
+ if (player.anti_magic == TRUE) then
+ msg_print("Your anti-magic shell disrupts any magic attempts.")
+ return
+ end
+
+ -- if it costs something then some condition must be met
+ if not no_cost then
+ -- Require lite
+ if (check_affect(s, "blind")) and ((player.blind > 0) or (no_lite() == TRUE)) then
+ msg_print("You cannot see!")
+ return
+ end
+
+ -- Not when confused
+ if (check_affect(s, "confusion")) and (player.confused > 0) then
+ msg_print("You are too confused!")
+ return
+ end
+
+ -- Enough mana
+ if (get_mana(s) > get_power(s)) then
+ if (get_check("You do not have enough "..get_power_name(s)..", do you want to try anyway?") == FALSE) then return end
+ end
+
+ -- Invoke the spell effect
+ if (magik(spell_chance(s)) == FALSE) then
+ if (__spell_spell[s]() ~= nil) then
+ use = TRUE
+ end
+ else
+ local index, sch
+
+ -- added because this is *extremely* important --pelpel
+ if (flush_failure) then flush() end
+
+ msg_print("You failed to get the spell off!")
+ for index, sch in __spell_school[s] do
+ if __schools[sch].fail then
+ __schools[sch].fail(spell_chance(s))
+ end
+ end
+ use = TRUE
+ end
+ else
+ __spell_spell[s]()
+ end
+
+ if use == TRUE then
+ -- Reduce mana
+ adjust_power(s, -get_mana(s))
+
+ -- Take a turn
+ if is_magestaff() == TRUE then energy_use = 80
+ else energy_use = 100 end
+ end
+
+ player.redraw = bor(player.redraw, PR_MANA)
+ player.window = bor(player.window, PW_PLAYER)
+end
+
+
+-- Can the spell be randomly found(in random books)
+function can_spell_random(i)
+ return __tmp_spells[i].random
+end
+
+-- Find a random spell
+function get_random_spell(typ, level)
+ local spl, tries
+
+ tries = 1000
+ while tries > 0 do
+ tries = tries - 1
+ spl = rand_int(__tmp_spells_num)
+ if (can_spell_random(spl) == typ) and (rand_int(spell(spl).skill_level * 3) < level) then
+ break
+ end
+ end
+ if tries > 0 then
+ return spl
+ else
+ return -1
+ end
+end
+
+-- Execute a lasting spell
+function exec_lasting_spell(spl)
+ assert(__tmp_spells[spl].lasting, "No lasting effect for spell "..__tmp_spells[spl].name.." but called as such")
+ return __tmp_spells[spl].lasting()
+end
+
+-- Helper function for spell effect to know if they are or not obvious
+function is_obvious(effect, old)
+ if old then
+ if old == TRUE or effect == TRUE then
+ return TRUE
+ else
+ return FALSE
+ end
+ else
+ return effect
+ end
+end
+
+-------------------------Sticks-------------------------
+
+-- Fire off the spell
+function activate_stick(spl)
+ local ret = __spell_spell[spl]()
+ local charge, obvious
+ if not ret then
+ charge = FALSE
+ obvious = FALSE
+ else
+ charge = TRUE
+ obvious = ret
+ end
+ return obvious, charge
+end
+
+----------------------------------- Wand, Staves, Rods specific functions ----------------------------
+
+-- Get a spell for a given stick(wand, staff, rod)
+function get_random_stick(stick, level)
+ local spl, tries
+
+ tries = 1000
+ while tries > 0 do
+ tries = tries - 1
+ spl = rand_int(__tmp_spells_num)
+ if __tmp_spells[spl].stick and (type(__tmp_spells[spl].stick[stick]) == "table") then
+ if (rand_int(spell(spl).skill_level * 3) < level) and (magik(100 - __tmp_spells[spl].stick[stick].rarity) == TRUE) then
+ break
+ end
+ end
+ end
+ if tries > 0 then
+ return spl
+ else
+ return -1
+ end
+end
+
+-- Get a random base level
+function get_stick_base_level(stick, level, spl)
+ -- Paranoia
+ if spl < 0 or spl >= __tmp_spells_num or not __tmp_spells[spl].stick[stick] then return 0 end
+
+ local min, max = __tmp_spells[spl].stick[stick].base_level[1], __tmp_spells[spl].stick[stick].base_level[2]
+ local range = max - min;
+
+ -- Ok the basic idea is to have a max possible level of half the dungeon level
+ if range * 2 > level then range = level / 2 end
+
+ -- Randomize a bit
+ range = m_bonus(range, dun_level)
+
+ -- And get the result
+ return min + range
+end
+
+-- Get a random max level
+function get_stick_max_level(stick, level, spl)
+ -- Paranoia
+ if spl < 0 or spl >= __tmp_spells_num or not __tmp_spells[spl].stick[stick] then return 0 end
+
+ local min, max = __tmp_spells[spl].stick[stick].max_level[1], __tmp_spells[spl].stick[stick].max_level[2]
+ local range = max - min;
+
+ -- Ok the basic idea is to have a max possible level of half the dungeon level
+ if range * 2 > level then range = level / 2 end
+
+ -- Randomize a bit
+ range = m_bonus(range, dun_level)
+
+ -- And get the result
+ return min + range
+end
+
+-- Get the number of desired charges
+function get_stick_charges(spl)
+ return __tmp_spells[spl].stick.charge[1] + randint(__tmp_spells[spl].stick.charge[2]);
+end
+
+-- Get activation desc
+function get_activation_desc(spl)
+ local turns
+ if type(__tmp_spells[spl].activate) == 'number' then
+ turns = __tmp_spells[spl].activate
+ else
+ turns = __tmp_spells[spl].activate[1] .. '+d' .. __tmp_spells[spl].activate[2]
+ end
+ return __tmp_spells[spl].desc[1] .. ' every ' .. turns .. ' turns'
+end
+
+-- Compute the timeout of an activation
+function get_activation_timeout(spl)
+ if type(__tmp_spells[spl].activate) == 'number' then
+ return __tmp_spells[spl].activate
+ else
+ return __tmp_spells[spl].activate[1] + randint(__tmp_spells[spl].activate[2])
+ end
+end
+
+-- Fire off the spell
+function activate_activation(spl, item)
+ __spell_spell[spl](item)
+end
+
+
+------- Add new GF type ----------
+max_gf = MAX_GF
+function add_spell_type(t)
+ t.index = max_gf
+ max_gf = max_gf + 1
+ assert(t.color, "No GF color")
+ if not t.monster then t.monster = function() end end
+ if not t.angry then t.angry = function() end end
+ if not t.object then t.object = function() end end
+ if not t.player then t.player = function() end end
+ if not t.grid then t.grid = function() end end
+
+ add_hooks
+ {
+ [HOOK_GF_COLOR] = function (gf, new_gfx)
+ local t = %t
+ if gf == t.index then return TRUE, t.color[new_gfx + 1] end
+ end,
+ [HOOK_GF_EXEC] = function (action, who, gf, dam, rad, y, x, extra)
+ local t = %t
+ if t.index == gf then
+ return t[action](who, dam, rad, y, x, extra)
+ end
+ end,
+ }
+ return t.index
+end
diff --git a/lib/core/stores.lua b/lib/core/stores.lua
new file mode 100644
index 00000000..d4a63168
--- /dev/null
+++ b/lib/core/stores.lua
@@ -0,0 +1,32 @@
+-- Take care of all concerning stores
+function store_buy_list(t)
+ assert(type(t) == "table", "store_buy_list got no table")
+ add_hooks
+ {
+ [HOOK_STORE_BUY] = function (index, name, obj)
+ local tbl = %t
+ local elt = tbl[index]
+ if not elt then
+ elt = tbl[name]
+ end
+ if elt then
+ if elt then
+ if type(elt) == "function" then
+ return TRUE, elt(obj)
+ elseif type(elt) == "table" then
+ local k, e
+ for k, e in elt do
+ if type(e) == "number" then
+ if obj.tval == e then return TRUE, TRUE end
+ else
+ if (obj.tval == e[1]) and (obj.sval >= e[2]) and (obj.sval <= e[3]) then return TRUE, TRUE end
+ end
+ end
+ elseif elt == -1 then
+ return TRUE, FALSE
+ end
+ end
+ end
+ end,
+ }
+end
diff --git a/lib/core/util.lua b/lib/core/util.lua
new file mode 100644
index 00000000..eea13014
--- /dev/null
+++ b/lib/core/util.lua
@@ -0,0 +1,158 @@
+-- various stuff to make scripters life easier
+
+-- Beware of the scary undefined globals
+function safe_getglobal(x)
+ local v = rawget(globals(), x)
+
+ if v then
+ return v
+ else
+ error("undefined global variable '"..x.."'")
+ end
+end
+
+function set_safe_globals()
+ settagmethod(tag(nil), "getglobal", safe_getglobal)
+end
+function unset_safe_globals()
+ settagmethod(tag(nil), "getglobal", nil)
+end
+
+set_safe_globals()
+
+-- Patch modules
+__patch_modules = {}
+
+function patch_version(name, version)
+ assert(not __patch_modules[name], "Patch " .. name .. " already loaded!!!")
+ __patch_modules[name] = version
+end
+
+function patchs_list()
+ local k, e, first
+ first = FALSE
+ for k, e in __patch_modules do
+ if first == FALSE then print_hook("\n\n [Patch modules]\n") first = TRUE end
+ print_hook("\n "..k.." version "..e)
+ end
+ if first == TRUE then print_hook("\n") end
+end
+
+function patchs_display()
+ local k, e
+ for k, e in __patch_modules do
+ msg_print("Patch: "..k.." version "..e)
+ end
+end
+
+
+-- Better hook interface
+__hooks_list_callback = {}
+__hooks_list_callback_max = 0
+
+function add_hooks(h_table, name_prefix)
+ local k, e
+
+ if not name_prefix then name_prefix = "" end
+ for k, e in h_table do
+ add_hook_script(k, "__"..name_prefix.."__hooks_list_callback"..__hooks_list_callback_max, "__"..name_prefix.."__hooks_list_callback"..__hooks_list_callback_max)
+ setglobal("__"..name_prefix.."__hooks_list_callback"..__hooks_list_callback_max, e)
+ __hooks_list_callback_max = __hooks_list_callback_max + 1
+ end
+end
+
+-- Wrapper for the real msg_print and cmsg_print
+-- it understands if we want color or not
+function msg_print(c, m)
+ if type(c) == "number" then
+ cmsg_print(c, m)
+ else
+ call(%msg_print, { c })
+ end
+end
+
+-- better timer add function
+__timers_callback_max = 0
+
+function new_timer(t)
+ assert(t.delay > 0, "no timer delay")
+ assert(t.enabled, "no timer enabled state")
+ assert(t.callback, "no timer callback")
+
+ local timer
+ if type(t.callback) == "function" then
+ setglobal("__timers_callback_"..__timers_callback_max, t.callback)
+ timer = %new_timer("__timers_callback_"..__timers_callback_max, t.delay)
+ __timers_callback_max = __timers_callback_max + 1
+ else
+ timer = %new_timer(t.callback, t.delay)
+ end
+
+ timer.enabled = t.enabled
+
+ return timer
+end
+
+-- saves all timer values
+function save_timer(name)
+ add_loadsave(name..".enabled", FALSE)
+ add_loadsave(name..".delay", 1)
+ add_loadsave(name..".countdown", 1)
+end
+
+
+-- displays a scrolling list
+function display_list(y, x, h, w, title, list, begin, sel, sel_color)
+ local l = create_list(getn(list))
+
+ for i = 1, getn(list) do
+ add_to_list(l, i - 1, list[i])
+ end
+
+ %display_list(y, x, h, w, title, l, getn(list), begin - 1, sel - 1, sel_color)
+
+ delete_list(l, getn(list))
+end
+
+-- Easier access to special gene stuff
+function set_monster_generation(monster, state)
+ if type(monster) == "string" then
+ m_allow_special[test_monster_name(monster) + 1] = state
+ else
+ m_allow_special[monster + 1] = state
+ end
+end
+function set_object_generation(obj, state)
+ if type(obj) == "string" then
+ m_allow_special[test_item_name(obj) + 1] = state
+ else
+ m_allow_special[obj + 1] = state
+ end
+end
+function set_artifact_generation(obj, state)
+ m_allow_special[obj + 1] = state
+end
+
+-- Strings
+function strcap(str)
+ if strlen(str) > 1 then
+ return strupper(strsub(str, 1, 1))..strsub(str, 2)
+ elseif strlen(str) == 1 then
+ return strupper(str)
+ else
+ return str
+ end
+end
+
+function msg_format(...)
+ msg_print(call(format, arg))
+end
+
+-- A way to check if the game is now running(as opposed to initialization/character gen)
+game = {}
+add_hooks
+{
+ [HOOK_GAME_START] = function ()
+ game.started = TRUE
+ end
+}
diff --git a/lib/core/xml.lua b/lib/core/xml.lua
new file mode 100644
index 00000000..14f0511f
--- /dev/null
+++ b/lib/core/xml.lua
@@ -0,0 +1,375 @@
+-- The xml module
+xml = {}
+
+function xml:parseargs (s)
+ local arg = {}
+ gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a)
+ %arg[w] = a
+ end)
+ return arg
+end
+
+-- s is a xml stream, returns a table
+function xml:collect (s)
+ local stack = {n=0}
+ local top = {n=0}
+ tinsert(stack, top)
+ local ni,c,label,args, empty
+ local i, j = 1, 1
+ while 1 do
+ ni,j,c,label,args, empty = strfind(s, "<(%/?)(%w+)(.-)(%/?)>", j)
+ if not ni then break end
+ local text = strsub(s, i, ni-1)
+ if not strfind(text, "^%s*$") then
+ tinsert(top, text)
+ end
+ if empty == "/" then -- empty element tag
+ tinsert(top, {n=0, label=label, args=xml:parseargs(args), empty=1})
+ elseif c == "" then -- start tag
+ top = {n=0, label=label, args=xml:parseargs(args)}
+ tinsert(stack, top) -- new level
+ else -- end tag
+ local toclose = tremove(stack) -- remove top
+ top = stack[stack.n]
+ if stack.n < 1 then
+ error("nothing to close with "..label)
+ end
+ if toclose.label ~= label then
+ error("trying to close "..toclose.label.." with "..label)
+ end
+ tinsert(top, toclose)
+ end
+ i = j+1
+ end
+ local text = strsub(s, i)
+ if not strfind(text, "^%s*$") then
+ tinsert(stack[stack.n], text)
+ end
+ if stack.n > 1 then
+ error("unclosed "..stack[stack.n].label)
+ end
+ return stack[1]
+end
+
+-- Viewport coordinates
+xml.write_out_y = 0
+xml.write_out_x = 0
+xml.write_out_h = 24
+xml.write_out_w = 80
+
+-- Offsets
+xml.write_off_y = 0
+xml.write_off_x = 0
+
+-- Current position
+xml.write_y = 0
+xml.write_x = 0
+
+xml.write_screen = function(color, s)
+ local i
+ for i = 1, strlen(s) do
+ local c = strsub(s, i, i + 1)
+ if c ~= "\n" then
+ if xml.write_y - xml.write_off_y >= 0 and xml.write_y - xml.write_off_y < xml.write_out_h and xml.write_x - xml.write_off_x >= 0 and xml.write_x - xml.write_off_x < xml.write_out_w then
+ Term_putch(xml.write_x - xml.write_off_x + xml.write_out_x, xml.write_y - xml.write_off_y + xml.write_out_y, color, strbyte(c))
+ end
+ xml.write_x = xml.write_x + 1
+ else
+ xml.write_x = 0
+ xml.write_y = xml.write_y + 1
+ end
+ end
+end
+
+xml.write_file = function (color, s)
+ print_hook(s)
+end
+
+xml.write = xml.write_screen
+
+xml.rule2string = {
+ ['name'] = {"Its ", "name", " is"},
+ ['contain'] = {"Its ", "name", " contains"},
+ ['symbol'] = {"Its ", "symbol", " is"},
+ ['inscribed'] = {"Its ", "inscription", " contains"},
+ ['state'] = {"Its ", "state", " is"},
+ ['status'] = {"Its ", "status", " is"},
+ ['tval'] = {"Its ", "tval", " is"},
+ ['race'] = {"Your ", "race", " is"},
+ ['subrace'] = {"Your ", "subrace", " is"},
+ ['class'] = {"Your ", "class", " is"},
+ ['foo1'] = {"The result of ", "test 1 ", "is"},
+ ['foo2'] = {"The result of ", "test 2 ", "is"},
+ ['foo3'] = {"The result of ", "test 3 ", "is"},
+}
+
+xml.display_english = 1
+function xml:display_xml(t, tab)
+ if xml.display_english then
+ xml:english_xml(t, tab)
+ else
+ xml:print_xml(t, tab)
+ end
+end
+
+function xml:english_xml(t, tab, not_flag)
+ local i, k, e
+ local pre, post, recurse
+ local children_not_flag
+ local nextlevel
+ local bcol, ecol = TERM_L_GREEN, TERM_GREEN
+
+ if xml.write_active and t == auto_aux.rule then bcol, ecol = TERM_VIOLET, TERM_VIOLET end
+
+ nextlevel = tab .. " "
+
+ recurse = 1
+
+ if t.label == "rule" then
+ if t.args.type == "inscribe" then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "A rule named \"")
+ xml.write(TERM_WHITE, tostring(t.args.name))
+ xml.write(ecol, "\" to ")
+ xml.write(bcol, "inscribe")
+ xml.write(ecol, " an item with \"")
+ xml.write(TERM_WHITE, t.args.inscription)
+ xml.write(ecol, "\" when")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "A rule named \"")
+ xml.write(TERM_WHITE, tostring(t.args.name))
+ xml.write(ecol, "\" to ")
+ xml.write(bcol, t.args.type)
+ xml.write(ecol, " when")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "and" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "At least one of the following is false:")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "All of the following are true:")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "or" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "All of the following are false:")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "At least one of the following are true:")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "not" then
+ if bcol == TERM_VIOLET or getn(t) == 0 then
+ xml.write(ecol, "(a negating rule)")
+ xml.write(TERM_WHITE, "\n")
+ else
+ nextlevel = tab
+ end
+ children_not_flag = not nil
+ elseif t.label == "inventory" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Nothing in your ")
+ xml.write(bcol, "inventory")
+ xml.write(ecol, " matches the following:")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Something in your ")
+ xml.write(bcol, "inventory")
+ xml.write(ecol, " matches the following:")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "equipment" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Nothing in your ")
+ xml.write(bcol, "equipment")
+ xml.write(ecol, " matches the following:")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Something in your ")
+ xml.write(bcol, "equipment")
+ xml.write(ecol, " matches the following:")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "comment" then
+ xml.write(TERM_WHITE, tab)
+ xml.write(TERM_WHITE, "(" .. t[1] .. ")")
+ xml.write(TERM_WHITE, "\n")
+ elseif t.label == "skill" then
+ local s = t[1]
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Your skill in ")
+ xml.write(bcol, s)
+ xml.write(ecol, " is not from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Your skill in ")
+ xml.write(bcol, s)
+ xml.write(ecol, " is from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "ability" then
+ local s = t[1]
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "You do not have the ")
+ xml.write(bcol, s)
+ xml.write(ecol, " ability")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "You have the ")
+ xml.write(bcol, s)
+ xml.write(ecol, " ability")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "level" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Your ")
+ xml.write(bcol, "level")
+ xml.write(ecol, " is not from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Your ")
+ xml.write(bcol, "level")
+ xml.write(ecol, " is from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "sval" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Its ")
+ xml.write(bcol, "sval")
+ xml.write(ecol, " is not from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Its ")
+ xml.write(bcol, "sval")
+ xml.write(ecol, " is from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "discount" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Its ")
+ xml.write(bcol, "discount")
+ xml.write(ecol, " is not from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Its ")
+ xml.write(bcol, "discount")
+ xml.write(ecol, " is from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ end
+ else
+ if xml.rule2string[t.label] then
+ local rule = xml.rule2string[t.label]
+ a, b, c = rule[1], rule[2], rule[3]
+ if not_flag then c = c .. " not" end
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, a)
+ xml.write(bcol, b)
+ xml.write(ecol, c)
+ xml.write(ecol, " \"")
+ xml.write(TERM_WHITE, t[1])
+ xml.write(ecol, "\"")
+ xml.write(TERM_WHITE, "\n")
+ else
+ if not_flag then
+ xml.write(bcol, "Not:\n")
+ tab = tab .. " "
+ xml:print_xml(t, tab)
+ return
+ end
+ end
+ end
+
+ for i = 1, getn(t) do
+ if type(t[i]) == "string" then
+ -- xml.write(TERM_WHITE, t[i].."\n")
+ else
+ xml:english_xml(t[i], nextlevel, children_not_flag)
+ end
+ end
+end
+
+function xml:print_xml(t, tab)
+ local i, k, e
+ local inside = nil
+ local bcol, ecol = TERM_L_GREEN, TERM_GREEN
+
+ if xml.write_active and t == auto_aux.rule then bcol, ecol = TERM_VIOLET, TERM_VIOLET end
+
+ xml.write(bcol, tab.."<"..t.label)
+ for k, e in t.args do
+ xml.write(TERM_L_BLUE, " "..k)
+ xml.write(TERM_WHITE, "=\"")
+ xml.write(TERM_YELLOW, e)
+ xml.write(TERM_WHITE, "\"")
+ end
+ xml.write(bcol, ">")
+
+ for i = 1, getn(t) do
+ if type(t[i]) == "string" then
+ xml.write(TERM_WHITE, t[i])
+ else
+ if not inside then xml.write(TERM_WHITE, "\n") end
+ inside = not nil
+ xml:print_xml(t[i], tab.." ")
+ end
+ end
+
+ if not inside then
+ xml.write(ecol, "</"..t.label..">\n")
+ else
+ xml.write(ecol, tab.."</"..t.label..">\n")
+ end
+end
+
+-- t is a table representing xml, outputs the xml code via xml.write()
+function xml:output(t)
+ local i
+ for i = 1, getn(t) do
+ xml:print_xml(t[i], "")
+ end
+end
diff --git a/lib/data/.cvsignore b/lib/data/.cvsignore
new file mode 100644
index 00000000..82490963
--- /dev/null
+++ b/lib/data/.cvsignore
@@ -0,0 +1,2 @@
+.cvsignore
+*.raw \ No newline at end of file
diff --git a/lib/data/delete.me b/lib/data/delete.me
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/lib/data/delete.me
diff --git a/lib/dngn/dun1.14 b/lib/dngn/dun1.14
new file mode 100644
index 00000000..6421e80b
--- /dev/null
+++ b/lib/dngn/dun1.14
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to the Heart of the Earth
+B:10
diff --git a/lib/dngn/dun10.0 b/lib/dngn/dun10.0
new file mode 100644
index 00000000..b89ce05e
--- /dev/null
+++ b/lib/dngn/dun10.0
@@ -0,0 +1,3 @@
+# Father branch is Mirkwood(1), on level 14
+A:1
+L:14
diff --git a/lib/dngn/dun11.20 b/lib/dngn/dun11.20
new file mode 100644
index 00000000..9cc611d3
--- /dev/null
+++ b/lib/dngn/dun11.20
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to the Nether Realm
+B:6
diff --git a/lib/dngn/dun11.22 b/lib/dngn/dun11.22
new file mode 100644
index 00000000..149e2c33
--- /dev/null
+++ b/lib/dngn/dun11.22
@@ -0,0 +1,2 @@
+#I'm downright evil
+F:NO_GENO |
diff --git a/lib/dngn/dun17.15 b/lib/dngn/dun17.15
new file mode 100644
index 00000000..d08bf5e7
--- /dev/null
+++ b/lib/dngn/dun17.15
@@ -0,0 +1,5 @@
+N:Machine
+U:s_factory.map
+D:The clatter of strange machinery surrounds you.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/dngn/dun18.0 b/lib/dngn/dun18.0
new file mode 100644
index 00000000..da1b6c27
--- /dev/null
+++ b/lib/dngn/dun18.0
@@ -0,0 +1,2 @@
+# The level is SAVED in the playername.mz? file
+#S:mz0
diff --git a/lib/dngn/dun18.1 b/lib/dngn/dun18.1
new file mode 100644
index 00000000..70f27718
--- /dev/null
+++ b/lib/dngn/dun18.1
@@ -0,0 +1,2 @@
+# The level is SAVED in the playername.mz? file
+#S:mz1
diff --git a/lib/dngn/dun19.11 b/lib/dngn/dun19.11
new file mode 100644
index 00000000..7fba690d
--- /dev/null
+++ b/lib/dngn/dun19.11
@@ -0,0 +1,5 @@
+N:Deathwatch
+U:s_death.map
+D:This level looks filled with evilness.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/dngn/dun2.31 b/lib/dngn/dun2.31
new file mode 100644
index 00000000..dd8669a5
--- /dev/null
+++ b/lib/dngn/dun2.31
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to the Mount Doom
+B:5
diff --git a/lib/dngn/dun22.10 b/lib/dngn/dun22.10
new file mode 100644
index 00000000..e7eb116e
--- /dev/null
+++ b/lib/dngn/dun22.10
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to the Small Water Cave
+B:24
diff --git a/lib/dngn/dun22.5 b/lib/dngn/dun22.5
new file mode 100644
index 00000000..11d8e51f
--- /dev/null
+++ b/lib/dngn/dun22.5
@@ -0,0 +1,5 @@
+N:Orc Town
+U:s_orc.map
+D:You hear orc warcries.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/dngn/dun24.0 b/lib/dngn/dun24.0
new file mode 100644
index 00000000..bbb93f85
--- /dev/null
+++ b/lib/dngn/dun24.0
@@ -0,0 +1,3 @@
+# Father branch is the Moria(22), on level 10
+A:22
+L:10
diff --git a/lib/dngn/dun29.15 b/lib/dngn/dun29.15
new file mode 100644
index 00000000..4df873b5
--- /dev/null
+++ b/lib/dngn/dun29.15
@@ -0,0 +1,6 @@
+N:Galleon
+U:s_ship.map
+D:A ship of antique design lies jammed in the ice here.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
+
diff --git a/lib/dngn/dun3.18 b/lib/dngn/dun3.18
new file mode 100644
index 00000000..84c0a74a
--- /dev/null
+++ b/lib/dngn/dun3.18
@@ -0,0 +1,5 @@
+N:Dim Gates
+U:s_gates.map
+D:Visions of death fill your mind.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/dngn/dun3.28 b/lib/dngn/dun3.28
new file mode 100644
index 00000000..0acd4193
--- /dev/null
+++ b/lib/dngn/dun3.28
@@ -0,0 +1,5 @@
+N:Nameless
+U:s_name.map
+D:You sense a powerful artifact here.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/dngn/dun3.3 b/lib/dngn/dun3.3
new file mode 100644
index 00000000..710ef5f8
--- /dev/null
+++ b/lib/dngn/dun3.3
@@ -0,0 +1,5 @@
+N:Crypt
+U:s_crypt.map
+D:Looks like a forgotten crypt...
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/dngn/dun5.0 b/lib/dngn/dun5.0
new file mode 100644
index 00000000..48a7bea6
--- /dev/null
+++ b/lib/dngn/dun5.0
@@ -0,0 +1,3 @@
+# Father branch is the Mordor, on level 32
+A:2
+L:31
diff --git a/lib/dngn/dun5.14 b/lib/dngn/dun5.14
new file mode 100644
index 00000000..3d7a3080
--- /dev/null
+++ b/lib/dngn/dun5.14
@@ -0,0 +1,14 @@
+# The level is SAVED in the playername.mdm file
+S:mdm
+
+# Use the map in s_doom.map file
+U:s_doom.map
+
+# Use Mt Doom as level name
+N:Mt Doom
+
+D:You finally reach the top of Mount Doom, here must lie the Great Fire.
+F:DESC
+F:NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:NO_TELEPORT
+
diff --git a/lib/dngn/dun6.0 b/lib/dngn/dun6.0
new file mode 100644
index 00000000..c750ea67
--- /dev/null
+++ b/lib/dngn/dun6.0
@@ -0,0 +1,3 @@
+# Father branch is Void(11), on level 20
+A:11
+L:20
diff --git a/lib/edit/a_info.txt b/lib/edit/a_info.txt
new file mode 100644
index 00000000..427d5060
--- /dev/null
+++ b/lib/edit/a_info.txt
@@ -0,0 +1,2889 @@
+# File: a_info.txt
+
+
+# This file is used to initialize the "lib/raw/a_info.raw" file, which is
+# used to initialize the "artifact" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/a_info.raw" file.
+
+
+# The artifact indexes are defined in "defines.h", and must not be changed.
+
+# Artifacts 1-15 are "special", 16-63 are "armor", and 64-127 are "weapons".
+
+# Hack -- "Grond" and "Morgoth" MUST have a rarity of one, or they might
+# not be dropped when Morgoth is killed. Note that they, like the "special"
+# artifacts, are never created "accidentally".
+
+# Artifacts now have descriptions. Special thanks to J.R.R Tolkien,
+# without whom the words would be unwritten, the images unconceived,
+# the deed undone.
+# -Leon Marrick
+# Contributors: Jeff Butler, Neal Hackler, Ethan Sicotte, Pat Tracy, Divia
+
+# Version stamp (required)
+
+V:2.0.0
+
+
+
+# The Phial of Galadriel
+
+N:1:of Galadriel
+I:39:100:4
+W:20:10:10:10000
+P:0:1d1:0:0:0
+F:ACTIVATE | SEARCH | LITE3 | LUCK
+F:INSTA_ART | HIDE_TYPE
+a:HARDCORE=LIGHT
+D:A small crystal phial, with the light of Earendil's Star contained inside.
+D:Its light is imperishable, and near it darkness cannot endure.
+
+
+# The Star of Elendil
+
+N:2:of Elendil
+I:39:101:1
+W:30:25:5:32500
+P:0:1d1:0:0:0
+F:ACTIVATE | SEE_INVIS | HOLD_LIFE |
+F:INSTA_ART | SPEED | LITE3 | LITE1 | HIDE_TYPE
+a:HARDCORE=MAP_LIGHT
+Z:detect curses
+D:The shining Star of the West, a famed heirloom of Elendil's house.
+
+
+# The Arkenstone of Thrain
+# Was +2 WIS/DEX
+
+N:3:of Thrain
+I:39:102:3
+W:50:50:5:50000
+P:0:1d1:0:0:0
+F:ACTIVATE | SEE_INVIS | HOLD_LIFE | RES_CHAOS | HIDE_TYPE | LUCK
+F:INSTA_ART | SPEED | RES_LITE | RES_DARK | ESP_ORC | LITE3
+a:HARDCORE=THRAIN
+D:A great globe seemingly filled with moonlight, the famed Heart of the
+D:Mountain, which splinters the light that falls upon it into a thousand
+D:glowing shards.
+
+
+# The Amulet of Carlammas
+
+N:4:of Carlammas
+I:40:10:2
+W:50:10:3:60000
+F:CON | HIDE_TYPE |
+F:ACTIVATE | RES_FIRE |
+F:INSTA_ART
+a:HARDCORE=PROT_EVIL
+D:A fiery circle of bronze, with mighty spells to ward off evil.
+
+
+# The Amulet of Ingwe
+
+N:5:of Ingwe
+I:40:11:3
+W:65:30:3:90000
+F:INT | WIS | CHR | SEARCH | INFRA | HIDE_TYPE |
+F:SEE_INVIS | FREE_ACT | ACTIVATE |
+F:RES_ACID | RES_COLD | RES_ELEC |
+F:INSTA_ART
+a:HARDCORE=DISP_EVIL
+D:The ancient heirloom of Ingwe, high lord of the Vanyar, against whom nothing
+D:of evil could stand.
+
+
+# The Necklace 'Nauglamir'
+
+N:6:'Nauglamir'
+I:40:12:3
+W:70:50:3:75000
+F:STR | CON | DEX | INFRA | HIDE_TYPE | RES_FEAR |
+F:SEE_INVIS | FREE_ACT | REGEN | LITE3 | SPEED |
+F:INSTA_ART
+D:A carencet of gold, set with a multitude of shining gems of
+D:Valinor. Despite its size, its weight seems as that of gossamer.
+
+
+# The Ring of Flare
+# (note: pval reduced to 3, otherwise it would probably be preferable
+# even to The One Ring!)
+
+N:7:of Flare
+I:45:52:3
+W:50:35:2:75000
+F:STR | CON | CHR | HIDE_TYPE |
+F:IM_FIRE | ACTIVATE | SEARCH |
+F:ESP_THUNDERLORD | SEE_INVIS | FLY |
+F:INSTA_ART
+a:HARDCORE=DIM_DOOR
+Z:swap position
+D:The mighty ring of the Thunderlord Flare that makes the wearer
+D:strong and healthy. Once a ring of power, it was
+D:given to Flare by Celegorm when he arrived on Middle-earth with a full nest
+D:of Thunderlords.
+
+
+# The Ring of Barahir
+
+N:8:of Barahir
+I:45:32:1
+W:50:25:2:75000
+F:STR | INT | WIS | DEX | CON | CHR | STEALTH | HIDE_TYPE |
+F:RES_POIS | RES_DARK | ACTIVATE | SEE_INVIS | SEARCH |
+F:INSTA_ART
+a:HARDCORE=BARAHIR
+D:A ring shaped into twinned serpents with eyes of emerald meeting beneath
+D:a crown of flowers, an ancient treasure of Isildur's house.
+
+
+# The Ring of Tulkas
+
+N:9:of Tulkas
+I:45:33:4
+W:70:50:2:175000
+F:STR | DEX | CON | HIDE_TYPE |
+F:ACTIVATE | SPEED | ESP_EVIL |
+F:INSTA_ART
+a:HARDCORE=TULKAS
+D:The treasure of Tulkas, most fleet and wrathful of the Valar.
+
+
+# The Ring of Power 'Narya'
+
+N:10:of Power 'Narya'
+I:45:34:1
+W:70:30:2:100000
+P:0:1d1:6:6:0
+F:STR | INT | WIS | DEX | CON | CHR | SPEED | HIDE_TYPE | LUCK
+F:ACTIVATE | FREE_ACT | SEE_INVIS |
+F:SUST_STR | SUST_CON | SUST_WIS | SUST_CHR | SPECIAL_GENE |
+F:IM_FIRE | RES_NETHER | RES_FEAR | REGEN |
+F:INSTA_ART
+a:HARDCORE=NARYA
+D:The Ring of Fire, set with a ruby that glows like flame. Narya is one
+D:of the three Rings of Power created by the Elves and hidden by them from
+D:Sauron.
+
+
+# The Ring of Power 'Nenya'
+
+N:11:of Power 'Nenya'
+I:45:35:2
+W:80:40:2:200000
+P:0:1d1:9:9:0
+F:STR | INT | WIS | DEX | CON | CHR | SPEED | HIDE_TYPE | LUCK
+F:ACTIVATE | HOLD_LIFE | FREE_ACT | SEE_INVIS |
+F:SUST_INT | SUST_WIS | SUST_CHR |
+F:IM_COLD | RES_BLIND | STEALTH | ESP_ALL |
+F:INSTA_ART
+a:HARDCORE=NENYA
+D:The Ring of Adamant, with a pure white stone as centrepiece. Nenya is one
+D:of the three Rings of Power created by the Elves and hidden by them from
+D:Sauron.
+
+
+# The Ring of Power 'Vilya'
+
+N:12:of Power 'Vilya'
+I:45:36:3
+W:90:50:2:300000
+P:0:1d1:12:12:0
+F:STR | INT | WIS | DEX | CON | CHR | SPEED | HIDE_TYPE | LUCK
+F:ACTIVATE | HOLD_LIFE | FREE_ACT | SEE_INVIS |
+F:FEATHER | SLOW_DIGEST | REGEN |
+F:SUST_STR | SUST_DEX | SUST_CON |
+F:IM_ELEC | RES_POIS | RES_DISEN |
+F:INSTA_ART
+a:HARDCORE=VILYA
+D:The Ring of Sapphire, with clear blue gems that shine like stars,
+D:glittering untouchable despite all that Sauron ever wrought. Vilya is
+D:one of the three Rings of Power created by the Elves and hidden by them
+D:from Sauron.
+
+
+# The Ring of Power 'The One Ring'
+
+N:13:of Power 'The One Ring'
+I:45:37:5
+W:100:100:2:5000000
+P:0:1d1:15:15:0
+F:STR | INT | WIS | DEX | CON | CHR | SPEED | HIDE_TYPE |
+F:ACTIVATE | AUTO_CURSE | HEAVY_CURSE | INVIS | SPELL | MANA |
+F:SEE_INVIS | REGEN | FREE_ACT | CURSED | CURSE_NO_DROP |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | PERMA_CURSE |
+F:SUST_STR | SUST_DEX | SUST_CON |
+F:SUST_INT | SUST_WIS | SUST_CHR |
+F:RES_BLIND | RES_POIS | RES_DISEN | RES_NETHER | ESP_ALL |
+F:DRAIN_MANA | DRAIN_HP | DRAIN_EXP |
+F:INSTA_ART
+a:HARDCORE=POWER
+Z:change the world
+D:"Ash nazg durbatuluk, ash nazg gimbatul, ash nazg thrakatuluk agh
+D:burzum-ishi krimpatul". Unadorned, made of massive gold,
+D:set with runes in the foul speech of Mordor, with power so great that it
+D:inevitably twists and masters any earthly being who wears it.
+
+
+# The Anchor of Space-Time
+
+N:14:of Space-Time
+I:39:105:0
+W:30:12:15:50000
+P:0:1d1:0:0:0
+F:INSTA_ART | LITE1
+D:A powerful stone that provides a strong light for any who
+D:wields it. It is rumoured that it may even protect the wearer from
+D:the passing of time.
+
+
+# This artifact has a low artifact level to prevent it being worthless for
+# chars with poor magic skills.
+
+# The Stone of Lore
+
+N:15:of Lore
+I:39:106:0
+W:15:12:15:20000
+P:0:1d1:0:0:0
+F:ACTIVATE | SPECIAL_GENE | EASY_USE | LITE1 |
+F:INSTA_ART
+a:HARDCORE=STONE_LORE
+D:A great emerald that fills your mind with images of knowledge and dreadful
+D:understanding as you stare into its depths.
+
+
+# The Multi-Hued Dragon Scale Mail 'Razorback'
+
+N:16:'Razorback'
+I:38:6:0
+W:90:9:500:400000
+P:30:2d4:-4:0:25
+F:FREE_ACT | IM_ELEC | SPECIAL_GENE |
+F:RES_FIRE | RES_COLD | RES_POIS | RES_LITE | RES_DARK |
+F:LITE1 | SEE_INVIS | AGGRAVATE | ESP_DRAGON
+F:ACTIVATE
+a:HARDCORE=RAZORBACK
+D:A massive suit of heavy dragon scales deeply saturated with many colours.
+D:It throbs with angry energies, and you feel the raw elemental might of
+D:untamed Lightning as you put it on.
+
+
+# The Power Dragon Scale Mail of Eternity
+# The ULTIMATE armour
+
+N:17:of Eternity
+I:38:30:0
+W:100:16:600:500000
+P:50:2d4:-8:0:35
+F:HOLD_LIFE | REGEN | ESP_DRAGON |
+F:RES_ACID | RES_FIRE | RES_COLD | RES_ELEC | RES_POIS | FEATHER | FLY |
+F:RES_NETHER | RES_NEXUS | RES_CHAOS | RES_LITE | RES_DARK | ULTIMATE |
+F:RES_SHARDS | RES_SOUND | RES_DISEN | RES_BLIND | RES_CONF |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | SPECIAL_GENE
+F:ACTIVATE
+a:HARDCORE=BLADETURNER
+D:A suit of adamant, set with scales of every colour, surrounded in a nimbus
+D:of perfectly untramelled yet inextricably intermingled and utterly mastered
+D:powers elemental and ethereal.
+
+
+# The Spear of Melkor
+
+N:18:of Melkor
+I:22:2:-4
+W:65:45:200:100000
+P:0:4d6:12:24:0
+F:STEALTH | WIS | CURSED | HEAVY_CURSE | TY_CURSE | ESP_GOOD |
+F:DRAIN_MANA | DRAIN_HP |
+F:RES_DARK | RES_BLIND | RES_LITE | RES_NETHER | BRAND_POIS | RES_CONF
+D:The mighty spear used once by Melkor to slay the trees of Valinor.
+
+
+# The Adamantite Plate Mail 'Soulkeeper'
+
+N:19:'Soulkeeper'
+I:37:30:2
+W:75:9:420:300000
+P:40:2d4:-4:0:20
+F:CON |
+F:HOLD_LIFE | SUST_CON | ESP_UNDEAD | RES_CONF | RES_FEAR |
+F:RES_ACID | RES_COLD | RES_DARK | RES_NETHER | RES_NEXUS | RES_CHAOS |
+F:ACTIVATE
+a:HARDCORE=CURE_1000
+D:A suit of imperishable adamant, with unconquerable strength to endure evil
+D:and disruptive magics, that protects the life force of its wearer as
+D:nothing else can.
+
+
+# The Full Plate Armour of Isildur
+
+N:20:of Isildur
+I:37:15:1
+W:30:3:300:50000
+P:25:2d4:0:0:25
+F:CON |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:RES_SOUND | RES_CONF | RES_NEXUS
+D:A gleaming steel suit covering the wearer from neck to foot, with runes of
+D:warding and stability deeply engraved into its surface.
+
+
+# The Metal Brigandine Armour of the Rohirrim
+
+N:21:of the Rohirrim
+I:37:9:2
+W:30:3:200:30000
+P:19:1d4:0:0:15
+F:STR | DEX | SPEED | HIDE_TYPE | RES_FEAR |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_CONF | RES_SOUND
+D:A stiff suit of armour composed of small metal plates sewn to an
+D:inner layer of heavy canvas, and covered with a second layer of
+D:cloth. Within it is the spirit of Eorl the Young, matchless in combat.
+
+
+# The Mithril Chain Mail 'Belegennon'
+
+N:22:'Belegennon'
+I:37:20:4
+W:40:10:150:135000
+P:28:1d4:-1:0:20
+F:STEALTH | WIS | INT |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS |
+F:HOLD_LIFE | RES_DARK | RES_FEAR |
+F:SEE_INVIS |
+F:ACTIVATE
+a:HARDCORE=BELEGENNON
+D:This wondrous suit of fine-linked chain shimmers as though of pure silver.
+D:It stands untouched amidst the fury of the elements, and a power of
+D:concealment rests within.
+
+
+# The Mithril Plate Mail of Celeborn
+
+N:23:of Celeborn
+I:37:25:4
+W:40:3:250:150000
+P:35:2d4:-3:0:25
+F:STR | CHR | HIDE_TYPE | ESP_ORC
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_DARK |
+F:RES_DISEN | ACTIVATE
+a:HARDCORE=GENOCIDE
+D:A shimmering suit of true-silver, forged long ago by dwarven smiths of
+D:legend. It gleams with purest white as you gaze upon it, and mighty are
+D:its powers to protect and banish.
+
+
+# The Chain Mail of Arvedui
+
+N:24:of Arvedui
+I:37:4:2
+W:20:3:220:32000
+P:14:1d4:-2:0:15
+F:STR | CHR | HIDE_TYPE |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_SHARDS | RES_NEXUS
+D:A hauberk, leggings, and sleeves of interlocking steel rings, well padded
+D:with leather. You feel strong and tall as Arvedui, last king of Arnor,
+D:as you put it on.
+
+
+# The Augmented Chain Mail of Caspanion
+
+N:25:of Caspanion
+I:37:6:3
+W:25:9:270:40000
+P:16:1d4:-2:0:20
+F:INT | WIS | CON | HIDE_TYPE |
+F:RES_ACID | RES_POIS | RES_CONF | ACTIVATE
+a:HARDCORE=DEST_DOOR
+D:A hauberk, leggings, and sleeves of interlocking steel rings, strategically
+D:reinforced at vital locations with a second layer of chain. Magics to
+D:enhance body and mind lie within, and no door can hope to resist the wearer.
+
+
+# The Thunderlord Coat of Marda
+
+N:26:of Marda
+I:36:16:5
+W:70:3:80:80000
+P:9:0d0:0:0:25
+F:FREE_ACT | RES_BLIND | RES_CONF | RES_FEAR | DRAIN_MANA |
+F:REFLECT | RES_NEXUS | SH_FIRE | SUST_INT | SUST_CON | SUST_CHR |
+F:ESP_THUNDERLORD | CON | CHR | INT |
+F:RES_ACID | RES_ELEC | IM_COLD | RES_COLD | AGGRAVATE | HEAVY_CURSE |
+F:CURSED
+D:The flying suit of Marda, very powerful armour that protects
+D:the wearer from cold. Wonderful as this mighty
+D:armour is, beware wearing it, for it has been cursed by a
+D:powerful wizard since Marda had it and is said to have gained
+D:a couple of undesirable side-effects...
+
+
+# The Thunderlord Coat of Trone
+
+N:27:of Trone
+I:36:16:4
+W:30:3:80:65000
+P:9:0d0:0:0:20
+F:REFLECT | RES_NEXUS | SH_FIRE | FLY | SPECIAL_GENE |
+F:STEALTH | ESP_THUNDERLORD | CON | INT | SPEED |
+F:RES_ACID | RES_ELEC | IM_FIRE | RES_COLD
+D:The flying suit of Trone. It protects the user from fire and
+D:imps are said to be less annoying with this on.
+
+
+# The Leather Scale Mail 'Thalkettoth'
+
+N:28:'Thalkettoth'
+I:36:11:3
+W:20:3:60:25000
+P:11:1d1:-1:0:25
+F:DEX | SPEED | HIDE_TYPE | SPECIAL_GENE |
+F:RES_ACID | RES_SHARDS
+D:A tunic and skirt sewn with thick, overlapping scales of hardened
+D:leather whose wearer moves with agility and assurance.
+
+
+# The Pair of Soft Leather Boots of Wormtongue
+
+N:29:of Wormtongue
+I:30:2:3
+W:40:20:20:50000
+P:2:1d1:-10:-10:10
+F:INT | DEX | CHR | STEALTH | SEARCH | SPEED | HIDE_TYPE |
+F:FREE_ACT | FEATHER | RES_DARK | RES_LITE | ESP_GOOD | ESP_UNIQUE
+Z:panic hit
+D:The pair of boots used by Grima son of Galmod, also named the Wormtongue:
+D:a treacherous but persuasive counsellor, ever ready to betray, sneak,
+D:lie, cheat and steal - but never ready to actually fight.
+
+
+# The Small Metal Shield of Thorin
+
+N:30:of Thorin
+I:34:3:4
+W:30:6:65:60000
+P:3:1d2:0:0:25
+F:STR | CON | HIDE_TYPE |
+F:FREE_ACT | IM_ACID | RES_SOUND |
+F:RES_CHAOS | ESP_ORC
+D:Invoking the strength and endurance of Thorin, King under the Mountain,
+D:this little metal shield is proof against the Element of Earth.
+
+
+# The Large Leather Shield of Celegorm
+
+N:31:of Celegorm
+I:34:4:0
+W:30:3:60:12000
+P:4:1d2:0:0:20
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_LITE | RES_DARK
+D:This shield emblazoned with a multitude of creatures not seen for ages
+D:once protected Celegorm, lord of Himlad; around it lies a mystic balance
+D:that contains the conflicts of the elements.
+
+
+# The Large Metal Shield of Anarion
+
+N:32:of Anarion
+I:34:5:0
+W:40:9:120:160000
+P:5:1d3:0:0:20
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | SUST_STR | SUST_INT |
+F:SUST_WIS | SUST_DEX | SUST_CON | SUST_CHR | ESP_EVIL
+D:The great metal-bound shield of Anarion, son of Elendil, who Sauron found
+D:himself powerless to wither or diminish.
+
+
+# The Beaked Axe of Hurin
+
+N:33:of Hurin
+I:22:10:3
+W:20:15:180:90000
+P:0:2d6:12:20:0
+F:STR | CON | HIDE_TYPE | BRAND_ACID | RES_ACID | LITE1 | DRAIN_MANA |
+F:SLAY_ORC | KILL_DEMON | SLAY_TROLL | ACTIVATE | SHOW_MODS
+F:MUST2H
+f:MUST2H
+a:HARDCORE=HURIN
+D:Wielded by Hurin Thalion in the Fifth Battle of Beleriand, this
+D:troll-bane smoked in the black blood of Gothmog's guards.
+
+
+# The Massive Iron Crown of Morgoth
+
+N:34:of Morgoth
+I:33:50:125
+W:100:1:20:10000000
+P:0:1d1:0:0:0
+F:STR | INT | WIS | DEX | CON | CHR | INFRA | HIDE_TYPE |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS |
+F:RES_LITE | RES_DARK | RES_CONF | RES_NEXUS | RES_NETHER |
+F:LITE1 | SEE_INVIS | ESP_ALL |
+F:CURSED | HEAVY_CURSE | PERMA_CURSE |
+F:INSTA_ART | SPECIAL_GENE
+D:Two Silmarils of Feanor blaze from the thunderous crown of twisted
+D:iron. The corrupted metal feels at once as infernal as hellfire
+D:and as chilling as the Outer Darkness. One protrusion from the
+D:crown is abruptly ended where a third jewel might have shone.
+
+
+# The Iron Crown of Beruthiel
+
+N:35:of Beruthiel
+I:33:10:-5
+W:40:12:20:0
+P:0:1d1:0:0:20
+F:STR | DEX | CON | HIDE_TYPE |
+F:FREE_ACT | SEE_INVIS | ESP_ANIMAL | ESP_EVIL | ESP_NONLIVING | ESP_ALL |
+F:CURSED | AUTO_CURSE
+D:The midnight-hued steel circlet of the sorceress-queen Beruthiel, which
+D:grants extraordinary powers of sight and awareness at a terrible physical
+D:cost.
+
+
+# The Hard Leather Cap of Thranduil
+
+N:36:of Thranduil
+I:32:2:2
+W:20:2:15:50000
+P:2:0d0:0:0:10
+F:INT | WIS | HIDE_TYPE |
+F:RES_BLIND | ESP_ORC | ESP_EVIL | ESP_TROLL
+D:The hunting cap of King Thranduil, to whose ears come all the secrets of
+D:his forest domain.
+
+
+# The Metal Cap of Thengel
+
+N:37:of Thengel
+I:32:3:3
+W:10:2:20:22000
+P:3:1d1:0:0:12
+F:WIS | CHR | RES_CONF | HIDE_TYPE | LUCK
+D:A ridged helmet made of steel, and embossed with scenes of valour in fine-
+D:engraved silver. It grants the wearer nobility, clarity of thought and
+D:understanding.
+
+
+# The Steel Helm of Hammerhand
+
+N:38:of Hammerhand
+I:32:6:3
+W:20:2:60:45000
+P:6:1d3:0:0:20
+F:STR | DEX | CON | HIDE_TYPE | SPECIAL_GENE | RES_FEAR |
+F:SUST_STR | SUST_DEX | SUST_CON |
+F:RES_ACID | RES_NEXUS | RES_COLD | RES_DARK | SLOW_DIGEST |
+Z:berserk
+D:A great helm as steady as the heroes of the Westdike. Mighty were the
+D:blows of Helm, the Hammerhand!
+
+
+# The Dragon Helm of Dor-Lomin
+
+N:39:of Dor-Lomin
+I:32:7:4
+W:40:12:75:300000
+P:8:1d3:0:0:20
+F:STR | DEX | CON | HIDE_TYPE |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_LITE | RES_BLIND |
+F:LITE1 | SEE_INVIS | ESP_DRAGON | ESP_THUNDERLORD | ACTIVATE
+a:HARDCORE=GORLIM
+D:The legendary dragon helm of Turin Turambar, an object of dread to the
+D:servants of Morgoth.
+
+# The Iron Helm 'Holhenneth'
+
+N:40:'Holhenneth'
+I:32:5:2
+W:20:5:75:100000
+P:5:1d3:0:0:10
+F:INT | WIS | SEARCH | HIDE_TYPE |
+F:RES_BLIND | SEE_INVIS | ACTIVATE
+a:HARDCORE=DETECT_ALL
+D:A famous helm of forged iron granting extraordinary powers of mind and
+D:awareness.
+
+
+# The Iron Helm of Gorlim
+
+N:41:of Gorlim
+I:32:5:-5
+W:20:5:75:0
+P:5:1d3:25:25:10
+F:INT | WIS | SEARCH | HIDE_TYPE | SHOW_MODS |
+F:SEE_INVIS | NO_MAGIC | HEAVY_CURSE | TY_CURSE
+F:RES_DISEN | RES_FEAR | FREE_ACT | RES_ACID | RES_FIRE | RES_POIS |
+F:IM_COLD | ACTIVATE | DRAIN_HP |
+F:TELEPORT | CURSED
+a:HARDCORE=GORLIM
+D:A headpiece, gaudy and barbaric, that betrayed a warrior when he most
+D:needed succor.
+
+
+# The Golden Crown of Gondor
+
+N:42:of Gondor
+I:33:11:3
+W:40:40:30:125000
+P:0:1d1:0:0:15
+F:STR | WIS | CON | HIDE_TYPE | SPEED | RES_CONF | RES_SOUND |
+F:RES_COLD | RES_FIRE | RES_LITE | RES_BLIND | RES_ELEC | RES_CHAOS |
+F:LITE1 | SEE_INVIS | REGEN | ACTIVATE
+a:HARDCORE=CURE_700
+D:The shining winged circlet brought by Elendil from dying Numenor, emblem of
+D:Gondor through an age of the world.
+
+
+# The Jewel Encrusted Crown of Numenor
+# Stolen from Oangband
+
+N:43:of Numenor
+I:33:12:3
+W:60:30:40:50000
+P:0:1d1:0:0:18
+F:INT | DEX | CHR | SEARCH | SPEED | HIDE_TYPE |
+F:SEE_INVIS | FREE_ACT | RES_DARK | RES_BLIND |
+F:RES_SHARDS | RES_SOUND | RES_LITE | RES_COLD |
+F:LITE1 | ACTIVATE | DRAIN_MANA
+a:HARDCORE=NUMENOR
+D:A crown of massive gold, set with wondrous jewels of thought and warding,
+D:worn by the kings of ancient Numenor. Its wearer may go into battle
+D:always knowing what he faces - unless his own folly blinds him to the
+D:nature and magnitude of the task.
+
+
+# The Cloak 'Colluin'
+
+N:44:'Colluin'
+I:35:1:0
+W:5:45:10:40000
+P:1:0d0:0:0:20
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS | ACTIVATE | ESP_GOOD
+a:HARDCORE=COLLUIN
+D:A cape worn by a hero from Valinor, a land utterly beyond the strife
+D:of Elements.
+
+
+# The Cloak 'Holcolleth'
+
+N:45:'Holcolleth'
+I:35:1:2
+W:5:25:10:13000
+P:1:0d0:0:0:4
+F:INT | WIS | SPEED | STEALTH | HIDE_TYPE |
+F:RES_ACID | ACTIVATE
+a:HARDCORE=SLEEP
+D:This elven-grey mantle possesses great powers of tranquility and of
+D:concealment, and grants the wearer the knowledge and understanding of
+D:the Sindar.
+
+
+# The Cloak of Thingol
+
+N:46:of Thingol
+I:35:1:3
+W:10:50:10:35000
+P:1:0d0:0:0:18
+F:DEX | CHR | HIDE_TYPE |
+F:FREE_ACT | RES_ACID | RES_FIRE | RES_COLD | ACTIVATE
+a:HARDCORE=RECHARGE
+D:A sable-hued cloak, with glowing elven-runes to restore magic showing calm
+D:and clear as moonlight on still water.
+
+
+# The Cloak of Thorongil
+
+N:47:of Thorongil
+I:35:1:0
+W:5:10:10:8000
+P:1:0d0:0:0:10
+F:FREE_ACT | RES_ACID | SEE_INVIS | RES_FEAR
+D:A cloak of shimmering green and brown that grants sight beyond sight and
+D:shakes off holding magics, worn by Aragorn son of Arathorn in his youth
+D:as he adventured under the name of Thorongil.
+
+
+# The Cloak 'Colannon'
+
+N:48:'Colannon'
+I:35:1:3
+W:5:20:10:11000
+P:1:0d0:0:0:15
+F:STEALTH | SPEED | RES_NEXUS |
+F:RES_ACID | ACTIVATE
+a:HARDCORE=TELEPORT
+D:A crystal-blue cape of fine silk worn by a silent messenger of
+D:the forces of Law. Somehow, its wearer is always able to escape
+D:trouble.
+
+
+# The Shadow Cloak of Luthien
+
+N:49:of Luthien
+I:35:6:2
+W:40:40:5:55000
+P:6:0d0:0:0:20
+F:INT | WIS | CHR | HIDE_TYPE | SPEED | STEALTH | INVIS | LUCK
+F:RES_ACID | RES_FIRE | RES_COLD | SPECIAL_GENE | ACTIVATE | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=REST_LIFE
+D:The opaque midnight folds, inset with a multitude of tiny diamonds, of
+D:this cloak swirl around you and you feel a hint, a fragment of the
+D:knowledge and power to restore that lay in Luthien, the most beautiful
+D:being that ever knew death.
+
+
+# The Shadow Cloak of Tuor
+
+N:50:of Tuor
+I:35:6:4
+W:40:40:5:35000
+P:6:0d0:0:0:12
+F:STEALTH | DEX | HIDE_TYPE | INVIS | WATER_BREATH
+F:FREE_ACT | IM_ACID | SEE_INVIS | CLIMB
+D:From the ruin of Gondolin did Tuor escape, through secret ways and travail,
+D:shielded by his cloak from a multitude of hostile eyes.
+
+
+# The Main Gauche of Azaghal, which wounded Glaurung
+N:51:of Azaghal
+I:23:5:0
+W:15:30:30:40000
+P:0:2d5:12:14:0
+F:KILL_DRAGON | IM_FIRE | ESP_DRAGON | RES_FEAR
+D:The weapon of Azaghal when he wounded Glaurung. It is deadly
+D:when fighting dragons and is said to make the breaths of fire
+D:completely harmless.
+
+
+# The Set of Leather Gloves 'Cambeleg'
+
+N:52:'Cambeleg'
+I:31:1:2
+W:10:6:5:36000
+P:1:0d0:8:8:15
+F:STR | CON | HIDE_TYPE |
+F:FREE_ACT | SHOW_MODS
+D:A hero's handgear that lends great prowess in battle.
+
+
+# The Set of Leather Gloves 'Cammithrim'
+
+N:53:'Cammithrim'
+I:31:1:0
+W:10:3:5:30000
+P:1:0d0:0:0:10
+F:FREE_ACT | RES_LITE | SUST_CON | LITE1 | ACTIVATE
+F:SPECIAL_GENE
+a:HARDCORE=BO_MISS_1
+D:These gloves glow so brightly as to light the way for their owner and cast
+D:magical bolts with great frequency.
+
+
+# The Set of Gauntlets 'Paurhach'
+
+N:54:'Paurhach'
+I:31:2:0
+W:10:5:25:15000
+P:2:1d1:0:0:15
+F:RES_FIRE | ACTIVATE | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=BO_FIRE_1
+D:A fiery set of gauntlets that can even shoot fire from the user's
+D:hands.
+
+
+# The Set of Gauntlets 'Paurnimmen'
+
+N:55:'Paurnimmen'
+I:31:2:4
+W:10:5:25:33000
+P:2:1d1:0:0:15
+F:RES_COLD | ACTIVATE
+F:SUST_CON | CON | REGEN | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=BO_COLD_1
+D:A set of handgear so icy as to be able to fire frost bolts.
+
+
+# The Set of Gauntlets 'Pauraegen'
+
+N:56:'Pauraegen'
+I:31:2:0
+W:10:5:25:11000
+P:2:1d1:0:0:15
+F:RES_ELEC | ACTIVATE | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=BO_ELEC_1
+D:A set of handgear with sparks surrounding it, able to fire
+D:bolts of electricity.
+
+
+# The Set of Gauntlets 'Paurnen'
+
+N:57:'Paurnen'
+I:31:2:0
+W:10:5:25:12000
+P:2:1d1:0:0:15
+F:RES_ACID | ACTIVATE | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=BO_ACID_1
+D:A set of handgear so corrosive that it may fire bolts of acid.
+
+
+# The Set of Gauntlets 'Camlost'
+
+N:58:'Camlost'
+I:31:2:-3
+W:10:20:25:0
+P:2:1d1:-11:-12:0
+F:STR | DEX | HIDE_TYPE | DRAIN_MANA |
+F:RES_POIS | IM_FIRE | IM_COLD | RES_DISEN | RES_NETHER | FREE_ACT |
+F:AGGRAVATE | SHOW_MODS | HEAVY_CURSE | TY_CURSE | TELEPORT | CURSED
+D:A pair of gauntlets that sap combat ability, named after the empty hand
+D:of Beren that once clasped a Silmaril.
+
+
+# The Set of Cesti of Fingolfin
+
+N:59:of Fingolfin
+I:31:5:4
+W:40:15:40:110000
+P:5:1d1:10:10:20
+F:DEX | HIDE_TYPE | LUCK
+F:FREE_ACT | RES_ACID | ACTIVATE | SHOW_MODS
+a:HARDCORE=BO_MISS_2
+Z:magic missile
+D:The hand-sheathing of Fingolfin, warrior-king of Elves and Men, who gave
+D:Morgoth seven mighty wounds and pain that will last forever.
+
+
+# The Pair of Hard Leather Boots of Feanor
+
+N:60:of Feanor
+I:30:3:15
+W:40:120:40:300000
+P:3:1d1:0:0:20
+F:SPEED | HIDE_TYPE |
+F:RES_NEXUS | ACTIVATE
+a:HARDCORE=SPEED
+D:This wondrous pair of leather boots once sped Feanor, creator of the
+D:Silmarils and the mightiest of the Eldar, along the Grinding Ice and to
+D:Middle-earth at last.
+
+
+# The Pair of Soft Leather Boots 'Dal-i-thalion'
+
+N:61:'Dal-i-thalion'
+I:30:2:5
+W:10:25:20:40000
+P:2:1d1:0:0:15
+F:DEX | HIDE_TYPE | CHR | SUST_CHR |
+F:ACTIVATE | FREE_ACT |
+F:RES_NETHER | RES_CHAOS | RES_CONF | SUST_CON
+a:HARDCORE=CURE_POISON
+D:A pair of high-laced shoes, strong against the powers of corruption and
+D:withering, that grant the wearer extraordinary agility.
+
+
+# The Pair of Metal Shod Boots of Thror
+
+N:62:of Thror
+I:30:6:3
+W:30:25:80:15000
+P:6:1d1:0:0:20
+F:STR | CON | HIDE_TYPE | SPEED | RES_FEAR | CLIMB
+D:Sturdy footwear of leather and steel as enduring as the long-suffering
+D:Dwarven King-in-exile who wore them. Of dwarven make, these boots will
+D:make their wearer completely at home in the mountains.
+
+
+# The Seeker Arrow of Bard
+# This is, of course, from my 'Artifact Ammo' thread and doesn't need much
+# explanation. It's rather nasty and deals 1000 or more damage on a
+# normal hit to a dragon. :) Doesn't put a dent in Sky Drakes and Power
+# Dragons, tho it's still good for helping to take down Smaug, Tiamat and
+# the other dragon uniques.
+# P+ changed name, rarity to 30
+
+N:63:of Bard
+I:17:2:0
+W:55:30:2:50000
+P:0:8d4:20:15:0
+F:SLAY_ANIMAL | SLAY_EVIL | SLAY_UNDEAD | SLAY_DEMON |
+F:SLAY_ORC | SLAY_TROLL | SLAY_GIANT | SLAY_DRAGON | KILL_DRAGON |
+F:BRAND_ACID | BRAND_ELEC | BRAND_FIRE | BRAND_COLD | BRAND_POIS
+D:Deadliest of arrows, imbued with elemental strength, this shaft is
+D:feared especially by the wyrmkin.
+
+
+# The Main Gauche of Maedhros
+
+N:64:of Maedhros
+I:23:5:3
+W:15:30:30:22500
+P:0:2d5:12:15:0
+F:INT | DEX | HIDE_TYPE | SPEED | SPECIAL_GENE
+F:SLAY_TROLL | SLAY_GIANT | FREE_ACT | SEE_INVIS | SHOW_MODS
+D:A short thrusting blade with a large guard worn by Maedhros the Tall,
+D:eldest son of Feanor, and wielded with his left hand after the loss of
+D:his right hand in the pits of Thangorodrim.
+
+
+# The Dagger 'Angrist'
+
+N:65:'Angrist'
+I:23:4:4
+W:20:80:12:125000
+P:0:2d4:10:15:5
+F:DEX | HIDE_TYPE | STEALTH | SEARCH | BRAND_POIS |
+F:SLAY_EVIL | SLAY_TROLL | SLAY_ORC | BRAND_ACID |
+F:FREE_ACT | RES_DARK | SUST_DEX | SEE_INVIS |
+F:SHOW_MODS
+D:Forged from meteoric iron, this long chopping dagger slices through
+D:ordinary metal as easily as its title, "Iron Cleaver", suggests.
+
+
+# The Dagger 'Narthanc'
+
+N:66:'Narthanc'
+I:23:4:0
+W:4:100:12:12000
+P:0:1d4:4:6:0
+F:BRAND_FIRE | RES_FIRE | ACTIVATE | SHOW_MODS | LITE1 | LEVELS
+a:HARDCORE=BO_FIRE_1
+D:A fiery dagger finely balanced for deadly throws.
+
+
+# The Dagger 'Nimthanc'
+
+N:67:'Nimthanc'
+I:23:4:0
+W:3:100:12:11000
+P:0:1d4:4:6:0
+F:BRAND_COLD | RES_COLD | ACTIVATE | SHOW_MODS | LEVELS
+a:HARDCORE=BO_COLD_1
+D:A frosty dagger finely balanced for deadly throws.
+
+
+# The Dagger 'Dethanc'
+
+N:68:'Dethanc'
+I:23:4:0
+W:5:100:12:13000
+P:0:1d4:4:6:0
+F:BRAND_ELEC | RES_ELEC | ACTIVATE | SHOW_MODS | LEVELS
+a:HARDCORE=BO_ELEC_1
+D:A dagger covered in sparks and finely balanced for deadly throws.
+
+
+# The Dagger of Rilia
+
+N:69:of Rilia
+I:23:4:0
+W:5:40:12:35000
+P:0:2d4:4:3:0
+F:SLAY_ORC | RES_POIS | RES_DISEN | ACTIVATE | SHOW_MODS | BRAND_POIS
+a:HARDCORE=BA_POIS_1
+D:A large stiletto dagger that glistens with odourless poison, to which the
+D:wearer seems oddly immune.
+
+
+# The Dagger 'Belangil'
+
+N:70:'Belangil'
+I:23:4:2
+W:10:40:12:50000
+P:0:2d4:6:9:0
+F:DEX | HIDE_TYPE | SPEED | BLOWS |
+F:BRAND_COLD | RES_COLD |
+F:SEE_INVIS | SLOW_DIGEST | REGEN |
+F:ACTIVATE | SHOW_MODS | BRAND_POIS
+a:HARDCORE=BELANGIL
+D:A frosty dagger surrounded in a nimbus of ice with a hilt of elk horn and
+D:an edge to wound the wind.
+
+
+# The Bastard Sword 'Calris'
+
+N:71:'Calris'
+I:23:21:5
+W:30:15:140:100000
+P:0:5d4:-20:20:0
+F:CON | HIDE_TYPE | DRAIN_HP |
+F:KILL_DRAGON | SLAY_EVIL | SLAY_DEMON | SLAY_TROLL | RES_DISEN |
+F:AGGRAVATE | CURSED | HEAVY_CURSE | SHOW_MODS | ESP_DRAGON | ESP_DEMON
+F:AUTO_CURSE
+F:COULD2H
+f:COULD2H
+D:This sword has runes of power incised on its ornate hilt and a single
+D:blood channel that gleams coldly blue as you grasp this mighty weapon of
+D:peril.
+
+
+# The Broad Sword 'Aranruth'
+
+N:72:'Aranruth'
+I:23:16:4
+W:20:45:150:125000
+P:0:3d5:20:12:0
+F:STR | DEX | CON | SUST_CON | SUST_STR
+F:REGEN | FREE_ACT | SEE_INVIS |
+F:RES_CHAOS | RES_NETHER | HOLD_LIFE | RES_FEAR |
+F:RES_COLD |
+F:SLAY_DEMON | SLAY_EVIL | SLAY_DRAGON | SLAY_UNDEAD |
+F:BRAND_COLD |
+F:SLOW_DIGEST | SHOW_MODS | HIDE_TYPE | BLESSED
+D:The beautiful sword of Thingol with a hilt of gold and silver inlay,
+D:glistening icily enough to freeze the hearts of demons. You feel supple
+D:and lightfooted as you hold it.
+
+
+# The Broad Sword 'Glamdring'
+
+N:73:'Glamdring'
+I:23:16:1
+W:20:20:150:40000
+P:0:2d5:10:15:0
+F:SEARCH | HIDE_TYPE | BLESSED | SLAY_DEMON |
+F:SLAY_EVIL | BRAND_FIRE | SLAY_ORC | RES_FIRE | RES_LITE | LITE1 |
+F:SLOW_DIGEST | SHOW_MODS | ESP_ORC | SPECIAL_GENE |
+D:This fiery, shining blade earned its sobriquet "Foe-Hammer" from dying orcs
+D:who dared to come near hidden Gondolin.
+
+
+# The Broad Sword 'Aeglin'
+
+N:74:'Aeglin'
+I:23:16:4
+W:20:90:150:95000
+P:0:2d5:12:16:0
+F:SEARCH | BLESSED | LITE1 | HIDE_TYPE |
+F:BRAND_ELEC | SLAY_ORC | SLAY_GIANT | SLAY_TROLL | RES_FEAR |
+F:RES_ELEC | RES_FIRE | RES_BLIND | ESP_ORC | ESP_GIANT | ESP_TROLL |
+F:SLOW_DIGEST | SHOW_MODS
+D:Like unto Orcrist and Glamdring, and like them long lost, this sword is
+D:continually coved in tiny arcs of captive lightning that flash and dance
+D:eerily in the globe of light they create.
+
+
+# The Broad Sword 'Orcrist'
+
+N:75:'Orcrist'
+I:23:16:3
+W:20:20:150:40000
+P:0:2d5:10:15:0
+F:SEARCH | ESP_ORC | SLAY_DRAGON | ESP_DRAGON | RES_COLD | HIDE_TYPE |
+F:SLAY_EVIL | BRAND_COLD | SLAY_ORC | RES_COLD | LITE1 | RES_DARK |
+F:SLOW_DIGEST | SHOW_MODS
+D:This coldly gleaming blade is called simply "Biter", by orcs who came to
+D:know its power all too well.
+
+
+# The Two-Handed Sword 'Gurthang'
+
+N:76:'Gurthang'
+I:23:25:2
+W:30:30:200:100000
+P:0:3d6:13:17:0
+F:STR | HIDE_TYPE | VORPAL | ESP_DRAGON | DRAIN_HP |
+F:RES_FIRE | RES_POIS | BRAND_FIRE | BRAND_POIS |
+F:KILL_DRAGON | SLAY_TROLL | FREE_ACT | SLOW_DIGEST | REGEN | SHOW_MODS
+F:MUST2H
+f:MUST2H
+D:A giant sword once wielded by mighty Turin, and a great dragonbane which
+D:bathed in Glaurung's blood: but beware, it will drink the blood of those
+D:who wield it eventually.
+
+
+# The Two-Handed Sword 'Zarcuthra'
+
+N:77:'Zarcuthra'
+I:23:25:4
+W:30:180:250:205000
+P:0:4d6:19:21:0
+F:STR | CHR | INFRA | HIDE_TYPE | VORPAL | DRAIN_MANA |
+F:KILL_DRAGON | SLAY_ANIMAL | SLAY_EVIL | BRAND_FIRE |
+F:SLAY_UNDEAD | SLAY_DEMON | SLAY_TROLL | SLAY_GIANT | SLAY_ORC |
+F:RES_FIRE | RES_CHAOS | FREE_ACT | SEE_INVIS | AGGRAVATE | SHOW_MODS
+F:MUST2H
+f:MUST2H
+D:Dark and deadly runes stand stark against the naked steel of this awesome
+D:weapon, and you feel a stunning power of slaying and rending as you
+D:slowly approach.
+
+
+# The Dark Sword 'Mormegil'
+
+N:78:'Mormegil'
+I:23:33:2
+W:30:15:250:0
+P:0:6d7:0:0:-20
+F:SPEED | IM_FIRE | RES_FIRE | BRAND_FIRE | RES_DISEN | RES_FEAR |
+F:AGGRAVATE | CURSED | HEAVY_CURSE | SHOW_MODS | LEVELS | TY_CURSE |
+F:BLOWS | SLAY_DRAGON | RES_CHAOS | ANTIMAGIC_50 |
+F:DRAIN_MANA | DRAIN_HP | DRAIN_EXP
+D:A foul, twisted sword with blackened spines and knobs, whose very name is a
+D:curse upon the lips of Elves and Men.
+
+
+# The Cutlass 'Gondricam'
+
+N:79:'Gondricam'
+I:23:12:3
+W:20:8:110:28000
+P:0:1d7:10:11:0
+F:DEX | STEALTH | HIDE_TYPE |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | FEATHER |
+F:SEE_INVIS | REGEN | SHOW_MODS
+D:Famed sea-defender of Lebennin. A short, slightly curved chopping blade
+D:with a perfect edge shining cleanly in the sun, an object of hate to the
+D:men of Umbar who met it in combat.
+
+
+# The Executioner's Sword 'Crisdurian'
+
+N:80:'Crisdurian'
+I:23:28:0
+W:40:15:260:111000
+P:0:4d5:18:19:0
+F:SLAY_DRAGON | SLAY_EVIL | SLAY_UNDEAD | SLAY_TROLL | SLAY_GIANT |
+F:SLAY_ORC | SEE_INVIS | SHOW_MODS | VORPAL | BRAND_POIS | WOUNDING
+F:MUST2H
+f:MUST2H
+D:A giant's weapon, with a long blade tall and straight thrusting out from a
+D:massive double-pronged hilt. On its blade are written doomspells against
+D:both the living and undead.
+
+
+# The Katana 'Aglarang'
+
+N:81:'Aglarang'
+I:23:20:5
+W:35:25:50:40000
+P:0:8d4:0:0:0
+F:DEX | TUNNEL | SPEED | HIDE_TYPE |
+F:SUST_DEX | SHOW_MODS
+F:COULD2H
+f:COULD2H
+D:An utterly perfect, cleanly chiselled sword, with a edge that effortlessly
+D:slices rock and bone, and spells to render the wearer lithe and nimble. It
+D:is combat incarnate.
+
+
+# The Long Sword 'Ringil'
+
+N:82:'Ringil'
+I:23:17:10
+W:20:120:130:300000
+P:0:4d5:22:25:0
+F:SPEED | HIDE_TYPE | RES_FEAR | BLESSED |
+F:SLAY_EVIL | BRAND_COLD | SLAY_UNDEAD | KILL_DEMON | SLAY_TROLL |
+F:FREE_ACT | RES_COLD | RES_LITE | LITE1 | SEE_INVIS | SLOW_DIGEST | REGEN |
+F:ACTIVATE | SHOW_MODS
+a:HARDCORE=BA_COLD_2
+D:The weapon of Fingolfin, High King of the Noldor; it shines like a column
+D:of ice lit by light unquenchable. Morgoth came but unwillingly to meet it
+D:of old; his lame foot will remind him of its might should he meet it again.
+
+
+# The Long Sword 'Anduril'
+
+N:83:'Anduril'
+I:23:17:4
+W:20:40:130:100000
+P:0:3d5:10:15:5
+F:STR | DEX | HIDE_TYPE | RES_FEAR | FREE_ACT | BLESSED | LUCK
+F:SLAY_EVIL | BRAND_FIRE | SLAY_TROLL | SLAY_ORC | FREE_ACT |
+F:RES_FIRE | SUST_DEX | SEE_INVIS | ACTIVATE | SHOW_MODS | LITE1
+F:RES_DISEN | SPECIAL_GENE
+a:HARDCORE=BA_FIRE_1
+D:The famed "Flame of the West", the sword that was broken and is forged
+D:again. It glows with the essence of fire, its wearer is mighty in combat,
+D:and no creature of Sauron can withstand it. It will never be stained or
+D:broken even in defeat.
+
+
+# The Long Sword 'Anguirel'
+
+N:84:'Anguirel'
+I:23:17:2
+W:20:30:130:40000
+P:0:2d5:8:12:0
+F:STR | CON | SPEED | HIDE_TYPE |
+F:SLAY_EVIL | BRAND_ELEC | SLAY_DEMON | FREE_ACT | RES_ELEC |
+F:RES_LITE | RES_DARK | SEE_INVIS | SHOW_MODS | VORPAL | WOUNDING
+F:AGGRAVATE | CURSED
+D:Forged of black galvorn by the Dark-Elven smith Eol, this blade has the
+D:living lightning trapped inside.
+
+
+# The Long Sword 'Elvagil'
+
+N:85:'Elvagil'
+I:23:17:2
+W:20:8:130:20000
+P:0:2d5:5:7:0
+F:DEX | CHR | STEALTH | HIDE_TYPE | ESP_ORC | ESP_TROLL
+F:SLAY_TROLL | SLAY_ORC | FEATHER | SEE_INVIS | SHOW_MODS
+D:The "Singing Blade", whose wearer can slay Orcs and Trolls in the hidden
+D:and secret places of the earth.
+
+
+# The Rapier 'Forasgil'
+
+N:86:'Forasgil'
+I:23:7:0
+W:15:8:40:15000
+P:0:1d6:12:19:0
+F:SLAY_ANIMAL | BRAND_COLD | RES_COLD | RES_LITE | SHOW_MODS
+D:A slender, tapered blade whose wielder strikes icy blows with deadly
+D:accuracy.
+
+
+# The Sabre 'Careth Asdriag'
+
+N:87:'Careth Asdriag'
+I:23:11:2
+W:15:8:50:25000
+P:0:2d7:6:8:0
+F:DEX | BLOWS | SPEED | CON |
+F:SLAY_DRAGON | SLAY_ANIMAL | SLAY_TROLL | SLAY_GIANT |
+F:SLAY_ORC | SHOW_MODS | ESP_ANIMAL
+D:An heirloom of the Lords of Rhun far to the east, and a name of
+D:dismay to creatures natural and unnatural.
+
+
+# The Small Sword 'Sting'
+
+N:88:'Sting'
+I:23:8:2
+W:20:205:75:100000
+P:0:1d6:7:8:0
+F:STR | DEX | CON | BLOWS | SPEED | LEVELS |
+F:ESP_ORC | ESP_UNDEAD | ESP_SPIDER |
+F:SLAY_EVIL | SLAY_UNDEAD | SLAY_ORC | SLAY_ANIMAL | LITE1 |
+F:FREE_ACT | RES_LITE | SEE_INVIS | SHOW_MODS |
+D:"I will give you a name, and I shall call you Sting." The perfect size
+D:for Bilbo, and stamped forever by the courage he found in Mirkwood, this
+D:sturdy little blade grants the wearer combat prowess and survival
+D:abilities they did not know they had.
+
+
+# The Scimitar 'Haradekket'
+
+N:89:'Haradekket'
+I:23:18:2
+W:20:8:130:111111
+P:0:2d5:9:11:0
+F:INT | WIS | BLOWS |
+F:SLAY_ANIMAL | SLAY_EVIL | SLAY_UNDEAD | SLAY_DRAGON | SLAY_DEMON |
+F:RES_CHAOS | RES_DISEN | RES_NEXUS |
+F:SEE_INVIS | BLESSED |
+F:SHOW_MODS
+D:A damascened scimitar that seems wondrously easy to hold. Famed in song as
+D:the "Sickle of Harad", and a deadly foe to the undead.
+
+
+# The Short Sword 'Gilettar'
+
+N:90:'Gilettar'
+I:23:10:2
+W:20:8:80:35000
+P:0:1d7:3:7:0
+F:BLOWS | HIDE_TYPE |
+F:SLAY_ANIMAL | SLOW_DIGEST | REGEN | SHOW_MODS | SEE_INVIS | RES_DISEN
+D:A stubby blade worn by Beren, whose horn sounded of old in the glades of
+D:Brethil.
+
+
+# The Blade of Chaos 'Doomcaller'
+
+N:91:'Doomcaller'
+I:23:30:0
+W:70:25:180:250000
+P:0:6d5:18:28:-50
+F:KILL_DRAGON | SLAY_ANIMAL | SLAY_EVIL | BRAND_COLD | SLAY_TROLL |
+F:SLAY_ORC | FREE_ACT | RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:RES_CHAOS | SEE_INVIS | ESP_EVIL | AGGRAVATE | SHOW_MODS |
+F:CHAOTIC | VORPAL | BRAND_FIRE | BRAND_POIS | SPECIAL_GENE
+D:This weapon of wrath, cursed with a violent anger, dives hungrily
+D:into the flesh of its enemies. It gathers shadows of death into its
+D:owner as they inflict wounds that will never heal.
+
+
+# The Long Sword 'Vorpal Blade'
+
+N:92:'Vorpal Blade'
+I:23:17:2
+W:50:30:150:250000
+P:0:5d5:32:32:0
+F:VORPAL | SLAY_EVIL | WOUNDING
+F:FREE_ACT | SEE_INVIS | SLOW_DIGEST | REGEN | SPEED | STR | DEX
+D:"One, two! One, two! And through, and through, the vorpal blade
+D:went snicker-snack!"
+
+
+# The Beaked Axe of Theoden
+
+N:93:of Theoden
+I:22:10:3
+W:20:15:180:40000
+P:0:2d6:8:10:0
+F:WIS | CON | HIDE_TYPE |
+F:SLAY_DRAGON | ESP_EVIL | ESP_UNDEAD | SLOW_DIGEST | ACTIVATE | SHOW_MODS
+a:HARDCORE=DRAIN_2
+D:The narrow axe head of this weapon, finely balanced by a crow's beak,
+D:would pierce even the armour of Smaug, and its wielder becomes aware of
+D:the minds of their enemies.
+
+
+# The Glaive of Pain
+
+N:94:of Pain
+I:22:13:0
+W:30:155:190:50000
+P:0:9d6:0:30:0
+F:SHOW_MODS | LEVELS | DRAIN_MANA
+F:COULD2H
+f:COULD2H
+D:The massive chopper that crowns this glaive glows blood-red and black;
+D:fell spells of annihilation swirl and dance as you swing death's myrmidon
+D:down.
+
+
+# The Halberd 'Osondir'
+
+N:95:'Osondir'
+I:22:15:3
+W:20:8:190:22000
+P:0:3d5:6:9:0
+F:CHR | HIDE_TYPE |
+F:BRAND_FIRE | SLAY_UNDEAD | SLAY_GIANT | RES_FIRE | RES_SOUND |
+F:FEATHER | SEE_INVIS | SHOW_MODS | ESP_GIANT
+F:COULD2H
+f:COULD2H
+D:Lordly and tall did Osondir stand against the wrath of giants, and
+D:clear-eyed in barrows fell, wielding a halberd glowing ruby red.
+
+
+# The Pike 'Til-i-arc'
+
+N:96:'Til-i-arc'
+I:22:8:2
+W:20:15:160:32000
+P:0:2d5:10:12:10
+F:INT | HIDE_TYPE |
+F:BRAND_COLD | BRAND_FIRE | SLAY_DEMON | SLAY_TROLL | SLAY_GIANT | ESP_GIANT
+F:RES_FIRE | RES_COLD | SUST_INT | SLOW_DIGEST | SHOW_MODS |
+F:COULD2H
+f:COULD2H
+D:Within this long thrusting spear lie the spirits of frost giants and fire
+D:demons, who war forever, trapped by magely spells.
+
+
+# The Spear 'Aeglos'
+
+N:97:'Aeglos'
+I:22:2:4
+W:15:45:50:180000
+P:0:3d6:15:25:5
+F:DEX | WIS | HIDE_TYPE |
+F:BRAND_COLD | BRAND_ELEC | LITE1 |
+F:SLAY_TROLL | SLAY_ORC | SLAY_GIANT | KILL_UNDEAD |
+F:FREE_ACT | RES_COLD | RES_ELEC | RES_LITE |
+F:SLOW_DIGEST | ACTIVATE | BLESSED | SHOW_MODS |
+a:HARDCORE=BA_ELEC_2
+D:The mighty spear of Gil-galad, famed as "Snow-point" in the songs of
+D:Elves, against which all the foul corruptions of Sauron dashed in vain.
+
+
+# The Spear of Orome
+
+N:98:of Orome
+I:22:2:4
+W:15:45:50:77777
+P:0:4d6:15:15:0
+F:INT | WIS | SPEED | TUNNEL | INFRA | HIDE_TYPE | SEARCH |
+F:BRAND_FIRE |
+F:SLAY_GIANT | SLAY_EVIL | SLAY_DEMON | SLAY_UNDEAD | SLAY_DRAGON |
+F:RES_FIRE | RES_LITE | HOLD_LIFE | RES_FEAR |
+F:FEATHER | ESP_GIANT
+F:SEE_INVIS |
+F:ACTIVATE | BLESSED | SHOW_MODS
+a:HARDCORE=STONE_MUD
+D:The thrusting spear of wise Orome the Vala, strong against giants of frost,
+D:which can melt rock or flesh with ease.
+
+
+# The Spear 'Nimloth'
+
+N:99:'Nimloth'
+I:22:2:3
+W:15:12:50:30000
+P:0:1d6:11:13:0
+F:STEALTH | RES_DARK | INFRA | SPEED | BLESSED |
+F:BRAND_COLD | SLAY_UNDEAD | RES_COLD | SEE_INVIS | SHOW_MODS
+D:A thin spike of thrice-forged steel caps a straight sylvan shaft cut from
+D:a legendary tree; spells to break the will of the undead and strike cold
+D:fear into the hearts of foes lie on this perfectly balanced spear.
+
+
+# The Lance of Eorlingas
+
+N:100:of Eorlingas
+I:22:20:2
+W:20:23:360:55000
+P:0:3d8:3:21:0
+F:STR | DEX | SPEED | HIDE_TYPE | RES_FEAR |
+F:SLAY_EVIL | SLAY_TROLL | SLAY_ORC | SEE_INVIS | SHOW_MODS
+F:MUST2H
+f:MUST2H
+D:"Forth Eorlingas!" To the field of Cormallen came Eorl the Young
+D:to save beleaguered Gondor, and from his lance fled massive trolls
+D:and dire wolves.
+
+
+# The Great Axe of Durin
+
+N:101:of Durin
+I:24:25:3
+W:30:90:230:150000
+P:0:4d4:10:20:15
+F:STR | CON | TUNNEL | HIDE_TYPE | ESP_EVIL | RES_FEAR |
+F:SLAY_DRAGON | KILL_DEMON | SLAY_TROLL | SLAY_ORC | FREE_ACT |
+F:RES_ACID | RES_FIRE | RES_LITE | RES_DARK | RES_CHAOS | SHOW_MODS |
+F:BRAND_ACID | BRAND_FIRE
+F:MUST2H
+f:MUST2H
+D:The twin massive axe heads of this ancient demon's dread gleam with
+D:mithril inlay, which tell sagas of endurance, invoking the powers of
+D:Khazad-dum to protect the wearer and slay all evils found underground.
+
+
+# The Great Axe of Eonwe
+
+N:102:of Eonwe
+I:24:25:2
+W:30:120:230:200000
+P:0:4d4:15:18:8
+F:STR | INT | WIS | DEX | CON | CHR | HIDE_TYPE |
+F:SLAY_EVIL | BRAND_COLD | KILL_DEMON | SLAY_UNDEAD | ESP_NONLIVING
+F:SLAY_ORC | FREE_ACT | IM_COLD | SEE_INVIS | ACTIVATE |
+F:BLESSED | SHOW_MODS
+a:HARDCORE=MASS_GENO
+D:The axe of Eonwe, leader of the Hosts of the West before the gates of
+D:Thangorodrim, strikes with icy wrath at the undead, disperses hosts of
+D:evil at a word, and grants Maia-like powers of body and mind.
+
+
+# The Battle Axe of Balli Stonehand
+
+N:103:of Balli Stonehand
+I:22:22:3
+W:30:15:170:90000
+P:0:3d8:8:11:5
+F:STR | CON | STEALTH | HIDE_TYPE | ESP_NONLIVING
+F:SLAY_DEMON | SLAY_TROLL | SLAY_ORC | FREE_ACT |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_BLIND | FEATHER |
+F:SEE_INVIS | REGEN | SHOW_MODS
+F:COULD2H
+f:COULD2H
+D:The twin blades of this weapon were forged in Belegost, and powerful forces
+D:to resist and endure lie ready for he who shall wield it once more.
+
+
+# The Battle Axe 'Lotharang'
+
+N:104:'Lotharang'
+I:22:22:1
+W:30:15:170:21000
+P:0:2d8:4:3:0
+F:STR | DEX | HIDE_TYPE |
+F:SLAY_TROLL | SLAY_ORC | ACTIVATE | SHOW_MODS
+a:HARDCORE=CURE_MW
+D:A superbly crafted double-bladed axe that slays the creatures of earth and
+D:allows rapid recovery from their blows.
+
+
+# The Lochaber Axe 'Mundwine' -> of the Dwarves
+
+N:105:of the Dwarves
+I:22:28:10
+W:30:8:250:80000
+P:0:3d8:12:17:0
+F:SLAY_EVIL | TUNNEL | INFRA | SEARCH | SLAY_GIANT |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_FEAR |
+F:SHOW_MODS
+F:COULD2H
+f:COULD2H
+D:A massive axe with twin razor-sharp heads, so large that it usually
+D:requires two hands to wield, intricately engraved in gold with spells
+D:to ward off the elements and smite evil.
+
+
+# The Broad Axe 'Barukkheled'
+
+N:106:'Barukkheled'
+I:24:11:3
+W:20:8:160:50000
+P:0:2d6:13:19:0
+F:CON | HIDE_TYPE |
+F:SLAY_EVIL | SLAY_TROLL | SLAY_GIANT | SLAY_ORC |
+F:SEE_INVIS | SHOW_MODS
+F:COULD2H
+f:COULD2H
+D:A royal heirloom of the southern coast, strong in combat against evil
+D:creatures of the earth.
+
+
+# The Trident of Wrath
+
+N:107:of Wrath
+I:22:5:2
+W:15:35:300:90000
+P:0:3d8:16:18:0
+F:STR | DEX | HIDE_TYPE | CHAOTIC | DRAIN_MANA |
+F:SLAY_EVIL | KILL_UNDEAD | RES_LITE | RES_DARK | SEE_INVIS |
+F:BLESSED | SHOW_MODS
+F:COULD2H
+f:COULD2H
+D:A massive triple-pronged spear, so great it normally requires two hands to
+D:wield, evoking the spirit of Osse who with it pierced legions of
+D:evil and undead.
+
+
+# The Trident of Ulmo
+
+N:108:of Ulmo
+I:22:5:4
+W:30:90:70:120000
+P:0:4d8:15:19:0
+F:DEX | HIDE_TYPE |
+F:SLAY_DRAGON | SLAY_ANIMAL | FREE_ACT | HOLD_LIFE | IM_ACID |
+F:RES_NETHER | SEE_INVIS | SLOW_DIGEST | REGEN | ACTIVATE |
+F:BLESSED | SHOW_MODS | WATER_BREATH
+a:HARDCORE=TELE_AWAY
+D:The awesome weapon of the Vala Ulmo, Lord of Waters. Mightiest of all the
+D:powers of good save Manwe himself, Ulmo laughs in scorn at the dread powers
+D:of the undead, and is utterly in command of the element of water.
+
+
+# The Scythe 'Avavir'
+
+N:109:'Avavir'
+I:22:17:3
+W:40:8:250:18000
+P:0:5d3:8:8:10
+F:DEX | CHR | HIDE_TYPE |
+F:BRAND_COLD | BRAND_FIRE | FREE_ACT | RES_FIRE | RES_COLD |
+F:RES_LITE | SEE_INVIS | ACTIVATE | SHOW_MODS
+F:COULD2H
+f:COULD2H
+a:HARDCORE=RECALL
+D:With elemental powers whose struggles turn this weapon red and purest
+D:white, this shining reaper bears within it a power of going forth and
+D:returning.
+
+
+# The Long Sword of the Dawn
+
+N:110:of the Dawn
+I:23:17:3
+W:40:160:130:250000
+P:0:3d5:20:20:0
+F:ACTIVATE | BRAND_FIRE | FREE_ACT | RES_FIRE | INFRA | LEVELS |
+F:SLAY_EVIL | SLAY_DRAGON | SLAY_UNDEAD | SLAY_DEMON | VORPAL | CLONE |
+F:CHR | SUST_CHR | RES_FEAR | RES_LITE | RES_BLIND | REGEN | SHOW_MODS
+a:HARDCORE=DAWN
+D:Forged in the farthest East by a race of mighty spellcasters, this
+D:shiny pale sword gleams with the rays of rising sun as you invoke
+D:its power of commanding legions of powerful immortal warriors...
+
+
+# The Mighty Hammer 'Grond'
+
+N:111:'Grond'
+I:21:50:2
+W:100:1:1000:500000
+P:0:9d9:25:25:10
+F:KILL_DRAGON | SLAY_ANIMAL | SLAY_EVIL | IMPACT | KILL_UNDEAD | NO_MAGIC |
+F:KILL_DEMON | SLAY_TROLL | SLAY_ORC | RES_ACID | RES_ELEC | RES_FIRE |
+F:RES_COLD | SEE_INVIS | ESP_ALL | AGGRAVATE | SHOW_MODS | INSTA_ART |
+F:LEVELS | ACTIVATE | SPECIAL_GENE
+F:MUST2H
+f:MUST2H
+a:HARDCORE=GROND
+D:The mighty Hammer of the Underworld, blackened by doomspells of shattering,
+D:whose wielder holds the lives of all Morgoth's servants in his hand.
+
+
+# The Flail 'Totila'
+
+N:112:'Totila'
+I:21:13:2
+W:20:8:150:55000
+P:0:3d6:6:8:0
+F:STEALTH |
+F:SLAY_EVIL | BRAND_FIRE | RES_FIRE | RES_CONF | ACTIVATE |
+F:SHOW_MODS | LITE1
+F:COULD2H
+f:COULD2H
+a:HARDCORE=CONFUSE
+D:A flail whose head befuddles those who stare as you whirl it around, and
+D:becomes a fiery comet as you bring it down.
+
+
+# The Two-Handed Flail 'Thunderfist'
+
+N:113:'Thunderfist'
+I:21:18:4
+W:45:38:300:160000
+P:0:3d6:5:18:0
+F:STR | CON | HIDE_TYPE | RES_FEAR |
+F:SLAY_ANIMAL | BRAND_FIRE | BRAND_ELEC | SLAY_TROLL | SLAY_ORC |
+F:RES_ELEC | RES_FIRE | RES_DARK | SHOW_MODS |
+F:MUST2H
+f:MUST2H
+D:The long-lost weapon of Kzurin, Dwarven champion of ancient Belegost,
+D:with runes of strength in its handle, and flames and sparks that roar and
+D:crackle around its massive head.
+
+
+# The Morning Star 'Bloodspike'
+
+N:114:'Bloodspike'
+I:21:12:4
+W:20:30:150:30000
+P:0:2d6:8:22:0
+F:STR | HIDE_TYPE | BRAND_POIS |
+F:SLAY_ANIMAL | SLAY_TROLL | SLAY_ORC | RES_NEXUS | SEE_INVIS |
+F:SHOW_MODS
+D:You feel strong and firm of foot as you whip the chain-suspended spiked orb
+D:around - and bathe it in the blood of your foes.
+
+
+# The Morning Star 'Firestar'
+
+N:115:'Firestar'
+I:21:12:0
+W:20:100:150:35000
+P:0:2d6:5:7:2
+F:BRAND_FIRE | IM_FIRE | ACTIVATE | SHOW_MODS | LITE1
+a:HARDCORE=FIRESTAR
+D:A famed battle-lord of old, with a ruddy head, coloured as embers are that
+D:can yet rise up in wrath.
+
+
+# The Mace 'Taratol'
+
+N:116:'Taratol'
+I:21:5:0
+W:20:15:200:50000
+P:0:3d4:12:12:0
+F:KILL_DRAGON | BRAND_ELEC | IM_ELEC | ACTIVATE | SHOW_MODS
+F:COULD2H
+f:COULD2H
+a:HARDCORE=SPEED
+D:A great ridged mace that calls around you a nimbus of living lightning;
+D:you remain utterly untouched even as fat sparks arc around your
+D:fingers and eyebrows.
+
+
+# The War Hammer of Aule
+
+N:117:of Aule
+I:21:8:4
+W:40:75:120:250000
+P:0:9d3:19:21:5
+F:WIS | TUNNEL | HIDE_TYPE | RES_FEAR |
+F:KILL_DRAGON | SLAY_EVIL | BRAND_ELEC | SLAY_UNDEAD | SLAY_DEMON |
+F:FREE_ACT | RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_NEXUS |
+F:SEE_INVIS | SHOW_MODS
+F:COULD2H
+f:COULD2H
+D:The wondrous hammer of Aule, creator of the wise Dwarven lords of old.
+D:It bears magics of demolishing that no serpent or demon can withstand, and
+D:invokes the strength of mountains to ward off the tumult of the elements.
+
+
+# The Quarterstaff 'Nar-i-vagil'
+
+N:118:'Nar-i-vagil'
+I:21:3:3
+W:20:18:150:70000
+P:0:1d9:10:20:0
+F:INT | HIDE_TYPE |
+F:SLAY_ANIMAL | BRAND_FIRE | RES_FIRE | SHOW_MODS
+F:COULD2H
+f:COULD2H
+D:Named for a fiery star and set with gems of great worth binding mystic
+D:virtues of protection and thought.
+
+
+# The Quarterstaff 'Eriril'
+
+N:119:'Eriril'
+I:21:3:4
+W:20:18:150:20000
+P:0:1d9:3:5:0
+F:INT | WIS | HIDE_TYPE | ESP_EVIL | SPELL_CONTAIN | WIELD_CAST
+F:SLAY_EVIL | RES_LITE | SEE_INVIS | ACTIVATE | SHOW_MODS
+a:HARDCORE=ID_PLAIN
+D:The radiant golden staff of an Istari of legend, this wizard's companion
+D:grants keen sight and the knowledge of many hidden things.
+
+
+# The Quarterstaff of Olorin
+
+N:120:of Olorin
+I:21:3:4
+W:30:105:150:140000
+P:0:2d9:10:13:0
+F:INT | WIS | CHR | HIDE_TYPE | SEARCH | BRAND_FIRE |
+F:SLAY_EVIL | BRAND_FIRE | SLAY_TROLL | SLAY_ORC | SPELL_CONTAIN | WIELD_CAST
+F:HOLD_LIFE | RES_FIRE | RES_NETHER | SEE_INVIS | ACTIVATE | SHOW_MODS
+a:HARDCORE=DETECT_XTRA
+D:A staff tall and sturdy, with rough-hewn runes that invoke the element of
+D:Earth, and which strikes down all creatures who live in the shadow of
+D:mountains.
+
+
+# The Mace of Disruption 'Deathwreaker'
+
+N:121:'Deathwreaker'
+I:21:20:6
+W:80:38:400:444444
+P:0:7d8:18:18:0
+F:STR | TUNNEL | HIDE_TYPE | NO_TELE | DRAIN_MANA |
+F:SLAY_DRAGON | SLAY_ANIMAL | SLAY_EVIL | KILL_UNDEAD | BRAND_FIRE |
+F:IM_FIRE | RES_DARK | RES_CHAOS | RES_DISEN | AGGRAVATE |
+F:SHOW_MODS | BRAND_POIS | VAMPIRIC
+F:MUST2H
+f:MUST2H
+D:A weapon so massive it seems beyond the strength of mortals, yet you feel
+D:the might of giants within you as you heft it. As you grip the handle
+D:of ebony and steel, coronas of fire blaze and mighty spells to preserve
+D:magic activate around you. You wield the Fear of Dragons and the Despair
+D:of the Undead!
+
+
+# The Lucerne Hammer 'Turmil'
+
+N:122:'Turmil'
+I:21:10:4
+W:20:15:120:30000
+P:0:2d5:10:6:8
+F:WIS | INFRA | HIDE_TYPE |
+F:BRAND_COLD | SLAY_ORC | RES_COLD | RES_LITE | REGEN |
+F:ACTIVATE | SHOW_MODS | ESP_ORC | ESP_TROLL | ESP_GIANT
+F:COULD2H
+f:COULD2H
+a:HARDCORE=TURMIL
+D:Wielded by the High Priest of Meneltarma, this great mace gleams coldly as
+D:though moonlit, and it can strike as mighty a blow spiritually as
+D:physically.
+
+
+# The Whip of Gothmog
+
+N:123:of Gothmog
+I:21:2:-2
+W:20:15:120:100000
+P:0:3d6:15:16:0
+F:INT | DEX | INFRA | HIDE_TYPE | DRAIN_HP |
+F:HEAVY_CURSE | CURSED | AGGRAVATE |
+F:BRAND_FIRE | SLAY_ANIMAL | SLAY_DEMON | RES_FIRE | ESP_SPIDER
+F:VORPAL | RES_LITE | LITE1 | REGEN | ESP_DEMON | WOUNDING
+F:SHOW_MODS
+D:With this unbearably bright whip of flame, the Balrog Gothmog has become
+D:known for never having lost in combat.
+
+
+# The Long Bow 'Belthronding'
+
+N:124:'Belthronding'
+I:19:13:3
+W:40:20:40:35000
+P:0:0d0:20:22:0
+F:DEX | STEALTH | HIDE_TYPE |
+F:RES_DISEN | XTRA_SHOTS | SHOW_MODS
+D:The great bow of Beleg, made of black yew and strung with elven hair that
+D:faintly shines a pale clear gold.
+
+
+# The Long Bow of Bard
+
+N:125:of Bard
+I:19:13:2
+W:30:20:40:20000
+P:0:0d0:17:19:0
+F:DEX | HIDE_TYPE | ESP_DRAGON | LUCK
+F:FREE_ACT | XTRA_MIGHT | SHOW_MODS
+D:The great yew bow of grim-faced Bard, who shot the mightiest arrow that
+D:songs record.
+
+
+# The Light Crossbow 'Cubragol'
+
+N:126:'Cubragol'
+I:19:23:10
+W:50:25:110:50000
+P:0:0d0:10:14:0
+F:SPEED | HIDE_TYPE |
+F:RES_FIRE | ACTIVATE | SHOW_MODS
+a:HARDCORE=CUBRAGOL
+D:A crossbow that grants fiery speed to he who finds it, and from which
+D:shoot bolts that blaze with flame unquenchable.
+
+
+# The Mage Staff of Eternity
+# Really powerful for a mage but extremely rare
+# The ULTIMATE "weapon" for a Sorceror or a magic class
+
+N:127:of Eternity
+I:6:1:12
+W:127:220:20:9000000
+P:0:1d4:-19:-19:0
+F:INT | CHR | WIS | MANA | SPELL | ACTIVATE |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | LUCK | SPECIAL_GENE
+F:SEE_INVIS | ESP_EVIL | ESP_DEMON | NEVER_BLOW | INFRA
+F:PRECOGNITION | IM_FIRE | ULTIMATE | SPELL_CONTAIN | WIELD_CAST
+F:COULD2H
+f:COULD2H
+a:HARDCORE=GANDALF
+D:A simple, wooden wizard's staff. Unremarkable in all aspects...
+D:except that it pulses with overwhelming power.
+
+
+# Boomerang Artifacts
+# The Metal Boomerang of Beor
+
+N:128:of Beor
+I:15:4:4
+W:20:10:20:40000
+P:0:4d5:8:12:0
+F:DEX | SPEED |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD
+D:Beor's boomerang makes its wielder as agile as the winds,
+D:and as hard to harm.
+
+
+# The Metal Boomerang 'Glimdrir'
+
+N:129:'Glimdrir'
+I:15:4:3
+W:40:20:20:60000
+P:0:5d5:15:16:0
+F:DEX | SPEED | FREE_ACT | BRAND_POIS | SLAY_EVIL | SLAY_UNDEAD | REGEN
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_SOUND | NO_TELE | CURSED
+D:A powerful boomerang that makes one agile and fast, with a thirst for
+D:evil and undead creatures, but demands its wielder not teleport, for fear
+D:of desertion.
+
+
+# The Robe of Incanus [aka Gandalf]
+
+N:130:of Incanus
+I:36:2:3
+W:30:20:20:60000
+P:2:0d0:0:0:20
+F:INT | WIS | SEARCH | HIDE_TYPE | SPELL_CONTAIN | WIELD_CAST
+F:SUST_INT | SUST_WIS | FREE_ACT | SEE_INVIS |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+Z:weigh magic
+D:Gandalf's long, flowing robe. It provides insight and allows the
+D:wearer to see things not seen by all.
+
+
+# The Sling of the Thain
+
+N:131:of the Thain
+I:19:2:4
+W:40:20:40:35000
+P:0:0d0:15:15:0
+F:HIDE_TYPE | DEX | CON
+F:RES_NETHER | XTRA_SHOTS | XTRA_MIGHT | SHOW_MODS
+D:This sling was crafted by Faramir I, Thain of the Shire, just in case
+D:the nasties of his father's stories ever dare to enter the Shire again.
+
+
+# The Whip 'Lasher'
+
+N:134:'Lasher'
+I:21:2:3
+W:20:5:30:50000
+P:0:1d6:12:15:0
+F:DEX | BLOWS | HIDE_TYPE |
+F:SLAY_ANIMAL | SLAY_ORC | BRAND_POIS | VORPAL |
+F:RES_POIS | FREE_ACT | ESP_ORC
+D:A powerful whip that is deadly against orcs. It poisons your foes
+D:and is said to go "snicker snack".
+
+
+# The Seeker Arrow 'Bullseye'
+
+N:135:'Bullseye'
+I:17:2:0
+W:45:1:2:50000
+P:0:7d4:20:15:0
+F:SLAY_ANIMAL | SLAY_EVIL | SLAY_UNDEAD | KILL_DEMON |
+F:SLAY_ORC | SLAY_TROLL | SLAY_GIANT | SLAY_DRAGON |
+F:BRAND_ACID | BRAND_ELEC | BRAND_FIRE | BRAND_COLD | BRAND_POIS
+D:A powerful arrow that is feared by even the mightiest demons.
+
+
+# The Rounded Pebble 'Travak'
+
+N:136:'Travak'
+I:16:0:0
+W:5:1:2:5000
+P:0:3d6:8:5:0
+F:BRAND_ACID | BRAND_ELEC | BRAND_FIRE | BRAND_COLD | BRAND_POIS
+D:A rounded pebble imbued with the powers of the elements.
+
+
+# The Harp of Maglor
+
+N:137:of Maglor
+I:14:59:3
+W:60:10:20:100000
+P:0:3d4:0:0:0
+F:CHR | SPEED | WIS | SEE_INVIS | RES_SOUND | STEALTH | LUCK
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | ESP_UNIQUE | WIELD_CAST
+D:This harp that once belonged to Maglor makes those who use it seem
+D:more forceful and convincing. It is also said that those who have
+D:used it found themselves walking faster, as if to an unheard beat.
+
+
+# The Drum of the Sky
+
+N:138:of the Sky
+I:14:58:2
+W:40:10:15:80000
+P:0:3d4:0:0:0
+F:CHR | SPEED | WIS | SEE_INVIS | RES_SOUND | STEALTH | LUCK
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | WIELD_CAST
+D:The drum is decorated with the images of the stars, the clouds, the
+D:Sun guided by Arien and the Moon with Tilion. It imparts to the
+D:wearer an echo of the beauty of the sky, and protects him from the
+D:elements day or night. The beat of the drum marks the passage of
+D:time, and will make time pass differently for the wearer.
+
+
+# The Harp of Daeron
+
+N:139:of Daeron
+I:14:59:1
+W:20:10:10:50000
+P:0:3d4:0:0:0
+F:CHR | SPEED | WIS | RES_SOUND | STEALTH | LUCK
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | WIELD_CAST
+D:A pretty harp that makes those who play it beautiful, wise and
+D:fast.
+
+
+# The Dwarven Pick of Erebor
+
+N:140:of Erebor
+I:20:6:5
+W:50:15:200:55000
+P:0:3d4:0:0:0
+F:STR | TUNNEL | SUST_STR | HIDE_TYPE | LITE1 | ACTIVATE | CLIMB
+F:RES_CHAOS | RES_LITE | RES_DARK
+a:HARDCORE=EREBOR
+D:A pick that provides a magical light by which to see while tunnelling.
+
+
+# The Drum of the Druedain
+
+N:141:of the Druedain
+I:14:58:4
+W:19:10:15:10000
+P:0:3d4:0:0:0
+F:ACTIVATE | STEALTH | SEARCH | INFRA | RES_POIS | RES_DARK | WIELD_CAST
+a:HARDCORE=DRUEDAIN
+D:The fabled Drum of the Druedain that will protect those who play it
+D:from darkness and poison attacks. It also aids in the seeing of
+D:warm-blooded creatures.
+
+
+# The Horn of Rohan
+
+N:142:of Rohan
+I:14:60:2
+W:14:10:15:80000
+P:0:3d4:0:0:0
+F:ACTIVATE | CHR | WIS | ESP_DRAGON | WIELD_CAST
+a:HARDCORE=ROHAN
+D:A horn carved from the bones of the Dragon of Ered-Mithrin, this
+D:heirloom of the House of Eorl bestows to its user the gifts of
+D:courage and command.
+
+
+# The Horn of Helm
+
+N:143:of Helm
+I:14:60:2
+W:16:10:15:15000
+P:0:3d4:0:0:0
+F:ACTIVATE | STR | CON | IM_COLD | RES_NETHER | RES_FEAR | WIELD_CAST
+a:HARDCORE=HELM
+D:Heedless of cold, fearless of darkness -- besiegers fled at the wind
+D:of the solitary coming of King Helm Hammerhand, proclaimed by a single
+D:horn-blast in the dead of winter.
+
+
+# The Horn of Boromir
+
+N:144:of Boromir
+I:14:60:3
+W:18:10:15:18000
+P:0:3d4:0:0:0
+F:ACTIVATE | STR | CON | RES_FEAR | RES_FIRE | AGGRAVATE | WIELD_CAST
+a:HARDCORE=BOROMIR
+D:Boromir's horn gives courage and endurance to the wearer, provided he does
+D:not wish to travel in secrecy: for it must always sound when its wielder
+D:sets forth on a journey. "Loud and clear it sounds in the valleys of the
+D:hills... and then let all the foes of Gondor flee!"
+
+
+# The Lochaber Axe of Gothmog, which slew Fingon
+
+N:145:of Gothmog
+I:22:28:-4
+W:30:8:250:30000
+P:0:3d8:14:19:0
+F:BRAND_FIRE | IM_FIRE | CHR | ACTIVATE | SHOW_MODS | CURSED | TY_CURSE
+a:HARDCORE=AXE_GOTHMOG
+D:The black axe of Gothmog, which struck Fingon at Nirnaeth. Mighty
+D:spells of evil make it unsafe in any hands but those of its original wielder.
+
+
+# The Seeker Arrow of Gondor
+
+N:146:of Gondor
+I:17:2:0
+W:20:5:3:25000
+P:0:10d8:10:20:0
+F:SLAY_EVIL | SLAY_DEMON
+D:An arrow that was created to rid the world of demons.
+
+
+# The Long Sword of Eternity
+# The ULTIMATE weapon for a warrior class
+
+N:147:of Eternity
+I:23:17:10
+W:127:220:130:9000000
+P:0:5d6:21:26:50
+F:LIFE | CON | CHR | LUCK
+F:SUST_STR | SUST_INT | SUST_WIS | SUST_DEX | SUST_CON | SUST_CHR |
+F:BRAND_FIRE | BRAND_COLD | BRAND_ELEC | VORPAL | IM_COLD |
+F:SLAY_EVIL | SLAY_UNDEAD | SLAY_DEMON | SLAY_TROLL | SLAY_DEMON |
+F:FREE_ACT | RES_FIRE | RES_DARK | LITE1 | SEE_INVIS | SLOW_DIGEST | REGEN |
+F:ACTIVATE | SHOW_MODS | BLESSED |
+F:PRECOGNITION | NO_MAGIC | ULTIMATE | SPECIAL_GENE
+a:HARDCORE=ERU
+D:A warm light bathes this translucent blade. The power of the fates are
+D:at the command of its wielder as the weapon passes Supreme Judgment on
+D:the inhabitants of Angband.
+
+
+# The Robe of Great Luck
+
+N:148:of Great Luck
+I:36:2:60
+W:50:120:20:60000
+P:-30:0d0:0:0:-20
+F:LUCK | HIDE_TYPE |
+F:FREE_ACT | DRAIN_HP | DRAIN_MANA
+D:A powerful wizard once created this robe to grant him incredible luck....
+D:It seems he forgot to wear it.
+
+
+# The Sling of Farmer Maggot
+
+N:149:of Farmer Maggot
+I:19:2:2
+W:10:10:5:20000
+P:0:0d0:20:0:0
+F:INFRA | SEARCH | HIDE_TYPE |
+F:XTRA_SHOTS | SHOW_MODS | ACTIVATE | SPECIAL_GENE
+a:SPELL=Artifact Maggot
+D:This ordinary seeming leather sling has been raised to legendary
+D:status amongst generations of hobbit children. Farmer Maggot's
+D:ability to notice and strike any mushroom thief anywhere within
+D:his patch almost keeps young poachers at bay, but once they get
+D:within range they soon flee for less painful pastures, frequently
+D:with rounded pebbles stinging their backsides...
+
+
+# The Long Sword of Angmar (a.k.a. anti-Ringil)
+# The next time someone wields an unidentified Long Sword (4d5) ...
+
+N:150:of Angmar
+I:23:17:-10
+W:20:40:130:30000
+P:0:4d5:-22:-25:0
+F:SPEED | STR | WIS | CHR | ESP_UNDEAD
+F:BRAND_FIRE | SEE_INVIS | SLOW_DIGEST | FREE_ACT |
+F:VAMPIRIC | NO_TELE | AGGRAVATE | WRAITH | INVIS |
+F:CURSED | HEAVY_CURSE | DG_CURSE | SHOW_MODS | CLONE |
+D:Dark flames wreath the naked steel of the Witch-King of Angmar.
+D:A mighty curse to all those who wield it apart from its master,
+D:the torture of the wraithworld awaits those who dare.
+
+
+# The Seeker Bolt of Feanor
+
+N:151:of Feanor
+I:18:2:0
+W:127:220:130:100000
+P:0:5d5:5:6:0
+F:BRAND_COLD | BRAND_FIRE | BRAND_ELEC | BRAND_ACID | BRAND_POIS |
+F:SLAY_DRAGON | SLAY_GIANT | SLAY_TROLL | KILL_UNDEAD | SLAY_ORC |
+F:SLAY_DEMON | SLAY_EVIL | SPECIAL_GENE
+D:Made during the war against Morgoth by Feanor, this powerful
+D:bolt is the bane of Morgoth's power, and has especial strength
+D:against those foes who are already dead.
+
+
+# The Heavy Crossbow of Eternity
+# The ULTIMATE bow for an archer class
+
+N:152:of Eternity
+I:19:24:5
+W:127:220:130:8000000
+P:0:0d0:36:28:0
+F:SEE_INVIS | SLOW_DIGEST | FREE_ACT | SPEED | DEX | CON | FLY | LUCK
+F:XTRA_MIGHT | XTRA_SHOTS | IM_ELEC | REFLECT | INVIS | STEALTH |
+F:SUST_STR | SUST_INT | SUST_WIS | SUST_DEX | SUST_CON | SUST_CHR |
+F:RES_CHAOS | RES_DISEN | RES_CONF | RES_BLIND | INFRA | ESP_ORC | ESP_TROLL | ESP_EVIL |
+F:PRECOGNITION | NO_MAGIC | ULTIMATE | SPECIAL_GENE
+D:Designed to be used with the Seeker Bolt of Feanor, this Crossbow
+D:is perfect against the terrible powers of Morgoth.
+
+
+# The Soft Leather Armour of the Sandworm
+
+N:153:of the Sandworm
+I:36:4:5
+W:30:3:80:65000
+P:30:0d0:0:0:0
+F:RES_POIS | RES_ELEC | RES_FIRE | RES_ACID | SPECIAL_GENE
+F:TUNNEL | STR | STEALTH | INFRA | ESP_ANIMAL
+D:This powerful piece of armour was made using the remains of
+D:the Sandworm Queen.
+
+
+# The Lochaber Axe 'Dragonbane'
+
+N:154:'Dragonbane'
+I:22:28:2
+W:70:20:260:33000
+P:0:3d8:20:20:0
+F:BLOWS | KILL_DRAGON | RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:RES_POIS | SHOW_MODS
+D:Forged by the Dwarves to defend their home of Khazad-dum from dragons,
+D:this axe has been lost to time... until now.
+
+
+# The Light War Axe 'Limbslicer'
+
+N:155:'Limbslicer'
+I:24:8:4
+W:15:3:140:12000
+P:0:2d5:12:15:0
+F:DEX | VORPAL | HIDE_TYPE | SHOW_MODS | WOUNDING
+D:The Petty-dwarves of Bathak forged this blade, and it shares their thirst
+D:for blood.
+
+
+# The Broad Axe 'Orchast'
+
+N:156:'Orchast'
+I:24:11:4
+W:15:2:170:12000
+P:0:2d7:20:14:0
+F:DEX | SEARCH | SLAY_ORC | ACTIVATE | HIDE_TYPE | SHOW_MODS
+F:COULD2H
+f:COULD2H
+a:HARDCORE=ORCHAST
+D:Forged by the dwarves of Khazad-dum in a time of desperation,
+D:this axe turned many a battle against the invading orcs.
+
+
+# The Hatchet of the Night
+
+N:157:of the Night
+I:24:1:4
+W:45:20:45:34000
+P:0:2d6:34:22:0
+F:DEX | STEALTH | VAMPIRIC | KILL_UNDEAD | RES_DARK | HIDE_TYPE |
+F:SHOW_MODS | SEE_INVIS | ACTIVATE | DRAIN_EXP
+a:HARDCORE=NIGHT
+D:Found on an unmarked grave after a violent storm, this hatchet
+D:has a sinister aura of darkness and decay.
+
+
+# The Slaughter Axe 'Naturebane'
+
+N:158:'Naturebane'
+I:24:30:3
+W:70:20:300:28400
+P:0:5d7:31:27:0
+F:STR | SLAY_ANIMAL | SUST_STR | RES_SHARDS | RES_NEXUS | FEATHER |
+F:HIDE_TYPE | SHOW_MODS | ACTIVATE | DRAIN_HP
+a:HARDCORE=NATUREBANE
+D:Used by the orcs in their battle at Dagor Bragollach against the elves, this
+D:axe has a bloodthirst for nature.
+
+
+# The Light War Axe of Ice
+
+N:159:of Ice
+I:24:8:3
+W:30:25:140:26550
+P:0:2d5:3:15:0
+F:INT | CHR | SUST_DEX | BRAND_COLD | IM_COLD | RES_NEXUS | HIDE_TYPE |
+F:SHOW_MODS
+D:Crafted of purest ice and held solid by powerful spells, this icy axe
+D:delivers a chill of death to its victims.
+
+
+# The Iron Helm of Knowledge
+
+N:160:of Knowledge
+I:32:5:-6
+W:20:5:75:100000
+P:6:1d3:0:0:20
+F:LITE1 | HIDE_TYPE | SPECIAL_GENE | LUCK
+F:AUTO_ID | ACTIVATE
+a:HARDCORE=KNOWLEDGE
+D:This helm, designed by Petty-Dwarves ages ago to act as the brain of a
+D:long lost project, is made of finest glass. Its light banishes all secrets,
+D:and makes audible whispers from the deceased.
+
+
+### Trapping Kits ###
+
+### note prices and rarities may have to be adjusted ###
+
+# The Catapult Trap Set of Ahromarwar
+
+N:161:of Ahromarwar
+I:46:1:3
+W:20:10:40:20000
+P:0:0d0:25:15:30
+F:STEALTH | AUTOMATIC_99 | XTRA_MIGHT | HIDE_TYPE
+D:A trap that can almost never be detected. Its missiles may be mere pebbles,
+D:but fired at an incredibly high velocity to penetrate even the toughest
+D:hide or armour.
+
+
+# The Device Trap Set 'Hanisbroner's Surprise'
+
+N:162:'Hanisbroner's Surprise'
+I:46:6:3
+W:20:20:40:20000
+P:0:0d0:0:0:25
+F:STEALTH | XTRA_SHOTS | TELEPORT_TO | HIDE_TYPE | AUTOMATIC_99
+D:A magical trap, armed with a wand. Unaccountably, its victims keep
+D:on coming back for more...
+
+
+# The Bolt Trap Set 'Merlion Karc's Demonbane'
+
+N:163:'Merlion Karc's Demonbane'
+I:46:3:2
+W:20:20:200:20000
+P:0:0d0:17:27:37
+F:STEALTH | XTRA_SHOTS | XTRA_MIGHT | HIDE_TYPE | ONLY_DEMON
+D:A snare set not for animals, or people, but for demons alone, and
+D:enchanted so that whenever the demon sets foot or claw into the
+D:(hidden) pentagram, its hide is immediately pierced by many magical
+D:crossbow bolts.
+
+
+# The Broken Sword 'Narsil'
+
+N:164:'Narsil'
+I:23:2:2
+W:20:5:30:2000
+P:0:3d2:6:10:0
+F:STR | DEX | HIDE_TYPE | BLESSED |
+F:SLAY_ORC | SLAY_TROLL | RES_FIRE
+D:The sword that was broken shall be reforged...
+
+
+# The Steel Helm 'Lebohaum'
+# The name comes from a french parody of dungeon dwelling in mp3
+# http://penofchaos.com/warham.htm
+
+N:165:'Lebohaum'
+I:32:6:0
+W:20:15:15:25000
+P:20:0d0:0:0:80
+F:ACTIVATE
+a:SPELL=Artifact Lebauhaum
+D:With the Helm 'Lebohaum' your head is safe!
+
+
+# The Power Dragon Scale Mail 'Mediator'
+
+N:166:'Mediator'
+I:38:30:0
+W:95:12:500:400000
+P:50:2d4:-8:0:35
+F:FEATHER | FLY | ESP_DRAGON |
+F:RES_NEXUS | RES_CHAOS | AGGRAVATE | REGEN |
+F:RES_SHARDS | RES_SOUND | RES_DISEN | RES_CONF |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+F:ACTIVATE
+a:HARDCORE=MEDIATOR
+D:A mighty suit of dragon armour, set with the scales of dragons of both
+D:Law and Chaos, and with power over both.
+
+
+# The Hard Leather Armour of Himring
+
+N:167:of Himring
+I:36:6:0
+W:50:20:100:35000
+P:6:0d0:0:0:15
+F:RES_CHAOS | RES_NETHER | RES_POIS | ACTIVATE
+a:HARDCORE=PROT_EVIL
+D:Contained within this studded cuirass of pliable leather is the memory of
+D:unvanquished Himring, defiant fortress surrounded by the legions of Morgoth.
+
+
+# The Soft Leather Armour 'Hithlomir'
+
+N:168:'Hithlomir'
+I:36:4:4
+W:20:3:80:45000
+P:4:0d0:0:0:20
+F:STEALTH | HIDE_TYPE | SEARCH |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_DARK
+D:Familiar with the secret ways hidden in darkness, this leather cuirass is
+D:truly more than it appears.
+
+
+# The Shield of Deflection of Gil-galad
+# Description from Sangband
+
+N:169:of Gil-galad
+I:34:10:5
+W:70:4:80:65000
+P:10:1d3:0:0:20
+F:ACTIVATE |
+F:LITE1 | WIS | CHR | SEARCH | LUCK
+F:RES_ELEC | RES_ACID | RES_DISEN | RES_DARK | HIDE_TYPE |
+F:SUST_WIS | SUST_DEX | SUST_CHR
+a:HARDCORE=GILGALAD
+D:The legendary shield of Gil-Galad, who fought his way to the gates of
+D:the Dark Tower, and with whom came light even to Gorgoroth.
+
+
+# The Metal Cap of Celebrimbor
+
+N:170:of Celebrimbor
+I:32:3:3
+W:55:12:20:45000
+P:3:1d1:0:0:18
+F:INT | DEX | CHR | SPELL | SEARCH |
+F:RES_FIRE | RES_ACID | RES_DISEN | RES_SHARDS |
+F:ACTIVATE
+a:HARDCORE=CELEBRIMBOR
+D:This once belonged to Celebrimbor, maker of the Rings of Power. One who
+D:knows both fire and acid, from the business of forging and engraving, will
+D:fear neither: nor have his enchantments ever faded. Celebrimbor was even
+D:aware of Sauron before Sauron became aware of him, when Sauron put on the
+D:One Ring for the first time.
+
+
+# The Heavy Crossbow of Umbar
+
+N:171:of Umbar
+I:19:24:2
+W:60:20:200:35000
+P:0:4d1:18:18:0
+F:STR | CON | XTRA_MIGHT | AGGRAVATE |
+F:RES_LITE | RES_DARK | RES_BLIND | RES_ELEC |
+F:HIDE_TYPE | ACTIVATE | SHOW_MODS
+a:HARDCORE=UMBAR
+D:A great brazen arbalest with arms of gleaming steel, shooting quarrels with
+D:speed and power for those brave enough to risk betrayal.
+
+
+# The Short Bows of Amrod and Amras, Feanor's twin sons
+# The Short Bow of Amrod
+
+N:172:of Amrod
+I:19:12:2
+W:25:10:30:9000
+P:0:0d0:12:15:0
+F:STR | CON | XTRA_MIGHT |
+F:RES_FIRE | RES_ELEC | RES_COLD | REGEN
+D:This bow, and its twin, belonged to Feanor's last two twin sons, Amrod
+D:and Amras, who both hunted with the Green-elves for a time. Like the
+D:twins, the bows are similar, for both protect their wielders from the
+D:elements: and yet they are also unlike, for this bow gives endurance
+D:and strength, while the other gives quickness and subtlety.
+
+
+# The Short Bow of Amras
+
+N:173:of Amras
+I:19:12:1
+W:25:10:30:9000
+P:0:0d0:12:15:0
+F:INT | WIS | DEX | XTRA_SHOTS | XTRA_MIGHT | SPEED |
+F:RES_FIRE | RES_ELEC | RES_COLD | SLOW_DIGEST
+D:This bow, and its twin, belonged to Feanor's last two twin sons, Amrod
+D:and Amras, who both hunted with the Green-elves for a time. Like the
+D:twins, the bows are similar, for both protect their wielders from the
+D:elements: and yet they are also unlike, for this bow gives quickness
+D:and subtlety, while the other gives endurance and strength.
+
+
+# The Mattock of Nain
+
+N:174:of Nain
+I:20:7:6
+W:60:5:250:30000
+P:0:3d8:12:18:0
+F:TUNNEL | INFRA | SEARCH | STR | ESP_ORC | CLIMB |
+F:SLAY_ORC | SLAY_TROLL | SLAY_GIANT | SLAY_DRAGON |
+F:BRAND_ACID | RES_ACID | RES_DARK | RES_DISEN |
+F:ACTIVATE
+a:HARDCORE=STONE_MUD
+D:Wielded by Nain of the Iron Hills at the Battle of Azanulbizar, this great
+D:mattock brought victory to the Dwarves over Azog's Orcs - though Nain
+D:himself fell at the last, even with victory already assured.
+
+
+# The Ball-and-Chain of Fundin Bluecloak
+
+N:175:of Fundin Bluecloak
+I:21:6:4
+W:25:100:130:60000
+P:0:5d4:13:17:10
+F:STR | WIS | SPEED | LITE1 | HIDE_TYPE |
+F:SLAY_EVIL | SLAY_UNDEAD |
+F:RES_FIRE | RES_ELEC | RES_NETHER | RES_DISEN | HOLD_LIFE |
+F:ACTIVATE
+F:COULD2H
+f:COULD2H
+a:HARDCORE=FUNDIN
+D:The weapon of one of the great dwarven priests, with powers
+D:to preserve body, soul and enchantments, and the bane of those
+D:who seek life beyond death.
+
+
+# The Large Leather Shield of the Haradrim
+
+N:176:of the Haradrim
+I:34:4:2
+W:35:12:120:25000
+P:4:1d2:0:0:15
+F:ACTIVATE |
+F:STR | CON | SUST_STR | SUST_CON | HIDE_TYPE |
+F:RES_FEAR | RES_BLIND | RES_POIS | AGGRAVATE
+a:HARDCORE=HARADRIM
+D:A great shield from the far lands of the South, whose wielder
+D:will go charging into battle heedless of danger, with the
+D:strength and endurance of a madman. Nor will he fear poison, for
+D:the Southron barbarians handle poisoned darts naturally.
+
+
+# The Lead-Filled Mace 'Skullcleaver'
+
+N:177:'Skullcleaver'
+I:21:15:5
+W:30:15:500:60000
+P:0:5d4:11:23:20
+F:STR | TUNNEL | INFRA | HIDE_TYPE |
+F:CURSED | AGGRAVATE | NO_MAGIC |
+F:RES_NEXUS | RES_BLIND | RES_SOUND |
+F:KILL_DRAGON | SLAY_ANIMAL | BRAND_POIS | BRAND_ELEC |
+F:ACTIVATE
+F:COULD2H
+f:COULD2H
+a:HARDCORE=SKULLCLEAVER
+D:This mighty bludgeon brings destruction to all around it, and is the
+D:bane of dragons and magic.
+
+
+# The Set of Gauntlets of Eol
+
+N:178:of Eol
+I:31:2:3
+W:55:35:25:40000
+P:3:1d1:0:0:15
+F:INT | MANA | FREE_ACT | FEATHER | RES_ELEC | RES_DARK | RES_POIS | ACTIVATE
+F:LUCK | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=EOL
+D:The iron-shod gauntlets of the Dark Elven smith Eol, tingling with magics
+D:that he could channel in battle.
+
+
+# The Pair of Hard Leather Boots of Nevrast
+
+N:179:of Nevrast
+I:30:3:3
+W:20:8:40:35000
+P:3:1d1:0:0:13
+F:STEALTH | CON | SPEED | HIDE_TYPE
+D:Footgear made of bear leather and set with opals, which grant the wearer
+D:silent, hasted movement.
+
+
+# The Pair of Metal Shod Boots of Gimli
+
+N:180:of Gimli
+I:30:6:4
+W:40:8:60:22500
+P:4:1d1:5:5:10
+F:INFRA | SEARCH | TUNNEL | CLIMB | HIDE_TYPE
+Z:magic map
+D:A set of iron-shod boots stamped by Gimli's combat prowess, a peerless
+D:ally to those journeying through halls of stone under mountains.
+
+
+# The demon garbs of Gothmog
+# The Demonblade of Gothmog
+
+N:181:of Gothmog
+I:115:55:-20
+W:10:0:150:500
+P:0:7d6:13:13:0
+F:SHOW_MODS | SLAY_DEMON | SLAY_EVIL | BRAND_FIRE | BRAND_POIS
+F:LUCK | CHAOTIC | LITE1 | WOUNDING | RES_MORGUL | WIELD_CAST
+F:HEAVY_CURSE | AUTO_CURSE
+
+
+# The Demonshield of Gothmog
+
+N:182:of Gothmog
+I:115:56:4
+W:15:0:70:500
+P:13:1d1:0:0:13
+F:DEX | INVIS | SUST_STR | SUST_CON | SUST_DEX
+F:FEATHER | SH_FIRE | FREE_ACT | HOLD_LIFE
+F:HEAVY_CURSE | AUTO_CURSE | WIELD_CAST
+
+
+# The Demonhorn of Gothmog
+
+N:183:of Gothmog
+I:115:57:-5
+W:20:0:30:500
+P:2:1d1:0:0:13
+F:LITE2 | REGEN | ESP_DEMON
+F:CHR | SLOW_DIGEST | SEE_INVIS
+F:HEAVY_CURSE | AUTO_CURSE | WIELD_CAST
+
+
+# The Long Sword 'Durandil'
+# The name comes from a french parody of dungeon dwelling in mp3
+# http://penofchaos.com/warham.htm
+N:184:'Durandil'
+I:23:17:3
+W:5:10:130:500
+P:0:2d5:5:6:0
+F:RES_FEAR | LUCK
+F:ACTIVATE | SHOW_MODS
+a:SPELL=Artifact Durandil
+D:Don't go adventuring without your Durandil sword!
+
+
+# The Phial of Undeath
+
+N:200:of Undeath
+I:39:103:-5
+W:20:10:10:0
+P:0:1d1:0:0:0
+F:CURSED | INT | WIS | CON | DEX | CHR | STR | ACTIVATE |
+F:LITE3 | LITE2 | LUCK | MAGIC_BREATH
+F:INSTA_ART | DG_CURSE | ESP_UNDEAD |
+a:HARDCORE=UNDEATH
+D:It appears like the Phial of Galadriel at first - but wait! It
+D:is a cursed phial created by an evil wizard to lure adventurers
+D:into wielding it unknowingly.
+
+
+# The template for artifacts corpses
+
+N:201:
+I:9:1:0
+W:200:1:10:0
+P:0:1d1:0:0:0
+F:INSTA_ART | SPECIAL_GENE
+
+
+# The Palantir of Orthanc
+
+N:202:of Orthanc
+I:39:104:2
+W:75:60:200:100000
+P:0:10d10:0:0:0
+F:WIS | INT | SEARCH | INFRA | HIDE_TYPE | ACTIVATE | ESP_ALL |
+F:SEE_INVIS | RES_BLIND | AGGRAVATE | DRAIN_MANA | LITE2
+F:INSTA_ART
+a:HARDCORE=PALANTIR
+D:A shining white ball of unbreakable crystal, the ancient Palantiri
+D:were used by kings of Numenor and later by the Exiles for rapid
+D:communication between distant lands. Nothing is hidden from one who
+D:gazes into a Palantir, but the observed will also be aware of the
+D:observer, as was Sauron when Saruman tried to spy on him with this
+D:particular Palantir.
+
+
+# The Ring of Phasing
+
+N:203:of Phasing
+I:45:55:15
+W:110:0:2:3000000
+P:0:1d1:0:0:0
+F:SPEED | SEE_INVIS | LUCK | MAGIC_BREATH
+F:CURSED | HEAVY_CURSE | REGEN
+F:WRAITH | IM_NETHER | DRAIN_EXP | HOLD_LIFE | SPECIAL_GENE |
+F:INSTA_ART
+Z:teleport
+D:Imbued with the screams of the victims of undead everywhere, this
+D:ring is more a hole in reality than anything else. Strange forces ripple over
+D:its surface, giving you visions of a reality considerably less solid than this
+D:one. You feel your senses reel, and must make a conscious effort not to throw
+D:this ring as far from you as possible.
+
+
+# The Blue Stone 'Toris Mejistos'
+
+N:204:'Toris Mejistos'
+I:40:18:2
+W:50:10:3:60000
+Z:restore life
+F:INT | WIS | HIDE_TYPE | MANA | LUCK
+F:SUST_INT | SUST_WIS | LITE1 | REGEN
+F:SLOW_DIGEST | AUTO_CURSE | HEAVY_CURSE
+F:ESP_GOOD | ESP_EVIL | HOLD_LIFE
+F:INSTA_ART | SPECIAL_GENE | WATER_BREATH
+F:SPELL_CONTAIN | WIELD_CAST
+D:A blue stone, with an incredible number of incredibly small runes of power
+D:on it. It carries many secrets.
+
+
+# The Ring of Durin - last of the Seven Rings of the Dwarf-lords
+
+N:205:of Durin
+I:45:57:2
+W:70:70:2:65000
+F:CON | CHR | STR | SUST_CHR | SUST_CON | SUST_STR | HIDE_TYPE |
+F:ESP_EVIL | AGGRAVATE | HEAVY_CURSE | HOLD_LIFE | DRAIN_EXP |
+F:RES_DARK | RES_CHAOS | RES_NETHER | RES_COLD | RES_ACID |
+F:INSTA_ART | SPECIAL_GENE | CURSED
+Z:Midas touch
+D:The greatest of the Seven Rings of the Dwarf-lords, and the last to be
+D:lost. Alone among the Seven, it was not taken by Sauron when he made
+D:war on the Elves, but was given as a gift from Celebrimbor to King Durin
+D:III of Moria in token of friendship: nevertheless, Sauron in disguise
+D:had a hand in its making, and so it is cursed, and draws evil towards it.
+
+
+# The Elfstone 'Elessar'
+
+N:206:'Elessar'
+I:40:19:4
+W:60:60:3:40000
+P:0:0d0:7:7:10
+F:STR | WIS | CHR | SPEED | LITE3 | INSTA_ART |
+F:RES_FEAR | RES_FIRE | RES_POIS | RES_DISEN | HIDE_TYPE |
+F:ACTIVATE
+a:HARDCORE=ELESSAR
+D:This green gem glows with inner light. Aragorn son of Arathorn wore
+D:it at the Battle of the Pelennor Fields, and he was himself given the
+D:name of 'Elessar' by the people of Gondor because of this.
+
+
+# The Jewel 'Evenstar'
+
+N:207:'Evenstar'
+I:40:20:3
+W:50:50:3:35000
+F:HOLD_LIFE | SUST_CON | SUST_WIS | SUST_INT | LITE1 | CON |
+F:RES_DARK | RES_COLD | RES_NETHER | REGEN | INSTA_ART |
+F:ACTIVATE
+a:HARDCORE=REST_ALL
+D:A pure white jewel, the last gift of Queen Arwen Undomiel to Frodo
+D:Baggins, intended to be worn around his neck on the chain that had
+D:once borne the One Ring.
+
+
+# The Palantir of Minas Ithil (be warned - it's *cursed*!)
+
+N:208:of Minas Ithil
+I:39:107:-3
+W:75:60:200:0
+P:0:10d10:0:0:-30
+F:LIFE | CON | INT | WIS | ESP_ALL | LITE3 | LITE1
+F:CURSED | HEAVY_CURSE | TY_CURSE | DRAIN_EXP |
+F:RES_BLIND | SEE_INVIS | ACTIVATE
+a:HARDCORE=PALANTIR
+D:A shining white ball of unbreakable crystal, the ancient Palantiri
+D:were used by kings of Numenor and later by the Exiles for rapid
+D:communication between distant lands. This Palantir, however, was
+D:taken by Sauron long ago, and mastered to his evil uses, to the
+D:destruction of all others who would gaze into it.
+
+
+# some artifact bolts
+# The Silver Bolt 'Balefire'
+
+N:209:'Balefire'
+I:18:3:0
+W:55:30:2:50000
+P:0:6d5:20:15:0
+F:ESP_DEMON | ESP_UNDEAD | LITE1 |
+F:BRAND_FIRE | KILL_DEMON | KILL_UNDEAD |
+D:This silver-tipped bolt, ablaze with undying celestial fire,
+D:is especially potent against undead and creatures of the
+D:netherworld; it even points the way to places where such
+D:enemies lurk.
+
+
+# The Silver Bolt 'Stone-biter'
+
+N:210:'Stone-biter'
+I:18:3:3
+W:55:30:2:50000
+P:0:6d5:20:15:0
+F:ESP_ORC | ESP_TROLL |
+F:INFRA | SEARCH | TUNNEL | LUCK
+F:BRAND_ACID | SLAY_ORC | SLAY_TROLL |
+D:Wherever it strikes, this silver-tipped bolt eats through rock
+D:and metal as easily as through flesh. The dwarf-smith who
+D:crafted Stone-biter also inscribed the shaft with powerful
+D:doom-spells against the orcs and trolls who had destroyed his
+D:ancestral home.
+
+
+# The Seeker Bolt 'Heart's Blood'
+
+N:211:'Heart's Blood'
+I:18:2:5
+W:85:40:3:35000
+P:0:8d5:15:20:0
+F:VORPAL | WOUNDING | CRIT |
+D:The barbed head of this bolt glows deep red with terrible runes
+D:of destruction; legend has it that Heart's Blood cannot hit its
+D:mark without causing a mortal wound.
+
+
+# The Seeker Bolt 'Scale-piercer'
+
+N:212:'Scale-piercer'
+I:18:2:0
+W:85:40:3:35000
+P:0:8d5:15:20:0
+F:ESP_DRAGON | RES_FEAR |
+F:KILL_DRAGON |
+D:This bolt, crafted from the bones of a Great Wyrm, is less famous
+D:and less powerful than Bard's black arrow. Nonetheless it enables
+D:the owner to find dragons unerringly, face them bravely, and kill
+D:them swiftly.
+
+
+# Artifacts from ToME 3.0.0 for the new maps of Lord Dimwit
+# The pval was set to the average of the flag values.
+
+
+# The Mage Staff of Forochel
+
+N:213:of Forochel
+I:6:1:3
+W:65:70:60:60000
+P:0:3d4:-12:-8:0
+F:INT | WIS | MANA | SPELL | INFRA | SEE_INVIS
+F:SUST_INT | SUST_WIS | RES_BLIND | IM_COLD | SENS_FIRE
+F:SPECIAL_GENE | WIELD_CAST
+F:COULD2H
+f:COULD2H
+D:A shaft of pure, invincible crystal cut from the heart of one
+D:of the great glaciers ringing the Ice-Bay of Forochel.
+D:While you hold it, your mind feels as clear as the winter sky.
+
+
+# The Elven Cloak of Mellyrn
+
+N:214:of Mellyrn
+I:35:2:4
+W:40:40:5:65000
+P:4:0d0:0:0:20
+F:HIDE_TYPE | INVIS | DEX | SPEED | STEALTH | LUCK
+F:SUST_DEX | RES_LITE | RES_DARK | SPECIAL_GENE
+D:Bearing the same lyrical name as the great trees of Lothlorien
+D:and containing in its close-woven folds the speed and skill of
+D:the Galadrim, this grey cloak is ideal for those who travel in
+D:forests.
+
+
+# The Bluesteel Blade of Ephel Duath
+
+N:215:of Ephel Duath
+I:23:31:-3
+W:60:60:50:30000
+P:0:2d6:-20:-18:0
+F:STR | WIS | CHR | BRAND_POIS | VAMPIRIC | VORPAL
+F:INVIS | AGGRAVATE | CURSED | HEAVY_CURSE | SHOW_MODS
+F:SPECIAL_GENE
+D:This filthy orc-blade is famed for vile deeds of torture and blood,
+D:and its wielder will never cease to fear treachery.
+
+
+# The Slaughter Axe 'Garachoth'
+
+N:216:'Garachoth'
+I:24:30:2
+W:70:300:400:91000
+P:0:7d5:18:18:-20
+F:STR | CON | SPEED | LEVELS | BLACK_BREATH
+F:KILL_DEMON | SLAY_ANIMAL | BRAND_FIRE | VORPAL
+F:RES_FEAR | RES_FIRE | RES_CHAOS | RES_NETHER
+F:HIDE_TYPE | SHOW_MODS | SPECIAL_GENE
+D:A ghastly axe with the soul of a demon lord trapped inside, this horrifying
+D:creation reverberates with the screams of the damned. As you gaze into its
+D:glassy, translucent blade, it seems that endless sulphrous wastelands
+D:stretch away from you into the distance, obscured by sheets of fire.
+
+
+# The Set of Cesti 'Skycleaver'
+
+N:217:'Skycleaver'
+I:31:5:1
+W:40:45:40:100000
+P:5:1d1:16:7:16
+F:STR | CON | DEX | CHR | LUCK | FLY
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS
+F:HIDE_TYPE | SHOW_MODS | SPECIAL_GENE
+D:The handgear of a legendary dragonslaying hero. The wearer of these
+D:wyrmskin gauntlets will be versed in all aerial ways, and will fear no
+D:dragon that walks or flies.
+
+
+# The Pair of Metal Shod Boots of the Machine
+# Replaced the stealth malus with AGGRAVATE
+
+N:218:of the Machine
+I:30:6:3
+W:30:100:170:19000
+P:6:1d1:0:0:24
+F:INT | SPEED | TUNNEL | AGGRAVATE
+F:RES_CHAOS | RES_SHARDS | RES_CONF
+F:ESP_NONLIVING | HIDE_TYPE | SPECIAL_GENE
+D:A massive pair of adamantine boots studded with gold, the final and
+D:greatest product of the petty-dwarven magical forge. Despite
+D:the great powers they contain, they are heavy and awkward enough to
+D:make quite a racket whenever you move.
diff --git a/lib/edit/ab_info.txt b/lib/edit/ab_info.txt
new file mode 100644
index 00000000..7b9aa152
--- /dev/null
+++ b/lib/edit/ab_info.txt
@@ -0,0 +1,118 @@
+# File: ab_info.txt
+
+
+# This file is used to initialize the "lib/data/ab_info.raw" file, which is
+# used to initialize the "abilities" information for the ToME game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# The ToME abilities indexes are defined in "defines.h", and must not be changed.
+# If you want to add new ones, add them after the tome ones
+
+# N:idx:name
+# D:desc
+# I:cost(in skill points)
+# A:action mkey:action desc
+
+# Prerequisites
+# k:level:skill
+# S:level(linear mode):stats
+# a:needed ability
+
+# E:excluding ability:excluding ability
+
+# If you need more sophisticated prereqs use the HOOK_LEARN_ABILITY
+
+# Version stamp (required)
+
+# Do not forget to update misc.txt with an entry like the following :
+# Maximum number of traits in ab_info.txt
+# M:b:50
+
+V:2.2.0
+
+N:0:Spread blows
+D:If a monster dies to your attack but you still have blows left
+D:you won't lose the full turn, allowing you to attack some other
+D:monster in the same turn
+D:Prereq: Weaponmastery skill@30, Dex@17
+I:5
+k:30:Weaponmastery
+S:17:DEX
+
+N:1:Tree walking
+D:Allows you to walk in dense forest
+D:Prereq: Nature skill@20
+I:7
+k:20:Nature
+
+N:2:Perfect casting
+D:Allows you to reach 0% failure rate on spells
+D:Prereq: Magic skill@35
+I:6
+k:35:Magic
+
+N:3:Extra Max Blow(1)
+D:Increases your max possible blows number by 1
+D:Prereq: Combat@10
+I:7
+k:10:Combat
+
+N:4:Extra Max Blow(2)
+D:Increases your max possible blows number by 1
+D:Prereq: Combat@20, Extra Max Blow(1)
+I:7
+k:20:Combat
+a:Extra Max Blow(1)
+
+N:5:Ammo creation
+D:Allows you to create shots, arrows and bolts from various materials
+D:Prereq: Archery@10
+A:10:Forge ammo
+I:8
+k:10:Archery
+
+N:6:Touch of death
+D:Your melee blows can insta-kill, but you only receive 1/3 of the experience
+D:Prereq: Necromancy@50, Combat@40, DEX@30, STR@30
+A:100:Activate touch of death
+I:15
+k:50:Necromancy
+k:40:Combat
+S:30:DEX
+S:30:STR
+
+N:7:Artifact Creation
+D:In combination with a high alchemy skill this ability will let you
+D:design your very own artifacts
+D:Prereq: Alchemy@40, INT@35, WIS@35
+I:70
+k:40:Alchemy
+S:35:INT
+S:35:WIS
+
+N:8:Far reaching attack
+D:You can attack an enemy one square far using a long polearm.
+D:At high levels of Polearm-mastery skill, you can even hit two enemies at once.
+D:Prereq: Combat@15, Polearm-mastery@15
+I:10
+A:102:Far reaching attack
+k:15:Combat
+k:15:Polearm-mastery
+
+N:9:Trapping
+D:Ability to set monster traps
+D:Prereq: Disarming@15
+I:10
+A:14:Set trap
+k:15:Disarming
+
+N:10:Undead Form
+D:Ability to turn into a weak undead being when you "die".
+D:You must then kill enough monsters to absorb enough life energy
+D:to come back to life.
+D:Prereq: Necromancy@30, INT@25
+I:15
+k:30:Necromancy
+S:25:INT
diff --git a/lib/edit/al_info.txt b/lib/edit/al_info.txt
new file mode 100644
index 00000000..fbd4c9a0
--- /dev/null
+++ b/lib/edit/al_info.txt
@@ -0,0 +1,2097 @@
+# File: al_info.txt
+
+
+# This file is used to initialize the "lib/raw/al_info.raw" file, which is
+# used as the alchemist recipes in ToME
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes.
+
+# Version stamp (required)
+
+V:2.0.0
+
+
+#Note: when you add anything to this file, you also need to change the M:a
+#line of misc.txt. Unlike other files, there is no 'count' entry. The
+#easiest and fastest way to find out what to say in misc.txt is:
+#
+# grep '^[Ia]:' <al.txt | wc -l
+# you need to add one to the result of the above statement.
+#
+# Which only works on unix systems. But if you have the misfortune not to
+#be working on a unix system, you can use an editor and to a global search
+#and replace, searching for I: and then for a:, which will give you a count
+#that's a few high, but will still work.
+
+
+#Format: There's only one kind of line here, and that's the
+# Item line. Goes like this:
+
+
+# I:tval:sval:Qty:essence
+#
+# The problem here is that it doesn't matter what order things are in.
+# Since the tval and sval are specified on each line, the lines that
+# describe a particular recipe for a particular item don't have to be
+# anywhere even close to each other in the file. This could cause a problem:
+# if the same item has two different entries for the same essence, it will
+# find one, assume that the player has enough, and display that one in green.
+# But when the player goes to make it, they may not have enough. It would also
+# cause weird recipe displays, with one essence listed twice. Funny-looking
+
+
+
+# Some special tvals:
+# 0 Not a tval, used internally by the parser to store the artifact flag essences.
+# We don't currently have any mechanism to control which tvals flags are used on.
+# 1 Not actually a tval, used for ego items, in which case the 'sval' is the e_idx
+# We don't need tvals or svals for ego items, because that information is
+# contained in the e_info record, which the e_idx points us to.
+#
+# 40 Amulet
+# 45 ring
+# 55 staff
+# 65 wand
+# 66 rod tip
+# 70 scroll
+# 71 potion
+# 40 Amulet
+# 45 ring
+# 55 staff
+# 65 wand
+# 66 rod tip
+# 70 scroll
+# 71 potion
+# 72 potion2
+# 80 Food ('shrooms, etc)
+
+# I:tval:sval:Qty:essence
+
+#**********************Mushrooms***********************
+
+#SV_FOOD_POISON 0
+I:80:0:1:LIFE
+I:80:0:8:POISON
+
+#SV_FOOD_BLINDNESS 1
+I:80:1:1:LIFE
+I:80:1:6:DARKNESS
+I:80:1:2:LITE
+
+#SV_FOOD_PARANOIA 2
+I:80:2:1:LIFE
+I:80:2:4:KNOWLEDGE
+I:80:2:4:CONFUSION
+
+#SV_FOOD_CONFUSION 3
+I:80:3:1:LIFE
+I:80:3:8:CONFUSION
+
+#SV_FOOD_HALLUCINATION 4
+I:80:4:1:LIFE
+I:80:4:4:CONFUSION
+I:80:4:4:MANA
+I:80:4:4:TELEPORT
+
+#SV_FOOD_PARALYSIS 5
+I:80:5:1:LIFE
+I:80:5:8:FORCE
+
+#SV_FOOD_WEAKNESS 6
+I:80:6:1:LIFE
+I:80:6:4:POISON
+I:80:6:4:FORCE
+
+#SV_FOOD_SICKNESS 7
+I:80:7:8:LIFE
+I:80:7:1:POISON
+
+#SV_FOOD_STUPIDITY 8
+I:80:8:1:LIFE
+I:80:8:1:MANA
+I:80:8:8:KNOWLEDGE
+
+#SV_FOOD_NAIVETY 9
+I:80:9:1:LIFE
+I:80:9:1:MANA
+I:80:9:4:CONFUSION
+I:80:9:4:KNOWLEDGE
+
+#SV_FOOD_UNHEALTH 10
+I:80:10:8:LIFE
+I:80:10:1:FORCE
+I:80:10:1:POISON
+
+#SV_FOOD_DISEASE 11
+I:80:11:1:LIFE
+I:80:11:1:TIME
+I:80:11:8:POISON
+
+#SV_FOOD_CURE_POISON 12
+I:80:12:1:LIFE
+I:80:12:8:POISON
+
+#SV_FOOD_CURE_BLINDNESS 13
+I:80:13:1:LIFE
+I:80:13:6:LITE
+I:80:13:2:DARKNESS
+
+#SV_FOOD_CURE_PARANOIA 14
+I:80:14:1:LIFE
+I:80:14:1:TIME
+
+#SV_FOOD_CURE_CONFUSION 15
+I:80:15:1:LIFE
+I:80:15:12:KNOWLEDGE
+
+#SV_FOOD_CURE_SERIOUS 16
+I:80:16:8:LIFE
+
+#SV_FOOD_RESTORE_STR 17
+I:80:17:20:LIFE
+I:80:17:2:TIME
+
+#SV_FOOD_RESTORE_CON 18
+I:80:18:20:LIFE
+I:80:18:2:TIME
+
+#SV_FOOD_RESTORING 19
+I:80:19:40:LIFE
+I:80:19:4:TIME
+
+#/* many missing mushrooms */
+#Note - the comment below appears on the list in defines.h, but I can't find
+#any more mushrooms in k_info.txt
+
+#define SV_FOOD_BISCUIT 32
+#define SV_FOOD_JERKY 33
+#define SV_FOOD_RATION 35
+#define SV_FOOD_SLIME_MOLD 36
+#define SV_FOOD_WAYBREAD 37
+#define SV_FOOD_PINT_OF_ALE 38
+#define SV_FOOD_PINT_OF_WINE 39
+#define SV_FOOD_ATHELAS 40
+#define SV_FOOD_GREAT_HEALTH 41
+#define SV_FOOD_FORTUNE_COOKIE 42
+
+
+
+#***************************Artifact Flags************************************
+#
+#A:Group:tval:sval:pval:pval?:level:xp
+# The first three describe the required item, they can be left unspecified
+# for no object, or specify starting with tval for increasingly specific
+# objects.
+# Note: pval? is boolean (0 or 1) if true, then this flag has a
+# variable effect, and we should require more experience and times for
+# increasing pvals.
+# Note:for tval=TV_CORPSE, sval=corpse type, pval=monster idx,
+# or use f:moster_race_flags, or leave all blank for any corpse at all.
+#F:object flag to be set
+#D:Description of flag
+#x:Description of activation (instead of description of flag, see below)
+#d:Description of required item
+#p:Description of required item (plural, optional. Illegal if pval != 1)
+#a:qty:object_flag_to_be_set Essence_name (not used)
+
+# Note that like I: lines, a: lines can be anywhere and in any order.
+# Note: 'flag' is the flag name from a_info.txt,
+# 'monster_race_flag' is from r_info.txt
+
+#The group numbers are 1-5, and the descriptions of the groups
+#are hard coded. see cmd7.c
+
+
+A:1:45:24:1:1:40:5000
+F:STR
+D:Add to Strength
+d:Ring of Strength
+p:Rings of Strength
+
+A:1:45:25:1:1:43:5000
+F:INT
+D:Add to Intelligence
+d:Ring of Intelligence
+p:Rings of Intelligence
+
+A:1:40:28:1:1:46:5000
+F:WIS
+D:Add to Wisdom
+d:Amulet of Wisdom
+p:Amulets of Wisdom
+
+A:1:45:26:1:1:46:5000
+F:DEX
+D:Add to Dexterity
+d:Ring of Dexterity
+p:Rings of Dexterity
+
+A:1:45:27:1:1:42:5000
+F:CON
+D:Add to Constitution
+d:Ring of Constitution
+p:Rings of Constitution
+
+A:1:40:2:0:1:30:5000
+F:CHR
+D:Add to Charisma
+d:Amulet of Adornment
+p:Amulets of Adornment
+
+A:1:45:10:0:0:32:1000
+F:SUST_STR
+D:Sustain Strength
+d:Ring of Sustain Strength
+
+A:1:45:11:0:0:34:1000
+F:SUST_INT
+D:Sustain Intelligence
+d:Ring of Sustain Intelligence
+
+A:1:45:12:0:0:28:1000
+F:SUST_WIS
+D:Sustain Wisdom
+d:Ring of Sustain Wisdom
+
+A:1:45:14:0:0:36:1000
+F:SUST_DEX
+D:Sustain Dexterity
+d:Ring of Sustain Dexterity
+
+A:1:45:13:0:0:36:1000
+F:SUST_CON
+D:Sustain Constitution
+d:Ring of Sustain Constitution
+
+A:1:45:15:0:0:25:1000
+F:SUST_CHR
+D:Sustain Charisma
+d:Ring of Sustain Charisma
+
+A:1:45:31:1:1:40:50000
+F:SPEED
+D:Speed
+d:Ring of Speed
+p:Rings of Speed
+
+A:1:45:49:1:1:38:150000
+F:BLOWS
+D:Extra Attacks
+d:Ring of Extra Attacks
+p:Rings of Extra Attacks
+
+A:1:30:2:0:1:32:5000
+F:STEALTH
+D:Stealthy
+d:Left Insole from a Used Soft Boot
+p:Left Insoles from Used Soft Boots
+
+A:1:36:1:0:1:29:2000
+F:SEARCH
+D:Adds to Searching
+d:Filthy Rag
+p:Filthy Rags
+
+A:1:39:1:0:1:6:1000
+F:INFRA
+D:Helps Infravision
+d:Brass Lantern
+p:Brass Lanterns
+
+A:1:9:-1:5:1:30:1000
+F:LUCK
+D:Lucky
+d:Rabbit's Left Forefoot
+p:Rabbit's Left Forefeet
+
+A:1:20:4:0:1:25:30000
+F:TUNNEL
+D:Aids in digging
+d:Pick
+p:Picks
+
+A:1:9:1:0:1:40:50000
+F:LIFE
+f:TROLL
+D:Multiplies Life
+d:Troll's Heart
+p:Troll's Hearts
+
+A:2:71:8:0:0:20:15000
+F:INVIS
+D:Invisibility
+d:Potion of Invisibility
+
+A:2:71:8:0:0:20:4000
+F:SEE_INVIS
+D:See Invisible
+d:Potion of Invisibility
+
+A:2:5:0:0:0:20:30000
+F:FREE_ACT
+D:Free Action
+d:Iron Spike
+
+A:2:34:5:0:0:38:90000
+F:REFLECT
+D:Reflection
+d:Large Metal Shield
+
+A:2:9:1:644:0:20:30000
+F:SH_FIRE
+D:Aura of Fire
+d:Lungs from an Ancient Red Dragon
+
+A:2:9:1:601:0:25:30000
+F:SH_ELEC
+D:Aura of Lightning
+d:Lungs from an Ancient Blue Dragon
+
+A:2:39:2:0:0:8:1000
+F:LITE1
+D:Light
+d:Everburning Torch
+
+A:2:39:3:0:0:20:10000
+F:LITE2
+D:Bright Light
+d:Dwarven Lantern
+
+A:2:39:4:0:0:40:100000
+F:LITE3
+D:Sunlight
+d:Feanorian Lamp
+
+A:2:38:-1:0:0:40:200000
+F:FLY
+D:Flight
+d:Suit of Dragon Armour (any colour)
+
+A:2:9:-1:862:0:50:10000000
+F:AUTO_ID
+D:Automatically IDs
+d:Morgoth's Testicles
+
+A:2:40:14:0:0:29:2000
+F:NO_TELE
+D:Anti-Teleportation
+d:Teleport Inhibiting Amulet
+
+A:2:40:13:0:0:34:2000
+F:NO_MAGIC
+D:Anti-Magic
+d:Magic Inhibiting Amulet
+
+A:2:71:62:0:0:50:100000
+F:WRAITH
+D:Wraith Form
+d:Potion of Invulnerability
+
+A:2:71:33:0:0:15:1000
+F:FEATHER
+D:Levitation
+d:Potion of Berserk Strength
+
+A:2:80:37:0:0:20:10000
+F:SLOW_DIGEST
+D:Slow Digestion
+d:Lembas Wafer
+
+A:2:80:10:0:0:32:20000
+F:REGEN
+D:Regenerate
+d:Mushroom of Unhealth
+
+A:2:80:3:0:0:12:20000
+F:TELEPORT
+D:Teleport
+d:Mushroom of Confusion
+
+A:3:21:2:0:1:30:20000
+F:CRIT
+D:Extra Critical Hits
+d:Whip
+p:Whips
+
+A:3:23:30:0:0:30:30000
+F:WOUNDING
+D:Wounds Monsters
+d:Blade of Chaos
+
+A:3:66:18:0:1:26:6000
+F:VAMPIRIC
+D:Vampiric
+d:Rod Tip of Drain Life
+
+A:3:9:1:0:0:16:2000
+F:SLAY_ANIMAL
+f:ANIMAL
+D:Slay Animal
+d:Dead Animal's Body
+
+A:3:9:-1:0:0:25:2000
+F:SLAY_EVIL
+f:EVIL
+D:Slay Evil
+d:Evil Dead Thing's Remains
+
+A:3:9:-1:0:0:30:2000
+F:SLAY_UNDEAD
+f:UNDEAD
+D:Slay Undead
+d:Remains of Undead Monster
+
+A:3:9:1:0:0:40:1500
+F:SLAY_DEMON
+f:DEMON
+D:Slay Demon
+d:Demon's Corpse
+
+A:3:9:1:0:0:10:700
+F:SLAY_ORC
+f:ORC
+D:Slay Orc
+d:Dead Orc
+
+A:3:9:1:0:0:16:700
+F:SLAY_TROLL
+f:TROLL
+D:Slay Troll
+d:Dead Troll
+
+A:3:9:1:0:0:25:900
+F:SLAY_GIANT
+f:GIANT
+D:Slay Giant
+d:Dead Giant
+
+A:3:9:1:0:0:33:2000
+F:SLAY_DRAGON
+f:DRAGON
+D:Slay Dragon
+d:Dead Dragon (any size will do)
+
+A:3:9:-1:593:0:41:5000
+F:KILL_DRAGON
+D:*Slay* Dragon
+d:Mature Multi-Hued Dragon's Remains
+
+A:3:9:-1:0:0:41:90000
+F:KILL_UNDEAD
+f:S_HI_UNDEAD
+D:*Slay* Undead
+d:Dead Summoner of Greater Undead
+
+A:3:9:-1:996:0:41:90000
+F:KILL_DEMON
+D:*Slay* Demon
+d:Lesser Balrog's Corpse
+
+A:3:0:0:0:0:36:20000
+F:VORPAL
+D:Vorpal
+
+A:3:0:0:0:0:40:90000
+F:IMPACT
+D:Earthquakes
+
+A:3:0:0:0:0:3:2000
+F:BRAND_POIS
+D:Poison Brand
+
+A:3:0:0:0:0:12:2000
+F:BRAND_ACID
+D:Acid Brand
+
+A:3:0:0:0:0:10:2000
+F:BRAND_ELEC
+D:Lightning Brand
+
+A:3:0:0:0:0:6:2000
+F:BRAND_FIRE
+D:Fire Brand
+
+A:3:0:0:0:0:8:2000
+F:BRAND_COLD
+D:Frost Brand
+
+A:3:0:0:0:1:30:3000
+F:XTRA_MIGHT
+D:Extra Might (Bows Only)
+
+A:3:0:0:0:1:35:3000
+F:XTRA_SHOTS
+D:Extra Shots (Bows Only)
+
+A:4:9:1:624:0:49:500000
+F:IM_ACID
+D:Immune to Acid
+d:Ancient Black Dragon's Foreskin
+
+A:4:9:1:601:0:50:500000
+F:IM_ELEC
+D:Immune to Lightning
+d:Ancient Blue Dragon's Foreskin
+
+A:4:9:1:644:0:49:500000
+F:IM_FIRE
+D:Immune to Fire
+d:Ancient Red Dragon's Foreskin
+
+A:4:9:1:617:0:50:500000
+F:IM_COLD
+D:Immune to Cold
+d:Ancient White Dragon's Foreskin
+
+A:4:40:8:0:0:30:30000
+F:HOLD_LIFE
+D:Hold Life
+d:Amulet of the Magi
+
+A:4:45:17:0:0:12:10000
+F:RES_ACID
+D:Resist Acid
+d:Ring of Acid
+
+A:4:45:56:0:0:15:10000
+F:RES_ELEC
+D:Resist Lightning
+d:Ring of Lightning
+
+A:4:71:30:0:0:13:10000
+F:RES_FIRE
+D:Resist Fire
+d:Potion of Resist Heat
+
+A:4:71:31:0:0:14:10000
+F:RES_COLD
+D:Resist Cold
+d:Potion of Resist Cold
+
+A:4:71:27:0:0:25:30000
+F:RES_POIS
+D:Resist Poison
+d:Potion of Cure Poison
+
+A:4:45:38:0:0:26:10000
+F:RES_FEAR
+D:Resist Fear
+d:Ring of Fear Resistance
+
+A:4:45:39:0:0:31:60000
+F:RES_LITE
+D:Resist Light
+d:Ring of Light and Darkness Resistance
+
+A:4:45:39:0:0:31:60000
+F:RES_DARK
+D:Resist Darkness
+d:Ring of Light and Darkness Resistance
+
+A:4:45:47:0:0:30:30000
+F:RES_BLIND
+D:Resist Blindness
+d:Ring of Blindness Resistance
+
+A:4:45:43:0:0:30:30000
+F:RES_CONF
+D:Resist Confusion
+d:Ring of Confusion Resistance
+
+A:4:45:42:0:0:30:60000
+F:RES_SOUND
+D:Resist Sound
+d:Ring of Sound Resistance
+
+A:4:45:44:0:0:30:60000
+F:RES_SHARDS
+D:Resist Shards
+d:Ring of Shard Resistance
+
+A:4:45:40:0:0:30:60000
+F:RES_NETHER
+D:Resist Nether
+d:Ring of Nether Resistance
+
+A:4:45:41:0:0:30:60000
+F:RES_NEXUS
+D:Resist Nexus
+d:Ring of Nexus Resistance
+
+A:4:45:46:0:0:30:60000
+F:RES_CHAOS
+D:Resist Chaos
+d:Ring of Chaos Resistance
+
+A:4:45:45:0:0:30:60000
+F:RES_DISEN
+D:Resist Disenchantment
+d:Ring of Disenchantment Resistance
+
+A:5:9:1:0:0:50:-100000
+F:TEMPORARY
+D:Temporary Item
+d:Corpse, any corpse
+
+A:5:36:1:0:0:10:-2000
+F:AUTO_CURSE
+D:Self-Cursing
+d:Filthy Rag
+
+A:5:80:40:0:0:45:-10000
+F:BLACK_BREATH
+D:Causes the Black Breath
+d:Sprig of Athelas
+
+A:5:70:15:0:0:40:-5000
+F:TY_CURSE
+D:Ancient Curse
+d:Scroll of *Remove Curse*
+
+A:5:0:0:0:0:40:-5000
+F:DRAIN_EXP
+D:Drains your Experience
+
+A:5:0:0:0:0:30:-5000
+F:AGGRAVATE
+D:Aggravates Monsters
+
+A:5:70:14:0:0:30:-500
+F:CURSED
+D:Curse
+d:Scroll of Remove Curse
+
+#Removed for balance - allows you to trade two essences of extra life,
+# and 25+ magic essence for 10000xp on your artifact, which isn't
+# anything to sneeze at. Curse, above, has the same problem, but
+# for 1000xp, I figure it's a fair trade.
+#A:5:70:15:0:0:40:-10000
+#D:Heavy Curse
+#F:HEAVY_CURSE
+#d:Scroll of *Remove Curse*
+
+A:5:0:0:0:0:50:-5000
+F:PERMA_CURSE
+D:Permanently Cursed
+
+A:5:0:0:0:0:35:-2000
+F:CURSE_NO_DROP
+D:Can't be Dropped
+
+A:5:0:0:0:0:45:-5000
+F:DRAIN_HP
+D:Drains your Hit Points
+
+A:5:0:0:0:0:20:-50000
+F:IMMOVABLE
+D:Wielder Can't Move
+
+#/* Floating eye corpse for esp all :) other ESP's don't require anything at all...*/
+A:5:9:1:32:0:40:20000
+F:ESP_ALL
+D:Telepathy
+d:Formerly Floating Eye
+
+A:5:0:0:0:0:25:3000
+F:ESP_ORC
+D:Sense Orcs
+
+A:5:0:0:0:0:25:3000
+F:ESP_TROLL
+D:Sense Trolls
+
+A:5:0:0:0:0:25:5000
+F:ESP_DRAGON
+D:Sense Dragons
+
+A:5:0:0:0:0:25:5000
+F:ESP_GIANT
+D:Sense Giants
+
+A:5:0:0:0:0:25:5000
+F:ESP_DEMON
+D:Sense Demons
+
+A:5:0:0:0:0:25:5000
+F:ESP_UNDEAD
+D:Sense Undead
+
+A:5:0:0:0:0:25:5000
+F:ESP_EVIL
+D:Sense Evil
+
+A:5:0:0:0:0:25:5000
+F:ESP_ANIMAL
+D:Sense Animals
+
+A:5:0:0:0:0:25:5000
+F:ESP_THUNDERLORD
+D:Sense Thunderlords
+
+A:5:0:0:0:0:25:5000
+F:ESP_GOOD
+D:Sense Good
+
+A:5:0:0:0:0:25:5000
+F:ESP_NONLIVING
+D:Sense Nonliving
+
+A:5:0:0:0:0:25:5000
+F:ESP_UNIQUE
+D:Sense Unique Monsters
+
+A:5:0:0:0:0:25:2000
+F:ESP_SPIDER
+D:Sense Spiders
+
+
+#***************************Activations for artifacts***********************
+# Activations follow all of the rules for artifact flags.
+# except: group number and pval are IGNORED
+# They MUST come after ALL artifact flags in this file!!!
+# There is no way (currently) to require essences...
+#
+# They use a LOWER CASE x: instead of the F: object flag
+#
+# all ACT_ constants are supported, anything else must be coded into init1.c
+# Internally, they are assigned the magic group number of '88'
+# and a NEGATIVE flag number (which is the activation number)
+# Note that although you can use the p: to give activations a plural
+# item description, it will never be used, because pval is forced to 0.
+#
+#A:<îgnored>:tval:sval:<ignored>:<ignored>:level:xp
+# tval and sval describe the required item, they can be left unspecified
+# for no object, or specify starting with tval for increasingly specific
+# objects.
+#F:object flag to be set
+#D:Description of flag
+#x:Description of activation (instead of description of flag)
+#d:Description of required item
+#p:Description of required item (plural, not used for activations)
+#a:qty:object_flag_to_be_set Essence_name
+
+#define ACT_PET_SUMMON 150
+#define ACT_CURE_PARA 151
+#define ACT_CURE_HALLU 152
+#define ACT_CURE_POIS 153
+#define ACT_CURE_HUNGER 154
+#define ACT_CURE_STUN 155
+#define ACT_CURE_CUTS 156
+#define ACT_CURE_FEAR 157
+#define ACT_CURE_CONF 158
+#define ACT_CURE_BLIND 159
+#define ACT_CURING 160
+#define ACT_ACQUIREMENT 163
+#define ACT_MUT 166
+#define ACT_CURE_INSANITY 167
+#define ACT_CURE_MUT 168
+#define ACT_REST_LIFE 84
+#define ACT_REST_ALL 85
+#define ACT_CURE_LW 81
+#define ACT_CURE_MW 82
+#define ACT_CURE_POISON 83
+#define ACT_CURE_700 86
+#define ACT_CURE_1000 87
+
+#define ACT_LIGHT 111
+
+#define ACT_SUNLIGHT 1
+A:0:70:15:0:0:40:40000
+x:SUNLIGHT
+D:Sunlight
+d:Brass Lantern
+
+#define ACT_MAP_LIGHT 112
+#define ACT_DETECT_ALL 113
+#define ACT_DETECT_XTRA 114
+#define ACT_ID_FULL 115
+#define ACT_ID_PLAIN 116
+
+#define ACT_GROW_MOLD 197
+
+
+#define ACT_BO_MISS_1 2
+A:0:0:0:0:0:20:4000
+x:BO_MISS_1
+D:Magic Missile (1)
+
+#define ACT_BO_MISS_2 15
+A:0:0:0:0:0:30:300000
+x:BO_MISS_2
+D:Magic Missile (2)
+
+#define ACT_BA_MISS_3 24
+A:0:0:0:0:0:40:400000
+x:BA_MISS_3
+D:Ball of Missiles
+
+#define ACT_BO_ELEC_1 4
+A:0:0:0:0:0:30:300000
+x:BO_ELEC_1
+D:Bolt of Lightning
+
+#define ACT_BA_ELEC_2 12
+A:0:0:0:0:0:30:300000
+x:BA_ELEC_2
+D:Ball of Lightning
+
+#define ACT_BA_ELEC_3 18
+A:0:0:0:0:0:35:350000
+x:BA_ELEC_3
+D:Ball of Lightning(2)
+
+#define ACT_BA_ELEC_H 172
+A:0:0:0:0:0:40:400000
+x:BA_ELEC_H
+D:Ball of Lightning(3)
+
+#define ACT_BA_ELEC_4 183
+A:0:0:0:0:0:40:400000
+x:BA_ELEC_4
+D:Ball of Lightning(4)
+
+#define ACT_BR_ELEC 184
+A:0:0:0:0:0:45:450000
+x:BR_ELEC
+D:Breathe Lightning
+
+#define ACT_BO_ACID_1 5
+#define ACT_BA_COLD_1 8
+#define ACT_BA_ACID_H 173
+#define ACT_BA_ACID_4 182
+#define ACT_BR_ACID 187
+#define ACT_BO_COLD_1 6
+#define ACT_BA_COLD_2 11
+#define ACT_BA_COLD_3 17
+#define ACT_BA_COLD_H 171
+#define ACT_BA_COLD_4 180
+#define ACT_BR_COLD 185
+#define ACT_BO_FIRE_1 7
+#define ACT_BA_FIRE_1 9
+#define ACT_BA_FIRE_2 16
+#define ACT_BA_FIRE_H 170
+#define ACT_BA_FIRE_4 181
+#define ACT_BR_FIRE 186
+#define ACT_BA_POIS_1 3
+#define ACT_BA_POIS_4 179
+#define ACT_BR_POIS 188
+#define ACT_BR_MANY 189
+#define ACT_BR_CONF 190
+#define ACT_BR_SOUND 191
+#define ACT_BR_CHAOS 192
+#define ACT_BR_SHARD 193
+#define ACT_BR_BALANCE 194
+#define ACT_BR_LIGHT 195
+#define ACT_BR_POWER 196
+#define ACT_ROCKET 22
+A:0:0:0:0:0:50:40000
+x:ROCKET
+D:Fire a Rocket
+
+#define ACT_JUMP 177
+#define ACT_WHIRLWIND 19
+#define ACT_CALL_CHAOS 21
+#define ACT_DISP_EVIL 23
+#define ACT_DISP_GOOD 25
+#define ACT_DAWN 61
+#define ACT_CHARM_ANIMAL 65
+#define ACT_CHARM_UNDEAD 66
+#define ACT_CHARM_OTHER 67
+#define ACT_CHARM_ANIMALS 68
+#define ACT_CHARM_OTHERS 69
+#define ACT_SUMMON_ANIMAL 70
+#define ACT_SUMMON_PHANTOM 71
+#define ACT_SUMMON_ELEMENTAL 72
+#define ACT_SUMMON_DEMON 73
+#define ACT_SUMMON_UNDEAD 74
+#define ACT_RUNE_EXPLO 117
+#define ACT_RUNE_PROT 118
+#define ACT_SATIATE 119
+#define ACT_DEST_DOOR 120
+#define ACT_STONE_MUD 121
+#define ACT_RECHARGE 122
+#define ACT_ALCHEMY 123
+#define ACT_DIM_DOOR 124
+#define ACT_TELEPORT 125
+#define ACT_RECALL 126
+
+#define ACT_SPIN 174
+#define ACT_NOLDOR 175
+#define ACT_SPECTRAL 176
+#define ACT_DEST_TELE 178
+#define ACT_DRAIN_1 10
+#define ACT_DRAIN_2 13
+#define ACT_VAMPIRE_1 14
+#define ACT_VAMPIRE_2 20
+#define ACT_GILGALAD 26
+#define ACT_CELEBRIMBOR 27
+#define ACT_SKULLCLEAVER 28
+#define ACT_HARADRIM 29
+#define ACT_FUNDIN 30
+#define ACT_EOL 31
+#define ACT_UMBAR 32
+#define ACT_NUMENOR 33
+#define ACT_KNOWLEDGE 34
+#define ACT_UNDEATH 35
+#define ACT_THRAIN 36
+#define ACT_BARAHIR 37
+#define ACT_TULKAS 38
+#define ACT_NARYA 39
+#define ACT_NENYA 40
+#define ACT_VILYA 41
+#define ACT_POWER 42
+#define ACT_STONE_LORE 43
+#define ACT_RAZORBACK 44
+#define ACT_BLADETURNER 45
+#define ACT_MEDIATOR 46
+#define ACT_BELEGENNON 47
+#define ACT_GORLIM 48
+#define ACT_COLLUIN 49
+#define ACT_BELANGIL 50
+#define ACT_CONFUSE 51
+#define ACT_SLEEP 52
+#define ACT_QUAKE 53
+#define ACT_TERROR 54
+#define ACT_TELE_AWAY 55
+#define ACT_BANISH_EVIL 56
+#define ACT_GENOCIDE 57
+#define ACT_MASS_GENO 58
+#define ACT_ANGUIREL 59
+#define ACT_ERU 60
+#define ACT_FIRESTAR 62
+#define ACT_TURMIL 63
+#define ACT_CUBRAGOL 64
+#define ACT_ELESSAR 75
+#define ACT_GANDALF 76
+#define ACT_MARDA 77
+#define ACT_PALANTIR 78
+#define ACT_ROBINTON 79
+#define ACT_PIEMUR 80
+#define ACT_MENOLLY 88
+#define ACT_EREBOR 89
+#define ACT_DRUEDAIN 90
+#define ACT_ESP 91
+#define ACT_BERSERK 92
+#define ACT_PROT_EVIL 93
+#define ACT_RESIST_ALL 94
+#define ACT_SPEED 95
+#define ACT_XTRA_SPEED 96
+#define ACT_WRAITH 97
+#define ACT_INVULN 98
+#define ACT_ROHAN 99
+#define ACT_HELM 100
+#define ACT_BOROMIR 101
+#define ACT_HURIN 102
+#define ACT_AXE_GOTHMOG 103
+#define ACT_MELKOR 104
+#define ACT_GROND 105
+#define ACT_NATUREBANE 106
+#define ACT_NIGHT 107
+#define ACT_ORCHAST 108
+
+#define ACT_DEATH 127
+#define ACT_RUINATION 128
+#define ACT_DESTRUC 129
+#define ACT_UNINT 130
+#define ACT_UNSTR 131
+#define ACT_UNCON 132
+#define ACT_UNCHR 133
+#define ACT_UNDEX 134
+#define ACT_UNWIS 135
+#define ACT_STATLOSS 136
+#define ACT_HISTATLOSS 137
+#define ACT_EXPLOSS 138
+#define ACT_HIEXPLOSS 139
+#define ACT_SUMMON_MONST 140
+#define ACT_PARALYZE 141
+#define ACT_HALLU 142
+#define ACT_POISON 143
+#define ACT_HUNGER 144
+#define ACT_STUN 145
+#define ACT_CUTS 146
+#define ACT_PARANO 147
+#define ACT_CONFUSION 148
+#define ACT_BLIND 149
+#define ACT_DARKNESS 161
+#define ACT_LEV_TELE 162
+#define ACT_WEIRD 164
+#define ACT_AGGRAVATE 165
+#define ACT_LIGHT_ABSORBTION 169
+#define ACT_MUSIC 200
+
+
+#***************************Amulets***********************
+
+#SV_AMULET_ADORNMENT
+I:40:2:4:DARKNESS
+
+#SV_AMULET_BRILLANCE
+I:40:6:1:KNOWLEDGE
+I:40:6:2:CONFUSION
+
+#SV_AMULET_CHARISMA
+I:40:7:4:DARKNESS
+
+#SV_AMULET_DEVOTION
+I:40:25:1:MAGIC
+I:40:25:2:CONFUSION
+I:40:25:8:KNOWLEDGE
+
+#SV_AMULET_ESP
+I:40:22:4:KNOWLEDGE
+
+#SV_AMULET_INFRA
+I:40:26:1:LITE
+
+#SV_AMULET_NO_MAGIC
+I:40:13:4:MAGIC
+
+#SV_AMULET_NO_TELE
+I:40:14:8:TELEPORT
+
+#SV_AMULET_REFLECTION
+I:40:9:10:FORCE
+I:40:9:10:MANA
+
+#SV_AMULET_REGENERATION
+I:40:30:4:LIFE
+
+#SV_AMULET_RESISTANCE
+I:40:15:4:ACID
+I:40:15:4:COLD
+I:40:15:4:FIRE
+I:40:15:4:LIGHTNING
+
+#SV_AMULET_RESIST_ACID
+I:40:4:4:ACID
+
+#SV_AMULET_RESIST_ELEC
+I:40:29:4:LIGHTNING
+
+#SV_AMULET_SEARCHING
+I:40:5:4:KNOWLEDGE
+I:40:5:4:LITE
+
+#SV_AMULET_SERPENT
+I:40:17:1:MANA
+I:40:17:4:ACID
+
+#SV_AMULET_SLOW_DIGEST
+I:40:3:4:LIFE
+
+#SV_AMULET_SUSTENANCE
+I:40:21:8:LIFE
+
+#SV_AMULET_TELEPORT
+I:40:1:8:TELEPORT
+
+#SV_AMULET_THE_MAGI
+I:40:8:1:MAGIC
+I:40:8:4:KNOWLEDGE
+
+#SV_AMULET_TRICKERY
+#I:40:23:1:MAGIC
+I:40:23:8:CONFUSION
+
+#SV_AMULET_WEAPONMASTERY
+I:40:24:12:EXPLOSION
+I:40:24:1:MAGIC
+
+#SV_AMULET_WISDOM
+I:40:28:1:KNOWLEDGE
+I:40:28:2:CONFUSION
+
+#*********Potions******************************
+#Note that these first few potions are the ones which
+#can be thrown for much damage, and are thus an integral part of
+#the alchemist's arsenal.
+
+#SV_POTION_DETONATIONS
+I:71:22:6:EXPLOSION
+
+#SV_POTION_DEATH
+I:71:23:10:LIFE
+
+#SV_POTION_RUINATION
+I:71:15:5:DARKNESS
+
+#SV_POTION_APPLE_JUICE
+I:71:1:1:LIFE
+
+#SV_POTION_AUGMENTATION
+I:71:55:16:POISON
+I:71:55:24:CONFUSION
+I:71:55:6:MAGIC
+I:71:55:8:EXPLOSION
+I:71:55:16:LIFE
+I:71:55:8:LIGHTNING
+I:71:55:16:DARKNESS
+
+#SV_POTION_BESERK_STRENGTH
+I:71:33:1:FIRE
+
+#SV_POTION_BLINDNESS
+I:71:7:1:DARKNESS
+
+#SV_POTION_BOLDNESS
+I:71:28:1:LITE
+
+#SV_POTION_CONFUSION
+I:71:9:1:CONFUSION
+
+#SV_POTION_CURE_CRITICAL
+I:71:36:4:LIFE
+
+#SV_POTION_CURE_LIGHT
+I:71:34:1:LIFE
+
+#SV_POTION_CURE_SERIOUS
+I:71:35:2:LIFE
+
+#SV_POTION_CURING
+I:71:61:1:LIFE
+
+#SV_POTION_DEC_CHR
+I:71:21:1:MANA
+I:71:21:8:DARKNESS
+I:71:21:8:CONFUSION
+
+#SV_POTION_DEC_CON
+I:71:20:1:MANA
+I:71:20:8:LIFE
+I:71:20:8:POISON
+
+#SV_POTION_DEC_DEX
+I:71:19:1:MANA
+I:71:19:8:LIGHTNING
+I:71:19:8:DARKNESS
+
+#SV_POTION_DEC_INT
+I:71:17:1:MANA
+I:71:17:8:CONFUSION
+I:71:17:8:KNOWLEDGE
+
+#SV_POTION_DEC_STR
+I:71:16:1:MANA
+I:71:16:8:EXPLOSION
+I:71:16:8:POISON
+
+#SV_POTION_DEC_WIS
+I:71:18:1:MANA
+I:71:18:8:CONFUSION
+I:71:18:8:LIFE
+
+#SV_POTION_DETECT_INVIS
+I:71:25:1:DARKNESS
+I:71:25:1:LITE
+
+#SV_POTION_ENLIGHTENMENT
+I:71:56:8:KNOWLEDGE
+
+#SV_POTION_EXPERIENCE
+I:71:59:30:EXTRALIFE
+
+#SV_POTION_HEALING
+I:71:37:1:EXTRALIFE
+
+#SV_POTION_HEROISM
+I:71:32:1:COLD
+
+#SV_POTION_INC_CHR
+I:71:53:1:MAGIC
+I:71:53:8:DARKNESS
+I:71:53:8:CONFUSION
+
+#SV_POTION_INC_CON
+I:71:52:1:MAGIC
+I:71:52:8:LIFE
+I:71:52:8:POISON
+
+#Potion of Slow Poison
+I:71:26:1:POISON
+
+#Potion of Cure Poison
+I:71:27:2:POISON
+
+#Potion of Poison
+I:71:6:1:POISON
+
+#SV_POTION_INC_DEX
+I:71:51:1:MAGIC
+I:71:51:8:LIGHTNING
+I:71:51:8:DARKNESS
+
+#SV_POTION_INC_INT
+I:71:49:1:MAGIC
+I:71:49:8:KNOWLEDGE
+I:71:49:8:CONFUSION
+
+#SV_POTION_INC_STR
+I:71:48:1:MAGIC
+I:71:48:8:EXPLOSION
+I:71:48:8:POISON
+
+#SV_POTION_INC_WIS
+I:71:50:1:MAGIC
+I:71:50:8:CONFUSION
+I:71:50:8:LIFE
+
+#SV_POTION_INFRAVISION
+I:71:24:1:LITE
+
+#SV_POTION_INVIS
+I:71:8:4:DARKNESS
+
+#SV_POTION_INVULNERABILITY
+I:71:62:10:FORCE
+I:71:62:4:MAGIC
+
+#SV_POTION_LIFE
+I:71:39:8:EXTRALIFE
+
+#SV_POTION_LOSE_MEMORIES
+I:71:13:20:DARKNESS
+
+#SV_POTION_MUTATION
+I:71:10:12:CHAOS
+
+#SV_POTION_NEW_LIFE
+I:71:63:16:EXTRALIFE
+
+#SV_POTION_RESISTANCE
+I:71:60:2:ACID
+I:71:60:2:COLD
+I:71:60:2:FIRE
+I:71:60:2:LIGHTNING
+
+#SV_POTION_RESIST_COLD
+I:71:31:1:COLD
+
+#SV_POTION_RESIST_HEAT
+I:71:30:1:FIRE
+
+#SV_POTION_RESTORE_EXP
+I:71:41:8:LIFE
+I:71:41:3:KNOWLEDGE
+
+#SV_POTION_RESTORE_MANA
+I:71:40:12:MANA
+
+#SV_POTION_RES_CHR
+I:71:47:12:LIFE
+
+#SV_POTION_RES_CON
+I:71:46:12:LIFE
+
+#SV_POTION_RES_DEX
+I:71:45:12:LIFE
+
+#SV_POTION_RES_INT
+I:71:43:12:LIFE
+
+#SV_POTION_RES_STR
+I:71:42:12:LIFE
+
+#SV_POTION_RES_WIS
+I:71:44:12:LIFE
+
+#SV_POTION_SALT_WATER
+I:71:5:1:LIGHTNING
+
+#SV_POTION_SELF_KNOWLEDGE
+I:71:58:2:KNOWLEDGE
+
+#SV_POTION_SLEEP
+I:71:11:1:MANA
+
+#SV_POTION_SLIME_MOLD
+I:71:2:1:LIFE
+
+#SV_POTION_SLOWNESS
+I:71:4:1:MANA
+
+#SV_POTION_SPEED
+I:71:29:1:TIME
+
+#SV_POTION_STAR_ENLIGHTENMENT
+I:71:57:12:KNOWLEDGE
+
+#SV_POTION_STAR_HEALING
+I:71:38:4:EXTRALIFE
+
+#SV_POTION_WATER
+I:71:0:1:LIFE
+
+#********************************Potion 2*********************************
+
+#SV_POTION2_MIMIC 1
+I:72:1:2:LIFE
+#SV_POTION2_CURE_LIGHT_SANITY 14
+I:72:14:1:CONFUSION
+I:72:14:1:DARKNESS
+#SV_POTION2_CURE_SERIOUS_SANITY 15
+I:72:15:2:CONFUSION
+I:72:15:2:DARKNESS
+#SV_POTION2_CURE_CRITICAL_SANITY 16
+I:72:16:4:CONFUSION
+I:72:16:4:DARKNESS
+#SV_POTION2_CURE_SANITY 17
+I:72:17:8:CONFUSION
+I:72:17:8:DARKNESS
+#SV_POTION2_CURE_WATER 18
+#I:72:18:4:EXPLOSION
+#I:72:18:4:POISON
+#I:72:18:2:EXTRALIFE
+
+#************Rod Tips.****************************
+
+#SV_ROD_ACID_BALL
+I:66:24:1:MAGIC
+I:66:24:8:ACID
+
+#SV_ROD_ACID_BOLT
+I:66:20:4:ACID
+
+#SV_ROD_COLD_BALL
+I:66:27:1:MAGIC
+I:66:27:8:COLD
+
+#SV_ROD_COLD_BOLT
+I:66:23:4:COLD
+
+#SV_ROD_CURING
+I:66:8:3:LIFE
+
+#SV_ROD_DETECTION
+I:66:6:8:KNOWLEDGE
+
+#SV_ROD_DETECT_DOOR
+I:66:1:1:KNOWLEDGE
+
+#SV_ROD_DETECT_TRAP
+I:66:29:1:KNOWLEDGE
+
+#SV_ROD_DISARMING
+I:66:14:4:TELEPORT
+
+#SV_ROD_DRAIN_LIFE
+I:66:18:10:LIFE
+
+#SV_ROD_ELEC_BALL
+I:66:25:1:MAGIC
+I:66:25:8:LIGHTNING
+
+#SV_ROD_ELEC_BOLT
+I:66:21:4:LIGHTNING
+
+#SV_ROD_FIRE_BALL
+I:66:26:1:MAGIC
+I:66:26:8:FIRE
+
+#SV_ROD_FIRE_BOLT
+I:66:22:4:FIRE
+
+#SV_ROD_HAVOC
+I:66:28:5:CHAOS
+
+#SV_ROD_HEALING
+I:66:9:4:EXTRALIFE
+
+#SV_ROD_IDENTIFY
+I:66:2:4:MANA
+I:66:2:4:KNOWLEDGE
+
+#SV_ROD_ILLUMINATION
+I:66:4:4:LITE
+
+#SV_ROD_LITE
+I:66:15:1:LITE
+
+#SV_ROD_MAPPING
+I:66:5:1:KNOWLEDGE
+I:66:5:8:LITE
+
+#SV_ROD_POLYMORPH
+I:66:19:1:CHAOS
+
+#SV_ROD_PROBING
+I:66:7:20:KNOWLEDGE
+I:66:7:3:MANA
+
+#SV_ROD_RECALL
+I:66:3:3:FORCE
+I:66:3:9:TELEPORT
+
+#SV_ROD_RESTORATION
+I:66:10:30:LIFE
+
+#SV_ROD_SLEEP_MONSTER
+I:66:16:1:MANA
+
+#SV_ROD_SLOW_MONSTER
+I:66:17:1:TIME
+
+#SV_ROD_SPEED
+I:66:11:10:TIME
+
+#SV_ROD_TELEPORT_AWAY
+I:66:13:8:TELEPORT
+
+#**************************Scrolls ********************
+
+#SV_SCROLL_ACQUIREMENT
+I:70:46:10:MAGIC
+
+#SV_SCROLL_ARTIFACT
+I:70:52:99:MAGIC
+
+#SV_SCROLL_BLESSING
+I:70:33:1:LIFE
+
+#SV_SCROLL_CHAOS
+I:70:50:2:CHAOS
+
+#SV_SCROLL_DARKNESS
+I:70:0:1:DARKNESS
+
+#SV_SCROLL_DETECT_DOOR
+I:70:29:1:KNOWLEDGE
+
+#SV_SCROLL_DETECT_GOLD
+I:70:26:1:KNOWLEDGE
+
+#SV_SCROLL_DETECT_INVIS
+I:70:30:1:DARKNESS
+I:70:30:1:KNOWLEDGE
+
+#SV_SCROLL_DETECT_ITEM
+I:70:27:2:KNOWLEDGE
+
+#SV_SCROLL_DETECT_TRAP
+I:70:28:1:KNOWLEDGE
+
+#SV_SCROLL_DISPEL_UNDEAD
+I:70:42:1:EXTRALIFE
+
+#SV_SCROLL_ENCHANT_ARMOR
+I:70:16:3:EXPLOSION
+
+#SV_SCROLL_ENCHANT_WEAPON_PVAL
+I:70:19:10:MAGIC
+
+#SV_SCROLL_ENCHANT_WEAPON_TO_DAM
+I:70:18:3:EXPLOSION
+
+#SV_SCROLL_ENCHANT_WEAPON_TO_HIT
+I:70:17:3:LITE
+
+#SV_SCROLL_FIRE
+I:70:48:1:FIRE
+
+#SV_SCROLL_GENOCIDE
+I:70:44:1:FORCE
+I:70:44:5:DARKNESS
+
+#SV_SCROLL_HOLY_CHANT
+I:70:34:2:LIFE
+
+#SV_SCROLL_HOLY_PRAYER
+I:70:35:3:LIFE
+
+#SV_SCROLL_ICE
+I:70:49:1:COLD
+
+#SV_SCROLL_IDENTIFY
+I:70:12:1:KNOWLEDGE
+
+#SV_SCROLL_LIGHT
+I:70:24:1:LITE
+
+#SV_SCROLL_MAPPING
+I:70:25:2:KNOWLEDGE
+I:70:25:5:LITE
+
+#SV_SCROLL_MASS_GENOCIDE
+I:70:45:1:FORCE
+I:70:45:30:DARKNESS
+
+#SV_SCROLL_MONSTER_CONFUSION
+I:70:36:1:CONFUSION
+
+#SV_SCROLL_PHASE_DOOR
+I:70:8:1:TELEPORT
+
+#SV_SCROLL_PROTECTION_FROM_EVIL
+I:70:37:1:MANA
+I:70:37:9:LIFE
+
+#SV_SCROLL_RECHARGING
+I:70:22:4:LIGHTNING
+
+#SV_SCROLL_REMOVE_CURSE
+I:70:14:1:LIFE
+
+#SV_SCROLL_RESET_RECALL
+I:70:23:1:FORCE
+
+#SV_SCROLL_RUMOR
+I:70:51:1:LIGHTNING
+
+#SV_SCROLL_RUNE_OF_PROTECTION
+I:70:38:1:EXTRALIFE
+I:70:38:6:FORCE
+
+#SV_SCROLL_SATISFY_HUNGER
+I:70:32:1:LIFE
+
+#SV_SCROLL_STAR_ACQUIREMENT
+I:70:47:20:MAGIC
+
+#SV_SCROLL_STAR_DESTRUCTION
+I:70:41:12:FORCE
+
+#SV_SCROLL_STAR_ENCHANT_ARMOR
+I:70:20:9:EXPLOSION
+
+#SV_SCROLL_STAR_ENCHANT_WEAPON
+I:70:21:9:EXPLOSION
+I:70:21:9:LITE
+
+#SV_SCROLL_STAR_IDENTIFY
+I:70:13:1:MAGIC
+I:70:13:20:KNOWLEDGE
+
+#SV_SCROLL_STAR_REMOVE_CURSE
+I:70:15:1:EXTRALIFE
+
+#SV_SCROLL_TELEPORT
+I:70:9:1:TELEPORT
+
+#SV_SCROLL_TELEPORT_LEVEL
+I:70:10:5:TELEPORT
+
+#SV_SCROLL_TRAP_CREATION
+I:70:7:1:CONFUSION
+I:70:7:1:TELEPORT
+
+#SV_SCROLL_TRAP_DOOR_DESTRUCTION
+I:70:39:1:FORCE
+
+#SV_SCROLL_WORD_OF_RECALL
+I:70:11:1:FORCE
+I:70:11:3:TELEPORT
+
+#***************************Staves************************
+
+#Globe of Light
+I:55:3:1:LITE
+#Fiery Shield
+I:55:4:2:FIRE
+I:55:4:1:MANA
+#Remove Curse
+I:55:5:2:LIFE
+#Wings of Winds
+I:55:6:1:FORCE
+#Shake
+I:55:7:4:FORCE
+#Disarm
+I:55:8:1:FORCE
+I:55:8:1:KNOWLEDGE
+#Teleportation
+I:55:9:1:TELEPORT
+#Probability Travel
+I:55:10:1:MANA
+I:55:10:1:TELEPORT
+#11 Recovery
+I:55:11:1:LIFE
+#12 Healing
+I:55:12:1:EXTRALIFE
+#13 Vision
+I:55:13:1:LITE
+#Identify
+I:55:14:1:KNOWLEDGE
+I:55:14:1:MANA
+#Sense Hidden
+I:55:15:1:KNOWLEDGE
+#Reveal Ways
+I:55:16:1:KNOWLEDGE
+#Sense Monsters
+I:55:17:1:KNOWLEDGE
+#Genocide
+I:55:18:1:FORCE
+I:55:18:5:DARKNESS
+#19 Summon
+I:55:19:1:LIFE
+I:55:19:1:TELEPORT
+#Wish
+I:55:20:99:MAGIC
+#Mana
+I:55:21:1:MANA
+#Sterilize
+I:55:24:1:POISON
+I:55:24:1:MANA
+
+#********************Wands*****************
+
+#MannaThrust
+I:65:3:4:MANA
+
+#FireFlash
+I:65:4:1:FIRE
+
+#FireWall
+I:65:5:4:FIRE
+I:65:5:1:MANA
+
+#Tidal Wave
+I:65:6:1:POISON
+I:65:6:1:ACID
+I:65:6:1:COLD
+
+#Ice Storm
+I:65:7:4:COLD
+I:65:7:1:MANA
+
+#Wand of Noxious Cloud
+I:65:8:1:POISON
+
+#Poison Blood
+I:65:9:2:POISON
+I:65:9:1:LIFE
+
+#Thunderstorm
+I:65:10:4:LIGHTNING
+
+#DIG
+I:65:11:1:FORCE
+
+#Stone Prison
+I:65:12:3:FORCE
+I:65:12:1:MANA
+
+#Strike
+I:65:13:1:FORCE
+#Teleport Away
+I:65:14:1:TELEPORT
+#Summon Animal
+I:65:15:4:LIFE
+I:65:15:1:MANA
+#MageLock
+I:65:16:1:FORCE
+#Slow Monster
+I:65:17:1:MANA
+#Essence of Speed
+I:65:18:1:TIME
+#Banishment
+I:65:19:2:TELEPORT
+#20 Disperse Magic
+I:65:20:4:LIFE
+I:65:20:4:MANA
+#Charm
+I:65:21:1:MANA
+I:65:21:1:LIFE
+#Confuse
+I:65:22:1:CONFUSION
+#Deamon Blade
+I:65:23:1:FORCE
+I:65:23:1:FIRE
+#Heal Monster
+I:65:24:1:LIFE
+#25 Haste Monster
+I:65:25:1:MANA
+
+
+
+#RINGS*********************************************************
+
+#ring of poison resistance
+I:45:20:8:POISON
+
+#Ring of Critical Hits
+I:45:59:8:MANA
+
+#Damage
+I:45:29:1:EXPLOSION
+
+#Slaying
+I:45:30:8:EXPLOSION
+I:45:30:8:LITE
+
+#Sound Resistance
+I:45:42:4:EXPLOSION
+I:45:42:4:LITE
+
+#Shard Resistance
+I:45:44:4:EXPLOSION
+I:45:44:4:TELEPORT
+
+#Flying
+I:45:54:12:TELEPORT
+
+#Extra Attacks
+I:45:49:8:TELEPORT
+I:45:49:4:TIME
+
+#Teleportation
+I:45:4:8:TELEPORT
+
+#Lordly Protection
+I:45:48:4:TELEPORT
+I:45:48:12:LITE
+I:45:48:1:EXTRALIFE
+
+#Ring of Ice
+I:45:19:8:COLD
+
+#Ring of Cold Resistance
+I:45:9:4:COLD
+
+#Ring of Flames
+I:45:18:8:FIRE
+
+#Ring of Fire Resistance
+I:45:8:4:FIRE
+
+#Ring of Acid
+I:45:17:8:ACID
+
+#Ring of Disenchantment Resistance
+I:45:45:8:ACID
+I:45:45:2:CHAOS
+
+#Ring of slow digestion
+I:45:6:4:LIFE
+I:45:6:1:TIME
+
+#ring of confusion resistance
+I:45:43:8:CONFUSION
+
+#Ring of Stupidity
+I:45:3:1:CONFUSION
+
+#Ring of Blindness Resistance
+I:45:47:8:LITE
+
+#Ring of Accuracy
+I:45:28:1:LITE
+
+#Ring of Searching
+I:45:23:4:LITE
+I:45:23:3:KNOWLEDGE
+
+#Ring of Chaos
+I:45:46:8:LITE
+
+#Ring of Light and Darkness Resistance
+I:45:39:8:LITE
+I:45:39:8:DARKNESS
+
+#Ring of Speed
+I:45:31:12:TIME
+
+#ring of Weakness
+I:45:2:1:POISON
+
+#ring of Constitution
+I:45:27:2:POISON
+I:45:27:8:LIFE
+
+#ring of Strength
+I:45:24:1:POISON
+I:45:24:1:EXPLOSION
+
+#Ring of Dexterity
+I:45:26:1:KNOWLEDGE
+I:45:26:1:LIGHTNING
+
+#ring of Sustain Constitution
+I:45:13:1:POISON
+I:45:13:4:LIFE
+I:45:13:1:MANA
+
+#ring of Sustain Strength
+I:45:10:1:POISON
+I:45:10:1:EXPLOSION
+I:45:10:1:MANA
+
+#ring of Sustain Intelligence
+I:45:11:1:CONFUSION
+I:45:11:1:MANA
+
+#ring of Intelligence
+I:45:25:1:CONFUSION
+I:45:25:12:KNOWLEDGE
+
+#Ring of Sustain Wisdom
+I:45:12:1:MANA
+I:45:12:4:CONFUSION
+
+#Ring of Sustain Dexterity
+I:45:14:1:MANA
+I:45:14:1:LIGHTNING
+
+#Ring of Sustain Charisma
+I:45:15:1:MANA
+I:45:15:1:DARKNESS
+
+#Ring of See Invisible
+I:45:22:8:DARKNESS
+
+#Ring of Invisibility
+I:45:53:8:DARKNESS
+
+#Ring of Fear resistance
+I:45:38:1:MAGIC
+
+#Ring of Levitation
+I:45:7:1:MANA
+
+#Ring of Nether Resistance
+I:45:40:1:MANA
+I:45:40:12:LIFE
+
+#Ring of Nexus Resistance
+I:45:41:1:MANA
+
+#Ring of Free Action
+I:45:21:1:FORCE
+
+#Ring of Protection
+I:45:16:10:FORCE
+
+#Ring of Lightning
+I:45:56:12:LIGHTNING
+
+#EGO ITEMS, in order by e_idx
+I:1:1:1:MAGIC },/*of Mana*/
+I:1:2:2:MAGIC },/*of Power*/
+I:1:3:3:MAGIC },/*of Wizardry*/
+I:1:4:2:MAGIC },/*of Spell*/
+I:1:5:4:ACID },/*of Resist Acid*/
+I:1:6:4:LIGHTNING },/*of Resist Lightning*/
+I:1:7:4:FIRE },/*of Resist Fire*/
+I:1:8:4:COLD },/*of Resist Cold*/
+I:1:9:4:ACID },/*of Resistance*/
+I:1:9:4:COLD },/*of Resistance*/
+I:1:9:4:FIRE },/*of Resistance*/
+I:1:9:4:LIGHTNING },/*of Resistance*/
+I:1:10:5:ACID },/*Elven*/
+I:1:10:5:COLD },/*Elven*/
+I:1:10:5:FIRE },/*Elven*/
+I:1:10:5:LIGHTNING },/*Elven*/
+I:1:11:1:MAGIC },/*of Permanence*/
+I:1:11:6:ACID },/*of Permanence*/
+I:1:11:6:COLD },/*of Permanence*/
+I:1:11:6:FIRE },/*of Permanence*/
+I:1:11:6:LIGHTNING },/*of Permanence*/
+I:1:12:1:POISON },/*of Leprousness*/
+I:1:13:3:MAGIC },/*of Immunity*/
+I:1:14:5:MAGIC },/*of Defense*/
+I:1:15:4:TELEPORT },/*of Jumping*/
+I:1:16:4:ACID },/*of Resist Acid*/
+I:1:17:4:LIGHTNING },/*of Resist Lightning*/
+I:1:18:4:FIRE },/*of Resist Fire*/
+I:1:19:4:COLD },/*of Resist Cold*/
+I:1:20:4:ACID },/*of Resistance*/
+I:1:20:4:COLD },/*of Resistance*/
+I:1:20:4:FIRE },/*of Resistance*/
+I:1:20:4:LIGHTNING },/*of Resistance*/
+I:1:21:12:FORCE },/*of Reflection*/
+I:1:22:8:LIGHTNING },/*of Electricity*/
+I:1:23:4:DARKNESS },/*of the Noldor*/
+I:1:24:4:KNOWLEDGE },/*of Intelligence*/
+I:1:25:4:KNOWLEDGE },/*of Wisdom*/
+I:1:26:4:KNOWLEDGE },/*of Beauty*/
+I:1:27:12:KNOWLEDGE },/*of the Magi*/
+I:1:28:12:EXPLOSION },/*of Might*/
+I:1:29:4:MANA },/*of Lordliness*/
+I:1:30:8:KNOWLEDGE },/*of Seeing*/
+I:1:31:1:LITE },/*of Infravision*/
+I:1:32:1:LITE },/*of Light*/
+I:1:33:8:KNOWLEDGE },/*of Telepathy*/
+I:1:34:4:LIFE },/*of Regeneration*/
+I:1:35:4:TELEPORT },/*of Teleportation*/
+I:1:40:8:EXPLOSION },/*Dwarven*/
+I:1:40:8:FIRE },/*Dwarven*/
+I:1:40:8:LIFE },/*Dwarven*/
+I:1:40:8:LITE },/*Dwarven*/
+I:1:40:8:MANA },/*Dwarven*/
+I:1:41:4:FORCE },/*of Protection*/
+I:1:42:4:DARKNESS },/*of Stealth*/
+I:1:43:4:ACID },/*of Aman*/
+I:1:43:4:COLD },/*of Aman*/
+I:1:43:4:DARKNESS },/*of Aman*/
+I:1:43:4:FIRE },/*of Aman*/
+I:1:43:4:LIGHTNING },/*of Aman*/
+I:1:44:8:FIRE },/*of Immolation*/
+I:1:48:8:LIGHTNING },/*of Electricity*/
+I:1:49:1:FORCE },/*of Free Action*/
+I:1:50:4:FORCE },/*of Slaying*/
+I:1:50:4:LITE },/*of Slaying*/
+I:1:51:4:LIGHTNING },/*of Agility*/
+I:1:52:4:EXPLOSION },/*of Power*/
+I:1:54:2:DARKNESS },/*of Charming*/
+I:1:57:3:DARKNESS },/*of Levitation*/
+I:1:58:3:DARKNESS },/*of Stealth*/
+I:1:59:3:DARKNESS },/*of Free Action*/
+I:1:60:5:TIME },/*of Speed*/
+I:1:61:2:DARKNESS },/*of Dwarvish Endurance*/
+I:1:61:2:EXPLOSION },/*of Dwarvish Endurance*/
+I:1:65:4:ACID },/*of Aman*/
+I:1:65:4:COLD },/*of Aman*/
+I:1:65:4:DARKNESS },/*of Aman*/
+I:1:65:4:FIRE },/*of Aman*/
+I:1:65:4:LIGHTNING },/*of Aman*/
+I:1:66:1:MAGIC },/*(Defender)*/
+I:1:66:4:ACID },/*(Defender)*/
+I:1:66:4:COLD },/*(Defender)*/
+I:1:66:4:FIRE },/*(Defender)*/
+I:1:66:4:LIGHTNING },/*(Defender)*/
+I:1:67:8:KNOWLEDGE },/*Blessed*/
+I:1:68:12:LIFE },/*of Greater Life*/
+I:1:68:2:MAGIC },/*of Greater Life*/
+I:1:69:4:DARKNESS },/*of Westernesse*/
+I:1:69:4:EXPLOSION },/*of Westernesse*/
+I:1:69:4:LIGHTNING },/*of Westernesse*/
+I:1:69:4:LITE },/*of Westernesse*/
+I:1:70:2:TIME },/*of Extra Attacks*/
+I:1:71:4:FORCE },/*of Slaying*/
+I:1:71:4:LITE },/*of Slaying*/
+I:1:72:4:EXPLOSION },/*of Spinning*/
+I:1:72:4:LIGHTNING },/*of Spinning*/
+I:1:73:4:ACID },/*Acidic*/
+I:1:74:4:LIGHTNING },/*Shocking*/
+I:1:75:4:FIRE },/*Fiery*/
+I:1:76:4:COLD },/*Frozen*/
+I:1:77:4:POISON },/*Venomous*/
+I:1:78:4:CHAOS },/*Chaotic*/
+I:1:79:4:FORCE },/*Sharp*/
+I:1:80:4:FORCE },/*of Earthquakes*/
+I:1:81:8:CHAOS },/*of Slay Animal*/
+I:1:82:8:CHAOS },/*of Slay Evil*/
+I:1:83:8:CHAOS },/*of Slay Undead*/
+I:1:84:8:CHAOS },/*of Slay Demon*/
+I:1:85:8:CHAOS },/*of Slay Orc*/
+I:1:86:8:CHAOS },/*of Slay Troll*/
+I:1:87:8:CHAOS },/*of Slay Giant*/
+I:1:88:8:CHAOS },/*of Slay Dragon*/
+I:1:89:12:CHAOS },/*of *Slay Animal**/
+I:1:90:12:CHAOS },/*of *Slay Evil**/
+I:1:91:12:CHAOS },/*of *Slay Undead**/
+I:1:92:12:CHAOS },/*of *Slay Demon**/
+I:1:93:12:CHAOS },/*of *Slay Orc**/
+I:1:94:12:CHAOS },/*of *Slay Troll**/
+I:1:95:12:CHAOS },/*of *Slay Giant**/
+I:1:96:12:CHAOS },/*of *Slay Dragon**/
+I:1:97:8:LIFE },/*Vampiric*/
+I:1:98:4:MAGIC },/*(*Defender*)*/
+I:1:98:8:ACID },/*(*Defender*)*/
+I:1:98:8:COLD },/*(*Defender*)*/
+I:1:98:8:FIRE },/*(*Defender*)*/
+I:1:98:8:LIGHTNING },/*(*Defender*)*/
+I:1:98:8:POISON },/*(*Defender*)*/
+I:1:99:12:TELEPORT },/*of the Thunderlords*/
+I:1:100:12:KNOWLEDGE },/*of Gondolin*/
+I:1:100:1:MAGIC },/*of Gondolin*/
+I:1:101:1:FORCE },/*of Digging*/
+I:1:102:12:LIFE },/*Spectral*/
+I:1:102:4:MANA },/*Spectral*/
+I:1:105:1:LITE },/*of Accuracy*/
+I:1:106:2:FORCE },/*of Power*/
+I:1:107:2:FORCE },/*of Extra Might*/
+I:1:108:1:FORCE },/*of Extra Shots*/
+I:1:108:1:LITE },/*of Extra Shots*/
+I:1:108:1:TIME },/*of Extra Shots*/
+I:1:109:2:FORCE },/*of Lothlorien*/
+I:1:109:2:LITE },/*of Lothlorien*/
+I:1:110:2:FORCE },/*of the Haradrim*/
+I:1:110:2:LITE },/*of the Haradrim*/
+I:1:111:2:FORCE },/*of Buckland*/
+I:1:111:2:LITE },/*of Buckland*/
+I:1:112:1:CHAOS },/*of Slay Animal*/
+I:1:113:1:CHAOS },/*of Slay Evil*/
+I:1:114:1:CHAOS },/*of Slay Undead*/
+I:1:115:1:POISON },/*of Venom*/
+I:1:116:1:ACID },/*of Acid*/
+I:1:117:12:ACID },/*Elemental*/
+I:1:117:12:COLD },/*Elemental*/
+I:1:117:12:FIRE },/*Elemental*/
+I:1:117:12:LIGHTNING },/*Elemental*/
+I:1:117:12:POISON },/*Elemental*/
+I:1:118:1:CHAOS },/*of Slay Demon*/
+I:1:119:1:CHAOS },/*of Slay Dragon*/
+I:1:120:1:FORCE },/*of Slaying*/
+I:1:120:1:LITE },/*of Slaying*/
+I:1:121:1:LIGHTNING },/*of Lightning*/
+I:1:121:1:LITE },/*of Lightning*/
+I:1:122:1:FIRE },/*of Flame*/
+I:1:122:1:LITE },/*of Flame*/
+I:1:123:1:COLD },/*of Frost*/
+I:1:123:1:LITE },/*of Frost*/
+I:1:124:1:LIFE },/*of Wounding*/
+I:1:128:2:ACID },/*of the Eldar*/
+I:1:128:2:DARKNESS },/*of the Eldar*/
+I:1:129:2:ACID },/*of Power*/
+I:1:129:2:COLD },/*of Power*/
+I:1:129:2:DARKNESS },/*of Power*/
+I:1:129:2:FIRE },/*of Power*/
+I:1:129:2:LIGHTNING },/*of Power*/
+I:1:130:1:MANA },/*Dragon*/
+I:1:131:1:MANA },/*Capacity of */
+I:1:132:1:LIFE },/*Cheapness of */
+I:1:133:1:TIME },/*Quickness of */
+I:1:134:1:TIME },/*Charging of */
+I:1:135:3:LIFE },/*the Istari of */
+I:1:135:3:MANA },/*the Istari of */
+I:1:135:3:TIME },/*the Istari of */
+I:1:136:1:LITE },/*of Boldness*/
+I:1:137:1:LITE },/*of Fearlessness*/
+I:1:138:2:LITE },/*of Illumination*/
+I:1:139:2:LITE },/*of Brightness*/
+I:1:140:4:LITE },/*of *Brightness**/
+I:1:141:4:DARKNESS },/*of the Shadows*/
+I:1:141:4:LITE },/*of the Shadows*/
+I:1:142:4:DARKNESS },/*of Infravision*/
+I:1:142:4:LITE },/*of Infravision*/
+I:1:143:8:DARKNESS },/*of the Eternal Eye*/
+I:1:144:4:MANA },/*of the Ethereal Eye*/
+I:1:146:4:DARKNESS },/*Dwarven*/
+I:1:146:4:EXPLOSION },/*Dwarven*/
+I:1:146:4:LITE },/*Dwarven*/
+I:1:147:1:MAGIC },/*Indestructible*/
+I:1:147:4:ACID },/*Indestructible*/
+I:1:147:4:COLD },/*Indestructible*/
+I:1:147:4:FIRE },/*Indestructible*/
+I:1:147:4:LIGHTNING },/*Indestructible*/
+I:1:147:4:MANA },/*Indestructible*/
+I:1:149:1:FIRE },/*Fireproof*/
+I:1:163:3:DARKNESS },/*of the Magi*/
+I:1:163:3:KNOWLEDGE },/*of the Magi*/
+I:1:163:3:MANA },/*of the Magi*/
+I:1:166:4:MAGIC },/*of Preservation*/
+I:1:166:4:MANA },/*of Preservation*/
+I:1:167:12:MANA },/*of Serenity*/
+I:1:168:4:DARKNESS },/*of Night and Day*/
+I:1:168:4:LITE },/*of Night and Day*/
+I:1:169:1:TIME },/*of the Magi*/
+I:1:169:8:KNOWLEDGE },/*of the Magi*/
+I:1:170:4:DARKNESS },/*of Invisibility*/
+I:1:171:8:DARKNESS },/*of the Bat*/
+I:1:171:8:TELEPORT },/*of the Bat*/
+I:1:172:4:LIGHTNING },/*of Thievery*/
+I:1:173:4:FORCE },/*of Combat*/
+I:1:174:4:TELEPORT },/*of Stability*/
+I:1:175:4:ACID },/*of Elvenkind*/
+I:1:175:4:COLD },/*of Elvenkind*/
+I:1:175:4:FIRE },/*of Elvenkind*/
+I:1:175:4:LIGHTNING },/*of Elvenkind*/
+I:1:176:1:MAGIC },/*of Fury*/
+I:1:176:4:CHAOS },/*of Fury*/
+I:1:176:4:EXPLOSION },/*of Fury*/
+I:1:176:4:MANA },/*of Fury*/
+I:1:178:8:FORCE },/*Magical*/
+I:1:179:4:KNOWLEDGE },/*Simplicity of */
+I:1:180:1:FIRE },/*of Warmth*/
+I:1:185:12:LIFE },/*of Life*/
+I:1:185:2:MAGIC },/*of Life*/
diff --git a/lib/edit/ba_info.txt b/lib/edit/ba_info.txt
new file mode 100644
index 00000000..8156fd2f
--- /dev/null
+++ b/lib/edit/ba_info.txt
@@ -0,0 +1,283 @@
+# File: ba_info.txt
+
+
+# This file is used to initialize the "lib/raw/ba_info.raw" file, which is
+# used to initialize the "store/building actions type" information for
+# the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# N:<index>:<name>
+# C:<hated cost>:<normal cost>:<liked cost>
+# I:<action>:<acttion restriction>:<letter>
+
+# Restriction:
+# 0 = No restrictions
+# 1 = Restrict to normal & liked
+# 2 = Restrict to liked
+
+# Version stamp (required)
+
+V:2.0.0
+
+N:0:Nothing
+C:0:0:0
+I:0:0:.
+
+N:1:Sell an item
+C:0:0:0
+I:43:0:s:d
+
+N:2:Purchase an item
+C:0:0:0
+I:44:0:p:g
+
+N:3:Examine an item
+C:0:0:0
+I:45:0:x
+
+N:4:Steal an item
+C:0:0:0
+I:46:0:Z
+
+N:5:Rest for the night
+C:25:20:15
+I:17:0:r
+
+N:6:Buy food and drink
+C:3:2:1
+I:18:0:f
+
+N:7:Listen for rumours
+C:0:0:0
+I:19:0:u
+
+N:8:Presage fate
+C:600:500:480
+I:42:0:l
+
+N:9:In-Between
+C:0:0:0
+I:12:0:b
+
+N:10:Play craps
+C:0:0:0
+I:14:0:c
+
+N:11:Spin the wheel
+C:0:0:0
+I:15:0:s
+
+N:12:Play dice slots
+C:0:0:0
+I:16:0:d
+
+N:13:Game rules
+C:0:0:0
+I:13:0:r
+
+N:14:Research item
+C:1400:1300:1200
+I:1:0:a
+
+N:15:Town history
+C:0:0:0
+I:2:0:h
+
+N:16:Race legends
+C:0:0:0
+I:3:0:l
+
+N:17:Look at busts of Kings
+C:0:0:0
+I:5:0:l
+
+N:18:Research monster
+C:1600:1500:1400
+I:20:0:r
+
+N:19:View bounties
+C:0:0:0
+I:38:0:v
+
+N:20:Receive bounty money
+C:0:0:0
+I:39:0:b
+
+N:21:Get quest monster
+C:0:0:0
+I:54:0:q
+
+N:22:Turn in quest corpse
+C:0:0:0
+I:55:0:m
+
+N:23:Compare weapons
+C:220:200:180
+I:21:0:c
+
+N:24:Enchant weapon
+C:750:700:150
+I:23:0:w
+
+N:25:Enchant armour
+C:750:700:150
+I:24:0:a
+
+N:26:Recharge item
+C:350:300:75
+I:25:0:r
+
+N:27:Identify possessions
+C:900:800:100
+I:26:0:i
+
+N:28:Healing prayer
+C:600:400:0
+I:28:0:h
+
+N:29:Restoration
+C:600:500:100
+I:29:0:r
+
+N:30:Get share of stolen gold
+C:0:0:0
+I:7:2:g
+
+N:31:Enchant arrows
+C:550:500:100
+I:30:0:a
+
+N:32:Enchant bow
+C:550:500:100
+I:31:0:b
+
+N:33:Recall to dungeon
+C:300:200:100
+I:33:0:r
+
+N:34:Teleport to dungeon-level
+C:15000:10000:1000
+I:34:0:t
+
+N:35:Get a quest
+C:0:0:0
+I:6:0:q
+
+# Restrict to liked/normal
+N:36:Get a quest
+C:0:0:0
+I:46:1:q
+
+N:37:Get a quest
+C:0:0:0
+I:47:0:q
+
+N:38:Get a quest
+C:0:0:0
+I:49:0:q
+
+N:39:Herbal Healing
+C:32000:10000:0
+I:50:0:h
+
+N:40:Song of Lore
+C:2000:800:50
+I:26:0:s
+
+N:41:Distribute earnings
+C:0:0:0
+I:7:2:d
+
+N:42:Morph restoration
+C:3000:1500:750
+I:37:0:r
+
+#for The Mirror
+N:43:View fate
+C:500:500:500
+I:42:0:v
+
+#for The Mirror
+N:44:Research item
+C:1500:1500:1500
+I:1:0:a
+
+#for library in gondol
+N:45:Research item
+C:2000:2000:2000
+I:1:0:a
+
+#for Star-Dome
+N:46:Identify possessions
+C:1200:1000:250
+I:26:0:i
+
+#for Star-Dome
+N:47:Recharge item
+C:1200:1000:150
+I:25:0:r
+
+#for Valarin Temple
+N:48:Restoration
+C:1200:1000:200
+I:29:0:r
+
+#for Sea-Dome
+N:49:Morph restoration
+C:1500:1500:1500
+I:37:0:r
+
+#for The Golden Flower
+N:50:Enchant arrows
+C:1100:1000:200
+I:30:0:a
+
+#for The Golden Flower
+N:51:Enchant bow
+C:1100:1000:200
+I:31:0:b
+
+#for The Fountain
+N:52:Enchant armour
+C:1100:1000:200
+I:24:0:a
+
+#for The Fountain
+N:53:See Healers
+C:1100:1000:0
+I:28:0:h
+
+N:54:Drop an item
+C:0:0:0
+I:43:0:d:s
+
+N:55:Get an item
+C:0:0:0
+I:44:0:g:p
+
+N:56:Request an item
+C:0:0:0
+I:51:2:r
+
+N:57:Ask for loan
+C:0:0:0
+I:52:2:a
+
+N:58:Pay back loan
+C:0:0:0
+I:53:2:p
+
+N:59:Donate an item
+C:0:0:0
+I:43:0:d
+
+# Mage Tower quest in Lothlorien
+N:60:Get a quest
+C:0:0:0
+I:56:0:q
+
+N:61:Get a quest
+C:0:0:0
+I:61:0:q
diff --git a/lib/edit/between.map b/lib/edit/between.map
new file mode 100644
index 00000000..1458cdb7
--- /dev/null
+++ b/lib/edit/between.map
@@ -0,0 +1,71 @@
+# Created by Mynstral (mynstral@thehelm.com)
+# Made for PernAngband on 14/08/2001
+
+# Monsters starts awake
+N:0
+
+# Permanent wall
+F:X:63:3
+
+# Floor with dirt
+F:.:88:3
+
+# Floor with grass
+F:,:89:3
+
+# Tree
+F:T:96:3
+
+# Floor with grass with a green thunderlord
+F:G:89:5:955
+
+# Floor with grass with a blue thunderlord
+F:L:89:5:956
+
+# Floor with grass with a brown thunderlord
+F:B:89:5:957:0:0:0:0:0:0:2
+
+# Floor with grass with a bronze thunderlord
+F:z:89:5:958:0:0:0:0:0:0:2
+
+# Floor with dirt with a bronze thunderlord
+F:Z:88:5:958:0:0:0:0:0:0:2
+
+# Floor with dirt with a gold thunderlord
+F:D:88:5:959:0:0:0:0:0:0:2
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X..T.TT..T...T...T...T.....T....T......T...T.,,.....T......T....T...T.T..T..TT...T..T.TT.T.TT.TX
+D:X.T.TTTTT...T..TT..T..T.T.T.T...T.....T..T.TT,,..T...T.....T..T......T..T.T..T.T.TT.T.T.T..TTT.X
+D:XTTT.T.T.T.T..TTT.T.T.TTT.T.T.T..T..T.T..T..T.,,..T....T....T..T.T.T..T.T..T.T.TT.T.TT.TT.TTT.TX
+D:XTTT.T...T....T....T..T.TT..T.T.T...T...GG....,,...GG....T...T...T.TTT.T..TTTT.TT...T.TT..T.T.TX
+D:X.TTT..T.T..TTTT.T.T..T..T.TT...T......G..L..,,...L..G..T..T.T...T....T.TTTTTT..TTTTT.T..TT..T.X
+D:XTT.T.TTT.T.T.T.T.T.T.T...T..T...T..T.G..L..B,,.B..L..G....T..T...TT.T.T..TTT.T.TTTT.TTTT..T.T.X
+D:X.T.TT..T.TT.TTT.T.T.T.T.T.T...T.T.T.G..L..B.,,..B..L..G..T..T...T...T.T.T..TTTT.T.T.TT.T.T.TT.X
+D:X.TT.T.TTT.T.T.T.T..T.T..T....T..T..G..L..B..,Z...B..L..G..T...T.T..T...T...T.T.T.TTT.T.T.T..T.X
+D:XT.T.TT.TTTT.TT.T.TTT...T.T.T...T.T.G..L..B..ZDz..B..L..G...T.T...T.T...T..T..T...T..T.TT.T.T.TX
+D:XTTT..TTTT.T.T.T..T.T....T...T..T.T..G..L..B.,,..B..L..G..T....T...T....T....T..T..TT.T.T.TTT..X
+D:XTT.TT..T.T.T.T.T...T...T....T.T..T.T.G..L...,,....L..G..T..T...T..T.......T...T....T..T..TT...X
+D:XTTT.T..T.T..T.T..T...T..T....TT..T.T..GG....,,.....GG...T.T...T.T...T..T.T...T....T...T..T.T..X
+D:XTT...T.T..T....T....T....T....T...T....T.T..,,,.....T...T..T...T.....T...T...T..T..T...T..T.T.X
+D:XT..T.T...T...T...T.....T....T....T....T...TTTTTTTT...T...T...T....T.....T......T....T.....T..TX
+D:XT.T...T...T..T.T...T.T.T..T...T.T...T...T.T...,.T...T...T...T...T..T.....T....T....T...T...T.TX
+D:XTT.T.T.T.T..T..T.T.T.....T....T..T...T.......,,..T........T...T...T...T...T.....T..T..T...TTT.X
+D:X..TT...T..T.....T...T....T...T...T...T..T...,,.....T..T..T.....T.T...T...T...T..T..T.T...T.TT.X
+D:X.TT..T....T.T..T...T..T...T..T.T.T..T..T.T.,,..T..T..T....T..T..T...T.T....T....T...TT.TTTTTT.X
+D:X.T.TTTTTT.T.T.T...T..T..T.....T.T..T...T.T.,,...T...T......T.....T....T...T..T....T..TT.TTTTTTX
+D:XTTT.T.T.TTTTT.TTT...T..T...TT.T.T...T.T....,,.T...T.....T.....T....T.......T..T...T.TT.T.T.TT.X
+D:XTT.T..T.TT.T.T.TT.T...T.T..T.T.......T..T.,,.....T....T....T...........T..T...TT.TTTTTTTTTTTTTX
+D:XTTTT....TT.T.T.TTTTT.T...T..T.T..T......T.,,T......T....T....T.....T...T...T..TTTT.T.TT.T.TTTTX
+D:XTT.TTTTTT.T.TT.TTTTTT...T....TT.T...T....,,.T...T....T.....T....T....T....T..TT.T.TTT.T.T.T.TTX
+D:XTT.T..TTT.T.T.TTTTTTTT.T...T....T....T.T,,.........T....T....T....T...T.T.T.TTT.T.T.T.T..T.T.TX
+D:XTT.T..TTT..T.T.T.T.TT..T.T.T......T.T.T.,,..T...T...T...T..T...T...T.T.TTT.T.T.T.T.T.T.T.T..T.X
+D:X.T.T.T.T.T.T..T.T.T.T.T.T..T...T..T.TT.T.,,..T...T.....T.....T.....T..TTT.T.T.TTTTT.T.TTT.TT.TX
+D:XTT.T.T.T.TTTT.T..T.T.T.TTTT.T..T.T..T.TT.,,.T...T..T..T.......T.T....TTTTT.TTTT.T.TTT.TTTT.T.TX
+D:XT.T.TT.TTTT.T.T.T.TTT.T.T.TT......T...T...,,..T...T...T....T....T.TTT.T.T.T.T.T.T..T.T.T.T.TT.X
+D:XT.TTT.T.T.TTTT.T.T.T.T.TTT.TT..T...T...T..,,..T...T....T....T..TT.T.TT.TTTTT.T.T.TT.TT.TT.T.T.T
+D:XTT.T.T.TT.T.TTTT.T..TT.T.T.TT.T.T.T..T....,,.T...T...T....T..TTTTTTTT.T.T.T.T.T.TT.T.TTTTT.T.TX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:17:47
diff --git a/lib/edit/d_info.txt b/lib/edit/d_info.txt
new file mode 100644
index 00000000..59a1e6f2
--- /dev/null
+++ b/lib/edit/d_info.txt
@@ -0,0 +1,512 @@
+# File: d_info.txt
+
+
+# This file is used to initialize the "lib/raw/d_info.raw" file, which is
+# used to initialize the "dungeon type" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# Some store indexes are defined in "defines.h", and must not be
+# changed.
+
+# N:<index>:<name>
+# D:<3 letter short name>:<long name>
+# W:<min depth>:<max depth>:<min player level>:<next dungeon>:<min alloc>:<max alloc chance>
+# L:<floor1>:<%1>:<floor2>:<%2>:<floor3>:<%3>
+# A:<wall1>:<%1>:<wall2>:<%2>:<wall3>:<%3>:<outer wall>:<inner wall>
+# O:<%treasure>:<%combat>:<%magic>:<%tools>
+# E:<dices>d<sides>:<frequency>:<attack type>
+# F:<flags>
+# R:<percent>:<flags mode>
+# M:<monster flags>
+# S:<monster spells>
+
+# Note for <flags mode> :
+# 0 = No restriction
+# 1 = AND
+# 2 = NAND
+# 3 = OR
+# 4 = NOR
+
+# Version stamp (required)
+
+V:2.0.0
+
+### Wilderness(purely cosmetic, never used) ###
+
+N:0:Wilderness
+D:Wil:a way to the Wilderness
+W:0:0:0:0:14:500
+L:89:80:199:20:1:0
+A:96:100:56:0:56:0:57:58
+O:20:20:20:20
+F:PRINCIPAL | FLAT | NO_RECALL
+R:100:0
+
+### The principal dungeons, they were created by spliting the vanilla dungeon ###
+
+N:1:Mirkwood
+D:Mkw:a way to the Mirkwood Forest.
+W:11:33:5:0:14:160
+L:89:95:199:5:88:0
+A:96:100:97:0:56:0:202:96
+O:20:20:20:20
+F:PRINCIPAL | NO_DOORS | NO_DESTROY | FLAT
+F:FILL_METHOD_0
+R:100:0
+
+N:2:Mordor
+D:Mdr:a door to the Land of Mordor.
+W:34:66:15:0:14:160
+L:88:67:93:33:1:0
+L:0:100:0
+A:97:50:56:50:56:0:57:97
+A:0:100:0
+O:20:20:20:20
+F:PRINCIPAL | LAVA_RIVER | CAVERN | NO_STREAMERS
+F:FILL_METHOD_2
+R:100:0
+
+N:3:Angband
+D:Ang:an entrance to the Pits of Angband.
+W:67:127:30:0:14:160
+L:1:100:1:0:1:0
+A:56:100:56:0:56:0:57:58
+O:20:20:20:20
+F:PRINCIPAL | CAVERN | NO_EASY_MOVE | NO_RECALL
+F:ADJUST_LEVEL_1_2 | ADJUST_LEVEL_1
+F:FILL_METHOD_0
+R:100:0
+
+N:4:Barrow-Downs
+D:BDw:a way to the Barrow-Downs.
+W:1:10:1:0:14:160
+L:88:78:89:18:199:4
+L:0:95:5
+A:96:34:97:66:56:0:57:97
+A:100:0:0
+O:20:20:20:20
+F:PRINCIPAL | FLAT
+F:FILL_METHOD_3
+R:25:1
+M:UNDEAD
+R:75:0
+
+# The Additional dungeons
+
+# Mount Doom
+# Levels 85-99
+N:5:Mount Doom
+D:MDm:a way to the top of the Mount Doom.
+W:85:99:18:0:14:160
+L:86:90:205:10:1:0
+A:177:100:0:0:0:0:85:87
+O:10:10:30:30
+E:2d10:10:FIRE
+F:CAVE | LAVA_RIVER | NO_RECALL | NO_STREAMERS | NO_UP
+F:FILL_METHOD_0 | NO_EASY_MOVE
+R:100:1
+M:IM_FIRE
+
+# Nether Realm
+# Levels 666-696 (!!!)
+# guarded by Tik'srvzllat, who has the Ring of Phasing
+N:6:Nether Realm
+D:Nth:a magical portal to the Nether Realm.
+W:666:696:40:0:14:160
+L:102:80:86:15:85:5
+A:85:80:87:20:87:0:57:85
+A:50:50:0
+O:25:25:25:25
+E:10d10:3:NETHER
+F:EMPTY | FORGET | NO_BREATH | NO_EASY_MOVE | NO_SHAFT
+F:RANDOM_TOWNS | ADJUST_LEVEL_2 | NO_RECALL | NO_STREAMERS
+F:LAVA_RIVER | FINAL_GUARDIAN_1032 | FINAL_ARTIFACT_203
+F:FILL_METHOD_2 | NO_RECALL_OUT | NO_UP
+R:5:0
+R:95:3
+M:RES_NETH | R_CHAR_G | R_CHAR_W | R_CHAR_U
+
+# The Lost Land of Numenor
+# levels 35-50
+# guarded by Ar-Pharazon the Golden, who has the stone "Toris Mejistos".
+N:7:Submerged Ruins
+D:Num:a submerged way to the lost land of Numenor.
+W:35:50:25:0:14:160
+L:84:95:187:5:1:0
+A:187:80:84:10:56:10:57:187
+A:60:0:40
+O:30:30:10:10
+E:1d1:1:ACID
+F:NO_STREAMERS
+F:FINAL_GUARDIAN_980 | FINAL_ARTIFACT_204
+F:FILL_METHOD_3 | WATER_BREATH
+R:20:0
+R:80:3
+M:AQUATIC | CAN_SWIM | CAN_FLY
+
+# Used for astral mode
+N:8:Halls of Mandos
+D:HMa:*A BUG*YOU should see this message!*
+W:1:98:1:0:14:160
+L:1:100:1:0:1:0
+O:20:20:20:20
+A:56:100:56:0:56:0:57:58
+F:RANDOM_TOWNS | NO_RECALL | NO_SHAFT
+F:FILL_METHOD_0
+R:100:2
+M:UNIQUE
+
+# Cirith Ungol
+# levels 25-50
+# guarded by Shelob.
+N:9:Cirith Ungol
+D:CUg:an entrance to Cirith Ungol.
+W:25:50:10:0:14:160
+L:87:5:88:65:16:30
+A:97:90:16:10:56:0:16:58
+O:30:30:30:10
+E:4d4:20:POISON
+F:FINAL_GUARDIAN_481
+F:CIRCULAR_ROOMS
+F:FILL_METHOD_2
+R:2:0
+R:49:3
+M:SPIDER | R_CHAR_c | R_CHAR_a | R_CHAR_I |
+R:49:3
+M:ORC | R_CHAR_w | R_CHAR_m | R_CHAR_j
+
+# The Heart of the Earth
+# levels 25-36
+# guarded by Golgarach, the Living Rock
+N:10:Heart of the Earth
+D:HoE:a passage leading into the very heart of the world.
+W:25:36:10:0:14:160
+L:1:100:1:0:1:0
+A:56:100:56:0:56:0:57:58
+O:40:10:10:20
+G:life
+F:EVOLVE | FINAL_GUARDIAN_1035 | NO_RECALL | NO_SHAFT | NO_UP
+R:40:3
+M:R_CHAR_# | R_CHAR_X | R_CHAR_g | R_CHAR_E |
+R:30:3
+M:PASS_WALL | KILL_WALL | HURT_ROCK
+R:30:0
+
+# The Void
+# Levels 128-150
+# Where Melkor lurks for the final battle!
+N:11:The Void
+D:Vod:a jumpgate to the Void
+W:128:150:40:0:20:160
+L:183:97:102:3:0:0
+A:183:90:102:10:0:0:102:102
+A:40:60:0
+O:25:25:25:25
+E:20d6:100:DARK
+F:EMPTY | FORGET | NO_BREATH | NO_EASY_MOVE | NO_RECALL_OUT | NO_RECALL |
+F:ADJUST_LEVEL_1_2 | ADJUST_LEVEL_1 | NO_STREAMERS | NO_SHAFT
+F:FILL_METHOD_2
+F:FINAL_GUARDIAN_1044 |
+R:1:0
+R:99:3
+M:UNDEAD | DEMON | DRAGON | NONLIVING | SPIRIT
+
+# TEST dungeon
+N:12:Test
+D:Tst:a way to test dungeon gen
+W:1:10:1:0:14:160
+L:88:78:89:18:199:4
+L:0:95:5
+A:177:100:0:0:0:0:85:87
+A:100:0:0
+O:20:20:20:20
+F:FILL_METHOD_3 | SMALL
+R:100:0
+G:dungeon2
+
+
+# The Paths of the Dead
+# levels 40-70
+# Feagwath is there, guarding Doomcaller
+N:16:Paths of the Dead
+D:PoD:the entrance to the Paths of the Dead.
+W:40:70:18:0:24:100
+L:88:85:84:15:1:0
+A:56:75:87:25:56:0:57:58
+O:30:30:30:2
+E:1d1:20:RAISE
+F:FINAL_GUARDIAN_804 | FINAL_ARTIFACT_91
+F:FILL_METHOD_3
+R:5:0
+R:10:3
+M:R_CHAR_p
+R:85:3
+M:UNDEAD | NONLIVING
+
+# The Illusory Castle
+# levels 35-52
+# Guarded by The Glass Golem guarding The Helm of Knowledge
+N:17:Illusory Castle
+D:Ill:an entrance to the Illusory Castle.
+W:35:52:10:0:24:100
+L:1:98:188:2:1:0
+A:56:50:189:50:56:0:57:58
+O:50:10:20:20
+E:6d2:6:CONFUSION
+F:RANDOM_TOWNS | NO_STREAMERS
+F:FINAL_GUARDIAN_1033 | FINAL_ARTIFACT_160
+F:FILL_METHOD_1
+R:30:0
+R:70:3
+M:STUPID | WEIRD_MIND | SHAPECHANGER | ATTR_MULTI | CHAR_MULTI | RAND_25 |
+M:RAND_50 | EMPTY_MIND | INVISIBLE | PASS_WALL | KILL_WALL
+S:BR_CONF | BR_CHAO | BA_CHAO | CONF | FORGET | TRAPS | MULTIPLY
+
+# The Maze
+# Levels 25-37
+# Guarded by The Minotaur of the Labyrinth with the Steel Helm of Hammerhand
+N:18:Maze
+D:Maz:a small tunnel leading to a maze of twisty little passages, all alike.
+W:25:37:15:0:20:160
+L:1:100:1:0:1:0
+A:56:98:48:2:56:0:57:58
+O:2:40:10:40
+G:maze
+F:SMALLEST | FORGET
+F:FINAL_GUARDIAN_1029 | FINAL_ARTIFACT_38
+R:80:0
+R:20:3
+M:R_CHAR_p
+
+# The Orc Cave
+# levels 10-22
+# There is Azog with the Wand of Thrain at the bottom
+N:19:Orc Cave
+D:Orc:a dark tunnel leading to an Orc Cave.
+W:10:22:8:0:35:200
+L:88:100:1:0:1:0
+A:97:100:56:0:56:0:57:97
+O:5:50:10:25
+F:RANDOM_TOWNS |
+F:FINAL_OBJECT_810 | FINAL_GUARDIAN_373 | CAVE |
+F:FILL_METHOD_0
+R:30:3
+M:TROLL
+R:20:0
+R:50:3
+M:ORC | R_CHAR_k | R_CHAR_o | R_CHAR_O
+
+# Erebor
+# levels 60-72
+# There is Glaurung
+N:20:Erebor
+D:Ere:a tunnel leading into depths of the Lonely Mountain.
+W:60:72:35:0:20:140
+L:88:100:1:0:1:0
+A:97:90:87:10:56:0:57:97
+O:40:40:40:40
+F:BIG | LAVA_RIVER | CAVERN | NO_RECALL | NO_STREAMERS
+F:CAVE | DOUBLE | FINAL_GUARDIAN_715 |
+F:FILL_METHOD_2
+R:10:0
+R:60:1
+M:DRAGON | R_CHAR_D
+R:30:1
+M:DRAGON | R_CHAR_d
+
+# The Old Forest
+# levels 13-25
+# Old Man Willow protects it
+N:21:The Old Forest
+D:OFr:a path into the Old Forest.
+W:13:25:5:0:15:100
+L:88:76:84:16:199:8
+L:68:16:16
+A:96:100:56:0:56:0:202:96
+O:20:5:15:30
+F:WATER_RIVERS | NO_DOORS | NO_DESTROY | FLAT | NO_STREAMERS
+F:RANDOM_TOWNS | FINAL_GUARDIAN_206
+F:FILL_METHOD_3
+R:30:0
+R:40:3
+M:ANIMAL
+R:30:3
+M:UNDEAD | R_CHAR_h
+
+# The Mines of Moria
+# levels 30-50
+# There is Durin's Bane
+N:22:Moria
+D:MoM:a stone door leading to the Mines of Moria.
+W:30:50:20:0:40:40
+L:88:100:1:0:1:0
+A:97:100:56:0:56:0:57:97
+O:30:50:10:5
+F:FINAL_GUARDIAN_872 | WATER_RIVER | BIG | NO_STREAMERS
+F:FORCE_DOWN
+F:RANDOM_TOWNS
+F:WILD_45_30__44_37
+F:FILL_METHOD_0
+R:40:3
+M:ORC
+R:30:3
+M:TROLL | GIANT
+R:20:3
+M:DEMON
+R:10:0
+
+# The tower of Dol Guldur
+# Levels 57-70
+# The Necromancer (weak Sauron) at the bottom, with the Ring of Durin
+N:23:Dol Guldur
+D:TDG:a gate leading to the tower of Dol Guldur.
+W:57:70:34:0:24:160
+L:1:80:174:20:1:0
+A:56:100:56:0:56:0:57:58
+O:20:1:70:9
+F:SMALL | FINAL_GUARDIAN_819 | FINAL_ARTIFACT_205
+F:FILL_METHOD_3
+R:30:3
+M:R_CHAR_p | R_CHAR_P
+R:10:3
+M:ORC | TROLL
+R:20:3
+M:UNDEAD
+R:30:3
+M:DEMON | DRAGON
+R:10:0
+
+# Dungeons from Variaz
+
+# The Small Water Cave
+# levels 32-34
+# The Watcher in the Water is at the bottom
+N:24:The Small Water Cave
+D:SWC:the entrance to a small water cave.
+W:32:34:20:0:14:160
+L:84:100:84:0:84:0
+A:97:100:56:0:56:0:57:58
+O:10:10:30:30
+E:1d1:20:ACID
+F:FINAL_GUARDIAN_517 | NO_RECALL | NO_UP
+F:FILL_METHOD_0
+R:10:0
+R:10:3
+M:AQUATIC
+R:40:1
+M:IM_COLD
+S:BA_WATE
+R:40:3
+M:IM_COLD
+
+# The Land of Mountains
+# Trone the rebel Thunderlord is hiding here, with his suit of
+# thunderlord armour.
+# Levels 45-70
+N:25:The Sacred Land Of Mountains
+D:LoM:the way to the Sacred Land of Mountains.
+W:45:70:20:0:14:160
+L:89:100:89:0:89:0
+A:97:100:56:0:56:0:97:97
+O:20:20:20:20
+F:RANDOM_TOWNS | FLAT | NO_STREAMERS
+F:FINAL_GUARDIAN_789 | FINAL_ARTIFACT_27
+F:FILL_METHOD_0
+R:60:3
+M:CAN_FLY
+R:40:0
+
+# The Land of Rhun
+# levels 26-40
+# Guarded by Ulfang the Black, Morgoth's first Easterling follower.
+N:26:The Land Of Rhun
+D:LoR:a way to the Land of Rhun.
+W:26:40:15:0:14:160
+L:89:100:1:0:1:0
+A:89:50:96:25:84:25:57:58
+O:20:20:20:20
+F:RANDOM_TOWNS | FLAT | NO_STREAMERS | FINAL_GUARDIAN_990
+F:FILL_METHOD_1
+R:30:3
+M:R_CHAR_p | R_CHAR_h
+R:30:3
+M:ANIMAL
+R:40:0
+
+# The Sandworm's Lair
+# level 22-30
+# guarded by the Sandworm Queen (and her children), who will drop her armour
+N:27:The Sandworm lair
+D:SwL:a sandhole.
+W:22:30:12:0:5:200
+L:91:85:94:10:93:5
+A:98:100:96:0:84:0:94:94
+O:15:5:60:20
+F:NO_DOORS | SAND_VEIN |
+F:FINAL_GUARDIAN_1030 | FINAL_ARTIFACT_153
+F:FILL_METHOD_0
+R:90:3
+M:R_CHAR_w
+R:10:3
+S:MULTIPLY
+
+# Used by the death fate
+N:28:Death fate
+D:Dth:a fated death.
+W:1:1:1:0:30:255
+L:1:100:1:0:1:0
+A:1:100:1:0:1:0:1:1
+O:1:1:1:1
+F:EMPTY | SMALLEST | NO_RECALL | NO_STREAMERS
+F:FILL_METHOD_0
+R:100:0
+
+# The Grinding Ice
+# levels 20-40
+# Guarded by the White Balrog
+N:29:The Helcaraxe
+D:Ice:the entrance to the Grinding Ice of the Helcaraxe.
+W:20:40:10:0:14:160
+L:90:0:88:70:84:30
+L:90:0:10
+A:95:0:56:100:56:0:57:58
+A:100:0:0
+O:20:20:20:20
+E:1d4:15:COLD
+F:DOUBLE | WATER_RIVER | CAVERN | NO_STREAMERS
+F:FINAL_GUARDIAN_1034 |
+F:FILL_METHOD_2
+R:100:1
+M:IM_COLD
+
+# The Lost Temple of "..player.pgod.."
+# Generated in god quest.
+# Most dungeon attributes altered during the quest.
+# See god.lua for details
+N:30:a lost temple
+D:LTm:the entrance to a lost temple.
+W:1:50:1:0:14:160
+L:1:100:1:0:1:0
+A:56:100:56:0:56:0:57:58
+O:20:20:20:20
+F:FILL_METHOD_4 | NO_RECALL
+R:100:0
+
+# N:<index>:<name>
+# D:<3 letter short name>:<long name>
+# W:<min depth>:<max depth>:<min player level>:<next dungeon>:<min alloc>:<max alloc chance>
+# L:<floor1>:<%1>:<floor2>:<%2>:<floor3>:<%3>
+# A:<wall1>:<%1>:<wall2>:<%2>:<wall3>:<%3>:<outer wall>:<inner wall>
+# O:<%treasure>:<%combat>:<%magic>:<%tools>
+# E:<dices>d<sides>:<frequency>:<attack type>
+# F:<flags>
+# R:<percent>:<flags mode>
+# M:<monster flags>
+# S:<monster spells>
+# 0 = No restriction
+# 1 = AND
+# 2 = NAND
+# 3 = OR
+# 4 = NOR
diff --git a/lib/edit/dragons.map b/lib/edit/dragons.map
new file mode 100644
index 00000000..164c97c8
--- /dev/null
+++ b/lib/edit/dragons.map
@@ -0,0 +1,43 @@
+# permanent wall
+F:X:61:0
+
+# Mountain Chain
+F:^:97:0
+
+# granite
+F:#:57:0
+
+# up staircase
+F:<:6:0
+
+# Dirt
+F:.:88:0
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:X^^^^^.....................^^^^^X
+D:X^^^.........................^^^X
+D:X^^...........................^^X
+D:X^^...........................^^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^^...........................^^X
+D:X^^...........................^^X
+D:X^^^........................<^^^X
+D:X^^^^^.....................^^^^^X
+D:X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:6:6
+
diff --git a/lib/edit/e_info.txt b/lib/edit/e_info.txt
new file mode 100644
index 00000000..f01d8cf7
--- /dev/null
+++ b/lib/edit/e_info.txt
@@ -0,0 +1,2210 @@
+# File: e_info.txt
+
+
+# This file is used to initialize the "lib/data/e_info.raw" file, which is
+# used to initialize the "ego-item" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/data/e_info.raw" file.
+
+# The ego-item indexes are defined in "defines.h", and must not be changed.
+
+# Note that every "ego-item" type has a different "index", and can only be
+# created from items that belong to a certain "slot" in the equipment, if
+# one assumes that "ammo" belongs to an imaginary slot (23). However, it
+# is possible for several "ego-item" types to have the same "textual name",
+# such as with "Armor of Resistance" and "Shield of Resistance".
+
+# === Understanding e_info.txt ===
+
+# N: serial number : ego type
+# D: description
+# T: tval : min sval : max sval
+# R: rarity
+# X: position : slot : rating
+# W: depth : rarity1 : rarity2 : cost
+# C: to-hit : to-dam : to-ac : pval
+# r:N:needed flags on the base object
+# r:F:forbidden flags on the base object
+# Z: granted_power
+# F: flags
+
+# 'N' indicated the beginning of an entry. The serial number must increase
+# for each new item.
+
+# 'D' contains description. This field is currently not supported.
+
+# 'T' is for possible tval and sval value of the base item.
+# Up to 5 entries are possible.
+
+# 'R' stands for rarity, or randomness. It specifies percentual chance
+# of generated item to have following 'F' flags. I.e. 'R:40' followed
+# by 'F:SPEED' means, that 40% of item of this ego type will boost speed.
+
+# 'X' is for extra information. Position value 'A' means that ego-type name
+# will appear after base-item name ('Robe of Permanence'), value 'B' means
+# that ego-type name will appear before base-item name ('Elven Plate Mail').
+# Slot is determining in which equipment slots item could be equipped. This
+# value is currently ignored. Rating determines how level feeling will be
+# affected.
+
+# 'W' is for extra information. Depth is the depth the object is normally
+# found at, rarity determines how common the object is and cost is the items
+# value.
+
+# 'C' stands for 'creation'. It determines maximal to-hit, to-damage, AC and
+# stats (pval) values item can get.
+
+# 'Z' is granted power. See tables.c, array powers_type_init (lines 4511-4943).
+
+# 'F' contains flags. Most are self explaining, rest could be found in source.
+
+
+
+# Version stamp (required)
+
+V:2.0.0
+
+### Mage Staff ###
+
+N:1:of Mana
+X:A:24:20
+T:6:0:255
+W:5:3:8:10000
+C:-30:-30:0:3
+R:100
+F:MANA
+f:MANA
+R:70
+F:PVAL_M2
+
+N:2:of Power
+X:A:24:30
+T:6:0:255
+W:5:5:8:20000
+C:-30:-30:0:10
+R:100
+F:SPELL
+f:SPELL
+R:70
+F:PVAL_M2
+
+N:3:of Wizardry
+X:A:24:60
+T:6:0:255
+W:10:1:8:50000
+C:-40:-40:0:3
+R:100
+F:MANA | SPELL
+R:50
+F:PVAL_M2
+
+N:4:of Spell
+T:6:0:255
+X:A:24:60
+W:0:2:8:40000
+C:0:0:0:0
+R:100
+F:ACTIVATE
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+### Body Armor ###
+
+N:5:of Resist Acid
+T:36:0:255
+T:37:0:255
+X:A:30:16
+W:0:4:20:1000
+R:100
+F:RES_ACID | IGNORE_ACID
+f:RES_ACID | IGNORE_ACID
+
+N:6:of Resist Lightning
+T:36:0:255
+T:37:0:255
+X:A:30:10
+W:0:4:20:400
+R:100
+F:RES_ELEC | IGNORE_ELEC
+f:RES_ELEC | IGNORE_ELEC
+
+N:7:of Resist Fire
+T:36:0:15
+T:36:17:255
+T:37:0:255
+X:A:30:14
+W:0:4:20:800
+R:100
+F:RES_FIRE | IGNORE_FIRE
+f:RES_FIRE | IGNORE_FIRE
+
+N:8:of Resist Cold
+T:36:0:15
+T:36:17:255
+T:37:0:255
+X:A:30:12
+W:0:4:20:600
+R:100
+F:RES_COLD | IGNORE_COLD
+f:RES_COLD | IGNORE_COLD
+
+N:9:of Resistance
+T:36:0:255
+T:37:0:255
+X:A:30:20
+W:0:2:20:12500
+C:0:0:10:0
+R:100
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+f:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+R:25
+F:R_HIGH
+
+N:10:Elven
+T:36:0:255
+T:37:0:255
+X:B:30:25
+W:0:2:20:15000
+C:0:0:10:3
+R:100
+F:STEALTH | ESP_ORC
+f:STEALTH
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:OLD_RESIST
+R:25
+F:RES_POIS
+
+# Robe
+N:11:of Permanence
+T:36:2:2
+X:A:30:30
+W:0:1:10:30000
+C:0:0:10:0
+R:100
+F:SUST_STR | SUST_DEX | SUST_CON | SUST_INT | SUST_WIS | SUST_CHR |
+F:HOLD_LIFE | RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:OLD_RESIST
+R:2
+F:R_IMMUNITY
+
+# Filthy rags of leprousness
+N:12:of Leprousness
+T:36:1:1
+X:A:30:0
+W:0:1:10:0
+C:0:0:0:-6
+R:100
+F:CON | STR | R_STAT | CURSED
+# No CURSE_NO_DROP here, players seems to unlike surprises
+
+# Mithirl & Adamantite mails & PDSM
+N:13:of Immunity
+T:37:25:25
+T:37:30:30
+T:38:30:30
+X:A:30:40
+W:60:10:100:30000
+C:0:0:5:0
+R:100
+F:R_IMMUNITY
+
+# Ego DSM
+N:14:of Defense
+T:38:0:255
+X:A:30:5
+W:20:40:100:1000
+C:0:0:8:0
+R:100
+F:SUSTAIN
+
+# Boots of Jumping
+N:15:of Jumping
+T:30:0:255
+X:A:35:16
+W:0:3:27:500
+C:0:0:0:3
+Z:blink
+R:100
+F:ACTIVATE
+a:HARDCORE=JUMP
+
+### Shields ###
+
+N:16:of Resist Acid
+T:115:56:56
+T:34:0:5
+T:34:7:255
+X:A:32:16
+W:0:6:22:1000
+R:100
+F:RES_ACID | IGNORE_ACID
+f:RES_ACID | IGNORE_ACID
+
+N:17:of Resist Lightning
+T:34:0:5
+T:34:7:255
+T:115:56:56
+X:A:32:10
+W:0:6:22:400
+R:100
+F:RES_ELEC | IGNORE_ELEC
+f:RES_ELEC | IGNORE_ELEC
+
+N:18:of Resist Fire
+T:34:0:5
+T:34:7:255
+T:115:56:56
+X:A:32:14
+W:0:6:22:800
+R:100
+F:RES_FIRE | IGNORE_FIRE
+f:RES_FIRE | IGNORE_FIRE
+
+N:19:of Resist Cold
+T:115:56:56
+T:34:0:5
+T:34:7:255
+X:A:32:12
+W:0:6:22:600
+R:100
+F:RES_COLD | IGNORE_COLD
+f:RES_COLD | IGNORE_COLD
+
+N:20:of Resistance
+T:115:56:56
+T:34:0:5
+T:34:7:255
+X:A:32:20
+W:0:2:22:12500
+C:0:0:10:0
+R:100
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+f:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:21:of Reflection
+T:115:56:56
+T:34:0:5
+T:34:7:255
+X:A:32:20
+W:0:2:22:15000
+C:0:0:5:0
+R:100
+F:REFLECT
+f:REFLECT
+F:IGNORE_ELEC | IGNORE_ACID | IGNORE_COLD | IGNORE_FIRE
+
+# Metal shields only
+N:22:of Electricity
+T:34:3:3
+T:34:5:5
+T:34:10:10
+X:A:32:10
+W:0:2:22:400
+R:100
+F:RES_ELEC | IGNORE_ELEC | SH_ELEC
+f:SH_ELEC
+
+### Crowns and Helms ###
+
+N:23:of the Noldor
+T:115:57:57
+T:32:0:6
+T:32:8:99
+X:A:33:13
+C:0:0:0:2
+W:0:1:8:500
+R:100
+F:DEX | SUST_DEX | ACTIVATE | ESP_ORC
+a:HARDCORE=NOLDOR
+
+N:24:of Intelligence
+X:A:33:13
+C:0:0:0:2
+W:0:2:15:500
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:INT | SUST_INT
+f:INT
+
+N:25:of Wisdom
+X:A:33:13
+W:0:2:15:500
+C:0:0:0:2
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:WIS | SUST_WIS
+f:WIS
+
+N:26:of Beauty
+X:A:33:8
+W:0:2:15:1000
+C:0:0:0:4
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:CHR | SUST_CHR
+f:CHR
+
+# 40% chance of increase spell power
+N:27:of the Magi
+X:A:33:15
+W:0:1:8:7500
+C:0:0:0:3
+T:33:0:99
+R:100
+F:INT | SUST_INT |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:ABILITY | R_HIGH
+R:40
+F:SPELL
+R:50
+F:SPELL_CONTAIN | WIELD_CAST
+
+N:28:of Might
+X:A:33:19
+W:0:1:8:2000
+C:0:0:0:3
+T:33:0:99
+R:100
+F:STR | DEX | CON | SUST_STR | SUST_DEX | SUST_CON | FREE_ACT
+F:R_HIGH
+
+N:29:of Lordliness
+X:A:33:17
+W:0:1:8:2000
+C:0:0:0:3
+T:33:0:99
+R:100
+F:WIS | CHR | SUST_WIS | SUST_CHR
+F:R_HIGH
+
+N:30:of Seeing
+X:A:33:8
+W:0:1:8:1000
+C:0:0:0:5
+T:32:0:6
+T:32:8:99
+T:33:0:99
+T:115:57:57
+R:100
+F:SEARCH | RES_BLIND | SEE_INVIS
+f:SEARCH
+R:20
+F:ESP_ALL
+
+N:31:of Infravision
+X:A:33:11
+W:0:1:15:500
+C:0:0:0:5
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:INFRA | HIDE_TYPE
+f:INFRA
+
+N:32:of Light
+X:A:33:6
+W:0:2:15:500
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:LITE1 | RES_LITE
+f:LITE1
+
+N:33:of Telepathy
+X:A:33:20
+W:0:1:8:50000
+T:33:0:99
+R:100
+F:ESP_ALL
+f:ESP_ALL
+
+N:34:of Regeneration
+X:A:33:10
+W:0:1:8:1500
+T:32:0:6
+T:32:8:99
+T:33:0:99
+T:115:57:57
+R:100
+F:REGEN
+f:REGEN
+
+N:35:of Teleportation
+X:A:33:0
+W:0:1:7:50
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:TELEPORT
+f:TELEPORT
+R:90
+F:CURSED
+
+N:36:of Stupidity
+X:A:33:0
+C:0:0:0:-5
+W:0:2:7:0
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:INT | CURSED
+f:INT
+# No CURSE_NO_DROP here, players seems to unlike surprises
+
+N:37:of Naivety
+X:A:33:0
+C:0:0:0:-5
+W:0:2:7:0
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:WIS
+f:WIS
+
+N:38:of Ugliness
+X:A:33:0
+C:0:0:0:-5
+W:0:1:7:0
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:CHR
+f:CHR
+
+N:39:of Sickliness
+X:A:33:0
+C:0:0:0:-5
+W:0:1:7:0
+T:33:0:99
+R:100
+F:STR | DEX | CON
+
+N:40:Dwarven
+T:32:0:6
+T:32:8:99
+X:B:33:13
+C:0:0:0:2
+W:0:1:8:500
+R:100
+F:INFRA | CON | RES_FIRE | ESP_TROLL | ESP_DRAGON
+
+
+### Cloaks ###
+
+N:41:of Protection
+X:A:31:10
+W:0:4:19:1500
+C:0:0:10:0
+T:35:0:255
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | RES_SHARDS
+
+N:42:of Stealth
+X:A:31:10
+W:0:8:18:500
+C:0:0:0:3
+T:35:0:99
+R:100
+F:STEALTH
+f:STEALTH
+
+N:43:of Aman
+X:A:31:20
+W:0:1:28:4000
+C:0:0:20:3
+T:35:0:255
+R:100
+F:STEALTH |
+f:STEALTH |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:OLD_RESIST
+
+# Aura, Fire
+N:44:of Immolation
+X:A:31:16
+W:0:1:18:4000
+C:0:0:4:0
+T:35:0:255
+R:100
+F:IGNORE_ACID | IGNORE_FIRE | SH_FIRE | RES_FIRE
+f:SH_FIRE
+
+N:45:of Enveloping
+X:A:31:0
+W:0:1:3:0
+C:-10:-10:0:0
+T:35:0:255
+R:100
+F:SHOW_MODS
+
+N:46:of Vulnerability
+X:A:31:0
+W:0:1:3:0
+C:0:0:-50:0
+T:35:0:255
+R:100
+F:AGGRAVATE
+
+N:47:of Irritation
+X:A:31:0
+W:0:1:3:0
+C:-15:-15:0:0
+T:35:0:255
+R:100
+F:AGGRAVATE | SHOW_MODS
+
+# Aura, Electricity
+N:48:of Electricity
+X:A:31:16
+W:0:1:18:4000
+C:0:0:4:0
+T:35:0:255
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | SH_ELEC | RES_ELEC
+
+### Gloves ###
+
+N:49:of Free Action
+X:A:34:11
+W:0:4:10:1000
+T:31:0:99
+R:100
+F:FREE_ACT
+f:FREE_ACT
+
+N:50:of Slaying
+X:A:34:17
+W:0:3:10:1500
+C:6:6:0:0
+T:31:0:99
+R:100
+F:SHOW_MODS
+
+N:51:of Agility
+X:A:34:14
+W:0:2:10:1000
+C:0:0:0:5
+T:31:0:99
+R:100
+F:DEX | HIDE_TYPE
+f:DEX
+
+N:52:of Power
+T:31:0:99
+X:A:34:22
+W:0:1:10:2500
+C:5:5:0:5
+R:100
+F:STR | SHOW_MODS | HIDE_TYPE
+f:STR
+F:R_HIGH
+
+# 53 Gauntlets only
+N:53:of Peace
+X:A:34:0
+W:0:1:3:0
+C:-10:-10:0:0
+T:31:2:2
+R:100
+F:HEAVY_CURSE | CURSED
+
+# 54 Gloves only
+N:54:of Charming
+X:A:34:5
+T:31:1:1
+W:0:1:11:400
+C:0:0:0:6
+R:100
+F:CHR
+R:33
+F:STEALTH
+f:STEALTH
+
+N:55:of Weakness
+T:31:0:99
+X:A:34:0
+W:0:1:3:0
+C:0:0:0:-10
+R:100
+F:STR
+
+N:56:of Clumsiness
+X:A:34:0
+W:0:1:3:0
+C:0:0:0:-10
+R:100
+F:DEX
+T:31:0:99
+
+
+### Boots ###
+
+N:57:of Levitation
+X:A:35:7
+W:0:8:27:250
+T:30:0:99
+R:100
+F:FEATHER
+f:FEATHER
+R:40
+F:R_HIGH
+
+N:58:of Stealth
+X:A:35:16
+W:0:8:27:500
+C:0:0:0:3
+T:30:0:99
+R:100
+F:STEALTH
+f:STEALTH
+
+N:59:of Free Action
+X:A:35:15
+W:0:5:27:1000
+T:30:0:99
+R:100
+F:FREE_ACT
+f:FREE_ACT
+
+N:60:of Speed
+X:A:35:25
+W:0:1:27:200000
+C:0:0:0:10
+T:30:0:99
+R:100
+F:SPEED | HIDE_TYPE
+f:SPEED
+R:10
+F:PVAL_M3
+
+# 61 Metal boots only
+
+N:61:of Dwarvish Endurance
+X:A:35:15
+W:0:1:20:5000
+C:0:0:0:6
+T:30:6:6
+R:100
+F:CON | INFRA | RES_DARK
+R:33
+F:STR
+
+N:62:of Noise
+X:A:35:0
+W:0:1:3:0
+T:30:0:99
+R:100
+F:AGGRAVATE
+f:AGGRAVATE
+
+N:63:of Slowness
+X:A:35:0
+W:0:1:3:0
+C:0:0:0:-5
+T:30:0:99
+R:100
+F:SPEED
+f:SPEED
+
+N:64:of Annoyance
+X:A:35:0
+W:0:1:3:0
+C:0:0:0:-10
+T:30:0:99
+R:100
+F:SPEED | AGGRAVATE
+
+
+### Weapons ###
+
+N:65:of Aman
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+X:A:24:30
+W:0:2:44:20000
+C:6:6:4:3
+R:100
+F:WIS |
+F:SLAY_EVIL | SLAY_UNDEAD | SLAY_DEMON |
+F:SEE_INVIS | BLESSED | RES_FEAR | ESP_EVIL
+F:SUSTAIN | LIMIT_BLOWS
+R:10
+F:BLOWS
+R:1
+F:PVAL_M1
+
+N:66:(Defender)
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+X:A:24:25
+W:0:2:44:15000
+C:4:4:8:4
+R:100
+F:STEALTH |
+f:STEALTH |
+F:FREE_ACT | SEE_INVIS | FEATHER | REGEN |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:SUSTAIN | R_HIGH
+R:33
+F:RES_POIS
+
+N:67:Blessed
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+X:B:24:20
+W:0:1:44:5000
+C:0:0:0:3
+R:100
+F:WIS | ESP_GOOD
+F:BLESSED | ABILITY
+f:BLESSED
+
+N:68:of Greater Life
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:20
+W:0:1:50:30000
+C:5:5:0:3
+r:N:MUST2H
+R:100
+F:LIFE | HOLD_LIFE
+f:LIFE
+
+N:69:of Westernesse
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+X:A:24:20
+W:0:2:44:20000
+C:5:5:0:2
+R:100
+F:STR | DEX | CON |
+F:SLAY_ORC | SLAY_TROLL | SLAY_GIANT |
+F:FREE_ACT | SEE_INVIS | ESP_ORC | ESP_TROLL | ESP_GIANT
+R:33
+F:RES_FEAR
+R:50
+F:RES_MORGUL
+
+N:70:of Extra Attacks
+T:125:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:20
+W:0:1:44:10000
+C:0:0:0:3
+R:100
+F:BLOWS
+f:BLOWS
+
+N:71:of Slaying
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:15
+W:0:2:44:2500
+C:0:0:0:0
+R:100
+F:SLAY_WEAP | WOUNDING
+
+N:72:of Spinning
+T:125:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:18
+W:0:1:44:9000
+C:8:8:0:2
+R:100
+F:DEX | STR | VORPAL | ACTIVATE
+a:HARDCORE=SPIN
+
+# The "Elemental" brands (4) (6)
+
+N:73:Acidic
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:B:24:15
+W:0:4:44:5000
+R:100
+F:BRAND_ACID | RES_ACID | IGNORE_ACID
+f:BRAND_ACID
+
+N:74:Shocking
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:B:24:20
+W:0:4:44:4500
+R:100
+F:BRAND_ELEC | RES_ELEC | IGNORE_ELEC
+f:BRAND_ELEC
+
+N:75:Fiery
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:B:24:20
+W:0:4:44:3500
+R:100
+F:BRAND_FIRE | RES_FIRE | IGNORE_FIRE | LITE1
+f:BRAND_FIRE |
+
+N:76:Frozen
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:B:24:15
+W:0:4:44:3000
+R:100
+F:BRAND_COLD | RES_COLD | IGNORE_COLD
+f:BRAND_COLD |
+
+N:77:Venomous
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:B:24:20
+W:0:4:44:4000
+R:100
+F:BRAND_POIS | RES_POIS
+f:BRAND_POIS |
+
+N:78:Chaotic
+T:125:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:29
+T:23:31:255
+T:24:0:255
+T:115:55:55
+X:B:24:28
+W:0:1:44:10000
+R:100
+F:CHAOTIC | RES_CHAOS | IGNORE_ELEC | IGNORE_ACID | IGNORE_FIRE
+f:CHAOTIC
+F:R_ANY
+
+N:79:Sharp
+T:125:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:B:24:20
+W:0:2:44:5000
+R:100
+F:VORPAL
+f:VORPAL
+
+N:80:of Earthquakes
+T:125:0:255
+T:21:0:255
+T:115:55:55
+X:A:24:20
+W:0:1:44:4000
+C:10:10:0:6
+R:100
+F:IMPACT | STR | TUNNEL | HIDE_TYPE
+f:IMPACT
+
+# The "Slay" brands (8)
+
+N:81:of Slay Animal
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:18
+W:0:6:44:3500
+R:100
+F:SLAY_ANIMAL
+f:SLAY_ANIMAL
+
+N:82:of Slay Evil
+T:15:0:255
+T:125:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:18
+W:0:6:44:3500
+R:100
+F:SLAY_EVIL
+f:SLAY_EVIL
+
+N:83:of Slay Undead
+T:15:0:255
+T:21:0:19
+T:21:21:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:18
+W:0:6:44:3500
+R:100
+F:SLAY_UNDEAD
+f:SLAY_UNDEAD
+
+N:84:of Slay Demon
+T:15:0:255
+T:125:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:14
+W:0:6:44:2500
+R:100
+F:SLAY_DEMON
+f:SLAY_DEMON
+
+N:85:of Slay Orc
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:10
+W:0:6:44:2500
+R:100
+F:SLAY_ORC
+f:SLAY_ORC
+
+N:86:of Slay Troll
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:10
+W:0:6:44:2500
+R:100
+F:SLAY_TROLL
+f:SLAY_TROLL
+
+N:87:of Slay Giant
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:14
+W:0:6:44:2500
+R:100
+F:SLAY_GIANT
+f:SLAY_GIANT
+
+N:88:of Slay Dragon
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:18
+W:0:6:44:3500
+R:100
+F:SLAY_DRAGON
+f:SLAY_DRAGON
+
+# The "Kill" brands (8)
+
+N:89:of *Slay Animal*
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:20
+W:0:2:44:6000
+C:0:0:0:2
+R:100
+F:INT | SLAY_ANIMAL | SLOW_DIGEST | STEALTH | ESP_ANIMAL
+f:SLAY_ANIMAL | STEALTH
+
+N:90:of *Slay Evil*
+T:125:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:20
+W:0:2:44:6000
+C:0:0:0:2
+R:100
+F:WIS | SLAY_EVIL | BLESSED | ESP_EVIL | RES_FEAR | ABILITY
+f:SLAY_EVIL |
+
+N:91:of *Slay Undead*
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:24
+W:0:2:44:8000
+C:0:0:0:2
+R:100
+F:WIS | KILL_UNDEAD | SEE_INVIS | ESP_UNDEAD | RES_NETHER
+f:KILL_UNDEAD |
+
+N:92:of *Slay Demon*
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:16
+W:0:2:44:8000
+C:0:0:0:2
+R:100
+F:INT | KILL_DEMON | ESP_DEMON | RES_FIRE | RES_CHAOS
+f:KILL_DEMON |
+
+N:93:of *Slay Orc*
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:14
+W:0:2:44:4000
+C:0:0:0:2
+R:100
+F:DEX | SLAY_ORC | ESP_ORC | SUST_DEX |
+f:SLAY_ORC |
+
+N:94:of *Slay Troll*
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:14
+W:0:2:44:4000
+C:0:0:0:2
+R:100
+F:STR | SLAY_TROLL | ESP_TROLL | REGEN | SUST_STR
+f:SLAY_TROLL |
+
+N:95:of *Slay Giant*
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:16
+W:0:2:44:4000
+C:0:0:0:2
+R:100
+F:STR | SLAY_GIANT | ESP_GIANT | RES_SHARDS | SUST_STR
+f:SLAY_GIANT |
+
+N:96:of *Slay Dragon*
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:24
+W:0:2:44:8000
+C:0:0:0:2
+R:100
+F:CON | KILL_DRAGON | ESP_DRAGON | RES_FEAR |
+f:KILL_DRAGON
+F:R_LOW | R_ELEM
+R:20
+F:RES_POIS
+
+N:97:Vampiric
+T:125:0:255
+T:23:0:255
+T:115:55:55
+X:B:24:25
+W:0:2:44:10000
+C:0:0:0:-2
+R:100
+F:LIFE | VAMPIRIC | HOLD_LIFE
+f:LIFE | VAMPIRIC
+
+N:98:(*Defender*)
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+X:A:24:35
+W:0:1:100:50000
+C:-15:-15:20:4
+R:100
+F:STEALTH | RES_POIS | DEX | CON | WIS | HOLD_LIFE |
+f:STEALTH
+F:FREE_ACT | SEE_INVIS | FEATHER | REGEN |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:R_ANY | R_LOW | SUSTAIN
+R:30
+F:R_ANY | R_LOW | SUSTAIN
+R:20
+F:R_ANY | R_LOW | SUSTAIN | R_HIGH
+R:10
+F:R_IMMUNITY | R_ANY
+
+N:99:of the Thunderlords
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+X:A:24:22
+W:0:1:100:7000
+C:4:4:0:2
+a:HARDCORE=TELEPORT
+R:100
+F:SLAY_EVIL | KILL_DRAGON | TELEPORT | FREE_ACT | SEARCH | BRAND_ELEC
+F:REGEN | SLOW_DIGEST | RES_NEXUS | ACTIVATE | FLY | ESP_DRAGON
+F:R_HIGH
+R:12
+F:ABILITY
+R:2
+F:R_P_ABILITY | PVAL_M3 | LIMIT_BLOWS
+
+N:100:of Gondolin
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+X:A:24:26
+W:0:1:44:25000
+C:7:7:0:3
+R:100
+F:STR | CON | ESP_EVIL | RES_FEAR |
+F:SLAY_EVIL | SLAY_TROLL | SLAY_DRAGON | SLAY_DEMON |
+F:FREE_ACT | SEE_INVIS | LITE1 | RES_DARK | ABILITY |
+F:IGNORE_ACID | IGNORE_FIRE
+R:33
+F:R_HIGH
+R:33
+F:HOLD_LIFE
+R:22
+F:DEX
+
+# Diggers only
+
+N:101:of Digging
+T:20:0:255
+X:A:24:4
+W:0:1:2:500
+C:0:0:0:5
+R:100
+F:TUNNEL |
+f:TUNNEL |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+# More weapons
+
+N:102:Spectral
+T:125:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:B:24:30
+W:0:1:5:5000
+R:100
+F:SLAY_UNDEAD | SEE_INVIS | HOLD_LIFE | DRAIN_HP
+F:ACTIVATE
+a:HARDCORE=SPECTRAL
+
+N:103:of Morgul
+T:125:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:0
+W:0:1:1:0
+C:-20:-20:-10:-10
+R:100
+F:LUCK
+F:SEE_INVIS | AGGRAVATE | HEAVY_CURSE | CURSED | BLACK_BREATH | DRAIN_EXP |
+F:AUTO_CURSE | WOUNDING
+# No CURSE_NO_DROP here, players seems to unlike surprises
+
+N:104:of Nothingness
+T:125:0:255
+T:15:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+X:A:24:0
+W:0:1:2:0
+C:-100:-100:0:0
+R:100
+F:NEVER_BLOW | HEAVY_CURSE | CURSED | AUTO_CURSE
+
+
+### Missile Launchers ###
+
+N:105:of Accuracy
+T:19:0:255
+T:15:0:255
+X:A:25:10
+W:0:8:21:1000
+C:15:5:0:0
+
+N:106:of Power
+T:19:0:255
+T:15:0:255
+X:A:25:10
+W:0:8:21:1000
+C:5:15:0:0
+
+N:107:of Extra Might
+T:19:0:255
+X:A:25:20
+W:0:4:21:10000
+C:5:10:0:1
+R:100
+F:XTRA_MIGHT | PVAL_M3 | R_ANY
+f:XTRA_MIGHT |
+
+N:108:of Extra Shots
+T:19:0:255
+X:A:25:20
+C:10:5:0:1
+W:0:4:21:10000
+R:100
+F:XTRA_SHOTS | PVAL_M2
+f:XTRA_SHOTS |
+
+# Bows only
+N:109:of Lothlorien
+T:19:12:13
+X:A:25:20
+W:50:2:21:30000
+C:10:10:0:2
+R:100
+F:DEX | XTRA_MIGHT | FREE_ACT | IGNORE_ACID | IGNORE_FIRE | HIDE_TYPE |
+F:BLESSED | ABILITY
+
+# Crossbows only
+N:110:of the Haradrim
+T:19:23:24
+X:A:25:30
+W:50:2:21:20000
+C:5:15:0:1
+R:100
+F:XTRA_MIGHT | XTRA_SHOTS | IGNORE_ACID | IGNORE_FIRE | HIDE_TYPE
+
+# Slings only
+N:111:of Buckland
+X:A:25:25
+W:40:2:21:20000
+C:8:8:0:2
+T:19:2:2
+R:100
+F:DEX | XTRA_SHOTS | XTRA_MIGHT | IGNORE_ACID | IGNORE_FIRE | HIDE_TYPE
+
+
+### Ammo ###
+
+N:112:of Slay Animal
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+W:0:2:12:25
+R:100
+F:SLAY_ANIMAL
+f:SLAY_ANIMAL
+
+N:113:of Slay Evil
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+W:0:2:12:25
+R:100
+F:SLAY_EVIL
+f:SLAY_EVIL
+
+N:114:of Slay Undead
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+W:0:1:12:35
+R:100
+F:SLAY_UNDEAD
+f:SLAY_UNDEAD
+
+N:115:of Venom
+T:16:0:99
+T:17:0:2
+T:18:0:2
+X:A:23:10
+R:100
+F:BRAND_POIS
+f:BRAND_POIS
+W:0:2:12:25
+
+N:116:of Acid
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:BRAND_ACID | IGNORE_ACID
+f:BRAND_ACID |
+W:0:1:12:30
+
+# 117 All Elements at once - melee weapon
+N:117:Elemental
+X:B:24:30
+W:10:1:50:26000
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+R:100
+F:BRAND_ACID | RES_ACID | IGNORE_ACID
+F:BRAND_ELEC | RES_ELEC | IGNORE_ELEC
+F:BRAND_FIRE | RES_FIRE | IGNORE_FIRE
+F:BRAND_COLD | RES_COLD | IGNORE_COLD
+F:BRAND_POIS | RES_POIS | DRAIN_MANA
+f:BRAND_ACID |
+f:BRAND_ELEC |
+f:BRAND_FIRE |
+f:BRAND_COLD |
+f:BRAND_POIS |
+
+N:118:of Slay Demon
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+W:0:1:12:35
+R:100
+F:SLAY_DEMON
+f:SLAY_DEMON
+
+N:119:of Slay Dragon
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:SLAY_DRAGON
+f:SLAY_DRAGON
+W:0:1:12:35
+
+N:120:of Slaying
+X:A:23:15
+W:0:1:12:20
+C:12:12:0:0
+R:100
+F:DAM_DIE
+
+N:121:of Lightning
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:BRAND_ELEC | IGNORE_ELEC
+f:BRAND_ELEC |
+W:0:1:12:30
+
+N:122:of Flame
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:BRAND_FIRE | IGNORE_FIRE
+f:BRAND_FIRE |
+W:0:2:12:25
+
+N:123:of Frost
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:BRAND_COLD | IGNORE_COLD
+f:BRAND_COLD |
+W:0:2:12:25
+
+N:124:of Wounding
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:5
+W:0:3:12:20
+C:6:6:0:0
+
+N:125:of Backbiting
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:0
+W:0:1:2:0
+C:-50:-50:0:0
+
+
+### Special Broken Items ###
+
+# Destroyed Weapon
+N:126:Shattered
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:B:24:0
+W:0:1:2:0
+C:-5:-5:0:0
+
+# Destroyed Body Armor
+
+N:127:Blasted
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:B:30:0
+W:0:1:2:0
+C:0:0:-10:0
+
+
+# Instruments
+
+N:128:of the Eldar
+T:14:0:59
+T:14:61:255
+X:A:25:20
+W:0:2:3:1000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+F:RES_ACID | CHR | SEE_INVIS
+F:R_ANY | PVAL_M2
+R:25
+F:PVAL_M1
+
+N:129:of Power
+T:14:0:59
+T:14:61:255
+X:A:25:20
+W:0:1:3:2000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | SUST_CHR |
+F:RES_FIRE | RES_COLD | RES_ELEC | RES_ACID | CHR | SEE_INVIS
+F:R_ANY | PVAL_M3
+R:50
+F:PVAL_M1
+R:35
+F:PVAL_M1
+
+# Horn, now four different ego items (for different GF_ values)
+# see items 181, 182 & 183.
+N:130:Dragon
+T:14:60:60
+X:B:25:20
+W:0:1:2:2000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | ACTIVATE
+F:R_ANY | PVAL_M2
+R:50
+F:PVAL_M1
+R:25
+F:PVAL_M1
+a:HARDCORE=BA_ACID_H
+
+# Rods ego
+N:131:Capacity of
+T:67:0:255
+X:A:51:10
+W:0:2:10:1000
+C:0:0:0:0
+R:100
+F:CAPACITY
+f:CAPACITY
+
+N:132:Cheapness of
+T:67:0:255
+X:A:51:10
+W:0:2:10:700
+C:0:0:0:0
+R:100
+F:CHEAPNESS
+f:CHEAPNESS
+
+N:133:Quickness of
+T:67:0:255
+X:A:51:15
+W:0:3:10:1100
+C:0:0:0:0
+R:100
+F:FAST_CAST
+f:FAST_CAST
+
+N:134:Charging of
+T:67:0:255
+X:A:51:15
+W:0:2:10:1500
+C:0:0:0:0
+R:100
+F:CHARGING
+f:CHARGING
+
+N:135:the Istari of
+T:67:0:255
+X:A:51:10
+W:0:1:10:10000
+C:0:0:0:0
+R:100
+F:CAPACITY | CHARGING | CHEAPNESS | FAST_CAST |
+
+### Lights ###
+
+N:136:of Boldness
+X:A:0:5
+T:39:0:99
+W:0:1:5:1000
+Z:remove fear
+
+N:137:of Fearlessness
+X:A:0:5
+T:39:0:99
+W:0:1:10:1500
+R:100
+F:RES_FEAR
+
+N:138:of Illumination
+X:A:0:5
+T:39:0:99
+W:0:3:10:1000
+Z:illuminate
+R:10
+F:LITE1
+R:5
+F:LITE2
+R:2
+F:LITE3
+
+N:139:of Brightness
+X:A:0:5
+T:39:0:99
+W:0:3:10:1000
+R:100
+F:LITE1
+f:LITE1
+R:60
+F:LITE2
+R:30
+F:LITE3
+R:30
+F:RES_DARK
+
+N:140:of *Brightness*
+X:A:0:9
+T:39:0:99
+W:0:1:40:5000
+R:100
+F:LITE1
+F:LITE2
+F:LITE3
+f:LITE1
+f:LITE2
+f:LITE3
+F:RES_DARK
+
+N:141:of the Shadows
+X:A:0:6
+T:39:0:99
+W:0:1:20:3000
+C:0:0:0:2
+R:100
+F:INVIS
+R:70
+F:RES_DARK
+R:50
+F:RES_LITE
+
+N:142:of Infravision
+X:A:0:3
+T:39:0:99
+W:0:1:10:700
+C:0:0:0:3
+R:100
+F:INFRA
+f:INFRA
+
+N:143:of the Eternal Eye
+X:A:0:7
+T:39:0:99
+W:0:3:40:4000
+C:0:0:0:0
+R:100
+F:RES_BLIND | SEE_INVIS
+
+N:144:of the Ethereal Eye
+X:A:0:7
+T:39:0:99
+W:0:3:40:4000
+C:0:0:0:0
+Z:magic map
+
+N:145:of Fading
+X:A:0:0
+T:39:2:99
+W:0:1:1:0
+C:0:0:0:0
+R:100
+F:FUEL_LITE
+
+# Armor (dwarven): must be heavy metal, and not rusty chain mail
+
+N:146:Dwarven
+T:37:2:255
+X:B:30:18
+W:0:2:20:5000
+C:0:0:15:2
+R:100
+F:STR | CON | INFRA | FREE_ACT | HIDE_TYPE |
+F:RES_FEAR | RES_DARK | SUST_STR | SUST_CON |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+# Ring and Amulet egos
+
+N:147:Indestructible
+X:B:0:2
+T:40:0:255
+T:45:0:255
+W:0:1:10:1000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+f:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:148:Cursed
+X:B:0:0
+T:40:0:255
+T:45:0:255
+W:0:1:10:0
+C:0:0:0:0
+R:100
+F:AUTO_CURSE
+f:AUTO_CURSE
+
+# Scrolls & school spellbooks & staves
+N:149:Fireproof
+X:B:0:1
+T:70:0:255
+T:111:0:255
+T:55:0:255
+W:0:1:10:1000
+C:0:0:0:0
+R:100
+F:IGNORE_FIRE
+f:IGNORE_FIRE
+
+# Wands & Staffs(NOT wishing nor nothing)
+N:150:of Plenty
+X:A:0:1
+T:55:0:29
+T:55:32:255
+T:65:0:29
+T:65:31:255
+W:0:1:20:1000
+C:0:0:0:3
+R:100
+F:PVAL_M5 | PVAL_M3
+R:50
+F:PVAL_M5 | PVAL_M3
+R:10
+F:PVAL_M5 | PVAL_M3
+R:1
+F:PVAL_M5 | PVAL_M3
+
+
+### Trapping Kits ###
+
+N:151:of Extra Might
+X:A:0:5
+T:46:1:3
+W:0:1:10:1000
+C:20:20:0:2
+R:100
+F:XTRA_MIGHT
+f:XTRA_MIGHT
+
+N:152:of Extra Shots
+X:A:0:10
+T:46:0:99
+W:0:1:10:2000
+C:20:20:0:3
+R:100
+F:XTRA_SHOTS
+f:XTRA_SHOTS
+
+N:153:Automatic
+X:B:0:15
+T:46:0:99
+W:0:1:10:3000
+C:10:10:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_COLD | IGNORE_FIRE |
+F:AUTOMATIC_5
+f:AUTOMATIC_5
+
+N:154:Fully Automatic
+X:B:0:15
+T:46:0:99
+W:0:1:15:5000
+C:10:10:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_COLD | IGNORE_FIRE |
+F:AUTOMATIC_99
+f:AUTOMATIC_99
+
+N:155:Well-hidden
+X:B:0:5
+T:46:0:99
+W:0:1:8:1000
+C:15:15:5:12
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_COLD | IGNORE_FIRE |
+F:STEALTH | HIDE_TYPE
+f:STEALTH
+
+N:156:Complicated
+X:B:0:10
+T:46:0:99
+W:0:1:12:2000
+C:15:15:30:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_COLD | IGNORE_FIRE
+
+N:157:Obvious
+X:B:0:0
+T:46:0:99
+W:0:1:1:0
+C:-20:-20:-20:-20
+R:100
+F:STEALTH | CURSED | HIDE_TYPE
+f:STEALTH
+
+N:158:for Dragons
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_DRAGON | HIDE_TYPE | XTRA_SHOTS |
+F:IGNORE_ACID | IGNORE_FIRE
+
+N:159:for Demons
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_DEMON | HIDE_TYPE | XTRA_SHOTS
+F:IGNORE_ACID | IGNORE_FIRE
+
+N:160:for Animals
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_ANIMAL | HIDE_TYPE | XTRA_SHOTS
+
+N:161:for Undead
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_UNDEAD | HIDE_TYPE | XTRA_SHOTS | KILL_GHOST
+
+N:162:for Evil
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_EVIL | HIDE_TYPE | XTRA_SHOTS | KILL_GHOST
+
+# Lite ego
+N:163:of the Magi
+X:A:0:0
+T:39:1:99
+W:0:1:150:2000
+C:0:0:0:3
+Z:magic map
+R:100
+F:INT | WIS | CHR
+R:60
+F:INVIS | RES_BLIND
+R:30
+F:R_HIGH
+R:30
+F:PVAL_M2
+R:50:
+F:SPELL_CONTAIN | WIELD_CAST
+
+### New ego-items added by JLE
+
+# Armor of Vulnerability (the only cursed armor)
+N:164:of Vulnerability
+X:A:30:0
+W:0:2:20:0
+C:0:0:-50:0
+T:36:0:99
+T:37:0:99
+R:100
+F:AGGRAVATE | CURSED
+
+# Shield of Vulnerability (the only cursed shield)
+N:165:of Vulnerability
+X:A:32:0
+W:0:2:22:0
+C:0:0:-50:0
+T:115:56:56
+T:34:0:99
+R:100
+F:AGGRAVATE | CURSED
+
+# Shield of Preservation -
+N:166:of Preservation
+X:A:32:25
+W:40:2:44:20000
+C:-10:-10:20:0
+T:115:56:56
+T:34:0:99
+R:100
+F:RES_DISEN | SUST_STR | SUST_CON | SUST_DEX | HOLD_LIFE | R_HIGH |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+R:33
+F:R_LOW
+R:33
+F:R_LOW
+
+# Helm/Crown of Serenity
+N:167:of Serenity
+X:A:33:20
+W:35:1:15:4000
+T:32:0:6
+T:32:8:99
+T:33:0:99
+R:100
+F:RES_SOUND | RES_CONF | RES_FEAR
+
+# Crown of Night and Day
+N:168:of Night and Day
+X:A:33:18
+W:35:1:15:4000
+T:33:0:99
+R:100
+F:RES_LITE | RES_DARK | LITE1 | SEE_INVIS | RES_BLIND | IGNORE_ACID
+
+# Cloak of the Magi
+N:169:of the Magi
+X:A:31:15
+W:30:1:18:2000
+C:-5:-5:5:3
+T:35:0:99
+R:100
+F:INT | SPEED | SUST_INT | FREE_ACT | STEALTH | HIDE_TYPE | IGNORE_ACID
+R:30
+F:SPELL_CONTAIN | WIELD_CAST
+
+# Cloak of Invisibility
+N:170:of Invisibility
+X:A:31:20
+W:40:1:18:3000
+C:0:0:10:5
+T:35:0:99
+R:100
+F:STEALTH | HIDE_TYPE | INVIS
+f:INVIS
+
+# Cloak of the Bat
+N:171:of the Bat
+X:A:31:15
+W:50:1:35:3000
+C:-10:-10:10:3
+T:35:0:99
+R:100
+F:SPEED | FLY | RES_DARK | SEE_INVIS | INFRA | HIDE_TYPE | STEALTH
+
+# Leather Gloves of Thievery
+N:172:of Thievery
+X:A:34:22
+W:40:1:15:5000
+C:8:3:0:5
+T:31:1:1
+R:100
+F:DEX | SEARCH | SHOW_MODS | FEATHER | FREE_ACT | HIDE_TYPE | IGNORE_ACID
+R:10
+F:SPEED
+
+# Gauntlets and Cesti of Combat
+N:173:of Combat
+X:A:34:22
+W:50:1:15:7000
+C:6:8:-20:2
+T:31:2:99
+R:100
+F:STR | CON | SHOW_MODS | AGGRAVATE | HIDE_TYPE | IGNORE_ACID | RES_FEAR |
+F:DRAIN_HP
+R:25
+F:BLOWS
+
+# Boots of Stability
+N:174:of Stability
+X:A:35:20
+W:0:3:27:5000
+T:30:0:99
+R:100
+F:RES_NEXUS | FEATHER
+
+# Boots of Elvenkind (leather boots only)
+N:175:of Elvenkind
+X:A:35:30
+W:60:1:36:200000
+C:0:0:0:5
+T:30:2:3
+R:100
+F:STEALTH | SPEED | HIDE_TYPE | FEATHER | IGNORE_ACID | IGNORE_FIRE | ABILITY
+
+# Weapon of Fury (must be big heavy type of weapon, no daggers or whips)
+N:176:of Fury
+X:A:24:30
+W:40:1:66:20000
+T:21:12:99
+T:22:10:99
+T:23:16:99
+T:24:8:99
+T:125:0:99
+C:10:10:-20:2
+R:100
+F:STR | BLOWS | AGGRAVATE | RES_FEAR | HIDE_TYPE |
+F:IGNORE_ACID | IGNORE_FIRE | DRAIN_MANA
+
+# Staffs of wishing
+N:177:of Plenty
+X:A:0:1
+T:55:31:31
+W:0:1:20:1000
+C:0:0:0:2
+R:100
+F:PVAL_M2
+
+
+# Diggers only
+
+N:178:Magical
+T:20:0:255
+X:B:24:4
+W:0:1:10:500
+C:0:0:0:0
+Z:stone to mud
+R:100
+
+# Rod
+N:179:Simplicity of
+T:67:0:255
+X:A:51:8
+W:3:2:8:1000
+C:0:0:0:0
+R:100
+F:EASY_USE
+f:EASY_USE
+
+# Lite ego
+N:180:of Warmth
+X:A:0:0
+T:39:1:99
+W:0:1:10:500
+C:0:0:0:0
+R:100
+F:RES_COLD
+
+#Three more horn types, for different activation types...
+N:181:Dragon
+T:14:7:7
+X:B:25:20
+W:0:1:2:2000
+C:0:0:0:0
+a:HARDCORE=BA_COLD_3
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+
+N:182:Dragon
+T:14:7:7
+X:B:25:20
+W:0:1:2:2000
+C:0:0:0:0
+a:HARDCORE=BA_ELEC_3
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+
+N:183:Dragon
+T:14:7:7
+X:B:25:20
+W:0:1:2:2000
+C:0:0:0:0
+a:HARDCORE=BA_FIRE_H
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+
+# Helm of water breathing
+N:184:of Water Breathing
+X:A:33:13
+C:0:0:0:2
+W:15:1:25:1000
+T:32:5:10
+R:100
+F:WATER_BREATH | IGNORE_ACID
+f:WATER_BREATH
+
+# A second of life for non MUST2H weapons, much lower value tho
+N:185:of Life
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+X:A:24:20
+W:0:1:50:30000
+C:5:5:0:1
+r:F:MUST2H
+R:100
+F:LIFE | HOLD_LIFE
+f:LIFE
+
+# Cloak of Air
+N:186:of Air
+X:A:31:10
+W:30:1:35:1500
+C:0:0:0:0
+T:35:0:255
+R:100
+F:MAGIC_BREATH
+
+# Ego DSM
+N:187:Polished
+T:38:0:255
+X:B:30:5
+W:40:25:100:25000
+C:0:0:0:0
+R:100
+F:REFLECT
+
+# Ego Heavy Crossbow
+N:188:of Siegecraft
+T:19:24:24
+X:A:25:30
+W:60:5:30:30000
+C:10:15:20:2
+R:120
+F:XTRA_MIGHT | XTRA_SHOTS | REFLECT | IMMOVABLE
+
+# N: serial number : ego type
+# D: description
+# T: tval : min sval : max sval
+# R: rarity
+# X: position : slot : rating
+# W: depth : rarity1 : rarity2 : cost
+# C: to-hit : to-dam : to-ac : pval
+# r:N:needed flags on the base object
+# r:F:forbidden flags on the base object
+# Z: granted_power
+# F: flags
diff --git a/lib/edit/evil.map b/lib/edit/evil.map
new file mode 100644
index 00000000..a2f00914
--- /dev/null
+++ b/lib/edit/evil.map
@@ -0,0 +1,52 @@
+# permanent wall
+F:X:61:0
+
+# granite
+F:#:57:0
+
+# Mountain Chain
+F:^:97:0
+
+# up staircase
+F:<:6:0
+
+# Dirt
+F:.:88:0
+
+# Lesser Balrog
+F:b:88:0:996:0:0:0:0:0:0:2
+
+# Greater Balrog
+F:B:88:0:807:0:0:0:0:0:0:2
+
+# Pit Fiend
+F:P:88:0:812:0:0:0:0:0:0:2
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X^..^^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:X^..^^^^^^^^^..^^^^^^^^^^^^^^^^^X
+D:X^...^^^^^^.........^^^^^^^^^^^^X
+D:X^^..^^^^^..^^^^..^B^^^^^^^^^^^^X
+D:X^...^^^^...^^^^^..^^^^^^^^^^^^^X
+D:X^^..^^^..^^.^^^^^^^^^^^^^^^^^^^X
+D:X^..^^^^^.....^^^^^.^^^^^^^^^^^^X
+D:X^^..^^^^..^^.^^^.^......^^^^^^^X
+D:X^..^^^^..^^...^^...^..^.^^^^^^^X
+D:X^^..^^^..^^^..^...^^^....^^^^^^X
+D:X^^^...^.^^^.....^^^^P...<^^^^^^X
+D:X^^^.....^^^^..^^^^^^^^..^^^^^^^X
+D:X^^^^^^.^^^^..^^^^^^^^^^^^^^^^^^X
+D:X^^^^^^^^^^^...^^^^^^^^^^^^^^^^^X
+D:X^^^^^.^^^^.^..^^^^^^^^^^^^^^^^^X
+D:X^^^^...^^...^^^...^^^^^^...^^^^X
+D:X^^^^.^....^^^^.^.....^..^..^^^^X
+D:X^^^^..^^^^^.....^...^..^^^B^^^^X
+D:X^^^P........^.....^^^^^^^^^^^^^X
+D:X^^^^^^...^^^^^^^^^^^^^^^^^^^^^^X
+D:X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:4
+
diff --git a/lib/edit/f_info.txt b/lib/edit/f_info.txt
new file mode 100644
index 00000000..c0dc2e9a
--- /dev/null
+++ b/lib/edit/f_info.txt
@@ -0,0 +1,941 @@
+# File: f_info.txt
+
+
+# This file is used to initialize the "lib/raw/f_info.raw" file, which is
+# used to initialize the "terrain feature" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/f_info.raw" file.
+
+# Note that the terrain feature are grouped into very regular groups,
+# such that each of the bits in the feature type conveys information.
+
+# Note that terrain feature zero contains the "darkness" picture.
+
+
+# Version stamp (required)
+
+V:2.0.0
+
+
+# 0x00 --> nothing
+
+N:0:nothing
+G: :w
+F:FLOOR
+
+# 0x01 --> open floor
+
+N:1:open floor
+G:.:w
+F:FLOOR | DONT_NOTICE_RUNNING | SUPPORT_LIGHT | CAN_RUN
+F:SUPPORT_GROWTH
+
+# 0x02 -> fountain
+N:2:fountain
+G:_:w
+F:FLOOR | NOTICE | REMEMBER | CAN_RUN
+D:0:The liquid here seems magical.
+
+# 0x03 --> glyph of warding
+
+N:3:glyph of warding
+G:;:y
+F:FLOOR | NOTICE | SUPPORT_LIGHT | CAN_RUN | REMEMBER
+D:0:There is a mighty spell of protection here.
+
+# 0x04 --> open door
+
+N:4:open door
+G:':U
+F:FLOOR | NOTICE | REMEMBER | CAN_RUN | DOOR
+
+# 0x05 --> broken door
+
+N:5:broken door
+G:':U
+F:FLOOR | NOTICE | REMEMBER | CAN_RUN | DOOR
+
+# 0x06 --> up stairs (perm)
+
+N:6:up staircase
+G:<:w
+F:FLOOR | PERMANENT | NOTICE | SUPPORT_LIGHT | REMEMBER | CAN_RUN
+D:0:There is an up staircase here.
+D:1:You cannot tunnel a stair.
+
+# 0x07 --> down stairs (perm)
+
+N:7:down staircase
+G:>:w
+F:FLOOR | PERMANENT | NOTICE | SUPPORT_LIGHT | REMEMBER | CAN_RUN
+D:0:There is a down staircase here.
+D:1:You cannot tunnel a stair.
+
+N:8:quest entrance
+G:>:y
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+D:1:You cannot tunnel a quest entrance.
+
+N:9:quest exit
+G:<:y
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+D:1:You cannot tunnel a quest exit.
+
+N:10:quest down level
+G:>:r
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+
+N:11:quest up level
+G:<:r
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+
+N:12:town exit
+G:>:g
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+
+N:13:shaft down
+G:>:U
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+D:0:There is a shaft down here.
+D:1:You cannot tunnel a shaft.
+
+N:14:shaft up
+G:<:U
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+D:0:There is a shaft up here.
+D:1:You cannot tunnel a shaft.
+
+# 0x0F -> empty fountain
+N:15:fountain
+G:_:D
+F:FLOOR | NOTICE | REMEMBER | CAN_RUN
+D:0:The fountain seems empty.
+
+N:16:web
+G:+:y
+F:CAN_PASS | NOTICE | WEB | NOTICE | TUNNELABLE
+D:1:You tunnel through the web.
+D:2:a web blocking your way
+
+# Trap -- the flags are not used by the program
+N:17:trap
+G:^:w
+F:FLOOR | NOTICE | REMEMBER
+
+# 0x12 --> 0x1F -- UNUSED
+
+# 0x2x --> locked door (power 0)
+
+N:32:door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 1)
+
+N:33:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 2)
+
+N:34:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 3)
+
+N:35:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 4)
+
+N:36:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 5)
+
+N:37:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 6)
+
+N:38:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 7)
+
+N:39:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 0)
+
+N:40:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 1)
+
+N:41:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 2)
+
+N:42:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 3)
+
+N:43:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 4)
+
+N:44:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 5)
+
+N:45:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 6)
+
+N:46:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 7)
+
+N:47:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x30 --> secret door
+
+N:48:secret door
+G:#:w
+M:56
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | DOOR
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel.
+
+# 0x31 --> rubble
+
+N:49:pile of rubble
+G:::w
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE
+F:CAN_FLY | SUPPORT_LIGHT
+F:TUNNELABLE
+D:1:You dig in the rubble.
+
+# 0x32 --> magma vein
+
+N:50:magma vein
+G:%:s
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the magma vein.
+
+# 0x33 --> quartz vein
+
+N:51:quartz vein
+G:%:w
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the quartz vein.
+
+# 0x34 --> magma vein + treasure
+
+N:52:magma vein
+G:%:s
+M:50
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the magma vein.
+
+# 0x35 --> quartz vein + treasure
+
+N:53:quartz vein
+G:%:w
+M:51
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the quartz vein.
+
+# 0x36 --> magma vein + known treasure
+
+N:54:magma vein with treasure
+G:*:o
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the magma vein.
+
+# 0x37 --> quartz vein + known treasure
+
+N:55:quartz vein with treasure
+G:*:o
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the quartz vein.
+
+# 0x38 --> granite wall -- basic
+
+N:56:granite wall
+G:#:w
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the granite wall.
+
+# 0x39 --> granite wall -- inner
+
+N:57:granite wall
+G:#:w
+M:56
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the granite wall.
+
+# 0x3A --> granite wall -- outer
+
+N:58:granite wall
+G:#:w
+M:56
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the granite wall.
+
+# 0x3B --> granite wall -- solid
+
+N:59:granite wall
+G:#:w
+M:56
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the granite wall.
+
+# 0x3C --> permanent wall -- basic (perm)
+
+N:60:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+# 0x3D --> permanent wall -- inner (perm)
+
+N:61:permanent wall
+G:#:w
+M:60
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+# 0x3E --> permanent wall -- outer (perm)
+
+N:62:permanent wall
+G:#:w
+M:60
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+# 0x3F --> permanent wall -- solid (perm)
+
+N:63:permanent wall
+G:#:w
+M:60
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:64:explosive rune
+G:*:R
+F:FLOOR | CAN_LEVITATE | CAN_FLY | NOTICE | SUPPORT_LIGHT
+D:0:This rune seems unstable.
+
+N:65:Straight Road startpoint
+G:*:w
+F:FLOOR | REMEMBER | NOTICE
+
+N:66:section of the Straight Road
+G:*:B
+F:FLOOR | REMEMBER | NOTICE
+
+N:67:section of the Straight Road
+G:*:b
+F:FLOOR | REMEMBER | NOTICE
+
+N:68:section of the Straight Road
+G:*:B
+F:FLOOR | REMEMBER | NOTICE
+
+N:69:section of the Straight Road
+G:*:b
+F:FLOOR | REMEMBER | NOTICE
+
+N:70:section of the Straight Road
+G:*:W
+F:FLOOR | REMEMBER | NOTICE
+
+N:71:section of the Straight Road (discharged)
+G:*:W
+F:FLOOR | REMEMBER | NOTICE
+
+N:72:Straight Road exit
+G:*:w
+F:FLOOR | REMEMBER | NOTICE
+
+N:73:corrupted section of the Straight Road
+G:*:D
+F:FLOOR | REMEMBER | NOTICE
+
+# 74 --> shop
+
+N:74:Building
+G:1:U
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+
+# 75 --> 78 Quests index
+
+N:75:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:76:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:77:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:78:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+# 79 --> 83 UNSUSED
+
+N:84:stream of shallow water
+G:~:B
+S:B:B:B:B:B:B:b
+F:ATTR_MULTI
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+F:SUPPORT_GROWTH
+
+# -1 = player level
+N:85:pool of deep lava
+G:.:R
+E:-1d2:1:FIRE
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+D:0:You move across the deep lava.
+
+N:86:stream of shallow lava
+G:.:r
+E:-1d1:1:FIRE
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+D:0:You move across the shallow lava.
+
+N:87:dark pit
+G:#:D
+F:CAN_LEVITATE | CAN_FLY
+F:NO_WALK | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+D:0:Ohhh, it is dark and deep.
+
+N:88:dirt
+G:.:U
+F:FLOOR | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+F:SUPPORT_GROWTH
+
+N:89:patch of grass
+G:.:G
+F:FLOOR | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+F:SUPPORT_GROWTH
+
+N:90:ice
+G:.:W
+E:1d1:50:ICE
+F:FLOOR | NOTICE
+
+N:91:sand
+G:.:y
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+N:92:dead tree
+G:#:D
+F:CAN_FLY | CAN_PASS
+F:WALL | NO_WALK | NO_VISION | NOTICE
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You chop away at the dead tree.
+D:2:a tree blocking your way
+
+N:93:ash
+G:.:s
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+N:94:mud
+G:.:u
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+N:95:ice wall
+G:#:W
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the ice wall... #BOh chilly#w.
+D:2:an ice wall blocking your way
+
+N:96:tree
+G:#:G
+F:CAN_FLY | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You chop away at the tree.
+D:2:a tree blocking your way
+
+N:97:mountain chain
+G:^:U
+F:CAN_CLIMB | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION
+F:DONT_NOTICE_RUNNING
+F:PERMANENT
+D:1:You cannot tunnel into such a hard stone.
+D:2:a hard stone block blocking your way
+
+# 0x62 --> sandwall
+
+N:98:sandwall
+G:#:y
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You easily dig into the sandwall.
+D:2:a sandwall blocking your way
+
+# 0x63 --> sandwall + treasure
+
+N:99:sandwall
+G:%:y
+M:98
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You easily dig into the sandwall.
+D:2:a sandwall blocking your way
+
+# 0x64 --> sandwall + known treasure
+
+N:100:sandwall with treasure
+G:*:o
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You easily tunnel into the sandwall.
+D:2:a sandwall blocking your way
+
+N:101:high mountain chain
+G:^:W
+F:WALL | NO_WALK | NO_VISION | PERMANENT
+F:DONT_NOTICE_RUNNING
+D:1:This rock is far too hard.
+D:2:a very hard stone block blocking your way
+
+N:102:nether mist
+G:.:v
+S:v:R:r:v:R:r:D
+E:1d1:40:NETHER
+F:ATTR_MULTI
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+
+# A diggable glass wall.
+N:103:molten glass wall
+G:.:B
+F:NO_WALK | WALL | CAN_PASS | TUNNELABLE | NOTICE
+F:DONT_NOTICE_RUNNING
+D:1:You tunnel into the molten glass wall...
+D:2:a molten glass wall blocking your way
+
+N:160:Void Jumpgate
+G:+:v
+F:FLOOR | REMEMBER | NOTICE | PERMANENT | CAN_RUN
+D:0:A dark rift opens to the void here.
+
+###### Here are the altars. ######
+
+N:161:Altar of Being
+G:0:W
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You feel at peace.
+
+N:162:Altar of Winds
+G:0:B
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You grow a desire to become a bird.
+
+N:163:Altar of Force
+G:0:R
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You grow a desire to fight evil.
+
+N:164:Altar of Darkness
+G:0:D
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:Images of pain and death fill your mind.
+
+N:165:Altar of Nature
+G:0:g
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You feel the desire to walk in a great forest.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+# Used as a marker for random quests
+N:172:open floor
+G:.:w
+F:FLOOR | CAN_RUN | DONT_NOTICE_RUNNING
+F:SUPPORT_GROWTH
+
+# Underground Tunnel
+N:173:Underground Tunnel
+G:#:s
+F:FLOOR | REMEMBER | SUPPORT_LIGHT | DONT_NOTICE_RUNNING | CAN_RUN
+D:0:Oh, an underground tunnel!
+
+# Tainted water
+N:174:stream of tainted water
+G:~:u
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:175:monster trap
+G:;:v
+F:FLOOR
+
+N:176:Void Jumpgate
+G:+:v
+F:FLOOR | REMEMBER | NOTICE | PERMANENT | CAN_RUN
+D:0:A dark rift opens to the void here.
+
+N:177:lava wall
+G:#:R
+S:R:R:r:r:U:u:R
+F:ATTR_MULTI
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+D:1:The lava is far too hot to tunnel into it.
+D:2:a lava wall blocking your way
+
+N:178:Great Fire
+G:%:v
+S:R:R:y:v:y:v:R
+E:150d2:1:HELL_FIRE
+F:ATTR_MULTI
+F:FLOOR | REMEMBER | NOTICE | PERMANENT
+D:0:This fire is so powerful it could destroy even the most powerful artifacts.
+
+N:179:path to the next area
+G:>:w
+F:FLOOR | PERMANENT | NOTICE | REMEMBER | CAN_RUN
+D:0:There is a path leading to the next area here.
+D:1:You cannot tunnel a path.
+
+N:180:path to the previous area
+G:<:w
+F:FLOOR | PERMANENT | NOTICE | REMEMBER | CAN_RUN
+D:0:There is a path leading to the previous area here.
+D:1:You cannot tunnel a path.
+
+N:181:field
+G:::g
+F:FLOOR | PERMANENT | NOTICE | REMEMBER
+F:DONT_NOTICE_RUNNING
+D:1:You cannot tunnel a field.
+
+N:182:Ekkaia, the Encircling Sea
+G:*:b
+S:b:b:b:b:b:b:B
+F:ATTR_MULTI
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:183:void
+G: :d
+F:FLOOR
+
+# XXX 182 - 186
+
+# 187 --> terrain -- deep water
+
+N:187:pool of deep water
+G:~:b
+S:b:b:b:b:b:b:B
+F:ATTR_MULTI
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+
+# Glass wall -- can see but not pass
+N:188:glass wall
+G:.:B
+F:NO_WALK | WALL | PERMANENT | NOTICE
+F:DONT_NOTICE_RUNNING
+D:1:This glass seems to be totaly impenetrable.
+D:2:a glass wall blocking your way
+
+# Illusion wall -- can't see but can pass
+N:189:illusion wall
+G:#:w
+F:FLOOR | NO_VISION | REMEMBER | SUPPORT_LIGHT | DONT_NOTICE_RUNNING
+D:0:Looks like this wall is not so real.
+
+# Grass roof
+N:190:Grass roof
+G:#:y
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# grass roof top
+N:191:grass roof top
+G:#:y
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# grass roof chimney
+N:192:grass roof chimney
+G:#:y
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# brick roof
+N:193:brick roof
+G:#:r
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# brick roof top
+N:194:brick roof top
+G:#:r
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# brick roof chimney
+N:195:brick roof chimney
+G:#:r
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# window
+N:196:window
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# small window
+N:197:small window
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# rain barrel
+N:198:rain barrel
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# grass with flowers
+N:199:grass with flowers
+G:;:G
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+# cobblestone road
+N:200:cobblestone road
+G:.:w
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+
+# cobblestone with outlet
+N:201:cobblestone with outlet
+G:.:w
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+
+N:202:small tree
+G:#:g
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN | SUPPORT_LIGHT | REMEMBER
+F:NO_VISION
+
+# Just to have a town entrance picture
+N:203:town
+G:*:w
+F:FLOOR | NOTICE
+
+# Underground Tunnel
+N:204:Underground Tunnel
+G:^:U
+F:FLOOR | REMEMBER | SUPPORT_LIGHT | DONT_NOTICE_RUNNING | CAN_RUN
+D:0:Oh, an underground tunnel!
+
+# Fire
+N:205:a blazing fire
+G:%:y
+S:y:y:y:R:r:y:R
+E:-1d2:1:FIRE
+D:0:The blazing fire burns you!
+F:ATTR_MULTI
+F:FLOOR | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+# Permanent rubble -- town use
+N:206:pile of rubble
+G:::w
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE
+F:CAN_FLY | SUPPORT_LIGHT | PERMANENT
+D:1:Looks like this pile of rubble is quite hard.
+
+# Rocky ground - rougher terrain.
+N:207:rocky ground
+G:.:s
+F:FLOOR | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+
+# cloud-like vapour. Floor for Eru's temple
+N:208:cloud-like vapour
+G:.:W
+S:W:B:B:W:w:W:B
+F:FLOOR | CAN_LEVITATE | CAN_FLY | SUPPORT_LIGHT
+F:ATTR_MULTI | CAN_RUN | DONT_NOTICE_RUNNING
+
+# condensing water
+N:209:condensing water
+G:~:B
+S:B:B:B:B:B:B:b
+F:ATTR_MULTI
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+
+# Dense mist. Can pass through, but not see through
+N:210:dense mist
+G:#:w
+S:w:W:s:s:s:w:w
+F:FLOOR | NO_VISION | REMEMBER | SUPPORT_LIGHT
+F:ATTR_MULTI | DONT_NOTICE_RUNNING
+D:0:You wander through the mist.
+D:1:You cannot tunnel through mist!
+
+# Hail-stone wall
+N:211:hail-stone wall
+G:#:W
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the hail-stone wall.
+
+N:212:dead small tree
+G:#:D
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN | SUPPORT_LIGHT | REMEMBER
+F:NO_VISION
+
+
+# New features for the Maps of Lord Dimwit
+
+N:213:copper pillar
+G:#:u
+S:u:u:u:o:u:u:u
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING | ATTR_MULTI
+D:1:The copper is too tough to tunnel through.
+D:2:a copper pillar blocking your way
+
+N:214:ethereal wall
+G:.:w
+F:WALL | NO_WALK | PERMANENT | NOTICE | DONT_NOTICE_RUNNING
+D:1:You can't even see your obstruction!
+D:2:an unseen force blocking your way
+
+N:215:glacial wall
+G:#:B
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING | TUNNELABLE
+D:1:You tunnel into the glacial wall... #BOh chilly#w.
+D:2:a hard glacial wall blocking your way
+
+N:216:battlement
+G:#:w
+F:NO_WALK | CAN_PASS | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING | TUNNELABLE
+D:1:You tunnel into the battlement.
+D:2:a hard stone battlement blocking your way
diff --git a/lib/edit/fireprof.map b/lib/edit/fireprof.map
new file mode 100644
index 00000000..35f6bec4
--- /dev/null
+++ b/lib/edit/fireprof.map
@@ -0,0 +1,60 @@
+# Created by fearoffours (fearoffours@moppy.co.uk)
+# Made for ToME 2.1.x on 03/09/02
+
+# Permanent wall
+F:X:63:3
+
+# Floor with dirt
+F:.:88:3
+
+# shallow lava
+F:f:86:3
+
+# Deep lava
+F:F:85:3
+
+### Random Monsters and/or Items
+# Random object (upto 3 levels ood)
+F:!:88:5:0:*21
+
+# red mold
+F:m:88:5:324
+
+# Chimaera
+F:H:88:5:341
+
+# Red dragon bat
+F:b:88:5:377
+
+# Hellhound and
+# Random object (upto 7 levels ood) on normal floor
+F:C:88:5:613:*25
+
+# Quest exit
+F:<:6:3
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X......m.................H.........b...m......X
+D:X.............b...............................X
+D:X.......................m.....m.......H...b.C.X
+D:X...............m.!........b.............FFFf.X
+D:X.........m!............H....!........fffFFFffX
+D:X..................................fffFFFFFFfFX
+D:XFFf..............................fFFFFff..fffX
+D:XFFFff........FFFFFF...........fffFFFfff......X
+D:XfFFFFfff....FFFFFFFf.......fffFFFFFf.........X
+D:X.fFFFFFFff.FFFFFFFFFfF..fffFFFFFFff..........X
+D:X..fFFFFFFFffFFFfffFFFfffFFFFFFFFf............X
+D:X...fFFFFFFFFFFff.ffFFFFFFFFFFFff.............X
+D:X....fffFFFFFFff...ffFFFFFFFFFf...............X
+D:X.......ffFFFf.......ffffFFfff................X
+D:X.........fff.................................X
+D:X.............................................X
+D:X.............................................X
+D:X.............................................X
+D:X..................................<..........X
+D:X.............................................X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:22:26
diff --git a/lib/edit/haunted.map b/lib/edit/haunted.map
new file mode 100644
index 00000000..49f72d5b
--- /dev/null
+++ b/lib/edit/haunted.map
@@ -0,0 +1,49 @@
+# permanent wall
+F:X:61:0
+
+# granite
+F:#:57:0
+
+# up staircase
+F:<:6:0
+
+# Floor
+F:.:1:0
+
+# Locked Door
+F:D:38:0
+
+# Secret Door
+F:S:48:0
+
+# Great item
+F:g:1:0:0:*:*
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXX...D.........................X
+D:XXX...XXXXXXXXXXXXXXXXXXXXXXXXX.X
+D:XXX...X....X....X....X....X...X.X
+D:XXX...X....X....X....X....X...X.X
+D:XXX...X....X....X....X....X...X.X
+D:XXXDXXXDXXXXDXXXXDXXXXDXXXXDXXX.X
+D:XXX.............................X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.X
+D:X.S.....X.....X.....X.....X...X.X
+D:X.X.....X.....X.....X.....X...X.X
+D:X.X.....X.....X.....X.....X...X.X
+D:X.X.....X.....X.....X.....X...X.X
+D:XgX.....X.....X.....X.....X...X.X
+D:XXXDXXXXXDXXXXXDXXXXXDXXXXXDXXX.X
+D:XXX.............................X
+D:XXXXXXXDXXXXXDXXXXXDXXXXXDXXXXXDX
+D:XgX<....X.....X.....X.....X.....X
+D:X.X.....X.....X.....X.....X.....X
+D:X.X.....X.....X.....X.....X.....X
+D:X.X.....X.....X.....X.....X.....X
+D:X.S.....X.....X.....X.....X.....X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:5
+
diff --git a/lib/edit/k_info.txt b/lib/edit/k_info.txt
new file mode 100644
index 00000000..aba86074
--- /dev/null
+++ b/lib/edit/k_info.txt
@@ -0,0 +1,6418 @@
+# File: k_info.txt
+
+
+# This file is used to initialize the "lib/data/k_info.raw" file, which is
+# used to initialize the "object kind" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/data/k_info.raw" file.
+
+# Available slots are marked with # XXX: 294, 299, 444-464, ...
+
+# XXX XXX Add some "IGNORE_XXX" flags to Rings, Amulets, etc.
+
+# The old "MULTI_HUED" objects are now "violet", and no other object
+# is violet, so all six violet objects can be made "multi-hued", though
+# this would be a heinous hack. XXX XXX
+
+# Note that object zero is used for the "stack" picture (unused).
+
+
+# Version stamp (required)
+
+V:2.0.0
+
+
+##### Something special #####
+
+N:0:something
+G:&:w
+
+
+##### Mushrooms #####
+
+N:1:Blindness
+G:,:d
+I:80:1:500
+W:5:0:1:0
+A:5/1
+D:'E'ating this mushrooms will blind you. You cannot cast magic
+D:or see monsters when you are blinded. You can still use magic items or
+D:quaff potions.
+
+N:2:Paranoia
+G:,:d
+I:80:2:500
+W:5:0:1:0
+A:5/1
+D:'E'ating this mushroom will make you scared.
+D:You will not be able to hit your enemies in combat if you're scared.
+
+N:3:Confusion
+G:,:d
+I:80:3:500
+W:5:0:1:0
+A:5/1
+D:'E'ating this mushroom will confuse you. You will not be able to cast spells,
+D:use wands, staves or scrolls. You can still quaff potions, though.
+
+N:4:Hallucination
+G:,:d
+I:80:4:500
+W:10:0:1:0
+A:10/1
+D:'E'ating this mushroom will make you hallucinate.
+D:You will not be able to recognise any monster or item.
+
+N:5:Cure Poison
+G:,:d
+I:80:12:500
+W:10:0:1:60
+A:10/1
+D:'E'ating this mushroom will cure you from poison.
+
+N:6:Cure Blindness
+G:,:d
+I:80:13:500
+W:10:0:1:50
+A:10/1
+D:'E'ating this mushroom will cure you from blindness.
+
+N:7:Cure Paranoia
+G:,:d
+I:80:14:500
+W:10:0:1:25
+A:10/1
+D:'E'ating this mushroom will cure your paranoia. Paranoia is the state when you are
+D:too afraid to attack monsters.
+
+N:8:Cure Confusion
+G:,:d
+I:80:15:500
+W:10:0:1:50
+A:10/1
+D:'E'ating this mushroom will cure your confusion. Confusion is when you are too confused
+D:to cast spells, zap staves, aim wands or read scrolls.
+
+N:9:Weakness
+G:,:d
+I:80:6:500
+W:10:0:1:0
+A:10/1
+P:0:5d5:0:0:0
+D:'E'ating this mushroom will reduce your strength by one point.
+
+N:10:Unhealth
+G:,:d
+I:80:10:500
+W:15:0:1:50
+A:15/1
+P:0:10d10:0:0:0
+D:'E'ating this mushroom will reduce your constitution by one point.
+
+N:11:Restore Constitution
+G:,:d
+I:80:18:500
+W:20:0:1:350
+A:20/1
+D:'E'ating this mushroom will restore your constitution. Your constitution
+D:needs restoring when it is displayed in yellow.
+
+N:12:Restoring
+G:,:d
+I:80:19:500
+W:20:0:1:1000
+A:20/8:30/4:40/1
+D:'E'ating this mushroom will restore your strength, dexterity, constitution,
+D:intelligence, wisdom and charisma. These need restoring when they
+D:are displayed in yellow.
+
+N:13:Stupidity
+G:,:d
+I:80:8:500
+W:15:0:1:0
+A:15/1
+D:'E'ating this mushroom will reduce your intelligence by one point.
+D:That's a bad thing.
+
+N:14:Naivety
+G:,:d
+I:80:9:500
+W:15:0:1:0
+A:15/1
+D:'E'ating this mushroom will reduce your wisdom by one point.
+D:That's a bad thing.
+
+N:15:Poison
+G:,:d
+I:80:0:500
+W:5:0:1:0
+A:5/1:5/1
+P:0:4d4:0:0:0
+D:'E'ating this mushroom will poison you. Poisoning makes you lose one hitpoint
+D:per turn until you magically stop the poison or until your body has
+D:fought off the poison.
+D:That's a bad thing.
+
+N:16:Sickness
+G:,:d
+I:80:7:500
+W:10:0:1:0
+A:10/1
+P:0:4d4:0:0:0
+D:'E'ating this mushroom will reduce your constitution by one point.
+D:It will also damage you quite severely in the process.
+D:That's a bad thing.
+
+N:17:Paralysis
+G:,:d
+I:80:5:500
+W:20:0:1:0
+A:20/1
+D:'E'ating this mushroom will paralyse you for a certain time.
+D:Any nearby monsters will take this opportunity to kill you.
+D:That's a bad thing.
+
+N:18:Restore Strength
+G:,:d
+I:80:17:500
+W:20:0:1:350
+A:20/1
+D:'E'ating this mushroom will restore your strength. Your strength
+D:needs restoring when it is displayed in yellow.
+
+N:19:Disease
+G:,:d
+I:80:11:500
+W:20:0:1:50
+A:20/1
+P:0:10d10:0:0:0
+D:'E'ating this mushroom will reduce your strength by one point.
+D:It will also damage you quite severely in the process.
+D:That's a bad thing.
+
+N:20:Cure Serious Wounds
+G:,:d
+I:80:16:500
+W:15:0:1:75
+A:15/1
+D:'E'ating this mushroom will heal several hit points. Your hit points
+D:need healing when they are displayed in yellow or red.
+
+##### Normal Food #####
+
+N:21:& Ration~ of Food
+G:,:U
+I:80:35:5000
+W:0:0:10:3
+A:0/1:5/1:10/1
+D:Lightweight and filling. Not an incredible taste experience, but that'd be asking a bit much.
+D:You can 'E'at it.
+
+N:22:& Hard Biscuit~
+G:,:U
+I:80:32:500
+W:0:0:2:1
+D:It doesn't look great, and 'E'ating it will only fill your stomach a bit,
+D:for a short time.
+
+N:23:& Strip~ of Venison
+G:,:u
+I:80:33:1500
+W:0:0:2:2
+D:It looks great, and 'E'ating it will fill your stomach well.
+
+N:24:& Slime Mold~
+G:,:g
+I:80:36:3000
+W:1:0:5:2
+A:1/1
+D:It looks disgusting, but if you really want to you can 'E'at it.
+D:Not an incredible taste experience, but that'd be asking a bit much.
+
+# New - now Lembas works as a scroll of Satisfy Hunger
+N:25:& Lembas~
+G:,:B
+I:80:37:0
+W:5:0:3:10
+A:5/1:10/1:20/1
+D:A sort of cake, tasty and sustaining. It even helps to overcome weariness. Its fabrication
+D:is a secret of the elves. If you 'E'at it, you will be full.
+
+N:26:& Pint~ of Fine Ale
+G:,:y
+I:80:38:500
+W:0:0:5:1
+D:A bottle of a dark beer-like beverage. You can drink it by pressing 'E'.
+
+N:27:& Pint~ of Fine Wine
+G:,:r
+I:80:39:1000
+W:0:0:10:2
+D:A bottle of fine wine. You can drink it by pressing 'E'.
+
+##### Extra digger #####
+
+N:28:& Mattock~
+G:\:D
+I:20:7:3
+W:50:0:250:700
+A:50/2
+P:0:1d8:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:This is a digging tool. Use it to dig in walls, destroy doors, or cut wood.
+
+# The Blue Stone 'Toris Mejistos' -- see artifact list
+
+N:29:& Blue Stone~
+G:":B
+I:40:18:0
+W:60:0:3:90000
+F:INSTA_ART | SPECIAL_GENE
+
+##### Edged Weapons #####
+
+N:30:& Broken Dagger~
+G:|:D
+I:23:1:0
+W:0:0:5:1
+A:0/2:5/2
+P:0:1d1:-2:-4:0
+F:SHOW_MODS
+D:The blade itself is a foot long and broken off not far above the hilt.
+
+N:31:& Bastard Sword~
+G:|:W
+I:23:21:0
+W:15:0:140:350
+A:15/1
+P:0:3d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This is a long, double-edged sword with a plain hilt that could
+D:be wielded in one or two hands. It's called a "bastard sword" because in
+D:size, it falls between the broad sword and the two-handed sword, thus not
+D:having a family of its own. It's typically around 51 inches long.
+D:It is effective for cutting through tougher armours. It could be used for
+D:thrusting, but most wielders swing it like a bat.
+
+N:32:& Scimitar~
+G:|:W
+I:23:18:0
+W:10:0:130:250
+A:10/1
+P:0:2d5:0:0:0
+F:SHOW_MODS
+D:This oriental blade has 2 edges and is deeply curved. It has a wide
+D:and very sharp end. It is the forefather of the sabre.
+
+N:33:& Tulwar~
+G:|:W
+I:23:15:0
+W:5:0:100:200
+A:5/1
+P:0:2d4:0:0:0
+F:SHOW_MODS
+D:This vicious sword is half sword and half club, with a slight hook on the tip.
+
+N:34:& Broad Sword~
+G:|:W
+I:23:16:0
+W:10:0:150:255
+A:10/1:15/1
+P:0:2d5:0:0:0
+F:SHOW_MODS
+D:This broader version of the long sword is a standard weapon in the army
+D:of Gondolin.
+
+N:35:& Short Sword~
+G:|:W
+I:23:10:0
+W:5:0:80:90
+A:5/1
+P:0:1d7:0:0:0
+F:SHOW_MODS
+D:This shorter version of the long sword is a common weapon for rogues
+D:and mages.
+
+N:36:& Blade~ of Chaos
+G:|:v
+I:23:30:0
+W:70:0:180:4000
+A:70/8
+P:0:6d5:0:0:0
+F:ATTR_MULTI
+F:RES_CHAOS | CHAOTIC | SHOW_MODS
+f:RES_CHAOS | CHAOTIC
+D:A mighty sword which seems to be completely blunt. However, it is a conduit
+D:into the realms of pure chaos and strikes its victims with the devastating
+D:might of chaos itself whenever it connects. It gives you resistance to chaos
+D:and it can polymorph, teleport, confuse or drain hit points from the monster
+D:you hit. It occasionally causes earthquakes as well.
+
+N:37:& Two-Handed Sword~
+G:|:W
+I:23:25:0
+W:30:0:200:775
+A:30/1:40/1
+P:0:3d6:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This blade is lot longer, wider and heavier than a long sword. You have to
+D:wield it with two hands. This means that wielding a shield makes fighting
+D:very difficult.
+
+N:38:& Main Gauche~
+G:|:W
+I:23:5:0
+W:3:0:30:25
+A:3/1
+P:0:1d5:0:0:0
+F:SHOW_MODS
+D:This blade is sinuously curved and tipped with a harpoon-like end.
+D:This blade has a large handguard and was designed as an off-hand weapon.
+D:This short but cruel blade is a favourite among orcs.
+
+N:39:& Cutlass~
+G:|:W
+I:23:12:0
+W:5:0:110:85
+A:5/1
+P:0:1d7:0:0:0
+F:SHOW_MODS
+D:This oriental weapon is a short, thick, curving sword
+D:with a single cutting edge. This simple slashing weapon
+D:is typically carried by buccaneers, pirates, and sailors.
+
+N:40:& Executioner's Sword~
+G:|:r
+I:23:28:0
+W:40:0:260:850
+A:40/1
+P:0:4d5:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:These weapons have been built in all sizes. They are custom-made
+D:for warriors that want to set out and kill their archenemy. These
+D:blades are rare, costly and very deadly.
+
+N:41:& Katana~
+G:|:W
+I:23:20:0
+W:20:0:120:400
+A:20/1
+P:0:3d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:The katana is a long blade with only a small disk for a guard.
+D:Its hilt is long enough for two hands, though it could be used
+D:with only one hand, and is usually wrapped in cloth or leather.
+D:The art of forging such swords is largely unknown in this part
+D:of Middle-earth, and such weapons are typically imported from
+D:distant lands.
+
+N:42:& Long Sword~
+G:|:W
+I:23:17:0
+W:10:0:130:300
+A:10/1:20/1
+P:0:2d5:0:0:0
+F:SHOW_MODS
+D:A long straight sword, tapering to a pronounced point. Mainly good for
+D:piercing attacks, but it can be used for slashing, too. It is a very
+D:popular design and has become standard issue in many armies.
+
+N:43:& Dagger~
+G:|:W
+I:23:4:0
+W:0:0:12:10
+A:0/1:5/1:10/1:20/1
+P:0:1d4:0:0:0
+F:SHOW_MODS
+D:It's the standard weapon of rogues and thieves. The blade is
+D:a foot long.
+
+N:44:& Rapier~
+G:|:W
+I:23:7:0
+W:5:0:40:42
+A:5/1
+P:0:1d6:0:0:0
+F:SHOW_MODS
+D:The rapier's hilt consisted of a pair of oval guards pierced with holes,
+D:recurved quillions, and a knuckle guard. The guard is very intricate
+D:and very effective as protection.
+
+N:45:& Sabre~
+G:|:W
+I:23:11:0
+W:5:0:50:50
+A:5/1
+P:0:1d7:0:0:0
+F:SHOW_MODS
+D:A long, one-edged, slightly curved sword with a knuckle guard and short
+D:hilt. It is two-edged in its lower part.
+
+N:46:& Small Sword~
+G:|:W
+I:23:8:0
+W:5:0:75:48
+A:5/1
+P:0:1d6:0:0:0
+F:SHOW_MODS
+D:It's the favourite weapon of strong mages and thieves. The blade is
+D:about twenty inches long. It's very easy to handle, although it is a lot less
+D:efficient than the longer and heavier designs.
+
+N:47:& Broken Sword~
+G:|:D
+I:23:2:0
+W:0:0:30:2
+A:0/2:5/2
+P:0:1d2:-2:-4:0
+F:SHOW_MODS
+D:Just a hilt and a few inches of blade, broken off in a jagged stump.
+D:Probably worthless.
+
+##### Hafted Weapons #####
+
+N:48:& Ball-and-Chain~
+G:\:D
+I:21:6:0
+W:20:0:150:200
+A:20/1
+P:0:2d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This weapon has a ball linked with a chain to a wooden handle.
+D:Preferred tactic is smashing the brains of your opponent.
+
+N:49:& Whip~
+G:\:D
+I:21:2:0
+W:3:0:30:30
+A:3/1
+P:0:1d6:0:0:0
+F:SHOW_MODS
+D:Think Doctor Jones. This weapon is light and easy to fight with.
+D:It has nasty barbs and hooks fixed to the thong to make it useful
+D:in combat. Whips give easily multiple attacks.
+
+N:50:& Flail~
+G:\:D
+I:21:13:0
+W:10:0:150:353
+A:10/1
+P:0:2d6:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This weapon was originally used to cut corn. More warlike versions
+D:sport a large blade stuck on a wooden handle. The hinge allows it to get
+D:past enemy defences or to strike with added momentum when used skillfully.
+
+N:51:& Two-Handed Flail~
+G:\:y
+I:21:18:0
+W:45:0:280:590
+A:45/1
+P:0:3d6:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This two-handed version of the flail gives the fighter a fearsome
+D:weapon that can do a fair amount of damage. It typically has several
+D:spiked metal lumps on chains.
+
+N:52:& Morning Star~
+G:\:D
+I:21:12:0
+W:10:0:150:396
+A:10/1
+P:0:2d6:0:0:0
+F:SHOW_MODS
+D:This weapon consists of a large club with chains that have wooden balls
+D:with metal spikes on the end.
+
+N:53:& Mace~
+G:\:D
+I:21:5:0
+W:5:0:120:130
+A:5/1
+P:0:2d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This weapon is a club ending in a sphere. The sphere is studded
+D:with metal shards, and thus can both crush and cut your adversary.
+
+N:54:& Quarterstaff~
+G:\:U
+I:21:3:0
+W:10:0:150:200
+A:10/1
+P:0:1d9:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A long, wooden pole, usually the height of the wielder. Four of them can be
+D:made out of the trunk of one young tree, hence the name. The quarterstaff
+D:is an excellent weapon for travellers as it doubles both as a walking staff
+D:and as a deterrent against brigands. The quarterstaff is used more in
+D:fencing and brawling than melee combat.
+
+N:55:& War Hammer~
+G:\:D8
+I:21:8:0
+W:5:0:120:225
+A:5/1
+P:0:3d3:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A large hammer, designed to crush skulls with mighty strikes.
+
+N:56:& Lead-Filled Mace~
+G:\:D
+I:21:15:0
+W:15:0:180:502
+A:15/1
+P:0:3d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A large, mean mace filled with lead in order to wreak a maximum of havoc.
+
+N:57:& Mace~ of Disruption
+G:\:v
+I:21:20:0
+W:80:0:400:4300
+A:80/5
+P:0:5d8:0:0:0
+F:SLAY_UNDEAD | SHOW_MODS | MUST2H
+f:MUST2H | SLAY_UNDEAD
+D:This mace is custom-made for priests that go out to destroy evil.
+D:It is deadly, especially for undead.
+
+N:58:& Lucerne Hammer~
+G:\:B
+I:21:10:0
+W:10:0:120:376
+A:10/1
+P:0:2d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A war hammer combined with a spearpoint, mounted on a long pole.
+
+##### Polearms #####
+
+N:59:& Beaked Axe~
+G:/:s
+I:22:10:0
+W:15:0:180:408
+A:15/1
+P:0:2d6:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This polearm has a beak mounted opposite the blade.
+
+N:60:& Glaive~
+G:/:s
+I:22:13:0
+W:20:0:190:363
+A:20/1
+P:0:2d6:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A polearm with a long, slightly curved knife-like blade. It has spurs on
+D:the dull side of the blade. It's primarily a slashing and chopping weapon. Glaives
+D:are often used to protect archers, crossbowmen, and gunners while they reload.
+D:Outside of combat they are a popular processional weapon and therefore many
+D:have ornately carved blades.
+
+N:61:& Halberd~
+G:/:s
+I:22:15:0
+W:25:0:190:430
+A:25/1
+P:0:3d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:The halberd has a broad, short axe blade on a 5 - 6ft long haft, with a
+D:spearpoint at the top, often a back-spike and occasionally a butt-spike. Used to
+D:combat heavier armour. It's usually used for cutting and stabbing. It's the most
+D:versatile polearm in Middle-earth. The axe is used in general melee. The top
+D:pike is used to pierce armour, or is set against a cavalry charge. The back
+D:hook could unseat horses, trip opponents, parry a blow, or be a general
+D:piercing weapon.
+
+N:62:& Awl-Pike~
+G:/:s
+I:22:4:0
+W:10:0:160:340
+A:10/1
+P:0:1d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This is a polearm with a long square-sectioned spike on the end.
+
+N:63:& Pike~
+G:/:s
+I:22:8:0
+W:15:0:160:358
+A:15/1
+P:0:2d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A staff, 16-18 feet long, that has a small piercing head about 10 inches
+D:long. The pike is often used by infantry to fend off cavalry. It is very
+D:effective against mounted troops.
+
+N:64:& Spear~
+G:/:s
+I:22:2:0
+W:5:0:50:36
+A:5/1
+P:0:1d6:0:0:0
+F:SHOW_MODS
+D:Spears tend to have a strong, wide, leaf-shaped head with a ridge down the
+D:middle. The spearhead is attached to the wooden shaft by a socket. The
+D:sockets are usually riveted to the shaft and some have two small lugs near
+D:the base of the socket to allow the head to be possibly bound on as well.
+D:This spear is 7 feet long.
+
+N:65:& Trident~
+G:/:y
+I:22:5:0
+W:5:0:70:120
+A:5/1
+P:0:1d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:The trident is based on the pitchfork. In fact, when not used as a weapon,
+D:it is often employed as a pitchfork. It is famous for its uses in
+D:gladiatorial arenas. It is used much like a spear and could even be thrown
+D:like one in desperate situations.
+
+N:66:& Lance~
+G:/:s
+I:22:20:0
+W:10:0:300:230
+A:10/1
+P:0:2d8:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This is the original polearm. It is shaped like a spear but is bigger. It's
+D:meant to fend off enemies, not to be thrown.
+
+N:67:& Great Axe~
+G:/:s
+I:24:25:0
+W:40:0:230:500
+A:40/1
+P:0:4d4:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:A huge and heavy two-headed axe.
+
+N:68:& Battle Axe~
+G:/:s
+I:22:22:0
+W:15:0:170:334
+A:15/1
+P:0:2d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:Nordic polearm with a broad blade and a hook mounted on the end of the shaft.
+D:The Nordics' take on the halberd. The polearm of choice for many Nordics,
+D:ideally suited for slashing, thrusting, and unseating cavalry.
+
+N:69:& Lochaber Axe~
+G:/:D
+I:22:28:0
+W:45:0:250:750
+A:45/1
+P:0:3d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:Nordic polearm with a broad blade and a hook mounted on the end of the shaft.
+D:A Nordic version of the halberd. The polearm of choice for many Nordics,
+D:this weapon is ideally suited for slashing, thrusting, and unseating cavalry.
+
+N:70:& Broad Axe~
+G:/:s
+I:24:11:0
+W:15:0:160:304
+A:15/1
+P:0:2d6:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A one-headed axe made for combat, with an elongated moon-shaped blade.
+
+N:71:& Scythe~
+G:/:s
+I:22:17:0
+W:45:0:250:800
+A:45/1
+P:0:5d3:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A simple farm implement, converted into a weapon by slightly straightening
+D:its blade and putting it in line with its pole, instead of the typical
+D:right angle.
+
+N:72:& Scythe~ of Slicing
+G:/:r
+I:22:30:0
+W:80:0:250:10000
+A:80/20
+P:0:8d4:0:0:0
+F:SHOW_MODS | MUST2H | WOUNDING | VORPAL
+f:MUST2H | VORPAL | WOUNDING
+D:The simple design of the war scythe, but this one uses a finely crafted and
+D:incredibly sharp steel blade which causes terrible wounds when it hits.
+
+##### Bows, Crossbows, Slings #####
+
+N:73:& Short Bow~
+G:}:U
+I:19:12:0
+W:3:0:30:50
+A:3/1:50/2
+F:SHOW_MODS
+D:A piece of bent wood, fitted with a string. Easy to transport and use, but
+D:its effect is not very impressive. You can 'f'ire it after you 'w'ield it.
+
+N:74:& Long Bow~
+G:}:U
+I:19:13:0
+W:10:0:40:120
+A:10/1:70/2
+F:SHOW_MODS
+D:A bow almost as long as a human. It takes considerable strength and skill to
+D:use and is rather awkward to carry around inside buildings. Nevertheless, it
+D:shoots arrows with astonishing force. You can 'f'ire it after you 'w'ield it.
+
+N:75:& Light Crossbow~
+G:}:s
+I:19:23:0
+W:15:0:110:140
+A:15/1:60/2
+F:SHOW_MODS
+D:A metal bow mounted on a wooden stock. It is used for shooting bolts. This
+D:design is relatively light and not too difficult to cock, but also shoots its
+D:quarrels with less force. You can 'f'ire with it after you 'w'ield it.
+
+N:76:& Heavy Crossbow~
+G:}:s
+I:19:24:0
+W:30:0:200:300
+A:30/1:80/2
+F:SHOW_MODS
+D:A metal bow mounted on a wooden stock, with attached cocking mechanism. It
+D:takes considerable time and strength to cock it and it's rather heavy.
+D:However, it hurls its ammunition with incredible force. You can 'f'ire with
+D:it after you 'w'ield it.
+
+N:77:& Sling~
+G:}:u
+I:19:2:0
+W:1:0:5:5
+A:1/1:40/2
+F:SHOW_MODS
+D:A simple cloth or leather pouch with two strings attached. It is used to hurl
+D:pebbles or iron shots. You can 'f'ire with it after you 'w'ield it.
+
+##### Missiles #####
+
+N:78:& Arrow~
+G:{:U
+I:17:1:0
+W:3:0:2:1
+A:3/1:15/1:50/1
+P:0:1d4:0:0:0
+F:SHOW_MODS
+D:A simple metal head on a piece of wood or bamboo, fitted with some feathers.
+D:You can use it for 'f'iring a bow.
+
+N:79:& Seeker Arrow~
+G:{:G
+I:17:2:0
+W:55:0:2:20
+A:55/2:80/2
+P:0:4d4:0:0:0
+F:SHOW_MODS
+D:A precision-made arrow, which allows you to hit precisely the most vulnerable
+D:place of an opponent. You can use it for 'f'iring a bow.
+
+N:80:& Bolt~
+G:{:s
+I:18:1:0
+W:3:0:3:2
+A:3/1:25/1:60/1
+P:0:1d5:0:0:0
+F:SHOW_MODS
+D:A short metal arrow, to be 'f'ired with a crossbow.
+
+N:81:& Seeker Bolt~
+G:{:B
+I:18:2:0
+W:65:0:3:25
+A:65/2:90/2
+P:0:4d5:0:0:0
+F:SHOW_MODS
+D:A precision-made bolt, which allows you to hit exactly the most vulnerable
+D:place of an opponent. You can use it for 'f'iring a crossbow.
+
+N:82:& Rounded Pebble~
+G:{:s
+I:16:0:0
+W:0:0:4:1
+A:0/1:10/2
+P:0:1d2:0:0:0
+F:SHOW_MODS
+D:Small round stones. When fired with a sling, they could even hurt a giant.
+D:You can use them for 'f'iring a sling.
+
+N:83:& Iron Shot~
+G:{:s
+I:16:1:0
+W:3:0:5:2
+A:3/1:40/2
+P:0:1d4:0:0:0
+F:SHOW_MODS
+D:Metal balls, made for shooting with slings. You can use them for 'f'iring a
+D:sling.
+
+##### Shovels and Picks #####
+
+N:84:& Shovel~
+G:\:s
+I:20:1:1
+W:1:0:60:10
+A:5/2
+P:0:1d2:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:A simple digging tool for shovelling away rubble and maybe even soft rock.
+
+N:85:& Gnomish Shovel~
+G:\:G
+I:20:2:2
+W:20:0:60:100
+A:20/3
+P:0:1d2:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:Crafted by the gnomes, its design profits greatly from the gnomes' expertise
+D:honed in the burrowing of their hovels.
+
+N:86:& Dwarven Shovel~
+G:\:B
+I:20:3:3
+W:40:0:120:200
+A:40/4
+P:0:1d3:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:The lighter digging tool used by dwarves to remove debris, but also good
+D:enough to clear away bits of rock when no pick is easily available.
+
+N:87:& Pick~
+G:\:s
+I:20:4:1
+W:5:0:150:50
+A:10/2
+P:0:1d3:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:A heavy digging tool, primarily for earthworking, but also good for tunnelling
+D:through stone, if one is willing to perform the time-consuming labour.
+
+N:88:& Orcish Pick~
+G:\:g
+I:20:5:2
+W:30:0:180:300
+A:30/3
+P:0:1d3:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:Although orcs tend to dig rather untidy mines and overcome difficulties in
+D:this work less by skill than mere stubbornness, they have amassed
+D:quite some expertise in mining, which has gone into this digging tool.
+
+N:89:& Dwarven Pick~
+G:\:b
+I:20:6:3
+W:50:0:200:600
+A:50/4
+P:0:1d4:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:The dwarves, miners of legend, have made this pick, which is so expertly
+D:crafted that even weaklings can bore through solid rock with it.
+
+##### Armour #####
+
+N:90:& Elven Cloak~
+G:(:G
+I:35:2:0
+W:30:0:5:1500
+A:30/4
+P:4:0d0:0:0:4
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_FIRE | IGNORE_ELEC
+F:STEALTH | SEARCH | LUCK
+f:STEALTH
+D:A wonderfully light cloak coloured in brown and green hues. Its colouring
+D:greatly helps the wearer to avoid undesired attention. Wearing it makes you
+D:feel lucky and somehow you seem to see what was meant to stay unseen.
+
+N:91:& Pair~ of Soft Leather Boots
+G:]:U
+I:30:2:0
+W:3:0:20:7
+A:3/1
+P:2:1d1:0:0:0
+D:A pair of low boots, comfortable to wear.
+
+N:92:& Pair~ of Hard Leather Boots
+G:]:U
+I:30:3:0
+W:5:0:40:12
+A:5/1
+P:3:1d1:0:0:0
+D:A pair of boots, with hardened leather at the caps, offering a little
+D:extra protection for the feet.
+
+N:93:& Pair~ of Metal Shod Boots
+G:]:s
+I:30:6:0
+W:20:0:80:50
+A:20/1
+P:6:1d1:0:0:0
+D:Heavy boots, with metal strips at the toes, heels and other vulnerable parts,
+D:to better protect the wearer's feet from harm.
+
+N:94:& Hard Leather Cap~
+G:]:u
+I:32:2:0
+W:3:0:15:12
+A:3/1
+P:2:0d0:0:0:0
+D:A piece of protective headgear made from hardened leather, just covering the
+D:skull.
+
+N:95:& Metal Cap~
+G:]:s
+I:32:3:0
+W:10:0:20:30
+A:10/1
+P:3:1d1:0:0:0
+D:A metal skullcap with nose and cheekguards.
+
+N:96:& Iron Helm~
+G:]:s
+I:32:5:0
+W:20:0:75:75
+A:20/1
+P:5:1d3:0:0:0
+D:A large helmet that can protect the entire head. Ventilation and bad vision
+D:can be a problem, however.
+
+N:97:& Steel Helm~
+G:]:W
+I:32:6:0
+W:40:0:60:200
+A:40/1
+P:6:1d3:0:0:0
+D:A helmet which protects the entire head. The expensive steel as base material
+D:allows it to offer very good protection while being fairly light.
+
+N:98:& Iron Crown~
+G:]:s
+I:33:10:0
+W:45:0:20:500
+A:45/1
+P:0:1d1:0:0:0
+D:An iron circlet which might be worn, but which is purely ornamental unless it
+D:has special powers.
+
+N:99:& Golden Crown~
+G:]:y
+I:33:11:0
+W:45:0:30:1000
+A:45/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID
+D:A gilded crown, which just looks good. Sometimes such headgear also has
+D:additional properties which might make it worth wearing.
+
+N:100:& Jewel Encrusted Crown~
+G:]:v
+I:33:12:0
+W:50:0:40:2000
+A:50/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID
+D:A gorgeous-looking silver crown, adorned with several gems. You might wear it
+D:on your head, if you really think you're worthy.
+
+N:101:& Robe~
+G:(:b
+I:36:2:0
+W:1:0:20:4
+A:1/1:50/1
+P:2:0d0:0:0:0
+D:A full-length garment which can be worn on the body. It is not really
+D:armour, but mages often wear them as they are very light and don't hinder
+D:movement much.
+
+N:102:& Filthy Rag~
+G:(:D
+I:36:1:0
+W:0:0:20:1
+A:0/1
+P:1:0d0:0:0:-1
+D:A piece of discarded cloth, smelly and dirty. Eurgh. You're not going to
+D:wear this, are you?
+
+N:103:& Soft Leather Armour~
+G:(:U
+I:36:4:0
+W:3:0:80:18
+A:3/1
+P:4:0d0:0:0:0
+D:A leather jerkin, light and unencumbering, but not very protective.
+
+N:104:& Soft Studded Leather~
+G:(:U
+I:36:5:0
+W:3:0:90:35
+A:3/1
+P:5:1d1:0:0:0
+D:A leather jerkin with metal studs in critical places offering slightly better
+D:protection.
+
+N:105:& Hard Leather Armour~
+G:(:U
+I:36:6:0
+W:5:0:100:150
+A:5/1
+P:6:1d1:-1:0:0
+D:A leather armour covering only the body. It is made of hardened leather to
+D:make it harder to penetrate. It's also a bit harder to move in, as it is
+D:rather stiff.
+
+N:106:& Hard Studded Leather~
+G:(:U
+I:36:7:0
+W:10:0:110:200
+A:10/1
+P:7:1d2:-1:0:0
+D:A suit of hardened leather armour, reinforced with metal studs.
+
+N:107:& Leather Scale Mail~
+G:(:U
+I:36:11:0
+W:15:0:140:450
+A:15/1
+P:11:1d1:-1:0:0
+D:A suit of armour made of overlapping hardened leather scales. It offers good
+D:protection while still being rather lightweight.
+
+N:108:& Metal Scale Mail~
+G:[:s
+I:37:3:0
+W:25:0:250:550
+A:25/1
+P:13:1d4:-2:0:0
+D:A suit of overlapping metal scales, sewn onto a leather or cloth jerkin.
+
+N:109:& Chain Mail~
+G:[:s
+I:37:4:0
+W:25:0:220:750
+A:25/1
+P:14:1d4:-2:0:0
+D:A suit of interlinked metal rings, to be worn over a woollen garment.
+
+N:110:& Rusty Chain Mail~
+G:[:r
+I:37:1:0
+W:25:0:200:550
+A:25/1
+P:14:1d4:-5:0:-8
+D:This chain mail has rusted beyond repair. It can still be worn, but some of
+D:the rings have gone missing and the rust has made the suit inflexible.
+D:Consequently, it offers very poor protection and is cumbersome to move in.
+
+N:111:& Augmented Chain Mail~
+G:[:s
+I:37:6:0
+W:30:0:270:900
+A:30/1
+P:16:1d4:-2:0:0
+D:A suit of interlinked metal rings, with additional metal plates or scales
+D:covering vulnerable parts of the wearer.
+
+N:112:& Bar Chain Mail~
+G:[:s
+I:37:8:0
+W:35:0:280:950
+A:35/1
+P:18:1d4:-2:0:0
+D:A suit of interlinked metal rings, with additional short metal bars added in
+D:many places to prevent penetration of the armour by piercing attacks.
+
+N:113:& Metal Brigandine Armour~
+G:[:s
+I:37:9:0
+W:35:0:290:1100
+A:35/1
+P:19:1d4:-3:0:0
+D:This is a leather armour with many small metal plates fixed to it, covering
+D:it entirely.
+
+N:114:& Partial Plate Armour~
+G:[:W
+I:37:12:0
+W:45:0:260:1200
+A:45/1
+P:22:1d6:-3:0:0
+D:An armour made of steel plates, covering only the body of the wearer.
+
+N:115:& Metal Lamellar Armour~
+G:[:W
+I:37:13:0
+W:45:0:340:1250
+A:45/1
+P:23:1d6:-3:0:0
+D:Lamellar consists of small rectangular plates (lames) attached to each other
+D:at each edge or corner with leather lacings through small holes in the plates.
+
+N:116:& Full Plate Armour~
+G:[:W
+I:37:15:0
+W:45:0:380:1350
+A:45/1
+P:25:2d4:-3:0:0
+D:A suit of armour made of metal plates, covering the body, arms and upper legs.
+D:A very effective but very heavy armour.
+
+N:117:& Ribbed Plate Armour~
+G:[:W
+I:37:18:0
+W:50:0:380:1500
+A:50/1
+P:28:2d4:-3:0:0
+D:This full suit of armour has been strengthened in places to better deflect or
+D:absorb blows.
+
+N:118:& Adamantite Plate Mail~
+G:[:G
+I:37:30:0
+W:75:0:420:20000
+A:75/4
+P:40:2d4:-4:0:0
+F:IGNORE_ACID
+D:A suit of plate armour fashioned from an unbreakable crystal by mage-smiths.
+
+N:119:& Mithril Plate Mail~
+G:[:B
+I:37:25:0
+W:60:0:300:15000
+A:60/3
+P:35:2d4:-3:0:0
+F:IGNORE_ACID
+D:A full suit of plate armour, fashioned from the rare true-silver. Only the
+D:dwarves know the secret of making armour or weapons of this metal.
+
+N:120:& Mithril Chain Mail~
+G:[:B
+I:37:20:0
+W:55:0:150:7000
+A:55/3
+P:28:1d4:-1:0:0
+F:IGNORE_ACID
+D:A suit of chain mail, made by dwarven smiths from the rare and precious metal
+D:also called true-silver.
+
+N:121:& Double Chain Mail~
+G:[:s
+I:37:7:0
+W:30:0:250:850
+A:30/1
+P:16:1d4:-2:0:0
+D:A suit of chain mail, with an additional layer of mail in some places.
+
+# This shield does not belong here
+
+N:122:& Shield~ of Deflection
+G:[:B
+I:34:10:0
+W:70:0:100:10000
+A:70/3
+P:10:1d1:0:0:10
+F:IGNORE_ACID
+D:A large shield fashioned from a metal alloy that is not subject to corrosion.
+D:It was especially crafted to better deflect attacks.
+
+### The Cloaks ###
+
+N:123:& Cloak~
+G:(:g
+I:35:1:0
+W:1:0:10:3
+A:1/1:20/1
+P:1:0d0:0:0:0
+D:A cloth coat typically worn as a loose outer garment. It is spacious enough
+D:to be worn even over bulky metal armour.
+
+N:124:& Shadow Cloak~
+G:(:D
+I:35:6:1
+W:60:0:5:7500
+A:75/4
+P:6:0d0:0:0:4
+F:RES_DARK | RES_LITE | STEALTH
+f:STEALTH
+D:A rare cloak imbued with magic to radiate a strange twilight, absorbing both
+D:extreme brightness and darkness.
+
+### The Gloves ###
+
+N:125:& Set~ of Leather Gloves
+G:]:U
+I:31:1:0
+W:1:0:5:3
+A:1/1
+P:1:0d0:0:0:0
+D:Light gloves which do not seriously hinder finger movements, while still
+D:protecting the hands somewhat.
+
+N:126:& Set~ of Gauntlets
+G:]:U
+I:31:2:0
+W:10:0:25:35
+A:10/1
+P:2:1d1:0:0:0
+D:Metal gloves protecting the hands up to the middle of the lower arm.
+
+N:127:& Set~ of Cesti
+G:]:W
+I:31:5:0
+W:50:0:40:100
+A:50/1
+P:5:1d1:0:0:0
+D:A set of metal gloves with nasty spikes and barbs. Though originally made to
+D:help in combat, the additional metal on the backs of the hands also offers a
+D:lot more protection.
+
+### The shields ###
+
+N:128:& Small Leather Shield~
+G:):U
+I:34:2:0
+W:3:0:50:30
+A:3/1
+P:2:1d1:0:0:0
+D:A small disc of lindenwood, with a leather covering on one side.
+
+N:129:& Large Leather Shield~
+G:):U
+I:34:4:0
+W:15:0:100:120
+A:15/1
+P:4:1d2:0:0:0
+D:A large oval or rectangular shield. It is made of wood, typically linden, and
+D:covered with a layer of hardened leather to offer better protection.
+
+N:130:& Small Metal Shield~
+G:):s
+I:34:3:0
+W:10:0:65:50
+A:10/1
+P:3:1d2:0:0:0
+D:A small shield strengthened with a layer of metal.
+
+N:131:& Large Metal Shield~
+G:):s
+I:34:5:0
+W:30:0:120:200
+A:30/1
+P:5:1d3:0:0:0
+D:A large piece of wood, rectangular or oval in shape, and covered with metal
+D:to strengthen it. It's to be worn strapped to the arm not occupied by the
+D:weapon when fighting.
+
+##### Rings #####
+
+N:132:Strength
+G:=:d
+I:45:24:0
+W:30:0:2:500
+A:30/1
+F:STR | HIDE_TYPE
+f:STR
+D:This bauble magically improves your strength.
+
+N:133:Dexterity
+G:=:d
+I:45:26:0
+W:30:0:2:500
+A:30/1
+F:DEX | HIDE_TYPE
+f:DEX
+D:This piece of jewellery magically improves your agility.
+
+N:134:Constitution
+G:=:d
+I:45:27:0
+W:30:0:2:500
+A:30/1
+F:CON | HIDE_TYPE
+f:CON
+D:This ring magically grants you health, improving your constitution.
+
+N:135:Intelligence
+G:=:d
+I:45:25:0
+W:30:0:2:500
+A:30/1
+F:INT | HIDE_TYPE
+f:INT
+D:This magical piece of jewellery makes you smarter.
+
+N:136:Speed
+G:=:d
+I:45:31:0
+W:75:0:2:100000
+A:75/1
+F:SPEED | HIDE_TYPE
+f:SPEED
+D:This wonderful ring grants you additional energy, allowing you to act faster.
+
+N:137:Searching
+G:=:d
+I:45:23:0
+W:5:0:2:250
+A:5/1
+F:SEARCH | HIDE_TYPE
+f:SEARCH
+D:This ring magically improves your attention, so you can detect hidden things better.
+
+# New : It can be activated but at the cost of its destruction
+N:138:Teleportation
+G:=:d
+I:45:4:0
+W:5:0:2:250
+A:5/1
+a:HARDCORE=DEST_TELE
+F:CURSED | TELEPORT | EASY_KNOW | ACTIVATE
+f:TELEPORT
+D:This ring will uncontrollably send you to different places at its whim.
+D:You can use its power once at your will, but it will destroy the ring.
+
+N:139:Slow Digestion
+G:=:d
+I:45:6:0
+W:5:0:2:250
+A:5/1
+F:SLOW_DIGEST | EASY_KNOW
+f:SLOW_DIGEST
+D:This magical bauble grants you some sustenance, allowing you to subsist on less food.
+
+N:140:Fire Resistance
+G:=:d
+I:45:8:0
+W:10:0:2:250
+A:10/1
+F:RES_FIRE | IGNORE_FIRE | EASY_KNOW
+f:RES_FIRE
+D:This piece of jewellery grants you some protection from the burning heat of fire.
+
+N:141:Cold Resistance
+G:=:d
+I:45:9:0
+W:10:0:2:250
+A:10/1
+F:RES_COLD | IGNORE_COLD | EASY_KNOW
+f:RES_COLD
+D:This piece of jewellery grants you some protection from the chilling forces of cold.
+
+N:142:Levitation
+G:=:d
+I:45:7:0
+W:5:0:2:200
+A:5/1
+F:FEATHER | EASY_KNOW
+f:FEATHER
+D:When you put on this ring, you will be able to float just above the floor.
+D:It prevents you from drowning, and all your falls will be painless.
+
+N:143:Poison Resistance
+G:=:d
+I:45:20:0
+W:60:0:2:16000
+A:60/2
+F:RES_POIS | EASY_KNOW
+f:RES_POIS
+D:This magical ring grants protection from poison.
+D:It is rumoured that in deep dungeons monsters can kill you at once if you
+D:don't have poison resistance.
+
+N:144:Free Action
+G:=:d
+I:45:21:0
+W:20:0:2:1500
+A:20/1
+F:FREE_ACT | EASY_KNOW
+f:FREE_ACT
+D:This magical bauble prevents you from being held.
+D:Some monsters will paralyse you and then kill you if you lack free action.
+
+N:145:Weakness
+G:=:d
+I:45:2:-5
+W:5:0:2:0
+A:5/1
+F:CURSED | STR | HIDE_TYPE
+f:STR
+D:This accursed ring will sap your strength, rendering you much weaker as long as you wear it.
+
+N:146:Flames
+G:=:d
+I:45:18:0
+W:50:0:2:3000
+A:50/1
+P:0:0d0:0:0:15
+a:HARDCORE=BA_FIRE_4
+F:RES_FIRE | IGNORE_FIRE | ACTIVATE
+f:RES_FIRE
+D:This fiery circlet grants you protection, makes fire less dangerous and even
+D:allows you to call forth a ball of flame.
+
+N:147:Acid
+G:=:d
+I:45:17:0
+W:50:0:2:3000
+A:50/1
+P:0:0d0:0:0:15
+a:HARDCORE=BA_ACID_4
+F:RES_ACID | IGNORE_ACID | ACTIVATE
+f:RES_ACID
+D:This magical ring is imbued with spells of devouring acid, granting protection against such
+D:assaults and the ability to shoot acid at your foes.
+
+N:148:Ice
+G:=:d
+I:45:19:0
+W:50:0:2:3000
+A:50/1
+a:HARDCORE=BA_COLD_4
+P:0:0d0:0:0:15
+F:RES_COLD | IGNORE_COLD | ACTIVATE
+f:RES_COLD
+D:This ring is imbued with supernatural cold, which makes you less vulnerable to such effects
+D:and occasionally allows you to throw balls of ice at your foes.
+
+N:149:Woe
+G:=:d
+I:45:0:-5
+W:50:0:2:0
+A:50/1
+F:CURSED | TELEPORT | WIS | CHR | HIDE_TYPE | AUTO_CURSE
+D:This accursed ring will turn you into a bumbling fool and, in addition, magically
+D:transports you to places you never wanted to see. It can recurse itself if
+D:you leave it on too long.
+
+N:150:Stupidity
+G:=:d
+I:45:3:-5
+W:5:0:2:0
+A:5/1
+F:CURSED | INT | HIDE_TYPE
+f:INT
+D:This wicked ring feeds off your intellect, magically making you stupid.
+
+N:151:Damage
+G:=:d
+I:45:29:0
+W:20:0:2:500
+A:20/1
+F:HIDE_TYPE
+D:This ring makes your hands magically strong in combat, allowing you to inflict
+D:greater pain with your hand-to-hand attacks.
+
+N:152:Accuracy
+G:=:d
+I:45:28:0
+W:20:0:2:500
+A:20/1
+F:HIDE_TYPE
+D:This ring magically improves your control in combat, allowing you to hit more often.
+
+N:153:Protection
+G:=:d
+I:45:16:0
+W:10:0:2:500
+A:10/1
+D:This ring creates a magical aura around you, protecting you against the blows of your enemies.
+
+N:154:Aggravate Monster
+G:=:d
+I:45:1:0
+W:5:0:2:0
+A:5/1
+F:CURSED | AGGRAVATE | EASY_KNOW | AUTO_CURSE
+f:AGGRAVATE
+D:This faithless ring will draw opponents' attention towards its hapless owner.
+
+N:155:See Invisible
+G:=:d
+I:45:22:0
+W:30:0:2:340
+A:30/1
+F:SEE_INVIS | EASY_KNOW
+f:SEE_INVIS
+D:This magical piece of jewellery allows your eyes to perceive beings otherwise unseen.
+
+N:156:Sustain Strength
+G:=:d
+I:45:10:0
+W:20:0:2:400
+A:20/1
+F:SUST_STR | EASY_KNOW
+f:SUST_STR
+D:This magical bauble protects your physical force against attacks attempting to drain it.
+
+N:157:Sustain Intelligence
+G:=:d
+I:45:11:0
+W:20:0:2:400
+A:20/1
+F:SUST_INT | EASY_KNOW
+f:SUST_INT
+D:This magical ring protects your intellect against attempts to lower it.
+
+N:158:Sustain Wisdom
+G:=:d
+I:45:12:0
+W:20:0:2:400
+A:20/1
+F:SUST_WIS | EASY_KNOW
+f:SUST_WIS
+D:This magical ring protects you from attempts to make you more foolish.
+
+N:159:Sustain Constitution
+G:=:d
+I:45:13:0
+W:20:0:2:400
+A:20/1
+F:SUST_CON | EASY_KNOW
+f:SUST_CON
+D:This magical ring protects your health, making it impossible for your opponents to lower it.
+
+N:160:Sustain Dexterity
+G:=:d
+I:45:14:0
+W:20:0:2:400
+A:20/1
+F:SUST_DEX | EASY_KNOW
+f:SUST_DEX
+D:This magical ring protects your nerves, so that you will never become clumsy.
+
+N:161:Sustain Charisma
+G:=:d
+I:45:15:0
+W:20:0:2:400
+A:20/1
+F:SUST_CHR | EASY_KNOW
+f:SUST_CHR
+D:This ring magically protects your beauty and charm from attempts to make you ugly.
+
+N:162:Slaying
+G:=:d
+I:45:30:0
+W:40:0:2:1000
+A:40/1
+F:SHOW_MODS
+D:This ring magically improves your fighting prowess, allowing to hit more often and harder.
+
+##### Amulets #####
+
+N:163:Brilliance
+G:":d
+I:40:6:0
+W:50:0:3:1000
+A:50/4
+F:INT | WIS | HIDE_TYPE | LITE1
+D:This talisman grants a sharper wit, greater insight and brightness to light dark places.
+
+N:164:Charisma
+G:":d
+I:40:7:0
+W:30:0:3:500
+A:30/1
+F:CHR | HIDE_TYPE
+f:CHR
+D:This amulet grants beauty beyond mere looks.
+
+N:165:Searching
+G:":d
+I:40:5:0
+W:15:0:3:600
+A:15/1
+F:SEARCH | HIDE_TYPE
+f:SEARCH
+D:This amulet grants keen sight, finding things that are hidden.
+
+N:166:Teleportation
+G:":d
+I:40:1:0
+W:10:0:3:250
+A:10/1
+F:CURSED | TELEPORT | EASY_KNOW
+f:TELEPORT
+D:This amulet nastily throws you all over the place.
+
+N:167:Slow Digestion
+G:":d
+I:40:3:0
+W:15:0:3:200
+A:15/1
+F:SLOW_DIGEST | EASY_KNOW
+f:SLOW_DIGEST
+D:This talisman will make you hungry less quickly when worn.
+
+N:168:Acid Resistance
+G:":d
+I:40:4:0
+W:10:0:3:250
+A:10/1
+F:RES_ACID | IGNORE_ACID | EASY_KNOW
+f:RES_ACID
+D:This magical talisman will make the corroding forces of acid less threatening to your health.
+
+N:169:Adornment
+G:":d
+I:40:2:0
+W:10:0:3:20
+A:10/1
+F:EASY_KNOW
+D:This amulet is not magical. It just looks good.
+
+##### Extra armour #####
+
+N:170:& Double Ring Mail~
+G:[:s
+I:37:5:0
+W:25:0:230:700
+A:25/1
+P:15:1d4:-2:0:0
+D:A suit of leather armour with metal rings sewn onto it. In addition, in important parts it is
+D:reinforced with mail.
+
+##### Additional amulets #####
+
+N:171:the Magi
+G:":d
+I:40:8:0
+W:70:0:3:30000
+A:70/8
+P:0:0d0:-4:-4:0
+F:INT | SUST_INT | SEARCH | SPELL_CONTAIN | WIELD_CAST
+F:FREE_ACT | RES_BLIND | RES_CONF |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This rare amulet is highly desirable for mages, as it makes its wearer smarter, more attentive
+D:and impervious to magics which would make their own magic-use impossible.
+
+N:172:Doom
+G:":d
+I:40:0:-5
+W:50:0:3:0
+A:50/1
+F:CURSED | STR | INT | WIS | DEX | CON | CHR | HIDE_TYPE
+F:AUTO_CURSE | CURSE_NO_DROP
+D:This wicked amulet will drain all your abilities, turning you into a mere shadow of yourself. It
+D:is exceedingly hard to get rid of.
+
+##### Scrolls #####
+
+N:173:Enchant Weapon To-Hit
+G:?:d
+I:70:17:0
+W:15:0:5:125
+A:15/1
+D:This magical scroll will allow you to improve the accuracy of a weapon in your possession.
+D:However, weapons which are already very highly enchanted are more difficult to improve
+D:further.
+
+N:174:Enchant Weapon To-Dam
+G:?:d
+I:70:18:0
+W:15:0:5:125
+A:15/1
+D:Upon reading this scroll, a magical enchantment will be placed on a weapon in your
+D:possession, increasing the pain it inflicts when hitting. On very highly enchanted weapons this
+D:enchantment may fail, wasting the scroll.
+
+N:175:Enchant Armour
+G:?:d
+I:70:16:0
+W:15:0:5:125
+A:15/1
+D:This scroll will try to enchant a piece of armour in your possession, making it more effective
+D:in protecting you. Highly enchanted armour is likely not to accept this enchantment, however.
+
+N:176:Identify
+G:?:d
+I:70:12:0
+W:1:0:5:50
+A:1/1:5/1:10/1:30/1
+D:If you read this scroll, the identity of an item you specify will be laid open to you.
+
+N:177:*Identify*
+G:?:d
+I:70:13:0
+W:30:0:5:1000
+A:30/1:50/2:80/1:100/1
+D:This scroll will allow you to gain insight into an object's special properties.
+D:Only the highly magical objects, like rare rings and amulets or very unusual weapons
+D:and armour possess abilities which warrant the use of this magic.
+
+N:178:Rumour
+G:?:d
+I:70:51:0
+W:1:0:5:10
+A:1/1
+D:A piece of paper inscribed with a little text. You may meditate over it or ignore it at your
+D:leisure.
+
+N:179:Chaos
+G:?:d
+I:70:50:0
+W:100:0:5:10000
+A:100/8
+F:IGNORE_FIRE | IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC
+D:A piece of paper inscribed with strange shifting runes. Upon reading them, they will release
+D:a blast of chaotic forces.
+
+N:180:Remove Curse
+G:?:d
+I:70:14:0
+W:10:0:5:100
+A:10/1:20/2:40/2
+D:A scroll inscribed with a beneficial formula. Upon reading it, evil magics will be removed
+D:from your possessions.
+
+N:181:Light
+G:?:d
+I:70:24:0
+W:0:0:5:15
+A:0/1:3/1:10/1
+D:A scroll which will create a permanent magical light, illuminating the surroundings.
+
+N:182:Fire
+G:?:d
+I:70:48:0
+W:50:0:5:1000
+A:50/4
+F:IGNORE_FIRE
+D:A piece of paper inscribed with runes glowing brightly red. Upon reading them, a large blast
+D:of fire will be released.
+
+N:183:Ice
+G:?:d
+I:70:49:0
+W:75:0:5:5000
+A:75/6
+F:IGNORE_COLD
+D:A piece of paper inscribed with light-blue runes that radiate a strange cold. Upon reading them,
+D:a large icy blast will be released.
+
+N:184:Summon Monsters
+G:?:d
+I:70:4:0
+W:1:0:5:0
+A:1/1
+D:This scroll was made by mischievous sorcerers. If it is read, a few creatures will appear to fight
+D:you.
+
+N:185:Phase Door
+G:?:d
+I:70:8:0
+W:1:0:5:15
+A:1/1
+D:Upon reading this scroll, you will be translocated over a short distance.
+
+N:186:Teleportation
+G:?:d
+I:70:9:0
+W:10:0:5:40
+A:10/1
+D:If you read this scroll, you will immediately be transported to another place on the level.
+
+N:187:Teleport Level
+G:?:d
+I:70:10:0
+W:20:0:5:50
+A:20/1
+D:This scroll will magically transport you to the level directly above or below, when read.
+
+N:188:Monster Confusion
+G:?:d
+I:70:36:0
+W:5:0:5:30
+A:5/1
+D:Reading this scroll will cause your hands to glow with a strange mesmerising light that will
+D:attempt to confuse the next creature you hit with a hand or weapon attack.
+
+N:189:Magic Mapping
+G:?:d
+I:70:25:0
+W:5:0:5:40
+A:5/1
+D:Reading this scroll will reveal the layout of your immediate surroundings to you.
+
+N:190:Rune of Protection
+G:?:d
+I:70:38:0
+W:50:0:5:500
+A:50/2:90/4
+D:This scroll is inscribed with a powerful protective incantation. When read, this will erect a
+D:strong magical ward around the location you currently stand on. Be aware that this magic is
+D:easily disturbed by already present structures and thus cannot work where an object is lying, or
+D:on a trap.
+
+N:191:*Remove Curse*
+G:?:d
+I:70:15:0
+W:50:0:5:8000
+A:50/2:75/2:85/2:95/1
+D:This valuable scroll is inscribed with a powerful blessing capable of dispelling all but the
+D:mightiest curses which may have been laid on your possessions.
+
+N:192:Treasure Detection
+G:?:d
+I:70:26:0
+W:0:0:5:15
+A:0/1
+D:This scroll magically reveals the locations of nearby loose change to you.
+
+N:193:Object Detection
+G:?:d
+I:70:27:0
+W:0:0:5:15
+A:0/1
+D:This scroll shows nearby objects to you. It only makes you aware of items on the floor,
+D:however, not those carried by creatures.
+
+N:194:Trap Detection
+G:?:d
+I:70:28:0
+W:5:0:5:35
+A:5/1:10/1
+D:This scroll is very helpful, because it reveals the locations of nearby snares and traps which you
+D:might otherwise blunder into.
+
+##### Extra ammunition #####
+
+N:195:& Sheaf Arrow~
+G:{:o
+I:17:1:0
+W:10:0:4:3
+A:15/2:50/2
+P:0:1d5:0:0:0
+F:SHOW_MODS
+D:These arrows have bigger arrowheads and bigger feathers.
+D:They also make bigger holes.
+
+N:196:& Mithril Shot~
+G:{:B
+I:16:2:0
+W:40:0:4:20
+A:40/2:65/1
+P:0:3d4:5:5:0
+F:SHOW_MODS | IGNORE_ACID
+D:Sling bullets made from the slags of mithril smelting. They are unusually heavy, hitting
+D:with great force, and are almost imperishable.
+
+##### Additional scrolls #####
+
+N:197:Door/Stair Location
+G:?:d
+I:70:29:0
+W:5:0:5:35
+A:5/1:10/1:15/1
+D:This scroll will reveal nearby passages.
+
+N:198:Acquirement
+G:?:d
+I:70:46:0
+W:20:0:5:100000
+A:20/8
+D:A great treasure is magically stored within the shimmering runes of this scroll. Reading the
+D:words will release it.
+
+N:199:*Acquirement*
+G:?:d
+I:70:47:0
+W:60:0:5:200000
+A:60/16
+D:Several great treasures have been hidden in a magical compartment. This scroll serves as the
+D:key and will release them when read.
+
+N:200:Mass Genocide
+G:?:d
+I:70:45:0
+W:50:0:5:1000
+A:50/4:100/4
+D:An astoundingly powerful death spell is stored in the runes of this spell. Reading
+D:it will annihilate all nearby creatures. Only a few beings of legendary stature
+D:can withstand it.
+
+N:201:Detect Invisible
+G:?:d
+I:70:30:0
+W:1:0:5:15
+A:1/1
+D:A minor detection spell is stored in this scroll, showing you the locations of otherwise
+D:unseen beings for a brief moment.
+
+N:202:Aggravate Monster
+G:?:d
+I:70:1:0
+W:5:0:5:0
+A:5/1
+D:This nasty scroll will make a loud noise, waking up foes in your vicinity.
+
+N:203:Trap Creation
+G:?:d
+I:70:7:0
+W:10:0:5:0
+A:10/1
+D:If you read this rather annoying scroll, snares and pitfalls will magically be planted all around
+D:you, ready to do nasty things to you once you walk onto them.
+
+N:204:Trap/Door Destruction
+G:?:d
+I:70:39:0
+W:10:0:5:50
+A:10/1
+D:A very specifically destructive spell is written on this scroll. It will smash all traps and all
+D:doors immediately next to you.
+
+N:205:Artifact Creation
+G:?:d
+I:70:52:0
+W:70:0:5:200000
+A:70/16
+D:The mighty magic on this scroll will imbue a mundane item you possess with supernatural powers,
+D:also rendering the object indestructible.
+
+N:206:Recharging
+G:?:d
+I:70:22:0
+W:40:0:5:200
+A:40/1
+D:This scroll is inscribed with a spell releasing the enchantments used to give wands and
+D:staves their power, allowing you to replenish their spent charges.
+
+N:207:Genocide
+G:?:d
+I:70:44:0
+W:40:0:5:750
+A:40/4:80/4
+D:This rare and powerful scroll will annihilate all members of a specified race of monsters in
+D:your current location, but this will also exact a price of pain from you.
+
+N:208:Darkness
+G:?:d
+I:70:0:0
+W:1:0:5:0
+A:1/1
+D:This scroll will create a blast of utter darkness, which then fades to leave the immediate
+D:surroundings in a lasting gloom. The extreme darkness can blind those who are not used to
+D:it.
+
+N:209:Protection from Evil
+G:?:d
+I:70:37:0
+W:30:0:5:250
+A:30/1
+D:Upon reading the runes on this piece of paper, a faint aura of holiness will spring into existence
+D:around you, protecting you from blows of evil creatures, unless they are more powerful than you.
+
+N:210:Satisfy Hunger
+G:?:d
+I:70:32:0
+W:5:0:5:10
+A:5/1:20/1:50/1:75/1
+D:Reading this scroll will transport a good portion of nourishing gruel directly into your
+D:stomach. Some people say that this is a ploy of a food producer whose food nobody wants to eat.
+
+N:211:Dispel Undead
+G:?:d
+I:70:42:0
+W:40:0:5:200
+A:40/1
+D:A powerful exorcism is inscribed on this scroll. When read it will hurt undead abominations
+D:nearby, possibly even destroying them.
+
+N:212:*Enchant Weapon*
+G:?:d
+I:70:21:0
+W:50:0:5:500
+A:50/1
+D:Reading this scroll will magically infuse a weapon of your choice, making it more effective
+D:in combat.
+
+N:213:Curse Weapon
+G:?:d
+I:70:3:0
+W:50:0:5:0
+A:50/1
+D:This scroll will ruin your weapon beyond repair. Only weapons of legend have a hope of
+D:escaping destruction, but even they will often be shattered.
+
+N:214:*Enchant Armour*
+G:?:d
+I:70:20:0
+W:50:0:5:500
+A:50/1:50/1
+D:This scroll will place a great enchantment on a piece of armour of your choice, making it much
+D:better at protecting you. Mark that improving armours which are already highly enchanted is very
+D:difficult and will often fail.
+
+N:215:Curse Armour
+G:?:d
+I:70:2:0
+W:50:0:5:0
+A:50/1
+D:This scroll bears a curse that will tear your armour to shreds. Don't read it!
+
+N:216:Summon Undead
+G:?:d
+I:70:5:0
+W:15:0:5:0
+A:15/1
+D:These spells scribed by ancient necromancers will call their horrible creatures to haunt you.
+
+N:217:Blessing
+G:?:d
+I:70:33:0
+W:1:0:5:15
+A:1/1
+D:The recitation of this scroll will grant you a blessing of the Valar, making you more confident
+D:in attack and defence for a few moments.
+
+N:218:Holy Chant
+G:?:d
+I:70:34:0
+W:10:0:5:40
+A:10/1
+D:This blessing will give you a holy warrior's prowess in battle for a while.
+
+N:219:Holy Prayer
+G:?:d
+I:70:35:0
+W:25:0:5:80
+A:25/1
+D:This incantation lets you fight as a warrior of Valinor for quite a while, supreme in attack and
+D:defence.
+
+N:220:Word of Recall
+G:?:d
+I:70:11:0
+W:5:0:5:150
+A:5/1
+D:The spell on this scroll will slowly build an ethereal conduit to the town for you if you are in
+D:a dungeon, and into the dungeon if you are above ground. Upon completion, which takes a while, you
+D:will suddenly be translocated to the other place.
+
+N:221:*Destruction*
+G:?:d
+I:70:41:0
+W:40:0:5:250
+A:40/1
+D:This scroll is inscribed with a mighty conjuration which wrecks the dungeon all around you.
+D:Monsters and objects will be annihilated by this blast; only completely indestructible things can
+D:withstand it.
+
+##### Potions #####
+
+N:222:Slime Mold Juice
+G:!:d
+I:71:2:400
+W:0:0:4:2
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A strange sort of yellowish-green slime, too viscous to even slosh in the bottle. And as I know
+D:you, you're going to slurp it down.
+
+N:223:Apple Juice
+G:!:d
+I:71:1:250
+W:0:0:4:1
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A healthy fruit beverage.
+
+N:224:Water
+G:!:d
+I:71:0:200
+W:0:0:4:1
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A small bottle filled with pure water.
+
+N:225:Strength
+G:!:d
+I:71:48:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:This beneficial potion will magically improve your physical strength.
+
+N:226:Weakness
+G:!:d
+I:71:16:0
+W:3:0:4:0
+A:3/1
+P:0:3d12:0:0:0
+F:FOUNTAIN
+D:This nasty potion will sap your strength, making you weaker.
+
+N:227:Restore Strength
+G:!:d
+I:71:42:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical potion will bring back your physical power to its full extent, should it be drained.
+
+N:228:Intelligence
+G:!:d
+I:71:49:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:This nice potion will magically enhance your wit, permanently improving your intellect.
+
+N:229:Stupidity
+G:!:d
+I:71:17:0
+W:20:0:4:0
+A:20/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This accursed potion will cloud your intellect, making you stupid.
+
+N:230:Restore Intelligence
+G:!:d
+I:71:43:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This beneficial potion will magically heal your brain, restoring drained intelligence.
+
+N:231:Wisdom
+G:!:d
+I:71:50:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:This potion grants great insight, making you wiser.
+
+N:232:Naivety
+G:!:d
+I:71:18:0
+W:20:0:4:0
+A:20/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion casts a shadow on your knowledge, making you foolish.
+
+N:233:Restore Wisdom
+G:!:d
+I:71:44:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion benefits the naive, bringing back their wisdom to what it once was.
+
+N:234:Charisma
+G:!:d
+I:71:53:0
+W:20:0:4:1000
+A:20/1:25/1
+P:0:1d1:0:0:0
+D:This potion infuses you with beauty and charm.
+
+N:235:Ugliness
+G:!:d
+I:71:21:0
+W:20:0:4:0
+A:20/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This wicked potion slightly twists your features, making you appear less fair.
+
+N:236:Restore Charisma
+G:!:d
+I:71:47:0
+W:20:0:4:300
+A:20/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This useful potion restores drained charm.
+
+N:237:Curing
+G:!:d
+I:71:61:100
+W:18:0:4:250
+A:18/1:40/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This blessed potion helps to recover from a wide variety of ailments.
+
+### Note! Invulnerability decreases your food... ###
+
+N:238:Invulnerability
+G:!:d
+I:71:62:-2500
+W:90:0:4:100000
+A:90/9
+P:0:1d1:0:0:0
+D:This immensely powerful potion makes your physique almost indestructible for a very short
+D:time. Very rarely, an attempt to hurt you will still succeed, so don't be too confident.
+
+N:239:New Life
+G:!:d
+I:71:63:100
+W:50:0:4:750000
+A:50/20:100/10:120/5
+P:0:1d1:0:0:0
+D:This potion fundamentally twists your physical features, as if you were another mother's child.
+D:Your physique will be shaped anew.
+
+N:240:Cure Serious Wounds
+G:!:d
+I:71:35:100
+W:3:0:4:40
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This beneficial potion will cure some wounds and other inhibiting ailments.
+
+N:241:Cure Critical Wounds
+G:!:d
+I:71:36:100
+W:5:0:4:100
+A:5/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This nice potion will cure a good bit of hurt you have suffered and also allows you to recover
+D:from unhealthy conditions like blood poisoning, confusion or blindness.
+
+N:242:Healing
+G:!:d
+I:71:37:200
+W:15:0:4:300
+A:15/1:30/1:60/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This blessed potion greatly heals you and also cures many other ailments from
+D:which you might suffer.
+
+N:243:Constitution
+G:!:d
+I:71:52:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:This magical concoction greatly improves your health, making you permanently tougher.
+
+N:244:Experience
+G:!:d
+I:71:59:0
+W:65:0:4:25000
+A:65/1
+P:0:1d1:0:0:0
+D:This exceptional drink instills into you knowledge, allowing you to advance further in your trade.
+
+N:245:Sleep
+G:!:d
+I:71:11:100
+W:0:0:4:0
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion was made to help people with bad sleeping disorders to find rest. Surely you don't
+D:want to take a nap while nasty goblins are searching for you?
+
+N:246:Blindness
+G:!:d
+I:71:7:0
+W:0:0:4:0
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This slightly poisonous potion temporarily impedes your eyesight, making you unable to see
+D:a thing.
+
+N:247:Booze
+G:!:d
+I:71:9:50
+W:0:0:4:0
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A small bottle of a dark brown distilled beverage. By its look and smell, it contains a fair
+D:amount of still muck and wood alcohol.
+
+N:248:Poison
+G:!:d
+I:71:6:0
+W:3:0:4:0
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This bottle is filled with a mild but still dangerous liquid poison. Drinking it would be highly
+D:unwise.
+
+N:249:Speed
+G:!:d
+I:71:29:0
+W:1:0:4:75
+A:1/1:40/1:60/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A magical drink which temporarily allows you to act much faster when imbibed.
+
+N:250:Slowness
+G:!:d
+I:71:4:50
+W:1:0:4:0
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A magical concoction which drains force from you, forcing you to move and act a lot slower,
+D:until it wears off.
+
+N:251:Dexterity
+G:!:d
+I:71:51:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:A strange magical drink which greatly improves your agility and nimbleness.
+
+N:252:Restore Dexterity
+G:!:d
+I:71:45:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical brew brings your agility back to its former glory should it have been reduced.
+
+N:253:Restore Constitution
+G:!:d
+I:71:46:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A beneficial magical concoction, restoring your damaged health.
+
+N:254:Lose Memories
+G:!:d
+I:71:13:0
+W:10:0:4:0
+A:10/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A wicked potion, making you less of an adventurer than by right you should be.
+
+N:255:Salt Water
+G:!:d
+I:71:5:0
+W:0:0:4:0
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A solution of salt in water, made for curing meat. Drinking it would cause violent nausea.
+
+N:256:Enlightenment
+G:!:d
+I:71:56:0
+W:25:0:4:800
+A:25/1:50/1:100/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:An exceptional magical drink which lets you "remember" your current location as if you had
+D:already seen all of it.
+
+N:257:Heroism
+G:!:d
+I:71:32:0
+W:1:0:4:35
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:Quaffing this drink will temporarily make you fight like a hero of great might.
+
+N:258:Berserk Strength
+G:!:d
+I:71:33:0
+W:3:0:4:100
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This strange drink will instill in you a wild battle rage for a while.
+
+N:259:Boldness
+G:!:d
+I:71:28:0
+W:1:0:4:10
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This drink will improve your courage, dispelling all fear.
+
+N:260:Restore Life Levels
+G:!:d
+I:71:41:0
+W:40:0:4:400
+A:40/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:If your life force has been drained, this blessed brew will bring it back.
+
+N:261:Resist Heat
+G:!:d
+I:71:30:0
+W:1:0:4:30
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical potion will make fire flow in your veins, rendering you less vulnerable to outward
+D:heat.
+
+N:262:Resist Cold
+G:!:d
+I:71:31:0
+W:1:0:4:30
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical potion will for a short while grant you a familiarity with frost, so that you take
+D:less harm from extreme cold.
+
+N:263:Detect Invisible
+G:!:d
+I:71:25:0
+W:3:0:4:50
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical concoction will temporarily improve your eyesight so that you can see creatures
+D:otherwise unseen.
+
+N:264:Slow Poison
+G:!:d
+I:71:26:0
+W:1:0:4:25
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This healthy potion will dilute poisons in your blood.
+
+N:265:Neutralise Poison
+G:!:d
+I:71:27:0
+W:5:0:4:75
+A:5/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This powerful antidote will completely negate the effect of poisons currently affecting you.
+
+N:266:Restore Mana
+G:!:d
+I:71:40:0
+W:25:0:4:350
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion infuses the drinker with pure magic force, bringing their magical potential back to
+D:its full extent.
+
+N:267:Infra-vision
+G:!:d
+I:71:24:0
+W:3:0:4:20
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion temporarily grants or improves the ability to optically perceive heat sources.
+
+N:268:Resistance
+G:!:d
+I:71:60:100
+W:20:0:4:250
+A:20/1:45/1:80/1:100/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:FOUNTAIN
+D:This great potion infuses you with the power of the elements, so that you can better
+D:withstand their ravages.
+
+##### Wands #####
+
+# Wand of school spells
+N:269:Spell
+G:-:d
+I:65:1:0
+W:3:0:10:100
+A:3/1:13/1:23/1:43/1:63/1:83/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE
+
+N:270:Manathrust
+G:-:d
+I:65:3:-1:SPELL=Manathrust
+W:3:0:10:100
+A:3/1
+P:0:1d1:0:0:0
+
+N:271:Fireflash
+G:-:d
+I:65:4:-1:SPELL=Fireflash
+W:10:0:10:100
+A:10/2
+P:0:1d1:0:0:0
+
+N:272:Firewall
+G:-:d
+I:65:5:-1:SPELL=Firewall
+W:20:0:10:100
+A:20/1
+P:0:1d1:0:0:0
+
+N:273:Tidal Wave
+G:-:d
+I:65:6:-1:SPELL=Tidal Wave
+W:20:0:10:100
+A:20/1
+P:0:1d1:0:0:0
+
+N:274:Ice Storm
+G:-:d
+I:65:7:-1:SPELL=Ice Storm
+W:15:0:10:100
+A:15/1
+P:0:1d1:0:0:0
+
+N:275:Noxious Cloud
+G:-:d
+I:65:8:-1:SPELL=Noxious Cloud
+W:5:0:10:100
+A:5/2
+P:0:1d1:0:0:0
+
+N:276:Poison Blood
+G:-:d
+I:65:9:-1:SPELL=Poison Blood
+W:30:0:10:100
+A:30/2
+P:0:1d1:0:0:0
+
+N:277:Thunderstorm
+G:-:d
+I:65:10:-1:SPELL=Thunderstorm
+W:40:0:10:100
+A:40/2
+P:0:1d1:0:0:0
+
+N:278:Dig
+G:-:d
+I:65:11:-1:SPELL=Dig
+W:15:0:10:100
+A:15/1
+P:0:1d1:0:0:0
+
+N:279:Stone Prison
+G:-:d
+I:65:12:-1:SPELL=Stone Prison
+W:50:0:10:100
+A:50/3
+P:0:1d1:0:0:0
+
+N:280:Strike
+G:-:d
+I:65:13:-1:SPELL=Strike
+W:30:0:10:100
+A:30/1
+P:0:1d1:0:0:0
+
+N:281:Teleport Away
+G:-:d
+I:65:14:-1:SPELL=Teleport Away
+W:20:0:10:100
+A:20/1
+P:0:1d1:0:0:0
+
+N:282:Summon Animal
+G:-:d
+I:65:15:-1:SPELL=Summon Animal
+W:60:0:10:100
+A:60/1
+P:0:1d1:0:0:0
+
+N:283:Magelock
+G:-:d
+I:65:16:-1:SPELL=Magelock
+W:1:0:10:100
+A:3/2
+P:0:1d1:0:0:0
+
+N:284:Slow Monster
+G:-:d
+I:65:17:-1:SPELL=Slow Monster
+W:3:0:10:100
+A:3/2
+P:0:1d1:0:0:0
+
+N:285:Essence of Speed
+G:-:d
+I:65:18:-1:SPELL=Essence of Speed
+W:25:0:10:100
+A:25/2
+P:0:1d1:0:0:0
+
+N:286:Banishment
+G:-:d
+I:65:19:-1:SPELL=Banishment
+W:45:0:10:100
+A:45/2
+P:0:1d1:0:0:0
+
+N:287:Disperse Magic
+G:-:d
+I:65:20:-1:SPELL=Disperse Magic
+W:10:0:10:100
+A:10/2
+P:0:1d1:0:0:0
+
+N:288:Charm
+G:-:d
+I:65:21:-1:SPELL=Charm
+W:15:0:10:100
+A:15/1
+P:0:1d1:0:0:0
+
+N:289:Confuse
+G:-:d
+I:65:22:-1:SPELL=Confuse
+W:7:0:10:100
+A:7/2
+P:0:1d1:0:0:0
+
+N:290:Demon Blade
+G:-:d
+I:65:23:-1:SPELL=Demon Blade
+W:60:0:10:100
+A:60/1
+P:0:1d1:0:0:0
+
+N:291:Heal Monster
+G:-:d
+I:65:24:-1:SPELL=Heal Monster
+W:1:0:10:0
+A:1/4
+P:0:1d1:0:0:0
+
+N:292:Haste Monster
+G:-:d
+I:65:25:-1:SPELL=Haste Monster
+W:1:0:10:0
+A:1/4
+P:0:1d1:0:0:0
+
+
+##### Extra ammunition #####
+
+N:293:& Flight Arrow~
+G:{:y
+I:17:1:0
+W:3:0:1:1
+A:3/2
+P:0:1d3:0:0:0
+F:SHOW_MODS
+D:An arrow designed for longer flight. Consequently, it is lighter and hits with less force.
+
+# XXX
+
+N:295:& Boulder~
+G:*:W
+I:11:1:0
+W:3:0:50:1
+A:3/200
+P:0:5d5:0:0:0
+F:SPECIAL_GENE
+D:A big nasty-looking piece of rock.
+
+# Used for a quest
+N:296:& Flame~ Imperishable
+G:~:v
+I:11:255:0
+W:127:0:4:0
+A:127/255
+P:0:1d1:0:0:0
+T:39:2
+F:NORM_ART | FULL_NAME | SPECIAL_GENE
+F:ACTIVATE | ACTIVATE_NO_WIELD
+a:SPELL=Artifact Eternal Flame
+D:An impossibly bright, flickering living flame. It can be used
+D:once to imbue an object with the power of Eru Iluvatar himself.
+
+N:297:& Necromantic Teeth~
+G:|:D
+I:23:34:0
+W:0:0:7:10
+A:0/1:5/1:10/1:20/1
+P:0:1d4:0:0:0
+F:SHOW_MODS | VAMPIRIC | SPECIAL_GENE
+D:This looks like some animal's teeth or at least you think
+D:it comes from an animal...
+
+# The Horn of the Thunderlords
+N:298:& Golden Horn~ of the Thunderlords
+G:_:d
+I:55:23:-1:SPELL=Artifact Thunderlords
+W:50:10:10:12000
+P:0:1d4:0:0:0
+A:50/200
+T:55:8
+F:NO_RECHARGE | EASY_USE | RECHARGED | NORM_ART | FULL_NAME | SPECIAL_GENE
+D:This horn was given to you as a reward. Blow it if you are in dire need
+D:of leaving your current location fast.
+
+# XXX
+
+##### Staves #####
+
+N:300:Spell
+G:_:d
+I:55:1:0
+W:5:0:50:100
+A:5/1:15/1:35/1:45/1:65/1:75/1:85/1:95/1
+P:0:1d2:0:0:0
+F:SPECIAL_GENE
+
+N:301:Nothing
+G:_:d
+I:55:2:-1:SPELL=Nothing
+W:5:0:50:100
+A:5/1
+P:0:1d2:0:0:0
+
+N:302:Globe of Light
+G:_:d
+I:55:3:-1:SPELL=Globe of Light
+W:7:0:50:100
+A:7/1
+P:0:1d2:0:0:0
+
+N:303:Fiery Shield
+G:_:d
+I:55:4:-1:SPELL=Fiery Shield
+W:15:0:50:100
+A:15/2
+P:0:1d2:0:0:0
+
+N:304:Remove Curses
+G:_:d
+I:55:5:-1:SPELL=Remove Curses
+W:10:0:50:100
+A:10/1
+P:0:1d2:0:0:0
+
+N:305:Wings of Winds
+G:_:d
+I:55:6:-1:SPELL=Wings of Winds
+W:25:0:50:100
+A:25/2
+P:0:1d2:0:0:0
+
+N:306:Shake
+G:_:d
+I:55:7:-1:SPELL=Shake
+W:30:0:50:100
+A:30/1
+P:0:1d2:0:0:0
+
+N:307:Disarm
+G:_:d
+I:55:8:-1:SPELL=Disarm
+W:2:0:50:100
+A:2/1
+P:0:1d2:0:0:0
+
+N:308:Teleportation
+G:_:d
+I:55:9:-1:SPELL=Teleportation
+W:20:0:50:100
+A:20/1
+P:0:1d2:0:0:0
+
+N:309:Probability Travel
+G:_:d
+I:55:10:-1:SPELL=Probability Travel
+W:50:0:50:100
+A:50/3
+P:0:1d2:0:0:0
+
+N:310:Recovery
+G:_:d
+I:55:11:-1:SPELL=Recovery
+W:20:0:50:100
+A:20/1
+P:0:1d2:0:0:0
+
+N:311:Healing
+G:_:d
+I:55:12:-1:SPELL=Healing
+W:25:0:50:100
+A:25/2
+P:0:1d2:0:0:0
+
+N:312:Vision
+G:_:d
+I:55:13:-1:SPELL=Vision
+W:30:0:50:100
+A:30/1
+P:0:1d2:0:0:0
+
+N:313:Identify
+G:_:d
+I:55:14:-1:SPELL=Identify
+W:10:0:50:100
+A:10/1
+P:0:1d2:0:0:0
+
+N:314:Sense Hidden
+G:_:d
+I:55:15:-1:SPELL=Sense Hidden
+W:10:0:50:100
+A:10/1
+P:0:1d2:0:0:0
+
+N:315:Reveal Ways
+G:_:d
+I:55:16:-1:SPELL=Reveal Ways
+W:5:0:50:100
+A:5/1
+P:0:1d2:0:0:0
+
+N:316:Sense Monsters
+G:_:d
+I:55:17:-1:SPELL=Sense Monsters
+W:5:0:50:100
+A:5/1
+P:0:1d2:0:0:0
+
+N:317:Genocide
+G:_:d
+I:55:18:-1:SPELL=Genocide
+W:55:0:50:100
+A:55/2
+P:0:1d2:0:0:0
+
+N:318:Summon
+G:_:d
+I:55:19:-1:SPELL=Summon
+W:5:0:50:100
+A:5/1
+P:0:1d2:0:0:0
+
+N:319:Sterilization
+G:_:d
+I:55:24:-1:SPELL=Sterilize
+W:20:0:50:100
+A:20/3
+P:0:1d2:0:0:0
+
+N:320:Wish
+G:_:d
+I:55:20:-1:SPELL=Wish
+W:95:0:50:10000
+A:95/40
+P:0:1d2:0:0:0
+F:NO_RECHARGE
+
+N:321:Mana
+G:_:d
+I:55:21:-1:SPELL=Mana
+W:60:0:50:100
+A:60/2
+P:0:1d2:0:0:0
+
+# XXX
+# ...
+# XXX
+
+##### School Books #####
+
+N:330:& Tome~ of Magical Energy
+G:?:B
+I:111:0:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:The bright blue cover of this tome seems to glow
+D:with an inner violet light. You feel more attuned
+D:to raw magic as you hold it.
+
+N:331:& Tome~ of the Eternal Flame
+G:?:R
+I:111:1:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | IGNORE_FIRE
+D:The cover of this tome is bright red, with flickering
+D:flames dancing across it once in a while. As you hold
+D:it, you begin to gain a much closer knowledge of all
+D:that is fiery.
+
+N:332:& Tome~ of the Blowing Wind
+G:?:b
+I:111:2:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | IGNORE_ELEC
+D:The pages of this tome have a tendency to turn themselves,
+D:as though flipped by an errant wind. As you hold it,
+D:you start feeling wind at your fingertips.
+
+N:333:& Tome~ of the Impenetrable Earth
+G:?:U
+I:111:3:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | IGNORE_ACID
+D:The solid leather cover of this tome seems permanently
+D:stained with caked mud and grass. Heavy it is to lift,
+D:yet strangely comforting to hold - you feel stronger
+D:and better supported.
+
+N:334:& Tome~ of the Everrunning Wave
+G:?:B
+I:111:4:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:The cover and pages of this tome seem to be perpetually
+D:wet, though they are not wet to the touch. As you hold
+D:it, you begin to understand ocean storms better.
+
+N:335:& Tome~ of Translocation
+G:?:B
+I:111:5:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This book seems to flicker strangely. It's one of those books
+D:with an annoying tendency to disappear when you need it and
+D:reappear in the unlikeliest places. As you hold it, you start
+D:to understand what conveyance really means.
+
+N:336:& Tome~ of the Tree
+G:?:G
+I:111:6:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:The cover of this tome is a bright shade of green, and it gives off
+D:a healthy, zesty scent that makes your thoughts clearer. As you
+D:hold it, your heart goes out to all living things upon Arda.
+
+N:337:& Tome~ of Knowledge
+G:?:D
+I:111:7:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:A thick book with solid leather binding. It looks entirely
+D:unremarkable, but as you hold it, you feel strangely able
+D:to learn the inner workings of things and creatures.
+
+##### Chests #####
+
+N:338:& Small wooden chest~
+G:~:s
+I:7:1:0
+W:5:0:250:20
+A:5/1
+P:0:2d3:0:0:0
+D:A small wooden box, locked and possibly trapped. You wonder what might be inside.
+
+N:339:& Large wooden chest~
+G:~:s
+I:7:5:0
+W:15:0:500:60
+A:15/1
+P:0:2d5:0:0:0
+D:A large wooden box. It doesn't seem to be locked - why not risk a look inside?
+
+N:340:& Small iron chest~
+G:~:s
+I:7:2:0
+W:25:0:300:100
+A:25/1
+P:0:2d4:0:0:0
+D:A small rectangular container made of wood and reinforced with iron corners and latches.
+
+N:341:& Large iron chest~
+G:~:s
+I:7:6:0
+W:35:0:1000:150
+A:35/1
+P:0:2d6:0:0:0
+D:A big container made of wood, with a heavy iron lock.
+
+N:342:& Small steel chest~
+G:~:s
+I:7:3:0
+W:45:0:500:200
+A:45/1
+P:0:2d4:0:0:0
+D:A small wooden box with strong steel locks and reinforcements.
+
+N:343:& Large steel chest~
+G:~:s
+I:7:7:0
+W:55:0:1000:250
+A:55/1
+P:0:2d6:0:0:0
+D:A nearly indestructible chest of wood and steel. The lock doesn't look impenetrable, but it
+D:might be trapped.
+
+N:344:& Ruined chest~
+G:~:s
+I:7:0:0
+W:0:0:250:0
+A:75/1
+D:A broken, empty chest.
+
+##### Various Stuff #####
+
+N:345:& Iron Spike~
+G:~:W
+I:5:0:0
+W:1:0:10:1
+A:1/1
+P:0:1d1:0:0:0
+D:A small spur of iron. Ramming one between a door and its frame might jam it.
+
+N:346:& Wooden Torch~
+G:~:u
+I:39:0:0:4000
+W:1:0:30:2
+A:1/1
+P:0:1d1:0:0:0
+F:EASY_KNOW | LITE1 | FUEL_LITE
+f:LITE1 | FUEL_LITE
+D:A piece of wood with an oily rag wrapped around it. When lit, it will give off a little light and
+D:much smoke.
+
+N:347:& Brass Lantern~
+G:~:U
+I:39:1:0:7500
+W:3:0:50:35
+A:3/1
+P:0:1d1:0:0:0
+F:EASY_KNOW | IGNORE_FIRE | LITE2 | FUEL_LITE
+f:LITE2 | FUEL_LITE
+D:A brass container with a wick emerging from it, protected from draughts by a sheet of greased
+D:paper. It can be carried by a handle.
+
+N:348:& Flask~ of oil
+G:!:y
+I:77:0:7500
+W:1:0:10:3
+A:1/1
+P:0:2d6:0:0:0
+D:A small clay container, filled with thick oil. The oil is flammable and can be used as lantern
+D:fuel.
+
+N:349:& Empty Bottle~
+G:!:w
+I:2:1:0
+W:0:0:2:1
+A:0/1
+P:0:1d1:0:0:0
+D:A small glass bottle. It's empty.
+
+
+##### Here are the Rod Tips #####
+
+N:350:Havoc
+G:-:d
+I:66:28:90
+W:95:0:15:150000
+A:100/16
+P:0:1d1:0:0:0
+D:This powerful rod will release great blasts of destructive energy, but there's no knowing what
+D:this effect will concentrate on.
+
+N:351:Door/Stair Location
+G:-:d
+I:66:1:10
+W:15:0:15:1000
+A:15/1
+P:0:1d1:0:0:0
+D:When fuelled with enough ambient mana, this rod can detect nearby passages.
+
+N:352:Trap Location
+G:-:d
+I:66:29:8
+W:5:0:15:100
+A:5/1:10/1:20/1
+P:0:1d1:0:0:0
+D:Zapping this rod will release a minor detection magic, alerting you of nearby pits and snares.
+
+N:353:Probing
+G:-:d
+I:66:7:50
+W:40:0:15:4000
+A:40/4
+P:0:1d1:0:0:0
+D:A rod of knowledge which will tell you about nearby creatures' health.
+
+N:354:Recall
+G:-:d
+I:66:3:80
+W:30:0:15:4500
+A:30/4
+P:0:1d1:0:0:0
+D:A rod which can transport you from the depths to your home and back.
+
+N:355:Illumination
+G:-:d
+I:66:4:8
+W:20:0:15:1000
+A:20/1
+P:0:1d1:0:0:0
+D:This rod carries a minor spell of brightness, lighting your immediate surroundings whenever
+D:activated.
+
+N:356:Light
+G:-:d
+I:66:15:15
+W:10:0:15:500
+A:10/1
+P:0:1d1:0:0:0
+D:This rod can shoot a lance of bright light, hurting creatures which lurk in the dark.
+
+N:357:Lightning Bolts
+G:-:d
+I:66:21:30
+W:20:0:15:2000
+A:20/1
+P:0:1d1:0:0:0
+D:This rod shoots a small spark of lightning, zapping the creature it hits.
+
+N:358:Frost Bolts
+G:-:d
+I:66:23:35
+W:25:0:15:2500
+A:25/1
+P:0:1d1:0:0:0
+D:A small but extremely cold shard of ice will fly from this rod to your enemy.
+
+N:359:Fire Bolts
+G:-:d
+I:66:22:40
+W:30:0:15:3000
+A:30/1
+P:0:1d1:0:0:0
+D:This rod fires a magical flaming arrow at your foe, burning it.
+
+N:360:Polymorph
+G:-:d
+I:66:19:25
+W:35:0:15:1200
+A:35/1
+P:0:1d1:0:0:0
+D:This rod of change will cause its target creature to mutate into something else.
+
+N:361:Slow Monster
+G:-:d
+I:66:17:25
+W:30:0:15:1500
+A:30/1
+P:0:1d1:0:0:0
+D:This obstructive rod emits an energy bolt which will slow the creature it hits.
+
+N:362:Sleep Monster
+G:-:d
+I:66:16:25
+W:30:0:15:1500
+A:30/1
+P:0:1d1:0:0:0
+D:This sorcerous rod will cause its target to stop in its tracks.
+
+N:363:Drain Life
+G:-:d
+I:66:18:30
+W:75:0:15:3600
+A:75/4
+P:0:1d1:0:0:0
+D:This necromantic magical rod will hurt a living creature struck by its spell.
+
+N:364:Teleport Other
+G:-:d
+I:66:13:60
+W:45:0:15:1400
+A:45/2
+P:0:1d1:0:0:0
+D:This rod of movement will displace its target to another location.
+
+N:365:Disarming
+G:-:d
+I:66:14:50
+W:35:0:15:2100
+A:35/1
+P:0:1d1:0:0:0
+D:This rod will clear a path for you, triggering and thus rendering harmless all traps on the way.
+
+N:366:Lightning Balls
+G:-:d
+I:66:25:50
+W:55:0:15:4000
+A:55/1
+P:0:1d1:0:0:0
+D:This rod will hurl a large ball of lightning at its target, electrifying all it engulfs.
+
+N:367:Cold Balls
+G:-:d
+I:66:27:55
+W:60:0:15:4500
+A:60/1
+P:0:1d1:0:0:0
+D:This rod will call forth a minor storm of ice which freezes everything in the area of its blast.
+
+N:368:Fire Balls
+G:-:d
+I:66:26:60
+W:75:0:15:5000
+A:75/1
+P:0:1d1:0:0:0
+D:This rod will cause a small storm of flame to rage in a small circular area of your choice.
+
+N:369:Acid Balls
+G:-:d
+I:66:24:60
+W:70:0:15:5500
+A:70/1
+P:0:1d1:0:0:0
+D:This destructive rod will drown its target and its immediate surroundings in caustic acid.
+
+N:370:Acid Bolts
+G:-:d
+I:66:20:40
+W:40:0:15:3500
+A:40/1
+P:0:1d1:0:0:0
+D:This rod will shoot a small glob of powerful acid at its target.
+
+N:371:Enlightenment
+G:-:d
+I:66:5:40
+W:65:0:15:10000
+A:65/4
+P:0:1d1:0:0:0
+D:This rod grants you knowledge of your surroundings.
+
+N:372:Perception
+G:-:d
+I:66:2:20
+W:50:0:15:13000
+A:50/8:100/8
+P:0:1d1:0:0:0
+D:This rod makes you insightful, laying open the identity of your possessions.
+
+N:373:Curing
+G:-:d
+I:66:8:35
+W:65:0:15:15000
+A:65/8
+P:0:1d1:0:0:0
+D:This is a rod with minor healing powers, alleviating many disabling conditions.
+
+N:374:Healing
+G:-:d
+I:66:9:120
+W:80:0:15:20000
+A:80/8
+P:0:1d1:0:0:0
+D:This rod has major healing powers and can restore your health if you have been wounded.
+
+N:375:Detection
+G:-:d
+I:66:6:80
+W:30:0:15:5000
+A:30/8
+P:0:1d1:0:0:0
+D:This rod grants knowledge about all things worthy of notice in your vicinity.
+
+N:376:Restoration
+G:-:d
+I:66:10:140
+W:80:0:15:25000
+A:80/16
+P:0:1d1:0:0:0
+D:This rod lets you remember your previous abilities and gain them back, should they have been
+D:reduced.
+
+N:377:Speed
+G:-:d
+I:66:11:100
+W:95:0:15:50000
+A:95/16
+P:0:1d1:0:0:0
+D:This energising rod will allow you to act a lot faster for some time.
+
+# Ring of Spell
+
+N:378:Spell
+G:=:d
+I:45:58:0
+W:10:0:2:1000
+A:10/1
+F:SPELL_CONTAIN | WIELD_CAST
+f:SPELL_CONTAIN
+D:This ring is a container for spells. Those that are skilled in copying spells can inscribe a
+D:spell into it.
+
+# Amulet of Spell
+
+N:379:Spell
+G:":d
+I:40:27:0
+W:10:0:2:1000
+A:10/1
+F:SPELL_CONTAIN | WIELD_CAST
+f:SPELL_CONTAIN
+D:This amulet is a container for spells. Those that are skilled in copying spells can inscribe a
+D:spell into it.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+##### Skeletons #####
+
+N:391:& Broken Skull~
+G:~:w
+I:1:1:0
+W:0:0:1:0
+A:0/1
+P:0:1d1:0:0:0
+D:Good old Yorick. So that's where he ended up.
+
+N:392:& Broken Bone~
+G:~:w
+I:1:2:0
+W:0:0:2:0
+A:0/1
+P:0:1d1:0:0:0
+D:A yellowish bone, broken off. Obviously, its owner no longer has a use for it.
+
+N:393:& Canine Skeleton~
+G:~:w
+I:1:4:0
+W:1:0:10:0
+A:1/1
+P:0:1d1:0:0:0
+D:Lassie?
+
+N:394:& Rodent Skeleton~
+G:~:w
+I:1:3:0
+W:1:0:10:0
+A:1/1
+P:0:1d1:0:0:0
+D:The remains of a cat's meal.
+
+N:395:& Human Skeleton~
+G:~:w
+I:1:8:0
+W:5:0:60:0
+A:5/1
+P:0:1d2:0:0:0
+D:It's dead, Jim.
+
+N:396:& Dwarf Skeleton~
+G:~:w
+I:1:7:0
+W:5:0:50:0
+A:5/1
+P:0:1d2:0:0:0
+D:The remains of a dwarf who met his or her demise here.
+
+N:397:& Elf Skeleton~
+G:~:w
+I:1:6:0
+W:5:0:40:0
+A:5/1
+P:0:1d2:0:0:0
+D:A person of about human shape, but considerably more slightly built, has died here long ago.
+
+N:398:& Gnome Skeleton~
+G:~:w
+I:1:5:0
+W:5:0:30:0
+A:5/1
+P:0:1d2:0:0:0
+D:This was once a gnome. Looks very dead now.
+
+##### Additional weapon #####
+
+N:399:& Great Hammer~
+G:\:D
+I:21:19:0
+W:45:0:300:350
+A:45/3
+P:0:4d6:0:0:0
+F:SHOW_MODS
+D:A massive smith's hammer, so large and heavy it can be used as a weapon.
+
+##### Dragon Scale Mail #####
+
+N:400:& Black Dragon Scale Mail~
+G:[:s
+I:38:1:0
+W:60:0:200:50000
+A:60/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_ACID
+F:RES_ACID | FLY |
+f:RES_ACID |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:An armour made of a black dragon's hide, containing some of this beast's powers.
+
+N:401:& Blue Dragon Scale Mail~
+G:[:b
+I:38:2:0
+W:50:0:200:40000
+A:50/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_ELEC
+F:RES_ELEC | FLY |
+f:RES_ELEC |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A piece of dragon hide fashioned into an armour, shimmering bright blue.
+
+N:402:& White Dragon Scale Mail~
+G:[:w
+I:38:3:0
+W:50:0:200:40000
+A:50/8
+a:HARDCORE=BR_COLD
+P:30:2d4:-2:0:10
+F:RES_COLD | FLY |
+f:RES_COLD |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:An armour fashioned from dragon hide, glistening the white of snow.
+
+N:403:& Red Dragon Scale Mail~
+G:[:r
+I:38:4:0
+W:60:0:200:50000
+A:60/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_FIRE
+F:RES_FIRE | FLY |
+f:RES_FIRE |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:The skin of a dragon made into a suit of armour. It glows a bright red and radiates heat.
+
+N:404:& Green Dragon Scale Mail~
+G:[:g
+I:38:5:0
+W:50:0:200:40000
+A:50/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_POIS
+F:RES_POIS | FLY |
+f:RES_POIS |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour fashioned of dragon hide. It is dirty green and smells awful.
+
+N:405:& Multi-Hued Dragon Scale Mail~
+G:[:v
+I:38:6:0
+W:90:0:200:150000
+A:90/32
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_MANY
+F:ATTR_MULTI
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS | FLY |
+f:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A powerful armour made of dragonhide. It glows red, blue, green, black and white.
+
+N:406:& Pseudo Dragon Scale Mail~
+G:[:v
+I:38:10:0
+W:70:0:200:70000
+A:70/16
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_LIGHT
+F:RES_LITE | RES_DARK | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour made of dragon hide, glowing with a strange light, or is it darkness?
+
+N:407:& Law Dragon Scale Mail~
+G:[:B
+I:38:12:0
+W:80:0:200:80000
+A:80/16
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_SHARD
+F:RES_SOUND | RES_SHARDS | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A piece of dragonhide cut and shaped so it can be worn as armour. The scales are very sharp,
+D:and the roaring of a storm seems to come from it, but you're not afraid of either.
+
+N:408:& Bronze Dragon Scale Mail~
+G:[:U
+I:38:14:0
+W:50:0:200:40000
+A:50/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_CONF
+F:RES_CONF | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour made from dragon skin. Its brownish scales glitter in a dazzling light.
+
+N:409:& Gold Dragon Scale Mail~
+G:[:y
+I:38:16:0
+W:60:0:200:50000
+A:60/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_SOUND
+F:RES_SOUND | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of golden-hued armour made of dragonhide. The rustle of its scales occasionally
+D:increases to a loud boom.
+
+N:410:& Chaos Dragon Scale Mail~
+G:[:v
+I:38:18:0
+W:80:0:200:80000
+A:80/16
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_CHAOS
+F:ATTR_MULTI
+F:RES_CHAOS | RES_DISEN | FLY |
+f:RES_CHAOS |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour made of dragon hide. It glows in colours you have never seen before. As you
+D:put it on, you feel like you could change the world and are no longer afraid of your equipment
+D:losing its magic.
+
+N:411:& Balance Dragon Scale Mail~
+G:[:v
+I:38:20:0
+W:95:0:200:100000
+A:95/32
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_BALANCE
+F:RES_CHAOS | RES_DISEN | RES_SOUND | RES_SHARDS | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour made of the hide of a dead dragon. When wearing it, you feel like you
+D:understand the principles of law and chaos, and no longer fear either.
+
+N:412:& Power Dragon Scale Mail~
+G:[:v
+I:38:30:0
+W:100:0:250:350000
+A:100/64
+P:40:2d4:-3:0:15
+a:HARDCORE=BR_POWER
+F:ATTR_MULTI
+F:RES_ACID | RES_FIRE | RES_COLD | RES_ELEC | RES_POIS | FLY |
+F:RES_NETHER | RES_NEXUS | RES_CHAOS | RES_LITE | RES_DARK |
+F:RES_SHARDS | RES_SOUND | RES_DISEN | RES_CONF |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour made of a very thick richly coloured dragonhide. You think you'll never have
+D:to fear dragons if you put it on.
+
+#### PDSM has been restored to (almost) its former glory in Zangband
+
+N:413:& Dragon Helm~
+G:]:G
+I:32:7:0
+W:45:0:50:10000
+A:80/4
+P:8:1d3:0:0:10
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_ELEC | IGNORE_COLD
+D:An iron helmet, covered with a layer of dragonhide. It offers great protection and may grant
+D:protection against some dragon's attacks, based on the dragon the hide was taken from.
+
+N:414:& Dragon Shield~
+G:[:G
+I:34:6:0
+W:70:0:100:10000
+A:80/4
+P:8:1d3:0:0:10
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_ELEC | IGNORE_COLD
+D:A large shield, with a dragonskin cover. Depending on which dragon the hide came from, it
+D:might grant protection against some sorts of dragon breath.
+
+##### Extra potions #####
+
+N:415:Death
+G:!:d
+I:71:23:0
+W:55:0:4:0
+A:55/4
+P:0:20d20:0:0:0
+F:FOUNTAIN
+D:A potent and very quickly working poison, sometimes utilised by those who wish to end their
+D:lives. It is immensely toxic and will seriously hurt you even if you just get some of it on your
+D:hands.
+
+N:416:Ruination
+G:!:d
+I:71:15:0
+W:40:0:4:0
+A:40/8
+P:0:20d20:0:0:0
+F:FOUNTAIN
+D:This wicked potion will seriously damage your abilities beyond the powers of magical
+D:restoration.
+
+N:417:Detonations
+G:!:d
+I:71:22:0
+W:60:0:4:10000
+A:60/8
+P:0:25d25:0:0:0
+F:FOUNTAIN
+D:This bottle is filled with a strange substance which will violently explode if strongly agitated.
+D:You don't want to know what it might do to your intestines.
+
+N:418:Augmentation
+G:!:d
+I:71:55:0
+W:40:0:4:60000
+A:40/16
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This blessed potion will greatly improve all your abilities, if they can still be improved.
+
+N:419:*Healing*
+G:!:d
+I:71:38:0
+W:40:0:4:1500
+A:40/4:60/2:80/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This highly desirable potion will greatly help recovering from wounds, typically healing you
+D:fully.
+
+N:420:Life
+G:!:d
+I:71:39:0
+W:60:0:4:5000
+A:60/4:100/2
+P:0:1d1:0:0:0
+D:This wonderful potion will fully heal you no matter how badly you're hurt, allow drained
+D:abilities to recover and remove various other ailments.
+
+N:421:Self Knowledge
+G:!:d
+I:71:58:0
+W:40:0:4:2000
+A:40/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A drink of insight, letting you know yourself better.
+
+N:422:*Enlightenment*
+G:!:d
+I:71:57:0
+W:70:0:4:80000
+A:70/4
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical concoction will grant you great insight, magically improving your wits and
+D:wisdom, letting you know precisely who and where you are and what you possess.
+
+# XXX
+# XXX
+
+N:425:Fear Resistance
+G:=:d
+I:45:38:0
+W:10:0:2:300
+A:10/2
+F:RES_FEAR | EASY_KNOW
+f:RES_FEAR |
+D:This ring grants courage, so that you can never become afraid.
+
+N:426:Light and Darkness Resistance
+G:=:d
+I:45:39:0
+W:30:0:2:3000
+A:30/2
+F:RES_LITE | RES_DARK | EASY_KNOW
+f:RES_LITE | RES_DARK |
+D:This ring protects against fluctuations of the light.
+
+N:427:Nether Resistance
+G:=:d
+I:45:40:0
+W:34:0:2:14500
+A:34/2
+F:RES_NETHER | HOLD_LIFE | EASY_KNOW
+f:RES_NETHER |
+D:This blessed ring improves your life force, protecting you from the draining forces of nether
+D:and other attempts to suck your lifeblood.
+
+N:428:Nexus Resistance
+G:=:d
+I:45:41:0
+W:24:0:2:3000
+A:24/2
+F:RES_NEXUS | EASY_KNOW
+f:RES_NEXUS |
+D:This ring of stability protects you from the warping forces of nexus.
+
+N:429:Sound Resistance
+G:=:d
+I:45:42:0
+W:26:0:2:3000
+A:26/2
+F:RES_SOUND | EASY_KNOW
+f:RES_SOUND |
+D:This ring projects an aura of quiet around you, protecting you from loud noise.
+
+N:430:Confusion Resistance
+G:=:d
+I:45:43:0
+W:22:0:2:3000
+A:22/2
+F:RES_CONF | EASY_KNOW
+f:RES_CONF |
+D:This ring stabilises your mind, protecting you from all kinds of befuddlement.
+
+N:431:Shard Resistance
+G:=:d
+I:45:44:0
+W:25:0:2:3000
+A:25/2
+F:RES_SHARDS | EASY_KNOW
+f:RES_SHARDS |
+D:This piece of jewellery magically toughens your skin, protecting you from flying shrapnel.
+
+N:432:Disenchantment Resistance
+G:=:d
+I:45:45:0
+W:90:0:2:15000
+A:90/10
+F:RES_DISEN | EASY_KNOW
+f:RES_DISEN |
+D:This rare ring of preservation protects your equipment from attempts to sap its magic, also
+D:causing you to suffer less pain from such attacks.
+
+N:433:Chaos Resistance
+G:=:d
+I:45:46:0
+W:50:0:2:13000
+A:50/2
+F:RES_CHAOS | RES_CONF | EASY_KNOW
+f:RES_CHAOS |
+D:This ring protects you from the horribly warping forces of chaos.
+
+N:434:Blindness Resistance
+G:=:d
+I:45:47:0
+W:60:0:2:7500
+A:60/2
+F:RES_BLIND | EASY_KNOW
+f:RES_BLIND |
+D:This ring magically preserves your eyesight, making you impervious to any attempt to blind
+D:you.
+
+N:435:Lordly Protection
+G:=:d
+I:45:48:0
+W:100:0:2:100000
+A:100/5
+F:RES_DISEN | RES_POIS | HOLD_LIFE | FREE_ACT
+f:RES_DISEN | RES_POIS | HOLD_LIFE | FREE_ACT
+D:This blessed ring will protect you from disenchantment, poison, attempts to drain your life
+D:force and holding magic.
+
+N:436:Extra Attacks
+G:=:d
+I:45:49:0
+W:50:0:2:100000
+A:50/2
+F:BLOWS
+f:BLOWS
+D:This powerful ring of fighters greatly enhances your fighting speed, allowing you to attack
+D:more often in a round of combat.
+
+N:437:Cure Light Wounds
+G:!:d
+I:71:34:50
+W:0:0:4:15
+A:0/1:1/1:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This healthy drink heals a little damage you have taken.
+
+N:438:Clumsiness
+G:!:d
+I:71:19:0
+W:5:0:4:0
+A:5/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This nasty concoction will numb your nerves, making you clumsier.
+
+N:439:Sickliness
+G:!:d
+I:71:20:0
+W:10:0:4:0
+A:10/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This unhealthy drink damages your health, reducing your physical constitution.
+
+###### Here start the maps #####
+
+# Map of Bree
+N:440:Map of Bree
+G:?:s
+I:8:200:0
+W:3:100:5:100
+A:3/3
+D:A map, showing the town of Bree and the landscape around it.
+
+# Map of Gondolin
+N:441:Map of Gondolin
+G:?:s
+I:8:201:0
+W:70:100:5:50000
+A:70/3
+D:A map detailing the place of the hidden city of Gondolin. Consider yourself lucky someone
+D:lost a map here, since the location is yet unknown even to Morgoth.
+
+# Map of Lothlorien
+N:442:Map of Lothlorien
+G:?:s
+I:8:202:0
+W:6:100:5:1000
+A:6/3
+D:A map vaguely describing the forest of Lothlorien and the elven settlements therein.
+
+# Map of Minas Anor
+N:443:Map of Minas Anor
+G:?:s
+I:8:203:0
+W:36:100:5:10000
+A:36/3
+D:A map of the great city of Gondor.
+
+# XXX Numbers 444-464 unused #
+
+N:465:& Silver Arrow~
+G:{:W
+I:17:3:0
+W:55:0:2:35
+A:50/4:90/2
+P:0:3d4:0:0:0
+F:SHOW_MODS | SLAY_EVIL | IGNORE_ACID | IGNORE_FIRE
+D:An arrow to be shot with a bow, its iron head coated with hallowed silver,
+D:a material that sears the flesh of all evil creatures.
+
+N:466:& Silver Bolt~
+G:{:w
+I:18:3:0
+W:50:0:2:40
+A:60/4:95/2
+P:0:3d5:0:0:0
+F:SHOW_MODS | SLAY_EVIL | IGNORE_ACID | IGNORE_FIRE
+D:This crossbow bolt has a silver tip, blessed by the Valar for fighting evil.
+
+N:467:Lightning Resistance
+G:":d
+I:40:29:0
+W:10:0:3:250
+A:10/1
+F:RES_ELEC | IGNORE_ELEC | EASY_KNOW
+f:RES_ELEC |
+D:This amulet will protect you from electrical discharges and storms.
+
+N:468:Wisdom
+G:":d
+I:40:28:0
+W:30:0:3:500
+A:30/1
+F:WIS | SUST_WIS | HIDE_TYPE
+f:WIS |
+D:This magical amulet will magically make you wiser, and fend off
+D:attacks that would reduce your wisdom. Beware: if cursed, the
+D:amulet will do the opposite.
+
+N:469:Regeneration
+G:":d
+I:40:30:0
+W:30:0:3:600
+A:30/3
+F:REGEN | EASY_KNOW
+f:REGEN |
+D:Wearing this amulet will trigger your body's regenerational
+D:processes quicker and make them proceed faster.
+
+N:470:Infravision
+G:":d
+I:40:26:0
+W:10:0:3:200
+A:10/1
+F:INFRA | HIDE_TYPE
+f:INFRA |
+D:This amulet will increase your ability to sense warm-blooded
+D:creatures in your vicinity. Beware: if cursed, it will do
+D:just the opposite.
+
+N:471:Devotion
+G:":d
+I:40:25:0
+W:70:0:3:30000
+A:70/8
+F:WIS | CHR | SUST_WIS | SUST_CHR | LITE1 | HIDE_TYPE |
+F:RES_DARK | RES_LITE | RES_FIRE | HOLD_LIFE |
+D:This blessed amulet will protect your wisdom and charms from
+D:diminishing, often adding to them as well. It also grants
+D:some extra protective magics by the grace of the Valar.
+
+N:472:Weaponmastery
+G:":d
+I:40:24:0
+W:70:0:3:30000
+A:70/8
+F:STR | CON | SUST_STR | SUST_CON | FREE_ACT | HIDE_TYPE |
+F:RES_FEAR | RES_DISEN |
+D:The ultimate amulet for a warrior, it will grant protection
+D:in the face of some evil magics, protect your strength and health,
+D:also increasing them. Beware: if cursed, the amulet will
+D:sap your strength and health instead.
+
+N:473:Trickery
+G:":d
+I:40:23:0
+W:70:0:3:30000
+A:70/8
+F:DEX | SUST_DEX | STEALTH | SPEED | INFRA | HIDE_TYPE |
+F:RES_NEXUS | RES_POIS
+D:The ultimate amulet for a rogue or assassin, it protects the
+D:wearer against some evil magics, granting improvements in
+D:the abilities vital to these adventurers. Beware: if cursed,
+D:the amulet will do just the opposite.
+
+N:474:Telepathy
+G:":d
+I:40:22:0
+W:50:0:3:25000
+A:50/6
+F:ESP_ALL |
+f:ESP_ALL |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This rare and powerful amulet lays bare the minds of monsters
+D:before the wearer.
+
+N:475:Sustenance
+G:":d
+I:40:21:0
+W:60:0:3:20000
+A:60/4
+F:SUST_STR | SUST_INT | SUST_WIS | SUST_DEX | SUST_CON | SUST_CHR |
+F:HOLD_LIFE | SLOW_DIGEST | EASY_KNOW |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This blessed amulet will make the wearer impervious to evil magics
+D:that would sap innate abilities. It also slows down the digestive
+D:system, making food less necessary on long journeys.
+
+# The Palantir of Minas Ithil -- see artifact list
+
+N:476:& Palantir~
+G:~:y
+I:39:107:0
+W:75:0:200:0
+P:0:10d10:0:0:0
+F:INSTA_ART
+
+# The Elfstone 'Elessar' -- see artifact list
+
+N:477:& Elfstone~
+G:":g
+I:40:19:0
+W:60:0:3:50000
+F:INSTA_ART
+
+# The Jewel 'Evenstar' -- see artifact list
+
+N:478:& Jewel~
+G:":w
+I:40:20:0
+W:50:0:3:35000
+F:INSTA_ART
+
+# The Ring of Durin -- see artifact list
+
+N:479:& Ring~
+G:=:d
+I:45:57:0
+W:70:0:2:65000
+F:INSTA_ART | SPECIAL_GENE
+
+##### And here starts the gold/gems #####
+
+N:480:copper
+G:$:u
+I:100:1:0
+W:1:0:0:3
+
+N:481:copper
+G:$:u
+I:100:2:0
+W:1:0:0:4
+
+N:482:copper
+G:$:u
+I:100:3:0
+W:1:0:0:5
+
+N:483:silver
+G:$:s
+I:100:4:0
+W:1:0:0:6
+
+N:484:silver
+G:$:s
+I:100:5:0
+W:1:0:0:7
+
+N:485:silver
+G:$:s
+I:100:6:0
+W:1:0:0:8
+
+N:486:garnets
+G:$:r
+I:100:7:0
+W:1:0:0:9
+
+N:487:garnets
+G:$:r
+I:100:8:0
+W:1:0:0:10
+
+N:488:gold
+G:$:y
+I:100:9:0
+W:1:0:0:12
+
+N:489:gold
+G:$:y
+I:100:10:0
+W:1:0:0:14
+
+N:490:gold
+G:$:y
+I:100:11:0
+W:1:0:0:16
+
+N:491:opals
+G:$:W
+I:100:12:0
+W:1:0:0:18
+
+N:492:sapphires
+G:$:b
+I:100:13:0
+W:1:0:0:20
+
+N:493:rubies
+G:$:r
+I:100:14:0
+W:1:0:0:24
+
+N:494:diamonds
+G:$:w
+I:100:15:0
+W:1:0:0:28
+
+N:495:emeralds
+G:$:g
+I:100:16:0
+W:1:0:0:32
+
+N:496:mithril
+G:$:B
+I:100:17:0
+W:1:0:0:40
+
+N:497:adamantite
+G:$:G
+I:100:18:0
+W:1:0:0:80
+
+
+##### Objects 498 and 499 are the "Morgoth Artifacts" #####
+
+# These objects, like objects 500 to 511, are never created
+# without being turned into artifacts. This simplifies the
+# code for "killing the winner monster".
+
+N:498:& Mighty Hammer~
+G:\:D
+I:21:50:0
+W:15:0:200:1000
+P:0:3d9:0:0:0
+F:SHOW_MODS | INSTA_ART | MUST2H | SPECIAL_GENE
+f:MUST2H
+
+N:499:& Massive Iron Crown~
+G:]:D
+I:33:50:0
+W:44:0:20:1000
+P:0:1d1:0:0:0
+F:INSTA_ART | SPECIAL_GENE
+
+
+##### Objects 500 to 511 are "Special Artifacts" #####
+
+# These objects do not specify "full names" because the artifact name
+# is added in "obj-desc.c" based on the artifact index ("i_ptr->name1").
+#
+# These objects do specify a "base name", which is used when the object
+# is "aware" (always true for lites)
+#
+# The Lites (and the One Ring) specify "physical colors", which
+# over-ride the "flavor" colors, if any. Note that the "One Ring"
+# also has a specific check for "unknown" in which it changes its
+# name to "a plain gold ring". See "object1.c"
+#
+# Note that ALL artifacts are given "IGNORE_ACID/ELEC/FIRE/COLD",
+# so we do not need to specify that here.
+#
+# Note that the "INSTA_ART" flag is used to prevent these objects from
+# being created without also turning them into artifacts. This flag
+# must be specified both here and in the artifact template.
+#
+# The only reason for having six different "ring" templates and three
+# different "amulet" templates is to allow each "special artifact" to
+# have a different "color" and "flavor", and also to allow the use of
+# special "base names" (such as "Necklace").
+
+
+# The Phial of Galadriel -- see artifact list
+
+N:500:& Phial~
+G:~:y
+I:39:100:0
+W:20:0:10:10000
+P:0:1d1:0:0:0
+F:INSTA_ART
+
+# The Star of Elendil -- see artifact list
+
+N:501:& Star~
+G:~:B
+I:39:101:0
+W:30:0:5:25000
+P:0:1d1:0:0:0
+F:INSTA_ART
+
+# The Arkenstone of Thrain -- see artifact list
+
+N:502:& Arkenstone~
+G:~:R
+I:39:102:0
+W:60:0:5:60000
+P:0:1d1:0:0:0
+F:INSTA_ART
+
+
+# The Amulet of Carlammas -- see artifact list
+
+N:503:& Amulet~
+G:":d
+I:40:10:0
+W:50:0:3:60000
+F:INSTA_ART
+
+# The Amulet of Ingwe -- see artifact list
+
+N:504:& Amulet~
+G:":d
+I:40:11:0
+W:60:0:3:90000
+F:INSTA_ART
+
+# The Necklace 'Nauglamir' -- see artifact list
+
+N:505:& Necklace~
+G:":d
+I:40:12:0
+W:70:0:3:75000
+F:INSTA_ART
+
+
+# The Ring of Barahir -- see artifact list
+
+N:506:& Ring~
+G:=:d
+I:45:32:0
+W:50:0:2:65000
+F:INSTA_ART
+
+# The Ring of Tulkas -- see artifact list
+
+N:507:& Ring~
+G:=:d
+I:45:33:0
+W:90:0:2:150000
+F:INSTA_ART
+
+# The Ring of Power 'Narya' -- see artifact list
+
+N:508:& Ring~
+G:=:d
+I:45:34:0
+W:80:0:2:100000
+F:INSTA_ART | SPECIAL_GENE
+
+# The Ring of Power 'Nenya' -- see artifact list
+
+N:509:& Ring~
+G:=:d
+I:45:35:0
+W:90:0:2:200000
+F:INSTA_ART
+
+# The Ring of Power 'Vilya' -- see artifact list
+
+N:510:& Ring~
+G:=:d
+I:45:36:0
+W:100:0:2:300000
+F:INSTA_ART
+
+# The Ring of Power 'The One Ring' -- see artifact list
+
+N:511:& Ring~
+G:=:y
+I:45:37:0
+W:110:0:2:5000000
+F:INSTA_ART
+
+
+### Room for new objects added after 511 (Zangband 2.1.0): 512-575
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+N:520:Reflection
+G:":d
+I:40:9:0
+W:60:0:3:30000
+A:60/4
+F:REFLECT | EASY_KNOW
+f:REFLECT |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This wondrous amulet will magically make the wearer
+D:reflect arrows and bolts launched by adversaries.
+
+#521 and 522 cannot have EASY_KNOW because they may be cursed
+
+N:521:Anti-Magic
+G:":d
+I:40:13:0
+W:40:0:3:30000
+A:40/4
+F:NO_MAGIC
+f:NO_MAGIC
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This amulet wards off magic of any kind, good or bad.
+
+N:522:Anti-Teleportation
+G:":d
+I:40:14:0
+W:30:0:3:15000
+A:30/4
+F:NO_TELE
+f:NO_TELE
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This amulet will prevent the space-time continuum from
+D:being disrupted around the wearer.
+
+#523 cannot have EASY_KNOW because it can get random resistances
+
+N:523:Resistance
+G:":d
+I:40:15:0
+W:50:0:3:25000
+A:50/4
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD
+f:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This amulet will make the wearer resist the elements.
+
+##### New arms #####
+
+N:524:& Zweihander~
+G:|:w
+I:23:29:0
+W:40:0:280:580
+A:40/3
+P:0:4d6:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This great sword of foreign origin is approximately 6 feet long. The hilt is
+D:long enough for even four hands to grip. A mighty weapon for a warrior.
+
+# Dwarven lantern
+N:525:& Dwarven Lantern~
+G:~:b
+I:39:3:0
+W:15:0:50:5000
+A:15/2
+P:0:1d1:0:0:0
+F:EASY_KNOW | IGNORE_FIRE | LITE2
+f:LITE2
+D:Made by the dwarves, this lantern provides light in the
+D:darkest recesses of the earth.
+
+N:526:& Splint Mail~
+G:[:D
+I:37:10:0
+W:35:0:250:950
+A:35/1
+P:19:1d4:-2:0:0
+D:A suit of metal armour that consists of metal strips applied vertically
+D:to the backing of chain, leather, or cloth.
+
+# Everburning torch
+N:527:& Everburning Torch~
+G:~:R
+I:39:2:0
+W:5:0:50:2500
+A:5/1
+P:0:1d1:0:0:0
+F:EASY_KNOW | IGNORE_FIRE | LITE1
+f:LITE1
+D:This enchanted torch never needs to be fuelled.
+
+N:528:& Trifurcate Spear~
+G:/:o
+I:22:26:0
+W:35:0:140:400
+A:35/3
+P:0:2d9:0:0:0
+F:SHOW_MODS
+D:This deadly spear's point has three branches, suited for inflicting
+D:greater damage than a regular spear.
+
+N:529:& Three Piece Rod~
+G:\:u
+I:21:11:0
+W:20:0:120:350
+A:20/3
+P:0:3d3:0:0:0
+F:SHOW_MODS
+D:A descendant of the threshing flail, consisting of three short wooden
+D:pieces linked by chain or rope.
+
+# Feanorian Lamp
+N:530:& Feanorian Lamp~
+G:~:B
+I:39:4:0
+W:25:0:50:15000
+A:25/3
+P:0:1d1:0:0:0
+F:EASY_KNOW | IGNORE_FIRE | LITE3
+f:LITE3
+D:Made by the descendants of the Noldo craftsman, this lamp
+D:contains a part of the flame which burned inside Feanor.
+
+N:531:& Fur Cloak~
+G:(:W
+I:35:3:0
+W:20:0:30:100
+A:20/2:30/2
+P:3:0d0:0:0:0
+D:A coat made from the fur of various wild animals - it is
+D:somewhat bulky, but still spacious enough to wear over armour.
+
+N:532:Water Curing
+G:!:d
+I:72:18:80
+W:0:0:4:0
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE
+D:It is a magical component that can purify water.
+
+N:533:& Hatchet~
+G:/:s
+I:24:1:0
+W:10:0:60:120
+A:10/2
+P:0:1d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This is a large axe that could be wielded in one or two hands. It has
+D:a single blade with a pick on the reverse, designed for armour piercing.
+
+##### New armour #####
+
+N:535:& Rhino Hide Armour~
+G:(:s
+I:36:8:0
+W:15:0:110:400
+A:15/1
+P:8:1d1:-1:0:0
+D:A hard leather armour made from the thick hide of a rhinoceros.
+
+N:536:& Leather Jacket~
+G:(:U
+I:36:12:0
+W:20:0:130:550
+A:20/3
+P:12:1d2:-1:0:0
+D:A garment fashioned from animal hide, resembling a robe that has been
+D:shortened to waist-length, with straight-cut sleeves and a bit of decorative
+D:fringe around the collar.
+
+##### New weapons #####
+
+N:537:& Sickle~
+G:/:s
+I:22:3:0
+W:10:0:70:110
+A:10/3
+P:0:2d3:0:0:0
+F:SHOW_MODS
+D:A semicircular blade attached to a short handle, good for chopping
+D:things up into pieces.
+
+# XXX
+# XXX
+# XXX
+# XXX
+
+N:542:& Club~
+G:\:u
+I:21:1:0
+W:0:0:100:3
+A:0/1
+P:0:1d4:0:0:0
+F:SHOW_MODS
+D:A stout heavy stick, thicker at one end. Useful for
+D:shattering and smashing things.
+
+N:543:& Broad Spear~
+G:/:w
+I:22:7:0
+W:14:0:100:240
+A:14/3
+P:0:1d9:0:0:0
+F:SHOW_MODS
+D:Designed specifically for foot soldiers combatting cavalry, this spear
+D:is too heavy to be effective when thrown.
+
+N:544:& Khopesh~
+G:|:W
+I:23:14:0
+W:10:0:130:190
+A:10/2
+P:0:2d4:0:0:0
+F:SHOW_MODS
+D:This sword comes from the regions of Far Harad. The blade is straight
+D:for 18 inches, and then it curves for another 2 feet.
+
+N:545:& Flamberge~
+G:|:W
+I:23:26:0
+W:40:0:230:600
+A:40/2
+P:0:3d7:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:A large, two-handed sword with a blade that weaves
+D:left and right until it reaches the hilt.
+
+N:546:& Claymore~
+G:|:W
+I:23:23:0
+W:40:0:200:600
+A:40/2
+P:0:2d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:Also known as a Claidhmore, or Greatsword, this weapon is favoured
+D:by powerful mercenaries. The blade is large, straight, and broad,
+D:almost as large as a two-handed sword.
+
+N:547:& Espadon~
+G:|:W
+I:23:24:0
+W:40:0:200:600
+A:40/3
+P:0:2d9:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This is the strictly two-handed version of the bastard sword.
+D:The blade is of medium length, double-edged, and considerably
+D:heavy to wield.
+
+N:548:& Great Scimitar~
+G:|:W
+I:23:22:0
+W:40:0:240:500
+A:40/3
+P:0:4d5:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This is a larger version of the curved oriental blade.
+D:Runes of war decorate its golden hilt.
+
+
+### Trapping Kits
+
+N:549:Arrow
+G:`:r
+I:46:2:0
+W:10:0:60:150
+A:10/2:50/2
+F:SHOW_MODS
+D:It must be loaded with arrows, which will be
+D:fired at the monster who triggers the trap.
+
+N:550:Bolt
+G:`:o
+I:46:3:0
+W:20:0:220:300
+A:20/2:50/2
+F:SHOW_MODS
+D:It must be loaded with crossbow bolts, which will
+D:be fired at the monster who triggers the trap.
+
+N:551:& Fauchard~
+G:/:s
+I:22:6:0
+W:18:0:155:301
+A:18/2
+P:0:1d10:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:It is a type of glaive with two ornate hooks on the back
+D:of the blade. It is typically 8 to 9 feet long.
+
+N:552:& Guisarme~
+G:/:s
+I:22:16:0
+W:21:0:165:320
+A:21/1
+P:0:2d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:Mounted on a long shaft for maximum reach, this weapon is
+D:effective at repelling both cavalry and infantry.
+
+N:553:& Heavy Lance~
+G:/:s
+I:22:29:0
+W:43:0:400:700
+A:43/2
+P:0:4d8:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This is a shock weapon. Its purpose is to unhorse a rider
+D:in single combat, or smash through the armour of opposing lines.
+
+N:554:& Basilard~
+G:|:w
+I:23:9:0
+W:15:0:80:220
+A:15/3
+P:0:1d8:0:0:0
+F:SHOW_MODS
+D:This is a two-edged dagger with a long blade. A favourite among travellers
+D:and warriors alike, it can be worn comfortably with plain clothes
+D:as well as armour.
+
+### Trapping Kits
+
+N:555:Catapult
+G:`:R
+I:46:1:0
+W:1:0:50:40
+A:1/2:20/2
+F:SHOW_MODS
+D:It must be loaded with sling bullets, which will
+D:be fired at the monster who triggers the trap.
+
+N:556:& Ring Mail~
+G:[:s
+I:37:2:0
+W:20:0:200:500
+A:20/1
+P:12:1d4:-2:0:0
+D:A suit of non-overlapping metal rings sewn onto a
+D:heavy leather backing.
+
+N:557:& Cord Armour~
+G:(:y
+I:36:9:0
+W:5:0:80:40
+A:5/1
+P:6:1d1:0:0:0
+D:Fibres of hemp or other natural material woven and knotted
+D:into a thick, tough fabric.
+
+N:558:& Paper Armour~
+G:(:w
+I:36:3:0
+W:5:0:30:40
+A:5/2
+P:4:1d1:0:0:0
+D:Thickly pleated sheets of paper assembled together into
+D:a suit of armour.
+
+N:559:& Padded Armour~
+G:(:y
+I:36:10:0
+W:2:0:60:40
+A:2/1
+P:4:1d1:0:0:0
+D:Heavy, multi-layered cloth sewn together to cover the body,
+D:with extra padding between layers.
+
+### Trapping Kits
+
+N:560:Fumes
+G:`:G
+I:46:4:0
+W:2:0:20:50
+A:2/2:30/2
+D:It must be loaded with potions, which will splatter
+D:over the monster who triggers the trap.
+
+N:561:& Stone and Hide Armour~
+G:(:U
+I:36:15:0
+W:35:0:200:500
+A:35/7
+P:15:1d1:-1:0:0
+D:A primitive armour made from a thick hide reinforced by stone shards.
+
+### Trapping Kits
+
+N:562:Magic
+G:`:g
+I:46:5:0
+W:5:0:20:50
+A:5/2:40/2
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC
+D:It must be loaded with scrolls, which will release
+D:their spells at the monster who triggers the trap.
+
+N:563:Device
+G:`:v
+I:46:6:0
+W:20:0:20:50
+A:20/2:40/2:60/2
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC
+D:It must be loaded with a magic device (wand, staff, or rod), which
+D:will fire its spell at the monster who triggers the trap.
+
+N:564:Nothing
+G:?:d
+I:70:53:0
+W:1:0:5:2
+A:1/1
+P:0:1d1:0:0:0
+
+N:565:Poison
+G:*:G
+I:4:1:5
+W:0:0:4:2
+A:0/1
+P:0:1d1:0:0:0
+
+# wand
+N:566:Nothing
+G:-:d
+I:65:2:-1:SPELL=Nothing
+W:2:0:10:20
+A:2/1
+P:0:1d1:0:0:0
+F:NO_RECHARGE | SPECIAL_GENE
+
+N:567:Nothing
+G:=:d
+I:45:50:0
+W:5:0:2:20
+A:5/1
+P:0:1d1:0:0:0
+
+N:568:Nothing
+G:_:d
+I:55:30:0
+W:5:0:50:50
+A:5/1
+P:0:1d1:0:0:0
+F:NO_RECHARGE | SPECIAL_GENE
+
+N:569:Nothing
+G:-:d
+I:66:0:1
+W:5:0:10:50
+A:5/1
+P:0:1d1:0:0:0
+
+
+# Here comes the Essences (randomly interspersed with other stuff...)
+
+N:570:Explosion
+G:*:G
+I:4:2:50
+W:0:0:4:2
+A:0/1:20/1:40/1:60/1
+P:0:1d1:0:0:0
+
+N:571:Teleport
+G:*:G
+I:4:3:190
+W:0:0:4:2
+A:5/1:20/1:40/1:60/1
+P:0:1d1:0:0:0
+
+# Amulet of Nothing
+
+N:572:Nothing
+G:":d
+I:40:16:0
+W:10:0:3:20
+A:10/1
+P:0:1d1:0:0:0
+
+# An artifact potion! The Blood of Life...
+
+N:573:& Blood~ of Life
+G:!:d
+I:71:3:200
+W:70:0:4:10000
+A:70/16
+P:0:1d1:0:0:0
+T:71:2
+F:NORM_ART | FULL_NAME
+D:Quaffing this measure of living blood will imbue your body and soul
+D:with the power to escape death one time.
+
+N:574:Cold
+G:*:G
+I:4:4:200
+W:0:0:4:2
+A:5/1:20/1:40/1:60/1
+P:0:1d1:0:0:0
+
+N:575:Fire
+G:*:G
+I:4:5:200
+W:0:0:4:2
+A:5/1:20/1:40/1:60/1
+P:0:1d1:0:0:0
+
+N:576:Acid
+G:*:G
+I:4:6:200
+W:0:0:4:2
+A:6/1:20/1:40/1:60/1
+P:0:1d1:0:0:0
+
+# Mage staffs (for Sorcerers to wield.)
+
+N:577:& Mage Staff~
+G:\:B
+I:6:1:0
+W:5:0:12:300
+A:5/1:20/1:50/1:80/1
+P:0:1d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:It looks like a simple walking stick, plain and nondescript.
+D:In the hands of a spellcaster, it can be a deadly weapon.
+
+# An extra ring, out of place
+
+N:578:Lightning
+G:=:d
+I:45:56:0
+W:50:0:2:3000
+A:50/1
+P:0:0d0:0:0:15
+a:HARDCORE=BA_ELEC_4
+F:RES_ELEC | IGNORE_ELEC | ACTIVATE
+f:RES_ELEC |
+D:This sparkling circlet grants you protection, makes electricity less
+D:dangerous and even allows you to call forth a ball of lightning.
+
+# More essences
+
+N:579:Life
+G:*:G
+I:4:7:300
+W:0:0:4:2
+A:0/1:20/1:40/1:60/1
+P:0:1d1:0:0:0
+
+N:580:Confusion
+G:*:G
+I:4:8:100
+W:0:0:4:2
+A:0/1:20/1:40/1:60/1
+P:0:1d1:0:0:0
+
+N:581:Light
+G:*:G
+I:4:9:60
+W:0:0:4:2
+A:0/1:20/1:40/1:60/1
+P:0:1d1:0:0:0
+
+# The Ring of Flare -- see artifact list
+
+N:582:& Ring~
+G:=:y
+I:45:52:5
+W:50:25:2:75000
+F:INSTA_ART
+
+# Potion of Invisibility
+
+N:583:Invisibility
+G:!:d
+I:71:8:0
+W:3:0:4:50
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical brew will temporarily hide you from sight, and also attunes you
+D:to this state so that your eyes can still perceive your hidden form.
+
+N:584:Chaos
+G:*:G
+I:4:10:200
+W:20:0:4:2
+A:20/1
+P:0:1d1:0:0:0
+F:ATTR_MULTI
+
+# Potion of Corruption
+
+N:585:Corruption
+G:!:d
+I:71:10:0
+W:3:0:4:0
+A:20/1:30/1:40/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This concoction of toxic wastes will strangely warp your shape.
+
+# Ring of Invisibility
+
+N:586:Invisibility
+G:=:d
+I:45:53:4
+W:50:0:2:10000
+A:50/1
+F:INVIS | HIDE_TYPE
+f:INVIS |
+D:This magical bauble will hide you from sight.
+
+### Just another essence, to confuse the edit file hackers ;) ###
+
+N:587:Time
+G:*:G
+I:4:11:600
+W:20:0:4:2
+A:20/1:40/1:60/1
+P:0:1d1:0:0:0
+
+######### Here are the parchments ########
+
+N:588:Deep Thoughts
+G:?:o
+I:8:0:0
+W:3:0:5:50
+A:3/1
+D:This parchment contains the thoughts of a powerful
+D:wizard who departed Middle-earth long ago.
+
+N:589:More Deep Thoughts
+G:?:o
+I:8:1:0
+W:4:0:5:50
+A:4/1
+D:This parchment contains the thoughts of a powerful
+D:wizard who departed Middle-earth long ago.
+
+N:590:Compendium of Deep Thoughts
+G:?:o
+I:8:2:0
+W:5:0:5:50
+A:5/1
+D:This parchment contains the thoughts of a powerful
+D:wizard who departed Middle-earth long ago.
+
+N:591:Artifact Lore Vol. I
+G:?:o
+I:8:6:0
+W:40:0:5:50
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+N:592:Artifact Lore Vol. II
+G:?:o
+I:8:7:0
+W:40:0:5:50
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+N:593:Artifact Lore Vol. III
+G:?:o
+I:8:8:0
+W:40:0:5:50
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+N:594:Monstrous Compendium 1
+G:?:o
+I:8:9:0
+W:10:0:5:50
+A:10/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:595:Monstrous Compendium 2
+G:?:o
+I:8:10:0
+W:11:0:5:50
+A:11/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:596:Monstrous Compendium 3
+G:?:o
+I:8:11:0
+W:12:0:5:50
+A:12/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:597:Monstrous Compendium 4
+G:?:o
+I:8:12:0
+W:13:0:5:50
+A:13/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:598:Monstrous Compendium 5
+G:?:o
+I:8:13:0
+W:14:0:5:50
+A:14/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:599:Monstrous Compendium 6
+G:?:o
+I:8:14:0
+W:15:0:5:50
+A:15/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:600:Monstrous Compendium 7
+G:?:o
+I:8:15:0
+W:16:0:5:50
+A:16/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:601:Monstrous Compendium 8
+G:?:o
+I:8:16:0
+W:17:0:5:50
+A:17/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:602:Monstrous Compendium 9
+G:?:o
+I:8:17:0
+W:18:0:5:50
+A:18/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:603:Monstrous Compendium 10
+G:?:o
+I:8:18:0
+W:19:0:5:50
+A:19/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:604:Monstrous Compendium 11
+G:?:o
+I:8:19:0
+W:20:0:5:50
+A:20/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+#### Here come the shape-shifting potions. ####
+
+N:605:& Morphic Oil~ of #
+G:!:d
+I:72:1:0
+W:5:0:4:100
+A:1/3:5/1:10/1
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This concoction can transform your body for a short period of time.
+
+# XXX 606 -> 617
+
+# The Mimic's cloaks
+
+N:618:& #~
+G:(:y
+I:35:100:0:50
+W:5:130:30:100
+A:5/1:15/1:35/1:55/1:75/1
+P:1:1d1:0:0:0
+D:Combined with proper skill, this cloak can make you seem
+D:like a different creature. Otherwise, it just provides some
+D:extra protection.
+
+# XXX 619 -> 639
+
+# One more essence...
+
+N:640:Magic
+G:*:G
+I:4:12:700
+W:20:0:4:2
+A:30/1:50/1:80/1
+P:0:1d1:0:0:0
+
+# Here are the corpses
+
+N:641:corpse
+G:~:U
+I:9:1:3000
+W:20:0:80:0
+A:30/1
+P:0:1d1:0:0:0
+F:DECAY
+D:Whatever happened with this one, it wasn't pretty.
+
+N:642:skeleton
+G:~:U
+I:9:2:800
+W:20:0:2:0
+A:30/1
+P:0:1d1:0:0:0
+D:The sorry, bony remains of some hapless creature.
+
+N:643:head
+G:~:U
+I:9:3:600
+W:20:0:10:0
+A:30/1
+P:0:1d1:0:0:0
+F:DECAY
+D:2 eyes, 2 ears, a mouth, some hair -- yep, that's a head.
+
+N:644:skull
+G:~:U
+I:9:4:1000
+W:20:0:20:0
+A:30/1
+P:0:1d1:0:0:0
+D:It's a white bony skull, smiling to you without teeth.
+
+N:645:raw meat
+G:~:U
+I:9:5:1200
+W:20:0:10:2
+A:30/1
+P:0:1d1:0:0:0
+F:DECAY
+D:Yuck, just looking at it makes your stomach upset.
+
+# New armour: Thunderlord Coat. (With two low resists, it shouldn't be
+# at only 5th level. Make it 25th. -JLE...)
+
+N:646:& Thunderlord Coat~
+G:(:y
+I:36:16:0
+W:5:0:60:400
+A:25/1
+P:9:1d1:0:0:0
+F:RES_FIRE | RES_COLD |
+D:This suit of thick impregnated cloth is worn by the riders of flying steeds,
+D:and protects them from extremes of temperatures.
+
+# The Stone of Lore -- see artifact list
+N:647:& Stone~
+G:~:g
+I:39:106:0
+W:15:0:15:20000
+F:INSTA_ART | SPECIAL_GENE
+
+# Here are the boomerangs
+
+N:648:& Small Wooden Boomerang~
+G:{:y
+I:15:1:0
+W:1:0:60:10
+A:1/1:5/2:10/2:20/2
+P:0:1d4:0:0:0
+D:A small curved piece of wood.
+
+N:649:& Wooden Boomerang~
+G:{:y
+I:15:2:0
+W:10:0:60:100
+A:10/1:20/2
+P:0:1d8:0:0:0
+D:A strange, curved leaf-shaped piece of wood.
+
+N:650:& Small Metal Boomerang~
+G:{:y
+I:15:3:0
+W:20:0:60:400
+A:20/1:30/2
+P:0:3d4:0:0:0
+D:A short boomerang with metal blades on the "forward" edges.
+
+N:651:& Metal Boomerang~
+G:{:y
+I:15:4:0
+W:30:0:60:800
+A:30/1:50/2
+P:0:4d5:0:0:0
+D:A strange curved leaf-shaped piece of wood, its "forward" edges enhanced with metal blades.
+
+# The Space-Time Anchor -- see artifact list
+N:652:& Anchor~
+G:~:v
+I:39:105:0
+W:30:0:15:50000
+F:INSTA_ART
+
+# To convert monsters into objects for wielding them ! ! ! :)
+# Funny, funny, funny :)
+# pval the monster idx, pval2 for the monster hp
+N:653:& ~
+G:~:y
+I:99:1:0
+W:127:200:60:0
+A:127/255
+P:0:0d0:0:0:0
+
+N:654:Summon Never-Moving Pet
+G:?:d
+I:70:6:0
+W:5:0:5:125
+A:5/1:15/1:25/1:35/1:65/1:85/1:95/1
+D:A piece of paper, inscribed with runes which will summon an immobile creature to your aid.
+
+# XXX
+# XXX
+
+###The potions of cure insanity, in light, medium, regular, and full
+###versions. Cure light's W:x entry reduced to 1, so it doesn't boost level rating when appearing
+###at 50' - nyra
+
+N:657:Cure Light Insanity
+G:!:d
+I:72:14:0
+W:1:5:4:15
+A:5/1:1/1:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A magical potion which drives away irrational quirks of behaviour.
+
+N:658:Cure Serious Insanity
+G:!:d
+I:72:15:0
+W:10:5:4:40
+A:10/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A magical brew which will lift shadows that have been cast on your soul.
+
+N:659:Cure Critical Insanity
+G:!:d
+I:72:16:0
+W:15:5:4:100
+A:15/3
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This drink will cure you even of serious mental disorders.
+
+N:660:Cure Insanity
+G:!:d
+I:72:17:0
+W:25:5:4:300
+A:25/3
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This blessed potion can make you completely sane and healthy, even if you have only the
+D:faintest shred of sanity left.
+
+# The Phial of Undeath -- see artifact list. He he he he...
+
+N:661:& Phial~
+G:~:y
+I:39:103:0
+W:1:0:10:0
+P:0:1d1:0:0:0
+F:INSTA_ART
+
+# Here is the random artifact type.
+# This is used as a template -- the sval will be chosen later
+# on in the game to be an index to the random_artifacts array,
+# which in turn determines:
+#
+# Name
+# Color
+# Level
+# Cost
+
+N:662:Random Artifact
+G:~:o
+I:102:0:0
+W:1:0:50:0
+A:1/1:10/1:20/1:30/1
+F:INSTA_ART | ACTIVATE | ACTIVATE_NO_WIELD
+
+N:663:Craftsmanship
+G:?:d
+I:70:19:0
+W:80:0:5:200000
+A:80/16
+D:A powerful scroll, desired by many, as it can magically improve the special powers of magical
+D:weaponry.
+
+# A Parchment, not the Artifact
+N:664:The One Ring
+G:?:s
+I:8:4:0
+W:10:100:5:50
+A:10/2
+D:This parchment contains words in the Black Speech and Westron,
+D:and they seem to speak of a powerful Ring... could it be true?
+
+# XXX 665 - 668 were the old music books
+
+### Musical Instruments ###
+
+N:669:& Horn~
+G:/:W
+I:14:60:1
+W:7:0:30:400
+A:7/2:20/1:40/1:80/1
+P:0:1d1:0:0:0
+F:CON | ACTIVATE | WIELD_CAST
+D:A simple wind instrument made from brass. If used by inexperienced musicians it sounds
+D:like somebody making "prbbt!" noises down a drainpipe.
+
+N:670:& Drum~
+G:/:W
+I:14:58:1
+W:7:0:30:400
+A:7/2:20/1:40/1:80/1
+P:0:1d1:0:0:0
+F:STR | WIELD_CAST
+D:A sort of clay pot with a bit of skin stretched over its mouth.
+
+N:671:& Harp~
+G:/:W
+I:14:59:1
+W:7:0:30:400
+A:7/2:20/1:40/1:80/1
+P:0:1d1:0:0:0
+F:CHR | WIELD_CAST
+D:A number of strings held by a wooden frame.
+
+#N:672:& Banjo~
+#G:/:W
+#I:14:2:0
+#W:15:0:30:200
+#A:15/1
+#P:0:1d1:0:0:0
+#D:A combination of kithara and tambourine. It looks strange and sounds bad.
+
+#N:673:& Lute~
+#G:/:W
+#I:14:3:0
+#W:20:0:30:200
+#A:20/1
+#P:0:1d1:0:0:0
+#D:A string instrument, to be plucked with your fingers.
+
+#N:674:& Mandolin~
+#G:/:W
+#I:14:4:0
+#W:25:0:30:300
+#A:25/1
+#P:0:1d1:0:0:0
+#D:A small string instrument, typically strummed with your fingers or a plectron.
+
+# The Palantir of Orthanc -- see artifact list
+
+N:675:& Palantir~
+G:~:y
+I:39:104:0
+W:75:0:200:100000
+P:0:10d10:0:0:0
+F:INSTA_ART
+
+### The Monster Egg template; note the theoretical weight of 3 lbs ###
+
+N:676:Egg
+G:,:W
+I:10:1:0
+W:5:0:30:100
+A:5/1:15/1:25/1:35/1
+P:0:1d1:0:0:0
+F:ACTIVATE | ACTIVATE_NO_WIELD
+
+### Two more scrolls ###
+
+N:677:Reset Recall
+G:?:d
+I:70:23:0
+W:20:0:5:125
+A:20/1:25/1:35/1
+D:A strange formula is inscribed on this scroll, which allows you to define another place as the
+D:location to which recalls shall move you.
+
+N:678:Divination
+G:?:d
+I:70:31:0
+W:20:0:5:600
+A:30/1:45/1:55/1
+D:This scroll is inscribed with a ritual which allows you to discern what fate holds in store for
+D:you.
+
+### Here comes the Runes ###
+
+N:679:Self
+G:?:b
+I:105:0:0
+W:3:5:2:40
+A:3/1
+P:0:1d1:0:0:0
+
+N:680:Ray
+G:?:b
+I:105:2:0
+W:10:5:2:300
+A:10/1
+P:0:1d1:0:0:0
+F:IGNORE_COLD | IGNORE_ELEC
+
+N:681:Sphere
+G:?:b
+I:105:3:0
+W:15:5:2:1000
+A:15/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:682:Knowledge
+G:?:b
+I:104:91:0
+W:6:5:2:200
+A:6/1
+P:0:1d1:0:0:0
+
+N:683:Life
+G:?:D
+I:104:53:0
+W:3:5:2:200
+A:3/1
+P:0:1d1:0:0:0
+
+N:684:Fire
+G:?:r
+I:104:5:0
+W:10:5:2:300
+A:10/1
+P:0:1d1:0:0:0
+F:IGNORE_FIRE
+
+N:685:Cold
+G:?:b
+I:104:4:0
+W:12:5:2:300
+A:12/1
+P:0:1d1:0:0:0
+F:IGNORE_COLD
+
+N:686:Lightning
+G:?:W
+I:104:1:0
+W:13:5:2:300
+A:13/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC
+
+N:687:Acid
+G:?:B
+I:104:3:0
+W:16:5:2:300
+A:16/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID
+
+N:688:Element
+G:?:g
+I:104:10:0
+W:23:5:2:1000
+A:23/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:689:Chaos
+G:?:v
+I:104:30:0
+W:26:5:2:2000
+A:26/1
+P:0:1d1:0:0:0
+F:ATTR_MULTI
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:690:Mind
+G:?:D
+I:104:85:0
+W:19:5:2:3000
+A:19/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC
+
+N:691:Holding
+G:?:B
+I:104:75:0
+W:5:5:2:500
+A:5/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID
+
+N:692:Arrow
+G:?:b
+I:105:1:0
+W:6:5:2:100
+A:6/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC
+
+N:693:Power Surge
+G:?:b
+I:105:4:0
+W:50:5:2:5000
+A:50/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | IGNORE_ACID
+
+N:694:Armageddon
+G:?:b
+I:105:5:0
+W:30:5:2:4000
+A:30/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | IGNORE_ACID
+
+N:695:Gravity
+G:?:G
+I:104:35:0
+W:16:5:2:300
+A:16/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID
+
+# And, among the runes, one more essence...
+
+N:696:Extra Life
+G:*:G
+I:4:13:900
+W:50:0:4:2
+A:50/1:70/1:90/1
+P:0:1d1:0:0:0
+
+# Now, the rest of the runes...
+
+N:697:Undeath
+G:?:G
+I:104:92:0
+W:35:5:2:1000
+A:35/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID
+
+N:698:Protection
+G:?:G
+I:104:74:0
+W:45:5:2:1500
+A:45/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID
+
+# XXX
+
+# The Ring of Precognition (now a k_info.txt artifact)
+N:700:& Ring~ of Precognition
+G:=:d
+I:45:51:0
+W:90:0:2:300000
+A:90/100
+T:45:23
+F:PRECOGNITION |
+f:PRECOGNITION |
+F:NORM_ART | FULL_NAME
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This magical ring allows you to know what you will encounter in the near future.
+
+# Athelas, cures Black Breath
+
+N:701:& Sprig~ of Athelas
+G:,:g
+I:80:40:0
+W:25:5:2:450
+A:25/2:55/1:85/1
+D:'When the black breath blows / And death's shadow grows /
+D:And all lights pass / Come Athelas! Come Athelas! /
+D:Life to the dying / In the King's hands lying.'
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+# The Scroll of Deincarnation (now an artifact)
+
+N:720:& Old Scroll~ of Deincarnation
+G:?:d
+I:70:40:0
+W:90:0:5:160000
+A:90/140
+T:70:51
+F:NORM_ART | FULL_NAME
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:It allows you to leave your body to reincarnate into
+D:another one. However, your current body is lost in the process.
+
+N:721:& Dark Sword~
+G:|:D
+I:23:33:0
+W:25:0:70:500
+A:25/1:80/2
+P:0:3d7:0:0:0
+F:SHOW_MODS | ANTIMAGIC_50
+f:ANTIMAGIC_50
+D:A strange, very sharp long sword, which seems to drain light from its surroundings. As you
+D:wield it, you feel much less attuned to magic.
+
+N:722:Numenorean for Beginners (I)
+G:?:s
+I:8:101:0
+W:10:100:5:50
+A:10/2
+D:These ancient words still contain magic.
+
+N:723:Numenorean for Beginners (II)
+G:?:s
+I:8:102:0
+W:5:100:5:50
+A:5/2
+D:These ancient words still contain magic.
+
+N:724:Advanced Lessons of Numenorean
+G:?:s
+I:8:103:0
+W:20:100:5:50
+A:20/2
+D:These ancient words still contain magic.
+
+N:725:Advanced Lessons of Sindarin
+G:?:s
+I:8:104:0
+W:20:100:5:50
+A:20/2
+D:These ancient words still contain magic.
+
+##### Junk #####
+
+N:726:& Shard~ of Pottery
+G:~:r
+I:11:3:0
+W:0:0:5:0
+A:0/1
+P:0:1d1:0:0:0
+F:EASY_KNOW
+D:Half a clay jar -- how many failed artists have taken refuge in these dungeons?
+
+N:727:& Broken Stick~
+G:~:r
+I:11:6:0
+W:0:0:3:0
+A:0/1
+P:0:1d1:0:0:0
+F:EASY_KNOW
+D:A piece of rotten wood.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+N:738:& Book~ of Beginner Cantrips
+G:?:w
+I:111:50:0
+W:5:0:30:100
+A:5/1
+P:0:1d1:0:0:0
+D:The blood smudged on the cover makes you wonder how many people had it before you...
+
+N:739:& Book~ of Teleportation
+G:?:w
+I:111:51:0
+W:10:0:30:1000
+A:10/1
+P:0:1d1:0:0:0
+D:A standard spellbook with a few spells.
+
+# XXX
+
+N:741:& Book~ of Summoning
+G:?:w
+I:111:52:0
+W:7:0:30:700
+A:7/1
+P:0:1d1:0:0:0
+D:A standard spellbook with a few spells.
+D:It smells like camel.
+
+# XXX
+
+# The Potion of Learning - another artifact!
+
+N:743:& Potion~ of Learning
+G:!:d
+I:71:12:200
+W:90:0:4:100000
+A:90/25
+P:0:1d1:0:0:0
+T:71:49
+F:NORM_ART | FULL_NAME
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC
+D:This old potion is supposed to grant more learning power
+D:to its user.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+N:751:Khuzdul - The Hidden Tongue of the Dwarves
+G:?:s
+I:8:105:0
+W:2:100:5:50
+A:2/2
+D:These ancient words still contain magic.
+
+N:752:Nandorin for Dummies
+G:?:s
+I:8:106:0
+W:20:100:5:50
+A:20/2
+D:These ancient words still contain magic.
+
+N:753:Advanced Lessons of Orcish
+G:?:s
+I:8:107:0
+W:30:100:5:50
+A:30/2
+D:These ancient words still contain magic.
+
+# Here's the Ring of Flying
+N:755:Flying
+G:=:d
+I:45:54:0
+W:20:0:2:16000
+A:20/3
+F:FLY | EASY_KNOW
+f:FLY |
+D:This ring is imbued with the power of eagles. It grants you the power of flight.
+
+N:756:& Tome~ of the Time
+G:?:b
+I:111:8:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This tome seems to have trouble deciding whether it really exists now. Its flickering pages
+D:contain all that is known about the currents of time.
+
+N:757:& Spellbook~ of #
+G:?:w
+I:111:255:0
+W:10:0:30:200
+A:10/1:20/1:30/1:40/1:50/1:60/1:70/1
+P:0:1d1:0:0:0
+D:This book contains a single spell within its pages.
+
+N:758:& Tome~ of Meta Spells
+G:?:v
+I:111:9:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | IGNORE_FIRE | ATTR_MULTI
+D:This tome gives you deeper insights on the works of magic.
+
+N:759:& Tome~ of the Mind
+G:?:B
+I:111:10:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This tome has no pages; knowledge is transferred to you if you simply
+D:hold it.
+
+N:760:& Holy Tome~ of Eru Iluvatar
+G:?:G
+I:111:20:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This dusty tome is filled with ancient rituals,
+D:designed to uncover all that is hidden.
+
+N:761:& Holy Tome~ of Manwe Sulimo
+G:?:B
+I:111:21:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:A large jewel-encrusted tome that transfers
+D:wisdom and understanding to its wearer.
+
+N:762:& War Tome~ of Tulkas
+G:?:R
+I:111:22:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This tome fills you with glorious visions of total devastation.
+D:Anyone in your way shall be destroyed.
+
+N:763:& Unholy Tome~ of the Hellflame
+G:?:v
+I:111:11:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | ATTR_MULTI
+D:This singed book smells like burned flesh. Its power is as evident
+D:as its thirst for your blood.
+
+N:764:& Corrupted Tome~ of Melkor
+G:?:D
+I:111:23:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:A black and scarlet flame springs from this tome, issuing
+D:a thunderous roar under which you think you hear the screams of tormented souls.
+
+N:768:& Forest Tome~ of Yavanna
+G:?:G
+I:111:24:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+
+# for the Library Quest
+# Tome of PLAYER
+N:769:Tome of#
+G:?:v
+I:111:61:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | ATTR_MULTI | SPECIAL_GENE
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | NORM_ART
+D:This book has some of your favourite spells inside.
+
+# The Ring of Phasing -- see artifact list
+
+N:770:& Ring~
+G:=:d
+I:45:55:0
+W:110:0:2:300000
+A:110/5
+F:INSTA_ART | SPECIAL_GENE
+
+N:771:[Earth]
+G:?:R
+I:114:0:0
+W:10:0:30:100
+A:10/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE
+D:A heavy lump of rock. As you touch it, you think you can see into the earth and perceive its
+D:secrets.
+
+N:772:[Fire]
+G:?:R
+I:114:1:0
+W:20:0:30:1000
+A:20/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE
+D:A bright red crystal, filled with a liquid flame that scorches you even though the surface of
+D:the gem is cool to the touch.
+
+N:773:[Air]
+G:?:r
+I:114:2:0
+W:50:0:30:2500
+A:50/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:SPECIAL_GENE
+D:A completely translucent gem; as you behold it, you hear a great wind and feel like you're
+D:about to take off and fly away.
+
+N:774:[Water]
+G:?:r
+I:114:3:0
+W:70:0:30:50000
+A:70/3
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:SPECIAL_GENE
+D:A large gem, filled with dark blue water. It feels strangely heavy and cold.
+
+N:775:[Mana]
+G:?:r
+I:114:4:0
+W:100:0:30:100000
+A:100/3
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:SPECIAL_GENE
+D:A large gem that seems somehow immaterial and is filled with a strange insubstantial... power?
+
+# Rod Tip of Home Summoning: now an artifact
+#N:776:& Great Rod Tip~ of Home Summoning
+N:776:Home Summoning
+G:-:d
+I:66:30:75
+W:90:0:15:150000
+A:100/14
+P:0:1d1:0:0:0
+T:66:1
+F:NORM_ART | FULL_NAME
+F:IGNORE_FIRE | IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC
+D:This rod creates a little hatch, allowing access to your home, no matter how far away the abode
+D:is.
+
+# Additional swords
+N:777:& Shadow Blade~
+G:|:D
+I:23:32:1
+W:50:900:45:2000
+A:48/4:60/2:80/1
+P:0:4d4:-2:2:0
+F:IGNORE_ACID | RES_DARK | STEALTH
+f:STEALTH
+D:A thin long sword made of a completely black metal, which reflects no light.
+
+N:778:& Bluesteel Blade~
+G:|:b
+I:23:31:0
+W:60:1800:50:6000
+A:60/20
+P:0:1d6:4:0:0
+F:SHOW_MODS | VORPAL
+D:A small sword made of a blueish metal with a strangely rough surface. As anything is hurt
+D:with it, the weapon will stick inside the wound and cause horrible wounds when torn away.
+
+# Amulet
+N:779:the Serpents
+G:":G
+I:40:17:0
+W:25:0:3:10000
+A:25/1
+a:HARDCORE=BA_POIS_4
+F:RES_POIS | DEX | ACTIVATE
+D:A petrified serpent's tongue, hung on a thin chain to be clasped around your neck. It makes you
+D:like unto snakes, able to wriggle out of tight corners, impervious to poisons and poisonous
+D:yourself.
+
+# Here comes the new Essences
+
+N:780:Darkness
+G:*:G
+I:4:14:20
+W:0:0:4:1
+A:0/1:20/1:40/1
+P:0:1d1:0:0:0
+D:It's a gem that eats all light that reaches it. It's perfectly black.
+
+N:781:Knowledge
+G:*:G
+I:4:15:100
+W:0:0:4:1
+A:20/1:30/1:70/1
+P:0:1d1:0:0:0
+D:It's a blue gem with countless formulae scribbled on it.
+
+N:782:Force
+G:*:G
+I:4:16:180
+W:0:0:4:1
+A:10/1:40/1
+P:0:1d1:0:0:0
+D:It's a green gem that can barely contain the forces in it.
+
+N:783:Lightning
+G:*:G
+I:4:17:200
+W:0:0:4:1
+A:28/1
+P:0:1d1:0:0:0
+D:It's a white gem. Inside you see lightning rage.
+
+N:784:Mana
+G:*:G
+I:4:18:400
+W:0:0:4:1
+A:45/2
+P:0:1d1:0:0:0
+D:It's an everchanging gem. You feel the magic throbbing through it.
+
+# The Nine Rings for mortal men doomed to die! When a Nazgul is
+# destroyed, it drops a Ring of Power with random powers.
+
+N:785:Ring~ of Power
+G:=:d
+I:45:5:0
+W:100:0:2:1
+A:100/100
+F:INVIS | DRAIN_EXP | CURSED | HEAVY_CURSE | CURSE_NO_DROP
+f:INVIS
+F:SPECIAL_GENE | FULL_NAME
+
+# To help people climb mountains...
+
+N:786:& Climbing Set~
+G:`:B
+I:12:0:0
+W:40:0:2:50000
+A:40/3
+F:CLIMB
+f:CLIMB
+D:A bunch of screws and hooks, a small pick and a very long rope. As long as a wall or rock face
+D:isn't really high, this collection of tools should help you across it.
+
+# Parchment to help beginners
+N:787:Adventurer's Guide to Middle-earth
+G:?:o
+I:8:20:0
+W:0:0:5:1
+A:0/1
+D:Read it!
+
+### Demonblades ###
+
+N:788:& Demonblade~
+G:|:R
+I:115:55:0
+W:10:0:150:500
+A:10/1
+P:0:4d6:0:0:0
+F:SHOW_MODS | SLAY_DEMON | WIELD_CAST
+D:This blade has been taken from the corpse of a demon.
+D:Some demonic energy is still coursing through it, helping
+D:you slay other demons.
+
+N:789:& Demonshield~
+G:]:R
+I:115:56:0
+W:15:0:70:500
+A:15/1
+P:5:1d1:0:0:0
+F:REGEN | WIELD_CAST
+D:This shield has been taken from the corpse of a demon.
+D:Some demonic energy is still coursing through it, giving
+D:life to any that wield it.
+
+N:790:& Demonhorn~
+G:[:R
+I:115:57:0
+W:20:0:30:500
+A:20/1
+P:2:1d1:0:0:0
+F:LITE2 | WIELD_CAST
+D:This horn is about six feet long. Just looking at it makes you nervous.
+
+# XXX
+# XXX
+
+### Rods ###
+
+N:793:& Wooden Rod~ of#
+G:-:u
+I:67:10:0
+W:10:0:15:100
+A:5/1:10/1
+P:0:1d1:0:0:0
+D:The most common rod of all. It's the wood of oak, cut at midnight by a fair maiden.
+
+N:794:& Copper Rod~ of#
+G:-:s
+I:67:20:0
+W:15:0:15:200
+A:15/1
+P:0:1d1:0:0:0
+D:This is the common rod of the dwarves. It is created by chanting incessantly for 48 hours.
+
+N:795:& Iron Rod~ of#
+G:-:D
+I:67:50:0
+W:20:0:15:500
+A:20/1
+P:0:1d1:0:0:0
+D:This is the better version of the copper rod. It has been forged with iron that comes from
+D:the greatest deeps, where even the dwarves fear to go.
+
+# Aluminium only exists since 30 years
+N:796:& Moonstone Rod~ of#
+G:-:U
+I:67:75:0
+W:25:0:15:750
+A:25/1
+P:0:1d1:0:0:0
+D:This rod has been fashioned from moonrock. Its alien nature gives it quite a bit of capacity.
+
+N:797:& Silver Rod~ of#
+G:-:s
+I:67:100:0
+W:30:0:15:1000
+A:30/1
+P:0:1d1:0:0:0
+D:This rod is used often used by court mages. Its creation costs an insane amount
+D:of gold but it is still lesser than a Golden Rod.
+
+N:798:& Golden Rod~ of#
+G:-:y
+I:67:125:0
+W:40:0:15:1250
+A:40/2
+P:0:1d1:0:0:0
+D:These rods are rare, since finding gold that can withstand the great magic
+D:capacity that this rod holds is very difficult.
+
+N:799:& Mithril Rod~ of#
+G:-:B
+I:67:160:0
+W:50:0:15:1600
+A:50/5
+P:0:1d1:0:0:0
+D:The mithril of this rod comes from very deep, too deep. Unknown powers have been
+D:infused in this rod, making it the second most powerful type of rod on Middle-earth.
+
+N:800:& Adamantite Rod~ of#
+G:-:v
+I:67:200:0
+W:60:0:15:2000
+A:60/10
+P:0:1d1:0:0:0
+D:This is the rarest and most powerful kind of rod there is. Treasure it!
+
+# Greater Ration of Health - artifact food item (!)
+N:801:& Greater Ration~ of Health
+G:,:g
+I:80:41:0
+W:90:5:2:60000
+A:90/50
+T:80:40
+F:NORM_ART | FULL_NAME
+D:This food will, once eaten, permanently add 70 HP.
+
+# Scroll of Mass Resurrection - artifact scroll
+N:802:& Crumpled Scroll~ of Mass Resurrection
+G:?:d
+I:70:43:0
+W:55:0:5:0
+A:55/1
+T:70:1
+F:NORM_ART | FULL_NAME
+F:IGNORE_FIRE | IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC
+D:This magical scroll sends a call to the halls of Mandos, issuing forth all those who have been
+D:slain by the reader.
+
+### Axes ###
+
+N:803:& Cleaver~
+G:/:s
+I:24:2:0
+W:13:0:110:175
+A:13/1
+P:0:2d4:0:0:0
+F:SHOW_MODS
+D:A small axe with a heavy rectangular blade.
+
+N:804:& Light War Axe~
+G:/:s
+I:24:8:0
+W:16:0:140:300
+A:16/1
+P:0:2d5:0:0:0
+F:SHOW_MODS
+D:A broad-bladed axe, suited for battle.
+
+N:805:& Slaughter Axe~
+G:/:G
+I:24:30:0
+W:70:0:300:6000
+A:70/8
+P:0:5d7:0:0:0
+F:SLAY_ANIMAL | SHOW_MODS
+D:A huge axe, the sort used for slaughtering animals, this weapon is unusually deadly against
+D:natural creatures.
+
+N:806:& Runestone~
+G:?:v
+I:105:255:0
+W:10:5:2:300
+A:10/3:20/2:30/1:60/1
+P:0:1d1:0:0:0
+F:IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:A small oval stone. One surface is flat, as if something ought to be scratched or inscribed into
+D:it.
+
+N:807:& Fortune cookie~
+G:,:U
+I:80:42:500
+W:0:0:2:10
+A:0/1:5/1:10/1
+D:A small, sweet bakery product, with a scrap of paper inside.
+
+# XXX was the Portable Hole
+
+N:809:Critical Hits
+G:=:d
+I:45:59:0
+W:50:0:2:10000
+A:50/3
+F:CRIT
+f:CRIT
+D:A magical ring to make it likelier for the wearer to hit exceptionally heavily.
+
+# The Wand of Stone to Mud of Thrain
+N:810:& Wand~ of Digging of Thrain
+G:-:d
+I:65:26:-1:SPELL=Dig
+W:10:10:10:3200
+A:10/200
+P:0:10d10:0:0:0
+T:65:6
+F:RECHARGE | SPECIAL_GENE | EASY_USE | RECHARGED | NORM_ART | FULL_NAME
+D:The miner's friend. This wand was used by Thrain to dig into the
+D:walls of the dungeon. Its indestructible nature makes it quite useful.
+
+# The Staff of Holy Fire of Mithrandir
+N:811:& Gnarled Staff~ of Holy Fire of Mithrandir
+G:_:d
+I:55:22:-1:SPELL=Holy Fire of Mithrandir
+W:50:10:10:12000
+P:0:10d4:0:0:0
+A:50/200
+T:55:8
+F:RECHARGE | EASY_USE | RECHARGED | NORM_ART | FULL_NAME
+D:Mithrandir's staff that throws powerful fire attacks at all enemies. It
+D:can be recharged without blowing up, for it is built to hold
+D:much magical energy.
+
+### Summoner totems ###
+
+N:812:Partial Totem
+G:":v
+I:54:1:0
+W:10:10:10:120
+P:0:1d1:0:0:0
+A:10/200
+F:SPECIAL_GENE
+D:An item which a Summoner can use to animate a copy of a creature that
+D:only exists by the will of its master.
+
+N:813:True Totem
+G:":v
+I:54:2:0
+W:10:10:10:120
+P:0:1d1:0:0:0
+A:10/200
+F:SPECIAL_GENE
+D:An item which a Summoner can use to revive a true copy of a creature.
+
+### Holy relics for God Quests ###
+
+N:814:& Piece~ of the Relic of Eru
+G:~:v
+I:11:7:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to Priests of Eru. The relic now lies in pieces, hidden
+D:from all but but his most dedicated followers.
+
+N:815:& Piece~ of the Relic of Manwe
+G:~:v
+I:11:8:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to Priests of Manwe. The relic now lies in pieces, hidden
+D:from all but his most dedicated followers.
+
+N:816:& Piece~ of the Relic of Tulkas
+G:~:v
+I:11:9:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to worshippers of Tulkas. The relic now lies in pieces,
+D:hidden from all but his most dedicated followers.
+
+N:817:& Piece~ of the Relic of Melkor
+G:~:v
+I:11:10:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to Dark Priests. The relic now lies in pieces, hidden
+D:from all but the most faithful followers of Melkor.
+
+N:818:& Piece~ of the Relic of Yavanna
+G:~:v
+I:11:11:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to Druids. The relic now lies in pieces, hidden
+D:from all but the most faithful followers of Yavanna.
diff --git a/lib/edit/library.map b/lib/edit/library.map
new file mode 100644
index 00000000..2369fbd6
--- /dev/null
+++ b/lib/edit/library.map
@@ -0,0 +1,62 @@
+# Permanent wall
+F:X:63:3
+
+# Granite Wall
+F:#:57:3
+
+# Cobblestone Road
+F:O:200:3
+
+# Floor
+F:.:1:3
+
+# Lich
+F:l:200:3:518
+
+# Master lich
+F:L:200:3:658
+
+# Quest exit
+F:<:6:3
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X###############################################################X
+D:X#<OlOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOL#X
+D:X###############################################################X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:4:4
diff --git a/lib/edit/maeglin.map b/lib/edit/maeglin.map
new file mode 100644
index 00000000..e3be9972
--- /dev/null
+++ b/lib/edit/maeglin.map
@@ -0,0 +1,85 @@
+# Created by Mynstral (mynstral@thehelm.com)
+# Made for PernAngband on 26/07/2001
+
+# Monsters starts awake
+N:0
+
+# Permanent wall
+F:X:63:3
+
+# Marker
+F:<:172:3
+
+# up stairs with maeglin
+F:{:6:3:825:0:0:0:0:0:0:2
+
+# Floor with dirt
+F:.:88:5
+
+# Floor with dirt with an Ettin
+F:e:88:5:621
+
+# Floor with dirt with a War Troll
+F:w:88:5:631
+
+# Floor with dirt with a Troll Chieftan
+F:t:88:5:799
+
+# Floor with dirt with a Snagga sapper
+F:s:88:5:251
+
+# Floor with dirt with an Orc Captain
+F:o:88:5:285
+
+# Floor with dirt with an Elite Uruk
+F:u:88:5:866
+
+# Floor with dirt with an Ancient blue dragon
+F:L:88:5:601
+
+# Floor with dirt with an Ancient bronze dragon
+F:Z:88:5:602
+
+# Floor with dirt with an Ancient white dragon
+F:W:88:5:617
+
+# Floor with dirt with an Ancient green dragon
+F:G:88:5:618
+
+# Floor with dirt with an Ancient black dragon
+F:B:88:5:624
+
+# Floor with dirt with an Ancient red dragon
+F:R:88:5:644
+
+# Floor with dirt with an Ancient gold dragon
+F:O:88:5:645
+
+# Floor with dirt with a Lesser Balrog
+F:U:88:5:996:0:0:0:0:0:0:2
+
+# Granite wall
+F:#:56:5
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X##..#########...#........###..R.....###.e...{X
+D:X#.wt.######..O....#s..#..##w.#..###.....#.t..X
+D:X#wBLe.####.U.###....##.U.#...##..u####.#####.X
+D:X#eRe.####..#..######.B...w...#.U#uuu##.#U...eX
+D:X##...#...G###s...##....##..####..##uu#B..##..X
+D:X####...e...#####.t...####...####.###u#####.w#X
+D:X###....##.w.######.e.#..##...###..##uu#e...##X
+D:X##..W#####...###.....#...##.e####.L##...#####X
+D:X##...######e.##Z..w.###.......####.###t.#####X
+D:X....########s....#s...##R..#.U.##..####..####X
+D:Xs..####....##.tU####...#####t...#.######..###X
+D:X#...##..##..#..######.t..e..##.w...#####w.###X
+D:X##.....####s..######.e.#.#t...#.#U.####..####X
+D:X#...####uu##.t..#####...e####s#........w.####X
+D:X...####uou...##...#####.....###..#####...####X
+D:X..#####uu##...###s.##........##..#####..#####X
+D:X.o.#######...e.###.....o.###s.##..###s...#..#X
+D:X#s..o#......#s.......u...####..#s.##...o.G...X
+D:Xsss##o....u###....u..o.o.#####........###.OZ.X
+D:X<ss...###############...##################U.#X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
diff --git a/lib/edit/misc.txt b/lib/edit/misc.txt
new file mode 100644
index 00000000..08e35c1f
--- /dev/null
+++ b/lib/edit/misc.txt
@@ -0,0 +1,91 @@
+# File: misc.txt
+
+# Maximum number of towns
+M:T:100
+
+# Maximum number of non random towns(must be < 20)
+M:t:5
+
+# Maximum x size of the wilderness
+M:X:101
+
+# Maximum y size of the wilderness
+M:Y:66
+
+# Maximum number of randart parts in ra_info.txt
+M:Z:516
+
+# Maximum number of monsters in r_info.txt
+# WARNING ! add one more to the real count for the player ghost !!
+M:R:1078
+
+# Maximum number of monsters in re_info.txt
+# WARNING ! Use the exact amount of ego types used, if not you
+# will get weird results !
+M:r:14
+
+# Maximum number of items in k_info.txt
+M:K:819
+
+# Maximum number of vaults in v_info.txt
+M:V:108
+
+# Maximum number of terrain features in f_info.txt
+M:F:256
+
+# Maximum number of alchemist recipes
+M:a:1000
+
+# Maximum number of artifacts in a_info.txt
+M:A:219
+
+# Maximum number of sets types in set_info.txt
+M:s:10
+
+# Maximum number of ego-items in e_info.txt
+M:E:200
+
+# Maximum number of dungeon types in d_info.txt
+M:D:31
+
+# Maximum number of trap types in tr_info.txt
+M:U:176
+
+# Maximum number of terrain types in wf_info.txt
+M:W:30
+
+# Maximum number of owners types in ow_info.txt
+M:N:70
+
+# Maximum number of building actions in ba_info.txt
+M:B:62
+
+# Maximum number of store types in st_info.txt
+M:S:61
+
+# Maximum size for "o_list[]"
+M:O:1024
+
+# Maximum size for "m_list[]"
+M:M:768
+
+# Maximum number of race types in p_info.txt
+M:P:R:22
+
+# Maximum number of subrace types in p_info.txt
+M:P:S:10
+
+# Maximum number of class types in p_info.txt
+M:P:C:32
+
+# Maximum number of meta class types in p_info.txt
+M:P:M:1
+
+# Maximum number of histories types in p_info.txt
+M:P:H:266
+
+# Maximum number of skills in s_info.txt
+M:k:60
+
+# Maximum number of traits in ab_info.txt
+M:b:50
diff --git a/lib/edit/nirnaeth.map b/lib/edit/nirnaeth.map
new file mode 100644
index 00000000..a8c06999
--- /dev/null
+++ b/lib/edit/nirnaeth.map
@@ -0,0 +1,64 @@
+# Permanent wall
+F:X:63:3
+
+# up stairs
+F:<:6:3
+
+# Floor with dirt
+F:.:1:5
+
+# Dirt (no-tele)
+F:s:88:5
+
+# Shallow water
+F:V:84:5
+
+# Dirt with Olog
+F:a:88:5:538:0:0:0:0:0:0:2
+
+# Dirt with Cave Troll
+F:b:88:5:496:0:0:0:0:0:0:2
+
+# Dirt with with Eldrak
+F:c:88:1:620:0:0:0:0:0:0:2
+
+# Dirt with with Ettin
+F:e:88:1:621:0:0:0:0:0:0:2
+
+# Dirt with with War troll
+F:f:88:1:631:0:0:0:0:0:0:2
+
+# Dirt with with Hru
+F:g:88:1:709:0:0:0:0:0:0:2
+
+# Dirt with Ulik the Troll
+F:h:88:5:729:0:0:0:0:0:0:2
+
+# Dirt with Ancient green dragon
+F:i:88:5:618:0:0:0:0:0:0:2
+
+# Dungeon
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X...a.bab....f.....f.XXXXXXXXXXX
+D:X..ab...b..ff..aa..b..XXXXXXXXXX
+D:X.aa..b..fff...a..g.f.b.XXXXXXXX
+D:Xab.....b....f.......f..bf..XXXX
+D:X..b.f......ff.f..aa...f..b.XXXX
+D:X...ff..f..ff.c.a..f.g.a..fXXXXX
+D:Xb.f....fff.ff...aaa....f..XXXXX
+D:X...ff...ff...f......aa..a..XXXX
+D:Xb.ff.a...f...bbb..a..aa.....XXX
+D:X.f.a...a....bbebb......f.fa.XXX
+D:X.....a.....bbecebb..g.a.a....XX
+D:X.a.a....aa.beccceb....f.a..c.XX
+D:X......a..f.bbecebba.f....ea...X
+D:XX.b.aa.f..f.bbebb...a.aa...g.aX
+D:XX..bb...a..f.bbb..a..a..aae..iX
+D:XXX....aa.aa.f...aa...e..b..h..X
+D:XXXXXX........bb...g....aa...gcX
+D:XXXXXXXX.g..aa...a...a.e...ac.<X
+D:XXXXXXXX........bb....e.c.i.e.iX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:3
diff --git a/lib/edit/numenor.txt b/lib/edit/numenor.txt
new file mode 100644
index 00000000..ec8621b1
--- /dev/null
+++ b/lib/edit/numenor.txt
@@ -0,0 +1,80 @@
+# File: numenor.txt
+
+# Way to the lost land of Numenor
+F:>:7:3:0:0:0:0:0:7
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW>VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:######################################################################################################################################################################################################
+
+
+############### Starting positions ###############
+
+# Standard starting position for normal races
+?:[EQU $LEAVING_QUEST 0]
+P:46:128
diff --git a/lib/edit/ow_info.txt b/lib/edit/ow_info.txt
new file mode 100644
index 00000000..a1e3d0a3
--- /dev/null
+++ b/lib/edit/ow_info.txt
@@ -0,0 +1,447 @@
+# File: ow_info.txt
+
+
+# This file is used to initialize the "lib/raw/ow_info.raw" file, which is
+# used to initialize the "owner info type" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# N:<index>:<name>
+# I:<max_cost>:<max_inflate>:<min_inflate>:<haggle_per>:<insult_max>
+# C:<hated cost>:<normal cost>:<liked cost>
+# L:liked races
+# H:hated races
+
+# Version stamp (required)
+
+V:2.0.0
+
+N:0:Bilbo the Friendly(Hobbit)
+I:20000:170:108:5:15
+C:120:100:80
+L:Elf | Half-Elf | High-Elf | Dunadan | Hobbit | Dwarf | RohanKnight
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold
+
+N:1:Uldrik(Human)
+I:20000:170:108:1:1
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:2:Otick(Human)
+I:100:170:108:4:10
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:3:Merana(Human)
+I:0:170:108:1:1
+C:200:100:95
+L:Human
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:4:Mirimbar(High-Elf)
+I:0:170:108:1:1
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:5:Raistlin the Chicken(Human)
+I:20000:175:108:4:12
+C:120:100:80
+L:Human
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:6:Sultan the Midget(Gnome)
+I:30000:170:107:5:15
+C:120:100:80
+L:Gnome | Dwarf | Petty-Dwarf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:7:Lyar-el the Comely(Elf)
+I:30000:165:107:6:18
+C:120:100:80
+L:Elf | Half-Elf | Dark-Elf | High-Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:8:Kon-Dar the Ugly(Half-Orc)
+I:5000:210:115:5:7
+C:120:100:80
+L:Orc | Troll | Half-Ogre | Beorning | Kobold
+H:Gnome | Dwarf | Human | RohanKnight | Elf | Half-Elf | High-Elf
+
+N:9:Darg-Low the Grim(Human)
+I:10000:190:111:4:9
+C:120:100:80
+L:Human
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:10:Decado the Handsome(Dunadan)
+I:25000:200:112:4:10
+C:120:100:80
+L:Human | Dunadan | RohanKnight
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:11:Wieland the Smith(Dwarf)
+I:30000:200:112:4:5
+C:120:100:80
+L:Gnome | Dwarf | Petty-Dwarf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:12:Arnold the Beastly(Barbarian)
+I:5000:210:115:6:6
+C:120:100:80
+
+N:13:Arndal Beast-Slayer(Half-Elf)
+I:10000:185:110:5:9
+C:120:100:80
+L:Elf | Half-Elf | Dark-Elf | High-Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:14:Eddie Beast-Master(Half-Orc)
+I:25000:190:115:5:7
+C:120:100:80
+L:Orc | Troll | Half-Ogre | Beorning | Kobold
+H:Gnome | Dwarf | Human | RohanKnight | Elf | Half-Elf | High-Elf
+
+N:15:Oglign Dragon-Slayer(Dwarf)
+I:30000:195:112:4:8
+C:120:100:80
+L:Gnome | Dwarf | Petty-Dwarf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:16:Aragorn(Dunadan)
+I:20000:200:112:4:10
+C:120:100:80
+L:Human | Dunadan | RohanKnight
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:17:Sondar(Human)
+I:0:200:112:4:10
+C:120:100:80
+
+N:18:Celebor(Half-Elf)
+I:100:170:108:4:10
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:19:Sharra(Human)
+I:25000:200:112:4:10
+C:120:100:80
+L:Human | Dunadan | RohanKnight
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:20:Hjolgar(Barbarian)
+I:5000:210:115:6:6
+C:120:100:80
+#L:Warrior |
+
+N:21:Tanistil(Elf)
+I:5000:210:115:6:6
+C:120:100:80
+#L:Mage | Sorceror | Thaumaturgist
+#H:Warrior |
+
+N:22:Eldore(Human)
+I:5000:210:115:6:6
+C:120:100:80
+#L:Priest
+#H:Necromancer
+
+N:23:Vilios(Human)
+I:5000:210:115:6:6
+C:120:100:80
+#L:Paladin
+#H:Necromancer
+
+N:24:Angros(Elf)
+I:5000:210:115:6:6
+C:120:100:80
+#L:Ranger
+
+N:25:Palano(Thunderlord)
+I:0:210:115:6:6
+C:120:100:80
+L:Thunderlord
+
+N:26:Ludwig the Humble(Dwarf)
+I:5000:175:109:6:15
+C:120:100:80
+L:Gnome | Dwarf | Petty-Dwarf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:27:Gunnar the Paladin(Half-Troll)
+I:10000:185:110:5:23
+C:120:100:80
+L:Orc | Troll | Half-Ogre | Beorning | Kobold
+H:Gnome | Dwarf | Human | RohanKnight | Elf | Half-Elf | High-Elf
+
+N:28:Torin the Chosen(High-Elf)
+I:25000:180:107:6:20
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:29:Sarastro the Wise(Human)
+I:30000:185:109:5:15
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:30:Mauser the Chemist(Half-Elf)
+I:10000:190:111:5:8
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:31:Wizzle the Chaotic(Hobbit)
+I:10000:190:110:6:8
+C:120:100:80
+L:Elf | Half-Elf | High-Elf | Dunadan | Hobbit | Dwarf | RohanKnight
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:32:Midas the Greedy(Gnome)
+I:15000:200:116:6:9
+C:120:100:80
+L:Gnome | Dwarf | Petty-Dwarf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:33:Ja-Far the Alchemist(Elf)
+I:15000:220:111:4:9
+C:120:100:80
+L:Elf | Half-Elf | Dark-Elf | High-Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:34:Ariel the Sorceress(Half-Elf)
+I:20000:200:110:7:8
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:35:Buggerby the Great(Gnome)
+I:20000:215:113:6:10
+C:120:100:80
+L:Gnome | Dwarf | Petty-Dwarf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:36:Inglorian the Mage(Human)
+I:30000:200:110:7:10
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:37:Luthien Starshine(High-Elf)
+I:30000:175:110:5:11
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:38:Gary Gygaz(Half-Troll)
+I:20000:250:150:10:5
+C:120:100:80
+#L:Rogue
+H:Gnome | Dwarf | Human | RohanKnight | Elf | Half-Elf | High-Elf
+
+N:39:Histor the Goblin(Half-Orc)
+I:20000:250:150:10:5
+C:120:100:80
+#L:Rogue
+H:Gnome | Dwarf | Human | RohanKnight | Elf | Half-Elf | High-Elf
+
+N:40:Zorak the Smart(Dwarf)
+I:30000:250:150:10:5
+C:120:100:80
+#L:Rogue
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:41:Tipo the Fair(Human)
+I:30000:250:150:10:5
+C:120:100:80
+#L:Rogue
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:42:Dolaf the Greedy(Human)
+I:10000:175:108:4:12
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
+
+
+N:43:Odnar the Sage(High-Elf)
+I:15000:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:44:Gandar the Neutral(Dark-Elf)
+I:25000:120:110:7:19
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold
+
+N:45:Ro-sha the Patient(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+L:Elf | Half-Elf | Dark-Elf | High-Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:46:N'rak the Summoner(Human)
+I:10000:175:108:4:12
+C:120:100:80
+L:Human | Dunadan | RohanKnight
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:47:Esperion the Beastlover(High-Elf)
+I:15000:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:48:Flarim the Shopkeeper(Dunadan)
+I:25000:120:110:7:19
+C:120:100:80
+L:Human | Dunadan | RohanKnight
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:49:Tril-akheb the Supreme(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+L:Elf | Half-Elf | Dark-Elf | High-Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:50:Dorchel(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+L:Elf | Half-Elf | Dark-Elf | High-Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:51:Galadriel(High-Elf)
+I:15000:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:52:Celeborn(High-Elf)
+I:15000:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:53:Aulendil(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+#L:Warrior |
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:54:Valceronwe(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+#L:Mage | Thaumaturgist | Sorceror
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:55:Voronwe(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+#L:Priest | Paladin
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:56:Celegail(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+#L:Ranger
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:57:Turgon(High-Elf)
+I:30000:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:58:Pengolodh(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:59:Aerandir(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:60:Celebrimbor(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+#L:Warrior |
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:61:Lomelosse(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf |
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:62:Arlindel(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+#L:Harper | Ranger
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:63:Sulraen(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+#L:Mage | Sorceror
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:64:Firiel(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf |
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:65:Earendur(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:66:Glorfindel(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf
+#L:Ranger
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:67:Ecthelion(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf
+#L:Paladin
+H:Orc | Troll | Half-Ogre | Beorning | Kobold |
+
+N:68:Kanris(Human)
+I:5000:210:115:6:6
+C:120:100:80
+#L:Merchant
+#H:Rogue
+
+N:69:Barliman Butterbur(Human)
+I:100:170:108:4:10
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Orc | Troll | DeathMold | Half-Ogre | Beorning | Kobold |
diff --git a/lib/edit/p_info.txt b/lib/edit/p_info.txt
new file mode 100644
index 00000000..1531f4fd
--- /dev/null
+++ b/lib/edit/p_info.txt
@@ -0,0 +1,1974 @@
+# File: p_info.txt
+
+
+# This file is used to initialize the "lib/raw/p_info.raw" file, which is
+# used to initialize the "player race/race mod/class" information for the
+# Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+V:2.0.0
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# General skills, that everybody starts with
+# G:k:value:modifier:skill name
+G:k:+0:+500:Monster-lore
+G:k:+1000:+0:Spell-learning
+G:k:+0:+500:Prayer
+G:k:+0:+400:Udun
+G:k:+1000:+1000:Magic-Device
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# C:N:index:name
+# C:D:0:class desc
+# C:D:1:titles
+# C:S:str:int:wis:dex:con:chr:mana:bonus blows
+# C:K:dis:dev:sav:stl:srh:fos:thn:thb
+# C:X:dis:dev:sav:stl:srh:fos:thn:thb
+# C:P:hitdie:xp%
+# C:B:num:wgt:mul
+# C:C:(H|L):(H|L):base:pl:plus
+# first (H|L) is for weapons/.. second is for magic things
+# H = heavy sensing, L = light sensing; result(lower = better) = base / (pl * plev + plus)
+# C:G:class flags
+# C:R:level:pval
+# C:F:flags
+# C:Z:power
+# C:E:weapons:torso:arms:finger:head:legs
+# C:O:tval:sval:xdy
+# C:k:value:modifier:skill name
+# C:b:level:ability
+
+# Specialities, autoskiller
+# C:a:N:Name
+# C:a:D:Desc
+# C:a:K:lvl 50 skill value:skill name
+# C:a:k:value:mod:skill name
+# C:a:b:level:ability
+# C:a:O:tval:sval:xdy
+
+C:N:0:Warrior
+C:D:0:Simple fighters, they hack away with their trusty weapon.
+C:D:1:Rookie
+C:D:1:Soldier
+C:D:1:Mercenary
+C:D:1:Veteran
+C:D:1:Swordsman
+C:D:1:Champion
+C:D:1:Hero
+C:D:1:Baron
+C:D:1:Duke
+C:D:1:Lord
+C:S:5:-2:-2:2:2:-1:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:30:5
+C:C:H:L:9000:2:40
+C:P:9:0
+C:R:30:0
+C:F:RES_FEAR
+C:E:0:0:0:0:0:0
+C:O:45:38:1d1
+C:O:37:4:1d1
+C:k:+2000:+800:Combat
+C:k:+1000:+850:Weaponmastery
+C:k:+0:+400:Sword-mastery
+C:k:+0:+400:Axe-mastery
+C:k:+0:+400:Hafted-mastery
+C:k:+0:+400:Polearm-mastery
+C:k:+1000:+600:Archery
+C:k:+1000:+900:Sneakiness
+C:k:+0000:+400:Stealth
+C:k:+1000:+900:Disarming
+C:k:+1000:+300:Magic
+C:k:+1000:+400:Spirituality
+C:k:+0:+550:Antimagic
+C:k:+0:+150:Magic-Device
+C:b:25:Spread blows
+C:b:1:Extra Max Blow(1)
+C:b:1:Extra Max Blow(2)
+
+# Specialities, autoskiller
+C:a:N:Warrior
+C:a:D:Simple fighters, they hack away with their trusty weapon.
+C:a:O:23:16:1d1
+C:a:g:All Gods
+
+C:a:N:Swordmaster
+C:a:D:Fighters specialised in the use of swords
+C:a:k:+1000:+300:Sword-mastery
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+0:-100:Axe-mastery
+C:a:k:+0:-100:Hafted-mastery
+C:a:k:+0:-100:Polearm-mastery
+C:a:O:23:16:1d1
+C:a:g:Nobody
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Melkor Bauglir
+C:a:g:Yavanna Kementari
+
+C:a:N:Axemaster
+C:a:D:Fighters specialised in the use of axes
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+1000:+300:Axe-mastery
+C:a:k:+0:-100:Sword-mastery
+C:a:k:+0:-100:Hafted-mastery
+C:a:k:+0:-100:Polearm-mastery
+C:a:O:24:1:1d1
+C:a:g:Nobody
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Melkor Bauglir
+C:a:g:Yavanna Kementari
+
+C:a:N:Haftedmaster
+C:a:D:Fighters specialised in the use of hafted weapons
+C:a:k:+1000:+300:Hafted-mastery
+C:a:k:+0:+500:Stunning-blows
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+0:-100:Axe-mastery
+C:a:k:+0:-100:Sword-mastery
+C:a:k:+0:-100:Polearm-mastery
+C:a:O:21:13:1d1
+C:a:g:All Gods
+
+C:a:N:Polearmmaster
+C:a:D:Fighters specialised in the use of polearms
+C:a:k:+1000:+300:Polearm-mastery
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+0:-100:Axe-mastery
+C:a:k:+0:-100:Hafted-mastery
+C:a:k:+0:-100:Sword-mastery
+C:a:O:22:8:1d1
+C:a:g:All Gods
+
+C:a:N:Unbeliever
+C:a:D:They don't believe in magic and can even prevent its usage around them
+C:a:k:=0:=0:Prayer
+C:a:k:=0:=0:Magic
+C:a:k:=0:=0:Magic-Device
+C:a:k:=0:=0:Spirituality
+C:a:k:+1000:+100:Antimagic
+C:a:O:23:33:1d1
+C:a:g:Nobody
+
+C:a:N:Demonologist
+C:a:D:Masters of the school of demonology, they are trained in both melee
+C:a:D:fighting and using demon spells to enhance their combat potential.
+C:a:O:115:55:1d1
+C:a:k:+0:-50:Combat
+C:a:k:+0:-100:Weaponmastery
+C:a:k:+0:+200:Sword-mastery
+C:a:k:=0:=0:Axe-mastery
+C:a:k:=0:=0:Hafted-mastery
+C:a:k:=0:=0:Polearm-mastery
+C:a:k:+1000:-200:Archery
+C:a:k:+1000:+900:Sneakiness
+C:a:k:+1000:+900:Disarming
+C:a:k:+1000:+400:Magic
+C:a:k:+1000:+300:Spirituality
+C:a:k:=0:=0:Antimagic
+C:a:k:+1000:+1000:Demonology
+C:a:g:Nobody
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Melkor Bauglir
+
+C:N:1:Mage
+C:D:0:The basic spellcaster with lots of different skills
+C:D:1:Apprentice
+C:D:1:Trickster
+C:D:1:Illusionist
+C:D:1:Spellbinder
+C:D:1:Evoker
+C:D:1:Conjurer
+C:D:1:Warlock
+C:D:1:Sorcerer
+C:D:1:Ipsissimus
+C:D:1:Archimage
+C:S:-5:3:0:1:-2:1:50:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:40:2
+C:C:L:H:240000:1:5
+C:P:0:30
+C:E:0:0:0:0:0:0
+C:k:+1000:+900:Magic
+C:k:+0:+200:Magic-Device
+C:k:+0:+600:Spell-power
+C:k:+1000:+600:Mana
+C:k:+0:+700:Fire
+C:k:+0:+700:Water
+C:k:+0:+700:Air
+C:k:+0:+700:Earth
+C:k:+0:+700:Temporal
+C:k:+0:+700:Divination
+C:k:+0:+700:Conveyance
+C:k:+0:+700:Nature
+C:k:+0:+700:Meta
+C:k:+0:+700:Mind
+C:k:+0:+700:Necromancy
+C:k:+0:+700:Runecraft
+C:k:+0:+700:Thaumaturgy
+C:k:+1000:+550:Spirituality
+C:k:+1000:+200:Combat
+C:k:+700:+500:Weaponmastery
+C:k:+1000:+900:Sneakiness
+C:k:+0000:+400:Stealth
+C:b:1:Perfect casting
+C:g:All Gods
+
+C:a:N:Mage
+C:a:D:The basic unspecialized warrior-spellcaster
+C:a:k:+0:+300:Combat
+C:a:k:+0:+200:Sorcery
+C:a:k:+0:+300:Mana
+C:a:k:+0:+200:Fire
+C:a:k:+0:+200:Water
+C:a:k:+0:+200:Air
+C:a:k:+0:+200:Earth
+C:a:k:+0:+200:Conveyance
+C:a:k:+0:+200:Nature
+C:a:k:+0:+200:Temporal
+C:a:k:+0:+200:Divination
+C:a:k:+0:+200:Meta
+C:a:k:+0:+200:Mind
+C:a:O:23:4:1d1
+C:a:O:111:50:1d1
+
+C:a:N:Geomancer
+C:a:D:The master of the four elements
+C:a:k:+0:-150:Magic-Device
+C:a:k:+1000:+100:Spell-power
+C:a:k:-1000:-600:Mana
+C:a:k:+1000:+700:Geomancy
+C:a:k:+1000:+350:Fire
+C:a:k:+1000:+350:Water
+C:a:k:+1000:+350:Air
+C:a:k:+1000:+350:Earth
+C:a:k:+0:-100:Weaponmastery
+C:a:O:6:1:1d1
+
+C:a:N:Warper
+C:a:D:The master of space and time
+C:a:k:+0:-150:Magic-Device
+C:a:k:+1000:+100:Spell-power
+C:a:k:+0:+100:Mana
+C:a:k:+0:+100:Fire
+C:a:k:+0:+100:Water
+C:a:k:+0:+100:Air
+C:a:k:+0:+100:Earth
+C:a:k:+0:+500:Conveyance
+C:a:k:+0:+100:Nature
+C:a:k:+0:+500:Temporal
+C:a:k:+0:+500:Divination
+C:a:k:+0:+100:Meta
+C:a:k:+0:-100:Weaponmastery
+C:a:O:23:4:1d1
+C:a:O:111:50:1d1
+
+C:a:N:Sorceror
+C:a:D:The master of all magic schools
+C:a:k:+0:-200:Magic-Device
+C:a:k:=0:=0:Weaponmastery
+C:a:k:=0:=0:Combat
+C:a:k:+1000:+700:Sorcery
+C:a:k:+0:+100:Magic
+C:a:k:-1000:+300:Mana
+C:a:k:+0:+300:Fire
+C:a:k:+0:+300:Water
+C:a:k:+0:+300:Air
+C:a:k:+0:+300:Earth
+C:a:k:+0:+300:Conveyance
+C:a:k:+0:+300:Nature
+C:a:k:+0:+300:Temporal
+C:a:k:+0:+300:Divination
+C:a:k:+0:+300:Meta
+C:a:k:+0:+300:Mind
+C:a:k:+0:+200:Necromancy
+C:a:k:+0:+200:Runecraft
+C:a:k:+0:+200:Thaumaturgy
+C:a:O:36:2:1d1
+C:a:O:111:50:1d1
+
+C:a:N:Necromancer
+C:a:D:The master of death, and undeath
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+200:Combat
+C:a:k:+1000:+300:Necromancy
+C:a:k:-1000:+0:Mana
+C:a:k:+0:+100:Fire
+C:a:k:+0:+100:Earth
+C:a:k:+0:-200:Nature
+C:a:k:+0:+100:Temporal
+C:a:k:+0:+200:Mind
+C:a:k:+1000:+600:Monster-lore
+C:a:k:+5000:+900:Corpse-preservation
+C:a:O:23:4:1d1
+C:a:O:111:50:1d1
+C:a:b:25:Undead Form
+
+C:a:N:Runecrafter
+C:a:D:Runecrafters use the runes found in Middle-earth to create
+C:a:D:finely tuned spells for each specific situation.
+C:a:k:+1000:+50:Magic
+C:a:k:+1000:+300:Runecraft
+C:a:k:+0:-100:Weaponmastery
+C:a:O:111:50:1d1
+C:a:O:105:1:1d1
+C:a:O:104:5:1d1
+C:a:O:23:4:1d1
+
+C:a:N:Thaumaturgist
+C:a:D:Thaumaturgy spells come from within and are different for each character.
+C:a:D:Since attack is the best defence, all their spells are offensive.
+C:a:k:-1000:+0:Mana
+C:a:k:+2000:+50:Magic
+C:a:k:+1000:+300:Thaumaturgy
+C:a:k:+0:-100:Weaponmastery
+C:a:k:+0:-150:Magic-Device
+C:a:O:23:4:1d1
+C:a:O:111:50:1d1
+
+C:a:N:Alchemist
+C:a:D:Alchemists can quickly create powerful magic items through the correct use
+C:a:D:of the essences of magic they can extract from magical objects.
+C:a:k:+2000:+0:Magic
+C:a:k:+0:-600:Spell-power
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:-600:Thaumaturgy
+C:a:k:+0:+250:Spirituality
+C:a:k:+0:+500:Combat
+C:a:k:+0:+200:Weaponmastery
+C:a:k:-1000:-600:Mana
+C:a:k:+0:-600:Fire
+C:a:k:+0:-600:Water
+C:a:k:+0:-600:Air
+C:a:k:+0:-600:Earth
+C:a:k:+0:-600:Conveyance
+C:a:k:+0:-600:Nature
+C:a:k:+0:-600:Temporal
+C:a:k:+0:-200:Divination
+C:a:k:+0:-200:Meta
+C:a:k:+0:-600:Mind
+C:a:k:+1000:+800:Alchemy
+C:a:k:+0:+50:Magic-Device
+C:a:O:31:1:1d1
+C:a:O:4:2:6d1
+C:a:O:2:1:1d1
+C:a:O:23:4:1d1
+C:a:G:EXPERIMENTAL
+
+C:N:2:Archer
+C:D:0:'Kill them before they see you' could be the motto of the archer class.
+C:D:0:As deadly with a bow as a warrior is with a sword.
+C:D:1:Rock Thrower
+C:D:1:Slinger
+C:D:1:Great Slinger
+C:D:1:Tosser
+C:D:1:Bowman
+C:D:1:Great Bowman
+C:D:1:Great Bowman
+C:D:1:Archer
+C:D:1:Archer
+C:D:1:Great Archer
+C:S:2:1:0:2:1:1:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:35:4
+C:C:H:L:9000:2:40
+C:P:4:30
+C:E:0:0:0:0:0:0
+C:k:+1000:+800:Combat
+C:k:+1000:+500:Weaponmastery
+C:k:+1000:+750:Archery
+C:k:+0:+300:Bow-mastery
+C:k:+0:+300:Crossbow-mastery
+C:k:+0:+300:Sling-mastery
+C:k:+0:+300:Boomerang-mastery
+C:k:+0:%150:Boulder-throwing
+C:k:+1000:+900:Sneakiness
+C:k:+0000:+400:Stealth
+C:k:+1000:+900:Disarming
+C:k:+1000:+300:Magic
+C:k:+0:+100:Magic-Device
+C:k:+1000:+400:Spirituality
+C:b:2:Ammo creation
+
+C:a:N:Archer
+C:a:D:'Kill them before they see you' could be the motto of the archer class.
+C:a:D:As deadly with a bow as a warrior is with a sword.
+C:a:k:+0:+100:Archery
+C:a:k:+0:+200:Bow-mastery
+C:a:k:+0:+200:Crossbow-mastery
+C:a:k:+0:+200:Sling-mastery
+C:a:k:+0:+200:Boomerang-mastery
+C:a:k:-1000:-100:Magic
+C:a:O:19:12:1d1
+C:a:O:19:2:1d1
+C:a:O:17:1:10d3
+C:a:O:17:1:10d3
+C:a:g:All Gods
+
+C:a:N:Ranger
+C:a:D:Rangers are capable archers but are also trained in hand to hand combat
+C:a:D:and nature/conveyance/divination magic schools
+C:a:k:+0:+400:Magic
+C:a:k:+0:+500:Nature
+C:a:k:+0:+500:Divination
+C:a:k:+0:+500:Conveyance
+C:a:k:+0:+700:Disarming
+C:a:k:+0:+50:Sneakiness
+C:a:k:+0:+200:Monster-lore
+C:a:O:19:12:1d1
+C:a:O:17:1:10d3
+C:a:O:23:10:1d1
+C:a:g:Nobody
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Yavanna Kementari
+
+C:N:3:Rogue
+C:D:0:Rogues are masters of tricks. They can steal from shops and monsters,
+C:D:0:and lure monsters into deadly monster traps.
+C:D:1:Cutpurse
+C:D:1:Robber
+C:D:1:Burglar
+C:D:1:Filcher
+C:D:1:Sharper
+C:D:1:Low Thief
+C:D:1:High Thief
+C:D:1:Master Thief
+C:D:1:Assassin
+C:D:1:Guildmaster
+C:S:2:1:-2:3:1:-1:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:30:3
+C:C:H:H:20000:2:40
+C:P:6:25
+C:O:23:4:1d1
+C:G:EASE_STEAL
+C:R:3:1
+C:F:CRIT
+C:R:6:1
+C:F:CRIT
+C:R:9:1
+C:F:CRIT
+C:R:12:1
+C:F:CRIT
+C:R:15:1
+C:F:CRIT
+C:R:18:1
+C:F:CRIT
+C:R:21:1
+C:F:CRIT
+C:R:24:1
+C:F:CRIT
+C:R:27:1
+C:F:CRIT
+C:R:30:1
+C:F:CRIT
+C:R:33:1
+C:F:CRIT
+C:R:36:1
+C:F:CRIT
+C:R:39:1
+C:F:CRIT
+C:R:42:1
+C:F:CRIT
+C:R:45:1
+C:F:CRIT
+C:R:48:1
+C:F:CRIT
+C:E:0:0:0:0:0:0
+C:k:+1000:+700:Combat
+C:k:+1000:+700:Weaponmastery
+C:k:+1000:+300:Sword-mastery
+C:k:+1000:+500:Critical-hits
+C:k:+1000:+700:Magic
+C:k:+0:+550:Magic-Device
+C:k:+0:+500:Conveyance
+C:k:+0:+500:Divination
+C:k:+0:+500:Temporal
+C:k:+1000:+700:Spirituality
+C:k:+1000:+2000:Sneakiness
+C:k:+1000:+1500:Stealth
+C:k:+1000:+2000:Disarming
+C:k:+1000:+1000:Backstab
+C:k:+1000:+2000:Stealing
+C:k:+1000:+2000:Dodging
+C:g:All Gods
+C:b:10:Extra Max Blow(1)
+
+C:a:N:Rogue
+C:a:D:Rogues are masters of tricks. They can steal from shops and monsters,
+C:a:D:and lure monsters into deadly monster traps.
+C:a:b:1:Trapping
+C:a:O:46:1:1d1
+
+C:a:N:Assassin
+C:a:D:Assassins are stealthy killers.
+C:a:k:+0:+100:Combat
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+300:Sword-mastery
+C:a:k:+1000:+300:Critical-hits
+C:a:k:+1000:+300:Boomerang-mastery
+C:a:k:+0:-500:Magic
+C:a:k:+0:-400:Conveyance
+C:a:k:+0:-400:Divination
+C:a:k:+0:-300:Temporal
+C:a:k:+0:+500:Stealth
+C:a:k:+0:-1000:Disarming
+C:a:k:+0:+1000:Backstab
+C:a:k:+0:-1800:Stealing
+C:a:k:+0:-800:Magic-Device
+
+C:N:4:Loremaster
+C:D:0:Loremasters are skilled in most combat and monster skills.
+C:D:1:Apprentice
+C:D:1:Apprentice
+C:D:1:Initiate
+C:D:1:Initiate
+C:D:1:Sage
+C:D:1:Sage
+C:D:1:Lorekeeper
+C:D:1:Lorekeeper
+C:D:1:Loremaster
+C:D:1:Loremaster
+C:S:1:-2:1:1:0:1:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:30:3
+C:C:H:L:9000:2:40
+C:P:8:40
+C:E:0:0:0:0:0:0
+C:k:+1000:+700:Combat
+C:k:+1000:+700:Weaponmastery
+C:k:+1000:+700:Archery
+C:k:+1000:+700:Barehand-combat
+C:k:+0:+600:Magic
+C:k:+1000:+700:Sneakiness
+C:k:+1000:+700:Stealth
+C:k:+1000:+700:Disarming
+C:k:+1000:+700:Spirituality
+C:k:+1000:+600:Monster-lore
+C:k:+0:+500:Possession
+C:k:+1000:+700:Corpse-preservation
+C:k:+0:+500:Summoning
+C:k:+0:+500:Symbiosis
+C:k:+0:+500:Mimicry
+C:k:+0:+300:Music
+C:g:All Gods
+
+C:a:N:Loremaster
+C:a:D:Loremasters are skilled in most combat and monster skills.
+C:a:O:21:3:1d1
+C:a:O:36:6:1d1
+C:a:O:19:2:1d1
+C:a:O:16:0:3d10
+
+C:a:N:Possessor
+C:a:D:Only the soul matters; a possessor can abandon his/her current body to
+C:a:D:incarnate in the body of a dead monster, thus gaining its powers
+C:a:D:and weaknesses.
+C:a:O:71:37:1d1
+C:a:O:23:10:1d1
+C:a:O:36:6:1d1
+C:a:k:+0:-100:Combat
+C:a:k:+0:-100:Weaponmastery
+C:a:k:+0:-300:Archery
+C:a:k:-1000:-700:Barehand-combat
+C:a:k:+0:-200:Disarming
+C:a:k:+0:-200:Spirituality
+C:a:k:+1000:+300:Possession
+C:a:k:+0:+200:Corpse-preservation
+C:a:k:+0:-500:Summoning
+C:a:k:+0:-500:Symbiosis
+C:a:k:+0:-500:Mimicry
+
+C:a:N:Mimic
+C:a:D:Disguise is the way of the mimic. Through the use of cloaks of mimicry
+C:a:D:they can change shape for a limited time. They also can temporarily
+C:a:D:change part of their anatomy.
+C:a:O:71:37:1d1
+C:a:O:23:4:1d1
+C:a:k:+0:+100:Combat
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:-100:Barehand-combat
+C:a:k:+1000:+100:Magic
+C:a:k:+0:+100:Sneakiness
+C:a:k:+0:+100:Stealth
+C:a:k:+0:-200:Spirituality
+C:a:k:+0:-400:Possession
+C:a:k:+0:+200:Corpse-preservation
+C:a:k:+0:-500:Summoning
+C:a:k:+0:-500:Symbiosis
+C:a:k:+1000:+300:Mimicry
+
+C:a:N:Symbiant
+C:a:D:A symbiant can merge his/her body with one of a monster unable to move
+C:a:D:by itself. They also have a few spells to help the symbiosis.
+C:a:O:23:4:1d1
+C:a:O:70:6:1d1
+C:a:k:+0:+100:Combat
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:-100:Barehand-combat
+C:a:k:+1000:+100:Magic
+C:a:k:+0:+100:Sneakiness
+C:a:k:+0:+100:Stealth
+C:a:k:+0:-200:Spirituality
+C:a:k:+0:-400:Possession
+C:a:k:+0:+200:Corpse-preservation
+C:a:k:+0:-500:Summoning
+C:a:k:+1000:+300:Symbiosis
+C:a:k:+0:-500:Mimicry
+
+C:a:N:Summoner
+C:a:D:The summoner can conjure monsters from totems made from defeated foes.
+C:a:O:71:37:1d1
+C:a:O:23:10:1d1
+C:a:O:36:6:1d1
+C:a:k:+0:-100:Combat
+C:a:k:+0:-100:Weaponmastery
+C:a:k:+0:-300:Archery
+C:a:k:-1000:-700:Barehand-combat
+C:a:k:+1000:+200:Magic
+C:a:k:+0:+0:Sneakiness
+C:a:k:+0:+0:Stealth
+C:a:k:+0:-200:Disarming
+C:a:k:+0:-200:Spirituality
+C:a:k:+15000:+100:Monster-lore
+C:a:k:+0:-500:Possession
+C:a:k:+0:+300:Corpse-preservation
+C:a:k:+1000:+200:Summoning
+C:a:k:+0:-500:Symbiosis
+C:a:k:+0:-500:Mimicry
+
+C:a:N:Monk
+C:a:D:Barehanded, lightly armoured fighters, they wreak havoc with
+C:a:D:their bare fists, and can also use a few prayers.
+C:a:O:71:37:1d1
+C:a:O:36:4:1d1
+C:a:k:-1000:+200:Combat
+C:a:k:-1000:-400:Weaponmastery
+C:a:k:-1000:-300:Archery
+C:a:k:+0:+200:Barehand-combat
+C:a:k:+0:+0:Magic
+C:a:k:+0:+200:Sneakiness
+C:a:k:+0:+200:Stealth
+C:a:k:+0:+200:Disarming
+C:a:k:+0:+200:Spirituality
+C:a:k:+0:-400:Possession
+C:a:k:+0:-200:Corpse-preservation
+C:a:k:+0:-500:Summoning
+C:a:k:+0:-500:Symbiosis
+C:a:k:+0:-500:Mimicry
+C:a:k:+0:+500:Meta
+C:a:k:+0:+500:Mind
+C:a:k:+0:+500:Temporal
+C:a:k:+0:+700:Dodging
+
+C:a:N:Bard
+C:a:D:Bards sing and play songs full of power, beauty or sadness to affect
+C:a:D:everything that can hear them, using music instruments of various types.
+C:a:O:71:37:1d1
+C:a:O:23:10:1d1
+C:a:O:36:2:1d1
+C:a:O:14:59:1d1
+C:a:k:+1000:+0:Magic
+C:a:k:-1000:-700:Archery
+C:a:k:+0:-100:Barehand-combat
+C:a:k:+0:-100:Disarming
+C:a:k:+0:+100:Spirituality
+C:a:k:+0:-500:Possession
+C:a:k:+0:-100:Summoning
+C:a:k:+0:-100:Symbiosis
+C:a:k:+0:-100:Mimicry
+C:a:k:+1000:+500:Music
+
+C:N:5:Priest
+C:D:0:A priest serves a god (Vala, Maia or Eru himself) to bring down
+C:D:0:the empire of fear and shadows of Morgoth.
+C:D:1:Believer
+C:D:1:Acolyte
+C:D:1:Adept
+C:D:1:Curate
+C:D:1:Canon
+C:D:1:Priest
+C:D:1:High Priest
+C:D:1:Cardinal
+C:D:1:Inquisitor
+C:D:1:Pope
+C:S:-1:-3:3:-1:0:2:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:35:3
+C:C:L:H:10000:2:40
+C:P:2:20
+C:Z:detect curses
+C:G:GOD_FRIEND |
+C:E:0:0:0:0:0:0
+C:k:+1000:+900:Magic
+C:k:+0:+600:Spell-power
+C:k:+0:+600:Necromancy
+C:k:+0:+600:Mindcraft
+C:k:+1000:+1000:Spirituality
+C:k:+1000:+700:Prayer
+C:k:+2000:+700:Combat
+C:k:+1000:+700:Weaponmastery
+C:k:+1000:+900:Sneakiness
+C:k:+0000:+900:Disarming
+C:k:+0000:+400:Stealth
+C:k:+0:+50:Magic-Device
+C:b:1:Perfect casting
+
+C:a:N:Priest(Eru)
+C:a:D:A priest that serves Eru Iluvatar to bring down
+C:a:D:the empire of fear and shadows of Morgoth.
+C:a:O:21:5:1d1
+C:a:g:Eru Iluvatar
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+100:Spell-power
+
+C:a:N:Priest(Manwe)
+C:a:D:A priest that serves Manwe Sulimo to bring down
+C:a:D:the empire of fear and shadows of Morgoth.
+C:a:O:21:5:1d1
+C:a:g:Manwe Sulimo
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+50:Weaponmastery
+
+C:a:N:Druid
+C:a:D:A priest that serves Yavanna Kementari to protect
+C:a:D:and help the regrowth of nature on Arda.
+C:a:O:21:5:1d1
+C:a:g:Yavanna Kementari
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+50:Weaponmastery
+C:a:k:+1000:+700:Monster-lore
+C:a:k:+1000:+700:Summoning
+
+C:a:N:Dark-Priest
+C:a:D:A priest that serves Melkor Bauglir to bring chaos
+C:a:D:and destruction to Arda.
+C:a:O:21:5:1d1
+C:a:g:Melkor Bauglir
+C:a:k:+0:+200:Prayer
+C:a:k:+0:+200:Necromancy
+C:a:k:+0:-600:Mindcraft
+C:a:k:+0:+200:Spell-power
+C:a:k:+1000:+1000:Corpse-preservation
+
+C:a:N:Paladin
+C:a:D:A fighting priest that serves Tulkas to bring down
+C:a:D:the empire of fear and shadows of Morgoth.
+C:a:O:23:25:1d1
+C:a:g:Tulkas
+C:a:k:+0:+200:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+0:+900:Barehand-combat
+C:a:b:1:Extra Max Blow(1)
+
+C:a:N:Mindcrafter
+C:a:D:A priest who has learned to tap in his own mental powers
+C:a:O:21:5:1d1
+C:a:g:Eru Iluvatar
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Melkor Bauglir
+C:a:g:Yavanna Kementari
+C:a:k:+0:-300:Prayer
+C:a:k:+0:-200:Necromancy
+C:a:k:+1000:+300:Mindcraft
+C:a:k:+0:+200:Sneakiness
+C:a:k:+0:+100:Magic-Device
+
+###############################TEST###############################
+C:N:30:Test
+C:D:0:Simple testers.
+C:D:1:Rookie
+C:D:1:Soldier
+C:D:1:Mercenary
+C:D:1:Veteran
+C:D:1:Swordsman
+C:D:1:Champion
+C:D:1:Hero
+C:D:1:Baron
+C:D:1:Duke
+C:D:1:Lord
+C:S:5:-2:-2:2:2:-1:0:3
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:6:30:5
+C:C:H:L:9000:2:40
+C:P:9:0
+C:R:30:0
+C:F:RES_FEAR
+C:E:0:0:0:0:0:0
+C:O:45:38:1d1
+C:O:37:4:1d1
+C:k:+1000:+800:Combat
+C:k:+1000:+850:Weaponmastery
+C:k:+0:+200:Sword-mastery
+C:k:+0:+200:Axe-mastery
+C:k:+0:+200:Hafted-mastery
+C:k:+0:+200:Polearm-mastery
+C:k:+1000:+600:Archery
+C:k:+1000:+900:Sneakiness
+C:k:+1000:+900:Disarming
+C:k:+1000:+300:Magic
+C:k:+0:+550:Antimagic
+
+C:a:N:Shinny test
+C:a:D:Simple testers, they test all with their shiny hacks !
+C:a:O:23:16:1d1
+###############################TEST###############################
+
+
+
+
+
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# R: Race definition
+# R:N:index:name
+# R:D:race desc
+# R:S:str:int:wis:dex:con:chr:luck
+# R:K:dis:dev:sav:stl:srh:fos:thn:thb
+# R:P:hitdie:xp%:infra:history chart
+# R:M:b_age:m_age:m_b_ht:m_m_ht:m_b_wt:m_m_wt:f_b_ht:f_m_ht:f_b_wt:f_m_wt
+# R:E:weapons:torso:arms:finger:head:legs
+# R:C:allowed classes
+# R:G:race flags
+# R:R:level:pval
+# R:F:flags
+# R:k:value:modifier:skill name
+# R:b:level:ability
+
+I:
+
+R:N:0:Human
+R:D:Humans are the second born, the Edain.
+R:D:They are the basic race to which all others are compared.
+R:D:Average in ability, they can be any class.
+R:S:0:0:0:0:0:0:0
+R:K:0:0:0:0:0:10:0:0
+R:P:10:100:0:1
+R:M:14:6:72:6:180:25:66:4:150:20
+R:E:1:1:1:2:1:1
+R:C:Warrior | Archer | Mage | Rogue | Priest | Loremaster
+
+R:N:1:Half-Elf
+R:D:A crossbreed of elf and human, they get the best of the two races.
+R:S:0:1:1:1:-1:1:0
+R:K:2:3:3:1:6:11:-1:5
+R:P:9:110:2:4
+R:M:24:16:66:6:130:15:62:6:100:10
+R:E:1:1:1:2:1:1
+R:C:Warrior | Archer | Mage | Rogue | Priest | Loremaster
+R:G:ELF
+R:k:+200:+000:Disarming
+R:k:+300:+000:Magic-Device
+R:k:+1500:+000:Spirituality
+R:k:+1000:+000:Stealth
+R:k:+600:+000:Sneakiness
+R:k:-100:+000:Weaponmastery
+R:k:+500:+000:Archery
+
+R:N:2:Elf
+R:D:Elves are the first born, the Eldar.
+R:D:More spiritual than physical beings, they are weaker than humans
+R:D:but are more intelligent.
+R:S:-1:2:2:1:-2:2:0
+R:K:5:6:6:2:8:12:-5:15
+R:P:8:120:3:5
+R:M:75:75:60:4:100:6:54:4:80:6
+R:E:1:1:1:2:1:1
+R:R:1:0
+R:F:RES_LITE |
+R:C:Warrior | Archer | Mage | Priest | Loremaster
+R:G:ELF
+R:k:+500:+000:Disarming
+R:k:+600:+000:Magic-Device
+R:k:+3000:+000:Spirituality
+R:k:+2000:+000:Stealth
+R:k:+800:+000:Sneakiness
+R:k:-500:+000:Weaponmastery
+R:k:+1500:+000:Archery
+
+R:N:3:Hobbit
+R:D:An old but quiet race related to humans.
+R:D:They are small and quite weak but good at many things.
+R:S:-2:2:1:3:2:1:5
+R:K:15:18:18:5:12:15:-10:20
+R:P:7:110:4:10
+R:M:21:12:36:3:60:3:33:3:50:3
+R:E:1:1:1:2:1:1
+R:Z:create food
+R:G:RESIST_BLACK_BREATH | XTRA_MIGHT_SLING |
+R:R:1:0
+R:F:SUST_DEX |
+R:C:Warrior | Archer | Mage | Rogue | Loremaster
+R:k:+0:+300:Sling-mastery
+R:k:+1500:+000:Disarming
+R:k:+1800:+000:Magic-Device
+R:k:+9000:+000:Spirituality
+R:k:+5000:+000:Stealth
+R:k:+1200:+000:Sneakiness
+R:k:-1000:+000:Weaponmastery
+R:k:+2000:+000:Archery
+
+R:N:4:Gnome
+R:D:Related to dwarves, Gnomes are between Dwarves and Hobbits in size.
+R:D:Very good at magic use, they are poor as fighters.
+R:S:-1:2:0:2:1:-2:2
+R:K:10:12:12:3:6:13:-8:12
+R:P:8:135:4:13
+R:M:50:40:42:3:90:6:39:3:75:3
+R:E:1:1:1:2:1:1
+R:Z:blink
+R:R:1:0
+R:F:FREE_ACT |
+R:C:Warrior | Mage | Rogue
+R:k:+1000:+000:Disarming
+R:k:+1200:+000:Magic-Device
+R:k:+6000:+000:Spirituality
+R:k:+3000:+000:Stealth
+R:k:+600:+000:Sneakiness
+R:k:-800:+000:Weaponmastery
+R:k:+1200:+000:Archery
+
+R:N:5:Dwarf
+R:D:The children of Aule, a strong but small race.
+R:D:Miners and fighters of legend.
+R:S:2:-2:2:-2:2:-3:0
+R:K:2:9:10:-1:7:10:15:0
+R:P:11:125:5:16
+R:M:35:15:48:3:150:10:46:3:120:10
+R:E:1:1:1:2:1:1
+R:Z:find secret passages
+R:R:1:0
+R:F:RES_BLIND |
+R:C:Warrior | Priest
+R:k:+0:+200:Axe-mastery
+R:k:+200:+000:Disarming
+R:k:+900:+000:Magic-Device
+R:k:+5000:+000:Spirituality
+R:k:-1000:+000:Stealth
+R:k:+700:+000:Sneakiness
+R:k:+1500:+000:Weaponmastery
+R:k:+500:+000:Archery
+
+R:N:6:Orc
+R:D:Quite strong but not very smart.
+R:S:2:-1:0:1:1:-4:-3
+R:K:-3:-3:-3:-1:0:7:12:-5
+R:P:10:110:3:25
+R:M:11:4:66:1:150:5:62:1:120:5
+R:E:1:1:1:2:1:1
+R:Z:remove fear
+R:R:1:0
+R:F:RES_DARK |
+R:C:Warrior | Archer | Rogue | Priest
+R:k:-300:+000:Disarming
+R:k:-300:+000:Magic-Device
+R:k:-1000:+000:Spirituality
+R:k:-1000:+000:Stealth
+R:k:+000:+000:Sneakiness
+R:k:+1200:+000:Weaponmastery
+R:k:-500:+000:Archery
+
+R:N:7:Troll
+R:D:They can bear the light of the sun.
+R:D:They are extremely strong and dumb.
+R:S:4:-4:-2:-4:3:-6:-4
+R:K:-5:-8:-8:-2:-1:5:20:-10
+R:P:12:137:3:22
+R:M:20:10:96:10:250:50:84:8:225:40
+R:E:1:1:1:2:1:1
+R:Z:berserk
+R:R:1:0
+R:F:SUST_STR |
+R:R:15:0
+R:F:REGEN |
+R:C:Warrior
+R:k:-500:+000:Disarming
+R:k:-800:+000:Magic-Device
+R:k:-4000:+000:Spirituality
+R:k:-2000:+000:Stealth
+R:k:-100:+000:Sneakiness
+R:k:+2000:+000:Weaponmastery
+R:k:-1000:+000:Archery
+
+R:N:8:Dunadan
+R:D:The greatest of the Edain, humans in all respects but
+R:D:stronger, smarter and wiser.
+R:S:1:2:2:2:3:2:2
+R:K:4:5:5:2:3:13:15:10
+R:P:10:180:0:1
+R:M:50:50:82:5:190:20:78:6:180:15
+R:E:1:1:1:2:1:1
+R:R:1:0
+R:F:SUST_CON | REGEN |
+R:C:Warrior | Archer | Mage | Rogue | Priest | Loremaster
+R:k:+400:+000:Disarming
+R:k:+500:+000:Magic-Device
+R:k:+2500:+000:Spirituality
+R:k:+2000:+000:Stealth
+R:k:+800:+000:Sneakiness
+R:k:+1500:+000:Weaponmastery
+R:k:+1000:+000:Archery
+
+R:N:9:High-Elf
+R:D:Elves are the first born, the Eldar.
+R:D:High elves are the best of the Eldar, strong, fast, intellectual, though
+R:D:they sometimes lack wisdom.
+R:S:1:3:2:3:1:5:0
+R:K:4:20:20:4:3:14:10:25
+R:P:10:200:4:7
+R:M:100:30:90:10:190:20:82:10:180:15
+R:E:1:1:1:2:1:1
+R:R:1:0
+R:F:SEE_INVIS |
+R:F:RES_LITE |
+R:G:ELF
+R:C:Warrior | Archer | Mage | Priest | Loremaster
+R:k:+400:+000:Disarming
+R:k:+2000:+000:Magic-Device
+R:k:+10000:+000:Spirituality
+R:k:+4000:+000:Stealth
+R:k:+300:+000:Sneakiness
+R:k:+1000:+000:Weaponmastery
+R:k:+2500:+000:Archery
+
+R:N:10:Half-Ogre
+R:D:A crossbreed between a human and an ogre.
+R:D:They are similar to half-trolls, strong and dumb.
+R:S:3:-1:-1:-1:3:-3:-2
+R:K:-3:-5:-5:-2:-1:5:20:0
+R:P:12:130:3:74
+R:M:40:10:92:10:255:60:80:8:235:60
+R:E:1:1:1:2:1:1
+R:Z:set explosive rune
+R:R:1:0
+R:F:SUST_STR | RES_DARK |
+R:C:Warrior | Priest
+R:k:-300:+000:Disarming
+R:k:-500:+000:Magic-Device
+R:k:-2500:+000:Spirituality
+R:k:-2000:+000:Stealth
+R:k:-100:+000:Sneakiness
+R:k:+2000:+000:Weaponmastery
+R:k:+000:+000:Archery
+
+R:N:11:Beorning
+R:D:A race of men shapeshifters.
+R:D:They have the unique power of being able to polymorph to bear forms.
+R:S:4:-2:-2:-1:3:-5:1
+R:K:-6:-8:-6:-2:-1:5:25:5
+R:P:12:150:3:75
+R:M:40:10:100:10:255:65:80:10:240:64
+R:E:1:1:1:2:1:1
+R:Z:turn into a bear
+R:R:1:0
+R:F:SUST_STR |
+R:R:20:1
+R:F:STR |
+R:C:Warrior | Rogue | Loremaster
+R:k:+1000:+1000:Bearform-combat
+R:k:-600:+000:Disarming
+R:k:-800:+000:Magic-Device
+R:k:-3000:+000:Spirituality
+R:k:-2000:+000:Stealth
+R:k:-100:+000:Sneakiness
+R:k:+2500:+000:Weaponmastery
+R:k:+500:+000:Archery
+
+R:N:12:Kobold
+R:D:A weaker kind of goblin, related to orcs.
+R:S:1:-1:0:1:0:-4:0
+R:K:-2:-3:-2:-1:1:8:10:-8
+R:P:9:125:3:82
+R:M:11:3:60:1:130:5:55:1:100:5
+R:E:1:1:1:2:1:1
+R:Z:poison dart
+R:R:1:0
+R:F:RES_POIS |
+R:C:Warrior | Archer | Rogue
+R:k:-200:+000:Disarming
+R:k:-300:+000:Magic-Device
+R:k:-1000:+000:Spirituality
+R:k:-1000:+000:Stealth
+R:k:+100:+000:Sneakiness
+R:k:+1000:+000:Weaponmastery
+R:k:-800:+000:Archery
+
+R:N:13:Petty-Dwarf
+R:D:A nearly extinct subrace of dwarves.
+R:D:They prefer to live in the darkness.
+R:S:1:-1:2:0:2:-4:-5
+R:K:3:5:10:1:5:10:9:0
+R:P:11:135:5:87
+R:M:40:12:43:3:92:6:40:3:78:3
+R:E:1:1:1:2:1:1
+R:Z:detect doors and traps
+R:R:1:0
+R:F:RES_DARK | RES_DISEN |
+R:C:Warrior | Rogue
+R:k:+300:+000:Disarming
+R:k:+500:+000:Magic-Device
+R:k:+5000:+000:Spirituality
+R:k:+1000:+000:Stealth
+R:k:+500:+000:Sneakiness
+R:k:+000:+000:Weaponmastery
+R:k:+000:+000:Archery
+
+R:N:14:Dark-Elf
+R:D:Elves are the first born, the Eldar.
+R:D:Dark elves are rare on Middle-earth and even though not evil
+R:D:they are not good.
+R:S:-1:3:2:2:-2:1:-2
+R:K:5:15:20:3:8:12:-5:10
+R:P:9:150:5:69
+R:M:75:75:60:4:100:6:54:4:80:6
+R:E:1:1:1:2:1:1
+R:Z:magic missile
+R:R:1:0
+R:F:RES_DARK |
+R:R:20:0
+R:F:SEE_INVIS |
+R:C:Warrior | Archer | Mage | Rogue | Priest
+R:G:ELF
+R:k:+0:+200:Magic
+R:k:+500:+000:Disarming
+R:k:+1500:+000:Magic-Device
+R:k:+10000:+000:Spirituality
+R:k:+3000:+000:Stealth
+R:k:+800:+000:Sneakiness
+R:k:-500:+000:Weaponmastery
+R:k:+1000:+000:Archery
+
+R:N:15:Ent
+R:D:Guardian of the forests of Middle-earth, summoned by Yavanna before
+R:D:even the elves awoke. It is said 'Trolls are strong, Ents are STRONGER'.
+R:S:10:-3:2:-5:11:-3:-2
+R:K:5:5:20:-6:5:4:15:5
+R:P:14:210:5:95
+R:M:255:70:72:6:100:25:66:4:100:20
+R:E:1:1:1:2:1:1
+R:Z:grow trees
+R:G:NO_STUN | NO_FOOD |
+R:G:AC_LEVEL |
+R:R:1:-5
+R:F:SPEED | SENS_FIRE | SLOW_DIGEST |
+R:R:5:0
+R:F:SEE_INVIS |
+R:R:20:0
+R:F:ESP_ORC |
+R:F:ESP_TROLL | ESP_EVIL |
+R:C:Warrior | Priest | Loremaster
+R:O:70:32:2d3
+R:b:1:Tree walking
+R:k:+0:+200:Barehand-combat
+R:k:+0:+600:Boulder-throwing
+R:k:+500:+000:Disarming
+R:k:+500:+000:Magic-Device
+R:k:+10000:+000:Spirituality
+R:k:-6000:+000:Stealth
+R:k:+500:+000:Sneakiness
+R:k:-300:+000:Weaponmastery
+R:k:-200:+000:Archery
+
+R:N:16:RohanKnight
+R:D:Humans from the land of Rohan, riding the great Mearas.
+R:D:Fast and powerful in battle.
+R:S:4:-2:3:1:4:2:0
+R:K:10:5:5:-8:1:1:5:5
+R:P:10:220:0:84
+R:M:20:3:60:3:80:4:54:3:70:4
+R:E:1:1:1:2:1:1
+R:Z:Rohan Knight's Powers
+R:R:1:3
+R:F:SPEED |
+R:R:5:1
+R:F:SPEED |
+R:R:10:1
+R:F:SPEED |
+R:R:15:1
+R:F:SPEED |
+R:R:20:1
+R:F:SPEED |
+R:R:25:1
+R:F:SPEED |
+R:R:30:1
+R:F:SPEED |
+R:R:35:1
+R:F:SPEED |
+R:R:40:1
+R:F:SPEED |
+R:R:45:1
+R:F:SPEED |
+R:C:Warrior | Priest
+R:k:+1000:+000:Disarming
+R:k:+500:+000:Magic-Device
+R:k:+2500:+000:Spirituality
+R:k:-8000:+000:Stealth
+R:k:+100:+000:Sneakiness
+R:k:+100:+200:Weaponmastery
+R:k:+500:+000:Archery
+
+R:N:17:Thunderlord
+R:D:A thunderlord is a Great Eagle of Manwe, ridden by a Maia of Manwe.
+R:D:They carry the power of wind and thunder.
+R:S:6:2:1:1:3:8:2
+R:K:6:0:10:-16:30:10:15:5
+R:P:12:400:0:89
+R:M:14:6:180:6:255:25:150:4:230:20
+R:E:1:1:1:2:1:1
+R:Z:Thunderlord's Powers
+R:R:1:0
+R:F:FEATHER |
+R:R:4:0
+R:F:ESP_DRAGON |
+R:R:5:0
+R:F:RES_ELEC |
+R:R:10:0
+R:F:RES_COLD |
+R:R:15:0
+R:F:RES_ACID |
+R:R:17:0
+R:F:FLY |
+R:R:35:0
+R:F:RES_POIS |
+R:R:45:0
+R:F:IM_ELEC |
+R:C:Warrior | Mage | Archer | Priest
+R:k:+600:+000:Disarming
+R:k:+000:+000:Magic-Device
+R:k:+5000:+000:Spirituality
+R:k:-16000:+000:Stealth
+R:k:+3000:+000:Sneakiness
+R:k:+1500:+000:Weaponmastery
+R:k:+500:+000:Archery
+
+R:N:18:DeathMold
+R:D:A pure mass of evilness, DeathMolds cannot move, but they have much more
+R:D:power than an average race.
+R:S:10:0:10:0:10:-15:-5
+R:K:15:-5:15:25:0:10:25:25
+R:P:15:250:10:100
+R:M:5:15:10:1:50:1:10:1:50:1
+R:E:1:1:1:4:0:0
+R:Z:Death Mold's Powers
+R:G:EXPERIMENTAL
+R:R:1:0
+R:F:IMMOVABLE | HOLD_LIFE |
+R:F:RES_NETHER | RES_NEXUS |
+R:C:Mage | Priest
+R:k:+0:+200:Necromancy
+R:k:+1500:+000:Disarming
+R:k:-500:+000:Magic-Device
+R:k:+7500:+000:Spirituality
+R:k:+25000:+000:Stealth
+R:k:+000:+000:Sneakiness
+R:k:+2500:+000:Weaponmastery
+R:k:+2500:+000:Archery
+
+R:N:19:Yeek
+R:D:The weakest of all the races, bad at everything except gaining levels quickly.
+R:S:-5:-5:-5:-5:-5:-5:-5
+R:K:-5:-5:-10:0:-5:0:-10:-10
+R:P:6:25:2:29
+R:M:10:4:40:5:50:10:35:4:45:10
+R:E:1:1:1:2:1:1
+R:C:Warrior | Archer | Mage | Rogue | Priest | Loremaster
+R:k:-500:+000:Disarming
+R:k:-500:+000:Magic-Device
+R:k:-2500:+000:Spirituality
+R:k:-5000:+000:Stealth
+R:k:-500:+000:Sneakiness
+R:k:-500:+000:Weaponmastery
+R:k:-500:+000:Archery
+
+R:N:20:Wood-Elf
+R:D:Elves are the first born, the Eldar.
+R:D:Wood elves live in the great forests of Middle-earth.
+R:S:-3:2:1:5:-4:1:0
+R:K:5:6:6:5:8:12:-25:40
+R:P:7:130:4:5
+R:M:75:75:60:4:100:6:54:4:80:6
+R:E:1:1:1:2:1:1
+R:G:XTRA_MIGHT_BOW |
+R:R:1:1
+R:F:XTRA_MIGHT | RES_LITE |
+R:C:Warrior | Archer | Mage | Priest | Loremaster
+R:G:ELF
+R:k:+0:+200:Archery
+R:b:1:Tree walking
+R:k:+500:+000:Disarming
+R:k:+600:+000:Magic-Device
+R:k:+3000:+000:Spirituality
+R:k:+5000:+000:Stealth
+R:k:+800:+000:Sneakiness
+R:k:-2500:+000:Weaponmastery
+R:k:+4000:+000:Archery
+
+R:N:21:Maia
+R:D:An old race, dating from before the creation of Arda, the Maiar were
+R:D:created by Eru to help the Valar in their task.
+R:S:0:0:0:0:0:0:4
+R:K:0:0:0:0:0:10:0:0
+R:P:10:100:0:91
+R:M:14:6:72:6:180:25:66:4:150:20
+R:E:1:1:1:2:1:1
+R:G:NO_GOD
+R:R:1:0
+R:F:AGGRAVATE |
+R:R:20:0
+R:F:DRAIN_EXP |
+R:R:6:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:12:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:18:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:24:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:30:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:36:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:42:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:48:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:C:Warrior | Archer | Mage
+R:k:+000:+000:Disarming
+R:k:+000:+000:Magic-Device
+R:k:+000:+000:Spirituality
+R:k:=0:=0:Prayer
+R:k:+000:+000:Stealth
+R:k:+000:+000:Sneakiness
+R:k:+000:+000:Weaponmastery
+R:k:+000:+000:Archery
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# S: Subrace definition
+# S:N:index:name
+# S:D:'A'fter/'B'efore:subrace desc
+# S:S:str:int:wis:dex:con:chr:luck:mana
+# S:K:dis:dev:sav:stl:srh:fos:thn:thb
+# S:P:hitdie:xp%:infra
+# S:M:b_age:m_age:m_b_ht:m_m_ht:m_b_wt:m_m_wt:f_b_ht:f_m_ht:f_b_wt:f_m_wt
+# S:E:weapons:torso:arms:finger:head:legs
+# S:A:allowed races
+# S:C:'A'llow/'F'orbid:allowed/forbiden classes
+# S:G:subrace flags
+# S:R:level:pval
+# S:F:flags
+# S:k:value:modifier:skill name
+# S:b:level:ability
+
+# Make the parser actually work :)
+I:
+
+S:N:0:
+S:D:A:A normal member of the race.
+S:S:0:0:0:0:0:0:0:100
+S:K:0:0:0:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Orc | Troll | Dunadan | High-Elf | Half-Ogre | Beorning |
+S:A:Kobold | Petty-Dwarf | Dark-Elf | Ent | RohanKnight | Thunderlord |
+S:A:DeathMold | Yeek | Wood-Elf | Maia |
+
+# Just a place holder, the actualy setting are done with corruptions, see
+# corrupt.lua and player.lua
+S:N:1:Vampire
+S:D:B:Vampires are powerful undead, wielding great powers. They still fear the
+S:D:B:sunlight and cannot easily satiate their hunger.
+S:S:0:0:0:0:0:0:0:100
+S:K:0:0:0:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Hobbit | Gnome | Dwarf | Orc |
+S:A:Troll | Dunadan | Half-Ogre | Beorning | Kobold | Petty-Dwarf |
+S:A:Dark-Elf | RohanKnight | Yeek |
+S:C:A:Mage
+S:O:70:0:5d3
+S:O:70:32:2d3
+
+S:N:2:Spectre
+S:D:B:Spectres only partially exist in the mortal world and so they can
+S:D:B:pass through walls. They are somewhat physically weak.
+S:S:-5:1:1:2:-3:-6:-3:105
+S:K:2:8:7:2:2:7:-5:-2
+S:P:-4:80:3
+S:M:50:15:0:0:-10:-5:0:0:-10:-5
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Orc | Troll | Dunadan | High-Elf | Half-Ogre | Beorning |
+S:A:Kobold | Petty-Dwarf | Dark-Elf | RohanKnight | Yeek | Wood-Elf |
+S:C:F:Warrior | Archer
+S:G:UNDEAD | NO_CUT | NO_FOOD | SEMI_WRAITH | NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SEE_INVIS | HOLD_LIFE |
+S:F:SLOW_DIGEST | RES_COLD | RES_POIS | RES_NETHER |
+S:O:70:32:2d3
+S:k:+200:+000:Disarming
+S:k:+800:+000:Magic-Device
+S:k:+700:+000:Spirituality
+S:k:+2000:+000:Stealth
+S:k:+200:+000:Sneakiness
+S:k:-500:+000:Weaponmastery
+S:k:-200:+000:Archery
+
+S:N:3:Skeleton
+S:D:B:Yet an other kind of undead. Their physical 'body' is not very vulnerable
+S:D:B:to sharp things.
+S:S:0:-2:-2:0:1:-4:-3:70
+S:K:-5:-5:5:-1:-1:8:8:0
+S:P:0:45:1
+S:M:50:15:0:0:-10:-5:0:0:-10:-5
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Orc | Troll | Dunadan | High-Elf | Half-Ogre | Beorning |
+S:A:Kobold | Petty-Dwarf | Dark-Elf | RohanKnight | Yeek | Wood-Elf |
+S:G:UNDEAD | NO_CUT | NO_FOOD | NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SEE_INVIS | HOLD_LIFE |
+S:F:RES_POIS | RES_SHARDS |
+S:R:10:0
+S:F:RES_COLD |
+S:O:70:32:2d3
+S:k:-500:+000:Disarming
+S:k:-500:+000:Magic-Device
+S:k:+500:+000:Spirituality
+S:k:-1000:+000:Stealth
+S:k:-100:+000:Sneakiness
+S:k:+800:+000:Weaponmastery
+S:k:+000:+000:Archery
+
+S:N:4:Zombie
+S:D:B:Strong and dumb is a zombie.
+S:S:2:-6:-6:1:4:-5:-4:70
+S:K:-2:-2:5:-1:-1:2:5:0
+S:P:3:45:1
+S:M:50:15:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Orc | Troll | Dunadan | High-Elf | Half-Ogre | Beorning |
+S:A:Kobold | Petty-Dwarf | Dark-Elf | RohanKnight | Yeek | Wood-Elf |
+S:C:F:Mage
+S:G:UNDEAD | NO_FOOD | NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SEE_INVIS | HOLD_LIFE |
+S:F:SLOW_DIGEST | RES_POIS |
+S:R:5:0
+S:F:RES_COLD |
+S:O:70:32:2d3
+S:k:-200:+000:Disarming
+S:k:-200:+000:Magic-Device
+S:k:+500:+000:Spirituality
+S:k:-1000:+000:Stealth
+S:k:-100:+000:Sneakiness
+S:k:+500:+000:Weaponmastery
+S:k:+000:+000:Archery
+
+S:N:5:Barbarian
+S:D:A:Hardy members of their race, they are strong fighters but poor spellcasters.
+S:S:2:-3:-2:1:1:-3:1:50
+S:K:-2:-10:2:-2:0:1:12:5
+S:P:1:25:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Dwarf | Orc | Troll | Half-Ogre | Beorning |
+S:C:F:Mage
+S:R:10:0
+S:F:RES_FEAR |
+S:k:-200:+000:Disarming
+S:k:-1000:+000:Magic-Device
+S:k:+200:+000:Spirituality
+S:k:-2000:+000:Stealth
+S:k:+000:+000:Sneakiness
+S:k:+1200:+000:Weaponmastery
+S:k:+500:+000:Archery
+
+S:N:6:Hermit
+S:D:A:Through years of isolation hermits can manage to increase their mana
+S:D:A:reserves but at the cost of an increased physical weakness.
+S:S:-3:1:1:-3:-3:1:0:120
+S:K:5:10:5:3:4:10:-5:-5
+S:P:-3:20:1
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Dunadan | High-Elf | Petty-Dwarf | Dark-Elf | Ent | RohanKnight |
+S:A:Thunderlord | DeathMold | Yeek | Wood-Elf | Maia |
+S:C:F:Warrior | Archer
+S:k:+500:+000:Disarming
+S:k:+1000:+000:Magic-Device
+S:k:+500:+000:Spirituality
+S:k:+3000:+000:Stealth
+S:k:+400:+000:Sneakiness
+S:k:-500:+000:Weaponmastery
+S:k:-500:+000:Archery
+
+S:N:8:LostSoul
+S:D:A:In some very rare occasions souls can come back from the Halls of Mandos.
+S:S:0:0:0:0:0:0:0:100
+S:K:0:0:0:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:G:ASTRAL | NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SEE_INVIS
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Orc | Troll | Dunadan | High-Elf | Half-Ogre | Beorning |
+S:A:Kobold | Petty-Dwarf | Dark-Elf | Ent | RohanKnight | Thunderlord |
+S:A:DeathMold | Yeek | Wood-Elf | Maia |
+S:O:70:32:25d2
+S:O:70:12:25d3
+
+# Used for corruptions that can change your subrace
+S:N:9:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+S:D:A:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+S:S:0:0:0:0:0:0:0:100
+S:K:0:0:0:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# H: Race history
+# H:index:chance:chart:next chart:social class bonus:desc
+
+# Dunadan, Human: 1 -> 2 -> 3 -> 50 -> 51 -> 52 -> 53.
+# RohanKnight: 84 -> 85 -> 50 -> 51 -> 52 -> 53.
+# Half-Ogre: 74 -> 20 -> 2 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Beorning: 75 -> 76 -> 20 -> 2 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Half-elf: 4 -> 1 -> 2 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Elf, Wood-elf: 5 -> 6 -> 9 -> 54 -> 55 -> 56.
+# High-elf: 7 -> 8 -> 9 -> 54 -> 55 -> 56.
+# Dark-elf: 69 -> 70 -> 71 -> 72 -> 73.
+# Hobbit: 10 -> 11 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Gnome: 13 -> 14 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Dwarf: 16 -> 17 -> 18 -> 57 -> 58 -> 59 -> 60 -> 61.
+# Petty-Dwarf: 87 -> 88 -> 18 -> 57 -> 58 -> 59 -> 60 -> 61.
+# Thunderlord: 89 -> 90 -> 93 -> 94.
+# Maia: 91 -> 92 -> 93 -> 94.
+# Ent: 95 -> 96.
+# Troll: 22 -> 23 -> 24 -> 62 -> 63 -> 64 -> 65 -> 66.
+# Orc 25 -> 26 -> 27 -> 28 -> 80 -> 81 -> 65 -> 66.
+# Yeek: 29 -> 3 -> 50 -> 51 -> 52 -> 53.
+# (not used: 78 -> 79 -> 80 -> 81 -> 65 -> 66.)
+# Kobold: 82 -> 83 -> 80 -> 81 -> 65 -> 66.
+# Deathmold: 100 -> 101 -> 102 -> 103 -> 104.
+
+H:0:10:1:2:25:You are the illegitimate and unacknowledged child
+H:1:20:1:2:35:You are the illegitimate but acknowledged child
+H:2:95:1:2:45:You are one of several children
+H:3:100:1:2:50:You are the first child
+
+H:4:40:2:3:65:of a Serf.
+H:5:65:2:3:80:of a Yeoman.
+H:6:80:2:3:90:of a Townsman.
+H:7:90:2:3:105:of a Guildsman.
+H:8:96:2:3:120:of a Landed Knight.
+H:9:99:2:3:130:of a Noble Lord.
+H:10:100:2:3:140:of the Royal Blood Line.
+
+H:11:20:3:50:20:You are the black sheep of the family.
+H:12:80:3:50:55:You are a credit to the family.
+H:13:100:3:50:60:You are a well-liked child.
+
+H:14:25:4:1:40:Your mother was of the Avari.
+H:15:40:4:1:50:Your father was of the Avari.
+H:16:65:4:1:60:Your mother was of the Nandor.
+H:17:80:4:1:60:Your father was of the Nandor.
+H:18:96:4:1:70:Your mother was of the Sindar.
+H:19:99:4:1:70:Your father was of the Sindar.
+H:20:100:4:1:100:Your ancestry traces to Elrond.
+
+H:21:60:5:6:50:You are one of several children
+H:22:100:5:6:55:You are the only child
+
+H:23:40:6:9:40:of an Avarin
+H:24:70:6:9:50:of a Nandorin
+H:25:100:6:9:60:of a Sindarin
+
+H:26:60:7:8:50:You are one of several children
+H:27:100:7:8:55:You are the only child
+
+H:28:75:8:9:50:of a Telerin
+H:29:95:8:9:55:of a Noldorin
+H:30:100:8:9:60:of a Vanyarin
+
+H:31:40:9:54:80:Ranger.
+H:32:70:9:54:90:Archer.
+H:33:87:9:54:110:Warrior.
+H:34:95:9:54:125:Mage.
+H:35:99:9:54:140:Prince.
+H:36:100:9:54:145:King.
+
+H:37:85:10:11:45:You are one of several children of a Hobbit
+H:38:100:10:11:55:You are the only child of a Hobbit
+
+H:39:20:11:3:55:Bum.
+H:40:30:11:3:80:Tavern Owner.
+H:41:40:11:3:90:Miller.
+H:42:50:11:3:100:Home Owner.
+H:43:80:11:3:110:Burglar.
+H:44:95:11:3:115:Warrior.
+H:45:99:11:3:125:Mage.
+H:46:100:11:3:140:Clan Elder.
+
+H:47:85:13:14:45:You are one of several children of a Gnome
+H:48:100:13:14:55:You are the only child of a Gnome
+
+H:49:20:14:3:55:Beggar.
+H:50:50:14:3:70:Braggart.
+H:51:75:14:3:85:Prankster.
+H:52:95:14:3:100:Warrior.
+H:53:100:14:3:125:Mage.
+
+H:54:25:16:17:40:You are one of two children of a Dwarven
+H:55:100:16:17:50:You are the only child of a Dwarven
+
+H:56:10:17:18:60:Thief.
+H:57:35:17:18:80:Smith.
+H:58:75:17:18:90:Miner.
+H:59:90:17:18:110:Warrior.
+H:60:99:17:18:130:Priest.
+H:61:100:17:18:150:King.
+
+H:62:15:18:57:10:You are the black sheep of the family.
+H:63:85:18:57:50:You are a credit to the family.
+H:64:100:18:57:55:You are a well liked child.
+
+H:65:100:20:2:50:You are the adopted child
+
+H:66:100:22:23:50:You are the offspring of a
+
+H:67:30:23:24:20:Forest-Troll
+H:68:60:23:24:25:Cave-Troll
+H:69:75:23:24:30:Hill-Troll
+H:70:90:23:24:35:Stone-Troll
+H:71:95:23:24:40:Snow-Troll
+H:72:100:23:24:45:Water-Troll
+
+H:73:25:24:62:50:Worker.
+H:74:95:24:62:55:Warrior.
+H:75:99:24:62:65:Shaman.
+H:76:100:24:62:80:Clan Chief.
+
+H:77:100:25:26:50:You are one of several children of
+
+H:78:40:26:27:40:a Snaga
+H:79:80:26:27:50:an Orc
+H:80:100:26:27:60:an Uruk
+
+H:81:30:27:28:20:Slave
+H:82:60:27:28:50:Archer
+H:83:90:27:28:60:Warrior
+H:84:95:27:28:80:Shaman
+H:85:100:27:28:100:Chieftain
+
+H:86:30:28:80:50:from the Misty Mountains.
+H:87:60:28:80:50:from the Grey Mountains.
+H:88:90:28:80:70:from the orc-hold of Mount Gundabad.
+H:89:100:28:80:80:from the Pits of Angband.
+
+H:90:25:29:3:50:You are one of five children of a blue Yeek.
+H:91:75:29:3:75:You are one of five children of a brown Yeek.
+H:92:100:29:3:100:You are one of five children of a master Yeek.
+
+H:93:20:50:51:50:You have dark brown eyes,
+H:94:60:50:51:50:You have brown eyes,
+H:95:70:50:51:50:You have hazel eyes,
+H:96:80:50:51:50:You have green eyes,
+H:97:90:50:51:50:You have blue eyes,
+H:98:100:50:51:50:You have blue-gray eyes,
+
+H:99:70:51:52:50:straight
+H:100:90:51:52:50:wavy
+H:101:100:51:52:50:curly
+
+H:102:30:52:53:50:black hair,
+H:103:70:52:53:50:brown hair,
+H:104:80:52:53:50:auburn hair,
+H:105:90:52:53:50:red hair,
+H:106:100:52:53:50:blond hair,
+
+H:107:10:53:0:50:and a very dark complexion.
+H:108:30:53:0:50:and a dark complexion.
+H:109:80:53:0:50:and an average complexion.
+H:110:90:53:0:50:and a fair complexion.
+H:111:100:53:0:50:and a very fair complexion.
+
+H:112:85:54:55:50:You have light grey eyes,
+H:113:95:54:55:50:You have light blue eyes,
+H:114:100:54:55:50:You have light green eyes,
+
+H:115:75:55:56:50:straight
+H:116:100:55:56:50:wavy
+
+H:117:75:56:0:50:black hair, and a fair complexion.
+H:118:85:56:0:50:brown hair, and a fair complexion.
+H:119:95:56:0:50:blond hair, and a fair complexion.
+H:120:100:56:0:50:silver hair, and a fair complexion.
+
+H:121:99:57:58:50:You have dark brown eyes,
+H:122:100:57:58:60:You have glowing red eyes,
+
+H:123:90:58:59:50:straight
+H:124:100:58:59:50:wavy
+
+H:125:75:59:60:50:black hair,
+H:126:100:59:60:50:brown hair,
+
+H:127:25:60:61:50:a one foot beard,
+H:128:60:60:61:51:a two foot beard,
+H:129:90:60:61:53:a three foot beard,
+H:130:100:60:61:55:a four foot beard,
+
+H:131:100:61:0:50:and a dark complexion.
+
+H:132:60:62:63:50:You have slime green eyes,
+H:133:85:62:63:50:You have puke yellow eyes,
+H:134:99:62:63:50:You have blue-bloodshot eyes,
+H:135:100:62:63:55:You have glowing red eyes,
+
+H:136:33:63:64:50:dirty
+H:137:66:63:64:50:mangy
+H:138:100:63:64:50:oily
+
+H:139:33:64:65:50:sea-weed green hair,
+H:140:66:64:65:50:bright red hair,
+H:141:100:64:65:50:dark purple hair,
+
+H:142:25:65:66:50:and green
+H:143:50:65:66:50:and blue
+H:144:75:65:66:50:and white
+H:145:100:65:66:50:and black
+
+H:146:33:66:0:50:ulcerous skin.
+H:147:66:66:0:50:scabby skin.
+H:148:100:66:0:50:leprous skin.
+
+H:149:85:69:70:45:You are one of several children of a Dark Elven
+H:150:100:69:70:55:You are the only child of a Dark Elven
+
+H:151:50:70:71:60:Warrior.
+H:152:80:70:71:75:Warlock.
+H:153:100:70:71:95:Noble.
+
+H:154:100:71:72:50:You have black eyes,
+
+H:155:70:72:73:50:straight
+H:156:90:72:73:50:wavy
+H:157:100:72:73:50:curly
+
+H:158:100:73:0:50:black hair and a very dark complexion.
+
+H:159:25:74:20:25:Your mother was an Ogre, but it is unacknowledged.
+H:160:100:74:20:25:Your father was an Ogre, but it is unacknowledged.
+
+H:161:90:75:76:50:You are a descendant of Beorn to the
+H:162:100:75:20:100:Your father was Beorn.
+
+H:163:13:76:20:55:9th degree.
+H:164:25:76:20:60:8th degree.
+H:165:38:76:20:65:7th degree.
+H:166:50:76:20:70:6th degree.
+H:167:63:76:20:75:5th degree.
+H:168:75:76:20:80:4th degree.
+H:169:88:76:20:85:3rd degree.
+H:170:100:76:20:90:2nd degree.
+
+H:171:100:78:79:50:You are one of several children of
+
+H:172:50:79:80:50:a Brown Yeek.
+H:173:75:79:80:50:a Blue Yeek.
+H:174:95:79:80:85:a Master Yeek.
+H:175:100:79:80:120:Boldor, the King of the Yeeks.
+
+H:176:25:80:81:50:You have pale eyes,
+H:177:50:80:81:50:You have glowing eyes,
+H:178:75:80:81:50:You have tiny black eyes,
+H:179:100:80:81:50:You have shining black eyes,
+
+H:180:20:81:65:50:no hair at all,
+H:181:40:81:65:50:short black hair,
+H:182:60:81:65:50:long black hair,
+H:183:80:81:65:50:bright red hair,
+H:184:100:81:65:50:colourless albino hair,
+
+H:185:100:82:83:50:You are one of several children of
+
+H:186:40:83:80:50:a Small Kobold.
+H:187:75:83:80:55:a Kobold.
+H:188:95:83:80:65:a Large Kobold.
+H:189:100:83:80:100:Mughash, the Kobold Lord.
+
+H:190:85:84:85:45:You are one of several children
+H:191:100:84:85:50:You are the first child
+
+H:192:60:85:50:40:of a Serf.
+H:193:85:85:50:55:of a Devoted Mercenary.
+H:194:96:85:50:60:of a Landed Knight.
+H:195:99:85:50:100:of a Marshal of the Riddermark.
+H:196:100:85:50:120:of a King of the Rohirrim.
+
+H:197:100:87:88:89:You are one of several children of
+
+H:198:30:88:18:20:a Petty-Dwarf Slave.
+H:199:50:88:18:40:a Petty-Dwarf Thief.
+H:200:70:88:18:60:a Petty-Dwarf Smith.
+H:201:90:88:18:75:a Petty-Dwarf Miner.
+H:202:95:88:18:100:a Petty-Dwarf Shaman.
+H:203:100:88:18:100:Mim, Betrayer of Turin.
+
+H:204:85:89:90:50:You are one of many Manwe Maia.
+H:205:100:89:90:60:You are the one of the most famous Manwe Maia.
+
+H:206:90:90:93:100:Your eagle looks very good.
+H:207:100:90:93:120:Your eagle is splendid.
+
+H:208:10:91:92:20:You are a unnoticed minion of
+H:209:25:91:92:30:You are a minor servant of
+H:210:45:91:92:40:You are a subject of
+H:211:65:91:92:50:You have attached yourself to
+H:212:85:91:92:65:You are associated with
+H:213:95:91:92:80:You are a notable follower of
+H:214:100:91:92:100:You are a celebrated assistant to
+
+H:215:20:92:93:55:Nessa.
+H:216:40:92:93:60:Vana.
+H:217:50:92:93:65:Tulkas.
+H:218:80:92:93:75:Mandos.
+H:219:90:92:93:80:Nienna.
+H:220:95:92:93:90:Varda.
+H:221:100:92:93:95:Manwe.
+
+H:222:100:93:94:50:In the past you dwelt on earth in the form of
+
+H:223:25:94:0:50:various animals.
+H:224:55:94:0:55:a spirit of forest and river.
+H:225:70:94:0:60:a beneficent but unseen force.
+H:226:96:94:0:70:a wise and ancient counsellor.
+H:227:100:94:0:80:a Wizard of legend.
+
+H:228:30:95:96:30:You are of an unknown generation of the Ents.
+H:229:40:95:96:50:You are of the third generation of the Ents.
+H:230:60:95:96:60:You are of the second generation of the Ents.
+H:231:100:95:96:80:You are one of the first beings who awoke on Arda.
+
+H:232:50:96:0:50:You have green skin and inflexible members.
+H:233:100:96:0:50:You have brown skin and inflexible members.
+
+H:234:10:100:101:30:You were born in dirty bilge-water,
+H:235:20:100:101:35:You were born in dirty straw,
+H:236:30:100:101:40:You were born in wet mud,
+H:237:40:100:101:45:You were born in a pile of dust,
+H:238:50:100:101:50:You were born in sand,
+H:239:60:100:101:50:You were born in pebbles,
+H:240:70:100:101:55:You were born in a kobold corpse,
+H:241:80:100:101:60:You were born in dragon droppings,
+H:242:90:100:101:65:You were born in a pile of bones,
+H:243:100:100:101:70:You were born in a corpse of a mighty hero,
+
+H:244:10:101:102:30:created by rotting flesh.
+H:245:20:101:102:35:created by a kobold magician.
+H:246:30:101:102:40:created by a corrupted apprentice.
+H:247:40:101:102:45:created by a curious mage apprentice.
+H:248:50:101:102:50:created by an evil Symbiant.
+H:249:60:101:102:50:created by a practicing Necromancer.
+H:250:70:101:102:55:created by the Mutant Breeders.
+H:251:80:101:102:60:created by a curious adventurer.
+H:252:90:101:102:65:called to life by the Witch-King of Angmar.
+H:253:100:101:102:70:called to life by Sauron himself.
+
+H:254:100:102:103:50:Since then you have given life to
+
+H:255:10:103:104:30:no
+H:256:20:103:104:35:one weak-willed
+H:257:30:103:104:40:two
+H:258:40:103:104:45:three
+H:259:50:103:104:50:four
+H:260:60:103:104:50:five
+H:261:70:103:104:55:about twenty
+H:262:80:103:104:60:dozens of
+H:263:90:103:104:65:hundreds of
+H:264:100:103:104:70:uncounted multitudes of
+
+H:265:100:104:0:50:foul offspring.
+
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# M:N:idx:color:Meta class name
+# M:C:class name
+
+I:
+
+M:N:0:U:Classes -- The Classes of Middle-earth
+M:C:Warrior
+M:C:Archer
+M:C:Rogue
+M:C:Mage
+M:C:Priest
+M:C:Loremaster
+#M:C:Test
+#M:C:Chaos-Warrior
+
+#M:N:1:B:Spellcasters -- Magic is The One True Way
+
+#M:N:2:y:Priests -- Hail the powers of the Ainur
+#M:C:Mindcrafter
+
+#M:N:3:G:Beastfriends -- Monsters are fun
+#M:C:BeastMaster
+
+#M:N:4:v:Others -- The way to your independence
+#M:C:Harper
+#M:C:Merchant
+
+#M:N:5:o:Tests -- Test is you dare !
+#M:C:Test
+#M:C:Blade
+#M:C:Black-Knight
diff --git a/lib/edit/qrand1.map b/lib/edit/qrand1.map
new file mode 100644
index 00000000..f42cbf1c
--- /dev/null
+++ b/lib/edit/qrand1.map
@@ -0,0 +1,32 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep lava
+F:F:85:12
+
+# Dungeon layout
+D:
+D: xxxxxxx
+D: xpGF..x
+D: xGGF,.D
+D: xFFF..x
+D: xxxxxxx
+D:
diff --git a/lib/edit/qrand10.map b/lib/edit/qrand10.map
new file mode 100644
index 00000000..ae45b9cb
--- /dev/null
+++ b/lib/edit/qrand10.map
@@ -0,0 +1,36 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:2056:0:0:0:0:*
+
+# Deep lava
+F:F:85:12
+
+# Dungeon layout
+D:
+D: xxxxxxx
+D: xFFFFFx
+D: xxxxxx,t.ttxxxx
+D: xFFG,t....t,,,xxx
+D: xFpG.......t.t.DD
+D: xFFG,t....t,,,xxx
+D: xxxxxx,t.ttxxxx
+D: xFFFFFx
+D: xxxxxxx
+D:
diff --git a/lib/edit/qrand11.map b/lib/edit/qrand11.map
new file mode 100644
index 00000000..4af3c266
--- /dev/null
+++ b/lib/edit/qrand11.map
@@ -0,0 +1,36 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep lava
+F:L:85:6
+
+# Shallow lava
+F:l:86:6
+
+# Dungeon layout
+D: ,llllllll ,
+D:, llLLLLLllll,
+D:llLLLGGGLLLlll,
+D:llLLLGpGLLLLlll
+D:lllLLGGGLLLllll
+D:lllllLLLLlllll,
+D:,lllllllllll,
+D: , ,llllll,
diff --git a/lib/edit/qrand12.map b/lib/edit/qrand12.map
new file mode 100644
index 00000000..4621ef0b
--- /dev/null
+++ b/lib/edit/qrand12.map
@@ -0,0 +1,36 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep water
+F:W:187:6
+
+# Shallow water
+F:w:84:6
+
+# Dungeon wayout
+D: ,wwwwwwww ,
+D:,,wwWWWWWwwww,
+D:wwWWWGGGWWWwww,
+D:wwWWWGpGWWWWwww
+D:wwwWWGGGWWWwwww
+D:wwwwwWWWWwwwww,
+D:,wwwwwwwwwww,
+D: , ,wwwwww,
diff --git a/lib/edit/qrand14.map b/lib/edit/qrand14.map
new file mode 100644
index 00000000..9f339db0
--- /dev/null
+++ b/lib/edit/qrand14.map
@@ -0,0 +1,37 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep water
+F:W:84:6
+
+# Shallow water
+F:w:187:6
+
+# Dungeon wayout
+D:
+D: xxxx xxxx
+D: x,,x x,,x
+D: xxDxxxxxxxDxx
+D: D,,,GpG,,,D
+D: xxDxxxxxxxDxx
+D: x,,x x,,x
+D: xxxx xxxx
+D:
diff --git a/lib/edit/qrand5.map b/lib/edit/qrand5.map
new file mode 100644
index 00000000..cc5d79ee
--- /dev/null
+++ b/lib/edit/qrand5.map
@@ -0,0 +1,27 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Dungeon layout
+D:
+D: xxxx.xxxx
+D: xx.......xx
+D: xxx..,...,..xxx
+D: xx.....GGG.....xx
+D: x......GpG......x
+D: xx..,..GGG..,..xx
+D: xxx....,....xxx
+D: xx.......xx
+D: xxxx.xxxx
+D:
diff --git a/lib/edit/qrand6.map b/lib/edit/qrand6.map
new file mode 100644
index 00000000..3b55e985
--- /dev/null
+++ b/lib/edit/qrand6.map
@@ -0,0 +1,37 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep water
+F:W:84:6
+
+# Shallow water
+F:w:187:6
+
+# Dungeon wayout
+D:
+D: xxxx xxxx
+D: xxxx xxxx
+D: xxxxxxxxxxDxx
+D: D,,,GpG,,,D
+D: xxxxxxxxxxDxx
+D: xxxx xxxx
+D: xxxx xxxx
+D:
diff --git a/lib/edit/qrand7.map b/lib/edit/qrand7.map
new file mode 100644
index 00000000..a7c0607f
--- /dev/null
+++ b/lib/edit/qrand7.map
@@ -0,0 +1,35 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep water
+F:W:84:6
+
+# Shallow water
+F:w:187:6
+
+# Dungeon wayout
+D:ttttt
+D:tGGGt ,x,
+D:tGpGt x,x
+D:tGGGt ,x,
+D:ttttt
+D: ,x,
+D:
diff --git a/lib/edit/r_info.txt b/lib/edit/r_info.txt
new file mode 100644
index 00000000..e7801d09
--- /dev/null
+++ b/lib/edit/r_info.txt
@@ -0,0 +1,18978 @@
+# File: r_info.txt
+# With new monsters for Zangband 2.2 (or 2.3)
+# With new monsters for PernAngband 3.x.x
+# With lots of monsters for PernAngband 4.x.x
+# With Spirits for ToME 2.1.x
+
+# This file is used to initialize the "lib/raw/r_info.raw" file, which is
+# used to initialize the "monster race" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/r_info.raw" file.
+
+# PernAngband notes:
+
+# Currently, "unique" monsters are just "special" monster races, with
+# the requirement that only one monster of that race can exist at a time,
+# and when it is killed, it can never again be generated.
+
+# ATTR_CLEAR monsters acquire their attr from the item/floor below them,
+# and use "white" for the recall window. See "cave.c" for info.
+
+# ATTR_MULTI monsters have a "flickering" attr, and use "violet" for the
+# recall window. See "cave.c" for info.
+
+# CHAR_CLEAR monsters use special symbols (.) as given below,
+# and use those symbols for the recall window. In theory, normally,
+# these monsters cannot be targetted, and when examined look like normal
+# floors, until the player "notices" them (perhaps check "awake").
+
+# CHAR_MULTI monsters use special symbols (!, ?, =) as given below,
+# and use those symbols for the recall window. In theory, normally,
+# these monsters cannot be targetted, and when examined look like normal
+# objects, until the player "notices" them (perhaps check "awake").
+
+# Note that there are (a few) normal monsters who are "violet" but not
+# ATTR_MULTI, and a lot of monsters which are "white" but not ATTR_CLEAR.
+
+# Note that currently both CHAR_CLEAR and CHAR_MULTI monsters are treated
+# as normal monsters that are just a little hard to see.
+
+# Note that the monster list underwent several changes for Angband 2.7.9,
+# including some monster name changes, some symbol redistributions, and
+# some color changes.
+
+# The Umber Hulk joined the Xorn/Xaren (X). The ticks (t) joined the
+# spiders (S). The townspeople (t) left the people (p). The "Jabberwock"
+# became the "Chaos beetle" (K). The major demons (&) became (U) and the
+# minor demons (I) became (u). Multiplying insects (fleas, fruit flies,
+# hummerhorns) became (I), visually "matching" the multiplying lice (l).
+# The "ant lions" (a) became "ants" (a). The mummified monsters (M)
+# joined the zombified monsters (z). The multi-headed hydras (M) left
+# the reptiles (R). The snakes (J) left the reptiles (R).
+
+# Some of the old "red" or "brown" monsters became "pink" if they lower
+# strength, while some of the old "fire" monsters became simply "red"
+# monsters. The "dragons" and "hounds" and related monsters underwent
+# a "color scheme regularization" ('w' = White/Cold, 's' = Black/Acid,
+# 'o' = Lite/Dark, 'r' = Red/Fire, 'g' = Green/Poison, 'b' = Blue/Elec,
+# 'u' = Brown/Earth/Force, 'D' = Dark/etc, 'W' = Stone/Inertia/Gravity/etc,
+# 'v' = Multihued/Chaos/Disenchantment/etc, 'y' = Gold/Sound, 'R' = Nexus,
+# 'G' = Nether, 'B' = Left-overs, and 'U' = Bronze/Confusion).
+
+# In several situations, two or more monsters with identical symbols and
+# colors were changed so that maximal information is conveyed by the symbol
+# and color.
+
+# The "people" (p), with more than 50 entries, got a new "color scheme"
+# ('w' = Paladin, 's' = Knight, 'o' = Mystic, 'r' = Mage, 'g' = High Priest,
+# 'b' = Thief, 'u' = Warrior, 'D' = Death knight, 'W' = Ranger/Archer,
+# 'v' = Sorcerer, 'y' = Ninja, 'R' = High Mage, 'G' = Priest, 'B' = High
+# Thief, 'U' = High Warrior). Note that most non-unique "people" already
+# had these colors, or colors close to these colors. A similar color scheme
+# was enforced for the "humanoid" (h) monsters as well, more or less.
+
+# TY: This is no longer entirely accurate. The monster coloring has been
+# changed 'back' to pre-2.7.* coloring in several cases. For example, I
+# prefer "black" thief characters. Also color can be (and should) be used to
+# convey information, but more importantly it is a visual presentation
+# of the creature and should be what the creature "looks" like.
+
+# Many of the "unique" monsters were changed to "match" the "base" monster
+# from which they were derived. Angband 2.8.0 may require every "unique"
+# monster to be based on a "normal" monster, and may enforce color matching.
+# This may result in the addition of some new monsters, to serve as "base"
+# monsters, possibly including Ogre captains, Greater Balrogs, Black Trolls,
+# Vampire Queens, Giant Werewolves, and others. This may be accompanied by
+# a separation of the monster list into a "normal" monster list (r_info)
+# with 512 entries, and a "unique" monster list (u_info) with 128 entries,
+# which will require reorganization of the list. Some new "player ghost"
+# unique monsters will probably be added at the same time.
+
+# Mushrooms look just like food (and use the "," symbol for both the recall
+# window and for normal display), Creeping coins look just like coins (and
+# use the "$" symbol for both the recall window and for normal display), and
+# Trappers/Lurkers can never be seen (and use the "." symbol for the recall
+# window). All other monsters use "alphabetic" symbols, and "alphabetic"
+# symbols are used only for monsters.
+
+# The "0" and "9" symbols are reserved for internal debugging use.
+
+# The "&" symbol is reserved for future use as a special "terrain feature".
+
+# The "`" symbol is reserved as an "alternate" open door picture, since
+# the "'" symbol looks like the "," symbol in some fonts (esp. IBM).
+
+# The "x" symbol is free for use as an "attr/char mapping" for annoying
+# monsters, such as magic mushrooms, drolems, etc.
+
+# Certain symbols ("X", "Y", "B", "l", "I", etc) are used by
+# very few monsters, and could be reorganized somewhat.
+
+# There are still too many "p" monsters, perhaps they should be broken up.
+
+# As always, you can enforce any "visual picture" you want with a "pref file".
+
+
+###### Understanding the entries ######
+
+# N: serial number : monster name
+# G: symbol : color
+# I: speed : hit points : vision : armor class : alertness
+# W: depth : rarity : corpse weight : experience for kill
+# E: weapons : torso : arms : finger : head : leg
+# O: treasure : combat : magic : tool
+# B: attack method : attack effect : damage
+# F: flag | flag | etc
+# S: spell frequency |
+# S: spell type | spell type | etc
+# D: Description
+
+# 'N' indicates the beginning of an entry. The serial number must
+# increase for each new item. Entry 0 is used for the player.
+
+# 'G' is for graphics - symbol and color. There are 16 colors, as
+# follows:
+
+# D - Dark Gray w - White s - Gray o - Orange
+# r - Red g - Green b - Blue u - Brown
+# d - Black W - Light Gray v - Violet y - Yellow
+# R - Light Red G - Light Green B - Light Blue U - Light Brown
+
+# 'I' is for information - speed, health, vision in tens of feet,
+# armor class, and alertness. 110 is normal speed. Alertness ranges
+# from 0 (ever vigilant for intruders) to 255 (prefers to ignore
+# intruders).
+
+# 'W' is for more information - level, rarity, corpse weight (expressed
+# in deci-pounds) [19 deci-pounds seem to get added to these number
+# in practice], and experience for killing.
+
+# 'E' is for equipment slots - weapon slots, torso slots (the "on body"
+# and "about body" equipment slots), arm slots (expressed in number
+# of pairs), finger slots, head slots, and leg slots (expressed
+# in number of pairs).
+
+# 'O' is for object drop chances - % chance to drop treasure, % chance
+# to drop combat items, % chance to drop magic type items (not
+# items of good blessing), and % chance to drop tools. The four
+# percents added together must be equal to or less than 100. If
+# the percent is less than 100, that is the chance for the monster
+# to drop junk.
+
+# 'B' is for blows - method of attack, effect of attack, and damage
+# from attack. There may be up to four of these lines; effect and
+# damage are optional.
+
+# 'S' is for spells. The first S: line must be S:1_IN_X with X the
+# number of monster turns, on average, before the monster will cast
+# one of its spells. X must not be zero.
+
+# 'F' is for flags. These are fairly self-explanatory. As many F:
+# lines may be used as are needed to specify all the flags and flags
+# are separated by the '|' symbol. The '|' symbol must also be used
+# to end all but the last line.
+
+# 'D' is for description. As many D: lines may be used as are needed
+# to describe the monster. Note that lines may need spaces at their
+# ends to prevent words from running together in the monster memory.
+
+
+# Note that monster zero is used for the "player" picture.
+
+# Version stamp (required)
+
+V:2.2.0
+
+##### The Player #####
+
+N:0:Player
+G:@:w
+E:1:1:1:2:1:1
+O:0:0:0:0
+
+##### Town monsters #####
+
+N:1:Filthy street urchin
+G:t:D
+I:110:1d4:4:1:40
+W:0:2:1200:0
+E:1:1:1:2:1:1
+O:1:1:1:1
+B:BEG:*
+B:TOUCH:EAT_GOLD
+F:MALE | EVIL | WILD_TOWN | WILD_ONLY |
+F:RAND_25 | FRIENDS |
+F:TAKE_ITEM | OPEN_DOOR | DROP_CORPSE | DROP_SKELETON |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He looks squalid and thoroughly revolting.
+
+N:2:Scrawny cat
+G:f:U
+I:110:1d2:30:1:10
+W:0:3:100:0
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d1
+F:RAND_25 | WILD_TOO | WILD_GRASS | WILD_TOWN | WILD_ONLY |
+F:ANIMAL | DROP_CORPSE | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:A skinny little furball with sharp claws and a menacing look.
+
+N:3:Sparrow
+G:B:U
+I:110:1d1:30:1:10
+W:0:3:90:0
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_25 | CAN_FLY | WILD_TOWN | WILD_ONLY |
+F:ANIMAL | DROP_SKELETON | HAS_EGG | IMPRESED |
+F:MORTAL | BASEANGBAND
+D:Utterly harmless, except when angry.
+
+N:4:Chaffinch
+G:B:r
+I:110:1d1:30:1:10
+W:0:3:80:0
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_25 | CAN_FLY | WILD_ONLY | WILD_WOOD | WILD_GRASS |
+F:ANIMAL | DROP_SKELETON | HAS_EGG | IMPRESED |
+F:MORTAL | BASEANGBAND
+D:Utterly harmless, except when angry.
+
+N:5:Wild rabbit
+G:r:U
+I:110:1d2:30:1:10
+W:0:3:100:0
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_50 | WILD_ONLY | WILD_GRASS | WILD_WOOD |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:It is not a carnivore, but will defend itself if you stray too
+D:close.
+
+N:6:Woodsman
+G:t:g
+I:110:3d3:10:1:255
+W:0:1:1000:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d6
+F:MALE | WILD_ONLY | WILD_WOOD |
+F:RAND_25 | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | HAS_LITE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND
+D:He has a strong axe with a sharp edge.
+
+N:7:Scruffy little dog
+G:C:U
+I:110:1d3:20:1:5
+W:0:3:300:0
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_25 | DROP_SKELETON | DROP_CORPSE | WILD_TOWN | WILD_ONLY |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A thin flea-ridden mutt, growling as you get close.
+
+N:8:Farmer Maggot
+G:h:w
+I:110:35d10:40:10:3
+W:0:4:730:0
+E:0:1:1:2:1:1
+O:0:100:0:0
+#B:MOAN:*
+#B:MOAN:*
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:FORCE_MAXHP | WILD_TOWN | WILD_ONLY | NO_TARGET
+F:NEVER_MOVE
+F:OPEN_DOOR | BASH_DOOR | SPECIAL_GENE
+F:NEUTRAL | NO_DEATH
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He's lost his dogs. He's had his mushrooms stolen. He's not a happy
+D:hobbit!
+
+N:9:Blubbering idiot
+G:t:W
+I:110:1d2:6:1:0
+W:0:1:1500:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:DROOL:*
+F:MALE | DROP_CORPSE | DROP_SKELETON | WILD_TOWN | WILD_ONLY |
+F:RAND_25 | DROP_1D2 | TAKE_ITEM |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He tends to blubber a lot.
+
+N:10:Boil-covered wretch
+G:t:g
+I:110:1d2:6:1:0
+W:0:1:1400:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:DROOL:*
+F:MALE | DROP_SKELETON | DROP_CORPSE | WILD_TOWN | WILD_ONLY |
+F:RAND_25 | DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:Ugly doesn't begin to describe him.
+
+N:11:Village idiot
+G:t:G
+I:120:4d4:6:1:0
+W:0:1:1400:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:DROOL:*
+F:MALE | DROP_CORPSE | DROP_SKELETON | WILD_TOWN | WILD_ONLY |
+F:RAND_25 | DROP_1D2 | TAKE_ITEM |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:Drooling and comical, but then, what do you expect?
+
+N:12:Pitiful-looking beggar
+G:t:U
+I:110:1d4:10:1:40
+W:0:1:1300:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BEG:*
+F:MALE | DROP_SKELETON | DROP_CORPSE |
+F:RAND_25 | WILD_TOWN | WILD_ONLY | DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:You just can't help feeling sorry for him.
+
+N:13:Mangy-looking leper
+G:t:u
+I:110:1d1:10:1:50
+W:0:1:1300:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BEG:*
+B:TOUCH:DISEASE
+F:MALE | DROP_CORPSE | DROP_SKELETON |
+F:RAND_25 | WILD_TOWN | WILD_ONLY | DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:You feel it isn't safe to touch him.
+
+N:14:Agent of the black market
+G:t:b
+I:110:2d8:10:8:99
+W:0:1:1200:0
+E:1:1:1:2:1:1
+O:25:50:20:5
+B:HIT:HURT:1d6
+B:TOUCH:EAT_ITEM
+B:INSULT:*
+F:MALE | DROP_CORPSE | DROP_SKELETON |
+F:DROP_60 | WILD_TOWN |
+F:WILD_SWAMP | WILD_WOOD | WILD_GRASS | WILD_MOUNTAIN | WILD_ONLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:He 'finds' new wares for the Black Market. From unwary adventurers...
+
+N:15:Singing, happy drunk
+G:t:y
+I:110:2d3:10:1:0
+W:0:1:1100:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BEG:*
+F:MALE |
+F:RAND_50 | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | WILD_TOWN | WILD_ONLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He makes you glad to be sober.
+
+N:16:Aimless-looking merchant
+G:t:o
+I:110:3d3:10:1:255
+W:0:1:1500:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d3
+F:MALE | RAND_50 |
+F:ONLY_GOLD | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_TOWN | WILD_ONLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:The typical ponce around town, with purse jingling, and looking for more
+D:amulets of adornment to buy.
+
+N:17:Mean-looking mercenary
+G:t:r
+I:110:5d8:10:20:250
+W:0:1:1700:0
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d10
+F:MALE | DROP_SKELETON | DROP_CORPSE |
+F:RAND_50 | DROP_90 | WILD_GRASS | WILD_TOWN | WILD_WOOD | WILD_ONLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:No job is too low for him.
+
+N:18:Battle-scarred veteran
+G:t:B
+I:110:7d8:10:30:250
+W:0:1:1650:0
+E:1:1:1:2:1:1
+O:25:50:25:0
+B:HIT:HURT:2d6
+F:MALE | DROP_SKELETON | DROP_CORPSE |
+F:RAND_50 | DROP_90 | WILD_TOWN | WILD_ONLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He doesn't take to strangers kindly.
+
+N:19:Martti Ihrasaari
+G:P:w
+I:109:35d20:50:15:4
+W:0:4:2794:0
+E:0:1:1:2:1:1
+O:50:50:0:0
+B:SHOW:*
+B:SHOW:*
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | DROP_CORPSE | WILD_TOWN | WILD_ONLY |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:JOKEANGBAND | HAS_LITE
+D:He weighs 127 kg. He is the president of some remote country.
+
+##### Normal monsters #####
+
+N:20:Grey mold
+G:m:s
+I:110:1d2:2:1:0
+W:1:1:20:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:HURT:1d4
+B:SPORE:HURT:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+D:A small strange growth.
+
+N:21:Large white snake
+G:J:w
+I:100:3d6:4:30:99
+W:1:1:600:2
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+B:CRUSH:HURT:1d1
+F:RAND_50 | WILD_TOO |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | HAS_EGG | MORTAL | BASEANGBAND
+D:It is about eight feet long.
+
+N:22:Grey mushroom patch
+G:,:s
+I:110:1d2:2:1:0
+W:1:1:10:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:CONFUSE:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+N:23:Newt
+G:R:y
+I:110:2d6:8:12:30
+W:1:1:10:2
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:BITE:HURT:1d3
+F:WEIRD_MIND | CAN_SWIM | WILD_TOO | DROP_CORPSE |
+F:WILD_GRASS | WILD_WASTE | WILD_SHORE | WILD_SWAMP | WILD_MOUNTAIN |
+F:ANIMAL | HAS_EGG | MORTAL | BASEANGBAND
+D:A small, harmless lizard.
+
+N:24:Giant white centipede
+G:c:w
+I:110:3d5:7:10:40
+W:1:1:500:2
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+B:STING:HURT:1d2
+F:RAND_50 | DROP_SKELETON |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is about four feet long and carnivorous.
+
+N:25:White icky thing
+G:i:w
+I:110:2d5:12:7:10
+W:1:1:500:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:HURT:1d2
+F:RAND_50 | RAND_25 | CAN_SWIM |
+F:EMPTY_MIND | DROP_CORPSE | BASEANGBAND
+D:It is a smallish, slimy, icky creature.
+
+N:26:Clear icky thing
+G:i:B
+I:110:2d5:12:6:10
+W:1:1:500:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:HURT:1d2
+F:ATTR_CLEAR | CAN_SWIM |
+F:RAND_50 | RAND_25 |
+F:INVISIBLE | EMPTY_MIND | DROP_CORPSE | BASEANGBAND
+D:It is a smallish, slimy, icky, blobby creature.
+
+N:27:Giant white mouse
+G:r:w
+I:110:1d3:8:4:20
+W:1:1:600:1
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | WILD_TOO | WILD_GRASS |
+F:CAN_SWIM |
+F:ANIMAL | DROP_CORPSE |
+F:MORTAL | BASEANGBAND |
+S:MULTIPLY
+D:It is about three feet long with large teeth.
+
+N:28:Large brown snake
+G:J:u
+I:100:4d6:4:35:99
+W:1:1:800:3
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:CRUSH:HURT:1d4
+F:RAND_25 | CAN_SWIM |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | HAS_EGG | MORTAL | BASEANGBAND
+D:It is about eight feet long.
+
+N:29:Small kobold
+G:k:y
+I:110:2d7:20:16:10
+W:1:1:800:5
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d5
+F:DROP_60 | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a small, dog-headed humanoid figure.
+
+N:30:Kobold
+G:k:G
+I:110:3d7:20:16:10
+W:2:1:900:5
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d8
+F:DROP_60 | WILD_TOO |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a squat and ugly dog-headed humanoid.
+
+N:31:White worm mass
+G:w:w
+I:100:4d4:7:1:10
+W:1:1:30:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:POISON:1d2
+F:RAND_50 | RAND_25 | CAN_SWIM |
+F:STUPID | WEIRD_MIND |
+F:ANIMAL | IM_POIS | HURT_LITE | NO_FEAR
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:32:Floating eye
+G:e:o
+I:110:3d6:2:6:10
+W:1:1:500:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:PARALYZE
+F:NEVER_MOVE | CAN_FLY | DROP_CORPSE |
+F:HURT_LITE | NO_FEAR | BASEANGBAND
+D:A disembodied eye, floating a few feet above the ground.
+
+N:33:Rock lizard
+G:R:U
+I:110:3d4:20:4:15
+W:1:1:100:2
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:ANIMAL | CAN_SWIM | WILD_TOO | WILD_MOUNTAIN |
+F:DROP_CORPSE | HAS_EGG |
+F:MORTAL | BASEANGBAND
+D:It is a small lizard with a hardened hide.
+
+N:34:Grid bug
+G:I:v
+I:110:2d4:10:2:10
+W:1:1:10:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:ELEC:1d4
+F:RAND_25 | FRIENDS | CAN_FLY |
+F:STUPID | WEIRD_MIND |
+F:ANIMAL | NO_FEAR | IM_ELEC | ZANGBAND
+D:A strange electric bug.
+
+N:35:Jackal
+G:C:U
+I:110:1d4:10:3:10
+W:1:1:400:1
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:FRIENDS |
+F:WILD_TOO | WILD_WOOD | WILD_GRASS | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is a yapping snarling dog, dangerous when in a pack.
+
+N:36:Soldier ant
+G:a:u
+I:110:2d5:10:3:10
+W:1:1:300:3
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:WEIRD_MIND | BASH_DOOR | DROP_SKELETON |
+F:ANIMAL | WILD_TOO | WILD_GRASS |
+F:MORTAL | BASEANGBAND
+D:A large ant with powerful mandibles.
+
+N:37:Fruit bat
+G:b:o
+I:120:1d6:20:3:10
+W:1:1:20:1
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:ANIMAL | CAN_FLY | WILD_TOO | WILD_WOOD | WILD_SWAMP | DROP_CORPSE
+F:MORTAL | BASEANGBAND | AI_ANNOY
+D:A fast-moving pest.
+
+N:38:Insect swarm
+G:I:u
+I:120:1d5:20:4:10
+W:1:1:100:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+B:STING:HURT:1d1
+F:ANIMAL | WEIRD_MIND | CAN_FLY | RAND_25 | WILD_TOO | WILD_GRASS |
+F:WILD_WOOD | WILD_SWAMP |
+F:MORTAL | SUSCEP_FIRE | BASEANGBAND | NO_CUT
+D:A lone insect may be harmless, but there's a whole swarm of
+D:them here!
+
+N:39:The Greater hell-beast
+G:U:s
+I:120:15d100:10:1:99
+W:1:16:2000:2500
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:*
+B:GAZE:*
+B:CRUSH:*
+F:EVIL | IM_ACID | IM_ELEC | IM_FIRE | IM_POIS | IM_COLD | UNIQUE |
+F:RES_NETH | RES_WATE | RES_PLAS | RES_DISE | RES_NEXU | NO_SLEEP | NO_CONF
+F:KILL_WALL | FORCE_MAXHP | CAN_SWIM | DROP_CORPSE | JOKEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:TPORT | BLINK | TELE_AWAY
+D:This unholy abomination will crush you. Flee while you can!
+
+N:40:Shrieker mushroom patch
+G:,:R
+I:110:1d1:4:1:0
+W:2:1:40:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | NEVER_MOVE | NEVER_BLOW |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | WILD_TOO | WILD_SWAMP | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:SHRIEK
+D:Yum! It looks quite tasty. It doesn't sound so nice, though...
+
+N:41:Blubbering icky thing
+G:i:W
+I:110:5d6:14:4:10
+W:2:1:400:8
+E:0:0:0:0:0:0
+O:20:20:20:20
+B:CRAWL:POISON:1d4
+B:CRAWL:EAT_FOOD
+B:DROOL:*
+B:DROOL:*
+F:RAND_50 | DROP_90 | CAN_SWIM | DROP_CORPSE |
+F:EMPTY_MIND | TAKE_ITEM | KILL_BODY |
+F:IM_POIS | BASEANGBAND
+D:It is a smallish, slimy, icky, hungry creature.
+
+N:42:Metallic green centipede
+G:c:g
+I:120:4d4:5:4:10
+W:3:1:500:5
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CRAWL:HURT:1d2
+F:RAND_50 | WILD_TOO | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is about four feet long and carnivorous.
+
+N:43:Novice warrior
+G:p:u
+I:110:9d4:20:16:5
+W:2:1:1600:6
+E:1:1:1:2:1:1
+O:25:50:0:20
+B:HIT:HURT:1d7
+B:HIT:HURT:1d6
+F:MALE |
+F:DROP_60 | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He looks inexperienced but tough.
+
+N:44:Novice rogue
+G:p:b
+I:110:8d4:20:12:5
+W:2:1:1400:6
+E:1:1:1:2:1:1
+O:50:25:0:20
+B:HIT:HURT:1d6
+B:TOUCH:EAT_GOLD
+F:MALE |
+F:DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_TOO |
+F:EVIL | MORTAL | BASEANGBAND
+D:A rather shifty individual.
+
+N:45:Novice priest
+G:p:g
+I:110:7d4:20:10:10
+W:2:1:1500:6
+E:1:1:1:2:1:1
+O:25:0:50:20
+B:HIT:HURT:1d5
+F:MALE |
+F:FORCE_SLEEP | GOOD | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:HEAL | SCARE | CAUSE_1
+D:He is tripping over his priestly robes.
+
+N:46:Novice mage
+G:p:r
+I:110:6d4:20:6:5
+W:2:1:1400:6
+E:1:1:1:2:1:1
+O:25:0:70:0
+B:HIT:HURT:1d4
+F:MALE |
+F:FORCE_SLEEP | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:BLINK | BLIND | CONF | MISSILE
+D:He is leaving behind a trail of dropped spell components.
+
+N:47:Yellow mushroom patch
+G:,:y
+I:110:1d1:2:1:0
+W:2:1:30:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:TERRIFY:1d6
+F:NEVER_MOVE | WILD_TOO | WILD_SWAMP |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+N:48:White jelly
+G:j:w
+I:120:8d8:2:1:99
+W:2:1:2000:10
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:POISON:1d2
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It's a large pile of white flesh.
+
+N:49:Giant black ant
+G:a:D
+I:110:3d6:8:20:80
+W:2:1:500:8
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+F:RAND_25 |
+F:WEIRD_MIND | DROP_SKELETON |
+F:BASH_DOOR | WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is about three feet long.
+
+N:50:Salamander
+G:R:o
+I:110:4d6:8:20:80
+W:2:1:100:10
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:1d3
+F:RAND_25 | CAN_SWIM | WILD_TOO | WILD_VOLCANO | DROP_CORPSE |
+F:ANIMAL | IM_FIRE | SUSCEP_COLD |
+F:MORTAL | BASEANGBAND
+D:A small black and orange lizard.
+
+N:51:White harpy
+G:H:w
+I:110:2d5:16:17:10
+W:2:1:500:5
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d1
+B:CLAW:HURT:1d1
+B:BITE:HURT:1d2
+F:FEMALE | CAN_FLY | WILD_TOO | WILD_MOUNTAIN |
+F:RAND_50 | DROP_CORPSE | ANIMAL | EVIL | MORTAL | BASEANGBAND
+D:A flying, screeching bird with a woman's face.
+
+N:52:Blue yeek
+G:y:b
+I:110:2d6:18:14:10
+W:2:1:700:4
+E:1:1:1:2:1:1
+O:25:0:0:55
+B:HIT:HURT:1d5
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | IM_ACID |
+F:MORTAL | BASEANGBAND
+D:A small humanoid figure.
+
+N:53:Grip, Farmer Maggot's dog
+G:C:w
+I:120:7d5:30:30:0
+W:2:2:600:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:UNIQUE | SPECIAL_GENE
+F:FORCE_MAXHP | RAND_25 | DROP_CORPSE
+F:BASH_DOOR | ANIMAL
+F:MORTAL | BASEANGBAND
+D:A rather vicious dog belonging to Farmer Maggot. It thinks you are
+D:stealing mushrooms.
+
+N:54:Wolf, Farmer Maggot's dog
+G:C:w
+I:120:7d5:30:30:0
+W:2:2:650:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:UNIQUE | SPECIAL_GENE
+F:FORCE_MAXHP | RAND_25 | DROP_CORPSE
+F:BASH_DOOR
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A rather vicious dog belonging to Farmer Maggot. It thinks you are
+D:stealing mushrooms.
+
+N:55:Fang, Farmer Maggot's dog
+G:C:w
+I:120:7d5:30:30:0
+W:2:2:700:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:UNIQUE | SPECIAL_GENE
+F:FORCE_MAXHP | RAND_25 | DROP_CORPSE
+F:BASH_DOOR
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A rather vicious dog belonging to Farmer Maggot. It thinks you are
+D:stealing mushrooms.
+
+N:56:Giant green frog
+G:R:g
+I:110:2d8:12:8:30
+W:2:1:200:6
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+F:RAND_25 | WILD_ONLY | WILD_SHORE | WILD_SWAMP | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is as big as a wolf.
+
+N:57:Freesia
+G:f:u
+I:120:6d5:30:30:0
+W:2:1:450:32
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d4
+F:UNIQUE |
+F:FORCE_MAXHP | DROP_SKELETON
+F:BASH_DOOR |
+F:ANIMAL
+F:MORTAL | ZANGBAND
+D:A striped housecat who enjoys hunting.
+
+N:58:Green worm mass
+G:w:g
+I:100:6d4:7:3:10
+W:2:1:40:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:ACID:1d3
+F:RAND_50 | RAND_25 |
+F:STUPID | WEIRD_MIND |
+F:ANIMAL | IM_ACID | CAN_SWIM |
+F:HURT_LITE | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:59:Large yellow snake
+G:J:y
+I:100:4d8:5:38:75
+W:2:1:1000:9
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:CRUSH:HURT:1d6
+F:RAND_25 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE
+F:BASH_DOOR | HAS_EGG | ANIMAL | MORTAL | BASEANGBAND
+D:It is about ten feet long.
+
+N:60:Cave spider
+G:S:D
+I:120:2d6:8:16:80
+W:2:1:400:7
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+F:FRIENDS |
+F:WEIRD_MIND | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | SPIDER | HURT_LITE |
+F:MORTAL | BASEANGBAND
+D:It is a black spider that moves in fits and starts.
+
+N:61:Crow
+G:B:s
+I:120:3d5:40:12:0
+W:2:2:300:8
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:BITE:HURT:1d3
+F:ANIMAL | WILD_TOO | WILD_WOOD | CAN_FLY | DROP_CORPSE
+F:MORTAL | HAS_EGG | BASEANGBAND
+D:It is a hooded crow, gray except for the black wings and head.
+
+N:62:Wild cat
+G:f:U
+I:120:3d5:40:12:0
+W:2:2:200:8
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+F:BASH_DOOR | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A larger than normal feline, hissing loudly. Its velvet claws conceal a
+D:fistful of needles.
+
+N:63:Smeagol
+G:h:B
+I:130:20d20:20:12:5
+W:3:2:670:16
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:TOUCH:EAT_GOLD
+F:UNIQUE | MALE | CAN_SWIM | DROP_SKELETON | DROP_CORPSE | DROP_CHOSEN |
+F:FORCE_MAXHP | CAN_SPEAK | SMART |
+F:RAND_50 | RAND_25 | WILD_TOO |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD | DROP_GREAT |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | INVISIBLE
+F:EVIL | BASEANGBAND
+D:Usually known as Gollum. He's been sneaking, and he wants his 'precious.'
+
+N:64:Green ooze
+G:j:g
+I:120:3d4:8:16:80
+W:3:2:300:4
+E:0:0:0:0:0:0
+O:50:0:25:20
+B:CRAWL:ACID:1d3
+F:RAND_50 | RAND_25 | DROP_90 |
+F:STUPID | EMPTY_MIND |
+F:IM_ACID | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It's green and it's oozing.
+
+N:65:Poltergeist
+G:G:s
+I:130:2d5:8:15:10
+W:3:1:0:8
+E:0:0:0:0:0:0
+O:50:5:30:10
+B:TOUCH:TERRIFY
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:DROP_60 | DROP_90 |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | TAKE_ITEM |
+F:EVIL | UNDEAD |
+F:IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLINK
+D:It is a ghastly, ghostly form.
+
+N:66:Yellow jelly
+G:j:y
+I:120:10d8:2:1:99
+W:3:1:2000:12
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:POISON:1d3
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:DRAIN_MANA
+D:It's a large pile of yellow flesh.
+
+N:67:Metallic blue centipede
+G:c:b
+I:120:4d5:6:6:15
+W:4:1:770:6
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CRAWL:HURT:1d3
+F:RAND_50 | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is about four feet long and carnivorous.
+
+N:68:Raven
+G:B:D
+I:120:4d5:40:12:0
+W:4:2:500:8
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:BITE:HURT:1d4
+F:ANIMAL | WILD_TOO | WILD_WOOD | CAN_FLY | DROP_CORPSE
+F:MORTAL | HAS_EGG | BASEANGBAND
+D:Larger than a crow, and pitch black.
+
+N:69:Giant white louse
+G:I:w
+I:120:1d1:6:5:10
+W:3:1:100:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:WEIRD_MIND | ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is six inches long.
+
+N:70:Giant yellow centipede
+G:c:y
+I:110:3d6:8:12:30
+W:2:1:500:3
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:STING:HURT:1d3
+F:RAND_50 | DROP_SKELETON |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is about four feet long and carnivorous.
+
+N:71:Black naga
+G:n:D
+I:110:6d8:16:40:120
+W:3:1:1700:20
+E:0:0:0:0:1:0
+O:0:75:20:5
+B:CRUSH:HURT:1d8
+F:FEMALE |
+F:RAND_25 | DROP_60 | DROP_CORPSE |
+F:BASH_DOOR | CAN_SWIM |
+F:EVIL | MORTAL | BASEANGBAND
+D:A large black serpent's body with a female torso.
+
+N:72:Spotted mushroom patch
+G:,:o
+I:110:1d1:2:1:0
+W:3:1:30:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:2d4
+F:NEVER_MOVE | WILD_TOO | WILD_SWAMP |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+N:73:Silver jelly
+G:j:W
+I:120:10d8:2:1:99
+W:3:2:2000:12
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EAT_LITE:1d3
+B:TOUCH:EAT_LITE:1d3
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:DRAIN_MANA
+D:It is a large pile of silver flesh that sucks all light from its
+D:surroundings.
+
+N:74:Scruffy-looking hobbit
+G:h:s
+I:110:3d5:16:8:10
+W:3:1:1000:4
+E:1:1:1:2:1:1
+O:0:50:0:40
+B:HIT:HURT:1d4
+B:TOUCH:EAT_GOLD
+F:MALE |
+F:DROP_60 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL
+F:MORTAL | BASEANGBAND
+D:A short little guy, in bedraggled clothes. He appears to be looking
+D:for a good tavern.
+
+N:75:Giant white ant
+G:a:w
+I:110:3d6:8:16:80
+W:3:1:800:7
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_GRASS |
+F:ANIMAL | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:It is about two feet long and has sharp pincers.
+
+N:76:Yellow mold
+G:m:y
+I:110:8d8:2:10:99
+W:3:1:30:9
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:HURT:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange growth on the dungeon floor.
+
+N:77:Metallic red centipede
+G:c:r
+I:120:4d8:8:9:20
+W:5:1:800:10
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CRAWL:HURT:2d3
+F:RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_SKELETON
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is about four feet long and carnivorous.
+
+N:78:Yellow worm mass
+G:w:y
+I:100:4d8:7:4:10
+W:3:2:200:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:LOSE_DEX:1d3
+F:RAND_50 | RAND_25 | CAN_SWIM |
+F:STUPID | WEIRD_MIND |
+F:ANIMAL | HURT_LITE | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:79:Clear worm mass
+G:w:B
+I:100:4d4:7:1:10
+W:3:2:200:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:POISON:1d2
+F:ATTR_CLEAR | CAN_SWIM |
+F:RAND_50 | RAND_25 |
+F:STUPID | WEIRD_MIND | INVISIBLE |
+F:ANIMAL |
+F:IM_POIS | HURT_LITE | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a disgusting mass of poisonous worms.
+
+N:80:Radiation eye
+G:e:R
+I:110:3d6:2:6:10
+W:3:1:500:6
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:LOSE_STR:1d6
+F:NEVER_MOVE | CAN_FLY | DROP_CORPSE |
+F:HURT_LITE | NO_FEAR | BASEANGBAND | HAS_LITE
+S:1_IN_11 |
+S:DRAIN_MANA
+D:A disembodied eye, crackling with energy.
+
+N:81:Yellow light
+G:*:y
+I:120:2d6:8:12:30
+W:4:1:0:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:BLIND
+F:EMPTY_MIND | CAN_FLY | NONLIVING | SUSCEP_ELEC |
+F:BASEANGBAND | HAS_LITE | RAND_50 | RAND_25 | NO_CUT
+D:A fast-moving bright light, apparently totally random in its movement.
+
+N:82:Cave lizard
+G:R:u
+I:110:3d6:8:16:80
+W:4:1:100:8
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d5
+F:ANIMAL | CAN_SWIM | DROP_CORPSE | HAS_EGG |
+F:MORTAL | BASEANGBAND
+D:It is an armoured lizard with a powerful bite.
+
+N:83:Novice ranger
+G:p:W
+I:110:6d8:20:8:5
+W:4:1:1400:18
+E:1:1:1:2:1:1
+O:25:45:25:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+F:MALE |
+F:FORCE_SLEEP | DROP_SKELETON | DROP_CORPSE
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_WOOD |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:ARROW_2 | MISSILE
+D:An agile hunter, ready and relaxed.
+
+N:84:Blue jelly
+G:j:b
+I:110:12d8:2:1:99
+W:4:1:2000:14
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:COLD:1d6
+F:NEVER_MOVE | COLD_BLOOD |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:IM_COLD | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | SUSCEP_FIRE | BASEANGBAND | NO_CUT
+D:It's a large pile of pulsing blue flesh.
+
+N:85:Creeping copper coins
+G:$:u
+I:100:7d8:3:24:10
+W:4:3:0:9
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d4
+B:TOUCH:POISON:2d4
+F:ONLY_GOLD | DROP_1D2 | SUSCEP_ACID |
+F:COLD_BLOOD | BASH_DOOR |
+F:IM_ELEC | IM_POIS | CHAR_MULTI |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of copper coins, until it starts crawling towards you
+D:on tiny legs.
+
+N:86:Giant white rat
+G:r:W
+I:110:2d2:8:7:30
+W:4:1:200:1
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d3
+F:RAND_25 |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is a very vicious rodent.
+
+N:87:Snotling
+G:o:U
+I:110:5d5:20:32:30
+W:4:1:900:15
+E:1:1:1:2:1:1
+O:25:50:0:20
+B:HIT:HURT:1d6
+F:MALE |
+F:FRIENDS | DROP_60 | RAND_50 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_WOOD |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:Immature Orclings, running wild and screaming all the time.
+
+N:88:Swordfish
+G:~:W
+I:120:4d7:14:10:20
+W:4:2:800:15
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+F:ANIMAL | AQUATIC | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A fish with a swordlike "beak".
+
+N:89:Blue worm mass
+G:w:b
+I:100:5d8:7:12:10
+W:4:1:40:5
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:COLD:1d4
+F:RAND_50 | RAND_25 |
+F:STUPID | WEIRD_MIND | COLD_BLOOD |
+F:ANIMAL | IM_COLD | CAN_SWIM |
+F:HURT_LITE | NO_FEAR |
+F:MORTAL | SUSCEP_FIRE | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:90:Large grey snake
+G:J:s
+I:100:6d8:6:41:50
+W:4:1:1300:14
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d5
+B:CRUSH:HURT:1d8
+F:RAND_25 | CAN_SWIM | DROP_SKELETON | DROP_CORPSE | WILD_TOO |
+F:BASH_DOOR | HAS_EGG | ANIMAL | MORTAL | BASEANGBAND
+D:It is about ten feet long.
+
+N:91:Skeleton kobold
+G:s:W
+I:110:5d8:20:26:40
+W:5:1:800:12
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d6
+F:COLD_BLOOD | EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a small animated kobold skeleton.
+
+N:92:Ewok
+G:h:G
+I:120:3d5:10:10:10
+W:9:2:700:20
+E:1:1:1:2:1:1
+O:50:0:50:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:DROP_60 | OPEN_DOOR | BASH_DOOR | FRIENDS | DROP_CORPSE |
+F:WILD_TOO | WILD_WOOD |
+F:MORTAL | JOKEANGBAND
+S:1_IN_8
+S:ARROW_1
+D:A cute little bear, full of merchandising potential.
+
+N:93:Novice mage
+G:p:r
+I:110:6d4:20:6:10
+W:6:2:1400:6
+E:1:1:1:2:1:1
+O:25:0:70:0
+B:HIT:HURT:1d4
+F:MALE |
+F:FORCE_SLEEP |
+F:FRIENDS | DROP_60 | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:BLINK | BLIND | CONF | MISSILE
+D:He is leaving behind a trail of dropped spell components.
+
+N:94:Green naga
+G:n:g
+I:110:9d8:18:40:120
+W:5:1:1700:30
+E:0:0:0:0:1:0
+O:0:25:0:65
+B:CRUSH:HURT:1d8
+B:SPIT:ACID:2d6
+F:FEMALE |
+F:RAND_25 | TAKE_ITEM | DROP_60 | DROP_CORPSE |
+F:BASH_DOOR | CAN_SWIM | WILD_TOO | WILD_SHORE |
+F:EVIL | IM_ACID | MORTAL | BASEANGBAND
+D:A large green serpent with a female torso. Her green skin glistens with
+D:acid.
+
+N:95:Giant leech
+G:w:u
+I:120:6d8:10:20:50
+W:5:1:30:20
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:3d1
+B:BITE:HURT:3d1
+F:ANIMAL | AQUATIC | WEIRD_MIND | RAND_25 | BASEANGBAND
+D:Yech! The disgusting thing only wants your blood!
+
+N:96:Barracuda
+G:~:G
+I:120:6d8:20:45:20
+W:5:2:150:30
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d10
+B:BITE:HURT:1d10
+F:AQUATIC | ANIMAL | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A predatory fish with razor-sharp teeth.
+
+N:97:Novice paladin
+G:p:w
+I:110:6d8:20:16:5
+W:4:1:1700:18
+E:1:1:1:2:1:1
+O:0:70:25:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+F:MALE | GOOD | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:SCARE | CAUSE_1
+D:An adventurer both devoutly religious and skilful in combat.
+D:He seems to consider you an agent of the devil.
+
+N:98:Zog
+G:h:b
+I:110:13d9:20:20:20
+W:5:1:600:25
+E:0:1:0:2:1:0
+O:50:0:25:20
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+B:DROOL:*
+F:EVIL | OPEN_DOOR | BASH_DOOR | DROP_90 | DROP_SKELETON |
+F:MORTAL | ZANGBAND
+D:Drooling, insectoid aliens with disgusting habits.
+
+N:99:Blue ooze
+G:j:b
+I:110:3d4:8:16:80
+W:5:1:300:7
+E:0:0:0:0:0:0
+O:45:20:20:0
+B:CRAWL:COLD:1d4
+F:RAND_50 | RAND_25 | DROP_60 |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:IM_COLD | SUSCEP_FIRE
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It's blue and it's oozing.
+
+N:100:Green glutton ghost
+G:G:g
+I:130:3d4:10:20:10
+W:5:1:0:15
+E:0:0:0:0:0:0
+O:30:30:30:5
+B:TOUCH:EAT_FOOD:1d1
+F:RAND_50 | RAND_25 |
+F:DROP_60 | DROP_90 | CAN_FLY |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It is a very ugly green ghost with a voracious appetite.
+
+N:101:Green jelly
+G:j:g
+I:120:22d8:2:1:99
+W:5:1:2500:18
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ACID:1d2
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:IM_ACID | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a large pile of pulsing green flesh.
+
+N:102:Large kobold
+G:k:b
+I:110:13d9:20:32:30
+W:5:1:1000:25
+E:1:1:1:2:1:1
+O:0:90:0:5
+B:HIT:HURT:1d10
+F:DROP_90 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It a man-sized figure with the all too recognisable face of a kobold.
+
+N:103:Grey icky thing
+G:i:s
+I:110:4d8:14:12:15
+W:5:1:500:10
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:HURT:1d5
+F:RAND_50 | CAN_SWIM | DROP_CORPSE |
+F:EMPTY_MIND | BASEANGBAND
+D:It is a smallish, slimy, icky, nasty creature.
+
+N:104:Disenchanter eye
+G:e:v
+I:100:7d8:2:10:10
+W:5:2:500:20
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:UN_BONUS
+F:ATTR_MULTI | ATTR_ANY | RES_DISE | DROP_CORPSE |
+F:NEVER_MOVE | CAN_FLY |
+F:HURT_LITE | NO_FEAR | BASEANGBAND
+S:1_IN_9 |
+S:DRAIN_MANA
+D:A disembodied eye, crackling with magic.
+
+N:105:Red worm mass
+G:w:r
+I:100:5d8:7:12:10
+W:5:1:40:6
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:FIRE:1d6
+F:RAND_50 | RAND_25 | SUSCEP_COLD |
+F:STUPID | EMPTY_MIND | BASH_DOOR |
+F:ANIMAL | IM_FIRE | CAN_SWIM |
+F:HURT_LITE | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:106:Copperhead snake
+G:J:o
+I:110:4d6:6:20:1
+W:5:1:200:15
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:POISON:2d4
+F:RAND_50 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE | BASH_DOOR |
+F:ANIMAL | IM_POIS | HAS_EGG | MORTAL | BASEANGBAND
+D:It has a copper head and sharp venomous fangs.
+
+N:107:Death sword
+G:|:W
+I:130:6d6:20:40:0
+W:6:5:0:30
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:NEVER_MOVE | NONLIVING | NO_FEAR | SUSCEP_ACID |
+F:STUPID | EMPTY_MIND | COLD_BLOOD | CHAR_MULTI | NO_CONF | NO_SLEEP |
+F:DROP_90 | EVIL | IM_COLD | IM_FIRE | FORCE_MAXHP | IM_ELEC | IM_POIS |
+F:BASEANGBAND | HAS_LITE | NO_CUT
+D:A bloodthirsty blade lurking for prey. Beware!
+
+N:108:Purple mushroom patch
+G:,:v
+I:110:1d1:2:1:0
+W:6:2:40:15
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:LOSE_CON:1d2
+B:SPORE:LOSE_CON:1d2
+B:SPORE:LOSE_CON:1d2
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yuk! It doesn't look so tasty.
+
+N:109:Novice priest
+G:p:g
+I:110:7d4:20:10:5
+W:6:2:1500:6
+E:1:1:1:2:1:1
+O:20:50:20:5
+B:HIT:HURT:1d5
+F:MALE | GOOD |
+F:FORCE_SLEEP | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:HEAL | SCARE | CAUSE_1
+D:He is tripping over his priestly robes.
+
+N:110:Novice warrior
+G:p:u
+I:110:9d4:20:16:5
+W:6:2:1600:6
+E:1:1:1:2:1:1
+O:0:95:0:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d6
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He looks inexperienced but tough.
+
+N:111:Nibelung
+G:h:D
+I:110:8d4:20:12:5
+W:6:1:900:6
+E:1:1:1:2:1:1
+O:90:0:0:5
+B:HIT:HURT:1d6
+B:TOUCH:EAT_GOLD
+F:MALE |
+F:FRIENDS | DROP_60 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | HURT_LITE | RES_DISE | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | ZANGBAND | HAS_LITE
+D:Night dwarfs collecting riches.
+
+N:112:The disembodied hand that strangled people
+G:z:g
+I:130:7d8:30:15:20
+W:6:2:300:20
+E:0:0:0:1:0:0
+O:0:0:0:0
+B:CRUSH:HURT:1d8
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_POIS | CAN_FLY | UNIQUE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | ZANGBAND | NO_CUT
+D:Even today, nobody knows where it lurks...
+
+N:113:Brown mold
+G:m:u
+I:110:15d8:2:12:99
+W:6:1:50:20
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:CONFUSE:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A strange brown growth on the dungeon floor.
+
+N:114:Giant brown bat
+G:b:u
+I:130:3d8:10:15:30
+W:6:1:600:10
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+F:RAND_50 | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:ANIMAL | DROP_CORPSE | AI_ANNOY
+F:MORTAL | BASEANGBAND
+D:It screeches as it attacks.
+
+N:115:Rat-thing
+G:r:R
+I:120:9d9:12:20:20
+W:6:1:1000:10
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d2
+B:BITE:HURT:3d1
+B:BITE:HURT:3d2
+F:EVIL | ANIMAL | DROP_CORPSE |
+F:MORTAL | ZANGBAND
+S:1_IN_9
+S:SCARE | CONF
+D:A ratlike creature with a humanlike face.
+
+N:116:Novice rogue
+G:p:b
+I:110:8d4:20:12:5
+W:6:2:1400:6
+E:1:1:1:2:1:1
+O:50:25:0:20
+B:HIT:HURT:1d6
+B:TOUCH:EAT_GOLD
+F:MALE | FRIENDS |
+F:DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_TOO |
+F:EVIL | MORTAL | BASEANGBAND
+D:A rather shifty individual.
+
+N:117:Creeping silver coins
+G:$:s
+I:100:12d8:4:30:10
+W:6:3:0:18
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:TOUCH:POISON:2d6
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:COLD_BLOOD | BASH_DOOR | SUSCEP_ACID | CHAR_MULTI |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of silver coins, until it starts crawling towards you
+D:on tiny legs.
+
+N:118:Snaga
+G:o:U
+I:110:8d8:20:32:30
+W:6:1:1600:15
+E:1:1:1:2:1:1
+O:20:50:5:15
+B:HIT:HURT:1d8
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is one of the many weaker 'slave' orcs, often mistakenly known as a
+D:goblin.
+
+N:119:Rattlesnake
+G:J:r
+I:110:6d7:6:24:1
+W:6:1:200:20
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:POISON:2d5
+F:RAND_50 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR | HAS_EGG | ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+D:It is recognised by the hard-scaled end of its body that is often rattled
+D:to frighten its prey.
+
+N:120:Giant slug
+G:w:U
+I:100:12d9:10:25:25
+W:6:1:600:25
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:ACID:2d4
+B:BITE:ACID:2d6
+F:ANIMAL | EMPTY_MIND | KILL_ITEM | KILL_BODY | CAN_SWIM | WILD_TOO |
+F:DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10
+S:BR_ACID
+D:It is slowly making its way towards you, eating everything in
+D:its path...
+
+N:121:Giant pink frog
+G:R:r
+I:110:5d8:12:16:50
+W:7:1:200:16
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:LOSE_STR:2d4
+F:RAND_50 | WILD_ONLY | WILD_SHORE | WILD_SWAMP |
+F:BASH_DOOR | DROP_CORPSE
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It looks poisonous.
+
+N:122:Dark elf
+G:h:D
+I:110:7d10:20:16:20
+W:7:2:1200:25
+E:1:1:1:2:1:1
+O:20:20:50:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:MALE |
+F:FORCE_SLEEP |
+F:DROP_90 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:CONF | DARKNESS | MISSILE
+D:An elven figure with jet black skin and white hair, his eyes are large and
+D:twisted with evil.
+
+N:123:Zombified kobold
+G:z:s
+I:110:6d8:20:14:30
+W:7:1:750:14
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d2
+B:HIT:HURT:1d2
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is an animated kobold corpse. Flesh falls off in large chunks as it
+D:shambles forward.
+
+N:124:Crypt creep
+G:s:D
+I:110:6d8:20:12:14
+W:7:2:0:25
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:1d2
+B:CLAW:HURT:1d2
+B:BITE:POISON
+F:RAND_25
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | FRIENDS |
+F:EVIL | UNDEAD | IM_POIS | IM_COLD |
+F:NO_CONF | NO_SLEEP | HURT_LITE | BASEANGBAND | NO_CUT
+S:1_IN_10
+S:CAUSE_1 | S_UNDEAD
+D:A frightening skeletal figure in a black robe.
+
+N:125:Rotting corpse
+G:z:R
+I:110:8d8:20:20:20
+W:8:1:0:15
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:POISON:1d3
+B:CLAW:POISON:1d3
+F:OPEN_DOOR | BASH_DOOR | FRIENDS |
+F:NO_CONF | NO_SLEEP | UNDEAD | EVIL | NO_FEAR | IM_POIS |
+F:IM_COLD | COLD_BLOOD | EMPTY_MIND | BASEANGBAND | NO_CUT
+D:Corpses awakened from their sleep by dark sorcery.
+
+N:126:Cave orc
+G:o:G
+I:110:11d9:20:32:30
+W:7:1:1900:20
+E:1:1:1:2:1:1
+O:20:70:0:0
+B:HIT:HURT:1d8
+F:MALE |
+F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is often found in huge numbers in deep caves.
+
+N:127:Wood spider
+G:S:U
+I:120:3d6:8:16:80
+W:7:3:600:15
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:STING:POISON:1d4
+F:FRIENDS | DROP_SKELETON |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_WOOD |
+F:ANIMAL | SPIDER | IM_POIS |
+F:MORTAL | BASEANGBAND
+D:It scuttles towards you.
+
+N:128:Manes
+G:u:r
+I:110:8d8:20:32:30
+W:7:2:300:16
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+F:FRIENDS |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | BASEANGBAND
+D:It is a minor but aggressive demon.
+
+N:129:Bloodshot eye
+G:e:r
+I:110:10d8:2:6:10
+W:7:3:550:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:BLIND:2d6
+F:NEVER_MOVE | CAN_FLY | DROP_CORPSE |
+F:HURT_LITE | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:DRAIN_MANA
+D:A disembodied eye, bloodshot and nasty.
+
+N:130:Red naga
+G:n:r
+I:110:11d8:20:40:120
+W:7:2:1800:40
+E:0:0:0:0:1:0
+O:50:0:50:0
+B:CRUSH:HURT:1d10
+B:BITE:LOSE_STR:1d4
+F:FEMALE | CAN_SWIM | WILD_TOO | WILD_SHORE |
+F:RAND_25 | DROP_60 |
+F:TAKE_ITEM | BASH_DOOR | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND
+D:A large red snake with a woman's torso.
+
+N:131:Red jelly
+G:j:r
+I:110:26d8:2:1:99
+W:7:1:2500:26
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:LOSE_STR:1d5
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:HURT_LITE | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a large pulsating mound of red flesh.
+
+N:132:Green icky thing
+G:i:g
+I:110:5d8:14:12:20
+W:7:2:500:18
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ACID:2d5
+F:RAND_50 | CAN_SWIM | DROP_CORPSE |
+F:EMPTY_MIND |
+F:IM_ACID | BASEANGBAND
+D:It is a smallish, slimy, icky, acidic creature.
+
+N:133:Lost soul
+G:G:W
+I:110:2d8:12:10:10
+W:7:2:0:18
+E:0:0:0:0:0:0
+O:60:0:25:0
+B:HIT:HURT:2d2
+B:TOUCH:LOSE_WIS
+F:RAND_50 | DROP_60 | DROP_90 | CAN_FLY |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD |
+F:IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:TPORT | DRAIN_MANA
+D:It is almost insubstantial.
+
+N:134:Night lizard
+G:R:b
+I:110:4d8:20:16:30
+W:7:2:400:35
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+B:BITE:HURT:1d6
+F:ANIMAL | CAN_SWIM | WILD_TOO | DROP_CORPSE
+F:MORTAL | HAS_EGG | BASEANGBAND
+D:It is a black lizard with overlapping scales and a powerful jaw.
+
+N:135:Mughash, the Kobold Lord
+G:k:v
+I:110:17d10:20:20:20
+W:7:3:1100:100
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+F:UNIQUE | MALE | CAN_SPEAK
+F:FORCE_MAXHP |
+F:ESCORT | ESCORTS | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:Strong and powerful, for a kobold.
+
+N:136:Skeleton orc
+G:s:W
+I:110:10d8:20:36:40
+W:8:1:1700:26
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:2d5
+F:COLD_BLOOD | EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is an animated orc skeleton.
+
+N:137:Wormtongue, Agent of Saruman
+G:p:B
+I:110:28d10:20:30:20
+W:9:2:1500:150
+E:1:1:1:2:1:1
+O:10:50:35:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+B:TOUCH:EAT_GOLD
+B:INSULT:*
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_GREAT |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON |
+F:EVIL | RES_TELE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:HEAL | SLOW | TRAPS | BO_COLD | BA_POIS
+D:He's been spying for Saruman. He is a snivelling wretch with no morals.
+
+N:138:Robin Hood, the Outlaw
+G:p:G
+I:120:16d12:20:30:20
+W:10:2:1600:150
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+B:TOUCH:EAT_GOLD
+B:TOUCH:EAT_ITEM
+F:UNIQUE | MALE | FORCE_SLEEP | FORCE_MAXHP | CAN_SPEAK |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_GREAT | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | EVIL | DROP_SKELETON | DROP_CORPSE
+F:MORTAL | ZANGBAND | HAS_LITE
+S:1_IN_5
+S:ARROW_2 | HEAL | TRAPS
+D:The legendary archer steals from the rich (you qualify).
+
+N:139:Nurgling
+G:u:o
+I:110:9d8:20:32:30
+W:8:2:800:19
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BITE:DISEASE:1d8
+F:FRIENDS | FRIEND |
+F:OPEN_DOOR | BASH_DOOR | IM_POIS |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | ZANGBAND
+D:It is a minor demon servitor of Nurgle. It looks like a hairless
+D:teddy bear, with twisted eyes and rotting, ghoulish skin.
+
+N:140:Lagduf, the Snaga
+G:o:y
+I:110:22d10:20:32:30
+W:8:2:1700:80
+E:1:1:1:2:1:1
+O:10:80:0:0
+B:HIT:HURT:1d11
+B:HIT:HURT:1d11
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+F:UNIQUE | MALE | EVIL | ORC | FORCE_MAXHP | ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | SPECIAL_GENE |
+F:OPEN_DOOR | BASH_DOOR | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A captain of a regiment of weaker orcs, Lagduf keeps his troop in order
+D:with displays of excessive violence.
+
+N:141:Brown yeek
+G:y:u
+I:110:4d8:18:18:10
+W:8:1:800:11
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID |
+F:MORTAL | BASEANGBAND
+D:It is a strange small humanoid.
+
+N:142:Novice ranger
+G:p:W
+I:110:6d8:20:8:5
+W:8:2:1500:18
+E:1:1:1:2:1:1
+O:0:80:0:15
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+F:MALE |
+F:FORCE_SLEEP | FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:ARROW_2 | MISSILE
+D:An agile hunter, ready and relaxed.
+
+N:143:Giant salamander
+G:R:R
+I:110:6d7:6:40:1
+W:8:1:600:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:3d6
+F:FORCE_SLEEP | SUSCEP_COLD |
+F:RAND_25 |
+F:ANIMAL | IM_FIRE | CAN_SWIM | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_9
+S:BR_FIRE
+D:A large black and yellow lizard. You'd better run away!
+
+N:144:Space monster
+G:.:d
+I:110:21d8:30:14:20
+W:8:2:0:28
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:TERRIFY:1d4
+F:PASS_WALL | NO_CONF | NO_SLEEP | NONLIVING | IM_ACID | CAN_FLY | JOKEANGBAND | NO_CUT
+D:A black hole in the fabric of reality.
+
+N:145:Carnivorous flying monkey
+G:H:R
+I:110:20d8:30:20:20
+W:8:2:800:30
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:5d1
+F:ANIMAL | CAN_FLY | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN |
+F:DROP_CORPSE | MORTAL | ZANGBAND | HAS_LITE
+D:It looks fantastic, yet frightening.
+
+N:146:Green mold
+G:m:g
+I:110:21d8:2:14:75
+W:8:1:40:28
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:TERRIFY:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_ACID | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange growth on the dungeon floor.
+
+N:147:Novice paladin
+G:p:w
+I:110:6d8:20:16:5
+W:8:2:1500:18
+E:1:1:1:2:1:1
+O:30:55:10:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+F:MALE | GOOD | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:SCARE | CAUSE_1
+D:He thinks you are an agent of the devil.
+
+N:148:Lemure
+G:u:U
+I:110:13d9:20:32:30
+W:8:3:1000:16
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:HIT:HURT:1d8
+F:FRIENDS |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | BASEANGBAND
+D:It is the larval form of a major demon.
+
+N:149:Hill orc
+G:o:u
+I:110:13d9:20:32:30
+W:8:1:2000:25
+E:1:1:1:2:1:1
+O:10:70:10:0
+B:HIT:HURT:1d10
+F:MALE |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is a hardy well-weathered survivor.
+
+N:150:Bandit
+G:p:b
+I:110:8d8:20:24:10
+W:10:2:1500:26
+E:1:1:1:2:1:1
+O:25:60:0:0
+B:HIT:HURT:2d4
+B:TOUCH:EAT_GOLD
+F:MALE |
+F:DROP_1D2 | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:He is after your possessions!
+
+N:151:Hunting hawk
+G:B:u
+I:120:8d8:30:25:10
+W:8:2:800:22
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d4
+F:ANIMAL | NO_FEAR | CAN_FLY | WILD_WOOD | WILD_TOO | DROP_CORPSE
+F:MORTAL | HAS_EGG | BASEANGBAND
+D:Trained to hunt and kill without fear.
+
+N:152:Phantom warrior
+G:G:B
+I:110:5d5:20:10:40
+W:8:1:0:15
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d11
+B:HIT:HURT:1d11
+F:PASS_WALL | NO_SLEEP | FRIENDS | COLD_BLOOD | NONLIVING |
+F:NO_FEAR | EMPTY_MIND | CAN_FLY | BASEANGBAND | NO_CUT
+D:Spectral creatures that are half real, half illusion.
+
+N:153:Gremlin
+G:u:u
+I:110:5d5:30:30:20
+W:8:3:500:6
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:EAT_FOOD:1d2
+B:CLAW:EAT_FOOD:1d2
+B:BITE:EAT_FOOD:1d3
+F:IM_POIS | HURT_LITE | EVIL | DEMON | OPEN_DOOR |
+F:TAKE_ITEM | CAN_SWIM |
+F:MORTAL | ZANGBAND
+S:MULTIPLY
+D:Don't feed them after midnight!
+
+N:154:Yeti
+G:Y:w
+I:110:11d9:20:24:10
+W:9:3:3500:30
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d4
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN | DROP_CORPSE |
+F:ANIMAL | IM_COLD |
+F:MORTAL | SUSCEP_FIRE | BASEANGBAND
+D:A large white figure covered in shaggy fur.
+
+N:155:Bloodshot icky thing
+G:i:r
+I:110:7d8:14:18:20
+W:9:3:60:24
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:HURT:1d4
+B:CRAWL:ACID:2d4
+F:RAND_50 |
+F:EMPTY_MIND | CAN_SWIM | DROP_CORPSE |
+F:IM_POIS | BASEANGBAND
+S:1_IN_11 |
+S:DRAIN_MANA
+D:It is a strange, slimy, icky creature.
+
+N:156:Giant grey rat
+G:r:s
+I:110:2d3:8:12:20
+W:9:1:250:2
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d4
+F:RAND_25 |
+F:ANIMAL | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is a rodent of unusual size.
+
+N:157:Black harpy
+G:H:D
+I:120:3d8:16:22:10
+W:9:1:600:19
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d2
+B:CLAW:HURT:1d2
+B:BITE:HURT:1d3
+F:FEMALE | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | DROP_CORPSE |
+F:RAND_25 | ANIMAL | EVIL | MORTAL | BASEANGBAND
+D:A woman's face on the body of a vicious black bird.
+
+N:158:Skaven
+G:r:G
+I:110:11d8:15:25:20
+W:9:1:600:20
+E:1:1:1:2:1:1
+O:35:35:20:0
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+F:EVIL | FRIENDS | DROP_60 | DROP_90 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | MALE | WILD_TOO | WILD_WASTE | WILD_SWAMP |
+F:MORTAL | ZANGBAND
+D:A mutated rat-creature from the great waste, it is vaguely
+D:humanoid in appearance and walks on its hind legs. This race
+D:serves chaos fervently and is greatly feared by others.
+
+N:159:The wounded bear
+G:q:r
+I:110:11d10:10:35:10
+W:12:1:3000:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d10
+B:CLAW:HURT:1d10
+B:BITE:HURT:1d11
+F:BASH_DOOR | FORCE_MAXHP | FORCE_SLEEP | UNIQUE | DROP_CORPSE |
+F:ANIMAL | WILD_ONLY | WILD_WOOD | WILD_GRASS | WILD_MOUNTAIN |
+F:MORTAL | BASEANGBAND
+D:A wounded bear, who has occasionally attacked humans.
+
+N:160:Cave bear
+G:q:u
+I:110:8d8:10:35:10
+W:9:1:3000:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d6
+B:CLAW:HURT:1d6
+B:BITE:HURT:1d8
+F:BASH_DOOR | FORCE_MAXHP | FORCE_SLEEP | DROP_CORPSE |
+F:ANIMAL | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN |
+F:MORTAL | BASEANGBAND
+D:A large bear appears to have made its home in this cave. It is hungry,
+D:and you are trespassing in its territory.
+
+N:161:Rock mole
+G:r:s
+I:110:10d10:20:30:75
+W:9:2:60:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d10
+B:BITE:HURT:1d10
+F:WEIRD_MIND | BASH_DOOR | KILL_WALL | KILL_ITEM | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:Despite its unimpressive size, this mole creature has fangs powerful
+D:enough to bore through solid rock.
+
+N:162:Mindcrafter
+G:p:y
+I:110:9d8:20:15:20
+W:16:2:1700:50
+E:1:1:1:2:1:1
+O:30:40:30:0
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:MALE |
+F:FORCE_SLEEP | DROP_90 | WILD_TOO |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:CONF | BLIND | HOLD | SLOW | MIND_BLAST | S_MONSTER | BLINK
+D:A master of the mental arts, able to damage or dominate the
+D:minds of others.
+
+N:163:Baby blue dragon
+G:d:b
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 | HAS_EGG | IMPRESED |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_ELEC | BASEANGBAND | ATTR_MULTI | ATTR_MULTI
+S:1_IN_12 |
+S:BR_ELEC
+D:This hatchling dragon is still soft, its eyes unaccustomed to light and
+D:its scales a pale blue.
+
+N:164:Baby white dragon
+G:d:w
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | ATTR_MULTI
+F:EVIL | DRAGON | IM_COLD | SUSCEP_FIRE | HAS_EGG | IMPRESED | BASEANGBAND
+F:ATTR_MULTI
+S:1_IN_12 |
+S:BR_COLD
+D:This hatchling dragon is still soft, its eyes unaccustomed to light and
+D:its scales a pale white.
+
+N:165:Baby green dragon
+G:d:g
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY | DROP_CORPSE |
+F:EVIL | DRAGON | IM_POIS | HAS_EGG | IMPRESED | BASEANGBAND | ATTR_MULTI
+S:1_IN_12 |
+S:BR_POIS
+D:This hatchling dragon is still soft, its eyes unaccustomed to light and
+D:its scales a sickly green.
+
+N:166:Baby black dragon
+G:d:s
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID | HAS_EGG | IMPRESED | BASEANGBAND | ATTR_MULTI
+S:1_IN_12 |
+S:BR_ACID
+D:This hatchling dragon is still soft, its eyes unaccustomed to light and
+D:its scales a dull black.
+
+N:167:Baby red dragon
+G:d:r
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE | SUSCEP_COLD |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_FIRE | HAS_EGG | IMPRESED | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_11 |
+S:BR_FIRE
+D:This hatchling dragon is still soft, its eyes unaccustomed to light and
+D:its scales a pale red.
+
+N:168:Giant red ant
+G:a:r
+I:110:4d8:12:34:60
+W:9:2:600:22
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:STING:LOSE_STR:1d4
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_SKELETON
+F:ANIMAL | MORTAL | BASEANGBAND | HAS_LITE
+D:It is large and has venomous mandibles.
+
+N:169:Brodda, the Easterling
+G:p:U
+I:110:24d10:20:25:20
+W:9:2:2200:100
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:1d13
+B:HIT:HURT:1d13
+B:HIT:HURT:1d13
+B:HIT:HURT:1d13
+F:UNIQUE | MALE | EVIL
+F:FORCE_MAXHP | CAN_SPEAK | WILD_TOO | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A nasty piece of work, Brodda picks on defenceless women and children.
+
+N:170:Bloodfang, the Wolf
+G:C:R
+I:120:8d6:30:30:20
+W:9:1:1600:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d12
+B:BITE:HURT:1d12
+F:BASH_DOOR | WILD_ONLY | WILD_GRASS | WILD_WOOD | DROP_CORPSE |
+F:ANIMAL | UNIQUE | FORCE_MAXHP |
+F:MORTAL | BASEANGBAND
+D:It has been terrorising the nearby villages.
+
+N:171:King cobra
+G:J:g
+I:110:8d10:8:30:1
+W:9:2:300:28
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:SPIT:BLIND:1d2
+B:BITE:POISON:3d4
+F:RAND_50 | WILD_TOO | WILD_SWAMP | WILD_WOOD | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR | CAN_SWIM | ANIMAL | IM_POIS | HAS_EGG | MORTAL | BASEANGBAND
+D:It is a large snake with a hooded face.
+
+N:172:Eagle
+G:B:u
+I:120:9d9:30:25:10
+W:12:2:600:22
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d6
+F:ANIMAL | CAN_FLY | WILD_ONLY | WILD_WASTE | WILD_MOUNTAIN | WILD_WOOD |
+F:DROP_CORPSE | MORTAL | BASEANGBAND | HAS_EGG
+D:A magnificent huge predatory bird.
+
+N:173:War bear
+G:q:u
+I:110:10d10:10:35:10
+W:9:1:2000:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:HURT:1d6
+F:WEIRD_MIND | BASH_DOOR | FRIENDS | DROP_SKELETON | DROP_CORPSE
+F:ANIMAL
+F:MORTAL | BASEANGBAND
+D:Bears with tusks, trained to kill.
+
+N:174:Killer bee
+G:I:y
+I:120:2d4:12:34:10
+W:9:2:50:22
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:STING:POISON:1d4
+B:STING:LOSE_STR:1d4
+F:WEIRD_MIND | FRIENDS | CAN_FLY | WILD_TOO |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is poisonous and aggressive.
+
+N:175:Giant spider
+G:S:v
+I:110:10d10:8:16:80
+W:10:2:700:35
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d10
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+B:BITE:HURT:1d10
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_SKELETON |
+F:ANIMAL | SPIDER | IM_POIS |
+F:MORTAL | BASEANGBAND
+D:It is a vast spider whose bulbous body is bloated with poison.
+
+N:176:Giant white tick
+G:S:w
+I:100:12d8:12:40:20
+W:10:2:200:27
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:2d6
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY |
+F:ANIMAL | IM_POIS |
+F:MORTAL | BASEANGBAND
+D:It is moving slowly towards you.
+
+N:177:The Borshin
+G:g:w
+I:110:12d20:40:30:0
+W:10:2:600:45
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:2d12
+B:CRUSH:HURT:2d15
+B:TOUCH:TERRIFY
+F:BASH_DOOR | UNIQUE | FORCE_MAXHP | NO_CONF
+F:IM_POIS | IM_COLD | NO_FEAR
+F:MORTAL | CTHANGBAND | NO_CUT
+D:Pallid and twisted, this creature hates the very sight of you.
+D:"It looked like something that had started out to be a man but had never
+D:quite made it. It had been stepped on, twisted, had holes poked into the
+D:sickly dough of its head-bulge. Bones showed through the transparent flesh
+D:of its torso and its short legs were as thick as trees, terminating in
+D:disk-shaped pads from which dozens of long toes hung like roots or worms.
+D:its arms were longer than its entire body. it was a crushed slug, a thing
+D:that had been frozen and thawed before it was fully baked. It was -
+D:'It is the Borshin', said the Lord of Bats."
+
+N:178:Dark elven mage
+G:h:r
+I:120:7d10:20:16:20
+W:10:1:1200:50
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_POIS | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BLIND | CONF | MISSILE | DARKNESS | BA_POIS
+D:A dark elven figure, dressed all in black, hurling spells at you.
+
+N:179:Kamikaze yeek
+G:y:r
+I:113:4d8:18:18:10
+W:10:1:800:10
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:EXPLODE:HURT:15d2
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID |
+F:MORTAL | ZANGBAND
+D:The evil wizard Bruce has trained them to be living weapons.
+
+N:180:Orfax, Son of Boldor
+G:y:B
+I:120:14d10:18:20:10
+W:11:3:600:80
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d9
+B:INSULT:*
+B:INSULT:*
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | EVIL | IM_ACID |
+F:MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:HEAL | BLINK | TELE_TO | SLOW | CONF |
+S:S_MONSTER
+D:He's just like his daddy! He knows mighty spells, but fortunately he is a
+D:yeek.
+
+N:181:Servant of Glaaki
+G:z:G
+I:110:9d9:20:20:20
+W:10:1:600:25
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:1d8
+B:CLAW:DISEASE:1d3
+F:OPEN_DOOR | BASH_DOOR | FRIENDS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | UNDEAD | EVIL | NO_FEAR | IM_POIS |
+F:IM_COLD | COLD_BLOOD | CTHANGBAND | NO_CUT
+S:1_IN_12
+S:CAUSE_1 | SCARE
+D:"...the hand of a corpse -- bloodless and skeletal, and with
+D:impossibly long, cracked nails."
+
+N:182:Dark elven warrior
+G:h:u
+I:110:10d11:20:16:20
+W:10:1:1400:50
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:MALE |
+F:DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_12
+S:MISSILE
+D:A dark elven figure in armour, ready with his sword.
+
+N:183:Sand-dweller
+G:u:y
+I:110:9d9:20:20:20
+W:10:1:600:30
+E:1:1:1:2:1:1
+O:20:50:20:5
+B:CLAW:HURT:1d6
+B:CLAW:HURT:1d6
+F:FRIENDS | WILD_TOO | WILD_WASTE | DROP_SKELETON |
+F:OPEN_DOOR | BASH_DOOR | HURT_LITE | EVIL | DROP_60 | DROP_90 |
+F:MALE
+F:MORTAL | CTHANGBAND
+D:"Rough-skinned, large-eyed, large-eared, with a horrible,
+D:distorted resemblance to the koala bear facially, though
+D:his body had an appearance of emaciation."
+
+N:184:Clear mushroom patch
+G:,:B
+I:120:1d1:4:1:0
+W:10:2:30:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:HURT:1d1
+F:ATTR_CLEAR |
+F:NEVER_MOVE | INVISIBLE | COLD_BLOOD |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:Yum! It smells quite tasty. If you could only see it...
+
+N:185:Quiver slot
+G:,:U
+I:120:1d1:4:1:0
+W:10:2:60:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:CONFUSE:1d1
+F:NEVER_MOVE | COLD_BLOOD |
+F:STUPID | EMPTY_MIND |
+F:NO_CONF | NO_SLEEP | NO_FEAR | JOKEANGBAND | NO_CUT
+S:MULTIPLY |
+S:1_IN_5 | ARROW_1
+D:What looks like the remains of a quiver dropped by a past adventurer
+D:has become overgrown with a strange mold intent on using the contents
+D:of the quiver to grab prey.
+
+N:186:Grishnakh, the Hill Orc
+G:o:y
+I:110:25d10:20:20:20
+W:10:3:2300:160
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d13
+B:HIT:HURT:1d11
+B:HIT:HURT:1d13
+B:HIT:HURT:1d11
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | SPECIAL_GENE |
+F:ESCORT | WILD_TOO |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is a cunning and devious orc with a chaotic nature.
+
+N:187:Giant tan bat
+G:b:U
+I:130:3d8:12:20:50
+W:10:2:600:18
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:TERRIFY:1d3
+B:CLAW:HURT:1d2
+B:CLAW:HURT:1d2
+F:RAND_50 | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:FORCE_SLEEP | ANIMAL | DROP_CORPSE | AI_ANNOY |
+F:MORTAL | BASEANGBAND
+D:A giant bat, the beating of whose wings produces a strangely unnerving noise.
+
+N:188:Owlbear
+G:H:o
+I:110:12d12:20:20:20
+W:10:1:2000:35
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:CRUSH:HURT:1d10
+F:EVIL | ANIMAL | OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A bizarre bear-creature with the claws and the face of an owl.
+
+N:189:Blue horror
+G:u:B
+I:110:14d9:20:35:20
+W:10:3:1200:25
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:TERRIFY:1d8
+B:CLAW:TERRIFY:1d8
+F:FRIENDS |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | NO_CONF | ZANGBAND
+D:An ugly screaming little demon servant of Tzeentch.
+
+N:190:Hairy mold
+G:m:o
+I:110:15d8:2:15:70
+W:10:1:50:32
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:1d3
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange hairy growth on the dungeon floor.
+
+N:191:Grizzly bear
+G:q:U
+I:110:15d15:10:35:10
+W:16:2:2600:55
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:1d12
+B:CRUSH:HURT:1d10
+F:WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:ANIMAL | BASH_DOOR |
+F:MORTAL | BASEANGBAND
+D:A huge, beastly bear, more savage than most of its kind.
+
+N:192:Disenchanter mold
+G:m:v
+I:110:16d8:2:20:70
+W:10:1:40:40
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:UN_BONUS:1d6
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND | RES_DISE |
+F:IM_POIS | ATTR_MULTI | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_11 |
+S:DRAIN_MANA
+D:It is a strange glowing growth on the dungeon floor.
+
+N:193:Pseudo dragon
+G:d:o
+I:110:20d10:20:30:40
+W:10:2:10000:150
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE |
+F:DROP_60 | BASH_DOOR | HAS_EGG |
+F:EVIL | DRAGON | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_11 |
+S:CONF | SCARE | BR_LITE | BR_DARK
+D:A small relative of the dragon that inhabits dark caves.
+
+N:194:Tengu
+G:u:b
+I:120:16d9:20:32:30
+W:10:1:600:40
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | RES_TELE | CAN_FLY | BASEANGBAND
+S:1_IN_3 |
+S:BLINK | TELE_TO | TELE_AWAY | TPORT
+D:It is a fast-moving demon that blinks quickly in and out of existence; no
+D:other demon matches its teleporting mastery.
+
+N:195:Creeping gold coins
+G:$:y
+I:100:18d8:5:36:10
+W:10:3:0:32
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d5
+B:TOUCH:POISON:3d5
+F:ONLY_GOLD | DROP_90 | DROP_1D2 |
+F:COLD_BLOOD | BASH_DOOR |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of gold coins, until it starts crawling towards you
+D:on tiny legs.
+
+N:196:Wolf
+G:C:u
+I:120:6d6:30:30:20
+W:10:1:600:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:RAND_25 | FRIENDS |
+F:BASH_DOOR | WILD_TOO | WILD_WOOD | WILD_WASTE | WILD_MOUNTAIN |
+F:ANIMAL | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:It howls and snaps at you.
+
+N:197:Giant fruit fly
+G:I:G
+I:120:2d2:8:14:10
+W:10:3:100:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | RAND_25 | CAN_FLY | WEIRD_MIND |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:A fast-breeding, annoying pest.
+
+N:198:Panther
+G:f:D
+I:120:10d8:40:30:0
+W:10:2:1300:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+F:BASH_DOOR | WILD_TOO | WILD_WOOD | WILD_GRASS | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A large black cat, stalking you with intent. It thinks you're its next
+D:meal.
+
+N:199:Brigand
+G:p:b
+I:110:9d8:20:32:10
+W:10:2:1700:35
+E:1:1:1:2:1:1
+O:25:60:0:0
+B:HIT:HURT:2d4
+B:TOUCH:EAT_ITEM
+F:MALE |
+F:DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | DROP_SKELETON |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is eyeing your backpack.
+
+N:200:Hobbes the Tiger
+G:f:y
+I:120:12d10:40:30:0
+W:10:2:1600:45
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d12
+B:CLAW:HURT:1d12
+B:BITE:HURT:1d5
+F:BASH_DOOR | UNIQUE | FORCE_MAXHP |
+F:ANIMAL | MALE | CAN_SPEAK | DROP_CORPSE |
+F:MORTAL | JOKEANGBAND
+D:Fast-moving, with a taste for tuna sandwiches.
+
+N:201:Shadow Creature of Fiona
+G:h:s
+I:110:11d8:12:12:16
+W:10:2:1000:35
+E:1:1:1:2:1:1
+O:20:30:50:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:BASH_DOOR | OPEN_DOOR | FRIENDS | DROP_60 | IM_POIS | NO_SLEEP | NO_CONF
+F:MALE | DROP_SKELETON | ZANGBAND
+D:"There was something unusual about their appearance... For one thing,
+D:all had uniformly bloodshot eyes. Very, very bloodshot eyes. With them,
+D:though, the condition seemed normal. For another, all had an extra joint
+D:to each finger and thumb, and sharp, forward-curving spurs on the backs
+D:of their hands. All of them had prominent jaws and forty-four teeth,
+D:most of them longer than human teeth, and several looking to be much
+D:sharper. Their flesh was grayish and hard and shiny. There were
+D:undoubtedly other differences also, but those were sufficient to prove
+D:a point of some sort."
+
+N:202:Undead mass
+G:j:u
+I:110:8d8:70:12:5
+W:10:2:200:33
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:DISEASE:1d6
+B:TOUCH:LOSE_CON:1d6
+F:UNDEAD | EMPTY_MIND | NO_CONF | NO_SLEEP | IM_POIS | IM_COLD | NO_FEAR |
+F:HURT_LITE | COLD_BLOOD | EVIL | NEVER_MOVE | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:A sickening mound of decaying flesh, bones, hands and so on. It seems to
+D:be growing.
+
+N:203:Chaos shapechanger
+G:H:v
+I:110:20d9:10:14:12
+W:11:2:0:38
+E:1:1:1:2:1:1
+O:20:50:20:6
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+B:HIT:CONFUSE:1d3
+F:DROP_60 | EVIL | SHAPECHANGER | ATTR_MULTI | ATTR_ANY
+F:MORTAL | ZANGBAND
+S:1_IN_5
+S:BO_FIRE | BO_COLD | CONF
+D:A vaguely humanoid form constantly changing its appearance.
+
+N:204:Baby multi-hued dragon
+G:d:v
+I:110:13d10:20:30:70
+W:11:2:5000:45
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:HURT:1d6
+F:ATTR_MULTI |
+F:FORCE_MAXHP | FORCE_SLEEP |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | DRAGON | CAN_FLY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | HAS_EGG | IMPRESED |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS
+D:This hatchling dragon is still soft, its eyes unaccustomed to light and
+D:its scales shimmering with a hint of colour.
+
+N:205:Vorpal bunny
+G:r:w
+I:120:10d10:40:40:0
+W:11:3:600:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:6d1
+B:BITE:HURT:7d1
+F:BASH_DOOR | WILD_TOO | WILD_MOUNTAIN | DROP_CORPSE |
+F:ANIMAL | MORTAL | ZANGBAND
+S:1_IN_8
+S:BLINK
+D:It looks very cute, except for the razor sharp teeth. It moans
+D:ominously as it jumps at your throat!
+
+N:206:Old Man Willow
+G:#:s
+I:110:32d30:20:20:20
+W:25:5:3000:150
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:TOUCH:PARALYZE:1d14
+B:TOUCH:PARALYZE:1d14
+B:CRUSH:HURT:2d12
+F:ANIMAL | NEVER_MOVE | COLD_BLOOD | DROP_RANDART
+F:EMPTY_MIND | UNIQUE | FORCE_MAXHP | FORCE_SLEEP |
+F:RES_WATE | IM_POIS | IM_ACID | SUSCEP_FIRE | SPECIAL_GENE |
+F:DROP_1D2 | DROP_GOOD | ONLY_ITEM | BASEANGBAND | NO_CUT
+S:1_IN_10 |
+S:TELE_TO | HOLD |
+D:The ancient grey willow tree, ruler of the Old Forest. He despises
+D:trespassers in his territory. "...a huge willow-tree, old and hoary.
+D:Enormous it looked, its sprawling branches going up like racing arms
+D:with may long-fingered hands, its knotted and twisted trunk gaping in
+D:wide fissures that creaked faintly as the boughs moved."
+
+N:207:Hippocampus
+G:H:B
+I:110:20d9:12:14:10
+W:11:1:900:30
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:2d5
+B:BITE:HURT:2d5
+F:AQUATIC | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A truly strange hybrid of a horse and a fish.
+
+N:208:Zombified orc
+G:z:s
+I:110:11d8:20:24:25
+W:11:1:1800:30
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+F:COLD_BLOOD | EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a shambling orcish corpse leaving behind a trail of flesh.
+
+N:209:Hippogryph
+G:H:U
+I:110:20d9:12:14:10
+W:11:1:1500:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:HIT:HURT:2d5
+B:BITE:HURT:2d5
+F:BASH_DOOR | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_GRASS |
+F:ANIMAL | DROP_CORPSE | MORTAL | BASEANGBAND
+D:A strange hybrid of eagle and horse. It looks weird.
+
+N:210:Black mamba
+G:J:D
+I:120:10d8:10:32:1
+W:12:3:300:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:POISON:4d4
+F:RAND_50 | BASH_DOOR | CAN_SWIM |
+F:WILD_TOO | WILD_WOOD | WILD_GRASS | WILD_SWAMP |
+F:ANIMAL | IM_POIS | DROP_SKELETON | DROP_CORPSE | HAS_EGG |
+F:MORTAL | BASEANGBAND
+D:It has glistening black skin, a sleek body, and highly venomous fangs.
+
+N:211:White wolf
+G:C:w
+I:120:7d7:30:30:20
+W:12:1:700:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:BITE:HURT:1d4
+F:RAND_25 |
+F:FRIENDS | SUSCEP_FIRE |
+F:BASH_DOOR | WILD_TOO | WILD_WASTE |
+F:ANIMAL | IM_COLD | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A large and muscled wolf from the northern wastes. Its breath is cold and
+D:icy and its fur coated in frost.
+
+N:212:Grape jelly
+G:j:v
+I:110:52d8:2:1:99
+W:12:3:2600:60
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EXP_10
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | HURT_LITE | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_11 |
+S:DRAIN_MANA
+D:Yum! It looks quite tasty. It is a pulsing mound of glowing flesh.
+
+N:213:Nether worm mass
+G:w:D
+I:100:5d8:10:15:3
+W:12:4:200:6
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EXP_10
+F:RAND_50 | RAND_25 | CAN_SWIM |
+F:STUPID | WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | HURT_LITE | NO_FEAR | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a disgusting mass of dark worms, eating each other, the floor,
+D:the air, you...
+
+N:214:Abyss worm mass
+G:w:D
+I:100:5d8:10:15:3
+W:12:4:200:7
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:EXP_10
+F:RAND_50 | RAND_25 |
+F:STUPID | WEIRD_MIND | BASH_DOOR | EVIL | CAN_SWIM |
+F:ANIMAL | HURT_LITE | NO_FEAR | KILL_WALL | COLD_BLOOD | INVISIBLE |
+F:MORTAL | ZANGBAND | NO_CUT
+S:MULTIPLY
+D:Even more disgusting dark worms, their essence that of unbeing.
+
+N:215:Golfimbul, the Hill Orc Chief
+G:o:y
+I:110:26d10:20:60:20
+W:12:3:2200:230
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:1d13
+B:HIT:HURT:1d13
+B:HIT:HURT:1d11
+B:HIT:HURT:1d11
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | WILD_TOO | SPECIAL_GENE |
+F:ESCORT | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | CAN_SPEAK |
+F:EVIL | ORC | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A leader of a band of raiding orcs, he picks on hobbits.
+
+N:216:Swordsman
+G:p:u
+I:110:12d8:20:34:20
+W:12:1:1800:40
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:MALE | WILD_TOO |
+F:DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A warrior of considerable skill.
+
+N:217:Skaven shaman
+G:r:g
+I:110:10d8:20:15:20
+W:12:1:600:36
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+F:MALE | WILD_TOO | WILD_SWAMP | WILD_WASTE |
+F:FORCE_SLEEP | DROP_90 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | ZANGBAND
+S:1_IN_8 |
+S:BLINK | CAUSE_1 | MISSILE | CONF | SCARE
+D:The shaman of a skaven tribe gets his powers from a mystic
+D:stone corrupted by chaos, called a Warp Stone.
+
+N:218:Baby bronze dragon
+G:d:U
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_CONF | HAS_EGG | IMPRESED | BASEANGBAND | ATTR_MULTI
+S:1_IN_12 |
+S:BR_CONF
+D:This hatchling dragon is still soft, its eyes unaccustomed to light and
+D:its scales a dull bronze.
+
+N:219:Baby gold dragon
+G:d:y
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_STUN | HAS_EGG | IMPRESED | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_12 |
+S:BR_SOUN
+D:This hatchling dragon is still soft, its eyes unaccustomed to light and
+D:its scales a pale gold.
+
+N:220:Evil eye
+G:e:D
+I:110:15d8:2:6:10
+W:18:3:600:80
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:EXP_10
+B:GAZE:EXP_10
+F:NEVER_MOVE | EVIL | CAN_FLY | DROP_CORPSE |
+F:HURT_LITE | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:HOLD | TELE_TO
+D:A huge disembodied eye. As you stare into the black nothingness of its pupil,
+D:you feel your will and vitality draining away, and are unable to do anything
+D:except approach it in horrified fascination.
+
+N:221:Mine-dog
+G:C:u
+I:120:6d6:30:30:20
+W:12:4:500:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:EXPLODE:HURT:6d6
+F:RAND_50 | FRIENDS | BASH_DOOR | ANIMAL |
+F:MORTAL | ZANGBAND
+D:An explosive charge has been attached to this poor animal, who
+D:has been trained to search for its target and detonate.
+
+N:222:Hellcat
+G:f:R
+I:120:9d8:20:30:30
+W:12:1:400:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d5
+B:CLAW:HURT:1d5
+B:BITE:HURT:1d8
+F:ANIMAL | WEIRD_MIND | FRIENDS | RAND_25 | IM_FIRE | EVIL | SUSCEP_COLD |
+F:MORTAL | ZANGBAND | HAS_LITE
+D:It is as large as a tiger, and its yellow eyes are pupilless.
+
+N:223:Moon beast
+G:q:W
+I:120:9d10:30:30:20
+W:12:1:800:57
+E:0:1:0:2:1:0
+O:50:0:40:5
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BUTT:HURT:1d6
+F:DROP_1D2 | ONLY_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | ANIMAL | DROP_CORPSE
+F:MORTAL | ZANGBAND
+S:1_IN_6
+S:HEAL | BLIND | DARKNESS | CONF | CAUSE_2
+D:"Great greyish-white slippery things which could expand and
+D:contract at will, and whose principle shape... was that of a
+D:sort of toad without any eyes, but with a curious vibrating mass
+D:of short pink tentacles on the end of its blunt, vague snout."
+
+N:224:Master yeek
+G:y:g
+I:110:12d9:18:24:10
+W:12:2:600:28
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:1d8
+F:FORCE_SLEEP |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | EVIL | IM_ACID | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:BLINK | TPORT | BLIND | SLOW | BA_POIS |
+S:S_MONSTER
+D:A small humanoid that radiates some power.
+
+N:225:Priest
+G:p:g
+I:110:12d8:20:22:40
+W:12:1:1500:36
+E:1:1:1:2:1:1
+O:0:20:80:0
+B:HIT:HURT:2d3
+B:HIT:HURT:2d3
+F:MALE | GOOD |
+F:FORCE_SLEEP |
+F:DROP_1D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | SCARE | CAUSE_2 |
+S:S_MONSTER
+D:A robed man dedicated to his god.
+
+N:226:Dark elven priest
+G:h:g
+I:120:7d10:20:30:30
+W:12:1:1200:50
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:HIT:HURT:1d9
+B:HIT:HURT:1d10
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:HEAL | BLIND | CONF | CAUSE_2 | DARKNESS | MISSILE
+D:A dark elven figure, dressed all in black, chanting curses and waiting to
+D:deliver your soul to hell.
+
+N:227:Air spirit
+G:E:B
+I:130:8d8:12:40:20
+W:12:2:0:40
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d3
+F:RAND_50 | RAND_25 | IM_ELEC | IM_POIS |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD | BASH_DOOR |
+F:IM_POIS | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A whirlwind of sentient air.
+
+N:228:Skeleton human
+G:s:W
+I:110:10d8:20:30:30
+W:12:1:1500:38
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is an animated human skeleton.
+
+N:229:Zombified human
+G:z:s
+I:110:12d8:20:24:20
+W:12:1:1500:34
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a shambling human corpse dropping chunks of flesh behind it.
+
+N:230:Tiger
+G:f:o
+I:120:12d10:40:40:0
+W:12:2:1500:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:1d6
+F:BASH_DOOR | WILD_TOO | WILD_GRASS | WILD_WOOD | WILD_MOUNTAIN |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:One of the largest of its species, a sleek orange and black shape creeps
+D:towards you, ready to pounce.
+
+N:231:Moaning spirit
+G:G:u
+I:120:5d8:14:20:10
+W:12:2:0:44
+E:0:0:0:0:0:0
+O:45:15:25:0
+B:WAIL:TERRIFY
+B:TOUCH:LOSE_DEX:1d8
+F:FORCE_SLEEP | RAND_25 |
+F:DROP_60 | DROP_90 | CAN_FLY |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:TPORT | SCARE
+D:A ghostly apparition that shrieks horribly.
+
+N:232:Stegocentipede
+G:c:u
+I:120:13d8:12:30:30
+W:12:2:1200:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:2d4
+B:BITE:HURT:2d4
+B:STING:HURT:2d4
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | DROP_SKELETON | MORTAL | BASEANGBAND
+D:It is a vast armoured centipede with massive mandibles and a spiked tail.
+
+N:233:Spotted jelly
+G:j:o
+I:120:13d8:12:18:1
+W:12:3:2500:33
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:2d6
+B:TOUCH:ACID:2d6
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND | COLD_BLOOD |
+F:IM_ACID | IM_POIS | HURT_LITE | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A strange jelly thing, covered in discoloured blotches.
+
+N:234:Drider
+G:S:b
+I:110:10d13:8:30:80
+W:13:2:2000:55
+E:1:1:1:2:1:0
+O:0:0:0:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:BITE:POISON:1d6
+F:FORCE_SLEEP |
+F:BASH_DOOR | DROP_SKELETON |
+F:EVIL | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:CONF | CAUSE_1 | DARKNESS | MISSILE | ARROW_2
+D:A dark elven torso merged with the bloated form of a giant spider.
+
+N:235:Mongbat
+G:b:U
+I:110:10d10:20:80:8
+W:13:2:800:65
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:POISON:1d8
+F:ANIMAL | EVIL | FRIENDS | CAN_FLY | FORCE_MAXHP |
+F:IM_COLD | IM_ELEC | IM_POIS | WEIRD_MIND | DROP_CORPSE
+F:MORTAL | BASEANGBAND
+D:Devil-bats, notoriously difficult to kill.
+
+N:236:Killer brown beetle
+G:K:u
+I:110:13d8:10:40:30
+W:13:1:500:38
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is a vicious insect with a tough carapace.
+
+N:237:Boldor, King of the Yeeks
+G:y:v
+I:120:20d10:18:24:10
+W:13:3:650:200
+E:1:1:1:2:1:1
+O:0:90:10:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:HIT:HURT:1d9
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS |
+F:ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR | CAN_SPEAK | DROP_CORPSE |
+F:ANIMAL | EVIL | IM_ACID |
+F:MORTAL | BASEANGBAND
+S:1_IN_2 |
+S:HEAL | BLINK | TPORT | BLIND | SLOW |
+S:S_KIN | S_MONSTER
+D:A great yeek, powerful in magic and sorcery, but a yeek all the same.
+
+N:238:Ogre
+G:O:U
+I:110:13d9:20:33:30
+W:13:2:2100:50
+E:1:1:1:2:1:1
+O:10:85:0:0
+B:HIT:HURT:2d8
+F:FRIENDS |
+F:DROP_60 | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A hideous, smallish giant that is often found near or with orcs.
+
+N:239:Creeping mithril coins
+G:$:B
+I:110:20d8:5:50:10
+W:13:3:0:45
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d5
+B:TOUCH:POISON:3d5
+F:ONLY_GOLD | DROP_90 | DROP_2D2 |
+F:COLD_BLOOD | BASH_DOOR | IM_ACID | CHAR_MULTI |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of sentient mithril coins that doesn't like being
+D:picked up.
+
+N:240:Illusionist
+G:p:R
+I:110:12d8:20:10:10
+W:13:2:1500:50
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:HIT:HURT:2d2
+F:MALE |
+F:FORCE_SLEEP | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HASTE | BLINK | TPORT | BLIND | HOLD | SLOW | CONF | DARKNESS
+D:A deceptive spell caster.
+
+N:241:Druid
+G:p:G
+I:110:12d12:20:10:10
+W:13:2:1400:50
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:MALE | WILD_TOO | WILD_WOOD |
+F:FORCE_SLEEP | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HASTE | BLINK | BLIND | HOLD | SLOW | BO_FIRE | BO_ELEC | S_ANIMAL
+D:A priest devoted to Nature.
+
+N:242:Pink horror
+G:u:R
+I:110:15d9:20:35:20
+W:13:3:1200:64
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:TERRIFY:1d8
+B:CLAW:TERRIFY:1d8
+B:BITE:CONFUSE:1d6
+F:FRIENDS |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | NO_CONF | ZANGBAND
+S:1_IN_8 |
+S:CONF | SCARE
+D:An ugly screaming little demon servant of Tzeentch.
+
+N:243:Cloaker
+G:(:g
+I:130:7d7:20:40:0
+W:13:5:60:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:PARALYZE:5d5
+B:HIT:TERRIFY:5d5
+F:NEVER_MOVE | NO_FEAR |
+F:STUPID | EMPTY_MIND | COLD_BLOOD | CHAR_MULTI | NO_CONF | NO_SLEEP |
+F:DROP_90 | IM_COLD | FORCE_MAXHP | IM_ELEC | IM_POIS |
+F:BASEANGBAND | NO_CUT
+D:It resembles a normal cloak until some poor fool ventures too close!
+
+N:244:Black orc
+G:o:D
+I:110:12d10:20:36:20
+W:13:1:2000:45
+E:1:1:1:2:1:1
+O:10:50:20:15
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:MALE | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9
+S:ARROW_2
+D:He is a large orc with powerful arms and deep black skin.
+
+N:245:Ochre jelly
+G:j:U
+I:120:13d8:12:18:1
+W:13:3:2300:40
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:2d6
+B:TOUCH:ACID:2d6
+F:STUPID | EMPTY_MIND | COLD_BLOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A fast moving highly acidic jelly thing, that is eating away the floor it
+D:rests on.
+
+N:246:Software bug
+G:I:r
+I:120:2d2:8:25:10
+W:14:1:0:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY |
+F:ANIMAL | MORTAL | JOKEANGBAND
+S:MULTIPLY
+D:Oh no! They are everywhere!
+
+N:247:Lurker
+G:.:w
+I:110:20d10:30:25:10
+W:14:3:0:80
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:CHAR_CLEAR | ATTR_CLEAR | CHAR_MULTI |
+F:NEVER_MOVE | FORCE_MAXHP |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+D:A strange creature that merges with the dungeon floor, trapping its
+D:victims by enveloping them within its perfectly disguised form.
+
+N:248:Tangleweed
+G:#:g
+I:100:5d5:5:5:5
+W:10:4:50:10
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:PARALYZE
+B:HIT:PARALYZE
+F:FORCE_SLEEP | NEVER_MOVE | STUPID | EMPTY_MIND | FRIENDS |
+F:KILL_TREES | SUSCEP_FIRE | ANIMAL |
+F:WILD_ONLY | COLD_BLOOD | WILD_WOOD | WILD_GRASS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | MORTAL | BASEANGBAND | DROP_60 | NO_CUT
+D:A mass of vegetation. As you pass near it, it reaches out tendrils to
+D:ensnare you. You can just make out skeletons of its previous victims
+D:deep within the thickets.
+
+N:249:Vlasta
+G:R:B
+I:120:12d6:12:20:12
+W:14:3:1000:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:BLIND:1d10
+B:BITE:BLIND:1d10
+F:OPEN_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | ZANGBAND
+D:This strange creature looks like a miniature tyrannosaur. It has
+D:empty, pale eyes and a sharp beak, which it aims at your eyes
+D:as it jumps at you!
+
+N:250:Giant white dragon fly
+G:F:w
+I:110:3d8:12:20:50
+W:14:2:150:60
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:COLD:1d6
+F:FORCE_SLEEP | WILD_TOO | WILD_WASTE |
+F:RAND_50 | CAN_FLY | SUSCEP_FIRE |
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_COLD |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_COLD
+D:It is a large fly that drips frost.
+
+N:251:Snaga sapper
+G:o:U
+I:111:8d8:20:32:30
+W:14:1:80:15
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:EXPLODE:HURT:20d2
+F:MALE |
+F:WILD_TOO | SUSCEP_FIRE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | ZANGBAND | HAS_LITE
+D:He is one of the many weaker 'slave' orcs, often mistakenly known as a
+D:goblin. He is equipped with an explosive charge.
+
+N:252:Blue icky thing
+G:i:b
+I:100:10d6:15:20:20
+W:14:4:600:20
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:POISON:1d4
+B:CRAWL:EAT_FOOD
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+F:FORCE_SLEEP |
+F:RAND_50 |
+F:OPEN_DOOR | BASH_DOOR | CAN_SWIM | DROP_CORPSE |
+F:EVIL | IM_POIS | BASEANGBAND
+S:MULTIPLY |
+S:1_IN_8 |
+S:BLIND | CONF | SCARE
+D:It is a strange, slimy, icky creature, with rudimentary intelligence,
+D:but evil cunning. It hungers for food, and you look tasty.
+
+N:253:Gibbering mouther
+G:j:o
+I:110:8d6:15:20:20
+W:14:4:2600:20
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:POISON:1d4
+F:NEVER_MOVE | EVIL | CAN_SWIM |
+F:IM_POIS | EMPTY_MIND | NO_FEAR | BASEANGBAND | NO_CUT
+S:MULTIPLY |
+S:1_IN_7 |
+S:SCARE | CONF | BR_LITE
+D:A chaotic mass of pulsating flesh, mouths and eyes.
+
+N:254:Wolfhound of Flora
+G:C:s
+I:120:9d9:20:20:0
+W:14:2:1600:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d5
+B:BITE:HURT:1d5
+F:ANIMAL | NO_FEAR | FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | ZANGBAND
+D:Well-trained watchdogs, obedient to death.
+
+N:255:Hill giant
+G:P:U
+I:110:30d15:20:45:50
+W:25:1:3500:150
+E:1:1:1:2:1:1
+O:20:50:20:5
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+F:DROP_60 | WILD_TOO | WILD_MOUNTAIN | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | MALE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A ten foot tall humanoid with powerful muscles.
+
+N:256:Flesh golem
+G:g:R
+I:110:12d8:12:30:10
+W:14:2:3000:50
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:EMPTY_MIND | BASH_DOOR | CAN_SWIM |
+F:IM_ELEC | IM_COLD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING |
+F:MORTAL | BASEANGBAND | NO_CUT
+D:A shambling humanoid monster with long scars.
+
+N:257:Warg
+G:C:D
+I:120:8d8:20:20:40
+W:16:2:700:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+B:BITE:HURT:1d6
+F:RAND_25 | BASH_DOOR | FRIENDS |
+F:WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | EVIL | MORTAL | BASEANGBAND
+D:It is a large wolf with eyes full of cunning.
+
+N:258:Cheerful leprechaun
+G:h:G
+I:120:2d5:8:6:6
+W:14:2:800:23
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:TOUCH:EAT_GOLD
+B:TOUCH:EAT_FOOD
+F:DROP_60 | ONLY_GOLD | RAND_50 | OPEN_DOOR | MALE |
+F:GOOD | MORTAL | ZANGBAND
+S:MULTIPLY |
+S:1_IN_6 |
+S:BLINK
+D:A merry little gnome.
+
+N:259:Giant flea
+G:I:s
+I:120:1d2:6:7:10
+W:14:3:90:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | CAN_FLY | WEIRD_MIND |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It makes you itch just to look at it.
+
+N:260:Ufthak of Cirith Ungol
+G:o:g
+I:110:34d10:20:50:20
+W:14:3:2600:250
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_COLD | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A strong orc guarding the pass of Cirith Ungol. He is mortally afraid of
+D:spiders: he was captured by Shelob once, but escaped when she forgot
+D:completely about him.
+
+N:261:Clay golem
+G:g:U
+I:110:14d8:12:30:10
+W:15:2:3200:60
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a massive animated statue made out of hardened clay.
+
+N:262:Black ogre
+G:O:D
+I:110:20d9:20:33:30
+W:15:2:2300:70
+E:1:1:1:2:1:1
+O:0:70:0:15
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+F:RAND_25 | WILD_TOO | WILD_MOUNTAIN | DROP_CORPSE |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A massive orc-like figure with black skin and powerful arms.
+
+N:263:Dweller on the threshold
+G:Y:s
+I:110:30d8:30:30:20
+W:15:5:3000:50
+E:1:1:1:2:1:1
+O:45:0:40:10
+B:GAZE:PARALYZE:4d4
+B:GAZE:TERRIFY:3d3
+B:GAZE:CONFUSE:3d3
+F:NEVER_MOVE | DROP_60 | EVIL | DEMON | DROP_CORPSE |
+F:IM_POIS | IM_COLD |IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP
+F:MORTAL | ZANGBAND
+S:1_IN_6
+S:BO_ACID | S_MONSTER | SCARE | DRAIN_MANA
+D:A gorilla-shaped arcane guardian with an appetite for mages.
+
+N:264:Half-orc
+G:o:s
+I:110:16d10:20:40:20
+W:15:2:1700:50
+E:1:1:1:2:1:1
+O:30:30:30:5
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:MALE | WILD_TOO |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | ORC | MORTAL | BASEANGBAND | HAS_LITE
+D:He is a hideous deformed cross-breed of man and orc, combining man's
+D:strength and cunning with orcish evil. The traitorous wizard Saruman is
+D:generally believed to be responsible for this abomination.
+
+N:265:Dark naga
+G:n:s
+I:110:22d11:60:65:60
+W:15:2:1900:90
+E:0:0:0:0:1:0
+O:0:0:80:20
+B:STING:HURT:1d10
+B:BITE:HURT:1d10
+F:FEMALE |
+F:RAND_25 | DROP_60 | DROP_1D2 | IM_POIS | IM_COLD | RES_WATE |
+F:OPEN_DOOR | BASH_DOOR | EMPTY_MIND | CAN_SWIM | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND
+S:1_IN_8
+S:HOLD | CONF | BO_COLD | HEAL | DARKNESS
+D:A giant snake-like figure with a woman's torso, talented in magic.
+
+N:266:Poison ivy
+G:#:g
+I:100:5d5:5:5:5
+W:10:4:50:10
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:POISON:2d2
+B:HIT:POISON:2d2
+F:FORCE_SLEEP | NEVER_MOVE | STUPID | EMPTY_MIND | FRIENDS |
+F:KILL_TREES | SUSCEP_FIRE | ANIMAL |
+F:WILD_ONLY | COLD_BLOOD | WILD_WOOD | WILD_GRASS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | MORTAL | BASEANGBAND | DROP_60 | NO_CUT
+S:MULTIPLY
+D:A mass of vegetation. It seems to be growing...
+
+N:267:Magic mushroom patch
+G:,:B
+I:140:1d1:40:10:0
+W:15:2:50:10
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:CONFUSE
+B:SPORE:CONFUSE
+B:SPORE:HALLU
+B:SPORE:HALLU
+F:FORCE_SLEEP | NEVER_MOVE |
+F:STUPID | RES_TELE | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:BLINK | SLOW | SCARE | DARKNESS
+D:Yum! It looks quite tasty. It seems to glow with an unusual light.
+
+N:268:Plaguebearer of Nurgle
+G:z:o
+I:110:9d10:20:50:20
+W:15:2:2800:75
+E:1:1:1:2:1:1
+O:50:20:20:10
+B:CLAW:DISEASE:2d5
+B:CLAW:DISEASE:2d5
+B:BUTT:HURT:3d5
+F:FORCE_MAXHP | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | IM_COLD |
+F:EVIL | DEMON | UNDEAD | IM_POIS | NONLIVING | ZANGBAND | NO_CUT
+S:1_IN_8 |
+S:SCARE | S_ANT | CAUSE_2 | SLOW
+D:An unfortunate individual, who was killed by the incurable
+D:disease known as Nurgle's Rot, and was transformed into a
+D:rotting demon zombie. It has but one eye, and a single
+D:pale horn in its forehead.
+
+N:269:Guardian naga
+G:n:y
+I:110:24d11:20:65:120
+W:15:2:1900:80
+E:0:0:0:0:1:0
+O:0:0:80:20
+B:CRUSH:HURT:2d8
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+F:FEMALE |
+F:RAND_25 | DROP_60 | DROP_1D2 | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:EVIL
+F:MORTAL | BASEANGBAND
+D:A giant snake-like figure with a woman's torso.
+
+N:270:Wererat
+G:r:D
+I:110:20d8:10:10:10
+W:15:2:30:55
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:2d6
+F:FORCE_SLEEP |
+F:ONLY_GOLD | DROP_60 | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | EVIL
+F:MORTAL | BASEANGBAND
+S:1_IN_9 |
+S:BLINK | CAUSE_2 | BO_COLD | BA_POIS | S_KIN
+D:A large rat with glowing red eyes, which can also assume human form. The wererat
+D:is a disgusting creature, relishing in filth and disease.
+
+N:271:Light hound
+G:Z:o
+I:110:6d6:30:30:0
+W:15:1:600:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:HURT:1d6
+F:FORCE_SLEEP | DROP_CORPSE |
+F:FRIENDS |
+F:BASH_DOOR |
+F:ANIMAL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BR_LITE
+D:A brilliant canine form whose light hurts your eyes, even at this distance.
+
+N:272:Dark hound
+G:Z:D
+I:110:6d6:30:30:0
+W:15:1:600:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:HURT:1d6
+F:FORCE_SLEEP | DROP_CORPSE |
+F:FRIENDS |
+F:BASH_DOOR | HURT_LITE |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_DARK
+D:A hole in the air in the shape of a huge hound. No light falls upon its
+D:form.
+
+N:273:Flying skull
+G:s:s
+I:110:10d10:30:30:20
+W:15:3:500:50
+E:0:0:0:0:1:0
+O:90:0:10:0
+B:BITE:POISON:1d3
+B:BITE:LOSE_STR:1d4
+F:UNDEAD | EVIL | IM_POIS | IM_COLD | WEIRD_MIND | NO_FEAR | CAN_FLY |
+F:NO_CONF | NO_SLEEP | DROP_60 | BASH_DOOR | FRIENDS | COLD_BLOOD |
+F:BASEANGBAND | NO_CUT
+D:A pack of skulls animated by necromantic spells.
+
+N:274:Mi-Go
+G:I:R
+I:120:13d8:20:30:20
+W:15:2:800:80
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:STING:POISON:1d4
+B:BITE:LOSE_STR:1d2
+F:IM_POIS | IM_COLD | COLD_BLOOD | ANIMAL | EVIL |
+F:NO_SLEEP | NO_CONF | CAN_FLY | DROP_SKELETON | CTHANGBAND
+S:1_IN_6
+S:CONF | S_MONSTER | S_DEMON
+D:"They were pinkish things about five feet long; with crustaceous
+D:bodies bearing vast pairs of dorsal fins or membranous wings and
+D:several sets of articulate limbs, and with a sort of convoluted
+D:ellipsoid, covered with multitudes of very short antenna, where
+D:a head would ordinarily be..."
+
+N:275:Giant tarantula
+G:S:o
+I:120:10d15:8:32:80
+W:15:3:1100:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | SPIDER | IM_POIS | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:A giant spider with hairy black and red legs.
+
+N:276:Giant clear centipede
+G:c:B
+I:110:5d8:12:30:30
+W:15:2:400:30
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:2d4
+B:STING:HURT:2d4
+F:ATTR_CLEAR |
+F:INVISIBLE | WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:It is about four feet long and carnivorous.
+
+N:277:Mirkwood spider
+G:S:G
+I:120:9d8:15:25:80
+W:15:2:1200:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+F:FRIENDS | WILD_TOO | WILD_WOOD |
+F:WEIRD_MIND | BASH_DOOR | HURT_LITE |
+F:ANIMAL | SPIDER | EVIL | IM_POIS | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:A strong and powerful spider from Mirkwood forest. Cunning and evil, it
+D:seeks to taste your juicy insides.
+
+N:278:Frost giant
+G:P:w
+I:110:32d15:20:50:50
+W:28:1:4000:180
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:COLD:5d8
+B:HIT:COLD:5d8
+F:DROP_60 | WILD_TOO | WILD_WASTE | WILD_MOUNTAIN |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | GIANT | MALE | AURA_COLD | SUSCEP_FIRE |
+F:IM_COLD | BASEANGBAND | HAS_LITE | MORTAL
+D:A twelve foot tall giant covered in furs.
+
+N:279:Griffon
+G:H:u
+I:110:30d8:12:15:10
+W:15:1:2500:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:HIT:HURT:3d4
+B:BITE:HURT:2d6
+F:BASH_DOOR | CAN_FLY | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | WILD_GRASS |
+F:ANIMAL | DROP_CORPSE | MORTAL | BASEANGBAND
+D:It is half lion, half eagle. It flies menacingly towards you.
+
+N:280:Homunculus
+G:u:y
+I:110:8d8:20:32:30
+W:15:3:100:40
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:PARALYZE:1d2
+B:HIT:HURT:1d10
+F:OPEN_DOOR | BASH_DOOR | NONLIVING | CAN_FLY |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | BASEANGBAND | HAS_LITE
+D:It is a small demonic spirit full of malevolence.
+
+N:281:Gnome mage
+G:h:R
+I:110:7d8:20:20:20
+W:15:2:900:40
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:HIT:HURT:1d5
+F:MALE |
+F:FORCE_SLEEP | FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLINK | DARKNESS | BO_COLD |
+S:S_MONSTER
+D:A mage of short stature.
+
+N:282:Clear hound
+G:Z:B
+I:110:6d6:30:30:0
+W:15:1:600:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d6
+B:CLAW:HURT:1d6
+B:BITE:HURT:1d8
+F:ATTR_CLEAR |
+F:FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:INVISIBLE | BASH_DOOR |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A faint sense of motion in the air, hound shaped, stands before you.
+
+N:283:Umber hulk
+G:X:U
+I:110:20d10:20:50:10
+W:16:1:5000:75
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:HURT:2d6
+F:EMPTY_MIND | COLD_BLOOD |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL |
+F:IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock.
+
+N:284:Rust monster
+G:q:o
+I:110:20d15:12:55:10
+W:16:2:900:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:STUPID | WEIRD_MIND | KILL_ITEM |
+F:IM_ACID | IM_POIS | DROP_CORPSE |
+F:NO_CONF |
+F:MORTAL | BASEANGBAND
+D:It is a weird, small animal with two antennae popping forth from
+D:its forehead. It looks hungry.
+
+N:285:Ogrillon
+G:O:W
+I:110:22d9:20:33:30
+W:16:2:2400:75
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:2d10
+B:HIT:HURT:2d10
+F:FRIENDS | DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | ORC |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:An unholy hybrid of ogre and orc.
+
+N:286:Gelatinous cube
+G:j:G
+I:110:36d10:12:18:1
+W:16:4:40000:80
+E:0:0:0:0:0:0
+O:40:30:20:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:FORCE_MAXHP |
+F:DROP_1D2 | DROP_4D2 |
+F:STUPID | EMPTY_MIND | COLD_BLOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange, vast gelatinous structure that assumes cubic proportions
+D:as it lines all four walls of the corridors it patrols. Through its
+D:transparent jelly structure you can see treasures it has engulfed, and a
+D:few corpses as well.
+
+N:287:Giant green dragon fly
+G:F:G
+I:110:3d8:12:20:50
+W:16:2:150:65
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 | WILD_TOO | WILD_SWAMP |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY |
+F:ANIMAL | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_POIS
+D:A vast, foul-smelling dragonfly.
+
+N:288:Fire giant
+G:P:r
+I:110:34d16:20:60:50
+W:30:1:5000:220
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:FIRE:6d8
+B:HIT:FIRE:6d8
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_VOLCANO | SUSCEP_COLD |
+F:EVIL | GIANT | MALE | AURA_FIRE | DROP_SKELETON | DROP_CORPSE |
+F:IM_FIRE | BASEANGBAND | HAS_LITE | MORTAL
+D:A glowing fourteen foot tall giant. Flames drip from its red skin.
+
+N:289:Hummerhorn
+G:I:y
+I:120:2d2:8:14:10
+W:16:4:100:4
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:CONFUSE:2d2
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:WEIRD_MIND | ANIMAL | BASEANGBAND
+S:MULTIPLY
+D:A giant buzzing wasp, its stinger drips venom.
+
+N:290:Lizard man
+G:h:G
+I:110:16d10:20:40:20
+W:16:3:1300:55
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:4d4
+B:HIT:HURT:4d4
+F:MALE | CAN_SWIM | IM_ACID |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_SHORE |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON
+F:EVIL
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:Intelligent lizard beings from the depths.
+
+N:291:Ulfast, Son of Ulfang
+G:p:U
+I:110:37d10:20:40:40
+W:16:3:1700:200
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:UNIQUE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:MALE |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:A short and swarthy Easterling.
+
+N:292:Crebain
+G:B:D
+I:120:3d5:40:12:0
+W:16:4:500:20
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+F:ANIMAL | EVIL | MORTAL | FRIENDS | BASEANGBAND | DROP_CORPSE | HAS_EGG |
+F:WILD_TOO | WILD_WASTE | WILD_MOUNTAIN | WILD_WOOD | WILD_VOLCANO |
+F:WILD_GRASS | WILD_SWAMP | WILD_SHORE | WILD_OCEAN | CAN_FLY
+S:1_IN_8 | SHRIEK
+D:A type of crow, specially bred by the forces of evil as spies; their
+D:rudimentary intelligence guided by an evil mind has tracked you down,
+D:and now they seek to alert other evil creatures to your presence.
+
+N:293:Berserker
+G:p:u
+I:120:60d25:20:80:10
+W:45:2:2300:2500
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:7d7
+B:HIT:HURT:7d7
+B:HIT:HURT:7d7
+F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | KILL_BODY | FORCE_MAXHP |
+F:DROP_SKELETON | DROP_CORPSE
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 | HASTE | SCARE
+D:Even the strongest of normal human warriors fears the Berserker - the one who
+D:can drive himself into such a terrible battle-frenzy that he can survive blows
+D:which should kill him, and still apparently feel no pain. He tramples weaker
+D:creatures underfoot in his eagerness to get to his real enemy, and his
+D:battle-cry strikes terror into his foes.
+
+N:294:Quasit
+G:u:o
+I:110:6d8:20:30:20
+W:16:2:500:50
+E:1:1:1:2:1:1
+O:0:50:30:10
+B:BITE:LOSE_DEX:1d6
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+F:FORCE_SLEEP | CAN_FLY |
+F:RAND_25 |
+F:ONLY_ITEM | DROP_1D2 |
+F:SMART | INVISIBLE | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NONLIVING | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BLINK | TPORT | TELE_TO | TELE_LEVEL | BLIND | CONF | SCARE
+D:The chaotic evil master's favourite pet.
+
+N:295:Sphinx
+G:H:o
+I:110:60d5:20:60:20
+W:17:2:6000:80
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+F:FORCE_SLEEP |
+F:ONLY_GOLD | DROP_1D2 | CAN_FLY | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_11 |
+S:SCARE | CONF
+D:It will eat you if you cannot answer its riddle.
+
+N:296:Imp
+G:u:g
+I:110:6d8:20:30:20
+W:17:2:400:55
+E:0:1:1:0:1:0
+O:30:20:50:0
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+F:FORCE_SLEEP | CAN_FLY |
+F:RAND_25 |
+F:ONLY_ITEM | DROP_1D2 |
+F:SMART | INVISIBLE | COLD_BLOOD | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | RES_TELE | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BLINK | TPORT | TELE_TO | TELE_LEVEL | BLIND | CONF | SCARE | BO_FIRE
+D:The lawful evil master's favourite pet.
+
+N:297:Forest troll
+G:T:g
+I:110:20d10:20:50:40
+W:17:1:3000:70
+E:1:1:1:2:1:1
+O:30:70:0:0
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+B:BITE:HURT:1d6
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_WOOD | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE | REGENERATE |
+F:EVIL | TROLL | HURT_LITE | BASEANGBAND
+D:He is green-skinned and ugly.
+
+
+N:298:Freezing sphere
+G:*:w
+I:120:6d6:100:30:0
+W:17:1:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:COLD:8d8
+F:FORCE_SLEEP | CAN_FLY | SUSCEP_FIRE | RAND_50 | RAND_25 |
+F:EMPTY_MIND | AURA_COLD |
+F:IM_COLD | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+D:A semi-sentient snowball, hurling itself at targets at random.
+
+N:299:Jumping fireball
+G:*:r
+I:120:6d6:100:30:0
+W:17:1:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:FIRE:8d8
+F:FORCE_SLEEP | CAN_FLY | SUSCEP_COLD |
+F:EMPTY_MIND | AURA_FIRE | RAND_50 | RAND_25 |
+F:IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+D:A semi-sentient fireball that moves around randomly.
+
+N:300:Ball lightning
+G:*:B
+I:120:6d6:100:30:0
+W:17:1:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:ELEC:8d8
+F:FORCE_SLEEP | CAN_FLY | RAND_25 | RAND_50 |
+F:EMPTY_MIND | AURA_ELEC |
+F:IM_ELEC | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | HAS_LITE |NO_CUT
+D:A crackling ball of energy, zooming about seemingly at random.
+
+N:301:2-headed hydra
+G:M:u
+I:110:100d3:20:60:20
+W:17:2:4000:80
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:ONLY_GOLD | DROP_1D2 | CAN_SWIM | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | HAS_EGG | IMPRESED |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_11 |
+S:SCARE
+D:A strange reptilian creature with two heads, guarding its hoard.
+
+N:302:Swamp thing
+G:H:g
+I:110:8d12:20:60:30
+W:17:2:2000:80
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:TERRIFY:2d5
+B:CLAW:TERRIFY:5d2
+F:CAN_SWIM | OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_SWAMP
+F:MORTAL | BASEANGBAND
+D:A creature that was once human, but is now as green as moss.
+
+N:303:Water spirit
+G:E:b
+I:120:9d8:12:28:40
+W:17:2:0:58
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:RAND_25 |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_POIS | IM_ACID | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A whirlpool of sentient liquid.
+
+N:304:Giant red scorpion
+G:S:r
+I:110:11d8:12:44:20
+W:17:1:1000:62
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d4
+B:STING:LOSE_STR:1d7
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:It is fast and poisonous.
+
+N:305:Earth spirit
+G:E:u
+I:120:13d8:10:40:50
+W:17:2:0:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:RAND_25 |
+F:EMPTY_MIND | COLD_BLOOD |
+F:PASS_WALL | CAN_FLY |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A whirling form of sentient rock.
+
+N:306:Fire spirit
+G:E:r
+I:120:10d9:16:30:20
+W:18:2:0:75
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:FIRE:2d6
+B:HIT:FIRE:2d6
+F:RAND_25 |
+F:EMPTY_MIND | BASH_DOOR | CAN_FLY | SUSCEP_COLD |
+F:IM_FIRE | IM_POIS | WILD_TOO | WILD_VOLCANO |
+F:NO_CONF | NO_SLEEP | NO_FEAR | AURA_FIRE | BASEANGBAND | HAS_LITE | NO_CUT
+D:A whirlwind of sentient flame.
+
+N:307:Fire hound
+G:Z:r
+I:110:10d6:30:30:0
+W:18:1:600:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:FIRE:2d6
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | SUSCEP_COLD |
+F:ANIMAL | IM_FIRE | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BR_FIRE
+D:Flames lick at its feet and its tongue is a blade of fire. You can feel a
+D:furnace heat radiating from the creature.
+
+N:308:Cold hound
+G:Z:w
+I:110:10d6:30:30:0
+W:18:1:600:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:COLD:2d6
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | IM_COLD | SUSCEP_FIRE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_COLD
+D:A hound as tall as a man, this creature appears to be composed of angular
+D:planes of ice. Cold radiates from it and freezes your breath in the air.
+
+N:309:Energy hound
+G:Z:b
+I:110:10d6:30:30:0
+W:18:1:600:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:ELEC:2d6
+F:FORCE_SLEEP |
+F:FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | IM_ELEC |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BR_ELEC
+D:Saint Elmo's Fire forms a ghostly halo around this hound, and sparks sting
+D:your fingers as energy builds up in the air around you.
+
+N:310:Lesser Mimic
+G:m:y
+I:110:10d10:25:30:250
+W:18:3:100:60
+E:0:0:0:0:0:0
+O:10:10:10:10
+B:HIT:POISON:3d4
+B:HIT:HURT:2d3
+B:HIT:HURT:2d3
+F:MIMIC |
+F:FORCE_SLEEP | NEVER_MOVE | SUSCEP_COLD |
+F:EMPTY_MIND | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BLIND | CONF | SCARE | CAUSE_2 | BO_COLD
+D:A strange creature that disguises itself as some object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:311:Door mimic
+G:+:U
+I:110:10d10:25:30:0
+W:18:6:100:70
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:POISON:3d4
+B:HIT:CONFUSE:2d3
+B:HIT:PARALYZE:2d3
+F:CHAR_MULTI |
+F:FORCE_SLEEP | NEVER_MOVE |
+F:EMPTY_MIND | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BLIND | CONF | SCARE | CAUSE_2 | BO_COLD
+D:A strange creature that disguises itself as a door to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:312:Blink dog
+G:C:B
+I:120:8d8:20:20:10
+W:18:2:400:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+F:RAND_25 | FRIENDS | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | RES_TELE | MORTAL | BASEANGBAND
+S:1_IN_4 | BLINK | TELE_TO
+D:A strange magical member of the canine race, its form seems to shimmer and
+D:fade in front of your very eyes.
+
+N:313:Uruk
+G:o:B
+I:110:8d10:20:50:20
+W:16:1:2300:60
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:MALE |
+F:FORCE_MAXHP | FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:ARROW_2
+D:It is a cunning orc of power, as tall as a man, and stronger. It fears
+D:little.
+
+N:314:Shagrat, the Orc Captain
+G:o:g
+I:110:42d10:20:60:20
+W:19:2:2600:400
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d9
+B:HIT:HURT:3d9
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | SPECIAL_GENE
+F:ESCORT | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is an orc of power and great cunning, leader of the garrison at Cirith Ungol.
+
+N:315:Gorbag, the Orc Captain
+G:o:g
+I:110:42d10:20:60:20
+W:19:2:2600:400
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d9
+B:HIT:HURT:3d9
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP |
+F:ESCORT | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is an orc of power and great cunning, leader of the garrison at Minas Morgul.
+
+N:316:Shambling mound
+G:,:g
+I:110:20d6:20:16:40
+W:18:2:3000:75
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:ONLY_GOLD | DROP_90 | WILD_TOO | WILD_SWAMP |
+F:STUPID | EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:SHRIEK
+D:A pile of rotting vegetation that slides towards you with a disgusting
+D:stench, waking all it nears.
+
+N:317:Giant Venus Flytrap
+G:#:g
+I:120:10d10:20:5:0
+W:15:5:200:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:PARALYZE:3d3
+B:HIT:PARALYZE:3d3
+B:HIT:PARALYZE:3d3
+F:NEVER_MOVE | EMPTY_MIND | STUPID | CHAR_CLEAR | CHAR_MULTI |
+F:WILD_ONLY | WILD_WOOD | WILD_SWAMP | ANIMAL | SUSCEP_FIRE | NO_CUT
+D:A carnivorous plant that is difficult to detect, until it suddenly snaps shut
+D:around its prey and releases paralysing enzymes to stop its struggles.
+
+N:318:Chaos beastman
+G:H:u
+I:110:20d8:20:50:30
+W:18:2:2300:75
+E:0:0:0:0:0:0
+O:25:45:20:0
+B:HIT:CONFUSE:3d5
+B:HIT:EXP_20:3d5
+F:DROP_1D2
+F:OPEN_DOOR | BASH_DOOR | NO_CONF | NO_SLEEP | DROP_CORPSE
+F:EVIL | IM_POIS | IM_FIRE | ATTR_ANY | ATTR_MULTI
+F:MORTAL | ZANGBAND
+S:1_IN_8
+S:MISSILE | BO_FIRE | CONF | TPORT
+D:A truly loathsome thing, twisted by chaos, it is a mixture
+D:of several different kinds of creature.
+
+N:319:Daemonette of Slaanesh
+G:u:R
+I:120:12d8:20:50:30
+W:18:2:2000:75
+E:1:1:1:0:1:1
+O:30:0:30:40
+B:CLAW:CONFUSE:3d5
+B:CLAW:CONFUSE:3d5
+F:FORCE_MAXHP | DROP_60 | FEMALE |
+F:OPEN_DOOR | BASH_DOOR | IM_COLD | NO_CONF | NO_SLEEP |
+F:EVIL | DEMON | IM_POIS | IM_FIRE | ZANGBAND
+S:1_IN_8
+S:SCARE | S_DEMON | CAUSE_2 | CONF | BO_FIRE | BO_COLD
+D:It is minor female demon, vaguely human-like, but with crab-like
+D:pincers instead of hands. She wears a rather indecent skimpy
+D:leather bikini, moves quickly and casts deadly spells!
+
+N:320:Giant bronze dragon fly
+G:F:U
+I:120:3d8:12:20:50
+W:18:2:150:80
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:CONFUSE:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 | CAN_FLY |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_CONF
+D:This vast gleaming bronze fly has wings which beat mesmerically fast.
+
+N:321:Stone giant
+G:P:W
+I:110:35d18:20:75:50
+W:33:1:7000:250
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:DROP_60 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | GIANT | MALE | WILD_TOO | WILD_MOUNTAIN | BASEANGBAND | HAS_LITE
+D:It is eighteen feet tall and looking at you.
+
+N:322:Giant black dragon fly
+G:F:s
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ACID:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | IM_ACID |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_ACID
+D:The size of a large bird, this fly drips caustic acid.
+
+N:323:Stone golem
+G:g:W
+I:100:28d8:12:75:10
+W:19:2:3500:100
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+F:COLD_BLOOD | EMPTY_MIND | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+D:It is a massive animated statue.
+
+N:324:Red mold
+G:m:r
+I:110:17d8:2:16:70
+W:19:1:40:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:FIRE:4d4
+F:NEVER_MOVE | SUSCEP_COLD |
+F:STUPID | EMPTY_MIND |
+F:IM_FIRE | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange red growth on the dungeon floor; it seems to burn with
+D:flame.
+
+N:325:Giant gold dragon fly
+G:F:y
+I:120:3d8:12:20:50
+W:22:2:150:75
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 | WILD_TOO | WILD_MOUNTAIN |
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_FIRE | CAN_FLY |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_SOUN
+D:Large beating wings support this dazzling insect. A loud buzzing noise
+D:pervades the air.
+
+N:326:Stunwall
+G:#:W
+I:110:4d8:45:25:0
+W:18:5:1000:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:PARALYZE:10d1
+B:TOUCH:PARALYZE:10d1
+F:NEVER_MOVE | IM_COLD | COLD_BLOOD | IM_ACID | IM_ELEC | NO_FEAR |
+F:IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | CHAR_MULTI |
+F:EMPTY_MIND | HURT_ROCK | ZANGBAND | NO_CUT
+D:A sentient section of wall.
+
+N:327:Ghast
+G:z:u
+I:120:30d10:40:40:20
+W:30:1:1500:130
+E:1:1:1:2:1:1
+O:20:35:25:10
+B:CLAW:PARALYZE:2d4
+B:CLAW:PARALYZE:2d4
+B:BITE:LOSE_CON:2d4
+B:BITE:LOSE_CHR:2d4
+F:DROP_60 | OPEN_DOOR | BASH_DOOR | ESCORT |
+F:NO_SLEEP | NO_CONF | UNDEAD | EVIL | IM_POIS | IM_COLD |
+F:COLD_BLOOD | HURT_LITE | CAN_SWIM | BASEANGBAND | NO_CUT
+D:This vile abomination is a relative of ghouls, and often leads packs
+D:of them. It smells foul, and its bite carries a rotting disease.
+
+N:328:Neekerbreeker
+G:I:D
+I:120:3d2:8:18:10
+W:19:4:100:4
+B:BITE:POISON:2d2
+F:RAND_50 | RAND_25 | CAN_FLY | WILD_SWAMP | WILD_TOO |
+F:WEIRD_MIND | ANIMAL | EVIL | BASEANGBAND
+S:MULTIPLY |
+S:1_IN_12 |
+S:SHRIEK
+D:Believed to be an evil relative of the cricket, this creature gets its name
+D:from its incessant squeaking, which can best be described as "neek-breek,
+D:neek-breek". The noise can drive people frantic, and worse still, can be
+D:heard for quite some distance, alerting other monsters to your presence.
+
+N:329:Huorn
+G:#:g
+I:110:50d10:40:45:20
+W:19:1:4000:75
+E:0:0:0:0:0:0
+O:30:30:30:5
+B:CRUSH:HURT:3d6
+B:CRUSH:HURT:3d6
+B:CRUSH:HURT:3d6
+B:CRUSH:HURT:3d6
+F:DROP_60 | NO_SLEEP | NO_CONF | ANIMAL | WEIRD_MIND | SUSCEP_FIRE |
+F:RES_WATE | IM_COLD | NEVER_MOVE | WILD_ONLY | WILD_WOOD |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9
+S:BLINK | TELE_TO
+D:A very strong near-sentient tree, which has become hostile to other living things.
+
+N:330:Bolg, Son of Azog
+G:o:v
+I:120:52d10:20:50:20
+W:20:4:2300:800
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d7
+B:HIT:HURT:3d7
+B:HIT:HURT:3d7
+B:HIT:HURT:3d7
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | SPECIAL_GENE |
+F:ESCORT | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A large and powerful orc, he looks just like his father. He is tall and
+D:fast, but fortunately blessed with orcish brains.
+
+N:331:Phase spider
+G:S:B
+I:120:6d8:15:25:80
+W:20:2:500:60
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+F:FRIENDS | WILD_TOO | WILD_WOOD | DROP_SKELETON |
+F:WEIRD_MIND | BASH_DOOR | CAN_SWIM |
+F:ANIMAL | SPIDER | IM_POIS | RES_TELE |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BLINK | TELE_TO
+D:A spider that never seems quite there. Everywhere you look it is just
+D:half-seen in the corner of one eye.
+
+N:332:Lizard king
+G:h:g
+I:120:18d11:20:40:20
+W:20:3:1600:150
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:WAIL:TERRIFY
+F:MALE | CAN_SWIM | IM_ACID | IM_POIS | WILD_SHORE |
+F:DROP_60 | DROP_1D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | FORCE_MAXHP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A lizardman leader.
+
+N:333:Landmine
+G:.:w
+I:110:6d6:30:25:10
+W:20:5:300:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:HURT:25d2
+F:CHAR_CLEAR | ATTR_CLEAR | CHAR_MULTI |
+F:NEVER_MOVE | FORCE_MAXHP |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | JOKEANGBAND | NO_CUT
+D:It was left here to be used against intruders.
+
+N:334:Wyvern
+G:d:g
+I:120:100d5:20:65:20
+W:22:2:4500:250
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+B:STING:POISON:1d6
+F:FORCE_SLEEP |
+F:ONLY_GOLD | DROP_2D2 | IM_POIS | CAN_FLY | HAS_EGG |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | DROP_CORPSE |
+F:WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_SKELETON |
+F:ANIMAL | EVIL | DRAGON | BASEANGBAND | ATTR_MULTI
+D:A fast-moving and deadly draconian animal. Beware its poisonous sting!
+
+N:335:Great eagle
+G:B:u
+I:120:100d5:20:65:20
+W:20:2:1000:150
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:6d3
+B:CLAW:HURT:6d3
+B:BITE:HURT:3d6
+F:CAN_FLY |
+F:WILD_ONLY | WILD_MOUNTAIN | WILD_VOLCANO | WILD_WASTE | WILD_WOOD |
+F:ANIMAL | GOOD | DROP_CORPSE | BASEANGBAND | HAS_EGG
+D:Greater and more intelligent than most of its kind, this great eagle is
+D:a messenger between the forces of good.
+
+N:336:Livingstone
+G:#:W
+I:110:6d8:45:28:20
+W:20:4:1000:56
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d5
+B:HIT:HURT:2d5
+F:NEVER_MOVE | IM_COLD | COLD_BLOOD | IM_ACID | IM_ELEC | NO_FEAR |
+F:IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | FRIENDS | CHAR_MULTI | HURT_ROCK |
+F:BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:A sentient section of wall.
+
+N:337:Earth hound
+G:Z:u
+I:110:15d8:30:30:0
+W:20:1:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP |
+F:FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_10 |
+S:BR_SHAR
+D:A beautiful crystalline shape does not disguise the danger this hound
+D:clearly presents. Your flesh tingles as it approaches.
+
+N:338:Air hound
+G:Z:g
+I:110:15d8:30:30:0
+W:20:1:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d8
+B:BITE:POISON:1d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP |
+F:FRIENDS | CAN_FLY |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_POIS
+D:Swirling vapours surround this beast as it floats towards you, seemingly
+D:walking on air. Noxious gases sting your throat.
+
+N:339:Sabre-tooth tiger
+G:f:y
+I:120:20d14:40:50:0
+W:20:2:1800:120
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d10
+B:CLAW:HURT:1d10
+B:BITE:HURT:1d10
+B:BITE:HURT:1d10
+F:BASH_DOOR | WILD_WOOD | WILD_TOO | WILD_GRASS |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE
+F:MORTAL | BASEANGBAND
+D:A fierce and dangerous cat, its huge tusks and sharp claws would lacerate
+D:even the strongest armour.
+
+N:340:Acid hound
+G:Z:s
+I:110:15d8:30:30:0
+W:20:1:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ACID:1d8
+B:BITE:ACID:1d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | CAN_SWIM | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | IM_ACID | MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_ACID
+D:Footprints are burned in the ground behind this hound as it pads
+D:around the dungeon. An acrid smell of acid rises from the dog's pelt.
+
+N:341:Chimaera
+G:H:r
+I:110:20d15:12:15:10
+W:20:2:1600:200
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BUTT:HURT:2d8
+B:BITE:HURT:2d10
+B:BITE:FIRE:2d6
+F:FORCE_SLEEP | CAN_FLY | DROP_CORPSE | SUSCEP_COLD |
+F:BASH_DOOR | WILD_TOO | WILD_MOUNTAIN |
+F:IM_FIRE | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BR_FIRE
+D:It is a strange concoction of goat, lion and dragon, with the heads of all
+D:three beasts.
+
+N:342:Quylthulg
+G:Q:y
+I:110:6d8:10:1:0
+W:20:1:3000:250
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | NEVER_MOVE | NEVER_BLOW
+F:EMPTY_MIND | INVISIBLE | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_4 |
+S:BLINK |
+S:S_MONSTER
+D:It is a strange pulsing mound of flesh.
+
+N:343:Sasquatch
+G:Y:W
+I:120:20d19:15:40:10
+W:20:3:3500:180
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:1d10
+B:CLAW:HURT:1d10
+B:BITE:HURT:2d8
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD | WILD_WASTE |
+F:ANIMAL | IM_COLD | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A tall shaggy, furry humanoid, it could call the yeti brother.
+
+N:344:Weir
+G:C:W
+I:110:10d12:15:30:40
+W:20:2:2010:150
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+F:RAND_25 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | EVIL | FRIENDS |
+F:MORTAL | ZANGBAND
+D:It is a tracker; half human, half beast.
+
+N:345:Ranger
+G:p:W
+I:110:15d11:20:40:40
+W:20:1:1700:55
+E:1:1:1:2:1:1
+O:20:50:20:0
+B:HIT:HURT:5d4
+B:HIT:HURT:5d4
+F:MALE |
+F:DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:DROP_SKELETON | DROP_CORPSE | BASEANGBAND | MORTAL | HAS_LITE
+S:1_IN_4 |
+S:ARROW_2 | MISSILE | BO_COLD | BO_ELEC | BLINK | S_ANIMAL
+D:A warrior who is at one with nature. A master of both bow and sword, with
+D:minor spellcasting skills.
+
+N:346:Paladin
+G:p:w
+I:110:15d11:20:40:40
+W:20:1:1700:55
+E:1:1:1:2:1:1
+O:20:60:0:10
+B:HIT:HURT:4d5
+B:HIT:HURT:4d5
+F:MALE | GOOD | DROP_SKELETON | DROP_CORPSE |
+F:DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:BASEANGBAND | MORTAL | HAS_LITE
+S:1_IN_4 |
+S:HEAL | CAUSE_2 | SLOW | SCARE | BLIND
+D:A warrior for a holy cause. Unfortunately, his god is not yours, and there is
+D:rivalry even between the various gods of Good, so he is your enemy.
+
+N:347:Werewolf
+G:C:D
+I:110:20d22:15:30:70
+W:20:2:900:150
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d10
+F:RAND_25 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON |
+F:ANIMAL | EVIL | MORTAL | BASEANGBAND
+D:It is a huge wolf with eyes that glow with manly intelligence.
+
+N:348:Dark elven lord
+G:h:s
+I:120:18d15:20:40:30
+W:20:2:1400:500
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d5
+F:MALE | FORCE_SLEEP |
+F:ONLY_ITEM | DROP_2D2 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:HASTE | BLIND | CONF | DARKNESS | BO_FIRE | BO_COLD | MISSILE
+D:A dark elven figure in armour and radiating evil power.
+
+N:349:Cloud giant
+G:P:b
+I:110:35d20:20:60:50
+W:36:1:9000:500
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:ELEC:8d8
+B:HIT:ELEC:8d8
+F:DROP_90 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | GIANT | IM_ELEC | MALE | BASEANGBAND | HAS_LITE
+D:It is a twenty foot tall giant wreathed in clouds.
+
+N:350:Ugluk, the Uruk
+G:o:v
+I:110:72d10:20:95:20
+W:21:3:2400:600
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_FIRE | IM_COLD | IM_POIS
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A strong and cunning orc warrior, the commander of Saruman's orcish horde.
+
+N:351:Blue dragon bat
+G:b:b
+I:130:4d4:12:26:50
+W:21:1:100:54
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:ELEC:1d3
+F:FORCE_SLEEP |
+F:RAND_50 |
+F:BASH_DOOR | CAN_FLY |
+F:ANIMAL | IM_ELEC | AI_ANNOY
+F:MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:BR_ELEC
+D:It is a glowing blue bat with a sharp tail.
+
+N:352:Mimic
+G:m:y
+I:110:10d14:30:40:0
+W:21:3:100:70
+E:0:0:0:0:0:0
+O:20:20:20:20
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+B:HIT:HURT:2d3
+B:HIT:HURT:2d3
+F:MIMIC |
+F:FORCE_SLEEP | NEVER_MOVE |
+F:EMPTY_MIND | COLD_BLOOD | SUSCEP_FIRE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BLIND | CONF | SCARE | CAUSE_2 | BO_FIRE |
+S:S_MONSTER
+D:A strange creature that disguises itself as an object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:353:Ultimate Mimic
+G:m:y
+I:110:15d40:30:40:0
+W:35:4:100:250
+E:0:0:0:0:0:0
+O:25:25:25:25
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+B:BUTT:CONFUSE:4d4
+B:SPIT:BLIND:4d4
+F:MIMIC |
+F:FORCE_SLEEP | NEVER_MOVE |
+F:EMPTY_MIND | COLD_BLOOD
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BLIND | CONF | SCARE | CAUSE_2 | BA_POIS |
+S:S_MONSTER
+D:A strange creature that disguises itself as an object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+
+N:354:Fire vortex
+G:v:r
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:FIRE:3d3
+F:FORCE_SLEEP | RAND_50 | CAN_FLY | WILD_VOLCANO | WILD_TOO | SUSCEP_COLD |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | AURA_FIRE |
+F:IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | HAS_LITE
+F:NO_CUT
+S:1_IN_6 |
+S:BR_FIRE
+D:A whirling maelstrom of fire.
+
+N:355:Acid vortex
+G:v:s
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:ACID:3d3
+F:FORCE_SLEEP | RAND_50 |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | CAN_FLY |
+F:IM_ACID | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_ACID
+D:A caustic spinning whirlpool of foaming, steaming water.
+
+N:356:Lugdush, the Uruk
+G:o:v
+I:110:66d10:20:90:20
+W:21:4:2500:550
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A large and powerful orc, captain of one of Saruman's orcish regiments.
+
+N:357:Arch-vile
+G:u:W
+I:130:11d11:100:30:0
+W:21:1:100:300
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:3d9
+B:CLAW:HURT:3d9
+F:RAND_50 | EVIL | DEMON | FORCE_SLEEP | FORCE_MAXHP |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | COLD_BLOOD |
+F:IM_FIRE | RES_NETH | NO_CONF | NO_SLEEP | NONLIVING | NO_STUN |
+F:ZANGBAND
+S:1_IN_3 |
+S:BA_FIRE | ANIM_DEAD
+D:A pale, corpse-like lesser demon, who moves very fast and spawns evil
+D:everywhere.
+
+N:358:Cold vortex
+G:v:w
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:COLD:3d3
+F:FORCE_SLEEP | RAND_50 | AURA_COLD | COLD_BLOOD | SUSCEP_FIRE |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | CAN_FLY |
+F:IM_COLD | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_COLD
+D:A twisting whirlpool of frost.
+
+N:359:Energy vortex
+G:v:b
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:ELEC:3d3
+F:FORCE_SLEEP | RAND_50 | CAN_FLY | HAS_LITE |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | AURA_ELEC |
+F:IM_ELEC | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_ELEC
+D:A shimmering tornado of air, sparks crackle along its length.
+
+N:360:Globefish
+G:~:w
+I:110:10d10:20:30:30
+W:21:1:600:111
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:POISON:10d5
+B:BITE:POISON:10d5
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | AQUATIC |
+F:IM_POIS | NO_STUN | WILD_TOO | COLD_BLOOD |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:BR_POIS
+D:This fish is among the most poisonous creatures there are.
+
+N:361:Giant firefly
+G:I:r
+I:120:3d2:8:18:10
+W:24:4:100:4
+B:BITE:BLIND:1d2
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:WEIRD_MIND | ANIMAL | BASEANGBAND
+S:MULTIPLY
+D:Clouds of these monsters light up the dungeon - so brightly that you can
+D:barely see through them.
+
+N:362:Mummified orc
+G:z:w
+I:110:15d8:20:28:75
+W:21:1:1700:56
+E:1:1:1:2:1:1
+O:10:70:0:10
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:DROP_90 |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is an orcish figure covered in wrappings.
+
+N:363:Wolf chieftain
+G:C:D
+I:120:22d22:20:20:5
+W:26:5:1000:120
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d10
+B:WAIL:TERRIFY
+F:ESCORTS | FORCE_MAXHP | IM_COLD | IM_ACID |
+F:SMART | ESCORT | ANIMAL | EVIL | MORTAL | BASEANGBAND |
+F:OPEN_DOOR | BASH_DOOR | NO_FEAR | MALE
+S:1_IN_8 | DARKNESS
+D:A great wolf-chieftain whose pack is in the service of the Dark Lord,
+D:and whose howls strike fear into even the boldest heart.
+
+N:364:Serpent man
+G:J:G
+I:120:15d10:20:40:20
+W:22:3:900:75
+E:1:1:1:2:1:1
+O:25:20:25:20
+B:BITE:POISON:5d5
+B:BITE:POISON:5d5
+F:MALE | CAN_SWIM | IM_POIS | IM_ACID |
+F:DROP_60 | DROP_2D2 | FRIENDS | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | EVIL | MORTAL | ZANGBAND
+S:1_IN_8
+S:BA_POIS | S_MONSTER | SCARE | HOLD
+D:"They walked lithely and sinuously erect on pre-mammalian
+D:members, their pied and hairless bodies bending with great
+D:suppleness. There was a loud hissing of formulae as they
+D:went to and fro."
+
+N:365:Vampiric mist
+G:#:D
+I:110:10d8:12:55:30
+W:22:1:0:40
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:EXP_20:1d6
+B:ENGULF:EXP_20:1d6
+F:RAND_25 | SUSCEP_ELEC | UNDEAD |
+F:IM_COLD | IM_POIS | IM_ACID | RES_NETH | WILD_TOO | WILD_SWAMP |
+F:EVIL | EMPTY_MIND | COLD_BLOOD | FRIENDS | BASEANGBAND | NO_CUT
+D:A cloud of evil, sentient mist.
+
+N:366:Killer stag beetle
+G:K:g
+I:110:15d8:12:55:30
+W:22:1:500:80
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d12
+B:CLAW:HURT:1d12
+F:RAND_25 | WILD_TOO | DROP_CORPSE |
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:It is a giant beetle with vicious claws.
+
+N:367:Iron golem
+G:g:s
+I:110:80d12:12:80:10
+W:22:2:3800:160
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d12
+F:FORCE_SLEEP | SUSCEP_ACID |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:SLOW
+D:It is a massive metal statue that moves steadily towards you.
+
+N:368:Auto-roller
+G:g:s
+I:120:70d12:10:80:12
+W:22:2:0:230
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:1d8
+B:CRUSH:HURT:1d8
+B:CRUSH:HURT:1d8
+B:CRUSH:HURT:1d8
+F:FORCE_SLEEP | RES_TELE
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
+F:NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | JOKEANGBAND | NO_CUT
+D:It looks like a huge spiked roller, moving on its own towards you.
+
+N:369:Giant yellow scorpion
+G:S:y
+I:110:12d8:12:38:20
+W:22:1:1200:60
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:STING:POISON:2d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:It is a giant scorpion with a sharp stinger.
+
+N:370:Jade monk
+G:p:G
+I:120:10d9:22:45:5
+W:23:1:1200:100
+E:1:1:1:2:1:1
+O:30:0:60:10
+B:KICK:HURT:4d1
+B:KICK:HURT:4d1
+B:HIT:HURT:4d5
+B:HIT:HURT:4d5
+F:OPEN_DOOR | BASH_DOOR | NO_FEAR | NO_CONF | NO_SLEEP |
+F:MALE | DROP_60 | DROP_1D2 | IM_FIRE | IM_COLD | IM_POIS |
+F:DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | ZANGBAND | HAS_LITE
+D:A monk trained in martial arts.
+
+N:371:Black ooze
+G:j:D
+I:90:6d8:10:6:1
+W:23:1:400:7
+E:0:0:0:0:0:0
+O:30:0:40:15
+B:TOUCH:ACID:2d6
+F:RAND_50 | DROP_60 | STUPID | EMPTY_MIND | CAN_SWIM |
+F:TAKE_ITEM | KILL_BODY | OPEN_DOOR | BASH_DOOR |
+F:IM_POIS | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+S:1_IN_11 |
+S:DRAIN_MANA
+D:It is a strangely moving puddle.
+
+N:372:Hardened warrior
+G:p:u
+I:110:15d11:20:40:40
+W:23:1:1900:60
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d5
+B:HIT:HURT:6d5
+F:MALE |
+F:DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:A scarred warrior who moves with confidence.
+
+N:373:Azog, King of the Uruk-Hai
+G:o:v
+I:120:94d10:20:80:20
+W:23:5:2700:1111
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:5d6
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT | ESCORTS | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is also known as the King of Khazad-dum. His ego is renowned to be
+D:bigger than his head.
+
+N:374:Fleshhound of Khorne
+G:C:R
+I:120:25d25:15:30:70
+W:30:3:700:150
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:4d1
+B:CLAW:HURT:4d1
+B:BITE:HURT:6d1
+B:BITE:HURT:6d1
+F:BASH_DOOR | DEMON | NO_STUN | NO_FEAR |
+F:ANIMAL | EVIL | IM_FIRE | NO_SLEEP | NO_CONF |
+F:RES_NETH | RES_NEXU | RES_DISE | RES_PLAS | ZANGBAND
+D:A revolting canine creature, a huge demon hound with a somewhat
+D:reptilian head.
+
+N:375:Dark elven warlock
+G:h:v
+I:120:7d10:20:16:20
+W:23:1:1700:75
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | FRIENDS
+F:EVIL | IM_POIS | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:CONF | MISSILE | DARKNESS | BO_MANA
+D:A dark elven mage with spells of frightening destructive power.
+
+N:376:Master rogue
+G:p:b
+I:120:15d9:20:30:40
+W:23:2:1600:110
+E:1:1:1:2:1:1
+O:80:10:10:0
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+B:HIT:EAT_GOLD:4d4
+F:MALE | DROP_SKELETON | DROP_CORPSE |
+F:DROP_2D2 | SUSCEP_ELEC |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:A thief of great power and shifty speed.
+
+N:377:Red dragon bat
+G:b:r
+I:130:3d8:12:28:50
+W:23:1:100:60
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:FIRE:1d3
+F:FORCE_SLEEP | RAND_50 | SUSCEP_COLD |
+F:BASH_DOOR | CAN_FLY | DROP_CORPSE | AI_ANNOY
+F:ANIMAL | IM_FIRE | BASEANGBAND
+S:1_IN_4 |
+S:BR_FIRE
+D:It is a sharp-tailed bat, wreathed in fire.
+
+N:378:Killer white beetle
+G:K:w
+I:110:18d8:14:55:30
+W:23:1:500:85
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:4d5
+F:RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:It is looking for prey.
+
+N:379:Ice skeleton
+G:s:w
+I:110:16d9:20:34:60
+W:23:1:0:70
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:CLAW:COLD:2d3
+B:CLAW:COLD:2d3
+F:ONLY_ITEM | DROP_90 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a skeleton covered in frost.
+
+N:380:Angamaite of Umbar
+G:p:U
+I:110:82d10:25:80:25
+W:24:2:2400:400
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:HIT:HURT:4d7
+B:HIT:HURT:4d7
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_ELEC
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:SLOW | FORGET
+D:A Black Numenorean who hates the men of the west.
+
+N:381:Forest wight
+G:W:g
+I:110:12d8:20:30:30
+W:24:1:0:140
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:TOUCH:EXP_20
+F:FORCE_SLEEP | RAND_25 |
+F:DROP_60 | DROP_90 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_10 |
+S:SCARE | DRAIN_MANA
+D:It is a ghostly apparition with a humanoid form.
+
+N:382:Khim, Son of Mim
+G:h:o
+I:110:84d10:20:80:10
+W:24:2:2300:300
+E:1:1:1:2:1:1
+O:10:80:0:10
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d7
+B:HIT:UN_BONUS
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_FIRE | IM_COLD
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:HEAL | SLOW | BO_FIRE
+D:One of the last of the Petty-Dwarves. Khim is a tricky sorcerous little
+D:being, full of mischief.
+
+N:383:Ibun, Son of Mim
+G:h:o
+I:110:84d10:20:80:10
+W:24:2:2300:300
+E:1:1:1:2:1:1
+O:10:80:0:5
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d7
+B:HIT:UN_BONUS
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_FIRE | IM_COLD
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:HEAL | SLOW | BO_FIRE
+D:One of the last of the Petty-Dwarves. Ibun is a tricky sorcerous little
+D:being, full of mischief.
+
+N:384:Meneldor the Swift
+G:B:u
+I:140:80d10:20:65:20
+W:24:6:1200:360
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:7d3
+B:CLAW:HURT:7d3
+B:BITE:HURT:3d7
+F:CAN_FLY | UNIQUE | FORCE_MAXHP | DROP_CORPSE | CAN_SPEAK |
+F:WILD_ONLY | WILD_MOUNTAIN | WILD_VOLCANO | PET |
+F:ANIMAL | GOOD | BASEANGBAND
+D:Among all the eagles of Middle-earth he is the swiftest, and in his time
+D:has borne messages between all of the Wise. It was Meneldor who bore the
+D:Ring-bearer away from the destruction of Mount Doom.
+
+N:385:Phantom beast
+G:G:B
+I:110:12d12:20:40:40
+W:24:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d33
+B:HIT:HURT:2d44
+F:PASS_WALL | NO_SLEEP | COLD_BLOOD | NONLIVING | NO_FEAR |
+F:FORCE_MAXHP | RES_TELE | EMPTY_MIND | CAN_FLY | BASEANGBAND | NO_CUT
+D:A creature that is half real, half illusion.
+
+N:386:Giant silver ant
+G:a:W
+I:110:9d8:10:38:40
+W:23:1:800:45
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ACID:4d4
+F:RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_SKELETON |
+F:ANIMAL | MORTAL | BASEANGBAND | HAS_LITE
+D:A giant silver ant with a caustic bite.
+
+N:387:4-headed hydra
+G:M:y
+I:120:100d6:20:70:20
+W:24:2:5000:450
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+F:FORCE_SLEEP |
+F:ONLY_GOLD | DROP_4D2 | WILD_TOO | WILD_SWAMP | WILD_SHORE |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_7 |
+S:SCARE
+D:A strange reptilian creature with four heads, guarding its hoard.
+
+N:388:Lesser hell-beast
+G:U:s
+I:115:15d100:10:100:50
+W:24:4:4000:400
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:TERRIFY:1d4
+B:GAZE:TERRIFY:1d4
+B:CRUSH:HURT:44d1
+F:EVIL | IM_ACID | IM_ELEC | IM_FIRE | IM_POIS | IM_COLD |
+F:RES_NETH | RES_WATE | RES_PLAS | RES_DISE | RES_NEXU |
+F:KILL_WALL | FORCE_MAXHP | CAN_SWIM | DROP_CORPSE | JOKEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:TPORT | BLINK | TELE_AWAY
+D:This creature just might crush you.
+
+N:389:Tyrannosaur
+G:R:g
+I:120:200d3:20:70:20
+W:24:2:5000:350
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d6
+B:CLAW:HURT:1d6
+B:BITE:HURT:3d6
+B:BITE:HURT:3d6
+F:FORCE_SLEEP |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | DROP_CORPSE |
+F:ANIMAL | MORTAL | ZANGBAND
+D:A horror from prehistory, reawakened by chaos.
+
+N:390:Mummified human
+G:z:w
+I:110:17d9:20:34:60
+W:24:1:1500:70
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:ONLY_ITEM | DROP_90 |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a human form encased in mouldy wrappings.
+
+N:391:Vampire bat
+G:b:D
+I:120:9d10:12:40:50
+W:24:2:50:150
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:EXP_40:1d4
+B:BITE:EXP_40:1d4
+F:RAND_50 | COLD_BLOOD | REGENERATE | CAN_FLY |
+F:EVIL | ANIMAL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A blood-sucking bat that flies at your neck hungrily.
+
+N:392:Sangahyando of Umbar
+G:p:U
+I:110:82d10:25:80:25
+W:24:2:2400:400
+E:1:1:1:2:1:1
+O:0:90:10:0
+B:HIT:HURT:4d7
+B:HIT:HURT:4d7
+B:HIT:HURT:4d7
+B:HIT:HURT:4d7
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_ELEC
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:SLOW | FORGET
+D:A Black Numenorean with a blacker heart.
+
+N:393:It
+G:.:W
+I:110:77d9:25:80:25
+W:24:3:500:400
+E:0:0:0:0:0:0
+O:10:0:90:0
+B:GAZE:BLIND:8d8
+B:TOUCH:TERRIFY
+B:GAZE:EXP_40
+B:TOUCH:EAT_ITEM
+F:ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD | DROP_GREAT | DROP_CORPSE |
+F:CHAR_MULTI | CHAR_CLEAR | ATTR_CLEAR | INVISIBLE | COLD_BLOOD |
+F:NO_CONF | UNIQUE | FORCE_MAXHP | NO_SLEEP | CAN_SPEAK | REFLECTING |
+F:IM_FIRE | IM_ELEC | EMPTY_MIND | EVIL | SMART | RES_TELE | CAN_FLY |
+F:ZANGBAND
+S:1_IN_4
+S:DRAIN_MANA | BLINK | BLIND | SCARE | CONF | S_UNDEAD | S_MONSTER |
+S:HEAL | TELE_AWAY | DARKNESS | S_HYDRA | TRAPS | FORGET | TELE_TO | SHRIEK
+D:Nobody has ever seen It.
+
+N:394:Banshee
+G:G:b
+I:120:6d8:20:24:10
+W:24:2:0:60
+E:0:0:0:0:0:0
+O:80:0:0:15
+B:WAIL:TERRIFY
+B:TOUCH:EXP_20
+F:FEMALE |
+F:RAND_50 | DROP_1D2 |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_15 |
+S:TPORT | DRAIN_MANA
+D:It is a ghostly woman's form that wails mournfully.
+
+N:395:Carrion crawler
+G:c:o
+I:110:20d12:15:40:10
+W:25:2:700:60
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:STING:PARALYZE:2d6
+B:STING:PARALYZE:2d6
+F:RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | DROP_SKELETON |
+F:ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+D:A hideous centipede covered in slime and with glowing tentacles around its
+D:head.
+
+N:396:Xiclotlan
+G:#:D
+I:110:25d13:15:60:10
+W:25:2:6000:60
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:6d4
+B:CRUSH:HURT:6d4
+B:BITE:HURT:3d2
+F:RAND_25 | SUSCEP_ACID |
+F:EMPTY_MIND | BASH_DOOR |
+F:IM_POIS | IM_ELEC |
+F:MORTAL | CTHANGBAND | NO_CUT
+D:"...a metallically grey tree... about sixteen feet high with
+D:very thick cylindrical branches... cylinders further
+D:divided into six flat circular extensions... and from the top
+D:of what I had taken for a trunk rose a featureless oval... an
+D:orifice gaping at the top."
+
+N:397:Silent watcher
+G:g:s
+I:110:80d25:60:80:0
+W:35:3:4000:800
+E:3:0:3:3:2:0
+O:0:0:0:0
+B:GAZE:TERRIFY
+B:GAZE:PARALYZE
+B:GAZE:LOSE_STR
+B:GAZE:HALLU
+F:EMPTY_MIND | COLD_BLOOD | NONLIVING | NEVER_MOVE |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | EVIL |
+F:HURT_ROCK | COLD_BLOOD | HURT_LITE | NO_FEAR |
+F:NO_CONF | NO_SLEEP | NO_STUN | NONLIVING | RES_TELE | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:SHRIEK | S_MONSTER | S_MONSTERS | HOLD | CONF | MIND_BLAST | DRAIN_MANA
+D:A figure carved from stone, with three vulture faces whose eyes glow
+D:with a malevolent light. None escape its vigilance.
+
+N:398:Pukelman
+G:g:D
+I:110:80d12:12:80:10
+W:25:3:10000:600
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d12
+B:HIT:HURT:3d6
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:SLOW | CONF | BO_ACID
+D:A stumpy figure carved from stone, with glittering eyes.
+
+N:399:Disenchanter beast
+G:q:v
+I:110:30d30:12:60:12
+W:25:2:2000:250
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:TOUCH:UN_BONUS:1d10
+B:TOUCH:UN_BONUS:1d10
+B:TOUCH:UN_BONUS:1d10
+B:TOUCH:UN_BONUS:1d10
+F:STUPID | WEIRD_MIND | RES_DISE | DROP_CORPSE | ATTR_MULTI |
+F:IM_ACID | IM_POIS |
+F:NO_CONF | ZANGBAND
+D:It looks like an anteater, and there is a static feeling
+D:crackling around its long trunk.
+
+N:400:Dark elven druid
+G:h:G
+I:120:20d20:15:75:10
+W:25:3:1200:500
+E:1:1:1:2:1:1
+O:10:0:80:10
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+B:HIT:HURT:3d8
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL | CONF | DARKNESS |
+S:S_MONSTER | S_SPIDER | S_ANIMAL
+D:A powerful dark elf, with mighty nature-controlling enchantments.
+
+N:401:Stone troll
+G:T:W
+I:110:23d10:20:50:50
+W:25:1:5000:85
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:HURT:3d4
+F:MALE |
+F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | TROLL | HURT_LITE | HURT_ROCK | BASEANGBAND | NO_CUT
+D:He is a giant troll with scabrous black skin.
+
+N:402:Black
+G:j:d
+I:111:12d12:12:65:30
+W:25:1:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:EXP_40:2d6
+B:ENGULF:EXP_40:2d6
+F:RAND_25 |
+F:IM_COLD | IM_POIS | IM_ACID | RES_NETH |
+F:EVIL | EMPTY_MIND | COLD_BLOOD | FRIENDS | CTHANGBAND | NO_CUT
+D:The eldritch blood of Yibb-Tstll is know only as "the Black": it is
+D:an amorphous substance, which will suck your life and deliver it to
+D:Yibb-Tstll.
+
+N:403:Hill troll
+G:T:s
+I:110:21d10:20:65:40
+W:21:1:4000:75
+E:1:1:1:2:1:1
+O:30:70:0:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+B:BITE:HURT:2d6
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_WASTE | WILD_MOUNTAIN |
+F:DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE | REGENERATE |
+F:EVIL | TROLL | HURT_LITE | BASEANGBAND
+D:A large troll with an extremely tough and warty hide.
+
+N:404:Wereworm
+G:w:u
+I:110:100d11:15:70:20
+W:25:3:6000:300
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:GAZE:EXP_20
+B:CRAWL:ACID:2d4
+B:BITE:HURT:1d10
+B:BITE:POISON:1d6
+F:BASH_DOOR | EVIL | CAN_SWIM | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | IM_ACID | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A huge wormlike shape dripping acid, twisted by evil sorcery into a foul
+D:monster that breeds on death.
+
+N:405:Killer red beetle
+G:K:r
+I:110:20d8:14:50:30
+W:25:1:600:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:LOSE_STR:4d4
+F:RAND_25 | WILD_TOO |
+F:WEIRD_MIND | BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:A giant beetle with poisonous mandibles.
+
+N:406:Disenchanter bat
+G:b:v
+I:130:6d8:12:28:50
+W:26:4:50:75
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:HIT:UN_BONUS
+B:HIT:UN_BONUS
+F:FORCE_SLEEP | RAND_50 | ANIMAL | MORTAL | ATTR_MULTI |
+F:DROP_CORPSE | AI_ANNOY | CAN_FLY | BASEANGBAND | WEIRD_MIND
+D:A giant bat which feeds on raw magical energy.
+
+N:407:Gnoph-Keh
+G:q:s
+I:110:20d8:12:50:25
+W:26:2:1500:95
+E:0:1:0:2:1:0
+O:20:40:20:10
+B:CLAW:COLD:2d4
+B:CLAW:COLD:2d4
+B:BUTT:HURT:2d9
+F:RAND_25 | DROP_90 | DROP_60
+F:OPEN_DOOR | BASH_DOOR | AURA_COLD | IM_COLD | SUSCEP_FIRE |
+F:ANIMAL | DROP_CORPSE | CTHANGBAND
+S:1_IN_8
+S:BR_COLD | BO_ICEE | BO_COLD | BA_COLD
+D:A creature with a sharp horn: "the hairy myth-thing of the
+D:Greenland ice, that walked sometimes on two legs, sometimes
+D:on four, and sometimes on six."
+
+N:408:Giant grey ant
+G:a:s
+I:110:19d8:10:40:40
+W:26:1:700:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d12
+F:RAND_25 | KILL_BODY | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | BASEANGBAND
+D:It is an ant encased in shaggy grey fur.
+
+N:409:Khufu, the Mummified King
+G:z:v
+I:110:85d11:20:40:40
+W:26:4:1800:500
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:GAZE:TERRIFY
+B:HIT:DISEASE:6d6
+B:CLAW:LOSE_CON:4d4
+B:CLAW:LOSE_CON:4d4
+F:UNIQUE | MALE | CAN_SPEAK | UNDEAD | EVIL | ESCORTS | ESCORT |
+F:FORCE_MAXHP | COLD_BLOOD | IM_POIS | IM_COLD | NO_FEAR | NO_CONF | NO_SLEEP |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | RES_TELE | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:TRAPS | CAUSE_3 | DARKNESS | S_UNDEAD | SCARE | SLOW |
+S:S_KIN | ANIM_DEAD
+D:He is out to have revenge on those who have desecrated his tomb.
+
+N:410:Gwaihir the Windlord
+G:B:u
+I:130:85d10:20:65:20
+W:24:6:1200:360
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:15d2
+B:CLAW:HURT:15d2
+B:BITE:HURT:3d10
+F:CAN_FLY | UNIQUE | FORCE_MAXHP | DROP_CORPSE | CAN_SPEAK |
+F:WILD_ONLY | WILD_MOUNTAIN | WILD_VOLCANO | PET |
+F:ANIMAL | GOOD | BASEANGBAND
+D:The greatest of eagles in the Third Age of Middle-earth, Gwaihir rescued
+D:Gandalf the Wizard from Orthanc, and has twice brought his flock to the
+D:aid of Sauron's enemies in battle - first outside the gates of Erebor in
+D:the Battle of Five Armies, and then before the Black Gate of Mordor itself.
+
+N:411:Giant fire tick
+G:S:R
+I:110:16d8:14:54:20
+W:26:2:200:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:3d6
+F:RAND_25 | SUSCEP_COLD |
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_FIRE | CAN_FLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is smoking and burning with great heat.
+
+N:412:Displacer beast
+G:f:b
+I:110:25d10:35:100:20
+W:26:2:1800:100
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d8
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+F:INVISIBLE | BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is a huge black panther, clubbed tentacles sprouting from its shoulders.
+
+N:413:Ulwarth, Son of Ulfang
+G:p:U
+I:110:85d10:20:40:40
+W:26:4:1800:500
+E:1:1:1:2:1:1
+O:40:60:0:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_MAXHP | WILD_TOO |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A short and swarthy Easterling.
+
+N:414:Werebear
+G:q:D
+I:110:25d25:20:50:20
+W:24:2:0:200
+E:0:1:0:2:1:0
+O:25:25:25:20
+B:CLAW:HURT:1d10
+B:CLAW:HURT:1d10
+B:BITE:HURT:2d8
+B:CRUSH:HURT:2d6
+F:BASH_DOOR | OPEN_DOOR |
+F:WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:ANIMAL | EVIL | DROP_1D2 | BASEANGBAND
+D:In the eyes of this bear, there glimmers the faintest light of intelligence.
+D:And then its form begins to change... The combination of animal cunning,
+D:human intelligence and the great physical strength of the bear makes for
+D:a dangerous enemy.
+
+N:415:Cave ogre
+G:O:u
+I:110:30d9:20:33:30
+W:26:2:2500:80
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:FRIENDS | DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A giant orc-like figure with an awesomely muscled frame.
+
+N:416:White wraith
+G:W:w
+I:110:15d8:20:40:10
+W:26:1:0:175
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:TOUCH:EXP_20
+F:FORCE_SLEEP |
+F:DROP_1D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:SCARE | CAUSE_2 | DARKNESS
+D:It is a tangible but ghostly form made of white fog.
+
+N:417:Angel
+G:A:o
+I:110:30d10:30:60:255
+W:26:4:2600:220
+E:1:1:1:2:1:1
+O:0:40:60:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:FORCE_MAXHP | FORCE_SLEEP | NO_FEAR |
+F:ONLY_ITEM | DROP_2D2 | GOOD | CAN_FLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:IM_ACID | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BLIND | CONF | SCARE | FORGET
+D:Who knows why you are now facing an angel as an enemy? Is it a punishment
+D:from your own god for your sins, or a test of your mettle, or has this angel
+D:been sent by another god on behalf of someone who wishes to claim the glory
+D:for his own god? Perhaps you will never know: but it is here, and you must
+D:fight it.
+
+N:418:Ghoul
+G:z:U
+I:110:15d9:30:30:20
+W:25:1:0:95
+E:1:1:1:2:1:1
+O:0:45:35:10
+B:CLAW:DISEASE:1d4
+B:CLAW:DISEASE:1d4
+B:BITE:PARALYZE:1d5
+F:DROP_60 | OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:EVIL | UNDEAD | FRIENDS | IM_POIS | IM_COLD | NO_CONF | NO_SLEEP |
+F:COLD_BLOOD | HURT_LITE | BASEANGBAND | NO_CUT
+S:1_IN_9
+S:SCARE | HOLD
+D:Flesh is falling off in chunks from this decaying abomination.
+
+N:419:Mim, Betrayer of Turin
+G:h:o
+I:120:11d105:20:80:20
+W:27:4:1200:1000
+E:1:1:1:2:1:1
+O:10:80:10:0
+B:HIT:HURT:3d9
+B:HIT:HURT:3d9
+B:HIT:HURT:3d9
+B:HIT:UN_BONUS:3d12
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | FORCE_SLEEP | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_DISE | RES_TELE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL | SCARE | BO_ACID | BA_ACID | TPORT | S_MONSTER
+D:The last of his race, Mim is a Petty-Dwarf. Petty-Dwarves are strange
+D:creatures, powerful in sorcery and originating in the East. They have
+D:been hunted nearly to extinction by the High Elves.
+
+N:420:Hellblade
+G:|:v
+I:120:13d13:20:40:20
+W:27:2:0:130
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:EXP_20:2d13
+B:HIT:EXP_20:2d13
+F:CHAR_MULTI | EVIL | IM_POIS | IM_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | SUSCEP_ACID |
+F:COLD_BLOOD | BASH_DOOR | NONLIVING |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+D:A deadly blade of chaos, moving of its own volition.
+
+N:421:Killer fire beetle
+G:K:R
+I:110:22d8:14:45:30
+W:27:1:600:95
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:SPIT:FIRE:4d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_VOLCANO | DROP_CORPSE |
+F:ANIMAL | IM_FIRE | CAN_FLY | SUSCEP_COLD |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle wreathed in flames.
+
+N:422:Beast of Nurgle
+G:q:y
+I:110:15d7:14:50:30
+W:27:2:2300:100
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:TOUCH:POISON:3d3
+B:TOUCH:DISEASE:3d3
+B:BITE:ACID:4d5
+F:WEIRD_MIND | BASH_DOOR | IM_ACID | IM_POIS |
+F:DEMON | EVIL | IM_FIRE | CAN_FLY | ZANGBAND
+D:It walks on four legs, but mostly resembles a slug-shaped jelly.
+D:It even has two disgusting antennae in its head. Yecch!
+
+N:423:Creeping adamantite coins
+G:$:G
+I:120:20d25:5:50:10
+W:27:3:0:60
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:POISON:3d4
+B:TOUCH:POISON:3d5
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+F:ONLY_GOLD | DROP_90 | DROP_2D2 |
+F:COLD_BLOOD | BASH_DOOR | CHAR_MULTI |
+F:IM_ELEC | IM_ACID | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of coins made of precious adamant, slithering toward
+D:you on lots of tiny legs.
+
+N:424:Algroth
+G:T:o
+I:110:21d12:20:60:40
+W:27:1:6000:150
+E:1:1:1:2:1:1
+O:10:80:0:10
+B:CLAW:POISON:3d3
+B:CLAW:POISON:3d3
+B:BITE:HURT:1d6
+F:FRIENDS | DROP_60 | WILD_WOOD | WILD_MOUNTAIN | WILD_TOO | WILD_SWAMP |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | REGENERATE |
+F:EVIL | TROLL | BASEANGBAND
+D:A powerful troll form. Venom drips from its needlelike claws.
+
+N:425:Flamer of Tzeentch
+G:,:r
+I:110:60d15:10:70:20
+W:27:2:0:500
+E:1:0:1:2:0:0
+O:0:0:0:0
+B:ENGULF:FIRE:3d6
+B:ENGULF:FIRE:3d6
+F:FORCE_SLEEP | BASH_DOOR | SUSCEP_COLD |
+F:IM_FIRE | IM_POIS | AURA_FIRE | DEMON | EVIL | RES_PLAS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | ZANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BO_FIRE | BA_FIRE
+D:It looks like an inverted mushroom, with two flexible arms.
+
+N:426:Roper
+G:#:D
+I:115:30d10:30:60:255
+W:27:5:0:235
+E:0:0:0:6:0:0
+O:0:0:0:0
+B:CRUSH:PARALYZE:3d5
+B:CRUSH:PARALYZE:3d5
+B:CRUSH:PARALYZE:3d5
+B:CRUSH:PARALYZE:3d5
+F:FORCE_MAXHP | FORCE_SLEEP | NO_FEAR | NEVER_MOVE |
+F:ONLY_GOLD | DROP_2D2 | DROP_60 | DROP_1D2 | EVIL |
+F:IM_ACID | IM_POIS | NO_CONF | NO_SLEEP | IM_COLD | IM_FIRE | BASEANGBAND
+F:NO_CUT
+S:1_IN_5 |
+S:BA_FIRE | BA_ELEC | BA_POIS | HASTE |
+S:TRAPS | SHRIEK | HOLD | CONF
+D:This creature look like a pillar of rock. However, a closer
+D:inspection reveals a glaring eye and powerful tentacles,
+D:which crush its prey and feed it to the creature's hungry
+D:mouth.
+
+N:427:Headless
+G:H:u
+I:110:25d12:20:50:40
+W:27:1:1600:175
+E:1:1:1:2:0:1
+O:0:100:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:FRIENDS | DROP_60 | OPEN_DOOR | BASH_DOOR | WILD_TOO |
+F:WILD_MOUNTAIN | WILD_WASTE | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | ZANGBAND
+S:1_IN_6
+S:SCARE
+D:Headless humanoid abominations created by a magical mutation.
+
+N:428:Vibration hound
+G:Z:y
+I:110:25d10:30:30:0
+W:27:2:600:250
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_SOUN
+D:A blurry canine form which seems to be moving as fast as the eye can
+D:follow. You can feel the earth resonating beneath your feet.
+
+N:429:Nexus hound
+G:Z:v
+I:110:25d10:30:30:0
+W:27:2:600:250
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP | RES_NEXU | DROP_SKELETON | DROP_CORPSE |
+F:FRIENDS |
+F:BASH_DOOR |
+F:ANIMAL | RES_TELE | NO_SLEEP | MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_NEXU
+D:A locus of conflicting points coalesce to form the vague shape of a huge
+D:hound. Or is it just your imagination?
+
+N:430:Half-ogre
+G:O:o
+I:110:35d9:20:33:30
+W:27:2:2700:80
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+F:FRIENDS | DROP_60 | DROP_CORPSE | SMART |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A giant, brutish figure, as ugly as an orc, but with some of the
+D:intelligence of his half-human ancestry.
+
+N:431:Lokkak, the Ogre Chieftain
+G:O:v
+I:120:15d103:20:100:20
+W:32:2:3000:1500
+E:1:1:1:2:1:1
+O:5:85:0:5
+B:HIT:HURT:6d7
+B:HIT:HURT:6d7
+B:HIT:HURT:6d7
+F:UNIQUE | MALE | CAN_SPEAK | WILD_TOO | WILD_SWAMP | WILD_SHORE |
+F:FORCE_MAXHP | ESCORT |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:EVIL | GIANT | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:An ogre renowned for acts of surprising cruelty, Lokkak is the leader of a large
+D:band of violent ogres.
+
+N:432:Vampire
+G:V:W
+I:110:25d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is a humanoid with an aura of power. You notice a sharp set of front
+D:teeth.
+
+N:433:Gorgimaera
+G:H:o
+I:110:25d20:12:55:10
+W:27:2:2300:400
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BUTT:HURT:2d10
+B:BITE:FIRE:2d10
+B:GAZE:PARALYZE:2d6
+F:FORCE_SLEEP | SUSCEP_COLD |
+F:BASH_DOOR | CAN_FLY | DROP_CORPSE |
+F:IM_FIRE | BASEANGBAND
+S:1_IN_8 |
+S:BR_FIRE
+D:The result of evil experiments, this travesty of nature should never be
+D:alive. It has three heads - goat, dragon and gorgon - all attached to a
+D:lion's body.
+
+N:434:Shantak
+G:H:D
+I:120:25d20:12:55:10
+W:27:2:6000:280
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+B:BITE:HURT:1d6
+B:BITE:HURT:1d6
+F:ANIMAL | IM_ACID | EVIL | ELDRITCH_HORROR | CAN_FLY | DROP_CORPSE |
+F:MORTAL | ZANGBAND
+S:1_IN_6
+S:SCARE | HASTE
+D:A scaly bird larger than an elephant, with a horse-like head.
+
+N:435:Colbran
+G:g:y
+I:120:80d12:12:80:10
+W:27:2:0:900
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:ELEC:3d8
+B:HIT:ELEC:3d8
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | CAN_FLY |
+F:IM_ELEC | IM_POIS | AURA_ELEC | REFLECTING |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BO_ELEC
+D:A man-shaped form of living lightning, sparks and shocks crackle all over
+D:this madly capering figure, as it leaps and whirls around and about you.
+
+N:436:Spirit naga
+G:n:w
+I:110:30d15:20:75:120
+W:28:2:0:60
+E:0:0:0:0:1:0
+O:20:0:80:0
+B:CRUSH:HURT:2d8
+B:CRUSH:HURT:2d8
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+F:FEMALE |
+F:FORCE_SLEEP | CAN_FLY |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | DROP_CORPSE |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:HEAL | BLIND | MIND_BLAST | DARKNESS
+D:A wraithly snake-like form with the torso of a beautiful woman, it is the
+D:most powerful of its kind.
+
+N:437:Corpser
+G:,:D
+I:112:30d15:20:75:120
+W:28:2:0:65
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:2d8
+B:CRUSH:HURT:2d8
+B:CRUSH:HURT:2d8
+B:CRUSH:HURT:2d8
+F:WILD_TOO | WILD_GRASS |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:MORTAL | ZANGBAND
+D:A creature who lives underground and eats surface dwellers that it catches
+D:with its poisonous tentacle, which is the only part of the creature that
+D:is ever seen. Perhaps it is better not to see the part which remains
+D:underground...
+
+N:438:Fiend of Slaanesh
+G:S:R
+I:120:15d20:12:50:40
+W:28:4:0:225
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:STING:POISON:8d1
+B:STING:LOSE_STR:8d1
+B:WAIL:TERRIFY:1d4
+F:BASH_DOOR |
+F:EVIL | DEMON | ZANGBAND
+D:Slaanesh's pet, a large scorpion-like creature with a human face and
+D:reptile skin.
+
+N:439:Stairway to Hell
+G:>:W
+I:120:15d8:90:40:20
+W:28:5:0:125
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:WAIL:UN_BONUS
+B:WAIL:EXP_20
+B:WAIL:EAT_GOLD
+B:WAIL:EAT_ITEM
+F:CHAR_MULTI | COLD_BLOOD | EVIL | NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING |
+F:UNDEAD | FORCE_MAXHP | IM_FIRE | IM_ELEC | IM_POIS | IM_ACID | EMPTY_MIND
+F:NEVER_MOVE | JOKEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_15
+S:S_DEMON | SHRIEK
+D:Often found in graveyards.
+
+N:440:5-headed hydra
+G:M:g
+I:120:100d8:20:80:20
+W:28:2:5500:650
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+F:FORCE_SLEEP |
+F:ONLY_GOLD | DROP_1D2 | DROP_4D2 | DROP_SKELETON | DROP_CORPSE
+F:BASH_DOOR | MOVE_BODY | CAN_SWIM |
+F:ANIMAL | IM_POIS | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:SCARE | BA_POIS
+D:A strange reptilian creature with five heads dripping venom.
+
+N:441:Barney the Dinosaur
+G:R:v
+I:120:110d9:10:90:20
+W:29:2:5000:500
+E:0:1:0:2:1:0
+O:10:0:90:0
+B:SHOW:LOSE_INT
+B:SHOW:LOSE_WIS
+B:CHARGE:EAT_GOLD
+B:CHARGE:EAT_GOLD
+F:DROP_1D2 | DROP_90 | DROP_GOOD | DROP_GREAT | ONLY_ITEM |
+F:EVIL | MALE | CAN_SPEAK | SMART | RES_TELE | CAN_SWIM | DROP_CORPSE
+F:ANIMAL | IM_POIS | FORCE_MAXHP | UNIQUE | FORCE_SLEEP
+F:MORTAL | JOKEANGBAND
+S:1_IN_3
+S:SHRIEK | CONF | S_HYDRA | SLOW | BLIND | DRAIN_MANA
+S:BA_POIS | BR_CHAO | FORGET | DARKNESS | BR_NUKE
+D:The lovable purple reptile is making a guest appearance here.
+
+N:442:Black knight
+G:p:s
+I:120:30d10:20:70:10
+W:28:1:2400:240
+E:1:1:1:2:1:1
+O:0:90:10:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:MALE |
+F:FORCE_SLEEP | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:BLIND | SCARE | CAUSE_3 | DARKNESS
+D:He is a figure encased in deep black plate armour; he looks at you
+D:menacingly.
+
+N:443:Seahorse
+G:~:o
+I:120:111d7:20:60:20
+W:28:2:3000:360
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:PARALYZE:4d5
+B:BITE:LOSE_DEX:4d5
+B:BITE:LOSE_CON:4d5
+F:FORCE_SLEEP | AQUATIC | GOOD | ANIMAL |
+F:IM_COLD | IM_POIS | IM_FIRE | IM_ELEC | WILD_TOO | WILD_OCEAN
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BO_WATE | BO_COLD | BO_ICEE | BO_MANA
+D:Your mind is filled with admiration as you view this wondrous,
+D:magical seahorse.
+
+N:444:Cyclops
+G:P:u
+I:120:60d20:20:90:20
+W:45:2:3500:1500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:9d9
+B:HIT:HURT:9d9
+F:FORCE_SLEEP |
+F:DROP_1D2 | TAKE_ITEM | WILD_TOO | WILD_SHORE | WILD_MOUNTAIN |
+F:BASH_DOOR | OPEN_DOOR | MOVE_BODY | DROP_CORPSE |
+F:EVIL | IM_POIS | IM_ACID | IM_FIRE | IM_COLD | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:ARROW_4
+D:A gigantic humanoid with but one eye.
+
+N:445:Clairvoyant
+G:p:y
+I:120:25d10:100:50:10
+W:28:3:1600:250
+E:1:1:1:2:1:1
+O:0:0:90:10
+B:HIT:CONFUSE:5d5
+B:HIT:TERRIFY:5d5
+F:MALE |
+F:FORCE_SLEEP | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | SMART |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:BLIND | MIND_BLAST | HOLD | CAUSE_3 | FORGET | S_MONSTER
+D:He is using his supernatural talents to bring about your
+D:destruction.
+
+N:446:Purple worm
+G:w:v
+I:110:65d8:14:65:30
+W:29:4:1000:400
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:BITE:ACID:2d8
+B:STING:POISON:1d8
+F:BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | IM_ACID | IM_POIS | CAN_SWIM |
+F:MORTAL | BASEANGBAND
+D:It is a massive worm form, many feet in length. Its vast maw drips acid
+D:and poison.
+
+N:447:Catoblepas
+G:q:g
+I:110:30d10:15:55:40
+W:29:2:0:400
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:TERRIFY:2d4
+B:GAZE:BLIND:2d4
+B:BUTT:HURT:2d6
+B:BITE:HURT:2d12
+F:ONLY_GOLD | DROP_2D2 | DROP_CORPSE
+F:BASH_DOOR | CAN_SWIM | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | IM_POIS
+F:MORTAL | BASEANGBAND
+D:A strange ox-like form with a huge head but a thin, weak neck, it looks
+D:like the creation of some deranged alchemist.
+
+N:448:Lesser wall monster
+G:#:W
+I:110:13d8:20:75:40
+W:28:4:0:600
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+F:FORCE_SLEEP | COLD_BLOOD | EMPTY_MIND | KILL_WALL | RAND_50 |
+F:BASH_DOOR | IM_COLD | IM_ACID | IM_FIRE | IM_ELEC | IM_POIS | NONLIVING |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | CHAR_MULTI | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:A sentient, moving section of wall.
+
+N:449:Mage
+G:p:r
+I:110:15d8:20:40:10
+W:28:1:1500:150
+E:1:1:1:2:1:1
+O:10:0:90:0
+B:HIT:HURT:2d5
+B:HIT:HURT:2d5
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HASTE | TPORT | TELE_TO | BLIND | CONF |
+S:BO_FIRE | BO_COLD | BO_ELEC |
+S:S_MONSTER
+D:A fat mage with glasses. And considerable power, too - as you can
+D:tell from the size of his hat.
+
+N:450:Mind flayer
+G:h:v
+I:110:15d10:20:60:10
+W:28:1:1400:200
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:CRUSH:LOSE_INT:2d6
+B:GAZE:INSANITY:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:ONLY_ITEM | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:BLIND | HOLD | SCARE | MIND_BLAST | BRAIN_SMASH | FORGET
+D:A humanoid form with a gruesome head, tentacular mouth, and piercing
+D:eyes. Claws reach out for you and you feel a presence invade your mind.
+
+N:451:The Ultimate Dungeon Cleaner
+G:g:D
+I:120:70d12:10:80:12
+W:28:2:0:555
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:2d10
+B:CRUSH:HURT:2d10
+B:CRUSH:HURT:2d10
+B:CRUSH:HURT:2d10
+F:FORCE_SLEEP | FORCE_MAXHP | KILL_BODY | KILL_ITEM | UNIQUE | REFLECTING |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
+F:NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | RES_TELE | JOKEANGBAND | NO_CUT
+D:It looks like a huge spiked roller. It was designed to keep this dungeon
+D:clean, and you are the biggest spot of dirt in sight.
+
+N:452:Deep one
+G:u:g
+I:120:35d12:20:50:20
+W:28:5:4000:150
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:CLAW:POISON:2d4
+B:CLAW:POISON:2d4
+B:BITE:HURT:4d4
+F:FRIENDS | WILD_TOO | WILD_SHORE | DROP_CORPSE |
+F:RAND_25 |
+F:DROP_60 | DROP_90 |
+F:CAN_SWIM | BASH_DOOR | ELDRITCH_HORROR | RES_TELE |
+F:EVIL | DEMON | IM_FIRE | IM_COLD | IM_POIS | RES_WATE | CTHANGBAND
+D:"I thought their predominant color was a greyish-green,
+D:though they had white bellies. They were mostly shiny and
+D:slippery, but the ridges of their backs were scaly. Their
+D:forms vaguely suggested the anthropoid, while their heads were
+D:the heads of fish, with prodigious bulging eyes that never
+D:closed. At the sides of their necks were palpitating gills and
+D:their long paws were webbed."
+
+N:453:Basilisk
+G:R:s
+I:120:20d30:15:90:30
+W:28:3:400:350
+E:0:1:0:2:1:0
+O:50:0:30:20
+B:GAZE:PARALYZE
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+F:ONLY_ITEM | DROP_1D2 | WILD_TOO | WILD_MOUNTAIN |
+F:OPEN_DOOR | BASH_DOOR | EVIL | IM_POIS | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP | CAN_SWIM |
+F:MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:BR_POIS
+D:An evil reptile that preys on unsuspecting travellers. Its eyes stare
+D:deeply at you and your soul starts to wilt!
+
+N:454:Ice troll
+G:T:w
+I:110:24d10:20:56:50
+W:28:1:5000:200
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+B:BITE:COLD:2d6
+B:BITE:COLD:2d6
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_WASTE | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE | REGENERATE |
+F:EVIL | TROLL | IM_COLD | HURT_LITE | BASEANGBAND
+D:He is a white troll with powerful clawed hands.
+
+N:455:Dhole
+G:w:s
+I:110:65d8:14:64:25
+W:29:4:1000:555
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:SPIT:ACID:1d8
+B:ENGULF:ACID:2d8
+B:CRUSH:HURT:4d8
+F:ANIMAL | EVIL | KILL_WALL | IM_ACID | ELDRITCH_HORROR |
+F:CAN_SWIM | FORCE_MAXHP | DROP_CORPSE |
+F:MORTAL | CTHANGBAND
+S:1_IN_6
+S:BR_ACID
+D:A gigantic worm dripping with acid. "...even as he looked, one
+D:reared up several hundred feet and leveled a bleached, viscous end
+D:at him."
+
+N:456:Archangel
+G:A:B
+I:110:60d10:30:68:255
+W:34:4:4000:1000
+E:1:1:1:2:1:1
+O:0:40:60:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:FORCE_MAXHP | FORCE_SLEEP | NO_FEAR | GOOD |
+F:ONLY_ITEM | DROP_2D2 | CAN_FLY |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | RES_TELE |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | HASTE | BLIND | CONF | SCARE
+D:A lesser angel protected by an aura of holiness. Its muscular form looks
+D:extremely powerful next to your own frail body.
+
+N:457:Greater Mimic
+G:m:y
+I:120:10d35:30:60:100
+W:29:3:100:200
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+F:MIMIC |
+F:FORCE_SLEEP | NEVER_MOVE | SUSCEP_ACID |
+F:EMPTY_MIND | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLIND | CONF | SCARE | CAUSE_2 | FORGET |
+S:BO_ACID | BO_FIRE | BO_COLD | BO_ELEC |
+S:S_MONSTER
+D:A strange creature that disguises itself as an object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:458:Chaos tile
+G:.:v
+I:120:3d5:30:60:100
+W:29:6:100:200
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:POISON:3d4
+B:HIT:CONFUSE:3d4
+F:CHAR_MULTI | ATTR_MULTI | ATTR_ANY |
+F:FORCE_SLEEP | NEVER_MOVE |
+F:EMPTY_MIND | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | ZANGBAND | NO_CUT
+S:MULTIPLY |
+S:1_IN_4 |
+S:BLIND | CONF | SCARE | CAUSE_2 | BLINK | S_MONSTER
+D:It is a floor tile corrupted by chaos.
+
+N:459:Young blue dragon
+G:d:b
+I:110:27d10:20:50:70
+W:29:1:20000:500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:DROP_2D2 | DROP_CORPSE | ATTR_MULTI
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_ELEC | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_ELEC
+D:It has a form out of legend. Its still-tender scales are a
+D:deep blue in hue. Sparks crackle along its length.
+
+N:460:Young white dragon
+G:d:w
+I:110:27d10:20:50:70
+W:29:1:20000:500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN | WILD_WASTE |
+F:DROP_2D2 | DROP_CORPSE | ATTR_MULTI
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY | SUSCEP_FIRE |
+F:EVIL | DRAGON | IM_COLD | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_COLD
+D:It has a form out of legend. Its still-tender scales are a
+D:frosty white in hue. Icy blasts of cold air come from it as it breathes.
+
+N:461:Young green dragon
+G:d:g
+I:110:27d10:20:50:70
+W:29:1:20000:500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN | WILD_SWAMP |
+F:DROP_2D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_POIS | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_POIS
+D:It has a form out of legend. Its still-tender scales are a
+D:deep green in hue. Foul gas seeps through its scales.
+
+N:462:Young bronze dragon
+G:d:U
+I:110:27d10:20:50:70
+W:29:1:20000:500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN |
+F:DROP_2D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | NO_CONF | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_CONF
+D:It has a form out of legend. Its still-tender scales are a
+D:rich bronze hue, and its shape masks its true form.
+
+N:463:Aklash
+G:T:R
+I:110:30d8:14:64:25
+W:29:4:4000:300
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:1d6
+B:CLAW:HURT:1d6
+B:BITE:POISON:1d20
+B:CRUSH:HURT:2d9
+F:TROLL | EVIL | FRIENDS | OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:IM_POIS | IM_ACID | REGENERATE | ZANGBAND | REGENERATE |
+S:1_IN_9 | BR_POIS
+D:Pale, bald, fat, hairless troll creatures. Ugly beyond description.
+D:Not to mention how bad their breath smells...
+
+N:464:Mithril golem
+G:g:B
+I:110:80d15:12:100:10
+W:30:4:10000:500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:ONLY_GOLD | DROP_2D2 |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | REFLECTING |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+D:It is a massive statue of purest mithril. It looks expensive!
+
+N:465:Skeleton troll
+G:s:W
+I:110:20d10:20:55:20
+W:30:1:5000:225
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:HURT:3d4
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | TROLL | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a troll skeleton animated by dark dweomers.
+
+N:466:Skeletal tyrannosaur
+G:R:w
+I:120:50d10:20:55:20
+W:30:2:6000:225
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:LOSE_CON:4d6
+B:GAZE:TERRIFY
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | ANIMAL | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | ZANGBAND | NO_CUT
+D:It is the skeleton of a tyrannosaur, animated by dark dweomers.
+
+N:467:Beorn, the Shape-Changer
+G:q:D
+I:120:20d70:25:60:25
+W:28:3:0:1000
+E:0:1:0:2:1:0
+O:20:60:20:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d8
+B:CRUSH:HURT:3d6
+F:UNIQUE | MALE | FORCE_MAXHP | FORCE_SLEEP |
+F:BASH_DOOR | ANIMAL | MOVE_BODY | SMART | PET
+F:WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | BASEANGBAND
+S:1_IN_6 | S_ANIMAL
+D:Beorn is only occasionally seen in human form these days, preferring to
+D:appear in the shape of a giant black bear: he also prefers the company of
+D:beasts to that of humans. He has never taken kindly to strangers, even in
+D:human form - and still less when in bear's shape, as he is now.
+
+N:468:Thorondor, Lord of Eagles
+G:B:u
+I:130:85d12:20:65:20
+W:30:6:1600:555
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:16d2
+B:CLAW:HURT:16d2
+B:BITE:HURT:4d10
+F:CAN_FLY | UNIQUE | FORCE_MAXHP | DROP_CORPSE | CAN_SPEAK |
+F:WILD_ONLY | WILD_MOUNTAIN | WILD_VOLCANO | PET |
+F:ANIMAL | GOOD | BASEANGBAND
+D:Among the mightiest of birds, Thorondor is the messenger of the Valar, and
+D:brings news of Middle-earth to Valinor itself. Nothing that can be seen
+D:from the airs of the world is hidden from him.
+
+N:469:Giant blue ant
+G:a:b
+I:110:8d8:10:50:60
+W:30:2:600:80
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ELEC:5d5
+F:RAND_25 | WILD_TOO | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_ELEC
+F:MORTAL | BASEANGBAND
+D:It is a giant ant that crackles with energy.
+
+N:470:Grave wight
+G:W:b
+I:110:12d10:20:50:30
+W:30:1:0:325
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+B:TOUCH:EXP_20
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_1D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | CAN_FLY |
+F:IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:SCARE | CAUSE_3 | DARKNESS
+D:It is a ghostly form with eyes that haunt you.
+
+N:471:Shadow drake
+G:d:G
+I:110:30d10:20:70:70
+W:33:3:18000:1100
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:EXP_10:3d6
+F:FORCE_SLEEP | FORCE_MAXHP | PASS_WALL |
+F:ONLY_ITEM | DROP_3D2 | CAN_FLY | DROP_CORPSE |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:BR_NETH | SLOW | CONF | SCARE | DARKNESS
+D:It is a dragon-like form wrapped in shadow. Glowing red eyes shine in
+D:the dark, and it is surrounded by an aura of unearthly cold that chills
+D:the soul rather than the body.
+
+N:472:Manticore
+G:H:y
+I:120:25d10:12:15:10
+W:30:2:1900:300
+E:1:1:1:2:1:0
+O:0:0:0:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:BASH_DOOR | CAN_FLY | WILD_TOO | WILD_WOOD | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:ARROW_4
+D:It is a winged lion's body with a human torso and a tail covered in
+D:vicious spikes.
+
+N:473:Giant army ant
+G:a:o
+I:120:19d6:10:40:40
+W:30:3:600:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d12
+F:RAND_25 | KILL_BODY | FRIENDS | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL
+F:MORTAL | BASEANGBAND
+D:An armoured form moving with purpose. Powerful on its own, flee when
+D:hordes of them march.
+
+N:474:Killer slicer beetle
+G:K:y
+I:110:25d10:14:60:30
+W:30:2:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:5d8
+B:BITE:HURT:5d8
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_GRASS | DROP_CORPSE
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:It is a beetle with deadly sharp cutting mandibles and a rock-hard
+D:carapace.
+
+N:475:Gorgon
+G:H:b
+I:110:30d20:12:88:20
+W:31:2:3000:275
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BUTT:HURT:3d9
+B:BUTT:HURT:3d9
+B:BITE:POISON:1d10
+B:KICK:HURT:2d4
+F:FORCE_SLEEP | ANIMAL | MOVE_BODY | WILD_TOO | WILD_WOOD |
+F:BASH_DOOR | IM_POIS | IM_ACID | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:BR_POIS
+D:A bull-like creature whose skin is made of steel plates. Watch out for
+D:its deadly breath!
+
+N:476:Gug
+G:P:G
+I:110:22d11:14:60:30
+W:31:2:1500:210
+E:2:0:2:4:1:1
+O:0:50:50:0
+B:BITE:HURT:10d4
+B:CLAW:HURT:2d7
+B:CLAW:HURT:2d7
+B:CLAW:HURT:2d7
+F:FORCE_SLEEP |
+F:DROP_1D2 | TAKE_ITEM |
+F:BASH_DOOR | OPEN_DOOR | DROP_CORPSE
+F:EVIL | IM_POIS | IM_ACID | GIANT | ZANGBAND
+D:A hideous, beastly, four-armed unclean giant: "...large as a
+D:barrel... The eyes jutted two inches from each side, shaded by
+D:bony protuberances overgrown of the mouth. That mouth had great
+D:yellow fangs and ran from the top to the tally."
+
+N:477:Ghost
+G:G:w
+I:120:13d8:20:30:10
+W:31:1:0:350
+E:0:0:0:0:0:0
+O:30:40:0:20
+B:WAIL:TERRIFY
+B:TOUCH:EXP_20
+B:CLAW:LOSE_INT:1d6
+B:CLAW:LOSE_WIS:1d6
+F:FORCE_SLEEP | RAND_25 | DROP_60 | DROP_1D2 |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | CAN_FLY |
+F:IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | DRAIN_MANA
+D:You don't believe in them.
+
+N:478:Death watch beetle
+G:K:D
+I:110:25d12:16:60:30
+W:31:3:800:220
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:5d4
+B:WAIL:TERRIFY:5d6
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:It is a giant beetle that produces a chilling sound.
+
+N:479:Mountain ogre
+G:O:s
+I:110:40d9:20:33:30
+W:30:2:3000:100
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:5d8
+B:HIT:HURT:5d8
+F:FRIENDS | DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:The largest breed of ogre, he is awesomely strong and awesomely ugly.
+
+N:480:Nexus quylthulg
+G:Q:v
+I:110:10d12:10:1:0
+W:32:1:3000:300
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | RES_NEXU | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | RES_TELE | BASEANGBAND
+S:1_IN_1 |
+S:BLINK | TELE_AWAY
+D:It is a very unstable, strange pulsing mound of flesh.
+
+N:481:Shelob, Spider of Darkness
+G:S:D
+I:120:35d100:30:120:80
+W:55:3:1400:27000
+E:0:1:0:2:1:0
+O:20:30:40:0
+B:CLAW:POISON:5d6
+B:CLAW:POISON:5d6
+B:BITE:PARALYZE:5d10
+B:STING:LOSE_STR:5d4
+F:UNIQUE | FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP | SPECIAL_GENE |
+F:ESCORT | ESCORTS | DROP_CORPSE |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD | DROP_RANDART
+F:SMART | BASH_DOOR | IM_POIS | IM_ACID |
+F:ANIMAL | SPIDER | EVIL | HURT_LITE | NO_SLEEP | BASEANGBAND
+S:1_IN_4 |
+S:HEAL | BLIND | SLOW | CONF | SCARE | CAUSE_3 | CAUSE_4 |
+S:TRAPS | BR_DARK | BR_POIS |
+S:S_SPIDER
+D:Shelob is an enormous bloated spider, the last daughter of Ungoliant the
+D:Unlight. Her poison is legendary, as is her ego. She normally guards the
+D:pass through Cirith Ungol, but occasionally goes out foraging for food to
+D:feed her voracious appetite.
+
+N:482:Giant squid
+G:~:g
+I:110:80d10:8:80:80
+W:32:3:3000:600
+E:3:0:3:6:1:0
+O:0:0:0:0
+B:CRUSH:HURT:8d4
+B:CRUSH:HURT:8d4
+B:CRUSH:HURT:8d4
+F:IM_ACID | RES_WATE | AQUATIC | ANIMAL | IM_COLD | MOVE_BODY
+F:FORCE_MAXHP | WILD_TOO | WILD_OCEAN | BASEANGBAND | COLD_BLOOD
+S:1_IN_8
+S:BR_ELEC | BR_ACID | BR_POIS
+D:Besides being capable of dragging whole ships underwater,
+D:this creature can also harm you with ranged attacks.
+
+N:483:Ghoulking
+G:z:D
+I:120:40d12:20:60:10
+W:32:2:0:340
+E:1:1:1:2:1:1
+O:20:40:30:0
+B:CLAW:LOSE_STR:3d4
+B:CLAW:DISEASE:3d4
+B:CLAW:DISEASE:3d4
+B:BITE:PARALYZE:3d5
+F:DROP_60 | OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:DROP_1D2 | FORCE_MAXHP | ESCORT | FORCE_SLEEP |
+F:EVIL | UNDEAD | IM_POIS | IM_COLD | NO_CONF | NO_SLEEP |
+F:COLD_BLOOD | HURT_LITE | BASEANGBAND | NO_CUT
+S:1_IN_7
+S:SCARE | HOLD | DARKNESS | SCARE | S_UNDEAD | ANIM_DEAD
+D:Flesh is falling off in chunks from this decaying abomination.
+
+N:484:Doombat
+G:b:R
+I:120:24d14:16:75:30
+W:32:2:150:250
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:FIRE:5d4
+B:BITE:FIRE:5d4
+B:BITE:FIRE:5d4
+F:WEIRD_MIND | BASH_DOOR | AURA_FIRE | CAN_FLY | DROP_CORPSE |
+F:IM_FIRE | AI_ANNOY |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is a fast moving creature of chaos, a gigantic black bat
+D:surrounded by flickering bright red flames.
+
+N:485:Ninja
+G:p:u
+I:120:13d12:20:60:10
+W:32:2:1600:300
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:POISON:3d4
+B:HIT:LOSE_STR:3d4
+B:HIT:LOSE_STR:3d4
+F:MALE |
+F:DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A humanoid clothed in black who moves with blinding speed.
+
+N:486:Memory moss
+G:,:b
+I:110:1d2:30:1:5
+W:32:3:50:150
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:CONFUSE:1d4
+B:HIT:CONFUSE:1d4
+F:FORCE_SLEEP | NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:FORGET
+D:A mass of vegetation. You don't remember seeing anything like it
+D:before.
+
+N:487:Storm giant
+G:P:B
+I:110:40d20:20:60:40
+W:40:1:13000:1000
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:ELEC:10d8
+B:HIT:ELEC:10d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_1D2 | WILD_TOO | WILD_MOUNTAIN |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | AURA_ELEC | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | GIANT | IM_COLD | IM_ELEC | MALE | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:BLINK | TELE_TO | CONF | SCARE | BO_ELEC | BA_ELEC
+D:It is a twenty-five foot tall giant wreathed in lightning.
+
+N:488:Spectator
+G:e:B
+I:110:15d13:30:1:5
+W:28:2:1600:150
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:PARALYZE:1d4
+B:GAZE:CONFUSE:1d4
+B:BITE:HURT:1d8
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:STUPID | EMPTY_MIND | CAN_FLY | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND
+S:1_IN_6 |
+S:FORGET | CAUSE_2 | HOLD | SLOW
+D:A lesser relative of the beholder: a globular body with a large toothy mouth,
+D:a large central eye, and four smaller eyes on stalks protruding from the top
+D:of its body.
+
+N:489:Bokrug
+G:R:v
+I:110:11d90:20:70:50
+W:33:7:0:2200
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:BITE:HURT:5d5
+B:CRUSH:HURT:2d10
+B:CRUSH:HURT:2d10
+F:UNIQUE | CAN_SPEAK |
+F:FORCE_MAXHP | NONLIVING | NO_CONF | NO_FEAR |
+F:ESCORT | ESCORTS | ELDRITCH_HORROR |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:EVIL | IM_COLD | IM_POIS | DEMON | CTHANGBAND
+S:1_IN_5
+S:S_UNDEAD | MIND_BLAST | CAUSE_3 | SCARE | BO_WATE | S_KIN
+D:A lizard-like Great Old One worshipped by the men of Sarnath.
+
+N:490:Biclops
+G:P:u
+I:120:65d20:20:90:20
+W:48:5:3000:1700
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:10d9
+B:HIT:HURT:10d9
+F:FORCE_SLEEP |
+F:DROP_1D2 | TAKE_ITEM | DROP_CORPSE |
+F:BASH_DOOR | OPEN_DOOR | MOVE_BODY |
+F:EVIL | IM_POIS | IM_ACID | IM_FIRE | IM_COLD | GIANT |
+F:MORTAL | ZANGBAND | HAS_LITE
+S:1_IN_8 |
+S:ARROW_4
+D:Oh, no! Aaargh! It is the most unnatural, most disgusting
+D:creature imaginable: a two-eyed cyclops! This perversion
+D:of nature must be exterminated!
+
+N:491:Half-troll
+G:T:U
+I:110:25d14:20:50:50
+W:34:2:3000:400
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:CLAW:HURT:1d5
+B:CLAW:HURT:1d5
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+F:MALE |
+F:FRIENDS |
+F:ONLY_ITEM | DROP_90 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | TROLL | IM_POIS | BASEANGBAND
+D:A huge, ugly, half-human in search of plunder.
+
+N:492:Ivory monk
+G:p:w
+I:120:38d9:22:55:5
+W:33:1:1600:900
+E:1:1:1:2:1:1
+O:40:0:50:10
+B:KICK:HURT:8d1
+B:HIT:HURT:8d4
+B:KICK:HURT:8d1
+B:HIT:HURT:8d4
+F:OPEN_DOOR | BASH_DOOR | NO_FEAR | NO_CONF | NO_SLEEP | DROP_SKELETON |
+F:DROP_CORPSE | MALE | DROP_60 | DROP_1D2 | IM_FIRE | IM_COLD | IM_POIS |
+F:MORTAL | ZANGBAND | HAS_LITE
+D:A monk trained in the most lethal martial arts.
+
+N:493:Bert the Stone Troll
+G:T:W
+I:120:11d100:20:70:50
+W:34:7:5000:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:BITE:HURT:3d10
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ESCORT | SPECIAL_GENE | MOVE_BODY | REGENERATE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | HURT_ROCK | BASEANGBAND | NO_CUT
+D:Big, brawny, powerful and with a taste for hobbit. He has friends called
+D:Bill and Tom.
+
+N:494:Bill the Stone Troll
+G:T:W
+I:120:11d100:20:70:50
+W:34:7:5000:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:BITE:HURT:3d10
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ESCORT | SPECIAL_GENE | MOVE_BODY | REGENERATE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | HURT_ROCK | BASEANGBAND | NO_CUT
+D:Big, brawny, powerful and with a taste for hobbit. He has friends called
+D:Bert and Tom.
+
+N:495:Tom the Stone Troll
+G:T:W
+I:120:11d100:20:70:50
+W:34:7:5000:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:BITE:HURT:3d10
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ESCORT | SPECIAL_GENE | MOVE_BODY | REGENERATE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | HURT_ROCK | BASEANGBAND | NO_CUT
+D:Big, brawny, powerful and with a taste for hobbit. He has friends called
+D:Bert and Bill.
+
+N:496:Cave troll
+G:T:u
+I:110:24d12:20:50:50
+W:33:1:6000:350
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+F:MALE |
+F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE | REGENERATE |
+F:EVIL | TROLL | IM_POIS | HURT_LITE | BASEANGBAND
+D:He is a vicious monster, feared for his ferocity.
+
+N:497:Anti-paladin
+G:p:D
+I:120:30d20:30:50:30
+W:33:2:2400:450
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:2d6
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:MALE | OPEN_DOOR | BASH_DOOR | TAKE_ITEM | DROP_1D2 | ONLY_ITEM |
+F:EVIL | IM_POIS | IM_COLD | NO_CONF | NO_SLEEP | DROP_SKELETON | DROP_CORPSE
+F:MORTAL | ZANGBAND | HAS_LITE
+S:1_IN_4
+S:HOLD | SCARE | BLIND | CAUSE_3 | TRAPS | DARKNESS | FORGET | HASTE
+D:An embodiment of all the cardinal vices, he beholds you scornfully.
+
+N:498:Chaos master
+G:p:v
+I:120:30d10:30:50:5
+W:37:3:2300:550
+E:1:1:1:2:1:1
+O:10:60:10:10
+B:HIT:HURT:10d2
+B:KICK:HURT:10d2
+B:PUNCH:HURT:10d2
+B:KICK:HURT:10d2
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | EVIL |
+F:ONLY_ITEM | DROP_1D2 | ATTR_ANY | DROP_SKELETON | DROP_CORPSE
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_POIS | NO_CONF | NO_SLEEP
+F:MORTAL | ZANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL |
+S:S_SPIDER | BA_CHAO | S_DEMON
+D:An adept of chaos, feared for his skill of invoking raw Chaos.
+
+N:499:Barrow wight
+G:W:v
+I:110:15d10:20:40:10
+W:33:3:0:375
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+B:TOUCH:EXP_40
+F:FORCE_SLEEP | FRIENDS | DROP_60 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:HOLD | SCARE | CAUSE_2 | DARKNESS
+D:It is a ghostly nightmare of an entity.
+
+N:500:Skeleton ettin
+G:s:W
+I:110:45d10:20:50:20
+W:33:1:7000:325
+E:1:1:1:2:2:1
+O:0:0:0:0
+B:HIT:HURT:1d9
+B:HIT:HURT:1d9
+B:BITE:HURT:1d5
+B:BITE:HURT:1d5
+F:FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | TROLL | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is the animated skeleton of a massive two-headed troll.
+
+N:501:Chaos drake
+G:d:v
+I:110:50d10:20:70:70
+W:33:3:18000:1400
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:ATTR_MULTI | ATTR_ANY | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | RES_DISE |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | DRAGON |
+F:IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_DISE | BR_CHAO
+D:A dragon twisted by the forces of chaos. It seems first ugly, then fair,
+D:as its form shimmers and changes in front of your eyes.
+
+N:502:Law drake
+G:d:B
+I:110:50d10:20:70:70
+W:33:3:18000:1400
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | CAN_FLY |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:DRAGON | EVIL |
+F:IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT | ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_SOUN | BR_SHAR
+D:This dragon is clever and cunning. It laughs at your puny efforts to
+D:disturb it.
+
+N:503:Balance drake
+G:d:v
+I:110:60d10:20:70:70
+W:33:3:18000:1600
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | RES_DISE |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE
+F:EVIL | DRAGON | CAN_FLY |
+F:IM_FIRE | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_SOUN | BR_SHAR | BR_DISE | BR_CHAO
+D:A mighty dragon, the balance drake seeks to maintain the Cosmic Balance,
+D:and despises your feeble efforts to destroy evil.
+
+N:504:Ethereal drake
+G:d:o
+I:110:40d10:20:70:70
+W:33:3:0:1200
+E:0:1:0:6:1:0
+O:40:50:10:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | CAN_FLY |
+F:INVISIBLE | PASS_WALL |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_LITE | BR_DARK | BR_CONF
+D:A dragon of great power with control over light and dark, the
+D:ethereal drake's eyes glare with white hatred from the shadows.
+
+N:505:Groo, the Wanderer
+G:p:U
+I:120:13d113:20:70:50
+W:35:7:5000:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:9d1
+B:HIT:HURT:6d5
+B:HIT:HURT:25d1
+B:HIT:HURT:6d5
+F:UNIQUE | MALE | WEIRD_MIND | CAN_SPEAK |
+F:FORCE_MAXHP | WILD_TOO | DROP_CORPSE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:DROP_CHOSEN |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_COLD | IM_POIS | ZANGBAND
+D:He who laughs at Groo's brains will find there is nothing to laugh
+D:about... erm, nobody laughs at Groo and lives.
+
+N:506:Fasolt the Giant
+G:P:u
+I:110:11d111:20:70:50
+W:33:4:10000:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:7d10
+B:HIT:HURT:7d10
+B:HIT:EAT_GOLD:2d10
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | WILD_TOO | DROP_CORPSE |
+F:ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | IM_COLD | IM_POIS | BASEANGBAND | HAS_LITE
+D:Big, brawny, powerful and with a greed for gold.
+
+N:507:Shade
+G:G:D
+I:120:14d20:20:30:10
+W:33:3:0:350
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:WAIL:TERRIFY
+B:TOUCH:EXP_40
+B:CLAW:LOSE_INT:1d10
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | CAN_FLY |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | DRAIN_MANA | FORGET
+D:A shadowy form clutches at you from the darkness. A powerful undead with
+D:a deadly touch.
+
+N:508:Spectre
+G:G:U
+I:120:14d20:20:30:10
+W:33:3:0:350
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:WAIL:TERRIFY
+B:TOUCH:EXP_40
+B:CLAW:LOSE_WIS:5d5
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | CAN_FLY |
+F:COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | DRAIN_MANA | FORGET
+D:A phantasmal shrieking spirit. Its wail drives the intense cold of pure
+D:evil deep within your body.
+
+N:509:Water troll
+G:T:B
+I:110:36d10:20:50:50
+W:35:1:4000:420
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d9
+B:HIT:HURT:1d9
+B:HIT:HURT:2d2
+B:HIT:HURT:2d2
+F:MALE | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:FRIENDS | DROP_60 | REGENERATE |
+F:OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | BASEANGBAND
+D:He is a troll that reeks of brackish water and mud.
+
+N:510:Fire elemental
+G:E:r
+I:110:30d8:12:50:50
+W:33:2:0:350
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:FIRE:4d6
+B:HIT:FIRE:4d6
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | CAN_FLY | WILD_TOO | WILD_VOLCANO |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL | AURA_FIRE |
+F:IM_FIRE | IM_POIS | IM_ELEC | IM_ACID |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BO_FIRE
+D:It is a towering inferno of flames.
+
+N:511:Cherub
+G:A:G
+I:120:100d10:30:68:255
+W:39:4:0:2700
+E:1:1:1:2:1:1
+O:0:90:10:0
+B:HIT:HURT:4d3
+B:HIT:HURT:3d8
+B:HIT:HURT:4d3
+B:HIT:HURT:3d8
+F:FORCE_SLEEP | FORCE_MAXHP | NO_FEAR | GOOD | CAN_FLY |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | REFLECTING | RES_TELE
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | HASTE | BLIND | SCARE | MIND_BLAST | BO_FIRE |
+S:S_MONSTERS
+D:It is an angel moving very quickly, wielding a holy war hammer and casting
+D:a volley of powerful spells in your direction.
+
+N:512:Water elemental
+G:E:b
+I:110:25d8:12:40:50
+W:33:2:0:325
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | COLD_BLOOD | CAN_FLY |
+F:KILL_BODY | KILL_ITEM | BASH_DOOR | POWERFUL |
+F:IM_POIS | IM_ACID | IM_FIRE | IM_COLD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BO_COLD
+D:It is a towering tempest of water.
+
+N:513:Multi-hued hound
+G:Z:v
+I:110:30d10:25:40:0
+W:33:3:600:600
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d4
+B:BITE:HURT:4d4
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | ATTR_MULTI | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:IM_ELEC | IM_POIS | IM_ACID | IM_FIRE | IM_COLD |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BR_ACID | BR_POIS | BR_COLD | BR_FIRE | BR_ELEC
+D:Shimmering in rainbow hues, this hound is beautiful and deadly.
+
+N:514:Invisible stalker
+G:E:y
+I:130:19d12:20:46:20
+W:35:3:0:300
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:RAND_50 |
+F:RES_TELE |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING
+F:BASEANGBAND | NO_CUT
+D:It is impossible to define its form but its violence is legendary.
+
+N:515:Carrion crawler
+G:c:o
+I:110:20d12:15:40:10
+W:34:2:2000:100
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:STING:PARALYZE:2d6
+B:STING:PARALYZE:2d6
+F:RAND_25 | FRIENDS | DROP_SKELETON |
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+D:A hideous centipede covered in slime and with glowing tentacles around its
+D:head.
+
+N:516:Master thief
+G:p:b
+I:130:18d10:20:30:40
+W:34:2:1300:350
+E:1:1:1:2:1:1
+O:90:10:0:0
+B:HIT:HURT:2d8
+B:HIT:HURT:3d4
+B:HIT:EAT_GOLD:4d4
+B:HIT:EAT_ITEM:4d5
+F:MALE |
+F:DROP_90 | DROP_2D2 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_6
+S:TRAPS | ARROW_2 | BLINK
+D:Cool and confident, fast and lithe; protect your possessions quickly!
+
+N:517:The Watcher in the Water
+G:~:v
+I:120:27d100:30:100:80
+W:45:3:7000:12000
+E:3:0:3:6:1:0
+O:50:50:0:0
+B:CRUSH:ACID:8d8
+B:CRUSH:POISON:8d8
+B:CRUSH:PARALYZE:8d8
+F:UNIQUE | FORCE_SLEEP | FORCE_MAXHP | CAN_SWIM | AQUATIC | ANIMAL |
+F:IM_ACID | IM_COLD | IM_POIS | RES_WATE | RES_TELE | DROP_CORPSE |
+F:NO_CONF | NO_FEAR | EVIL | COLD_BLOOD | BASEANGBAND |
+F:ONLY_ITEM | DROP_GOOD | DROP_4D2 | DROP_1D2 | SPECIAL_GENE | DROP_RANDART
+S:1_IN_5 | BA_WATE | BO_WATE | HOLD | BR_POIS | BO_ICEE | TELE_TO
+D:A vile creature which seems to consist mostly of tentacles, it seeks to
+D:drag people to their doom in the water. Few have ever escaped its grasp.
+
+N:518:Lich
+G:L:o
+I:110:30d10:20:60:60
+W:34:2:0:1000
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:TOUCH:EXP_40
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:2d8
+B:TOUCH:LOSE_DEX:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_1D2 |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLINK | TELE_TO | TELE_AWAY | BLIND | HOLD | SLOW | SCARE |
+S:CAUSE_3 | DRAIN_MANA | BRAIN_SMASH
+D:It is a skeletal form dressed in robes. It radiates vastly evil power.
+
+N:519:Gas spore
+G:e:g
+I:110:25d10:30:1:5
+W:34:4:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:DISEASE:30d2
+F:FORCE_SLEEP |
+F:STUPID | EMPTY_MIND | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:From a distance, this creature is often mistaken for the
+D:much more dangerous beholder.
+
+N:520:Master vampire
+G:V:g
+I:110:34d20:20:60:10
+W:36:1:1600:750
+E:1:1:1:2:1:1
+O:20:40:30:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:BITE:EXP_40:3d6
+B:BITE:EXP_40:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:TELE_TO | HOLD | CONF | SCARE | CAUSE_3 | MIND_BLAST | FORGET |
+S:DARKNESS | BO_NETH
+D:It is a humanoid form dressed in robes. Power emanates from its chilling
+D:frame.
+
+N:521:Oriental vampire
+G:V:s
+I:110:30d30:20:60:10
+W:40:3:0:750
+E:1:1:1:2:1:1
+O:10:45:35:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:BITE:EXP_40:3d6
+B:BITE:EXP_40:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_4D2 | CAN_FLY |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | INVISIBLE | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | RES_TELE |
+F:BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:TELE_TO | HOLD | CONF | SCARE | CAUSE_3 | MIND_BLAST | FORGET |
+S:DARKNESS | BO_NETH
+D:The oriental vampire can transform into a mist at will.
+
+N:522:Greater mummy
+G:z:y
+I:110:34d10:30:68:255
+W:36:3:0:800
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:CLAW:LOSE_CON:3d6
+B:CLAW:DISEASE:3d6
+B:GAZE:EXP_40:3d4
+B:GAZE:TERRIFY:3d4
+F:FORCE_SLEEP | FORCE_MAXHP | NO_FEAR | EVIL | UNDEAD |COLD_BLOOD |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | RES_TELE |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:HEAL | HASTE | BLIND | SCARE | S_UNDEAD | ANIM_DEAD |
+S:BA_POIS | BA_NETH | BA_COLD | DRAIN_MANA |
+S:MIND_BLAST | CAUSE_3 | DARKNESS | FORGET
+D:Once a powerful ruler, now an even more powerful undead menace.
+
+N:523:Bloodletter of Khorne
+G:U:r
+I:120:30d8:20:40:30
+W:34:1:0:450
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:EXP_20:13d1
+B:HIT:EXP_20:13d1
+B:HIT:EXP_20:13d1
+F:FORCE_MAXHP | OPEN_DOOR | FRIENDS | DROP_60 | REGENERATE |
+F:ONLY_ITEM | DROP_CHOSEN | NO_FEAR | NONLIVING |
+F:EVIL | IM_POIS | IM_COLD | IM_FIRE | DEMON | ZANGBAND | HAS_LITE
+D:Slender, red-skinned demons twisting in nightmarish shapes.
+D:They are armed with hellblades, which will suck the life from
+D:your body.
+
+N:524:Giant grey scorpion
+G:S:s
+I:120:18d20:12:50:40
+W:34:4:1200:275
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+B:STING:POISON:1d4
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_SKELETON |
+F:ANIMAL
+F:MORTAL | BASEANGBAND
+D:It is a giant grey scorpion. It looks poisonous.
+
+N:525:Earth elemental
+G:E:u
+I:100:30d10:10:60:90
+W:34:2:0:375
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD |
+F:KILL_ITEM | KILL_BODY | PASS_WALL | POWERFUL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:BO_ACID
+D:It is a towering form composed of rock with fists of awesome power.
+
+N:526:Air elemental
+G:E:B
+I:120:30d5:12:50:50
+W:34:2:0:390
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d10
+B:HIT:CONFUSE:1d4
+B:HIT:HURT:1d10
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | COLD_BLOOD | CAN_FLY |
+F:KILL_BODY | KILL_ITEM | BASH_DOOR | POWERFUL |
+F:IM_ACID | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:BO_ELEC
+D:It is a towering tornado of winds.
+
+N:527:Shimmering mold
+G:m:b
+I:110:32d8:2:24:70
+W:27:1:0:140
+B:SPORE:ELEC:5d4
+B:SPORE:ELEC:5d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_ELEC | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange growth on the dungeon floor, glowing and crackling with sparks.
+
+N:528:Gargoyle
+G:u:s
+I:110:18d12:10:50:15
+W:34:2:3000:110
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:1d6
+F:DROP_60 | ONLY_GOLD | EVIL | DEMON | FRIENDS | HURT_LITE |
+F:WILD_TOO | WILD_MOUNTAIN | WILD_WASTE |
+F:IM_POIS | IM_FIRE | IM_COLD | IM_ELEC | HURT_ROCK | NONLIVING |
+F:BASEANGBAND | NO_CUT
+S:1_IN_12
+S:BR_ELEC | BR_FIRE
+D:A weird demon creature with a stone-like skin.
+
+N:529:Malicious leprechaun
+G:h:v
+I:120:4d5:8:13:8
+W:35:4:1200:85
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:TOUCH:EAT_GOLD
+B:TOUCH:EAT_ITEM
+F:INVISIBLE | RAND_25 | TAKE_ITEM | COLD_BLOOD |
+F:HURT_LITE | EVIL | OPEN_DOOR | MALE |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY |
+S:1_IN_6 |
+S:BLINK | TPORT | TELE_TO | CAUSE_1
+D:This little creature has a fiendish gleam in its eyes.
+
+N:530:Eog golem
+G:g:u
+I:100:100d20:12:125:10
+W:34:4:12000:1200
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+F:ONLY_GOLD | DROP_2D2 |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | REFLECTING |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+D:It is a massive deep brown statue, striding towards you with an
+D:all-too-familiar purpose. Your magic surprisingly feels much less
+D:powerful now.
+
+N:531:Little Boy
+G:{:D
+I:120:12d12:10:80:12
+W:35:2:0:200
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:SHATTER:100d2
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | REFLECTING |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
+F:NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | RES_TELE | JOKEANGBAND | NO_CUT
+D:A shining machine of death and destruction.
+
+N:532:Dagashi
+G:p:u
+I:120:13d25:20:70:10
+W:35:4:1600:500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:POISON:3d4
+B:HIT:LOSE_STR:3d4
+B:HIT:LOSE_STR:3d4
+B:HIT:POISON:3d4
+F:MALE |
+F:DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A human warrior, moving with lightning speed.
+
+N:533:Headless ghost
+G:G:u
+I:120:20d25:20:30:10
+W:35:3:0:550
+E:0:0:0:0:0:0
+O:35:25:25:0
+B:TOUCH:TERRIFY
+B:TOUCH:EXP_40
+B:CLAW:LOSE_INT:5d5
+B:CLAW:LOSE_WIS:5d5
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | CAN_FLY |
+F:COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | DRAIN_MANA | SCARE | BO_COLD | FORGET
+D:A phantasmal apparition with no head.
+
+N:534:Dread
+G:G:o
+I:120:25d20:20:30:10
+W:35:2:0:600
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:LOSE_STR:3d4
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_60 | DROP_2D2 |
+F:TAKE_ITEM | INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | CAN_FLY |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | CONF | DRAIN_MANA | BO_NETH
+D:It is a form that screams its presence against the eye. Death incarnate,
+D:its hideous black body seems to struggle against reality as the universe
+D:itself struggles to banish it.
+
+N:535:Leng spider
+G:S:v
+I:120:16d20:12:50:40
+W:35:4:600:250
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d6
+B:STING:POISON:1d6
+F:WEIRD_MIND | BASH_DOOR | FRIENDS | ELDRITCH_HORROR | DROP_CORPSE |
+F:ANIMAL | SPIDER | CTHANGBAND
+D:Bloated purple spiders with long, bristly legs.
+
+N:536:Gauth
+G:e:s
+I:110:15d20:20:50:20
+W:36:2:1600:600
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:UN_BONUS:5d2
+B:GAZE:UN_BONUS:5d2
+B:GAZE:UN_POWER:5d2
+B:GAZE:UN_POWER:5d2
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE |
+F:BASH_DOOR | EVIL | BASEANGBAND | MORTAL
+S:1_IN_5 |
+S:CAUSE_2 | TELE_AWAY | BA_COLD | BO_ELEC | HOLD | DRAIN_MANA
+D:Another lesser relative of the beholder, this six-eyed creature feeds on magic.
+
+N:537:Smoke elemental
+G:E:R
+I:120:15d10:10:80:90
+W:36:3:0:375
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:HURT:2d6
+B:ENGULF:HURT:2d6
+F:FORCE_SLEEP |
+F:EMPTY_MIND |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | CAN_FLY | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:DARKNESS | BO_FIRE
+D:It is a towering blackened form, crackling with heat.
+
+N:538:Olog
+G:T:y
+I:110:42d10:20:50:50
+W:36:1:6000:450
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:BITE:HURT:2d3
+B:BITE:HURT:2d3
+F:FORCE_MAXHP | OPEN_DOOR | FRIENDS | DROP_60 | REGENERATE |
+F:SMART | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | TROLL | IM_POIS | BASEANGBAND
+D:It is a massive troll, more intelligent than most of its kind, with needle-
+D:sharp fangs.
+
+N:539:Halfling slinger
+G:h:U
+I:110:30d9:20:40:30
+W:35:1:900:330
+E:1:1:1:2:1:1
+O:100:0:0:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+F:FORCE_MAXHP | OPEN_DOOR | FRIENDS | DROP_90 |
+F:SMART | EVIL | IM_POIS | IM_COLD | MALE | DROP_SKELETON | DROP_CORPSE
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3
+S:ARROW_4
+D:A rebel halfling who has rejected the halfling tradition of archery.
+
+N:540:Gravity hound
+G:Z:W
+I:110:35d10:30:30:0
+W:35:2:700:500
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_GRAV
+D:Unfettered by the usual constraints of gravity, these unnatural creatures
+D:are walking on the walls and even the ceiling! The earth suddenly feels
+D:rather less solid as you see gravity warp all around these monsters.
+
+N:541:Acidic cytoplasm
+G:j:s
+I:120:40d10:12:18:1
+W:35:5:3000:180
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:FORCE_MAXHP | TAKE_ITEM | COLD_BLOOD |
+F:DROP_1D2 | DROP_4D2 | CAN_SWIM |
+F:STUPID | EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_FEAR | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:A disgusting animated blob of destruction. Flee its gruesome hunger!
+
+N:542:Inertia hound
+G:Z:W
+I:110:35d10:30:30:0
+W:35:2:700:500
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_INER
+D:Bizarrely, this hound seems to be hardly moving at all, yet it approaches
+D:you with deadly menace. It makes you tired just to look at it.
+
+N:543:Impact hound
+G:Z:u
+I:110:35d10:30:30:0
+W:35:2:700:500
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_WALL
+D:A deep brown shape is visible before you, its canine form striking you with
+D:an almost physical force. The dungeon floor buckles as if struck by a
+D:powerful blow as it stalks towards you.
+
+N:544:Shardstorm
+G:v:u
+I:120:32d10:40:12:0
+W:37:1:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:HURT:6d6
+F:FORCE_SLEEP | RAND_50 | NONLIVING | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:NO_FEAR | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BR_SHAR
+D:A howling blast of razor-sharp mountain fragments, kept intact by perilous
+D:magics.
+
+N:545:Ooze elemental
+G:E:g
+I:110:13d10:10:80:90
+W:36:3:0:300
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_ACID | IM_FIRE | CAN_SWIM | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BO_ACID | BA_ACID
+D:It is a towering mass of filth, an eyesore of ooze.
+
+N:546:Young black dragon
+G:d:s
+I:110:30d10:20:60:70
+W:31:1:20000:700
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_SWAMP |
+F:DROP_3D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_ACID | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_ACID
+D:It has a form out of legend. Its still-tender scales are a
+D:darkest black hue. Acid drips from its body.
+
+N:547:Mumak
+G:q:s
+I:110:90d10:20:55:100
+W:35:3:150000:2100
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BUTT:HURT:8d6
+B:BUTT:HURT:8d6
+B:CRUSH:HURT:8d4
+F:BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A massive elephantine form with eyes twisted by madness.
+
+N:548:Giant fire ant
+G:a:R
+I:110:20d10:14:49:40
+W:35:1:700:350
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+F:FORCE_MAXHP | KILL_BODY | FRIENDS | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR | SUSCEP_COLD |
+F:ANIMAL | IM_FIRE
+F:MORTAL | BASEANGBAND
+D:A giant ant covered in shaggy fur. Its powerful jaws glow with heat.
+
+N:549:Mature white dragon
+G:d:w
+I:110:40d10:20:70:70
+W:34:1:110000:1200
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_4D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_WASTE | WILD_MOUNTAIN |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | SUSCEP_FIRE | BASEANGBAND |
+F:HAS_LITE | ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_COLD
+D:A large dragon, scales gleaming bright white.
+
+N:550:Xorn
+G:X:u
+I:110:16d10:20:80:10
+W:36:2:30000:650
+E:0:0:0:3:0:0
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD |
+F:KILL_ITEM | PASS_WALL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:A huge creature of the element Earth. Able to merge with its element, it
+D:has four huge arms protruding from its enormous torso.
+
+N:551:Rogrog the Black Troll
+G:T:D
+I:120:15d100:20:70:50
+W:41:5:9000:5000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d7
+B:HIT:HURT:6d7
+B:BITE:HURT:4d10
+B:SPIT:ACID:4d8
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ESCORT | MOVE_BODY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | TROLL | IM_COLD | IM_POIS | BASEANGBAND
+D:A massive and cruel troll of great power, drool slides caustically down
+D:his muscular frame. Despite his bulk, he strikes with stunning speed.
+
+N:552:Mist giant
+G:#:B
+I:120:35d10:20:50:50
+W:36:2:0:450
+E:0:0:0:0:0:0
+O:10:90:0:0
+B:CRUSH:HURT:4d8
+B:CRUSH:HURT:4d8
+B:CRUSH:HURT:4d8
+B:BITE:EXP_40:3d9
+F:FORCE_MAXHP | OPEN_DOOR | DROP_60 | WILD_TOO | WILD_SWAMP |
+F:SMART | BASH_DOOR |
+F:EVIL | GIANT | IM_POIS | CAN_FLY | CTHANGBAND | NO_CUT
+D:"Two eyes, the colour of a thin, yellow wine, were set high in the
+D:thing's body; though it had no separate head. A mouthing, obscene slit,
+D:filled with fangs lay just beneath the eyes. It had no nose or ears...
+D:Four appendages sprang from its upper parts and its lower body
+D:slithered along the ground, unsupported by any limbs... incredibly
+D:disgusting to behold and its amorphous body gave off a stench of death
+D:and decay..."
+
+N:553:Phantom
+G:G:v
+I:120:20d25:30:30:20
+W:36:3:0:400
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:EXP_80
+B:TOUCH:EXP_40
+B:CLAW:LOSE_INT:1d10
+B:CLAW:LOSE_WIS:1d10
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_5 |
+S:FORGET | MIND_BLAST
+D:An unholy creature of darkness, the aura emanating from this evil being
+D:saps your very soul.
+
+N:554:Grey wraith
+G:W:s
+I:110:19d10:20:50:10
+W:36:1:0:700
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:TOUCH:EXP_40
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_60 | DROP_90 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | HURT_LITE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:HOLD | SCARE | CAUSE_3 | DARKNESS
+D:A tangible but ghostly form, made of grey fog. The air around it feels
+D:deathly cold.
+
+N:555:Revenant
+G:W:u
+I:110:2d111:20:50:10
+W:36:1:0:725
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:GAZE:PARALYZE
+B:CLAW:LOSE_CON:1d10
+B:CLAW:LOSE_CON:1d10
+B:GAZE:EXP_40
+F:FORCE_SLEEP | FORCE_MAXHP | REGENERATE |
+F:DROP_60 | DROP_90 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | HURT_LITE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:CONF | SCARE | CAUSE_3 | DARKNESS
+D:Back from the grave, to wreak vengeance upon the living. A skeletal figure
+D:wearing a black robe, with eyes that burn with undying hatred.
+
+N:556:Young multi-hued dragon
+G:d:v
+I:110:32d10:20:60:70
+W:32:1:20000:900
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:3d8
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:DROP_1D2 | DROP_3D2 | CAN_FLY |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC |
+F:IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:SCARE |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS
+D:It has a form out of legend. Beautiful scales of shimmering
+D:and magical colours cover it.
+
+N:557:Raal's Tome of Destruction
+G:?:r
+I:120:50d15:20:150:15
+W:36:4:0:1500
+E:0:0:0:0:0:0
+O:20:0:80:0
+F:NEVER_MOVE | NEVER_BLOW | NONLIVING |
+F:FORCE_SLEEP | DROP_90 | DROP_GOOD | EVIL | COLD_BLOOD | EMPTY_MIND |
+F:FORCE_MAXHP | NO_CONF | NO_FEAR | NO_SLEEP | CHAR_MULTI |
+F:IM_ACID | IM_POIS | IM_COLD | IM_ELEC | SUSCEP_FIRE | RES_NETH | RES_TELE |
+F:ZANGBAND | HAS_LITE | NO_CUT
+S:1_IN_2 |
+S:BO_ACID | BR_FIRE | BO_MANA | BR_COLD | BR_POIS |
+S:BO_WATE | BA_POIS | BR_NETH
+D:A sentient arcane tome casting spells with malevolent intent.
+
+N:558:Colossus
+G:g:G
+I:110:30d100:15:150:10
+W:36:4:35000:900
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+F:FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC |
+F:IM_POIS | NONLIVING | REFLECTING |
+F:NO_CONF | NO_SLEEP | NO_FEAR
+F:MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_8
+S:ARROW_4
+D:An enormous construct resembling a titan made from stone. It strides
+D:purposefully towards you, swinging its slow fists with earth-shattering
+D:power.
+
+N:559:Young gold dragon
+G:d:y
+I:110:30d10:20:60:70
+W:31:1:20000:700
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_3D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN |
+F:EVIL | DRAGON | BASEANGBAND | NO_STUN | HAS_LITE | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_SOUN
+D:It has a form out of legend. Its still-tender scales are a
+D:tarnished gold hue, and light is reflected from its form.
+
+N:560:Mature blue dragon
+G:d:b
+I:110:40d10:20:70:70
+W:34:1:110000:1200
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_4D2 | DROP_CORPSE
+F:BASH_DOOR | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:EVIL | DRAGON | IM_ELEC | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_ELEC
+D:A large dragon, scales tinted deep blue.
+
+N:561:Mature green dragon
+G:d:g
+I:110:40d10:20:70:70
+W:34:1:110000:1200
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_4D2 | DROP_CORPSE |
+F:BASH_DOOR | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:EVIL | DRAGON | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_POIS
+D:A large dragon, scales tinted deep green.
+
+N:562:Mature bronze dragon
+G:d:U
+I:110:40d10:20:70:70
+W:34:1:110000:1200
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d8
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN |
+F:DROP_4D2 | CAN_FLY |
+F:BASH_DOOR | DROP_CORPSE |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_9 |
+S:CONF | SCARE |
+S:BR_CONF
+D:A large dragon with scales of rich bronze.
+
+N:563:Young red dragon
+G:d:r
+I:110:30d10:20:60:70
+W:31:1:20000:700
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | SUSCEP_COLD |
+F:DROP_3D2 | WILD_TOO | WILD_MOUNTAIN | WILD_VOLCANO |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE
+F:EVIL | DRAGON | IM_FIRE | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_FIRE
+D:It has a form out of legend. Its still-tender scales are a
+D:deepest red hue. Heat radiates from its form.
+
+N:564:Nightblade
+G:h:D
+I:120:19d13:20:60:10
+W:36:2:1600:315
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+B:HIT:LOSE_CON:3d4
+F:MALE |
+F:DROP_1D2 | FRIENDS | INVISIBLE | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | HURT_LITE |
+F:EVIL | NO_CONF | NO_SLEEP | ZANGBAND
+D:A dark elven assassin, so stealthy that he is almost impossible to see.
+
+N:565:Trapper
+G:.:w
+I:120:60d10:30:75:10
+W:36:3:1300:580
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:PARALYZE:15d1
+B:HIT:PARALYZE:15d1
+F:CHAR_CLEAR | ATTR_CLEAR | CHAR_MULTI |
+F:NEVER_MOVE | FORCE_MAXHP |
+F:INVISIBLE | EMPTY_MIND | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND
+D:This creature traps unsuspecting victims
+D:and paralyzes them, to be slowly digested later.
+
+N:566:Bodak
+G:u:r
+I:110:35d10:10:68:90
+W:36:2:0:750
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:FIRE:4d6
+B:HIT:FIRE:4d6
+B:GAZE:EXP_20
+F:FORCE_SLEEP |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | AURA_FIRE | NONLIVING |
+F:EVIL | DEMON | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:HAS_LITE
+S:1_IN_4 |
+S:BO_FIRE | BA_FIRE |
+S:S_DEMON
+D:It is a humanoid form composed of flames and hatred.
+
+N:567:Time bomb
+G:.:w
+I:130:12d12:30:40:0
+W:36:5:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:TIME:30d2
+F:CHAR_CLEAR | ATTR_CLEAR | CHAR_MULTI |
+F:NEVER_MOVE | FORCE_MAXHP |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | JOKEANGBAND | NO_CUT
+D:It was left here to be used against intruders.
+
+N:568:Mezzodaemon
+G:u:o
+I:110:40d10:10:68:90
+W:36:2:0:750
+E:1:1:1:0:1:1
+O:0:0:0:0
+B:CLAW:HURT:5d6
+B:CLAW:HURT:5d6
+F:FORCE_SLEEP | PASS_WALL | INVISIBLE |
+F:IM_POIS | IM_COLD | IM_ACID | IM_FIRE |
+F:NO_SLEEP | NO_CONF | NO_STUN | NONLIVING |
+F:EVIL | DEMON | BASEANGBAND
+S:1_IN_4 |
+S:BLINK | DARKNESS | S_DEMON
+D:An ugly demon with insect-like extremities and large bulbous eyes.
+
+N:569:Elder thing
+G:u:G
+I:110:35d10:10:70:50
+W:36:3:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:4d6
+B:CRUSH:HURT:4d6
+B:CRUSH:HURT:4d6
+B:TOUCH:LOSE_WIS
+F:FORCE_SLEEP | OPEN_DOOR | BASH_DOOR | ELDRITCH_HORROR | NONLIVING |
+F:EVIL | DEMON | IM_POIS | IM_ACID | NO_CONF | NO_SLEEP | RES_TELE |
+F:CAN_SWIM | CTHANGBAND
+S:1_IN_4 |
+S:SCARE | TELE_AWAY | BA_NUKE | CAUSE_4 | BA_POIS |
+S:CONF | S_DEMON | S_UNDEAD
+D:"...some ridged barrel-shaped objects with thin
+D:horizontal arms radiating spoke-like from a central ring and with
+D:vertical knobs or bulbs projecting from the head and base of the
+D:barrel. Each of these knobs was the hub of a system of five long,
+D:flat, triangularly tapering arms arranged around it like the arms
+D:of a starfish."
+
+N:570:Ice elemental
+G:E:w
+I:110:35d10:10:60:90
+W:37:3:0:650
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:COLD:4d3
+B:HIT:HURT:4d6
+B:TOUCH:COLD:4d3
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD | AURA_COLD |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_COLD | IM_ELEC | CAN_SWIM | IM_POIS | IM_ACID |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BO_ICEE | BA_COLD
+D:It is a towering glacier of ice.
+
+N:571:Necromancer
+G:p:R
+I:110:28d10:20:50:10
+W:36:2:1600:666
+E:1:1:1:2:1:1
+O:10:0:90:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HASTE | TPORT | TELE_TO | BLIND | HOLD | SCARE | CAUSE_3 |
+S:BO_NETH | MIND_BLAST | FORGET |
+S:S_UNDEAD | ANIM_DEAD
+D:A gaunt figure, clothed in black robes.
+
+N:572:The Greater hell magic mushroom were-quylthulg
+G:Q:s
+I:120:19d99:50:80:50
+W:36:3:0:2500
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:GAZE:EXP_40:4d8
+B:GAZE:EXP_40:4d8
+B:CRUSH:ACID:8d8
+B:CRUSH:ACID:8d8
+F:FORCE_MAXHP | FORCE_SLEEP | UNIQUE | NO_STUN | NO_CONF |
+F:NO_SLEEP| EVIL | IM_ACID | IM_ELEC | IM_FIRE | IM_POIS |
+F:IM_COLD | RES_NETH | RES_WATE | RES_PLAS | RES_DISE | SMART |
+F:RES_NEXU | NONLIVING | RES_TELE | KILL_WALL | ELDRITCH_HORROR |
+F:BASH_DOOR | DEMON | COLD_BLOOD | ANIMAL | CAN_SWIM |
+F:DROP_GOOD | DROP_GREAT | ONLY_ITEM | DROP_2D2 | JOKEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLINK | SLOW | SCARE | DARKNESS | HEAL | ANIM_DEAD
+S:TPORT | TELE_AWAY | HASTE | S_MONSTER | DRAIN_MANA |
+S:S_UNDEAD | S_DEMON | S_DRAGON | S_KIN
+D:This unholy abomination will crush you too. Flee while you can!
+
+N:573:Lorgan, Chief of the Easterlings
+G:p:v
+I:120:18d100:25:100:10
+W:36:2:0:1200
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:TELE_TO | S_MONSTERS
+D:A mighty warrior from the east, Lorgan hates everything that he cannot
+D:control.
+
+N:574:Chaos spawn
+G:e:s
+I:110:21d21:20:50:20
+W:38:2:1900:700
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:HURT:10d10
+B:GAZE:UN_BONUS:5d2
+B:GAZE:EXP_40:5d2
+B:GAZE:PARALYZE:5d2
+F:FORCE_MAXHP | BASH_DOOR | EVIL | CAN_FLY | ZANGBAND
+D:It has two eyestalks and a large central eye. Its gaze can kill.
+
+N:575:Mummified troll
+G:z:w
+I:110:25d10:20:50:50
+W:34:1:5000:420
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:FORCE_MAXHP |
+F:DROP_60 |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | TROLL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a massive figure clothed in wrappings. You are wary of its massive
+D:fists.
+
+N:576:Storm of Unmagic
+G:v:v
+I:130:32d20:50:40:0
+W:53:3:0:4000
+B:ENGULF:EXP_80:5d5
+B:ENGULF:UN_POWER:5d5
+B:ENGULF:UN_BONUS:5d5
+B:HIT:LOSE_ALL:5d5
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:RAND_50 | RAND_25 | NONLIVING | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_TIME | BR_DISE
+D:Howling through the disintegrating dungeon, this awesome whirlpool of Unmagic
+D:rips the enchantments from everything it touches.
+
+N:577:Crypt thing
+G:L:G
+I:120:80d10:20:60:60
+W:37:2:0:2500
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:TOUCH:EXP_40
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:2d10
+B:TOUCH:LOSE_DEX:2d10
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_1D2 | RES_TELE |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | TELE_AWAY | TELE_LEVEL |
+S:CAUSE_3 | DRAIN_MANA | BRAIN_SMASH
+D:It is a skeletal form dressed in robes. It looks evil and devious...
+
+N:578:Chaos butterfly
+G:I:G
+I:120:60d10:40:60:10
+W:37:2:0:1000
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:3d7
+B:CLAW:HURT:3d7
+B:CRUSH:HURT:10d5
+F:FORCE_SLEEP |
+F:CAN_FLY |
+F:WEIRD_MIND | BASH_DOOR | ATTR_MULTI | ATTR_ANY |
+F:NO_CONF | NO_SLEEP | MORTAL | ZANGBAND
+S:1_IN_9
+S:BR_CONF | BR_CHAO
+D:With fractal patterns on its wings, it is clearly one of those butterflies
+D:that mathematicians keep talking about - the ones that flap their wings on the
+D:other side of the world to cause storms here. Now's your chance to stop it...
+
+N:579:Time elemental
+G:E:G
+I:120:35d10:90:70:10
+W:39:2:0:1000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TIME:3d4
+B:TOUCH:TIME:3d4
+F:PASS_WALL | IM_POIS | IM_FIRE | IM_ELEC | IM_FIRE | IM_ACID | CAN_FLY |
+F:NO_CONF | NO_SLEEP | EMPTY_MIND | KILL_ITEM | RAND_50 |
+F:ZANGBAND | NO_CUT
+S:1_IN_7
+S:SLOW | BR_TIME |
+D:You have not seen it yet.
+
+N:580:Flying polyp
+G:~:R
+I:120:35d10:90:70:10
+W:37:2:0:1000
+E:3:0:3:6:1:0
+O:0:0:0:0
+B:CRUSH:PARALYZE:8d4
+B:CRUSH:PARALYZE:8d4
+B:CRUSH:PARALYZE:8d4
+F:PASS_WALL | INVISIBLE | FORCE_MAXHP | RES_DISE |
+F:IM_POIS | IM_COLD | IM_ACID | ELDRITCH_HORROR |
+F:NO_CONF | NO_SLEEP | EVIL | CAN_FLY | CTHANGBAND |NO_CUT
+S:1_IN_7
+S:BR_WALL |
+D:"They were only partly material and had the power of aerial motion,
+D:despite the absence of wings... Suggestions of monstrous plasticity
+D:and of temporary lapses of visibility..."
+
+N:581:The Queen Ant
+G:a:v
+I:120:15d100:30:100:10
+W:37:2:2000:1000
+E:0:1:0:2:1:0
+O:50:50:0:0
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+F:UNIQUE | FEMALE | GOOD | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:WEIRD_MIND | OPEN_DOOR | BASH_DOOR |
+F:ANIMAL |
+F:MORTAL | BASEANGBAND
+S:1_IN_2 |
+S:S_KIN
+D:She's upset because you hurt her children.
+
+N:582:Will o' the wisp
+G:E:W
+I:130:20d10:30:150:0
+W:38:4:0:500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d9
+B:HIT:HURT:1d9
+B:HIT:HALLU:1d9
+B:HIT:HALLU:1d9
+F:FORCE_SLEEP | FORCE_MAXHP | RAND_50 |
+F:SMART | EMPTY_MIND | INVISIBLE |
+F:PASS_WALL | POWERFUL | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_2 |
+S:BLINK | TPORT | CONF | CAUSE_2
+D:A strange ball of glowing light. It disappears and reappears and seems to
+D:draw you to it. You seem somehow compelled to stand still and watch its
+D:strange dancing motion.
+
+N:583:Shan
+G:I:B
+I:120:20d8:20:120:20
+W:37:4:0:250
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:IM_POIS | IM_COLD | COLD_BLOOD | ANIMAL | EVIL |
+F:NO_SLEEP | NO_CONF | CAN_FLY | NEVER_BLOW | CTHANGBAND |
+S:1_IN_2
+S:CONF | HOLD | DRAIN_MANA | FORGET | MIND_BLAST | SHRIEK
+D:"Those huge lidless eyes which stared with hate at me, the jointed
+D:tendrils which seemed to twist from the head in cosmic rhythms,
+D:the ten legs, covered with black shining tentacles and folded into
+D:the pallid underbelly, and the semi-circular ridged wings covered
+D:with triangular scales -- all this cannot convey the soul-ripping
+D:horror of the shape which darted at me. I saw the three mouths
+D:of the thing move moistly, and then it was upon me."
+
+N:584:Magma elemental
+G:E:o
+I:110:35d10:10:70:90
+W:37:3:0:950
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:FIRE:3d7
+B:HIT:HURT:4d6
+B:HIT:FIRE:3d7
+F:FORCE_SLEEP |
+F:EMPTY_MIND | AURA_FIRE | WILD_TOO | WILD_VOLCANO |
+F:KILL_ITEM | KILL_BODY | PASS_WALL | POWERFUL |
+F:IM_FIRE | IM_ELEC | IM_ACID | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_7 |
+S:BO_PLAS | BA_FIRE
+D:It is a towering glowing form of molten rock.
+
+N:585:Black pudding
+G:j:D
+I:110:40d10:12:18:1
+W:37:5:300:50
+E:0:0:0:0:0:0
+O:90:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:FORCE_MAXHP |
+F:FRIENDS |
+F:DROP_60 | DROP_90 | DROP_1D2 |
+F:STUPID | EMPTY_MIND | COLD_BLOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | CAN_SWIM | BASEANGBAND | NO_CUT
+D:A lump of rotting black flesh that slurrrrrrrps across the dungeon floor.
+
+N:586:Killer iridescent beetle
+G:K:v
+I:110:25d15:16:60:30
+W:37:2:600:850
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:ELEC:1d12
+B:CLAW:ELEC:1d12
+B:GAZE:PARALYZE
+F:ATTR_MULTI | FORCE_MAXHP |
+F:WEIRD_MIND | BASH_DOOR | AURA_ELEC | DROP_CORPSE |
+F:ANIMAL | IM_ELEC | CAN_FLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle, whose carapace shimmers with vibrant energies.
+
+N:587:Nexus vortex
+G:v:v
+I:120:32d10:100:40:0
+W:37:1:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:HURT:5d5
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 | RES_NEXU | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BR_NEXU
+D:A maelstrom of potent magical energy.
+
+N:588:Plasma vortex
+G:v:R
+I:120:32d10:100:40:0
+W:37:1:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:FIRE:4d8
+B:ENGULF:ELEC:4d8
+F:FORCE_SLEEP | SUSCEP_COLD |
+F:RAND_50 | RAND_25 | RES_PLAS | AURA_FIRE | AURA_ELEC |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:IM_FIRE | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BR_PLAS
+D:A whirlpool of intense flame, charring the stones at your feet.
+
+N:589:Mature red dragon
+G:d:r
+I:110:50d10:20:80:70
+W:36:1:110000:1500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d10
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN | WILD_VOLCANO |
+F:DROP_1D2 | DROP_4D2 | CAN_FLY | DROP_CORPSE | SUSCEP_COLD |
+F:BASH_DOOR |
+F:EVIL | DRAGON | IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_9 |
+S:CONF | SCARE |
+S:BR_FIRE
+D:A large dragon, scales tinted deep red.
+
+N:590:Mature gold dragon
+G:d:y
+I:110:50d10:20:80:70
+W:36:1:110000:1500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d10
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN |
+F:DROP_1D2 | DROP_4D2 | CAN_FLY | DROP_CORPSE |
+F:BASH_DOOR |
+F:EVIL | DRAGON | NO_STUN | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_9 |
+S:CONF | SCARE |
+S:BR_SOUN
+D:A large dragon with scales of gleaming gold.
+
+N:591:Crystal drake
+G:d:u
+I:110:45d10:20:70:70
+W:33:3:18000:1350
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:ONLY_ITEM | DROP_3D2 | REFLECTING |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_SHAR
+D:A dragon of strange crystalline form. Light shines through it, dazzling
+D:your eyes with spectrums of colour.
+
+N:592:Mature black dragon
+G:d:s
+I:110:50d10:20:80:70
+W:36:1:110000:1500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d10
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE |
+F:DROP_1D2 | DROP_4D2 | WILD_TOO | WILD_SWAMP | WILD_MOUNTAIN |
+F:BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_ACID
+D:A large dragon, with scales of deepest black.
+
+N:593:Mature multi-hued dragon
+G:d:v
+I:110:60d10:20:80:70
+W:38:1:110000:1800
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d12
+B:CLAW:HURT:2d12
+B:BITE:HURT:4d12
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_2D2 | DROP_4D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_7 |
+S:BLIND | CONF | SCARE |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS
+D:A large dragon, scales shimmering many colours.
+
+N:594:Sky whale
+G:~:G
+I:110:80d10:20:75:30
+W:38:6:4000:1750
+E:0:0:0:0:1:0
+O:50:50:0:0
+B:CRUSH:HURT:20d2
+B:CRUSH:HURT:20d2
+B:CRUSH:HURT:20d2
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_60 | DROP_90 | DROP_2D2 | DROP_CORPSE |
+F:BASH_DOOR | SMART | GOOD |
+F:NO_CONF | NO_SLEEP | RES_NEXU | RES_TELE | RES_DISE
+F:MORTAL | ZANGBAND
+S:1_IN_9 |
+S:BRAIN_SMASH | CONF | SCARE | FORGET | TELE_TO | TELE_AWAY | SHRIEK
+D:A vastly intelligent whale-like being from the stars.
+
+N:595:Draebor, the Imp
+G:u:v
+I:120:19d99:12:80:50
+W:38:3:3000:3250
+E:0:1:1:0:1:0
+O:30:20:50:0
+B:CLAW:POISON:8d4
+B:CLAW:POISON:8d4
+B:BITE:HURT:8d8
+B:INSULT:*
+F:ESCORT
+F:DROP_60 | DROP_90 | DROP_1D2 | DROP_GOOD | ONLY_ITEM | DROP_CORPSE |
+F:CAN_SWIM | BASH_DOOR | RES_TELE | CAN_SPEAK |
+F:EVIL | DEMON | IM_FIRE | IM_COLD | IM_POIS | RES_WATE |
+F:UNIQUE | MALE | FORCE_SLEEP | FORCE_MAXHP | POWERFUL |
+F:NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:S_KIN | BLINK | TPORT | TELE_TO | TELE_AWAY | TELE_LEVEL | BLIND |
+S:CONF | SCARE
+D:An intensely irritating git of a monster.
+
+N:596:Mother Hydra
+G:u:v
+I:120:25d99:12:80:50
+W:40:3:30000:3250
+E:0:1:0:2:2:0
+O:0:50:50:0
+B:CLAW:POISON:8d4
+B:CLAW:POISON:8d4
+B:BITE:HURT:8d8
+F:ESCORT |
+F:DROP_60 | DROP_90 | DROP_1D2 | DROP_GOOD | ONLY_ITEM | DROP_CORPSE |
+F:CAN_SWIM | BASH_DOOR | ELDRITCH_HORROR | RES_TELE | CAN_SPEAK |
+F:EVIL | DEMON | IM_FIRE | IM_COLD | IM_POIS | RES_WATE |
+F:UNIQUE | FEMALE | FORCE_SLEEP | FORCE_MAXHP | POWERFUL |
+F:NO_CONF |
+F:MORTAL | CTHANGBAND
+S:1_IN_7 |
+S:S_HYDRA | S_DEMON | DARKNESS | BA_WATE | BO_ACID | BA_ACID
+D:The queen of the deep ones. "Vast, Polyphemus-like, and loathsome, it
+D:darted like a stupendous monster of nightmares..."
+
+N:597:Death knight
+G:p:D
+I:120:60d10:20:100:10
+W:38:1:2700:1111
+E:1:1:1:2:1:1
+O:0:90:0:10
+B:HIT:EXP_20:6d6
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_NETH |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_COLD | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_5 |
+S:BLIND | SCARE | CAUSE_3 | BO_NETH |
+S:S_MONSTERS
+D:It is a humanoid figure dressed in armour of an ancient form. From beneath
+D:its helmet, eyes glow a baleful red and seem to pierce you like lances of
+D:fire.
+
+N:598:Castamir the Usurper
+G:p:R
+I:120:88d10:20:90:40
+W:38:5:0:1600
+E:1:1:1:2:1:1
+O:10:60:10:10
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | TAKE_ITEM | BASH_DOOR |
+F:EVIL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | TRAPS | BO_FIRE | BO_COLD | BO_ELEC | BO_ICEE
+D:A Black Numenorean who usurped the throne of Gondor, he is treacherous and
+D:evil.
+
+N:599:Time vortex
+G:v:B
+I:130:32d10:100:40:0
+W:38:4:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:TIME:5d5
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_TIME
+D:You haven't seen it yet.
+
+N:600:Shimmering vortex
+G:v:o
+I:140:32d10:100:40:0
+W:38:4:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:BLIND:4d4
+B:ENGULF:BLIND:4d4
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_4 |
+S:BR_LITE | SHRIEK
+D:A strange pillar of shining light that hurts your eyes. Its shape changes
+D:constantly as it cuts through the air towards you. It is like a beacon,
+D:waking monsters from their slumber.
+
+N:601:Ancient blue dragon
+G:D:b
+I:120:72d10:20:90:80
+W:40:1:170000:2000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:ELEC:7d8
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_3D2 | DROP_4D2 | DROP_CORPSE |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
+F:EVIL | DRAGON | IM_ELEC | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_ELEC
+D:A huge draconic form. Lightning crackles along its length.
+
+N:602:Ancient bronze dragon
+G:D:U
+I:120:72d10:20:90:80
+W:40:1:170000:2000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:HURT:7d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_3D2 | DROP_4D2 | CAN_FLY |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_CONF
+D:A huge draconic form enveloped in a cascade of colour.
+
+N:603:Beholder
+G:e:U
+I:120:16d100:30:80:10
+W:40:3:1600:6000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:EXP_20:2d6
+B:GAZE:UN_POWER:2d6
+B:GAZE:INSANITY:2d6
+B:BITE:HURT:6d6
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | CAN_FLY |
+F:BASH_DOOR | DROP_CORPSE |
+F:EVIL | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_2 |
+S:BLIND | SLOW | CONF | SCARE | DRAIN_MANA | MIND_BLAST |
+S:FORGET | DARKNESS | BO_ACID | BO_FIRE | BO_COLD | BO_ELEC
+D:A vile creature with one huge central eye, twelve smaller eyes on stalks, and
+D:a huge mouth filled with sharp teeth.
+
+N:604:Emperor wight
+G:W:r
+I:120:38d10:20:40:10
+W:38:2:0:1600
+E:0:0:0:0:0:0
+O:0:40:60:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:TOUCH:EXP_80
+B:TOUCH:EXP_80
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_4D2 | CAN_FLY |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:HOLD | SCARE | CAUSE_3 | BO_NETH
+D:Your life force is torn from your body as this powerful unearthly being
+D:approaches.
+
+N:605:Seraph
+G:A:r
+I:120:150d10:30:68:255
+W:45:4:3100:5000
+E:1:1:1:2:1:1
+O:0:30:70:0
+B:HIT:HURT:4d6
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:4d6
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | NO_FEAR | GOOD | CAN_FLY |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | REFLECTING | RES_TELE
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_11 |
+S:HEAL | HASTE | TELE_AWAY | CONF | BO_MANA | BO_PLAS |
+S:S_MONSTERS | S_ANGEL
+D:It is an angel, fast and strong. You are stunned by its extreme holiness
+D:and try to resist all desires to obey it.
+
+N:606:Vargo, Tyrant of Fire
+G:E:r
+I:120:24d100:12:50:50
+W:43:3:0:4000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:FIRE:6d6
+B:HIT:FIRE:6d6
+B:HIT:FIRE:6d6
+B:HIT:FIRE:6d6
+F:UNIQUE | SUSCEP_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP | RAND_25 | CAN_SPEAK |
+F:EMPTY_MIND | CAN_SPEAK | MALE | AURA_FIRE |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_ACID | IM_POIS | IM_ELEC | NO_STUN |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_4 |
+S:BO_PLAS | BA_FIRE
+D:A towering fire elemental, Vargo burns everything beyond recognition.
+
+N:607:Black wraith
+G:W:D
+I:120:50d10:20:55:10
+W:38:2:0:1700
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:TOUCH:EXP_40
+B:TOUCH:EXP_40
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP
+F:BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | BO_NETH
+D:A figure that seems made of void, its strangely human shape is cloaked in
+D:shadow. It reaches out at you.
+
+N:608:Nightgaunt
+G:U:D
+I:110:24d10:20:50:80
+W:38:2:0:1000
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:STING:LOSE_STR:1d5
+B:TOUCH:PARALYZE:3d4
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_60 | ELDRITCH_HORROR |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | CAN_FLY |
+F:EVIL | DEMON |
+F:IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | ZANGBAND
+S:1_IN_7 |
+S:BLIND | CONF | BO_FIRE
+D:It is a black, horned humanoid with wings.
+
+N:609:Baron of hell
+G:U:U
+I:110:150d12:10:130:40
+W:38:3:0:1000
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:11d2
+B:CLAW:HURT:11d2
+B:CLAW:HURT:22d1
+F:IM_POIS | OPEN_DOOR | BASH_DOOR | MALE | RES_PLAS | IM_FIRE | NONLIVING |
+F:IM_FIRE | NO_CONF | NO_SLEEP | EVIL | DEMON | FORCE_MAXHP | RES_TELE |
+F:ZANGBAND | HAS_LITE
+S:1_IN_2 |
+S:BO_PLAS
+D:A minor demon lord with a goat's head, tough to kill.
+
+N:610:Scylla
+G:M:B
+I:125:100d20:20:100:70
+W:42:1:15000:13000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:POISON:10d3
+B:BITE:POISON:10d3
+B:BITE:POISON:10d3
+B:BITE:POISON:10d3
+F:FORCE_SLEEP | UNIQUE | AQUATIC | FORCE_MAXHP | COLD_BLOOD |
+F:ONLY_GOLD | DROP_2D2 | DROP_4D2 | DROP_CORPSE |
+F:BASH_DOOR | MOVE_BODY | EVIL | ZANGBAND | RES_WATE |
+F:ANIMAL | IM_POIS | IM_FIRE
+S:1_IN_5 |
+S:BR_POIS | BR_FIRE | SCARE | CONF | S_HYDRA
+D:A many-headed sea-monster, this foul creature preys on all those who
+D:escape the clutches of Charybdis.
+
+N:611:Monastic lich
+G:L:u
+I:120:12d100:30:80:30
+W:39:2:2000:5000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:KICK:HURT:24d1
+B:KICK:HURT:24d1
+B:CLAW:EXP_80:4d2
+B:CLAW:LOSE_DEX:4d2
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_TELE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | SMART |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | BLIND | HOLD | CONF | SCARE | CAUSE_3 | CAUSE_4 |
+S:DRAIN_MANA | BRAIN_SMASH | ANIM_DEAD
+D:A skeletal form wrapped in priestly robes. Before its un-death, it
+D:was a monk in an evil order.
+
+N:612:Nether wraith
+G:W:G
+I:120:48d10:20:55:10
+W:39:2:0:1700
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:TOUCH:EXP_80
+B:TOUCH:EXP_80
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_90 | DROP_4D2 |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BLIND | SCARE | CAUSE_3 | MIND_BLAST | DARKNESS | BO_NETH
+D:A form that hurts the eye, death permeates the air around it. As it nears
+D:you, a coldness saps your soul.
+
+N:613:Hellhound
+G:C:r
+I:120:48d10:25:80:30
+W:35:3:600:600
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:RAND_25 | FRIENDS | AURA_FIRE | SUSCEP_COLD |
+F:BASH_DOOR | MOVE_BODY |
+F:ANIMAL | EVIL | IM_FIRE | BASEANGBAND | HAS_LITE |
+S:1_IN_5 | BR_FIRE
+D:It is a giant dog that glows with heat. Flames pour from its nostrils.
+
+N:614:7-headed hydra
+G:M:G
+I:120:100d10:20:90:20
+W:39:2:7000:2000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:POISON:3d9
+B:BITE:POISON:3d9
+B:BITE:POISON:3d9
+B:SPIT:BLIND:1d2
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:ONLY_GOLD | DROP_2D2 | DROP_4D2 | CAN_SWIM | DROP_CORPSE
+F:BASH_DOOR | MOVE_BODY |
+F:ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:SCARE | BA_POIS |
+S:BR_POIS
+D:A strange reptilian creature with seven heads dripping venom.
+
+N:615:Waldern, King of Water
+G:E:b
+I:130:25d100:12:80:50
+W:43:3:0:4250
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:8d5
+B:HIT:HURT:8d5
+B:HIT:HURT:8d5
+B:HIT:HURT:8d5
+F:UNIQUE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_ACID | IM_FIRE | IM_POIS | IM_COLD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BO_ICEE | BO_WATE | BA_COLD | BA_WATE
+D:A towering water elemental, Waldern is master of all things liquid.
+D:Wave after wave drowns your frail body.
+
+N:616:Kavlax the Many-Headed
+G:d:v
+I:120:13d100:20:85:30
+W:39:3:90000:3000
+E:0:1:0:6:2:0
+O:50:50:0:0
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+F:UNIQUE | MALE | ATTR_MULTI | CAN_SPEAK | ATTR_ANY |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | RES_NEXU |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | CAN_FLY |
+F:EVIL | DRAGON | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC |
+F:BASEANGBAND | HAS_LITE |
+S:1_IN_4 |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_SOUN | BR_CONF |
+S:BR_SHAR | BR_GRAV | BR_NEXU
+D:A large dragon with a selection of heads, all shouting and arguing as they
+D:look for prey, but each with its own deadly breath weapon.
+
+N:617:Ancient white dragon
+G:D:w
+I:120:72d10:20:90:80
+W:40:1:170000:2000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:COLD:7d8
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_3D2 | DROP_4D2 | DROP_CORPSE |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | SUSCEP_FIRE | BASEANGBAND
+F:HAS_LITE | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_COLD
+D:A huge draconic form. Frost covers it from head to tail.
+
+N:618:Ancient green dragon
+G:D:g
+I:120:72d10:20:90:80
+W:40:1:170000:2000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:POISON:7d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_3D2 | DROP_4D2 | CAN_FLY |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_POIS
+D:A huge draconic form enveloped in clouds of poisonous vapour.
+
+N:619:Chthonian
+G:w:D
+I:120:100d10:20:90:20
+W:39:2:12000:2300
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:SHATTER:3d11
+B:CRUSH:SHATTER:3d11
+B:TOUCH:LOSE_CON:1d2
+B:TOUCH:LOSE_CON:1d2
+F:IM_FIRE | RES_PLAS | IM_COLD | IM_POIS | ELDRITCH_HORROR | RES_TELE |
+F:KILL_WALL | ONLY_GOLD | DROP_4D2 | DROP_2D2 | CAN_SWIM | DROP_CORPSE |
+F:EVIL | FORCE_MAXHP | CTHANGBAND
+S:1_IN_5 |
+S:SCARE | CONF | HOLD | S_DEMON |
+S:MIND_BLAST | HEAL | HASTE | FORGET | BRAIN_SMASH
+D:"Flowing tentacles and a pulpy gray-black elongated sack of a body...
+D:no distinguishing features at all other than the reaching, groping
+D:tentacles. Or was there -- yes! -- a lump in the upper body of
+D:the thing... a container of sorts for the brain, ganglia, or
+D:whichever diseased organ governed this horror's loathsome life!"
+
+N:620:Eldrak
+G:T:r
+I:110:75d10:20:80:50
+W:38:3:7000:1500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:BITE:HURT:3d4
+B:BITE:HURT:3d4
+F:FORCE_MAXHP | MOVE_BODY |
+F:ONLY_ITEM | DROP_2D2 | REGENERATE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_SHORE | WILD_WOOD |
+F:EVIL | TROLL | IM_POIS | NO_CONF | NO_SLEEP | DROP_CORPSE | BASEANGBAND
+D:A massive troll of huge strength. Eldraks are extremely stupid and extremely
+D:violent.
+
+N:621:Ettin
+G:T:b
+I:110:15d100:20:100:30
+W:39:3:8000:2000
+E:1:1:1:2:2:1
+O:0:100:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:BITE:HURT:3d8
+B:BITE:HURT:3d8
+F:FORCE_MAXHP | REGENERATE | MOVE_BODY |
+F:ONLY_ITEM | DROP_1D2 | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD | WILD_SWAMP |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | TROLL | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+D:A massive two-headed troll, larger and stronger than many men together.
+D:Fortunately, ettins are solitary creatures. They are also living proof that
+D:two heads are not necessarily more intelligent than one...
+
+N:622:Night mare
+G:q:G
+I:120:15d100:30:85:0
+W:39:3:6000:2900
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:EXP_80:2d6
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:CONFUSE:6d6
+F:FORCE_MAXHP |
+F:ONLY_GOLD | DROP_2D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:HAS_LITE | NO_CUT
+D:A fearsome skeletal horse with glowing eyes that watch you with little
+D:more than a hatred of all that lives. Its flying hooves do not touch the
+D:ground.
+
+N:623:Vampire lord
+G:V:b
+I:120:20d100:20:70:10
+W:42:1:1700:1800
+E:1:1:1:2:1:1
+O:0:70:30:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:BITE:EXP_80:4d6
+B:BITE:EXP_80:4d6
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_60 | DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | RES_TELE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | DARKNESS | BO_NETH
+D:A foul wind chills your bones as this ghastly figure approaches.
+
+N:624:Ancient black dragon
+G:D:s
+I:120:10d100:20:90:80
+W:41:1:170000:2500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d9
+B:CLAW:HURT:4d9
+B:BITE:ACID:7d9
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_3D2 | DROP_4D2 | DROP_CORPSE |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_ACID | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_ACID
+D:A huge draconic form. Pools of acid melt the floor around it.
+
+N:625:Weird fume
+G:#:v
+I:120:35d10:100:40:0
+W:40:2:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:CONFUSE:8d4
+B:ENGULF:CONFUSE:8d4
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 | RES_NEXU | AURA_ELEC | IM_FIRE | IM_ELEC |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:CAN_FLY | ATTR_MULTI | ATTR_ANY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | ZANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_CHAO | BR_NEXU | BR_NUKE
+D:A swirling spiral of mist, constantly changing its appearance.
+
+N:626:Spawn of Ubbo-Sathla
+G:j:v
+I:120:30d10:100:40:0
+W:40:5:0:300
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:ACID:8d4
+B:CRUSH:ACID:8d4
+F:FORCE_SLEEP | ATTR_MULTI | ATTR_ANY | EVIL |
+F:RAND_25 | RES_NEXU | AURA_ELEC | IM_FIRE | IM_ELEC |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | KILL_BODY |
+F:CAN_SWIM | NO_CONF | NO_SLEEP | CTHANGBAND | NO_CUT
+S:MULTIPLY
+D:Weird, jelly like creatures. No two look the same.
+
+N:627:Fat Man
+G:{:D
+I:120:14d14:10:80:12
+W:40:2:0:200
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:SHATTER:200d2
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | REFLECTING |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
+F:NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | RES_TELE | JOKEANGBAND | NO_CUT | NO_STUN
+D:A shining machine of death and destruction.
+
+N:628:Malekith the Accursed
+G:h:v
+I:125:25d100:20:70:10
+W:44:2:3500:7500
+E:1:1:1:2:1:1
+O:50:0:50:0
+B:HIT:HURT:12d9
+B:HIT:HURT:12d9
+F:MALE | REGENERATE | UNIQUE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:ONLY_ITEM | DROP_90 | DROP_4D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | HURT_LITE | ZANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | TELE_TO | BLIND | CONF | CAUSE_3 | DARKNESS | FORGET | HOLD |
+S:S_MONSTER | S_MONSTERS | S_DEMON | TPORT | BA_NETH | MIND_BLAST |
+S:S_KIN
+D:One of the oldest and most powerful dark elves, Malekith is a master
+D:sorcerer devoted to evil. The left side of his face is pale, and the other
+D:is dark. His hair is long and white.
+
+N:629:Shadowfax, steed of Gandalf
+G:q:v
+I:130:30d100:20:100:50
+W:40:3:2600:2000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:KICK:HURT:5d5
+B:KICK:HURT:5d5
+B:BITE:HURT:6d6
+F:FORCE_MAXHP | UNIQUE | ANIMAL | GOOD |
+F:REGENERATE | BASH_DOOR | IM_FIRE | IM_COLD | IM_ELEC |
+F:IM_POIS | NO_FEAR | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:Shadowfax is the chief of the "Mearas", the greatest of all horses that are
+D:bred in the fields of Rohan. Although the Mearas should technically be only
+D:ridden by the royal family of Rohan, only Gandalf the Wizard has ever
+D:succeeded in taming Shadowfax: and even then, Shadowfax will not be subjected
+D:to a bridle or saddle, but must be ridden bareback.
+
+N:630:Spirit troll
+G:G:G
+I:110:10d100:20:90:5
+W:40:3:0:900
+E:0:0:0:0:0:0
+O:10:90:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:FORCE_MAXHP |
+F:DROP_90 |
+F:INVISIBLE | PASS_WALL | CAN_FLY |
+F:EVIL | TROLL | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:A weird ghostly troll-like being from the ethereal plane.
+
+N:631:War troll
+G:T:b
+I:120:50d10:20:100:50
+W:40:3:6500:800
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:BITE:HURT:3d5
+B:BITE:HURT:3d5
+F:FORCE_MAXHP | SUSCEP_FIRE | REGENERATE |
+F:DROP_90 | REGENERATE | FRIENDS |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | TROLL | IM_POIS | NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+D:A massive troll, equipped with a scimitar and heavy armour.
+
+N:632:Disenchanter worm mass
+G:w:v
+I:100:10d8:7:5:10
+W:40:3:50:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:UN_BONUS:1d4
+F:RAND_50 | RES_DISE | ATTR_MULTI | CAN_SWIM |
+F:STUPID | WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | HURT_LITE | NO_FEAR | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a strange mass of squirming worms. Magical energy crackles
+D:around its disgusting form.
+
+N:633:Rotting quylthulg
+G:Q:u
+I:120:48d10:20:1:0
+W:45:1:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_UNDEAD
+D:It is a pulsing flesh mound that reeks of death and putrefaction.
+
+N:634:Lesser titan
+G:P:y
+I:120:24d100:30:80:15
+W:56:3:30000:6000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:CONFUSE:9d9
+B:HIT:CONFUSE:9d9
+B:HIT:CONFUSE:9d9
+B:HIT:CONFUSE:9d9
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_GOOD | DROP_4D2 | DROP_SKELETON | DROP_CORPSE |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | MALE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | TELE_TO | SCARE |
+S:S_MONSTERS
+D:It is a humanoid figure thirty feet tall that gives off an aura of power
+D:and hate.
+
+N:635:9-headed hydra
+G:M:r
+I:120:100d12:20:95:20
+W:40:2:8000:3000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:FIRE:3d10
+B:BITE:FIRE:3d10
+B:BITE:FIRE:3d10
+B:BITE:FIRE:3d10
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:ONLY_GOLD | DROP_3D2 | DROP_4D2 | CAN_SWIM |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | DROP_CORPSE |
+F:ANIMAL | IM_FIRE | MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:SCARE | BO_FIRE | BR_FIRE
+D:A strange reptilian creature with nine smouldering heads.
+
+N:636:Enchantress
+G:p:R
+I:130:52d10:20:60:10
+W:40:4:1700:2100
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:HIT:HURT:2d8
+F:FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:BLIND |
+S:S_DRAGON
+D:This elusive female spellcaster has a special affinity for dragons, without
+D:whom she rarely fights.
+
+N:637:Ranger chieftain
+G:p:W
+I:120:50d20:20:60:10
+W:41:2:1800:1800
+E:1:1:1:2:1:1
+O:30:50:20:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:MALE | INVISIBLE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | TAKE_ITEM |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP | IM_FIRE | IM_ELEC | IM_COLD | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:S_MONSTERS |
+S:ARROW_2 | ARROW_3 | ARROW_4 | MISSILE | BO_FIRE | BO_ELEC | BA_COLD |
+S:HASTE | BLINK | S_ANIMALS
+D:A chieftain among the Rangers. His understanding of nature gives him
+D:powerful elemental spells to use against you, in addition to his skills
+D:as an archer and a warrior. Furthermore, he is a master of camouflage, so
+D:you will need magically enhanced seeing to spot him.
+
+N:638:Sorcerer
+G:p:R
+I:130:52d10:20:60:10
+W:40:2:1700:2150
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_90 | DROP_4D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:BLINK | TELE_TO | BLIND | CONF | CAUSE_3 | TRAPS |
+S:BO_ACID | BA_FIRE | BA_COLD |
+S:S_MONSTER | S_UNDEAD | S_DRAGON
+D:A human figure in robes, he moves with magically improved speed, and his
+D:hands are ablur with spell casting.
+
+N:639:Xaren
+G:X:s
+I:120:32d10:20:80:10
+W:40:1:500000:1200
+E:0:0:0:3:0:0
+O:0:0:0:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:FORCE_MAXHP | SUSCEP_ACID |
+F:EMPTY_MIND | COLD_BLOOD |
+F:ONLY_GOLD | DROP_2D2 |
+F:KILL_ITEM | PASS_WALL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It is a tougher relative of the Xorn. Its hide glitters with metal ores.
+
+N:640:Giant roc
+G:B:u
+I:110:80d13:20:70:10
+W:40:3:6000:1000
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CRUSH:HURT:8d12
+B:CRUSH:HURT:8d12
+B:HIT:ELEC:12d12
+F:BASH_DOOR | CAN_FLY | WILD_MOUNTAIN | WILD_WOOD |
+F:ANIMAL | IM_ELEC | DROP_CORPSE | SUSCEP_ACID | HAS_EGG
+F:MORTAL | BASEANGBAND
+D:A vast legendary bird, its iron talons rake the most impenetrable of
+D:surfaces and its screech echoes through the many winding dungeon corridors.
+
+N:641:Minotaur
+G:H:U
+I:130:100d10:13:25:10
+W:40:2:15000:2100
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BUTT:HURT:4d6
+B:BUTT:HURT:4d6
+B:BUTT:HURT:2d6
+B:BUTT:HURT:2d6
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND
+D:It is a cross between a human and a bull.
+
+N:642:Medusa, the Gorgon
+G:n:v
+I:120:24d100:30:100:5
+W:40:3:4000:9000
+E:1:1:1:2:0:1
+O:30:35:35:0
+B:GAZE:EXP_80
+B:GAZE:PARALYZE
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+F:UNIQUE | FEMALE | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_FIRE | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:1_IN_2 |
+S:HOLD | SCARE | CAUSE_3 | BO_FIRE | BO_PLAS | BA_ACID |
+S:S_HYDRA | S_KIN
+D:One of the original three ugly sisters. Her face could sink a thousand
+D:ships. Her scales rattle as she slithers towards you, venom dripping from
+D:her ghastly mouth.
+
+N:643:Death drake
+G:D:G
+I:120:21d100:25:100:80
+W:45:2:170000:10000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:EXP_80:7d10
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | RES_TELE
+F:INVISIBLE | TAKE_ITEM | CAN_FLY |
+F:PASS_WALL | POWERFUL | MOVE_BODY | RES_NETH |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_NETH
+D:It is a dragon-like form wrapped in darkness. You cannot make out its
+D:true form but you sense its evil.
+
+N:644:Ancient red dragon
+G:D:r
+I:120:10d100:20:90:80
+W:41:1:170000:2500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d9
+B:CLAW:HURT:4d9
+B:BITE:FIRE:7d9
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:DROP_3D2 | DROP_4D2 | CAN_FLY | SUSCEP_COLD |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_FIRE
+D:A huge draconic form. Wisps of smoke steam from its nostrils and the
+D:extreme heat surrounding it makes you gasp for breath.
+
+N:645:Ancient gold dragon
+G:D:y
+I:120:10d100:20:90:80
+W:41:1:170000:2500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d9
+B:CLAW:HURT:4d9
+B:BITE:HURT:7d9
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:DROP_3D2 | DROP_4D2 | CAN_FLY |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | NO_STUN | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN
+D:A huge draconic form wreathed in a nimbus of light. Its roar stuns and
+D:deafens you.
+
+N:646:Great crystal drake
+G:D:U
+I:120:21d100:25:100:80
+W:45:2:170000:10000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:HURT:7d10
+F:FORCE_SLEEP | FORCE_MAXHP | REFLECTING | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | CAN_FLY |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_SHAR
+D:A huge crystalline dragon. Its claws could cut you to shreds and its
+D:teeth are razor sharp. Strange colours ripple through it as it moves in
+D:the light.
+
+N:647:Wyrd sister
+G:p:v
+I:125:50d11:20:60:10
+W:40:4:1600:1900
+E:1:1:1:2:1:1
+O:10:0:80:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d8
+F:FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_SKELETON
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP
+F:MORTAL | ZANGBAND
+S:1_IN_2 |
+S:BLIND |
+S:S_DEMON | CONF | SCARE | DARKNESS | BA_CHAO
+D:This old crone is rumoured to be a witch of chaos... but you don't
+D:really believe in witches, do you?
+
+N:648:Vrock
+G:U:s
+I:110:40d10:20:50:80
+W:40:2:2700:2000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:3d4
+B:CRUSH:HURT:8d12
+B:CRUSH:HURT:8d12
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:FRIENDS |
+F:ONLY_ITEM | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_8 |
+S:BLIND | CONF
+D:It is a demon with a long neck and raking claws.
+
+N:649:Death quasit
+G:u:D
+I:130:44d10:20:80:0
+W:40:3:600:1000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:BITE:LOSE_DEX:3d6
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | DROP_4D2 | NONLIVING |
+F:SMART | INVISIBLE | PASS_WALL | CAN_FLY |
+F:EVIL | DEMON | IM_FIRE | IM_POIS | RES_TELE
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_10 |
+S:BLIND | CONF | SCARE | CAUSE_3 | FORGET |
+S:S_DEMON
+D:It is a demon of small stature, but its armoured frame moves with
+D:lightning speed and its powers make it a tornado of death and destruction.
+
+N:650:Giganto, the Gargantuan
+G:~:s
+I:110:80d10:20:75:30
+W:38:6:8000:1750
+E:0:1:0:0:1:0
+O:60:40:0:0
+B:CRUSH:HURT:30d2
+B:CRUSH:HURT:30d2
+B:CRUSH:HURT:30d2
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SWIM | IM_FIRE |
+F:DROP_60 | DROP_90 | DROP_2D2 | UNIQUE | WEIRD_MIND |
+F:BASH_DOOR | SMART | EVIL | IM_COLD | DROP_CORPSE
+F:RES_WATE | WILD_OCEAN |
+F:MORTAL | ZANGBAND
+S:1_IN_9 |
+S:BR_NUKE | BA_WATE
+D:A gargantuan mutant whale, who has grown legs that enable it to walk
+D:on dry land as well.
+
+N:651:Strygalldwir
+G:U:W
+I:120:12d100:90:60:10
+W:41:3:5000:8000
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:CLAW:HURT:5d5
+B:CLAW:HURT:5d5
+B:HIT:LOSE_STR:4d4
+B:TOUCH:EXP_80:8d1
+F:UNIQUE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | MOVE_BODY | NONLIVING | NO_SLEEP | NO_CONF|
+F:OPEN_DOOR | BASH_DOOR | IM_POIS | IM_COLD | DEMON | EVIL | ZANGBAND
+S:1_IN_3 |
+S:CAUSE_3 | HOLD | SCARE | BLIND | BO_ACID | S_DEMON |
+S:FORGET | BO_NETH | MIND_BLAST | DARKNESS
+D:"it was well over six feet in height, with great branches of antlers
+D:growing out of its forehead. Nude, its flesh was a uniform ash-gray
+D:in color. It appeared to be sexless, and it had gray, leathery wings
+D:extending far out behind it."
+
+N:652:Fallen angel
+G:A:s
+I:130:100d25:30:90:255
+W:49:6:0:8000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:GAZE:EXP_40:4d4
+B:GAZE:EXP_40:4d4
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | NO_FEAR | EVIL | REFLECTING |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | RES_TELE | RES_NETH |
+F:CAN_FLY | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:TELE_TO | BLIND | SCARE | CAUSE_2 | CAUSE_4 |
+S:S_DEMON | BO_NETH
+D:An angelic being, who was mighty once, but dared defy its Creator.
+
+N:653:Giant headless
+G:H:u
+I:110:30d12:20:50:40
+W:41:2:4000:900
+E:1:1:1:2:1:0
+O:0:100:0:0
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+F:FRIENDS | DROP_60 | DROP_90 | OPEN_DOOR | BASH_DOOR |
+F:DROP_SKELETON | DROP_CORPSE
+F:EVIL | ZANGBAND
+S:1_IN_6
+S:SCARE | BA_NUKE | BLIND
+D:Giant headless humanoid abominations created by a magical mutation.
+
+N:654:Judge Fire
+G:s:R
+I:120:18d100:90:70:10
+W:41:3:0:12000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:FIRE:5d5
+B:HIT:FIRE:5d5
+B:GAZE:EXP_80
+B:WAIL:TERRIFY
+F:UNIQUE | MALE | CAN_SPEAK | SUSCEP_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | POWERFUL |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | SUSCEP_COLD | IM_POIS | IM_FIRE | RES_PLAS |
+F:NO_CONF | NO_SLEEP | JOKEANGBAND | HAS_LITE | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:CAUSE_3 | BO_FIRE | BA_FIRE | BR_FIRE | BO_PLAS
+S:DARKNESS | S_MONSTER | S_DEMON | S_UNDEAD | TPORT | BLINK | SCARE
+D:One of the Dark Judges, he has come to punish your crime of living.
+D:He looks like a skeleton enveloped in flames.
+
+N:655:Ubbo-Sathla, the Unbegotten Source
+G:j:W
+I:120:20d100:90:80:10
+W:41:3:0:13500
+E:0:0:0:0:0:0
+O:30:50:0:10
+B:CRUSH:ACID:5d5
+B:HIT:POISON:5d5
+B:CRUSH:ACID:5d5
+B:HIT:POISON:5d5
+F:UNIQUE | CAN_SPEAK | NO_STUN | NO_SLEEP | NO_CONF | NO_STUN |
+F:FORCE_SLEEP | FORCE_MAXHP | ELDRITCH_HORROR | ESCORT |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | REGENERATE | SUSCEP_FIRE |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | KILL_BODY |
+F:EVIL | SUSCEP_FIRE | IM_COLD | IM_POIS | CTHANGBAND | NO_CUT
+D:"There, in the gray beginning of Earth, the formless mass that was
+D:Ubbo-Sathla reposed amid the slime and the vapors. Headless,
+D:without organs or members..."
+
+N:656:Judge Mortis
+G:z:G
+I:120:18d100:90:70:10
+W:41:3:0:13000
+E:1:1:1:2:1:1
+O:0:75:0:15
+B:HIT:POISON:5d5
+B:HIT:DISEASE:5d5
+B:TOUCH:LOSE_ALL
+B:TOUCH:EXP_80
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | SUSCEP_FIRE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | JOKEANGBAND | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:BLIND | SCARE | CAUSE_3 | BO_ACID | BO_NETH | BR_POIS |
+S:BR_NETH | BO_NETH | BLINK | TPORT | ANIM_DEAD
+S:BO_POIS | S_UNDEAD
+D:Another Dark Judge, he is a rotting humanoid with a cow's skull as
+D:his head.
+
+N:657:Dark elven sorcerer
+G:h:R
+I:130:80d10:20:70:10
+W:41:2:1300:3000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_90 | DROP_4D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | BLINK | TELE_TO | BLIND | CONF | CAUSE_3 | DARKNESS |
+S:BO_ACID | BA_FIRE | BA_COLD | ANIM_DEAD
+S:S_MONSTER | S_UNDEAD | S_DEMON | MISSILE
+D:A dark elven figure, dressed in deepest black. Power seems to crackle
+D:from his slender frame.
+
+N:658:Master lich
+G:L:r
+I:120:18d100:20:80:50
+W:41:2:1800:7000
+E:1:1:1:2:1:1
+O:10:45:25:10
+B:TOUCH:EXP_80
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:2d12
+B:TOUCH:LOSE_DEX:2d12
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_TELE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | BLIND | HOLD | CONF | SCARE | CAUSE_3 | CAUSE_4 |
+S:DRAIN_MANA | BRAIN_SMASH | S_UNDEAD
+D:A skeletal form wrapped in robes. Powerful magic crackles along its
+D:bony fingers.
+
+N:659:Byakhee
+G:U:D
+I:110:40d10:20:40:80
+W:41:3:1300:1500
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:CLAW:LOSE_STR:3d4
+B:BITE:EXP_20:3d4
+F:FORCE_SLEEP | FORCE_MAXHP | FRIENDS |
+F:ONLY_ITEM | DROP_2D2 | ELDRITCH_HORROR |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | CAN_FLY |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | CTHANGBAND
+S:1_IN_9 |
+S:BO_FIRE |
+S:S_DEMON | CONF
+D:"There flapped rhythmically a horde of tame, trained, hybrid
+D:winged things... not altogether crows, nor moles, nor buzzards,
+D:nor ants, nor decomposed human beings, but something I cannot
+D:and must not recall."
+
+N:660:Eol, the Dark Elf
+G:h:D
+I:130:80d30:20:100:60
+W:49:2:1400:25000
+E:1:1:1:2:1:1
+O:10:40:40:10
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | CAN_SPEAK |
+F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GOOD | DROP_CHOSEN |
+F:SMART | IM_ELEC | IM_COLD | IM_POIS | IM_FIRE |
+F:REFLECTING | OPEN_DOOR | BASH_DOOR | SPECIAL_GENE |
+F:HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | BLINK | TELE_TO | BLIND | CONF | CAUSE_4 | DARKNESS |
+S:BA_NETH | BA_ELEC | BA_ACID | BA_FIRE | BA_COLD | BO_MANA |
+S:S_MONSTERS | S_UNDEAD | S_DRAGON | S_DEMON
+D:A lord of the Teleri, Eol is a mighty metalsmith, the first
+D:one ever to forge weapons of meteorite iron. His dark
+D:countenance glares at you in disdain.
+
+N:661:Archon
+G:A:y
+I:130:100d35:30:140:255
+W:55:5:3200:12000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:GAZE:TERRIFY:4d4
+B:GAZE:TERRIFY:4d4
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | NO_FEAR | GOOD | REFLECTING |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | RES_TELE | CAN_FLY
+F:BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:TELE_TO | BLIND | SCARE | CAUSE_2 | CAUSE_4 | BO_MANA |
+S:S_ANGEL
+D:Never a more heavenly being have you seen. The very holiness of its
+D:presence makes you deeply respect it. Few creatures can match the powers
+D:of an Archon; fewer still live to tell the tale after attacking one.
+
+N:662:Formless spawn of Tsathoggua
+G:U:D
+I:110:22d20:20:40:80
+W:41:2:0:1850
+E:0:0:0:0:0:0
+O:35:45:0:10
+B:HIT:ACID:2d4
+B:HIT:ACID:2d4
+B:CRUSH:HURT:3d4
+B:BITE:ACID:6d6
+F:FORCE_SLEEP | FORCE_MAXHP | ELDRITCH_HORROR | NONLIVING |
+F:ONLY_ITEM | DROP_90 | REGENERATE | RES_TELE |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | CAN_SWIM |
+F:EVIL | DEMON | NO_CONF | NO_SLEEP | SUSCEP_FIRE | IM_POIS | CTHANGBAND | NO_CUT
+S:1_IN_9 |
+S:BO_FIRE | BO_ACID |
+S:S_DEMON | MIND_BLAST | DARKNESS |
+D:"...living things that oozed along stone channels...
+D:But they were not toads like Tsathoggua himself. Far worse --
+D:they were amorphous lumps of viscous black slime that took
+D:temporary shapes for various purposes."
+
+N:663:Hunting horror
+G:U:D
+I:110:30d17:20:90:80
+W:42:2:0:2300
+E:0:0:0:0:0:0
+O:45:35:0:10
+B:BITE:LOSE_DEX:1d3
+B:BITE:POISON:1d3
+B:CRUSH:HURT:9d4
+F:FORCE_SLEEP | FORCE_MAXHP | ELDRITCH_HORROR |
+F:ONLY_ITEM | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | CAN_FLY |
+F:EVIL | DEMON | HURT_LITE | IM_POIS |
+F:IM_FIRE | NO_CONF | NO_SLEEP | CTHANGBAND
+S:1_IN_9 |
+S:BLIND | CONF | S_DEMON | BR_DARK
+D:"And in the air there were great viperine creatures,
+D:which had curiously distorted heads, and grotesquely great
+D:clawed appendages, supporting themselves with ease by the aid
+D:of black rubbery wings of singularly monstrous dimensions."
+
+N:664:Undead beholder
+G:e:u
+I:120:27d100:30:100:10
+W:45:3:1600:8000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:EXP_40:3d6
+B:GAZE:UN_POWER:3d6
+B:GAZE:INSANITY:3d6
+B:BITE:EXP_40:7d6
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE |
+F:COLD_BLOOD | BASH_DOOR |
+F:EVIL | UNDEAD | CAN_FLY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:SLOW | CONF | CAUSE_4 | DRAIN_MANA | MIND_BLAST | FORGET |
+S:BO_MANA | BO_NETH | BRAIN_SMASH | BA_FIRE | BA_COLD | BO_ACID |
+S:S_UNDEAD | ANIM_DEAD
+D:A beholder which has cheated death. Black nether storms rage around the
+D:bloodshot pupil of its central giant eye, and light seems to bend as it
+D:sucks its power from the very air around it. Your soul chills as it drains
+D:your vitality for its evil enchantments.
+
+N:665:Shadow
+G:G:D
+I:120:10d20:30:30:20
+W:37:3:0:400
+E:0:0:0:0:0:0
+O:90:10:0:0
+B:TOUCH:EXP_80
+B:TOUCH:EXP_40
+B:CLAW:LOSE_INT:1d10
+B:CLAW:LOSE_WIS:1d10
+F:FORCE_SLEEP | CAN_FLY |
+F:ONLY_ITEM | DROP_1D2 | POWERFUL | REGENERATE | HURT_LITE |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | RES_NETH |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_8 |
+S:BO_NETH | TELE_TO | SLOW
+D:A mighty spirit of darkness of vaguely humanoid form. Razor-edged claws
+D:reach out to end your life as it glides towards you, seeking to suck the
+D:energy from your soul to feed its power.
+
+N:666:Iron lich
+G:L:s
+I:120:22d100:30:100:10
+W:42:4:0:10000
+E:0:0:0:0:1:0
+O:0:0:100:0
+B:BUTT:COLD:3d6
+B:BUTT:FIRE:3d6
+B:BUTT:ELEC:3d6
+F:FORCE_SLEEP | FORCE_MAXHP | REFLECTING |
+F:COLD_BLOOD | BASH_DOOR | CAN_FLY | SUSCEP_ACID |
+F:EVIL | UNDEAD | POWERFUL | SMART |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | RES_TELE |
+F:ONLY_ITEM | DROP_60 | DROP_GOOD |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:BA_WATE | BA_FIRE | BO_ICEE | BA_ELEC | BA_COLD |
+S:CAUSE_4 | DRAIN_MANA | BRAIN_SMASH | S_UNDEAD
+D:It is a huge, twisted grey skull floating through the air. Its cold eyes
+D:burn with hatred towards all who live.
+
+N:667:Dread
+G:G:o
+I:120:25d20:20:30:10
+W:42:1:1000:600
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:LOSE_STR:3d4
+F:FORCE_SLEEP |
+F:RAND_25 | FRIENDS | CAN_FLY |
+F:ONLY_ITEM | DROP_60 |
+F:TAKE_ITEM | INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | CONF | DRAIN_MANA | BO_NETH
+D:It is a form that screams its presence against the eye. Death incarnate,
+D:its hideous black body seems to struggle against reality as the universe
+D:itself struggles to banish it.
+
+N:668:Greater basilisk
+G:R:D
+I:120:20d100:25:100:15
+W:42:2:3000:10000
+E:0:1:0:2:1:0
+O:0:50:50:0
+B:GAZE:PARALYZE:3d12
+B:GAZE:PARALYZE:3d12
+B:BITE:POISON:2d12
+B:BITE:POISON:2d12
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | POWERFUL |
+F:OPEN_DOOR | BASH_DOOR | EVIL | IM_POIS | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP | CAN_SWIM |
+F:MORTAL | BASEANGBAND
+S:1_IN_8
+S:BR_POIS | BR_DARK | BR_NEXU
+D:A large basilisk, whose shape resembles that of a great wyrm.
+
+N:669:Charybdis
+G:~:r
+I:120:20d100:20:100:70
+W:42:1:15000:13000
+E:0:0:0:0:1:0
+O:50:50:0:0
+B:ENGULF:HURT:10d8
+B:ENGULF:HURT:10d8
+B:ENGULF:HURT:10d8
+F:AQUATIC | EVIL | UNIQUE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | DROP_GOOD |
+F:SMART | POWERFUL | MOVE_BODY | NEVER_MOVE |
+F:IM_ACID | IM_FIRE | IM_COLD | RES_WATE | COLD_BLOOD |
+F:IM_ELEC | IM_POIS | NO_STUN | ZANGBAND
+S:1_IN_5 |
+S:BA_WATE
+D:A monstrous dweller of the depths; its hungry maw has been the doom
+D:of innumerable sailors!
+
+N:670:Jack of Shadows
+G:p:s
+I:150:30d100:70:150:4
+W:60:4:2300:10000
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:5d10
+B:HIT:HURT:5d10
+B:HIT:EAT_ITEM:2d10
+B:HIT:EAT_ITEM:2d10
+F:MALE | FORCE_MAXHP | CAN_SPEAK | REFLECTING | DROP_SKELETON | DROP_CORPSE |
+F:REGENERATE |
+F:IM_ACID | IM_ELEC | IM_COLD | IM_FIRE | IM_POIS | RES_TELE |
+F:ONLY_ITEM | DROP_3D2 | DROP_GOOD | DROP_GREAT | UNIQUE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | SMART | POWERFUL |
+F:MORTAL | ZANGBAND
+S:1_IN_3
+S:BLIND | HEAL | BA_DARK | HASTE | CONF |
+D:Deriving his strength from the shadows, this king of thieves
+D:steals only for the challenge.
+
+N:671:Zephyr Lord
+G:W:v
+I:130:80d10:20:70:10
+W:43:2:600:3000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:EXP_20:8d2
+B:HIT:LOSE_STR:8d2
+B:HIT:LOSE_CON:8d2
+F:MALE | ATTR_MULTI | UNDEAD | EVIL |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS |
+F:ONLY_ITEM | DROP_90 | DROP_4D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:NO_STUN | NO_CONF | NO_SLEEP | ZANGBAND | NO_CUT
+S:1_IN_5 |
+S:SHRIEK | S_HOUND
+D:An undead master of the vicious Zephyr hounds.
+
+N:672:Juggernaut of Khorne
+G:g:D
+I:120:90d19:12:90:10
+W:43:3:6000:2500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BUTT:HURT:6d6
+B:CRUSH:HURT:8d6
+B:CRUSH:HURT:8d6
+B:BUTT:HURT:6d6
+F:COLD_BLOOD | BASH_DOOR | REFLECTING | KILL_ITEM |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | ZANGBAND | NO_CUT
+D:A great, vicious beast whose flesh is made of steel and whose
+D:blood is fire. It charges at you ignoring everything else.
+
+N:673:Mumak
+G:q:s
+I:110:90d10:20:55:100
+W:63:2:150000:2100
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BUTT:HURT:8d6
+B:BUTT:HURT:8d6
+B:CRUSH:HURT:8d4
+F:FRIENDS | DROP_CORPSE |
+F:BASH_DOOR | ANIMAL | MORTAL | BASEANGBAND
+D:A massive elephantine form with eyes twisted by madness.
+
+N:674:Judge Fear
+G:W:D
+I:120:18d100:90:70:10
+W:43:4:0:12000
+E:1:1:1:2:1:1
+O:100:0:0:0
+B:GAZE:TERRIFY
+B:GAZE:EXP_40
+B:GAZE:EXP_40
+B:GAZE:HURT:2d20
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | JOKEANGBAND | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | MIND_BLAST | BRAIN_SMASH |
+S:S_UNDEAD | DRAIN_MANA | FORGET | ANIM_DEAD
+D:A Dark Judge, reputedly so frightening that his gaze can kill.
+
+N:675:Ancient multi-hued dragon
+G:D:v
+I:120:21d100:25:100:80
+W:43:1:170000:13000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:HURT:7d10
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_ACID | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BLIND | CONF | SCARE |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS
+D:A huge draconic form. Many colours ripple down its massive frame. Few
+D:live to see another.
+
+N:676:Ethereal dragon
+G:D:o
+I:120:21d100:25:100:80
+W:45:2:170000:10000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:HURT:7d10
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 |
+F:INVISIBLE | CAN_FLY |
+F:PASS_WALL | POWERFUL | MOVE_BODY |
+F:DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF |
+S:BR_LITE | BR_DARK | BR_CONF
+D:A huge dragon emanating from the ethereal plane, this terrible creature is
+D:a master of light and dark. Its form disappears from sight as it cloaks
+D:itself in unearthly shadows.
+
+N:677:Dark young of Shub-Niggurath
+G:U:g
+I:120:12d100:20:75:80
+W:43:2:0:5000
+E:0:0:0:0:0:0
+O:0:40:30:20
+B:CRUSH:HURT:5d6
+B:CRUSH:HURT:5d6
+B:BITE:LOSE_STR:1d6
+B:BITE:LOSE_STR:1d6
+F:FORCE_SLEEP | FORCE_MAXHP | ELDRITCH_HORROR |
+F:ONLY_ITEM | DROP_1D2 | NONLIVING | CAN_SWIM |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | HURT_LITE |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | RES_TELE | CTHANGBAND
+S:1_IN_9 |
+S:BLIND | CAUSE_2 |
+S:S_DEMON | HEAL
+D:"Something black in the road, something that wasn't a tree.
+D:Something big and black and ropy, just squatting there, waiting,
+D:with ropy arms squirming and reaching... It came crawling up the
+D:hillside... and it was the black thing of my dreams... that black,
+D:ropy, slimy jelly tree-thing out of the woods. It crawled up and it
+D:flowed up on its hoofs and mouths and snaky arms."
+
+N:678:Colour out of space
+G:.:v
+I:120:12d100:20:100:10
+W:43:2:0:8000
+E:0:0:0:0:0:0
+O:35:35:10:10
+B:TOUCH:LOSE_ALL:7d6
+B:TOUCH:LOSE_ALL:7d6
+F:FORCE_SLEEP | FORCE_MAXHP | RAND_25 |
+F:INVISIBLE | PASS_WALL | CAN_FLY |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | ATTR_MULTI | ATTR_ANY |
+F:CHAR_CLEAR | SMART | COLD_BLOOD | EVIL |
+F:IM_COLD | IM_FIRE | IM_ACID | IM_ELEC | IM_POIS |
+F:NO_STUN | NO_CONF | NO_SLEEP | CTHANGBAND | HAS_LITE | NO_CUT
+S:1_IN_9 |
+S:DRAIN_MANA | BR_DISE | BR_NETH | TPORT
+D:"The shaft of phosphorescence from the well... was no longer shining
+D:out, it was pouring out; and as the shapeless stream of unplaceable
+D:colour left the well it seemed to flow directly into the sky."
+
+N:679:Quaker, Master of Earth
+G:E:u
+I:110:28d100:10:97:90
+W:43:3:0:4500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:SHATTER:10d10
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD | KILL_WALL |
+F:KILL_ITEM | KILL_BODY | PASS_WALL | POWERFUL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT | NO_STUN
+S:1_IN_6 |
+S:BO_ACID | BA_ACID
+D:A towering stone elemental stands before you. The walls and ceiling are
+D:reduced to rubble as Quaker advances.
+
+N:680:Death leprechaun
+G:h:D
+I:120:6d6:8:13:8
+W:44:6:0:85
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:TOUCH:EXP_40:1d10
+B:TOUCH:EAT_GOLD
+B:TOUCH:EAT_ITEM
+F:INVISIBLE | RAND_25 | TAKE_ITEM | COLD_BLOOD | SMART |
+F:HURT_LITE | EVIL | OPEN_DOOR | MALE | UNDEAD | RES_NETH | ZANGBAND | NO_CUT
+S:MULTIPLY |
+S:1_IN_6 |
+S:BLINK | TPORT | TELE_TO | CAUSE_3 | ANIM_DEAD
+D:Nasty undead little creatures. They are chanting the name of the
+D:sinister wizard who created them: 'Bruce! Bruce..!'
+
+N:681:Chaugnar Faugn, Horror from the Hills
+G:q:D
+I:110:20d100:10:125:90
+W:44:4:0:6250
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:10d10
+B:CRUSH:HURT:10d10
+B:BITE:LOSE_CON:8d2
+B:BITE:LOSE_CON:8d1
+F:UNIQUE | CAN_SPEAK | EVIL | DEMON |
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE |
+F:ELDRITCH_HORROR | POWERFUL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK |
+F:NO_CONF | NO_FEAR | CTHANGBAND
+S:1_IN_6 |
+S:HOLD | CAUSE_4 | CONF | SCARE | FORGET | BRAIN_SMASH |
+S:MIND_BLAST | CAUSE_3 | S_DEMON | S_MONSTERS
+D:"The ears were webbed and tentacled, the trunk terminated in
+D:a huge flaring disk at least a foot in diameter... Its forelimbs
+D:were bent stiffly at the elbow, and its hands... rested palms
+D:upward on its lap."
+
+N:682:Lloigor
+G:v:B
+I:120:100d15:20:100:20
+W:44:2:0:6000
+E:0:0:0:0:0:0
+O:90:0:10:0
+B:ENGULF:LOSE_CON:4d10
+B:ENGULF:LOSE_CON:4d10
+B:ENGULF:LOSE_CON:4d10
+F:FORCE_SLEEP | ELDRITCH_HORROR | PASS_WALL |
+F:INVISIBLE | DROP_2D2 | DROP_4D2 | CAN_FLY |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | POWERFUL |
+F:SMART | IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS |
+F:MORTAL | CTHANGBAND | HAS_LITE | NO_CUT
+S:1_IN_4 |
+S:BR_WALL | TELE_AWAY | BR_GRAV |
+S:S_KIN | MIND_BLAST | BLIND | BLINK
+D:"Invisible ones from the stars... They sometimes took forms...
+D:but existed as vortices of power in their natural state."
+
+N:683:Utgard-Loke
+G:P:v
+I:120:40d100:30:125:15
+W:44:3:0:13500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:COLD:12d12
+B:HIT:COLD:12d12
+B:HIT:COLD:12d12
+B:HIT:COLD:12d12
+F:ESCORT | UNIQUE | IM_COLD | AURA_COLD | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | MALE | ZANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | TELE_TO |
+S:S_KIN | BR_COLD
+D:A frost giant chieftain, unusually smart for a giant.
+
+N:684:Quachil Uttaus, Treader of the Dust
+G:z:D
+I:120:50d66:30:80:15
+W:44:3:0:20000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:CLAW:HURT:50d1
+B:TOUCH:TIME:1d50
+B:TOUCH:TIME:1d50
+F:ESCORT | UNIQUE | IM_COLD | ELDRITCH_HORROR | RES_NETH |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | KILL_BODY | DROP_GREAT |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | NO_SLEEP | NO_CONF
+F:EVIL | UNDEAD | DEMON | REGENERATE | CTHANGBAND | NO_CUT
+S:1_IN_3 |
+S:BR_TIME | SLOW | HASTE | HEAL
+D:"It was a figure no larger than a young child, but severe and
+D:shriveled as some millenial mummy. Its hairless head, its
+D:unfeatured face, borne on a neck of skeleton thinness, were
+D:lined with a thousand reticulated wrinkles. The body was like
+D:that of some monstrous, withered abortion that had never drawn
+D:breath. The pipelike arms, ending in bony claws, were outhrust as if
+D:enclosed in a posture of an eternal dreadful grasping."
+
+N:685:Shoggoth
+G:j:D
+I:140:50d20:20:80:20
+W:44:2:0:2500
+E:0:0:0:0:0:0
+O:30:70:0:0
+B:CRUSH:ACID:5d6
+B:CRUSH:ACID:5d6
+B:CRUSH:ACID:5d6
+B:CRUSH:HURT:9d9
+F:REGENERATE | ONLY_ITEM | KILL_ITEM | DROP_2D2 | DROP_90 | DROP_60
+F:BASH_DOOR | EVIL | NO_CONF | NO_SLEEP | KILL_BODY | CAN_SWIM |
+F:FORCE_MAXHP | FORCE_SLEEP | HURT_LITE | POWERFUL |
+F:IM_ACID | IM_FIRE | RES_PLAS | IM_POIS | IM_COLD | IM_ELEC | RES_TELE
+F:CTHANGBAND | HAS_LITE | NO_CUT
+D:"The nightmare, plastic column of fetid, black iridescence oozed
+D:tightly onward... A shapeless congerie of protoplasmic bubbles,
+D:faintly self-luminous and with myriads of temporary eyes forming
+D:and unforming as pustules of greenish light all over the
+D:tunnel-filling front that bore down upon us, crushing the frantic
+D:penguins and slithering over glistening floor that it and its
+D:kind had swept so evilly free of all litter. Still came that eldritch
+D:mocking cry -- 'Tekeli-li! Tekeli-li!'"
+
+N:686:Judge Death
+G:W:D
+I:120:45d50:90:90:10
+W:43:3:0:14000
+E:1:1:1:2:1:1
+O:0:20:80:0
+B:CLAW:POISON:10d5
+B:CLAW:POISON:10d5
+B:CLAW:EXP_40:10d1
+B:GAZE:TERRIFY
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_ELEC | IM_COLD | SUSCEP_FIRE |
+F:IM_POIS | NO_CONF | NO_SLEEP | JOKEANGBAND | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_4 | BA_FIRE | BA_NETH | ANIM_DEAD
+S:S_MONSTERS | S_UNDEAD | S_HI_UNDEAD | DRAIN_MANA |
+D:The most powerful Dark Judge, whose touch means death.
+
+N:687:Ariel, Queen of Air
+G:E:B
+I:130:27d100:12:50:50
+W:43:3:0:4750
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:4d6
+B:HIT:CONFUSE:4d4
+B:HIT:HURT:4d6
+B:HIT:CONFUSE:4d4
+F:UNIQUE | FEMALE | AURA_ELEC | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:RAND_25 | CAN_FLY |
+F:EMPTY_MIND | COLD_BLOOD |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_ACID | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BO_ELEC | BA_COLD | BA_ELEC
+D:A towering air elemental, Ariel the sorceress avoids your blows
+D:with her extreme speed.
+
+N:688:11-headed hydra
+G:M:R
+I:120:100d18:20:100:20
+W:44:2:8500:6000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:ONLY_GOLD | DROP_2D2 | DROP_4D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:ANIMAL | IM_FIRE | CAN_SWIM |
+F:MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:SCARE | BO_FIRE | BO_PLAS | BA_FIRE | BR_FIRE
+D:A strange reptilian hybrid with eleven smouldering heads.
+
+N:689:Patriarch
+G:p:G
+I:120:52d10:20:60:10
+W:40:2:1800:1800
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d5
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | BLIND | HOLD | CAUSE_4 | CAUSE_3 | ANIM_DEAD |
+S:S_MONSTERS | S_UNDEAD
+D:An evil priest, dressed all in black. Deadly spells hit you at an
+D:alarming rate as his black spiked mace rains down blow after blow on your
+D:pitiful frame.
+
+N:690:Dreadmaster
+G:G:y
+I:120:12d100:20:100:10
+W:44:2:1000:8000
+E:0:0:0:0:0:0
+O:10:40:25:10
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:LOSE_STR:3d4
+B:HIT:LOSE_STR:3d4
+F:FORCE_SLEEP | FORCE_MAXHP | RAND_25 |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | CAN_FLY |
+F:SMART | TAKE_ITEM | INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_9 |
+S:TELE_LEVEL | BLIND | HOLD | CONF | CAUSE_4 | DRAIN_MANA | BO_NETH |
+S:S_UNDEAD
+D:It is an unlife of power almost unequalled. An affront to existence, its
+D:very touch abuses and disrupts the flow of life, and its unearthly limbs,
+D:of purest black, crush rock and flesh with ease.
+
+N:691:Drolem
+G:g:g
+I:120:30d100:25:130:30
+W:44:3:40000:12000
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d10
+B:CLAW:HURT:3d10
+B:BITE:POISON:5d10
+B:BITE:POISON:5d10
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:DRAGON | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+F:ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | SLOW | CONF | ARROW_3 |
+S:BR_POIS
+D:A constructed dragon, the drolem has massive strength. Powerful spells
+D:weaved during its creation make it a fearsome adversary. Its eyes show
+D:little intelligence, but it has been instructed to destroy all it meets.
+
+N:692:Scatha the Worm
+G:D:W
+I:120:22d100:30:130:70
+W:46:2:210000:17000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:COLD:4d14
+B:BITE:COLD:4d14
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | SUSCEP_FIRE |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_CORPSE
+F:BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:CONF | CAUSE_3 |
+S:BR_COLD
+D:An ancient and wise dragon, Scatha has grown clever over the long years.
+D:His scales are covered with frost, and his breath sends a shower of ice
+D:into the air.
+
+N:693:Warrior of the Dawn
+G:p:R
+I:120:25d25:20:70:20
+W:45:2:1600:500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:IM_POIS | IM_FIRE | IM_ELEC | IM_ACID | IM_COLD |
+F:NO_SLEEP | NO_FEAR |
+F:FRIENDS |
+F:MALE | OPEN_DOOR | BASH_DOOR | ZANGBAND | HAS_LITE
+D:Fierce, barbaric warriors, armed with great spiked clubs, and surrounded
+D:in an aura of scarlet. Whenever one of them is slain, another appears
+D:out of nowhere to take his place.
+
+N:694:Lesser black reaver
+G:L:D
+I:120:25d100:20:120:50
+W:45:3:2600:12000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:HIT:UN_BONUS:4d8
+B:HIT:UN_BONUS:4d8
+B:HIT:LOSE_STR:4d6
+B:HIT:LOSE_STR:4d6
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | CAN_SWIM |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | RES_TELE
+F:NO_CONF | NO_SLEEP | KILL_WALL | NO_FEAR
+F:MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:TELE_TO | BLIND | HOLD | CONF | CAUSE_3 | DRAIN_MANA |
+S:MIND_BLAST | BA_NETH | ANIM_DEAD
+D:A humanoid form, black as night, advancing steadily and unstoppably.
+
+N:695:Zoth-Ommog
+G:R:v
+I:120:25d100:12:50:50
+W:45:4:0:18000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:25d3
+B:CRUSH:HURT:25d3
+B:BITE:LOSE_DEX:2d10
+B:BITE:LOSE_CON:2d10
+F:UNIQUE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:RAND_25 | CAN_SWIM | ELDRITCH_HORROR |
+F:KILL_ITEM | BASH_DOOR | POWERFUL |
+F:EVIL | IM_ACID | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_FEAR | CTHANGBAND
+S:1_IN_5 |
+S:S_MONSTER | SCARE | CAUSE_4 | S_HYDRA | S_SPIDER |
+S:BA_NETH | BA_POIS | BA_ACID | CAUSE_3 | HOLD | MIND_BLAST
+D:"A body shaped like a road-based, truncated cone. A flat, blunt,
+D:wedge-shaped, vaguely reptilian head surmounts this conical torso,
+D:and the head is almost entirely hidden behind swirling tresses.
+D:This hair, or beard and mane, consists of thickly carved and
+D:coiling ropes, like serpents or worms... Through this repulsive
+D:Medusa-mane of ropy tendrils, two fierce, serpent-like eyes
+D:glare in a horrible intermingling of cold, inhuman mockery and
+D:what I can only describe as gloating menace."
+
+N:696:Grand master thief
+G:p:b
+I:130:15d100:50:75:40
+W:46:2:0:1500
+E:1:1:1:2:1:1
+O:70:10:10:10
+B:HIT:EAT_ITEM:5d5
+B:HIT:EAT_ITEM:5d5
+B:HIT:EAT_GOLD:5d5
+B:HIT:EAT_GOLD:5d5
+F:MALE | DROP_2D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT | TELE_TO | CONF | TRAPS | ARROW_2
+D:A class of its own: you are already too late to protect your possessions -
+D:and he seems to have studied magic too, and is a master of setting traps.
+
+N:697:Smaug the Golden
+G:D:R
+I:120:24d100:30:150:80
+W:48:2:230000:23000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:FIRE:5d14
+B:BITE:FIRE:5d14
+F:UNIQUE | MALE | REFLECTING | CAN_FLY | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SPEAK |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:SMART | EVIL | DRAGON | IM_FIRE | BASEANGBAND
+F:HAS_LITE
+S:1_IN_4 |
+S:CONF | CAUSE_3 |
+S:BR_FIRE
+D:Smaug is one of the Uruloki that still survive, a fire-drake of immense
+D:cunning and intelligence. His speed through air is matched by few other
+D:dragons, his dragonfire is legendary, and his hide is
+D:armoured with diamonds. He is believed to be the greatest dragon still
+D:surviving into the Third Age.
+
+N:698:The Stormbringer
+G:|:D
+I:120:13d123:20:99:20
+W:45:2:0:13333
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:WAIL:TERRIFY
+B:HIT:EXP_80:64d1
+B:HIT:EXP_80:64d1
+B:HIT:EXP_80:8d8
+F:CHAR_MULTI | EVIL | IM_POIS | IM_COLD | IM_FIRE | RES_NETH |
+F:FORCE_SLEEP | UNIQUE | FORCE_MAXHP | CAN_FLY |
+F:COLD_BLOOD | BASH_DOOR | NONLIVING |
+F:NO_CONF | NO_SLEEP | NO_FEAR | ZANGBAND | HAS_LITE | NO_CUT | NO_STUN
+D:The mightiest of hellblades, a black runesword which thirsts for
+D:your soul.
+
+N:699:Knight Templar
+G:p:w
+I:120:60d20:20:60:10
+W:44:2:1800:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:IM_POIS | IM_FIRE | IM_ELEC | IM_ACID | IM_COLD | GOOD |
+F:RES_NETH | RES_NEXU | RES_DISE | RES_TELE | DROP_SKELETON | DROP_CORPSE
+F:NO_SLEEP | NO_CONF | NO_FEAR | NO_STUN |
+F:DROP_2D2 | DROP_90 | REFLECTING |
+F:MALE | OPEN_DOOR | BASH_DOOR | FORCE_MAXHP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:HEAL | CAUSE_3 | CAUSE_4 | HASTE | SCARE | BLIND | S_ANGEL
+D:It seems that the more devout the person, the more likely they are to cross
+D:the boundary between piety and sanctimoniousness. And such is the case with
+D:the Order of the Knights Templar; they are among the most pious and
+D:powerful of the religious knightly orders, but noted for their intolerance.
+D:Thus it is Morgoth's will that is unwittingly done, as the forces of good
+D:are set against each other.
+
+N:700:Leprechaun fanatic
+G:h:r
+I:123:6d6:8:13:8
+W:46:6:800:80
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:EXPLODE:HURT:20d3
+F:RAND_25 | TAKE_ITEM | SMART |
+F:EVIL | OPEN_DOOR | MALE |
+F:MORTAL | ZANGBAND
+S:MULTIPLY |
+S:1_IN_6 |
+S:BLINK | TPORT | TELE_TO
+D:These leprechauns are not afraid to die for their cause. They are
+D:carrying explosives and making terrorist strikes...
+
+N:701:Dracolich
+G:D:G
+I:120:35d100:25:120:80
+W:55:2:180000:18000
+E:0:1:0:6:1:0
+O:10:50:40:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:EXP_80:7d14
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | RES_TELE |
+F:COLD_BLOOD | CAN_FLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT | ATTR_MULTI
+S:1_IN_6 |
+S:CONF | SCARE |
+S:BR_COLD | BR_NETH
+D:The skeletal form of a once-great dragon, enchanted by magic most
+D:perilous. Its animated form strikes with speed and drains life from its
+D:prey to satisfy its hunger.
+
+N:702:Greater titan
+G:P:o
+I:120:38d100:30:125:15
+W:66:3:50000:23500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:CONFUSE:12d12
+B:HIT:CONFUSE:12d12
+B:HIT:CONFUSE:12d12
+B:HIT:CONFUSE:12d12
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_4D2 | DROP_1D2 | DROP_GOOD | MOVE_BODY |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | MALE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | TELE_TO |
+S:S_MONSTERS
+D:A forty foot tall humanoid that shakes the ground as it walks. The power
+D:radiating from its frame shakes your courage, its hatred inspired by your
+D:defiance.
+
+N:703:Dracolisk
+G:D:R
+I:120:35d100:25:120:80
+W:55:2:180000:18000
+E:0:1:0:6:1:0
+O:0:50:40:10
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:FIRE:7d14
+B:GAZE:PARALYZE
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | RES_NEXU | RES_TELE |
+F:ANIMAL | EVIL | DRAGON | IM_ACID | IM_FIRE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:HOLD | SCARE |
+S:BR_FIRE | BR_NEXU
+D:A mixture of dragon and basilisk, the dracolisk stares at you with deep
+D:piercing eyes, its evil breath burning the ground where it stands.
+
+N:704:Winged Horror
+G:B:D
+I:120:25d80:30:80:5
+W:48:3:4500:4000
+B:CLAW:HURT:3d8
+B:CLAW:HURT:3d8
+B:BITE:EXP_40:4d6
+B:BITE:EXP_40:4d6
+F:ANIMAL | MORTAL | EVIL | CAN_FLY | BASH_DOOR | IM_COLD | IM_POIS
+F:WILD_TOO | WILD_WASTE | WILD_WOOD | WILD_SWAMP | BASEANGBAND
+S:1_IN_6
+S:BR_NETH | BR_DARK | BR_POIS
+D:A terrifying sight: a winged creature greater than any bird you have ever
+D:seen, and with no feathers on its horrid black leathery wings. Descended
+D:from a creature of an older world perhaps, bred by Sauron to be a winged
+D:steed for his Ringwraiths.
+
+N:705:Spectral tyrannosaur
+G:R:G
+I:120:70d50:25:120:30
+W:46:3:0:15000
+E:0:0:0:0:0:0
+O:20:20:20:20
+B:BITE:EXP_40:2d13
+B:BITE:EXP_40:2d13
+B:BITE:LOSE_STR:5d8
+B:GAZE:TERRIFY
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:EVIL | UNDEAD | ANIMAL | RES_NEXU | RES_TELE
+F:NO_CONF | NO_FEAR | NO_SLEEP |
+F:IM_POIS | IM_ACID | IM_COLD |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | ZANGBAND | NO_CUT
+S:1_IN_6 |
+S:HOLD | SCARE |
+S:BR_NEXU | BR_POIS | BR_NETH
+D:A deadly undead horror which looks like a skeletal tyrannosaur
+D:surrounded by a sickly green glow.
+
+N:706:Yibb-Tstll, the Patient One
+G:P:D
+I:120:99d21:20:100:20
+W:46:2:0:16000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:LOSE_ALL:1d166
+B:TOUCH:LOSE_ALL:1d166
+F:UNIQUE | FORCE_SLEEP | FORCE_MAXHP |
+F:ELDRITCH_HORROR | NEVER_MOVE | REGENERATE | POWERFUL |
+F:DROP_2D2 | DROP_4D2 | DROP_GOOD | ONLY_ITEM |
+F:SMART | IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS | CTHANGBAND
+S:1_IN_4 |
+S:BR_NUKE | S_DEMON | DARKNESS | S_UNDEAD | ANIM_DEAD
+S:BR_NEXU | BR_CHAO
+D:"There, about the pulsating body of the Ancient One, hugely
+D:winged reptilian creatures without faces cluttered and clutched
+D:at a multitude of blackly writhing, pendulous breasts! Its eyes
+D:moved quickly, independently -- sliding with vile viscosity over
+D:the whole rotten surface of Yib-Tstll's pulpy, glistening head!"
+
+N:707:Ghatanothoa
+G:v:D
+I:120:100d20:20:100:20
+W:46:2:0:16000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:CLAW:LOSE_INT:5d10
+B:CLAW:LOSE_WIS:5d10
+B:BITE:CONFUSE:5d10
+F:FORCE_SLEEP | ELDRITCH_HORROR | PASS_WALL | UNIQUE |
+F:INVISIBLE | DROP_2D2 | DROP_4D2 | CAN_FLY | DROP_GOOD | ONLY_ITEM |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | POWERFUL | NO_CONF | NO_SLEEP |
+F:SMART | IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS |
+F:MORTAL | CTHANGBAND | NO_CUT
+S:1_IN_4 |
+S:BR_WALL | TELE_AWAY | BR_GRAV | TELE_LEVEL | S_DEMON | S_UNDEAD | S_KIN |
+S:BRAIN_SMASH | HASTE | BLIND | BLINK | BR_INER | CAUSE_3 | CAUSE_4
+D:The chief among the creatures known as Lloigor. Ghatanothoa, unlike most of
+D:his kind, has assumed a shape, and one which is too horrible to describe:
+D:"Nothing I could say could even adumbrate the loathsome, unholy, non-human,
+D:extra-galactic horror and hatefulness and unutterable evil of that forbidden
+D:spawn of black chaos, and illimitable night."
+
+N:708:Ent
+G:#:G
+I:110:40d100:30:120:15
+W:46:3:0:12500
+E:1:1:1:2:1:1
+O:30:50:20:0
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+F:FORCE_SLEEP | FORCE_MAXHP | PET | SUSCEP_FIRE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
+F:SMART | TAKE_ITEM | KILL_WALL | BASH_DOOR |
+F:GOOD | BASEANGBAND | NO_CUT
+D:A tree-herd: a sentient, moving tree. Its wrath is fearsome, and it could
+D:split stones and even the very rock of Isengard with its roots.
+
+N:709:Hru
+G:P:s
+I:120:40d100:30:150:15
+W:54:3:40000:14500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:SHATTER:12d13
+B:HIT:SHATTER:12d13
+B:HIT:SHATTER:12d13
+B:HIT:SHATTER:12d13
+F:FORCE_SLEEP | FORCE_MAXHP | HURT_ROCK |
+F:ONLY_GOLD | DROP_4D2 | MOVE_BODY | KILL_WALL |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | MALE | HAS_LITE | NO_CUT
+D:A rock giant, a being made of living stone.
+
+N:710:Itangast the Fire Drake
+G:D:R
+I:120:22d100:30:120:70
+W:47:2:220000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:FIRE:4d14
+B:BITE:FIRE:4d14
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | SUSCEP_COLD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_FIRE | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:CONF | CAUSE_3 |
+S:BR_FIRE
+D:A mighty ancient dragon, Itangast's form scorches your flesh. Wisps of
+D:smoke curl up from his nostrils as he regards you with disdain.
+
+N:711:Death mold
+G:m:D
+I:140:100d20:200:60:0
+W:47:1:100:1000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:UN_BONUS:7d7
+B:SPORE:UN_BONUS:7d7
+B:SPORE:UN_BONUS:7d7
+B:SPORE:EXP_80:5d5
+F:FORCE_SLEEP | NEVER_MOVE | CAN_SWIM |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is the epitome of all that is evil, in a mold. Its lifeless form draws
+D:power from sucking the souls of those that approach it; a nimbus of pure
+D:evil surrounds it. Luckily for you, it can't move...
+
+N:712:Fafner the Dragon
+G:D:G
+I:120:25d110:30:130:80
+W:48:2:170000:25000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:FIRE:5d14
+B:BITE:POISON:5d14
+F:UNIQUE | MALE | SUSCEP_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SPEAK | DROP_CORPSE |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | INVISIBLE |
+F:EVIL | DRAGON | IM_FIRE | IM_POIS | ZANGBAND |
+F:HAS_LITE
+S:1_IN_3 |
+S:CONF | CAUSE_3 |
+S:BR_FIRE | BR_POIS | SCARE | CAUSE_3 | CONF
+D:The mighty dragon of myth, Fafner was a giant who slew his
+D:brother to win a treasure hoard, and then transformed himself
+D:into a dragon, greedily watching over his gold.
+
+N:713:Charon, Boatman of the Styx
+G:W:B
+I:120:28d100:30:100:10
+W:47:3:0:25000
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:WAIL:LOSE_ALL
+B:TOUCH:UN_POWER
+B:HIT:EXP_80:8d12
+B:HIT:EAT_GOLD:8d12
+F:UNIQUE | MALE | SMART | CAN_SWIM |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_GOLD | DROP_3D2 | DROP_4D2 |
+F:COLD_BLOOD | PASS_WALL | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_STUN | NO_CONF | NO_SLEEP | RES_TELE | ZANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | DARKNESS |
+S:BO_ICEE | BO_NETH | BA_COLD | BA_NETH | BA_WATE |
+S:S_UNDEAD
+D:The ferryman across the river Styx to the land of the dead.
+D:He wishes to receive payment for your entry.
+
+N:714:Quickbeam, the Ent
+G:#:G
+I:120:40d100:30:120:15
+W:47:3:0:13500
+E:1:1:1:2:1:1
+O:10:50:20:10
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | CAN_SPEAK |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY | SUSCEP_FIRE |
+F:SMART | TAKE_ITEM | KILL_WALL | BASH_DOOR |
+F:GOOD | PET | BASEANGBAND | NO_CUT
+D:Unusually hasty, for an ent. Quickbeam hates evil creatures, and orcs in
+D:particular, since the destruction of his beloved rowan-trees to feed the
+D:fires of Orthanc.
+
+N:715:Glaurung, Father of the Dragons
+G:D:R
+I:130:120d100:20:125:70
+W:70:2:300000:50000
+E:0:1:0:6:1:0
+O:30:70:0:0
+B:CLAW:HURT:5d12
+B:CLAW:HURT:5d12
+B:BITE:FIRE:8d14
+B:BITE:POISON:8d14
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_RANDART
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:SMART | EVIL | DRAGON | IM_POIS | IM_FIRE |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BLIND | CONF | SCARE |
+S:BR_FIRE | BR_POIS | BR_SOUN | S_HI_DRAGON
+D:Glaurung is the father of all dragons, and was for a long time the most
+D:powerful. Though this is no longer so, he still has full command over
+D:his brood and can command them to appear whenever he so wishes. He is
+D:the definition of dragonfire.
+
+N:716:Behemoth
+G:H:B
+I:120:50d100:25:180:30
+W:49:3:6000:16000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:5d8
+B:BITE:FIRE:5d8
+B:CRUSH:HURT:3d15
+B:CRUSH:HURT:3d15
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SWIM | ANIMAL | AQUATIC |
+F:IM_FIRE | IM_ACID | IM_COLD | IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND
+S:1_IN_9
+S:BR_FIRE
+D:A great water-beast, with an almost impenetrable skin.
+
+N:717:Garm, Guardian of Hel
+G:C:b
+I:120:30d100:20:120:70
+W:49:2:0:25000
+E:0:1:0:2:1:0
+O:50:50:0:0
+B:CLAW:HURT:7d13
+B:CLAW:HURT:7d13
+B:BITE:HURT:8d13
+B:BITE:HURT:8d13
+F:UNIQUE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | RES_NETH |
+F:ANIMAL | EVIL | IM_FIRE | NO_SLEEP | ZANGBAND
+S:1_IN_3 |
+S:BR_NETH | BR_COLD | BR_DARK |
+S:S_HOUND | S_UNDEAD
+D:Garm is a gigantic hound, whose job is to guard that none escapes
+D:the tortures of Hel, the place of punishment for the wicked
+D:and cowardly dead.
+
+N:718:Greater wall monster
+G:#:W
+I:120:15d40:20:80:20
+W:44:4:0:900
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:FORCE_SLEEP | COLD_BLOOD | EMPTY_MIND | PASS_WALL | RAND_50 |
+F:BASH_DOOR | IM_COLD | IM_ACID | IM_FIRE | IM_ELEC | IM_POIS | NONLIVING |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | CHAR_MULTI | CAN_FLY | BASEANGBAND
+F:NO_CUT
+S:MULTIPLY |
+D:A sentient, moving section of wall.
+
+N:719:Nycadaemon
+G:U:o
+I:120:29d99:20:80:80
+W:51:3:0:10000
+E:1:1:1:2:1:1
+O:50:0:50:0
+B:TOUCH:TERRIFY
+B:CLAW:HURT:6d6
+B:CLAW:HURT:6d6
+B:CLAW:HURT:6d6
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE | NONLIVING |
+F:REGENERATE | IM_ACID | IM_COLD | IM_FIRE | CAN_FLY |
+F:NO_SLEEP | NO_STUN | NO_CONF | EVIL | DEMON |
+F:INVISIBLE | KILL_WALL |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | BASEANGBAND
+S:1_IN_4 |
+S:HOLD | BLINK | CONF | S_DEMON | BRAIN_SMASH | BR_NETH
+D:A loathsome, sturdy, winged, horned demon, with talons that could tear
+D:a stone wall down.
+
+N:720:Barbazu
+G:U:G
+I:120:120d10:25:60:80
+W:55:2:0:3000
+E:1:1:1:2:1:1
+O:20:40:20:20
+B:HIT:HURT:4d10
+B:HIT:HURT:4d10
+B:HIT:LOSE_CON:10d2
+B:STING:POISON:5d5
+F:FORCE_SLEEP | FORCE_MAXHP | FRIENDS |
+F:ONLY_ITEM | DROP_1D2 | NONLIVING | BASEANGBAND |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON | IM_POIS | NO_CONF | NO_SLEEP
+S:1_IN_7 |
+S:SCARE | S_DEMON
+D:A foul, humanoid creature with a long tail, clawed hands and feet,
+D:and a disgusting, wiry, snaky beard. They are the elite shock troops
+D:of the hells, capable of a terrifying berserk fury.
+
+N:721:Goat of Mendes
+G:q:D
+I:120:18d111:30:66:40
+W:50:3:0:6666
+E:0:1:0:2:1:0
+O:0:0:100:0
+B:GAZE:TERRIFY
+B:BUTT:HURT:6d6
+B:BITE:EXP_40
+B:BITE:LOSE_CON
+F:EVIL | DEMON | FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | SMART | NONLIVING |
+F:NO_CONF | NO_SLEEP | HURT_LITE | IM_FIRE | IM_COLD | ZANGBAND
+S:1_IN_4 |
+S:BLIND | CONF | BRAIN_SMASH | SCARE | ANIM_DEAD
+S:BA_NETH | FORGET | S_UNDEAD | DRAIN_MANA |
+S:S_DEMON | CAUSE_4 | BA_COLD
+D:It is a demonic creature from the lowest hell, vaguely resembling a
+D:large black he-goat.
+
+N:722:Nightwing
+G:W:D
+I:120:60d60:20:120:10
+W:61:4:0:10000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:TOUCH:POISON:6d5
+B:TOUCH:POISON:6d5
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | RES_TELE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLIND | SCARE | CAUSE_4 | BRAIN_SMASH |
+S:BO_MANA | BO_NETH | BA_NETH | S_UNDEAD
+D:Everywhere colours seem paler and the air chiller. At the centre of the
+D:cold stands a mighty figure. Its wings envelop you in the chill of death
+D:as the nightwing reaches out to draw you into oblivion. Your muscles sag
+D:and your mind loses all will to fight as you stand in awe of this mighty
+D:being.
+
+N:723:Maulotaur
+G:H:s
+I:130:250d13:13:50:10
+W:50:2:40000:4500
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:SHATTER:8d8
+B:HIT:SHATTER:8d8
+B:BUTT:HURT:4d6
+B:BUTT:HURT:4d6
+F:ONLY_ITEM | DROP_60 | DROP_GOOD | RES_TELE |
+F:BASH_DOOR | STUPID | DROP_CORPSE |
+F:EVIL | IM_FIRE | FORCE_SLEEP | FORCE_MAXHP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BO_PLAS | BA_FIRE
+D:It is a belligerent minotaur with a destructive magical arsenal, armed
+D:with a hammer.
+
+N:724:Nether hound
+G:Z:G
+I:120:60d10:30:100:0
+W:51:2:800:5000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d12
+B:CLAW:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+F:FORCE_SLEEP |
+F:FRIENDS | RES_NETH | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BR_NETH
+D:You feel a soul-tearing chill upon viewing this beast, a ghostly form of
+D:darkness in the shape of a large dog.
+
+N:725:Time hound
+G:Z:B
+I:130:60d10:30:100:0
+W:51:2:800:5000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d12
+B:CLAW:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_TIME
+D:You get a terrible sense of deja vu, or is it a premonition? All at once
+D:you see a little puppy and a toothless old dog. Perhaps you should give
+D:up and go to bed.
+
+N:726:Plasma hound
+G:Z:R
+I:120:60d10:30:100:0
+W:51:2:800:5000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d12
+B:CLAW:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+F:FORCE_SLEEP | SUSCEP_COLD |
+F:FRIENDS | RES_PLAS |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | IM_FIRE | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_5 |
+S:BR_PLAS
+D:The very air warps as pure elemental energy stalks towards you in the
+D:shape of a giant hound. Your hair stands on end and your palms itch as
+D:you sense trouble.
+
+N:727:Demonic quylthulg
+G:Q:r
+I:120:48d10:20:1:0
+W:45:1:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_DEMON
+D:A pile of pulsing flesh that glows with an inner hellish fire. The world
+D:itself seems to cry out against it.
+
+N:728:Great Storm Wyrm
+G:D:b
+I:120:40d100:30:150:80
+W:63:2:190000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:ELEC:6d14
+B:BITE:ELEC:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_ELEC | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | IM_ELEC | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_ELEC
+D:A vast dragon of power. Storms and lightning crash around its titanic
+D:form. Deep blue scales reflect the flashes and highlight the creature's
+D:great muscles. It regards you with contempt.
+
+N:729:Ulik the Troll
+G:T:v
+I:130:35d100:30:120:30
+W:51:4:16000:18000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:SHATTER:20d12
+B:HIT:SHATTER:20d12
+B:BITE:POISON:6d14
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:DROP_90 | REGENERATE | KILL_WALL | RES_TELE | KILL_BODY |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | TROLL | IM_POIS |
+F:IM_ELEC | IM_COLD | IM_FIRE | BASEANGBAND
+D:Ulik is the strongest troll who has ever lived. He could challenge
+D:the immortals and pound them to dust with his great strength.
+
+N:730:Baphomet the Minotaur Lord
+G:H:v
+I:130:35d100:30:120:30
+W:58:4:16000:18000
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:BUTT:HURT:12d13
+B:BUTT:HURT:12d13
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | DROP_CORPSE |
+F:EVIL | IM_FIRE | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:1_IN_6 |
+S:SLOW | ARROW_4 | BO_MANA | BO_PLAS | BA_ELEC |
+S:BR_WALL
+D:A fearsome bull-headed monster, Baphomet swings a mighty axe as he curses
+D:all that defy him.
+
+N:731:Hell knight
+G:p:D
+I:120:15d100:20:100:10
+W:52:1:2200:10000
+E:1:1:1:2:1:1
+O:0:40:60:0
+B:HIT:HURT:10d5
+B:HIT:HURT:10d5
+B:HIT:EXP_80:10d5
+B:HIT:EXP_80:10d5
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | IM_FIRE | IM_COLD | IM_POIS |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | RES_NETH | RES_NEXU | RES_PLAS |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_COLD |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BLIND | SCARE | CAUSE_3 | BA_NETH | BA_FIRE | BO_PLAS
+S:S_MONSTERS | S_DEMON
+D:It is a humanoid form dressed in armour of ancient style. From beneath
+D:its helmet, eyes glow with hellfire.
+
+N:732:Bull Gates
+G:p:D
+I:140:25d100:40:90:0
+W:52:3:1600:20000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:CHARGE:EAT_GOLD:5d5
+B:CHARGE:EAT_ITEM:5d5
+B:SPIT:BLIND:10d5
+B:DROOL:DISEASE:8d5
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:IM_POIS | EVIL | RES_TELE
+F:MORTAL | JOKEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:TRAPS | S_BUG
+D:He may not code worth a dime, but he certainly knows how to make money.
+
+N:733:Santa Claus
+G:h:r
+I:150:25d100:90:100:10
+W:52:3:2600:45000
+E:1:1:1:2:1:1
+O:20:20:20:20
+B:HIT:LOSE_CHR:5d5
+B:TOUCH:LOSE_ALL:10d1
+B:TOUCH:LOSE_ALL:10d1
+B:CHARGE:EAT_GOLD
+F:UNIQUE | MALE | CAN_SPEAK | REFLECTING | DROP_SKELETON | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:NO_STUN | NO_SLEEP |
+F:IM_ELEC | IM_FIRE | IM_POIS | IM_COLD |
+F:COLD_BLOOD | RES_TELE | JOKEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:CAUSE_4 | HOLD | DRAIN_MANA | SCARE | BLIND |
+S:S_UNDEAD | S_HI_UNDEAD | S_HI_DRAGON | S_UNIQUE |
+S:BA_NETH | FORGET | TRAPS | BRAIN_SMASH | TELE_AWAY
+D:Why would anybody want to kill Santa Claus? To get all the presents,
+D:of course!
+
+N:734:Eihort, the Thing in the Labyrinth
+G:j:R
+I:120:33d100:50:90:10
+W:53:3:0:45000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:BITE:PARALYZE:8d1
+B:CRUSH:HURT:10d10
+B:CRUSH:HURT:10d10
+B:CRUSH:HURT:10d10
+F:UNIQUE | CAN_SPEAK | ESCORT | REGENERATE |
+F:FORCE_SLEEP | FORCE_MAXHP | ELDRITCH_HORROR |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_SLEEP | RES_TELE | CTHANGBAND | NO_CUT
+S:1_IN_4 |
+S:S_UNDEAD | S_DEMON | S_MONSTER | BLINK | BA_ACID | FORGET
+D:"Then came pale movement in the well, and something clambered
+D:up from the dark, a bloated blanched oval supported on myriad
+D:fleshless legs. Eyes formed in the gelatinous oval and stared
+D:at him."
+
+N:735:The King in Yellow
+G:L:y
+I:120:32d100:90:100:10
+W:53:3:0:50000
+E:0:0:0:0:0:0
+O:50:0:40:10
+B:CRUSH:HURT:12d12
+B:CRUSH:HURT:12d12
+B:GAZE:LOSE_WIS:5d10
+B:GAZE:TERRIFY:5d10
+F:UNIQUE | MALE | CAN_SPEAK | ATTR_MULTI | ATTR_ANY |
+F:FORCE_SLEEP | FORCE_MAXHP | CTHANGBAND |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_ACID | IM_FIRE | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | RES_TELE | NO_CUT
+S:1_IN_2 |
+S:S_DEMON | S_UNDEAD | S_KIN | SCARE | CAUSE_3 | CAUSE_4 | ANIM_DEAD
+S:TELE_AWAY | TPORT | BRAIN_SMASH | CONF
+D:The King in Yellow is an Avatar of Hastur: "He has no
+D:face, and is twice as tall as a man. He wears pointed shoes under
+D:his tattered, fantastically colored robes, and a streamer of silk
+D:appears to fall from the pointed tip of his hood. At times he appears
+D:to be winged; at others, haloed."
+
+N:736:Great unclean one
+G:U:g
+I:120:80d80:30:150:20
+W:53:3:0:17500
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:BITE:DISEASE:10d10
+B:BITE:ACID:10d10
+B:BITE:POISON:10d10
+B:BITE:CONFUSE:10d10
+F:DEMON | EVIL | NONLIVING | CAN_SWIM |
+F:FORCE_SLEEP | FORCE_MAXHP | ONLY_ITEM | DROP_2D2 | ELDRITCH_HORROR |
+F:OPEN_DOOR | BASH_DOOR | SMART | POWERFUL | DROP_GOOD | KILL_BODY |
+F:IM_ACID | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP
+F:KILL_ITEM | ZANGBAND
+S:1_IN_3
+S:BR_ACID | BR_POIS | BR_NUKE | SCARE | ANIM_DEAD
+S:CAUSE_3 | CAUSE_4 | S_DEMON | S_UNDEAD
+D:This disgusting demon resembles a shambling pile of rotting
+D:green flesh, with dozens of mouths drooling and leaving a
+D:trail of foul-smelling goo behind. Nurgle must be
+D:proud of himself to have created this atrocity!
+
+N:737:Lord of Chaos
+G:p:v
+I:130:45d55:30:80:5
+W:60:3:0:17500
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:KICK:HURT:20d2
+B:KICK:HURT:10d2
+B:HIT:POISON:20d1
+B:HIT:LOSE_ALL:15d1
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON |
+F:ONLY_ITEM | DROP_4D2 | ATTR_MULTI | EVIL | SHAPECHANGER | ATTR_ANY |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR | SMART | POWERFUL | EVIL |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:ZANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | MIND_BLAST | BA_CHAO |
+S:S_SPIDER | S_HOUND | S_DEMON
+D:He is one of the few true masters of the art, being extremely skillful in
+D:all forms of unarmed combat and controlling the Chaos
+D:with disdainful ease.
+
+N:738:Old Sorcerer
+G:p:R
+I:130:52d25:20:60:10
+W:54:2:0:5000:0
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:6d8
+B:HIT:HURT:6d8
+B:HIT:HURT:6d8
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 |
+F:OPEN_DOOR | BASH_DOOR | TAKE_ITEM |
+F:EVIL | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:BLINK | TELE_TO | BLIND | CONF | CAUSE_3 | CAUSE_4 | TRAPS |
+S:BO_ACID | BA_FIRE | BA_COLD | BA_POIS |
+S:S_MONSTER | S_DEMON | S_HI_DRAGON | S_UNDEAD
+D:A human figure in robes, he moves with magically improved speed, and his
+D:hands are ablur with spell casting. You stagger at the mighty sound of his
+D:spells as they echo hollowly through the dungeon.
+
+N:739:Ethereal hound
+G:Z:G
+I:120:60d15:30:100:0
+W:55:3:900:6000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:CLAW:HURT:2d12
+F:FORCE_SLEEP | FRIENDS |
+F:INVISIBLE | PASS_WALL |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_NETH
+D:A pale green hound. Pulsing red lines and strange fluorescent light
+D:hint at internal organs best left to the imagination.
+
+N:740:Lesser kraken
+G:~:G
+I:120:30d100:30:150:80
+W:54:2:8000:20000
+E:3:0:3:0:1:0
+O:25:25:50:0
+B:CRUSH:HURT:16d12
+B:CRUSH:HURT:16d12
+B:CRUSH:HURT:16d12
+B:CRUSH:HURT:16d12
+F:FORCE_SLEEP | FORCE_MAXHP | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:ONLY_ITEM | DROP_3D2 | DROP_GOOD | DROP_CORPSE |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | SMART | RES_WATE |
+F:EVIL | IM_ELEC | NO_CONF | NO_SLEEP | IM_POIS | IM_FIRE | BASEANGBAND
+S:1_IN_4 |
+S:BLIND | CONF | SCARE | CAUSE_4 | CAUSE_3 |
+S:BA_WATE | DARKNESS | BR_DARK | TELE_TO
+D:An enormously fearsome and powerful inhabitant of the depths. It
+D:resembles a gargantuan octopus and its evil is almost tangible.
+
+N:741:Great Ice Wyrm
+G:D:w
+I:120:40d100:30:150:80
+W:63:2:190000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:COLD:6d14
+B:BITE:COLD:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | AURA_COLD |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | SUSCEP_FIRE |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_COLD
+D:An immense dragon capable of awesome destruction. You have never felt
+D:such extreme cold, or witnessed such an icy stare. Begone quickly or feel
+D:its wrath!
+
+N:742:Demilich
+G:L:U
+I:120:35d100:20:100:50
+W:54:2:3000:12500
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:EXP_80
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:4d12
+B:TOUCH:LOSE_DEX:4d12
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_TELE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | BLIND | HOLD | CONF | SCARE | CAUSE_3 | CAUSE_4 |
+S:DRAIN_MANA | BRAIN_SMASH | S_HI_UNDEAD | S_UNDEAD | FORGET | S_DEMON |
+S:TPORT | HEAL | ANIM_DEAD
+D:A lich who is partially immaterial, on its way to a new, ethereal form.
+
+N:743:The Phoenix
+G:B:r
+I:120:36d100:60:130:0
+W:54:3:6000:40000
+E:0:1:1:0:1:0
+O:0:50:50:0
+B:BITE:FIRE:12d6
+B:BITE:FIRE:12d6
+B:HIT:FIRE:9d12
+B:HIT:FIRE:9d12
+F:UNIQUE | CAN_SPEAK | RES_PLAS | AURA_FIRE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | SUSCEP_COLD |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID | IM_FIRE | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP
+F:BASEANGBAND | HAS_LITE | REGENERATE
+S:1_IN_3 |
+S:BO_FIRE | BO_PLAS | BA_FIRE |
+S:BR_FIRE | BR_LITE | BR_PLAS
+D:A massive glowing eagle bathed in flames. The searing heat chars your
+D:skin and melts your armour.
+
+N:744:Nightcrawler
+G:W:D
+I:120:80d60:20:160:10
+W:69:3:10000:1500
+E:0:0:0:0:1:0
+O:40:0:50:10
+B:STING:LOSE_CON:8d8
+B:STING:LOSE_CON:8d8
+B:BITE:ACID:10d10
+B:BITE:ACID:10d10
+F:FORCE_SLEEP | SMART | KILL_WALL | CAN_SWIM | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS | RES_TELE |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLIND | SCARE | BRAIN_SMASH |
+S:BO_MANA | BO_NETH | BA_NETH | BR_NETH | S_UNDEAD
+D:This intensely evil creature bears the form of a gargantuan black worm.
+D:Its gaping maw is a void of blackness, and acid drips from its steely hide.
+D:It is like nothing you have ever seen before, and a terrible chill runs
+D:down your spine as you face it.
+
+N:745:Lord of Change
+G:U:v
+I:130:50d70:30:150:20
+W:54:3:0:17000
+E:0:1:1:0:1:0
+O:0:0:100:0
+B:CLAW:CONFUSE:10d10
+B:CLAW:CONFUSE:10d10
+B:BITE:BLIND:12d12
+F:DEMON | EVIL | ATTR_MULTI | DROP_GOOD | MOVE_BODY | NONLIVING |
+F:FORCE_SLEEP | FORCE_MAXHP | ONLY_ITEM | DROP_2D2 | ELDRITCH_HORROR |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR | SMART | POWERFUL | CAN_FLY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:ZANGBAND
+S:1_IN_3
+S:MIND_BLAST | BA_CHAO | SCARE | BRAIN_SMASH | DRAIN_MANA |
+S:S_HOUND | S_DEMON | S_DRAGON | TPORT | HASTE | CONF | SCARE |
+S:TELE_AWAY | FORGET
+D:The most powerful of Tzeentch's servitors. This demon looks like
+D:a huge bird-creature, with the head of a predatory bird and
+D:fantastically multi-coloured wings.
+
+N:746:Keeper of Secrets
+G:H:G
+I:130:60d70:30:150:20
+W:54:3:0:17000
+E:2:0:2:2:1:1
+O:0:0:100:0
+B:HIT:CONFUSE:10d10
+B:HIT:TERRIFY:10d10
+B:HIT:BLIND:10d10
+B:HIT:TERRIFY:10d10
+F:DEMON | EVIL | DROP_GOOD | NONLIVING | CAN_SWIM |
+F:FORCE_SLEEP | FORCE_MAXHP | ONLY_ITEM | DROP_2D2 | ELDRITCH_HORROR |
+F:OPEN_DOOR | BASH_DOOR | SMART | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | ZANGBAND
+S:1_IN_3
+S:SCARE | BRAIN_SMASH | DRAIN_MANA |
+S:BR_CONF | S_DEMON | S_UNDEAD | TPORT | HEAL |
+S:TELE_AWAY
+D:This demonic keeper of forbidden secrets looks like a hairless
+D:minotaur with extra arms, decorated with tattoos and nose rings.
+D:It is the embodiment of Slaanesh's perverted magic.
+
+N:747:Shudde M'ell
+G:w:s
+I:125:100d40:20:90:20
+W:59:2:0:23000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:SHATTER:55d2
+B:CRUSH:SHATTER:55d2
+B:TOUCH:LOSE_CON:1d2
+B:TOUCH:LOSE_CON:1d2
+F:IM_FIRE | RES_PLAS | IM_COLD | IM_POIS | ELDRITCH_HORROR | RES_TELE |
+F:KILL_WALL | ONLY_GOLD | DROP_4D2 | DROP_2D2 | CAN_SWIM |
+F:EVIL | FORCE_MAXHP | SMART | UNIQUE | CTHANGBAND | NO_STUN
+S:1_IN_5 |
+S:SCARE | CONF | HOLD | S_DEMON | S_KIN |
+S:HEAL | HASTE | FORGET | BRAIN_SMASH |
+S:BR_DARK | BR_ACID | BR_DISE
+D:The most powerful and most evil of all Chthonians.
+D:"A great gray thing a mile long chanting and exuding strange acids...
+D:charging through the depths of the earth at a fantastic speed, in a
+D:dreadful fury... melting basaltic rocks like butter under a blowtorch."
+
+N:748:Hand druj
+G:s:y
+I:130:60d10:20:110:10
+W:57:2:10:18000
+E:0:0:0:1:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW | RES_TELE |
+F:SMART | COLD_BLOOD | CAN_SWIM |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_1 |
+S:TELE_AWAY | BLIND | CONF | SCARE | CAUSE_3 | FORGET | DARKNESS |
+S:BO_FIRE | BO_ACID | BO_COLD | BO_ELEC
+D:A skeletal hand floating in the air, motionless except for its flexing
+D:fingers.
+
+N:749:Eye druj
+G:s:r
+I:130:10d100:20:90:10
+W:58:2:2:21000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW | RES_TELE |
+F:SMART | COLD_BLOOD |
+F:EVIL | UNDEAD | CAN_SWIM |
+F:IM_FIRE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_1 |
+S:BO_MANA | BO_NETH | BA_NETH | BRAIN_SMASH | S_UNDEAD
+D:A bloodshot eyeball floating in the air, you'd be forgiven for assuming it
+D:harmless.
+
+N:750:Skull druj
+G:s:o
+I:130:14d100:20:120:10
+W:59:2:1000:24000
+E:0:0:0:0:1:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | RES_TELE |
+F:SMART | COLD_BLOOD |
+F:EVIL | UNDEAD | CAN_SWIM |
+F:IM_FIRE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_1 |
+S:SLOW | CAUSE_4 | MIND_BLAST | BRAIN_SMASH | TRAPS | BO_PLAS |
+S:BO_NETH | BA_WATE | S_UNDEAD
+D:A glowing skull possessed by sorcerous power. It need not move, but
+D:merely blast you with mighty magic.
+
+N:751:Chaos vortex
+G:v:v
+I:140:32d20:100:80:0
+W:53:1:0:4000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:CONFUSE:5d5
+B:ENGULF:CONFUSE:5d5
+B:ENGULF:HURT:5d5
+B:ENGULF:HURT:5d5
+F:ATTR_MULTI | ATTR_ANY | FORCE_SLEEP |
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_CHAO
+D:Void, nothingness, spinning destructively.
+
+N:752:Aether vortex
+G:v:v
+I:130:40d20:100:40:0
+W:54:2:0:5000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:ELEC:5d5
+B:ENGULF:FIRE:5d5
+B:ENGULF:ACID:5d5
+B:ENGULF:COLD:5d5
+F:ATTR_MULTI | ATTR_ANY | FORCE_SLEEP | CAN_FLY |
+F:RAND_50 | RAND_25 | AURA_COLD | RES_WATE | RES_DISE |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | RES_NETH | RES_NEXU |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | AURA_FIRE | AURA_ELEC |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | RES_PLAS | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS | BR_LITE |
+S:BR_DARK | BR_SOUN | BR_CONF | BR_CHAO | BR_SHAR | BR_NETH |
+S:BR_WALL | BR_INER | BR_TIME | BR_GRAV | BR_PLAS | BR_NEXU
+D:An awesome vortex of pure magic, power radiates from its frame.
+
+N:753:Nidhogg, the Hel-Drake
+G:D:D
+I:120:39d111:20:133:70
+W:55:2:260000:25000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:LOSE_CON:8d12
+B:CLAW:LOSE_CON:8d12
+B:BITE:EXP_80:8d15
+B:BITE:EXP_80:8d15
+F:UNIQUE | CAN_FLY | RES_NETH |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | IM_POIS |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | CAN_SPEAK | IM_ACID |
+F:EVIL | DRAGON | IM_FIRE | NO_SLEEP | IM_COLD | ZANGBAND |
+F:HAS_LITE
+S:1_IN_5 |
+S:CAUSE_3 | BR_NETH | BR_COLD |
+S:BR_ACID | BR_POIS |
+S:S_DRAGON | S_UNDEAD
+D:In the bowels of Hel, the dread Nidhogg, a dragon blacker than the
+D:night, feasts on the essences of the dead.
+
+N:754:The Lernaean Hydra
+G:M:v
+I:120:45d100:20:140:20
+W:55:2:13000:20000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:POISON:8d6
+B:BITE:POISON:8d6
+B:BITE:FIRE:12d6
+B:BITE:FIRE:12d6
+F:UNIQUE | SUSCEP_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | DROP_CORPSE |
+F:ONLY_GOLD | DROP_3D2 | DROP_4D2 | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:OPEN_DOOR | BASH_DOOR | KILL_BODY | POWERFUL | REGENERATE |
+F:ANIMAL | IM_FIRE | IM_POIS |
+F:NO_CONF | NO_STUN | CAN_SWIM |
+F:MORTAL | BASEANGBAND
+S:1_IN_3 |
+S:SCARE |
+S:BO_FIRE | BO_PLAS | BA_FIRE | BA_POIS |
+S:BR_FIRE | BR_POIS | S_HYDRA | S_KIN
+D:A massive legendary hydra. It has twelve powerful heads. Its many eyes
+D:stare at you as clouds of smoke and poisonous vapour rise from its
+D:seething form. It grows new heads as fast as you chop them off.
+
+N:755:Thuringwethil, the Vampire Messenger
+G:V:v
+I:130:50d100:20:145:10
+W:67:3:1500:23000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:BITE:EXP_80:6d6
+B:BITE:EXP_80:6d6
+B:HIT:CONFUSE:6d6
+B:HIT:CONFUSE:6d6
+F:UNIQUE | FEMALE | SPECIAL_GENE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | CAN_SPEAK | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | NO_STUN
+F:RES_TELE | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | BA_NETH | S_KIN | S_HI_UNDEAD
+D:Chief messenger between Sauron and Morgoth, she is the most deadly of her
+D:vampire race on Middle-earth. At first she is charming to meet, but her
+D:wings and eyes give away her true form.
+
+N:756:Great Hell Wyrm
+G:D:r
+I:120:50d100:30:150:80
+W:67:2:190000:23000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:FIRE:6d14
+B:BITE:FIRE:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | SUSCEP_COLD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | AURA_FIRE |
+F:EVIL | DRAGON | IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_FIRE
+D:A vast dragon of immense power. Fire leaps continuously from its huge
+D:form. The air around it scalds you. Its slightest glance burns you, and
+D:you realise how truly insignificant you are.
+
+N:757:Hastur the Unspeakable
+G:H:b
+I:120:55d95:20:150:10
+W:55:4:0:23000
+E:2:0:2:4:1:0
+O:25:25:25:10
+B:CRUSH:HURT:14d8
+B:CRUSH:HURT:14d8
+B:BITE:EXP_80:6d6
+B:BITE:EXP_80:6d6
+F:UNIQUE | ELDRITCH_HORROR | CAN_SWIM |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | CAN_SPEAK | AURA_ELEC |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | POWERFUL | SMART | NONLIVING |
+F:EVIL | DEMON | IM_COLD | IM_POIS | HURT_LITE | NO_SLEEP |
+F:RES_TELE | CTHANGBAND
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | BA_WATE | S_DEMON | HASTE |
+S:TPORT | TELE_AWAY | TELE_TO | HEAL | BR_DARK | BR_NETH
+D:His form is partially that of a reptile, partially that of a gigantic
+D:octopus. He will destroy you.
+
+N:758:Bloodthirster
+G:U:r
+I:130:60d70:30:180:20
+W:55:3:0:18500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:50d1
+B:HIT:HURT:50d1
+B:HIT:HURT:50d1
+F:DEMON | EVIL | DROP_GOOD | REGENERATE | CAN_FLY | NONLIVING |
+F:FORCE_SLEEP | FORCE_MAXHP | ONLY_ITEM | DROP_4D2 | ELDRITCH_HORROR |
+F:OPEN_DOOR | BASH_DOOR | RES_NETH | RES_NEXU | RES_TELE | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | NO_FEAR
+F:CAN_FLY | ZANGBAND | HAS_LITE
+D:Khorne's mightiest servant, a winged hound-demon walking on
+D:two paws and wielding a mighty axe and a whip in the other
+D:two. Intelligent, bloodthirsty eyes leer at you from inside
+D:the blood-soaked demon armour.
+
+N:759:Draconic quylthulg
+G:Q:g
+I:120:48d10:20:1:0
+W:45:1:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_DRAGON
+D:It looks like it was once a dragon corpse, now deeply infected with
+D:magical bacteria that make it pulse in a foul and degrading way.
+
+N:760:Nyogtha, the Thing that Should not Be
+G:j:D
+I:130:55d99:20:120:20
+W:56:2:0:20000
+E:0:0:0:0:0:0
+O:50:0:40:10
+B:CRUSH:ACID:10d6
+B:CRUSH:ACID:10d6
+B:CRUSH:ACID:10d6
+B:CRUSH:HURT:16d16
+F:UNIQUE | ELDRITCH_HORROR |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SPEAK | SMART | CAN_SWIM |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:REGENERATE | ONLY_ITEM | KILL_ITEM | DROP_2D2 | DROP_90 | DROP_60 |
+F:BASH_DOOR | EVIL | NO_CONF | NO_SLEEP | KILL_BODY |
+F:FORCE_MAXHP | FORCE_SLEEP | HURT_LITE | POWERFUL | RES_NETH | NONLIVING |
+F:IM_ACID | IM_FIRE | RES_PLAS | IM_POIS | IM_COLD | IM_ELEC | RES_TELE
+F:CTHANGBAND | NO_CUT
+S:1_IN_5 |
+S:BRAIN_SMASH | MIND_BLAST | HASTE | TPORT |
+S:S_DEMON | S_UNDEAD | S_HI_UNDEAD | S_KIN |
+S:BR_DARK | BR_NUKE | BR_ACID | BR_POIS
+D:"...a little finger of blackness crept out from beneath its edge
+D:a great wave of iridescent blackness, neither liquid nor solid,
+D:a frightful gelatinous mass."
+
+N:761:Ahtu, Avatar of Nyarlathotep
+G:#:D
+I:130:50d110:30:120:15
+W:56:3:0:22500
+E:1:1:1:2:1:1
+O:0:30:60:10
+B:CRUSH:HURT:13d13
+B:CRUSH:FIRE:10d10
+B:CRUSH:HURT:13d13
+B:CRUSH:FIRE:10d10
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | CAN_SPEAK |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | NONLIVING | ELDRITCH_HORROR | CTHANGBAND | NO_CUT | NO_SLEEP | NO_CONF | NO_STUN
+S:1_IN_6
+S:BR_FIRE | S_DEMON | CAUSE_4 | BR_PLAS | BR_NETH | BRAIN_SMASH |
+S:S_UNDEAD | BA_DARK
+D:"Higher already than the giants of the forest ringing it, the
+D:fifty-foot-thick column... sprouted a ring of tendrils, ruddy and
+D:golden and glittering overall with inclusions of quartz."
+
+N:762:Fundin Bluecloak
+G:h:B
+I:130:50d100:25:195:10
+W:56:2:1400:20000
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:HIT:HURT:10d10
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP | PET |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:HEAL | BLIND | CONF | SCARE | CAUSE_3 | CAUSE_4 | BRAIN_SMASH |
+S:FORGET | S_MONSTERS | S_ANIMALS
+D:He is one of the greatest dwarven priests to walk the earth. Fundin has
+D:earned a high position in the church, and his skill with both weapon and
+D:spell only justify his position further. His combination of both dwarven
+D:strength and priestly wisdom are a true match for any adventurer.
+
+N:763:Bile Demon
+G:U:R
+I:120:35d100:40:90:80
+W:61:2:0:12000
+E:1:0:1:2:1:0
+O:30:70:0:0
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+B:CRUSH:ACID:9d9
+B:CRUSH:ACID:9d9
+F:FORCE_SLEEP | FORCE_MAXHP | BASEANGBAND |
+F:ONLY_ITEM | DROP_3D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | NONLIVING |
+F:EVIL | DEMON | IM_POIS | IM_ACID | NO_CONF | NO_SLEEP
+S:1_IN_6 |
+S:BR_POIS | BR_ACID | S_DEMON | BLIND | CONF | ARROW_4
+D:It's big. It's fat. It's red. It's ugly. It's got a severe attack of
+D:highly poisonous flatulence. And its insides are corrosive. All of which
+D:go together to make the single most repulsive sight - and smell - you have
+D:ever experienced.
+
+N:764:Uriel, Angel of Fire
+G:A:R
+I:130:55d100:40:160:10
+W:61:3:3400:25000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:FIRE:4d12
+B:HIT:FIRE:4d12
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:UNIQUE | MALE | CAN_SPEAK | NO_FEAR | GOOD | AURA_FIRE | REFLECTING |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | SUSCEP_COLD |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | NO_SLEEP
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_ELEC | IM_POIS | RES_TELE | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:TELE_TO | BLIND |
+S:BO_FIRE | BO_MANA | BA_FIRE |
+S:BR_FIRE | BR_PLAS |
+S:S_ANGEL
+D:A creature of godly appearance. You dare not challenge Uriel's supremacy.
+D:Those who stood against him before are but a memory, cremated by his
+D:mastery of elemental fire.
+
+N:765:Azriel, Angel of Death
+G:A:D
+I:130:60d100:40:170:10
+W:62:3:3400:30000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:EXP_80:10d5
+B:HIT:EXP_80:10d5
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:UNIQUE | MALE | CAN_SPEAK | RES_NETH | NO_FEAR | GOOD |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | REFLECTING | AURA_COLD |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | CAN_FLY | NO_SLEEP
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | RES_TELE | BASEANGBAND
+F:HAS_LITE
+S:1_IN_2 |
+S:TELE_TO | BLIND |
+S:BO_MANA | BO_NETH | BA_NETH |
+S:BR_NETH |
+S:S_ANGEL
+D:Azriel commands awesome power, his visage holy enough to shrivel your
+D:soul. You shriek with disbelief as his mastery of death draws you to your
+D:grave. It is truly beyond all but the mightiest of warriors to stand
+D:against him and live.
+
+N:766:Ancalagon the Black
+G:D:D
+I:140:180d100:40:170:70
+W:90:1:330000:60000
+E:0:1:0:6:1:0
+O:60:40:0:0
+B:CLAW:HURT:10d12
+B:CLAW:HURT:10d12
+B:BITE:HURT:10d14
+B:BITE:HURT:10d14
+F:UNIQUE | MALE | CAN_FLY | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BR_ACID | BR_FIRE | BR_DISI | BR_WALL | BR_TIME |
+S:S_HI_DRAGON | S_KIN
+D:"Rushing Jaws" is his name, and death is his game; the greatest and most
+D:terrible of all dragonkind, his power dismayed even the Valar for a time.
+
+N:767:Daoloth, the Render of the Veils
+G:U:s
+I:120:72d100:20:125:70
+W:58:3:0:27500
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:CONFUSE:5d12
+B:TOUCH:CONFUSE:5d12
+B:TOUCH:CONFUSE:5d12
+B:TOUCH:CONFUSE:5d12
+F:UNIQUE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:IM_ACID | IM_FIRE | IM_POIS | IM_COLD | ELDRITCH_HORROR |
+F:NEVER_MOVE | RES_NEXU | REFLECTING | PASS_WALL
+F:NO_CONF | NO_SLEEP | NO_CUT | NO_STUN | NO_FEAR | CTHANGBAND
+S:1_IN_3 |
+S:TELE_AWAY | S_MONSTERS | TELE_LEVEL | BR_NEXU | TPORT | BLINK
+D:"Not shapeless, but so complex that the eye could recognise no
+D:describable shape. There were hemispheres and shining metal,
+D:coupled by long plastic rods. The rods were of a flat gray color,
+D:so that he could not make out which were nearer; they merged into
+D:a flat mass from which protruded individual cylinders. As he looked
+D:at it, he had a curious feeling that eyes gleamed from between
+D:these rods; but wherever he glanced at the construction, he saw
+D:only the spaces between them."
+
+N:768:Nightwalker
+G:W:D
+I:130:80d70:20:175:10
+W:73:3:75000:20000
+E:1:1:1:2:1:1
+O:30:0:70:0
+B:HIT:UN_BONUS:10d10
+B:HIT:UN_BONUS:10d10
+B:HIT:UN_BONUS:7d7
+B:HIT:UN_BONUS:7d7
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | CAN_SWIM |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | RES_TELE |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLIND | SCARE | BRAIN_SMASH |
+S:BO_MANA | BO_NETH | BA_NETH | S_UNDEAD
+D:A huge giant garbed in black, more massive than a titan and stronger than
+D:a dragon. With terrible blows, it breaks your armour from your back,
+D:leaving you defenceless against its evil wrath. It can smell your fear,
+D:and you in turn smell the awful stench of death as this ghastly figure
+D:strides towards you menacingly.
+
+N:769:Gabriel, the Messenger
+G:A:w
+I:130:75d100:40:180:10
+W:64:3:3500:35000
+E:1:1:1:2:1:1
+O:0:40:60:0
+B:HIT:UN_BONUS:6d8
+B:HIT:FIRE:6d8
+B:HIT:BLIND:10d10
+B:HIT:BLIND:10d10
+F:UNIQUE | MALE | FORCE_MAXHP | CAN_SPEAK | NO_SLEEP | GOOD |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | AURA_ELEC | REFLECTING | RES_TELE
+F:ESCORT | CAN_FLY |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:TELE_TO | BLIND | BO_MANA |
+S:S_ANGEL | S_KIN
+D:Commanding a legion of angels, Gabriel will destroy you for your sins. He
+D:will crush you like the pitiful insignificant being he sees you to be.
+D:Your very soul will be taken into judgement by his supreme authority as he
+D:cleanses the world of evil.
+
+N:770:Artsi, the Champion of Chaos
+G:h:v
+I:130:11d666:25:175:10
+W:59:2:1600:20000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:EXP_80:10d10
+B:HIT:EXP_80:10d10
+B:HIT:EXP_80:10d10
+F:UNIQUE | MALE | CAN_SPEAK | ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | DROP_CORPSE
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | RES_NEXU | RES_NETH |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:ZANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BA_FIRE | BA_CHAO | CONF | TPORT | S_DEMON | BR_CHAO | BA_MANA
+D:He is one of the greatest warriors of chaos to walk the earth.
+D:His bloody blade has slain thousands and tens of thousands, and still
+D:hungers for more.
+
+N:771:Saruman of Many Colours
+G:p:v
+I:120:70d100:100:100:0
+W:60:1:1600:35000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:UNIQUE | MALE | ATTR_MULTI | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | REFLECTING | RES_TELE
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:DROP_GREAT | DROP_CHOSEN |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | HASTE | TPORT | TELE_AWAY | BLIND | CONF | SCARE |
+S:CAUSE_4 | MIND_BLAST | FORGET | TRAPS | ANIM_DEAD | BO_MANA |
+S:BO_ICEE | BA_ACID | BA_FIRE | BA_COLD | BA_WATE | BA_CHAO |
+S:S_UNDEAD | S_DEMON | S_HI_DRAGON | S_ANIMALS
+D:Originally known as the White, Saruman fell prey to Sauron's wiles. He
+D:searches forever for the One Ring, to become a mighty Sorcerer-King of the
+D:world.
+
+N:772:Harowen the Black Hand
+G:p:B
+I:140:25d100:30:36:0
+W:51:3:0:20000
+E:1:1:1:2:1:1
+O:90:10:0:0
+B:TOUCH:EAT_GOLD:5d5
+B:TOUCH:EAT_ITEM:5d5
+B:HIT:BLIND:10d5
+B:HIT:POISON:8d5
+F:UNIQUE | MALE | CAN_SPEAK | SMART |
+F:FORCE_SLEEP | FORCE_MAXHP | MOVE_BODY |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:IM_POIS | BASEANGBAND
+S:1_IN_6 |
+S:TELE_TO | TRAPS
+D:He is a master of disguise, an expert of stealth, a genius at traps, and
+D:moves with blinding speed. Check your pockets!
+
+N:773:Osyluth
+G:U:W
+I:130:40d100:20:75:80
+W:65:2:0:13000
+E:1:1:1:2:1:1
+O:20:40:20:20
+B:HIT:LOSE_CHR:8d8
+B:HIT:LOSE_CHR:8d8
+B:BITE:POISON:10d10
+B:STING:LOSE_STR:9d9
+F:FORCE_SLEEP | FORCE_MAXHP | NONLIVING |
+F:ONLY_ITEM | DROP_3D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY
+F:EVIL | DEMON | NO_CONF | NO_SLEEP | INVISIBLE | BASEANGBAND |
+F:IM_ACID | IM_ELEC | IM_POIS | IM_COLD | IM_FIRE | NO_CUT
+S:1_IN_6 |
+S:BA_ELEC | BA_COLD | BO_ICEE | SCARE | S_DEMON
+D:It is a demon made almost entirely out of bones. It is humanoid, but with
+D:a large tail similar to that of a giant scorpion, and emits a foul smell
+D:of decay and rot. They are despised even in the hells.
+
+N:774:Dreadlord
+G:G:r
+I:120:30d100:20:150:10
+W:62:2:0:20000
+E:0:0:0:0:0:0
+O:10:10:60:10
+B:HIT:EXP_40:6d6
+B:HIT:EXP_40:6d6
+B:HIT:LOSE_STR:4d6
+B:HIT:LOSE_STR:4d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | CAN_FLY |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | RES_TELE | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:HOLD | DRAIN_MANA | BLIND | S_UNDEAD | CONF |
+S:SCARE | TELE_TO | TPORT | BRAIN_SMASH | ANIM_DEAD
+S:BA_NETH | DARKNESS
+D:It is a massive form of animated death, its colour deeper than black. It
+D:drinks in light, and space around it is twisted and torn by the weight of
+D:its evil. It is unlife and it knows nothing but the stealing of souls and
+D:the stench of death. Flee its hunger!
+
+N:775:Greater kraken
+G:~:G
+I:120:40d100:30:175:80
+W:60:2:10000:25000
+E:3:0:3:0:1:0
+O:10:80:0:10
+B:CRUSH:HURT:15d15
+B:CRUSH:HURT:15d15
+B:CRUSH:HURT:15d15
+B:CRUSH:HURT:15d15
+F:FORCE_SLEEP | FORCE_MAXHP | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:ONLY_ITEM | DROP_3D2 | DROP_GOOD | DROP_CORPSE |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | SMART | RES_WATE |
+F:EVIL | IM_ELEC | NO_CONF | NO_SLEEP | IM_POIS | IM_FIRE | BASEANGBAND
+S:1_IN_3 |
+S:BLIND | CONF | SCARE | CAUSE_4 | CAUSE_3 | TELE_TO | TELE_AWAY |
+S:BA_WATE | DARKNESS | BR_DARK | BR_ACID | BR_POIS
+D:An enormously fearsome and powerful inhabitant of the depths. It
+D:resembles a gargantuan octopus and its evil is almost tangible.
+
+N:776:Archlich
+G:L:B
+I:120:45d100:20:120:50
+W:64:2:0:20000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:EXP_80
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:8d12
+B:TOUCH:LOSE_DEX:8d12
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_TELE | CAN_FLY |
+F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | BLIND | HOLD | SCARE | CAUSE_4 |
+S:DRAIN_MANA | BRAIN_SMASH | S_HI_UNDEAD | FORGET |
+S:TPORT | HEAL | S_DEMON | BA_NETH | ANIM_DEAD
+D:A lich who has reached its ultimate evolutionary stage: a completely
+D:immaterial state.
+
+N:777:The Cat Lord
+G:f:v
+I:130:48d100:100:200:0
+W:66:3:0:30000
+E:0:1:0:2:1:0
+O:30:60:0:10
+B:CLAW:CONFUSE:12d12
+B:CLAW:LOSE_DEX:2d12
+B:CLAW:BLIND:10d5
+B:BITE:PARALYZE:15d1
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_POIS | NO_CONF | BASEANGBAND
+S:1_IN_3 |
+S:TELE_TO | S_KIN
+D:Master of all things feline, the Cat Lord moves with catlike stealth.
+
+N:778:Jabberwock
+G:H:v
+I:130:32d100:35:125:255
+W:68:3:2300:19000
+E:0:1:0:2:1:0
+O:20:50:20:0
+B:CLAW:HURT:10d10
+B:CLAW:HURT:10d10
+B:BITE:HURT:10d10
+B:BITE:HURT:10d10
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE |
+F:ONLY_ITEM | DROP_60 | DROP_90 |
+F:BASH_DOOR | CAN_FLY | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND |
+S:1_IN_5 |
+S:CAUSE_4 |
+S:BR_CHAO
+D:'Twas brillig, and the slithy toves / Did gyre and gimble in the wabe: /
+D:All mimsy were the borogoves, / And the mome raths outgrabe. /
+D:"Beware the Jabberwock, my son! / The jaws that bite, the claws that catch!"
+
+N:779:Chaos hound
+G:Z:v
+I:120:60d30:30:100:0
+W:65:2:900:10000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:CLAW:HURT:2d12
+F:ATTR_MULTI | ATTR_ANY | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP | FRIENDS | BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_5 |
+S:BR_CHAO
+D:A constantly changing canine form, this hound rushes towards you as if
+D:expecting mayhem and chaos ahead. It appears to have an almost kamikaze
+D:relish for combat. You suspect all may not be as it seems.
+
+N:780:Vlad Dracula, Prince of Darkness
+G:V:D
+I:130:70d100:20:166:10
+W:76:4:1800:33333
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:BITE:EXP_80:8d8
+B:BITE:EXP_80:8d8
+B:HIT:CONFUSE:8d8
+B:HIT:CONFUSE:8d8
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | CAN_SPEAK | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:RES_TELE | ZANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | DRAIN_MANA | S_HI_UNDEAD |
+S:BRAIN_SMASH | BA_NETH | S_KIN | DARKNESS | BA_DARK
+D:The most feared of all vampires, the Prince of Darkness himself.
+
+N:781:Beholder hive-mother
+G:e:y
+I:120:40d100:30:80:10
+W:67:3:2600:17000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:EXP_80:6d6
+B:GAZE:PARALYZE:5d5
+B:GAZE:INSANITY:5d5
+B:GAZE:UN_POWER:5d5
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | CAN_FLY |
+F:BASH_DOOR | FEMALE | SMART | DROP_CORPSE |
+F:EVIL | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_2 |
+S:BLIND | CONF | FORGET | SCARE | DRAIN_MANA | BRAIN_SMASH |
+S:BA_DARK | BO_MANA | BA_ACID | BA_FIRE | BA_COLD | BO_NETH |
+S:S_KIN
+D:A hive mother of the race of beholders, she can summon her brood to her aid
+D:whenever she wishes.
+
+N:782:Leviathan
+G:~:v
+I:120:50d100:40:180:30
+W:67:3:300000:28000
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:BITE:FIRE:5d12
+B:BITE:FIRE:5d12
+B:CRUSH:HURT:6d15
+B:CRUSH:HURT:6d15
+F:FORCE_SLEEP | FORCE_MAXHP | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:IM_FIRE | IM_ACID | IM_COLD | IM_POIS |
+F:ANIMAL | NO_CONF | NO_SLEEP | NO_FEAR | DROP_CORPSE | BASEANGBAND
+S:1_IN_9
+S:BR_FIRE | BR_ACID | BR_DARK | BR_POIS | BA_WATE |
+S:S_DRAGON | S_HYDRA | HEAL | CONF | DARKNESS
+D:An enormous, terrible sea-monster, the true master of the ocean.
+
+N:783:Great Wyrm of Chaos
+G:D:v
+I:120:60d100:40:170:100
+W:75:2:190000:29000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:5d12
+B:CLAW:HURT:5d12
+B:BITE:HURT:7d14
+B:BITE:HURT:7d14
+F:ATTR_MULTI | ATTR_ANY |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_DISE | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_CHAO | BR_DISE |
+S:S_DRAGON | S_HI_DRAGON
+D:A massive dragon of changing form. As you watch, it appears first fair
+D:and then foul. Its body is twisted by chaotic forces as it strives to
+D:stay real. Its very existence distorts the universe around it.
+
+N:784:Great Wyrm of Law
+G:D:B
+I:120:60d100:40:170:100
+W:75:2:190000:29000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:5d12
+B:CLAW:HURT:5d12
+B:BITE:HURT:7d14
+B:BITE:HURT:7d14
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
+F:EVIL | DRAGON | NO_STUN | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN | BR_SHAR |
+S:S_DRAGON | S_HI_DRAGON
+D:A massive dragon of powerful intellect. It seeks to dominate the universe
+D:and despises all other life. It sees all who do not obey it as mere
+D:insects to be crushed underfoot.
+
+N:785:Great Wyrm of Balance
+G:D:v
+I:120:70d100:40:170:100
+W:80:2:190000:31000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:6d12
+B:CLAW:HURT:6d12
+B:BITE:HURT:8d14
+B:BITE:HURT:8d14
+F:DRAGON | EVIL | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | RES_DISE |
+F:NO_STUN | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT | ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN | BR_CHAO | BR_SHAR | BR_DISE |
+S:S_DRAGON | S_HI_DRAGON
+D:A massive dragon, it is thousands of
+D:years old and seeks to maintain the Cosmic Balance. It sees you as an
+D:upstart troublemaker without the wisdom to control your actions.
+
+N:786:Shambler
+G:E:W
+I:130:50d100:40:150:50
+W:67:4:9000:22500
+E:0:0:0:0:0:0
+O:20:20:60:0
+B:CLAW:HURT:3d12
+B:CLAW:HURT:3d12
+B:CRUSH:HURT:8d12
+B:CRUSH:HURT:8d12
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | CAN_SWIM | DROP_CORPSE |
+F:BASH_DOOR | OPEN_DOOR | POWERFUL | MOVE_BODY |
+F:NO_CONF | NO_SLEEP | EVIL | ZANGBAND | NO_CUT
+S:1_IN_3 |
+S:BR_ELEC
+D:This elemental creature is power incarnate; it looks like a huge polar bear
+D:with a huge gaping maw instead of a head.
+
+N:787:Gelugon
+G:U:w
+I:130:45d100:20:100:80
+W:69:3:0:14000
+E:2:1:2:0:0:1
+O:20:60:20:0
+B:CLAW:COLD:6d10
+B:CLAW:COLD:6d10
+B:BITE:COLD:9d9
+B:HIT:PARALYZE:8d8
+F:FORCE_SLEEP | FORCE_MAXHP | BASEANGBAND | NONLIVING |
+F:ONLY_ITEM | DROP_GOOD | DROP_4D2 | CAN_FLY |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | REGENERATE |
+F:EVIL | DEMON | IM_COLD | NO_CONF | NO_SLEEP
+S:1_IN_6
+S:BR_COLD | BR_SHAR | BA_COLD | BO_ICEE | S_HI_DEMON |
+S:SLOW | SCARE | HOLD
+D:This demon from the ice planes is a truly terrifying sight. It has an
+D:extremely large, insect-like body towering a full twelve feet tall, with
+D:great claws on its hands and pincers on its mouth, and its head bulges
+D:with great multi-faceted eyes. Its tail is covered with razor-sharp
+D:spikes.
+
+N:788:Glaaki
+G:~:v
+I:130:52d99:20:150:10
+W:67:2:0:36000
+E:0:0:0:0:1:0
+O:0:0:100:0
+B:STING:HURT:20d1
+B:STING:DISEASE:20d1
+B:CRUSH:HURT:3d20
+F:UNIQUE | CAN_SPEAK | ATTR_MULTI | ELDRITCH_HORROR |
+F:NO_STUN | RES_NEXU | RES_WATE | CAN_SWIM | REGENERATE |
+F:FORCE_SLEEP | FORCE_MAXHP | EVIL | SMART | DEMON |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:NO_STUN |
+F:IM_POIS | IM_COLD | IM_ACID | CTHANGBAND
+S:1_IN_5
+S:BA_WATE | S_HYDRA | S_DRAGON | S_DEMON | SCARE |
+S:BLIND | CONF | CAUSE_4 | BR_POIS
+D:"From an oval body protruded countless thin, pointed spines of
+D:multi-colored metal; at the more rounded end of the oval a
+D:circular, thick-lipped mouth formed the centre of a spongy
+D:face, from which rose three yellow eyes on thin stalks. Around
+D:the underside of the body were many white pyramids, presumably
+D:used for locomotion. The diameter of the body must have been
+D:at least ten feet at its least wide..."
+
+N:789:Trone, the Rebel Thunderlord
+G:B:D
+I:130:80d100:20:120:80
+W:72:2:400000:45000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:12d10
+B:HIT:HURT:12d10
+B:CHARGE:HURT:10d10
+B:CHARGE:HURT:10d10
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE | SPECIAL_GENE |
+F:FORCE_MAXHP | REGENERATE | THUNDERLORD | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | OPEN_DOOR | BASH_DOOR | DROP_CHOSEN |
+F:EVIL | IM_FIRE | IM_COLD | IM_POIS |
+F:MORTAL | HAS_LITE
+S:1_IN_4 |
+S:TELE_TO | SCARE | BR_TIME | BR_FIRE |
+S:BO_MANA | S_THUNDERLORD
+D:As the Thunderlords came from afar to help the elves, Trone and his rebel
+D:wing came to defend Morgoth! He is an evil and powerful Thunderlord.
+
+N:790:Great Wyrm of Many Colours
+G:D:v
+I:120:70d100:40:170:255
+W:80:2:190000:31000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:6d12
+B:CLAW:HURT:6d12
+B:CLAW:HURT:8d14
+B:BITE:HURT:8d14
+F:ATTR_MULTI | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE | AURA_ELEC | RES_TELE |
+F:IM_FIRE | IM_ACID | IM_POIS | IM_COLD | IM_ELEC | AURA_COLD |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BR_POIS | BR_ELEC | BR_ACID | BR_FIRE | BR_COLD |
+S:CONF | SCARE | BLIND
+D:A huge dragon whose scales shimmer in myriad hues.
+
+N:791:Marda, rider of gold Laronth
+G:B:y
+I:130:100d85:100:100:50
+W:75:6:420000:35000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:12d15
+B:HIT:HURT:12d15
+B:HIT:HURT:12d15
+B:HIT:HURT:12d15
+F:UNIQUE | FEMALE | CAN_SPEAK | THUNDERLORD | ONLY_ITEM | RES_TELE |
+F:DROP_CHOSEN | DROP_CORPSE | DROP_SKELETON | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 |
+F:EVIL | IM_POIS | IM_ELEC | SMART | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | HAS_LITE
+S:1_IN_4 |
+S:SCARE | BLIND | TPORT | BLINK | TELE_AWAY | TELE_TO |
+S:BR_FIRE | BA_MANA | S_THUNDERLORD
+D:Former leader among the Thunderlords, she and Trone have fallen under the
+D:control of Morgoth. Laronth, her eagle, can summon Thunderlords to her aid.
+
+N:792:Tselakus, the Dreadlord
+G:G:R
+I:130:65d100:20:150:10
+W:68:2:1000:35000
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:LOSE_STR:4d6
+B:HIT:LOSE_STR:4d6
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SPEAK | CAN_FLY |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | AURA_COLD |
+F:IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:BLIND | HOLD | CONF |
+S:BA_DARK | BA_NETH |
+S:S_WRAITH | S_HI_UNDEAD | S_KIN
+D:This huge affront to existence twists and tears at the fabric of space.
+D:Darkness itself recoils from the touch of Tselakus as he leaves a trail
+D:of death and destruction. Mighty claws rend reality as he
+D:annihilates all in his path to your soul!
+
+N:793:Sky Drake
+G:D:B
+I:130:60d100:40:200:255
+W:77:2:220000:40000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:6d12
+B:CLAW:HURT:6d12
+B:BITE:ELEC:8d14
+B:BITE:ELEC:8d14
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_ELEC | AURA_COLD | DROP_CORPSE |
+F:IM_ELEC | EVIL | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY |
+F:DRAGON | NO_CONF | NO_SLEEP | RES_TELE | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BR_ELEC | BR_GRAV | BR_LITE |
+S:S_DRAGON | S_HI_DRAGON |
+S:SCARE | BLIND
+D:The mightiest elemental dragon of air, it can destroy you with ease.
+
+N:794:Eilinel the Entrapped
+G:p:D
+I:120:90d10:10:40:1
+W:42:10:0:3500
+E:1:1:1:2:1:1
+O:20:20:50:10
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:TOUCH:UN_POWER:3d3
+B:TOUCH:UN_BONUS:3d3
+F:UNIQUE | FEMALE |
+F:FORCE_MAXHP |
+F:DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_FIRE | NO_CONF | NO_SLEEP | ZANGBAND | NO_CUT | NO_STUN
+S:1_IN_2 |
+S:BLINK | TELE_TO | HEAL | S_MONSTER | BO_ACID | BO_MANA | CAUSE_3
+D:In life, she was the wife of Gorlim. In death, her shade was
+D:entrapped by Morgoth and used to trick her husband into betraying
+D:Barahir. Now she is totally entrapped by Morgoth's power, and uses
+D:her magic to do his bidding.
+
+N:795:Horned Reaper
+G:U:B
+I:130:50d100:40:120:80
+W:72:3:0:18000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:11d11
+B:HIT:HURT:11d11
+B:HIT:HURT:11d11
+B:HIT:HURT:11d11
+F:FORCE_SLEEP | FORCE_MAXHP | REGENERATE | NONLIVING |
+F:ONLY_ITEM | DROP_GOOD | DROP_4D2 | DROP_2D2 | BASEANGBAND |
+F:OPEN_DOOR | BASH_DOOR | KILL_BODY | POWERFUL |
+F:EVIL | DEMON | NO_CONF | NO_SLEEP | CAN_FLY |
+F:IM_FIRE | IM_COLD | IM_POIS | IM_ACID | IM_ELEC
+S:1_IN_5 |
+S:HASTE | SLOW | SCARE | S_HI_DEMON
+D:A giant humanoid demon wielding a massive, heavy and sharp scythe. Feared
+D:by foes and friends alike when it flies into one of its berserk rages, the
+D:Horned Reaper will cut down anything in its path between it and you - even
+D:the minions it has just summoned.
+
+N:796:The Norsa
+G:H:B
+I:130:100d100:20:125:70
+W:70:4:16000:47500
+E:0:1:0:2:1:0
+O:50:0:50:0
+B:CRUSH:ACID:8d12
+B:CRUSH:FIRE:8d12
+B:CRUSH:ELEC:8d12
+B:CRUSH:POISON:10d14
+F:ATTR_MULTI | ELDRITCH_HORROR | DROP_CORPSE |
+F:UNIQUE | CAN_SPEAK | AURA_FIRE | AURA_ELEC | AURA_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | EVIL |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:ZANGBAND
+S:1_IN_2 |
+S:BLIND | CONF | SCARE |
+S:BR_NETH | BR_CHAO | BR_TIME | BR_GRAV | BR_DISI |
+S:S_HI_DRAGON | S_MONSTERS
+D:An elephantine horror with five trunks, each capable of breathing
+D:destructive blasts. It is said that it is better to face the fury
+D:of a thousand raging lions than the Norsa!
+
+N:797:Rhan-Tegoth
+G:S:b
+I:130:90d100:20:125:70
+W:70:4:0:42500
+E:0:1:0:2:1:0
+O:0:50:50:0
+B:CLAW:HURT:8d12
+B:CRUSH:LOSE_STR:5d12
+B:CLAW:HURT:8d12
+B:CRUSH:ACID:5d12
+F:ELDRITCH_HORROR | CAN_SWIM | EVIL |
+F:UNIQUE | CAN_SPEAK | AURA_FIRE | AURA_ELEC |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_ELEC | IM_POIS | NO_SLEEP | RES_WATE | CTHANGBAND
+S:1_IN_5 |
+S:S_DEMON | BR_ACID | S_UNDEAD | S_KIN | CONF | SCARE |
+S:MIND_BLAST | BR_CONF
+D:"An almost globular torso, with six long, sinuous limbs terminating
+D:in crab-like claws. From the upper end a subsidiary globe bulged
+D:forward bubble-like; its triangle of three staring, fishy eyes,
+D:its foot-long and evidently flexible proboscis, and a distended
+D:lateral system analogous to gills, suggested that it was a head."
+
+N:798:Black reaver
+G:L:D
+I:120:50d100:20:170:50
+W:74:3:1900:23000
+E:0:0:0:0:0:0
+O:0:60:40:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+B:HIT:LOSE_STR:4d6
+B:HIT:LOSE_STR:4d6
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | CAN_SWIM |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | RES_TELE |
+F:NO_CONF | NO_SLEEP | KILL_WALL | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:TELE_TO | BLIND | HOLD | CONF | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | BA_MANA | BA_NETH | S_UNDEAD
+D:A humanoid form, black as night, advancing steadily and unstoppably, even
+D:the very rock of the dungeon cannot prevent it reaching you.
+
+N:799:Master mindcrafter
+G:p:y
+I:120:80d10:20:60:10
+W:40:2:1700:2000
+E:1:1:1:2:1:1
+O:20:40:40:0
+B:HIT:HURT:4d5
+B:HIT:HURT:4d5
+B:HIT:HURT:4d5
+F:MALE | ONLY_ITEM | FORCE_SLEEP | FORCE_MAXHP | DROP_4D2 |
+F:SMART | BASH_DOOR | TAKE_ITEM | MOVE_BODY |
+F:EVIL | IM_FIRE | IM_ELEC | IM_POIS | BASEANGBAND |
+F:NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR
+S:1_IN_2 |
+S:HEAL | BLIND | HOLD | CONF | SCARE | TPORT | BA_COLD | BA_FIRE |
+S:MIND_BLAST | BRAIN_SMASH | S_MONSTERS | TELE_AWAY | BLINK | BO_NETH
+D:A mindcrafter of the highest order. Powerful and evil, and a dangerous
+D:enemy: a master of mind over matter, of his own mind, and of the minds of
+D:others, who slavishly follow him into battle when he calls them.
+
+N:800:Greater demonic quylthulg
+G:Q:R
+I:120:15d100:20:1:0
+W:71:2:5000:10500
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TELE_TO |
+S:S_HI_DEMON
+D:A massive pulsating mound of flesh, glowing with an inner hellish light.
+
+N:801:Greater draconic quylthulg
+G:Q:G
+I:120:15d100:20:1:0
+W:71:2:5000:10500
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TELE_TO |
+S:S_HI_DRAGON
+D:A massive mound of scaled flesh, throbbing and pulsating with multi-hued
+D:light.
+
+N:802:Greater rotting quylthulg
+G:Q:U
+I:120:15d100:20:1:0
+W:71:2:5000:10500
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND |NO_CUT
+S:1_IN_2 |
+S:BLINK | TELE_TO |
+S:S_HI_UNDEAD
+D:A massive pile of rotting flesh. A disgusting stench fills the air as it
+D:throbs and writhes.
+
+N:803:Null, the Living Void
+G:.:d
+I:110:50d100:30:100:20
+W:72:2:0:32500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:LOSE_ALL:6d16
+B:TOUCH:EXP_80:6d16
+B:TOUCH:UN_POWER:6d16
+F:PASS_WALL | NONLIVING | IM_ACID | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | SMART | EMPTY_MIND |
+F:ELDRITCH_HORROR | IM_COLD | RES_NETH | NO_STUN | UNIQUE | NO_SLEEP | NO_CONF | NO_FEAR |
+F:REGENERATE | ZANGBAND | NO_CUT
+S:1_IN_5
+S:BR_NETH | BRAIN_SMASH | SCARE | S_UNDEAD | S_HI_UNDEAD |
+S:DRAIN_MANA | HEAL | ANIM_DEAD
+D:A black hole in the fabric of reality. It simply is not there.
+
+N:804:Feagwath, the Undead Sorcerer
+G:L:y
+I:130:60d100:20:85:50
+W:77:2:1900:30000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:TOUCH:EXP_80:6d12
+B:TOUCH:UN_POWER:6d12
+B:TOUCH:LOSE_DEX:6d12
+B:TOUCH:LOSE_DEX:6d12
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD |
+F:IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:BLINK | TELE_TO | HOLD | SCARE | CAUSE_4 |
+S:BRAIN_SMASH | TRAPS | BA_MANA |
+S:BO_MANA | BA_NETH |
+S:S_MONSTERS | S_UNDEAD | S_KIN | ANIM_DEAD
+D:A stench of corruption and decay surrounds this sorcerer, who has clearly
+D:risen from the dead to continue his foul plots and schemes.
+
+N:805:Omarax the Eye Tyrant
+G:e:v
+I:130:65d100:30:80:10
+W:73:3:600:25000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:UN_BONUS:6d6
+B:GAZE:UN_POWER:6d6
+B:GAZE:INSANITY:6d6
+B:BITE:EXP_80:8d8
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:SMART | BASH_DOOR |
+F:EVIL | IM_POIS |
+F:BASEANGBAND
+S:1_IN_2 |
+S:BLIND | CONF | FORGET | SCARE | DRAIN_MANA | BRAIN_SMASH |
+S:BA_DARK | BO_MANA | BA_NETH | BA_ACID | BA_FIRE | BA_COLD |
+S:S_KIN
+D:A beholder of great size and age, floating in the air. His gaze seems to
+D:shred your soul and his spells crush your will. He is ancient, his history
+D:steeped in forgotten evils, his atrocities numerous and sickening.
+
+N:806:Tsathoggua, the Sleeper of N'kai
+G:R:D
+I:130:66d100:30:80:100
+W:74:4:0:16500
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:CRUSH:LOSE_ALL:5d6
+B:CRUSH:ACID:5d6
+B:CRUSH:LOSE_ALL:5d6
+B:CRUSH:ACID:5d6
+F:UNIQUE | CAN_SPEAK | RES_TELE | ELDRITCH_HORROR |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_1D2 | DROP_2D2 |
+F:ONLY_ITEM | DROP_GOOD | MOVE_BODY |
+F:SMART | BASH_DOOR |
+F:EVIL | DEMON | IM_POIS | IM_ACID | IM_COLD |
+F:NO_CONF | NO_SLEEP | CTHANGBAND | HAS_LITE | NO_CUT
+S:1_IN_2 |
+S:S_DEMON | S_MONSTERS | S_UNDEAD | HOLD | SCARE | MIND_BLAST |
+S:BR_ACID | BR_NETH | CAUSE_4
+D:"...the formless bulking of a couchant mass. And the mass stirred
+D:a little... and put forth with infinite slothfulness a huge and
+D:toad-shaped head. And the head opened its eyes very slowly, as if
+D:half awakened from slumber, so that they were visible as two slits
+D:of oozing phosphor in the black browless face."
+
+N:807:Greater Balrog
+G:U:v
+I:130:75d100:40:140:40
+W:80:3:0:25000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:FIRE:8d12
+B:HIT:FIRE:8d12
+B:CRUSH:HURT:7d12
+B:TOUCH:UN_POWER
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | NONLIVING |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | SMART |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | KILL_WALL |
+F:RES_NETH | RES_PLAS | REGENERATE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BLIND | CONF | BRAIN_SMASH |
+S:BR_FIRE | BA_NETH | BA_FIRE | BR_PLAS | BO_PLAS |
+S:S_HI_DEMON | S_UNDEAD | S_DEMON |
+D:Originally of the semi-divine Maiar, this evil spirit swore allegiance
+D:to Morgoth at the beginning of time and is now one of his most terrible
+D:demonic servants. With its flaming whip and sword it seeks to destroy you.
+
+N:808:Ungoliant, the Unlight
+G:S:D
+I:130:130d100:8:160:80
+W:75:1:1500:35000
+E:0:1:0:2:1:0
+O:20:0:80:0
+B:CLAW:POISON:8d6
+B:CLAW:POISON:8d6
+B:BITE:PARALYZE:8d10
+B:STING:LOSE_STR:8d4
+F:UNIQUE | FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:SMART | BASH_DOOR | IM_ACID |
+F:ANIMAL | SPIDER | EVIL | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP
+F:BASEANGBAND
+S:1_IN_3 |
+S:HEAL | BLIND | SLOW | CONF | SCARE | DARKNESS | BA_DARK |
+S:BR_POIS | BR_DARK | S_SPIDER
+D:This enormous, hideous spirit of void is in the form of a spider of
+D:immense proportions. She is surrounded by a cloud of Unlight as she sucks
+D:in all living light into her bloated body, and breathes out the blackest of
+D:darkness. She is always ravenously hungry and would even eat herself to
+D:avoid starvation.
+
+N:809:Atlach-Nacha, the Spider God
+G:S:D
+I:120:110d100:8:160:80
+W:73:1:2000:31000
+E:0:1:0:2:1:0
+O:60:0:40:0
+B:BITE:POISON:3d9
+B:BITE:LOSE_STR:3d9
+B:STING:POISON:2d9
+B:STING:LOSE_STR:2d9
+F:UNIQUE | CAN_SPEAK | ELDRITCH_HORROR | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:SMART | BASH_DOOR | MOVE_BODY | NONLIVING |
+F:ANIMAL | SPIDER | EVIL | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:CTHANGBAND
+S:1_IN_3 |
+S:SCARE | BLIND | CONF | HOLD | BR_POIS |
+S:DARKNESS | BR_DARK | S_KIN | S_HI_DEMON
+D:"...there was a kind of face on the squat ebon body, low down amid
+D:the several-jointed legs. The face peered up with a weird expression
+D:of doubt and inquiry..."
+
+N:810:Y'golonac
+G:H:R
+I:120:130d99:8:160:80
+W:75:1:0:37500
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:LOSE_INT:1d20
+B:BITE:HURT:40d1
+B:TOUCH:LOSE_WIS:1d20
+B:BITE:HURT:40d1
+F:UNIQUE | CAN_SPEAK | ELDRITCH_HORROR | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:SMART | BASH_DOOR | MOVE_BODY | NONLIVING |
+F:EVIL | IM_POIS | CTHANGBAND
+S:1_IN_3 |
+S:SCARE | BLIND | CONF | HOLD | HASTE | DRAIN_MANA | HASTE |
+S:CAUSE_3 | CAUSE_4 | DARKNESS | FORGET | S_DEMON | S_HOUND |
+S:TPORT | TELE_TO
+D:"He saw why the shadow on the frosted pane yesterday had been
+D:headless and he screamed... but before he could scream out his
+D:protest his breath was cut off, as the hands descended on his
+D:face and the wet red mouths opened in their palms."
+
+N:811:Aether hound
+G:Z:v
+I:120:60d40:30:100:0
+W:74:3:1000:10000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d12
+B:BITE:HURT:3d12
+B:CLAW:HURT:3d12
+B:CLAW:HURT:3d12
+F:ATTR_MULTI | ATTR_ANY |
+F:FORCE_SLEEP | CAN_FLY |
+F:FRIENDS | RES_NETH | RES_PLAS | RES_NEXU | RES_DISE |
+F:BASH_DOOR | AURA_FIRE | AURA_ELEC | AURA_COLD |
+F:DROP_CORPSE | DROP_SKELETON |
+F:ANIMAL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS |
+S:BR_LITE | BR_DARK | BR_SOUN | BR_CONF | BR_CHAO | BR_SHAR |
+S:BR_NETH | BR_DISE | BR_WALL | BR_INER | BR_TIME |
+S:BR_GRAV | BR_PLAS | BR_NEXU
+D:A shifting, swirling form. It seems to be all colours and sizes and
+D:shapes, though the dominant form is that of a huge dog. You feel very
+D:uncertain all of a sudden.
+
+N:812:Pit Fiend
+G:U:o
+I:130:60d100:30:120:75
+W:77:3:0:22000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:CLAW:FIRE:8d10
+B:CLAW:FIRE:8d10
+B:BITE:POISON:7d10
+B:BITE:LOSE_CON:7d10
+F:FORCE_SLEEP | FORCE_MAXHP | REGENERATE | NONLIVING |
+F:ONLY_ITEM | DROP_GOOD | DROP_4D2 | DROP_2D2 | BASEANGBAND |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | POWERFUL | CAN_FLY |
+F:EVIL | DEMON | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP
+S:1_IN_5 |
+S:S_HI_DEMON | S_HI_DRAGON | BR_FIRE | BR_POIS | BR_CHAO | BA_CHAO |
+S:SCARE | BA_FIRE | CAUSE_4
+D:Appearing as a giant, clawed and winged humanoid with a scaly red body
+D:and massive fangs dripping a foul green liquid, the Pit Fiend is a
+D:dreadful enemy from the lowest depths of the hells. They are often the
+D:commanders of vast demon armies.
+
+N:813:The Serpent of Chaos
+G:J:v
+I:130:66d100:30:180:150
+W:75:2:0:25000
+E:0:0:0:0:1:0
+O:40:40:20:0
+B:CRUSH:POISON:15d10
+B:CRUSH:CONFUSE:15d10
+B:CRUSH:UN_BONUS:10d15
+B:CRUSH:UN_POWER:10d15
+F:UNIQUE | ATTR_MULTI | ATTR_ANY | AURA_FIRE | AURA_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP | POWERFUL | REGENERATE |
+F:DROP_2D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | ANIMAL | EVIL | CAN_FLY |
+F:KILL_ITEM | KILL_BODY |
+F:NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR | ZANGBAND |
+F:IM_COLD | IM_FIRE | IM_POIS
+S:1_IN_3 |
+S:BR_CHAO | BR_DISI | BA_CHAO | BR_NETH | BR_MANA |
+S:S_MONSTERS | S_HI_DEMON | S_HI_DRAGON
+D:Writhing coil upon coil, this mighty spawn of Chaos constantly disintegrates
+D:and reforms before your dazzled eyes. It gazes balefully upon you with its
+D:one remaining eye, and seeks to destroy you utterly.
+
+N:814:Yig, Father of Serpents
+G:J:b
+I:130:111d60:100:100:15
+W:76:1:2300:37500
+E:0:0:0:0:1:0
+O:80:0:20:0
+B:CLAW:POISON:8d10
+B:CLAW:POISON:8d10
+B:CRUSH:HURT:8d15
+B:BITE:HURT:100d1
+F:UNIQUE | MALE | CAN_SPEAK | SMART | RES_TELE | ANIMAL |
+F:ESCORT | ESCORTS | CAN_SWIM | ELDRITCH_HORROR |
+F:OPEN_DOOR | BASH_DOOR |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
+F:EVIL | IM_POIS | IM_ACID | IM_ELEC | REGENERATE | ZANGBAND
+S:1_IN_4 |
+S:BR_POIS | BR_NUKE | BR_ACID | S_HYDRA | S_KIN | S_DEMON |
+D:"The half-human father of serpents... the snake-god of the central
+D:plains tribes -- presumably the primal source of the more
+D:southerly Quetzalcoatl or Kukulcan -- was odd, half-anthropomorphic
+D:devil."
+
+N:815:Unmaker
+G:E:v
+I:120:6d66:60:50:60
+W:77:4:0:10000
+E:0:0:0:0:0:0
+O:20:50:20:0
+B:TOUCH:LOSE_ALL:10d10
+B:TOUCH:UN_BONUS:10d10
+B:TOUCH:UN_POWER:10d10
+F:KILL_WALL | KILL_ITEM | KILL_BODY | NO_FEAR |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ATTR_MULTI | SHAPECHANGER | ATTR_ANY |
+F:DROP_60 | DROP_GOOD | POWERFUL | AURA_ELEC | AURA_FIRE | AURA_COLD |
+F:BASH_DOOR | IM_ELEC | IM_FIRE | RES_NEXU | IM_COLD | ZANGBAND |
+F:IM_POIS | IM_ACID | RES_PLAS | RES_DISE | COLD_BLOOD | NONLIVING | RAND_50
+F:NO_CUT
+S:MULTIPLY |
+S:1_IN_5 |
+S:BR_CHAO
+D:Spawned from the Pits of the Abyss, it is a mass of sentient Chaos,
+D:spreading uncontrollably and destroying everything in its path.
+
+N:816:Cyberdemon
+G:U:u
+I:120:70d101:90:90:90
+W:77:4:15000:30000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d50
+B:HIT:HURT:1d50
+B:HIT:HURT:1d50
+B:HIT:HURT:1d50
+F:RAND_25 | EVIL | DEMON |
+F:DROP_2D2 | DROP_GOOD | ONLY_ITEM | RES_TELE | SUSCEP_ACID |
+F:IM_POIS | IM_FIRE | FORCE_SLEEP | FORCE_MAXHP | NONLIVING
+F:MORTAL | ZANGBAND | HAS_LITE
+S:1_IN_4 |
+S:ROCKET
+D:Reverbrant metal steps announce the arrival of this huge creature,
+D:half demon half machine. It has an unsurpassable firepower.
+
+N:817:Hela, Queen of the Dead
+G:p:G
+I:130:74d100:60:110:10
+W:74:3:8000:45000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:TOUCH:LOSE_ALL:50d1
+B:TOUCH:EXP_80:50d1
+B:TOUCH:UN_BONUS:50d1
+F:UNIQUE | FEMALE | CAN_SPEAK | POWERFUL | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_1D2 | DROP_GREAT | DROP_GOOD |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | RES_NETH | IM_COLD | IM_POIS |
+F:IM_FIRE | NO_CONF | NO_SLEEP | ZANGBAND | HAS_LITE
+S:1_IN_3 |
+S:CAUSE_3 | CAUSE_4 | HAND_DOOM | TELE_TO | HOLD |
+S:S_UNDEAD | S_HI_UNDEAD | S_HI_DRAGON | FORGET | SCARE | BLIND |
+S:BA_DARK | BA_NETH | HEAL | ANIM_DEAD
+D:The Norse ruler of Hel is a merciless queen, who ever hunts for more
+D:souls to add to her collection of tortured spirits. She arrives in
+D:an ominous green robe, a certain sign of impending doom, to claim
+D:as her own those who die an ignoble death.
+
+N:818:The Mouth of Sauron
+G:p:v
+I:130:90d100:60:100:10
+W:78:3:1900:38000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+B:TOUCH:UN_POWER
+B:TOUCH:UN_POWER
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_COLD |
+F:IM_ELEC | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:TELE_TO | HOLD | CAUSE_3 | TRAPS | ANIM_DEAD |
+S:BO_PLAS | BA_DARK | BA_MANA | BA_FIRE | BA_WATE | BA_NETH
+S:S_HI_DEMON | S_HI_UNDEAD
+D:The Mouth of Sauron is a mighty spell caster. So old that even he cannot
+D:remember his own name, his power and evil are undeniable. He believes
+D:unshakeably that he is unbeatable and laughs as he weaves his awesome
+D:spells.
+
+N:819:The Necromancer of Dol Guldur
+G:p:v
+I:130:82d100:60:100:10
+W:75:3:1900:40000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_POWER:6d8
+B:HIT:BLIND:6d8
+B:HIT:CONFUSE:6d8
+F:UNIQUE | MALE | CAN_SPEAK | POWERFUL | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_1D2 | DROP_GREAT | DROP_GOOD | SPECIAL_GENE |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_COLD |
+F:IM_ELEC | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_2 |
+S:CAUSE_3 | TELE_TO | BA_FIRE | DRAIN_MANA | HOLD |
+S:TRAPS | BA_WATE | BO_PLAS | BA_NETH |
+S:BA_MANA | BA_DARK | S_HI_UNDEAD | BA_CHAO | HAND_DOOM | ANIM_DEAD
+D:The dark master of the terrible fortress of southern Mirkwood. It is
+D:rumoured that this is in fact none other than Sauron in disguise:
+D:although if this is so, he has yet to reveal his full power - and perhaps
+D:will not do so while his deception lasts, in the hope of keeping it going.
+
+N:820:Lisa, rider of gold Romth
+G:B:y
+I:130:65d100:100:100:15
+W:78:6:420000:35500
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:10d15
+B:HIT:HURT:10d15
+B:HIT:HURT:10d15
+B:HIT:HURT:10d15
+F:UNIQUE | FEMALE | THUNDERLORD | RES_TELE | CAN_FLY | GOOD |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | PET |
+F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
+F:IM_COLD | IM_POIS | IM_ACID | IM_ELEC | REGENERATE |
+F:MORTAL | HAS_LITE
+S:1_IN_4 |
+S:TPORT | TELE_TO | BR_FIRE | S_THUNDERLORD |
+S:TELE_AWAY | HEAL | BA_NETH | BO_NETH | BA_FIRE | BO_FIRE
+D:She came to help you.
+
+N:821:Master quylthulg
+G:Q:B
+I:120:30d100:20:1:0
+W:76:2:7000:15000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:S_MONSTERS | S_HI_UNDEAD | S_HI_DRAGON | S_HI_DEMON | S_ANIMALS | BLINK | TELE_TO
+D:A giant seething mass of flesh, overwhelming you with monster after monster.
+
+N:822:Qlzqqlzuup, the Lord of Flesh
+G:Q:v
+I:130:50d100:30:1:0
+W:79:3:10000:20000
+E:0:0:0:0:0:0
+O:20:20:20:20
+F:UNIQUE | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:ONLY_ITEM | DROP_4D2 |
+F:INVISIBLE | ATTR_MULTI | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_1 |
+S:S_MONSTERS | S_ANGEL | S_HOUND | S_HYDRA | S_SPIDER | S_ANT | S_ANIMALS |
+S:S_HI_UNDEAD | S_HI_DRAGON | S_HI_DEMON | S_WRAITH | S_UNIQUE | S_KIN
+D:A gigantic seething mass of flesh, Qlzqqlzuup changes colours in front
+D:of your eyes. Pulsating first one colour then the next, it knows only it
+D:must bring help to protect itself.
+
+N:823:Cthugha, the Living Flame
+G:E:R
+I:133:50d100:30:1:20
+W:78:3:0:17500
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:BLIND
+B:TOUCH:FIRE:12d10
+B:TOUCH:FIRE:12d10
+B:TOUCH:FIRE:12d10
+F:UNIQUE | RES_TELE | AURA_FIRE | IM_FIRE | CAN_FLY | RES_PLAS |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | SMART | ELDRITCH_HORROR |
+F:EVIL | KILL_ITEM | KILL_BODY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | CTHANGBAND | HAS_LITE | NO_CUT
+S:1_IN_4 |
+S:BR_FIRE | S_KIN
+D:"But even though we had shielded our eyes, it was impossible not
+D:to see the great amorphous shapes streaming skyward from the
+D:accursed place, nor the equally great being hovering like a cloud
+D:of living fire above the trees."
+
+N:824:Flare, rider of bronze Moonth
+G:B:U
+I:130:70d100:100:100:15
+W:79:5:400000:38500
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:15d15
+B:HIT:HURT:15d15
+B:HIT:HURT:15d15
+B:HIT:HURT:15d15
+F:UNIQUE | MALE | THUNDERLORD | RES_TELE | CAN_FLY | CAN_SPEAK |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_SLEEP | FORCE_MAXHP | PET | GOOD |
+F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
+F:IM_COLD | IM_POIS | IM_ACID | IM_ELEC | IM_FIRE | REGENERATE |
+F:MORTAL | HAS_LITE
+S:1_IN_4 |
+S:SCARE | TPORT | TELE_TO | S_THUNDERLORD |
+S:TELE_LEVEL | HEAL | BR_FIRE | BR_TIME | ROCKET
+D:A leader from afar, he has come with his eagle to help you in
+D:your battle. Having already saved his home, he now wants to save Arda!
+
+N:825:Maeglin, the Traitor of Gondolin
+G:h:D
+I:130:60d100:220:120:20
+W:81:2:1400:35000
+E:1:1:1:2:1:1
+O:30:70:0:0
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | CAN_SPEAK | SMART | EVIL | AI_SPECIAL |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | KILL_WALL | MOVE_BODY | TAKE_ITEM |
+F:IM_FIRE | IM_COLD | IM_POIS | SPECIAL_GENE |
+F:REGENERATE | REFLECTING | DROP_SKELETON | DROP_CORPSE | BASEANGBAND
+F:HAS_LITE
+S:1_IN_6 |
+S:S_MONSTERS | S_WRAITH | S_HI_UNDEAD |
+S:S_HI_DRAGON | S_HI_DEMON | S_UNIQUE | S_ANIMALS
+D:The son of Eol the Dark Elf, Maeglin is every bit as evil as his father
+D:and more. His greed for gold led him to betray the Hidden Kingdom of
+D:Gondolin to Morgoth's forces. He is a mighty warrior himself, and some
+D:of Morgoth's greatest servants answer to his call.
+
+N:826:Cyaegha
+G:e:G
+I:130:64d100:90:120:10
+W:80:3:0:44444
+E:0:0:0:0:0:0
+O:20:50:30:0
+B:CRUSH:HURT:15d15
+B:CRUSH:HURT:15d15
+B:CRUSH:HURT:15d15
+B:CRUSH:HURT:15d15
+F:UNIQUE | CAN_SPEAK | RES_TELE | ELDRITCH_HORROR | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | DEMON | IM_ACID | IM_ELEC |
+F:IM_COLD | IM_POIS | CTHANGBAND | HAS_LITE
+S:1_IN_3 |
+S:TELE_AWAY | BLIND | HOLD | SCARE | BRAIN_SMASH |
+S:BR_DARK | BA_DARK | BR_NETH | HAND_DOOM |
+S:S_HI_UNDEAD | S_DEMON | S_MONSTERS | S_HYDRA
+D:"...it was a gigantic eye staring down at them. Around the eye,
+D:the sky split; deep clefts opened through which the darkness
+D:began to ooze, a darkness blacker than the night, which crawled
+D:down as a set of slimy tentacles, taking on more form, more
+D:definite shape... something was standing, outlined against
+D:the black sky, something which had tentacles of darkness
+D:and a green-glowing eye."
+
+N:827:Pazuzu, Lord of Air
+G:U:b
+I:140:55d100:40:125:10
+W:82:2:0:30000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:ELEC:12d12
+B:HIT:ELEC:12d12
+B:HIT:ELEC:12d12
+B:HIT:ELEC:12d12
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC |
+F:IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_3 |
+S:MIND_BLAST | BO_ELEC | BO_MANA | BA_ELEC | S_HI_DEMON
+D:A winged humanoid demon from the Planes of Hell, Pazuzu grins inhumanely at you
+D:as he decides your fate.
+
+N:828:Ithaqua the Windwalker
+G:Y:B
+I:140:55d100:40:125:10
+W:82:2:0:32500
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:CLAW:COLD:12d12
+B:CLAW:COLD:12d12
+B:CRUSH:ELEC:12d12
+B:CRUSH:ELEC:12d12
+F:UNIQUE | CAN_SPEAK | ESCORT | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | AURA_COLD |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | AURA_ELEC |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR | NONLIVING |
+F:EVIL | DEMON | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC |
+F:IM_POIS | NO_CONF | NO_SLEEP | CTHANGBAND
+S:1_IN_3 |
+S:BO_MANA | SCARE | BR_COLD | S_DEMON | BO_ELEC | BA_ELEC |
+S:MIND_BLAST | CAUSE_4 | BA_CHAO | BA_WATE | S_HI_UNDEAD | S_KIN
+D:The Wendigo, moving so fast that you can see little except two
+D:glowing eyes burning with hatred.
+
+N:829:Greater Hellhound
+G:C:r
+I:120:48d30:25:80:30
+W:78:2:600:600
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:5d12
+B:BITE:FIRE:5d12
+B:BITE:FIRE:5d12
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:RAND_25 | FRIENDS | AURA_FIRE | SUSCEP_COLD |
+F:BASH_DOOR | MOVE_BODY |
+F:ANIMAL | EVIL | IM_FIRE | BASEANGBAND | HAS_LITE |
+S:1_IN_5 | BR_FIRE
+D:It is a giant dog that glows with heat. Flames pour from its nostrils.
+
+N:830:Cantoras, the Skeletal Lord
+G:s:v
+I:140:75d100:20:120:80
+W:84:2:0:45000
+E:1:1:1:2:1:1
+O:50:0:50:0
+B:GAZE:EXP_80:5d5
+B:GAZE:EXP_80:5d5
+B:TOUCH:POISON:5d5
+B:TOUCH:POISON:5d5
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:TELE_TO | SLOW | SCARE | CAUSE_4 | BRAIN_SMASH |
+S:BO_ICEE | BO_MANA | BA_WATE | BA_NETH |
+S:S_HI_UNDEAD | ANIM_DEAD
+D:A legion of evil undead druj animating the skeleton of a once mighty
+D:sorcerer. His power is devastating and his speed unmatched in the
+D:underworld. Flee his wrath!
+
+N:831:Mephistopheles, Lord of Hell
+G:U:r
+I:140:30d222:20:150:50
+W:84:2:0:42500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:GAZE:EXP_80:10d5
+B:GAZE:TERRIFY:10d5
+B:TOUCH:FIRE:4d15
+B:TOUCH:UN_POWER:4d15
+F:MALE | UNIQUE | CAN_SPEAK | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:IM_FIRE | RES_PLAS | RES_NETH | AURA_FIRE |
+F:NO_CONF | NO_SLEEP | NONLIVING | EVIL | DEMON |
+F:ESCORTS | IM_COLD | IM_POIS | ZANGBAND | HAS_LITE
+S:1_IN_3 |
+S:TELE_TO | SCARE | HOLD | BRAIN_SMASH |
+S:S_DEMON | S_HI_UNDEAD | S_UNDEAD |
+S:BR_FIRE | BR_NETH | S_HI_DEMON | HAND_DOOM | ANIM_DEAD
+D:A duke of hell, in the flesh.
+
+N:832:Godzilla
+G:R:v
+I:130:85d100:50:185:20
+W:84:2:900000:35000
+E:0:1:0:2:1:0
+O:100:0:0:0
+B:CLAW:POISON:5d10
+B:CLAW:POISON:5d10
+B:BITE:HURT:20d10
+B:CRUSH:UN_BONUS:5d12
+F:UNIQUE | CAN_SWIM | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP | RES_PLAS | RES_DISE | RES_TELE
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | IM_FIRE | IM_COLD | IM_POIS
+F:MORTAL | JOKEANGBAND
+S:1_IN_2 |
+S:BR_DISE | BR_PLAS | BR_NUKE | BR_POIS | BR_ACID
+D:Godzilla rose from the contaminated sea. This terrible creature could
+D:level whole cities in anger.
+
+N:833:Abhoth, Source of Uncleanness
+G:j:G
+I:130:80d105:50:150:0
+W:85:3:0:40000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:ACID:11d11
+B:TOUCH:DISEASE:11d11
+B:TOUCH:ACID:11d11
+B:TOUCH:POISON:11d11
+F:ONLY_ITEM | DROP_1D2 | CAN_SWIM |
+F:DROP_GOOD | DROP_GREAT |
+F:CAN_SPEAK | EVIL | UNIQUE | NEVER_MOVE | FORCE_MAXHP | FORCE_SLEEP |
+F:IM_ACID | IM_POIS | IM_COLD | IM_ELEC | RES_NETH | RES_WATE | RES_NEXU |
+F:NO_FEAR | NO_CONF | NO_SLEEP | DEMON | SMART | ELDRITCH_HORROR |
+F:COLD_BLOOD | RES_DISE | NO_STUN | CTHANGBAND | NO_CUT
+S:1_IN_6 |
+S:S_MONSTERS | S_DEMON | S_HI_DRAGON | S_HI_UNDEAD | HEAL |
+S:TELE_AWAY | TPORT | CAUSE_4 | BRAIN_SMASH | DRAIN_MANA |
+S:BR_NUKE | BR_POIS | BR_CHAO | BR_NEXU | ANIM_DEAD
+D:"...in the pool [there was] a grayish, horrid mass that nearly choked
+D:it from rim to rim. Here, it seemed, was the ultimate source of all
+D:miscreation and abomination. For the gray mass quobbed and quivered,
+D:and swelled perpetually; and from it, in manifold fission, were
+D:spawned the anatomies that crept away on every side through the
+D:grotto."
+
+N:834:Ymir, the Ice Giant
+G:P:w
+I:130:86d110:50:160:20
+W:71:2:0:32500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:COLD:9d11
+B:HIT:HURT:9d11
+B:HIT:COLD:9d11
+B:HIT:HURT:9d11
+F:UNIQUE | CAN_SPEAK | SUSCEP_FIRE |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | RES_NETH | RES_WATE | MALE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | EVIL | ESCORT | GIANT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | TAKE_ITEM | RES_DISE |
+F:EVIL | IM_COLD | IM_POIS | SUSCEP_FIRE |
+F:COLD_BLOOD | AURA_COLD | DROP_CORPSE | ZANGBAND | HAS_LITE | NO_CUT
+S:1_IN_5 |
+S:BR_COLD | BO_ICEE | DARKNESS | TELE_TO | S_KIN | S_HI_UNDEAD |
+S:TELE_AWAY | HAND_DOOM
+D:Ymir is one of the oldest beings in existence. He looks like a giant
+D:humanoid made of ice.
+
+N:835:Loki, the Trickster
+G:P:D
+I:130:110d100:50:160:20
+W:85:2:0:75000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:BLIND:6d11
+B:HIT:UN_BONUS:6d11
+B:HIT:UN_POWER:6d11
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | RES_NETH | RES_PLAS |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_GREAT | EVIL | AURA_FIRE |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | TAKE_ITEM | CAN_SPEAK |
+F:EVIL | IM_FIRE | NO_CONF | NO_SLEEP | IM_POIS | SUSCEP_COLD | GIANT |
+F:REGENERATE | ZANGBAND | HAS_LITE
+S:1_IN_5 |
+S:SHRIEK | HASTE | HEAL | DRAIN_MANA | TPORT | TELE_TO | TELE_AWAY |
+S:TELE_LEVEL | FORGET | S_HI_DEMON | HAND_DOOM | S_HI_UNDEAD |
+S:S_UNIQUE | S_HI_DRAGON | BA_DARK | BA_MANA | ANIM_DEAD
+D:Loki, the god of mischief, is a nasty person. He will use every
+D:dirty trick in the book, and then some. In the end, his half-giant
+D:heritage is bound to show, as he will defect to the side of the
+D:giants and fight against the other gods of Asgard.
+
+N:836:Star-spawn of Cthulhu
+G:U:G
+I:130:75d100:90:90:90
+W:86:2:0:44000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:CLAW:POISON:1d30
+B:CLAW:ACID:1d30
+B:TOUCH:UN_POWER:1d10
+B:CRUSH:UN_BONUS:2d33
+F:RAND_25 | KILL_ITEM | OPEN_DOOR | BASH_DOOR | RES_NETH | ELDRITCH_HORROR |
+F:DROP_1D2 | DROP_2D2 | DROP_90 | ONLY_ITEM | FORCE_SLEEP | FORCE_MAXHP |
+F:EVIL | DEMON | IM_POIS | IM_COLD | IM_ACID | IM_ELEC | RES_TELE | NONLIVING |
+F:POWERFUL | IM_FIRE | CAN_SWIM | CTHANGBAND
+S:1_IN_3
+S:SCARE | CONF | S_DEMON | S_UNDEAD | DRAIN_MANA | BR_ACID |
+S:BR_FIRE | TPORT | S_MONSTERS | BRAIN_SMASH | BR_NETH |
+S:HEAL | MIND_BLAST | BA_NUKE | ANIM_DEAD
+D:The last remnants of sanity threaten to leave your brain as you
+D:behold this titanic bat-winged, octopus-headed unholy abomination.
+D:"They all lay in stone houses in their great city of R'lyeh,
+D:preserved by the spells of mighty Cthulhu for a glorious
+D:resurrection when the stars and the earth might once more
+D:be ready..."
+
+N:837:Surtur, the Fire Giant
+G:P:r
+I:130:86d110:50:160:20
+W:71:2:0:32500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:FIRE:9d11
+B:HIT:HURT:9d11
+B:HIT:FIRE:9d11
+B:HIT:HURT:9d11
+F:UNIQUE | SUSCEP_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | RES_NETH | RES_PLAS | MALE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | EVIL | AURA_FIRE |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | TAKE_ITEM | CAN_SPEAK |
+F:EVIL | IM_FIRE | NO_CONF | NO_SLEEP | IM_POIS | SUSCEP_COLD | GIANT |
+F:ZANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BR_FIRE | BR_PLAS | BLIND | TELE_TO | S_KIN |
+S:HAND_DOOM | TELE_AWAY | S_HI_DEMON
+D:Surtur is another of the most ancient of all creatures. He is a demonic
+D:giant of fire, who is destined to set the nine worlds afire with his
+D:accursed sword of doom on the day of Ragnarok.
+
+N:838:The Tarrasque
+G:R:v
+I:130:130d100:50:185:20
+W:84:2:50000:35000
+E:1:1:1:2:1:1
+O:20:50:25:5
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:TOUCH:UN_POWER:10d10
+B:TOUCH:UN_POWER:10d10
+F:UNIQUE | ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | IM_FIRE | IM_COLD | NO_SLEEP | BASEANGBAND
+S:1_IN_2 |
+S:BR_FIRE | BR_COLD | BR_DISE
+D:The Tarrasque is a massive reptile of legend, rumoured to be unkillable
+D:and immune to magic. Fear its anger, for its devastation is unmatched!
+
+N:839:Lungorthin, the Balrog of White Fire
+G:U:v
+I:130:80d100:20:125:80
+W:88:2:14000:37000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:FIRE:8d12
+B:HIT:FIRE:8d12
+B:CRUSH:HURT:8d12
+B:TOUCH:UN_POWER
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON | IM_FIRE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_FIRE | BR_PLAS |
+S:S_HI_DEMON | S_UNDEAD
+D:A massive form cloaked in flame. Lungorthin stares balefully at you with
+D:eyes that smoulder red. The dungeon floor where he stands is scorched by
+D:the heat of his body.
+
+N:840:Draugluin, Sire of All Werewolves
+G:C:v
+I:130:80d100:80:90:90
+W:83:2:1000:40000
+E:0:1:0:2:1:0
+O:0:0:100:0
+B:CLAW:HURT:6d8
+B:CLAW:HURT:6d8
+B:BITE:POISON:6d6
+B:BITE:POISON:6d6
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS | DROP_CORPSE |
+F:RAND_25 |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:ANIMAL | EVIL | IM_POIS | BASEANGBAND
+S:1_IN_3 |
+S:SCARE | S_MONSTERS | S_HOUND
+D:Draugluin provides Sauron with a fearsome personal guard. He is an
+D:enormous wolf inhabited by a human spirit. He is chief of all his kind.
+
+N:841:Shuma-Gorath
+G:e:G
+I:130:85d100:50:150:0
+W:88:3:0:47000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:CRUSH:HURT:12d12
+B:CRUSH:HURT:12d12
+B:GAZE:LOSE_INT:2d12
+B:GAZE:LOSE_WIS:2d12
+F:ONLY_ITEM | DROP_1D2 | CAN_SWIM |
+F:DROP_GOOD | DROP_GREAT |
+F:CAN_SPEAK | EVIL | UNIQUE | NEVER_MOVE | FORCE_MAXHP | FORCE_SLEEP |
+F:IM_ACID | IM_POIS | IM_COLD | IM_ELEC | RES_NETH | RES_WATE | RES_NEXU |
+F:NO_FEAR | NO_CONF | NO_SLEEP | DEMON | SMART | ELDRITCH_HORROR |
+F:COLD_BLOOD | RES_DISE | CTHANGBAND | NO_CUT
+S:1_IN_2 |
+S:FORGET | HEAL | HAND_DOOM | BA_MANA | TPORT | TELE_AWAY |
+S:TELE_LEVEL | CONF | BLIND | BRAIN_SMASH | DRAIN_MANA |
+S:S_MONSTERS | S_KIN | S_HI_DEMON | S_HOUND | S_HYDRA |
+S:S_UNIQUE | S_HI_UNDEAD | S_HI_DRAGON | ANIM_DEAD
+D:Shuma-Gorath is one of the immortal lords of chaos. The true form of
+D:this blasphemous horror is a huge, all-seeing eye surrounded by tentacles.
+
+N:842:Tulzscha, the Green Flame
+G:E:G
+I:130:100d100:90:100:50
+W:89:4:0:45000
+E:0:0:0:0:0:0
+O:0:100:0:0
+B:HIT:HURT:2d50
+B:HIT:HURT:2d50
+B:HIT:HURT:2d50
+B:HIT:HURT:2d50
+F:RAND_25 | EVIL | DEMON | AURA_FIRE | AURA_COLD | ELDRITCH_HORROR |
+F:DROP_2D2 | DROP_4D2 | DROP_GOOD | ONLY_ITEM | RES_TELE |
+F:IM_POIS | IM_FIRE | FORCE_SLEEP | FORCE_MAXHP | NONLIVING |
+F:IM_COLD | IM_ACID | IM_ELEC | RES_NEXU | RES_NETH | RES_PLAS |
+F:REGENERATE | UNIQUE | CTHANGBAND | HAS_LITE | NO_CUT | NO_SLEEP | NO_FEAR
+S:1_IN_3 |
+S:BR_NEXU | BR_NETH | BR_COLD | BR_FIRE
+D:"A belching column of sick greenish flame... spouting volcanically
+D:from the depths profound and inconceivable, casting no shadows as
+D:healthy flame should, and coating the nitrous stone with a nasty,
+D:venomous verdigris. For all that seething combustion no warmth
+D:lay, but only the clamminess of death and corruption."
+
+N:843:Oremorj, the Cyberdemon Lord
+G:U:u
+I:130:90d100:90:90:90
+W:89:4:0:50000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:2d50
+B:HIT:HURT:2d50
+B:HIT:HURT:2d50
+B:HIT:HURT:2d50
+F:RAND_25 | EVIL | DEMON | SUSCEP_ACID |
+F:DROP_2D2 | DROP_GOOD | ONLY_ITEM | RES_TELE | DROP_GREAT | UNIQUE | NO_SLEEP |
+F:IM_POIS | IM_FIRE | FORCE_SLEEP | FORCE_MAXHP | NONLIVING | JOKEANGBAND |
+F:HAS_LITE
+S:1_IN_3 |
+S:ROCKET | S_HI_DEMON
+D:The mightiest of Cyberdemons, their lord and ruler.
+
+N:844:Vecna, the Emperor Lich
+G:L:v
+I:130:80d100:100:100:0
+W:92:3:0:45000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:EXP_80:7d12
+B:HIT:LOSE_DEX:7d12
+B:HIT:UN_POWER:7d12
+B:HIT:UN_POWER:7d12
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:TPORT | BLIND | SCARE | CAUSE_4 | BRAIN_SMASH |
+S:BA_MANA | BO_MANA | BA_FIRE | BA_NETH |
+S:S_MONSTERS | S_HI_DEMON | S_HI_UNDEAD | S_KIN | HAND_DOOM | ANIM_DEAD
+D:The greatest of all undead sorcerers, even the gods once feared him. This
+D:ancient shadow of death wilts every living thing it passes.
+
+N:845:Yog-Sothoth, the All-in-One
+G:j:v
+I:130:66d99:100:100:20
+W:90:3:0:45000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:HURT:40d5
+B:TOUCH:LOSE_CON:16d2
+B:TOUCH:LOSE_CON:16d2
+F:UNIQUE | CAN_SPEAK | SMART | ELDRITCH_HORROR | RES_TELE
+F:PASS_WALL | FORCE_SLEEP | FORCE_MAXHP | AURA_ELEC | AURA_FIRE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | ATTR_MULTI | ATTR_ANY | AURA_COLD |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | NONLIVING | CAN_FLY |
+F:EVIL | IM_ACID | IM_COLD | IM_ELEC | IM_POIS | IM_FIRE | NO_CONF | NO_SLEEP
+F:CTHANGBAND | HAS_LITE | NO_CUT
+S:1_IN_3 |
+S:BO_MANA | BRAIN_SMASH | BA_MANA | S_MONSTERS | S_HI_DEMON |
+S:BA_CHAO | S_DEMON | S_HI_UNDEAD | S_HOUND | BR_MANA | BR_DISI
+D:"Great globes of light massing towards the opening... the breaking
+D:apart of the nearest globes, and the protoplasmic flesh that
+D:flowed blackly outward to join together and form that eldritch,
+D:hideous horror from outer space... whose mask was a congeries
+D:of iridescent globes... who froths as primal slime in nuclear
+D:chaos forever beyond the nethermost outposts of space and time!"
+
+N:846:Fenris Wolf
+G:C:D
+I:130:70d100:80:90:40
+W:90:2:0:35000
+E:0:1:0:2:1:0
+O:20:0:80:0
+B:BITE:HURT:20d6
+B:CLAW:HURT:8d8
+B:CLAW:HURT:8d8
+B:BITE:HURT:20d6
+F:UNIQUE | CAN_SPEAK | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:RAND_25 |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | KILL_BODY | NO_SLEEP
+F:ANIMAL | EVIL | IM_POIS | IM_FIRE | IM_COLD | ZANGBAND
+S:1_IN_8 |
+S:BR_DARK | BR_POIS | BR_COLD
+D:The immensely huge wolf who would swallow the sun to satisfy its
+D:hunger - and leave the gods for dessert.
+
+N:847:Great Wyrm of Power
+G:D:v
+I:130:111d111:40:160:70
+W:85:4:220000:47500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:8d12
+B:CLAW:HURT:8d12
+B:BITE:HURT:10d14
+B:BITE:HURT:10d14
+F:FORCE_SLEEP | FORCE_MAXHP | MOVE_BODY | AURA_FIRE | REFLECTING | AURA_ELEC |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | AURA_COLD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | RES_NETH | RES_DISE |
+F:DRAGON | GOOD | RES_TELE | DROP_CORPSE |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:RES_NEXU | RES_PLAS | CAN_FLY | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_4 |
+S:S_HI_DRAGON | S_DRAGON | S_KIN |
+S:BR_ACID | BR_ELEC | BR_FIRE |
+S:BR_COLD | BR_POIS | BR_NETH | BR_LITE | BR_DARK |
+S:BR_CONF | BR_SOUN | BR_CHAO | BR_DISE | BR_NEXU |
+S:BR_TIME | BR_INER | BR_GRAV | BR_SHAR | BR_PLAS |
+S:BR_WALL | BR_MANA | BR_DISI
+D:The mightiest of all dragonkind, a great wyrm of power is seldom
+D:encountered in our world. It can crush stars with its might.
+
+N:848:Shub-Niggurath, Black Goat of the Woods
+G:U:D
+I:130:65d99:100:100:20
+W:91:3:0:47500
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:CRUSH:LOSE_WIS:20d5
+B:CRUSH:LOSE_INT:20d5
+B:BITE:LOSE_STR:10d2
+B:BITE:LOSE_CON:10d2
+F:UNIQUE | CAN_SPEAK | FEMALE | ELDRITCH_HORROR | AURA_ELEC | RES_TELE |
+F:ATTR_MULTI | FORCE_SLEEP | FORCE_MAXHP | PASS_WALL | ATTR_ANY |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_90 | NONLIVING | CAN_FLY |
+F:SMART | OPEN_DOOR | BASH_DOOR | REGENERATE | DEMON | AURA_COLD |
+F:EVIL | IM_ACID | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | CTHANGBAND
+S:1_IN_3 |
+S:BO_MANA | BRAIN_SMASH | BA_DARK | S_MONSTERS |
+S:CAUSE_4 | HEAL | BR_CHAO | BR_CONF | BR_POIS | BR_NUKE |
+S:BA_CHAO | S_HI_DEMON | S_HI_UNDEAD | S_UNIQUE | ANIM_DEAD
+D:This horrendous outer god looks like a writhing cloudy mass filled
+D:with mouths and tentacles.
+
+N:849:Nodens, Lord of the Great Abyss
+G:P:W
+I:130:75d99:100:100:20
+W:81:3:0:48000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:2d66
+B:HIT:HURT:2d66
+B:HIT:HURT:2d66
+B:HIT:HURT:2d66
+F:UNIQUE | CAN_SPEAK | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | PASS_WALL |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_90 | DROP_GREAT |
+F:SMART | OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:GOOD | IM_ACID | IM_COLD | IM_POIS | IM_FIRE | IM_ELEC |
+F:RES_NEXU | RES_NETH | RES_WATE | ZANGBAND | HAS_LITE
+S:1_IN_1 |
+S:TELE_AWAY | TELE_TO | TELE_LEVEL | TPORT |
+S:BO_MANA | BA_MANA | S_MONSTERS | HEAL |
+S:CAUSE_4 | HASTE | HAND_DOOM |
+S:S_ANGEL | S_UNIQUE
+D:The hoary Lord of the Great Abyss seems a wizened man,
+D:but appearances can be deceiving.
+
+N:850:Carcharoth, the Jaws of Thirst
+G:C:D
+I:130:90d100:80:110:10
+W:94:1:3400:40000
+E:0:1:0:2:1:0
+O:30:10:60:0
+B:CLAW:POISON:9d12
+B:CLAW:POISON:9d12
+B:BITE:FIRE:9d12
+B:BITE:FIRE:9d12
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | AURA_FIRE |
+F:SMART | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:ANIMAL | EVIL | IM_FIRE | IM_POIS | BASEANGBAND
+S:1_IN_3 |
+S:BR_DARK | BR_POIS | BR_FIRE | BR_NETH | S_HOUND
+D:The first guard of Angband, Carcharoth, also known as 'The Red Maw', is
+D:the largest wolf to ever walk the earth. He is highly intelligent and a
+D:deadly opponent in combat.
+
+N:851:Nyarlathotep, the Crawling Chaos
+G:U:r
+I:130:90d99:100:100:20
+W:93:3:0:49000
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:CRUSH:LOSE_CON:30d4
+B:CRUSH:LOSE_STR:30d4
+B:GAZE:LOSE_INT:1d50
+B:GAZE:LOSE_WIS:1d50
+F:UNIQUE | CAN_SPEAK | ELDRITCH_HORROR | RES_TELE | NONLIVING |
+F:FORCE_SLEEP | FORCE_MAXHP | PASS_WALL | DEMON | RES_NEXU |
+F:SHAPECHANGER | ATTR_MULTI | ATTR_ANY | MALE | AURA_ELEC |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_GREAT | DROP_90 |
+F:SMART | OPEN_DOOR | BASH_DOOR | REGENERATE | AURA_COLD |
+F:EVIL | IM_ACID | IM_POIS | IM_FIRE | NO_CONF | NO_SLEEP | CTHANGBAND
+S:1_IN_3 |
+S:TELE_AWAY | TELE_TO | TELE_LEVEL | TPORT | BR_NEXU | BA_CHAO |
+S:BA_MANA | BA_FIRE | S_MONSTERS | BRAIN_SMASH | MIND_BLAST |
+S:CAUSE_4 | HASTE | S_HI_UNDEAD | S_HI_DRAGON | ANIM_DEAD |
+S:S_ANGEL | HEAL | S_SPIDER | S_HOUND | S_HI_DEMON | HAND_DOOM
+D:Nyarlathothep is the messenger, the heart and the soul of the outer gods.
+D:He is a shapechanger capable of assuming thousands of nightmarish forms.
+D:One of them looks like this: "A tall, slim figure with the young face of
+D:an antique pharaoh, gay with prismatic robes and crowned with a
+D:pshent that glowed with inherent light... the fascination of a
+D:dark god or fallen archangel, and around whose eyes there lurked
+D:the languid sparkle of capricious humor."
+
+N:852:Azathoth, the Daemon Sultan
+G:E:B
+I:130:99d99:100:150:100
+W:93:3:0:50000
+E:0:0:0:0:0:0
+O:0:50:0:50
+B:CRUSH:HURT:35d5
+B:CRAWL:ACID:35d5
+B:CRUSH:HURT:35d5
+B:CRAWL:ACID:35d5
+F:UNIQUE | ELDRITCH_HORROR | RES_TELE
+F:FORCE_SLEEP | FORCE_MAXHP | KILL_WALL | DEMON | AURA_FIRE | AURA_ELEC |
+F:ATTR_MULTI | ESCORTS | ESCORT | POWERFUL | ATTR_ANY | NONLIVING |
+F:KILL_ITEM | KILL_WALL | CAN_SWIM | AURA_COLD
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_90 | RES_DISE |
+F:STUPID | OPEN_DOOR | BASH_DOOR | REGENERATE | EMPTY_MIND |
+F:EVIL | IM_ACID | IM_POIS | IM_FIRE | NO_CONF | NO_SLEEP | NO_STUN | CTHANGBAND
+F:HAS_LITE | NO_CUT
+S:1_IN_5 |
+S:S_DEMON | BR_CHAO | BR_DISE | BR_MANA | BA_WATE | BR_DISI
+D:"That last amorphous blight of nethermost confusion which
+D:blasphemes and bubbles at the centre of all infinity --
+D:the boundless daemon sultan Azathoth, whose name no lips
+D:dare speak aloud, and who gnaws hungrily in inconceivable,
+D:unlighted chambers beyond time amidst the muffled, maddening
+D:beating of vile drums and the thin monotonous whine of
+D:accursed flutes."
+
+N:853:Huan, Wolfhound of the Valar
+G:C:W
+I:130:90d100:50:160:10
+W:93:2:3400:40000
+E:0:1:0:2:1:0
+O:30:10:60:0
+B:CLAW:COLD:9d12
+B:CLAW:COLD:9d12
+B:BITE:COLD:9d12
+B:BITE:COLD:9d12
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | AURA_COLD |
+F:SMART | OPEN_DOOR | BASH_DOOR | KILL_BODY |
+F:ANIMAL | GOOD |
+F:IM_COLD | IM_ACID | IM_ELEC | BASEANGBAND
+S:1_IN_5 |
+S:BR_COLD | BR_SHAR | BR_SOUN | BR_LITE |
+D:The wolfhound of the Valar, Huan has served many masters in his time, from
+D:Celegorm son of Feanor to Beren son of Barahir: but now he runs wild and
+D:acknowledges no master save himself, as he hunts alone for his nemesis -
+D:Carcharoth, the terrible wolf of Angband.
+
+N:854:Jormungand the Midgard Serpent
+G:J:v
+I:130:120d120:100:200:0
+W:94:1:3000:45000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CRUSH:HURT:20d10
+B:CRUSH:HURT:20d10
+B:BITE:HURT:5d50
+F:UNIQUE | FORCE_MAXHP | FORCE_SLEEP | WILD_TOO | WILD_OCEAN | WILD_SWAMP |
+F:MOVE_BODY | KILL_WALL | IM_FIRE | IM_POIS | IM_ACID | IM_COLD | COLD_BLOOD |
+F:RES_WATE | RES_PLAS | RES_NEXU | NO_STUN | REGENERATE | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | ZANGBAND
+S:1_IN_3
+S:BA_WATE | BR_MANA | BR_NETH | BR_POIS | BR_DISI | S_KIN
+D:The Midgard Serpent is so huge that its body surrounds the world of
+D:mortal men. It could grind even the gods into lifeless pulp.
+
+N:855:The Destroyer
+G:g:v
+I:130:140d140:100:200:0
+W:94:1:0:45000
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:30d9
+B:HIT:HURT:30d9
+B:HIT:HURT:30d9
+B:HIT:HURT:30d9
+F:UNIQUE | NONLIVING | NO_FEAR | FORCE_MAXHP | FORCE_SLEEP | REFLECTING |
+F:MOVE_BODY | KILL_WALL | IM_FIRE | IM_ELEC | IM_POIS | IM_ACID | IM_COLD |
+F:RES_NETH | RES_WATE | RES_PLAS | RES_NEXU | NO_STUN | REGENERATE |
+F:NO_CONF | NO_SLEEP | NO_STUN | CAN_FLY |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | ZANGBAND | NO_CUT
+S:1_IN_3 |
+S:BR_DISI | BO_MANA
+D:The Destroyer was built by the Norse deities to be their ultimate weapon
+D:against the space gods who had arrived to judge the world. Unfortunately,
+D:the Destroyer has gone berserk and is destroying everything it sees. The
+D:mystical Destroyer is nearly indestructible, and it is said that when it
+D:uses its power of complete disintegration, the day of Ragnarok is near.
+
+N:856:Gothmog, the High Captain of Balrogs
+G:U:v
+I:130:120d100:100:140:0
+W:95:1:17000:43000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:FIRE:9d12
+B:HIT:FIRE:9d12
+B:CRUSH:HURT:8d12
+B:TOUCH:UN_POWER
+F:UNIQUE | MALE | CAN_SPEAK | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS | KILL_WALL | AURA_FIRE | NONLIVING |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON |
+F:IM_FIRE | IM_ELEC | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BLIND | CONF | SCARE |
+S:BR_FIRE | S_KIN |
+S:S_HI_DEMON | S_HI_UNDEAD
+D:Gothmog is the Chief Balrog in Morgoth's personal guard. He is renowned
+D:for slaying three High Kings of the Noldor Elves, and he has never been
+D:defeated in combat. With his whip of flame and awesome fiery breath he
+D:saved his master from Ungoliant's rage.
+
+N:857:Great Cthulhu
+G:U:g
+I:130:100d100:100:140:100
+W:97:2:4000:62500
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:CRUSH:HURT:50d4
+B:CLAW:UN_POWER:15d2
+B:CLAW:UN_BONUS:15d2
+B:TOUCH:DISEASE:100d1
+F:UNIQUE | CAN_SPEAK | DEMON | ELDRITCH_HORROR | NONLIVING |
+F:FORCE_SLEEP | FORCE_MAXHP | ESCORT | ESCORTS | SMART | RES_PLAS | RES_NEXU |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | REGENERATE | RES_NETH |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_1D2 | DROP_GOOD |
+F:DROP_GREAT | RES_DISE | RES_TELE | CAN_SWIM |
+F:EVIL | DEMON | IM_FIRE | IM_POIS | IM_ELEC | IM_ACID | NO_CONF | NO_SLEEP |
+F:CTHANGBAND
+S:1_IN_3
+S:TPORT | SCARE | BLIND | MIND_BLAST | BRAIN_SMASH | DRAIN_MANA |
+S:BR_POIS | BR_ACID | BR_FIRE | CONF | DARKNESS | FORGET | S_HI_UNDEAD |
+S:BR_NUKE | BR_NETH | BR_CHAO | BR_DISE | BR_DARK | BR_PLAS | BR_CONF
+S:BR_NEXU | S_HI_DEMON | BR_DISI | HAND_DOOM |
+S:ANIM_DEAD
+D:This creature is death incarnate. "A monster of vaguely anthropoid
+D:outline, but with an octopus-like head whose face was a mass of
+D:feelers, a scaly, rubbery-looking body, prodigious claws on hind
+D:fore feet, and long, narrow wings behind. This thing... was a
+D:somewhat bloated corpulence... It lumbered slobberingly into sight
+D:and gropingly squeezed its gelatinous green immensity through the
+D:black doorway... A mountain shambled or walked."
+
+N:858:Sarko, rider of gold Foronth
+G:B:y
+I:145:99d111:100:165:0
+W:97:6:420000:65000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:12d12
+B:HIT:HURT:12d12
+B:HIT:FIRE:12d12
+B:HIT:FIRE:12d12
+F:UNIQUE | FEMALE | DROP_CORPSE |
+F:ATTR_MULTI | THUNDERLORD | RES_TELE | PET | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | GOOD |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:DROP_CHOSEN | REFLECTING | AURA_FIRE | AURA_ELEC |
+F:SMART | OPEN_DOOR | BASH_DOOR | MOVE_BODY | REGENERATE |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | POWERFUL |
+F:MORTAL | HAS_LITE
+S:1_IN_4 |
+S:TPORT | TELE_TO | BR_FIRE | BR_TIME | S_THUNDERLORD | TELE_AWAY |
+D:Foronth is the first Eagle queen, and Sarko the first to discover
+D:the Firebirds, the ancestor of the Thunderlord eagles. She will try to
+D:help you!
+
+N:859:The Unicorn of Order
+G:q:w
+I:130:66d100:30:170:150
+W:75:2:0:65000
+E:0:1:0:2:1:0
+O:25:50:25:0
+B:KICK:UN_POWER:13d13
+B:KICK:UN_POWER:12d12
+B:BUTT:UN_BONUS:11d11
+B:BITE:TIME:10d10
+F:UNIQUE | FORCE_SLEEP | FORCE_MAXHP | REFLECTING | AURA_COLD |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | KILL_BODY | POWERFUL | BASH_DOOR | REGENERATE | CAN_FLY |
+F:ANIMAL | GOOD | IM_ACID | IM_COLD | IM_ELEC |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_STUN | RES_TELE | ZANGBAND
+S:1_IN_3 |
+S:BR_SOUN | BR_LITE | BR_TIME | BR_SHAR | BR_MANA |
+S:S_MONSTERS | HEAL | S_ANGEL
+D:The Unicorn of Order, who once stole an eye from the great Serpent
+D:of Chaos, regards you as a mortal meddling in the affairs of immortals,
+D:and thus is attempting to eliminate you.
+
+N:860:Sauron, the Sorcerer
+G:p:v
+I:130:100d225:100:160:0
+W:99:1:2300:50000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:10d12
+B:HIT:UN_BONUS:10d12
+B:HIT:UN_POWER:8d12
+B:HIT:UN_POWER:8d12
+F:UNIQUE | MALE | CAN_SPEAK | REFLECTING |
+F:FORCE_SLEEP | FORCE_MAXHP | FORCE_DEPTH |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | OPEN_DOOR | BASH_DOOR | MOVE_BODY | REGENERATE | NO_SLEEP | NO_FEAR | NO_CONF |
+F:EVIL | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_TELE | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:TPORT | TELE_LEVEL | BLIND | CONF | SCARE | CAUSE_4 |
+S:BRAIN_SMASH | FORGET | BO_ICEE | BO_MANA | BO_PLAS |
+S:BA_MANA | BA_FIRE | BA_WATE | BA_NETH | BA_DARK | BA_CHAO |
+S:S_MONSTERS | S_HI_DEMON | S_HI_UNDEAD | S_HI_DRAGON | S_WRAITH | S_UNIQUE |
+S:HAND_DOOM | ANIM_DEAD
+D:Mighty in spells and enchantments, he created the One Ring.
+D:His eyes glow with power and with his gaze he seeks to destroy
+D:your soul. He has many servants, and rarely fights without them.
+
+N:861:DarkGod, the Mighty Coder of Hell
+G:P:B
+I:155:180d100:111:175:0
+W:127:1:1600:66666
+E:2:0:2:6:1:1
+O:20:20:20:20
+B:GAZE:EAT_GOLD:20d10
+B:HIT:SHATTER:20d10
+B:BITE:LOSE_ALL:10d12
+B:TOUCH:UN_POWER
+F:UNIQUE | CAN_SPEAK | ATTR_MULTI | ATTR_ANY | MALE |
+F:FORCE_MAXHP | WEIRD_MIND | DROP_CORPSE | DROP_SKELETON |
+F:REFLECTING | AURA_FIRE | AURA_ELEC | AURA_COLD |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | RES_NETH | INVISIBLE |
+F:SMART | KILL_WALL | KILL_BODY | POWERFUL | RES_TELE |
+F:REGENERATE | CAN_FLY | CAN_SWIM | DG_CURSE | WYRM_PROTECT |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF |NO_FEAR | NO_STUN | RES_TELE
+F:MORTAL | JOKEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:S_THUNDERLORD | BR_CHAO | BA_CHAO | ROCKET | BRAIN_SMASH | S_HI_DEMON |
+S:BR_NETH | HASTE | BR_MANA | S_HI_UNDEAD | S_HI_DRAGON | TRAPS | FORGET |
+S:BR_NUKE | BR_POIS | BR_DISI | HAND_DOOM | HEAL | TPORT | TELE_TO |
+S:S_BUG | S_RNG |
+D:He is the master of coding; none can match his skill. He created the
+D:Variant Maintainer, the RNGs, and the software bugs. Bull Gates is
+D:nothing next to him. Do not think that since he loves the novels of
+D:Tolkien he is to be ignored! He wishes to translate your soul into
+D:assembler, the one hitch being that he must kill you first. If you
+D:encounter him, pray your deity holds you in good stead.
+
+N:862:Morgoth, Lord of Darkness
+G:P:D
+I:140:200d150:100:150:0
+W:100:1:200000:60000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:SHATTER:24d10
+B:HIT:SHATTER:24d10
+B:HIT:LOSE_ALL:10d12
+B:TOUCH:UN_POWER
+F:UNIQUE | CAN_SPEAK | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | FORCE_DEPTH |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | DROP_CHOSEN | RES_NETH |
+F:SMART | KILL_WALL | MOVE_BODY | AURA_COLD |
+F:REGENERATE | POWERFUL |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_STUN | NO_SLEEP | NO_FEAR | RES_TELE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BRAIN_SMASH |
+S:BA_MANA | BO_MANA | BA_NETH | BA_CHAO | BA_DARK | ANIM_DEAD |
+S:S_MONSTERS | S_UNIQUE | S_HI_DEMON | S_HI_UNDEAD | S_HI_DRAGON |
+S:ROCKET | BR_NETH | BR_DISI | HAND_DOOM | S_WRAITH
+D:He was the most powerful of the Valar, the equal of Manwe.
+D:He is the Master of the Pits of Angband. His figure is like a black
+D:mountain crowned with Lightning. He rages with everlasting anger, his
+D:body scarred by Fingolfin's eight mighty wounds. He can never rest from
+D:his pain, but seeks forever to dominate all that is light and good in the
+D:world. He is the origin of man's fear of darkness and created many foul
+D:creatures with his evil powers. Orcs, Dragons, and Trolls are his most
+D:foul corruptions, causing much pain and suffering in the world to please
+D:him. His disgusting visage, twisted with evil, is crowned with iron, the
+D:two remaining Silmarils forever burning him. Grond, the mighty Hammer of
+D:the Underworld, cries defiance as he strides towards you to crush you to a
+D:pulp!
+
+N:863:Human Warrior
+G:p:u
+I:110:9d8:10:10:0
+W:0:20:1700:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:5d8
+F:MALE |
+F:PET | FRIENDS | WILD_ONLY |
+F:ONLY_GOLD | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR
+F:DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:They are used as the main assault force of the human kings.
+D:They will help you in some quests.
+
+N:864:Elven archer
+G:h:W
+I:110:9d7:10:10:0
+W:0:20:1400:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:2d8
+F:MALE |
+F:PET | FRIENDS | WILD_ONLY |
+F:ONLY_GOLD | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR
+F:DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_1 |
+S:ARROW_2 | ARROW_1 | ARROW_2 | ARROW_1 |
+D:They are used as the main assault force of the elven kings.
+D:They will help you in some quests.
+
+N:865:Dwarven warrior
+G:h:U
+I:110:8d8:10:10:0
+W:0:20:1500:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:6d8
+F:MALE |
+F:PET | FRIENDS | WILD_ONLY |
+F:ONLY_GOLD | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR
+F:DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:They are used as the main assault force of the dwarven kings.
+D:They will help you in some quests.
+
+N:866:Elite uruk
+G:o:w
+I:110:10d10:20:50:0
+W:20:1:2000:70
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:8d5
+B:HIT:HURT:8d5
+F:MALE |
+F:FORCE_MAXHP | FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:ARROW_2
+D:It is a cunning orc of power, taller than a man, and stronger. It fears
+D:little.
+
+N:867:The Philosophy Teacher
+G:p:r
+I:120:50d100:30:50:0
+W:56:1:1900:20000
+E:1:1:1:2:1:1
+O:20:20:20:20
+B:GAZE:CONFUSE:15d5
+B:GAZE:PARALYZE:15d5
+B:TOUCH:INSANITY:5d5
+B:TOUCH:EXP_40:5d5
+F:FEMALE | UNIQUE | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD | DROP_GREAT |
+F:CAN_SPEAK | WEIRD_MIND | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | NO_CONF | NO_SLEEP | JOKEANGBAND | HAS_LITE
+S:1_IN_3
+S:BR_CONF | BR_SOUN | BR_CHAO | BR_TIME |
+S:HOLD | SCARE | SLOW | CONF | FORGET
+D:She is a feared teacher, mistress of chaos and strangely minded.
+D:She wants to take your mind. Fear her and flee while you can.
+
+N:868:The Variant Maintainer
+G:p:B
+I:160:10d10:30:50:0
+W:10:1:1700:3000
+E:1:1:1:2:1:1
+O:20:20:20:20
+B:INSULT:*
+B:HIT:INSANITY:1d8
+B:HIT:LOSE_WIS:1d8
+F:ONLY_ITEM | DROP_2D2 | UNIQUE | CAN_FLY |
+F:DROP_GOOD | WEIRD_MIND | CAN_SPEAK |
+F:RAND_50 | RAND_25 | INVISIBLE | EVIL |
+F:MORTAL | JOKEANGBAND | HAS_LITE
+S:1_IN_2
+S:S_BUG | S_RNG | BR_CONF
+D:A deranged programmer, scattering bizarre ideas and bad code everywhere.
+
+N:869:Random Number Generator
+G:I:b
+I:130:1d6:10:50:0
+W:10:1:0:10
+E:0:0:0:0:0:0
+O:20:20:20:20
+B:INSULT:*
+B:MOAN:*
+B:HIT:CONFUSE:1d6
+F:DROP_1D2 | EVIL |
+F:EMPTY_MIND | RAND_50 | RAND_25 | JOKEANGBAND
+S:MULTIPLY
+D:A feared creation of the Variant Maintainer, it tries to generate Morgoth
+D:in the town and the One Ring in the magic shop.
+
+N:870:Rocket mine
+G:.:R
+I:110:20d8:20:3:10
+W:50:10:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:10d5
+F:NEVER_MOVE | IM_POIS | NONLIVING | IM_ACID | STUPID |
+F:FORCE_MAXHP | UNDEAD | EVIL | JOKEANGBAND | NO_CUT
+S:1_IN_4
+S:ROCKET | ARROW_4
+D:It was left here to be used against intruders.
+
+N:871:Bouncing mine
+G:.:B
+I:120:20d15:50:5:10
+W:70:10:0:200
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:10d5
+F:NEVER_MOVE | IM_POIS | NONLIVING | IM_ACID | STUPID |
+F:FORCE_MAXHP | UNDEAD | EVIL | JOKEANGBAND | NO_CUT
+S:1_IN_3
+S:ROCKET | ARROW_4 | BLINK | BR_POIS | BR_CHAO | BR_NEXU
+D:It was left here to be used against intruders.
+
+N:872:Durin's Bane
+G:U:v
+I:130:30d100:20:100:80
+W:50:3:13000:30000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:FIRE:6d12
+B:HIT:FIRE:6d12
+B:CRUSH:HURT:5d12
+B:TOUCH:UN_POWER
+F:UNIQUE | MALE | SPECIAL_GENE | DROP_RANDART
+F:FORCE_SLEEP | FORCE_MAXHP | KILL_WALL |
+F:ESCORT | ESCORTS | DROP_CORPSE | NONLIVING |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_CHOSEN |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON | IM_FIRE |
+F:NO_CONF | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:CONF | SCARE |
+S:BR_FIRE |
+S:S_UNDEAD | S_DEMON
+D:A huge Balrog surrounded by raging pillars of fire, this is indeed a
+D:terrible opponent. Wielding a great whip of fire and a blazing sword, his
+D:fury blisters your skin and melts your flesh!
+
+N:873:The Icky Queen
+G:i:v
+I:120:40d10:20:50:10
+W:20:5:3000:400
+E:0:0:0:0:0:0
+O:40:30:10:10
+B:CRAWL:POISON:3d4
+B:CRAWL:EAT_FOOD:3d4
+B:TOUCH:ACID:3d5
+B:HIT:HURT:3d5
+F:UNIQUE | FEMALE |
+F:FORCE_MAXHP | CAN_SPEAK | SMART | ESCORT | ESCORTS |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_CORPSE |
+F:WEIRD_MIND | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_ELEC | IM_FIRE | IM_COLD | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:DRAIN_MANA | BLIND | CONF | SCARE | S_KIN
+D:And you thought her offspring were icky!
+
+N:874:Rot jelly
+G:j:u
+I:120:20d8:2:30:99
+W:5:1:2000:15
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EAT_FOOD:2d3
+B:TOUCH:LOSE_CHR:2d3
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:HURT_LITE | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a large pile of rotting flesh, whose touch spoils your food. The terrible
+D:smell it exudes is also very hard to get rid of...
+
+N:875:Death
+G:G:D
+I:130:50d100:200:120:5
+W:80:6:3000:25000
+E:1:1:1:2:1:1
+O:10:80:20:0
+B:HIT:HURT:20d5
+B:HIT:HURT:20d5
+B:TOUCH:EXP_80:20d5
+B:TOUCH:EXP_80:20d5
+F:UNIQUE |
+F:FORCE_MAXHP | DROP_CORPSE |
+F:DROP_GOOD | DROP_GREAT | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | PASS_WALL | NO_SLEEP | NO_STUN | NO_CONF |
+F:EVIL | UNDEAD | JOKEANGBAND | NO_CUT
+D:"And I looked, and behold a pale horse: and his name that sat on him was
+D:Death, and Hell followed with him. And power was given unto them over the
+D:fourth part of the earth, to kill with sword, and with hunger, and with
+D:death, and with the beasts of the earth."
+
+N:876:Famine
+G:G:U
+I:130:50d100:200:120:5
+W:77:6:3000:25000
+E:1:1:1:2:1:1
+O:10:80:20:0
+B:TOUCH:EAT_FOOD:20d4
+B:GAZE:UN_BONUS:20d4
+B:WAIL:LOSE_INT:10d5
+B:WAIL:LOSE_DEX:10d5
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | DROP_CORPSE |
+F:DROP_GOOD | DROP_GREAT | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | PASS_WALL | NO_STUN | NO_SLEEP | NO_CONF |
+F:EVIL | UNDEAD | JOKEANGBAND | NO_CUT
+D:One of the horsemen of the apocalypse, before you lies Famine. A
+D:figure so gaunt that the shape of the bones beneath are revealed,
+D:Famine rides a pale grey mare that appears near death.
+
+N:877:Pestilence
+G:G:G
+I:130:50d100:200:120:5
+W:74:6:3000:25000
+E:1:1:1:2:1:1
+O:10:80:20:0
+B:TOUCH:POISON:20d4
+B:TOUCH:POISON:20d4
+B:TOUCH:DISEASE:16d5
+B:TOUCH:DISEASE:16d5
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | DROP_CORPSE |
+F:DROP_GOOD | DROP_GREAT | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | PASS_WALL | NO_SLEEP | NO_STUN | NO_CONF |
+F:EVIL | UNDEAD | JOKEANGBAND | NO_CUT
+S:1_IN_2 |
+S:S_ANT | S_SPIDER
+D:One of the horsemen of the apocalypse, before you lies Pestilence.
+D:At first, it looks like a human, but then you notice ants, worms, and
+D:worse peeking out of the flesh. Pestilence rides a purple horse with
+D:skin that bulges and occasionally gives hints of the vermin within.
+
+N:878:War
+G:G:r
+I:130:50d100:200:120:5
+W:71:6:3000:25000
+E:1:1:1:2:1:1
+O:10:80:20:0
+B:TOUCH:PARALYZE:20d4
+B:WAIL:CONFUSE:20d4
+B:GAZE:BLIND:20d4
+B:WAIL:TERRIFY:20d4
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | DROP_CORPSE |
+F:DROP_GOOD | DROP_GREAT | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | PASS_WALL | NO_SLEEP | NO_STUN | NO_CONF | NO_FEAR |
+F:EVIL | UNDEAD | JOKEANGBAND | NO_CUT
+S:1_IN_2 |
+S:S_MONSTER
+D:One of the horsemen of the apocalypse, before you lies War. A healthy and
+D:hearty warrior, War grins a little too wide at you as he prepares for
+D:combat. War rides a large well-groomed yellow horse that leaves behind
+D:puddles of blood where its hooves touch the ground.
+
+##### Some aquatic monsters. #####
+
+N:879:Pike
+G:~:s
+I:125:2d7:80:35:0
+W:2:1:100:7
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:2d3
+F:ANIMAL | AQUATIC | STUPID | DROP_CORPSE | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:It's a common fresh-water predatory fish.
+
+N:880:Electric eel
+G:J:B
+I:110:15d15:15:40:70
+W:20:2:500:145
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:TOUCH:ELEC:2d7
+B:TOUCH:ELEC:2d7
+B:TOUCH:ELEC:2d7
+F:AQUATIC | ANIMAL | RAND_25 | IM_ELEC | RES_WATE |
+F:WILD_TOO | WILD_OCEAN | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:This serpentine creature can create a deadly voltage. Better watch out!
+
+N:881:Giant crayfish
+G:~:R
+I:90:4d10:6:100:20
+W:4:1:1200:10
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d4
+B:CLAW:HURT:3d4
+F:ANIMAL | AQUATIC | STUPID | WEIRD_MIND | DROP_CORPSE | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A man-sized, heavily armoured fresh-water relative of the lobster.
+
+N:882:Mermaid
+G:h:G
+I:110:5d8:50:30:0
+W:4:1:1600:20
+E:1:1:1:2:1:0
+O:20:50:10:5
+B:TOUCH:LOSE_WIS
+B:TOUCH:INSANITY:2d3
+B:TOUCH:CONFUSE
+F:FEMALE | RAND_25 | DROP_60 | SMART | AQUATIC | NO_CONF | DROP_CORPSE |
+F:MORTAL | ZANGBAND
+D:A green-skinned humanoid with a fishtail. Beware - there are rumours
+D:of adventures losing their minds under the fearsome
+D:charms of mermaids.
+
+N:883:Box jellyfish
+G:~:B
+I:110:10d10:20:30:75
+W:10:2:3000:25
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:PARALYZE:1d6
+B:TOUCH:PARALYZE:1d6
+F:ANIMAL | AQUATIC | IM_POIS | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A strange water creature, whose touch can be deadly.
+
+N:884:Giant piranha
+G:~:g
+I:120:6d8:30:20:10
+W:10:2:300:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:5d1
+B:BITE:HURT:5d1
+F:NO_SLEEP | WILD_TOO | COLD_BLOOD |
+F:FRIENDS | AQUATIC | ANIMAL |
+F:MORTAL | BASEANGBAND
+D:A very large and bloodthirsty fish.
+
+N:885:Piranha
+G:~:g
+I:120:2d6:20:8:5
+W:3:1:200:8
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:FRIENDS | AQUATIC | ANIMAL | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:Bloodthirsty fish who can smell your blood from a great distance.
+
+N:886:Bullywug
+G:h:g
+I:110:6d10:20:15:0
+W:7:1:700:25
+E:1:1:1:2:1:1
+O:30:40:10:10
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:MALE | ONLY_ITEM | DROP_1D2 | SMART | AQUATIC | DROP_CORPSE | FRIENDS |
+F:MORTAL | BASEANGBAND | HAS_LITE | COLD_BLOOD
+D:A vaguely humanoid creature, it looks like a cross between a hobbit and a
+D:frog.
+
+N:887:Bullywug warrior
+G:h:g
+I:110:8d10:20:15:0
+W:8:1:750:35
+E:1:1:1:2:1:1
+O:15:60:10:10
+B:HIT:HURT:2d5
+B:HIT:HURT:2d5
+F:MALE | ONLY_ITEM | DROP_1D2 | SMART | AQUATIC | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE | COLD_BLOOD
+D:A member of the frog-people clan. He is wielding a long, sharp shark tooth.
+
+N:888:Bullywug shaman
+G:h:g
+I:110:6d10:20:15:0
+W:8:1:800:35
+E:1:1:1:2:1:1
+O:25:10:50:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:MALE | ONLY_ITEM | DROP_1D2 | SMART | AQUATIC | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE | COLD_BLOOD
+S:1_IN_5 |
+S:BLIND | CONF | DARKNESS | BO_COLD | HEAL | MISSILE | CAUSE_2
+D:A leader of a clan of frog-people, he is cloaked in a cloak made of
+D:shark skin.
+
+N:889:Whale
+G:~:G
+I:110:22d22:15:50:70
+W:20:4:9000:175
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CRUSH:HURT:1d20
+B:CRUSH:HURT:1d20
+F:RAND_25 | FORCE_MAXHP | RES_WATE |
+F:ANIMAL | AQUATIC | WILD_TOO |
+F:MORTAL | BASEANGBAND
+D:Although it looks like a fish and lives in water, it is in fact
+D:a mammal. And it is huge!
+
+N:890:Sand mite
+G:~:B
+I:110:3d10:5:25:80
+W:10:2:500:25
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:POISON:3d6
+B:BITE:POISON:3d6
+F:AQUATIC | ANIMAL | IM_POIS | FRIENDS |
+F:CHAR_CLEAR | ATTR_CLEAR | DROP_CORPSE | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY
+D:A relative of crabs and shrimp, this is a tiny creature that inhabits sandy
+D:bottoms. It has a pair of dangerous-looking claws.
+
+N:891:Octopus
+G:~:g
+I:105:60d6:60:60:60
+W:15:2:1200:60
+E:3:0:3:6:1:0
+O:0:0:0:0
+B:SPIT:BLIND:1d3
+B:CRUSH:HURT:6d3
+B:CRUSH:HURT:6d3
+B:CRUSH:HURT:6d3
+F:RAND_25 | IM_COLD | RES_WATE | AQUATIC | ANIMAL | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:It doesn't move very fast, but when it does - watch out!
+
+N:892:Giant octopus
+G:~:g
+I:115:100d6:10:35:5
+W:30:1:1800:180
+E:3:0:3:6:1:0
+O:0:0:0:0
+B:SPIT:BLIND:1d4
+B:CRUSH:HURT:8d4
+B:CRUSH:HURT:8d4
+B:CRUSH:PARALYZE:8d4
+F:AQUATIC | SMART | IM_POIS | ANIMAL | NO_CONF | NO_SLEEP |
+F:NO_FEAR | SMART | WEIRD_MIND | DROP_CORPSE | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+S:1_IN_15 |
+S:DARKNESS | SLOW | CONF | SCARE
+D:A cunning and dangerous undersea opponent.
+
+N:893:Eye of the deep
+G:e:b
+I:120:16d100:10:20:40
+W:40:3:1600:6000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:EXP_20:2d6
+B:GAZE:UN_POWER:2d6
+B:GAZE:INSANITY:2d6
+B:BITE:HURT:6d6
+F:EVIL | IM_POIS | NO_CONF | NO_SLEEP | AQUATIC |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | RES_TELE |
+F:SMART | DROP_CORPSE | BASEANGBAND
+S:1_IN_2 |
+S:BLIND | SLOW | CONF | SCARE | DRAIN_MANA | MIND_BLAST |
+S:FORGET | DARKNESS | BO_WATE | BO_ICEE | BO_MANA | BO_COLD
+D:A beholder that inhabits the depths of the sea, sleeping and pondering
+D:alien thoughts for centuries. Occasionally, it will float to the
+D:surface to wreck the lives of surface dwellers.
+
+N:894:Murk dweller
+G:S:s
+I:110:200d5:70:30:0
+W:27:3:3000:800
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:5d10
+B:CLAW:PARALYZE
+B:STING:INSANITY:5d10
+B:STING:UN_BONUS
+F:AQUATIC | ANIMAL | WEIRD_MIND | FORCE_MAXHP | HURT_LITE |
+F:EVIL | SMART | NO_CONF | NO_SLEEP | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BA_POIS | BR_DARK | BLIND | BR_POIS | SLOW | CONF | MIND_BLAST |
+S:BRAIN_SMASH | DARKNESS
+D:A gigantic aquatic monster, somewhat resembling a cross between a
+D:lobster and a spider. It is coated in poisonous slime and noxious
+D:parasites. This foul creature hides in the silt of the deep ocean floor,
+D:waiting to trap unsuspecting prey.
+
+N:895:Drowned soul
+G:G:B
+I:110:9d8:5:33:50
+W:11:1:0:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:BLIND:3d3
+B:TOUCH:POISON:2d4
+B:WAIL:TERRIFY
+F:COLD_BLOOD | EMPTY_MIND | EVIL | AQUATIC | UNDEAD | IM_COLD | INVISIBLE |
+F:IM_POIS | NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_8
+S:BLIND | HOLD | CONF
+D:A ghastly victim of drowning, forever doomed to wander the ocean waters
+D:looking for revenge.
+
+N:896:Tiger shark
+G:~:g
+I:120:10d5:100:32:0
+W:12:1:3000:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:4d4
+F:RAND_25 | AQUATIC | ANIMAL | STUPID | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A small species of shark, although the teeth are still as deadly.
+
+N:897:Hammerhead shark
+G:~:g
+I:115:16d10:20:59:20
+W:16:3:1500:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:BUTT:HURT:3d4
+B:BITE:HURT:3d4
+F:ANIMAL | AQUATIC | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A hungry shark with a strange head.
+
+N:898:Great white shark
+G:~:w
+I:120:100d6:20:70:20
+W:24:2:5000:250
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:4d6
+B:BITE:HURT:4d6
+B:BITE:HURT:4d6
+F:FORCE_SLEEP | AQUATIC | COLD_BLOOD |
+F:ANIMAL MORTAL | BASEANGBAND
+D:A very large carnivorous fish.
+
+N:899:Aquatic golem
+G:g:b
+I:100:25d10:35:75:10
+W:19:1:0:100
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:3d10
+B:HIT:HURT:3d10
+F:COLD_BLOOD | EMPTY_MIND | AQUATIC |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:An ingenious gnomish invention -- a golem designed for underwater
+D:usage.
+
+N:900:Aquatic kobold
+G:k:B
+I:110:13d9:10:30:15
+W:5:1:1500:35
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d10
+F:DROP_90 | EVIL | IM_POIS | AQUATIC | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:Yes, your favourite denizen of evil also comes in an aquatic variety.
+
+N:901:White shark
+G:~:W
+I:120:30d10:20:50:10
+W:18:1:3000:100
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:3d5
+B:BITE:HURT:3d5
+B:BITE:HURT:3d5
+F:ANIMAL | AQUATIC | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A fast-moving hunter of the depths. When this creature moves,
+D:everybody in the water is in danger!
+
+N:902:Scrag
+G:T:B
+I:110:40d10:20:50:50
+W:35:1:5000:440
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:HIT:HURT:3d2
+B:HIT:HURT:3d2
+F:MALE |
+F:FORCE_MAXHP | AQUATIC | REGENERATE |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_OCEAN |
+F:OPEN_DOOR | BASH_DOOR | RES_WATE |
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | BASEANGBAND
+D:A troll of the sea, he reeks of brine.
+
+N:903:Jaws
+G:~:w
+I:130:100d20:200:80:70
+W:40:2:7000:2000
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:11d2
+B:BITE:HURT:22d1
+B:BITE:HURT:11d2
+B:BITE:HURT:22d1
+F:FORCE_MAXHP | UNIQUE | MOVE_BODY |
+F:WILD_OCEAN | WILD_TOO | COLD_BLOOD |
+F:BASH_DOOR | IM_COLD | IM_ELEC | IM_POIS | ANIMAL | AQUATIC |
+F:NO_CONF | NO_SLEEP |
+F:MORTAL | ZANGBAND
+D:The biggest white shark who has ever lived, it is hunting for you now!
+
+N:904:Aquatic elf
+G:h:b
+I:110:14d8:30:30:6
+W:9:1:1400:25
+E:1:1:1:2:1:0
+O:20:20:50:10
+B:HIT:HURT:3d4
+F:MALE | AQUATIC | SMART | DROP_CORPSE |
+F:FRIENDS | DROP_60 | ZANGBAND | HAS_LITE
+D:A sleek form vaguely shaped like a dolphin, except with a humanoid
+D:head and arms. The facial features are decidedly elven.
+
+N:905:Aquatic elven warrior
+G:h:b
+I:110:20d8:40:35:5
+W:10:1:1500:35
+E:1:1:1:2:1:0
+O:20:60:10:10
+B:HIT:HURT:4d4
+B:HIT:HURT:4d4
+F:MALE | AQUATIC | FRIENDS | SMART | DROP_60 | DROP_CORPSE | ZANGBAND |
+F:HAS_LITE
+D:An aquatic elf trained in all forms of combat.
+
+N:906:Aquatic elven shaman
+G:h:b
+I:110:12d8:30:30:6
+W:10:1:1400:35
+E:1:1:1:2:1:0
+O:10:10:70:10
+B:TOUCH:UN_BONUS
+F:MALE | AQUATIC | SMART | DROP_2D2 | DROP_CORPSE | ZANGBAND |
+F:HAS_LITE
+S:1_IN_12 |
+S:BO_MANA | BO_COLD | S_MONSTERS
+D:A wizened aquatic elf skilled in the magical arts. You can see an
+D:iridescent film coating the water around him.
+
+N:907:Stargazer
+G:~:y
+I:100:15d9:10:25:30
+W:21:1:800:60
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:GAZE:PARALYZE
+F:AQUATIC | ANIMAL | SMART | RAND_25 | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:S_MONSTER
+D:A giant fish shaped like a flounder. There are two enormous eyes
+D:occupying half of the creature's body.
+
+N:908:Elder stargazer
+G:~:y
+I:100:20d10:15:25:30
+W:29:1:1000:75
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:GAZE:PARALYZE
+B:GAZE:CONFUSE
+F:AQUATIC | ANIMAL | SMART | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:S_MONSTERS
+D:A stargazer a bit larger than average, covered with barnacles.
+
+N:909:Flounder
+G:~:s
+I:100:10d5:5:25:30
+W:13:1:700:55
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:2d6
+F:AQUATIC | ANIMAL | RAND_25 | INVISIBLE | ATTR_CLEAR | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A flattened fish which is able to change body colouring for
+D:camouflage.
+
+N:910:Giant turtle
+G:R:G
+I:110:5d8:10:14:30
+W:7:1:3000:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d2
+B:BITE:HURT:2d2
+F:ANIMAL | AQUATIC | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A giant turtle with flippers, adapted for life in the ocean.
+
+N:911:Baby dragon turtle
+G:d:W
+I:110:10d10:20:60:50
+W:9:1:20000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:EVIL | DRAGON | AQUATIC | BASEANGBAND | ATTR_MULTI
+S:1_IN_12 |
+S:BR_SOUN
+D:A newly-hatched dragon turtle. It still hasn't grown a proper shell.
+
+N:912:Young dragon turtle
+G:d:W
+I:110:30d10:20:70:70
+W:31:1:80000:700
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_3D2 |
+F:EVIL | DRAGON | AQUATIC | BASEANGBAND | ATTR_MULTI
+S:1_IN_11 |
+S:SCARE |
+S:BR_SOUN
+D:A dragon-like creature inhabiting lightless reaches of ocean caves. It has
+D:a long neck with a tiny head, and four massive flippers. It has a soft and
+D:flexible shell.
+
+N:913:Mature dragon turtle
+G:d:W
+I:110:50d10:20:80:70
+W:38:1:170000:1500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d10
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_4D2 |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | AQUATIC | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_SOUN
+D:A large dragon turtle, covered with a tough white shell.
+
+N:914:Ancient dragon turtle
+G:D:W
+I:120:70d10:20:90:80
+W:41:1:220000:2500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:HURT:7d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_1D2 | DROP_4D2 |
+F:SMART | AQUATIC | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_9 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN
+D:A huge dragon turtle. You can see many barnacles covering its body.
+
+N:915:Fastitocalon
+G:D:g
+I:120:40d100:25:150:30
+W:52:3:250000:16000
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:BITE:HURT:5d8
+B:BITE:HURT:5d8
+B:CRUSH:POISON:3d10
+B:CRUSH:POISON:3d10
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:IM_FIRE | IM_ACID | IM_COLD | IM_POIS |
+F:DRAGON | NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:BR_FIRE | BR_ACID | BR_SOUN | BA_WATE
+D:A huge aquatic dragon-turtle, its shell is as large as a small island.
+
+N:916:Undead stargazer
+G:~:y
+I:100:18d9:10:25:30
+W:25:1:0:100
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:GAZE:PARALYZE
+B:GAZE:EXP_20
+F:AQUATIC | ANIMAL | SMART | INVISIBLE | UNDEAD | BASEANGBAND | NO_CUT
+S:1_IN_10 |
+S:S_UNDEAD | S_MONSTER
+D:A stargazer brought back from the dead under control of some unholy
+D:sorceror.
+
+N:917:Killer whale
+G:~:w
+I:120:20d50:12:55:30
+W:25:1:9500:85
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:7d4
+B:BITE:HURT:7d4
+F:AQUATIC | WILD_TOO | WILD_OCEAN |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:An almost beautiful, deadly beast.
+
+N:918:Merrow
+G:O:B
+I:110:30d9:20:33:30
+W:28:2:2300:80
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:FRIENDS | DROP_60 | DROP_CORPSE | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:OPEN_DOOR | BASH_DOOR | RES_WATE | IM_COLD | IM_POIS |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A great ogre of the sea, it is violent and stupid.
+
+N:919:Water naga
+G:n:B
+I:110:30d10:10:55:10
+W:24:1:1600:60
+E:0:0:0:0:1:0
+O:40:0:50:10
+B:CRUSH:HURT:2d8
+B:CRUSH:HURT:2d8
+B:BITE:POISON:1d8
+B:BITE:POISON:1d8
+F:FEMALE |
+F:AQUATIC | DROP_CORPSE |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 |
+F:EVIL | NO_CONF | NO_SLEEP | SMART |
+F:MORTAL | BASEANGBAND
+S:1_IN_7 |
+S:DARKNESS | CAUSE_3 | BO_ICEE
+D:A naga adapted to underwater life. She has a fish-like tail and a pair
+D:of gills.
+
+N:920:Devilfish
+G:~:s
+I:105:10d5:10:10:5
+W:12:1:900:60
+E:0:0:0:0:1:0
+O:0:0:0:0
+F:NEVER_BLOW | ATTR_MULTI | AQUATIC | NO_CONF | DROP_CORPSE |
+F:MORTAL | ZANGBAND
+S:1_IN_4 |
+S:BR_CHAO | BR_LITE | BR_SOUN | BR_DISE | BR_TIME
+D:A disgusting fish, it has a large gaping mouth and a small lantern dangling
+D:from an outgrowth on its head.
+
+N:921:Undead devilfish
+G:~:D
+I:105:10d5:10:10:5
+W:15:1:0:75
+E:0:0:0:0:1:0
+O:0:0:0:0
+F:NEVER_BLOW | ATTR_MULTI | AQUATIC | INVISIBLE | NO_CONF | UNDEAD |
+F:ZANGBAND | NO_CUT
+S:1_IN_4 |
+S:BR_NETH | BR_DISE | BR_TIME | BR_NEXU | BR_POIS
+D:A devilfish brought back from the dead.
+
+N:922:Moby Dick, the White Whale
+G:~:w
+I:120:100d25:200:80:70
+W:50:2:10000:2500
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CRUSH:HURT:10d10
+B:CRUSH:HURT:10d10
+B:CRUSH:HURT:10d10
+B:CRUSH:HURT:10d10
+F:FORCE_MAXHP | UNIQUE | MOVE_BODY |
+F:WILD_OCEAN | WILD_TOO | COLD_BLOOD |
+F:BASH_DOOR | IM_COLD | IM_ELEC | IM_POIS | ANIMAL | AQUATIC |
+F:MORTAL | JOKEANGBAND
+S:1_IN_6 | BA_WATE
+D:The mightiest whale of the seas, he has sunk many ships in his time. With
+D:a mere flick of his tail he can create a mighty whirlpool, to the ruin
+D:of all who would travel the ocean.
+
+N:923:Aquatic hound
+G:Z:B
+I:110:15d5:60:60:0
+W:20:1:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:CONFUSE:2d8
+B:BITE:HURT:2d8
+B:CLAW:POISON:2d8
+F:FRIENDS | DROP_CORPSE |
+F:ANIMAL | AQUATIC |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BO_ICEE | BO_WATE
+D:A dog with a finned tail and large, muscular flippers for hind legs.
+D:It has a rubbery skin instead of fur.
+
+N:924:Water demon
+G:U:B
+I:110:35d20:30:50:10
+W:40:1:0:1000
+E:0:0:0:0:1:0
+O:20:60:20:0
+B:HIT:HURT:3d4
+B:GAZE:POISON:8d12
+B:CLAW:INSANITY:8d12
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:FRIENDS | SMART |
+F:ONLY_ITEM | DROP_60 |
+F:AQUATIC | POWERFUL |
+F:EVIL | DEMON | IM_ACID | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:BO_ICEE | BA_WATE
+D:A hideous scaled demon, it is a sleek form with many fins but no visible
+D:arms or legs. It has a toothed gaping maw, reminiscent of a caricature
+D:of a shark's jaws.
+
+N:925:Ixitxachitl
+G:~:s
+I:110:12d8:20:30:20
+W:12:1:1600:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:STING:POISON:2d5
+B:STING:POISON:2d5
+F:ANIMAL | EVIL | AQUATIC | IM_POIS | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:An intelligent devil-ray of the depths.
+
+N:926:Ixitxachitl priest
+G:~:s
+I:110:10d10:20:40:20
+W:19:1:1600:80
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:STING:POISON:2d7
+B:STING:POISON:2d7
+F:ANIMAL | EVIL | AQUATIC | IM_POIS | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+S:1_IN_6
+S:TELE_TO | HEAL | SCARE | CAUSE_2 | BLIND | S_MONSTER
+D:A devil-ray of the depths, with priestly magic.
+
+N:927:Vampiric ixitxachitl
+G:~:D
+I:110:15d15:20:50:20
+W:26:1:1800:120
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:STING:POISON:3d8
+B:STING:EXP_40:3d8
+F:ANIMAL | EVIL | AQUATIC | RES_NETH | IM_POIS | WILD_TOO |
+F:BASEANGBAND | COLD_BLOOD
+S:1_IN_6
+S:HEAL | SCARE | CAUSE_3 | BLIND | FORGET | HASTE
+D:A devil-ray of the depths, with vampiric powers.
+
+N:928:Mathilde, the Science Student
+G:h:y
+I:110:220d100:40:10:3
+W:0:4:1100:0
+E:0:1:1:2:1:1
+O:20:20:20:20
+F:UNIQUE | FEMALE | CAN_SPEAK | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_MAXHP | WILD_TOWN | WILD_ONLY | RAND_25
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:OPEN_DOOR | DG_CURSE |
+F:MORTAL | JOKEANGBAND | HAS_LITE
+D:She loves joking, and she's constantly giggling. A very happy girl.
+D:Beware, it is rumoured that Dark God has put a mighty curse on her.
+
+
+N:929:Child spirit
+G:G:W
+I:120:5d5:8:15:10
+W:5:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:3d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:930:Young spirit
+G:G:W
+I:120:8d8:8:15:10
+W:10:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:9d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:931:Mature spirit
+G:G:W
+I:120:16d16:8:15:10
+W:40:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:18d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:932:Experienced spirit
+G:G:W
+I:120:18d18:8:15:10
+W:60:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:20d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:933:Wise spirit
+G:G:W
+I:120:25d25:8:15:10
+W:90:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:30d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:934:Fangorn the Treebeard, Lord of the Ents
+G:#:G
+I:120:50d100:30:120:15
+W:52:3:6000:15500
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:CRUSH:HURT:13d13
+B:CRUSH:HURT:13d13
+B:CRUSH:HURT:13d13
+B:CRUSH:HURT:13d13
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | CAN_SPEAK | SUSCEP_FIRE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY | DROP_CORPSE |
+F:SMART | TAKE_ITEM | BASH_DOOR | KILL_WALL | NO_SLEEP |
+F:GOOD | PET | BASEANGBAND | NO_CUT
+D:The first being to awoke on Arda, apart from the Valar themselves. He is the
+D:first, oldest, greatest and most respected of all the Ents: and though he is
+D:slow to anger, he is a terrible foe when roused.
+
+N:935:Gandalf the Grey
+G:p:s
+I:120:49d101:101:100:0
+W:60:7:1600:35000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+B:HIT:TERRIFY:5d5
+B:HIT:TERRIFY:5d5
+F:UNIQUE | MALE | CAN_SPEAK | PET | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | REFLECTING | RES_TELE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:GOOD | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | HASTE | TPORT | TELE_AWAY | BLIND | CONF | SCARE |
+S:CAUSE_4 | BRAIN_SMASH | FORGET | TRAPS |
+S:BA_FIRE | BO_FIRE | BO_PLAS | BO_MANA | CAUSE_4 |
+S:S_MONSTERS | S_ANGEL | S_DRAGON | S_KIN
+D:The wizard who opposed Sauron and, in the end, was the only
+D:one of the Istari to succeed in his task. Gandalf is very
+D:wise and specialises in fire magic.
+
+N:936:Nar, the Dwarf
+G:h:y
+I:110:45d10:25:70:25
+W:17:2:1400:250
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | FORCE_SLEEP |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_POIS |
+F:DROP_CORPSE | DROP_SKELETON | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL | BLIND | CONF | CAUSE_2 | MIND_BLAST
+D:The friend and companion of the dwarven king Thror, he went mad with
+D:grief after Thror's death at the hands of Azog the Orc. With torn beard
+D:and ragged clothes, he seems to have fixed on you as a convenient target
+D:to vent his anger.
+
+N:937:Novice mindcrafter
+G:p:y
+I:110:6d8:20:10:5
+W:8:1:900:18
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | WILD_TOO | FRIENDS |
+F:OPEN_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE | NO_CONF | NO_SLEEP
+S:1_IN_12 | BLIND | SLOW | CONF | SCARE
+D:A novice in the arts of mind over matter.
+
+N:938:Great Swamp Wyrm
+G:D:g
+I:120:40d100:30:150:80
+W:63:2:190000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:POISON:6d14
+B:BITE:POISON:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_POIS
+D:A truly enormous dragon with great powers. The foul gases issuing
+D:from the beast nearly make you vomit; and while you may try to hold
+D:your breath as you fight it, it sees no reason to do likewise.
+
+N:939:Great Bile Wyrm
+G:D:s
+I:120:50d100:30:150:80
+W:67:2:190000:23000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:ACID:6d14
+B:BITE:ACID:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | IM_ACID | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_ACID
+D:A huge and very powerful dragon. Great steaming pools of acid drip from
+D:its form onto the ground. You shudder when you see the acid eating away
+D:the very stones of the dungeon - what could it do to you?
+
+N:940:Blue Firebird
+G:B:B
+I:120:4d5:8:15:10
+W:5:3:100:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d4
+B:CLAW:FIRE:5d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:941:Green Firebird
+G:B:G
+I:120:4d5:10:15:10
+W:7:3:110:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:4d4
+B:CLAW:FIRE:5d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:942:Brown Firebird
+G:B:u
+I:120:5d5:10:15:10
+W:10:3:120:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:5d4
+B:CLAW:FIRE:7d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:943:Bronze Firebird
+G:B:U
+I:120:6d5:15:15:10
+W:13:3:130:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:6d4
+B:CLAW:FIRE:7d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:944:Gold Firebird
+G:B:y
+I:120:6d5:20:15:10
+W:15:3:140:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:6d4
+B:CLAW:FIRE:8d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:945:High-elven ranger
+G:h:G
+I:120:50d30:20:70:0
+W:40:3:1400:500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:10d8
+B:HIT:HURT:10d8
+F:MALE | FRIENDS | OPEN_DOOR | BASH_DOOR |
+F:GOOD | DROP_SKELETON | DROP_CORPSE | SMART | PET |
+F:IM_ACID | IM_COLD | RES_WATE | RES_NETH |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:ARROW_4
+D:An elf cloaked in green wielding a longbow.
+
+N:946:Uvatha the Horseman
+G:W:D
+I:120:24d100:90:60:10
+W:40:13:0:10000
+E:0:0:0:0:0:0
+O:30:30:30:10
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:EXP_80:4d6
+B:HIT:EXP_80:4d6
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | NAZGUL |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | DROP_CHOSEN |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | SPECIAL_GENE | NO_CUT
+D:A tall black Ringwraith, he is a master of horsemanship. He longs
+D:to taste your blood.
+
+N:947:Adunaphel the Quiet
+G:W:D
+I:120:27d100:90:60:10
+W:43:13:0:13000
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:TOUCH:EXP_80:5d6
+B:TOUCH:EXP_80:5d6
+F:UNIQUE | FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP | NAZGUL | DROP_CHOSEN |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | MOVE_BODY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | FORGET |
+S:BO_ACID | BO_FIRE | BO_COLD | BO_NETH |
+S:S_MONSTER
+D:A sorceress in life, Adunaphel quickly fell under Sauron's sway and the
+D:power of the rings.
+
+N:948:Akhorahil the Blind
+G:W:D
+I:120:30d100:90:70:10
+W:45:13:0:15000
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:HIT:HURT:7d6
+B:HIT:HURT:7d6
+B:GAZE:EXP_80:6d6
+B:WAIL:TERRIFY:6d6
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | NAZGUL | DROP_CHOSEN |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | DARKNESS |
+S:BO_FIRE | BO_COLD | BO_NETH |
+S:S_MONSTERS
+D:A mighty sorcerer king, Akhorahil was blind in life. With powerful
+D:enchantments, he created jewelled eyes that enabled him to see better than
+D:any ordinary man ever could.
+
+N:949:Ren the Unclean
+G:W:D
+I:120:35d100:90:70:10
+W:48:13:0:18000
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:HIT:HURT:7d7
+B:HIT:HURT:7d7
+B:TOUCH:EXP_80:6d7
+B:WAIL:TERRIFY:6d7
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | NAZGUL | DROP_CHOSEN |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | BO_FIRE | BO_NETH | BA_FIRE |
+S:S_MONSTER
+D:Ren was an insane eastern king who believed himself to be the son of a
+D:volcano god. At an early age his sanity was destroyed by a plague that
+D:wiped out his family, and he never recovered.
+
+N:950:Ji Indur Dawndeath
+G:W:D
+I:120:40d100:90:70:10
+W:52:13:0:22000
+E:0:0:0:0:0:0
+O:30:30:30:10
+B:HIT:HURT:8d7
+B:HIT:HURT:8d7
+B:TOUCH:EXP_40:6d7
+B:TOUCH:EXP_40:6d7
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | NAZGUL | DROP_CHOSEN |
+F:INVISIBLE | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 |
+S:BA_FIRE | BA_NETH | BA_COLD | BA_ELEC | BA_ACID |
+S:S_UNDEAD
+D:This Ringwraith was a weak-minded sorcerer-king who fell easily under
+D:Sauron's power.
+
+N:951:Dwar, Dog Lord of Waw
+G:W:D
+I:120:45d100:90:90:10
+W:56:13:0:25000
+E:0:1:0:2:1:0
+O:30:30:30:10
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+B:BITE:EXP_40:6d7
+B:WAIL:TERRIFY:6d7
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | NAZGUL | DROP_CHOSEN |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | BA_FIRE | BA_NETH |
+S:S_MONSTERS | S_UNDEAD | S_HOUND
+D:Dwar had a special affinity for dogs in life, and can still command them
+D:at will. He howls manically as he reaches out to destroy you.
+
+N:952:Hoarmurath of Dir
+G:W:D
+I:130:60d100:90:100:10
+W:64:13:0:30000
+E:0:0:0:0:0:0
+O:30:30:30:10
+B:HIT:HURT:9d9
+B:HIT:HURT:9d9
+B:TOUCH:EXP_80:6d7
+B:WAIL:TERRIFY:6d7
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NAZGUL | DROP_CHOSEN |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | MIND_BLAST |
+S:BO_COLD | BA_COLD | BA_NETH |
+S:S_UNDEAD
+D:A Ringwraith powerful in fell sorcery, he yearns for the life he has
+D:exchanged for an unlife of everlasting torment.
+
+N:953:Khamul, the Black Easterling
+G:W:D
+I:130:70d100:90:100:10
+W:72:13:2600:40000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:9d10
+B:HIT:HURT:9d10
+B:TOUCH:EXP_80:7d7
+B:TOUCH:EXP_80:7d7
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | NAZGUL | DROP_CHOSEN |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_ACID | IM_FIRE | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | RES_TELE | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:TELE_LEVEL | BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | BO_MANA |
+S:BA_FIRE | BA_COLD | BA_NETH | ANIM_DEAD |
+S:S_HI_UNDEAD | S_KIN
+D:He was the warrior-king of the East, now a Ringwraith. Khamul is a powerful opponent, his skill in
+D:combat awesome and his form twisted by evil cunning.
+
+N:954:The Witch-King of Angmar
+G:W:D
+I:130:90d100:90:120:10
+W:80:14:1800:60000
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:EXP_80:7d7
+B:HIT:EXP_80:7d7
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | NAZGUL |
+F:EVIL | UNDEAD | DROP_CHOSEN |
+F:IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:TELE_AWAY | BLIND | HOLD | SCARE | CAUSE_3 | BRAIN_SMASH |
+S:BO_MANA | BA_NETH | S_WRAITH |
+S:S_KIN | S_HI_UNDEAD | S_HI_DRAGON | S_MONSTERS | ANIM_DEAD
+D:The Chief of the Ringwraiths. A fell being of devastating power, his
+D:spells are lethal and his combat blows crushingly hard. He moves at
+D:speed, and commands legions of evil to do his bidding. It is said that he
+D:is fated never to die by the hand of mortal man.
+
+N:955:Green Thunderlord
+G:B:g
+I:120:50d50:20:100:50
+W:30:4:30000:10000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+F:FEMALE |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE |
+S:BLINK | TELE_AWAY
+D:A Thunderlord. Among the weaker breeds, but still dangerous.
+
+N:956:Blue Thunderlord
+G:B:b
+I:120:60d60:20:100:50
+W:40:4:30000:20000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:8d7
+B:HIT:HURT:8d7
+F:MALE | SMART |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE |
+S:TPORT | BLINK
+D:A Thunderlord. Among the weaker breeds, but still dangerous.
+
+N:957:Brown Thunderlord
+G:B:u
+I:130:70d70:30:100:50
+W:50:4:30000:20000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:8d9
+B:HIT:HURT:8d9
+F:MALE | SMART |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE |
+S:TPORT | BLINK
+D:A Thunderlord. Beware its flame.
+
+N:958:Bronze Thunderlord
+G:B:U
+I:130:80d80:30:100:50
+W:60:5:30000:20000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:10d9
+B:HIT:HURT:10d9
+F:MALE | SMART |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE | BR_TIME |
+S:TPORT | BLINK
+D:A Thunderlord, mightiest among the males.
+
+N:959:Gold Thunderlord
+G:B:y
+I:130:90d90:30:100:50
+W:70:5:30000:20000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:10d9
+B:HIT:HURT:10d9
+B:HIT:HURT:10d9
+B:HIT:HURT:10d9
+F:FEMALE | SMART |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE | BR_TIME |
+S:TPORT | BLINK | TELE_TO | TELE_AWAY |
+S:S_THUNDERLORD
+D:A Thunderlord, among the queens of their kind.
+
+N:960:Blood Sprout
+G:,:g
+I:140:3d5:10:1:0
+W:50:1:50:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:HURT:3d15
+B:TOUCH:HURT:3d15
+B:TOUCH:HURT:3d15
+B:TOUCH:HURT:3d15
+F:STUPID | EMPTY_MIND | KILL_TREES |
+F:IM_POIS | IM_ELEC | IM_ACID | IM_COLD |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL
+S:MULTIPLY
+D:A kind of giant mycorrhiza, corrupted into a carnivore by Morgoth.
+
+N:961:Gorlim, Betrayer of Barahir
+G:p:s
+I:120:16d100:20:120:40
+W:41:3:1800:7000
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:HAS_LITE
+S:1_IN_2 |
+S:CAUSE_3 | BO_WATE | BO_MANA
+D:This sad creature - once a mighty warrior - betrayed his former friends to
+D:Morgoth's army in return for, he thought, safety for himself and his wife.
+D:And so he fell under Morgoth's power and became little more than a mindless
+D:servant of evil, even though the other side of his "bargain" was not kept.
+
+N:962:The Blubbering idiot, agent of black market, Simon the weak
+G:t:W
+I:110:5d11:10:16:0
+W:5:1:1500:50
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:2d5
+B:TOUCH:EAT_ITEM
+B:TOUCH:INSANITY:2d5
+B:TOUCH:INSANITY:2d5
+F:MALE | DROP_CORPSE | DROP_SKELETON | WILD_TOO |
+F:RAND_25 | UNIQUE | STUPID | MALE | FORCE_MAXHP |
+F:TAKE_ITEM | CAN_SPEAK | CAN_SWIM | EVIL |
+F:MORTAL | JOKEANGBAND | HAS_LITE
+S:1_IN_8
+S:SHRIEK
+D:He tends to blubber a lot, he was a simple blubbering idiot before he lost
+D:himself in the dungeon and fell under Morgoth's will.
+D:Now he is a mindless servant of Morgoth. Destroy him - if you can...
+
+N:963:Aranea
+G:S:r
+I:120:20d10:20:45:50
+W:30:2:1000:250
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:POISON:2d8
+B:CLAW:POISON:2d8
+B:BITE:POISON:2d6
+B:BITE:POISON:2d6
+F:DROP_SKELETON | FORCE_MAXHP | FRIENDS |
+F:OPEN_DOOR | BASH_DOOR | HURT_LITE |
+F:ANIMAL | SPIDER | EVIL | IM_POIS | BASEANGBAND
+S:1_IN_4
+S:BO_FIRE | SLOW | HOLD | CAUSE_3 | MISSILE
+D:A red arachnid with legs weaving spells in the air.
+
+N:964:Elder aranea
+G:S:v
+I:120:30d20:20:65:50
+W:40:3:1800:2500
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:POISON:5d8
+B:CLAW:POISON:5d8
+B:BITE:HALLU:5d6
+B:BITE:HALLU:5d6
+F:DROP_SKELETON | FORCE_MAXHP |
+F:OPEN_DOOR | BASH_DOOR | HURT_LITE | SMART |
+F:ANIMAL | SPIDER | EVIL | IM_FIRE | IM_POIS | BASEANGBAND
+S:1_IN_6
+S:SLOW | HOLD | DRAIN_MANA | MIND_BLAST | HEAL |
+S:BA_FIRE | BO_FIRE | CAUSE_3 | S_SPIDER
+D:A vast, bloated arachnid, master of its brood: among the more terrible of
+D:Ungoliant's descendants, this is a monster such as those who haunted the dread
+D:valley of Nan Dungortheb long ago.
+
+N:965:Giant brown tick
+G:S:u
+I:110:16d8:12:50:20
+W:25:2:400:27
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:2d6
+B:STING:BLIND:1d1
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY |
+F:ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+D:It is moving slowly towards you.
+
+N:966:Wavelord
+G:p:b
+I:120:16d100:30:120:40
+W:61:3:1800:7000
+E:1:1:1:2:1:1
+O:20:50:10:5
+B:HIT:HURT:8d9
+B:HIT:COLD:8d9
+B:HIT:HURT:8d9
+B:HIT:COLD:8d9
+F:SMART | PET | DROP_CORPSE | FRIENDS | WILD_SHORE | WILD_OCEAN | WILD_TOO |
+F:IM_POIS | AQUATIC | CAN_SWIM | DROP_USEFUL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | DROP_GOOD | DROP_3D2 |
+F:MORTAL | REGENERATE | TAKE_ITEM | GOOD | SUSCEP_FIRE |
+F:RES_WATE | RES_NEXU | HAS_LITE
+S:1_IN_4
+S:BO_WATE | BA_WATE | BO_ICEE
+D:The Dolphiners came with the Thunderlords from their far home.
+D:These friendly beings ride their sharks into combat to assist you.
+
+N:967:Novice possessor (soul)
+G:G:D
+I:110:1d1:30:1:10
+W:10:3:10:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:SMART | POSSESSOR |
+F:BASEANGBAND | NO_CUT
+D:It does not look that powerful.
+
+N:968:Bat of Gorgoroth
+G:b:g
+I:120:20d10:20:30:30
+W:28:3:150:100
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:POISON:1d10
+B:CLAW:HURT:1d4
+F:DROP_60 | RAND_25 | MOVE_BODY | CAN_FLY | DROP_CORPSE |
+F:BASH_DOOR | MOVE_BODY | FRIENDS | WEIRD_MIND |
+F:ANIMAL | IM_POIS | AI_ANNOY | MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:SCARE | BR_POIS | BR_DARK
+D:Fed with horrid meats and grown to enormous size, this slavering creature
+D:seeks livelier prey.
+
+N:969:The Princess
+G:p:y
+I:110:1d1:40:250:3
+W:0:4:730:0
+E:0:1:1:2:1:1
+O:0:0:1:0
+F:FEMALE | CAN_SPEAK
+F:FORCE_MAXHP | SPECIAL_GENE | NO_TARGET
+F:NEVER_MOVE | NEVER_BLOW | GOOD | NO_DEATH | RES_TELE
+F:MORTAL | BASEANGBAND | UNIQUE | PET |
+D:The princess of an unknown kingdom, you need to save her!
+
+N:970:Merton Proudfoot, the lost hobbit
+G:h:v
+I:110:1d1:40:250:3
+W:1:1:730:0
+E:0:1:1:2:1:1
+O:0:0:0:1
+F:MALE | CAN_SPEAK
+F:FORCE_MAXHP | SPECIAL_GENE
+F:NEVER_MOVE | NEVER_BLOW | GOOD | NO_TARGET
+F:MORTAL | BASEANGBAND | UNIQUE | PET | NO_DEATH
+D:The poor hobbit got lost in the dreadful maze!
+
+N:971:The Wight-King of the Barrow-downs
+G:W:v
+I:120:38d22:30:45:0
+W:46:3:0:22000
+E:0:0:0:0:0:0
+O:15:55:15:0
+B:HIT:HURT:2d10
+B:WAIL:PARALYZE:2d6
+B:TOUCH:EXP_80:4d8
+B:TOUCH:EXP_80:4d8
+F:SPECIAL_GENE | FORCE_MAXHP | SMART | CAN_SPEAK |
+F:DROP_4D2 | DROP_2D2 | COLD_BLOOD | UNIQUE |
+F:CAN_SWIM | CAN_FLY | EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:HOLD | SCARE | CAUSE_3 | BA_NETH
+D:He has lived in the Barrow-Downs for centuries after his first death at the
+D:hands of the Witch-King of Angmar. A once loyal captain under the
+D:Witch-King's command, he now awaits a time when his undead forces shall
+D:rise again to avenge their deaths.
+
+N:972:Adventurer
+G:@:U
+I:115:3d20:50:50:10
+W:0:3:100:0
+O:50:50:0:0
+B:HIT:HURT:2d6
+B:PUNCH:HURT:1d7
+B:KICK:HURT:1d8
+F:SPECIAL_GENE | SMART | OPEN_DOOR
+F:FORCE_MAXHP | CAN_SWIM | BASEANGBAND |
+F:NO_SLEEP | NO_CONF
+D:A great warrior.
+
+N:973:Experienced possessor (soul)
+G:G:D
+I:120:5d5:30:50:10
+W:30:3:10:0
+O:0:0:0:0
+F:SMART | POSSESSOR |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9
+S:S_KIN
+D:It does not look that powerful.
+
+N:974:Old possessor (soul)
+G:G:D
+I:130:10d10:30:100:10
+W:95:3:10:0
+O:0:0:0:0
+F:SMART | POSSESSOR |
+F:BASEANGBAND | NO_CUT
+S:1_IN_4
+S:S_KIN
+D:It does not look that powerful.
+
+N:975:Death orb
+G:E:D
+I:130:40d100:255:75:0
+W:80:5:10:5000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:PARASITE:20d10
+B:ENGULF:ACID:6d5
+B:ENGULF:EXP_80:6d5
+B:ENGULF:LOSE_ALL:6d5
+F:FORCE_MAXHP | ZANGBAND | KILL_ITEM | KILL_WALL | KILL_BODY |
+F:NONLIVING | COLD_BLOOD | EMPTY_MIND | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_STUN | REGENERATE |
+F:IM_ACID | IM_FIRE | IM_ELEC | IM_COLD | IM_POIS |
+F:RES_NETH | RES_PLAS | RES_WATE | RES_DISE | RES_NEXU |
+F:DEATH_ORB | NO_CUT
+D:A small, apparently unassuming orb which spawns death and destruction.
+
+N:976:Bronze dragon worm
+G:w:U
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_CONF |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_CONF
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Its scales glitter in
+D:a multitude of perplexing and distracting ways.
+
+N:977:Gold dragon worm
+G:w:y
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_STUN |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_SOUN
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. You can feel the air itself
+D:vibrating as you near it.
+
+N:978:Moldoux, the Defenceless Mold
+G:m:v
+I:100:1d1:1:1:0
+W:1:1:20:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:NEVER_MOVE | UNIQUE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | FORCE_DEPTH |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | WYRM_PROTECT | ONLY_DEPTH | JOKEANGBAND | NO_CUT
+D:A small strange growth. It seems to be defenceless...
+
+N:979:The Physics Teacher
+G:p:w
+I:120:65d100:30:120:15
+W:62:3:100000:13500
+E:1:1:1:2:1:1
+O:20:20:20:20
+B:TOUCH:LOSE_INT:13d13
+B:TOUCH:LOSE_WIS:13d13
+B:GAZE:PARALYZE
+B:WAIL:EXP_80
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SPEAK | DROP_CORPSE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:PASS_WALL | MOVE_BODY | AURA_FIRE |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | ANIMAL | DEMON | UNDEAD | JOKEANGBAND | NO_CUT
+S:1_IN_3
+S:BR_FIRE | BR_PLAS | BR_TIME | BA_WATE | ROCKET |
+S:FORGET
+D:A keeper of forbidden wisdom, this Teacher bombards you with his mastery
+D:over elements of matter.
+
+N:980:Ar-Pharazon the Golden
+G:p:y
+I:130:50d100:30:45:255
+W:55:1:0:2500
+E:1:1:1:2:1:1
+O:20:70:10:0
+B:HIT:HURT:8d12
+B:HIT:HURT:8d12
+B:HIT:HURT:8d12
+B:HIT:HURT:8d12
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | CAN_SPEAK | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD | DROP_SKELETON | DROP_CORPSE |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | MOVE_BODY | BASEANGBAND |
+F:HAS_LITE | AQUATIC
+S:1_IN_6 |
+S:HEAL | HASTE | TELE_AWAY | S_MONSTERS | S_KIN
+D:Last and proudest king of ancient Numenor. Corrupted by power and
+D:avarice, he fell victim to Sauron's wiles, tried to fight the immortals
+D:themselves, and condemned Numenor to oblivion.
+
+N:981:Doppelganger
+G:@:w
+I:1:1d1:1:1:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:NEVER_MOVE | NEVER_BLOW | DOPPLEGANGER | BASEANGBAND | HAS_LITE
+D:It looks like you...
+
+N:982:Marylene, Heartbreakeress of the Netherworld
+G:P:W
+I:155:200d120:155:175:0
+W:127:1:1600:66666
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:GAZE:PARALYZE:20d15
+B:HIT:EXP_80:20d17
+B:BITE:LOSE_ALL:10d12
+B:TOUCH:INSANITY:12d9
+F:UNIQUE | CAN_SPEAK | ATTR_MULTI | ATTR_ANY | FEMALE |
+F:FORCE_MAXHP | WEIRD_MIND | DROP_CORPSE | DROP_SKELETON |
+F:REFLECTING | AURA_FIRE | AURA_ELEC | AURA_COLD |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | RES_NETH | INVISIBLE |
+F:SMART | KILL_WALL | KILL_BODY | POWERFUL | RES_TELE |
+F:REGENERATE | CAN_FLY | CAN_SWIM | WYRM_PROTECT |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_STUN | RES_TELE | DEMON |
+F:MORTAL | DG_CURSE | JOKEANGBAND | HAS_LITE
+S:1_IN_1 |
+S:BR_CHAO | BA_CHAO | BRAIN_SMASH | SHRIEK | BR_CONF | BR_SOUN |
+S:BR_NETH | HASTE | TRAPS | FORGET | BR_DISE | BR_TIME | MIND_BLAST |
+S:HEAL | TPORT | TELE_TO | CAUSE_1 | CAUSE_2 | CAUSE_3 | CAUSE_4 | BLIND |
+S:CONF | SLOW | HOLD | S_ANGEL | S_UNIQUE
+D:A woman of mind-shattering beauty, none can match her beauty. She is perfect,
+D:and totally evil. She loves nothing but herself and her evil is as
+D:great as her beauty. No one can stand against her, even DarkGod.
+D:As you see her approaching, you feel your heart breaking.
+D:She is the perfection, don't even try against her; you will surely lose
+D:your mind...
+
+N:983:The Greater Lag Monster
+G:U:v
+I:110:60d100:40:10:3
+W:95:4:730:0
+E:0:0:0:0:0:0
+O:40:40:0:10
+B:GAZE:PARALYZE:20d15
+B:HIT:HURT:15d10
+B:TOUCH:EXP_80:10d5
+B:TOUCH:EAT_ITEM
+F:RAND_50 | TAKE_ITEM | FORCE_MAXHP | UNIQUE |
+F:DROP_3D2 | DROP_GOOD | DROP_GREAT | WYRM_PROTECT |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_STUN | RES_TELE | DEMON |
+F:EVIL | WEIRD_MIND | RES_NETH | INVISIBLE |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | JOKEANGBAND | NO_CUT
+S:1_IN_2
+S:CONF | SHRIEK | BR_CONF | BR_TIME | BR_INER | BR_GRAV | BRAIN_SMASH |
+S:SCARE | BLIND | SLOW | HOLD | HASTE | HEAL | TELE_TO | FORGET |
+S:S_HI_DEMON | S_MONSTERS | S_HYDRA | S_HI_DRAGON | S_HI_UNDEAD | S_ANGEL |
+S:S_HOUND | S_UNIQUE |
+D:It is even worse than the RNG, coming from Mangband,
+D:it seeks to crush you to pulp... and surely can.
+
+N:984:Hrungnir, the Stone Giant
+G:P:W
+I:130:99d110:50:160:20
+W:78:2:0:45000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:SHATTER:9d11
+B:HIT:SHATTER:9d11
+B:HIT:HURT:9d11
+B:HIT:HURT:9d11
+F:UNIQUE | SUSCEP_ACID | HURT_ROCK |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | RES_NETH | RES_PLAS | MALE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | EVIL |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | TAKE_ITEM | CAN_SPEAK |
+F:EVIL | IM_FIRE | IM_POIS | GIANT |
+F:ZANGBAND | HAS_LITE | NO_CUT
+S:1_IN_5 |
+S:BR_WALL | BR_GRAV | BR_SHAR | BLIND | TELE_TO | S_KIN | S_MONSTERS |
+S:HAND_DOOM | TELE_AWAY |
+D:Hrungnir is the strongest of all the Stone Giants: one who would even dare
+D:to challenge Thor himself to single combat.
+
+N:985:Bullroarer the Hobbit
+G:h:U
+I:120:6d10:16:8:10
+W:5:3:1000:90
+E:1:1:1:2:1:1
+O:25:55:0:20
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is a sturdy hobbit who is renowned for his unusual strength and
+D:vigour. He can prove a troublesome opponent.
+
+N:986:3-headed hydra
+G:M:o
+I:120:100d5:20:65:20
+W:20:2:4500:350
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP | CAN_SWIM |
+F:DROP_CORPSE | DROP_SKELETON | ONLY_GOLD | DROP_2D2 |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_9 |
+S:SCARE
+D:A strange reptilian creature with three heads, guarding its hoard.
+
+N:987:Uldor the Accursed
+G:p:U
+I:110:10d100:20:70:40
+W:28:4:2000:600
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 | S_KIN
+D:An evil and cunning man from the East. Having once sworn allegiance to the
+D:sons of Feanor, it was Uldor's treachery that turned the tide of the Battle
+D:of Unnumbered Tears in Morgoth's favour.
+
+N:988:Mystic
+G:p:o
+I:120:35d10:30:50:5
+W:33:3:1400:500
+E:1:1:1:2:1:1
+O:30:0:60:10
+B:KICK:HURT:10d2
+B:KICK:HURT:10d2
+B:KICK:HURT:10d2
+B:KICK:HURT:10d2
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_1D2 |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_POIS | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL |
+S:S_SPIDER | S_ANIMAL
+D:An adept at unarmed combat, the mystic strikes with stunning power. He
+D:can summon help from nature and is able to focus his power to ease any
+D:pain.
+
+N:989:Elder vampire
+G:V:r
+I:120:34d100:20:90:10
+W:54:3:1700:4500
+E:1:1:1:2:1:1
+O:0:70:30:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:BITE:EXP_80:5d6
+B:BITE:EXP_80:5d6
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_60 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | RES_TELE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | DARKNESS | BO_NETH | S_UNDEAD
+D:A terrible robed undead figure, this creature has existed in its
+D:unlife for many centuries by stealing the life of others. It can
+D:summon the very shades of its victims from beyond the grave to
+D:come enslaved to its aid.
+
+N:990:Ulfang the Black
+G:p:U
+I:120:25d100:20:90:40
+W:44:5:2100:1200
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:5d8
+B:HIT:HURT:5d8
+B:HIT:HURT:5d8
+B:HIT:HURT:5d8
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_MAXHP | IM_FIRE | IM_COLD | IM_ELEC | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_RANDART
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 | S_KIN | S_MONSTERS
+D:A short and swarthy Easterling dressed in black. He and his three sons
+D:once openly swore allegiance to the High Elves, but were secretly in the
+D:pay of Morgoth.
+
+N:991:Demonologist
+G:p:R
+I:120:28d10:20:50:10
+W:36:2:1100:700
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON
+F:RES_NETH | RES_NEXU |
+F:ONLY_ITEM | DROP_1D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:TPORT | HOLD |
+S:S_DEMON | BO_FIRE
+D:A figure twisted by evil standing in robes of deepest crimson.
+
+N:992:Hezrou
+G:U:g
+I:110:52d10:20:40:80
+W:41:3:2100:2500
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:FORCE_SLEEP | FORCE_MAXHP | FRIENDS
+F:ONLY_ITEM | DROP_2D2 |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | NONLIVING
+F:BASEANGBAND
+S:1_IN_9 |
+S:BO_FIRE |
+S:S_DEMON
+D:It is a demon of lizard form with cruel-looking jaws.
+
+N:993:Glabrezu
+G:U:U
+I:110:70d10:20:40:80
+W:43:2:2300:3000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | NONLIVING |
+F:BASEANGBAND
+S:1_IN_9 |
+S:BO_FIRE |
+S:S_DEMON
+D:It is a demon with arms and pincers, its form a true mockery of life.
+
+N:994:Nalfeshnee
+G:U:r
+I:110:90d10:20:50:80
+W:45:2:6000:5000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE
+F:ONLY_ITEM | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON |
+F:IM_FIRE | NO_CONF | NO_SLEEP | NONLIVING
+F:BASEANGBAND
+S:1_IN_9 |
+S:BLIND | CONF |
+S:BR_FIRE |
+S:S_DEMON
+D:It is a large demon with the head of a giant boar. Flames run up and down
+D:its length.
+
+N:995:Marilith
+G:U:y
+I:120:20d70:20:75:80
+W:47:2:3000:7000
+E:3:0:3:4:1:0
+O:0:50:50:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | NONLIVING |
+F:BASEANGBAND
+S:1_IN_9 |
+S:BLIND | CAUSE_2 |
+S:S_DEMON
+D:She is a demon of female form with many arms, each bearing deadly weapons.
+
+N:996:Lesser Balrog
+G:U:v
+I:120:20d100:20:50:80
+W:49:2:9000:10000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:FIRE:4d12
+B:HIT:FIRE:4d12
+B:CRUSH:HURT:3d12
+B:TOUCH:UN_POWER
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE | KILL_WALL |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | NONLIVING |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLIND | CONF |
+S:BR_FIRE |
+S:S_DEMON
+D:It is a massive humanoid demon wreathed in flames.
+
+N:997:Master mystic
+G:p:o
+I:130:11d100:30:60:5
+W:50:3:1600:6000
+E:1:1:1:2:1:1
+O:40:0:40:20
+B:KICK:HURT:10d2
+B:KICK:HURT:10d2
+B:HIT:POISON:20d1
+B:HIT:PARALYZE:15d1
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL |
+S:S_SPIDER | S_ANIMALS
+D:A lord of all that is natural, skilled in the mystic ways. He is a master
+D:of martial arts and is at one with nature, able to summon help from the
+D:wild if need be.
+
+N:998:Grand master mystic
+G:p:o
+I:130:22d100:30:80:5
+W:57:3:1800:15000
+E:1:1:1:2:1:1
+O:40:0:40:20
+B:KICK:HURT:20d2
+B:KICK:HURT:10d2
+B:HIT:POISON:20d1
+B:HIT:PARALYZE:15d1
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_4D2 |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | MIND_BLAST |
+S:S_SPIDER | S_HOUND | S_ANIMALS
+D:He is one of the few true masters of the art, being extremely skillful in
+D:all forms of unarmed combat and controlling the world's natural creatures
+D:with disdainful ease.
+
+N:999:Erinyes
+G:U:u
+I:110:24d10:20:50:80
+W:38:2:0:1000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:3d4
+B:TOUCH:LOSE_STR:1d5
+F:FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON |
+F:IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP |
+F:BASEANGBAND
+S:1_IN_7 |
+S:BLIND | CONF | BO_FIRE
+D:It is a lesser demon of female form; however, she takes little time to
+D:show her true colours.
+
+N:1000:Novice mindcrafter
+G:p:y
+I:110:6d8:20:10:5
+W:4:1:900:18
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | WILD_TOO |
+F:OPEN_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE | NO_CONF | NO_SLEEP
+S:1_IN_9 | BLIND | SLOW | CONF | SCARE
+D:A novice in the arts of mind over matter.
+
+N:1001:Polyphemus, the Blind Cyclops
+G:P:g
+I:130:65d100:40:140:40
+W:69:3:40000:29000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:11d10
+B:HIT:SHATTER:11d10
+B:HIT:HURT:11d10
+B:HIT:SHATTER:11d10
+F:UNIQUE | MALE | BASEANGBAND | HAS_LITE | CAN_SWIM |
+F:FORCE_SLEEP | FORCE_MAXHP | RAND_25 | DROP_CORPSE |
+F:DROP_2D2 | DROP_3D2 | DROP_GOOD | ONLY_ITEM | KILL_ITEM |
+F:BASH_DOOR | KILL_BODY |
+F:EVIL | GIANT | IM_ACID | IM_POIS | IM_FIRE | IM_COLD |
+S:1_IN_5 |
+S:BO_WATE | BA_WATE | BO_ICEE | BA_ACID | ARROW_4
+D:No ordinary cyclops, but the son of a sea-god: he wields the powers of
+D:elemental water as well as the considerable strength of a cyclops. His
+D:one eye was blinded long ago by the warrior Odysseus, but he has trained
+D:himself to hear so well that it nearly makes up for his disability.
+
+N:1002:Great Wyrm of Perplexity
+G:D:U
+I:120:40d100:30:150:80
+W:63:2:190000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:CONFUSE:6d14
+B:BITE:CONFUSE:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_CONF
+D:A dragon of great size and power. Its polished bronze scales reflect the
+D:light in strange and confusing patterns, and you find it hard to keep your
+D:mind on the job of fighting for your life.
+
+N:1003:Hound of Tindalos
+G:Z:s
+I:120:60d15:30:100:0
+W:59:3:600:8000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:TIME:2d12
+B:BITE:TIME:2d12
+B:CLAW:HURT:2d12
+B:CLAW:HURT:2d12
+F:FORCE_SLEEP | FRIENDS | RES_NETH |
+F:INVISIBLE | PASS_WALL | EVIL | CAN_FLY |
+F:ANIMAL | NO_CONF | NO_SLEEP | CTHANGBAND
+S:1_IN_5 | BLINK | TELE_TO |
+S:BR_NETH | BR_TIME
+D:"They are lean and athirst!... All the evil in the universe
+D:was concentrated in their lean, hungry bodies. Or had they
+D:bodies? I saw them only for a moment, I cannot be certain."
+
+N:1004:Great Wyrm of Thunder
+G:D:y
+I:120:50d100:30:150:80
+W:67:2:190000:23000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:HURT:6d14
+B:BITE:HURT:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | NO_STUN | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN
+D:A dragon of gigantic proportions, with destructive abilities to match. The
+D:sheer loudness of its roar leaves you stunned and unable to think clearly
+D:enough to defend yourself adequately.
+
+N:1005:Silver mouse
+G:r:W
+I:110:1d3:8:4:20
+W:4:1:200:1
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:EAT_LITE:1d2
+F:RAND_25 | CAN_SWIM | ANIMAL |
+F:DROP_CORPSE | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is about three feet long with large teeth. As the light of your lamp falls
+D:on it, it seems to grow stronger.
+
+N:1006:The Rat King
+G:r:v
+I:120:20d12:30:30:0
+W:18:1:950:32
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:3d2
+B:CLAW:HURT:3d2
+B:BITE:DISEASE:4d2
+B:BITE:DISEASE:4d2
+F:UNIQUE | ESCORT | ESCORTS | FORCE_MAXHP |
+F:BASH_DOOR | ANIMAL | NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND
+D:A massive rat. He's the leader of the pack.
+
+N:1007:Vort the Kobold Queen
+G:k:v
+I:110:12d10:20:20:20
+W:7:3:1000:100
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+F:UNIQUE | FEMALE | CAN_SPEAK |
+F:FORCE_MAXHP |
+F:ESCORT | ESCORTS | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_6 | MISSILE | HEAL | CAUSE_1 | CONF
+D:Where Mughash is the strongest of his kind, his consort Vort is the
+D:wisest: she is her tribe's chief shamaness.
+
+N:1008:Giant black louse
+G:I:D
+I:120:1d2:6:7:10
+W:14:1:100:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | RAND_25 | CAN_FLY | WEIRD_MIND |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is six inches long.
+
+N:1009:Fire Phantom
+G:G:r
+I:120:10d100:20:90:40
+W:34:5:0:1200
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:HIT:HURT:5d5
+F:UNIQUE | MALE | CAN_SPEAK
+F:FORCE_MAXHP | UNDEAD | NO_CONF | NO_SLEEP | REGENERATE | NO_STUN |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | PASS_WALL |
+F:MORTAL | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6
+S:BR_FIRE | HOLD | CONF | SCARE | MIND_BLAST
+D:He's back from the grave for vengeance on those who
+D:burnt him. He has no mercy for those in his way.
+
+N:1010:The Insane Player
+G:p:v
+I:120:18d100:25:100:10
+W:36:2:1500:1200
+E:1:1:1:2:1:1
+O:20:20:20:20
+B:HIT:HURT:3d8
+F:UNIQUE | MALE | CAN_SPEAK | ATTR_MULTI |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | RAND_25 |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR
+F:JOKEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:TELE_TO | SHRIEK | SCARE
+D:Once a powerful adventurer, this poor fighter has seen a few too many
+D:software bugs in his time. Any shred of lucidity is long gone, but
+D:he still remains dangerous. He wanders aimlessly through the dungeon
+D:randomly striking at foes both real and imagined, all the while screaming
+D:out at the world that caused his condition.
+
+N:1011:Glaryssa, Succubus Queen
+G:U:W
+I:120:12d100:90:60:10
+W:41:3:3000:8000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:CLAW:HURT:5d5
+B:HIT:LOSE_STR:4d4
+B:TOUCH:EXP_80:8d3
+F:UNIQUE | FEMALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | NO_SLEEP | NO_CONF
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | PASS_WALL | MOVE_BODY | NONLIVING |
+F:OPEN_DOOR | BASH_DOOR | IM_POIS | IM_COLD | DEMON | EVIL |
+F:ZANGBAND
+S:1_IN_3 |
+S:CAUSE_3 | HOLD | BLIND | BO_ACID | S_DEMON |
+S:FORGET | BO_NETH | MIND_BLAST | DARKNESS
+D:Drop dead gorgeous - literally.
+
+N:1012:Vermicious Knid
+G:j:s
+I:110:90d10:20:55:100
+W:44:2:1400:2100
+E:0:0:0:0:0:0
+O:40:30:20:10
+B:TOUCH:TERRIFY:4d6
+B:CRAWL:HURT:4d6
+B:ENGULF:HURT:4d6
+F:FRIENDS | EVIL | IM_COLD | SMART |
+F:COLD_BLOOD | NO_FEAR | WEIRD_MIND |
+F:OPEN_DOOR | ONLY_ITEM | DROP_2D2 | HURT_ROCK |
+F:NONLIVING |
+F:JOKEANGBAND | NO_CUT
+D:An amorphous shape that looks like wet grey clay with two pale eyes.
+D:It is totally silent as it oozes towards you.
+
+N:1013:Bone golem
+G:g:w
+I:120:35d100:20:170:50
+W:61:3:5000:23000
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:UN_BONUS:8d8
+B:HIT:UN_BONUS:8d8
+B:HIT:LOSE_STR:6d6
+B:HIT:LOSE_STR:6d6
+F:FORCE_SLEEP | FORCE_MAXHP | EMPTY_MIND |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | IM_FIRE | IM_ELEC | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:TELE_TO | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | BA_NETH | S_HI_UNDEAD
+D:A skeletal form, black as night, constructed from the bones of its
+D:previous victims.
+
+N:1014:Snake of Yig
+G:J:b
+I:120:48d10:25:80:30
+W:38:4:2000:600
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:POISON:3d12
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:RAND_25 | FRIENDS | AURA_FIRE |
+F:BASH_DOOR | MOVE_BODY | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | HAS_EGG | EVIL | IM_FIRE | IM_POIS |
+F:MORTAL | ZANGBAND
+S:1_IN_5 |
+S:BR_POIS
+D:It is a giant snake that drips with poison.
+
+N:1015:Bronze golem
+G:g:o
+E:2:1:2:4:1:1
+O:0:0:0:0
+I:120:40d100:25:170:50
+W:65:3:5500:26000
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:FORCE_MAXHP | FORCE_SLEEP | EMPTY_MIND | COLD_BLOOD |
+F:OPEN_DOOR | BASH_DOOR | IM_FIRE | IM_ELEC | IM_POIS | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BO_PLAS | BA_FIRE | BR_FIRE | BA_ELEC | S_HI_DEMON | TELE_TO
+D:A gigantic four-armed animated bronze statue, glowing with great heat.
+
+N:1016:Dimensional shambler
+G:h:B
+I:120:40d10:30:68:255
+W:29:6:1100:400
+E:0:0:0:0:0:0
+O:20:40:40:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:FORCE_MAXHP | FORCE_SLEEP | NO_FEAR | GOOD |
+F:ONLY_ITEM | DROP_2D2 | NONLIVING |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | RES_TELE |
+F:CTHANGBAND
+S:1_IN_3 |
+S:HEAL | HASTE | BLIND | CONF | SCARE | TPORT | BLINK
+D:A shabby humanoid with a wrinkled skin. It seems to shift
+D:in and out of existence as you watch.
+
+N:1017:Cultist
+G:p:G
+I:110:14d8:20:22:40
+W:17:1:1500:36
+E:1:1:1:2:1:1
+O:10:0:90:0
+B:HIT:HURT:4d3
+F:MALE |
+F:FORCE_SLEEP |
+F:DROP_1D2 | EVIL |
+F:DROP_SKELETON | DROP_CORPSE |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | CTHANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | SCARE | CAUSE_2 |
+S:S_MONSTER | MIND_BLAST
+D:A robed humanoid dedicated to a demonic outer god.
+
+N:1018:Cult leader
+G:p:G
+I:120:52d14:20:60:10
+W:47:2:1800:1800
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:HIT:HURT:6d4
+B:HIT:HURT:6d4
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:DROP_SKELETON | DROP_CORPSE |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:MORTAL | CTHANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | BLIND | HOLD | CONF | CAUSE_3 |
+S:S_MONSTER | S_UNDEAD | S_DEMON | BA_CHAO | BRAIN_SMASH
+D:An evil priest, dressed all in black and devoted to one of the netherworld
+D:demons that call themselves "the outer gods".
+
+N:1019:Servitor of the outer gods
+G:H:y
+I:130:100d35:30:140:255
+W:41:6:2100:15000
+E:0:0:0:0:0:0
+O:10:20:70:0
+B:GAZE:TERRIFY:4d4
+B:HIT:HURT:8d6
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | NO_FEAR | REFLECTING |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NONLIVING |
+F:RES_TELE | ELDRITCH_HORROR | SHAPECHANGER | ATTR_MULTI |
+F:CTHANGBAND
+S:1_IN_3 |
+S:TELE_TO | BLIND | SCARE | CAUSE_2 | CAUSE_4 | BO_MANA |
+S:S_UNDEAD
+D:"Toad-like creatures which seemed constantly to be changing shape and
+D:appearance, and from whom emanated, by some means I could not distinguish,
+D:a ghostly ululation, a piping." August Derleth - "The Lurker at The
+D:Threshold".
+
+N:1020:Avatar of Nyarlathotep
+G:p:R
+I:120:25d25:20:70:20
+W:45:2:0:500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:5d5
+F:IM_POIS | IM_FIRE | IM_ELEC | IM_ACID | IM_COLD |
+F:NO_SLEEP | NO_FEAR | SHAPECHANGER | ELDRITCH_HORROR | NONLIVING |
+F:MALE | OPEN_DOOR | BASH_DOOR |
+F:CTHANGBAND | HAS_LITE
+D:The Crawling Chaos with a thousand forms. Nyarlathotep is amused at your
+D:puny attempts to kill him, and will keep coming back for another go
+D:until he gets bored with the game.
+
+N:1021:Thiazi, the Storm Giant
+G:P:B
+I:130:99d110:50:160:20
+W:78:2:0:45000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:ELEC:9d11
+B:HIT:HURT:9d11
+B:HIT:ELEC:9d11
+B:HIT:HURT:9d11
+F:UNIQUE | SUSCEP_COLD | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | RES_NETH | RES_PLAS | MALE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | EVIL | AURA_ELEC |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | TAKE_ITEM | CAN_SPEAK |
+F:EVIL | IM_FIRE | IM_POIS | SUSCEP_COLD | GIANT | DEMON
+F:ZANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BR_ELEC | BR_PLAS | BR_MANA | BLIND | TELE_TO | S_KIN | S_HI_DRAGON |
+S:HAND_DOOM | TELE_AWAY
+D:Thiazi is the greatest of all the Storm Giants: when travelling, he takes
+D:the form of a giant eagle. It was he who succeeded in kidnapping Iduna and
+D:her apples of youth from Asgard itself.
+
+N:1022:Hypnos, Lord of Sleep
+G:p:G
+I:130:51d99:20:150:10
+W:67:2:5000:36000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:TOUCH:LOSE_ALL:2d25
+B:GAZE:PARALYZE:1d20
+B:GAZE:TERRIFY:1d20
+B:GAZE:BLIND:1d20
+F:UNIQUE | MALE | CAN_SPEAK | ATTR_MULTI |
+F:NO_STUN | RES_DISE | RES_NEXU | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP | EVIL | SMART | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:NO_SLEEP | NO_CONF | NO_STUN | IM_POIS | IM_COLD | IM_FIRE | IM_ACID
+F:ZANGBAND | HAS_LITE
+S:1_IN_3
+S:BR_NEXU | BR_CHAO | HOLD | SLOW | BR_INER | BA_NUKE |
+S:MIND_BLAST | BRAIN_SMASH | CONF | BLIND | TELE_TO | HEAL |
+S:TELE_AWAY | TELE_LEVEL | TPORT | S_UNDEAD | S_DEMON | DRAIN_MANA
+D:"Young with the youth that is outside time, and with a handsome
+D:bearded face, curved, smiling lips, Olympian brow; and dense locks
+D:waving and poppy-crowned."
+
+N:1023:Blue dragon worm
+G:w:B
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ELEC |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_ELEC
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Sparks fly from its jaws.
+
+N:1024:White dragon worm
+G:w:W
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_COLD |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_COLD
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Its breath condenses in the air.
+
+N:1025:Green dragon worm
+G:w:G
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_POIS |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_POIS
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. You can smell foul gases
+D:on its breath.
+
+N:1026:Black dragon worm
+G:w:s
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_ACID
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Acidic drool drips from its jaws.
+
+N:1027:Red dragon worm
+G:w:R
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_FIRE |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_FIRE
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Smoke comes from its mouth.
+
+N:1028:Multi-hued dragon worm
+G:w:v
+I:100:10d20:10:40:80
+W:23:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 | ATTR_MULTI |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ELEC | IM_FIRE | IM_ACID | IM_COLD | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY |
+S:1_IN_6 | BR_ELEC | BR_COLD | BR_FIRE | BR_ACID | BR_POIS
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Its scales shimmer different
+D:colours as you watch.
+
+N:1029:The Minotaur of the Labyrinth
+G:H:s
+I:130:150d10:13:25:10
+W:40:2:17500:3100
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BUTT:HURT:4d6
+B:BUTT:HURT:4d6
+B:BUTT:HURT:3d6
+B:BUTT:HURT:3d6
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | UNIQUE | SPECIAL_GENE |
+F:MORTAL | BASEANGBAND
+D:It is a cross between a human and a bull.
+
+N:1030:The Sandworm Queen
+G:w:v
+I:120:30d20:10:40:80
+W:30:3:4500:12
+E:0:0:0:0:1:0
+O:30:60:0:10
+B:CLAW:ACID:5d4
+B:CLAW:POISON:5d4
+B:BITE:FIRE:5d4
+B:BITE:ELEC:5d4
+F:FORCE_MAXHP | DROP_60 | ONLY_ITEM | DROP_GREAT | DROP_GOOD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | FEMALE | POWERFUL | SPECIAL_GENE | REFLECTING |
+F:EVIL | ANIMAL | IM_ELEC | IM_FIRE | IM_ACID | IM_POIS | ESCORT |
+F:MORTAL | BASEANGBAND | EMPTY_MIND | UNIQUE | NO_CONF
+S:1_IN_2 | BR_POIS | S_KIN
+D:Queen and mother of the sandworms, fear her and her prolific children.
+
+N:1031:Sandworm
+G:w:y
+I:115:10d15:10:40:80
+W:27:6:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:POISON:4d4
+B:CLAW:POISON:4d4
+B:CLAW:POISON:4d4
+B:BITE:HURT:5d5
+F:RAND_25 |
+F:FORCE_MAXHP | DROP_CORPSE | POWERFUL |
+F:EVIL | IM_ELEC | IM_FIRE | IM_POIS | EMPTY_MIND |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY
+D:Offbreed of the Sandworm Queen, they are harmless alone...
+
+
+N:1032:Tik'srvzllat
+G:G:v
+I:142:180d100:200:170:0
+W:127:2:1000:350000
+E:1:1:1:2:1:1
+O:50:0:50:0
+B:GAZE:UN_BONUS:10d10
+B:GAZE:TIME:10d10
+B:GAZE:INSANITY:10d10
+B:GAZE:INSANITY:10d5
+F:UNIQUE | SPECIAL_GENE |
+F:FORCE_MAXHP | POWERFUL |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | WEIRD_MIND |
+F:EVIL | UNDEAD | IM_COLD | IM_FIRE | IM_ACID | IM_ELEC | AURA_COLD |
+F:IM_POIS | RES_NETH | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:S_UNDEAD | S_DEMON | S_DRAGON |
+S:S_UNIQUE | S_WRAITH | S_HI_DEMON |
+S:S_HI_UNDEAD | S_HI_DRAGON | S_KIN |
+S:BR_DISE | BA_NETH
+D:A disembodied and barely sentient mind, Tik'srvzllat floated
+D:through the void for eons before being awakened by sorcery, pulled
+D:into the nether realm, and shaped into the being you see before you.
+D:A flickering purple outline of a sphere, with eerie yellow-purple
+D:mist circling rapidly around it, Tik'srvzllat threatens your sanity
+D:with its appearance alone.
+
+N:1033:The Glass Golem
+G:g:W
+I:130:100d15:200:170:0
+W:52:4:0:2000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:INSANITY:5d6
+B:HIT:INSANITY:6d6
+B:HIT:INSANITY:7d6
+B:HIT:INSANITY:6d6
+F:COLD_BLOOD | EMPTY_MIND | KILL_WALL | FORCE_MAXHP | POWERFUL | SPECIAL_GENE |
+F:BASH_DOOR | IM_COLD | IM_ACID | IM_FIRE | IM_ELEC | IM_POIS | NONLIVING |
+F:ESCORTS | ESCORT | UNIQUE | NO_SLEEP | NO_CONF | NO_FEAR | NO_STUN
+F:CHAR_MULTI | CAN_FLY | BASEANGBAND | NO_CUT
+S:1_IN_4
+S:BR_CONF | BR_LITE | BR_DARK | BR_WALL
+S:S_KIN | TELE_LEVEL | SHRIEK
+D:One of the last creations of the petty dwarves of Ludarin, its existence
+D:explains their destruction. A creation of finest glass, the body of this
+D:creature bends and amplifies light in a way that makes you unsure of its
+D:position. You feel somewhat dizzy as the radiant light reflects off the
+D:walls, the ceiling and your gear.
+
+N:1034:The White Balrog
+G:U:W
+I:120:25d100:20:100:100
+W:50:3:12000:25000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:COLD:4d12
+B:HIT:COLD:4d12
+B:CRUSH:HURT:3d12
+B:TOUCH:UN_POWER
+F:UNIQUE | FORCE_SLEEP | FORCE_MAXHP | AURA_COLD | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | NONLIVING | DROP_RANDART
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | SMART |
+F:EVIL | DEMON | IM_COLD | NO_CONF | KILL_WALL | BASEANGBAND |
+F:HAS_LITE | SPECIAL_GENE
+S:1_IN_4 |
+S:BLIND | CONF | BRAIN_SMASH |
+S:BR_COLD | BO_COLD | BA_NETH | S_UNDEAD | S_DEMON
+D:It is a massive humanoid demon wreathed in frost, wielding a cruel looking
+D:pike in its hands.
+
+N:1035:Golgarach, the Living Rock
+G:#:W
+I:120:50d30:20:100:40
+W:45:2:0:1500
+E:0:0:0:0:0:0
+O:60:0:40:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:FORCE_SLEEP | COLD_BLOOD | EMPTY_MIND | PASS_WALL | KILL_BODY | ESCORT |
+F:BASH_DOOR | IM_COLD | IM_ACID | IM_ELEC | IM_POIS | NONLIVING | UNIQUE
+F:HURT_ROCK | NO_CONF | NO_SLEEP | NO_CUT | CHAR_MULTI | BASEANGBAND | SPECIAL_GENE
+F:NO_CUT | DROP_RANDART
+S:1_IN_10 | S_KIN | BO_ACID | BA_FIRE
+D:Deep in the heart of the earth, even the rock itself is sentient
+D:and has learned to despise intruders.
+
+N:1036:Atlas, the Titan
+G:P:s
+I:130:100d100:30:160:15
+W:76:3:70000:37000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:SHATTER:13d13
+B:HIT:CONFUSE:13d13
+B:HIT:SHATTER:13d13
+B:HIT:CONFUSE:13d13
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_GOOD | DROP_4D2 | KILL_BODY | KILL_WALL |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | GIANT | HURT_ROCK | BASEANGBAND | HAS_LITE |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+D:The strongest of all the Titans. Legend has it that he once held the sky
+D:on his shoulders; and the mountain range that now does so is named after him.
+
+N:1037:Kronos, Lord of the Titans
+G:P:v
+I:130:130d100:30:150:15
+W:87:3:80000:42000
+B:HIT:CONFUSE:12d12
+B:HIT:CONFUSE:12d12
+B:HIT:CONFUSE:12d12
+B:HIT:CONFUSE:12d12
+E:1:1:1:2:1:1
+O:0:100:0:0
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | MOVE_BODY |
+F:ONLY_ITEM | DROP_4D2 | DROP_3D2 | DROP_GOOD |
+F:SMART | TAKE_ITEM | BASH_DOOR | HAS_LITE |
+F:EVIL | GIANT | ESCORT | BASEANGBAND | DROP_CORPSE |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_POIS | IM_ELEC
+S:1_IN_3 |
+S:BR_FIRE | BR_COLD | BR_SHAR | BR_SOUN | ROCKET |
+S:S_MONSTERS | S_KIN | TELE_TO | HEAL
+D:The lord of the Titans, he has broken loose from his confinement in
+D:the nether hells to seek revenge on the world.
+
+N:1038:Water hound
+G:Z:r
+I:110:12d6:30:30:0
+W:43:1:600:150
+B:BITE:HURT:1d6
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+E:0:1:0:2:1:0
+O:0:0:0:0
+F:FORCE_SLEEP | BASH_DOOR | DROP_CORPSE | FRIENDS
+F:ANIMAL | IM_COLD | MORTAL | BASEANGBAND | RES_WATE | NO_CUT
+S:1_IN_5 | BA_WATE
+D:The sound of a hundred waterfalls rushes through your ears as
+D:a huge wave of water, vaguely hound-shaped, rushes towards you.
+
+N:1039:Improv, the mighty MoLD
+G:m:v
+I:150:170d100:40:140:0
+W:127:2:3000:50000
+E:3:0:3:6:1:0
+O:20:20:20:20
+B:SPORE:UN_BONUS:10d10
+B:SPORE:EXP_80:10d10
+B:SPORE:TIME:10d10
+B:SPORE:TIME:10d10
+F:UNIQUE | NEVER_MOVE | CAN_SWIM |
+F:FORCE_MAXHP | WEIRD_MIND | DROP_CORPSE |
+F:REFLECTING | AURA_ELEC | ONLY_ITEM | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | FORCE_SLEEP | RES_NETH |
+F:SMART | POWERFUL | RES_TELE | REGENERATE | CAN_FLY |
+F:DG_CURSE | WYRM_PROTECT | EVIL |
+F:IM_ACID | IM_FIRE | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_STUN |
+F:JOKEANGBAND | HAS_LITE | RES_WATE | NO_CUT
+S:1_IN_2 |
+S:S_HI_DRAGON | S_KIN | BR_DISI | HEAL | TPORT |
+S:TELE_LEVEL | TELE_TO
+D:An assistant to DarkGod, Improv has chosen the form of a dense
+D:purple smog for his incarnation into Middle-earth. It travels the
+D:dungeons, killing software bugs and creating random artifacts for
+D:guests to find.
+
+N:1040:Emperor Mimic
+G:m:y
+I:120:50d50:30:60:100
+W:40:3:100:200
+E:0:0:0:0:0:0
+O:25:25:25:25
+B:HIT:POISON:5d5
+B:HIT:POISON:5d5
+B:HIT:POISON:5d5
+B:HIT:POISON:5d5
+F:MIMIC | UNIQUE
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD |
+F:IM_ACID | IM_FIRE | IM_ELEC | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_1 |
+S:BLIND | CONF | SCARE | CAUSE_4 | CAUSE_3 | FORGET |
+S:BA_ACID | BA_FIRE | BA_COLD | BA_ELEC |
+S:S_MONSTER | S_KIN | SHRIEK | BRAIN_SMASH | TRAPS
+D:A strange creature that disguises itself as an object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:1041:Melinda Proudfoot
+G:h:v
+I:110:1d1:40:250:3
+W:1:1:730:0
+E:0:1:1:2:1:1
+O:0:0:0:1
+F:FEMALE | CAN_SPEAK
+F:FORCE_MAXHP | SPECIAL_GENE
+F:NEVER_MOVE | NEVER_BLOW | GOOD | NO_TARGET
+F:MORTAL | BASEANGBAND | UNIQUE | NEUTRAL | NO_DEATH
+D:She seems to seek someone, you may help...
+
+N:1042:Thrain, the King Under the Mountain
+G:h:B
+I:110:1d1:40:250:3
+W:60:1:730:0
+E:0:1:1:2:1:1
+O:0:0:0:1
+F:MALE | CAN_SPEAK
+F:FORCE_MAXHP | SPECIAL_GENE
+F:NEVER_MOVE | NEVER_BLOW | GOOD | NO_TARGET
+F:MORTAL | BASEANGBAND | UNIQUE | NEUTRAL | NO_DEATH
+D:He must have suffered horrible tortures...
+
+N:1043:Fire golem
+G:g:r
+I:115:3d20:50:50:10
+W:0:3:100:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:HIT:FIRE:3d6
+B:HIT:FIRE:3d6
+F:BASH_DOOR | AURA_FIRE | HAS_LITE
+F:IM_FIRE | SPECIAL_GENE
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | NO_STUN
+F:MORTAL | BASEANGBAND | NO_CUT | AI_PLAYER
+S:1_IN_10 |
+S:BR_FIRE
+D:A sentient mass of pure fire.
+
+N:1044:Melkor, Lord of Darkness
+G:G:v
+I:150:300d300:100:150:0
+W:150:1:200000:60000
+E:1:1:1:2:1:1
+O:25:25:25:25
+B:HIT:ABOMINATION:3d10
+B:HIT:TIME:24d10
+B:HIT:INSANITY:24d10
+B:HIT:LOSE_ALL:24d10
+F:UNIQUE | CAN_SPEAK | MALE |
+F:FORCE_MAXHP | SPIRIT
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | DROP_CHOSEN | RES_NETH |
+F:SMART | KILL_WALL | MOVE_BODY | AURA_FIRE |
+F:REGENERATE | POWERFUL | SPECIAL_GENE | CAN_FLY | KILL_TREES
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_STUN | NO_SLEEP | NO_FEAR | RES_TELE | BASEANGBAND |
+S:1_IN_4 |
+S:BRAIN_SMASH |
+S:BA_MANA | BO_MANA | BA_NETH | BA_CHAO | BA_DARK | ANIM_DEAD | S_KIN |
+S:S_MONSTERS | S_UNIQUE | S_HI_DEMON | S_HI_UNDEAD | S_HI_DRAGON |
+S:BR_NETH | BR_DISI | HAND_DOOM | S_WRAITH | HEAL | BRAIN_SMASH |
+S:DRAIN_MANA | TELE_TO | DARKNESS | SHRIEK
+D:He was the most powerful of the Valar, the equal of Manwe.
+D:You banned him here, in the Void, and now you must destroy him
+D:forever. However here in the Void, his spirit gained much power
+D:for he is closer to the Flame Imperishable. He is coming to you in pure
+D:madness, which makes him even more dangerous. You are on the verge
+D:of dying!
+
+## Here are the Spirits, inhabitants of the Void, all called "Spirit" making it hard to know what we are up against ##
+## Note: I am nasty heheh :)
+
+# Spirit of nether
+N:1045:Spirit
+G:G:v
+I:120:40d80:30:50:20
+W:128:2:0:5000
+E:0:1:1:2:0:0
+O:25:0:75:0
+B:TOUCH:EXP_80:10d10
+B:TOUCH:EXP_80:10d10
+F:SPIRIT | BASEANGBAND | NEVER_MOVE | EMPTY_MIND | NO_CUT |
+F:COLD_BLOOD | INVISIBLE
+S:1_IN_1 |
+S:BA_NETH
+D:This strange, almost intangible spirit keeps assaulting you!
+
+# Spirit of annoyance (hahaha AI_ANNOY and MULTIPLY)
+N:1046:Spirit
+G:G:B
+I:130:40d20:30:70:70
+W:144:4:0:500
+E:0:0:0:0:0:0
+O:5:5:5:0
+B:TOUCH:POISON:10d10
+B:CRAWL:POISON:10d10
+B:CRAWL:EAT_ITEM:10d9
+B:BITE:UN_BONUS:9d9
+F:SPIRIT | BASEANGBAND | WEIRD_MIND | FRIENDS |
+F:AI_ANNOY | PASS_WALL
+S:MULTIPLY
+D:These things multiply at an apparently unstoppable rate!
+
+# Spirit of movement
+N:1047:Spirit
+G:G:B
+I:130:10d80:50:65:10
+W:132:1:10:5500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:LOSE_DEX:2d3
+B:TOUCH:PARALYZE:1d12
+B:TOUCH:PARALYZE:1d12
+F:SPIRIT | BASEANGBAND | NO_SLEEP | PASS_WALL | WEIRD_MIND
+S:1_IN_2 |
+S:SLOW | BLINK | HOLD | HASTE
+D:Coming towards you quickly, it seems intent on moving faster than you.
+
+# Spirit of confusion
+N:1048:Spirit
+G:G:v
+I:120:40d80:80:85:0
+W:135:2:0:5500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:HALLU:16d8
+B:ENGULF:HALLU:16d8
+B:ENGULF:CONFUSE:16d8
+B:ENGULF:CONFUSE:16d8
+F:SPIRIT | BASEANGBAND | RES_NEXU | AURA_ELEC | IM_FIRE | IM_ELEC |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | CAN_FLY | ATTR_MULTI |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_CUT
+S:1_IN_3 |
+S:BR_CHAO | BR_NEXU | BR_CONF
+D:A swirling mass, constantly changing its appearance.
+
+# Spirit of brawn
+N:1049:Spirit
+G:G:U
+I:130:140d100:50:180:30
+W:145:3:10000:8000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:SHATTER:18d18
+B:HIT:CONFUSE:18d18
+B:HIT:SHATTER:18d18
+B:HIT:CONFUSE:18d18
+F:SPIRIT | BASEANGBAND | DROP_4D2 | KILL_BODY | KILL_WALL |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | KILL_TREES |
+F:EVIL | GIANT | HURT_ROCK | BASEANGBAND | HAS_LITE |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+D:Strong and swarthy, this spirit could bend metal with his bare hands.
+
+# Spirit of Wyrms
+N:1050:Spirit
+G:G:v
+I:130:151d151:50:190:50
+W:147:8:10000:87500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:10d15
+B:CLAW:HURT:10d15
+B:BITE:HURT:14d18
+B:BITE:HURT:14d18
+F:SPIRIT | FORCE_MAXHP | MOVE_BODY | AURA_FIRE | REFLECTING | AURA_ELEC |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | AURA_COLD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | RES_NETH | RES_DISE |
+F:DRAGON | GOOD | RES_TELE | DROP_CORPSE | KILL_TREES |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:RES_NEXU | RES_PLAS | CAN_FLY | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_3 |
+S:S_HI_DRAGON | S_DRAGON | S_KIN |
+S:BR_ACID | BR_ELEC | BR_FIRE |
+S:BR_COLD | BR_POIS | BR_NETH | BR_LITE | BR_DARK |
+S:BR_CONF | BR_SOUN | BR_CHAO | BR_DISE | BR_NEXU |
+S:BR_TIME | BR_INER | BR_GRAV | BR_SHAR | BR_PLAS |
+S:BR_WALL | BR_MANA | BR_DISI
+D:This spirit bears a remarkable similarity to some of the most powerful
+D:types of dragonkind found in Middle-earth. It appears to be even more
+D:fearsome though!
+
+# Spirit of snakes
+N:1051:Spirit
+G:G:g
+I:130:150d100:40:80:20
+W:133:3:90:750
+E:1:1:1:2:1:1
+O:25:20:25:20
+B:BITE:POISON:15d15
+B:BITE:POISON:15d15
+B:BITE:LOSE_ALL:10d12
+F:SPIRIT | CAN_SWIM | IM_POIS | IM_ACID |
+F:DROP_60 | DROP_2D2 | FRIENDS | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | EVIL | BASEANGBAND
+S:1_IN_4 |
+S:BA_POIS | S_MONSTER | SCARE | HOLD
+D:It slides towards you, a horrible scaly, slidy thing.
+
+# Spirit of seeing
+N:1052:Spirit
+G:G:v
+I:130:95d110:60:130:10
+W:141:3:60:50000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:UN_BONUS:12d12
+B:GAZE:UN_POWER:12d10
+B:GAZE:INSANITY:12d14
+B:GAZE:LOSE_ALL:6d6
+F:SPIRIT | BASH_DOOR | EVIL | IM_POIS |
+F:CAN_FLY | BASEANGBAND
+S:1_IN_2 |
+S:BLIND | CONF | FORGET | SCARE | DRAIN_MANA | BRAIN_SMASH |
+S:BA_DARK | BO_MANA | BA_NETH | BA_ACID | BA_FIRE | BA_COLD
+D:You will find it difficult to avoid being seen by this spirit! And
+D:once it has you in its sight, beware!
+
+# Spirit of unseeing
+N:1053:Spirit
+G:.:W
+I:120:55d50:20:130:80
+W:142:6:60:4000
+E:0:0:0:0:0:0
+O:10:0:90:0
+B:TOUCH:UN_BONUS:12d12
+B:TOUCH:UN_POWER:12d10
+B:TOUCH:INSANITY:12d14
+B:TOUCH:LOSE_ALL:6d6
+F:SPIRIT | CAN_FLY | REFLECTING |
+F:SMART | BASH_DOOR | COLD_BLOOD | INVISIBLE | EMPTY_MIND |
+F:EVIL | BASEANGBAND | CHAR_MULTI | CHAR_CLEAR | ATTR_CLEAR
+S:1_IN_3 |
+S:DRAIN_MANA | BLINK | BLIND | SCARE | CONF |
+S:HEAL | TELE_AWAY | DARKNESS | TRAPS | FORGET | SHRIEK
+D:Hopefully you will kill this spirit before you realise it exists.
+
+# Spirit of ickyness
+N:1054:Spirit
+G:G:g
+I:130:80d80:30:60:10
+W:138:4:300:40000
+E:0:0:0:0:0:0
+O:40:30:10:10
+B:CRAWL:POISON:12d14
+B:CRAWL:EAT_FOOD:12d14
+B:TOUCH:ACID:13d15
+B:HIT:HURT:13d15
+F:SPIRIT | BASEANGBAND |
+F:EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_ELEC | IM_FIRE | IM_COLD | IM_POIS |
+F:EMPTY_MIND
+S:1_IN_4 |
+S:DRAIN_MANA | BLIND | CONF | SCARE | S_KIN
+D:A horrible slimy spirit, that seems to ooze evilness. I wouldn't get
+D:too close to it if I were you.
+
+# Spirit of friendship
+N:1055:Spirit
+G:G:W
+I:130:35d100:40:150:100
+W:136:3:200:10000
+E:0:1:0:2:1:0
+O:50:50:0:0
+B:BITE:HURT:12d12
+B:BITE:HURT:12d12
+B:BITE:HURT:12d8
+B:BITE:HURT:12d8
+F:SPIRIT | BASEANGBAND |
+F:ESCORT | ESCORTS |
+F:OPEN_DOOR | BASH_DOOR
+S:1_IN_2 |
+S:S_KIN
+D:This spirit appears to have lots of friends!
+
+# Spirit of abomination
+N:1056:Spirit
+G:G:d
+I:130:40d80:30:125:125
+W:134:2:200:5000
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:WAIL:TERRIFY:8d9
+B:HIT:HURT:10d10
+B:HIT:ABOMINATION:6d10
+B:HIT:ABOMINATION:6d10
+F:SPIRIT | BASEANGBAND |
+F:EVIL | UNDEAD | IM_POIS | IM_COLD | NO_CONF | NO_SLEEP |
+F:COLD_BLOOD | HURT_LITE | NO_CUT
+S:1_IN_3 |
+S:SCARE | HOLD | DARKNESS | SCARE
+D:It seems to have been woken from the dead, this spirit. It lumbers
+D:towards you, seeking to turn you into a form as hideous as its own!
+
+### Here come the spirits of <player stat> ###
+#
+# Spirit of strength
+N:1057:Spirit
+G:G:u
+I:120:140d100:50:180:170
+W:129:2:10000:8000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:LOSE_STR:4d8
+B:HIT:LOSE_STR:4d8
+B:HIT:LOSE_STR:4d8
+F:SPIRIT | BASEANGBAND | DROP_2D2 | KILL_BODY | KILL_WALL |
+F:BASH_DOOR | EVIL | GIANT | HURT_ROCK |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+D:It is coming for you, this massive imposing tower of strength.
+D:It appears almost unstoppable!
+
+# Spirit of intelligence
+N:1058:Spirit
+G:G:r
+I:140:80d100:50:100:10
+W:131:2:10000:8000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:LOSE_INT:4d8
+B:HIT:LOSE_INT:4d8
+B:HIT:LOSE_INT:4d8
+F:EVIL | SPIRIT | BASEANGBAND | DROP_2D2 |
+F:OPEN_DOOR | SMART |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+S:1_IN_2 |
+S:HASTE | TPORT | TELE_TO | BLIND | CONF |
+S:BO_MANA | BO_FIRE | BO_COLD | BO_ELEC |
+D:This spirit looks very clever, cunning almost.
+
+# Spirit of wisdom
+N:1059:Spirit
+G:G:G
+I:130:120d100:50:200:130
+W:137:2:10000:8000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:LOSE_WIS:4d8
+B:HIT:LOSE_WIS:4d8
+B:HIT:LOSE_WIS:4d8
+F:EVIL | SPIRIT | BASEANGBAND | DROP_2D2 |
+F:OPEN_DOOR |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+S:1_IN_2 |
+S:HEAL | MIND_BLAST | CAUSE_4 | SCARE |
+S:DRAIN_MANA | BRAIN_SMASH | FORGET |
+D:This spirit has something of a priestly look about it.
+
+# Spirit of dexterity
+N:1060:Spirit
+G:G:W
+I:160:120d100:50:160:50
+W:139:2:10000:8000
+E:1:1:1:2:1:1
+O:0:50:25:25
+B:HIT:LOSE_DEX:4d8
+B:HIT:LOSE_DEX:4d8
+B:HIT:LOSE_DEX:4d8
+F:EVIL | SPIRIT | BASEANGBAND | DROP_2D2 |
+F:OPEN_DOOR | SMART |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+S:1_IN_1 |
+S:ARROW_4
+D:This spirit moves almost too quickly for you to see him.
+
+# Spirit of constitution
+N:1061:Spirit
+G:G:s
+I:120:140d100:50:180:50
+W:143:2:10000:8000
+E:1:1:1:2:1:1
+O:0:50:0:50
+B:HIT:LOSE_CON:4d8
+B:HIT:LOSE_CON:4d8
+B:HIT:LOSE_CON:4d8
+F:EVIL | SPIRIT | BASEANGBAND | DROP_2D2 | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+D:This spirit moves slower than most, but thunders on and on
+D:towards you.
+
+# Spirit of charisma
+N:1062:Spirit
+G:G:b
+I:140:80d100:50:120:90
+W:146:2:10000:8000
+E:1:1:1:2:1:1
+O:70:10:10:10
+B:HIT:LOSE_CHR:4d8
+B:HIT:LOSE_CHR:4d8
+B:HIT:LOSE_CHR:4d8
+F:SPIRIT | BASEANGBAND | DROP_2D2 |
+F:OPEN_DOOR | EVIL | TAKE_ITEM |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+S:1_IN_2 |
+S:TRAPS | ARROW_3 | BLINK | TELE_TO | CONF
+D:There is something attractive about this spirit, and it seems
+D:to have a full purse.
+
+### Here come some elemental spirits ###
+#
+# Spirit of flickering fire
+N:1063:Spirit
+G:G:r
+I:120:60d100:50:65:80
+W:130:1:5:6000
+E:1:1:1:2:1:1
+O:25:60:0:15
+B:HIT:FIRE:10d8
+B:HIT:FIRE:10d8
+B:HIT:FIRE:10d8
+F:SPIRIT | BASEANGBAND | AI_ANNOY | IM_FIRE | AURA_FIRE | HAS_LITE
+S:1_IN_2 |
+S:BO_FIRE | BA_FIRE
+D:Flickering towards you, and then away, this spirit will burn you badly!
+
+# Spirit of icy cold
+N:1064:Spirit
+G:G:w
+I:120:60d100:50:65:80
+W:148:1:5:6000
+E:1:1:1:2:1:1
+O:25:60:0:15
+B:HIT:COLD:10d8
+B:HIT:COLD:10d8
+B:HIT:COLD:10d8
+F:SPIRIT | BASEANGBAND | IM_COLD | AURA_COLD |
+F:COLD_BLOOD | BASH_DOOR
+S:1_IN_2 |
+S:BO_COLD | BA_COLD
+D:The temperature around you drops as soon as you set eyes on this spirit.
+
+# Spirit of corrosion (acid)
+N:1065:Spirit
+G:G:s
+I:120:60d100:50:65:80
+W:146:1:5:6000
+E:1:1:1:2:1:1
+O:25:60:0:15
+B:HIT:ACID:10d8
+B:HIT:ACID:10d8
+B:HIT:ACID:10d8
+F:SPIRIT | BASEANGBAND | IM_ACID | BASH_DOOR | KILL_TREES
+S:1_IN_2 |
+S:BO_ACID | BA_ACID
+D:The very fabric of the void heals itself where this spirit walks.
+
+# Spirit of shocking (electricity)
+N:1066:Spirit
+G:G:b
+I:120:60d100:50:65:80
+W:149:1:5:6000
+E:1:1:1:2:1:1
+O:25:60:0:15
+B:HIT:ELEC:10d8
+B:HIT:ELEC:10d8
+B:HIT:ELEC:10d8
+F:SPIRIT | BASEANGBAND | IM_ELEC | AURA_ELEC | BASH_DOOR
+S:1_IN_2 |
+S:BO_ELEC | BA_ELEC
+D:The air crackles as this spirit approaches, and you smell singed flesh.
+
+# Spirit of Valaraukar (Balrogs)
+N:1067:Spirit
+G:G:v
+I:130:130d100:100:140:10
+W:149:1:170:43000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:FIRE:11d12
+B:HIT:FIRE:11d12
+B:CRUSH:HURT:10d12
+B:TOUCH:UN_POWER
+F:SPIRIT | CAN_FLY | KILL_WALL | AURA_FIRE | NONLIVING |
+F:ONLY_ITEM | DROP_2D2 | EVIL | DEMON |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_FIRE | IM_ELEC | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BLIND | CONF | SCARE | BR_FIRE
+D:Carrying a whip of fire, this spirit looks not dissimilar to a certain
+D:Balrog.
+
+# Spirit of shadows
+N:1068:Spirit
+G:G:d
+I:130:30d100:70:150:4
+W:140:4:2300:10000
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:TOUCH:EXP_80:20d8
+B:TOUCH:EXP_40:20d8
+F:SPIRIT | BASEANGBAND | REFLECTING | REGENERATE |
+F:IM_ACID | IM_ELEC | IM_COLD | IM_FIRE | IM_POIS | RES_TELE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | SMART | POWERFUL
+S:1_IN_3 |
+S:BLIND | HEAL | BA_DARK | HASTE | CONF
+D:Deriving his strength from the shadows, this spirit
+D:steals only for the challenge.
+
+# Spirit of vampire or something
+N:1069:Spirit
+G:G:W
+I:130:50d50:30:90:10
+W:143:2:1700:18000
+E:1:1:1:2:1:1
+O:0:70:30:0
+B:HIT:HURT:10d9
+B:HIT:HURT:9d9
+B:BITE:EXP_80:9d9
+B:BITE:EXP_80:9d9
+F:SPIRIT | FORCE_SLEEP | CAN_FLY |
+F:DROP_60 | DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | RES_TELE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT | SPIRIT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | DARKNESS | BO_NETH
+D:Your blood curdles and your bones chill as this spirit approaches.
+
+# Spirit of unresistability (hehehehe)
+N:1070:Spirit
+G:G:v
+I:140:40d100:40:70:20
+W:149:4:1200:20000
+E:1:1:1:2:1:1:
+O:0:0:0:100
+B:HIT:SHATTER:18d10
+B:HIT:SHATTER:18d10
+B:HIT:LOSE_ALL:8d8
+B:TOUCH:UN_POWER
+F:BASEANGBAND | SPIRIT | SMART |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:RES_NEXU | RES_NETH |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:IM_POIS | IM_ELEC | IM_ACID | IM_COLD |
+S:1_IN_2 |
+S:BA_MANA | BR_PLAS | BR_TIME | ROCKET | HAND_DOOM | FORGET | BA_WATE
+D:This spirit appears to be afraid of very little, and confident in its
+D:ability to destroy you.
+
+# Spirit of time
+N:1071:Spirit
+G:G:G
+I:130:80d100:40:110:0
+W:150:3:800:50000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:TOUCH:TIME:6d12
+B:TOUCH:TIME:6d12
+B:TOUCH:TIME:6d12
+B:TOUCH:TIME:6d12
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:SPIRIT | BASEANGBAND
+S:1_IN_2 |
+S:BR_TIME | SLOW | HASTE | HOLD
+D:All at once you see that which is to come and that which has gone before.
+
+# Spirit of Gold
+N:1072:Spirit
+G:G:y
+I:130:50d80:20:110:100
+W:130:4:80:8000
+E:0:1:0:2:1:0
+O:100:0:0:0
+B:TOUCH:EAT_GOLD:7d15
+B:TOUCH:EAT_GOLD:7d15
+B:HIT:POISON:6d12
+B:HIT:POISON:6d12
+F:ONLY_GOLD | SPIRIT | BASEANGBAND |
+F:DROP_4D2 | DROP_4D2 | DROP_4D2 | REFLECTING | COLD_BLOOD | REGENERATE |
+F:BASH_DOOR | MOVE_BODY | IM_ELEC | IM_COLD | IM_POIS |
+F:RES_TELE | NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP
+S:1_IN_4 |
+S:ARROW_4 | HEAL | FORGET
+D:It is the very essence of financial greed...
+
+# Spirit of doom
+N:1073:Spirit
+G:G:D
+I:136:60d70:40:70:30
+W:134:2:60:8000
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:HIT:HURT:14d14
+B:HIT:HURT:14d14
+B:HIT:HURT:14d14
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:SPIRIT | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HAND_DOOM | CAUSE_4 | DARKNESS
+D:The very presence of this creature fills the air with an aura of doom.
+D:You feel waves of depression descending on you as it approaches.
+
+# Spirit of etherealism (?)
+N:1074:Spirit
+G:G:o
+I:120:40d100:30:120:40
+W:141:3:1700:10000
+E:0:1:0:6:1:0
+B:CLAW:HURT:14d10
+B:CLAW:HURT:14d10
+B:BITE:HURT:17d10
+F:INVISIBLE | CAN_FLY | SPIRIT | WEIRD_MIND |
+F:PASS_WALL | POWERFUL | MOVE_BODY |
+F:EVIL | NO_CONF | NO_SLEEP | BASEANGBAND | SPIRIT
+S:1_IN_2 |
+S:BLIND | CONF |
+S:BR_LITE | BR_DARK | BR_CONF
+D:This sprit seems to flicker in and out of this plane, and is a master
+D:of light and dark.
+
+# Spirit of orc (boring huh)
+N:1075:Spirit
+G:G:v
+I:120:90d10:30:160:100
+W:142:3:2700:11111
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS | ONLY_ITEM |
+F:MORTAL | BASEANGBAND | HAS_LITE | SPIRIT
+D:Stupid but strong, this spirit has an orcish aura about him.
+
+### Here endeth the Spirits ###
+
+N:1076:Neil, the Sorceror
+G:h:v
+# *Not* enough hitpoints
+I:110:50d100:20:30:30
+# Bottom of Erebor
+W:72:100:330:50000
+E:1:1:1:2:1:1
+O:0:5:90:5
+# Sorceror, not warrior
+B:HIT:HURT:1d1
+B:HIT:HURT:1d1
+F:OPEN_DOOR | SMART | MALE | DROP_SKELETON | DROP_CORPSE
+F:MORTAL | HAS_LITE | JOKEANGBAND | UNIQUE
+# Trone, of course
+F:CAN_FLY | REFLECTING | IM_FIRE
+# Thorin
+F:IM_ACID | FORCE_MAXHP
+# No cold or random gen... waiting on elven rings only at bottom of Erebor
+F:SPECIAL_GENE
+# Dig
+F:KILL_WALL
+# Obvious resistances
+F:NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR
+# Well, he's been there a while
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_GREAT
+# Essence of speed, Manathrust, Noxious Cloud, and Fireflash
+S:1_IN_1 |
+S:HASTE | BO_MANA | BA_POIS | BA_FIRE
+D:He looks like he is looking for something, and the flecks of dragon
+D:blood on his face tell you he means business!
diff --git a/lib/edit/ra_info.txt b/lib/edit/ra_info.txt
new file mode 100644
index 00000000..57dcee95
--- /dev/null
+++ b/lib/edit/ra_info.txt
@@ -0,0 +1,1927 @@
+# File: ra_info.txt
+
+
+# This file is used to initialize the "lib/raw/ra_info.raw" file, which is
+# used to initialize the "randart parts" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/ra_info.raw" file.
+
+# N:index
+# X:power value:max number of time it can appear on one object
+# T:tval:min sval:max sval (up to 20 T: lines)
+# W:mininum player level to create it:rarity1:rarity2
+# C:max to dam:max to hit:max to AC:max to pval
+# F:flags
+
+# Version stamp (required)
+
+V:2.0.0
+
+# General info, number of powers
+G:100:1d5:1
+G:14:0d0:1
+G:10:0d0:1
+G:3:0d0:1
+
+### Mage Staff randarts ###
+
+N:1
+X:10:1
+T:6:0:255
+W:5:1:4
+C:-5:-5:0:5
+F:MANA
+
+N:2
+X:14:1
+T:6:0:255
+W:10:1:8
+C:-10:-10:0:5
+F:SPELL
+
+N:3
+X:5:1
+T:6:0:255
+W:1:1:4
+C:-3:-3:0:5
+F:INT
+
+### Weapons ###
+
+# + To damage
+N:4
+X:5:2
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:19:0:255
+T:22:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:2
+C:10:0:0:0
+
+# + To Damage for swords
+N:5
+X:5:2
+T:23:0:255
+T:115:55:55
+W:1:1:2
+C:9:0:0:0
+
+# + To damage for hafted weapons
+N:6
+X:5:2
+T:21:0:255
+W:1:1:2
+C:11:0:0:0
+
+# + To hit
+N:7
+X:5:2
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:19:0:255
+T:22:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:2
+C:0:10:0:0
+
+# + To Hit for swords
+N:8
+X:5:2
+T:23:0:255
+T:115:55:55
+W:1:1:2
+C:0:11:0:0
+
+# + To Hit for hafted weapons
+N:9
+X:5:2
+T:21:0:255
+W:1:1:2
+C:0:9:0:0
+
+N:10
+X:15:1
+T:24:0:255
+T:115:55:55
+W:15:1:25
+C:4:0:0:0
+F:VORPAL
+
+N:11
+X:15:1
+T:23:2:2
+T:23:9:9
+T:23:11:33
+T:115:55:55
+W:15:1:25
+C:2:2:0:0
+F:VORPAL
+
+N:12
+X:15:1
+T:22:30:30
+W:10:1:16
+C:6:-2:0:0
+F:VORPAL
+
+N:13
+X:15:1
+T:22:17:17
+T:22:3:3
+T:22:0:15
+W:15:1:25
+C:4:0:0:0
+F:VORPAL
+
+N:14
+X:10:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+T:115:55:55
+W:4:1:10
+C:5:2:0:0
+F:BRAND_POIS
+
+N:15
+X:10:1
+T:23:0:255
+T:115:55:55
+W:4:1:10
+C:4:3:0:0
+F:BRAND_POIS
+
+N:16
+X:10:1
+T:21:0:255
+W:4:1:10
+C:5:2:0:0
+F:BRAND_POIS
+
+N:17
+X:11:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:5:1:11
+C:3:1:0:0
+F:BRAND_FIRE
+A:BRAND_COLD
+
+N:18
+X:11:1
+T:23:0:255
+T:115:55:55
+W:5:1:11
+C:2:2:0:0
+F:BRAND_FIRE
+A:BRAND_COLD
+
+N:19
+X:11:1
+T:21:0:255
+W:5:1:11
+C:4:0:0:0
+F:BRAND_FIRE
+A:BRAND_COLD
+
+N:20
+X:12:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:5:1:11
+C:5:1:0:0
+F:BRAND_COLD
+A:BRAND_FIRE
+
+N:21
+X:12:1
+T:23:0:255
+T:115:55:55
+W:5:1:11
+C:4:2:0:0
+F:BRAND_COLD
+A:BRAND_FIRE
+
+N:22
+X:12:1
+T:21:0:255
+W:5:1:11
+C:6:0:0:0
+F:BRAND_COLD
+A:BRAND_FIRE
+
+N:23
+X:13:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:5:1:13
+C:4:0:0:0
+F:BRAND_ELEC
+
+N:24
+X:13:1
+T:23:0:255
+T:115:55:55
+W:5:1:13
+C:3:1:0:0
+F:BRAND_ELEC
+
+N:25
+X:13:1
+T:21:0:255
+W:5:1:13
+C:5:-1:0:0
+F:BRAND_ELEC
+
+N:26
+X:15:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:7:1:15
+C:3:0:0:0
+F:BRAND_ACID
+
+N:27
+X:15:1
+T:23:0:255
+T:115:55:55
+W:7:1:15
+C:2:1:0:0
+F:BRAND_ACID
+
+N:28
+X:15:1
+T:21:0:255
+W:7:1:15
+C:4:0:0:0
+F:BRAND_ACID
+
+N:29
+X:5:1
+T:21:0:255
+W:15:1:35
+C:15:2:0:0
+F:IMPACT
+
+N:30
+X:5:1
+T:18:0:255
+T:19:0:255
+T:22:0:255
+T:24:0:255
+W:2:1:9
+C:2:2:0:6
+F:STR
+
+N:31
+X:5:1
+T:23:0:255
+T:115:55:55
+W:2:1:9
+C:0:4:0:6
+F:STR
+
+N:32
+X:5:1
+T:21:0:255
+W:1:1:7
+C:4:0:0:6
+F:STR
+
+N:33
+X:3:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:1:1:6
+C:0:0:0:6
+F:CHR
+
+N:34
+X:3:1
+T:23:0:255
+T:115:55:55
+W:2:1:6
+C:-1:1:0:6
+F:CHR
+
+N:35
+X:2:1
+T:21:0:255
+W:2:1:6
+C:1:-1:0:5
+F:CHR
+
+N:36
+X:4:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:2:1:8
+C:0:0:0:4
+F:INT
+
+N:37
+X:4:1
+T:21:0:255
+W:2:1:8
+C:1:-1:0:4
+F:INT
+
+N:38
+X:4:1
+T:23:0:255
+T:115:55:55
+W:2:1:8
+C:-1:1:0:4
+F:INT
+
+N:39
+X:6:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:3:1:10
+C:0:0:0:6
+F:CON
+
+N:40
+X:6:1
+T:23:0:255
+T:115:55:55
+W:3:1:10
+C:-1:1:0:6
+F:CON
+
+N:41
+X:6:1
+T:21:0:255
+C:1:-1:0:6
+F:CON
+
+N:42
+X:4:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:2:1:8
+C:0:0:0:5
+F:WIS
+
+N:43
+X:4:1
+T:21:0:255
+W:2:1:9
+C:1:-1:0:6
+F:WIS
+
+N:44
+X:4:1
+T:23:0:255
+T:115:55:55
+W:2:1:9
+C:-1:1:0:5
+F:WIS
+
+N:45
+X:4:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:2:1:7
+C:0:0:0:5
+F:DEX
+
+N:46
+X:4:1
+T:23:0:255
+T:115:55:55
+W:2:1:7
+C:-1:1:0:6
+F:DEX
+
+N:47
+X:4:1
+T:21:0:255
+W:2:1:7
+C:1:-1:0:5
+F:DEX
+
+N:48
+X:4:1
+T:21:0:255
+W:9:1:14
+C:3:0:0:6
+F:TUNNEL
+
+N:49
+X:40:1
+T:22:0:255
+T:24:0:255
+W:30:1:100
+C:0:-4:0:3
+F:BLOWS
+
+N:50
+X:40:1
+T:23:0:255
+T:115:55:55
+W:30:1:100
+C:-1:-3:0:3
+F:BLOWS
+
+N:51
+X:40:1
+T:21:0:255
+W:30:1:100
+C:1:-5:0:3
+F:BLOWS
+
+N:52
+X:50:1
+T:18:0:255
+T:19:0:255
+T:22:0:255
+T:24:0:255
+W:40:1:90
+C:-2:-2:0:5
+F:SPEED
+
+N:53
+X:50:1
+T:21:0:255
+W:40:1:90
+C:-1:-3:0:5
+F:SPEED
+
+N:54
+X:50:1
+T:23:0:255
+T:115:55:55
+W:40:1:90
+C:-3:-1:0:5
+F:SPEED
+
+N:55
+X:12:1
+T:18:0:255
+T:22:0:255
+T:21:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:11:1:20
+C:10:10:0:0
+F:CHAOTIC
+
+N:56
+X:8:1
+T:18:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:11:1:20
+C:-10:-10:0:0
+F:CHAOTIC
+
+N:57
+X:12:1
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:15:1:20
+C:4:0:0:4
+F:VAMPIRIC
+
+N:58
+X:12:1
+T:21:0:255
+W:15:1:20
+C:5:-1:0:0
+F:VAMPIRIC
+
+N:59
+X:12:1
+T:23:0:19
+T:115:55:55
+W:15:1:20
+C:3:1:0:4
+F:VAMPIRIC
+
+N:60
+X:11:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:10:1:10
+C:0:0:0:0
+F:SLAY_ANIMAL
+
+N:61
+X:11:1
+T:21:0:255
+W:10:1:10
+C:1:-1:0:0
+F:SLAY_ANIMAL
+
+N:62
+X:11:1
+T:23:0:255
+T:115:55:55
+W:10:1:10
+C:-1:1:0:0
+F:SLAY_ANIMAL
+
+N:63
+X:19:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:15:1:17
+C:0:0:0:0
+F:SLAY_EVIL
+
+N:64
+X:19:1
+T:21:0:255
+W:15:1:15
+C:1:-1:0:0
+F:SLAY_EVIL
+
+N:65
+X:19:1
+T:23:0:255
+T:115:55:55
+W:15:1:17
+C:-1:1:0:0
+F:SLAY_EVIL
+
+N:66
+X:15:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:13:1:15
+C:0:0:0:0
+F:SLAY_UNDEAD
+A:KILL_UNDEAD
+
+N:67
+X:15:1
+T:21:0:255
+W:13:1:15
+C:1:-1:0:0
+F:SLAY_UNDEAD
+A:KILL_UNDEAD
+
+N:68
+X:15:1
+T:23:0:255
+T:115:55:55
+W:13:1:15
+C:-1:1:0:0
+F:SLAY_UNDEAD
+A:KILL_UNDEAD
+
+N:69
+X:5:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:11:1:25
+C:0:0:0:0
+F:SLAY_DEMON
+A:KILL_DEMON
+
+N:70
+X:5:1
+T:21:0:255
+W:11:1:25
+C:1:-1:0:0
+F:SLAY_DEMON
+A:KILL_DEMON
+
+N:71
+X:5:1
+T:23:0:255
+T:115:55:55
+W:11:1:25
+C:-1:1:0:0
+F:SLAY_DEMON
+A:KILL_DEMON
+
+N:72
+X:10:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:3:1:10
+C:0:0:0:0
+F:SLAY_ORC
+
+N:73
+X:10:1
+T:21:0:255
+W:3:1:10
+C:1:-1:0:0
+F:SLAY_ORC
+
+N:74
+X:10:1
+T:23:0:255
+T:115:55:55
+W:3:1:10
+C:-1:1:0:0
+F:SLAY_ORC
+
+N:75
+X:11:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:15:2:17
+C:0:0:0:0
+F:SLAY_TROLL
+
+N:76
+X:11:1
+T:21:0:255
+W:15:2:17
+C:1:-1:0:0
+F:SLAY_TROLL
+
+N:77
+X:11:1
+T:23:0:255
+T:115:55:55
+W:15:2:17
+C:-1:1:0:0
+F:SLAY_TROLL
+
+N:78
+X:10:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:20:1:20
+C:0:0:0:0
+F:SLAY_GIANT
+
+N:79
+X:10:1
+T:21:0:255
+W:20:1:20
+C:-1:1:0:0
+F:SLAY_GIANT
+
+N:80
+X:10:1
+T:23:0:255
+T:115:55:55
+W:20:1:20
+C:0:0:0:0
+F:SLAY_GIANT
+
+N:81
+X:20:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:17:1:20
+C:0:0:0:0
+F:SLAY_DRAGON
+A:KILL_DRAGON
+
+N:82
+X:20:1
+T:21:0:255
+W:17:1:20
+C:1:-1:0:0
+F:SLAY_DRAGON
+A:KILL_DRAGON
+
+N:83
+X:20:1
+T:23:0:255
+T:115:55:55
+C:-1:1:0:0
+W:17:1:20
+F:SLAY_DRAGON
+A:KILL_DRAGON
+
+N:84
+X:31:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:17:1:35
+C:0:0:0:0
+F:KILL_DRAGON
+A:SLAY_DRAGON
+
+N:85
+X:31:1
+T:21:0:255
+W:17:1:35
+C:1:-1:0:0
+F:KILL_DRAGON
+A:SLAY_DRAGON
+
+N:86
+X:31:1
+T:23:0:255
+T:115:55:55
+W:17:1:35
+C:-1:1:0:0
+F:KILL_DRAGON
+A:SLAY_DRAGON
+
+N:87
+X:15:1
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:5:1:10
+C:-2:-2:0:0
+F:BLESSED
+A:CURSED
+
+N:88
+X:15:1
+T:21:0:255
+W:5:1:7
+C:-1:-3:0:0
+F:BLESSED
+A:CURSED
+
+N:89
+X:15:1
+T:23:0:255
+T:115:55:55
+W:5:1:10
+C:-3:-1:0:0
+F:BLESSED
+A:CURSED
+
+N:90
+X:-5:1
+T:15:0:255
+T:16:0:255
+T:18:0:255
+T:19:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:20
+C:0:0:0:0
+F:CURSED
+A:BLESSED
+
+N:93
+X:-10:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:20
+C:0:0:0:0
+F:AGGRAVATE
+A:STEALTH
+
+N:94
+X:13:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:15
+C:0:0:0:0
+F:LITE1
+A:RES_LITE
+
+N:95
+X:40:1
+T:19:0:255
+W:20:1:38
+C:0:0:0:3
+F:XTRA_MIGHT
+
+N:96
+X:40:1
+T:19:0:255
+W:20:1:38
+C:0:0:0:0
+F:XTRA_SHOTS
+
+N:97
+X:25:1
+T:23:0:255
+T:24:0:255
+T:22:17:17
+T:22:3:3
+T:22:0:15
+T:115:55:55
+W:14:1:23
+C:3:0:0:0
+F:WOUNDING
+
+N:98
+X:60:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:27:1:50
+C:0:0:0:0
+F:KILL_UNDEAD
+A:SLAY_UNDEAD
+
+N:99
+X:45:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:25:1:34
+C:0:0:0:0
+F:KILL_DEMON
+A:SLAY_DEMON
+
+N:100
+X:20:1
+T:18:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:15:1:25
+C:2:0:0:0
+Z:BERSERK
+
+N:101
+X:15:1
+T:20:0:255
+T:21:0:255
+W:20:1:35
+C:0:0:0:0
+Z:EARTHQUAKE
+
+N:102
+X:5:1
+T:20:0:255
+W:2:1:9
+C:0:0:0:6
+F:STR
+
+
+### Armor ###
+
+N:295
+X:60:1
+T:36:0:255
+T:37:0:255
+W:20:1:90
+C:-70:-70:0:2
+F:LIFE
+
+N:296
+X:7:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:1:1:14
+C:0:0:0:0
+F:SUST_STR
+
+N:297
+X:6:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:6:0:255
+W:1:1:12
+C:0:0:0:0
+F:SUST_INT
+
+N:298
+X:6:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:6:0:255
+W:1:1:12
+C:0:0:0:0
+F:SUST_WIS
+
+N:299
+X:5:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:1:1:11
+C:0:0:1:0
+F:SUST_DEX
+
+N:300
+X:9:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:1:1:16
+C:0:0:0:0
+F:SUST_CON
+
+N:301
+X:4:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:1:1:9
+C:0:0:0:0
+F:SUST_CHR
+
+N:302
+X:50:1
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:30:1:70
+C:0:0:0:0
+F:IM_ACID
+
+N:303
+X:50:1
+T:34:0:255
+T:115:56:56
+W:30:1:90
+C:0:0:0:0
+F:IM_ACID
+
+N:304
+X:50:1
+T:35:0:255
+W:30:1:80
+C:0:0:0:0
+F:IM_ACID
+
+N:305
+X:45:1
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:30:1:78
+F:IM_ELEC
+
+N:306
+X:45:1
+T:34:0:255
+T:115:56:56
+W:30:1:98
+C:0:0:0:0
+F:IM_ELEC
+
+N:307
+X:45:1
+T:35:0:255
+W:30:1:88
+C:0:0:0:0
+F:IM_ELEC
+
+N:308
+X:55:1
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:30:1:86
+C:0:0:0:0
+F:IM_FIRE
+
+N:309
+X:55:1
+T:34:0:255
+T:115:56:56
+T:35:0:255
+W:30:1:95
+C:0:0:0:0
+F:IM_FIRE
+
+N:310
+X:47:1
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:30:1:90
+C:0:0:0:0
+F:IM_COLD
+
+N:311
+X:47:1
+T:34:0:255
+T:115:56:56
+T:35:0:255
+W:30:1:90
+C:0:0:0:0
+F:IM_COLD
+
+N:312
+X:47:1
+T:35:3:3
+W:30:1:100
+C:0:0:0:0
+F:IM_COLD
+
+N:313
+X:35:1
+T:34:0:255
+T:38:0:255
+T:115:56:56
+W:20:1:45
+C:0:0:0:0
+F:REFLECT
+
+N:314
+X:35:1
+T:34:10:10
+T:115:56:56
+W:10:1:15
+C:0:0:0:0
+F:REFLECT
+
+N:315
+X:17:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+T:6:0:255
+W:5:1:7
+C:0:0:0:0
+F:FREE_ACT
+
+N:316
+X:23:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:8:1:14
+C:0:0:0:0
+F:HOLD_LIFE
+
+N:317
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:1:1:10
+C:0:0:0:0
+F:RES_ACID
+
+N:318
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:1:1:10
+C:0:0:0:0
+F:RES_FIRE
+
+N:319
+X:13:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:1:1:9
+C:0:0:0:0
+F:RES_ELEC
+
+N:320
+X:12:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:1:1:8
+C:0:0:0:0
+F:RES_COLD
+
+N:321
+X:20:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:5:1:18
+C:0:0:0:0
+F:RES_POIS
+
+N:322
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:6:1:15
+C:0:0:0:0
+F:RES_FEAR
+
+N:323
+X:10:1
+T:30:0:255
+T:31:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:56
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:5:1:10
+C:0:0:0:0
+F:RES_LITE
+
+N:324
+X:10:1
+T:32:0:255
+T:115:57:57
+W:1:1:7
+C:0:0:0:0
+F:RES_LITE
+
+N:325
+X:15:1
+T:32:0:255
+T:115:57:57
+W:5:1:15
+C:0:0:0:0
+F:LITE1
+A:RES_LITE
+
+N:326
+X:17:1
+T:32:0:255
+T:115:57:57
+W:10:1:20
+C:0:0:0:0
+F:LITE2
+A:RES_LITE
+
+N:327
+X:20:1
+T:32:0:255
+T:115:57:57
+W:15:1:25
+C:0:0:0:0
+F:LITE3
+A:RES_LITE
+
+N:328
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:10:1:15
+C:0:0:0:0
+F:RES_DARK
+
+N:329
+X:20:1
+T:115:57:57
+T:32:0:255
+T:40:0:255
+T:45:0:255
+T:6:0:255
+W:13:1:27
+C:0:0:0:0
+F:RES_BLIND
+
+N:330
+X:17:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:13:1:18
+C:0:0:0:0
+F:RES_SOUND
+
+N:331
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:115:56:57
+T:34:0:255
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:17:1:15
+C:0:0:0:0
+F:RES_NEXUS
+
+N:332
+X:19:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:16:1:19
+C:0:0:0:0
+F:RES_SHARDS
+
+N:333
+X:30:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:30:1:50
+C:0:0:0:0
+F:RES_NETHER
+
+N:334
+X:25:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:25:1:30
+F:RES_CHAOS
+
+N:335
+X:20:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+T:6:0:255
+W:25:1:35
+C:0:0:0:0
+F:RES_CONF
+
+N:336
+X:25:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+C:0:0:0:0
+W:23:1:32
+F:RES_DISEN
+
+N:337
+X:20:1
+T:35:0:255
+W:10:1:17
+C:0:0:0:0
+F:SH_FIRE | RES_FIRE
+
+N:338
+X:22:1
+T:35:0:255
+W:10:1:20
+C:0:0:0:0
+F:SH_ELEC | RES_ELEC
+
+N:339
+X:18:1
+T:115:57:57
+T:32:0:255
+T:33:0:255
+T:40:0:255
+T:45:0:255
+T:6:0:255
+W:5:1:15
+C:0:0:0:0
+F:SEE_INVIS
+
+N:340
+X:14:1
+T:30:0:255
+T:40:0:255
+T:45:0:255
+W:5:1:13
+C:0:0:0:0
+F:FEATHER
+A:FLY
+
+N:341
+X:80:1
+T:35:0:255
+T:30:0:255
+T:6:0:255
+W:40:1:90
+C:0:0:0:0
+F:FLY
+A:FEATHER
+
+N:342
+X:30:1
+T:115:57:57
+T:32:0:255
+T:33:0:255
+W:20:1:30
+C:0:0:0:0
+Z:MIND BLAST
+
+N:343
+X:30:1
+T:115:57:57
+T:32:0:255
+T:33:0:255
+W:20:1:30
+C:0:0:0:0
+Z:TELEKINESIS
+
+N:344
+X:35:1
+T:31:0:255
+W:25:1:40
+C:0:0:0:0
+Z:MIDAS TOUCH
+
+N:345
+X:15:1
+T:31:0:255
+C:0:0:0:0
+Z:COLD TOUCH
+
+N:346
+X:30:1
+T:35:0:255
+W:20:1:27
+C:0:0:0:0
+Z:BLINK
+A:RES_NEXUS
+
+### + To AC ###
+N:347
+X:15:4
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:6:0:255
+W:1:1:5
+C:0:0:5:0
+
+### + To Dam (Only Gloves) ###
+N:348
+X:40:1
+T:31:0:255
+W:1:1:45
+C:10:0:0:0
+
+### + To Hit (Only Gloves) ###
+N:349
+X:35:1
+T:31:0:255
+W:1:1:40
+C:0:10:0:0
+
+# N:index
+# X:power value:max number of time it can appear on one object
+# T:tval:min sval:max sval (up to 20 T: lines)
+# W:mininum player level to create it:rarity1:rarity2
+# C:max to dam:max to hit:max to AC:max to pval
+# F:flags
+
+# Helm of water breathing
+N:350
+X:50:1
+T:32:5:10
+W:20:1:25
+C:0:0:0:0
+F:WATER_BREATH
+
+
+### Amulets And Rings ###
+N:442
+X:15:1
+T:40:0:255
+T:45:0:255
+W:5:1:17
+C:0:0:0:5
+F:STR
+
+N:443
+X:11:1
+T:40:0:255
+T:45:0:255
+W:3:1:12
+C:0:0:0:5
+F:DEX
+
+N:444
+X:13:1
+T:40:0:255
+T:45:0:255
+W:5:1:15
+C:0:0:0:5
+F:WIS
+
+N:445
+X:13:1
+T:40:0:255
+T:45:0:255
+W:1:1:15
+C:0:0:0:5
+F:INT
+
+N:446
+X:7:1
+T:40:0:255
+T:45:0:255
+W:1:1:15
+C:0:0:0:5
+F:CHR
+
+N:447
+X:18:1
+T:40:0:255
+T:45:0:255
+W:7:1:20
+C:0:0:0:5
+F:CON
+
+N:448
+X:15:1
+T:40:0:255
+T:45:0:255
+W:5:1:15
+C:0:0:0:0
+F:SUST_STR
+
+N:449
+X:20:1
+T:40:0:255
+T:45:0:255
+W:7:1:20
+C:0:0:0:0
+F:SUST_CON
+
+N:450
+X:7:1
+T:40:0:255
+T:45:0:255
+W:1:1:15
+F:SUST_CHR
+
+N:451
+X:11:1
+T:40:0:255
+T:45:0:255
+W:1:1:11
+F:SUST_DEX
+
+N:452
+X:13:1
+T:40:0:255
+T:45:0:255
+W:5:1:13
+F:SUST_INT
+
+N:453
+X:13:1
+T:40:0:255
+T:45:0:255
+W:5:1:13
+F:SUST_WIS
+
+N:454
+X:40:1
+T:45:0:255
+C:0:0:0:5
+W:25:1:55
+F:INVIS
+
+N:455
+X:70:1
+T:45:0:255
+C:0:0:0:5
+W:40:1:90
+F:SPEED
+
+N:456
+X:17:1
+T:40:0:255
+T:45:0:255
+W:5:1:16
+C:0:0:0:0
+F:SLOW_DIGEST
+A:REGEN
+
+N:457
+X:20:1
+T:40:0:255
+T:45:0:255
+W:7:1:19
+C:0:0:0:0
+F:REGEN
+A:SLOW_DIGEST
+
+N:458
+X:15:1
+T:40:0:255
+T:45:0:255
+T:35:0:255
+W:10:1:16
+C:0:0:0:4
+F:STEALTH
+A:AGGRAVATE
+
+N:459
+X:7:1
+T:40:0:255
+T:45:0:255
+W:1:1:12
+C:0:0:0:6
+F:SEARCH
+
+N:460
+X:10:1
+T:40:0:255
+T:45:0:255
+W:1:1:12
+C:0:0:0:4
+F:INFRA
+
+N:461
+X:80:1
+T:45:0:255
+W:40:1:95
+C:0:0:0:3
+F:BLOWS
+
+N:462
+X:70:1
+T:45:0:255
+W:38:1:75
+C:0:0:0:0
+F:FLY
+A:FEATHER
+
+N:463
+X:80:1
+T:45:0:255
+W:43:1:85
+C:0:0:0:5
+F:CRIT
+
+
+### Lights ###
+
+N:501
+X:15:1
+T:39:0:255
+T:6:0:255
+W:5:1:15
+F:LITE1
+
+N:502
+X:20:1
+T:39:0:255
+W:10:1:25
+C:0:0:0:0
+F:LITE2
+
+N:503
+X:30:1
+T:39:0:255
+W:20:1:35
+C:0:0:0:0
+F:LITE3
+
+N:504
+X:15:1
+T:39:0:255
+W:10:1:15
+C:0:0:0:0
+F:RES_LITE
+
+N:505
+X:18:1
+T:39:0:255
+W:11:1:17
+C:0:0:0:0
+F:RES_DARK
+
+N:506
+X:20:1
+T:39:0:255
+W:15:1:22
+C:0:0:0:0
+F:SEE_INVIS
+
+N:507
+X:12:1
+T:39:0:255
+W:1:1:10
+C:0:0:0:4
+F:SEARCH
+
+N:508
+X:12:1
+T:39:0:255
+W:1:1:15
+C:0:0:0:4
+F:INFRA
+
+N:509
+X:21:1
+T:39:0:255
+W:5:1:20
+C:0:0:0:0
+Z:ILLUMINATE
+
+N:510
+X:35:1
+T:39:0:255
+W:20:1:27
+C:0:0:0:0
+Z:MAGIC MAP
+
+N:511
+X:30:1
+T:39:0:255
+W:20:1:24
+C:0:0:0:0
+Z:DETECT CURSES
+
+N:512
+X:25:1
+T:39:0:255
+W:20:1:17
+C:0:0:0:0
+Z:DAZZLE
+
+N:513
+X:40:1
+T:39:0:255
+W:20:1:50
+Z:DETECT DOORS AND TRAPS
diff --git a/lib/edit/re_info.txt b/lib/edit/re_info.txt
new file mode 100644
index 00000000..c0e36a92
--- /dev/null
+++ b/lib/edit/re_info.txt
@@ -0,0 +1,183 @@
+# File: re_info.txt
+
+# This file is used to initialize the "lib/raw/re_info.raw" file, which is
+# used to initialize the "monster ego race" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# Version stamp (required)
+
+# Most values can be used with the +, -, % and = operators, = will set the
+# monster value, + and - will modify it based on the normal monster
+# % will apply that percentage to the monster value
+# defaults : NO DEFAULT, MUST precise one
+
+# N:x:ego name
+# G:x:y (x=monster letter, y=colour, use * to use the same as the standard monster)
+# I:speed:(dice)d(side):aaf:ac:sleep
+# W:lev:rarity:weight:xp:place('B'efore or 'A'fter)
+# E:weapon:torso:arms:finger:head:legs
+# B:method:effect:(dice)d(side) (up to x4 lines)
+# F:flags that the standard monster MUST have - at least ONE of the R_CHAR_x
+# flags (if present, to determine which monster letters can have this ego
+# type), plus ALL of the rest
+# H:flags that the standard monster MUST NOT have
+# M:monster flags to add for the ego-type
+# O:monster flags to remove, use MF_ALL for all
+# S:monster spells to add for the ego-type
+# T:monster spells to remove, use MF_ALL for all
+
+V:2.0.0
+
+# A few undeads, to be created by the ANIM_DEAD spell
+
+N:1:Skeleton
+G:s:*
+I:%100:+1d+1:+0:+5:-5
+W:+5:13:%30:%95:B
+F:DROP_SKELETON
+H:UNDEAD | NONLIVING | R_CHAR_Z | R_CHAR_A | R_CHAR_E | R_CHAR_g
+M:DROP_SKELETON | UNDEAD | IM_COLD | IM_POIS | NO_FEAR | NO_CONF |
+M:NO_SLEEP | EMPTY_MIND | COLD_BLOOD | STUPID | EVIL
+O:GOOD | DROP_CORPSE | FRIEND | FRIENDS | ESCORT | ESCORTS | SMART |
+O:DROP_GREAT | DROP_GOOD | RAND_25 | RAND_50 | MORTAL
+T:MF_ALL
+
+N:2:Zombie
+G:z:*
+I:%95:%110d%100:%90:+10:-5
+W:+10:14:%70:%100:B
+F:DROP_CORPSE
+H:UNDEAD | NONLIVING | R_CHAR_Z | R_CHAR_A | R_CHAR_E | R_CHAR_g
+M:DROP_CORPSE | UNDEAD | IM_COLD | IM_POIS | NO_FEAR | NO_CONF
+M:NO_SLEEP | EVIL | EMPTY_MIND | COLD_BLOOD | STUPID | EVIL
+O:GOOD | DROP_SKELETON | FRIEND | FRIENDS | ESCORT | ESCORTS | SMART
+O:DROP_GREAT | DROP_GOOD | RAND_25 | RAND_50 | MORTAL
+T:MF_ALL
+
+N:3:Lich
+G:L:*
+I:%100:+0d+1:+10:+20:-10
+W:+30:22:+0:%200:B
+B:TOUCH:LOSE_DEX:+0d+0
+B:TOUCH:LOSE_DEX:+0d+0
+B:TOUCH:UN_POWER:+0d+0
+B:TOUCH:EXP_40:+0d+0
+F:DROP_SKELETON | SMART | R_CHAR_h | R_CHAR_p | R_CHAR_P | R_CHAR_O
+H:UNDEAD | NONLIVING | R_CHAR_Z | R_CHAR_A | R_CHAR_E | R_CHAR_g
+M:UNDEAD | IM_COLD | IM_POIS | NO_FEAR | NO_CONF
+M:NO_SLEEP | SMART | EVIL | COLD_BLOOD
+O:DROP_SKELETON | GOOD | DROP_CORPSE | FRIEND | FRIENDS | ESCORT | ESCORTS |
+O:DROP_GREAT | RAND_25 | RAND_50 | MORTAL
+S:1_IN_4 |
+S:BLINK | TELE_TO | TELE_AWAY | BRAIN_SMASH | DRAIN_MANA | CAUSE_3 |
+S:BLIND | HOLD | SLOW | SCARE
+
+N:4:Spectral
+G:G:*
+I:+10:%80d%100:+10:+20:-5
+W:+20:20:%10:%110:B
+B:*:EXP_20:+0d+0
+B:*:EXP_20:+0d+0
+F:DROP_CORPSE
+H:UNDEAD | NONLIVING | R_CHAR_Z | R_CHAR_A | R_CHAR_E | R_CHAR_g
+M:UNDEAD | IM_COLD | IM_POIS | NO_FEAR | NO_CONF
+M:NO_SLEEP | PASS_WALL | EVIL | COLD_BLOOD
+O:GOOD | DROP_CORPSE | FRIEND | FRIENDS | ESCORT | ESCORTS |
+O:DROP_GREAT | EMPTY_MIND | RAND_50 | MORTAL
+S:1_IN_5 | BLIND | HOLD | SCARE
+T:MF_ALL
+
+N:5:Captain
+G:*:v
+I:+5:%150d%100:+5:%120:-2
+W:+5:4:%120:%150:A
+B:*:*:+0d+1
+B:*:*:+0d+1
+B:*:*:+0d+1
+B:*:*:+0d+1
+F:R_CHAR_o | R_CHAR_y | R_CHAR_k | BASEANGBAND
+M:FORCE_MAXHP | FRIENDS | SMART | DROP_1D2
+
+N:6:Chieftain
+G:*:*
+I:+10:%200d%100:+10:%120:-3
+W:+5:4:%120:%200:A
+B:*:*:+1d+2
+B:*:*:+1d+2
+B:*:*:+1d+2
+B:*:*:+1d+2
+F:R_CHAR_T | R_CHAR_P | R_CHAR_O | BASEANGBAND
+M:FORCE_MAXHP | FRIENDS | SMART | DROP_1D2
+
+N:7:Shaman
+G:*:r
+I:+0:%90d%100:+10:%90:+0
+W:+2:1:%90:%120:A
+F:R_CHAR_o | R_CHAR_k | R_CHAR_n | BASEANGBAND
+M:SMART | FORCE_MAXHP | DROP_1D2
+O:FRIENDS
+S:1_IN_6 | MISSILE | CAUSE_1 | CONF | BLINK
+
+N:8:Priest
+G:*:G
+I:+0:%90d%100:+10:%90:+0
+W:+3:2:%90:%120:A
+F:R_CHAR_T | R_CHAR_P | R_CHAR_O | BASEANGBAND
+M:FRIENDS | SMART | FORCE_MAXHP | DROP_1D2
+S:1_IN_6 | CAUSE_2 | MISSILE | DARKNESS | CONF | SCARE | BLINK
+
+N:9:Mage
+G:*:r
+I:+0:%150d%100:+10:%120:+0
+W:+5:4:%120:%150:A
+B:*:*:+0d+0
+B:*:*:+0d+0
+B:HIT:HURT:=2d=8
+B:HIT:HURT:=2d=8
+F:R_CHAR_O | BASEANGBAND
+M:SMART | FORCE_MAXHP | DROP_1D2
+O:FRIENDS
+S:1_IN_6 | BA_COLD | BO_FIRE | TRAPS | HEAL | HOLD | S_MONSTER | TPORT
+
+N:10:Archer
+G:*:W
+I:+0:+0d+0:+0:+0:+0
+W:+1:1:%100:%110:A
+F:R_CHAR_y | R_CHAR_k | R_CHAR_O | R_CHAR_o | BASEANGBAND
+S:1_IN_4 | ARROW_2
+
+N:11:Rogue
+G:*:b
+I:+2:+0d+0:+0:+10:-30
+W:+1:2:%90:%100:A
+B:*:EAT_GOLD:+0d+0
+F:R_CHAR_y | R_CHAR_k | R_CHAR_o
+
+# For townpeople
+N:12:Elven
+G:*:*
+I:+2:+0d+0:+0:+0:+0
+W:+0:15:+0:+0:B
+F:WILD_TOWN
+H:ANIMAL
+
+# For townpeople
+N:13:Dwarven
+G:*:*
+I:+2:+0d+0:+0:+0:+0
+W:+0:15:+0:+0:B
+F:WILD_TOWN
+H:ANIMAL
+
+# N:x:ego name
+# G:x:y x is the char, y the attribute, * means the normal one
+# I:speed:(dice)d(side):aaf:ac:sleep
+# W:lev:rarity:weight:xp:place('B'efore or 'A'fter)
+# F:flags that the normal monster *must* have
+# H:flags that the normal monster *must not* have
+# M:monster flags that the ego-monster adds
+# O:monster flags to remove (use MF_ALL for all)
+# S:monster spells that the ego-monster adds
+# T:monster spells to remove (use MF_ALL for all)
diff --git a/lib/edit/readme.txt b/lib/edit/readme.txt
new file mode 100644
index 00000000..4c0ecbe7
--- /dev/null
+++ b/lib/edit/readme.txt
@@ -0,0 +1,96 @@
+# File: a_info.txt
+# This file is used to initialize the "artifact" information for the Angband game.
+# This is were you find Cubragol, The Phial , Ringil etc.
+
+# File: ba_info.txt
+# This file is used used to initialize the "store/building actions type" information for the Angband game.
+# This is where you find the ID numbers for 'Presage fate', 'Play craps' , 'Sell an item' etc.
+
+# File: d_info.txt
+# This file is used to used to set the dungeons for the Angband game.
+# This is where you find 'Barrow Downs', 'The Maze' , 'Mordor' etc.
+
+# File: e_info.txt
+# This file is used to initialize the "ego-item" information for the Angband game.
+# This is where you find 'Helms of the Noldor' , 'Filthy rags of leprousness' , 'Boots of Jumping' etc.
+
+# File: f_info.txt
+# This file is used to used to initialize the "terrain feature" information for the Angband game.
+# This is where you find the ID numbers for 'Underground tunnel' , 'grass with flowers' , 'open floor' etc.
+
+# File: k_info.txt
+# This file is used to initialize the "object kind" information for the Angband game.
+# This is where you find 'Katanas' , 'Mushrooms of Sickness' , 'Jewel Encrusted Crowns' etc.
+
+# File: misc.txt
+# This file contains a lot of 'maximums ' for the Angband game.
+# This is where you find 'Maximum number of skills in s_info.txt' ,
+#'Maximum number of items in k_info.txt' , 'Maximum number of artifacts in a_info.txt' etc.
+
+# File: ow_info.txt
+# This file is used to initialize the "owner info type" information for the Angband game.
+# This is where you find 'Bilbo the Friendly(Hobbit)' , 'Raistlin the Chicken(Human)' ,
+# Inglorian the Mage(Human) etc.
+
+# File: p_info.txt
+# This file is used to initialize the "player race/race mod/class" information for the Angband game.
+# You will find here races like 'Humans' , subraces like 'Vampire', classes like 'Monk'
+
+# File: r_info.txt
+# This file is used to initialize the "monster race" information for the Angband game.
+# You will find here monsters like 'Marylene, Heartbreakeress of the Netherworld',
+# 'The Minotaur of the Labyrinth' , 'Morgoth, Lord of Darkness' etc.
+
+# File: ra_info.txt
+# This file is used to initialize the "randart parts" information for the Angband game.
+# Here you will find info for random artefacts made of 'Mage Staves' , 'Lights' , 'Gloves' etc.
+
+# File: re_info.txt
+# This file is used to initialize the "monster ego race" information for the Angband game.
+# Here you will find ego monster types like 'Spectral','Skeleton','Archer' etc.
+
+# File: s_info.txt
+# This file is used to initialize the "skills" information for the ToME game.
+# Here you will find player & monster skills, 8you can use their IDs in other files(?),
+# You will find skills like 'Bearform-combat' , 'Necromancy' , 'Spell-power' etc.
+
+# File: set_info.txt
+# This file is used to initialize the "lib/raw/set_info.raw" file, which is
+# used to initialize the "item set" information for the Angband game.
+# You find linked Items like 'The bow of Bard' & 'The arrow of Bard'
+# It is like totally unclear to me what this does, especially because
+# the big spider doesnt drop Sting, hint hint !
+
+# File: special.txt
+# Contains terrain parsings for the special levels now being kept in seperate map files
+# You will find there entries as in f_info.txt
+
+# File: st_info.txt
+# This file is used to initialize the "store info type" information for the Angband game.
+# You will find there stores like 'Armoury' , 'Temple' , 'The Mathom-house' etc.
+
+# File: t_info.txt
+# Includes the town definitions of the game Angband
+# You will find here the towns like 'Gondor' , 'Bree' , 'Lothlorien' etc.
+
+# File: t_pref.txt
+# Defines the preferences for the town features
+# You will find there entries as in f_info.txt
+
+# File: tr_info.txt
+# This file comes from Angband64 written by Jurriaan Kalkman
+# and describes the traps items can have
+# You will find traps like 'Summon Fast Quylthulgs Trap' , 'Wisdom Trap' etc.
+
+# File: v_info.txt
+# This file is used to initialize the "vault template" information for the Angband game.
+# You will find vaults like 'The I in the Storm' , 'Greater vault (mortuary temple of sety)' ,
+# 'Lesser vault (amenhotep I)' etc.
+
+# File: W_info.txt
+# This is the wilderness
+# Change the dimensions at your perils, most likely the game will crash !!!
+
+# File: wf_info.txt
+# This file is used to initialize the "wilderness feats" information for the Angband game.
+# You will stuff like 'Ekkaia, the Encircling Sea' , 'mountain' , 'Minas Anor' etc.
diff --git a/lib/edit/s_crypt.map b/lib/edit/s_crypt.map
new file mode 100644
index 00000000..3d6ce71c
--- /dev/null
+++ b/lib/edit/s_crypt.map
@@ -0,0 +1,109 @@
+# Special level "The Forgotten Crypt" in The Pits of Angband
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Written by Mynstral (mynstral@thehelm.com)
+
+%:special.txt
+
+### Guaranteed Monsters
+# Vampire on normal floor
+F:a:1:0:432
+
+# Ghoul on normal floor
+F:b:1:0:418
+
+# Rotting Quylthulg on normal floor
+F:c:1:0:633
+
+# Master Vampire on normal floor
+F:d:1:0:520
+
+# Vampire Lord on normal floor
+F:e:1:0:623
+
+# Greater Rotting Quylthulg on normal floor
+F:f:1:0:802
+
+# Ghast on normal floor
+F:g:1:0:327
+
+# Undead Beholder on normal floor
+F:h:1:0:664
+
+# Thuringwethil, the Vampire Messenger on normal floor
+F:i:1:0:755
+
+# Black Reaver on normal floor
+F:j:1:0:798
+
+### Random Monsters and/or Items
+# Random monster (upto 5 levels ood) on normal floor
+F:&:1:0:*75
+
+# Random monster (upto 11 levels ood) on normal floor
+F:@:1:0:*81
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on normal floor
+F:8:1:0:*79:*77
+
+# Random monster (upto 40 levels ood) and
+# Random object (upto 20 levels ood
+F:9:1:0:*110:*90
+
+# Random monster (upto 3 levels ood)
+F:-:1:0:*73
+
+# Random object (upto 7 levels ood)
+F:=:1:0:0:*77
+
+### Guaranteed Items
+# The Shadow Cloak of Luthien on normal floor
+F:1:1:0:0:0:0:49
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XA.%@=-=-X8XX6...XX.XXLLL..c..LLLXX.XX...7XX8X=-=-...5X
+D:X.%%@=-=-X99X.....X..XLL..X%X..LLX..XhVV..X99X=-=-..GGX
+D:X%%@@...XXX9XX....XX.XX...X.X...XX.XXVVVVXX9XXX=-=.XGGX
+D:X@@@....X8X-=XgggggX..X..dX4Xd..X..XWWWWWX-=X8X-=-.XGGX
+D:X......XX%XX=XXgddgXX.XX8GXXXG8XX.XXWWWWXX-XX%XX...XGGX
+D:XIXIXXIX*X=X-=XgddggX..X8G^.^G8X..XWWWWWX-=X.X.X&&&XGGX
+D:XXXIXIXX*X-XX=XXggggXX.XXG^.^GXX.XXWWWWXX-XX.X.XX&&XGGX
+D:XXXXXIX**X=-X=-XIIXXXX..XG^.^GX..XVWWWVX=-XX.XddX@@XGGX
+D:X^^^^XX**X=-XX=XXIXIIXX.XX^.^XX.XXVVVVXX-XX%.XedXX@XGGX
+D:X^^f^Xe**X%%.X=-XXIXXIXbbX^.^XbbX.VV.XX=-XbX.XXXIX@IIGX
+D:X^^^XXe..X...XX=-XXXIXXXbXX.XXbXX...XX=-XXbX.XaaaXXXIGX
+D:X^^XXbbb.XGGG.XX=-XXIIXXbbXDXbbX...XX=-XXbbX.XaaaaXXIGX
+D:X^XXcbab.XVdG.cXX=-XXXIXXabXbaXX.XXX=-XXbbbX.XaaaaaXXfX
+D:X%XbbbbbbXVWG.%.XX.DbXDXXXbXbXXXDXbD.XX....G.XGGGGGGX%X
+D:XX.bababa%eWG.%.BXXXbcbbbbX.XbbbbcbXXXC...fX.%.......XX
+D:X%XbbbbbbXVWG.%.XX.DbXDXXXbXbXXXDXbD.XX....G.XGGGGGGX%X
+D:X8XXcbab.XVdG.cXX=-XXX.XXabXbaXXLXXX=-XXbbbX.XaaaaaXX.X
+D:X88XXbbb.XGGG.XX=-XX...XbbXDXbbXLLLXX=-XXbbX.XaaaaXXX.X
+D:XXXIXXe..X...XX=-XX.GGXXbXX.XXbXXILIXX=-XXbX.XaaaXXXX.X
+D:X9889Xe**X%%.X=-XXG.GdXbbX^.^XbbXILLIXX=-XbX.XXXIXhGG.X
+D:XXIXXXX**X=-XX=XXdG.GXX.XX^.^XX.XXILIIXX-XX%.XedXXXXX.X
+D:X99999X**X=-X=-XGGG..X..XI^a^IX..XILLIIX=-XX.XddX..eeeX
+D:XXXXIXXX*X=XX-XX....XX.XXI^a^IXX.XXILLIXX=XX.X.XX.GGGGX
+D:X^^^^^cX*X-X=-X.....X..X.I^a^I.X..XIILLIX=-X.X.Xdddd..X
+D:XllllX^XX%XX=XXG.GGXX.XX.IXXXI.XX.XXIILIXX-XX%XXXXXXX.X
+D:X^^^cl^=X8X-=XeG.GeX..X...X4X...X..XILLLIX-=X8X.aaaaaaX
+D:XLLX^l^-XXX9XXGG.GXX.XX...X.X...XX.XXLLLLXX9XXX.GGGGGGX
+D:X..L^l^=-X99X.....X..XWW..X%X..WWX..XLLLL.X99XXbbbbb..X
+D:X7.L^l^=-X8XX5...XX.XXWWW..c..WWWXX.XXLL.AXX8XXbbbbb.6X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXIIIIXIIIIXXIIIXIIIIXXIIIXXXXggggXc..cXaaaaXbb.CX
+D:XIIIIIXIXXIIIXXIIXIXIXIXXIXXIXIXXXXgddg%....%aaaa%bb..X
+D:XIXXXIXIXXXXXXXXIIIXIXIIXIXXIXIXXXXggggXc..cXaaaaXbbbbX
+D:XIXXXIIIXIIIIIIXXXXXIXXIXIXIIXIXXXXXXXXXXIIXXXXXXXXXXXX
+D:X..XXXXXXIXXXXIXIIIXIXIIXIXIXXIXXXXVVVjXddddXe..eX....X
+D:XB.IIIIIXIIIXIIXIXIXIIIXXIXIXIIXIIIVVVEX....%.ee.%.hh.X
+D:X..XXXXIXXXIXIXXIXIXXXXXIIXIXIXXIXXVVVjXddddXe..eX....X
+D:XIXXXIXIIIXIXIIIIXIIIIXIIXXIXIXXIXXXXXXXXXXXXXXXXXXDDXX
+D:XIXXXIXXXIIIXXXXXXXXXIXIXXIIXIIIIXXGGGGXgggdddeIVX....X
+D:XIIXXIXXXXXXXIIIIXXIXXXIIIIXXXXXXXXE.heDgggaaaiG1X....X
+D:XXIIIIIIIIIIIIXXIIIIXIIIXXXXXXXXXXXGGGGXgggdddeIVX..j>X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting location
+P:17:29
diff --git a/lib/edit/s_death.map b/lib/edit/s_death.map
new file mode 100644
index 00000000..398b5fd1
--- /dev/null
+++ b/lib/edit/s_death.map
@@ -0,0 +1,104 @@
+# Special level "Deathwatch" in the Orc Caves
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Altered by Mynstral (mynstral@thehelm.com)
+
+%:special.txt
+
+### Guaranteed monsters
+# Snaga on normal floor
+F:a:1:0:118
+
+# Cave orc on normal floor
+F:b:1:0:126
+
+# Hill orc on normal floor
+F:c:1:0:149
+
+# Black orc on normal floor
+F:d:1:0:244
+
+# Half-orc on normal floor
+F:e:1:0:264
+
+# Uruk on normal floor
+F:f:1:0:313
+
+# orc captain on normal floor
+F:g:1:0:285
+
+# Lagduf on normal floor
+F:h:1:0:140
+
+# Grishnakh on normal floor
+F:i:1:0:186
+
+# Golfimbul on normal floor
+F:j:1:0:215
+
+### Guaranteed items
+# Thalkettoth on normal floor
+F:1:1:0:0:0:0:28
+
+# Maedhros on normal floor
+F:2:1:0:0:0:0:64
+
+# Cammithrim on normal floor
+F:3:1:0:0:0:0:53
+
+### Dungeon Design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X XXXXXXXXXXXX X
+D:X X..........X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X
+D:X X....>.....X X.XdX.X.X.XcX.X.X...XcX.X.XcX.X.XgXd+2X X
+D:X X..........X XDXDXDXDXDXDXDXDX...XDXDXDXDXDXDXDXDXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X
+D:X XXXXXDXXXXXX X...............D...D...............X X...f............a...XXXXX.......b..f....a....+1X X
+D:X X.X XDXDXDXDXDXDXDXDX..cXDXDXDXDXDXDXDXDX X........b...........XXXXX...a..........b.....XXX X
+D:X X.X X.XcX.XcXdX.X.X.X...XcX.XdXcX.X.X.XgX XXXXXXXXXXDDXXXXXXXXXXXXXXXXXXXXXXXXDDXXXXXXXXX X
+D:X X.X XXXXXXXXXXXXXXXXX.c.XXXXXXXXXXXXXXXXX XXXXXXXXXXDDXXXXXXXXXXXXXXXXXXXXXXXXDDXXXXXXXXX X
+D:X X.X XXX X...X X...........f...a....XXXXX....b.a...........b.X X
+D:X XX.XX X.XXXXXXXXXXXXDDDXXXXX X..f...b.............XXXXX..a....f.....b..a...X X
+D:X XX...XX XXXDXXXXXXXXX.......c.XX XXXXXXXXXXDDXXXXXXXXXXXXXXXXXXXXXXXXDDXXXXXXXXX X
+D:X XX.....XX XdD........D...c......dX X........a...............a....................X X
+D:X XX.......XX XXXDXXXXXXXX......c....X Xf....b..........f............a.........f.....X X
+D:X X.........X XeX XX.........XX X.............a.......b...........a...........X X
+D:X XXXXX.XXXXX X.X XXXXDDDXXXX X....a...............................a........X X
+D:X X.X X.X X...X XXXXXXXXXXXXXXXXXXXXX...XXXXXXXXXXXXXXXXXXXXXXX X
+D:X X.X X.X X...X X...X X
+D:X X.X X.X XX...XX X.b.X X
+D:X X.X X.X XX.....XX X...X X
+D:X XXDXX XXXX X.X XX.......XX X..bX X
+D:X X...XXXX..X XdX XX...ccc...XX X...X X
+D:X X...+..D..X X.X XX....ccc...dXX X...X X
+D:X X...XXXX..X X.X XX.d..ccicc....XX XXXXXXXXXXXXXDDDXXXXXXXXXXXX X
+D:X XX.XX XXXX X.X XX......ccc..g...XX XX......a...............f...XX X
+D:X X.X X.X XX...g...ccc.......XX XXX..f.........................XX XXXXX X
+D:X X.X X.X X......g.........g..X XX..................b....a.......XX Xa.aX X
+D:X X.X XgX XXXX..XXXXXXX..XXXXXX XX.....a.........a..............a..XX X.a.X X
+D:X X.X X.X X..X X..X XXXXXXXX..........f........................XX XDXXX X
+D:X X.X X.X Xd.XXXXXXX..XXXXXXX X.....D...b.................b...f...........XXXXXXXXXXX.X X
+D:X X.X X.X X...c.......D.....X X.....D...........a..h.............a........D......a....X X
+D:X X.X X.X X.......c.g.D.....X X...XXXX.....b.............................XXXXXXXXXXXX.X X
+D:X XXXX.XXXX X.X XXXXXXXXXXXXXXXX..XXXXXXX X...X XX..............a......a...........XX X.X X
+D:X X.......X X.X X........XXXXXXX...X XX.........f.............f.......XX X.X X
+D:X XXX...XXX X.X X..d...............X XX.....b...........b.........f.XX XaX X
+D:X X.......X X.X X........XXXXXXX...X XX..........b................XX X.X X
+D:X XXXX.XXXX X.X XXXXXXXXXX XXXXX XXXXXXXXXXXXDDDDDXXXXXXXXXXXX X.X X
+D:X X.X XDXXXXXXXXXXXXXXX X.....X X.X X
+D:X X.X X..d...e......d.XXXXXXXXXXX XXXXXXXXXXXX X.b...X X.X X
+D:X X.X X....e..g.......D.........X X.d..gg..eeX XXX.....XX X.X X
+D:X X.X XXXXX X..g..d.....e...XXXXXXXXDDXXXXXXXX....gg..eeXXXXX XX...XXX..XXX XXXXXXDXX X
+D:X X.X XeeeX XDXXXXXXXXXXXXXXX Xg.d.......D.e..e..gg..eej+3+% XX....XXX....XXXXXX XXX...D..aX X
+D:X X.X Xeg.X XX.XX X....e....eD.e.....gg..eedXXX% X.............X...X XaD...X...X X
+D:X XXXX.XXX XX+XXXX...X X.d........XXXX....gg..eeXX % XXXXX XXXXXXXXXXXX..D...X XXX..aX...X X
+D:X X......X XX.......X XXXX...e...d..XXXX...dgg..eeX % X...X XX.....D..XXXXXX XXXXXXXDXX X
+D:X X......X X.g.....XXXXXX X..D....g..e..Dd.XXXXXXXXXXXX % XXXDXX X......X..X....X X...X X
+D:X X......X X...d...DeeeeX X..XXXXXXXXXXXX..X + X...X XXXXXXXX..X....X X...X X
+D:X X......X X.....e.XXXXXX XXXX XXXX % X...XXXXXX X....D..D....X XXXXXXXXDXDXXXX X
+D:X XXXDDXXXXXXXXXXXXXX+XXXXXX % X....X...X X..XXX..XXXXXXXXX X.....a..X....X X
+D:X X........%........X %+%%....D...XXXXXX.D..D.....+.X X........X....X X
+D:X XXXXXXXXXXXXXXXXXXX XXXXXX..........X..X.....XXX XXXXXXXXXXXXXXX X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting Location
+P:51:125
diff --git a/lib/edit/s_doom.map b/lib/edit/s_doom.map
new file mode 100644
index 00000000..5be3b67d
--- /dev/null
+++ b/lib/edit/s_doom.map
@@ -0,0 +1,226 @@
+# Mount Doom
+
+### Terrain Features
+# Permanent Wall
+F:X:177:0
+
+# Lava Wall
+F:#:177:0
+F: :177:0
+
+# Great Fire
+F:$:178:0
+
+# Fire
+F:%:205:0
+
+# Hidden Door
+F:+:48:0:0:0:0:0:0:0:177
+
+# Normal Door
+F:D:32:0
+
+# Shallow Lava
+F:.:86:0
+
+# Deep Lava
+F:L:85:0
+
+# Treasure (random) on shallow lava
+F:*:86:0:0:*
+
+# Trap (random) on deep lava
+F:^:85:0:0:0:0:0:*
+
+# Trap (random) on shallow lava
+F:t:86:0:0:0:0:0:*
+
+# up staircase
+F:<:6:0
+
+### Guaranteed Monsters
+# Greater Balrog on deep lava
+F:A:85:0:807
+
+# Greater Balrog on shallow lava
+F:a:86:0:807
+
+# Lesser Balrog on deep lava
+F:B:85:0:996
+
+# Lesser Balrog on shallow lava
+F:b:86:0:996
+
+# Pit Fiend on deep lava
+F:C:85:0:812
+
+# Pit Fiend on shallow lava
+F:c:86:0:812
+
+# Great Wyrm of Power on deep lava
+F:E:85:0:847
+
+# Great Wyrm of Power on shallow lava
+F:e:86:0:847
+
+# Bone Golem on deep lava
+F:F:85:0:1013
+
+# Bone Golem on shallow lava
+F:f:86:0:1013
+
+# Dracolisk on deep lava
+F:G:85:0:703
+
+# Dracolisk on shallow lava
+F:g:86:0:703
+
+# Nycadaemon on deep lava
+F:H:85:0:719
+
+# Nycadaemon on shallow lava
+F:h:86:0:719
+
+# Barbazu on deep lava
+F:I:85:0:720
+
+# Barbazu on shallow lava
+F:i:86:0:720
+
+# Plasma Hounds on deep lava
+F:J:85:0:726
+
+# Plasma Hounds on shallow lava
+F:j:86:0:726
+
+# Hell knight on deep lava
+F:K:85:0:731
+
+# Hell knight on shallow lava
+F:k:86:0:731
+
+# Nightcrawler on deep lava
+F:M:85:0:744
+
+# Nightcrawler on shallow lava
+F:m:86:0:744
+
+# Aether Hound on deep lava
+F:N:85:0:811
+
+# Aether Hound on shallow lava
+F:n:86:0:811
+
+# Eye druj on deep lava
+F:O:85:0:749
+
+# Eye druj on shallow lava
+F:o:86:0:749
+
+# Skull druj on deep lava
+F:P:85:0:750
+
+# Skull druj on shallow lava
+F:p:86:0:750
+
+# Great Hell Wyrm on deep lava
+F:Q:85:0:756
+
+# Great Hell Wyrm on shallow lava
+F:q:86:0:756
+
+# Nightwalker on deep lava
+F:R:85:0:768
+
+# Nightwalker on shallow lava
+F:r:86:0:768
+
+# Osyluth on deep lava
+F:S:85:0:773
+
+# Osyluth on shallow lava
+F:s:86:0:773
+
+# Great Wyrm of Many Colours on deep lava
+F:U:85:0:790
+
+# Great Wyrm of Many Colours on shallow lava
+F:u:86:0:790
+
+# Horned Reaper on deep lava
+F:V:85:0:811
+
+# Horned Reaper on shallow lava
+F:v:86:0:811
+
+# Bronze Golem on deep lava
+F:W:85:0:1015
+
+# Bronze Golem on shallow lava
+F:w:86:0:1015
+
+### Random Monsters and/or Items
+# Random monster on deep lava
+F:!:85:0:*99
+
+# Random monster on shallow lava
+F:1:86:0:*99
+
+# Random monster (upto 10 levels ood) on deep lava
+F:@:85:0:*109
+
+# Random monster (upto 10 levels ood) on shallow lava
+F:2:86:0:*109
+
+# Random monster and
+# Random object on deep lava
+F:&:85:0:*99:*99
+
+# Random monster and
+# Random object on shallow lava
+F:7:86:0:*99:*99
+
+# Random monster (upto 10 levels ood) and
+# Random object (upto 5 levels ood) on deep lava
+F:(:85:0:*109:*104
+
+# Random monster (upto 10 levels ood) and
+# Random object (upto 5 levels ood) on shallow lava
+F:9:86:0:*109:*104
+
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X #%%NNLL...JJJ....LL# ############## X
+D:X ##### #NNNN...Ljjjjj..LLL# #############################################..1!!!!...L### X
+D:X##.LL## #nNNN...LLJJj.LLLLL# #L....&!&!&....L%%%%%%%L..mRR%R%%M%MML%LL...DL...!1&..@L%%# X
+D:X#LL<..# #nn.LL.LLLL...%%%LL# #..##########################################LLL....LLL%%%# X
+D:X##%LL## #....LLL%%LLL..^LLL# #.L# #LL2.t..q.LLL## X
+D:X ###+# #D##############+#######.L# ##%%.LLLL&L...# X
+D:X #!# #.# #.......L%%# ##%%LL..2...t.## X
+D:X #^# #.############ ##########+# XXXXXXXXXX ##.9.t.LLLLL## X
+D:X #.# #LL%%%%LL...p# #11111# X########X ###############.2..LQ#+# X
+D:X ##.# ############D## #11211# X#9....9#X #o.....t...# ###^L..#(# X
+D:X #L## ##%%V## #12221# XXXXXX#..$$..#XXXXXX#LLLLKkk...# ###D#### X
+D:X ##!# ##.VH^%## #12221# X######t....m######X#LLLLkkk.LL# #.# X
+D:X #.# ##.iH%%hv## #11211### X#sSSSrrt%.mVVVLLe#X#.LL.kkk...# ##.# X
+D:X ###D######### #tiI%HHhvL# #11111+9# X#rRssRr.%.mVvvm..#X#%...LLL...# ##Lo###### X
+D:X #.^t^LLL...L## #.LIH%Hc..# ######### X#.MmmM..%..MMLLL.#X#%%......L&# ##.L##EBBB# X
+D:X #.jJ%%%L....L# ##..ICCL.## X#.L..L..%ttL.....#X########D### #.####LAAB## X
+D:X #JJJJL%LLL&..# ##..L.L## X#9LLL...%..LL(LLq#X #..L..# #.LL..LB%%L# X
+D:X #J%J..LLL%%LL## ##.t.## X######......######X #L.#### ###..LL%%%L## X
+D:X #jJJ^..bL%LL..## ##D################# XXXXXX#.LUUL.#XXXXXX #.L# #.PL%%%@(L# X
+D:X ##....BABLL..L.## #.uLL^L..L%^^..L%%# X#.L%%LL#X #L.#### ###.L%LL..##X
+D:X ##....B%%L.....## #################L# X#LLL..t#X #..twW# #L..LL...+pX
+D:X ###....LLL...LLL####################.# X#%L..7.#X #####L# ###LL...1###oX
+D:X #9+L%%L...LLL....D.+..%%oF.%%^..%%LL.# X#LLLLt.#X #p# #%%%!@..## #tX
+D:X ##################L###.L###..###.L#### X#7tt.LL#X #.# ######### #EX
+D:X ##################.# ############## X#.LLLL.#X ######D###################LX
+D:X ##11!!!&LL.+(#L# X#LL%%LL#X #G..LLL.LL...D..LL....^LLL%X
+D:X ##1!!!%%%%Lp###L# X#L%%%%Q#X #..LF....K...##############X
+D:X ##!!%%%%%LLL..#.# XXXXDDXXXX########.LLLL..KKK..#### X
+D:X ##.LLLLLLL...+.# #%%%%%%%%%%%%%+LL7..LL.k..L+o7# X
+D:X ############### ############################### X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting location
+P:6:6
diff --git a/lib/edit/s_factory.map b/lib/edit/s_factory.map
new file mode 100755
index 00000000..111829f1
--- /dev/null
+++ b/lib/edit/s_factory.map
@@ -0,0 +1,238 @@
+# Map "s_factory.map"
+#
+# Special Level "Foul Factory" in the Illusory Castle
+#
+# Created for ToME 3.x on 11/11/2003
+# Written by Lord Dimwit (lorddimwit@hotmail.com)
+#
+# Middle-game dungeon
+# Comments: This level isn't designed to kill the player, really, just
+# induce such severe aggravation that their head explodes. There are
+# two parts of it, the "abusive trickery" part that leads the player
+# through a horrendous maze of strategically placed glass walls, permanent
+# walls, and ethereal walls (like permanent walls only invisible, very awful),
+# followed by a "Factory" stage that follows more traditional patterns of
+# throwing monsters systematically at the player.
+
+# Backported to ToME 2.x by Massimiliano Marangio on 02/07/2004
+
+# Replaced the letter : by R for Rubble
+# Changed the starting position to 21:51
+# Corrected the exits of the jumpgates
+
+### F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>:<mimic>
+
+### Terrain Features
+
+
+# Permanent wall
+F:X:61:4
+
+# Fake wall
+F:I:189:0
+
+# Ethereal wall
+F:#:214:0
+
+# Copper Pillar
+F:;:213:0
+
+# Mountains
+F:M:97:0
+
+# granite
+F:G:57:4
+
+# Floor
+F:.:1:0
+
+# Deep Water
+F:~:187:4
+
+# Ash
+F:,:93:4
+
+# Fire
+F:%:205:0
+
+# Deep lava
+F:L:85:0
+
+# Shallow lava
+F:l:86:0
+
+# Glass Wall
+F:_:188:0
+
+# Rubble
+F:R:49:0
+
+# Trees
+F:T:96:0
+
+# Tainted water
+F:t:174:0
+
+# Chasm
+F:C:87:0
+
+# up staircase
+F:<:6:0
+
+# down staircase
+F:>:7:0
+
+# between gate 1
+F:1:160:6:0:0:0:0:0:845
+
+# between gate 2
+F:2:160:6:0:0:0:0:0:846
+
+# between gate 3
+F:3:160:6:0:0:0:0:0:4370
+
+# between gate 4
+F:4:160:6:0:0:0:0:0:3339
+
+# between gate 5
+F:5:160:6:0:0:0:0:0:4119
+
+# between gate 6
+F:6:160:6:0:0:0:0:0:6659
+
+# between gate 7
+F:7:160:6:0:0:0:0:0:9257
+
+# between gate 8
+F:8:160:6:0:0:0:0:0:8018
+
+# between gate 9
+F:9:160:6:0:0:0:0:0:9298
+
+# between gate A
+F:A:160:6:0:0:0:0:0:805
+
+# between gate B
+F:B:160:6:0:0:0:0:0:831
+
+# between gate D
+F:D:160:6:0:0:0:0:0:809
+
+# between gate E
+F:E:160:6:0:0:0:0:0:2826
+
+# between gate F
+F:F:160:6:0:0:0:0:0:2831
+
+# between gate H
+F:H:160:6:0:0:0:0:0:4631
+
+# between gate J
+F:J:160:6:0:0:0:0:0:7198
+
+# between gate K
+F:K:160:6:0:0:0:0:0:7990
+
+# between gate N
+F:N:160:6:0:0:0:0:0:9253
+
+# Treasure on floor
+F:$:1:0:0:*65
+
+# Trap (random) on floor
+F:^:1:0:0:0:0:0:*
+
+
+### Monsters
+
+# Eog Golem on floor
+F:g:1:0:530
+
+# Clay Golem on floor
+F:a:1:0:261
+
+# Aquatic Golem in water (OK, just for show)
+F:?:187:0:899
+
+# Stone Golem on floor
+F:b:1:0:323
+
+# Iron Golem on floor
+F:c:1:0:367
+
+# Colbran on floor
+F:d:1:0:435
+
+# Mithril golem on floor
+F:e:1:0:464
+
+# Colossus on floor
+F:f:1:0:558
+
+# Drolem on floor
+F:h:1:0:691
+
+# Demonic Q on shallow lava
+F:Q:86:0:727
+
+# Livingstone on floor
+F:i:1:0:336
+
+# Random monster (upto 8 levels ood) on normal floor
+F:&:1:0:*58
+
+
+### Items
+
+# Broken Stick
+F:s:1:0:0:727
+
+
+### Guaranteed Items
+
+# The Boots of the Machine
+F:*:205:0:0:0:0:218
+
+
+### Level layout
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X..e.e...I.......Xe..c.a..ca.c.....1X..3..XQQX,llllllllllllll2XX#Gi.X.X..XLABLX..X
+D:X.XXX...XXX.....XXXe.c..XXX__XX__XXXX.;.;.XllX,ll,ll,XXXXXXXXXXi.X#.XiXXXXL%%LXXXX
+D:X&XXXe.XX~XXeeeXX~XXe..XX~~~~~~ttttXX.....X,,,,Ll,ll,X..XII.X.X.i.XXG_XXXXL%%LXXXX
+D:X..&..XX~~~XXeXX~?~XX.&X~~~~t~ttttttX.;.;.X,lllll,ll,XX_..XX.XX#X..X#XXf.X_GG_X.fX
+D:XGXGXGX?~~~~_c_~~~~~X.&XX~~~~t~ttttXX.....X,L,,,,,lL,.X.#XXi..G.XXiX..XX.........X
+D:X.....XX~~?XXcXX~~~XXa..XXX__XX__XXXX.;.;.X,L,.XXX%L%XXXXcXX.XXX.X.X.X.XX.X.ff.X.X
+D:XXgXgXgXX~XXcccXX?XXXXX.a^^a.^^a...bXXXGXXX%L%XX.XX%XXa.aXIX.Xi#.XiXI.X.X........X
+D:XgXgXgXgXXX^^^^^XXX,ccXXXXXXXXXXXb.XX#...#XX%XX.XI_XX....X.X.#XXXIX.#GX.X.X....X.X
+D:X.......4X.^^5^^.X.c.c..c..c.c..c.XX.#...#.XXXIXX.X.a.c..XXi..I.X._.X.XXX...&&...X
+D:X..&&...XXXXXXXXXXc,c,c.XX_XX..ccXX..#...#..XX#iiX.X.a..a.XX.#XX._X.XX.XX.X....X.X
+D:X......XXEX,,,c,c,cc,ccXXMRMXXc.XX...#...#...XXX#iXXXXXc..IXGX.XXiX.....X........X
+D:XXXXXXXX..X,,,,,,,,,,,XXM..RMXXXX$$XXX...XXX$$XX..XX_GXXXXXX.Ii.X_X.X#XXX.X....X.X
+D:XT.T._.g.gXX,C,,,.,C,c_M.R.R.MXX$$$XXX...XXX$$$XX..XIXIXII.i.XX_.X.XX.XXXXGGGGGGXX
+D:X.T.T_.....XXlXXXXXlXFXXM..RMXX$$XXXXX...XXXXX$$XX.#.XX.X_X_XXI#.XXIIX.Xeee...eeeX
+D:X..T._.g..g.XlX_D_XlXXXXXM.MXX$$$#....%%%....#$$$X.X..XX_G.#.X.XXIXX..cXXXX...XXXX
+D:XMMMMX...&..XlX_._XlX6..XXXXXX$$$#....%*%....#$$$X._X#iX.XX..G_Xi.XXd..XLl#_._#lLX
+D:Xs.s._..&.&.XlX_._XlX..gg....X$$$#....%%%....#$$$X.IIX.X..XIXX.X.G#X..dXLl#_._#lLX
+D:X.s.s_g....XXlXXGXXlXX.g..d&.XX$$XXXXX...XXXXX$$XXXX._XG#X.XX.X_X.XX.c.XXXX...XXXX
+D:XXXXXXXXXXIXLLLXGXLLLXgg.g.d..XX$$$XXX...XXX$$$XX<...XiXX.X.Xi.X.X.Xd..X.........X
+D:Xgg.gXg.gXIXL%LXGXL%LXGXXX__XXXXX$$XXX...XXX$$XXXXXXIXXiX#XX#XX#X_XX...XXXXXXXIXXX
+D:X^^X^X^X^X^XX_XXGXX_XXGXXg..g.%.XX...X...X...XX.GI.X._iXXG...I..I.GX..dIX#I#I#I#IX
+D:X^^X^X^X^X^Xhl,&c.a&g.l.XX.g.g%RRXX..X###X..XX..#_X..XXX_iXXIXiXi_.Xc..X.IX.XXXIXX
+D:X^^X^X^X^X^X&,,,l&,lac.&.__.g.%.R.XX...>...XX#X.X..XX#.._X.X.X.#.XGX.X.XX_XX.X#i.X
+D:XH.Xg.gXg.gXla,ca&,f.fl.leXX..%R.RRXX.....XX.G.XX#XXI.XX.#.XGXXXiX.#X.XX.i._X.XGX#
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXGXXXXXXXG.X..X#XXX.XX.XXI._XIX.XIXXI#.XXX.X
+D:X,.,G,&&,ee,ff,hgg,&&,,,.,,I7XXXc..aX.;.;.X&..XXXG#XX.G.XXX..XG######.G.#..##..iXX
+D:X^X,G.&&.ee,ff..gg,&&,.,,,,XXX..MRM.X.....X.....XXX.IIX.XGI.XX..IXXXXXXXXXXX._.X._
+D:X^X,XXXXXXXXXXX.XXXXXX,,.XXX..$.....X.;.;.Xh..&...GXXXGXi#IXX.IXX..#.....#.XX##XXX
+D:X^X,llL,LlLL,LXXXlll,XXXXX..aMR..$.cX.....X.....XXXX8XXXXXXXX#IX###..##.#..#XI.XKX
+D:X^XlLCCCCCCCCLllll%%l.R.R.R.R..M.R..X.;.;.X&..XXX.#X#.i.#.XXX#X...###.#.##.#.X#IXX
+D:X^X,lL,llL,Ll,XXX,lllXXXXXc.M..R.c..X.....XXXXX#.#.XIX#Xi.X...X###.#####.#...X#XXX
+D:X^X,XXXXXXXXXXX.XXXXXX,.,XXX...$.M..X.;.;.Xh.##i#.#XX_IX.#X.##I....#.#.###.##X#I.X
+D:X^X.G,&&,,gg.&.,ee,ff,,.,.,XXXa..R..X.....X..#.###.XIXX.X.X.##XX####..#..###II.X.X
+D:X,,,G,&&,,gg.&h.ee,ff,..,.,I^XXXM..9X.;J;.Xh.##.###..iiX#.X....II.....#....IX..XNX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+
+### Starting location
+P:21:51
diff --git a/lib/edit/s_gates.map b/lib/edit/s_gates.map
new file mode 100644
index 00000000..3ac7ccbf
--- /dev/null
+++ b/lib/edit/s_gates.map
@@ -0,0 +1,117 @@
+# Special Level "The Dimensional Gates" in the Pits of Angband
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Written by Mynstral (mynstral@thehelm.com)
+
+%:special.txt
+
+### Gauranteed monsters
+
+# Quylthulg on normal floor
+F:a:1:0:342
+
+# Demonic Quylthulg on normal floor
+F:b:1:0:727
+
+# Draconic Quylthulg on normal floor
+F:c:1:0:759
+
+# Rotting Quylthulg on normal floor
+F:d:1:0:633
+
+# Greater Draconic Quylthulg on normal floor
+F:e:1:0:801
+
+# Greater Rotting Quylthulg on normal floor
+F:f:1:0:802
+
+# Great Hell Wyrm on normal floor
+F:g:1:0:756
+
+# Master Quythulg on normal floor
+F:h:1:0:821
+
+### Random monsters and/or items
+
+# Random monster (upto 5 levels ood) on normal floor
+F:&:1:0:*90
+
+# Random monster (upto 11 levels ood) on normal floor
+F:@:1:0:*96
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on normal floor
+F:8:1:0:*94:*92
+
+# Random monster (upto 40 levels ood) and
+# Random object (upto 20 levels ood
+F:9:1:0:*125:*105
+
+### Guaranteed items
+
+# The Ring of Power 'Narya' on normal floor
+F:1:1:0:0:0:0:10
+
+
+### Level design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X*****...@%...aX.X9@********%%%%%%X9.VV....Xd.............A^^.......dX
+D:X*****...@%...aX.X@@********%%%%%%X.VVVV.X.XX.............B^^........X
+D:X*****...@%...aX.X99*XXX****%%88%%XVVWWVVX..XX.............^^.......9X
+D:X*****...@%...aX.X@@XXdXX***%%88%%XVVWWVVX...XX............^^.......CX
+D:X*****...@%...aX.X@XX...XX**%%%%%%X.VVVV.X.X..XX..........5^^........X
+D:X........@%...aX.XXX.....XX*%%%%%%X9.VV..X.XX..XX.........F^^.......dX
+D:X%X......@%...aX.X........XIXXXXXXXXXXX..X..XX..XXXXIXXXXXXXXXXXXXXXXX
+D:X.XXX....@%...aX.X..........XXX..>X...X..X...XX..XXXaXaXaXaXaXaXaXaXaX
+D:X...XXX..@%...aI.X..........XXX7..X...D..X.X..XX..XX.................X
+D:X.....XXX@%...aX.X..........XXXXXXXXXXX..X.XX..XX..XX................X
+D:X.......XXX...aX.X..........XXXXXXXaG....X..XX..XX..XX...............X
+D:X..X......XXX.XX%XX^^^^^X...XXXXXXXaG....X...XX..XX..XX..............X
+D:X^^XX.......XXX***X^^^^^X...XIIII7XXXXXXXXXX..XX..XX..XXXXXXXXXXXX+X8X
+D:X^^XX.........X.6.X^^^^^X...XIXXXXX&&&&&&&&XX..XX..XX...........cX.XXX
+D:X..XXX........X***X^^^^^X...XIXXXXX.........XX..XX..XXXXXXXXXXXXXX..XX
+D:X^^X8X........XXXXX^^^^^X...XIIIIIXVVV.......XX..XX.............bXX..X
+D:X..X8XX................XX...XXXXXIXVVVV.......XX..XXXXXXXXXXXXXXXXXX+X
+D:X^^X88X................XX...XIIIIIXVVVVVV..@...XX.^^^^^^^^^^^^^a.....X
+D:X^^X99XX...............XX...XIXXXXX4..VVVV......XXXXXXXXXXXXXXXXXXXXXX
+D:X..X999X...............XX...XIXXXXXXXXX.VVVV....***********.........bX
+D:X^^XIIIXX..............XX...XIX...5..fX...VVVVV.@....................X
+D:X..X....X........d.....XX...XIXf......X...VVVVVVV...............@....X
+D:X^^X....XX............XXX...XIXXXXXXXXX.......VVVVVVV................X
+D:X^^X&&&&&X............XXX...XIIIIIXe...........VVVVVVVVVVVV..........X
+D:X..X%%%.%XX..........XXX....XXXXXIX.............@VVVVVVVVVVVV@.......X
+D:X^^X88%.%8X.........XXX.....XXXXXIX...................VVVVVVVVVV.....X
+D:X..X%%%.%%XX........XX......XXXXXIX@.....................VVVVVVVVVVVVX
+D:X^^X......cX......XXXX......XXXXXIX........@..........@....VVVVVVVVVVX
+D:X^^^......cXX888XXXXX......dIIIIIIX.........................b.VVV...6X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXgLLLLLgXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLLLXXLLLLLLXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXgLLLLLXXXXXgLLLLLLLXXgXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXLLLLgXXXXXXXXXXXXXXLLLLLLLXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXLLXXXXXXXXXXXXXXXXXXgXXXLLLgXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXLgXXXXXXXXXXXXXXXXXXXXXXXXLLLLXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXfXXXXXXXXLXXXXXXXXXXXXXXXXXXXXXXXXXgLLLLXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXX.XXXXXXXghgXXXXbXXXXXXXXaXXXXXXXXXXXXXXLLLLgXXXXXXX
+D:XXXXXXXXXXXXXXXXXXX.XXXXXXXg1gXXXX.XXXXXXXX.XXXXXXXXXXXXXXXXgLLXXXXXXX
+D:XXXXXXXXXXXXXXXXXXX^XXXXXXXXXXXXXX^XXXXXXXX^XXXXXXXXXXXXXXXXXXLXXXXXXX
+D:XXXXXXXXXXXXXXX4..^^^..^^^.......^^^......^^^.........EXXXXXXXLXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXX^XXXXXXXXX^XXXXXXXX^XXXXXXXXXXXXXXXXXLLXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXX.XXXXXXXX.XXXXXXXXXXXXXXXXLLLXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXcXXXXXXXXaXXXXXXXXXXXXXXXLLXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXeXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXgLLLXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLLXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLXgXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLXXXXXXXXXXXXXXX
+D:X...dXXXXXXXXXXe..0XXXXXXXXXXXXXXXD..EXXXXXXXXXXXXXXLLXXXXXXXXXXXcc..X
+D:X...dXXXXXXXXXX....XXXXXXXXXXXXXXX....XXXXXXXXXXXXXX.XXXXXXXXXXXX....X
+D:XA...XXXXXXXXXXF..eXXXXXXXXXXXXXXXC...XXXXXXXXXXXXXX0XXXXXXXXXXXX...BX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+
+# Starting location
+P:11:37
diff --git a/lib/edit/s_info.txt b/lib/edit/s_info.txt
new file mode 100644
index 00000000..5e41fe97
--- /dev/null
+++ b/lib/edit/s_info.txt
@@ -0,0 +1,546 @@
+# File: s_info.txt
+
+
+# This file is used to initialize the "lib/data/s_info.raw" file, which is
+# used to initialize the "skills" information for the PernAngband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/data/s_info.raw" file.
+
+# The skill indexes are defined in "defines.h", and must not be changed.
+
+# N:idx:name
+# D:desc
+# A:action mkey:action desc
+# I:rate
+
+# E:exclusive skill:exclusive skill
+# O:skill:opposing skill%percent
+# A:skill:friendly skill%percent
+
+# T:father:child
+
+# Version stamp (required)
+
+V:2.0.0
+
+################################## MAGIC ##################################
+
+N:56:Magic-Device
+D:Eases the use of magical devices, such as wands, staves and rods
+D:It also helps pseudo-id of magic objects
+I:1000
+F:RANDOM_GAIN
+
+N:54:Spell-learning
+D:You should not see that ! that is a BUG!
+#A:18:Learn a spell from a realm
+I:1000
+F:HIDDEN
+
+N:41:Sorcery
+D:Ability to use all the magic schools as if their skill was sorcery
+D:But the price to channel that much magic is your health
+A:17:Cast a spell
+I:1000
+
+N:1:Conveyance
+D:Ability to learn and use spells from the Conveyance school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+F:RANDOM_GAIN
+
+N:2:Mana
+D:Ability to learn and use spells from the Mana school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:3:Fire
+D:Ability to learn and use spells from the Fire school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:4:Air
+D:Ability to learn and use spells from the Air school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:5:Water
+D:Ability to learn and use spells from the Water school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:6:Nature
+D:Ability to learn and use spells from the Nature school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:7:Earth
+D:Ability to learn and use spells from the Earth school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:10:Divination
+D:Ability to learn and use spells from the Divination school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+F:RANDOM_GAIN
+
+N:11:Temporal
+D:Ability to learn and use spells from the Temporal school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:14:Meta
+D:Ability to learn and use spells from the Meta school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:51:Mind
+D:Ability to learn and use spells from the Mind school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:55:Udun
+D:Ability to learn and use spells from the Udun school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+F:HIDDEN
+
+N:13:Demonology
+D:Ability to use incantations from the Demonblades
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:31:Necromancy
+D:Ability to harness the powers of the dead
+D:Spells use the intelligence stat
+A:7:Use Necromancy
+I:1000
+F:RANDOM_GAIN
+G:60
+
+N:34:Runecraft
+D:Ability to combine magic runes to create your own spells
+D:Runespells use the dexterity stat
+A:9:Use Runespells
+I:1000
+
+N:43:Thaumaturgy
+D:Ability to gain and cast innate spells
+D:Spells use the intelligence stat
+A:8:Cast a thaumaturgy spell
+I:1000
+F:RANDOM_GAIN
+
+N:15:Magic
+D:General ability to do magic, also affects mana reserves and
+D:magic device ability. Helps pseudo-id of magic objects
+A:19:Copy a spell
+I:1000
+F:RANDOM_GAIN
+
+N:45:Spell-power
+D:Ability to increase the power of spells
+I:1000
+
+N:59:Geomancy
+D:Ability to understand the raw elemental forces of nature and use
+D:them to your advantage. Most spells need Fire/Water/Earth/Air skills
+A:101:Use Geomancy
+I:1000
+
+# All magic skills affect magic skill
+f:Magic-Device:Magic%7
+f:Spell-power:Magic%20
+f:Sorcery:Magic%20
+f:Mana:Magic%10
+f:Fire:Magic%10
+f:Air:Magic%10
+f:Water:Magic%10
+f:Earth:Magic%10
+f:Geomancy:Fire%45
+f:Geomancy:Earth%45
+f:Geomancy:Air%45
+f:Geomancy:Water%45
+f:Conveyance:Magic%10
+f:Divination:Magic%10
+f:Nature:Magic%10
+f:Temporal:Magic%10
+f:Meta:Magic%10
+f:Mind:Magic%10
+f:Udun:Magic%10
+f:Demonology:Magic%10
+f:Necromancy:Magic%4
+f:Runecraft:Magic%12
+f:Thaumaturgy:Magic%6
+
+
+
+################################## COMBAT ##################################
+
+N:16:Combat
+D:General ability to fight and to pseudo-id armour and weapons
+D:It also allows the use of heavier armour without penalties
+I:1000
+F:RANDOM_GAIN
+
+N:17:Weaponmastery
+D:General ability to use melee weapons
+I:1000
+F:RANDOM_GAIN
+
+N:18:Sword-mastery
+D:Ability to use swords
+I:1000
+
+N:19:Axe-mastery
+D:Ability to use axes
+I:1000
+
+N:20:Polearm-mastery
+D:Ability to use polearms
+I:1000
+
+N:21:Hafted-mastery
+D:Ability to use hafted weapons
+I:1000
+
+N:22:Backstab
+D:Ability to backstab fleeing and sleeping monsters to increase damage
+I:1000
+
+N:23:Archery
+D:General ability to use ranged weapons
+I:1000
+F:RANDOM_GAIN
+
+N:24:Sling-mastery
+D:Ability to use slings
+A:23:Fire piercing shots
+I:1000
+
+N:25:Bow-mastery
+D:Ability to use bows
+A:23:Fire piercing shots
+I:1000
+
+N:26:Crossbow-mastery
+D:Ability to use crossbows
+A:23:Fire piercing shots
+I:1000
+
+N:27:Boomerang-mastery
+D:Ability to use boomerangs
+I:1000
+
+N:58:Boulder-throwing
+D:Ability to make and throw boulders
+A:21:Tear down a wall to create boulders
+I:1000
+
+N:42:Barehand-combat
+D:Ability to fight barehanded
+I:1000
+F:RANDOM_GAIN
+G:70
+
+N:47:Bearform-combat
+D:Ability to fight in bear form
+I:1000
+F:HIDDEN | AUTO_HIDE
+
+N:52:Critical-hits
+D:Ability to deal critical hits with swords < 5lb
+I:1000
+
+N:57:Stunning-blows
+D:Ability to stun opponents when doing critical hits with hafted weapons > 5 lb
+I:1000
+
+# List of combat friendly skills
+
+# Melee: Specific masteries improve generic mastery
+f:Critical-hits:Sword-mastery%5
+f:Sword-mastery:Weaponmastery%25
+f:Axe-mastery:Weaponmastery%25
+f:Polearm-mastery:Weaponmastery%25
+f:Stunning-blows:Hafted-mastery%5
+f:Hafted-mastery:Weaponmastery%25
+
+# Ranged: Specific masteries improve generic mastery
+f:Sling-mastery:Archery%25
+f:Bow-mastery:Archery%25
+f:Crossbow-mastery:Archery%25
+f:Boomerang-mastery:Archery%25
+
+# All combat skills improve Combat
+f:Weaponmastery:Combat%50
+f:Sword-mastery:Combat%7
+f:Axe-mastery:Combat%7
+f:Polearm-mastery:Combat%7
+f:Hafted-mastery:Combat%7
+f:Archery:Combat%50
+f:Sling-mastery:Combat%7
+f:Bow-mastery:Combat%7
+f:Crossbow-mastery:Combat%7
+f:Boomerang-mastery:Combat%7
+f:Barehand-combat:Combat%50
+f:Boulder-throwing:Combat%40
+
+# No more, let's see how it turns out
+# Sorcery and Weaponmastery aren't exactly friendly to each other
+#O:Sorcery:Weaponmastery%100
+#O:Sorcery:Archery%100
+#O:Sorcery:Barehand-combat%100
+#O:Weaponmastery:Sorcery%100
+#O:Archery:Sorcery%100
+#O:Barehand-combat:Sorcery%100
+
+
+
+############################### SPIRITUALITY SKILLS ###########################
+
+N:28:Spirituality
+D:General ability to use spiritual skills and also influence your Saving Throw
+I:1000
+F:RANDOM_GAIN
+
+N:53:Prayer
+D:Ability to learn and use spells from the gods' schools
+D:Spells use the wisdom stat and cost piety instead of mana
+A:17:Cast a spell
+I:1000
+
+N:12:Druidistic
+D:Ability to learn and use prayers from the Druidistic realm
+D:Nature powers use the wisdom stat
+A:1:Cast a druidistic spell
+I:1000
+
+N:29:Mindcraft
+D:Ability to focus the powers of the mind
+D:Mindpowers use the wisdom stat
+A:2:Use Mindcraft
+I:1000
+F:RANDOM_GAIN
+G:50
+
+N:9:Music
+D:Ability to learn and sing songs
+D:Songs use the charisma stat
+A:17:Cast a spell
+I:1000
+
+f:Prayer:Spirituality%10
+f:Druidistic:Spirituality%10
+f:Mindcraft:Spirituality%10
+f:Music:Spirituality%10
+
+f:Prayer:Magic%10
+f:Druidistic:Magic%10
+f:Mindcraft:Magic%10
+f:Music:Magic%10
+
+
+################################## MISC SKILLS ###############################
+
+N:30:Misc
+D:Not a real skill, it is only used to regroup some skills
+I:0
+
+N:33:Antimagic
+D:Ability to generate an antimagic field
+A:3:Use antimagic
+I:1000
+F:RANDOM_GAIN
+G:80
+
+N:39:Alchemy
+D:Ability to use essences to modify/create magic items
+A:5:Use Alchemy
+I:1000
+
+# Antimagic exclude all magic
+E:Magic-Device:Antimagic
+E:Mana:Antimagic
+E:Geomancy:Antimagic
+E:Fire:Antimagic
+E:Air:Antimagic
+E:Water:Antimagic
+E:Earth:Antimagic
+E:Conveyance:Antimagic
+E:Divination:Antimagic
+E:Temporal:Antimagic
+E:Meta:Antimagic
+E:Mind:Antimagic
+E:Nature:Antimagic
+E:Udun:Antimagic
+E:Sorcery:Antimagic
+E:Demonology:Antimagic
+E:Runecraft:Antimagic
+E:Necromancy:Antimagic
+E:Mindcraft:Antimagic
+E:Music:Antimagic
+E:Prayer:Antimagic
+E:Druidistic:Antimagic
+E:Thaumaturgy:Antimagic
+
+################################## SNEAKINESS SKILLS ###############################
+
+N:35:Sneakiness
+D:General ability at the sneakiness skills.
+D:It also affects the searching abilities
+I:0
+F:RANDOM_GAIN
+
+N:36:Stealth
+D:Ability to move unnoticed, silently
+I:0
+F:RANDOM_GAIN
+
+N:37:Disarming
+D:Ability to disarm the various traps
+I:0
+F:RANDOM_GAIN
+
+N:40:Stealing
+D:Ability to steal objects
+A:15:Steal object
+I:0
+
+N:46:Dodging
+D:Ability to dodge blows and bolts
+A:16:Check dodge chance
+I:0
+
+f:Stealth:Sneakiness%15
+f:Disarming:Sneakiness%10
+f:Backstab:Sneakiness%5
+f:Stealing:Sneakiness%15
+f:Dodging:Sneakiness%10
+
+
+################################## MONSTER SKILLS ################################
+
+N:48:Monster-lore
+D:General ability at the monster related skills, ability to gain experience
+D:from friendly kills. It also affects the number of companions you can have
+I:0
+A:22:Turn pet into companion
+F:RANDOM_GAIN
+
+N:44:Summoning
+D:Ability to create totems from monsters and use them to summon monsters
+A:13:Manipulate totems
+I:1000
+F:RANDOM_GAIN
+G:60
+
+N:49:Corpse-preservation
+D:Ability not to destroy the monsters' corpses when killing them
+I:0
+
+N:50:Possession
+D:Ability to incarnate into monsters
+A:11:Use the possession skill
+I:0
+
+N:8:Symbiosis
+D:Ability to enter in symbiosis with monsters unable to move by themselves
+D:Spells use the intelligence stat
+A:20:Use symbiotic powers
+I:1000
+F:RANDOM_GAIN
+G:70
+
+N:32:Mimicry
+D:Ability to use cloaks of mimicry to change form
+A:6:Use Mimicry
+I:1000
+F:RANDOM_GAIN
+G:80
+
+f:Possession:Monster-lore%10
+f:Corpse-preservation:Monster-lore%10
+f:Summoning:Monster-lore%10
+f:Symbiosis:Monster-lore%10
+f:Mimicry:Monster-lore%10
+
+################################## SKILL TREE ################################
+
+T:Main:Combat
+T:Combat:Weaponmastery
+T:Weaponmastery:Sword-mastery
+T:Sword-mastery:Critical-hits
+T:Weaponmastery:Axe-mastery
+T:Weaponmastery:Hafted-mastery
+T:Hafted-mastery:Stunning-blows
+T:Weaponmastery:Polearm-mastery
+T:Combat:Archery
+T:Archery:Sling-mastery
+T:Archery:Bow-mastery
+T:Archery:Crossbow-mastery
+T:Archery:Boomerang-mastery
+T:Combat:Barehand-combat
+T:Combat:Bearform-combat
+T:Combat:Boulder-throwing
+T:Combat:Antimagic
+
+T:Main:Sneakiness
+T:Sneakiness:Stealth
+T:Sneakiness:Disarming
+T:Sneakiness:Backstab
+T:Sneakiness:Stealing
+T:Sneakiness:Dodging
+
+T:Main:Magic
+T:Magic:Magic-Device
+T:Magic:Spell-power
+T:Magic:Sorcery
+T:Magic:Mana
+T:Magic:Geomancy
+T:Magic:Meta
+T:Magic:Conveyance
+T:Magic:Divination
+T:Magic:Temporal
+T:Magic:Mind
+T:Magic:Nature
+T:Magic:Udun
+T:Magic:Demonology
+T:Magic:Necromancy
+T:Magic:Runecraft
+T:Magic:Thaumaturgy
+T:Magic:Alchemy
+
+T:Geomancy:Fire
+T:Geomancy:Water
+T:Geomancy:Air
+T:Geomancy:Earth
+
+T:Main:Spirituality
+T:Spirituality:Prayer
+T:Spirituality:Mindcraft
+T:Spirituality:Music
+
+T:Main:Monster-lore
+T:Monster-lore:Summoning
+T:Monster-lore:Corpse-preservation
+T:Monster-lore:Possession
+T:Monster-lore:Symbiosis
+T:Monster-lore:Mimicry
diff --git a/lib/edit/s_name.map b/lib/edit/s_name.map
new file mode 100644
index 00000000..795d8786
--- /dev/null
+++ b/lib/edit/s_name.map
@@ -0,0 +1,110 @@
+# Special level "The Nameless Level" in the Pits of Angband
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Written by Mynstral (mynstral@thehelm.com)
+
+%:special.txt
+
+# Great Storm Wyrm on normal floor
+F:a:1:0:728
+
+# Mature Red Dragon on normal floor
+F:b:1:0:589
+
+# Mature White Dragon on normal floor
+F:c:1:0:549
+
+# Ancient Blue Dragon on normal floor
+F:d:1:0:601
+
+# Ancient Black Dragon on normal floor
+F:e:1:0:624
+
+# Ancient Multi-hued Dragon on normal floor
+F:f:1:0:675
+
+# Great Hell Wyrm on normal floor
+F:g:1:0:756
+
+# Great Wyrm of Many Colours on normal floor
+F:h:1:0:790
+
+# Great Ice Wyrm on normal floor
+F:i:1:0:741
+
+# Sky Drake on normal floor
+F:j:1:0:793
+
+### Random Monsters and/or Items
+# Random monster (upto 5 levels ood) on normal floor
+F:&:1:0:*100
+
+# Random monster (upto 11 levels ood) on normal floor
+F:@:1:0:*106
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on normal floor
+F:8:1:0:*104:*102
+
+# Random monster (upto 40 levels ood) and
+# Random object (upto 20 levels ood
+F:9:1:0:*135:*115
+
+# Random monster (upto 3 levels ood)
+F:-:1:0:*98
+
+# Random object (upto 7 levels ood)
+F:=:1:0:0:*102
+
+### Guaranteed Items
+# The Multi-Hued Dragon Scale Mail 'Razorback' on normal floor
+F:1:1:0:0:0:0:16
+
+### Level Design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X.....LLLLLLLLL.....XXX.G=-&&=-G^.........>X
+D:X.LLL...........LLLXX...G=-&.=-G^........1.X
+D:X.L9L.LLLLLLLLLLLLX%...EGE.=&.FG^..........X
+D:X.L99.L&..........X%....G..&-..G^....j.....X
+D:X.LLLLL&LLLLLLLLL.LXX...G=-=&-=G^..........X
+D:X....&&&L.......L.L*XXX.G-=&&-=G^^^^^^^^^^^X
+D:XLLLLLLLL.LLLLL..&L**XXXXXXXGGGG%XXXXXXXXXXX
+D:XXXXXXLL..L***LLLLLLLX^^^^8Xi....%@@^^.^^@@X
+D:X5..8X.&.XXXXXX......D^^^^8XIIIIIXbb^^.^^ccX
+D:X...8X...XA...X.LLLLLX^^^^8X.....X..^^.^^..X
+D:X...8X.XXXC...X.LL...XXXIXXX^^^^^X..^^.^^..X
+D:XGXXXX.LfX7...X&LL.L.Xa^^^aXf...fX..^^.^^..X
+D:X.X5XL.L*XB...X&&..L.X^b^b^X^^^^^X..^^.^^..X
+D:X.X^XL.L*XXXXXXLLLLL.X^^7^^X.....X..^^.^^..X
+D:X.X^XL.L***fXL.....&&X^b^b^XIIIIIX..^^.^^..X
+D:X.X^XL.LLLLLXL.LLLLLLXa^^^aXi....X..^^.^^..X
+D:X.X^XL.........XXXXXXXXX%XXXXXXXXX..^^.^^..X
+D:X.X^XXXXXXXXXXLX^...^Xe-^=dX^^..&X..^^.^^..X
+D:X.X^^^^^^^^^^XLX.^^^.X-^^^=X^^..&X..^^.^^..X
+D:X.XXXXXXXXXX^X8Xf^B^.%^^6^^%^^C.&X..^^.^^..X
+D:X.LLLLLLLLL+^XXX.^^^.X-^^^=X^^..&X..^^.^^..X
+D:X.XXXXXXXXXXXXXX^...^Xd-^=eX^^..&X..^^.^^..X
+D:X.Xbbbbb......XXXXXXXXXX%XXXXXXXXX..^^.^^..X
+D:X.XbbbbXXXX^^^^XX....X^^^^^X...h.X..^^.^^..X
+D:X.XbbbXX^^XXX^^^XX...X^ccc^X....0X..^^.^^..X
+D:X.XbbXX.^X%bXX^^^XX..X^.A.^X.....X..^^0^^..X
+D:X.IbXX..XXbbbXX^^^XX.X^ccc^XIXXXXXXXXXXXXXXX
+D:X.XXX..XX.....X%^^^XXX^^^^^XlllllllllllllllX
+D:X.X99.XXW......XX^^^XXXXXXXXlllllllllllllllX
+D:X.X99XXWWW...a..XX^^.XXllllllLLLLLlXXXX%XXXX
+D:X.XXXX..WWW.....cXX^.XXXXXlllllllllXVVVVVVVX
+D:X.X8.....WWW....ccX^.X^^^XLLLlLLLLLXVVVVVVVX
+D:X.X%XXXXXXXWW...cXXX.X+X^XlllllllllXV%%%%%VX
+D:X.X.......XWWW..X%^X.XLX^XlLLLLLLLLXV%8^8%VX
+D:X.XXXXXX%.X.WWWXX^^X.XLX^XlllllllllXV%^a^%VX
+D:X.X.IIIIX.X..WXX..XXcXLX^XLLLlLLLLlXV%^^^%VX
+D:X.X%XXXIX.X..XX..XXccXLX^XlglllLgllXV%^^^%VX
+D:X.Xa.6XIX.X.XX..XXcccXLX^XlllllXXXXXV%^a^%VX
+D:X+XXX.XIX.X.X99XXccccXLX^XXXXXXX888XV%8^8%VX
+D:X%%%Xa%.X.%8X99XcccccXLX^^^^^^4X...XV%%%%%VX
+D:X%.%XXXXXXXXXXXXIXXXXXLXXXXXXXXX...XVVVVVVVX
+D:X.%%+..........................G..4X...F...X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting Location
+P:43:4
diff --git a/lib/edit/s_orc.map b/lib/edit/s_orc.map
new file mode 100644
index 00000000..48913e02
--- /dev/null
+++ b/lib/edit/s_orc.map
@@ -0,0 +1,109 @@
+# Special level "The Orc Barracks" in the Pits of Angband
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+
+%:special.txt
+
+#Y:40:118:126:149:264:238:285:313:330:404:15:0:0:35:22
+# Shrieker
+F:a:1:0:40
+
+# snaga
+F:b:1:0:118
+
+# cave orc
+F:c:1:0:126
+
+# hill orc
+F:d:1:0:149
+
+# half orc
+F:e:1:0:264
+
+# ogre
+F:f:1:0:238
+
+# ogrillion
+F:g:1:0:285
+
+# bolg
+F:h:1:0:330
+
+# uruk
+F:i:1:0:313
+
+# black orc
+F:j:1:0:244
+
+### Random Monsters and/or Items
+# Random monster (upto 5 levels ood) on normal floor
+F:&:1:0:*35
+
+# Random monster (upto 11 levels ood) on normal floor
+F:@:1:0:*46
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on normal floor
+F:8:1:0:*44:*42
+
+# Random monster (upto 40 levels ood) and
+# Random object (upto 20 levels ood
+F:9:1:0:*75:*55
+
+# Random monster (upto 3 levels ood)
+F:-:1:0:*38
+
+# Random object (upto 7 levels ood)
+F:=:1:0:0:*42
+
+### Guaranteed Items
+
+# The stone of lore
+F:1:1:0:0:0:0:15
+
+### Level Design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:Xa.......................ccccccccc.......................aX
+D:X.lllllllllllllllllllllllllllllllllllllllllllllllllllllll.X
+D:X.l......................ccccccccc.....g.g..............l.X
+D:X.l.XXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXDXXXXXXXXXXXXXX.l.X
+D:X.l.Xa.......efX1Xfe.......aX.X.aaa.D.gX.XacbdddccjjjaX.l.X
+D:X.l.D........efG.Gfe........D.D.bbb.XXXX.XcfbcbcbbjjeeX.l.X
+D:X.l.X........efX.Xfe........X.X.bbb.D.gX.XfbbgdcbdbjjjX.l.X
+D:X.l.XXXXXX...efG.Gfe...XXXXXX.X.bbb.XXXX.XebdcfbdccejjX.l.X
+D:X.l.X.c..XXX.efX.Xfe.XXXcc.aX.D.ccc.D.gX.XcfcbgeebdebfX.l.X
+D:X.l.D..d..aXXXfX.XfXXXe.....D.X.ccc.XXXX.XedbcdbcdcggeX.l.X
+D:X.l.X........XXX.XXX..bbb.ddX.X.ddd.D.gX.XdgfcfegbeebcX.l.X
+D:X.l.X..f.c.bf.G...G.c..cc...X.D.ddd.XXXX.XcbeefccbfbdbX.l.X
+D:X.l.X.d..bb.d.Gi.iG...cbb.bdX.X.eee.D.gX.XbgcfbgcfdebcX.l.X
+D:X.l.X.cc...c..G.7.G.cc..d.e.X.X.eee.XXXX.XcbdfeccdbcdbX.l.X
+D:X.l.X..b.f.bbXGGGGGX.bbb.bb.X.D.f.f.D.gX.XfdebbdgeefgdX.l.X
+D:X.l.D.c..dbbXXa...aXXX..d...D.X.f.f.XXXX.DdefddbcbdbddX.l.X
+D:X.l.X...c.XXX..g.g...XXX...bX.X.....D..XGXXeegcefdcefcX.l.X
+D:X.l.Xbb..aXg.gggjgggg.gX.bbaXDXaaa..XXjIa8XacbddbegbdaX.l.X
+D:X.l.XXXXXXXXDXXXXXXXXDXXXXXXXaXXXXXXXXXXXXXXXXXXXXXXXXX.l.X
+D:X.l........................Da.aD........................l.X
+D:X.l.XXXXXXXXXXXXXXXXXXXXXXXXXaXXXXXXXXXXXXXXXXXXXXXXXXX.l.X
+D:X.l.....eeeeee.........fffXXXDXXXfff.........eeeeee.....l.X
+D:X.l.....eeeeee.........fffX.....Xfff.........eeeeee.....l.X
+D:X.llllllllllllllllllllllllX.....Xllllllllllllllllllllllll.X
+D:Xa.....................XXXXGGGGGXXXX.....................aX
+D:XXXXXXXXXXIXXXXXXXXXXXXXgafff>fffagXXXXXXXXXXXXXIXXXXXXXXXX
+D:XjjjX.#########.XfffXXgggfffffffffgggXXfffX.#########.XjjjX
+D:XfffX...........XeeeXggggjjj...jjjggggXgggX...........XfffX
+D:XfffXGGGDX.XXXXXX...Xgggg....h....ggggX...XXXXXX.XDGGGXfffX
+D:Xgg......X.X........Xgggg.........ggggX........X.X......eeX
+D:Xgg....ggX.X.XXXXXX.XXgggggggggggggggXX.XXXXXX.X.Xee....eeX
+D:Xgg....ggX.X.X......XXXXgggggggggggXXXX......X.X.Xee....eeX
+D:Xgg....ggX.X.X.XXXXXX..XXXXfffffXXXX..XXXXXX.X.X.Xee....eeX
+D:Xgg....ggX.X.X.........#.4XXXDXXX4.#.........X.X.Xee....eeX
+D:Xgg....ggX.X.XXXXXXXXXIXXXXa...aXXXXIXXXXXXXXX.X.Xee....eeX
+D:Xgg....ggX.X.Xigfedcba.XiX..X#X..XiX.abcdefgiX.X.Xee....eeX
+D:Xgg....ggX.X.XGGGGGGGGGX....X.X....IGGGGGGGGGX.X.Xee....eeX
+D:XggggggggX.X.X@@@@@@@@@IXXXaX7XaXXXX@@@@@@@@@X.X.XeeeeeeeeX
+D:XggggggggI.X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X.IeeeeeeeeX
+D:XaaaaagggX.......................................XeeeaaaaaX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting Location
+P:22:31
diff --git a/lib/edit/s_ship.map b/lib/edit/s_ship.map
new file mode 100755
index 00000000..f429d4ec
--- /dev/null
+++ b/lib/edit/s_ship.map
@@ -0,0 +1,239 @@
+# s_ship.map
+#
+# Special Level "Arvedui's Galleon" in the Helcaraxe#
+#
+# Created for ToME 3.x on 9/11/03
+#
+# Written by Lord Dimwit (lorddimwit@hotmail.com)
+# Middle-game dungeon
+# Comments: This large level is a variation on the classic 'ghost ship' theme;
+# the ship was caught in the Helcaraxe and everyone on board died. The polar waters
+# surrounding the ship contain some unpleasant surprises for inquisitive and unwary
+# adventurers--the hardest monsters on the map are actually there.
+
+# Ported to ToME 2.x on 6/6/04 by masmarangio
+#
+# Changed the starting position to 28:122
+# Replaced the undefined letter 'c' with '.'
+# The exits of the between gates pointed to incorrect positions.
+# I'm not sure esp. about the correct exit of gate #3.
+
+
+#%:special.txt
+
+
+### Terrain Features
+
+# up staircase
+F:<:6:0
+
+# down staircase
+F:>:7:0
+
+# Permanent wall
+F:X:61:4
+
+# Glacial Wall
+F:#:215:4
+
+# Ice Wall
+F:M:95:4
+
+# Deep Water
+F: :187:4
+
+# Fog
+F:*:210:4
+
+# Shallow water
+F:~:84:4
+
+# Ice
+F:.:90:4
+
+# Hidden Door
+F:+:48:0
+
+# Normal Door
+F:=:32:0
+
+# Ash
+F:,:93:4
+
+# Fake wall
+F:I:189:4
+
+
+### Monsters
+
+# Leviathan in deep water
+F:L:187:0:782
+
+# Greater Kraken in deep water
+F:K:187:0:775
+
+# Lesser Kraken in deep water
+F:k:187:0:740
+
+# Giant Squid in deep water
+F:s:187:0:482
+
+# Killer Whale in deep water
+F:w:187:0:917
+
+# Drowned Soul in shallow water
+F:G:84:0:895
+
+# Ancient White Dragon on ice
+F:D:90:0:617
+
+# Mature White Dragon on ice
+F:d:90:0:549
+
+# Ice Troll on ice
+F:T:90:0:454
+
+# Headless Ghost on ice
+F:H:90:0:533
+
+# Shadow on ice
+F:g:90:0:665
+
+# Young White Dragon on ice
+F:b:90:0:460
+
+# Zombified Human on ice
+F:z:90:0:229
+
+# Greater mummy on ice
+F:m:90:0:522
+
+# Cold Hound on ice
+F:Z:90:0:308
+
+# Giant White Dragon Fly on ice
+F:F:90:0:250
+
+# Ice Elemental on ice
+F:E:90:0:570
+
+# Yeti on ice
+F:Y:90:0:154
+
+# Ice skeleton on ice
+F:i:90:0:379
+
+# Skeleton human on ice
+F:h:90:0:228
+
+# Ghost on ice (apologies to Eldridge Cleever)
+F:W:90:0:477
+
+# Hand druj on ice
+F:S:90:0:748
+
+# Eye druj on ice
+F:J:90:0:749
+
+# Dread on ice
+F:o:90:0:534
+
+# Dreadmaster on ice
+F:O:90:0:690
+
+# Night mare on ice
+F:q:90:0:622
+
+# Random monster (upto 5 levels ood) on ice
+F:&:90:0:*40
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on ice
+F:8:90:0:*44:*42
+
+# Treasure (random) on ice
+F:$:90:0:0:*47
+
+# Treasure (good) on ice
+F:%:90:0:0:*60
+
+# Trap (random) on ice
+F:^:90:0:0:0:0:0:*
+
+# Trap (random) on shallow water
+F:t:84:0:0:0:0:0:*
+
+# Trap (random) on fog
+F:@:210:0:0:0:0:0:*
+
+# Human skeleton on ice
+F:x:90:0:0:395
+
+
+### Between Gates
+
+# between gate 3: was 711
+F:3:160:6:0:0:0:0:0:1136
+
+# between gate A: was 6247
+F:A:160:6:0:0:0:0:0:6761
+
+# between gate 4: was 3339
+F:4:160:6:0:0:0:0:0:3853
+
+# between gate B: was 3085
+F:B:160:6:0:0:0:0:0:3599
+
+
+### Guaranteed Items
+
+# The Mage Staff of Forochel
+F:!:90:0:0:0:0:213
+
+
+### Level Design
+
+D:XXXXXXXXXXXXXXXX XXXXXXXXXXXX XXXXXXX XXXXXXXXXXXXXXX XXXX
+D:X###############..~ .#. k w ~.#XX######### .~~ s G..#####.. w .###.######X##~~ .GX.###
+D:X####%####...~ ~.~ s .#.X#~~.##### .~ s w G..#.##.#.XGG~XXk~.####A####.~X ~~.X...
+D:X##%#$#######...~ w wXXXXXX#XXXX###XXX #~XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..XX....~.XX X#xX.#..#.#G. w ~X G~~
+D:X##$#########.... s XXXTT^...~.~#####w~###~~~~8....**.tE.&E ^^.M^.xx.....x..ZZ..^XTTTT M...GG.~.. w G.###~XX~~#XX . s X
+D:X#########...~ w XXXTTTT.^..x~.H#### ###~~D....8**.~M~.E..M^.MM^..xh.h...ZZZZ^~M.,.,.,.~~ .G...~~ ~###. w . w M.d.
+D:X#####.x.x~~~ XXXTTTXXXMxx.H.####### ~##~~~8...#.**.~tE&EE^^~%M^.h.x.E.xh.ZZ..^X.,.^....~ ...G.~ s ~# XX ~~ w X
+D:X######...~~ MM~ w XXX^^XXX.MMMxx...G#####w ~#~.~..&...**E.MEt.^^.MM^~..i.....ZZZZ^~M.,.,,.gM.~.,~.,G.G~~ G~. G~.MM XX..~
+D:X##.....~~ XXX^E=^XX$b.MMMMxH..HG#.## w ~#~##~8....*E~.&EM^^.M^h..i..x.x..ZZ..^XTTTTX.,.,~........~.G~~..w . G~...G~X
+D:X...~~~ K XXX^^EXXXX$$$..MMXXXXXXX#### #####XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..,.X..M~.........~G..G ~~.G...G~
+D: ~~~ w XXX^^EXXXdX%d$$b$$XXd~~~~##### s ###.,.W.**,.x.,.,.,.,.,.***,,....,x....,,.SX.,.,.,..,o.,.,.~~.G..~.G..G..~X k
+D: w MMM. w XXX^E^XXX.,*XDDd$$$XXd$..~~~~#### ###.,.,.,.**..,.,i.,.,W,.,**..z.,.,.q...g.,......~.,.,.,.,.~.~..F.~M~......~
+D: MM. XXX4EEXXXi^**.XX%%$dXX$d$.H#####~G~~####.~.,~..,.h*,,~,.,.,.,~,.,.,.H.,.~.,..~,.,,,.~,.,.~.,.,.X.~,g.~~..~.~..,..,X
+D: s XXXBXXXXX^.**.W.,XDD%XXb$$b####..G~~~G###~.,,.,.,.,...,,.x,.~.,.,~..,.~.,.,~,.,.,,.,.,~,.,.,.~,.,..,X.,.***.~***,W.,X
+D: XXX.o..X.g***i.*.,.XX%XX######^^^^t ##ttt^^^^^t^^^^^^t^^^^^t^^^^^^^t^^^^^^t^^^^t^^tt^^^tt^^^^t^tXo..x************X
+D: k XXX^E..o.XX8.****,.g..XXX..#........~~~~~ttt###~~.,.G~.......XXXXX..~,..,,..,,.~.,..,.,..,,..,.,x..,.ooX******W***g.*.g*X
+D: XXX%S^^E..ooX,*****,..,.X.....h........XXX~~~tt#tt w ~~G~...XXXXXXX.,**.,..D.**.G.,~,..XXX...~~~.....o8X***.~.,.****$$..X
+D: XX%%%^mm.E..oXH**.^.*i.....#.....i..*..XXXXX~~ G~~.XXXXXXXXX~.*..,.,*..~,..,.,XXXXX...~..,.XXXXXo.W.$$.g.x....o.X
+D: XXX%S^^E..ooX8.*~~...,~~##...,..,.***,.XXX~G~ k ~~~~XXXXXXX.,.*. g...*..x..W.~.XXX.***.,,o..oO8X.o.,.o.xx$$$XXXXX
+D: XXX^E..o.XXH.###....###~~~.,h..,.*.,..~~.~~ s ~~.XXXXX.~..**...i~**.....~.,,.,,.***~,,,.oXXXXXXXXXXXXXXXX.!.X
+D: s XXX.o..X&..w~##..##~~~X~^^^^^^^^^^t^ttt^tt w tt^tttt^^tt^^^^^ttt^^^^ttt@@^^^^ttt^^^^^ttt@^^ttXXXW ^^.M*.t^oo.^^...X s
+D: ~~~ XXX>XXH~G..#####~G~~Gt..,.,..,.,xx..x ~~~ i~~xx.~...x....~.~..~..,~..***..~..~...,~.~*.~.XXXE.^^H..SM.~^.oo....JX
+D: ~~....~~ XXX$8w~.^####G~G ~i.XX.,,.,...........G~~~s~~ iiF~...........~.......x.,.**~....,~....~.*XXX.EE.W.^^.M*.~^^^o^O^..X
+D: ~.#..#..~~ XXX8##t..##~#.G.t..XX..,H...,.W...,...,~~...,...*,,.x...,.i.....g.....**.........XXXXXXX...EE.^^H..SM.~.^oo...^JX
+D: ~.##.##..~ XXX###GG~~~*h~.^..XX.....,....,.W...,.G....W.***...,...,...,....,...,**..q....SX3tttW#...EE.W.^^.M*.t.oo.^.^.XX
+D: ~~.###..~~ X##.##~~G^~~~~i*^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX~~
+D: ~~...###.~ k ~###X.G~~@Gh~x*~^..^i.zX8~i.~..h....zzzXiX..^$.T.t$......F.t..XX..^TTT*..M..Y....^.Y.^*.^..~....X.x..x~.<XX~.
+D: ~.....####.....#####XXXx@@~i~.z..z.it,#**t..h..Gzh.zzX@.@Xd*t.~...*~.t......^X..T.^T*@*TXMM...^....^**@.^.x*...+..~....XX..~
+D: ~~.#$%#########....XXX~h~i.HH...h,i^X*.H..h.^G..WX@.E.^X**8..Y.~*8...Y...^+XXXXXXXXXXXMF...~....^.*..x.***..X..x..~XX...~~w
+D: ~~.#$$######.~ ~w XXX$~.x..~G^..,i.,.~.h.^~~..zzX@.@Xd*......F**..~....^XbM..^~ZZZZXMM..*.....~^......*.XXXXXXXIXX.~~#~w
+D: L ~~xx########.~~ XXX$$.G#GX#.i,,^ih.^W.zG^zzzXiX.$.t88.~..^**F..T...tXX~~.^^ZZZZM~..**@~~.Y~..^#^..xXI&X8&..XX ~~~## w
+D: ~.########..~~ XXXXX~#X~X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ~###~w
+D: ~~.#########..~ w K w ~##### w ~.M.~ ~..####.~ s~~~~.~~ s K ~##..~
+D: ~..#########.~ ~##### ~...~ k ~..###.~ ~~####~~~ w w ~###..~
+D: XXXXXXXXXXXX XXXXXX XXXXXX XXXXXXXXX XXXXXX
+
+
+### Starting Location
+P:28:122
+
+
+
+
+
diff --git a/lib/edit/set_info.txt b/lib/edit/set_info.txt
new file mode 100644
index 00000000..b6141e01
--- /dev/null
+++ b/lib/edit/set_info.txt
@@ -0,0 +1,77 @@
+# File: set_info.txt
+
+
+# This file is used to initialize the "lib/raw/set_info.raw" file, which is
+# used to initialize the "item set" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# Version stamp (required)
+
+# N:idx:name
+# D:description
+# P:artifact index:number of item needed:pval
+# F:flags
+
+V:2.0.0
+
+# The Elven Gifts, took from Oangband
+
+N:0:Elven Gifts
+D:It is from a group of Elven items once entrusted to Hobbits
+# Phial of Galadriel
+P:1:2:1
+F:WIS | CHR | RES_DARK
+# Sting
+P:88:2:2
+F:STEALTH | REGEN
+
+
+# The Dragon Slayer
+
+N:1:Dragon Slayer
+D:It is from a group of items rumoured to be the bane of dragons.
+# Bow of bard
+P:125:2:3
+F:DEX | CON | RES_FIRE
+# Arrow of Bard
+P:63:2:5
+F:SPEED
+
+
+# The Trinity -- Possessor set
+
+N:2:The Trinity
+D:It is one of the 3 legendary daggers.
+# Narthanc
+P:66:2:2
+F:STR
+P:66:3:1
+F:KILL_DRAGON | REGEN | SH_FIRE
+# Nimthanc
+P:67:2:2
+F:CON
+P:67:3:1
+F:KILL_DEMON | IM_COLD
+# Dethanc
+P:68:2:2
+F:DEX
+P:68:3:1
+F:KILL_UNDEAD | SH_ELEC | FLY
+
+
+# Gothmog's Armoury -- Demonologists set
+
+N:3:Gothmog's Armoury
+D:It is from a group of items that once belonged to Gothmog,
+D:the High Captain of the Balrogs
+# The demonblade of Gothmog
+P:181:3:7
+F:STR | CON | SPEED | VAMPIRIC
+# The demonshield of Gothmog
+P:182:3:0
+F:IM_FIRE | IM_COLD | SH_ELEC
+# The demonhorn of Gothmog
+P:183:3:0
+F:ESP_EVIL | ESP_GOOD | AUTO_ID
diff --git a/lib/edit/special.txt b/lib/edit/special.txt
new file mode 100644
index 00000000..8d1c94b9
--- /dev/null
+++ b/lib/edit/special.txt
@@ -0,0 +1,67 @@
+# Contains terrain parsings for the special levels now being kept in seperate map files
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Written by Mynstral (mynstral@thehelm.com)
+
+# Permanent Wall
+F:X:63:0
+F: :63:0
+
+# Granite Wall
+F:#:57:0
+F:%:57:0
+
+# Hidden Door
+F:+:48:0
+
+# Normal Door
+F:D:32:0
+
+# Floor
+F:.:1:0
+
+# Tree
+F:T:96:0
+
+# Mountain
+F:M:97:0
+
+# Shallow Water
+F:w:84:0
+F:V:84:0
+
+# Deep Water
+F:W:187:0
+
+# Shallow Lava
+F:l:86:0
+
+# Deep Lava
+F:L:85:0
+
+# Glass Wall
+F:G:188:0
+
+# Illusion Wall
+F:I:189:0
+
+# Treasure (random) on normal floor
+F:*:1:0:0:*
+
+# Trap (random) on normal floor
+F:^:1:0:0:0:0:0:*
+
+# down staircase
+F:>:7:0
+
+# between gates
+F:4:160:0:0:0:0:0:0:-1
+F:5:160:0:0:0:0:0:0:-1
+F:6:160:0:0:0:0:0:0:-1
+F:7:160:0:0:0:0:0:0:-1
+F:A:160:0:0:0:0:0:0:-1
+F:B:160:0:0:0:0:0:0:-1
+F:C:160:0:0:0:0:0:0:-1
+F:E:160:0:0:0:0:0:0:-1
+F:F:160:0:0:0:0:0:0:-1
+F:0:160:0:0:0:0:0:0:-1
diff --git a/lib/edit/spiders.map b/lib/edit/spiders.map
new file mode 100644
index 00000000..146c152c
--- /dev/null
+++ b/lib/edit/spiders.map
@@ -0,0 +1,66 @@
+# Lit permanent wall
+F:X:61:6
+
+# up staircase
+F:<:6:8
+
+# Grass
+F:-:89:3
+
+# Trees
+F:t:96:3
+
+# Grass with Giant spider
+F:a:89:3:175
+
+# Grass with Giant tarantula
+F:b:89:3:275
+
+# Grass with Mirkwood Spider
+F:c:89:3:277
+
+# Grass with Aranea
+F:d:89:3:963:0:0:0:0:0:0:2
+
+# Grass with Elder aranea
+F:e:89:3:964:0:0:0:0:0:0:2
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X<---tttttttttttttttttttttttttttttttttttttttttttttttttttttttX
+D:X---ttttttttttttttttttttttttttta--ctttttttttttttttttttttttttX
+D:Xtt---------------ttttttttttttt--tttttttttttttttttttttttttttX
+D:Xttttttttt--------------cttttttt--ttttttttttttttttttttttttttX
+D:Xtttttttttttttt--tttttt---------c--tttttttttttttttttttttttttX
+D:Xttttttttttttta-bttt---cttttttttttttttttttttttttttttttttttttX
+D:Xttttttttttttttttttttt---tttt-ttd--c-ttt---c---tttttttttttttX
+D:Xtttttttttttttttttttc---btttttttt-----ttc-----ttttttttttttttX
+D:Xtttttttttttttttttt----tttttttttc-c---------d---c-ctttttttttX
+D:Xtttttttttttttttttb-tttt---c---t----tttttt----------ctttttttX
+D:Xtttttttttttttttttt----ttttt-----c---tttttt-c--cttttttttttttX
+D:Xttttttttttttttttc--at----c---ttttttttttttttttttttttttttttttX
+D:Xttttttttttttta----ttttt-b--tttttttttd--etttttttttttttttttttX
+D:Xtttttttttttt---c--ttttt------tttt-c-tttttttte----dtttttttttX
+D:Xttttttttttttttttttt----c--d----tttt---ttttttt--d----ettttttX
+D:Xttttttttttttttttttttt-c-d---tttttttc--cttttttt-----ttttttttX
+D:Xttttttttttta-c--ttt-------tttt-------ttttt----d--ttttttttttX
+D:Xtttttttttttt----ttttt--ttt--c--c--t-----c--ttttttttttttttttX
+D:Xttttttttttt--c---ttt--c--c---ttttt--c----t----tttttttttttttX
+D:Xtttttttttt-c----c---t-----tttttttt-----ttt-------dtttttttttX
+D:Xttttttttttt---c---tttt--c--ttttttttt-ttttttttt-d---ttttttttX
+D:Xtttttttttttta-----tttttt---d---dttd----cttttt-----tttttttttX
+D:Xtttttttttttttttttttt---c-----ttttt---c----ettd--tttttttttttX
+D:Xtttttttttttttttt----d----tttttttttttttttttttttt---tttttttttX
+D:Xttttttt-------c---tttt-d----c--ettttttttttttd-----dttttttttX
+D:Xtttttc--c-c------tttttt-------------ettttttt----tttttttttttX
+D:Xttttttt------ttttttt--c---d---ttttttttttttt--d--tttttttttttX
+D:Xttttt----cc-tttttttttttte----d-ttttttttttttttt----tttttttttX
+D:Xttttt--c------ttttttttttttttttttttttttttte--tt------ettttttX
+D:Xttt--c----ctttttttttttttttttttttttttte------------tttttttttX
+D:Xtttttttttttttttttttttttttttttttttttttttttt--e--ttttttttttttX
+D:XtttttttttttttttttttttttttttttttttttttttttttttttttttttttttttX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:3
+
diff --git a/lib/edit/st_info.txt b/lib/edit/st_info.txt
new file mode 100644
index 00000000..3762d0c5
--- /dev/null
+++ b/lib/edit/st_info.txt
@@ -0,0 +1,744 @@
+# File: st_info.txt
+
+# Fixed Potions of Cure Light/Serious Wounds in the Temple, Potions of
+# Restore Str/Con in the Alchemist
+# Magic Shop - Amulet of Slow Digestion, Wand of Light, Staffs of Enlightenment,
+# Door/Stair Location, Detect Invis/Evil, and Remove Curse
+
+# This file is used to initialize the "lib/raw/st_info.raw" file, which is
+# used to initialize the "store info type" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# Some store indexes are defined in "defines.h", and must not be
+# changed.
+
+# N:<index>:<name>
+# I:<proba>:<item name>
+# T:<proba>:<tval>:<sval>
+# G:char:attr
+# W:max number of items in the store
+
+# proba is the chance(out of 100) of the item being generated
+
+# Version stamp (required)
+
+V:2.0.0
+
+N:0:General Store
+I:100:& Wooden Torch~
+I:95:& Brass Lantern~
+I:95:& Flask~ of oil
+I:100:& Ration~ of Food
+I:100:& Hard Biscuit~
+I:90:& Strip~ of Venison
+I:70:& Pint~ of Fine Wine
+I:80:& Pint~ of Fine Ale
+I:60:& Shovel~
+I:50:& Pick~
+I:100:& Iron Spike~
+I:70:& Iron Shot~
+I:70:& Bolt~
+I:70:& Arrow~
+I:98:& Cloak~
+I:46:& Fur Cloak~
+A:0:0:1:2:3:4
+O:0:5:6:7
+G:1:U
+W:24
+
+N:1:Armoury
+I:70:& Pair~ of Soft Leather Boots
+I:60:& Pair~ of Hard Leather Boots
+I:80:& Hard Leather Cap~
+I:70:& Metal Cap~
+I:65:& Iron Helm~
+I:100:& Robe~
+I:90:& Soft Leather Armour~
+I:90:& Soft Studded Leather~
+I:90:& Hard Leather Armour~
+I:85:& Hard Studded Leather~
+I:90:& Leather Scale Mail~
+I:80:& Metal Scale Mail~
+I:75:& Chain Mail~
+I:80:& Augmented Chain Mail~
+I:75:& Metal Brigandine Armour~
+I:68:& Bar Chain Mail~
+I:100:& Set~ of Leather Gloves
+I:80:& Set~ of Gauntlets
+I:100:& Small Leather Shield~
+I:90:& Large Leather Shield~
+I:80:& Small Metal Shield~
+A:0:0:1:2:3:4
+O:8:9:10:11
+G:2:s
+W:24
+
+N:2:Weaponsmith
+I:100:& Dagger~
+I:100:& Main Gauche~
+I:100:& Rapier~
+I:100:& Small Sword~
+I:100:& Short Sword~
+I:100:& Sabre~
+I:100:& Cutlass~
+I:100:& Tulwar~
+I:100:& Broad Sword~
+I:100:& Long Sword~
+I:100:& Scimitar~
+I:100:& Katana~
+I:100:& Bastard Sword~
+I:100:& Spear~
+I:100:& Awl-Pike~
+I:100:& Trident~
+I:100:& Pike~
+I:100:& Beaked Axe~
+I:100:& Broad Axe~
+I:100:& Lance~
+I:100:& Battle Axe~
+I:100:& Hatchet~
+I:100:& Sling~
+I:100:& Short Bow~
+I:100:& Long Bow~
+I:100:& Light Crossbow~
+I:100:& Iron Shot~
+I:100:& Arrow~
+I:100:& Bolt~
+I:100:& Whip~
+I:100:& Small Wooden Boomerang~
+A:23:0:1:2:3:4
+O:12:13:14:15
+G:3:w
+W:24
+
+N:3:Temple
+I:100:& Nunchaku~
+I:100:& Quarterstaff~
+I:100:& Mace~
+I:100:& Bo Staff~
+I:100:& War Hammer~
+I:100:& Lucerne Hammer~
+I:100:& Morning Star~
+I:100:& Flail~
+I:100:& Lead-Filled Mace~
+I:100:Remove Curse
+I:100:Blessing
+I:100:Holy Chant
+I:100:Heroism
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Word of Recall
+#I:100:Cure Light Wounds
+T:100:71:34
+#I:100:Cure Serious Wounds
+#I:100:Cure Serious Wounds
+T:100:71:35
+T:100:71:35
+I:100:Cure Critical Wounds
+I:100:Cure Critical Wounds
+I:100:Restore Life Levels
+I:100:Restore Life Levels
+I:100:Restore Life Levels
+I:100:& Whip~
+I:100:& Mace~
+I:100:& Ball-and-Chain~
+I:100:& War Hammer~
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Cure Critical Wounds
+I:100:Cure Critical Wounds
+I:100:Restore Life Levels
+I:100:Restore Life Levels
+I:100:Restore Life Levels
+I:100:Remove Curse
+I:100:Remove Curse
+I:100:*Remove Curse*
+I:100:*Remove Curse*
+A:0:0:1:2:3:4
+O:26:27:28:29
+G:4:g
+W:24
+
+N:4:Alchemy shop
+I:100:Enchant Weapon To-Hit
+I:100:Enchant Weapon To-Dam
+I:100:Enchant Armour
+I:100:Identify
+I:100:Identify
+I:100:Identify
+I:100:Identify
+I:100:Light
+I:100:Phase Door
+I:100:Phase Door
+T:100:70:9
+I:100:Monster Confusion
+I:100:Magic Mapping
+I:100:Treasure Detection
+I:100:Object Detection
+I:100:Trap Detection
+I:100:Detect Invisible
+I:100:Recharging
+I:100:Satisfy Hunger
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Word of Recall
+T:100:70:9
+T:100:70:9
+#I:100:Restore Strength
+T:100:71:42
+I:100:Restore Intelligence
+I:100:Restore Wisdom
+I:100:Restore Dexterity
+#I:100:Restore Constitution
+T:100:71:46
+I:100:Restore Charisma
+I:100:Identify
+I:100:*Identify*
+I:100:*Identify*
+I:100:*Identify*
+I:100:*Identify*
+I:100:*Identify*
+I:100:*Identify*
+I:100:Light
+#I:100:Restore Strength
+T:100:71:42
+I:100:Restore Intelligence
+I:100:Restore Wisdom
+I:100:Restore Dexterity
+#I:100:Restore Constitution
+T:100:71:46
+I:100:Restore Charisma
+I:100:Enchant Armour
+I:100:Enchant Armour
+I:100:Recharging
+I:100:Satisfy Hunger
+I:100:Satisfy Hunger
+I:100:Satisfy Hunger
+A:0:0:1:2:3:4
+O:30:31:32:33
+G:5:b
+W:24
+
+N:5:Magic shop
+I:100:Protection
+I:100:Levitation
+I:100:Protection
+I:100:Fire Resistance
+I:100:Cold Resistance
+I:100:Charisma
+I:100:Slow Digestion
+T:100:40:3
+I:100:Acid Resistance
+I:100:Lightning Resistance
+I:100:Searching
+I:100:Cure Light Wounds
+# Rods
+I:100:Probing
+I:25:& Wooden Rod~ of#
+# Book
+T:100:111:50
+# Wands
+T:100:65:3
+T:100:65:8
+T:100:65:11
+T:100:65:16
+T:100:65:22
+# Staves
+T:100:55:3
+T:100:55:5
+T:100:55:8
+T:100:55:9
+T:100:55:14
+T:60:55:15
+T:60:55:16
+T:60:55:17
+A:0:0:1:2:3:4
+O:34:35:36:37
+G:6:r
+W:24
+
+N:6:Black Market
+A:30:0:1:2:3:4
+O:38:39:40:41
+G:7:D
+F:ALL_ITEM | MEDIUM_LEVEL
+W:24
+
+N:7:Home
+A:0:0:54:55:3:0
+O:0:0:0:0
+G:8:y
+W:24
+
+N:8:Book Store
+# & Book~ of Beginner Cantrips
+T:100:111:50
+T:100:111:50
+T:100:111:255
+T:100:111:255
+T:100:111:255
+T:100:111:255
+T:100:111:255
+T:100:111:255
+A:0:0:1:2:3:4
+O:42:43:44:45
+G:9:o
+W:24
+
+N:9:Pet Shop
+I:100:Egg
+T:100:70:6
+I:100:& Hard Biscuit~
+A:0:0:1:2:3:4
+O:46:47:48:49
+G:+:b
+F:MEDIUM_LEVEL
+W:12
+
+N:10:Mayor's Office
+A:0:0:16:15:35:0
+O:1:1:1:1
+G:+:o
+W:0
+
+N:11:Inn
+I:100:& Ration~ of Food
+I:100:& Hard Biscuit~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Fine Wine
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:2:2:18:18
+G:+:w
+W:8
+
+N:12:The Soothsayer
+I:20:Divination
+I:20:Divination
+I:20:Divination
+I:20:Divination
+I:20:Divination
+I:20:Divination
+A:0:0:2:0:8:0
+O:3:3:3:3
+G:+:B
+F:RANDOM
+W:2
+
+N:13:Library
+I:100:Identify
+A:0:0:14:15:16:2
+O:4:4:4:4
+G:+:U
+W:2
+
+N:14:Castle
+A:0:0:16:35:0:0
+O:16:16:16:16
+G:+:o
+W:0
+
+N:15:Casino
+A:13:0:9:10:0:12
+O:17:17:17:17
+G:+:s
+W:0
+
+N:16:Beastmaster Shanty
+# Disabled the bounty list for the time being to not confuse people
+# with the bounty quest
+# A:18:0:19:20:21:22
+A:18:0:21:22:0:0
+O:19:19:19:19
+G:+:g
+W:0
+
+N:17:Fighters Hall
+A:0:0:24:25:0:0
+O:20:20:20:20
+G:+:s
+W:0
+
+N:18:Tower of Magery
+A:0:0:26:27:0:0
+O:21:21:21:21
+G:+:b
+W:0
+
+N:19:Inner Temple
+A:0:0:28:29:0:0
+O:22:22:22:22
+G:+:G
+W:0
+
+N:20:Paladins Guild
+A:0:0:28:25:0:0
+O:23:23:23:23
+G:+:g
+W:0
+
+N:21:Rangers Guild
+A:0:0:31:32:0:0
+O:24:24:24:24
+G:+:u
+W:0
+
+N:22:Thunderlords' Nest
+A:0:0:33:2:34:0
+O:25:25:25:25
+G:+:U
+W:0
+
+N:23:The Mirror
+A:0:0:44:15:16:43
+O:51:51:51:51
+G:+:U
+W:0
+
+N:24:Seat of Ruling
+A:0:0:17:35:0:0
+O:52:52:52:52
+G:+:U
+W:0
+
+N:25:Wizards Spire
+A:60:0:26:27:0:0
+O:54:54:54:54
+G:+:U
+W:0
+
+N:26:Priests Circle
+A:0:0:28:29:0:0
+O:55:55:55:55
+G:+:o
+W:0
+
+N:27:Tower of the King
+A:0:0:17:35:0:0
+O:57:57:57:57
+G:+:U
+W:0
+
+N:28:Library
+I:100:Identify
+A:0:0:14:15:16:2
+O:58:58:58:58
+G:+:U
+W:2
+
+N:29:The White Tree
+I:100:& Ration~ of Food
+I:100:& Hard Biscuit~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Fine Wine
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:59:59:59:59
+G:+:w
+W:8
+
+N:30:Craftsmaster
+A:0:0:24:25:0:0
+O:60:60:60:60
+G:+:s
+W:0
+
+N:31:Earth-Dome (Nature)
+A:0:0:39:0:0:0
+O:61:61:61:61
+G:+:U
+W:0
+
+N:32:Minstrels Haven
+A:0:0:40:41:0:0
+O:62:62:62:62
+G:+:U
+W:0
+
+N:33:Star-Dome
+A:0:0:46:47:0:0
+O:63:63:63:63
+G:+:U
+W:0
+
+N:34:Valarin Temple
+A:0:0:28:48:0:0
+O:64:64:64:64
+G:+:U
+W:0
+
+N:35:Sea-Dome
+A:0:0:49:35:0:0
+O:65:65:65:65
+G:+:U
+W:0
+
+N:36:The Golden Flower
+A:0:0:50:51:0:0
+O:66:66:66:66
+G:+:U
+W:0
+
+N:37:The Fountain
+A:0:0:52:53:0:0
+O:67:67:67:67
+G:+:U
+W:0
+
+# Here begins the random shops, for the random towns
+N:38:Axe Smith
+T:100:24:256
+A:0:0:1:2:3:4
+O:12:13:14:15
+G:3:w
+F:RANDOM | MEDIUM_LEVEL
+W:12
+
+N:39:Hafted Smith
+T:100:21:256
+A:0:0:1:2:3:4
+O:12:13:14:15
+G:3:w
+F:RANDOM | MEDIUM_LEVEL
+W:12
+
+N:40:Polearm Smith
+T:100:22:256
+A:0:0:1:2:3:4
+O:12:13:14:15
+G:3:w
+F:RANDOM | MEDIUM_LEVEL
+W:12
+
+N:41:Sword Smith
+T:100:23:256
+A:0:0:1:2:3:4
+O:12:13:14:15
+G:3:w
+F:RANDOM | MEDIUM_LEVEL
+W:12
+
+N:42:Rare Jewelry Shop
+T:100:40:256
+T:100:45:256
+A:0:0:1:2:3:4
+O:34:35:36:37
+G:6:v
+F:RANDOM | DEPEND_LEVEL | DEEP_LEVEL | FORCE_LEVEL
+F:VERY_RARE
+W:10
+
+N:43:Jewelry Shop
+T:100:40:256
+T:100:45:256
+A:0:0:1:2:3:4
+O:34:35:36:37
+G:6:y
+F:RANDOM | DEPEND_LEVEL | MEDIUM_LEVEL | FORCE_LEVEL
+F:RARE
+W:20
+
+N:44:Footwear Shop
+T:100:30:256
+A:0:0:1:2:3:4
+O:8:9:10:11
+G:2:r
+F:RANDOM | MEDIUM_LEVEL
+F:COMMON
+W:12
+
+N:45:Rare Footwear Shop
+T:100:30:256
+A:0:0:1:2:3:4
+O:8:9:10:11
+G:2:r
+F:RANDOM | DEEP_LEVEL | MEDIUM_LEVEL
+F:VERY_RARE
+W:8
+
+N:46:Library
+T:100:110:256
+T:100:111:256
+T:100:112:256
+T:100:113:256
+T:100:114:256
+T:100:115:256
+T:100:116:256
+T:100:117:256
+T:100:118:256
+T:100:119:256
+T:100:120:256
+T:100:121:256
+T:100:122:256
+T:100:123:256
+T:100:124:256
+T:100:125:256
+A:27:0:1:2:3:4
+O:8:9:10:11
+G:9:y
+F:RANDOM | DEPEND_LEVEL | MEDIUM_LEVEL
+W:24
+
+N:47:Forbidden Library
+T:100:110:256
+T:100:111:256
+T:100:112:256
+T:100:113:256
+T:100:114:256
+T:100:115:256
+T:100:116:256
+T:100:117:256
+T:100:118:256
+T:100:119:256
+T:100:120:256
+T:100:121:256
+T:100:122:256
+T:100:123:256
+T:100:124:256
+T:100:125:256
+A:27:0:1:2:3:4
+O:8:9:10:11
+G:9:v
+F:RANDOM | DEPEND_LEVEL | DEEP_LEVEL
+F:RARE
+W:12
+
+N:48:Expensive Black Market
+A:0:0:1:2:3:4
+O:38:39:40:41
+G:7:v
+F:RANDOM | ALL_ITEM | DEEP_LEVEL | DEPEND_LEVEL | MEDIUM_LEVEL
+W:12
+
+N:49:Common Shop
+I:95:& Brass Lantern~
+I:100:& Flask~ of oil
+I:100:& Ration~ of Food
+I:60:& Shovel~
+I:50:& Pick~
+I:100:& Iron Spike~
+I:70:& Iron Shot~
+I:70:& Bolt~
+I:70:& Arrow~
+I:98:& Cloak~
+I:46:& Fur Cloak~
+I:100:Word of Recall
+I:100:Cure Critical Wounds
+A:0:0:1:2:3:4
+O:0:5:6:7
+G:1:U
+W:12
+F:RANDOM
+
+N:50:Dragon Hunter
+T:100:38:256
+A:0:0:1:2:3:4
+O:8:9:10:11
+G:2:v
+F:RANDOM | DEEP_LEVEL | DEPEND_LEVEL
+F:VERY_RARE
+W:12
+
+N:51:Speed Ring Market
+T:100:45:31
+A:0:0:1:2:3:4
+O:34:35:36:37
+G:6:G
+F:RANDOM | SHALLOW_LEVEL | DEPEND_LEVEL
+F:VERY_RARE
+W:6
+
+N:52:Scribe
+T:100:70:256
+A:0:0:1:2:3:4
+O:8:9:10:11
+G:5:B
+F:RANDOM | MEDIUM_LEVEL | DEPEND_LEVEL
+W:12
+
+N:53:Potion Store
+T:100:71:256
+T:100:72:256
+A:0:0:1:2:3:4
+O:8:9:10:11
+G:5:B
+F:RANDOM | MEDIUM_LEVEL | DEPEND_LEVEL
+W:12
+
+N:54:Recaller
+I:100:Word of Recall
+A:33:0:1:2:3:0
+O:8:9:10:11
+G:+:b
+F:RANDOM | COMMON
+W:2
+
+N:55:Master Archer
+T:100:19:2
+T:100:19:12
+T:20:19:13
+T:100:19:23
+T:20:19:24
+T:50:16:256
+T:50:17:256
+T:50:18:256
+A:0:0:1:2:3:4
+O:12:13:14:15
+G:3:g
+F:RANDOM | MEDIUM_LEVEL | DEPEND_LEVEL
+F:RARE
+W:24
+
+N:56:Merchants Guild
+A:0:0:56:57:58:0
+O:68:68:68:68
+G:+:g
+W:0
+
+N:57:The Mathom-house
+A:0:0:59:0:3:0
+O:0:0:0:0
+G:+:g
+F:MUSEUM
+W:255
+
+N:58:The Prancing Pony
+I:100:& Ration~ of Food
+I:100:& Hard Biscuit~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Fine Wine
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:69:69:69:69
+G:+:w
+W:8
+
+##### Mining equipment for Khazad-Dum #####
+
+N:59:Mining Supply store
+T:100:20:256
+I:100:& Wooden Torch~
+I:95:& Brass Lantern~
+I:95:& Flask~ of oil
+I:75:& Dwarven Lantern~
+I:60:& Feanorian Lamp~
+T:60:65:6
+T:70:71:22
+A:0:0:1:2:3:4
+O:11:15:26:40
+F:MEDIUM_LEVEL
+G:+:s
+W:24
+
+## Library quest in Minas Anor
+
+N:60:Library
+I:100:Identify
+A:61:0:14:15:16:2
+O:4:4:4:4
+G:+:U
+W:2
+
diff --git a/lib/edit/t_basic.txt b/lib/edit/t_basic.txt
new file mode 100644
index 00000000..78103425
--- /dev/null
+++ b/lib/edit/t_basic.txt
@@ -0,0 +1,80 @@
+# File: t_lite.txt
+
+# *Basic* town (vanilla style)
+
+
+############### Town Layout ###############
+
+F:*:7:3:0:0:0:0:0:8
+
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:###################################################################................................................................###################################################################
+D:###################################################################................................................................###################################################################
+D:###################################################################................................................................###################################################################
+D:###################################################################.....................#########...................#########......###################################################################
+D:###################################################################.......#########.....#########......#######......#########......###################################################################
+D:###################################################################.......#########.....####3####......#######......####1####......###################################################################
+D:###################################################################.......####4####....................#######.....................###################################################################
+D:###################################################################....................................###2###.....................###################################################################
+D:###################################################################................................................................###################################################################
+D:###################################################################.................................*..............................###################################################################
+D:###################################################################...##8##........................................................###################################################################
+D:###################################################################...#####..............####5####...................###7###.......###################################################################
+D:###################################################################...#####..............#########.....####6####.....#######.......###################################################################
+D:###################################################################...#####..............#########.....#########.....#######.......###################################################################
+D:###################################################################...........###9###....#########.....#########.....#######.......###################################################################
+D:###################################################################...........#######..................#########.....#######.......###################################################################
+D:###################################################################...........#######................................#######.......###################################################################
+D:###################################################################..................................................#######.......###################################################################
+D:###################################################################................................................................###################################################################
+D:###################################################################................................................................###################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+
+############### Starting positions ###############
+
+# Standard starting position for normal races
+P:32:100
diff --git a/lib/edit/t_bree.txt b/lib/edit/t_bree.txt
new file mode 100644
index 00000000..c74fd58a
--- /dev/null
+++ b/lib/edit/t_bree.txt
@@ -0,0 +1,131 @@
+# File: t_bree.txt
+
+# Bree
+
+############### Additional default terrain settings ###############
+
+# Default for Quest 1 = entrance is quest entrance
+F:z:8:3:0:0:0:0:0:4
+
+# Default for Quest 18 = entrance is tree
+F:y:96:3
+
+# Default for Quest 18 = entrance is tree
+F:x:96:3
+
+############### Quest 4 - Thieves Hideout finished = house ###############
+?:[EQU $QUEST4 2]
+F:z:74:3:0:0:0:0:0:7
+?:[EQU $QUEST4 5]
+F:z:74:3:0:0:0:0:0:7
+?:1
+
+############### Quest 8 - Troll Glade ###############
+?:[AND [EQU $QUEST8 1] [EQU $DAYTIME 0] ]
+F:y:8:3:0:0:0:0:0:8
+?:1
+
+############### Quest 9 - Wights Grave ###############
+?:[EQU $QUEST9 1]
+F:x:8:3:0:0:0:0:0:9
+?:1
+
+###### Additionnal buildings #######
+
+# Castle: Plot Bree
+F:B:75:3:0:0:0:0:0:1
+
+# Mayor's house
+F:b:74:3:0:0:0:0:0:10
+
+# The Prancing Pony
+F:a:74:3:0:0:0:0:0:58
+
+# Soothsayer
+F:c:74:3:0:0:0:0:0:12
+
+# Merchant Guild
+F:d:74:3:0:0:0:0:0:56
+
+# The Mathom-house
+F:e:74:3:0:0:0:0:0:57
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:# VV -- #
+D:# V -- #
+D:# VV -- #
+D:# VVV -- #
+D:# VV -- #
+D:#OOOO V -- #
+D:# OOOO V -- #
+D:#--- OOOOO VVV --- VV #
+D:#------ OOOOOO V -- VVVV #
+D:#---------- OO V -- VVWWVVV #
+D:#-------------- OO VVV -- VVVWWWWWVVV #
+D:#--------------- OOO VVV -- VVWWWWWWWWWVV #
+D:#----------------- OO VVVVVVV VVWWWWWWWWWWWV #
+D:#------------------- OOOOO --VVVV VVVVV VVWWWWWWWWWWWVV #
+D:###------------------ OO ,,,,,,,,,,,,,,,,,, -- VVVVV VV VVVVVVVWWWWWWWVVV #
+D:#CC####------------------ OOO ,,,,,CCCCCCCCCCCCCCCCCC,,,,,,,,, -- VVVVVV VVVVWWVVV #
+D:#TTCCCC###---------------,, OO ,,,CCCCCCTTTTTTTTTTTTTTTTCCCCCCCCCC,,,, -- VVVV #
+D:#--TTTTCCC###---------,,,-- OO ,,CCCCTTTTTT--------------TTTTTTTTTTCCCCC,,,,, ^-- #
+D:#------TTTCCC##-----,,------ O ,,CCCTTTT..................----------TTTTTCCCCCC,, ^^^ -- #
+D:#---------TTTCC##,,,-------- OO ,CCCTTT....--ssssssss-..---..........-----TTTTTTCCC,,, ^^ -- #
+D:#------------TC,,###- --- OO ,CCTTT...-----SSSSSSSS--.----------,,.....------TTTCCCC,, ^^ -- #
+D:#-------------,TTCCC### -- OOO ,,CCTT...-,,,,--ssssssss-..-sssssssssss,---......---TTTTCCT,, ^^ -- #
+D:#--------- ,,,--TTTCCC -- OO ,,CCCTT..-------,,##9#####-.--sssssssssss-,-------...----TTCCTT, ^^^ -- #
+D:#-------- ,, ,,----TTTCC O ,CCC T..--sssSsss,,,,------.--StSStSSSStS--,------.-....--TTCCTT,^^^ -- #
+D:#------ ,, , OO ,CCTTT...---ssstSSS---,,,----.--sssssssssss---,---...----..--TTCCT^^^^ ^^ -- #
+D:#------- x, ,, OO ,CCTT...-----sssssss--,,-,,---.--sssssssssss---,-...-------..--TTC^^^ ^ ---- #
+D:#------- {, OO ,CTT..---,,,,###6###,,,---,,--.--###########----..----------..--T^^^^ ^ --- -- #
+D:#--------- OOO ,CT..,,,,----,,,,,,,,------,,-.--###b###e###-....,---sssss---.--T^^ ^ -- -- #
+D:#---------- OO ,CCT.,sssssss----,-----------,,.-----.-----....-,--,,-StSSS---.-T^^^ ^ -- ----- #
+D:#------------- OO ,CCTT.-StStSSS---,-----ssssss--..-----.--....--,,,,,,-,sssss---.-T^^^ ^ -- -- ,,, #
+D:#----------- OOOOO ,CTT-.-sssssss---,-----SSSSSS--.------.-..--,,,-ssss--,#####---.-T^^ ^ -- ----- ,, #
+D:#-------- OO ,CCT-..-##5####----,----ssssss-..........--XXXX,-ssss--,------...-^^^ ^ ^^ ^ --- ---- ,,, #
+D:#- ---- OOOOOOOO ,C OOOO--OOOOO----,----#c##4#-.---.,----,-UUUU,-SSSS--,-----..---^^ ^ ^ --- -----, OOOOOOOOOOOOOO#
+D:#- ---- OOOOOOO ,CT-OssOOOO---OOOOOOOOO--OOOO--.-T-.-sss--,XXXX,-ssss---,---..--T^^ -- -- OOO #
+D:#- ----- OOOOOOOOSt.---------XXXX-OOOO--OOOO---.-StS--,#0##,-ssss---,---.---^^ ^ ^ -- --- OOOO #
+D:#- --- ----- ,,CT--.ss.-sssss---XXXX,---------OOOO.-sss---,,,,,-####--,---..-T^^ ^ ^ -- --- OO #
+D:# ---- ---- ,,CT--.B#.-SStSS---####,------------OO-#z#-ssssss-,,,---,----.--T^^ ^ -,- OOOOO #
+D:# ------- ---- ,,CTT-....-sssss--,,,,,,-------------OO-,--SSSSSt-ss-,-,---...-T^^ ^ ^ -, OOOO #
+D:# ------- ------ ,,CCTT---..#2###-,sssss,-SSSSSSSS-----OO,--ssssss-tS--,.....---^^ ^^ ^^^ -, OOOOOOOO #
+D:# ----- ----- ,,CCT----..,,,,,-StSSS,-ssssssss------OOO-#1##a#-ss....-----T^^ ^^ -,- OOOOO #
+D:# ---- -------- ,,CCTT----..----,sssss,-##7###d#--------OO,.,,.,-##.----TTTT^^ ^ ^^ -, OOOOO #
+D:# --------------- ,,,CCTTTT--..---,##3##-,--,,,---------...OOOOOOOOOOOTTTTTCC^^^ ^^ ^^ ,- OOO #
+D:# -------- ,,,CCCC --..........,-,,---,--.......-------TTTTTOCCCCC,,^^^^^^^^^^^ -.- OOOOO #
+D:# ---------- ,, ,,CCCTT----------.....-......-------TTTTTTTCCCCO,,,,, ^^^^^^^ -.- O #
+D:# ------- ,, ,,CCTTTTTTTTTT-----...------TTTTTTTCCCCCC,,,,OOO -.- OOOO #
+D:# ---- ,,, ,CCCCCCCCCCTTTTT-----TTTTTTCCCCCC,,,,,, OOO OOOOOOOOO #
+D:# ^^ ---- ,, ,,,,,,,,,,CCCCCTTTTTTCCCCC,,,,,, OO OOO-- #
+D:# ^^^^^ ,,, ,,,,,CCCCCC,,,,, OOOO OOO-- #
+D:# ^^^^^^^^^ ,, ,,,,,, OOOOOOO OOO--- #
+D:# ^^^^^^^^^ ,, OOOOOOO---- #
+D:# ^^^^^^^^^^^^^^^ ,,, ..------ #
+D:# ^^^^^^^^^^^^^^ ,,, ...... ....----- #
+D:# ^^^^^^^^^^^^^^^ ,,, ........... ............ ............-------,,,, #
+D:#^^^^^^^^^^^^^^^^^ ,, ... .........-------------- ,,,,,,, ,,,,,,,,, #
+D:# ^^^^^^^^^^^^^ ,, . ,,,,,, ,,,,,,,,, #
+D:# ^^^^^^^^^^^^^^ ,, ... ,,,,, ------ --- #
+D:# ^^^^^^^^^^^^^^^ ,, . ,,,,,,,,------- ----- #
+D:# ^^^^^^^^^^^^^^ , .. ---------------- #
+D:# ^^^^^^^^^^^^^^^^ ,, .. ---------y-------- #
+D:# ^^^^^^^^^^^^^^^ , .. ----------------- #
+D:# ^^^^^^^^^^^^^^^^ ,,. --- ---- ---- #
+D:# ^^^^^^^^^^^^^ ,. - -- -- #
+D:# ^^^^^^^^^^^^^^ . #
+D:# ^^^^^^^^^^^^^^ . #
+D:######################################################################################################################################################################################################
+
+
+############### Starting positions ###############
+
+# Standard starting position for normal races
+?:[AND [EQU $LEAVING_QUEST 0] [NOT [EQU $RACE Vampire] ] ]
+P:33:131
+
+# Standard starting position for vampires (at the dungeon entrance)
+?:[AND [EQU $LEAVING_QUEST 0] [EQU $RACE Vampire] ]
+P:31:150
diff --git a/lib/edit/t_d_bree.txt b/lib/edit/t_d_bree.txt
new file mode 100644
index 00000000..2112bc4e
--- /dev/null
+++ b/lib/edit/t_d_bree.txt
@@ -0,0 +1,101 @@
+# File: t_d_bree.txt
+#
+# Destroyed Bree
+
+# original town by someone else
+# screwing up by fearoffours (fearoffours@moppy.co.uk)
+#
+# Created for ToME
+
+
+# Dead/burnt tree
+F:D:92:3
+
+# Ash
+F:A:93:3
+
+# Fire
+F:F:205:3
+
+# Permanent rubble
+F:R:206:3
+
+############### Town Layout ###############
+
+D:###########################################################################################################F##########################################################################################
+D:#DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDFDDDDDDDDDDDDDDD VVDDDDDDDDDDDDDD--DDDDDDDDFFDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:# DDD DDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD VDDDDDDDDDDDDDD--DDDDDDDDDDDDDDDDD D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDDDDDDDDDDD D D DDDDDDDDDDDDDDDDDDDDDDDDDD DD D D D DDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDVVDDDDDDD --DDDDDDDFFFFDDDDD DDDDDDDDDDDDDD DDD DD DDDDDDDDDDDDDDDD #
+D:#DDDDDDD D DDDDDDDDDDDDDDDDD DDDDDDDD DD D AADD D D DDDD D D D D D D DDAADDDDFDDDDDDDDDDDDDDDDDDDDDDDVVFFFDDDDD --DDDDDAAADDDDDD FDDDDFDDDDFFFDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDD#
+D:# DDDD DDD DD DDDDDDDDDDDDDDDDD D DD DDDDDDDDD D D DDDDDDDDDDDDDDDDDDDDDDDDDAAADDDDDDDDDDDD VVDDDDDDD --DDDDDDDDDDDDDDDDDDDDDDAAA DDDDDDDDDDDDDDAAADDDDDDDFDDDDDDD #
+D:#OOOODDDDDDD D D DDDDDDDD D DDDDDDDDD D DD D DDDDDDDDDDDDD D DDDDDDDDDDDDDDDAADDDDDDD DDDDDDDDDDDDDDD VDDDDDDD --DDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDFFFADDDDDDDDDDDD #
+D:# OOOODDDDDDD DDDDDDDDDDDDDDDDDDDDDDD AA DDDDDDDDD ADD DDDDDDDDDDDDD D DDDDDAAAAAADDDDDDDDDDDDAAADDDDDDDDDDDDDDD VDDDDDDD --DDDDDDDDDDDD DDDDDAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDFF #
+D:#--- OOOOODDDDDDDDDDDDDDDDD DDDDDDDD D DD D AAADDAADDDDDDDDD D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDFFDDDD VVV ---DDDDDDDDDDDD DDDDDDDDD VVDDDDDADDDDDDDDDDDDDDDDD #
+D:#------ OOOOOO DD D D DDDDDDDDDD DDD DDDDDDDDDDDAAAA F D DDDDDDDDDDDDDDDDDDDDAAADDDDDDDDDDDDDDDDDDDDDDDD V --DDDDDDDDDDDDD DDDDAD VVVVDDDDDDDDDFF DDDDDDDDDDD #
+D:#---------- OO DDD ADAAADDD DDDDDDDDDDDDDDDDD D D DDDDAAADDDDDDDDDDDDD D ADDDDDDD FDDDDDDDDDDDDDDFFFDDDDDDDDDDDDD V -- DDDDDDDDDDD DD VVWWVVVDDDDDAAA DDDDDDDDDDDDDD #
+D:#-------------- OO DDDDDDDDDDDDDDDDD A D D D DDDDDAAADDDDDDDDDDDDDD DDD D DDDDDDDDDDDDDDDDDDDDDDAFFADDAADDDDDDDDDDVVV --DDDDDDDDAAAADDDDDD DDD VVVWWWWWVVVDDDDDDDDDDDDDDDDDDDDDDD#
+D:#------D-------- OOODDDDDDD D DDDDAAADDD AAD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDD FDDDDDDDDDDDDDDDD VVV --DDDDDDDDDDDDDDDD VVWWWWWWWWWVVDDDDDDDDDDDDDDDD #
+D:#----------------- OO A DDDDDDDDDDDDDDDDD AAA D DDDD DD DDDDDDDDDDDDDDDDDDDDD DDDDDD DDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDD VVVVVVVDDDDDDDDDDDDDDDD VVWWWWWWWWWWWVDDDDDD DDDDDDDD #
+D:#------------------- OOOOO DD DDDDDDDDDD DDDDDDDD D DDDDDDDDDDD DDD DDD DD DDD DDDDD DDDDDDDDDDDDDDDDDFDDDDDDDDDDDDDDDD--VVVV VVVVVDDDDDDD VVWWWWWWWWWWWVVDDDDDDDDD DDDDD #
+D:###------------------ OOA D AA DDD DDDDDDDDD DDDDDDDDDDDDDDDDD DDDD DDD ,,,,,,,,,,,,,,,AA,DDDDDDDDDDDDDDDDDDDDDFFDDDDDDDDD -- VVVVV VV VVVVVVVWWWWWWWVVVDDDDDDD DDDDDDDD #
+D:#CC####------------------ OOODDDDDDD DDD DDDDDDDDD DD D DDDD DD DDDD,,,,CCCCCCCCCCCCCCCCCC,,,,,,,A,DDDDDDDDDDDDDDDDDDDDDDD --DDDDDDD VVVVVV VVVVWWVVVDDDDDDDDDDDDDDDDDDDDDDD #
+D:#TTCCCC###----D----------,, OO DDDDDDDDDDDDDDDFDDDDDDDDDDDDDDDDDDDDDDD DD ,,,CCCCCCTTTDDTTTDD TTDDTCCCCCCCCCC,,,,DDDDDDDFDDDDDFFDDDDDDDD --DDDDDDDDDDDDDDDDDDDDDDDVVVVDDDDDDFFFAAADDDDFDDDDDD #
+D:#--TTTTCCC###---------,,,-- OO F DDD D DDDDDDDD DD D DDD DDDD,CCCCTTTTTD---R----------TT T TDDDTCCCCC,,,,,DDDDDDDDDDDDDD A ^--DDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#------TTTCCC##-----,,------ ODDDDDDDDDDDDDDDD DDDDDDDDD DDDDDDDD DD ,,CCCTTDDD....RRR........D.----A-----TDDTTCCCCCC,,DDDDDDDDDDDDDD^^^ --DDDDDDDDDDDDDFFDD DDDDDDDDDD DDDDDDDDDDDDDDDDDD #
+D:#---------TTTCC##,,,-------- OO D DDAAAADDDDDD DDDDDDDDDD D DD ,CCC TD....--ssss-sss-D.--A.......A..--R--TTDDDTCCC,,,DDDDDDD ^^ --DDDAAAD DDDDDDDD DDDDDDDDDDDDDDD DDDDD FDDDDDDD #
+D:#------------TC,,###- --- OODDDDDDD DDDD A FDDDDDDD DD D,CCTTT.DDAF---S.SFRSRS#-.------DD-R,,.....------TDDDCCC,,DDDDDDD^^ --DDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDFDDDDDDDD #
+D:#-------------,TTCCC### -- OOO DDD DDD DDDD D D DD DD ,,CCTD...F,,,,A-ssss.ss-...-ssFs--sssss,---...A..---TDDDCCT,A ^^DDDDDDD--DDDDDDDDDDDD DDDDD DDDDDDDDDDDDFFDDDDDDDDDDD #
+D:#--------- ,,,--TTTCCC -- OODDDDDDDDDDDADDDDDDDDDDDDDDDDDD D ,,CCCTT..-------,,#.,##,-#-.--sss.sRRRssss,--RAA--..R----TDCCTT, ^^^DDDDDDD --DDDDDDDDDDDDFFFDDDDDD DDDDDDDDDDDDDDDDDDDDDDDD #
+D:#-------- ,, ,,----TTTCCDDDDDDD O FDDDDDDDDD DDDDDAADDDDD DDDDCCC DF.A-sssSssRS,,,------.--S.SSSSFSSRR--,----DD.-....--FDCCTT,^^^DDDDDDD --DDDDFAAADDDD DDDDDD DDDDDDDDDDFDDDDDDDDDDDDDDD#
+D:#------ ,, ,DDDDDDDDDDDDDDDD OO DDDDDDDDDD DADDDDDDDD DDD,CCTDT.F.---ssRsSSS---,,,--A-.--ss,sRsFsssFs--,-R-.FF-R--..--TDCCT^^^^ ^^DDDDDDD --FDDDDDDDDDDDDDD DD DD FDDDDDDDDDDDDDDDD #
+D:#------- ,, ,,DDDDDDDDAAADDDDD OODDDDDDDDDDDDDADDDDDDDDDDD D ,CCTT...-----s,,-sss#-,,-,DD-R.--.ssssAsss,s#--,-...-------..-FFTC^^^ ^DDDDDDD ----DDDDDDDDDDDDDDDDDDDD DDDDDD DDDDDDDD #
+D:#------- {,DDDDDDDDDDDDDDDD F OODDDDDDD DDDDDDDDDD DDD,CTT..-DD,A,,####R###R,-R-,,--.--#####F.#R#A----..-DD---A---R.--D^^^^ ^DDDDDDD--- --DDDDDDDDDDDDDDDDDD DDDDDD DDDD #
+D:#-F-------DDDDDDD DDDDDADDDDDDDDDDDOOO D DDDDDDDD DDD D ,CT..,,,,----,,,,,#,,------,A-R--#.-#.##.##R-...R,---.sss----.--T^^ ^DDDDDDD -- --DDDDDDD ADDDDDDDDDDDDDDDDDDDDDDDFFFDDDDDD#
+D:#----------DDDDDDDDDDDDDDDDDDDDDDD OO DDDDDDDD DDD,CCT.,ssRsss#----,R---DD---#-,FF-----.----#....-,--,,sStSSS--R.-D^^^ ^DDDDDDD -- -----DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#-------------DDDDDDD ADDDDDDD F OODDDDDDDDDDDDDDDD D ,CCTT.-StS,RS----,-----RsRsA,--..-FA-----....--,,,R,,-.s.sss#--.-D^^^ ^ --DDDDDDD --DDDDDDD ,,DDDDDDDDDD DDDD #
+D:#----------FDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDOOOOO DD D ,CTT-.--sFs,ss#-R,-----SRSSSS--.------R-..FF,,,-sssss-,##FF#---.-T^^ ^DDDDDDD --DDDDFFD -----DDDDDDD ,,DDDDDDDDDDDDDDDDDDDDDDD #
+D:#--------DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD OO D DD D DD,CCT-..-#####,#---AA---RsssRs,-...R...A.R--RXXX,-Rss---,------..F-^^^ ^ ^^ ^ ---DDDDDDD D---D ,,, ADDDDDDDDDDDDDDDD #
+D:#- ----DDDDDDD FDAADDDDDDDDDDDDD FDDDDDDD OOOOOOOOR DD RD ,C OOOO--OOOOO----,----######-.---.,----,-UUUUs-SSSR--,--A--..---^^ ^ ^ A ---DDDDDAADDDDDDDDD -----,DDDDDDD OOOOOOOOOOOOOO#
+D:#- ----DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDOOOOOOOFF,CT-OssOOOO---OOOOOOOOO--OOOO--.-D-.-sRs--,XXXX,-Fsss-R-,---RR-FD^^DDDDDDDDDDDDDD--DDDDDDDAAADDDDDD --DDDDDDD OOADDDDDDD #
+D:#- -----DDDDDDDDDDDDAADD FDDDDD DDDDDDDDDDDDDDDD OOOOOOOOSt.---------XXXR-OOOO--OOOO---.SStS--,####,--sRs-F-,DD-.--F^^ ^ ^ --DDDDDDDDDDAAADDDDDDDDDD--- OOOO ADDDDDDD #
+D:#- --- -----DDDDDDAAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,,CT--.ss.-RsAsR---RXXs,---------OOOO.-sRs---,,,,,-###.--,---..-T^^ ^ ^DDDDDDD --DDDDDDDADDDDDDDDDDDDDDDD --- OOADDDDDDDDDDDDDDDD #
+D:# ---D ----DDDDDDDDDDDDDDDDDDDDDDD F FDDDDDDD ,,CT--.s#.-SSt,S-AA##A#,---A-R------OO-#R#-ss,,ss-,,,---,---D.--DA^ ^DDDDDDD -,-DDDDDDDDDDDDDDDDDDDDDDD OOOOODDDDAAADDDDDDDDD #
+D:# ------- ---- ADDDDDDDDDDDDDDDDDDD DDDDDDDDDDD ,,CTT-..RR-FsssR--,,,,,,---------DDA-OO-,--SSSRSt-ss-,-RR--...-T^^ ^ ^DDDDDDD -,DDDDDDD FDDDDDDDDDDDDDDOOOODDDDDDDDDDDDAD DDDDDDD#
+D:# ------- ------DDDDDDDDD DD DDDDDDDDDDD DDDDDDDDDD ,,CCTD---.R#,#R,-,sss,,S-S,SSSSS--R---OO,--s-ss----S--,.....---^^ ^^ ^^^ -,DDDDDDDDDDDDDDDD OOOOOOOODDDDDDDDDDDDD DDDDDDDDD #
+D:# -----DDDDDDD -----DDDDDDDDDDDDDDDD FDDDDDDDDDDDDDDDD ,,CCT----..,,,,,-StRSS,-s,s,sRss--FF--OOO-#,##-R-ss....-FF--T^^DDDDDDD ^^ -,-DDDDDDDDDDDDDD OOOOODDDDDDDDDDDDDDDDDDD DDDDDDDDDDD #
+D:# ---- --------DDDDDDDDDDDDDDDDDDDDDDAADDDDDDDD A ,,CCTD--DD R--RRsssR,-##,##,#F--------OO,.,,.,-##.----DDDT^^ ^ ^^DDDDDDD-,DDDDDDD OOOOODDDDDDD DDDDD ADDDDDDDDDFFFDDDD#
+D:# ---------------DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD D ,,,CCTTTT--..---,##,###,--,,,--AA-----...OOOOOOOOOOOTTDDDCC^^^ ^^ ^^DDDDDDD ,-DDDDDDD OOODDDDDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDD #
+D:#DDDDDDD --------DDDDDDDD DDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDA,,CCCC --.DD.....AA,-,FF--,--FF..A..--A----TDDTTOCCCCC,,^^^^^^^^^F^DDDDDDD -.- OOOOODDDDDD DDDDDDDDDDDDDDDDAAADDDDDDDDDDDD #
+D:# ----------DDDDDDDDDDDDDD F ADDDDDAAADDDDDDDDDDDDDDD ,, ,,CCCTT-------D--.....R....A.-------TTTDDTTCCCCO,,,,, ^^^^^^^DDDDDDD -.- ODDDDDDDDDDDDDDDDDDAADD DDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDD -----D-DDDDDDDDDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDD ,, ,,CCTTT TTDTTDD-D--...------DTTTDDDCCCCCC,,,,OOOADDDDDDDDDDDDDDDD -.- OOOODDDDDDDDDDDDD DDAAADDDDDDDDD DDDDDD D #
+D:#DDDDDDD ----DDDDDDDDDDDDDDDDAADDDDDDDDDDDDDAAA FDDDDDDD ,,, ,CCCCCCCCCCTTDDT--FF-TTTTDTCCCCCC,,,,,, OOODDDDDDDDDDDDDDDD OOOOOOOOODDDDDDDD DDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDDD #
+D:# ^^ ----DDDDDDDDDDDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDD ,, ,A,,,,,,,,CCCCCTTTDDTCCCCC,,,,,,DDDDDDDDDDDDDDOODDDDDDD DDDDDDDDDOOO--DDDDDDDDDDDDDDDDDDDDDDDDDDDDADDDDDD DDDDD DAADDDDDDDD #
+D:# ^^^^^DDDDDDDDDDDDDDDD DDDDDDDDDDDD DDDDDDDDDDDDDDDDD ,,,DDDDDDDDDDDDDD,,,,,CCCCCC,,,,, ADDDDDDD D OOOODDDDDDD OOO--DDDDDDDAAADDDDDDDDDD DDDAADDDD DDDDDDDDDDDD #
+D:# ^^^^^^^^^DDDDDDDDDDAAAADDDDDDDDDDDAD DDDAAADDDDDDDDDDDDDD ,,DDDDDDDDDDDDDDDD ,,,,,,DDDDDDDDDDDDDDDDDDDDDDD OOOOOOO OOO---DDDDDDDDDDDDDDDD ADDDDDDDDDDDDDD DDDDDDDDDDDDD #
+D:# ^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,,DDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDOOOOOOO----DDDDDFFF DDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:# ^^^^^^^^^^^^^^^DDDDDDDDD DDDDDDDDDDDDDDDDDDDD AA FDDDDDDD ,,,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD FDDDDDDDDDDDDDDDDDDDDDDD ..------DDDDDDDDDDDDDDDDDDDDDDDDDDDD DDD DDDDDDDDDAAADDDDDDDD #
+D:# ^^^^^^^^^^^^^^DDDDDDDDDDDDDDDD DDDDDDDDDDD DDDDDDDDDDD ,,,FDDDDDDDDDDDDDDDD AA......DDDDDDDDDDDDDDDDDDDDDDD ....-----DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAFFDDDDDD #
+D:# ^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDD DDDDDDDDDDDD DDDDDDDDDDDD,,,DDDDDDD ........... ............DDDDDDD....F.......-------,,,,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDAADDD #
+D:#^^^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,,DDDDDDD .AADDDDDDDDDDDDDDDDDDDDDDD .........--------AA----DDDDDDD,,,,,,, ,,,,,,,,,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDFFDDD #
+D:# ^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDD DDDDDDDD DDDDDDDDDDDDDDD ,, A .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAFFDDDDDDDDDDD ,,,,,,DDDDDDD,,,,,,,,,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:# ^^^^^^^^^^^^^^DDDDDDDDDDDDD DDDDD DD DDDDDDDDDDDDDDDDDDDDD ,, AA... ADDDDDDDDDDDDDDFDAAADDDDDDDDD DDDDDDDDD DDD DDDDDDDDDDDDDDDDDDDDDDDDDDD,,,,,DDDDDDD ------ ---DDDDDDD #
+D:# ^^^^^^A^^^^^^^^DDDDDDD DDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDD,, .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,,,,,,,,------- -----DDDDDDD#
+D:# ^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDAAADDDDDDDDDDDDDDDDDDDDD , ..ADDDDDDDDDDDDDDFFDDDDDDDDDDDDDDDDDDDDDDDDDDAADADDDDDADDDDD DDDD DDDDDDDDDDDDDDDDDDDDDDDD A---------------- #
+D:# ^^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDD ,, ..DDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD---------D--------DDDDDDD#
+D:# ^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDD DDDDAAAD DDDDDDDDDDDDD , ..DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDADDDDDDDDDDDDFFFFDDDDDDDDDDDDDDDDDDDDDDDDD -----------------DDDDDDD #
+D:# ^^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDAAAD DDDDDDDDDDDDDDDDDDDDDDDD ,,.DDDDDDDDDDDDDDDDDDD FFFDDDDDD DDDDAADDDDDDDDDDAAFFDDDDDDDDDDDDAAADDDDDDDDDDDDD DDDDDDDDDDDDD --- ---- ----DDDDDDD#
+D:# ^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDD ,.DDDDDDDDDDDDFFDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDFFFDDDDDDDDDDDDDDDDDDDD - -- --DDDFFDD #
+D:# ^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDD .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAADDFFDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAADDDDDDDDDDDDDDDDDDDDDDDDDDAAADDD #
+D:# ^^^^^^^^^^^^^^ ADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAAAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:######################################################################################################################################################################################################
+
+
+############### Starting positions ###############
+
+# Standard starting position for normal races
+?:[AND [EQU $LEAVING_QUEST 0] [NOT [EQU $RACE Vampire] ] ]
+P:33:131
+
+# Standard starting position for vampires (at the dungeon entrance)
+?:[AND [EQU $LEAVING_QUEST 0] [EQU $RACE Vampire] ]
+P:31:150
diff --git a/lib/edit/t_d_gond.txt b/lib/edit/t_d_gond.txt
new file mode 100644
index 00000000..12483e32
--- /dev/null
+++ b/lib/edit/t_d_gond.txt
@@ -0,0 +1,118 @@
+# File: t_d_gond.txt
+
+# Destroyed Gondolin: Your failure has left the city in ruins.
+# Created by Mynstral (mynstral@thehelm.com)
+
+
+# Extra terrain features that aren't commonly used
+
+# Dead/burnt tree
+F:D:92:3
+
+# Ash
+F:A:93:3
+
+# Fire
+F:F:205:3
+
+# Permanent rubble
+F:R:206:3
+
+# Tainted water
+F:w:174:3
+
+# Decoration = Straight Road (B)
+F:":66:3
+
+# Decoration = Straight Road (W)
+F:$:70:3
+
+
+# Town Layout
+
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################^^^^^^^^^^^^R ####
+D:####################################^^^^^^^^^^^R ####
+D:##################################^^^^^^^ R R R ###
+D:#################################^^^^^^^^R C C R CCR CC CC C CCRC CR R ###
+D:################################^^^R^^^^^^^ C RCRCR#R######R#R#####R#####CCR CCR R R ###
+D:###############################^^^^^^^^^^^^ CRRR C# ###### DD D ####RDRD D D ###R###CC C R ^^^^^ ###
+D:##############################^^^^^^R^^^R C R####R##RD DDD R.R## R.DD DDD#RR#####C R R^^^^^^^ R ###
+D:#############################^^^^^^^^^^ # R##########D R######### .D##########R R ^^^^^^^^^^^^ ###
+D:############################^^RR^^ R ############ ..R###########R ..D############C R ^^^^^^^^^^^^^^R ###
+D:############################ C #############DR .###ww#####ww### .D#############CR ^^^^^^^^^^^^^ ###
+D:########################### RR R #############DD .#wwww#R###wwRw# R.RR############# R ^^^^^^^^^^^ ###
+D:########################### R . R RR C#R###########DR .ww###R###ww .DR############C R R ^^^^^^^ R R ###
+D:########################## R ##### RR R #### R R C######wwww### ..w## R##R ..D####wwww#####CR ####### # R ^^^^ ###
+D:########################## R #R##### R ##R## ####### C#R####D DDww#DR # .R# DRRwD DD######C R## ##R#RR ###
+D:####R#################R#w# ### ###R ### R ####### ###### DDw#R D#wDD D####R ##R#### ###
+D:####wR#w###R#R#####R#Rwww# R####R### #R##R ####### R######D R RR..R######R ###
+D:#####wR##w#w##R##wRwww#w## #####R### # ### #########R ######D R .. DD DD ..RRD######CR R ###
+D:#####RwRwRwww##RwRwww#RR## R######R# R ##R R##R#### RR R RC#######Rw ..DD D####### DD ..ww#R##### C # R ###
+D:######w##ww#ww#wwwww#R#### . R R R# R# #######R## D ##### R###### DD ########## R ## ## ### R RR ###
+D:######www#wwwRwRwRwwRw#### .. R CR####### .. D###### R# # ##### .. ########R #R#######R###R#### ###
+D:#######RwwwwRwwwRwwR#ww### R #####D DD .. D###R.R#R# #R## .###D ..DDDR#####CR R #### # #######R ###
+D:########RwwRwwRwwwR#w###### # ###### R R## #####R C# D ..D## ..## RR ..# R .. D DD# R RR#R#######R## ###
+D:#########R#wwwwRww########## #R#R####R ############ R#D R .R#R ## R ..R R.. ..## D R# # ..D#C R R ###R### R## ###
+D:##########R#################### # ####### ############ R #D R R####R D## R# R ..# @ @ ## .#R##R R RD# ## #R#R#R## @ @ ###
+D:#### R#################### ####R# ##R #####R####### RC#D # #R R. D## @@@ @ .##D ..R## R .D #RC #### R @@@@@@ ###
+D:#### ####RRRC##w#LL#""## #######R ## R##R#R ## C### R ###R . D ### R @w@@..###D D .#### ###R @ @ @@@@wwww@@@ ###
+D:#### R####R##RC# R#LL#""# # . R R ###D R##R D###.### .#####w@ @###.## R###R R### R @@ @@wwwwwww@ ###
+D:##### ################### . R C### ## #R D## ..##.R##wRww#..## ..# D ## R D###C @@@@wwwwwwwww@ ###
+D:# R#### D# .#..#ww#Rw#..# .#D R## .. @wwwwwwwwwwww@@ ###
+D:#.. ..#w#w#w# R @wwwwwwwwwwww@ @ ###
+D:# .##R# D# .#.R#ww#wR#..# .#D ####R .. @@wwwwwwwwwww@@ @ R ###
+D:############ ########## # . . . R###D ..#R###R ## ..##..##www##..## ..## #R # R R##C @wwwwwwwwww@@@@ ^^###
+D:#### #### K# C# #LL# "# R . R . . ### ##R# DD###.### .##### R###.###D R### . D#R# @@@wwwwwww@@@@@@ R ^^###
+D:#### ### K CC ww# L# "## ##### # R ## #### # # #### CR##D .. DD### ..###DD .###R DD####RC @@wwwww@@ @ @ ^^^^###
+D:#### ####KK#CC#ww#L # "### ## ###### ###R ###R# R# ##### R#DD D## R .##D ..R# # D #####CR @@wwww@ R R^^^^^^###
+D:######## ###################### ######### R####R#R### # ## R# CRD ..D## R#R .RR ## .#R##R .D##### R DD @@@@@@@ ^^^^^^^###
+D:####### #####R$R$#R#### #### ### ###R# R ## ########R# # # # ww ww .DD## R R.##RR ## RR## D #R# R###### DD DD DD DD DD ^^^^^^^^^###
+D:########$R$$R#R$RR$##### ## R##R###### ##R# ### R### R## R CRR..ww# R #Rw D####.#########R#R####D ..######C D DD DDD D D DD DDD ^^^^^^^^^###
+D:######$$R#$R$$#$#$##$#$### R C D..w#R .###w . DD#################D D .DR#####R DD DDD########DDD DDDD ^^^^^^^###
+D:#######R#$##$$$#$#$$R$#### C#D .w###.R# R D D### #########DD D #R###R DDD###DD D D### D DD R ^^^^^^###
+D:######R$R$$$#$#R#$R$$R$$# R R RR RC##D.w##R # Rw ..D D ####### D D ### DDD##DD D ##DDDDDD ^^^^###
+D:#####$$$$#$$R#$$$$$R$$R### ###### # RR### R###RR RC#D.ww#####ww R RR DD#C DD#DD D DD## D DD R ^^^^###
+D:#####R$$#$$R#####$R$$$R### ## ####R R #R## ##### ##R R ..ww###wwR ..D DR RDDDR R R .DD R R D DR R. DR R D ##D DDD ^^^^###
+D:####R$$###R########R#R$$$# ###R#####R ## ####### # C wwwRw .DDR######R#RDRD RDDD#R###R#R#DDD RR R R D#DD D DD##D ^^^^^^###
+D:###R$#################R### # ## ## # ###########R# CRDD .DD###wwwwww####R . R#R##wwwwww### D .DD#C R DDD##DDD D D##DD D ^^^^^^^###
+D:#######################R## R#### #R ############# R# .D##www .wRw###DDD###www .www#RDR .D#R DDDD D D D###DD D R ^^^^^^^###
+D:########################### R # R R CR# .D#ww ..ww#######ww R.ww#D D#R DD D DD# ## ## DDD DD ^^^^^###
+D:########################### R R# C#D R ..####### R ..DD#R DD D DDD DDD DD D ^^^^###
+D:############################ ##R #R R#D ..D#ww R R..ww#######wR R ..ww#D .. DR# R DDDD DD D D R R ^^^^^^###
+D:############################ ######### C ##DD .D##www .www#########www R.www##D . R## DDD D DD D ^^^^^^^^^###
+D:############################# #####R# R#D DD DD ##wwwwww## #### #####wwwwww###D DD D##RC ^^^^^^^^^^^^###
+D:############################## R ###R #### DD DDD ##### # ######R # ########DDDD RDRD ###RC R ^^^^^^^^^^^^^^###
+D:############################### ### RR CR R#R#R##DDD RDR DD##############D DRRD D D## #R#CCRR R^^^^^^^^^^^^^^^^^###
+D:################################ R # CC R ##R# #R#####R###R#R#R#####R###R###RCRC CR R ^^^^^^^^^^^^^^^^^###
+D:################################# R R R # R CRCR CCCRCC CRRCRCCC C R #C C CR RC C R ^^^^^^^^^^^^^^^^^^####
+D:################################## #### R R R # R ^^^^^^^^^^^^^^^^^^^^^####
+D:#################################### R ##### R ^^^^^^^^^^^^^^^^^^^######
+D:###################################### #### ######## R ^^^^^^^^^^^^^^^^^^########
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+
+# Default starting position
+?:[EQU $LEAVING_QUEST 0]
+P:33:50
+
+# Starting position when coming from quest 19
+?:[EQU $LEAVING_QUEST 19]
+P:51:190
+
+# Starting position when coming from quest 20
+?:[EQU $LEAVING_QUEST 20]
+P:33:13
+
+# Starting position when coming from quest 21
+?:[EQU $LEAVING_QUEST 21]
+P:27:168
+
+# Starting position when coming from quest 22
+?:[EQU $LEAVING_QUEST 22]
+P:6:42
diff --git a/lib/edit/t_d_khaz.txt b/lib/edit/t_d_khaz.txt
new file mode 100644
index 00000000..950f5c82
--- /dev/null
+++ b/lib/edit/t_d_khaz.txt
@@ -0,0 +1,87 @@
+# Town Name: Destroyed Khazad-Dum
+# by fearoffours (fearoffours@moppy.co.uk)
+#
+# Created for ToME
+
+F:o:207:3
+
+# Ash
+F:A:93:3
+
+# Fire
+F:F:205:3
+
+# Permanent rubble
+F:R:206:3
+
+# Town Layout
+D:######################################################################################################################################################################################################
+D:#ooooooooooooo####^^^^^^^^^#######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#####oooo#######oo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^##########oooooooooo CCCCCCC #
+D:#ooo##ooooooooo#####^^^^^##########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^########ooo########ooo##########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^################oooooooooooo CCCCCCCC #
+D:##oo###oo####oo##############################^^^^^^^^^^^^^^^^^########################oooo#########oo#### ###########^^^^^^^^^^^^^^^^^^^^^^^^####### #######oooo########## CCCCCCCC #
+D:##############o#########oo###oo###################^^^^^^^############################oooo#########oo###### ################################# #####ooooooooo############# CCCCCCCC ; #
+D:#^^^^########oooooooooooooo##ooooooooo############################# #################oooo########oo########### ########################## ######ooooooooo################ CCCCCCCC ; #
+D:#############ooooooooooooooooooooooooooo###### ########### ###### ############## ####oooo#######o##o############# ################### ###########ooo######################## CCCCCCCC ; #
+D:#^#############ooooo##################oo### # #### # ##### #### ############### ###ooo########ooo## ## ###### # ## ## ## # #######ooooo########################### CCCCCCCC #
+D:#^^################oo#################ooooo#### ## ; ## ;; o ; o ## # ooooooooo############################ CCCCCCCC #
+D:#^^^^################o##########o#####oooooooooooooooooooooo AAAAAAAA # o ; oooooooooooooooooooooooo##ooo############################ CCCCCCC #
+D:#^^^^^^################################# ## ; o ; AAFFFFFAA A o ; o R#o################################### CCCCCCC#
+D:#^^^^^^################################ ### o ### AAFFFFAAAA ## o ###; o ##A ######################################## CCCCCC#
+D:#^^^^^################################# ### o ### ### ## AAFFFFFAAo ### o ### o #AAFFA RR###################################### CCCCCC#
+D:#^^^^^^^################################ ###### ;; o ######### AAAFFFFFAo ###### o ## ### o ## #AFA #R##################################### ; CCCCCC#
+D:#^^^^^^^^################################ # ## #### o ; ## # # AAAAAAAAA ####### # #### # o ## ###FF# ###R#R################################## CCCCCC #
+D:#^^^^^^^################################### ## ## o ; ;### # AAAAo # # ##o # ## ; o # ##FF ;#R##RR################################# CCCCCCC #
+D:#^^^^^^^^^################################ ## AAAAAAAA ### o ### o # # o ## # #R################################## CCCCCC ; #
+D:#^^^^^^^^^################################# AAFFFFFFAA o o o #R ################################## CCCCCC #
+D:#^^^^^^^^^^################################ ; AAFFFFFFFAAoooooooo o o oooooooooooo AAAA R################################# CCCCCC ; #
+D:#^^^^^^^^^^^^^########################### AAAFFFFFAA o o o o FFFFF A ################################# CCCCCCC #
+D:#^^^^^^^^^^^^^^^########################## AAAAAAAAAAAAAAFF o ### # o o ;### o ### # AF FAA #R############################## CCCCCCC ; #
+D:#^^^^^^^^^^^^############################# AFFFAA #####; o # ## o o # ### o # # # FF ; ###############################; CCCCCCC ; #
+D:#^^^^^^^^^############################### AAFFFA; ## ## # o #### ## o ; o ####### o ### #A AAA ############################ CCCCCCC #
+D:#^######################################### AFAA; ## ### oooooooo #### # #o o ###### oooooo ###AAFF o ; R#############################; CCCCCCC #
+D:#################ooo###################### AA ; ### # o # ## o o ##### o ## AFFA# RR#############oo############## CCCCC; #
+D:####oo##ooo#####o#######o###ooo########### ## ; o ## o o ### o ; ###FFAA ;; R########oo###oooooo#####oo###### CCCCC ; #
+D:#ooooooooooooooooooooooooooooooo##oooooooo ; o ; o o o ; # ;; ; oooooooooooo##oooooooo##oooooooooo CCCCC ; #
+D:#ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooAAAFooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo CCCCCC #
+D:#oooooooooooooooooo##oooooo##oooooo##ooooo AA ; o o AA FFA ; Roooooooo#oooooooooooooooooooooooo CCCCC #
+D:#^#######################oo####ooooo####### ##### FFAFA # # o o AFFF### # ######o####oo####oo######oo######; CCCCC #
+D:#^^#######################o########### #### AAFFFAA# oA o A FA## # ## ## ## RR####o####################oo#### CCCCC #
+D:#^####################################### ## ### ;; ; AAFFAA##### oA FFFAA ### ### ## #### R####oo######################### CCCCCC #
+D:#^^######################################## ####### ; #A##### oA o # #### # # ### RRR###o############oo########## CCCCCCC #
+D:#^^^###############ooo################### ### # ; ;# ## oA AA o FA ##### ; ### ## ;; R#####oo########ooooo####### CCCCCCCC #
+D:#####oo##oo#####oooooooo##############oo## ### ; #### o AA o F A ### ### R#######oooo##oooooo####### CCCCCCCCC ; #
+D:#ooooooooooo###ooooooooooooooooooooooooooo # o A oF # ooooooooooooooooooooooooooo CCCCCCCC #
+D:#ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooFoooFooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo CCCCCCCC ; #
+D:#^ooooooooooooooooo###oooooooooo##oooooooo o #o A o o AA # ooooooo####ooooooooooooo CCCCCCCC #
+D:#^^#o###ooo#####ooo#####ooooo########oo# # # ; o ### o A Fo ;### o A ### oR#########ooooo###oo# CCCCCCCC ; #
+D:#^^^^^###o################oo############# # # # ; o ###### # AF o ## # o #### ; R###########oo######## CCCCCCCC ; #
+D:#^^^^^^^##################################R ; #### ooooooo ##### o ; A o ###### ooooo A ####### ######################## CCCCCCCCC #
+D:#^^^^^^^^^^##############################RR AA; ## ##### o ; ####### o Ao ### # o FFF # ## # o ; #R######################## CCCCCCCC #
+D:#^^^^^^^^^^^^^^^######################### R AA FF A ; ## ## o #### o A ##### o AFF ### # ############################ CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^###################RR AAAFFFAA ## ; o ### o o # # o ; A ### ; ;; RR########################## CCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^#################### R AAAFFFAA ; o ;; o ; o o A ; R########################### CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^######################R AAFFA A ooooooooooo o o oooooooooooo ;; ;R ############################ CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^^^^#################RRR ; AFFA o ; ; o o ; A o R############################ CCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^##############R ### o # # o ### o ###; FF A o #### RR############################ CCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^############RRR ### # o AAA A # ### o ## # o # # # AAFF Ao # ## R ######################## CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^##########R R ### # #;; ; o AAAA ## #### o ## #### o ### ### FFAo ####### R########################### CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^##########RR ## ### o ;A A #### ## A A o ### # # o # ## ### AAF AA ####### ############################ CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^########### ### o ; ;## ## AAA o # ### o ##### ; FFAA #### ; ############################## CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^############## R ### ; o ## AAAA o # # o A ## A oFA ### R############################## CCCCCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^^^^#################R o A AoAA A Ao A A AAAAA FFF R#########oo###oo################# CCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^#############o#######oooooooooooooooooooooo ## AA A o A A A AR AAFFFAFA oooooooooooooooooRoooooooooooooooooo################## CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^############ooooooooooo# ### RRR RR # ### RR R o RR## AAR F FFA#FF A AA FFFFRR R ## R oooooo##oooooooooo################### CCCCCCC #
+D:#^^^^^^^^^^^#################ooooooooooo####R######R ## RR### ######### ###RR####o RR##### #ooo# ### R#F#F#RRRR A FF##R#R ##### ####################ooo##################### CCCCCCC #
+D:#^^^^^^^^^^###################oo######oo### ########### ######## ## #### ###########oooo########ooo ##########R#A##A A ######R# ###### ####################oo###################### CCCCCCC #
+D:#^^^^^^^##########oo####oo####ooo######### ############ ######### ###^^^ #########ooooo########oo##################A################### #########^######oooo##ooo################## CCCCCCC #
+D:##^^^^^#########oooooooooooooooo#################^^####### ###########^^^^^###########ooooo######ooo####################################### #####^^^#######ooooooooooooo############# ; CCCCCCC#
+D:#^^^##########ooooooooooo##ooooo######^#########^^^^##################^^^^^^^^^^^######ooo#######oooo#########^^^^^^^^^^^^^^^^^^^########### #####^^^#######oo##oooooooo############# CCCCCC#
+D:##############ooooo##########oo######^^^#####^^^^^^^^###############^^^^^^^^^^^^^^#####oooo#######ooo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^###### ####^^^^^###############ooo############## CCCCC#
+D:########ooo#####oo##################^^^^^^^^^^^^^^^^^#############^^^^^^^^^^^^^^^^^####oo########oooo#####^^^^^^^^^^^^^^^^^^^^^^^^^^^########### #######^^^^^#############ooo#ooo######## CCCCCC#
+D:#o##oooooooooooooooo##############^^^^^^^^^^^^^^^^^^^^^^#########^^^^^^^^^^^^^^^^^^#####oo########oo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####### # ######^^^^^^^^^^^^########oooooooooooooo CCCCC #
+D:#oooooooooooooooooo########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^########oooo#######ooooo###^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^##############^^^^^^^^^^^^^^^#######ooooooooooo CCCCC #
+D:######################################################################################################################################################################################################
+
+# Default starting position
+# ?:[EQU $LEAVING_QUES 0]
+# P:31:32
diff --git a/lib/edit/t_d_lori.txt b/lib/edit/t_d_lori.txt
new file mode 100644
index 00000000..e5ab3abf
--- /dev/null
+++ b/lib/edit/t_d_lori.txt
@@ -0,0 +1,101 @@
+# Town Name: Lothlorien (destroyed)
+#
+# original town by Akhronath (zzhou22876@aol.com)
+# destruction by fearoffours (fearoffours@moppy.co.uk)
+#
+# Created for ToME
+
+
+
+
+# Dead/burnt tree
+F:D:92:3
+
+# Ash
+F:A:93:3
+
+# Fire
+F:F:205:3
+
+# Permanent rubble
+F:R:206:3
+
+# Town Layout
+D:######################################################################################################################################################################################################
+D:#DDDDDDDDDDDDDDDDDDDDDDDD , ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD .DDDDDDDDDDDDDD,DDDD,DDDDDDDDDDDDDD ,,DDDDDDDDDDDDDDDDDDDDDDDD , ,DDDDDDDDDDD ,DDDDDDDD DDDDAAA#
+D:#DDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDD , #
+D:#DDDDAADDDDDDDD ,DDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDAAADDDDD.DDDDD DD DDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAADDDDDDDDDDDDDDDAAA#
+D:#DDDDDDDDDDDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDD ,,DDDDDDDDDDD, .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD,DDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, #
+D:#DDDDDDDDDDDDDDDDDD ,,DDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAADDDDDD.AAADDDDDDDDDDD ,DDDDDDDDDDDDDD ,,DDDDDDDAAA,DDDDDDDDDDDDDD,DDDDDDDDDDDDDD , ,DDDDDDDDDDDDDD,DDDD#
+D:#DDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDD,DDDDDDDDDDDDDDDDDDDDDDDD ,DDDD ,DDDDDDDDDDDDDDDDDD ,DDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA#
+D:#DDDDDDDDDDD,DDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDAADDDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDD DDDDDDDDDDDDDDDDDDD ,DDDDDDAADDDDDDDDDD #
+D:#DDDDDDDDDD DDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDDDDAAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA,DDDDDDDDDDDDDD ,DDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#DDDDDDDDDDDDDD ,,DDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDADDDDDDDDFDDDDDDDDDDDDDD ,DDDD ,DDDD,,DDDDDDDDD DDDDDDDDDDDDDDDD ,DDDDDDDDDDAADDDDDDDDDDDDDDDAAA,DDDDDDDDDDDDDD ,DDDDDDD #
+D:#DDDDDDDAAA,DDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD AADDDDDDDDDDDDDD AAAAFDDDDDDD ,DDDDDDDDDDDDDDDDDDDDAAA,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDDDDDDDDDDDDDDDDDD , ,DDDDDDD ADDDDDDDDDDDDDDDDDDDDDDDDDDDAAA,DDDDDDDDDDDDDD FDDDD FFDDDD ,DDDDDDDDDDDDDD,DDDD,DDDDDDDDDDDDDD ,,DDDDDDDDDDDDDDDDDDDDDDDD , ,DDDDDDDDDDD ,DDDDDDDDDDDDDDAAA#
+D:#DDDDDDDDDDDDDDAAADDD ,DDDDDDDDDAAADDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDD AADDDDDDDDDDD FDDDD F F F ,DDDDDDDDDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD , #
+D:#DDDD DDDDDDDDD ,DDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD AADDDDDDDAA ADDDDDDDADDDDDDD## F,AAA##DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDD DDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDD #### , # ##DDDDDDDDDDDDDDDDDDD DDAAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD , #
+D:#DDDDDDDDDDDDDD ,DDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDD AFDDDDDDD ADDDDDDD RDDDDDDD##DDDD FDDDD##R,,F,, ##DDDD ADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDD DDDDDDDDDDDDDDDDDD,DDDDDDADDDDDDDDDDDDDDDDD A ,DDDDDDDDDDDDDD## #DDDD#####, AADDDD## , , ###DDDD F ADDDDDDDDDDDDDDDDDDDDDDDD , DDAAA,DDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, #
+D:#DDDADDDDDDDDDDDDDD ,,DDDD ,DDDDDDDDDDDDDD AAAAADDDDDDDDDDDFFDDDDDDD A # #A# A ### #DDDDDDD ##AAA,AAAA#DDDD AAAAAADDDDDDDDDDDADD ,,DDDDDDDAAA,DDDDDDDDDDDDDD,DDDDDDDDDDDDDD , ,DDDDDDDDDDDDDD,DDDD#
+D:#DDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDA, A ,DDDDDDDDDDDDDDDDDDDDDDDD## ##AAA, #A##DDDD##AAAR#AAA,AAA##AAA, FAADDDDDDDDDDDDDDDDDDDDDDDDDDD AA ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA#
+D:#DDDDDDDDDDD,DDDDDDDDDDDDDDDDDD,AADDDDD AAAADDDDDDD###AADDDD FDDDDA,AAA#####DDDD##.##AAA####RR ## , ##DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDADDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDDDDDDDD ,,DDDD ,DDDDDDDDDDDDDD A ADDDD FFF##DDDDDDD # ## #DDDDA #DDDDDDD.DDDD ##########,,,, # #AAAF,,DDDDDDDDD DDDDDDDDDDDDDDDD ,DAADDDDDDDDDDDADDDDDDDDDDDDAAA,DDDDDDDDDDDDDD ,DDDDDDD #
+D:#DDDDDDDDD DDDDDDDDDDDDDDDD,DDDDDDD AA ADDDDDDD #### ,A R ####DDDD ,DDDDDDD , ,, ##F#####AAAA ####DDDDFDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, #
+D:#DD DDDDDDDDDDDDDD ,,DDDD ,DDDDDDDDDDD ADDDDDDDDDDD###R# # ######DDDDDDD,DDDDDDD ,DDDD #R#AAA#AAA,AAA##DDDD FAAA,DDDDDDDDDDDDDD ,,DDDDDDD A,DDDDDDDDDDDDDD,DDDDDDDDDDDDDD , ,DDDDDDDDDDDDDD,DDDD#
+D:#DDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDA,DDDD,DDDD #### ##A###F##DAADDDD, F , , AAAAF ,DDDDDDD ,AAA##AAA, F FDDDDDDD DDDDDDDDDDDD ADDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA#
+D:#DDDDDDDDDDD,DDDDDDDDDDDDDDDDDD,DDDDDDDAADDDDDDDDDDD ############,,,,AA,,,AAA,,AAA,DDDD F ,DDDD A , ###DDDDDDDDDDD ADDDDDDDDDDDDDDDDDDDD A ,DDDDDDDDDADDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDAAA,DDD DDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD##### #######DDDDDDD ,DDDD,,,,,,,,,,,A,,,F,,,,,,,,R###DDDDDDDDD AAAA ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDDDDDDDDDDDDDDDDDD , ,DDDDDDD ADDDDDDDDDDD ######## #####AAA,AAA,DDDDDDDDDDDDDD FDDDD AA , ###AAA,,DDDD, F ,ADDDDDDDDDDDDDD ,,DDDDDDDDDDDDDDDDDDDDAAAAA, ,DDDDDDDDDDD ,DDDDDDDDDDDDDDAAA#
+D:#DD DDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDAAADDDDFDDDD,## # RRAAA######DDDD ,DDDDDDDDDDDDDDDDDD FDDDD ,DDDD# ,DDDDRDDDDDDDDDDDAAADDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD , #
+D:#DDDDDDDDDDDDDD ,DDDDDDDDDDDDDD,DDDDDDDDDDD FFAAA###DDDDDDD # R #DDDD ##DDDD A ## #AAA## A FF ,DDDD ,AAA### ###DDDDDDDDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDDDD ,DDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDD #DDDDDDDDDDDDDD#,AAA#R###DDDD F ##DDDD####AAAA ,AAA,,,AAA##### ####DDDDDDDDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA## ## AAAA###DDDD #FAAAF,,,,,,,,DDDD ##########DDDDAADDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDD ,DDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#DDDD DDDDDDDDD ,,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ### # AAA ,#DDDD ,DDDD ,F ,AAA, ,DDDD### ###DDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDADDDDAAA,DDDDDDDDDDDDDD ,DDDDDDD #
+D:#DDDDDDDAAA,DDDDDDDAAAAAADDDDDDDDDDDDDDDDDDDDDDDDDDD ADDDDDDDDDDDDDDDDDDDDDDDD A ,DDDD ,DDDD,, ,AAA,DDDD AA,DDDD### ## ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDDDDDDDDDDDDDDDDDD , ,DDDDDDDDD DDDDDDDDDAAAAAFDDDDDDDDDDDDDDDDDDDD ,,AA ,,,,,,,,,,,,, ,F, ,DDDDDDD, , , # ##DDDDDDDDDDD ,,DDDDDDDDDDDDDDDDDDDDAAADDD ,DDDDDDDDDDD ,DDDDDDDDDDDDDDAAA#
+D:#DDDD DDD DDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDD ,FDDDDDDDDDDDDDDDDDDDD AA , ,,A,DDDDDDDDDDD,AA,F,F,,,,,,,,,,,,,AA,,R###DDDDDDD AADDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDAADDDDDAADDDDDDDDDDDAAA, #
+D:#DDDDDDDDDDDDDD ,DDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDD AADDDDDDDDDDD AA A ADDDD,,DDDDDDDDDDD ADDDD ,,, FDDDDDDDAA A,DDDD# ##DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#DDDDDDDDDDDDDDD DDDDDDDDDAA,DDDDDDDDDDDDDDDDDDDD AADDDD ,DDDD AAAAADDDD --,--AAAA,AADDDDDDDDDDD ,AAAVVV@DDDD F#,DDDD # #DDDDDDDDDDADDDAAA,DDDD ,DDDDDDAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, #
+D:#DDDDDDDDDDDDDDDDDD ,,DDDD ,DDDDDDDDDDDDDDDDDDDDDDDD F FDDDDDDDAAAF AAAA----,---- AADDDDDDDDDDD AA VWWWV@DDDD #R#DDDDDDDDDDDDDD ,,DDDDDDD DD,DDDDDDDDDDDDDD,DDDDDDDDDDDDDD , ,DDDDDDDDDDDDDD,DDDD#
+D:#DDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDD,DDDDDDDDDDD AAAAADADDDD ---VV,@@---ADDDDDDDDDDDDDD , @WWV@@ ,AAAF###DDDDDDDDDDDDDDDDDDDDDDDDDDD A ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA#
+D:#DDDDDDDDDDDDDDDDDD D ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDA AA A ---VVW,WV@---DDDDDDD A AAAA, V@VVDDDDDDD#F####DDDDF,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDADADDDDDDD #
+D:#DDDDDDDDDDDDDDDDDDDDDDDD , ,DDDDDDDDDDDDDDDDDDDDDDDD FFAADDDDDDD A ,F---VWW@WV@---DDDDDDDDDDDAAAA,, @@DDDDDDDR###AAA,AAAFDDDDDDDDDDD ,,DDDDDDDDDDDDDDDDDDDDDDAAA, ,DDDDDDDAAADDD,DDDDDDDDDDDDDDAAA#
+D:#DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDFDDDDAADDDDADDDD---V@WWW@V---DDDDDDD ADDDDDDD,,ADDDDADDDD #DDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#DD DDDDDDDDDD ,,AAAD ,DDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDD AADDDDDDDAAA---V@VVV@--AAA,A,,,,,,,AA,,,, ,DDDDDDD,,DDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDAAA,DDDDDDDDDDDDDD ,DDDDDDD #
+D:#DDDDDDDDDAAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ------@@-DDDD,DDDDDDD ADDDD ,DDDDADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDD DDD ,DDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#DDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDD FDDDDDDD ---DDDDDDD,DDDDDDD ADDDD #R#DDDD FDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD , #
+D:#DDDDDDDDDDDDDD ,DDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ADDDD F FDDDDDDD ,DDDDADDDDDDD R##DDDDAAADDDD FAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#DDDD DDDDDDDDDDDDDDDDDDDDD,DDDDDDDDDDDAADDDDAADDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDAAA,AAA#F##DDDDDDDF AADDDDDDDAAADDDDDDDDDD ,DDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD , #
+D:#DDDDDDDDDDDDDDDDDD ,, AAAAADDDDDDDDDDDDDD AAAAAAADDDDDDDDDDDDDDDDDD AADDDDDDDDDDD #R#DDDD ADDDDDDD #DDDD AAA ,ADDDDDDDDDDDDDD ,,DDDDDDDAAA,DDDDDDDDDDDDDD,DDDDDDDDDDDDDD , ,DDDDDDDDDDDDDD,DDDD#
+D:#DDD ADA AA,DDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDD,DDDDDDDDDDDDDDDDDDADDDDDDD,DDDD ,DDDD ##R#DDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA#
+D:#DDDDDDDDDDD,DDDDDDDDDDDDDDAAAAADDDDDDDDDDDDDDAA AAAADDDDDDDDDDDAFAADDDDDDDAAAFDDDD####RAAAFDDDDDDD AADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDAADDDDDDDDDDDDDDDDDDDDDDDDDDAAADDDDDD AADDDDDDDDDDDDDD ADDDD FDDDDAA FDDDD#F#DDDD FDDDDDDD AADDDDDDDDDDDDDDDDDDDDDDDDDAAADDDDDDDDDD ,DDDDDDDDDDDDDD ,DDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#DDDDDDDDDDDDDD ,, AA ,DDDDDDDDDDDDDDDDDDDD AADDDDDDDDDDDDDDDDDDDDDDDD FDDDDDDDDDDD #DDDDDDDDDDDDDD A ,DDDD,,DDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA,DDDDDDDDDDADDD ,DDDDDDD #
+D:#DDDDDDDAAA,DDDDDDDAAAAAAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAADDDD AADDDDDDDAADDDDDDDDDDDDDDDDDDDDDDDD AAADDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDDDDDDDDDDDDDDAAAAA, ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDD AADDDDDDDDDDDDDDDDDDAADDDDDDDDDDD ,DDDD,DDDDDDDDDDDDDD ,,DDDDDDDDDDDDDDDDDDDDDDDD , ,DDDDDDDDDDD ,DDDDDDDDDDDDDDAAA#
+D:#DDDDDDDDDDDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDD ADDDD ,,DDDDDDDDDDDAADDDDDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDD ,AAAAAA,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, #
+D:#DDDDDDD DDDDDDDDDD ,, AAA,DAADDDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDD ,,DDDDDDD A ,DDDDDDDDDDDDDD,DDDDDDDDDDDDDD , ,DDDDDDDDDDDDDD,DDDD#
+D:#DDDDDDAA A ,DDDDDDDDDDDDDDDDDDDDDDDDDDD ,AAAAADDDDDDDD DDDDDDDDDDDDDD ,DDDD ,DDDDDDDDDDDDDAAADDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD AA,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAAA#
+D:#DDDDDDD A ,DDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDDDDDDDDDDD #
+D:#DDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDD ,DDDDDDDD DDDDD ,DDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#DDDDDDDDDDDDDD ,, AA ,DDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD , AAA,DDDDDDDDDDDDDDDDDAADDDDDDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDAAA,DDDDDDDDDDDAAAA ,DDDDDDD #
+D:#DDDDDDDDDDDDDDDDDDDDAA,DDDDDDDDDDDDDDDDDDDDAAAD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, #
+D:#DDDDDDDDDDDDDD ,DDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDD DDDDDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDDDDDDD DDDDDDDDDDDDDD ,,DDDDDDDDDDD,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,DDDD ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, #
+D:#DDDDDD D DDDDDDDD ,,AAA ,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD,DDDDDDDDDDDDDD ,,DDDDDDDAAA,DDDDDDDDDDDDDD,DDDDDDDDDDDDDD , ,DDDDDDDDDDDDDD,DDDD#
+D:#DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:######################################################################################################################################################################################################
+
+# Default starting position
+?:[EQU $LEAVING_QUES 0]
+P:13:99
+
+# Starting position when coming from quest 12
+?:[EQU $LEAVING_QUES 12]
+P:26:109
+
+# Starting position when coming from quest 13
+?:[EQU $LEAVING_QUES 13]
+P:7:99
diff --git a/lib/edit/t_d_mina.txt b/lib/edit/t_d_mina.txt
new file mode 100644
index 00000000..49a32b04
--- /dev/null
+++ b/lib/edit/t_d_mina.txt
@@ -0,0 +1,91 @@
+# File: t_d_mina.txt
+
+# Minas Anor: The Royal City of Gondor (destroyed)
+# original town by Mynstral (mynstral@thehelm.com)
+#
+# screwing up by fearoffours (fearoffours@moppy.co.uk)
+#
+# Created for ToME
+
+# Completed: 23/07/02
+
+# Dead/burnt tree
+F:D:92:3
+
+# Ash
+F:A:93:3
+
+# Fire
+F:F:205:3
+
+# Permanent rubble
+F:R:206:3
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:#^^########------------------AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF@@@@@@@AAAAAAAAAAAAAAAAAAF@@@@@@@@@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF#
+D:#^^^----#####AF------##FF-------AAAAAAAAAAFFF^AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF@@VVVVV@@AAAAAAAAAAAAAAFFF@@VVVVVVV@@@@@@@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF,,,AAAAAAAAAAAAAAAAAAAAAAAAF#
+D:#^^^----------#R##---###F###-------AAAAAAAAF^^^^^AAAAAAAAAAAAAAAAAAAAAAAAAAADDDAAAAAAAAAAAA@VVVVVVV@@@@@AAAAAAAAAAFF@@VV@@@@@@VVVVVV@@@@AAAAAAAAADDDAAADDDAAAAAAAAAAAAAF,,AAAAAAAAAAAAAAAAAAAAAAAAFFF#
+D:#^^----ssss-----#R#--------###FF-----AAAAAAAA^^^^^^AAAAAAAAAAAAAAAAAAAAAAADDAAAAAAAAAAAAAFF@VVVVVV@@VVV@@@AAAAAAAAAA@VV@@AAAA@@@@@@VVVV@@AAAAAAAAADDDDDAAAAAAAAAAAAAFFF,,AAAAAAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^^^---St-RF--------F--#ssss--###-------AAAAFF^^^^^^^^AAAAAAAAAAFFAAAAAAAAAAFFFAAAAAAAAAFFF@@VVVVVVVV@VVV@@@@@@@@F@@@V@@AAAAAAAAAA@@@@VV@@@@AAAAAAAAAAAAAAAAAAAAAAAAAAA,AAAAAAAAAAAFFAAAAAAAAAAAAAAAA#
+D:#^^----sFss----OO---##--#StSS--FFF##F-----AAAAF^^^^^^^^AAAAAAAAAFFFAAAAAAAAAAAFFFAAAAAAAAFFF@@V@V,@@@@@@VVVVVVVV@@@VVV@AAAAAAAAAAAAAA@@VVVV@@AAAAAAAAAAAAAAAAAAAAAAAAA,,AAAAAAAAAAAFFADDDAAAAAAAAAAAA#
+D:#^^----##-#-----OOO--#---#s--RF----###------AAAA^^^^^^^^AAAAAAAAAAFFAAAAAAAAAAAAAAAAAAAAAAFFF@@@@@AAAAF@@@@@@@@VVVVV@@@AAAAAAAAAAAAAAF@@@@VV@@@AAAAAAAAAADDAAAAAAAAA,,,AAAAADDDAAAAAFFAAAAAAAAAAAAAAF#
+D:#^F---------------OO---#-####-#------AAAA----FFF^^^^^^^^^^AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF@VVV@@AAAAAAAAAAAAAAAAA@@VVV@@AAAAAAAAAAAAAAAAAFFF,O,AAAAAAAAADDDDAAAAAAAFAAAAAAAAAAAF#
+D:#^FStSSSS-----ss---OO---##-----OOOOO---###----FFF^^^^^^^^^^^AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@AAAAAAAAAAAAAAAAAFFF@@VVV@@AAAAAAAAAAAAAAAAAFFOOAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAFF#
+D:#^^ss-AFF----Ssss---AFO--#-F--R#O-O-OO---##----FFFAD^^^^^^^AAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAADDDAAAAAAAAAAAAAAAAAAAAAAAAAAAF@@VVV@AAAAAAAAAAAAAAAAAFFOOAAAAAAAAAAAAAAAAAAAAAAAAAADDAAAAAAAFFF#
+D:#^F#-R###---sAFR--F--OOO--F#-OOOOOOO-OOO--##----AAAA^^^^^AAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF@@VVV@@AAAAAAAAAAAAAAAAAFOOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^^^-------##sssSss---AAO--#OOO--s--OOOOO--###F--AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@AAAAF@@VVV@@AAAAAAAAAAAAAAAAAFOOAAAAAAAAAAAAAAAAAAAAAADDDAAAAAAAAAAAF#
+D:#^^^##RR##---##AFA--s--OOO-OOO--StS#-OOOO----#FF--AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF@@VVVVVVVV@@@@@@@V@@@@AAAAAAAAAAAAAAAAAFOOAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAFF#
+D:#^AA^----###---##--ssS--OOO--##-ssss--OOOOOO--#R---AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFFAAAAAAAADDDDAAAAF@VVVVVVVVVVVV@@VV@@AAAAFFOOOAAAAAAAAAAAAAAOOAAAAAAAAAAAAAAAAAAFFAAAAAAAAAAAAAFFF#
+D:#^^--------#R-----ssSs#--AF#-#--#AFAF#-OOAAAO--##-AAAAAAAAAAAAAA----AAAAAAAAAAAAAAAAAAAAAAAAFFFFFFFFFAAAAAAAAAAAAAAAAAAA@VVVV@@@@VVVVVVV@@AAAAFFOOOOOAAAAAAAAFOOOOOAAAAAAAAAAAAFAAAAAAAAAADDDAAAAAAAA#
+D:#^F-----------#--#s-RRF-OO-O--#---------OOOOOO--FF-----AAAAFFF--------AAAAAAAAAAAAAAAAAAAAAAAAAFFFFAAAAAAAAAAAADAAAAAAF@@VVV@@FF@@VVV@@@@AAAAFFFOOFFOOAAAAFFFOOAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAFF#
+D:#^^----AAA----R---###--OOOOOO-#--#sss#RF-OOOOOO,#FFFF---AAAAF---#-------AAAAAAAAAAAAAAAAAAAAAAAAFFAAAAAAAAAAAAAAAAAAFF@@VVV@@AAAA@@@@@AAAAAAAAFOO-FFFOOOOOOOOOAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAFFF#
+D:#^^-------------##-#-#-O#-OOO--#--ssssss----OOO,,,,,#----FF-AAssAF--R----AAAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAADDDAAAAAAF@VVV@@AAAAAAAAAAAAAAFFF-ORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFAAAAAAAF#
+D:#^^-------------R#---O-O-t-OOO-F#-#SS-##--OOOOOO,##,##--------sssssssAAA-#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDAAAAAA@VV@@AAAAAAAAAAAAAAFF--OO-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAF#
+D:#^^^-FAF--AA-----##-OOO-sssOOAA-#--ssssss-OOOOOO--#,#RR##-----SSR---SS-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDAAAAAAA@@VV@AAAAAAAAAAAAAAFF--OR-AAAAAAAAAAAFFAAAAAAAADDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^^^--AF----------#OOORA#-RFOOO-#--ss#sss--OAAOOOFFAAAF##FF---sFFFAFss--O---AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF@@VVV@AAAAAAAAAAAAAAFF-OO--AAAAAAAAAAAAAAAAAAAAAAAFFAAAAAFFFAAAAAAAAAAAAAAAAAAAAA#
+D:#^^--###--AAAA--AA--O-------OOAAA--####AAA-OOOOOO-##,###,,##--sssFAFAs--AAA-AAAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAF@VVV@@AAAAAAAAAAAAAAF--O--AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFAAAAAAAAAAAAAAAAF#
+D:#^^^-##AFA-------OOO#--SSStS---OAAAAA----AAAOOOO---#AAAAAAF#F-ssssR-#F--O-----AAAAAAAAAAAAAAAAAAAAAAAAAFFAAAAAAAFFF@@VV@@AAAAAAAAAAAAAAF--OR-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF#
+D:#^^-####R-------OOO-#--sssss-OOO-##---#s--OOOOO--T-#,--AAAAA--AFA##AA#--O---AA-AAAAAAAAAAAAAAAAAAAAFFAAAAAAAAAAAAFF@VVV@AAAAAAAAAAAAAAF--OO--AAAAAAAAAAFFAAAAAAAADDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^^#######------OO--##-###R-AAAO-##-ssss---OOOO-TT-FAA-AAA,#----AAA,,,,,O------AAAAAAAAAAFFFAAAAAAAAAFFFFAAAAAAAAF@@VV@@AAAAAAAAAAAAAA--OO--AAAAAAAAAAAAAAAAAAAAADAFFAAAADDDAAAAAAAAAAAAAAAAAAAAAAAAF#
+D:#^^^###AFAF#----OOO--#---R---OOO--AAS#-R--OOOOAAAT-#---AA,,###----------O---AA--AAAAAAAAAFFAFAAAAAAAAAAFFFAAAAAAAA@VVV@@AAAAAAAAAAFFF--OO--AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFAAAAAAAAAAAAAAAAAAFF#
+D:#^^#####R--####-OR---##-StSSS-AAO-#-sss-RFOOOOO--T-#F---,,##FF-s-ssAFF--O--------AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@VV@@AAAAAAAAAAFFF--ODR--AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF#
+D:#^^^#########---OOOAAA#-sss-RF--O---ssss-AAOOOOO---FF,AAA#FF---SSSAFAFF-O--AAA-AA-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF@@@VVV@AAAAAAAAAAFFF--ORO--AAAAAAAAAFAAAAAAAAAAAAAAAAAAADDDAAAAAAAAAAAAFFFAAAAAAFFF#
+D:#^^###AAA###----OOO#--#-###A##OOO-#-##A#---OOOOOO--##FF#A#-----sR-ssss--O----------AAAAAAAAFFFAAAAAAAAAAAAAAAAAAAA@VVVV@@AAAAAAAAAAF---OOO--AAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAA#
+D:#^^^##R##-------OOO---#-#--^--OOO-#----#----OO--RROOFOOOOOOOO--####--R#-O-----------AAAAAAAAFFAAAAAAAAAAAAAAAAAFF@@VVV@@AAAAAAAAF-A----OO--AAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAFFFAAAAAAAAF#
+D:#^^######-##OOOROOO-^^^^^^^^-^MMM^^^^^^^^#^^^OOOOOO-ROOOO-ROOAOOOOOOOAAOO----AAA----AAAAAAAAAAFAAAAAAAAAAAAAAAA@@@VVV@@AAAAAAAAFA-AOOOOOO--AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDFAAAAFFAFFFAAAAAAAAF#
+D:#^^####AFFAAOROOOO######A#####III##-#########^OOAAAOOOOOOO#OOOOOOOOOO#OOOOO-------AAAAAAAAAAAAAAAAAAAAAAAAAAAF@@VVVV@@AAAAAAAAF---OOOOOO--AAAAAAAAAAAAAAAAAAAAAAAFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF#
+D:#^F######-##OOOO-##-####AA#AA#III#####-##--##^OOOOR-OOOOOOOOAAAOO-OOOOOOOOOO------A--AAAAAAAAAAAAAAAAAAAAAAAAA@VVVV@@AAAAAAAA----OOORRO----AAAAAAAAAAAAAAAAAAAAAAAFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^F###-A##-OOOOOOOO-^#^^^^^#A^MM#^^^^#^^#^^-#AFOOAFOOOOOR-OOOOAOOOOOOOOOOOOOOO--AA---AAAAAAAAAAAAAAAAAAAAAAAAA@VVV@@AAAAFFA--AD-OOOR-----AAAAAAAAAAFAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF#
+D:#^^^#######-----OOO---A-sAA#--OOO##--##-----R--OOOOOOOOOOOOOO-----------OOO-R-O----AAAAAAAAAAAAAAAAFFF---------##@VVVR##F--------OOOOO-----AAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAFFFFFAAAAAAAAAA#
+D:#^^#########----OAO---#-sSss--OOO---ssss#--OOOOOO--##FF###---AA---ss-#-#O-OOOOO-AA--AAAAAAAAAAAAAAFFF--OOOO-----######R--------OOOOOO-----AAAAAAAAAAAAADDDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAF#
+D:#^^####R-AFA#---OOR--R--sts##-O-R-#-SSASS-OOOOOO---##F##AFF---------t-S-O-OOROO----AAAAAAAAAAAAAAFFF--OOOOOOOOOOOOO#OOOOROOOOOOOOOOO-AAA-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFDDAAAAFFAAAAAAAAAAA#
+D:#^^###########--OOO--##-sSFR--OOO-R-s-#---AFOOO--TFF#F#,,,##F#--A-sssss-O--OOOOO---AAAAAAAAAAAAAAFF--ROOOOOOOOOOOOOOOOOOOOOOOOO#AOO-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFADDDAAAAAF#
+D:#^^#R--R--##----OOO--#--####-OOO--#-sssss-OOAOO-TT-#,,,,-AAFF-----sAAFA-R---OR-O---AAAAAAAAAAAAAAF--OOOAA-OOOOOOORAAO#OOOOOOOOOOO------AAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFFAAAAAAAAAF#
+D:#^^#######------O-R-##-------OO---#-###A#-OOOOO-TT-F#----AFF#F----###R--O-AAOOOOAA--AAAAAAAAAAFFF--OOOO---------#######------------A--AAAAAAAAAAAAAAAAAAAFAAAAADDAAAAAADDAAAAAAAAAAAAADDDAAAAAAAAAFFF#
+D:#^^-###R-#-AA---OOO-#--S-ss##OOO-#--------OOOOO--T-##-----AAA----A------A----OOOO----AAAAAAAAAAF--OOOA----DD---##@VVV@##-D-----A---AAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF#
+D:#^^^-###---------OO-#-#stss--OOO-#-ssssss--OR-RO---#,--AA,A#----sss-#s--O-----OOOO--A-AAAAAAAA---OOOO---AAAAAAAAF@VVV@@AAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAFFAAAAAAAAAA#
+D:#^^--####---------OOO--#s#s-OOO--FRStS##---OAFAOO-#FF-,,#F##----S--#AA--O------OOR-----AAAAFF--OOOOO----AAAAAAAAF@VVV@@AAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF#
+D:#^^---#AA--AA-----#OOO--##--OOO-###ssssss--OOOOOO-#,,,##FF#------RsAFA--O--A----OOR#----AAAA--OOOOO----AAAAAAAAAA@VVVV@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^^^--#------AFF-R--AFAAA--OO----#-###A##-OOR-OO--#F####AAA-AA--ss#-ss-OO----D---OOOO----AA--OOOOO---FFFAAAAAAAAF@@VVV@@@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF@@@@AAAAAAAAAAAAAAAAAAAAFFF#
+D:#^^^-------------#---OOO---OOO--#F------##OOOOOO##AAAAF-AA--AA--#-##-AAA-R-AA-----R--A----OOOOOO-AA--AAAAAAAAAAFFF@@VVVV@@@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF@@@@@@AAAAAAAAAADDAAAAAAAAFFF#
+D:#^^----------AFFA-----AFAAOOO-----ss------OOR-O,,##FAAA--------AAA-----AAA--A--AAA-OOOOOOOOROO-----AAAAAAAAAAAAAAFF@@@VVVV@@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@V@@@AAAAAAAAAAAADDDDAAAAFF#
+D:#^^^----AAAA-R-##-#ss--OOO#OO-##F-#Ss----OOOA-O,F#AAA---AAAAA-------AA-O--------F---OOO#OOOOO--AAAAFFFAAAAAAAAAAAAAAF@@VVVV@@AAAAAAAAAAAAAAAAAAAA@@@@@AAAAAAAAAA@@@@@@@@@@@@@AAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^^^---------##---ss-s--OOOO----Fsst#DD-OOOOOO--#F-----F------ssss-s--OR---A--AAAA---OOOOO-A--AAFFAAAAAAAAAAAAAAAAAFFF@@VVVV@@@AAAAAAAAAAAAAAFF@@@VVV@@@AAAAAAAA@@@V@@@@@@@@AAAAAAAAAAAAAAAAAAAAAAAAF#
+D:#^^--------##R---sstss#--OOO-##FssS-#--OOO#OO--##F----AAAA-----#S--RR-OA-----AAAAFF----------AAAAAAAAAAAAAAAAAAAAAAAAAF@@@VVVV@@@@@AAAAAAAAF@@@@VVVVVVV@@FFF@@@@@V@@V@@@V@@AAAAAAAAAAAAAAAAAAAAAAAAFF#
+D:#^^-AAAA-###-----#Ss-R--OOOOO###sSs#--OOOOOO--##-----AAAAFF---ssssss--O-----AAAAAAAAAAA-AA-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@VVVVVV@@@@@@@@@@@VVVVV@@@VVV@@@@@VVVV@@@@F@@@@AAAAAAAAAAAAAAAAAAAAAAAAFFF#
+D:#^^^######----#---#s#--OOO-OOO--Ss#--#OAA#---##-#AAAAAAAAAAA--##--##-OO--DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFF@@VVVVVVVVVVVVVVVVV@@@@@F@@@VVVVVVV@@@@AAAAAAAAAAAAAAAAAAAAAAAAAAADDAAAAAF#
+D:#^^^-------ss-#S---#--OOO---AA#--#--OOOOR--#-------AAAAAAAAAA--------O-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF@@@@@@@@@@@@@@@@@@@AAAAFFF@@@@@@@@@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^^-sssss-#sssts-----OOO--#--OOO---OOOOO---#AF-AAAAAAAAAAAAAAF------OO-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFF#
+D:#^^-SSStA--#sSAFs#--OOO--#----AOOOOOOAA--#-------AAAAFFAAAFFAAAFAA--O----AAAAADDAAAAAAAAAAAAAAAAAAAAAFFFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^^-sFAF----#ss-R--OO----#--AF-OAOOO------------AAAAAAAAFAAAFFAA---O---AAAAAAADDDAAAAAFFFFAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAADDAAAAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAFF#
+D:#^^^#####----##---OO--###--XXX-OOO----#-------AAAAAAAAAAAAAFAAAAFF---AAAAAAAAAAAAAAAAAAAAAAAADDAAAADDDFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDAAAAAFAFFFAAAAAAAAAAAAAAAAFFFFFFFAAAAAAFFFAAAAAAAAAAAAAA#
+D:#^^^------------OOO--###--XXX#----FAFFA----AAAAAAAAADDDDAAFAAAFAAAAAAAAAAAADDDAAAAAAAAADDAAADDAAAAAFDDFAAAAAADDAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDDAAAAAAAAAAAAAFFAFFAAAAAAAAFFFFAAAAAAAAAAFFF#
+D:#^^--SStSSAAA--OO-AAA#--XXAA#---#AFA-AAA-AAAAAAADDDDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDAAAAAAAAAAAAFFFFAAAAAAAAAAAAAAAAAAAFFFFAAAAAAAAAAAAAAAAAAAAFFAFFAAAAAAFFFFFADDAAAAADDDAAAAF#
+D:#^^^-sss-R----------#--###-----AF#-----AAAAAAAAADDDDAFAAFAAAFAAAFAAADDDAAAAAAAAAADDAAAAADDDAAAAAAAAAAAAAAAADDDAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAADDADDDAAAAAFFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAA#
+D:#^^--####-------###--------###-#-#---AAAAAAAAAAAAAAAAAAFAAFAAFAAAAAADDDDAAAAAAAAAFFAAADDDAAAAAAFFAFFFFFAADDAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF#
+D:#^^^----------##-----##-#-#-AFF---AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFFAAAAAAAAAAAAAFFFFAAAAAAAAAAAAAAAAADDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFF#
+D:#^^^------##-#--##-###--#-------AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDAAAAAAFFFFFAAAAAAAAAAAAAFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF#
+D:#^^######-#-----------------AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF#
+D:######################################################################################################################################################################################################
diff --git a/lib/edit/t_gondol.txt b/lib/edit/t_gondol.txt
new file mode 100644
index 00000000..779c4fbb
--- /dev/null
+++ b/lib/edit/t_gondol.txt
@@ -0,0 +1,219 @@
+# File: Gondolin.txt
+
+# Gondolin: The Hidden Kingdom of the Noldor
+# Created by Akhronath (zzhou22876@aol.com)
+
+############### Additional default terrain settings ###############
+
+# Default for Quest 13 = entrance is mountain
+F:z:97:3
+
+# Default for Quest 14 = entrance is floor
+F:y:1:3
+
+# Default for Quest 15 = entrance is floor
+F:x:1:3
+
+# Default for Quest 23 = entrance is quest entrance
+F:w:8:3:0:0:0:0:0:23
+
+# Decoration = Straight Road (B)
+F:":66:3
+
+# Decoration = Straight Road (W)
+F:$:70:3
+
+# Rare jewelry shop -- unusable yet, need finish quest
+F:!:63:3
+
+# Between gate to minas anor -- unusable yet, need finish quest
+F:Z:63:3
+
+#################### Quest 13 - Eol the Dark Elf ####################
+
+# Quest 13 assigned, entrance is quest entrance
+?:[EQU $QUEST13 1]
+F:z:8:3:0:0:0:0:0:13
+
+?:1
+
+#################### Quest 14 - Nirnaeth Arnoediad ####################
+
+# Quest 14 assigned, entrance is quest entrance
+?:[EQU $QUEST14 1]
+F:y:8:3:0:0:0:0:0:14
+
+# Quest 14 finished, reward is a rare jewelry shop
+?:[EQU $QUEST14 5]
+F:!:74:3:0:0:0:0:0:42
+
+?:1
+
+#################### Quest 15 - Invasion of Gondolin ####################
+
+# Quest 15 assigned, entrance is quest entrance
+?:[EQU $QUEST15 1]
+F:x:8:3:0:0:0:0:0:15
+
+?:1
+
+#################### Quest 16 - The last Alliance ####################
+
+# Quest 16 finished, reward is a between gate
+?:[EQU $QUEST16 5]
+F:Z:176:3:0:0:0:0:0:1
+
+?:1
+
+############### Quest 23 - Wolves hut finished = house ###############
+?:[EQU $QUEST23 2]
+F:w:74:3:0:0:0:0:0:7
+?:[EQU $QUEST23 5]
+F:w:74:3:0:0:0:0:0:7
+?:1
+
+#################### Buildings ####################
+
+# h: Orange (Minstrel)
+# i: Red (Sorcery)
+# j: Green (Temple)
+# k: Violet (Chaos)
+# l: Dark Brown (Ranger)
+# m: White (Paladin)
+
+# Tower of the King
+F:a:74:3:0:0:0:0:0:27
+
+# Library
+F:b:74:3:0:0:0:0:0:28
+
+# Castle: Gondolin Plot
+F:B:75:3:0:0:0:0:0:4
+
+# The White Tree:Aerandir:High-Elf
+F:c:74:3:0:0:0:0:0:29
+
+# Craftsmaster
+F:d:74:3:0:0:0:0:0:30
+
+# Earth-Dome
+F:e:74:3:0:0:0:0:0:31
+
+# Prophet
+F:f:74:3:0:0:0:0:0:12
+
+# Minstrels Haven
+F:h:74:3:0:0:0:0:0:32
+
+# Star-Dome:Sulraen:High-Elf
+F:i:74:3:0:0:0:0:0:33
+
+# Valarin Temple
+F:j:74:3:0:0:0:0:0:34
+
+# Sea-Dome
+F:k:74:3:0:0:0:0:0:35
+
+# The Golden Flower
+F:l:74:3:0:0:0:0:0:36
+
+# The Fountain
+F:m:74:3:0:0:0:0:0:37
+
+# Thunderlord's Hide
+F:n:74:3:0:0:0:0:0:22
+
+# Merchant guild
+F:o:74:3:0:0:0:0:0:56
+
+# Force elven monsters
+f:ELVEN
+
+# Town Layout
+
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################^^^^^^^^^^^^^,,, ####
+D:####################################^^^^^^^^^^^^,,,, ####
+D:##################################^^^^^^^^,,,,,,,, ####
+D:###########B#####################^^^^^^^^^,,,,,, CCCCCCCCCCCCCCCCCCCCCCCCC ,,,,,,, ,,,,###
+D:################################^^^^^^^^^^^,,, CCCCCCCC#######################CCCCCCCC ,,,,,,,,,,, ,,,,,###
+D:###############################^^^^^^^^^^^^,, CCCCCCC########TTTTTTTT#####TTTTTTTT########CCCCCC ,,,,,^^^^^,,,, ,,,,###
+D:##############################^^^^^^^^^^^,,, CCCC########TTTTTT........###........TTTTTT########CCCC ,,,,^^^^^^^,,,,,, ,,,,,###
+D:#############################^^^^^^^n^^,,, CC###########T..........#########..........T###########CC ,,,,^^^^^^^^^^^^,,,,,,,,,,,###
+D:############################^^^^^^,,,,,, ......................... CC############T........#############........T############CC ,,,,^^^^^^^^^^^^^^,,,,,,,,,###
+D:############################,,,,,,,,, ......................... CC#############T.......###WW#####WW###.......T#############CC ,,,,^^^^^^^^^^^^^,,,,,,,,,###
+D:###########################,,,,,, ... . ... C#############TT.......#WWWW##h##WWWW#.......TT#############C ,,,,,^^^^^^^^^^^,,,,,,,,,###
+D:########################### ... . #### ... #### C#############T..........VV###.###VV..........T#############C ,,,,,,^^^^^^^,,, ,,,,,###
+D:########################## ... ##### ####5#### CC######WWWW###T...........V##...##V...........T####WWWW#####CC ######### ,,,,,,^^^^,,, ,,,,###
+D:########################## ######### ... ##### ####### C######TTTTWW#TT............#.....#............TT#WWTTTT######C ######### ,,,,,,,,,, ,,,,###
+D:####W###################W# ######### ... ##### ####### C#####l...TTW#T.................................T#WTT...T#####C ######### ,,,,,,,, ,,,,,,###
+D:####WWWW#############WWWW# ######### ... ##### ####### C######T...............................................T######C ,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,###
+D:#####WWWWWWW#####WWWWWWW## ######### ... ##### ######### C######TTT.................TTTTTTTTT.................TTT######C , ,,,,,,,,,, ,,,,,,,,,###
+D:#####WWWWWWWWWWWWWWWWWWW## ####w#### ... ##### ######5###### CC#######WW..............TTTT#######TTTT..............WW#######CC , ### ,,,,,,,,,,,,,,,,###
+D:######WWWWWWWWWWWWWWWWW### . ... ##...## C##########............TTT#############TTT............##########C , ########## ,,, ,,,,,,,,###
+D:######WWWWWWWWWWWWWWWWW### ........... ... C########TT...........TT#################TT...........TT########C , ################### ,,,,,###
+D:######WWWWWWWWWWWWWWWWW### ... ... C#####TTTT...........TT###..###aaa###..###TT...........TTTT#####C , ############### ,,,,,,###
+D:########WWWWWWWWWWWWW###### ######### ... ############# ... C#TTTTT..............T##.....#!...Z#.....##T..............TTTTT#C , ############## ,,,,###
+D:###########WWWWWWW########## ######### ... ############# ... C#T...........###...TT##.....#.....#.....##TT...###...........T#C , ############## ,,,###
+D:############################### ######### ... ############# ... C#T.........####....T##......#.....#......##T....####.........T#C , ########### ,,,,###
+D:####--####KK#CC#VV#LL#""## ######### ... ############# ... CC#TT.......####.....T##...................##T.....####.......TT#CC , #### , ## ,,,###
+D:####--####KK#CC#VV#LL#""## ######### ... ######1###### ... C###T......####....TTT###.................###TTT....####......T###C , , VVVVV ,,,,###
+D:####--####KK#CC#VV#LL#""# ... . ... C###T......d###...TT###.###....#####....###.###TT...###b......T###C ,,,,,,,,,,,,,,, VVWWWVV ,,,###
+D:######################### ... . ... C###T......d###...T##.....##..##WWW##..##.....##T...###b......T###C , VVVWWWWWV ,,,,###
+D:#..............................................................................................####...T#.......#..#WV#VW#..#.......#T...####........... , VVVVWWWWWWWV ,,,,,###
+D:#.x.........y.....................................................................................................#W#V#W#..............................,,,, VWWWWWWWWWWV ,,,,###
+D:#..............................................................................................####...T#.......#..#WV#VW#..#.......#T...####........... , VVWWWWWWWVVV ,,,,,###
+D:######################### . ... . . C###T......c###...T##.....##..##WWW##..##.....##T...####......T###C , VWWWWWVVVV ,,,,,^^###
+D:####--####KK#CC#VV#LL#""# . ... . . C###T......####...TT###.###....#####....###.###TT...####....TTT###C , VVWWWVV ,,,,,,^^###
+D:####--####KK#CC#VV#LL#""## ####1#### ... ######2###### ##3## C###T..............TTT###.................###TTT....####...TT#####C , VVWWV ,,,,,,^^^^###
+D:####--####KK#CC#VV#LL#""### ######### ... ############# ##### CC#TT................T##...................##T.....####...TT#####CC , VVVV ,,,,,,^^^^^^###
+D:############################### ########1...... ############# ##### C#T.................T##......#.....#......##T....####....T######C , ------TT------------ ,,,,,^^^^^^^###
+D:###########$$$$$$$########## ######### ... ############# ##### C#T...VV...VV.......TT##.....##...##.....##TT...###.......f#####C ,------TT-TTT--TT-TT-TT---- ,,,,^^^^^^^^^###
+D:########$$$$$$$$$$$$$###### ######### ... ############# ##### C#T..VV#...#VV.......T####.#####m#####.####T..............f#####C -,--TTTTTTTTTTTTTTT-TT-TTT---,,,,^^^^^^^^^###
+D:######$$$$$$$$$$$$$$$$$### ... C#T..V###.###V.......TTT#################TTT.............T######C ---,--TT-TTT########TTT-TTTT----,,,,,^^^^^^^###
+D:######$$$$$$$$$$$$$$$$$### ... C#TT.V##4.j##V.........TTT#############TTT...............TT#####C----,---TTT###TTTTTT###TT-T-TT----,,,,,^^^^^^###
+D:######$$$$$$$$$$$$$$$$$$## ... C##T.V#######V...........TTTT#######TTTT..................TT####C----,--TTT##TTT----TTT##TTTTTT------,,,,,^^^^###
+D:#####$$$$$$$$$$$$$$$$$$$## ######### ... ############# CC#T.VV#####VV.............................................TTT#CC----,---TT#TT--------TT##T-T-TT------,,,,^^^^###
+D:#####$$$$$$$#####$$$$$$$## ######### ... ############# C#T..VV###VV.....TTTTTTTTTTT.......TTTTTTTTTTT..............T#C-----,,,,,,,,,,,,,,,,,,,e#TT-TTT------,,,,^^^^###
+D:####$$$$#############$$$$# ########o.........7############ C#T...VVVVV....TTT#########TTT...TTT#########TTT............T#C----------T#TT--------TT##TTT-------,,,,^^^^^^###
+D:####$###################$# ######### ... ############# C#TT..........TT###VVVVVV####TT.TT####WWWWWW###TT..........TT#C--------TTT##TTT----TTT##TTTTT-----,,,,^^^^^^^###
+D:########################## ######### ... ############# C##T..........T##VVV....VVV###TTT###WWW....WWW##T..........T##C-------TTTTT###TTTTTT###TTTTT-----,,,,,^^^^^^^###
+D:########################### ... CC#T..........T#VV........VV#######WW........WW#T..........T#CC -----TTTT-TTT########TTTTTT------,,,,,,,^^^^^###
+D:########################### #...# C#TT.......................i#####k.......................TT#C -T---TTTTT-TTTTTTTTTT-TT------ ,,,,,,,z^^^###
+D:############################ ##...## C##TT........T#VV........VV#######WW........WW#T........TT##C ------TTTT-TT--TT---T----- ,,,,,,,^^^^^^###
+D:############################ ####6#### CC##TT.......T##VVV....VVV#########WWW....WWW##T.......TT##CC ------TTT-TTTT--T----- ,,,,,,,^^^^^^^^^###
+D:############################# ####### CC##TTTT...TTT###VVVVVV#############WWWWWW###TTT...TTTT##CC ------T-------- ,,,,,,^^^^^^^^^^^^###
+D:############################## ##### CC####TTTTTTTTT###########################TTTTTTTTT####CC ,,,,,,^^^^^^^^^^^^^^###
+D:############################### ##### CCCC######TTTTTTTTTTT##############TTTTTTTTTT######CCCC ,,,,,,^^^^^^^^^^^^^^^^^###
+D:################################ ##### CCCCCC#####################################CCCCCC ,,,,,,,,,,^^^^^^^^^^^^^^^^^###
+D:################################# ##### CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC ,,,,,,,,,,^^^^^^^^^^^^^^^^^^####
+D:################################## ####### ,,,,,,,,,,,^^^^^^^^^^^^^^^^^^^^^####
+D:#################################### ######### ,,,,,,,,,,,,,^^^^^^^^^^^^^^^^^^^######
+D:###################################### ############# ,,,,,,,,,,,,,,,^^^^^^^^^^^^^^^^^^########
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+
+# Default starting position
+?:[EQU $LEAVING_QUEST 0]
+P:33:50
+
+# Starting position when coming from quest 19
+?:[EQU $LEAVING_QUEST 19]
+P:51:190
+
+# Starting position when coming from quest 20
+?:[EQU $LEAVING_QUEST 20]
+P:33:13
+
+# Starting position when coming from quest 21
+?:[EQU $LEAVING_QUEST 21]
+P:27:168
+
+# Starting position when coming from quest 22
+?:[EQU $LEAVING_QUEST 22]
+P:6:42
diff --git a/lib/edit/t_info.txt b/lib/edit/t_info.txt
new file mode 100644
index 00000000..7aca3781
--- /dev/null
+++ b/lib/edit/t_info.txt
@@ -0,0 +1,41 @@
+# File: t_info.txt
+
+# Includes the town definitions
+
+# Preferences for the town features
+%:t_pref.txt
+
+# Town Bree
+?:[AND [EQU $TOWN 1] [EQU $TOWN_DESTROY1 1] ]
+%:t_d_bree.txt
+?:[AND [EQU $TOWN 1] [NOT [EQU $TOWN_DESTROY1 1] ] ]
+%:t_bree.txt
+?:1
+
+# Town Gondor
+?:[AND [EQU $TOWN 2] [EQU $TOWN_DESTROY2 1] ]
+%:t_d_gond.txt
+?:[AND [EQU $TOWN 2] [NOT [EQU $TOWN_DESTROY2 1] ] ]
+%:t_gondol.txt
+?:1
+
+# Minas Anor
+?:[AND [EQU $TOWN 3] [EQU $TOWN_DESTROY3 1] ]
+%:t_d_mina.txt
+?:[AND [EQU $TOWN 3] [NOT [EQU $TOWN_DESTROY3 1] ] ]
+%:t_minas.txt
+?:1
+
+# Town Lothlorien
+?:[AND [EQU $TOWN 4] [EQU $TOWN_DESTROY4 1] ]
+%:t_d_lori.txt
+?:[AND [EQU $TOWN 4] [NOT [EQU $TOWN_DESTROY4 1] ] ]
+%:t_lorien.txt
+?:1
+
+# Khazad-Dum
+?:[AND [EQU $TOWN 5] [EQU $TOWN_DESTROY5 1] ]
+%:t_d_khaz.txt
+?:[AND [EQU $TOWN 5] [NOT [EQU $TOWN_DESTROY5 1] ] ]
+%:t_khazad.txt
+?:1
diff --git a/lib/edit/t_khazad.txt b/lib/edit/t_khazad.txt
new file mode 100644
index 00000000..0139fa40
--- /dev/null
+++ b/lib/edit/t_khazad.txt
@@ -0,0 +1,105 @@
+# Town Name: Khazad-Dum
+# by fearoffours (fearoffours@moppy.co.uk)
+#
+# Created for ToME
+
+F:o:207:3
+
+###################### Buildings ########################
+
+# Fighters Hall
+F:f:74:3:0:0:0:0:0:17
+
+# Paladins Guild
+F:g:74:3:0:0:0:0:0:20
+
+# Inner Temple
+F:h:74:3:0:0:0:0:0:19
+
+# Mining Supplies
+F:i:74:3:0:0:0:0:0:59
+
+# Default for Quest 25 = entrance is quest entrance
+F:w:8:3:0:0:0:0:0:25
+
+# Force dwarven monsters
+f:DWARVEN
+
+############### Quest 25 - Evil cave finished = house ###############
+?:[EQU $QUEST25 2]
+F:w:74:3:0:0:0:0:0:7
+?:[EQU $QUEST25 5]
+F:w:74:3:0:0:0:0:0:7
+?:1
+
+# Town Layout
+D:######################################################################################################################################################################################################
+D:#ooooooooooooo####^^^^^^^^^#######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#####oooo#######oo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^##########oooooooooo CCCCCCC #
+D:#ooo##ooooooooo#####^^^^^##########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^########ooo########ooo##########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^################oooooooooooo CCCCCCCC #
+D:##oo###oo####oo##############################^^^^^^^^^^^^^^^^^########################oooo#########oo#### ###########^^^^^^^^^^^^^^^^^^^^^^^^####### #######oooo########## CCCCCCCC #
+D:##############o#########oo###oo###################^^^^^^^############################oooo#########oo###### ################################# #####ooooooooo############# CCCCCCCC ; #
+D:#^^^^########oooooooooooooo##ooooooooo############################# #################oooo########oo########### ########################## ######ooooooooo################ CCCCCCCC ; #
+D:#############ooooooooooooooooooooooooooo###### ###########1###### ##############2####oooo#######o##o##3####f##### ##g####4####h###### ###########ooo######################## CCCCCCCC ; #
+D:#^#############ooooo##################oo### # #### # ##### #### ############### ###ooo########ooo## ## ###### # ## ## ## # #######ooooo########################### CCCCCCCC #
+D:#^^################oo#################ooooo#### ## ; ;; o ; o ## # ooooooooo############################ CCCCCCCC #
+D:#^^^^################o##########o#####oooooooooooooooooooooo o o ; oooooooooooooooooooooooo##ooo############################ CCCCCCC #
+D:#^^^^^^################################# ## ; o ; ; o o ; o ##o################################### CCCCCCC#
+D:#^^^^^^################################ ### o ### o ### o ###; o ### ######################################## CCCCCC#
+D:#^^^^^################################# ##### o ##### o ##### o ##### o ##### ######################################## CCCCCC#
+D:#^^^^^^^################################ #######;; o ####### o ####### o ####### o ####### ####################################### ; CCCCCC#
+D:#^^^^^^^^################################ # ####### o ; ####### o ####### o ####### o ####### ######################################## CCCCCC #
+D:#^^^^^^^################################### ##### o ; ;##### o ##### o ##### ; o ##### ;####################################### CCCCCCC #
+D:#^^^^^^^^^################################ ### o ### o ### o ### o ### # #################################### CCCCCC ; #
+D:#^^^^^^^^^################################# o o o o ## ################################## CCCCCC #
+D:#^^^^^^^^^^################################ ; oooooooooooo o o oooooooooooo 5################################ CCCCCC ; #
+D:#^^^^^^^^^^^^^########################### o o o o ################################# CCCCCCC #
+D:#^^^^^^^^^^^^^^^########################## ### o ### o o ;### o ### ################################ CCCCCCC ; #
+D:#^^^^^^^^^^^^############################# ##### ; o ##### o o ##### o ##### ; ###############################; CCCCCCC ; #
+D:#^^^^^^^^^############################### ; ####### o ####### o ; o ####### o ####### ############################ CCCCCCC #
+D:#^######################################### ; ####### oooooooo ####### o o ####### oooooo ####### o ; ##############################; CCCCCCC #
+D:#################ooo###################### ; ##### o ##### o o ##### o ##### ###############oo############## CCCCC; #
+D:####oo##ooo#####o#######o###ooo########### ### ; o ### o o ### o ; ### ; ;; #########oo###oooooo#####oo###### CCCCC ; #
+D:#ooooooooooooooooooooooooooooooo##oooooooo ; o ; o o o ; ;; ; oooooooooooo##oooooooo##oooooooooo CCCCC ; #
+D:#ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo CCCCCC #
+D:#oooooooooooooooooo##oooooo##oooooo##ooooo ; o o ; ooooooooo#oooooooooooooooooooooooo CCCCC #
+D:#^#######################oo####ooooo####### ### ### o o ###; ### ######o####oo####oo######oo######; CCCCC #
+D:#^^#######################o########### ##### ##### o o ##### ##### ######o####################oo#### CCCCC #
+D:#^####################################### #######;; ; ####### o o ####### ####### ####oo######################### CCCCCC #
+D:#^^######################################## ####### ; ####### o o ####### ####### ######o############oo########## CCCCCCC #
+D:#^^^###############ooo################### ##### ; ;##### o o ##### ; ##### ;; ######oo########ooooo####### CCCCCCCC #
+D:#####oo##oo#####oooooooo##############oo## ### ; ### o o ### ### ########oooo##oooooo####### CCCCCCCCC ; #
+D:#ooooooooooo###ooooooooooooooooooooooooooo o o ooooooooooooooooooooooooooo CCCCCCCC #
+D:#oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo CCCCCCCC ; #
+D:#^ooooooooooooooooo###oooooooooo##oooooooo o o o o ooooooo####ooooooooooooo CCCCCCCC #
+D:#^^#o###ooo#####ooo#####ooooo########oo# ### ; o ### o o ;### o ### oo#########ooooo###oo# CCCCCCCC ; #
+D:#^^^^^###o################oo############# ##### ; o ##### o o ##### o ##### ; ###########oo######## CCCCCCCC ; #
+D:#^^^^^^^################################## ; ####### ooooooo ####### o ; o ####### ooooo ####### ######################## CCCCCCCCC #
+D:#^^^^^^^^^^############################## ; ####### o ; ####### o o ####### o ####### o ; ########################## CCCCCCCC #
+D:#^^^^^^^^^^^^^^^######################### ; ##### o ##### o o ##### o ##### ############################ CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^################### ### ; o ### o o ### o ; ### ; ;; ############################ CCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^#################### ; o ;; o ; o o ; ############################ CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^###################### ooooooooooo o o oooooooooooo ;; ; 7########################### CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^^^^################# ; o ; ; o o ; o ############################# CCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^############## ### o ### o ### o ###; o ### ############################# CCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^############ ##### o ##### o ##### o ##### o ##### ######################## CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^########## #######;; ; o ####### o ####### o ####### o ####### ########################### CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^#########i ####### o ; ####### o ####### o ####### o ####### ############################ CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^########### ##### o ; ;##### o ##### o ##### ; o ##### ; ############################## CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^############## ### ; o ### o ### o ### o ### ############################## CCCCCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^^^^################# o o o o #########oo###oo################# CCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^#############o#######oooooooooooooooooooooo ## o o oooooooooooooooooooooooooooooooooooo################## CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^############ooooooooooo# ### ## ######## o o ## o ## ## oooooo##oooooooooo################### CCCCCCC #
+D:#^^^^^^^^^^^#################ooooooooooo#### ###### ### #### ############# ####oooo###### #ooo# ### ###### # ### ## ##### ####################ooo##################### CCCCCCC #
+D:#^^^^^^^^^^###################oo######oo### ########### #######9####################oooo########oooo############w### ######## ###### ####################oo###################### CCCCCCC #
+D:#^^^^^^^##########oo####oo####ooo######### ############# ##############^^^##########ooooo########oo###################################### #########^######oooo##ooo################## CCCCCCC #
+D:##^^^^^#########oooooooooooooooo#################^^####### ###########^^^^^###########ooooo######ooo####################################### #####^^^#######ooooooooooooo############# ; CCCCCCC#
+D:#^^^##########ooooooooooo##ooooo######^#########^^^^##################^^^^^^^^^^^######ooo#######oooo#########^^^^^^^^^^^^^^^^^^^########### #####^^^#######oo##oooooooo############# CCCCCC#
+D:##############ooooo##########oo######^^^#####^^^^^^^^###############^^^^^^^^^^^^^^#####oooo#######ooo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^###### ####^^^^^###############ooo############## CCCCC#
+D:########ooo#####oo##################^^^^^^^^^^^^^^^^^#############^^^^^^^^^^^^^^^^^####oo########oooo#####^^^^^^^^^^^^^^^^^^^^^^^^^^^########### #######^^^^^#############ooo#ooo######## CCCCCC#
+D:#o##oooooooooooooooo##############^^^^^^^^^^^^^^^^^^^^^^#########^^^^^^^^^^^^^^^^^^#####oo########oo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####### # ######^^^^^^^^^^^^########oooooooooooooo CCCCC #
+D:#oooooooooooooooooo########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^########oooo#######ooooo###^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^##############^^^^^^^^^^^^^^^#######ooooooooooo CCCCC #
+D:######################################################################################################################################################################################################
+
+# Default starting position
+# ?:[EQU $LEAVING_QUES 0]
+# P:31:32
diff --git a/lib/edit/t_lorien.txt b/lib/edit/t_lorien.txt
new file mode 100644
index 00000000..9c8c8ad3
--- /dev/null
+++ b/lib/edit/t_lorien.txt
@@ -0,0 +1,162 @@
+# Town Name: Lothlorien
+# by Akhronath (zzhou22876@aol.com)
+#
+# Created for PernAngband
+
+# Default for Mage/Fireproof Quest = entrance is tree
+F:z:96:3
+
+# Default for Quest 10 = entrance is tree
+F:y:96:3
+
+# Default for Quest 11 = entrance is tree
+F:x:96:3
+
+# Default for entrance to the Void, entrance is dirt
+F:v:88:3
+
+# Default for Quest 22 = entrance is quest entrance
+F:w:8:3:0:0:0:0:0:22
+
+############### Quest 22 - Wolves hut finished = house ###############
+?:[EQU $QUEST22 2]
+F:w:74:3:0:0:0:0:0:7
+?:[EQU $QUEST22 5]
+F:w:74:3:0:0:0:0:0:7
+?:1
+
+############### Entrance to the Void ###############
+?:[EQU $QUEST20 1]
+F:v:7:3:0:0:0:0:0:11
+?:1
+
+############### Quest 10 - Spiders of Mirkwood ###############
+# Quest 10 taken, entrance is quest entrance
+?:[EQU $QUEST10 1]
+F:y:8:3:0:0:0:0:0:10
+?:1
+
+############### Quest - Mage/Fireroof quest ###############
+# Mage/Fireproof Quest taken, entrance is quest entrance
+?:[EQU $QUEST"Old Mages quest" 1]
+F:z:8:3:0:0:0:0:0:"Old Mages quest"
+?:1
+
+###################### Buildings ########################
+
+# The Mirror
+F:a:74:3:0:0:0:0:0:23
+
+# Castle: Plot Lorien
+F:B:75:3:0:0:0:0:0:2
+
+# Seat of Ruling
+F:b:74:3:0:0:0:0:0:24
+
+# Inn
+F:c:74:3:0:0:0:0:0:11
+
+# Beastmaster Shanty
+F:d:74:3:0:0:0:0:0:16
+
+# Fighters Hall
+F:f:74:3:0:0:0:0:0:17
+
+# Wizards Spire
+F:g:74:3:0:0:0:0:0:25
+
+# Priests Circle
+F:h:74:3:0:0:0:0:0:26
+
+# Rangers Guild allows Ranger
+F:i:74:3:0:0:0:0:0:21
+
+# Nest
+F:j:74:3:0:0:0:0:0:22
+
+# Altars
+F:k:161:3
+F:l:162:3
+F:m:163:3
+F:n:165:3
+
+# Force elven monsters
+f:ELVEN
+
+# Town Layout
+D:######################################################################################################################################################################################################
+D:# , , , . , , ,, , , , #
+D:# , , . , #
+D:# , , . #
+D:# , , ,, , . , , , #
+D:# ,, , , , ,, , , , , , #
+D:# , , , , , , , , #
+D:# , , , ,x , , #
+D:# , , , , #
+D:# ,, , , , ,, , , , #
+D:# , , , , #
+D:# , , , , , , ,, , , , #
+D:# , , , , #
+D:# , , z,,,, ## , ## #
+D:# , , , #### , #### , #
+D:# , , , ### ###1,,,,,h### #
+D:# , , ### , #####, ####, , #### , , , #
+D:# ,, , ##### , ##### ## , ## , ,, , , , , , #
+D:# , , , ##### , ,##.## ### ## , ## , , #
+D:# , , # #, ##### , ##.## ######### , #### , , #
+D:# ,, , ### ### #g# , . ########c,,,,,4### ,, , , , #
+D:# , #### , #### , , , ,, ######### , #### , , , #
+D:# ,, , ############## ,,,,, , #9# ## , ## , ,, , , , , , #
+D:# , , , ############## , , , , , ## , , #
+D:# , , ###########j,,,,,,,,,,,,,, , , , #### , , #
+D:# , , #####B######## , ,,,,,,,,,,,,,,,,,,,,,,,,d### y , #
+D:# , , ############## , , , #### ,, , , ,, , , , #
+D:# , ,#### #### , , ## , , #
+D:# , , ### ### #6# ### ### , , ### ### #
+D:# , , # #, ##### ### ### , ,,, ########## , , #
+D:# ##### #7# #i# ,,,,,,,, ########## , , , #
+D:# ,, , ### , , , , , , #3# ### , , , #
+D:# , , , , ,, , , , , ## , #
+D:# , , ,,, ,,,,,,,,,,,,, ,,, , , , , #### ,, , , , #
+D:# , , , ,,,, ,,,,b,,,,,,,,,,,,,,,,,,,w### , #
+D:# , , v, ,,, , #### #
+D:# , , --,-- ,, , VVV , ## , , , #
+D:# ,, , l----,----m , VWWWV #2# ,, , , , , , #
+D:# , , , ---VV,VV--- , VWWVV , ##### , #
+D:# , , ---VVW,WVV--- , VVVV ##### , #
+D:# , , , ---VWWaWVV--- ,, ### , ,, , , , #
+D:# ---VVWWWVV--- ,,, , , , #
+D:# ,, , ---VVVVV--- ,,,,,,,,,,,,,,, , ,, , , , #
+D:# n---------k , , , , , #
+D:# , , --- , #5# , #
+D:# , , , ### #
+D:# , , , , ### , , , #
+D:# ,, , #0# , ,, , , , , , #
+D:# , , , , , ##### , , #
+D:# , , , ##### , , #
+D:# ### , , , #
+D:# ,, , , ,, , , , #
+D:# , , , #
+D:# , , , , , ,, , , , #
+D:# , , ,, , , , , #
+D:# ,, , , ,, , , , , , #
+D:# , , , , , , , #
+D:# , , , , , #
+D:# , , , #
+D:# ,, , , ,, , , , #
+D:# , , , #
+D:# , , #
+D:# , , ,, , , , , #
+D:# ,, , , ,, , , , , , #
+D:# #
+D:######################################################################################################################################################################################################
+
+# Default starting position
+?:[EQU $LEAVING_QUES 0]
+P:13:99
+
+# Starting position when coming from quest 12
+?:[EQU $LEAVING_QUES 12]
+P:26:109
+
+
diff --git a/lib/edit/t_minas.txt b/lib/edit/t_minas.txt
new file mode 100644
index 00000000..51c74da3
--- /dev/null
+++ b/lib/edit/t_minas.txt
@@ -0,0 +1,144 @@
+# File: t_minas.txt
+
+# Minas Anor: The Royal City of Gondor
+# Created by Mynstral (mynstral@thehelm.com)
+
+# Completed: 22/06/01
+
+# Between gate to gondolin -- need to finish the quest
+F:Z:63:3
+
+# Default for Quest 24 = entrance is quest entrance
+F:w:8:3:0:0:0:0:0:24
+
+#################### Quest 16 - The last Alliance ####################
+
+# Quest 16 finished, reward is a between gate
+?:[EQU $QUEST16 5]
+F:Z:176:3:0:0:0:0:0:0
+
+?:1
+
+############### Quest 24 - Haunted House finished = house ###############
+?:[EQU $QUEST24 2]
+F:w:74:3:0:0:0:0:0:7
+?:[EQU $QUEST24 5]
+F:w:74:3:0:0:0:0:0:7
+?:1
+
+#################### Buildings ####################
+
+# Library
+F:a:74:3:0:0:0:0:0:60
+
+# Castle
+F:b:74:3:0:0:0:0:0:14
+
+# Casino
+F:d:74:3:0:0:0:0:0:15
+
+# Inn
+F:e:74:3:0:0:0:0:0:11
+
+# Beastmaster Shanty
+F:f:74:3:0:0:0:0:0:16
+
+# Fighters hall
+F:g:74:3:0:0:0:0:0:17
+
+# Tower of Magery
+F:h:74:3:0:0:0:0:0:18
+
+# Inner temple
+F:i:74:3:0:0:0:0:0:19
+
+# Paladin guild
+F:j:74:3:0:0:0:0:0:20
+
+# Ranger guild
+F:k:74:3:0:0:0:0:0:21
+
+# Thunderlord's Hide
+F:l:74:3:0:0:0:0:0:22
+
+# Castle: Plot Minas Anor
+F:B:75:3:0:0:0:0:0:5
+
+# Merchant guild
+F:m:74:3:0:0:0:0:0:56
+
+# Library Quest
+F:x:63:3
+
+?:[EQU $QUEST"Library quest" 1]
+F:x:8:3:0:0:0:0:0:"Library quest"
+?:1
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:#^^########------------------ @@@@@@@ @@@@@@@@@ #
+D:#^^^------############---------- ^ @@VVVVV@@ @@VVVVVVV@@@@@@@ ,,, #
+D:#^^^----------###----#######------- ^^^^^ @VVVVVVV@@@@@ @@VV@@@@@@VVVVVV@@@@ ,, #
+D:#^^----ssss-----###--------####------ ^^^^^^ @VVVVVV@@VVV@@@ @VV@@ @@@@@@VVVV@@ ,, #
+D:#^^^---StSS-------###--#ssss--###------- ^^^^^^^^ @@VVVVVVVV@VVV@@@@@@@@ @@@V@@ @@@@VV@@@@ , #
+D:#^^----ssss----OO---##--#StSS---####------ ^^^^^^^^ @@V@V,@@@@@@VVVVVVVV@@@VVV@ @@VVVV@@ ,, #
+D:#^^----x#a#-----OOO--##--#sssss----###------ ^^^^^^^^ @@@@@ @@@@@@@@VVVVV@@@ @@@@VV@@@ ,,, #
+D:#^ ---------------OO--###-#m#7#------###----- ^^^^^^^^^^ @VVV@@ @@VVV@@ ,O, #
+D:#^ StSSSS-----ss---OO---##-----OOOOO---###---- ^^^^^^^^^^^ @@@ @@VVV@@ OO #
+D:#^^ssssss----Ssss---OOO--##---OOOOOOOO---##---- ^l^^^^^^^ @@VVV@ OO #
+D:#^ ####9#---sstSss---OOO--##-OOOOOOOOOOO--##---- ^^^^^ @@VVV@@ OO #
+D:#^^^-------##sssSss---OOO--#OOO--s--OOOOO--###--- @@@@@@@@@@ @@VVV@@ OO #
+D:#^^^######---##ssh--s--OOO-OOO--StS--OOOOO---##--- @@VVVVVVVV@@@@@@@V@@@@ OO #
+D:#^^^^----###---##--ssS--OOOOO#--ssss--OOOOOO--##--- @VVVVVVVVVVVV@@VV@@ OOO OO #
+D:#^^--------###----ssSs#--OOO-##-#####--OOOOOO--##--- ---- @VVVV@@@@VVVVVVV@@ OOOOO OOOOO #
+D:#^ ----------##--#stsi--OOOO--#---------OOOOOO--#------ -------- @@VVV@@ @@VVV@@@@ OO OO OO #
+D:#^^-----------###-#s#--OOOOOO-##-#sssss--OOOOOO,#####--- ----------- @@VVV@@ @@@@@ OO- OOOOOOOOO #
+D:#^^-------------##-#--OOO-OOO--#--ssssss--OOOOO,,,,,#---- ---ssssssss--- @VVV@@ -OO #
+D:#^^--------------#---OOO-t-OOO-##-#SStSS--OOOOOO,##,#---------ssssssss---- @VV@@ --OO- #
+D:#^^^--#----------##-OOO-sssOOO--#--ssssss-OOOOOO--#,#####-----SStSSSSS----- @@VV@ --OO- #
+D:#^^^--#-----------#OOO-##4##OOO-##-ssssss--OOOOOO-#,,######---ssssssss--O--- @@VVV@ -OO-- #
+D:#^^--###----------OOO-------OOO--#-####2#--OOOOOO-##,#k#,,##--ssssssss--O---- @VVV@@ --O-- #
+D:#^^^-###---------OOO#--SSStS-OOO-#---------OOOOO---#,,,,,,,#--ssssssss--O----- @@VV@@ --OO- #
+D:#^^-#####-------OOO-#--sssss-OOO-#--ssss--OOOOO--T-#,-----,#--#####d##--O------ @VVV@ --OO-- #
+D:#^^#######------OOO-##-###j#-OOO-##-ssss--OOOOO-TT-#------,#-------,,,,,O------ @@VV@@ --OO-- #
+D:#^^^########----OOO--#-------OOO--#-StSS--OOOOO-TT-#-----,,#------------O------- @VVV@@ --OO-- #
+D:#^^############-OOO--##-StSSS-OOO-#-ssss--OOOOO--T-#----,,##---ssssssss-O-------- @@VV@@ --OOO-- #
+D:#^^^#########---OOO---#-sssss-OOO-#-ssss--OOOOOO---#,,,,,##----SSSSStSS-O--------- @@@VVV@ --OOO-- #
+D:#^^#####B###----OOO---#-###6#-OOO-#-##g#---OOOOOO--#######-----ssssssss-O---------- @VVVV@@ ---OOO-- #
+D:#^^^#######-----OOO---#-------OOO-#---------OOOOOOOOOOOOOOOOO--###e####-O----------- @@VVV@@ ------OO-- #
+D:#^^#######bOOOOOOOO-^^^^^^^^^^MMM^^^^^^^^^^^^OOOOOOOOOOOOOOOOOOOOOOOOOOOO----------- @@@VVV@@ ---OOOOOO-- #
+D:#^^#######bOOOOOOO############III############^OOOOOOOOOOOOOOOOOOOOOOOOOOOOO--------- @@VVVV@@ ---OOOOOO-- #
+D:#^ #######bOOOOOOO############III############^OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO--------- @VVVV@@ ----OOOOOO---- #
+D:#^ #######bOOOOOOOO-^^^^^^^^^^MMM^^^^^^^^^^^^OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO------- @VVV@@ ------OOOO------ #
+D:#^^^######Z-----OOO---#-sSss--OOO-#---------OOOOOOOOOOOOOOOOO-----------OOOOOOO------ ---------##@VVV@## --------OOOOO----- #
+D:#^^#########----OOO---#-sSss--OOO-#-sssss--OOOOOO--#######--------sssss-O-OOOOO----- --OOOO-----#######--------OOOOOO----- #
+D:#^^##########---OOO---#-stss--OOO-#-SStSS-OOOOOO---####,,##-------SStSS-O-OOOOO---- --OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO----- #
+D:#^^############-OOO--##-sSss--OOO-#-sssss-OOOOO--T-##k#,,,##------sssss-O--OOOOO--- --OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO----- #
+D:#^^#########----OOO--#--####-OOO--#-sssss-OOOOO-TT-#,,,,-,,#------sssss-O---OOOO--- --OOOOO-OOOOOOOOOOOOOOOOOOOOOOO------- #
+D:#^^#######------OOO-##-------OOO-##-###3#-OOOOO-TT-#,-----,#------###0#-O---OOOOO--- --OOOO---------#######--------------- #
+D:#^^-#####-------OOO-#--Ssss--OOO-#--------OOOOO--T-#,-----,#------------O----OOOO---- --OOOO---------##@VVV@##----------- #
+D:#^^^-###---------OOO#-#stss--OOO-#-ssssss--OOOOO---#,----,,#----ssssss--O-----OOOO---- ---OOOO--- @VVV@@ #
+D:#^^--###----------OOO--#sSs-OOO--#-StSSSS--OOOOOO-##,-,,,,##----SStSSS--O------OOOO---- --OOOOO---- @VVV@@ #
+D:#^^---#-----------#OOO--###-OOO-##-ssssss--OOOOOO-#,,,,####-----ssssss--O-------OOOO---- --OOOOO---- @VVVV@ #
+D:#^^^--#----------##-OOO----OOO--#--###5##-OOOOOO--#,#####-------ssssss-OO--------OOOO--------OOOOO---- @@VVV@@@ @@@@ #
+D:#^^^-------------#---OOO---OOO-##---------OOOOOO,##,#-----------####1#-O----------OOOO----OOOOOO----- @@VVVV@@@ @@@@@@ #
+D:#^^-------------##----OOO-OOO--#--ss------OOOOO,,,,,#------------------O-----------OOOOOOOOOOO----- @@@VVVV@@ @@@@@@@@@V@@@ #
+D:#^^^----------###--ss--OOOOOO-##-ssSs----OOOOOO,#####------------------O-------- ---OOOOOOOOO--- @@VVVV@@ @@@@@ @@@@@@@@@@@@@ #
+D:#^^^---------##---ssSs--OOOO--#--ssts#--OOOOOO--#------ ------ssssss--OO------ ---OOOOO----- @@VVVV@@@ @@@VVV@@@ @@@V@@@@@@@@ #
+D:#^^--------###---sstss#--OOO-##-ssSs#--OOOOOO--##----- ----StSSSS--O------ ----------- @@@VVVV@@@@@ @@@@VVVVVVV@@ @@@@@V@@V@@@V@@ #
+D:#^^------###-----#Sss#--OOOOO#--sSsf--OOOOOO--##----- ---ssssss--O----- ------- @@@VVVVVV@@@@@@@@@@@VVVVV@@@VVV@@@@@VVVV@@@@ @@@@ #
+D:#^^^######---ss---#s#--OOO-OOO--Ss#--OOOOO---##----- --###w##-OO----- @@VVVVVVVVVVVVVVVVV@@@@@ @@@VVVVVVV@@@@ #
+D:#^^^-------ssssS---#--OOO--#OOO--#--OOOOO--###----- --------O----- @@@@@@@@@@@@@@@@@@@ @@@@@@@@@ #
+D:#^^-sssss-#ssstss----OOO--##-OOO---OOOOO--##------ ------OO---- #
+D:#^^-SSStS--#sSsss#--OOO--##---OOOOOOOO---##------ ----O---- #
+D:#^^-sssss---#ss##--OO---##--X--OOOOO---###------ ---O--- #
+D:#^^^#####----##---OO--###--XXX-OOO---###------ --- #
+D:#^^^------------OOO--##---XXX#-----###----- #
+D:#^^--SStSS-----OO---##--XX###---####----- #
+D:#^^^-sssss--------###--###----###------ #
+D:#^^--#####------###--------####------ #
+D:#^^^----------###----#######------ #
+D:#^^^------############---------- #
+D:#^^########----------------- #
+D:######################################################################################################################################################################################################
diff --git a/lib/edit/t_pref.txt b/lib/edit/t_pref.txt
new file mode 100644
index 00000000..84ff947d
--- /dev/null
+++ b/lib/edit/t_pref.txt
@@ -0,0 +1,111 @@
+# File: t_pref.txt
+
+# Defines the preferences for the town features
+# letter:feature:cave_info:monster:object:ego:artifact:trap:special
+
+# Barrow-Downs entrance
+F:{:7:3:0:0:0:0:0:4
+
+# Mirkwood Forest entrance
+F:~:7:3:0:0:0:0:0:1
+
+# Land of Mordor entrance
+F:|:7:3:0:0:0:0:0:2
+
+# Angband Dungeon entrance
+F:>:7:3:0:0:0:0:0:3
+
+# Mountain chain
+F:^:97:3
+
+# Floor
+F:.:1:3
+
+# Trees
+F:T:96:3
+
+# Deep water
+F:W:187:3
+
+# Shallow water
+F:V:84:3
+
+# Deep Lava
+F:L:85:3
+
+# Shallow Lava
+F:K:86:3
+
+# Chasm
+F:C:87:3
+
+# Dirt
+F:,:88:3
+
+# Mud
+F:@:94:3
+
+# Rubble
+F:;:49:3
+
+# Grass
+F:-:89:3
+
+# Permanent wall
+F:#:63:3
+
+# Brick Roof
+F:s:193:3
+# Brick Roof Top
+F:S:194:3
+# Brick Roof Chimney
+F:t:195:3
+
+# Grass Roof
+F:X:190:3
+# Grass Roof Top
+F:U:191:3
+# Grass Roof Chimney
+F:Y:192:3
+
+# Cobblestone Road
+F:O:200:3
+
+# General Store
+F:1:74:3:0:0:0:0:0:0
+
+# Armoury
+F:2:74:3:0:0:0:0:0:1
+
+# Weapons Smith
+F:3:74:3:0:0:0:0:0:2
+
+# Temple
+F:4:74:3:0:0:0:0:0:3
+
+# Alchemy Shop
+F:5:74:3:0:0:0:0:0:4
+
+# Magic Shop
+F:6:74:3:0:0:0:0:0:5
+
+# Black Market
+F:7:74:3:0:0:0:0:0:6
+
+# Home
+F:8:74:3:0:0:0:0:0:7
+
+# Bookstore
+F:9:74:3:0:0:0:0:0:8
+
+# Pet Shop
+F:0:74:3:0:0:0:0:0:9
+
+# Underground Tunnels -- used for tunnels in towns
+F:I:173:3
+
+# Underground Tunnels -- used for tunnels in towns
+F:M:204:3
+
+# Fake blank feature
+F: :0:3
diff --git a/lib/edit/thieves.map b/lib/edit/thieves.map
new file mode 100644
index 00000000..a2cdb442
--- /dev/null
+++ b/lib/edit/thieves.map
@@ -0,0 +1,70 @@
+# Floor
+F:.:1:6
+
+# Dark floor
+F:,:1:4
+
+# Permanent wall
+F:X:61:4
+
+# Lit permanent wall
+F:x:61:6
+
+# Magically locked door
+F:M:38:22
+
+# Locked door
+F:D:38:6
+
+# Open door
+F:d:4:6
+
+# up staircase
+F:<:6:8
+
+# Floor with Novice rogue
+F:a:1:6:44:0:0:0:0:0:0:2
+
+# Floor with Bandit
+F:b:1:6:150:43:*:0:0:0:0:2
+
+# Floor with novice warrior
+F:c:1:6:43:0:0:0:0:0:0:2
+
+# Floor with novice mage
+F:e:1:6:46:0:0:0:0:0:0:2
+
+# Dark floor with novice warrior
+F:f:1:4:43:0:0:0:0:0:0:2
+
+# Floor with human skeleton
+F:z:1:6:0:395
+
+# Dungeon layout
+D:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+D:x.....x....zx.....x.............x
+D:x.....x.....x.....x.............x
+D:x.....x.....x.....x.............x
+D:xxxMxxxxxdxxxxxdxxxxxxxxxDxxxxxxx
+D:XXx..........................xXXX
+D:XXx.xxxxx.xxxxx.xxxxxxxxx.xx,xXXX
+D:XXxxxXXXxxxXXXxxxXXXXXXXxxx,,,XXX
+D:XXXXxxxxxxxxxxxxxxxxxXXXXX,,,,,XX
+D:XXXXxe..xb..x...x...xXXXX,,,,,,,X
+D:XXXXx...x...xa..x...xXXXX,,,,,,,X
+D:XXXXx...x...x...x.a.xXXXX,,,,,,,X
+D:xxxxxxDxxxDxxxDxxxDxxXXXXX,,,,,XX
+D:x,,,x...............xXXXXXX,,,XXX
+D:x,,,x..x.........x..xXXXXXXX,XXXX
+D:x,,,D.....x...x.....D,,,,,,,,XXXX
+D:x,,,x..x.........x..xXXXXXXXXXXXX
+D:x,,,x...............xXXXXXXXXXXXX
+D:x,,,xxDxxxDxxxDxxxDxxXXXXXXXXXXXX
+D:x,,,x...x...x.a.xa..xXXXXXXXXXXXX
+D:x,,,xc..x.a.x...x...xXXXXXXXXXXXX
+D:xf,fx...x...x...x...xXXXXXXXXXXXX
+D:xxxxxxxxxxxxxxxxxxxxxXXXXXXXXXXXX
+
+# Starting position
+P:4:4
+
diff --git a/lib/edit/thrain.map b/lib/edit/thrain.map
new file mode 100644
index 00000000..8adc41be
--- /dev/null
+++ b/lib/edit/thrain.map
@@ -0,0 +1,35 @@
+# Floor
+F:.:1:0:0:0:0:0:0:0:61
+
+# Some Nazguls
+F:1:1:0:951:0:0:0:0:0:61:2
+F:2:1:0:952:0:0:0:0:0:61:2
+F:o:1:0:866:0:0:0:0:0:61
+
+# Marker
+F:,:172:6:0:0:0:0:0:0:61
+
+# Lit permanent wall
+F:x:61:6
+
+# Door
+F:D:48:0:0:0:0:0:0:0:61
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep lava
+F:l:85:0:0:0:0:0:0:0:61
+
+# Dungeon layout
+D:
+D: xxxxxxxx
+D: xoooo..x
+D: xo2oo..x
+D: xlloo..x
+D: x,loo..D
+D: xlloo..x
+D: xo1oo..x
+D: xoooo..x
+D: xxxxxxxx
+D:
diff --git a/lib/edit/tr_info.txt b/lib/edit/tr_info.txt
new file mode 100644
index 00000000..e86d9617
--- /dev/null
+++ b/lib/edit/tr_info.txt
@@ -0,0 +1,817 @@
+# This file comes from Angband64 written by Jurriaan Kalkman
+# and describes the traps items can have
+#
+# byte type; /* this goes into sval */
+# s16b probability; /* probability of existence in 1000 */
+# s16b another; /* does this trap easily combine in 1000 */
+# s16b pvalinc; /* how much does this trap attribute to pval */
+# byte difficulty; /* how difficult to disarm */
+# byte level; /* minimum level - disenchantment trap at 200' is */
+# /* not so nice */
+# byte color;
+# cptr name; /* what name does this trap have */
+#
+# d TERM_DARK |r TERM_RED |D TERM_L_DARK |R TERM_L_RED
+# w TERM_WHITE |g TERM_GREEN|W TERM_L_WHITE|G TERM_L_GREEN
+# s TERM_SLATE |b TERM_BLUE |v TERM_VIOLET |B TERM_L_BLUE
+# o TERM_ORANGE|u TERM_UMBER|y TERM_YELLOW |U TERM_L_UMBER
+#
+# b blue for stat traps
+# w white for teleport traps
+# o orange for dungeon rearrangement traps
+# v violet for summoning traps
+# y yellow for stealing/equipment traps
+# r red for other character affecting traps
+# g green for elemental bolt trap
+# B umber for elemental ball trap
+# R l red for arrow/dagger traps
+# W for compound trap!!!
+# don't use U or you'll get trapped doors that are indistinguishable from untrapped doors!
+#
+# an unknown character is multi-hued!
+#
+# N:type:name
+# I:diff:prob:another:pval:minlevel:damage:color
+# I:diff:prob: :minlevel: :color
+# D:description
+
+V:2.0.0
+
+#
+# stat traps
+#
+
+N:1:Weakness Trap
+I:2:100:5:5:2:0d0:b
+D:A poisoned needle weakens you!
+F:FLOOR | CHEST | DOOR
+
+N:2:Weakness Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle seriously weakens you!
+F:FLOOR | CHEST | DOOR
+
+N:3:Weakness Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle permanently weakens you!
+F:FLOOR | CHEST | DOOR
+
+N:4:Intelligence Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle makes you feel stupid!
+F:FLOOR | CHEST | DOOR
+
+N:5:Intelligence Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle makes you feel very stupid!
+F:FLOOR | CHEST | DOOR
+
+N:6:Intelligence Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle makes you feel permanently stupid!
+F:FLOOR | CHEST | DOOR
+
+N:7:Wisdom Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle makes you feel naive!
+F:FLOOR | CHEST | DOOR
+
+N:8:Wisdom Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle makes you feel very naive!
+F:FLOOR | CHEST | DOOR
+
+N:9:Wisdom Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle makes you feel permanently naive!
+F:FLOOR | CHEST | DOOR
+
+N:10:Fumbling Fingers Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle makes you feel clumsy!
+F:FLOOR | CHEST | DOOR
+
+N:11:Fumbling Fingers Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle makes you feel very clumsy!
+F:FLOOR | CHEST | DOOR
+
+N:12:Fumbling Fingers Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle makes you feel permanently clumsy!
+F:FLOOR | CHEST | DOOR
+
+N:13:Wasting Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle makes you feel sickly!
+F:FLOOR | CHEST | DOOR
+
+N:14:Wasting Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle makes you feel very sickly!
+F:FLOOR | CHEST | DOOR
+
+N:15:Wasting Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle makes you feel permanently sickly!
+F:FLOOR | CHEST | DOOR
+
+N:16:Beauty Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle scars you!
+F:FLOOR | CHEST | DOOR
+
+N:17:Beauty Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle scars you horribly!
+F:FLOOR | CHEST | DOOR
+
+N:18:Beauty Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle scars you permanently!
+F:FLOOR | CHEST | DOOR
+
+#
+# miscellaneous traps
+#
+
+N:20:Trap of Curse Weapon
+I:5:10:0:12:20:0d0:y
+D:Your weapon will never be the same...
+F:FLOOR | CHEST | DOOR
+
+N:21:Trap of Curse Armour
+I:5:15:0:12:20:0d0:y
+D:Your armour doesn't exactly get better by setting off this trap...
+F:FLOOR | CHEST | DOOR
+
+N:22:Earthquake Trap
+I:5:20:0:10:10:0d0:o
+D:The ceiling collapses around you!
+F:FLOOR | CHEST | DOOR
+
+N:23:Poison Needle Trap
+I:1:50:50:3:2:0d0:r
+D:A poisoned needle pricks you!
+F:FLOOR | CHEST | DOOR
+
+N:24:Summon Monster Trap
+I:2:50:40:4:2:0d0:v
+D:Monsters defend the memory of the owner...
+F:FLOOR | CHEST | DOOR
+
+N:25:Summon Undead Trap
+I:4:25:40:6:10:0d0:v
+D:Undead rise from the grave to defend this!
+F:FLOOR | CHEST | DOOR
+
+N:26:Summon Greater Undead Trap
+I:8:10:50:20:20:0d0:v
+D:Greater undead defend this!
+F:FLOOR | CHEST | DOOR
+
+N:27:Teleport Trap
+I:3:100:50:3:2:0d0:w
+D:Now you know why nobody ever got close enough to disarm this trap...
+F:FLOOR | CHEST | DOOR
+
+N:28:Paralysing Trap
+I:1:100:20:2:2:0d0:r
+D:You suddenly cannot move!
+F:FLOOR | CHEST | DOOR
+
+N:29:Explosive Device
+I:3:100:80:0:3:3d8:r
+D:Ha! It explodes before your hands can illegally touch it!
+F:FLOOR | CHEST | DOOR
+
+N:30:Teleport Item Trap
+I:3:50:50:3:5:0d0:w
+D:The item magically disappears from your greedy hands!
+F:FLOOR | CHEST
+
+N:31:Lose Memory Trap
+I:6:30:30:6:10:0d0:r
+D:You suddenly can't remember what you were doing here...
+F:FLOOR | CHEST | DOOR
+
+N:32:Bitter Regret Trap
+I:9:15:20:9:20:0d0:r
+D:You already regret trying this...
+F:FLOOR | CHEST | DOOR
+
+N:33:Bowel Cramps Trap
+I:1:90:20:1:6:0d0:r
+D:Your stomach twists with a sharp pang!
+F:FLOOR | CHEST | DOOR
+
+N:34:Blindness/Confusion Trap
+I:4:100:50:4:6:0d0:r
+D:You suddenly can't see, and thinking is difficult too....
+F:FLOOR | CHEST | DOOR
+
+N:35:Aggravation Trap
+I:2:100:50:2:3:0d0:o
+D:Your hear a high-pitched humming noise...
+F:FLOOR | CHEST | DOOR
+
+N:36:Multiplication Trap
+I:3:90:0:3:5:0d0:o
+D:The floor around you doesn't seem the same...
+F:FLOOR | CHEST | DOOR
+
+N:37:Steal Item Trap
+I:3:100:50:3:6:0d0:y
+D:The chest seems to swell, while your backpack feels lighter..
+F:FLOOR | CHEST
+
+N:38:Summon Fast Quylthulgs Trap
+I:8:50:10:10:25:0d0:v
+D:Parts of the owner seem to return from somewhere else, as you slow in awe.
+F:FLOOR | CHEST | DOOR
+
+N:39:Trap of Sinking
+I:2:50:0:0:3:0d0:w
+D:A trapdoor opens up under you!
+F:FLOOR | DOOR
+
+N:40:Trap of Mana Drain
+I:4:100:50:3:4:0d0:r
+D:You suddenly can't think so clearly any more...
+F:FLOOR | CHEST | DOOR
+
+N:41:Trap of Missing Money
+I:2:100:50:2:2:0d0:y
+D:Money isn't everything, they say...
+F:FLOOR | CHEST | DOOR
+
+N:42:Trap of No Return
+I:5:20:10:4:8:0d0:y
+D:Do stay a while!
+F:FLOOR | CHEST | DOOR
+
+N:43:Trap of Silent Switching
+I:4:100:50:3:6:0d0:y
+D:You suddenly are a different person!
+F:FLOOR | CHEST | DOOR
+
+N:44:Trap of Walls
+I:6:100:50:2:10:0d0:o
+D:The room seems to shrink!
+F:FLOOR | CHEST | DOOR
+
+N:45:Trap of Calling Out
+I:10:100:100:5:15:0d0:v
+D:You hear something coming closer, much closer.
+F:FLOOR | CHEST | DOOR
+
+N:46:Trap of Sliding
+I:8:50:50:4:8:0d0:r
+D:Your feet seem to have a life of their own!
+F:FLOOR | CHEST | DOOR
+
+N:47:Trap of Charges Drain
+I:6:100:70:2:3:0d0:y
+D:You feel as if you've just lost something...
+F:FLOOR | CHEST | DOOR
+
+N:48:Trap of Stair Movement
+I:6:0:50:3:4:0d0:o
+D:The dungeon seems different...
+F:FLOOR | CHEST | DOOR
+
+N:49:Trap of New Trap
+I:5:100:5:0:4:0d0:o
+D:Somehow, disarming isn't over, you feel...
+F:FLOOR | CHEST | DOOR
+
+N:50:Trap of Scatter Items
+I:10:50:50:6:12:0d0:w
+D:You hear crashing sounds from all over the dungeon!
+F:FLOOR | CHEST | DOOR
+
+N:51:Trap of Decay
+I:4:100:50:4:4:0d0:r
+D:Your stomach isn't empty, but suddenly you think of food.
+F:FLOOR | CHEST | DOOR
+
+N:52:Trap of Wasting Wands
+I:6:100:40:4:5:0d0:y
+D:Your wands seem different...
+F:FLOOR | CHEST | DOOR
+
+N:53:Trap of Filling
+I:10:100:0:10:25:0d0:o
+D:The whole room vibrates in a strange way...
+F:FLOOR | CHEST | DOOR
+
+N:54:Trap of Drain Speed
+I:8:50:10:25:80:0d0:y
+D:You suddenly seem to have more time to self-reflect...
+F:FLOOR | CHEST | DOOR
+
+#
+# bolt traps
+#
+
+N:60:Lightning Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:You are jolted with electricity!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:61:Poison Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:A blast of poison gas hits you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:62:Acid Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:A jet of acid shoots out at you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:63:Cold Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:You are suddenly very cold!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:64:Fire Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:You are suddenly very hot!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:65:Plasma Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A bolt of plasma hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:66:Water Bolt Trap
+I:4:80:5:5:8:5d10:g
+D:A gush of water hits you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:67:Light Bolt Trap
+I:4:80:5:5:8:5d10:g
+D:There is a sudden flash of light around you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:68:Dark Bolt Trap
+I:4:80:5:5:8:5d10:g
+D:A bolt of pure elemental darkness hits you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:69:Shards Bolt Trap
+I:6:80:5:6:15:6d10:g
+D:A blast of crystal shards hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:70:Sound Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A sudden roar of sound hurts your eardrums!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:71:Confusion Bolt Trap
+I:4:80:5:5:8:6d10:g
+D:A blast of confusion gas engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:72:Force Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A bolt of pure force hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:73:Inertia Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:Your feet feel like lead!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:74:Mana Bolt Trap
+I:8:80:5:9:25:15d16:g
+D:A bolt of pure magic hits you!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:75:Ice Bolt Trap
+I:4:80:5:5:8:5d10:g
+D:A bolt of ice hits you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:76:Chaos Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A blast of raw chaos hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:77:Nether Bolt Trap
+I:8:80:5:9:25:15d16:g
+D:A bolt of negative energy hits you!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:78:Disenchantment Bolt Trap
+I:8:80:5:9:25:15d16:g
+D:There is a static feeling in the air...
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:79:Nexus Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A bolt of nexus hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:80:Time Bolt Trap
+I:8:80:5:9:25:15d16:g
+D:Suddenly, several months pass by in a second!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:81:Gravity Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:Gravity suddenly warps around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+#
+# ball traps
+#
+
+N:82:Lightning Ball Trap
+I:3:60:5:5:8:3d10:B
+D:A massive electrical charge shoots through you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:83:Poison Ball Trap
+I:3:60:5:5:8:3d10:B
+D:A large cloud of poison gas envelops you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:84:Acid Ball Trap
+I:3:60:5:5:8:3d10:B
+D:You are suddenly drenched in acid!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:85:Cold Ball Trap
+I:3:60:5:5:8:3d10:B
+D:A blast of hideously cold air envelops you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:86:Fire Ball Trap
+I:3:60:5:5:8:3d10:B
+D:You are suddenly in the centre of a raging inferno!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:87:Plasma Ball Trap
+I:8:60:5:8:20:12d18:B
+D:You are engulfed in plasma!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:88:Water Ball Trap
+I:5:60:5:6:15:8d12:B
+D:A whirlpool engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:89:Light Ball Trap
+I:5:60:5:6:15:8d12:B
+D:A massive flash of light erupts around you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:90:Darkness Ball Trap
+I:5:60:5:6:15:8d12:B
+D:A large patch of darkness erupts around you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:91:Shards Ball Trap
+I:8:60:5:8:20:12d18:B
+D:A violent blast of crystal shards hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:92:Sound Ball Trap
+I:8:60:5:8:20:12d18:B
+D:BOOM! Your eardrums nearly explode!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:93:Confusion Ball Trap
+I:5:60:5:6:15:8d12:B
+D:You are enveloped in a cloud of confusion gas!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:94:Force Ball Trap
+I:8:60:5:8:20:12d18:B
+D:A violent blast of pure force smashes down around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:95:Inertia Ball Trap
+I:8:60:5:8:20:12d18:B
+D:Suddenly, your entire body feels like lead!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:96:Mana Ball Trap
+I:10:60:5:10:30:16d20:B
+D:You are hit by a blast of pure magic!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:97:Ice Ball Trap
+I:5:60:5:6:15:8d12:B
+D:A massive blast of ice crystals engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:98:Chaos Ball Trap
+I:8:60:5:8:20:12d18:B
+D:A violent blast of raw chaos engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:99:Nether Ball Trap
+I:10:60:5:10:30:16d20:g
+D:A blast of energy from the netherworld engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+# N:type:name
+# I:diff:prob:another:pval:minlevel:color
+# D:description
+
+N:100:Disenchantment Ball Trap
+I:10:60:5:10:30:16d20:B
+D:You are hit by a blast of pure anti-magic!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:101:Nexus Ball Trap
+I:8:60:5:8:20:12d18:B
+D:A ball of nexus hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:102:Time Ball Trap
+I:10:60:5:10:30:16d20:B
+D:Suddenly, several years pass by in a second!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:103:Gravity Ball Trap
+I:8:60:5:8:20:12d18:B
+D:You suddenly feel gravity warp violently around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:110:Arrow Trap
+I:2:100:0:5:2:0d0:R
+D:An arrow shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:111:Bolt Trap
+I:2:100:0:5:5:0d0:R
+D:A bolt shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:112:Seeker Arrow Trap
+I:2:100:0:6:10:0d0:R
+D:A seeker arrow shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:113:Seeker Bolt Trap
+I:2:100:0:6:12:0d0:R
+D:A seeker bolt shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:114:Poison Arrow Trap
+I:2:100:0:5:4:0d0:R
+D:A poisoned arrow shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:115:Poison Bolt Trap
+I:2:100:0:6:6:0d0:R
+D:A poisoned bolt shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:116:Poison Seeker Arrow Trap
+I:2:100:0:7:12:0d0:R
+D:A poisoned seeker arrow shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:117:Poison Seeker Bolt Trap
+I:2:100:0:7:15:0d0:R
+D:A poisoned seeker bolt shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:118:Broken Dagger Trap
+I:2:100:0:5:2:0d0:R
+D:An broken dagger shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:119:Dagger Trap
+I:2:100:0:5:5:0d0:R
+D:A dagger shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:120:Poison Broken Dagger Trap
+I:2:100:0:5:4:0d0:R
+D:A poisoned broken dagger shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:121:Poison Dagger Trap
+I:2:100:0:6:6:0d0:R
+D:A poisoned dagger shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+#
+# multiple arrows/daggers traps
+#
+
+N:122:Arrows Trap
+I:4:100:0:7:16:0d0:R
+D:Some arrows shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:123:Bolts Trap
+I:4:100:0:7:18:0d0:R
+D:Some bolts shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:124:Seeker Arrow Trap
+I:5:100:0:8:20:0d0:R
+D:Some seeker arrows shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:125:Seeker Bolt Trap
+I:5:100:0:8:24:0d0:R
+D:Some seeker bolts shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:126:Poison Arrows Trap
+I:5:100:0:8:18:0d0:R
+D:Some poisoned arrows shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:127:Poison Bolt Trap
+I:6:100:0:8:20:0d0:R
+D:Some poisoned bolts shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:128:Poison Seeker Arrows Trap
+I:7:100:0:9:27:0d0:R
+D:Some poisoned seeker arrows shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:129:Poison Seeker Bolts Trap
+I:9:100:0:9:30:0d0:R
+D:Some poisoned seeker bolts shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:130:Broken Daggers Trap
+I:4:100:0:6:12:0d0:R
+D:Some broken daggers shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:131:Dagger Trap
+I:4:100:0:6:15:0d0:R
+D:Some daggers shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:132:Poison Broken Daggers Trap
+I:5:100:0:7:18:0d0:R
+D:Some poisoned broken daggers shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:133:Poison Daggers Trap
+I:6:100:0:7:23:0d0:R
+D:Some poisoned daggers shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:140:Trap of Drop Item
+I:3:50:0:2:5:0d0:y
+D:A sudden sound startles you and you drop something!
+F:FLOOR | CHEST | DOOR
+
+N:141:Trap of Drop Items
+I:5:50:0:5:12:0d0:y
+D:A sudden sound startles you and you drop several things!
+F:FLOOR | CHEST | DOOR
+
+N:142:Trap of Drop Everything
+I:8:50:0:8:20:0d0:y
+D:A sudden sound startles you and you drop everything!
+F:FLOOR | CHEST | DOOR
+
+#-SC-
+N:150:Trap of Femininity
+I:4:30:5:0:10:2d8:r
+D:You feel like a new woman!
+F:FLOOR | CHEST | DOOR
+
+N:151:Trap of Masculinity
+I:4:30:5:0:10:2d8:r
+D:You feel like a new man!
+F:FLOOR | CHEST | DOOR
+
+N:152:Trap of Neutrality
+I:4:30:5:0:10:2d8:r
+D:You feel like a new woman... erm, a new man... er, WHAT did you say???
+F:FLOOR | CHEST | DOOR
+
+N:153:Trap of Aging
+I:5:50:5:0:15:1d8:r
+D:You suddenly age very fast!
+F:CHEST | DOOR
+
+N:154:Trap of Growing
+I:3:75:5:0:5:1d8:r
+D:You begin to grow!
+F:FLOOR | CHEST | DOOR
+
+N:155:Trap of Shrinking
+I:3:75:5:0:5:1d8:r
+D:You begin to shrink!
+F:FLOOR | CHEST | DOOR
+
+#N:156: UNUSED
+
+#N:157: UNUSED
+
+N:158:Trap of Divine Anger
+I:6:100:5:0:15:0d0:G
+D:A voice booms out "Have a care, mortal!"
+F:FLOOR | CHEST | DOOR
+
+N:159:Trap of Divine Wrath
+I:9:50:5:0:30:0d0:G
+D:A voice booms out "Sacrilege!"
+F:FLOOR | CHEST | DOOR
+
+N:160:Hallucination Trap
+I:3:100:10:0:4:0d0:r
+D:Your vision is clouded by a blast of kaleidoscopic light!
+F:FLOOR | CHEST | DOOR
+
+# Bolt traps
+N:161:Greater Magic Missile Trap
+I:6:80:5:6:75:25d20:g
+D:A greater magic missile hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+#N:162:Foulness Trap
+#I:6:80:5:6:15:10d12:g
+#D:You feel foul!
+#F:FLOOR | CHEST | DOOR | LEVEL3
+
+#N:163:Trap of Death Ray
+#I:8:80:5:9:25:15d16:g
+#D:A Ray of Death hits you!
+#F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:164:Trap of Holy Fire
+I:6:80:5:6:15:10d12:g
+D:Holy fire rises around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:165:Trap of Hell Fire
+I:6:80:5:6:15:10d12:g
+D:Hellfire rises around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:166:Psi Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:Your mind is suddenly blasted!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:167:Psi Drain Trap
+I:6:80:5:6:15:8d10:r
+D:You suddenly can't think clearly any more...
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+# Ball Traps
+
+### this one *ought* to be a Nuke Ball trap, not plasma ball, as trap 87
+### is also plasma ball. I've put the description right in advance.
+
+#N:168:Plasma Ball Trap
+#I:8:60:5:8:20:12d18:B
+#D:A blast of radiation engulfs you!
+#F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:169:Psi Ball Trap
+I:8:60:5:8:20:12d18:B
+D:Your brain is suddenly blasted!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+# Useful traps
+
+N:170:Acquirement Trap
+I:1:40:5:5:18:0d0:v
+D:Whoa!
+F:FLOOR | DOOR
+
+# More bolt traps
+
+N:171:Greater Lightning Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:You are jolted with electricity!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:172:Greater Poison Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:A blast of deadly poison gas hits you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:173:Greater Acid Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:A jet of acid shoots out at you! It burns severely!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:174:Greater Cold Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:You are suddenly extremely cold!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:175:Greater Fire Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:You are suddenly extremely hot!
+F:FLOOR | CHEST | DOOR | LEVEL1
diff --git a/lib/edit/trolls.map b/lib/edit/trolls.map
new file mode 100644
index 00000000..e5d104fd
--- /dev/null
+++ b/lib/edit/trolls.map
@@ -0,0 +1,58 @@
+# Permanent wall
+F:X:63:3
+
+# up stairs
+F:<:6:3
+
+# Floor with tree
+F:T:96:3
+
+# Floor with tree(marked)
+F:H:96:1027
+
+# Floor with dirt
+F:.:88:3
+
+# Floor with grass
+F:;:89:3
+
+# Floor with forest troll
+F:f:89:3:297:0:0:0:0:0:0:2
+
+# Floor with stone troll
+F:s:89:3:401:0:0:0:0:0:0:2
+
+# Floor with algroth
+F:a:89:3:424:0:0:0:0:0:0:2
+
+# Floor with Bert
+F:b:89:3:493:0:0:0:0:0:0:2
+
+# Floor with Bill
+F:i:89:3:494:0:0:0:0:0:0:2
+
+# Floor with a Dwarven skeleton
+F:k:89:8:0:396
+
+# Marker
+F:,:172:6
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X..HTTTTTTTTTTTTTTTTTTTTTTTX
+D:XH...;TTTTTTTTTTTTTTTTTTTTTX
+D:XTTT;;HTTTTTTTTTTTTTa.TTTTTX
+D:XTTH.k...TTTHHkTHTs.fTTTTTTX
+D:XTTTT;..f.TT.;...HTTTTaTTTTX
+D:XTTTTTHT...;......TTT..HTTTX
+D:XTTTTTTT;;.k..;k.HH.i.TTTTTX
+D:XTTTTTTH.HTHTT..TH.,.HTTTTTX
+D:XTTTTT;THTTTTTHTH.bTTTTTTTTX
+D:XTTT.f.TTTTTTTaTTs;TTTTTTTTX
+D:XTTs..TTTTTTT...fHTTTTTTTTTX
+D:XTTTas.TTTTTTTTTTTTTTTTTTTTX
+D:XTTTTTTTTTTTTTTTTTTTTTTTTTTX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:3
diff --git a/lib/edit/v_info.txt b/lib/edit/v_info.txt
new file mode 100644
index 00000000..fb4a4d20
--- /dev/null
+++ b/lib/edit/v_info.txt
@@ -0,0 +1,2287 @@
+# File: v_info.txt
+
+
+# This file is used to initialize the "lib/raw/v_info.raw" file, which is
+# used to initialize the "vault template" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/v_info.raw" file.
+
+# Note that the "spacing" in the "description" lines is very important!
+
+
+# New vault types added for Zangband -TY
+
+# Quest vaults added - rr9
+
+# Version stamp (required)
+
+V:2.0.0
+
+
+### Simple Vaults (type 7) -- maximum size 44x22 ###
+
+
+N:0:Lesser vault (round)
+X:7:5:12:20
+D: %%%%%%
+D: %%%..##..%%%
+D: %%....####....%%
+D: %......#**#......%
+D:%...,.##+##+##.,...%
+D:%.,.,.#*#*&#*#.,.,.%
+D:%.,.,.#*#&*#*#.,.,.%
+D:%...,.##+##+##.,...%
+D: %......#**#......%
+D: %%....####....%%
+D: %%%..##..%%%
+D: %%%%%%
+
+
+N:1:Lesser vault (octagon)
+X:7:5:14:20
+D: %%%%%%%%%%%%%%
+D: %%.##########.%%
+D: %%..#..,,,,..#..%%
+D:%%,..#.,####,.#..,%%
+D:%....#.,#**#,.#....%
+D:%.###+,##&&##,+###.%
+D:%.#..,,#*&**#,,..#.%
+D:%.#..,,#**&*#,,..#.%
+D:%.###+,##&&##,+###.%
+D:%....#.,#**#,.#....%
+D:%%,..#.,####,.#..,%%
+D: %%..#..,,,,..#..%%
+D: %%.##########.%%
+D: %%%%%%%%%%%%%%
+
+
+N:2:Lesser vault (octagon)
+X:7:5:12:20
+D: %%%%%%%%%%%%
+D: %%%%..........%%%%
+D: %...###+##+###...%
+D:%%...#,,#,,#,,#...%%
+D:%.###+##+##+##+###.%
+D:%.#,,#&&#**#&&#,,#.%
+D:%.#,,#&&#**#&&#,,#.%
+D:%.###+##+##+##+###.%
+D:%%...#,,#,,#,,#...%%
+D: %...###+##+###...%
+D: %%%%..........%%%%
+D: %%%%%%%%%%%%
+
+
+N:3:Lesser vault (square)
+X:7:5:12:20
+D:%%%%%%%%%%%%%%%%%%%%
+D:%*.......&........*%
+D:%.################.%
+D:%.#,.,.,.,.,.,.,.#.%
+D:%.#.############,#.%
+D:%.#,+,&&+**#&*,#.#&%
+D:%&#.#,*&#**+&&,+,#.%
+D:%.#,############.#.%
+D:%.#.,.,.,.,.,.,.,#.%
+D:%.################.%
+D:%*........&.......*%
+D:%%%%%%%%%%%%%%%%%%%%
+
+
+N:4:Lesser vault (diagonal)
+X:7:5:12:20
+D:%%%%%%%%%%%%%%%%%
+D:%,,,##,,,,##....%%
+D:%,,,,##,,,,##....%%
+D:%#,,,,##,,,,##....%%
+D:%##,,,,##,,,,##....%
+D:%.##,,,,,,,,,,#+...%
+D:%..#+,,,,,,,,,,##..%
+D:%...##,,,,##,,,,##.%
+D:%%...##,,,,##,,,,##%
+D: %%...##,,,,##,,,,#%
+D: %%...##,,,,##,,,,%
+D: %%%%%%%%%%%%%%%%%
+
+
+N:5:Lesser vault (diagonal)
+X:7:5:12:20
+D: %%%%%%%%%%%%%%%%%
+D: %%....##,,,,##,,,%
+D: %%....##,,,,##,,,,%
+D:%%....##,,,,##,,,,#%
+D:%....##,,,,##,,,,##%
+D:%...+#,,,,,,,,,,##.%
+D:%..##,,,,,,,,,,+#..%
+D:%.##,,,,##,,,,##...%
+D:%##,,,,##,,,,##...%%
+D:%#,,,,##,,,,##...%%
+D:%,,,,##,,,,##...%%
+D:%%%%%%%%%%%%%%%%%
+
+
+N:6:Lesser vault (square)
+X:7:5:12:20
+D:%%%%%%%%%%%%%%%%%%%%
+D:%,################,%
+D:%^#.*...&..,....,#^%
+D:%^#...,......&...#^%
+D:%^#######++#######^%
+D:%^+.,..&+,*+*....+^%
+D:%^+..*.,+.&+.,.&.+^%
+D:%^#######++#######^%
+D:%^#....,.,.....,.#^%
+D:%^#..&......*....#^%
+D:%,################,%
+D:%%%%%%%%%%%%%%%%%%%%
+
+N:7:Lesser vault (spiral)
+X:7:5:19:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.+################.%
+D:%.#^#*&..,.......*#.%
+D:%.#.#.###########.#.%
+D:%.#.#.#*.,.....*#.#.%
+D:%.#.#.#.#######.#.#.%
+D:%.#.#.#.#,...*#.#.#.%
+D:%.#.#.#.#,###.#.#.#.%
+D:%.#,#,#,#,,*#,#,#,#.%
+D:%.#.#.#.###,#.#.#.#.%
+D:%.#.#.#*.,.*#.#.#.#.%
+D:%.#.#.#######.#.#.#.%
+D:%.#.#*...,...*#.#.#.%
+D:%.#.###########.#.#.%
+D:%.#*.....,....&*#^#.%
+D:%.################+.%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+N:8:Lesser vault (layers)
+X:7:5:21:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.########+########.%
+D:%.#.......,.......#.%
+D:%.#.#############.#.%
+D:%.#.#....+.#*...#.#.%
+D:%.#.#.####+####.#.#.%
+D:%.#.#.#...&...#.#.#.%
+D:%.#.#.#.#####.#.#.#.%
+D:%.#.#.#.#*,*#.#.#.#.%
+D:%.#^#^#^#,,,#^#^#.#.%
+D:%.#.#.#.#*,*#.#.#.#.%
+D:%.#.#.#.##+##.#.#.#.%
+D:%.#.#.#..+,#*.#.#.#.%
+D:%.#.#.#########.#.#.%
+D:%.#.#.....,.....#.#.%
+D:%.#.######+######.#.%
+D:%.#.....*#.+......#.%
+D:%.#################.%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+N:9:Lesser vault (bank)
+X:7:7:9:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.&XXXXXXXXXXXXXXXXX%
+D:%&&XXXXX+XXX+XX*,XXX%
+D:%&&+###########,*XXX%
+D:%.&XXX+XXX+XXX+XXXXX%
+D:%.&XXXXXXXXXXXXXXXXX%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+N:10:Lesser vault (mine)
+X:7:7:9:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.XXXXXXXXXXXXXXXXXX%
+D:%.XX##XXXX*,,XX,*,XX%
+D:%.*#XX,*##X*#XX***XX%
+D:%.XXXX*,XXXXX##,*,XX%
+D:%.XXXXXXXXXXXXXXXXXX%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+N:11:Lesser vault (maze)
+X:7:5:22:22
+D:%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXX............%
+D:%.XX,,.XXXXXXXXXXXXX.%
+D:%.XXXX*...&........X.%
+D:%.X.,,XXXXXXXXXXXX*X.%
+D:%.X.XXX.....*......X.%
+D:%.X..XX.XXXXXXXXXX.X.%
+D:%.XX.X.&.XX.X.....*X.%
+D:%.XX.XXX...*X,XXXX.^.%
+D:%.X.XX,XXXX.XXXX,XXX.%
+D:%.X.XX.....*..&.*X,X.%
+D:%.X.,XXXXXXXXXXX.X,X.%
+D:%.XXXX....*..X,X.X,X.%
+D:%.X....XXX.X.X.X.X.X.%
+D:%.X.XXXX,X.X.&.X.X.X.%
+D:%.X.X...*X.XXXXX.X.X.%
+D:%.X.X,XX&X....&..X.X.%
+D:%.X.XXXX.XXXXXXXXX.X.%
+D:%.X.....*...X*X*X..X.%
+D:%.XX^XXXXXX..X*X,XXX.%
+D:%........XXXXXXXXXXX.%
+D:%%%%%%%%%%%%%%%%%%%%%%
+
+N:12:Lesser vault (prison)
+X:7:10:16:35
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.+..&..+..&..+..&..+..&..+..&..+.%
+D:%.###.#####.#####.#####.#####.###.%
+D:% #,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%.#,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%.#,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%.#,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%.#,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%&+..&..+..&..+..&..+..&..+..&..+.%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:13:Lesser vault (camp)
+X:7:10:15:37
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...................................%
+D:%.####^^^^^^^^^^^^^^^^^^^^^^^^^####.%
+D:%.#,&############+++############&,#.%
+D:%.###+.........................+###.%
+D:%.^#....##+#.....#+#....##+#....#^..%
+D:%.^+....#,,#.....#,#....#,,#....+^..%
+D:%.^+....+&&+..&..+&+..&.+&&+....+^..%
+D:%.^+....#,,#.....#,#....#,,#....+^..%
+D:%.^#....#+##.....#+#....#+##....#^..%
+D:%.###+.........................+###.%
+D:%.#,&############+++############&,#.%
+D:%.####^^^^^^^^^^^^^^^^^^^^^^^^^####.%
+D:%...................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:14:Lesser vault (serpent)
+X:7:10:17:32
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..............................%
+D:%..##########################..%
+D:%.##...#.^.#.^.#...#...#.,.###.%
+D:%.#..#.*.#...#...#.^.#...#...+.%
+D:%.#.##########################.%
+D:%.#..#..#.,.#.^.#.^.#.*.#...##.%
+D:%.##^#.#..#...#...#...#...#..#.%
+D:%.#..#.####################..#.%
+D:%.#,##.&+,,,,,,,,,,,,,,,,,#*##.%
+D:%.#..##&+,,,,,,,,,,,,,,,,,#..#.%
+D:%.##^#######################.#.%
+D:%.#..#...#...#...#...#.^.#...#.%
+D:%.##...#.^.#.,.#.*.#.^.#...###.%
+D:%..##########################..%
+D:%..............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:15:Lesser vault (zelazny)
+X:7:5:18:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%.###############.%
+D:%.+,,,,,,,,,,,,,#.%
+D:%.###########,,,#.%
+D:%.#,,,,+..##,,,##.%
+D:%.#,,,##.##,,,##..%
+D:%.#,*##.##,,,##...%
+D:%.#&##.##,,,##.##.%
+D:%.###.##,,,##.###.%
+D:%.##.##,,,##.##&#.%
+D:%...##,,,##.##*,#.%
+D:%..##,,,##..+,,,#.%
+D:%.##,,,##########.%
+D:%.#,,,,,,,,,,,,,+.%
+D:%.###############.%
+D:%.................%
+D:%%%%%%%%%%%%%%%%%%%
+
+N:16:Lesser vault (overlap)
+X:7:5:12:18
+D:%%%%%%%%%%%%%%%%%%
+D:%................%
+D:%.##########.....%
+D:%.#,,,^^^^^+&....%
+D:%.#,,,##########.%
+D:%.#,,,#****+,,,#.%
+D:%.#,,,+****#,,,#.%
+D:%.##########,,,#.%
+D:%....&+^^^^^,,,#.%
+D:%.....##########.%
+D:%................%
+D:%%%%%%%%%%%%%%%%%%
+
+N:17:Lesser vault (celtic)
+X:7:5:17:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.#####..#+#..#####.%
+D:%.#&,##.##&##.##,&#.%
+D:%.#+##..#*^*#..##+#.%
+D:%.#....###.###....#.%
+D:%...####..&..####...%
+D:%.###*##.#+#.##*###.%
+D:%.+&.^..&+*+&..^.&+.%
+D:%.###*##.#+#.##*###.%
+D:%...####..&..####...%
+D:%.#....###.###....#.%
+D:%.#+##..#*^*#..##+#.%
+D:%.#&,##.##&##.##,&#.%
+D:%.#####..#+#..#####.%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+
+N:18:Lesser vault (mirror)
+X:7:5:17:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%.+#############+.%
+D:%.##&,,,,#,,,,&##.%
+D:%.#&#,,,###,,,#&#.%
+D:%.#,,,,,,#,,,,,,#.%
+D:%.##,,,,,#,,,,,##.%
+D:%.###,,,^#^,,,###.%
+D:%.#######+#######.%
+D:%.###,,,^#^,,,###.%
+D:%.##,,,,,#,,,,,##.%
+D:%.#,,,,,,#,,,,,,#.%
+D:%.#&#,,,###,,,#&#.%
+D:%.##&,,,,#,,,,&##.%
+D:%.+#############+.%
+D:%.................%
+D:%%%%%%%%%%%%%%%%%%%
+
+
+N:19:Lesser vault (tower)
+X:7:5:18:15
+D:%%%%%%%%%%%%%%%
+D:%.............%
+D:%..XXX...XXX..%
+D:%..X&XXXXX&X..%
+D:%..XX*****XX..%
+D:%...XX***XX...%
+D:%....X#+#X....%
+D:%....X&&&X....%
+D:%....X^^^X....%
+D:%....X#+#X....%
+D:%....X,,,X....%
+D:%....X^^^X....%
+D:%...XX+#+XX...%
+D:%..XX,&,&,XX..%
+D:%..X^^^*^^^X..%
+D:%.##+#####+##.%
+D:%...&.....&...%
+D:%%%%%%%%%%%%%%%
+
+
+### Greater vaults (type 8) -- maximum size 66x44 ###
+
+N:20:Greater vault (huge)
+X:8:20:17:39
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%+&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8#&#8#&#8#&#88888888888#8#&#8#&#8#&X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#&+%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:21:Greater vault (large)
+X:8:35:18:40
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X,#,#,#,#,#,#,#,#*@@*#,#,#,#,#,#,#,#,X%
+D:%X+XXXXXXXXXXXXXXXX##XXXXXXXXXXXXXXXX+X%
+D:%X.,..,.X&.&.,*XX******XX*,.&.&X.,...,#%
+D:%X..,.^^X....,XX***@@***XX,....X^^..,.#%
+D:%XXXXXX+X^&.&XX***@##@***XX&.&^X+XXXXXX%
+D:%X,.&.^^X+XXXX***@#XX#@***XXXX+X^^.,..X%
+D:%X..,&,.X^^^@X**@#X88X#@**#@^^^X.,..&,X%
+D:%X.,....X^^^@#**@#X88X#@**X@^^^X.&.,..X%
+D:%X...,^^X+XXXX***@#XX#@***XXXX+X^^..,.X%
+D:%XXXXXX+X^&.&XX***@##@***XX&.&^X+XXXXXX%
+D:%#.,..^^X.....XX***@@***XX,....X^^.,..X%
+D:%#...,..X&.&.,*XX******XX*,.&.&X..,..,X%
+D:%X+XXXXXXXXXXXXXXXX##XXXXXXXXXXXXXXXX+X%
+D:%X,#,#,#,#,#,#,#,#*@@*#,#,#,#,#,#,#,#,X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:22:Greater vault (butterfly)
+X:8:25:18:40
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X*9..&XX***++^^^^^^^^^^^^++***XX&..*9X%
+D:%X9..&XX,,,,,XX^^^^^^^^^^XX,,,,,#X&..*X%
+D:%X..&#X.....,.XX^^^^^^^^XX..&....XX&..X%
+D:%X.&XX..,.&....XX^^^^^^XX..,...&..XX&.X%
+D:%X&XX..*...&.^..XX^^^^XX..*....,..,XX&X%
+D:%XXXX+XXXXXXXXXXXXX++XXXXXXXXXXXXX+XXXX%
+D:%+....,.,.X&&&&***+99+***&&&&X,.,.,...+%
+D:%+...,.,.,X&&&&***+99+***&&&&X.,.,....+%
+D:%XXXX+XXXXXXXXXXXXX++XXXXXXXXXXXXX+XXXX%
+D:%X&XX..*....&...XX^^^^XX...*...&,..#X&X%
+D:%X.&XX..&.^....XX^^^^^^XX....&....XX&.X%
+D:%X..&XX....&..XX^^^^^^^^XX..,..*.XX&..X%
+D:%X*..&#X,,,,,XX^^^^^^^^^^XX,,,,,XX&..9X%
+D:%X9*..&XX***++^^^^^^^^^^^^++***XX&..*9X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+N:23:Greater vault (castle)
+X:8:35:27:27
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.........................%
+D:%..XXXXX..XXX+XXX..XXXXX..%
+D:%..X,,,X..X.,,,.X..X,,,X..%
+D:%..X,,*XXXX.&&&.XXXX*,,X..%
+D:%..XXXX+....&&&....+XXXX..%
+D:%.....X.....,,,.....X.....%
+D:%.....X..,XXX+XXX,..X.....%
+D:%.....X.XXX^^^^^XXX.X.....%
+D:%.&...X.X,,*****,,X.X..&..%
+D:%....XX.X,XXX+XXX,X.XX....%
+D:%....X..X,X@@@@@X,X..X....%
+D:%....X..X,X@999@X,X..X....%
+D:%....X..X,X@989@X,X..X....%
+D:%....X..X,X@999@X,X..X....%
+D:%....X..X,X@@@@@X,X..X....%
+D:%....XX.X,XXX+XXX,X.XX....%
+D:%.....X.X,,*****,,X.X.....%
+D:%.....X.XXX^^^^^XXX.X.....%
+D:%.....X..,XXX+XXX,..X.....%
+D:%.....X.....&&&.....X.....%
+D:%..XXXX+....&&&....+XXXX..%
+D:%..X,,*XXXX.&&&.XXXX*,,X..%
+D:%..X,,,X..X.,,,.X..X,,,X..%
+D:%..XXXXX..XX^^^XX..XXXXX..%
+D:%.........................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:24:Greater vault (chambers)
+X:8:25:15:40
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%&+.^..^..^..^..^..^..^..^..^..^..^..+&%
+D:%+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+%
+D:%.X.&.^,X&^&^X****+^*^@^X.*.&..X..*.,X.%
+D:%^X.,.&^+^&^@X^^^^X@^*^*X....*^+.^...X^%
+D:%.X*..,.XXX+XXXX+XXXX+XXX.&.^..X..&,.X.%
+D:%^X..^.*X*..^&&@@*X,,,,,XXXX+XXX,....X^%
+D:%.XX+XXXXXXXXXXXXXX,*8*,X,,,,,,XXX+XXX.%
+D:%^X*&X.&,*.X,*&^*^X,,,,,X,,,,,,X....,X^%
+D:%.X&,+....*+,*&^*^XXXXXXXXXX+XXX.,...+.%
+D:%^X.,X.*.&.X,*&^*^+.,.&.^*.&^&^X.....X^%
+D:%.X^*X.,..,X,*&^*^X*.^*.,..&&&^X,..,.X.%
+D:%+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+%
+D:%&+..^..^..^..^..^..^..^..^..^..^..^.+&%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:25:Greater vault (Sierpinski)
+X:8:35:28:39
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..................X..................%
+D:%.................XXX.................%
+D:%.................X8X.................%
+D:%.....&..........XX+XX................%
+D:%...............XX999XX........&......%
+D:%......&........X@X9X@X...............%
+D:%..............XXXX+XXXX..............%
+D:%.............XX*@*@*@*XX....&........%
+D:%.............X@X*@*@*X@X.............%
+D:%............XXXX**@**XXXX............%
+D:%..........&XX,,,X***X,,,XX&..........%
+D:%..........XX,X@X,X,X,X@X,XX..........%
+D:%.........XXXXX+XXXXXXX+XXXXX.........%
+D:%........XX+,,,,,,,,,,,,,,,+XX........%
+D:%........X@X,,,,,,,,,,,,,,,X@X........%
+D:%.......XX+XX,,,,,,,,,,,,,XX+XX.......%
+D:%......XX,,,XX,,,,,,,,,,,XX,,,XX......%
+D:%......X,X,X,X,,,,,,,,,,,X,X,X,X......%
+D:%.....XXXX+XXXX,,,,,,,,,XXXX+XXXX.....%
+D:%....XX*******XX,,,,,,,XX*******XX....%
+D:%....X,X*****X,X,,,,,,,X,X*****X,X....%
+D:%...XXXX*****XXXX,,,,,XXXX*****XXXX...%
+D:%..XX,,,X***X,,,XX,,,XX,,,X***X,,,XX..%
+D:%..X,X,X,X*X,X,X,X,,,X,X,X,X*X,X,X,X..%
+D:%.XXXXXXXX+XXXXXXXXXXXXXXXXX+XXXXXXXX.%
+D:%.........&.................&.........%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:26:Greater vault (swastika)
+X:8:25:23:29
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....^^^^^^^^^^^^^^^^^^^^^..%
+D:%^^^^^###################^..%
+D:%^####+..#..............#^..%
+D:%^#.....####.XXXXXXXXXX.#^..%
+D:%^#...&.#,&..X,,,@,@,9X.#^..%
+D:%^#.XXX.####.X,XXXXXXXX.#^..%
+D:%^#.X9X..&,#.X,X......&.#^^^%
+D:%^#.X,X.####.X,X.#######+##^%
+D:%^#.X@X.....^X^X^.........#^%
+D:%^#.X@XXXXXXX+*+XXXXXXXXX.#^%
+D:%^#.X,,,,,,,^*X*^,,,,,,,X.#^%
+D:%^#.XXXXXXXXX+*+XXXXXXX@X.#^%
+D:%^#.........^X^X^.....X@X.#^%
+D:%^##+#######.X,X.####.X,X.#^%
+D:%^^^#.&......X,X.#,&..X9X.#^%
+D:%..^#.XXXXXXXX,X.####.XXX.#^%
+D:%..^#.X9,@,@,,,X..&,#.&...#^%
+D:%..^#.XXXXXXXXXX.####.....#^%
+D:%..^#..............#..+####^%
+D:%..^###################^^^^^%
+D:%..^^^^^^^^^^^^^^^^^^^^^....%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:27:Greater vault (great spiral)
+X:8:40:39:39
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.....................................%
+D:%.X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X@X.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^^+.%
+D:%.X.X^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X.X.X,..,..,..,..,..,..,..,..,..,.X.%
+D:%.X.X^X.XXXXXXXXXXXXXXXXXXXXXXXXXXX.X.%
+D:%.X.X.X.X......&...&...&...&...@..X,X.%
+D:%.X.X^X,X@XXXXXXXXXXXXXXXXXXXXXXX.X.X.%
+D:%.X.X.X.X.X&.........8.........&X*X.X.%
+D:%.X.X^X.X.X.XXXXXXXXXXXXXXXXXXX.X.X,X.%
+D:%.X.X.X,X.X.X.^.^.^.^.^.^.^.^.X.X.X.X.%
+D:%.X.X^X.X.X.X^XXXXXXXXXXXXXXX*X.X*X.X.%
+D:%.X.X.X.X&X.X.X,..,..,..,..,X.X.X.X,X.%
+D:%.X.X^X,X.X.X^X.XXXXXXXXXXX.X*X.X.X.X.%
+D:%.X.X.X.X.X.X.X.X..&..&..9X.X.X.X*X.X.%
+D:%.X.X^X.X&X.X^X,X9XXXXXXX.X,X*X.X.X,X.%
+D:%.X.X.X,X.X.X.X.X&X@@..&X.X.X.X.X.X.X.%
+D:%.X.X^X.X.X9X^X.X*X+XXX.X&X.X*X.X*X.X.%
+D:%.X.X.X.X.X.X.X,X^+8+^X.X.X,X.X.X.X,X.%
+D:%.X9X^X,X.X.X^X.XXX+X^X.X*X.X*X.X.X.X.%
+D:%.X.X.X.X&X.X.X.,.,,X.X9X.X.X.X.X*X.X.%
+D:%.X.X^X.X.X.X^XXXXXXX^X.X*X,X*X9X.X,X.%
+D:%.X.X.X,X.X.X.^.^.^.^.X.X.X.X.X.X.X.X.%
+D:%.X.X^X.X.X.XXXXXXXXXXX.X^X.X^X.X*X.X.%
+D:%.X.X.X.X8X&.....9.....&X.X,X.X.X.X,X.%
+D:%.X.X^X,X.XXXXXXXXXXXXXXX^X.X^X.X.X.X.%
+D:%.X.X.X.X..&....8......@..X.X.X.X*X.X.%
+D:%.X.X^X.XXXXXXXXXXXXXXXXXXX,X^X.X.X,X.%
+D:%.X.X.X,..,..,..,..,..,..,..X.X.X.X.X.%
+D:%.X.X^XXXXXXXXXXXXXXXXXXXXXXX^X.X*X.X.%
+D:%.X.X.*.^.*.*.*.*.*.*.*.*.*.^.X.X.X,X.%
+D:%.X.XXXXXXXXXXXXXXXXXXXXXXXXXXX.X.X.X.%
+D:%.X&.............9.............&X*X.X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.X,X.%
+D:%.+^^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.X,X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X.%
+D:%.....................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:28:Greater vault (greater castle)
+X:8:40:25:51
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.................................................%
+D:%...XXXXXX...............................XXXXXX...%
+D:%..XX,,,,XX.............................XX,,,,XX..%
+D:%.XX,*99*,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,*99*,XX.%
+D:%.XX,*99*,+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+,*99*,XX.%
+D:%..XX,,,,XXXXXXXXXXXXXXX+X+XXXXXXXXXXXXXXX,,,,XX..%
+D:%...XX++XX...............X...............XX++XX...%
+D:%....X^^X.............XXXXXXX.............X^^X....%
+D:%....X^^X.X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X.X^^X....%
+D:%....X^^X.X^^^XXXXXXXXXXXXXXXXXXXXXXX^^^X.X^^X....%
+D:%....X^^+&X^^XX@.+***************+.@XX^^X&+^^X....%
+D:%....X^^XXX^^+@.@X*9999988899999*X@.@+^^XXX^^X....%
+D:%....X^^+.X^^XX@.+***************+.@XX^^X.+^^X....%
+D:%....X^^X.X^^^XXXXXXXXXXXXXXXXXXXXXXX^^^X.X^^X....%
+D:%....X^^X.X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X.X^^X....%
+D:%....X^^X............XXXX+XXXX............X^^X....%
+D:%...XX++XX..........XX&.&.&.&XX..........XX++XX...%
+D:%..XX,,,,XXXXXXXXXXXX&.&.&.&.&XXXXXXXXXXXX,,,,XX..%
+D:%.XX,*99*,+********9XXXXX+XXXXX9********+,*99*,XX.%
+D:%.XX,*99*,XXXXXXXXXXX&.&.&.&.&XXXXXXXXXXX,*99*,XX.%
+D:%..XX,,,,XX.........XX&.&.&.&XX.........XX,,,,XX..%
+D:%...XXXXXX...........XXXX+XXXX...........XXXXXX...%
+D:%.................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:29:Lesser vault (x-factor)
+X:8:25:25:26
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%^^^^^^^^^^^^^^^^^^^^^^^^%
+D:%^##########++##########^%
+D:%^#XX,,,,,,,,,,,,,,,,XX#^%
+D:%^#,XX,,,,,,,,,,,,,,XX,#^%
+D:%^#,,XX,,,,,,,,,,,,XX,,#^%
+D:%^#,,,XX,,,,,,,,,,XX,,,#^%
+D:%^#,,,,XX,,,,,,,,XX,,,,#^%
+D:%^#,,,,,XX,,,,,,XX,,,,,#^%
+D:%^#,,,,,,XX,,,,XX,,,,,,#^%
+D:%^#,,,,,,,X+XX+X,,,,,,,#^%
+D:%^+,,,,,,,,X99X,,,,,,,,+^%
+D:%^+,,,,,,,,X99X,,,,,,,,+^%
+D:%^+,,,,,,,,X99X,,,,,,,,+^%
+D:%^#,,,,,,,X+XX+X,,,,,,,#^%
+D:%^#,,,,,,XX,,,,XX,,,,,,#^%
+D:%^#,,,,,XX,,,,,,XX,,,,,#^%
+D:%^#,,,,XX,,,,,,,,XX,,,,#^%
+D:%^#,,,XX,,,,,,,,,,XX,,,#^%
+D:%^#,,XX,,,,,,,,,,,,XX,,#^%
+D:%^#,XX,,,,,,,,,,,,,,XX,#^%
+D:%^#XX,,,,,,,,,,,,,,,,XX#^%
+D:%^##########++##########^%
+D:%^^^^^^^^^^^^^^^^^^^^^^^^%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:30:Greater vault (university)
+X:8:30:29:38
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....................................%
+D:%.##################################.%
+D:%.#*+..&#..,#,#..,#,#..,#,#.,#&+*#*#.%
+D:%.#####.#.###.#.###.#.###.#.##.###+#.%
+D:%.#***#.#.#*..#.#*..#.#*..#.#..#..&#.%
+D:%.#+###+#+###+#+###+#+###+#+##+###+#.%
+D:%.#...+&......................&+...#.%
+D:%.#.###.##########++##########.###.#.%
+D:%.#,#.+.#,,,,,,,,,,,,,,,,,,,,#.#*#,#.%
+D:%.###.#.#,.,..,..,@.,..,..,.,#.#.###.%
+D:%.#,..#.#,..,..,..,..,..,..,,#.+..,#.%
+D:%.#####.#,9&,,,9,,&,,&,,.,,,,#.#####.%
+D:%.+^^^+.+,,,&,,,&,,,9,,&,,&,,+.+^^^+.%
+D:%.+^^^+.+,.,...,...,...,...,,+.+^^^+.%
+D:%.###+#.#,,,,&,,&,,,9,&,,,&,,#.#####.%
+D:%.#*#&#.#,,,&,,,9,&,,&,,,,,9,#.#..,#.%
+D:%.#+#*#.#,.,...,....,....,..,#.#.###.%
+D:%.#.###.#,,,&,,,,&,9,,&,,,&,,#.+.#,#.%
+D:%.#&..+.#,,,,,,,,.,,,,,,,,,,,#.###.#.%
+D:%.#####.##########++##########.+...#.%
+D:%.#&..+&......................&#+###.%
+D:%.#.###+#+###+#+###+#+###+#+##+#...#.%
+D:%.#.+*#.#.#*..#.#*..#.#*..#.#..###,#.%
+D:%.#####.#.###.#.###.#.###.#.##&#*###.%
+D:%.#*+..&#..,#,#..,#,#..,#,#.,#.+,*,#.%
+D:%.##################################.%
+D:%....................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:31:Greater vault (nethack castle (almost))
+X:8:35:19:62
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%............................................................%
+D:%.XXXXXXX............................................XXXXXXX.%
+D:%.X,,9,,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,9,,X.%
+D:%.X,,,,,+.......^....*....^ ..........^.......*...^..+,,,,,X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%......X,.,9,,,,X,,,,,,,,,+,.,.,.,.,.,X,.,.,.+^+,.,.,.X......%
+D:%......X,.9*9,.,X,,,,,,,,,X,.,..,..,.,X,.,.,.X^X,.,.,.X......%
+D:%....&.X.&*@*&,.XXXXXXXXXXX,.,.,9,.,.,XXXXXXXX+XXXXXXXX......%
+D:%......+9*@8@*9.+^^^^^^^^^+,.,,9@9,,.,+^^^^^^^^^^^^^^^+......%
+D:%....&.X.&*@*&,.XXXXXXXXXXX,.,.,9,.,.,XXXXXXXX+XXXXXXXX......%
+D:%......X,.9*9,.,X,,,,,,,,,X,.,.,,,.,.,X.,.,.,X^X.,.,.,X......%
+D:%......X,.,9,,,,X,,,,,,,,,+,.,.,.,.,.,X.,.,.,+^+.,.,.,X......%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X,,,,,+.......^....*....^...........^.......*...^..+,,,,,X.%
+D:%.X,,9,,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,9,,X.%
+D:%.XXXXXXX............................................XXXXXXX.%
+D:%............................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:32:Greater vault (another nethack-style castle)
+X:8:30:18:52
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..................................................%
+D:%.XXXXX......................................XXXXX.%
+D:%.X9,,X......................................X,,9X.%
+D:%.XXX+XXXXXXXXXXXXXXXXXXX++XXXXXXXXXXXXXXXXXXX+XXX.%
+D:%...X^^^^^^^^^^^^^^^^^^^+..+^^^^^^^^^^^^^^^^^^^X...%
+D:%...X^XXXXXXXXXXXXXXXXXXX++XXXXXXXXXXXXXXXXXXX^X...%
+D:%...X^X,,,,,,,,,,,,,,,,,X..X,,,,,,,,,X,,@@@@,X^X...%
+D:%...X^X,,,,,,,,,,,,,,,,,+..+,,,,,,,,,+,,,,998X^X...%
+D:%...X^X,,,,,,,,,,,,,,,,,+..+,,,,,,,,,+,,,,998X^X...%
+D:%...X^X,,,,,,,,,,,,,,,,,X..X,,,,,,,,,X,,@@@@,X^X...%
+D:%...X^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX^X...%
+D:%...X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X...%
+D:%.XXX+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+XXX.%
+D:%.X9,,X......................................X,,9X.%
+D:%.XXXXX......................................XXXXX.%
+D:%..................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:33:Lesser vault (nethack-style tower)
+X:7:5:15:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%...###.###.###...%
+D:%...#&#.#&#.#&#...%
+D:%.###+###+###+###.%
+D:%.#.,.,.,.+.+,,,#.%
+D:%.###+#####.#####.%
+D:%...+*&*&*#.+,#...%
+D:%.###+#####.#####.%
+D:%.#.,.,.,.+.+,,,#.%
+D:%.###+###+###+###.%
+D:%...#&#.#&#.#&#...%
+D:%...###.###.###...%
+D:%.................%
+D:%%%%%%%%%%%%%%%%%%%
+
+
+N:34:Lesser vault (nethack, rooms)
+X:7:5:14:27
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.........................%
+D:%.#+#####################.%
+D:%.#.^.^.^.+^+^...^#,,,,,#.%
+D:%.#^###+###^#####.+,,,,,#.%
+D:%.#.#,,,,,#.#,,,#^#,,,,,#.%
+D:%.#^#,,,,,#^+,,,#+#######.%
+D:%.#.#######.#,,,#.......#.%
+D:%.#^#,,,,,#^#,,,#..&.&..#.%
+D:%.#.#,,,,,#.#####.......#.%
+D:%.#^+,,,,,#^.^.^+..&.&.^+.%
+D:%.#######################.%
+D:%.........................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:35:Lesser vault (nethack city)
+X:7:9:17:33
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...............................%
+D:%.############.....############.%
+D:%.#,,,#,,,#,,#.....#**#,,,#***#.%
+D:%.#,,,#,,,#,,#.....+**#,,,#***#.%
+D:%.#,,,#,,,#,,#.....#**#,,,#&&&#.%
+D:%.#^,,#,,,#+##.....####+###+###.%
+D:%.#+####+##.....................%
+D:%...............................%
+D:%.#+###+###....###+##...........%
+D:%.#^,,#^,,####.#,,,,#.######+##.%
+D:%.#,,,#,,,#**#.#,&&,#.+^^#,,,,#.%
+D:%.#,,,#,,,#*^+.#,&@,#.#^^#,,,,#.%
+D:%.#,,,#,,,#**#.#,,,,#.#**#,,,,#.%
+D:%.############.######.#########.%
+D:%...............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:36:Greater vault (nethack, large city)
+X:8:25:21:54
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....................................................%
+D:%.##################################################.%
+D:%.#................................................#.%
+D:%.#.####################.########..#####.#########.#.%
+D:%.#.#^,,,,^#^****^#^,,^#.#^,,,,^#..#^^^#.#^,,,,,^#.#.%
+D:%.#.#^,,,,^#^****^#^,,^#.#^,,,,^#..+^**#.#^,,,,,^#.#.%
+D:%.#.#^,,,,^#^,,,,^#^^^^#.#^^^^^^#..#^^^#.#^,,,,,^#.#.%
+D:%.#.#^^^^^^#^^^^^^###+##.###+####..#####.#^^^^^^^#.#.%
+D:%.#.#+#########+###......................######+##.#.%
+D:%.#................................................#.%
+D:%.#.###+######+####......###+########..............#.%
+D:%.#.#^^^^^^#^^^^^^######.#^^^^^^^^^^#...###+#####..#.%
+D:%.#.#^,,,,^#^,,,,^#^^^^+.#^,,,,,,,,^#...#^^^^^^^#..#.%
+D:%.#.#^****^#^,,,,^#,,,^#.#^@999999@^#...#^,,,,,^#..#.%
+D:%.#.#^****^#^,,,,^#,,,^#.#^^^^^^^^^^#...#^,,,,,^#..#.%
+D:%.+.####################.############...#########..#.%
+D:%.#................................................#.%
+D:%.##################################################.%
+D:%....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:37:Lesser vault (nethack, tiny castle)
+X:7:5:14:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................................%
+D:%.#####....................#####.%
+D:%.#*,&#....................#&,*#.%
+D:%.###+######################+###.%
+D:%...#,,,,,,,,,,,,,#,,,,,,,,,,#...%
+D:%...+,,,,,,,,,,,,,+,,,,,,,,,,+...%
+D:%...+,,,,,,,,,,,,,+,,,,,,,,,,+...%
+D:%...#,,,,,,,,,,,,,#,,,,,,,,,,#...%
+D:%.###+######################+###.%
+D:%.#*,&#....................#&,*#.%
+D:%.#####....................#####.%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:38:Greater vault (nethack mirror)
+X:8:25:22:41
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................................%
+D:%...............XXXX+XXXX...............%
+D:%...............X**X^X**X...............%
+D:%....XXXXXXXXXXXX**X^X**XXXXXXXXXXXX....%
+D:%....X^+99999999X+XX^XX+X99999999+^X....%
+D:%....X^X9*******X,,X^X,,X*******9X^X....%
+D:%....X^X9*******X,,X^X,,X*******9X^X....%
+D:%.XXXX+XXXXXXXXXXX+X+X+XXXXXXXXXXX+XXXX.%
+D:%.X**X,,,,,,,,,,X,,,,,,,X,,,,,,,,,,X**X.%
+D:%.X*@+,,,,,,,,,,+,,,,8,,X,,,,,,,,,,+@*X.%
+D:%.X*@+,,,,,,,,,,X,,,8,,,+,,,,,,,,,,+@*X.%
+D:%.X**X,,,,,,,,,,X,,,,,,,X,,,,,,,,,,X**X.%
+D:%.XXXX+XXXXXXXXXXX+X+X+XXXXXXXXXXX+XXXX.%
+D:%....X^X9*******X,,X^X,,X*******9X^X....%
+D:%....X^X9*******X,,X^X,,X*******9X^X....%
+D:%....X^+99999999X+XX^XX+X99999999+^X....%
+D:%....XXXXXXXXXXXX**X^X**XXXXXXXXXXXX....%
+D:%...............X**X^X**X...............%
+D:%...............XXXX+XXXX...............%
+D:%.......................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:39:Greater vault (nethack tomb)
+X:8:25:13:57
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................................................%
+D:%..........XXXXX.XXXXX.XXXXX.XXXXX.XXXXX................%
+D:%..........X,,,X.X,,,X.X,,,X.X,,,X.X,,,X................%
+D:%.XXXXXXXXXX,&,XXX,&,XXX,&,XXX,&,XXX,&,XXXXXXXXXXXXXXXX.%
+D:%.X&^&X....^...^...^...^...^...^...^..^..X,,,,,,,,X,,9X.%
+D:%.+^^^+..^...^...^...^...^...^...^...^.@.+,,,,,,,,+,98X.%
+D:%.X&^&X....^...^...^...^...^...^...^.....X,,,,,,,,X,,9X.%
+D:%.XXXXXXXXXX,&,XXX,.,XXX,.,XXX,&,XXX,&,XXXXXXXXXXXXXXXX.%
+D:%..........X,,,X.X,,,X.X,,,X.X,,,X.X,,,X................%
+D:%..........XXXXX.XXXXX.XXXXX.XXXXX.XXXXX................%
+D:%.......................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:40:Greater vault (nethack hell level #1)
+X:8:30:17:55
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.....................................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.XX*XXXXXXXXXX**XXXXXXXXXXXX***********************X.%
+D:%.XX*X,,,,X***X+XX,,,,,,X***XXXXXXXXXXXX^^^^^^^^^^^^X.%
+D:%.XX,X,,,,+***X@^+,,,,,,X***+,,,,,,,,,,X^^^^^^^^^^^^X.%
+D:%.XX&X,,,,XXXXXXXX^^^^^^^^^^X,,,XXXXXXXXXXXXXX^^^^^^X.%
+D:%.XX+X....XXXX.............^X,,,+,,,,,,,,,,,9XXXXX^^X.%
+D:%.+^^^^^^^^^^+^^^^^^^^^^^^^^XXXXX,,,,,,,,,,,9+888+@@X.%
+D:%.XX+X....XXXX.............^X,,,+,,,,,,,,,,,9XXXXX^^X.%
+D:%.XX&X,,,,XXXXXXXX^^^^^^^^^^X,,,XXXXXXXXXXXXXX^^^^^^X.%
+D:%.XX,X,,,,+***X@^+,,,,,,X***+,,,,,,,,,,X^^^^^^^^^^^^X.%
+D:%.XX*X,,,,X***X+XX,,,,,,X***XXXXXXXXXXXX^^^^^^^^^^^^X.%
+D:%.XX*XXXXXXXXXX**XXXXXXXXXXXX***********************X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:41:Greater vault (nethack hell level #2)
+X:8:30:15:54
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....................................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...%
+D:%.+^XX,+^^^^^X^^^^^^^^^^^^^^^^^^^^^X,,,X,@^X*^*+9X...%
+D:%.X^XX,X^XXX,X@XXXXXXXXXXXXXXXXXXX^X,X,X,X^X*X*X9X...%
+D:%.X^XX,X^^^X,X^^^^^^^^^^^^^^^^^^@X^X,X,X,X^X*X*X9X...%
+D:%.X^XXXXXX^X,XXXXXXXXXXXXXXXXXXX^X^X,X,X,X^X*X*X+XXX.%
+D:%.X^^^^^^X^X,X,,,,,,,,,,,,,,,,,X^X^X,X,X,X^X*X*X888X.%
+D:%.X+XXXX^X^X,X,XXXXXXXXXXXXXXX,X^X^X,X,X,X^X*X*X+XXX.%
+D:%.X,XX,X^X^X,X,X,,,,,,,,,,,,,,,X^X^X,X,X,X^X*X*X9X...%
+D:%.X,XX,X^X&X,X,X,XXXXXXXXXXXXXXX^X^X,X,X,X^X*X*X9X...%
+D:%.X,XX,+^^^X,,,X^^^^^^^^^^^^^^^^^X^@,X,,,X^@*X*+9X...%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...%
+D:%....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:42:Greater vault (nethack hell level #3)
+X:8:30:17:55
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.....................................................%
+D:%...XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.........%
+D:%...X,,,,,,,,,,,,,,,,,,,,,XXX^^^^^^^^^^^^^^^X.........%
+D:%...X,^^^^^^^^^^XXXX,,,,,,+&&^XXXXXXXXXXXX^^+.........%
+D:%...X,^XXXXXX******X,,XXXXXXXXX^^^^******XXXX.........%
+D:%...X,^X****X@*XXXXXXXX,,,,,,,,,,,XXXXXXXXXXXXXX......%
+D:%.XXXX+X,,,,XXXX,,,,,,,,,,,,,,,,,^+************XXXXX..%
+D:%.X@,,,,,XX,,,,+,,XXXXXXXXXXXXXXXXX****9999****+888X..%
+D:%.XXXX+X,,,,XXXX,,,,,,,,,,,,,,,,,^+************XXXXX..%
+D:%...X,^X****X@*XXXXXXXX,,,,,,,,,,,XXXXXXXXXXXXXX......%
+D:%...X,^XXXXXX******X,,XXXXXXXXX^^^^******XXXX.........%
+D:%...X,^^^^^^^^^^XXXX,,,,,+&&^^XXXXXXXXXXXX^^+.........%
+D:%...X,,,,,,,,,,,,,,,,,,,,XXX^^^^^^^^^^^^^^^^X.........%
+D:%...XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.........%
+D:%.....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:43:Lesser vault (easter egg)
+X:7:5:14:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%.###############.%
+D:%.#,^,^,^,^,^,^,#.%
+D:%.#+###########^#.%
+D:%.#,^,^,^,^,^,#,#.%
+D:%.###########,#^#.%
+D:%.#,^,^,^,^,#^#,#.%
+D:%.#+#######,#,#^#.%
+D:%.#,,,,,,,#^#^#,#.%
+D:%.#,,,,,,,#,+,#^+.%
+D:%.###############.%
+D:%.................%
+D:%%%%%%%%%%%%%%%%%%%
+
+N:44:Greater vault (nethack samurai castle)
+X:8:35:20:59
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.........................................................%
+D:%.XXXXX.............................................XXXXX.%
+D:%.X***X.............................................X***X.%
+D:%.X***XXX.....XX+XXXXXXXXXXXXXXXXXXXXXXXXX+XX.....XXX***X.%
+D:%.XXX@,,X.....X^&^X,,,X***X,,,X***X^^^+8X^&^X.....X,,@XXX.%
+D:%...X,,,XXXXXXX^^^X,,,X^^^X,,,X^^^X@@^X8X^^^XXXXXXX,,,X...%
+D:%...XXX^^^^^^^^^XXXXX+XXX+X+XXXXX+X+XXXXXXX^^^^^^^^^XXX...%
+D:%.....X^^XXXXXXXX*X,,,,,,,,,,,,,,,,,,,,,X*XXXXXXXX^^X.....%
+D:%.....X^^+,,,,,,,,+,,,,,,,,,99,,,,,,,,,,+,,,,,,,,+^^X.....%
+D:%.....X^^+,,,,,,,,+,,,,,,,,,99,,,,,,,,,,+,,,,,,,,+^^X.....%
+D:%.....X^^XXXXXXXX*X,,,,,,,,,,,,,,,,,,,,,X*XXXXXXXX^^X.....%
+D:%...XXX^^^^^^^^^XXXXXXX+X+XXXXX+X+XXX+XXXXX^^^^^^^^^XXX...%
+D:%...X,,,XXXXXXX^^^X8X^@@X^^^X^^^X,,,X,,,X^^^XXXXXXX,,,X...%
+D:%.XXX@,,X.....X^&^X8+^^^X***X***X,,,X,,,X^&^X.....X,,@XXX.%
+D:%.X***XXX.....XX+XXXXXXXXXXXXXXXXXXXXXXXXX+XX.....XXX***X.%
+D:%.X***X.............................................X***X.%
+D:%.XXXXX.............................................XXXXX.%
+D:%.........................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:45:Greater vault (nethack samurai castle #2)
+X:8:35:20:61
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...........................................................%
+D:%.XXXXXXXXXXXXX...............................XXXXXXXXXXXXX.%
+D:%.X,,^^^^^^^,,X...............................X,,^^^^^^^,,X.%
+D:%.X,,^XXXXX^,,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,^XXXXX^,,X.%
+D:%.X,,^+999X^,,X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X,,^X999+^,,X.%
+D:%.X,,^XXXXX^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^XXXXX^,,X.%
+D:%.X^^^^^^^^^^^XXXXXX+XXXXXXXXXXXXXXXXXXX+XXXXXX^^^^^^^^^^^X.%
+D:%.XXXX^^^XXXXXXXX*X,,,,,,,,,,,,,,,,,,,,,,,X*XXXXXXXX^^^XXXX.%
+D:%....+^^^X********+,,,,,,,,,,,,,,,,,,,,,,,+********X^^^+....%
+D:%....+^^^X********+,,,,,,,,,,,,,,,,,,,,,,,+********X^^^+....%
+D:%.XXXX^^^XXXXXXXX*X,,,,,,,,,,,,,,,,,,,,,,,X*XXXXXXXX^^^XXXX.%
+D:%.X^^^^^^^^^^^XXXXXX+XXXXXXXXXXXXXXXXXXX+XXXXXX^^^^^^^^^^^X.%
+D:%.X,,^XXXXX^,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^XXXXX^,,X.%
+D:%.X,,^+999X^,,X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X,,^X999+^,,X.%
+D:%.X,,^XXXXX^,,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,^XXXXX^,,X.%
+D:%.X,,^^^^^^^,,X...............................X,,^^^^^^^,,X.%
+D:%.XXXXXXXXXXXXX...............................XXXXXXXXXXXXX.%
+D:%...........................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:46:Greater vault (nethack spiral)
+X:8:30:19:38
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.........XXXXXXXXX+XXXXXXXXX........%
+D:%......XXXX^^^^^^^^^^^^^^^^^XXXX.....%
+D:%...XXXX^^^^^XXXXXXXXXXXXX^^^^^XXXX..%
+D:%..XX^^^^^XXXX^^^^^^^^^^^XXXX^^^^^XX.%
+D:%.XX^^^^XXX^^^^XXXXXXXXX^^^^XXX^^^^XX%
+D:%.X^^^^XX^^^^XXX,^^^^^,XXX^^^^XX^^^^X%
+D:%.X,,,XX,,,XXX,,^XX+XX^,,XXX,,,XX,,,X%
+D:%.X,,,X,,,,X,,,^XX***XX^,,,X,,,,X,,,X%
+D:%.X,,,X,99,X,,,^+@888@+^,,,X,,,,+,,,X%
+D:%.X,,,X,,,,X,,,^XX***XX^,,,X,,,,X,,,X%
+D:%.X,,,XX,,,XXX,,^XX+XX^,,XXX,,,XX,,,X%
+D:%.X,,,,XX^^^^XXX,^^^^^,XXX^^^^XX,,,,X%
+D:%.XX,,,,XXX^^^^XXXX+XXXX^^^^XXX,,,,XX%
+D:%..XX,,,**XXXX^^^^^^^^^^^XXXX,,,,,XX.%
+D:%...XXXX**,,,XXXXXXXXXXXXX,,,,,XXXX..%
+D:%......XXXX,,,,,,,,,,,,,,,,,XXXX.....%
+D:%.........XXXXXXXXXXXXXXXXXXX........%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:47:Greater vault (nethack building)
+X:8:30:16:41
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%...X^^^^^^^^^^^^^^^^X**@**X**@**X**@**X%
+D:%...X^^XXXXXXXXXXXX^^XXX+XXXXX+XXXXX+XXX%
+D:%...X^^X,,,,,,,,,,X^^X^^^^^^^^^^^^^^^^^X%
+D:%...X^^X,,,,,,,,,,X^^X+XXX+XXX+XXXXX+XXX%
+D:%.XXX^^X,,,,,,,,,,X^^^^^^X,,,X,,,X,,,,,X%
+D:%.+^&^^X,,,,,,,,,,+^^^^^^X,,,X,,,X,989,X%
+D:%.+^&^^X,,,,,,,,,,+^^^^^^X,,,X,,,X,989,X%
+D:%.XXX^^X,,,,,,,,,,X^^^^^^X,,,X,,,X,,,,,X%
+D:%...X^^X,,,,,,,,,,X^^X+XXXXX+XXX+XXX+XXX%
+D:%...X^^X,,,,,,,,,,X^^X^^^^^^^^^^^^^^^^^X%
+D:%...X^^XXXXXXXXXXXX^^XXX+XXXXX+XXXXX+XXX%
+D:%...X^^^^^^^^^^^^^^^^X**@**X**@**X**@**X%
+D:%...XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:48:Lesser vault (nethack, spiral rooms)
+X:7:5:13:32
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..............................%
+D:%....#######################...%
+D:%..###^+,,,,,,#^^^^^^^^^^+*###.%
+D:%..#,#^#,,,,,,#+############,#.%
+D:%..#^#^#,,,,,,#,,,+,,,,,,#^#^#.%
+D:%..+^+^#,,,,,,#,,,#,,,,,,#^+^+.%
+D:%..#^#^#,,,,,,+,,,#,,,,,,#^#^#.%
+D:%..#,############+#,,,,,,#^#,#.%
+D:%..###*+^^^^^^^^^^#,,,,,,+^###.%
+D:%....#######################...%
+D:%..............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:49:Greater vault (nethack building)
+X:8:30:17:54
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....................................................%
+D:%........XXXXXXXXXXXXX.................XXXXXXXXXXXXX.%
+D:%........X***********X.................X***********X.%
+D:%.XXXXXXXX***********XXXXXXXXXXXXXXXXXXX***********X.%
+D:%.+^^^^^^X,,,,,,,,,,,X**X**X**X**X**X**X*,,,,,,,,,*X.%
+D:%.X^,,,,^X^,,,,,,,,,,X,@X,@X,@X,@X,@X,@X,,,,,,,,,,,X.%
+D:%.X^^^^^^+^^^^^^^^^^^XX+XX+XX+XX+XX+XX+X,,,,,,,,,,,X.%
+D:%.XXXXXXXX^^^^^^^^^^^+^^^^^^^^^^^^^^^^^+,,,,,89,,,,X.%
+D:%.X^^^^^^+^^^^^^^^^^^XX+XX+XX+XX+XX+XX+X,,,,,98,,,,X.%
+D:%.X^,,,,^X^,,,,,,,,,,X,@X,@X,@X,@X,@X,@X,,,,,,,,,,,X.%
+D:%.+^^^^^^X,,,,,,,,,,,X**X**X**X**X**X**X*,,,,,,,,,*X.%
+D:%.XXXXXXXX***********XXXXXXXXXXXXXXXXXXX***********X.%
+D:%........X***********X.................X***********X.%
+D:%........XXXXXXXXXXXXX.................XXXXXXXXXXXXX.%
+D:%....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:50:Lesser vault (nethack, head)
+X:7:7:17:29
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%........###########........%
+D:%...#####################...%
+D:%...######,,,,,,,,,######...%
+D:%..#+^^^^#,,,,,,,,,#^^^^+#..%
+D:%..##^^^^#,,,,,,,,,+^,,^##..%
+D:%.#####+##,,,,,,,,,#^^^^###.%
+D:%.##^^^^^^,,,,,,,,,########.%
+D:%.####+###++#########*@+*##.%
+D:%.##^^^^^#^^#,,,#^@^####*##.%
+D:%.##^^,,^#^^#,###^#^#****##.%
+D:%..##^,,^#^^#,,,.^#^#@####..%
+D:%..#+^^^^#^^#####^#^^^^^##..%
+D:%...######^^^^^^^^#######...%
+D:%...#####################...%
+D:%........###########........%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:51:Lesser vault (maze of rooms)
+X:7:10:16:32
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..............................%
+D:%.#+##########################.%
+D:%.#^#,,,+^#*#^+,,+*#^+^#*#**@#.%
+D:%.#^+,,,#^+^+^######^#^#*###+#.%
+D:%.#########+###,,,,#^#,+@#,,,#.%
+D:%.#,,,,,,+^^+,,,,,,+^#######+#.%
+D:%.###+#######,,,,,#####,,+^^^#.%
+D:%.#,,,+**#**+,,,,,#^^^+,,#^,^#.%
+D:%.#############+###^,^#+##^^^#.%
+D:%.#***#^+,,#,,,,,,+^^^#^######.%
+D:%.#+###^#,,+,,,,,,#####^+,^^^#.%
+D:%.#,,,+^#,,########,,,+^#,^^^#.%
+D:%.##########################+#.%
+D:%..............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:52:Lesser vault (tetris tiles)
+X:7:5:20:13
+D:%%%%%%%%%%%%%
+D:%..#######..%
+D:%..#**#**#..%
+D:%..#,###,#..%
+D:%..#,#^#,#..%
+D:%.##+#^#+##.%
+D:%.#&,#^#,&#.%
+D:%.#,,+^+,,#.%
+D:%.####+####.%
+D:%.###,^,###.%
+D:%.#*##^##*#.%
+D:%.#,,#+#,,#.%
+D:%.##,#^#,##.%
+D:%.##+#^#+##.%
+D:%.#,,#^#,,#.%
+D:%.##,+^+,##.%
+D:%..#,#+#,#..%
+D:%..###.###..%
+D:%...........%
+D:%%%%%%%%%%%%%
+
+N:53:Lesser vault (hospital ward)
+X:7:5:14:20
+D:%%%%%%%%%%%%%%%%%%%%
+D:%..................%
+D:%.################.%
+D:%.#,,#,,#,,#,,#,,#.%
+D:%.#,,#,,#,,#,,#,,#.%
+D:%.##+##+##+##+##+#.%
+D:%.+..............+.%
+D:%.+..............+.%
+D:%.#+##+##+##+##+##.%
+D:%.#,,#,,#,,#,,#,,#.%
+D:%.#,,#,,#,,#,,#,,#.%
+D:%.################.%
+D:%..................%
+D:%%%%%%%%%%%%%%%%%%%%
+
+N:54:Lesser vault (lesser crypt)
+X:7:5:13:26
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................###.....%
+D:%................#,#.....%
+D:%......#######.###+###...%
+D:%..###.#,#,#,#.#^^^^^#...%
+D:%.##&###+#+#+###^###^###.%
+D:%.+^^^+^^^^^^^+^^#9#^+,#.%
+D:%.##&###+#+#+###^###^###.%
+D:%..###.#,#,#,#.#^^^^^#...%
+D:%......#######.###+###...%
+D:%................#,#.....%
+D:%................###.....%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:55:Lesser vault (arena)
+X:7:5:15:17
+D:%%%%%%%%%%%%%%%%%
+D:%...............%
+D:%.+###########+.%
+D:%.#...........#.%
+D:%.#.####^####.#.%
+D:%.#.#,,,,,,,#.#.%
+D:%.#.#,,,,,,,#.#.%
+D:%.#.^,,,,,,,^.#.%
+D:%.#.#,,,,,,,#.#.%
+D:%.#.#,,,,,,,#.#.%
+D:%.#.####^####.#.%
+D:%.#...........#.%
+D:%.+###########+.%
+D:%...............%
+D:%%%%%%%%%%%%%%%%%
+
+N:56:Lesser vault (monster wc)
+X:7:5:12:12
+D:%%%%%%%%%%%%
+D:%..#######.%
+D:%..#.&&&&#.%
+D:%..#^#####.%
+D:%.##...+,#.%
+D:%.#*...###.%
+D:%.#*...+,#.%
+D:%.#*...###.%
+D:%.##...+,#.%
+D:%..#+#####.%
+D:%..........%
+D:%%%%%%%%%%%%
+
+N:57:Lesser vault ('not' 'and')
+X:7:5:11:15
+D:%%%%%%%%%%%%%%%
+D:%.............%
+D:%..#########..%
+D:%.#+,,,#,,,+#.%
+D:%.#,#,#+#,#,#.%
+D:%.#,,#+*+#,,#.%
+D:%.#,#,#+#,#,#.%
+D:%.#+,,,#,,,+#.%
+D:%..#########..%
+D:%.............%
+D:%%%%%%%%%%%%%%%
+
+N:58:Lesser vault (brain's lair)
+X:7:5:18:17
+D:%%%%%%%%%%%%%%%%%
+D:%...............%
+D:%.#############.%
+D:%.#...........#.%
+D:%.#.####^####.#.%
+D:% #.#...&...#.#.%
+D:%.#.#.#####.#.#.%
+D:%.#.#.#,,,#.#.#.%
+D:%.#.#.#,,,#.#.#.%
+D:%.#.#.#,,,#.#.#.%
+D:%.#.#.##+##.#.#.%
+D:%.^.#..#^#..#.^.%
+D:%.####.#^#.####.%
+D:%.#,,#.#+#.#,,#.%
+D:%.#,,+..&..+,,#.%
+D:%.#############.%
+D:%...............%
+D:%%%%%%%%%%%%%%%%%
+
+N:59:Lesser vault (yin-yang)
+X:7:5:17:16
+D:%%%%%%%%%%%%%%%%
+D:%..............%
+D:%.#+##########.%
+D:%.#&#^^^^^^^^#.%
+D:%.#.#^######^#.%
+D:%.#&#^#****#^#.%
+D:%.#.#^#*,**#^#.%
+D:%.#&#^#****#^#.%
+D:%.#.#+####+#^#.%
+D:%.#&#,,,,#.#^#.%
+D:%.#.#,,*,#&#^#.%
+D:%.#&#,,,,#.#^#.%
+D:%.#.######&#^#.%
+D:%.#&.&.&.&.#^#.%
+D:%.##########+#.%
+D:%..............%
+D:%%%%%%%%%%%%%%%%
+
+N:60:Greater vault (der el bahri)
+X:8:35:28:45
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X***X,,X^^^^^^^^X9988899X^^^^^^^^+******X.%
+D:%.X***X,,+^..,...^X9999999X^...,..^XXXX***X.%
+D:%.X***XXXX^......^XXXX+XXXX^......^X**XXXXX.%
+D:%.X^^^X,,X^..,...^^^^^^^^^^^...,..^X******X.%
+D:%.X@@@X,,X^.......................^X,,,,,,X.%
+D:%.X^^^X,,X^..,..,..,..,..,..,..,..^X,,,,,,X.%
+D:%.X^^^X++X^.......................^X,,,,,,X.%
+D:%.X^^^X^^X^..,..,..,..,..,..,..,..^X,,,,,,X.%
+D:%.X^^^^^^+^.......................^X,,,,,,X.%
+D:%.X^^^^^^X^..,..,..,..,..,..,..,..^X,,,,,,X.%
+D:%.XXX+XXXX^.......................^X,,,,,,X.%
+D:%.X***X**X^..,..,..,..,..,..,..,..^X,,,,,,X.%
+D:%.XXXXX**X^.......................^X,,,,,,X.%
+D:%.X,,,,,,+^.......................^+,,,,,,X.%
+D:%.X,,,,,,+^^^^^^^^^^^^^^^^^^^^^^^^^+,,,,,,X.%
+D:%.XXXXXXXXXXXXXXXXXXX+++XXXXXXXXXXXXXXXXXXX.%
+D:%.X.............^^^^^^^^^^^^..............X.%
+D:%.X................^^^^^^^................X.%
+D:%.XXXXXXXXXXXXXXXXXXX^^^XXXXXXXXXXXXXXXXXXX.%
+D:%.X.................X.^.X.................X.%
+D:%.X.X.X.X.X.X.X.X.X.X^^^X.X.X.X.X.X.X.X.X.X.%
+D:%.X.................X.^.X.................X.%
+D:%.X.X.X.X.X.X.X.X.X.X^^^X.X.X.X.X.X.X.X.X.X.%
+D:%.X.................X.^.X.................X.%
+D:%...........................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:61:Lesser vault (der el bahri sanctuary)
+X:7:5:12:22
+D:%%%%%%%%%%%%%%%%%%%%%%
+D:%....................%
+D:%..........###.......%
+D:%..........#,#.......%
+D:%..###.###.#,#.......%
+D:%.##,###,###,#######.%
+D:%.+^^^^^^^+^^^+,,,,#.%
+D:%.+^^^^^^^+^^^+,,,,#.%
+D:%.######+###########.%
+D:%......###...........%
+D:%....................%
+D:%%%%%%%%%%%%%%%%%%%%%%
+
+N:62:Greater vault (hypostyle of ramses III)
+X:8:40:38:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X888888+*******X*******+88888X.%
+D:%.XXXXXXXXX+XXXXXXXXXXX+XXXXXXXX.%
+D:%.X99+***+^^^+^^^^^^^+^^^+**+99X.%
+D:%.XXXXXXXXXXXXXX+++XXXXXXXXXXXXX.%
+D:%.X**X,,X,,+^X^^^^^^^X^X,,,+***X.%
+D:%.X**X,,X,,X^X^X...X^X^X,,,XXXXX.%
+D:%.X+XX,,X,,X^X^..@..^X^X,,,X***X.%
+D:%.X,,X,,XXXX^X^X...X^X^X^^^X***X.%
+D:%.X,,X,,X,*X^X^^^^^^^X^XX+XXXX+X.%
+D:%.X+XXX+X+XX^XXX+++XXX^X^^X,,,,X.%
+D:%.X^^^^^X^^+^^^^^^^^^^^+^^X,**,X.%
+D:%.X+XXXXXXXX^X.X...X.X^XXXX,**,X.%
+D:%.X^^^^^X,,X^.........^X**X,**,X.%
+D:%.X^X,X^X,,X^X.X.@.X.X^X++X,,,,X.%
+D:%.X^^^^^X,,X^.........^+^^X^^^^X.%
+D:%.XXX+XXX++X^XXX...XXX^XXXX+XXXX.%
+D:%.X^^^^^^^^+^....&....^+****+^^X.%
+D:%.XXXXXXXXXX^X.X...X.X^XXXXXXX^X.%
+D:%.X^^^^^+^^X^.........^X^^^^^^^X.%
+D:%.X^#X#^X^^X^X.X.&.X.X^X^,*XXXXX.%
+D:%.X^X9X^X^^X^.........^X^,*X***X.%
+D:%.X^#X#^X^^X^X.X...X.X^X^,*XXX+X.%
+D:%.X^^^^^X^^X^^^^^^^^^^^X^^^X,,,X.%
+D:%.XXXXXXX++XXXXX+++XXXXXX+XX,,,X.%
+D:%.X*****+^^^^^^^^^^^^^^^^^+,,,,X.%
+D:%.XXXXXXX^.X.X.X...X.X.X.^XXXXXX.%
+D:%.X,,X,,X^...............^+,,,,X.%
+D:%.X,,X,,X^.X.X.X...X.X.X.^XXXXXX.%
+D:%.X++X++X^.....&.&.&.....^+,,,,X.%
+D:%.X^^^^^+^.X.X.X...X.X.X.^XXXXXX.%
+D:%.X++X++X^...............^+,,,,X.%
+D:%.X,,X,,X^.X.X.X...X.X.X.^XXXXXX.%
+D:%.X,,X,,X^^^^^^^^^^^^^^^^^+,,,,X.%
+D:%.XXXXXXXXXXXXXX+++XXXXXXXXXXXXX.%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:63:Lesser vault (amada temple)
+X:7:10:15:30
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%............................%
+D:%.######################.....%
+D:%.#**#,,,,+^^#.....&...#.....%
+D:%.#**#,,,,#^^#...&.....#.....%
+D:%.#+#######^^#..#.#.#.##.....%
+D:%.#,,,,,,,#^^#^^^^^^^^^#####.%
+D:%.#,,,,,,,+^^+^^^^^^^^^+^^^+.%
+D:%.#,,,,,,,#^^#^^^^^^^^^#####.%
+D:%.#+#######^^#..#.#.#.##.....%
+D:%.#**#,,,,#^^#...&..&..#.....%
+D:%.#**#,,,,+^^#.........#.....%
+D:%.######################.....%
+D:%............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:64:Lesser vault (amenhotep I)
+X:7:10:18:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................................%
+D:%...............######...........%
+D:%...............#.&&.#...........%
+D:%.###############.##.#...........%
+D:%.#**#,,,+^^^^^^^^##.###.........%
+D:%.#**#,,,#^^^^^^^^^^...#########.%
+D:%.##+#####^^#######^&#.#.......#.%
+D:%.#,,,,,,+^^+,*,*,+^^^^^^^^^^^^+.%
+D:%.#,,,,,,+^^+*,*,*+^^^^^^^^^^^^+.%
+D:%.##+#####^^#######^&#.#.......#.%
+D:%.#**#,,,#^^^^^^^^^^...#########.%
+D:%.#**#,,,+^^^^^^^^##.###.........%
+D:%.###############.##.#...........%
+D:%...............#.&&.#...........%
+D:%...............######...........%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:65:Lesser vault (hathor chapel)
+X:7:10:21:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%......##+###.....%
+D:%.######^^^######.%
+D:%.#,,#^#...#^#,,#.%
+D:%.#,,+^..*..^+,,#.%
+D:%.#,,#^#...#^#,,#.%
+D:%.####^.....^####.%
+D:%....#^^^^^^^#....%
+D:%....#.##+##.#....%
+D:%....#&#^^^#&#....%
+D:%....###,^,###....%
+D:%....#,,,,,,,#....%
+D:%....####+####....%
+D:%....#,,,,,,,#....%
+D:%....####+####....%
+D:%....#,,,,,,,#....%
+D:%....####+####....%
+D:%.....#*****#.....%
+D:%.....#######.....%
+D:%%%%%%%%%%%%%%%%%%%
+
+
+N:66:Lesser vault (osiris halls)
+X:7:10:17:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................................%
+D:%.###########################....%
+D:%.#*,+^^^^^#^^^^^^^^^^^^+,,*#....%
+D:%.####^#.#^#^#.#.#.#.#.^#####....%
+D:%.#*,+^.&.^+^..&...&...^+,,*#....%
+D:%.####^#.#^#^#.#.#.#.#.^#####....%
+D:%.#*,+^^^^^#^^^^^^^^^^^^+,,*#....%
+D:%.####################++########.%
+D:%.#,,#,,#,,#,,#,,#,,#....#,,#,,#.%
+D:%.#,,#,,#,,#,,#,,#,,#....#,,#,,#.%
+D:%.#,,#,,#,,#,,#,,#,,#.&..#,,#,,#.%
+D:%.#++#++#++#++#++#++#....#++#++#.%
+D:%.#^^^^^^^^^^^^^^^^^^^^^^^^^^^^+.%
+D:%.##############################.%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:67:Lesser vault (temple of sety)
+X:7:10:22:25
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.##########+##########.%
+D:%.#,,,,,,,#^^^#,,,,,,,#.%
+D:%.#,,,,,,,+^^^+,,,,,,,#.%
+D:%.#########^^^#########.%
+D:%.#,,,,,,,#^^^#,,,,,,,#.%
+D:%.#,,,,,,,+^^^+,,,,,,,#.%
+D:%.#########+###########.%
+D:%.#^^^+^^^+^^^^^#,.,.,#.%
+D:%.#.#^#^#.#^#.#.#.#.#.#.%
+D:%.#.&^#^.&#^.&..#,.,.,#.%
+D:%.#.#^+^#.#^#.#.#.#.#.#.%
+D:%.#^^^#^^^#^^^^^#,.,.,#.%
+D:%.#+#+###+###+###.#.#.#.%
+D:%.#,#^^^^^^^^^^^#,.,.,#.%
+D:%.#,#.#.#.#.#.#.#+###^#.%
+D:%.#,#...........#,**#^#.%
+D:%.#*#.#.#.#.#.#.#####+#.%
+D:%.#*#^^^^^^^^^^^+&^^^&#.%
+D:%.#######+#############.%
+D:%.......................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:68:Lesser vault (temple at abydos)
+X:7:10:21:23
+D:%%%%%%%%%%%%%%%%%%%%%%%
+D:%^^^^^^^^^^^^^^^^^^^^^%
+D:%^#+#+#####+#####+#+#^%
+D:%^#,#,#^^^^^^^^^#,#,#^%
+D:%^#,#,#^#.#.#.#^#,#,#^%
+D:%^#,#,#^...&...^#,#,#^%
+D:%^#####^#.#.#.#^#####^%
+D:%^#*,,+^^^^^^^^^+,,*#^%
+D:%^#########+#########^%
+D:%^#*,,+^^^^^^^^^+,,*#^%
+D:%^#####^#.#.#.#^#####^%
+D:%^#*,,+^...&...^+,,*#^%
+D:%^#####^#.#.#.#^#####^%
+D:%^#*,,+^^^^^^^^^+,,*#^%
+D:%^##+###+##+##+###+##^%
+D:%^#,,,,#,#^^^#,#,,,,#^%
+D:%^#,##,#,#,#,#,#,##,#^%
+D:%^#,,,,#,#***#,#,,,,#^%
+D:%^###################^%
+D:%^^^^^^^^^^^^^^^^^^^^^%
+D:%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:69:Greater vault (Spiral castle)
+X:8:35:31:25
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................%
+D:%.XXXXX...........XXXXX.%
+D:%.X,,,X...........X,,,X.%
+D:%.X,,,X...........X,,,X.%
+D:%.XXX+XXXXXXXXXXXXX+XXX.%
+D:%...X^^^^^^^^^^^^^^^X...%
+D:%...X^XXXXXXXXXXXXX^X...%
+D:%...X^X^^^^^^^^^^^+^X...%
+D:%...X^X^XXXXXXXXXXX^X...%
+D:%...X^X^X&..&....&X^X...%
+D:%...X^X^X.XXXXXXX.X^X...%
+D:%...X^X^X.X^^^^^X.X^X...%
+D:%...X^X^X&X+XXX^X.X^X...%
+D:%...X^X^X.X*9*X^X&X^X...%
+D:%...+^X^X,X989X^X.X^+...%
+D:%...X^X^X.X*9*X^X.X^X...%
+D:%...X^X^X.XXX+X^X,X^X...%
+D:%...X^X^X..&..X^X.X^X...%
+D:%...X^X.XXXXXXX^X.X^X...%
+D:%...X^X^^^^^^^^^X&X^X...%
+D:%...X^XXXXXXXXXXX.X^X...%
+D:%...X^+...&..&...,X^X...%
+D:%...X^XXXXXXXXXXXXX^X...%
+D:%...X^^^^^^^^^^^^^^^X...%
+D:%.XXX+XXXXXXXXXXXXX+XXX.%
+D:%.X,,,X...........X,,,X.%
+D:%.X,,,X...........X,,,X.%
+D:%.XXXXX...........XXXXX.%
+D:%.......................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:70:Lesser vault (temple of dendereh)
+X:7:10:20:22
+D:%%%%%%%%%%%%%%%%%%%%%%
+D:%....................%
+D:%.##################.%
+D:%.#***+^&#**#&^+***#.%
+D:%.#***#^^#,,#^^#***#.%
+D:%.#####++#++#++#####.%
+D:%.#,,,+^^^^^^^^+,,,#.%
+D:%.#####^######^#####.%
+D:%.#,,,+^#,,,,#^+,,,#.%
+D:%.#####^#,**,#^#####.%
+D:%.#,,,+^#,**,#^#***#.%
+D:%.#####^#,**,#^#^^^#.%
+D:%.#,,,+^#,**,#^##+##.%
+D:%.#####^#,,,,#^#,,,#.%
+D:%.#,,,#^##++##^#&,&#.%
+D:%.#,,,+^^^^^^^^##+##.%
+D:%.#,,,#^^^^^^^^^^^^#.%
+D:%.########++########.%
+D:%....................%
+D:%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:71:Greater vault (Karnak, part I)
+X:8:35:24:44
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X*****+^+^^^^+^^^X,,,X***X***X***X,****X.%
+D:%.XXXXXXXXX^XX^X,,,X,X,X,X,X,X,X*X*X,X*X*X.%
+D:%.X,X,X,X,X^..^X,,,X,,,X^^^X^^^X**@+^,,,,X.%
+D:%.X^^^^^^^+^@.^X,,,XX+XX+XXXXX+XXXXX+XXXXX.%
+D:%.X,X^^^X,X^XX^X***X^^^+^^^^^^^+,,*X^^^^^X.%
+D:%.XXXX+XXXX^^^^X,,,XXXXX^X.X.X^XXXXX^X^X^X.%
+D:%.X^^^^^^^XXXXXX,,,X,,,X^..@..^+,,*X^^^^&X.%
+D:%.X^X,X,X^X,,,,X,,,X,X,X^X.X.X^XXXXX^XXXXX.%
+D:%.X^^^^^^^X,,,,X^^^X,,,X^^^^^^^+,,*X^+,,*X.%
+D:%.XXXX+XXXXX++XXX+XXX+XXXXX+XXXXXXXX^XXXXX.%
+D:%.X*,+^^^^^^^^^^^^^^^^^^^^^^^^^+,,*X^+,,*X.%
+D:%.XXXX^X.X.X.X.X.X.X.X.X.X.X.X^XXXXX^XXXXX.%
+D:%.X*,+^.........&.....&.......^X,,*X^+,,*X.%
+D:%.XXXX^X.X.X.X.X.X.X.X.X.X.X.X^+,X*X^XXXXX.%
+D:%.X**X^.......................^X,,*X^+,,*X.%
+D:%.X,,+^X.X.X.X.X.X.X.X.X.X.X.X^XXXXX^XXXXX.%
+D:%.XXXX^.........&.....&.......^+^^^^^+,,*X.%
+D:%.X,,+^X.X.X.X.X.X.X.X.X.X.X.X^X,X,X^XXXXX.%
+D:%.X**X^^^^^^^^^^^^^^^^^^^^^^^^^X.*.X^+,,*X.%
+D:%.XXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXXXXXX.%
+D:%..........................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:72:Lesser vault (Karnak, part II)
+X:7:10:20:29
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...........................%
+D:%.###+######################%
+D:%.#,+^#,,#,,#^+^+^#*#,#^+,#.%
+D:%.###.#,,#,,#^#^#^#*#,#^###.%
+D:%.#,+^#,,#,,#^#^#^#*#+#^+,#.%
+D:%.###.#++#++#^#^#^#+#.#^###.%
+D:%.#,+^#^^^^^+^#^#^+,,,#^+,#.%
+D:%.###.#^^^^^+^#^#+#+###^###.%
+D:%.#,+^#+#+#+#^#^#,#^+,#^+,#.%
+D:%.###.#,#,#,#^#^#######^###.%
+D:%.#,+^#######+#,,+,,,,,^+,#.%
+D:%.###^^^^^^#,^#,,+,,,,#^###.%
+D:%.#,+^#,#*^##+####,,,,,^+,#.%
+D:%.###^,,,*^#^^^^^#,,,,#^###.%
+D:%.#,+^#,#*^#,,,,^+,,,,,^+,#.%
+D:%.###^^^^^^#^^^^^#,,,,,^###.%
+D:%...##########+##########...%
+D:%...........................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:73:Greater vault (mortuary temple of sety)
+X:8:35:25:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X^+,,***X,,+^^^^^+,,X*X,,X*X9X.%
+D:%.X^XXXXXXX,,X^X*X^X,,X,X,,X*X9X.%
+D:%.X^+,,***XXXX^*@*^X,,X^X,,X@X9X.%
+D:%.X^XXXXXXX,,X^X*X^XXXX^X,,X^X9X.%
+D:%.X^+,,***X,,+^^^^^+..X^X,,X^X^X.%
+D:%.X^XXXXXXXXXXXX+XXXXXX+X++X+X+X.%
+D:%.X^X*X*X*X**X,+.+,X**X^^^^+^^^X.%
+D:%.X+X,X,X,X,,XXX.XXX,,X^^^^+^^^X.%
+D:%.X^X^X^X^X,,X,X.X,X,,X^^XXXXXXX.%
+D:%.X^X+X+X+X^^X,X.X,X^^X^^X,,,,,X.%
+D:%.X^+^^^^^X++X+X+X+X++X^^X,X,X,X.%
+D:%.X^XXXXXXX^^^^^^^^^^^X^^X,,,,,X.%
+D:%.X^X*X*X*XXXX^...^XXXX^^X,X,X,X.%
+D:%.X^X,X,X,X,,+^X*X^+,,X^^X,,,,,X.%
+D:%.X^X^X^X^XXXX^.&.^XXXX^^X,X,X,X.%
+D:%.X^X+X+X+X,,+^X*X^+,,X^^X,,,,,X.%
+D:%.X^X^^^^^XXXX^...^XXXX^^X,X,X,X.%
+D:%.X^X*X,X*X,,X^X*X^X,,X^^X,,,,,X.%
+D:%.X^+^^^^^+^^+^^^^^+^^+^^X,,,,,X.%
+D:%.XXXXXXXXXXXXXX+XXXXXXXXXXX+XXX.%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:74:Lesser vault (edfu)
+X:7:5:15:15
+D:%%%%%%%%%%%%%%%
+D:%.............%
+D:%.###########.%
+D:%.#,+^#,#^+,#.%
+D:%.###+#+#+###.%
+D:%.#,+^...^+,#.%
+D:%.###.###.###.%
+D:%.#,+.#*#.+,#.%
+D:%.###.#,#.###.%
+D:%.#,+.#^#.#,#.%
+D:%.###^...^#+#.%
+D:%.#,+,#+#,+,#.%
+D:%.#####^#####.%
+D:%.............%
+D:%%%%%%%%%%%%%%%
+
+N:75:Greater vault (kom ombo)
+X:8:40:36:30
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X****X,99,X9889X,99,X****X.%
+D:%.X****X,,,,X9999X,,,,X****X.%
+D:%.X+XXXX+XXXX+XXXX+XXXX+XXXX.%
+D:%.X@^^^^^^^^^^^^^^^^^^^^^^@X.%
+D:%.X^XXXXXXXXXXXXXXXXXXXXXX^X.%
+D:%.X^X**X,,X,,X,,X,,X,,X**X^X.%
+D:%.X^X,,X+XX+XX+XXX+XX+X,,X^X.%
+D:%.X^X,^+^^^^^^^^^^^^^^+^,X^X.%
+D:%.X^XXXX^XX+XX^^XX+XX^XXXX^X.%
+D:%.X^X,,X^X,,,X^^X,,,X^+^,X^X.%
+D:%.X^X,,X^X***X^^X***X^X,*X^X.%
+D:%.X^X,,X^X9X9X^^X9X9X^XXXX^X.%
+D:%.X^X,,X^X***X^^X***X^+^,X^X.%
+D:%.X^X++X^X,,,X^^X,,,X^X,*X^X.%
+D:%.X^X^^X^XX+XX^^XX+XX^XXXX^X.%
+D:%.X^X^^+^^^^^^^^^^^^^^X,*X^X.%
+D:%.X^X,,X^^^^^^^^^^^^^^+^,X^X.%
+D:%.X^XXXXXXX+XXXXXX+XXXXXXX^X.%
+D:%.X^X,X,X,,,,,XX,,,,,X***X^X.%
+D:%.X^X,X^X,***,++,***,+*@*X^X.%
+D:%.X^X,+^+,,,,,XX,,,,,X***X^X.%
+D:%.X^XXX+XXX+XXXXXX+XXXX+XX^X.%
+D:%.X^X*,^X,,,,,XX,,,,,+^^*X^X.%
+D:%.X^X,,^+,,*,,++,,*,,XX+XX^X.%
+D:%.X^X*,*X,,,,,XX,,,,,X,,,X^X.%
+D:%.X^XXXXXXX+XXXXXX+XXXXXXX^X.%
+D:%.X^X^^^^^^^^^^^^^^^^^^^^X^X.%
+D:%.X^X^^XX,XX^^XX^^XX,XX^^X^X.%
+D:%.X^X^^^^^^^^^^^^^^^^^^^^X^X.%
+D:%.X^+^^XX,XX^^XX^^XX,XX^^+^X.%
+D:%.X,X^^^^^^^^^^^^^^^^^^^^X,X.%
+D:%.XXXXXXXXX+XXXXXX+XXXXXXXXX.%
+D:%............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:76:Lesser vault (belvoir keep)
+X:7:5:19:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.###...........###.%
+D:%.#,######+######,#.%
+D:%.##+^^^^+&+^^^^+##.%
+D:%..#&^####+####^.#..%
+D:%..#.^#,^+^+,,#^.#..%
+D:%..#.^#,^#^#,,#^.#..%
+D:%..#.^#,*#^##+#^.#..%
+D:%..#.^#,^#^#,,#^&#..%
+D:%..#.^#,^+^#*,#^.#..%
+D:%..#.^####+####^.#..%
+D:%.##+^^^^^^^^^^^+##.%
+D:%.#,######+######,#.%
+D:%.###...#,*,#...###.%
+D:%.......#*,*#.......%
+D:%.......#####.......%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+#N:77:Lesser vault (Pattern)
+#X:8:30:31:47
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+#D:%X@&+.............................+&@X,,,,,,X.%
+#D:%XXXX.p...bad.bad.bad.bad.cbb.....XXXX,,,,,,X.%
+#D:%X@&X.a.dcb.dcb.dcb.dcb.dcc.baa...X&@X,,,,,,X.%
+#D:%XX+X.b.d.....................ad..X+XX,,,,,,X.%
+#D:%X....c.a.dabcdabcda...........dc....X,,,,,,X.%
+#D:%X....d.b.d........a..cbadcba...c....X,,,,,,X.%
+#D:%X...ad.c.c.dcbadcba..c.....ad..cb...X++XXX+X.%
+#D:%X...a..d.b.d.........cdabc..d...b...X^^X^^^X.%
+#D:%X...b.ad.a.a..abcd.......cd.dcb.a...X**X^X+X.%
+#D:%X..cb.a..d.b..a..d..adcb..d...b.ad..X,,X^X^X.%
+#D:%X..c..b..c.c..d.ad..a..ba.a...a..d..X&&X^X&X.%
+#D:%X.dc.cb..b.d..c.a..PPP..a.a.cda..dc.X^^X^X+X.%
+#D:%X.d..c...a.a..b.b.PPAPP.d.b.c.....c.+^^X^X*X.%
+#D:%X.da.cd..d.b..a.c.PABAP.c.b.cba..bc.X^^X^X*X.%
+#D:%X..a..d..c.c..d.d.PPAPP.b.c...a..b..X&&X^XXX.%
+#D:%X..ab.da.b.d..c.a..PPP..a.c...d.ab..X,,X^X,X.%
+#D:%X...b..a.a.a..b.ab.....da.d..cd.a...XXXX+X+X.%
+#D:%X...c..b.d.b..a..bcd.bcd..a.bc..d...X**^^^,X.%
+#D:%X...cd.bcd.c..ad...dab...ba.b..cd...X,,,,,,X.%
+#D:%X....d.....d...dc......dcb..a..c....X,,,XXXX.%
+#D:%X....da....da...cbadcbad...da.bc....X,,,+,,X.%
+#D:%X.....a.....abc...........cd..b.....X,,,X,,X.%
+#D:%XX+X..ab......cdabcdabcdabc..ab..X+XXXXXX,,X.%
+#D:%X@&X...bc...................da...X&@X,,,,,,X.%
+#D:%XXXX....cddaabbccddaabbcdabcd....XXXX,,,,,&+.%
+#D:%X@&+.............................+&@X****&&+.%
+#D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX++X.%
+#D:%.............................................%
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#
+#
+#N:78:Greater vault (Pattern 2)
+#X:8:30:29:45
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+#D:%X8+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+8X%
+#D:%X+XXXXXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXX+X%
+#D:%X^X.....................................X^X%
+#D:%X^X.................p...................X^X%
+#D:%X^X.........adcbadcba.dcbadcbad.........X^X%
+#D:%X@X......dcba.........d.......dcba......X@X%
+#D:%X,X...baad.....abcdab.dabcda.....addc...X,X%
+#D:%X,X..cb.....bcda....b......abcd.....cb..X,X%
+#D:%X,X.dc....dab....adcb.adcb....dab....ba.X,X%
+#D:%X,X.d....cd....cba....a..bad....bc....a.X,X%
+#D:%X,X.a...bc...adc...PPPPP...dcb...cd...d.X,X%
+#D:%X,X.b...b....a....PPPAPPP....b....d...c.X,X%
+#D:%X,X.c...a....b....PPABAPP....a....a...c.X,X%
+#D:%X,X.d...d....c....PPPAPPP....d....b...b.X,X%
+#D:%X,X.a...dc...cda...PPPPP...bcd...cb...b.X,X%
+#D:%X,X.b....cb....abc.......dab....dc....a.X,X%
+#D:%X,X.bc....bad....cddaabbcd....bad....da.X,X%
+#D:%X,X..cd.....dcba...........adcb.....cd..X,X%
+#D:%X,X...dabc.....adcbadcbadcba.....dabc...X,X%
+#D:%X^X......cdab.................abcd......X^X%
+#D:%X^X.........bccddaabcdabcdabcda.........X^X%
+#D:%X^X.....................................X^X%
+#D:%X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+#D:%X9+^^^@,,,,,&,,,,,,,,&,,,,,,,&,,,,,,@^^^+9X%
+#D:%XXXXXXXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXXXX%
+#D:%...........................................%
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#
+#
+#
+#N:79:Greater vault (Pattern 2)
+#X:8:30:30:42
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+#D:%.X9+^^^^^^^^^^^^^^^^^+,,,,,,,,,,,,,,,+8X%
+#D:%.X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+#D:%.X,X.................................X^X%
+#D:%.X,X....adcbadcbadcbadcbadcbadc......X^X%
+#D:%.X,X...ba.....................cbad...X^X%
+#D:%.X,X..cb..bad.bad.bad.bad.bad....d...X^X%
+#D:%.X,X..c..cb.dcb.dcb.dcb.dcb.dcba.dc..X^X%
+#D:%.X&X..d.dc.....................a..c..X^X%
+#D:%.X&X..d.d..bbcc...cbadcba..adc.ad.b..X^X%
+#D:%.X+X..a.a.ab..cd.dc.....ad.a.c..d.a..X+X%
+#D:%.X^X..a.b.a....d.d..PPP..d.b.c.cd.d..X@X%
+#D:%&X^X..b.c.ad...a.a.PPAPP.c.c.b.c..dc.X9X%
+#D:%.+^X..b.d..dc..a.b.PABAP.b.d.b.cb..c.+8X%
+#D:%&X^X..c.a...cb.b.c.PPAPP.a.a.a..b..b.X9X%
+#D:%.X^X..d.b....b.c.d..PPP..d.b.d.ab..a.X@X%
+#D:%.X+X..a.c.cdab.d.da..d...dcb.d.a..da.X+X%
+#D:%.X&X..b.d.c....a..abcd.......c.ad.d..X^X%
+#D:%.X&X..c.a.cbad.ab......abc..bc..d.c..X^X%
+#D:%.X,X..d.b....d..bcdabcda.cdab..cd.b..X^X%
+#D:%.X,X..a.bcda.c................bc..a..X^X%
+#D:%.X,X..b....abc..dab.dab.dab.dab..da..X^X%
+#D:%.X,X..bcda.....cd.bcd.bcd.bcd...cd...X^X%
+#D:%.X,X.....abcdabc..............pbc....X^X%
+#D:%.X,X.................................X^X%
+#D:%.X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+#D:%.X9+^^^^^^^^^^^^^^^^^+,,,,,,,,,,,,,,,+8X%
+#D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+# XXX
+
+# XXX
+
+N:82:Lesser vault (checkerboard)
+X:7:5:13:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXX%
+D:%X&#9#&#9#&#9#&#9#&+%
+D:%X#XXXXXXXXXXXXXXXXX%
+D:%X9#&#9#&#9#&#9#&#9X%
+D:%XXXXXXXXXXXXXXXXX#X%
+D:%X&#9#&#88888#&#9#&X%
+D:%X#XXXXXXXXXXXXXXXXX%
+D:%X9#&#9#&#9#&#9#&#9X%
+D:%XXXXXXXXXXXXXXXXX#X%
+D:%+&#9#&#9#&#9#&#9#&X%
+D:%XXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+
+N:83:Lesser vault (spiral checkers)
+X:7:5:14:17
+D:%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXX%
+D:%X&#9#&#9#&#9#&X%
+D:%+XXXXXXXXXXXX#X%
+D:%XXX@#9#@#9#@X9X%
+D:%X9#XXXXXXXX#X#X%
+D:%X#XXX98X89#9X&X%
+D:%X&X9#98X89XXX#X%
+D:%X#X#XXXXXXXX#9X%
+D:%X9X@#9#@#9#@XXX%
+D:%X#XXXXXXXXXXXX+%
+D:%X&#9#&#9#&#9#&X%
+D:%XXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%
+
+
+N:84:Greater vault (monstrosity)
+X:8:25:17:28
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X^@^@^@^@^@#X9X9X9X9X9X9XX%
+D:%X#XXXXXXXXXX9X9X9X9X9X9X9X%
+D:%XX9X9X9X9XXXXXXXXXXXXXXX#X%
+D:%X9X9X9X9X9X##############X%
+D:%XXXXXXXXX#X#XXXXXXXXXXXXXX%
+D:%X&,&X&,&X&X8888X&,&X&,&X&+%
+D:%X,X,X,X,X,XXXXXX,X,X,X,X,X%
+D:%+&X&,&X&,&X8888X&X&,&X&,&X%
+D:%XXXXXXXXXXXXXX#X#XXXXXXXXX%
+D:%X##############X9X9X9X9X9X%
+D:%X#XXXXXXXXXXXXXXX9X9X9X9XX%
+D:%X9X9X9X9X9X9X9XXXXXXXXXX#X%
+D:%XX9X9X9X9X9X9X#@^@^@^@^@^X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:85:Cyclone
+X:8:40:23:91
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%XXXX^^^^^^^^^XXX^^^^^^^^^XXX^^^#XXX8.X.&.X.&.X..*X+^.^.^.^.^.^..XX*^.^.^.^.^.^.^.^.^.^#8X%
+D:%XX***XXX...XXX...XXX...XXX...XXX^^X*.X^X^X^X^X^X.*XXXXXXXXXXXXX..XX^^XXXXXXXXXXXXXXXXXX#X%
+D:%X88XXX...XXX...XXX...XXX...XXX^^^,X*.X^X^X^X^X^X..*XX8@,,,,,,@XX,.XX^^..........@&.,**X.X%
+D:%XXXX@&@XXX@@@XXX&&&XXX&@&XXX^^^,..X*.X^X^X^X^X^X...@X@........@X,..X...........@&..,**X.X%
+D:%XX...XXX...XXX...XXX...XXX^^^,....X*.X^X^X^X^X^X...@X*..*9*..@XX^^XXXX*.......@&@..,**X.X%
+D:%X*.XXX...XXX...XXX...XXX^^^^....,,X*.&.X.&.X.&.X..*XX*.....,XXX.XXX@@XXX*....@&..@.,**X.X%
+D:%X*XX...XXX...XXX...XXX^^^,.^...XX+XXXXXXXXXXXXXX.*XX*....,,XXX.XXXXXX&&XXX*.@&....@8**X.X%
+D:%X^^^^XXX^^^^^^^^^XXX^^^,..*^.&XX.*X&^^*****^^#X.*XX*....,XXX&&XXX@@X#X*..XX@&.....8@**X.X%
+D:%XXXXXXXXXXXXXXXXXX^^^,...**^.&X8.*X@XXXXXXXXXX^.XX&....XXX&&XXX*****XXX*..XXXXXXXXXXXXX.X%
+D:%#^^^^^^^^^^^^^9#^^^.....*99^.@X8.*#^^^*****8XXXXX8@..XX#@@XX#@@@....8XXX*.+^.^.^.^.^.^+.X%
+D:%XXXXXXXXXXXXXXXXXX^^^,...**^.&X8.*X@XXXXXXXXXX^.XX&....XXX&&XXX*****XXX*..XXXXXXXXXXXXX.X%
+D:%X^^^^XXX^^^^^^^^^XXX^^^,..*^.&XX.*X&^^*****^^#X.*XX*....,XXX&&XXX@@X#X*..XX@&.....8@**X.X%
+D:%X*XX...XXX...XXX...XXX^^^,.^...XX+XXXXXXXXXXXXXX.*XX*....,,XXX.XXXXXX&&XXX*.@&....@8**X.X%
+D:%X*.XXX...XXX...XXX...XXX^^^^....,,X*.&.X.&.X.&.X..*XX*.....,XXX.XXX@@XXX*....@&..@.,**X.X%
+D:%XX...XXX...XXX...XXX...XXX^^^,....X*.X^X^X^X^X^X...@X*..*9*..@XX^^XXXX*.......@&@..,**X.X%
+D:%XXXX@&@XXX@@@XXX&&&XXX&@&XXX^^^,..X*.X^X^X^X^X^X...@X@........@X,..X...........@&..,**X.X%
+D:%X88XXX...XXX...XXX...XXX...XXX^^^,X*.X^X^X^X^X^X..*XX8@,,,,,,@XX,.XX^^..........@&.,**X.X%
+D:%XX***XXX...XXX...XXX...XXX...XXX^^X*.X^X^X^X^X^X.*XXXXXXXXXXXXX..XX^^XXXXXXXXXXXXXXXXXX#X%
+D:%XXXX^^^^^^^^^XXX^^^^^^^^^XXX^^^#XXX8.X.&.X.&.X..*X+^.^.^.^.^.^..XX*^.^.^.^.^.^.^.^.^.^#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:86:Miniature Cell
+X:7:5:5:5
+D:%%%%%
+D:%#8#%
+D:%888%
+D:%#8#%
+D:%%%%%
+
+N:87:Castle Death
+X:8:35:20:60
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+XX....+XX...X****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....XXX....@X****X%
+D:%X.........................................XXX....&.@X****X%
+D:%X+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX....@.&.@X*99*X%
+D:%X999X..9..X&&&&&X,,,,,X@@@@@X..&..X@@@XXX....&.@.&.@X*99*X%
+D:%X@@@X.&.&.X&&&&&X,,,,,X@@@@@X99.99X9XXX.X..@.&.@.&.@X****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...X..@.&.@.&.@XX##XX%
+D:%+^...&.&.&+...@.@.@+...@@@@@+.....99+...+..@.&.@.&.8+^^^^X%
+D:%+^...&.&.&+...@.@.@+...@@@@@+.....99+...+..@.&.@.&.8+^^^^X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...X..@.&.@.&.@XX##XX%
+D:%X@@@X.&.&.X&&&&&X,,,,,X@@@@@X99.99X9XXX.X..@.&.@.&.@X****X%
+D:%X999X..9..X&&&&&X,,,,,X@@@@@X..&..X@@@XXX....&.@.&.@X*99*X%
+D:%X+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX....@.&.@X*99*X%
+D:%X.........................................XXX....&.@X****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....XXX....@X****X%
+D:%X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+XX....+XX...X****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:88:Mirrored Quartet
+X:8:20:21:49
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X89@@@XXX,,,,XXX....^^^^^^^....XXX,,,,XXX@@@98X%
+D:%X9@@#XX....XXX**....XXX#XXX....**XXX....XX#@@9X%
+D:%X@XXX&&&&XXX**....@XX&&@&&XX@....**XXX&&&&XXX@X%
+D:%XXX....XXX**......@X**...**X@......**XXX....XXX%
+D:%X@...XXX**.......XXXXX...XXXXX.......**XXX...@X%
+D:%X@.#XX**.......9XX888XX^XX888XX9.......**XX#.@X%
+D:%XXXX&&&&&&&&&&&9#,,,,,X^X,,,,,#9&&&&&&&&&&&XXXX%
+D:%XXXXXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXX%
+D:%%,,,,,,,,,,,,,,,,,,,,,#8#,,,,,,,,,,,,,,,,,,,,,%%
+D:%XXXXXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXX%
+D:%XXXX&&&&&&&&&&&9#,,,,,X^X,,,,,#9&&&&&&&&&&&XXXX%
+D:%X@.#XX**.......9XX888XX^XX888XX9.......**XX#.@X%
+D:%X@...XXX**.......XXXXX...XXXXX.......**XXX...@X%
+D:%XXX....XXX**......@X**...**X@......**XXX....XXX%
+D:%X@XXX&&&&XXX**....@XX&&@&&XX@....**XXX&&&&XXX@X%
+D:%X9@@#XX....XXX**....XXX#XXX....**XXX....XX#@@9X%
+D:%X89@@@XXX,,,,XXX**..^^^^^^^..**XXX,,,,XXX@@@98X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:89:False Wall
+X:8:20:15:64
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+D:%X^+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXXXXXX+X##X+XXXXXXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+@*&*@*&*@*&*@*&*@*&*@*&*@*X@@X*@*&*@*&*@*&*@*&*@*&*@*&*@+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXXXXX+XX,,XX+XXXXXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+&.@.&.@.&.@.&.@.&.@.&.@.&X*..*X&.@.&.@.&.@.&.@.&.@.&.@.&+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXXXX+XX*..*XX+XXXXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+,,,,,,,,,,,,,,,,,,,,,,,,X,,..,,X,,,,,,,,,,,,,,,,,,,,,,,,+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXXX+XX##99##XX+XXXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+&.@.&.@.&.@.&.@.&.@.&.@X..####..X@.&.@.&.@.&.@.&.@.&.@.&+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXX+XX...##...XX+XXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+*&*@*&*@*&*@*&*@*&*@*&X&@&@88&@&@X&*@*&*@*&*@*&*@*&*@*&*+^X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:90:Hellpit
+X:8:20:19:60
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..........................................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X@@&....#8.#9....^^&&&&&&&&&&&&###.^^,,......+8*9+,,,,,X.%
+D:%.X@&@.............^^................^^,,......+9*9+,,,,,X.%
+D:%.X&@@.............^^@@@@@@@@@@@###..^^,,......+9*9+,,,,,X.%
+D:%.X.....#8....#9...^^................^^,,......+9*9+,,,,,X.%
+D:%.X................^^&&&&&&&&&&&&###.^^,,.&&&&&+9*9+,,,,,X.%
+D:%.X.......@@@@.....^^................^^,,.&@@@&+9*9+,,,,,X.%
+D:%.#....#8.@@@@.#9..^^@@@@@@@@@@@###..^^,,.&@9@&+8*9+,,,,,X.%
+D:%.X.......@@@@.....^^................^^,,.&@@@&+9*9+,,,,,X.%
+D:%.X................^^&&&&&&&&&&&&###.^^,,.&&&&&+9*9+,,,,,X.%
+D:%.X.....#8....#9...^^................^^,,......+9*9+,,,,,X.%
+D:%.X&@@.............^^@@@@@@@@@@@###..^^,,......+9*9+,,,,,X.%
+D:%.X@&@.............^^................^^,,......+9*9+,,,,,X.%
+D:%.X@@&....#8.#9....^^&&&&&&&&&&&&###.^^,,......+8*9+,,,,,X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%..........................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:91:Roundabout Three
+X:8:30:20:97
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X,&,,,,,,,,,,,^^^^^^^^^^......XX.#X.XXX.......X.X.......XXX.X#.XX......^^^^^^^^^^,,,,,,,,,,,&,X%
+D:%X,&,,,,,,,,,,,^^^^^^^^^^.....XX.XX.XXX..XXXX..X.X..XXXX..XXX.XX.XX.....^^^^^^^^^^,,,,,,,,,,,&,X%
+D:%X,&,,,,,,,,,,,XXXXXXXXXX....XX.XX.XXX^^XX@@XX.X&X.XX@@XX^^XXX.XX.XX....XXXXXXXXXX,,,,,,,,,,,&,X%
+D:%X,&&&&&&&&&&XXX********XXX..XX.XX.XXX^^X****X.X&X.X****X^^XXX.XX.XX..XXX********XXX&&&&&&&&&&,X%
+D:%X,,,,,,,,,,XXX..XXXXXX...XX+XX.XX.XXX^^XX&&...X@X...&&XX^^XXX.XX.XX+XX...XXXXXX..XXX,,,,,,,,,,X%
+D:%X@@@@@@@@XXX..XXX****XXX.....XX.XX.XXX..XX...XX+XX...XX..XXX.XX.XX.....XXX****XXX..XXX@@@@@@@@X%
+D:%X9988899XXX..XXX.XXXX@@XXXXXX.XX.XX.XXX..XXXXX^^^XXXXX..XXX.XX.XX.XXXXXX@@XXXX.XXX..XXX9998999X%
+D:%X######XXX**X##&&@**XX&&&@98X^^^^^XX.##X^^^^^^^^^^^^^^^X##.XX^^^^^X89@&&&XX**@&&##X**XXX######X%
+D:%X######XXX**X##&&@**XX&&&@98X^^^^^XX.##X^^^^^^^^^^^^^^^X##.XX^^^^^X89@&&&XX**@&&##X**XXX######X%
+D:%X9988899XXX..XXX.XXXX@@XXXXXX.XX.XX.XXX..XXXXX^^^XXXXX..XXX.XX.XX.XXXXXX@@XXXX.XXX..XXX9998999X%
+D:%X@@@@@@@@XXX..XXX****XXX.....XX.XX.XXX..XX...XX+XX...XX..XXX.XX.XX.....XXX****XXX..XXX@@@@@@@@X%
+D:%X,,,,,,,,,,XXX..XXXXXX...XX+XX.XX.XXX^^XX&&...X@X...&&XX^^XXX.XX.XX+XX...XXXXXX..XXX,,,,,,,,,,X%
+D:%X,&&&&&&&&&&XXX********XXX..XX.XX.XXX^^X****X.X&X.X****X^^XXX.XX.XX..XXX********XXX&&&&&&&&&&,X%
+D:%X,&,,,,,,,,,,,XXXXXXXXXX....XX.XX.XXX^^XX@@XX.X&X.XX@@XX^^XXX.XX.XX....XXXXXXXXXX,,,,,,,,,,,&,X%
+D:%X,&,,,,,,,,,,,^^^^^^^^^^.....XX.XX.XXX..XXXX..X.X..XXXX..XXX.XX.XX.....^^^^^^^^^^,,,,,,,,,,,&,X%
+D:%X,&,,,,,,,,,,,^^^^^^^^^^......XX.#X.XXX.......X.X.......XXX.X#.XX......^^^^^^^^^^,,,,,,,,,,,&,X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:92:The Reward is Worth It
+X:8:20:16:63
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXX##XXXXXXXXXXXXX#XXXXXXXXXXXXX##XXXXXXXXXXXXXXX%
+D:%X@@@@@@@@@@@.XX88XX.......,,,X^X,,,.......XX88XX.@@@@@@@@@@@X%
+D:%X@XXXXXXXXXX..XXXX...XXXX.,,,X^X,,,.XXXX...XXXX..XXXXXXXXXX@X%
+D:%X@X8888888XXX..XX...XXX@XX,,,X^X,,,XX@XXX...XX..XXX8888888X@X%
+D:%X@X88899999XXX.....XXX@@@X..&X^X&..X@@@XXX.....XXX99999888X@X%
+D:%X@X8899.....XXX...XXX@@@@@..&X^X&..@@@@@XXX...XXX.....9988X@X%
+D:%X@X899.......XXX...XXX......&X^X&......XXX...XXX.......998X@X%
+D:%X+XXX...XXX&&&XXX^^^XXX.....&X^X&.....XXX^^^XXX&&&XXX...XXX+X%
+D:%X@@XXX.XXXX&&&&XXX^^^XXX....&X^X&....XXX^^^XXX&&&&XXXX.XXX@@X%
+D:%X^^^^XXX88X^^^^^^XXX^^^XXX..&X^X&..XXX^^^XXX^^^^^^X88XXX^^^^X%
+D:%X&&&&&&&&XX^^^^^^^^XXX...XXX&X^X&XXX...XXX^^^^^^^^XX&&&&&&&&X%
+D:%X,,,,,,,XX,,,,,,,,,,,XXX&&&XXX^XXX&&&XXX,,,,,,,,,,,XX,,,,,,,X%
+D:%X,,,,,,X#@@@@@@@@@@@@@@XXX&&&&&&&&&XXX@@@@@@@@@@@@@@#X,,,,,,X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:93:Little League Treasure Hoard
+X:7:2:5:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%....#...&...#....%
+D:%.#.#.##***##.#.#.%
+D:%....#...&...#....%
+D:%%%%%%%%%%%%%%%%%%%
+
+N:94:Mini Maze
+X:7:2:15:25
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................%
+D:%.X+XXXXXXXXXXXXXXXXXXX.%
+D:%.X.X,.......X........X.%
+D:%.X.X..XXX.X...XXXX.X.X.%
+D:%.X.XX.X...X.XXX..X...X.%
+D:%.X......X.X.X....XXX.X.%
+D:%.X.XXXXX..X.X.X..X,X.X.%
+D:%.X.X,..XXXX.X.X.XX.X.X.%
+D:%.X.XXX........X...XX.X.%
+D:%.X...XXXXXX.XXXXXXX..X.%
+D:%.X.X........X,.......X.%
+D:%.XXXXXXXXXXXXXXXXXXXXX.%
+D:%.......................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:95:Circlular Room
+X:7:2:8:9
+D:%%%%%%%%%
+D:%.......%
+D:%..###..%
+D:%.#+*+#.%
+D:%.#+*+#.%
+D:%..###..%
+D:%.......%
+D:%%%%%%%%%
+
+N:96:Minor Boss Vault
+X:7:3:10:10
+D:%%%%%%%%%%
+D:%........%
+D:%..XXXX..%
+D:%.XX.9XX.%
+D:%.X....X.%
+D:%.XX++XX.%
+D:%.XX^^XX.%
+D:%..X++X..%
+D:%........%
+D:%%%%%%%%%%
+
+N:97:(Lesser) Major Boss Vault
+X:7:20:10:10
+D:%%%%%%%%%%
+D:%........%
+D:%..XXXX..%
+D:%.XX.8XX.%
+D:%.X....X.%
+D:%.XX++XX.%
+D:%.XX^^XX.%
+D:%..X++X..%
+D:%........%
+D:%%%%%%%%%%
+
+N:98:(Greater) Majorly Bossy Vault
+X:8:37:10:10
+D:%%%%%%%%%%
+D:%........%
+D:%.@XXXX@.%
+D:%.XX88XX.%
+D:%.X8888X.%
+D:%.XX++XX.%
+D:%.XX^^XX.%
+D:%.@X++X@.%
+D:%........%
+D:%%%%%%%%%%
+
+N:99:Bubbles
+X:8:35:25:41
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXX#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X8X#X8XXX8XXX8XXX8XXX8XXX8XXX8XXX8XXX8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%XX.9.#.9.X.9.#.9.X.9.#.9.X.9.#.9.#.9.XX%
+D:%XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX%
+D:%X8XXX8X#X8X#X8X#X8X#X8X#X8X#X8X#X8X#X8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%XX.9.#.9.X.9.X.9.#.9.X.9.#.9.X.9.X.9..X%
+D:%XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX%
+D:%X8X#X8XXX8X#X8XXX8XXX8XXX8XXX8XXX8X#X8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%XX.9.X.9.#.9.X.9.#.9.#.9.#.9.#.9.X.9.XX%
+D:%XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX%
+D:%X8X#X8X#X8X#X8XXX8XXX8XXX8XXX8X#X8X#X8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%XX.9.#.9.X.9.#.9.#.9.#.9.#.9.#.9.X.9.XX%
+D:%XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX%
+D:%X8XXX8XXX8XXX8XXX8XXX8XXX8XXX8XXX8X#X8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%##.9.#.9.#.9.#.9.#.9.#.9.#.9.#.9.X.9.XX%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%X8XXX8XXX8XXX8XXX8XXX8XXX8XXX8XXX8XXX8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:100:Lesser Vault (Cross)
+X:7:10:13:20
+D:%%%%%%%%%%%%%%%%%%%%
+D:%########++########%
+D:%#*....*#..#*....*#%
+D:%#....&,#^^#,&....#%
+D:%#....,##..##,....#%
+D:%#+#####*..*#####+#%
+D:%#^^.....,,.....^^#%
+D:%#+#####*..*#####+#%
+D:%#....,##..##,....#%
+D:%#....&,#^^#,&....#%
+D:%#*....*#..#*....*#%
+D:%########++########%
+D:%%%%%%%%%%%%%%%%%%%%
+
+N:101:The I in the Storm
+X:8:30:25:41
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXX%
+D:%X&&..^..#9X..^^^^^^^^^^^^^..X9#..^..&&X%
+D:%X&...#....X..XXXXXX^XXXXXX..X....#...&X%
+D:%X...&#..#.X9XX.@8XX^XX8@.XX9X.#..#&...X%
+D:%X..&9#....XXX...@X,,,X@...XXX....#9&..X%
+D:%X^####..#...XX..XX,.,XX..XX...#..####^X%
+D:%X........,#..XX^X,,.,,X^XX..#,........X%
+D:%X.......#.....^XX,...,XX^.....#.......X%
+D:%X........,#...9X,,...,,X9...#,........X%
+D:%X.......#.....XX.......XX.....#.......X%
+D:%X.#......,#..XX^.......^XX..#,......#.X%
+D:%X.9#....#....#^^...9...^^#....#....#9.X%
+D:%X.#......,#..XX^.......^XX..#,......#.X%
+D:%X.......#.....XX.......XX.....#.......X%
+D:%X........,#...9X,,...,,X9...#,........X%
+D:%X.......#.....^XX,...,XX^.....#.......X%
+D:%X........,#..XX^X,,.,,X^XX..#,........X%
+D:%X^####..#...XX..XX,.,XX..XX...#..####^X%
+D:%X..&9#....XXX...@X,,,X@...XXX....#9&..X%
+D:%X...&#..#.X9XX.@8XX^XX8@.XX9X.#..#&...X%
+D:%X&...#....X&&XXXXXX^XXXXXX&&X....#...&X%
+D:%X&&..^..#9X..^^^^^^^^^^^^^..X9#..^..&&X%
+D:%XXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:102:Roundabout Two
+X:8:30:25:40
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%#^X.^^+X@XX.+X^^^^^+.X...X8#@&*X*****X%
+D:%X^X.^XX@XX.XX^^^^^^X.X.X^XXX@.&+9....X%
+D:%X^X.XX&XX.XX^^^^^^^X.X.X^X8#@&*X99...X%
+D:%X^X.X^^X&.XXXXXXXXXX.X.X^XXXXXXXXXX++X%
+D:%X^X.X.*X&.X.......&..X.X^X........X^^X%
+D:%X^X&X.*X^^X.XXXXXXXXXX.X&X#XXXXXX.X^.X%
+D:%X^X.X..X^^X...@........X.X......X.X^^X%
+D:%X^X.X..X^^XXXXXXXXXXXXXX.XXXXXX.X.X.^X%
+D:%X^X.X..X^^X..,.....,....&X8#,*X.X.X^^X%
+D:%X^X&X,,X^^X^XXXXXXXXXXXXXX##,,X.X.X^.X%
+D:%X^+&X..+^^X^^^^^^^^^^^^^^^9...#.X.#^^X%
+D:%X^X&X,,X^^X^XXXXXXXXXXXXXX##,*X.X.X.^X%
+D:%X^X.X..X^^X..,.....,....&X8#,,X.X.X^^X%
+D:%X^X.X..X^^XXXXXXXXXXXXXX.XXXXXX.X.X^.X%
+D:%X^X.X..X^^X...@........X.X......X.X^^X%
+D:%X^X&X.*X^^X.XXXXXXXXXX.X&X#XXXXXX.X.^X%
+D:%X^X.X.*X&.X.......&..X.X^X........X^^X%
+D:%X^X.X^^X&.XXXXXXXXXX.X.X^XXXXXXXXXX++X%
+D:%X^X.XX&XX.XX^^^^^^^X.X.X^X8#@&*X99...X%
+D:%X^X.^XX@XX.XX^^^^^^X.X.X^XXX@.&+9....X%
+D:%#^X.^^+X@XX.+X^^^^^+.X...X8#@&*X*****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:103:Modified Greater Vault (Huge)
+X:8:45:17:39
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8X.X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X#X%
+D:%X8X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8X8X.X%
+D:%X#X#XXXXXXXXXXXXXXXXXXXXXXXXXXX#X#X#X%
+D:%X8X8X8#8#8#8#8#8#8#8#8#8#8#8#8#8X8X.X%
+D:%X#X#X#XXXXXXXXXXXXXXXXXXXXXXXXXXX#X#X%
+D:%X8X8X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8X.X%
+D:%X#X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#.X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:104:The Bank from Hell
+X:8:30:20:31
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXX+XXXXXXXXXXXXXX%
+D:%X.&.&.&.&.&.#...#.&.&.&.&.&.X%
+D:%X.#.#.#.#.#.#...#.#.#.#.#.#.X%
+D:%X...........#...#...........X%
+D:%X##########+##+##+##########X%
+D:%X@........^^^^^^^^^........@X%
+D:%X@^^^.....^^^...^^^.....^^^@X%
+D:%X##+#######+#####+#######+##X%
+D:%X.^^^.#@..^^^...^^^..@#.^^^.X%
+D:%X#...##...............#.###.X%
+D:%X@...@#.&.&.&.&.&.&.&.#..@..X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+D:%X.+^*****X*******^+^******X.X%
+D:%X@X^....^X^......^X^.....*X@X%
+D:%X.X*****^+^*******X*******X.X%
+D:%X@XXXXXXXXXXXXXXXXXXXXXXXXX@X%
+D:%X.@.@.@.@.@.@.@.@.@.@.@.@.@.X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+# Between vaults from weisiger
+N:105:The Between Vault
+X:8:15:6:25
+D:XXXXXXXXXXXXXXXXXXXXXXXXX
+D:#,,,,,X&...@X..**&X....9X
+D:#...&1X.,,,2X..**&X3...9X
+D:#...&.X1,,,.X2.**3X....9X
+D:#,,,,,X&...@X..**&X....9X
+D:XXXXXXXXXXXXXXXXXXXXXXXXX
+
+N:106:Greater Vault (Mix&Match)
+X:8:35:28:73
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................................................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X1.^^^^*&XX,,,9,,,XX...X...X...X&..X@..X@.8X7X8#X8#X8#X8#X8#X8#X8#.7X.%
+D:%.X..^^^*,XX@&@&@&@&X.X...X...X..#X&..X&..X@.#XXX#8XX8XX8XX8XX8XX8XXXXX.%
+D:%.X^^^^*,XXXX.......X6.X...X...X.#.X&..X@..X@.8X8XXXXXXXXXXXXXXXXXX88XX.%
+D:%.X^^^*,XX&&XX.....XXXXXXXX.X...X#..X&.#X&..X@.XX#9#9#9#9X88XX^^XX#8XXX.%
+D:%.X^^*,X#^^^^XX^XXX.X***&@XXXX...X...X&#.X@..X@X8X9X9X9X9X8#X^^XX8#X#8X.%
+D:%.X^*,XX^^^^^^XX^XX5X***@&,,XXX...X...X#..X&..XX#X#X#X#X#XXX^^XX##XX88X.%
+D:%.X*,XX........XX^XXX***&@,,,,XXX..X..#X&..X@..X8X8X8X8X8XX^^XX88XXXXXX.%
+D:%.X&XX..........XX^XX***@&,,,,#.XXX.X.#.X&..X&.X#X#X#X#X#X^^X#8XXXX,#.X.%
+D:%.XXX************XX6X@&@&@,,,,#...XXXX#..X&.#X@X8X8X8X8X8#XXXXXX,,,,#.X.%
+D:%.XX&,&,&,&,&,&,&,XXXX@&@&,,,,#.....XXX...X&#.XX8X8X8X8X8XXXX,,,,,,,#.X.%
+D:%.XX#************XX.^#X,,,,,,,#.......XXXXXXXXXX8X8X8XXXXX@&#,,,,,,XX#X.%
+D:%.X^XX..........XXX.XXXX,,,,,,#................X8XXXXX&&#&@&#,,XXXXX#.X.%
+D:%.X.XXX........XX3X^X99XXXXXXXXXXXXXXX#XXXXXXX.XXXX,#&&&#&@&XXXX,#^X#.X.%
+D:%.X.XXXX......XXX.X.X@@,,,,,,,,,,,,X1X.......X.X,,,,#&&&#XXXX,,,,#^X.#X.%
+D:%.X^XXXXX....XXXX.^.XXXXXXXXXXXXXX*X^X+XXXXX.X.X,,,,#&&XXX##9,,,,#^X.#X.%
+D:%.X.X^^.XX@@XXXXXXXXX9@&,,,,,,,,,X*X.X^^&,,X.X.X#####XXX#9@##@,,,#^X#.X.%
+D:%.X.X^X.XXXXX^^^XXXXXXXXXXXXXXXX,X*X.X^^^,,X.X.X&&&XXX@8##&@##@,,#^X#.X.%
+D:%.X^X.X2XXXX3^^^XXX.^..^..^..^.X,X*X^X&^^^&X.X.X##XX5.@89##9@##&,#^#.#X.%
+D:%.X.X^XXXXXXXXX^^XX.XXXXXXXXXX.X,X*X.X..^^^X.X.X^XXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X.X^^.^..^..X^^^X.^..^..^.4X^X,X*X.X2.&^^+.+.X.^.^.^.^.^.^.^.^.^.^.4X.%
+D:%.X^XXXXXXXXX^X^^^XXXXXXXXXXXX#X#X#X^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X..^..^..^..X^^^#................X..^..^..^..^..^..^..^..^..^..^..^.+.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.......................................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+# Wilderness vault test
+N:107:The Wilderness Vault
+X:10:1:3:7
+D:XXXXXXX
+D:T,,,,8X
+D:XXXXXXX
diff --git a/lib/edit/volcano.txt b/lib/edit/volcano.txt
new file mode 100644
index 00000000..1b89cf3d
--- /dev/null
+++ b/lib/edit/volcano.txt
@@ -0,0 +1,83 @@
+# File: volcano.txt
+
+# Stairway to the Hell
+F:$:7:3:0:0:0:0:0:6
+
+# Hole to the center of the Volcano
+F:>:7:3:0:0:0:0:0:5
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL$LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^>^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:######################################################################################################################################################################################################
+
+
+############### SLarting positions ###############
+
+# Standard starting position for normal races
+?:[EQU $LEAVING_QUEST 0]
+P:64:80
diff --git a/lib/edit/w_info.txt b/lib/edit/w_info.txt
new file mode 100644
index 00000000..65efc2fc
--- /dev/null
+++ b/lib/edit/w_info.txt
@@ -0,0 +1,120 @@
+# PernAngband wilderness definition file by DarkGod (darkgod@pernangband.org)
+# with the help form Gwidon S. Naskrent (naskrent@artemida.amu.edu.pl)
+# Designed to "look like" Middle-earth map
+
+W:D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+W:D:XgggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:XgggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:Xggggggggggg=========g=========gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:Xgggggg========t===ggg==========gggggtggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:Xggggg=========gtgg^g======ggg=gggggggggggtggtggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:Xggg=========gg^t^^g========ggggt^g^ttggtgtgggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:X==========,,,,&__ttgg=ggg=ggggt^^%t^^^tg&ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:X========..tt&&&^__,ttttttttttttt,gttttt&&&&ggtggggggggggtgggggtgggggggggggggggggtggggggggggggggtgggX
+W:D:X===^===....,&&&,t__,,,,,,g,t,,,,,,,,tttgt&^^&g&g&ggtggggggggggggggggtttggtgggggggtgggtgggggtgggggggX
+W:D:X=========.,.&&,,,,__t,,,,,t,,,,t,t,,,,,tttt&t&^MMM&ggggg&g&&&gggttttttgtttgttttttttttttttttttttttttX
+W:D:X=========.,.&&,,_,__,,,,,,,,,,,,,,,,,,,,,tttg...2Mt&&&&&&&t&t&&&&tgttttttttttttgtttttttttttttttttttX
+?:[EQU $TOWN_DESTROY2 1]
+W:M:0:1
+W:D:X=========.,.&&,,_,__,,,,,,,,,,,,,,,,,,,,,tttg...PMt&&&&&&&t&t&&&&tgttttttttttttgtttttttttttttttttttX
+?:1
+W:D:X========..T.&___.___,,^,,,,,,,,,,,,,,,,,,tttt.&MMM^^__t^&&&,t^^ttttt,t,t,ttttttttttttttttttttttttttX
+W:D:X======.,..__&&,,,,__,,^^,,,,,,,,,,,,,,,,,t....t&&t^^__^__&.&,&&&^^,,t,,,,,,,,t,t,t,ttttttttttttttttX
+W:D:X=====,..__.T&&..,,__,,^^,,,,.,,,^^,,,,,,,,^^^t^&&&&,__^__tTTT,,,,,,,,,,,,t,,,,,,,,,,,,,t,ttttttttttX
+W:D:X===....__.,.&&,.,,__,,_^,,,,,,,,^^,,,,,,,,^^,^^^_&_^^__TT__T_TT,,&_,,,,,,,,,,,,,^,^,t,,,,,,t,ttttttX
+W:D:X===..,.__.TT&&..,__,__^^==,,.,^^,,.,,.,,,,^^____^&&___,TTTT_T__,,__,,,,^^,^^^^^^^^,,,,,t,,,,,,,,,,tX
+W:D:X===....__..T&&....__,^^=,__....,.....,,.,,^__^^,^&&,__,TTTTT__T_==,,,,,,,^_,,^,,,,,,,,,,,,,,t,t,,,,X
+W:D:X===...__..TT&&...__,.^^^..__.........,,,,,__^^^^^&&,__,TTTTTT_TT_=,,,,,,,__,,,,,,,,,,,,,,,,,,,,,,t,X
+W:D:X===...__..TT&&&..__..^..,.__...,..^..,,,,__^.^^^^&&,__,TTTTT&T&T__,,,,,,,,,__,,,,,,,,,,,,,,,,,,,,,,X
+W:D:X===....==..T.&..__..,.....__TTT....^^...__..TTT._&&..__,TTT&T&T&T__,,,,,,,,,__,,,,,,,,,,,,,,,,,,,,,X
+W:D:X====...==.....==......^...__TTTT.1.^^..,__...T__&&...__.TTTTTTTTT__,,,,,,,,__,,,,,,,,,,,,,,,,,,,,,,X
+W:D:X=====..========...^.^......__TTT._.^....__..,__._&...__.TTTTTTTTTT,__,,,,,,,__,,,,,,,,,,,,,,,,,,,,,X
+W:D:X==============..............__TT........__..__^_&&..,.__.TTTTTTTTT,__,,,,,,,,__,,,,,,,,,,,,,,,,,,,,X
+W:D:X======..==....&&............__..^^^....__...__^&&.....__.*TTTTTTT,,,__,,,,,,__,,,,,,,,,,,,,,,,,,,,,X
+W:D:X======........&&......,.....__...^.^...__.__.^^&&..._.__.TTTTTTTT..,,______,__,,,,,,,,,,,,,,,,,,,,,X
+W:D:X======........&&............__.,......__..__.^^&&___.___.TTTTTTTT....,,.,,,__,,,,,,,,,,,,,,,,,,,,,,X
+W:D:X======........&&....^......__..........___...^^&&.....__.TTTTT.T.,.....,,,,,__,,,,,,,,,,,,,,,,,,,,,X
+W:D:X=======.....T&&&..^^^^....__..........__....^^&&^...,__...TTTT......,....,,,__,,,,,,,,,,,,,,,,,,,,,X
+W:D:X==========..T&&&T.......__..........__......^^&&&&^..__...TTTT...........,,,,__,,,_,,,,,,,T,T,,,,,,X
+W:D:X==========..TTT&&T&&...__........,___......^)^&&.&^.__.....TTTTTT....,.....,,__,__,_=,,,TTTTTT,,,,,X
+W:D:X==========...TT&TT..___.__.......__.@__..._^^^&&....__..TTTTTTTTTT...........,,_,.,,==...T=_TT,,,,,X
+W:D:X==========.....T.T.__.._........__..._____^___&__...__,TTTTTTTTTT...,..,..,....,,,,,========TT,,,,,X
+W:D:X===========.=......__.........__.........^^^&&&_T,T__,.TT&TTTTTTT..........,.,.....=========T,,,,,,X
+W:D:X================..__..........__,.......^.^M&&._T4T__..TTTTTTTTT......,......,.....=====..==,,,,,,,X
+W:D:X=================.==T....,...__.........^^^MM&,.TTT.__...TTTTT..........,..........========,,.,,,,,X
+W:D:X===================TT........__.........^^MMMTT.T.^.^__^^........,......,,......^^..=======,,,.,.,,X
+W:D:X===================T==......__......,...^^M)MTTTT^___^.__^.,....................^,..==...==..,,.,.,X
+W:D:X===================T==.....__...........^&MgMMTTTTT..___^^................,..,..^^.......=.....,.,,X
+W:D:X=====================.....__...,........^&M5MTTTTTT.^^^__.....,..,......,,,.....^^...,......,......X
+W:D:X=====================.....=_............&&MMMTTTTT..^^..__.,.........,.........,^^.......,.........X
+W:D:X======================...==........,....&&&&&T.._......__..,..................................,..,.X
+W:D:X=======================.===.............._&^.....__..,...__.....,.........,..,,,...,...,...........X
+W:D:X===========================..............__.......__....__......,.......,...........,..............X
+W:D:X==========================.........._._..__.......__...__^..^,..............................,..,...X
+W:D:X==========================...._.,.__._.___........__...^^_^^@.....,..,.....,.,,....,,....,.,.,.....X
+W:D:X==========================..__.__.___._..&&^^.....__...^^_^^_@..&.&.....,.......,....,.............X
+W:D:X============================....._..._.__.&&&.....__....__.@...&&DD&&....,..................,.,..,.X
+W:D:X===========================.............._&&&^^....__...___....&&D^^D&&.&.&.&.&.&.&.&.&^^^,,,,,,,,,X
+W:D:X===========================.......^.&.^^&&&&&&&......______.....&&DDD&^&^&D&D&D&,&,&,&,,,,,,,,,,,,,X
+W:D:X===========================.....^^.&.&_&^&.&^&_&&&^...._.___....&&^DDD&^DDDDDD^&_,,,,,,,,,,,,,D,D,,X
+W:D:X===========================....^....__^^...^^^__^&&........__...&&^D&DDDDDDD^^,_,__,,,,,,,,,,,,,,,,X
+W:D:X===========================..^^^_..__......^^.__^^&&&........__.&&^DDDDDDDDD^^,,,,__,,,,,D,,,,,,,,,X
+W:D:X============================.^__.__.__......__&^^^.&&&&&&&&&..__&&^DDDDDDD^__,,,,,,__,,,,,,,DDDD,,,X
+W:D:X============================.&^__.._....^^.__&&&^^.._&&&&&&&.^__&^^DDDDD^^,,__,,,,,,__,,,,,,,,,,,,,X
+W:D:X============================^&^__.^^^^^^^^...__...__^&^&&&&&.__^&&^DDD^^^,,,,__,,,D,,__,,,,,,,D,,D,X
+W:D:X===========================.^^.__..^.^.........___..^&^^.^^3.__.&&^D^D^^,,,,__,,D,,,D,__,,,D,,,,,,,X
+W:D:X==========================.^^^..__....===.====__..&^...._^...__.&&,^,^,,,,,,,____,,,,,__,,,,,,,,,,,X
+W:D:X==========================^^....__..===========.&&^....__....__.$&,,,,,,,,D,,,,,=_,,__,,,,,D,,D,D,,X
+W:D:X========================..^^=...=_.==========&^^^^.._.__....__..&&,,,,,,,,,,,,,,==__,,&,,,,,,,,,,,,X
+W:D:X======================^^.^=====.==============^^^._=._......__.._&&,,,,,,,,,======,,,,&&,,D,D,D,D,,X
+W:D:X==============================================.^^^==...._.__..__.&&,,,___,_======,D,,&&,D,,,D,,,DD,X
+W:D:X===============================================..====___.__.__...&&,__,,D_,,D,,=_,,,D&&,D,DD,DDD,DDX
+W:D:X===============================================.==^==_@@..._.....&&_,,,,,,,,,,,__,&&&&DDDDDDDDD,,DDX
+W:D:X=================================================^^===...........&&,&,&,&,&,&,&__&&&DD,DD,DDD,D,,DDX
+W:D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Definition of all the entrances to the dungeons
+# W:E:<dungeon>:<y>:<x>
+
+# Numenor
+W:E:7:25:1
+
+# Path of the Dead
+W:E:16:49:38
+
+# Illusory Castle
+W:E:17:34:42
+
+# Maze
+W:E:18:25:35
+
+# Orc Cave
+W:E:19:15:32
+
+# Erebor
+W:E:20:17:77
+
+# Old Forest
+W:E:21:21:31
+
+# The Sacred Land Of Mountains
+W:E:25:37:80
+
+# The Wild Land Of Rhun
+W:E:26:30:75
+
+# The Sandworm Lair
+W:E:27:28:10
+
+# The Grinding Ice
+W:E:29:3:3
+
+# Dol Guldur
+W:E:23:30:60
+
+# Cirith Ungol
+W:E:9:56:65
+
+
+# Starting position
+W:P:34:21
diff --git a/lib/edit/wf_info.txt b/lib/edit/wf_info.txt
new file mode 100644
index 00000000..80ab14a6
--- /dev/null
+++ b/lib/edit/wf_info.txt
@@ -0,0 +1,170 @@
+# File: wf_info.txt
+
+
+# This file is used to initialize the "lib/raw/wf_info.raw" file, which is
+# used to initialize the "wilderness feats" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/wf_info.raw" file.
+
+# The wilderness feat indexes are defined in "defines.h", and must not be
+# changed.
+
+# N:<index>:<name>
+# D:<long name>
+# W:<level>:<entrance>:<road>:<feat>:<terrain_idx>:<character(must be unique)>
+# F:<flags>
+# X:<feat1>...<feat18>
+
+# Note for <road> :
+# 1 = NORTH
+# 2 = SOUTH
+# 4 = EAST
+# 8 = WEST
+
+# Note for <entrance> :
+# if < 1000 then it points to a town
+# if >= 1000 then it points to the x - 1000 dungeon type
+
+# Version stamp (required)
+
+V:2.0.0
+
+N:0:Ekkaia
+D:the Encircling Sea
+W:1:0:0:182:0:X
+X:182:182:182:182:182:182:182:182:182:182:182:182:182:182:182:182:182:182
+
+N:1:Bree
+D:a small village
+W:1:1:0:203:1:1
+X:88:88:89:89:89:89:96:96:96:96:96:96:96:96:96:96:96:96
+
+N:2:Gondolin
+D:The hidden town of the Noldor
+W:1:2:0:203:1:2
+X:88:88:88:89:89:89:89:89:89:89:89:89:89:96:96:96:96:96
+
+N:3:Minas Anor
+D:The great town of Gondor
+W:1:3:0:203:1:3
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:4:Lothlorien
+D:The land of Galadriel
+W:1:4:0:203:1:4
+X:88:88:96:96:96:96:96:96:96:96:96:96:96:96:96:89:89:89
+
+N:5:grass
+D:a plain of grass
+W:5:0:0:89:6:.
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:6:forest
+D:a forest
+W:20:0:0:96:7:T
+X:88:88:96:96:96:96:96:96:96:96:96:96:96:96:96:89:89:89
+
+N:7:road
+D:a west-east road
+W:5:0:12:1:6:-
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:8:road
+D:a north-south road
+W:5:0:3:1:6:|
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:9:mountain
+D:a mountain chain
+W:50:0:0:97:11:&
+X:1:1:89:89:88:96:96:97:97:97:97:97:97:97:97:97:97:97
+
+N:10:road
+D:a west-east-south road
+W:5:0:14:1:6:,
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+# XXX
+
+N:12:The Nether Realm
+D:the entrance to the netherworld
+W:127:1006:0:7:10:6
+X:88:88:88:86:86:86:85:85:85:85:85:85:85:85:85:97:97:97
+
+N:13:deep water
+D:a deep water area
+W:70:0:0:187:2:=
+X:187:187:187:187:187:187:187:187:187:187:187:187:84:84:84:84:84:84
+
+N:14:shallow water
+D:a shallow water area
+W:20:0:0:84:3:_
+X:187:187:187:84:84:84:84:84:84:84:84:84:84:84:84:1:88:89
+
+N:15:Mirkwood
+D:The Forest of Mirkwood
+W:20:1001:0:7:7:*
+X:88:88:96:96:96:96:96:96:96:96:96:96:96:96:96:89:89:89
+
+N:16:Mordor
+D:The Gates of Mordor
+W:50:1002:0:7:11:$
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:17:Angband
+D:The Pits of Angband
+W:50:1003:0:7:11:%
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:18:hill
+D:a hill
+W:50:0:0:97:11:^
+X:1:1:89:89:88:96:96:97:97:97:97:97:97:97:97:97:97:97
+
+N:19:desert
+D:a desert
+W:5:0:0:91:6:D
+X:1:1:88:88:91:91:91:91:91:91:91:91:91:91:91:98:98:92
+
+N:20:jungle
+D:a jungle
+W:20:0:0:96:7:t
+X:88:88:96:96:96:96:96:96:96:96:96:96:96:96:96:89:89:89
+
+N:21:swamp
+D:a swamp
+W:5:0:0:89:6:@
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:22:glacier
+D:a glacier
+W:20:0:0:90:7:g
+X:94:94:90:90:90:90:90:90:90:90:90:90:90:90:90:90:92:92
+
+N:23:grass
+D:a plain of grass
+W:5:0:0:89:6:,
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:24:Moria
+D:The Doors of Moria
+W:30:1022:0:7:11:)
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:25:high mountain
+D:a high mountain chain
+W:80:0:0:101:11:M
+X:101:101:101:101:101:101:101:101:101:101:101:101:101:101:101:101:101:101
+
+N:26:Gondolin
+D:The pillaged city of the Noldor
+W:1:2:0:203:1:P
+X:49:49:49:88:88:88:92:92:92:92:93:93:94:94:94:174:205:205
+
+N:27:Khazad-dum
+D:The dwarven stronghold
+W:1:5:0:203:1:5
+X:1:1:1:1:1:1:1:1:1:1:88:88:88:88:88:88:88:88
diff --git a/lib/edit/wights.map b/lib/edit/wights.map
new file mode 100644
index 00000000..d35c20ee
--- /dev/null
+++ b/lib/edit/wights.map
@@ -0,0 +1,82 @@
+# Permanent wall
+F:X:63:3
+
+# up stairs
+F:<:6:3
+
+# Floor with mountain
+F:^:97:3
+
+# Floor
+F:.:1:3
+
+# Floor with dirt
+F:;:88:3
+
+# Floor with forest wight
+F:f:88:3:381
+
+# Floor with grave wight
+F:g:88:3:470:0:0:0:0:0:0:2
+
+# Floor with barrow wight
+F:b:88:3:499:0:0:0:0:0:0:2
+
+# Floor with Emperor Wight
+F:e:88:3:604:0:0:0:0:0:0:2
+
+# Floor with a Human Skeleton
+F:k:88:8:0:395
+
+# Marker
+F:,:172:6
+
+# between gate 1
+F:1:160:6:0:0:0:0:0:2057
+
+# between gate 2
+F:2:160:6:0:0:0:0:0:1036
+
+# between gate 3
+F:3:160:6:0:0:0:0:0:3847
+
+# between gate 4
+F:4:160:6:0:0:0:0:0:2321
+
+# between gate 5
+F:5:160:6:0:0:0:0:0:1043
+
+# between gate 6
+F:6:160:6:0:0:0:0:0:3599
+
+# between gate 7
+F:7:160:6:0:0:0:0:0:2071
+
+# between gate 8
+F:8:160:6:0:0:0:0:0:3350
+
+# between gate 9
+F:9:160:6:0:0:0:0:0:771
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X..k^^^^^^^^^^^^^^^^^^^^^^^XX
+D:Xfkff^^^^^...^^^^..ff^^^^^^XX
+D:X^f1^^^^^^.ffg^^^^.fgg^^^^^XX
+D:X^^^^^^^^^^^fg4^^^^f6^^^^^^XX
+D:X^^^^^^^^^^^^f^^^^^^^^^gb8^XX
+D:X^^^^^^.f^^^^^^^^^^^^.fgb^^XX
+D:X^^^^.ff2^^^^^^.^^^^^^.g^^^XX
+D:X^^^^^3.^^^^^^^f^^^^^^^^^^^XX
+D:X^^^^^^^^^^^^bg.^^^^^^^^^^^XX
+D:X^^^^^^^^^^^7bgf^^^^^^^^f^^XX
+D:X^^^^^^^^^^^^^^^^^^^..^..^^XX
+D:X^^^^^^^^^^^^.^^^^^^...ffg^XX
+D:X^^^^...^^^^^ff^^^^^^.fgb^^XX
+D:X^^^.fff^^^^bgb^^^^..fgbee^^X
+D:X^^^^g5^^^^.g8^^^^^f^fgbe,9^X
+D:X^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:3
diff --git a/lib/edit/wolves.map b/lib/edit/wolves.map
new file mode 100644
index 00000000..0e3030ea
--- /dev/null
+++ b/lib/edit/wolves.map
@@ -0,0 +1,55 @@
+# permanent wall
+F:X:61:0
+
+# granite
+F:#:57:0
+
+# up staircase
+F:<:6:0
+
+# Grass
+F:-:89:0
+
+# Dirt
+F:.:88:0
+
+# Trees
+F:t:96:0
+
+# Open door
+F:D:4:0
+
+# Broken door
+F:d:5:0
+
+# Grass with elf skeleton
+F:z:89:0:0:397
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X...t.---.......-.-.....-...#.--X
+D:X-..#..-......-.....--......t...X
+D:X...t.--.tt#ddt##t#dd#t#....#...X
+D:Xz-.t....#.--...#...-..#.--.t...X
+D:X#d##....#.z.z..t---...t....#tD#X
+D:X....---.t......t..-.z.#..z.....X
+D:X...--.-.#...z..#.--...t........X
+D:X##t#-z-.#####dd#dd##tt#....#t#tX
+D:X..-t.--.t....-.t...--.#.---t...X
+D:X.--t---.t......#..--z-#----#-..X
+D:X...D....#.--z...---.--t--.-d--.X
+D:X...#....#........---..#--..#z-.X
+D:X#t#t....t..-...t-z-...t....#tt#X
+D:X..-.....#-..-..#......#.....--.X
+D:X...-.--.#dd#ttt##t##Dd#.....--.X
+D:X#Dt#....#-.....#......#....##t#X
+D:X...#...-t----..#......t...-tz--X
+D:X.z.t...-#--.-..t......#.---#-..X
+D:X.--t.---#-z.--.#.....zt--..d-..X
+D:X---#....###dd#tt##dd###--..t...X
+D:X.z-t..-...-....-..-.--.....#<zzX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:4
+
diff --git a/lib/file/book-0.txt b/lib/file/book-0.txt
new file mode 100644
index 00000000..07403e0d
--- /dev/null
+++ b/lib/file/book-0.txt
@@ -0,0 +1,86 @@
+
+ Mordekainen's Magical Compendum of Deep Thought.
+ ------------------------------------------------
+
+If they ever come up with a swashbuckling School, I think one of the
+courses should be Laughing, Then Jumping Off Something.
+
+It takes a big man to cry, but it takes a bigger man to laugh at that man.
+
+The people in the village were real poor, so none of the children had
+any toys. But this one little boy had gotten an old enema bag and
+filled it with rocks, and he would go around and whap the other
+children across the face with it. Man, I think my heart almost
+broke. Later the boy came up and offered to give me the toy. This was
+too much! I reached out my hand, but then he ran away. I chased him
+down and took the enema bag. He cried a little, but that's the way of
+these people.
+
+Dad always thought laughter was the best medicine, which I guess is
+why several of us died of tuberculosis.
+
+Maybe in order to understand mankind, we have to look at the word
+itself: "Mankind". Basically, it's made up of two separate words -
+"mank" and "ind". What do these words mean? It's a mystery, and
+that's why so is mankind.
+
+Ambition is like a frog sitting on a Venus Flytrap. The flytrap can
+bite and bite, but it won't bother the frog because it only has little
+tiny plant teeth. But some other stuff could happen and it could be
+like ambition.
+
+I'd rather be rich than stupid.
+
+We tend to scoff at the beliefs of the ancients. But we can't scoff at
+them personally, to their faces, and this is what annoys me.
+
+Probably the earliest flyswatters were nothing more than some sort of
+striking surface attached to the end of a long stick.
+
+As the evening sky faded from a salmon color to a sort of flint gray,
+I thought back to the salmon I caught that morning, and how gray he
+was, and how I named him Flint.
+
+When I was a kid my favorite relative was Uncle Caveman. After school
+we'd all go play in his cave, and every once in a while he would eat
+one of us. It wasn't until later that I found out that Uncle Caveman
+was a bear.
+
+Why do there have to be rules for everything? It's gotten to the point
+that rules dominate just about every aspect of our lives. In fact, it
+might be said that rules have become the foot-long sticks of mankind.
+
+If I had a mine shaft, I don't think I would just abandon it. There's
+got to be a better way.
+
+If I had a nickname, I think I would want it to be "Prince of
+Weasels", because then I could go up and bite people and they would
+turn around and go, "What the-?" And then they would recognize me, and
+go, "Oh, it's you, the Prince of Weasels."
+
+It's amazing to me that one of the world's most feared diseases would
+be carried by one of the world's smallest animals: the real tiny
+dog.
+
+Sometimes life seems like a dream, especially when I look down and see
+that I forgot to put on my pants.
+
+I bet it was pretty hard to pick up girls if you had the Black Death.
+
+It's fascinating to think that all around us there's an invisible
+world we can't even see. I'm speaking, of course, of the World of the
+Invisible Scary Skeletons.
+
+Whenever I hear the sparrow chirping, watch the woodpecker chirp,
+catch a chirping trout, or listen to the sad howl of the chirp rat, I
+think: Oh boy! I'm going insane again.
+
+He was the kind of man who was not ashamed to show affection. I guess
+that's what I hated about him.
+
+The next time I have meat and mashed potatoes, I think I'll put a very
+large blob of potatoes on my plate with just a little piece of
+meat. And if someone asks me why I didn't get more meat, I'll just
+say, "Oh, you mean this?" and pull out a big piece of meat from inside
+the blob of potatoes, where I've hidden it. Good magic trick, huh?
+
diff --git a/lib/file/book-1.txt b/lib/file/book-1.txt
new file mode 100644
index 00000000..014932f5
--- /dev/null
+++ b/lib/file/book-1.txt
@@ -0,0 +1,83 @@
+
+ Mordekainen's Magical Compendum of Deep Thought, Vol. 2
+ -------------------------------------------------------
+
+
+It makes me mad when people say I turned and ran like a scared
+rabbit. Maybe it was like an angry rabbit, who was running to go fight
+in another fight, away from the first fight.
+
+Perhaps, if I am very lucky, the feeble efforts of my lifetime will
+someday be noticed, and maybe, in a small way, they will be acknowledged
+as the greatest works of genius ever created by Man.
+
+Sometimes I think I'd be better off dead. No, wait, not me, you.
+
+If you ever catch on fire, try to avoid looking in a mirror, because I
+bet that will really throw you into a panic.
+
+Children need encouragement. If a kid gets an answer right, tell him
+it was a lucky guess. That way he develops a good, lucky feeling.
+
+The crows seemed to be calling his name, thought Caw.
+
+If your friend is already dead, and being eaten by vultures, I think
+it's okay to feed some bits of your friend to one of the vultures, to
+teach him to do some tricks. But only if you're serious about adopting
+the vulture.
+
+Broken promises don't upset me. I just think, why did they believe me?
+
+One thing vampire children have to be taught early on is, don't run
+with a wooden stake.
+
+Consider the daffodil. And while you're doing that, I'll be over here,
+looking through your stuff.
+
+I think my new thing will be to try to be a real happy guy. I'll just
+walk around being real happy until some jerk says something stupid to
+me.
+
+I hope some animal never bores a hole in my head and lays its eggs in
+my brain, because later you might think you're having a good idea but
+it's just eggs hatching.
+
+Whenever you read a good book, it's like the author is right there, in
+the room talking to you, which is why I don't like to read good books.
+
+What is it about a beautiful sunny afternoon, with the birds singing
+and the wind rustling through the leaves, that makes you want to get
+drunk?
+
+Instead of a trap door, what about a trap window? The guy looks out
+it, and if he leans too far, he falls out. Wait. I guess that's like a
+regular window.
+
+If I ever get real rich, I hope I'm not real mean to poor people, like
+I am now.
+
+Most of the time it was probably real bad being stuck down in a
+dungeon. But some days, when there was a bad storm outside, you'd look
+out your little window and think, "Boy, I'm glad I'm not out in that."
+
+Sometimes you have to be careful when selecting a new name for
+yourself. For instance, let's say you have chosen the nickname "Fly
+Head." Normally you would think that "fly Head" would mean a person
+who has beautiful swept-back features, as if flying through the
+air. But think again. Couldn't it also mean "having a head like a
+fly"? I'm afraid some people might actually think that.
+
+I hope that after I die, people will say of me: "That guy sure owed me
+a lot of money."
+
+The tired and thirsty prospector threw himself down at the edge of the
+watering hole and started to drink. But then he looked around and saw
+skulls and bones everywhere. "Uh-oh," he thought. "This watering hole
+is reserved for skeletons."
+
+Anytime I see something screech across a room and latch onto someone's
+neck, and the guy screams and tries to get it off, I have to laugh,
+because what is that thing.
+
+I hope life isn't a big joke, because I don't get it.
+
diff --git a/lib/file/book-10.txt b/lib/file/book-10.txt
new file mode 100644
index 00000000..51d43c60
--- /dev/null
+++ b/lib/file/book-10.txt
@@ -0,0 +1,250 @@
+The Large yellow snake is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Cave spider is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Wild cat is an uncommon monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+Smeagol is a unique monster,
+occurring at surface depths.
+He is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Green ooze is an uncommon monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Poltergeist is a common undead monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Metallic blue centipede is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Giant white louse is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Black naga is a common monster,
+occurring at surface depths.
+She is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Spotted mushroom patch is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Silver jelly is an uncommon monster,
+occurring at surface depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Yellow jelly is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Scruffy looking hobbit is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Giant white ant is a common monster,
+occurring at surface depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Yellow mold is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Metallic red centipede is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Yellow worm mass is an uncommon animal,
+occurring at surface depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Clear worm mass is an uncommon animal,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Radiation eye is a common monster,
+occurring at surface depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Cave lizard is a common animal,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Novice ranger is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has an inkling of magical powers.
+
+The Novice paladin is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has an inkling of magical powers.
+
+The Blue jelly is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Creeping copper coins is an uncommon animal,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Giant white rat is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Blue worm mass is a common animal,
+occurring at surface depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Large grey snake is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+Bullroarer the Hobbit is a unique monster,
+occurring at surface depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Novice mage is an uncommon monster,
+occurring at surface depths.
+He is laughably weak, just a small bit dangerous,
+and has rudimentary magical powers.
+
+The Green naga is a common monster,
+occurring at surface depths.
+She is extremely weak, just a small bit dangerous,
+and has no magical powers.
+
+The Blue ooze is a common monster,
+occurring at surface depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Green glutton ghost is a common undead monster,
+occurring at surface depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Green jelly is a common monster,
+occurring at surface depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Large kobold is a common monster,
+occurring at surface depths.
+It is extremely weak, just a little bit dangerous,
+and has no magical powers.
+
+The Skeleton kobold is a common undead monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Grey icky thing is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Disenchanter eye is an uncommon monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Red worm mass is a common animal,
+occurring at surface depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Copperhead snake is a common animal,
+occurring at surface depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Purple mushroom patch is an uncommon monster,
+occurring at surface depths.
+It is laughably weak, moderately dangerous,
+and has no magical powers.
+
+The Novice priest is an uncommon monster,
+occurring at surface depths.
+He is laughably weak, just a little bit dangerous,
+and has small magical powers.
+
+The Novice warrior is an uncommon monster,
+occurring at surface depths.
+He is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Novice rogue is an uncommon monster,
+occurring at surface depths.
+He is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Brown mold is a common monster,
+occurring at surface depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Giant brown bat is a common animal,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Novice archer is an uncommon monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has an inkling of magical powers.
+
+The Creeping silver coins is an uncommon animal,
+occurring at surface depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Snaga is a common orc,
+occurring at surface depths.
+He is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Rattlesnake is a common animal,
+occurring at surface depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Cave orc is a common orc,
+occurring at surface depths.
+He is extremely weak, just a little bit dangerous,
+and has no magical powers.
+
diff --git a/lib/file/book-101.txt b/lib/file/book-101.txt
new file mode 100644
index 00000000..e45865a7
--- /dev/null
+++ b/lib/file/book-101.txt
@@ -0,0 +1,4 @@
+nalo means shadow
+ure means sun
+ido means now
+nimir means shine or elf
diff --git a/lib/file/book-102.txt b/lib/file/book-102.txt
new file mode 100644
index 00000000..3b737923
--- /dev/null
+++ b/lib/file/book-102.txt
@@ -0,0 +1,4 @@
+gimli means star
+kadar means city
+izindi means starlight
+lomi means night
diff --git a/lib/file/book-103.txt b/lib/file/book-103.txt
new file mode 100644
index 00000000..0ffeea37
--- /dev/null
+++ b/lib/file/book-103.txt
@@ -0,0 +1,6 @@
+attu means father
+aru means king
+bawiba means wind
+dulgi means black
+balik means ships
+daira means Earth
diff --git a/lib/file/book-104.txt b/lib/file/book-104.txt
new file mode 100644
index 00000000..3b60e8ca
--- /dev/null
+++ b/lib/file/book-104.txt
@@ -0,0 +1,6 @@
+naur means fire
+mellon means friend
+Edain means Dunedain
+pedo means speak
+Pheriain means Halflings
+a minno means and enter
diff --git a/lib/file/book-105.txt b/lib/file/book-105.txt
new file mode 100644
index 00000000..f3667d64
--- /dev/null
+++ b/lib/file/book-105.txt
@@ -0,0 +1,7 @@
+baraz means red
+Baruk means Axes
+dum means halls
+Khazad means Dwarves
+gabil means great
+aimenu means upon you
+gathol means fortress
diff --git a/lib/file/book-106.txt b/lib/file/book-106.txt
new file mode 100644
index 00000000..81c4043c
--- /dev/null
+++ b/lib/file/book-106.txt
@@ -0,0 +1,5 @@
+dori means land
+hrassa means precipice
+Danas means Green-elves
+dunna means black
+garma means wolf
diff --git a/lib/file/book-107.txt b/lib/file/book-107.txt
new file mode 100644
index 00000000..1abc6d8e
--- /dev/null
+++ b/lib/file/book-107.txt
@@ -0,0 +1,6 @@
+nazg means ring
+ghash means fire
+snaga means slave
+burz means black
+ronk means pool
+bubhosh means great
diff --git a/lib/file/book-11.txt b/lib/file/book-11.txt
new file mode 100644
index 00000000..bd3c0593
--- /dev/null
+++ b/lib/file/book-11.txt
@@ -0,0 +1,250 @@
+The Wood spider is a somewhat rare animal,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Manes is an uncommon monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Bloodshot eye is a somewhat rare monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Pink naga is an uncommon monster,
+occurring at surface depths.
+She is extremely weak, just a little bit dangerous,
+and has no magical powers.
+
+The Pink jelly is a common monster,
+occurring at surface depths.
+It is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Giant pink frog is a common animal,
+occurring at surface depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Green icky thing is an uncommon monster,
+occurring at surface depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Zombified kobold is a common undead monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Lost soul is an uncommon undead monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Dark elf is an uncommon monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has an inkling of magical powers.
+
+The Night lizard is an uncommon monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+Mughash the Kobold Lord is a unique monster,
+occurring at surface depths.
+He is extremely weak, moderately dangerous,
+and has no magical powers.
+
+Wormtongue, Agent of Saruman is a unique monster,
+occurring at surface depths.
+He is very weak, not at all dangerous,
+and has remarkable magical powers.
+
+Lagduf, the Snaga is a unique orc,
+occurring at surface depths.
+He is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Brown yeek is a common animal,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Novice ranger is a common monster,
+occurring at surface depths.
+He is laughably weak, just a little bit dangerous,
+and has an inkling of magical powers.
+
+The Giant salamander is a common animal,
+occurring at surface depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Green mold is an uncommon monster,
+occurring at surface depths.
+It is extremely weak, moderately dangerous,
+and has no magical powers.
+
+The Skeleton orc is a common undead monster,
+occurring at surface depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Novice paladin is an uncommon monster,
+occurring at surface depths.
+He is laughably weak, just a little bit dangerous,
+and has an inkling of magical powers.
+
+The Lemure is a somewhat rare monster,
+occurring at surface depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Hill orc is a common monster,
+occurring at surface depths.
+He is extremely weak, just a small bit dangerous,
+and has no magical powers.
+
+The Bandit is an uncommon monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Yeti is a somewhat rare animal,
+occurring at surface depths.
+It is extremely weak, not one little bit dangerous,
+and has no magical powers.
+
+The Bloodshot icky thing is a somewhat rare monster,
+occurring at surface depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Giant grey rat is a common animal,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Black harpy is a common animal,
+occurring at surface depths.
+She is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Orc shaman is a common orc,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has rudimentary magical powers.
+
+The Baby blue dragon is an uncommon dragon,
+occurring at surface depths.
+It is extremely weak, not at all dangerous,
+and has no magical powers.
+
+The Baby white dragon is an uncommon dragon,
+occurring at surface depths.
+It is extremely weak, not at all dangerous,
+and has no magical powers.
+
+The Baby green dragon is an uncommon dragon,
+occurring at surface depths.
+It is extremely weak, not at all dangerous,
+and has no magical powers.
+
+The Baby black dragon is an uncommon dragon,
+occurring at surface depths.
+It is extremely weak, not at all dangerous,
+and has no magical powers.
+
+The Baby red dragon is an uncommon dragon,
+occurring at surface depths.
+It is extremely weak, not at all dangerous,
+and has no magical powers.
+
+The Giant pink ant is an uncommon monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+Brodda, the Easterling is a unique monster,
+occurring at surface depths.
+It is very weak, just a little bit dangerous,
+and has no magical powers.
+
+The King cobra is an uncommon animal,
+occurring at surface depths.
+It is extremely weak, just a little bit dangerous,
+and has no magical powers.
+
+The Giant spider is an uncommon animal,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Dark elven mage is a common monster,
+occurring at very shallow depths.
+He is laughably weak, not at all dangerous,
+and has simple magical powers.
+
+Orfax, Son of Boldor is a unique animal,
+occurring at very shallow depths.
+He is extremely weak, somewhat dangerous,
+and has remarkable magical powers.
+
+The Dark elven warrior is a common monster,
+occurring at very shallow depths.
+He is extremely weak, not one little bit dangerous,
+and has no magical powers.
+
+The Clear mushroom patch is an uncommon monster,
+occurring at very shallow depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+Grishnakh, the Hill Orc is a unique orc,
+occurring at very shallow depths.
+He is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Giant white tick is an uncommon animal,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Hairy mold is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Disenchanter mold is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, moderately dangerous,
+and has no magical powers.
+
+The Pseudo dragon is an uncommon monster,
+occurring at very shallow depths.
+It is very weak, not at all dangerous,
+and has simple magical powers.
+
+The Tengu is a common monster,
+occurring at very shallow depths.
+It is extremely weak, just a small bit dangerous,
+and has rudimentary magical powers.
+
+The Creeping gold coins is a somewhat rare animal,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Wolf is a common animal,
+occurring at very shallow depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Giant fruit fly is a legendary animal,
+occurring at very shallow depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
diff --git a/lib/file/book-12.txt b/lib/file/book-12.txt
new file mode 100644
index 00000000..d111d15d
--- /dev/null
+++ b/lib/file/book-12.txt
@@ -0,0 +1,250 @@
+The Panther is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, not one little bit dangerous,
+and has no magical powers.
+
+The Brigand is an uncommon monster,
+occurring at very shallow depths.
+He is extremely weak, not one little bit dangerous,
+and has no magical powers.
+
+The Baby multi-hued dragon is an uncommon dragon,
+occurring at very shallow depths.
+It is extremely weak, moderately dangerous,
+and has arcane magical powers.
+
+The Hippogryph is a common monster,
+occurring at very shallow depths.
+It is extremely weak, not one little bit dangerous,
+and has no magical powers.
+
+The Zombified orc is a common undead monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Gnome mage is an uncommon monster,
+occurring at very shallow depths.
+He is laughably weak, not one little bit dangerous,
+and has unremarkable magical powers.
+
+The Black mamba is a somewhat rare animal,
+occurring at very shallow depths.
+It is extremely weak, just a small bit dangerous,
+and has no magical powers.
+
+The White wolf is a common animal,
+occurring at very shallow depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Grape jelly is a somewhat rare monster,
+occurring at very shallow depths.
+It is moderately strong, just a small bit dangerous,
+and has no magical powers.
+
+The Nether worm mass is a somewhat rare animal,
+occurring at very shallow depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+Golfimbul, the Hill Orc Chief is a unique orc,
+occurring at very shallow depths.
+He is somewhat weak, moderately dangerous,
+and has no magical powers.
+
+The Master yeek is an uncommon animal,
+occurring at very shallow depths.
+It is extremely weak, not one little bit dangerous,
+and has arcane magical powers.
+
+The Priest is a common monster,
+occurring at very shallow depths.
+He is extremely weak, not one little bit dangerous,
+and has unremarkable magical powers.
+
+The Dark elven priest is a common monster,
+occurring at very shallow depths.
+He is extremely weak, not one little bit dangerous,
+and has unremarkable magical powers.
+
+The Air spirit is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Skeleton human is a common undead monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Zombified human is a common undead monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Tiger is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, not one little bit dangerous,
+and has no magical powers.
+
+The Moaning spirit is an uncommon undead monster,
+occurring at very shallow depths.
+It is laughably weak, moderately dangerous,
+and has rudimentary magical powers.
+
+The Swordsman is a common monster,
+occurring at very shallow depths.
+He is extremely weak, not one little bit dangerous,
+and has no magical powers.
+
+The Stegocentipede is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, not at all dangerous,
+and has no magical powers.
+
+The Spotted jelly is a somewhat rare monster,
+occurring at very shallow depths.
+It is extremely weak, moderately dangerous,
+and has no magical powers.
+
+The Drider is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, just a little bit dangerous,
+and has rudimentary magical powers.
+
+The Killer brown beetle is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, not at all dangerous,
+and has no magical powers.
+
+Boldor, King of the Yeeks is a unique animal,
+occurring at very shallow depths.
+He is very weak, somewhat dangerous,
+and has remarkable magical powers.
+
+The Ogre is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, just a small bit dangerous,
+and has no magical powers.
+
+The Creeping mithril coins is a rare animal,
+occurring at very shallow depths.
+It is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Illusionist is an uncommon monster,
+occurring at very shallow depths.
+He is extremely weak, not one little bit dangerous,
+and has arcane magical powers.
+
+The Druid is an uncommon monster,
+occurring at very shallow depths.
+He is extremely weak, not one little bit dangerous,
+and has remarkable magical powers.
+
+The Black orc is an uncommon orc,
+occurring at very shallow depths.
+He is extremely weak, just a little bit dangerous,
+and has no magical powers.
+
+The Ochre jelly is a somewhat rare monster,
+occurring at very shallow depths.
+It is extremely weak, very dangerous,
+and has no magical powers.
+
+The Giant flea is a common monster,
+occurring at very shallow depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+Ufthak of Cirith Ungol is a unique orc,
+occurring at very shallow depths.
+He is somewhat weak, moderately dangerous,
+and has no magical powers.
+
+The Giant white dragon fly is a somewhat rare animal,
+occurring at very shallow depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Blue icky thing is a rare monster,
+occurring at very shallow depths.
+It is laughably weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Hill giant is a common monster,
+occurring at very shallow depths.
+It is very weak, not one little bit dangerous,
+and has no magical powers.
+
+The Flesh golem is a common monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Warg is an uncommon animal,
+occurring at very shallow depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Giant black louse is a common monster,
+occurring at very shallow depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Lurker is a somewhat rare monster,
+occurring at very shallow depths.
+It is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Wererat is an uncommon animal,
+occurring at very shallow depths.
+It is extremely weak, not one little bit dangerous,
+and has simple magical powers.
+
+The Black ogre is an uncommon giant,
+occurring at very shallow depths.
+It is very weak, just a little bit dangerous,
+and has no magical powers.
+
+The Magic mushroom patch is an uncommon monster,
+occurring at very shallow depths.
+It is laughably weak, not at all dangerous,
+and has arcane magical powers.
+
+The Guardian naga is an uncommon monster,
+occurring at very shallow depths.
+She is somewhat weak, not one little bit dangerous,
+and has no magical powers.
+
+The Light hound is a common monster,
+occurring at very shallow depths.
+It is laughably weak, just a little bit dangerous,
+and has an inkling of magical powers.
+
+The Dark hound is a common monster,
+occurring at very shallow depths.
+It is laughably weak, just a little bit dangerous,
+and has an inkling of magical powers.
+
+The Half-orc is a somewhat rare orc,
+occurring at very shallow depths.
+He is very weak, just a small bit dangerous,
+and has no magical powers.
+
+The Giant tarantula is a somewhat rare animal,
+occurring at very shallow depths.
+It is extremely weak, moderately dangerous,
+and has no magical powers.
+
+The Giant clear centipede is an uncommon monster,
+occurring at very shallow depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Mirkwood spider is an uncommon animal,
+occurring at very shallow depths.
+It is laughably weak, moderately dangerous,
+and has no magical powers.
+
diff --git a/lib/file/book-13.txt b/lib/file/book-13.txt
new file mode 100644
index 00000000..b8a15e3f
--- /dev/null
+++ b/lib/file/book-13.txt
@@ -0,0 +1,250 @@
+The Frost giant is a common giant,
+occurring at very shallow depths.
+It is very weak, not at all dangerous,
+and has no magical powers.
+
+The Griffon is a common animal,
+occurring at very shallow depths.
+It is very weak, not one little bit dangerous,
+and has no magical powers.
+
+The Homonculous is a somewhat rare monster,
+occurring at very shallow depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Gnome mage is an uncommon monster,
+occurring at very shallow depths.
+He is laughably weak, just a little bit dangerous,
+and has unremarkable magical powers.
+
+The Clear hound is an uncommon monster,
+occurring at very shallow depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Clay golem is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, moderately dangerous,
+and has no magical powers.
+
+The Umber hulk is a common animal,
+occurring at very shallow depths.
+It is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Orc captain is a somewhat rare orc,
+occurring at very shallow depths.
+He is very weak, not one little bit dangerous,
+and has no magical powers.
+
+The Gelatinous cube is a rare monster,
+occurring at very shallow depths.
+It is somewhat weak, hellishly dangerous,
+and has no magical powers.
+
+The Giant green dragon fly is an uncommon animal,
+occurring at very shallow depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Fire giant is an uncommon giant,
+occurring at very shallow depths.
+It is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Hummerhorn is an extremely rare animal,
+occurring at very shallow depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+Ulfast, Son of Ulfang is a unique monster,
+occurring at very shallow depths.
+He is somewhat weak, just a little bit dangerous,
+and has no magical powers.
+
+The Quasit is an uncommon monster,
+occurring at very shallow depths.
+It is laughably weak, somewhat dangerous,
+and has average magical powers.
+
+The Imp is an uncommon monster,
+occurring at very shallow depths.
+It is laughably weak, moderately dangerous,
+and has average magical powers.
+
+The Forest troll is a common troll,
+occurring at very shallow depths.
+He is very weak, just a little bit dangerous,
+and has no magical powers.
+
+Nar, the Dwarf is a unique monster,
+occurring at very shallow depths.
+He is somewhat strong, moderately dangerous,
+and has simple magical powers.
+
+The 2-headed hydra is an uncommon monster,
+occurring at very shallow depths.
+It is somewhat weak, not one little bit dangerous,
+and has no magical powers.
+
+The Water spirit is a common monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Giant pink scorpion is a common monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Earth spirit is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, moderately dangerous,
+and has no magical powers.
+
+The Fire spirit is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, moderately dangerous,
+and has no magical powers.
+
+The Fire hound is a common animal,
+occurring at very shallow depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Cold hound is a common animal,
+occurring at very shallow depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Energy hound is a common animal,
+occurring at very shallow depths.
+It is laughably weak, moderately dangerous,
+and has no magical powers.
+
+The Mimic (potion) is a somewhat rare monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has small magical powers.
+
+The Blink dog is an uncommon monster,
+occurring at very shallow depths.
+It is laughably weak, just a little bit dangerous,
+and has rudimentary magical powers.
+
+The Uruk is a common orc,
+occurring at very shallow depths.
+He is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+Shagrat, the Orc Captain is a unique orc,
+occurring at very shallow depths.
+He is moderately strong, somewhat dangerous,
+and has no magical powers.
+
+Gorbag, the Orc Captain is a unique orc,
+occurring at very shallow depths.
+He is moderately strong, somewhat dangerous,
+and has no magical powers.
+
+The Shambling mound is an uncommon monster,
+occurring at very shallow depths.
+It is extremely weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Stone giant is a common monster,
+occurring at very shallow depths.
+It is very weak, not one little bit dangerous,
+and has no magical powers.
+
+The Giant black dragon fly is an uncommon animal,
+occurring at very shallow depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Stone golem is an uncommon monster,
+occurring at very shallow depths.
+It is very weak, moderately dangerous,
+and has no magical powers.
+
+The Red mold is a common monster,
+occurring at very shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Giant gold dragon fly is an uncommon animal,
+occurring at very shallow depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+Bolg, Son of Azog is a unique orc,
+occurring at somewhat shallow depths.
+He is somewhat strong, somewhat dangerous,
+and has no magical powers.
+
+The Phase spider is an uncommon animal,
+occurring at somewhat shallow depths.
+It is laughably weak, moderately dangerous,
+and has rudimentary magical powers.
+
+The 3-headed hydra is an uncommon monster,
+occurring at somewhat shallow depths.
+It is somewhat strong, not one little bit dangerous,
+and has no magical powers.
+
+The Earth hound is a common monster,
+occurring at somewhat shallow depths.
+It is extremely weak, just a little bit dangerous,
+and has no magical powers.
+
+The Air hound is a common animal,
+occurring at somewhat shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Sabre-tooth tiger is an uncommon monster,
+occurring at somewhat shallow depths.
+It is somewhat weak, not one little bit dangerous,
+and has no magical powers.
+
+The Water hound is an uncommon animal,
+occurring at somewhat shallow depths.
+It is extremely weak, moderately dangerous,
+and has no magical powers.
+
+The Chimera is a common monster,
+occurring at somewhat shallow depths.
+It is extremely weak, not at all dangerous,
+and has no magical powers.
+
+The Quylthulg is a common monster,
+occurring at somewhat shallow depths.
+It is laughably weak, just a small bit dangerous,
+and has rudimentary magical powers.
+
+The Sasquatch is a somewhat rare animal,
+occurring at somewhat shallow depths.
+It is moderately strong, not one little bit dangerous,
+and has no magical powers.
+
+The Werewolf is a common animal,
+occurring at somewhat shallow depths.
+It is moderately strong, not one little bit dangerous,
+and has no magical powers.
+
+The Dark elven lord is an uncommon monster,
+occurring at somewhat shallow depths.
+He is somewhat weak, not one little bit dangerous,
+and has average magical powers.
+
+The Cloud giant is a common giant,
+occurring at somewhat shallow depths.
+It is somewhat weak, somewhat dangerous,
+and has no magical powers.
+
+Ugluk, the Uruk is a unique orc,
+occurring at somewhat shallow depths.
+He is very strong, somewhat dangerous,
+and has no magical powers.
+
diff --git a/lib/file/book-14.txt b/lib/file/book-14.txt
new file mode 100644
index 00000000..b987ea99
--- /dev/null
+++ b/lib/file/book-14.txt
@@ -0,0 +1,250 @@
+Lugdush, the Uruk is a unique orc,
+occurring at somewhat shallow depths.
+He is extremely strong, moderately dangerous,
+and has no magical powers.
+
+The Blue dragon bat is a common animal,
+occurring at somewhat shallow depths.
+It is laughably weak, not at all dangerous,
+and has an inkling of magical powers.
+
+The Mimic (scroll) is a somewhat rare monster,
+occurring at somewhat shallow depths.
+It is extremely weak, moderately dangerous,
+and has average magical powers.
+
+The Fire vortex is a common monster,
+occurring at somewhat shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Water vortex is a common monster,
+occurring at somewhat shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Cold vortex is a common monster,
+occurring at somewhat shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Energy vortex is a common monster,
+occurring at somewhat shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Mummified orc is a common undead monster,
+occurring at somewhat shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Killer stag beetle is a common monster,
+occurring at somewhat shallow depths.
+It is very weak, not one little bit dangerous,
+and has no magical powers.
+
+The Iron golem is an uncommon monster,
+occurring at somewhat shallow depths.
+It is unimaginably strong, moderately dangerous,
+and has no magical powers.
+
+The Giant yellow scorpion is a common monster,
+occurring at somewhat shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Black ooze is a common monster,
+occurring at somewhat shallow depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Hardened warrior is a common monster,
+occurring at somewhat shallow depths.
+He is very weak, not one little bit dangerous,
+and has no magical powers.
+
+Azog, King of the Uruk-Hai is a unique orc,
+occurring at somewhat shallow depths.
+He is alarmingly strong, moderately dangerous,
+and has no magical powers.
+
+The Master rogue is an uncommon monster,
+occurring at somewhat shallow depths.
+He is extremely weak, not one little bit dangerous,
+and has no magical powers.
+
+The Red dragon bat is a common animal,
+occurring at somewhat shallow depths.
+It is laughably weak, not one little bit dangerous,
+and has an inkling of magical powers.
+
+The Killer white beetle is a common monster,
+occurring at somewhat shallow depths.
+It is very weak, not one little bit dangerous,
+and has no magical powers.
+
+The Giant bronze dragon fly is a common animal,
+occurring at very shallow depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Forest wight is a common undead monster,
+occurring at somewhat shallow depths.
+It is extremely weak, just a little bit dangerous,
+and has an inkling of magical powers.
+
+Ibun, Son of Mim is a unique monster,
+occurring at somewhat shallow depths.
+He is alarmingly strong, somewhat dangerous,
+and has small magical powers.
+
+Khim, Son of Mim is a unique monster,
+occurring at somewhat shallow depths.
+He is alarmingly strong, somewhat dangerous,
+and has small magical powers.
+
+The 4-headed hydra is an uncommon monster,
+occurring at somewhat shallow depths.
+It is strong, not one little bit dangerous,
+and has no magical powers.
+
+The Mummified human is a common undead monster,
+occurring at somewhat shallow depths.
+It is extremely weak, somewhat dangerous,
+and has no magical powers.
+
+The Vampire bat is an uncommon undead monster,
+occurring at somewhat shallow depths.
+It is extremely weak, moderately dangerous,
+and has no magical powers.
+
+Sangahyando of Umbar is a unique monster,
+occurring at somewhat shallow depths.
+He is extremely strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+Angamaite of Umbar is a unique monster,
+occurring at somewhat shallow depths.
+He is extremely strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Banshee is an uncommon undead monster,
+occurring at somewhat shallow depths.
+She is laughably weak, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Pukelman is a somewhat rare monster,
+occurring at somewhat shallow depths.
+It is unimaginably strong, moderately dangerous,
+and has small magical powers.
+
+The Dark elven druid is a somewhat rare monster,
+occurring at somewhat shallow depths.
+He is moderately strong, just a little bit dangerous,
+and has unremarkable magical powers.
+
+The Stone troll is a common troll,
+occurring at somewhat shallow depths.
+He is very weak, just a little bit dangerous,
+and has no magical powers.
+
+The Troll priest is a common troll,
+occurring at somewhat shallow depths.
+He is somewhat weak, just a little bit dangerous,
+and has unremarkable magical powers.
+
+The Wereworm is a somewhat rare animal,
+occurring at somewhat shallow depths.
+It is hellishly strong, somewhat dangerous,
+and has no magical powers.
+
+The Carrion crawler is an uncommon animal,
+occurring at somewhat shallow depths.
+It is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Killer pink beetle is an uncommon monster,
+occurring at somewhat shallow depths.
+It is very weak, just a small bit dangerous,
+and has no magical powers.
+
+The Giant grey ant is a common monster,
+occurring at somewhat shallow depths.
+It is extremely weak, not one little bit dangerous,
+and has no magical powers.
+
+Ulwarth, Son of Ulfang is a unique monster,
+occurring at somewhat shallow depths.
+He is extremely strong, just a little bit dangerous,
+and has no magical powers.
+
+The Displacer beast is an uncommon monster,
+occurring at somewhat shallow depths.
+It is somewhat weak, just a little bit dangerous,
+and has no magical powers.
+
+The Giant red tick is a common animal,
+occurring at somewhat shallow depths.
+It is extremely weak, just a small bit dangerous,
+and has no magical powers.
+
+The Cave ogre is a common monster,
+occurring at somewhat shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has no magical powers.
+
+The White wraith is a common undead monster,
+occurring at somewhat shallow depths.
+It is extremely weak, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Monadic Deva is a legendary monster,
+occurring at somewhat shallow depths.
+It is somewhat weak, moderately dangerous,
+and has small magical powers.
+
+Mim, Betrayer of Turin is a unique monster,
+occurring at somewhat shallow depths.
+He is hellishly strong, moderately dangerous,
+and has unremarkable magical powers.
+
+The Killer red beetle is a common animal,
+occurring at somewhat shallow depths.
+It is extremely weak, just a little bit dangerous,
+and has no magical powers.
+
+The Creeping adamantite coins is a rare animal,
+occurring at somewhat shallow depths.
+It is somewhat strong, moderately dangerous,
+and has no magical powers.
+
+The Algroth is a common monster,
+occurring at somewhat shallow depths.
+It is somewhat weak, moderately dangerous,
+and has no magical powers.
+
+The Vibration hound is a somewhat rare animal,
+occurring at somewhat shallow depths.
+It is very weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Nexus hound is a somewhat rare animal,
+occurring at somewhat shallow depths.
+It is very weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Ogre mage is an uncommon giant,
+occurring at somewhat shallow depths.
+It is moderately strong, not one little bit dangerous,
+and has arcane magical powers.
+
+Lokkak, the Ogre Chieftain is a unique giant,
+occurring at somewhat shallow depths.
+He is hellishly strong, somewhat dangerous,
+and has no magical powers.
+
+The Vampire is a common undead monster,
+occurring at somewhat shallow depths.
+It is somewhat weak, moderately dangerous,
+and has arcane magical powers.
+
diff --git a/lib/file/book-15.txt b/lib/file/book-15.txt
new file mode 100644
index 00000000..5f33444b
--- /dev/null
+++ b/lib/file/book-15.txt
@@ -0,0 +1,250 @@
+The Gorgimera is an uncommon monster,
+occurring at somewhat shallow depths.
+It is somewhat strong, just a small bit dangerous,
+and has no magical powers.
+
+The Colbran is an uncommon monster,
+occurring at somewhat shallow depths.
+It is unimaginably strong, moderately dangerous,
+and has an inkling of magical powers.
+
+The Spirit naga is an uncommon monster,
+occurring at somewhat shallow depths.
+She is somewhat strong, somewhat dangerous,
+and has unremarkable magical powers.
+
+The 5-headed hydra is an uncommon animal,
+occurring at somewhat shallow depths.
+It is extremely strong, moderately dangerous,
+and has rudimentary magical powers.
+
+The Black knight is a common monster,
+occurring at somewhat shallow depths.
+He is somewhat weak, not one little bit dangerous,
+and has rudimentary magical powers.
+
+Uldor the Accursed is a unique monster,
+occurring at somewhat shallow depths.
+He is unimaginably strong, just a little bit dangerous,
+and has no magical powers.
+
+The Mage is a common monster,
+occurring at somewhat shallow depths.
+He is extremely weak, not one little bit dangerous,
+and has unimaginably powerful magical powers.
+
+The Mind flayer is a common monster,
+occurring at somewhat shallow depths.
+It is very weak, moderately dangerous,
+and has remarkable magical powers.
+
+Draebor, the Imp is a unique monster,
+occurring at somewhat shallow depths.
+It is somewhat strong, very dangerous,
+and has arcane magical powers.
+
+The Basilisk is a somewhat rare animal,
+occurring at somewhat shallow depths.
+It is strong, not at all dangerous,
+and has no magical powers.
+
+The Ice troll is a common troll,
+occurring at somewhat shallow depths.
+He is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Giant purple worm is a somewhat rare animal,
+occurring at somewhat shallow depths.
+It is somewhat strong, somewhat dangerous,
+and has no magical powers.
+
+The Movanic Deva is a legendary monster,
+occurring at somewhat shallow depths.
+It is moderately strong, moderately dangerous,
+and has unremarkable magical powers.
+
+The Catoblepas is an uncommon animal,
+occurring at somewhat shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has no magical powers.
+
+The Mimic (ring) is a somewhat rare monster,
+occurring at somewhat shallow depths.
+It is moderately strong, extremely dangerous,
+and has hellishly powerful magical powers.
+
+The Young blue dragon is a common dragon,
+occurring at somewhat shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Young white dragon is a common dragon,
+occurring at somewhat shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Young green dragon is a common dragon,
+occurring at somewhat shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Young bronze dragon is a somewhat rare dragon,
+occurring at somewhat shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Mithril golem is a rare monster,
+occurring at shallow depths.
+It is hellishly strong, moderately dangerous,
+and has no magical powers.
+
+The Shadow drake is an uncommon dragon,
+occurring at shallow depths.
+It is very weak, just a small bit dangerous,
+and has simple magical powers.
+
+The Skeleton troll is a common undead monster,
+occurring at shallow depths.
+It is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Manticore is an uncommon monster,
+occurring at shallow depths.
+It is very weak, not at all dangerous,
+and has an inkling of magical powers.
+
+The Giant blue ant is an uncommon animal,
+occurring at shallow depths.
+It is extremely weak, just a little bit dangerous,
+and has no magical powers.
+
+The Giant army ant is a somewhat rare monster,
+occurring at shallow depths.
+It is extremely weak, just a small bit dangerous,
+and has no magical powers.
+
+The Grave wight is a common undead monster,
+occurring at shallow depths.
+It is extremely weak, just a little bit dangerous,
+and has rudimentary magical powers.
+
+The Killer slicer beetle is an uncommon monster,
+occurring at shallow depths.
+It is very weak, not at all dangerous,
+and has no magical powers.
+
+The Ghost is a common undead monster,
+occurring at shallow depths.
+It is extremely weak, alarmingly dangerous,
+and has an inkling of magical powers.
+
+The Death watch beetle is a somewhat rare monster,
+occurring at shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has no magical powers.
+
+The Ogre shaman is an uncommon giant,
+occurring at shallow depths.
+It is extremely weak, not one little bit dangerous,
+and has advanced magical powers.
+
+The Nexus quylthulg is a common monster,
+occurring at shallow depths.
+It is extremely weak, not at all dangerous,
+and has average magical powers.
+
+Shelob, Spider of Darkness is a unique animal,
+occurring at shallow depths.
+She is hellishly strong, unimaginably dangerous,
+and has very powerful magical powers.
+
+The Ninja is an uncommon monster,
+occurring at shallow depths.
+He is very weak, moderately dangerous,
+and has no magical powers.
+
+The Memory moss is a somewhat rare monster,
+occurring at shallow depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Storm giant is a common giant,
+occurring at shallow depths.
+It is moderately strong, moderately dangerous,
+and has average magical powers.
+
+The Cave troll is a common troll,
+occurring at shallow depths.
+He is somewhat weak, somewhat dangerous,
+and has no magical powers.
+
+The Half-troll is an uncommon troll,
+occurring at shallow depths.
+He is moderately strong, somewhat dangerous,
+and has no magical powers.
+
+The Mystic is a somewhat rare monster,
+occurring at shallow depths.
+He is moderately strong, moderately dangerous,
+and has rudimentary magical powers.
+
+The Barrow wight is a somewhat rare undead monster,
+occurring at shallow depths.
+It is extremely weak, somewhat dangerous,
+and has small magical powers.
+
+The Giant skeleton troll is a common undead monster,
+occurring at shallow depths.
+It is somewhat strong, moderately dangerous,
+and has no magical powers.
+
+The Chaos drake is a somewhat rare dragon,
+occurring at shallow depths.
+It is strong, somewhat dangerous,
+and has remarkable magical powers.
+
+The Law drake is a somewhat rare dragon,
+occurring at shallow depths.
+It is strong, somewhat dangerous,
+and has average magical powers.
+
+The Balance drake is a somewhat rare dragon,
+occurring at shallow depths.
+It is very strong, somewhat dangerous,
+and has hellishly powerful magical powers.
+
+The Ethereal drake is a somewhat rare dragon,
+occurring at shallow depths.
+It is somewhat strong, somewhat dangerous,
+and has unremarkable magical powers.
+
+Bert the Stone Troll is a unique troll,
+occurring at shallow depths.
+He is hellishly strong, somewhat dangerous,
+and has no magical powers.
+
+Bill the Stone Troll is a unique troll,
+occurring at shallow depths.
+He is hellishly strong, somewhat dangerous,
+and has no magical powers.
+
+Tom the Stone Troll is a unique troll,
+occurring at shallow depths.
+He is hellishly strong, somewhat dangerous,
+and has no magical powers.
+
+The Shade is a somewhat rare undead monster,
+occurring at shallow depths.
+It is somewhat weak, moderately dangerous,
+and has small magical powers.
+
+The Spectre is a somewhat rare undead monster,
+occurring at shallow depths.
+It is somewhat weak, moderately dangerous,
+and has small magical powers.
+
+The Water troll is a common troll,
+occurring at shallow depths.
+He is moderately strong, moderately dangerous,
+and has no magical powers.
+
diff --git a/lib/file/book-16.txt b/lib/file/book-16.txt
new file mode 100644
index 00000000..d2b36408
--- /dev/null
+++ b/lib/file/book-16.txt
@@ -0,0 +1,250 @@
+The Fire elemental is an uncommon monster,
+occurring at shallow depths.
+It is very weak, moderately dangerous,
+and has no magical powers.
+
+The Astral Deva is a legendary monster,
+occurring at shallow depths.
+It is somewhat strong, alarmingly dangerous,
+and has advanced magical powers.
+
+The Water elemental is an uncommon monster,
+occurring at shallow depths.
+It is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Invisible stalker is a somewhat rare monster,
+occurring at shallow depths.
+It is very weak, moderately dangerous,
+and has no magical powers.
+
+The Carrion crawler is an uncommon animal,
+occurring at shallow depths.
+It is very weak, somewhat dangerous,
+and has no magical powers.
+
+The Master thief is an uncommon monster,
+occurring at shallow depths.
+He is very weak, not at all dangerous,
+and has no magical powers.
+
+Ulfang the Black is a unique monster,
+occurring at shallow depths.
+He is unimaginably strong, just a little bit dangerous,
+and has no magical powers.
+
+The Lich is a somewhat rare undead monster,
+occurring at shallow depths.
+It is somewhat weak, very dangerous,
+and has very powerful magical powers.
+
+The Master vampire is a somewhat rare undead monster,
+occurring at shallow depths.
+It is moderately strong, moderately dangerous,
+and has very powerful magical powers.
+
+The Giant grey scorpion is a rare monster,
+occurring at shallow depths.
+It is moderately strong, somewhat dangerous,
+and has no magical powers.
+
+The Earth elemental is an uncommon monster,
+occurring at shallow depths.
+It is somewhat weak, very dangerous,
+and has no magical powers.
+
+The Air elemental is an uncommon monster,
+occurring at shallow depths.
+It is very weak, alarmingly dangerous,
+and has no magical powers.
+
+The Hell hound is a somewhat rare animal,
+occurring at shallow depths.
+It is moderately strong, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Eog golem is a rare monster,
+occurring at shallow depths.
+It is hellishly strong, moderately dangerous,
+and has no magical powers.
+
+The Olog is a common troll,
+occurring at shallow depths.
+It is moderately strong, somewhat dangerous,
+and has no magical powers.
+
+The Dagashi is a rare monster,
+occurring at shallow depths.
+He is somewhat weak, extremely dangerous,
+and has no magical powers.
+
+The Gravity hound is an uncommon animal,
+occurring at shallow depths.
+It is somewhat weak, somewhat dangerous,
+and has an inkling of magical powers.
+
+The Acidic cytoplasm is an extremely rare monster,
+occurring at shallow depths.
+It is moderately strong, hellishly dangerous,
+and has no magical powers.
+
+The Inertia hound is an uncommon animal,
+occurring at shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Impact hound is an uncommon animal,
+occurring at shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has no magical powers.
+
+The Dread is an uncommon undead monster,
+occurring at shallow depths.
+It is somewhat strong, moderately dangerous,
+and has simple magical powers.
+
+The Ooze elemental is a somewhat rare monster,
+occurring at shallow depths.
+It is very weak, hellishly dangerous,
+and has small magical powers.
+
+The Smoke elemental is a somewhat rare monster,
+occurring at shallow depths.
+It is very weak, moderately dangerous,
+and has rudimentary magical powers.
+
+The Young black dragon is a common dragon,
+occurring at shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Mumak is a somewhat rare monster,
+occurring at shallow depths.
+It is alarmingly strong, not one little bit dangerous,
+and has no magical powers.
+
+The Giant red ant is a common animal,
+occurring at shallow depths.
+It is very weak, moderately dangerous,
+and has no magical powers.
+
+The Mature white dragon is a common dragon,
+occurring at shallow depths.
+It is moderately strong, somewhat dangerous,
+and has an inkling of magical powers.
+
+The Xorn is an uncommon monster,
+occurring at shallow depths.
+It is very weak, very dangerous,
+and has no magical powers.
+
+The Shadow is a somewhat rare undead monster,
+occurring at shallow depths.
+It is very weak, extremely dangerous,
+and has an inkling of magical powers.
+
+The Phantom is a somewhat rare undead monster,
+occurring at shallow depths.
+It is somewhat strong, extremely dangerous,
+and has an inkling of magical powers.
+
+The Grey wraith is a common undead monster,
+occurring at shallow depths.
+It is very weak, somewhat dangerous,
+and has small magical powers.
+
+The Young multi-hued dragon is a common dragon,
+occurring at shallow depths.
+It is somewhat weak, very dangerous,
+and has very powerful magical powers.
+
+The Colossus is a rare monster,
+occurring at shallow depths.
+It is hellishly strong, extremely dangerous,
+and has no magical powers.
+
+The Young gold dragon is an uncommon dragon,
+occurring at shallow depths.
+It is somewhat weak, not at all dangerous,
+and has an inkling of magical powers.
+
+Rogrog the Black Troll is a unique troll,
+occurring at shallow depths.
+He is hellishly strong, moderately dangerous,
+and has no magical powers.
+
+The Mature blue dragon is a common dragon,
+occurring at shallow depths.
+It is moderately strong, somewhat dangerous,
+and has an inkling of magical powers.
+
+The Mature green dragon is a common dragon,
+occurring at shallow depths.
+It is moderately strong, somewhat dangerous,
+and has an inkling of magical powers.
+
+The Mature bronze dragon is an uncommon dragon,
+occurring at shallow depths.
+It is somewhat strong, just a small bit dangerous,
+and has rudimentary magical powers.
+
+The Young red dragon is a common dragon,
+occurring at shallow depths.
+It is somewhat weak, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Trapper is a somewhat rare monster,
+occurring at shallow depths.
+It is strong, moderately dangerous,
+and has no magical powers.
+
+The Bodak is an uncommon monster,
+occurring at shallow depths.
+It is moderately strong, somewhat dangerous,
+and has average magical powers.
+
+The Ice elemental is an uncommon monster,
+occurring at shallow depths.
+It is moderately strong, moderately dangerous,
+and has unremarkable magical powers.
+
+The Necromancer is an uncommon monster,
+occurring at shallow depths.
+He is somewhat weak, just a little bit dangerous,
+and has unimaginably powerful magical powers.
+
+Lorgan, Chief of the Easterlings is a unique monster,
+occurring at shallow depths.
+He is hellishly strong, very dangerous,
+and has rudimentary magical powers.
+
+The Demonologist is an uncommon monster,
+occurring at shallow depths.
+He is somewhat weak, not at all dangerous,
+and has unremarkable magical powers.
+
+The Mummified troll is a common undead monster,
+occurring at shallow depths.
+It is very weak, moderately dangerous,
+and has no magical powers.
+
+The Queen Ant is a unique animal,
+occurring at shallow depths.
+She is hellishly strong, moderately dangerous,
+and has rudimentary magical powers.
+
+The Will o' the Wisp is a rare monster,
+occurring at shallow depths.
+It is somewhat weak, hellishly dangerous,
+and has average magical powers.
+
+The Magma elemental is an uncommon monster,
+occurring at shallow depths.
+It is moderately strong, extremely dangerous,
+and has simple magical powers.
+
+The Black pudding is an extremely rare monster,
+occurring at shallow depths.
+It is moderately strong, hellishly dangerous,
+and has no magical powers.
+
diff --git a/lib/file/book-17.txt b/lib/file/book-17.txt
new file mode 100644
index 00000000..18f2b663
--- /dev/null
+++ b/lib/file/book-17.txt
@@ -0,0 +1,250 @@
+The Killer blue beetle is an uncommon animal,
+occurring at shallow depths.
+It is somewhat weak, somewhat dangerous,
+and has no magical powers.
+
+The Nexus vortex is a common monster,
+occurring at shallow depths.
+It is somewhat weak, not one little bit dangerous,
+and has no magical powers.
+
+The Plasma vortex is a common monster,
+occurring at shallow depths.
+It is somewhat weak, somewhat dangerous,
+and has no magical powers.
+
+The Mature red dragon is a common dragon,
+occurring at shallow depths.
+It is somewhat strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Mature gold dragon is an uncommon dragon,
+occurring at shallow depths.
+It is strong, just a small bit dangerous,
+and has rudimentary magical powers.
+
+The Crystal drake is an uncommon dragon,
+occurring at shallow depths.
+It is strong, somewhat dangerous,
+and has small magical powers.
+
+The Mature black dragon is a common dragon,
+occurring at shallow depths.
+It is somewhat strong, somewhat dangerous,
+and has an inkling of magical powers.
+
+The Mature multi-hued dragon is an uncommon dragon,
+occurring at shallow depths.
+It is very strong, extremely dangerous,
+and has extremely powerful magical powers.
+
+The Death knight is a common monster,
+occurring at shallow depths.
+It is very strong, somewhat dangerous,
+and has remarkable magical powers.
+
+Castamir the Usurper is a unique monster,
+occurring at shallow depths.
+He is alarmingly strong, not at all dangerous,
+and has extremely powerful magical powers.
+
+The Time vortex is a rare monster,
+occurring at shallow depths.
+It is somewhat weak, not one little bit dangerous,
+and has no magical powers.
+
+The Shimmering vortex is a rare monster,
+occurring at shallow depths.
+It is extremely weak, not one little bit dangerous,
+and has small magical powers.
+
+The Ancient blue dragon is a common dragon,
+occurring at shallow depths.
+It is very strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Ancient bronze dragon is an uncommon dragon,
+occurring at shallow depths.
+It is extremely strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Beholder is a rare monster,
+occurring at shallow depths.
+It is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+The Emperor wight is an uncommon undead monster,
+occurring at shallow depths.
+It is moderately strong, somewhat dangerous,
+and has small magical powers.
+
+The Planetar is a legendary monster,
+occurring at shallow depths.
+It is somewhat strong, extremely dangerous,
+and has hellishly powerful magical powers.
+
+Vargo, Tyrant of Fire is a unique monster,
+occurring at shallow depths.
+It is hellishly strong, moderately dangerous,
+and has unremarkable magical powers.
+
+The Black wraith is an uncommon undead monster,
+occurring at shallow depths.
+It is somewhat strong, somewhat dangerous,
+and has small magical powers.
+
+The Erinyes is an uncommon monster,
+occurring at shallow depths.
+She is very weak, moderately dangerous,
+and has an inkling of magical powers.
+
+The Nether wraith is an uncommon undead monster,
+occurring at shallow depths.
+It is somewhat strong, moderately dangerous,
+and has unremarkable magical powers.
+
+The Eldrak is a somewhat rare troll,
+occurring at shallow depths.
+It is extremely strong, somewhat dangerous,
+and has no magical powers.
+
+The Ettin is a somewhat rare troll,
+occurring at shallow depths.
+It is hellishly strong, somewhat dangerous,
+and has no magical powers.
+
+Waldern, King of Water is a unique monster,
+occurring at shallow depths.
+It is hellishly strong, somewhat dangerous,
+and has unimaginably powerful magical powers.
+
+Kavlax the Many-Headed is a unique dragon,
+occurring at shallow depths.
+He is hellishly strong, moderately dangerous,
+and has hellishly powerful magical powers.
+
+The Ancient white dragon is a common dragon,
+occurring at shallow depths.
+It is very strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Ancient green dragon is a common dragon,
+occurring at shallow depths.
+It is extremely strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The 7-headed hydra is an uncommon animal,
+occurring at shallow depths.
+It is unimaginably strong, moderately dangerous,
+and has unremarkable magical powers.
+
+The Night mare is a somewhat rare undead monster,
+occurring at shallow depths.
+It is hellishly strong, very dangerous,
+and has no magical powers.
+
+The Vampire lord is a somewhat rare undead monster,
+occurring at shallow depths.
+It is hellishly strong, unimaginably dangerous,
+and has very powerful magical powers.
+
+The Ancient black dragon is a common dragon,
+occurring at shallow depths.
+It is extremely strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Disenchanter worm mass is a somewhat rare animal,
+occurring at shallow-to-moderate depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Rotting quylthulg is a common animal,
+occurring at shallow-to-moderate depths.
+It is extremely weak, just a small bit dangerous,
+and has unremarkable magical powers.
+
+The Spirit troll is a somewhat rare troll,
+occurring at shallow-to-moderate depths.
+It is unimaginably strong, very dangerous,
+and has no magical powers.
+
+The Lesser titan is a somewhat rare monster,
+occurring at shallow-to-moderate depths.
+It is unimaginably strong, moderately dangerous,
+and has unremarkable magical powers.
+
+The 9-headed hydra is an uncommon animal,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, just a small bit dangerous,
+and has simple magical powers.
+
+The Enchantress is a rare monster,
+occurring at shallow-to-moderate depths.
+She is somewhat strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Archpriest is an uncommon monster,
+occurring at shallow-to-moderate depths.
+He is somewhat strong, somewhat dangerous,
+and has arcane magical powers.
+
+The Sorcerer is an uncommon monster,
+occurring at shallow-to-moderate depths.
+He is somewhat strong, somewhat dangerous,
+and has hellishly powerful magical powers.
+
+The Xaren is a common monster,
+occurring at shallow-to-moderate depths.
+It is moderately strong, very dangerous,
+and has no magical powers.
+
+The Giant roc is a somewhat rare animal,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, somewhat dangerous,
+and has no magical powers.
+
+Uvatha the Horseman is a unique undead monster,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, extremely dangerous,
+and has no magical powers.
+
+The Minotaur is an uncommon monster,
+occurring at shallow-to-moderate depths.
+It is unimaginably strong, not one little bit dangerous,
+and has no magical powers.
+
+Medusa, the Gorgon is a unique monster,
+occurring at shallow-to-moderate depths.
+She is hellishly strong, moderately dangerous,
+and has hellishly powerful magical powers.
+
+The Death drake is an uncommon dragon,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, hellishly dangerous,
+and has small magical powers.
+
+The Ancient red dragon is a common dragon,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Ancient gold dragon is an uncommon dragon,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Great crystal drake is an uncommon dragon,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, somewhat dangerous,
+and has small magical powers.
+
+The Vrock is an uncommon monster,
+occurring at shallow-to-moderate depths.
+It is moderately strong, moderately dangerous,
+and has no magical powers.
+
+The Death quasit is a somewhat rare monster,
+occurring at shallow-to-moderate depths.
+It is somewhat strong, alarmingly dangerous,
+and has unremarkable magical powers.
+
diff --git a/lib/file/book-18.txt b/lib/file/book-18.txt
new file mode 100644
index 00000000..c36b205f
--- /dev/null
+++ b/lib/file/book-18.txt
@@ -0,0 +1,250 @@
+Adunaphel the Quiet is a unique undead monster,
+occurring at shallow-to-moderate depths.
+She is hellishly strong, moderately dangerous,
+and has hellishly powerful magical powers.
+
+The Dark elven sorceror is an uncommon monster,
+occurring at shallow-to-moderate depths.
+He is extremely strong, just a small bit dangerous,
+and has hellishly powerful magical powers.
+
+The Master lich is an uncommon undead monster,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, extremely dangerous,
+and has hellishly powerful magical powers.
+
+The Hezrou is a somewhat rare monster,
+occurring at shallow-to-moderate depths.
+It is somewhat strong, moderately dangerous,
+and has rudimentary magical powers.
+
+Akhorahil the Blind is a unique undead monster,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, somewhat dangerous,
+and has hellishly powerful magical powers.
+
+Gorlim, Betrayer of Barahir is a unique monster,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, hellishly dangerous,
+and has remarkable magical powers.
+
+The Solar is a legendary monster,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, alarmingly dangerous,
+and has advanced magical powers.
+
+The Glabrezu is an uncommon monster,
+occurring at shallow-to-moderate depths.
+It is strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+Ren the Unclean is a unique undead monster,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, moderately dangerous,
+and has hellishly powerful magical powers.
+
+The Nalfeshnee is an uncommon monster,
+occurring at shallow-to-moderate depths.
+It is very strong, somewhat dangerous,
+and has small magical powers.
+
+The Undead beholder is a rare undead monster,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+The Dread is a common undead monster,
+occurring at shallow-to-moderate depths.
+It is somewhat strong, extremely dangerous,
+and has simple magical powers.
+
+The Mumak is an uncommon monster,
+occurring at shallow-to-moderate depths.
+It is alarmingly strong, just a small bit dangerous,
+and has no magical powers.
+
+The Ancient multi-hued dragon is a common dragon,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, alarmingly dangerous,
+and has extremely powerful magical powers.
+
+The Ethereal dragon is an uncommon dragon,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, moderately dangerous,
+and has average magical powers.
+
+Ji Indur Dawndeath is a unique undead monster,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, moderately dangerous,
+and has very powerful magical powers.
+
+The Marilith is an uncommon monster,
+occurring at shallow-to-moderate depths.
+She is hellishly strong, somewhat dangerous,
+and has an inkling of magical powers.
+
+Quaker, Master of Earth is a unique monster,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, hellishly dangerous,
+and has rudimentary magical powers.
+
+The Lesser Balrog is a somewhat rare monster,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, moderately dangerous,
+and has simple magical powers.
+
+Ariel, Queen of Air is a unique monster,
+occurring at shallow-to-moderate depths.
+She is hellishly strong, hellishly dangerous,
+and has average magical powers.
+
+The 11-headed hydra is an uncommon animal,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, just a small bit dangerous,
+and has extremely powerful magical powers.
+
+The Patriarch is an uncommon monster,
+occurring at shallow-to-moderate depths.
+He is extremely strong, somewhat dangerous,
+and has extremely powerful magical powers.
+
+The Dreadmaster is an uncommon undead monster,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, unimaginably dangerous,
+and has very powerful magical powers.
+
+The Drolem is a somewhat rare dragon,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, hellishly dangerous,
+and has small magical powers.
+
+Scatha the Worm is a unique dragon,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, somewhat dangerous,
+and has small magical powers.
+
+Dwar, Dog Lord of Waw is a unique undead monster,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, moderately dangerous,
+and has hellishly powerful magical powers.
+
+Smaug the Golden is a unique dragon,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, somewhat dangerous,
+and has small magical powers.
+
+The Dracolich is an uncommon undead monster,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, alarmingly dangerous,
+and has simple magical powers.
+
+The Greater titan is a somewhat rare monster,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, moderately dangerous,
+and has simple magical powers.
+
+The Dracolisk is an uncommon dragon,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, somewhat dangerous,
+and has simple magical powers.
+
+The Death mold is a common monster,
+occurring at shallow-to-moderate depths.
+It is hellishly strong, hellishly dangerous,
+and has no magical powers.
+
+Itangast the Fire Drake is a unique dragon,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, somewhat dangerous,
+and has small magical powers.
+
+Glaurung, Father of the Dragons is a unique dragon,
+occurring at shallow-to-moderate depths.
+He is hellishly strong, somewhat dangerous,
+and has unremarkable magical powers.
+
+The Master mystic is a somewhat rare monster,
+occurring at moderate depths.
+He is hellishly strong, hellishly dangerous,
+and has small magical powers.
+
+Durin's Bane is a unique monster,
+occurring at moderate depths.
+He is hellishly strong, moderately dangerous,
+and has remarkable magical powers.
+
+The Nightwing is a rare undead monster,
+occurring at moderate depths.
+It is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+The Nether hound is an uncommon animal,
+occurring at moderate depths.
+It is very strong, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Time hound is a rare animal,
+occurring at moderate depths.
+It is very strong, just a small bit dangerous,
+and has no magical powers.
+
+The Plasma hound is an uncommon animal,
+occurring at moderate depths.
+It is very strong, somewhat dangerous,
+and has an inkling of magical powers.
+
+The Demonic quylthulg is a common animal,
+occurring at moderate depths.
+It is moderately strong, just a small bit dangerous,
+and has unremarkable magical powers.
+
+The Great storm wyrm is an uncommon dragon,
+occurring at moderate depths.
+It is hellishly strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+Baphomet the Minotaur Lord is a unique monster,
+occurring at moderate depths.
+He is hellishly strong, somewhat dangerous,
+and has hellishly powerful magical powers.
+
+Harowen the Black Hand is a unique monster,
+occurring at moderate depths.
+He is hellishly strong, moderately dangerous,
+and has no magical powers.
+
+Hoarmurath of Dir is a unique undead monster,
+occurring at moderate depths.
+He is hellishly strong, somewhat dangerous,
+and has hellishly powerful magical powers.
+
+The Grand master mystic is a somewhat rare monster,
+occurring at moderate depths.
+He is hellishly strong, hellishly dangerous,
+and has arcane magical powers.
+
+Khamul the Easterling is a unique undead monster,
+occurring at moderate depths.
+He is hellishly strong, moderately dangerous,
+and has hellishly powerful magical powers.
+
+The Ethereal hound is a somewhat rare animal,
+occurring at moderate depths.
+It is unimaginably strong, somewhat dangerous,
+and has an inkling of magical powers.
+
+The Great ice wyrm is an uncommon dragon,
+occurring at moderate depths.
+It is hellishly strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Phoenix is a unique animal,
+occurring at moderate depths.
+It is hellishly strong, alarmingly dangerous,
+and has hellishly powerful magical powers.
+
+The Nightcrawler is a rare undead monster,
+occurring at moderate depths.
+It is hellishly strong, unimaginably dangerous,
+and has hellishly powerful magical powers.
+
diff --git a/lib/file/book-19.txt b/lib/file/book-19.txt
new file mode 100644
index 00000000..62ecebc9
--- /dev/null
+++ b/lib/file/book-19.txt
@@ -0,0 +1,250 @@
+The Hand druj is a rare undead monster,
+occurring at moderate depths.
+It is very strong, somewhat dangerous,
+and has extremely powerful magical powers.
+
+The Eye druj is a rare undead monster,
+occurring at moderate depths.
+It is unimaginably strong, moderately dangerous,
+and has hellishly powerful magical powers.
+
+The Skull druj is a rare undead monster,
+occurring at moderate depths.
+It is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+The Chaos vortex is a common monster,
+occurring at moderate depths.
+It is very strong, not one little bit dangerous,
+and has no magical powers.
+
+The Aether vortex is an uncommon monster,
+occurring at moderate depths.
+It is strong, unimaginably dangerous,
+and has hellishly powerful magical powers.
+
+The Lernean Hydra is a unique animal,
+occurring at moderate depths.
+It is hellishly strong, alarmingly dangerous,
+and has hellishly powerful magical powers.
+
+Thuringwethil is a unique undead monster,
+occurring at moderate depths.
+She is hellishly strong, alarmingly dangerous,
+and has very powerful magical powers.
+
+The Great hell wyrm is an uncommon dragon,
+occurring at moderate depths.
+It is hellishly strong, somewhat dangerous,
+and has rudimentary magical powers.
+
+The Draconic quylthulg is a somewhat rare animal,
+occurring at moderate depths.
+It is very strong, just a small bit dangerous,
+and has unremarkable magical powers.
+
+Fundin Bluecloak is a unique monster,
+occurring at moderate depths.
+It is hellishly strong, extremely dangerous,
+and has unimaginably powerful magical powers.
+
+Uriel, Angel of Fire is a unique monster,
+occurring at moderate depths.
+He is hellishly strong, alarmingly dangerous,
+and has hellishly powerful magical powers.
+
+Azriel, Angel of Death is a unique monster,
+occurring at moderate depths.
+He is hellishly strong, extremely dangerous,
+and has hellishly powerful magical powers.
+
+Ancalagon the Black is a unique dragon,
+occurring at moderate depths.
+He is hellishly strong, moderately dangerous,
+and has extremely powerful magical powers.
+
+The Nightwalker is a rare undead monster,
+occurring at moderate depths.
+It is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+Gabriel, the Messenger is a unique monster,
+occurring at moderate depths.
+He is hellishly strong, hellishly dangerous,
+and has remarkable magical powers.
+
+Saruman of Many Colours is a unique monster,
+occurring at moderate-to-deep depths.
+He is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+The Dreadlord is an uncommon undead monster,
+occurring at moderate-to-deep depths.
+It is hellishly strong, unimaginably dangerous,
+and has arcane magical powers.
+
+The Cat Lord is a unique monster,
+occurring at moderate-to-deep depths.
+He is hellishly strong, hellishly dangerous,
+and has an inkling of magical powers.
+
+The Chaos beetle is a rare monster,
+occurring at moderate-to-deep depths.
+It is hellishly strong, not at all dangerous,
+and has rudimentary magical powers.
+
+The Chaos hound is a common animal,
+occurring at moderate-to-deep depths.
+It is hellishly strong, just a small bit dangerous,
+and has an inkling of magical powers.
+
+The Great Wyrm of Chaos is an uncommon dragon,
+occurring at moderate-to-deep depths.
+It is hellishly strong, somewhat dangerous,
+and has very powerful magical powers.
+
+The Great Wyrm of Law is an uncommon dragon,
+occurring at moderate-to-deep depths.
+It is hellishly strong, somewhat dangerous,
+and has very powerful magical powers.
+
+The Great Wyrm of Balance is a rare dragon,
+occurring at moderate-to-deep depths.
+It is hellishly strong, somewhat dangerous,
+and has hellishly powerful magical powers.
+
+Tselakus, the Dreadlord is a unique undead monster,
+occurring at moderate-to-deep depths.
+He is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+Tiamat, Celestial Dragon of Evil is a unique dragon,
+occurring at deep depths.
+She is hellishly strong, unimaginably dangerous,
+and has hellishly powerful magical powers.
+
+The Black reaver is a somewhat rare undead monster,
+occurring at deep depths.
+It is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+The Master quylthulg is a somewhat rare animal,
+occurring at deep depths.
+It is hellishly strong, just a small bit dangerous,
+and has hellishly powerful magical powers.
+
+The Greater draconic quylthulg is a somewhat rare animal,
+occurring at deep depths.
+It is hellishly strong, just a small bit dangerous,
+and has simple magical powers.
+
+The Greater rotting quylthulg is a somewhat rare animal,
+occurring at deep depths.
+It is hellishly strong, just a small bit dangerous,
+and has simple magical powers.
+
+Vecna, the Emperor Lich is a unique undead monster,
+occurring at deep depths.
+He is hellishly strong, unimaginably dangerous,
+and has hellishly powerful magical powers.
+
+Omarax the Eye Tyrant is a unique monster,
+occurring at deep depths.
+He is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+Ungoliant, the Unlight is a unique animal,
+occurring at deep depths.
+She is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+The Aether hound is an uncommon animal,
+occurring at deep depths.
+It is hellishly strong, very dangerous,
+and has hellishly powerful magical powers.
+
+The Mouth of Sauron is a unique monster,
+occurring at deep depths.
+He is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+The Emperor Quylthulg is a unique animal,
+occurring at deep depths.
+It is hellishly strong, just a little bit dangerous,
+and has unimaginably powerful magical powers.
+
+Qlzqqlzuup, the Lord of Flesh is a unique animal,
+occurring at deep depths.
+It is hellishly strong, just a little bit dangerous,
+and has hellishly powerful magical powers.
+
+Murazor, the Witch-King of Angmar is a unique undead monster,
+occurring at very deep depths.
+He is hellishly strong, extremely dangerous,
+and has hellishly powerful magical powers.
+
+Pazuzu, Lord of Air is a unique monster,
+occurring at very deep depths.
+He is hellishly strong, hellishly dangerous,
+and has advanced magical powers.
+
+The Hell hound is a rare animal,
+occurring at very deep depths.
+It is somewhat strong, moderately dangerous,
+and has an inkling of magical powers.
+
+Cantoras, the Skeletal Lord is a unique undead monster,
+occurring at very deep depths.
+He is hellishly strong, unimaginably dangerous,
+and has hellishly powerful magical powers.
+
+The Tarrasque is a unique monster,
+occurring at very deep depths.
+It is hellishly strong, somewhat dangerous,
+and has average magical powers.
+
+Lungorthin, the Balrog of White Fire is a unique monster,
+occurring at very deep depths.
+He is hellishly strong, extremely dangerous,
+and has advanced magical powers.
+
+Draugluin, Sire of All Werewolves is a unique animal,
+occurring at very deep depths.
+He is hellishly strong, moderately dangerous,
+and has simple magical powers.
+
+Feagwath the Undead Sorceror is a unique undead monster,
+occurring at extremely deep depths.
+He is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+Carcharoth, the Jaws of Thirst is a unique animal,
+occurring at extremely deep depths.
+He is hellishly strong, moderately dangerous,
+and has advanced magical powers.
+
+Cerberus, Guardian of Hades is a unique animal,
+occurring at extremely deep depths.
+It is hellishly strong, moderately dangerous,
+and has very powerful magical powers.
+
+Gothmog, the High Captain of Balrogs is a unique monster,
+occurring at extremely deep depths.
+He is hellishly strong, unimaginably dangerous,
+and has advanced magical powers.
+
+Sauron, the Sorcerer is a unique monster,
+occurring at extremely deep depths.
+He is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+Morgoth, Lord of Darkness is a unique monster,
+occurring at bottomless depths.
+He is hellishly strong, hellishly dangerous,
+and has hellishly powerful magical powers.
+
+The Haughty noble is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
diff --git a/lib/file/book-2.txt b/lib/file/book-2.txt
new file mode 100644
index 00000000..75493c29
--- /dev/null
+++ b/lib/file/book-2.txt
@@ -0,0 +1,90 @@
+
+ Mordekainen's Magical Compendum of Deep Thought, Vol. 3
+ -------------------------------------------------------
+
+
+I think my new thing will be to try to be a real happy guy. I'll just
+walk around being real happy until some jerk says something stupid to
+me.
+
+When you're going up the stairs and you take a step, kick the other
+leg up high behind you to keep people from following too close.
+
+I wonder if angels believe in ghosts.
+
+I don't understand people who say life is a mystery, because what is
+it they want to know?
+
+I think people tend to forget that trees are living creatures. They're
+sort of like dogs. Huge, quiet, motionless dogs, with bark instead of
+fur.
+
+Sometimes I think the world has gone completely mad. And then I think,
+"Aw, who cares?" And then I think, "Hey, what's for supper?"
+
+If a kid asks where rain comes from, I think a cute thing to tell him
+is "God is crying". And if he asks why God is crying, another cute
+thing to tell him is "Probably because of something you did".
+
+Contrary to popular belief, the most dangerous animal is not the lion
+or tiger or even the elephant. The most dangerous animal is a shark
+riding on an elephant, just trampling and eating everything they see.
+
+As I bit into the nectarine, it had a crisp juiciness about it that
+was very pleasurable- until I realized it wasn't a nectarine at all,
+but a HUMAN HEAD!!
+
+Anytime I see something screech across a room and latch onto someone's
+neck, and the guy screams and tries to get it off, I have to laugh,
+because what _is_ that thing?!
+
+If you define cowardice as running away at the first sign of danger,
+screaming and tripping and begging for mercy, then yes, Mister Brave
+Man, I guess I am a coward.
+
+Blow ye winds, like the trumpet blows, but without that noise.
+
+The face of a child can say it all, especially the mouth part of the face.
+
+When I heard that trees grow a new "ring" for each year they live, I
+thought, we humans are kind of like that; we grow a new layer of skin
+each year; and after many years we are thick and unwieldy from all our
+skin layers.
+
+It's too bad that whole families have been torn apart by something as
+simple as wild dogs.
+
+Even though he was an enemy of mine, I had to admit that what he had
+accomplished was a brilliant piece of strategy. First, he punched me,
+then he kicked me, then he punched me again.
+
+To me, truth is not some vague, foggy notion. Truth is real. And, at
+the same unreal. Fiction and fact and everything in-between, plus some
+things I can't remember, all rolled into one big "thing". This is
+truth, to me.
+
+If you're ever stuck in some thick undergrowth, in your underwear,
+don't stop and start thinking of what other words have "under" in
+them, because that's probably the first sign of jungle madness.
+
+Sometimes the beauty of the world is so overwhelming, I just want to
+throw back my head and gargle. Just gargle and gargle, and I don't
+care who hears me, because I am beautiful.
+
+We used to laugh at Grandpa when he'd head off to go fishing. But we
+wouldn't be laughing when he'd come back with some whore he picked up
+in town.
+
+I think in one of my previous lives I was a mighty king, because I
+like people that do what I say.
+
+A man doesn't automatically get my respect. He has to get down in the
+dirt and beg for it.
+
+People think it would be fun to be a bird because you could fly. But
+they forget the negative side, which is the preening.
+
+When I think back on all the blessings I have been given in my life, I
+can't think of a single one, unless you count that rattlesnake that
+granted me all those wishes.
+
diff --git a/lib/file/book-20.txt b/lib/file/book-20.txt
new file mode 100644
index 00000000..c76012af
--- /dev/null
+++ b/lib/file/book-20.txt
@@ -0,0 +1,139 @@
+#####R /----------------------------------------\
+#####R < Adventurer's guide to the Middle-earth >
+#####R \----------------------------------------/
+
+Summary:
+*****/abook-20.txt*1[(a) The Towns]
+*****/bbook-20.txt*2[(b) Other strange and frightening places]
+*****/cbook-20.txt*3[(c) Equipment issues]
+*****/dbook-20.txt*4[(d) Macros]
+
+Introduction:
+
+Middle-earth is vast and mysterious, full of dangers but also full of
+rewards for the brave.
+
+New adventurers should know that pressing < and > can switch
+the wilderness view between a normal scale and a larger map. This map
+makes travelling safer and faster, but you can't enter wilderness
+dungeons from it.
+
+
+~~~~~1
+#####G(a) The Towns
+
+You start in a small village named Bree in the western part of the Middle-earth.
+Here you will also find the entrance to the Barrow-Downs, a fairly safe and
+simple dungeon.
+
+When the Barrow-Downs become too easy for you, and Bree too small,
+you might consider going to Lothlorien, the land of Galadriel. [[[[[BNote that]
+[[[[[Byou should take a lot of food with you, for it is a long journey.] You'll have
+to head south-east following the Moria mountain's chain, then walk around
+the forest of Fangorn to head north to finally find your destination. The Forest
+of Mirkwood (another dungeon) can be found to the north east of Lothlorien.
+
+If you survive this dangerous dungeon, you should head south, following
+the Anduin river. There, near the dark land of Mordor, you will find the
+great town of Gondor, Minas Anor. From there you can want to pay a "visit" to
+the land of Mordor, which is east of Minas Anor.
+
+After Mordor you should finally travel to Gondolin, the hidden town of the
+Noldor. First go back to Bree, and then from there walk northeast and you
+will find it. From this city, you will be able to attack Angband, the
+dungeon of Morgoth, which is north west west of Gondolin.
+
+
+~~~~~2
+#####G(b) Other strange and frightening places
+
+The Old Forest to the west is the last remains of the big forests of the first
+age, but it has been corrupted. It is said it is guarded by a living tree.
+
+You may also wish to investigate the Orc Caves north of Bree; they are
+another place suitable for those finished with the Barrow-Downs. They also
+are rumored to hold great
+mysteries.
+
+The Maze: To the south of Bree there is a magical Maze. Many adventurers
+that ventured there never came back... It is rumored that a Minotaur is
+lurking down there, guarding an ancient and powerful artifact.
+Bring along digging equipment and some means to recall.
+
+Durin's Bane, the Balrog of Moria, guards the Mines of Moria, to the south east
+of Bree.
+
+During the Second Age of the world there was a great island called
+Numenor. The people who dwelt there were wise and powerful, but as time
+passed their last kings fell under the power of Sauron. Under Sauron's
+orders, they tried to attack Valinor, the blessed land, and for this
+Numenor was destroyed, swallowed by the sea. The ruins are still
+accessible, far out to sea to the west of Bree.
+
+Many other strange places wait to be explored by the valiant adventurer,
+but their locations are secret. You will have to find them yourself!
+
+
+~~~~~3
+#####G(c) Equipment issues
+
+Beware adventurer! If you plan to go down into the dungeons be prepared. Some
+items you will need badly.
+
+First think of some light, maybe a lantern is better than the torches.
+
+Second things to mention are your combat equipment. Sometimes the weapon and
+armor you got from your mentor are not enough for the nasties inside the
+dungeons.
+
+And third and most important, [[[[[Balways carry a shovel or other digger with you],
+because there is much rubble in the dungeons, which you cannot clear with
+your hands.
+
+~~~~~4
+#####G(d) Macros
+
+Spellcasters might find that pressing 4 keys (at least) to cast a spell is a
+lot, they are right. That is why there are macros. You can access the macro
+screen by pressing @. You can find help on the *****macrofaq.txt*0[macros] in the docs.
+
+Now you either have the hard way or the easy way.
+
+**The Hard Way**
+
+What the fellow adventurer should know is how to create a basic spell macro.
+Press @ to enter the macro screen.
+Press 4 to create a new macro.
+Press the key to bind the macro to, usually one uses the F* keys(you can combine
+them with the ctrl, shift, ... keys too)
+Enter the key sequence to be done for the macro.
+Press 2 to save the macro.
+
+Now a problem that might arise, imagine your macro looks like: mcaa*t
+to cast manathrust spell('m' to use skill, 'c' for cast a spell skill,
+'a' for first book, 'a' for first spell, *t to… target the first monster).
+This macro will break if you gain a new skill so that "Cast a spell" is no more
+the skill 'c', or if you get a new book. There is a way around that.
+When the game asks for a skill or a spell it allows you to press @ to enter
+the skill/spell name directly, so your macro would become:
+m@Cast a spell\r@Manathrust\r*t
+Now this will always work as long as one of your books have the spell in it.
+
+
+**The Easy Way**
+
+This time you will only use the macro recorder. To do that:
+Press $ to start it
+Now each key you press will be recorded, so press all keys you want.
+It is recommended to start your macro by pressing Escape key a few time, so
+if there are messages when you use the macro it will first erase them instead
+of screwing your macro :)
+it is also recommended to take advantage of the @ key when selecting skills or
+objects whenever the possibility is offered to you. It will make sure you
+always use the good object/skill even if it moves in your inventory.
+Once all keys are pressed press $ again to stop it.
+It you are satisfied with your macro now you get to press the key to bind it
+to.
+
+As in the Hard Way you must use the macro screen if you want to permanently
+save your macros.
diff --git a/lib/file/book-200.txt b/lib/file/book-200.txt
new file mode 100644
index 00000000..21ad9089
--- /dev/null
+++ b/lib/file/book-200.txt
@@ -0,0 +1,5 @@
+4
+34
+21
+6
+0
diff --git a/lib/file/book-201.txt b/lib/file/book-201.txt
new file mode 100644
index 00000000..d89e8f16
--- /dev/null
+++ b/lib/file/book-201.txt
@@ -0,0 +1,5 @@
+4
+49
+11
+3
+0
diff --git a/lib/file/book-202.txt b/lib/file/book-202.txt
new file mode 100644
index 00000000..3c61caee
--- /dev/null
+++ b/lib/file/book-202.txt
@@ -0,0 +1,5 @@
+4
+50
+34
+4
+0
diff --git a/lib/file/book-203.txt b/lib/file/book-203.txt
new file mode 100644
index 00000000..c169a628
--- /dev/null
+++ b/lib/file/book-203.txt
@@ -0,0 +1,5 @@
+4
+60
+56
+3
+0
diff --git a/lib/file/book-4.txt b/lib/file/book-4.txt
new file mode 100644
index 00000000..29501076
--- /dev/null
+++ b/lib/file/book-4.txt
@@ -0,0 +1,11 @@
+Ash nazg durbatuluk,
+ash nazg gimbatul,
+ash nazg thrakatuluk
+agh burzum-ishi krimpatul.
+
+-------------------------------
+
+One Ring to rule them all,
+One Ring to find them,
+One Ring to bring them all,
+And in the darkness bind them.
diff --git a/lib/file/book-6.txt b/lib/file/book-6.txt
new file mode 100644
index 00000000..4a2638cb
--- /dev/null
+++ b/lib/file/book-6.txt
@@ -0,0 +1,263 @@
+
+ Artifact Lore, Vol. I
+ Ancient Weapons
+ ---------------------
+
+
+ The Longsword 'Ringil' (4d5) (+22,+25)
+ The Sword of Fingolfin (High-Elf). When wielded it will
+ haste its wielder. It is a blade of such deathly cold that
+ it shines bright white acting as a permanent light and
+ delivering cold criticals. It slays evil, demons, undead
+ and trolls. Allows you to resist cold, regenerate mana and
+ hit points more quickly with no extra food consumption. Also
+ lets you see invisible and be immune to paralyzation. Being
+ made of white eog, it is capable of casting Ice Storms.
+
+ The Longsword 'Anduril' (3d5) (+10,+15) [+5]
+ The Sword of Aragorn the Dunadan Ranger and King. It
+ increases your strength to match true Kingly strength,
+ increases armour class by +5. Being the 'Flame of the West'
+ it delivers heat criticals and defends against fire. It
+ slays evil, orcs and trolls. It allows you to see invisible
+ and avoid paralyzation. So near to the element fire is the
+ blade, that Fire Balls can be cast from its searing
+ surface.
+
+ The Lead-filled Mace 'Grond' (9d9) (+25,+25) [+10]
+ The Hammer of the Underworld, this is Morgoth's chief
+ weapon. It weighs so much that it slows anything of less
+ than godly status. It is so awesome that it aggravates all
+ that see it. It makes it's wielder see all and resist all.
+ It slays all of Morgoths personal creations of orcs, trolls,
+ and demons and it executes dragons doing five times normal
+ damage against them, (it can kill all but a very few dragons
+ in one mighty blow!). Plus it causes impact criticals that
+ cause earthquakes and it can tunnel through solid granite
+ walls!
+
+ The Two-Handed Sword 'Gurthang' (3d6) (+13,+17)
+ This Iron of Death belonging to Turin Turambar, made of
+ black eog, was designed to slay Dragons (and Trolls), doing
+ five times normal damage against dragons. It gives you the
+ strength to wield it, regenerates your hit points and mana
+ at no extra cost and allows you to be free of paralyzation.
+
+ The Two-Handed Sword 'Mormegil' (6d7) (0,0) [-20]
+ This evil black sword is heavily cursed, slowing its wielder
+ and aggravating all that see it...
+
+ The Broadsword 'Arunruth' (2d5) (+20,+12)
+ This Sword of Accuracy rarely misses. It increases the
+ wielders dexterity, saves from falls, slays orcs and demons,
+ and protects from paralyzation.
+
+ The Broadsword 'Glamdring' (2d5) (+10,+15)
+ This High-Elven sword (mate to Orcrist) was made during foul
+ orc wars of long ago. It was once wielded by Gandalf the
+ Grey Wizard. It slays orcs and other evil, shining bright
+ red continuously, which aids searching and decreases food
+ consumption. Its element is flame, and it gives resistance
+ to flame to the wielder, and slays those who have not.
+
+ The Broadsword 'Orcrist' (2d5) (+10,+15)
+ This High-Elven sword (mate to Glamdring) was made during
+ foul orc wars of long ago. It was once wielded by Thorin
+ Oakenshield the Dwarf-King-Under-the-Mountain. It slays orcs
+ and other evil, shining bright white continuously, which
+ decreases food consumption, plus making the wielder more
+ stealthy. Being of the element frost, it protects from cold,
+ and slays non-cold based creatures.
+
+ The Broadsword 'Aeglin' (2d5) (+12,+16)
+ This High-Elven sword, is the long, lost and forgotten third
+ mate to Orcrist and Glamdring. It is also the most powerful.
+ Like Glamdring and Orcrist, made during the Orc-wars, it
+ slays Orcish-kind, shining bright blue continuously, which
+ decreases food consumption and aiding searching. Being of
+ electric element, it delivers lightning criticals, which it
+ also defends against.
+
+ The Long Bow 'Belthronding' (+20,+22) (+3)
+ This Noldorin black-yew bow, belonged to the greatest elven
+ archer, Beleg Cuthalion, who was slain by his own blade, by
+ his best friend Turin Turumbar. The bow increases stealth
+ and dexterity, and rarely missed its target.
+
+ The Long Bow of Bard (+17,+19)
+ This bow of men gives free action and increased dexterity.
+
+ The Light Crossbow 'Cubragol' (+10,+14)
+ This amazing bow of fire hastes its wielder and brands
+ all bolts with its element.
+
+ The Bastard Sword 'Calris' (5d4) (-20,+20)
+ This sword of Lungorthin the Balrog of White Flame, is an
+ evil cursed sword that needs great mastering to control its
+ powers. If mastered it can execute dragons, slay other evil
+ including demons and trolls, this naturally aggravates them.
+ Also it gives its wielder far greater internal constitution.
+
+ The Spear 'Aeglos' (3d6) (+15,+25) [+5]
+ This Snow-thorn of Gil-Galad the High-Elf, delivers very
+ deep cold-criticals, while protecting you from cold and
+ increasing your armour class. Being elvish it naturally
+ slays orcs and trolls. It increases the wielders wisdom,
+ slows their digestion and frees their actions from holding
+ forces of evil, also casting Frost Balls occasionally.
+
+ The Spear 'Nimloth' (1d6) (+11,+13) (+3 to stealth)
+ This elven spear, branded with frost, allows its wielder
+ to creep up on the Undead and Slay them.
+
+ The Dagger 'Angrist' (2d5) (+10,+15) [+5]
+ This Iron-cleaver of Beren the Edain, increases and sustains
+ dexterity, increases you protection, prevents paralyzation
+ and slays orcs and trolls.
+
+ The Small sword 'Sting' (1d6) (+7,+8)
+ This small weapon is one of the most powerful weapons of
+ Westernesse. Once wielded by Bilbo and Frodo Baggins (of
+ Hobbit kind), Sting slays undead, evil, and orcs and also
+ shines a continuous, bright blue. It increases the wielder's
+ physical statistics and its piercing blue light lights up
+ those normally invisible to sight.
+
+ The Great Axe of Durin (4d4) (+10,+20) [+15]
+ This Wonderful Dwarven Axe was once wielded by Durin the
+ Deathless (Father and King of the Dwarves), gives its
+ wielder high protection, executes dragons, while resisting
+ fire and acid. It slays demons, trolls and orcs, frees
+ action and increases constitution.
+
+ The War Hammer of Aule (5d5) (+19,+21) [+5]
+ This is the great war hammer of the deity, Aule the Smith.
+ Forged in his great furnaces it delivers Shock criticals
+ causing five times normal damage to those not resistant to
+ this element, and even then it executes dragons, slays evil,
+ demons and undead. It resists fire, cold, acid and lightning
+ and allows you to see invisible and be free of paralyzation.
+ It increases its wielder's wisdom so that one may choose
+ wisely what to slay with it. Truly an awesome weapon.
+
+ The Two-Handed Great Flail 'Thunderfist' (3d6) (+5,+18)
+ This weapon of Electricity and Flame, delivers shock and
+ heat criticals, delivering five times or three times normal
+ damage against the respective types of creatures, also slays
+ animals, trolls and orcs. It also gives the wielder great
+ strength.
+
+ The Morningstar 'Bloodspike' (2d6) (+8,+22)
+ This Bloody weapon slays animals, trolls, and orcs. It allows
+ you to see invisible creatures, as well as giving the wielder
+ great strength.
+
+ The Quarterstaff 'Nar-i-vagil' (1d10) (+10,+20)
+ This fiery staff slays animals and resists fire, doing times
+ fire criticals. It also increases the wielders intelligence.
+
+ The Blade of Chaos 'Doomcaller' (6d5) (+18,+28) [-50]
+ This deadly blade calls doom to all who see it, this
+ naturally aggravates them. It shows you wherever a creature
+ is, be it invisible or blocked by a wall. It resists
+ all elements and executes dragons, slays evil, animal, orc
+ and troll. It delivers cold criticals, but severely impedes
+ its wielders health.
+
+ The Three Daggers, 'Narthanc', 'Nimthanc', 'Dethanc' (1d4) (+4,+6)
+ These elemental daggers of flame, frost, and electricity
+ respectively do their elemental criticals, and defend
+ against them. They also cast bolts of their element often.
+
+ The Dagger of Rilia (2d4) (+4,+3)
+ This ancient, and poisonous dagger casts stinking clouds
+ with great frequency.
+
+ The Dagger 'Belangil' (2d4) (+6,+9)
+ This nimble weapon of cold increases the wielder's dexterity
+ and regeneration, while slowing digestion. Being of dark
+ origins it see alls invisible and casts frost balls.
+
+ The Battle Axe of Balli Stonehand (3d6) (+8,+11) [+5]
+ This Dwarvish Battle axe protects from elements, falls and
+ the invisible. It slays all demons, trolls and orcs, giving
+ even dwarves the stealth, strength and constitution to do
+ so, never letting holding spells affect its use in a fight.
+
+ The Battle Axe 'Lotharang' (2d8) (+4,+3)
+ This petty-dwarvish axe, slays orcs and trolls, increasing
+ strength and dexterity. For those of faint heart it also
+ cures medium wounds and cuts.
+
+ The Morningstar 'Firestar' (2d6) (+5,+7) [+2]
+ This weapon of flame casts fire balls.
+
+ The Quarterstaff 'Eriril' (1d10) (+3,+5)
+ This staff of people who believe in the power of mind over
+ matter, greatly increases wisdom and intelligence and gives
+ the power to identify. It also sees invisible and slays all
+ evil.
+
+ The Longsword 'Elvagil' (2d5) (+2,+7)
+ This joyful sword increases dexterity, charisma and stealth.
+ It protects from falls and the invisible, and slays orcs and
+ trolls.
+
+ The Glaive of Pain (9d6) (+0,+30)
+ This weapon is designed to cause pain to anything without
+ discrimination.
+
+ The Lance of the Eorlingas (3d8) (+3,+21)
+ This heavy lance is suprisingly easy to control, allowing
+ slaughter of orcs, trolls and other evil (visible or not).
+
+ The Broad Axe 'Barukkheled' (2d6) (+13,+19)
+ This beautiful axe slays orcs, trolls, giants and other evil
+ (visible or not), while greatly increasing the wielders
+ internal constitution.
+
+ The Trident of Wrath (3d8) (+16,+18)
+ This extremely heavy and dangerous trident belonging to the
+ greatest Maiar spirit, Osse, slaughters evil and undead
+ without mercy wherever they hide, and increases the wielder's
+ strength and dexterity.
+
+ The Scimitar 'Haradekket' (2d5) (+9,+11)
+ This sword of the south slays the invisible undead, evil and
+ animals, and increases the wielder's dexterity. In addition,
+ the magically enhanced blade is rumored to give extra
+ attacks in combat.
+
+ The Lochaber Axe 'Mundwine' (3d8) (+12,+17)
+ This strong friend in battle, slays evil and resists the
+ elements.
+
+ The Cutlass 'Gondricam' (1d7) (+10,+11)
+ This defender increases the wielders dexterity.
+
+ The Sabre 'Careth Asdriag' (1d7) (+6,+8)
+ This lightning-quick blade slays dragons, giants, trolls,
+ orcs, and animals.
+
+ The Rapier 'Forasgil' (1d6) (+12,+19)
+ This glittering ice-blade also slays animals as well as
+ lighting the way.
+
+ The Executioner's Sword 'Crisdurian' (4d5) (+18,+19)
+ This executer slays evil, invisible undead, dragons, giants
+ orcs and trolls.
+
+ The Flail 'Totila' (3d6) (+6,+8) (+2)
+ This flaming flail slays evil in stealth. It also casts
+ confusion.
+
+ The Short sword 'Gilettar' (1d7) (+3,+7)
+ This roguish sword gives better regeneration and slower
+ digestion, slaying all animals with uncanny speed.
+
+ The Katana 'Aglarang' (8d4) (+0,+0)
+ This super-light and sharp katana greatly increases the
+ wielders dexterity and sustains it. Rarely does the wielder
+ get less than four attacks a round with it, and often as
+ many as six!
+
diff --git a/lib/file/book-7.txt b/lib/file/book-7.txt
new file mode 100644
index 00000000..f6a4a49b
--- /dev/null
+++ b/lib/file/book-7.txt
@@ -0,0 +1,141 @@
+
+ Artifact Lore, Vol. II
+ Ancient Armor
+ ----------------------
+
+
+ Adamantite Plate Mail 'Soulkeeper' [40,+20]
+ This amazing armour protects your soul from cold, and from
+ life level loss. It is also capable of fully healing you.
+
+ The Pair of Hard Leather Boots of Feanor [3,+20]
+ These amazing boots belonging to Feanor the High-Elf, haste
+ the wearer permanently and temporarily in combat, making him
+ or her stealthy as well.
+
+ The Pair of Soft Leather Boots 'Dal-i-thalion' [3,+15]
+ These amazing boots of agility, ensure free action in
+ combat, greatly increasing your dexterity and ensuring that
+ you will never become less agile. It is said that they can
+ also make you more confident and brave.
+
+ Full Plate Armour of Isildur [25,+25]
+ This armour of the Dunedain Lord, Isildur, Resists.
+
+ The Large Metal Shield of Anarion [5,+20]
+ This shield Resists and sustains your stats.
+
+ The Set of Cesti of Fingolfin (+10,+10) [5,+20]
+ These amazing gauntlets increase the wearers dexterity, and
+ slay creatures at (+10,+10). They will never be stopped by
+ paralyaztion and they also resist damage. They occasionally
+ grow magical spikes that can be fired causing great damage.
+
+ The Set of Leather Gloves 'Cambeleg' (+5,+5) [1,+15]
+ These Gloves of Might, increase strength and constitution.
+ They never allow their wearer to be paralyzed, and help
+ his/her slaying abilities.
+
+ The Set of Leather Gloves 'Cammithrim' [1,+10]
+ These Gloves of Light, sustain dexterity and give off light
+ so brightly that they can cast magic missiles almost
+ endlessly.
+
+ The Set of Gauntlets 'Paurhach' [2,+15]
+ These Fists of Fire resist fire and can cast fire bolts.
+
+ The Set of Gauntlets 'Paurnimmen' [2,+15]
+ These Fists of Frost resist cold and can cast frost bolts.
+
+ The Set of Gauntlets 'Pauraegen' [2,+15]
+ These Fists of Lightning resist lightning and can cast
+ lightning bolts.
+
+ The Set of Gauntlets 'Paurnen' [2,+15]
+ These Fists of Water resist acid and can cast acid bolts.
+
+ The Set of Gauntlets 'Camlost' (-11,-12) [2,+0] (-5)
+ The Empty Hand aggravates monsters, and greatly reduces
+ fighting ability. Named after the empty hand of Beren that
+ once clasped a Silmaril.
+
+ Mithril Chain Mail of Belegennon [28,+20]
+ This Chain Mail Resists and makes you stealthy.
+
+ The Iron Helm of Dor-Lomin [8,+20]
+ This is the Dragon Helm of Turin Turambar. It is rumored
+ that its wearer will never die in combat. It resists all
+ and sees all, and increases all fighting stats.
+
+ The Iron Helm of Holhenneth [5,+10]
+ This helm of brilliance and vision, greatly increases your
+ mental prowess. It allows you to see all that is hidden,
+ casting detection spells at frequent intervals.
+
+ The Iron Helm of Gorlim [5,+10] (-125)
+ This unhappy helm of betrayal ruins thought and sight.
+
+ Soft Leather Armour 'Hithlomir' [4,+20] (+4)
+ This dark-misty leather resists the elements and melds the
+ wearer into the background with incredible stealth.
+
+ Leather Scale Mail 'Thalkettoth' (+3) [11,+25]
+ This light leather scale mail is suprisingly good at
+ dodging attacks, and is resistant to acid. Often nicknamed
+ Blade-Turner.
+
+ Chain Mail of Arvedui [14,+15]
+ This wonderful chain mail belonged to the last king of
+ Arnor. It resists the elements and increases strength and
+ charisma.
+
+ The Hard Leather Cap of Thranduil [2,+10]
+ This acid resistant leather is a thinker's cap. Increasing
+ wisdom and intelligence.
+
+ The Metal Cap of Thengel [3,+12]
+ This cap of the Rohan King Thengel, gives kingly wisdom and
+ charisma.
+
+ The Steel Helm 'Hammerhand' [6,+20]
+ This warriors' helm increases the fighting stats.
+
+ The Large Leather Shield of Celegorm [4,+20]
+ A quality shield of Resistance.
+
+ The Pair of Metal Shod Boots of Thror [6,+20]
+ These Dwarf-king boots are ideal for combat, increasing
+ strength and constitution.
+
+ The Cloak 'Colluin' [1,+15]
+ This cloak of resistance even casts extra resistance spells
+ that can defend against poison.
+
+ The Cloak 'Holcolleth' [1,+4]
+ This mage cloak increases intelligence and wisdom and casts
+ spells to make monsters lose their concentration and fall
+ to sleep.
+
+ The Cloak 'Colannon' [1,+15]
+ This Gate-cloak, teleports the player at will, and gives
+ stealth so as to avoid awkward situations.
+
+ The Iron Crown of Beruthiel [0,+20] (-125)
+ This crown once belonged to the Cat-Queen of Gondor, who
+ disdained armed combat. Giving you cat like vision, and
+ sight within sight, it allows its wearer to be free of
+ combat, and infact finding armed combat beyond his or her
+ means.
+
+ The Iron Crown of Morgoth
+ This awesome artifact is a plain iron crown, mounted with
+ three jewels that capture the eternal light of the Trees
+ of the Valar, Teleperion and Laurelein. These Jewels were
+ made by the Noldorian High-Elf, Feanor who named them the
+ Silmarils. Their beauty, unsurpassed, drove Morgoth to
+ steal these jewels (with the aid of Ungoliant the Unlight).
+ The crown then, maximises all you stats, sustains all your
+ stats, is a permanent light source and allows the wearer to
+ see all.
+
+
diff --git a/lib/file/book-8.txt b/lib/file/book-8.txt
new file mode 100644
index 00000000..22a952fc
--- /dev/null
+++ b/lib/file/book-8.txt
@@ -0,0 +1,47 @@
+
+ Artifact Lore, Vol. III
+ Ancient Magical Tools
+ -----------------------
+
+
+ The Amulet of Ingwe (+3)
+ This amulet belonged to the high king of the Vanyar, the
+ most powerful of the High Elves. It gives resistance, and
+ greatly increases your wisdom and charisma. It gives you
+ good infravision, see invisible, and it casts a x5 strength
+ dispel evil.
+
+ The Amulet of Carlammas (+2)
+ This fiery amulet protects from flame, casts protection
+ from evil and increases your constitution.
+
+ The Phial of Galadriel (+4)
+ This wonderful object is an infinite light source, and once
+ identified it can light up rooms.
+
+ The Three Elven Rings
+ Made by Celebrimbor, Elf of the Girth-I-Mirdain. These
+ Rings of Power are of awesome power, and are very rare.
+
+ The Ring of Power 'Narya' (+1)
+ Celeborn gave this to Cirdan who gave it to Gandalf.
+ The least powerful of the Elven rings is of the element
+ fire. And as such makes you completely immune to fire. It
+ is also capable of casting very powerful fire balls. It
+ increases all your stats by one. It also protects from
+ from life draining and helps you regenerate.
+
+ The Ring of Power 'Nenya' (+2)
+ This was kept by Galadriel.
+ As Narya is to fire, Nenya is to Frost... Plus two to all
+ your stats.
+
+ The Ring of Power 'Vilya' (+3)
+ This was kept by Gil-galad who gave it to Elrond.
+ This gives immunity to lightning and resists poison. Plus three
+ to all your stats. Casts very powerful lightning balls.
+
+ Rumors exist of a Ring of Power known as the One Ring, which was
+ made to master the other Rings of Power. Its powers are what
+ legends are made of....
+
diff --git a/lib/file/book-9.txt b/lib/file/book-9.txt
new file mode 100644
index 00000000..2c37a3aa
--- /dev/null
+++ b/lib/file/book-9.txt
@@ -0,0 +1,240 @@
+The Filthy street urchin is an uncommon monster,
+occurring at surface depths.
+He is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Scrawny cat is a somewhat rare animal,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Scruffy little dog is a somewhat rare animal,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+Farmer Maggot is a unique monster,
+occurring at surface depths.
+He is somewhat weak, somewhat dangerous,
+and has no magical powers.
+
+The Blubbering idiot is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Boil-covered wretch is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Village idiot is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Pitiful looking beggar is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Mangy looking leper is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Squint eyed rogue is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Singing, happy drunk is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Aimless looking merchant is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Mean looking mercenary is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Town Guardsman is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Grey mold is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Grey mushroom patch is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Giant yellow centipede is a common monster,
+occurring at surface depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Giant white centipede is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The White icky thing is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Clear icky thing is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Giant white mouse is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Large brown snake is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Large white snake is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Small kobold is a common monster,
+occurring at surface depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Kobold is a common monster,
+occurring at surface depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The White worm mass is a common animal,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Floating eye is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Rock lizard is a common animal,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Jackal is a common animal,
+occurring at surface depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Soldier ant is a common monster,
+occurring at surface depths.
+It is laughably weak, not at all dangerous,
+and has no magical powers.
+
+The Fruit bat is a common animal,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Shrieker mushroom patch is a common monster,
+occurring at surface depths.
+It is laughably weak, not at all dangerous,
+and has an inkling of magical powers.
+
+The Blubbering icky thing is a common monster,
+occurring at surface depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The Metallic green centipede is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Novice warrior is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Novice rogue is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Novice priest is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has small magical powers.
+
+The Novice mage is a common monster,
+occurring at surface depths.
+He is laughably weak, not one little bit dangerous,
+and has rudimentary magical powers.
+
+The Yellow mushroom patch is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The White jelly is a common monster,
+occurring at surface depths.
+It is laughably weak, somewhat dangerous,
+and has no magical powers.
+
+The Giant green frog is a common animal,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Giant black ant is a common monster,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Salamander is a common animal,
+occurring at surface depths.
+It is laughably weak, just a little bit dangerous,
+and has no magical powers.
+
+The White harpy is a common animal,
+occurring at surface depths.
+She is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+The Blue yeek is a common animal,
+occurring at surface depths.
+It is laughably weak, not one little bit dangerous,
+and has no magical powers.
+
+Grip, Farmer Maggot's dog is a unique animal,
+occurring at surface depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+Fang, Farmer Maggot's dog is a unique animal,
+occurring at surface depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
+The Green worm mass is a common animal,
+occurring at surface depths.
+It is laughably weak, just a small bit dangerous,
+and has no magical powers.
+
diff --git a/lib/file/bravado.txt b/lib/file/bravado.txt
new file mode 100644
index 00000000..bf151229
--- /dev/null
+++ b/lib/file/bravado.txt
@@ -0,0 +1,106 @@
+104
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+cackles evilly.
+cackles diabolically.
+says: 'Surrender, miserable flea!'
+says: 'Come get some!'
+says: 'Let's rock!'
+laughs devilishly.
+says: 'Flee while you can, gnat!'
+says: 'You are about to die, maggot!'
+says: 'Read your prayers!'
+hisses: 'Die!'
+says: 'You don't have a chance, moron!'
+says: 'Fear my wrath, fool!'
+says: 'Feel my fury, dolt!'
+says: 'Groo is a genius, compared to you!'
+gives you a contemptuous glance.
+says: 'Prepare to meet your Maker, fool!'
+says: 'Perish, mortal!'
+says: 'Your puny efforts make me laugh!'
+says: 'Drop dead, wimp!'
+says: 'You should have fled while you had the chance.'
+screams: 'Die by my hand!'
+says: 'Your last wish, punk?'
+says: 'Your death shall be a slow, painful one.'
+says: 'Your head shall be my next trophy.'
+screams: 'You are DOOMED!'
+grins sadistically.
+says: 'This dungeon shall be your TOMB!'
+laughs fiendishly.
+says: 'Your fate is sealed, worm.'
+says: 'Resistance is useless.'
+says: 'Hell shall soon claim your remains.'
+says: 'Thou shalt repent of thy cunning.'
+says: 'Verily, thou shalt be one dead cretin.'
+says: 'Surrender or die!'
+says: 'Savor thy breath, it be thine last.'
+says: 'Prepare to die, miscreant!'
+says: 'You're history, dude!'
+says: 'Feeling lucky, punk?'
+says: 'You're toast!'
+says: 'You're dead meat.'
+says: 'Make my day.'
+says: 'I shall flatten you!'
+says: 'I could spare you, but why?'
+says: 'Take this, you sissy!'
+says: 'Nothing can save you now!'
+says: 'This dungeon ain't big enough for the both of us.'
+says: 'I'm gonna break your face!'
+says: 'I hope you enjoy pain!'
+says: 'Give me your best blow!'
+says: 'Draw, if you are a man!'
+says: 'A time to die, fool!'
+bellows frighteningly!
+says: 'You will never leave this dungeon alive!'
+says: 'You'll leave this dungeon only in a wooden box!'
+says: 'Your mother wears army boots!'
+says: 'Drop that weapon, NOW!'
+says: 'Life ain't for you, and I'm the cure!'
+says: 'Resistance is futile. You will be terminated.'
+says: 'Sight and smell of this, it gets me going.'
+says: 'Victim is your name and you shall fall.'
+says: 'Stepping out? You'll feel our hell on your back!'
+says: 'Now I will waste my hate on you.'
+says: 'Don't tread on me!'
+says: 'So be it! Threaten no more!'
+says: 'Kill for gain or shoot to maim, but I don't need a reason.'
+says: 'You'll die as you lived, in a flash of the blade.'
+says: 'You'd better stand cos there's no turning back.'
+says: 'I just want to see your blood, I just want to stand and stare.'
+says: 'I've been looking so long for you; you won't get away from my grasp.'
+says: 'I'm coming after you; you can kiss your arse good-bye.'
+says: 'It's official; you suck!'
+sings: 'I hate you, you hate me, we're a helluva family.'
+says: 'A mere mortal dares challenge *ME*?!'
+says: 'There is no escape and that's for sure.'
+says: 'This is the end; I won't take any more.'
+says: 'Say good-bye to the world you live in.'
+says: 'You've always been taking, but now you're giving.'
+says: 'My brain's on fire with the feeling to kill.'
+says: 'Don't try running away, because you're the one I'll find.'
+says: 'I was looking for you to start up a fight.'
+says: 'My innocent victims are slaughtered with wrath and despise!'
+says: 'I have found you, and there is no place to run.'
+says: 'My blood lust defies all my needs.'
+says: 'And damn'd be him that first cries: Hold, enough!'
+says: 'I can smell your blood, human!'
+says: 'Has your folly led to this?'
+wonders aloud how many experience points you're worth...
+says: 'Pride yourself on this, that you were slain by a champion.'
+thunders: 'May heaven have mercy on your soul, for I will have none.'
+screams for your blood!
+sighs: 'They send a poorer grade of adventurers down each year than the last.'
+says: 'Your life-blood will baptise my blade!'
+shouts: 'You will serve me in Valhalla!'
+snickers: 'Mommy's not here to save you now!'
+says: 'You're almost not worth killing... almost!'
+leaps towards you with death in its eye.
+sings: 'Cuts yer if ye stand, shoot yer if ye run.'
+says: 'Another adventurer? I just got through picking my teeth with the last.'
+says: 'Your two ears will decorate my belt.'
+says: 'I love all that blood.'
+says: 'I don't want to hurt you. I only want to kill you.'
+says: 'I like killing people, because it's so much fun.'
+screams: 'I'm out to destroy and I will cut you down!'
+says: 'Bring it on!'
diff --git a/lib/file/chainswd.txt b/lib/file/chainswd.txt
new file mode 100644
index 00000000..4755391c
--- /dev/null
+++ b/lib/file/chainswd.txt
@@ -0,0 +1,8 @@
+6
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+KILL, KILL, KILL!
+The Chainsword roars noisily!
+VROOM! VROOM!
+Kill, kill, kill, kill, kill, kill!
+Blood, blood, blood!
+Bloodbath!
diff --git a/lib/file/dam_huge.txt b/lib/file/dam_huge.txt
new file mode 100644
index 00000000..62f2ba60
--- /dev/null
+++ b/lib/file/dam_huge.txt
@@ -0,0 +1,9 @@
+7
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+You nearly decapitate %s!
+You impale %s on your weapon.
+Your weapon almost slices %s in half!
+%^s's head caves in!
+You broke %s's spine!
+Your weapon slices into %s's heart!
+You smashed %s's ribcage!
diff --git a/lib/file/dam_lots.txt b/lib/file/dam_lots.txt
new file mode 100644
index 00000000..1784d67c
--- /dev/null
+++ b/lib/file/dam_lots.txt
@@ -0,0 +1,21 @@
+18
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+You stab %s in the stomach.
+You cut off %s's hand.
+You chop down on %s's shins.
+You gave %s a deep gash.
+You gave %s a gigantic bruise.
+You cut off %s's arm!
+You cut off %s's leg!
+You stab %s in the heart.
+You slash at %s face.
+You throw %s down at the ground.
+You attempt to strangle %s.
+You grab %s's head and twist it.
+You knocked out several of %s's teeth!
+You broke some of %s's ribs!
+%^s spins around dizzily after your blow.
+%^s sputters at your tight, choking hold!
+%^s grunts under the force of your blows.
+%^s screams shrilly in fear.
+
diff --git a/lib/file/dam_med.txt b/lib/file/dam_med.txt
new file mode 100644
index 00000000..fc1db066
--- /dev/null
+++ b/lib/file/dam_med.txt
@@ -0,0 +1,25 @@
+23
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+You kick %s in the belly!
+You head-butt %s.
+You push %s over.
+You broke %s's finger!
+You broke %s's toe!
+You kick %s in the shins.
+You stab %s in the arm.
+You stab %s in the leg.
+You hit %s over the head.
+You knee %s in the groin!
+You aim a high kick at %s's head.
+You stab %s in the ribs.
+You chop at %s's neck.
+You put a tight choke-hold on %s.
+You attempt to topple %s over.
+You punch %s.
+You attempt to poke %s in the eye!
+You twist %s's leg.
+You twist %s's arm.
+You bend %s's fingers.
+You punch %s in the kidneys!
+You smash %s with your elbow.
+You smash %s with your knee.
diff --git a/lib/file/dam_none.txt b/lib/file/dam_none.txt
new file mode 100644
index 00000000..a6c20248
--- /dev/null
+++ b/lib/file/dam_none.txt
@@ -0,0 +1,24 @@
+22
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+You scratch %s.
+You give %s a nasty bruise.
+You stub %s's toe.
+You jab %s in the ribs.
+You almost poked your eye out while fighting %s!
+You made %s's nose bleed.
+You almost slipped while fighting %s.
+%^s doesn't even flinch!
+You accidentally hurt yourself while fighting %s.
+You slap %s.
+%^s slips and falls.
+%^s laughs at your wild swings.
+You pull at %s's hair.
+You punch %s in the nose.
+You pull at %s's ear.
+%^s growls at you.
+%^s is very, very annoyed!
+You scream an insult at %s.
+%^s makes a nasty face.
+You scowl at %s.
+%^s gnashes his teeth.
+%^s lets out a gurgling laugh.
diff --git a/lib/file/dam_xxx.txt b/lib/file/dam_xxx.txt
new file mode 100644
index 00000000..afceffe1
--- /dev/null
+++ b/lib/file/dam_xxx.txt
@@ -0,0 +1,11 @@
+9
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+%^s disintegrates into a fine mist!
+%^s splatters all over the floor.
+%^s explodes into tiny chunks.
+%^s's bones are crushed at the force of your blow!
+You almost squash %s into a pancake!
+Your weapons neatly slice %s into many little pieces.
+You cleave %s in half.
+%^s's head flies off in a wide trajectory.
+%^s is driven several feet into the ground under your blow!
diff --git a/lib/file/dead.txt b/lib/file/dead.txt
new file mode 100644
index 00000000..f32dae4d
--- /dev/null
+++ b/lib/file/dead.txt
@@ -0,0 +1,24 @@
+ #s_____#w #D,#w-#Wv#s___#w
+ #s_d&#y*#D'"#w #W/#w #D`#w|
+ #D,#W/#s?#D'#w | |#D'#w
+ #s?#D'#w|#D'#w | #D.,#W~#w-#D'""'#w |#D.#w
+ #D,#w| #sT#w --#y+#w-- #D,#W~#D'#w #D.,#W~#s:#w| #D`#W~\#w
+ | #sL#w | #D,#Wv#s_#D.#w #W/#D'#w #D,#W/#D"#w | #sT#D`#W\#D.`#W\#D.#w
+ |#D.#w |#W\#w | #D""'#w #s?#w--#Wv#D,#s?#w |#D'#w #s?#D,#w #W\#D.#w
+ #W\#w #D`#W\#D.#w #sT#w #D`#W~#w-#W\#s_]#w |
+ #D`#W\#D.#w #D"#W^~v#D.#w | #D"#W^#w-#W~v#w
+ #D`#W\#s_#w #sT#D.#w #D"#W^~v#w #D.#s__#D.#w #W/#w
+ #D``#w-#W~#w--| | |#D,#w #D"#s:#w| #D.#s___#D.#w #D.#w|
+ #D`#W\#w #s?#W\#w #W/#w #W/#w #D"#s:&#w #D,#w-#Wv#s_#W/#w
+ #D`#W\#D.#w #D`#W\#w| |#D'#w #D.,#W~#D'#w #D.#W/#D'#w
+ #D`#W~\#D.#w #D`#W^#D'"#w #D,#W~#D'#w
+ #D.#w| #s__#Wv#w-#W~#D''#w
+ #W/#w #W/#D'#w
+ #D,#w| #D.#w|
+ #W/#w #sJ#w
+ |#D'#w |
+---------------------------------------------#W/#w #W/#s:#w-------------------------
+ |#D'#w #D,#w|
+ |#D'#w #D'#w
+ #D`#w
+
diff --git a/lib/file/death.txt b/lib/file/death.txt
new file mode 100644
index 00000000..73ac47cd
--- /dev/null
+++ b/lib/file/death.txt
@@ -0,0 +1,351 @@
+349
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+Live and let live, right..?
+AAAAAAAAARRRRRRRRRRRRRRGGGGGGGGGGGGGHHHHHHHHHHHHHHH!!!!!!!!!!!!
+AAAARRRGGGHHH!!!
+Somehow, I have a bad feeling about this...
+Strangely, all of a sudden I don't feel so good.
+You can see armored women on winged horses coming for you.
+Oh well, you can't always win.
+I'm too young to die!
+I'll be back!
+O, untimely death!
+Slave, thou hast slain me!
+Ouch! That smarts!
+Who knocked?
+Did anybody get the number of that truck..?
+Ouch.
+Et tu, Brute! Then fall, Caesar!
+O! I die, Horatio...
+I told you to be careful with that sword...
+This guy's a little crazy...
+Ok, ok, I get it: No more pals.
+No more mr. nice guy!
+Who turned off the light..?
+Join the army, see the world, they said...
+Mom told me there'd be days like this...
+Rats!
+Shall this fellow live?
+Help, ho!
+What ho! Help!
+What hast thou done?
+I'll be revenged on the whole pack of you!
+You will *pay* for this!
+They say blood will have blood...
+Violence is no solution!
+Yes?
+#&%#&#%*#*&%!!!!!
+F***!
+No time to make a testament?
+Ugh!
+Aargh!
+Aaagghhh!
+I'm melting!
+Oof..
+Oh!
+Did somebody knock?
+Later, dude...
+CU!
+What? Who? Me? Oh, s..t!
+...amen!
+Eeek!
+Aacch!
+I hate it when that happens.
+One direct hit can ruin your whole day.
+Oh no!
+Not me!
+Ouch.
+Oh no, not again.
+Another one bites the dust.
+Goodbye.
+Help me!
+Farewell, cruel world.
+Oh man!
+Doough!
+This is the End, my only friend.
+It's all over.
+The fat lady sang.
+Why does everything happen to me?
+I'm going down.
+Crapola.
+Pow!
+Bif!
+Bam!
+Zonk!
+I should've listened to my mother...
+No... a Bud light!
+What was that noise?
+Mama said there'd be days like this.
+It's just one of those days...
+I see a bright light...
+Mommy? Is that you?
+I let you hit me!
+Sucker shot!
+I didn't want to live anyway.
+-<sob>-
+Hah haa! Missed me! Ha---
+Was that as close as I think it was?
+Monsters rejoice: the hero has been defeated.
+It wasn't just a job it was an adventure!
+I didn't like violence anyway!
+I thought you liked me?
+Such senseless violence! I don't understand it.
+I think this guy's a little crazy.
+Somehow I don't feel like killing anymore.
+Help me! I am undone!
+Hey! Killin' ain't cool.
+This fell sergeant, Death, is strict in his arrest...
+The rest is silence.
+Guh!
+It's game over, man!
+You've run out of life.
+Thou art slain.
+Finish him!
+Trust me, I know what I'm doing...
+Die, mortal!
+Kill men i' the dark! What be these bloody thieves?
+Ho! Murder! Murder!
+O! I am spoil'd, undone by villains!
+O murderous slave! O villain!
+O, falsely, falsely murder'd!
+A guiltless death I die.
+AAAAAAAAAAAAAAAAAAAAAAAAHHHHHHH!
+Trust me.
+Dammit, this thing won't die!
+He hit me for HOW MUCH?????
+Look, behind you!!!
+Who fed steroids to that kobold?
+Don't worry, be happy!
+I don't believe this!
+Oops.
+Oups.
+Can't you take a joke?
+Well, I didn't much like this character, anyway...
+Oops, sorry... didn't mean to disturb you.
+I never get to have any fun!
+Stop!
+Cut it out!
+Don't worry. I've got a plan.
+It didn't look so tough.
+Run away!
+All clear, guys.
+AGAIN!?!?!
+I don't like this dungeon...
+Maybe this wasn't such a good idea.
+My God will protect me.
+You wouldn't dare!
+But what about my Parry Skill? Tumbling?
+Don't worry - I have Pilot-7.
+And I've *never* done you any harm.
+I don't understand. It should be dead by now.
+I'm heir to the crown. They wouldn't dare!
+Hey! Where's my stomach? My hands?
+Ha! That's the oldest trick in the book.
+Cover me.
+Watch this.
+And damn'd be him that first cries, 'Hold, enough!'
+I will not yield.
+...but like a man he died.
+If you cut me down, I will only become more powerful.
+Well, at least I tried...?
+What could possibly have gone wrong?
+You die...
+What's with that weirdo with the teeth?
+Surrender? Never!
+I'm sure reinforcements will get here on time. They promised.
+Funny, didn't *look* like a cyberpsycho....
+I have a very bad feeling about this.
+Do something, SCHMUCK!
+I feel I could cast 'Speak with Dead' and talk to myself.
+Oh, that's just a light wound.
+Ach, is doch nur 'ne Fleischwunde...
+I thought you were on MY side...
+Next time, try talking!
+Oh shit... I'll try to teleport again.
+Somebody get me a Rod of Resurrection... QUICK!
+Uhh... oh-oh...
+Gee, where'd everybody go?
+I see it coming...aaargllhhhh! {sough}
+What do you mean 'aaargllhhhh'? Hey man, I've paid for this.
+Ay! Ay! Ay!
+Ohe! Ohe! Ohe!
+Et tu, Caesar! Then fall, Brute!
+Even the best laid plans...
+Hey, not too rough!
+The Random Number Generator hates me!
+So when I die, the first thing I will see in heaven is a score list?
+Can't we talk this thing over?
+Wait! Spare me and I'll make you rich! Money is not a problem!
+I hate you!
+By the kind gods, 'twas most ignobly done!
+Mein Leben!
+Meine Lieder!
+I'm the hero of this story! I CAN'T die!
+I thought heroes were supposed to win!
+Gee... thanks.
+You've fallen and can't get up!
+911?
+Sure don't look good...
+Oh No! Here I blow again!
+Hey - I've got lawyers.
+Thanks, I needed that.
+I AM toast!!
+Scheisse!
+Fatality!
+Brutality!
+Toasty!
+And you thought Tristan was unlucky...
+Just wait till I get my hands on the crook who sold me this crappy armor...
+All is lost. Monks, monks, monks!
+All my possessions for a moment of time!
+Don't let poor Nelly starve!
+Wally, what is this? It is death, my boy: they have deceived me.
+Everyone dances with the Grim Reaper.
+Adios.
+I'm going home, babe.
+I am innocent, innocent, innocent!
+Watch where you're pointing with that sword! You nearly...
+Hmm, some things are better wanted than had...
+And they told me it was not loaded.
+Of course I know what I am doing.
+It looked harmless.
+Hilfe, hilfe, hilfe!
+Look, dad! No head!
+Look! I'm flying!
+Think I'm gonna fall for that?
+I'll be back... as soon as I can.
+3... 2... 1... Liftoff!
+My wallet? In your dreams!
+Yes! Yes! YES! YES! YY... AAARRRGGGHH!
+See you later, alligator!
+Up, up and awaaaayyy!
+Been nice knowing you.
+But I just got a little prick!
+And I just wanted that fancy suit of armour you were carrying...
+Hey guys, where are you?
+Hey look... ARCHERS!
+I can't probably miss...
+I don't care. I have a Scroll of Raise Dead.
+I don't care. I have a Ring of Regeneration.
+I have this dungeon at home, I know where everything is!
+This HAS to be an illusion. I attempt to disbelieve it.
+I thought you could be trusted.
+Never try to sneak in a plate mail.
+I'll never surrender.
+I'll use the Cheat Death option...
+I'm invincible!
+I'm death incarnate! Nothing can harm me!
+Hey, it was only a joke, all right?
+Hey, don't talk to me like that!
+I have rights, too!
+Just because you're big and ugly doesn't mean you can push ME around.
+Me first! Me first!
+Let me handle this.
+No problem. That's easy.
+Oh, shit.
+So what?
+Tell me this is an illusion... please!
+I hate the RNG...
+They need a twenty to hit me! I'm invincible!
+Trust me.
+CHARGE!
+What do you mean, how many hit points do I have?
+What do you mean, my GOI expired?
+Yeah, I knew it was dangerous, but I was thinking about the experience points.
+You mean you get to use the critical hit chart too?
+You'd have to be a GOD to smile after that hit!
+I'm not afraid of death. I just don't want to be there when it happens.
+I have such sweet thoughts.
+I pray you all pray for me.
+I shall hear in heaven.
+Is not this dying with courage and true greatness?
+I must sleep now.
+Nurse, nurse, what murder! What blood! I have done wrong!
+It is finished.
+That unworthy hand! That unworthy hand!
+I am dying.
+Oh, dear.
+I will not kneel. Strike!
+I have led a happy life.
+Dying, dying.
+I feel the flowers growing over me.
+Now it is come.
+Let me die to the sound of sweet music.
+I will now enter the Halls of Mandos.
+Ungrateful traitors!
+We perish, we disappear, but the march of time goes on forever.
+Youth, I forgive thee.
+Treason! Treason!
+Coward! Why did you not protect me?
+I am absolutely undone.
+It is well. I die hard, but am not afraid to go.
+Do let me die in peace.
+Nothing is real but pain now.
+Violent use brings violent plans.
+Soldier boy, made of clay, now an empty shell.
+Bodies fill the fields I see, the slaughter never ends.
+Life planned out before my birth, nothing could I say.
+Blood will follow blood, dying time is here.
+Never happy endings on these dark sets.
+No one to play soldier now, no one to pretend.
+Time for lust, time for lie, time to kiss your life goodbye.
+Greetings, Death, he's yours to take away.
+I was born for dying.
+The higher you walk, the farther you fall.
+Where's your crown, King Nothing?
+Exit: light - enter: night!
+New blood joins this earth...
+You labeled me, I'll label you, so I dub thee unforgiven.
+If you're gonna die, die with your boots on!
+There's a time to live, and a time to die, when it's time to meet the maker.
+Isn't it strange, as soon as you're born you're dying?
+Only the good die young, all the evil seem to live forever.
+I don't wanna die, I'm a god, why can't I live on?
+And in my last hour, I'm a slave to the power of death.
+Now I am cold, but a ghost lives in my veins.
+You got to watch them - be quick or be dead.
+Heaven can wait 'till another day.
+You'll take my life but I'll take yours too.
+We won't live to fight another day.
+As I lay forgotten and alone, without fear I draw my parting groan.
+Somebody please tell me that I'm dreaming!
+Can't it be there's been some sort of error?
+Is it really the end not some crazy dream?
+Life down there is just a strange illusion.
+Your body tries to leave your soul.
+I'm so tired of living, I might as well end today.
+Life, life! Death, death! How curious it is!
+Catch my soul 'cos it's willing to fly away!
+Flames? Not yet, I think.
+Someone call the Gendarmes!
+I split my brain, melt through the floor.
+And now the dreams end.
+Off to Never-Never Land!
+Death greets me warm, now I will just say goodbye.
+What is this? I've been stricken by fate!
+This can't be happening to me!
+Flash before my eyes: now it's time to die.
+You have been dying since the day you were born.
+No point asking who's to blame.
+But for all his power he couldn't foresee his own demise.
+My creator will lay my soul to rest.
+Was that worth dying for?
+Can you say you are proud of what you've done?
+But there are some things which cannot be excused.
+Why is it some of us are here just so that we'll die?
+The shortest straw, pulled for you.
+There's got to be just more to it that this or tell me why do we exist?
+I can't believe that really my time has come.
+Too much of a good thing, I guess...
+I really screwed up this time.
+Wow, what a trip!
+What is Time, friend or foe
+Time waits for none
+Running through your fingers like sand
+Taking us along to future unknown
+And all too sudden, like it or not
+We become part of the Land.
+Hah! I'm not dead yet. I still have five hit points.
+I don't understand. It should be dead by now.
+I rolled a 20. How could that be a miss?
+What the frell?!
diff --git a/lib/file/elvish.txt b/lib/file/elvish.txt
new file mode 100644
index 00000000..a00b5a22
--- /dev/null
+++ b/lib/file/elvish.txt
@@ -0,0 +1,218 @@
+216
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+adan
+ael
+in
+agl
+ar
+aina
+alda
+al
+qua
+am
+arth
+amon
+anca
+an
+dune
+anga
+anna
+ann
+on
+ar
+ien
+atar
+band
+bar
+ad
+bel
+eg
+brag
+ol
+breth
+il
+brith
+cal
+en
+gal
+en
+cam
+car
+ak
+cel
+eb
+cor
+on
+cu
+cui
+vie
+cul
+curu
+dae
+dag
+or
+del
+din
+dol
+dor
+draug
+du
+duin
+dur
+ear
+ech
+or
+edh
+el
+eith
+elen
+er
+ereg
+es
+gal
+fal
+as
+far
+oth
+faug
+fea
+fin
+for
+men
+fuin
+gaer
+gaur
+gil
+gir
+ith
+glin
+gol
+odh
+gond
+gor
+groth
+grod
+gul
+gurth
+gwaith
+gwath
+wath
+had
+hod
+haudh
+heru
+him
+hini
+hith
+hoth
+hyar
+men
+ia
+iant
+iath
+iaur
+ilm
+iluve
+kal
+gal
+kano
+kel
+kemen
+khel
+ek
+khil
+kir
+lad
+laure
+lhach
+lin
+lith
+lok
+lom
+lome
+londe
+los
+loth
+luin
+maeg
+mal
+man
+mel
+men
+menel
+mer
+eth
+min
+as
+mir
+mith
+mor
+moth
+nan
+nar
+naug
+dil
+dur
+nel
+dor
+nen
+nim
+orn
+orod
+os
+pal
+an
+pel
+quen
+quet
+ram
+ran
+rant
+ras
+rauko
+ril
+rim
+ring
+ris
+roch
+rom
+rond
+ros
+ruin
+ruth
+sarn
+ser
+eg
+sil
+sir
+sul
+tal
+dal
+tal
+ath
+tar
+tath
+ar
+taur
+tel
+thal
+thang
+thar
+thaur
+thin
+thol
+thon
+thor
+on
+til
+tin
+tir
+tol
+tum
+tur
+uial
+ur
+val
+wen
+wing
+yave
diff --git a/lib/file/error.txt b/lib/file/error.txt
new file mode 100644
index 00000000..201ab8e9
--- /dev/null
+++ b/lib/file/error.txt
@@ -0,0 +1,67 @@
+65
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+What game do you think you are playing anyway?
+Aivan sairas kaveri kun tuollaista aikoo puuhata!
+Insufficient data for further analysis.
+Non sequitur. Your facts are uncoordinated.
+Type '?' or '\' for help.
+Invalid command.
+What?
+WHAT?!
+You must be out of your mind!
+You're killing me.
+Are you sure?
+Are you sure you know what you are doing?
+Aww, come on!
+That makes no sense.
+I beg your pardon.
+Degreelessness mode on.
+Degreelessness mode off.
+Syntax error.
+That doesn't compute.
+I don't understand you.
+???
+Sure. Piece of cake.
+Error.
+You can't do that!
+Help!
+Come again?
+Sorry?
+Sorry, I'm not sure I understand you.
+What's your point?
+Unknown command.
+Command not found.
+An unexpected error has occurred because an error of type 42 occurred.
+Somehow, you think that would never work.
+Welcome to level 42.
+Don't be ridiculous!
+lfae aierty agnxzcg?
+Soyha, azho bouate!
+I don't fully understand you.
+Why would anybody want to do THAT?
+Yes, yes, now tell me about your childhood.
+Satisfied?
+Something is wrong here.
+There's something wrong with YOU.
+You leap up 9' and perform a miraculous 5xSpiral in the air.
+Aw, shaddap!
+Shut up, smartass!
+I see little point in doing that.
+Oh, really?
+Very funny.
+You've got to be kidding!
+I'm not amused.
+I must have misheard you.
+Nothing happens.
+Where did you learn THAT command?
+When all else fails, read the instructions.
+Why not read the instructions first?
+Cut it out!
+Nothing interesting happens.
+Just how exactly am I supposed to do THAT?
+That's morally wrong and I won't do it.
+I'm not gonna take this abuse.
+AAAAAAAAAAAAAHHHHHHHHHHHHHHHRRRRRRRRRRRGGGGGGGGGGG!
+No more, if you value your character's life!
+Give it up, guy.
+Disk error. (a)bort, (r)etry, (f)ail?
diff --git a/lib/file/mondeath.txt b/lib/file/mondeath.txt
new file mode 100644
index 00000000..e78ca4e9
--- /dev/null
+++ b/lib/file/mondeath.txt
@@ -0,0 +1,334 @@
+332
+****** BUFFER LINE *********************************** DO NOT REMOVE *******
+'Live and let live, right..?'
+'AAAAAAAAARRRRRRRRRRRRRRRRGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHH!!!!!!!!!!!'
+'AAAARRRGGGHHH!!!'
+'Somehow, I have a bad feeling about this...'
+'Strangely, all of a sudden I don't feel so good.'
+'I can see armored women on winged horses coming for me.'
+'Oh well, you can't always win.'
+'I'm too young to die!'
+'I'll be back!'
+'O, untimely death!'
+'Slave, thou hast slain me!'
+'Ouch! That smarts!'
+'Who knocked?'
+'Did anybody get the number of that truck..?'
+'Ouch.'
+'Et tu, Brute! Then fall, Caesar!'
+'O! I die, Horatio...'
+'I told you to be careful with that sword...'
+'This guy's a little crazy...'
+'Ok, ok, I get it: No more pals.'
+'No more Mr. Nice Guy!'
+'Who turned off the light..?'
+'Join the army, see the world, they said...'
+'Mom told me there'd be days like this...'
+'Rats!'
+'Shall this fellow live?'
+'Help, ho!'
+'What ho! Help!'
+'What hast thou done?'
+'I'll be revenged on the whole pack of you!'
+'You will *pay* for this!'
+'They say blood will have blood...'
+'Violence is no solution!'
+'Yes?'
+'#&%#&#%*#*&%!!!!!'
+'F***!'
+'No time to make a testament?'
+'Ugh!'
+'Aargh!'
+'Aaagghhh!'
+'I'm melting!'
+'Oof..'
+'Oh!'
+'Did somebody knock?'
+'Later, dude...'
+'CU!'
+'What? Who? Me? Oh, s..t!'
+'...amen!'
+'Eeek!'
+'Aacch!'
+'I hate it when that happens.'
+'One direct hit can ruin your whole day.'
+'Oh no!'
+'Not me!'
+'Ouch.'
+'Oh no, not again.'
+'Another one bites the dust.'
+'Goodbye.'
+'Help me!'
+'Farewell, cruel world.'
+'Oh man!'
+'Doough!'
+'This is the End, my only friend.'
+'It's all over.'
+'The fat lady sang.'
+'Why does everything happen to me?'
+'I'm going down.'
+'Crapola.'
+'Pow!'
+'Bif!'
+'Bam!'
+'Zonk!'
+'I should've listened to my mother...'
+'No... a Bud light!'
+'What was that noise?'
+'Mama said there'd be days like this.'
+'It's just one of those days...'
+'I see a bright light...'
+'Mommy? Is that you?'
+'I let you hit me!'
+'Sucker shot!'
+'I didn't want to live anyway.'
+'-<sob>-'
+'Hah haa! Missed me! Ha---'
+'Was that as close as I think it was?'
+'The monsters rejoice: the hero has been defeated.'
+'It wasn't just a job it was an adventure!'
+'I didn't like violence anyway!'
+'I thought you liked me?'
+'Such senseless violence! I don't understand it.'
+'I think this guy's a little crazy.'
+'Somehow I don't feel like killing anymore.'
+'Help me! I am undone!'
+'Hey! Killin' ain't cool.'
+'This fell sergeant, Death, is strict in his arrest...'
+'The rest is silence.'
+'Guh!'
+'It's game over, man!'
+'Trust me, I know what I'm doing...'
+'Kill men i' the dark! What be these bloody thieves?'
+'Ho! Murder! Murder!'
+'O! I am spoil'd, undone by villains!'
+'O murderous slave! O villain!'
+'O, falsely, falsely murder'd!'
+'A guiltless death I die.'
+'AAAAAAAAAAAAAAAAAAAAAAAAHHHHHHH!'
+'Trust me.'
+'Dammit, this thing won't die!'
+'He hit me for HOW MUCH?????'
+'Look, behind you!!!'
+'Who fed steroids to that kobold?'
+'Don't worry, be happy!'
+'I don't believe this!'
+'Oops.'
+'Can't you take a joke?'
+'Well, I didn't much like this character, anyway...'
+'Oops, sorry... didn't mean to disturb you.'
+'I never get to have any fun!'
+'Stop!'
+'Cut it out!'
+'Don't worry. I've got a plan.'
+'It didn't look so tough.'
+'Run away!'
+'All clear, guys.'
+'AGAIN!?!?!'
+'I don't like this dungeon...'
+'Maybe this wasn't such a good idea.'
+'My God will protect me.'
+'You wouldn't dare!'
+'But what about my Parry Skill? Tumbling?'
+'Don't worry - I have Pilot-7.'
+'And I've *never* done you any harm.'
+'I don't understand. It should be dead by now.'
+'I'm heir to the crown. They wouldn't dare!'
+'Hey! Where's my stomach? My hands?'
+'Ha! That's the oldest trick in the book.'
+'Cover me.'
+'Watch this.'
+'And damn'd be him that first cries: Hold, enough!'
+'I will not yield.'
+'...but like a man he died.'
+'If you cut me down, I will only become more powerful.'
+'Well, at least I tried...?'
+'What could possibly have gone wrong?'
+'What's with that weirdo with the teeth?'
+'Surrender? Never!'
+'I'm sure reinforcements will get here on time. They promised.'
+'Funny, didn't *look* like a cyberpsycho....'
+'I have a very bad feeling about this.'
+'Do something, SCHMUCK!'
+'I feel I could cast Speak with Dead and talk to myself.'
+'Oh, that's just a light wound.'
+'Ach, is doch nur 'ne Fleischwunde...'
+'I thought you were on MY side...'
+'Next time, try talking!'
+'Oh shit... I'll try to teleport again.'
+'Somebody get me a Rod of Resurrection... QUICK!'
+'Uhh... oh-oh...'
+'Gee, where'd everybody go?'
+'I see it coming...aaargllhhhh! {sough}'
+'Ay! Ay! Ay!'
+'Ohe! Ohe! Ohe!'
+'Et tu, Caesar! Then fall, Brute!'
+'Even the best laid plans...'
+'Hey, not too rough!'
+'The Random Number Generator hates me!'
+'So when I die, the first thing I will see in heaven is a score list?'
+'Can't we talk this thing over?'
+'Wait! Spare me and I'll make you rich! Money is not a problem!'
+'I hate you!'
+'By the kind gods, 'twas most ignobly done!'
+'Mein Leben!'
+'Meine Lieder!'
+'I'm the hero of this story! I CAN'T die!'
+'Gee... thanks.'
+'I've fallen and I can't get up!'
+'911?'
+'Sure don't look good...'
+'Oh No! Here I blow again!'
+'I'll be back...'
+'Hey - I've got lawyers.'
+'Thanks, I needed that.'
+'I AM toast!!'
+'Scheisse!'
+'Oh, basely done! I had hoped for better of thee!'
+'I am death incarnate! NOTHING can harm me!'
+'And you thought Tristan was unlucky...'
+'Just wait till I get my hands on the crook who sold me this crappy armor...'
+'All is lost. Monks, monks, monks!'
+'All my possessions for a moment of time!'
+'Don't let poor Nelly starve!'
+'Wally, what is this? It is death, my boy: they have deceived me.'
+'Everyone dances with the Grim Reaper.'
+'Adios.'
+'I'm going home, babe.'
+'I am innocent, innocent, innocent!'
+'Watch where you're pointing with that sword! You nearly...'
+'Hmm, some things are better wanted than had...'
+'And they told me it was not loaded.'
+'Of course I know what I am doing.'
+'It looked harmless.'
+'Hilfe, hilfe, hilfe!'
+'Look, dad! No head!'
+'Look! I'm flying!'
+'Think I'm gonna fall for that?'
+'I'll be back... as soon as I can.'
+'3... 2... 1... Liftoff!'
+'My wallet? In your dreams!'
+'Yes! Yes! YES! YES! YY... AAARRRGGGHH!'
+'See you later, alligator!'
+'Up, up and awaaaayyy!'
+'Been nice knowing you.'
+'But I just got a little prick!'
+'And I just wanted that fancy suit of armour you were carrying...'
+'Hey guys, where are you?'
+'Hey look... ARCHERS!'
+'I can't probably miss...'
+'I don't care. I have a Scroll of Raise Dead.'
+'I don't care. I have a Ring of Regeneration.'
+'I have this dungeon at home, I know where everything is!'
+'This HAS to be an illusion. I attempt to disbelieve it.'
+'I thought you could be trusted.'
+'Never try to sneak in a plate mail.'
+'I'll never surrender.'
+'I'll use the Cheat Death option...'
+'I'm invincible!'
+'Hey, it was only a joke, all right?'
+'Hey, don't talk to me like that!'
+'I have rights, too!'
+'Just because you're big and ugly doesn't mean you can push ME around.'
+'Me first! Me first!'
+'Let me handle this.'
+'No problem. That's easy.'
+'Oh, shit.'
+'So what?'
+'Tell me this is an illusion... please!'
+'I hate the RNG...'
+'They need a twenty to hit me! I'm invincible!'
+'Trust me.'
+'CHARGE!'
+'What do you mean, how many hit points do I have?'
+'What do you mean, my GOI expired?'
+'Yeah, I knew it was dangerous, but I was thinking about the XP...'
+'You mean you get to use the critical hit chart too?'
+'You'd have to be a GOD to smile after that hit!'
+'Morons! I have morons on my payroll!'
+'Idiots! I am surrounded by incompetent idiots!'
+'I have such sweet thoughts'
+'I pray you all pray for me.'
+'Is not this dying with courage and true greatness?'
+'I must sleep now.'
+'Nurse, nurse, what murder! What blood! I have done wrong!'
+'That unworthy hand! That unworthy hand!'
+'I am dying.'
+'Oh, dear.'
+'I will not kneel. Strike!'
+'I have led a happy life.'
+'Dying, dying.'
+'I feel the flowers growing over me.'
+'Now it is come.'
+'Let me die to the sound of sweet music.'
+'I will now enter the Halls of Mandos.'
+'Ungrateful traitors!'
+'We perish, we disappear, but the march of time goes on forever.'
+'Youth, I forgive thee.'
+'Treason! Treason!'
+'Cowards! Why did you not protect me?'
+'I am absolutely undone.'
+'It is well. I die hard, but am not afraid to go.'
+'Do let me die in peace.'
+'Nothing is real but pain now.'
+'Violent use brings violent plans.'
+'Soldier boy, made of clay, now an empty shell.'
+'Bodies fill the fields I see, the slaughter never ends.'
+'Life planned out before my birth, nothing could I say.'
+'Blood will follow blood, dying time is here.'
+'Never happy endings on these dark sets.'
+'No one to play soldier now, no one to pretend.'
+'Time for lust, time for lie, time to kiss your life goodbye.'
+'Greetings, Death, I'm yours to take away.'
+'I was born for dying.'
+'The higher you walk, the farther you fall.'
+'Exit: light - enter: night!'
+'New blood joins this earth...'
+'You labeled me, I'll label you, so I dub thee unforgiven.'
+'If you're gonna die, die with your boots on!'
+'There's a time to live, and a time to die, when it's time to meet the maker.'
+'Isn't it strange, as soon as you're born you're dying?'
+'Only the good die young, all the evil seem to live forever.'
+'I don't wanna die, I'm a god, why can't I live on?'
+'And in my last hour, I'm a slave to the power of death.'
+'Now I am cold, but a ghost lives in my veins.'
+'You got to watch them - be quick or be dead.'
+'Heaven can wait till another day.'
+'You'll take my life but I'll take yours too.'
+'We won't live to fight another day.'
+'As I lay forgotten and alone, without fear I draw my parting groan.'
+'Somebody please tell me that I'm dreaming!'
+'Can't it be there's been some sort of error?'
+'Is it really the end not some crazy dream?'
+'Life down there is just a strange illusion.'
+'My life suffocates, planting seeds of hate.'
+'I split my brain, melt through the floor.'
+'My body tries to leave my soul.'
+'I'm so tired of living, I might as well end today.'
+'Life, life! Death, death! How curious it is!'
+'Catch my soul 'cos it's willing to fly away!'
+'Flames? Not yet, I think.'
+'Someone call the Gendarmes!'
+'And now the dreams end.'
+'I'm off to Never-Never Land!'
+'Death greets me warm, now I will just say goodbye.'
+'What is this? I've been stricken by fate!'
+'This can't be happening to me!'
+'Flash before my eyes: now it's time to die.'
+'You have been dying since the day you were born.'
+'No point asking who's to blame.'
+'But for all my power I couldn't foresee my own demise.'
+'My creator will lay my soul to rest.'
+'Was that worth dying for?'
+'Can you say you are proud of what you've done?'
+'But there are some things which cannot be excused.'
+'Why is it some of us are here just so that we'll die?'
+'The shortest straw, pulled for me.'
+'There's got to be just more to it that this or tell me why do we exist?'
+'I can't believe that really my time has come.'
+'Too much of a good thing, I guess...'
+'When the dream dies, the nightmare begins.'
+'You maggots make me sick. I'll be avenged. Lucifer dwells within all of us!'
+'I really screwed up this time.'
+'Wow, what a trip!'
+'I believe my kingdom will come'
diff --git a/lib/file/monfear.txt b/lib/file/monfear.txt
new file mode 100644
index 00000000..5bd2e91c
--- /dev/null
+++ b/lib/file/monfear.txt
@@ -0,0 +1,63 @@
+61
+*********** BUFFER LINE ********************** DO NOT REMOVE *****************
+says: 'I am too young to die.'
+says: 'Ok, ok! I get: no more pals.'
+screams: 'Help, ho!'
+screams: 'What ho! Help!'
+says: 'You will pay for this!'
+says: 'Violence is no solution!'
+says: 'I thought you liked me.'
+says: 'Such senseless violence! I don't understand it!'
+screams: 'Ho! Murder! Murder!'
+says: 'Look, behind you!'
+screams: 'Run away!'
+screams: 'Run to the hills! Run for your lives!'
+says: 'Wait! Spare me and I'll make you rich! Money isn't a problem!'
+says: 'I'll be back...'
+says: 'Hey -- I've got lawyers!'
+says: 'All my possession for a moment of time!'
+says: 'Hey, it was only a joke, all right?'
+says: 'Stop!'
+says: 'Cut it out, will you?'
+says: 'I will not kneel. Strike!'
+screams: 'Cowards! Why did you not protect me?'
+screams: 'Idiots! I am surrounded by incompetent idiots!'
+says: 'I don't wanna die, I'm a god, why can't I live on?'
+yells: 'Someone call the Gendarmes!'
+screams: 'Keep that lunatic away from me!'
+shouts: 'Drop that weapon, now!'
+says: 'Fool! You don't know what you're doing!'
+screams for help!
+begs for mercy.
+sobs.
+screams: 'Help! The maniac's murdering me!'
+says: 'Just what is it you want? Money? Babes? I can arrange it...'
+says: 'Wait! Let's make a deal!'
+says: 'Just can't stop this surmounting terror!'
+says: 'If there is a God, then why has he let me die?'
+says: 'I know where I'm going -- out!'
+says: 'No hope, no life, just pain and fear.'
+says: 'I am a fugitive, hunted down like game.'
+says: 'You'll live to regret this blasphemous offence!'
+says: 'All my life's blood is slowly draining away...'
+asks: 'Should we be fighting at all?'
+asks: 'What are we fighting for?'
+asks you: 'Can you say you are proud of what you've done?'
+says: 'Every minute I get weaker...'
+says: 'All my life I've run away...'
+says: 'All that I see, absolute horror!'
+says: 'I have fallen prey to failure.'
+says: 'Just leave me alone!'
+says: 'Please, save me!'
+says: 'You've won a battle, but I'll win the war!'
+says: 'You've won this round, next time it's *my* turn!'
+says: 'Another time, another battlefield, *my* victory.'
+says: 'I've got to keep running.'
+says: 'It's all so futile!'
+says: 'Cowards live to fight another day.'
+says: 'Life it seems will fade away, drifting further every day.'
+says: 'Emptiness is filling me, to the point of agony.'
+says: 'Cannot stand this hell I feel!'
+cries: 'Someone help me, oh please God help me!'
+cries: 'Please! I have a mate and six siblings!'
+cries: 'Mama, they try and break me!'
diff --git a/lib/file/monspeak.txt b/lib/file/monspeak.txt
new file mode 100644
index 00000000..5981f91c
--- /dev/null
+++ b/lib/file/monspeak.txt
@@ -0,0 +1,361 @@
+# This is the file for allowing uniques to speak their "own" lines.
+# Deleting this file will have no real effect on the game. Modifying it may
+# cause STRANGE unique lines to come up if the format's wrong, but shouldn't
+# crash anything. The format goes like so:
+#
+# N:45:whoever this is
+# 3
+# says bravado line 1
+# says bravado line 2
+# says bravado line 3
+# 2
+# says fear line 1
+# says fear line 2
+#
+# The number after the N: is the "monster index number" obtained from
+# r_info.txt. The text field after that number isn't actually used--it's
+# just there to help humans edit the file. The numbers on lines by
+# themselves say the number of "bravado" and "fear" lines. Getting these
+# numbers wrong won't crash anything, but will produce strange lines.
+#
+# Two or more monsters can share lines; just put their N: lines in a
+# contiguous block.
+#
+# To stop a certain monster from having unique lines, put a # in front of
+# its N: line.
+#
+# Have fun with this! --Matt G
+
+N:8:Farmer Maggot
+3
+says, 'I'm carrying CASH!'
+smirks, 'You wouldn't kill me, would you?'
+gleefully shows off a nifty object he just bought.
+2
+screams, 'Don't hurt a poor helpless hobbit!'
+yells, 'Where are my vicious dogs when I need them?'
+
+N:63:Smeagol
+27
+sniggers.
+grovels.
+picks his nose.
+pines for his precious.
+searches his pockets.
+eats some slimy creatures.
+mutters, 'My precious, wheres my precious?'
+shouts, 'No Master Hobbitsisisisis!'
+cries, 'The ring was ours for agesisisisis!'
+says, 'Smeagol sneeking! ME! Shneekingsisis!'
+screams, 'Nasty Hobbitsisisisis...'
+says, 'Come on, quickly, follow Smeagol'
+says, 'Every way is guarded, silly foolsis!'
+says, 'Nasty Bagginis, stole my precious.'
+says, 'She will kill them oh yes she will precious.'
+whines, 'Weees wants some fishises.'
+says, 'Whats has its got in its pocketses, hmmm?'
+whimpers, 'We've lost itses we have.'
+says, 'He'll eastus all the world if he getsitses it.'
+says, 'No food, no rest; Smeagol a SNEAK!'
+says, 'What a dainty little dish you will be for her.'
+says, 'Hobbitses always SOOOO Polite.'
+screams, 'Stop, Thief!'
+says, 'Makeses him drop his weapon precious.'
+grovels, 'He has only four fingers on the black hand.'
+growls, 'Not nice Hobbits, not sensible!'
+says, 'If you findesis it, give it us back.'
+3
+says, 'Don't hurt us, mastersisis.'
+says, 'Poor Smeagol, poor Smeagol.'
+says, 'No AH! Don't hurtsis us.'
+
+N:135:Mughash the Kobold Lord
+4
+says, 'I may be a kobold, but I can beat you!'
+says, 'Feel my wrath, fool!'
+says, 'Death and destruction make me happy!'
+snickers evilly.
+2
+screams, 'Cowards! Why did you abandon me?'
+begs for mercy.
+
+N:137:Wormtongue, Agent of Saruman
+6
+whines and sniggers.
+leafs through 'Cowards Monthly.'
+whispers nasty things.
+says, 'I'll slaughter you slowly...'
+giggles as he fingers his knife.
+says, 'Now, you shall taste my wrath!'
+3
+begs you to spare his miserable life.
+whines, 'This is not my fault!'
+screams, 'Help! Help!'
+
+N:138:Robin Hood, the Outlaw
+6
+eyes your money pouch covetously.
+says, 'You look like Nottingham's man to me!'
+says, 'I bet I can shoot better than you...'
+says, 'Give 'til it hurts!'
+says, 'Don't force me to put an arrow in your skull...'
+says, 'Kevin Costner has soiled my name!'
+3
+begs you to spare his life.
+says, 'But I'm a GOOD guy, really!'
+says, 'Money? Sure, take it all back!'
+
+#N:169:Brodda, the Easterling
+#N:291:Ulfast, Son of Ulfang
+
+N:180:Orfax, Son of Boldor
+N:237:Boldor, King of the Yeeks
+5
+wonders aloud about the quality of your weapon.
+spouts torrents of taunts.
+shouts, 'YEEK! YEEK! YEEK!'
+says, 'I'll teach you to respect yeeks!'
+says, 'Feel lucky, punk?'
+2
+sobs, 'I didn't MEAN it...'
+whimpers and moans.
+
+N:200:Hobbes the Tiger
+4
+says, 'Why were people put here? TIGER FOOD!'
+says, 'Yum! Adventurer sandwiches!'
+says, 'I ate Calvin, now I'll eat YOU!'
+says, 'I'll make your short life nasty and brutish!'
+1
+yells, 'Ow! Get me back to the comics!'
+
+N:140:Lagduf, the Snaga
+N:186:Grishnakh, the Hill Orc
+N:215:Golfimbul, the Hill Orc Chief
+N:260:Ufthak of Cirith Ungol
+N:314:Shagrat, the Orc Captain
+N:315:Gorbag, the Orc Captain
+N:330:Bolg, Son of Azog
+N:350:Ugluk, the Uruk
+N:356:Lugdush, the Uruk
+N:373:Azog, King of the Uruk-Hai
+19
+fingers his blade and grins evilly.
+snickers, 'Now, I strike a blow for *our* side!'
+says, 'Orcs don't get no respect... I'm gonna change that!'
+calls your mother nasty names.
+says, 'I'll bet your innards would taste real sweet...'
+belches and spits.
+scratches his armpits.
+says, 'I love the smell of fresh blood.'
+says, 'Yeeha! Another idiot to slaughter!'
+hawks a loogie in your direction.
+farts thunderously.
+wonders aloud how many experience points you're worth.
+says, 'I love being psychotic!'
+says, 'My brain's on fire with the feeling to kill!'
+says, 'I shall torture you slowly.'
+calls you a scum-sucking pig-dog.
+says, 'I shall break you!'
+says, 'You're not so tough, loser!'
+says, 'Heh-heh, heh-heh, killing people is cool.'
+6
+screams, 'Hey, orcs have rights too!'
+says, 'You're just prejudiced against orc-kind, aren't you?'
+begs, 'Spare me and I'll get you Ringil! Really!'
+says, 'Next time, I'm bringing more Uruks with me!'
+says, 'Don't hate me because I'm ugly!'
+whimpers and grovels.
+
+N:382:Mime, the Nibelung
+4
+says, 'Wagner misrepresented us!'
+says, 'I'll mess up all your stuff!'
+says, 'Give me the Rheingold, or die!'
+hums 'Ride of the Valkyries.'
+1
+screams, 'Help! Murder! Murder!'
+
+#N:392:Sangahyando of Umbar
+#N:380:Angamaite of Umbar
+
+#This next may be unnecessarily evil... :-]
+
+N:393:It
+6
+says, 'Nyah, nyah, betcha can't find me!'
+says, 'Come get some!'
+magically summons mighty undead opponents!
+chuckles evilly.
+magically summons Cyberdemons!
+summons special opponents!
+2
+howls, 'I'll be back!'
+whimpers, 'They said this invisibility thing was better than it is!'
+
+N:441:Barney the Dinosaur
+7
+says, 'Cooperation! That's the magic word!'
+mutters, 'I *hate* those Teletubbies...'
+says, 'Won't you be my friend?'
+says, 'Let's all sing a HAPPY SONG!'
+mugs for the camera.
+simpers disgustingly.
+chews up a 'Tinky Winky' doll.
+3
+begs, 'Don't! Think of the children!'
+screams, 'But I'm a big TV star!'
+sobs, 'All right! I apologise! I really really do!'
+
+N:505:Groo the Wanderer
+4
+says: 'A fray! A fray!'
+says: 'Groo does what Groo does best!'
+says: 'All right, you savage, mindless creature. Prepare to meet your equal!'
+says: 'I will slay you, and hack you, and waste you, and destroy you!'
+3
+says: 'Did I err?'
+says: 'I did not think Groo could be frightened...'
+says: 'I need no aid! Groo is beyond help!'
+
+N:934:Fangorn the Treebeard
+6
+says: 'The night stretches out on the Isengard!'
+says: 'Trolls are strong, Ents are STRONGER!'
+says: 'Saruman will now stop using his axes on the trees...'
+says: 'have you seen some Ent women ?'
+says: 'I will crush all those burarum ... those orcs!'
+says: 'I am totally of the side of nobody since nobody is totally of my side...'
+0
+
+N:732:Bull Gates
+10
+says, '640K should be enough for ANYBODY!'
+says, 'Buy Windows 2000; the filesystem rocks!'
+says, 'Linux? Never heard of it...'
+says, 'Resistance is futile--you will be assimilated.'
+says, 'NT is the solution for ALL your needs!'
+hacks out some code and calls it a Service Pack.
+says, 'We don't have a monopoly... Mac OS still exists!'
+wonders if he should buy a small country.
+says, 'Where will we let you go today? The Recycle Bin!'
+cackles diabolically.
+3
+sobs, 'OK, Linux doesn't suck. Let me live?'
+screams, 'Is megalomania THAT bad?'
+apologises for MS-DOS.
+
+N:733:Santa Claus
+8
+says, 'Ho ho ho! You're gonna die!'
+says, 'You're gettin' COAL in your stocking!'
+says, 'On Smasher, on Crasher, now dash away all!'
+chortles sadistically.
+says, 'You're on the Naughty List!'
+says, 'No presents for you, ever!'
+says, 'I'll sic my man-eating reindeer on you!'
+says, 'I hate Christmas so much that I've gone psychotic!'
+3
+sobs, 'Think of the children you'll disappoint!'
+sobs, 'No, Virginia, there isn't... not any more...'
+attempts to buy you off with offers of goodies.
+
+N:764:Uriel, Angel of Fire
+N:765:Azriel, Angel of Death
+N:769:Gabriel, the Messenger
+7
+says, 'Repent, evildoer!'
+says, 'My righteousness shall cleanse you!'
+says, 'Don't EVER steal from the collection plate!'
+says, 'God may love you, but *I* don't!'
+says, 'I shall smite thee with extreme prejudice!'
+says, 'Hope you like eternal damnation!'
+says, 'Verily, it is too late for thee.'
+3
+screams, 'Help! I am undone!'
+says, 'The Most High hath ordained this; I must follow.'
+screams, 'My God, my God, why hast thou forsaken me?'
+
+
+N:850:Carcharoth, the Jaws of Thirst
+N:846:Fenris Wolf
+N:840:Draugluin, Sire of All Werewolves
+8
+barks and bellows frighteningly!
+says, 'Oh good, another chew toy!'
+says, 'Yummy! I was getting tired of chicken...'
+lets out an earsplitting howl.
+drools all over the dungeon.
+lifts his leg at the nearest wall.
+says, 'Bad adventurer! No more living for you!'
+snarls and howls.
+3
+cringes and whimpers.
+says, 'Look, I promise I won't bite the mailman anymore!'
+says, 'Hey, put that rolled-up newspaper down!'
+
+N:830:Cantoras, the Skeletal Lord
+N:831:Mephistopheles, Lord of Hell
+N:818:The Mouth of Sauron
+N:819:Klingsor, Evil Master of Magic
+N:804:Vecna, the Emperor Lich
+N:844:Feagwath the Undead Sorceror
+N:856:Gothmog, the High Captain of Balrogs
+N:860:Sauron, the Sorcerer
+12
+brags, 'My power is beyond compare!'
+snorts, 'A mere mortal dares challenge my might? HA!'
+says, 'Not another one! I just finished chewing on the last!'
+wonders aloud how many XP you're worth.
+leafs through 'Evil Geniuses For Dummies'.
+mutters, 'Another darn loser to kill...'
+says, 'Angband shall claim your remains!'
+says, 'Another 12 skulls and I get that reward from the Boss!'
+yawns at your pathetic efforts to kill him.
+says, 'Minions, slaughter this fool!'
+says, 'Set thine house in order, for thou shalt die...'
+says, 'I'm no god... God has MERCY!'
+2
+screams, 'This CAN'T be happening!'
+shouts, 'Kill me if you want, the Boss will getcha!'
+
+N:928:Mathilde, the Science Student
+3
+waves.
+wishes you luck.
+skips along happily.
+1
+is surrounded by the purple aura of the RNG. Touch at your peril.
+
+N:861:Dark God, the Mighty Coder of Hell
+6
+says 'Hullo'.
+emits a low 'hmmmm'.
+screams 'I came from the Hells for YOU!'
+laughs out loudly.
+mutters something about bugs.
+asks you about the new version.
+1
+screams 'ToME rules!'.
+
+N:969:Princess
+4
+cries.
+screams 'Help me !!!'.
+whines 'I need your help, great hero...'.
+implores you to help her.
+1
+screams 'I am too young to die!'.
+
+N:970:Merton Proudfoot, the lost hobbit
+1
+whines 'Please help me, noble hero! My leg is broken, and I cannot walk.'
+1
+whines 'No, please don't hurt me!'
+
+N:1039:Improv, the mighty MoLD
+2
+screams 'Your code is ugly!'
+mutters something about bugs.
+1
+screams 'ToME rules!'.
diff --git a/lib/file/news.txt b/lib/file/news.txt
new file mode 100644
index 00000000..a6b5cc76
--- /dev/null
+++ b/lib/file/news.txt
@@ -0,0 +1,24 @@
+#G #W ~ ~~~ ~~~ ( #G
+#G ======/ ===== #W ~~ ) ~~ ) #G === === ===
+#G / // / __ \ #W )~ #r,.#W~ ( (#G // || \\ //
+#G // | | | | #W _#r,-"####`-^ #W ) #G || || || ||==:
+#G || | | | | #W ,#D###########r`W='#D###W`.#W () #G || || || ||
+#G \\_// \ -- / #W ,#D#######################D###W:#r,=. #G || || || \\===
+#G \_/ ===== #W /.#D###W,".#D#####W,".#D###########r"#W##\#G
+#W ,-. _,-= /"._ ,-. #w ," #W `:' `:#D#####W[JW] ,. #G
+#W," `," `=._ `" -#w; #G The #W\#D#####W;"' V \#W __,-. ,-=.
+#W / " `-. #w / #GTroubles of #W `" `-.#W__,-""._," "--," >-=-
+#W ,-"`. #w _' #G Middle Earth#w "._ #W` _/
+ _," #y __ #w "=.".
+ _," #y _,' `-. #w `._,=-._ _,-.
+ _._ ,"._," #y ,'_,'Y`-. `. #w "-." \,-.
+-" `-" #y / / ,' `. \ #w `-
+ #y / / / \ \ #w One Ring to rule them all,
+Maintained by darkgod #y f f f l l#w One Ring to find them.
+ #o darkgod@t-o-m-e.net #y t t t j j
+ #y \ \ \ / / #w One Ring to bring them all
+ #ohttp://www.t-o-m-e.net #y \ \ \._ / /#w and in the Darkness bind them.
+ #y `_`-._J-' /
+ #y `-.___,-'
+ In the Land of Mordor, where the Shadows lie. [J.R.R. Tolkien]
+.
diff --git a/lib/file/news2.txt b/lib/file/news2.txt
new file mode 100644
index 00000000..ea656899
--- /dev/null
+++ b/lib/file/news2.txt
@@ -0,0 +1,24 @@
+#G #W ~ ~~~ ~~~ ( #G
+#G ======/ ===== #W ~~ ) ~~ ) #G === === ===
+#G / // / __ \ #W )~ #r,.#W~ ( (#G // || \\ //
+#G // | | | | #W _#r,-"####`-^ #W ) #G || || || ||==:
+#G || | | | | #W ,#D###########r`W='#D###W`.#W () #G || || || ||
+#G \\_// \ -- / #W ,#D#######################D###W:#r,=. #G || || || \\===
+#G \_/ ===== #W /.#D###W,".#D#####W,".#D###########r"#W##\#G
+#W ,-. _,-= /"._ ,-. #w ," #W `:' `:#D#####W[JW] ,. #G
+#W," `," `=._ `" -#w; #G The #W\#D#####W;"' V \#W __,-. ,-=.
+#W / " `-. #w / #G Tales of #W `" `-.#W__,-""._," "--," >-=-
+#W ,-"`. #w _' #G Middle Earth#w "._ #W` _/
+ _," #y __ #w "=.".
+ _," #y _,' `-. #w `._,=-._ _,-.
+ _._ ,"._," #y ,'_,'Y`-. `. #w "-." \,-.
+-" `-" #y / / ,' `. \ #w `-
+ #y / / / \ \ #w One Ring to rule them all,
+Maintained by darkgod #y f f f l l#w One Ring to find them.
+ #o darkgod@t-o-m-e.net #y t t t j j
+ #y \ \ \ / / #w One Ring to bring them all
+ #ohttp://www.t-o-m-e.net #y \ \ \._ / /#w and in the Darkness bind them.
+ #y `_`-._J-' /
+ #y `-.___,-'
+ In the Land of Mordor, where the Shadows lie. [J.R.R. Tolkien]
+.
diff --git a/lib/file/rart_f.txt b/lib/file/rart_f.txt
new file mode 100644
index 00000000..3bebf94d
--- /dev/null
+++ b/lib/file/rart_f.txt
@@ -0,0 +1,86 @@
+85
+The Bag of Tricks
+Kenault's Cantrip Generator
+The Deck of Wild Magic
+Baalzebub's Tormented Box
+Baalzebub's All-seeing Servant
+Boccob's Unfinished Works
+The Gem of Fire
+The Gem of Ice
+The Gem of Venom
+The Gem of Knowledge
+The Gem of Rage
+The Gem of Hate
+The Gem of Wisdom
+The Gem of Ghosts
+The Shrunken Head of Nightmares
+Raal's Voodoo Doll of Revenge
+The Mirror of Alternate Dimensions
+The Ebon Cube of Darkness
+The Diamond Prism of Light
+Gruumsh's Bottle of Death
+The Devil's Pentagram
+Mordekainen's Sneaking Eye
+Kelek's Practical Joke
+Kelek's Wormhole Machine
+Tenser's Alteration Manual
+Raal's Tome of Unconventional Warfare
+The Tome of Collected Weird Magic
+The Pendulum of Orcus
+Raal's Black Candle
+Mordekainen's Pocket Magician
+Benetar's Death Ray Experiment
+Valdarbon's Automatic Alchemist
+Lloth's Ceremonial Dagger
+The Tome of Elven Household Magic
+a Parchment titled ``Demigods and their Uses''
+a Parchment titled ``Magic for the Layman''
+Balrilbon's Bag of Wondrous Tricks
+Bumganir's Bag of Magic Toys
+The Skull of Ancient Wisdom
+Benetar's Mana Battery
+Benetar's Portable Plague
+Gamenlon's Summoning Manual
+Balrilbon's Soulgem
+The Lost Works of Kenault
+The Crystal Ball of Godly Sights
+The Box of Many Wonders
+Baalzebub's Tormented Skullcap
+The Jester's Cap of Insanity
+The Bottomless Bottle
+a Parchment titled ``Planar Travel Made Easy''
+The Wand Construction Kit
+The Clay Tablets of Antiquity
+Raal's Tormented Spirits
+Tenser's Mechanical Magician
+Boccob's Magical Mish-mash
+The Grail of Kenault
+a Parchment titled ``Household Magic''
+a Parchment titled ``Tenser's Last Words''
+The Hand of Vecna
+The Skull of Vecna
+The Eye of Vecna
+The Crystal Ball of The Witch-King of Angmar
+a Parchment titled ``Secrets of the Gnomish Wizards''
+The Medallion of Good Will
+The Immortal Skull of Benetar
+Heward's Excellent Experimental Earmuffs
+Bigby's Big Book of Brutality
+The Cunning Plan of Zog
+a Parchment titled ''Immortality For Dummies''
+Raistlin's Ready Ranger
+Tenser's Torch of Spontaneous Combustion
+Mordenkainen's Mysterious Mind-Masher
+a Parchment titled ''Famous Last Words''
+Jor's Buckler of Missile Attraction
+Jor's Compendium of Strange Behaviour
+Agannazar's Antique Acorn
+Cathal's Corrupting Cymbal
+Pytar's Portable Pandemonium
+The Toenail of Vecna
+Jor's Book of Impossible Occurences
+a Parchment titled ''Finer Points of Munchkinism''
+Agannazar's Altruistic Assassin
+Tenser's Top-Heavy Teaspoon
+Olive's Omnipotent Ostrich
+Cathal's Collapsible Crutch
diff --git a/lib/file/rart_s.txt b/lib/file/rart_s.txt
new file mode 100644
index 00000000..88515a84
--- /dev/null
+++ b/lib/file/rart_s.txt
@@ -0,0 +1,87 @@
+85
+a Bag
+a Shiny, Black Box
+a Deck of Cards
+a Rusty, Slimy Box
+an Eyeball
+a Red Tome
+a Red Gem
+a Blue Gem
+a Green Gem
+a White Gem
+an Orange Gem
+a Black Gem
+a Gray Gem
+a Translucent Gem
+a Shrunken Head
+a Voodoo Doll
+a Mirror
+a Black Cube
+a Prism
+a Black Bottle
+a Pentagram
+a Glass Eyeball
+something weird
+a Portable Vortex
+a Green Tome
+a Black Tome
+a White Tome
+a Pendulum
+a Black Candle
+a Tiny Doll
+a Black Staff
+a Tiny Doll
+a Slimy Dagger
+a Gray Tome
+a Parchment
+a Parchment
+a Bag
+a Bag
+a Human Skull
+a Blue Box
+a Gray Bottle
+an Orange Tome
+a Shiny Gem
+an Ancient Gray Tome
+a Crystal Ball
+a Golden Box
+a Skullcap
+a Jester's Cap
+a Broken Bottle
+an Arcane Parchment
+many Small Wooden Sticks
+some Clay Tablets
+a Smoky Vial
+a Doll
+some Multi-colored Clay
+a Clay Jar
+an Arcane Parchment
+an Arcane Parchment
+a Decayed Hand
+a Decayed Skull
+a Decayed Eye
+a Large Crystal Ball
+an Arcane Parchment
+a Medallion
+a Jewel-Encrusted Skull
+some Earmuffs
+a Battered Book
+a Small Note
+a Parchment
+a Small Figurine
+a Torch
+a Rune
+a Singed Parchment
+a Holed Buckler
+a Red Book
+an Acorn
+a Cymbal
+a Mechanical Music-Box
+a Toenail
+a Torn Book
+a Greasy Parchment
+a Blackened Figurine
+a Heavy Teaspoon
+an Avian Figurine
+a Crutch
+
diff --git a/lib/file/readme! b/lib/file/readme!
new file mode 100644
index 00000000..90b6bbf2
--- /dev/null
+++ b/lib/file/readme!
@@ -0,0 +1,36 @@
+Most files in this directory are use by the get_rnd_line function for various
+purposes in the game. They can be edited and customised by the user with any
+ascii text editor. If you add / remove lines you should modify the index (the
+first line) accordingly. If you set an invalid index or remove the buffer line
+weird messages and other things can appear, and you can crash the game. Please
+see sample.txt before you try modifying the files.
+The a_*.txt and w_*.txt are used when the game generates a random artifact.
+However, instead of picking a name from the appropriate file, the game may
+form a new name from syllables[].
+
+The files in this directory:
+
+A_CURSED TXT Possible names for randomly generated cursed armour artifacts
+A_HIGH TXT Possible names for randomly generated 'powerful' armour artifacts
+A_LOW TXT Possible names for randomly generated 'weak' armour artifacts
+A_MED TXT Possible names for randomly generated 'medium' armour artifacts
+BRAVADO TXT Possible lines for speaking uniques
+CHAINSWD TXT Possible noise for the Chainsword
+CRIME TXT Possible crimes that speaking uniques may have committed
+DEAD TXT The tombstone picture (the death screen)
+DEATH TXT Possible 'last words' when the player dies
+ELVISH TXT Syllables for the names of random artifacts
+ERROR TXT Possible random error messages (instead of "Type ? for help")
+MONDEATH TXT Possible 'last words' for speaking uniques
+MONFEAR TXT Possible lines for scared speaking uniques
+NEWS TXT The game intro screen
+README! You are reading this file right now
+RUMORS TXT Possible rumours (for scrolls or rumour and shopkeepers)
+SAMPLE TXT A sample file for the random line selecting function
+SILLY TXT Silly monster names for hallucination
+SMEAGOL TXT Smeagol lines
+SMEAGOLR TXT Smeagol fleeing
+W_CURSED TXT Possible names for randomly generated cursed weapon artifacts
+W_HIGH TXT Possible names for randomly generated 'powerful' weapon artifacts
+W_LOW TXT Possible names for randomly generated 'weak' weapon artifacts
+W_MED TXT Possible names for randomly generated 'medium' weapon artifacts
diff --git a/lib/file/rumors.txt b/lib/file/rumors.txt
new file mode 100644
index 00000000..1928670b
--- /dev/null
+++ b/lib/file/rumors.txt
@@ -0,0 +1,201 @@
+199
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+They say that you can't trust rumors.
+You have no more Black Potions of Death.
+They say that smart guys hang around at 1600'.
+They say that tough guys hang around at 1500'.
+They say that handsome guys hang around at 1200'.
+They say that a visit to 3250' can be quite an experience.
+They say that a visit to 3250' will only get you killed.
+Throw a Potion of Blindness at a monster and it cannot cast any spells!
+MAKE MONEY FAST! Find a Treasure Pit!
+Not satisfied with the artifacts you find? Then create your own!
+They say that Sauron has forged an all-powerful Ring.
+A good item will not corrode.
+They say that Nibelungs live in dark caves.
+Some weapons that slay dragons can be very deadly against them...
+Finding the Phial of Galadriel at 50' is nothing to be proud of.
+There are Black Market stores hidden deep in the dungeon, with COOL stuff!
+What a pity, you cannot read it!
+You will encounter a dark, tall stranger...
+A Mithril mail will not rust.
+An Adamantite mail will not rust.
+A Rusty Chain Mail cannot rust any further.
+If you are a mage, you will NOT want to find Raal's Tome of Destruction!
+You won't want to find Raal's Tome of Destruction!
+You won't want to find Raal's Tome of Destruction, unless you are a mage.
+A Wand of Death is useless against monsters that are tougher than you.
+A Wand of Death is of little use against foes that are dead already.
+Try taking off your armor before fighting a Gelatinous Cube!
+They say that only one sword can score *CRITICAL* hits.
+This rumor is not true.
+If you can fall like a feather, you need not care about gravity.
+They say that you should rejoice if you find a scroll labeled ""!
+You don't always have to kill everything you meet!
+If you can't beat it, leave it alone!
+An umber hulk can be a confusing sight.
+There *is* a good use for Potions of Detonations, Ruination and Death...
+Watch your step!
+It's a bad idea to throw away a Longsword (4d5).
+It's a bad idea to wield a Longsword (4d5).
+It's useless to bash monsters with bows - but there's one notable exception...
+Actually, Slime Mold Juice is not completely useless.
+Help me! I'm being held captive in a Vault at 2850'!
+Ever tried inscribing your armor {erodeproof}?
+Using a Morningstar in the evening has no effect.
+Why are you wasting time reading fortunes?
+There is a horrible, ghastly fate awaiting you... at 2700'!
+You can get the Longsword 'Ringil' by doing the following:
+You can protect yourself from Great Wyrms of Power by doing the following:
+Its true name is 249.
+You feel like someone's pulling your leg!
+AAAAAAAAAAARRRRRRRRGGGGHHHHHHH!
+Try inscribing the name of the first monster killed by it in the weapon!
+The richer the victim the happier the thief.
+Beware the Jabberwock, my son! The jaws that bite, the claws that catch...
+There's something bad about what you are carrying in your backpack...
+Thieves are more likely to appear if you are carrying a lot of money.
+Brand's sword, Werewindle, probably knows more than just one trick.
+They say that Scrolls of *Curse Weapon* can create powerful cursed artifacts.
+They say that the Chainsword makes monsters mad with its awful noise!
+They say that Ringil shines so brightly that it makes monsters angry.
+Orcs are mortally afraid of weapons that can slay them.
+There is a way to turn a Ring of Speed (-20) into a Ring of Speed (+20).
+There is no way to turn a Ring of Speed (-20) into a Ring of Speed (+20).
+VECNA LIVES!!!
+Cool guys can resist fire.
+They say that death incarnate wears heavy metal boots...
+You feel the Longsword (t) you are carrying in your backpack is special...
+If you start seeing red monsters, you have probably gained infravision.
+They say that the dungeon is deeper than the Abyss.
+When all else fails, read the instructions.
+No poison is immediately deadly.
+I have seen a Ring of Speed (+50) in the Black Market!
+Telepathy works like a two-way door.
+Elvish waybread might negate the effects of poison.
+Once uncursed, Calris will become a deadly weapon.
+If there's a stairway to hell, there must also be a stairway to heaven.
+You feel your luck is turning...
+If you thought Death swords were bad, wait until you meet Killer katanas!
+Overeating can be bad for your health if there are others nearby.
+Cave dwellers are accustomed to darkness and rarely enjoy bright light.
+A creature made of stone can be slain by a spell that turns stone to mud.
+It is often a good idea to throw items that you don't want to eat or drink.
+The faster you run the more food you will burn.
+Invisible monsters will often expose themselves if you drop items around you.
+They say that the key to killing tougher monsters is called "hit&run".
+They say that there is no such thing as free advice.
+Wearing an Amulet of Doom will take you into the Dungeons of Doom.
+You can often wrest one last charge from an empty wand if you try hard enough.
+Wands may recharge themselves if you leave them on the floor long enough.
+There is more than one way to deal with a locked door.
+Afraid of your valuables getting stolen? Carry more junk!
+Afraid of your money getting stolen? Invest it!
+If you hear something smash into splinters, you had better watch out.
+They say that you had better leave Greater hell-beasts alone.
+Selling unidentified potions to shopkeepers might be safer than quaffing them.
+Always look out for trapdoors on "special" feeling levels!
+There is a way to max out your stats with Potions of Charisma & Nexus.
+Unique opponents will recover their health faster than other creatures.
+"So when I die, the first thing I will see in heaven is a score list?"
+You're going into the morgue at midnight?
+How dare you! I will not buy that!
+A Potion of Detonations is also known as nitroglycerin...
+Operation OVERKILL has started now.
+There is a trap on this level!
+A weapon of Undead Slaying has all you need to kill a ghost.
+A weapon of Dragon Slaying may give you resistance to a dragon's breath attack.
+They say that only a Warrior will want to wear the Terror Mask.
+All that is shall come to an end - a dark day dawns for the gods.
+The One Ring is powerful, but will eventually destroy its owner.
+Having troubles with summoners? Door Creation is your friend!
+Stairway Creation may be slower than Teleport Level, but safer...
+Wands of Heal Monster are useful! Hint: ball spell, @....moo(o)ooo
+Guaranteed heal self - scenario: o'@, type c4c4c4c4
+If it can't see you, it can't hurt you!
+If it can't see you, you might still be able to hurt it...
+I love you, you love me, we are a happy family!
+No animal is interested in sex if it is mortally scared.
+The butler did it.
+The butler is innocent.
+There is a plenty of Longswords around 1000'.
+Groo is your worst nightmare.
+Freddy Krueger is your worst nightmare.
+Groo is an idiot! Groo is a dolt! He is a fool! He has no mind!
+There are often stairways in graveyards: bad people are carried to hell...
+Only a god of Thunder could ride a lightning bolt!
+When the day of Ragnarok comes, Surtur will set the world afire...
+Surtur's accursed sword, Twilight, burns with everlasting fire.
+Groo may be as dumb as an amoeba, but he knows a good sword when he sees one.
+Weapons of Flame will light your way.
+Want to invest some money? Contact $crooge McDuck, 1300'.
+Need a loan? Contact $crooge McDuck, 1300'.
+They say that the gods get angry if you pray too much.
+For any remedy there is a misery.
+Poison will kill you slowly.
+Didn't you forget to pay?
+Death is just life's way of telling you you've been fired.
+They say that nobody can defeat his own ghost.
+A greedy genocide can be a fatal mistake, especially if you are low on hits.
+PLEASE ignore the previous rumor.
+There are scrolls that can be read only by mages.
+Some undead opponents will come back if defeated, more powerful than before!
+The answer is 42.
+Your mother wears army boots!
+One level further down somebody is getting killed, right now.
+Meet me at 1900' if you are a man.
+Bashing a creature may sometimes stun it.
+And now, Groo does what Groo does best!
+One Ring to rule them all, One Ring to find them.
+One Ring to bring them all and in the darkness bind them.
+Three Rings for the Elven-kings under the sky...
+Never carry a Potion of Detonations if there is a fire trap nearby!
+Laugh to scorn the power of man, for none of woman born shall harm thee!
+All hail thee that shalt be king hereafter!
+He who laughs at Groo's brains will find there is nothing to laugh about.
+A wise man always speaks too soon...
+Let us not dwell on possible bad fortunes!
+Appearance is only the frosting, not the cake!
+A feeling of Death flows through your body.
+Violence is no solution.
+Boots of Speed (+50) are no myth!
+You will need to Restore the Constitution if the Anarchists strike.
+Drain you of your sanity: Face the Thing That Should Not Be!
+Since by curse it came to me, accursed be this Ring!
+Each shall itch to possess the Ring, but none in it shall find pleasure!
+I know whatever was; whatever is, whatever shall be.
+Barney MUST die!!!
+Pudpadnoy Tooboothokoot is possessed by a demon known only as "It".
+They say that the One Ring has a very special curse.
+They say that alcohol is bad for your health.
+What if you DON'T give a name to the artifact you create..?
+They say that ancient battlefields are often haunted.
+Beware of pits that fill the whole level!
+Liar! I have not the gold!
+They say that the true name of wall monsters is 177.
+Never mind the Phial of Galadriel - the Phial of the Gods kicks its butt!
+A Ring of Speed? Phooey! Try looking for a Ring of *Speed*!
+Thisss cccity isss guilty... the crime isss life... the ssentence isss DEATH!
+If you hear heavy steps - watch out!
+A visit to the Zoo is educational: you meet many strange animals.
+What happens if you wear a Ring of Extra Ring Fingers (-2) {cursed}?
+Oremor nhoj em llik tsum uoy emag siht niw ot.
+If I cancel tomorrow the undead will thank me today.
+Hellfire will burn your soul...
+Call the Void needs a lot of room to cast...
+Why doesn't Detect Monsters show invisible monsters? 'Cos you can't see 'em!
+I'll tell you the truth, son: your soul's gonna burn in a lake of fire!
+There is a rare spellbook called [M$ PowerFools] {cursed}
+*** LOW HITPOINT WARNING! ***
+You cruelly stab the helpless, sleeping Software bug!
+Slab: Jus' say AarrghaarrghpleeassennononoUGH.
+You feel the Windows (95) on your hard disk is broken...
+Spirit, hatch that painted spirit of the lamb sparrow.
+Gone insane from the pain that sure they know: for who the flange sound?
+With time the child dissipates within, this blinking boy made badly.
+Not to be never, never not to see, so as to dub the thee unforgiven.
+Soon in order to fill up our lungs: the warmth of twenty dead women.
+The eternal death of eons of the foreigner of the lie can die not absolutely.
+Drain you of your sanity: in front do the thing that does not have to be.
+The opinion you had were salt expresses.
+They say that the dark mists of Morgoth can both bestow and remove the curse.
diff --git a/lib/file/sample.txt b/lib/file/sample.txt
new file mode 100644
index 00000000..5ff826f7
--- /dev/null
+++ b/lib/file/sample.txt
@@ -0,0 +1,5 @@
+3
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+line # 1
+line # 2
+line # 3
diff --git a/lib/file/sfail.txt b/lib/file/sfail.txt
new file mode 100644
index 00000000..ca4d9cb5
--- /dev/null
+++ b/lib/file/sfail.txt
@@ -0,0 +1,34 @@
+32
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+rose petals
+dirty straw
+rusty metal cutlery
+small, furry animals
+assorted toy jewelry
+visions of merry, dancing gnomes
+old and dusty accounting records
+moldy crusts of bread
+grass
+wet mud
+smelly bilge water
+clean linens
+scrap metal
+rotting wood
+leaves
+small insects
+rainwater
+flowers
+perfumed water
+overcooked sausage
+twigs
+pine needles
+hard leather
+small bones
+feathers
+crumbling manuscripts
+fresh air
+stale, smelly air
+dust
+clay
+earth
+wood shavings
diff --git a/lib/file/silly.txt b/lib/file/silly.txt
new file mode 100644
index 00000000..9d46c8b8
--- /dev/null
+++ b/lib/file/silly.txt
@@ -0,0 +1,301 @@
+299
+******************BUFFER LINE -- DO NOT REMOVE!*****************************
+Borg
+Dalek
+Destructor
+Predator
+Wizard of Yendor
+Smurf
+Cosmic Horror
+Ultimate Unspeakable Lovecraftian Nightmare
+Space Invader
+Transformer
+Master of the Universe
+He-Man
+Pizza Worm
+Bogeyman
+Care Bear
+My Little Pony
+IRA Terrorist
+Nazi
+Klingon
+Cardassian
+Snark
+Luggage
+Killer penguin
+Were-penguin
+Giant were-penguin
+Peeping-Tom
+Jester
+Battlemech
+Invid
+Amazon
+Teenage Mutant Ninja Turtle
+Stork
+Hippo
+Roadrunner
+Fooglebird
+Ghoti
+Whale
+Apocalyptic Beast
+Anti-Christ
+Dark Avenger
+Evil Computer
+Finnish Sprayer
+Natas
+Poodle
+Fire Hydrant
+Multi-hued elephant
+Martian
+Purple alligator
+Space ship
+Miniature space fleet
+6-feet tall elephant
+Insurance salesman
+Benji
+Magnet
+Squid
+Typewriter
+Manitou
+Miniature Shetland pony
+Munchkin
+Mad Scientist
+Keystone Kop
+Magnificent big-game hunter
+Wicked witch
+B-1 Bomber
+Superman
+Batman
+Boy Wonder
+Incredible Hulk
+Amazing Spider-Man
+Orphan
+Fifth columnist
+Secret agent
+Spy
+Dog catcher
+Vacuum cleaner
+Lawnmower Man
+Bloodletter of Khorne
+Buzzard
+Oyster
+Wombat
+Midget elephant
+Chameleon
+Dungeon Master
+Dungeon Keeper
+Beyonder
+Robocop
+Robocod
+Paradroid
+Dominatrix
+Paranoid
+Wagtail
+Great tit
+Pope
+Tribble
+Jedi knight
+Dark Jedi
+Master of Teras Kasi
+Vulcan
+Rancor
+Sarlacc
+Warbot
+Tailgunner
+Skinhead
+Paul Bunyan Machine
+Bungee
+Sumo wrestler
+Gargantuan sumo wrestler
+Karateka
+President
+King
+Lobo
+Trashman
+Teacher
+Cheshire Cat
+Mad Hatter
+March Hare
+Voodoo doll
+Rag doll
+Scarecrow
+Porcupine
+Stone idol
+Hacker
+Samurai
+Samurai Cat
+Phantom of the Opera
+X-man
+Wumpus
+Walrus
+Silver Surfer
+Chimpanzee
+Omnipotent being
+Reaperbot
+G. I. Joe
+Cobra Commander
+Dreadnok
+Autobot
+Battlemage
+Saboteur
+Master of Sinanju
+Cyborg
+Lemming
+Green Goblin
+Galactus
+Gooey Kablooie
+Prowler
+Iron Fist
+Stuka
+Mahdi
+Xeroc
+Catwoman
+Stupendous Man
+Lost boy
+Hunter-killer
+Mad butcher
+Vore
+Rotfish
+Heresiarch
+False prophet
+Emperor
+Tumtum
+Androgyne
+Thieving magpie
+Boast of England
+Red Rose Knight
+Unholy cow
+Q
+Red Baron
+Giddy goon
+Vogon
+Lizard King
+Hutt
+Puppet master
+Wookie
+Giant sandworm
+Muad' Dib
+Ent
+Huorn
+Werepotato
+Mindless one
+Alien queen
+Alligator man
+Ancient ape
+Ancient astronaut
+Astro-zombie
+Beast from 20000 fathoms
+Beast with a million eyes
+Black goat of the woods with a thousand young
+Behemoth
+Leviathan
+Big Bug
+Blob
+Khyberdemon
+Body snatcher
+Brain from Planet Ardus
+Scatologist
+Brain of Venus
+Brain that would not die
+Breath blaster
+Chickenstein's monster
+Creature from the Black Lagoon
+Loch Ness monster
+Creeping death
+Creeping unknown
+Fifty-foot woman
+Flumsh
+4D-man
+Bride of Frankenstein
+Galaxy being
+Giant baby
+Giant chicken
+Krazy Kat
+Giant celery stalk
+Gorilla witch
+Great god Porno
+H-dial monster
+Heap
+Love lotus
+Herman munster
+Highest intelligence
+H-man
+Hound of the Baskervilles
+Wizball
+ID monster
+Mancubus
+Arch-vile
+Pain elemental
+I-ball
+Killdozer
+Killer tomato
+Lurking fear
+Madball
+M.U.L.E.
+Magnetic monster
+Mixed-up zombie
+Hunchback of Notre Dame
+Monster that challenged the World
+Monster from green hell
+Morlock
+Queen Kong
+Robot Kong
+Mecha-Godzilla
+Ghidhrah
+Saucerman
+Ethereal
+Space Brain
+Floating brain of Hitler
+Stay Puft Marshmallow Man
+Supercow
+Swamp Thing
+Thing
+Teenage Frankenstein
+Teenage Werewolf
+Terror from the year 5000
+Triffid
+Tripod
+Xenophobic man
+Undying monster
+Unknown terror
+Unnamable
+Womaneater
+E.T.
+Toxic Avenger
+Onslaught
+Pacman
+Paradroid
+Bantha
+Ass-headed fish
+Wizard of Oz
+Juggernaut
+Cheshire Cat
+Tauntaun
+Heretic
+Other
+Uncanny
+Libido
+Super-ego
+Boy Blunder
+Big nothing
+Parademon
+Zelda
+Super Mario
+Great Giana Sister
+Magnetic man
+Pink elephant
+Elephant man
+Great Unknown
+Lurking unknown
+Cenobite
+Cheerleader
+Model T-1000 Terminator
+Whippoorwill
+Moon Maniac
+Killer Clown
+Stocking Strangler
+Torture Doctor
+Beast of the Black Forest
+Demon of the Belfry
+Sex Beast
+Sunday Morning Slasher
diff --git a/lib/file/smeagol.txt b/lib/file/smeagol.txt
new file mode 100644
index 00000000..53b1955a
--- /dev/null
+++ b/lib/file/smeagol.txt
@@ -0,0 +1,29 @@
+27
+******** BUFFER LINE *******************
+sniggers.
+grovels.
+picks his nose.
+pines for his precious.
+searches his pockets.
+eats some slimy creatures.
+mutters: 'My precious, wheres my precious?'
+shouts: 'No Master Hobbitsisisisis!'
+cries: 'The ring was ours for agesisisisis!'
+says: 'Smeagol sneeking! ME! Shneekingsisis!'
+screams: 'Nasty Hobbitsisisisis...'
+says: 'Come on, quickly, follow Smeagol'
+says: 'Every way is guarded, silly foolsis!'
+says: 'Nasty Bagginis, stole my precious.'
+says: 'She will kill them oh yes she will precious.'
+whines: 'Weees wants some fishises.'
+says: 'Whats has its got in its pocketses, hmmm?'
+whimpers: 'We've lost itses we have.'
+says: 'He'll eastus all the world if he getsitses it.'
+says: 'No food, no rest; Smeagol a SNEAK!'
+says: 'What a dainty little dish you will be for her.'
+says: 'Hobbitses always SOOOO Polite.'
+screams: 'Stop, Thief!'
+says: 'Makeses him drop his weapon precious.'
+grovels: 'He has only four fingers on the black hand.'
+growls: 'Not nice Hobbits, not sensible!'
+says: 'If you findesis it, give it us back.'
diff --git a/lib/file/smeagolr.txt b/lib/file/smeagolr.txt
new file mode 100644
index 00000000..cc13c96f
--- /dev/null
+++ b/lib/file/smeagolr.txt
@@ -0,0 +1,5 @@
+3
+******** BUFFER LINE **************
+says: 'Don't hurt us, mastersisis.'
+says: 'Poor Smeagol, poor Smeagol.'
+says: 'No AH! Don't hurtsis us.'
diff --git a/lib/file/speakpet.txt b/lib/file/speakpet.txt
new file mode 100644
index 00000000..d369fe8a
--- /dev/null
+++ b/lib/file/speakpet.txt
@@ -0,0 +1,53 @@
+51
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+says: 'Oi, loan me 2 quid for a drink or I'll knock your head off!'
+says: 'Nice boots, mate.'
+says: 'Wow, isn't it dark down here?'
+says: 'I think I saw something move..'
+says: 'I really think I saw something move this time..'
+says: 'Phew, what's that smell?'
+says: 'There's slime all over the walls..'
+says: 'Isn't it dark down here?'
+says: 'Dungeon explorers should be *friends*, right?'
+says: 'I luv you, you luv me..'
+says: 'Are we there yet?'
+says: 'I'm hungry, look for a McMorgoth's..'
+says: 'Is there a 'Monster WC' vault on this level?'
+says: 'Not sure of max line length, but...'
+says: 'Excuse me, but do you know the way to vanilla?'
+says: 'I heard that the orcs just voted in a union'
+says: 'You gonna finish that?'
+says: 'You're gonna eat *that*?'
+says: 'Oops. I've got slime mold on my boot/claw/wisp of vapor.'
+says: 'It's a fantastic space. Knock in a skylight to open it up...'
+says: 'I love troll. Eat once, stay full for a week.'
+says: 'Your sword sure is shiny.'
+says: 'Hey! WATCH IT! You almost hit me.'
+says: 'So, you gonna do some abracadabra?'
+says: 'Keep that demon blade away from me.'
+says: 'Do the one where the ceiling collapses!'
+says: 'That oak tree ain't bad looking. Think it has a sister?'
+says: 'The One Ring. That sure is a silly name...'
+says: 'Groo and Stormbringer entered a bar...'
+says: 'If Lokkak asks, I'm not here.'
+says: 'buurrrrppp'
+says: 'Kill, kill, kill. Let's play chess.'
+says: 'Swordmanship: 8.4, Style: 9.0'
+says: 'When *I* was young, it was up stairs BOTH WAYS.'
+says: 'Lohengrin, schmohengrin.'
+says: 'Very fancy. Bet you can't do it again.'
+says: '10AU says I can behead that snaga!'
+says: 'I bet the chicks dig those boots.'
+says: 'Have you seen those Teletubbie uniques?'
+says: 'Were you looking for these?'
+says: 'Let's blitz 'em!'
+says: 'You da bomb!'
+says: 'Medusa: now, SHE is ugly.'
+says: 'Do you *really* like me?'
+says: 'ToME just switched to an HMO.'
+says: 'Do you like my outfit?'
+says: 'So, you're an auto-roller baby...'
+says: 'Where'd you put the snaga call?'
+says: 'I've split my reed. Bummer.'
+says: 'A wand of rockets. Yeah, that's the ticket.'
+says: 'It's Zymurgist's Time!'
diff --git a/lib/file/timefun.txt b/lib/file/timefun.txt
new file mode 100644
index 00000000..ca3f642f
--- /dev/null
+++ b/lib/file/timefun.txt
@@ -0,0 +1,92 @@
+S:0000
+E:0059
+D:It's the witching hour!
+
+S:0100
+E:0259
+D:There may be Vampires around!
+
+S:0200
+E:0459
+D:Only ToME players are up now!
+
+S:0100
+E:0459
+D:It's really *very* late!
+
+S:0500
+E:0558
+D:Aren't you sleepy yet?
+
+S:0559
+E:0559
+D:It doesn't matter what you found!
+
+S:0600
+E:0759
+D:The sun is up. Time to have fun!
+
+S:0601
+E:0800
+D:Are you having fun yet?
+
+S:0800
+E:0905
+D:@$#$@$!%@$#%$@&$^#%@$!^#&#*
+
+S:0800
+E:1059
+D:You feel there is something special about this level.
+
+S:1100
+E:1159
+D:You see a maze of twisty passages, all alike.
+
+S:1155
+E:1200
+D:Are you having fun yet?
+
+S:1159
+E:1200
+D:This fortune is broken!
+
+S:1200
+E:1205
+D:This fortune is still broken!
+
+S:1200
+E:1359
+D:Uh oh, now you've done it!
+
+S:1400
+E:1729
+D:What did you do with the Phial?
+
+S:1730
+E:1744
+D:You need your chocolate vitamin!
+
+S:1745
+E:1759
+D:Tornado Warning!
+
+S:1759
+E:1800
+D:Night is coming. Danger! Danger!
+
+S:1700
+E:1859
+D:Take a Vampire out for dinner!
+
+S:2100
+E:2159
+D:Warp Factor Nine. Now!
+
+S:2200
+E:2359
+D:PARTY!
+
+S:2359
+E:2359
+D:It's almost the witching hour!
+
diff --git a/lib/file/timenorm.txt b/lib/file/timenorm.txt
new file mode 100644
index 00000000..611da496
--- /dev/null
+++ b/lib/file/timenorm.txt
@@ -0,0 +1,83 @@
+S:0000
+E:0000
+D:It is midnight.
+
+S:0001
+E:0200
+D:It is deep night.
+
+S:0300
+E:0400
+D:It is early morning, but still dark.
+
+S:0500
+E:0544
+D:It will be day soon.
+
+S:0545
+E:0559
+D:The sun is rising.
+
+S:0600
+E:0614
+D:The sun has risen.
+
+S:0615
+E:0659
+D:Morning has broken.
+
+S:0700
+E:0859
+D:It is early morning.
+
+S:0900
+E:0959
+D:It is midmorning.
+
+S:1000
+E:1154
+D:It is late morning.
+
+S:1155
+E:1159
+D:It is almost noon.
+
+S:1200
+E:1200
+D:It is noon.
+
+S:1201
+E:1459
+D:It is early afternoon.
+
+S:1500
+E:1559
+D:It is midafternoon.
+
+S:1600
+E:1659
+D:It is late afternoon.
+
+S:1700
+E:1729
+D:It will be night soon.
+
+S:1730
+E:1759
+D:The sun is setting.
+
+S:1800
+E:1859
+D:The night has begun.
+
+S:1900
+E:2059
+D:It is early night.
+
+S:2100
+E:2358
+D:It is late night.
+
+S:2359
+E:2358
+D:It is almost midnight.
diff --git a/lib/help/TANG.txt b/lib/help/TANG.txt
new file mode 100644
index 00000000..ffbb5701
--- /dev/null
+++ b/lib/help/TANG.txt
@@ -0,0 +1,134 @@
+|||||oy
+~~~~~01|Help|Newbie help
+#####R The ToME Newbie Guide
+by Pat Gunn and others
+Based loosely off of Chris Weisieger's Angband Newbie Guide.
+
+ Welcome to ToME, a popular descendant of Moria/Angband.
+ToME has many unique features that set it apart from other
+Angband/Moria descendants, with a nice mix of races/classes available.
+This guide will walk you, a player of ToME, through your first
+game (or two), introducing you to basic features that will help your
+character survive.
+
+ After you start the game for the first time, you will be
+prompted to create a new character. For this guide, we will start
+out with simple, easy to play characters. Go through the prompts,
+and select one of the following class/race combinations that will
+make for a simple first character:
+
+ Wood Elf (Classical) Archer
+ Half-Troll (Zombie) Unbeliever
+ Half-Ogre (Barbarian) Warrior
+
+After class/race selection, you will roll your statistics. Roll a few times
+until you get decent strength, constitution, and dexterity scores (the higher
+the better). After naming your character, you will appear in the
+town.
+
+ The town is a (relatively) safe place for you to buy/sell equipment,
+start quests, drop off items for storage, and various other things. Each store
+is represented by a symbol (either a number or a '+') on the side of a
+*****bldg.txt*0[building]. To enter a store, move over that symbol. You can also 'l'ook
+around to see the identity of stores and other inhabitants of the town. At
+this level, be wary of merchants and mercenaries -- they can probably kill you
+with little difficulty.
+
+ You will want to 'w'ield the weapons/armour you have started with
+(if you chose the archer, wield the bow, and then wield the arrows). You
+can check to see what you're wearing/wielding at any time by pressing
+'e'. Ideally, throughout the game you'll always have some kind of missile
+weapon and a decent melee weapon. Initially, purchasing a short bow and
+some plain arrows might be wise (archers start with a bow and some arrows,
+but you'll probably want to buy more ammo). Choice of a melee weapon is
+much more complex, but for now, unless you start with a good melee weapon
+(unbelievers do), you might want to consider buying a whip from the
+weapon store '3' (or the temple '4'). If available, purchase a lantern
+and 2 or 3 flasks of oil from the general store '1'. If you have some
+money left, buy some of the cheaper armour pieces from the armoury '2',
+such as boots, gloves, cap, and the like. You should now be ready to
+do some adventuring.
+
+ Just west of Bree are some steps into the first dungeon. Move on top
+of these stairs and hit '>' to go down. You will notice that when you arrive
+in the dungeon, you will be on top of some stairs going back up, and in the
+lower right, you will see how deep in the dungeon you are. When you need to
+return to town, head upstairs from the top level of the dungeon (which you are
+in now). Other stairs down will take you deeper in the dungeon. For now, stay
+on the first level of the dungeon, and fight some monsters to gain some
+experience. Be careful only to fight one monster at a time -- avoid fighting
+in open rooms when monsters can gang up on you. Also, avoid floating eyes
+'e', and 'l'ook at monsters before getting involved in combat with them.
+The 'C' button will bring up a screen telling you how many experience points
+you need to go to next level, and 'l'ooking at monsters will tell you how
+many experience points they are worth.
+
+ Once you go up a level, you'll want to invest some skill points so
+that your character improves. See the *****skills.txt*0[skills] help file for details.
+
+ Grab treasure, and when you are carrying close to as much as you can
+carry, head back to Bree and sell your loot. Buy phase door scrolls, teleport
+scrolls, and potions that will cure your wounds. Use any remaining money to
+buy identify scrolls. After a few trips, and reaching experience level 3, try
+going deeper in the dungeon before coming up.
+
+ Before you start going past the 8th or 9th level down, you will
+want some means of detecting traps, as traps begin to be a problem around
+that depth. Eventually, you'll want a rod of trap location (unless you are
+an unbeliever), but scrolls or staves will do until you find a rod and a
+rod tip of the right kind. These items, when used, will display all traps
+in a radius around you. This means that you'll want to use them again
+every time you run to the edge of that radius and into an area where you
+haven't yet detected traps.
+
+ Some kinds of items grant useful resistances or powers. You can
+see your current resistances and other stats by hitting 'C' and scrolling
+through the screens that come up. If you come across a Thunderlord coat
+early in the game, they make a good choice, as they grant resistance to
+fire and cold. Resistances reduce the damage attacks of certain kinds do,
+and often reduce the effectiveness of side-effects they have.
+
+ As you progress deeper in the dungeon, you will want to start using
+scrolls of recall to move to and from the dungeon. These scrolls, when
+read, schedule your return either to the surface or to the dungeon level
+you were last exploring. They do, however, take several turns to take effect,
+so reading them in an emergency will do little good.
+
+ Eventually, once you are around level 13 or 14, you will be ready
+to make trips to some of the other towns. The easiest town to get to is
+northeast of Bree; the others are more difficult to find and reach. When
+planning a trip, be sure to carry lots of food and/or scrolls of
+satisfy hunger. Multiple light sources may also be wise, and a bow is
+almost essential. To make long trips easier, ToME has a map mode
+specifically designed for travel. To use it, hit '<' in the wilderness.
+This will change the scale of the map, and make time go by at a much
+faster rate per square of movement (each square being many normal grid
+squares). Be sure to de-equip any exhaustible light sources before
+the trip, and never allow yourself to get past hungry while in this mode --
+drop down to the normal mode (with '>') if you get a message that you are
+hungry. Eventually, you will also make surface trips to find new dungeons
+to visit.
+
+#####REquipment notation:
+#####GA Weapon (3d4) (+3,+7)
+ This weapon, when you attack an enemy, does base damage calculated
+ by rolling a 4-sided die 3 times (adding the results up). It gets a
+ +3 to hit, and +7 to damage. If the weapon is light enough and
+ you are strong/dextrous enough, you can attack with it multiple times,
+ getting the base and extra damage once for each attack.
+
+#####GA Shield [5,+4]
+ This is a piece of armour, with a base defence of 5 and a magical
+ bonus of +4. If you wear it, your armour rating will increase by 9.
+
+#####GA Weapon (Defender) (1d6) (+12,+5) [+6] (+2 to stealth)
+ This is a special type of weapon, with special powers. The powers
+ depend on the type (there are more types than just Defender),
+ and some types can grant a variety of different powers. To get the
+ full info on this kind of weapon, you can either 'x'amine it if it's
+ being sold in a store, use certain kinds of magic (*Id*), or use
+ the (very expensive) services of certain stores.
+
+Many armours also have special powers.
+Some very powerful items are unique, and are called artifacts. They are
+normally indestructible, and will prove very useful in your quest.
diff --git a/lib/help/ability.txt b/lib/help/ability.txt
new file mode 100644
index 00000000..175d6745
--- /dev/null
+++ b/lib/help/ability.txt
@@ -0,0 +1,115 @@
+|||||oy
+~~~~~01|Abilities
+#####R=== ToME Abilities ===
+As well as spending your skill points on *****skills.txt*0[skills], you can also choose
+to spend them on abilities.
+Abilities are bought once, and then have a permanent effect. You cannot
+continue adding skill points into them, (which you can with *****skills.txt*0[skills]) as there
+would be no way that these abilities can improve. They are a "one-off
+purchase".
+As a consequence of this, they are often quite powerful abilities and can
+cost quite a few skill points to buy.
+Most abilities have a prerequisite skill or stat level which you must reach
+before being able to buy.
+
+For instance, you can invest in the *****ability.txt*03[Tree walking] ability. This will allow
+you to pass through dense undergrowth. In order to purchase this skill you must
+first have your *****skills.txt*34[Nature] skill at 20 or greater, and then it will cost you 7
+skill points to buy. This means you have to "save up" enough skill points in
+order to be able to afford this ability.
+
+You can access the Ability screen by pressing 'N' (in the original keyset, or
+'\N' in the roguelike keyset). Scroll up and down the abilities and then
+navigate right to buy selected ability.
+
+Adapt your character with skills and abilities in order to make it unique,
+playable, and maybe even powerful enough to win the game!
+
+Here follows a list of all the available abilities:
+
+*****ability.txt*02[Spread blows] *****ability.txt*03[Tree walking]
+*****ability.txt*04[Perfect casting] *****ability.txt*05[Extra Max Blow(1)]
+*****ability.txt*06[Extra Max Blow(2)] *****ability.txt*07[Ammo creation]
+*****ability.txt*08[Touch of death] *****ability.txt*09[Artifact Creation]
+*****ability.txt*10[Far reaching attack] *****ability.txt*11[Trapping]
+*****ability.txt*12[Undead Form]
+
+~~~~~02|Abilities|Spread blows
+[[[[[BSpread blows]
+If a monster dies to your attack but you still have blows left
+you won't lose the full turn, allowing you to attack some other
+monster in the same turn.
+#####UPrereq: Weaponmastery skill@30, Dex@17
+#####rCost: 5
+Warriors (of all types) gain this ability for free at character level 25.
+~~~~~03|Abilities|Tree walking
+[[[[[BTree walking]
+Allows you to walk in dense forest.
+#####UPrereq: Nature skill@20
+#####rCost: 7
+Ents and Wood Elves are born with this ability.
+~~~~~04|Abilities|Perfect casting
+[[[[[BPerfect casting]
+Allows you to reach 0% failure rate on spells.
+#####UPrereq: Magic skill@35
+#####rCost: 6
+Priests and Mages (of all types) are born with this ability.
+~~~~~05|Abilities|Extra Max Blow 1
+[[[[[BExtra Max Blow(1)]
+Increases your max possible blows number by 1.
+#####UPrereq: Combat skill@10
+#####rCost: 7
+Warriors (of all types) and Paladins are born with this ability.
+Rogues (of all types) gain this ability for free at character level 10.
+~~~~~06|Abilities|Extra Max Blow 2
+[[[[[BExtra Max Blow(2)]
+Increases your max possible blows number by 1 (Cumulative with
+Extra Max Blow(1)).
+#####UPrereq: Combat skill@20, Extra Max Blow(1)
+#####rCost: 7
+Warriors (of all types) are born with this ability.
+~~~~~07|Abilities|Ammo creation
+[[[[[BAmmo creation]
+Allows you to create shots, arrows and bolts from various materials.
+You can always make shots.
+At Archery level 10 you can start making arrows.
+At Archery level 20 you can start making bolts.
+#####UPrereq: Archery skill@10
+#####rCost: 8
+Archers (of all types) gain this ability for free at character level 2.
+~~~~~08|Abilities|Touch of death
+[[[[[BTouch of death]
+Your melee blows can insta-kill, but you only receive 1/3 of the experience
+for that kill.
+You must activate this from your 'm' menu.
+#####UPrereq: Necromancy skill@50, Combat skill@40, DEX@30, STR@30
+#####rCost: 15
+~~~~~09|Abilities|Artifact Creation
+[[[[[BArtifact Creation]
+In combination with a high alchemy skill this ability will let you
+design your very own artifacts.
+Prereq: Alchemy@40, INT@35, WIS@35
+#####rCost: 70
+~~~~~10|Abilities|Far reaching attack
+[[[[[BFar reaching attack]
+You can attack an enemy one square far using a long polearm.
+At high levels of Polearm-mastery skill, you can even hit two enemies at once.
+#####UPrereq: Combat@15, Polearm-mastery@15
+#####rCost: 10
+~~~~~11|Abilities|Trapping
+[[[[[BTrapping]
+Enables you to set traps which harm monsters.
+#####UPrereq: Disarming@15
+#####rCost: 10
+Rogues are born with this ability.
+~~~~~12|Abilities|Undead Form
+[[[[[BUndead Form]
+With this ability your character receives a small amount of Death Points (DP)
+when they 'die'. Every normal (+0 speed) turn, one DP
+is lost; you can regain it like you would do with Hit Points.
+If you manage to kill enough monsters before your DP goes below 0, your
+character is brought back to life.
+#####UPrereq: Necromancy@30, INT@25
+#####rCost: 15
+Necromancers gain this ability for free at character level 25.
+
diff --git a/lib/help/advanced.hlp b/lib/help/advanced.hlp
new file mode 100644
index 00000000..3f6fe4bd
--- /dev/null
+++ b/lib/help/advanced.hlp
@@ -0,0 +1,15 @@
+|||||oy
+#####RWelcome to the ToME Advanced Help System.
+#####R=============================================
+
+Please choose one of the following help files:
+
+ *****/aoption.txt*0[(a) Options]
+ *****/bmacrofaq.txt*0[(b) Macros]
+ *****/cautomat.txt*0[(c) Automatizer help]
+ (d) Lua scripting help - coming soon
+ *****/edebug.txt*0[(e) Debug commands]
+ *****/fversion.txt*0[(f) Version information] A history of ToME's roots
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
+
diff --git a/lib/help/attack.txt b/lib/help/attack.txt
new file mode 100644
index 00000000..68fce965
--- /dev/null
+++ b/lib/help/attack.txt
@@ -0,0 +1,148 @@
+|||||oy
+~~~~~01|Attacking Monsters
+~~~~~02|Monsters|Attacking
+#####R=== Attacking and Being Attacked ===
+
+{{{{{<p>}Attacking is simple in ToME; attempting to move over a creature
+attacks it. It is also possible to attack from a distance by firing a missile
+or by magical means (wand, rod, spell, etc). Creatures attack in the same way.
+This means that if you do not wish to melee with a creature, it is wise to keep
+distant from it. This strategy is not perfect -- some monsters, such as
+dragons, have a way to attack from a distance.
+
+Some creatures, such as Ghosts, have the ability to pass through walls.
+To attack creatures (that you can see) who are currently in a wall,
+attempt to move over it (even if you cannot pass through walls, the
+attack will still happen). Monsters will take less damage from attacks
+while they are in walls. Also, if you cannot see the monster (e.g. if you
+are blind, or it is invisible and you do not have see invisible), this
+will not work: you'll have to try to tunnel. Most spells and magic devices
+cannot target monsters in walls. In situations like this, it is usually wise to
+lure the monster out of the wall before attacking it.
+
+Melee attacks are handled as such:
+#####G To-hit:
+ Your strength grants a bonus or penalty to-hit
+ Your class might grant a bonus or penalty to-hit
+ Your skill with specific kinds of weapons gives a bonus
+ to-hit (e.g.: Swordmastery gives a to-hit bonus
+ when using swords)
+ Enchantments on your weapon grant a bonus or penalty to-hit
+ Certain rings (accuracy, slaying) may also grants a bonus
+ or penalty to-hit
+ Your Tactic setting may give bonuses o penalties to-hit
+ (to change it, press 'C' and then 't' or 'T')
+ Other temporary effects (berserk, etc) might affect your
+ chance to hit
+ The armor rating of the monster you're attacking makes a
+ big difference
+
+#####G Blows:
+ Your strength and dexterity affect how many blows you get
+ Your class and level might affect how many blows you get
+ The weight of the weapon very likely will affect how many
+ blows you get
+ Certain skills (e.g. Swordmastery) may affect how many blows
+ you get with particular weapons
+ Enchantments on your weapon might also affect how many
+ blows you get (this is rare)
+ Certain very rare rings (of attacks) may also affect how
+ many blows you get
+
+#####G Damage:
+ The base damage of your weapon is rolled
+ Strength grants a bonus or penalty
+ Your class might grant a bonus or penalty
+ Combat and Weaponmastery skills increase your melee damage
+ Ranged masteries increase the damage multiplier of slings,
+ bows, crossbows or boomerangs(see below)
+ Enchantments on your weapon might also grant a bonus or
+ penalty
+ Your Tactic setting may give bonuses o penalties to damage
+ (to change it, press 'C' and then 't'or'T')
+ Temporary effects also might grant a bonus or penalty
+
+So, each blow you are entitled to is checked for a hit. If this is the case,
+the damage is then applied to the monster. Note that unless you have some
+barehanded combat training or are possessing a monster, melee without a weapon
+will result in a single blow that does base damage of 1d1. This might, however,
+be useful in attacking certain rare monsters that destroy weapons.
+
+Combat with a bow/sling is similar, except ammo is used (which will eventually
+run out, requiring replacement). Bows don't have a base damage rating (ammo
+does), instead having a damage multiplier. Bows can, however, be enchanted,
+and enchantment on bows and arrows is cumulative (meaning that well-enchanted
+bows and arrows can be one of the more effective weapons in the game. They
+do, however, tend to be very expensive, as non-artifact arrows frequently break
+after being fired).
+Using ammo without the appropriate bow generally has poor results.
+~~~~~03|Armor
+#####R=== Armor ===
+
+As the armor class of a monster greatly affects how hard it is for it
+to be hit, your armor class affects how hard it is for it to hit you.
+A high armor rating will make it much easier to survive deep in the dungeon.
+For a warrior style class (Unbelievers, Fighters, Archers, etc), it is
+generally wise to wear as much and as powerful armor as possible (subject
+to weight limitations, of course). Spellcasting classes, however, have
+limits on how much armor they can wear before it disrupts their motion
+and makes it hard for them to cast spells properly. For many of these classes,
+gloves are especially bad for spellcasting. Monks and Rogues skilled
+at dodging will often find heavy armor cumbersome, too.
+Armor has a base rating and an enchantment rating. The base rating is constant
+for the type of armor (e.g. paper armor always has a base rating of 4), and
+the enchantment depends on the item. There are also ways to further enchant
+armor you have. Certain very powerful enchantments grant resistances to
+specific forms of magical attacks.
+~~~~~04|Attacking Monsters|Resistances
+~~~~~05|Armor|Resistances
+#####R=== Resistances and typed attacks===
+Many kinds of monsters, traps, and other effects do damage that has a type.
+Types can have side effects in addition to the raw damage they deal. Certain
+enchanted items can grant resistances, reducing the raw damage and possibly
+reducing or eliminating the side effects. Some monsters also have resistances,
+so watching the messages when attacking a monster can often reveal that a
+particular attack is ineffective.
+~~~~~06|Attacking Monsters|Damage Effect type (Fire/cold/nether etc)
+~~~~~09|Damage Effects
+#####GLow attacks
+ Fire - Destroys weapons, armor, scrolls, and staves. Reduces strength.
+ Cold - Shatters potions.
+ Elec - Reduces dexterity, destroys rings and wands.
+ Acid - Reduces bonuses on equipped armor, reduces charisma.
+
+#####GMiddle attacks
+ Poison - Player becomes poisoned
+ Light - Blinds player, perma-lights area
+ Dark - Blinds player, darkens area
+ Confusion - Confuses player
+
+#####GHigh attacks
+ Nether - Drains experience
+ Nexus - Scrambles statistics, teleports player randomly
+ Disenchantment - Reduces bonuses on equipped items
+ Chaos - Confuses, drains life, causes hallucination, and more
+ Sound - Shatters potions
+ Shards - Cuts player
+
+#####GUnresistable attacks
+ Water - Stuns player
+ Ice - Stuns player, shatters potions
+ Plasma - Stuns player, otherwise same as fire attacks
+ Force - Pushes player a few squares back
+ Inertia - Slows player
+ Gravity - Slows and teleports player a few squares
+ Disintegration - Destroys items on ground, destroys walls
+ Mana - Destroys items on ground
+~~~~~07|Monsters|Monster Memory
+#####R=== Monster Memory ===
+
+The thousands of different creatures in ToME have many different
+characteristics, including spells, resistances, health, attacks, and speed.
+The information you have learned about each monster from your encounters
+with them is recorded in the monster memory (accessed with '/' or by 'l'ooking
+at a monster). It is possible to eventually learn all the characteristics
+of any given monster by interacting with them enough, but this is not always
+desirable (hanging around great hell wyrms, for example, can be hazardous
+to one's health). Certain spells may help you learn faster, as well as
+research centres in town.
diff --git a/lib/help/automat.txt b/lib/help/automat.txt
new file mode 100644
index 00000000..bf6478f8
--- /dev/null
+++ b/lib/help/automat.txt
@@ -0,0 +1,504 @@
+|||||oy
+~~~~~01|Automatizer
+~~~~~02|Auto pick-up
+~~~~~03|Auto destroy
+~~~~~04|Autosquelch
+#####R /----------------------------------------\
+#####R < The Automatizer >
+#####R \----------------------------------------/
+
+#####GWhat is the Automatizer?
+The automatizer is an advanced auto-pickup or auto-squelch (auto-destroyer). At
+a basic level, it will allow you to automatically destroy things that you have
+no use for once you walk over them, providing that you have identified one of
+them with your current character.
+
+#####GIs that it?
+Well no. The automatizer is far more flexible than that. The old-fashioned auto
+squelch allowed you to destroy things dependent on how they pseudo-id'd - you
+could auto-destroy all {cursed} swords for instance.
+This is fine to start with, but once you get deep in the dungeon, and have a lot
+of money and a decent weapon, you'll be interested in destroying {average} and
+{good} items too right? Well the automatizer allows you to define destruction of
+things providing you are of a certain level.
+
+#####GSounds quite cool, but wha...
+STOP RIGHT THERE! I haven't finished yet! Let's look at some other examples.
+Most of the time, scrolls of darkness are pretty useless. Unless you are a
+vampire, or an alchemist, right? So you might think it was no good to add
+auto-destroy of scrolls of darkness to the automatizer. But you'd be wrong, for
+you can add rules that are dependent on certain conditions, like that you are
+of a certain race, or class.
+
+#####GHey this is sounding good. What if it destroys my artifacts?
+It can't. Artifacts can never be destroyed, by the automatizer. However, watch
+out for items that are VERY cool but not artifacts... you wouldn't want to go
+destroying boots of speed would you? Fortunately there are provisions for this
+too, you could set a rule that destroyed all excellent boots (providing you were
+past character level 45 say), but not if they were boots of speed.
+
+#####GWoah! This sounds amazing!
+Yes it is, isn't it.
+
+#####GSo how do I use it?
+Well the very simplest way is as follows. When you hit 'k' (^D in the roguelike
+keyset) to destroy an item, you'll see that one option is "$ new automatizer
+rule(OFF)". If you want to destroy all future items like that that you find,
+then hit the $ key. You'll see that (OFF) changes to (ON). Now pick the item you
+want to destroy. Let's say it is a Potion of Salt Water. You would now, as
+normal, see a message "You destroy a Potion of Salt Water". Following this you
+get a prompt, "Destroy all of the same [T]ype, [F]amily, or [N]ame, also use
+[S]tatus (no)?". Let's take the easy one first and hit 'n' to go with name.
+You'll now see a message, "Rule added, please go to the automatizer screen
+(press = then T) to save the modified ruleset". Let's do that then, shall we. If
+this is the first time you have used the automatizer with this savefile, you'll
+be asked to enable it as you hit T. Confirm that you would like to enable it,
+otherwise it won't work.
+
+#####GWhat's the point in having it disabled then?
+Well let's say you spotted something that you weren't sure how it would be
+affected by your rules, but didn't want to destroy it; you could just disable
+the automatizer for a moment and check it over before deciding what to do with
+it and switching the automatizer back on.
+
+#####GHmmm, ok. So I've enabled the automatizer, now what?
+Well, you'll see a screen like this:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|GsGaGlGtG GwGaGtGeGrB B B w B|G<GrGuGlGeB BnBaBmBew=w"ysyaylyty ywyaytyeyrw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G<GnGaGmGeG>wpwowtwiwownw wowfw wswawlwtw wwwawtwewrg<g/gngagmgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+
+(snipped for brevity).
+
+The automatizer rules are written in XML, so if you're familiar with that format
+you shouldn't find things too difficult. It's also similar in format to HTML, as
+you may notice from the way that there are opening tags (<name>) and closing
+tags (</name>), and that everything between those tags is affected by that
+rule.
+
+#####GXML? HTML? What is this? Isn't ToME enough acronyms to be going on with?
+OK, so you don't know anything about mark-up languages, it's no problem. Let's
+take a look at the automatizer screen bit by bit, starting with the instructions
+bottom right.
+
+up/down to scroll. Well as you move the up/down cursor keys or number keys, a
+different rule name is highlighted in the left hand window, and that rule is
+displayed in the right hand window.
+tab to switch to the rule window. Does what it says on the tin: switches to the
+rule window (the right hand pane) to allow editing of existing rules.
+u/d to move rules. Pressing 'u' or 'd' will move the rule up or down the order
+displayed in the left hand window. Purely for cosmetic reasons.
+new rule. Adds the beginning of a new rule.
+rename rule. This is handy, as every rule added from the destroy prompt (as
+explained above) is automatically named 'destroy', which gets a bit confusing
+when you have 50 or so rules... renaming your rules will make them much easier
+to edit later.
+save rules. Saves all existing rules to a filename you designate (default is
+automat.atm). Don't forget to do this after adding new rules/before exiting the
+game.
+k to disable the automatizer. Disables the automatizer, preserving the rules you
+have made.
+
+#####GYeah yeah, so what about the rule window on the right hand side itself?
+OK, here we go. This is the real juicy stuff.
+
+Anything inside pointy brackets (greater than and less than signs) is called a
+tag. You'll notice that each tag opens with a word, and then that same word
+appears in another tag later on, preceded by a slash. These are referred to as
+opening tags (like <name> ) and closing tags (like </name> ). Everything within
+a set of closing and opening tags is affected by those tags. This will make more
+sense as we continue. Tags and the things they enclose are like "mini-rules"
+which will together make up one rule. I call these mini-rules, clauses.
+
+the first line:
+<rule name="destroy" type="destroy">
+Each rule starts with the tag <rule>, and this contains the rule name, and the
+rule type. The rule name is how it is identified in the left hand window, and
+need not be unique. The rule type will be either "destroy" (destroys items when
+conditions stated below are met) or "pickup" (picks up item when conditions are
+met) or "nothing" (neither picks up, nor destroys item when conditions are met)
+
+The second line:
+ <name>Potion of Salt Water</name>
+This tells us that for the rule to be carried out, the name of the item must be
+"Potion of Salt Water"
+
+The third line:
+</rule>
+This tells us the rule is ended.
+
+In total then, the rule named "destroy" checks to see if the name of every item
+is Potion of Salt water, and if it is, it destroys it.
+
+Nice and simple huh?
+
+#####GYes Yes, very simple. It doesn't look very advanced at the moment.
+Well, we've barely scratched the surface.
+Let's take a look at those other options we got at the destroy prompt. Let's say
+I was at a stage in the game where I wanted to be able to switch on an auto-
+destroy for all swords that pseudo-id'd as {average}. So let's say I have a
+dagger in my backpack, and I want to create an auto-destroy rule for that and
+all subsequent swords... This is what I'd do:
+Hit 'k' to destroy items and hit '$' to turn on automatizer rules. Then I'd
+select the dagger and confirm the destruction. Hit 's' to switch the status
+toggle. This toggle will include (when ON) how the dagger pseudo-ids, and
+finally hit 'f' to add a rule saying destroy by family. What you'll see in the
+automatizer screen now is this:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|GdGeGsGtGrGoGyB B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ydyeysytyryoyyw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wdwewswtwrwowyB B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+#####GOK, well I can see the pseudo-id status is there, what's that tval thing? And
+#####Gwhere does it say swords?
+Well actually the tval thing is where it says swords! This is what is added by
+the 'destroy by family' option.
+
+It's probably worth explaining a bit here about the internal structure of ToME
+code. Don't worry it's not too scary. In ToME, all objects are divided into
+types: swords, axes, hafted-weapons, scrolls, rings etc. Every type is further
+divided into sub-types. Eg swords are divided into daggers, broad swords, two-
+handed swords and so on. Scrolls are divided into their specific actions;
+scrolls of light, scrolls of satisfy hunger etc. Each type has a number assigned
+to it, that never changes, and so does each sub-type. In this way we can
+identify an exact object using just two values: it's type, or tvalue (tval) and
+it's sub-type, or svalue (sval). You see where we're going with this?
+Now daggers have a tval of 23 and an sval of 4. So you can see that we've said
+in the rule that all things with a tval of 23 and a status of average can be
+destroyed.
+
+#####GAh, right. I see. And what's with the <and> tags?
+Well, everything in those tags must be true for the rule to carry out. If we had
+the <tval>23</tval> and the <status>average</average> lines without the <and>
+tags, it would not be clear whether we wanted just one of those clauses to be
+true for the rule to be carried out, or both of them.
+
+#####GErr...
+In other words, without the <and> tags it might look like we wanted to destroy
+a) EVERYTHING that pseudo id'd as average, and
+b) EVERY sword, regardless of how it pseudo-id'd!
+
+#####GRight. What if I did want a rule that was more general, and had either/or
+options in it?
+Then there are tags to do that - the <or> </or> tags. If ANY of the clauses
+return as true within or tags, then the rule is carried out. Substitute <or>
+tags for the <and> tags in our sword example above, and the rule will operate in
+the rather unhelpful way I explained above (all {average} things destroyed, and
+all swords destroyed, regardless of how they pseudo-id). So essentially, if your
+rule has more than one clause, you will need to include either <and> tags or
+<or> tags, or in some cases both.
+
+#####GOK and so what does the [T]ype option do?
+It merely adds the sval, thus narrowing down the parameters for the auto-
+destroy. For instance if I'd chosen to destroy by type rather than family in the
+last example, we'd have ended up with this:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|GdGeGsGtGrGoGyB B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ydyeysytyryoyyw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wdwewswtwrwowyB B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GsGvGaGlB BmBiBnw=w"y4w"B BmBaBxw=w"y4w"G>g<g/gsgvgaglg>B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+You can see in this example that we have nested <and> tags. Evaluating the tags
+from the ones nested deepest first we can see that if an object has a tval of 23
+and an sval between the values of 4 and 4 (i.e. if it is 4) then the rule will
+check against the next part, which is to see if the object identifies {average}.
+If it does, then all the clauses have been met and rule is carried out. In
+short, it destroys all average daggers, rather than all average swords. Strictly
+speaking the nested <and> tags aren't needed, but they do no harm, and are added
+automatically when destroying by [T]ype.
+
+#####GThis is all well and good but the numbers are going to get rather confusing
+#####Garen't they? Be much easier if I could just write 'swords' or 'daggers'.
+Well, you can. Kind of. Instead of using the admittedly rather obtuse numbers,
+you can use the name of that tvalue rather than the number it represents. So
+instead of <tval>23</tval> you could write <tval>TV_SWORD</tval>.
+
+#####GAh that would be better. But where can I find out what all the names, and
+#####Gnumbers of tvalues are?
+Well I've written a *****defines.txt*0[file] which lists tvalues and one which lists svalues for you
+to check on, and you may want to check the objects entry in k_info.txt in your
+lib/edit directory. If you look at the entry for dagger you'll see:
+
+N:43:& Dagger~
+G:|:W
+I:23:4:0
+W:0:0:12:10
+A:0/1:5/1:10/1:20/1
+P:0:1d4:0:0:0
+<snip>
+The only line we're interested in is the one that starts I (for Index). The
+first number is the tval, and the second is the sval.
+Of course you could always rename your rule to make things clearer.
+
+#####GOK so you mentioned something about setting rules up that happen only if a
+#####Gplayer is a certain level?
+Yeah, good point. Well, let's develop our destroy average swords rule for the
+moment. Let's say we always wanted to destroy average swords by the time we got
+to character level 20. They don't earn enough gold to make it worth carrying
+back to town, and we'll have a better weapon by then anyway. So here we are in
+the automatizer screen, with the destroy sword rule displaying in the right hand
+window. If we hit tab, the right window becomes active and the rules at the
+bottom change:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|gdgegsgtgrgogyB B B B B B w B|v<vrvuvlveB BnBaBmBew=w"ydyeysytyryoyyw"B BtByBpBew=w"ydyeysytyryoyyw"v>B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wdwewswtwrwowyB B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|v<v/vrvuvlvev>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW/BlBeBfBtW/BrBiBgBhBtW WtWoW WnWaWvWiWtWaWgWeW WrWuWlWeW,W B9W/B3W/B7W/B1W WtWoW WsWcWrWoWlWlw w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BtBaBbW WfWoWrW WsWwWiWtWcWhW,W BaWdWdW WcWlWaWuWsWeW,W BdWeWlWeWtWeW WcWlWaWuWsWeW/WrWuWlWew w w w w w w w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+You can see the <rule> tags have changed to purple, indicating they are the
+active ones, that all key presses will act upon. Let's just quickly scoot
+through these new commands:
+up/down/left/right to navigate rule: These will change which clause is active,
+enabling you to delete that clause, or add further clauses inside that one if it
+so allows it.
+9/3/7/1 to scroll: scrolls the whole screen which can become useful if you have
+a particularly long rule or one with lots of nested clauses.
+tab for switch: will make the left-hand window active again.
+add clause: adds a new clause within the active one, providing the active clause
+is either a <and>, <or> or <not> tag.
+delete clause/rule: deletes the active clause, and any clauses nested within
+that one. Therefore if the <rule> tags are active, the whole rule will be
+deleted. Beware!
+
+So if we now hit our right arrow we see that the <and> tags are active. We can
+now add a new clause here. Let's do so by pressing 'a'. You'll now see a list of
+different types of clauses you can add, which you simply scroll through using up
+and down keys, and select by hitting enter. A brief description of the selected
+clause is shown in the right hand window. Scroll down to the 'level' rule type
+and hit enter. You'll be asked to enter a player level. Let's go for 20. You'll
+then be asked for a maximum level, put 50, as we want the rule to be true from
+level 20 and upwards. You'll now see our rule displays as:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|gdgegsgtgrgogyB B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ydyeysytyryoyyw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wdwewswtwrwowyB B B B B B w B|v v v v v<vavnvdv>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y2y0w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|v v v v v<v/vavnvdv>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW/BlBeBfBtW/BrBiBgBhBtW WtWoW WnWaWvWiWtWaWgWeW WrWuWlWeW,W B9W/B3W/B7W/B1W WtWoW WsWcWrWoWlWlw w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BtBaBbW WfWoWrW WsWwWiWtWcWhW,W BaWdWdW WcWlWaWuWsWeW,W BdWeWlWeWtWeW WcWlWaWuWsWeW/WrWuWlWew w w w w w w w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+So there we go. A rule which will destroy all {average} swords once the player
+is past character level 20.
+
+#####GHmmm I've tried this, it doesn't destroy cursed swords though...
+Nope. You haven't told it to. If you want a scaling rule, which always destroys
+cursed swords and then destroys average swords at character level 20, then {good}
+swords at character level 35, have a look at this, rather more complicated rule.
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|wswhwiwewlwdB B B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ysywyoyrydysw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wbwowwB B B B B B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|whwrwdw wawrwmwowuwrB B B w B|G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wawxwewsB B B B B B B B B w B|G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|whwewlwmwsB B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswowfwtw wawrwmB B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y0w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B B w B|
+&&&&&B|wbwowlwtwsB B B B B B B B w B|G G G G G G G G G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wbwowowtwsB B B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wvwewrwyw wbwawdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wgwlwowvwewsB B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wbwawdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wpwowlwewawrwmwsB B B B B w B|g g g g g g g g g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wcwlwowawkB B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|GsGwGoGrGdGsB B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|whwawfwtwewdwsB B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y1y5w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|wawrwrwowwwsB B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswhwowtB B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wbwowowmwewrwawnwgB B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wtwowrwcwhB B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y2y5w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|wrwowdw wtwiwpwsB B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wgwowowdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wpwowtwiwownwsB B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wrwiwnwgwsB B B B B B B B w B|g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wwwawnwdwsB B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wmwuwswhwrwowowmwsB B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswcwrwowlwlwsB B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wawmwuwlwewtwsB B B B B B w B|w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w B|
+&&&&&B|wpwawrwcwhwmwewnwtwsB B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|wswhwawpwew wpwowtB B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|wswtwawvwewsw w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+#####GWoah! What the heck is that?!
+OK ok slow down a minute. Look at it carefully and a clause at a time. It's not
+difficult. Let's take it from the top. It's a destroying rule called swords. It
+opens with some <and> tags. The object must be a sword (tval 23). Now we have an
+OR tag, so we know that there are going to be some options:
+option 1: the player is between level 0 and level 50, and the sword pseudo id's
+as either cursed or worthless.
+option 2: the player is above character level 15, and the sword pseudo id's as
+average.
+option 3: the player is above character level 25, and the sword pseudo id's as
+good.
+If any of these options are true, the rule is carried out. This rule could
+easily be copied for other weapons or pieces of armour, substituting only the
+tval, and perhaps the name.
+
+#####GHmmm ok. looks good. I might want to change those character level values
+#####Gthough. they look a bit low...
+Well yeah, that's up to your playing style I guess... If you want to edit
+clauses directly rather than delete and re-add them, you might want to edit the
+automat.atm file directly. Just open it in your text editor (it's located in
+your lib/user directory or in ~/.tome on multiuser systems) and you'll see the
+format is identical to how it is displayed in the automatizer file. Just watch
+your spellings, and keep a back-up of the original to replace if things go
+wrong. Don't mess about in there if you feel unsure of what you're doing though.
+
+#####GSo what about those examples you gave up above? Like destroying scrolls of
+#####Gdarkness unless you are a vampire or an alchemist?
+OK, let's add this rule from scratch rather than from the destroy item prompt.
+In the automatizer screen, hit 'n' for new rule. It asks for a name and a type
+of rule (destroy/pickup/nothing). I called my rule "? of darkness", and it's a
+destroy rule. It is worthwhile thinking at this point how the rule is going to
+be structured; for very complicated rules pen and paper may help. We're going to
+need to define the object (either by name, or by tval and sval) then we're going
+to say unless the player race modifier is vampire, or the player class is
+alchemist. So we are obviously going to have more than one clause, and the
+clauses are going to have to BOTH be true for the rule to take effect so the
+first clause we add is an <and> one. So hit 'a' for add clause and enter to
+select the <and> clause. Lets now hit our right arrow, so the <and> tags are
+active, and add a new rule. We can now select the <name> tags. At this point
+we're prompted for the name. Now it's not case-sensitive, but you do need to
+spell it correctly!
+With the <and> tags still highlighted we now want to add our "unless vampire or
+alchemist" clause. Seeing as this is an "unless" type clause, we start with a
+<not> tag. So again, 'a'dd a new clause, and select <not>.
+Now make the <not> tag active by moving right and down with the cursor keys. We
+want "EITHER vampire or alchemist" so we include <or> tags, again by moving
+across to make the <not> tags active and 'a'dding a new <or> clause. Then select
+the <or> tags and 'a'dd a new <subrace> clause. Enter 'vampire'.
+So the last part is to add alchemist. Now this might at first glance seem to be
+a simple case of 'a'dding a new clause of the <class> type, within the <or>
+tags, and there is certainly nothing 'wrong' with doing this. At present there
+is no way for non-alchemists to get the alchemy skill, but it is sometimes best
+to 'future-proof' against such possibilities. That's what we're going to do
+here.
+So rather than add a <class> clause, we're going to add a <skill> clause.
+With the <or> tags active, 'a'dd a new <skill> clause. You're first asked for a
+minimum skill level. Well, we can't use any skill unless we have 1.00 whole
+skill points in it or more, so we can put 1 in here. We're then asked for a
+maximum skill level, so we'll put in 50 here. The skill name must be spelled
+correctly (as it appears on the skill screen) so we put 'Alchemy' here. Your
+complete rule now appears as follows:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|G?G GdGaGrGkGnGeGsGsB B B w B|G<GrGuGlGeB BnBaBmBew=w"y?y ydyayrykynyeysysw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswwwowrwdwsB B B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswawlwtw wwwawtwewrB B B w B|G G G G G G G G G<GnGaGmGeG>wSwcwrwowlwlw wowfw wdwawrwkwnwewswsg<g/gngagmgeg>B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GnGoGtG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGuGbGrGaGcGeG>wvwawmwpwiwrweg<g/gsgugbgrgagcgeg>B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGkGiGlGlB BmBiBnw=w"y1w"B BmBaBxw=w"y5y0w"G>wAwlwcwhwewmwyg<g/gsgkgiglglg>B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g<g/gngogtg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+You'll notice I've also renamed the rules to make things a bit more legible.
+
+#####GOK I'm getting there now, what about the boots of speed thing you talked about?
+Heh. Take a look at this, and see if you can work out what it's doing first
+before I talk you through it
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|GbGoGoGtGsB B B B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ybyoyoytysw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|w?w wdwawrwkwnwewswsB B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswwwowrwdwsB B B B B B B w B|G G G G G G G G G<GtGvGaGlG>wTwVw_wBwOwOwTwSg<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswawlwtw wwwawtwewrB B B w B|G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y0w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wvwewrwyw wbwawdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wbwawdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y2y0w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y3y5w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wgwowowdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y4y5w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wvwewrwyw wgwowowdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGeG>wiwdwewnwtwiwfwiwewdg<g/gsgtgagtgeg>B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GnGoGtG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GcGoGnGtGaGiGnG>wswpwewewdg<g/gcgogngtgagigng>B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g g g g g<g/gngogtg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+The majority of this is fairly similar to the swords rule; it destroys {average}
+boots at character level 20, {good} ones at character level 35 and cursed ones
+always. The addition is at the bottom. It adds clauses which will destroy
+excellent items providing that they have been identified and that the name does
+not contain the word "speed". The <state>identified</state> bit is important
+here, as it would destroy the boots on pseudo-id otherwise, before it even saw
+the full name of the boots.
+
+#####GThis is fantastic! Where can I get more help?
+email me: fearoffours@t-o-m-e.net
diff --git a/lib/help/birth.txt b/lib/help/birth.txt
new file mode 100644
index 00000000..00b1a921
--- /dev/null
+++ b/lib/help/birth.txt
@@ -0,0 +1,593 @@
+|||||oy
+~~~~~84|Birth
+~~~~~11|Character
+#####R /----------------------------------------\
+#####R < Creating a Character >
+#####R \----------------------------------------/
+
+ *****birth.txt*01[Creating a Character] *****birth.txt*02[Character Characteristics]
+ *****birth.txt*03[Races] *****birth.txt*04[Race Modifiers]
+ *****birth.txt*05[Classes] *****birth.txt*83[Gods]
+ *****birth.txt*06[Stats] *****birth.txt*07[Abilities]
+ *****birth.txt*08[Combinations of Race and Class] *****birth.txt*09[Stat bonus tables]
+
+~~~~~01|Character|Creating a Character
+~~~~~12|Creating a Character
+#####R=== Creating a Character ===
+
+ToME is a roleplaying game, in which you, the player, control a
+character in the various dungeons and places of Arda. Perhaps the most
+important thing you control is the birth of your character, in which you
+choose or allow to be chosen various attributes that will affect the future
+life of your character.
+
+Character creation, or birth, is controlled through a variety of choices
+as to constraints on the type of character you wish to play, followed by
+a series of random calculations to generate ("roll up") a random character
+matching the appropriate constraints.
+
+Once your character has been generated, you will be given the choice to
+generate a new character obeying the same constraints, and once you have
+generated more than one character, you can switch back and forth between
+the two most recent characters, until you are presented with a personality
+that you feel comfortable with.
+
+You may start the entire process over at any time.
+
+Once you have accepted a character you will asked to provide a name for the
+character. In general, the actual choice of a name is not important, but do
+keep in mind that it may have some effect on the game itself. For example,
+on some machines, the character name determines the filename that will be
+used to save the character to disk. On others, the character name specifies
+special "pref" files. And the character name is used on the high score list.
+
+~~~~~02|Character|Characteristics
+~~~~~13|Character|Stats 1
+~~~~~14|Stats|Display
+~~~~~37|Display
+~~~~~82|Stats
+#####R=== Character Characteristics ===
+
+Each character has four primary attributes -- gender, race, race modifier and
+class -- that are chosen before the character is generated, and all but gender
+stay fixed for the entire life of that character. These attributes have many
+effects, which will be mentioned as they come up. Keep in mind that in the
+current version of ToME, your choice of race may restrict your choice
+of class.
+
+Each character has a few secondary attributes -- height, weight, social class,
+and background history -- which are randomly determined, but which are affected
+by the gender and race of the character. In general, these attributes are only
+used to provide "flavor" to the character, to assist in the role playing, but
+they do have a few minor effects on the game. For example, background history
+affects social class, which affects the amount of money the character will
+start with.
+
+Each character also has six primary "stats": strength (STR), intelligence
+(INT), wisdom (WIS), dexterity (DEX), constitution (CON), and charisma (CHR).
+
+By default, primary statistics are represented in a linear way rather than a
+percentile way. You can change to percentile via the game option sequence '=',
+'5' (ToME options), arrow down to 'stats are represented in a linear way', and
+type 'n' for no. Don't forget to save your options when you are done.
+
+These stats modify the abilities of the character in a variety of ways. Every
+stat has a numerical value, ranging from a minimum of 3, up to a normal maximum
+of 18, and even higher, into the "percentile" range, represented as "18/01"
+through "18/100". Actually, every stat can be raised even above 18/100 by
+magical means, up to a pure maximum of 18/220, which is represented as
+"18/***". Traditionally, a percentile stat such as "18/50" has been though of
+as representing a value part way between 18 and 19, and this is one way to
+think of them. However, often, the best way to view the "bonus" values after
+the "18/" is as "tenth" points, since it often takes the same magic to raise a
+stat from, say, 4 to 5, or 16 to 17, as it does from, say, 18/40 to 18/50. The
+important thing to remember is that almost all internal calculations "ignore"
+the final digit of any "bonus", so that, for example, "18/40" and "18/49"
+generally have the same effects. During character generation, each stat is
+rolled out as a number from 8 to 17, with a normal (bell-curve) distribution,
+and is then immediately modified based on the race and class of the character.
+
+Each character also has several primary "skills" -- disarming, magic devices,
+saving throws, stealth, searching ability, searching frequency, fighting skill,
+and shooting skill -- which are derived from the character's race, class, level,
+stats, and current equipment. These skills have rather obvious effects, but
+will be described more completely below.
+
+Each character may have one or more "intrinsic racial skills", based on
+the race of the character. These may include special resistances, abilities
+such as infravision, or even activatable powers such as food creation.
+~~~~~16|Gold
+~~~~~81|Abbreviations
+~~~~~17|Abbreviations|AU
+~~~~~18|Money
+Money in ToME is referred to in gold pieces, also frequently abbreviated as AU
+(the chemical symbol for gold).
+
+Each character starts with some gold, which can be used to buy items from the
+shops in town. Additionally, gold can be obtained by several means:
+
+ * selling items you have, or find, to the shops
+ * taking it from dead monsters
+ * finding it lying around on the floor in the dungeon
+ * digging it out of the walls in certain dungeons
+
+Each character starts out with some gold. The amount you start with is based on
+social class (higher is better), charisma (higher is better), and some other
+stats (less powerful characters start with more gold).
+~~~~~85|Inventory - starting info
+Inventory is what you are carrying and/or wearing at the moment. All items you
+carry/wear have a certain weight. If the weight is very heavy for your
+strength, it can slow you down, and that is not a good thing for your
+character's continuing health. When your character is first created, all items
+you are granted upon creation will be in your inventory. Sometimes starting
+inventory includes something other than a weapon or armor (for example, a light
+source, scroll, potion, or food.)
+~~~~~86|Weapons - starting info
+Some characters start with a weapon. If yours does, you will need to 'w'ield it
+in order to gain its attack capabilities.
+~~~~~23|Character|Armor Class
+~~~~~19|Armor|Armor Class
+~~~~~20|Abbreviations|AC
+#####R === Armour Class ===
+Each character has an armor class, representing how well the character can
+avoid damage. The armor class is affected by dexterity, the equipment, and
+sometimes the race. The higher the AC, the better.
+
+The numbers following a piece of armor's name indicate how good it is. A Metal
+Cap [3,+0] is not as good as an Iron Helm [5,+0], AC-wise, since the 5 is a
+bigger number than the 3. On the other hand, an Iron Helm is heavier than a
+Metal Cap, and that may make a difference to you.
+
+The plusses following the first number (e.g. the +0) indicate a magical bonus.
+If the plus number is more than zero, it should be added on to the base
+number. E.g. a Metal Cap [3,+3] has a higher AC than an Iron Helm [5,+0].
+
+Some characters start with armor. If yours does, you need will need to 'w'ield
+it in order to gain its protection.
+~~~~~21|Abbreviations|HP
+~~~~~22|Character|Hit Points
+Each character has hit points (HP), representing how much damage the character
+can sustain before death. Hit points are derived from your race, class,
+level, and constitution, and can be temporarily boosted by magical means.
+Hit points may be regained by resting, or by a variety of magical means.
+~~~~~24|Abbreviations|SN
+~~~~~25|Character|Sanity Points
+Each character has sanity points (SN), representing how much mental damage the
+character can sustain before death. Sanity points are derived from your wisdom
+and character level. Sanity points may only be regained by magical means and
+won't be regained by resting.
+~~~~~26|Abbreviations|SP
+~~~~~27|Magic|Mana
+~~~~~28|Character|Mana
+Each character has a certain amount of mana. The amount of mana represents how
+many spells of a certain difficulty a character can cast. When a spell is
+cast, you lose amount of mana corresponding to the 'cost' of the spell.
+
+When all mana is gone, or the cost of a given spell is greater than the amount
+of mana you have left, you may attempt to cast a spell; beware, as there are
+consequences to such a rash act.
+
+Spell points may be regained by resting. They can also be restored by a few
+magical means.
+
+Your spell points are derived from your Magic skill, player level and the
+greatest of INT and WIS.
+
+Your total spell points are additionally affected by:
+
+ * your character's race modifier
+ * character class
+
+Your total spell points may be affected by:
+
+ * your encumbrance
+ * what you wear
+
+~~~~~29|Abbreviations|Pt
+~~~~~30|Gods|Piety
+~~~~~31|Character|Piety
+Finally, characters that have chosen to follow a *****gods.txt*0[God] will have piety points
+(Pt). These points represent the character's standing with their God, a
+standing which may rise or fall over time. A character may spend piety points
+to cast a spell granted by his/her God. Spent piety points can be regained in
+different fashions, depending on which God is involved -- each is pleased or
+displeased by assorted actions. Pleasing your God gains you piety, while
+displeasing your god will lose you piety.
+
+In addition to forming the basis for God-granted spells, accumulated piety
+points may also confer various benefits or penalties upon your character,
+depending on the God involved. For example, followers of Eru who have
+accmulated lots of piety points gain a WIS bonus. The actual rules are
+quite specific to each God.
+~~~~~03|Races
+#####R=== Races ===
+
+There are lots different races that you can choose from in ToME. Some
+races are restricted as to what profession they may be, and each race has
+its own adjustments to a character's stats and abilities. Most races also
+have intrinsic abilities, which can be accessed via the "U" command (original
+keyset, or "O" in the roguelike keyset).
+
+ *****r_beorn.txt*0[Beorning] *****r_hafelf.txt*0[Half-Elf] *****r_orc.txt*0[Orc]
+ *****r_drkelf.txt*0[Dark Elf] *****r_hafogr.txt*0[Half-Ogre] *****r_pettyd.txt*0[Petty-Dwarf]
+ *****r_deathm.txt*0[Death Mold] *****r_hielf.txt*0[High-Elf] *****r_rohank.txt*0[Rohan Knight]
+ *****r_dunad.txt*0[Dunadan] *****r_hobbit.txt*0[Hobbit] *****r_thlord.txt*0[Thunderlord]
+ *****r_dwarf.txt*0[Dwarf] *****r_human.txt*0[Human] *****r_troll.txt*0[Troll]
+ *****r_elf.txt*0[Elf] *****r_kobold.txt*0[Kobold] *****r_wodelf.txt*0[Wood Elf]
+ *****r_ent.txt*0[Ent] *****r_maia.txt*0[Maia] *****r_yeek.txt*0[Yeek]
+ *****r_gnome.txt*0[Gnome]
+
+~~~~~04|Race Modifiers
+#####R=== Race Modifiers ===
+
+There are many different race modifiers from which you can choose in ToME.
+Some are restricted as to what race they can be used with, and each one has
+its own adjustments to a character's stats and abilities. Most also have
+intrinsic abilities. If you are not asked for a race modifier, it is because
+your race only supports the classical form.
+
+ *****rm_class.txt*0[Classical] *****rm_barb.txt*0[Barbarian]
+ *****rm_herm.txt*0[Hermit] *****rm_lsoul.txt*0[Lost Soul]
+ *****rm_skel.txt*0[Skeleton] *****rm_spec.txt*0[Spectre]
+ *****rm_vamp.txt*0[Vampire] *****rm_zomb.txt*0[Zombie]
+
+~~~~~05|Classes
+#####R=== Classes ===
+
+Once a race has been chosen, you will need to pick a class. Some classes will
+not be available to certain races, for instance, a Troll cannot become a
+Paladin. For the first few adventures it is suggested that you run a warrior
+or rogue. Spell casting generally requires a more experienced player that is
+familiar with survival techniques.
+
+ *****c_alchem.txt*0[Alchemist] *****c_mage.txt*0[Mage] *****c_rogue.txt*0[Rogue]
+ *****c_archer.txt*0[Archer] *****c_mimic.txt*0[Mimic] *****c_runecr.txt*0[Runecrafter]
+ *****c_assass.txt*0[Assassin] *****c_mindcr.txt*0[Mindcrafter] *****c_sorcer.txt*0[Sorceror]
+ *****c_axemas.txt*0[Axemaster] *****c_monk.txt*0[Monk] *****c_summon.txt*0[Summoner]
+ *****c_bard.txt*0[Bard] *****c_necro.txt*0[Necromancer] *****c_swordm.txt*0[Swordmaster]
+ *****c_pr_drk.txt*0[Dark-Priest] *****c_palad.txt*0[Paladin] *****c_symbia.txt*0[Symbiant]
+ *****c_demono.txt*0[Demonologist] *****c_polear.txt*0[Polearmmaster] *****c_thaum.txt*0[Thaumaturgist]
+ *****c_druid.txt*0[Druid] *****c_posses.txt*0[Possessor] *****c_unbel.txt*0[Unbeliever]
+ *****c_geoman.txt*0[Geomancer] *****c_pr_eru.txt*0[Priest(Eru)] *****c_warper.txt*0[Warper]
+ *****c_hafted.txt*0[Haftedmaster] *****c_pr_man.txt*0[Priest(Manwe)] *****c_warrio.txt*0[Warrior]
+ *****c_lorema.txt*0[Loremaster] *****c_ranger.txt*0[Ranger]
+~~~~~83
+#####R=== Gods ===
+
+Once a class has been chosen you may be given the option to choose a god. Some
+classes (notably most Priests) will be given a God to worship automatically.
+Some classes are not necessarily suited to following a God, and Gods are not
+recommended for new players. You can also choose your mind about who (if
+anyone) to worship during the game by finding an *****tome_faq.txt*04[altar] of that God.
+
+Read *****gods.txt*0[gods.txt] for a little more information about Gods.
+
+ *****g_eru.txt*0[Eru Iluvatar] *****g_manwe.txt*0[Manwe Sulimo]
+ *****g_yavann.txt*0[Yavanna Kementari] *****g_tulkas.txt*0[Tulkas]
+ *****g_melkor.txt*0[Melkor Bauglir]
+
+
+~~~~~39|Character|Stats 2
+~~~~~06|Stats|Individual explanations
+#####R=== Stats ===
+~~~~~32|Stats|Strength
+~~~~~34|Strength
+#####G Strength (STR)
+ Strength is important in fighting with weapons and in melee
+ combat. A high strength can improve your chances of hitting
+ as well as the amount of damage done with each hit. Char-
+ acters with low strengths may receive penalties. Strength
+ is also useful in tunnelling and in carrying heavy items.
+~~~~~33|Stats|Intelligence
+~~~~~35|Intelligence
+#####G Intelligence (INT)
+ Intelligence affects the spellcasting abilities of mage-like
+ spell schools (whether these spells are learned directly through
+ their associated skills, or indirectly through the Prayer
+ skill), as well as some of the special abilities of various
+ classes (e.g. Symbiants). Intelligence will affect the number
+ of spell points you receive. A high intelligence may also
+ improve your chances of successfully casting a spell. You cannot
+ learn spells if your intelligence is 7 or lower. A good
+ intelligence can also help with using magic devices, picking
+ locks, and disarming traps.
+~~~~~36|Stats|Wisdom
+~~~~~38|Wisdom
+#####G Wisdom (WIS)
+ The primary function of wisdom is to determine the ability
+ of a priest or paladin to use prayers (God-granted spells), just
+ like intelligence affects mage spells. Again, high wisdom will
+ increase the number of spell points you have (even though
+ prayers use piety points), and will improve the chance that a
+ prayer will be successful. A good wisdom can also help to
+ improve your chances of resisting magical spells cast
+ upon you by monsters.
+~~~~~40|Stats|Dexterity
+~~~~~41|Dexterity
+#####G Dexterity (DEX)
+ Dexterity is a combination of agility and quickness. A high
+ dexterity may allow your character to get multiple blows with
+ lighter weapons, thus greatly increasing your kill power, and
+ will increase your chances of hitting with any weapon and
+ dodging blows from enemies. Dexterity is also useful in
+ picking locks, disarming traps, and protecting yourself from
+ some of the thieves that inhabit the dungeons. The unscrupulous
+ adventurer may also find dexterity effective in obtaining items
+ from stores without rendering payment.
+~~~~~42|Stats|Constitution
+~~~~~43|Constitution
+#####G Constitution (CON)
+ Constitution is a character's ability to resist damage to his
+ body, and to recover from damage received. Therefore a
+ character with a high constitution will receive more hit
+ points and also recover them faster while resting.
+~~~~~44|Stats|Charisma
+~~~~~45|Charisma
+#####G Charisma (CHR)
+ Charisma represents a character's personality and physical
+ appearance. A character with a high charisma will receive
+ better prices from store owners, whereas a character with a
+ very low charisma may be robbed blind. A high charisma will
+ also mean more starting money for the character.
+~~~~~07
+~~~~~46|Character|Abilities
+#####R=== Abilities ===
+
+ Characters possess some different abilities which can help them
+ to survive. The starting abilities of a character are based upon
+ race and class. Abilities may be adjusted by high or low stats,
+ and increase with the corresponding *****skills.txt*0[skill] level.
+~~~~~48|Attacking monsters|Fighting ability
+#####G Fighting
+ Fighting is the ability to hit and do damage with weapons or
+ fists. Normally a character gets a single blow from any
+ weapon, but if his dexterity and strength are high enough,
+ he may receive more blows per round with lighter weapons.
+ Strength and dexterity both modify the ability to hit an
+ opponent. This skill increases with the *****skills.txt*02[Weaponmastery] skill
+ and its sub-skills.
+~~~~~50|Attacking monsters|Shooting
+#####G Shooting Ability (Bows/Throw)
+ Using ranged missile weapons (and throwing objects) is
+ included in this skill. Different stats apply to different
+ weapons, but this ability may modify the distance an object
+ is thrown/fired, the amount of damage done, and the ability
+ to hit a creature. This skill increases with the *****skills.txt*08[Archery] skill
+ and its sub-skills.
+~~~~~52|Saving throw
+#####G Saving Throw
+ A Saving Throw is the ability of a character to resist the
+ effects of a spell cast on him by another person/creature.
+ This does not include spells cast on the player by his own
+ stupidity, such as quaffing a nasty potion. This ability
+ increases with the *****skills.txt*38[Spirituality] skill,
+ A high wisdom also increases this ability.
+~~~~~54|Stealth
+#####G Stealth
+ The ability to move silently about is very useful. Charac-
+ ters with good stealth can usually surprise their opponents,
+ gaining the first blow. Also, creatures may fail to notice
+ a stealthy character entirely, allowing a player to avoid
+ certain fights. This skill is based upon race, class and the
+ *****skills.txt*15[Stealth] skill.
+~~~~~56|Disarming traps
+#####G Disarming
+ Disarming is the ability to remove traps (safely), and
+ includes picking locks on traps and doors. A successful
+ disarming will gain the character some experience. A trap
+ must be found before it can be disarmed. Dexterity and
+ intelligence both modify the ability to disarm, and this
+ ability increases with the *****skills.txt*16[Disarming] skill.
+~~~~~58|Magical Devices
+#####G Magic Device
+ Using a magical device such as a wand or staff requires
+ experience and knowledge. Spell users such as magi and
+ priests are therefore much better at using a magical device
+ than say a warrior. This skill is modified by intelligence,
+ and increases with the *****skills.txt*54[Magic-Device] skill.
+~~~~~60|Searching
+~~~~~61|Searching|Searching Frequency - Perception
+~~~~~62|Perception
+#####G Searching Frequency (Perception)
+ Perception is the ability to notice something without
+ actively seeking it out. This skill is based upon race,
+ class and the *****skills.txt*14[Sneakiness] skill.
+~~~~~63|Searching|Searching Ability
+#####G Searching Ability (Searching)
+ To search is to actively look for secret doors, floor traps,
+ and traps on chests. Rogues are the best at searching, but
+ magi, rangers, and priests are also good at it. This skill
+ is based upon race, class and the *****skills.txt*14[Sneakiness] skill.
+~~~~~66|Infra-vision
+#####G Infra-vision
+ Infra-vision is the ability to see heat sources. Since most
+ of the dungeon is cool or cold, infra-vision will not allow
+ the player to see walls and objects. Infra-vision will allow
+ a character to see any warm-blooded creatures up to a cer-
+ tain distance. This ability works equally well with or with
+ out a light source. The majority of ToME's creatures are
+ cold-blooded, and will not be detected unless lit up by a
+ light source. Most non-human races have innate infra-vision
+ ability. Humans can gain infra-vision only through magic
+ enhancement.
+
+~~~~~08|Character|Race and Class Combinations
+~~~~~67|Races|Combinations with class
+~~~~~68|Classes|Combinations with Race
+~~~~~69|Tables
+~~~~~70|Tables|Combinations of Race and Class
+#####R=== Combinations of Race and Class ===
+
+These are the classes that are recommended for different races. You can
+still select a race that is not in the chart, but these combinations are
+either rather poor (like a zombie mage), a concept so silly that they
+are not recommended, or an incredibly unfair combination of race and class.
+If you pick a combination that is not on the chart, don't complain if things
+don't turn out as you expected them to.
+
+#####B Warrior Archer Rogue Mage Priest Loremaster
+#####B
+Beorning Yes No Yes No No Yes
+Dark Elf Yes Yes Yes Yes Yes No
+Death Mold No No No Yes Yes No
+Dunadan Yes Yes Yes Yes Yes Yes
+Dwarf Yes No No No Yes No
+Elf Yes Yes No Yes Yes Yes
+Ent Yes No No No Yes Yes
+Gnome Yes No Yes Yes No No
+Half-Elf Yes Yes Yes Yes Yes Yes
+Half-Ogre Yes No No No Yes No
+High-Elf Yes Yes No Yes Yes Yes
+Hobbit Yes Yes Yes Yes No Yes
+Human Yes Yes Yes Yes Yes Yes
+Kobold Yes Yes Yes No No No
+Maia Yes Yes Yes Yes Yes Yes
+Orc Yes Yes Yes No Yes No
+Petty Dwarf Yes No Yes No No No
+RohanKnight Yes No No No Yes No
+Thunderlord Yes Yes No Yes Yes No
+Troll Yes No No No No No
+Wood Elf Yes Yes No Yes Yes Yes
+Yeek Yes Yes Yes Yes Yes Yes
+~~~~~09|Character|Stat Bonus Table
+~~~~~71|Stats|Bonus table
+~~~~~72|Tables|Stat bonuses
+#####R=== Stat Bonus Tables ===
+
+Stat, hit dice, and experience points per level modifications due to race
+are listed in the following table.
+~~~~~75|Races|Stat Bonuses
+#####GRaces:
+#####B STR INT WIS DEX CON CHR Hit Dice Rqd Exp/level
+ Beorning +4 -2 -2 -1 +3 -5 12 +50%
+ Dark Elf -1 +3 +2 +2 -2 +1 9 +50%
+ Death Mold +10 0 +10 +0 +10 -15 15 +150%
+ Dunadan +1 +2 +2 +2 +3 +2 10 +80%
+ Dwarf +2 -2 +2 -2 +2 -3 11 +25%
+ Elf -1 +2 +2 +1 -2 +2 8 +20%
+ Ent +10 -3 +2 -5 +11 -3 14 +110%
+ Gnome -1 +2 0 +2 +1 -2 8 +35%
+ Half-Elf 0 +1 +1 +1 -1 +1 9 +10%
+ Half-Ogre +3 -1 -1 -1 +3 -3 12 +30%
+ High-Elf +1 +3 +2 +3 +1 +5 10 +100%
+ Hobbit -2 +2 +1 +3 +2 +1 7 +10%
+ Human 0 0 0 0 0 0 10 +0%
+ Kobold +1 -1 0 +1 0 -4 9 +25%
+ Maia 0 0 0 0 0 0 10 +0%
+ Petty Dwarf +1 -1 +2 0 +2 -4 11 +35%
+ Orc +2 -1 0 +1 +1 -4 10 +10%
+ RohanKnight +4 -2 +3 +1 +4 +2 10 +120%
+ Thunderlord +6 +2 +1 +1 +3 +8 12 +300%
+ Troll +4 -4 -2 -4 +3 -6 12 +37%
+ Wood Elf -3 +2 +1 +5 -4 +1 7 +30%
+ Yeek -5 -5 -5 -5 -5 -5 6 -75%
+~~~~~76|Race Modifiers|Stat Bonuses
+#####GRace Modifiers:
+#####B STR INT WIS DEX CON CHR Hit Dice Rqd Exp/level
+ Classical 0 0 0 0 0 0 +0 +0%
+ Barbarian +2 -3 -2 +1 +1 -3 +1 +25%
+ Hermit -3 +1 +1 -3 -3 +1 -3 +20%
+ Lost Soul 0 0 0 0 0 0 +0 +0%
+ Skeleton 0 -2 -2 0 +1 -4 +0 +45%
+ Spectre -5 +2 +2 +2 -3 -6 -4 +80%
+ Vampire +3 +2 -3 -2 +1 -4 +1 +100%
+ Zombie +2 -6 -6 +1 +4 -5 +3 +45%
+
+~~~~~77|Classes|Stat Bonuses
+#####GClasses:
+#####B STR INT WIS DEX CON CHR
+ Axemaster +5 -2 -2 +2 +2 -1
+ Demonologist +5 -2 -2 +2 +2 -1
+ Haftedmaster +5 -2 -2 +2 +2 -1
+ Polearmmaster +5 -2 -2 +2 +2 -1
+ Swordmaster +5 -2 -2 +2 +2 -1
+ Unbeliever +5 -2 -2 +2 +2 -1
+ Warrior +5 -2 -2 +2 +2 -1
+
+ Alchemist -5 +3 0 +1 -2 +1
+ Geomancer -5 +3 0 +1 -2 +1
+ Mage -5 +3 0 +1 -2 +1
+ Necromancer -5 +3 0 +1 -2 +1
+ Runecrafter -5 +3 0 +1 -2 +1
+ Sorceror -5 +3 0 +1 -2 +1
+ Thaumaturgist -5 +3 0 +1 -2 +1
+ Warper -5 +3 0 +1 -2 +1
+
+ Archer +2 +1 0 +2 +1 +1
+ Ranger +2 +2 0 +2 +1 +1
+
+ Assassin +2 +1 -2 +3 +1 -1
+ Rogue +2 +1 -2 +3 +1 -1
+
+ Bard +1 -2 +1 +1 0 +1
+ Loremaster +1 -2 +1 +1 0 +1
+ Mimic +1 -2 +1 +1 0 +1
+ Monk +1 -2 +1 +1 0 +1
+ Possessor +1 -2 +1 +1 0 +1
+ Summoner +1 -2 +1 +1 0 +1
+ Symbiant +1 -2 +1 +1 0 +1
+
+ Dark-Priest -1 -3 +3 -1 0 +2
+ Druid -1 -3 +3 -1 0 +2
+ Mindcrafter -1 -3 +3 -1 0 +2
+ Paladin -1 -3 +3 -1 0 +2
+ Priest(Eru) -1 -3 +3 -1 0 +2
+ Priest(Manwe) -1 -3 +3 -1 0 +2
+~~~~~10|Character|Skill tables
+~~~~~74|Tables|Skill Tables
+#####R=== Skill Tables ===
+
+~~~~~78|Races|Skill table
+#####GRaces:
+#####B Disarm Devices Sprtlty Stealth Sneak Wepnmas Archery
+ Beorning -0.6 -0.8 -3.0 -2.0 -0.1 +2.5 +0.5
+ Dark-Elf +0.5 +1.5 +10.0 +3.0 +0.8 -0.5 +1.0
+ DeathMold +1.5 -0.5 +7.5 +25 0 +2.5 +2.5
+ Dunadan +0.4 +0.5 +2.5 +2.0 +0.8 +1.5 +1.0
+ Dwarf +0.2 +0.9 +5.0 -1.0 +0.7 +1.5 +0.5
+ Elf +0.5 +0.6 +3.0 +2.0 +0.8 -0.5 +1.5
+ Ent +0.5 +0.5 +10.0 -6.0 +0.5 -0.3 -0.2
+ Gnome +1.0 +1.2 +6.0 +3.0 +0.6 -0.8 +1.2
+ Half-Elf +0.2 +0.3 +1.5 +1.0 +0.6 -0.1 +0.5
+ Half-Ogre -0.3 -0.5 -2.5 -2.0 -0.1 +2.0 0
+ High-Elf +0.4 +2.0 +10.0 +4.0 +0.3 +1.0 +2.5
+ Hobbit +1.5 +1.8 +9.0 +5.0 +1.2 -1.0 +2.0
+ Human 0 0 0 0 0 0 0
+ Kobold -0.2 -0.3 -1.0 -1.0 +0.1 +1.0 -0.8
+ Maia 0 0 0 0 0 0 0
+ Orc -0.3 -0.3 -1.0 -1.0 0 +1.2 -0.5
+ Petty Dwarf +0.3 +0.5 +5.0 +1.0 +0.5 0 0
+ RohanKnight +1.0 +0.5 +2.5 -8.0 +0.1 +0.1 +0.5
+ Thunderlord +0.6 0 +5.0 -16.0 +3.0 +1.5 +0.5
+ Troll -0.5 -0.8 -4.0 -2.0 -0.1 +2.0 -1.0
+ Wood-Elf +0.5 +0.6 +3.0 +5.0 +0.8 -2.5 +4.0
+ Yeek -0.5 -0.5 -2.5 -5.0 -0.5 -0.5 -0.5
+
+In addition to the racial starting bonuses for the standard skills listed
+above, there are some special bonuses to the skill modifier:
+
+ Beorning +1.0 Bearform-combat modifier (also 1.0 points to start)
+ Dark-Elf +0.2 Magic modifier
+ DeathMold +0.2 Necromancy modifier
+ Dwarf +0.2 Axe-mastery modifier
+ Ent +0.2 Barehand-combat modifier;
+ +0.6 Boulder-throwing modifier
+ Hobbit +0.3 Sling-mastery modifier
+ Maia Not allowed to use Prayer (modifier reduced to 0.000)
+ RohanKnight +0.2 Weaponmastery modifier
+ Wood-Elf +0.2 Archery modifier
+
+(If the character's class does not normally possess the skill, this racial
+modifier bonus will grant the skill at a starting level of 0.000.)
+
+~~~~~79|Race Modifiers|Skill table
+#####GRace Modifiers:
+#####B Disarm Devices Sprtlty Stealth Sneak Wepnmas Archery
+ Classical 0 0 0 0 0 0 0
+ Barbarian -0.2 -1.0 +0.2 -2.0 +0.0 +1.2 +0.5
+ Hermit +0.5 +1.0 +0.5 +3.0 +0.4 -0.5 -0.5
+ Lost Soul 0 0 0 0 0 0 0
+ Skeleton -0.5 -0.5 +0.5 -1.0 -0.1 +0.8 0
+ Spectre +0.2 +0.8 +0.7 +2.0 +0.2 -0.5 -0.2
+ Vampire 0 0 0 0 0 0 0
+ Zombie -0.2 -0.2 +0.5 -1.0 -0.1 +0.5 0
diff --git a/lib/help/bldg.txt b/lib/help/bldg.txt
new file mode 100644
index 00000000..3a767968
--- /dev/null
+++ b/lib/help/bldg.txt
@@ -0,0 +1,59 @@
+|||||oy
+~~~~~01|Buildings
+#####R=== Historical Town View ===
+The town is composed of both stores and buildings.
+
+#####RStores
+The stores are where you can pick up the supplies you need before entering the
+depths of the dungeon. These include:
+
+[[[[[GGeneral Store (1):] food, torches, shovels... the necessities.
+[[[[[GArmoury (2):] to protect from the ravages of the dungeon.
+[[[[[GWeaponsmith (3):] they carry anything sharp and to the point.
+[[[[[GTemple (4):] prayerbooks and those items holy.
+[[[[[GAlchemist (5):] for all sorts of bubbling potions and scrolls.
+[[[[[GMagic Shop (6):] get your wands and spellbooks here.
+[[[[[GBlack Market (7):] the prices are high, but the items unique.
+[[[[[GYour Home (8):] to store your precious treasures.
+[[[[[GBook Store (9):] for all sorts of basic spell book needs.
+
+#####ROther Buildings
+In addition to the basic stores, there are some special buildings that can be
+found in some towns. These buildings (represented by +'s) include:
+
+[[[[[GMayor's Office/Castle:] The administrative center of the town.
+Adventurers looking for work besides exploring the dungeon should hunt in here.
+[[[[[GPet Shop:] Great place to purchase eggs and get pets.
+[[[[[GThe Soothsayer:] To discover what *****/afatespoi.txt*0[fates ("a")] lie in store for you.
+[[[[[GThe Inn:] Wine, dine, rest and relax!
+[[[[[GThe Nest:] Thunderlords are masters of teleportation, and will consent to bear
+you to your chosen dungeon destination for a fee.
+[[[[[GBeastmaster Shanty:] For those who enjoy trophy hunting, and to research the
+strange animals seen during their adventures.
+[[[[[GFighters Hall:] The place to reforge weapons and armour.
+[[[[[GRangers Guild:] The place to reforge bows and arrows.
+[[[[[GLibrary:] For information of all kinds.
+[[[[[GGambling House:] Read the *****/bgambling.txt*0[rules ("b")] before paying. The games are not
+rigged, just naturally difficult.
+[[[[[GTower of Magery/Wizards Spire:] The wizards will identify your items or recharge
+your magical items for a fee.
+[[[[[GInner temple/Priests Circle:] A place of healing.
+[[[[[GPaladin guild:] Some healing and enchantments available.
+[[[[[GThe Mathom House:] Donate your unwanted items to this museum.
+... and several more!
+
+Some of the places have been known to give out quests to adventurers they
+deem capable enough. While the mayor's office is the obvious place to start,
+the Sea Dome or Beastmaster Shanty may also want you to bring in various heads
+for reasons of their own. Go into every building you can find. Quests may
+pop up in unexpected places.
+
+There are misty rumours that there may be stores outside of Bree. The faintest
+speak of stores of powerful items deep in the dungeon.
+Rumours can be helpful or just plain silly.
+All buildings are made of stone and unlikely to move around.
+
+
+ File Updated for Pern 4.x.x by Dawnmist.
+ File Updated for ToME 2.1.x by Kat B.
+ File Updated for ToME 2.3.x by gwooledge
diff --git a/lib/help/c_alchem.txt b/lib/help/c_alchem.txt
new file mode 100644
index 00000000..2f7cd58c
--- /dev/null
+++ b/lib/help/c_alchem.txt
@@ -0,0 +1,135 @@
+|||||oy
+~~~~~01|Alchemist
+~~~~~02|Classes|Alchemist
+#####R=== Alchemists ===
+
+#####GDescription
+Alchemists are the only class that can harness the abilities of the
+essences found in the dungeon. They can add these essences to staves,
+rings, wands, rods, and sometimes weapons and armour to create new items
+or recharge old ones. They can also extract essences from magical items
+they find. Using these abilities, Alchemists can get very good items at
+low levels. The trouble is getting them to survive later on.
+
+Alchemists are extremely proficient with all kinds of magical devices,
+and have made a fine art of extracting, storing, and using these
+objects' magical energies. Because they neither fight well nor cast
+powerful spells, Alchemists rely on their craftsmanship to cope with
+the dangers of the dungeons. They will quickly learn to create damage-
+dealing wands, rods, and staffs, forge powerful weapons and armour,
+make highly useful objects of other kinds, and eventually, at great cost
+to other knowledge, they can learn the perilous art of artifact creation
+itself.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +0%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.700]
+ Weaponmastery 0.700 [0.700]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 3.000 [0.900]
+ Magic-Device 1.000 [1.250]
+ Geomancy
+ Fire 0.000 [0.100]
+ Water 0.000 [0.100]
+ Air 0.000 [0.100]
+ Earth 0.000 [0.100]
+ Meta 0.000 [0.500]
+ Conveyance 0.000 [0.100]
+ Divination 0.000 [0.500]
+ Temporal 0.000 [0.100]
+ Mind 0.000 [0.100]
+ Nature 0.000 [0.100]
+ Necromancy 0.000 [0.100]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.100]
+ Alchemy 1.000 [0.800]
+Spirituality 1.000 [0.800]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*An Alchemist cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+An Alchemist begins the game with:
+ a Dagger
+ six Essences of Explosion
+ an Empty Bottle
+ a Set of Leather Gloves
+~~~~~03|Alchemist|Alchemy powers explained
+~~~~~05|Skills|Alchemy - Alchemy powers
+#####GAlchemy
+[[[[[BThe alchemical techniques are accessed using the 'm' key.]
+Alchemists may then 'E'xtract essences or add 'P'owers. The Alchemist [[[[[vmust]
+be wearing GLOVES to use their alchemy powers.
+
+An Alchemist is also capable of [[[[[Bcreating their own artifacts], but
+this is a time-consuming, and costly, activity. To do so, he must first
+learn the ability *****ability.txt*09[Artifact Creation], which costs a whopping 70 skill points
+to learn, and requires some high pre-requisites. Once he has done so,
+he needs to imbue an ego item with a number of essences of magic (equal
+to their skill level) and then wield the item. While using the item,
+it will gain experience (which reduces the amount of exp the wearer
+gains during this time). When the Alchemist feels that the item is
+powerful enough, he can finalise the artifact by "buying" powers using
+the experience the artifact has collected. He will also require exotic
+ingredients to add the abilities.
+
+Most (but not all) potions, scrolls, wands, staffs, rods, rings, and
+amulets contain usable magical energies. An Alchemist taps that
+energy, using the technique "'E'xtract essences" to create one or more
+essences of a type appropriate to the original object.
+
+The drained object itself is now called "of nothing". Unlike any
+other kind of object, it can have new magics added to it.
+
+An Alchemist can add power to such items by using essences he made or
+found. He does this with the technique "'P'ower". He can then select
+the object he wishes to enchant, and the kind of object he wishes to
+create. Only object types for which he knows the recipe will be displayed,
+and ones for which essences are lacking will be displayed in red. Objects
+whose level exceeds his own are sometimes difficult to create, though
+he can always add gold to improve the chances of his success.
+
+[[[[[BA few pointers:]
+ -Recipes are (usually) logical. Acid essences don't make Dragon
+ Weapons. And you can always look at the recipes you know with
+ the "recipe 'B'ook" command.
+ -Not all objects or ego-item types can be made using alchemy.
+ -Alchemy is mostly reversible. Most items that you can
+ 'E'xtract from, you can later re-create, if you learn about
+ them when extracting from them. You won't always get enough
+ essences from destroying an item to recreate it, though the
+ chance of doing so will get higher as you increase in skill.
+ -*Identifying* an object that you can destroy will always teach
+ you how to create it (if creating it is possible).
+ -Since you can't create abilities in artifacts that you aren't
+ aware of, make sure to *identify* all the artifacts you can.
+ -You can't *identify* things you buy in shops, so you'll have
+ to extract from them and take your chances.
+
+[[[[[BSome Recipes:]
+Any Alchemist worth his salt knows lots of recipes. By extracting from
+items in the dungeon, he learns to create more and more items. You can
+see the recipes you know using the "recipe 'B'ook" command. The Alchemist
+starts off knowing some basic recipes, and gains more recipes as time
+goes on.
+
+More details can be found in the *****essences.txt*0[Essences SPOILER]).
+
diff --git a/lib/help/c_archer.txt b/lib/help/c_archer.txt
new file mode 100644
index 00000000..a115e6f2
--- /dev/null
+++ b/lib/help/c_archer.txt
@@ -0,0 +1,68 @@
+~~~~~01|Archer
+~~~~~02|Classes|Archer
+#####R=== Archers ===
+
+#####GDescription
+Archers are to bows what warriors are to melee. They are the best class
+around with any bow/crossbow/sling/boomerang.
+
+Needing a lot of ammo, they will learn early how to make it from junk found
+in the dungeons. They also gain, at skill level 20, the unique ability to make
+their arrows/bolts/shots pierce through monsters!
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom +0
+Dexterity +2
+Constitution +1
+Charisma +1
+Hit Die +d4
+Spell Points +0%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.500]
+ Archery 1.000 [0.850]
+ Sling-mastery 0.000 [0.500]
+ Bow-mastery 0.000 [0.500]
+ Crossbow-mastery 0.000 [0.500]
+ Boomerang-mastery 0.000 [0.500]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 0.000 [0.200]
+ Magic-Device 1.000 [1.100]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Ammo creation 2
+
+#####GStarting Equipment
+An Archer begins the game with:
+ a Short Bow
+ a Sling
+ some ammo
+~~~~~03|Creating Ammo
+#####GCreating Ammo
+Archers automatically gain the *****ability.txt*07[Ammo Creation] ability when they reach character
+level 2. (Other classes can purchase this ability when they have enough skill
+points.) This ability is accessed via the 'm' command. The first type of
+ammo you can make is sling ammo (pebbles or shots); as you increase in skill
+you'll be able to make other arrows (bow ammo) or bolts (crossbow ammo).
+
+Shots (or other sling ammo) are created from rubble piles found in the dungeons
+and other places. To make shots, stand next to a rubble pile, activate the
+ammo creation ability from the 'm' menu, select 's'hots, then specify the
+direction to the rubble pile, which will be consumed during the ammo creation.
+Arrows or bolts are made from "junk" items ('~' symbol, such as shards of
+pottery) that you can find in the dungeons and other places. To make arrows or
+bolts, assuming you have sufficient Archery skill, you must have the junk item
+in your inventory or on the ground at your feet. Specify the junk item after
+selecting 'a'rrows or 'b'olts from the ammo creation menu, and it will be
+consumed and replaced with a stack of ammo.
diff --git a/lib/help/c_assass.txt b/lib/help/c_assass.txt
new file mode 100644
index 00000000..4269e3e8
--- /dev/null
+++ b/lib/help/c_assass.txt
@@ -0,0 +1,58 @@
+~~~~~01|Assassin
+~~~~~02|Classes|Assassin
+#####R=== Assassins ===
+#####GDescription
+Assassins are similar to Rogues, but have trained their combat abilities more
+extensively by neglecting the study of magic. They also tend to be more stealthy
+and careful in their dungeon exploration, but aren't so good at stealing,
+trapping and disarming as their more "peaceful" counterparts.
+
+Assassins have access to the schools of *****m_convey.txt*0[Conveyance], *****m_divin.txt*0[Divination] and *****m_tempo.txt*0[Temporal] magic.
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom -2
+Dexterity +3
+Constitution +1
+Charisma -1
+Hit Die +d6
+Spell Points +0%
+Exp Penalty 25%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.800]
+ Sword-mastery 1.000 [0.600]
+ Critical-hits 2.000 [0.800]
+ Archery
+ Boomerang-mastery 1.000 [0.300]
+Sneakiness 1.000 [2.000]
+ Stealth 1.000 [2.000]
+ Disarming 1.000 [1.000]
+ Backstab 1.000 [2.000]
+ Stealing 1.000 [0.200]
+ Dodging 1.000 [2.000]
+Magic 1.000 [0.200]
+ Magic-Device 1.000 [0.750]
+ Conveyance 0.000 [0.100]
+ Divination 0.000 [0.100]
+ Temporal 0.000 [0.200]
+Spirituality 1.000 [0.700]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*An Assassin cannot learn the Archery skill, but it is shown in his skill
+screen because Boomerang-mastery is a sub-skill of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 10
+
+#####GStarting Equipment
+An Assassin begins the game with:
+ a Dagger
+
+
+
diff --git a/lib/help/c_axemas.txt b/lib/help/c_axemas.txt
new file mode 100644
index 00000000..cdd6ba88
--- /dev/null
+++ b/lib/help/c_axemas.txt
@@ -0,0 +1,51 @@
+~~~~~01|Axemaster
+~~~~~02|Classes|Axemaster
+#####R=== Axemasters ===
+
+#####GDescription
+The Axemaster is a Warrior who specialises in axes.
+The training is so intense and specific that Axemasters gain huge bonuses
+when fighting with their chosen weapon, dependent on their Axe-mastery skill.
+In most other respects they perform about as well as a generic Warrior.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.900]
+ Weaponmastery 1.000 [0.950]
+ Sword-mastery 0.000 [0.300]
+ Axe-mastery 1.000 [0.700]
+ Hafted-mastery 0.000 [0.300]
+ Polearm-mastery 0.000 [0.300]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+An Axemaster begins the game with:
+ a Ring of Fear Resistance
+ a Chain Mail
+ a Hatchet
diff --git a/lib/help/c_bard.txt b/lib/help/c_bard.txt
new file mode 100644
index 00000000..23ba42ca
--- /dev/null
+++ b/lib/help/c_bard.txt
@@ -0,0 +1,69 @@
+|||||oy
+~~~~~01|Bard
+~~~~~02|Classes|Bard
+#####R=== Bards ===
+
+#####GDescription
+Bards are traditional musicians. Their magical attacks are sound-based, and
+last as long as the Bard has mana. If the Bard runs out of mana, he/she stops
+singing. There is also a low-level "spell" that will cease the song.
+
+While any class can use musical instruments, only Bards can tap the
+power of voice to aid themselves and hinder, dismay, and kill their
+foes.
+
+#####GMagic Usage
+
+Songs are continuous, and the song consumes mana every turn in order to
+maintain itself. The song will continue, once played, until either the 'Stop
+Singing' song is sung, or the player's mana runs out.
+
+Each song has a magic school level associated with, just as any other magic
+spell does. Each song also has a Roman numeral (e.g. I, II, III, IV, V)
+following its name. These numerals correspond to 1, 2, 3, 4, 5. The higher the
+numeral, the more music skill the Bard must have to play that song.
+
+Each musical instrument has a value between 1 and 4 assigned to it, as well.
+The higher the number, the better the craftmanship. A Bard can only play
+higher level songs with a more powerful instrument. You would be able to cast
+"Stop Singing (I)" and "Song of the Sun (I)" with a a Harp (+1). A Harp (+2)
+would allow you to sing those songs, as well as "Flow of Life (II)".
+
+For information on song effects see the *****m_music.txt*0[Music Songs] file.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Barehand-combat 1.000 [0.600]
+Sneakiness 1.000 [0.700]
+ Stealth 1.000 [0.700]
+ Disarming 1.000 [0.600]
+Magic 1.000 [0.600]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.800]
+ Prayer 0.000 [0.500]
+ Music 1.000 [0.800]
+Monster-lore 1.000 [1.100]
+ Summoning 0.000 [0.400]
+ Corpse-preservation 1.000 [0.700]
+ Symbiosis 0.000 [0.400]
+ Mimicry 0.000 [0.400]
+
+#####GStarting Equipment
+A Bard begins the game with:
+ a Harp (+1)
+ a Short Sword
+ a Robe
+ a Potion of Healing
diff --git a/lib/help/c_demono.txt b/lib/help/c_demono.txt
new file mode 100644
index 00000000..98b0bc9b
--- /dev/null
+++ b/lib/help/c_demono.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Demonologist
+~~~~~02|Classes|Demonologist
+#####R=== Demonologists ===
+
+#####GDescription
+Masters of the Demons, members of this class can gain tremendous power
+over demonkind, either for good or for evil ends.
+
+Their spells are contained in specific blades, shields and helms (actually
+shaped in the form of horns) which when wielded allow the Demonologist to
+cast spells unique to her class; each piece of equipment holds 3 spells.
+
+See the information on the *****m_demono.txt*0[Demonology] school of magic for more details.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.750]
+ Weaponmastery 1.000 [0.750]
+ Sword-mastery 0.000 [0.600]
+ Archery 2.000 [0.400]
+Sneakiness 2.000 [1.800]
+ Stealth 0.000 [0.400]
+ Disarming 2.000 [1.800]
+Magic 2.000 [0.700]
+ Magic-Device 1.000 [1.150]
+ Demonology 1.000 [1.000]
+Spirituality 2.000 [0.700]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+A Demonologist begins the game with:
+ a Ring of Fear Resistance
+ a Demonblade
+ a Chain Mail
+
diff --git a/lib/help/c_druid.txt b/lib/help/c_druid.txt
new file mode 100644
index 00000000..0b0493e2
--- /dev/null
+++ b/lib/help/c_druid.txt
@@ -0,0 +1,55 @@
+|||||oy
+~~~~~01|Druid
+~~~~~02|Classes|Druid
+~~~~~03|Yavanna|Druid
+#####R=== Druids ===
+
+#####GDescription
+When Melkor first dug up Utumno and Angband, rivers were polluted and gave
+birth to dark clouds of stinging insects; animals changed into dark, horrible
+horned things and the forests themselves screamed in horror at their corruption.
+
+*****g_yavann.txt*0[Yavanna] heard this scream and gave to some of the children of Eru the strength
+to defend Nature; at first Ents were chosen, but later on other races were
+allowed to tread the path of the Druid.
+
+The embodiment of life itself, a Druid is a true force of nature and nothing
+can prevent him from completing his final quest: returning Angband to the
+grassy sunlit plain it once was.
+
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.750]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.600]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 1.000 [1.200]
+ Summoning 1.000 [0.700]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Druid begins the game with:
+ a Spellbook of Charm Animal
+ a Mace
diff --git a/lib/help/c_geoman.txt b/lib/help/c_geoman.txt
new file mode 100644
index 00000000..47855875
--- /dev/null
+++ b/lib/help/c_geoman.txt
@@ -0,0 +1,59 @@
+|||||oy
+~~~~~01|Geomancer
+~~~~~02|Classes|Geomancer
+#####R=== Geomancers ===
+
+#####GDescription
+Geomancers harness the power of the elements earth, air, fire and water.
+The level of their *****skills.txt*60[Geomancy] skill gives them access to their own
+*****m_geoman.txt*0[school of Geomancy], but the levels of the Fire, Water, Air, and Earth
+skills will have an effect on the outcome of each spell.
+
+Geomancers need the aid of a Mage Staff in order to use their powers.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.200]
+ Weaponmastery 0.700 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 1.000 [0.700]
+ Geomancy 1.000 [0.700]
+ Fire 1.000 [1.050]
+ Water 1.000 [1.050]
+ Air 1.000 [1.050]
+ Earth 1.000 [1.050]
+ Meta 0.000 [0.700]
+ Conveyance 0.000 [0.700]
+ Divination 0.000 [0.700]
+ Temporal 0.000 [0.700]
+ Mind 0.000 [0.700]
+ Nature 0.000 [0.700]
+ Necromancy 0.000 [0.700]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Geomancer begins the game with:
+ a Spellbook of Geyser
+ a Mage Staff
diff --git a/lib/help/c_hafted.txt b/lib/help/c_hafted.txt
new file mode 100644
index 00000000..7e8a3f89
--- /dev/null
+++ b/lib/help/c_hafted.txt
@@ -0,0 +1,54 @@
+~~~~~01|Haftedmaster
+~~~~~02|Classes|Haftedmaster
+#####R=== Haftedmasters ===
+
+#####GDescription
+The Haftedmaster is a Warrior who specialises in blunt weapons.
+
+The training is so intense and specific that Haftedmasters gain huge bonuses
+when fighting with their chosen weapon, dependent on their *****skills.txt*06[Hafted-mastery] skill.
+
+In most other respects they perform about as well as a generic Warrior.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.900]
+ Weaponmastery 1.000 [0.950]
+ Sword-mastery 0.000 [0.300]
+ Axe-mastery 0.000 [0.300]
+ Hafted-mastery 1.000 [0.700]
+ Stunning-blows 0.000 [0.500]
+ Polearm-mastery 0.000 [0.300]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+An Haftedmaster begins the game with:
+ a Ring of Fear Resistance
+ a Chain Mail
+ a Flail
diff --git a/lib/help/c_lorema.txt b/lib/help/c_lorema.txt
new file mode 100644
index 00000000..35c2093b
--- /dev/null
+++ b/lib/help/c_lorema.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Loremaster
+~~~~~02|Classes|Loremaster
+#####R=== Loremasters ===
+
+#####GDescription
+Loremasters are students of the creatures of Arda.
+
+To protect themselves during their observations, they usually learn how to
+pass unobserved, but should their attempt fail they have decent saving throws
+and almost always learn some kind of combat style, but the exact preference
+varies from Loremaster to Loremaster.
+
+As a result of their studies, they become familiar with a broad range of
+skills, ranging from *****skills.txt*45[Possession] and *****m_symbio.txt*0[Symbiosis] to *****skills.txt*43[Summoning] and *****skills.txt*47[Mimicry].
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Archery 1.000 [0.700]
+ Barehand-combat 1.000 [0.700]
+Sneakiness 1.000 [0.700]
+ Stealth 1.000 [0.700]
+ Disarming 1.000 [0.700]
+Magic 0.000 [0.600]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.700]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Summoning 0.000 [0.500]
+ Corpse-preservation 1.000 [0.700]
+ Possession 0.000 [0.500]
+ Symbiosis 0.000 [0.500]
+ Mimicry 0.000 [0.500]
+
+#####GStarting Equipment
+A Loremaster begins the game with:
+ a Sling
+ a Hard Leather Armour
+ a Quarterstaff
+ some Rounded Pebbles
diff --git a/lib/help/c_mage.txt b/lib/help/c_mage.txt
new file mode 100644
index 00000000..949d3bcc
--- /dev/null
+++ b/lib/help/c_mage.txt
@@ -0,0 +1,67 @@
+|||||oy
+~~~~~01|Mage
+~~~~~02|Classes|Mage
+#####R=== Mages ===
+
+#####GDescription
+A Mage must live by his wits. He cannot hope to simply hack his way
+through the dungeon, and so must therefore use his magic to defeat,
+deceive, confuse, and escape. A Mage is not really complete without an
+assortment of magical devices to use in addition to his spells. He can
+master the higher level magical devices easily and has good saving throws.
+
+There is no reason a Mage cannot become a good fighter, but spells are
+his true realm. For more information on magic schools and spell effects see
+the *****magic.txt*01[Magic help file].
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.500]
+ Weaponmastery 0.700 [0.500]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.200]
+ Spell-power 0.000 [0.600]
+ Sorcery 0.000 [0.200]
+ Mana 1.000 [0.900]
+ Geomancy
+ Fire 0.000 [0.900]
+ Water 0.000 [0.900]
+ Air 0.000 [0.900]
+ Earth 0.000 [0.900]
+ Meta 0.000 [0.900]
+ Conveyance 0.000 [0.900]
+ Divination 0.000 [0.900]
+ Temporal 0.000 [0.900]
+ Mind 0.000 [0.900]
+ Nature 0.000 [0.900]
+ Necromancy 0.000 [0.700]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Mage cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Mage begins the game with:
+ a Book of Beginner Cantrips
+ a Dagger
diff --git a/lib/help/c_merch.txt b/lib/help/c_merch.txt
new file mode 100644
index 00000000..31fb60dd
--- /dev/null
+++ b/lib/help/c_merch.txt
@@ -0,0 +1,29 @@
+#####R=== Merchants ===
+
+#####GDescription
+A Merchant is neither a warrior nor a spellcaster. They still have some great
+advantages, they can use chests to warp items into other items, they can
+indentify items, they soon learn to detect all objects in the area, and
+at higher level they can see all monsters carrying objects. They will also
+get the power to appraise items and to turn them into gold. A merchant will
+naturraly get better prices in shops and get access to the merchant guild
+services, loan and item request.
+
+#####GPrimary Stats
+Charisma
+Intelligence (Ability stat)
+
+#####GMagic Usage
+Merchants can use portable holes to carry more stuff than other classes but
+at the cost of an increased weight. To do that they must wear a portable hole
+and use it with 'm'.
+They also can use their merchants abilities and midas touch in the 'U' menu.
+
+#####GStarting Equipment
+A merchant begins the game with:
+ A portable hole
+ A small steel chest containing gold and items
+ A long sword
+ A wand of tame monsters
+
+
diff --git a/lib/help/c_mimic.txt b/lib/help/c_mimic.txt
new file mode 100644
index 00000000..b9378a03
--- /dev/null
+++ b/lib/help/c_mimic.txt
@@ -0,0 +1,53 @@
+~~~~~01|Mimic
+~~~~~02|Classes|Mimic
+#####R=== Mimics ===
+
+#####GDescription
+Mimics possess the ability to transform into various creatures using
+special cloaks. While transformed, they lose their intrinsic abilities,
+and gain those of the creature they have transformed into.
+
+At higher skill levels, Mimics gain additional Mimicry powers which help them
+to further blend in with their surroundings or modify themselves.
+
+See more on *****m_mimic.txt*0[Mimicry powers].
+
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.800]
+ Archery 1.000 [0.700]
+ Barehand-combat 1.000 [0.600]
+Sneakiness 1.000 [0.800]
+ Stealth 1.000 [0.800]
+ Disarming 1.000 [0.700]
+Magic 1.000 [0.700]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.500]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 1.000 [0.900]
+ Possession 0.000 [0.100]
+ Mimicry 1.000 [0.800]
+
+#####GStarting Equipment
+A Mimic begins the game with:
+ a Mouse Fur
+ a Potion of Healing
+ a Dagger
+
+
+
diff --git a/lib/help/c_mindcr.txt b/lib/help/c_mindcr.txt
new file mode 100644
index 00000000..c4ed2747
--- /dev/null
+++ b/lib/help/c_mindcr.txt
@@ -0,0 +1,57 @@
+|||||oy
+~~~~~01|Mindcrafter
+~~~~~02|Classes|Mindcrafter
+#####R=== Mindcrafters ===
+
+#####GDescription
+The Mindcrafter is a priest who uses the powers of mind instead of magic.
+These abilities vary from simple extrasensory perception to mental domination of
+others. Since these powers are developed by the practice of certain
+disciplines, a Mindcrafter requires no spellbooks to use them.
+The Mindcrafter uses the Mindcraft skill to determine how well she can
+perform these psychic "spells", and available powers are simply determined by
+the skill level. In combat a Mindcrafter is roughly the equivalent of a
+priest.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+Sneakiness 1.000 [1.100]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.150]
+ Spell-power 0.000 [0.600]
+ Necromancy 0.000 [0.400]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [0.900]
+ Mindcraft 1.000 [0.900]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GMindcraft Powers
+Although the powers of a Mindcrafter may seem like magic, this is not
+-- strictly speaking -- the case. They are mental powers, independent
+of the ordinary sources of magic. Consequently, Mindcrafters are not
+interested in 'magic' and learn no spells. These mental powers can be
+accessed through the "m" command, and you can find a full list of their
+powers in the *****m_mindcr.txt*0[Mindcraft powers] document.
+
+#####GStarting Equipment
+A Mindcrafter begins the game with:
+ a Mace
diff --git a/lib/help/c_monk.txt b/lib/help/c_monk.txt
new file mode 100644
index 00000000..87730f18
--- /dev/null
+++ b/lib/help/c_monk.txt
@@ -0,0 +1,87 @@
+|||||oy
+~~~~~01|Monk
+~~~~~02|Classes|Monk
+#####R=== Monks ===
+
+#####GDescription
+The Monk character class is very different from all other classes.
+Although they can use weapons and armour just like any other class,
+their training in martial arts makes them much more powerful with no
+armour nor weapons.
+
+As the Monk's skill level rises, new and more powerful forms of attack become
+available. It is also rumoured that the monastic training makes experienced
+monks faster than any other character class!
+
+A Monk might need to wear some kind of armour to gain the resistances necessary
+for survival at higher levels, but if that armour is too heavy, it will
+severely disturb his/her martial arts maneuvers.
+
+If skill points are invested in *****skills.txt*20[Dodging], a Monk's defensive capabilities
+(blocking and dodging) will also increase. However, if armour is being worn,
+dodging is much less effective. Fortunately, a Monk can increase his/her
+ability to fight while still wearing armor by increasing his/her
+*****skills.txt*13[Barehanded-combat] skill.
+
+Monks also have access to the schools of *****m_meta.txt*0[Meta],
+*****m_tempo.txt*0[Temporal] and *****m_mind.txt*0[Mind] magic.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 0.000 [0.900]
+ Weaponmastery 0.000 [0.300]
+ Archery 0.000 [0.400]
+ Barehand-combat 1.000 [0.900]
+Sneakiness 1.000 [0.900]
+ Stealth 1.000 [0.900]
+ Disarming 1.000 [0.900]
+ Dodging 0.000 [0.700]
+Magic 0.000 [0.600]
+ Magic-Device 1.000 [1.000]
+ Meta 0.000 [0.500]
+ Temporal 0.000 [0.500]
+ Mind 0.000 [0.500]
+Spirituality 1.000 [0.900]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 1.000 [0.500]
+ Possession 0.000 [0.100]
+
+#####GStarting Equipment
+A Monk begins the game with:
+ a Potion of Healing
+ a Soft Leather Armour
+~~~~~03|Monk|Monk attacks
+~~~~~04|Tables|Monk attacks
+#####GMonk Attacks
+#####BAttack Name Min.lvl Damage Stun Notes
+-----------------------------------------------------------------------------
+Punch 1 1d4 -
+Kick 2 1d6 -
+Strike 3 1d7 -
+Knee 5 2d3 * Painful to males; likely to stun them
+Elbow 7 1d8 -
+Butt 9 2d5 -
+Ankle Kick 11 3d4 - May slow down the opponent
+Uppercut 13 4d4 6
+Double-kick 16 5d4 8
+Cat's Claw 20 5d5 -
+Jump Kick 25 5d6 10
+Eagle's Claw 29 6d6 -
+Circle Kick 33 6d8 10
+Iron Fist 37 8d8 10
+Flying Kick 41 8d10 12
+Dragon Fist 45 10d10 16
+Crushing Blow 48 10d12 18
diff --git a/lib/help/c_necro.txt b/lib/help/c_necro.txt
new file mode 100644
index 00000000..f3a5ad2c
--- /dev/null
+++ b/lib/help/c_necro.txt
@@ -0,0 +1,80 @@
+|||||oy
+~~~~~01|Necromancer
+~~~~~02|Classes|Necromancer
+#####R=== Necromancers ===
+
+#####GDescription
+As a Priest devotes his life to his chosen deity, so Necromancers
+devote their lives to the study of death. Familiar with all of the
+forms of unbeing, they are able to manipulate spirit and flesh for
+great effect.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.400]
+ Weaponmastery 0.700 [0.600]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.200]
+ Spell-power 0.000 [0.600]
+ Mana 0.000 [0.600]
+ Geomancy
+ Fire 0.000 [0.800]
+ Water 0.000 [0.700]
+ Air 0.000 [0.700]
+ Earth 0.000 [0.800]
+ Meta 0.000 [0.700]
+ Conveyance 0.000 [0.700]
+ Divination 0.000 [0.700]
+ Temporal 0.000 [0.800]
+ Mind 0.000 [0.900]
+ Nature 0.000 [0.500]
+ Necromancy 1.000 [1.000]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 5.000 [0.900]
+
+*A Necromancer cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+Undead Form 25
+
+#####GStarting Equipment
+A Necromancer begins the game with:
+ a Book of Beginner Cantrips
+ a Dagger
+
+#####GNecromancy
+*****m_necrom.txt*0[Necromancy powers] [[[[[Bare accessed using the 'm' key.]
+Even from the start of his career, an inexperienced Necromancer
+can channel forces from the underworld to assault the mind of
+living creatures, therefore terrifying them. With little effort he
+can also learn the art of reanimating a dead corpse, turning it into
+an undead slave. It is only at a later point in his career that this
+foul mage learns to manipulate his life force as well, gaining the
+ability to absorb hit points from both living and dead opponents.
+The greatest Necromancers even gain the ability to survive their own
+death: when they should be killed, they instead turn into a ghostly
+being; they then receive a set number of Death Points, which are in
+all respects similar to hit points except that they go automatically
+down each turn. If the Necromancer manages to kill a certain number
+of creatures before his Death Points reach 0 he is returned to life;
+otherwise his will dissipates and he finally achieves true death.
diff --git a/lib/help/c_palad.txt b/lib/help/c_palad.txt
new file mode 100644
index 00000000..b4cc650b
--- /dev/null
+++ b/lib/help/c_palad.txt
@@ -0,0 +1,49 @@
+|||||oy
+~~~~~01|Paladin
+~~~~~02|Classes|Paladin
+~~~~~03|Tulkas|Paladin
+#####R=== Paladins ===
+
+#####GDescription
+A Paladin is a warrior-priest at the service of *****g_tulkas.txt*0[Tulkas]. As such, his duty
+is to be ever vigilant against the forces of evil and even seek and destroy
+those monsters which are evil to the core, especially the foulest
+spawns of hell. Luckily, his quest is eased by the blessing bestowed
+by Tulkas himself.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.800]
+ Weaponmastery 1.000 [0.800]
+ Barehand-combat 0.000 [0.900]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.600]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.400]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+Extra Max Blow(1) 1
+
+#####GStarting Equipment
+A Paladin begins the game with:
+ a Spellbook of Divine Aim
+ a Two-Handed Sword
diff --git a/lib/help/c_polear.txt b/lib/help/c_polear.txt
new file mode 100644
index 00000000..8ea2f04a
--- /dev/null
+++ b/lib/help/c_polear.txt
@@ -0,0 +1,52 @@
+~~~~~01|Polearmmaster
+~~~~~02|Classes|Polearmmaster
+#####R=== Polearmmasters ===
+
+#####GDescription
+The Polearmmaster is a Warrior who specialises in polearms.
+
+The training is so intense and specific that Polearmmasters gain huge bonuses
+when fighting with their chosen weapon, dependent on their Polearm-mastery
+skill. In most other respects they perform about as well as a generic Warrior.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.900]
+ Weaponmastery 1.000 [0.950]
+ Sword-mastery 0.000 [0.300]
+ Axe-mastery 0.000 [0.300]
+ Hafted-mastery 0.000 [0.300]
+ Polearm-mastery 1.000 [0.700]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+A Polearmmaster begins the game with:
+ a Ring of Fear Resistance
+ a Chain Mail
+ a Pike
diff --git a/lib/help/c_posses.txt b/lib/help/c_posses.txt
new file mode 100644
index 00000000..2d67a883
--- /dev/null
+++ b/lib/help/c_posses.txt
@@ -0,0 +1,70 @@
+~~~~~01|Possessor
+~~~~~02|Classes|Possessor
+#####R=== Possessors ===
+
+#####GDescription
+Possessors are unusual; they aren't good fighters, and they can't cast
+magic. Their special ability is that of being able to leave their
+bodies and inhabit corpses. While "in" a corpse, the Possessor gains
+the abilities of the monster, and their hit points and the monster's
+are averaged. (Most monsters have no, or very few, spell points.) While
+in the incorporeal form between bodies, they have only one hitpoint.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.600]
+ Weaponmastery 1.000 [0.600]
+ Archery 1.000 [0.400]
+Sneakiness 1.000 [0.700]
+ Stealth 1.000 [0.700]
+ Disarming 1.000 [0.500]
+Magic 0.000 [0.600]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.500]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 1.000 [0.900]
+ Possession 1.000 [0.800]
+
+#####GStarting Equipment
+A Possessor begins the game with:
+ a Potion of Healing
+ a Short Sword
+ a Hard Leather Armour
+
+~~~~~03|Possessor|Possessor powers
+~~~~~04|Skills|Possession - Possessor powers
+#####GPossession
+The strange art of reanimating the corpse of a monster and making
+it one's own can be of extreme benefit to those skilled in it. The body
+the player possesses can grant powerful abilities, such as increased
+speed, summoning, healing, breathing, and various resistances, and often
+gives the player a large number of hit points. Possessing uniques is
+especially neat.
+
+Possessors leave their own body by using the 'm' command, and choosing
+"[I]incarnating powers". Lacking a life force to sustain it, a corpse may rot
+immediately when a Possessor leaves it, but a high Possession skill score
+may prevent this from happening. They then become a very vulnerable ghostly
+being which travels to where another corpse is lying on the floor, and
+possesses it by again using the 'm' command. Once possessed, many
+monster corpses allow the player to perform various special actions
+(such as blinking or summoning) by using the option "Use your [R]ace
+powers".
+
+All corpses alter the player's melee attacks. When they incarnate in a
+monster that allows the use of a weapon, monster blows are ignored
+[[[[[Btotally]. When they incarnate in a monster that doesn't allow use of a
+weapon (dragons for example) they use the monster blows [[[[[Band only them]!
diff --git a/lib/help/c_pr_drk.txt b/lib/help/c_pr_drk.txt
new file mode 100644
index 00000000..fa99f89f
--- /dev/null
+++ b/lib/help/c_pr_drk.txt
@@ -0,0 +1,57 @@
+|||||oy
+~~~~~01|Dark Priest
+~~~~~02|Classes|Dark Priest
+~~~~~03|Melkor|Dark Priests
+#####R=== Melkor's Priests ===
+
+#####GDescription
+All gods have priests; but those serving *****g_melkor.txt*0[Melkor], the dark enemy, are not
+like their good counterparts. While usually it takes devotion and awe to be
+inspired into serving a deity, Melkor's followers revere him because of the
+power he gives them. Some of them may even be so ambitious as to aspire to
+take his place upon the black throne of Angband. This he knows very well, but
+as long as he can use those puny mortals to inspire fear into the followers of
+the Valar and to bring destruction to Arda, he doesn't mind; he even lends power
+to the ones more bent on destruction, while sapping their minds to reduce them
+to unthinking slaves.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.800]
+**Udun 0.000 [0.400]
+ Necromancy 0.000 [0.800]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.400]
+Monster-lore 0.000 [0.500]
+ Corpse-preservation 1.000 [1.000]
+
+**Actually, every character has this level of proficiency with the *****m_udun.txt*0[Udun] school,
+provided they are worshipping Melkor
+
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Priest serving Melkor begins the game with:
+ a Spellbook of Curse
+ a Mace
diff --git a/lib/help/c_pr_eru.txt b/lib/help/c_pr_eru.txt
new file mode 100644
index 00000000..ff5a0126
--- /dev/null
+++ b/lib/help/c_pr_eru.txt
@@ -0,0 +1,55 @@
+|||||oy
+~~~~~01|Priest - Eru
+~~~~~02|Classes|Priest - Eru
+~~~~~03|Eru|Priest - Eru
+#####R=== Eru's Priests ===
+
+#####GDescription
+*****g_eru.txt*0[Eru] is the father of the Valar: he created the world and all its inhabitants. He is the wisest being ever and even if he foresaw Morgoth's
+evil, his role was that of the creator; as such, he chose not to destroy
+anything on Arda.
+
+His priests are therefore expected to avoid all forms of bloodshed (so they
+can only use blunt weapons without penalty); however, Eru knows that sometimes
+destruction is unavoidable and marks a blade with his rune; his priests call
+them Blessed and use them without feeling guilty, for they know that divine
+wisdom will guide every swing of those weapons.
+
+Still, a priest serving Eru will find that his true strength lies in knowledge
+and in the use of the force of Mana to avoid close contact with evil beings,
+rather than in blind assault of Morgoth's hordes.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.700]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Priest serving Eru begins the game with:
+ a Spellbook of See the Music
+ a Mace
diff --git a/lib/help/c_pr_man.txt b/lib/help/c_pr_man.txt
new file mode 100644
index 00000000..3f83e8af
--- /dev/null
+++ b/lib/help/c_pr_man.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Priest - Manwe
+~~~~~02|Classes|Priest - Manwe
+~~~~~03|Manwe|Priest - Manwe
+#####R=== Manwe's Priests ===
+
+#####GDescription
+As the forces of darkness arose, *****g_manwe.txt*0[Manwe], lord of air, realised that urgent
+action was needed to save Arda from the incoming darkness. So he started
+gathering followers from the ranks of men and elves and he instructed them to
+do battle against the forces of Udun.
+
+His priests must be quick and strike before the situation becomes
+critical, always keeping a direct line of prayer with their patron deity.
+
+Manwe doesn't tolerate laziness, but He also does not appreciate mindless
+killing; only a few measure up to his standards, but those are granted access
+to a whole series of divine powers which will help them in their enduring
+efforts.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.750]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.600]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Priest serving Manwe begins the game with:
+ a Spellbook of Manwe's Blessing
+ a Mace
diff --git a/lib/help/c_priest.txt b/lib/help/c_priest.txt
new file mode 100644
index 00000000..2054fbe5
--- /dev/null
+++ b/lib/help/c_priest.txt
@@ -0,0 +1,13 @@
+|||||oy
+~~~~~01|Priests
+#####R=== Priests ===
+
+#####GDescription
+There are 6 separate classes of Priest:
+
+*****c_pr_eru.txt*0[Priest(Eru)]
+*****c_pr_man.txt*0[Priest(Manwe)]
+*****c_druid.txt*0[Druid]
+*****c_palad.txt*0[Paladin]
+*****c_pr_drk.txt*0[Dark-Priest]
+*****c_mindcr.txt*0[Mindcrafter]
diff --git a/lib/help/c_ranger.txt b/lib/help/c_ranger.txt
new file mode 100644
index 00000000..ad3b4843
--- /dev/null
+++ b/lib/help/c_ranger.txt
@@ -0,0 +1,55 @@
+|||||oy
+~~~~~01|Ranger
+~~~~~02|Classes|Ranger
+#####R=== Rangers ===
+
+#####GDescription
+Rangers are warrior-mages, devoted to nature. They are good fighters
+and quite effective with bows; their magic often allows them to avoid
+the worst of situations, but they have only a mild chance of resisting
+magical effects and are not terribly stealthy.
+
+They have access to the schools of *****m_divin.txt*0[Divination], *****m_convey.txt*0[Conveyance] and *****m_nature.txt*0[Nature] magic.
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom +0
+Dexterity +2
+Constitution +1
+Charisma +1
+Hit Die +d4
+Spell Points +0%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.500]
+ Archery 1.000 [0.750]
+ Sling-mastery 0.000 [0.300]
+ Bow-mastery 0.000 [0.300]
+ Crossbow-mastery 0.000 [0.300]
+ Boomerang-mastery 0.000 [0.300]
+Sneakiness 1.000 [0.950]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [1.600]
+Magic 1.000 [0.700]
+ Magic-Device 1.000 [1.100]
+ Conveyance 0.000 [0.500]
+ Divination 0.000 [0.500]
+ Nature 0.000 [0.500]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.700]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Ammo creation 2
+
+#####GStarting Equipment
+A Ranger begins the game with:
+ a Spellbook of Phase Door
+ a Short Sword
+ a Short Bow
+ some Arrows
diff --git a/lib/help/c_rogue.txt b/lib/help/c_rogue.txt
new file mode 100644
index 00000000..b42df3d5
--- /dev/null
+++ b/lib/help/c_rogue.txt
@@ -0,0 +1,62 @@
+|||||oy
+~~~~~01|Rogue
+~~~~~02|Classes|Rogue
+#####R== Rogues ===
+
+#####GDescription
+A rogue is a jack of all trades, but the master of none. With the notable
+exception of Archery and Monster-related skills, Rogues are capable of adapting
+to almost any situation. Their strong point lies in stealth and careful
+planning: Where a Warrior would simply hack away (and risk being hacked up
+himself) or a Mage would Manathrust, a Rogue would awaken a monster with a
+dagger in the back, or would wait for the creature to be killed by the line of
+traps she had previously laid between her and her opponent.
+
+Rogues have access to the schools of *****m_convey.txt*0[Conveyance], *****m_divin.txt*0[Divination] and *****m_tempo.txt*0[Temporal] magic.
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom -2
+Dexterity +3
+Constitution +1
+Charisma -1
+Hit Die +d6
+Spell Points +0%
+Exp Penalty 25%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Sword-mastery 1.000 [0.300]
+ Critical-hits 1.000 [0.500]
+Sneakiness 1.000 [2.000]
+ Stealth 1.000 [1.500]
+ Disarming 1.000 [2.000]
+ Backstab 1.000 [1.000]
+ Stealing 1.000 [2.000]
+ Dodging 1.000 [2.000]
+Magic 1.000 [0.700]
+ Magic-Device 1.000 [1.550]
+ Conveyance 0.000 [0.500]
+ Divination 0.000 [0.500]
+ Temporal 0.000 [0.500]
+Spirituality 1.000 [0.700]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Trapping 1
+Extra Max Blow(1) 10
+
+#####GStarting Equipment
+A Rogue begins the game with:
+ a Dagger
+ a Catapult Trap Set
+ some Iron Shots
+
+
+
+
diff --git a/lib/help/c_runecr.txt b/lib/help/c_runecr.txt
new file mode 100644
index 00000000..8388eff9
--- /dev/null
+++ b/lib/help/c_runecr.txt
@@ -0,0 +1,110 @@
+~~~~~01|Runecrafter
+~~~~~02|Classes|Runecrafter
+#####R=== Runecrafters ===
+
+#####GDescription
+Instead of using spellbooks like the other spellcasters they instead
+use mystic runes. To cast a spell they select a primary rune of the
+elements (fire, cold, etc.) and they also choose a set of secondary runes,
+which shape the effect of the first one. The secondary runes include
+Self, Arrow, Ray, ... and Armageddon. After that they chose the amount
+of mana to use and the spell is cast! But the more secondary runes they
+chose the more mana is used to cast the spell. They also are bad
+fighters, but if they concentrate all their mana in one spell
+(especially with a mage staff of mana) they could kill nearly anything.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.200]
+ Weaponmastery 0.700 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 2.000 [0.950]
+ Magic-Device 1.000 [1.200]
+ Spell-power 0.000 [0.600]
+ Mana 1.000 [0.600]
+ Geomancy
+ Fire 0.000 [0.700]
+ Water 0.000 [0.700]
+ Air 0.000 [0.700]
+ Earth 0.000 [0.700]
+ Meta 0.000 [0.700]
+ Conveyance 0.000 [0.700]
+ Divination 0.000 [0.700]
+ Temporal 0.000 [0.700]
+ Mind 0.000 [0.700]
+ Nature 0.000 [0.700]
+ Necromancy 0.000 [0.700]
+ Runecraft 1.000 [1.000]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Runecrafter cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+~~~~~03|Runecrafter|Runecrafter powers
+~~~~~04|Skills|Runecrafting - Runecrafter powers
+#####GRune Magic
+Runecrafters combine runes using the 'm' command. They first select a
+rune that controls magic type, then apply one or more runes to fine-tune
+effects, (pressing ESC when done), and then input the amount of mana
+they wish to expend on the spell.
+
+Runecrafters can cast the spells from their runes in several ways:
+1. On-the-fly by combining runes when they need them.
+2. Memorise rune combinations for quick use when needed (and they don't
+ need to be able to see then!), and then later cast from memory.
+3. Carving them into a Runestone, then using the Runestone later (takes
+ less mana, but they have to be able to see).
+
+[[[[[BSpell Types:]
+(Some kinds are not listed, and are left for the reader to discover...)
+ Knowledge: Identify all objects in affected grids, Self-knowledge
+ if Self rune is used.
+ Life: Heals monsters in affected grids, heals player if Self rune
+ is used.
+ Fire, Cold, Lightning, Acid: Casts magics of that element.
+ Elements: Irresistible damage.
+ Mind: A mind blast that badly effects intelligent monsters.
+ Temporary ESP if Self rune is used.
+ Gravity: A gravity spell that both does damage and whisks affected
+ creatures around.
+
+[[[[[BSpell Effects] (all are listed):
+ Self: Effects the caster. This rune can be used with any other;
+ if used alone, only the caster's grid is affected.
+ Arrow: Spell will include a bolt effect. This allows aiming.
+ Ray: Spell will include a beam effect. This allows aiming.
+ Increases difficulty slightly.
+ Sphere: Spell will end with a circular explosion. Increases
+ difficulty a bit. Can be used alone, or with Self, Arrow, or
+ Ray.
+ Power Surge: Not currently recommended for use. Increases
+ difficulty a lot.
+ Armageddon: Hurls down meteors of the magical type in the vicinity
+ of the caster. Increases difficulty noticeably, but can do a
+ great deal of damage.
+
+#####GStarting Equipment
+A Runecrafter begins the game with:
+ a Rune [Fire]
+ a Rune [Arrow]
+ a Dagger
+
diff --git a/lib/help/c_sorcer.txt b/lib/help/c_sorcer.txt
new file mode 100644
index 00000000..8a33184f
--- /dev/null
+++ b/lib/help/c_sorcer.txt
@@ -0,0 +1,68 @@
+|||||oy
+~~~~~01|Sorceror
+~~~~~02|Classes|Sorceror
+#####R=== Sorcerors ===
+
+#####GDescription
+Sorcerors are to magic what Unbelievers are to melee. They are the all-
+around best magicians, being able to cast spells from any school using
+only a single skill. They cannot comfortably use any weapon but a Mage Staff, and even with a Mage Staff, they will be unable to achieve anything remotely resembling battle effectiveness.
+
+The energies used for learning Sorcery also sap the life force of a
+Sorceror, penalising them with the loss of a percentage of their hit
+points equal to their Sorcery skill score and penalising their combat
+ability even more strongly.
+
+For more information on magic schools and spell effects see the
+*****magic.txt*01[Magic help file].
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [1.000]
+ Magic-Device 1.000 [1.000]
+ Spell-power 0.000 [0.600]
+ Sorcery 1.000 [0.700]
+ Mana 0.000 [0.900]
+ Geomancy
+ Fire 0.000 [1.000]
+ Water 0.000 [1.000]
+ Air 0.000 [1.000]
+ Earth 0.000 [1.000]
+ Meta 0.000 [1.000]
+ Conveyance 0.000 [1.000]
+ Divination 0.000 [1.000]
+ Temporal 0.000 [1.000]
+ Mind 0.000 [1.000]
+ Nature 0.000 [1.000]
+ Necromancy 0.000 [1.000]
+ Runecraft 0.000 [0.900]
+ Thaumaturgy 0.000 [0.900]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Sorceror cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Sorceror begins the game with:
+ a Book of Beginner Cantrips
+ a Robe
+
diff --git a/lib/help/c_summon.txt b/lib/help/c_summon.txt
new file mode 100644
index 00000000..a3eca1de
--- /dev/null
+++ b/lib/help/c_summon.txt
@@ -0,0 +1,80 @@
+~~~~~01|Summoners
+~~~~~02|Classes|Summoners
+#####R=== Summoners ===
+
+#####GDescription
+A Summoner is, with one exception, a fairly weak class. While he starts
+out a decent enough fighter, his fighting skill doesn't improve that much,
+he doesn't cast magic and has little in the way of survival skills. However,
+this weakness doesn't trouble him much, because he can summon creatures to
+do his bidding and still gain experience from their kills.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution 0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.600]
+ Weaponmastery 1.000 [0.600]
+ Archery 1.000 [0.400]
+Sneakiness 1.000 [0.700]
+ Stealth 1.000 [0.700]
+ Disarming 1.000 [0.500]
+Magic 1.000 [0.800]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.500]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 16.000 [1.200]
+ Summoning 1.000 [0.700]
+ Corpse-preservation 1.000 [1.000]
+
+#####GStarting Equipment
+A Summoner starts the game with:
+ A Potion of Healing
+ A Short Sword
+ A Suit of Hard Leather Armour
+~~~~~03|Summoners|Summoning
+~~~~~04|Skills|Summoning - Summoning powers
+#####GSummoning
+[[[[[BThe summoner's powers of invocation are accessed using the 'm' key.]
+In order to invoke a monster, a summoner must possess a related totem.
+
+There are two kinds of summoning, decided by the totem used:
+
+[[[[[BPartial Summoning]
+Partial summoning creates a simulacrum of the monster, with little will
+of its own. The Summoner must maintain the simulacrum using mana; when
+he runs out, or stops paying the mana, the simulacrum vanishes.
+
+[[[[[BTrue Summoning]
+True summoning is quite different in effect from Partial Summoning, but the
+two are closely related in usage. A True Totem conjures a full copy of the
+creature in question; the process tends to make the monster a loyal ally to
+the summoner, but this loyalty is not guaranteed, nor is the survival of the
+totem used in the summoning.
+
+[[[[[BTotem Creation]
+In order to summon any creature, the Summoner needs a totem. Totems cannot be
+found; they must be created through a special process which involves taking
+the corpse of a creature (the summoner need not have been involved in the
+death of the creature in question), and extracting certain essences from it.
+
+The summoner can create a totem using the 'm' command, and unless one is
+working on a unique's corpse, must choose whether the resulting totem is a
+Partial or True Totem.
+
+[[[[[BImportant Note]
+Uniques are very willful creatures by definition, and thus have three special
+rules about their summoning:
+1. No partial totem can be made from a unique's corpse.
+2. The totem in question is always destroyed.
+3. The unique is twice as likely to be disloyal.
diff --git a/lib/help/c_swordm.txt b/lib/help/c_swordm.txt
new file mode 100644
index 00000000..a3b5ed05
--- /dev/null
+++ b/lib/help/c_swordm.txt
@@ -0,0 +1,52 @@
+~~~~~01|Swordmasters
+~~~~~02|Classes|Swordmasters
+#####R=== Swordmasters ===
+
+#####GDescription
+The Swordmaster is a Warrior who specialises in swords.
+
+The training is so intense and specific that Swordmasters gain huge bonuses
+when fighting with their chosen weapon, dependent on their Sword-mastery skill.
+In most other respects they perform about as well as a generic Warrior.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.900]
+ Weaponmastery 1.000 [0.950]
+ Sword-mastery 1.000 [0.700]
+ Axe-mastery 0.000 [0.300]
+ Hafted-mastery 0.000 [0.300]
+ Polearm-mastery 0.000 [0.300]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread-blows 25
+
+#####GStarting Equipment
+A Swordmaster begins the game with:
+ a Ring of Fear Resistance
+ a Chain Mail
+ a Broad Sword
diff --git a/lib/help/c_symbia.txt b/lib/help/c_symbia.txt
new file mode 100644
index 00000000..9bbd92fd
--- /dev/null
+++ b/lib/help/c_symbia.txt
@@ -0,0 +1,68 @@
+|||||oy
+~~~~~01|Symbiant
+~~~~~02|Classes|Symbiant
+#####R=== Symbiants ===
+
+#####GDescription
+Symbiants live in harmony with all of the monsters that do not move:
+the Mushrooms, Molds, Floating Eyes, and such. They can hypnotise these
+creatures and then form a symbiotic relationship. Using other symbiotic
+powers, they can even use the magical abilities of their pets.
+
+Once hypnotised, the monster is placed onto the body, or "worn" in order to
+initiate the symbiotic relationship.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution 0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.800]
+ Archery 1.000 [0.700]
+ Barehand-combat 1.000 [0.600]
+Sneakiness 1.000 [0.800]
+ Stealth 1.000 [0.800]
+ Disarming 1.000 [0.700]
+Magic 1.000 [0.700]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.500]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 1.000 [0.900]
+ Possession 0.000 [0.100]
+ Symbiosis 1.000 [0.800]
+
+#####GStarting Equipment
+A Symbiant begins the game with:
+ a Dagger
+ a Scroll of Summon Never-Moving Pet
+
+
+#####GSymbiosis
+Symbiants rely on the partnerships they form, hypnotising creatures
+and then "wearing" them: "I get by with a little help from my friends".
+Depending on the monster, this does nothing except protect the player
+slightly (the worn monster takes some of the damage the player would
+otherwise) or grant some very powerful attacks and summons.
+Their "spells" are used by the 'm' command; as their Symbiosis skill
+increases, they automatically gain more powers.
+For more detail about the specific powers, look here: *****m_symbio.txt*0[Symbiosis]
+~~~~~03|Symbiant|Naming your symbiote
+#####GNaming your symbiote
+For those sentimental Symbiants who like to name your symbiotes, you
+can use the Inscribe command '{'. Inscribe your hypnotized symbiote
+with "#named Fido" (or whatever name you choose, but don't forget the
+leading '#'), and it will be listed in your equipment as "a Red Mold
+named Fido", and the game will refer to your symbiote by name ("Fido
+is healed", for instance, rather than "Your Red mold is healed").
+
diff --git a/lib/help/c_thaum.txt b/lib/help/c_thaum.txt
new file mode 100644
index 00000000..653e84fa
--- /dev/null
+++ b/lib/help/c_thaum.txt
@@ -0,0 +1,84 @@
+~~~~~01|Thaumaturgist
+~~~~~02|Classes|Thaumaturgy
+#####R=== Thaumaturgists ===
+
+#####GDescription
+A Thaumaturgist is a Mage that prefers chaos to order. As such, they tend to
+learn random spells, and since attacking something creates more chaos than
+anything else, every spell they learn is an attack spell. They have no need
+for spell-books, as they harness the spells from within themselves. However,
+they also have no ability to improve the power of a particular spell - once
+learnt it will remain at the same strength for ever. Likewise, they also have
+no ability to control what they learn, and some of their spells will cause
+them damage (like darkness spells blinding them if they do not resist
+darkness).
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.200]
+ Weaponmastery 0.700 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 3.000 [0.950]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.600]
+ Mana 0.000 [0.600]
+ Geomancy
+ Fire 0.000 [0.700]
+ Water 0.000 [0.700]
+ Air 0.000 [0.700]
+ Earth 0.000 [0.700]
+ Meta 0.000 [0.700]
+ Conveyance 0.000 [0.700]
+ Divination 0.000 [0.700]
+ Temporal 0.000 [0.700]
+ Mind 0.000 [0.700]
+ Nature 0.000 [0.700]
+ Necromancy 0.000 [0.700]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 1.000 [1.000]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Thaumaturgist cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Thaumaturgist begins the game with:
+ a Book of Beginner Cantrips
+ a Dagger
+
+
+#####GThaumaturgy
+Thaumaturgists can wreak an amazing amount of destruction, and they don't
+even need spellbooks to do it. As they gain skill they memorise new,
+randomly generated attack spells. Note that they possess no guaranteed
+utility or alteration magics, and can never alter themselves.
+[[[[[BThaumaturgists just kill.]
+
+They use their magics through the 'm' key. They then select a general
+group of spells, followed by a specific spell. Thaumaturgists can learn
+more about a specific spell by browsing it; this is very useful for
+choosing the perfect spell for the occasion.
+
+Thaumaturgy spells can take the form of a bolt, a beam, a ball (either
+centred on the caster or targetable), an area (multiple balls in the
+vicinity of the caster), or a spell that affects all monsters in line of sight.
+
+You can find a little more information here: *****m_thaum.txt*0[Thaumaturgy].
diff --git a/lib/help/c_unbel.txt b/lib/help/c_unbel.txt
new file mode 100644
index 00000000..feec5723
--- /dev/null
+++ b/lib/help/c_unbel.txt
@@ -0,0 +1,65 @@
+~~~~~01|Unbeliever
+~~~~~02|Classes|Unbeliever
+#####R=== Unbelievers ===
+
+#####GDescription
+The full opposite of Sorcerors, Unbelievers so strongly despise magic
+that not only do they refuse to use magic spells, they refuse all
+training in the use of magic items, which leaves them almost totally
+incompetent when trying to use a magic item.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.800]
+ Weaponmastery 1.000 [0.850]
+ Sword-mastery 0.000 [0.400]
+ Axe-mastery 0.000 [0.400]
+ Hafted-mastery 0.000 [0.400]
+ Polearm-mastery 0.000 [0.400]
+ Archery 1.000 [0.600]
+ Antimagic 1.000 [0.650]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+An Unbeliever begins the game with:
+ a Ring of Fear Resistance
+ a Dark Sword
+ a Chain Mail
+
+~~~~~03|Unbelievers|Antimagic
+~~~~~04|Antimagic
+~~~~~05|Skills|Antimagic powers
+#####GAntimagic
+Thought carries power. And since Unbelievers think that magic doesn't
+exist, they can suppress its manifestation around them.
+Their magic-inhibiting ability and the area of effect around them are
+determined by the skill level in Antimagic. If they wield a Dark Sword,
+the strength and radius of the magic disrupting field are increased further,
+with best results if the blade is unenchanted.
+
+High levels of proficiency in Antimagic allow them also to stabilise the
+space-time continuum, so preventing teleportation, to sense the magical
+emanations coming from traps and to destroy these around them.
+These abilities are accessed using the 'm' key.
+
+
diff --git a/lib/help/c_warper.txt b/lib/help/c_warper.txt
new file mode 100644
index 00000000..55d16be5
--- /dev/null
+++ b/lib/help/c_warper.txt
@@ -0,0 +1,60 @@
+|||||oy
+~~~~~01|Warper
+~~~~~02|Classes|Warper
+#####R=== Warpers ===
+
+#####GDescription
+A Warper is a type of mage that prefers to deal in magic that alters the
+fabric of space and time. They specialise in the schools of *****m_convey.txt*0[Conveyance],
+*****m_divin.txt*0[Divination] and *****m_tempo.txt*0[Temporal] magic.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.200]
+ Weaponmastery 0.700 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 1.000 [0.700]
+ Mana 1.000 [0.700]
+ Geomancy
+ Fire 0.000 [0.800]
+ Water 0.000 [0.800]
+ Air 0.000 [0.800]
+ Earth 0.000 [0.800]
+ Meta 0.000 [0.800]
+ Conveyance 0.000 [1.200]
+ Divination 0.000 [1.200]
+ Temporal 0.000 [1.200]
+ Mind 0.000 [0.700]
+ Nature 0.000 [0.800]
+ Necromancy 0.000 [0.700]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Warper cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Warper begins the game with:
+ a Book of Beginner Cantrips
+ a Dagger
diff --git a/lib/help/c_warrio.txt b/lib/help/c_warrio.txt
new file mode 100644
index 00000000..942b34bb
--- /dev/null
+++ b/lib/help/c_warrio.txt
@@ -0,0 +1,54 @@
+~~~~~01|Warrior
+~~~~~02|Classes|Warrior
+#####R=== Warriors ===
+
+#####GDescription
+A Warrior is a hack-and-slash character, who solves most of his problems
+by cutting them to pieces, but will occasionally fall back on the help
+of a magical device or a bow.
+
+A Warrior learns no magic, and can even suppress it like an Unbeliever through
+the Antimagic skill.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.800]
+ Weaponmastery 1.000 [0.850]
+ Sword-mastery 0.000 [0.400]
+ Axe-mastery 0.000 [0.400]
+ Hafted-mastery 0.000 [0.400]
+ Polearm-mastery 0.000 [0.400]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+A Warrior begins the game with:
+ a Ring of Fear Resistance
+ a Broad Sword
+ a Chain Mail
+
diff --git a/lib/help/command.txt b/lib/help/command.txt
new file mode 100644
index 00000000..6616c252
--- /dev/null
+++ b/lib/help/command.txt
@@ -0,0 +1,1251 @@
+|||||oy
+~~~~~99|Commands
+#####R=== List of Commands ===
+
+
+ Angband commands are entered as an "underlying command" (a single key)
+plus a variety of optional or required arguments. You may choose how the
+"keyboard keys" are mapped to the "underlying commands" by choosing one of
+two standard "keysets", the "original" keyset or the "roguelike" keyset.
+
+ The original keyset is very similar to the "underlying" command set,
+with a few additions (such as the ability to use the numeric "directions" to
+"walk" or the "5" key to "stay still"). The roguelike keyset provides similar
+additions, and also allows the use of the h/j/k/l/y/u/b/n keys to "walk" (or,
+in combination with the shift or control keys, to run or tunnel), which thus
+requires a variety of key mappings to allow access to the underlying commands
+used for walking/running/tunneling. In particular, the "roguelike" keyset
+includes many more "capital" and "control" keys, as shown below.
+
+ Note that any keys that are not required for access to the underlying
+command set may be used by the user as "command macro" triggers (see below).
+You may always specify any "underlying command" directly by pressing backslash
+("\") plus the "underlying command" key. This is normally only used in "macro"
+definitions. [[[[[BYou may often enter "control-keys" as a caret ("^") plus the key]
+(so "^" + "p" often yields "^P").
+
+ Some commands allow an optional "repeat count", which allows you to tell
+the game that you wish to do the command multiple times, unless you press a
+key or are otherwise disturbed. To enter a "repeat count", type '0', followed
+by the numerical count, followed by the command. You must type "space" before
+entering certain commands. Skipping the numerical count yields a count of 99.
+An option allows certain commands (open, disarm, tunnel, etc) to auto-repeat.
+
+ Some commands will prompt for extra information, such as a direction, an
+inventory or equipment item, a spell, a textual inscription, the symbol of a
+monster race, a sub-command, a verification, an amount of time, a quantity,
+a file name, or various other things. Normally you can hit return to choose
+the "default" response, or escape to cancel the command entirely.
+
+ Some commands will prompt for a spell or an inventory item. Pressing
+space (or '*') will give you a list of choices. Pressing "-" (minus) selects
+the item on the floor. Pressing a lowercase letter selects the given item.
+Pressing a capital letter selects the given item after verification. Pressing
+a numeric digit '#' selects the first item (if any) whose inscription contains
+"@#" or "@x#", where "x" is the current "underlying command". You may only
+specify items which are "legal" for the command. Whenever an item inscription
+contains "!*" or "!x" (with "x" as above) you must verify its selection.
+
+ In ToME, there are items which occasionally teleport you away, asking
+for permission first. The recurring "Teleport (y/n)?" can be annoying, and
+this behavior can be eliminated by inscribing the object which causes the
+teleportation with "." (or any inscription containing the character ".").
+With this inscription, the object will no longer teleport you around nor
+keep asking you. If you want to restore the teleport ability to the object,
+just remove the "." from its inscription. Note that cursed items which
+teleport you are unaffected by the inscription.
+
+ Some commands will prompt for a direction. You may enter a "compass"
+direction using any of the "direction keys" shown below. Sometimes, you may
+specify that you wish to use the current "target", by pressing "t" or "5", or
+that you wish to select a new target, by pressing "*" (see "Target" below).
+~~~~~95
+#####G Original Keyset Directions Roguelike Keyset Directions
+
+ 7 8 9 y k u
+ 4 6 h l
+ 1 2 3 b j n
+
+ Each of the standard keysets provides some short-cuts over the "underlying
+commands". For example, both keysets allow you to "walk" by simply pressing
+an "original" direction key (or a "roguelike" direction key if you are using
+the roguelike keyset), instead of using the "walk" command plus a direction.
+[[[[[BThe roguelike keyset allows you to "run" or "tunnel" by simply holding the]
+[[[[[Bshift or control modifier key down while pressing a "roguelike" direction key,]
+[[[[[Binstead of using the "run" or "tunnel" command plus a direction.] Both keysets
+allow the use of the "5" key to "stand still", which is most convenient when
+using the original keyset.
+
+ Note that on many systems, it is possible to define "macros" (or "command
+macros") to various keys, or key combinations, so that it is often possible to
+make macros which, for example, allow the use of the shift or control modifier
+keys, plus a numeric keypad key, to specify the "run" or "tunnel" command, with
+the given direction, regardless of any keymap definitions, by using the fact
+that you can always, for example, use "\" + "." + "6", to specify "run east".
+~~~~~100|Commands|Original keyset
+#####R=== Original Keyset Command Summary (4.2.x) ===
+
+ *****command.txt*1[a Aim a wand] *****command.txt*2[A Activate an artifact]
+ *****command.txt*3[b Browse a book] *****command.txt*4[B Bash a door]
+ *****command.txt*5[c Close a door] *****command.txt*6[C Character description]
+ *****command.txt*7[d Drop an item] *****command.txt*8[D Disarm a trap]
+ *****command.txt*9[e Equipment list] *****command.txt*10[E Eat some food]
+ *****command.txt*11[f Fire (shoot) an item] *****command.txt*12[F Fuel your lantern/torch]
+ *****command.txt*13[g Stay still (flip pickup)] *****command.txt*14[G Gain new skills]
+ *****command.txt*15[h Hack up a corpse] *****command.txt*16[H Drink from a fountain]
+ *****command.txt*17[i Inventory list] *****command.txt*18[I Inspect (closely examine) an item]
+ *****command.txt*19[j Jam a door] J (unused)
+ *****command.txt*20[k Destroy an item] *****command.txt*21[K Cure meat]
+ *****command.txt*22[l Look around] *****command.txt*23[L Look around dungeon by sector]
+ *****command.txt*24[m Cast a spell / use mental power] *****command.txt*25[M Full dungeon map]
+ *****command.txt*85[n Repeat last command] *****command.txt*91[N Abilities Screen]
+ *****command.txt*26[o Open a door or chest] *****command.txt*27[O Sacrifice at an altar]
+ *****command.txt*28[p Pray to your god (if any)] *****command.txt*29[P Pet commands]
+ *****command.txt*30[q Quaff a potion] *****command.txt*31[Q Quit (commit suicide)]
+ *****command.txt*32[r Read a scroll] *****command.txt*33[R Rest for a period]
+ *****command.txt*34[s Search for traps/doors] *****command.txt*35[S Toggle search mode]
+ *****command.txt*36[t Take off equipment] *****command.txt*37[T Dig a tunnel]
+ *****command.txt*38[u Use a staff] *****command.txt*39[U Use bonus power (if any)]
+ *****command.txt*40[v Throw an item] *****command.txt*41[V Version Info]
+ *****command.txt*42[w Wear/wield equipment] W (unused)
+ *****command.txt*43[x Engrave the floor] X (unused)
+ *****command.txt*44[y Give item to monster] *****command.txt*96[Y Chat with a monster]
+ *****command.txt*45[z Zap a rod] *****command.txt*46[Z Steal]
+ *****command.txt*47[! Interact with system] *****debug.txt*101[^A (special - debug command)]
+ *****command.txt*49[@ Interact with macros] ^B (unused)
+ *****command.txt*89[# Begin extended command] ^C (special - break)
+ *****command.txt*97[$ Record macros] ^D (unused)
+ *****command.txt*51[% Interact with visuals] *****command.txt*52[^E Toggle choice window]
+ ^ (special - control key) *****command.txt*53[^F Repeat level feeling]
+ *****command.txt*54[& Interact with colors] ^G (unused)
+ *****command.txt*55[* Target monster or location] ^H (unused)
+ ( (unused) ^I (special - tab)
+ ) (unused) ^J (special - linefeed)
+ *****command.txt*58[{ Inscribe an object] ^K (unused)
+ *****command.txt*59[} Uninscribe an object] ^L (unused)
+ [ (unused) ^M (special - return)
+ ] (unused) ^N (unused)
+ *****command.txt*60[- Walk (flip pickup)] ^O (unused)
+ *****command.txt*61[_ Re-Enter store] *****command.txt*62[^P Show previous messages]
+ *****command.txt*63[+ Alter grid] *****command.txt*64[^Q Quit to next midi song]
+ *****command.txt*65[= Set options] *****command.txt*66[^R Redraw the screen]
+ *****command.txt*67[; Walk (with pickup)] *****command.txt*68[^S Save and don't quit]
+ *****command.txt*69[: Take notes] *****command.txt*70[^T Time of the day]
+ ' (unused) ^U (unused)
+ *****command.txt*71[" Enter a user pref command] ^V (unused)
+ *****command.txt*72[, Stay still (with pickup)] ^W (special - wizard mode)
+ *****command.txt*74[< Go up staircase] *****command.txt*75[^X Save and quit]
+ *****command.txt*76[. Run] ^Y (unused)
+ *****command.txt*77[> Go down staircase] ^Z (special - borg command)
+ *****command.txt*79[\ (special - bypass keymap)] *****command.txt*80[| Do cmovies]
+ *****command.txt*81[` (special - escape)] *****command.txt*82[~ Display current knowledge]
+ *****command.txt*83[/ Identify symbol] *****command.txt*84[? Help]
+ *****command.txt*98[^\] Take an html screenshot]
+
+
+~~~~~101|Commands|Roguelike keyset
+#####R=== Roguelike Keyset Command Summary (4.2.x) ===
+
+ *****command.txt*45[a Zap a rod (Activate)] *****command.txt*2[A Activate an artifact]
+ *****command.txt*95[b (walk - south west)] *****command.txt*95[B (run - south west)]
+ *****command.txt*5[c Close a door] *****command.txt*6[C Character description]
+ *****command.txt*7[d Drop an item] *****command.txt*8[D Disarm a trap or chest]
+ *****command.txt*9[e Equipment list] *****command.txt*10[E Eat some food]
+ *****command.txt*4[f Bash a door (force)] *****command.txt*12[F Fuel your lantern/torch]
+ *****command.txt*13[g Stay still (flip pickup)] *****command.txt*14[G Gain new skills]
+ *****command.txt*95[h (walk - west)] *****command.txt*95[H (run - west)]
+ *****command.txt*17[i Inventory list] *****command.txt*18[I Observe an item]
+ *****command.txt*95[j (walk - south)] *****command.txt*95[J (run - south)]
+ *****command.txt*95[k (walk - north)] *****command.txt*95[K (run - north)]
+ *****command.txt*95[l (walk - east)] *****command.txt*95[L (run - east)]
+ *****command.txt*24[m Spell casting / mental power] *****command.txt*25[M Full dungeon map]
+ *****command.txt*95[n (walk - south east)] *****command.txt*95[N (run - south east)]
+ *****command.txt*26[o Open a door or chest] *****command.txt*39[O Use bonus power (if any)]
+ *****command.txt*28[p Pray to your god (if any)] *****command.txt*3[P Browse a book]
+ *****command.txt*30[q Quaff a potion] *****command.txt*31[Q Quit (commit suicide)]
+ *****command.txt*32[r Read a scroll] *****command.txt*33[R Rest for a period]
+ *****command.txt*34[s Search for traps/doors] *****command.txt*97[S Record macros]
+ *****command.txt*11[t Fire an item] *****command.txt*36[T Take off equipment]
+ *****command.txt*95[u (walk - north east)] *****command.txt*95[U (run - north east)]
+ *****command.txt*40[v Throw an item] *****command.txt*16[V Drink from a fountain]
+ *****command.txt*42[w Wear/wield equipment] *****command.txt*23[W Locate player on map (Where)]
+ *****command.txt*22[x Look around] *****command.txt*29[X Pet commands]
+ *****command.txt*95[y (walk - north west)] *****command.txt*95[Y (run - north west)]
+ *****command.txt*1[z Aim a wand (Zap)] *****command.txt*38[Z Use a staff (Zap)]
+ *****command.txt*47[! Interact with system] ^A (special - debug command)
+ *****command.txt*49[@ Interact with macros] *****command.txt*95[^B (tunnel - south west)]
+ *****command.txt*35[# Toggle search mode] ^C (special - break)
+ *****command.txt*15[$ Hack up a corpse] *****command.txt*20[^D Destroy item]
+ *****command.txt*51[% Interact with visuals] *****command.txt*52[^E Toggle choice window]
+ ^ (special - control key) *****command.txt*53[^F Repeat level feeling]
+ *****command.txt*54[& Interact with colors] *****command.txt*27[^G Sacrifice at an altar]
+ *****command.txt*55[* Target monster or location] *****command.txt*95[^H (tunnel - west)]
+ *****command.txt*96[( Chat] ^I (special - tab)
+ *****command.txt*89[) Begin extended command] *****command.txt*95[^J (tunnel - south)]
+ *****command.txt*58[{ Inscribe an object] *****command.txt*95[^K (tunnel - north)]
+ *****command.txt*59[} Uninscribe an object] *****command.txt*95[^L (tunnel - east)]
+ [*****command.txt*46[ Steal] *****command.txt*95[^M (tunnel - south)]
+ ]*****command.txt*43[ Engrave the floor] *****command.txt*95[^N (tunnel - south east)]
+ *****command.txt*60[- Walk (flip pickup)] *****command.txt*21[^O Cure meat]
+ *****command.txt*61[_ Enter store] *****command.txt*62[^P Show previous messages]
+ *****command.txt*63[+ Alter grid] *****command.txt*64[^Q Quit to next midi song]
+ *****command.txt*65[= Set options] *****command.txt*66[^R Redraw the screen]
+ *****command.txt*67[; Walk (with pickup)] *****command.txt*68[^S Save and don't quit]
+ *****command.txt*69[: Take notes] *****command.txt*37[^T Dig a Tunnel]
+ *****command.txt*44[' Give object to monster] *****command.txt*95[^U (tunnel - north east)]
+ *****command.txt*71[" Enter a user pref command] ^V (unused)
+ *****command.txt*76[, Run] ^W (special - wizard mode)
+ *****command.txt*74[< Go up staircase] *****command.txt*75[^X Save and quit]
+ *****command.txt*72[. Stay still (with pickup)] *****command.txt*95[^Y (tunnel - north west)]
+ *****command.txt*77[> Go down staircase] ^Z (special - borg command)
+ *****command.txt*79[\ (special - bypass keymap)] *****command.txt*80[| Do cmovies]
+ *****command.txt*81[` (special - escape)] *****command.txt*82[~ Display current knowledge]
+ *****command.txt*83[/ Identify symbol] *****command.txt*84[? Help]
+
+~~~~~102|Commands|Special keys
+#####R=== Special Keys ===
+
+ Certain special keys may be intercepted by the operating system or
+the host machine, causing unexpected results. In general, these special keys
+are control keys, and often, you can disable their special effects.
+
+ If you are playing on a UNIX or similar system, then Ctrl-C will
+interrupt ToME. The second and third interrupt will induce a warning
+bell, and the fourth will induce both a warning bell and a special message,
+since the fifth will quit the game, after killing your character. Also,
+Ctrl-Z will suspend the game, and return you to the original command shell,
+until you resume the game with the "fg" command. There is now a compilation
+option to force the game to prevent the "double ctrl-z escape death trick".
+The Ctrl-\ and Ctrl-D and Ctrl-S keys should not be intercepted.
+
+ It is often possible to specify "control-keys" without actually
+pressing the control key, by typing a caret ("^") followed by the key.
+This is useful for specifying control-key commands which might be caught
+by the operating system as explained above.
+~~~~~79
+ Pressing [[[[[Gbackslash ("\\")] before a command will bypass all keymaps,
+and the next keypress will be interpreted as an "underlying command" key,
+unless it is a caret ("^"), in which case the keypress after that will be
+turned into a control-key and interpreted as a command in the underlying
+ToME keyset. The backslash key is useful for creating macro actions
+which are not affected by any keymap definitions that may be in force, for
+example, the sequence "\" + "." + "6" will always mean "run east", even if
+the "." key has been mapped to a different underlying command.
+
+ The "0" and "^" and "\" keys all have special meaning when entered
+at the command prompt, and there is no "useful" way to specify any of them
+as an "underlying command", which is okay, since they would have no effect.
+~~~~~81
+ For many input requests or queries, the [[[[[Gspecial character ESCAPE]
+will abort the command. The "[y/n]" prompts may be answered with "y" or
+"n", or escape. The "-more-" message prompts may be cleared (after reading
+the displayed message) by pressing ESCAPE, SPACE, RETURN, LINEFEED, or by
+any keypress, if the "quick_messages" option is turned on.
+~~~~~103|Commands|Command counts
+~~~~~104|Commands|Repeating a command
+#####R=== Command Counts ===
+
+ Some commands can be executed a fixed number of times by preceding
+them with a count. Counted commands will execute until the count expires,
+until you type any character, or until something significant happens, such
+as being attacked. Thus, a counted command doesn't work to attack another
+creature. While the command is being repeated, the number of times left
+to be repeated will flash by on the line at the bottom of the screen.
+
+ [[[[[BTo give a count to a command, type 0, the repeat count, and then]
+[[[[[Bthe command.] If you want to give a movement command and you are using the
+original command set (where the movement commands are digits), press space
+after the count and you will be prompted for the command.
+
+ Counted commands are very useful for searching or tunneling, as
+they automatically terminate on success, or if you are attacked. You may
+also terminate any counted command (or resting or running), by typing any
+character. This character is ignored, but it is safest to use a SPACE or
+ESCAPE which are always ignored as commands in case you type the command
+just after the count expires.
+
+ You can tell ToME to automatically use a repeat count of 99
+with commands you normally want to repeat (open, disarm, tunnel, bash,
+alter, etc) by setting the "always_repeat" option.
+
+
+#####R=== Selection of Objects ===
+
+ Many commands will also prompt for a particular object to be used.
+For example, the command to read a scroll will ask you which of the
+scrolls that you are carrying that you wish to read. In such cases, the
+selection is made by typing a letter of the alphabet. The prompt will
+indicate the possible letters, and will also allow you to type the key
+"*", which causes all of the available options to be described. The list
+of choices will also be shown in the Choice window, if you are using a
+windows environment and windows are turned on. Often you will be able to
+press "/" to select an object from your equipment instead of your
+inventory. Pressing space once will have the same effect as "*", and
+the second time will cancel the command and run the "i" or "e" command.
+
+ [[[[[BThe particular object may be selected by an upper case or a lower]
+[[[[[Bcase letter. If lower case is used, the selection takes place]
+[[[[[Bimmediately. If upper case is used, then the particular option is]
+[[[[[Bdescribed, and you are given the option of confirming or retracting that]
+[[[[[Bchoice.] Upper case selection is thus safer, but requires an extra key
+stroke. Also see the "!*" and "!x" inscriptions, below.
+
+ For many commands, [[[[[Byou can also use "-" to select an object on the]
+[[[[[Bfloor where you are standing.] This lets you read scrolls or quaff
+potions, for example, off the dungeon floor without picking them up.
+~~~~~90
+ If you enter a number between 0 and 9, the first item engraved
+with "@#" where "#" is the number you entered will be selected. For example,
+if you have a shovel engraved with "@0" and you type "w" (for wield) and
+then 0, you will wield the shovel. This is very useful for macros (see
+below), since you can use this to select an object regardless of its
+location in your pack. Multiple numbers can be engraved on the same object; for
+example, if a sword is engraved with @1@0, then either "w1" or "w0" will
+wield it. Normally, you inscribe "@1@0" on your primary weapon, and
+"@2@0" on your secondary weapon. [[[[[BNote that an inscription containing]
+[[[[[B"@x#" will act like "@#" but only when the current "ToME command"]
+[[[[[Bis "x".] Thus you can put "@z4" on a rod and "@u4" on a staff, and then
+use both "z4" and "u4" as desired.
+
+ Note that any object containing "!x" in its inscription, where
+"x" is the current "ToME command" (or containing "!*" ever) will induce
+"verification" whenever that object is "selected". Thus, inscribing, say,
+"!f!k!d" on an object will greatly reduce the odds of you "losing" it by
+accident, and [[[[[Binscribing "!*" on an object] will allow you to be very paranoid
+about the object. Note that "selling" and "dropping" both use the "d" command.
+
+~~~~~105|Pref files
+#####R=== User Pref Files ===
+
+ ToME allows you to change various aspects of the game to suit
+your tastes. You may define keymaps (changing the way ToME maps your
+keypresses to underlying commands), create macros (allowing you to map a
+single keypress to a series of keypresses), modify the visuals (allowing
+you to change the appearance of monsters, objects, or terrain features),
+change the colors (allowing you to make a given color brighter, darker,
+or even completely different), or set options (turning them off or on).
+
+ ToME stores your preferences in files called "user pref files",
+which contain comments and "user pref commands", which are simple strings
+describing one aspect of the system about which the user has a preference.
+There are many ways to load a user pref file, and in fact, some of these
+files are automatically loaded for you by the game. All of the files are
+kept in the "lib/user/" directory, though you may have to use one of the
+command line arguments to redirect this directory, especially on multiuser
+systems. You may also enter single user pref commands directly, using the
+special "Enter a user pref command" command, activated by "double quote".
+You may have to use the "redraw" command (^R) after changing certain of
+the aspects of the game, to allow ToME to adapt to your changes.
+
+ When the game starts up, after you have loaded an old character,
+or created a new character, some user pref files are loaded automatically.
+First, the "pref.prf" file is loaded. This file contains some user pref
+commands which will work on all platforms. Then one of "font-xxx.prf"
+(for normal usage) or "graf-xxx.prf" (for bitmap usage) is loaded. These
+files contain attr/char changes to allow the monsters, objects, and/or
+terrain features to look "better" on your system. Then the "pref-xxx.prf"
+file is loaded. This file contains pre-defined system specific stuff
+(macros, color definitions, etc). Then, the "user-xxx.prf" file is loaded.
+This file contains user-defined system specific stuff. The "user-xxx.prf"
+file is used as the "default" user pref file in many places. The "xxx" is
+the "system suffix" for your system, taken from the "main-xxx.c" file which
+was used to generate your executable. Finally, the "Race.prf", "Class.prf",
+and "Name.prf" files are loaded, where "Race", "Class", and "Name" are
+replaced by the actual race, class, and name of the current character.
+
+ Several commands allow you to both load existing user pref files,
+create new user pref files, append information to existing user pref files,
+and/or interact with various of the user preferences in a more intuitive
+way than the user pref commands allow. The commands include "Interact with
+macros" (@), "Interact with visuals" (%), and "Interact with colors" (&),
+described below.
+~~~~~106|Pref files|Macros
+#####G--- User Pref Files (Macros) ---
+
+ The "Interact with macros" command allows you to define or remove
+"macros", which are mappings from a single logical keypress to a sequence
+of keypresses, allowing you to use special keys on the keyboard, such as
+function keys or keypad keys, possibly in conjunction with modifier keys,
+to "automate" repetitive multi-keypress commands that you use a lot.
+
+ Since macros represent keypress sequences, and not all keypresses
+have a printable representation, macro triggers and actions must often be
+"encoded" into a human readable form. This is done using several types
+of encoding, including "\xHH" for character number HH in hexidecimal, "\e"
+for the "escape" code, "\n" for the "newline" code, "\r" for the "return"
+code, "\s" for the "space" code, "\\" for backslash, "\^" for caret, and
+"^X" for the code for any "control" key "ctrl-X". Note that the "action"
+of a macro will not be checked against other macro triggers (unless the
+macro action contains a "control-backslash"), so you cannot make infinite
+loops. You may specify extremely long macros, but you are limited in
+length by the underlying input mechanisms, which in general limit you
+to about 1024 keys in both triggers and actions.
+
+ The special "\" command (which must be encoded in macros as "\\")
+is very useful in macros, since it bypasses all keymaps and allows the next
+keystroke to be considered a command in the underlying ToME command set.
+For example, a macro which maps Shift-KP6 to "\" + "." + "6" will induce
+the "run east" behavior, regardless of what keyset the user has chosen, and
+regardless of what keymaps have been defined.
+
+ Macros can be specified in user pref files as a pair of lines, one
+of the form "A:<str>", which defines the encoded macro action, and one of
+the form "P:<str>", which defines the encoded macro trigger.
+
+ A [[[[[Bcommon example of a macro] to cast the first spell in your first spell
+book at the nearest monster would be: \e\e\em1a*t where \e is an escape (to make
+sure you are not still within another command), m1 selects the spell book that
+is inscribed ({) with @m1, a selects the first spell in that book, and *t targets
+the nearest monster.
+
+ More detailed information about specific macros can be found in
+*****macrofaq.txt*0[macrofaq.txt], originally written by Jim Lyon (jplyon@attglobal.net),
+modified for ToME with Jim's permission by Dawnmist
+(angband@dawnmist.8m.com).
+~~~~~107|Pref files|Keymaps
+#####G--- User Pref Files (Keymaps) ---
+
+ The "Interact with macros" command also allows you to define
+"keymaps", which are vaguely related to macros. A keymap maps a single
+keypress to a series of keypresses, which bypass both other keymaps and
+any macros. ToME uses keymaps to map the original and the roguelike
+keysets to the underlying command set, and allows the user to modify or
+add keymaps of their own. Note that all keymap actions must be specified
+using underlying commands, not keypresses from the original or roguelike
+keysets. The original keyset is almost identical to the underlying keyset,
+except that "numbers" are mapped to ";" plus a direction, "5" is mapped to
+",", and a few control-keys are mapped to various things. See "command.txt"
+for the full set of underlying commands. Some uses for keymaps include the
+ability to "disable" a command by mapping it to "\x00",
+
+ Keymaps can be specified in user pref files as line of the form
+"M:<T> <key> <str>", where <T> is the keyset (0/1 for original/roguelike),
+<key> is the encoded trigger key, and <str> is the encoded keymap action.
+~~~~~108|Pref files|Visuals
+#####G--- User Pref Files (Visuals) ---
+
+ You can use the "Interact with visuals" command to change various
+visual information, currently including the choice of what attr/char values
+are used to represent various monsters, objects, or terrain features. Note
+that in combination appropriate support in "main-xxx.c", and with the use of
+the "use_graphics" flag, you may be able to specify that "graphic bitmaps"
+should be used instead of normal "colored characters" for various things.
+
+ When interactively modifying the attr/char values for monsters,
+objects, or terrain features, pressing "n" or "N" will change which entry
+you are changing, pressing "a" or "A" will rotate through the available
+attr values, and pressing "c" or "C" will rotate though the available char
+values. Note that attr/char values with the "high bit" set may induce the
+display of special "graphic" pictures if the "use_graphics" flag is set,
+and your system supports the "use_graphics" flag.
+
+ Note that this command can be abused in various ways, and if you
+must do so, remember that you are only cheating yourself.
+
+ Keymaps can be specified in user pref files as line of the form
+"R:<N>:<A>/<C>" or "K:<N>:<A>/<C>" or "F:<N>:<A>/<C>" or "U:<N>:<A>/<C>".
+~~~~~109|Pref files|Colors
+#####G--- User Pref Files (Colors) ---
+
+ The "Interact with colors" command allows you to change the actual
+internal values used to display various colors. This command may or may
+not have any effect on your machine. Advanced machines may allow you to
+change the actual RGB values used to represent each of the 16 colors used
+by ToME, and perhaps even allow you to define new colors which are not
+currently used by ToME.
+
+ Colors can be specified in user pref files as line of the form
+"V:<N>:<V>:<R>:<G>:<B>".
+~~~~~110|Pref files|Options
+#####G--- User Pref Files (Options) ---
+
+ The "Interact with options" command allows you to turn options
+on or off. You may turn options off or on using the user pref commands
+of the form "X:<option>" or "Y:<option>" respectively.
+
+~~~~~111|Commands|Command descriptions
+#####R=== Command Descriptions ===
+
+ The following command descriptions are listed as the command name
+plus the "underlying command" key. This is followed by the command name
+and "roguelike" keyset key, if different from the underlying command key.
+Then comes a brief description of the command, including information about
+alternative methods of specifying the command in each keyset, when needed.
+Several commands (tunnel, disarm, bash, open) are repeated 99 times if the
+"always_repeat" option is set and no repeat count is given. Some commands
+use the "repeat count" to automatically repeat the command several times,
+while others use the "repeat count" as an "argument", for example, commands
+which need a "quantity" will use the "repeat count" instead of asking for
+a quantity, allowing the use of "0d" for "drop all". Commands which ask
+for a quantity will convert any "letters" into the maximal legal value.
+~~~~~112|Commands|Inventory
+#####R--- Inventory Commands ---
+~~~~~17
+[[[[[GInventory list (i)]
+ Displays a list of objects being carried but not equipped. You
+ can carry up to 23 different items, not counting those in your
+ equipment. Often, many identical objects can be "stacked" into
+ a "pile" which will count as a single item. This is always
+ true of things like potions, scrolls, and food, but you may have
+ to set options to allow wands, staves, and other such objects to
+ stack. Each object has a weight, and if you carry more objects
+ than your strength permits, you will begin to slow down.
+~~~~~9
+[[[[[GEquipment list (e)]
+ Use this command to display a list of the objects currently being
+ used by your character. The number and type of available slots for
+ equipment may vary. A human for example has 15 slots for equipment,
+ each corresponding to a different location on the body, and each of
+ which may contain only a single object at a time, and each of which
+ may only contain objects of the proper "type".
+ If the option "show_labels" is set, the slots are labelled as follows:
+ Wielding (weapon), Shooting (missile launcher or instruments),
+ On finger (ring), Around neck (amulet), Light source (light source),
+ On body (armor), About body (cloak), On arm (shield), On head (helmet),
+ On hands (gloves), On feet (boots), Carrying (symbiote), Quiver (ammo),
+ Using (tool). You must be using an object to receive any of its special
+ powers.
+~~~~~7
+[[[[[GDrop an item (d)]
+ This command drops an item from your inventory or equipment onto the
+ dungeon floor. If the place you are standing on already has objects
+ in it, ToME will attempt to drop the item onto an adjacent space.
+ A floor spot can hold more than one object, but there is still the
+ possibility that if the floor is too full and you attempt to drop
+ something, it may disappear and be destroyed. If the selected pile
+ contains multiple items, you may specify a quantity.
+~~~~~20
+[[[[[GDestroy an item (k) or Destroy an item (^D)]
+ This destroys an item in your inventory or on the dungeon floor.
+ If the selected pile contains multiple objects, you may specify
+ a quantity. You must always verify this command, unless the item
+ is cursed or worthless and the option "auto_destroy" is set.
+~~~~~42
+[[[[[GWear/Wield equipment (w)]
+ To wear or wield an object in your inventory, use this command.
+ Since only one object can be in each slot at a time, if you wear
+ or wield an item into a slot which is already occupied, the old
+ item will be first be taken off, and may in fact be dropped if
+ there is no room for it in your inventory.
+~~~~~36
+[[[[[GTake off equipment (t) or Take off equipment (T)]
+ Use this command to take off a piece of equipment and return it
+ to your inventory. Occasionally, you will run into a cursed item
+ which cannot be removed. These items normally penalise you in some
+ way and cannot be taken off until the curse is removed. If there
+ is no room in your inventory for the item, your pack will overflow
+ and you will drop the item after taking it off.
+~~~~~113|Commands|Movement
+#####R--- Movement Commands ---
+~~~~~67
+[[[[[GWalk (with pickup) (;)]
+ Moves one step in the given direction. The square you are moving
+ into must not be blocked by walls or doors. You will pick up any
+ items in the destination grid if the "always_pickup" option is set,
+ or if the "query_pickup" option is set and you respond correctly.
+ This command can take a count and requires a direction. You may
+ also use the "original" direction keys (both keysets) or the
+ "roguelike" direction keys (roguelike keyset) to walk in a
+ direction.
+~~~~~60
+[[[[[GWalk (flip pickup) (-)]
+ This is just like normal move, except that the "Pick things up"
+ option is inverted. In other words, if you normally pick up
+ anything you encounter (the default), you will not pick things up
+ when using this command. If you normally do not pick things up,
+ you will when using this command. This command can take a count
+ and requires a direction.
+~~~~~76
+[[[[[GRun (.) or Run (,)]
+ This command will move in the given direction, following any bends
+ in the corridor, until you either have to make a "choice" between
+ two directions or you are disturbed. You can configure what will
+ disturb you by setting the disturbance options. Run requires a
+ direction. You may also use shift plus the "roguelike" direction
+ keys (roguelike keyset), or shift plus the "original" direction keys
+ on the keypad (both keysets, some machines) to run in a direction.
+~~~~~74
+[[[[[GGo up staircase (<)]
+ Climbs up an up staircase you are standing on. There is always at
+ least one staircase going up on every level (this doesn't mean it's
+ easy to find) except for the surface, where '<' will bring up the
+ wilderness map. Going up a staircase will take you to a new dungeon
+ level unless you are at the first level of the dungeon, in which case
+ you will return to the surface. Note that whenever you leave a dungeon
+ level, you will never find it again, unless the level contains a dungeon
+ town. This means that for all intents and purposes, any objects on that
+ level are destroyed. This includes unknown artifacts unless the "Create
+ characters in preserve mode" option was set when your character was
+ created, in which case the artifacts may show up again later.
+~~~~~77
+[[[[[GGo down staircase (>)]
+ Descends a down staircase you are standing on. There are always
+ at least two staircases going down on each level, except for the
+ last level of a dungeon, and some "quest" levels, which have none until
+ the quest monsters are killed. Going down a staircase will take you
+ to a new dungeon level. See "Go Up Staircase" for more info.
+
+ This command is also used to enter Void Jumpgates, and to zoom in from
+ the wilderness map.
+~~~~~114|Commands|Resting
+#####R--- Resting Commands ---
+~~~~~72
+[[[[[GStay still (with pickup) (,) or Stay still (with pickup) (.)]
+ Stays in the same square for one move. If you normally pick up
+ objects you encounter, you will pick up whatever you are standing
+ on. This command can take a count. You may also use the "5" key
+ (both keysets).
+~~~~~13
+[[[[[GStay still (flip pickup) (g)]
+ Stays in the same square for one move. If you normally pick up
+ objects you encounter, you will not pick up whatever you are
+ standing on. If you normally do not pick up objects, you will
+ pick up what you are standing on. This command is normally only
+ used when the "always_pickup" option is false. This command can
+ take a count.
+~~~~~33
+[[[[[GRest (R)]
+ Resting is better for you than repeatedly staying still, and can
+ be told to automatically stop after a certain amount of time, or
+ when various conditions are met. In any case, you always wake up
+ when anything disturbing happens, or when you press any key. To
+ rest, enter the Rest command, followed by the number of turns you
+ want to rest, or "*" to rest until your hit points and mana are
+ restored, or "&" to rest until you are fully "healed". This command
+ can take a count, which is used for the number of turns to rest.
+~~~~~61
+[[[[[GEnter store (_)]
+ When standing on the door of a store, this command allows the character
+ to enter the store again.
+~~~~~115|Commands|Searching
+#####R--- Searching Commands ---
+~~~~~34
+[[[[[GSearch (s)]
+ This command can be used to locate hidden traps and secret doors
+ in the spaces adjacent to the player. More than a single turn of
+ searching will be required in most cases. You should always
+ search a chest before trying to open it, since they are generally
+ trapped. This command can take a count, which is useful if you
+ are fairly sure of finding something eventually, since the command
+ stops as soon as anything is found. This command can take a count.
+~~~~~35
+[[[[[GToggle search mode (S) or Toggle search mode (#)]
+ This command will take you into and out of search mode. When
+ first pressed, the message "Searching" will appear at the bottom
+ of the screen. You are now taking two turns for each command, one
+ for the command and one turn to search. This means that you are
+ taking twice the time to move around the dungeon, and therefore
+ twice the food. Search mode will automatically turn off if you
+ are disturbed. You may also turn off search mode by entering the
+ Search Mode command again.
+~~~~~116|Commands|Alteration commands
+~~~~~117|Commands|Terrain interaction
+#####R--- Alter Commands ---
+~~~~~37
+[[[[[GTunnel (T) or Tunnel (^T)]
+ Tunnelling or mining is a very useful art. There are many kinds of
+ rock, with varying hardness, including permanent rock (permanent),
+ granite (very hard), quartz veins (hard), magma veins (soft), and
+ rubble (very soft). Quartz and Magma veins may be displayed in a
+ special way, and may sometimes contain treasure, in which case they
+ will be displayed in a different way. Rubble sometimes covers an
+ object. It is only possible to tunnel if you are wielding a digging
+ tool such as a shovel or a pick. Tunnelling ability increases with
+ strength and tool weight. This command can take a count, requires a
+ direction, and is affected by the "always_repeat" option.
+~~~~~26
+[[[[[GOpen a door or chest (o)]
+ To open an object such as a door or chest, you must use this
+ command. If the object is locked, you will attempt to pick the
+ lock based on your disarming ability. If you open a trapped chest
+ without disarming the traps first, the trap will be set off. Some
+ doors will be jammed shut and may have to be forced open. You may
+ need several tries to open a door or chest. Open can take a count,
+ requires a direction, and is affected by the "always_repeat" option.
+~~~~~5
+[[[[[GClose a door (c)]
+ Non-intelligent and some other creatures cannot open doors, so
+ shutting doors can be quite valuable. Broken doors cannot be closed.
+ Bashing a door open may break it. Close can take a count, requires a
+ direction, and is affected by the "always_repeat" option.
+~~~~~19
+[[[[[GJam a door (j) or Spike a door (S)]
+ Many monsters can simply open closed doors, and can eventually
+ get through a locked door. You may therefore occasionally want
+ to jam a door shut with iron spikes. Each spike used on the door
+ will make it harder to bash down the door, up to a certain limit.
+ Smaller monsters are less able to bash down doors. In order to
+ use this command, you must be carrying iron spikes. Jam or Spike
+ requires a direction.
+~~~~~4
+[[[[[GBash a door (B) or Force a door (f)]
+ This command allows you to bash down jammed doors. Your bashing
+ ability increases with strength. Bashing open a door can (briefly)
+ throw you off balance. Doors that are stuck, or which have been
+ jammed closed with spikes can only be opened by bashing, and all
+ closed doors can be bashed open if desired. Bashing a door open
+ may permanently break it so that it can never be closed. Bash or
+ Force can take a count, requires a direction, and is affected by
+ the "always_repeat" option.
+~~~~~8
+[[[[[GDisarm a trap or chest (D)]
+ You can attempt to disarm traps on the floor or on chests. If you
+ fail, there is a chance that you will blunder and set it off. You
+ can only disarm a trap after you have found it (usually with the
+ Search command). Disarm can take a count, requires a direction,
+ and is affected by the "always_repeat" option.
+~~~~~63
+[[[[[GAlter (+)]
+ This special command allows the use of a single keypress to select
+ any of the "obvious" commands above (attack, tunnel, bash, open,
+ disarm, close), and, by using macros or keymaps, to combine this
+ keypress with directions. In general, this allows the use of the
+ "control" key plus the appropriate "direction" key (including the
+ roguelike direction keys in roguelike mode) as a kind of generic
+ "alter the terrain feature of an adjacent grid" command. Alter
+ can take a count, requires a direction, and is affected by the
+ "always_repeat" option.
+~~~~~43
+[[[[[GEngrave the floor (x)]
+ The dungeon is full of magics, and as such pools of it collect on
+ the floor in places. With the "inscribe" command, it is possible
+ to create some spell effects by inscribing words you have read from
+ various parchments detailing the languages used within the dungeon.
+ Then, if there is enough mana collected on that square, walking over
+ the inscription will trigger the spell. Some spells can be triggered
+ only by the player, some only by monsters, and some are triggered by
+ both.
+~~~~~46
+[[[[[GSteal (Z)]
+ Allows the player to try to steal items from shops. Also allows
+ rogues to steal from monsters.
+~~~~~118|Commands|Spells and prayers
+#####R--- Spell and Prayer Commands ---
+~~~~~3
+[[[[[GBrowse a book (b) or Peruse a book (P)]
+ Only characters with some knowledge in the magic schools, such as
+ mages, priests, rogues, and rangers, can read magic spellbooks.
+ Warriors normally cannot read any books. When this command is used,
+ all of the spells or prayers contained in the selected book are
+ displayed, along with information such as their level, the amount of
+ mana or piety required to cast them, and whether or not you know the
+ spell or prayer.
+~~~~~14
+[[[[[GGain new skills (G)]
+ Use this command to access the skills menu and spend the skill points
+ you gain at each new character level to increase the range of things
+ your character is able to do.
+~~~~~91
+[[[[[GGain new abilities (N)]
+ Use this command to access the Abilities menu and spend the skill points
+ you gain at each new character level to increase the range of things
+ your character is able to do.
+~~~~~24
+[[[[[GCast a spell / Pray a prayer (m) / Use a mental power]
+ To cast a spell or prayer, you must have the skill level required in
+ that school of magic to be able access that spell, and a book that
+ contains that spell in your inventory (for most schools). Each spell
+ has a chance of failure which starts out fairly large but decreases
+ as you gain levels. If you don't have enough mana to cast a spell,
+ you will be told you do not have enough mana to cast it. Since in most
+ cases you must read the spell from a book, you cannot be blind or
+ confused while casting, and there must be some light present.
+
+ Some classes (for example, Thaumaturgists) have the ability to use
+ some magic without actually needing spell books of any sort. These
+ classes are able to access their magical powers through the use of
+ the 'm' command.
+~~~~~39
+[[[[[GUse bonus power (if any) (U) or (O)]
+ Some races and classes have special natural abilities. All of these
+ possible abilities are listed in an index under the U (or O) command.
+ These type of abilities can include the Vampire's bite, a DeathMold's
+ telekinesis, and a RohanKnight's light speed capabilities.
+~~~~~119|Commands|Object manipulation
+#####R--- Object Manipulation Commands ---
+~~~~~10
+[[[[[GEat some food (E)]
+ You must eat regularly to prevent starvation. As you grow hungry,
+ a message will appear at the bottom of the screen saying "Hungry".
+ If you go hungry long enough, you will become weak, then start
+ fainting, and eventually, you may will die of starvation. You
+ may use this command to eat food in your inventory. Note that
+ you can sometimes find food in the dungeon, or you can butcher
+ corpses of killed creatures to obtain raw meat, but it is not
+ always wise to eat strange food.
+~~~~~12
+[[[[[GFuel your lantern/torch (F)]
+ If you are using a torch and have more torches in your pack,
+ or you are using a lantern and have flasks of oil in your pack,
+ then your can "refuel" them with this command. Torches and Lanterns
+ are limited in their maximal fuel. In general, two flasks will fully
+ fuel a lantern and two torches will fully fuel a torch.
+~~~~~30
+[[[[[GQuaff a potion (q)]
+ Use this command to drink a potion. Potions affect the player in
+ various ways, but the effects are not always immediately obvious.
+~~~~~32
+[[[[[GRead a scroll (r)]
+ Use this command to read a scroll. Scroll spells usually have an
+ area effect, except for a few cases where they act on other objects.
+ Reading a scroll causes the parchment to disintegrate as the scroll
+ takes effect, unless you are an Alchemist. Most scrolls which prompt
+ for more information can be aborted (by pressing escape), which will
+ stop reading the scroll before it disintegrates.
+~~~~~58
+[[[[[GInscribe an object ({)]
+ This command inscribes a string on an object. The inscription is
+ displayed inside curly braces after the object description. The
+ inscription is limited to the particular object (or pile) and is
+ not automatically transferred to all similar objects. Under certain
+ circumstances, ToME will display "fake" inscriptions on certain
+ objects ("cursed", "broken", "tried", "empty", "NN% off") when
+ appropriate. These "fake" inscriptions are "covered up" by real
+ inscriptions, but will re-appear if the real inscription is removed.
+ In addition, ToME will occasionally place a "real" inscription on
+ an object for you, normally as the result of your character getting
+ a "feeling" about the item. All characters will get "feelings" about
+ weapons and armor after carrying them for a while. Warriors get the
+ most detailed feelings, and get them quicker than any other class.
+ An item labeled as "{empty}" was found to be out of charges, and an
+ item labeled as "{tried}" is a "flavoured" item which the character
+ has used, but whose effects are unknown. Certain inscriptions have
+ a meaning to the game, see "@#", "@x#", "!*", and "!x", in the section
+ on *****command.txt*90[inventory object selection.]
+~~~~~59
+[[[[[GUninscribe an object (})]
+ This command removes the inscription on an object. This command will
+ have no effect on "fake" inscriptions added by the game itself.
+~~~~~15
+[[[[[GHack up a corpse (h or $)]
+ Corpses can be cut up into smaller pieces of meat, allowing the user to
+ eat the meat, or cure it for later use.
+~~~~~21
+[[[[[GCure meat (K)]
+ Curing meat requires the use of a potion of salt water, and is used to
+ protect meat from hacked-up corpses from going bad.
+~~~~~16
+[[[[[GDrink from a fountain (H)]
+ All fountains in Arda are magical, and act like magical potions. The
+ game will ask you whether you want to quaff from a fountain or to fill
+ empty bottles. The only way to identify the type of fountain is to
+ fill your bottles from it and see what you get.
+~~~~~44
+[[[[[GGive item to monster (y)]
+ This command is used to give an item within your inventory to a monster
+ standing next to you. The monster may not accept the item you give it,
+ however.
+~~~~~96
+[[[[[GChat (Y)]
+ This command allows you to chat with someone. Be warned that most
+ monsters won't chat
+
+#####R--- Magical Object Commands ---
+~~~~~2
+[[[[[GActivate an artifact (A)]
+ You have heard rumours of special weapons and armour deep in the
+ Pits, items that can let you breath fire like a dragon or light
+ rooms with just a thought. Should you ever be lucky enough to
+ find such an item, this command will let you activate its special
+ ability. Special abilities can only be used if you are wearing or
+ wielding the item.
+ Note that there are also a few common objects that can be activated,
+ e.g. music instruments, monster eggs and spell-storing mage staves,
+ and that some artifacts, so-called "junkarts", can't be wielded, but
+ must be activated from the backpack.
+~~~~~1
+[[[[[GAim a wand (a) or Zap a wand (z)]
+ Wands must be aimed in a direction to be used. Wands are magical
+ devices, and therefore there is a chance you will not be able to
+ figure out how to use them if you aren't good with magical
+ devices. They will fire a shot that affects the first object or
+ creature encountered or fire a beam that affects anything in a
+ given direction, depending on the wand. An obstruction such as a
+ door or wall will generally stop the effects from traveling any
+ farther. This command requires a direction and can use a target.
+~~~~~38
+[[[[[GUse a staff (u) or Zap a staff (Z)]
+ This command will use a staff. A staff is normally very similar
+ to a scroll, in that they normally either have an area effect or
+ affect a specific object. Staves are magical devices, and there
+ is a chance you will not be able to figure out how to use them.
+~~~~~45
+[[[[[GZap a rod (z) or Activate a rod (a)]
+ Rods are extremely powerful magical items, which cannot be burnt
+ or shattered, and which can have either staff-like or wand-like
+ effects, but unlike staves and wands, they don't have charges.
+ Instead, they draw on the ambient magical energy to recharge
+ themselves, and therefore can only be activated once every few
+ turns. The recharging time varies depending on the type of rod.
+ This command may require a direction (depending on the type of
+ rod, and whether you are aware of its type) and can use a target.
+~~~~~120|Commands|Throwing and missile weapons
+#####R--- Throwing and Missile Weapons ---
+~~~~~11
+[[[[[GFire an item (f) or Fire an item (t)]
+ You may throw any object carried by your character. Depending on
+ the weight, it may travel across the room or drop down beside you.
+ Only one object from a pile will be thrown at a time. Note that
+ throwing an object will often cause it to break, so be careful!
+ If you throw something at a creature, your chances of hitting it
+ are determined by your pluses to hit, your ability at throwing,
+ and the object's pluses to hit. Once the creature is it, the
+ object may or may not do any damage to it. You've heard rumors
+ that some objects found in the dungeon can do huge amounts of
+ damage when thrown, but you're not sure which objects those
+ are.... Note that flasks of oil will do a fairly large chunk
+ of damage to a monster on impact, supposedly representing fire
+ damage, but it works against fire elementals too... If you are
+ wielding a missile launcher compatible with the object you are
+ throwing, then you automatically use the launcher to fire the
+ missile with much higher range, accuracy, and damage, then you
+ would get by just throwing the missile. Fire or Throw requires
+ a direction. Targeting mode (see the next command) can be invoked
+ with "*" at the "Direction?" prompt.
+~~~~~40
+[[[[[GThrow an item (v)]
+ You may throw any object carried by your character. The lighter
+ the object, the farther you can throw it. Only one object from a
+ stack may be thrown at a time. Throwing an object may break it.
+ If you throw something at a monster, your chances of hitting it
+ are determined by your pluses to hit, your ability at throwing,
+ and the object's pluses to hit. If the object hits the monster,
+ it may or may not do damage. Some objects, such as weapons, or
+ flasks of oil, can do a substantial amount of damage. This
+ command requires a direction, and can take a target.
+~~~~~55
+[[[[[GTargeting Mode (*)]
+ This will allow you to aim your spells and such at a specific
+ monster or grid, so that you can point directly towards that
+ monster or grid (even if this is not a "compass" direction) when
+ you are asked for a direction. You can set a target using this
+ command, or you can set a new target at the "Direction?" prompt when
+ appropriate. At the targeting prompt, you have many options. First
+ of all, targetting mode starts targetting nearby monsters which can
+ be reached by "projectable" spells and thrown objects. In this mode,
+ you can press "t" (or "5" or ".") to select the current monster,
+ space to advance to the next monster, "-" to back up to the previous
+ monster, direction keys to advance to a monster more or less in that
+ direction, "r" to "recall" the current monster, "q" to exit targetting
+ mode, and "p" (or "o") to stop targetting monsters and enter the mode
+ for targetting a location on the floor or in a wall. Note that if
+ there are no nearby monsters, you will automatically enter this mode.
+ Note that hitting "o" is just like "p", except that the location
+ cursor starts on the last examined monster instead of on the player.
+ In this mode, you use the "direction" keys to move around, and the
+ "q" key to quit, and the "t" (or "5" or ".") key to target the cursor
+ location. Note that targetting a location is slightly "dangerous",
+ as the target is maintained even if you are far away. To cancel an
+ old target, simply hit "*" and then ESCAPE (or "q"). Note that when
+ you cast a spell or throw an object at the target location, the path
+ chosen is the "optimal" path towards that location, which may or may
+ not be the path you want. Sometimes, by clever choice of a location
+ on the floor for your target, you may be able to convince a thrown
+ object or cast spell to squeeze through a hole or corridor that is
+ blocking direct access to a different grid. Launching a ball spell
+ or breath weapon at a location in the middle of a group of monsters
+ can often improve the effects of that attack, since ball attacks are
+ not stopped by interposed monsters if the ball is launched at a target.
+ This command takes no time.
+~~~~~121|Commands|Looking
+#####R--- Looking Commands ---
+~~~~~25
+[[[[[GFull screen map (M)]
+ This command will show a map of the entire dungeon, reduced by a
+ factor of nine, on the screen. Only the major dungeon features
+ will be visible because of the scale, so even some important
+ objects may not show up on the map. This is particularly useful
+ in locating where the stairs are relative to your current
+ position, or for identifying unexplored areas of the dungeon.
+ This command takes no time.
+~~~~~23
+[[[[[GLocate player on map (L) or Where is the player (W)]
+ This command lets you scroll your map around, looking at all sectors
+ of the current dungeon level, until you press escape, at which point
+ the map will be re-centred on the player if necessary. To scroll
+ the map around, simply press any of the "direction" keys. The top
+ line will display the sector location, and the offset from your
+ current sector. This command takes no time.
+~~~~~22
+[[[[[GLook around (l) or Examine things (x)]
+ This command is used to look around at nearby monsters (to determine
+ their type and health) and objects (to determine their type). It is
+ also used to find out what objects (if any) are under monsters, and
+ if a monster is currently inside a wall. This command takes no time.
+ When you are looking at something, you may hit space for more details,
+ or to advance to the next interesting monster or object, or minus ("-")
+ to go back to the previous monster or object, or a direction key to
+ advance to the nearest interesting monster or object (if any) in that
+ general direction, or "r" to recall information about the current
+ monster race, or "q" or escape to stop looking around. You always
+ start out looking at the "nearest" interesting monster or object.
+~~~~~18
+[[[[[GObserve an item (I)]
+ This command lets you observe a previously *identified* item.
+ This will tell you things about the special powers of the object.
+ Currently, it only makes sense for artifacts and ego-items.
+~~~~~122|Commands|Messages
+#####R--- Message Commands ---
+~~~~~53
+[[[[[GRepeat level feeling (^F)]
+ Repeats the feeling about the dungeon level that you got when you
+ first entered the level.
+~~~~~62
+[[[[[GView previous messages (^P)]
+ This command shows you all the recent messages. You can scroll
+ through them, or exit with ESCAPE. This command takes no time.
+~~~~~69
+[[[[[GTake notes (:)]
+ This command allows you to take notes, which will then appear in your
+ note file, if the birth-option "take_notes" was set (the default), or
+ in your message list (prefixed with "Note:"), if the option was not set.
+ The note file can be displayed through the "Display Current Knowledge"
+ command (~ or |). This command takes no time.
+~~~~~123|Commands|Game status
+#####R--- Game Status Commands ---
+~~~~~6
+[[[[[GCharacter Description (C)]
+ Brings up a full description of your character, including your
+ skill levels, your current and potential stats, and various other
+ information. From this screen, you can change your name or use
+ the file character description command to save your character
+ status to a file. That command saves additional information,
+ including your background, your inventory, and the contents of
+ your house.
+~~~~~82
+[[[[[GDisplay Current Knowledge (~ or |)]
+ The command opens a menu from which you can lookup information
+ collected so far. This includes known artifacts, unique monsters,
+ identified objects, killed creatures, recall depths, acquired
+ corruptions, current pets, current quests, current fates, known
+ traps, known dungeon towns and last but not least the note file.
+
+ Display known artifacts
+ This selection lists all of the artifacts that you have encountered.
+ Any artifact that appears in this list, which you cannot seem to
+ find, has been lost forever. The "preserve" mode will prevent
+ you from accidentally losing any artifacts, but will also prevent
+ you from ever getting a "special" level feeling.
+
+ Display known uniques
+ Brings up a list of known unique monsters, plus their current
+ status. Once killed, unique monsters never show up again, with a
+ few remarkable exceptions.
+
+ Display known objects
+ This list all 'flavoured' objects (such as rings, scrolls, wands,
+ potions, etc.) which you have identified.
+
+ Display kill count
+ This lists all killed creatures together with a total kill count.
+
+ Display recall depths
+ This lists all recall depths of entered dungeons as well as marks
+ the current recall dungeon with an asterisk.
+
+ Display corruptions
+ This lists all acquired corruptions with their beneficial and
+ detrimental effects.
+
+ Display current pets
+ Display current quests
+ Display current fates
+ Display known traps
+ Display known dungeon towns
+
+ Display notes
+ If the option "take_notes" is set shows you your notes file, where all
+ remarkable events are noted. You can add notes yourself by using the
+ "Take notes" command (:).
+
+~~~~~70
+[[[[[GTime of the day (^T)]
+ This command is used to give the current date and time within the game.
+ Extremely useful for characters such as Vampires to check whether
+ it is safe to leave the dungeon.
+~~~~~124|Commands|Saving and Exiting
+~~~~~125|Saving and Exiting
+#####R--- Saving and Exiting Commands ---
+~~~~~75
+[[[[[GSave and Quit (Ctrl-X)]
+ To save your game so that you can return to it later, use this
+ command. Save files will also be generated (hopefully) if the
+ game crashes due to a system error. After you die, you can use
+ your savefile to play again with the same options and such.
+~~~~~68
+[[[[[GSave (Ctrl-S)]
+ This command saves the game but doesn't exit ToME. Use this
+ frequently if you are paranoid about having the computer crash
+ while you are playing.
+~~~~~31
+[[[[[GQuit (commit suicide) (Q)]
+ Kills your character and exits ToME. You will be prompted to
+ make sure you really want to do this, and then asked to verify
+ that choice. Note that dead characters are dead forever.
+~~~~~126|Commands|Pref files
+~~~~~127|Pref files|Commands
+#####R--- User pref file commands ---
+~~~~~65
+[[[[[GInteract with options (=)]
+ Allow you to interact with options. Note that using the "cheat"
+ options may mark your savefile as unsuitable for the high score
+ list. You may change normal options using the "X" and "Y" user
+ pref commands. You must use the "redraw" command (^R) after
+ changing certain options.
+~~~~~49
+[[[[[GInteract with macros (@)]
+ Allow you to interact with macros. You may load or save macros
+ from user pref files, create macros of various types, or define
+ keymaps. You must define a "current action", shown at the bottom
+ of the screen, before you attempt to use any of the "create macro"
+ commands, which use that "current action" as their action. This
+ is a horrible interface, and will be fixed eventually.
+~~~~~51
+[[[[[GInteract with visuals (%)]
+ Allow you to interact with visuals. You may load or save visuals
+ from user pref files, or modify the attr/char mappings for the
+ monsters, objects, and terrain features. You must use the "redraw"
+ command (^R) to redraw the map after changing attr/char mappings.
+~~~~~54
+[[[[[GInteract with colors (&)]
+ Allow the user to interact with colors. This command only
+ works on some systems.
+~~~~~47
+[[[[[GInteract with the system (!)]
+ Allow the user to interact with the underlying visual system.
+ This command is currently unused.
+~~~~~71
+[[[[[GEnter a user pref command (")]
+ ToME stores your preferences in files called "user pref files",
+ which contain comments and "user pref commands", which are simple strings
+ describing one aspect of the system about which the user has a preference.
+ You may enter single user pref commands directly, using the special "Enter
+ a user pref command" command, activated by "double quote". You may have to
+ use the "redraw" command (^R) after changing certain of the aspects of the
+ game, to allow ToME to adapt to your changes.
+~~~~~128|Commands|Help
+#####R--- Help ---
+~~~~~84
+[[[[[GHelp (?)]
+ Brings up the ToME on-line help system. Note that the help
+ files are just text files in a particular format, and that other
+ help files may be available on the Net. In particular, there are
+ a variety of spoiler files which do not come with the standard
+ distribution. Check the place you got ToME from or ask on the
+ newsgroup rec.games.roguelike.angband about them.
+~~~~~83
+[[[[[GIdentify Symbol (/)]
+ Use this command to find out what a character stands for. For
+ instance, by pressing "/.", you can find out that the "." symbol
+ stands for a floor spot. When used with a symbol that represents
+ creatures, the this command will tell you only what class of
+ creature the symbol stands for, not give you specific information
+ about a creature you can see. To get that, use the Look command.
+
+ There are three special symbols you can use with the Identify
+ Symbol command to access specific parts of your monster memory.
+ Typing Ctrl-A when asked for a symbol will recall details about
+ all monsters, typing Ctrl-U will recall details about all unique
+ monsters, and typing Ctrl-N will recall details about all
+ non-unique monsters.
+
+ If the character stands for a creature, you are asked if you want
+ to recall details. If you answer yes, information about the
+ creatures you have encountered with that symbol is shown in the
+ Recall window if available, or on the screen if not. You can also
+ answer "k" to see the list sorted by number of kills, or "p" to
+ see the list sorted by dungeon level the monster is normally found
+ on. Pressing ESCAPE at any point will exit this command.
+~~~~~41
+[[[[[GGame Version (V)]
+ This command will tell you what version of ToME you are using.
+ For more information, see the "version.txt" help file.
+
+~~~~~129|Commands|Extras
+#####R--- Extra Commands ---
+~~~~~85
+[[[[[GRepeat last command (n)]
+ This will automatically repeat the last command you inputted.
+~~~~~27
+[[[[[GSacrifice at an altar (O)]
+ Altars are places dedicated to the worship of a particular God. To
+ start worshipping the God who owns the altar, you must first sacrifice
+ on their altar.
+
+ Be warned, not all Gods are equal in power, and once you have selected
+ a God to worship, it is almost impossible to change which God you worship.
+ When your God is happy with you, you will receive more benefits from them.
+ Your God's happiness will decrease over time, so you will need to accomplish
+ deeds that increase your standing. Note that there is no requirement
+ for most classes to worship any God. (See *****gods.txt*0[gods.txt] for more information)
+~~~~~28
+[[[[[GPray to your God (p)]
+ If you worship a God, you have the option of praying. The effects of
+ praying differ considerably depending on the god, ranging from the
+ battle frenzy of paladins to the self-healing powers of druids.
+ However, Gods do not like being disturbed, with negative effects on
+ your piety. See *****gods.txt*0[gods.txt] for more information.
+~~~~~29
+[[[[[GPet commands (P)]
+ From time to time, you may acquire a pet within the dungeon. Pets are able
+ (to a more or less limited extent) to follow some simple commands, like
+ follow me. These commands are all accessed through the menu under "Pet
+ Commands".
+~~~~~52
+[[[[[GToggle Choice Window (^E)]
+ Toggles the display in the choice window (if available) between
+ your inventory and your equipment. This command only applies if
+ you are running ToME under a windowing environment and the
+ choice window is available. This also redraws the choice window.
+~~~~~66
+[[[[[GRedraw Screen (^R)]
+ This command adapts to various changes in global options, and
+ redraws all of the windows. This command should be used after
+ changing various global properties (options, attr/char mappings,
+ color definitions, etc). When in doubt, use it.
+~~~~~56
+[[[[[GLoad screen dump (left-paren)]
+ This command loads a "snap-shot" of the current screen from the file
+ "dump.txt", and displays it on the screen.
+~~~~~57
+[[[[[GSave screen dump (right-paren)]
+ This command dumps a "snap-shot" of the current screen to the file
+ "dump.txt", including encoded color information.
+~~~~~64
+[[[[[GQuit to next midi song (^Q)]
+ In the DOS binary (and maybe Windows) of ToME, it is possible for
+ the game to play any midi song in the lib/xtra/music directory. This
+ command allows the player to force the game to finish the current song
+ and move on to another one (i.e. if you are tired of hearing the current
+ song, you can change it).
+~~~~~80
+[[[[[GDo cmovies (|)]
+ The cmovie command (press | key in both normal or roguelike set) allows
+ you to make a "movie" that you can send to people showing your movement
+ through a part of the dungeon (like clearing that GCV . . .)
+
+ It asks for a name (it will add the extension itself) and then if you wish
+ to play or record it.
+
+ The cmovie files (.cmv) are located in lib/cmov, note that they quickly
+ become huge and so you REALLY should compress them before sending to friends.
+~~~~~97
+[[[[[GRecord macros ($)]
+ This is an easier way to create macros. Activate it, press the key
+ sequence for your macro, reactivate it and it will create the macro
+ for you. Note than when possible using the @ key at item selection
+ is a good idea since it removes the need to inscribe items.
+~~~~~98
+[[[[[GTake html screenshot (^\])]
+ Creates an html screenshot of the current screen.
+~~~~~89
+[[[[[GBegin extended command (#)]
+ Begins an extended command. Type "help" or "?" at the prompt for a
+ list of these commands.
+
+--
+Original: Alexander Cutler and Andy Astrand
+Updated (2.7.6): Russ Allbery (rra@cs.stanford.edu)
+Updated (2.7.9): Ben Harrison (benh@phial.com)
+Updated PernAngband 5.x.x: Dawnmist (angband@dawnmist.8m.com)
+Updated for ToME 2.1
diff --git a/lib/help/corspoil.txt b/lib/help/corspoil.txt
new file mode 100644
index 00000000..baac4fae
--- /dev/null
+++ b/lib/help/corspoil.txt
@@ -0,0 +1,136 @@
+~~~~~01|Corruptions (Spoiler)
+~~~~~02|Spoilers|Corruptions
+#####R=== ToME Corruptions Spoiler ===
+
+Sometimes adventurers become exposed to the dark powers of Morgoth. If they
+are unable to resist these powers, they become corrupted. Corruptions can
+change their physical or mental abilities, some of which can be good, and
+some bad. Most corruptions will affect you permanently, although some only
+operate when they are activated (whether by player choice or as a random
+event). You can check which corruptions do you have in the knowledge screen
+6 (accessed through the '~' menu) or in a character dump.
+
+#####GGaining and (not) losing corruptions
+There are several ways that you can become corrupted.
+
+You can become corrupted by quaffing a Potion of Corruption or by drinking
+from a Fountain of Corruption. Also some strange items can be activated
+for corruption.
+
+Corruptions are permanent. Once you have one, you have it for life.
+
+[[[[[BBalrog Aura]
+ Surrounds you with a fiery aura
+ But it can burn scrolls when you read them
+[[[[[GGain message: A corrupted wall of flames surrounds you.]
+[[[[[RLose message: The wall of corrupted flames abandons you.]
+
+
+[[[[[BBalrog Wings]
+ Creates ugly, but working, wings allowing you to fly
+ But it reduces charisma by 4 and dexterity by 2
+[[[[[GGain message: Wings of shadow grow in your back.]
+[[[[[RLose message: The wings in your back fall apart.]
+
+
+[[[[[BBalrog Strength]
+ Provides 3 strength and 1 constitution
+ But it reduces charisma by 1 and dexterity by 3
+[[[[[GGain message: Your muscles get unnatural strength.]
+[[[[[RLose message: Your muscles get weaker again.]
+
+
+[[[[[BBalrog Form]
+ Allows you to turn into a Balrog at will
+ You need Balrog Aura, Balrog Wings and Balrog Strength to activate it
+[[[[[GGain message: You feel the might of a Balrog inside you.]
+[[[[[RLose message: The presence of the Balrog seems to abandon you.]
+It depends on:
+ Balrog Aura
+ Balrog Wings
+ Balrog Strength
+
+
+[[[[[BDemon Spirit]
+ Increases your intelligence by 1
+ But reduce your charisma by 2
+[[[[[GGain message: Your spirit opens to corrupted thoughts.]
+[[[[[RLose message: Your spirit closes again to the corrupted thoughts.]
+
+
+[[[[[BDemon Hide]
+ Increases your armour class by your level
+ Provides immunity to fire at level 40
+ But reduces speed by your level / 7
+[[[[[GGain message: Your skin grows into a thick hide.]
+[[[[[RLose message: Your skin returns to a natural state.]
+
+
+[[[[[BDemon Breath]
+ Provides fire breath
+ But gives a small chance to spoil potions when you quaff them
+[[[[[GGain message: Your breath becomes mephitic.]
+[[[[[RLose message: Your breath is once again normal.]
+
+
+[[[[[BDemon Realm]
+ Provides access to the demon school skill and the use of demonic equipment
+ You need Demon Spirit, Demon Hide and Demon Breath to activate it
+[[[[[GGain message: You feel more attuned to the demon realm.]
+[[[[[RLose message: You lose your attunement to the demon realm.]
+It depends on:
+ Demon Spirit
+ Demon Hide
+ Demon Breath
+
+
+[[[[[BRandom teleportation]
+ Randomly teleports you around
+[[[[[GGain message: Space seems to fizzle around you.]
+[[[[[RLose message: Space solidify again around you.]
+It is opposed to:
+ Anti-teleportation
+
+
+[[[[[BAnti-teleportation]
+ Prevents all teleportations, be it of you or monsters
+[[[[[GGain message: Space continuum freezes around you.]
+[[[[[RLose message: Space continuum can once more be altered around you.]
+It is opposed to:
+ Random teleportation
+
+
+[[[[[BTroll Blood]
+ Troll blood flows in your veins, granting increased regeneration
+ It also enables you to feel the presence of other troll beings
+ But it will make your presence more noticeable and aggravating
+[[[[[GGain message: Your blood thickens, you sense corruption in it.]
+[[[[[RLose message: Your blood returns to a normal state.]
+
+
+[[[[[BVampiric Teeth]
+ Your teeth allow you to drain blood to feed yourself
+ However your stomach now only accepts blood.
+[[[[[GGain message: You grow vampiric teeth!]
+It is not removable.
+
+
+[[[[[BVampiric Strength]
+ Your body seems somewhat dead
+ In this near-undead state it has improved strength, constitution and
+ intelligence, but also reduced dexterity, wisdom and charisma.
+[[[[[GGain message: Your body seems more dead than alive.]
+It is not removable.
+It depends on:
+ Vampiric Teeth
+
+
+[[[[[BVampire]
+ You are a Vampire. As such you resist cold, poison, darkness and nether.
+ Your life is sustained, but you cannot stand the light of the sun.
+[[[[[GGain message: You die to be reborn in a Vampire form.]
+It is not removable.
+It depends on:
+ Vampiric Strength
+
+
diff --git a/lib/help/debug.txt b/lib/help/debug.txt
new file mode 100644
index 00000000..4d5e75da
--- /dev/null
+++ b/lib/help/debug.txt
@@ -0,0 +1,275 @@
+|||||oy
+~~~~~99|Debug
+#####R=== Debug Commands ===
+
+
+Debug commands are entered as an "underlying command" (a single key)
+plus a variety of optional or required arguments.
+
+The debug commands are used for debugging and experimenting. The game
+will not be scored if you use debug commands.
+
+~~~~~100|Debug|Command List
+#####R=== Command List Summary ===
+
+ *****debug.txt*1[a Autorestore] *****debug.txt*2[A Show all stats]
+ *****debug.txt*3[b Teleport to target] *****debug.txt*4[B HP to zero]
+ *****debug.txt*5[c Create object] *****debug.txt*6[C Create artifact]
+ *****debug.txt*7[d Detect all] *****debug.txt*8[D Teleport to the wilderness]
+ *****debug.txt*9[e Edit character attributes] *****debug.txt*10[E Change grid's mana]
+ *****debug.txt*11[f *IDENTIFY*] *****debug.txt*12[F Features]
+ *****debug.txt*13[g Create good item] G (unused)
+ *****debug.txt*15[h Change life rating] *****debug.txt*16[H Hostile monster creation]
+ *****debug.txt*17[i Identify] I (unused)
+ *****debug.txt*19[j Jump to other level] J (unused)
+ *****debug.txt*21[k Check attributes] K (unused)
+ *****debug.txt*23[l Learn about objects] L (unused)
+ *****debug.txt*25[m Magic Mapping] *****debug.txt*26[M Gain corruption]
+ *****debug.txt*27[n Summon named monster] *****debug.txt*28[N Summon _friendly_ named monster]
+ *****debug.txt*29[o Edit object attributes] O (unused)
+ *****debug.txt*31[p Phase door] P (unused)
+ *****debug.txt*33[q Get a quest] Q (unused)
+ *****debug.txt*35[r Gain reward] *****debug.txt*36[R Create a trap]
+ *****debug.txt*37[s Summon monster] *****debug.txt*38[S Change the feature of the map]
+ *****debug.txt*39[t Teleport] *****debug.txt*40[T Teleport to a town]
+ *****debug.txt*41[u Complete map] *****debug.txt*42[U Become undead]
+ *****debug.txt*43[v Random artifact/ego item] V (unused)
+ *****debug.txt*45[w Wizard light the level] *****debug.txt*46[W Wish]
+ *****debug.txt*47[x XP boost] X (unused)
+ y (unused) Y (unused)
+ *****debug.txt*51[z Zap monsters] Z (unused)
+ ! (unused) ^A (unused)
+ *****debug.txt*55[@ Increment monster level] ^B (unused)
+ # (unused) ^C (unused)
+ $ (unused) ^D (unused)
+ % (unused) ^E (unused)
+ ^ (unused) ^F (unused)
+ & (unused) ^G (unused)
+ *****debug.txt*61[* Lose special powers] ^H (unused)
+ ( (unused) ^I (unused)
+ ) (unused) ^J (unused)
+ { (unused) ^K (unused)
+ } (unused) ^L (unused)
+ [ (unused) ^M (unused)
+ ] (unused) ^N (unused)
+ *****debug.txt*67[- Create object] ^O (unused)
+ *****debug.txt*69[_ The path to the god dark] ^P (unused)
+ *****debug.txt*71[+ Gain a fate] ^Q (unused)
+ *****debug.txt*73[= Align monster] ^R (unused)
+ ; (unused) ^S (unused)
+ : (unused) ^T (unused)
+ ' (unused) ^U (unused)
+ *****debug.txt*75[" Create spoiler] ^V (unused)
+ , (unused) ^W (unused)
+ < (unused) ^X (unused)
+ . (unused) ^Y (unused)
+ *****debug.txt*81[> Lua script] ^Z (unused)
+ \ (unused) | (unused)
+ ` (unused) ~ (unused)
+ *****debug.txt*91[/ Summon monster] *****debug.txt*92[? Help]
+ ^\ (unused)
+
+~~~~~111|Debug|Command descriptions
+#####R=== Command Descriptions ===
+
+ The following command descriptions are listed as the command name
+plus the "underlying command" key. Then comes a brief description of the
+command. Some commands use the "repeat count" to automatically repeat the
+command several times, while others use the "repeat count" as an "argument",
+for example, commands which need a "quantity" will use the "repeat count"
+instead of asking for a quantity, allowing the use of "0d" for "drop all".
+Commands which ask for a quantity will convert any "letters" into the
+maximal legal value.
+~~~~~112|Debug|General
+#####R--- General Commands ---
+~~~~~1
+[[[[[GAutorestore (a)]
+ Restores all your stats. This includes HP, SP, hunger, lost levels, etc.
+~~~~~2
+[[[[[GShow all stats (A)]
+ This brings up the Character status menu, where you can view
+ all the stats about your character.
+~~~~~3
+[[[[[GTeleport to target (b)]
+ You first need to have a monster targeted, then you can use
+ this command to teleport next to the monster.
+~~~~~4
+[[[[[GHP to zero (B)]
+ Bring your health down to zero.
+~~~~~5
+[[[[[GCreate object (c)]
+ Allows you to select and create a new object where you stand.
+ This brings up a menu where you can choose what type of object
+ you want created.
+~~~~~6
+[[[[[GCreate artifact (C)]
+ Allows you to select and create a new artifact where you stand.
+ Use the "Command count", aka 0, to specify a number from
+ a_info.txt to put it on the ground where you are standing.
+ For example : 03^AC will create the Arkenstone of Thrane (+3)
+~~~~~7
+[[[[[GDetect all (d)]
+ Sense ways out/monsters/objects/traps.
+~~~~~8
+[[[[[GTeleport to the wilderness (D)]
+ From a dungeon this will teleport you to the wilderness level
+ and if used in the wilderness it acts like teleport.
+~~~~~9
+[[[[[GEdit character attributes (e)]
+ Edit character attributes including Str, Int, Dex, experience, gold, luck, etc.
+~~~~~10
+[[[[[GChange grid's mana (E)]
+ Alter how much mana a grid has.
+ Use the "Command count", aka 0, to specify the amount of mana
+ that you want.
+~~~~~11
+[[[[[G*IDENTIFY* (f)]
+ Like a Scroll of *Identify*.
+~~~~~12
+[[[[[GFeatures (F)]
+ Use the "Command count", aka 0, to specify a number from
+ f_info.txt to put a feature on the ground where you are
+ standing.
+~~~~~13
+[[[[[GCreate good item (g)]
+ Create a random good item where you stand.
+~~~~~15
+[[[[[GChange life rating (h)]
+ Change your life rating.
+~~~~~16
+[[[[[GHostile monster creation (H)]
+ Summons a Pack of Creatures of the same kind. Will only work
+ if MONSTER_HORDES has been defined at compile time.
+~~~~~17
+[[[[[GIdentify (i)]
+ Like a Scroll of Identify.
+~~~~~19
+[[[[[GJump to other level (j)]
+ Jump to other dungeon level. This does not work in the
+ wilderness as it is treated as all one level.
+~~~~~21
+[[[[[GCheck attributes (k)]
+ Displays your characters attributes.
+~~~~~23
+[[[[[GLearn about objects (l)]
+ Make you know about all objects. Not sure how this works.
+~~~~~25
+[[[[[GMagic Mapping (m)]
+ Like a Scroll of Magic mapping.
+~~~~~26
+[[[[[GGain corruption (M)]
+ Allows your character to gain a corruption.
+~~~~~27
+[[[[[GSummon named monster (n)]
+ Summon a monster that will appear next to you.
+ Use the "Command count", aka 0, to specify a number from
+ r_info.txt to summon a monster.
+~~~~~28
+[[[[[GSummon _friendly_ named monster (N)]
+ The same as n but the creature will be your pet. Try this
+ with number 861, Darkgod is now your pet.
+~~~~~29
+[[[[[GEdit object attributes (o)]
+ Allows you to alter the attributes of any object that you
+ have in your backpack.
+~~~~~31
+[[[[[GPhase door (p)]
+ Like a Scroll of Phase Door.
+~~~~~33
+[[[[[GGet a quest (q)]
+ Get a quest.
+ Use the "Command count", aka 0, to specify a number from
+ 1 to 25, as defined in defines.h ( the QUEST_XXX items ).
+ For example : 04^Aq will get you the thieves quest.
+~~~~~35
+[[[[[GGain reward (r)]
+ Some high being grants you a reward.
+~~~~~36
+[[[[[GCreate a trap (R)]
+ Use the "Command count", aka 0, to specify a number from
+ tr_info.txt to put a trap on the ground where you are
+ standing.
+~~~~~37
+[[[[[GSummon monster (s)]
+ Summon a random monster, next to where you stand.
+~~~~~38
+[[[[[GChange the feature of the map (S)]
+ This allows you to change the "special" field of the current
+ grid. This special field is used to store things like quest
+ ids, dungeon entries, and so on, not to be used unless
+ one knows what it's doing.
+~~~~~39
+[[[[[GTeleport (t)]
+ Like a Scroll of Teleport.
+~~~~~40
+[[[[[GTeleport to a town (T)]
+ Teleports you to a specific town.
+ Use the "Command count", aka 0, to specify a number from
+ wf_info.txt for where you want to go.
+ standing.
+ For example : 02^AT will teleport you to Gondolin
+~~~~~41
+[[[[[GComplete map (u)]
+ Displays the complete map of the dungeon.
+~~~~~42
+[[[[[GBecome undead (U)]
+ This is supposed to make you undead (as in the Necromantic power).
+~~~~~43
+[[[[[GRandom artifact/ego item (v)]
+ Create a random artifact/ego item where you stand.
+~~~~~45
+[[[[[GWizard light the level (w)]
+ Looks like the same as u.
+~~~~~46
+[[[[[GWish (W)]
+ Makes all your wishes come true.
+
+ Read the *****wishing.txt*0[wishing spoiler] to see how these work.
+~~~~~47
+[[[[[GXP boost (x)]
+ Use the "Command count", aka 0, to specify the increment,
+ if you do not specify a parameter it doubles your XP,
+ otherwise it increments by the specified amount.
+~~~~~51
+[[[[[GZap monsters (z)]
+ All monsters in sight range vanish like Mass Genocide, only with no
+ HP price.
+~~~~~55
+[[[[[GIncrement monster level (@)]
+ Level up a monster.
+~~~~~61
+[[[[[GLose special powers (*)]
+ Returns your powers to a normal level.
+~~~~~67
+[[[[[GCreate object (-)]
+ Allows you to create a new object where you stand. You must
+ specify an object number from k_info.txt.
+~~~~~69
+[[[[[GThe path to the god dark (_)]
+ Do not use this as it is used by DarkGod as a test for Lua
+ and will CRASH the game. You have been warned.
+~~~~~71
+[[[[[GGain a fate (+)]
+ Unearth more of your prophecy.
+~~~~~73
+[[[[[GAlign monster (=)]
+ Use the "Command count", aka 0, to specify one of the following
+ alignment types:
+ 0 monster becomes enemy
+ 1 monster becomes neutral
+ 2 monster becomes friendly
+ 3 monster becomes pet
+ 4 monster becomes companion
+ You then point at an enemy and press space.
+~~~~~75
+[[[[[GCreate spoiler (")]
+ Brings up a menu that allows you to create a spoiler file.
+~~~~~81
+[[[[[GLua script (>)]
+ Allows you to run a Lua script.
+~~~~~91
+[[[[[GSummon monster (/)]
+ Summons a random monster next to you.
+~~~~~91
+[[[[[GHelp (?)]
+ Displays the main help file.
diff --git a/lib/help/def.aux b/lib/help/def.aux
new file mode 100644
index 00000000..983e9683
--- /dev/null
+++ b/lib/help/def.aux
@@ -0,0 +1,3 @@
+file_ext="html"
+link_prefix=""
+link_suffix=""
diff --git a/lib/help/defines.txt b/lib/help/defines.txt
new file mode 100644
index 00000000..ac997501
--- /dev/null
+++ b/lib/help/defines.txt
@@ -0,0 +1,639 @@
+|||||oy
+~~~~~81|Defines
+~~~~~85|Defines|Tvals
+~~~~~82|Automatizer|Defines
+~~~~~83|Tvals
+#####R /----------------------------------------\
+#####R < Tvals and svals >
+#####R \----------------------------------------/
+
+Some objects don't have svals as such. Spellbooks, wands, and staves for
+instance don't have svalues as they are defined in lua.
+
+TV_SKELETON 1 /* Skeletons ('s') */
+TV_BOTTLE 2 /* Empty bottles ('!') */
+*****defines.txt*04[TV_BATERIE] 4 /* For the Alchemists */
+TV_SPIKE 5 /* Spikes ('~') */
+TV_MSTAFF 6 /* Mage Staffs */
+TV_CHEST 7 /* Chests ('~') */
+TV_PARCHMENT 8 /* Parchments from Kamband */
+*****defines.txt*09[TV_CORPSE] 9 /* Monster corpses */
+TV_EGG 10 /* Monster Eggs */
+TV_JUNK 11 /* Sticks, Pottery, etc ('~') */
+*****defines.txt*12[TV_TOOL] 12 /* Tools */
+*****defines.txt*14[TV_INSTRUMENT] 14 /* Musical instruments */
+*****defines.txt*15[TV_BOOMERANG] 15 /* Boomerangs */
+*****defines.txt*16[TV_SHOT] 16 /* Ammo for slings */
+*****defines.txt*16[TV_ARROW] 17 /* Ammo for bows */
+*****defines.txt*16[TV_BOLT] 18 /* Ammo for x-bows */
+*****defines.txt*19[TV_BOW] 19 /* Slings/Bows/Xbows */
+*****defines.txt*20[TV_DIGGING] 20 /* Shovels/Picks */
+*****defines.txt*21[TV_HAFTED] 21 /* Priest Weapons */
+*****defines.txt*22[TV_POLEARM] 22 /* Pikes/Glaives/Spears/etc. */
+*****defines.txt*23[TV_SWORD] 23 /* Edged Weapons */
+*****defines.txt*24[TV_AXE] 24 /* Axes/Cleavers */
+*****defines.txt*30[TV_BOOTS] 30 /* Boots */
+*****defines.txt*31[TV_GLOVES] 31 /* Gloves */
+*****defines.txt*32[TV_HELM] 32 /* Helms */
+*****defines.txt*32[TV_CROWN] 33 /* Crowns */
+*****defines.txt*34[TV_SHIELD] 34 /* Shields */
+*****defines.txt*35[TV_CLOAK] 35 /* Cloaks */
+*****defines.txt*36[TV_SOFT_ARMOR] 36 /* Soft Armor */
+*****defines.txt*37[TV_HARD_ARMOR] 37 /* Hard Armor */
+*****defines.txt*38[TV_DRAG_ARMOR] 38 /* Dragon Scale Mail */
+*****defines.txt*39[TV_LITE] 39 /* Lites (including Specials) */
+*****defines.txt*40[TV_AMULET] 40 /* Amulets (including Specials) */
+*****defines.txt*45[TV_RING] 45 /* Rings (including Specials) */
+*****defines.txt*46[TV_TRAPKIT] 46 /* Trapkits */
+TV_TOTEM 54 /* Summoner totems */
+*****defines.txt*55[TV_STAFF] 55 /* Staffs */
+*****defines.txt*65[TV_WAND] 65 /* Wands */
+*****defines.txt*66[TV_ROD] 66 /* Rod tips */
+*****defines.txt*67[TV_ROD_MAIN] 67 /* Rod body's */
+*****defines.txt*70[TV_SCROLL] 70 /* Scrolls */
+*****defines.txt*71[TV_POTION] 71 /* potions */
+*****defines.txt*72[TV_POTION2] 72 /* Second set of potion */
+TV_FLASK 77 /* Flasks of oil */
+*****defines.txt*80[TV_FOOD] 80 /* Food, including mushrooms */
+TV_HYPNOS 99 /* To wield monsters !:) */
+TV_GOLD 100 /* Gold can only be picked up by players */
+TV_RANDART 102 /* Random Artifacts */
+TV_RUNE1 104 /* Base runes */
+TV_RUNE2 105 /* Modifier runes */
+TV_BOOK 111 /* spell books */
+*****defines.txt*115[TV_DAEMON_BOOK] 115 /* Demon blades, shields and horns */
+~~~~~84|Defines|Svals
+~~~~~12|Svals
+/* The "sval" codes for TV_TOOL */
+ SV_TOOL_CLIMB 0
+ SV_PORTABLE_HOLE 1
+~~~~~16
+/* The "sval" codes for TV_SHOT/TV_ARROW/TV_BOLT */
+ SV_AMMO_LIGHT 0 /* pebbles */
+ SV_AMMO_NORMAL 1 /* shots, arrows, bolts */
+ SV_AMMO_HEAVY 2 /* seeker arrows and bolts, mithril shots */
+~~~~~14
+/* The "sval" codes for TV_INSTRUMENT */
+ SV_FLUTE 1
+ SV_BANJO 2
+ SV_LUTE 3
+ SV_MANDOLIN 4
+ SV_DRUM 5
+ SV_HARP 6
+ SV_HORN 7
+~~~~~46
+/* The "sval" codes for TV_TRAPKIT */
+ SV_TRAPKIT_SLING 1
+ SV_TRAPKIT_BOW 2
+ SV_TRAPKIT_XBOW 3
+ SV_TRAPKIT_POTION 4
+ SV_TRAPKIT_SCROLL 5
+ SV_TRAPKIT_DEVICE 6
+~~~~~15
+/* The "sval" codes for TV_BOOMERANG */
+ SV_BOOM_S_WOOD 1 /* 1d4 */
+ SV_BOOM_WOOD 2 /* 1d9 */
+ SV_BOOM_S_METAL 3 /* 1d8 */
+ SV_BOOM_METAL 4 /* 2d4 */
+~~~~~19
+/* The "sval" codes for TV_BOW (note information in "sval") */
+ SV_SLING 2 /* (x2) */
+ SV_SHORT_BOW 12 /* (x2) */
+ SV_LONG_BOW 13 /* (x3) */
+ SV_LIGHT_XBOW 23 /* (x3) */
+ SV_HEAVY_XBOW 24 /* (x4) */
+~~~~~20
+/* The "sval" codes for TV_DIGGING */
+ SV_SHOVEL 1
+ SV_GNOMISH_SHOVEL 2
+ SV_DWARVEN_SHOVEL 3
+ SV_PICK 4
+ SV_ORCISH_PICK 5
+ SV_DWARVEN_PICK 6
+ SV_MATTOCK 7
+~~~~~21
+/* The "sval" values for TV_HAFTED */
+ SV_CLUB 1 /* 1d4 */
+ SV_WHIP 2 /* 1d6 */
+ SV_QUARTERSTAFF 3 /* 1d9 */
+ SV_NUNCHAKU 4 /* 2d3 */
+ SV_MACE 5 /* 2d4 */
+ SV_BALL_AND_CHAIN 6 /* 2d4 */
+ SV_WAR_HAMMER 8 /* 3d3 */
+ SV_LUCERN_HAMMER 10 /* 2d5 */
+ SV_THREE_PIECE_ROD 11 /* 3d3 */
+ SV_MORNING_STAR 12 /* 2d6 */
+ SV_FLAIL 13 /* 2d6 */
+ SV_LEAD_FILLED_MACE 15 /* 3d4 */
+ SV_TWO_HANDED_FLAIL 18 /* 3d6 */
+ SV_GREAT_HAMMER 19 /* 4d6 */
+ SV_MACE_OF_DISRUPTION 20 /* 5d8 */
+ SV_GROND 50 /* 3d4 */
+~~~~~24
+/* The "sval" values for TV_AXE */
+ SV_HATCHET 1 /* 1d5 */
+ SV_CLEAVER 2 /* 2d4 */
+ SV_LIGHT_WAR_AXE 8 /* 2d5 */
+ SV_BEAKED_AXE 10 /* 2d6 */
+ SV_BROAD_AXE 11 /* 2d6 */
+ SV_BATTLE_AXE 22 /* 2d8 */
+ SV_GREAT_AXE 25 /* 4d4 */
+ SV_LOCHABER_AXE 28 /* 3d8 */
+ SV_SLAUGHTER_AXE 30 /* 5d7 */
+~~~~~22
+/* The "sval" values for TV_POLEARM */
+ SV_SPEAR 2 /* 1d6 */
+ SV_SICKLE 3 /* 2d3 */
+ SV_AWL_PIKE 4 /* 1d8 */
+ SV_TRIDENT 5 /* 1d9 */
+ SV_FAUCHARD 6 /* 1d10 */
+ SV_BROAD_SPEAR 7 /* 1d9 */
+ SV_PIKE 8 /* 2d5 */
+ SV_GLAIVE 13 /* 2d6 */
+ SV_HALBERD 15 /* 3d4 */
+ SV_GUISARME 16 /* 2d5 */
+ SV_SCYTHE 17 /* 5d3 */
+ SV_LANCE 20 /* 2d8 */
+ SV_TRIFURCATE_SPEAR 26 /* 2d9 */
+ SV_HEAVY_LANCE 29 /* 4d8 */
+ SV_SCYTHE_OF_SLICING 30 /* 8d4 */
+~~~~~23
+/* The "sval" codes for TV_SWORD */
+ SV_BROKEN_DAGGER 1 /* 1d1 */
+ SV_BROKEN_SWORD 2 /* 1d2 */
+ SV_DAGGER 4 /* 1d4 */
+ SV_MAIN_GAUCHE 5 /* 1d5 */
+ SV_RAPIER 7 /* 1d6 */
+ SV_SMALL_SWORD 8 /* 1d6 */
+ SV_BASILLARD 9 /* 1d8 */
+ SV_SHORT_SWORD 10 /* 1d7 */
+ SV_SABRE 11 /* 1d7 */
+ SV_CUTLASS 12 /* 1d7 */
+ SV_KHOPESH 14 /* 2d4 */
+ SV_TULWAR 15 /* 2d4 */
+ SV_BROAD_SWORD 16 /* 2d5 */
+ SV_LONG_SWORD 17 /* 2d5 */
+ SV_SCIMITAR 18 /* 2d5 */
+ SV_KATANA 20 /* 3d4 */
+ SV_BASTARD_SWORD 21 /* 3d4 */
+ SV_GREAT_SCIMITAR 22 /* 4d5 */
+ SV_CLAYMORE 23 /* 2d8 */
+ SV_ESPADON 24 /* 2d9 */
+ SV_TWO_HANDED_SWORD 25 /* 3d6 */
+ SV_FLAMBERGE 26 /* 3d7 */
+ SV_EXECUTIONERS_SWORD 28 /* 4d5 */
+ SV_ZWEIHANDER 29 /* 4d6 */
+ SV_BLADE_OF_CHAOS 30 /* 6d5 */
+ SV_SHADOW_BLADE 31 /* 4d4 */
+ SV_BLUESTEEL_BLADE 32 /* 3d9 */
+ SV_DARK_SWORD 33 /* 3d7 */
+~~~~~34
+/* The "sval" codes for TV_SHIELD */
+ SV_SMALL_LEATHER_SHIELD 2
+ SV_SMALL_METAL_SHIELD 3
+ SV_LARGE_LEATHER_SHIELD 4
+ SV_LARGE_METAL_SHIELD 5
+ SV_DRAGON_SHIELD 6
+ SV_SHIELD_OF_DEFLECTION 10
+~~~~~32
+/* The "sval" codes for TV_HELM */
+ SV_HARD_LEATHER_CAP 2
+ SV_METAL_CAP 3
+ SV_IRON_HELM 5
+ SV_STEEL_HELM 6
+ SV_DRAGON_HELM 7
+ SV_IRON_CROWN 10
+ SV_GOLDEN_CROWN 11
+ SV_JEWELED_CROWN 12
+ SV_MORGOTH 50
+~~~~~30
+/* The "sval" codes for TV_BOOTS */
+ SV_PAIR_OF_SOFT_LEATHER_BOOTS 2
+ SV_PAIR_OF_HARD_LEATHER_BOOTS 3
+ SV_PAIR_OF_METAL_SHOD_BOOTS 6
+~~~~~35
+/* The "sval" codes for TV_CLOAK */
+ SV_CLOAK 1
+ SV_ELVEN_CLOAK 2
+ SV_FUR_CLOAK 3
+ SV_SHADOW_CLOAK 6
+~~~~~31
+/* The "sval" codes for TV_GLOVES */
+ SV_SET_OF_LEATHER_GLOVES 1
+ SV_SET_OF_GAUNTLETS 2
+ SV_SET_OF_CESTI 5
+~~~~~36
+/* The "sval" codes for TV_SOFT_ARMOR */
+ SV_FILTHY_RAG 1
+ SV_ROBE 2
+ SV_PAPER_ARMOR 3 /* 4 */
+ SV_SOFT_LEATHER_ARMOR 4
+ SV_SOFT_STUDDED_LEATHER 5
+ SV_HARD_LEATHER_ARMOR 6
+ SV_HARD_STUDDED_LEATHER 7
+ SV_RHINO_HIDE_ARMOR 8
+ SV_CORD_ARMOR 9 /* 6 */
+ SV_PADDED_ARMOR 10 /* 4 */
+ SV_LEATHER_SCALE_MAIL 11
+ SV_LEATHER_JACK 12
+ SV_STONE_AND_HIDE_ARMOR 15 /* 15 */
+ SV_THUNDERLORD_SUIT 16
+~~~~~37
+/* The "sval" codes for TV_HARD_ARMOR */
+ SV_RUSTY_CHAIN_MAIL 1 /* 14- */
+ SV_RING_MAIL 2 /* 12 */
+ SV_METAL_SCALE_MAIL 3 /* 13 */
+ SV_CHAIN_MAIL 4 /* 14 */
+ SV_DOUBLE_RING_MAIL 5 /* 15 */
+ SV_AUGMENTED_CHAIN_MAIL 6 /* 16 */
+ SV_DOUBLE_CHAIN_MAIL 7 /* 16 */
+ SV_BAR_CHAIN_MAIL 8 /* 18 */
+ SV_METAL_BRIGANDINE_ARMOUR 9 /* 19 */
+ SV_SPLINT_MAIL 10 /* 19 */
+ SV_PARTIAL_PLATE_ARMOUR 12 /* 22 */
+ SV_METAL_LAMELLAR_ARMOUR 13 /* 23 */
+ SV_FULL_PLATE_ARMOUR 15 /* 25 */
+ SV_RIBBED_PLATE_ARMOUR 18 /* 28 */
+ SV_MITHRIL_CHAIN_MAIL 20 /* 28+ */
+ SV_MITHRIL_PLATE_MAIL 25 /* 35+ */
+ SV_ADAMANTITE_PLATE_MAIL 30 /* 40+ */
+~~~~~38
+/* The "sval" codes for TV_DRAG_ARMOR */
+ SV_DRAGON_BLACK 1
+ SV_DRAGON_BLUE 2
+ SV_DRAGON_WHITE 3
+ SV_DRAGON_RED 4
+ SV_DRAGON_GREEN 5
+ SV_DRAGON_MULTIHUED 6
+ SV_DRAGON_SHINING 10
+ SV_DRAGON_LAW 12
+ SV_DRAGON_BRONZE 14
+ SV_DRAGON_GOLD 16
+ SV_DRAGON_CHAOS 18
+ SV_DRAGON_BALANCE 20
+ SV_DRAGON_POWER 30
+~~~~~39
+/* The sval codes for TV_LITE */
+ SV_LITE_TORCH 0
+ SV_LITE_LANTERN 1
+ SV_LITE_TORCH_EVER 2
+ SV_LITE_DWARVEN 3
+ SV_LITE_FEANORIAN 4
+ SV_LITE_GALADRIEL 100
+ SV_LITE_ELENDIL 101
+ SV_LITE_THRAIN 102
+ SV_LITE_UNDEATH 103
+ SV_LITE_PALANTIR 104
+ SV_ANCHOR_SPACETIME 105
+ SV_STONE_LORE 106
+~~~~~40
+/* The "sval" codes for TV_AMULET */
+ SV_AMULET_DOOM 0
+ SV_AMULET_TELEPORT 1
+ SV_AMULET_ADORNMENT 2
+ SV_AMULET_SLOW_DIGEST 3
+ SV_AMULET_RESIST_ACID 4
+ SV_AMULET_SEARCHING 5
+ SV_AMULET_BRILLANCE 6
+ SV_AMULET_CHARISMA 7
+ SV_AMULET_THE_MAGI 8
+ SV_AMULET_REFLECTION 9
+ SV_AMULET_CARLAMMAS 10
+ SV_AMULET_INGWE 11
+ SV_AMULET_DWARVES 12
+ SV_AMULET_NO_MAGIC 13
+ SV_AMULET_NO_TELE 14
+ SV_AMULET_RESISTANCE 15
+ SV_AMULET_NOTHING 16
+ SV_AMULET_SERPENT 17
+ SV_AMULET_TORIS_MEJISTOS 18
+ SV_AMULET_ELESSAR 19
+ SV_AMULET_EVENSTAR 20
+ SV_AMULET_SUSTENANCE 21
+ SV_AMULET_TELEPATHY 22
+ SV_AMULET_TRICKERY 23
+ SV_AMULET_WEAPONMASTERY 24
+ SV_AMULET_DEVOTION 25
+ SV_AMULET_INFRA 26
+ SV_AMULET_SPELL 27
+ SV_AMULET_WISDOM 28
+ SV_AMULET_RESIST_ELEC 29
+ SV_AMULET_REGEN 30
+~~~~~45
+/* The sval codes for TV_RING */
+ SV_RING_WOE 0
+ SV_RING_AGGRAVATION 1
+ SV_RING_WEAKNESS 2
+ SV_RING_STUPIDITY 3
+ SV_RING_TELEPORTATION 4
+ SV_RING_SPECIAL 5
+ SV_RING_SLOW_DIGESTION 6
+ SV_RING_FEATHER_FALL 7
+ SV_RING_RESIST_FIRE 8
+ SV_RING_RESIST_COLD 9
+ SV_RING_SUSTAIN_STR 10
+ SV_RING_SUSTAIN_INT 11
+ SV_RING_SUSTAIN_WIS 12
+ SV_RING_SUSTAIN_CON 13
+ SV_RING_SUSTAIN_DEX 14
+ SV_RING_SUSTAIN_CHR 15
+ SV_RING_PROTECTION 16
+ SV_RING_ACID 17
+ SV_RING_FLAMES 18
+ SV_RING_ICE 19
+ SV_RING_RESIST_POIS 20
+ SV_RING_FREE_ACTION 21
+ SV_RING_SEE_INVIS 22
+ SV_RING_SEARCHING 23
+ SV_RING_STR 24
+ SV_RING_INT 25
+ SV_RING_DEX 26
+ SV_RING_CON 27
+ SV_RING_ACCURACY 28
+ SV_RING_DAMAGE 29
+ SV_RING_SLAYING 30
+ SV_RING_SPEED 31
+ SV_RING_BARAHIR 32
+ SV_RING_TULKAS 33
+ SV_RING_NARYA 34
+ SV_RING_NENYA 35
+ SV_RING_VILYA 36
+ SV_RING_POWER 37
+ SV_RING_RES_FEAR 38
+ SV_RING_RES_LD 39
+ SV_RING_RES_NETHER 40
+ SV_RING_RES_NEXUS 41
+ SV_RING_RES_SOUND 42
+ SV_RING_RES_CONFUSION 43
+ SV_RING_RES_SHARDS 44
+ SV_RING_RES_DISENCHANT 45
+ SV_RING_RES_CHAOS 46
+ SV_RING_RES_BLINDNESS 47
+ SV_RING_LORDLY 48
+ SV_RING_ATTACKS 49
+ SV_RING_NOTHING 50
+ SV_RING_PRECONITION 51
+ SV_RING_FLAR 52
+ SV_RING_INVIS 53
+ SV_RING_FLYING 54
+ SV_RING_WRAITH 55
+ SV_RING_ELEC 56
+ SV_RING_DURIN 57
+ SV_RING_SPELL 58
+ SV_RING_CRIT 59
+~~~~~55
+/* The "sval" codes for TV_STAFF */
+ SV_STAFF_SCHOOL 1
+ SV_STAFF_NOTHING 2
+~~~~~65
+/* The "sval" codes for TV_WAND */
+ SV_WAND_SCHOOL 1
+ SV_WAND_NOTHING 2
+~~~~~66
+/* The "sval" codes for TV_ROD(Rod Tips) */
+ SV_ROD_NOTHING 0
+ SV_ROD_DETECT_DOOR 1
+ SV_ROD_IDENTIFY 2
+ SV_ROD_RECALL 3
+ SV_ROD_ILLUMINATION 4
+ SV_ROD_MAPPING 5
+ SV_ROD_DETECTION 6
+ SV_ROD_PROBING 7
+ SV_ROD_CURING 8
+ SV_ROD_HEALING 9
+ SV_ROD_RESTORATION 10
+ SV_ROD_SPEED 11
+ SV_ROD_TELEPORT_AWAY 13
+ SV_ROD_DISARMING 14
+ SV_ROD_LITE 15
+ SV_ROD_SLEEP_MONSTER 16
+ SV_ROD_SLOW_MONSTER 17
+ SV_ROD_DRAIN_LIFE 18
+ SV_ROD_POLYMORPH 19
+ SV_ROD_ACID_BOLT 20
+ SV_ROD_ELEC_BOLT 21
+ SV_ROD_FIRE_BOLT 22
+ SV_ROD_COLD_BOLT 23
+ SV_ROD_ACID_BALL 24
+ SV_ROD_ELEC_BALL 25
+ SV_ROD_FIRE_BALL 26
+ SV_ROD_COLD_BALL 27
+ SV_ROD_HAVOC 28
+ SV_ROD_DETECT_TRAP 29
+ SV_ROD_HOME 30
+~~~~~67
+/* The "sval" codes for TV_ROD_MAIN(Rods) */
+ SV_ROD_WOODEN 10
+ SV_ROD_COPPER 20
+ SV_ROD_IRON 50
+ SV_ROD_ALUMINIUM 75
+ SV_ROD_SILVER 100
+ SV_ROD_GOLDEN 125
+ SV_ROD_MITHRIL 160
+ SV_ROD_ADMANTITE 200
+~~~~~70
+/* The "sval" codes for TV_SCROLL */
+ SV_SCROLL_DARKNESS 0
+ SV_SCROLL_AGGRAVATE_MONSTER 1
+ SV_SCROLL_CURSE_ARMOR 2
+ SV_SCROLL_CURSE_WEAPON 3
+ SV_SCROLL_SUMMON_MONSTER 4
+ SV_SCROLL_SUMMON_UNDEAD 5
+ SV_SCROLL_SUMMON_MINE 6
+ SV_SCROLL_TRAP_CREATION 7
+ SV_SCROLL_PHASE_DOOR 8
+ SV_SCROLL_TELEPORT 9
+ SV_SCROLL_TELEPORT_LEVEL 10
+ SV_SCROLL_WORD_OF_RECALL 11
+ SV_SCROLL_IDENTIFY 12
+ SV_SCROLL_STAR_IDENTIFY 13
+ SV_SCROLL_REMOVE_CURSE 14
+ SV_SCROLL_STAR_REMOVE_CURSE 15
+ SV_SCROLL_ENCHANT_ARMOR 16
+ SV_SCROLL_ENCHANT_WEAPON_TO_HIT 17
+ SV_SCROLL_ENCHANT_WEAPON_TO_DAM 18
+ SV_SCROLL_ENCHANT_WEAPON_PVAL 19
+ SV_SCROLL_STAR_ENCHANT_ARMOR 20
+ SV_SCROLL_STAR_ENCHANT_WEAPON 21
+ SV_SCROLL_RECHARGING 22
+ SV_SCROLL_RESET_RECALL 23
+ SV_SCROLL_LIGHT 24
+ SV_SCROLL_MAPPING 25
+ SV_SCROLL_DETECT_GOLD 26
+ SV_SCROLL_DETECT_ITEM 27
+ SV_SCROLL_DETECT_TRAP 28
+ SV_SCROLL_DETECT_DOOR 29
+ SV_SCROLL_DETECT_INVIS 30
+ SV_SCROLL_DIVINATION 31
+ SV_SCROLL_SATISFY_HUNGER 32
+ SV_SCROLL_BLESSING 33
+ SV_SCROLL_HOLY_CHANT 34
+ SV_SCROLL_HOLY_PRAYER 35
+ SV_SCROLL_MONSTER_CONFUSION 36
+ SV_SCROLL_PROTECTION_FROM_EVIL 37
+ SV_SCROLL_RUNE_OF_PROTECTION 38
+ SV_SCROLL_TRAP_DOOR_DESTRUCTION 39
+ SV_SCROLL_DEINCARNATION 40
+ SV_SCROLL_STAR_DESTRUCTION 41
+ SV_SCROLL_DISPEL_UNDEAD 42
+ SV_SCROLL_MASS_RESURECTION 43
+ SV_SCROLL_GENOCIDE 44
+ SV_SCROLL_MASS_GENOCIDE 45
+ SV_SCROLL_ACQUIREMENT 46
+ SV_SCROLL_STAR_ACQUIREMENT 47
+ SV_SCROLL_FIRE 48
+ SV_SCROLL_ICE 49
+ SV_SCROLL_CHAOS 50
+ SV_SCROLL_RUMOR 51
+ SV_SCROLL_ARTIFACT 52
+ SV_SCROLL_NOTHING 53
+ SV_SCROLL_SPELL 54
+~~~~~71
+/* The "sval" codes for TV_POTION */
+ SV_POTION_WATER 0
+ SV_POTION_APPLE_JUICE 1
+ SV_POTION_SLIME_MOLD 2
+ SV_POTION_BLOOD 3
+ SV_POTION_SLOWNESS 4
+ SV_POTION_SALT_WATER 5
+ SV_POTION_POISON 6
+ SV_POTION_BLINDNESS 7
+ SV_POTION_INVIS 8
+ SV_POTION_CONFUSION 9
+ SV_POTION_MUTATION 10
+ SV_POTION_SLEEP 11
+ SV_POTION_LEARNING 12
+ SV_POTION_LOSE_MEMORIES 13
+ SV_POTION_RUINATION 15
+ SV_POTION_DEC_STR 16
+ SV_POTION_DEC_INT 17
+ SV_POTION_DEC_WIS 18
+ SV_POTION_DEC_DEX 19
+ SV_POTION_DEC_CON 20
+ SV_POTION_DEC_CHR 21
+ SV_POTION_DETONATIONS 22
+ SV_POTION_DEATH 23
+ SV_POTION_INFRAVISION 24
+ SV_POTION_DETECT_INVIS 25
+ SV_POTION_SLOW_POISON 26
+ SV_POTION_CURE_POISON 27
+ SV_POTION_BOLDNESS 28
+ SV_POTION_SPEED 29
+ SV_POTION_RESIST_HEAT 30
+ SV_POTION_RESIST_COLD 31
+ SV_POTION_HEROISM 32
+ SV_POTION_BESERK_STRENGTH 33
+ SV_POTION_CURE_LIGHT 34
+ SV_POTION_CURE_SERIOUS 35
+ SV_POTION_CURE_CRITICAL 36
+ SV_POTION_HEALING 37
+ SV_POTION_STAR_HEALING 38
+ SV_POTION_LIFE 39
+ SV_POTION_RESTORE_MANA 40
+ SV_POTION_RESTORE_EXP 41
+ SV_POTION_RES_STR 42
+ SV_POTION_RES_INT 43
+ SV_POTION_RES_WIS 44
+ SV_POTION_RES_DEX 45
+ SV_POTION_RES_CON 46
+ SV_POTION_RES_CHR 47
+ SV_POTION_INC_STR 48
+ SV_POTION_INC_INT 49
+ SV_POTION_INC_WIS 50
+ SV_POTION_INC_DEX 51
+ SV_POTION_INC_CON 52
+ SV_POTION_INC_CHR 53
+ SV_POTION_AUGMENTATION 55
+ SV_POTION_ENLIGHTENMENT 56
+ SV_POTION_STAR_ENLIGHTENMENT 57
+ SV_POTION_SELF_KNOWLEDGE 58
+ SV_POTION_EXPERIENCE 59
+ SV_POTION_RESISTANCE 60
+ SV_POTION_CURING 61
+ SV_POTION_INVULNERABILITY 62
+ SV_POTION_NEW_LIFE 63
+~~~~~72
+/* The "sval" codes for TV_POTION2 */
+ SV_POTION2_MIMIC_ABOMINATION 1
+ SV_POTION2_MIMIC_WOLF 2
+ SV_POTION2_MIMIC_APE 3
+ SV_POTION2_MIMIC_GOAT 4
+ SV_POTION2_MIMIC_INSECT 5
+ SV_POTION2_MIMIC_SPARROW 6
+ SV_POTION2_MIMIC_STATUE 7
+ SV_POTION2_MIMIC_VAMPIRE 8
+ SV_POTION2_MIMIC_SPIDER 9
+ SV_POTION2_MIMIC_MANA_BALL 10
+ SV_POTION2_MIMIC_FIRE_CLOUD 11
+ SV_POTION2_MIMIC_COLD_CLOUD 12
+ SV_POTION2_MIMIC_CHAOS_CLOUD 13
+ SV_POTION2_CURE_LIGHT_SANITY 14
+ SV_POTION2_CURE_SERIOUS_SANITY 15
+ SV_POTION2_CURE_CRITICAL_SANITY 16
+ SV_POTION2_CURE_SANITY 17
+ SV_POTION2_CURE_WATER 18
+~~~~~80
+/* The "sval" codes for TV_FOOD */
+ SV_FOOD_POISON 0
+ SV_FOOD_BLINDNESS 1
+ SV_FOOD_PARANOIA 2
+ SV_FOOD_CONFUSION 3
+ SV_FOOD_HALLUCINATION 4
+ SV_FOOD_PARALYSIS 5
+ SV_FOOD_WEAKNESS 6
+ SV_FOOD_SICKNESS 7
+ SV_FOOD_STUPIDITY 8
+ SV_FOOD_NAIVETY 9
+ SV_FOOD_UNHEALTH 10
+ SV_FOOD_DISEASE 11
+ SV_FOOD_CURE_POISON 12
+ SV_FOOD_CURE_BLINDNESS 13
+ SV_FOOD_CURE_PARANOIA 14
+ SV_FOOD_CURE_CONFUSION 15
+ SV_FOOD_CURE_SERIOUS 16
+ SV_FOOD_RESTORE_STR 17
+ SV_FOOD_RESTORE_CON 18
+ SV_FOOD_RESTORING 19
+ SV_FOOD_BISCUIT 32
+ SV_FOOD_JERKY 33
+ SV_FOOD_RATION 35
+ SV_FOOD_SLIME_MOLD 36
+ SV_FOOD_WAYBREAD 37
+ SV_FOOD_PINT_OF_ALE 38
+ SV_FOOD_PINT_OF_WINE 39
+ SV_FOOD_ATHELAS 40
+ SV_FOOD_GREAT_HEALTH 41
+ SV_FOOD_FORTUNE_COOKIE 42
+~~~~~04
+/* The "sval" codes for TV_BATERIE */
+ SV_BATERIE_POISON 1
+ SV_BATERIE_EXPLOSION 2
+ SV_BATERIE_TELEPORT 3
+ SV_BATERIE_COLD 4
+ SV_BATERIE_FIRE 5
+ SV_BATERIE_ACID 6
+ SV_BATERIE_LIFE 7
+ SV_BATERIE_CONFUSION 8
+ SV_BATERIE_LITE 9
+ SV_BATERIE_CHAOS 10
+ SV_BATERIE_TIME 11
+ SV_BATERIE_MAGIC 12
+ SV_BATERIE_XTRA_LIFE 13
+ SV_BATERIE_DARKNESS 14
+ SV_BATERIE_KNOWLEDGE 15
+ SV_BATERIE_FORCE 16
+ SV_BATERIE_LIGHTNING 17
+ SV_BATERIE_MANA 18
+ MAX_BATERIE_SVAL 18
+~~~~~09
+/* The "sval" codes for TV_CORPSE */
+ SV_CORPSE_CORPSE 1
+ SV_CORPSE_SKELETON 2
+ SV_CORPSE_HEAD 3
+ SV_CORPSE_SKULL 4
+ SV_CORPSE_MEAT 5
+~~~~~115
+/* The "sval" codes for TV_DAEMON_BOOK */
+ SV_DEMONBLADE 55
+ SV_DEMONSHIELD 56
+ SV_DEMONHORN 57
diff --git a/lib/help/dungeon.txt b/lib/help/dungeon.txt
new file mode 100644
index 00000000..eca8046d
--- /dev/null
+++ b/lib/help/dungeon.txt
@@ -0,0 +1,706 @@
+|||||oy
+~~~~~02|Dungeons
+#####R /----------------------------------------\
+#####R < The Dungeons and Places of Middle-earth >
+#####R \----------------------------------------/
+
+ *****dungeon.txt*04[Symbols On Your Map] *****dungeon.txt*07[The Town and Buildings]
+ *****dungeon.txt*01[The Wilderness] *****dungeon.txt*06[In the Dungeon]
+ *****dungeon.txt*08[Objects] *****dungeon.txt*13[Mining]
+ *****dungeon.txt*12[Doors, Rooms, Staircases etc.] *****dungeon.txt*18[Pets]
+ *****dungeon.txt*14[Winning] *****dungeon.txt*15[Dying]
+ *****dungeon.txt*16[Where to get more help]
+
+After you have *****birth.txt*0[created your character], you will begin your ToME
+adventure. Symbols appearing on your screen will represent the world's
+walls, floor, objects, features, and creatures lurking about. In order
+to direct your character through his adventure, you will enter single
+character commands (see "*****command.txt*0[command.txt]").
+
+~~~~~03|Symbols
+~~~~~04|Identifying features
+#####R=== Symbols On Your Map ===
+
+Symbols on your map can be broken down into three categories: Features of
+the world such as walls, floor, doors, and traps; Objects which can be
+picked up such as treasure, weapons, magical devices, etc; and creatures
+which may or may not move about the dungeon, but are mostly harmful to your
+character's well being.
+
+Some symbols are used to represent more than one type of entity, and some
+symbols are used to represent entities in more than one category. The "@"
+symbol (by default) is used to represent the character.
+
+It will not be necessary to remember all of the symbols and their meanings.
+The "slash" command ("/") will identify any character appearing on your map
+(see "*****command.txt*0[command.txt]").
+
+Note that you can use a *****command.txt*105["user pref file"] to change any of these symbols to
+something you are more comfortable with.
+
+
+#####G Features that do not block line of sight
+
+ . A floor space 1 Entrance to General Store
+ . A trap (hidden) 2 Entrance to Armoury
+ ^ A trap (known) 3 Entrance to Weapon Smith
+ [[[[[y;] A glyph of warding 4 Entrance to Temple
+ [[[[[U'] An open door 5 Entrance to Alchemy Shop
+ [[[[[U'] A broken door 6 Entrance to Magic Shop
+ < A staircase up 7 Entrance to the Black Market
+ [[[[[y<] A quest exit 8 Entrance to your Home
+ [[[[[r<] A quest up level 9 Entrance to Bookstore
+ [[[[[U<] A shaft up [[[[[r>] A quest down level
+ > A staircase down [[[[[U>] A shaft down
+ [[[[[y>] A quest entrance [[[[[v>] Dungeon entrance
+ _ A fountain [[[[[D_] An empty fountain
+ * Straight road start/exit [[[[[B*] Section of the Straight Road
+ [[[[[b*] Section of the Straight Road [[[[[W*] Section of the Straight Road
+ [[[[[D*] Corrupted straight road [[[[[R*] An explosive rune
+ [[[[[B~] Stream of water (shallow) [[[[[b~] Stream of water (deep)
+ [[[[[u~] Tainted stream (water) [[[[[s#] Underground tunnel
+ [[[[[U#] Pool of lava (shallow) [[[[[r#] Pool of lava (deep)
+ [[[[[D#] Dark pit [[[[[u.] Dirt
+ [[[[[g.] Patch of Grass [[[[[W.] Ice
+ [[[[[y.] Sand [[[[[D.] Ash
+ [[[[[u.] Mud [[[[[v.] Nether mist
+ [[[[[r.] Floor [[[[[D0] Altar of Darkness
+ [[[[[R0] Altar of Force [[[[[B0] Altar of Winds
+ [[[[[W0] Altar of Being [[[[[v+] Void Jumpgate
+ [[[[[v;] Monster trap [[[[[B.] Glass wall
+ [[[[[w#] Illusion wall [[[[[g;] Grass with flowers
+ [[[[[w.] Cobblestone road [[[[[g#] Small tree
+ [[[[[w*] Town (in wilderness) [[[[[U^] Underground tunnel
+ [[[[[y+] A web
+
+#####G Features that block line of sight
+
+ [[[[[w#] A secret door # A wall
+ [[[[[U+] A closed door % A mineral vein
+ [[[[[U+] A locked door [[[[[o*] A mineral vein + treasure
+ [[[[[U+] A jammed door [[[[[w:] A pile of rubble
+ [[[[[D#] A dead tree [[[[[W#] Ice wall
+ [[[[[G#] A tree [[[[[y#] Sand wall
+ [[[[[U^] A mountain chain [[[[[W^] High mountain chain
+
+
+#####G Objects
+
+ ! A potion (or flask) / A pole-arm
+ ? A scroll, book, map, parchment / Music instrument
+ ? A rune, runestone | An edged weapon
+ , A mushroom (or food) \ A hafted weapon or digger
+ - A wand, rod or rod tip } A sling, bow, or x-bow
+ _ A staff { A shot, arrow, bolt, boomerang
+ = A ring ( Soft armour/cloak
+ " An amulet [ Hard armour
+ $ Gold or gems ] Misc. armour
+ ~ Lites, Tools, Chests, etc ) A shield
+ ~ Junk, Sticks, Skeletons, etc ` Trapping kit, climbing set
+ ~ Stone, random artifact o Egg
+ * An essence & (unused)
+
+~~~~~05|Monsters
+#####G Monsters
+
+ $ Creeping Coins , Mushroom Patch
+ a Giant Ant A Angelic being
+ b Giant Bat B Bird
+ c Giant Centipede C Canine
+ d Dragon D Ancient Dragon
+ e Floating Eye E Elemental
+ f Feline F Dragon Fly
+ g Golem G Ghost
+ h Humanoids H Hybrid
+ i Icky-Thing I Insect
+ j Jelly J Snake
+ k Kobold K Killer Beetle
+ l Giant Louse L Lich
+ m Mold M Multi-Headed Hydra
+ n Naga N (unused)
+ o Orc O Ogre
+ p Human P Giant Human(oid)
+ q Quadruped Q Quylthulg
+ r Rodent R Reptile/Amphibian
+ s Skeleton S Spider/Scorpion/Tick
+ t Townsperson T Troll
+ u Minor demon U Major demon
+ v Vortex V Vampire
+ w Worm or Worm Mass W Wight/Wraith
+ x (unused) X Xorn/Xaren
+ y Yeek Y Yeti
+ z Zombie/Mummy Z Zephyr Hound
+
+
+~~~~~07|Town
+#####R=== The Town Level ===
+
+The town level is where you will begin your adventure. The town consists of
+several buildings (most with an entrance), some townspeople, and a main wall
+which surrounds the town (with gates in it). Outside the gates may be found
+unclaimed lands and wilderness, where beasts still run wild. The first time
+you are in town it will be daytime (unless you are an undead character), but
+note that the sun will rise and set (rather instantly) as time passes.
+
+There are a few different towns around the world map, and your starting town
+will eventually become too small for you (if you survive the dangers of the
+dungeon). Other towns will have some different facilities, and you can find
+your way to other towns by reading the "Adventurer's Guide to Middle-earth"
+parchment with which *every* character begins the game.
+
+
+#####R=== Townspeople ===
+
+The town contains many different kinds of people. There are the street
+urchins, young children who will mob an adventurer for money, and seem to
+come out of the woodwork when excited. Blubbering idiots are a constant
+annoyance, but not harmful. Public drunks wander about the town singing,
+and are of no threat to anyone. Sneaky rogues who work for the black
+market are always greedily eyeing your backpack for potential new
+'purchases'... And finally, what town would be complete without a
+swarm of half drunk warriors, who take offense or become annoyed just for
+the fun of it.
+
+Most of the townspeople should be avoided by the largest possible distance
+when you wander from store to store. Fights will break out, though, so be
+prepared. Since your character grew up in this world of intrigue, no
+experience is awarded for killing the town inhabitants, though you may
+acquire treasure.
+
+~~~~~21|Buildings
+#####R=== Town Buildings ===
+
+Your character will begin his adventure with some basic supplies, and some
+extra gold with which to purchase more supplies at the town stores.
+
+You may enter any open store and barter with the owner for items you can
+afford. When bartering, you enter prices you will pay (or accept) for some
+object. You can either enter the absolute amount, or precede a number with
+a plus or minus sign to give a positive or negative increment on your
+previous offer. But be warned that the owners can easily be insulted, and
+may even throw you out for a while if you insult them too often. [[[[[BTo enter]
+[[[[[Ba store, simply move onto the entrance, which is represented by a number]
+[[[[[Bfrom 1 to 9.]
+
+If you consistently bargain well in a store, that is, you reach the final
+offer much more often than not, then the store owner will eventually
+recognise that you are a superb haggler, and will go directly to the final
+offer instead of haggling with you. Items which cost less than 10 gold
+pieces do not count, as haggling well with these items is usually either
+very easy or almost impossible. The more expensive the item is, the less
+likely the store owner is to assume that you are a good haggler. Note that
+you may disable haggling with a software option, though this will inflict a
+10% "sales tax" on all purchases for which the store owner would have
+required you to haggle.
+
+Once inside a store, you will see the name and race of the store owner, the
+name of the store, the maximum amount of cash that the store owner will pay
+for any one item, and the store inventory, listed along with tentative
+prices, which will become "fixed" (at the "final offer") should you ever
+manage to haggle a store owner down to his final offer.
+
+You will also see an (incomplete) list of available commands. Note that
+many of the commands which work in the dungeon work in the stores as well,
+but some do not, especially those which involve "using" objects.
+
+Stores do not always have everything in stock. As the game progresses, they
+may get new items, so check back from time to time. Also, if you sell them
+an item, it may get sold to a customer while you are adventuring, so don't
+always expect to be able to get back everything you have sold. If you have
+a lot of spare gold, you can purchase every item in a store, which will
+induce the store owner to bring out new stock, and perhaps even retire. If
+you are low on funds (and morals), you may attempt to steal an item from
+the store, but beware -- if you are caught, the store owner will not let you
+back in for a very long time.
+
+Store owners will not buy harmful or useless items. If an object is
+unidentified, they will pay you some base price for it. Once they have
+bought it they will immediately identify the object. If it is a good object,
+they will add it to their inventory. If it was a bad bargain, they simply
+throw the item away. In any case, you may receive some knowledge of the
+item in case another is encountered.
+
+#####GThe General Store ("1")
+ The General Store sells foods, drinks, some clothing, torches, lamps,
+ oil, shovels, picks, and spikes. All of these items and some others
+ can be sold back to the General store for money.
+
+#####GThe Armoury ("2")
+ The Armoury is where the town's armour is fashioned. All sorts of
+ protective gear may be bought and sold here.
+
+#####GThe Weaponsmith's Shop ("3")
+ The Weaponsmith's Shop is where the town's weapons are fashioned. Hand
+ and missile weapons may be purchased and sold here, along with arrows,
+ bolts, and shots.
+
+#####GThe Temple ("4")
+ The Temple deals in healing and restoration potions, as well as bless
+ scrolls, word of recall scrolls, some approved priestly weapons, and
+ priest spell books.
+
+#####GThe Alchemy shop ("5")
+ The Alchemy Shop deals in all types of potions and scrolls.
+
+#####GThe Magic User's Shop ("6")
+ The Magic User's Shop deals in all sorts of rings, wands, amulets, and
+ staves, as well as spell books.
+
+#####GThe Black Market ("7")
+ The Black Market will sell and buy anything at extortionate prices.
+ However it occasionally has VERY good items in it. The shopkeepers are
+ not known for their tolerance...
+
+#####GYour Home ("8")
+ This is your house where you can store objects that you cannot carry
+ on your travels, or will need at a later date.
+
+#####GThe Bookstore ("9")
+ The Bookstore deals in all sorts of magical books. You can purchase
+ and sell spellbooks for spellcasters and priests here.
+
+
+#####ROther Buildings
+In addition to the basic stores, there are some special buildings that can be
+found in some towns. These Buildings (represented by +'s) include:
+
+#####GMayor's Office/Castle
+ The home office for the town. Adventurers looking for work besides
+ exploring the dungeon should hunt in here.
+
+#####GPet Shop
+ Great place to purchase eggs and get pets.
+
+#####GThe Soothsayer
+ To discover what *****/afatespoi.txt*0[fates ("a")] lie in store for you.
+
+#####GThe Prancing Pony
+ Wine, dine, rest and relax!
+
+#####GThe Nest
+ Thunderlords are masters of teleportation, and will consent to bear you
+ to your chosen dungeon destination for a fee.
+
+#####GBeastmaster Shanty
+ For those who enjoy trophy hunting, and to research that strange animal
+ you saw during your adventures.
+
+#####GFighters Hall
+ The place to reforge weapons and armour.
+
+#####GRangers Guild
+ The place to reforge distance weapons and their ammunition.
+
+#####GLibrary
+ For information of all kinds.
+
+#####GGambling House
+ Read the *****/bgambling.txt*0[rules ("b")] before paying. The games are
+ not rigged, just naturally difficult.
+
+#####GTower of Magery/Wizards Spire
+ The wizards will identify your items or recharge your magical items for
+ a fee.
+
+#####GInner temple/Priests Circle
+ A place of healing.
+
+#####GPaladin guild
+ Some healing and enchantments available.
+
+#####GThe Mathom House
+ Donate important, but unwanted items you find in the dungeon.
+
+
+~~~~~1|Wilderness
+#####R=== The Wilderness and the Wilderness Map ===
+
+Between the towns, the hand of civilisation has not tamed the lands, and
+wild creatures run rampant. This is another place that is worth exploring.
+Hidden within the wilderness are several interesting locations, with the
+four main ones for any adventurer - Barrow Downs, Mirkwood, Mordor and
+Angband each being located at or near one of the main towns of Middle-
+earth. These locations should be explored consecutively, as each one
+increases in difficulty from the point where the previous dungeon finished.
+A new character should not try to go at Mordor or Angband as their first
+dungeon (well, not if you wish to survive your first step, anyway)!
+
+As well as these (and other) locations, the wilderness can be a good place
+to go when you are seeking a change from the scenery of the dungeons, or just
+a bit of fast experience.
+
+Be warned - some creatures found in the wilderness can be quite dangerous,
+and travel through the wilderness can be time-consuming. If you are wishing
+to simply move to another town, there is an overview map (called the
+"Wilderness Map") that can be travelled through by going up "<" from the
+town level. While travelling through this map, your character is still having
+to actually walk through each square of the normal view, but you only see the
+end result of them moving from one 4x4 panel to the next. As such, food
+consumption will appear to be much higher in the Wilderness View than it is
+normally, and it is recommended that you travel prepared. It is also possible
+for the wild creatures within the wilderness to ambush you when travelling,
+which will force you out of the Wilderness Map so that you can safely get
+yourself out of trouble, before continuing on your way.
+
+All of the special locations can be seen as downstairs (">") on the
+Wilderness Map and towns as "*"s. This makes it *much* easier to find your
+way from one interesting place to another.
+
+The "Adventurer's Guide to Middle-earth" (a parchment with which *every*
+character begins the game) contains details about the towns and some of
+the dungeons, including rough directions on how to get there.
+
+~~~~~06|Dungeons|In the dungeon
+#####R=== Within The Dungeon ===
+
+Once your character is adequately supplied with food, light, armor, and
+weapons, he is ready to enter Barrow Downs. Move on top of the ">" symbol
+and use the "Down" command (">").
+
+Your character will enter a maze of interconnecting staircases and finally
+arrive somewhere on the first level of the dungeon. Each level of the
+dungeon is fifty feet high (thus dungeon level "Lev 1" is often called
+"50 ft"), and is divided into rectangular regions several times
+larger than the screen. Once you leave a level by a
+staircase, you will never again find your way back to that region of that
+level, but there are an infinite number of other regions at that same "depth"
+that you can explore later. So be careful that you have found all the
+treasure before you leave a level, or you may never find it again! The
+monsters, of course, can use the stairs, and you may eventually encounter
+them again.
+
+In the dungeon, there are many things to find, but your character must
+survive many horrible and challenging encounters to find the treasure lying
+about and take it safely back to the town to sell.
+
+~~~~~23|Light
+There are two sources for light once inside the dungeon: permanent light
+which has been magically placed within rooms, and a light source carried by
+the player (or some of the monsters). If neither is present, the character
+will be unable to see. This will affect searching, picking locks, disarming
+traps, reading scrolls, casting spells, browsing books, etc. So be very
+careful not to run out of light!
+
+A character must wield a torch or lamp in order to supply his own light. A
+torch or lamp burns fuel as it is used, and once it is out of fuel, it stops
+supplying light. You will be warned as the light approaches this point. You
+may use the "Fuel" command ("F") to refuel your lantern (with flasks of oil)
+or your torch (with other torches), so it is a good idea to carry extra
+torches or flasks of oil, as appropriate. There are rumours of objects of
+exceptional power which glow with their own never-ending light.
+
+~~~~~08|Objects
+#####R=== Objects Found In The Dungeon ===
+
+The mines are full of objects just waiting to be picked up and used. How
+did they get there? Well, the main source for useful items are all the
+foolish adventurers (like you?) that proceeded into the dungeon before you.
+They get killed, and the helpful creatures scatter the various treasures
+throughout the dungeon. Most cursed items are placed there by the joyful evil
+sorcerers, who enjoy a good joke when it gets you killed.
+
+You pick up objects by moving on top of them. You can carry up to 23
+different items in your backpack while wearing and wielding up to 12 others.
+Although you are limited to 23 different items, each item may actually be a
+"pile" of up to 99 similar items. If you somehow manage to stuff 24 items
+into your pack, for example, by removing an item from your head while your
+pack is full, then your pack will "overflow" and the most recently added
+item will fall out and onto the ground. You will be warned about any command
+that seems likely to induce this behaviour.
+
+You are, in addition, limited in the total amount of weight that you can
+carry. As you approach this value, you become slower, making it easier for
+monsters to chase you. Note that there is no upper bound on how much you can
+carry, if you do not mind being slow. Your weight limit is determined by your
+strength.
+
+Objects do not block the line of sight, but may stack on top of one another,
+with the one on top hiding others beneath it.
+
+ Q: I'm standing on a pile of items. How do I see what's in the pile
+ without picking it all up, moving it, or destroying it all?
+ A: 1. Stand on the pile in question
+ 2. Type shift + i (examine)
+ 3. Type - (examine items on floor)
+ 4. Type * (expand list of items on floor)
+ 5. (as needed) Type letter associated with item to look at it more
+ closely.
+
+Objects may also obscure stairs, Ways and void jumpgates.
+
+ Q: I'm standing on a pile of items. Is there a command to see if
+ there is a stair beneath the pile?
+ A: Stairs, void jumpgates and Ways that obscured by clutter still
+ function.
+ You are advised to take a good hard look at your surroundings before
+ creating lots of dungeon clutter. You can see if there is a stair
+ beneath the pile with either of these methods:
+ 1. Pick up, move, or eliminate the pile.
+ 2. Press l (look), then select the square you wish to inquire about.
+ Press <enter>; it will scroll through everything on the ground,
+ and eventually it ends with "It is in a Void Jumpgate", or
+ whatever.
+
+
+Many objects found within the dungeon have special commands for their use.
+Wands must be Aimed, staves must be Used, scrolls must be Read, and potions
+must be Quaffed. You may, in general, not only use items in your pack, but
+also items on the ground, if you are standing on top of them. For a detailed
+list of the commands to use objects, see *****command.txt*0[command.txt].
+
+Chests are complex objects, containing traps, locks, and possibly treasure
+or other objects inside them once they are opened. Many of the commands that
+apply to traps or doors also apply to chests and, like traps and doors, these
+commands do not work if you are carrying the chest.
+
+One item in particular will be discussed here. [[[[[BThe scroll of "Word of]
+[[[[[BRecall"] can be found within the dungeon, or bought at the temple in
+town. It acts in two manners, depending upon your current location. If read
+within the dungeon, it will teleport you back to town. If read in town, it
+will teleport you back down to the deepest level of the dungeon to which your
+character has previously journeyed. This makes the scroll very useful for
+getting back to the deeper levels of the dungeon. Once the scroll has been
+read it takes a while for the spell to act, so don't expect it to save you
+in a crisis. Reading a second scroll before the first has had a chance to
+take effect will cancel both scrolls. Since an accidental dive to a new depth
+(via a trapdoor, for example), may result in the Word of Recall dungeon depth
+being 'broken', so to speak (meaning that the next Word of Recall in town
+will take you back deeper than you would like to), there is a feature in
+ToME which allows you to read a scroll of Word of Recall on a different
+level and 'reset' the recall depth to that level (instead of the deepest
+level). Some dungeons cannot be recalled into, though you can still recall
+out.
+
+You may "inscribe" any object with a textual inscription of your choice.
+These inscriptions are not limited in length, though you may not be able to
+see the whole inscription on the item. The game applies special meaning to
+inscriptions containing any text of the form "@#" or "@x#" or "!x" or "!*",
+see "*****command.txt*0[command.txt]" and "*****macrofaq.txt*0[macrofaq.txt]".
+
+The game provides some "fake" inscriptions to help you keep track of your
+possessions. Wands and staves which are known to be empty will be inscribed
+with "empty". Objects which have been tried at least once but haven't been
+identified yet will be inscribed with "tried". Cursed objects are inscribed
+with "cursed". Broken objects may be inscribed with "broken". Also, any
+item which was purchased at a discount, implying that it is slightly
+"sub-standard", will be inscribed with the appropriate "discount", such as
+"25% off". Note that these inscriptions are fake, and cannot be removed,
+though they can be covered up by a real inscription if you so desire. Try
+"_" as a nice short one.
+
+Also, occasionally you will notice that something in your inventory or
+equipment list seems to be magical. High level characters are much more
+likely to notice this than beginning characters. When you do notice this,
+the item in question will be inscribed with "good" or "cursed" as is
+relevant. You can increase your ability to notice magical effects of armour
+and weapons by increasing the *****skills.txt*01[Combat] skill. You can increase your ability
+to sense particularly well enchanted magical items (potions, scrolls. wands
+etc) by increasing your *****skills.txt*21[Magic] skill. If you increase these
+high enough, you will gain a special method of "sensing" your
+inventory/equipment items, which tells you not only whether an item is "good"
+or "cursed", but also if it is "average", "special", "excellent", "terrible" or
+"worthless".
+
+~~~~~21|Objects|Colour of inventory slot letter
+The colour of the letter that identifies each item in your backpack can tell
+you something about their magical status. Grey indicates the item has not been
+identified yet. After identification, the colour changes to one of the
+following: white, indicating it is normal; blue indicates it is an ego-item
+(pseudo-id's as {excellent}); yellow indicates it is an artifact {special};
+green shows it is an artifact which is part of a set.
+
+It is rumoured that rings of power and extra rare spell books may be found
+deeper in the dungeon....
+
+And lastly, a final warning: not all objects are what they seem. The line
+between tasty food and annoying mushroom is a fine one, and sometimes a
+potion will reach out and bite you...
+~~~~~09|Objects|Cursed Objects
+~~~~~10|Cursed Objects
+#####R=== Cursed Objects ===
+
+Some objects, mainly armour and weapons, have had curses laid upon them.
+These horrible objects will look like any other normal item, but will
+detract from your character's stats or abilities if worn. They will also
+be impossible to remove until the curse is removed. In fact some are
+so badly cursed that even this will not work, and more potent methods are
+needed.
+
+If you wear or wield a cursed item, you will immediately feel something
+wrong. The item will also be inscribed "cursed".
+
+Shopkeepers will refuse to buy any known cursed item.
+~~~~~13|Mining
+~~~~~11|Dungeons|Mining
+#####R=== Digging and Mining ===
+
+It is possible for you to be trapped within the dungeon. You will not be able
+to dig your way out without a digging tool (shovel, pick, or other means of
+digging). It is absolutely essential to always carry some kind of digging tool,
+even when you are not planning on tunnelling for treasure. Do not leave the
+town level of Bree without a digger!
+
+Picks and shovels have a digging ability expressed as "(+<num>)", e.g. (+2).
+The higher the number, the better the digging ability of the tool. Diggers are
+effective against rubble, trees, and many walls. Rubble and veins may hide
+treasure; trees do not.
+
+You dig in something with the tunnel (shift + t) command. Thorough digging
+removes one ASCII square (i.e. tile) of what is being dug. This may require
+multiple attempts depending on how good your digger is (and how high your
+strength is). Once the square is removed, you will be informed if you found
+anything there. If another diggable square exists beyond the area you just dug,
+you can begin the process again.
+
+Some dungeons contain rich strikes which may be found only by mining it out of
+the walls. Quartz veins are the richest, yielding the most metals and gems, but
+magma veins may also hide hoards within them. When digging rock, granite is
+much harder to dig through than quartz or magma veins, so it is much faster to
+follow a vein exactly and dig around the granite. There is also a game option
+for highlighting magma and quartz within the walls, which makes this easier.
+
+If the character has a scroll, staff, or spell of treasure location, she can
+immediately locate all strikes of treasure within a vein shown on the screen.
+This makes mining much easier and more profitable.
+~~~~~12|Dungeons|Doors, Passages, Rooms and Staircases
+#####R=== Staircases, Ways, Void jumpgates, Secret Doors, Passages, and Rooms ===
+
+Staircases are the manner in which you get deeper or climb out of the
+dungeon. The symbols for the up and down staircases are the same as the
+commands to use them. A "<" represents an up staircase and a ">" represents
+a down staircase. You must move your character over the staircase before
+you can use it. You use it by typing the same character as the staircase
+itself (either "<" or ">".)
+
+In flat environments such as forests, Ways replace staircases. On the map, Ways
+are identical to staircases and behave the same way.
+
+Yellow down stairs and Ways are quest entrances (although not every quest
+is reached by such means).
+
+Shafts are also represented by "<" or ">", but are brown. They work similarly
+to stairs and Ways, but if you use one, you might traverse more than one
+dungeon level all in one go as a result.
+
+Stairs, impenetrable walls, and shop entrances like titanium walls, and the
+doors into shops, cannot be destroyed by any means (although their location can
+occasionally change under the right circumstances).
+~~~~~23|Void jumpgates
+A void jumpgate appears on your map as a violet "+". Jumpgates always occur in
+pairs. To activate a jumpgate, stand on it and type ">". You will instantly
+appear on top of its paired jumpgate, which will be somewhere else on the same
+dungeon level.
+
+Many secret doors are used within the dungeon to confuse and demoralise
+adventurers foolish enough to enter. But with some luck, and lots of
+concentration, you can find these secret doors. Secret doors will sometimes
+hide rooms or corridors, or even entire sections of that level of the
+dungeon. Sometimes they simply hide small empty closets or even dead ends.
+Secret doors always look like granite walls, just like traps always look
+like normal floors.
+
+Creatures in the dungeon will generally know and use these secret doors, and
+can sometimes be counted on to leave them open behind them when they pass
+through.
+
+For historical reasons, secret doors are never locked.
+
+~~~~~18|Pets
+~~~~~19|Companions
+~~~~~20|Monsters|Pets
+#####R=== Pets and Companions ===
+You may, in the course of a game, acquire friendly monsters who will help you
+defeat enemies. There are several different types of these, you can determine
+which your monster is by 'l'ooking at it.
+[[[[[vneutral] This monster will not help you by attacking other monsters, but nor
+ will it attack you.
+[[[[[vco-aligned] This monster will attack other enemy monsters, but you will not
+ gain any experience for its kills.
+[[[[[vpet] This monster will kill things for you. The amount of experience you gain
+ from its kills is determined by the level of your *****skills.txt*42[Monster-lore] skill.
+ This monster will gain levels and experience of its own, but cannot travel
+ between dungeon levels.
+[[[[[vcompanion] This type of monster will not only take experience and level up like
+ pets, but will also follow you from one dungeon level to the next. If
+ you successfully complete an adventurer quest for a lost sword and let
+ him join you, he will become a companion. Once again the amount of
+ experience you gain from a companion's kill depends upon your
+ Monster-lore skill.
+
+Your Monster-lore skill also determines the maximum number of pets and
+companions you can have at any one time.
+
+Pets, companions and co-aligned creatures cannot deliver killing blows to
+uniques or quest monsters. You must do this yourself!
+
+You can give commands to pets and companions to make them more useful, using
+the "P" command. The list of available commands is as follows:
+[[[[[vdismiss companions] Dismisses your companions. They can be difficult to get rid
+ of any other way.
+[[[[[vdismiss pets] Dismisses pets. You will be given the opportunity to dismiss all
+ current pets, or if you answer no to that first question, to
+ dismiss specific pets.
+[[[[[vcall pets] Calls your pets (and companions) to you.
+[[[[[vfollow me] Asks your pets (and companions) to follow you. They do have a mind of
+ their own, and may not be able to travel as fast as you can.
+[[[[[vseek and destroy] Selecting this will cause your pets and companions to wander
+ further from you, looking for enemies to kill.
+[[[[[vallow/disallow open doors] Selecting this toggles whether your pets and
+ companions can open doors.
+[[[[[vallow/disallow pickup items] Selecting this toggles whether your pets and
+ companions can pick up items. Disallowing it will
+ cause the monster to drop any items he is carrying on
+ the floor.
+[[[[[vgive target to a friend] Selecting this will cause one of your pets or
+ companions to attack your current target.
+[[[[[vgive target to all friends] Causes all pets or companions to attack your
+ current target.
+[[[[[vfriend forget target] All your friends will follow their normal attack
+ patterns, neglecting any targets you have given them.
+
+~~~~~14|Objectives
+#####R=== Game Objectives ===
+
+In ToME you will be required to complete a certain number of quests. Your
+first quest is to discover the true nature of the evil lurking in the Tower of
+Dol Guldur near Mirkwood.
+
+Each quest may lead on to others, and most quests can be postponed until when
+you feel ready to tackle them. Simply explore other dungeons until you feel you
+have gained enough experience to tackle your next task. Other quests are
+optional and can be used for further experience.
+
+Once you have finished your final quest, when you are ready to retire, simply
+"commit suicide" ("^Q") to have your character entered into the high score list
+as a winner. Note that until you retire, you can still be killed, so you may
+want to retire before wandering into a hoard of nasties....
+
+You may also like to make a character sheet of your winning character (by
+going through the "C"haracter screen and choosing "f"ile), and post in the
+rec.games.roguelike.angband newsgroup with a text copy of the dump pasted
+into the post. Include details about anything major that happened to your
+character - did they find a ring of speed (+10) on dungeon level 2? Or had
+they reached dungeon level 60 before finding their first artifact? Did you
+have a really scary moment that stands out from the rest of the game? And how
+*did* you actually win the game, anyway?
+
+~~~~~15|Dying
+~~~~~17|Loading old characters
+#####R=== Upon Death and Dying ===
+
+If your character falls below 0 hit points, he has died and cannot be
+restored (for most classes, anyway). A tombstone showing information about
+your character will be displayed. You are also permitted to get a record of
+your character, and all your equipment (identified) either on the screen or
+in a file.
+
+Your character will leave behind a reduced save file, which contains only
+the monster memory and your option choices. It may be restored, in which
+case the new character is generated exactly as if the file was not there,
+but the new player will find his monster memory containing all the experience
+of past incarnations.
+
+In this way, death in ToME is permanent. You cannot simply 'reload at the last
+save' as in most other contemporary games. Death is permanent, just as it is
+in real life.
+
diff --git a/lib/help/dunspoil.txt b/lib/help/dunspoil.txt
new file mode 100644
index 00000000..2da6d6b7
--- /dev/null
+++ b/lib/help/dunspoil.txt
@@ -0,0 +1,173 @@
+|||||oy
+~~~~~01|Dungeons|Spoilers
+~~~~~02|Spoilers|Dungeons
+#####R=== ToME's DUNGEONS ===
+
+There are numerous dungeons within Middle-earth, but not all
+of them are required to be ventured into. The original Angband
+dungeon has been split into 4 parts, each found near or at a
+different town. Travel between towns is usually easiest by
+using the wilderness overview map ("<" from the town level),
+but remember to take lots of food with you!
+
+#####GThe Basic Dungeons
+#####G------------------
+
+#####G1. Barrow-Downs
+Found near the outskirts of Bree (the starting town), this
+dungeon is where you should begin your adventure. It
+contains the main Dungeon levels 1 (50') to 10 (500'),
+after which it becomes necessary for the character to seek
+out a new dungeon in order to be able to descend further in
+their quest to kill Morgoth.
+
+#####G2. Mirkwood
+The Mirkwood forest contains levels 11 (550') to 33 (1650'),
+and can be found to the north-east of Lothlorien.
+
+#####G3. Mordor
+The Land of Mordor is a hot, cavernous region, containing
+levels 34 (1700') to 66 (3300') of the dungeon. Located to
+the East of Minas Anor, it is a place filled with danger,
+and only a wary adventurer will make it through to the other
+end of this dungeon.
+
+#####G4. Angband
+Only the most successful of adventurers usually make it this
+far. The Dungeon Angband contains both Sauron and Morgoth,
+who will gladly wipe out any who dare to oppose them! This
+dungeon covers levels 67 (3350') to 127 (6350'), but Sauron
+waits for you at level 99, and Morgoth at level 100. This
+dungeon can be found near Gondolin.
+
+
+#####GAdditional ToME Dungeons
+#####G------------------------
+
+In addition to the basic 4 dungeons, there are numerous other
+dungeons scattered around the world for an adventurer to explore
+while preparing for the final fight. Many of the dungeons have a
+guardian at the bottom of them, and a few have unique levels
+somewhere within them (like an orc town) with guaranteed artifacts
+and nasties within them. Other than the unique levels, all of the
+dungeons can be exited and re-entered at your leisure.
+
+Be warned though that some dungeons are partly toxic to the
+adventurer, and will damage you BY THEMSELVES just by you walking
+within them!
+
+#####GOrc Cave
+A dark tunnel leading to an Orc Cave, guarded at its base by Azog,
+King of the Uruk-Hai. Also somewhere within this dungeon is the
+hidden special level called Deathwatch.
+Equivalent to dungeon levels 10 to 22.
+
+#####GThe Old Forest
+A Forest is a haven for many animals, both of the good variety, and
+the bad. This forest is no exception. In the past, unsuccessful
+attempts have been made to cultivate this land, and it is possible
+that some of the towns may remain. It is also rumoured that Old Man
+Willow has made his home here, and is the source of the Forest's
+resistance to cultivation.
+Equivalent to dungeon levels 13 to 25.
+
+#####GHelcaraxe
+The Grinding Ice of Helcaraxe is a bitterly cold series of caverns,
+and guarded by the White Balrog.
+Equivalent to dungeon levels 20 to 40.
+
+#####GThe Sandworm lair
+A deep sandhole where most worms originated, it is guarded at its
+base by the Sandworm Queen.
+Equivalent to dungeon levels 22 to 30.
+
+#####GThe Heart of the Earth
+A dark passage leading into the heart of the world, the Heart of
+the Earth is the source of all the earth's changes. Some claim it
+to be the home of Golgarach, the Living Rock, who assists in the
+creation of new, ever-changing landforms.
+Equivalent to dungeon levels 25 to 36.
+
+#####GMaze
+A strange Maze where it becomes very difficult to remember where you
+have been, it is guarded at the bottom by The Minotaur of the Labyrinth.
+Equivalent to dungeon levels 25 to 37.
+
+#####GCirith Ungol
+The dungeon Cirith Ungol is full of poisonous fumes rising from the
+ground, and the land here looks diseased. Shelob is said to lurk
+within these depths.
+Equivalent to dungeon levels 25 to 50.
+
+#####GThe Land Of Rhun
+The Land Of Rhun is located on a large plain, and has been taken over
+by Ulfang the Black, Morgoth's first Easterling follower.
+Equivalent to dungeon levels 26 to 40.
+
+#####GThe Mines of Moria
+A stone door leads down to the depths of the Moria. Once the home of
+the dwarves, the mines have been taken over by creeping evil things, and
+unlucky adventurers may well stumble upon their training grounds. In
+the depths lurks Durin's Bane, the Balrog of Moria, and return from
+these depths can be difficult....
+Equivalent to dungeon levels 30 to 50.
+
+#####GThe Small Water Cave
+A small water cave filled with salt water, which rusts and damages an
+adventurer's equipment. This cave is not very deep, and is guarded by
+The Watcher in the Water.
+Equivalent to dungeon levels 32 to 34.
+
+#####GSubmerged Ruins
+The lost land of Numenor lies submerged here. The salt water causes
+everything to rust. These ruins are guarded by Ar-Pharazon the
+Golden.
+Equivalent to dungeon levels 35 to 50.
+
+#####GIllusory Castle
+The Illusory Castle is a very strange and confusing place for an
+adventurer to visit, and is rumoured to contain many strange
+monsters. Deep within the castle can be found The Glass Golem.
+Equivalent to dungeon levels 35 to 52.
+
+#####GPaths of the Dead
+A dark underground graveyard, this place looks extremely dangerous.
+It is claimed that the dead have all arisen in these depths, and are
+lead by Feagwath, the Undead Sorcerer.
+Equivalent to dungeon levels 40 to 70.
+
+#####GThe Sacred Land Of Mountains
+The Sacred Land Of Mountains is located in a large mountain range,
+with the remains of many old towns. Considered a perfect place to hide
+for one who could fly, it is rumoured that Trone the rebel Thunderlord
+fled into the ruins here.
+Equivalent to dungeon levels 45 to 70.
+
+#####GThe Tower of Dol Guldur
+The tower of of Dol Guldur is the last known residence of one known only
+as "the Necromancer". It is rumoured to be filled with his conjurations,
+although none have made it out of the Tower alive to confirm or deny this
+rumour.
+Equivalent to dungeon levels 57 to 70.
+
+#####GErebor, the Lonely Mountain
+A big, dark and frightening tunnel leading to the depth of the Lonely
+Mountain, this large cave is the ancestral home of the Dragons.
+Glaurung, Father of the Dragons has long made his home here.
+Equivalent to dungeon levels 60 to 72.
+
+#####GMount Doom
+A steaming cave in the centre of Mount Doom, this place is *hot*.
+It is said that Sauron forged the One Ring here and that it's the only place
+where it could be destroyed.
+Equivalent to dungeon levels 85 to 99.
+
+#####GNether Realm
+The Nether Realm is accessible only through a magic portal. Also
+known as Hell, this land is lethal to any who are unprepared for the
+ravages of Nether, and is guarded by Tik'srvzllat.
+#####BEquivalent to dungeon levels 666 to 696!!!!!
+
+
+ Created by Dawnmist for PernAngband 5.x.x
+ Updated for ToME 2.1.x
diff --git a/lib/help/essences.txt b/lib/help/essences.txt
new file mode 100644
index 00000000..f329fa80
--- /dev/null
+++ b/lib/help/essences.txt
@@ -0,0 +1,219 @@
+|||||oy
+~~~~~01|Spoilers|Essences
+~~~~~02|Alchemist|Essence Spoiler
+#####REssence Spoiler for ToME 2.2.0
+#####R------------------------------
+
+Essences are the tools of the trade for Alchemists, and unfortunately are
+useless for any other class. Alchemists use essences to create magical
+items for them to use.
+
+They can be either found on the floor while exploring the dungeon, or
+extracted from other magical items the alchemist finds during his
+adventures.
+
+To create an artifact, the alchemist will first have to have learnt the
+Artifact Creation ability. This ability costs 70 skill points (yes, 70,
+it's a very powerful ability!). And you need an alchemy skill of at least
+40, plus INT and WIS at 35 (thats 18/170 in non-linear form).
+To create the artifact, the alchemist will have to sacrifice 10 hit points,
+and an amount of magic essence similar to his skill in alchemy. The
+alchemist then allows the artifact to gain experience, and when it has
+enough, uses that experience to add abilities to the artifact. The
+alchemist can allow the artifact to continue to gain experience, thus
+keeping open the option to add more abilities later. This requires a
+similar amount of magic essence, but does not require the sacrifice of
+more hit points.
+
+Note that the experience you gain is divided among the artifacts that you
+have as well as going to yourself, so you will gain levels more slowly when
+empowering artifacts. Also, the artifact only gets 60% of the experience.
+So killing a creature worth 20xp would gain 10 for you, and 6 for the
+artifact.
+
+You can also modify existing artifacts when you attain skill level 50. Also
+at skill level 50 you will gain the ability to make temporary artifacts,
+which don't require the complex empowerments that regular items require,
+but also vanish after awhile.
+
+You cannot give an artifact an ability unless you have *Identified* an
+artifact which has that ability.
+
+For every four levels gained in the alchemy skill, the alchemist learns
+about objects of level (skill level)/4, starting by learning about level 1
+objects at skill level 0. (actually 1, but who's counting?)
+
+At skill level 5 you gain the ability to make ego items - but watch it!
+Your base failure rate will be 90%, and won't be 0% until you reach skill
+level 50. Adding gold will increase the chances of success in direct
+proportion to the value of the item you are trying to create. Note that
+this results in automatic success when the item you are trying to create
+happens to pick up a curse in the process.
+
+At skill level 5 you also gain knowledge of some basic ego item recipes.
+These are: Acidic, Shocking, Fiery, Frozen, Venomous, and Chaotic weapons,
+Resist Fire armour, and light sources of Fearlessness.
+
+At skill level 10 you will gain knowledge of digging ego items, if you have
+selected the option "always generate very unusual rooms" (ironman_rooms).
+
+At skill level 15 you can create ego wands, staves, rings, etc.
+
+At skill level 25 you gain the ability to empower double ego items.
+
+At skill level 50 you gain the ability to create temporary artifacts, which
+don't require any exotic ingredients beyond a single corpse of any type.
+
+Between skill levels 25 and 50, you will steadily gain the ability to set
+more and more flags.
+
+To finalise an artifact, you "P"ower it, and select the powers you want.
+Powers are divided into the following six categories:
+*****essences.txt*03[Stats, Sustains, Luck, Speed, Vision, etc.]
+*****essences.txt*04[Misc. (Auras, Light, See Invisibility, etc.)]
+*****essences.txt*05[Weapon Brands]
+*****essences.txt*06[Resistances and Immunities]
+*****essences.txt*07[ESP and Curses]
+*****essences.txt*08[Artifact Activations]
+
+~~~~~03
+#####GStats, Sustains, Luck, Speed, Vision, etc.
+lvl xp Power
+40 5000 Add to Strength Ring of Strength
+43 5000 Add to Intelligence Ring of Intelligence
+46 5000 Add to Wisdom Amulet of Wisdom
+46 5000 Add to Dexterity Ring of Dexterity
+42 5000 Add to Constitution Ring of Constitution
+30 5000 Add to Charisma Amulet of Adornment
+32 1000 Sustain Strength Ring of Sustain Strength
+34 1000 Sustain Intelligence Ring of Sustain Intelligence
+28 1000 Sustain Wisdom Ring of Sustain Wisdom
+36 1000 Sustain Dexterity Ring of Sustain Dexterity
+36 1000 Sustain Constitution Ring of Sustain Constitution
+25 1000 Sustain Charisma Ring of Sustain Charisma
+40 50000 Speed Ring of Speed
+38 150000 Extra Attacks Ring of Extra Attacks
+32 5000 Stealthy Left Insole from a Used Soft Boot
+29 2000 Adds to Searching Filthy Rag
+ 6 1000 Helps Infravision Brass Lantern
+30 1000 Lucky Rabbit's Left Forefoot
+25 30000 Aids in digging Pick
+40 50000 Multiplies Life Troll's Heart
+
+~~~~~04
+#####GMisc. (Auras, Light, See Invisibility, etc.)
+lvl xp Power
+20 15000 Invisibility Potion of Invisibility
+20 4000 See Invisible Potion of Invisibility
+20 30000 Free Action Iron Spike
+38 90000 Reflection Large Metal Shield
+20 30000 Aura of Fire Lungs from an Ancient Red Dragon
+25 30000 Aura of Lightning Lungs from an Ancient Blue Dragon
+ 8 1000 Light Everburning Torch
+20 10000 Bright Light Dwarven Lantern
+40 100000 Sunlight Feanorian Lamp
+40 200000 Flight Suit of Dragon Armour (any colour)
+50 10000000 Automatically IDs Morgoth's Testicles
+29 2000 Anti-Teleportation Teleport Inhibiting Amulet
+34 2000 Anti-Magic Magic Inhibiting Amulet
+50 100000 Wraith Form Potion of Invulnerability
+15 1000 Levitation Potion of Berserk Strength
+20 10000 Slow Digestion Lembas Wafer
+32 20000 Regenerate Mushroom of Unhealth
+12 20000 Teleport Mushroom of Confusion
+
+~~~~~05
+#####GWeapon Brands
+lvl xp Power
+30 20000 Extra Critical Hits Whip
+30 30000 Wounds Monsters Blade of Chaos
+26 6000 Vampiric Rod Tip of Drain Life
+16 2000 Slay Animal Dead Animal's Body
+25 2000 Slay Evil Evil Dead Thing's Remains
+30 2000 Slay Undead Remains of Undead Monster
+40 1500 Slay Demon Demon's Corpse
+10 700 Slay Orc Dead Orc
+16 700 Slay Troll Dead Troll
+25 900 Slay Giant Dead Giant
+33 2000 Slay Dragon Dead Dragon (any size will do)
+41 5000 *Slay* Dragon Mature Multi-Hued Dragon's Remains
+41 90000 *Slay* Undead Dead Summoner of Greater Undead
+41 90000 *Slay* Demon Lesser Balrog's Corpse
+36 20000 Vorpal
+40 90000 Earthquakes
+ 3 2000 Poison Brand
+12 2000 Acid Brand
+10 2000 Lightning Brand
+ 6 2000 Fire Brand
+ 8 2000 Frost Brand
+30 3000 Extra Might (Bows Only)
+35 3000 Extra Shots (Bows Only)
+
+~~~~~06
+#####GResistances and Immunities
+lvl xp Power
+49 500000 Immune to Acid Ancient Black Dragon's Foreskin
+50 500000 Immune to Lightning Ancient Blue Dragon's Foreskin
+49 500000 Immune to Fire Ancient Red Dragon's Foreskin
+50 500000 Immune to Cold Ancient White Dragon's Foreskin
+30 30000 Hold Life Amulet of the Magi
+12 10000 Resist Acid Ring of Acid
+15 10000 Resist Lightning Ring of Lightning
+13 10000 Resist Fire Potion of Resist Heat
+14 10000 Resist Cold Potion of Resist Cold
+25 30000 Resist Poison Potion of Cure Poison
+26 10000 Resist Fear Ring of Fear Resistance
+31 60000 Resist Light Ring of Light and Darkness Resistance
+31 60000 Resist Darkness Ring of Light and Darkness Resistance
+30 30000 Resist Blindness Ring of Blindness Resistance
+30 30000 Resist Confusion Ring of Confusion Resistance
+30 60000 Resist Sound Ring of Sound Resistance
+30 60000 Resist Shards Ring of Shard Resistance
+30 60000 Resist Nether Ring of Nether Resistance
+30 60000 Resist Nexus Ring of Nexus Resistance
+30 60000 Resist Chaos Ring of Chaos Resistance
+30 60000 Resist Disenchantment Ring of Disenchantment Resistance
+
+~~~~~07
+#####GESP and Curses
+lvl xp Power
+50 -100000 Temporary Item Corpse, any corpse
+10 -2000 Self-Cursing Filthy Rag
+45 -10000 Causes the Black Breath Sprig of Athelas
+40 -5000 Ancient Curse Scroll of *Remove Curse*
+40 -5000 Drains your Experience
+30 -5000 Aggravates Monsters
+30 -500 Curse Scroll of Remove Curse
+50 -5000 Permanently Cursed
+35 -2000 Can't be Dropped
+45 -5000 Drains your Hit Points
+20 -50000 Wielder Can't Move
+40 20000 Telepathy Formerly Floating Eye
+25 3000 Sense Orcs
+25 3000 Sense Trolls
+25 5000 Sense Dragons
+25 5000 Sense Giants
+25 5000 Sense Demons
+25 5000 Sense Undead
+25 5000 Sense Evil
+25 5000 Sense Animals
+25 5000 Sense Thunderlords
+25 5000 Sense Good
+25 5000 Sense Nonliving
+25 5000 Sense Unique Monsters
+25 2000 Sense Spiders
+
+~~~~~08
+#####GArtifact Activations
+lvl xp Power
+40 40000 Sunlight Brass Lantern
+20 4000 Magic Missile (1)
+30 300000 Magic Missile (2)
+40 400000 Ball of Missiles
+30 300000 Bolt of Lightning
+30 300000 Ball of Lightning
+35 350000 Ball of Lightning(2)
+40 400000 Ball of Lightning(3)
+40 400000 Ball of Lightning(4)
+45 450000 Breath Lightning
+50 40000 Fire a Rocket
diff --git a/lib/help/experien.hlp b/lib/help/experien.hlp
new file mode 100644
index 00000000..5e0bb9eb
--- /dev/null
+++ b/lib/help/experien.hlp
@@ -0,0 +1,28 @@
+|||||oy
+~~~~~01|Experience
+#####RGaining experience
+#####R==============================================
+
+The principle way for your character to gain experience (XP) is to kill
+monsters. There are a few other ways too, like lockpicking, but these only
+give small rewards.
+
+Once your character has gained enough experience to go up a level, then she
+will be given skill points to spend as you see fit. These points can be
+spent on either
+
+ *****/askills.txt*0[(a) Skills] which improve more for each point you put into them,
+or
+ *****/bability.txt*0[(b) Abilities] which are one-off purchases and grant your character new,
+ non-improvable powers
+
+Certain monsters can "drain" your experience, and thus your level. Although you
+do not lose the skill points you've already gained, you also will not gain
+further points until you reach a character level you have not already
+achieved. Luckily, you can restore drained experience through magical means,
+or by simply regaining the experience all over again.
+
+ *****/ynewbie.hlp*0[(y) New player help menu]
+ *****/zhelp.hlp*0[(z) Main menu]
+
+
diff --git a/lib/help/explore.hlp b/lib/help/explore.hlp
new file mode 100644
index 00000000..0c302ab8
--- /dev/null
+++ b/lib/help/explore.hlp
@@ -0,0 +1,16 @@
+|||||oy
+~~~~~01|Help|Exploring menu
+~~~~~02|Exploring menu
+#####RWelcome to the ToME Help System.
+#####R==============================================
+
+Please choose one of the following online help files:
+
+ *****/acommand.txt*0[(a) Available commands] How to control your character
+ *****/battack.txt*0[(b) Attacking monsters] How to attack, elemental attacks and resistances etc
+ *****/cdungeon.txt*0[(c) Exploring the dungeons] Symbols on your map, mining, pets, objects + more
+
+ *****/ynewbie.hlp*0[(y) New player help menu]
+ *****/zhelp.hlp*0[(z) Main menu]
+
+ \ No newline at end of file
diff --git a/lib/help/fatespoi.txt b/lib/help/fatespoi.txt
new file mode 100644
index 00000000..2815129e
--- /dev/null
+++ b/lib/help/fatespoi.txt
@@ -0,0 +1,28 @@
+|||||oy
+~~~~~01|Spoilers|Fates
+~~~~~02|Fates (spoiler)
+#####R Fate Spoiler
+#####R Accurate for PernAngband 5.x.x
+#####R by Dustin Ragan
+
+Numerous spirits inhabit the land of Arda, from the murderous barrow wights to
+the enigmatic Tom Bombadil. These spirits usually are bound to a specific
+geographic region, but there are exceptions to this rule. Sometimes one of
+these spirits will take interest in an adventurer. This can either be very,
+very good or very, very bad. These spirits will "rig" reality to ensure that
+something happens--or doesn't happen.
+
+In order to attract the attention of a spirit, the adventurer must be somewhat
+experienced, having attained at least the 11th level of experience. Every 10
+game turns, which corresponds to 1 normal speed player turn, there is a
+1 in 50,000 chance of gaining a fate. When this fate is chosen, there is a
+7/18 chance of being fated to find a specific mundane item on a specific
+dungeon level. A more belligerent spirit will, 7/18 of the time, summon a
+malicious monster to do battle on a specific dungeon level. There is a 1/9
+chance to be destined to find an artifact on a given level. There is also
+a 1/18 chance that you will meet your demise on a given level. Finally, there
+is a 1/18 chance of becoming invulnerable to attacks from mortals.
+
+Whenever a level is being chosen for a fate, it is always chosen within 20
+levels of your current recall depth. Items, monsters, and artifacts are all
+generated up to 10 levels out of depth for your current recall depth.
diff --git a/lib/help/foot.aux b/lib/help/foot.aux
new file mode 100644
index 00000000..47328799
--- /dev/null
+++ b/lib/help/foot.aux
@@ -0,0 +1,4 @@
+</TT></PRE>
+</FONT>
+</body>
+</html>
diff --git a/lib/help/g_eru.txt b/lib/help/g_eru.txt
new file mode 100644
index 00000000..113875b3
--- /dev/null
+++ b/lib/help/g_eru.txt
@@ -0,0 +1,65 @@
+|||||oy
+~~~~~01|Gods|Eru
+~~~~~02|Eru
+#####R === Eru Iluvatar ===
+
+Eru Iluvatar is the father of the Valar. His most faithful followers are those
+of the class *****c_pr_eru.txt*0[Priest(Eru)].
+
+#####GThe benefits of Worshipping Eru Iluvatar
+1. As you increase your piety, Eru will grant you a boost to your wisdom.
+ Eventually he will also start increasing your ability to handle magical
+ power, resulting in a boost to your spellpoints.
+2. If you are praying to him at the time, there is a chance that he will
+ deflect some blows from evil monsters (that increases with your level of
+ piety).
+3. If you are praying to him at the time, there is a chance that he will
+ resurrect you from the dead (provided you are very pious!).
+4. Your piety automatically increases over time if you are:
+ a) Not praying, and
+ b) Actively doing something (i.e. not resting or in the Wilderness map).
+
+#####GThe disadvantages of Worshipping Eru Iluvatar
+1. He doesn't like it if you destroy blessed weapons.
+2. You can only wield blunt or blessed weapons without penalty.
+3. He doesn't like it if you kill monsters that are aligned with good.
+4. He will completely abandon you if you wear The One Ring.
+~~~~~~03|Eru|Prayers
+#####GEru Iluvatar's Magic
+Worshipping Eru Iluvatar gives the adventurer access to a set of special
+spells that come directly from the hands of Eru. These spells use your piety
+to cast rather than your spellpoints, and the level of spells that Eru will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for his help without offending him!
+
+There is a special book called the "Holy Tome of Eru Iluvatar" which
+contains instructions for the procedure for each of the prayers Eru will
+grant. There are four prayers all told, which are:
+1. [[[[[BSee the Music] (Level 1)
+ Allows you to 'see' the Great Music from which the world originates,
+ allowing you to see unseen things, and can be cast while blind.
+ At spell level 10 it allows you to see your surroundings.
+ At spell level 20 it allows you to cure blindness.
+ At spell level 30 it allows you to fully see all the level.
+2. [[[[[BListen to the Music] (Level 7)
+ Allows you to listen to the Great Music from which the world originates,
+ allowing you to understand the meaning of things.
+ At spell level 14 it allows you to identify all your pack.
+ At spell level 30 it allows you to identify all items on the level.
+3. [[[[[BKnow the Music] (Level 30)
+ Allows you to understand the Great Music from which the world originates,
+ allowing you to know the full abilities of things.
+ At spell level 10 it allows you to *identify* all your pack.
+4. [[[[[BLay of Protection] (Level 35)
+ Creates a circle of safety around you.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Eru will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+ *****m_mana.txt*0[Mana School] at 1/2 the Prayer skill level.
+ *****m_divin.txt*0[Divination School] at 2/3 the Prayer skill level.
+ *****m_mind.txt*0[Mind School] at 1/3 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/help/g_manwe.txt b/lib/help/g_manwe.txt
new file mode 100644
index 00000000..4bbc85fd
--- /dev/null
+++ b/lib/help/g_manwe.txt
@@ -0,0 +1,62 @@
+|||||oy
+~~~~~01|Gods|Manwe
+~~~~~02|Manwe
+#####R === Manwe Sulimo ===
+
+Manwe is the strongest of the Valar, next to Morgoth. His most faithful
+followers are those of the class *****c_pr_man.txt*0[Priest(Manwe)].
+
+#####GThe benefits of Worshipping Manwe Sulimo
+1. As you increase your piety, Manwe will grant boosts to your speed (up to
+ a maximum boost of +7 speed).
+2. If you are praying, Manwe likes it when you kill monsters that are aligned
+ with evil.
+3. As your piety increases, Manwe will grant you the following abilities (in
+ order):
+ a) Levitation
+ b) Free Action (while praying)
+ c) Flying (while praying)
+4. Manwe likes elves.
+
+#####GThe disadvantages of Worshipping Manwe Sulimo
+1. Your piety slowly decreases with time, whether you are praying or not.
+2. He doesn't like it if you kill monsters that are aligned with good.
+3. He will completely abandon you if you wear The One Ring.
+~~~~~03|Manwe|Prayers
+#####GManwe Sulimo's Magic
+Worshipping Manwe Sulimo gives the adventurer access to a set of special
+spells that come directly from the hands of Manwe. These spells use your piety
+to cast rather than your spellpoints, and the level of spells that Manwe will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for his help without offending him!
+
+There is a special book called the "Holy Tome of Manwe Sulimo" which
+contains instructions for the procedure for each of the prayers Manwe will
+grant. There are four prayers all told, which are:
+1. [[[[[BManwe's Blessing] (Level 1)
+ Manwe's Blessing removes your fears, blesses you and surrounds you with holy
+ light.
+ At spell level 10 it also grants heroism.
+ At spell level 20 it also grants super heroism.
+ At spell level 30 it also grants holy luck and life protection.
+2. [[[[[BWind Shield] (Level 10)
+ It surrounds you with a shield of wind that deflects blows from evil
+ monsters.
+ At level 10 it increases your armour rating.
+ At level 20 it retaliates against monsters that melee you.
+3. [[[[[BManwe's Call] (Level 20)
+ Manwe's Call summons a Great Eagle to help you battle the forces of
+ Morgoth.
+4. [[[[[BAvatar] (Level 35)
+ It turns you into a full grown Maia.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Manwe will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+ *****m_air.txt*0[Air School] at 2/3 the Prayer skill level.
+ *****m_convey.txt*0[Conveyance School] at 1/2 the Prayer skill level.
+ *****m_meta.txt*0[Meta School] at 1/3 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/help/g_melkor.txt b/lib/help/g_melkor.txt
new file mode 100644
index 00000000..3f38aa32
--- /dev/null
+++ b/lib/help/g_melkor.txt
@@ -0,0 +1,64 @@
+|||||oy
+~~~~~01|Melkor
+~~~~~02|Gods|Melkor
+#####R === Melkor Bauglir ===
+
+Melkor Bauglir is Morgoth, the Dark Enemy. He once was the most powerful
+of the Valar. His most faithful followers are those of the class *****c_pr_drk.txt*0[Dark Priest].
+
+#####GThe benefits of Worshipping Melkor Bauglir
+ 1. As you increase your piety, Melkor will grant boosts to your strength,
+ constitution and charisma and will decrease intelligence and wisdom.
+ 2. As a follower of Melkor you are resistant to fire.
+ 3. If you are praying, Melkor may make you invisible and immune to fire.
+ 4. If you are praying, Melkor may cast Curse on your foes when you melee them.
+ 5. If you are praying, Melkor likes it when you kill monsters.
+ 6. If you are praying, Melkor *likes* it when you kill monsters that are
+ aligned with good.
+ 7. Melkor likes the sacrifice of corpses and books at his altars.
+ 8. Melkor likes the permanent sacrifice of your own health at his altars.
+ 9. Melkor hates elves.
+10. Melkor grants access to the *****m_udun.txt*0[Udun] school of magic.
+11. Melkor can summon undead and demons to help you when your life goes down.
+
+#####GThe disadvantages of Worshipping Melkor Bauglir
+1. Your piety decreases with time.
+2. Your piety decreases with time even more if you are praying.
+3. He will completely abandon you if you destroy The One Ring.
+~~~~~03|Melkor|Prayers
+#####GMelkor Bauglir's Magic
+Worshipping Melkor Bauglir gives the adventurer access to a set of special
+spells that come directly from the hands of Melkor. These spells use your piety
+to cast rather than your spellpoints, and the level of spells that Melkor will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for his help without offending him!
+
+There is a special book called the "Corrupted Tome of Melkor" which
+contains instructions for the procedure for each of the prayers Melkor will
+grant. There are three prayers all told, which are:
+1. [[[[[BCurse] (Level 1)
+ It curses a monster, reducing its melee power
+ At level 5 it can be auto-casted (with no piety cost) while fighting
+ if your piety is over 5000.
+ At level 15 it also reduces armor
+ At level 25 it also reduces speed
+ At level 35 it also reduces max life (but it is never fatal)
+2. [[[[[BCorpse Explosion] (Level 10)
+ It makes corpses in an area around you explode for a percent of their hit
+ points as damage
+3. [[[[[BMind Steal] (Level 20)
+ It allows your spirit to temporarily leave your own body, which will
+ be vulnerable, to control one of your enemies body
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Melkor will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. This school is as follows:
+ *****m_mind.txt*0[Mind School] at 1/3 the Prayer skill level.
+
+Melkor also grants all of his followers access to the *****m_udun.txt*0[Udun] school of magic,
+but only powerful mages are able to cast all of its spells.
+
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/help/g_tulkas.txt b/lib/help/g_tulkas.txt
new file mode 100644
index 00000000..2c05292a
--- /dev/null
+++ b/lib/help/g_tulkas.txt
@@ -0,0 +1,45 @@
+|||||oy
+~~~~~01|Tulkas
+~~~~~02|Gods|Tulkas
+#####R === Tulkas ===
+
+Another of the Valar. His most faithful followers are *****c_palad.txt*0[Paladins].
+
+#####GThe benefits of Worshipping Tulkas
+1. As you increase your piety, Tulkas will grant boosts to your constitution
+ and your strength (up to a maximum of +3 each).
+2. He likes it when you kill monsters that are aligned with evil.
+3. He loves it when you kill evil monsters while praying.
+4. He *adores* it when you kill demons while praying.
+5. If you are praying, Tulkas may increase the damage you do in melee combat.
+
+#####GThe disadvantages of Worshipping Tulkas
+1. When you are praying, your piety slowly decreases with time.
+2. He will completely abandon you if you wear The One Ring.
+~~~~~03|Tulkas|Prayers
+#####GTulkas's Magic
+Worshipping Tulkas gives the adventurer access to a set of special spells
+that come directly from the hands of Tulkas. These spells use your piety to
+cast rather than your spellpoints, and the level of spells that Tulkas will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for his help without offending him!
+
+There is a special book called the "War Tome of Tulkas" which contains
+instructions for the procedure for each of the prayers Tulkas will grant.
+There are three prayers all told, which are:
+1. [[[[[BDivine Aim] (Level 1)
+ It makes you more accurate in combat.
+ At spell level 20 all your blows are critical hits.
+2. [[[[[BWhirlwind] (Level 10)
+ It allows you to spin around and hit all monsters nearby.
+3. [[[[[BWave of Power] (Level 20)
+ It allows you to project a number of melee blows across a distance.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Tulkas will also assist with your ability to
+use some magic from one of the "standard" schools, in relation to how skilled
+you are at Prayer. This school is as follows:
+ *****m_earth.txt*0[Earth School] at 4/5 the Prayer skill level.
+The spells from this school are all cast using your normal spellpoints.
diff --git a/lib/help/g_yavann.txt b/lib/help/g_yavann.txt
new file mode 100644
index 00000000..6e6937ca
--- /dev/null
+++ b/lib/help/g_yavann.txt
@@ -0,0 +1,62 @@
+|||||oy
+~~~~~01|Yavanna
+~~~~~02|Gods|Yavanna
+#####R === Yavanna Kementari===
+
+Yavanna, the Giver of Fruits, created all plants and animals and awakened the
+Ents to protect the forests of Arda. Kementari, Queen of the Earth, is her
+surname. Her most faithful followers are the *****c_druid.txt*0[Druids].
+
+#####GThe benefits of Worshipping Yavanna
+1. As you increase your piety, Yavanna will grant you the ability to pass
+ trees while praying.
+2. She makes you regenerate faster while praying on grass.
+3. She likes it when you kill nonliving creatures, undead or demons.
+4. She likes it if you charm animals (except evil ones).
+5. Yavanna likes Ents.
+
+#####GThe disadvantages of Worshipping Yavanna
+1. Your piety slowly decreases with time, whether you are praying or not.
+2. She doesn't like it if you kill monsters while praying.
+3. She hates it if you kill animals while praying.
+4. She hates it if you hurt your animal pets.
+5. She hates it if you burn or destroy trees with magic or allow monsters to
+ do so.
+6. She will completely abandon you if you wear The One Ring.
+~~~~~03|Yavanna|Prayers
+#####GYavanna's Magic
+Worshipping Yavanna gives the adventurer access to a set of special spells
+that come directly from the hands of Yavanna. These spells use your piety to
+cast rather than your spellpoints, and the level of spells that Yavanna will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for her help without offending her!
+
+There is a special book called the "Forest Tome of Yavanna" which contains
+instructions for the procedure for each of the prayers Yavanna will grant.
+There are five prayers all told, which are:
+1. [[[[[BCharm Animal] (Level 1)
+ Tries to tame animals in a zone around your target.
+2. [[[[[BGrow Grass] (Level 10)
+ Creates a floor of grass around you. While on grass and praying,
+ a worshipper of Yavanna will know a greater regeneration rate.
+3. [[[[[BTree Roots] (Level 15)
+ Creates roots deep in the floor from your feet, making you more stable and
+ able to do better attacks, but preventing any movement (even teleportation).
+ It also makes you recover from stunning almost immediately.
+4. [[[[[BWater Bite] (Level 20)
+ Imbues your melee weapon with a natural stream of water.
+ At level 25, it spreads over a 1 radius zone around your target.
+5. [[[[[BUproot] (Level 35)
+ Awakes a tree to help you battle the forces of Morgoth.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to her specific magic, Yavanna will also assist with your ability
+to use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+ *****m_earth.txt*0[Earth School] at 1/2 the Prayer skill level.
+ *****m_nature.txt*0[Nature School] at 1/2 the Prayer skill level.
+ *****m_water.txt*0[Water School] at 1/2 the Prayer skill level.
+ *****m_tempo.txt*0[Temporal School] at 1/6 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/help/gambling.txt b/lib/help/gambling.txt
new file mode 100644
index 00000000..62352600
--- /dev/null
+++ b/lib/help/gambling.txt
@@ -0,0 +1,29 @@
+|||||oy
+~~~~~01|Gambling
+#####R=== Gambling Rules ===
+
+#####GBetween :
+ Three 12-sided dice rolled; 2 black, 1 red. The red
+ die must be between both black to win. If the red die
+ matches a black die, you lose. Pays 3 to 1
+#####GCraps:
+ Two 6-sided dice are rolled. On first roll, a 7 or 11
+ wins. A 2, 3 or 12 loses. Otherwise roll until the first
+ roll is matched (win) or a 7 is rolled (loss). Pays 2 to 1
+#####GWheel:
+ Pick a number from 0-9. If the number shows on wheel
+ after it stops spinning, you win. Pays 10 to 1
+
+#####GSlots:
+ Three dice rolled. Matches win gold.
+ Numbers are:
+ 1=Lemon, 2=Orange, 3=Sword, 4=Shield, 5=Plum, 6=Cherry
+ Payoffs are as follows:
+ Cherry Cherry Lemon 2-1 Cherry Cherry Orange 3-1
+ Cherry Cherry Sword 4-1 Cherry Cherry Shield 5-1
+ Cherry Cherry Plum 6-1
+ Lemon Lemon Lemon 4-1 Orange Orange Orange 16-1
+ Sword Sword Sword 6-1 Shield Shield Shield 25-1
+ Plum Plum Plum 9-1 Cherry Cherry Cherry 36-1
+
+
diff --git a/lib/help/general.txt b/lib/help/general.txt
new file mode 100644
index 00000000..17dc187c
--- /dev/null
+++ b/lib/help/general.txt
@@ -0,0 +1,39 @@
+|||||oy
+~~~~~01|Help
+#####R=== Using the Online Help ===
+
+This help system has been designed to be read whilst in-game. Printing it off
+will make it look clumsy and a little difficult to read.
+
+Any text in orange/yellow colour is likely to be a hyperlink, and pressing
+<enter> while the link is active (yellow) will take you to the relevant page.
+Navigate between viewable links by using the left-right keys. Some links also
+have bracketed letters included in the links. Pressing these letters on your
+keyboard will activate the link even if it is orange.
+
+The help files total over 850 kb, so there is a lot of information. They have
+been designed to be browsed, but you may be looking for specific information,
+in which case you should try looking at the alphabetical *****index.txt*0[index].
+
+Here are all the relevant keypresses for navigating the help system.
+
+#####GKey | Action
+-------------------------------------------------------------------
+Escape | Leave the Online Help
+Backspace | Return to previous Help File
+Space | Advance 1 page (screen)
+2, down arrow | Advance 1 line
+8, up arrow | Back up 1 line
+- | Back up 1 page (screen)
+6, right arrow | Advance 1 link
+4, left arrow | Back up 1 link
+Return | Activate the selected link
+# | Go to a specific line (defaults to line 0)
+% | Go to a specific help file (defaults to help.hlp)
+= | Highlight lines containing a string (e.g. "word")
+/ | Search for a string (e.g. "word")
+-------------------------------------------------------------------
+
+There are other sources for help playing ToME. Try http://forum.t-o-m-e.net
+and http://wiki.t-o-m-e.net . We also have an IRC channel #tome on the
+worldirc and freenode networks (they are linked) which is fairly low traffic.
diff --git a/lib/help/gods.txt b/lib/help/gods.txt
new file mode 100644
index 00000000..0d091204
--- /dev/null
+++ b/lib/help/gods.txt
@@ -0,0 +1,38 @@
+|||||oy
+~~~~~01|Gods
+#####RThe Guide to the Gods.
+
+#####G1. Introduction
+ Everybody likes to have a little helping hand now and then. What
+could be better than having a god on your side? But it's not quite that easy.
+The gods won't help just any mortal who calls for help. You have to give them
+a little something too.
+
+#####G2. How Do I Get in on This?
+ When you start a character, you get a choice of whether or not you
+wish to begin worshipping a God (unless you're something like a priest - they
+*must* start with a God to worship). If you do choose to be a follower of one
+of the Gods, you will gain certain abilities provided you do not do things
+that displease them. The measure of how happy your God is with you is your
+Piety - the Pt stat is your measure of Piety. Different actions will allow you
+to gain or lose Piety over time. You can change your mind about whom (if
+anyone) to worship during the game by finding an *****tome_faq.txt*04[altar] of that God.
+
+#####G3. What about spells?
+God-granted spells are also known as prayers, and are cast using Piety instead
+of Mana. God-spells can be increased in level by improving either your Prayer
+or Spell-power skill. The chance of successfully invoking a prayer depends
+on the Prayer skill and your wisdom.
+
+Each God also grants access to standard magical spell schools; which school(s)
+vary depending on the Gods' individual preferences. Spells from these schools
+are cast using Mana, not Piety; and success depends on your intelligence, not
+your wisdom.
+
+#####G4. So, Who Are These Gods?
+ In ToME, there are five Gods you may choose to worship, being:
+1. *****g_eru.txt*0[Eru Iluvatar] - the father of the Valar.
+2. *****g_manwe.txt*0[Manwe Sulimo] - the second strongest of the Valar (Morgoth was the strongest).
+3. *****g_yavann.txt*0[Yavanna Kementari] - the Earth Queen who created plants and animals.
+4. *****g_tulkas.txt*0[Tulkas] - another of the Valar, Tulkas values strength and courage.
+5. *****g_melkor.txt*0[Melkor Bauglir] - the Dark Enemy himself, once the most powerful of the Valar.
diff --git a/lib/help/head.aux b/lib/help/head.aux
new file mode 100644
index 00000000..92e979d3
--- /dev/null
+++ b/lib/help/head.aux
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>T.o.M.E. Documentation</title>
+ <meta name="description" content="ToME and TomeNET homepage. ToME is a roguelike dungeon exploration game, based on Angband.">
+ <meta name="keywords" content="angband, tome, tomenet, library, angband, official, roguelike">
+</head>
+<body bgcolor="#000000" text="#FFFFFF" link="#CC0000" alink="#FF9900" vlink="#FFCC66">
+<FONT text="#CCCCCC">
+<PRE><TT>
diff --git a/lib/help/help.hlp b/lib/help/help.hlp
new file mode 100644
index 00000000..7c4b431f
--- /dev/null
+++ b/lib/help/help.hlp
@@ -0,0 +1,33 @@
+|||||oy
+~~~~~01|Help|Main Menu
+~~~~~02|Main Menu
+#####RWelcome to the ToME Online Help System.
+#####R==============================================
+
+Please choose one of the following online help files:
+
+ *****/ageneral.txt*0[(a) About this help system]
+ *****/bnewbie.hlp*0[(b) Help for new players] Skills, magic, races, classes + more
+ *****/cadvanced.hlp*0[(c) Help for more experienced players] Options, Macros, Automatizer etc
+ *****/dtome_faq.txt*0[(d) ToME FAQ] Common questions
+
+ *****/sspoiler.hlp*0[(s) Spoiler menu] Dungeons, fates, luck, corruptions and stuff
+
+
+ *****/xindex.txt*0[(x) Alphabetical index] Trouble finding something? Try here
+
+#####GBasic keys:
+Space | Advance 1 page (screen)
+2, down arrow | Advance 1 line
+8, up arrow | Back up 1 line
+- | Back up 1 page (screen)
+6, right arrow | Advance 1 link
+4, left arrow | Back up 1 link
+Return | Activate the selected link
+Escape | Leave the Online Help
+Backspace, ? | Return to previous Help File
+# | Go to a specific line (defaults to line 0)
+% | Go to a specific help file (defaults to help.hlp)
+= | Highlight lines containing a string (e.g. "word")
+/ | Search for a string (e.g. "word")
+
diff --git a/lib/help/index.txt b/lib/help/index.txt
new file mode 100644
index 00000000..d306b688
--- /dev/null
+++ b/lib/help/index.txt
@@ -0,0 +1,592 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Help Index >
+#####R \----------------------------------------/
+
+This is the index of everything in the T.o.M.E. documentation.
+
+#####BHit a letter key to jump to the entries for that letter.
+
+Some entries in the index link to the same place as other entries. This is
+intentional, so that the information you want is easy to find.
+
+Don't forget you can browse the help from the *****help.hlp*02[Main menu].
+
+#####sSpotted a problem with the help files, or some content thats missing?
+#####sContact fearoffours@t-o-m-e.net .
+
+~~~~~65
+*****/Aindex.txt*65[A]
+ *****birth.txt*81[Abbreviations]
+ *****birth.txt*20[AC]
+ *****birth.txt*17[AU]
+ *****tome_faq.txt*25[FF]
+ *****birth.txt*21[HP]
+ *****birth.txt*29[Pt]
+ *****birth.txt*24[SN]
+ *****birth.txt*26[SP]
+ *****ability.txt*01[Abilities]
+ *****ability.txt*07[Ammo creation]
+ *****ability.txt*09[Artifact Creation]
+ *****ability.txt*05[Extra Max Blow 1]
+ *****ability.txt*06[Extra Max Blow 2]
+ *****ability.txt*10[Far reaching attack]
+ *****ability.txt*04[Perfect casting]
+ *****ability.txt*02[Spread blows]
+ *****ability.txt*08[Touch of death]
+ *****ability.txt*11[Trapping]
+ *****ability.txt*03[Tree walking]
+ *****ability.txt*12[Undead Form]
+ *****m_air.txt*02[Air Magic]
+ *****c_alchem.txt*01[Alchemist]
+ *****c_alchem.txt*03[Alchemy powers explained]
+ *****essences.txt*02[Essence Spoiler]
+ *****tome_faq.txt*03[Altars]
+ *****tome_faq.txt*37[Anti-magic Amulets and the Anti-magic shell]
+ *****c_unbel.txt*04[Antimagic]
+ *****c_archer.txt*01[Archer]
+ *****attack.txt*03[Armor]
+ *****birth.txt*19[Armor Class]
+ *****attack.txt*05[Resistances]
+ *****tome_faq.txt*18[Artifacts that activate but I cannot wear or wield]
+ *****c_assass.txt*01[Assassin]
+ *****attack.txt*01[Attacking Monsters]
+ *****attack.txt*06[Damage Effect type ]
+ *****attack.txt*04[Resistances]
+ *****birth.txt*48[Fighting ability]
+ *****birth.txt*50[Shooting]
+ *****automat.txt*03[Auto destroy]
+ *****automat.txt*02[Auto pick-up]
+ *****automat.txt*01[Automatizer]
+ *****defines.txt*82[Defines]
+ *****automat.txt*04[Autosquelch]
+ *****c_axemas.txt*01[Axemaster]
+~~~~~66
+*****/Bindex.txt*66[B]
+ *****rm_barb.txt*01[Barbarian]
+ *****c_bard.txt*01[Bard]
+ *****tome_faq.txt*36[Beginner strategy]
+ *****r_beorn.txt*01[Beorning]
+ *****birth.txt*84[Birth]
+ *****dungeon.txt*21[Buildings]
+~~~~~67
+*****/Cindex.txt*67[C]
+ *****birth.txt*11[Character]
+ *****birth.txt*46[Abilities]
+ *****birth.txt*10[Ability tables]
+ *****birth.txt*23[Armor Class]
+ *****birth.txt*02[Characteristics]
+ *****birth.txt*01[Creating a Character]
+ *****birth.txt*22[Hit Points]
+ *****birth.txt*28[Mana]
+ *****birth.txt*31[Piety]
+ *****birth.txt*08[Race and Class Combinations]
+ *****birth.txt*25[Sanity Points]
+ *****birth.txt*09[Stat Bonus Table]
+ *****birth.txt*13[Stats 1]
+ *****birth.txt*39[Stats 2]
+ *****tome_faq.txt*34[Character choice is too confusing]
+ *****birth.txt*45[Charisma]
+ *****birth.txt*05[Classes]
+ *****c_alchem.txt*02[Alchemist]
+ *****c_archer.txt*02[Archer]
+ *****c_assass.txt*02[Assassin]
+ *****c_axemas.txt*02[Axemaster]
+ *****c_bard.txt*02[Bard]
+ *****birth.txt*68[Combinations with Race]
+ *****c_pr_drk.txt*02[Dark Priest]
+ *****c_demono.txt*02[Demonologist]
+ *****c_druid.txt*02[Druid]
+ *****c_geoman.txt*02[Geomancer]
+ *****c_hafted.txt*02[Haftedmaster]
+ *****c_lorema.txt*02[Loremaster]
+ *****c_mage.txt*02[Mage]
+ *****c_mimic.txt*02[Mimic]
+ *****c_mindcr.txt*02[Mindcrafter]
+ *****c_monk.txt*02[Monk]
+ *****c_necro.txt*02[Necromancer]
+ *****c_palad.txt*02[Paladin]
+ *****c_polear.txt*02[Polearmmaster]
+ *****c_posses.txt*02[Possessor]
+ *****c_pr_eru.txt*02[Priest - Eru]
+ *****c_pr_man.txt*02[Priest - Manwe]
+ *****c_ranger.txt*02[Ranger]
+ *****c_rogue.txt*02[Rogue]
+ *****c_runecr.txt*02[Runecrafter]
+ *****c_sorcer.txt*02[Sorceror]
+ *****birth.txt*77[Stat Bonuses]
+ *****c_summon.txt*02[Summoners]
+ *****c_swordm.txt*02[Swordmasters]
+ *****c_symbia.txt*02[Symbiant]
+ *****c_thaum.txt*02[Thaumaturgy]
+ *****c_unbel.txt*02[Unbeliever]
+ *****c_warper.txt*02[Warper]
+ *****c_warrio.txt*02[Warrior]
+ *****rm_class.txt*01[Classical]
+ *****command.txt*99[Commands]
+ *****command.txt*116[Alteration commands]
+ *****command.txt*103[Command counts]
+ *****command.txt*111[Command descriptions ]
+ *****command.txt*129[Extras]
+ *****command.txt*123[Game status]
+ *****command.txt*128[Help]
+ *****command.txt*112[Inventory]
+ *****command.txt*121[Looking ]
+ *****command.txt*122[Messages]
+ *****command.txt*113[Movement]
+ *****command.txt*119[Object manipulation]
+ *****command.txt*100[Original keyset]
+ *****command.txt*126[Pref files]
+ *****command.txt*104[Repeating a command]
+ *****command.txt*114[Resting]
+ *****command.txt*101[Roguelike keyset]
+ *****command.txt*124[Saving and Exiting]
+ *****command.txt*115[Searching]
+ *****command.txt*102[Special keys]
+ *****command.txt*118[Spells and prayers]
+ *****command.txt*117[Terrain interaction]
+ *****command.txt*120[Throwing and missile weapons]
+ *****dungeon.txt*19[Companions]
+ *****birth.txt*43[Constitution]
+ *****m_convey.txt*02[Conveyance Magic]
+ *****corspoil.txt*01[Corruptions ]
+ *****c_archer.txt*03[Creating Ammo]
+ *****birth.txt*12[Creating a Character]
+ *****dungeon.txt*10[Cursed Objects]
+~~~~~68
+*****/Dindex.txt*68[D]
+ *****attack.txt*09[Damage Effects]
+ *****r_drkelf.txt*01[Dark Elf]
+ *****c_pr_drk.txt*01[Dark Priest]
+ *****tome_faq.txt*29[Dark grey things are difficult to see]
+ *****r_deathm.txt*01[DeathMolds]
+ *****spoil_faq.txt*19[Deathmolds on Mount Doom and other quest areas]
+ *****debug.txt*99[Debug]
+ *****debug.txt*100[Command List]
+ *****debug.txt*111[Command descriptions ]
+ *****debug.txt*112[General]
+ *****defines.txt*81[Defines]
+ *****defines.txt*84[Svals]
+ *****defines.txt*85[Tvals]
+ *****c_demono.txt*01[Demonologist]
+ *****m_demono.txt*02[Demonology Magic]
+ *****version.txt*01[Development history]
+ *****birth.txt*41[Dexterity]
+ *****birth.txt*56[Disarming traps]
+ *****birth.txt*37[Display]
+ *****m_divin.txt*02[Divination Magic]
+ *****c_druid.txt*01[Druid]
+ *****r_dunad.txt*01[Dunedain]
+ *****dungeon.txt*02[Dungeons]
+ *****dungeon.txt*12[Doors]
+ *****dungeon.txt*06[In the dungeon]
+ *****dungeon.txt*11[Mining]
+ *****dunspoil.txt*01[Spoilers]
+ *****r_dwarf.txt*01[Dwarf]
+ *****dungeon.txt*15[Dying]
+~~~~~69
+*****/Eindex.txt*69[E]
+ *****m_earth.txt*02[Earth Magic]
+ *****r_elf.txt*01[Elf]
+ *****r_ent.txt*01[Ent]
+ *****g_eru.txt*02[Eru]
+ *****g_eru.txt*03[Prayers]
+ *****c_pr_eru.txt*03[Priest - Eru]
+ *****tome_faq.txt*10[Essences]
+ *****experien.hlp*01[Experience]
+ *****explore.hlp*02[Exploring menu]
+~~~~~70
+*****/Findex.txt*70[F]
+ *****tome_faq.txt*02[FAQ - Spoiler free]
+ *****spoil_faq.txt*02[FAQ - contains spoilers]
+ *****tome_faq.txt*13[Prophets]
+ *****fatespoi.txt*02[Fates ]
+ *****m_fire.txt*02[Fire Magic]
+ *****inscrip.txt*01[Floor Inscriptions ]
+ *****tome_faq.txt*28[Floor tiles displaying incorrectly]
+ *****tome_faq.txt*05[Fountains]
+ *****tome_faq.txt*24[Fumblefingers quests]
+~~~~~71
+*****/Gindex.txt*71[G]
+ *****gambling.txt*01[Gambling]
+ *****tome_faq.txt*30[Game ]
+ *****c_geoman.txt*01[Geomancer]
+ *****m_geoman.txt*02[Geomancy spells]
+ *****r_gnome.txt*01[Gnome]
+ *****gods.txt*01[Gods]
+ *****tome_faq.txt*04[Altars]
+ *****g_eru.txt*01[Eru]
+ *****g_manwe.txt*01[Manwe]
+ *****g_melkor.txt*02[Melkor]
+ *****birth.txt*30[Piety]
+ *****spoil_faq.txt*23[Quest - Spoilers]
+ *****g_tulkas.txt*02[Tulkas]
+ *****g_yavann.txt*02[Yavanna]
+ *****birth.txt*16[Gold]
+~~~~~72
+*****/Hindex.txt*72[H]
+ *****c_hafted.txt*01[Haftedmaster]
+ *****r_hafelf.txt*01[Half-Elf]
+ *****r_hafogr.txt*01[Half-Ogre]
+ *****general.txt*01[Help]
+ *****explore.hlp*01[Exploring menu]
+ *****tome_faq.txt*01[FAQ - Spoiler free]
+ *****magic.hlp*02[Magic]
+ *****help.hlp*01[Main Menu]
+ *****newbie.hlp*01[New players]
+ *****spoil_faq.txt*01[Spoiled FAQ]
+ *****rm_herm.txt*01[Hermit]
+ *****r_hielf.txt*01[High-Elf]
+ *****r_hobbit.txt*01[Hobbit]
+ *****tome_faq.txt*12[Homes]
+ *****r_human.txt*01[Human]
+~~~~~73
+*****/Iindex.txt*73[I]
+ *****tome_faq.txt*35[I STILL keep dying]
+ *****tome_faq.txt*31[I keep dying]
+ *****dungeon.txt*04[Identifying features]
+ *****birth.txt*66[Infra-vision]
+ *****birth.txt*35[Intelligence]
+ *****birth.txt*85[Inventory - starting info]
+ *****tome_faq.txt*32[Invisible character]
+~~~~~75
+*****/Kindex.txt*75[K]
+ *****macrofaq.txt*44[Keymaps]
+ *****macrofaq.txt*46[Macro recorder]
+ *****r_kobold.txt*01[Kobold]
+~~~~~76
+*****/Lindex.txt*76[L]
+ *****dungeon.txt*23[Light]
+ *****dungeon.txt*17[Loading old characters]
+ *****c_lorema.txt*01[Loremaster]
+ *****rm_lsoul.txt*01[Lost Soul]
+ *****luckspoi.txt*01[Luck ]
+~~~~~77
+*****/Mindex.txt*77[M]
+ *****macrofaq.txt*43[Macros]
+ *****macrofaq.txt*45[Macro recorder]
+ *****c_mage.txt*01[Mage]
+ *****magic.txt*03[Magic]
+ *****m_air.txt*01[Air School]
+ *****m_convey.txt*01[Conveyance School]
+ *****m_demono.txt*01[Demonology School]
+ *****m_divin.txt*01[Divination School]
+ *****m_earth.txt*01[Earth School]
+ *****m_fire.txt*01[Fire School]
+ *****m_geoman.txt*01[Geomancy]
+ *****magic.hlp*01[Index]
+ *****birth.txt*27[Mana]
+ *****m_mana.txt*01[Mana School]
+ *****m_meta.txt*01[Meta School]
+ *****m_mimic.txt*01[Mimicry]
+ *****m_mind.txt*01[Mind School]
+ *****m_mindcr.txt*01[Mindcraft]
+ *****m_music.txt*01[Music]
+ *****m_nature.txt*01[Nature School]
+ *****m_necrom.txt*01[Necromancy]
+ *****magic.txt*01[Schools]
+ *****m_symbio.txt*01[Symbiosis]
+ *****m_tempo.txt*01[Temporal School]
+ *****m_thaum.txt*01[Thaumaturgy]
+ *****m_udun.txt*01[Udun School]
+ *****magic.txt*04[Wands and Staves]
+ *****m_water.txt*01[Water School]
+ *****birth.txt*58[Magical Devices]
+ *****r_maia.txt*01[Maia]
+ *****help.hlp*02[Main Menu]
+ *****m_mana.txt*02[Mana Magic]
+ *****g_manwe.txt*02[Manwe]
+ *****g_manwe.txt*03[Prayers]
+ *****c_pr_man.txt*03[Priest - Manwe]
+ *****tome_faq.txt*14[Mathilde]
+ *****g_melkor.txt*01[Melkor]
+ *****c_pr_drk.txt*03[Dark Priests]
+ *****g_melkor.txt*03[Prayers]
+ *****m_meta.txt*02[Meta Magic]
+ *****c_mimic.txt*01[Mimic]
+ *****m_mimic.txt*02[Mimicry powers]
+ *****m_mind.txt*02[Mind Magic]
+ *****c_mindcr.txt*01[Mindcrafter]
+ *****m_mindcr.txt*02[Mindcraft powers]
+ *****dungeon.txt*13[Mining]
+ *****birth.txt*18[Money]
+ *****c_monk.txt*01[Monk]
+ *****c_monk.txt*03[Monk attacks]
+ *****dungeon.txt*05[Monsters]
+ *****attack.txt*02[Attacking]
+ *****attack.txt*07[Monster Memory]
+ *****dungeon.txt*20[Pets]
+ *****tome_faq.txt*08[They are talking to me]
+ *****m_music.txt*02[Music]
+~~~~~78
+*****/Nindex.txt*78[N]
+ *****m_nature.txt*02[Nature Magic]
+ *****c_necro.txt*01[Necromancer]
+ *****m_necrom.txt*02[Necromancy Magic]
+~~~~~79
+*****/Oindex.txt*79[O]
+ *****dungeon.txt*14[Objectives]
+ *****dungeon.txt*08[Objects]
+ *****dungeon.txt*21[Colour of inventory slot letter]
+ *****dungeon.txt*09[Cursed Objects]
+ *****tome_faq.txt*33[Piles]
+ *****option.txt*05[Options]
+ *****option.txt*16[Automatizer]
+ *****option.txt*15[Autosave]
+ *****option.txt*13[Base Delay Factor]
+ *****option.txt*18[Cheating]
+ *****option.txt*09[Disturbance]
+ *****option.txt*19[Dump]
+ *****option.txt*11[Efficiency]
+ *****option.txt*10[Game-play]
+ *****option.txt*14[Hitpoint Warning]
+ *****option.txt*07[Ingame]
+ *****option.txt*08[Interface]
+ *****option.txt*06[Startup]
+ *****option.txt*12[ToME Options]
+ *****option.txt*17[Window Flags]
+ *****r_orc.txt*01[Orc]
+~~~~~80
+*****/Pindex.txt*80[P]
+ *****c_palad.txt*01[Paladin]
+ *****birth.txt*62[Perception]
+ *****dungeon.txt*18[Pets]
+ *****r_pettyd.txt*01[Petty Dwarf]
+ *****c_polear.txt*01[Polearmmaster]
+ *****c_posses.txt*01[Possessor]
+ *****c_posses.txt*03[Possessor powers ]
+ *****command.txt*105[Pref files]
+ *****command.txt*109[Colors]
+ *****command.txt*127[Commands]
+ *****command.txt*107[Keymaps]
+ *****command.txt*106[Macros]
+ *****command.txt*110[Options]
+ *****command.txt*108[Visuals]
+ *****c_pr_eru.txt*01[Priest - Eru]
+ *****c_pr_man.txt*01[Priest - Manwe]
+ *****c_priest.txt*01[Priests]
+~~~~~82
+*****/Rindex.txt*82[R]
+ *****birth.txt*04[Race Modifiers]
+ *****birth.txt*79[Ability table]
+ *****rm_barb.txt*02[Barbarian]
+ *****rm_class.txt*02[Classical]
+ *****rm_herm.txt*02[Hermit]
+ *****rm_lsoul.txt*02[Lost Soul]
+ *****rm_skel.txt*02[Skeleton]
+ *****rm_spec.txt*02[Spectre]
+ *****birth.txt*76[Stat Bonuses]
+ *****rm_vamp.txt*02[Vampire]
+ *****rm_zomb.txt*02[Zombie]
+ *****birth.txt*03[Races]
+ *****birth.txt*78[Ability table]
+ *****r_beorn.txt*02[Beorning]
+ *****birth.txt*67[Combinations with class]
+ *****r_drkelf.txt*02[Dark Elf]
+ *****r_deathm.txt*02[DeathMolds]
+ *****r_dunad.txt*02[Dunedain]
+ *****r_dwarf.txt*02[Dwarf]
+ *****r_elf.txt*02[Elf]
+ *****r_ent.txt*02[Ent]
+ *****r_gnome.txt*02[Gnome]
+ *****r_hafelf.txt*02[Half-Elf]
+ *****r_hafogr.txt*02[Half-Ogre]
+ *****r_hielf.txt*02[High-Elf]
+ *****r_hobbit.txt*02[Hobbit]
+ *****r_human.txt*02[Human]
+ *****r_kobold.txt*02[Kobold]
+ *****r_maia.txt*02[Maia]
+ *****r_orc.txt*02[Orc]
+ *****r_pettyd.txt*02[Petty Dwarf]
+ *****r_rohank.txt*02[RohanKnight]
+ *****birth.txt*75[Stat Bonuses]
+ *****r_thlord.txt*02[Thunderlord]
+ *****r_troll.txt*02[Troll]
+ *****r_wodelf.txt*02[Wood Elf]
+ *****r_yeek.txt*02[Yeek]
+ *****tome_faq.txt*26[Random quests are not working]
+ *****tome_faq.txt*36[Random quests strategy]
+ *****c_ranger.txt*01[Ranger]
+ *****c_rogue.txt*01[Rogue]
+ *****r_rohank.txt*01[RohanKnight]
+ *****c_runecr.txt*01[Runecrafter]
+ *****c_runecr.txt*03[Runecrafter powers]
+ *****tome_faq.txt*11[Runes]
+~~~~~83
+*****/Sindex.txt*83[S]
+ *****command.txt*125[Saving and Exiting]
+ *****birth.txt*52[Saving throw]
+ *****birth.txt*60[Searching]
+ *****birth.txt*63[Searching Ability]
+ *****birth.txt*61[Searching Frequency - Perception]
+ *****tome_faq.txt*09[Sentient weapons]
+ *****rm_skel.txt*01[Skeleton]
+ *****skills.txt*55[Skills]
+ *****skills.txt*27[Air]
+ *****m_air.txt*03[Air - Spell Info]
+ *****skills.txt*49[Alchemy]
+ *****c_alchem.txt*05[Alchemy - Alchemy powers]
+ *****skills.txt*50[Antimagic]
+ *****c_unbel.txt*05[Antimagic powers]
+ *****skills.txt*08[Archery]
+ *****skills.txt*05[Axe-mastery]
+ *****skills.txt*18[Backstab]
+ *****skills.txt*13[Barehand-combat]
+ *****skills.txt*61[Bearform-combat]
+ *****skills.txt*12[Boomerang-mastery]
+ *****skills.txt*58[Boulder-throwing]
+ *****skills.txt*10[Bow-mastery]
+ *****skills.txt*01[Combat]
+ *****skills.txt*30[Conveyance]
+ *****m_convey.txt*03[Conveyance - Spell Info]
+ *****skills.txt*44[Corpse-preservation]
+ *****skills.txt*04[Critical-Hits]
+ *****skills.txt*11[Crossbow-mastery]
+ *****skills.txt*52[Demonology]
+ *****m_demono.txt*03[Demonology - Spell Info]
+ *****skills.txt*16[Disarming]
+ *****skills.txt*31[Divination]
+ *****m_divin.txt*03[Divination - Spell Info]
+ *****skills.txt*20[Dodging]
+ *****skills.txt*28[Earth]
+ *****m_earth.txt*03[Earth - Spell Info]
+ *****skills.txt*25[Fire]
+ *****m_fire.txt*03[Fire - Spell Info]
+ *****skills.txt*60[Geomancy]
+ *****m_geoman.txt*03[Geomancy - Spell Info]
+ *****skills.txt*06[Hafted-mastery]
+ *****skills.txt*57[List of skills]
+ *****skills.txt*21[Magic]
+ *****skills.txt*54[Magic-device]
+ *****skills.txt*24[Mana]
+ *****m_mana.txt*03[Mana - Spell Info]
+ *****skills.txt*29[Meta]
+ *****m_meta.txt*03[Meta - Spell Info]
+ *****skills.txt*47[Mimicry]
+ *****m_mimic.txt*03[Mimicry - mimicry powers]
+ *****skills.txt*33[Mind]
+ *****m_mind.txt*03[Mind - Spell Info]
+ *****skills.txt*41[Mindcraft]
+ *****m_mindcr.txt*03[Mindcraft - Spell Info]
+ *****skills.txt*42[Monster-lore]
+ *****skills.txt*59[Music]
+ *****m_music.txt*03[Music - Song Info]
+ *****skills.txt*34[Nature]
+ *****m_nature.txt*03[Nature - Spell Info]
+ *****skills.txt*35[Necromancy]
+ *****m_necrom.txt*03[Necromancy - Spell Info]
+ *****skills.txt*07[Polearm-mastery]
+ *****skills.txt*45[Possession]
+ *****c_posses.txt*04[Possession - Possessor powers ]
+ *****skills.txt*39[Prayer]
+ *****skills.txt*36[Runecraft]
+ *****c_runecr.txt*04[Runecrafting - Runecrafter powers]
+ *****skills.txt*56[Screen]
+ *****skills.txt*09[Sling-mastery]
+ *****skills.txt*14[Sneakiness]
+ *****skills.txt*23[Sorcery]
+ *****skills.txt*22[Spell-power]
+ *****skills.txt*38[Spirituality]
+ *****skills.txt*19[Stealing]
+ *****skills.txt*15[Stealth]
+ *****skills.txt*53[Stunning-blows]
+ *****skills.txt*43[Summoning]
+ *****c_summon.txt*04[Summoning - Summoning powers]
+ *****skills.txt*03[Sword-mastery]
+ *****skills.txt*46[Symbiosis]
+ *****m_symbio.txt*03[Symbiosis - Symbiotic Powers]
+ *****skills.txt*32[Temporal]
+ *****m_tempo.txt*03[Temporal - Spell Info]
+ *****skills.txt*37[Thaumaturgy]
+ *****m_thaum.txt*03[Thaumaturgy - Spell Info]
+ *****skills.txt*48[Udun]
+ *****m_udun.txt*03[Udun - Spell Info]
+ *****skills.txt*26[Water]
+ *****m_water.txt*03[Water - Spell Info]
+ *****skills.txt*02[Weaponmastery]
+ *****c_sorcer.txt*01[Sorceror]
+ *****rm_spec.txt*01[Spectre]
+ *****spoiler.hlp*01[Spoilers]
+ *****corspoil.txt*02[Corruptions]
+ *****dunspoil.txt*02[Dungeons]
+ *****essences.txt*01[Essences]
+ *****fatespoi.txt*01[Fates]
+ *****inscrip.txt*02[Floor Inscriptions]
+ *****spoil_faq.txt*20[God Quest - directions]
+ *****spoil_faq.txt*22[God Quest - how many]
+ *****spoil_faq.txt*21[God Quest - relic]
+ *****spoil_faq.txt*07[Lothlorien Poisoned water quest]
+ *****luckspoi.txt*02[Luck]
+ *****spoil_faq.txt*06[Merton the lost Hobbit quest]
+ *****wishing.txt*01[Wishing]
+ *****birth.txt*82[Stats]
+ *****birth.txt*71[Bonus table]
+ *****birth.txt*44[Charisma]
+ *****birth.txt*42[Constitution]
+ *****birth.txt*40[Dexterity]
+ *****birth.txt*14[Display]
+ *****birth.txt*06[Individual explanations]
+ *****birth.txt*33[Intelligence]
+ *****birth.txt*32[Strength]
+ *****birth.txt*36[Wisdom]
+ *****magic.txt*05[Staves]
+ *****birth.txt*54[Stealth]
+ *****tome_faq.txt*17[Strange items]
+ *****birth.txt*34[Strength]
+ *****c_summon.txt*01[Summoners]
+ *****c_summon.txt*03[Summoning]
+ *****defines.txt*12[Svals]
+ *****c_swordm.txt*01[Swordmasters]
+ *****c_symbia.txt*01[Symbiant]
+ *****c_symbia.txt*03[Naming your symbiote]
+ *****m_symbio.txt*02[Symbiosis Magic]
+ *****dungeon.txt*03[Symbols]
+~~~~~84
+*****/Tindex.txt*84[T]
+ *****birth.txt*69[Tables]
+ *****birth.txt*74[Ability Tables]
+ *****birth.txt*70[Combinations of Race and Class]
+ *****c_monk.txt*04[Monk attacks]
+ *****birth.txt*72[Stat bonuses]
+ *****m_tempo.txt*02[Temporal Magic]
+ *****m_thaum.txt*02[Thaumaturgical Magic]
+ *****c_thaum.txt*01[Thaumaturgist]
+ *****r_thlord.txt*01[Thunderlord]
+ *****whattome.txt*01[ToME - a General Description]
+ *****dungeon.txt*07[Town]
+ *****r_troll.txt*01[Troll]
+ *****g_tulkas.txt*01[Tulkas]
+ *****c_palad.txt*03[Paladin]
+ *****g_tulkas.txt*03[Prayers]
+ *****defines.txt*83[Tvals]
+~~~~~85
+*****/Uindex.txt*85[U]
+ *****m_udun.txt*02[Udun Magic]
+ *****c_unbel.txt*01[Unbeliever]
+ *****c_unbel.txt*03[Antimagic]
+~~~~~86
+*****/Vindex.txt*86[V]
+ *****rm_vamp.txt*01[Vampire]
+ *****tome_faq.txt*16[Void jumpgates]
+ *****dungeon.txt*23[Void jumpgates]
+~~~~~87
+*****/Windex.txt*87[W]
+ *****magic.txt*02[Wands]
+ *****c_warper.txt*01[Warper]
+ *****c_warrio.txt*01[Warrior]
+ *****m_water.txt*02[Water Magic]
+ *****birth.txt*86[Weapons - starting info]
+ *****tome_faq.txt*27[Weird display]
+ *****dungeon.txt*1[Wilderness]
+ *****birth.txt*38[Wisdom]
+ *****r_wodelf.txt*01[Wood Elf]
+ *****tome_faq.txt*15[Wrists hurting]
+~~~~~89
+*****/Yindex.txt*89[Y]
+ *****g_yavann.txt*01[Yavanna]
+ *****c_druid.txt*03[Druid]
+ *****g_yavann.txt*03[Prayers]
+ *****r_yeek.txt*01[Yeek]
+~~~~~90
+*****/Zindex.txt*90[Z]
+ *****rm_zomb.txt*01[Zombie]
diff --git a/lib/help/inscrip.txt b/lib/help/inscrip.txt
new file mode 100644
index 00000000..517c81c2
--- /dev/null
+++ b/lib/help/inscrip.txt
@@ -0,0 +1,65 @@
+~~~~~01|Floor Inscriptions (spoiler)
+~~~~~02|Spoilers|Floor Inscriptions
+#####R=== Floor Inscriptions ===
+
+It is possible to inscribe words on the floor in ToME. If you happen
+to be lucky and inscribe a spell formula from another language, the inscription
+will use the floor's mana to cast that spell when either you walk over it, a
+monster walks over it, or both walk over it. Not all inscriptions are triggered
+by monsters, and not all can be triggered by the player.
+
+In order to write an inscription in another language, you must first have found
+and read a parchment with some of that language's words upon it. So, just
+copying the inscriptions here won't work unless you have read the words on a
+parchment first ;-).
+
+#####GLight up the Room
+Inscription: 'ure nimir' (sun shine)
+Parchment: Numenorean for Beginners (I)
+Triggered by: Player, Monster.
+Grid Mana Needed: 30
+Effect: Lights up the current room
+
+#####GDarkness in Room
+Inscription: 'lomi gimli' (night stars)
+Parchment: Numenorean for Beginners (II)
+Triggered by: Player, Monster.
+Grid Mana Needed: 10
+Effect: Casts the room into darkness
+
+#####GStorm
+Inscription: 'dulgi bawiba' (black winds)
+Parchment: Advanced Lessons of Numenorean
+Triggered by: Player, Monster.
+Grid Mana Needed: 40
+Effect: Electrical Ball of energy released around the inscription
+
+#####GProtection
+Inscription: 'pedo mellon a minno' (say friend and enter)
+Parchment: Advanced Lessons of Sindarin
+Triggered by: Monster.
+Grid Mana Needed: 8
+Effect: Prevents a monster from stepping on the affected square
+
+#####GDwarven summoning
+Inscription: 'Baruk Khazad! Khazad aimenu!' (Axes of the Dwarves, the Dwarves
+ are upon you!)
+Parchment: Khuzdul - The Hidden Tongue of the Dwarves
+Triggered by: Player.
+Grid Mana Needed: 100
+Effect: Generates friendly Dwarven Warriors to help your cause
+
+#####GOpen Chasm
+Inscription: 'dunna hrassa' (black precipice)
+Parchment: Nandorin for Dummies
+Triggered by: Monster.
+Grid Mana Needed: 50
+Effect: Creates a bottomless hole in the floor that monsters (and potentially
+ objects) fall down
+
+#####GBlast of Black Fire
+Inscription: 'burz ghash ronk' (black fire pool)
+Parchment: Advanced Lessons of Orcish
+Triggered by: Player, Monster.
+Grid Mana Needed: 60
+Effect: Releases a ball of Hellfire around the inscription
diff --git a/lib/help/lua.hlp b/lib/help/lua.hlp
new file mode 100644
index 00000000..ba61676a
--- /dev/null
+++ b/lib/help/lua.hlp
@@ -0,0 +1,34 @@
+|||||oy
+~~~~~01|Help|Lua scripting for ToME
+#####R Welcome to the ToME Lua Help System.
+#####R=============================================
+
+Please choose one of the following help files:
+
+ *****/alua_intr.txt*0[(a) An Introduction to scripting]
+ *****/blua_pow.txt*0[(b) Adding a racial power (the 'U' menu)]
+ *****/clua_skil.txt*0[(c) Adding new skills (the 'm' menu)]
+ *****/dlua_ques.txt*0[(d) Adding a quest]
+
+
+ *****/elua_mon.txt*0[(e) Useful functions in monster.pkg]
+ *****/flua_play.txt*0[(f) Useful functions in player.pkg]
+ *****/glua_spel.txt*0[(g) Useful functions in spell.pkg]
+ *****/hlua_util.txt*0[(h) Useful functions in util.pkg]
+
+ *****/ilua_gf.txt*0[(g) A list of GF_FOO flags]
+
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/help/lua_gf.txt b/lib/help/lua_gf.txt
new file mode 100644
index 00000000..000f4af5
--- /dev/null
+++ b/lib/help/lua_gf.txt
@@ -0,0 +1,45 @@
+|||||oy
+#####R /--------------------------\
+#####R< A partial list of GF_FLAGS >
+#####R \--------------------------/
+
+GF_ARROW: arrows
+GF_MISSILE: magic missiles
+GF_MANA: mana
+GF_LITE_WEAK: light
+GF_DARK_WEAK: dark
+GF_WATER: water
+GF_PLASMA: plasma
+GF_METEOR: meteors
+GF_ICE: ice
+GF_GRAVITY: gravity
+GF_INERTIA: inertia
+GF_FORCE: force
+GF_TIME: pure time
+GF_ACID: acid
+GF_ELEC: lightning
+GF_FIRE: flames
+GF_COLD: cold
+GF_POIS: poison
+GF_LITE: pure light
+GF_DARK: pure dark
+GF_CONFUSION: confusion
+GF_SOUND: sound
+GF_SHARDS: shards
+GF_NEXUS: nexus
+GF_NETHER: nether
+GF_CHAOS: chaos
+GF_DISENCHANT: disenchantment
+GF_KILL_WALL: wall destruction
+GF_KILL_DOOR: door destruction
+GF_KILL_TRAP: trap destruction
+GF_STONE_WALL: wall creation
+GF_MAKE_DOOR: door creation
+GF_MAKE_TRAP: trap creation
+GF_DESTRUCTION: destruction
+
+Back to the *****lua.hlp*0[lua help index] .
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
+
+
diff --git a/lib/help/lua_intr.txt b/lib/help/lua_intr.txt
new file mode 100644
index 00000000..ccb87067
--- /dev/null
+++ b/lib/help/lua_intr.txt
@@ -0,0 +1,133 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Scripting for ToME with lua >
+#####R \----------------------------------------/
+
+So, you want to patch ToME eh? Maybe you've had a look at how the edit files
+work, maybe even added your own race/class, but want to go further and add
+new racial (U) or magic (m) powers. Well these help files will show a little
+bit of how to do that.
+
+I am not a master at this kind of thing. I wrote a small script, with much
+help from DarkGod, and he subsequently asked me to write these help files. I
+was looking forward to when the lua help files came out so that I could look
+at them myself. Little did I know I'd be asked to write them. Therefore I
+apologise for any inaccuracies or errors that you find, and if you care to let
+me know of any improvements which could be made (especially if you're an
+experienced programmer/scripter), I'd love to know. Email me at
+[[[[[gfearoffours@moppy.co.uk].
+
+#####R=== The example scripts ===
+
+These help files take the form of a tutorial, adding a line at a time to a
+script, and explaining important concepts along the way. To see it all in
+action, I strongly suggest that you download my example script pack from
+[[[[[Ghttp://www.moppy.co.uk/angband.htm]. As well as including all the
+scripts covered in these help files, they also include the addition of my
+"hina" race which has a Lua scripted racial power which you might like to look
+at. There's also a quest which I will be including documentation for as a
+tutorial soon. Plus there's all the other lua scripts in the lib\scpt
+directory to look at. Most of what you see in these files has been learned from
+those files anyway!
+
+The source code is invaluable as well. There's a searchable and browsable
+version of the latest ToME source code available online at
+[[[[[Ghttp://www.t-o-m-e.net/cvs.php]. Use it!
+
+If you don't want to download and install the example scripts, then just
+follow the tutorials with a text editor open! But I'll say it again, it's a lot
+easier if you download and install the example scripts.
+
+This file goes on to explain the concepts of scripting, programming,
+variables and functions. If you're familiar with these concepts, you might
+as well take a look at how to add a power to the U menu in the
+*****lua_pow.txt*0[Scripting a racial power] file.
+
+
+#####R=== Defining some basic stuff ===
+
+Computers don't do anything that they're not told to do. When we script, or
+program, we must assume they know nothing. We have to tell them each little
+bit of information from the ground up.
+
+A program, or a script (we'll talk about exact differences later) is like a
+set of instructions. Let's imagine that people responded to programs, and
+that we had a program called "Housework". Its series of instructions might
+look something like this:
+
+#####BDo the Washing up.
+#####BClean the kitchen.
+#####BDust the shelves.
+#####BHoover the lounge.
+
+Each step above could be called a function, as they are all actions that
+need to be carried out. Now to you and me, we'd understand that program just
+fine, but if someone didn't know HOW to wash, or what hoovering was, they'd
+soon run into problems. For those people we'd need to define each function
+clearly. Thus "do the washing up" might be -
+
+#####BRun hot water into bowl.
+#####BAdd washing up liquid.
+#####BPut dirty plates into bowl
+#####BScrub plates till clean
+#####BPlace clean plates on rack to dry,
+
+There's still plenty of problems here though. We've not said to turn the tap
+off, or what the bowl is, or to wash any dirty cutlery, mugs, saucepans, etc.,
+etc. Whilst this might seem fairly obvious to a person, this is how we need
+to think when writing programs for computers.
+
+Lets look now at some of the terms we're going to be using, in the rest of
+these help files, and what they mean...
+
+#####R=== Variables and Constants ===
+A variable is a way to store information in a computer. Just as you store
+things in your own memory, you can store things in the computer's memory. And
+just as things change in your memory, so things can change in the computer's
+memory. This factor of change is why they're called "variables" and not
+"statics".
+
+For instance, you may have a friend's email address committed to memory, but
+things change over time, they get a new ISP or domain, and so their email
+address changes. You commit this new address to memory, and eventually
+forget the old one. The thing you have stored in your memory is the same
+(your friend's address) but the value (property) of what you have stored has
+changed (from friend@old-address.com to friend@new-address.com).
+
+Variables are the building blocks out of which you will create your patch.
+
+A variable which will *never* change its value is called a constant.
+
+#####R===Functions===
+
+A function is a series of steps or statements, grouped together and given
+one name. When you want to carry out those steps, you simply ask the
+computer to carry out that function. To go back to our original example,
+rather than saying, "I'd like you to run some hot water into a bowl, add the
+washing up liquid, put the dirty plates into it, and then scrub them till
+they're clean", we just say "do the washing up".
+
+This is where we come to the difference between scripting and programming.
+With scripting we can use the functions and variables that exist in the
+ToME code. Maintainers like DarkGod have already made sure that the
+computer knows how to "do the washing up", including turning the tap off and
+what the bowl is. All we need to do in our script is say "do the washing
+up". Or to look at it in a more relevant way, the game has been coded so
+that when a magic missile is fired, a bolt or beam spell with a black line
+of asterisks will be drawn in the direction indicated by the player, the
+mana of that spell will be used up, the monster will take the appropriate
+amount of damage, and so on. All we need to do in our script is say "fire a
+magic missile".
+
+As you script, you will still be designing your own functions, and
+variables, but the hardest parts have been done for you!
+
+Not every function and global variable in the source-code has been exported to
+use in your scripting. But the ones that have are easily identifiable by
+looking in any source files with the extension .pkg . Chris Hadgis has written
+some excellent documentation which outline the use of the most important
+functions in some of these files. They outline the functions from the
+
+OK, the first tutorial proper is on *****lua_pow.txt*0[adding a racial power] .
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
diff --git a/lib/help/lua_mon.txt b/lib/help/lua_mon.txt
new file mode 100644
index 00000000..9bb363c0
--- /dev/null
+++ b/lib/help/lua_mon.txt
@@ -0,0 +1,535 @@
+|||||oy
+
+#####R /----------------------------------------\
+#####R < monster.pkg functions helper file >
+#####R \----------------------------------------/
+
+
+----------------------------------------------------------------------
+
+#####R=== race_info_idx ===
+
+#####GDeclaration
+ extern monster_race* race_info_idx(int r_idx, int ego);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Return a (monster_race*) with the combinations of the monster
+ * properties and the ego type
+ */
+
+#####GDescription
+Get monster info and ego info for monster with monster index "r_idx"
+and monster ego "ego". The ego information is applied to the monster
+information and the new monster information is returned.
+
+For example, race_info_idx(141,7) will create a brown yeek (monster)
+shaman (ego).
+
+#####GParameters
+> "r_idx" is an entry from the "r_info.txt" file. Beware: there is no
+ range checking.
+> "ego" is an entry from the "re_info.txt". Beware: there is no range
+ checking.
+
+----------------------------------------------------------------------
+
+#####R=== delete_monster_idx ===
+
+#####GDeclaration
+ extern void delete_monster_idx(int i);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Delete a monster by index.
+ *
+ * When a monster is deleted, all of its objects are deleted.
+ */
+
+#####GDescription
+Delete monster "i" from the monster array.
+
+#####GParameters
+> "i" is the index for the monster list (m_list[]). Beware: there is
+ no range checking.
+
+----------------------------------------------------------------------
+
+#####R=== m_pop ===
+
+#####GDeclaration
+ extern s16b m_pop(void);
+
+#####GFile
+ monsters2.c
+
+#####GComment
+/*
+ * Acquires and returns the index of a "free" monster.
+ *
+ * This routine should almost never fail, but it *can* happen.
+ */
+
+#####GDescription
+Get an empty slot in the monster list (m_list[]). If there are no
+empty slots, a slot will be reclaimed from a "dead" monster. If all
+slots are full, 0 is returned, which means the function has failed
+("Too many monsters!").
+
+----------------------------------------------------------------------
+
+#####R=== get_mon_num_prep ===
+
+#####GDeclaration
+ extern errr get_mon_num_prep(void);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Apply a "monster restriction function" to the "monster allocation table"
+ */
+
+#####GDescription
+There are no parameters, but there are some other variables which will
+need to be set. They are get_mon_num_hook and get_mon_num2_hook. They
+are pointers to functions.
+
+For example, get_mon_num_hook = monster_volcano means when
+get_mon_num_hook is called (*get_mon_num_hook)(index), the actual
+function called is monster_volcano(index). This particular function
+returns TRUE if the monster indicated by "index" has the
+RF8_WILD_VOLCANO flag set.
+
+It is a good idea to store the old value of get_mon_num_hook before
+setting a new one, and restoring it when your function is finished.
+
+Following is a list of functions which can be assigned to
+get_mon_num_hook:
+
+create_molds_hook
+create_townpeople_hook
+mon_hook_bounty
+monster_dungeon
+monster_grass
+monster_mountain
+monster_ocean
+monster_quest
+monster_shore
+monster_town
+monster_volcano
+monster_waste
+monster_wood
+mutate_monster_okay
+place_monster_okay
+summon_specific_okay
+vault_aux_animal
+vault_aux_chapel
+vault_aux_clone
+vault_aux_demon
+vault_aux_dragon
+vault_aux_giant
+vault_aux_jelly
+vault_aux_kennel
+vault_aux_orc
+vault_aux_symbol
+vault_aux_treasure
+vault_aux_troll
+vault_aux_undead
+
+Or you can write your own. The function must take an integer (index)
+as a parameter and return boolean (TRUE if the monster is selected,
+or FALSE if it is not).
+
+----------------------------------------------------------------------
+
+#####R=== get_mon_num ===
+
+#####GDeclaration
+ extern s16b get_mon_num(int level);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Choose a monster race that seems "appropriate" to the given level
+ *
+ * This function uses the "prob2" field of the "monster allocation table",
+ * and various local information, to calculate the "prob3" field of the
+ * same table, which is then used to choose an "appropriate" monster, in
+ * a relatively efficient manner.
+ *
+ * Note that "town" monsters will *only* be created in the town, and
+ * "normal" monsters will *never* be created in the town, unless the
+ * "level" is "modified", for example, by polymorph or summoning.
+ *
+ * There is a small chance (1/50) of "boosting" the given depth by
+ * a small amount (up to four levels), except in the town.
+ *
+ * It is (slightly) more likely to acquire a monster of the given level
+ * than one of a lower level. This is done by choosing several monsters
+ * appropriate to the given level and keeping the "hardest" one.
+ *
+ * Note that if no monsters are "appropriate", then this function will
+ * fail, and return zero, but this should *almost* never happen.
+ */
+
+Description:
+For the given level "level", return the index of an appropriate
+monster race.
+
+#####GParameters
+> "level" is a dungeon level
+
+----------------------------------------------------------------------
+
+#####R=== monster_desc ===
+
+#####GDeclaration
+ extern void monster_desc(char *desc, monster_type *m_ptr,
+ int mode);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Build a string describing a monster in some way.
+ *
+ * We can correctly describe monsters based on their visibility.
+ * We can force all monsters to be treated as visible or invisible.
+ * We can build nominatives, objectives, possessives, or reflexives.
+ * We can selectively pronominalize hidden, visible, or all monsters.
+ * We can use definite or indefinite descriptions for hidden monsters.
+ * We can use definite or indefinite descriptions for visible monsters.
+ *
+ * Pronominalization involves the gender whenever possible and allowed,
+ * so that by cleverly requesting pronominalization / visibility, you
+ * can get messages like "You hit someone. She screams in agony!".
+ *
+ * Reflexives are acquired by requesting Objective plus Possessive.
+ *
+ * If no m_ptr arg is given (?), the monster is assumed to be hidden,
+ * unless the "Assume Visible" mode is requested.
+ *
+ * If no r_ptr arg is given, it is extracted from m_ptr and r_info
+ * If neither m_ptr nor r_ptr is given, the monster is assumed to
+ * be neuter, singular, and hidden (unless "Assume Visible" is set),
+ * in which case you may be in trouble... :-)
+ *
+ * I am assuming that no monster name is more than 70 characters long,
+ * so that "char desc[80];" is sufficiently large for any result.
+ *
+ * Mode Flags:
+ * 0x01 --> Objective (or Reflexive)
+ * 0x02 --> Possessive (or Reflexive)
+ * 0x04 --> Use indefinites for hidden monsters ("something")
+ * 0x08 --> Use indefinites for visible monsters ("a kobold")
+ * 0x10 --> Pronominalize hidden monsters
+ * 0x20 --> Pronominalize visible monsters
+ * 0x40 --> Assume the monster is hidden
+ * 0x80 --> Assume the monster is visible
+ *
+ * Useful Modes:
+ * 0x00 --> Full nominative name ("the kobold") or "it"
+ * 0x04 --> Full nominative name ("the kobold") or "something"
+ * 0x80 --> Genocide resistance name ("the kobold")
+ * 0x88 --> Killing name ("a kobold")
+ * 0x22 --> Possessive, genderized if visible ("his") or "its"
+ * 0x23 --> Reflexive, genderized if visible ("himself") or "itself"
+ */
+
+#####GDescription
+Return a monster description "desc" for monster "monster_type" using
+flag "mode". The modes are described above.
+
+#####GParameters
+> "desc" is the returned description.
+> "monster type" is the monster (monster pointer).
+> "mode" is one of the modes described in the comments.
+
+----------------------------------------------------------------------
+
+#####R=== monster_race_desc ===
+
+#####GDeclaration
+ extern void monster_race_desc(char *desc, int r_idx,
+ int ego);
+
+#####GFile
+ monster2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the monster description "desc" for monster with monster index
+"r_idx" and monster ego "ego". The monster description is made up of
+the ego name (if any) and monster name, or the unique name.
+
+#####GParameters
+> "desc" is the returned description.
+> "r_idx" is an entry from the "r_info.txt" file. Beware: there is no
+ range checking.
+> "ego" is an entry from the "re_info.txt". Beware: there is no range
+ checking.
+
+----------------------------------------------------------------------
+
+#####R=== place_monster_aux ===
+
+#####GDeclaration
+ extern bool place_monster_aux(int y, int x, int r_idx,
+ bool slp, bool grp, int status);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Attempt to place a monster of the given race at the given location
+ *
+ * Note that certain monsters are now marked as requiring "friends".
+ * These monsters, if successfully placed, and if the "grp" parameter
+ * is TRUE, will be surrounded by a "group" of identical monsters.
+ *
+ * Note that certain monsters are now marked as requiring an "escort",
+ * which is a collection of monsters with similar "race" but lower
+ * level.
+ *
+ * Some monsters induce a fake "group" flag on their escorts.
+ *
+ * Note the "bizarre" use of non-recursion to prevent annoying output
+ * when running a code profiler.
+ *
+ * Note the use of the new "monster allocation table" code to restrict
+ * the "get_mon_num()" function to "legal" escort types.
+ */
+
+#####GDescription
+Attempt to place a monster at grid "y", "x". The monster has monster
+index "m_idx". The monster may be asleep ("slp"). The monster may be
+surrounded by a group of identical monsters ("grp"). The monster has
+a status of "status" (see below). The function returns TRUE if the
+monster is placed successfully, otherwise FALSE.
+
+#####GParameters
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "r_idx" is an entry from the "r_info.txt" file. Beware: there is no
+ range checking.
+> "slp" is TRUE if the monster is asleep, otherwise FALSE.
+> "grp" is TRUE if the monster is surrounded by a group, otherwise
+ FALSE.
+> "status" is the status of the monster
+ *****fields.txt*0[status]
+
+----------------------------------------------------------------------
+
+#####R=== place_monster ===
+
+#####GDeclaration
+ extern bool place_monster(int y, int x, bool slp,
+ bool grp);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Hack -- attempt to place a monster at the given location
+ *
+ * Attempt to find a monster appropriate to the "monster_level"
+ */
+
+#####GDescription
+Attempt to place a monster at grid "y", "x". The monster may be asleep
+("slp"). The monster may be surrounded by a group of identical
+monsters ("grp"). The monster is of the appropriate monster level. The
+function returns TRUE if the monster is placed successfully, otherwise
+FALSE.
+
+#####GParameters
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "slp" is TRUE if the monster is asleep, otherwise FALSE.
+> "grp" is TRUE if the monster is surrounded by a group, otherwise
+ FALSE.
+
+----------------------------------------------------------------------
+
+#####R=== place_monster_one ===
+
+#####GDeclaration
+ extern s16b place_monster_one(int y, int x, int r_idx,
+ int ego, bool slp, int status);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Attempt to place a monster of the given race at the given location.
+ *
+ * To give the player a sporting chance, any monster that appears in
+ * line-of-sight and is extremely dangerous can be marked as
+ * "FORCE_SLEEP", which will cause them to be placed with low energy,
+ * which often (but not always) lets the player move before they do.
+ *
+ * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters.
+ *
+ * XXX XXX XXX Use special "here" and "dead" flags for unique monsters,
+ * remove old "cur_num" and "max_num" fields.
+ *
+ * XXX XXX XXX Actually, do something similar for artifacts, to simplify
+ * the "preserve" mode, and to make the "what artifacts" flag more useful.
+ *
+ * This is the only function which may place a monster in the dungeon,
+ * except for the savefile loading code.
+ */
+
+#####GDescription
+Attempt to place a monster at grid "y", "x". The monster has monster
+index "m_idx". The monster may be asleep ("slp"). The monster may have
+an ego type ("ego"). The monster has a status of "status" (see below).
+The function returns TRUE if the monster is placed successfully,
+otherwise FALSE.
+
+#####GParameters
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "r_idx" is an entry from the "r_info.txt" file. Beware: there is no
+ range checking.
+> "slp" is TRUE if the monster is asleep, otherwise FALSE.
+> "ego" is an entry from the "re_info.txt". Beware: there is no range
+ checking.
+> "status" is the status of the monster
+ *****fields.txt*0[status]
+
+----------------------------------------------------------------------
+
+#####R=== is_friend ===
+
+#####GDeclaration
+ extern int is_friend(monster_type *m_ptr);
+
+#####GFile
+ monster3.c
+
+#####GComment
+/*
+ * Is the monster in friendly state(pet, friend, ..)
+ * -1 = enemy, 0 = neutral, 1 = friend
+ */
+
+#####GDescription
+Return a value to indicate the status of monster "m_ptr".
+ *****fields.txt*0[status]
+
+#####GParameters
+> "m_ptr" is a pointer to a monster.
+
+----------------------------------------------------------------------
+
+#####R=== is_enemy ===
+
+#####GDeclaration
+ extern bool is_enemy(monster_type *m_ptr,
+ monster_type *t_ptr);
+
+#####GFile
+ monster3.c
+
+#####GComment
+/* Should they attack each others */
+
+#####GDescription
+Return TRUE if monster "m_ptr" should attack monster "t_ptr". If
+"m_ptr" is stupid and "r_ptr" is a different type of monster then the
+function will return TRUE. If "m_ptr" is not neutral and "r_ptr" is a
+breeder, and "r_ptr" is a different type of monster then the function
+will return TRUE (and vice versa). If both monsters are not neutral
+and one is friendly and the other isn't then the function will return
+TRUE. Otherwise the function returns FALSE.
+
+#####GParameters
+> "m_ptr" is a pointer to a monster.
+> "t_ptr" is a pointer to a monster (target).
+
+----------------------------------------------------------------------
+
+#####R=== change_side ===
+
+#####GDeclaration
+ extern bool change_side(monster_type *m_ptr);
+
+#####GFile
+ monster3.c
+
+#####GComment
+(none)
+
+#####GDescription
+Change the status of monster "m_ptr" from friendly to unfriendly and
+vice versa. Friends and pets become enemies. Neutral Ms become
+neutral Ps and vice versa. Companions are unaffected. The
+function returns TRUE if the status changed, otherwise FALSE.
+
+#####GParameters
+> "m_ptr" is a pointer to a monster.
+
+----------------------------------------------------------------------
+
+#####R=== find_position ===
+
+#####GDeclaration
+ extern void find_position(int y, int x, int *yy = 0,
+ int *xx = 0);
+
+#####GFile
+ lua_bind.c
+
+#####GComment
+(none)
+
+#####GDescription
+Find a new grid "yy", "xx" within 6 grids of target grid "y", "x".
+The new grid must be within line-of-sight of the target grid. A
+maximum of 5000 attempts is made.
+
+#####GParameters
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "yy" is the y co-ordinate of the new grid.
+> "xx" is the x co-ordinate of the new grid.
+
+----------------------------------------------------------------------
+
+#####R=== can_create_companion ===
+
+#####GDeclaration
+ extern bool can_create_companion();
+
+#####GFile
+ monster3.c
+
+#####GComment
+/* Returns if a new companion is allowed */
+
+#####GDescription
+Return TRUE if a companion can be created, otherwise FALSE.
+
+----------------------------------------------------------------------
+
+Back to the *****lua.hlp*0[lua help index] .
+
+
+ [[[[[gThis file by Chris Hadgis]
diff --git a/lib/help/lua_play.txt b/lib/help/lua_play.txt
new file mode 100644
index 00000000..6ab64ddb
--- /dev/null
+++ b/lib/help/lua_play.txt
@@ -0,0 +1,1225 @@
+|||||oy
+
+#####R /----------------------------------------\
+#####R < player.pkg functions helper file >
+#####R \----------------------------------------/
+
+----------------------------------------------------------------------
+
+#####RFunction: set_parasite
+
+#####GDeclaration: bool set_parasite(int v, int r);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->parasite" and "p_ptr->parasite_r_idx"
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until parasite with monster index "r" is created. The
+player gets the message "You feel something growing in you" if "v"
+is > 0. Otherwise the player gets the message "Your body convulse
+and spawn <monster name>" if the monster is created (80% chance) or
+"The hideous thing growing in you seems to die" if the monster dies.
+
+#####GParameters:
+>v is the time until the parasite gestates (must be between 0 and
+ 10000).
+>r is the monster index of parasite to be created.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_disrupt_shield
+
+#####GDeclaration: bool set_disrupt_shield(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->disrupt_shield"
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until shield of invulnerability expires. The player gets
+the message "You feel invulnerable" if "v" is > 0. Otherwise the
+player gets the message "You are more vulnerable".
+
+#####GParameters:
+>v is the time until the shield expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_prob_travel
+
+#####GDeclaration: bool set_prob_travel(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->prob_travel"
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until random teleportation expires. The player gets
+the message "You feel instable" if "v" is > 0. Otherwise the
+player gets the message "You are more stable".
+
+#####GParameters:
+>v is the time until random teleportation expires (must be between 0
+ and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_deadly
+
+#####GDeclaration: bool set_tim_deadly(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_deadly"
+*/
+
+#####GDescription:
+Set time "v" until deadly accuracy expires. The player gets the
+message "You feel extremely accurate" if "v" is > 0. Otherwise the
+player gets the message "You are suddenly much less accurate".
+
+#####GParameters:
+>v is the time until deadly accuracy expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_res_time
+
+#####GDeclaration: bool set_tim_res_time(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_res_time"
+*/
+
+#####GDescription:
+Set time "v" until space-time distortions expire. The player gets the
+message "You are now protected against the space-time distortions" if
+"v" is > 0. Otherwise the player gets the message "You are no longer
+protected against the space-time distortions".
+
+#####GParameters:
+>v is the time until space-time distortions expire (must be between
+ 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_reflect
+
+#####GDeclaration: bool set_tim_reflect(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_reflect"
+*/
+
+#####GDescription:
+Set time "v" until reflection expire. The player gets the message
+"You start reflecting the world around you" if "v" is > 0. Otherwise
+the player gets the message "You stop reflecting".
+
+#####GParameters:
+>v is the time until reflection expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_meditation
+
+#####GDeclaration: bool set_meditation(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->meditation"
+*/
+
+#####GDescription:
+Set time "v" until meditation expire. The player gets the message
+"You start meditating on yourself" if "v" is > 0. Otherwise the
+player gets the message "You stop your self meditation".
+
+#####GParameters:
+>v is the time until meditation expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_strike
+
+#####GDeclaration: bool set_strike(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->strike"
+*/
+
+#####GDescription:
+Set time "v" until accurate strikes expire. The player gets the
+message "You feel very accurate" if "v" is > 0. Otherwise the player
+gets the message "You are no longer very accurate".
+
+#####GParameters:
+>v is the time until accurate strikes expire (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_walk_water
+
+#####GDeclaration: bool set_walk_water(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->walk_water", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until walking on water expires. The player gets the
+message "You feel strangely insubmersible" if "v" is > 0. Otherwise
+the player gets the message "You are no longer insubmersible".
+
+#####GParameters:
+>v is the time until walking on water expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_ffall
+
+#####GDeclaration: bool set_tim_ffall(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_ffall"
+*/
+
+#####GDescription:
+Set time "v" until feather-fall expires. The player gets the message
+"You feel very light" if "v" is > 0. Otherwise the player gets the
+message "You are suddenly heavier".
+
+#####GParameters:
+>v is the time until feather-fall expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_fire_aura
+
+#####GDeclaration: bool set_tim_fire_aura(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_fire_aura"
+*/
+
+#####GDescription:
+Set time "v" until fiery aura expires. The player gets the message
+"You are enveloped in flames" if "v" is > 0. Otherwise the player
+gets the message "You are no longer enveloped in flames".
+
+#####GParameters:
+>v is the time until fiery aura expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_holy
+
+#####GDeclaration: bool set_holy(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->holy", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until holiness expires. The player gets the message
+"You feel a holy aura around you" if "v" is > 0. Otherwise the
+player gets the message "The holy aura vanishes".
+
+#####GParameters:
+>v is the time until holiness expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_grace
+
+#####GDeclaration: void set_grace(s32b v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->grace", notice observable changes
+*/
+
+#####GDescription:
+Set grace to value "v". Don't allow grace to fall below -30000 or
+rise above 30000.
+
+#####GParameters:
+>v is the value of grace.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_mimic
+
+#####GDeclaration: bool set_mimic(int v, int p);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_mimic", and "p_ptr->mimic_form",
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until morph into monster with monster index "p" expires.
+The player gets the message "You feel your body change" if "v" is > 0.
+Otherwise the player gets the message "You are no longer transformed".
+
+#####GParameters:
+>v is the time until transformation expires (must be between 0 and
+ 10000).
+>p is the monster index of the monster the player wants to mimic.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_no_breeders
+
+#####GDeclaration: bool set_no_breeders(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "no_breeds"
+*/
+
+#####GDescription:
+Set time "v" until breeders can breed again. The player gets the
+message "You feel an anti-sexual aura" if "v" is > 0. Otherwise the
+player gets the message "You no longer feel an anti-sexual aura".
+Okay...
+
+#####GParameters:
+>v is the time until breeders can breed again (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_invis
+
+#####GDeclaration: bool set_invis(int v,int p);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_invis", and "p_ptr->tim_inv_pow",
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until invisibility expires. The player gets the message
+"You feel your body fade away" if "v" is > 0. Otherwise the player
+gets the message "You are no longer invisible".
+
+#####GParameters:
+>v is the time until invisibility expires (must be between 0 and
+ 10000).
+>p is the power of timed invisibility.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_lite
+
+#####GDeclaration: bool set_lite(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_lite", notice observable changes
+*
+* Note the use of "PU_VIEW", which is needed to
+* memorise any terrain features which suddenly become "visible".
+* Note that blindness is currently the only thing which can affect
+* "player_can_see_bold()".
+*/
+
+#####GDescription:
+Set time "v" until brightness expires. The player gets the message
+"You suddenly seem brighter" if "v" is > 0. Otherwise the player
+gets the message "You are no longer bright".
+
+#####GParameters:
+>v is the time until brightness expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_blind
+
+#####GDeclaration: bool set_blind(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->blind", notice observable changes
+*
+* Note the use of "PU_UN_VIEW", which is needed to memorise any terrain
+* features which suddenly become "visible".
+* Note that blindness is currently the only thing which can affect
+* "player_can_see_bold()".
+*/
+
+#####GDescription:
+Set time "v" until blindness expires. The player gets the message "You
+are blind" if "v" is > 0. Otherwise the player gets the message "You
+can see again".
+
+#####GParameters:
+>v is the time until blindness expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_confused
+
+#####GDeclaration: bool set_confused(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->confused", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until confusion expires. The player gets the message "You
+are confused" if "v" is > 0. Otherwise the player gets the message
+"You feel less confused now".
+
+#####GParameters:
+>v is the time until confusion expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_poisoned
+
+#####GDeclaration: bool set_poisoned(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->poisoned", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until poison expires. The player gets the message "You
+are poisoned" if "v" is > 0. Otherwise the player gets the message
+"You are no longer poisoned".
+
+#####GParameters:
+>v is the time until poison expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_afraid
+
+#####GDeclaration: bool set_afraid(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->afraid", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until fear expires. The player gets the message "You are
+terrified" if "v" is > 0. Otherwise the player gets the message "You
+feel bolder now".
+
+#####GParameters:
+>v is the time until fear expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_paralyzed
+
+#####GDeclaration: bool set_paralyzed(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->paralyzed", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until paralysis expires. The player gets the message "You
+are paralyzed" if "v" is > 0. Otherwise the player gets the message
+"You can move again".
+
+#####GParameters:
+>v is the time until paralysis expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_image
+
+#####GDeclaration: bool set_image(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->image", notice observable changes
+*
+* Note that we must redraw the map when hallucination changes.
+*/
+
+#####GDescription:
+Set time "v" until hallucination expires. The player gets the message
+"Oh, wow! Everything looks so cosmic now" if "v" is > 0. Otherwise
+the player gets the message "You can see clearly again".
+
+#####GParameters:
+>v is the time until hallucination expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_fast
+
+#####GDeclaration: bool set_fast(int v, int p);
+
+#####GFile: xtra2.c
+
+#####GComment:
+(none)
+
+#####GDescription:
+Set time "v" until speed of speed factor "p" expires. The player gets
+the message "You feel yourself moving faster" if "v" is > 0. Otherwise
+the player gets the message "You feel yourself slow down".
+
+#####GParameters:
+>v is the time until speed expires (must be between 0 and 10000).
+>p is the speed factor.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_light_speed
+
+#####GDeclaration: bool set_light_speed(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->lightspeed", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until light-speed expires. The player gets the message
+"You feel as if time has stopped" if "v" is > 0. Otherwise the player
+gets the message "You feel time returning to its normal rate".
+
+#####GParameters:
+>v is the time until light-speed expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_slow
+
+#####GDeclaration: bool set_slow(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->slow", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until slowness expires. The player gets the message "You
+feel yourself moving slower" if "v" is > 0. Otherwise the player gets
+the message "You feel yourself speed up".
+
+#####GParameters:
+>v is the time until slowness expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_shield
+
+#####GDeclaration: bool set_shield(int v, int p, s16b o, s16b d1, s16b d2);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->shield", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until stone-shield expires. The player gets the message
+"Your skin turns to stone" if "v" is > 0. Otherwise the player gets
+the message "Your skin returns to normal". Stone-shield has spell
+power "p", spell option "o", and power options "d1" and "d2".
+
+#####GParameters:
+>v is the time until stone-shield expires (must be between 0 and
+ 10000).
+>p is the power of the stone-shield spell.
+>o is the option of the stone-shield spell.
+>d1 is the power for option 1 of the stone-shield spell.
+>d2 is the power for option 2 of the stone-shield spell.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_blessed
+
+#####GDeclaration: bool set_blessed(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->blessed", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until blessing expires. The player gets the message "You
+feel righteous" if "v" is > 0. Otherwise the player gets the message
+"The prayer has expired".
+
+#####GParameters:
+>v is the time until blessing expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_hero
+
+#####GDeclaration: bool set_hero(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->hero", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until heroism expires. The player gets the message "You
+feel like a hero" if "v" is > 0. Otherwise the player gets the
+message "The heroism wears off".
+
+#####GParameters:
+>v is the time until heroism expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_shero
+
+#####GDeclaration: bool set_shero(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->shero", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until berserk expires. The player gets the message "You
+feel like a killing machine" if "v" is > 0. Otherwise the player gets
+the message "You feel less Berserk".
+
+#####GParameters:
+>v is the time until berserk expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_protevil
+
+#####GDeclaration: bool set_protevil(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->protevil", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until protection from evil expires. The player gets the
+message "You feel safe from evil" if "v" is > 0. Otherwise the player
+gets the message "You no longer feel safe from evil".
+
+#####GParameters:
+>v is the time until protection from evil expires (must be between 0
+ and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_protgood
+
+#####GDeclaration: bool set_protgood(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->protgood", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until protection from good expires. The player gets the
+message "You feel safe from good" if "v" is > 0. Otherwise the player
+gets the message "You no longer feel safe from good".
+
+#####GParameters:
+>v is the time until protection from evil expires (must be between 0
+ and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_protundead
+
+#####GDeclaration: bool set_protundead(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->protundead", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until protection from undead expires. The player gets the
+message "You feel safe from undead" if "v" is > 0. Otherwise the
+player gets the message "You no longer feel safe from undead".
+
+#####GParameters:
+>v is the time until protection from undead expires (must be between
+ 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_invuln
+
+#####GDeclaration: bool set_invuln(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->invuln", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until invulnerability expires. The player gets the
+message "Invulnerability" if "v" is > 0. Otherwise the player gets
+the message "The invulnerability wears off".
+
+#####GParameters:
+>v is the time until invulnerability expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_invis
+
+#####GDeclaration: bool set_tim_invis(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_invis", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until see invisible expires. The player gets the message
+"Your eyes feel very sensitive" if "v" is > 0. Otherwise the player
+gets the message "Your eyes feel less sensitive".
+
+#####GParameters:
+>v is the time until see invisible expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_infra
+
+#####GDeclaration: bool set_tim_infra(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_infra", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until infravision expires. The player gets the message
+"Your eyes begin to tingle" if "v" is > 0. Otherwise the player gets
+the message "Your eyes stop tingling".
+
+#####GParameters:
+>v is the time until infravision expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_mental_barrier
+
+#####GDeclaration: bool set_mental_barrier(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_mental_barrier", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until mental barrier expires. The player gets the message
+"Your mind grows stronger" if "v" is > 0. Otherwise the player gets
+the message "Your mind is no longer especially strong".
+
+#####GParameters:
+>v is the time until mental barrier expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_acid
+
+#####GDeclaration: bool set_oppose_acid(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+
+#####GDescription:
+Set time "v" until feather-fall expires. The player gets the message
+"You feel very light" if "v" is > 0. Otherwise the player gets the
+message "You are suddenly heavier".
+
+#####GParameters:
+>v is the time until feather-fall expires (must be between 0 and
+ 10000).
+>v is the time until feather-fall expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_elec
+
+#####GDeclaration: bool set_oppose_elec(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_elec", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until electricity resistance expires. The player gets
+the message "You feel resistant to electricity" if "v" is > 0.
+Otherwise the player gets the message "You feel less resistant to
+electricity".
+
+#####GParameters:
+>v is the time until electricity resistance expires (must be between
+ 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_fire
+
+#####GDeclaration: bool set_oppose_fire(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_fire", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until fire resistance expires. The player gets the
+message "You feel resistant to fire" if "v" is > 0. Otherwise the
+player gets the message "You feel less resistant to fire".
+
+#####GParameters:
+>v is the time until fire resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_cold
+
+#####GDeclaration: bool set_oppose_cold(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_cold", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until cold resistance expires. The player gets the
+message "You feel resistant to cold" if "v" is > 0. Otherwise the
+player gets the message "You feel less resistant to cold".
+
+#####GParameters:
+>v is the time until cold resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_pois
+
+#####GDeclaration: bool set_oppose_pois(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_pois", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until poison resistance expires. The player gets the
+message "You feel resistant to poison" if "v" is > 0. Otherwise the
+player gets the message "You feel less resistant to poison".
+
+#####GParameters:
+>v is the time until poison resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_ld
+
+#####GDeclaration: bool set_oppose_ld(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_ld"
+*/
+
+#####GDescription:
+Set time "v" until light and dark resistance expires. The player gets
+the message "You feel protected against the light's fluctuation" if
+"v" is > 0. Otherwise the player gets the message "You are no longer
+protected against the light's fluctuation".
+
+#####GParameters:
+>v is the time until light and dark resistance expires (must be
+ between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_cc
+
+#####GDeclaration: bool set_oppose_cc(int v);
+
+#####GFile: xtra2.c
+/*
+* Set "p_ptr->oppose_cc"
+*/
+
+#####GComment:
+
+#####GDescription:
+Set time "v" until chaos resistance expires. The player gets the
+message "You feel protected against raw chaos" if "v" is > 0.
+Otherwise the player gets the message "You are no longer protected
+against chaos".
+
+#####GParameters:
+>v is the time until chaos resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_ss
+
+#####GDeclaration: bool set_oppose_ss(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_ss"
+*/
+
+#####GDescription:
+Set time "v" until sound and shard resistance expires. The player gets
+the message "You feel protected against the ravages of sound and
+shards" if "v" is > 0. Otherwise the player gets the message "You are
+no longer protected against the ravages of sound and shards".
+
+#####GParameters:
+>v is the time until sound and shard resistance expires (must be
+ between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_nex
+
+#####GDeclaration: bool set_oppose_nex(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_nex"
+*/
+
+#####GDescription:
+Set time "v" until nexus resistance expires. The player gets the
+message "You feel protected against the strange forces of nexus" if
+"v" is > 0. Otherwise the player gets the message "You are no longer
+protected against the strange forces of nexus".
+
+#####GParameters:
+>v is the time until nexus resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_stun
+
+#####GDeclaration: bool set_stun(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->stun", notice observable changes
+*
+* Note the special code to only notice "range" changes.
+*/
+
+#####GDescription:
+Set stun level "v". If the player race can't be stunned then the level
+is forced to 0. A value > 100 means the player is knocked out. A value
+>50 is a heavy stun. A value > 0 is a stun. If the stun level has
+increased, a message is printed. There is a small chance of stun level
+in 1000, or a 1 in 16 chance of a vicious blow which decreases
+intelligence and/or wisdom for a while.
+
+#####GParameters:
+>v is the stun level.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_cut
+
+#####GDeclaration: bool set_cut(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->cut", notice observable changes
+*
+* Note the special code to only notice "range" changes.
+*/
+
+#####GDescription:
+Set cut level "v". If the player race can't be cut then the time is
+forced to 0. A value > 1000 is a mortal wound. A value > 200 is a deep
+gash. A value > 100 is a severe cut. A value > 50 is a nasty cut. A
+value > 25 is a bad cut. A value > 10 is a light cut. A value > 0 is a
+graze. If the cut level has increased, a message is printed. There is
+a small chance of stun level in 1000, or a 1 in 16 chance of scarring
+which decreases charisma for a while.
+
+#####GParameters:
+>v is the cut level.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_food
+
+#####GDeclaration: bool set_food(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->food", notice observable changes
+*
+* The "p_ptr->food" variable can get as large as 20000, allowing the
+* addition of the most "filling" item, Elvish Waybread, which adds
+* 7500 food units, without overflowing the 32767 maximum limit.
+*
+* Perhaps we should disturb the player with various messages,
+* especially messages about hunger status changes. XXX XXX XXX
+*
+* Digestion of food is handled in "dungeon.c", in which, normally,
+* the player digests about 20 food units per 100 game turns, more
+* when "fast", more when "regenerating", less with "slow digestion",
+* but when the player is "gorged", he digests 100 food units per 10
+* game turns, or a full 1000 food units per 100 game turns.
+*
+* Note that the player's speed is reduced by 10 units while gorged,
+* so if the player eats a single food ration (5000 food units) when
+* full (15000 food units), he will be gorged for (5000/100)*10 = 500
+* game turns, or 500/(100/5) = 25 player turns (if nothing else is
+* affecting the player speed).
+*/
+
+#####GDescription:
+Set hunger level "v". A value < 500 is fainting. A value < 1000 is
+weak. A value < 2000 is weak. A value < 10000 is full. A value
+< 15000 is bloated. A value < 20000 is gorged. If one of these
+levels is crossed a message is printed.
+
+#####GParameters:
+>v is the hunger level (must be between 0 and 20000).
+
+----------------------------------------------------------------------
+
+#####RFunction: check_experience
+
+#####GDeclaration: void check_experience(void);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Advance experience levels and print experience
+*/
+
+#####GDescription:
+Check if player experience level has changed. If a player has achieved
+a level for the first time, give reward or corruption (1 chance in 3)
+if they apply, and increase skill points.
+
+----------------------------------------------------------------------
+
+#####RFunction: check_experience_obj
+
+#####GDeclaration: void check_experience_obj(object_type *o_ptr);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Advance experience levels and print experience
+*/
+
+#####GDescription:
+Check if object "o_ptr" experience level has changed. If an object has
+achieved a level for the first time, apply gains.
+
+#####GParameters:
+>o_ptr is the pointer to the object gaining experience.
+
+----------------------------------------------------------------------
+
+#####RFunction: gain_exp
+
+#####GDeclaration: void gain_exp(s32b amount);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Gain experience (share it to objects if needed)
+*/
+
+#####GDescription:
+Gain "amount" of experience. Count the number of objects which will
+gain experience. The objects share equally 2/3 of "amount". Give
+corruption if it applies. Gain experience. If experience is less
+than maximum, then increase maximum experience by 20% of "amount".
+Check for level change and print experience (check_experience).
+
+#####GParameters:
+>amount is the amount of experience to share.
+
+----------------------------------------------------------------------
+
+#####RFunction: lose_exp
+
+#####GDeclaration: void lose_exp(s32b amount);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Lose experience
+*/
+
+#####GDescription:
+Decrease experience by "amount". Experience can not fall below zero.
+Check for level change and print experience (check_experience).
+
+#####GParameters:
+>amount is the amount of experience to lose.
+
+----------------------------------------------------------------------
+
+
+Back to the *****lua.hlp*0[lua help index] .
+
+
+ [[[[[gThis file by Chris Hadgis]
+
+
diff --git a/lib/help/lua_pow.txt b/lib/help/lua_pow.txt
new file mode 100644
index 00000000..c221a664
--- /dev/null
+++ b/lib/help/lua_pow.txt
@@ -0,0 +1,266 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Adding new racial powers >
+#####R \----------------------------------------/
+
+#####R=== Introduction ===
+
+You *must* download and install my lua example files from
+[[[[[Ghttp://www.moppy.co.uk/angband.htm]. And also you should read the
+*****lua_intr.txt*0[scripting introduction] file if you haven't already done
+so.
+
+The (commented) accompanying script file for this tutorial is
+lib\scpt\pheonix.lua. Open it in your text editor!
+
+#####R=== The Racial Power ===
+
+Let's start with something simple. Let's say you wanted your new race (let's
+call it "Pheonix") to be able to cast fire balls as their racial power.
+
+#####R=== Starting off ===
+
+If you have a look at pheonix.lua you'll note the first lines are comments.
+I'll talk a bit more about comments later, but it's worth pointing out that any
+lines of text preceded by a double hyphen ([[[[[B--]) will be ignored by the
+scripting engine, and are therefore comments.
+After the comments, the first 10 lines of code are as follows:
+
+#####BPHEONIX_POWER = add_power
+#####B{
+#####B ["name"] = "Fire Breath",
+#####B ["desc"] = "You are able to cast fireballs",
+#####B ["desc_get"] = "Your beak glows red",
+#####B ["desc_lose"] = "Your beak goes cold again",
+#####B ["level"] = 10,
+#####B ["cost"] = 11,
+#####B ["stat"] = A_INT,
+#####B ["fail"] = 14,
+
+So, [[[[[BPHEONIX_POWER = add_power] is registering our power. We're giving it
+a name (PHEONIX_POWER) and saying that it is defined by calling the special
+function [[[[[Badd_power]. This special function is only used to define lua-
+scripted
+powers, and has attributes which are identified by their inclusion in square
+brackets.
+Note the following:
+- Lua is case sensitive. The name of our power is a constant, will never change
+so that's been named with capitals. variables and functions are named all in
+lower case. Technically speaking, Lua does not support constants, but we can
+emulate them by variables in this way. They don't have to be capitalised, but
+if you capitalise all your constants, it makes things easier to read, and
+you'll be following normal programming protocol.
+- There are no spaces in the name of the power. Use an underscore for spaces
+if you need to improve legibility.
+
+[[[[[B"name" = "Fire Breath",] This is the name of the power as it is
+displayed in the
+U menu, and as you will define it in p_info.txt (more about that later).
+
+[[[[[B"desc" = "You are able to cast fireballs",] This is what would
+appear in the
+information display list if you drank a potion of self knowledge or
+similar.
+
+[[[[[B"desc_get" = "Your beak glows red",] This is the information displayed
+when you
+gain this power.
+
+[[[[[B"desc_lose" = "Your beak goes cold again",] This is the information
+displayed when
+you lose this power. Eg After a mutation/corruption.
+
+[[[[[B"level" = 10,] Character level which must be gained in order to use
+power,
+
+[[[[[B"cost" = 11,] Amount of mana to cast this power.
+
+[[[[[B"stat" = A_INT,] stat which will define whether it works or not,
+
+[[[[[B"fail" = 14,] how high that stat must be.
+
+So our Pheonix will be able to cast PHEONIX_POWER from clvl 10, at a cost of
+11 mana, providing that the player's intelligence is 14 and upwards.
+
+#####R=== The function ===
+
+The next section is a lot longer, so we'll look at it line by line. I'll
+strip the comments for the purpose of this helpfile.
+
+#####B["power"] = function()
+#####B local ret, dir, damage
+#####B ret, dir = get_aim_dir();
+#####B if (ret == FALSE) then
+#####B return
+#####B end
+#####B damage = player.lev*3
+#####B msg_print("You breathe fire.")
+#####B fire_ball(GF_FIRE, dir, damage, 3)
+#####Bend,
+
+The [[[[[B"power"] bit is what actually happens when the player accesses this
+power
+from their 'U' menu. Every function must start with the word [[[[[Bfunction].
+Normally, we'd also declare its name at this point, but as this is contained
+within the [[[[[Badd_power] function, we just use the word [[[[[Bfunction] The
+empty
+brackets after this denote that no arguments are passed to the function.
+Lets look at the next line.
+
+#####B local ret, dir, damage
+
+The [[[[[Blocal] bit is saying that we're going to declare some local
+variables. That
+is, that there will be three variables used in this function , that apply
+exclusively to this function, and to no others. Global variables are
+variables that apply to the whole script, in multiple functions. The three
+variables will be called [[[[[Bret] (return), [[[[[Bdir] (direction), and
+[[[[[Bdamage]. They will be used to determine the direction the ball
+will fire in, and how much damage it will do. We'll see them in use when we add
+the third line:
+
+#####B ret, dir = get_aim_dir();
+
+here we're saying that the variables will take their value from the result
+of a function. The program performs the function [[[[[Bget_aim_dir] which
+essentially asks the player to choose a direction or pick a target.
+[[[[[Bget_aim_dir]
+assigns the value [[[[[Bret] to either TRUE (if the player correctly selected a
+direction) or FALSE (if the player failed to do so (maybe they changed their
+mind, or hit the wrong key!)). The value [[[[[Bdir] is the direction which was
+selected (or the path to the target if a target was selected). OK so let's add
+the next line:
+
+#####B if (ret == FALSE) then return end
+
+This introduces another fundamental scripting concept - [[[[[Bif] statements.
+They work just as you would expect them too. You say "if a certain condition is
+met, then do the following things."
+So in this function we're saying, "if the value of [[[[[Bret] is FALSE then
+[[[[[Breturn]."
+As I mentioned above, [[[[[Bret] is false if the player aborted (either
+deliberately or accidentally) the spell casting whilst choosing a direction
+for the spell. The double equals sign are used to mean "is equal to" as a
+single equals sign is used for defining variables remember? A single equals
+sign is more of a "let x be equal to y" thing.
+[[[[[Breturn] means stop the current function. And [[[[[Bend] signifies the
+close of the [[[[[Bif]
+statement. Every [[[[[Bif] statement must begin with an [[[[[Bif] and finish
+with an [[[[[Bend].
+So, what our [[[[[Bif] statement is saying is; "if the player failed to specify
+a direction or target for the spell, stop the function here."
+If the player has correctly specified a direction/target, the function
+continues to the next line:
+
+#####B damage = player.lev*3
+
+Here we're saying that the variable [[[[[Bdamage] has a value equal to the
+players current character level, multiplied by 3.
+
+#####B msg_print("You breathe fire.")
+
+Fairly easy to see what this does - displays the message "You breathe fire."
+I could have put anything there obviously, like [[[[[Bmsg_print("You open]
+[[[[[Byour mouth and everyone falls over with the smell of hot curry")] or
+some other such rubbish. But note that the message is enclosed within double
+quotes. The quotes aren't displayed in the message on screen, but signify the
+start and end of the message.
+
+#####B fire_ball(GF_FIRE, dir, damage, 3)
+
+This is the line that casts the spell. it says execute the function
+[[[[[Bfire_ball]. Now, this doesn't mean a fireball, it means fire a ball.
+There's an important distinction there! All it knows it is doing is firing a
+ball, it doesn't know what kind of ball, or where, or how big, or how much
+damage.
+The [[[[[BGF_FIRE,] bit is what tell us it is a fire ball. If it was
+[[[[[BGF_COLD,]
+ we'd have a cold ball, or [[[[[BGF_CHAOS,] it would be a chaos ball and
+so on and so on. A full list of those types can be found in *****lua_gf.txt*0[lua_gf.txt].
+[[[[[B dir,] is the direction, from the [[[[[Bget_aim_dir()] bit.
+[[[[[B damage,] is the damage. As we've already said, this will be clvl*3.
+[[[[[B 3)] is the radius.
+and finally...
+
+#####B end,
+#####B}
+
+[[[[[Bend,] tells it the function has ended. Every function must finish with
+[[[[[Bend].
+You should have spotted that after the end of each attribute is a comma. Make
+sure you include this, and don't forget the braces at the very very end to
+close the [[[[[Badd_power] function.
+
+#####R=== Finishing the LUA file ===
+
+Save this as a text file 'pheonix.lua' Put it into the lib\scrpt directory
+of ToME, and open the init.lua file which you'll find in the same
+directory.
+
+Add the following line and resave the init.lua file.
+
+#####Btome_dofile("pheonix.lua")
+
+This ensures that ToME loads your file on start-up. Because you've installed
+the example scripts, this has all been done for you.
+
+#####R=== A quick word about comments ===
+
+One of the reasons Angband has so many variants is because the source code is
+clearly commented. Almost every line of code has an accompanying comment,
+explaining what that line does. It's good practice to add comments to any code
+or script you write. It's helpful to others who are learning, anyone who takes
+over your project, and also to yourself when you come back in a month's time
+and can't remember what you did! So comment your code clearly, and well!
+
+You can also add multi line comments which should be enclosed by [[[[[B--[[]
+and
+#####B]]
+
+#####R=== Tying it all together ===
+
+You'll now need to link this 'U' power to the pheonix race via the
+p_info.txt file. Simply add a line within the class definition file that has
+the format [[[[[BR:Z:<name>]the name of the power as it appears in the
+[[[[[B"name"]
+section we did right at the beginning, remember? Seeing as there is no pheonix
+race, I've gone ahead and made one up as a demonstration. If you've downloaded
+and installed the example files from [[[[[Ghttp://www.moppy.co.uk/angband.htm/]
+then
+you'll notice you already have the pheonix race available. Printed below is
+the p_info.txt entry for it.
+
+
+#####BR:N:23:Pheonix
+#####BR:D:Born from flame, these powerful bird like creatures gain fire related
+#####BR:D:abilities as they grow.
+#####BR:S:1:0:2:1:-3:2:-5
+#####BR:K:-8:15:20:-10:5:-1:-5:-5
+#####BR:P:8:130:5:210
+#####BR:M:255:70:2:1:20:5:2:1:18:3
+#####BR:E:1:1:1:2:1:1
+#####BR:C:Warrior | Mage | Priest | Rogue | Ranger | Paladin | Blade |
+#####BR:C:Warlock | Chaos-Warrior | Monk | Mindcrafter | High-Mage |
+#####BR:C:BeastMaster | Alchemist | Power-Mage | Runecrafter |
+#####BR:C:Sorceror | Archer | Illusionist | Druid | Necromancer | Black-Knight
+|
+#####BR:C:Daemonologist | Weaponmaster | Summoner |
+#####BR:Z:Fire Ball
+#####BR:R:1:0
+#####BR:F:RES_FIRE | FEATHER |
+
+Note the [[[[[BR:Z:] line.
+
+If all is well, you should be able to start ToME now and breathe fire! Once
+you get to lvl 10 anyhow. Don't forget, this is the kind of thing wizard mode
+was invented for! Ctrl-A and confirm at the prompt, and then 'e' will allow
+you to alter stats, including experience. Approx 1000 exp should do to get you
+to clvl 10.
+
+Ready for more? How about adding a new *****lua_skil.txt*0[skill] ?
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
+
+
+
+
diff --git a/lib/help/lua_ques.txt b/lib/help/lua_ques.txt
new file mode 100644
index 00000000..1d4b9c65
--- /dev/null
+++ b/lib/help/lua_ques.txt
@@ -0,0 +1,299 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Adding a new quest >
+#####R \----------------------------------------/
+
+#####R=== Introduction ===
+
+Adding a quest involves a bit more work, and there is, in some ways, rather
+more potential for things to go wrong! But it's a great way of showing just
+WHAT can be done with lua scripting. It proves just how much a lua patch can
+change the overall feel of the game. And it will give you a much better idea of
+how lua interfaces with the game source. You should have read the
+*****lua_intr.txt*0[scripting introduction], *****lua_pow.txt*0[racial power tutorial]
+and *****lua_skil.txt*0[adding new skills tutorial] before going much
+further. All of the above files contain some fairly fundamental information
+which you will find necessary for full understanding of this file.
+
+The script we're looking at is going to create a quest entrance in the middle
+of Bree. Entering the quest you see a little girl who has had her necklace
+stolen. Your job is to travel down a corridor, killing some monsters on the
+way, pick up the amulet and return it to the girl. Once done, she'll reveal the
+stairs back to Bree, and give you a (randomly generated) ring. If you feel the
+monsters are too hard, the only thing to do is talk to the little girl who will
+reveal the stairs again, failing the quest for you, and also block off the
+entrance to the amulet so that you can't cheat and make off with the amulet!
+
+#####R=== Getting started ===
+
+Open amulet.lua (you have downloaded the example scripts from
+[[[[[Ghttp://www.moppy.co.uk/angband.htm], haven't you?). The first thing you
+should see is that yet again we're calling a function that takes its arguments
+from a table, making it easy to read what's going on in the script.
+
+This time our function is add_quest and we have the following keys and values:
+
+#####B["global"] = "AMULET_QUEST",
+#####B["name"] = "Hannahs lost amulet",
+#####B["desc"] = {
+#####B "Retrieve an amulet for Hannah Cooke. It's guarded!"
+#####B },
+#####B["level"] = 5,
+#####B["hooks"] = {
+
+[[[[[B"global" = ] is a constant that we set when we refer to this quest in
+various places...
+[[[[[B"name" = ] Obviously a long name for the quest. This will appear in the
+quest screen (Ctrl-Q) and we may use in some map files too.
+[[[[[B"desc" = ] This is a long description for the quest. Again this is what
+will appear in the quest screen, and each line should be not more than 80
+characters.
+[[[[[B"level" = ] This is a rough indicator of how hard the quest is, and again,
+appears in the quest screen
+[[[[[B"hooks" = ] This is the real 'meat' of the quest. Like the [[[[[B"spell_list"] key
+in the [[[[[Badd_magic] function, this is another sub-table.
+
+To understand fully the structure of the "hooks" key it's worth taking a bit of
+a detour at this point and discussing how the scripting interface works in
+general.
+
+#####R=== How the scripts work (ish) ===
+
+Essentially there's a list of events that happen in the game. As each of these
+events happen they run a check to see if there's any functions that they need
+to run at that event. When we ran the add_mkey part of adding a new skill
+power, we essentially said "when the 'm' key is pressed in the game, perform
+the [[[[[Bexecute_magic(constructor_powers)] function". Likewise we did a similar
+thing with adding the racial power, only we hooked onto the pressing of the
+'U' key.
+
+All of this was partly hidden because of the way that the [[[[[Badd_magic] and
+[[[[[Badd_power] functions work. But here in the [[[[[Badd_quest] function it's a bit more
+specific. We are going to specify what events we're going to hook onto, and
+what functions we want to trigger at that event.
+
+A full list of hooks can be found in the source-file util.pkg.
+
+#####R=== The hooks ===
+
+#####B[HOOK_BIRTH_OBJECTS] = function()
+#####B quest(AMULET_QUEST).status = QUEST_STATUS_TAKEN
+#####Bend,
+
+So here we are with our first hook. We've declared that we're adding it to the
+birth of your character. That is, the function will be called when you create
+your character. And what we're doing here is automatically declaring the quest
+as being taken, like the Dol Guldur quest is. Each quest has 7 different
+statuses:
+
+[[[[[BQUEST_STATUS_IGNORED -1 ] This is unused, but the quest is
+ignored (will not be taken and has not been taken).
+[[[[[BQUEST_STATUS_UNTAKEN 0 ] The quest has not been accepted yet
+[[[[[BQUEST_STATUS_TAKEN 1 ] You have accepted the quest
+[[[[[BQUEST_STATUS_COMPLETED 2 ] You have completed the quest
+successfully but not been rewarded for it
+[[[[[BQUEST_STATUS_REWARDED 3 ] You've completed and rewarded the quest
+[[[[[BQUEST_STATUS_FAILED 4 ] You've failed the quest
+[[[[[BQUEST_STATUS_FINISHED 5 ] The quest is completely finished
+successfully.
+[[[[[BQUEST_STATUS_FAILED_DONE 6 ] The quest is completely finished
+unsuccessfully.
+
+You see that we've used the constant we defined in the "global" section is
+passed as an argument to [[[[[Bquest.status].
+
+Next hook then:
+
+#####B[HOOK_GEN_QUEST] = function()
+#####B if (player.inside_quest ~= AMULET_QUEST) then
+#####B return FALSE
+#####B else
+#####B load_map("amulet.map", 2, 2)
+#####B return TRUE
+#####B end
+#####Bend,
+
+Ok, we're hooking onto the generation of the quest here. This is specifically
+triggered in this instance by going down the quest entrance stairs in Bree.
+Once you've gone down the stairs, you are technically inside the quest, which
+means we can say if the person is not inside the amulet quest, then ignore this
+function, otherwise load the file 'amulet.map' at co-ordinates x=2 y=2. You'll
+find the amulet.map file in the edit directory, make sure you check it out. The
+syntax for map files is fairly simple, though I might get round to writing a
+tutorial on them some day! In the mean time holler for me at the usual email
+address if you're unsure.
+
+#####B[HOOK_FEELING] = function()
+#####B if (player.inside_quest ~= AMULET_QUEST) then
+#####B return FALSE
+#####B else
+#####B cmsg_print(TERM_L_BLUE, "Hannah speaks to you:")
+#####B cmsg_print(TERM_YELLOW, "'Some nasty monsters stole my
+#####B favourite necklace.'")
+#####B cmsg_print(TERM_YELLOW, "'It's hidden at the back of that
+#####B corridor! Please fetch it for me'")
+#####B return TRUE
+#####B end
+#####Bend,
+
+We're moving into some rather more obvious territory here, and getting into the
+meat of the quest. The [[[[[BHOOK_FEELING] is triggered at the point when the level
+feeling appears. It's important that this is run only if the player is inside
+the amulet quest, as otherwise it will trigger EVERY time a level feeling
+occurs, when you go down a level in the barrow-downs, whenever! Returning TRUE
+will replace the level feeling with what's above, returning FALSE will still
+perform the function but will amend the normal level feeling - so here if we'd
+returned false we'd still get our custom messages, but they'd follow with
+'looks like a typical quest level'. Of course returning false may cause you
+other problems (see end of this file!) depending on what else you have in your
+function.
+
+#####B[HOOK_GIVE] = function(m_idx, item)
+
+#####B m_ptr = monster(m_idx)
+#####B o_ptr = get_object(item)
+
+#####B if (m_ptr.r_idx == test_monster_name("Hannah Cooke, a little girl"))
+#####B and (o_ptr.tval == TV_AMULET) and (o_ptr.sval == 2) then
+
+#####B cmsg_print(TERM_YELLOW, "'Thank-you!'")
+
+#####B inven_item_increase(item, -1)
+#####B inven_item_optimize(item)
+
+#####B quest(AMULET_QUEST).status = QUEST_STATUS_COMPLETED
+
+#####B cave_set_feat(7, 6, 6)
+
+#####B cmsg_print(TERM_YELLOW, "'Here, take this pretty ring I found
+#####B as a token of gratitude!'")
+#####B random_type = randint(57)
+#####B reward = create_object(TV_RING, random_type)
+#####B drop_near(reward, -1, py, px)
+#####B quest(AMULET_QUEST).status = QUEST_STATUS_REWARDED
+#####B return TRUE
+#####B else
+#####B return FALSE
+#####B end
+#####Bend,
+
+This is a fairly long function, but don't be intimidated. It's not really
+difficult to understand. As you can see we're hooking into the giving of an
+object to a monster (the 'y' key). Because of this, the function takes two
+arguments - [[[[[Bm_idx] (the monster that you're giving to) and [[[[[Bitem] (the item that
+you're giving).
+
+We then make it possible to work with the monster and item variables by
+referencing them to two functions which identify them from the edit files:
+[[[[[Bmonster()] and [[[[[Bget_object()]. This enables us to now say, 'if the name of the
+monster is "Hannah Cooke, a little girl" and the type of item is an amulet and
+that amulet is an amulet of adornment, then carry out the following commands'.
+
+We then say call the function [[[[[Binven_item_increase()] which places an object in
+the inventory. It takes two arguments, the first being what object to put in
+the inventory and the second being how many of that type of objects to put in
+the inventory. You can see that by placing -1 as the second argument it fairly
+obviously subtracts that item from the inventory. The [[[[[Binven_item_optimize()]
+function checks that there are no empty inventory slots, and if there are,
+erases them.
+
+The quest is then completed, and the stairs are revealed using the
+[[[[[Bcave_set_feat()] function. This function takes three arguments, the first is the
+x co-ordinate of the cave square you wish to change (counted from top left) the
+second is the y co-ordinate, and the third is the index number of the feature
+you wish the square to become as defined in f_info.txt.
+
+We then set about rewarding the player. As you can see we call [[[[[Bcreate_object()]
+which takes two variables: the first is the type of object (these are all
+listed in object.pkg) and the second is the sub-type of that object. I searched
+k_info.txt to see how many different types of ring there were (57) and used a
+randomly selected number with a maximum value of 57 as that specific sub-type.
+
+We then drop the object (although it's been created, it has only been created
+in the game's memory, it's nowhere that the player can interact with it until
+we drop it). The [[[[[Bdrop_near()] function takes 3 variables, the first being the
+object that you wish to drop, the second being the chance that it disappears
+(like an arrow, or mimicked creature) on drop. If you set it to -1, it won't
+ever disappear. The last two are the co-ordinates at which the object will be
+dropped. py and px are the global variables defined by where the player is
+standing, so in this case it will drop under the player. You could do
+[[[[[Binven_item_increase(reward, 1)] if you wanted, but I wanted to show a variety of
+ways of handling objects.
+
+OK, let's take a look at the next hook:
+
+#####B[HOOK_CHAT] = function(m_idx)
+#####B m_ptr = monster(m_idx)
+#####B if (m_ptr.r_idx == test_monster_name("Hannah Cooke, a little girl")) then
+#####B if (quest(AMULET_QUEST).status == QUEST_STATUS_REWARDED) then
+#####B cmsg_print(TERM_YELLOW, "'Bye!'")
+#####B else
+#####B cmsg_print(TERM_YELLOW, "'Are the monsters too tough?
+#####B Do you want to leave?'")
+#####B if (get_check("Really leave and fail the quest?") ==
+#####B FALSE)
+#####B then
+#####B cmsg_print(TERM_YELLOW, "'Go and get my
+#####B amulet then!'")
+#####B else
+#####B cmsg_print(TERM_YELLOW, "'Awww. Never
+#####B mind. It was only a bit of rabbits foot'")
+#####B quest(AMULET_QUEST).status =
+#####B QUEST_STATUS_FAILED
+#####B cave_set_feat(7, 6, 6)
+#####B cave_set_feat(12, 5, 60)
+#####B end
+#####B end
+#####B return TRUE
+#####B end
+#####B return FALSE
+#####Bend,
+
+This only looks complicated because of the nested 'if' statements. It's easy to
+lose your way when doing this kind of thing, always make sure you close all the
+statements and put the returns in the right place. [[[[[BHOOK_CHAT] functions have one
+argument - the monster you are chatting to. As you can see, we perform a check
+to make sure it's the right monster and then away we go.... If the player wants
+to leave the quest without completion they talk to Hannah, who gives them a
+chance to change their mind! If the player asks to leave the entrance to the
+corridor is blocked off (the second cave_set_feat()) so that the user can't
+then go and get the amulet. Gumband or Zangband players may at this point think
+they've lost out on the rabbits foot of burglary! (they haven't though as it
+doesn't exist in ToME).
+
+#####B[HOOK_CHAR_DUMP] = function()
+#####B if (quest(AMULET_QUEST).status == QUEST_STATUS_FAILED) then
+#####B print_hook("\n You chickened out of rescuing a necklace and
+#####B made a little girl sad. ")
+#####B elseif (quest(AMULET_QUEST).status == QUEST_STATUS_COMPLETED) or
+#####B (quest(AMULET_QUEST).status == QUEST_STATUS_REWARDED) or
+#####B (quest(AMULET_QUEST).status == QUEST_STATUS_FINISHED) then
+#####B print_hook("\n You rescued little Hannah Cooke's necklace from
+#####B the nasty monsters ")
+#####B end
+#####B return FALSE
+#####Bend,
+
+This quite simply and obviously prints an appropriate line in the character
+dump based on the status of the quest. The [[[[[B\n] bit ensures the text goes on a
+new line, so make sure you include it! Also you should return FALSE as
+returning TRUE will stop executing all the other character dump lines (and you
+may get other quests not having their lines printed).
+
+=== A word about returning TRUE and FALSE ===
+
+As I mentioned above, you need to be careful what you return when dealing with
+HOOKS as you can mess up the game a bit. Bear in mind that if you add a
+function to [[[[[BHOOK_GEN_QUEST], every time a quest is generated, that function will
+run. If you return TRUE, then no further functions attached to that hook will
+run. If you return FALSE, it continues processing functions on that hook.
+
+That is pretty much it. Do take a look at the other included scripts that I
+haven't gone into any detail about in the files, as you'll pick up some useful
+techniques there too. Especially worthy of note is the hina.lua file which uses
+hooks outside of the quest structure and also global variables and variables in
+a table. If you have any questions, let me know at the email addy below.
+
+Back to the *****lua.hlp*0[lua help index] .
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
diff --git a/lib/help/lua_skil.txt b/lib/help/lua_skil.txt
new file mode 100644
index 00000000..87385e5d
--- /dev/null
+++ b/lib/help/lua_skil.txt
@@ -0,0 +1,342 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Adding new skill-based powers >
+#####R \----------------------------------------/
+
+#####R=== Introduction ===
+
+This is very much in the same vein as adding a racial/extra power, but has to
+be tied into skills, and we're defining more than one spell at once. You should
+have read the *****lua_intr.txt*0[scripting introduction] and
+*****lua_pow.txt*0[racial power tutorial] before going much further. Both of the above files
+contain some fairly fundamental information which you will find necessary for
+full understanding of this file.
+
+#####R=== Getting started ===
+
+Open construc.lua (you have downloaded the example scripts from
+[[[[[Ghttp://www.moppy.co.uk/angband.htm], haven't you?). The idea behind this
+script is that it adds a skill which affects you ability to build/knock down
+stuff. It treats the equivalent of stone-to-mud and trap-door destruction
+spells as if they were "building skills". It also adds quite a few high-level
+'spells' which do funky things like carving out corridors and chambers in a
+single turn, and building doors and stuff. Just think of it as if the person
+who has plenty of skills in this area would be a builder-type with lots of
+strength and constitution...
+
+In order to add these powers we're going to edit the s_info.txt file which
+lives in the edit folder, and add a new skill, underneath the 'misc' tree,
+called construction. The powers will then be accessed through the 'm' menu, in
+a similar way to mindcraft or alchemy skills or such. (That is, no books are
+needed to cast them, as we're treating them as a craft that has been learnt,
+rather than spells.) Our fist line of the script file reads:
+
+#####BSKILL_CONSTRUCT = 57
+
+This merely links the skill index that we'll be defining in s_info.txt to this
+file. We'll come back to this at the end of the tutorial.
+
+#####Bconstructor_powers = add_magic
+
+In a similar way to the [[[[[Badd_power] function we called when we added the
+Phoenix racial ability, this line calls a special function which we use to
+define new skills. It follows a very specific, but easy to understand form. It
+starts with a brace, which indicates the add_magic function will be storing
+these values in a table. Don't worry about this too much, but understand that a
+table starts and ends with braces [[[[[B{] and [[[[[B}] respectively. Each key
+(or field name) takes the format [[[[[B"key" = value,] (the comma is
+important!).
+
+#####B ["fail"] = function()
+#####B msg_print("You decide now is a good time for a cuppa")
+#####B end,
+#####B ["stat"] = A_STR,
+#####B ["get_level"] = function()
+#####B return get_skill_scale(SKILL_CONSTRUCT, 50)
+#####B end,
+#####B ["spell_list"] =
+
+[[[[[B"fail"] is a function that is called whenever you ##fail to cast the
+spells##. Here it does nothing spectacular.
+[[[[[B"stat"] defines the stat used to cast the spells. Here it is strength.
+Any other stat can be used, prefix it with [[[[[BA_].
+[[[[[B"get_level"] is used to determine the level of the spell. It's associated
+with spells that increase in power the more points that are invested in the
+associated skill. I know that's not terribly clear, I'll come back to it in a
+moment.
+[[[[[B"spell_list"] is just that, a list of all the spells.
+Each of these four properties within the table must end with a comma. If a
+function is defined in the property itself then we add the comma after the
+closing [[[[[Bend]. Again compare with construct.lua to see it. Any line NOT
+ending with a comma will cause a lua error on startup, probably of the type
+[[[[[V'}' expected to close '{' at line <whatever>.]
+
+#####R=== The spell list ===
+
+Each spell, within the [[[[[B"spell_list"] key has its own set of properties
+that we need to define from a sub-table so we open another set of braces to
+start the spell list, and then a third set of braces to start the first spell.
+So with all this, our first spell looks like:
+
+#####B ["spell_list"] =
+#####B {
+#####B {
+#####B ["name"] =
+#####B ["desc"] =
+#####B ["mana"] =
+#####B ["level"] =
+#####B ["fail"] =
+#####B ["spell"] =
+#####B ["info"] =
+#####B },
+
+[[[[[B"name"] is, as you would expect, the name of the spell, as you want it to
+appear in the spell list when choosing a spell. The maximum number of
+characters for this is 29.
+[[[[[B"desc"] is the description received when you hit the capital letter of
+that spell in the menu. (i.e., press 'a' to cast the first spell, but press 'A'
+to receive info about the first spell.
+[[[[[B"mana"] is the amount of mana required to cast the spell.
+[[[[[B"level"] is the level required to use that spell (that's level of the (in
+this case construction) skill, not character level!).
+[[[[[B"fail"] is base fail rate.
+[[[[[B"spell"] is the function that is executed when the spell is cast. Note
+that it MUST take the form [[[[[Bfunction() blah end] even if you're calling
+a C function directly. If you have a look at the end of the file, you'll see
+the "rebuild dungeon" spell which is identical to the "alter_reality" spell.
+However, rather than reading [[[[[B"spell" = alter_reality()], it reads:
+
+#####B["spell"] = function()
+#####B alter_reality()
+#####Bend,
+
+which appears to be a long way round to do the same thing, but this is how it
+must be done.
+
+In a similar way, the [[[[[B"info"] key must begin with a [[[[[Bfunction()]
+and return the value of what is to be displayed alongside the spell name,
+level and mana in the spell list. The maximum number of characters that can be
+displayed here is dependent on the width of the user's screen, but try to keep
+it under 12 if you can, as this will fit in a standard 80x24 terminal screen.
+The first character will need to be a space otherwise you'll have the info line
+squashed right up against the fail rate and it will look odd. If you wish to
+have this part blank in the spell list, you still need to return a value, so
+just a single space will do : [[[[[Breturn " "]
+
+All of these keys are repeated for each spell, with each spell in its own
+table (therefore, it's own set of braces). Again, check the lua file for
+clarification.
+
+When entering the spells in the "spell_list", you must take care to specify
+them in the order which they are gained, otherwise they display incorrectly in
+the spell list.
+
+You should by now be experienced enough to understand most of what's going on
+in the actual spell functions (especially if you dig around in the source a
+bit, and check out Chris Hadgis' excellent *****lua_spel.txt*0[spell.pkg] helper
+files. I'm not going to go through the whole file line by line, as this is
+something you should do yourself, figuring out what's going on. I'm going to
+examine a few of the things we haven't covered before though, so pay attention.
+
+#####R=== The get_level() function ===
+
+Probably one of the most important functions that you see reappearing in the
+file is the [[[[[Bget_level()] function. All this does is return the numerical
+value of the power that is given as the first argument. So [[[[[Bget_level]
+[[[[[B(constructor_power)] will return the current level of the constructor power.
+Given that the level of this is taken directly from the construction skill, (we
+defined that in the [[[[[B"get_level"] key, by saying [[[[[Bget_skill_scale]
+[[[[[B(SKILL_CONSTRUCT, 50)] ) it will return the value of your construction skill.
+[[[[[Bconstructor_power] is the name of the whole power, we named it thus on
+the second line of the script!
+
+[[[[[Bget_level] takes the following arguments: [[[[[Bget_level(power, max, ]
+[[[[[Bmin)]. The power is obviously which power we're taking the value from, and the
+max and min allow you to define boundaries for the spell. For instance the
+current maximum value that [[[[[Bget_level(constructor_power)] can return is
+50, as that is the maximum number of skill points you can have in that skill.
+If you were using this as the basis for the damage of a low-level bolt spell,
+you might decide that having a damage of 50 would be too much (unlikely, but
+still possible). You could therefore define a maximum value of 20 so that when
+the value of the construction skill was over 50, the maximum value for
+damage of that spell would be 20. To achieve this you'd have:
+[[[[[Bget_level(constructor_power, 20)]. In a similar way, you can force the
+minimum value of the spell to be higher than the actual construction skill
+level, with a [[[[[Bget_level(constructor_power, 50, 15)]. This would be useful
+say for spells that you wanted to be available when the construction skill
+level reaches 10, but for whom you wanted a (for example) base damage of 15
+right from the word go. These re-scale values rather than capping them!
+
+You can leave out the minimum value as I have done above. You can also leave
+the maximum value out (it will default to 50). If you want to specify a minimum
+value though, you MUST specify a maximum value as well.
+
+As you have hopefully been able to tell, the [[[[[Bget_level()] function
+enables us to have spells that increase in usefulness as you gain levels. Let's
+take the "Dismantle" spell. The function in the [[[[[B"spell"] key is as
+follows:
+
+#####Bfunction()
+#####B local ret, dir, dam
+
+#####B if (get_level(constructor_powers, 50) >= 11) then
+#####B ret, dir = get_aim_dir();
+#####B if (ret == FALSE) then return end
+#####B fire_beam(GF_KILL_TRAP, dir, 1)
+#####B else
+#####B fire_ball(GF_KILL_TRAP, 0, 1, 1)
+#####B end
+#####Bend,
+
+The [[[[[Bif] statement is obviously what really interests us here. You'll
+notice that this has the amendment of an [[[[[Belse] clause, which the [[[[[Bif]
+statement we used in the previous tutorial did not. As you would expect, if the
+condition on the first line of this statement is met, then the instructions
+immediately below it are carried out. If the condition is not met, then the
+statements that follow the [[[[[Belse] are executed.
+
+Coming back to the [[[[[Bget_level] function, we learnt from above, that the
+[[[[[Bget_level] part of this function translates as, "if the value of the
+construction_power level (which happens to be identical to the construction
+skill level) is greater than or equal to 11, cast a beam of trap disarming in
+the specified direction. (The first part of this is all straightforward,
+getting a direction, and cancelling correctly if the player presses 'ESC'.)
+Otherwise, cast a ball of trap disarming with a radius of one, centred on the
+player."
+
+In the same way, as you look at the construc.lua file, you will see that
+[[[[[Bget_level()] is used many times in this way, to increase the power of
+detection spells, to change bolt spells to ball spells, to keep a constantly
+increasing damage going, and so on.
+
+#####R=== Elseif's and things ===
+
+If you want to provide more than one alternative condition, in an
+[[[[[Bif-then-else] statement, you can use [[[[[Belseif]s which do what you
+might expect. Take a look at the first spell, "Survey area", for an example of
+this:
+
+#####Bif (get_level(constructor_powers, 50) >= 28) then
+#####B wiz_lite()
+#####Belseif (get_level(constructor_powers, 50) >= 15) then
+#####B map_area()
+#####B detect_traps(DEFAULT_RADIUS)
+#####Belseif (get_level(constructor_powers, 50) >= 5) then
+#####B detect_traps(DEFAULT_RADIUS)
+#####B detect_stairs(DEFAULT_RADIUS)
+#####B detect_doors(DEFAULT_RADIUS)
+#####Belse
+#####B detect_stairs(DEFAULT_RADIUS)
+#####B detect_doors(DEFAULT_RADIUS)
+#####Bend
+
+If the level of constructor powers is greater or equal to 28, then the function
+[[[[[Bwiz_lite()] is performed, and no other part of the if statement is
+executed. [[[[[Bwiz_lite()] is just the enlightenment spell. If it is less than
+28, the next condition is examined: that if the level of constructor powers is
+greater than or equal to 15, then [[[[[Bmap_area()](Magic mapping) and detect
+traps are called. If the level of constructor power is less than 15, it moves
+onto the next condition, which says that if the level of constructor power is
+greater than 5, then detect stairs, traps and doors. If none of these
+conditions are met,(that is, if the level of construction skill is less than 5)
+then we just detect doors and stairs.
+
+You'll note that each of the detection spells includes a DEFAULT_RADIUS
+constant. You could change this to a numerical value, or a variable defined
+somewhere else in your script. eg [[[[[Bdetect_traps(2)] would detect traps
+with a radius of 2 centred on the player.
+
+#####R=== Registering the skill type ===
+
+This is what we do at the end of the file, and is what ties the powers we've
+defined to the action of pressing the 'm' key in game. Once more we're calling
+a special function [[[[[Badd_mkey()] which takes its arguments for a table.
+There are only two keys in this table though which keeps things simple.
+
+#####Badd_mkey
+#####B{
+#####B ["mkey"] = MKEY_CONSTRUCT_POWERS,
+#####B ["fct"] = function()
+#####B execute_magic(constructor_powers)
+#####B energy_use = energy_use + 100;
+#####B end
+#####B}
+
+[[[[[B"mkey"] must be a UNIQUE value > 1000 . Here I've defined it as a
+constant, [[[[[BMKEY_CONSTRUCT_POWERS], which has the value 1004. This value
+we'll call again in the s_info.txt file.
+[[[[[B"fct"] is the function that's called when the user presses the key in the
+'m' menu. So here, it calls the [[[[[Bexecute_magic] function which actually
+displays a list of powers for the user to choose from. The argument it takes is
+the powers it will use (alchemy, mindcraft, etc., or in this case constructor),
+and then the [[[[[Benergy_use] line tells the game to take one game turn to do
+the action.
+
+#####R=== Adding the skill in s_info.txt ===
+
+Take a look in the s_info.txt file, under the Misc section. You'll see,
+
+#####BN:57:Construction
+#####BD:Ability to use constructor powers
+#####BD:Construction powers use strength
+#####BA:1004:Build or knock down stuff
+#####BI:1000
+
+The first line is the index of the skill; again this must be unique. The second
+property is the name of the skill. The [[[[[BD] lines are the lines displayed
+when the skill is highlighted in the skill screen.
+The first entry on the [[[[[BA] line is the value of the [[[[[B"mkey"] we
+defined in the [[[[[Badd_mkey] function in our script. The second entry is the
+display for selecting the construction power in the 'm' menu.
+The [[[[[BI] line is currently unused, but add a 1000 there anyway. That's what
+all the others have so when it's introduced, at least it will affect your
+powers identically to how it affects all the other powers.
+
+If you scroll to the very bottom of the file now, you'll see I've placed the
+skill at the bottom of the Misc branch of the skills tree. I then made a new
+class, constructor, which you can see in p_info.txt.
+
+That is all that is NEEDED when writing a script to add a skill - defining an
+mkey using add_mkey, and defining any powers that are called in the
+[[[[[B"fct"] (generally using [[[[[Badd_magic] ).
+
+And I've added the line
+
+#####Btome_dofile("construc.lua")
+
+in init.lua so the script is loaded on start-up!
+
+Below I'm going to talk in depth about a few other functions that you may find
+useful in your scripting.
+
+#####R=== fire_bolt() and fire_beam() ===
+
+In the last help file we looked at the routine for firing a ball -
+[[[[[Bfire_ball()]. Here's a quick note about beams and bolts...
+[[[[[Bfire_beam()] and [[[[[Bfire_bolt()] take 2 arguments:
+[[[[[B(type, direction, damage)]. So in the dismantle spell we have the
+direction passed from [[[[[Bget_aim_dir()] (the function that asks the player
+for a direction), the type of damage is [[[[[BGF_KILL_TRAP], which as you might
+expect disarms traps. And the damage is only 1 because it's not going to hurt
+monsters, just dismantle traps.
+
+#####R=== set_oppose_elec() ===
+
+OK here's another thing. Wander on down to the sparky_skills spell. After the
+appropriate bolt/ball is fired, we have the line:
+
+#####Bif player.oppose_elec == 0 then
+#####B set_oppose_elec(randint(10) + 20 + get_level(constructor_powers, 20)*3)
+#####Bend
+
+This is the bit that grants temporary resist electricity. We've called the
+function [[[[[Bset_oppose_elec(turns)], which sets the player's resist
+electricity to "on" for the time specified in the argument "turns". We're only
+calling this if the player is not already granted temporary resist electricity,
+and we've linked the number of turns it is active to the level of the
+construction skill. I've limited the maximum value of get_level to 20 in this
+instance. A similar idea can be used for temporarily granting levitation,
+extended infravision, protection against evil, resist fire, stuns, cuts and so
+on and so on. Have a look in player.pkg in the source for a full list....
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
diff --git a/lib/help/lua_spel.txt b/lib/help/lua_spel.txt
new file mode 100644
index 00000000..aa4a532b
--- /dev/null
+++ b/lib/help/lua_spel.txt
@@ -0,0 +1,2150 @@
+|||||oy
+
+#####R /----------------------------------------\
+#####R < spell.pkg functions helper file >
+#####R \----------------------------------------/
+
+----------------------------------------------------------------------
+
+#####R=== teleport_player_directed ===
+
+#####GDeclaration
+ extern void teleport_player_directed(int rad, int dir);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport player, using a distance and a direction as a rough guide.
+ *
+ * This function is not at all obsessive about correctness.
+ * This function allows teleporting into vaults (!)
+ */
+
+#####GDescription
+Teleport a player up to "rad" grids away roughly in "dir" direction.
+
+#####GParameters
+> "rad" must not exceed 200. The distance teleported is a minimum of a
+ quarter of "rad".
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+
+----------------------------------------------------------------------
+
+#####R=== teleport_away ===
+
+#####GDeclaration
+ extern void teleport_away(int m_idx, int dis);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport a monster, normally up to "dis" grids away.
+ *
+ * Attempt to move the monster at least "dis/2" grids away.
+ *
+ * But allow variation to prevent infinite loops.
+ */
+
+#####GDescription
+Teleport monster indicated by "m_idx" up to "dis" grids away.
+
+#####GParameters
+> "m_idx" is the index of the monster in m_list[].
+> "dis" must not exceed 200. The distance teleported is a minimum of a
+ quarter of "dis".
+
+----------------------------------------------------------------------
+
+#####R=== teleport_player ===
+
+#####GDeclaration
+ extern void teleport_player(int dis);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport the player to a location up to "dis" grids away.
+ *
+ * If no such spaces are readily available, the distance may increase.
+ * Try very hard to move the player at least a quarter that distance.
+ */
+
+#####GDescription
+Teleport player up to "dis" grids away.
+
+#####GParameters
+> "dis" must not exceed 200. The distance teleported is a minimum of a
+ quarter of "dis".
+
+----------------------------------------------------------------------
+
+#####R=== teleport_player_to ===
+
+#####GDeclaration
+ extern void teleport_player_to(int ny, int nx);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport player to a grid near the given location
+ *
+ * This function is slightly obsessive about correctness.
+ * This function allows teleporting into vaults (!)
+ */
+
+#####GDescription
+Teleport player to a grid near the given location ("ny", "nx"). If
+the location is empty, the player goes there, otherwise they go to
+a grid as close as possible to the location.
+
+#####GParameters
+> "ny" is the y co-ordinate of the location.
+> "nx" is the x co-ordinate of the location.
+
+----------------------------------------------------------------------
+
+#####R=== teleport_monster_to ===
+
+#####GDeclaration
+ extern void teleport_monster_to(int m_idx, int ny,
+ int nx);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport a monster to a grid near the given location
+ *
+ * This function is slightly obsessive about correctness.
+ */
+
+#####GDescription
+Teleport monster indicated by "m_idx" to a grid near the given
+location ("ny", "nx"). If the location is empty, the monster goes
+there, otherwise they go to a grid as close as possible to the
+location.
+
+#####GParameters
+> "m_idx" is the index of the monster in m_list[].
+> "ny" is the y co-ordinate of the location.
+> "nx" is the x co-ordinate of the location.
+
+----------------------------------------------------------------------
+
+#####R=== teleport_player_level ===
+
+#####GDeclaration
+ extern void teleport_player_level(void);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport the player one level up or down (random when legal)
+ */
+
+#####GDescription
+Teleport the player one level up or down at random.
+
+----------------------------------------------------------------------
+
+#####R=== recall_player ===
+
+#####GDeclaration
+ extern void recall_player(void);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Recall the player to town or dungeon
+ */
+
+#####GDescription
+Recall the player to town (if in dungeon) or dungeon (if in town).
+
+----------------------------------------------------------------------
+
+#####R=== take_hit ===
+
+#####GDeclaration
+ extern void take_hit(int damage, cptr kb_str);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Decreases players hit points and sets death flag if necessary
+ *
+ * XXX XXX XXX Invulnerability needs to be changed into a "shield"
+ *
+ * XXX XXX XXX Hack -- this function allows the user to save (or quit)
+ * the game when he dies, since the "You die." message is shown before
+ * setting the player to "dead".
+ */
+
+#####GDescription
+Reduce the player's current hit points by "damage" points. If the
+player dies, "kb_str" is used to record what the player was killed by
+(see high-score table).
+
+#####GParameters
+> "damage" is the amount of damage.
+> "kb_str" is a string describing what killed the player.
+
+----------------------------------------------------------------------
+
+#####R=== take_sanity_hit ===
+
+#####GDeclaration
+ extern void take_sanity_hit(int damage, cptr hit_from);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/* Decrease player's sanity. This is a copy of the function above. */
+
+#####GDescription
+Reduce the player's current sanity points by "damage" points. If the
+player dies, "hit_from" is used to record what the player was killed
+by (see high-score table).
+
+#####GParameters
+> "damage" is the amount of damage.
+> "hit_from" is a string describing what killed the player.
+
+----------------------------------------------------------------------
+
+#####R=== project ===
+
+#####GDeclaration
+ extern bool project(int who, int rad, int y, int x,
+ int dam, int typ, int flg);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Generic "beam"/"bolt"/"ball" projection routine.
+ *
+ * Input:
+ * who: Index of "source" monster (negative for "player")
+ * jk -- -2 for traps, only used with project_jump
+ * rad: Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
+ * y,x: Target location (or location to travel "towards")
+ * dam: Base damage roll to apply to affected monsters (or player)
+ * typ: Type of damage to apply to monsters (and objects)
+ * flg: Extra bit flags (see PROJECT_xxxx in "defines.h")
+ *
+ * Return:
+ * TRUE if any "effects" of the projection were observed, else FALSE
+ *
+ * Allows a monster (or player) to project a beam/bolt/ball of a given kind
+ * towards a given location (optionally passing over the heads of interposing
+ * monsters), and have it do a given amount of damage to the monsters (and
+ * optionally objects) within the given radius of the final location.
+ *
+ * A "bolt" travels from source to target and affects only the target grid.
+ * A "beam" travels from source to target, affecting all grids passed through.
+ * A "ball" travels from source to the target, exploding at the target, and
+ * affecting everything within the given radius of the target location.
+ *
+ * Traditionally, a "bolt" does not affect anything on the ground, and does
+ * not pass over the heads of interposing monsters, much like a traditional
+ * missile, and will "stop" abruptly at the "target" even if no monster is
+ * positioned there, while a "ball", on the other hand, passes over the heads
+ * of monsters between the source and target, and affects everything except
+ * the source monster which lies within the final radius, while a "beam"
+ * affects every monster between the source and target, except for the casting
+ * monster (or player), and rarely affects things on the ground.
+ *
+ * Two special flags allow us to use this function in special ways, the
+ * "PROJECT_HIDE" flag allows us to perform "invisible" projections, while
+ * the "PROJECT_JUMP" flag allows us to affect a specific grid, without
+ * actually projecting from the source monster (or player).
+ *
+ * The player will only get "experience" for monsters killed by himself
+ * Unique monsters can only be destroyed by attacks from the player
+ *
+ * Only 256 grids can be affected per projection, limiting the effective
+ * "radius" of standard ball attacks to nine units (diameter nineteen).
+ *
+ * One can project in a given "direction" by combining PROJECT_THRU with small
+ * offsets to the initial location (see "line_spell()"), or by calculating
+ * "virtual targets" far away from the player.
+ *
+ * One can also use PROJECT_THRU to send a beam/bolt along an angled path,
+ * continuing until it actually hits something (useful for "stone to mud").
+ *
+ * Bolts and Beams explode INSIDE walls, so that they can destroy doors.
+ *
+ * Balls must explode BEFORE hitting walls, or they would affect monsters
+ * on both sides of a wall. Some bug reports indicate that this is still
+ * happening in 2.7.8 for Windows, though it appears to be impossible.
+ *
+ * We "pre-calculate" the blast area only in part for efficiency.
+ * More importantly, this lets us do "explosions" from the "inside" out.
+ * This results in a more logical distribution of "blast" treasure.
+ * It also produces a better (in my opinion) animation of the explosion.
+ * It could be (but is not) used to have the treasure dropped by monsters
+ * in the middle of the explosion fall "outwards", and then be damaged by
+ * the blast as it spreads outwards towards the treasure drop location.
+ *
+ * Walls and doors are included in the blast area, so that they can be
+ * "burned" or "melted" in later versions.
+ *
+ * This algorithm is intended to maximise simplicity, not necessarily
+ * efficiency, since this function is not a bottleneck in the code.
+ *
+ * We apply the blast effect from ground zero outwards, in several passes,
+ * first affecting features, then objects, then monsters, then the player.
+ * This allows walls to be removed before checking the object or monster
+ * in the wall, and protects objects which are dropped by monsters killed
+ * in the blast, and allows the player to see all affects before he is
+ * killed or teleported away. The semantics of this method are open to
+ * various interpretations, but they seem to work well in practice.
+ *
+ * We process the blast area from ground-zero outwards to allow for better
+ * distribution of treasure dropped by monsters, and because it provides a
+ * pleasing visual effect at low cost.
+ *
+ * Note that the damage done by "ball" explosions decreases with distance.
+ * This decrease is rapid, grids at radius "dist" take "1/dist" damage.
+ *
+ * Notice the "napalm" effect of "beam" weapons. First they "project" to
+ * the target, and then the damage "flows" along this beam of destruction.
+ * The damage at every grid is the same as at the "centre" of a "ball"
+ * explosion, since the "beam" grids are treated as if they ARE at the
+ * centre of a "ball" explosion.
+ *
+ * Currently, specifying "beam" plus "ball" means that locations which are
+ * covered by the initial "beam", and also covered by the final "ball", except
+ * for the final grid (the epicentre of the ball), will be "hit twice", once
+ * by the initial beam, and once by the exploding ball. For the grid right
+ * next to the epicentre, this results in 150% damage being done. The centre
+ * does not have this problem, for the same reason the final grid in a "beam"
+ * plus "bolt" does not -- it is explicitly removed. Simply removing "beam"
+ * grids which are covered by the "ball" will NOT work, as then they will
+ * receive LESS damage than they should. Do not combine "beam" with "ball".
+ *
+ * The array "gy[],gx[]" with current size "grids" is used to hold the
+ * collected locations of all grids in the "blast area" plus "beam path".
+ *
+ * Note the rather complex usage of the "gm[]" array. First, gm[0] is always
+ * zero. Second, for N>1, gm[N] is always the index (in gy[],gx[]) of the
+ * first blast grid (see above) with radius "N" from the blast centre. Note
+ * that only the first gm[1] grids in the blast area thus take full damage.
+ * Also, note that gm[rad+1] is always equal to "grids", which is the total
+ * number of blast grids.
+ *
+ * Note that once the projection is complete, (y2,x2) holds the final location
+ * of bolts/beams, and the "epicentre" of balls.
+ *
+ * Note also that "rad" specifies the "inclusive" radius of projection blast,
+ * so that a "rad" of "one" actually covers 5 or 9 grids, depending on the
+ * implementation of the "distance" function. Also, a bolt can be properly
+ * viewed as a "ball" with a "rad" of "zero".
+ *
+ * Note that if no "target" is reached before the beam/bolt/ball travels the
+ * maximum distance allowed (MAX_RANGE), no "blast" will be induced. This
+ * may be relevant even for bolts, since they have a "1x1" mini-blast.
+ *
+ * Note that for consistency, we "pretend" that the bolt actually takes "time"
+ * to move from point A to point B, even if the player cannot see part of the
+ * projection path. Note that in general, the player will *always* see part
+ * of the path, since it either starts at the player or ends on the player.
+ *
+ * Hack -- we assume that every "projection" is "self-illuminating".
+ *
+ * Hack -- when only a single monster is affected, we automatically track
+ * (and recall) that monster, unless "PROJECT_JUMP" is used.
+ *
+ * Note that all projections now "explode" at their final destination, even
+ * if they were being projected at a more distant destination. This means
+ * that "ball" spells will *always* explode.
+ *
+ * Note that we must call "handle_stuff()" after affecting terrain features
+ * in the blast radius, in case the "illumination" of the grid was changed,
+ * and "update_view()" and "update_monsters()" need to be called.
+ */
+
+#####GDescription
+Generate a beam/bolt/ball starting from "who" with a radius of "rad"
+at target grid "y,x" for "damage" points of "typ" damage. The beam/
+bolt/ball can have various properties as denoted by "flg".
+
+#####GParameters
+> "who" is > 0 (index of monster in m_list[]), < 0 and
+ not -100 or -101 (player), -100 or -101 (trap).
+> "rad" is 0 for a beam/bolt and 1-9 for a ball.
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "dam" is the number of points of damage.
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "flg" is the projection effect
+ *****fields.txt*0[PROJECT_fields]
+
+----------------------------------------------------------------------
+
+#####R=== corrupt_player ===
+
+#####GDeclaration
+ extern void corrupt_player(void);
+
+#####GFile
+ spells1.c
+
+#####GComment
+(none)
+
+#####GDescription
+Swap two of the players stats at random.
+
+----------------------------------------------------------------------
+
+#####R=== grow_trees ===
+
+#####GDeclaration
+ extern void grow_trees(int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Grow trees
+ */
+
+#####GDescription
+Grow up to (("rad" x "rad") + 11) trees around the player.
+
+#####GParameters
+> "rad" is the radius of the area where trees may grow.
+
+----------------------------------------------------------------------
+
+#####R=== hp_player ===
+
+#####GDeclaration
+ extern bool hp_player(int num);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Increase players hit points, notice effects
+ */
+
+#####GDescription
+Add "num" points to the player's current hit points. The total can
+not exceed the maximum.
+
+#####GParameters
+> "num" is the number of points to add.
+
+----------------------------------------------------------------------
+
+#####R=== heal_insanity ===
+
+#####GDeclaration
+ extern bool heal_insanity(int val);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/* Heal insanity. */
+
+#####GDescription
+Add "val" points to the player's current sanity points. The total can
+not exceed the maximum.
+
+#####GParameters
+> "val" is the number of points to add.
+
+----------------------------------------------------------------------
+
+#####R=== warding_glyph ===
+
+#####GDeclaration
+ extern void warding_glyph(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Leave a "glyph of warding" which prevents monster movement
+ */
+
+#####GDescription
+Place a glyph at the player's location. The location must be bare.
+
+----------------------------------------------------------------------
+
+#####R=== explosive_rune ===
+
+#####GDeclaration
+ extern void explosive_rune(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Place a minor glyph (explosive rune) at the player's location. The
+location must be bare.
+
+----------------------------------------------------------------------
+
+#####R=== do_dec_stat ===
+
+#####GDeclaration
+ extern bool do_dec_stat(int stat, int mode);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Lose a "point"
+ */
+
+#####GDescription
+Attempt to reduce the player's "stat" statistic by a point.
+
+#####GParameters
+> "stat" is the statistic
+ *****fields.txt*0[A_fields]
+> "mode" is the type of decrease: temporary, normal, or permanent
+ *****fields.txt*0[STAT_DEC_fields]
+
+----------------------------------------------------------------------
+
+#####R=== do_res_stat ===
+
+#####GDeclaration
+ extern bool do_res_stat(int stat);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Restore lost "points" in a stat
+ */
+
+#####GDescription
+Restore the player's "stat" statistic.
+
+#####GParameters
+> "stat" is the statistic
+ *****fields.txt*0[A_fields]
+
+----------------------------------------------------------------------
+
+#####R=== do_inc_stat ===
+
+#####GDeclaration
+ extern bool do_inc_stat(int stat);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Gain a "point" in a stat
+ */
+
+#####GDescription
+Increase the player's "stat" statistic by a point.
+
+#####GParameters
+> "stat" is the statistic
+ *****fields.txt*0[A_fields]
+
+----------------------------------------------------------------------
+
+#####R=== identify_pack ===
+
+#####GDeclaration
+ extern void identify_pack(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Identify everything being carried.
+ * Done by a potion of "self knowledge".
+ */
+
+#####GDescription
+Identify all items in the inventory.
+
+----------------------------------------------------------------------
+
+#####R=== remove_curse ===
+
+#####GDeclaration
+ extern bool remove_curse(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Remove most curses
+ */
+
+#####GDescription
+Remove all curses except for heavy curses.
+
+----------------------------------------------------------------------
+
+#####R=== remove_all_curse ===
+
+#####GDeclaration
+ extern bool remove_all_curse(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Remove all curses
+ */
+
+#####GDescription
+Remove all curses including heavy curses.
+
+----------------------------------------------------------------------
+
+#####R=== restore_level ===
+
+#####GDeclaration
+ extern bool restore_level(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Restores any drained experience
+ */
+
+#####GDescription
+Restore all drained experience points (if any).
+
+----------------------------------------------------------------------
+
+#####R=== self_knowledge ===
+
+#####GDeclaration
+ extern void self_knowledge(FILE *fff);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * self-knowledge... idea from nethack. Useful for determining powers and
+ * resistances of items. It saves the screen, clears it, then starts listing
+ * attributes, a screenful at a time. (There are a LOT of attributes to
+ * list. It will probably take 2 or 3 screens for a powerful character whose
+ * using several artifacts...) -CFT
+ *
+ * It is now a lot more efficient. -BEN-
+ *
+ * See also "identify_fully()".
+ *
+ * XXX XXX XXX Use the "show_file()" method, perhaps.
+ */
+
+#####GDescription
+Show all attributes including racial powers, mutations, and equipment
+effects.
+
+#####GParameters
+> "*ffff" points to a file (write info to file) or is NULL (write info
+ to screen).
+
+----------------------------------------------------------------------
+
+#####R=== lose_all_info ===
+
+#####GDeclaration
+ extern bool lose_all_info(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Forget everything
+ */
+
+#####GDescription
+Forget about objects and the map.
+
+----------------------------------------------------------------------
+
+#####R=== detect_traps ===
+
+#####GDeclaration
+ extern bool detect_traps(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all traps on current panel
+ */
+
+#####GDescription
+Detect all traps on current panel.
+
+----------------------------------------------------------------------
+
+#####R=== detect_doors ===
+
+#####GDeclaration
+ extern bool detect_doors(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all doors on current panel
+ */
+
+#####GDescription
+Detect all doors on current panel.
+
+----------------------------------------------------------------------
+
+#####R=== detect_stairs ===
+
+#####GDeclaration
+ extern bool detect_stairs(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all stairs on current panel
+ */
+
+#####GDescription
+Detect all stairs on current panel.
+
+----------------------------------------------------------------------
+
+#####R=== detect_treasure ===
+
+#####GDeclaration
+ extern bool detect_treasure(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect any treasure on the current panel
+ */
+
+#####GDescription
+Detect any treasure on the current panel.
+
+----------------------------------------------------------------------
+
+Field: hack_no_detect_message
+Value: FALSE
+
+----------------------------------------------------------------------
+
+#####R=== detect_objects_gold ===
+
+#####GDeclaration
+ extern bool detect_objects_gold(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "gold" objects on the current panel
+ */
+
+#####GDescription
+Detect all objects with the TV_GOLD flag.
+
+----------------------------------------------------------------------
+
+#####R=== detect_objects_normal ===
+
+#####GDeclaration
+ extern bool detect_objects_normal(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "normal" objects on the current panel
+ */
+
+#####GDescription
+Detect all objects without the TV_GOLD flag.
+
+----------------------------------------------------------------------
+
+#####R=== detect_objects_magic ===
+
+#####GDeclaration
+ extern bool detect_objects_magic(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "magic" objects on the current panel.
+ *
+ * This will light up all spaces with "magic" items, including artifacts,
+ * ego-items, potions, scrolls, books, rods, wands, staves, amulets, rings,
+ * and "enchanted" items of the "good" variety.
+ *
+ * It can probably be argued that this function is now too powerful.
+ */
+
+#####GDescription
+Detect all "magic" objects which are artefacts, ego items, or have one
+of the following flags - TV_AMULET, TV_RING, TV_BATERIE, TV_STAFF,
+TV_WAND, TV_ROD, TV_ROD_MAIN, TV_SCROLL, TV_POTION, TV_POTION2,
+TV_VALARIN_BOOK, TV_MAGERY_BOOK, TV_SHADOW_BOOK, TV_CHAOS_BOOK,
+TV_SPIRIT_BOOK, TV_NETHER_BOOK, TV_DAEMON_BOOK, TV_CRUSADE_BOOK,
+TV_SIGALDRY_BOOK, TV_SYMBIOTIC_BOOK, TV_MUSIC_BOOK.
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_normal ===
+
+#####GDeclaration
+ extern bool detect_monsters_normal(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "normal" monsters on the current panel
+ */
+
+#####GDescription
+Detect all non-invisible monsters (without RF2_INVISIBLE).
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_invis ===
+
+#####GDeclaration
+ extern bool detect_monsters_invis(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "invisible" monsters on current panel
+ */
+
+#####GDescription
+Detect all invisible monsters (with RF2_INVISIBLE).
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_evil ===
+
+#####GDeclaration
+ extern bool detect_monsters_evil(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "evil" monsters on current panel
+ */
+
+#####GDescription
+Detect all evil monsters (with RF3_EVIL).
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_good ===
+
+#####GDeclaration
+ extern bool detect_monsters_good(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/* Detect good monsters */
+
+#####GDescription
+Detect all good monsters (with RF3_GOOD).
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_xxx ===
+
+#####GDeclaration
+ extern bool detect_monsters_xxx(u32b match_flag);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * A "generic" detect monsters routine, tagged to flags3
+ */
+
+#####GDescription
+Detect all monsters with "match_flag" flag.
+
+#####GParameters
+> "match_flag" can be any RF3_ flag (see defines.h) but only
+ RF3_DEMON, RF3_UNDEAD, RF3_GOOD work.
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_string ===
+
+#####GDeclaration
+ extern bool detect_monsters_string(cptr);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all (string) monsters on current panel
+ */
+
+#####GDescription
+Detect all monsters whose default monster character matches a
+character pointed to by "cptr".
+
+#####GParameters
+> "cptr" is a pointer to a single character, eg 'Z' for hounds. For
+ available characters, see the "symbol" field of the graphics (G)
+ line of r_info.txt.
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_nonliving ===
+
+#####GDeclaration
+ extern bool detect_monsters_nonliving(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "nonliving", "undead" or "demonic" monsters on current panel
+ */
+
+#####GDescription
+Detect all non-living monsters (with RF3_NONLIVING, RF3_UNDEAD, or
+RF3_DEMON).
+
+----------------------------------------------------------------------
+
+#####R=== detect_all ===
+
+#####GDeclaration
+ extern bool detect_all(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect everything
+ */
+
+#####GDescription
+Detects traps, doors, stairs, treasure, gold objects, normal objects,
+invisible monsters, normal (visible) monsters.
+
+----------------------------------------------------------------------
+
+#####R=== stair_creation ===
+
+#####GDeclaration
+ extern void stair_creation(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Create stairs at the player location
+ */
+
+#####GDescription
+Create stairs at the player location. This is not allowed if the grid
+is not empty, the player is not in a dungeon, the player is on a
+special level, the player is in an arena or quest. If the player is
+in the town or wilderness the stairs will go down. If the player is
+on a quest level or at the bottom of a dungeon, the stairs will go up.
+Otherwise there is an even chance the stairs will go up or down.
+
+----------------------------------------------------------------------
+
+#####R=== wall_stone ===
+
+#####GDeclaration
+ extern bool wall_stone(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Create a stone wall on the player's grid. This function uses the
+project() function to create the stone wall. Apparently zero can be
+used as the "who" parameter for the player. See details for the
+project() function elsewhere in this document.
+
+----------------------------------------------------------------------
+
+#####R=== create_artifact ===
+
+#####GDeclaration
+ extern bool create_artifact(object_type *o_ptr,
+ bool a_scroll, bool get_name);
+
+#####GFile
+ randart.c
+
+#####GComment
+(none)
+
+#####GDescription
+Create an artifact from object "*optr".
+
+#####GParameters
+> "*optr* is a pointer to an object
+> "a_scroll" is true if the artifact is created by reading a scroll
+> "get_name" is true if the artifact is to be named by the player (if
+ a_scroll is true) or created randomly (a_scroll is false), or false
+ if an inscription is used.
+
+----------------------------------------------------------------------
+
+#####R=== ident_spell ===
+
+#####GDeclaration
+ extern bool ident_spell(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Identify an object in the inventory (or on the floor)
+ * This routine does *not* automatically combine objects.
+ * Returns TRUE if something was identified, else FALSE.
+ */
+
+#####GDescription
+Identify an object in the inventory (or on the floor).
+
+----------------------------------------------------------------------
+
+#####R=== identify_fully ===
+
+#####GDeclaration
+ extern bool identify_fully(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Fully "identify" an object in the inventory -BEN-
+ * This routine returns TRUE if an item was identified.
+ */
+
+#####GDescription
+Fully "identify" an object in the inventory (or on the floor).
+
+----------------------------------------------------------------------
+
+#####R=== recharge ===
+
+#####GDeclaration
+ extern bool recharge(int num);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Recharge a wand/staff/rod from the pack or on the floor.
+ * This function has been rewritten in Oangband. -LM-
+ *
+ * Mage -- Recharge I --> recharge(90)
+ * Mage -- Recharge II --> recharge(150)
+ * Mage -- Recharge III --> recharge(220)
+ *
+ * Priest or Necromancer -- Recharge --> recharge(140)
+ *
+ * Scroll of recharging --> recharge(130)
+ * Scroll of *recharging* --> recharge(200)
+ *
+ * It is harder to recharge high level, and highly charged wands,
+ * staffs, and rods. The more wands in a stack, the more easily and
+ * strongly they recharge. Staffs, however, each get fewer charges if
+ * stacked.
+ *
+ * XXX XXX XXX Beware of "sliding index errors".
+ */
+
+#####GDescription
+Recharge an object in the inventory (or on the floor) with "num"
+power.
+
+#####GParameters
+> "num" is the power used in recharging. It is compared to the
+ object's level to determine whether the item is recharged
+ successfully or destroyed. If it is recharged, it also determines
+ how many charges are added, or how much recharge time is reduced.
+
+----------------------------------------------------------------------
+
+#####R=== aggravate_monsters ===
+
+#####GDeclaration
+ extern void aggravate_monsters(int who);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Wake up all monsters, and speed up "los" monsters.
+ */
+
+#####GDescription
+Aggravate monsters, originating from "who".
+
+#####GParameters
+> "who" is the index of monster in m_list[] (1 if it is the player)
+ which triggers the aggravation;
+
+----------------------------------------------------------------------
+
+#####R=== genocide ===
+
+#####GDeclaration
+ extern bool genocide(bool player_cast);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Genocide a monster race.
+
+#####GParameters
+> "player_cast" is true if the player cast the spell so the player can
+ take damage.
+
+----------------------------------------------------------------------
+
+#####R=== mass_genocide ===
+
+#####GDeclaration
+ extern bool mass_genocide(bool player_cast);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Delete all nearby (non-unique) monsters
+ */
+
+#####GDescription
+Delete all nearby (non-unique) monsters.
+
+#####GParameters
+> "player_cast" is true if the player cast the spell so the player can
+ take damage.
+
+----------------------------------------------------------------------
+
+#####R=== probing ===
+
+#####GDeclaration
+ extern bool probing(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Probe nearby monsters
+ */
+
+#####GDescription
+Probe all nearby monsters.
+
+----------------------------------------------------------------------
+
+#####R=== banish_evil ===
+
+#####GDeclaration
+ extern bool banish_evil(int dist);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Banish evil monsters
+ */
+
+#####GDescription
+Banish nearby evil monsters doing "dist" points of GF_AWAY_EVIL
+damage.
+
+#####GParameters
+> "dist" is the amount of damage done to each monster.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_evil ===
+
+#####GDeclaration
+ extern bool dispel_evil(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel evil monsters
+ */
+
+#####GDescription
+Dispel nearby evil monsters doing "dam" points of GF_DISP_EVIL
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_good ===
+
+#####GDeclaration
+ extern bool dispel_good(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel good monsters
+ */
+
+#####GDescription
+Dispel nearby good monsters doing "dam" points of GF_DISP_GOOD
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_undead ===
+
+#####GDeclaration
+ extern bool dispel_undead(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel undead monsters
+ */
+
+#####GDescription
+Dispel nearby undead monsters doing "dam" points of GF_DISP_UNDEAD
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_monsters ===
+
+#####GDeclaration
+ extern bool dispel_monsters(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel all monsters
+ */
+
+#####GDescription
+Dispel all nearby monsters doing "dam" points of GF_DISP_ALL
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_living ===
+
+#####GDeclaration
+ extern bool dispel_living(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel 'living' monsters
+ */
+
+#####GDescription
+Dispel nearby living monsters doing "dam" points of GF_DISP_LIVING
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_demons ===
+
+#####GDeclaration
+ extern bool dispel_demons(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel demons
+ */
+
+#####GDescription
+Dispel nearby demon monsters doing "dam" points of GF_DISP_DEMON
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== turn_undead ===
+
+#####GDeclaration
+ extern bool turn_undead(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Turn undead
+ */
+
+#####GDescription
+Turn nearby undead monsters doing a point of GF_TURN_UNDEAD damage for
+each player level.
+
+----------------------------------------------------------------------
+
+#####R=== wipe ===
+
+#####GDeclaration
+ extern void wipe(int y1, int x1, int r);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Wipe -- Empties a part of the dungeon
+ */
+
+#####GDescription
+Delete monsters and objects from an area of the dungeon centred at
+grid "y1,x1" for a radius "r". This does not work on special levels or
+quests. The player may be blinded. The player forgets the affected
+area and it becomes dark. All grids become floor.
+
+#####GParameters
+> "y1" is the y-coordinate of the wipe's origin.
+> "x1" is the x-coordinate of the wipe's origin.
+> "r" is the radius of the wipe.
+
+----------------------------------------------------------------------
+
+#####R=== destroy_area ===
+
+#####GDeclaration
+ extern void destroy_area(int y1, int x1, int r,
+ bool full);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * The spell of destruction
+ *
+ * This spell "deletes" monsters (instead of "killing" them).
+ *
+ * Later we may use one function for both "destruction" and
+ * "earthquake" by using the "full" to select "destruction".
+ */
+
+#####GDescription
+Delete monsters and objects from an area of the dungeon centred at
+grid "y1,x1" for a radius "r". This does not work on special levels or
+quests. The epicentre is NOT affected. The player may be blinded. The
+player forgets the affected area and it becomes dark. The grids can
+become granite, quartz, magma, or floor.
+
+#####GParameters
+> "y1" is the y-coordinate of the destruction's origin.
+> "x1" is the x-coordinate of the destruction's origin.
+> "r" is the radius of the destruction.
+> "full" is currently unused.
+
+----------------------------------------------------------------------
+
+#####R=== earthquake ===
+
+#####GDeclaration
+ extern void earthquake(int cy, int cx, int r);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Induce an "earthquake" of the given radius at the given location.
+ *
+ * This will turn some walls into floors and some floors into walls.
+ *
+ * The player will take damage and "jump" into a safe grid if possible,
+ * otherwise, he will "tunnel" through the rubble instantaneously.
+ *
+ * Monsters will take damage, and "jump" into a safe grid if possible,
+ * otherwise they will be "buried" in the rubble, disappearing from
+ * the level in the same way that they do when genocided.
+ *
+ * Note that thus the player and monsters (except eaters of walls and
+ * passers through walls) will never occupy the same grid as a wall.
+ * Note that as of now (2.7.8) no monster may occupy a "wall" grid, even
+ * for a single turn, unless that monster can pass_walls or kill_walls.
+ * This has allowed massive simplification of the "monster" code.
+ */
+
+#####GDescription
+Create an earthquake centred on grid "cy,cx" with a radius of "r".
+This does not work on quest levels. The epicentre is NOT affected.
+Only about 15% of the grids are affected. The player takes 300 points
+of damage if they can't be moved to a safe grid, otherwise damage is
+from 10 to 40 points. The player forgets the affected area and it
+becomes dark. The grids can become granite, quartz, magma, or floor.
+
+#####GParameters
+Parameters:
+> "cy" is the y-coordinate of the earthquake origin.
+> "cx" is the x-coordinate of the earthquake origin.
+> "r" is the radius of the earthquake.
+
+----------------------------------------------------------------------
+
+#####R=== map_area ===
+
+#####GDeclaration
+ extern void map_area(void);
+
+#####GFile
+ cave.c
+
+#####GComment
+/*
+ * Hack -- map the current panel (plus some) ala "magic mapping"
+ */
+
+#####GDescription
+Map the current panel plus up to 10 grids up and down, and up to 20
+grids left and right.
+
+----------------------------------------------------------------------
+
+#####R=== wiz_lite ===
+
+#####GDeclaration
+ extern void wiz_lite(void);
+
+#####GFile
+ cave.c
+
+#####GComment
+/*
+ * Light up the dungeon using "clairvoyance"
+ *
+ * This function "illuminates" every grid in the dungeon, memorises all
+ * "objects", memorises all grids as with magic mapping, and, under the
+ * standard option settings (view_perma_grids but not view_torch_grids)
+ * memorises all floor grids too.
+ *
+ * Note that if "view_perma_grids" is not set, we do not memorise floor
+ * grids, since this would defeat the purpose of "view_perma_grids", not
+ * that anyone seems to play without this option.
+ *
+ * Note that if "view_torch_grids" is set, we do not memorise floor grids,
+ * since this would prevent the use of "view_torch_grids" as a method to
+ * keep track of what grids have been observed directly.
+ */
+
+#####GDescription
+Light up the entire dungeon and show all monsters and objects.
+
+----------------------------------------------------------------------
+
+#####R=== wiz_lite_extra ===
+
+#####GDeclaration
+ extern void wiz_lite_extra(void);
+
+#####GFile
+ cave.c
+
+#####GComment
+(none)
+
+#####GDescription
+Light up the entire dungeon and show all monsters and objects. All
+squares are lit and remembered.
+
+----------------------------------------------------------------------
+
+#####R=== wiz_dark ===
+
+#####GDeclaration
+ extern void wiz_dark(void);
+
+#####GFile
+ cave.c
+
+#####GComment
+/*
+ * Forget the dungeon map (ala "Thinking of Maud...").
+ */
+
+#####GDescription
+Forget all grids and objects. All grids become dark.
+
+----------------------------------------------------------------------
+
+#####R=== lite_room ===
+
+#####GDeclaration
+ extern void lite_room(int y1, int x1);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Illuminate any room containing the given location.
+ */
+
+#####GDescription
+Light up the room (if any) of grid "y1,x1".
+
+#####GParameters
+> "y1" is the y-coordinate of the grid.
+> "x1" is the x-coordinate of the grid.
+
+----------------------------------------------------------------------
+
+#####R=== unlite_room ===
+
+#####GDeclaration
+ extern void unlite_room(int y1, int x1);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Darken all rooms containing the given location
+ */
+
+#####GDescription
+Darken all rooms (if any) of grid "y1,x1".
+
+#####GParameters
+> "y1" is the y-coordinate of the grid.
+> "x1" is the x-coordinate of the grid.
+
+----------------------------------------------------------------------
+
+#####R=== lite_area ===
+
+#####GDeclaration
+ extern bool lite_area(int dam, int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Hack -- call light around the player
+ * Affect all monsters in the projection radius
+ */
+
+#####GDescription
+Light up the room (if any) of the player's grid. Monsters take "dam"
+points of GF_LITE_WEAK damage if they are within "r" grids of the
+player.
+
+#####GParameters
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage.
+
+----------------------------------------------------------------------
+
+#####R=== unlite_area ===
+
+#####GDeclaration
+ extern bool unlite_area(int dam, int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Hack -- call darkness around the player
+ * Affect all monsters in the projection radius
+ */
+
+#####GDescription
+Darken the room (if any) of the player's grid. Monsters take "dam"
+points of GF_DARK_WEAK damage if they are within "r" grids of the
+player.
+
+#####GParameters
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_ball_beam ===
+
+#####GDeclaration
+ extern bool fire_ball_beam(int typ, int dir, int dam,
+ int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a ball-beamed spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+
+#####GDescription
+Cast a ball-beamed spell of type "typ" in direction "dir" for damage
+"dam" points with a radius of "rad" grids.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage (must be <= 16).
+
+----------------------------------------------------------------------
+
+#####R=== fire_ball ===
+
+#####GDeclaration
+ extern bool fire_ball(int typ, int dir, int dam, int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a ball spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+
+#####GDescription
+Cast a ball spell of type "typ" in direction "dir" for "dam" points of
+damage. The ball has a radius of "rad" grids.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage (must be <= 16).
+
+----------------------------------------------------------------------
+
+#####R=== fire_bolt ===
+
+#####GDeclaration
+ extern bool fire_bolt(int typ, int dir, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a bolt spell
+ * Stop if we hit a monster, as a "bolt"
+ * Affect monsters (not grids or objects)
+ */
+
+#####GDescription
+Cast a bolt spell of type "typ" in direction "dir" for "dam" points of
+damage.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_beam ===
+
+#####GDeclaration
+ extern bool fire_beam(int typ, int dir, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a beam spell
+ * Pass through monsters, as a "beam"
+ * Affect monsters (not grids or objects)
+ */
+
+#####GDescription
+Cast a beam spell of type "typ" in direction "dir" for "dam" points of
+damage.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_druid_ball ===
+
+#####GDeclaration
+ extern bool fire_druid_ball(int typ, int dir, int dam,
+ int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a druidic ball spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+
+#####GDescription
+Cast a ball spell of type "typ" in direction "dir" for "dam" points of
+damage. The ball has a radius of "rad" grids. The spell follows a mana
+path.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage (must be <= 16).
+
+----------------------------------------------------------------------
+
+#####R=== fire_druid_bolt ===
+
+#####GDeclaration
+ extern bool fire_druid_bolt(int typ, int dir, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a druidic bolt spell
+ * Stop if we hit a monster, as a "bolt"
+ * Affect monsters (not grids or objects)
+ */
+
+#####GDescription
+Cast a bolt spell of type "typ" in direction "dir" for "dam" points of
+damage. The spell follows a mana path.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_druid_beam ===
+
+#####GDeclaration
+ extern bool fire_druid_beam(int typ, int dir, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a druidistic beam spell
+ * Pass through monsters, as a "beam"
+ * Affect monsters (not grids or objects)
+ */
+
+#####GDescription
+Cast a beam spell of type "typ" in direction "dir" for "dam" points of
+damage. The spell follows a mana path.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_bolt_or_beam ===
+
+#####GDeclaration
+ extern bool fire_bolt_or_beam(int prob, int typ, int dir,
+ int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a bolt spell, or rarely, a beam spell
+ */
+
+#####GDescription
+Cast a beam (chance of "prob" in 100) or bolt spell of type "typ" in
+direction "dir" for "dam" points of damage.
+
+#####GParameters
+> "prob" is the number of times out of 100 that the bolt will actually
+ be a beam. Obviously this value should range from 1 to 99 (0 will
+ always give a beam, 100 or higher will always give a beam. There are
+ separate functions for these cases).
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== alchemy ===
+
+#####GDeclaration
+ extern bool alchemy(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/* Turns an object into gold, gain some of its value in a shop */
+
+#####GDescription
+The player selects an object (and quantity if it applies) from the
+inventory or the floor and attempts to turn it into gold. If the
+price of the item is < 0 then the player gains nothing (fool's gold),
+otherwise the player gets a third of the price in gold. Artifacts are
+not affected.
+
+----------------------------------------------------------------------
+
+#####R=== alter_reality ===
+
+#####GDeclaration
+ extern void alter_reality(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+The player leaves the level immediately.
+
+----------------------------------------------------------------------
+
+#####R=== teleport_swap ===
+
+#####GDeclaration
+ extern void teleport_swap(int dir);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Player swaps places with target in direction "dir". The target must be
+a monster. It will not work if the space-time continuum can not be
+disrupted or if the monster resists teleportation.
+
+----------------------------------------------------------------------
+
+#####R=== project_meteor ===
+
+#####GDeclaration
+ extern void project_meteor(int radius, int typ, int dam,
+ u32b flg);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Apply a "project()" a la meteor shower
+ */
+
+#####GDescription
+Generate between "rad" and "rad" x 2 ball spells of type "typ" for
+"dam" points of damage. The ball can have various properties as
+denoted by "flg".
+
+#####GParameters
+> "rad" is the minimum number of balls created. "rad" + randint("rad")
+ balls are created. Each ball has a radius of 2 grids. Each target
+ grid is within 5 grids of the player.
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dam" is the number of points of damage.
+> "flg" is the projection effect
+ *****fields.txt*0[PROJECT_fields]
+
+----------------------------------------------------------------------
+
+#####R=== passwall ===
+
+#####GDeclaration
+ extern bool passwall(int dir, bool safe);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Send the player shooting through walls in the given direction until
+ * they reach a non-wall space, or a monster, or a permanent wall.
+ */
+
+#####GDescription
+Move the player through walls in direction "dir". if "safe" then the
+player can not end up in a wall - if they do, the wall is replaced by
+a floor. This does not work in the wilderness, on quest levels, or if
+teleport is not allowed. Stopping on monsters or inside vaults is not
+allowed.
+
+#####GParameters
+> "dir" must be from 0 to 9. It can not be 5.
+ *****fields.txt*0[direction]
+> "safe" must be true if the player is not to be trapped in a wall
+ when the movement is finished.
+
+----------------------------------------------------------------------
+
+#####R=== project_hook ===
+
+#####GDeclaration
+ extern bool project_hook(int typ, int dir, int dam,
+ int flg);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Hack -- apply a "projection()" in a direction (or at the target)
+ */
+
+#####GDescription
+Generate a beam/bolt of type "typ" in direction "dir" (or at a target)
+for "dam" points of damage. The beam/bolt can have various properties
+as denoted by "flg".
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9. 5 means use the current target.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+> "flg" is the projection effect
+ *****fields.txt*0[PROJECT_fields]
+
+----------------------------------------------------------------------
+
+#####R=== reset_recall ===
+
+#####GDeclaration
+ extern bool reset_recall(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Ask the player for a dungeon and appropriate level within the dungeon.
+The player can not specify a dungeon they have not gone to yet. If the
+player chooses levels 99 or 100, the level is set to 98.
+
+----------------------------------------------------------------------
+
+#####R=== get_aim_dir ===
+
+#####GDeclaration
+ extern bool get_aim_dir(int *dp = 0);
+
+#####GFile
+ xtra2.c
+
+#####GComment
+/*
+ * Get an "aiming direction" from the user.
+ *
+ * The "dir" is loaded with 1,2,3,4,6,7,8,9 for "actual direction", and
+ * "0" for "current target", and "-1" for "entry aborted".
+ *
+ * Note that "Force Target", if set, will pre-empt user interaction,
+ * if there is a usable target already set.
+ *
+ * Note that confusion over-rides any (explicit?) user choice.
+ */
+
+#####GDescription
+Get an aiming direction from the user and store it in "dp". A target
+can be selected. If the player is confused, the direction will be
+random.
+
+#####GParameters
+> "dp" = player direction.
+
+----------------------------------------------------------------------
+
+#####R=== project_hack ===
+
+#####GDeclaration
+ extern bool project_hack(int typ, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Apply a "project()" directly to all viewable monsters
+ *
+ * Note that affected monsters are NOT auto-tracked by this usage.
+ */
+
+#####GDescription
+Generate beam/bolt spells of type "typ" for "dam" points of damage to
+all viewable monsters in line of site.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+
+Back to the *****lua.hlp*0[lua help index] .
+
+ [[[[[gThis file by Chris Hadgis]
diff --git a/lib/help/lua_util.txt b/lib/help/lua_util.txt
new file mode 100644
index 00000000..8886a2b4
--- /dev/null
+++ b/lib/help/lua_util.txt
@@ -0,0 +1,898 @@
+|||||oy
+
+#####R /----------------------------------------\
+#####R < util.pkg functions helper file >
+#####R \----------------------------------------/
+
+----------------------------------------------------------------------
+
+#####R=== bst ===
+
+#####GDeclaration
+ s32b bst(s32b what, s32b t);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Break scalar time
+ */
+
+#####GDescription
+Return the minute, hour, day, or year for turn "t". One turn takes 7.5
+seconds.
+
+#####GParameters
+> "what" is the unit to be returned and must be one of
+ MINUTE (number of turns per minute, which is 8)
+ HOUR (number of turns per hour, which is 480)
+ DAY (number of turns per day, which is 11,520)
+ YEAR (number of turns per year, which is 4,204,800)
+> "t" is the number of turns.
+
+----------------------------------------------------------------------
+
+#####R=== path_build ===
+
+#####GDeclaration
+ errr path_build(char *buf, int max, cptr path, cptr file);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Create a new path by appending a file (or directory) to a path
+*
+* This requires no special processing on simple machines, except
+* for verifying the size of the filename, but note the ability to
+* bypass the given "path" with certain special file-names.
+*
+* Note that the "file" may actually be a "sub-path", including
+* a path and a file.
+*
+* Note that this function yields a path which must be "parsed"
+* using the "parse" function above.
+*/
+
+#####GDescription
+Append file "file" to path "path" and return the result in "buf". The
+length of "buf" is a maximum of "max" characters. If "file" starts
+with '~' then return "file". If "file" starts with the path separator
+and the path separator is not blank then return "file". If there is no
+path then return "file". Otherwise return "path" + path separator +
+"file". The path separator is defined in "H-config.h".
+
+#####GParameters
+> "buf" contains the new path.
+> "max" is the maximum number of characters allowed in "buf".
+> "path" is the original path.
+> "file" is the original file.
+
+----------------------------------------------------------------------
+
+#####R=== move_cursor ===
+
+#####GDeclaration
+ void move_cursor(int row, int col);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Move the cursor
+*/
+
+#####GDescription
+Move the cursor to row "row" and column "col".
+
+#####GParameters
+> "row" is the row the cursor is to be moved to.
+> "col" is the column the cursor is to be moved to.
+
+----------------------------------------------------------------------
+
+#####R=== inkey ===
+
+#####GDeclaration
+ char inkey(void);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Get a keypress from the user.
+*
+* This function recognises a few "global parameters". These are variables
+* which, if set to TRUE before calling this function, will have an effect
+* on this function, and which are always reset to FALSE by this function
+* before this function returns. Thus they function just like normal
+* parameters, except that most calls to this function can ignore them.
+*
+* If "inkey_xtra" is TRUE, then all pending keypresses will be flushed,
+* and any macro processing in progress will be aborted. This flag is
+* set by the "flush()" function, which does not actually flush anything
+* itself, but rather, triggers delayed input flushing via "inkey_xtra".
+*
+* If "inkey_scan" is TRUE, then we will immediately return "zero" if no
+* keypress is available, instead of waiting for a keypress.
+*
+* If "inkey_base" is TRUE, then all macro processing will be bypassed.
+* If "inkey_base" and "inkey_scan" are both TRUE, then this function will
+* not return immediately, but will wait for a keypress for as long as the
+* normal macro matching code would, allowing the direct entry of macro
+* triggers. The "inkey_base" flag is extremely dangerous!
+*
+* If "inkey_flag" is TRUE, then we will assume that we are waiting for a
+* normal command, and we will only show the cursor if "hilite_player" is
+* TRUE (or if the player is in a store), instead of always showing the
+* cursor. The various "main-xxx.c" files should avoid saving the game
+* in response to a "menu item" request unless "inkey_flag" is TRUE, to
+* prevent savefile corruption.
+*
+* If we are waiting for a keypress, and no keypress is ready, then we will
+* refresh (once) the window which was active when this function was called.
+*
+* Note that "back-quote" is automatically converted into "escape" for
+* convenience on machines with no "escape" key. This is done after the
+* macro matching, so the user can still make a macro for "backquote".
+*
+* Note the special handling of "ascii 30" (ctrl-caret, aka ctrl-shift-six)
+* and "ascii 31" (ctrl-underscore, aka ctrl-shift-minus), which are used to
+* provide support for simple keyboard "macros". These keys are so strange
+* that their loss as normal keys will probably be noticed by nobody. The
+* "ascii 30" key is used to indicate the "end" of a macro action, which
+* allows recursive macros to be avoided. The "ascii 31" key is used by
+* some of the "main-xxx.c" files to introduce macro trigger sequences.
+*
+* Hack -- we use "ascii 29" (ctrl-right-bracket) as a special "magic" key,
+* which can be used to give a variety of "sub-commands" which can be used
+* any time. These sub-commands could include commands to take a picture of
+* the current screen, to start/stop recording a macro action, etc.
+*
+* If "angband_term[0]" is not active, we will make it active during this
+* function, so that the various "main-xxx.c" files can assume that input
+* is only requested (via "Term_inkey()") when "angband_term[0]" is active.
+*
+* Mega-Hack -- This function is used as the entry point for clearing the
+* "signal_count" variable, and of the "character_saved" variable.
+*
+* Hack -- Note the use of "inkey_next" to allow "keymaps" to be processed.
+*
+* Mega-Hack -- Note the use of "inkey_hack" to allow the "Borg" to steal
+* control of the keyboard from the user.
+*/
+
+#####GDescription
+Get a keypress from the user.
+
+----------------------------------------------------------------------
+
+#####R=== cmsg_print ===
+
+#####GDeclaration
+ void cmsg_print(byte color, cptr msg);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Output a message to the top line of the screen.
+*
+* Break long messages into multiple pieces (40-72 chars).
+*
+* Allow multiple short messages to "share" the top line.
+*
+* Prompt the user to make sure he has a chance to read them.
+*
+* These messages are memorised for later reference (see above).
+*
+* We could do "Term_fresh()" to provide "flicker" if needed.
+*
+* The global "msg_flag" variable can be cleared to tell us to
+* "erase" any "pending" messages still on the screen.
+*
+* XXX XXX XXX Note that we must be very careful about using the
+* "msg_print()" functions without explicitly calling the special
+* "msg_print(NULL)" function, since this may result in the loss
+* of information if the screen is cleared, or if anything is
+* displayed on the top line.
+*
+* XXX XXX XXX Note that "msg_print(NULL)" will clear the top line
+* even if no messages are pending. This is probably a hack.
+*/
+
+#####GDescription
+In color "color", output message "msg" to the top line of the screen.
+If the message is blank or has more than 1000 characters, nothing is
+printed. Long messages are split after the 40th character and before
+the 72nd character.
+
+#####GParameters
+> "color" is the color of the message.
+ *****fields.txt*0[colors]
+> "msg" is the message.
+
+----------------------------------------------------------------------
+
+#####R=== msg_print ===
+
+#####GDeclaration
+ void msg_print(cptr msg);
+
+#####GFile
+ util.c
+
+#####GComment
+/* Hack -- for compatibility and easy sake */
+
+#####GDescription
+Print message "msg" in white (see cmsg_print() above).
+
+#####GParameters
+> "msg" is the message.
+
+----------------------------------------------------------------------
+
+#####R=== screen_save ===
+
+#####GDeclaration
+ void screen_save(void);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Save the screen, and increase the "icky" depth.
+ *
+ * This function must match exactly one call to "screen_load()".
+ */
+
+#####GDescription
+Save a screen shot.
+
+----------------------------------------------------------------------
+
+#####R=== screen_load ===
+
+#####GDeclaration
+ void screen_load(void);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Load the screen, and decrease the "icky" depth.
+ *
+ * This function must match exactly one call to "screen_save()".
+ */
+
+#####GDescription
+Load a previously saved screen shot.
+
+----------------------------------------------------------------------
+
+#####R=== c_put_str ===
+
+#####GDeclaration
+ void c_put_str(byte attr, cptr str, int row, int col);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Display a string on the screen using an attribute.
+*
+* At the given location, using the given attribute, if allowed,
+* add the given string. Do not clear the line.
+*/
+
+#####GDescription
+Put string "str" at row "row" and column "col" with attribute "attr".
+
+#####GParameters
+> "attr" is the color of the message.
+ *****fields.txt*0[colors]
+> "msg" is the message.
+> "row" is the row the message is to be printed at.
+> "col" is the column the message is to be printed at.
+
+----------------------------------------------------------------------
+
+#####R=== c_prt ===
+
+#####GDeclaration
+ void c_prt(byte attr, cptr str, int row, int col);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Display a string on the screen using an attribute, and clear
+* to the end of the line.
+*/
+
+#####GDescription
+Clear row "row" from column "col". Put string "str" at "row", "col"
+with attribute "attr".
+
+#####GParameters
+> "attr" is the color of the message.
+ *****fields.txt*0[colors]
+> "msg" is the message.
+> "row" is the row the message is to be printed at.
+> "col" is the column the message is to be printed at.
+
+----------------------------------------------------------------------
+
+#####R=== clear_from ===
+
+#####GDeclaration
+ void clear_from(int row);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Clear part of the screen
+*/
+
+#####GDescription
+Clear the screen from row "row" onwards.
+
+#####GParameters
+> "row" is the first row of the screen to be cleared.
+
+----------------------------------------------------------------------
+
+#####R=== askfor_aux ===
+
+#####GDeclaration
+ bool askfor_aux(char *buf, int len);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Get some input at the cursor location.
+* Assume the buffer is initialized to a default string.
+* Note that this string is often "empty" (see below).
+* The default buffer is displayed in yellow until cleared.
+* Pressing RETURN right away accepts the default entry.
+* Normal chars clear the default and append the char.
+* Backspace clears the default or deletes the final char.
+* ESCAPE clears the buffer and the window and returns FALSE.
+* RETURN accepts the current buffer contents and returns TRUE.
+*/
+
+#####GDescription
+Get string "buf" from the screen. "buf" is to be no more than "len"
+bytes. The string starts at the current cursor position. The length
+can not exceed the number of bytes from the cursor to the end of the
+line. Accept user input until the escape or return key is pressed.
+
+#####GParameters
+> "buf" is the string returned from the screen.
+> "len" is the length of the string. If it is <1 it is forced to 1.
+
+----------------------------------------------------------------------
+
+#####R=== get_string ===
+
+#####GDeclaration
+ bool get_string(cptr prompt, char *buf, int len);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Get a string from the user
+*
+* The "prompt" should take the form "Prompt: "
+*
+* Note that the initial contents of the string is used as
+* the default response, so be sure to "clear" it if needed.
+*
+* We clear the input, and return FALSE, on "ESCAPE".
+*/
+
+#####GDescription
+Print prompt "prompt" at the top-left corner of the screen and return
+response "buf" which will have a maximum length "length". If ESCAPE
+is entered, the function returns FALSE, otherwise it returns TRUE.
+
+#####GParameters
+> "prompt" is the prompt for input.
+> "buf" is the returned response.
+> "len" is the maximum length of the string.
+
+----------------------------------------------------------------------
+
+#####R=== get_check ===
+
+#####GDeclaration
+ bool get_check(cptr prompt);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Verify something with the user
+*
+* The "prompt" should take the form "Query? "
+*
+* Note that "[y/n]" is appended to the prompt.
+*/
+
+#####GDescription
+Ask the user question "prompt" which requires a yes/no answer. The
+prompt appears in the top-left corner of the screen. A response of
+'Y' (either case) returns TRUE. A response of 'N' (either case) or
+ESCAPE returns FALSE.
+
+#####GParameters
+> "prompt" is the question asked. It has a maximum length of 70
+ characters.
+
+----------------------------------------------------------------------
+
+#####R=== get_com_lua ===
+
+#####GDeclaration
+ bool get_com_lua @ get_com(cptr promtp, int *com);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Prompts for a keypress
+*
+* The "prompt" should take the form "Command: "
+*
+* Returns TRUE unless the character is "Escape"
+*/
+
+#####GDescription
+Ask the user for command "prompt" and return the key press "com". A
+response of ESCAPE returns FALSE. All other responses return TRUE.
+
+#####GParameters
+> "prompt" is the prompt for the key press.
+> "com" is the returned key press.
+
+----------------------------------------------------------------------
+
+#####R=== get_quantity ===
+
+#####GDeclaration
+ s32b get_quantity(cptr prompt, s32b max);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Request a "quantity" from the user
+*
+* Hack -- allow "command_arg" to specify a quantity
+*/
+
+#####GDescription
+Ask the user for quantity "prompt" of maximum value "max" and return
+a quantity. If the user quantity is higher than the maximum then the
+maximum is returned. If the response is a letter then the maximum is
+returned. If the user quantity is negative then zero is returned.
+
+#####GParameters
+> "prompt" is the prompt for a quantity.
+> "max" is the maximum value allowed.
+
+----------------------------------------------------------------------
+
+#####R=== test_monster_name ===
+
+#####GDeclaration
+ int test_monster_name(cptr name);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Given monster name as string, return the index in r_info array. Name
+ * must exactly match (look out for commas and the like!), or else 0 is
+ * returned. Case doesn't matter. -GSN-
+ */
+
+#####GDescription
+Return the monster index for monster with name "name". If no match is
+found then zero is returned.
+
+#####GParameters
+> "name" is the monster name.
+
+----------------------------------------------------------------------
+
+#####R=== test_item_name ===
+
+#####GDeclaration
+ int test_item_name(cptr name);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Given item name as string, return the index in k_info array. Name
+ * must exactly match (look out for commas and the like!), or else 0 is
+ * returned. Case doesn't matter. -DG-
+ */
+
+#####GDescription
+Return the item index for item with name "name". If no match is found
+then zero is returned.
+
+#####GParameters
+> "name" is the item name.
+
+----------------------------------------------------------------------
+
+#####R=== luck ===
+
+#####GDeclaration
+ int luck(int min, int max);
+
+#####GFile
+ xtra1.c
+
+#####GComment
+/*
+ * Return a luck number between a certain range
+ */
+
+#####GDescription
+Return a number for luck between minimum "min" and maximum "max". The
+value begins with the player's current luck. The value is forced to
+be between -30 and +30. 30 is added to give a value between 0 and 60.
+The value is multiplied by the range (maximum - minimum) and divided
+by 60. The value is increased by the minimum. The value is returned.
+
+For example, if the player's current luck is 15, the minimum is -10,
+and the maximum is 10 (range 20), then the value returned is
+(45 * 20) / 60 which is 900 / 60 which is 15 + the minimum -10 gives
+a returned value of 5.
+
+#####GParameters
+> "min" is the minimum luck.
+> "max" is the maximum luck. Beware: this should be greater than the
+ minimum but it is not checked!
+
+----------------------------------------------------------------------
+
+#####R=== get_player_race_name ===
+
+#####GDeclaration
+ cptr get_player_race_name(int pr, int ps);
+
+#####GFile
+ util.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the name for player race "pr" and player sub-race "ps".
+
+#####GParameters
+> "pr" is the index for player race.
+> "ps" is the index for player sub-race.
+
+----------------------------------------------------------------------
+
+#####R=== quit ===
+
+#####GDeclaration
+ void quit(cptr str);
+
+#####GFile
+ z-util.c
+
+#####GComment
+/*
+ * Exit (ala "exit()"). If 'str' is NULL, do "exit(0)".
+ * If 'str' begins with "+" or "-", do "exit(atoi(str))".
+ * Otherwise, plog() 'str' and exit with an error code of -1.
+ * But always use 'quit_aux', if set, before anything else.
+ */
+
+#####GDescription
+Quit the game. If "str" is a string then write the string to the
+error file or screen. If "str" is a number then exit with the
+number as the exit code.
+
+#####GParameters
+> "str" is an error message or exit code.
+
+----------------------------------------------------------------------
+
+#####R=== dump_hooks ===
+
+#####GDeclaration
+ void dump_hooks();
+
+#####GFile
+ plots.c
+
+#####GComment
+(none)
+
+#####GDescription
+Print the name and type (C or Lua) of hooks in the hook list.
+
+----------------------------------------------------------------------
+
+#####R=== add_hook_script ===
+
+#####GDeclaration
+ void add_hook_script(int h_idx, char *script, cptr name);
+
+#####GFile
+ plots.c
+
+#####GComment
+(none)
+
+#####GDescription
+To hook list with index "h_idx", add a script with script file
+"script" and name "name" as a Lua hook if a hook with that name
+does not already exist.
+
+#####GParameters
+> "h_idx" is the index of the hook list in the array of hook lists.
+> "script" is the name of the script file.
+> "name" is the name of the hook to be added.
+
+----------------------------------------------------------------------
+
+#####R=== del_hook_name ===
+
+#####GDeclaration
+ void del_hook_name(int h_idx, cptr name);
+
+#####GFile
+ plots.c
+
+#####GComment
+(none)
+
+#####GDescription
+Search hook list with index "h_idx" and remove the hook with name
+"name".
+
+#####GParameters
+> "h_idx" is the index of the hook list in the array of hook lists.
+> "name" is the name of the hook to be removed.
+
+----------------------------------------------------------------------
+
+#####R=== pern_dofile ===
+
+#####GDeclaration
+ bool pern_dofile(char *file);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Parse the Lua script file "file".
+
+#####GParameters
+> "file" is the Lua script file to be parsed.
+
+----------------------------------------------------------------------
+
+#####R=== intMod ===
+
+#####GDeclaration
+ s32b intMod(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of operation "a" mod "b" (a % b).
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intAnd ===
+
+#####GDeclaration
+ s32b intAnd(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" AND "b" (a & b).
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intOr ===
+
+#####GDeclaration
+ s32b intOr(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" OR "b" (a | b).
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intXor ===
+
+#####GDeclaration
+ s32b intXor(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" XOR "b" (a ^ b).
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intShiftl ===
+
+#####GDeclaration
+ s32b intShiftl(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" << "b".
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intShiftr ===
+
+#####GDeclaration
+ s32b intShiftr(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" >> "b".
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intBitNot ===
+
+#####GDeclaration
+ s32b intBitNot(s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation NOT "b" (~ b).
+
+#####GParameters
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== register_savefile ===
+
+#####GDeclaration
+ void register_savefile(int num);
+
+#####GFile
+ loadsave.c
+
+#####GComment
+/*
+ * Add num slots to the savefile
+ */
+
+#####GDescription
+Add "num" slots to the save file.
+
+#####GParameters
+> "num" is the number of slots to add to the savefile. If num is <0
+ then "num" is forced to zero.
+
+----------------------------------------------------------------------
+
+#####R=== save_number_key ===
+
+#####GDeclaration
+ void save_number_key(char *key, s32b val);
+
+#####GFile
+ util.c
+
+#####GComment
+(none)
+
+#####GDescription
+Save the length of key "key", the key itself, and the value "val" as
+bytes in the savefile.
+
+#####GParameters
+> "key" is the key string for the value.
+> "val" is the value to be saved.
+
+----------------------------------------------------------------------
+
+
+
+Back to the *****lua.hlp*0[lua help index] .
+
+
+ [[[[[gThis file by Chris Hadgis]
+
diff --git a/lib/help/luckspoi.txt b/lib/help/luckspoi.txt
new file mode 100644
index 00000000..50466902
--- /dev/null
+++ b/lib/help/luckspoi.txt
@@ -0,0 +1,112 @@
+|||||oy
+~~~~~01|Luck (spoiler)
+~~~~~02|Spoilers|Luck
+#####RLuck
+
+"You've got to ask yourself one question: do I feel lucky? Well do ya
+punk?"
+ --Clint Eastwood (Dirty Harry)
+
+#####G1. Starting luck
+Most races start with no luck points. Those that start with luck are listed
+below from most luck to least luck.
+
+Hobbit (+5);
+Maia (+4);
+Gnome, Dunadan, Thunderlord (+2);
+Beorning (+1);
+Half-Ogre, Dark Elf, Ent (-2);
+Orc (-3);
+Troll (-4);
+Petty Dwarf, DeathMold, Yeek (-5).
+
+Most subraces start with no luck points. Those that start with luck are listed
+below from most luck to least luck.
+
+Barbarian (+1);
+Spectre, Skeleton (-3);
+Zombie (-4).
+
+So, a Hobbit starts with 5 luck points, a Beorning Barbarian starts with 2 luck
+points, while a Yeek Zombie starts with -9 luck points.
+
+#####G2. Descriptions
+Drinking a potion of self-knowledge will tell you how lucky or unlucky your
+character is.
+
+DESCRIPTION VALUE
+incredibly unlucky less than -27
+extremely unlucky less than -18
+very unlucky less than -9
+unlucky less than 0
+normal luck 0
+lucky more than 0
+very lucky more than 9
+extremely lucky more than 18
+incredibly lucky more than 27
+
+Luck < -30 is treated as -30 and luck > 30 is treated as +30.
+
+#####G3. Items affecting luck
+Elven cloaks give a bonus to luck.
+
+Only one type of ego item is lucky, or perhaps that should be unlucky.
+All Morgul items have -10 luck.
+
+Artifacts can affect your luck. Beware: not all artifacts give you good luck.
+Listed below are the artifacts which affect your luck.
+
+The Phial of Galadriel (+4)
+The Arkenstone of Thrain (+3)
+The Ring of Power 'Narya' (+1)
+The Ring of Power 'Nenya' (+2)
+The Ring of Power 'Vilya' (+3)
+The Metal Cap of Thengel (+3)
+The Shadow Cloak of Luthien (+2)
+The Set of Cesti of Fingolfin (+4)
+The Long Sword 'Anduril' (+4)
+The Long Bow of Bard (+2)
+The Mage Staff of Eternity (+12)
+The Harp of Maglor (+3)
+The Drum of the Sky (+2)
+The Harp of Daeron (+1)
+The Long Sword of Eternity (+10)
+The Robe of Great Luck (+60)
+The Heavy Crossbow of Eternity (+5)
+The Iron Helm of Knowledge (-6)
+The Shield of Deflection of Gil-galad (+5)
+The Set of Gauntlets of Eol (+3)
+The Demonblade of Gothmog (-20)
+The Long Sword 'Durandil' (+3)
+The Phial of Undeath (-5)
+The Ring of Phasing (+15)
+The Blue Stone 'Toris Mejistos' (+2)
+The Silver Bolt 'Stone-biter' (+3)
+The Elven Cloak of Mellyrn (+4)
+The Set of Cesti 'Skycleaver' (+1)
+
+#####G4. What does it affect.
+It affects your chance to-hit in ranged combat and melee combat.
+
+It affects your chance of critical hits in ranged combat and melee combat.
+
+It affects your chance of being missed by a monster attack. This effectively
+changes armour class by -13 (incredibly unlucky) to +13 (incredibly lucky).
+
+It affects the rarity of special objects, artifacts, and ego items.
+
+It affects the number of wishes on a staff of wishing.
+
+It affects the base level for applying magic to an item.
+
+It affects the chance of an item being good or great.
+
+It affects the chance of creating a special object.
+
+It prevents the death fate if you are lucky.
+
+It affects the number of skill points you receive when quaffing the Potion of
+Learning.
+
+
+ Written for ToME 2.0 by Chris Hadgis
diff --git a/lib/help/m_air.txt b/lib/help/m_air.txt
new file mode 100644
index 00000000..ee9fa8d0
--- /dev/null
+++ b/lib/help/m_air.txt
@@ -0,0 +1,42 @@
+|||||oy
+~~~~~01|Magic|Air School
+~~~~~02|Air Magic
+~~~~~03|Skills|Air - Spell Info
+#####R === ToME Magic - Air School ===
+
+The air school of magic contains spells where the element of air is used
+to create the final spell effect. There are rumours of a "Tome of the Blowing
+Wind" which contains all the air school spells within its bindings.
+
+Worshipping the God Manwe Sulimo also gives the ability to cast spells from
+the air school at a level of 2/3 of your prayer level. E.g. if the skill
+"Spirituality: Prayer" is at level 12, you can cast up to level 8 air school
+spells.
+
+#####BAir Spells
+There are six spells available for the air school. These spells are:
+1. [[[[[BNoxious Cloud] (school level 3)
+ Creates a cloud of poison.
+ The cloud will persist for some turns, damaging all monsters passing by.
+ At spell level 30 it turns into a thick gas attacking all living beings.
+2. [[[[[BPoison Blood] (school level 12)
+ Grants resist poison.
+ At spell level 15 it provides poison branding to the wielded weapon.
+3. [[[[[BInvisibility] (school level 16)
+ Grants invisibility.
+4. [[[[[BSterilize] (school level 20)
+ Prevents explosive breeding for a while.
+5. [[[[[BWings of Winds] (dual school level 22)
+ Grants the power of levitation.
+ At spell level 16 it grants the power of controlled flight.
+#####v Your Air and Conveyance skills must have reached a combined average level
+#####v of 22 in order to cast this spell.
+6. [[[[[BThunderstorm] (dual school level 25)
+ Charges up the air around you with electricity.
+ Each turn it will throw a bolt of thunder at a random monster in sight.
+ This thunder does 3 types of damage:
+ one third of lightning
+ one third of sound
+ and one third of light.
+#####v Your Air and Nature skills must have reached a combined average level
+#####v of 25 in order to cast this spell.
diff --git a/lib/help/m_convey.txt b/lib/help/m_convey.txt
new file mode 100644
index 00000000..91ed8556
--- /dev/null
+++ b/lib/help/m_convey.txt
@@ -0,0 +1,71 @@
+|||||oy
+~~~~~01|Magic|Conveyance School
+~~~~~02|Conveyance Magic
+~~~~~03|Skills|Conveyance - Spell Info
+#####R === ToME Magic - Conveyance School ===
+
+The conveyance school of magic contains spells where the forces of space are
+manipulated by the spell. There are rumours of a "Tome of of Translocation"
+which contains all the conveyance school spells within its bindings.
+
+Worshipping the God Manwe Sulimo also gives the ability to cast spells from
+the conveyance school at a level of 1/2 of your prayer level. E.g. if the
+skill "Spirituality: Prayer" is at level 10, you can cast up to level 5
+conveyance school spells.
+
+#####sConveyance Spells
+There are six spells available for the conveyance school. These Spells are:
+1. [[[[[sPhase Door] (school level 1)
+ Teleports you on a small scale range.
+ At spell level 30 it creates void jumpgates.
+2. [[[[[sDisarm] (school level 3)
+ Destroys doors and disarms traps in adjacent tiles.
+ At spell level 10 it unlocks doors and disarms traps.
+3. [[[[[sTeleportation] (school level 10)
+ Teleports you around the level.
+ The casting time decreases with level.
+4. [[[[[sTeleport Away] (school level 23)
+ Teleports a line of monsters away.
+ At spell level 10 it turns into a ball.
+ At spell level 20 it teleports all monsters in sight.
+5. [[[[[sRecall] (school level 30)
+ Cast on yourself, it will recall you to the surface/dungeon.
+ Cast at a monster, it will make you swap positions with the monster.
+ Cast at an object, it will fetch the object to you (note that you must have
+ an empty space under your feet for the object to fall onto).
+6. [[[[[sProbability Travel] (school level 35)
+ Renders you unstable. When you hit a wall you travel through it and
+ instantly appear on the other side of it. You can also float up and down
+ at will.
+
+#####GAir spells that can be cast with Conveyance skill
+
+1. [[[[[BWings of Winds] (dual school level 22)
+ Grants the power of levitation.
+ At spell level 16 it grants the power of controlled flight.
+#####v Your Air and Conveyance skills must have reached a combined average level
+#####v of 22 in order to cast this spell.
+
+#####GTemporal spells that can be cast with Conveyance skill
+
+1. [[[[[sBanishment] (dual school level 30)
+ Disrupts the space/time continuum in your area and teleports all monsters
+ away.
+ At spell level 15 it also may lock them in a time bubble for some turns.
+#####v Your Temporal and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+
+#####GMeta spells that can be cast with Conveyance skill
+
+1. [[[[[sTracker] (dual school level 30)
+ Tracks down the last teleportation that happened on the level and teleports
+ you to it.
+#####v Your Meta and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+
+#####GUdun spells that can be cast with Conveyance skill
+
+1. [[[[[DWraithform] (dual school level 30)
+ Turns you temporarily into an immaterial being.
+#####v Your Udun and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
diff --git a/lib/help/m_demono.txt b/lib/help/m_demono.txt
new file mode 100644
index 00000000..cb32d360
--- /dev/null
+++ b/lib/help/m_demono.txt
@@ -0,0 +1,44 @@
+|||||oy
+~~~~~01|Magic|Demonology School
+~~~~~02|Demonology Magic
+~~~~~03|Skills|Demonology - Spell Info
+#####R === ToME Magic - Demonology ===
+
+Available only to Demonologists, or those sufficiently corrupted with
+demon-like powers, this school contains spells where demonic energies
+are used to create mainly devastating effects.
+
+#####oDemonic equipment
+Unlike other magic schools, the spells of a Demonologist are not written
+in spell books, but are contained within items of demonic origin known as
+Demonblades, Demonshields, and Demonhorns (helms), which when wielded allow
+the Demonologist to cast spells; each piece of equipment holds three spells.
+
+#####oDemonblade spells
+1. [[[[[oDemon Blade] (school level 1)
+ Imbues your blade with fire to deal more damage.
+ At level 30 it deals hell fire damage.
+ At level 45 it spreads over a 1 radius zone around your target.
+2. [[[[[oDemon Madness] (school level 10)
+ Fire 2 balls in opposite directions of randomly chaos, confusion or charm.
+3. [[[[[oDemon Field] (school level 20)
+ Fires a lingering cloud of deadly nexus over a radius of 7.
+
+#####oDemonshield spells
+1. [[[[[oDoom Shield] (school level 1)
+ Raises a mirror of pain around you, doing very high damage to your foes
+ that dare hit you, but greatly reduces your armour class.
+2. [[[[[oDemon Cloak] (school level 20)
+ Raises a mirror that can reflect bolts and arrows for a time.
+3. [[[[[oUnholy Word] (school level 25)
+ Kills a pet to heal you. There is a chance that the pet won't die but will
+ turn against you. This chance will decrease with higher spell levels.
+
+#####oDemonhorn spells
+1. [[[[[oSummon Demon] (school level 5)
+ Summons a leveled demon to your side.
+ At level 35 it summons a high demon.
+2. [[[[[oDischarge Minion] (school level 10)
+ The targeted pet will explode in a burst of gravity.
+3. [[[[[oControl Demon] (school level 25)
+ Attempts to control a demon.
diff --git a/lib/help/m_divin.txt b/lib/help/m_divin.txt
new file mode 100644
index 00000000..9d3455fc
--- /dev/null
+++ b/lib/help/m_divin.txt
@@ -0,0 +1,37 @@
+|||||oy
+~~~~~01|Magic|Divination School
+~~~~~02|Divination Magic
+~~~~~03|Skills|Divination - Spell Info
+#####R === ToME Magic - Divination School ===
+
+The divination school of magic contains spells where magic is used to
+psychically gain information about things. There are rumours of a "Tome of
+Knowledge" which contains all the divination school spells within its bindings.
+
+Worshipping the God Eru Iluvatar also gives the ability to cast spells from
+the divination school at a level of 2/3 of your prayer level. E.g. if the
+skill "Spirituality: Prayer" is at level 12, you can cast up to level 8
+divination school spells.
+
+#####sDivination Spells
+There are six spells available for the divination school. These Spells are:
+1. [[[[[sSense Monsters] (school level 1)
+ Detects all monsters near you.
+ At spell level 30 it allows you to sense monster minds for a while.
+2. [[[[[sSense Hidden] (school level 5)
+ Detects the traps in a certain radius around you.
+ At spell level 15 it allows you to sense invisible monsters for a while.
+3. [[[[[sIdentify] (school level 8)
+ Asks for an object and identifies it.
+ At spell level 17 it identifies all objects in the inventory.
+ At spell level 27 it identifies all objects in the inventory and in a
+ radius on the floor, as well as probing monsters in that radius.
+4. [[[[[sReveal Ways] (school level 9)
+ Detects the doors/stairs/ways in a certain radius around you.
+5. [[[[[sVision] (school level 15)
+ Detects the layout of the surrounding area.
+ At spell level 25 it maps and lights the whole level.
+6. [[[[[sGreater Identify] (school level 35)
+ Asks for an object and fully identifies it, providing the full list of
+ powers (as with a scroll of *Identify*).
+ Cast at yourself, it will reveal your powers (Self Knowledge).
diff --git a/lib/help/m_earth.txt b/lib/help/m_earth.txt
new file mode 100644
index 00000000..9c5623c3
--- /dev/null
+++ b/lib/help/m_earth.txt
@@ -0,0 +1,35 @@
+|||||oy
+~~~~~01|Magic|Earth School
+~~~~~02|Earth Magic
+~~~~~03|Skills|Earth - Spell Info
+#####R === ToME Magic - Earth School ===
+
+The earth school of magic contains spells where the element of earth is used
+to create the final spell effect. There are rumours of a "Tome of the
+Impenetrable Earth" which contains all the earth school spells within its
+bindings.
+
+Worshipping the God Tulkas or the Goddess Yavanna Kementari also gives the
+ability to cast spells from the earth school, at a level of 4/5 or 1/2,
+respectively, of your prayer level. E.g. if the skill "Spirituality: Prayer"
+is at level 10, a worshipper of Tulkas can cast up to level 8 earth school
+spells, whereas a worshipper of Yavanna can cast up to level 5 earth school
+spells.
+
+#####uEarth Spells
+There are five spells available for the earth school. These Spells are:
+1. [[[[[uStone Skin] (school level 1)
+ Creates a shield of earth around you to protect you.
+ At spell level 25 it starts dealing damage to attackers.
+2. [[[[[uDig] (school level 12)
+ Digs a hole in a wall much faster than any shovels.
+3. [[[[[uStone Prison] (school level 25)
+ Creates a prison of walls around you.
+ At spell level 10 it allows you to target a monster.
+4. [[[[[uShake] (school level 27)
+ Creates a localised earthquake.
+ At spell level 10 it can be targeted at any location.
+5. [[[[[uStrike] (school level 30)
+ Creates a micro-ball of force that will push monsters backwards.
+ If the monster is caught near a wall, it'll be crushed against it.
+ At spell level 12 it turns into a ball of radius 1.
diff --git a/lib/help/m_fire.txt b/lib/help/m_fire.txt
new file mode 100644
index 00000000..7ddda433
--- /dev/null
+++ b/lib/help/m_fire.txt
@@ -0,0 +1,49 @@
+|||||oy
+~~~~~01|Magic|Fire School
+~~~~~02|Fire Magic
+~~~~~03|Skills|Fire - Spell Info
+#####R === ToME Magic - Fire School ===
+
+The fire school of magic contains spells where the element of fire is used
+to create the final spell effect. There are rumours of a "Tome of the Eternal
+Flame" which contains all the fire school spells within its bindings.
+
+#####RFire Spells
+There are five spells available for the fire school. These spells are:
+1. [[[[[RGlobe of Light] (school level 1)
+ Creates a globe of pure light.
+ At spell level 3 it starts damaging monsters.
+ At spell level 15 it starts creating a more powerful kind of light.
+2. [[[[[RFire Golem] (dual school level 7)
+ Creates a fiery golem and controls it.
+ During the control the available keylist is:
+ Movement keys: move the golem (depending on its speed it can move more
+ than one square).
+ , : pickup all items on the floor
+ d : drop all carried items
+ i : list all carried items
+ m : end the possession/use golem powers
+ Most of the other keys are disabled; you cannot interact with your
+ real body while controlling the golem.
+ But to cast the spell you will need a lantern or a wooden torch to create
+ the golem.
+#####v Your Fire and Mind skills must have reached a combined average level
+#####v of 7 in order to cast this spell.
+3. [[[[[RFireflash] (school level 10)
+ Conjures a ball of fire to burn your foes to ashes.
+ At spell level 20 it turns into a ball of holy fire.
+4. [[[[[RFirewall] (school level 15)
+ Creates a fiery wall to incinerate monsters stupid enough to attack you.
+ At spell level 6 it turns into a wall of hell fire.
+5. [[[[[RFiery Shield] (school level 20)
+ Creates a shield of fierce flames around you.
+ At spell level 8 it turns into a greater kind of flame that cannot be
+ resisted by your foes.
+
+
+#####GUdun spells that can be cast with Fire skill
+
+1. [[[[[DFlame of Udun] (dual school level 35)
+ Turns you temporarily into a powerful Balrog.
+#####v Your Fire and Udun skills must have reached a combined average level
+#####v of 35 in order to cast this spell.
diff --git a/lib/help/m_geoman.txt b/lib/help/m_geoman.txt
new file mode 100644
index 00000000..97c1ac1a
--- /dev/null
+++ b/lib/help/m_geoman.txt
@@ -0,0 +1,75 @@
+|||||oy
+~~~~~01|Magic|Geomancy
+~~~~~02|Geomancer|Geomancy spells
+~~~~~03|Skills|Geomancy - Spell Info
+#####R === ToME Magic - Geomancy ===
+Geomancy harnesses the power of nature to awesome effect. Therefore neither
+books nor light are necessary, and as the geomancers's skill increases, so do
+his powers over the elements of nature.
+
+Because Geomancy relies so heavily on the environment, you will need
+sufficient knowledge of the elemental skills (Earth, Air, Fire and Water) in
+order to cast some of the spells, and the exact effects of a spell often
+depend upon your levels in the elemental skills and your current surroundings.
+
+The powers are accessed using the 'm' key and then selecting 'Use Geomancy';
+they are cast with spell points, like normal spells, which can be increased
+as usual through the *****skills.txt*21[Magic] skill.
+
+1. [[[[[RCall] [[[[[GThe] [[[[[BElements] (Level 1) Cost:2
+ Randomly creates various elements around you.
+ The chance for each type of element is controlled by your level in the
+ corresponding skill.
+ At level 17 it can be targeted.
+
+2. [[[[[UChannel] [[[[[GElements] (Level 3) Cost:3
+ Draws on the caster's immediate environs to form an attack or other effect.
+ Grass/Flower heals.
+ Water creates water bolt attacks.
+ Ice creates ice bolt attacks.
+ Sand creates a wall of burning sand around you, but the wall is thick and
+ blinds you.
+ Lava creates fire bolt attacks.
+ Deep lava creates fire ball attacks.
+ Chasm creates darkness bolt attacks.
+ At Earth level 18, darkness becomes nether.
+ At Water level 8, water attacks become beams with a striking effect.
+ At Water level 12, ice attacks become balls of ice shards.
+ At Water level 18, water attacks push monsters back.
+ At Fire level 15, fire becomes hellfire.
+
+3. [[[[[RElemental] [[[[[BWave] (Level 15) Cost:15
+ Draws on an adjacent special square to project a slow-moving wave of that
+ element in that direction.
+ Abyss squares cannot be channeled into a wave.
+
+4. [[[[[UElemental] [[[[[RMinion] (Level 20) Cost:40
+ Summons a minion from a nearby element.
+ Walls can summon Earth elmentals, Xorns and Xarens.
+ Dark Pits can summon Air elementals, Ancient blue dragons, Great Storm Wyrms
+ and Sky Drakes.
+ Sandwalls and lava can summon Fire elementals and Ancient red dragons.
+ Icewalls and water can summon Water elementals, Water trolls and Water
+ demons.
+
+5. [[[[[GVaporize] (Level 4) Cost:3
+ Draws upon your immediate environs to form a cloud of damaging vapors.
+#####v You must have reached at least level 4 in the Air skill to cast this
+#####v spell.
+
+6. [[[[[UGeolysis] (Level 7) Cost:15
+ Burrows deeply and slightly at random into a wall, leaving behind tailings
+ of various different sorts of walls in the passage.
+#####v You must have reached at least level 7 in the Earth skill to cast this
+#####v spell.
+
+7. [[[[[BDripping Tread] (Level 10) Cost:15
+ Causes you to leave random elemental forms behind as you walk.
+#####v You must have reached at least level 10 in the Water skill to cast this
+#####v spell.
+
+8. [[[[[UGrow Barrier] (Level 12) Cost:30
+ Creates impassable terrain (walls, trees, etc.) around you.
+ At air level 20 it can be projected around another area.
+#####v You must have reached at least level 12 in the Earth skill to cast this
+#####v spell.
diff --git a/lib/help/m_mana.txt b/lib/help/m_mana.txt
new file mode 100644
index 00000000..d4634e0e
--- /dev/null
+++ b/lib/help/m_mana.txt
@@ -0,0 +1,39 @@
+|||||oy
+~~~~~01|Magic|Mana School
+~~~~~02|Mana Magic
+~~~~~03|Skills|Mana - Spell Info
+#####R === ToME Magic - Mana School ===
+
+The mana school of magic contains spells where the raw force of magic is used
+to create the final spell effect. There are rumours of a "Tome of Magical
+Energy" which contains all the mana school spells within its bindings.
+
+Worshipping the God Eru Iluvatar also gives the ability to cast spells from
+the mana school at a level of 1/2 of your prayer level. E.g. if the skill
+"Spirituality: Prayer" is at level 10, you can cast up to level 5 mana school
+spells.
+
+#####sMana Spells
+There are four spells available for the mana school. These spells are:
+1. [[[[[sManathrust] (school level 1)
+ Conjures up mana into a powerful bolt.
+ The damage is irresistible and will increase with spell level.
+2. [[[[[sRemove Curses] (school level 10)
+ Removes curses of worn objects.
+ At spell level 20, removes heavy curses.
+3. [[[[[sElemental Shield] (school level 20)
+ Provides resistance to the four basic elements.
+4. [[[[[sDisruption Shield] (school level 45)
+ Uses mana instead of hitpoints to take damage.
+ At spell level 5 switches to Globe of Invulnerability.
+ The spell breaks as soon as a melee, shooting, throwing or magical skill
+ action is attempted, and lasts only a short time otherwise.
+
+
+#####GUdun spells that can be cast with Mana skill
+
+1. [[[[[DDrain] (dual school level 1)
+ Drains the mana contained in wands, staves and rods to increase yours.
+#####v Your Mana and Udun skills must have reached a combined average level
+#####v of 1 in order to cast this spell.
+
diff --git a/lib/help/m_meta.txt b/lib/help/m_meta.txt
new file mode 100644
index 00000000..f5570a2a
--- /dev/null
+++ b/lib/help/m_meta.txt
@@ -0,0 +1,75 @@
+|||||oy
+~~~~~01|Magic|Meta School
+~~~~~02|Meta Magic
+~~~~~03|Skills|Meta - Spell Info
+#####R === ToME Magic - Meta School ===
+
+The meta school of magic contains spells where the raw forces of magic are
+manipulated by the spell. There are rumours of a "Tome of Meta Spells" which
+contains all the meta school spells within its bindings.
+
+Worshipping the God Manwe Sulimo also gives the ability to cast spells from
+the meta school at a level of 1/3 of your prayer level. E.g. if the skill
+"Spirituality: Prayer" is at level 15, you can cast up to level 5 meta school
+spells.
+
+#####sMeta Spells
+There are five spells available for the meta school. These spells are:
+1. [[[[[sRecharge] (school level 5)
+ Taps the ambient mana to recharge an object's power (charges or mana).
+2. [[[[[sDisperse Magic] (school level 15)
+ Dispels a lot of magic that can affect you, be it good or bad:
+ Spell Level 1: blindness and light.
+ Spell Level 5: confusion and hallucination.
+ Spell Level 10: speed (either bad or good) and light speed.
+ Spell Level 15: stunning, meditation and cuts.
+ Spell Level 20: heroism, super heroism, blessing, shields, fear, parasites
+ and mimicry.
+3. [[[[[sSpellbinder] (school level 20)
+ Stores spells in a trigger.
+ When the condition is met all spells fire off at the same time. This spell
+ takes a long time to cast so you are advised to prepare it in a safe area.
+ Also it will use the mana for the Spellbinder and the mana for the selected
+ spells.
+4. [[[[[sTracker] (dual school level 30)
+ Tracks down the last teleportation that happened on the level and teleports
+ you to it.
+#####v Your Meta and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+5. [[[[[sInertia Control] (school level 37)
+ Changes the energy flow of a spell to be continuously recasted at a given
+ interval. The inertia-controlled spell reduces your maximum mana by four
+ times its cost.
+
+#####R=== List of Controllable Spells ===
+ Armor of Fear
+ Banishment
+ Disperse Magic
+ Disruption Shield
+ Elemental Shield
+ Ent's Potion
+ Essence of Speed
+ Fiery Shield
+ Flame of Udun
+ Globe of Light
+ Grow Trees
+ Ice Storm
+ Invisibility
+ Phase Door
+ Poison Blood
+ Probability Travel
+ Recovery
+ Regeneration
+ Remove Curses
+ Reveal Ways
+ Sense Hidden
+ Sense Monsters
+ Shake
+ Stone Skin
+ Teleportation
+ Thunderstorm
+ Tidal Wave
+ Vapor
+ Vision
+ Wings of Winds
+ Wraithform
diff --git a/lib/help/m_mimic.txt b/lib/help/m_mimic.txt
new file mode 100644
index 00000000..79d39521
--- /dev/null
+++ b/lib/help/m_mimic.txt
@@ -0,0 +1,33 @@
+|||||oy
+~~~~~01|Magic|Mimicry
+~~~~~02|Mimic|Mimicry powers
+~~~~~03|Skills|Mimicry - mimicry powers
+#####R === ToME Magic - Mimicry ===
+Mimics can alter their form using special cloaks called cloaks of mimicry.
+Even though this ability can give them access to increased stats, regeneration,
+speed and resistances, there is always the risk of the shape-change going
+horribly wrong, turning the character into an abomination for some time.
+Also, you should keep in mind that any racial power or stat modifier is
+overridden during the shape-shift.
+
+As your mimicry skill increases, your character is less likely to spoil
+the transformation attempt and may even gain other powers, such as making
+his colouration match his surroundings (becoming in all respects invisible)
+or even stranger abilities... rumours abound about Tarka the Chameleon and
+her two pairs of boots of speed.
+
+The powers are accessed using the 'm' key and then selecting 'Use Mimicry';
+they are cast with spell points, like normal spells, which can be increased
+as usual through the *****skills.txt*21[Magic] skill.
+
+1. [[[[[sMimic] (Level 1) Cost:2
+ Allows you to mimic the creature whose cloak you are wearing for a time.
+2. [[[[[sInvisibility] (Level 10) Cost:6
+ Turns you invisible for a time.
+3. [[[[[sLegs Mimicry] (Level 25) Cost:20
+ Gives you an additional set of legs for a time.
+4. [[[[[sWall Mimicry] (Level 30) Cost:40
+ Allows you to move within walls, and [[[[[Bonly] walls, for a time.
+[[[[[v Be careful you don't get stuck in a wall when it runs out.]
+5. [[[[[sArms Mimicry] (Level 35) Cost:100
+ Gives you an additional set of arms for a time.
diff --git a/lib/help/m_mind.txt b/lib/help/m_mind.txt
new file mode 100644
index 00000000..b6c1196f
--- /dev/null
+++ b/lib/help/m_mind.txt
@@ -0,0 +1,49 @@
+|||||oy
+~~~~~01|Magic|Mind School
+~~~~~02|Mind Magic
+~~~~~03|Skills|Mind - Spell Info
+#####R === ToME Magic - Mind School ===
+
+The mind school of magic contains spells which alter the mind. There are
+rumours of a "Tome of the Mind" which contains all the mind school spells
+within its bindings.
+
+Worshipping the God Eru Iluvatar or the God Melkor Bauglir also gives the
+ability to cast spells from the mind school at a level of 1/3 of your prayer
+level. E.g. if the skill "Spirituality: Prayer" is at level 12, you can cast
+up to level 4 mind school spells.
+
+#####sMind Spells
+There are four spells available for the mind school. These spells are:
+1. [[[[[sCharm] (school level 1)
+ Tries to manipulate the mind of a monster to make it friendly.
+ At spell level 15 it turns into a ball.
+ At spell level 35 it affects all monsters in sight.
+2. [[[[[sConfuse] (school level 5)
+ Tries to manipulate the mind of a monster to confuse it.
+ At spell level 15 it turns into a ball.
+ At spell level 35 it affects all monsters in sight.
+3. [[[[[sArmor of Fear] (school level 10)
+ Creates a shield of pure fear around you. Any monster attempting to hit
+ you must save or flee.
+4. [[[[[sStun] (school level 15)
+ Tries to manipulate the mind of a monster to stun it.
+ At spell level 20 it turns into a ball.
+
+#####GFire spells that can be cast with Mind skill
+
+1. [[[[[RFire Golem] (school level 7)
+ Creates a fiery golem and controls it.
+ During the control the available keylist is:
+ Movement keys: move the golem (depending on its speed it can move more
+ than one square).
+ , : pickup all items on the floor
+ d : drop all carried items
+ i : list all carried items
+ m : end the possession/use golem powers
+ Most of the other keys are disabled; you cannot interact with your
+ real body while controlling the golem.
+ But to cast the spell you will need a lantern or a wooden torch to create
+ the golem.
+#####v Your Fire and Mind skills must have reached a combined average level
+#####v of 7 in order to cast this spell.
diff --git a/lib/help/m_mindcr.txt b/lib/help/m_mindcr.txt
new file mode 100644
index 00000000..4f420656
--- /dev/null
+++ b/lib/help/m_mindcr.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Magic|Mindcraft
+~~~~~02|Mindcrafter|Mindcraft powers
+~~~~~03|Skills|Mindcraft - Spell Info
+#####R === ToME Magic - Mindcraft ===
+Mindcrafting uses the power of the mind to cast its spells. Therefore neither
+books nor light are necessary, and as the mindcrafter's skill increases, so do
+the powers of his mind.
+
+The powers are accessed using the 'm' key and then selecting 'Use Mindcraft';
+they are cast with spell points, like normal spells, which can be increased
+as usual through the *****skills.txt*21[Magic] skill.
+
+1. [[[[[sPrecognition] (Level 1) Cost:1
+ Detects monster minds around you.
+ At level 5 it also detects traps.
+ At level 15 it also allows you to see invisible monsters for a time.
+ At level 20 it maps out the surrounding area.
+ At level 25 it gives you ESP for a time.
+ At level 30 it also detects objects and treasure.
+ At level 45 it fully shows the entire level.
+2. [[[[[sNeural blast] (Level 2) Cost:1
+ Fires a bolt or beam, to stun and damage monsters.
+3. [[[[[sMinor Displacement] (Level 3) Cost:2
+ Teleports you a short distance.
+ At level 25 it grants the ability to create void jumpgates.
+4. [[[[[sMajor Displacement] (Level 7) Cost:6
+ Teleports you a good distance.
+ At level 30 it also banishes the monsters around you.
+5. [[[[[sDomination] (Level 9) Cost:7
+ Attempts to dominate the minds of your foes, scaring them.
+ At level 30 it attempts to charm monsters.
+6. [[[[[sPulverise] (Level 11) Cost:7
+ Fires pure sound at your opponents, crushing their bodies.
+7. [[[[[sCharacter Armour] (Level 13) Cost:12
+ Raises a physical shield around your body.
+ At level 15 it also grants resistance to acid.
+ At level 20 it also grants resistance to fire.
+ At level 25 it also grants resistance to cold.
+ At level 30 it also grants resistance to electricity.
+ At level 35 it also grants resistance to poison.
+8. [[[[[sPsychometry] (Level 15) Cost:12
+ Senses the quality of an item.
+ At level 40 it identifies an item.
+9. [[[[[sMindwave] (Level 18) Cost:10
+ Blasts the minds of monsters close to you.
+ At level 25 it affect all monsters in line of sight.
+10.[[[[[sAdrenaline Channeling] (Level 23) Cost:15
+ Heals you, hastes you and cures you.
+11.[[[[[sPsychic Drain] (Level 25) Cost:10
+ Drains the life of your foes into your mana reserves.
+12.[[[[[sTelekinesis] (Level 28) Cost:20
+ Projects a wave of pure telekinetic force from your body, damaging and maybe
+ banishing monsters.
diff --git a/lib/help/m_music.txt b/lib/help/m_music.txt
new file mode 100644
index 00000000..0f84f08f
--- /dev/null
+++ b/lib/help/m_music.txt
@@ -0,0 +1,77 @@
+|||||oy
+~~~~~01|Magic|Music
+~~~~~02|Music
+~~~~~03|Skills|Music - Song Info
+#####R === ToME Spells - Music ===
+
+Musical songs can have powerful effects for those who have the ability to
+play instruments, chiefly *****c_bard.txt*0[Bards].
+
+In order to continue playing a song, mana is consumed each turn, until
+either the 'Stop Singing' song is sung, or the player's mana runs out.
+
+Each song, as well as having a school level like any other magic spell, also
+has a roman numeral following its name. The higher this number, the greater the
+craftmanship of the instrument required to play it.
+
+Each musical instrument has a value assigned to it as well, between 1 and 4. The
+higher the number, the better the craftmanship; hence it will be possible
+for the bard to play higher level songs only with more powerful instruments.
+E.g. a Harp(+1) will allow you to cast "Stop Singing(I)" and "Song of the
+Sun(I)". A Harp(+2) would allow you to sing those songs, as well as "Flow of
+Life(II)".
+
+There are 3 different types of instruments: Harps, Drums and Horns. Each type
+of instrument contains a different family of musical songs:
+
+
+#####vMusical Songs
+
+#####GAll Instruments
+1. [[[[[vStop Singing(I)] (school level 1)
+ Stops the current song, if any.
+
+#####GDrums
+1. [[[[[vHolding Pattern(I)] (school level 1)
+ Slows down all monsters listening the song.
+ Consumes mana each turn.
+2. [[[[[vIllusion Pattern(II)] (school level 5)
+ Tries to confuse all monsters listening the song.
+ Consumes mana each turn.
+3. [[[[[vStun Pattern(IV)] (school level 10)
+ Stuns all monsters listening to the song.
+ Consumes mana each turn.
+
+#####GHarps
+1. [[[[[vSong of the Sun(I)] (School level 1)
+ Provides light as long as you sing.
+ Consumes mana each turn.
+2. [[[[[vFlow of Life(II)] (School level 5)
+ Heals you as long as you sing.
+ Consumes mana each turn.
+3. [[[[[vHeroic Ballad(II)] (School level 10)
+ Increases melee accuracy.
+ At level 10 it increases it even more and reduces armour a bit.
+ At level 20 it increases it still more.
+ At level 25 it grants protection against chaos and confusion.
+ Consumes mana each turn.
+4. [[[[[vHobbit Melodies(III)] (School level 20)
+ Greatly increases your reflexes allowing you to block more melee blows.
+ At level 15 it also makes you faster.
+ Consumes mana each turn.
+5. [[[[[vClairaudience(IV)] (School level 25)
+ Allows you to sense monster minds as long as you sing.
+ At level 10 it identifies all objects in a radius on the floor,
+ as well as probing monsters in that radius.
+ Consumes mana each turn.
+
+#####GHorns
+1. [[[[[vBlow(I)] (School level 4)
+ Produces a powerful, blowing sound all around you.
+2. [[[[[vGush of Wind (II)] (School level 14)
+ Produces a outgoing gush of wind that sends monsters away.
+3. [[[[[vHorns of Ylmir(III)] (School level 20)
+ Produces an earth-shaking sound.
+4. [[[[[vAmbarkanta(IV)] (School level 25)
+ Produces a reality-shaking sound that transports you to a nearly
+ identical reality.
diff --git a/lib/help/m_nature.txt b/lib/help/m_nature.txt
new file mode 100644
index 00000000..3de854e1
--- /dev/null
+++ b/lib/help/m_nature.txt
@@ -0,0 +1,53 @@
+|||||oy
+~~~~~01|Magic|Nature School
+~~~~~02|Nature Magic
+~~~~~03|Skills|Nature - Spell Info
+#####R === ToME Magic - Nature School ===
+
+The nature school of magic contains spells that interact with nature. There
+are rumours of a "Tome of the Tree" which contains all the nature school
+spells within its bindings.
+
+Worshipping the Goddess Yavanna Kementari also gives the ability to cast spells
+from the nature school at a level of 1/2 of your prayer level. E.g. if the skill
+"Spirituality: Prayer" is at level 10, you can cast up to level 5 nature school
+spells.
+
+#####GNature Spells
+There are five spells available for the nature school. These spells are:
+1. [[[[[GGrow Trees] (dual school level 6)
+ Makes trees grow extremely quickly around you.
+#####v Your Nature and Temporal skills must have reached a combined average level
+#####v of 6 in order to cast this spell.
+2. [[[[[GHealing] (school level 10)
+ Heals a portion of your hitpoints.
+3. [[[[[GRecovery] (school level 15)
+ Reduces the length of time that you are poisoned.
+ At spell level 5 it cures poison and cuts.
+ At spell level 10 it restores drained stats.
+ At spell level 15 it restores lost experience.
+4. [[[[[GRegeneration] (school level 20)
+ Increases your body's regeneration rate.
+5. [[[[[GSummon Animal] (school level 25)
+ Summons a leveled animal to your aid.
+
+
+#####GAir spells that can be cast with Nature skill
+
+1. [[[[[BThunderstorm] (dual school level 25)
+ Charges up the air around you with electricity.
+ Each turn it will throw a bolt of thunder at a random monster in sight.
+ This thunder does 3 types of damage:
+ one third of lightning
+ one third of sound
+ and one third of light.
+#####v Your Nature and Air skills must have reached a combined average level
+#####v of 25 in order to cast this spell.
+
+#####GUdun spells that can be cast with Nature skill
+
+1. [[[[[DGenocide] (dual school level 25)
+ Genocides all monsters of a specified race on the level.
+ At level 10 it can genocide all monsters near you.
+#####v Your Nature and Udun skills must have reached a combined average level
+#####v of 25 in order to cast this spell.
diff --git a/lib/help/m_necrom.txt b/lib/help/m_necrom.txt
new file mode 100644
index 00000000..8de4fd37
--- /dev/null
+++ b/lib/help/m_necrom.txt
@@ -0,0 +1,35 @@
+|||||oy
+~~~~~01|Magic|Necromancy
+~~~~~02|Necromancy Magic
+~~~~~03|Skills|Necromancy - Spell Info
+#####R === ToME Magic - Necromancy ===
+The art of Necromancy is the foul practice of manipulating the life
+force of creatures.
+
+Necromancy powers are accessed using the 'm' key and then selecting
+'Use Necromancy'; they are cast with Spell Points, like normal spells,
+and do not need light to be performed.
+
+1. [[[[[DHorrify] (Level 1) Cost:2
+ Calls upon the dark forces and opens a channel into the mind of a
+ monster, stunning and scaring it.
+ At level 21 it affects all monsters in a beam.
+ At level 36 it affects all monsters in a ball.
+ At level 46 it affects all monsters in sight.
+2. [[[[[DRaise Dead] (Level 5) Cost:6
+ This power makes corpses in a small radius around the caster rise as
+ undead ego monsters at the service of the caster. The loyalty of those
+ monsters is not guaranteed, though. It also heals all monsters within the
+ same radius.
+3. [[[[[DNecromantic Teeth] (Level 12) Cost:20
+ This conjures up a temporary vampiric weapon.
+4. [[[[[DAbsorb Soul] (Level 20) Cost:10
+ This heals you by a substantial amount every time you kill a monster within
+ its duration. It is especially useful when your character is in
+ *****ability.txt*12[Undead Form].
+5. [[[[[DVampirism] (Level 30) Cost:15
+ Drains part of the life-force from a nearby monster and gives it to you.
+6. [[[[[DDeath] (Level 35) Cost:100
+ Yes, the name is not nice. Neither are the effects: the target dies
+ immediately, but so does your character (note that death is not such a great
+ annoyance for necromancers).
diff --git a/lib/help/m_symbio.txt b/lib/help/m_symbio.txt
new file mode 100644
index 00000000..b7e04632
--- /dev/null
+++ b/lib/help/m_symbio.txt
@@ -0,0 +1,50 @@
+|||||oy
+~~~~~01|Magic|Symbiosis
+~~~~~02|Symbiosis Magic
+~~~~~03|Skills|Symbiosis - Symbiotic Powers
+#####R === ToME Magic - Symbiosis ===
+
+Symbiosis is the art of joining body, fate and sometimes even mind with
+creatures not capable of moving on their own.
+
+While a humble student of the Craft of Slime (as it's sometimes called)
+has very few options apart from asking the symbiote to help him in combat,
+master practitioners have access to an incredible array of tricks.
+
+Once hypnotised, the monster is placed onto the body, or "worn", in order to
+initiate the symbiotic relationship.
+
+#####uSymbiotic Powers
+There are nine powers a symbiant can develop. They are:
+1. [[[[[uHypnotize] (level 1) Cost:1
+ The very basis of symbiosis itself, this asks a monster to lower its
+ natural defences so that it can be safely "worn".
+2. [[[[[uRelease] (level 1) Cost:1
+ Sometimes even life-long friends part. This power allows you to revert
+ a monster on the floor to its primal state, even though the shock of waking
+ up will lower it to 0 HP.
+3. [[[[[uCharm never-moving] (level 3) Cost:2
+ A symbiant soon learns to communicate with molds and slimes.
+ This power allows him to gain the "friendship" of such a creature.
+4. [[[[[uLife share] (level 5) Cost:5
+ The cells of the symbiant and the symbiote intermingle, spreading damage
+ evenly among the two organisms.
+5. [[[[[uUse minor powers] (level 10) Cost:10
+ Allows you to tap into minor magic abilities provided by your symbiote
+ such as Blink or Slow.
+6. [[[[[uHeal symbiote] (level 15) Cost:14
+ Consciously altering the metabolism of your symbiote, you can urge its
+ bodily structure to repair itself almost instantaneously.
+7. [[[[[uUse major powers] (level 25) Cost:30
+ Highly intelligent slimes such as Quylthulgs may be more than willing to
+ employ their summoning or teleporting powers on your behalf; this power
+ can also call upon the abilities normally invoked by "Use minor powers"
+ (but this would be a waste of mana).
+8. [[[[[uSummon never-moving pet] (level 30) Cost:35
+ By releasing certain chemicals in the air, a symbiant can attract the
+ attention of slimes and mold; the better specimens are found in deeper
+ dungeons, of course.
+9. [[[[[uForce symbiosis] (level 40) Cost:60
+ An expert symbiant has such control over the cells of primitive
+ life-forms that he can temporarily "charm" part of them, thus forcing
+ their powers to manifest at his own advantage.
diff --git a/lib/help/m_tempo.txt b/lib/help/m_tempo.txt
new file mode 100644
index 00000000..d0b5a1fa
--- /dev/null
+++ b/lib/help/m_tempo.txt
@@ -0,0 +1,41 @@
+|||||oy
+~~~~~01|Magic|Temporal School
+~~~~~02|Temporal Magic
+~~~~~03|Skills|Temporal - Spell Info
+#####R === ToME Magic - Temporal School ===
+
+The temporal school of magic contains spells where magic is used to meddle
+in the relationship between time and space. There are rumours of a "Tome of
+the Time" which contains all the temporal school spells within its bindings.
+
+Worshipping the Goddess Yavanna Kementari also gives the ability to cast spells
+from the temporal school at a level of 1/6 of your prayer level. E.g. if the
+skill "Spirituality: Prayer" is at level 12, you can cast up to level 2
+temporal school spells.
+
+
+#####sTemporal Spells
+There are four spells available for the temporal school. These Spells are:
+1. [[[[[sMagelock] (school level 1)
+ Magically locks a door.
+ At spell level 30 it creates a glyph of warding.
+ At spell level 40 the glyph can be placed anywhere in the field of vision.
+2. [[[[[sSlow Monster] (school level 10)
+ Magically slows down the passing of time around a monster.
+ At level 20 it affects a zone.
+3. [[[[[sEssence of Speed] (school level 15)
+ Magically decreases the passing of time around you, allowing you to move
+ and act more quickly with respect to the rest of the universe.
+4. [[[[[sBanishment] (school level 30)
+ Disrupts the space/time continuum in your area and teleports all monsters
+ away.
+ At spell level 15 it also may lock them in a time bubble for some turns.
+#####v Your Temporal and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+
+#####GNature spells that can be cast with Temporal skill
+
+1. [[[[[GGrow Trees] (dual school level 6)
+ Makes trees grow extremely quickly around you.
+#####v Your Nature and Temporal skills must have reached a combined average level
+#####v of 6 in order to cast this spell.
diff --git a/lib/help/m_thaum.txt b/lib/help/m_thaum.txt
new file mode 100644
index 00000000..253d52be
--- /dev/null
+++ b/lib/help/m_thaum.txt
@@ -0,0 +1,31 @@
+|||||oy
+~~~~~01|Magic|Thaumaturgy
+~~~~~02|Thaumaturgical Magic
+~~~~~03|Skills|Thaumaturgy - Spell Info
+#####R === ToME Magic - Thaumaturgy ===
+
+Thaumaturgy is a different type of magic where the spells learnt are not
+restricted to one school, nor are they read out of spellbooks. Each time an
+adventurer increases her thaumaturgy skill, she gains access to a few
+[[[[[Rrandom] attack spells, each one automatically "learnt" at a specific
+casting level. Since she doesn't need spellbooks, she does not end up with
+inventory slots being filled up so quickly by the necessary items for safe
+exploration of the dungeon, and can therefore collect more loot.
+
+The downside of this is that she has no ability to choose what spells she
+learns, and no ability to improve the power of a learnt spell. So, a bolt
+spell with damage 1d5 will remain at 1d5 damage for the whole game. And the
+spells learnt are *all* attack spells of some sort (remembering that things
+like light and stone-to-mud can damage some monsters) - so no teleporting, no
+identify, no healing spells are learnt. At most, some wall creation may be
+employed.
+
+Thaumaturgist use their magic through the 'm' key. They then select a general
+group of spells, followed by a specific spell.
+
+Thaumaturgy spells can take the form of:
+- a bolt, targeted at a single location;
+- a beam, which hits all monsters in a line;
+- a ball (either centred on the caster or targetable);
+- an meteor strike (multiple balls in the vicinity of the caster);
+- a spell that affects all monsters in line of sight.
diff --git a/lib/help/m_udun.txt b/lib/help/m_udun.txt
new file mode 100644
index 00000000..a903d9f9
--- /dev/null
+++ b/lib/help/m_udun.txt
@@ -0,0 +1,35 @@
+|||||oy
+~~~~~01|Magic|Udun School
+~~~~~02|Udun Magic
+~~~~~03|Skills|Udun - Spell Info
+#####R === ToME Magic - Udun School ===
+
+The Udun school of magic contains spells where the corrupted forces of Melkor
+Bauglir are used to create the final spell effect. There are rumours of an
+"Unholy Tome of the Hellflame" which contains all the Udun school spells within
+its bindings.
+
+The Udun school is available only to worshippers of *****g_melkor.txt*0[Melkor Bauglir]. They will also
+need some proficiency in the magic schools of Mana, Nature, Conveyance, and Fire
+(or alternatively Sorcery) to cast the Udun spells. On the other hand, the spell
+power of Udun spells is greatly increased by the level of the caster.
+
+#####DUdun Spells
+There are four spells available for the Udun school. These spells are:
+1. [[[[[DDrain] (dual school level 1)
+ Drains the mana contained in wands, staves and rods to increase yours.
+#####v Your Udun and Mana skills must have reached a combined average level
+#####v of 1 in order to cast this spell.
+2. [[[[[DGenocide] (dual school level 25)
+ Genocides all monsters of a specified race on the level.
+ At level 10 it can genocide all monsters near you.
+#####v Your Udun and Nature skills must have reached a combined average level
+#####v of 25 in order to cast this spell.
+3. [[[[[DWraithform] (dual school level 30)
+ Turns you temporarily into an immaterial being.
+#####v Your Udun and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+4. [[[[[DFlame of Udun] (dual school level 35)
+ Turns you temporarily into a powerful Balrog.
+#####v Your Udun and Fire skills must have reached a combined average level
+#####v of 35 in order to cast this spell.
diff --git a/lib/help/m_water.txt b/lib/help/m_water.txt
new file mode 100644
index 00000000..5daee1b1
--- /dev/null
+++ b/lib/help/m_water.txt
@@ -0,0 +1,33 @@
+|||||oy
+~~~~~01|Magic|Water School
+~~~~~02|Water Magic
+~~~~~03|Skills|Water - Spell Info
+#####R === ToME Magic - Water School ===
+
+The water school of magic contains spells where the element of water is
+used to create the final spell effect. There are rumours of a "Tome of the
+Everrunning Wave" which contains all the water school spells within its
+bindings.
+
+Worshipping the Goddess Yavanna Kementari also gives the ability to cast spells
+from the water school at a level of 1/2 of your prayer level. E.g. if the skill
+"Spirituality: Prayer" is at level 10, you can cast up to level 5 water school
+spells.
+
+#####bWater Spells
+There are four spells available for the water school. These Spells are:
+1. [[[[[bGeyser] (school level 1)
+ Shoots a geyser of water from your fingertips.
+ Sometimes it can blast through its first target.
+2. [[[[[bVapor] (school level 2)
+ Fills the air with toxic moisture to wash away annoying creatures.
+3. [[[[[bEnt's Potion] (school level 6)
+ Fills up your stomach (i.e. satisfy hunger).
+ At spell level 5 it emboldens your heart (boldness).
+ At level 12 it make you heroic.
+4. [[[[[bTidal Wave] (school level 16)
+ Summons a monstrous tidal wave that will expand and crush monsters under
+ its mighty waves.
+5. [[[[[bIce Storm] (school level 22)
+ Engulfs you in a storm of roaring cold that strikes your foes.
+ At spell level 10 it turns into shards of ice.
diff --git a/lib/help/macrofaq.txt b/lib/help/macrofaq.txt
new file mode 100644
index 00000000..03a00eaa
--- /dev/null
+++ b/lib/help/macrofaq.txt
@@ -0,0 +1,2356 @@
+|||||oy
+~~~~~43|Macros
+~~~~~44|Keymaps
+#####R======================================================================
+#####B ToME Macro FAQ
+
+ Original Angband Macro FAQ by Jim Lyon
+ (jplyon@attglobal.net)
+ 09-Dec-2000
+ Compiled from usenet postings to r.g.r.a
+ and Angband source & documentation
+
+#####B Edited by Dawnmist (angband@dawnmist.8m.com)
+#####B for PernAngband 5.x.x on 03-Aug-2001
+#####B with permission from Jim Lyon
+~~~~~30
+#####R======================================================================
+#####R1. Introduction
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G1.1 About this FAQ
+#####G----------------------------------------------------------------------
+
+This FAQ is mean to be a companion to the standard ToME help files
+for using inscriptions, macros, and keymaps. The ToME help files
+which also describe them are listed in the "References" section.
+
+This documentation is for ToME, version 4.2.x.
+
+#####B==================================
+#####B SPOILER ALERT
+#####B==================================
+
+This document gives some information on how the game does or doesn't
+work that might be considered spoiling.
+(Most players advanced enough to use macros probably won't notice.)
+
+#####G----------------------------------------------------------------------
+#####G1.2 Table of contents
+#####G----------------------------------------------------------------------
+
+ *****macrofaq.txt*30[1. Introduction]
+ *****macrofaq.txt*5[2. Quick start tutorial]
+ *****macrofaq.txt*32[3. Overview]
+ *****macrofaq.txt*33[4. Common macros and techniques]
+ *****macrofaq.txt*34[5. Common questions]
+ *****macrofaq.txt*35[6. Common problems]
+ *****macrofaq.txt*36[7. Inscriptions added by the game]
+ *****macrofaq.txt*37[8. Keys and commands]
+ *****macrofaq.txt*38[9. Pref files]
+*****macrofaq.txt*39[10. Macro editing commands]
+*****macrofaq.txt*20[11. Advanced macro techniques]
+*****macrofaq.txt*41[12. Problems]
+*****macrofaq.txt*42[13. Miscellaneous]
+
+#####G----------------------------------------------------------------------
+#####G1.3 Notation
+#####G----------------------------------------------------------------------
+
+#####BSingle Quotes (')
+These are generally used to delimit a single character to be typed in.
+These shouldn't by typed in themselves.
+
+#####BDouble Quotes (")
+These are generally used to delimit a sequence of characters to be
+typed in. These shouldn't by typed in themselves.
+
+#####BParentheses ( )
+These are generally used for single-key Angband commands.
+
+#####BBraces { }
+These are used to enclose inscriptions. These aren't typed in as part
+of inscribing an item. They are added by the interface.
+
+#####G= Special Keys =
+#####G-----------------------------------
+The following abbreviations are used in this document. These keys may
+be named differently or missing on some keyboards. Some keys may be
+duplicated. These abbreviations shouldn't be typed in literally. For
+example, when F1 is encountered in a string of keys to press it means
+to press the F1 function key, not 'F','1', unless otherwise stated.
+Additional special keys may be listed later.
+
+Alt Alt
+Ctrl Control
+Del Delete
+Esc Escape
+Enter Enter / Return
+F1 Function key F1, ...
+Shift Shift
+
+#####G= System abbreviations =
+#####G-----------------------------------
+Each system that ToME compiles on has a semi-standard 3-letter
+abbreviation. These are commonly referred to in the source and docs
+using "xxx" as a "wildcard" standing for any one of them. In this
+document "***" is used instead because there are actual generic files
+not associated with any specific system that use "xxx". Sometimes this
+refers to a feature instead of a specific system: "xxx" is used for a
+generic / default file, and "new" is used for Adam Bolt's tiles.
+
+~~~~~5
+#####R======================================================================
+#####R2. Quick Start Tutorial
+#####R======================================================================
+
+This section is designed to get you quickly using the most common
+keymaps and macros. Later sections explain the techniques used in more
+detail. These examples may not be the "best" ones to use in real play.
+
+#####G----------------------------------------------------------------------
+#####G2.0 Definitions
+#####G----------------------------------------------------------------------
+
+First, you should know some fundamental terms:
+
+Actions are sequences of keypresses that the game can recognise. They
+can't be recorded by the game, but must be input manually.
+
+Macros and keymaps map a keypress to an action. They can be used to
+customise the keyboard, reduce typing, and speed up game play. Macros
+must be used when the trigger key doesn't have a system-independent
+representation. Keymap actions can only contain underlying commands.
+[[[[[BMost customisation should be done with keymaps instead of macros when]
+[[[[[Bthere is a choice.]
+
+Inscriptions are "markings" which you can put on any game item. One
+use is to label items in a way that doesn't depend on inventory
+position. Another allows verifying the selection of an item. Under the
+right conditions they can save your life.
+
+#####G----------------------------------------------------------------------
+#####G2.1 Swap weapons
+#####G----------------------------------------------------------------------
+
+First inscribe your main weapon:
+(Press the following keys in sequence)
+
+1) { Inscribe an object
+2) * Show inventory list
+3) / Switch to equipment list
+4) a Main weapon slot
+5) @w0 Wield when object 0 is chosen
+6) (Hit Enter)
+
+Now inscribe the second weapon:
+
+1) { Inscribe an object
+2) * Show inventory list
+3) (Choose letter of second weapon)
+4) @w0 Wield when object 0 is chosen
+5) (Hit Enter)
+
+Finally, ToME (unlike standard 'Vanilla' Angband) does
+not have an automatic trigger key to swap items, so it must be
+created. Select a key that is not being used for any other commands
+('X' in the normal keyset is free - see *****command.txt*0[command.txt]), and create
+the following keymap:
+
+1) @ Interact with macros
+2) 8 Create a keymap
+3) X The trigger key for the keymap
+4) w0 Wield object 0
+5) (Hit Enter)
+6) (Hit Esc to exit the editor)
+
+Now to swap weapons, just press the trigger key 'X' which is bound to
+the default keymap "w0". You may also press "w0" directly to swap.
+~~~~~45|Macros|Macro recorder
+~~~~~46|Keymaps|Macro recorder
+#####G----------------------------------------------------------------------
+#####G2.2 Using the macro-recorder
+#####G----------------------------------------------------------------------
+
+You may find all the key-presses involved in ToME a long and time-consuming way
+to play the game. There are ways to speed up repeated commands by assigning
+them to a trigger key which can help. These are called macros or keymaps.
+
+The most obvious use for these in ToME is for mage-types, especially sorcerors,
+who rely on their spells for just about everything. Typing mbaa*t in order to
+fire a Manathrust is fine if you only have to do it once or twice, but can
+quickly get annoying when you're doing it every move. Far easier to assign that
+sequence of keypresses to a single trigger key which you can then press as many
+times as you need. (Until your SP run out of course!)
+
+The easiest way to assign a macro is to use the macro-recorder. Start this by
+hitting the '$' key. You'll then receive a message telling you that the macro
+recorder has now started and you will need to press the '$' key a second time
+to stop the recorder. Preparation is all important here. It is best to be in a
+situation where you really NEED to cast the spell before recording the macro,
+so you use all the correct casting techniques and the game behaves as it would
+in a real (combat) situation (if the spell is to be generally cast in combat).
+
+So assuming we're going to create a macro for manathrust. We've walked into a
+room and there's a nasty small kobold. What do we do?
+
+1) $ Start macro recorder
+2) *t target monster (or player if no monster in Line of sight)
+3) m open skills menu
+4) @ enters verbose mode
+5) Cast a Spell selects skill to use - CASE SENSITIVE
+6) @ enters verbose mode
+7) Manathrust casts spell from any book/spell container - CASE SENSITIVE
+8) $ end macro recorder
+9) y confirms macro keystrokes[[[[[B*]
+10) (choose trigger key)
+11) @ opens macro saving/loading screen
+12) 2 appends macros to a file
+13) (choose a name for the file, e.g. sorceror.prf)
+14) (Hit Enter)
+15) (Hit Esc to exit the editor)
+
+This will search for the spell in all your books and equipment. If it is found,
+in either a book or a wielded item that contains a spell, then the spell is
+cast at the targetted monster.
+
+This technique can be used for all the other skills as well (Use Mindcraft,
+Forge Ammo) etc.
+
+[[[[[B*]If you answer no the recorder continues recording keypresses. If
+you know you have made a mistake, you need to answer yes, and then not
+save the macro!
+
+~~~~~12
+#####G----------------------------------------------------------------------
+#####G2.3 Prevent unwanted use of an item
+#####G----------------------------------------------------------------------
+
+#####BPrevent "losing" an item by "accident":
+
+1) { Inscribe an object
+2) * Show inventory list
+3) (Choose an item)
+4) !d!k!v
+ !d - don't drop (d)
+ !k - don't destroy (k)
+ !v - don't throw (v)
+5) (Hit Enter)
+
+This prevents dropping, destroying, or throwing the item. You will be
+asked if you really want to do so. This is one of the most common
+inscriptions used, and one of the most useful.
+
+#####BPrevent "using" an item at all:
+
+1) { Inscribe an object
+2) * Show inventory list
+3) (Choose an item)
+4) !* Don't do anything with this item without verifying
+5) (Hit Enter)
+
+This inscription is commonly used on Scrolls of Word of Recall...
+~~~~~8
+#####G----------------------------------------------------------------------
+#####G2.4 Saving these macros and keymaps for reuse
+#####G----------------------------------------------------------------------
+
+Save the macros and keymaps for reuse by the current character:
+
+1) @ Interact with macros
+2) 2 Append macros to a file
+ (optionally enter a filename: e.g. dump.prf or dump.txt)
+ (Hit Enter to save the file with the filename shown)
+3) 6 Append keymaps to a file
+ (Hit Enter to save the file with the filename shown)
+4) (Hit Esc to exit the editor)
+
+This pref file will be automatically loaded any time a character with
+a name, race, or class matching the filename is loaded.
+
+The "Append macros/keymaps to a file" commands will append ALL current
+macros/keymaps to the given file. They will not overwrite the file.
+
+You should edit the file to remove macros that weren't added by you,
+to reduce clutter and prevent errors. Unfortunately the best way to do
+this is still "by hand". Open up the pref file in a text editor and
+remove the duplicate macros and keymaps added. These will be added
+after the headers "# Automatic macro dump" and "# Automatic keymap
+dump". The ones you added will be the very last ones in the list. The
+others are the entire set of keymaps and macros from all other prefs
+loaded. (This step isn't necessary, but is very helpful.)
+
+~~~~~32
+#####R======================================================================
+#####R3. Overview
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G3.1 Inscriptions
+#####G----------------------------------------------------------------------
+
+Inscriptions are "markings" which you can inscribe on any game item.
+
+One common use is recording where you got one of your favorite items.
+Example: The Broad Sword 'Glamdring' (2d5) (+10,+15) {icky thing, 50'!}
+
+Another is to note important resists or activations on an item to make
+figuring out resist combinations easier.
+Example: The Nice Shiny Armor (-3) [35,+25] {resDk,resDis,A:Geno}
+
+Inscriptions can "number" an item so that you don't have to know where
+it is in your inventory.
+Example: inscribing your scrolls {@r1} lets you use '1' at the prompt
+for which scroll to read, instead of having to use the inventory letter,
+which can change unnoticed.
+
+Number inscriptions work together with macros to allow reproducible
+labeling of items independent of inventory position.
+
+Note that the game produces "fake" inscriptions, which look like real
+inscriptions, but are really just displayed the same way (e.g. "cursed").
+
+Finally, if you are in symbiosis with another creature, you can name it by
+inscribing it with "#named SomeName" (the word "#named" must be entered
+literally at the start of the inscription). This will tell the game that
+your symbiotic partner should be referred to by its name, rather than simply
+"Your white jelly". This has no effect on game play other than the aesthetic.
+
+#####G----------------------------------------------------------------------
+#####G3.2 Macros
+#####G----------------------------------------------------------------------
+
+Macros are mappings from a single "logical" keypress to a sequence of
+keypresses, allowing you to use special keys on the keyboard, such as
+function keys or keypad keys, possibly in conjunction with modifier
+keys, to "automate" repetitive multi-key commands that you use a lot.
+
+[[[[[BFor keys which don't have a system-independent representation, such as]
+[[[[[Bfunction keys, this is the only way to change their behavior.]
+
+#####G----------------------------------------------------------------------
+#####G3.3 Keymaps
+#####G----------------------------------------------------------------------
+
+Keymaps are vaguely related to macros. A keymap maps a single keypress
+to a series of keypresses, which bypass both other keymaps and any
+macros. Angband uses keymaps to map the original and the roguelike
+keysets to the underlying command set, and allows the user to modify or
+add keymaps of their own. All keymap actions must be specified using
+underlying commands. Keymaps and macros aren't expanded. The original
+keyset is almost identical to the underlying keyset, except that
+"numbers" are mapped to ";" plus a direction, "5" is mapped to ",",
+and a few control-keys are mapped to various things. See *****command.txt*0[command.txt]
+for the full set of underlying commands. Keymaps also allow the
+"disabling" of a command by mapping it to "\x00".
+
+#####G----------------------------------------------------------------------
+#####G3.4 Pref files
+#####G----------------------------------------------------------------------
+
+Preference files save commands such as macros and keymaps which are
+used to customise the game. They are used to implement the "original"
+and "roguelike" keysets. They provide default appearances for items.
+
+They also implement the default behaviors which make Angband look and
+play the same (for the most part) on different systems.
+
+Pref files can be saved with the name of a player name, class, and
+race, and anytime a player with a matching characteristic is loaded,
+the appropriate pref file is loaded. This makes some customisations
+transparent and automatic.
+
+Pref files let you do some things that could otherwise only reasonably
+be done by changing the info files or source, such as changing the
+appearance of a given terrain feature, or the symbol used for the
+player.
+
+Pref files let you set up and save your favorite game options, and
+have them available for new characters without having to redo them.
+
+~~~~~33
+#####R======================================================================
+#####R4. Common macros and techniques
+#####R======================================================================
+~~~~~13
+#####G----------------------------------------------------------------------
+#####G4.1 Clearing the command buffer
+#####G----------------------------------------------------------------------
+
+[[[[[v++++++++++ This is one of the most important techniques! ++++++++++]
+
+Almost all action strings should begin with a sequence to clear the
+buffer of existing commands and messages. These sequences are often
+omitted in usenet postings and in this FAQ because they clutter the
+description, but they should almost always be used.
+
+If an unfinished command is still waiting for input when you press the
+trigger key of a macro or keymap, the characters of its action string
+will be taken as input for the command. The command will ignore keys
+it doesn't know how to handle until it finds one that it does. This
+often leads to something completely unexpected, with embarrassing
+results such as your death, or losing a really nifty item.
+
+If there are still messages waiting, the first characters in the
+action will instead just clear the waiting messages. How this happens
+depends on whether the *****option.txt*1[option (quick_messages)] is set. Then the action
+will start executing in the middle of its action string, with equally
+dangerous results as in the above case. Note that some messages caused
+by a command are quite rare, and others could be produced by a game
+state change like becoming hungry that has nothing to do with the command.
+
+These types of problems are more common when using an action such as
+auto-firing where a trigger key is repeatedly pressed.
+
+[[[[[B"\e\e\e"]
+Multiple escapes are used to clear the command buffer. Escape cancels
+any command/input still being processed, and also clears a [single]
+message whether/not the (quick_messages) option is set. This string
+should be used to begin all action strings. It is also wise to put it
+between actions in multi-action macros. Note that this technique can
+also be dangerous, hiding warnings or important information.
+Example: an action like "*tf1" would be changed to "\e\e\e*tf1".
+
+There are a few situations in which you do not want to use escapes.
+For example, after the spell Detect Monsters, an escape will clear the
+detection. Or if the action is part of a multi-part action or is meant
+to wait for user input such as the firing action "f1" which will wait
+for targeting information.
+
+[[[[[B"\s\s\s"]
+Spaces are useful for clearing messages, but won't cancel a command
+that is waiting for an item choice. Sometimes it is useful to split
+an action into two parts and bind them to two separate trigger keys.
+Prefixing spaces before the 2nd action will discard any remaining
+messages without canceling unfinished commands from the 1st one. Some
+players create a macro consisting of a large number of spaces to be
+used to clear a flood of messages.
+
+See sections:
+- *****macrofaq.txt*1["Messages and Questions"] for how to deal with them.
+- *****macrofaq.txt*2["My macro outputs "e - Floating Eye"..."] for an example of a common
+ mistake using escape sequences.
+- *****macrofaq.txt*3["My macro drops/takes off my main weapon!"] for an example of the
+ kind of thing that can go wrong when you fail to use them.
+- *****macrofaq.txt*4["What just killed me?"] for an example of skipping over messages
+ *too* fast.
+
+#####G----------------------------------------------------------------------
+#####G4.2 Swap weapons
+#####G----------------------------------------------------------------------
+
+If you followed the *****macrofaq.txt*5[Quick-Start Tutorial] in Section 2.1, the 'X' key has
+the keymapping "w0", which will wield the first item inscribed as "@0"
+or "@w0". This will swap between 2 weapons which are both inscribed with
+{@0} or {@w0}. If there is more than one item in the inventory inscribed
+as 0, it will use the first one.
+
+This will also work for other wieldable items. For example, if you
+have a helm which gives telepathy, which can be a real pain when you
+need to rest, it can be used to swap it with another helm.
+
+Inscribing weapons with {@w1@w0}, {@w2@w0} allows directly wielding a
+specific one. If you don't want that ability, you can just inscribe
+both with {@w0}. These can also be inscribed as just {@1@0} and {@2@0}
+if you don't inscribe any other items with numbers, although this is
+not recommended.
+
+
+#####G----------------------------------------------------------------------
+#####G4.3 Resting
+#####G----------------------------------------------------------------------
+
+#####B= Rest as needed =
+"R&\r"
+R - rest
+& - until 100% healthy
+\r - return.
+
+Note that this isn't particularly dangerous, because the game will
+break out of the resting command if you are disturbed by hunger,
+sensing a monster, ...
+
+#####B= Rest for a specific duration =
+"R100\r"
+R - rest
+100 - turn count
+\r - return
+
+This version is useful if you are already healed up. For fighter
+pseudo-id, for example. Also useful for recovering a fixed amount of
+mana before/after a spell, waiting for a Recall spell to kick in,...
+
+Note that this is one of the few times when you can directly enter the
+count after the command. Usually you need to enter the count before
+the command, using the (0) count command.
+
+#####B= Maximum Rest =
+"R9999\r"
+
+The maximum number of turns you can use as an argument. This can be
+useful when waiting for shop inventory to change, etc. Be sure to take
+off any non-permanent light source, and have plenty of food when you
+rest for long periods of time.
+
+#####G----------------------------------------------------------------------
+#####G4.4 Activate the phial
+#####G----------------------------------------------------------------------
+
+"Am\s\s"
+A - Activate
+m - light source (the phial).
+\s - skip message
+\s - skip message
+
+"Am\s\sR50\r"
+Activate the phial and rest for 50 turns.
+
+This can be bound to 'F' key since you won't need to refuel lanterns
+much after you have the phial :).
+
+#####G----------------------------------------------------------------------
+#####G4.5 Kill item(s) on floor
+#####G----------------------------------------------------------------------
+
+The need to destroy large numbers of items arises as one reaches
+deeper levels of the dungeon. The auto-squelch feature only partially
+reduces the need for this. The behavior of these actions is affected
+by the option (quick_messages), and the possible presence of a pile of
+items on the floor.
+
+*****option.txt*1[(quick_messages)] allows any key to cancel a message.
+
+In ToME, multiple items on the floor are displayed in a list.
+This allows the player to select an item from the floor by entering an
+item index when there is a pile (more than one item). This generally
+complicates writing these macros.
+
+Note that space '\s' is used to clear messages in the action strings,
+but one could use escape '\e' just as well.
+
+Note: you cannot destroy artifacts, so these macros are safer and more
+useful than they might first appear. The (k) Destroy item command will
+fail when trying to destroy an artifact, leaving any following
+characters in the action string, which may be interpreted differently
+than anticipated.
+
+[[[[[B"k-yy"]
+k - Kill item
+- - Select item from floor
+y - "yes" to query "Really destroy a <item>?"
+y - skip the "you destroy the <item>" message.
+
+This version only works when (quick_messages) option is on. Here the
+last 'y' key gets rid of the last message, since any key will. This
+won't work for piles. The 'y' will be ignored as an invalid item choice.
+
+[[[[[B"k-y\s"]
+k - Kill item
+- - Select item from floor
+y - "yes" to query "Really destroy a <item>?"
+\s - skip the "you destroy the <item>" message.
+
+This version works as above, but also when (quick_messages) is off.
+
+[[[[[B"0k-y\s"]
+0 - enter count (causes to skip prompt for how many to destroy)
+k - Kill item
+- - Select item from floor
+\s - skip the "you destroy the <item>" message.
+
+Destroy a single item on floor below you. Doesn't prompt for a count.
+This won't work for piles, which will prompt you for the item. Works
+correctly when (quick_messages) is off, because there is no prompt
+for how many to destroy.
+
+[[[[[B"0k-ay\e"]
+0 - enter count (causes to skip prompt for how many to destroy)
+k - Kill item
+- - Select item from floor
+a - either item 'a', or ignored
+\e - escape (ignored), or cancel message
+
+Destroy a single item on floor below you. Doesn't ask to confirm.
+[[[[[vWARNING:] This action can destroy the first item in your inventory if
+there aren't any items on the floor below you!
+
+The leading '0' causes a prompt for a count to be skipped. If there is
+a pile, the 'a' key will select the top item in the pile. If not, the
+'a' will aim a wand, the following 'y' will be ignored, and the final
+escape will cancel the aiming.
+
+[[[[[B"0k-yay\e"]
+0 - enter count (causes to skip prompt for how many to destroy)
+k - Kill item
+- - Select item from floor
+y - "yes" to query "Really destroy a <item>?", or ignored.
+a - top item (a) in a pile, or activate wand.
+y - "yes" to query "Really destroy a <item>?" (for piles).
+\e - skip the "you destroy the <item>" message.
+
+The above action will work in most cases. This version works correctly
+for piles. If there is a pile, the 'y' is ignored and the 'a' selects
+the top item. If there isn't a pile, then the 'y' will correctly answer
+the yes/no question "Really destroy a <item>?", and the following "ay"
+will aim a rod, and then ignore the 'y' key press, and the final escape
+will cancel the aiming. Works correctly when (quick_messages) is off.
+When (quick_messages) is on, and there is no pile, the 'a' will cancel
+the message, and the following 'y' will be passed through as an
+unimplemented command, and the space will cancel the error message.
+
+Backslashes "\\" may be required to keep the 'y's from being
+interpreted as keymaps in case 'y' has been assigned one.
+
+#####G----------------------------------------------------------------------
+#####G4.6 Fire missile at nearest target
+#####G----------------------------------------------------------------------
+
+Each of these needs "\e\e\e\e" afterwards to cancel up to 4 possible
+messages. The first message will always occur. Note that adding too
+many escapes can cause you to miss the messages in which the monster
+fights back.
+- "You have NN <ammo> left. -more-"
+- "The <ammo> hits the <monster>. -more-"
+- "It was a <adj> hit! The monster ... -more-"
+- "The <monster> dies/grunts with pain/..."
+
+[[[[[B"f*t"]
+f - fire ammo from quiver slot
+* - target
+t - select first target
+
+Note that targeting is affected by the option (*****option.txt*4[use_old_target]). If
+this action is used with the (use_old_target) option set, the "f"
+part will fire the missile before the targeting part "*t" is reached.
+See section *****macrofaq.txt*6["My auto-firing macro shoots the wrong target!"].
+
+[[[[[B"*tf"]
+*t - select first target
+f - fire ammo from quiver slot
+
+If (use_old_target) is on, this works correctly, by selecting the
+target before firing. If the option is off, it will still prompt you
+to select a target, even though you just selected one.
+
+[[[[[B"*tf*t"]
+*t - select first target
+f - fire ammo from quiver slot
+*t - select first target
+
+This works correctly for (use_old_target) either on/off. If the option
+is on, this works by selecting the target before firing. If the option
+is off, the first target selection will be ignored, and firing will
+wait on the second target selection.
+
+Note that if there are no valid targets, "*t" will select the player's
+current position. Also, it is fairly easy to make safe assumptions
+about the (use_old_target) option, since a player doesn't tend to
+change back and forth. It is generally easier to make one set of
+actions that work for (use_old_target) on, and another for it off.
+
+Note also that the swapping weapon macro can be very useful for swapping
+the type of ammo in the quiver slot when you have two different sets of
+ammo you use - your standard "fire at everyone normal" ammo (usually
+not enchanted), and your big damage "Uniques and nasty monster"
+enchanted ammo.
+
+#####G----------------------------------------------------------------------
+#####G4.7 Preventing actions
+#####G----------------------------------------------------------------------
+
+#####B= Prevent selling =
+{!d}
+Prevent selling - use on main weapon, artifacts.
+
+#####B= Prevent going up/down =
+{^<}
+Verify before going up stairs.
+{^>}
+Inscribe boots to make confirm before going down stairs.
+This can also be useful on Charisma boosting items that you wear
+around town but don't want to take into the dungeon.
+{^>^r^z^m^p}
+Prevent leaving town with this item. Need to catch stairs, scrolls and
+rods of Recall, and Mage and Priest Word of Recall spells.
+
+#####G----------------------------------------------------------------------
+#####G4.8 Warrior macros and inscriptions
+#####G----------------------------------------------------------------------
+
+#####B= Identify with list =
+Inscribe Identify scrolls {@r0}.
+Then action "r0*" will cast Identify and bring up the inventory list.
+
+#####B= Identify floor =
+"r0-" will Identify without showing the inventory.
+
+#####G----------------------------------------------------------------------
+#####G4.9 Verification techniques
+#####G----------------------------------------------------------------------
+
+#####B= Verify All =
+{!*}
+verify any attempt to use this item. Useful for some things such as
+Scrolls/rods of Recall that you don't want to lose or use by accident.
+
+#####B= Verify drop, destroy, throw =
+{!d!k!v}
+don't drop, destroy, or throw this item. Prevents dropping your
+favorite weapon,... This is one of the most useful inscriptions, as it
+prevents the kind of typing accidents that can get you killed.
+
+#####B= Verify selling =
+{!d}
+Prevents selling as well as dropping.
+
+#####B= Multiple verification =
+These inscriptions can be repeated. So {!*!*} will make you confirm
+twice for any action using that item.
+
+#####G----------------------------------------------------------------------
+#####G4.10 Canceling targeting
+#####G----------------------------------------------------------------------
+
+[[[[[B"*\e\s"]
+* - start targeting
+\e - cancel targeting.
+\s - skip message "Target Aborted."
+
+OR
+
+[[[[[B"*q\r"]
+* - start targeting
+q - cancels targeting.
+\r - skip message "Target Aborted."
+
+This is useful before casting Stone to Mud, or a ball spell. For ball
+spells you usually want to target the middle of a pack, or sometimes
+to "miss" the creature in order to get the ball to detonate on a
+nearby wall.
+
+Using a targeted action after this will cause the user to be prompted
+for a target.
+
+Canceling targeting is made necessary by the existence of the option
+(use_last_target), which causes an action which requires a target to
+use the last target without prompting. See section
+*****macrofaq.txt*6["My auto-firing macro shoots the wrong target!"] for more on this.
+~~~~~15
+#####G----------------------------------------------------------------------
+#####G4.11 Automatically loading pref files
+#####G----------------------------------------------------------------------
+
+Angband automatically loads pref files when a character is loaded or
+born. Among the last ones loaded are: "<$RACE>.prf", "<$CLASS>.prf",
+and "<$PLAYER>.prf", in that order. These are the best ones to use to
+customise the game for individuals. The order is important because
+pref files which load later will overwrite options and macros/keymaps
+from previous ones.
+
+Here <$RACE> is the name of the character's race, <$CLASS> is the name
+of its class, and <$PLAYER> is the character's name. Both <$RACE> and
+<$CLASS> have a fixed number of choices. These are listed for ToME
+in section *****macrofaq.txt*7["Pref file loading order"].
+
+Your character's name is the one that appears during game play in the
+upper left hand corner of the screen. If it isn't visible there, you
+can use the (C) Character description command. Note that this name may
+be different than the filename of the character's save file.
+
+Filenames for the save and pref files are built from a "base name",
+which is the player name with all non-alphanumeric characters changed
+to underscores (_). On Windows and DOS systems the base name will also
+be truncated to 8 characters. This could lead to different characters
+having the same (default) pref files.
+Example: "Grog the Elder" and "Grog the Younger" would both try to
+load the same pref file "Grog_the.prf".
+
+In recent versions of ToME "<$PLAYER>.prf" is the default filename
+when saving your macros and keymaps from the (@) Interact with macros
+screen. Just hit Enter to accept that name.
+
+On some systems you may encounter problems automatically loading this
+file if your name is more than 8 characters, or if it contains spaces
+or special characters.
+
+See section *****macrofaq.txt*8["Saving these macros and keymaps for reuse"] for how to
+save your character's preferences.
+
+See section *****macrofaq.txt*7["Pref file loading order"] for the full list of pref files
+loaded and their order.
+
+Note: for pref files to load automatically they must end in the file
+extension "prf", which is the default when saving pref files. But it
+is possible to save and load pref files with any or no file extension,
+from the macros and visuals editor screens.
+
+#####G----------------------------------------------------------------------
+#####G4.12 Multiple macros bound to one trigger key
+#####G----------------------------------------------------------------------
+
+Angband supports using modifier keys on trigger keys. One thing this
+lets you do is easily choose between variants of an action. Another is
+to minimise the amount of moving your hands have to do, speeding up
+play and reducing stress on your wrists.
+
+[[[[[BYou can bind multiple versions of the same macro to the same trigger]
+[[[[[Bkey, using Alt, Control, Shift in different combinations] to choose
+among the different versions.
+Example: use <Alt> for targeted, and <Shift> for non-targeted.
+
+Another use is to heavily use modifiers on numeric keypad keys. The
+standard version already comes with Shift-<digit> bound to running in
+that direction. But by using various combinations of modifier keys, it
+is possibly to play with the right hand almost always on the numeric
+keypad, and the left on the modifier keys.
+
+#####G----------------------------------------------------------------------
+#####G4.13 Multi-part actions
+#####G----------------------------------------------------------------------
+
+Better to only do this when spells have ~0% failure.
+Be careful of the order of commands. Commands that leave useful info
+on the screen shouldn't be followed by ones that will clear it.
+Be careful of commands that set or clear targets.
+Use "\e\e\e\e" in-between commands to be safe.
+
+#####G----------------------------------------------------------------------
+#####G4.14 Easy running
+#####G----------------------------------------------------------------------
+
+Bind Shift+<keypad dir> to running for each of the directions.
+For example, running "North":
+
+1) @ Interact with macros
+2) 4 Create a macro
+3) Shift+8 (Trigger key for the macro)
+4) \\. Run
+ 8 "North"
+5) (Hit Enter)
+6) (Hit Esc to exit the editor)
+
+Macros for the other directions are added similarly. Remember that the
+original and roguelike keysets differ, but using the backslashes makes
+sure that the "underlying" keyset gets used:
+ 7 8 9
+ 4 6
+ 1 2 3
+
+These macros are already in the "pref-***.prf" files that ship with
+the standard Angband distribution for some systems, but not all.
+Systems "mac", "win", "x11" have them. If you aren't sure if you have
+them, just try moving in any direction with the shift key down.
+
+[[[[[BThese do have to be macros instead of keymaps], because they rely on
+keypad keys having different scan codes than the top-row number keys.
+
+There are also default macros for Ctrl+<dir> which applies the command
+(+) Alter to that direction.
+
+#####G----------------------------------------------------------------------
+#####G4.15 Farming techniques
+#####G----------------------------------------------------------------------
+
+#####v+++ NOTE: This is considered scumming! (cheating) +++
+
+Farming is the practice of automatically "harvesting" large numbers of
+weaker monsters for their experience value. This is usually done to
+advance a lower level character. There are apparently several methods
+that the "old timers" used to use. I don't know that farming is that
+popular any more. Even then it was sort of a lark.
+
+Apparently a golf ball is just the right size and weight for many
+keyboards to hold a key down and get it to auto repeat. Then you walk
+away, and the next morning you have gained several levels. Ballpoint
+pen caps are also supposed to be good at wedging a key down.
+
+Using a farming macro for long periods of time like this requires a
+way of getting food, so it really needs to be employed by a magic user
+who can create their own food.
+
+Use turn counts with attack (move) commands to move around the room,
+mowing down creatures as you move. Periodically rest enough to
+regenerate to full mana. This may not be necessary if it takes long
+enough to kill the monsters as you move.
+
+This requires an effective macro and a room full of breeders which
+can't attack for enough damage to kill you. Farming for short periods
+of time with a fighter class is quite feasible. The limitation for
+fighters is food. The limitation for spell casters is probably hit
+points. You may also need to insert action sequences for healing if
+the farmed monsters are capable of significantly damaging you.
+
+Note that red and green worm masses can knock down the doors of the
+room you're in. Blues can destroy potions and flasks, so you will need
+to stash your potions outside somewhere before farming.
+~~~~~10
+#####G----------------------------------------------------------------------
+#####G4.16 Macros can contain their own trigger key
+#####G----------------------------------------------------------------------
+
+It is permissible to make a macro or keymap which contains its own key
+in its action. It won't cause recursion, but there are a few wrinkles.
+
+Example: you can bind "*tf1" to the 'f' key, to cause it to auto-fire
+at the nearest target. You can still use the 'f' key for Fire in other
+macros or keymaps.
+
+If you bound 'f' as a keymap you will need to use "\\f" for Fire when
+it is used in a macro action string. You don't need to do anything
+special to use it in a keymap in its usual sense. Keymap and macro
+expansion isn't done inside keymap action strings.
+
+If you bound 'f' as a macro, the problem will be in entering the new
+macro or keymap in the editor. When you try to press an 'f' key for
+the action, it will expand to "*tf1", even when you don't want it to.
+You will first have to remove the macro bound to 'f', then add the
+macro or keymap that uses 'f' in its action, and then reenter the 'f'
+macro. You can also create the macro in a pref file and load it using
+the "Load pref file" command in the (@) Interact with macros screen.
+
+#####G----------------------------------------------------------------------
+#####G4.17 Changing the player's color and character (ASCII text display)
+#####G----------------------------------------------------------------------
+
+#####B= Using the Visuals Editor =
+1) % Interact with visuals.
+2) 6 Change monster attr/chars
+3) a (repeatedly) cycle thru colors (A moves backwards)
+4) c (repeatedly) cycle thru characters (C moves backwards)
+5) Esc accept changes
+6) Esc exit the editor
+
+#####B= Using the Enter User Pref command =
+1) " Enter user pref line
+2) "R:0:<attr>:<char>"
+ The user pref line.
+ <attr> - the attr (color) specified as an integer index.
+ <char> - the (ASCII) character specified as an integer.
+3) (Hit Enter)
+
+You can't directly use the Angband attr letters to specify colors, but
+must instead use their index. Eg 4 is Red. These indexes can be found
+from within the game using the (&) Interact with colors command. That
+editor also allows you to change the colors used by the game.
+
+The <char> integer is generally the index of an (ASCII) character.
+Non-ASCII characters may be available on some systems. Available
+characters can found using the (%) Interact with visuals command.
+
+These integers can be specified in decimal, hexadecimal, or octal
+notation. Decimal is the default, hexadecimal numbers are prefixed
+with "0x", and octal numbers are prefixed with 0 (zero). Example: the
+standard character for the player is '@'. This may be entered as "64",
+"0x40", or "0100". Yellow may be entered as "11", "0x0B", or "013".
+
+This pref line can be added to any pref file to save the change for
+future reuse. Changes made using the internal colors editor screen can
+be dumped from that screen. Note that colors and characters saved in
+pref dumps are in hexadecimal.
+
+After making a change, you must move the character or otherwise cause
+a screen redraw for the change to be visible.
+
+If you make a mistake, you can use the (0) command in the editor to
+reset the visuals to their original colors and characters.
+
+#####B= Changing Using the Monster Info file =
+#####B----------------------------------------
+
+This may also be done by changing the entry for the player in the info
+file "r_info.txt". The player data starts with line "N:0:Player". In
+the following line G:<c>:<a> the character <c> is entered directly,
+and the attr (color) is specified by letter. See the section "Message
+color lines" for the list of standard colors. In many versions you
+will have to delete the file "lib\data\r_info.raw" and restart the
+game for this change to take effect. Note that that char/attr pair is
+entered in the opposite order as for an R: user pref line.
+
+#####B= Options which Change Player appearance =
+#####B------------------------------------------
+
+These are accessible through the (=) Set options command.
+
+*****option.txt*2[(hilite_player)] -- causes the player's symbol to be drawn with the
+"cursor" on it. It will be drawn with the same color as the character.
+
+*****option.txt*3[(player_symbols)] -- for graphics mode only, and only works when option
+(use_graphics) is also on. This apparently varies the player graphic
+and its color based on class, race, and sex.
+
+#####G----------------------------------------------------------------------
+#####G4.18 Recharging a rod using a Recharge Item spell
+#####G----------------------------------------------------------------------
+
+(You can also recharge staffs and wands with this technique.)
+
+Inscribe the rod with {@m<d>}, where <d> is any decimal digit not
+already used as a label.
+
+The trick is that we want to use a digit to label the rod so we can
+refer to it using its label instead of its inventory letter, but we
+have usually used up many of the digits for spell books. If we were to
+label the rod with {@m1} and the first spellbook was also labeled with
+{@m1}, then the spellbook will sort first in the inventory so it will
+be found first when looking for item '1' to use with the (m) command.
+So that would try to recharge the spellbook, which will fail. Angband
+doesn't restrict itself to "appropriate" items when looking for a
+labeled item. It simply finds the first one whose command letter and
+digit match.
+
+You can't get around this by omitting the letter 'm', or using 'z'
+instead. Using no command letter means it will still match. And if you
+use a command letter it has to be 'm', because that is the built-in
+trigger for the current command.
+
+Note that the digits used with different command triggers can be
+different, so inscribing {@z1@m0} is perfectly legal. Use digit 1
+when zapping the rod, and 0 when referring to it during the casting
+of a [mage] spell.
+
+You can also use this technique with scrolls. In that case you need to
+use the inscription {@r<d>} since the item is being referred to while
+processing the (r) Read scroll command.
+
+#####G----------------------------------------------------------------------
+#####G4.19 Disabling a built-in command
+#####G----------------------------------------------------------------------
+
+At times it may be useful to disable an underlying Angband command.
+For example, a dangerous key may be too easy to press by accident.
+The macro editor commands for removing macros and keymaps can't be
+used in this situation. [[[[[BInstead bind the trigger key to the action]
+[[[[[Bstring "\x00"]. This special 'command' takes no "energy" and won't
+generate an error message. It truly does "nothing". This will work for
+both macros and keymaps. If possible you should use a keymap instead
+of a macro to disable the key. A keymap will catch occurrences of the
+key both in macros and by typing, and will still allow you to use the
+key when it isn't being interpreted as a command.
+
+If you use the "Query a macro/keymap" on a trigger key bound to this
+action, it will report having found it, but no action string will be
+printed.
+
+Another technique is to use the action "\e\e\e". This is used in some
+of the standard pref files.
+
+[[[[[BIf you need to use the built-in command again you can use the '\' key]
+[[[[[Bat any prompt to bypass its macro/keymap.]
+
+#####G----------------------------------------------------------------------
+#####G4.20 "Naming" an item (patch)
+#####G----------------------------------------------------------------------
+
+#####B= 'Fake artifact' name =
+# "Name" an item
+This isn't an actual command in the interface, but a flag character
+that alters the way an item description is generated. This isn't part
+of standard Angband. It's added by Tom Morton's 'fake artifact' patch.
+
+Example: inscription {#Thumper} will cause a Club (+8,+8) to display
+as Club 'Thumper' (+8,+8) in your inventory and messages.
+
+~~~~~34
+#####R======================================================================
+#####R5. Common Questions
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G5.1 Why can't I add a keymap for a function key?
+#####G----------------------------------------------------------------------
+
+Because keymaps can only be created for keys with system-independent
+representations. This leaves out function keys, and several other
+special keys. The "Create a keymap" command will continue waiting for
+a keypress until you press a valid keymap trigger. You can, however,
+create a macro for a function key.
+
+#####G----------------------------------------------------------------------
+#####G5.2 How can I automatically inscribe items when I pick them up?
+#####G----------------------------------------------------------------------
+
+You need to turn on the "Merge inscriptions when stacking" option.
+If you are already carrying the same item with an inscription, a new
+one will be added to the stack. Note that this WON'T merge discounts.
+Although discounts display like inscriptions, they are different.
+
+1) = Options
+2) 1 User interface options
+3) "Merge inscriptions when stacking" (stack_force_notes)
+ move down to this line and change to "yes".
+
+#####G----------------------------------------------------------------------
+#####G5.3 Can I use macros inside other macros?
+#####G----------------------------------------------------------------------
+
+No. Macros don't expand macro triggers they contain in their actions,
+in order to avoid recursion and other problems. However, keymap
+substitution is done, so you can use keymaps to alter the behavior of
+macros. This keymap expansion can be bypassed by preceding a trigger
+with "\\" in the action.
+
+Keymaps don't expand macro or keymap triggers in their actions.
+
+Also see section *****macrofaq.txt*9["Can I create an infinite loop using a macro?"].
+
+#####G----------------------------------------------------------------------
+#####G5.4 How do I find out what the standard commands are?
+#####G----------------------------------------------------------------------
+
+1) ? Angband help
+2) 6 *****command.txt*0[Command Descriptions (command.txt)]
+
+Space - moves you down by a page
+Minus - moves up by a page
+2 - moves down by a line
+8 - moves you up by a line
+
+Note that the original and roguelike command sets differ, and both are
+different from the "underlying" command set.
+
+#####G----------------------------------------------------------------------
+#####G5.5 How can I tell if a key has a keymap/macro?
+#####G----------------------------------------------------------------------
+
+#####B= Query Macro/Keymap =
+
+In ToME this is easy:
+1) @ Interact with macros
+2) 3 Query a macro
+OR 7 Query a keymap
+3) (Press the trigger key to test)
+4) Esc (Exit macro editor when done)
+
+It will report "Found no macro" or "Found a macro" at the top of the
+screen. The action it is bound to will be displayed at the bottom of
+the screen, under the "Current action..." line. You must test for both
+macros and keymaps, and keymaps will only show for the current "mode",
+i.e. original/roguelike.
+
+#####B= Notes =
+
+Note: on some machines, there are duplicate keys such as left and right
+Shift keys. These will generally produce different key codes and can
+have different macros and keymaps.
+
+Note: just because a key doesn't have a macro doesn't mean there isn't
+a command that uses that key.
+
+#####G----------------------------------------------------------------------
+#####G5.6 How can I tell if a key has a built-in command bound to it?
+#####G----------------------------------------------------------------------
+
+Er ... try pressing the key. If there is a command bound to that key
+it should usually generate a message of some kind. If there isn't one,
+it may respond: "Type '?' for help.". Some keys may not generate any
+message at all. Function keys are a good example.
+
+In ToME, the game will also generate "silly" error messages
+which may not look like error messages at first. After a few repeated
+key presses it uses the standard "Type '?' for help." message.
+
+Failing that, look in *****command.txt*0["command.txt"], which lists all
+commands, and is up-to-date. There is no specific method for checking if
+a key has a command bound to it from within the game.
+
+#####G----------------------------------------------------------------------
+#####G5.7 Can I inscribe multiple items with the same number?
+#####G----------------------------------------------------------------------
+
+You can, but it can cause problems if you aren't careful. Use the
+command letter in the inscriptions to minimise problems. For example,
+it is safe to inscribe both rods with {@z1} and a spell book with
+{@m1} because the command letter allows distinguishing the two.
+
+When the game looks for an item to use with a command, it tries the
+first one it finds that matches. If the command fails on that item, it
+doesn't continue looking. The search for a matching item also doesn't
+know how to only check the right kind of item, so if you have a Spellbook
+inscribed {@1} and scrolls inscribed {@1} or {@r1}, when you read a
+scroll it will find the spellbook first, even though it doesn't make
+sense to read it, and the command will fail.
+
+#####G----------------------------------------------------------------------
+#####G5.8 How do I convert a macro to a keymap?
+#####G----------------------------------------------------------------------
+
+You can simply remove it and re-add it "by hand", but for more complex
+actions there are faster, safer ways.
+
+#####B= Directly modifying the pref file =
+
+A macro with the following form in the pref file:
+ A:<action string>
+ P:<trigger>\r
+Should be converted to the keymap form:
+ A:<action string>
+ C:0:<trigger>
+The "\r" needs to be removed, and the 0 (zero) means standard keyset.
+Use 1 for roguelike keyset. To make a keymap for both keysets:
+ A:<action string>
+ C:0:<trigger>
+ C:1:<trigger>
+
+#####G= Using the "Interact with Macros" editor =
+
+1) @ Interact with Macros
+2) 3 Query a macro
+ <k> The trigger key for the macro
+ (its action string will now become the current action)
+3) 5 Remove a macro
+ <k> The trigger key for the macro
+4) 8 Create a keymap
+ <k> The trigger key for the keymap
+5) (Hit Enter to accept the current action)
+ (Hit Esc to clear the message "Added a keymap")
+
+This technique can also be used to move or copy actions between macros
+or keymaps of the same kind. [[[[[BAnd old macro MUST be removed from a key]
+[[[[[Bbefore it can be used as the trigger key for a keymap], otherwise the
+macro action will expand when you press the trigger key in the editor.
+Converting a keymap to a macro doesn't require removing the keymap
+first.
+
+Note that not all macros can be converted to keymaps. Keymaps don't do
+macro or keymap expansion on their action strings, so macros that rely
+on this will no longer work. Also, keymaps can only be bound to a
+trigger key with a printable internal representation. For example, a
+function key can't be a trigger for a keymap.
+~~~~~9
+#####G----------------------------------------------------------------------
+#####G5.9 Can I create an infinite loop using a macro?
+#####G----------------------------------------------------------------------
+
+No. Well, okay, you can, but only if you work *really* hard at it and
+abuse bugs in the macro handling code. This isn't something that will
+happen by accident just by using the trigger key inside its action.
+
+You also can't create recursion. So don't worry about this. See the
+section *****macrofaq.txt*10["Macros can contain their own trigger key"] for more info.
+~~~~~4
+#####G----------------------------------------------------------------------
+#####G5.10 What just killed me?
+#####G----------------------------------------------------------------------
+
+When you are using lots of escapes and spaces in your macros to skip
+over messages, you can miss important things happening. One of these
+is dying. Usually when something goes wrong, you can just use the (^P)
+Previous Messages command to see what happened. But if you died the
+escapes can take you past the tombstone screen, your last chance to
+examine the previous messages list. This also happens without macros.
+
+To examine your recall, load the savefile and start a new character.
+You will then be able to use the message recall command to see the
+last messages of that character's previous incarnation.
+
+~~~~~35
+#####R======================================================================
+#####R6. Common Problems
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G6.1 My macro works all the time when I press its key!
+#####G----------------------------------------------------------------------
+
+Macros *do* work all the time. Every time you press a key, macro
+expansion is done on it, and then keymap expansion. So if you use 'y'
+as a trigger key for a macro, and then you try and answer a yes/no
+prompt with 'y', instead you will get the macro's action string.
+
+The answer to this is to change your macro to a keymap. These can be
+bound to keys which have a system-independent representation in the
+game, which includes all keys that you would use when interacting with
+the game interface.
+
+If you don't want to change it to a keymap, try changing the trigger
+key to a "special" key, such as a function key.
+~~~~~6
+#####G----------------------------------------------------------------------
+#####G6.2 My auto-firing macro shoots the wrong target!
+#####G----------------------------------------------------------------------
+
+Your macro is probably firing at the previous target. This will happen
+if the option (*****option.txt*4[use_old_target]) is set. Then a macro will like "f1*t"
+or "m1a*t" will execute as:
+
+f Fire
+1 Ammo inscribed 1
+ (it will now fire at the last [wrong] target)
+* Choose a [new] target
+t Accept first target
+
+If there are no valid targets, the (t) targeting command will centre
+on your position. If you move, the target will still be your old
+square. The first time you use the "f1*t" macro it will fire at that
+square, even if there is now a valid target (monster) nearby.
+
+One fix is to turn off the (use_old_taret) option, since the action
+doesn't require it. This is done with the (=) Set Options command.
+
+Another is to change the action to choose the target before it fires.
+Example: "*tf1".
+
+[[[[[BNote:] just because you can "see" a monster doesn't mean you can target
+it. The code used for vision (line of sight) and firing (projection)
+is slightly different. So when shooting near corners or pillars it may
+happen that you can "see" a monster but not target it. If your action
+kills messages at the end, you could keep hitting your auto-fire macro
+and the only thing happening would be a large pile of missiles quietly
+accumulating underneath you.
+
+#####G----------------------------------------------------------------------
+#####G6.3 I used to have items inscribed, and now they aren't!
+#####G----------------------------------------------------------------------
+
+The game only knows about inscriptions that you are carrying. There is
+no way to "store" them independently of a character's save file. So if
+you lose all of an item that was inscribed, picking up another of that
+kind won't automatically inscribe it.
+
+Normal inscriptions aren't affected by your player's "memory".
+
+Note that some items, when fully identified, could have their
+descriptions grow so long that no inscription will show. In that case
+you can use the (I) Identify command. It will display the full
+description, even if nothing special is known about that item.
+
+#####G----------------------------------------------------------------------
+#####G6.4 I changed some macros in a pref file and nothing happened!
+#####G----------------------------------------------------------------------
+
+Settings loaded in later pref files will overwrite earlier ones. So if
+you add macros for the same trigger key to files "<$CLASS>.prf" and
+"<$PLAYER>.prf", the second one will get used because its file loads
+later. This affects macros, keymaps, actions, attrs/colors, and other
+info. See section *****macrofaq.txt*11["Pref lines summary"] for all the types of settings
+that can be loaded. Also see section *****macrofaq.txt*7["Pref file loading order"].
+
+#####G----------------------------------------------------------------------
+#####G6.5 It moves me when I try to use my bow/rod/wand!
+#####G----------------------------------------------------------------------
+
+Example: you type "f1" and it moves you in direction 1 (South West).
+What is happening is that the 'f' key isn't being handled correctly.
+It may be remapped to a bogus command, or one which doesn't take an
+argument. So the 'f' command is skipped/dealt with, and the '1' key is
+then treated as a direction. You can examine what is going on with the
+'f' key using the (@) Interact with macros screen to check for any
+macros or keymaps bound to that key. Use the appropriate "Remove ..."
+command to restore the built-in Angband command.
+~~~~~3
+#####G----------------------------------------------------------------------
+#####G6.6 My macro drops/takes off my main weapon!
+#####G----------------------------------------------------------------------
+
+This is probably caused by an auto-fire macro like "*tm1a" for magic
+missile. If you hold down the trigger key to repeatedly use it, and
+some game event (possibly caused by the macro) creates a message, then
+the action will be interpreted as:
+* (cancel message)
+t Take off item
+m (ignored as invalid)
+1 (ignored as invalid)
+a Item a (main weapon)
+
+If there is room in your inventory, it will be put there. If not, your
+inventory will overflow and it will be dropped on the ground. If this
+happens during combat this is a very good way to die. This is just
+another good reason to have {!d!k!v} on your main weapon. See the
+section *****macrofaq.txt*12["Prevent unwanted use of an item"].
+
+This can be fixed by using the escape sequence "\e\e\e" before and
+after the action string to cancel any pending messages or commands.
+See the section *****macrofaq.txt*13["Clearing the command buffer"].
+~~~~~2
+#####G----------------------------------------------------------------------
+#####G6.7 My macro outputs "e - Floating Eye" on the message line!
+#####G----------------------------------------------------------------------
+
+It is wise to add an escape sequence "\e\e\e" to the beginning and end
+of all macros for which this doesn't destroy useful information. See
+section *****macrofaq.txt*13["Clearing the command buffer"] for more information on this.
+
+But many players play on flavors of unix, which uses '/' as the path
+separator for files, and automatically type a forward slash when they
+mean to type a backslash. So many actions in macros/keymaps in usenet
+posts have the wrong type of slash. Angband "gurus" are perhaps more
+vulnerable to this than novices.
+
+The game sees this as:
+/ Identify a character
+e Character to be identified
+And outputs "e - Floating Eye" on the message line.
+
+If this sequence gets expanded when you are trying to select an item,
+it will lead to different behaviors.
+Example:
+/ Switch between inventory and equipment
+e Select item e.
+Or:
+/ Switch between inventory and equipment
+e (ignored because invalid) Select item e.
+/ Switch between inventory and equipment
+e Select item e.
+
+~~~~~36
+#####R======================================================================
+#####R7. Inscriptions added by the game
+#####R======================================================================
+
+Some inscriptions are added by the game itself. These can overwrite
+your inscriptions. There are also "fake" and "special" inscriptions,
+which "look" like real inscriptions to the player.
+
+#####G----------------------------------------------------------------------
+#####G7.1 Fake inscriptions
+#####G----------------------------------------------------------------------
+
+These "fake" inscriptions are "covered up" by real inscriptions, but
+will reappear if the real inscription is removed.
+
+"fake" inscriptions are unaffected by the uninscribe command (}).
+
+{cursed} - cursed item
+{empty} - item out of charges
+{tried} - a "flavored" item which the character
+ has used, but whose effects are unknown.
+{N% off} - item bought on sale
+{quest} - this item is a quest item. It may need to be taken to someone.
+
+#####G----------------------------------------------------------------------
+#####G7.2 Auto-inscriptions
+#####G----------------------------------------------------------------------
+
+These added when your character gets a "feeling" about an item.
+In ToME these are "special" inscriptions, like "fake" inscriptions
+above, which don't overwrite user inscriptions. They just hide user
+inscriptions, which are still there.
+
+{terrible} - cursed or broken artifact
+{broken} - broken item
+{cursed} - cursed item
+{uncursed} - previously cursed item
+{average}
+{good} - good (magical) item
+{excellent} - ego item
+{special} - unique item
+{on sale} - displayed only in the store
+
+~~~~~37
+#####R======================================================================
+#####R8. Keys and commands
+#####R======================================================================
+
+This section gives short descriptions of keys and commands used in
+actions and trigger key representations. They are only listed in this
+section if they aren't fully described elsewhere in this FAQ. Not all
+of these keys are actually for "commands". See the normal Angband help
+for a fuller description of these commands. The commands and keysets
+are documented in *****command.txt*0["command.txt"].
+
+#####G----------------------------------------------------------------------
+#####G8.1 Keysets
+#####G----------------------------------------------------------------------
+
+ToME supports two "keysets", which are fully customisable sets of
+keymaps. The "original" command set is close to the built-in commands,
+with some additions for ease of use such as number keys moving you in
+that direction. The "roguelike" command set allows easy movement on a
+keyboard without a numeric keypad. As a consequence its letter keys
+are almost completely "full". These used to be hard-coded by the game,
+but are now fully customisable. The default keymaps are in "pref.prf".
+
+#####G----------------------------------------------------------------------
+#####G8.2 Item selection
+#####G----------------------------------------------------------------------
+
+(*) - gives list of choices
+(-) - selects item on the floor
+(/) - toggles between the inventory and equipment lists.
+
+(space) - shows list of choices. Pressing (space) again hides the list.
+(lower) - selects the inventory item with that letter.
+(upper) - selects the inventory item with that letter, and requires
+ confirmation.
+(digit) - selects first item inscribed with "@#" or "@x#" where 'x' is
+ the command, and '#' is the digit. Only legal items are allowed.
+
+#####G----------------------------------------------------------------------
+#####G8.3 Directions and Movement
+#####G----------------------------------------------------------------------
+
+Original keyset directions
+7 8 9
+4 5 6
+1 2 3
+
+Roguelike keyset directions
+y k u
+h 5 l
+b j n
+
+#####B= Underlying command keys =
+
+;<dir> - walk (with pickup)
++<dir> - alter
+.<dir> - run
+
+Digits AREN'T built-in movement commands in ToME. They are actually
+keymaps found in the standard pref file "pref.prf". The digits are
+direction arguments to the (;) Walk command.
+
+#####G----------------------------------------------------------------------
+#####G8.4 Escape sequences
+#####G----------------------------------------------------------------------
+
+Many [non-printable] characters have a standard printable encoding
+which uses an "escape" character to change the meaning of the
+following character. The backslash character is used as in the C
+language for many keys. The caret '^' is used for control keys.
+
+#####B= Escape sequences =
+\b backspace
+\e escape
+\n newline
+\r return
+\s space
+\t tab
+\xNN hex ASCII char
+\\ (literal) backslash
+\^ (literal) caret
+
+#####B= Backslash =
+In a macro, "\\" followed by a character uses the "underlying" command
+for that character without translation. This is useful in macros to
+avoid keymaps changing the behavior of the macro. In particular this
+can be used to make macros which work for both original and roguelike
+keysets. Keymaps don't have this problem.
+
+#####B= Newline and Return =
+These two characters can be used interchangeably.
+
+#####B= ASCII chars =
+Any ASCII character can be encoded in this way. So many keys will have
+more than one representation. For example, [Enter] can be "\r", "^M",
+and "\x09". The backslash representations are case sensitive, so "\t"
+is [Tab], but "\T" will just be interpreted as "T". The hexadecimal
+number must be exactly 2 digits.
+
+#####B= Escape and Space =
+See section *****macrofaq.txt*13["Clearing the command buffer"] for their main uses.
+
+#####G----------------------------------------------------------------------
+#####G8.5 Repeats and Counts
+#####G----------------------------------------------------------------------
+
+#####B= Auto repeat =
+Some commands will automatically repeat. These are:
+(T) Tunnel
+(B) Bash
+(D) Disarm
+(o) Open
+(c) Close
+(+) Alter
+
+#####B= Number keys =
+
+0 - starts a repeat count. Some commands take a repeat count argument.
+They can be entered as "0<count><cmmd>". If the command is movement,
+it can (must) be preceded by space(s) to separate the direction
+(command) number from the count number.
+~~~~~1
+#####G----------------------------------------------------------------------
+#####G8.6 Messages and Questions
+#####G----------------------------------------------------------------------
+
+#####B= Yes/No queries =
+Yes/No questions can be answered with 'y', 'n', or Esc. These are not
+case sensitive. Only 'y' or 'Y' will respond Yes. 'n', 'N', and Esc
+are No. If the option (quick_messages) is on, any other keypress is
+also No. When the option is off, it will keep waiting for a valid key.
+
+#####B= "-more-" message prompts =
+These may be cleared by Esc(\e), Space(\s), Enter(\r), or Newline(\n).
+If the (quick_messages) option is on, they can be cleared by any key.
+
+#####G----------------------------------------------------------------------
+#####G8.7 Special keys
+#####G----------------------------------------------------------------------
+
+#####B= Function keys =
+Function keys are free for reassignment, but only as macros. [[[[[BFunction]
+[[[[[Bkeys can be modified by Alt, Ctrl, Shift like other keys.]
+
+#####B= Alt keys =
+Alt-modified keys are generally free for reassignment as either macros
+or keymaps.
+
+#####B= Control keys =
+Control keys can be entered in as "^x" where 'x' is the key. Note
+that the case of 'x' is unimportant. This also allows typing control
+keys which would be intercepted by the operating system, such as ^C.
+You must type the caret '^' and the following key separately. Note
+that some have special meanings, such as ^M for Return, and ^H for
+backspace. Some also have special Operating System meanings, such as
+"^Z" in un*x, and "^C" in DOS. Control keys can be trigger keys for
+both macros and keymaps.
+
+#####B= Interrupting the game =
+(^C) This will kill your character and quit the game, after verifying.
+
+#####G----------------------------------------------------------------------
+#####G8.8 Keys used in inscriptions
+#####G----------------------------------------------------------------------
+
+#####B= Confirm command =
+^ Confirm the following command.
+This isn't an actual command, but a character with a special meaning
+inside command strings. {^*} will confirm all actions for the item.
+
+~~~~~38
+#####R======================================================================
+#####R9. Pref files
+#####R======================================================================
+
+All pref files are loaded from and saved to folder "\lib\user". The
+folder "\lib\pref" is unused at this time! The location and name of
+this folder can be configured.
+
+Warning: the directory "\lib\pref" is unused by the game. Pref files
+moved there will never get used (unless the user has redirected the
+folder locations).
+
+Integers can be in hex "0x10", decimal "16", or octal "020" formats.
+These are converted using the C library fn strtol(), and are case
+insensitive.
+
+Decimal numbers start with '1'-'9'.
+Octal numbers must start with '0' (zero).
+Hex numbers start with '0x' or '0X'.
+
+#####G----------------------------------------------------------------------
+#####G9.1 Standard Pref files
+#####G----------------------------------------------------------------------
+
+Below "***" stands for the 3-letter system abbreviations, such as
+"acn", "mac", "win", "x11", ...
+
+"font.prf"
+Includes "font-***.prf" files.
+This file defines special attr/char mappings for "text" mode.
+
+"graf.prf"
+Includes "graf-***.prf" files.
+This file defines special attr/char mappings for "graphics" mode.
+
+"pref.prf"
+Includes "pref-***.prf" files.
+This file defines "default" actions of various kinds. This includes
+mapping the original and roguelike keysets to the underlying keyset.
+
+"user.prf"
+Includes "user-***.prf" files.
+This file defines "override" actions of various kinds. It includes the
+pref files based on system, race, and class.
+
+"xtra-***.prf"
+This file defines special attr/char mappings for "graphics" mode.
+Currently this just maps the player icon based on race and class.
+"new" refers to Adam Bolt's tiles.
+
+[[[[[vWarning:] you shouldn't edit the base pref files without a good reason,
+and understanding what you are doing. Breaking these files can make
+your game unusable. They are, however, the place to make changes that
+should affect all users.
+~~~~~7
+#####G----------------------------------------------------------------------
+#####G9.2 Pref file loading order
+#####G----------------------------------------------------------------------
+
+This loading order follows from the order of includes in "pref.prf".
+Files which are "hard-coded" in the source are preceded with an index.
+The rest are included by the other files. Files which come later will
+overwrite settings from earlier files.
+
+(1) "pref.prf"
+ "message.prf"
+ "pref-***.prf"
+
+(2) "graf.prf"
+ "font-xxx.prf"
+ "graf-***.prf"
+
+(3) "font.prf"
+ "font-xxx.prf"
+ "font-***.prf"
+
+(4) "user.prf"
+ "user-***.prf"
+ "<$RACE>.prf"
+ "<$CLASS>.prf"
+
+(5) "<$PLAYER>.prf"
+
+(6) ".angband.prf"
+
+
+= $RACE =
+Can be one of any of the races in ToME.
+
+= $CLASS =
+Can be one of any of the classes in ToME.
+
+= $PLAYER =
+The name of the current player being loaded or born. See section
+*****macrofaq.txt*15["Automatically loading pref files"] for more information.
+
+#####B= Specific pref files =
+#####B-----------------------------------
+
+"user-mac.prf"
+This is the only user pref file with example macros that ships with
+ToME. A good set of examples.
+
+"pref-win.prf"
+This is the same as (missing) "pref-dos.prf" and "pref-ibm.prf".
+
+"colours.prf"
+Amiga only. Contains Amiga palette.
+
+".angband.prf"
+Only on multi-user systems. This doesn't ship with the source. This
+file must be located in the directory contained in environ variable
+"HOME".
+~~~~~11
+#####G----------------------------------------------------------------------
+#####G9.3 Pref lines summary
+#####G----------------------------------------------------------------------
+
+Comment lines start with a '#' and extend to end of line.
+
+Note: integer values can be specified as decimal, as hexadecimal by
+preceding with an "x", or as octal by using a leading "0" (zero).
+
+E:<tv>:<a> - attr/char values for inventory objects by index
+F:<num>:<a>:<c> - attr/char values for features by index
+K:<num>:<a>:<c> - attr/char values for objects by index
+R:<num>:<a>:<c> - attr/char values for monsters by index
+S:<num>:<a>:<c> - attr/char values for special things by index
+
+A:<str> - action line
+ An action line should be followed by a keymap trigger "C:" line
+ or a macro trigger "P:" line. There can be intervening comments
+ and lines. The same action will be [re]used by all keymap and
+ command lines which follow it until there is another action line.
+P:<str> - macro line
+ <str> a macro encoding of a keypress. (system dependent)
+C:<mode>:<str> - keymap line
+ <mode> 0 = "original, 1 = "roguelike".
+ <str> logical keypress, including backslash codes such as "\e" and
+ control codes such as "^K". (system independent)
+ Note that there are 2 independent sets of keymaps now. Changing a
+ keymap in one doesn't affect the other.
+
+V:<num>:<kv>:<rv>:<gv>:<bv> - specify visual information
+ <num> is the color index (0-255, only 0-15 used)
+ <kv> black (?) value -- unused
+ <rv> red value (0-255)
+ <gv> green value (0-255)
+ <bv> blue value (0-255)
+W:<win>:<flag>:<value> - turn a window flag on/off.
+ <win> window number (1-7)
+ <flag> (0-31)
+ <value> 0 = off, 1 = on
+
+X:<str> - turn option off
+Y:<str> - turn option on
+ <str> the name of an option in option_text[].
+ These are the names displayed in the options screen (=).
+
+?: - conditional expression
+%: - include another pref file
+
+#####G----------------------------------------------------------------------
+#####G9.4 Option lines "X:" and "Y:"
+#####G----------------------------------------------------------------------
+
+Options and their descriptions are listed in help file *****option.txt*0["option.txt"].
+These options are set within the game using the (=) Options command,
+and the option names are the ones displayed within parentheses in the
+options screen.
+
+#####B= Common options =
+rogue_like_commands
+use_old_target
+always_pickup
+depth_in_feet
+alert_hitpoint
+auto_haggle
+auto_scum
+
+#####G----------------------------------------------------------------------
+#####G9.5 Conditional expression lines "?:"
+#####G----------------------------------------------------------------------
+
+expressions are lisp-like prefix notation.
+names (class, race, ...) aren't placed in quotes.
+AND - logical AND
+IOR - inclusive OR
+EQU - (string) equals
+NOT - logical negation
+LEQ - (string) less than or equal to
+GEQ - (string) greater than or equal to
+[,] - group expressions
+$CLASS - current class
+$GRAF - 3-letter graphics abbr in "graf-***.prf" (old, new)
+$PLAYER - current player name
+$RACE - current race
+$SYS - 3-letter system abbr in "pref-***.prf" (ami, mac, win,...)
+
+0 - false
+1 - true (can't just be non-zero)
+
+If the conditional expression is false all pref file commands
+encountered until the next conditional pref line are skipped.
+
+This isn't an actual command. It only works in pref files.
+
+The variables $CLASS, $GRAF, $PLAYER, $RACE, $PLAYER, $SYS and the
+string values they take on are case sensitive. The values also can't
+contain spaces. These constraints on the values hold when they are
+used in a pref file, but might not when used as pref filenames.
+
+This can be "turned back on" using the pref line "?:1", which is
+generally the last line in a file which contains conditional macros,
+to make sure that any files loaded after it don't get ignored as well.
+
+#####G----------------------------------------------------------------------
+#####G9.6 Macro trigger lines "P:"
+#####G----------------------------------------------------------------------
+
+All "special" keys are translated by "main-***.c" into encoded "macro
+triggers". These macro triggers have the encoded form "^_MMMxSS\r",
+where the "modifier" flags are stored in "MMM", and the two digit
+hexadecimal scan code of the keypress is stored in "SS". See source
+file "main-ibm.c" and others for more info. Note that because these
+scan codes are system-dependent, macro trigger encodings are as well.
+Keymaps are used for system independent mapping of triggers to actions.
+
+#####BModifier flags
+
+A - Alt
+C - Control
+S - Shift
+O - Option key (Mac)
+
+#####BIBM Scan codes
+
+x47 - keypad 7
+x48 - keypad 8
+x49 - keypad 9
+x4A - keypad -
+x4B - keypad 4
+x4C - keypad 5
+x4D - keypad 6
+x4E - keypad +
+x4F - keypad 1
+x50 - keypad 2
+x51 - keypad 3
+x52 - keypad Ins / .
+x53 - keypad Del / Enter
+x45 - Pause
+
+Others can be found using the "Query a macro" feature.
+
+Note that scan codes can't be assumed to be "in order", even for keys
+like function keys which "logically" should be!
+
+Note that you can't always just add a modifier to a known scan code
+because that combination might not be recognised by the hardware or
+the translation code in "main-***.c".
+
+Example: a Windows system will recognise function key F1, Shift-F1,
+and Ctrl-F1, but not Ctrl-Shift-F1. Similarly Pause and Alt-Pause are
+recognised, but not Ctrl-Pause, and Shift-Pause gives the same
+encoding as Pause alone.
+
+#####G----------------------------------------------------------------------
+#####G9.7 Saving to a pref file
+#####G----------------------------------------------------------------------
+
+Commands "Append macros to file" and "Append keymaps to file" don't
+erase the previous macros or keymaps. Instead they are appended. Note
+that this can produce *large* files after a while. Newer versions
+append to "<$PLAYER>.prf" by default, whereas older versions appended
+to "user.prf". The appended sections are preceded by headers of the
+form "Automatic macro/keymap dump". Using a distinctive comment line
+such as ###... after your entries can make editing the appended ones
+easier.
+
+[[[[[BNote: macros and keymaps aren't saved in the character file, so they]
+[[[[[Bmust be saved separately. All macros and keymaps entered by the user]
+[[[[[Bare lost when Angband terminates.]
+
+Note: keeping macros in the <$PLAYER>.prf files allows several users
+to share the same installation without interfering with each other.
+You can easily reuse or share preferences by moving them into a pref
+file "<my-name>.prf" and using the pref line "%:<my-name>.prf" to
+include them in "user.prf" for single user installations, or
+<$PLAYER>.prf for multi-user installations.
+
+#####G----------------------------------------------------------------------
+#####G9.8 Editing pref files
+#####G----------------------------------------------------------------------
+
+This is still most easily done in a text editor.
+
+~~~~~39
+#####R======================================================================
+#####R10. Macro editing commands
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G10.1 (") Enter a User Pref Command
+#####G----------------------------------------------------------------------
+
+This allows entering a single pref line.
+Example: "X:auto_scum" turns auto-scum off.
+
+Example "A:<str>" sets the current action string. If you open the
+"Interact with macros" screen this action will be the default used.
+Then using the (") command again with "P:<key>" will create a macro
+for the action <str> previously entered.
+
+Not all pref commands can be used here, or are meaningful.
+The "pseudo" pref commands (?), (%) cannot be used here.
+
+See section *****macrofaq.txt*20["Advanced macro techniques"] for ways to [ab]use this.
+
+#####G----------------------------------------------------------------------
+#####G10.2 (@) Interact with macros
+#####G----------------------------------------------------------------------
+
+#####B= Vanilla command set = (2.8.3 - 2.9.1)
+#####B-----------------------------------
+Load a user pref file
+Append macros to a file
+Query a macro action
+Create a macro
+Remove a macro
+Append keymaps to a file
+Query a keymap
+Create a keymap
+Remove a keymap
+Enter a new action
+
+#####B= Load a user pref file =
+#####B-----------------------------------
+Loads a user pref file from "lib\user". Defaults to the name of the
+current character. Macros/keymaps loaded will replace existing ones.
+
+#####B= Append macros to a file =
+#####B-----------------------------------
+Macros are dumped in macro list order. Newer ones are at the end.
+Macros are *appended* to the file. The old one isn't overwritten. This
+prevents you from accidentally wiping out your old pref file. However,
+the file can grow very long without your noticing it. Placing a line
+of ###'s at the end of your macros can help sort out what is what.
+Macros are labeled with comment "# Macro 'NNN' ". These numbers are the
+internal macro list numbers, and have no relation to key scan codes.
+The filename must end in ".prf". It will save correctly without this
+extension, or with a different one, but if you save as "<$NAME>"
+instead of "<$NAME>.prf", it won't be automatically loaded when you
+load the character with that name.
+
+#####B= Query a macro =
+#####B-----------------------------------
+Press the trigger key to test at the prompt.
+This will show "Found a macro" on the message line if it found one,
+and the line "Trigger: <trigger>". This will show "Found no macro"
+on the message line if it didn't find a macro. Some keys such as
+function keys won't be recognised by the prompt. It will wait until
+you hit a key it recognises.
+
+This command doesn't alter any settings. It will return to the main
+menu after you hit any key it recognises.
+
+#####B= Create a macro =
+#####B-----------------------------------
+After choosing this command, press the trigger key for the macro.
+The internal form will be shown after the "Trigger: " prompt.
+Note that some keys may not be recognised for remapping, such as the
+new Windows keys, as well as modifier keys such as Alt, Control, Shift
+pressed by themselves. In this case it will continue to wait for a
+valid trigger key.
+
+The current action (if any) will be shown *below* the "Trigger: "
+prompt line. On the prompt line ("Action: ") will be shown the last
+macro sequence entered. This is the action in the "action buffer".
+This isn't necessarily the macro sequence currently bound to this key.
+This is the action that will be bound to the current trigger key if
+you hit Enter.
+
+You may type in an action string to replace the one after the prompt.
+Hit Enter when you are finished.
+
+For ToME you can quit the command assignment by hitting
+Esc. The new action entered won't be assigned, and the previous one
+will remain unaltered.
+
+#####B= Remove a macro =
+#####B-----------------------------------
+Removes the macro from the trigger key by creating an identity macro
+on that key for itself. So the macro isn't completely removed, just
+overwritten. The new identity macro will be saved when the macros are
+appended to a file. This is different from the "Remove a keymap"
+command, which completely removes the keymap.
+
+#####B----------------------------------------------------------------------
+The following "keymap" commands only apply to the current "mode"
+(original/roguelike). Keymaps for the other mode will be unaffected.
+Because keymaps can only be bound to trigger keys which have a system
+independent representation, some key presses won't be recognised by
+these editing commands. They will instead wait until you press a valid
+trigger key.
+#####B----------------------------------------------------------------------
+
+#####B= Append keymaps to a file =
+#####B-----------------------------------
+Works just like "Append macros to a file". These are appended after a
+header comment "# Automatic keymap dump".
+
+#####B= Query a keymap =
+#####B-----------------------------------
+Works just like "Query a macro". This will show "Found a keymap" on
+the message line if it found one, and will display "Keypress: <map>".
+This will show "Found no keymap" on the message line if it didn't
+find a keymap. This command doesn't alter any settings. It will return
+to the main menu after you hit any key it recognises.
+
+#####B= Create a keymap =
+#####B-----------------------------------
+Works just like the "Create a macro" command. Keymaps can only be
+assigned to keys which have a system independent representation. Note
+that creating a keymap will cause the behavior of any macro whose
+action string contains that key to change.
+
+#####B= Remove a keymap =
+#####B-----------------------------------
+Removes the keymap completely from the trigger key. If the key had a
+built-in command it can now be used again. Note that removing a keymap
+will cause the behavior of any macro whose action string contained
+that key to change. This behaves differently from the "Remove a macro"
+command, which creates an identity macro.
+
+If the original "command" was itself a keymap, removing a user-entered
+keymap won't restore it. Example: the key (n) is bound to the built-in
+command "Repeat last action" in file "pref.prf" via a keymap. If you
+add a keymap for (n) and then remove it, the "Repeat last command"
+functionality won't be restored. You will have to add it back by hand,
+or reload a pref file that contains that stored keymap. [[[[[BIn particular]
+[[[[[Balmost all roguelike commands are now implemented as keymaps.]
+
+#####B= Enter a new action =
+#####B-----------------------------------
+Allows entering a new action. Actions are entered into a static buffer
+which is shared by both macros and keymaps. The action string entered
+will become the default action for creating a keymap or action, and
+will only change when a keymap or macro is created with a different
+action string, or when one is queried. Note that the same action can
+be bound to multiple trigger keys by hitting Enter when using the
+commands to create a keymap/macro.
+
+~~~~~20
+#####R======================================================================
+#####R11. Advanced Macro Techniques
+#####R======================================================================
+
+This section outlines advanced techniques not really required for game
+play. But macros become addictive after a while ...
+
+Action strings in this section are enclosed in braces {} because many
+use a double quote (") inside the action string. These are not
+inscriptions.
+
+#####G----------------------------------------------------------------------
+#####G11.1 Set current action using (@) command in an action
+#####G----------------------------------------------------------------------
+
+{"@0<str>\r\e}
+@ - Interact with macros
+0 - Enter a new action
+<str>- (action string)
+\r - Enter the action
+\e - Exit the macro editor
+
+This will work when bound to a macro.
+
+#####G----------------------------------------------------------------------
+#####G11.2 Set current action using (") command in an action
+#####G----------------------------------------------------------------------
+
+{"A:<action>\r} - sets the current action.
+" - Enter pref line
+A: - Action line
+<str>- (action string)
+\r - Enter the action
+
+This works in either a macro or keymap.
+
+#####G----------------------------------------------------------------------
+#####G11.3 Create a new keymap using (") command in an action
+#####G----------------------------------------------------------------------
+
+{"A:<act>\r"C:0:<key>\r}
+Here <act> can't contain an '\r' or '\e'.
+
+Example {"A:z0\r"C:0:J\r} binds action "z0" to (standard) keymap 'J'.
+
+#####G----------------------------------------------------------------------
+#####G11.4 Create a new macro using (") command in an action
+#####G----------------------------------------------------------------------
+
+{"A:<act>\r"P:<key>\r}
+Here <act> can't contain an '\r' or '\e'.
+Here <key> is a standard key. (not a "special" one like F1, \b, or ^A)
+
+Example
+{"A:<action1>\r"P:j\r} binds action <action1> to trigger 'j'.
+{"A:<action2>\r"P:j\r} binds action <action2> to trigger 'j'.
+If we bind these 2 macros to different trigger keys, the action that
+is on key (j) can be swapped back and forth.
+
+#####G----------------------------------------------------------------------
+#####G11.5 Turning an option on/off in an action
+#####G----------------------------------------------------------------------
+
+Turn an option on:
+{"Y:<option_name>\r}
+
+Turn an option of:
+{"Y:<option_name>\r}
+
+Example: Turn (quick_messages) on, do an action, and turn it back off:
+{"Y:quick_messages\r<action>"X:quick_messages\r}
+
+This will work in either a macro or keymap. <option_name> is the name
+of the option as it appears in the option editor accessed through the
+(=) command. These are also listed in the help file *****option.txt*0["option.txt"]. Note
+that option names contain underscores instead of spaces.
+
+#####G----------------------------------------------------------------------
+#####G11.6 Inscribe/Uninscribe an item in an action
+#####G----------------------------------------------------------------------
+
+(These action strings are enclosed in double quotes)
+
+Inscribe an item:
+"{<item>\s<inscr>\r"
+
+Uninscribe an item:
+"}<item>\r"
+
+<item> must be the inventory letter of the item, possibly preceded by
+a '/' to switch to the equipment list. You can't use digit labels for
+items with inscriptions that contain the command triggers '{' or '}',
+but you can use "@<digit>".
+
+This will work in either a macro or keymap.
+
+~~~~~41
+#####R======================================================================
+#####R12. Problems
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G12.1 Keys to avoid remapping
+#####G----------------------------------------------------------------------
+
+These don't really *need* to be avoided, but all carry dangers of one
+kind or another. You should think through potential problems before
+deciding to use them. You have been warned.
+
+#####B= Navigation keys =
+Enter, Esc, Backspace, ...
+These aren't a good choice unless you *really* need them. If you do it
+is far better to use keymaps. If you bind a macro to the Enter key,
+you will lose the ability to enter line-based commands like Inscribe.
+
+#####B= Commands generated internally =
+(_) Enter store
+This command is generated internally by the game when the player moves
+onto the door of a store. In some versions, if this key has a keymap
+bound to it, that will fire when you try to enter a store.
+
+#####B= Keys with important Operating System meanings =
+^Z (un*x) Suspends the game and returns to the command shell. This
+ is an operating system command, not an Angband command.
+ Command "fg" returns to Angband.
+^\, ^D, ^S
+ These are keys that shouldn't be bound to macros or have their
+ behavior altered.
+
+#####B= Keys with dangerous ToME meanings =
+(Q) Quit (commit suicide), (k) destroy item, (^A) Enter Debug mode...
+Using these as triggers is dangerous in case, for some reason, you
+wind up in a situation where the macro hasn't loaded or is disabled.
+You also don't want to get into a habit of typing these too fast.
+
+#####B= Selection keys =
+(e) Equipment, (i) Inventory, (-) Floor item, (/) Switch inventory
+lists. You should avoid binding these as macro triggers, to prevent
+making inventory and choice management next to impossible. But even as
+keymaps they hold some dangers.
+Example: you bind keymap on '-' to destroy item on the floor. Now if
+you try to do an action on a floor item, and it fails (such as using
+rod to identify), then the '-' can be taken from the input stream and
+used as a keymap, which would destroy the item you tried to identify.
+
+#####B= Response keys =
+(y) yes, (n) no, (Esc) cancel, (Space) skip message,...
+Binding macros to these is a [[[[[vVery Bad Idea.] Macro expansion will then
+be done when you answer a question like "Are you sure you want to quit
+the game without saving?". The expanded macro action string will be
+used as the input, and may not lead to the answer you were trying for.
+Keymaps don't have this problem. As a rule you should never use a
+macro instead of a keymap unless necessary.
+
+#####G----------------------------------------------------------------------
+#####G12.2 Num lock
+#####G----------------------------------------------------------------------
+
+Whether/not NumLock is on can make a difference for some macros.
+For example, if NumLock is on under X11 the 'X' macro won't work.
+
+#####G----------------------------------------------------------------------
+#####G12.3 Recovering
+#####G----------------------------------------------------------------------
+
+Restarting ToME clears all macros entered during the last session.
+
+You can use "Load a pref file" in the "Interact with macros" screen to
+reload a good set of prefs, overwriting bad ones being used. This will
+not "erase" a macro/keymap which doesn't have a corresponding saved
+one in the pref file. So if you add a macro/keymap to a trigger key
+which didn't have anything bound to it, reloading the pref file won't
+restore the key to its original state.
+
+If you still have problems, restore or edit any modified *.prf files
+that might be loaded.
+
+Try saving your macros, and examine them to see what went wrong.
+
+[[[[[BYou can use the backspace '\' key at the command prompt to use the]
+[[[[[Boriginal "underlying" command bound to that key. For example, if you]
+[[[[[Bbound the key '@' to a macro, you wouldn't be able to enter the macro]
+[[[[[Beditor to rebind it to itself.] Pressing '\' first, then '@' causes the
+command handler to use the built-in command, which allows you to enter
+the command editor. Note: when you use the backspace inside an action
+string, you have to double it as "\\". Do not use just a single back-
+slash, or it will be ignored, and possibly alter the meaning of the
+character that follows it.
+
+You can remove a macro/keymap from an essential key (such as the Esc
+key). Use the (@) "Interact with macros" command to access the remove
+commands.
+
+#####G----------------------------------------------------------------------
+#####G12.4 Unrecognised keys
+#####G----------------------------------------------------------------------
+
+#####B= Un*x =
+
+Function keys may not be recognised on some Un*x systems.
+
+#####B= PC/Dos/Windows =
+Doesn't recognise the WINDOWS key (start menu) or the APPLICATION key
+(context menu).
+
+On some systems, doesn't recognise modifier keys (Alt, Ctrl, Shift) on
+keypad keys when NumLock is on.
+
+See special_key_list[] in "main-win.c" for list of "special" keys that
+are recognised.
+
+#####G----------------------------------------------------------------------
+#####G12.5 Nonexistent commands
+#####G----------------------------------------------------------------------
+
+Macros and keymaps can only be bound to keypresses. The game state
+changing isn't a keypress, so you can't trigger an action when you
+become hungry, blind, confused, slowed, pseudo-id an item, pick up an
+item, gain a level, have a rod recharge, or any other event that isn't
+directly triggered by a keypress.
+
+"Attacking" also isn't a command, but you can use commands (+) Alter
+grid, (;) Walk, and (.) Run.
+
+So you don't really _attack_ Morgoth, you just _alter_ him. First he's
+alive, then he's not. :)
+
+#####G----------------------------------------------------------------------
+#####G12.6 File permissions
+#####G----------------------------------------------------------------------
+
+If you lack write permission to the pref file currently loaded by the
+game, try saving to a file with a new name. The macros can be copied
+over "by hand" later.
+
+~~~~~42
+#####R======================================================================
+#####R13. Miscellaneous
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G13.1 References
+#####G----------------------------------------------------------------------
+
+*****command.txt*0["COMMAND.TXT"]
+- lists standard and roguelike keys and commands. full descriptions.
+- long description of command behavior.
+- intro to macros and user pref files.
+
+*****dungeon.txt*8["DUNGEON.TXT"]
+- look under "Objects Found in the Dungeon".
+
+*****option.txt*0["OPTION.TXT"]
+- list of options and their descriptions.
+
+"INSCRIPTIONS.HTML"
+- short intro by Julian Lighton. Available from
+"http://www.fragment.com/~jl8e/angband/inscriptions.html".
+
+#####G----------------------------------------------------------------------
+#####G13.2 Contributors
+#####G----------------------------------------------------------------------
+
+This FAQ was largely compiled from newsgroup postings to "r.g.r.a".
+So thanks to the generous contributors to the newsgroup! Email
+addresses have been removed to foil spam-bots.
+
+Ben Harrison -- maintainer: Angband 2.7.1 - 2.8.5, =Ben= in source.
+Robert Ruehlman -- maintainer: Angband 2.9.0 - present.
+DarkGod -- maintainer: PernAngband 2.9.9a - present
+
+Scott Bigham, DamonShawX, Jonathan Ellis, George W. Harris, Roger
+Hoyle, Graham S. Johnson, Chris Kern, Matthias Kurzke, Steve Lamb,
+Julian Lighton, Art Mruczek, Daniel Nash, Timo Pietilä, Jack Wise,
+Greg Wooledge, and others.
+
+#####G----------------------------------------------------------------------
+#####G13.3 Legalese
+#####G----------------------------------------------------------------------
+
+Copyright 2000 Jim Lyon and others. Redistribution of unaltered copies
+of this document is permitted without restriction. Distribution of
+altered copies is permitted without restriction as long as the
+alteration does not significantly alter the content. (For example,
+translation and conversion to another format is permitted.)
+Distribution of all other altered copies is permitted as long as credit
+for previous authors is maintained, the contact information is
+replaced with that of the alterer, and redistribution is not further
+restricted.
+
+Edited for PernAngband V5.x.x by Dawnmist with permission from Jim Lyon
+August 2001. All comments to angband@dawnmist.8m.com
diff --git a/lib/help/magic.hlp b/lib/help/magic.hlp
new file mode 100644
index 00000000..382451c3
--- /dev/null
+++ b/lib/help/magic.hlp
@@ -0,0 +1,41 @@
+|||||oy
+~~~~~01|Magic|Index
+~~~~~02|Help|Magic
+#####RWelcome to the ToME Magic Help System.
+#####R=============================================
+
+Please choose one of the following help files:
+
+General Info
+
+ *****/amagic.txt*0[(a) The ToME magic system]
+ *****/bmagic.txt*02[(b) Wands and Staves]
+
+Magic schools
+
+ *****/cm_air.txt*0[(c) The Air School]
+ *****/dm_convey.txt*0[(d) The Conveyance School]
+ *****/em_demono.txt*0[(e) The Demonology School]
+ *****/fm_divin.txt*0[(f) The Divination School]
+ *****/gm_earth.txt*0[(g) The Earth School]
+ *****/hm_fire.txt*0[(h) The Fire School]
+ *****/im_geoman.txt*0[(i) The Geomancy School]
+ *****/jm_mana.txt*0[(j) The Mana School]
+ *****/km_meta.txt*0[(k) The Meta School]
+ *****/lm_mind.txt*0[(l) The Mind School]
+ *****/mm_nature.txt*0[(m) The Nature School]
+ *****/nm_necrom.txt*0[(n) The Necromancy School]
+ *****/om_tempo.txt*0[(o) The Temporal School]
+ *****/pm_udun.txt*0[(p) The Udun School]
+ *****/qm_water.txt*0[(q) The Water School]
+
+Other powers accessed by the 'm' menu
+
+ *****/rm_mimic.txt*0[(r) Mimicry Powers]
+ *****/sm_mindcr.txt*0[(s) Mindcrafting Powers]
+ *****/tm_music.txt*0[(t) Musical Songs]
+ *****/um_symbio.txt*0[(u) Symbiotic Powers]
+ *****/vm_thaum.txt*0[(v) Thaumaturgical Spells]
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
+ \ No newline at end of file
diff --git a/lib/help/magic.txt b/lib/help/magic.txt
new file mode 100644
index 00000000..93486f0b
--- /dev/null
+++ b/lib/help/magic.txt
@@ -0,0 +1,143 @@
+|||||oy
+~~~~~03|Magic
+#####R === ToME Magic system ===
+
+*****magic.txt*02[Wands and Staves]
+
+For the basics of how to use skills, please see *****skills.txt*0[Using Skills].
+
+In ToME you have a basic *****skills.txt*21[Magic] skill. This skill is one of the most
+important ones for a spellcaster, since it is responsible for how much mana you
+have. You can never have too much of it. If you like magical devices, the
+Magical Device skill is also important, since it controls the Magical
+Device ability of your character. This ability again dictates the fail rates
+of use of wands/rods/staffs and activation of random-artifacts/artifacts, and
+it will also increase the power of these items.
+~~~~~01|Magic|Schools
+ToME uses skills to define the various schools of magic. There are 11 primary
+schools:
+ *****m_mana.txt*0[Mana] *****m_fire.txt*0[Fire] *****m_water.txt*0[Water]
+ *****m_air.txt*0[Air] *****m_earth.txt*0[Earth] *****m_meta.txt*0[Meta]
+ *****m_convey.txt*0[Conveyance] *****m_divin.txt*0[Divination] *****m_tempo.txt*0[Temporal]
+ *****m_mind.txt*0[Mind] *****m_nature.txt*0[Nature]
+
+Other magical skills, generally being used primarily by characters of a
+specific class, are:
+ *****m_demono.txt*0[Demonology] *****m_necrom.txt*0[Necromancy] *****skills.txt*36[Runecraft]
+ *****m_thaum.txt*0[Thaumaturgy] *****skills.txt*49[Alchemy] *****m_geoman.txt*0[Geomancy]
+
+The *****m_demono.txt*0[Demonology] skill is primarily used by *****c_demono.txt*0[Demonologists] for their special
+spells, whereas the *****m_necrom.txt*0[Necromancy] skill is used by *****c_necro.txt*0[Necromancers] for their own set
+of special spells.
+The same goes for *****skills.txt*36[Runecraft], which is used by *****c_runecr.txt*0[Runecrafters] to allow use of more
+difficult runes or rune-combinations. *****m_thaum.txt*0[Thaumaturgy] gives you randomly chosen
+attack spells, and as such each game with it will be different. *****c_geoman.txt*0[Geomancers]
+harness the powers of the elements using *****m_geoman.txt*0[Geomancy]. Lastly we have
+*****skills.txt*49[Alchemy], which is used by *****c_alchem.txt*0[Alchemists].
+
+In addition to the schools of magic, you can get access to special sets of
+spells if you worship a God. There are currently four good Gods,
+*****g_eru.txt*0[Eru Iluvatar], *****g_manwe.txt*0[Manwe Sulimo], *****g_yavann.txt*0[Yavanna Kementari] and *****g_tulkas.txt*0[Tulkas]. There is also an evil
+god, *****g_melkor.txt*0[Melkor]. Each of them gives you access to different types of spells.
+
+*****c_pr_drk.txt*0[Worshippers of Melkor] also have access to the special *****m_udun.txt*0[Udun] school of magic,
+whereas other *****c_priest.txt*0[Priests] and *****c_mindcr.txt*0[Mindcrafters] can use *****m_mindcr.txt*0[Mindcrafting Powers].
+
+*****c_symbia.txt*0[Symbiants] have access to their own special brand of *****m_symbio.txt*0[magic powers], and *****c_bard.txt*0[Bards] have
+access to *****m_music.txt*0[Songs], which affect creatures in ways that can appear to be magical.
+
+The 11 different primary schools give you access to different spells of
+variable usefulness. The way they work is that adding skill points to a
+specific school will enable you to get higher level spells for that specific
+school. By level requirements for a specific spell you could actually say skill
+requirement, since they correlate exactly. Let's take a simple example:
+If you have the *****m_mana.txt*0[Mana] school skill at level 24.000, it means you can use any
+spell in the mana school up to and including those requiring level 24. [[[[[BThere are]
+[[[[[Balso some spells requiring a certain skill level in two schools, and there is a]
+[[[[[Bpossibility of spells requiring three or more. For this kind of spells the ]
+[[[[[Bspell level is determined by taking an average of the necessary skills. ]
+When calculating spell level for spells which require more than one school,
+sorcery (or god-granted access) can be used in place of the primary schools in
+the normal way. Once the average has been calculated, any bonus from the
+spell-power skill can also be applied as normal. If one of the schools required
+is the Udun school, then the appropriate bonus from character level will be
+applied. Lastly, if you look at a spell, and the spell level reads -2 or some
+other negative value while it's also grayed out, that means you need to
+increase the corresponding school's skill level by 3, since only 2 will have
+it end up on spell level 0, where it still is unusable. If it reads n/a, you
+currently have no skill points in that school.
+
+Another thing that should be explained about the skills and schools of magic
+right now, is that the skill doesn't stop being useful only for gaining spells.
+The higher the skill level, the higher the spell level will be, and the more
+powerful your spells will be. For instance, say you have the *****m_mana.txt*0[Mana] skill at
+level 24. Now, the Manathrust spell is one of the spells for that school
+that only requires skill level 1, but since you've got skill at level 24, the
+power of the spell is increased as well. For comparison, a level 1
+Manathrust costs 1 mana and does 4d2 damage, while at level 24 it costs 12
+mana and does a whopping 27d10 damage.
+
+The *****skills.txt*23[Sorcery] skill is a nice skill, since it gives you
+access to all the 11 primary schools of magic, just as if you'd spent an equal
+amount of skill points in all the skills. It's available to any mage character,
+but only a *****c_sorcer.txt*0[Sorceror] will be able to be proficient in it. Also, having this
+skill at level 1 will give you a hitpoint-penalty of 1%, all the way up to
+skill level 50, with a hitpoint-penalty of 50%. There are also ToHit and ToDam
+penalties for sorcery, so don't choose sorcery if you plan to do much fighting.
+
+There is also the *****skills.txt*22[Spell Power] skill. This skill is rather nice, since it
+will augment the power of spells you already know. The distinction between this
+and the others, is that it will not grant you new spells, but instead increases
+the levels of spells. At level 50 it grants 20 extra spell levels. [[[[[BThis skill ]
+[[[[[Bonly affects the 11 primary schools] (Mana, Earth, Air, Fire, Water, Meta,
+Mind, Temporal, Conveyance, Divination and Nature) as well as Geomancy and the
+spells granted by the Gods.
+
+There is also the Magic-Device skill which affects your ability to use wands,
+staves, rods and to activate special objects. It also affects the spell-levels
+of the staff and wand spells, as explained below.
+~~~~~02|Wands
+~~~~~04|Magic|Wands and Staves
+~~~~~05|Staves
+#####GWands and Staves
+
+Wands and staves (sticks) operate in a similar fashion, and in fact most of
+them use the same spells with the same effects. When you pick up a stick, you'll
+see it has two numbers in the format [x|y] in addition to the number of charges
+it holds. By increasing your magic-device skill you can increase the level (and
+hence the power) of the spell in that stick. The x value are skill level
+bonuses which the staff itself holds, and these are added onto your existing
+magic-device skill for the purpose of using the staff. The y value is the
+maximum possible skill level for that stick. Things are balanced by the use of a
+"minimum magic-device skill level required to raise spell level". Here's an
+example:
+A Staff of Sense Hidden [1|10]. Your magic device skill is at 6. If you were to
+identify the staff and then 'I'nspect it, you would see the following
+information:
+
+&&&&&w wSwpwewlwlw wdwewswcwrwiwbwtwiwownw:w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wDwewtwewcwtwsw wtwhwew wtwrwawpwsw wiwnw waw wcwewrwtwawiwnw wrwawdwiwuwsw wawrwowuwnwdw wywowuw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wAwtw wlwewvwewlw w1w5w wiwtw wawlwlwowwwsw wywowuw wtwow wswewnwswew wiwnwvwiwswiwbwlwew wfwowrw waw wwwhwiwlwew w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wSwpwewlwlw wlwewvwewlw:w B3w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wMwiwnwiwmwuwnw wMwawgwiwcw wDwewvwiwcwew wlwewvwewlw wtwow wiwnwcwrwewawswew wswpwewlwlw wlwewvwewlw:w B5w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wSwpwewlwlw wfwawiwlw:w g2g3w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wSwpwewlwlw wiwnwfwow:w yryaydy y1y3w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+The Spell level is the level at which the spell will actually be cast.
+Spell fail is the spell fail percentage. The spell info may contain the radius
+of effect, amount of damage, or duration the spell might last.
+The Minimum Magic Device level to increase your spell level is just that. If
+your magic device skill was less than this level, then the staff would be
+casting the spell at level one. Our magic device skill is 6. Therefore we are
+casting at level 2 (at skill level 5, we should be casting the spell at level
+1). Then we add the bonus from the staff of 1, which gives us our spell level
+of 3. If our magic device in this example had been 14, this would have given us
+a spell level of 1 + (14 - 5 + 1) = 11. This is calculated from the formula:
+spell level = staff bonus + (magic device - minimum magic device + 1)).
+However given that the maximum spell level with this staff is 10, you'll be
+casting with a spell level of 10.
+As you get deeper into the dungeons, you will find sticks with higher bonuses
+and maximum spell levels.
+
+ Written by: vrak AKA Per-Arne Holtmon Akoe
+ Wands and Staves section added by fearoffours
diff --git a/lib/help/newbie.hlp b/lib/help/newbie.hlp
new file mode 100644
index 00000000..2dda8dbc
--- /dev/null
+++ b/lib/help/newbie.hlp
@@ -0,0 +1,16 @@
+|||||oy
+~~~~~01|Help|New players
+#####RWelcome to the ToME New Players Help System.
+#####R=============================================
+
+Please choose one of the following help files:
+
+ *****/awhattome.txt*0[(a) What is ToME?]
+ *****/bbirth.txt*0[(b) Creating a character] Race, class, gods, stats + more
+ *****/cexplore.hlp*0[(c) Exploring the town and dungeon] Dungeons, commands, features
+ *****/dexperien.hlp*0[(d) Gaining experience] Skills and abilities
+ *****/emagic.hlp*0[(e) Using magic and magical items] Magic schools, the 'm' menu, wands etc
+ *****/fTANG.txt*0[(f) The ToME newbie guide]
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
+
diff --git a/lib/help/option.txt b/lib/help/option.txt
new file mode 100644
index 00000000..6fd3b413
--- /dev/null
+++ b/lib/help/option.txt
@@ -0,0 +1,698 @@
+|||||oy
+~~~~~05|Options
+#####R=== Options and Effects (ToME 2.1.x) ===
+
+Most of the options are accessible through the '=' command, which provides
+an interface to the various sets of options available to the player.
+
+In the descriptions below, each option is listed as the textual summary
+which is shown on the options screen, plus the internal name of the
+option in brackets, followed by a textual description of the option.
+
+Note that the internal name of the option can be used in user pref files
+to force the option to a given setting; see *****command.txt*105["command.txt"] for more info.
+
+Various concepts are mentioned in the descriptions below, including "disturb"
+(cancel any running, resting, or repeated commands, which are in progress),
+"flush" (forget any keypresses waiting in the keypress queue, including any
+macros in progress), and "fresh" (dump any pending output to the screen).
+
+~~~~~06|Options|Startup
+#####R=== Birth/Startup Options ===
+
+The birth or startup options are only able to be changed during character
+creation, and can be accessed by typing '=' during the creation process. They
+can also be viewed from the option menu while playing, but not changed then.
+
+#####GMaximise stats [maximize]
+ Maximise causes the race and class stat bonuses to be applied like
+ equipment bonuses. This usually makes the character harder at the
+ beginning of the game, but easier later on, since the stats are no longer
+ limited to a "natural" value of 28 (18/100).
+
+#####GPreserve artifacts [preserve]
+ Preserve artifacts cancels all level feelings of the "special" variety,
+ but allows missed artifacts to be "saved" by wandering monsters and
+ found again at a later time. This only works for non-identified artifacts.
+
+#####GSpecify 'minimal' stats [autoroll]
+ Uses the standard autoroller for character creation. This allows the player
+ to specify a set of minimum values for the stats, and the game will keep
+ rerolling until it achieves them (or 1 million rolls, whichever comes
+ first). Be warned, however, that there is a maximum total power permitted
+ for a starting character. Setting one stat to near maximum is easily
+ achievable; 2 is reasonable; but 3 would require the remaining 3 stats to
+ be near their minimum values.
+
+#####GGenerate character using a point system [point_based]
+ Allows the player to distribute a certain number of points among her stats.
+ It results in the player being able to get one or two really high stats, at
+ the expense of other not-so-important stats; or to have a well-rounded
+ character who is above average (but not great) in all stats. Unused points
+ convert into starting gold for the player.
+
+#####GAlways generate very unusual rooms [ironman_rooms]
+ Tries to place a special room or vault on every dungeon level. Very fun,
+ but extremely deadly - imagine that Greater Checkerboard Vault with Lokkak
+ on dungeon level 1!
+
+#####GAllow notes to be written to a file [take_notes]
+ Allows any player-written notes (with the "|" command) to be written to
+ a file and kept (instead of being put in the message list).
+
+#####GAutomatically note important events [auto_notes]
+ Used in conjunction with the take_notes option, this option makes a note
+ each time you gain a level, kill a unique, find an artifact, etc.
+
+#####GFast autoroller (NOT on multiuser systems) [fast_autoroller]
+ The normal autoroller has a built-in delay that helps prevent it from
+ overloading a system. This option reduces that delay, allowing characters
+ to be rolled in a much shorter time, but should not be used on multiuser
+ systems.
+
+#####GAllow use of some 'joke' monsters [joke_monsters]
+ Allows monsters flagged as being some of DarkGod's jokes to be generated.
+
+#####GAlways make small levels [always_small_level]
+ Overrides the in-game option of small_levels, generating smaller levels
+ whenever possible.
+
+#####GYou can receive fates, good or bad [fate_option]
+ Allows the player to turn off ToME's *****fatespoi.txt*0[fates] for that character.
+
+~~~~~07|Options|Ingame
+#####RIN GAME OPTIONS
+#####R===============
+
+These options are available from within the game, and can be toggled on and
+off at will during the course of the game.
+
+~~~~~08|Options|Interface
+#####R=== Option Set 1 -- User Interface ===
+
+#####GRogue-like commands [rogue_like_commands]
+ Selects the "roguelike" command set (see *****command.txt*0["command.txt"] for info).
+~~~~~1
+#####GActivate quick messages [quick_messages]
+ Allows the use of any keypress as a response to the "-more-" prompt
+ (useful for monster farming). Allows most keys to mean "no" to any
+ "[y/n]" prompt.
+
+#####GPrompt for various information [other_query_flag]
+ No longer used.
+
+#####GPrompt before picking things up [carry_query_flag]
+ Forces the game to ask you for confirmation when you do something that
+ would normally cause an item to be picked up.
+~~~~~4
+#####GUse old target by default [use_old_target]
+ Forces all commands which normally ask for a direction to use the
+ current target if there is one. If the current target is a monster, it
+ becomes unset when that monster dies. Use of this option can be dangerous
+ if you target locations on the ground, unless you clear them when done.
+
+#####GPick things up by default [always_pickup]
+ Tells the game that walking onto an item should attempt to pick it up.
+ Otherwise, you must use the "g" command, or the "-" command while walking.
+ Combined with "carry_query_flag" (Prompt before picking things up), allows
+ you to selectively pick up all items which you step on.
+
+#####GPrompt before picking up heavy objects [prompt_pickup_heavy]
+ Generates a prompt whenever the character tries to pick up an item that
+ would slow him down.
+
+#####GRepeat obvious commands [always_repeat]
+ Tells the game that when you attempt to open a door or chest, bash
+ a door, tunnel through walls, or disarm traps or chests, that you
+ wish to repeat the command 99 times (see *****command.txt*0["command.txt"]).
+
+#####GShow dungeon level in feet [depth_in_feet]
+ Display the dungeon depth in "feet" instead of as a level number (one
+ level is equivalent to 50'). This also affects the monster memory display.
+
+#####GMerge inscriptions when stacking [stack_force_notes]
+ Force otherwise identical objects to merge, even if one has an empty
+ inscription and the other does not. The resulting stack keeps the
+ non-empty inscription.
+
+#####GMerge discounts when stacking [stack_force_costs]
+ Force otherwise identical objects to merge, even if they have different
+ discounts. The resulting stack keeps the largest discount. This option
+ may cause you to lose "value", but will give you optimal pack usage.
+
+#####GShow labels in object lists [show_labels]
+ Display the "labels" for objects in the equipment list, and in any
+ special window which is displaying the equipment. These labels
+ indicate what the player is using the object for, such as "wielding"
+ or "wearing" (in a given location). After you have played for a while,
+ this information is no longer useful, and can be annoying.
+ Note that in ToME this option no longer controls the "plain
+ flavoured object descriptions": a separate option for them has been added
+ under "ToME Options".
+
+#####GShow weights in object lists [show_weights]
+ Display the weight of objects in the inventory and equipment lists,
+ and in stores, and in any special window which is displaying any of
+ these lists.
+
+#####GShow graphics in inventory list [show_inven_graph]
+ Display the graphics of objects in the inventory list, and in any special
+ window which is displaying the inventory list.
+
+#####GShow graphics in equipment list [show_equip_graph]
+ Display the graphics of objects in the equipment list, and in any special
+ window which is displaying the equipment list.
+
+#####GShow graphics in stores [show_store_graph]
+ Display the graphics of objects in the store list.
+
+#####GShow choices in certain sub-windows [show_choices]
+ Indicate legal choices in special windows which display lists.
+
+#####GShow details in certain sub-windows [show_details]
+ Indicate extra details in special windows, currently used to activate
+ the display of death counts and monster descriptions when recalling
+ details about a monster.
+
+#####GAudible bell (on errors, etc) [ring_bell]
+ Attempt to make a "bell" noise when various errors occur.
+
+~~~~~09|Options|Disturbance
+#####R=== Option Set 2 -- Disturbance ===
+
+#####GRun past stairs [find_ignore_stairs]
+ Ignore stairs when running.
+
+#####GRun through open doors [find_ignore_doors]
+ Ignore open doors when running.
+
+#####GRun past known corners [find_cut]
+ Cut sharply around known corners when running. This will result in
+ faster running, but may cause you to run into a lurking monster.
+
+#####GRun into potential corners [find_examine]
+ Fully explore potential corners in hallways. This is strongly
+ recommended if your light source has a small radius (e.g. a torch).
+
+#####GDisturb whenever any monster moves [disturb_move]
+ Disturb the player when any monster moves, appears, or disappears.
+ This includes monsters which are only visible due to telepathy, so
+ you should probably turn this option off if you want to "rest" near
+ such monsters.
+
+#####GDisturb whenever viewable monster moves [disturb_near]
+ Disturb the player when any viewable monster moves, whenever any
+ monster becomes viewable for the first time, and also whenever any
+ viewable monster becomes no longer viewable. This option ignores
+ the existence of telepathy for the purpose of determining whether
+ a monster is viewable. See also the "view_reduce_view" option.
+
+#####GDisturb whenever map panel changes [disturb_panel]
+ This option causes you to be disturbed (stop running) when the screen
+ scrolls, as it does when you get close to the edge of the visible screen.
+
+#####GDisturb whenever leaving trap-detected area [disturb_detect]
+ This option causes you to be disturbed whenever you are leaving
+ a trap-detected area. This option is strongly recommended.
+
+#####GDisturb whenever player state changes [disturb_state]
+ This option causes you to be disturbed whenever the player state
+ changes, including changes in hunger, resistance, confusion, etc.
+
+#####GDisturb whenever boring things happen [disturb_minor]
+ This option causes you to be disturbed by various boring things,
+ including monsters bashing down doors, inventory feelings, and
+ beginning to run out of light-source fuel.
+
+#####GDisturb whenever random things happen [disturb_other]
+ In ToME, uncursed teleporting items may teleport you around sometimes,
+ asking for your confirmation (and possibly disturbing your rest). If you
+ unset this option, they will stop asking you and teleporting you randomly.
+ Cursed items will neither ask for confirmation nor stop teleporting you
+ even if this option is unset. (You may also inscribe an item with {.}
+ to suppress its random-teleportation power, unless it is cursed.)
+
+#####GAlert user to critical hitpoints [alert_hitpoint]
+ Produce a "bell" noise, and flushes all pending input, when your hitpoints
+ reach the warning point chosen elsewhere, preventing stupid deaths.
+
+#####GAlert user to various failures [alert_failure]
+ Produce a "bell" noise, and flushes all pending input, when various
+ failures occur, as described above.
+
+#####GGet last words when the character dies [last_words]
+ Display a random line from the "death.txt" file when your character
+ dies. If this option is not selected, the "You die." message is displayed
+ instead.
+
+#####GAllow shopkeepers and uniques to speak [speak_unique]
+ If this option is in use, shopkeepers may sometimes whisper rumours to
+ you. Also certain monsters start boasting as they attack you, and when
+ they die, they say their "last words".
+
+#####GNo query to destroy known worthless items [auto_destroy]
+ It can sometimes be annoying that the Destroy command asks for confirmation
+ when you are attempting to destroy a Broken sword {cursed}. If this option
+ is set, no confirmation will be asked if you attempt to destroy an object
+ which you know to be worthless. Of course, cursed artifacts cannot be
+ destroyed even if this option is set.
+
+#####GConfirm to wear/wield known cursed items [confirm_wear]
+ Some players may occasionally, due to a typing mistake, find themselves
+ wearing an item which they knew was cursed. If this option is set, you
+ should be safe from such typing mistakes: you will be prompted if you
+ attempt to wear or wield an item if your character knows it is cursed.
+
+#####GPrompt before exiting a dungeon level [confirm_stairs]
+ Some players (such as myself) often accidentally press the '<' key
+ and exit a Special feeling level. If this option is set, the program
+ asks for confirmation before you go up or down the stairs. Others may
+ find the prompt annoying; they should of course not set this option. :-)
+
+#####GDisturb when visible pets move [disturb_pets]
+ The player may wish that some of the disturbance options do not apply
+ to pets: for example, it can be annoying if your rest is always disturbed
+ by a pet dog who pops in every now and then. By default, pets do not
+ disturb you even if full monster disturbance options are set. If you
+ want your pets to disturb you like normal monsters, set this option.
+
+#####GAutomatically open doors [easy_open]
+ Opens (and unlocks) doors by walking into them. Also, if you are adjacent
+ to only one known door, using the "o"pen command will not prompt you for
+ a direction.
+
+#####GAutomatically disarm traps [easy_disarm]
+ Attempts to disarm traps by walking into/over them. Also, if you are
+ adjacent to only one known trap, using the "D"isarm command will not
+ prompt you for a direction. If your disarming ability is particularly
+ low, you should probably not enable this option, because you will often
+ fail to disarm the traps, and sometimes trigger them.
+
+#####GAutomatically tunnel walls [easy_tunnel]
+ Automatically tunnels into walls by walking into them.
+
+~~~~~10|Options|Game-play
+#####R=== Option Set 3 -- Game-play ===
+
+#####GAuto-haggle in stores [auto_haggle]
+ Disable haggling in stores, resulting in a ten percent sales tax
+ on items which you would have otherwise been forced to haggle for.
+ When this option is on, all prices listed in stores will be the
+ actual price that you pay for an item, as opposed to the price
+ that the shop-keeper will suggest.
+
+#####GAuto-scum for good levels [auto_scum]
+ This is a hack but allows you to force the generation of "good" levels
+ in the dungeon. This option may be extremely slow on some machines,
+ especially deep in the dungeon. The minimum "goodness" of the level
+ is based on the dungeon level, so the deeper you go, the better the
+ level will be.
+
+#####GAllow weapons and armor to stack [stack_allow_items]
+ Allow identical weapons and armor to be combined into a stack. This
+ also allows unidentified, but identical, ammo to be combined, which
+ may result in the auto-identification of some of the ammo, but which
+ makes it a lot easier to actually use unidentified ammo.
+
+#####GAllow wands/staffs/rods to stack [stack_allow_wands]
+ Allow identical wands/staffs/rods to be combined into a stack. This
+ may force the items to be unstacked to use them, which may result
+ in overflow of the pack. Also, the entire stack can be recharged
+ (and possibly destroyed) at the same time.
+
+#####GExpand the power of the look command [expand_look]
+ Expand the "l"ook command to allow the user to look at grids which
+ are not actually in view of the player, allowing the examination of
+ objects/monsters which have only been detected by spells, or sensed
+ via telepathy.
+
+#####GExpand the power of the list commands [expand_list]
+ Expand the "listing" commands so that they wrap at the edges of
+ the appropriate list. This allows the "l"ook and "t"arget commands
+ to cycle through all appropriate grids forever, and the "identify
+ symbol" to browse through all of the monsters of a given type.
+
+#####GMap remembers all perma-lit grids [view_perma_grids]
+ Memorise all perma-lit floor grids which are seen by the player.
+ This option allows you to keep track of which explored floor grids
+ were perma-lit, but does not distinguish between dark floor grids,
+ unexplored floor grids, and unknown grids. Turning off this option
+ allows the player to always know which lit floor grids are in line
+ of sight, but this is better accomplished by the "view_bright_lite"
+ option. Note that any non-floor grids which is seen by the player
+ are always memorised, and any object which is seen by the player is
+ memorised independently from the memorisation of the grid itself.
+
+#####GMap remembers all torch-lit grids [view_torch_grids]
+ Memorise all (torch-lit) floor grids which are seen by the player.
+ This option not only allows you to keep track of which floor grids
+ have been explored, but also which ones are dark, because the use
+ of this option activates a special color scheme for the display of
+ floor grids, in which dark grids are drawn in dark grey, lit grids
+ are drawn in white, and (if the "view_bright_lite" option is set)
+ lit grids which are also in line of sight are drawn in orange. Note
+ that grids which are currently torch-lit are considered to be "lit",
+ and are thus drawn in white, unless the "view_yellow_lite" option is
+ set, in which case they are drawn in yellow.
+
+#####GAllow some monsters to carry light [monster_lite]
+ This option allows some monsters to carry light sources around with them,
+ lighting up the space around them. It can also allow you to see when some
+ monsters are heading your way before they reach the bend in the corridor
+ where you are hiding in ambush....
+
+#####GGenerate dungeons with aligned rooms [dungeon_align]
+ Force all rooms to be aligned with the "panel" divisions. This results
+ in a much prettier dungeon, but may result in fewer greater vaults.
+
+#####GGenerate dungeons with connected stairs [dungeon_stair]
+ Always generate a staircase back to the level whence you came, if you used
+ a staircase to get to the level. This is more "realistic", and safer,
+ but less of a challenge for some people.
+
+#####GMonsters chase current location (v.slow) [flow_by_sound]
+ Allow monsters to make paths to the player when they are nearby. This
+ option is extremely slow, but can produce viciously smart monsters.
+~~~~~3
+#####GUse special symbols for the player char [player_symbols]
+ If this option has been compiled in, it allows you to display your
+ character using race / class / sex dependent colours and graphical
+ symbols. Note that the support for this option may not have been
+ compiled in on all platforms.
+
+#####GPlain object descriptions [plain_descriptions]
+ In ToME, this option disables "full" names for identified flavoured
+ objects; in other words, if this option is not in use, an identified
+ Potion of Speed could be listed (for example) as a Blue Potion of Speed.
+ If you prefer simpler, less verbose descriptions, set this option.
+
+#####GMonsters learn from their mistakes [smart_learn]
+ Allow monsters to learn what spell attacks you are resistant to,
+ and to use this information to choose the best attacks.
+
+#####GMonsters exploit players weaknesses [smart_cheat]
+ Allow monsters to know what spell attacks you are resistant to, without
+ first having to observe such an attack upon you, and to use this
+ information to choose the best attacks.
+
+#####GMonsters behave stupidly [stupid_monsters]
+ ToME incorporates Keldon Jones' improved monster Artificial
+ Intelligence patch. While this patch most certainly makes monsters
+ behave more realistically, they will also be more deadly with the
+ improved AI. If you are a sissy, set this option to get the old,
+ really stupid monster AI.
+ Note that the new AI is a bit processing power expensive. If you have
+ an old computer (386sx) and ToME is running too slowly, you could
+ try turning stupid_monsters on. Or dumpster-dive for a Pentium so you can
+ run ToME. :-)
+
+#####GAllow unusually small dungeon levels [small_levels]
+ This option enables the creation of levels of varying sizes. Levels
+ that are as small as one "screen" (80x24) are possible, and they can be
+ quite dangerous, especially for a low level character, because they have
+ as many monsters and traps as their full-sized counterparts.
+ Note that this option has the side effect of enabling / disabling
+ 'destroyed' levels (they are enabled if small levels are).
+
+#####GAllow empty 'arena' levels [empty_levels]
+ Normal dungeon levels consist mostly of rock. If this option is in
+ use, levels which have empty floor instead of solid rock may also
+ be created (somewhat reminiscent of Nethack's "big-room" levels).
+ These levels can be extremely deadly, especially with breathing
+ monsters (since there are few obstructions to shield you). Arena levels
+ may have vaults, nests and pits in them like normal levels. Some
+ arena levels are dark when they are created, but most are lit.
+
+~~~~~11|Options|Efficiency
+#####R=== Option Set 4 -- Efficiency ===
+
+#####GReduce lite-radius when running [view_reduce_lite]
+ Reduce the radius of the player's light to that of a torch (radius 1)
+ when the player is running, which makes running more efficient (CPU-wise),
+ but is extremely annoying. Certain older versions of Angband used
+ this behavior always, so "purists" should turn it on.
+
+#####GReduce view-radius in town [view_reduce_view]
+ No longer in use.
+
+#####GAvoid checking for user abort [avoid_abort]
+ Avoid checking to see if the user has pressed a key during resting
+ or running or repeated commands. This not only makes the game much
+ more efficient (on many systems), but also allows the use of certain
+ obscure macro sequences, such as turning this option on, resting until
+ done, turning this option off, and casting a spell. Note that the use
+ of this option may be dangerous on certain "graphic" machines. Resting
+ for long periods of time with this option set is dangerous since the
+ resting may not stop until the user takes damage from starvation.
+
+#####GAvoid processing special colors [avoid_other]
+ Avoid processing the "multi-hued" or "clear" attributes of monsters.
+ This will cause all multi-hued monsters to appear violet and all
+ clear monsters to appear white, and will cause trappers and lurkers to
+ be visible on some machines, but it may greatly increase efficiency
+ especially when telepathy is active. Certain systems may choose to set
+ this option if they are unable to support the special color processing,
+ but if they handle graphics "correctly", by using attr/char pairs with
+ the "high bits" set, then not only will the game correctly avoid using
+ any "dangerous" color processing, but it will allow such processing to
+ occur when it is not dangerous. So if you are using graphics, and you
+ use a normal attr/char for the floor grids, then you can use the
+ "special lighting effects" for floors.
+
+#####GFlush input on various failures [flush_failure]
+ This option forces the game to flush all pending input whenever various
+ "failures" occur, such as failure to cast a spell, failure to use a wand,
+ etc. This is very useful if you use macros which include "directional"
+ components with commands that can fail, since it will prevent you from
+ walking towards monsters when your spells fail.
+
+#####GFlush input whenever disturbed [flush_disturb]
+ This option forces the game to flush all pending input whenever the
+ character is "disturbed". This is useful if you use macros which take
+ time, since it will prevent you from continuing your macro while being
+ attacked by a monster.
+
+#####GFlush input before every command [flush_command]
+ This option forces the game to flush all pending input before every
+ command. This option is silly, unless you are very paranoid.
+
+#####GFlush output before every command [fresh_before]
+ This option forces the game to flush all output before every command.
+ This will give you maximal information, but may slow down the game
+ somewhat. Note that this option is only useful when using macros,
+ resting, running, or repeating commands, since the output is always
+ flushed when the game is waiting for a keypress from the user.
+
+#####GFlush output after every command [fresh_after]
+ This option forces the game to flush all output after not only every
+ player command, but also after every round of processing monsters and
+ objects, which will give you maximal information, but may slow down
+ the game a lot, especially on slower machines; and on faster machines
+ you normally do not have a chance to see the results anyway.
+
+#####GFlush output after every message [fresh_message]
+ This option forces the game to flush all output after every message
+ displayed by the game. This will give you maximal information, but
+ may slow down the game somewhat.
+
+~~~~~2
+#####GHilite the player with the cursor [hilite_player]
+ Place the visible cursor on the player. This looks fine on some Unix
+ machines, but horrible on most graphics machines. Note that only some
+ machines are able to *not* show the cursor, but on those machines, hiding
+ the cursor often speeds up the game and looks better.
+
+#####GUse special colors for torch-lit grids [view_yellow_lite]
+ This option causes special colors to be used for "torch-lit" grids in
+ certain situations (see "view_granite_lite" and "view_special_lite").
+ Turning this option off will slightly improve game speed.
+
+#####GUse special colors for 'viewable' grids [view_bright_lite]
+ This option causes special colors to be used for non "viewable" grids
+ in certain situations (see "view_granite_lite" and "view_special_lite").
+ When this option is set, floor grids which are normally drawn in white
+ but which are not currently viewable by the player are instead drawn
+ in dark grey. This makes the viewable grids appear brighter than the
+ others, allowing the player to easily determine which floor grids are
+ in line of sight. Turning this option off will probably increase the
+ speed of the game.
+
+#####GUse special colors for wall grids (slow) [view_granite_lite]
+ This option activates a special color scheme for all wall grids which
+ are normally drawn in white (as walls and rubble normally are). When
+ the player is blind, we use dark grey, else if the grid is torch-lit,
+ we use yellow (or white, depending on the "view_yellow_lite" option),
+ else if the "view_bright_lite" option is set, and the grid is not in line
+ of sight, or the grid is dark, or the grid is only "partially" lit, then
+ we use grey, otherwise we use the normal white. Turning this option
+ off will probably increase the speed of the game.
+
+#####GUse special colors for floor grids (slow) [view_special_lite]
+ This option activates a special color scheme for all floor grids which
+ are normally drawn in white (as they normally are). When the player is
+ blind, we use dark grey, else if the grid is torch-lit, we use yellow
+ (or white, depending on the "view_yellow_lite" option), else if the grid
+ is dark, we use dark grey, else if the "view_bright_lite" option is
+ set, and the grid is not in line of sight, we use grey, otherwise we
+ use the normal white. Turning this option off will probably increase
+ the speed of the game.
+
+#####GCentre the view on the player (very slow) [center_player]
+ Keeps the player's character in the centre of the screen, and moves the
+ dungeon around the player. Can be useful to prevent off-screen breaths.
+
+~~~~~12|Options|ToME Options
+#####R=== ToME Options ===
+
+Features which are unique to ToME are collected in this menu.
+
+#####GIngame contextual help [ingame_help]
+ Setting this option allows the game to trigger a help message the first
+ time you come across an item or some other trigger. This is very useful
+ for new players. More experienced players may wish to switch this option
+ off.
+
+#####GShow the experience needed for the next level [exp_need]
+ Setting this option alters the display of experience on the left of
+ the main screen to the experience needed to reach the next character level,
+ instead of the character's current total experience.
+
+#####GUse the old(Z) coloring scheme(reload the game) [old_colors]
+ Setting this option toggles the ASCII game colour display from the
+ standard Angband monster colours to the Zangband-based monster colours.
+ Since this alters the display and monster memory display, you need to
+ reload the game when you alter this setting before it will display the
+ new colours.
+
+#####GAutomatically clear '-more-' prompts [auto_more]
+ Setting this option automatically clears any messages from the top
+ of the window. Be warned that this could be dangerous, as you don't
+ actually get to see the messages unless you use ^P.
+
+#####GPlayer char represent his/her health [player_char_health]
+ Setting this option only affects the game when playing without tiles.
+ As the player becomes injured, his icon changes to a figure representing
+ the percentage of health remaining; for example if he is down to 68% of
+ his maximum hitpoints, his character will be a '6' instead of an '@'.
+ The character used only starts changing once the player has lost at
+ least 30% of his maximum hitpoints.
+
+#####GStats are represented in a linear way [linear_stats]
+ Setting this option alters the display of character stats. The default
+ is 3 to 40 (linear), but the older 3 to 18/220 (Moria/Angband style) is
+ retained for players who prefer it.
+
+#####GIn option windows, just omit the select char [inventory_no_move]
+ If this option is set, the equipment/inventory windows don't move items
+ around when a prompt asks for an item.
+
+
+#####R=== Stacking Options ===
+
+In ToME items are allowed to stack on floors and monsters are allowed to
+maintain inventories. These features are enabled by default, and aren't
+accessible through the option menu, but can still be disabled through
+user pref files (see *****command.txt*105["command.txt"]).
+
+#####GAllow objects to stack on the floor [testing_stack]
+ Allows a cave grid to hold more than one object (or one kind of
+ object).
+
+#####GAllow monsters to carry objects [testing_carry]
+ If this option is set, monsters which "pick up" objects will drop
+ the objects they were carrying when you kill them. Note that monsters
+ which "crush" objects are not affected by this option.
+
+~~~~~13|Options|Base Delay Factor
+#####R=== Base Delay Factor ===
+
+The "delay_factor" value, if non-zero, is used to slow down the game, which is
+useful to allow you to observe the temporal effects of bolt, beam, and ball
+attacks. The actual delay is equal to "delay_factor" cubed, in milliseconds.
+Frequently used factors are 2 or 3.
+
+~~~~~14|Options|Hitpoint Warning
+#####R=== Hitpoint Warning ===
+
+The "hitpoint_warn" value, if non-zero, is the percentage of maximal hitpoints
+at which the player is warned that he may die. It is also used as the cut-off
+for using red to display hitpoints, mana and sanity. It is entered as a value
+between 0 and 9 (0% and 90%).
+
+~~~~~15|Options|Autosave
+#####R=== Autosave Options ===
+
+Ideally, the game should be so stable that these options are not needed
+at all. However, even if the game were 100% reliable (which, to be frank, it
+probably is not), the user might forget to save, and his hardware could fail
+him. For all of these reasons, you may want to use these options:
+
+#####GAutosave when entering new levels [autosave_l]
+ If this option is set, the program will attempt to save your
+ character every time before creating a new dungeon level. Useful
+ if you experience any game or computer crashes (or your dog enjoys
+ kicking your power cords out of the wall like mine does!).
+
+#####GTimed autosave [autosave_t]
+ If this option is set, the program will attempt to save your
+ character every n game turns, where n is the "frequency". To set
+ frequency, press n: it will increase the frequency to the next
+ category, these being every 50, 100, 250, 500, 1000, 2500, 5000,
+ 10000 or 25000 turns. (After 25000, pressing n again will cycle back
+ to 0.) Note that the frequency must be higher than 0 and the
+ "Timed autosave" set to "yes" for timed autosaves to take place.
+
+~~~~~16|Options|Automatizer
+#####R=== The Automatizer ===
+
+Allows you to set options for the game to automatically destroy or pick up
+objects when you identify them, for example skeletons, essences, cursed
+daggers, etc. Useful for reducing the clutter in the dungeon, and reducing the
+amount of loot to have to sort through. This *****automat.txt*0[Tutorial] may help you.
+
+~~~~~17|Options|Window Flags
+#####R=== Window Flags ===
+
+Selects what kind of information is displayed in which window, on platforms
+which use multiple windows.
+
+You can select a window to be able to toggle between 2 different
+sets of information (e.g. Basic Character stats and monster recall)
+by pressing the "y" key over the second display option.
+
+~~~~~18|Options|Cheating
+#####R=== Cheating Options ===
+
+#####GPeek into object creation [cheat_peek]
+ Cheaters never win. But they can peek at object creation.
+
+#####GPeek into monster creation [cheat_hear]
+ Cheaters never win. But they can peek at monster creation.
+
+#####GPeek into dungeon creation [cheat_room]
+ Cheaters never win. But they can peek at room creation.
+
+#####GPeek into something else [cheat_xtra]
+ Cheaters never win. But they can see debugging messages.
+
+#####GKnow complete monster info [cheat_know]
+ Cheaters never win. But they can know all about monsters.
+
+#####GAllow player to avoid death [cheat_live]
+ Cheaters never win. But they can cheat death.
+
+~~~~~19|Options|Dump/Load Options
+#####R=== Dump Options ===
+
+Allows the player to save the options to a file (defaults to charname.prf)
+so that they can be reloaded into other character files.
+
+
+#####R=== Load Options ===
+
+Allows you to load a preference file saved through the "Dump Options"
+command in another character file, hence saving all the initial time of having
+to reset all the options every time you wish to play.
+
+
++++ Ben +++ (Updated by Dark God and Dawnmist et al. for ToME)
diff --git a/lib/help/r_beorn.txt b/lib/help/r_beorn.txt
new file mode 100644
index 00000000..b000403f
--- /dev/null
+++ b/lib/help/r_beorn.txt
@@ -0,0 +1,33 @@
+~~~~~01|Beorning
+~~~~~02|Races|Beorning
+#####R=== Beornings ===
+
+#####GDescription
+Beornings are the descendants of Beorn, a powerful shapeshifter who
+dwells near Mirkwood. They have all inherited his shapeshifting abilities
+and can turn into powerful bears at will.
+
+#####GStat Modifiers
+Strength +4
+Intelligence -2
+Wisdom -2
+Dexterity -1
+Constitution +3
+Charisma -5
+Hit Dice Sides 12
+Exp Penalty +50%
+
+#####GSkill Bonuses (supplementary to existing skills)
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 2.500 [0.000]
+ Archery 0.500 [0.000]
+ Bearform-combat 1.000 [1.000]
+Sneakiness -0.100 [0.000]
+ Stealth -2.000 [0.000]
+ Disarming -0.600 [0.000]
+Magic
+ Magic-Device -0.800 [0.000]
+Spirituality -3.000 [0.000]
diff --git a/lib/help/r_deathm.txt b/lib/help/r_deathm.txt
new file mode 100644
index 00000000..d65403dd
--- /dev/null
+++ b/lib/help/r_deathm.txt
@@ -0,0 +1,33 @@
+~~~~~01|DeathMolds
+~~~~~02|Races|DeathMolds
+#####R=== DeathMolds ===
+
+#####GDescription
+Death Molds are incredibly powerful creatures. However, they are also
+molds. Lacking the ability to move as other creatures do, Death Molds have
+the powers of Phase Door, targeted teleportation, telekinesis, and
+controlled Teleport Level. They also intrinsically resist Nexus and Nether,
+and are more skilled at Necromancy than other races.
+
+#####GStat Modifiers
+Strength +10
+Intelligence 0
+Wisdom +10
+Dexterity 0
+Constitution +10
+Charisma -15
+Hit Dice Sides 15
+Exp Penalty +150%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 2.500 [0.000]
+ Archery 2.500 [0.000]
+Sneakiness
+ Stealth 25.000 [0.000]
+ Disarming 1.500 [0.000]
+Magic
+ Magic-Device -0.500 [0.000]
+ Necromancy 0.000 [0.200]
+Spirituality 7.500 [0.000]
diff --git a/lib/help/r_drkelf.txt b/lib/help/r_drkelf.txt
new file mode 100644
index 00000000..3f0758e5
--- /dev/null
+++ b/lib/help/r_drkelf.txt
@@ -0,0 +1,33 @@
+~~~~~01|Dark Elf
+~~~~~02|Races|Dark Elf
+#####R=== Dark Elves ===
+
+#####GDescription
+Another dark, cave-dwelling race, likewise unhampered by darkness attacks,
+the Dark Elves have a long tradition and knowledge of magic. With their
+intelligence and wisdom they can become superb mages or priests, and they
+have an inherent magic missile attack available to them at a low level. With
+their keen sight, they also learn to see invisible things as their relatives
+the High-Elves do, but at a higher level.
+
+#####GStat Modifiers
+Strength -1
+Intelligence +3
+Wisdom +2
+Dexterity +2
+Constitution -2
+Charisma +1
+Hit Dice Sides 9
+Exp Penalty +50%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.500 [0.000]
+ Archery 1.000 [0.000]
+Sneakiness 0.800 [0.000]
+ Stealth 3.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic 0.000 [0.200]
+ Magic-Device 1.500 [0.000]
+Spirituality 10.000 [0.000]
diff --git a/lib/help/r_dunad.txt b/lib/help/r_dunad.txt
new file mode 100644
index 00000000..79b85049
--- /dev/null
+++ b/lib/help/r_dunad.txt
@@ -0,0 +1,32 @@
+~~~~~01|Dunedain
+~~~~~02|Races|Dunedain
+#####R=== Dunedain ===
+
+#####GDescription
+Dunedain are a race of hardy men from the West. This elder race surpasses
+human abilities in every field, especially constitution. However, being
+men of the world, very little is new to them, and levels are very hard for
+them to gain. They can play all classes. Their constitution cannot be
+reduced and they regain hit points quickly.
+
+#####GStat Modifiers
+Strength +1
+Intelligence +2
+Wisdom +2
+Dexterity +2
+Constitution +3
+Charisma +2
+Hit Dice Sides 10
+Exp Penalty +80%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.500 [0.000]
+ Archery 1.000 [0.000]
+Sneakiness 0.800 [0.000]
+ Stealth 2.000 [0.000]
+ Disarming 0.400 [0.000]
+Magic
+ Magic-Device 0.500 [0.000]
+Spirituality 2.500 [0.000]
diff --git a/lib/help/r_dwarf.txt b/lib/help/r_dwarf.txt
new file mode 100644
index 00000000..6c5a9b80
--- /dev/null
+++ b/lib/help/r_dwarf.txt
@@ -0,0 +1,39 @@
+~~~~~01|Dwarf
+~~~~~02|Races|Dwarf
+#####R=== Dwarves ===
+
+#####GDescription
+Dwarves are the headstrong miners and fighters of legend. Since dungeons
+are the natural home of a dwarf, they are excellent choices for a warrior
+or priest. Dwarves tend to be stronger and tougher but less agile and
+intelligent than humans. Because they are so headstrong and are somewhat
+wise, they resist spells which are cast on them. Dwarves also have very
+good infra-vision because they live underground. They do have one big
+drawback, though: dwarves are loud-mouthed and proud, singing in boisterous
+voices, arguing with themselves for no good reason, and screaming out
+challenges at nearby foes. In other words, dwarves have miserable
+stealth. They can never be blinded, and they can also open secret tunnels
+through rock.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -2
+Wisdom +2
+Dexterity -2
+Constitution +2
+Charisma -3
+Hit Dice Sides 11
+Exp Penalty +25%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.500 [0.000]
+ Axe-mastery 0.000 [0.200]
+ Archery 0.500 [0.000]
+Sneakiness 0.700 [0.000]
+ Stealth -1.000 [0.000]
+ Disarming 0.200 [0.000]
+Magic
+ Magic-Device 0.900 [0.000]
+Spirituality 5.000 [0.000]
diff --git a/lib/help/r_elf.txt b/lib/help/r_elf.txt
new file mode 100644
index 00000000..6b4ceb3b
--- /dev/null
+++ b/lib/help/r_elf.txt
@@ -0,0 +1,32 @@
+~~~~~01|Elf
+~~~~~02|Races|Elf
+#####R=== Elves ===
+
+#####GDescription
+Elves are better magicians than humans, but not as good at fighting. They
+tend to be smarter and faster than either humans or half-elves and also
+have better wisdom. Elves are better at searching, disarming, perception,
+stealth, bows, and magic, but they are not as good at hand weapons.
+They resist light effects intrinsically.
+
+#####GStat Modifiers
+Strength -1
+Intelligence +2
+Wisdom +2
+Dexterity +1
+Constitution -2
+Charisma +2
+Hit Dice Sides 8
+Exp Penalty +20%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -5.000 [0.000]
+ Archery 1.500 [0.000]
+Sneakiness 0.800 [0.000]
+ Stealth 2.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic
+ Magic-Device 0.600 [0.000]
+Spirituality 3.000 [0.000]
diff --git a/lib/help/r_ent.txt b/lib/help/r_ent.txt
new file mode 100644
index 00000000..66edf5c2
--- /dev/null
+++ b/lib/help/r_ent.txt
@@ -0,0 +1,39 @@
+~~~~~01|Ent
+~~~~~02|Races|Ent
+#####R=== Ents ===
+
+#####GDescription
+The Ents are a powerful race dating back to the beginning of the world and
+are the eldest of all animals or plants that inhabit Arda. Spirits of the land,
+they were summoned to guard the forests of Middle-earth. Being much like
+trees they are very slow but strong, and very susceptible to fire.
+As the Shepherds of the Trees, they have the innate ability to cause trees to
+rise about them for protection.
+
+#####GStat Modifiers
+Strength +10
+Intelligence -3
+Wisdom +2
+Dexterity -5
+Constitution +11
+Charisma -3
+Hit Dice Sides 14
+Exp Penalty +110%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.300 [0.000]
+ Archery -0.200 [0.000]
+ Barehand-combat 0.000 [0.200]
+ Boulder-throwing 0.000 [0.600]
+Sneakiness 0.500 [0.000]
+ Stealth -6.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic
+ Magic-Device 0.500 [0.000]
+Spirituality 10.000 [0.000]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Tree-walking 1
diff --git a/lib/help/r_gnome.txt b/lib/help/r_gnome.txt
new file mode 100644
index 00000000..8272e8a5
--- /dev/null
+++ b/lib/help/r_gnome.txt
@@ -0,0 +1,36 @@
+~~~~~01|Gnome
+~~~~~02|Races|Gnome
+#####R=== Gnomes ===
+
+#####GDescription
+Gnomes are smaller than dwarves but larger than halflings. Like the hobbits,
+they live in the earth in burrow-like homes. Gnomes make excellent magi,
+and have very good saving throws. They are good at searching, disarming,
+perception, and stealth. They have lower strength than humans and they are
+not very good at fighting with hand weapons, but have developed a fondness
+for the crossbow. Gnomes have fair infra-vision, so they can detect
+warm-blooded creatures at a distance. Gnomes are intrinsically protected
+against paralysis and some slowing effects. At higher levels, gnomes learn
+to teleport at will.
+
+#####GStat Modifiers
+Strength -1
+Intelligence +2
+Wisdom 0
+Dexterity +2
+Constitution +1
+Charisma -2
+Hit Dice Sides 8
+Exp Penalty +35%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.800 [0.000]
+ Archery 1.200 [0.000]
+Sneakiness 0.600 [0.000]
+ Stealth 3.000 [0.000]
+ Disarming 1.000 [0.000]
+Magic
+ Magic-Device 1.200 [0.000]
+Spirituality 6.000 [0.000]
diff --git a/lib/help/r_hafelf.txt b/lib/help/r_hafelf.txt
new file mode 100644
index 00000000..ea748440
--- /dev/null
+++ b/lib/help/r_hafelf.txt
@@ -0,0 +1,31 @@
+~~~~~01|Half-Elf
+~~~~~02|Races|Half-Elf
+#####R=== Half-Elves ===
+
+#####GDescription
+Half-elves tend to be smarter and more agile than humans, but not as tough.
+Half-elves are slightly better at searching, disarming, saving throws,
+stealth, bows, and magic, but they are not as good at hand weapons. Half-
+elves may choose any class and do not receive any intrinsic abilities.
+
+#####GStat Modifiers
+Strength 0
+Intelligence +1
+Wisdom +1
+Dexterity +1
+Constitution -1
+Charisma +1
+Hit Dice Sides 9
+Exp Penalty +10%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -1.000 [0.000]
+ Archery 0.500 [0.000]
+Sneakiness 0.600 [0.000]
+ Stealth 1.000 [0.000]
+ Disarming 0.200 [0.000]
+Magic
+ Magic-Device 0.300 [0.000]
+Spirituality 1.500 [0.000]
diff --git a/lib/help/r_hafogr.txt b/lib/help/r_hafogr.txt
new file mode 100644
index 00000000..2a173e98
--- /dev/null
+++ b/lib/help/r_hafogr.txt
@@ -0,0 +1,31 @@
+~~~~~01|Half-Ogre
+~~~~~02|Races|Half-Ogre
+#####R=== Half-Ogres ===
+
+#####GDescription
+Half-Ogres are a crossbreed between a human and an ogre. They are big, bad, and
+stupid. For warriors, they have all the necessary attributes, and they can even
+become priests: after all, they are related to Ogre Magi, from whom they have
+learned the skill of setting trapped runes once their level is high enough. Like
+orcs, they resist darkness, and like trolls, they have their strength sustained.
+
+#####GStat Modifiers
+Strength +3
+Intelligence -1
+Wisdom -1
+Dexterity -1
+Constitution +3
+Charisma -3
+Hit Dice Sides 12
+Exp Penalty +30%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 2.000 [0.000]
+Sneakiness -0.100 [0.000]
+ Stealth -2.000 [0.000]
+ Disarming -0.300 [0.000]
+Magic
+ Magic-Device -0.500 [0.000]
+Spirituality -2.500 [0.000]
diff --git a/lib/help/r_hielf.txt b/lib/help/r_hielf.txt
new file mode 100644
index 00000000..3317a67b
--- /dev/null
+++ b/lib/help/r_hielf.txt
@@ -0,0 +1,34 @@
+~~~~~01|High-Elf
+~~~~~02|Races|High-Elf
+#####R=== High-Elves ===
+
+#####GDescription
+High-elves are a race of immortal beings dating from the beginning of
+time. They are masters of all skills, and are strong and intelligent.
+They can play all classes except rogues, and very well at that.
+High-elves begin their lives able to see the unseen, and resist light
+effects just like regular elves. However, there are few things that
+they have not seen already, and experience is very hard for them to
+gain.
+
+#####GStat Modifiers
+Strength +1
+Intelligence +3
+Wisdom +2
+Dexterity +3
+Constitution +1
+Charisma +5
+Hit Dice Sides 10
+Exp Penalty +100%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.000 [0.000]
+ Archery 2.500 [0.000]
+Sneakiness 0.300 [0.000]
+ Stealth 4.000 [0.000]
+ Disarming 0.400 [0.000]
+Magic
+ Magic-Device 2.000 [0.000]
+Spirituality 10.000 [0.000]
diff --git a/lib/help/r_hobbit.txt b/lib/help/r_hobbit.txt
new file mode 100644
index 00000000..30cd885f
--- /dev/null
+++ b/lib/help/r_hobbit.txt
@@ -0,0 +1,37 @@
+~~~~~01|Hobbit
+~~~~~02|Races|Hobbit
+#####R=== Hobbits ===
+
+#####GDescription
+Hobbits, or halflings, are very good at ranged combat (especially with slings),
+throwing, and have good saving throws. They also are very good at searching,
+disarming, perception and stealth; so they make excellent rogues, but prefer
+to be called burglars. They are much weaker than humans, and not good at melee
+fighting. Halflings have fair infra-vision, so they can detect warm creatures
+at a distance. Hobbits have their dexterity sustained and in time they learn to
+cook a delicious meal from available ingredients. Their sturdy constitutions
+also allow them to resist the insidious poison of the ring-wraiths.
+
+#####GStat Modifiers
+Strength -2
+Intelligence +2
+Wisdom +1
+Dexterity +3
+Constitution +2
+Charisma +1
+Hit Dice Sides 7
+Exp Penalty +10%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -1.000 [0.000]
+ Archery 2.000 [0.000]
+ Sling-Mastery 0.000 [0.300]
+Sneakiness 1.200 [0.000]
+ Stealth 5.000 [0.000]
+ Disarming 1.500 [0.000]
+Magic
+ Magic-Device 1.800 [0.000]
+Spirituality 9.000 [0.000]
+
diff --git a/lib/help/r_human.txt b/lib/help/r_human.txt
new file mode 100644
index 00000000..57606764
--- /dev/null
+++ b/lib/help/r_human.txt
@@ -0,0 +1,23 @@
+~~~~~01|Human
+~~~~~02|Races|Human
+#####R=== Humans ===
+
+#####GDescription
+Humans act as a baseline race -- all other races are compared to them.
+Humans can choose any class and are average at everything. Humans tend to
+go up levels faster than most other races because of their shorter life
+spans. No racial adjustments or intrinsics occur to characters choosing
+the human race.
+
+#####GStat Modifiers
+Strength 0
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution 0
+Charisma 0
+Hit Dice Sides 10
+Exp Penalty 0%
+
+#####GRacial Skill Modifiers:
+None. Humans are the baseline race.
diff --git a/lib/help/r_kobold.txt b/lib/help/r_kobold.txt
new file mode 100644
index 00000000..26d39f86
--- /dev/null
+++ b/lib/help/r_kobold.txt
@@ -0,0 +1,31 @@
+~~~~~01|Kobold
+~~~~~02|Races|Kobold
+#####R=== Kobolds ===
+
+#####GDescription
+Kobolds are a weak goblin race. They love poisoned weapons, and can learn
+to throw poisoned darts (of which they carry an unlimited supply). They
+are also inherently resistant to poison, and can become adequate fighters,
+although they are not one of the more powerful races.
+
+#####GStat Modifiers
+Strength +1
+Intelligence -1
+Wisdom 0
+Dexterity +1
+Constitution 0
+Charisma -4
+Hit Dice Sides 9
+Exp Penalty +25%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.000 [0.000]
+ Archery -0.800 [0.000]
+Sneakiness 0.100 [0.000]
+ Stealth -1.000 [0.000]
+ Disarming -0.200 [0.000]
+Magic
+ Magic-Device -0.300 [0.000]
+Spirituality -1.000 [0.000]
diff --git a/lib/help/r_maia.txt b/lib/help/r_maia.txt
new file mode 100644
index 00000000..fa575f82
--- /dev/null
+++ b/lib/help/r_maia.txt
@@ -0,0 +1,22 @@
+~~~~~01|Maia
+~~~~~02|Races|Maia
+#####R=== Maia ===
+
+#####GDescription
+An old race, dating from before the creation of Arda, the Maiar were created by
+Eru to help the Valar in their task. However, they can not worship a God, nor
+is experience easy to remember for them. Due to their perceived advantages,
+they are rather disliked by the denizens of the dungeon, and will find that most
+creatures take an instant dislike for the Maia. However, when they do finally
+manage to remember their encounters, they will find that their abilities will
+increase as they gain in knowledge.
+
+#####GStat Modifiers
+Strength 0
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution 0
+Charisma 0
+Hit Dice Sides 10
+Exp Penalty +0%
diff --git a/lib/help/r_orc.txt b/lib/help/r_orc.txt
new file mode 100644
index 00000000..c4bcf691
--- /dev/null
+++ b/lib/help/r_orc.txt
@@ -0,0 +1,35 @@
+~~~~~01|Orc
+~~~~~02|Races|Orc
+#####R=== Orcs ===
+
+#####GDescription
+Orcs make excellent warriors and decent priests, but are terrible at magic.
+They are as bad as dwarves at stealth, and horrible at searching, disarming,
+and perception. Orcs are quite ugly, and tend to pay more for goods in town.
+Orcs do make good warriors and rogues, for the simple reason that Orcs tend
+to have great constitutions and lots of hit points. Because of their
+preference for living underground rather than on the surface, orcs resist
+darkness attacks. Upon reaching experience level 3, an orc learns to dispel
+any fear that may be upon him.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -1
+Wisdom 0
+Dexterity +1
+Constitution +1
+Charisma -4
+Hit Dice Sides 10
+Exp Penalty +10%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.200 [0.000]
+ Archery -0.500 [0.000]
+Sneakiness
+ Stealth -1.000 [0.000]
+ Disarming -0.300 [0.000]
+Magic
+ Magic-Device -0.300 [0.000]
+Spirituality -1.000 [0.000]
diff --git a/lib/help/r_pettyd.txt b/lib/help/r_pettyd.txt
new file mode 100644
index 00000000..c8b8eba3
--- /dev/null
+++ b/lib/help/r_pettyd.txt
@@ -0,0 +1,30 @@
+~~~~~01|Petty Dwarf
+~~~~~02|Races|Petty Dwarf
+#####R=== Petty Dwarves ===
+
+#####GDescription
+A hated and persecuted race of nocturnal dwarves, these cave-dwellers are not
+bothered much by darkness. Their natural inclination to magically augmented
+items has made them immune to effects which could drain away magical
+enchantments, and, like ordinary dwarves, they can examine the dungeon to
+discover traps and secret doors. They are quite proficient as priests,
+warriors or rogues.
+
+#####GStat Modifiers
+Strength +1
+Intelligence -1
+Wisdom +2
+Dexterity 0
+Constitution +2
+Charisma -4
+Hit Dice Sides 11
+Exp Penalty +35%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Sneakiness 0.500 [0.000]
+ Stealth 1.000 [0.000]
+ Disarming 0.300 [0.000]
+Magic
+ Magic-Device 0.500 [0.000]
+Spirituality 5.000 [0.000]
diff --git a/lib/help/r_rohank.txt b/lib/help/r_rohank.txt
new file mode 100644
index 00000000..03391d4b
--- /dev/null
+++ b/lib/help/r_rohank.txt
@@ -0,0 +1,33 @@
+~~~~~01|RohanKnight
+~~~~~02|Races|RohanKnight
+#####R=== RohanKnights ===
+
+#####GDescription
+Knights of the Riddermark, these warriors are mounted upon swift steeds.
+Thus they receive a bonus to speed from the beginning and gain in speed
+as they become more experienced in riding. Wise through their prolonged
+contact with the Dunedain, their wrath may be seen in auras of war that
+drive their foes to confusion, and in a ray of light when jumping at light
+speed.
+
+#####GStat Modifiers
+Strength +4
+Intelligence -2
+Wisdom +3
+Dexterity +1
+Constitution +4
+Charisma +2
+Hit Dice Sides 10
+Exp Penalty +120%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 0.100 [0.200]
+ Archery 0.500 [0.000]
+Sneakiness 0.100 [0.000]
+ Stealth -8.000 [0.000]
+ Disarming 1.000 [0.000]
+Magic
+ Magic-Device 0.500 [0.000]
+Spirituality 2.500 [0.000]
diff --git a/lib/help/r_thlord.txt b/lib/help/r_thlord.txt
new file mode 100644
index 00000000..6de113fe
--- /dev/null
+++ b/lib/help/r_thlord.txt
@@ -0,0 +1,32 @@
+~~~~~01|Thunderlord
+~~~~~02|Races|Thunderlord
+#####R=== Thunderlords ===
+
+#####GDescription
+The Thunderlords are supremely powerful spirits created by Manwe Sulimo,
+each riding a Great Eagle. They have the ability to conjure powerful
+thunderbolts, they are telepathic, and they gain the ability to use the
+Straight Road, which can carry them to any location they have previously been.
+Due to their special clothing, they can resist elemental damage. However,
+they take a very long time to gain levels as both rider and eagle must
+accumulate experience.
+
+#####GStat Modifiers
+Strength +6
+Intelligence +2
+Wisdom +1
+Dexterity +1
+Constitution +3
+Charisma +8
+Hit Dice Sides 12
+Exp Penalty +300%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.500 [0.000]
+ Archery 0.500 [0.000]
+Sneakiness 3.000 [0.000]
+ Stealth -16.000 [0.000]
+ Disarming 0.600 [0.000]
+Spirituality 5.000 [0.000]
diff --git a/lib/help/r_troll.txt b/lib/help/r_troll.txt
new file mode 100644
index 00000000..f35e5aa6
--- /dev/null
+++ b/lib/help/r_troll.txt
@@ -0,0 +1,34 @@
+~~~~~01|Troll
+~~~~~02|Races|Troll
+#####R=== Trolls ===
+
+#####GDescription
+Trolls are incredibly strong, and have more hit points than most other
+character races, so they make great warriors, and marginal priests. They
+are also very stupid and clumsy. They are bad at searching, disarming,
+perception, and stealth. They are so ugly that an orc grimaces in their
+presence. They also happen to be fun to play.... Trolls always have
+their strength sustained. At higher levels, trolls learn to enter a
+berserk fury, and regenerate from their wounds automatically.
+
+#####GStat Modifiers
+Strength +4
+Intelligence -4
+Wisdom -2
+Dexterity -4
+Constitution +3
+Charisma -6
+Hit Dice Sides 12
+Exp Penalty +37%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 2.000 [0.000]
+ Archery -1.000 [0.000]
+Sneakiness -0.100 [0.000]
+ Stealth -2.000 [0.000]
+ Disarming -0.500 [0.000]
+Magic
+ Magic-Device -0.800 [0.000]
+Spirituality -4.000 [0.000]
diff --git a/lib/help/r_wodelf.txt b/lib/help/r_wodelf.txt
new file mode 100644
index 00000000..d40295fa
--- /dev/null
+++ b/lib/help/r_wodelf.txt
@@ -0,0 +1,37 @@
+~~~~~01|Wood Elf
+~~~~~02|Races|Wood Elf
+#####R=== Wood Elves ===
+
+#####GDescription
+The first love of Wood Elves is hunting. As such, their skill with the bow
+is unparalleled. They train tirelessly with their bows, to the point of
+neglecting even melee skills. They resist light as with other elves, and
+do extra damage with a ranged weapon. They are almost custom made for the
+archer class, but also make interesting warriors. Even Wood Elf Mages
+are feasible, using the bow to attack and saving their magic for defence.
+
+#####GStat Modifiers
+Strength -3
+Intelligence +2
+Wisdom +1
+Dexterity +5
+Constitution -4
+Charisma +1
+Hit Dice Sides 7
+Exp Penalty +30%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -2.500 [0.000]
+ Archery 4.000 [0.000]
+Sneakiness 0.800 [0.000]
+ Stealth 5.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic
+ Magic-Device 0.600 [0.000]
+Spirituality 4.000 [0.000]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Tree-walking 1
diff --git a/lib/help/r_yeek.txt b/lib/help/r_yeek.txt
new file mode 100644
index 00000000..5326f604
--- /dev/null
+++ b/lib/help/r_yeek.txt
@@ -0,0 +1,30 @@
+~~~~~01|Yeek
+~~~~~02|Races|Yeek
+#####R=== Yeeks ===
+
+#####GDescription
+Yeeks are the least powerful of all the races. They suffer disadvantages
+in nearly all skills and attributes but to compensate they learn (and thus
+gain levels) extremely quickly. "Live fast, die young!"
+
+#####GStat Modifiers
+Strength -5
+Intelligence -5
+Wisdom -5
+Dexterity -5
+Constitution -5
+Charisma -5
+Hit Dice Sides 6
+Exp Penalty -75%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.500 [0.000]
+ Archery -0.500 [0.000]
+Sneakiness -0.500 [0.000]
+ Stealth -5.000 [0.000]
+ Disarming -0.500 [0.000]
+Magic
+ Magic-Device -0.500 [0.000]
+Spirituality -2.500 [0.000]
diff --git a/lib/help/rm_barb.txt b/lib/help/rm_barb.txt
new file mode 100644
index 00000000..57d793ff
--- /dev/null
+++ b/lib/help/rm_barb.txt
@@ -0,0 +1,38 @@
+~~~~~01|Barbarian
+~~~~~02|Race Modifiers|Barbarian
+#####R=== Barbarian Race ===
+
+#####GDescription
+Barbarians are hardy members of their race. They are fierce in combat, and
+their wrath is feared throughout the world. Combat is their life: they learn
+to feel no fear. Barbarians are, however, suspicious of magic, which makes
+magic devices fairly hard for them to use, and also makes it impossible for
+them to play Mages.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -3
+Wisdom -2
+Dexterity +1
+Constitution +1
+Charisma -3
+Hit Dice +1 side
+Spell Points -50%
+Exp Penalty +25%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.200 [0.000]
+ Archery 0.500 [0.000]
+Sneakiness
+ Stealth -2.000 [0.000]
+ Disarming -0.200 [0.000]
+Magic
+ Magic-Device -1.000 [0.000]
+Spirituality 0.200 [0.000]
+
+#####GStarting Equipment
+A barbarian character begins the game with:
+ Some rations
+ Some torches
diff --git a/lib/help/rm_class.txt b/lib/help/rm_class.txt
new file mode 100644
index 00000000..81f72d87
--- /dev/null
+++ b/lib/help/rm_class.txt
@@ -0,0 +1,14 @@
+~~~~~01|Classical
+~~~~~02|Race Modifiers|Classical
+#####R=== Classical Race ===
+
+#####GDescription
+This is the normal, classical character of your chosen race.
+
+#####GStat Modifiers
+No changes to stats.
+
+#####GStarting Equipment
+A classical character begins the game with:
+ Some rations
+ Some torches
diff --git a/lib/help/rm_herm.txt b/lib/help/rm_herm.txt
new file mode 100644
index 00000000..4787b8ae
--- /dev/null
+++ b/lib/help/rm_herm.txt
@@ -0,0 +1,36 @@
+~~~~~01|Hermit
+~~~~~02|Race Modifiers|Hermit
+#####R=== Hermit Race ===
+
+#####GDescription
+Hermits live retired from the world. Spending long hours studying, they
+weaken their physical side while they strengthen their spiritual powers.
+Thus they get higher mana reserves but are much worse at physical combat.
+
+#####GStat Modifiers
+Strength -3
+Intelligence +1
+Wisdom +1
+Dexterity -3
+Constitution -3
+Charisma +1
+Hit Dice -3 sides
+Spell Points +20%
+Exp Penalty +20%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.500 [0.000]
+ Archery -0.500 [0.000]
+Sneakiness 0.400 [0.000]
+ Stealth 3.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic
+ Magic-Device 1.000 [0.000]
+Spirituality 0.500 [0.000]
+
+#####GStarting Equipment
+A hermit begins the game with:
+ Some rations
+ Some torches
diff --git a/lib/help/rm_lsoul.txt b/lib/help/rm_lsoul.txt
new file mode 100644
index 00000000..8a2e8a9c
--- /dev/null
+++ b/lib/help/rm_lsoul.txt
@@ -0,0 +1,26 @@
+~~~~~01|Lost Soul
+~~~~~02|Race Modifiers|Lost Soul
+#####R=== LostSoul ===
+
+#####GDescription
+
+#####RThis is a difficult modifier. Your character will almost always die quickly.
+#####RIt's probably best only to play it after you have some experience with normal
+#####Rcharacters.
+
+There are haunting whispers of souls that have come back from the Halls of
+Mandos, for purposes unknown. These are called Lost Souls, for it is presumed
+that their real body died off long ago, leaving only a soul to wander forever...
+or until killed again.
+Lost Souls start at level 98 of the Halls of Mandos. Very few ever make it out
+again. Those that do can continue as a fairly normal character, but with the
+advantage of any treasure and experience gained.
+
+#####GStat Modifiers
+No changes to stats.
+
+#####GStarting Equipment
+A Lost Soul starts the game with:
+ Some torches.
+ Over thirty scrolls of Identify.
+ Over twenty scrolls of Satisfy Hunger.
diff --git a/lib/help/rm_skel.txt b/lib/help/rm_skel.txt
new file mode 100644
index 00000000..aff6408d
--- /dev/null
+++ b/lib/help/rm_skel.txt
@@ -0,0 +1,40 @@
+~~~~~01|Skeleton
+~~~~~02|Race Modifiers|Skeleton
+#####R=== Skeletal Race ===
+
+#####GDescription
+As undead beings, skeletons need to worry very little about poison or
+attacks that can drain life. They do not really use eyes for perceiving
+things, and are thus not fooled by invisibility. Their bones are resistant
+to sharp shrapnels (not much to cut there), and they will quickly become
+resistant to cold. It is very hard for skeletons to eat food or drink potions.
+Although the magical effects of these will affect the skeleton even without
+entering the skeleton's (non-existent) belly, the potion / food itself will
+fall through the skeleton's jaws, giving no nutritional benefit.
+
+#####GStat Modifiers
+Strength 0
+Intelligence -2
+Wisdom -2
+Dexterity 0
+Constitution +1
+Charisma -4
+Hit Dice +0 sides
+Spell Points -30%
+Exp Penalty +45%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 0.800 [0.000]
+Sneakiness -0.100 [0.000]
+ Stealth -1.000 [0.000]
+ Disarming -0.500 [0.000]
+Magic
+ Magic-Device -0.500 [0.000]
+Spirituality 0.500 [0.000]
+
+#####GStarting Equipment
+A skeletal character begins the game with:
+ Some scrolls of satisfy hunger
+ Some torches
diff --git a/lib/help/rm_spec.txt b/lib/help/rm_spec.txt
new file mode 100644
index 00000000..4a11e0fd
--- /dev/null
+++ b/lib/help/rm_spec.txt
@@ -0,0 +1,44 @@
+~~~~~01|Spectre
+~~~~~02|Race Modifiers|Spectre
+#####R=== Spectral Race ===
+
+#####GDescription
+
+Another powerful undead creature, the spectre is a ghastly apparition,
+surrounded by an unearthly glow. They exist only partially on our
+plane of existence: half-corporeal, they can pass through walls, though
+this requires a sacrifice of some of their life-force. As a result
+they cannot rest whilst passing through a wall.
+
+As undead, they have a firm hold on their life force, can see invisible, and
+resist poison and cold. They also resist nether. Spectres make superb
+spellcasters, but their physical form is very weak. Like Zombies,
+Spectres gain almost no nutrition from ordinary food.
+
+#####GStat Modifiers
+Strength -5
+Intelligence +2
+Wisdom +2
+Dexterity +2
+Constitution -3
+Charisma -6
+Hit Dice -3 sides
+Spell Points +5%
+Exp Penalty +80%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.500 [0.000]
+ Archery -0.200 [0.000]
+Sneakiness 0.200 [0.000]
+ Stealth 2.000 [0.000]
+ Disarming 0.200 [0.000]
+Magic
+ Magic-Device 0.800 [0.000]
+Spirituality 0.700 [0.000]
+
+#####GStarting Equipment
+A spectral character begins the game with:
+ Some scrolls of satisfy hunger
+ Some torches
diff --git a/lib/help/rm_vamp.txt b/lib/help/rm_vamp.txt
new file mode 100644
index 00000000..22ae6514
--- /dev/null
+++ b/lib/help/rm_vamp.txt
@@ -0,0 +1,32 @@
+~~~~~01|Vampire
+~~~~~02|Race Modifiers|Vampire
+#####R=== Vampire ===
+
+#####GDescription
+One of the mightier undead creatures, the vampire is an awe-inspiring
+sight. Yet this mighty creature has a serious weakness: the bright rays of
+sun are its bane, and it will need to flee the surface to the deep
+recesses of the earth until the sun finally sets. Darkness, on the other
+hand, only makes the vampire stronger. Being undead, the vampire has a firm
+hold on its life force, and resists nether attacks. The vampire also
+resists cold and poison based attacks. It is, however, susceptible to its
+perpetual hunger for fresh blood, which can only be satiated by sucking
+the blood from a nearby monster, which is the vampire's special power.
+
+It should be noted that the vampires are so sensitive to daylight that even
+certain artifact light items which are filled with daylight will hurt them
+if they try to wield the items. Fortunately, the vampires do not really
+need these items, since they radiate an aura of 'dark light' of their own.
+Light resistance will, in any case, protect the vampire from the adverse
+effects of sunlight.
+
+#####GStat Modifiers
+Strength +3
+Intelligence +2
+Wisdom -3
+Dexterity -2
+Constitution +1
+Charisma -4
+Hit Dice +1 side
+Spell Points +0%
+Exp penalty +100%
diff --git a/lib/help/rm_zomb.txt b/lib/help/rm_zomb.txt
new file mode 100644
index 00000000..be89162b
--- /dev/null
+++ b/lib/help/rm_zomb.txt
@@ -0,0 +1,39 @@
+~~~~~01|Zombie
+~~~~~02|Race Modifiers|Zombie
+#####R=== Zombie Race ===
+
+#####GDescription
+Much like Skeletons, zombies too are undead horrors: they are resistant to
+life-draining attacks, they become resistant to cold-based attacks (actually
+earlier than skeletons), resist poison and can see invisible, while being still
+vulnerable to cuts (unlike skeletons). They also gain very little nutrition from
+the food of mortals. However, zombies are, as the name implies, practically
+mindless.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -6
+Wisdom -6
+Dexterity +1
+Constitution +4
+Charisma -5
+Hit Dice +3 sides
+Spell Points -30%
+Exp Penalty +45%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 0.500 [0.000]
+Sneakiness -0.100 [0.000]
+ Stealth -1.000 [0.000]
+ Disarming -0.200 [0.000]
+Magic
+ Magic-Device -0.200 [0.000]
+Spirituality 0.500 [0.000]
+
+#####GStarting Equipment
+A zombie character begins the game with:
+ Some scrolls of satisfy hunger
+ Some torches
+
diff --git a/lib/help/skills.txt b/lib/help/skills.txt
new file mode 100644
index 00000000..c4a02c06
--- /dev/null
+++ b/lib/help/skills.txt
@@ -0,0 +1,539 @@
+|||||oy
+~~~~~55|Skills
+#####R=== ToME Skills System ===
+One of the big differences between standard "Vanilla" Angband and ToME is the
+implementation of a skill system where the player can choose what skills she
+will improve as her character progresses. As such, many abilities such as
+spell casting, fighting and trap disarming *do not* increase automatically -
+the player must choose to use skill points to improve those abilities. This
+gives the player the chance to tailor a character to suit their playing style
+with a lot more flexibility than has existed with a fixed progression system
+in the past. However, not all types of characters are able to gain skills to
+the same degree; while a fighter can learn some magic, he's unlikely to become
+as good at it as a mage can. So the number of skill points required to raise
+a skill to the next level varies according to the starting "type" of character.
+
+You can also spend skill points in "one-off purchase" *****ability.txt*0[Abilities].
+~~~~~56|Skills|Screen
+#####GThe Skills Menu
+Each time you gain a level of experience, you receive 6 skill points to spread
+around as you wish. To use these skill points, you need to access the skills
+menu ("G" for both keysets). This opens up a long list of abilities that can
+be improved. The menu may look something like this:
+
+&&&&&w w w w w w w w w w w w w w w w w w w w w w w w w w w w wTwowMwEw wSwkwiwlwlwsw wSwcwrwewewnw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&BEBnBtBeBrW WtWoW WdWeWvWeWlWoWpW WaW WbWrWaWnWcWhW,W BuBpW/BdBoBwBnW WtWoW WmWoWvWeW,W BrBiBgBhBtW/BlBeBfBtW WtWoW WmWoWdWiWfWyW,W B?W WfWoWrW WhWeWlWpw w w w
+&&&&&BSBkBiBlBlB BpBoBiBnBtBsB BlBeBfBtB:B B6w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&yGyeynyeyryayly yaybyiylyiytyyy ytyoy yfyiygyhyty yaynydy ytyoy ypysyeyuydyoy-yiydy yayrymyoyrysy yaynydy ywyeyaypyoynysy.w w w w w w w w w w w w w w w w w w w
+&&&&&yIyty yaylysyoy yaylylyoywysy ytyoy yuysyey yhyeyayvyiyeyry yayrymyoyuyrysy ywyiytyhyoyuyty ypyeynyaylytyiyeysw w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&G[G-G]GCGoGmGbGaGtw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w G0G2G.G0G0G0G G[G0G.G8G0G0G]w w w w w w
+&&&&&w w w w w w-w wWwewawpwownwmwawswtwewrwyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w8w5w0w]w w w w w w
+&&&&&w w w w w w w w o o.o oSowooorodo-omoaosotoeoroyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o4o0o0o]w w w w w w
+&&&&&w w w w w w w w o o.o oAoxoeo-omoaosotoeoroyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o4o0o0o]w w w w w w
+&&&&&w w w w w w w w o o.o oHoaofotoeodo-omoaosotoeoroyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o4o0o0o]w w w w w w
+&&&&&w w w w w w w w o o.o oPoooloeoaoromo-omoaosotoeoroyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o4o0o0o]w w w w w w
+&&&&&w w w w w w.w wAwrwcwhwewrwyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w6w0w0w]w w w w w w
+&&&&&w w w w o o.o oAonotoiomoaogoiocw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o5o5o0o]w w w w w w
+&&&&&w w+w wSwnwewawkwiwnwewswsw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w9w0w0w]w w w w w w
+&&&&&w w+w wMwawgwiwcw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w3w0w0w]w w w w w w
+&&&&&w w-w wSwpwiwrwiwtwuwawlwiwtwyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w4w0w0w]w w w w w w
+&&&&&w w w w o o.o oPoroaoyoeorw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o5o0o0o]w w w w w w
+&&&&&o o.o oMooonosotoeoro-oloooroew w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o5o0o0o]w w w w w w
+
+Now, looking at this screen, there are several things to be aware of. The
+first line lets you know if you have any available skill points to spend, and
+how many there are. Following that are 2 description lines for the currently
+selected skill - in this case they are describing the "Combat" skill. When
+looking at the list of skills, there are a few different colours used - the
+light green coloured skill (which also has its starting character in square
+brackets []) is the currently selected one - Combat in the example above.
+Skills that you cannot learn are omitted from the list. Skills that you are
+capable of learning, but as yet have not, are coloured in orange, while skills
+of which you have some knowledge are shown in white.
+
+At the end of each skill is a pair of numbers. The first represents your
+current level of knowledge in the skill, and the second how much an advance
+in this knowledge investing one skill point in this skill would produce. So,
+in the above example, if the player invested one skill point in their Combat
+skill, the skill would increase from 02.000 to 02.800.
+
+In addition, investing in some skills may raise your knowledge in others.
+This improvement is based on the modifier in the related class (the one which
+gets the free points). For example, a skill point put into Weaponmastery
+raises Combat by 0.5 skill points. This is actually multiplied by the skill
+modifier that your character has in the Combat skill. For example, a
+Swordmaster investing a skill point into Weaponmastery would have his Combat
+skill raised by 0.5 * [0.900] while a Runecrafter would have his Combat
+skill raised by 0.5 * [0.200].
+
+As well as this, skills are grouped together in similar types. Looking under
+the Combat skill, there are subtypes of Weaponmastery, Archery and Antimagic.
+An increase of one of these subskills may also increase the main skill by a
+small amount. You can tell which skills have subskills by the + (or -) in front
+of their name. The + indicates that there are more skills within this category.
+To open a skill category up, move the cursor up/down until the skill category
+is green, then hit the "Enter" key. Likewise, the - indicates that the category
+is already opened, and selecting this and hitting the "Enter" key will close it
+up again. Skills which don't have usable subskills start with a ".".
+
+To spend points on a skill (including skill categories), use the left/right
+arrow (right arrow or "6" adds one skill point, left arrow or "4" removes
+one). Spending points on a sub-skill will also marginally improve the parent
+skill (or skill category). When you've finished spending skill points (and any
+unspent points *will* be saved), hit the "Esc" key to finish. This will give
+a confirmation prompt to check that you really do want to spend your points as
+you've assigned them. Saying 'y' saves the changes and allows you to use or
+apply your new skills :).
+
+All skills have a maximum level of 50, and as long as you can learn a skill,
+and have enough skill points to pump into it, it is theoretically possible to
+get it to level 50 no matter what your race, class or how you learned it.
+
+Each skill affects your character differently. It may be worth getting one or
+more of your characters skills to 50, but it may not be worth investing [[[[[Bany]
+skill points in some other skills. As general and personal advice, which may
+not work for you, I'd say concentrate on a few skills, and leave the others
+empty. Just because you [[[[[Bcan] learn a skill, it doesn't mean you have to.
+It often pays to have a plan ("I'm going to make this assassin the
+stealthiest, most able-dodging, backstabber around. I'm not going to bother
+with trapping or thieving ability") which you can stick to for the whole game.
+~~~~~57|Skills|List of skills
+#####GThe Skills Themselves
+So you want to know what each of the skills do so that you can decide how to
+spend you're hard-earned points, huh? Well, each skill affects different
+abilities, and not all of them are intuitive - but they don't take all that
+long to learn :).
+If you don't find this informative enough, and would like more detailed spoilers
+on what each skill does, try [[[[[ghttp://www.killerbunnies.org/angband/skill-220.html]
+for some third party help!
+The skills are:
+
+ *****skills.txt*27[Air] *****skills.txt*49[Alchemy] *****skills.txt*50[Antimagic] *****skills.txt*08[Archery]
+ *****skills.txt*05[Axe-mastery] *****skills.txt*18[Backstab] *****skills.txt*13[Barehand-combat] *****skills.txt*61[Bearform-combat]
+ *****skills.txt*12[Boomerang-mastery] *****skills.txt*58[Boulder-throwing] *****skills.txt*10[Bow-mastery] *****skills.txt*01[Combat]
+ *****skills.txt*30[Conveyance] *****skills.txt*44[Corpse-preservation]*****skills.txt*04[Critical-hits] *****skills.txt*11[Crossbow-mastery]
+ *****skills.txt*52[Demonology] *****skills.txt*16[Disarming] *****skills.txt*31[Divination] *****skills.txt*20[Dodging]
+ *****skills.txt*28[Earth] *****skills.txt*25[Fire] *****skills.txt*60[Geomancy] *****skills.txt*06[Hafted-mastery]
+ *****skills.txt*21[Magic] *****skills.txt*54[Magic-device] *****skills.txt*24[Mana] *****skills.txt*29[Meta]
+ *****skills.txt*47[Mimicry] *****skills.txt*33[Mind] *****skills.txt*41[Mindcraft] *****skills.txt*42[Monster-lore]
+ *****skills.txt*59[Music] *****skills.txt*34[Nature] *****skills.txt*35[Necromancy] *****skills.txt*07[Polearm-mastery]
+ *****skills.txt*45[Possession] *****skills.txt*39[Prayer] *****skills.txt*36[Runecraft] *****skills.txt*09[Sling-mastery]
+ *****skills.txt*14[Sneakiness] *****skills.txt*22[Spell-power] *****skills.txt*38[Spirituality] *****skills.txt*23[Sorcery]
+ *****skills.txt*19[Stealing] *****skills.txt*15[Stealth] *****skills.txt*53[Stunning-blows] *****skills.txt*43[Summoning]
+ *****skills.txt*03[Sword-mastery] *****skills.txt*46[Symbiosis] *****skills.txt*32[Temporal] *****skills.txt*37[Thaumaturgy]
+ *****skills.txt*48[Udun] *****skills.txt*26[Water] *****skills.txt*02[Weaponmastery]
+
+
+~~~~~01|Skills|Combat
+[[[[[BCombat]
+The combat skill is used to determine the maximum combined weight of armour
+you can wear before you become encumbered by it. It also affects your general
+fighting ability, although not to as great an extent as Weaponmastery, and
+determines the speed and strength of pseudo-id of weapons and armour.
+
+Investing in the combat skill? You might be interested in the
+*****ability.txt*05[Extra Max Blow(1)] and *****ability.txt*06[(2)] abilities.
+
+Sub-skills of Combat are Weaponmastery, Archery, Barehand-combat,
+Boulder-throwing and Anti-magic.
+~~~~~02|Skills|Weaponmastery
+[[[[[BWeaponmastery]
+This skill is a sub-skill of the Combat skill. It affects your general
+ability to use melee weapons of all sorts. Spending 1 skill point on
+Weaponmastery adds 0.5 bonus skill points to Combat.
+
+Investing in the weaponmastery skill? You might be interested in the
+*****ability.txt*02[Spread Blows] ability.
+
+Sub-skills of Weaponmastery are Sword-mastery, Axe-mastery, Hafted-mastery
+and Polearm-mastery.
+~~~~~03|Skills|Sword-mastery
+[[[[[BSword-mastery]
+This skill is a sub-skill of the Weaponmastery skill. It affects your ability
+to use bladed weapons (e.g. daggers, swords). Spending 1 skill point on your
+Sword-mastery skill adds 0.25 bonus skill points to your Weaponmastery skill
+and adds 0.07 bonus skill points to your Combat skill.
+
+Critical-hits is a sub-skill of Sword-mastery.
+~~~~~04|Skills|Critical-Hits
+[[[[[BCritical-hits]
+This skill is a sub-skill of the Sword-mastery skill. It affects your ability
+to deal critical hits to monsters using a bladed weapon that weighs less than 5
+pounds. Spending one skill point on your Critical-hits skill also increases
+your Sword-mastery skill by 0.05 skill points.
+~~~~~05|Skills|Axe-mastery
+[[[[[BAxe-mastery]
+This skill is a sub-skill of the Weaponmastery skill. It affects your ability
+to use axes. Spending 1 skill point on your Axe-mastery skill adds 0.25 bonus
+skill points to your Weaponmastery skill and adds 0.07 bonus skill points to
+your Combat skill.
+~~~~~06|Skills|Hafted-mastery
+[[[[[BHafted-mastery]
+This skill is a sub-skill of the Weaponmastery skill. It affects your ability
+to use hafted weapons (e.g. whips & maces). Spending 1 skill point on your
+Hafted-mastery skill adds 0.25 bonus skill points to your Weaponmastery skill
+and adds 0.07 bonus skill points to your Combat skill.
+
+Stunning-blows is a sub-skill of Hafted-mastery.
+~~~~~53|Skills|Stunning-blows
+[[[[[BStunning-blows]
+This skill is a sub-skill of the Hafted-mastery skill. It affects your ability
+to stun opponents when doing critical hits with a hafted weapon that weighs
+more than 5 lbs. Spending one skill point on your Stunning-blows skill also
+increases your Hafted-mastery skill by 0.05 skill points.
+~~~~~07|Skills|Polearm-mastery
+[[[[[BPolearm-mastery]
+This skill is a sub-skill of the Weaponmastery skill. It affects your ability
+to use polearms (e.g. pikes & halberds). Spending 1 skill point on your
+Polearm-mastery skill adds 0.25 bonus skill points to your Weaponmastery skill
+and adds 0.07 bonus skill points to your Combat skill.
+
+Investing in the Polearm-mastery skill? You might be interested in the
+*****ability.txt*10[Far reaching attack] ability.
+~~~~~08|Skills|Archery
+[[[[[BArchery]
+This skill is a sub-skill of the Combat skill. It affects your general
+ability to use ranged weapons of all sorts. Spending one skill point on your
+Archery skill adds 0.5 bonus skill points to your Combat skill.
+
+Investing in the Archery skill? You might be interested in the
+*****ability.txt*07[Ammo creation] ability.
+
+Sub-skills of Archery include Sling-mastery, Bow-mastery, Crossbow-mastery
+and Boomerang-mastery.
+~~~~~09|Skills|Sling-mastery
+[[[[[BSling-mastery]
+This skill is a sub-skill of the Archery skill. It affects your ability to
+use Slings. Spending 1 skill point on your Sling-mastery skill adds 0.25
+bonus skill points to your Archery skill and 0.07 bonus skill points to your
+Combat skill.
+~~~~~10|Skills|Bow-mastery
+[[[[[BBow-mastery]
+This skill is a sub-skill of the Archery skill. It affects your ability to
+use both Long and Short Bows. Spending 1 skill point on your Bow-mastery
+skill adds 0.25 bonus skill points to your Archery skill and 0.07 bonus skill
+points to your Combat skill.
+~~~~~11|Skills|Crossbow-mastery
+[[[[[BCrossbow-mastery]
+This skill is a sub-skill of the Archery skill. It affects your ability
+to use both Heavy and Light Crossbows. Spending 1 skill point on your
+Crossbow-mastery skill adds 0.25 bonus skill points to your Archery skill
+and 0.07 bonus skill points to your Combat skill.
+~~~~~12|Skills|Boomerang-mastery
+[[[[[BBoomerang-mastery]
+This skill is a sub-skill of the Archery skill. It affects your ability to
+use all boomerangs. Spending 1 skill point on your Boomerang-mastery skill
+adds 0.25 bonus skill points to your Archery skill and 0.07 bonus skill
+points to your Combat skill.
+~~~~~13|Skills|Barehand-combat
+[[[[[BBarehand-combat]
+This skill is a sub-skill of the Combat skill. It affects your general ability
+to fight using martial arts. In order to utilise it, you must be capable of
+using a weapon in the first place, but choose not to. Spending 1 skill point
+on your Barehand-combat skill adds 0.5 bonus skill points to your Combat skill.
+Barehand-combat fighters develop stronger and faster attacks, and also gain
+speed bonuses, as they advance in skill. However, they cannot use this skill
+whilst wearing heavy armour.
+~~~~~61|Skills|Bearform-combat
+[[[[[BBearform-combat]
+This skill is a sub-skill of the Combat skill. It affects your ability to fight
+while in the form of a bear. In order to utilise it, you must be in bearform.
+*****r_beorn.txt*0[Beornings] are the adventurers most likely to use this form of skill.
+~~~~~58|Skills|Boulder-throwing
+[[[[[BBoulder-throwing]
+This skill is a sub-skill of the Combat skill. It affects your ability to
+throw boulders and make them from granite walls. Spending 1 skill point on
+your Boulder-throwing skill adds 0.4 bonus skill points to your Combat skill.
+~~~~~50|Skills|Antimagic
+[[[[[BAntimagic]
+This skill is a sub-skill of the Combat skill. It generates a field around
+the character within which magic cannot work. As such, it can be very useful
+to prevent monsters from casting offensive spells against you or from
+teleporting away from you just before you kill them - but it will also prevent
+you from casting spells, or teleporting away when they've almost killed you!
+It also inhibits your ability to do magic, affecting *all* the magic and
+spirituality sub-skills.
+
+This skill does not affect your ability to use scrolls and potions, but other
+items that require [Self]Magic-Device are affected. At higher levels you gain
+the ability to detect traps and disrupt all teleportation.
+~~~~~14|Skills|Sneakiness
+[[[[[BSneakiness]
+The sneakiness skill affects your searching and perception abilities.
+
+Sub-skills of Sneakiness include Stealth, Disarming, Trapping, Backstab,
+Stealing and Dodging.
+~~~~~15|Skills|Stealth
+[[[[[BStealth]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to move around the dungeon quietly so that you are not noticed by its
+inhabitants. Spending 1 skill point on your Stealth skill adds 0.15 bonus
+skill points to your Sneakiness skill.
+~~~~~16|Skills|Disarming
+[[[[[BDisarming]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to safely disarm any traps you find. Spending 1 skill point on your Disarming
+skill adds 0.1 bonus skill points to your Sneakiness skill.
+
+Investing in the Disarming skill? You might be interested in the *****ability.txt*11[Trapping]
+ability.
+~~~~~18|Skills|Backstab
+[[[[[BBackstab]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to sneak up on monsters and do extra damage to them before they wake up.
+It also affects monsters who have turned to flee from you. Spending 1 skill
+point on your Backstab skill adds 0.05 bonus skill points to your Sneakiness
+skill.
+~~~~~19|Skills|Stealing
+[[[[[BStealing]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to steal items from monsters and shops. Be careful when stealing from shops;
+if you're caught, the shopkeeper will close his doors to you and not open
+them again. I have heard that shop keepers do not stay in one shop forever
+though. Spending 1 skill point on your Stealing skill adds 0.15 bonus skill
+points to your Sneakiness skill.
+~~~~~20|Skills|Dodging
+[[[[[BDodging]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to dodge out of the way of monster blows and bolts. The less armour you wear
+and the less you carry, the greater your chance of dodging a blow. Rings and
+amulets do not affect your chance to dodge, but full armour will almost render
+the effect of the skill obsolete. Spending 1 skill point on your Dodging skill
+adds 0.1 bonus skill points to your Sneakiness skill.
+~~~~~21|Skills|Magic
+[[[[[BMagic]
+The Magic skill affects your general use of magic items, the amount of mana
+you can handle, and in general your ability to do magic. It can also affect
+the strength of wands and staffs.
+
+Investing in the Magic skill? You might be interested in the *****ability.txt*04[Perfect Casting]
+ability.
+
+Sub-skills include: Magic-device, Spell-power, Sorcery, Mana, Fire, Water, Air,
+Earth, Meta, Conveyance, Divination, Temporal, Mind, Nature, Udun, Demonology,
+Necromancy, Runecraft, Thaumaturgy, and Alchemy.
+~~~~~54|Skills|Magic-device
+[[[[[BMagic-device]
+This skill is a sub-skill of the Magic skill. It eases the use of magical
+devices, such as wands, staves, and rods, and boosts the casting level of spells
+stored in a wand or a staff. *****magic.txt*02[More on this]. It also helps pseudo-id of magic
+objects. Spending 1 skill point on your Magic-device skill adds 0.07 bonus skill
+points to your Magic skill.
+~~~~~22|Skills|Spell-power
+[[[[[BSpell-power]
+This skill is a sub-skill of the Magic skill. It boosts the casting level of
+most spells you are capable of casting. For example, if you have level one in
+the mana school, you could cast "Manathrust". For every 2.5 skill levels of
+Spell-power, Manathrust becomes more powerful, adding +1 casting level to the
+spell. Note that this is not exactly the same as certain magic items which
+boost spell power. Spending 1 skill point on your Spell-power skill adds 0.2
+bonus skill points to your Magic skill.
+
+[[[[[BThis skill only affects the 11 primary schools] (Mana, Earth, Air, Fire,
+Water, Meta, Mind, Temporal, Conveyance, Divination and Nature), as well as
+Geomancy and the spells granted by the Gods.
+~~~~~23|Skills|Sorcery
+[[[[[BSorcery]
+This skill is a sub-skill of the Magic skill. It allows you to access any
+spell in the 11 schools up to the sorcery skill level. For example, if you
+have a sorcery skill of 1, you could cast "Manathrust", which is a level 1
+mana school spell; and "Phase Door", which is a level 1 conveyance school
+spell. Spending 1 skill point on your Sorcery skill adds 0.2 bonus skill
+points to your Magic skill.
+
+[[[[[BThis skill only affects the 11 primary schools] (Mana, Earth, Air, Fire,
+Water, Meta, Mind, Temporal, Conveyance, Divination and Nature).
+
+However, handling that much magic is hazardous to your health, and as such
+reduces both your hit points and your fighting ability. Any ability in sorcery
+affects your Weaponmastery, Archery, Barehand-combat and gives a negative
+percentage modifier to your total hit points, equal to the level of your
+sorcery skill (i.e. if sorcery is 12.500, hit points get modified by -12.5%).
+~~~~~24|Skills|Mana
+[[[[[BMana]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_mana.txt*0[mana] school, and as it increases so does the casting level of
+spells already attained in the school. For example, if you have level 1 in
+the mana school, you could cast "Manathrust" at a casting level of 1. For
+every skill level you add to Mana, Manathrust will become more powerful,
+adding 1 casting level to the spell. Spending 1 skill point on your Mana
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~60|Skills|Geomancy
+[[[[[BGeomancy]
+This skill is a subskill of the Magic skill. It gives access to spells
+within the *****m_geoman.txt*0[Geomancy] school, and as it increases so does the casting level of
+spells already attained in the school. Most spells from this school rely
+on the Fire, Water, Air and Earth skills as well. Spending 1 skill point
+on your Geomancy skill adds 0.45 bonus skill points to your Fire, Water,
+Air and Earth skills.
+~~~~~25|Skills|Fire
+[[[[[BFire]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_fire.txt*0[fire] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Fire
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~26|Skills|Water
+[[[[[BWater]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_water.txt*0[water] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Water
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~27|Skills|Air
+[[[[[BAir]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_air.txt*0[air] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Air
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~28|Skills|Earth
+[[[[[BEarth]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_earth.txt*0[earth] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Earth
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~29|Skills|Meta
+[[[[[BMeta]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_meta.txt*0[meta] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Meta
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~30|Skills|Conveyance
+[[[[[BConveyance]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_convey.txt*0[conveyance] school, and as it increases so does the casting level
+of spells already attained in the school. Spending 1 skill point on your
+Conveyance skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~31|Skills|Divination
+[[[[[BDivination]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_divin.txt*0[divination] school, and as it increases so does the casting level
+of spells already attained in the school. Spending 1 skill point on your
+Divination skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~32|Skills|Temporal
+[[[[[BTemporal]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_tempo.txt*0[temporal] school, and as it increases so does the casting level
+of spells already attained in the school. Spending 1 skill point on your
+Temporal skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~33|Skills|Mind
+[[[[[BMind]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_mind.txt*0[mind] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Mind
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~34|Skills|Nature
+[[[[[BNature]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_nature.txt*0[nature] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Nature
+skill adds 0.1 bonus skill points to your Magic skill.
+
+Investing in the Nature skill? You might be interested in the *****ability.txt*03[Tree Walking]
+ability.
+~~~~~48|Skills|Udun
+[[[[[BUdun]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_udun.txt*0[Udun] school, and is available only to worshippers of Melkor.
+As it increases so does the casting level of spells already attained in the
+school. Spending 1 skill point on your Udun skill adds 0.1 bonus skill
+points to your Magic skill.
+~~~~~52|Skills|Demonology
+[[[[[BDemonology]
+This skill is a sub-skill of the Magic skill. *****m_demono.txt*0[Demonology] gives access to spells
+contained within special Demon-blades, -shields and -horns (helms), and as it
+increases so does the casting level of spells already attained in the school.
+This skill is available only to Demonologists, or those sufficiently
+corrupted with demon-like powers. Spending 1 skill point on your Demonology
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~35|Skills|Necromancy
+[[[[[BNecromancy]
+This skill is a sub-skill of the Magic skill. It grants access to *****m_necrom.txt*0[necromancy]
+spells. This is the base skill of the Necromancer class. Spending 1 skill
+point on your Necromancy skill adds 0.04 bonus skill points to your Magic skill.
+
+Investing in the Necromancy skill? You might be interested in the
+*****ability.txt*08[Touch of Death] and *****ability.txt*12[Undead Form] abilities.
+~~~~~36|Skills|Runecraft
+[[[[[BRunecraft]
+This skill is a sub-skill of the Magic skill. This is the base skill of the
+Runecrafter class. Spending 1 skill point on your Runecraft skill adds 0.12
+bonus skill points to your Magic skill.
+~~~~~37|Skills|Thaumaturgy
+[[[[[BThaumaturgy]
+This skill is a sub-skill of the Magic skill. Each level of *****m_thaum.txt*0[thaumaturgy] gives
+a few random attack spells that can be cast without the use of spell books of
+any sort. However, once learned these spells do not gain in levels as the
+thaumaturgy skill or the spell-power skills are increased. Spending 1 skill
+point on your Thaumaturgy skill adds 0.06 bonus skill points to your Magic
+skill.
+~~~~~49|Skills|Alchemy
+[[[[[BAlchemy]
+The Alchemy skill affects your ability to extract and use essences to create
+magical items.
+
+Investing in the Alchemy skill? You might be interested in the *****ability.txt*09[Artifact Creation]
+ability.
+~~~~~38|Skills|Spirituality
+[[[[[BSpirituality]
+The spirituality skill influences things which have a "helping hand" from the
+Gods, like your saving throw, and the general spirituality skills.
+
+Sub-skills of Spirituality are Prayer, Mindcraft and Music.
+~~~~~39|Skills|Prayer
+[[[[[BPrayer]
+This skill is a sub-skill of the Spirituality skill. It affects what level of
+your *****gods.txt*0[God's] special magic you can access (and what levels of the additional
+schools that each God also provides). Spending 1 skill point on your Prayer
+skill adds 0.1 bonus skill points to your Spirituality skill and 0.1 bonus
+skill points to your Magic skill.
+~~~~~41|Skills|Mindcraft
+[[[[[BMindcraft]
+This skill is a sub-skill of the Spirituality skill. It affects what level of
+*****m_mindcr.txt*0[Mindcrafter powers] you can access, which is done without books and is
+available under the "m" menu. Spending 1 skill point on your Mindcraft skill
+adds 0.1 bonus skill points to your Spirituality skill and 0.1 bonus skill
+points to your Magic skill.
+~~~~~59|Skills|Music
+[[[[[BMusic]
+This skill is a sub-skill of the Spirituality skill. It affects what level of
+*****m_music.txt*0[Musical songs] you can access through instruments. This power
+is available under the "m" menu. Spending 1 skill point on your Music skill
+adds 0.1 bonus skill points to your Spirituality skill and 0.1 bonus skill
+points to your Magic skill.
+~~~~~42|Skills|Monster-lore
+[[[[[BMonster-lore]
+The monster-lore skill affects your general ability at the monster related
+skills. It determines how much experience you will gain if your *****dungeon.txt*18[pets] kill a
+monster, and how many companions you can have. At skill level 12, it allows
+you to turn a pet into a loyal companion.
+
+Sub-skills of Monster-lore are Summoning, Corpse-preservation, Possession,
+Symbiosis, and Mimicry.
+~~~~~43|Skills|Summoning
+[[[[[BSummoning]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to create "totems" and use them to summon monsters to your aid. Spending 1
+skill point on your Summoning skill adds 0.1 bonus skill points to your
+Monster-lore skill.
+~~~~~44|Skills|Corpse-preservation
+[[[[[BCorpse-preservation]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to kill monsters without destroying their bodies, so the corpses will be
+available to use. Spending 1 skill point on your Corpse-preservation skill
+adds 0.1 bonus skill points to your Monster-lore skill.
+~~~~~45|Skills|Possession
+[[[[[BPossession]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to possess a dead monster's corpse. Spending 1 skill point on your Possession
+skill adds 0.1 bonus skill points to your Monster-lore skill.
+~~~~~46|Skills|Symbiosis
+[[[[[BSymbiosis]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to go into symbiosis with monsters that cannot move, and to cast *****m_symbio.txt*0[Symbiotic]
+spells. Spending 1 skill point on your Symbiosis skill adds 0.1 bonus skill
+points to your Monster-lore skill.
+~~~~~47|Skills|Mimicry
+[[[[[BMimicry]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to use cloaks of mimicry to change form and to cast *****m_mimic.txt*0[Mimicry spells].
+Spending 1 skill point on your Mimicry skill adds 0.1 bonus skill points to
+your Monster-lore skill.
diff --git a/lib/help/spoil_faq.txt b/lib/help/spoil_faq.txt
new file mode 100644
index 00000000..e4a77c15
--- /dev/null
+++ b/lib/help/spoil_faq.txt
@@ -0,0 +1,73 @@
+|||||oy
+~~~~~01|Help|Spoiled FAQ
+~~~~~02|FAQ - contains spoilers
+#####R ToME Spoiler FAQ
+#####R Updated for version 2.3.x
+
+#####G------------------------------------------------------------------------------
+
+This page contains significant spoilers. Don't browse it unless you want some
+parts of the game ruined, but don't expect the spoilers to spoil you completely!
+
+~~~~~06|Spoilers|Merton the lost Hobbit quest
+#####G------------------------------------------------------------------------------
+#####GQ: I'm in the Maze, but I cannot find Merton!
+
+A: Merton appears on a *random* level between dungeon level 26 (1300') and
+36 (1800'). Each maze level is one panel by one panel in size, but *full* of
+passageways - so you may have to do quite a bit of tunnelling to search the
+whole level.
+
+#####G------------------------------------------------------------------------------
+#####GQ: I've found Merton, now what?
+
+A: There is a new command that has been added to ToME that allows you to pass
+objects to creatures. What would you try and do if you had a broken leg and
+needed to get back to the town?
+~~~~~07|Spoilers|Lothlorien Poisoned water quest
+#####G------------------------------------------------------------------------------
+#####GQ: I'm trying to find the Poisoned water quest at Lothlorien, but cannot
+#####G find the quest entrance!
+
+A: This quest is located in the wilderness. To the west of Lothlorien are 4
+water squares in an upside down L shape. One of these squares will contain the
+quest. (Viewed from the Wilderness map). There is no yellow > sign, so don't
+bother looking for one.
+~~~~~20|Spoilers|God Quest - directions
+~~~~~23|Gods|Quest - Spoilers
+#####G------------------------------------------------------------------------------
+#####GQ: I've been given directions to a temple by my God but can't find the
+#####G temple anywhere!
+
+A: It [[[[[BIS] there. However, your god's idea of compass directions that are
+not directly on the 4 main axes are probably slightly less acurate than your
+idea. In other words, if your god says it is South-East, s/he means it is
+somewhere in the quadrant that is between the south and east axes.
+~~~~~21|Spoilers|God Quest - relic
+#####G------------------------------------------------------------------------------
+#####GQ: Where is the relic by god was talking about? I've looked in the lost
+#####G temple and can't find it anywhere!
+
+A: It [[[[[BIS] there. However, when your god told you to look for it VERY
+carefully, s/he meant it. Regardless of your game settings, the relic will only
+be created once in the temple, at a random place. If you have searched the
+whole temple once over, and not located it, then you have missed it, and it is
+lost forever. Each temple has 5 dungeon levels, and the relic might be on
+any of these 5 levels.
+~~~~~22|Spoilers|God Quest - how many?
+#####G------------------------------------------------------------------------------
+#####GQ: Apparently my god has lost another piece of his relic and wants me to go
+#####G find it again. How many of these are there?
+
+A: You can receive up to five god quests, with the final piece yielding an
+extra reward. However you will only receive extra quests if you have
+sucessfully completed all the previous ones.
+~~~~~19|Deathmolds on Mount Doom and other quest areas.
+#####G------------------------------------------------------------------------------
+#####GQ: How do I complete the special no-teleport level quests with a Deathmold?
+
+A: You will need either some morphic oils, some mimicry skill, or the ring of
+Flare. Deathmolds are marked as experimental for a reason you know. Morphic
+oils can also help if you're having trouble communictaing with monsters. A very
+beautiful Elf springs to mind as possibly causing some problems if you are in
+Deathmold form.
diff --git a/lib/help/spoiler.hlp b/lib/help/spoiler.hlp
new file mode 100644
index 00000000..bc229852
--- /dev/null
+++ b/lib/help/spoiler.hlp
@@ -0,0 +1,18 @@
+|||||oy
+~~~~~01|Spoilers
+#####RWelcome to the Angband Online Spoiler System.
+#####R=============================================
+
+Please choose one of the following online spoiler files:
+
+ *****/acorspoil.txt*0[(a) Corruptions]
+ *****/bdunspoil.txt*0[(b) Dungeons]
+ *****/cessences.txt*0[(c) Essence Spoiler]
+ *****/dinscrip.txt*0[(d) Floor Inscriptions]
+ *****/eluckspoi.txt*0[(e) Luck]
+ *****/ffatespoi.txt*0[(f) Fates]
+ *****/gwishing.txt*0[(g) Wishing]
+ *****/hspoil_faq.txt*0[(h) Spoiled FAQ]
+
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
diff --git a/lib/help/tome_faq.txt b/lib/help/tome_faq.txt
new file mode 100644
index 00000000..7ad7a421
--- /dev/null
+++ b/lib/help/tome_faq.txt
@@ -0,0 +1,373 @@
+|||||oy
+~~~~~01|Help|FAQ - Spoiler free
+~~~~~02|FAQ - Spoiler free
+#####R ToME FAQ
+#####R Updated for version 2.3.x
+
+#####G------------------------------------------------------------------------------
+
+#####R=== Differences Between ToME and Vanilla Angband ===
+
+The first main difference a new player to ToME will need to be aware of is
+that it has implemented a skills based system. Instead of the adventurer
+automatically improving in his abilities as he becomes more experienced,
+he gets 6 skill points to spend on his skills, allowing the player to
+customise what type of character she will play. See the *****skills.txt*0[skills] help file
+for details.
+
+A second major difference is that the main dungeon from Angband has been split
+into 4 "dungeons", each of which covers a different portion of the Angband
+dungeon's levels. Each of these 4 dungeons is located either in or near one of
+the four main towns so that the character can keep stocked up on supplies. As
+the adventurer advances in ability, he will need to travel overland to the next
+town/dungeon, which is most easily carried out using the wilderness map ("<"
+from town level). As well as these main places, there are a number of
+additional dungeons which the character may or may not choose to enter, which
+can have guardians, contain specific artifacts, or just be used as an
+alternative place to enjoy gaining experience. Note that not all of the places
+are actually "dungeons" - some are caves, forests, etc.
+
+ToME also offers the player the ability to undertake a series of quests.
+Random quests can be specified during start-up, and involve rescuing a princess
+from a group of monsters within the dungeon, or recovering a lost sword from
+(you guessed it...) a group of monsters. If you do not wish to play with
+random quests, simply specify "0" when asked how many you want during character
+generation. Other "fixed" quests are also available from the towns (whether
+random quests are enabled or not), usually given by the town leaders upon the
+request of the adventurer. It is not required for any adventurer to undertake
+the fixed quests, but they can result in some nice rewards.
+
+The third main difference between Vanilla Angband and ToME is the difference
+in character classes and races, as well as a very different magic system.
+See the help files on *****birth.txt*0[Creating a character] and the *****magic.txt*0[magic] system.
+Class abilities (generally referred to as skills) are generally accessed
+through the 'm' command. Most racial abilities, or corruptions, are accessed
+through the "U" command.
+
+To balance the expansion in things like player abilities and customisation, the
+list of both monsters and items has also been expanded. Be warned that items
+which were by default safe in Vanilla are not necessarily safe in ToME (a
+certain early artifact comes to mind here...), and picking on defenceless
+creatures is frowned upon....
+
+Happy adventuring!
+~~~~~03|Altars
+~~~~~04|Gods|Altars
+#####G------------------------------------------------------------------------------
+#####GQ: How do I use the altars (the 'O's) I see in the dungeon?
+
+A: ToME introduces a new system of gods.
+
+You can find altars only in Lothlorien and in the dungeon.
+The ones on the surface are dedicated to the good Valar (Eru, Manwe, Tulkas and
+Yavanna), while altars found in the dungeons are "sacred" for Melkor.
+You can use altars to convert yourself to the service of a specific Vala by
+using the "O" command while standing on them. Beware, this works only if you
+don't already have a God, and as a new convert, your God won't like you that
+much. Melkor also uses his altars as a mean of collecting sacrifices from his
+devotees; this function is likewise accomplished by the "O" command.
+
+Read *****gods.txt*0[gods.txt] for more information about Gods.
+~~~~~05|Fountains
+#####G------------------------------------------------------------------------------
+#####GQ: How do I use the fountains (the '_'s) I see in the dungeon?
+
+A: Fountains in ToME act like potions, but can only be identified by
+drinking from them. Each one can hold between 3 and 12 doses of the potion.
+Quaffing from a fountain can be done by using the 'H' command (in the standard
+keyset) and answering 'Q' at the prompt.
+
+You can also fill empty bottles at a fountain (enabling you to identify the
+potion and hence the type of fountain) by using the 'H' command and answering
+'F' at the prompt. The game will then ask you to choose bottles and how many
+bottles you want to fill. You can find empty bottles on the dungeon and
+drinking pints of fine ale/wine will give you emtpy bottles; if you are
+trained in Alchemy, you can reuse bottles after quaffing potions as well.
+
+#####G------------------------------------------------------------------------------
+#####GQ: I got killed by a Great Wyrm of Power at 50'!!! What happened?
+
+A: You killed a defenceless creature. I told you that it was frowned upon!
+~~~~~18|Artifacts that activate but I cannot wear or wield
+~~~~~17|Strange items
+#####G------------------------------------------------------------------------------
+#####GQ: I've found some strange items like a Red Tome, a Voodoo Doll, ...
+#####G What can I do with them?
+
+A: You've found an unusual artifact that cannot be wielded, but always
+has a sometimes-useful activation. It will not be listed in the known
+artifact list and its activation is chosen randomly. It would probably be
+wise for this kind of artifact be *identified* before use, as the
+activation can be something very nasty....
+
+To activate it, use the normal Activation command, but when prompted for which
+item to activate change to the backpack instead of wielded equipment.
+~~~~~10|Essences
+~~~~~11|Runes
+#####G------------------------------------------------------------------------------
+#####GQ: I keep coming across "essences" and "runes". What are they?
+
+Essences are the *****c_alchem.txt*0[Alchemist's] friend, and you can only use them if you
+have access to the *****skills.txt*49[Alchemy] skill.
+Runes are used to cast and store spells of varying types. *****c_runecr.txt*0[Runecrafters] are the
+class who are most proficient at using these. You can only use them if you
+have access to the *****skills.txt*36[Runecrafting] skill.
+~~~~~12|Homes
+#####G------------------------------------------------------------------------------
+#####GQ: Where can I store all my equipment? Theere's not enough room in my
+#####Ginventory? And what happened to the thieves quest in Bree?
+
+Nor is there supposed to be enough room in your backpack. It's not
+bottomless you know! If you go talk to the Mayor in Bree, he might let you know
+about a slight problem that there's been in town. If you can clear up the
+problem, you may find yourself with somewhere extra to keep your stuff. I've
+heard tell that there are similiar problems in other towns in Middle-Earth.
+~~~~~13|Fates|Prophets
+#####G------------------------------------------------------------------------------
+#####GQ: I spent 500 gp at the Prophet but she said nothing. Is that a bug ?
+
+A: No. Nor is it because Prophets are swindlers. She said nothing
+because you have no fate at this moment. You gain fates while playing, and
+will be warned by a message such as "You feel your fate has changed". A fate
+can be useless like finding a broken skull at level 30, deadly like dying at
+level 56, or really useful like never dying by the hand of a mortal.
+~~~~~14|Mathilde
+#####G------------------------------------------------------------------------------
+#####GQ: Who is Mathilde, the Science Student whom I see every so often in the
+#####G town?
+
+A: Most of the time she laughs and giggles. She has no loot on her, and
+she's never done you any harm. So leave her be - even if she should
+happen to shout "Drop dead, creep!"
+~~~~~15|Wrists hurting
+#####G------------------------------------------------------------------------------
+#####GQ: My wrists hurt a lot when playing the game. Should I take precautions?
+
+A: Yes, you should. Repetitive strain on wrists (which results from a badly
+placed keyboard, for example) can lead to serious injury of the wrist ligaments
+called Carpal Tunnel Syndrome. If you feel your wrists are strained, here is
+an exercise posted by Jason Maskell in rec.games.roguelike.angband which might
+help:
+
+Hold your arms out horizontally, make a fist, and then point the fist towards
+the floor, as much as you can. This will stretch one side's tendons. Hold for
+5 seconds. Then make a flat hand and hold it level with your arm, hold for 5
+seconds. Now splay your fingers and attempt to make your hand point toward the
+ceiling (this one is hard, so don't push it too much). You should feel your
+tendons stretching. Repeat this a few times. Take frequent breaks and do this
+if it starts to hurt a little bit. I was sliding very fast towards CTS and this
+corrected it.
+~~~~~16|Void jumpgates
+#####G------------------------------------------------------------------------------
+#####GQ: When I stand on void jumpgates I'm never teleported away, what's wrong?
+
+A: Void jumpgates are not automatic. You must press '>' while standing
+on one to activate it.
+
+~~~~~08|Monsters|They are talking to me!
+#####G------------------------------------------------------------------------------
+#####GQ: Farmer Maggot / Melinda Proudfoot keep shouting at me, and I cannot
+#####G kill them.
+
+A: Both these people need to talk to you about something. Have a chat with them
+(check the file *****command.txt*96[command.txt] for how to chat).
+~~~~~09|Sentient weapons
+#####G------------------------------------------------------------------------------
+#####GQ: I have found a sentient weapon, it says it has access to the realms
+#####G of Earth and Fire. How do I use these realms?
+
+A: You don't actually 'use' them as such. If a weapon is sentient it means it
+gains experience itself as it delivers killing blows. As it levels up it has
+the chance to gain pluses to hit and to damage, and also powers from any of the
+available 'realms'. For instance, the realm of fire gives the chance to gain
+resistance to fire, or fire branding on your weapon. The realm of earth has a
+chance to confer extra attacks or the power of causing earthquakes and so on.
+~~~~~24|Fumblefingers quests
+~~~~~25|Abbreviations|FF
+#####G------------------------------------------------------------------------------
+#####GQ: What or who is Fumblefingers? How do I get his quests?
+
+A: FF is short for Fumblefingers, the name that some players give to the
+adventurer who keeps having his sword stolen by monsters and asking you to
+find it for him. So named because he often seems to lose it to molds and
+other creatures you wouldn't expect to be able to pickpocket! During birth
+you'll be asked to specify a number of random quests you would like to
+attempt to complete. Some of these quests will take the form of princess
+quests, others will be fumble-finger quests. If you complete the task he
+sets you sucessfully, he'll offer to join you as a companion. If you do not
+want him to join you, he'll offer to teach you some new skills. Quite handy.
+~~~~~26|Random quests are not working.
+#####G------------------------------------------------------------------------------
+#####GQ: Where has the option gone to set the number of random quests?
+#####G Why aren't there any after the Barrow-downs?
+
+A: Turning on either of the options "Allow permanent dungeon levels" or "Always
+create special rooms" will disable random quests. Random quests can only be
+found in the four main dungeons (Barrowdowns, Mirkwood, Mordor and Angband).
+~~~~~27|Weird display
+~~~~~28|Floor tiles displaying incorrectly
+#####G------------------------------------------------------------------------------
+#####GQ: How do I get the dots to show up on floor tiles in Windows XP? I've tried
+#####G changing the tile character to the brighter dot. Toggling 'Bizarre Display'
+#####G mode helped with the trailing @@@@@@@@@@@@@@@@@ problem. Any suggestions? I
+#####G gave up a long time ago and play with graphics tiles now, but I'd like to be
+#####G able to fix this.
+
+A: In the file ./lib/pref/font_win.prf, either remove or comment out with # the
+lines that end in /0x1F, e.g.
+# open floor
+# F:1:0x01/0x1F
+Another possibility is to manually change the symbols used with the '%'
+command, but the previous solution is faster.
+~~~~~29|Dark grey things are difficult to see
+#####G------------------------------------------------------------------------------
+#####GQ: Many things are written in a dark grey color which is next to impossible to
+#####G read against a black background. Also, some monsters appear in dark grey and
+#####G are easy to miss! What can I do to fix this?
+
+A: Fix the gamma control of your display. If your display software does not
+include such a tool, access the 'Interact with Colors' screen in ToME via
+shift+7, type '4', and modify the gamma correction there.
+~~~~~30|Game 'balance'
+#####G------------------------------------------------------------------------------
+#####GQ: Why don't you make X class less powerful or Y class more powerful?
+
+A: In ToME the player determines how hard the game is. Classes, races, and
+subraces are neither meant nor desired to be equal in game difficulty. So no,
+we won't make Axemasters more powerful just to "balance them out", nor will we
+make Sorcerors weaker.
+~~~~~31|I keep dying!
+#####G------------------------------------------------------------------------------
+#####GQ: Why do I always start in a terribly difficult, very deep dungeon instead of
+#####G a town? Is the game really this hard?
+
+A: You have chosen a "Lost soul" character subrace. That's where Lost souls
+start. They tend to die very quickly, so don't choose them if you're new to
+ToME.
+~~~~~32|Invisible character
+#####G------------------------------------------------------------------------------
+#####GQ: My character is invisible. That's great, but how do I know where she is if
+#####G I can't see her?!
+
+A: You could seek for a way to see invisible things.
+You could also go to game options:
+ 1. Type = (game options)
+ 2. Type 4 (efficiency options)
+ 3. Arrow down to 'hilite the player with the cursor'
+ 4. Type y to toggle the option to 'yes'
+~~~~~33|Objects|Piles
+#####G------------------------------------------------------------------------------
+#####GQ: I'm standing on a pile of items. How do I see what's in the pile without
+#####G picking it all up, moving it, or destroying it all?
+A:
+ 1. Stand on the pile in question
+ 2. Type shift + I (inspect)
+ 3. Type - (examine items on floor)
+ 4. Type * (expand list of items on floor)
+ 5. (as needed) Type letter associated with item to look at it more closely.
+
+#####G------------------------------------------------------------------------------
+#####GQ: If I'm standing on a pile of items. Is there a command to see if there is a
+#####G stairway or jumpgate beneath the pile?
+
+A: Stairs/jumpgates obscured by clutter do still function. You are advised to
+take a good hard look at your surroundings before creating lots of dungeon
+clutter.
+ 1. You can pick up, move, or eliminate the pile.
+ 2. Press l (look), then select the square you wish to inquire about. Press
+<enter>; it will scroll through everything on the ground, and eventually it
+ends with "It is in a Void Jumpgate", or whatever.
+~~~~~34|Character choice is too confusing
+~~~~~36|Beginner strategy
+#####G------------------------------------------------------------------------------
+#####GQ: What is a good starting character?
+
+A: Make sure to read the parchment you start the game with!
+
+If you're new to ToME, understand that your characters are going to die a lot.
+Be prepared for that. In fact, take advantage of it by using the various
+characters you run to experiment and learn the game's various facets.
+
+Try a warrior. A Dunadan Swordmaster is an excellent combination of race and
+class.
+
+Try a priest. A Rohan Knight Paladin gives you some magic to go with strong
+combat, but your terrible stealth will give you a tougher time in some respects.
+
+Try an archer. A Wood-elf Archer will have fewer hitpoints than you're used to,
+but lets you use excellent ranged combat instead. Also note how your higher
+stealth wakes up fewer monsters, letting you fight them more on your own terms.
+
+Try a mage. A Dark-elf Mage lets you keep using weapons, while getting a taste
+of the various magic schools. You have even fewer hitpoints, though, so beware.
+
+Try another mage. A Hobbit Sorceror is a fun character, but the hitpoint
+penalties make you need to be very careful. You get high-powered magic, though,
+to more than make up for it.
+
+I would just add that for those who get frustrated in the early levels and want
+to run a more powerful character that I think the three easiest combinations
+are probably the Zombie Rohan Knight Unbeliever, the Thunderlord (or Vampire
+Half-Ogre) Sorceror, and the High-Elf (or Deathmold if you can figure it out)
+Possessor. Also, you might want to try a priest of Eru or Tulkas. Most of these
+have low stealth, but should be pretty easy to play up to around level 30, and
+they offer an attractive range of experiences for the new player.
+~~~~~35|I STILL keep dying!
+#####G------------------------------------------------------------------------------
+#####GQ: I'm getting killed a lot. Can you recommend some starting options to
+#####G make my chances a little better?
+
+A: Realize that getting killed a lot is to be expected. Having said that, try
+this. At character creation:
+ 1. Turn off "always generate very unusual rooms".
+ 2. Turn off joke monsters.
+ 3. Turn off "always make small levels".
+ 4. Regarding the number of random quests: See the Q/A below.
+ 5. Do not choose a Lost Soul character.
+
+Later, set these options:
+ 1. Turn on "expand the power of the look command".
+ 2. Turn on "allow some monsters to carry light".
+ 3. Turn on "map remembers all perma-lit grids".
+ 4. Turn on "map remembers all torch-lit grids".
+ 5. Turn off "monsters learn from their mistakes".
+ 6. Turn off "monsters exploit player weaknesses".
+ 7. Turn on "monsters behave stupidly".
+ 8. Turn off "allow unusually small dungeon levels".
+ 9. Turn off "allow empty 'arena' levels".
+
+~~~~~36|Random quests strategy
+#####G------------------------------------------------------------------------------
+#####GQ: How many random quests should I choose?
+
+A: One big question a beginner is faced with is: How many (random) optional
+quests to choose?
+
+I think this is another area where the beginner should mix it up. The early
+items from princesses are a great benefit to beginners, but coming to rely on
+those can be a problem when it comes time to enter deep dungeons and the real
+nasty quests begin.
+
+Also high counts, especially 98 quests, can be very frustrating for a beginner
+when it puts an especially difficult quest on dungeon level 1 or 2.
+
+~~~~~37|Anti-magic Amulets and the Anti-magic shell
+#####G------------------------------------------------------------------------------
+#####GQ: Are Amulets of Anti-magic and the Anti-magic skill related?
+
+A: No. The Anti-magic shell of the Amulet of Anti-magic has nothing to do with
+the Anti-magic field given off by the skill and Dark Swords.
+
+~~~~~38|Beornings and Bearform-combat
+#####G------------------------------------------------------------------------------
+#####GQ: My Beorning character doesn't have Bearform-combat! Why?
+
+A: You cannot put points into Bearform-combat unless you are transformed
+into a bear. Use the racial power ('U' in the original keyset, 'O' in
+roguelike) to transform first.
+
+#####G------------------------------------------------------------------------------
+#####GQ: The game is so slow...
+
+A: Yeah :(
+Try disabling the various options marked as (slow)
diff --git a/lib/help/version.txt b/lib/help/version.txt
new file mode 100644
index 00000000..501be7f6
--- /dev/null
+++ b/lib/help/version.txt
@@ -0,0 +1,354 @@
+|||||oy
+~~~~~01|Development history
+*****version.txt*01[The origins of ToME]
+*****version.txt*02[Zangband History and Information]
+*****version.txt*03[Brief Version History (of standard Angband)]
+*****version.txt*04[A Posting from the Original Author (of Moria)]
+*****version.txt*05[Previous Versions (outdated)]
+
+
+#####R====== ToME Brief History =======
+
+When Zangband came to its 2.2.0 version I (DarkGod) was an Angband winner and
+I had been a C programmer for a long time, so I decided to take the sources
+and to try to code my own variant. At this time I was reading the Pern
+novels from Anne McCaffrey and I found them *VERY* good, so I decided to
+include some elements of them into my variant from which it takes the name,
+PernAngband.
+
+One hard thing to decide was on which Angband to base it. Although I didn't
+like Zangband because of the Zelazny universe, which I found to be not very
+Tolkienish, I chose it because of all the good things it had (especially
+the race powers that I wasn't able to code at the time). So I removed
+much of the Zelazny stuff and replaced it with Tolkien and Pernish stuff.
+And so the history of PernAngband began with the version 2.9.9a.
+
+Now, in PernAngband 5.x.x, PernAngband is a thriving Angband variant
+with plenty of unique features.
+
+Then came some legal problems with Anne McCaffrey estate and ubisoft and
+I had to remove the Pern stuff, so the game got renamed to ToME,
+the Troubles of Middle Earth.
+~~~~~02
+#####R=== Zangband History and Information ===
+
+The seeds of Zangband lie in an obsolete and long ago vanished PC variant
+(somewhat misleadingly) dubbed Angband--. The variant was written by a
+hopeless Angband addict (previously Moria veteran and winner) who got
+bored with the standard monsters and wanted to introduce some new
+monsters. Angband-- was based on the PC Angband 1.31 sources, and
+it was set in Roger Zelazny's 'Amber' universe.
+
+Later this individual got a better computer and learned to code, and
+produced the PC Zangband, and most Angband-- monsters survived into
+PC Zangband 1.0. PC Zangband 1.0 was the first PC Angband to introduce
+(simple, font-based) graphics, which were also used in the graphical
+PC Angband 1.40.
+
+Yet this individual was still not cured of his addiction... his almost
+as strong addiction to the Civilization style fantasy strategy game
+'Master of Magic' inspired him to write a new magic system. The current
+version of Zangband (2.*) incorporates this magic system, as well as
+the best features from Angband-- and PC Zangband 1.0. It is based on
+the Angband 2.8.1 sources (by Ben Harrison), and is therefore portable
+to other systems (unlike the earlier versions which were for DOS-PC's
+only).
+
+Incidentally, this person (me, Topi Ylinen) also thought that the
+standard Angband monsters were too easy, which led him to introduce
+such monsters as Death swords, Cyberdemons and Great Wyrms of Power...
+
+Special thanks -- The current version of Zangband might not have come into
+existence without the significant help from these excellent Angband
+programmers:
+
+ Ben Harrison, for obvious reasons.
+
+ Greg Wooledge, who pointed out a bug in the dos compiler,
+ which was preventing my progress with the first 2.* version
+ of Zangband and for various patches.
+
+ Julian Lighton, who must have sent me more ideas, patches, and
+ bug reports than all the others together.
+
+ Robert Ruehlmann, whose nice new main-dos.c enables SVGA
+ graphics and even windows in MS-DOS.
+
+ Paul Sexton, who is responsible for about 50% of the new code
+ in 2.1.0.
+
+ Heino Vander Sanden, who created the quest-code and
+ Dean Anderson, whose patch showed me the quickest way to
+ implement the quests.
+
+ Adam Bolt, who created the new ZAngband tiles.
+
+ Scott Bigham, for the S-Lang patch.
+
+ Jeff Duprey for the new mutations.
+
+ Leigh Silas Hanrihan for the new items.
+
+ Benny S. Hofmann, Aram Harrow, Greg Harvey, Keldon Jones,
+ Graham Murray, Remco Gerlich, Tim Baker and many others
+ for bugreports, patches, bugfixes, and ideas.
+
+
+ZAngband 2.1.0c was Topi's last version, he has got a job and
+doesn't have enough time anymore to continue work on ZAngband.
+He asked for a new maintainer and I was the one to take over the task.
+May I introduce myself, my name is Robert Ruehlmann, I'm the creator
+of the graphical Angband versions for DOS and webmaster of
+"Thangorodrim - The Angband Page" ("http://www.thangorodrim.net").
+~~~~~03
+#####R=== Brief Version History (of standard Angband) ===
+
+First came "VMS Moria", by Robert Alan Koeneke (1985).
+
+Then came "Umoria" (Unix Moria), by James E. Wilson (1989).
+
+In 1990, Alex Cutler and Andy Astrand, with the help of other students
+at the University of Warwick, created Angband 1.0, based on the existing
+code for Umoria 5.2.1. They wanted to expand the game, keeping or even
+strengthening the grounding in Tolkien lore, while adding more monsters
+and items, including unique monsters and artifact items, plus activation,
+pseudo-sensing, level feelings, and special dungeon rooms.
+
+Over time, Sean Marsh, Geoff Hill, Charles Teague, and others, worked on
+the source, releasing a copy known as "Angband 2.4.frog_knows" at some
+point, which ran only on Unix systems, but which was ported by various
+people to various other systems.
+
+Then Charles Swiger (cs4w+@andrew.cmu.edu) attempted to clean up the mess,
+resulting in several versions, starting sometime around November, 1993, with
+Angband 2.5.1 (more or less) and leading up to Angband 2.6.2 in late 1994.
+Several people ported (the primarily Unix/NeXT centered) Angband 2.6.1 to
+other platforms, including Keith Randall, who made a Macintosh port that
+added support for color usage. Some of the changes during this period were
+based on suggestions from the "net", PC Angband 1.40, UMoria 5.5, and some
+of the Angband "variations", such as FAngband.
+
+Finally, I (Ben Harrison) took over in late 1994 when Charles Swiger left.
+Initially my intention was simply to clean up what had become, after ten
+years, a rather unholy mess, but the deeper I delved into the code, the
+more it became apparent that drastic changes were needed, so, starting
+with MacAngband 2.6.1, I began a more or less total rewrite, resulting,
+eventually, in Angband 2.7.0, released around January first, 1995.
+
+Angband 2.7.0 was a very clean (but very buggy) rewrite that, among other
+things, allowed extremely simple porting to multiple platforms, starting
+with Unix and Macintosh, and by the time most of the bugs were cleaned up,
+in Angband 2.7.2, including X11, and various IBM machines. Angband 2.7.4
+was released to the "ftp.cis.ksu.edu" site, and quickly gained acceptance,
+perhaps helped by the OS2 and Windows and Amiga and Linux ports. Angband
+2.7.5 and 2.7.6 added important capabilities such as macros and user pref
+files, and continued to clean up the source. Angband 2.7.8 was designed
+to supply another "stable" version that we can all give to our friends,
+with new "help files" and "spoiler files" for the "online help", plus a
+variety of minor tweaks and some new features. Angband 2.7.9 optimized
+a few things, and tweaked a few other things, and cleaned up a few other
+things, and introduced a few minor semantic changes.
+
+It is very hard to pin down, along the way from 2.6.2 to 2.7.0, and thence
+to 2.7.8, exactly what was added exactly when. Most of these steps involved
+so many changes as to make "diff files" not very useful, since often the diff
+files were as long as the code itself. Most of the changes, with the notable
+exception of the creation of the new "main-xxx.c" files for the various new
+platforms, and a few other exceptions generally noted in the source, were
+written by myself, either spontaneously, or, more commonly, as the result of
+a suggestion or comment by an Angband player. So if you have any problems
+with anything that you do not recognize from older versions, you can blame
+them on me. And if you like the new features and such, you can send me a
+brief little "thank you" email (to benh@phial.com) or something...
+
+The Official Angband Home Page ("http://www.phial.com/")
+was created along with Angband 2.7.9 to serve as an up to date description
+of any bugs found in various versions, and to list all of the people whose
+email addresses I kept having to look up.
+
+~~~~~04
+#####R=== A Posting from the Original Author ===
+
+From: koeneke@ionet.net (Robert Alan Koeneke)
+Newsgroups: rec.games.roguelike.angband,rec.games.roguelike.moria
+Subject: Early history of Moria
+Date: Wed, 21 Feb 1996 04:20:51 GMT
+
+I had some email show up asking about the origin of Moria, and its
+relation to Rogue. So I thought I would just post some text on the
+early days of Moria.
+
+First of all, yes, I really am the Robert Koeneke who wrote the first
+Moria. I had a lot of mail accussing me of pulling their leg and
+such. I just recently connected to Internet (yes, I work for a
+company in the dark ages where Internet is concerned) and
+was real surprised to find Moria in the news groups... Angband was an
+even bigger surprise, since I have never seen it. I probably spoke to
+its originator though... I have given permission to lots of people
+through the years to enhance, modify, or whatever as long as they
+freely distributed the results. I have always been a proponent of
+sharing games, not selling them.
+
+Anyway...
+
+Around 1980 or 81 I was enrolled in engineering courses at the
+University of Oklahoma. The engineering lab ran on a PDP 1170 under
+an early version of UNIX. I was always good at computers, so it was
+natural for me to get to know the system administrators. They invited
+me one night to stay and play some games, an early startrek game, The
+Colossal Cave Adventure (later just 'Adventure'), and late one night,
+a new dungeon game called 'Rogue'.
+
+So yes, I was exposed to Rogue before Moria was even a gleam in my
+eye. In fact, Rogue was directly responsible for millions of hours of
+play time wasted on Moria and its descendents...
+
+Soon after playing Rogue (and man, was I HOOKED), I got a job in a
+different department as a student assistant in computers. I worked on
+one of the early VAX 11/780's running VMS, and no games were available
+for it at that time. The engineering lab got a real geek of an
+administrator who thought the only purpose of a computer was WORK!
+Imagine... Soooo, no more games, and no more rogue!
+
+This was intolerable! So I decided to write my own rogue game, Moria
+Beta 1.0. I had three languages available on my VMS system. Fortran
+IV, PASCAL V1.?, and BASIC. Since most of the game was string
+manipulation, I wrote the first attempt at Moria in VMS BASIC, and it
+looked a LOT like Rogue, at least what I could remember of it. Then I
+began getting ideas of how to improve it, how it should work
+differently, and I pretty much didn't touch it for about a year.
+
+Around 1983, two things happened that caused Moria to be born in its
+recognizable form. I was engaged to be married, and the only cure for
+THAT is to work so hard you can't think about it; and I was enrolled
+for fall to take an operating systems class in PASCAL.
+
+So, I investigated the new version of VMS PASCAL and found out it had
+a new feature. Variable length strings! Wow...
+
+That summer I finished Moria 1.0 in VMS PASCAL. I learned more about
+data structures, optimization, and just plain programming that summer
+then in all of my years in school. I soon drew a crowd of devoted
+Moria players... All at OU.
+
+I asked Jimmey Todd, a good friend of mine, to write a better
+character generator for the game, and so the skills and history were
+born. Jimmey helped out on many of the functions in the game as well.
+This would have been about Moria 2.0
+
+In the following two years, I listened a lot to my players and kept
+making enhancements to the game to fix problems, to challenge them,
+and to keep them going. If anyone managed to win, I immediately found
+out how, and 'enhanced' the game to make it harder. I once vowed it
+was 'unbeatable', and a week later a friend of mine beat it! His
+character, 'Iggy', was placed into the game as 'The Evil Iggy', and
+immortalized... And of course, I went in and plugged up the trick he
+used to win...
+
+Around 1985 I started sending out source to other universities. Just
+before a OU / Texas football clash, I was asked to send a copy to the
+Univeristy of Texas... I couldn't resist... I modified it so that
+the begger on the town level was 'An OU football fan' and they moved
+at maximum rate. They also multiplied at maximum rate... So the
+first step you took and woke one up, it crossed the floor increasing
+to hundreds of them and pounded you into oblivion... I soon received
+a call and provided instructions on how to 'de-enhance' the game!
+
+Around 1986 - 87 I released Moria 4.7, my last official release. I
+was working on a Moria 5.0 when I left OU to go to work for American
+Airlines (and yes, I still work there). Moria 5.0 was a complete
+rewrite, and contained many neat enhancements, features, you name it.
+It had water, streams, lakes, pools, with water monsters. It had
+'mysterious orbs' which could be carried like torches for light but
+also gave off magical aura's (like protection from fire, or aggrivate
+monster...). It had new weapons and treasures... I left it with the
+student assistants at OU to be finished, but I guess it soon died on
+the vine. As far as I know, that source was lost...
+
+I gave permission to anyone who asked to work on the game. Several
+people asked if they could convert it to 'C', and I said fine as long
+as a complete credit history was maintained, and that it could NEVER
+be sold, only given. So I guess one or more of them succeeded in
+their efforts to rewrite it in 'C'.
+
+I have since received thousands of letters from all over the world
+from players telling about their exploits, and from administrators
+cursing the day I was born... I received mail from behind the iron
+curtain (while it was still standing) talking about the game on VAX's
+(which supposedly couldn't be there due to export laws). I used to
+have a map with pins for every letter I received, but I gave up on
+that!
+
+I am very happy to learn my creation keeps on going... I plan to
+download it and Angband and play them... Maybe something has been
+added that will surprise me! That would be nice... I never got to
+play Moria and be surprised...
+
+Robert Alan Koeneke
+koeneke@ionet.net
+
+~~~~~05
+#####R=== Previous Versions (outdated) ===
+
+
+ VMS Moria Version 4.8
+Version 0.1 : 03/25/83
+Version 1.0 : 05/01/84
+Version 2.0 : 07/10/84
+Version 3.0 : 11/20/84
+Version 4.0 : 01/20/85
+
+Modules :
+ V1.0 Dungeon Generator - RAK
+ Character Generator - RAK & JWT
+ Moria Module - RAK
+ Miscellaneous - RAK & JWT
+ V2.0 Town Level & Misc - RAK
+ V3.0 Internal Help & Misc - RAK
+ V4.0 Source Release Version - RAK
+
+Robert Alan Koeneke Jimmey Wayne Todd Jr.
+Student/University of Oklahoma Student/University of Oklahoma
+
+
+ Umoria Version 5.2 (formerly UNIX Moria)
+Version 4.83 : 5/14/87
+Version 4.85 : 10/26/87
+Version 4.87 : 5/27/88
+Version 5.0 : 11/2/89
+Version 5.2 : 5/9/90
+
+James E. Wilson, U.C. Berkeley
+ wilson@ernie.Berkeley.EDU
+ ...!ucbvax!ucbernie!wilson
+
+Other contributors:
+D. G. Kneller - MS-DOS Moria port
+Christopher J. Stuart - recall, options, inventory, and running code
+Curtis McCauley - Macintosh Moria port
+Stephen A. Jacobs - Atari ST Moria port
+William Setzer - object naming code
+David J. Grabiner - numerous bug reports, and consistency checking
+Dan Bernstein - UNIX hangup signal fix, many bug fixes
+and many others...
+
+
+
+
+Copyright (c) 1989 James E. Wilson, Robert A. Keoneke
+ This software may be copied and distributed for educational, research, and
+ not for profit purposes provided that this copyright and statement are
+ included in all such copies.
+
+Umoria Version 5.2, patch level 1
+
+Angband Version 2.0 Alex Cutler, Andy Astrand, Sean Marsh, Geoff Hill,
+ Charles Teague.
+
+Angband Version 2.4 : 5/09/93
+
+Angband Version 2.5 : 12/05/93 Charles Swiger.
+
+Angband Version 2.6 : 9/04/94
+
+Angband Version 2.7 : 1/1/95 Ben Harrison
diff --git a/lib/help/whattome.txt b/lib/help/whattome.txt
new file mode 100644
index 00000000..43ebb2e1
--- /dev/null
+++ b/lib/help/whattome.txt
@@ -0,0 +1,30 @@
+|||||oy
+~~~~~01|ToME - a General Description
+#####R /----------------------------------------\
+#####R < What is ToME? >
+#####R \----------------------------------------/
+
+Tales of Middle Earth (ToME) is a fantasy adventure game, based on the works
+of Tolkien. Focusing on game-play rather than fancy graphics that get boring
+after a week, ToME will keep you playing for years.
+
+Explore dozens of different dungeons including hundreds of randomly generated
+levels filled with multitudes of different items and treasures. Fight off
+hundreds of monsters and uniques from the stories in a complex fighting system.
+Gain experience and learn skills; choose from the dozens of races and classes
+available to the player; cast spells from simple teleportation spells to
+advanced spells that can wipe out a whole army at once. It's the only game where
+you can burn spell books by trudging in lava (unless you have gained immunity
+from some armour), dry up rivers to cast mighty spells, strike at orcs with
+blades attuned to slay them specifically, summon armies from a simple totem,
+and even enter a symbiotic relationship with a mold!
+
+Explore dungeons, gain power, and save Middle-earth!
+
+The player will begin his adventure on the town level where he may acquire
+supplies, weapons, armour, and magical devices by bartering with various shop
+owners. After preparing for his adventure, the player can descend into the
+dungeon near Bree where fantastic adventures await his coming!
+
+Make sure you read the parchment you are given when you start the game, and
+read the in-game documentation.
diff --git a/lib/help/wishing.txt b/lib/help/wishing.txt
new file mode 100644
index 00000000..d16f5ae9
--- /dev/null
+++ b/lib/help/wishing.txt
@@ -0,0 +1,24 @@
+~~~~~01|Spoilers|Wishing
+#####R=== Wishes ===
+
+Some items in ToME will grant the user the ability to "wish" for an
+object that they are interested in. As such, these are generally very rare
+and very powerful objects.
+
+#####GRules for Wishes
+Due to the powerful nature of wishes, there are some rules that govern
+what is able to be wished for. These rules are as follows:
+1. You cannot wish for a wish, or any other item which would grant more
+ wishes.
+2. A wish will always generate *one* object. So, never put a number, "a"
+ or "an" in front of the object you are wishing for.
+3. It is not possible to wish for the magical +'s to the object (i.e. you
+ cannot wish for "gloves of slaying (+10,+10)", but you can wish for
+ "gloves of slaying").
+4. You cannot wish for artifacts, but you *can* wish for excellent (ego)
+ items.
+5. You can wish for monsters and ego monsters (e.g. "cave orc", "rogue cave
+ orc").
+6. You cannot wish for unique monsters.
+7. You can wish the monster to have a specific flag - a pet, or a foe.
+ Possible flags include: enemy, neutral, friendly, pet, companion.
diff --git a/lib/info/delete.me b/lib/info/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/info/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/mods/.cvsignore b/lib/mods/.cvsignore
new file mode 100644
index 00000000..61a33fff
--- /dev/null
+++ b/lib/mods/.cvsignore
@@ -0,0 +1 @@
+tomk
diff --git a/lib/mods/mods_aux.lua b/lib/mods/mods_aux.lua
new file mode 100644
index 00000000..1562a566
--- /dev/null
+++ b/lib/mods/mods_aux.lua
@@ -0,0 +1,185 @@
+-- Ok some functions that we dont need are dangerous
+--[[
+execute = nil
+getenv = nil
+setlocale = nil
+exit = nil
+openfile = nil
+writeto = nil
+readfrom = nil
+appendto = nil
+remove = nil
+rename = nil
+tmpname = nil
+]]
+modules = {}
+
+current_module = nil
+
+function setup_module(mod)
+ -- For standart game, nothing needs to be done
+ if not mod.layout then return end
+
+ for k, e in mod.layout do
+ module_reset_dir(k, e)
+ end
+end
+
+function init_module(i)
+ setup_module(get_module(i))
+end
+
+function max_modules()
+ local i = 0
+ for k, e in modules do
+ if type(k) == "number" and type(e) == "table" then
+ i = i + 1
+ end
+ end
+ return i
+end
+
+function get_module_name(j)
+ local i = 0
+ for k, e in modules do
+ if type(k) == "number" and type(e) == "table" then
+ if i == j then return e.name end
+ i = i + 1
+ end
+ end
+end
+
+function get_module_desc(j)
+ local i = 0
+ for k, e in modules do
+ if type(k) == "number" and type(e) == "table" then
+ if i == j then return e.desc end
+ i = i + 1
+ end
+ end
+end
+
+function get_module(j)
+ local i = 0
+ for k, e in modules do
+ if type(k) == "number" and type(e) == "table" then
+ if i == j then return e end
+ i = i + 1
+ end
+ end
+end
+
+function find_module(name)
+ local i = 0
+ for k, e in modules do
+ if type(k) == "number" and type(e) == "table" then
+ if name == e.name then return i end
+ i = i + 1
+ end
+ end
+end
+
+function assign_current_module(name)
+ current_module = get_module(find_module(name))
+end
+
+function get_module_info(type, subtype)
+ if subtype then
+ return current_module[type][subtype]
+ else
+ return current_module[type]
+ end
+end
+
+function exec_module_info(type, ...)
+ return call(current_module[type], arg)
+end
+
+function module_savefile_loadable(savefile_mod, savefile_death)
+ for _, e in current_module.mod_savefiles do
+ if e[1] == savefile_mod then
+ if e[2] == "all" then
+ return TRUE
+ elseif e[2] == "alive" and savefile_death == FALSE then
+ return TRUE
+ elseif e[2] == "dead" and savefile_death == TRUE then
+ return TRUE
+ end
+ end
+ end
+ return FALSE
+end
+
+function scan_extra_modules()
+ scansubdir(ANGBAND_DIR_MODULES)
+ for i = 0, scansubdir_max - 1 do
+ if (scansubdir_result[i + 1] ~= ".") and (scansubdir_result[i + 1] ~= "..") then
+ local dir = path_build(ANGBAND_DIR_MODULES, scansubdir_result[i + 1])
+ local file = path_build(dir, "module.lua")
+ if file_exist(file) == TRUE then
+ tome_dofile_anywhere(dir, "module.lua")
+ end
+ end
+ end
+end
+
+function add_module(t)
+ assert(t.name, "No module name")
+ assert(type(t.version) == "table", "No module version")
+ assert(t.desc, "No module desc")
+ assert(t.author, "No module author")
+ assert(t.mod_savefiles, "No loadable savefiles module mark")
+
+ for _, e in modules do
+ if type(e) == "table" and e.name == t.name then
+ error("Module name already defined: "..t.name)
+ end
+ end
+
+ if type(t.author) == "string" then
+ t.author = { t.author, "unknown@unknown.net" }
+ end
+
+ for k, e in t.mod_savefiles do
+ if type(e) == "string" then t.mod_savefiles[k] = { e, "all" } end
+ end
+
+ if type(t.desc) == "table" then
+ local d = ""
+ for k, e in t.desc do
+ d = d .. e
+ if k < getn(t.desc) then
+ d = d .. "\n"
+ end
+ end
+ t.desc = d
+ end
+
+ if not t.rand_quest then t.rand_quest = FALSE end
+ if not t.C_quest then t.C_quest = FALSE end
+
+ if not t.base_dungeon then t.base_dungeon = 4 end
+ if not t.death_dungeon then t.death_dungeon = 28 end
+
+ if not t.astral_dungeon then t.astral_dungeon = 8 end
+ if not t.astral_wild_x then t.astral_wild_x = 45 end
+ if not t.astral_wild_y then t.astral_wild_y = 19 end
+
+ if not t.random_artifact_weapon_chance then
+ t.random_artifact_weapon_chance = 30
+ end
+ if not t.random_artifact_armor_chance then
+ t.random_artifact_armor_chance = 20
+ end
+ if not t.random_artifact_jewelry_chance then
+ t.random_artifact_jewelry_chance = 20
+ end
+
+ if not t.max_plev then t.max_plev = 50 end
+ if not t.max_skill_overage then t.max_skill_overage = 4 end
+ if not t.skill_per_level then t.skill_per_level = function() return 6 end end
+
+ if not t.allow_birth then t.allow_birth = TRUE end
+
+ tinsert(modules, t)
+end
diff --git a/lib/mods/modules.lua b/lib/mods/modules.lua
new file mode 100644
index 00000000..5deddef7
--- /dev/null
+++ b/lib/mods/modules.lua
@@ -0,0 +1,5 @@
+-- Load ToME
+tome_dofile_anywhere(ANGBAND_DIR, "module.lua")
+
+-- Look for more modules
+scan_extra_modules()
diff --git a/lib/mods/theme/apex/delete.me b/lib/mods/theme/apex/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/mods/theme/apex/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/mods/theme/changelog.txt b/lib/mods/theme/changelog.txt
new file mode 100644
index 00000000..3cb3cb45
--- /dev/null
+++ b/lib/mods/theme/changelog.txt
@@ -0,0 +1,73 @@
+=== RECENT VERSION HISTORY (1.1.5 to 1.2.0) ===
+
+1.1.5 AKA "Angles and Corners"
+- Dropped the NOTICE flag from regular sandwalls.
+- Flight is now possible over wooden wilderness structures.
+- The Anduin River lost the CAN_RUN and DONT_NOTICE_RUNNING flags.
+- The Orc Cave now leads you out to the other side of the Misty Mountains.
+- Put an Eagles' nest into Khazad-Dum.
+
+- The Map of Thror no longer lives in the Bree town quest. It is now on a special (branch) level of the Barrow-Downs.
+- The Key of Thorin no longer lives in the Minas Anor town quest. It is now on a special (branch) level of Mirkwood.
+- Reworked the Bridge of Khazad-Dum level to be more nasty and random, played with the layout a bit.
+- Added new level "Orthanc" in the Isengard dungeon, based heavily on the one created by Burb Lulls. There is, however, a canonical twist (or two). >:)
+
+1.1.6 AKA "Curses to This Mirage"
+- Druids (r_info) lost the EVIL flag. These are supposed to be Yavanna's people and they're certainly not evil. The dark elven druids are stil evil.
+- All neutral monsters defined in r_info have been forced into the wilderness.
+- The coaligned spirits now have the GOOD flag. This is mostly to clean up the Mandos piety code (later).
+
+- Fixed the automatic stat gain script to forget stat gain on death, so the savefile can be reused and monster memory retained.
+- Drastically reduced piety gain for quaffing pots of corruption. It's meant to be a fun thematic addition, not a scumming tactic.
+- Aewroeg, Narroeg and Wainriders now start with their stated spellbooks
+
+1.1.7 AKA "Poor Madeleine"
+- Rings and amulets no longer ignore the elements. The rationale for this was that Middle-earth magical items are *really* magical and therefore powerful, but it was unbalancing, not to mention made it a pain destroying objects in the late game.
+- Rings of Lordly Protection have been renamed to 'of Arnor'
+- Pushed Potions of Corruption deeper into the dungeon.
+- Changed names on Aule's and Ulmo's spellbooks to be more impressive-sounding
+- Removed the miscellaneous food items, except for Longbottom leaf, milk and honey.
+- New item types: Ranger's Arrow, Throwing Axe, Buckler, Small Mithril Boomerang, Mithril Boomerang (the latter three adapted from FuryMod)
+
+1.1.8 AKA "Little White Candle"
+- Weapons of Unmagic now have negative to-hit and to-dam modifiers; demonology equipment can no longer get this ego type.
+- Reworked the T-Plus "Rogue" ego type for boots to balance it: reduced the pval, added to_h and to_d penalties and made the stealth and luck bonuses rarer.
+- Boots of Elvenkind no longer guarantee a speed bonus; chance is 50%.
+- Pushed 'of the Maiar' items deeper into the dungeon.
+- Filthy Rags of Leprousness are no more; they're replaced by Armour of Dunharrow (same effects, but can show up on all soft & hard armour plus cloaks)
+- A number of the "bad" ego types got the aggravation flag to offset the benefits of flip-scumming.
+- Drastically reduced magic breath chances on Ethereal robes and cloaks.
+- The 'of Lordliness' ego type is now 'of Arnor'; 'of Might' is now 'of Gondor'; 'of Nothingness' is now 'of Angmar'; boots of speed are now 'of Rohan' and all 'of Stealth' is now 'of Eriador'. Because of the hobbit connection, the 'of Eriador' items now have a 10% chance of a luck bonus equal to the stealth bonus (which remains at 100%).
+- The 'of Arnor' and 'of Gondor' ego types can now show up on all headgear, not just crowns.
+- The 'Sharp' ego has been extended to arrows and crossbow bolts (I added a new index and called them 'Sharpened' to make sure the additional cost is not exorbitant).
+- The 'of Sensitivity' ego type is no longer possible on body armour; there were too many T-lines in e_info.txt.
+- The 'Elemental' ego type on rings is only possible on high-level rings and amulets now; same reason as above.
+- The 'Blazing' ego type is now only possible on crowns, high-level rings and amulets; same reason as above.
+- The 'Radiant' ego type is now only possible on crowns, high-level rings and all amulets (as before); same reason as above.
+- The 'Glowing' and 'Dazzling' ego types are now only possible on crowns and low-level rings and amulets; same reason as above.
+- Rings of the Elements have been removed; one Elemental ego for jewelry is enough.
+- New ego types: Magical for jewelry, cloaks, soft armour and gloves -- makes the item ignore the elements and gives a 50% chance of the ability to store a spell. Magical for missile launchers -- adds a tiny boost to mana; designed with magic-using archer and warrior-types in mind.
+
+1.1.9 AKA "Kit Bag Full of Marbles"
+- Randart magestaves can now gain % to life
+- Randart armour, lights, jewelry and magestaves can now get the ability to store a spell
+- Randart high-level soft armour, hard armour and DSM can gain nether immunity
+- Randart light weapons (no broken ones) can gain sentience
+
+- Humans may no longer be Lost Souls for thematic reasons; the Doom of Men is that their fate after death is unknown to anyone except Eru. This applies to: Edain, Druedain, Rohirrim, Dunedain, Easterlings and Beornings. Also no longer allowed as LostSouls are yeeks, orcs, trolls and half-ogres.
+- Flying creatures (Eagles, Dragons, Aewroeg) now learn to fly high enough to pass mountains at clvl50.
+
+- FF now may also offer the following skills: Nature, Runecraft, Boulder-throwing.
+
+1.2.0 AKA "Twining Light"
+- Ultimate amulet no longer weighs 60lbs. >.>
+- Reworked the Paur* artifact gauntlets to be more thematic, added stat bonuses and sustains. I never liked the fact that it was a no-brainer which of them to keep if you had all four.
+- Fixed some rarity bugs with a number of Theme artifacts.
+- Removed the lesser (Dwarven) rings of power (except the Ring of Durin). They were taking up artifact space and didn't do much. They'll be back, tweaked, in a 3.0.0-compatible Theme.
+- Fixed some lurking bugs in in set_info
+- Reduced rarity on the Cloak of Valinor. It was a little incongruous that it cost far less than Ancanaur and was far more rare than is decent.
+- Gandalf's robe now gives fire immunity
+- Ancanaur is now a shadow blade, not a bluesteel blade.
+- The Golden Horn of the Thunderlords now ignores elements.
+- New artifacts: Erkenbrand's shield, Gimli's axe and shield.
+- New item set: Gimli's Gear (boots, axe, shield) \ No newline at end of file
diff --git a/lib/mods/theme/core/auto.lua b/lib/mods/theme/core/auto.lua
new file mode 100644
index 00000000..b758db52
--- /dev/null
+++ b/lib/mods/theme/core/auto.lua
@@ -0,0 +1,859 @@
+-- This file is the core of the Automatizer
+-- Please do not touch unless you know what you are doing
+
+__rules = {}
+__rules_max = 0
+
+rule_aux = {}
+
+-- Rule apply function, does .. nothing
+function auto_nothing(obj, item)
+ return
+end
+
+function auto_inscribe(obj, item, note)
+ if obj.note ~= 0 then return end
+ msg_print("<Auto-Inscribe {"..note.."}>")
+ obj.note = quark_add(note)
+ return TRUE
+end
+
+-- Rule apply function, pickup object
+function auto_pickup(obj, item)
+ if item >= 0 then return end
+ if inven_carry_okay(obj) == FALSE then return end
+ msg_print("<Auto-pickup>")
+ object_pickup(-item)
+ return TRUE
+end
+
+-- Rule apply function, destroy item
+function auto_destroy(obj, item)
+ -- be carefull to what we can destroy
+ -- Unaware things won't be destroyed.
+ if is_aware(obj) == FALSE then return end
+
+ -- Inscribed things won't be destroyed!
+ if obj.note ~= 0 then return end
+
+ -- Keep Artifacts -- they cannot be destroyed anyway
+ if is_artifact(obj) == TRUE then return end
+
+ -- Cannot destroy CURSE_NO_DROP objects
+ local f1, f2, f3, f4, f5, esp = object_flags(obj);
+ if band(f4, TR4_CURSE_NO_DROP) ~= 0 and band(obj.ident, IDENT_CURSED) then return end
+
+ msg_print("<Auto-destroy>")
+
+ -- Eliminate the item (from the pack)
+ if item >= 0 then
+ inven_item_increase(item, -obj.number)
+ inven_item_describe(item)
+ inven_item_optimize(item)
+ -- Eliminate the item (from the floor)
+ else
+ floor_item_increase(0 - item, -obj.number)
+ floor_item_describe(0 - item)
+ floor_item_optimize(0 - item)
+ end
+ return TRUE
+end
+
+-- Report the status of an object
+function object_status(obj)
+ local sense =
+ {
+ [SENSE_CURSED] = "bad",
+ [SENSE_WORTHLESS] = "very bad",
+ [SENSE_AVERAGE] = "average",
+ [SENSE_GOOD_LIGHT] = "good",
+ [SENSE_GOOD_HEAVY] = "good",
+ [SENSE_EXCELLENT] = "very good",
+ [SENSE_SPECIAL] = "special",
+ [SENSE_TERRIBLE] = "terrible",
+ }
+
+ if is_known(obj) == FALSE then
+ if sense[obj.sense] then
+ return sense[obj.sense]
+ else
+ return ""
+ end
+ else
+if nil then -- test
+ local osense = -1
+ local type = select_sense(obj, TRUE, TRUE)
+ if type == 1 then
+ osense = value_check_aux1(obj)
+ elseif type == 2 then
+ osense = value_check_aux1_magic(obj)
+ end
+print("type : "..type)
+ if sense[osense] then
+ print("sense: "..sense[osense])
+ return sense[osense]
+ else
+ print("sense: ")
+ return ""
+ end
+
+else -- the real one
+
+ local slot = wield_slot_ideal(obj, TRUE)
+
+ -- Arts items
+ if is_artifact(obj) == TRUE then
+ if band(obj.ident, IDENT_CURSED) == 0 then return "special"
+ else return "terrible" end
+ -- Ego items
+ elseif (obj.name2 > 0 or obj.name2b > 0) then
+ if band(obj.ident, IDENT_CURSED) == 0 then return "very good"
+ else return "very bad" end
+ -- weapon
+ elseif (slot == INVEN_WIELD) or (slot == INVEN_BOW) or (slot == INVEN_AMMO) or (slot == INVEN_TOOL) then
+ if obj.to_h + obj.to_d < 0 then
+ return "bad"
+ elseif obj.to_h + obj.to_d > 0 then
+ return "good"
+ else
+ return "average"
+ end
+ -- armor
+ elseif (slot >= INVEN_BODY) and (slot <= INVEN_FEET) then
+ if obj.to_a < 0 then
+ return "bad"
+ elseif obj.to_a > 0 then
+ return "good"
+ else
+ return "average"
+ end
+ -- ring
+ elseif slot == INVEN_RING then
+ if (obj.to_d + obj.to_h < 0) or (obj.to_a < 0) or (obj.pval < 0) then
+ return "bad"
+ else
+ return "average"
+ end
+ -- amulet
+ elseif slot == INVEN_NECK then
+ if (obj.pval < 0) then
+ return "bad"
+ else
+ return "average"
+ end
+ -- chests
+ elseif obj.tval == TV_CHEST then
+ if obj.pval == 0 then
+ return "empty"
+ elseif obj.pval < 0 then
+ return "disarmed"
+ else
+ return "average"
+ end
+ else
+ return "average"
+ end
+end
+ end
+end
+
+-- Recursive function to generate a rule function tree
+function gen_rule_fct(r)
+ -- It is a test rule (or, and, ...)
+ if r.label == "and" or r.label == "or" then
+ local i
+ local fct_tbl = {}
+ for i = 1, getn(r) do
+ if r[i].label ~= "comment" then
+ tinsert(fct_tbl, gen_rule_fct(r[i]))
+ end
+ end
+ if r.label == "and" then
+ return function(object)
+ local fcts = %fct_tbl
+ local i
+ for i = 1, getn(fcts) do
+ if not fcts[i](object) then return end
+ end
+ return TRUE
+ end
+ elseif r.label == "or" then
+ return function(object)
+ local fcts = %fct_tbl
+ local i
+ for i = 1, getn(fcts) do
+ if fcts[i](object) then return TRUE end
+ end
+ end
+ end
+ -- It is a condition rule (name, type, level, ...)
+ else
+ if r.label == "not" then
+ local f
+ if not r[1] then
+ f = function (object) return TRUE end
+ else
+ f = gen_rule_fct(r[1])
+ end
+ return function(object) return not %f(object) end
+ elseif r.label == "inventory" then
+ local f
+ if not r[1] then
+ f = function(object) return end
+ else
+ f = gen_rule_fct(r[1])
+ end
+ return function(object)
+ local i = 0
+ while i < INVEN_WIELD do
+ if %f(player.inventory(i)) then
+ return TRUE
+ end
+ i = i + 1
+ end
+ end
+ elseif r.label == "equipment" then
+ local f
+ if not r[1] then
+ f = function(object) return end
+ else
+ f = gen_rule_fct(r[1])
+ end
+ return function(object)
+ local i = INVEN_WIELD
+ while i < INVEN_TOTAL do
+ if %f(player.inventory(i)) then
+ return TRUE
+ end
+ i = i + 1
+ end
+ end
+ elseif r.label == "name" then
+ return function(object) if strlower(object_desc(object, -1, 0)) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "contain" then
+ return function(object) if strfind(strlower(object_desc(object, -1, 0)), strlower(%r[1])) then return TRUE end end
+ elseif r.label == "symbol" then
+ return function(object) if strchar(get_kind(object).d_char) == %r[1] then return TRUE end end
+ elseif r.label == "inscribed" then
+ return function(object) if object.note ~= 0 and strfind(strlower(quark_str(object.note)), strlower(%r[1])) then return TRUE end end
+ elseif r.label == "discount" then
+ local d1 = r.args.min
+ local d2 = r.args.max
+ if tonumber(d1) == nil then d1 = getglobal(d1) else d1 = tonumber(d1) end
+ if tonumber(d2) == nil then d2 = getglobal(d2) else d2 = tonumber(d2) end
+ return function(object) if is_aware(object) == TRUE and object.discount >= %d1 and object.discount <= %d2 then return TRUE end end
+ elseif r.label == "tval" then
+ local tv = r[1]
+ if tonumber(tv) == nil then tv = getglobal(tv) else tv = tonumber(tv) end
+ return function(object) if object.tval == %tv then return TRUE end end
+ elseif r.label == "sval" then
+ assert(r.args.min and r.args.max, "sval rule lacks min or max")
+ local sv1 = r.args.min
+ local sv2 = r.args.max
+ if tonumber(sv1) == nil then sv1 = getglobal(sv1) else sv1 = tonumber(sv1) end
+ if tonumber(sv2) == nil then sv2 = getglobal(sv2) else sv2 = tonumber(sv2) end
+ return function(object) if is_aware(object) == TRUE and object.sval >= %sv1 and object.sval <= %sv2 then return TRUE end end
+ elseif r.label == "status" then
+ return function(object) if object_status(object) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "state" then
+ if r[1] == "identified" then
+ return function(object) if is_known(object) == TRUE then return TRUE end end
+ else
+ return function(object) if is_known(object) == FALSE then return TRUE end end
+ end
+ elseif r.label == "race" then
+ return function(object) if strlower(get_race_name()) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "subrace" then
+ return function(object) if strlower(get_subrace_name()) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "class" then
+ return function(object) if strlower(get_class_name()) == strlower(%r[1]) then return TRUE end end
+ elseif r.label == "level" then
+ assert(r.args.min and r.args.max, "level rule lacks min or max")
+ return function(object) if player.lev >= tonumber(%r.args.min) and player.lev <= tonumber(%r.args.max) then return TRUE end end
+ elseif r.label == "skill" then
+ assert(r.args.min and r.args.max, "skill rule lacks min or max")
+ local s = find_skill_i(r[1])
+ assert(s ~= -1, "no skill "..r[1])
+ return function(object) if get_skill(%s) >= tonumber(%r.args.min) and get_skill(%s) <= tonumber(%r.args.max) then return TRUE end end
+ elseif r.label == "ability" then
+ local s = find_ability(r[1])
+ assert(s ~= -1, "no ability "..r[1])
+ return function(object) if has_ability(%s) == TRUE then return TRUE end end
+ end
+ end
+end
+
+function auto_inscribe_maker(inscription)
+ return function(...)
+ arg.n = arg.n + 1
+ arg[getn(arg)] = %inscription
+ return call(auto_inscribe, arg)
+ end
+end
+
+-- Generate a rule from a table
+function gen_full_rule(t)
+ -- only honor rules for this module
+ if not t.args.module then
+ t.args.module = "ToME"
+ end
+
+ if not ((t.args.module == "all") or (t.args.module == game_module)) then
+ return function() end
+ end
+
+ -- Check for which action to do
+ local apply_fct = auto_nothing
+ if t.args.type == "destroy" then apply_fct = auto_destroy
+ elseif t.args.type == "pickup" then apply_fct = auto_pickup
+ elseif t.args.type == "inscribe" then apply_fct = auto_inscribe_maker(t.args.inscription)
+ end
+
+ -- create the function tree
+ local rf
+ if t[1] then
+ rf = gen_rule_fct(t[1])
+ else
+ rf = function (object) end
+ end
+
+ -- create the final function
+ return function(...)
+ local rf = %rf
+ if rf(arg[1]) then
+ if call(%apply_fct, arg) == TRUE then return TRUE end
+ end
+ end
+end
+
+-- Create a function that checks for the rules(passed in xml form)
+function add_ruleset(s)
+ local tbl = xml:collect(s)
+ local i
+
+ -- Add all rules
+ for i = 1, getn(tbl) do
+ local t = tbl[i]
+
+ if t.label == "rule" then
+ -- Create the function tree
+ local fct = gen_full_rule(t)
+
+ -- Create the test function
+ __rules[__rules_max] =
+ {
+ ["table"] = t,
+ ["fct"] = fct
+ }
+ __rules_max = __rules_max + 1
+ end
+ end
+end
+
+-- Apply the current rules to an object
+-- call with at least (object, idx)
+function apply_rules(...)
+ local i
+ for i = 0, __rules_max - 1 do
+ if call(__rules[i].fct, arg) then return TRUE end
+ end
+ return FALSE
+end
+
+-- Clear the current rules
+function clean_ruleset()
+ __rules_max = 0
+ __rules = {}
+end
+
+------ helper fonctions for the GUI
+
+auto_aux = {}
+auto_aux.stack = { n = 0 }
+auto_aux.idx = 1
+auto_aux.rule = 1
+function auto_aux:go_right()
+ if auto_aux.rule[1] and type(auto_aux.rule[1]) == "table" then
+ tinsert(auto_aux.stack, auto_aux.idx)
+ tinsert(auto_aux.stack, auto_aux.rule)
+ auto_aux.rule = auto_aux.rule[1]
+ auto_aux.idx = 1
+ end
+end
+
+function auto_aux:go_left(sel)
+ local n = getn(auto_aux.stack)
+
+ if n > 0 then
+ auto_aux.idx = auto_aux.stack[n - 1]
+ auto_aux.rule = auto_aux.stack[n]
+ tremove(auto_aux.stack)
+ tremove(auto_aux.stack)
+ end
+end
+
+function auto_aux:go_down()
+ if getn(auto_aux.stack) > 1 then
+ if auto_aux.stack[getn(auto_aux.stack)][auto_aux.idx + 1] then
+ auto_aux.idx = auto_aux.idx + 1
+ auto_aux.rule = auto_aux.stack[getn(auto_aux.stack)][auto_aux.idx]
+ end
+ end
+end
+
+function auto_aux:go_up()
+ if getn(auto_aux.stack) > 1 then
+ if auto_aux.stack[getn(auto_aux.stack)][auto_aux.idx - 1] then
+ auto_aux.idx = auto_aux.idx - 1
+ auto_aux.rule = auto_aux.stack[getn(auto_aux.stack)][auto_aux.idx]
+ end
+ end
+end
+
+function auto_aux:scroll_up()
+ xml.write_off_y = xml.write_off_y - 1
+end
+
+function auto_aux:scroll_down()
+ xml.write_off_y = xml.write_off_y + 1
+end
+
+function auto_aux:scroll_left()
+ xml.write_off_x = xml.write_off_x + 1
+end
+
+function auto_aux:scroll_right()
+ xml.write_off_x = xml.write_off_x - 1
+end
+
+function auto_aux:adjust_current(sel)
+ if __rules_max == 0 then return end
+
+ xml.write_off_y = 0
+ xml.write_off_x = 0
+ auto_aux.idx = 1
+ auto_aux.stack = { n = 0 }
+ auto_aux.rule = __rules[sel].table
+end
+
+function auto_aux:move_up(sel)
+ if sel > 0 then
+ local u = __rules[sel - 1]
+ local d = __rules[sel]
+ __rules[sel - 1] = d
+ __rules[sel] = u
+ return sel - 1
+ end
+ return sel
+end
+
+function auto_aux:move_down(sel)
+ if sel < __rules_max - 1 then
+ local u = __rules[sel]
+ local d = __rules[sel + 1]
+ __rules[sel + 1] = u
+ __rules[sel] = d
+ return sel + 1
+ end
+ return sel
+end
+
+function auto_aux:new_rule(sel, nam, typ, arg)
+ local r
+
+
+ -- nam can also directly be the table itself
+ if type(nam) == "table" then
+ r =
+ {
+ ["table"] = nam,
+ ["fct"] = function (object) end
+ }
+ elseif typ == "inscribe" then
+ if arg == "" then
+ arg = input_box("Inscription?", 79)
+ end
+ r =
+ {
+ ["table"] =
+ {
+ label = "rule",
+ args = { name = nam, type = typ, inscription = arg, module = game_module },
+ },
+ ["fct"] = function (object) end
+ }
+ else
+ r =
+ {
+ ["table"] =
+ {
+ label = "rule",
+ args = { name = nam, type = typ, module = game_module },
+ },
+ ["fct"] = function (object) end
+ }
+ end
+ tinsert(__rules, sel, r)
+ __rules_max = __rules_max + 1
+end
+
+function auto_aux:rename_rule(sel, nam)
+ if sel >= 0 and sel < __rules_max then
+ __rules[sel].table.args.name = nam
+ end
+end
+
+function auto_aux:save_ruleset()
+ xml.write = xml.write_file
+
+ print_hook("clean_ruleset()\nadd_ruleset\n[[\n")
+ local i
+ for i = 0, __rules_max - 1 do
+ xml:print_xml(__rules[i].table, '')
+ end
+ print_hook("]]\n")
+
+ xml.write = xml.write_screen
+end
+
+function auto_aux:del_self(sel)
+ if auto_aux.rule.label == "rule" then
+ tremove(__rules, sel)
+ __rules_max = __rules_max - 1
+ return sel - 1
+ else
+ local idx = auto_aux.idx
+ auto_aux:go_left(sel)
+ tremove(auto_aux.rule, idx)
+ return sel
+ end
+end
+
+auto_aux.types_desc =
+{
+ ["and"] =
+ {
+ "Check is true if all rules within it are true",
+ xml:collect([[<and><foo1>...</foo1><foo2>...</foo2><foo3>...</foo3></and>]]),
+ function ()
+ return xml:collect("<and></and>")
+ end,
+ },
+ ["or"] =
+ {
+ "Check is true if at least one rule within it is true",
+ xml:collect([[<or><foo1>...</foo1><foo2>...</foo2><foo3>...</foo3></or>]]),
+ function ()
+ return xml:collect("<or></or>")
+ end,
+ },
+ ["not"] =
+ {
+ "Invert the result of its child rule",
+ xml:collect([[<not><foo1>...</foo1></not>]]),
+ function ()
+ return xml:collect("<not></not>")
+ end,
+ },
+ ["comment"] =
+ {
+ "Comments are meaningless",
+ xml:collect([[<comment>Comment explaining something</comment>]]),
+ function ()
+ local n = input_box("Comment?", 79)
+ if n == "" then return end
+ return xml:collect("<comment>"..n.."</comment>")
+ end,
+ },
+ ["name"] =
+ {
+ "Check is true if object name matches name",
+ xml:collect([[<name>potion of healing</name>]]),
+ function ()
+ local n = input_box("Object name to match?", 79)
+ if n == "" then return end
+ return xml:collect("<name>"..n.."</name>")
+ end,
+ },
+ ["contain"] =
+ {
+ "Check is true if object name contains word",
+ xml:collect([[<contain>healing</contain>]]),
+ function ()
+ local n = input_box("Word to find in object name?", 79)
+ if n == "" then return end
+ return xml:collect("<contain>"..n.."</contain>")
+ end,
+ },
+ ["inscribed"] =
+ {
+ "Check is true if object inscription contains word",
+ xml:collect([[<inscribed>=g</inscribed>]]),
+ function ()
+ local n = input_box("Word to find in object inscription?", 79)
+ if n == "" then return end
+ return xml:collect("<inscribed>"..n.."</inscribed>")
+ end,
+ },
+ ["discount"] =
+ {
+ "Check is true if object discount is between 2 values",
+ xml:collect([[<sval min='50' max='100'></sval>]]),
+ function ()
+ local s = "<discount "
+
+ local n = input_box("Min discount?", 79)
+ if n == "" then return end
+ s = s.."min='"..n.."' "
+
+ n = input_box("Max discount?", 79)
+ if n == "" then return end
+ s = s.."max='"..n.."'></discount>"
+ return xml:collect(s)
+ end,
+ },
+ ["symbol"] =
+ {
+ "Check is true if object symbol is ok",
+ xml:collect([[<symbol>!</symbol>]]),
+ function ()
+ local n = input_box("Symbol to match?", 1)
+ if n == "" then return end
+ return xml:collect("<symbol>"..n.."</symbol>")
+ end,
+ },
+ ["status"] =
+ {
+ "Check is true if object status is ok",
+ xml:collect([[<status>good</status>]]),
+ function ()
+ local n = msg_box("[t]errible, [v]ery bad, [b]ad, [a]verage, [G]ood, [V]ery good, [S]pecial?")
+ local t =
+ {
+ ["t"] = "terrible",
+ ["v"] = "very bad",
+ ["b"] = "bad",
+ ["a"] = "average",
+ ["G"] = "good",
+ ["V"] = "very good",
+ ["S"] = "special",
+ }
+ if not t[strchar(n)] then return end
+ return xml:collect("<status>"..t[strchar(n)].."</status>")
+ end,
+ },
+ ["state"] =
+ {
+ "Check is true if object is identified/unidentified",
+ xml:collect([[<state>identified</state>]]),
+ function ()
+ local n = msg_box("[i]dentified, [n]on identified?")
+ local t =
+ {
+ ["i"] = "identified",
+ ["n"] = "not identified",
+ }
+ if not t[strchar(n)] then return end
+ return xml:collect("<state>"..t[strchar(n)].."</state>")
+ end,
+ },
+ ["tval"] =
+ {
+ "Check is true if object tval(from k_info.txt) is ok",
+ xml:collect([[<tval>55</tval>]]),
+ function ()
+ local n = input_box("Tval to match?", 79)
+ if n == "" then return end
+ return xml:collect("<tval>"..n.."</tval>")
+ end,
+ },
+ ["sval"] =
+ {
+ {
+ "Check is true if object sval(from k_info.txt) is between",
+ "2 values",
+ },
+ xml:collect([[<sval min='0' max='100'></sval>]]),
+ function ()
+ local s = "<sval "
+
+ local n = input_box("Min sval?", 79)
+ if n == "" then return end
+ s = s.."min='"..n.."' "
+
+ n = input_box("Max sval?", 79)
+ if n == "" then return end
+ s = s.."max='"..n.."'></sval>"
+ return xml:collect(s)
+ end,
+ },
+ ["race"] =
+ {
+ "Check is true if player race is ok",
+ xml:collect([[<race>dunadan</race>]]),
+ function ()
+ local n = input_box("Player race to match?", 79)
+ if n == "" then return end
+ return xml:collect("<race>"..n.."</race>")
+ end,
+ },
+ ["subrace"] =
+ {
+ "Check is true if player subrace is ok",
+ xml:collect([[<subrace>vampire</subrace>]]),
+ function ()
+ local n = input_box("Player subrace to match?", 79)
+ if n == "" then return end
+ return xml:collect("<subrace>"..n.."</subrace>")
+ end,
+ },
+ ["class"] =
+ {
+ "Check is true if player class is ok",
+ xml:collect([[<class>sorceror</class>]]),
+ function ()
+ local n = input_box("Player class to match?", 79)
+ if n == "" then return end
+ return xml:collect("<class>"..n.."</class>")
+ end,
+ },
+ ["level"] =
+ {
+ "Check is true if player level is between 2 values",
+ xml:collect([[<level min='20' max='50'></level>]]),
+ function ()
+ local s = "<level "
+
+ local n = input_box("Min player level?", 79)
+ if n == "" then return end
+ s = s.."min='"..n.."' "
+
+ n = input_box("Max player level?", 79)
+ if n == "" then return end
+ s = s.."max='"..n.."'></level>"
+
+ return xml:collect(s)
+ end,
+ },
+ ["skill"] =
+ {
+ "Check is true if player skill level is between 2 values",
+ xml:collect([[<skill min='10' max='20'>Divination</skill>]]),
+ function ()
+ local s = "<skill "
+
+ local n = input_box("Min skill level?", 79)
+ if n == "" then return end
+ s = s.."min='"..n.."' "
+
+ n = input_box("Max skill level?", 79)
+ if n == "" then return end
+ s = s.."max='"..n.."'>"
+
+ n = input_box("Skill name?", 79)
+ if n == "" then return end
+ if find_skill_i(n) == -1 then return end
+ s = s..n.."</skill>"
+
+ return xml:collect(s)
+ end,
+ },
+ ["ability"] =
+ {
+ "Check is true if player has the ability",
+ xml:collect([[<ability>Ammo creation</ability>]]),
+ function()
+ local n = input_box("Ability name?", 79)
+ if n == "" then return end
+ if find_ability(n) == -1 then return end
+ return xml:collect("<ability>"..n.."</ability>")
+ end,
+ },
+ ["inventory"] =
+ {
+ {
+ "Check is true if something in player's inventory matches",
+ "the contained rule",
+ },
+ xml:collect([[<inventory><foo1>...</foo1></inventory>]]),
+ function ()
+ return xml:collect("<inventory></inventory>")
+ end,
+ },
+ ["equipment"] =
+ {
+ {
+ "Check is true if something in player's equipment matches",
+ "the contained rule",
+ },
+ xml:collect([[<equipment><foo1>...</foo1></equipment>]]),
+ function ()
+ return xml:collect("<equipment></equipment>")
+ end,
+ },
+}
+
+function auto_aux:display_desc(sel)
+ local d = auto_aux.types_desc[sel][1]
+ if type(d) == "string" then
+ c_prt(TERM_WHITE, d, 1, 17)
+ else
+ local k, e, i
+ i = 0
+ for k, e in d do
+ c_prt(TERM_WHITE, e, 1 + i, 17)
+ i = i + 1
+ end
+ end
+end
+
+function auto_aux:add_child(sel)
+ -- <rule> and <not> contain only one match
+ if (auto_aux.rule.label == "rule" or auto_aux.rule.label == "not") and auto_aux.rule[1] then return end
+ if (auto_aux.rule.label == "rule" or auto_aux.rule.label == "equipment") and auto_aux.rule[1] then return end
+ if (auto_aux.rule.label == "rule" or auto_aux.rule.label == "inventory") and auto_aux.rule[1] then return end
+
+ -- Only <and> and <or> can contain
+ if auto_aux.rule.label ~= "rule" and auto_aux.rule.label ~= "and" and auto_aux.rule.label ~= "or" and auto_aux.rule.label ~= "not" and auto_aux.rule.label ~= "equipment" and auto_aux.rule.label ~= "inventory" then return end
+
+ -- get it
+ local r = auto_aux.types_desc[sel][3]()
+ if not r then return end
+
+ -- Ok add it
+ tinsert(auto_aux.rule, r[1])
+end
+
+function auto_aux.regen_ruleset()
+ local i
+ for i = 0, __rules_max - 1 do
+ __rules[i].fct = gen_full_rule(__rules[i].table)
+ end
+end
+
+
+-- Easily add new rules
+function easy_add_rule(typ, mode, do_status, obj)
+ local detect_rule
+
+ if mode == "tval" then
+ detect_rule = "<tval>"..obj.tval.."</tval>"
+ elseif mode == "tsval" then
+ detect_rule = "<and><tval>"..obj.tval.."</tval><sval min='"..obj.sval.."' max='"..obj.sval.."'></sval></and>"
+ elseif mode == "name" then
+ detect_rule = "<name>"..strlower(object_desc(obj, -1, 0)).."</name>"
+ end
+
+ if do_status == TRUE then
+ local status = object_status(obj)
+ if status and not (status == "") then
+ detect_rule = "<and>"..detect_rule.."<status>"..status.."</status></and>"
+ end
+ end
+
+ local rule = "<rule module='"..game_module.."' name='"..typ.."' type='"..typ.."'>"..detect_rule.."</rule>"
+ auto_aux:new_rule(0, xml:collect(rule)[1], '')
+ auto_aux.regen_ruleset()
+ msg_print("Rule added. Please go to the Automatizer screen (press = then T)")
+ msg_print("to save the modified ruleset.")
+end
diff --git a/lib/mods/theme/core/building.lua b/lib/mods/theme/core/building.lua
new file mode 100644
index 00000000..8e88888a
--- /dev/null
+++ b/lib/mods/theme/core/building.lua
@@ -0,0 +1,15 @@
+__building_actions = {}
+
+function add_building_action(a)
+ assert(a.index, "No building action index")
+ assert(a.action, "No building action action")
+ __building_actions[a.index] = a.action
+end
+
+function __bact_activate(bact)
+ if __building_actions[bact] then
+ return __building_actions[bact]()
+ end
+end
+
+add_hook_script(HOOK_BUILDING_ACTION, "__bact_activate", "__bact_activate")
diff --git a/lib/mods/theme/core/crpt_aux.lua b/lib/mods/theme/core/crpt_aux.lua
new file mode 100644
index 00000000..97f8d4b6
--- /dev/null
+++ b/lib/mods/theme/core/crpt_aux.lua
@@ -0,0 +1,182 @@
+-- Core functions for corruptions
+
+__corruptions = {}
+__corruptions_max = 0
+__corruptions_callbacks_max = 0
+
+-- Get the corruption
+function player.corruption(c, set)
+ if set then
+ player.corruptions_aux[c + 1] = set
+ player.redraw = bor(player.redraw, PR_BASIC)
+ player.update = bor(player.update, PU_BONUS, PU_TORCH, PU_BODY, PU_POWERS)
+ if (set == TRUE) and (__corruptions[c].gain) then
+ __corruptions[c].gain()
+ end
+ if (set == FALSE) and (__corruptions[c].lose) then
+ __corruptions[c].lose()
+ end
+ else
+ return player.corruptions_aux[c + 1]
+ end
+end
+
+-- Test if we have that corruption
+-- We must:
+-- 1) have it or be willing to get it
+-- 2) have all its dependancies
+-- 3) have none of its opposing corruptions
+-- 4) pass the possible tests
+function test_depend_corrupt(corrupt, can_gain)
+ local i, c
+
+ if not can_gain then can_gain = FALSE end
+
+ if can_gain == TRUE then
+ if (player.corruption(corrupt) ~= FALSE) then
+ return FALSE
+ end
+ else
+ if (player.corruption(corrupt) ~= TRUE) then
+ return FALSE
+ end
+ end
+
+ for c, i in __corruptions[corrupt].depends do
+ if test_depend_corrupt(c) ~= TRUE then
+ return FALSE
+ end
+ end
+
+ for c, i in __corruptions[corrupt].oppose do
+ if test_depend_corrupt(c) ~= FALSE then
+ return FALSE
+ end
+ end
+
+ -- are we even allowed to get it?
+ if __corruptions[corrupt].can_gain and (not __corruptions[corrupt].can_gain()) then
+ return FALSE
+ end
+
+ return TRUE
+end
+
+-- Gain a new corruption
+function gain_corruption(group)
+ local i, max
+ local pos = {}
+
+ -- Get the list of all possible ones
+ max = 0
+ for i = 0, __corruptions_max - 1 do
+ if __corruptions[i].group == group and test_depend_corrupt(i, TRUE) == TRUE and __corruptions[i].random == TRUE and __corruptions[i].allow() then
+ pos[max] = i
+ max = max + 1
+ end
+ end
+
+ -- Ok now get one of them
+ if (max > 0) then
+ local ret = rand_int(max)
+
+ player.corruption(pos[ret], TRUE)
+ cmsg_print(TERM_L_RED, __corruptions[pos[ret]].get_text)
+
+ return pos[ret]
+ else
+ return -1
+ end
+end
+
+-- Lose an existing corruption
+function lose_corruption()
+ local i, max
+ local pos = {}
+
+ -- Get the list of all possible ones
+ max = 0
+ for i = 0, __corruptions_max - 1 do
+ if test_depend_corrupt(i) == TRUE and __corruptions[i].removable == TRUE then
+ pos[max] = i
+ max = max + 1
+ end
+ end
+
+ -- Ok now get one of them
+ if (max > 0) then
+ local ret = rand_int(max)
+
+ player.corruption(pos[ret], FALSE)
+ cmsg_print(TERM_L_RED, __corruptions[pos[ret]].lose_text)
+
+ -- Ok now lets see if it broke some dependancies
+ for i = 0, max - 1 do
+ if player.corruption(pos[i]) ~= test_depend_corrupt(pos[i]) then
+ player.corruption(pos[i], FALSE)
+ cmsg_print(TERM_L_RED, __corruptions[pos[i]].lose_text)
+ end
+ end
+
+ return pos[ret]
+ else
+ return -1
+ end
+end
+
+-- Lose all corruptions (for e.g. Potion of New Life)
+function lose_all_corruptions()
+ local i;
+ for i = 0, __corruptions_max - 1 do
+ lose_corruption()
+ end
+ return -1
+end
+
+-- Creates a new corruption
+function add_corruption(c)
+ assert(c.color, "No corruption color")
+ assert(c.name, "No corruption name")
+ assert(c.get_text, "No corruption get_text")
+ assert(c.lose_text, "No corruption lose_text")
+ assert(c.desc, "No corruption desc")
+ assert(c.hooks, "Nothing to do for corruption")
+ if not c.random then c.random = TRUE end
+ if not c.removable then c.removable = TRUE end
+ if not c.allow then c.allow = function() return not nil end end
+
+ if c.depends == nil then c.depends = {} end
+ if c.oppose == nil then c.oppose = {} end
+
+ -- We must make sure the other ones opposes too
+ local o, i
+ for o, i in c.oppose do
+ __corruptions[o].oppose[__corruptions_max] = TRUE
+ end
+
+ local index, h
+ for index, h in c.hooks do
+ add_hook_script(index, "__lua__corrupt_callback"..__corruptions_callbacks_max, "__lua__corrupt_callback"..__corruptions_callbacks_max)
+ setglobal("__lua__corrupt_callback"..__corruptions_callbacks_max,
+ function (...)
+ if test_depend_corrupt(%__corruptions_max) == TRUE then
+ return call(%h, arg)
+ end
+ end
+ )
+ __corruptions_callbacks_max = __corruptions_callbacks_max + 1
+ end
+
+ if type(c.desc) == "table" then
+ local new_desc = ""
+ for index, h in c.desc do
+ new_desc = new_desc..h.."\n"
+ end
+ c.desc = new_desc
+ end
+
+ __corruptions[__corruptions_max] = c
+ __corruptions_max = __corruptions_max + 1
+ return (__corruptions_max - 1)
+end
+
diff --git a/lib/mods/theme/core/dungeon.lua b/lib/mods/theme/core/dungeon.lua
new file mode 100644
index 00000000..d91d785b
--- /dev/null
+++ b/lib/mods/theme/core/dungeon.lua
@@ -0,0 +1,55 @@
+-- Internal lua file in charge of dungeon stuff
+
+function place_dungeon(y, x, d_idx)
+ if d_idx then
+ wild_map(y, x).entrance = 1000 + d_idx
+ else
+ wild_map(y, x).entrance = 0
+ end
+end
+
+function dungeon(d_idx)
+ return d_info[1 + d_idx]
+end
+
+function wild_feat(wild)
+ return wf_info[1 + wild.feat]
+end
+
+function explode_dir(dir)
+ return ddy[dir + 1], ddx[dir + 1]
+end
+
+function rotate_dir(dir, mov)
+ if mov > 0 then
+ if dir == 7 then dir = 8
+ elseif dir == 8 then dir = 9
+ elseif dir == 9 then dir = 6
+ elseif dir == 6 then dir = 3
+ elseif dir == 3 then dir = 2
+ elseif dir == 2 then dir = 1
+ elseif dir == 1 then dir = 4
+ elseif dir == 4 then dir = 7
+ end
+ elseif mov < 0 then
+ if dir == 7 then dir = 4
+ elseif dir == 4 then dir = 1
+ elseif dir == 1 then dir = 2
+ elseif dir == 2 then dir = 3
+ elseif dir == 3 then dir = 6
+ elseif dir == 6 then dir = 9
+ elseif dir == 9 then dir = 8
+ elseif dir == 8 then dir = 7
+ end
+ end
+
+ return dir
+end
+
+-- Place a trap for a specific level
+function place_trap(y, x, level)
+ local old_dun = dun_level
+ dun_level = level
+ %place_trap(y, x)
+ dun_level = old_dun
+end
diff --git a/lib/mods/theme/core/gen_idx.lua b/lib/mods/theme/core/gen_idx.lua
new file mode 100644
index 00000000..5f3af435
--- /dev/null
+++ b/lib/mods/theme/core/gen_idx.lua
@@ -0,0 +1,261 @@
+-- Place here the list of files to parse
+files =
+{
+ "birth.txt",
+ "experien.hlp",
+ "gods.txt",
+ "explore.hlp",
+ "newbie.hlp",
+ "advanced.hlp",
+ "help.hlp",
+ "general.txt",
+ "whattome.txt",
+ "dungeon.txt",
+ "spoiler.hlp",
+ "g_melkor.txt",
+ "skills.txt",
+ "c_bard.txt",
+ "c_druid.txt",
+ "c_lorema.txt",
+ "c_mage.txt",
+ "c_mimic.txt",
+ "c_mindcr.txt",
+ "c_monk.txt",
+ "c_palad.txt",
+ "c_posses.txt",
+ "c_pr_drk.txt",
+ "c_pr_eru.txt",
+ "c_pr_man.txt",
+ "c_symbia.txt",
+ "c_alchem.txt",
+ "c_archer.txt",
+ "c_assass.txt",
+ "c_axemas.txt",
+ "c_demono.txt",
+ "c_geoman.txt",
+ "c_hafted.txt",
+ "c_necro.txt",
+ "c_polear.txt",
+ "c_ranger.txt",
+ "c_rogue.txt",
+ "c_runecr.txt",
+ "c_sorcer.txt",
+ "c_swordm.txt",
+ "c_thaum.txt",
+ "c_unbel.txt",
+ "c_warper.txt",
+ "c_warrio.txt",
+ "m_meta.txt",
+ "rm_skel.txt",
+ "rm_zomb.txt",
+ "luckspoi.txt",
+ "m_air.txt",
+ "dunspoil.txt",
+ "g_eru.txt",
+ "g_manwe.txt",
+ "g_tulkas.txt",
+ "m_divin.txt",
+ "m_mimic.txt",
+ "m_water.txt",
+ "magic.txt",
+ "r_drkelf.txt",
+ "r_dwarf.txt",
+ "r_elf.txt",
+ "r_hielf.txt",
+ "r_hobbit.txt",
+ "r_pettyd.txt",
+ "r_wodelf.txt",
+ "rm_spec.txt",
+ "tome_faq.txt",
+ "ability.txt",
+ "automat.txt",
+ "c_summon.txt",
+ "command.txt",
+ "corspoil.txt",
+ "debug.txt",
+ "m_music.txt",
+ "rm_barb.txt",
+ "macrofaq.txt",
+ "m_necrom.txt",
+ "m_mindcr.txt",
+ "m_symbio.txt",
+ "m_thaum.txt",
+ "magic.hlp",
+ "m_convey.txt",
+ "m_fire.txt",
+ "m_mana.txt",
+ "m_mind.txt",
+ "m_nature.txt",
+ "m_tempo.txt",
+ "m_udun.txt",
+ "m_geoman.txt",
+ "essences.txt",
+ "r_ent.txt",
+ "g_yavann.txt",
+ "defines.txt",
+ "rm_vamp.txt",
+ "inscrip.txt",
+ "m_earth.txt",
+ "option.txt",
+ "attack.txt",
+ "version.txt",
+ "m_demono.txt",
+ "r_beorn.txt",
+ "r_deathm.txt",
+ "r_rohank.txt",
+ "r_hafogr.txt",
+ "r_human.txt",
+ "r_kobold.txt",
+ "r_maia.txt",
+ "r_orc.txt",
+ "r_thlord.txt",
+ "r_troll.txt",
+ "r_yeek.txt",
+ "rm_class.txt",
+ "rm_herm.txt",
+ "rm_lsoul.txt",
+ "wishing.txt",
+ "c_priest.txt",
+ "fatespoi.txt",
+ "gambling.txt",
+ "r_dunad.txt",
+ "r_gnome.txt",
+ "r_hafelf.txt",
+ "c_merch.txt",
+ "spoil_faq.txt",
+}
+
+out_file = "index.txt"
+
+index = {}
+
+function parse_file(file)
+ local fff = openfile(path_build(ANGBAND_DIR_HELP, file), "r")
+ local line
+
+ line = read(fff, "*l")
+ while line do
+ local i, j, anchor, name, subname = strfind(line, "~~~~~(%d+)|([%d%a -]+)|([%d%a -]+)")
+ if not i then
+ i, j, anchor, name = strfind(line, "~~~~~(%d+)|([%d%a -]+)")
+
+ subname = nil
+ end
+
+ if i then
+ if not index[name] then
+ index[name] = {}
+ end
+ if subname then
+ tinsert(index[name], { __name__ = subname, __file__ = file, __anchor__ = anchor})
+ else
+ tinsert(index[name], { __name__ = "__primary__", __file__ = file, __anchor__ = anchor})
+ end
+ end
+
+ line = read(fff, "*l")
+ end
+
+ closefile(fff)
+end
+
+function sort_fct(a, b)
+ local i, len
+
+ a = a.__name__
+ b = b.__name__
+
+ if strlen(a) > strlen(b) then len = strlen(b) else len = strlen(a) end
+
+ for i = 1, len do
+ local ac = strbyte(a, i)
+ local bc = strbyte(b, i)
+
+ if ac < bc then
+ return not nil
+ elseif ac > bc then
+ return nil
+ end
+ end
+ if strlen(a) > strlen(b) then return nil else return not nil end
+end
+
+function generate_index()
+ local k, e, index_list
+ for _, e in files do
+ parse_file(e)
+ end
+
+ index_list = {}
+ for k, e in index do
+ -- Ok either my sort function or lua sort function sucks ass ..
+ sort(e, sort_fct)
+ sort(e, sort_fct)
+ sort(e, sort_fct)
+ sort(e, sort_fct)
+ sort(e, sort_fct)
+ tinsert(index_list, {__name__= k, __table__ = e})
+ end
+
+ -- Ok either my sort function or lua sort function sucks ass ..
+ sort(index_list, sort_fct)
+ sort(index_list, sort_fct)
+ sort(index_list, sort_fct)
+ sort(index_list, sort_fct)
+ sort(index_list, sort_fct)
+ index = index_list
+end
+
+function out_link(fff, space, name, file, anchor)
+ write(fff, space.."*****"..file.."*"..anchor.."["..name.."]\n")
+end
+
+function print_index()
+ local i, j, c, new_c
+ local fff = openfile(path_build(ANGBAND_DIR_HELP, out_file), "w")
+
+ write(fff,
+[[|||||oy
+#####R /----------------------------------------\
+#####R < Help Index >
+#####R \----------------------------------------/
+
+This is the index of everything in the T.o.M.E. documentation.
+
+#####BHit a letter key to jump to the entries for that letter.
+
+Some entries in the index link to the same place as other entries. This is
+intentional, so that the information you want is easy to find.
+
+Don't forget you can browse the help from the *****help.hlp*02[Main menu].
+
+#####sSpotted a problem with the help files, or some content thats missing?
+#####sContact fearoffours@t-o-m-e.net .
+
+]])
+
+ c = ' '
+ for i = 1, getn(index) do
+ new_c = strbyte(index[i].__name__, 1)
+ if c ~= new_c then
+ c = new_c
+ write(fff, "~~~~~"..c.."\n")
+ write(fff, "*****/"..strchar(c)..out_file.."*"..c.."["..strchar(c).."]\n")
+ end
+ for j = 1, getn(index[i].__table__) do
+ if index[i].__table__[j].__name__ == "__primary__" then
+ out_link(fff, " ", index[i].__name__, index[i].__table__[j].__file__, index[i].__table__[j].__anchor__)
+ end
+ end
+ for j = 1, getn(index[i].__table__) do
+ if index[i].__table__[j].__name__ ~= "__primary__" then
+ out_link(fff, " ", index[i].__table__[j].__name__, index[i].__table__[j].__file__, index[i].__table__[j].__anchor__)
+ end
+ end
+ end
+ closefile(fff)
+end
+
+generate_index()
+
+print_index()
diff --git a/lib/mods/theme/core/gods.lua b/lib/mods/theme/core/gods.lua
new file mode 100644
index 00000000..77e0aad5
--- /dev/null
+++ b/lib/mods/theme/core/gods.lua
@@ -0,0 +1,40 @@
+-- Gods helper files
+
+-- Gods structs
+
+__gods_hook = {}
+__gods_callbacks = {}
+__gods_callbacks_max = 0
+
+function add_god(q)
+ local i, index, d, z, qq
+
+ assert(q.name, "No god name")
+ assert(q.desc, "No god desc")
+ assert(q.hooks, "No god hooks")
+
+ i = add_new_gods(q.name);
+
+ z = 0
+ for index, d in q.desc do
+ desc_god(i, z, d);
+ z = z + 1
+ end
+
+ __gods_hook[i] = q.hooks
+ for index, d in q.hooks do
+ add_hook_script(index, "__lua__gods_callback"..__gods_callbacks_max, "__lua__gods_callback"..__gods_callbacks_max)
+ setglobal("__lua__gods_callback"..__gods_callbacks_max, d)
+ __gods_callbacks_max = __gods_callbacks_max + 1
+ end
+ if q.data then
+ for index, d in q.data do
+ -- Besure it exists
+ setglobal(index, d)
+
+ -- Make it save & load
+ add_loadsave(index, d)
+ end
+ end
+ return i
+end
diff --git a/lib/mods/theme/core/help.lua b/lib/mods/theme/core/help.lua
new file mode 100644
index 00000000..a581fe63
--- /dev/null
+++ b/lib/mods/theme/core/help.lua
@@ -0,0 +1,141 @@
+-- Ingame contextual help
+
+-- We use our own hook list as to not overburn the hook proccessor
+-- with many hooks that would slow down things
+-- It would be very meaningless if the option is not even on
+__ingame_hooks = {}
+
+__ingame_help_max = 0
+
+function ingame_help(t, ...)
+ -- This function can also be used to call the callbacks
+ if type(t) == "string" then
+ local f = getglobal("__ingame_help_fct_"..t)
+ call(f, arg)
+ return
+ end
+
+ assert(t.desc or t.fct, "no ingame help desc/fct")
+ assert(t.hook or t.callback, "no ingame help hook/callback")
+ if t.hook then assert(t.event, "no ingame hepl event needed by hook") end
+
+ -- Set it to only trigger once
+ setglobal("__ingame_help_activated_"..__ingame_help_max, FALSE)
+ -- Save/load it
+ add_loadsave("__ingame_help_activated_"..__ingame_help_max, FALSE)
+
+ if t.hook then
+ -- If the hok list didnt exist yet, add it
+ if not __ingame_hooks[t.hook] then
+ -- Set it to empty, we'll fill it later
+ __ingame_hooks[t.hook] = {}
+ -- Add the global hook
+ add_hooks
+ {
+ [t.hook] = function (...)
+ if option_ingame_help ~= TRUE then return end
+ local k, e
+ for k, e in __ingame_hooks[%t.hook] do
+ if k ~= "n" then
+ call(e, arg)
+ end
+ end
+ end
+ }
+ end
+ if t.desc then
+ tinsert(__ingame_hooks[t.hook],
+ function (...)
+ local tbl = %t
+ if getglobal("__ingame_help_activated_"..%__ingame_help_max) == FALSE then
+ if call(tbl.event, arg) == TRUE then
+ local k, e
+ for k, e in tbl.desc do
+ msg_print(TERM_YELLOW, e)
+ end
+ setglobal("__ingame_help_activated_"..%__ingame_help_max, TRUE)
+ end
+ end
+ end
+ )
+ elseif t.fct then
+ tinsert(__ingame_hooks[t.hook],
+ function (...)
+ local tbl = %t
+ if getglobal("__ingame_help_activated_"..%__ingame_help_max) == FALSE then
+ if call(tbl.event, arg) == TRUE then
+ if tbl.fct() == TRUE then
+ setglobal("__ingame_help_activated_"..%__ingame_help_max, TRUE)
+ end
+ end
+ end
+ end
+ )
+ end
+ else
+ local no_test = FALSE
+ if t.no_test == TRUE then no_test = TRUE end
+ if t.desc then
+ setglobal
+ (
+ "__ingame_help_fct_"..(t.callback),
+ function (...)
+ local tbl = %t
+ if ((option_ingame_help == TRUE) or (%no_test == TRUE)) and (getglobal("__ingame_help_activated_"..%__ingame_help_max) == FALSE) then
+ local k, e
+ for k, e in tbl.desc do
+ msg_print(TERM_YELLOW, e)
+ end
+ setglobal("__ingame_help_activated_"..%__ingame_help_max, TRUE)
+ end
+ end
+ )
+ elseif t.fct then
+ setglobal
+ (
+ "__ingame_help_fct_"..(t.callback),
+ function (...)
+ local tbl = %t
+ if ((option_ingame_help == TRUE) or (%no_test == TRUE)) and (getglobal("__ingame_help_activated_"..%__ingame_help_max) == FALSE) then
+ if call(tbl.fct, arg) == TRUE then
+ setglobal("__ingame_help_activated_"..%__ingame_help_max, TRUE)
+ end
+ end
+ end
+ )
+ end
+ end
+
+ __ingame_help_max = __ingame_help_max + 1
+end
+
+-- Clean up the ingame help seen at birth
+add_hooks
+{
+ [HOOK_BIRTH_OBJECTS] = function()
+ local i
+ for i = 0, __ingame_help_max - 1 do
+ setglobal("__ingame_help_activated_"..i, FALSE)
+ end
+ end
+}
+
+function ingame_clean()
+ local i
+ for i = 0, __ingame_help_max - 1 do
+ setglobal("__ingame_help_activated_"..i, FALSE)
+ end
+end
+
+-- helper function, brings up a doc
+function ingame_help_doc(name, anchor)
+ -- Save screen
+ screen_save();
+
+ -- Peruse the help file
+ if not anchor then anchor = 0 end
+ show_file(name, 0, -anchor, 0)
+
+ -- Load screen
+ screen_load()
+end
diff --git a/lib/mods/theme/core/init.lua b/lib/mods/theme/core/init.lua
new file mode 100644
index 00000000..11b812d5
--- /dev/null
+++ b/lib/mods/theme/core/init.lua
@@ -0,0 +1,83 @@
+--
+-- This file is loaded at the initialisation of ToME
+-- Load the system functions
+--
+
+-- Name of globals to save
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "load.lua")
+
+-- Very thin xml parser(49 lines ;)
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "xml.lua")
+
+-- various vital helper code
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "util.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "player.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "objects.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "monsters.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "building.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "dungeon.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "s_aux.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "crpt_aux.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "mimc_aux.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "quests.lua")
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "gods.lua")
+
+-- Load the ingame contextual help
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "help.lua")
+
+-- let the store specific stuff happen!
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "stores.lua")
+
+--------------------------------------------------------------
+--------------------------------------------------------------
+--------------------------------------------------------------
+-------------Here we load the non vital scripts---------------
+-----------------------from lib/scpt--------------------------
+--------------------------------------------------------------
+--------------------------------------------------------------
+tome_dofile("init.lua")
+
+-- The dofile functions for each patch
+patch_dofile = {}
+
+-- Now load patches
+function load_patches()
+ scansubdir(ANGBAND_DIR_PATCH)
+ for i = 0, scansubdir_max - 1 do
+ if (scansubdir_result[i + 1] ~= ".") and (scansubdir_result[i + 1] ~= "..") then
+ local dir = path_build(ANGBAND_DIR_PATCH, scansubdir_result[i + 1])
+ local file = path_build(dir, "patch.lua")
+ if file_exist(file) == TRUE then
+ patch_init = nil
+ tome_dofile_anywhere(dir, "patch.lua", TRUE)
+ unset_safe_globals()
+ if patch_init == nil then
+ set_safe_globals()
+ quit("Patch in "..file.." did not include a patch_init() function")
+ else
+ set_safe_globals()
+
+ -- create the dofile function
+ patch_dofile[scansubdir_result[i + 1]] = function(f)
+ tome_dofile_anywhere(%dir, f, TRUE)
+ end
+
+ local name, version = patch_init()
+ if name == nil or version == nil then
+ quit("Patch in "..file.." did not return valid name or version.\nIt must return name, version")
+ end
+ patch_version(name, version)
+ end
+ end
+ end
+ end
+end
+load_patches()
+
+--------------------------------------------------------------
+--------------------------------------------------------------
+--------------------------------------------------------------
+--
+-- Do not thouch after this line
+--
+tome_dofile_anywhere(ANGBAND_DIR_CORE, "load2.lua")
diff --git a/lib/mods/theme/core/load.lua b/lib/mods/theme/core/load.lua
new file mode 100644
index 00000000..9522ec91
--- /dev/null
+++ b/lib/mods/theme/core/load.lua
@@ -0,0 +1,37 @@
+-- Savefile stuff
+-- Do not meddle in the affairs of savefiles for they are subtle and quick to be become incompatible
+
+__loadsave_name = {}
+__loadsave_max = 0
+__loadsave_tmp = 0
+
+function add_loadsave(name, default)
+ assert(name, "No variable name to save")
+ assert(default, "No default value")
+
+ -- if it is a table we must create many entries
+ if type(default) == "table" then
+ for k, e in default do
+ add_loadsave(name.."."..k, e)
+ end
+ else
+ __loadsave_name[__loadsave_max] = { name = name, default = default }
+ __loadsave_max = __loadsave_max + 1
+ end
+end
+
+-- Example of how to save a table
+-- NOTE: { 1, 2, 3 } will NOT work, the key MUST be a string
+--[[
+add_loadsave("t",
+{
+ foo = 7,
+ tab = {
+ a = 1,
+ b = 2,
+ tab = {
+ a=1, b=2, c=3,
+ },
+ },
+})
+]]
diff --git a/lib/mods/theme/core/load2.lua b/lib/mods/theme/core/load2.lua
new file mode 100644
index 00000000..7e151d91
--- /dev/null
+++ b/lib/mods/theme/core/load2.lua
@@ -0,0 +1,56 @@
+-- Savefile helpers
+
+-- function called when a key in the variable part ofthe savefile is read
+-- if the key matches what we need, we use it, otehrwise just ignore it
+function __savefile_load(key, val)
+ local index, elem
+
+ for index, elem in __loadsave_name do
+ if (key == elem.name) then
+ dostring(elem.name.." = "..val)
+ end
+ end
+end
+
+-- called when the game is saved, can only save numbers
+-- assosiate a key with them to allow the loading code to recognize them
+function __savefile_save()
+ local index, elem
+ for index, elem in __loadsave_name do
+ dostring("__loadsave_tmp = "..elem.name)
+ save_number_key(elem.name, __loadsave_tmp);
+ end
+end
+
+register_savefile(__loadsave_max)
+add_hook_script(HOOK_LOAD_GAME, "__savefile_load", "__hook_load")
+add_hook_script(HOOK_SAVE_GAME, "__savefile_save", "__hook_save")
+
+-- Parse a flattened(i.e: foo.bar.zog) table path and recrate tables
+function reconstruct_table(name)
+ for i = 1, strlen(name) - 1 do
+ if strsub(name, i, i) == "." then
+ local tbl = strsub(name, 1, i - 1)
+
+ if dostring("return "..tbl) == nil then
+ dostring(tbl.."={}")
+ end
+ end
+ end
+end
+
+-- Automagically set unkown variables, otherwise the savefile code
+-- might get VERY upset
+do
+ local k, e
+ -- We need to be able to check for unknown globals
+ unset_safe_globals()
+ for k, e in __loadsave_name do
+ reconstruct_table(e.name)
+ if dostring("return "..(e.name)) == nil then
+ dostring((e.name).." = "..(e.default))
+ end
+ end
+ -- Now taht we did, we set it back, for it is usefull ;)
+ set_safe_globals()
+end
diff --git a/lib/mods/theme/core/mimc_aux.lua b/lib/mods/theme/core/mimc_aux.lua
new file mode 100644
index 00000000..cea1f4dc
--- /dev/null
+++ b/lib/mods/theme/core/mimc_aux.lua
@@ -0,0 +1,96 @@
+-- Mimic shapes helper file
+
+__mimics = {}
+__mimics_max = 1
+__mimics_names = {}
+
+function add_mimic_shape(t)
+ assert(t.name, "no mimic name")
+ assert(t.desc, "no mimic desc")
+ assert(t.calc, "no mimic calc")
+ assert(t.level, "no mimic level")
+ assert(t.duration, "no mimic duration")
+
+ if not t.limit then t.limit = 0 end
+
+ if not t.obj_name then
+ t.obj_name = t.name
+ end
+
+ t.show_name = '['..t.name..']'
+
+ -- if it needs hooks, add them
+ if t.hooks then
+ add_hooks(t.hooks)
+ end
+
+ -- Add it in a name to index hash table
+ __mimics_names[t.name] = __mimics_max
+
+ __mimics[__mimics_max] = t
+ __mimics_max = __mimics_max + 1
+end
+
+function resolve_mimic_name(name)
+ if __mimics_names[name] then
+ return __mimics_names[name]
+ else
+ return -1
+ end
+end
+
+function find_random_mimic_shape(level, limit, realm)
+ local mimic, tries
+
+ tries = 1000
+ while tries > 0 do
+ tries = tries - 1
+ mimic = rand_range(1, __mimics_max - 1)
+ if (not realm) or (__mimics[mimic].realm == realm) then
+ if limit >= __mimics[mimic].limit then
+ if (rand_int(__mimics[mimic].level * 3) < level) and (__mimics[mimic].rarity < 100) and (magik(100 - __mimics[mimic].rarity) == TRUE) then
+ break
+ end
+ end
+ end
+ end
+ if tries > 0 then
+ return mimic
+ else
+ return resolve_mimic_name("Abomination")
+ end
+end
+
+function get_mimic_info(mimic, info)
+ if not __mimics[mimic] then return 0 end
+ return __mimics[mimic][info]
+end
+
+function get_mimic_rand_dur(mimic)
+ return rand_range(__mimics[mimic].duration[1], __mimics[mimic].duration[2])
+end
+
+function calc_mimic(mimic)
+ return __mimics[mimic].calc()
+end
+
+function calc_mimic_power(mimic)
+ if __mimics[mimic].power then __mimics[mimic].power() end
+end
+
+--- Here comes the only vital shape
+
+add_mimic_shape
+{
+ ["name"] = "Abomination",
+ ["obj_name"] = "Abominable Cloak",
+ ["desc"] = "Abominations are failed experiments of powerful wizards.",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {20, 100},
+ ["calc"] = function ()
+ apply_flags(TR1_SPEED + TR1_STR + TR1_INT + TR1_WIS + TR1_DEX + TR1_CON + TR1_CHR, 0, 0, 0, 0, 0, -10)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_AGGRAVATE)
+ end,
+}
diff --git a/lib/mods/theme/core/monsters.lua b/lib/mods/theme/core/monsters.lua
new file mode 100644
index 00000000..ca2851a0
--- /dev/null
+++ b/lib/mods/theme/core/monsters.lua
@@ -0,0 +1,16 @@
+-- SYSTEM FILE
+--
+-- Monster stuff, do not touch
+--
+
+function summon_monster(y, x, lev, friend, typ)
+ if type(typ) == "number" then
+ if friend == TRUE then
+ return summon_specific_friendly(y, x, lev, typ, FALSE)
+ else
+ return summon_specific(y, x, lev, typ)
+ end
+ else
+ return summon_monster_aux(y, x, lev, friend, typ)
+ end
+end
diff --git a/lib/mods/theme/core/objects.lua b/lib/mods/theme/core/objects.lua
new file mode 100644
index 00000000..97320b82
--- /dev/null
+++ b/lib/mods/theme/core/objects.lua
@@ -0,0 +1,45 @@
+-- SYSTEM FILE
+--
+-- Lua object funtions
+--
+
+function create_object(tval, sval)
+ local obj = new_object()
+ object_prep(obj, lookup_kind(tval, sval))
+ return (obj)
+end
+
+function set_item_tester(tester)
+ if tolua.type(tester) == "number" then
+ lua_set_item_tester(tester, "")
+ end
+ if tolua.type(tester) == "string" then
+ lua_set_item_tester(0, tester)
+ end
+ if tolua.type(tester) == "function" then
+ __get_item_hook_default = tester
+ lua_set_item_tester(0, "__get_item_hook_default")
+ end
+end
+
+function create_artifact(a_idx)
+ local obj
+ local tval, sval
+
+ tval = a_info[a_idx + 1].tval
+ sval = a_info[a_idx + 1].sval
+ obj = create_object(tval, sval)
+ obj.name1 = a_idx
+ apply_magic(obj, -1, TRUE, TRUE, TRUE)
+
+ return (obj)
+end
+
+function get_kind(obj)
+ return k_info[obj.k_idx + 1]
+end
+
+function get_item(ask, deny, flags, mask)
+ set_item_tester(mask)
+ return get_item_aux(0, ask, deny, flags)
+end
diff --git a/lib/mods/theme/core/player.lua b/lib/mods/theme/core/player.lua
new file mode 100644
index 00000000..16878228
--- /dev/null
+++ b/lib/mods/theme/core/player.lua
@@ -0,0 +1,135 @@
+-- SYSTEM FILE
+--
+-- Lua player funtions
+--
+
+-- Gods
+function deity(i)
+ return deity_info[1 + i]
+end
+
+-------- skill stuff ---------
+
+-- Easy skill access
+function skill(i)
+ return s_info[i + 1]
+end
+
+-- Sart a lasting spell
+function player.start_lasting_spell(spl)
+ player.music_extra = -spl
+end
+
+-- stat mods
+function player.modify_stat(stat, inc)
+ player.stat_add[1 + stat] = player.stat_add[1 + stat] + inc
+end
+
+-- powers mods
+function player.add_power(pow)
+ player.powers[1 + pow] = TRUE
+end
+
+-- easier inventory access
+function player.inventory(i)
+ return player.inventory_real[i + 1]
+end
+
+-- modify mana
+-- returns TRUE if there is a pb
+function increase_mana(amt)
+ player.csp = player.csp + amt
+ player.redraw = bor(player.redraw, PR_MANA)
+ if (player.csp < 0) then
+ player.csp = 0
+ return TRUE
+ end
+ if (player.csp > player.msp) then
+ player.csp = player.msp
+ end
+ return FALSE
+end
+
+
+-- Return the coordinates of the player whether in wild or not
+function player.get_wild_coord()
+ if player.wild_mode == TRUE then
+ return player.py, player.px
+ else
+ return player.wilderness_y, player.wilderness_x
+ end
+end
+
+-- Create a new power
+__power_fct = {}
+function add_power(p)
+ local i
+
+ assert(p.name, "No power name!")
+ assert(p.desc, "No power desc!")
+ assert(p.desc_get, "No power desc get!")
+ assert(p.desc_lose, "No power desc lose!")
+ assert(p.stat, "No power stat!")
+ assert(p.level, "No power level!")
+ assert(p.cost, "No power cost!")
+ assert(p.fail, "No power fail!")
+ assert(p.power, "No power power!")
+
+ i = add_new_power(p.name, p.desc, p.desc_get, p.desc_lose, p.level, p.cost, p.stat, p.fail)
+ __power_fct[i] = p.power
+ return i
+end
+
+function __power_fct_activate(power)
+ if __power_fct[power] then
+ __power_fct[power]()
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+-- Register in the hook list
+add_hook_script(HOOK_ACTIVATE_POWER, "__power_fct_activate", "__power_fct_activate")
+
+
+--- Mkeys
+
+-- Create a new power
+__mkey_fct = {}
+function add_mkey(p)
+ local i
+
+ assert(p.mkey, "No mkey mkey!")
+ assert(p.fct, "No mkeey fct!")
+
+ __mkey_fct[p.mkey] = p.fct
+end
+
+function __mkey_fct_activate(power)
+ if __mkey_fct[power] then
+ __mkey_fct[power]()
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+-- Register in the hook list
+add_hook_script(HOOK_MKEY, "__mkey_fct_activate", "__mkey_fct_activate")
+
+
+-- Subraces
+function subrace(racem)
+ return race_mod_info[racem + 1]
+end
+
+function subrace_add_power(subrace, power)
+ for i = 1, 4 do
+ if subrace.powers[i] == -1 then
+ subrace.powers[i] = power
+ return not nil
+ end
+ end
+ return nil
+end
diff --git a/lib/mods/theme/core/quests.lua b/lib/mods/theme/core/quests.lua
new file mode 100644
index 00000000..dfe9db51
--- /dev/null
+++ b/lib/mods/theme/core/quests.lua
@@ -0,0 +1,57 @@
+-- Quest helper files
+
+-- Quest structs
+
+__quest_hook = {}
+__quest_callbacks = {}
+__quest_callbacks_max = 0
+__quest_dynamic_desc = {}
+
+function add_quest(q)
+ local i, index, d, z, qq
+
+ assert(q.global, "No quest global name")
+ assert(q.name, "No quest name")
+ assert(q.desc, "No quest desc")
+ assert(q.level, "No quest level")
+ assert(q.hooks, "No quest hooks")
+
+ i = new_quest(q.name);
+ setglobal(q.global, i)
+
+ -- Make it save & load
+ add_loadsave("quest("..q.global..").status", QUEST_STATUS_UNTAKEN)
+
+ if type(q.desc) == "table" then
+ z = 0
+ for index, d in q.desc do
+ quest_desc(i, z, d);
+ z = z + 1
+ end
+ else
+ __quest_dynamic_desc[i] = q.desc
+ quest(i).dynamic_desc = TRUE
+ end
+ quest(i).level = q.level
+ if not q.silent then
+ quest(i).silent = FALSE
+ else
+ quest(i).silent = q.silent
+ end
+ __quest_hook[i] = q.hooks
+ for index, d in q.hooks do
+ add_hook_script(index, "__lua__quest_callback"..__quest_callbacks_max, "__lua__quest_callback"..__quest_callbacks_max)
+ setglobal("__lua__quest_callback"..__quest_callbacks_max, d)
+ __quest_callbacks_max = __quest_callbacks_max + 1
+ end
+ if q.data then
+ for index, d in q.data do
+ -- Besure it exists
+ setglobal(index, d)
+
+ -- Make it save & load
+ add_loadsave(index, d)
+ end
+ end
+ return i
+end
diff --git a/lib/mods/theme/core/s_aux.lua b/lib/mods/theme/core/s_aux.lua
new file mode 100644
index 00000000..ec609b04
--- /dev/null
+++ b/lib/mods/theme/core/s_aux.lua
@@ -0,0 +1,716 @@
+-- Functions to help with spells, do not touch
+
+__schools = {}
+__schools_num = 0
+
+__tmp_spells = {}
+__tmp_spells_num = 0
+
+function add_school(s)
+ __schools[__schools_num] = s
+
+ __schools_num = __schools_num + 1
+ return (__schools_num - 1)
+end
+
+function finish_school(i)
+ local s
+
+ s = __schools[i]
+ assert(s.name, "No school name!")
+ assert(s.skill, "No school skill!")
+
+ -- Need hooks?
+ if s.hooks then
+ add_hooks(s.hooks)
+ end
+
+ new_school(i, s.name, s.skill)
+end
+
+function add_spell(s)
+ __tmp_spells[__tmp_spells_num] = s
+
+ __tmp_spells_num = __tmp_spells_num + 1
+ return (__tmp_spells_num - 1)
+end
+
+function finish_spell(must_i)
+ local i, s
+
+ s = __tmp_spells[must_i]
+ assert(s.name, "No spell name!")
+ assert(s.school, "No spell school!")
+ assert(s.level, "No spell level!")
+ assert(s.mana, "No spell mana!")
+ if not s.mana_max then s.mana_max = s.mana end
+ assert(s.fail, "No spell failure rate!")
+ assert(s.spell, "No spell function!")
+ if not s.info then s.info = function() return "" end end
+ assert(s.desc, "No spell desc!")
+ if not s.random then s.random = SKILL_MAGIC end
+ if s.lasting then
+ assert(type(s.lasting) == "function", "Spell lasting is not function")
+ end
+ if s.stick then
+ local k, e
+ for k, e in s.stick do
+ if type(k) == "table" then
+ assert(e.base_level, "Arg no stick base level")
+ assert(e.max_level, "Arg no stick max level")
+ end
+ end
+ end
+
+ i = new_spell(must_i, s.name)
+ assert(i == must_i, "ACK ! i != must_i ! please contact the maintainer")
+ if type(s.school) == "number" then __spell_school[i] = {s.school}
+ else __spell_school[i] = s.school end
+ spell(i).mana = s.mana
+ spell(i).mana_max = s.mana_max
+ spell(i).fail = s.fail
+ spell(i).skill_level = s.level
+ __spell_spell[i] = s.spell
+ __spell_info[i] = s.info
+ __spell_desc[i] = s.desc
+ return i
+end
+
+-- Creates the school books array
+__spell_spell = {}
+__spell_info = {}
+__spell_desc = {}
+__spell_school = {}
+school_book = {}
+
+-- Find a spell by name
+function find_spell(name)
+ local i
+
+ i = 0
+ while (i < __tmp_spells_num) do
+ if __tmp_spells[i].name == name then return i end
+ i = i + 1
+ end
+ return -1
+end
+
+-- Find if the school is under the influence of a god, returns nil or the level
+function get_god_level(sch)
+ if __schools[sch].gods[player.pgod] then
+ return (s_info[__schools[sch].gods[player.pgod].skill + 1].value * __schools[sch].gods[player.pgod].mul) / __schools[sch].gods[player.pgod].div
+ else
+ return nil
+ end
+end
+
+-- Change this fct if I want to switch to learnable spells
+function get_level_school(s, max, min)
+ local lvl, sch, index, num, bonus
+ local allow_spell_power = TRUE
+
+ lvl = 0
+ num = 0
+ bonus = 0
+
+ -- No max specified ? assume 50
+ if not max then
+ max = 50
+ end
+ if not min then
+ min = 1
+ end
+
+ -- Do we pass tests?
+ if __tmp_spells[s].depend then
+ if __tmp_spells[s].depend() ~= TRUE then
+ return min, "n/a"
+ end
+ end
+
+ for index, sch in __spell_school[s] do
+ local r, s, p, ok = 0, 0, 0, 0
+
+ -- Does it require we worship a specific god?
+ if __schools[sch].god then
+ if __schools[sch].god ~= player.pgod then
+ if min then return min, "n/a"
+ else return 1, "n/a" end
+ end
+ end
+
+ -- Take the basic skill value
+ r = s_info[(school(sch).skill) + 1].value
+
+ -- Do we pass tests?
+ if __schools[sch].depend then
+ if __schools[sch].depend() ~= TRUE then
+ return min, "n/a"
+ end
+ end
+
+ -- Are we under sorcery effect ?
+ if __schools[sch].sorcery then
+ s = s_info[SKILL_SORCERY + 1].value
+ end
+
+ -- Are we affected by spell power ?
+ -- All teh schools must allow it for it to work
+ if not __schools[sch].spell_power then
+ allow_spell_power = nil
+ end
+
+ -- Are we under a god effect ?
+ if __schools[sch].gods then
+ p = get_god_level(sch)
+ if not p then p = 0 end
+ end
+
+ -- Find the higher
+ ok = r
+ if ok < s then ok = s end
+ if ok < p then ok = p end
+
+ -- Do we need to add a special bonus ?
+ if __schools[sch].bonus_level then
+ bonus = bonus + (__schools[sch].bonus_level() * (SKILL_STEP / 10))
+ end
+
+ -- All schools must be non zero to be able to use it
+ if ok == 0 then return min, "n/a" end
+
+ -- Apply it
+ lvl = lvl + ok
+ num = num + 1
+ end
+
+ -- Add the Spellpower skill as a bonus
+ if allow_spell_power then
+ bonus = bonus + (get_skill_scale(SKILL_SPELL, 20) * (SKILL_STEP / 10))
+ end
+
+ -- Add bonus from objects
+ bonus = bonus + (player.to_s * (SKILL_STEP / 10))
+
+ -- / 10 because otherwise we can overflow a s32b and we can use a u32b because the value can be negative
+ -- The loss of information should be negligible since 1 skill = 1000 internally
+ lvl = (lvl / num) / 10
+ lvl = lua_get_level(s, lvl, max, min, bonus)
+
+ return lvl, nil
+end
+
+-- This is the function to use when casting through a stick
+function get_level_device(s, max, min)
+ local lvl
+
+ -- No max specified ? assume 50
+ if not max then
+ max = 50
+ end
+
+ lvl = s_info[SKILL_DEVICE + 1].value
+ lvl = lvl + (get_level_use_stick * SKILL_STEP)
+
+ -- Sticks are limited
+ if lvl - ((spell(s).skill_level + 1) * SKILL_STEP) >= get_level_max_stick * SKILL_STEP then
+ lvl = (get_level_max_stick + spell(s).skill_level - 1) * SKILL_STEP
+ end
+
+ -- / 10 because otherwise we can overflow a s32b and we can use a u32b because the value can be negative
+ -- The loss of information should be negligible since 1 skill = 1000 internally
+ lvl = lvl / 10
+ if not min then
+ lvl = lua_get_level(s, lvl, max, 1, 0)
+ else
+ lvl = lua_get_level(s, lvl, max, min, 0)
+ end
+
+ return lvl
+end
+
+-- The real get_level, works for schooled magic and for innate powers
+get_level_use_stick = -1
+get_level_max_stick = -1
+function get_level(s, max, min)
+ if type(s) == "number" then
+ -- Ahah shall we use Magic device instead ?
+ if get_level_use_stick > -1 then
+ return get_level_device(s, max, min)
+ else
+ local lvl, na = get_level_school(s, max, min)
+ return lvl
+ end
+ else
+ return get_level_power(s, max, min)
+ end
+end
+
+-- Can we cast the spell ?
+function is_ok_spell(s, obj)
+ if get_level(s, 50, 0) == 0 then return nil end
+ if __tmp_spells[s].pval and obj.pval < __tmp_spells[s].pval then return nil end
+ return 1
+end
+
+-- Get the amount of mana(or power) needed
+function get_mana(s)
+ return spell(s).mana + get_level(s, spell(s).mana_max - spell(s).mana, 0)
+end
+
+-- Return the amount of power(mana, piety, whatever) for the spell
+function get_power(s)
+ if check_affect(s, "piety", FALSE) then
+ return player.grace
+ else
+ return player.csp
+ end
+end
+
+-- Return the amount of power(mana, piety, whatever) for the spell
+function get_power_name(s)
+ if check_affect(s, "piety", FALSE) then
+ return "piety"
+ else
+ return "mana"
+ end
+end
+
+-- Get the level of a power
+function get_level_power(s, max, min)
+ if not max then max = 50 end
+ if not min then min = 1 end
+
+ return value_scale(s.get_current_level(), 50, max, min)
+end
+
+-- Changes the amount of power(mana, piety, whatever) for the spell
+function adjust_power(s, x)
+ if check_affect(s, "piety", FALSE) then
+ inc_piety(GOD_ALL, x)
+ else
+ increase_mana(x)
+ end
+end
+
+-- Get spell school name(s) as a /-separated string.
+function spell_school_name(s)
+ local xx, sch_str
+ xx = nil
+ sch_str = ""
+ for index, sch in __spell_school[s] do
+ if xx then
+ sch_str = sch_str.."/"..school(sch).name
+ else
+ xx = 1
+ sch_str = sch_str..school(sch).name
+ end
+ end
+ return sch_str
+end
+
+-- Print the book and the spells
+function print_book(book, spl, obj)
+ local x, y, index, sch, size, s
+
+ x = 0
+ y = 2
+ size = 0
+
+ -- Hack if the book is 255 it is a random book
+ if book == 255 then
+ school_book[book] = {spl}
+ end
+
+ -- Parse all spells
+ for index, s in school_book[book] do
+ local color = TERM_L_DARK
+ local lvl, na = get_level_school(s, 50, -50)
+ local xx, sch_str
+
+ if is_ok_spell(s, obj) then
+ if get_mana(s) > get_power(s) then color = TERM_ORANGE
+ else color = TERM_L_GREEN end
+ end
+
+ sch_str = spell_school_name(s)
+
+ if na then
+ c_prt(color, format("%c) %-20s%-16s %3s %4s %3d%s %s", size + strbyte("a"), spell(s).name, sch_str, na, get_mana(s), spell_chance(s), "%", __spell_info[s]()), y, x)
+ else
+ c_prt(color, format("%c) %-20s%-16s %3d %4s %3d%s %s", size + strbyte("a"), spell(s).name, sch_str, lvl, get_mana(s), spell_chance(s), "%", __spell_info[s]()), y, x)
+ end
+ y = y + 1
+ size = size + 1
+ end
+ prt(format(" %-20s%-16s Level Cost Fail Info", "Name", "School"), 1, x)
+ return y
+end
+
+-- Output the describtion when it is used as a spell
+function print_spell_desc(s, y)
+ local index, desc, x
+
+ x = 0
+
+ if type(__spell_desc[s]) == "string" then c_prt(TERM_L_BLUE, __spell_desc[s], y, x)
+ else
+ for index, desc in __spell_desc[s] do
+ c_prt(TERM_L_BLUE, desc, y, x)
+ y = y + 1
+ end
+ end
+ if check_affect(s, "piety", FALSE) then
+ c_prt(TERM_L_WHITE, "It uses piety to cast.", y, x)
+ y = y + 1
+ end
+ if not check_affect(s, "blind") then
+ c_prt(TERM_ORANGE, "It is castable even while blinded.", y, x)
+ y = y + 1
+ end
+ if not check_affect(s, "confusion") then
+ c_prt(TERM_ORANGE, "It is castable even while confused.", y, x)
+ y = y + 1
+ end
+end
+
+-- Output the desc when sued as a device
+function print_device_desc(s)
+ local index, desc
+
+ if type(__spell_desc[s]) == "string" then text_out(__spell_desc[s])
+ else
+ for index, desc in __spell_desc[s] do
+ text_out("\n" .. desc)
+ end
+ end
+end
+
+function book_spells_num(book)
+ local size, index, sch
+
+ size = 0
+
+ -- Hack if the book is 255 it is a random book
+ if book == 255 then
+ return 1
+ end
+
+ -- Parse all spells
+ for index, s in school_book[book] do
+ size = size + 1
+ end
+ return size
+end
+
+function spell_x(book, spl, s)
+ if book == 255 then
+ return spl
+ else
+ local i, x, val
+
+ i, val = next(school_book[book], nil)
+ x = 0
+ while x < s do
+ i, val = next(school_book[book], i)
+ x = x + 1
+ end
+ return val
+ end
+end
+
+function spell_in_book(book, spell)
+ local i, s
+
+ for i, s in school_book[book] do
+ if s == spell then return TRUE end
+ end
+ return FALSE
+end
+
+-- Returns spell chance of failure for spell
+function spell_chance(s)
+ local chance, s_ptr
+
+ s_ptr = spell(s)
+
+ -- Extract the base spell failure rate
+ if get_level_use_stick > -1 then
+ chance = lua_spell_device_chance(s_ptr.fail, get_level(s, 50), s_ptr.skill_level)
+ else
+ chance = lua_spell_chance(s_ptr.fail, get_level(s, 50), s_ptr.skill_level, get_mana(s), get_power(s), get_spell_stat(s))
+ end
+
+ -- Return the chance
+ return chance
+end
+
+function check_affect(s, name, default)
+ local s_ptr = __tmp_spells[s]
+ local a
+
+ if type(s_ptr[name]) == "number" then
+ a = s_ptr[name]
+ else
+ a = default
+ end
+ if a == FALSE then
+ return nil
+ else
+ return TRUE
+ end
+end
+
+-- Returns the stat to use for the spell, INT by default
+function get_spell_stat(s)
+ if not __tmp_spells[s].stat then return A_INT
+ else return __tmp_spells[s].stat end
+end
+
+function cast_school_spell(s, s_ptr, no_cost)
+ local use = FALSE
+
+ -- No magic
+ if (player.antimagic > 0) then
+ msg_print("Your anti-magic field disrupts any magic attempts.")
+ return
+ end
+
+ -- No magic
+ if (player.anti_magic == TRUE) then
+ msg_print("Your anti-magic shell disrupts any magic attempts.")
+ return
+ end
+
+ -- if it costs something then some condition must be met
+ if not no_cost then
+ -- Require lite
+ if (check_affect(s, "blind")) and ((player.blind > 0) or (no_lite() == TRUE)) then
+ msg_print("You cannot see!")
+ return
+ end
+
+ -- Not when confused
+ if (check_affect(s, "confusion")) and (player.confused > 0) then
+ msg_print("You are too confused!")
+ return
+ end
+
+ -- Enough mana
+ if (get_mana(s) > get_power(s)) then
+ if (get_check("You do not have enough "..get_power_name(s)..", do you want to try anyway?") == FALSE) then return end
+ end
+
+ -- Invoke the spell effect
+ if (magik(spell_chance(s)) == FALSE) then
+ if (__spell_spell[s]() ~= nil) then
+ use = TRUE
+ end
+ else
+ local index, sch
+
+ -- added because this is *extremely* important --pelpel
+ if (flush_failure) then flush() end
+
+ msg_print("You failed to get the spell off!")
+ for index, sch in __spell_school[s] do
+ if __schools[sch].fail then
+ __schools[sch].fail(spell_chance(s))
+ end
+ end
+ use = TRUE
+ end
+ else
+ __spell_spell[s]()
+ end
+
+ if use == TRUE then
+ -- Reduce mana
+ adjust_power(s, -get_mana(s))
+
+ -- Take a turn
+ if is_magestaff() == TRUE then energy_use = 80
+ else energy_use = 100 end
+ end
+
+ player.redraw = bor(player.redraw, PR_MANA)
+ player.window = bor(player.window, PW_PLAYER)
+end
+
+
+-- Can the spell be randomly found(in random books)
+function can_spell_random(i)
+ return __tmp_spells[i].random
+end
+
+-- Find a random spell
+function get_random_spell(typ, level)
+ local spl, tries
+
+ tries = 1000
+ while tries > 0 do
+ tries = tries - 1
+ spl = rand_int(__tmp_spells_num)
+ if (can_spell_random(spl) == typ) and (rand_int(spell(spl).skill_level * 3) < level) then
+ break
+ end
+ end
+ if tries > 0 then
+ return spl
+ else
+ return -1
+ end
+end
+
+-- Execute a lasting spell
+function exec_lasting_spell(spl)
+ assert(__tmp_spells[spl].lasting, "No lasting effect for spell "..__tmp_spells[spl].name.." but called as such")
+ return __tmp_spells[spl].lasting()
+end
+
+-- Helper function for spell effect to know if they are or not obvious
+function is_obvious(effect, old)
+ if old then
+ if old == TRUE or effect == TRUE then
+ return TRUE
+ else
+ return FALSE
+ end
+ else
+ return effect
+ end
+end
+
+-------------------------Sticks-------------------------
+
+-- Fire off the spell
+function activate_stick(spl)
+ local ret = __spell_spell[spl]()
+ local charge, obvious
+ if not ret then
+ charge = FALSE
+ obvious = FALSE
+ else
+ charge = TRUE
+ obvious = ret
+ end
+ return obvious, charge
+end
+
+----------------------------------- Wand, Staves, Rods specific functions ----------------------------
+
+-- Get a spell for a given stick(wand, staff, rod)
+function get_random_stick(stick, level)
+ local spl, tries
+
+ tries = 1000
+ while tries > 0 do
+ tries = tries - 1
+ spl = rand_int(__tmp_spells_num)
+ if __tmp_spells[spl].stick and (type(__tmp_spells[spl].stick[stick]) == "table") then
+ if (rand_int(spell(spl).skill_level * 3) < level) and (magik(100 - __tmp_spells[spl].stick[stick].rarity) == TRUE) then
+ break
+ end
+ end
+ end
+ if tries > 0 then
+ return spl
+ else
+ return -1
+ end
+end
+
+-- Get a random base level
+function get_stick_base_level(stick, level, spl)
+ -- Paranoia
+ if spl < 0 or spl >= __tmp_spells_num or not __tmp_spells[spl].stick[stick] then return 0 end
+
+ local min, max = __tmp_spells[spl].stick[stick].base_level[1], __tmp_spells[spl].stick[stick].base_level[2]
+ local range = max - min;
+
+ -- Ok the basic idea is to have a max possible level of half the dungeon level
+ if range * 2 > level then range = level / 2 end
+
+ -- Randomize a bit
+ range = m_bonus(range, dun_level)
+
+ -- And get the result
+ return min + range
+end
+
+-- Get a random max level
+function get_stick_max_level(stick, level, spl)
+ -- Paranoia
+ if spl < 0 or spl >= __tmp_spells_num or not __tmp_spells[spl].stick[stick] then return 0 end
+
+ local min, max = __tmp_spells[spl].stick[stick].max_level[1], __tmp_spells[spl].stick[stick].max_level[2]
+ local range = max - min;
+
+ -- Ok the basic idea is to have a max possible level of half the dungeon level
+ if range * 2 > level then range = level / 2 end
+
+ -- Randomize a bit
+ range = m_bonus(range, dun_level)
+
+ -- And get the result
+ return min + range
+end
+
+-- Get the number of desired charges
+function get_stick_charges(spl)
+ return __tmp_spells[spl].stick.charge[1] + randint(__tmp_spells[spl].stick.charge[2]);
+end
+
+-- Get activation desc
+function get_activation_desc(spl)
+ local turns
+ if type(__tmp_spells[spl].activate) == 'number' then
+ turns = __tmp_spells[spl].activate
+ else
+ turns = __tmp_spells[spl].activate[1] .. '+d' .. __tmp_spells[spl].activate[2]
+ end
+ return __tmp_spells[spl].desc[1] .. ' every ' .. turns .. ' turns'
+end
+
+-- Compute the timeout of an activation
+function get_activation_timeout(spl)
+ if type(__tmp_spells[spl].activate) == 'number' then
+ return __tmp_spells[spl].activate
+ else
+ return __tmp_spells[spl].activate[1] + randint(__tmp_spells[spl].activate[2])
+ end
+end
+
+-- Fire off the spell
+function activate_activation(spl, item)
+ __spell_spell[spl](item)
+end
+
+
+------- Add new GF type ----------
+max_gf = MAX_GF
+function add_spell_type(t)
+ t.index = max_gf
+ max_gf = max_gf + 1
+ assert(t.color, "No GF color")
+ if not t.monster then t.monster = function() end end
+ if not t.angry then t.angry = function() end end
+ if not t.object then t.object = function() end end
+ if not t.player then t.player = function() end end
+ if not t.grid then t.grid = function() end end
+
+ add_hooks
+ {
+ [HOOK_GF_COLOR] = function (gf, new_gfx)
+ local t = %t
+ if gf == t.index then return TRUE, t.color[new_gfx + 1] end
+ end,
+ [HOOK_GF_EXEC] = function (action, who, gf, dam, rad, y, x, extra)
+ local t = %t
+ if t.index == gf then
+ return t[action](who, dam, rad, y, x, extra)
+ end
+ end,
+ }
+ return t.index
+end
diff --git a/lib/mods/theme/core/stores.lua b/lib/mods/theme/core/stores.lua
new file mode 100644
index 00000000..d4a63168
--- /dev/null
+++ b/lib/mods/theme/core/stores.lua
@@ -0,0 +1,32 @@
+-- Take care of all concerning stores
+function store_buy_list(t)
+ assert(type(t) == "table", "store_buy_list got no table")
+ add_hooks
+ {
+ [HOOK_STORE_BUY] = function (index, name, obj)
+ local tbl = %t
+ local elt = tbl[index]
+ if not elt then
+ elt = tbl[name]
+ end
+ if elt then
+ if elt then
+ if type(elt) == "function" then
+ return TRUE, elt(obj)
+ elseif type(elt) == "table" then
+ local k, e
+ for k, e in elt do
+ if type(e) == "number" then
+ if obj.tval == e then return TRUE, TRUE end
+ else
+ if (obj.tval == e[1]) and (obj.sval >= e[2]) and (obj.sval <= e[3]) then return TRUE, TRUE end
+ end
+ end
+ elseif elt == -1 then
+ return TRUE, FALSE
+ end
+ end
+ end
+ end,
+ }
+end
diff --git a/lib/mods/theme/core/util.lua b/lib/mods/theme/core/util.lua
new file mode 100644
index 00000000..eea13014
--- /dev/null
+++ b/lib/mods/theme/core/util.lua
@@ -0,0 +1,158 @@
+-- various stuff to make scripters life easier
+
+-- Beware of the scary undefined globals
+function safe_getglobal(x)
+ local v = rawget(globals(), x)
+
+ if v then
+ return v
+ else
+ error("undefined global variable '"..x.."'")
+ end
+end
+
+function set_safe_globals()
+ settagmethod(tag(nil), "getglobal", safe_getglobal)
+end
+function unset_safe_globals()
+ settagmethod(tag(nil), "getglobal", nil)
+end
+
+set_safe_globals()
+
+-- Patch modules
+__patch_modules = {}
+
+function patch_version(name, version)
+ assert(not __patch_modules[name], "Patch " .. name .. " already loaded!!!")
+ __patch_modules[name] = version
+end
+
+function patchs_list()
+ local k, e, first
+ first = FALSE
+ for k, e in __patch_modules do
+ if first == FALSE then print_hook("\n\n [Patch modules]\n") first = TRUE end
+ print_hook("\n "..k.." version "..e)
+ end
+ if first == TRUE then print_hook("\n") end
+end
+
+function patchs_display()
+ local k, e
+ for k, e in __patch_modules do
+ msg_print("Patch: "..k.." version "..e)
+ end
+end
+
+
+-- Better hook interface
+__hooks_list_callback = {}
+__hooks_list_callback_max = 0
+
+function add_hooks(h_table, name_prefix)
+ local k, e
+
+ if not name_prefix then name_prefix = "" end
+ for k, e in h_table do
+ add_hook_script(k, "__"..name_prefix.."__hooks_list_callback"..__hooks_list_callback_max, "__"..name_prefix.."__hooks_list_callback"..__hooks_list_callback_max)
+ setglobal("__"..name_prefix.."__hooks_list_callback"..__hooks_list_callback_max, e)
+ __hooks_list_callback_max = __hooks_list_callback_max + 1
+ end
+end
+
+-- Wrapper for the real msg_print and cmsg_print
+-- it understands if we want color or not
+function msg_print(c, m)
+ if type(c) == "number" then
+ cmsg_print(c, m)
+ else
+ call(%msg_print, { c })
+ end
+end
+
+-- better timer add function
+__timers_callback_max = 0
+
+function new_timer(t)
+ assert(t.delay > 0, "no timer delay")
+ assert(t.enabled, "no timer enabled state")
+ assert(t.callback, "no timer callback")
+
+ local timer
+ if type(t.callback) == "function" then
+ setglobal("__timers_callback_"..__timers_callback_max, t.callback)
+ timer = %new_timer("__timers_callback_"..__timers_callback_max, t.delay)
+ __timers_callback_max = __timers_callback_max + 1
+ else
+ timer = %new_timer(t.callback, t.delay)
+ end
+
+ timer.enabled = t.enabled
+
+ return timer
+end
+
+-- saves all timer values
+function save_timer(name)
+ add_loadsave(name..".enabled", FALSE)
+ add_loadsave(name..".delay", 1)
+ add_loadsave(name..".countdown", 1)
+end
+
+
+-- displays a scrolling list
+function display_list(y, x, h, w, title, list, begin, sel, sel_color)
+ local l = create_list(getn(list))
+
+ for i = 1, getn(list) do
+ add_to_list(l, i - 1, list[i])
+ end
+
+ %display_list(y, x, h, w, title, l, getn(list), begin - 1, sel - 1, sel_color)
+
+ delete_list(l, getn(list))
+end
+
+-- Easier access to special gene stuff
+function set_monster_generation(monster, state)
+ if type(monster) == "string" then
+ m_allow_special[test_monster_name(monster) + 1] = state
+ else
+ m_allow_special[monster + 1] = state
+ end
+end
+function set_object_generation(obj, state)
+ if type(obj) == "string" then
+ m_allow_special[test_item_name(obj) + 1] = state
+ else
+ m_allow_special[obj + 1] = state
+ end
+end
+function set_artifact_generation(obj, state)
+ m_allow_special[obj + 1] = state
+end
+
+-- Strings
+function strcap(str)
+ if strlen(str) > 1 then
+ return strupper(strsub(str, 1, 1))..strsub(str, 2)
+ elseif strlen(str) == 1 then
+ return strupper(str)
+ else
+ return str
+ end
+end
+
+function msg_format(...)
+ msg_print(call(format, arg))
+end
+
+-- A way to check if the game is now running(as opposed to initialization/character gen)
+game = {}
+add_hooks
+{
+ [HOOK_GAME_START] = function ()
+ game.started = TRUE
+ end
+}
diff --git a/lib/mods/theme/core/xml.lua b/lib/mods/theme/core/xml.lua
new file mode 100644
index 00000000..14f0511f
--- /dev/null
+++ b/lib/mods/theme/core/xml.lua
@@ -0,0 +1,375 @@
+-- The xml module
+xml = {}
+
+function xml:parseargs (s)
+ local arg = {}
+ gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a)
+ %arg[w] = a
+ end)
+ return arg
+end
+
+-- s is a xml stream, returns a table
+function xml:collect (s)
+ local stack = {n=0}
+ local top = {n=0}
+ tinsert(stack, top)
+ local ni,c,label,args, empty
+ local i, j = 1, 1
+ while 1 do
+ ni,j,c,label,args, empty = strfind(s, "<(%/?)(%w+)(.-)(%/?)>", j)
+ if not ni then break end
+ local text = strsub(s, i, ni-1)
+ if not strfind(text, "^%s*$") then
+ tinsert(top, text)
+ end
+ if empty == "/" then -- empty element tag
+ tinsert(top, {n=0, label=label, args=xml:parseargs(args), empty=1})
+ elseif c == "" then -- start tag
+ top = {n=0, label=label, args=xml:parseargs(args)}
+ tinsert(stack, top) -- new level
+ else -- end tag
+ local toclose = tremove(stack) -- remove top
+ top = stack[stack.n]
+ if stack.n < 1 then
+ error("nothing to close with "..label)
+ end
+ if toclose.label ~= label then
+ error("trying to close "..toclose.label.." with "..label)
+ end
+ tinsert(top, toclose)
+ end
+ i = j+1
+ end
+ local text = strsub(s, i)
+ if not strfind(text, "^%s*$") then
+ tinsert(stack[stack.n], text)
+ end
+ if stack.n > 1 then
+ error("unclosed "..stack[stack.n].label)
+ end
+ return stack[1]
+end
+
+-- Viewport coordinates
+xml.write_out_y = 0
+xml.write_out_x = 0
+xml.write_out_h = 24
+xml.write_out_w = 80
+
+-- Offsets
+xml.write_off_y = 0
+xml.write_off_x = 0
+
+-- Current position
+xml.write_y = 0
+xml.write_x = 0
+
+xml.write_screen = function(color, s)
+ local i
+ for i = 1, strlen(s) do
+ local c = strsub(s, i, i + 1)
+ if c ~= "\n" then
+ if xml.write_y - xml.write_off_y >= 0 and xml.write_y - xml.write_off_y < xml.write_out_h and xml.write_x - xml.write_off_x >= 0 and xml.write_x - xml.write_off_x < xml.write_out_w then
+ Term_putch(xml.write_x - xml.write_off_x + xml.write_out_x, xml.write_y - xml.write_off_y + xml.write_out_y, color, strbyte(c))
+ end
+ xml.write_x = xml.write_x + 1
+ else
+ xml.write_x = 0
+ xml.write_y = xml.write_y + 1
+ end
+ end
+end
+
+xml.write_file = function (color, s)
+ print_hook(s)
+end
+
+xml.write = xml.write_screen
+
+xml.rule2string = {
+ ['name'] = {"Its ", "name", " is"},
+ ['contain'] = {"Its ", "name", " contains"},
+ ['symbol'] = {"Its ", "symbol", " is"},
+ ['inscribed'] = {"Its ", "inscription", " contains"},
+ ['state'] = {"Its ", "state", " is"},
+ ['status'] = {"Its ", "status", " is"},
+ ['tval'] = {"Its ", "tval", " is"},
+ ['race'] = {"Your ", "race", " is"},
+ ['subrace'] = {"Your ", "subrace", " is"},
+ ['class'] = {"Your ", "class", " is"},
+ ['foo1'] = {"The result of ", "test 1 ", "is"},
+ ['foo2'] = {"The result of ", "test 2 ", "is"},
+ ['foo3'] = {"The result of ", "test 3 ", "is"},
+}
+
+xml.display_english = 1
+function xml:display_xml(t, tab)
+ if xml.display_english then
+ xml:english_xml(t, tab)
+ else
+ xml:print_xml(t, tab)
+ end
+end
+
+function xml:english_xml(t, tab, not_flag)
+ local i, k, e
+ local pre, post, recurse
+ local children_not_flag
+ local nextlevel
+ local bcol, ecol = TERM_L_GREEN, TERM_GREEN
+
+ if xml.write_active and t == auto_aux.rule then bcol, ecol = TERM_VIOLET, TERM_VIOLET end
+
+ nextlevel = tab .. " "
+
+ recurse = 1
+
+ if t.label == "rule" then
+ if t.args.type == "inscribe" then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "A rule named \"")
+ xml.write(TERM_WHITE, tostring(t.args.name))
+ xml.write(ecol, "\" to ")
+ xml.write(bcol, "inscribe")
+ xml.write(ecol, " an item with \"")
+ xml.write(TERM_WHITE, t.args.inscription)
+ xml.write(ecol, "\" when")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "A rule named \"")
+ xml.write(TERM_WHITE, tostring(t.args.name))
+ xml.write(ecol, "\" to ")
+ xml.write(bcol, t.args.type)
+ xml.write(ecol, " when")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "and" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "At least one of the following is false:")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "All of the following are true:")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "or" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "All of the following are false:")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "At least one of the following are true:")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "not" then
+ if bcol == TERM_VIOLET or getn(t) == 0 then
+ xml.write(ecol, "(a negating rule)")
+ xml.write(TERM_WHITE, "\n")
+ else
+ nextlevel = tab
+ end
+ children_not_flag = not nil
+ elseif t.label == "inventory" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Nothing in your ")
+ xml.write(bcol, "inventory")
+ xml.write(ecol, " matches the following:")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Something in your ")
+ xml.write(bcol, "inventory")
+ xml.write(ecol, " matches the following:")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "equipment" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Nothing in your ")
+ xml.write(bcol, "equipment")
+ xml.write(ecol, " matches the following:")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Something in your ")
+ xml.write(bcol, "equipment")
+ xml.write(ecol, " matches the following:")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "comment" then
+ xml.write(TERM_WHITE, tab)
+ xml.write(TERM_WHITE, "(" .. t[1] .. ")")
+ xml.write(TERM_WHITE, "\n")
+ elseif t.label == "skill" then
+ local s = t[1]
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Your skill in ")
+ xml.write(bcol, s)
+ xml.write(ecol, " is not from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Your skill in ")
+ xml.write(bcol, s)
+ xml.write(ecol, " is from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "ability" then
+ local s = t[1]
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "You do not have the ")
+ xml.write(bcol, s)
+ xml.write(ecol, " ability")
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "You have the ")
+ xml.write(bcol, s)
+ xml.write(ecol, " ability")
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "level" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Your ")
+ xml.write(bcol, "level")
+ xml.write(ecol, " is not from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Your ")
+ xml.write(bcol, "level")
+ xml.write(ecol, " is from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "sval" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Its ")
+ xml.write(bcol, "sval")
+ xml.write(ecol, " is not from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Its ")
+ xml.write(bcol, "sval")
+ xml.write(ecol, " is from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ end
+ elseif t.label == "discount" then
+ if not_flag then
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Its ")
+ xml.write(bcol, "discount")
+ xml.write(ecol, " is not from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ else
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, "Its ")
+ xml.write(bcol, "discount")
+ xml.write(ecol, " is from ")
+ xml.write(TERM_WHITE, tostring(t.args.min))
+ xml.write(ecol, " to ")
+ xml.write(TERM_WHITE, tostring(t.args.max))
+ xml.write(TERM_WHITE, "\n")
+ end
+ else
+ if xml.rule2string[t.label] then
+ local rule = xml.rule2string[t.label]
+ a, b, c = rule[1], rule[2], rule[3]
+ if not_flag then c = c .. " not" end
+ xml.write(TERM_WHITE, tab)
+ xml.write(ecol, a)
+ xml.write(bcol, b)
+ xml.write(ecol, c)
+ xml.write(ecol, " \"")
+ xml.write(TERM_WHITE, t[1])
+ xml.write(ecol, "\"")
+ xml.write(TERM_WHITE, "\n")
+ else
+ if not_flag then
+ xml.write(bcol, "Not:\n")
+ tab = tab .. " "
+ xml:print_xml(t, tab)
+ return
+ end
+ end
+ end
+
+ for i = 1, getn(t) do
+ if type(t[i]) == "string" then
+ -- xml.write(TERM_WHITE, t[i].."\n")
+ else
+ xml:english_xml(t[i], nextlevel, children_not_flag)
+ end
+ end
+end
+
+function xml:print_xml(t, tab)
+ local i, k, e
+ local inside = nil
+ local bcol, ecol = TERM_L_GREEN, TERM_GREEN
+
+ if xml.write_active and t == auto_aux.rule then bcol, ecol = TERM_VIOLET, TERM_VIOLET end
+
+ xml.write(bcol, tab.."<"..t.label)
+ for k, e in t.args do
+ xml.write(TERM_L_BLUE, " "..k)
+ xml.write(TERM_WHITE, "=\"")
+ xml.write(TERM_YELLOW, e)
+ xml.write(TERM_WHITE, "\"")
+ end
+ xml.write(bcol, ">")
+
+ for i = 1, getn(t) do
+ if type(t[i]) == "string" then
+ xml.write(TERM_WHITE, t[i])
+ else
+ if not inside then xml.write(TERM_WHITE, "\n") end
+ inside = not nil
+ xml:print_xml(t[i], tab.." ")
+ end
+ end
+
+ if not inside then
+ xml.write(ecol, "</"..t.label..">\n")
+ else
+ xml.write(ecol, tab.."</"..t.label..">\n")
+ end
+end
+
+-- t is a table representing xml, outputs the xml code via xml.write()
+function xml:output(t)
+ local i
+ for i = 1, getn(t) do
+ xml:print_xml(t[i], "")
+ end
+end
diff --git a/lib/mods/theme/data/delete.me b/lib/mods/theme/data/delete.me
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/lib/mods/theme/data/delete.me
diff --git a/lib/mods/theme/dngn/dun1.14 b/lib/mods/theme/dngn/dun1.14
new file mode 100644
index 00000000..6421e80b
--- /dev/null
+++ b/lib/mods/theme/dngn/dun1.14
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to the Heart of the Earth
+B:10
diff --git a/lib/mods/theme/dngn/dun1.22 b/lib/mods/theme/dngn/dun1.22
new file mode 100644
index 00000000..cbf78046
--- /dev/null
+++ b/lib/mods/theme/dngn/dun1.22
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to a trail left by a purposeful dwarf
+B:40 \ No newline at end of file
diff --git a/lib/mods/theme/dngn/dun10.0 b/lib/mods/theme/dngn/dun10.0
new file mode 100644
index 00000000..b89ce05e
--- /dev/null
+++ b/lib/mods/theme/dngn/dun10.0
@@ -0,0 +1,3 @@
+# Father branch is Mirkwood(1), on level 14
+A:1
+L:14
diff --git a/lib/mods/theme/dngn/dun11.20 b/lib/mods/theme/dngn/dun11.20
new file mode 100644
index 00000000..9cc611d3
--- /dev/null
+++ b/lib/mods/theme/dngn/dun11.20
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to the Nether Realm
+B:6
diff --git a/lib/mods/theme/dngn/dun11.22 b/lib/mods/theme/dngn/dun11.22
new file mode 100644
index 00000000..149e2c33
--- /dev/null
+++ b/lib/mods/theme/dngn/dun11.22
@@ -0,0 +1,2 @@
+#I'm downright evil
+F:NO_GENO |
diff --git a/lib/mods/theme/dngn/dun17.15 b/lib/mods/theme/dngn/dun17.15
new file mode 100644
index 00000000..d08bf5e7
--- /dev/null
+++ b/lib/mods/theme/dngn/dun17.15
@@ -0,0 +1,5 @@
+N:Machine
+U:s_factory.map
+D:The clatter of strange machinery surrounds you.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/mods/theme/dngn/dun18.0 b/lib/mods/theme/dngn/dun18.0
new file mode 100644
index 00000000..da1b6c27
--- /dev/null
+++ b/lib/mods/theme/dngn/dun18.0
@@ -0,0 +1,2 @@
+# The level is SAVED in the playername.mz? file
+#S:mz0
diff --git a/lib/mods/theme/dngn/dun18.1 b/lib/mods/theme/dngn/dun18.1
new file mode 100644
index 00000000..70f27718
--- /dev/null
+++ b/lib/mods/theme/dngn/dun18.1
@@ -0,0 +1,2 @@
+# The level is SAVED in the playername.mz? file
+#S:mz1
diff --git a/lib/mods/theme/dngn/dun19.11 b/lib/mods/theme/dngn/dun19.11
new file mode 100644
index 00000000..7fba690d
--- /dev/null
+++ b/lib/mods/theme/dngn/dun19.11
@@ -0,0 +1,5 @@
+N:Deathwatch
+U:s_death.map
+D:This level looks filled with evilness.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/mods/theme/dngn/dun2.31 b/lib/mods/theme/dngn/dun2.31
new file mode 100644
index 00000000..dd8669a5
--- /dev/null
+++ b/lib/mods/theme/dngn/dun2.31
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to the Mount Doom
+B:5
diff --git a/lib/mods/theme/dngn/dun20.1 b/lib/mods/theme/dngn/dun20.1
new file mode 100644
index 00000000..61bc6a65
--- /dev/null
+++ b/lib/mods/theme/dngn/dun20.1
@@ -0,0 +1,5 @@
+U:s_smaug.map
+N:Lower Halls
+D:You can just make out a malevolent red glow at the end of the corridor.
+F:DESC
+F:NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR | ASK_LEAVE \ No newline at end of file
diff --git a/lib/mods/theme/dngn/dun22.10 b/lib/mods/theme/dngn/dun22.10
new file mode 100644
index 00000000..e7eb116e
--- /dev/null
+++ b/lib/mods/theme/dngn/dun22.10
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to the Small Water Cave
+B:24
diff --git a/lib/mods/theme/dngn/dun22.20 b/lib/mods/theme/dngn/dun22.20
new file mode 100644
index 00000000..a04a2788
--- /dev/null
+++ b/lib/mods/theme/dngn/dun22.20
@@ -0,0 +1,5 @@
+N:The Bridge
+U:s_bridge.map
+D:You hear the beating of drums in the Deep.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT \ No newline at end of file
diff --git a/lib/mods/theme/dngn/dun22.5 b/lib/mods/theme/dngn/dun22.5
new file mode 100644
index 00000000..11d8e51f
--- /dev/null
+++ b/lib/mods/theme/dngn/dun22.5
@@ -0,0 +1,5 @@
+N:Orc Town
+U:s_orc.map
+D:You hear orc warcries.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/mods/theme/dngn/dun24.0 b/lib/mods/theme/dngn/dun24.0
new file mode 100644
index 00000000..bbb93f85
--- /dev/null
+++ b/lib/mods/theme/dngn/dun24.0
@@ -0,0 +1,3 @@
+# Father branch is the Moria(22), on level 10
+A:22
+L:10
diff --git a/lib/mods/theme/dngn/dun29.15 b/lib/mods/theme/dngn/dun29.15
new file mode 100644
index 00000000..4df873b5
--- /dev/null
+++ b/lib/mods/theme/dngn/dun29.15
@@ -0,0 +1,6 @@
+N:Galleon
+U:s_ship.map
+D:A ship of antique design lies jammed in the ice here.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
+
diff --git a/lib/mods/theme/dngn/dun3.18 b/lib/mods/theme/dngn/dun3.18
new file mode 100644
index 00000000..84c0a74a
--- /dev/null
+++ b/lib/mods/theme/dngn/dun3.18
@@ -0,0 +1,5 @@
+N:Dim Gates
+U:s_gates.map
+D:Visions of death fill your mind.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/mods/theme/dngn/dun3.28 b/lib/mods/theme/dngn/dun3.28
new file mode 100644
index 00000000..0acd4193
--- /dev/null
+++ b/lib/mods/theme/dngn/dun3.28
@@ -0,0 +1,5 @@
+N:Nameless
+U:s_name.map
+D:You sense a powerful artifact here.
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/mods/theme/dngn/dun3.3 b/lib/mods/theme/dngn/dun3.3
new file mode 100644
index 00000000..710ef5f8
--- /dev/null
+++ b/lib/mods/theme/dngn/dun3.3
@@ -0,0 +1,5 @@
+N:Crypt
+U:s_crypt.map
+D:Looks like a forgotten crypt...
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT
diff --git a/lib/mods/theme/dngn/dun36.5 b/lib/mods/theme/dngn/dun36.5
new file mode 100644
index 00000000..9fddd4dd
--- /dev/null
+++ b/lib/mods/theme/dngn/dun36.5
@@ -0,0 +1,5 @@
+N:Orthanc
+U:s_orthanc.map
+D:#BAnd here you shall stay, foolish adventurer, and die quickly. For I am Saruman the Wise, Saruman the Ring-maker, Saruman of Many Colours!#w
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT \ No newline at end of file
diff --git a/lib/mods/theme/dngn/dun39.0 b/lib/mods/theme/dngn/dun39.0
new file mode 100644
index 00000000..57fa485e
--- /dev/null
+++ b/lib/mods/theme/dngn/dun39.0
@@ -0,0 +1,9 @@
+# Father branch is Barrow-Downs(4), on level 10
+A:4
+L:9
+
+N:Bilbo's trail
+U:s_bilbo.map
+D:#yYou hear someone shout, "I am in a frightful hurry, but Gandalf told me to leave this map for you! Find it, then seek Thorin in Mirkwood!"#w
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT \ No newline at end of file
diff --git a/lib/mods/theme/dngn/dun4.9 b/lib/mods/theme/dngn/dun4.9
new file mode 100644
index 00000000..e09273d6
--- /dev/null
+++ b/lib/mods/theme/dngn/dun4.9
@@ -0,0 +1,2 @@
+# On this level there is a stairway leading to a trail left by a fleeing hobbit
+B:39 \ No newline at end of file
diff --git a/lib/mods/theme/dngn/dun40.0 b/lib/mods/theme/dngn/dun40.0
new file mode 100644
index 00000000..0cd769c4
--- /dev/null
+++ b/lib/mods/theme/dngn/dun40.0
@@ -0,0 +1,9 @@
+# Father branch is Mirkwood(1), on level 33
+A:1
+L:22
+
+N:Thorin's trail
+U:s_thorin.map
+D:#yYou hear someone shout, "My mad kinsmen have taken the key to the Lonely Mountain! Get the key, then find that fool hobbit and my map! If you haven't already."#w
+F:DESC | NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:ASK_LEAVE | NO_TELEPORT \ No newline at end of file
diff --git a/lib/mods/theme/dngn/dun5.0 b/lib/mods/theme/dngn/dun5.0
new file mode 100644
index 00000000..48a7bea6
--- /dev/null
+++ b/lib/mods/theme/dngn/dun5.0
@@ -0,0 +1,3 @@
+# Father branch is the Mordor, on level 32
+A:2
+L:31
diff --git a/lib/mods/theme/dngn/dun5.14 b/lib/mods/theme/dngn/dun5.14
new file mode 100644
index 00000000..3d7a3080
--- /dev/null
+++ b/lib/mods/theme/dngn/dun5.14
@@ -0,0 +1,14 @@
+# The level is SAVED in the playername.mdm file
+S:mdm
+
+# Use the map in s_doom.map file
+U:s_doom.map
+
+# Use Mt Doom as level name
+N:Mt Doom
+
+D:You finally reach the top of Mount Doom, here must lie the Great Fire.
+F:DESC
+F:NO_GENO | NO_NEW_MONSTER | SPECIAL | NO_STAIR
+F:NO_TELEPORT
+
diff --git a/lib/mods/theme/dngn/dun6.0 b/lib/mods/theme/dngn/dun6.0
new file mode 100644
index 00000000..c750ea67
--- /dev/null
+++ b/lib/mods/theme/dngn/dun6.0
@@ -0,0 +1,3 @@
+# Father branch is Void(11), on level 20
+A:11
+L:20
diff --git a/lib/mods/theme/edit/a_info.txt b/lib/mods/theme/edit/a_info.txt
new file mode 100644
index 00000000..e2a312c5
--- /dev/null
+++ b/lib/mods/theme/edit/a_info.txt
@@ -0,0 +1,3359 @@
+# File: a_info.txt
+
+
+# This file is used to initialize the "lib/raw/a_info.raw" file, which is
+# used to initialize the "artifact" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/a_info.raw" file.
+
+
+# The artifact indexes are defined in "defines.h", and must not be changed.
+
+# Artifacts 1-15 are "special", 16-63 are "armor", and 64-127 are "weapons".
+
+# Hack -- "Grond" and "Morgoth" MUST have a rarity of one, or they might
+# not be dropped when Morgoth is killed. Note that they, like the "special"
+# artifacts, are never created "accidentally".
+
+# Artifacts now have descriptions. Special thanks to J.R.R Tolkien,
+# without whom the words would be unwritten, the images unconceived,
+# the deed undone.
+# -Leon Marrick
+# Contributors: Jeff Butler, Neal Hackler, Ethan Sicotte, Pat Tracy, Divia
+# The 'Theme' module for ToME introduces many changes into this file; please
+# refer to changes.txt in the module root folder for details.
+
+# Version stamp (required)
+
+V:2.0.0
+
+
+
+# The Phial of Galadriel
+
+N:1:of Galadriel
+I:39:100:4
+W:20:10:10:10000
+P:0:1d1:0:0:0
+F:ACTIVATE | SEARCH | LITE3 | LUCK
+F:INSTA_ART | HIDE_TYPE
+a:HARDCORE=LIGHT
+D:A small crystal phial, with the light of Earendil's Star contained inside.
+D:Its light is imperishable, and near it darkness cannot endure.
+
+
+# The Star of Elendil
+
+N:2:of Elendil
+I:39:101:1
+W:30:25:5:32500
+P:0:1d1:0:0:0
+F:ACTIVATE | SEE_INVIS | HOLD_LIFE |
+F:INSTA_ART | SPEED | LITE3 | LITE1 | HIDE_TYPE
+a:HARDCORE=MAP_LIGHT
+Z:detect curses
+D:The shining Star of the West, a famed heirloom of Elendil's house.
+D:A white diamond set as a star in a silver fillet to be bound at the
+D:forehead.
+
+# The Arkenstone of Thrain
+# Was +2 WIS/DEX
+
+N:3:of Thrain
+I:39:102:3
+W:50:50:5:50000
+P:0:1d1:0:0:0
+F:ACTIVATE | SEE_INVIS | HOLD_LIFE | RES_CHAOS | HIDE_TYPE | LUCK
+F:INSTA_ART | SPEED | RES_LITE | RES_DARK | ESP_ORC | LITE3 | SPECIAL_GENE
+a:HARDCORE=THRAIN
+D:A great globe seemingly filled with moonlight, the famed Heart of the
+D:Mountain, which splinters the light that falls upon it into a thousand
+D:glowing shards.
+
+# The Amulet of Annatar (replaces Carlammas in Theme)
+
+N:4:of Annatar
+I:40:10:10
+W:70:30:3:90000
+F:HIDE_TYPE | MANA | LIFE | SPELL | DRAIN_EXP | AGGRAVATE
+F:INSTA_ART
+D:This fiery golden circle once belonged to one who was known to the elves
+D:of Eregion as 'The Lord of Gifts'. Treacherous were his gifts, as was his
+D:teaching. Sauron the Sorcerer lurked behind the guise and his gifts, like
+D:this necklace, were not without cost.
+
+# The Amulet of Ingwe
+
+N:5:of Ingwe
+I:40:11:3
+W:65:30:3:90000
+F:INT | WIS | CHR | SEARCH | INFRA | HIDE_TYPE |
+F:SEE_INVIS | FREE_ACT | ACTIVATE |
+F:RES_ACID | RES_COLD | RES_ELEC |
+F:INSTA_ART
+a:HARDCORE=DISP_EVIL
+D:The ancient heirloom of Ingwe, high lord of the Vanyar, against whom nothing
+D:of evil could stand.
+
+
+# The Necklace 'Nauglamir'
+# Inherits Flare's old activation, since Flare is gone in Theme.
+
+N:6:'Nauglamir'
+I:40:12:3
+W:70:50:3:75000
+F:STR | CON | DEX | INFRA | HIDE_TYPE | RES_FEAR |
+F:SEE_INVIS | FREE_ACT | REGEN | LITE3 | SPEED |
+F:INSTA_ART | SPECIAL_GENE
+a:HARDCORE=DIM_DOOR
+D:A carencet of gold, set with a multitude of shining gems of
+D:Valinor. Despite its size, its weight seems as that of gossamer.
+
+# The Shadow Blade 'Ancanaur' - adapted from Annals of Ea
+
+
+N:7:'Ancanaur'
+I:23:32:3
+W:80:120:45:5000000
+P:0:12d12:10:10:0
+F:CHR | CON | DEX | DRAIN_EXP | FREE_ACT | HEAVY_CURSE | HIDE_TYPE | HOLD_LIFE | IM_FIRE | INT | KILL_DEMON | LEVELS | LITE1 | REGEN | RES_DARK | RES_FEAR | RES_NETHER | RES_NEXUS | SEE_INVIS | SHOW_MODS | SLAY_EVIL | SLAY_UNDEAD | SPEED | STR | WIS
+Z:mind blast
+D:"The Jaws of Fire", this is the sword that Feanor forged in secret
+D:to do battle against his enemies. The sword which threatened Fingolfin,
+D:the sword which in the end did not prevent its owner's untimely death.
+
+# The Ring of Barahir
+
+N:8:of Barahir
+I:45:32:1
+W:50:25:2:75000
+F:STR | INT | WIS | DEX | CON | CHR | STEALTH | HIDE_TYPE |
+F:RES_POIS | RES_DARK | ACTIVATE | SEE_INVIS | SEARCH |
+F:INSTA_ART
+a:HARDCORE=BARAHIR
+D:A ring shaped into twinned serpents with eyes of emerald meeting beneath
+D:a crown of flowers, an ancient treasure of Isildur's house.
+
+# The Slaughter Axe 'Dramborleg' - Tuor's axe
+# Replaces the Ring of Tulkas in Theme
+# Inherits the activation.
+
+N:9:'Dramborleg'
+I:24:30:5
+W:90:60:300:500000
+P:0:5d7:18:25:0
+F:CRIT | HIDE_TYPE | KILL_DEMON | SHOW_MODS | VORPAL | WOUNDING | ACTIVATE
+a:HARDCORE=TULKAS
+D:The great axe of Tuor, Thudder-Sharp is its name. The axe that smote
+D:both a heavy dint as of a club and cleft as a sword. When it was swung
+D:by the hands of Tuor, it sang like the rush of eagle's wings in the
+D:air and took death as it fell. Its name alone instills fear in Balrogs
+D:and other corruptions of Morgoth.
+
+# The Ring of Power 'Narya'
+
+N:10:of Power 'Narya'
+I:45:34:1
+W:70:30:2:100000
+P:0:1d1:6:6:0
+F:STR | INT | WIS | DEX | CON | CHR | SPEED | HIDE_TYPE | LUCK
+F:ACTIVATE | FREE_ACT | SEE_INVIS |
+F:SUST_STR | SUST_CON | SUST_WIS | SUST_CHR | SPECIAL_GENE |
+F:IM_FIRE | RES_NETHER | RES_FEAR | REGEN |
+F:INSTA_ART
+a:HARDCORE=NARYA
+D:The Ring of Fire, set with a ruby that glows like flame. Narya is one
+D:of the three Rings of Power created by the Elves and hidden by them from
+D:Sauron.
+
+
+# The Ring of Power 'Nenya'
+
+N:11:of Power 'Nenya'
+I:45:35:2
+W:80:40:2:200000
+P:0:1d1:9:9:0
+F:STR | INT | WIS | DEX | CON | CHR | SPEED | HIDE_TYPE | LUCK
+F:ACTIVATE | HOLD_LIFE | FREE_ACT | SEE_INVIS |
+F:SUST_INT | SUST_WIS | SUST_CHR |
+F:IM_COLD | RES_BLIND | STEALTH | ESP_ALL |
+F:INSTA_ART
+a:HARDCORE=NENYA
+D:The Ring of Adamant, with a pure white stone as centrepiece. Nenya is one
+D:of the three Rings of Power created by the Elves and hidden by them from
+D:Sauron.
+
+
+# The Ring of Power 'Vilya'
+
+N:12:of Power 'Vilya'
+I:45:36:3
+W:90:50:2:300000
+P:0:1d1:12:12:0
+F:STR | INT | WIS | DEX | CON | CHR | SPEED | HIDE_TYPE | LUCK
+F:ACTIVATE | HOLD_LIFE | FREE_ACT | SEE_INVIS |
+F:FEATHER | SLOW_DIGEST | REGEN |
+F:SUST_STR | SUST_DEX | SUST_CON |
+F:IM_ELEC | RES_POIS | RES_DISEN |
+F:INSTA_ART
+a:HARDCORE=VILYA
+D:The Ring of Sapphire, with clear blue gems that shine like stars,
+D:glittering untouchable despite all that Sauron ever wrought. Vilya is
+D:one of the three Rings of Power created by the Elves and hidden by them
+D:from Sauron.
+
+
+# The Ring of Power 'The One Ring'
+
+N:13:of Power 'The One Ring'
+I:45:37:5
+W:100:100:2:5000000
+P:0:1d1:15:15:0
+F:STR | INT | WIS | DEX | CON | CHR | SPEED | HIDE_TYPE |
+F:ACTIVATE | AUTO_CURSE | HEAVY_CURSE | INVIS | SPELL | MANA |
+F:SEE_INVIS | REGEN | FREE_ACT | CURSED | CURSE_NO_DROP |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | PERMA_CURSE |
+F:SUST_STR | SUST_DEX | SUST_CON |
+F:SUST_INT | SUST_WIS | SUST_CHR |
+F:RES_BLIND | RES_POIS | RES_DISEN | RES_NETHER | ESP_ALL |
+F:DRAIN_MANA | DRAIN_HP | DRAIN_EXP |
+F:INSTA_ART
+a:HARDCORE=POWER
+Z:change the world
+D:"Ash nazg durbatuluk, ash nazg gimbatul, ash nazg thrakatuluk agh
+D:burzum-ishi krimpatul". Unadorned, made of massive gold,
+D:set with runes in the foul speech of Mordor, with power so great that it
+D:inevitably twists and masters any earthly being who wears it.
+
+
+# The Anchor of Space-Time
+
+N:14:of Space-Time
+I:39:105:0
+W:30:12:15:50000
+P:0:1d1:0:0:0
+F:INSTA_ART | LITE1
+D:A powerful stone that provides a strong light for any who
+D:wields it. It is rumoured that it may even protect the wearer from
+D:the passing of time.
+
+
+# The Key of Orthanc - replaces Stone of Lore
+# This artifact has a low artifact level to prevent it being worthless for
+# chars with poor magic skills.
+
+N:15:of Orthanc
+I:39:106:0
+W:15:12:15:20000
+P:0:1d1:0:0:0
+F:ACTIVATE | SPECIAL_GENE | EASY_USE | LITE1 |
+F:INSTA_ART
+a:HARDCORE=STONE_LORE
+D:The key to the tower of Saruman, which fills your mind
+D:with images of knowledge and dreadful understanding. It
+D:is not a regular key - it is a perfectly round stone
+D:that is meant to fit into a hole. It can be used to
+D:light your way in the dungeon as well.
+
+# The Multi-Hued Dragon Scale Mail 'Lothronfaun'
+
+N:16:'Lothronfaun'
+I:38:6:0
+W:90:9:500:400000
+P:30:2d4:-4:0:25
+F:FREE_ACT | IM_ELEC | SPECIAL_GENE |
+F:RES_FIRE | RES_COLD | RES_POIS | RES_LITE | RES_DARK |
+F:LITE1 | SEE_INVIS | AGGRAVATE | ESP_DRAGON
+F:ACTIVATE
+a:HARDCORE=RAZORBACK
+D:A massive suit of heavy dragon scales deeply saturated with many colours.
+D:It throbs with angry energies. May-cloud it is called, after the
+D:element lightning which courses through it with unusual vigour.
+
+# The Power Dragon Scale Mail of the Sun
+
+N:17:of the Sun
+I:38:30:0
+W:100:16:600:500000
+P:50:2d4:-8:0:35
+F:HOLD_LIFE | REGEN | ESP_DRAGON |
+F:RES_ACID | RES_FIRE | RES_COLD | RES_ELEC | RES_POIS | FEATHER | FLY |
+F:RES_NETHER | RES_NEXUS | RES_CHAOS | RES_LITE | RES_DARK | ULTIMATE |
+F:RES_SHARDS | RES_SOUND | RES_DISEN | RES_BLIND | RES_CONF |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | SPECIAL_GENE
+F:ACTIVATE
+a:HARDCORE=BLADETURNER
+D:A suit of tilkal, set with scales of every colour, surrounded in a nimbus
+D:of perfectly untramelled yet inextricably intermingled and utterly mastered
+D:powers elemental and ethereal.
+
+
+# The Spear of Melkor
+
+N:18:of Melkor
+I:22:2:-4
+W:65:45:200:100000
+P:0:4d6:12:24:0
+F:STEALTH | WIS | CURSED | HEAVY_CURSE | TY_CURSE | ESP_GOOD |
+F:DRAIN_MANA | DRAIN_HP |
+F:RES_DARK | RES_BLIND | RES_LITE | RES_NETHER | BRAND_POIS | RES_CONF
+D:The mighty spear used once by Melkor to slay the trees of Valinor.
+
+# The Galvorn Plate Mail of Eol
+
+N:19:of Eol
+I:37:30:2
+W:75:9:420:300000
+P:40:2d4:-4:0:20
+F:CON |
+F:HOLD_LIFE | SUST_CON | ESP_UNDEAD | RES_CONF | RES_FEAR |
+F:RES_ACID | RES_COLD | RES_DARK | RES_NETHER | RES_NEXUS | RES_CHAOS |
+F:ACTIVATE
+a:HARDCORE=CURE_1000
+D:A suit of imperishable galvorn, with unconquerable strength to endure evil
+D:and disruptive magics. It protects the life force of its wearer like
+D:nothing else can. Eol the Dark Elf made it in secret for his son, but
+D:Maeglin left Nan Elmoth with his mother Aredhel and never got to wear it.
+
+# The Full Plate Armour of Isildur
+
+N:20:of Isildur
+I:37:15:1
+W:30:3:300:50000
+P:25:2d4:0:0:25
+F:CON |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:RES_SOUND | RES_CONF | RES_NEXUS
+D:A gleaming steel suit covering the wearer from neck to foot, with runes of
+D:warding and stability deeply engraved into its surface.
+
+
+# The Metal Brigandine Armour of the Rohirrim
+
+N:21:of the Rohirrim
+I:37:9:2
+W:30:3:200:30000
+P:19:1d4:0:0:15
+F:STR | DEX | SPEED | HIDE_TYPE | RES_FEAR |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_CONF | RES_SOUND
+D:A stiff suit of armour composed of small metal plates sewn to an
+D:inner layer of heavy canvas, and covered with a second layer of
+D:cloth. Within it is the spirit of Eorl the Young, matchless in combat.
+
+
+# The Mithril Chain Mail 'Belegennon'
+
+N:22:'Belegennon'
+I:37:20:4
+W:40:10:150:135000
+P:28:1d4:-1:0:20
+F:STEALTH | WIS | INT |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS |
+F:HOLD_LIFE | RES_DARK | RES_FEAR |
+F:SEE_INVIS |
+F:ACTIVATE
+a:HARDCORE=BELEGENNON
+D:This wondrous suit of fine-linked chain shimmers as though of pure silver.
+D:It stands untouched amidst the fury of the elements, and a power of
+D:concealment rests within.
+
+
+# The Mithril Plate Mail of Celeborn
+
+N:23:of Celeborn
+I:37:25:4
+W:40:3:250:150000
+P:35:2d4:-3:0:25
+F:STR | CHR | HIDE_TYPE | ESP_ORC
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_DARK |
+F:RES_DISEN | ACTIVATE
+a:HARDCORE=GENOCIDE
+D:A shimmering suit of true-silver, forged long ago by dwarven smiths of
+D:legend. It gleams with purest white as you gaze upon it, and mighty are
+D:its powers to protect and banish.
+
+
+# The Chain Mail of Arvedui
+
+N:24:of Arvedui
+I:37:4:2
+W:20:3:220:32000
+P:14:1d4:-2:0:15
+F:STR | CHR | HIDE_TYPE |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_SHARDS | RES_NEXUS
+D:A hauberk, leggings, and sleeves of interlocking steel rings, well padded
+D:with leather. You feel strong and tall as Arvedui, last king of Arnor,
+D:as you put it on.
+
+
+# The Augmented Chain Mail of Caspanion
+
+N:25:of Caspanion
+I:37:6:3
+W:25:9:270:40000
+P:16:1d4:-2:0:20
+F:INT | WIS | CON | HIDE_TYPE |
+F:RES_ACID | RES_POIS | RES_CONF | ACTIVATE
+a:HARDCORE=DEST_DOOR
+D:A hauberk, leggings, and sleeves of interlocking steel rings, strategically
+D:reinforced at vital locations with a second layer of chain. Magics to
+D:enhance body and mind lie within, and no door can hope to resist the wearer.
+
+
+# The Mithril Helm of Gil-galad
+# Designed with no-infravision warrior-types in mind.
+# Replaces Marda's coat in Theme
+
+N:26:of Gil-galad
+I:32:8:10
+W:50:80:50:20000
+P:6:1d3:0:0:10
+F:ACTIVATE | HIDE_TYPE | INFRA | LITE2 | LITE3 | SEARCH
+a:HARDCORE=SUNLIGHT
+D:The shining helm that Gil-galad, legendary Elven-king, wore in battle.
+
+# The Leather Jerkin of Tom Bombadil
+# Based on a suggestion by Maverick in the forums:
+# Replaces Trone's coat in Theme.
+
+
+N:27:of Tom Bombadil
+I:36:12:1
+W:10:10:70:30000
+P:40:2d4:0:0:0
+F:CHR | CON | DEX | HIDE_TYPE | INT | STR | WIS
+Z:teleport
+D:This garment was once the property of Tom Bombadil -
+D:a strange being rumoured to be older than Arda itself. It
+D:may be the explanation for how Tom could always turn up
+D:when he was most needed.
+
+# The Leather Scale Mail 'Thalkettoth'
+
+N:28:'Thalkettoth'
+I:36:11:3
+W:20:3:60:25000
+P:11:1d1:-1:0:25
+F:DEX | SPEED | HIDE_TYPE | SPECIAL_GENE |
+F:RES_ACID | RES_SHARDS
+D:A tunic and skirt sewn with thick, overlapping scales of hardened
+D:leather whose wearer moves with agility and assurance.
+
+
+# The Pair of Soft Leather Boots of Wormtongue
+
+N:29:of Wormtongue
+I:30:2:3
+W:40:20:20:50000
+P:2:1d1:-10:-10:10
+F:INT | DEX | CHR | STEALTH | SEARCH | SPEED | HIDE_TYPE |
+F:FREE_ACT | FEATHER | RES_DARK | RES_LITE | ESP_GOOD | ESP_UNIQUE
+Z:panic hit
+D:The pair of boots used by Grima son of Galmod, also named the Wormtongue:
+D:a treacherous but persuasive counsellor, ever ready to betray, sneak,
+D:lie, cheat and steal - but never ready to actually fight.
+
+
+# The Small Mithril Shield of Thorin
+
+N:30:of Thorin
+I:34:7:4
+W:30:6:65:60000
+P:5:1d2:0:0:25
+F:STR | CON | HIDE_TYPE |
+F:FREE_ACT | IM_ACID | RES_SOUND |
+F:RES_CHAOS | ESP_ORC
+D:Invoking the strength and endurance of Thorin, King under the Mountain,
+D:this little shield forged of true-silver is proof against the Element
+D:of Earth.
+
+# The Large Leather Shield of Celegorm
+
+N:31:of Celegorm
+I:34:4:0
+W:30:3:60:12000
+P:4:1d2:0:0:20
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_LITE | RES_DARK
+D:This shield emblazoned with a multitude of creatures not seen for ages
+D:once protected Celegorm, lord of Himlad; around it lies a mystic balance
+D:that contains the conflicts of the elements.
+
+
+# The Large Metal Shield of Anarion
+
+N:32:of Anarion
+I:34:5:0
+W:40:9:120:160000
+P:5:1d3:0:0:20
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | SUST_STR | SUST_INT |
+F:SUST_WIS | SUST_DEX | SUST_CON | SUST_CHR | ESP_EVIL
+D:The great metal-bound shield of Anarion, son of Elendil, who Sauron found
+D:himself powerless to wither or diminish.
+
+
+# The Beaked Axe of Hurin
+
+N:33:of Hurin
+I:22:10:3
+W:20:15:180:90000
+P:0:2d6:12:20:0
+F:STR | CON | HIDE_TYPE | BRAND_ACID | RES_ACID | LITE1 | DRAIN_MANA |
+F:SLAY_ORC | KILL_DEMON | SLAY_TROLL | ACTIVATE | SHOW_MODS
+F:MUST2H
+f:MUST2H
+a:HARDCORE=HURIN
+D:Wielded by Hurin Thalion in the Fifth Battle of Beleriand, this
+D:troll-bane smoked in the black blood of Gothmog's guards.
+
+
+# The Massive Iron Crown of Morgoth
+
+N:34:of Morgoth
+I:33:50:125
+W:100:1:20:10000000
+P:0:1d1:0:0:0
+F:STR | INT | WIS | DEX | CON | CHR | INFRA | HIDE_TYPE |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS |
+F:RES_LITE | RES_DARK | RES_CONF | RES_NEXUS | RES_NETHER |
+F:LITE1 | SEE_INVIS | ESP_ALL |
+F:CURSED | HEAVY_CURSE | PERMA_CURSE |
+F:INSTA_ART | SPECIAL_GENE
+D:Two Silmarils of Feanor blaze from the thunderous crown of twisted
+D:iron. The corrupted metal feels at once as infernal as hellfire
+D:and as chilling as the Outer Darkness. One protrusion from the
+D:crown is abruptly ended where a third jewel might have shone.
+
+
+# The Iron Crown of Beruthiel
+
+N:35:of Beruthiel
+I:33:10:-5
+W:40:12:20:0
+P:0:1d1:0:0:20
+F:STR | DEX | CON | HIDE_TYPE |
+F:FREE_ACT | SEE_INVIS | ESP_ANIMAL | ESP_EVIL | ESP_NONLIVING | ESP_ALL |
+F:CURSED | AUTO_CURSE
+D:The midnight-hued steel circlet of the sorceress-queen Beruthiel, which
+D:grants extraordinary powers of sight and awareness at a terrible physical
+D:cost.
+
+
+# The Hard Leather Cap of Thranduil
+
+N:36:of Thranduil
+I:32:2:2
+W:20:2:15:50000
+P:2:0d0:0:0:10
+F:INT | WIS | HIDE_TYPE |
+F:RES_BLIND | ESP_ORC | ESP_EVIL | ESP_TROLL
+D:The hunting cap of King Thranduil, to whose ears come all the secrets of
+D:his forest domain.
+
+
+# The Metal Cap of Thengel
+
+N:37:of Thengel
+I:32:3:3
+W:10:2:20:22000
+P:3:1d1:0:0:12
+F:WIS | CHR | RES_CONF | HIDE_TYPE | LUCK
+D:A ridged helmet made of steel, and embossed with scenes of valour in fine-
+D:engraved silver. It grants the wearer nobility, clarity of thought and
+D:understanding.
+
+
+# The Steel Helm of Hammerhand
+
+N:38:of Hammerhand
+I:32:6:3
+W:20:2:60:45000
+P:6:1d3:0:0:20
+F:STR | DEX | CON | HIDE_TYPE | SPECIAL_GENE | RES_FEAR |
+F:SUST_STR | SUST_DEX | SUST_CON |
+F:RES_ACID | RES_NEXUS | RES_COLD | RES_DARK | SLOW_DIGEST |
+Z:berserk
+D:A great helm as steady as the heroes of the Westdike. Mighty were the
+D:blows of Helm, the Hammerhand!
+
+
+# The Dragon Helm of Dor-Lomin
+
+N:39:of Dor-Lomin
+I:32:7:4
+W:40:12:75:300000
+P:8:1d3:0:0:20
+F:STR | DEX | CON | HIDE_TYPE |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_LITE | RES_BLIND |
+F:LITE1 | SEE_INVIS | ESP_DRAGON | ESP_THUNDERLORD | ACTIVATE
+a:HARDCORE=GORLIM
+D:The legendary dragon helm of Turin Turambar, an object of dread to the
+D:servants of Morgoth.
+
+# The Iron Helm 'Holhenneth'
+
+N:40:'Holhenneth'
+I:32:5:2
+W:20:5:75:100000
+P:5:1d3:0:0:10
+F:INT | WIS | SEARCH | HIDE_TYPE |
+F:RES_BLIND | SEE_INVIS | ACTIVATE
+a:HARDCORE=DETECT_ALL
+D:A famous helm of forged iron granting extraordinary powers of mind and
+D:awareness.
+
+
+# The Iron Helm of Gorlim
+
+N:41:of Gorlim
+I:32:5:-5
+W:20:5:75:0
+P:5:1d3:25:25:10
+F:INT | WIS | SEARCH | HIDE_TYPE | SHOW_MODS |
+F:SEE_INVIS | NO_MAGIC | HEAVY_CURSE | TY_CURSE
+F:RES_DISEN | RES_FEAR | FREE_ACT | RES_ACID | RES_FIRE | RES_POIS |
+F:IM_COLD | ACTIVATE | DRAIN_HP |
+F:TELEPORT | CURSED
+a:HARDCORE=GORLIM
+D:A headpiece, gaudy and barbaric, that betrayed a warrior when he most
+D:needed succor.
+
+
+# The Golden Crown of Gondor
+
+N:42:of Gondor
+I:33:11:3
+W:40:40:30:125000
+P:0:1d1:0:0:15
+F:STR | WIS | CON | HIDE_TYPE | SPEED | RES_CONF | RES_SOUND |
+F:RES_COLD | RES_FIRE | RES_LITE | RES_BLIND | RES_ELEC | RES_CHAOS |
+F:LITE1 | SEE_INVIS | REGEN | ACTIVATE
+a:HARDCORE=CURE_700
+D:The shining winged circlet brought by Elendil from dying Numenor, emblem of
+D:Gondor through an age of the world.
+
+
+# The Jewel Encrusted Crown of Numenor
+# Stolen from Oangband
+
+N:43:of Numenor
+I:33:12:3
+W:60:30:40:50000
+P:0:1d1:0:0:18
+F:INT | DEX | CHR | SEARCH | SPEED | HIDE_TYPE |
+F:SEE_INVIS | FREE_ACT | RES_DARK | RES_BLIND |
+F:RES_SHARDS | RES_SOUND | RES_LITE | RES_COLD |
+F:LITE1 | ACTIVATE | DRAIN_MANA
+a:HARDCORE=NUMENOR
+D:A crown of massive gold, set with wondrous jewels of thought and warding,
+D:worn by the kings of ancient Numenor. Its wearer may go into battle
+D:always knowing what he faces - unless his own folly blinds him to the
+D:nature and magnitude of the task.
+
+# The Cloak of Valinor
+# Replaces Colluin in Theme
+# *THE* cloak for Barehanders/Mages
+
+N:44:of Valinor
+I:35:1:0
+W:60:90:10:40000
+P:1:0d0:0:0:20
+F:ACTIVATE | IM_ACID | IM_COLD | IM_ELEC | IM_FIRE | RES_POIS
+a:HARDCORE=COLLUIN
+D:A cape worn by a hero from Valinor, a land utterly beyond the strife
+D:of the elements.
+
+# The Cloak 'Holcolleth'
+
+N:45:'Holcolleth'
+I:35:1:2
+W:5:25:10:13000
+P:1:0d0:0:0:4
+F:INT | WIS | SPEED | STEALTH | HIDE_TYPE |
+F:RES_ACID | ACTIVATE
+a:HARDCORE=SLEEP
+D:This elven-grey mantle possesses great powers of tranquility and of
+D:concealment, and grants the wearer the knowledge and understanding of
+D:the Sindar.
+
+
+# The Cloak of Thingol
+
+N:46:of Thingol
+I:35:1:3
+W:10:50:10:35000
+P:1:0d0:0:0:18
+F:DEX | CHR | HIDE_TYPE |
+F:FREE_ACT | RES_ACID | RES_FIRE | RES_COLD | ACTIVATE
+a:HARDCORE=RECHARGE
+D:A sable-hued cloak, with glowing elven-runes to restore magic showing calm
+D:and clear as moonlight on still water.
+
+
+# The Cloak of Thorongil
+
+N:47:of Thorongil
+I:35:1:0
+W:5:10:10:8000
+P:1:0d0:0:0:10
+F:FREE_ACT | RES_ACID | SEE_INVIS | RES_FEAR
+D:A cloak of shimmering green and brown that grants sight beyond sight and
+D:shakes off holding magics, worn by Aragorn son of Arathorn in his youth
+D:as he adventured under the name of Thorongil.
+
+
+# The Cloak 'Colannon'
+
+N:48:'Colannon'
+I:35:1:3
+W:5:20:10:11000
+P:1:0d0:0:0:15
+F:STEALTH | SPEED | RES_NEXUS |
+F:RES_ACID | ACTIVATE
+a:HARDCORE=TELEPORT
+D:A crystal-blue cape of fine silk worn by a silent messenger of
+D:the forces of Law. Somehow, its wearer is always able to escape
+D:trouble.
+
+
+# The Shadow Cloak of Luthien
+
+N:49:of Luthien
+I:35:6:2
+W:40:40:5:55000
+P:6:0d0:0:0:20
+F:INT | WIS | CHR | HIDE_TYPE | SPEED | STEALTH | INVIS | LUCK
+F:RES_ACID | RES_FIRE | RES_COLD | SPECIAL_GENE | ACTIVATE | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=REST_LIFE
+D:The opaque midnight folds, inset with a multitude of tiny diamonds, of
+D:this cloak swirl around you and you feel a hint, a fragment of the
+D:knowledge and power to restore that lay in Luthien, the most beautiful
+D:being that ever knew death.
+
+
+# The Shadow Cloak of Tuor
+
+N:50:of Tuor
+I:35:6:4
+W:40:40:5:35000
+P:6:0d0:0:0:12
+F:STEALTH | DEX | HIDE_TYPE | INVIS | WATER_BREATH
+F:FREE_ACT | IM_ACID | SEE_INVIS | CLIMB
+D:From the ruin of Gondolin did Tuor escape, through secret ways and travail,
+D:shielded by his cloak from a multitude of hostile eyes.
+
+
+# The Main Gauche of Azaghal, which wounded Glaurung
+N:51:of Azaghal
+I:23:5:0
+W:15:30:30:40000
+P:0:2d5:12:14:0
+F:KILL_DRAGON | IM_FIRE | ESP_DRAGON | RES_FEAR
+D:The weapon of Azaghal when he wounded Glaurung. It is deadly
+D:when fighting dragons and is said to make the breaths of fire
+D:completely harmless.
+
+
+# The Set of Leather Gloves 'Cambeleg'
+
+N:52:'Cambeleg'
+I:31:1:2
+W:10:6:5:36000
+P:1:0d0:8:8:15
+F:STR | CON | HIDE_TYPE |
+F:FREE_ACT | SHOW_MODS
+D:A hero's handgear that lends great prowess in battle.
+
+
+# The Set of Leather Gloves 'Cammithrim'
+
+N:53:'Cammithrim'
+I:31:1:0
+W:10:3:5:30000
+P:1:0d0:0:0:10
+F:FREE_ACT | RES_LITE | SUST_CON | LITE1 | ACTIVATE
+F:SPECIAL_GENE
+a:HARDCORE=BO_MISS_1
+D:These gloves glow so brightly as to light the way for their owner and cast
+D:magical bolts with great frequency.
+
+# The Set of Gauntlets of Eregion (formerly 'Paurhach')
+
+N:54:of Eregion
+I:31:2:4
+W:10:5:25:33000
+P:2:1d1:0:0:15
+F:RES_FIRE | ACTIVATE |
+F:SUST_STR | STR | REGEN | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=BO_FIRE_1
+D:A fiery set of gauntlets that can even shoot fire from the user's
+D:hands. Wrought by Curufin's people, they guard the wearer's
+D:strength and enhance it.
+
+# The Set of Gauntlets of Nargothrond (formerly 'Paurnimmen')
+
+N:55:of Nargothrond
+I:31:2:4
+W:10:5:25:33000
+P:2:1d1:0:0:15
+F:RES_COLD | ACTIVATE |
+F:SUST_CON | CON | REGEN | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=BO_COLD_1
+D:A set of handgear so icy as to be able to fire frost bolts. Wrought by
+D:Finrod Felagund himself, it is inscribed with runes that guard and
+D:boost health.
+
+# The Set of Gauntlets of Lorien (formerly 'Pauraegen')
+
+N:56:of Lorien
+I:31:2:4
+W:10:5:25:33000
+P:2:1d1:0:0:15
+F:RES_ELEC | ACTIVATE | FREE_ACT |
+F:SUST_DEX | DEX | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=BO_ELEC_1
+D:A set of handgear wrought by the Galadhrim. Sparks surround it, enabling
+D:the wearer to fire bolts of electricity. Ever has lightning improved and
+D:protected agility, and these gauntlets are no exception.
+
+# The Set of Gauntlets of Ossiriand (formerly 'Paurnen')
+
+N:57:of Ossiriand
+I:31:2:4
+W:10:5:25:33000
+P:2:1d1:0:0:15
+F:RES_ACID | ACTIVATE |
+F:SUST_CHR | CHR | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=BO_ACID_1
+D:Mighty was the woodcraft of the Laiquendi, for they learned to control the
+D:element of acid to a level theretofore unknown. This set of handgear is so
+D:corrosive that it may fire bolts of acid.
+
+# The Set of Gauntlets 'Camlost'
+
+N:58:'Camlost'
+I:31:2:-3
+W:10:20:25:0
+P:2:1d1:-11:-12:0
+F:STR | DEX | HIDE_TYPE | DRAIN_MANA |
+F:RES_POIS | IM_FIRE | IM_COLD | RES_DISEN | RES_NETHER | FREE_ACT |
+F:AGGRAVATE | SHOW_MODS | HEAVY_CURSE | TY_CURSE | TELEPORT | CURSED
+D:A pair of gauntlets that sap combat ability, named after the empty hand
+D:of Beren that once clasped a Silmaril.
+
+
+# The Set of Cesti of Fingolfin
+
+N:59:of Fingolfin
+I:31:5:4
+W:40:15:40:110000
+P:5:1d1:10:10:20
+F:DEX | HIDE_TYPE | LUCK
+F:FREE_ACT | RES_ACID | ACTIVATE | SHOW_MODS
+a:HARDCORE=BO_MISS_2
+Z:magic missile
+D:The hand-sheathing of Fingolfin, warrior-king of Elves and Men, who gave
+D:Morgoth seven mighty wounds and pain that will last forever.
+
+
+# The Pair of Hard Leather Boots of Feanor
+
+N:60:of Feanor
+I:30:3:15
+W:40:120:40:300000
+P:3:1d1:0:0:20
+F:SPEED | HIDE_TYPE |
+F:RES_NEXUS | ACTIVATE
+a:HARDCORE=SPEED
+D:This wondrous pair of leather boots once sped Feanor, creator of the
+D:Silmarils and the mightiest of the Eldar, along the Grinding Ice and to
+D:Middle-earth at last.
+
+
+# The Pair of Soft Leather Boots 'Dal-i-thalion'
+
+N:61:'Dal-i-thalion'
+I:30:2:5
+W:10:25:20:40000
+P:2:1d1:0:0:15
+F:DEX | HIDE_TYPE | CHR | SUST_CHR |
+F:ACTIVATE | FREE_ACT |
+F:RES_NETHER | RES_CHAOS | RES_CONF | SUST_CON
+a:HARDCORE=CURE_POISON
+D:A pair of high-laced shoes, strong against the powers of corruption and
+D:withering, that grant the wearer extraordinary agility.
+
+
+# The Pair of Metal Shod Boots of Thror
+
+N:62:of Thror
+I:30:6:3
+W:30:25:80:15000
+P:6:1d1:0:0:20
+F:STR | CON | HIDE_TYPE | SPEED | RES_FEAR | CLIMB
+D:Sturdy footwear of leather and steel as enduring as the long-suffering
+D:Dwarven King-in-exile who wore them. Of dwarven make, these boots will
+D:make their wearer completely at home in the mountains.
+
+
+# The Seeker Arrow of Bard
+# This is, of course, from my 'Artifact Ammo' thread and doesn't need much
+# explanation. It's rather nasty and deals 1000 or more damage on a
+# normal hit to a dragon. :) Doesn't put a dent in Sky Drakes and Power
+# Dragons, tho it's still good for helping to take down Smaug, Tiamat and
+# the other dragon uniques.
+# P+ changed name, rarity to 30
+
+N:63:of Bard
+I:17:2:0
+W:55:30:2:50000
+P:0:8d4:20:15:0
+F:SLAY_ANIMAL | SLAY_EVIL | SLAY_UNDEAD | SLAY_DEMON |
+F:SLAY_ORC | SLAY_TROLL | SLAY_GIANT | SLAY_DRAGON | KILL_DRAGON |
+F:BRAND_ACID | BRAND_ELEC | BRAND_FIRE | BRAND_COLD | BRAND_POIS
+D:Deadliest of arrows, imbued with elemental strength, this shaft is
+D:feared especially by the wyrmkin.
+
+
+# The Main Gauche of Maedhros
+
+N:64:of Maedhros
+I:23:5:3
+W:15:30:30:22500
+P:0:2d5:12:15:0
+F:INT | DEX | HIDE_TYPE | SPEED | SPECIAL_GENE
+F:SLAY_TROLL | SLAY_GIANT | FREE_ACT | SEE_INVIS | SHOW_MODS
+D:A short thrusting blade with a large guard worn by Maedhros the Tall,
+D:eldest son of Feanor, and wielded with his left hand after the loss of
+D:his right hand in the pits of Thangorodrim.
+
+# The Broken Dagger 'Angrist'
+
+N:65:'Angrist'
+I:23:1:4
+W:25:80:12:150000
+P:0:2d4:10:15:5
+F:BRAND_ACID | BRAND_POIS | DEX | FREE_ACT | HIDE_TYPE | LUCK | RES_DARK | SEARCH | SEE_INVIS | SHOW_MODS | SLAY_EVIL | SLAY_ORC | SLAY_TROLL | STEALTH | SUST_DEX
+D:The knife Beren Barahir`s son took from Curufin and with which he cut
+D:out a Silmaril from the crown of Morgoth, The blade snapped and broke
+D:when he tried to gain one more and the splint hit Morgoth at his chin.
+D:It was made of Telchar the dwarf from Nogrod and it could cut through
+D:stone. Even broken, it retains power.
+
+# The Dagger of Samwise
+
+N:66:of Samwise
+I:23:4:0
+W:4:100:12:12000
+P:0:1d4:4:6:0
+F:ACTIVATE | BRAND_FIRE | LEVELS | LITE1 | RES_FIRE | SHOW_MODS
+a:HARDCORE=BO_FIRE_1
+D:The blade of Samwise Gamgee, chosen by him from the hoard of the
+D:Barrow-wights. A fiery dagger finely balanced for deadly throws.
+
+# The Dagger of Peregrin
+
+N:67:of Peregrin
+I:23:4:0
+W:3:100:12:11000
+P:0:1d4:4:6:0
+F:ACTIVATE | BRAND_COLD | LEVELS | RES_COLD | SHOW_MODS
+a:HARDCORE=BO_COLD_1
+D:The blade of Peregrin Took, chosen by him from the hoard of the
+D:Barrow-wights. A frosty dagger finely balanced for deadly throws.
+
+# The Dagger of Meriadoc
+
+N:68:of Meriadoc
+I:23:4:0
+W:5:100:12:13000
+P:0:1d4:4:6:0
+F:BRAND_ELEC | RES_ELEC | ACTIVATE | SHOW_MODS | LEVELS
+a:HARDCORE=BO_ELEC_1
+D:The blade of Meriadoc Brandybuck, chosen by him from the hoard of
+D:the Barrow-wights. A dagger covered in sparks and finely balanced
+D:for deadly throws.
+
+# The Dagger of Rilia
+
+N:69:of Rilia
+I:23:4:0
+W:5:40:12:35000
+P:0:2d4:4:3:0
+F:SLAY_ORC | RES_POIS | RES_DISEN | ACTIVATE | SHOW_MODS | BRAND_POIS
+a:HARDCORE=BA_POIS_1
+D:A large stiletto dagger that glistens with odourless poison, to which the
+D:wearer seems oddly immune.
+
+
+# The Dagger 'Belangil'
+
+N:70:'Belangil'
+I:23:4:2
+W:10:40:12:50000
+P:0:2d4:6:9:0
+F:DEX | HIDE_TYPE | SPEED | BLOWS |
+F:BRAND_COLD | RES_COLD |
+F:SEE_INVIS | SLOW_DIGEST | REGEN |
+F:ACTIVATE | SHOW_MODS | BRAND_POIS
+a:HARDCORE=BELANGIL
+D:A frosty dagger surrounded in a nimbus of ice with a hilt of elk horn and
+D:an edge to wound the wind.
+
+
+# The Bastard Sword 'Calris'
+
+N:71:'Calris'
+I:23:21:5
+W:30:15:140:100000
+P:0:5d4:-20:20:0
+F:CON | HIDE_TYPE | DRAIN_HP |
+F:KILL_DRAGON | SLAY_EVIL | SLAY_DEMON | SLAY_TROLL | RES_DISEN |
+F:AGGRAVATE | CURSED | HEAVY_CURSE | SHOW_MODS | ESP_DRAGON | ESP_DEMON |
+F:AUTO_CURSE |
+F:COULD2H
+f:COULD2H
+D:This sword has runes of power incised on its ornate hilt and a single
+D:blood channel that gleams coldly blue as you grasp this mighty weapon of
+D:peril.
+
+
+# The Broad Sword 'Aranruth'
+
+N:72:'Aranruth'
+I:23:16:4
+W:20:45:150:125000
+P:0:3d5:20:12:0
+F:STR | DEX | CON | SUST_CON | SUST_STR
+F:REGEN | FREE_ACT | SEE_INVIS |
+F:RES_CHAOS | RES_NETHER | HOLD_LIFE | RES_FEAR |
+F:RES_COLD |
+F:SLAY_DEMON | SLAY_EVIL | SLAY_DRAGON | SLAY_UNDEAD |
+F:BRAND_COLD |
+F:SLOW_DIGEST | SHOW_MODS | HIDE_TYPE | BLESSED
+D:The beautiful sword of Thingol with a hilt of gold and silver inlay,
+D:glistening icily enough to freeze the hearts of demons. You feel supple
+D:and lightfooted as you hold it.
+
+
+# The Broad Sword 'Glamdring'
+
+N:73:'Glamdring'
+I:23:16:1
+W:20:20:150:40000
+P:0:2d5:10:15:0
+F:SEARCH | HIDE_TYPE | BLESSED | SLAY_DEMON |
+F:SLAY_EVIL | BRAND_FIRE | SLAY_ORC | RES_FIRE | RES_LITE | LITE1 |
+F:SLOW_DIGEST | SHOW_MODS | ESP_ORC | SPECIAL_GENE
+D:This fiery, shining blade earned its sobriquet "Foe-Hammer" from dying orcs
+D:who dared to come near hidden Gondolin. Inscribed upon the guard in Cirth
+D:is the following --
+D:gûd daedheloth, dam an Glamhoth." - "Turgon King of Gondolin wields, has and
+D:holds the sword Glamdring, foe of Morgoth's realm, hammer to the Din-horde."
+
+# The Quarterstaff of Thranduil [Replaces the 'Aeglin' sword in Theme]
+
+N:74:of Thranduil
+I:21:3:0
+W:20:18:150:50000
+P:0:1d9:10:20:0
+F:BRAND_POIS | COULD2H | RES_POIS | SLAY_ANIMAL | HIDE_TYPE | SHOW_MODS | ESP_ANIMAL
+f:COULD2H
+D:The carven oak staff of the King of the Woodland Realm,
+D:this weapon is a fighter's best friend in a forest.
+
+# The Broad Sword 'Orcrist'
+
+N:75:'Orcrist'
+I:23:16:3
+W:20:20:150:40000
+P:0:2d5:10:15:0
+F:SEARCH | ESP_ORC | SLAY_DRAGON | ESP_DRAGON | RES_COLD | HIDE_TYPE |
+F:SLAY_EVIL | BRAND_COLD | SLAY_ORC | RES_COLD | LITE1 | RES_DARK |
+F:SLOW_DIGEST | SHOW_MODS
+D:This coldly gleaming blade is called simply "Biter", by orcs who came to
+D:know its power all too well.
+
+# The Two-Handed Sword 'Anglachel'
+
+N:76:'Anglachel'
+I:23:25:2
+W:30:30:200:100000
+P:0:3d6:13:17:0
+F:STR | HIDE_TYPE | VORPAL | ESP_DRAGON | DRAIN_HP |
+F:RES_FIRE | RES_POIS | BRAND_FIRE | BRAND_POIS |
+F:KILL_DRAGON | SLAY_TROLL | FREE_ACT | SLOW_DIGEST | REGEN | SHOW_MODS |
+F:MUST2H
+f:MUST2H
+D:A giant sword once wielded by mighty Turin, and a great dragonbane which
+D:bathed in Glaurung's blood. Its blade once shone brightly, it can cleave
+D:iron as though it is old wood. Beleg Cuthalion chose this sword from the
+D:armoury of Thingol in Doriath. Turin son of Hurin slew his friend Beleg
+D:with it by accident, and since then the blade is black and dull.
+
+# The Two-Handed Sword 'Zarcuthra'
+
+N:77:'Zarcuthra'
+I:23:25:4
+W:30:180:250:205000
+P:0:4d6:19:21:0
+F:STR | CHR | INFRA | HIDE_TYPE | VORPAL | DRAIN_MANA |
+F:KILL_DRAGON | SLAY_ANIMAL | SLAY_EVIL | BRAND_FIRE |
+F:SLAY_UNDEAD | SLAY_DEMON | SLAY_TROLL | SLAY_GIANT | SLAY_ORC |
+F:RES_FIRE | RES_CHAOS | FREE_ACT | SEE_INVIS | AGGRAVATE | SHOW_MODS |
+F:MUST2H
+f:MUST2H
+D:Dark and deadly runes stand stark against the naked steel of this awesome
+D:weapon, and you feel a stunning power of slaying and rending as you
+D:slowly approach.
+
+
+# The Dark Sword 'Mormegil'
+
+N:78:'Mormegil'
+I:23:33:2
+W:30:15:250:0
+P:0:6d7:0:0:-20
+F:SPEED | IM_FIRE | RES_FIRE | BRAND_FIRE | RES_DISEN | RES_FEAR |
+F:AGGRAVATE | CURSED | HEAVY_CURSE | SHOW_MODS | LEVELS | TY_CURSE |
+F:BLOWS | SLAY_DRAGON | RES_CHAOS | ANTIMAGIC_50 |
+F:DRAIN_MANA | DRAIN_HP | DRAIN_EXP
+D:A foul, twisted sword with blackened spines and knobs, whose very name is a
+D:curse upon the lips of Elves and Men.
+
+
+# The Cutlass 'Gondricam'
+
+N:79:'Gondricam'
+I:23:12:3
+W:20:8:110:28000
+P:0:1d7:10:11:0
+F:DEX | STEALTH | HIDE_TYPE |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | FEATHER |
+F:SEE_INVIS | REGEN | SHOW_MODS
+D:Famed sea-defender of Lebennin. A short, slightly curved chopping blade
+D:with a perfect edge shining cleanly in the sun, an object of hate to the
+D:men of Umbar who met it in combat.
+
+
+# The Executioner's Sword 'Crisdurian'
+
+N:80:'Crisdurian'
+I:23:28:0
+W:40:15:260:111000
+P:0:4d5:18:19:0
+F:SLAY_DRAGON | SLAY_EVIL | SLAY_UNDEAD | SLAY_TROLL | SLAY_GIANT |
+F:SLAY_ORC | SEE_INVIS | SHOW_MODS | VORPAL | BRAND_POIS | WOUNDING |
+F:MUST2H
+f:MUST2H
+D:A giant's weapon, with a long blade tall and straight thrusting out from a
+D:massive double-pronged hilt. On its blade are written doomspells against
+D:both the living and undead.
+
+# The Long Sword 'Herugrim' - sword of Theoden
+# Replaces 'Aglarang' in Theme
+
+N:81:'Herugrim'
+I:23:17:2
+W:60:40:130:300000
+P:0:3d5:8:9:0
+F:ACTIVATE | ESP_EVIL | FREE_ACT | HIDE_TYPE | INT | RES_CONF | RES_DARK | SHOW_MODS | VORPAL
+a:HARDCORE=CURE_INSANITY
+D:The ancient blade of Theoden, King of the Mark. It was taken from
+D:the king by Grima the Wormtongue, and hidden from him in a dusty
+D:chest. It was once instrumental in restoring the King's wits from
+D:evil bewitchment.
+
+# The Long Sword 'Ringil'
+
+N:82:'Ringil'
+I:23:17:10
+W:20:120:130:300000
+P:0:4d5:22:25:0
+F:SPEED | HIDE_TYPE | RES_FEAR | BLESSED |
+F:SLAY_EVIL | BRAND_COLD | SLAY_UNDEAD | KILL_DEMON | SLAY_TROLL |
+F:FREE_ACT | RES_COLD | RES_LITE | LITE1 | SEE_INVIS | SLOW_DIGEST | REGEN |
+F:ACTIVATE | SHOW_MODS
+a:HARDCORE=BA_COLD_2
+D:The weapon of Fingolfin, High King of the Noldor; it shines like a column
+D:of ice lit by light unquenchable. Morgoth came but unwillingly to meet it
+D:of old; his lame foot will remind him of its might should he meet it again.
+
+
+# The Long Sword 'Anduril'
+
+N:83:'Anduril'
+I:23:17:4
+W:20:40:130:100000
+P:0:3d5:10:15:5
+F:STR | DEX | HIDE_TYPE | RES_FEAR | FREE_ACT | BLESSED | LUCK
+F:SLAY_EVIL | BRAND_FIRE | SLAY_TROLL | SLAY_ORC | FREE_ACT |
+F:RES_FIRE | SUST_DEX | SEE_INVIS | ACTIVATE | SHOW_MODS | LITE1 |
+F:RES_DISEN | SPECIAL_GENE
+a:HARDCORE=BA_FIRE_1
+D:The famed "Flame of the West", the sword that was broken and is forged
+D:again. It glows with the essence of fire, its wearer is mighty in combat,
+D:and no creature of Sauron can withstand it. It will never be stained or
+D:broken even in defeat. Its pommel glows anew with the Quenya words --
+D:"Anar. Nanye Anduril i ne Narsil i macil Elendilo. Lercuvanten i moli
+D:Mordoreo. Isil." - "Sun. I am Anduril who once was Narsil, sword of Elendil.
+D:The slaves of Mordor shall flee from me. Moon."
+
+# The Long Sword 'Anguirel'
+
+N:84:'Anguirel'
+I:23:17:2
+W:20:30:130:40000
+P:0:2d5:8:12:0
+F:STR | CON | SPEED | HIDE_TYPE |
+F:SLAY_EVIL | BRAND_ELEC | SLAY_DEMON | FREE_ACT | RES_ELEC |
+F:RES_LITE | RES_DARK | SEE_INVIS | SHOW_MODS | VORPAL | WOUNDING |
+F:AGGRAVATE | CURSED
+D:Forged of black galvorn by the Dark-Elven smith Eol, this blade has the
+D:living lightning trapped inside.
+
+
+# The Long Sword 'Elvagil'
+
+N:85:'Elvagil'
+I:23:17:2
+W:20:8:130:20000
+P:0:2d5:5:7:0
+F:DEX | CHR | STEALTH | HIDE_TYPE | ESP_ORC | ESP_TROLL
+F:SLAY_TROLL | SLAY_ORC | FEATHER | SEE_INVIS | SHOW_MODS
+D:The "Singing Blade", whose wearer can slay Orcs and Trolls in the hidden
+D:and secret places of the earth.
+
+
+# The Rapier 'Forasgil'
+
+N:86:'Forasgil'
+I:23:7:0
+W:15:8:40:15000
+P:0:1d6:12:19:0
+F:SLAY_ANIMAL | BRAND_COLD | RES_COLD | RES_LITE | SHOW_MODS
+D:A slender, tapered blade whose wielder strikes icy blows with deadly
+D:accuracy.
+
+
+# The Sabre 'Careth Asdriag'
+
+N:87:'Careth Asdriag'
+I:23:11:2
+W:15:8:50:25000
+P:0:2d7:6:8:0
+F:DEX | BLOWS | SPEED | CON |
+F:SLAY_DRAGON | SLAY_ANIMAL | SLAY_TROLL | SLAY_GIANT |
+F:SLAY_ORC | SHOW_MODS | ESP_ANIMAL
+D:An heirloom of the Lords of Rhun far to the east, and a name of
+D:dismay to creatures natural and unnatural.
+
+# The Short Sword 'Sting'
+
+N:88:'Sting'
+I:23:10:2
+W:20:205:75:100000
+P:0:1d7:7:8:0
+F:BLOWS | CON | DEX | ESP_ORC | ESP_SPIDER | ESP_UNDEAD | FREE_ACT |
+F:LEVELS | LITE1 | RES_LITE | SEE_INVIS | SHOW_MODS | SLAY_ANIMAL |
+F:SLAY_EVIL | SLAY_ORC | SLAY_UNDEAD | SPEED | STR
+D:The perfect size for Bilbo, and stamped forever by the courage he found
+D:in Mirkwood, this sturdy little blade grants the wearer combat prowess
+D:and survival abilities they did not know they had. The blade is inscribed
+D:with Tengwar writing -- "Sting is my name, I am the spiders' bane."
+
+# The Scimitar 'Haradekket'
+
+N:89:'Haradekket'
+I:23:18:2
+W:20:8:130:111111
+P:0:2d5:9:11:0
+F:INT | WIS | BLOWS |
+F:SLAY_ANIMAL | SLAY_EVIL | SLAY_UNDEAD | SLAY_DRAGON | SLAY_DEMON |
+F:RES_CHAOS | RES_DISEN | RES_NEXUS |
+F:SEE_INVIS | BLESSED |
+F:SHOW_MODS
+D:A damascened scimitar that seems wondrously easy to hold. Famed in song as
+D:the "Sickle of Harad", and a deadly foe to the undead.
+
+
+# The Short Sword 'Gilettar'
+
+N:90:'Gilettar'
+I:23:10:2
+W:20:8:80:35000
+P:0:1d7:3:7:0
+F:BLOWS | HIDE_TYPE |
+F:SLAY_ANIMAL | SLOW_DIGEST | REGEN | SHOW_MODS | SEE_INVIS | RES_DISEN
+D:A stubby blade worn by Beren, whose horn sounded of old in the glades of
+D:Brethil.
+
+# The Blade of Chaos 'Daedheloth'
+
+N:91:'Daedheloth'
+I:23:30:0
+W:70:25:180:250000
+P:0:6d5:18:28:-50
+F:KILL_DRAGON | SLAY_ANIMAL | SLAY_EVIL | BRAND_COLD | SLAY_TROLL |
+F:SLAY_ORC | FREE_ACT | RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:RES_CHAOS | SEE_INVIS | ESP_EVIL | AGGRAVATE | SHOW_MODS |
+F:CHAOTIC | VORPAL | BRAND_FIRE | BRAND_POIS | SPECIAL_GENE
+D:This weapon of wrath, cursed with a violent anger, dives hungrily
+D:into the flesh of its enemies. It gathers shadows of death into its
+D:owner as they inflict wounds that will never heal.
+
+# The Long Sword 'Sereghathol'
+
+N:92:'Sereghathol'
+I:23:17:2
+W:50:30:150:250000
+P:0:5d5:32:32:0
+F:DEX | FREE_ACT | LEVELS | REGEN | SEE_INVIS | SLAY_EVIL | SLOW_DIGEST | SPEED | STR | VORPAL | WOUNDING
+D:Blood-Sword it is called, after its thirst for the blood of foes.
+
+# The Beaked Axe of Dain Ironfoot
+
+N:93:of Dain Ironfoot
+I:22:10:3
+W:20:15:180:40000
+P:0:2d6:8:10:0
+F:WIS | CON | HIDE_TYPE |
+F:SLAY_DRAGON | ESP_EVIL | ESP_UNDEAD | SLOW_DIGEST | ACTIVATE | SHOW_MODS
+a:HARDCORE=DRAIN_2
+D:The narrow axe head of this weapon, finely balanced by a crow's beak,
+D:would pierce even the armour of Smaug, and its wielder becomes aware of
+D:the minds of their enemies.
+
+
+# The Glaive of Pain
+
+N:94:of Pain
+I:22:13:0
+W:30:155:190:50000
+P:0:9d6:0:30:0
+F:SHOW_MODS | LEVELS | DRAIN_MANA |
+F:COULD2H
+f:COULD2H
+D:The massive chopper that crowns this glaive glows blood-red and black;
+D:fell spells of annihilation swirl and dance as you swing death's myrmidon
+D:down.
+
+
+# The Halberd 'Osondir'
+
+N:95:'Osondir'
+I:22:15:3
+W:20:8:190:22000
+P:0:3d5:6:9:0
+F:CHR | HIDE_TYPE |
+F:BRAND_FIRE | SLAY_UNDEAD | SLAY_GIANT | RES_FIRE | RES_SOUND |
+F:FEATHER | SEE_INVIS | SHOW_MODS | ESP_GIANT |
+F:COULD2H
+f:COULD2H
+D:Lordly and tall did Osondir stand against the wrath of giants, and
+D:clear-eyed in barrows fell, wielding a halberd glowing ruby red.
+
+
+# The Pike 'Til-i-arc'
+
+N:96:'Til-i-arc'
+I:22:8:2
+W:20:15:160:32000
+P:0:2d5:10:12:10
+F:INT | HIDE_TYPE |
+F:BRAND_COLD | BRAND_FIRE | SLAY_DEMON | SLAY_TROLL | SLAY_GIANT | ESP_GIANT
+F:RES_FIRE | RES_COLD | SUST_INT | SLOW_DIGEST | SHOW_MODS |
+F:COULD2H
+f:COULD2H
+D:Within this long thrusting spear lie the spirits of frost giants and fire
+D:demons, who war forever, trapped by magely spells.
+
+# The Spear 'Aiglos'
+
+N:97:'Aiglos'
+I:22:2:4
+W:15:45:50:180000
+P:0:3d6:15:25:5
+F:DEX | WIS | HIDE_TYPE |
+F:BRAND_COLD | BRAND_ELEC | LITE1 |
+F:SLAY_TROLL | SLAY_ORC | SLAY_GIANT | KILL_UNDEAD |
+F:FREE_ACT | RES_COLD | RES_ELEC | RES_LITE |
+F:SLOW_DIGEST | ACTIVATE | BLESSED | SHOW_MODS
+a:HARDCORE=BA_ELEC_2
+D:The mighty spear of Gil-galad, famed as "Snow-point" in the songs of
+D:Elves, against which all the foul corruptions of Sauron dashed in vain.
+D:The spear is inscribed with Tengwar runes, reading "Gil-galad ech vae
+D:vaegannen matha, / Aith heleg nin i orch gostatha; / Nin cíniel na
+D:nguruthos / Hon ess nín istatha --
+D:well-made spear, / The Orc will fear my point of ice; / When he sees me,
+D:in fear of death / he will know my name
+
+# The Spear of Caradhras
+
+N:98:of Caradhras
+I:22:2:4
+W:15:45:50:77777
+P:0:4d6:15:15:0
+F:INT | WIS | SPEED | TUNNEL | INFRA | HIDE_TYPE | SEARCH |
+F:BRAND_FIRE |
+F:SLAY_GIANT | SLAY_EVIL | SLAY_DEMON | SLAY_UNDEAD | SLAY_DRAGON |
+F:RES_FIRE | RES_LITE | HOLD_LIFE | RES_FEAR | FEATHER | ESP_GIANT |
+F:SEE_INVIS | ACTIVATE | BLESSED | SHOW_MODS
+a:HARDCORE=STONE_MUD
+D:A magical spear, rumoured to have been forged by Orome himself
+D:in the coldest reach of the cruel Redhorn.
+
+# The Spear 'Nimloth'
+
+N:99:'Nimloth'
+I:22:2:3
+W:15:12:50:30000
+P:0:1d6:11:13:0
+F:STEALTH | RES_DARK | INFRA | SPEED | BLESSED |
+F:BRAND_COLD | SLAY_UNDEAD | RES_COLD | SEE_INVIS | SHOW_MODS
+D:A thin spike of thrice-forged steel caps a straight sylvan shaft cut from
+D:a legendary tree; spells to break the will of the undead and strike cold
+D:fear into the hearts of foes lie on this perfectly balanced spear.
+
+
+# The Lance of Eorlingas
+
+N:100:of Eorlingas
+I:22:20:2
+W:20:23:360:55000
+P:0:3d8:3:21:0
+F:STR | DEX | SPEED | HIDE_TYPE | RES_FEAR |
+F:SLAY_EVIL | SLAY_TROLL | SLAY_ORC | SEE_INVIS | SHOW_MODS |
+F:MUST2H
+f:MUST2H
+D:"Forth Eorlingas!". To the field of Cormallen came Eorl the Young
+D:to save beleaguered Gondor, and from his lance fled massive trolls
+D:and dire wolves.
+
+
+# The Great Axe of Durin
+
+N:101:of Durin
+I:24:25:3
+W:30:90:230:150000
+P:0:4d4:10:20:15
+F:STR | CON | TUNNEL | HIDE_TYPE | ESP_EVIL | RES_FEAR |
+F:SLAY_DRAGON | KILL_DEMON | SLAY_TROLL | SLAY_ORC | FREE_ACT |
+F:RES_ACID | RES_FIRE | RES_LITE | RES_DARK | RES_CHAOS | SHOW_MODS |
+F:BRAND_ACID | BRAND_FIRE |
+F:MUST2H
+f:MUST2H
+D:The twin massive axe heads of this ancient demon's dread gleam with
+D:mithril inlay, which tell sagas of endurance, invoking the powers of
+D:Khazad-dum to protect the wearer and slay all evils found underground.
+
+
+# The Great Axe of Eonwe
+
+N:102:of Eonwe
+I:24:25:2
+W:30:120:230:200000
+P:0:4d4:15:18:8
+F:STR | INT | WIS | DEX | CON | CHR | HIDE_TYPE |
+F:SLAY_EVIL | BRAND_COLD | KILL_DEMON | SLAY_UNDEAD | ESP_NONLIVING
+F:SLAY_ORC | FREE_ACT | IM_COLD | SEE_INVIS | ACTIVATE |
+F:BLESSED | SHOW_MODS
+a:HARDCORE=MASS_GENO
+D:The axe of Eonwe, leader of the Hosts of the West before the gates of
+D:Thangorodrim, strikes with icy wrath at the undead, disperses hosts of
+D:evil at a word, and grants Maia-like powers of body and mind.
+
+
+# The Battle Axe of Balli Stonehand
+
+N:103:of Balli Stonehand
+I:22:22:3
+W:30:15:170:90000
+P:0:3d8:8:11:5
+F:STR | CON | STEALTH | HIDE_TYPE | ESP_NONLIVING
+F:SLAY_DEMON | SLAY_TROLL | SLAY_ORC | FREE_ACT |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_BLIND | FEATHER |
+F:SEE_INVIS | REGEN | SHOW_MODS |
+F:COULD2H
+f:COULD2H
+D:The twin blades of this weapon were forged in Belegost, and powerful forces
+D:to resist and endure lie ready for he who shall wield it once more.
+
+
+# The Battle Axe 'Lotharang'
+
+N:104:'Lotharang'
+I:22:22:1
+W:30:15:170:21000
+P:0:2d8:4:3:0
+F:STR | DEX | HIDE_TYPE |
+F:SLAY_TROLL | SLAY_ORC | ACTIVATE | SHOW_MODS
+a:HARDCORE=CURE_MW
+D:A superbly crafted double-bladed axe that slays the creatures of earth and
+D:allows rapid recovery from their blows.
+
+
+# The Lochaber Axe 'Mundwine' -> of the Dwarves
+
+N:105:of the Dwarves
+I:22:28:10
+W:30:8:250:80000
+P:0:3d8:12:17:0
+F:SLAY_EVIL | TUNNEL | INFRA | SEARCH | SLAY_GIANT |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_FEAR |
+F:SHOW_MODS |
+F:COULD2H
+f:COULD2H
+D:A massive axe with twin razor-sharp heads, so large that it usually
+D:requires two hands to wield, intricately engraved in gold with spells
+D:to ward off the elements and smite evil.
+
+# The Broad Axe 'Barukkheled'
+
+N:106:'Barukkheled'
+I:24:11:3
+W:20:8:160:50000
+P:0:2d6:13:19:0
+F:CON | HIDE_TYPE |
+F:SLAY_EVIL | SLAY_TROLL | SLAY_GIANT | SLAY_ORC |
+F:SEE_INVIS | SHOW_MODS |
+F:COULD2H
+f:COULD2H
+D:A royal heirloom of the southern coast, strong in combat against evil
+D:creatures of the earth.
+
+# The Broad Sword 'Guthwine' - sword of Eomer
+# Replaces the Trident of Wrath in Theme
+
+N:107:'Guthwine'
+I:23:16:1
+W:30:10:150:45000
+P:0:2d6:6:7:0
+F:CRIT | ESP_ORC | HIDE_TYPE | LITE1 | RES_BLIND | RES_FEAR |
+F:SHOW_MODS | SLAY_ORC | WOUNDING
+D:The sword of Eomer, son of Eomund, leader of the Riders of the Mark.
+D:As one flashed this sword with Anduril during a battle long ago.
+D:Legendary are its powers in the rallying of desperate troops.
+
+# The Trident of Osse
+
+N:108:of Osse
+I:22:5:4
+W:30:90:70:120000
+P:0:4d8:15:19:0
+F:DEX | HIDE_TYPE |
+F:SLAY_DRAGON | SLAY_ANIMAL | FREE_ACT | HOLD_LIFE | IM_ACID |
+F:RES_NETHER | SEE_INVIS | SLOW_DIGEST | REGEN | ACTIVATE |
+F:BLESSED | SHOW_MODS | WATER_BREATH
+a:HARDCORE=TELE_AWAY
+D:The awesome weapon imbued with some of the power of the Vala Ulmo,
+D:Lord of Waters. It allows the wearer to laugh in scorn at the dread
+D:powers of the undead, and be utterly in command of the element of water.
+
+# The Scythe 'Avavir'
+
+N:109:'Avavir'
+I:22:17:3
+W:40:8:250:18000
+P:0:5d3:8:8:10
+F:DEX | CHR | HIDE_TYPE |
+F:BRAND_COLD | BRAND_FIRE | FREE_ACT | RES_FIRE | RES_COLD |
+F:RES_LITE | SEE_INVIS | ACTIVATE | SHOW_MODS |
+F:COULD2H
+f:COULD2H
+a:HARDCORE=RECALL
+D:With elemental powers whose struggles turn this weapon red and purest
+D:white, this shining reaper bears within it a power of going forth and
+D:returning.
+
+# The Long Sword of Dernhelm - from T-Plus by Ingeborg S. Norden
+# Replaces the Long Sword of the Dawn in Theme
+
+N:110:of Dernhelm
+I:23:17:5
+W:70:50:150:250000
+P:0:3d5:20:25:0
+F:BLESSED | ESP_UNIQUE | FREE_ACT | HIDE_TYPE | HOLD_LIFE | KILL_UNDEAD |
+F:LITE1 | LUCK | RES_DISEN | RES_FEAR | RES_MORGUL | SEE_INVIS |
+F:SHOW_MODS | SLAY_EVIL | SPEED | STEALTH | VORPAL | WOUNDING | SPECIAL_GENE
+D:Eomer's sister Eowyn once wielded this shining sword when she
+D:battled the Witch-King of Angmar, hiding her true identity to
+D:join the battle. Others are less likely to notice the wielder
+D:immediately. Eowyn's sword also allowed her to move swiftly,
+D:sense powerful enemies, inflict terrible wounds, and partly
+D:withstand the worst attacks of the Nazgul.
+
+# The Mighty Hammer 'Grond'
+
+N:111:'Grond'
+I:21:50:2
+W:100:1:1000:500000
+P:0:9d9:25:25:10
+F:KILL_DRAGON | SLAY_ANIMAL | SLAY_EVIL | IMPACT | KILL_UNDEAD | NO_MAGIC |
+F:KILL_DEMON | SLAY_TROLL | SLAY_ORC | RES_ACID | RES_ELEC | RES_FIRE |
+F:RES_COLD | SEE_INVIS | ESP_ALL | AGGRAVATE | SHOW_MODS | INSTA_ART |
+F:LEVELS | ACTIVATE | SPECIAL_GENE |
+F:MUST2H
+f:MUST2H
+a:HARDCORE=GROND
+D:The mighty Hammer of the Underworld, blackened by doomspells of shattering,
+D:whose wielder holds the lives of all Morgoth's servants in his hand.
+
+# The Flail 'Totila'
+
+N:112:'Totila'
+I:21:13:2
+W:20:8:150:55000
+P:0:3d6:6:8:0
+F:STEALTH |
+F:SLAY_EVIL | BRAND_FIRE | RES_FIRE | RES_CONF | ACTIVATE |
+F:SHOW_MODS | LITE1 |
+F:COULD2H
+f:COULD2H
+a:HARDCORE=CONFUSE
+D:A flail whose head befuddles those who stare as you whirl it around, and
+D:becomes a fiery comet as you bring it down.
+
+
+# The Two-Handed Flail 'Thunderfist'
+
+N:113:'Thunderfist'
+I:21:18:4
+W:45:38:300:160000
+P:0:3d6:5:18:0
+F:STR | CON | HIDE_TYPE | RES_FEAR |
+F:SLAY_ANIMAL | BRAND_FIRE | BRAND_ELEC | SLAY_TROLL | SLAY_ORC |
+F:RES_ELEC | RES_FIRE | RES_DARK | SHOW_MODS |
+F:MUST2H
+f:MUST2H
+D:The long-lost weapon of Kzurin, Dwarven champion of ancient Belegost,
+D:with runes of strength in its handle, and flames and sparks that roar and
+D:crackle around its massive head.
+
+# The Morning Star 'Maegnas-in-sereg'
+
+N:114:'Maegnas-in-sereg'
+I:21:12:4
+W:20:30:150:30000
+P:0:2d6:8:22:0
+F:STR | HIDE_TYPE | BRAND_POIS |
+F:SLAY_ANIMAL | SLAY_TROLL | SLAY_ORC | RES_NEXUS | SEE_INVIS |
+F:SHOW_MODS
+D:You feel strong and firm of foot as you whip the chain-suspended spiked orb
+D:around - and bathe it in the blood of your foes.
+
+# The Morning Star 'Naurgil'
+
+N:115:'Naurgil'
+I:21:12:0
+W:20:100:150:35000
+P:0:2d6:5:7:2
+F:BRAND_FIRE | IM_FIRE | ACTIVATE | SHOW_MODS | LITE1
+a:HARDCORE=FIRESTAR
+D:A famed battle-lord of old, with a ruddy head, coloured as embers are that
+D:can yet rise up in wrath.
+
+
+# The Mace 'Taratol'
+
+N:116:'Taratol'
+I:21:5:0
+W:20:15:200:50000
+P:0:3d4:12:12:0
+F:KILL_DRAGON | BRAND_ELEC | IM_ELEC | ACTIVATE | SHOW_MODS |
+F:COULD2H
+f:COULD2H
+a:HARDCORE=SPEED
+D:A great ridged mace that calls around you a nimbus of living lightning;
+D:you remain utterly untouched even as fat sparks arc around your
+D:fingers and eyebrows.
+
+# The War Hammer of Gamil Zirak
+
+N:117:of Gamil Zirak
+I:21:8:4
+W:40:75:120:250000
+P:0:9d3:19:21:5
+F:WIS | TUNNEL | HIDE_TYPE | RES_FEAR |
+F:KILL_DRAGON | SLAY_EVIL | BRAND_ELEC | SLAY_UNDEAD | SLAY_DEMON |
+F:FREE_ACT | RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_NEXUS |
+F:SEE_INVIS | SHOW_MODS |
+F:COULD2H
+f:COULD2H
+D:Gamil Zirak was a great craftsman, the master of Telchar of Nogrod.
+D:This weapon was rescued from Thingol's treasury, and it is rumoured
+D:that its wielder need not fear dragons or other fell beings of the
+D:Dark.
+
+# The Quarterstaff 'Nar-i-vagil'
+
+N:118:'Nar-i-vagil'
+I:21:3:3
+W:20:18:150:70000
+P:0:1d9:10:20:0
+F:INT | HIDE_TYPE |
+F:SLAY_ANIMAL | BRAND_FIRE | RES_FIRE | SHOW_MODS |
+F:COULD2H
+f:COULD2H
+D:Named for a fiery star and set with gems of great worth binding mystic
+D:virtues of protection and thought.
+
+
+# The Quarterstaff 'Eriril'
+
+N:119:'Eriril'
+I:21:3:4
+W:20:18:150:20000
+P:0:1d9:3:5:0
+F:INT | WIS | HIDE_TYPE | ESP_EVIL | SPELL_CONTAIN | WIELD_CAST
+F:SLAY_EVIL | RES_LITE | SEE_INVIS | ACTIVATE | SHOW_MODS
+a:HARDCORE=ID_PLAIN
+D:The radiant golden staff of an Istari of legend, this wizard's companion
+D:grants keen sight and the knowledge of many hidden things.
+
+
+# The Quarterstaff of Olorin
+
+N:120:of Olorin
+I:21:3:4
+W:30:105:150:140000
+P:0:2d9:10:13:0
+F:INT | WIS | CHR | HIDE_TYPE | SEARCH | BRAND_FIRE |
+F:SLAY_EVIL | BRAND_FIRE | SLAY_TROLL | SLAY_ORC | SPELL_CONTAIN | WIELD_CAST
+F:HOLD_LIFE | RES_FIRE | RES_NETHER | SEE_INVIS | ACTIVATE | SHOW_MODS
+a:HARDCORE=DETECT_XTRA
+D:A staff tall and sturdy, with rough-hewn runes that invoke the element of
+D:Earth, and which strikes down all creatures who live in the shadow of
+D:mountains.
+
+# The Mace of Disruption 'Nguruthos'
+
+N:121:'Nguruthos'
+I:21:20:6
+W:80:38:400:444444
+P:0:7d8:18:18:0
+F:STR | TUNNEL | HIDE_TYPE | NO_TELE | DRAIN_MANA |
+F:SLAY_DRAGON | SLAY_ANIMAL | SLAY_EVIL | KILL_UNDEAD | BRAND_FIRE |
+F:IM_FIRE | RES_DARK | RES_CHAOS | RES_DISEN | AGGRAVATE |
+F:SHOW_MODS | BRAND_POIS | VAMPIRIC |
+F:MUST2H
+f:MUST2H
+D:A weapon so massive it seems beyond the strength of mortals, yet you feel
+D:the might of giants within you as you heft it. As you grip the handle
+D:of ebony and steel, coronas of fire blaze and mighty spells to preserve
+D:magic activate around you. It is named 'Fear of Death' - you wield the
+D:Fear of Dragons and the Despair of the Undead.
+
+# The Lucerne Hammer 'Turmil'
+
+N:122:'Turmil'
+I:21:10:4
+W:20:15:120:30000
+P:0:2d5:10:6:8
+F:WIS | INFRA | HIDE_TYPE |
+F:BRAND_COLD | SLAY_ORC | RES_COLD | RES_LITE | REGEN |
+F:ACTIVATE | SHOW_MODS | ESP_ORC | ESP_TROLL | ESP_GIANT |
+F:COULD2H
+f:COULD2H
+a:HARDCORE=TURMIL
+D:Wielded by the High Priest of Meneltarma, this great mace gleams coldly as
+D:though moonlit, and it can strike as mighty a blow spiritually as
+D:physically.
+
+
+# The Whip of Gothmog
+
+N:123:of Gothmog
+I:21:2:-2
+W:20:15:120:100000
+P:0:3d6:15:16:0
+F:INT | DEX | INFRA | HIDE_TYPE | DRAIN_HP | HEAVY_CURSE |
+F:CURSED | AGGRAVATE | BRAND_FIRE | SLAY_ANIMAL | SLAY_DEMON |
+F:RES_FIRE | ESP_SPIDER | VORPAL | RES_LITE | LITE1 | REGEN |
+F:ESP_DEMON | WOUNDING | SHOW_MODS
+D:With this unbearably bright whip of flame, the Balrog Gothmog has become
+D:known for never having lost in combat.
+
+
+# The Long Bow 'Belthronding'
+
+N:124:'Belthronding'
+I:19:13:3
+W:40:20:40:35000
+P:0:0d0:20:22:0
+F:DEX | STEALTH | HIDE_TYPE |
+F:RES_DISEN | XTRA_SHOTS | SHOW_MODS
+D:The great bow of Beleg, made of black yew and strung with elven hair that
+D:faintly shines a pale clear gold.
+
+
+# The Long Bow of Bard
+
+N:125:of Bard
+I:19:13:2
+W:30:20:40:20000
+P:0:0d0:17:19:0
+F:DEX | HIDE_TYPE | ESP_DRAGON | LUCK
+F:FREE_ACT | XTRA_MIGHT | SHOW_MODS
+D:The great yew bow of grim-faced Bard, who shot the mightiest arrow that
+D:songs record.
+
+
+# The Light Crossbow 'Cubragol'
+
+N:126:'Cubragol'
+I:19:23:10
+W:50:25:110:50000
+P:0:0d0:10:14:0
+F:SPEED | HIDE_TYPE |
+F:RES_FIRE | ACTIVATE | SHOW_MODS
+a:HARDCORE=CUBRAGOL
+D:A crossbow that grants fiery speed to he who finds it, and from which
+D:shoot bolts that blaze with flame unquenchable.
+
+# The Mage Staff of Manwe
+# The ULTIMATE "weapon" for a mage
+
+N:127:of Manwe
+I:6:1:12
+W:127:220:20:9000000
+P:0:1d4:-19:-19:0
+F:INT | CHR | WIS | MANA | SPELL | ACTIVATE | LUCK |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | SPECIAL_GENE |
+F:SEE_INVIS | ESP_EVIL | ESP_DEMON | NEVER_BLOW | INFRA |
+F:PRECOGNITION | IM_FIRE | ULTIMATE | SPELL_CONTAIN | WIELD_CAST |
+F:COULD2H
+f:COULD2H
+a:HARDCORE=GANDALF
+D:A simple, wooden wizard's staff. Unremarkable in all aspects...
+D:except that it pulses with overwhelming power.
+
+# Boomerang Artifacts
+
+# The Metal Boomerang of Beor
+
+N:128:of Beor
+I:15:4:4
+W:20:10:20:40000
+P:0:4d5:8:12:0
+F:DEX | SPEED |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD
+D:Beor's boomerang makes its wielder as agile as the winds,
+D:and as hard to harm.
+
+
+# The Metal Boomerang 'Glimdrir'
+
+N:129:'Glimdrir'
+I:15:4:3
+W:40:20:20:60000
+P:0:5d5:15:16:0
+F:DEX | SPEED | FREE_ACT | BRAND_POIS | SLAY_EVIL | SLAY_UNDEAD | REGEN
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_SOUND | NO_TELE | CURSED
+D:A powerful boomerang that makes one agile and fast, with a thirst for
+D:evil and undead creatures, but demands its wielder not teleport, for fear
+D:of desertion.
+
+
+# The Robe of Incanus [aka Gandalf]
+
+N:130:of Incanus
+I:36:2:3
+W:30:20:20:60000
+P:2:0d0:0:0:20
+F:INT | WIS | SEARCH | HIDE_TYPE | SPELL_CONTAIN | WIELD_CAST
+F:SUST_INT | SUST_WIS | FREE_ACT | SEE_INVIS |
+F:RES_ACID | RES_ELEC | IM_FIRE | RES_COLD
+Z:weigh magic
+D:Gandalf's long, flowing robe. It provides insight and allows the
+D:wearer to see things not seen by all.
+
+
+# The Sling of the Thain
+
+N:131:of the Thain
+I:19:2:4
+W:40:20:40:35000
+P:0:0d0:15:15:0
+F:HIDE_TYPE | DEX | CON
+F:RES_NETHER | XTRA_SHOTS | XTRA_MIGHT | SHOW_MODS
+D:This sling was crafted by Faramir I, Thain of the Shire, just in case
+D:the nasties of his father's stories ever dare to enter the Shire again.
+
+# The Small Metal Shield of Gimli
+
+N:132:of Gimli
+I:34:3:3
+W:40:3:65:80000
+P:3:0d0:9:10:40
+F:INT | CON | RES_FEAR | HIDE_TYPE | IM_FIRE | RES_SHARDS
+Z:find secret passages
+D:A gift from the King of Rohan to Gimli the Dwarf, this shield
+D:combines the cunning and stamina of Gimli Elf-friend, Gimli the
+D:Lock-bearer.
+
+# The Bearded Axe of Gimli
+
+N:133:of Gimli
+I:24:3:2
+W:35:60:35:65000
+P:0:1d6:5:15:0
+F:STR | BLOWS | LEVELS | SLAY_ORC | FREE_ACT | VORPAL |
+F:ESP_UNDEAD | ESP_NONLIVING | COULD2H
+f:COULD2H
+D:"Gimli sensed the Dead behind following, but he continued on
+D:after Aragorn." The trusty axe of Gimli son of Gloin, one of
+D:the Nine Walkers of old.
+
+# The Whip 'Lasher'
+
+N:134:'Lasher'
+I:21:2:3
+W:20:5:30:50000
+P:0:1d6:12:15:0
+F:DEX | BLOWS | HIDE_TYPE |
+F:SLAY_ANIMAL | SLAY_ORC | BRAND_POIS | VORPAL |
+F:RES_POIS | FREE_ACT | ESP_ORC
+D:A powerful whip that is deadly against orcs. It poisons your foes
+D:and is said to go "snicker snack".
+
+# The Harp of Thorin
+
+N:135:of Thorin
+I:14:59:2
+W:50:10:30:40000
+P:0:1d1:0:0:0
+F:ACTIVATE | CHR | INFRA | INSTA_ART | LUCK | STEALTH | SUST_CHR | TUNNEL
+a:HARDCORE=CHARM_OTHERS
+Z:remove fear
+D:This magical instrument once belonged to Thorin Oakenshield,
+D:a mighty dwarf warrior of old. The sounds emanating from it
+D:once gave a frightened hobbit a glimpse of beauty and helped
+D:allay his fears, and to this day the harp preserves its magical
+D:powers to encourage when all seems horribly wrong.
+
+# The Mithril Helm of Thorin
+
+N:136:of Thorin
+I:32:8:3
+W:40:5:20:55000
+P:10:2d4:0:0:0
+F:ACTIVATE | DEX | HIDE_TYPE | HOLD_LIFE | REGEN | RES_FEAR | SUST_CON | SUST_DEX | SUST_STR
+a:HARDCORE=TERROR
+D:Mighty was Thorin Oakenshield as he emerged from the Gate of the
+D:Lonely Mountain on the day of the Battle of the Five Armies, clad
+D:in shining armour, part of which was this helm. He gleamed like
+D:gold in the dying fire of the day, red light leapt from his
+D:eyes, and his foes were terrified at the mere sight of him.
+
+# The Harp of Maglor
+
+N:137:of Maglor
+I:14:59:3
+W:60:10:20:100000
+P:0:3d4:0:0:0
+F:CHR | SPEED | WIS | SEE_INVIS | RES_SOUND | STEALTH | LUCK
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | ESP_UNIQUE
+D:This harp that once belonged to Maglor makes those who use it seem
+D:more forceful and convincing. It is also said that those who have
+D:used it found themselves walking faster, as if to an unheard beat.
+
+
+# The Drum of the Sky
+
+N:138:of the Sky
+I:14:58:2
+W:40:10:15:80000
+P:0:3d4:0:0:0
+F:CHR | SPEED | WIS | SEE_INVIS | RES_SOUND | STEALTH | LUCK
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD
+D:The drum is decorated with the images of the stars, the clouds, the
+D:Sun guided by Arien and the Moon with Tilion. It imparts to the
+D:wearer an echo of the beauty of the sky, and protects him from the
+D:elements day or night. The beat of the drum marks the passage of
+D:time, and will make time pass differently for the wearer.
+
+
+# The Harp of Daeron
+
+N:139:of Daeron
+I:14:59:1
+W:20:10:10:50000
+P:0:3d4:0:0:0
+F:CHR | SPEED | WIS | RES_SOUND | STEALTH | LUCK
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD
+D:A pretty harp that makes those who play it beautiful, wise and
+D:fast.
+
+
+# The Dwarven Pick of Erebor
+
+N:140:of Erebor
+I:20:6:5
+W:50:15:200:55000
+P:0:3d4:5:0:0
+F:STR | TUNNEL | SUST_STR | HIDE_TYPE | LITE1 | ACTIVATE | CLIMB
+F:RES_CHAOS | RES_LITE | RES_DARK
+a:HARDCORE=EREBOR
+D:A pick that provides a magical light by which to see while tunnelling.
+
+
+# The Drum of the Druedain
+
+N:141:of the Druedain
+I:14:58:4
+W:19:10:15:10000
+P:0:3d4:0:0:0
+F:ACTIVATE | STEALTH | SEARCH | INFRA | RES_POIS | RES_DARK
+a:HARDCORE=DRUEDAIN
+D:The fabled Drum of the Druedain that will protect those who play it
+D:from darkness and poison attacks. It also aids in the seeing of
+D:warm-blooded creatures.
+
+
+# The Horn of Rohan
+
+N:142:of Rohan
+I:14:60:2
+W:14:10:15:80000
+P:0:3d4:0:0:0
+F:ACTIVATE | CHR | WIS | ESP_DRAGON
+a:HARDCORE=ROHAN
+D:A horn carved from the bones of the Dragon of Ered-Mithrin, this
+D:heirloom of the House of Eorl bestows to its user the gifts of
+D:courage and command.
+
+
+# The Horn of Helm
+
+N:143:of Helm
+I:14:60:2
+W:16:10:15:15000
+P:0:3d4:0:0:0
+F:ACTIVATE | STR | CON | IM_COLD | RES_NETHER | RES_FEAR
+a:HARDCORE=HELM
+D:Heedless of cold, fearless of darkness -- besiegers fled at the wind
+D:of the solitary coming of King Helm Hammerhand, proclaimed by a single
+D:horn-blast in the dead of winter.
+
+
+# The Horn of Boromir
+
+N:144:of Boromir
+I:14:60:3
+W:18:10:15:18000
+P:0:3d4:0:0:0
+F:ACTIVATE | STR | CON | RES_FEAR | RES_FIRE | AGGRAVATE
+a:HARDCORE=BOROMIR
+D:The great horn made of the horns of kine of Araw. It is inlaid with silver
+D:and gold signs; when blown, it can be heard for miles over. The horn gives
+D:courage and endurance to its wearer, provided that secrecy is not desired.
+D:"Loud and clear it sounds in the valleys of the hills... and then let all
+D:the foes of Gondor flee!"
+
+# The Lochaber Axe of Gothmog, which slew Fingon
+
+N:145:of Gothmog
+I:22:28:-4
+W:30:8:250:30000
+P:0:3d8:14:19:0
+F:BRAND_FIRE | IM_FIRE | CHR | ACTIVATE | SHOW_MODS | CURSED | TY_CURSE
+a:HARDCORE=AXE_GOTHMOG
+D:The black axe of Gothmog, which struck Fingon at Nirnaeth. Mighty
+D:spells of evil make it unsafe in any hands but those of its original wielder.
+
+
+# The Seeker Arrow of Gondor
+
+N:146:of Gondor
+I:17:2:0
+W:20:5:3:25000
+P:0:10d8:10:20:0
+F:SLAY_EVIL | SLAY_DEMON
+D:An arrow that was created to rid the world of demons.
+
+# The Long Sword of Tulkas
+# The ULTIMATE weapon for a Swordmaster class
+
+N:147:of Tulkas
+I:23:17:10
+W:127:220:130:9000000
+P:0:5d6:21:26:50
+F:LIFE | CON | CHR | LUCK
+F:SUST_STR | SUST_INT | SUST_WIS | SUST_DEX | SUST_CON | SUST_CHR |
+F:BRAND_FIRE | BRAND_COLD | BRAND_ELEC | VORPAL | IM_COLD |
+F:SLAY_EVIL | SLAY_UNDEAD | SLAY_DEMON | SLAY_TROLL | SLAY_DEMON |
+F:FREE_ACT | RES_FIRE | RES_DARK | LITE1 | SEE_INVIS | SLOW_DIGEST | REGEN |
+F:ACTIVATE | SHOW_MODS | BLESSED |
+F:PRECOGNITION | NO_MAGIC | ULTIMATE | SPECIAL_GENE
+a:HARDCORE=ERU
+D:A warm light bathes this translucent blade. The power of the fates are
+D:at the command of its wielder as the weapon passes Supreme Judgment on
+D:the inhabitants of Angband.
+
+
+# The Robe of Great Luck
+
+N:148:of Great Luck
+I:36:2:60
+W:50:120:20:60000
+P:2:0d0:0:0:0
+F:LUCK | HIDE_TYPE |
+F:FREE_ACT | DRAIN_HP | DRAIN_MANA
+D:A powerful wizard once created this robe to grant him incredible luck....
+D:It seems he forgot to wear it.
+
+
+# The Sling of Farmer Maggot
+
+N:149:of Farmer Maggot
+I:19:2:2
+W:10:10:5:20000
+P:0:0d0:20:0:0
+F:INFRA | SEARCH | HIDE_TYPE |
+F:XTRA_SHOTS | SHOW_MODS | ACTIVATE | SPECIAL_GENE
+a:SPELL=Artifact Maggot
+D:This ordinary seeming leather sling has been raised to legendary
+D:status amongst generations of hobbit children. Farmer Maggot's
+D:ability to notice and strike any mushroom thief anywhere within
+D:his patch almost keeps young poachers at bay, but once they get
+D:within range they soon flee for less painful pastures, frequently
+D:with rounded pebbles stinging their backsides...
+
+
+# The Long Sword of Angmar (a.k.a. anti-Ringil)
+# The next time someone wields an unidentified Long Sword (4d5) ...
+
+N:150:of Angmar
+I:23:17:-10
+W:20:40:130:30000
+P:0:4d5:-22:-25:0
+F:SPEED | STR | WIS | CHR | ESP_UNDEAD
+F:BRAND_FIRE | SEE_INVIS | SLOW_DIGEST | FREE_ACT |
+F:VAMPIRIC | NO_TELE | AGGRAVATE | WRAITH | INVIS |
+F:CURSED | HEAVY_CURSE | DG_CURSE | SHOW_MODS | CLONE
+D:Dark flames wreath the naked steel of the Witch-King of Angmar.
+D:A mighty curse to all those who wield it apart from its master,
+D:the torture of the wraithworld awaits those who dare.
+
+
+# The Seeker Bolt of Feanor
+
+N:151:of Feanor
+I:18:2:0
+W:127:220:130:100000
+P:0:5d5:5:6:0
+F:BRAND_COLD | BRAND_FIRE | BRAND_ELEC | BRAND_ACID | BRAND_POIS |
+F:SLAY_DRAGON | SLAY_GIANT | SLAY_TROLL | KILL_UNDEAD | SLAY_ORC |
+F:SLAY_DEMON | SLAY_EVIL | SPECIAL_GENE
+D:Made during the war against Morgoth by Feanor, this powerful
+D:bolt is the bane of Morgoth's power, and has especial strength
+D:against those foes who are already dead.
+
+# The Heavy Crossbow of Orome
+# The ULTIMATE crossbow for a crossbow-master
+
+N:152:of Orome
+I:19:24:5
+W:127:220:130:8000000
+P:0:0d0:36:28:0
+F:CON | DEX | ESP_EVIL | ESP_ORC | ESP_TROLL | FLY | FREE_ACT | IM_ELEC | INFRA | INVIS | LUCK | NO_MAGIC | PRECOGNITION | REFLECT | RES_BLIND | RES_CHAOS | RES_CONF | RES_DISEN | SEE_INVIS | SLOW_DIGEST | SPECIAL_GENE | SPEED | STEALTH | SUST_CHR | SUST_CON | SUST_DEX | SUST_INT | SUST_STR | SUST_WIS | ULTIMATE | XTRA_MIGHT | XTRA_SHOTS
+D:A crossbow handcrafted by Aule for the Huntsman of the Valar during
+D:the first pursuit of Melkor Bauglir.
+
+# The Soft Leather Armour of the Sandworm
+
+N:153:of the Sandworm
+I:36:4:5
+W:30:3:80:65000
+P:30:0d0:0:0:0
+F:RES_POIS | RES_ELEC | RES_FIRE | RES_ACID | SPECIAL_GENE
+F:TUNNEL | STR | STEALTH | INFRA | ESP_ANIMAL
+D:This powerful piece of armour was made using the remains of
+D:the Sandworm Queen.
+
+# The Lochaber Axe 'Lhugdagnir'
+
+N:154:'Lhugdagnir'
+I:22:28:2
+W:70:20:260:33000
+P:0:3d8:20:20:0
+F:BLOWS | KILL_DRAGON | RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:RES_POIS | SHOW_MODS
+D:Forged by the Dwarves to defend their home of Khazad-dum from dragons,
+D:this axe has been lost to time... until now.
+
+# The Light War Axe 'Cam-tal-crist'
+
+N:155:'Cam-tal-crist'
+I:24:8:4
+W:15:3:140:12000
+P:0:2d5:12:15:0
+F:DEX | VORPAL | HIDE_TYPE | SHOW_MODS | WOUNDING
+D:The Petty-dwarves of Bathak forged this blade, and it shares their thirst
+D:for blood.
+
+
+# The Broad Axe 'Orchast'
+
+N:156:'Orchast'
+I:24:11:4
+W:15:2:170:12000
+P:0:2d7:20:14:0
+F:DEX | SEARCH | SLAY_ORC | ACTIVATE | HIDE_TYPE | SHOW_MODS |
+F:COULD2H
+f:COULD2H
+a:HARDCORE=ORCHAST
+D:Forged by the dwarves of Khazad-dum in a time of desperation,
+D:this axe turned many a battle against the invading orcs.
+
+
+# The Hatchet of the Night
+
+N:157:of the Night
+I:24:1:4
+W:45:20:45:34000
+P:0:2d6:34:22:0
+F:DEX | STEALTH | VAMPIRIC | KILL_UNDEAD | RES_DARK | HIDE_TYPE |
+F:SHOW_MODS | SEE_INVIS | ACTIVATE | DRAIN_EXP
+a:HARDCORE=NIGHT
+D:Found on an unmarked grave after a violent storm, this hatchet
+D:has a sinister aura of darkness and decay.
+
+# The Slaughter Axe 'Lavandagnir'
+
+N:158:'Lavandagnir'
+I:24:30:3
+W:70:20:300:28400
+P:0:5d7:31:27:0
+F:STR | SLAY_ANIMAL | SUST_STR | RES_SHARDS | RES_NEXUS | FEATHER |
+F:HIDE_TYPE | SHOW_MODS | ACTIVATE | DRAIN_HP
+a:HARDCORE=NATUREBANE
+D:Used by the orcs in their battle at Dagor Bragollach against the elves, this
+D:axe has a bloodthirst for nature.
+
+# The Light War Axe of Helcar
+
+N:159:of Helcar
+I:24:8:3
+W:30:25:140:26550
+P:0:2d5:3:15:0
+F:INT | CHR | SUST_DEX | BRAND_COLD | IM_COLD | RES_NEXUS | HIDE_TYPE |
+F:SHOW_MODS
+D:Crafted of purest ice and held solid by powerful spells, this icy axe
+D:delivers a chill of death to its victims.
+
+
+# The Iron Helm of Knowledge
+
+N:160:of Knowledge
+I:32:5:-6
+W:20:5:75:100000
+P:6:1d3:0:0:20
+F:LITE1 | HIDE_TYPE | SPECIAL_GENE | LUCK |
+F:AUTO_ID | ACTIVATE
+a:HARDCORE=KNOWLEDGE
+D:This helm, designed by Petty-Dwarves ages ago to act as the brain of a
+D:long lost project, is made of finest glass. Its light banishes all secrets,
+D:and makes audible whispers from the deceased.
+
+
+### Trapping Kits ###
+
+# The Catapult Trap Set of the Edain
+
+N:161:of the Edain
+I:46:3:3
+W:20:10:40:20000
+P:0:0d0:25:15:30
+F:STEALTH | AUTOMATIC_99 | XTRA_MIGHT | HIDE_TYPE
+D:A trap that can almost never be detected. Its missiles may be mere pebbles,
+D:but fired at an incredibly high velocity to penetrate even the toughest
+D:hide or armour.
+
+# The Device Trap Set of the Noegyth Nibin
+
+N:162:of the Noegyth Nibin
+I:46:6:3
+W:20:20:40:20000
+P:0:0d0:0:0:25
+F:STEALTH | XTRA_SHOTS | TELEPORT_TO | HIDE_TYPE | AUTOMATIC_99
+D:A magical trap, armed with a wand. Unaccountably, its victims keep
+D:on coming back for more...
+
+# The Bolt Trap Set of the Naugrim
+
+N:163:of the Naugrim
+I:46:2:2
+W:20:20:200:20000
+P:0:0d0:17:27:37
+F:STEALTH | XTRA_SHOTS | XTRA_MIGHT | HIDE_TYPE | ONLY_DEMON
+D:A snare set not for animals, or people, but for demons alone, and
+D:enchanted so that whenever the demon sets foot or claw into the
+D:(hidden) pentagram, its hide is immediately pierced by many magical
+D:crossbow bolts.
+
+# The Broken Sword 'Narsil'
+
+N:164:'Narsil'
+I:23:2:2
+W:20:5:30:15000
+P:0:3d2:6:10:0
+F:BLESSED | DEX | HIDE_TYPE | RES_FIRE | SLAY_ORC | SLAY_TROLL | STR
+D:These are the shards of the mighty blade of Isildur, which deprived
+D:the dark lord Sauron of The One Ring of Power. Legend has it that
+D:the sword that was broken shall be reforged. You can barely make out
+D:a Tengwar inscription on the pommel, reading "Narsil essenya, macil
+D:meletya; Telchar carneron Navarotesse." - "Narsil is my name, a mighty
+D:sword; Telchar made me in Nogrod."
+
+# The Chain Mail of Peregrin Took
+# From T-Plus by Ingeborg S. Norden
+
+N:165:of Peregrin Took
+I:37:4:2
+W:20:3:220:32000
+P:14:1d4:3:5:11
+F:ACTIVATE | ESP_TROLL | HIDE_TYPE | LITE1 | REGEN | RES_FEAR | SHOW_MODS | STR | SUST_STR
+a:HARDCORE=GORLIM
+D:This sturdy mail shirt was a gift from the nobility of Gondor to the halfling
+D:Peregrin Took. It enables a warrior to fight more capably and cling to life when
+D:others would be killed. It also reveals enemies (especially trolls) hiding in the
+D:dark, and terrifies anyone who threatens the wearer.
+
+# The Balance Dragon Scale Mail 'Loknare'
+
+N:166:'Loknare'
+I:38:20:0
+W:95:12:500:400000
+P:50:2d4:-8:0:35
+F:FEATHER | FLY | ESP_DRAGON |
+F:RES_NEXUS | RES_CHAOS | AGGRAVATE | REGEN |
+F:RES_SHARDS | RES_SOUND | RES_DISEN | RES_CONF |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+F:ACTIVATE
+a:HARDCORE=MEDIATOR
+D:A mighty suit of dragon armour, set with the scales of dragons of both
+D:Law and Chaos, and with power over both. Loknare means Dragonblaze.
+
+# The Hard Leather Armour of Himring
+
+N:167:of Himring
+I:36:6:0
+W:50:20:100:35000
+P:6:0d0:0:0:15
+F:RES_CHAOS | RES_NETHER | RES_POIS | ACTIVATE
+a:HARDCORE=PROT_EVIL
+D:Contained within this studded cuirass of pliable leather is the memory of
+D:unvanquished Himring, defiant fortress surrounded by the legions of Morgoth.
+
+
+# The Soft Leather Armour 'Hithlomir'
+
+N:168:'Hithlomir'
+I:36:4:4
+W:20:3:80:45000
+P:4:0d0:0:0:20
+F:STEALTH | HIDE_TYPE | SEARCH |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_DARK
+D:Familiar with the secret ways hidden in darkness, this leather cuirass is
+D:truly more than it appears.
+
+
+# The Shield of Deflection of Gil-galad
+# Description from Sangband
+
+N:169:of Gil-galad
+I:34:10:5
+W:70:4:80:65000
+P:10:1d3:0:0:20
+F:ACTIVATE |
+F:LITE1 | WIS | CHR | SEARCH | LUCK
+F:RES_ELEC | RES_ACID | RES_DISEN | RES_DARK | HIDE_TYPE |
+F:SUST_WIS | SUST_DEX | SUST_CHR
+a:HARDCORE=GILGALAD
+D:The legendary shield of Gil-Galad, who fought his way to the gates of
+D:the Dark Tower, and with whom came light even to Gorgoroth.
+
+
+# The Metal Cap of Celebrimbor
+
+N:170:of Celebrimbor
+I:32:3:3
+W:55:12:20:45000
+P:3:1d1:0:0:18
+F:INT | DEX | CHR | SPELL | SEARCH |
+F:RES_FIRE | RES_ACID | RES_DISEN | RES_SHARDS |
+F:ACTIVATE
+a:HARDCORE=CELEBRIMBOR
+D:This once belonged to Celebrimbor, maker of the Rings of Power. One who
+D:knows both fire and acid, from the business of forging and engraving, will
+D:fear neither: nor have his enchantments ever faded. Celebrimbor was even
+D:aware of Sauron before Sauron became aware of him, when Sauron put on the
+D:One Ring for the first time.
+
+
+# The Heavy Crossbow of Umbar
+
+N:171:of Umbar
+I:19:24:2
+W:60:20:200:35000
+P:0:4d1:18:18:0
+F:STR | CON | XTRA_MIGHT | AGGRAVATE |
+F:RES_LITE | RES_DARK | RES_BLIND | RES_ELEC |
+F:HIDE_TYPE | ACTIVATE | SHOW_MODS
+a:HARDCORE=UMBAR
+D:A great brazen arbalest with arms of gleaming steel, shooting quarrels with
+D:speed and power for those brave enough to risk betrayal.
+
+# The Short Bows of Amrod and Amras, Feanor's twin sons
+
+# The Short Bow of Amrod
+
+N:172:of Amrod
+I:19:12:2
+W:25:10:30:9000
+P:0:0d0:12:15:0
+F:STR | CON | XTRA_MIGHT |
+F:RES_FIRE | RES_ELEC | RES_COLD | REGEN
+D:This bow, and its twin, belonged to Feanor's last two twin sons, Amrod
+D:and Amras, who both hunted with the Green-elves for a time. Like the
+D:twins, the bows are similar, for both protect their wielders from the
+D:elements: and yet they are also unlike, for this bow gives endurance
+D:and strength, while the other gives quickness and subtlety.
+
+
+# The Short Bow of Amras
+
+N:173:of Amras
+I:19:12:1
+W:25:10:30:9000
+P:0:0d0:12:15:0
+F:INT | WIS | DEX | XTRA_SHOTS | XTRA_MIGHT | SPEED |
+F:RES_FIRE | RES_ELEC | RES_COLD | SLOW_DIGEST
+D:This bow, and its twin, belonged to Feanor's last two twin sons, Amrod
+D:and Amras, who both hunted with the Green-elves for a time. Like the
+D:twins, the bows are similar, for both protect their wielders from the
+D:elements: and yet they are also unlike, for this bow gives quickness
+D:and subtlety, while the other gives endurance and strength.
+
+
+# The Mattock of Nain
+
+N:174:of Nain
+I:20:7:6
+W:60:5:250:30000
+P:0:3d8:12:18:0
+F:TUNNEL | INFRA | SEARCH | STR | ESP_ORC | CLIMB |
+F:SLAY_ORC | SLAY_TROLL | SLAY_GIANT | SLAY_DRAGON |
+F:BRAND_ACID | RES_ACID | RES_DARK | RES_DISEN |
+F:ACTIVATE
+a:HARDCORE=STONE_MUD
+D:Wielded by Nain of the Iron Hills at the Battle of Azanulbizar, this great
+D:mattock brought victory to the Dwarves over Azog's Orcs - though Nain
+D:himself fell at the last, even with victory already assured.
+
+
+# The Ball-and-Chain of Fundin Bluecloak
+
+N:175:of Fundin Bluecloak
+I:21:6:4
+W:25:100:130:60000
+P:0:5d4:13:17:10
+F:STR | WIS | SPEED | LITE1 | HIDE_TYPE |
+F:SLAY_EVIL | SLAY_UNDEAD | ACTIVATE |
+F:RES_FIRE | RES_ELEC | RES_NETHER | RES_DISEN | HOLD_LIFE |
+F:COULD2H
+f:COULD2H
+a:HARDCORE=FUNDIN
+D:The weapon of one of the great dwarven priests, with powers
+D:to preserve body, soul and enchantments, and the bane of those
+D:who seek life beyond death.
+
+
+# The Large Leather Shield of the Haradrim
+
+N:176:of the Haradrim
+I:34:4:2
+W:35:12:120:25000
+P:4:1d2:0:0:15
+F:ACTIVATE |
+F:STR | CON | SUST_STR | SUST_CON | HIDE_TYPE |
+F:RES_FEAR | RES_BLIND | RES_POIS | AGGRAVATE
+a:HARDCORE=HARADRIM
+D:A great shield from the far lands of the South, whose wielder
+D:will go charging into battle heedless of danger, with the
+D:strength and endurance of a madman. Nor will he fear poison, for
+D:the Southron barbarians handle poisoned darts naturally.
+
+# The Lead-Filled Mace 'Dolcrist'
+
+N:177:'Dolcrist'
+I:21:15:5
+W:30:15:500:60000
+P:0:5d4:11:23:20
+F:STR | TUNNEL | INFRA | HIDE_TYPE |
+F:CURSED | AGGRAVATE | NO_MAGIC | ACTIVATE |
+F:RES_NEXUS | RES_BLIND | RES_SOUND |
+F:KILL_DRAGON | SLAY_ANIMAL | BRAND_POIS | BRAND_ELEC |
+F:COULD2H
+f:COULD2H
+a:HARDCORE=SKULLCLEAVER
+D:This mighty bludgeon brings destruction to all around it, and is the
+D:bane of dragons and magic. Skull-cleaver (or head-cleaver) it is called.
+
+# The Set of Gauntlets of Eol
+
+N:178:of Eol
+I:31:2:3
+W:55:35:25:40000
+P:3:1d1:0:0:15
+F:INT | MANA | FREE_ACT | FEATHER | RES_ELEC | RES_DARK | RES_POIS |
+F:ACTIVATE | LUCK | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=EOL
+D:The iron-shod gauntlets of the Dark Elven smith Eol, tingling with magics
+D:that he could channel in battle.
+
+
+# The Pair of Hard Leather Boots of Nevrast
+
+N:179:of Nevrast
+I:30:3:3
+W:20:8:40:35000
+P:3:1d1:0:0:13
+F:STEALTH | CON | SPEED | HIDE_TYPE
+D:Footgear made of bear leather and set with opals, which grant the wearer
+D:silent, hasted movement.
+
+
+# The Pair of Metal Shod Boots of Gimli
+
+N:180:of Gimli
+I:30:6:4
+W:40:8:60:22500
+P:4:1d1:5:5:10
+F:INFRA | SEARCH | TUNNEL | CLIMB | HIDE_TYPE
+Z:magic map
+D:A set of iron-shod boots stamped by Gimli's combat prowess, a peerless
+D:ally to those journeying through halls of stone under mountains.
+
+# The demon garbs of Gothmog
+
+# The Demonblade of Gothmog
+
+N:181:of Gothmog
+I:115:55:-20
+W:10:0:150:500
+P:0:7d6:13:13:0
+F:SHOW_MODS | SLAY_DEMON | SLAY_EVIL | BRAND_FIRE | BRAND_POIS
+F:LUCK | CHAOTIC | LITE1 | WOUNDING | RES_MORGUL | WIELD_CAST
+F:HEAVY_CURSE | AUTO_CURSE
+
+
+# The Demonshield of Gothmog
+
+N:182:of Gothmog
+I:115:56:4
+W:15:0:70:500
+P:13:1d1:0:0:13
+F:DEX | INVIS | SUST_STR | SUST_CON | SUST_DEX
+F:FEATHER | SH_FIRE | FREE_ACT | HOLD_LIFE
+F:HEAVY_CURSE | AUTO_CURSE | WIELD_CAST
+
+
+# The Demonhorn of Gothmog
+
+N:183:of Gothmog
+I:115:57:-5
+W:20:0:30:500
+P:2:1d1:0:0:13
+F:LITE2 | REGEN | ESP_DEMON
+F:CHR | SLOW_DIGEST | SEE_INVIS
+F:HEAVY_CURSE | AUTO_CURSE | WIELD_CAST
+
+# The Elven cloak of Peregrin Took
+# From T-Plus by Ingeborg S. Norden
+
+N:184:of Peregrin Took
+I:35:2:3
+W:10:10:10:12500
+P:4:0d0:0:0:16
+F:ACTIVATE | CHR | DEX | HIDE_TYPE | INVIS | LUCK | SEARCH | STEALTH
+a:HARDCORE=CURE_HUNGER
+D:This simple-looking cloak, dyed in hues that blend into the woodlands, was a gift
+D:from the elves of Lothlorien to the halfling Peregrin Took. Its wearer has an
+D:uncanny knack for making friends, escaping bonds, moving among enemies completely
+D:unseen--and finding food.
+
+# The Harp of Tom Bombadil
+# From T-Plus by Ingeborg S. Norden
+
+N:185:of Tom Bombadil
+I:14:59:4
+W:80:60:20:150000
+P:0:3d4:0:0:0
+F:ACTIVATE | BLESSED | CHR | ESP_UNDEAD | FREE_ACT |
+F:HIDE_TYPE | HOLD_LIFE | LIFE | LUCK | RES_FEAR |
+F:RES_SOUND | SEARCH | SEE_INVIS | STEALTH | SUST_CHR
+a:HARDCORE=PROT_EVIL
+D:This small, serviceable wooden harp once belonged to Tom Bombadil--
+D:a mysterious figure whose song prevented the Wight-King from
+D:attacking Frodo and his companions. Its music still inspires
+D:boldness and strengthens the life force of all who play it.
+
+# The Quarterstaff of Radagast
+# From T-Plus by Ingeborg S. Norden
+
+N:186:of Radagast
+I:21:3:2
+W:100:120:150:180000
+P:0:2d9:10:13:0
+F:ACTIVATE | BLESSED | CHR | ESP_ANIMAL | ESP_EVIL |
+F:HIDE_TYPE | INFRA | INT | MANA | RES_COLD | RES_ELEC |
+F:RES_FIRE | RES_MORGUL | SEARCH | SEE_INVIS | SHOW_MODS |
+F:SLAY_ANIMAL | SLAY_EVIL | SPELL | SPELL_CONTAIN |
+F:STEALTH | WATER_BREATH | WIELD_CAST | WIS
+a:SPELL=Artifact Radagast
+Z:grow trees
+D:Rumoured to be a gift from Yavanna to Radagast the Brown, this
+D:plain-seeming oak staff shields its bearer against the elements
+D:and helps him fight off malicious beasts (such as the goblins'
+D:Warg-steeds). It also grants exceptional insight into Nature
+D:magic, and can even cause trees or healing herbs to spring forth
+D:at the bearer's command.
+
+# The Horn 'Valaroma'
+# From T-Plus by Ingeborg S. Norden
+
+N:187:'Valaroma'
+I:14:60:4
+W:80:60:15:90000
+P:0:3d4:0:0:0
+F:ACTIVATE | BLESSED | CON | ESP_ANIMAL | ESP_EVIL |
+F:FREE_ACT | HIDE_TYPE | LUCK | RES_CONF | RES_FEAR |
+F:RES_SOUND | SEARCH | SEE_INVIS | STEALTH
+a:SPELL=Artifact Valaroma
+D:This heavenly instrument, wrought from gleaming silver, most
+D:often appears in the hands of the Valarin huntsman Orome; yet
+D:he may lend mortal champions the horn from time to time. Its
+D:music inspires courage and clarity of mind in pure-hearted
+D:beings, but drives evil ones far away.
+
+# The Cloak 'Menelcol'
+# From T-Plus by Ingeborg S. Norden
+
+N:188:'Menelcol'
+I:35:1:5
+W:70:70:10:27500
+P:1:0d0:0:0:25
+F:ACTIVATE | CHR | FLY | HIDE_TYPE | IM_ELEC | INFRA |
+F:LITE1 | MAGIC_BREATH | RES_COLD | RES_DARK | RES_LITE |
+F:SEARCH | SEE_INVIS | SUST_CHR
+a:HARDCORE=GILGALAD
+D:This deep-blue velvet cloak, embroidered with silvery stars, sheds a
+D:celestial light that reveals hidden things and bestows unearthly
+D:beauty. It also wards off damage from elements of the skies, and
+D:allows the wearer to fly unscathed even through airless space.
+
+# The Filthy Rag of Ghan-buri-Ghan
+# Suggested by ShinesmanOffWhite in the forums
+
+N:189:of Ghan-buri-Ghan
+I:36:1:2
+W:25:10:20:30000
+P:2:0d0:0:0:32
+F:CON | HIDE_TYPE | LIFE | RES_COLD | RES_FIRE |
+F:RES_POIS | RES_SOUND | STR | SUST_CON |
+F:SUST_STR | SUST_WIS | WIS
+Z:poison dart
+D:The wrappings of a leader among the wild Men of Druadan
+D:forest. It contains a multitude of tiny pockets filled
+D:with small darts dripping with venom.
+
+# The Cloak of Ghan-buri-Ghan
+# Suggested by ShinesmanOffWhite in the forums
+
+N:190:of Ghan-buri-Ghan
+I:35:1:5
+W:30:15:10:25000
+P:1:0d0:5:5:13
+F:DEX | HIDE_TYPE | INVIS | SPEED | STEALTH | SUST_DEX
+Z:berserk
+D:This dark-coloured cloak once belonged to the leader of the
+D:Druedain. As you put it on, you feel safer from attempts to
+D:waylay you on your travels.
+
+# The Black Banner of Gondor
+# Suggested by ShinesmanOffWhite in the forums
+
+N:191:of Gondor
+I:39:108:-3
+W:60:30:50:50000
+P:0:0d0:0:0:0
+F:ACTIVATE | ESP_UNDEAD | HIDE_TYPE | INSTA_ART | INVIS |
+F:LITE1 | RES_CHAOS | RES_DARK | RES_NETHER | STEALTH
+a:HARDCORE=SUMMON_UNDEAD
+D:A large banner of pure black, strangely gleaming with a dark light
+D:that is faint and at the same time so bright it attracts attention.
+
+# The Mage Staff of Saruman
+# Suggested by ShinesmanOffWhite in the forums
+
+N:192:of Saruman
+I:6:1:4
+W:60:80:12:60000
+P:0:1d4:5:5:0
+F:ACTIVATE | HIDE_TYPE | INT | MANA | SHOW_MODS | SPEED |
+F:SPELL | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=BA_COLD_1
+Z:weigh magic
+D:A white quarterstaff that faintly gleams a pale white, it once belonged
+D:to one of the most powerful beings on Middle-Earth, Saruman the White.
+D:Saruman fell into shadow, and the staff left him during his travels. As
+D:you wield it, you become much more attuned to magic.
+
+# The Robe of Curunir
+# Suggested by ShinesmanOffWhite in the forums
+
+N:193:of Curunir
+I:36:2:10
+W:60:80:20:2000000
+P:2:0d0:-40:-40:36
+F:ACTIVATE | HIDE_TYPE | IM_COLD | IM_ELEC | SPEED | SPELL_CONTAIN |
+F:SUST_CHR | SUST_CON | SUST_DEX | SUST_INT | SUST_STR | WIELD_CAST
+a:HARDCORE=BA_ELEC_2
+D:The white robe of the Istari wizard Curunir, known on Middle-earth as
+D:Saruman the White and Saruman of Many Colours. Imbued with cold and
+D:lightning used in the creation of the Fire of Orthanc, it grants the
+D:wearer some mastery over these elements.
+
+# The Light Crossbow of Brand
+# Adapted from Hengband
+
+N:194:of Brand
+I:19:23:10
+W:30:10:110:40000
+P:0:0d0:5:7:0
+F:ACTIVATE | HIDE_TYPE | RES_COLD | SHOW_MODS | STEALTH
+a:HARDCORE=RUNE_EXPLO
+D:The bow of Brand, last King of Dale. It was given to him
+D:as a gift by the King under the Mountain of Erebor, and
+D:has access to an especially secret realm of Dwarven lore.
+
+# The Pearl 'Nimphelos'
+# Adapted from Annals of Ea by Feanor
+
+N:195:'Nimphelos'
+I:39:109:1
+W:20:10:10:40000
+P:0:1d1:0:0:0
+F:HIDE_TYPE | INFRA | INSTA_ART | LITE3 | SEARCH
+Z:dazzle
+D:It was a gift from the Falas-Elves to the Naugrim who built Menegroth,
+D:the abode of Thingol and Melian. It shines like starlight on the waves
+D:of the sea.
+
+# The Silmaril of Flames
+# Adapted from Annals of Ea by Feanor
+
+N:196:of Flames
+I:39:110:2
+W:75:90:200:100000
+P:0:10d10:0:0:0
+F:ACTIVATE | AUTO_CURSE | CURSED | DRAIN_EXP | DRAIN_MANA |
+F:ESP_EVIL | HEAVY_CURSE | HIDE_TYPE | INSTA_ART | LITE2 |
+F:LITE3 | RES_CHAOS | RES_DARK | RES_FIRE | RES_LITE |
+F:RES_NETHER | RES_NEXUS | RES_SHARDS | SEE_INVIS | STR
+a:HARDCORE=INVULN
+Z:banish evil
+D:A Silmaril of Feanor. It shines with the unquenchable light of the
+D:White Trees of Valinor. It was stolen from the camp of Eonwe by
+D:Maedhros the Tall, whose evil deeds made him unable to hold the
+D:shining jewel. Desperate and anguished, he cast himself into a
+D:fiery chasm, along with the jewel. Yet the jewel seems to have
+D:survived. Forever did the Oath of Feanor bind this jewel to the fate
+D:of Middle-earth.
+
+# The Silmaril of the Seas
+# Adapted from Annals of Ea by Feanor
+
+N:197:of the Seas
+I:39:111:2
+W:75:90:200:100000
+P:0:10d10:0:0:0
+F:ACTIVATE | AUTO_CURSE | CURSED | DRAIN_EXP | DRAIN_HP | ESP_EVIL |
+F:HEAVY_CURSE | HIDE_TYPE | INSTA_ART | INT | LITE2 | LITE3 |
+F:RES_CHAOS | RES_DARK | RES_LITE | RES_NETHER | RES_NEXUS | SEE_INVIS
+a:HARDCORE=RECALL
+Z:banish evil
+D:A Silmaril of Feanor. It shines with the unquenchable light of the
+D:White Trees of Valinor. It was stolen from the camp of Eonwe by
+D:Maglor, yet he soon discovered that the light of the Valar cannot
+D:abide in the hands of evildoers. Thus he could not bear to hold it,
+D:and he cast it into the sea. Thereafter he wandered ever upon the
+D:shores singing in pain, regret and sorrow. Forever did the Oath of
+D:Feanor bind this jewel to the fate of Middle-earth.
+
+# The Sceptre of Numenor
+
+N:198:of Numenor
+I:12:2:-3
+W:50:40:24:80000
+P:0:0d0:0:0:0
+F:ACTIVATE | AUTO_CURSE | CHR | CON | CURSED | HEAVY_CURSE |
+F:INSTA_ART | LUCK | SPEED | SPELL_CONTAIN | STR | WIELD_CAST | WRAITH
+a:HARDCORE=DISP_GOOD
+D:The chief mark of royalty in Westernesse, it is said to have perished
+D:in the fall of Numenor. It once belonged to Ar-Pharazon the Golden and
+D:the evilness of that fallen King still courses through it.
+
+# The Rod of Annuminas
+
+N:199:of Annuminas
+I:12:3:4
+W:60:50:24:80000
+P:0:0d0:0:0:0
+F:ACTIVATE | BLESSED | CHR | FREE_ACT | INSTA_ART | LUCK |
+F:RES_CONF | SPELL_CONTAIN | WIELD_CAST
+a:HARDCORE=RUNE_PROT
+D:The chief mark of royalty in Arnor, possibly the oldest remaining work
+D:of Men. It came from Numenor, but it belonged to the Lords of Andunie
+D:of whom the first was Valandil son of Silmarien. It was passed down to
+D:Elendil and thus survived the downfall of Numenor.
+# The Feanorian Lamp of Taniquetil
+# From T-Plus by Ingeborg S. Norden
+
+N:200:of Taniquetil
+I:39:4:2
+W:75:60:200:100000
+P:0:1d1:0:0:0
+F:ACTIVATE | BLESSED | ESP_ALL | HIDE_TYPE | INFRA | INT |
+F:LITE1 | LITE2 | LITE3 | RES_BLIND | RES_LITE | SEARCH |
+F:SEE_INVIS | WATER_BREATH | WIS
+a:HARDCORE=PALANTIR
+Z:detect curses
+D:This holy lamp once belonged to a seeress who warned Ar-Pharazon of
+D:the dire fate Numenor would suffer for daring to break the ban against
+D:mortals' entering the Blessed Realms alive. The king had the seeress
+D:executed and discarded her possessions--but rumors persist that a source
+D:of pure vision, untainted by Sauron's darkness, lies hidden away
+D:somewhere on Arda.
+
+# The template for artifacts corpses
+
+N:201:
+I:9:1:0
+W:200:1:10:0
+P:0:1d1:0:0:0
+F:INSTA_ART | SPECIAL_GENE
+
+
+# The Palantir of Orthanc
+
+N:202:of Orthanc
+I:39:104:2
+W:75:60:200:100000
+P:0:10d10:0:0:0
+F:WIS | INT | SEARCH | INFRA | HIDE_TYPE | ACTIVATE | ESP_ALL |
+F:SEE_INVIS | RES_BLIND | AGGRAVATE | DRAIN_MANA | LITE2
+F:INSTA_ART
+a:HARDCORE=PALANTIR
+D:A shining white ball of unbreakable crystal, the ancient Palantiri
+D:were used by kings of Numenor and later by the Exiles for rapid
+D:communication between distant lands. Nothing is hidden from one who
+D:gazes into a Palantir, but the observed will also be aware of the
+D:observer, as was Sauron when Saruman tried to spy on him with this
+D:particular Palantir.
+
+# The Ring 'Fuin'
+
+N:203:'Fuin'
+I:45:55:15
+W:110:0:2:3000000
+P:0:1d1:0:0:0
+F:SPEED | SEE_INVIS | LUCK | MAGIC_BREATH
+F:CURSED | HEAVY_CURSE | REGEN
+F:WRAITH | IM_NETHER | DRAIN_EXP | HOLD_LIFE | SPECIAL_GENE |
+F:INSTA_ART
+Z:teleport
+D:Imbued with the screams of the victims of undead everywhere, this
+D:ring is more a hole in reality than anything else. Strange forces ripple over
+D:its surface, giving you visions of a reality considerably less solid than this
+D:one. You feel your senses reel, and must make a conscious effort not to throw
+D:this ring as far from you as possible.
+
+# The Blue Stone 'Coimir' (formerly 'Toris Mejistos')
+# From T-Plus by Ingeborg S. Norden
+
+N:204:'Coimir'
+I:40:18:2
+W:80:120:3:120000
+P:0:0d0:0:0:0
+F:FREE_ACT | HIDE_TYPE | HOLD_LIFE | INSTA_ART | LIFE | LITE1 | LUCK | REGEN | RES_NETHER | SLOW_DIGEST | SPECIAL_GENE | SPELL_CONTAIN | SUST_CON | SUST_DEX | SUST_STR | WATER_BREATH | WIELD_CAST
+Z:restore life
+D:Called 'Life-jewel' by the Vanyar of old, this flawless sapphire
+D:pendant bears potent runes that preserve body and soul.
+
+# The Ring of Durin - last of the Seven Rings of the Dwarf-lords
+
+N:205:of Durin
+I:45:57:2
+W:70:70:2:65000
+F:CON | CHR | STR | SUST_CHR | SUST_CON | SUST_STR | HIDE_TYPE |
+F:ESP_EVIL | AGGRAVATE | HEAVY_CURSE | HOLD_LIFE | DRAIN_EXP |
+F:RES_DARK | RES_CHAOS | RES_NETHER | RES_COLD | RES_ACID |
+F:INSTA_ART | SPECIAL_GENE | CURSED
+Z:Midas touch
+D:The greatest of the Seven Rings of the Dwarf-lords, and the last to be
+D:lost. Alone among the Seven, it was not taken by Sauron when he made
+D:war on the Elves, but was given as a gift from Celebrimbor to King Durin
+D:III of Moria in token of friendship: nevertheless, Sauron in disguise
+D:had a hand in its making, and so it is cursed, and draws evil towards it.
+
+
+# The Elfstone 'Elessar'
+
+N:206:'Elessar'
+I:40:19:4
+W:60:60:3:40000
+P:0:0d0:7:7:10
+F:STR | WIS | CHR | SPEED | LITE3 | INSTA_ART |
+F:RES_FEAR | RES_FIRE | RES_POIS | RES_DISEN | HIDE_TYPE |
+F:ACTIVATE
+a:HARDCORE=ELESSAR
+D:This green gem glows with inner light. Aragorn son of Arathorn wore
+D:it at the Battle of the Pelennor Fields, and he was himself given the
+D:name of 'Elessar' by the people of Gondor because of this.
+
+
+# The Jewel 'Evenstar'
+
+N:207:'Evenstar'
+I:40:20:3
+W:50:50:3:35000
+F:HOLD_LIFE | SUST_CON | SUST_WIS | SUST_INT | LITE1 | CON |
+F:RES_DARK | RES_COLD | RES_NETHER | REGEN | INSTA_ART |
+F:ACTIVATE
+a:HARDCORE=REST_ALL
+D:A pure white jewel, the last gift of Queen Arwen Undomiel to Frodo
+D:Baggins, intended to be worn around his neck on the chain that had
+D:once borne the One Ring.
+
+# The Palantir of Minas Ithil
+
+N:208:of Minas Ithil
+I:39:107:-3
+W:75:60:200:0
+P:0:10d10:0:0:-30
+F:LIFE | CON | INT | WIS | ESP_ALL | LITE3 | LITE1
+F:CURSED | HEAVY_CURSE | TY_CURSE | DRAIN_EXP |
+F:RES_BLIND | SEE_INVIS | ACTIVATE
+a:HARDCORE=PALANTIR
+D:A shining white ball of unbreakable crystal, the ancient Palantiri
+D:were used by kings of Numenor and later by the Exiles for rapid
+D:communication between distant lands. This Palantir, however, was
+D:taken by Sauron long ago, and mastered to his evil uses, to the
+D:destruction of all others who would gaze into it.
+
+### More new artifacts in Theme ###
+
+# The Map of Thror
+
+N:209:of Thror
+I:8:33:0
+W:70:100:30:1
+P:0:0d0:0:0:0
+F:INSTA_ART | SPECIAL_GENE
+D:A map made by Thror, the King under the Mountain. It shows the Lonely
+D:Mountain of Erebor, the Running River, and the lands about devastated by
+D:Smaug. It also contains mention of a secret entrance to the Mountain.
+D:This map and a key are all you need to enter a special cavern in Erebor.
+
+# The Key of Thorin
+
+N:210:of Thorin
+I:11:13:0
+W:70:100:5:1
+P:0:0d0:0:0:0
+F:INSTA_ART | SPECIAL_GENE
+D:A small silver key, given to Thorin Oakenshield by Gandalf the Grey,
+D:who got it from Thrain, Thorin's father, in Dol Guldur. It opens a
+D:magical gate to a special cavern in the Lonely Mountain - you will
+D:also need a map to show you the gate's precise location.
+
+# The Cup of Thror
+
+N:211:of Thror
+I:11:14:0
+W:70:100:50:100000
+P:0:0d0:0:0:0
+F:ACTIVATE | ACTIVATE_NO_WIELD | HIDE_TYPE | INSTA_ART | SPECIAL_GENE
+a:HARDCORE=ALCHEMY
+D:It was made for Thror, King under the Mountain. It is a huge golden bowl
+D:with two handles, hammered and carved, with birds and flowers whose eyes
+D:and leaves are made in jewels.
+
+# The Red Arrow of Gondor
+
+N:212:of Gondor
+I:11:15:0
+W:40:70:2:70000
+P:0:0d0:0:0:0
+F:ACTIVATE | ACTIVATE_NO_WIELD | HIDE_TYPE | INSTA_ART
+a:HARDCORE=BOROMIR
+D:The summons of Gondor, an arrow sent as a symbol of desperate need from
+D:Gondor to its northern allies, the Rohirrim. The tradition dates back to
+D:the time of Borondir, who rode north from Gondor to summon aid from the
+D:ancestors of the Rohirrim, the Eotheod. The Red Arrow was only sent north
+D:in the most perilous of circumstances.
+
+# ToME artifacts (new since 2.3.x) #
+
+# The Mage Staff of Forochel
+
+N:213:of Forochel
+I:6:1:3
+W:65:70:60:60000
+P:0:3d4:-12:-8:0
+F:INT | WIS | MANA | SPELL | INFRA | SEE_INVIS |
+F:SUST_INT | SUST_WIS | RES_BLIND | IM_COLD | SENS_FIRE |
+F:SPECIAL_GENE | WIELD_CAST |
+F:COULD2H
+f:COULD2H
+D:A shaft of pure, invincible crystal cut from the heart of one
+D:of the great glaciers ringing the Ice-Bay of Forochel.
+D:While you hold it, your mind feels as clear as the winter sky.
+
+
+# The Elven Cloak of Mellyrn
+
+N:214:of Mellyrn
+I:35:2:4
+W:40:40:5:65000
+P:4:0d0:0:0:20
+F:HIDE_TYPE | INVIS | DEX | SPEED | STEALTH | LUCK |
+F:SUST_DEX | RES_LITE | RES_DARK
+D:Bearing the same lyrical name as the great trees of Lothlorien
+D:and containing in its close-woven folds the speed and skill of
+D:the Galadrim, this grey cloak is ideal for those who travel in
+D:forests.
+
+
+# The Bluesteel Blade of Ephel Duath
+
+N:215:of Ephel Duath
+I:23:31:-3
+W:60:60:50:30000
+P:0:2d6:-20:-18:0
+F:STR | WIS | CHR | BRAND_POIS | VAMPIRIC | VORPAL |
+F:INVIS | AGGRAVATE | CURSED | HEAVY_CURSE | SHOW_MODS |
+D:This filthy orc-blade is famed for vile deeds of torture and blood,
+D:and its wielder will never cease to fear treachery.
+
+
+# The Slaughter Axe 'Garachoth'
+
+N:216:'Garachoth'
+I:24:30:2
+W:70:50:400:0
+P:0:7d5:18:18:-20
+F:STR | CON | SPEED | LEVELS | BLACK_BREATH |
+F:KILL_DEMON | SLAY_ANIMAL | BRAND_FIRE | VORPAL |
+F:RES_FEAR | RES_FIRE | RES_CHAOS | RES_NETHER |
+F:HIDE_TYPE | SHOW_MODS
+D:A ghastly axe with the soul of a demon lord trapped inside, this horrifying
+D:creation reverberates with the screams of the damned. As you gaze into its
+D:glassy, translucent blade, it seems that endless sulphrous wastelands
+D:stretch away from you into the distance, obscured by sheets of fire.
+
+
+# The Set of Cesti 'Skycleaver'
+
+N:217:'Skycleaver'
+I:31:5:1
+W:40:45:40:100000
+P:5:1d1:16:7:16
+F:STR | CON | DEX | CHR | LUCK | FLY |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS |
+F:HIDE_TYPE | SHOW_MODS
+D:The handgear of a legendary dragonslaying hero. The wearer of these
+D:wyrmskin gauntlets will be versed in all aerial ways, and will fear no
+D:dragon that walks or flies.
+
+
+# The Pair of Metal Shod Boots of the Machine
+# Replaced the stealth malus with AGGRAVATE
+
+N:218:of the Machine
+I:30:6:3
+W:30:100:170:19000
+P:6:1d1:0:0:24
+F:INT | SPEED | TUNNEL | AGGRAVATE |
+F:RES_CHAOS | RES_SHARDS | RES_CONF |
+F:ESP_NONLIVING | HIDE_TYPE | SPECIAL_GENE
+D:A massive pair of adamantine boots studded with gold, the final and
+D:greatest product of the petty-dwarven magical forge. Despite
+D:the great powers they contain, they are heavy and awkward enough to
+D:make quite a racket whenever you move.
+
+# Theme artifacts continued #
+
+# The Robe of Belegaer
+# Based on Robe of the Seven Seas from T-Plus by Ingeborg S. Norden
+
+N:219:of Belegaer
+I:36:2:5
+W:100:200:20:1500000
+P:2:0d0:0:0:20
+F:FREE_ACT | HIDE_TYPE | IM_ACID | IM_COLD | IM_ELEC | LITE1 | LUCK | RES_BLIND | RES_DARK | SEARCH | STEALTH | WATER_BREATH
+D:This pearl-trimmed blue robe was created by a Maia loremaster in
+D:Ulmo's service. No ocean storm can harm its wearer or anything
+D:he carries; the pressure and darkness of deep water cannot hinder
+D:him, either.
+
+# The Necklace of Girion
+
+N:220:of Girion
+I:40:4:5
+W:20:5:2:15000
+P:0:1d1:0:0:10
+F:ACTIVATE | CHR | INSTA_ART | RES_NEXUS | RES_POIS | SEE_INVIS | SUST_CHR
+a:HARDCORE=GROW_MOLD
+D:A necklace of emeralds, green as the grass. It once belonged to Girion,
+D:King of Dale, and was given to the Dwarves of the Lonely Mountain as
+D:payment for a mithril mail shirt for Girion's son. It seems to have
+D:overgrown with a strange moss over the years.
+
+# The Silver Bolt 'Dailir' - the 'dart' of Beleg Cuthalion, based on Heart's Blood
+
+N:221:'Dailir'
+I:18:3:5
+W:85:40:3:35000
+P:0:8d5:15:20:0
+F:CRIT | HIDE_TYPE | SHOW_MODS | VORPAL | WOUNDING
+D:The beloved dart of Beleg Cuthalion. It never failed to be found
+D:unharmed, until it broke when Beleg fell upon it while he was
+D:carrying Turin Turambar away from an Orc-camp, the night Beleg
+D:met his end. Turin remade the bolt and kept it to his dying day in
+D:memory of his friend.
+
+# The Amulet of Faramir [adapted from Oangband]
+# The equivalent of the Phial (not too rare) for a stealth bonus and a source of RES_CONF early
+
+N:222:of Faramir
+I:40:29:5
+W:10:2:2:10000
+P:0:0d0:18:0:8
+F:HIDE_TYPE | INSTA_ART | RES_CONF | SHOW_MODS | STEALTH | SUST_DEX
+D:A slim neckpiece of True-silver, with quiet spells of Ithilien to aid and
+D:protect the wearer.
+
+# The Large Mithril Shield of Earendil
+# Adapted from Oangband; its chief benefits are the +to_ac and the activation
+
+N:223:of Earendil
+I:34:8:0
+W:95:80:100:90000
+P:20:1d1:0:0:80
+F:ACTIVATE | RES_BLIND | RES_DARK | RES_ELEC | RES_FIRE | RES_NETHER
+a:HARDCORE=BLADETURNER
+D:A shining shield, once borne by the great mariner Earendil, "scored with
+D:runes to keep all wounds and harm from him".
+
+# The Long Bow of Legolas
+
+N:224:of Legolas
+I:19:13:3
+W:40:20:40:30000
+P:0:0d0:17:19:0
+F:XTRA_MIGHT | XTRA_SHOTS | FREE_ACT | HIDE_TYPE | ESP_ORC |
+F:STEALTH | INFRA | DEX
+D:The great bow of Legolas, one of the Nine Walkers of old.
+D:Handcrafted specially for Thranduil's son in Lothlorien,
+D:this bow gives clarity of sight and agility to the wielder.
+
+# The Large Metal Shield of Erkenbrand
+
+N:225:of Erkenbrand
+I:34:5:3
+W:40:9:120:200000
+P:0:0d0:0:0:30
+F:REFLECT | STR | CHR | SUST_DEX | HIDE_TYPE | ESP_ORC |
+F:FREE_ACT | REGEN
+D:Tall and strong stood Erkenbrand, Lord of the Westfold, as he rode
+D:to combat the forces of Isengard. The valour of Helm Hammerhand lived
+D:again in him. This shield is painted red according to Rohan custom
+D:and it grants magical protection against enemy projectiles, as well
+D:as lets the wearer sense approaching enemy hordes.
+
+# XXX 226 Room for another artifact here XXX #
+# XXX 227 Room for another artifact here XXX #
+# XXX 228 Room for another artifact here XXX #
+# XXX 229 Room for another artifact here XXX #
+# XXX 230 Room for another artifact here XXX #
+# XXX 231 Room for another artifact here XXX #
+# XXX 232 Room for another artifact here XXX #
+# XXX 233 Room for another artifact here XXX #
+# XXX 234 Room for another artifact here XXX #
+# XXX 235 Room for another artifact here XXX #
+# XXX 236 Room for another artifact here XXX #
+# XXX 237 Room for another artifact here XXX #
+# XXX 238 Room for another artifact here XXX #
+# XXX 239 Room for another artifact here XXX #
+# XXX 240 Room for another artifact here XXX #
+
+### New Ultimate items added in Theme ###
+
+# The Lucerne Hammer of the Eruchin (Haftedmasters/Eru warriors)
+
+N:241:of the Eruchin
+I:21:10:10
+W:127:220:130:9000000
+P:0:5d6:21:26:50
+F:ACTIVATE | BLESSED | BRAND_COLD | BRAND_ELEC | BRAND_FIRE |
+F:CHR | CON | FREE_ACT | IM_COLD | LIFE | LITE1 | LUCK |
+F:NO_MAGIC | PRECOGNITION | REGEN | RES_DARK | RES_FIRE |
+F:SEE_INVIS | SHOW_MODS | SLAY_DEMON | SLAY_EVIL | SLAY_TROLL |
+F:SLAY_UNDEAD | SLOW_DIGEST | SPECIAL_GENE | SUST_CHR | SUST_CON |
+F:SUST_DEX | SUST_INT | SUST_STR | SUST_WIS | ULTIMATE | VORPAL
+a:HARDCORE=ERU
+D:A weapon forged by Aule himself and blessed by Eru Iluvatar,
+D:calling upon the strength of all his children (hence the name,
+D:which means Children of Eru). It is Eru Iluvatar's gift to you,
+D:made for a single purpose
+
+# The Trident of Ulmo (Polearmmasters)
+
+N:242:of Ulmo
+I:22:5:10
+W:127:220:130:9000000
+P:0:5d6:21:26:50
+F:ACTIVATE | BLESSED | BRAND_COLD | BRAND_ELEC | BRAND_FIRE |
+F:CHR | CON | FREE_ACT | IM_COLD | LIFE | LITE1 | LUCK |
+F:NO_MAGIC | PRECOGNITION | REGEN | RES_DARK | RES_FIRE |
+F:SEE_INVIS | SHOW_MODS | SLAY_DEMON | SLAY_EVIL | SLAY_TROLL |
+F:SLAY_UNDEAD | SLOW_DIGEST | SPECIAL_GENE | SUST_CHR | SUST_CON |
+F:SUST_DEX | SUST_INT | SUST_STR | SUST_WIS | ULTIMATE | VORPAL
+a:HARDCORE=ERU
+D:The awesome weapon of the Vala Ulmo, Lord of Waters. Mightiest of all the
+D:powers of good save Manwe himself, Ulmo laughs in scorn at the dread powers
+D:of the undead, and is utterly in command of the element of water.
+
+# The Broad Axe of Aule (Axemasters)
+
+N:243:of Aule
+I:24:11:10
+W:127:220:130:9000000
+P:0:5d6:21:26:50
+F:ACTIVATE | BLESSED | BRAND_COLD | BRAND_ELEC | BRAND_FIRE |
+F:CHR | CON | FREE_ACT | IM_COLD | LIFE | LITE1 | LUCK |
+F:NO_MAGIC | PRECOGNITION | REGEN | RES_DARK | RES_FIRE |
+F:SEE_INVIS | SHOW_MODS | SLAY_DEMON | SLAY_EVIL | SLAY_TROLL |
+F:SLAY_UNDEAD | SLOW_DIGEST | SPECIAL_GENE | SUST_CHR | SUST_CON |
+F:SUST_DEX | SUST_INT | SUST_STR | SUST_WIS | ULTIMATE | VORPAL
+a:HARDCORE=ERU
+D:Aule's mighty weapon, granted to you to aid the defeat of Melkor.
+
+# The Rapier of Vaire (Rogues, whose Critical-hits skill is only useful with lighter swords)
+
+N:244:of Vaire
+I:23:7:10
+W:127:220:130:9000000
+P:0:5d6:21:26:50
+F:ACTIVATE | BLESSED | BRAND_COLD | BRAND_ELEC | BRAND_FIRE | CHR |
+F:CON | FREE_ACT | IM_COLD | LIFE | LITE1 | LUCK | NO_MAGIC |
+F:PRECOGNITION | REGEN | RES_DARK | RES_FIRE | SEE_INVIS | SHOW_MODS |
+F:SLAY_DEMON | SLAY_EVIL | SLAY_TROLL | SLAY_UNDEAD | SLOW_DIGEST |
+F:SPECIAL_GENE | SUST_CHR | SUST_CON | SUST_DEX | SUST_INT | SUST_STR |
+F:SUST_WIS | ULTIMATE | VORPAL
+a:HARDCORE=ERU
+D:A shining rapier used by Vaire to cut the strings of time when
+D:dire need arises. Its power with that of the Flame Imperishable
+D:will let you destroy Melkor forever.
+
+# The Long Bow of Irmo (Bow-masters)
+
+N:245:of Irmo
+I:19:13:5
+W:127:220:130:8000000
+P:0:0d0:36:28:0
+F:CON | DEX | ESP_EVIL | ESP_ORC | ESP_TROLL | FLY | FREE_ACT |
+F:IM_ELEC | INFRA | INVIS | LUCK | NO_MAGIC | PRECOGNITION |
+F:REFLECT | RES_BLIND | RES_CHAOS | RES_CONF | RES_DISEN |
+F:SEE_INVIS | SLOW_DIGEST | SPECIAL_GENE | SPEED | STEALTH |
+F:SUST_CHR | SUST_CON | SUST_DEX | SUST_INT | SUST_STR |
+F:SUST_WIS | ULTIMATE | XTRA_MIGHT | XTRA_SHOTS
+D:A gift from Orome to Irmo, a mighty bow that sings the songs of the
+D:garden of Lorien. It will guide your hand and steady your grip in
+D:your encounter with Melkor.
+
+# The Sling of Nessa (Sling-masters)
+
+N:246:of Nessa
+I:19:2:5
+W:127:220:130:8000000
+P:0:0d0:36:28:0
+F:CON | DEX | ESP_EVIL | ESP_ORC | ESP_TROLL | FLY | FREE_ACT |
+F:IM_ELEC | INFRA | INVIS | LUCK | NO_MAGIC | PRECOGNITION |
+F:REFLECT | RES_BLIND | RES_CHAOS | RES_CONF | RES_DISEN |
+F:SEE_INVIS | SLOW_DIGEST | SPECIAL_GENE | SPEED | STEALTH |
+F:SUST_CHR | SUST_CON | SUST_DEX | SUST_INT | SUST_STR | SUST_WIS |
+F:ULTIMATE | XTRA_MIGHT | XTRA_SHOTS
+D:This sling was made for the most lithe of the Valier to provide
+D:her with amusement as she used it to shoot magical pebbles of
+D:cheer and charm while dancing in the lush green fields of Valinor.
+D:She grants it to you now in your time of trial.
+
+# The Metal Boomerang of Varda (Boomerang-masters)
+
+N:247:of Varda
+I:15:4:5
+W:127:220:130:8000000
+P:0:0d0:36:28:0
+F:CON | DEX | ESP_EVIL | ESP_ORC | ESP_TROLL | FLY | FREE_ACT |
+F:IM_ELEC | INFRA | INVIS | LUCK | NO_MAGIC | PRECOGNITION |
+F:REFLECT | RES_BLIND | RES_CHAOS | RES_CONF | RES_DISEN |
+F:SEE_INVIS | SLOW_DIGEST | SPECIAL_GENE | SPEED | STEALTH |
+F:SUST_CHR | SUST_CON | SUST_DEX | SUST_INT | SUST_STR | SUST_WIS |
+F:ULTIMATE | XTRA_MIGHT | XTRA_SHOTS
+D:Made from living starlight, this boomerang will dispel the darkest
+D:of darkness. It is a gift from Varda Elentari, to aid you in your
+D:task.
+
+# The Amulet of Mandos (Weaponless fighters)
+
+N:248:of Mandos
+I:40:27:0
+W:100:16:60:500000
+P:0:2d4:0:0:85
+F:ACTIVATE | ESP_DRAGON | FEATHER | FLY | HOLD_LIFE | IGNORE_ACID |
+F:IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | REGEN | RES_ACID |
+F:RES_BLIND | RES_CHAOS | RES_COLD | RES_CONF | RES_DARK | RES_DISEN |
+F:RES_ELEC | RES_FIRE | RES_LITE | RES_NETHER | RES_NEXUS | RES_POIS |
+F:RES_SHARDS | RES_SOUND | SPECIAL_GENE | ULTIMATE
+a:HARDCORE=BLADETURNER
+D:This amulet contains the power of Mandos, the Doomsman of the
+D:Valar. It will grant you protection against the foul dark magic
+D:of Melkor, though you will still need your wits and strength
+D:about you as you face your ultimate foe.
+
+# XXX 249 Room for another artifact here XXX ###
+# XXX 250 Room for another artifact here XXX ###
+# XXX 251 Room for another artifact here XXX ###
+# XXX 252 Room for another artifact here XXX ###
+# XXX 253 Room for another artifact here XXX ###
+# XXX 254 Room for another artifact here XXX ###
+# XXX 255 Room for another artifact here XXX ###
+# XXX 256 Room for another artifact here XXX ###
+
+### 256 is the maximum number of artifacts (257 in misc.txt).
+
+# N: serial number : & object name~
+# G: symbol : color
+# I: tval : sval : pval
+# W: depth : rarity : weight : cost
+# P: base armor class : base damage : plus to-hit : plus to-dam : plus to-ac
+# F: flag | flag | etc
+# D: description
diff --git a/lib/mods/theme/edit/ab_info.txt b/lib/mods/theme/edit/ab_info.txt
new file mode 100644
index 00000000..4272776a
--- /dev/null
+++ b/lib/mods/theme/edit/ab_info.txt
@@ -0,0 +1,109 @@
+# File: ab_info.txt
+
+
+# This file is used to initialize the "lib/data/ab_info.raw" file, which is
+# used to initialize the "abilities" information for the ToME game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# The ToME abilities indexes are defined in "defines.h", and must not be changed.
+# If you want to add new ones, add them after the tome ones
+
+# N:idx:name
+# D:desc
+# I:cost(in skill points)
+# A:action mkey:action desc
+
+# Prerequisites
+# k:level:skill
+# S:level(linear mode):stats
+# a:needed ability
+
+# E:excluding ability:excluding ability
+
+# If you need more sophisticated prereqs use the HOOK_LEARN_ABILITY
+
+# Version stamp (required)
+
+# Do not forget to update misc.txt with an entry like the following :
+# Maximum number of traits in ab_info.txt
+# M:b:50
+
+V:2.2.0
+
+N:0:Spread blows
+D:If a monster dies to your attack but you still have blows left
+D:you won't lose the full turn, allowing you to attack some other
+D:monster in the same turn
+D:Prereq: Weaponmastery skill@30, Dex@17
+I:5
+k:30:Weaponmastery
+S:17:DEX
+
+N:1:Tree walking
+D:Allows you to walk in dense forest
+D:Prereq: Nature skill@20
+I:7
+k:20:Nature
+
+N:2:Perfect casting
+D:Allows you to reach 0% failure rate on spells
+D:Prereq: Magic skill@35
+I:6
+k:35:Magic
+
+N:3:Extra Max Blow(1)
+D:Increases your max possible blows number by 1
+D:Prereq: Combat@10
+I:7
+k:10:Combat
+
+N:4:Extra Max Blow(2)
+D:Increases your max possible blows number by 1
+D:Prereq: Combat@20, Extra Max Blow(1)
+I:7
+k:20:Combat
+a:Extra Max Blow(1)
+
+N:5:Ammo creation
+D:Allows you to create shots, arrows and bolts from various materials
+D:Prereq: Archery@10
+A:10:Forge ammo
+I:8
+k:10:Archery
+
+N:6:Touch of death
+D:Your melee blows can insta-kill, but you only receive 1/3 of the experience
+D:Prereq: Necromancy@50, Combat@40, DEX@30, STR@30
+A:100:Activate touch of death
+I:15
+k:50:Necromancy
+k:40:Combat
+S:30:DEX
+S:30:STR
+
+N:8:Far reaching attack
+D:You can attack an enemy one square far using a long polearm.
+D:At high levels of Polearm-mastery skill, you can even hit two enemies at once.
+D:Prereq: Combat@15, Polearm-mastery@15
+I:10
+A:102:Far reaching attack
+k:15:Combat
+k:15:Polearm-mastery
+
+N:9:Trapping
+D:Ability to set monster traps
+D:Prereq: Disarming@15
+I:10
+A:14:Set trap
+k:15:Disarming
+
+N:10:Undead Form
+D:Ability to turn into a weak undead being when you "die".
+D:You must then kill enough monsters to absorb enough life energy
+D:to come back to life.
+D:Prereq: Necromancy@30, INT@25
+I:15
+k:30:Necromancy
+S:25:INT
diff --git a/lib/mods/theme/edit/al_info.txt b/lib/mods/theme/edit/al_info.txt
new file mode 100644
index 00000000..c5e7c55d
--- /dev/null
+++ b/lib/mods/theme/edit/al_info.txt
@@ -0,0 +1,12 @@
+# File: al_info.txt
+
+
+# This file is used to initialize the "lib/raw/al_info.raw" file, which is
+# used as the alchemist recipes in ToME
+
+# This file is intentionally blank in Theme
+# because the Alchemist class has been removed.
+
+# Version stamp (required)
+
+V:2.0.0 \ No newline at end of file
diff --git a/lib/mods/theme/edit/ba_info.txt b/lib/mods/theme/edit/ba_info.txt
new file mode 100644
index 00000000..b76f79dd
--- /dev/null
+++ b/lib/mods/theme/edit/ba_info.txt
@@ -0,0 +1,310 @@
+# File: ba_info.txt
+
+
+# This file is used to initialize the "lib/raw/ba_info.raw" file, which is
+# used to initialize the "store/building actions type" information for
+# the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# N:<index>:<name>
+# C:<hated cost>:<normal cost>:<liked cost>
+# I:<action>:<acttion restriction>:<letter>
+
+# Restriction:
+# 0 = No restrictions
+# 1 = Restrict to normal & liked
+# 2 = Restrict to liked
+
+# Version stamp (required)
+
+V:2.0.0
+
+N:0:Nothing
+C:0:0:0
+I:0:0:.
+
+N:1:Sell an item
+C:0:0:0
+I:43:0:s:d
+
+N:2:Purchase an item
+C:0:0:0
+I:44:0:p:g
+
+N:3:Examine an item
+C:0:0:0
+I:45:0:x
+
+N:4:Steal an item
+C:0:0:0
+I:46:0:Z
+
+N:5:Rest for the night
+C:25:20:15
+I:17:0:r
+
+N:6:Buy food and drink
+C:3:2:1
+I:18:0:f
+
+N:7:Listen for rumours
+C:0:0:0
+I:19:0:u
+
+N:8:Presage fate
+C:600:500:480
+I:42:0:l
+
+N:9:In-Between
+C:0:0:0
+I:12:0:b
+
+N:10:Play craps
+C:0:0:0
+I:14:0:c
+
+N:11:Spin the wheel
+C:0:0:0
+I:15:0:s
+
+N:12:Play dice slots
+C:0:0:0
+I:16:0:d
+
+N:13:Game rules
+C:0:0:0
+I:13:0:r
+
+N:14:Research item
+C:1400:1300:1200
+I:1:0:a
+
+N:15:Town history
+C:0:0:0
+I:2:0:h
+
+N:16:Race legends
+C:0:0:0
+I:3:0:l
+
+N:17:Look at busts of Kings
+C:0:0:0
+I:5:0:l
+
+N:18:Research monster
+C:1600:1500:1400
+I:20:0:r
+
+N:19:View bounties
+C:0:0:0
+I:38:0:v
+
+N:20:Receive bounty money
+C:0:0:0
+I:39:0:b
+
+N:21:Get quest monster
+C:0:0:0
+I:54:0:q
+
+N:22:Turn in quest corpse
+C:0:0:0
+I:55:0:m
+
+N:23:Compare weapons
+C:220:200:180
+I:21:0:c
+
+N:24:Enchant weapon
+C:750:700:150
+I:23:0:w
+
+N:25:Enchant armour
+C:750:700:150
+I:24:0:a
+
+N:26:Recharge item
+C:350:300:75
+I:25:0:r
+
+N:27:Identify possessions
+C:900:800:100
+I:26:0:i
+
+N:28:Healing prayer
+C:600:400:0
+I:28:0:h
+
+N:29:Restoration
+C:600:500:100
+I:29:0:r
+
+N:30:Get share of stolen gold
+C:0:0:0
+I:7:2:g
+
+N:31:Enchant arrows
+C:550:500:100
+I:30:0:a
+
+N:32:Enchant bow
+C:550:500:100
+I:31:0:b
+
+N:33:Recall to dungeon
+C:300:200:100
+I:33:0:r
+
+N:34:Teleport to dungeon-level
+C:15000:10000:1000
+I:34:0:t
+
+N:35:Get a quest
+C:0:0:0
+I:6:0:q
+
+# Restrict to liked/normal
+N:36:Get a quest
+C:0:0:0
+I:46:1:q
+
+N:37:Get a quest
+C:0:0:0
+I:47:0:q
+
+N:38:Get a quest
+C:0:0:0
+I:49:0:q
+
+N:39:Herbal Healing
+C:32000:10000:0
+I:50:0:h
+
+N:40:Song of Lore
+C:2000:800:50
+I:26:0:s
+
+N:41:Distribute earnings
+C:0:0:0
+I:7:2:d
+
+N:42:Morph restoration
+C:3000:1500:750
+I:37:0:r
+
+#for The Mirror
+N:43:View fate
+C:500:500:500
+I:42:0:v
+
+#for The Mirror
+N:44:Research item
+C:1500:1500:1500
+I:1:0:a
+
+#for library in gondol
+N:45:Research item
+C:2000:2000:2000
+I:1:0:a
+
+#for Star-Dome
+N:46:Identify possessions
+C:1200:1000:250
+I:26:0:i
+
+#for Star-Dome
+N:47:Recharge item
+C:1200:1000:150
+I:25:0:r
+
+#for Valarin Temple
+N:48:Restoration
+C:1200:1000:200
+I:29:0:r
+
+#for Sea-Dome
+N:49:Morph restoration
+C:1500:1500:1500
+I:37:0:r
+
+#for The Golden Flower
+N:50:Enchant arrows
+C:1100:1000:200
+I:30:0:a
+
+#for The Golden Flower
+N:51:Enchant bow
+C:1100:1000:200
+I:31:0:b
+
+#for The Fountain
+N:52:Enchant armour
+C:1100:1000:200
+I:24:0:a
+
+#for The Fountain
+N:53:See Healers
+C:1100:1000:0
+I:28:0:h
+
+N:54:Drop an item
+C:0:0:0
+I:43:0:d:s
+
+N:55:Get an item
+C:0:0:0
+I:44:0:g:p
+
+N:56:Request an item
+C:0:0:0
+I:51:2:r
+
+N:57:Ask for loan
+C:0:0:0
+I:52:2:a
+
+N:58:Pay back loan
+C:0:0:0
+I:53:2:p
+
+N:59:Donate an item
+C:0:0:0
+I:43:0:d
+
+# Mage Tower quest in Lothlorien
+N:60:Get a quest
+C:0:0:0
+I:56:0:q
+
+N:61:Get a quest
+C:0:0:0
+I:61:0:q
+
+# Free rest for the night option for homes
+N:62:Rest for the night
+C:0:0:0
+I:17:0:r
+
+# Free rest for the night option at some 'town' locations
+# Restricted to 'liked' races for thematic reasons
+N:63:Rest for the night
+C:0:0:0
+I:17:2:r
+
+# Enchant arrows option with a different letter for Imladris forge
+N:64:Enchant arrows
+C:550:500:100
+I:30:0:r
+
+# Getting free dinner at some 'town' locations
+# Restricted to 'liked' races for thematic reasons
+N:65:Get food and drink
+C:0:0:0
+I:18:2:f
+
+# Ask Bard for directions to Erebor
+N:66:Ask about Erebor
+C:0:0:0
+I:66:0:a \ No newline at end of file
diff --git a/lib/mods/theme/edit/between.map b/lib/mods/theme/edit/between.map
new file mode 100644
index 00000000..4fed5c95
--- /dev/null
+++ b/lib/mods/theme/edit/between.map
@@ -0,0 +1,71 @@
+# Created by Mynstral (mynstral@thehelm.com)
+# Made for PernAngband on 14/08/2001
+
+# Monsters starts awake
+N:0
+
+# Permanent wall
+F:X:63:3
+
+# Floor with dirt
+F:.:88:3
+
+# Floor with grass
+F:,:89:3
+
+# Tree
+F:T:96:3
+
+# Floor with grass with a green thunderlord
+F:G:89:5:955
+
+# Floor with grass with a blue thunderlord
+F:L:89:5:956
+
+# Floor with grass with a brown thunderlord
+F:B:89:5:957:0:0:0:0:0:0:2
+
+# Floor with grass with a bronze thunderlord
+F:z:89:5:958:0:0:0:0:0:0:2
+
+# Floor with dirt with a bronze thunderlord
+F:Z:88:5:958:0:0:0:0:0:0:2
+
+# Floor with grass with a gold thunderlord
+F:D:88:5:959:0:0:0:0:0:0:2
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X..T.TT..T...T...T...T.....T....T......T...T.,,.....T......T....T...T.T..T..TT...T..T.TT.T.TT.TX
+D:X.T.TTTTT...T..TT..T..T.T.T.T...T.....T..T.TT,,..T...T.....T..T......T..T.T..T.T.TT.T.T.T..TTT.X
+D:XTTT.T.T.T.T..TTT.T.T.TTT.T.T.T..T..T.T..T..T.,,..T....T....T..T.T.T..T.T..T.T.TT.T.TT.TT.TTT.TX
+D:XTTT.T...T....T....T..T.TT..T.T.T...T...GG....,,...GG....T...T...T.TTT.T..TTTT.TT...T.TT..T.T.TX
+D:X.TTT..T.T..TTTT.T.T..T..T.TT...T......G..L..,,...L..G..T..T.T...T....T.TTTTTT..TTTTT.T..TT..T.X
+D:XTT.T.TTT.T.T.T.T.T.T.T...T..T...T..T.G..L..B,,.B..L..G....T..T...TT.T.T..TTT.T.TTTT.TTTT..T.T.X
+D:X.T.TT..T.TT.TTT.T.T.T.T.T.T...T.T.T.G..L..B.,,..B..L..G..T..T...T...T.T.T..TTTT.T.T.TT.T.T.TT.X
+D:X.TT.T.TTT.T.T.T.T..T.T..T....T..T..G..L..B..,Z...B..L..G..T...T.T..T...T...T.T.T.TTT.T.T.T..T.X
+D:XT.T.TT.TTTT.TT.T.TTT...T.T.T...T.T.G..L..B..ZDz..B..L..G...T.T...T.T...T..T..T...T..T.TT.T.T.TX
+D:XTTT..TTTT.T.T.T..T.T....T...T..T.T..G..L..B.,,..B..L..G..T....T...T....T....T..T..TT.T.T.TTT..X
+D:XTT.TT..T.T.T.T.T...T...T....T.T..T.T.G..L...,,....L..G..T..T...T..T.......T...T....T..T..TT...X
+D:XTTT.T..T.T..T.T..T...T..T....TT..T.T..GG....,,.....GG...T.T...T.T...T..T.T...T....T...T..T.T..X
+D:XTT...T.T..T....T....T....T....T...T....T.T..,,,.....T...T..T...T.....T...T...T..T..T...T..T.T.X
+D:XT..T.T...T...T...T.....T....T....T....T...TTTTTTTT...T...T...T....T.....T......T....T.....T..TX
+D:XT.T...T...T..T.T...T.T.T..T...T.T...T...T.T...,.T...T...T...T...T..T.....T....T....T...T...T.TX
+D:XTT.T.T.T.T..T..T.T.T.....T....T..T...T.......,,..T........T...T...T...T...T.....T..T..T...TTT.X
+D:X..TT...T..T.....T...T....T...T...T...T..T...,,.....T..T..T.....T.T...T...T...T..T..T.T...T.TT.X
+D:X.TT..T....T.T..T...T..T...T..T.T.T..T..T.T.,,..T..T..T....T..T..T...T.T....T....T...TT.TTTTTT.X
+D:X.T.TTTTTT.T.T.T...T..T..T.....T.T..T...T.T.,,...T...T......T.....T....T...T..T....T..TT.TTTTTTX
+D:XTTT.T.T.TTTTT.TTT...T..T...TT.T.T...T.T....,,.T...T.....T.....T....T.......T..T...T.TT.T.T.TT.X
+D:XTT.T..T.TT.T.T.TT.T...T.T..T.T.......T..T.,,.....T....T....T...........T..T...TT.TTTTTTTTTTTTTX
+D:XTTTT....TT.T.T.TTTTT.T...T..T.T..T......T.,,T......T....T....T.....T...T...T..TTTT.T.TT.T.TTTTX
+D:XTT.TTTTTT.T.TT.TTTTTT...T....TT.T...T....,,.T...T....T.....T....T....T....T..TT.T.TTT.T.T.T.TTX
+D:XTT.T..TTT.T.T.TTTTTTTT.T...T....T....T.T,,.........T....T....T....T...T.T.T.TTT.T.T.T.T..T.T.TX
+D:XTT.T..TTT..T.T.T.T.TT..T.T.T......T.T.T.,,..T...T...T...T..T...T...T.T.TTT.T.T.T.T.T.T.T.T..T.X
+D:X.T.T.T.T.T.T..T.T.T.T.T.T..T...T..T.TT.T.,,..T...T.....T.....T.....T..TTT.T.T.TTTTT.T.TTT.TT.TX
+D:XTT.T.T.T.TTTT.T..T.T.T.TTTT.T..T.T..T.TT.,,.T...T..T..T.......T.T....TTTTT.TTTT.T.TTT.TTTT.T.TX
+D:XT.T.TT.TTTT.T.T.T.TTT.T.T.TT......T...T...,,..T...T...T....T....T.TTT.T.T.T.T.T.T..T.T.T.T.TT.X
+D:XT.TTT.T.T.TTTT.T.T.T.T.TTT.TT..T...T...T..,,..T...T....T....T..TT.T.TT.TTTTT.T.T.TT.TT.TT.T.T.T
+D:XTT.T.T.TT.T.TTTT.T..TT.T.T.TT.T.T.T..T....,,.T...T...T....T..TTTTTTTT.T.T.T.T.T.TT.T.TTTTT.T.TX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:17:47
diff --git a/lib/mods/theme/edit/d_info.txt b/lib/mods/theme/edit/d_info.txt
new file mode 100644
index 00000000..91cf3d20
--- /dev/null
+++ b/lib/mods/theme/edit/d_info.txt
@@ -0,0 +1,701 @@
+# File: d_info.txt
+
+
+# This file is used to initialize the "lib/raw/d_info.raw" file, which is
+# used to initialize the "dungeon type" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# Some store indexes are defined in "defines.h", and must not be
+# changed.
+
+# N:<index>:<name>
+# D:<3 letter short name>:<long name>
+# W:<min depth>:<max depth>:<min player level>:<next dungeon>:<min alloc>:<max alloc chance>
+# L:<floor1>:<%1>:<floor2>:<%2>:<floor3>:<%3>
+# A:<wall1>:<%1>:<wall2>:<%2>:<wall3>:<%3>:<outer wall>:<inner wall>
+# O:<%treasure>:<%combat>:<%magic>:<%tools>
+# E:<dices>d<sides>:<frequency>:<attack type>
+# F:<flags>
+# R:<percent>:<flags mode>
+# M:<monster flags>
+# S:<monster spells>
+
+# Note for <flags mode> :
+# 0 = No restriction
+# 1 = AND
+# 2 = NAND
+# 3 = OR
+# 4 = NOR
+
+# Version stamp (required)
+
+V:2.0.0
+
+### Wilderness(purely cosmetic, never used) ###
+
+N:0:Wilderness
+D:Wil:a way to the Wilderness
+W:0:0:0:0:14:500
+L:89:80:199:20:1:0
+A:96:100:56:0:56:0:57:58
+O:20:20:20:20
+F:PRINCIPAL | FLAT | NO_RECALL
+R:100:0
+
+### The principal dungeons, they were created by spliting the vanilla dungeon ###
+
+N:1:Mirkwood
+D:Mkw:a way to the Mirkwood Forest.
+W:11:33:5:0:14:160
+L:89:95:199:5:88:0
+A:96:100:97:0:56:0:202:96
+O:20:20:20:20
+F:PRINCIPAL | NO_DOORS | NO_DESTROY | FLAT
+F:FILL_METHOD_0
+R:100:0
+
+N:2:Barad-Dur
+D:BDr:a door to the tower of Barad-Dur.
+W:34:66:15:0:14:160
+L:88:67:93:33:1:0
+L:0:100:0
+A:97:50:56:50:56:0:57:97
+A:0:100:0
+O:20:20:20:20
+F:PRINCIPAL | LAVA_RIVER | CAVERN | NO_STREAMERS
+F:FILL_METHOD_2 | NO_RECALL
+R:100:0
+
+N:3:Angband
+D:Ang:an entrance to the Pits of Angband.
+W:67:100:30:0:14:160
+L:1:100:1:0:1:0
+A:56:100:56:0:56:0:57:58
+O:20:20:20:20
+F:PRINCIPAL | CAVERN | NO_EASY_MOVE | NO_RECALL
+F:ADJUST_LEVEL_1_2 | ADJUST_LEVEL_1
+F:FILL_METHOD_0
+R:100:0
+
+N:4:Barrow-Downs
+D:BDw:a way to the Barrow-Downs.
+W:1:10:1:0:14:160
+# Theme adds *fog* (dense mist) on the Barrow-Downs :)
+L:88:94:210:2:199:4
+A:96:80:97:19:57:1:57:97
+A:100:0:0
+O:20:20:20:20
+F:PRINCIPAL | FLAT
+F:FILL_METHOD_3
+R:25:1
+M:UNDEAD
+R:75:0
+
+# The Additional dungeons
+
+# Mount Doom
+# Levels 85-99
+N:5:Orodruin
+D:MDm:a way to the top of the Mount Doom.
+W:85:99:18:0:14:160
+L:86:90:205:10:1:0
+A:177:100:0:0:0:0:85:87
+O:10:10:30:30
+E:2d10:10:FIRE
+F:CAVE | LAVA_RIVER | NO_RECALL | NO_STREAMERS
+F:FILL_METHOD_0 | NO_EASY_MOVE
+R:100:1
+M:IM_FIRE
+
+# Nether Realm
+# Levels 666-696 (!!!)
+# guarded by Tik'srvzllat, who has the Ring 'Fuin'
+N:6:Nether Realm
+D:Nth:a magical portal to the Nether Realm.
+W:666:696:40:0:14:160
+L:102:80:86:15:85:5
+A:85:80:87:20:87:0:57:85
+A:50:50:0
+O:25:25:25:25
+E:10d10:3:NETHER
+F:EMPTY | FORGET | NO_BREATH | NO_EASY_MOVE | NO_SHAFT
+F:ADJUST_LEVEL_2 | NO_RECALL | NO_STREAMERS
+F:LAVA_RIVER | FINAL_GUARDIAN_1032 | FINAL_ARTIFACT_203
+F:FILL_METHOD_2 | NO_RECALL_OUT
+R:5:0
+R:95:3
+M:RES_NETH | R_CHAR_G | R_CHAR_W | R_CHAR_U
+
+# The Lost Land of Numenor
+# levels 35-50
+# guarded by Ar-Pharazon the Golden, who has the stone "Coimir".
+N:7:Submerged Ruins
+D:Num:a submerged way to the lost land of Numenor.
+W:35:50:25:0:14:160
+L:84:95:187:5:1:0
+A:187:80:84:10:56:10:57:187
+A:60:0:40
+O:30:30:10:10
+E:1d1:1:ACID
+F:NO_STREAMERS
+F:FINAL_GUARDIAN_980 | FINAL_ARTIFACT_204
+F:FILL_METHOD_3 | WATER_BREATH
+R:20:0
+R:80:3
+M:AQUATIC | CAN_SWIM | CAN_FLY
+
+# Used for astral mode
+N:8:Halls of Waiting
+D:HWa:*A BUG*YOU should see this message!*
+W:1:98:1:0:14:160
+L:1:100:1:0:1:0
+O:20:20:20:20
+A:56:100:56:0:56:0:57:58
+F:RANDOM_TOWNS | NO_RECALL | NO_SHAFT
+F:FILL_METHOD_0
+R:100:2
+M:UNIQUE
+
+# Cirith Ungol
+# levels 25-50
+# guarded by Shelob.
+# Updated for Theme to lead out into Gorgoroth a la Moria
+N:9:Cirith Ungol
+D:CUg:an entrance to Cirith Ungol.
+W:25:50:10:0:14:160
+L:87:5:88:65:16:30
+A:97:90:16:10:56:0:16:58
+O:30:30:30:10
+E:4d4:20:POISON
+F:FINAL_GUARDIAN_481
+F:RANDOM_TOWNS | CIRCULAR_ROOMS
+F:FILL_METHOD_2
+F:FORCE_DOWN
+F:WILD_65_56__67_53
+R:2:0
+R:49:3
+M:SPIDER | R_CHAR_a | R_CHAR_I |
+R:49:3
+M:ORC | R_CHAR_w | R_CHAR_m | R_CHAR_j
+
+# The Heart of the Earth
+# levels 25-36
+# guarded by Golgarach, the Living Rock
+N:10:Heart of the Earth
+D:HoE:a passage leading into the very heart of the world.
+W:25:36:10:0:14:160
+L:1:100:1:0:1:0
+A:56:100:56:0:56:0:57:58
+O:40:10:10:20
+G:life
+F:EVOLVE | FINAL_GUARDIAN_1035 | NO_RECALL | NO_SHAFT
+R:40:3
+M:R_CHAR_# | R_CHAR_X | R_CHAR_g | R_CHAR_E |
+R:30:3
+M:PASS_WALL | KILL_WALL | HURT_ROCK
+R:30:0
+
+# The Void
+# Levels 128-150
+# Where Melkor lurks for the final battle!
+N:11:The Void
+D:Vod:a jumpgate to the Void
+W:128:150:40:0:20:160
+L:183:97:102:3:0:0
+A:183:90:102:10:0:0:102:102
+A:40:60:0
+O:25:25:25:25
+E:20d6:100:DARK
+F:EMPTY | FORGET | NO_BREATH | NO_EASY_MOVE | NO_RECALL_OUT | NO_RECALL |
+F:ADJUST_LEVEL_1_2 | ADJUST_LEVEL_1 | NO_STREAMERS | NO_SHAFT
+F:FILL_METHOD_2
+F:FINAL_GUARDIAN_1044 |
+R:1:0
+R:99:3
+M:UNDEAD | DEMON | DRAGON | NONLIVING | SPIRIT
+
+# TEST dungeon
+N:12:Test
+D:Tst:a way to test dungeon gen
+W:1:10:1:0:14:160
+L:88:78:89:18:199:4
+L:0:95:5
+A:177:100:0:0:0:0:85:87
+A:100:0:0
+O:20:20:20:20
+F:FILL_METHOD_3 | SMALL
+R:100:0
+G:dungeon2
+
+
+# The Paths of the Dead
+# levels 40-70
+# Feagwath is there, guarding Doomcaller
+N:16:Paths of the Dead
+D:PoD:the entrance to the Paths of the Dead.
+W:40:70:18:0:24:100
+L:88:85:84:15:1:0
+A:56:75:87:25:56:0:57:58
+O:30:30:30:2
+E:1d1:20:RAISE
+F:FINAL_GUARDIAN_804 | FINAL_ARTIFACT_91
+F:FILL_METHOD_3
+R:5:0
+R:10:3
+M:R_CHAR_p
+R:85:3
+M:UNDEAD | NONLIVING
+
+# The Illusory Castle
+# levels 35-52
+# Guarded by The Glass Golem guarding The Helm of Knowledge
+N:17:Illusory Castle
+D:Ill:an entrance to the Illusory Castle.
+W:35:52:10:0:24:100
+L:1:98:188:2:1:0
+A:56:50:189:50:56:0:57:58
+O:50:10:20:20
+E:6d2:6:CONFUSION
+F:RANDOM_TOWNS | NO_STREAMERS
+F:FINAL_GUARDIAN_1033 | FINAL_ARTIFACT_160
+F:FILL_METHOD_1
+R:30:0
+R:70:3
+M:STUPID | WEIRD_MIND | SHAPECHANGER | ATTR_MULTI | CHAR_MULTI | RAND_25 |
+M:RAND_50 | EMPTY_MIND | INVISIBLE | PASS_WALL | KILL_WALL
+S:BR_CONF | BR_CHAO | BA_CHAO | CONF | FORGET | TRAPS | MULTIPLY
+
+# The Maze
+# Levels 25-37
+# Guarded by The Minotaur of the Labyrinth with the Steel Helm of Hammerhand
+N:18:Maze
+D:Maz:a small tunnel leading to a maze of twisty little passages, all alike.
+W:25:37:15:0:20:160
+L:1:100:1:0:1:0
+A:56:98:48:2:56:0:57:58
+O:2:40:10:40
+G:maze
+F:SMALLEST | FORGET
+F:FINAL_GUARDIAN_1029 | FINAL_ARTIFACT_38
+R:80:0
+R:20:3
+M:R_CHAR_p
+
+# The Orc Cave
+# levels 10-22
+# There is Azog with the Wand of Thrain at the bottom
+N:19:Orc Cave
+D:Orc:a dark tunnel leading to an Orc Cave.
+W:10:22:8:0:35:200
+L:88:100:1:0:1:0
+A:97:100:56:0:56:0:57:97
+O:5:50:10:25
+F:RANDOM_TOWNS |
+F:FINAL_OBJECT_810 | FINAL_GUARDIAN_373 | CAVE |
+F:FILL_METHOD_0
+F:FORCE_DOWN
+F:WILD_49_21__51_19
+R:30:3
+M:TROLL
+R:20:0
+R:50:3
+M:ORC | R_CHAR_o | R_CHAR_O
+
+# Erebor
+# levels 60-72
+# There is Glaurung
+N:20:Erebor
+D:Ere:a tunnel leading into depths of the Lonely Mountain.
+W:60:72:35:0:20:140
+L:88:100:1:0:1:0
+A:97:90:87:10:56:0:57:97
+O:40:40:40:40
+F:BIG | LAVA_RIVER | CAVERN | NO_RECALL | NO_STREAMERS
+F:CAVE | DOUBLE | FINAL_GUARDIAN_715 |
+F:FILL_METHOD_2
+R:10:0
+R:60:1
+M:DRAGON | R_CHAR_D
+R:30:1
+M:DRAGON | R_CHAR_d
+
+# The Old Forest
+# levels 13-25
+# Old Man Willow protects it
+N:21:The Old Forest
+D:OFr:a path into the Old Forest.
+W:13:25:5:0:15:100
+L:88:76:84:16:199:8
+L:68:16:16
+A:96:100:56:0:56:0:202:96
+O:20:5:15:30
+F:WATER_RIVERS | NO_DOORS | NO_DESTROY | FLAT | NO_STREAMERS
+F:RANDOM_TOWNS | FINAL_GUARDIAN_206
+F:FILL_METHOD_3
+R:30:0
+R:40:3
+M:ANIMAL
+R:30:3
+M:UNDEAD | R_CHAR_h | R_CHAR_l
+
+# The Mines of Moria
+# levels 30-50
+# There is Durin's Bane
+N:22:Moria
+D:MoM:a stone door leading to the Mines of Moria.
+W:30:50:20:0:40:40
+L:88:100:1:0:1:0
+A:97:100:56:0:56:0:57:97
+O:30:50:10:5
+F:FINAL_GUARDIAN_872 | WATER_RIVER | NO_STREAMERS
+F:FORCE_DOWN
+F:RANDOM_TOWNS
+F:WILD_45_30__44_37
+F:FILL_METHOD_0
+R:40:3
+M:ORC
+R:30:3
+M:TROLL | GIANT
+R:20:3
+M:DEMON
+R:10:0
+
+# The tower of Dol Guldur
+# Levels 57-70
+# The Necromancer (weak Sauron) at the bottom, with the Ring of Durin
+N:23:Dol Guldur
+D:TDG:a gate leading to the tower of Dol Guldur.
+W:57:70:34:0:24:160
+L:1:80:174:20:1:0
+A:56:100:56:0:56:0:57:58
+O:20:1:70:9
+F:SMALL | FINAL_GUARDIAN_819 | FINAL_ARTIFACT_205
+F:FILL_METHOD_3
+R:30:3
+M:R_CHAR_p | R_CHAR_P
+R:10:3
+M:ORC | TROLL
+R:20:3
+M:UNDEAD
+R:30:3
+M:DEMON | DRAGON
+R:10:0
+
+# Dungeons from Variaz
+
+# The Small Water Cave
+# levels 32-34
+# The Watcher in the Water is at the bottom
+N:24:The Small Water Cave
+D:SWC:the entrance to a small water cave.
+W:32:34:20:0:14:160
+L:84:100:84:0:84:0
+A:97:100:56:0:56:0:57:58
+O:10:10:30:30
+E:1d1:20:ACID
+F:FINAL_GUARDIAN_517 | NO_RECALL
+F:FILL_METHOD_0
+R:10:0
+R:10:3
+M:AQUATIC
+R:40:1
+M:IM_COLD
+S:BA_WATE
+R:40:3
+M:IM_COLD
+
+# The Land of Mountains
+# Trone the rebel Thunderlord is hiding here, with
+# the Robe of Curunir (Theme update as Trone's coat is gone)
+# Levels 45-70
+N:25:The Sacred Land Of Mountains
+D:LoM:the way to the Sacred Land of Mountains.
+W:45:70:20:0:14:160
+L:89:100:89:0:89:0
+A:97:100:56:0:56:0:97:97
+O:20:20:20:20
+F:RANDOM_TOWNS | FLAT | NO_STREAMERS
+F:FINAL_GUARDIAN_789 | FINAL_ARTIFACT_228
+F:FILL_METHOD_0
+R:60:3
+M:CAN_FLY
+R:40:0
+
+# The Land of Rhun
+# levels 26-40
+# Guarded by Ulfang the Black, Morgoth's first Easterling follower.
+N:26:The Land Of Rhun
+D:LoR:a way to the Land of Rhun.
+W:26:40:15:0:14:160
+L:89:100:1:0:1:0
+A:89:50:96:25:84:25:57:58
+O:20:20:20:20
+F:RANDOM_TOWNS | FLAT | NO_STREAMERS | FINAL_GUARDIAN_990
+F:FILL_METHOD_1
+R:30:3
+M:R_CHAR_p | R_CHAR_h | R_CHAR_l
+R:30:3
+M:ANIMAL
+R:40:0
+
+# The Withered Heath
+# level 22-30
+# guarded by the Sandworm Queen (and her children), who will drop her armour
+N:27:The Withered Heath
+D:SwL:the Withered Heath, from whence came the Great Worms.
+W:22:30:12:0:5:200
+L:91:85:94:10:93:5
+A:98:100:96:0:84:0:94:94
+O:15:5:60:20
+F:NO_DOORS | SAND_VEIN |
+F:FINAL_GUARDIAN_1030 | FINAL_ARTIFACT_153
+F:FILL_METHOD_0
+R:100:1
+M:R_CHAR_w
+R:10:3
+S:MULTIPLY
+
+# Used by the death fate
+N:28:Death fate
+D:Dth:a fated death.
+W:1:1:1:0:30:255
+L:1:100:1:0:1:0
+A:1:100:1:0:1:0:1:1
+O:1:1:1:1
+F:EMPTY | SMALLEST | NO_RECALL | NO_STREAMERS
+F:FILL_METHOD_0
+R:100:0
+
+# The Grinding Ice
+# levels 20-40
+# Guarded by Elenwe the Lost
+N:29:The Helcaraxe
+D:Ice:the entrance to the Grinding Ice of the Helcaraxe.
+W:20:40:10:0:14:160
+L:90:0:88:70:84:30
+L:90:0:10
+A:95:0:56:100:56:0:57:58
+A:100:0:0
+O:20:20:20:20
+E:1d4:15:COLD
+F:DOUBLE | WATER_RIVER | CAVERN | NO_STREAMERS
+F:FINAL_GUARDIAN_1034 |
+F:FILL_METHOD_2
+R:100:1
+M:IM_COLD
+
+# The Lost Temple of "..player.pgod.."
+# Generated in god quest.
+# Most dungeon attributes altered during the quest.
+# See god.lua for details
+N:30:a Lost Temple
+D:LTm:the entrance to a lost temple.
+W:1:50:1:0:14:160
+L:1:100:1:0:1:0
+A:56:100:56:0:56:0:57:58
+O:20:20:20:20
+F:FILL_METHOD_4 | NO_RECALL
+R:100:0
+
+### New dungeons added for Theme module ###
+
+
+# Forodwaith
+# levels 75-80
+# Guarded by The Hunter
+N:31:Forodwaith
+D:NWa:a path leading through the wastelands of the North
+W:75:80:40:0:14:160
+# ice, ash, and dirt
+L:90:20:93:40:88:40
+#Ugly - using floor tiles for walls, only rooms have real walls
+A:90:20:93:40:88:40:88:211
+O:20:20:20:20
+# it is always dark here in the northern wastelands
+E:2d4:1:DARK
+F:NO_DOORS | CAVERN | COLD | NO_DESTROY | EMPTY | FLAT |
+F:NO_RECALL | LIFE_LEVEL | NO_STREAMERS | NO_SHAFT |
+F:FINAL_GUARDIAN_389 |
+F:FILL_METHOD_4
+R:100:3
+M:COLD_BLOOD | HURT_LITE | IM_COLD
+
+# Emyn Luin
+# levels 60-70
+# Guarded by Naugladur, who has Nauglamir
+N:32:Emyn Luin
+D:ELu:a path into the depths of the Blue Mountains
+W:60:70:30:0:14:160
+# grass, flowers, and dirt
+L:89:45:81:5:88:50
+# blue mountains, granite, hailstones
+A:215:100:215:0:215:0:56:211
+# lots of treasure, not much magic
+O:50:20:10:30
+F:CAVE | CAVERN | CIRCULAR_ROOMS | RANDOM_TOWNS |
+F:NO_STREAMERS | NO_RECALL | NO_DESTROY
+# no_recall because it should not be so easy to get Nauglamir. :P
+F:FINAL_GUARDIAN_457 | FINAL_ARTIFACT_6
+F:FILL_METHOD_3
+R:100:0
+M:R_CHAR_k | R_CHAR_o
+
+#Dol Amroth - Castle of Prince Imrahil
+#levels 25-35
+#Guarded by Prince Imrahil (yes, he's evil in this game)
+N:33:Dol Amroth
+D:DAm:a way to the top of the castle of Dol Amroth
+W:25:35:15:0:14:160
+# Vanilla-style
+L:1:100:1:0:1:0
+A:56:100:56:0:56:0:57:58
+O:20:20:20:20
+F:SMALLEST | NO_DESTROY | TOWER | RANDOM_TOWNS |
+F:ADJUST_LEVEL_1 | NO_STREAMERS | NO_SHAFT | NO_STAIR |
+F:NO_EASY_MOVE | FILL_METHOD_2
+F:FINAL_GUARDIAN_402 |
+R:80:3
+M:R_CHAR_p | R_CHAR_P
+R:20:3
+M:SMART | TAKE_ITEM
+
+#Angmar
+#levels 80-90
+#Guarded by Fuinur, who has Eowyn's sword
+N:34:Angmar
+D:WRA:a dark path through the Witch Realm of Angmar
+W:80:90:49:0:14:160
+# Tainted, dark, evil
+L:93:70:174:20:226:10
+# Dark mountain chains only
+A:214:100:214:0:214:0:214:214
+O:20:20:20:20
+# In addition to swamp water poison, we have disenchantment
+E:1d1:1:DISENCHANT
+F:ADJUST_LEVEL_1_2 | NO_DOORS | NO_STREAMERS |
+F:HOT | FLAT | NO_SHAFT | NO_NEW_MONSTER | CIRCULAR_ROOMS |
+F:FINAL_GUARDIAN_242 | FINAL_ARTIFACT_110
+F:FILL_METHOD_2
+R:50:0
+R:50:3
+M:RES_DISE | UNDEAD | DEMON | NONLIVING
+
+#Near Harad
+#levels 20-25
+#Guarded by Herumor, who has the heavy crossbow of Umbar
+N:35:Near Harad
+D:NHa:a desert path into Near Harad
+W:20:25:15:0:14:160
+#It's a desert, so sand and only sand
+L:91:100:91:0:91:0
+#Ugly - using floor tiles for walls, only rooms have real walls
+A:91:100:91:0:91:0:98:91
+O:20:20:20:20
+#Living is slow in the desert, heh :)
+E:1d1:1:INERTIA
+F:NO_DOORS | CAVE | CAVERN | HOT | NO_DESTROY | EMPTY | FLAT
+F:RANDOM_TOWNS | NO_STREAMERS | NO_SHAFT |
+F:FINAL_GUARDIAN_395 | FINAL_ARTIFACT_171
+F:FILL_METHOD_4
+#It's a desert (sort of wilderness) so WILD_TOO monsters, plus the 'p's for the Haradrim
+R:30:0
+R:70:3
+M:WILD_TOO | R_CHAR_p
+
+#Isengard - Orc Cave on steroids.
+#levels 35-40
+#It ends in a special level with the Palantir of Orthanc and Sharkey
+N:36:Isengard
+D:Isg:a passage to the caves beneath Isengard
+W:35:40:20:0:14:160
+# Like the Orc caves
+L:88:100:1:0:1:0
+A:97:100:56:0:56:0:57:97
+O:20:20:20:20
+F:CAVE | ADJUST_LEVEL_2 | NO_STREAMERS |
+F:FILL_METHOD_0
+R:20:0
+R:30:3
+M:TROLL | R_CHAR_T |
+R:50:3
+M:ORC | R_CHAR_o | R_CHAR_O
+
+# Tol Eressea - of course you never actually set foot on Tol Eressea ;)
+# levels 40-45
+# Guarded by Marda and the Robe of Belegaer
+N:37:Tol Eressea
+D:TEr:a way to the Lonely Isle
+W:40:45:40:0:14:160
+# shallow water, lilies
+L:84:60:222:40:222:0
+# Going to have to add walls here to avoid being overly nasty
+A:211:100:211:0:211:0:211:211
+# As little loot as possible, this is open water, after all
+O:1:1:1:1
+F:SMALLEST | NO_DOORS | NO_DESTROY | EMPTY | FLAT |
+F:ADJUST_LEVEL_1 | NO_STREAMERS | NO_SHAFT | NO_NEW_MONSTER |
+F:FINAL_GUARDIAN_791 | FINAL_ARTIFACT_219 |
+F:FILL_METHOD_0
+R:1:0
+R:99:1
+M:R_CHAR_B
+
+#Utumno
+#levels 101-127
+#Guarded by no one (yet!)
+N:38:Utumno
+D:Utu:an entrance to the depths of Utumno
+W:101:127:30:0:14:160
+L:1:100:1:0:1:0
+A:56:100:56:0:56:0:57:58
+O:20:20:20:20
+F:CAVERN | NO_EASY_MOVE | NO_RECALL
+F:ADJUST_LEVEL_1_2 | ADJUST_LEVEL_1
+F:FILL_METHOD_0
+R:100:0
+
+# Bilbo's trail in the Barrow-downs
+# just one special level that later becomes a different one, sans princess.
+N:39:Bilbo's trail
+D:Btr:a trail left by a fleeing hobbit
+W:10:10:1:0:14:160
+L:88:94:210:2:199:4
+A:96:80:97:19:57:1:57:97
+A:100:0:0
+O:20:20:20:20
+F:FLAT
+F:FILL_METHOD_3
+R:25:1
+M:UNDEAD
+R:75:0
+
+# Thorin's trail in Mirkwood
+# just one special level that later becomes a different one, sans princess.
+N:40:Thorin's trail
+D:Ttr:a trail left by a purposeful dwarf
+W:33:33:15:0:14:160
+L:89:95:199:5:88:0
+A:96:100:97:0:56:0:202:96
+O:20:20:20:20
+F:NO_DOORS | NO_DESTROY | FLAT
+F:FILL_METHOD_0
+R:100:0
+
+# N:<index>:<name>
+# D:<3 letter short name>:<long name>
+# W:<min depth>:<max depth>:<min player level>:<next dungeon>:<min alloc>:<max alloc chance>
+# L:<floor1>:<%1>:<floor2>:<%2>:<floor3>:<%3>
+# A:<wall1>:<%1>:<wall2>:<%2>:<wall3>:<%3>:<outer wall>:<inner wall>
+# O:<%treasure>:<%combat>:<%magic>:<%tools>
+# E:<dices>d<sides>:<frequency>:<attack type>
+# F:<flags>
+# R:<percent>:<flags mode>
+# M:<monster flags>
+# S:<monster spells>
+# 0 = No restriction
+# 1 = AND
+# 2 = NAND
+# 3 = OR
+# 4 = NOR
diff --git a/lib/mods/theme/edit/dragons.map b/lib/mods/theme/edit/dragons.map
new file mode 100644
index 00000000..164c97c8
--- /dev/null
+++ b/lib/mods/theme/edit/dragons.map
@@ -0,0 +1,43 @@
+# permanent wall
+F:X:61:0
+
+# Mountain Chain
+F:^:97:0
+
+# granite
+F:#:57:0
+
+# up staircase
+F:<:6:0
+
+# Dirt
+F:.:88:0
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:X^^^^^.....................^^^^^X
+D:X^^^.........................^^^X
+D:X^^...........................^^X
+D:X^^...........................^^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^.............................^X
+D:X^^...........................^^X
+D:X^^...........................^^X
+D:X^^^........................<^^^X
+D:X^^^^^.....................^^^^^X
+D:X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:6:6
+
diff --git a/lib/mods/theme/edit/e_info.txt b/lib/mods/theme/edit/e_info.txt
new file mode 100644
index 00000000..72b8348e
--- /dev/null
+++ b/lib/mods/theme/edit/e_info.txt
@@ -0,0 +1,3007 @@
+# File: e_info.txt
+
+
+# This file is used to initialize the "lib/data/e_info.raw" file, which is
+# used to initialize the "ego-item" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/data/e_info.raw" file.
+
+# The ego-item indexes are defined in "defines.h", and must not be changed.
+
+# Note that every "ego-item" type has a different "index", and can only be
+# created from items that belong to a certain "slot" in the equipment, if
+# one assumes that "ammo" belongs to an imaginary slot (23). However, it
+# is possible for several "ego-item" types to have the same "textual name",
+# such as with "Armor of Resistance" and "Shield of Resistance".
+
+# === Understanding e_info.txt ===
+
+# N: serial number : ego type
+# D: description
+# T: tval : min sval : max sval
+# R: rarity
+# X: position : slot : rating
+# W: depth : rarity1 : rarity2 : cost
+# C: to-hit : to-dam : to-ac : pval
+# r:N:needed flags on the base object
+# r:F:forbidden flags on the base object
+# Z: granted_power
+# F: flags
+
+# 'N' indicated the beginning of an entry. The serial number must increase
+# for each new item.
+
+# 'D' contains description. This field is currently not supported.
+
+# 'T' is for possible tval and sval value of the base item.
+# Up to 5 entries are possible.
+
+# 'R' stands for rarity, or randomness. It specifies percentual chance
+# of generated item to have following 'F' flags. I.e. 'R:40' followed
+# by 'F:SPEED' means, that 40% of item of this ego type will boost speed.
+
+# 'X' is for extra information. Position value 'A' means that ego-type name
+# will appear after base-item name ('Robe of Permanence'), value 'B' means
+# that ego-type name will appear before base-item name ('Elven Plate Mail').
+# Slot is determining in which equipment slots item could be equipped. This
+# value is currently ignored. Rating determines how level feeling will be
+# affected.
+
+# 'W' is for extra information. Depth is the depth the object is normally
+# found at, rarity determines how common the object is and cost is the items
+# value.
+
+# 'C' stands for 'creation'. It determines maximal to-hit, to-damage, AC and
+# stats (pval) values item can get.
+
+# 'Z' is granted power. See tables.c, array powers_type_init (lines 4511-4943).
+
+# 'F' contains flags. Most are self explaining, rest could be found in source.
+
+
+
+# Version stamp (required)
+
+V:2.0.0
+
+### Mage Staff ###
+
+N:1:of Mana
+X:A:24:20
+T:6:0:99
+W:5:3:8:10000
+C:-30:-30:0:3
+R:100
+F:MANA
+f:MANA
+R:70
+F:PVAL_M2
+
+N:2:of Power
+X:A:24:30
+T:6:0:99
+W:5:5:8:20000
+C:-30:-30:0:10
+R:100
+F:SPELL
+f:SPELL
+R:70
+F:PVAL_M2
+
+N:3:of Wizardry
+X:A:24:60
+T:6:0:99
+W:10:1:8:50000
+C:-40:-40:0:3
+R:100
+F:MANA | SPELL
+R:50
+F:PVAL_M2
+
+N:4:of Spell
+T:6:0:99
+X:A:24:60
+W:0:2:8:40000
+C:0:0:0:0
+R:100
+F:ACTIVATE
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+### Body Armor ###
+
+N:5:of Resist Acid
+T:36:0:99
+T:37:0:99
+X:A:30:16
+W:0:4:20:1000
+R:100
+F:RES_ACID | IGNORE_ACID
+f:RES_ACID | IGNORE_ACID
+
+N:6:of Resist Lightning
+T:36:0:99
+T:37:0:99
+X:A:30:10
+W:0:4:20:400
+R:100
+F:RES_ELEC | IGNORE_ELEC
+f:RES_ELEC | IGNORE_ELEC
+
+N:7:of Resist Fire
+T:36:0:15
+T:36:17:99
+T:37:0:99
+X:A:30:14
+W:0:4:20:800
+R:100
+F:RES_FIRE | IGNORE_FIRE
+f:RES_FIRE | IGNORE_FIRE
+
+N:8:of Resist Cold
+T:36:0:15
+T:36:17:99
+T:37:0:99
+X:A:30:12
+W:0:4:20:600
+R:100
+F:RES_COLD | IGNORE_COLD
+f:RES_COLD | IGNORE_COLD
+
+N:9:of Resistance
+T:36:0:99
+T:37:0:99
+X:A:30:20
+W:0:2:20:12500
+C:0:0:10:0
+R:100
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+f:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+R:25
+F:R_HIGH
+
+N:10:Elven
+T:36:0:99
+T:37:0:99
+X:B:30:25
+W:0:2:20:15000
+C:0:0:10:3
+R:100
+F:STEALTH | ESP_ORC
+f:STEALTH
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:OLD_RESIST
+R:25
+F:RES_POIS
+
+# Robe
+N:11:of Permanence
+T:36:2:2
+X:A:30:30
+W:0:1:10:30000
+C:0:0:10:0
+R:100
+F:SUST_STR | SUST_DEX | SUST_CON | SUST_INT | SUST_WIS | SUST_CHR |
+F:HOLD_LIFE | RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:OLD_RESIST
+R:2
+F:R_IMMUNITY
+
+# Armour of Dunharrow - built on Filthy rags of leprousness
+N:12:of Dunharrow
+T:35:0:99
+T:36:0:99
+T:37:0:99
+X:A:30:0
+W:0:1:10:0
+C:0:0:0:-6
+R:100
+F:CON | STR | R_STAT | CURSED | HEAVY_CURSE | AGGRAVATE
+# No CURSE_NO_DROP here, players seems to unlike surprises
+
+# Mithirl & Galvorn mails & PDSM
+N:13:of Immunity
+T:37:25:25
+T:37:30:30
+T:38:30:30
+X:A:30:40
+W:60:10:100:30000
+C:0:0:5:0
+R:100
+F:R_IMMUNITY
+
+# Ego DSM
+N:14:of Defense
+T:38:0:99
+X:A:30:5
+W:20:40:100:1000
+C:0:0:8:0
+R:100
+F:SUSTAIN
+
+# Boots of Jumping
+N:15:of Jumping
+T:30:0:99
+X:A:35:16
+W:0:3:27:500
+C:0:0:0:3
+Z:blink
+R:100
+F:ACTIVATE
+a:HARDCORE=JUMP
+
+### Shields ###
+
+N:16:of Resist Acid
+T:115:56:56
+T:34:0:5
+T:34:7:99
+X:A:32:16
+W:0:6:22:1000
+R:100
+F:RES_ACID | IGNORE_ACID
+f:RES_ACID | IGNORE_ACID
+
+N:17:of Resist Lightning
+T:34:0:5
+T:34:7:99
+T:115:56:56
+X:A:32:10
+W:0:6:22:400
+R:100
+F:RES_ELEC | IGNORE_ELEC
+f:RES_ELEC | IGNORE_ELEC
+
+N:18:of Resist Fire
+T:34:0:5
+T:34:7:99
+T:115:56:56
+X:A:32:14
+W:0:6:22:800
+R:100
+F:RES_FIRE | IGNORE_FIRE
+f:RES_FIRE | IGNORE_FIRE
+
+N:19:of Resist Cold
+T:115:56:56
+T:34:0:5
+T:34:7:99
+X:A:32:12
+W:0:6:22:600
+R:100
+F:RES_COLD | IGNORE_COLD
+f:RES_COLD | IGNORE_COLD
+
+N:20:of Resistance
+T:115:56:56
+T:34:0:5
+T:34:7:99
+X:A:32:20
+W:0:2:22:12500
+C:0:0:10:0
+R:100
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+f:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:21:of Reflection
+T:115:56:56
+T:34:0:5
+T:34:7:99
+X:A:32:20
+W:0:2:22:15000
+C:0:0:5:0
+R:100
+F:REFLECT
+f:REFLECT
+F:IGNORE_ELEC | IGNORE_ACID | IGNORE_COLD | IGNORE_FIRE
+
+# Metal shields only
+N:22:of Electricity
+T:34:3:3
+T:34:5:5
+T:34:10:10
+X:A:32:10
+W:0:2:22:400
+R:100
+F:RES_ELEC | IGNORE_ELEC | SH_ELEC
+f:SH_ELEC
+
+### Crowns and Helms ###
+
+N:23:of the Noldor
+T:115:57:57
+T:32:0:6
+T:32:8:99
+X:A:33:13
+C:0:0:0:2
+W:0:1:8:500
+R:100
+F:DEX | SUST_DEX | ACTIVATE | ESP_ORC
+a:HARDCORE=NOLDOR
+
+N:24:of Intelligence
+X:A:33:13
+C:0:0:0:2
+W:0:2:15:500
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:INT | SUST_INT
+f:INT
+
+N:25:of Wisdom
+X:A:33:13
+W:0:2:15:500
+C:0:0:0:2
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:WIS | SUST_WIS
+f:WIS
+
+N:26:of Beauty
+X:A:33:8
+W:0:2:15:1000
+C:0:0:0:4
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:CHR | SUST_CHR
+f:CHR
+
+# 40% chance of increase spell power
+N:27:of the Magi
+X:A:33:15
+W:0:1:8:7500
+C:0:0:0:3
+T:33:0:99
+R:100
+F:INT | SUST_INT |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:ABILITY | R_HIGH
+R:40
+F:SPELL
+R:50
+F:SPELL_CONTAIN | WIELD_CAST
+
+N:28:of Gondor
+X:A:33:19
+W:0:1:8:2000
+C:0:0:0:3
+T:32:0:99
+T:33:0:99
+R:100
+F:STR | DEX | CON | SUST_STR | SUST_DEX | SUST_CON | FREE_ACT
+F:R_HIGH
+
+N:29:of Arnor
+X:A:33:17
+W:0:1:8:2000
+C:0:0:0:3
+T:32:0:99
+T:33:0:99
+R:100
+F:WIS | CHR | SUST_WIS | SUST_CHR
+F:R_HIGH
+
+N:30:of Seeing
+X:A:33:8
+W:0:1:8:1000
+C:0:0:0:5
+T:32:0:6
+T:32:8:99
+T:33:0:99
+T:115:57:57
+R:100
+F:SEARCH | RES_BLIND | SEE_INVIS
+f:SEARCH
+R:20
+F:ESP_ALL
+
+N:31:of Infravision
+X:A:33:11
+W:0:1:15:500
+C:0:0:0:5
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:INFRA | HIDE_TYPE
+f:INFRA
+
+N:32:of Light
+X:A:33:6
+W:0:2:15:500
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:LITE1 | RES_LITE
+f:LITE1
+
+N:33:of Telepathy
+X:A:33:20
+W:0:1:8:50000
+T:33:0:99
+R:100
+F:ESP_ALL
+f:ESP_ALL
+
+N:34:of Regeneration
+X:A:33:10
+W:0:1:8:1500
+T:32:0:6
+T:32:8:99
+T:33:0:99
+T:115:57:57
+R:100
+F:REGEN
+f:REGEN
+
+N:35:of Teleportation
+X:A:33:0
+W:0:1:7:50
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:TELEPORT
+f:TELEPORT
+R:90
+F:CURSED
+
+N:36:of Stupidity
+X:A:33:0
+C:0:0:0:-5
+W:0:2:7:0
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:INT | CURSED
+f:INT
+# No CURSE_NO_DROP here, players seems to unlike surprises
+
+N:37:of Naivety
+X:A:33:0
+C:0:0:0:-5
+W:0:2:7:0
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:WIS
+f:WIS
+
+N:38:of Ugliness
+X:A:33:0
+C:0:0:0:-5
+W:0:1:7:0
+T:32:0:6
+T:32:8:99
+T:115:57:57
+R:100
+F:CHR
+f:CHR
+
+N:39:of Sickliness
+X:A:33:0
+C:0:0:0:-5
+W:0:1:7:0
+T:33:0:99
+R:100
+F:STR | DEX | CON
+
+N:40:Dwarven
+T:32:0:6
+T:32:8:99
+X:B:33:13
+C:0:0:0:2
+W:0:1:8:500
+R:100
+F:INFRA | CON | RES_FIRE | ESP_TROLL | ESP_DRAGON
+
+
+### Cloaks ###
+
+N:41:of Protection
+X:A:31:10
+W:0:4:19:1500
+C:0:0:10:0
+T:35:0:99
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | RES_SHARDS
+
+N:42:of Eriador
+X:A:31:10
+W:0:8:18:500
+C:0:0:0:3
+T:35:0:99
+R:100
+F:STEALTH
+f:STEALTH
+R:10
+F:LUCK
+f:LUCK
+
+N:43:of Aman
+X:A:31:20
+W:0:1:28:4000
+C:0:0:20:3
+T:35:0:99
+R:100
+F:STEALTH |
+f:STEALTH |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:OLD_RESIST
+
+# Aura, Fire
+N:44:of Immolation
+X:A:31:16
+W:0:1:18:4000
+C:0:0:4:0
+T:35:0:99
+R:100
+F:IGNORE_ACID | IGNORE_FIRE | SH_FIRE | RES_FIRE
+f:SH_FIRE
+
+N:45:of Enveloping
+X:A:31:0
+W:0:1:3:0
+C:-10:-10:0:0
+T:35:0:99
+R:100
+F:SHOW_MODS
+
+N:46:of Vulnerability
+X:A:31:0
+W:0:1:3:0
+C:0:0:-50:0
+T:35:0:99
+R:100
+F:AGGRAVATE
+
+N:47:of Irritation
+X:A:31:0
+W:0:1:3:0
+C:-15:-15:0:0
+T:35:0:99
+R:100
+F:AGGRAVATE | SHOW_MODS
+
+# Aura, Electricity
+N:48:of Electricity
+X:A:31:16
+W:0:1:18:4000
+C:0:0:4:0
+T:35:0:99
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | SH_ELEC | RES_ELEC
+
+### Gloves ###
+
+N:49:of Free Action
+X:A:34:11
+W:0:4:10:1000
+T:31:0:99
+R:100
+F:FREE_ACT
+f:FREE_ACT
+
+N:50:of Slaying
+X:A:34:17
+W:0:3:10:1500
+C:6:6:0:0
+T:31:0:99
+R:100
+F:SHOW_MODS
+
+N:51:of Agility
+X:A:34:14
+W:0:2:10:1000
+C:0:0:0:5
+T:31:0:99
+R:100
+F:DEX | HIDE_TYPE
+f:DEX
+
+N:52:of Power
+T:31:0:99
+X:A:34:22
+W:0:1:10:2500
+C:5:5:0:5
+R:100
+F:STR | SHOW_MODS | HIDE_TYPE
+f:STR
+F:R_HIGH
+
+# 53 Gauntlets only
+N:53:of Peace
+X:A:34:0
+W:0:1:3:0
+C:-10:-10:0:0
+T:31:2:2
+R:100
+F:HEAVY_CURSE | CURSED
+
+# 54 Gloves only
+N:54:of Charming
+X:A:34:5
+T:31:1:1
+W:0:1:11:400
+C:0:0:0:6
+R:100
+F:CHR
+R:33
+F:STEALTH
+f:STEALTH
+
+N:55:of Weakness
+T:31:0:99
+X:A:34:0
+W:0:1:3:0
+C:0:0:0:-10
+R:100
+F:STR
+
+N:56:of Clumsiness
+X:A:34:0
+W:0:1:3:0
+C:0:0:0:-10
+R:100
+F:DEX
+T:31:0:99
+
+
+### Boots ###
+
+N:57:of Levitation
+X:A:35:7
+W:0:8:27:250
+T:30:0:99
+R:100
+F:FEATHER
+f:FEATHER
+R:40
+F:R_HIGH
+
+N:58:of Eriador
+X:A:35:16
+W:0:8:27:500
+C:0:0:0:3
+T:30:0:99
+R:100
+F:STEALTH
+f:STEALTH
+R:10
+F:LUCK
+f:LUCK
+
+N:59:of Free Action
+X:A:35:15
+W:0:5:27:1000
+T:30:0:99
+R:100
+F:FREE_ACT
+f:FREE_ACT
+
+N:60:of Rohan
+X:A:35:25
+W:0:1:27:200000
+C:0:0:0:10
+T:30:0:99
+R:100
+F:SPEED | HIDE_TYPE
+f:SPEED
+R:10
+F:PVAL_M3
+
+# 61 Metal boots only
+
+N:61:of Dwarvish Endurance
+X:A:35:15
+W:0:1:20:5000
+C:0:0:0:6
+T:30:6:6
+R:100
+F:CON | INFRA | RES_DARK
+R:33
+F:STR
+
+N:62:of Noise
+X:A:35:0
+W:0:1:3:0
+T:30:0:99
+R:100
+F:AGGRAVATE
+f:AGGRAVATE
+
+N:63:of Slowness
+X:A:35:0
+W:0:1:3:0
+C:0:0:0:-5
+T:30:0:99
+R:100
+F:SPEED
+f:SPEED
+
+N:64:of Annoyance
+X:A:35:0
+W:0:1:3:0
+C:0:0:0:-10
+T:30:0:99
+R:100
+F:SPEED | AGGRAVATE
+
+
+### Weapons ###
+
+N:65:of Aman
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:30
+W:0:2:44:20000
+C:6:6:4:3
+R:100
+F:WIS |
+F:SLAY_EVIL | SLAY_UNDEAD | SLAY_DEMON |
+F:SEE_INVIS | BLESSED | RES_FEAR | ESP_EVIL
+F:SUSTAIN | LIMIT_BLOWS
+R:10
+F:BLOWS
+R:1
+F:PVAL_M1
+
+N:66:(Defender)
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:25
+W:0:2:44:15000
+C:4:4:8:4
+R:100
+F:STEALTH |
+f:STEALTH |
+F:FREE_ACT | SEE_INVIS | FEATHER | REGEN |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:SUSTAIN | R_HIGH
+R:33
+F:RES_POIS
+
+N:67:Blessed
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:B:24:20
+W:0:1:44:5000
+C:0:0:0:3
+R:100
+F:WIS | ESP_GOOD
+F:BLESSED | ABILITY
+f:BLESSED
+
+N:68:of Greater Life
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:20
+W:0:1:50:30000
+C:5:5:0:3
+r:N:MUST2H
+R:100
+F:LIFE | HOLD_LIFE
+f:LIFE
+
+N:69:of Westernesse
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:20
+W:0:2:44:20000
+C:5:5:0:2
+R:100
+F:STR | DEX | CON |
+F:SLAY_ORC | SLAY_TROLL | SLAY_GIANT |
+F:FREE_ACT | SEE_INVIS | ESP_ORC | ESP_TROLL | ESP_GIANT
+R:33
+F:RES_FEAR
+R:50
+F:RES_MORGUL
+
+N:70:of Extra Attacks
+T:125:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:20
+W:0:1:44:10000
+C:0:0:0:3
+R:100
+F:BLOWS
+f:BLOWS
+
+N:71:of Slaying
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:15
+W:0:2:44:2500
+C:0:0:0:0
+R:100
+F:SLAY_WEAP | WOUNDING
+
+N:72:of Spinning
+T:125:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:18
+W:0:1:44:9000
+C:8:8:0:2
+R:100
+F:DEX | STR | VORPAL | ACTIVATE
+a:HARDCORE=SPIN
+
+# The "Elemental" brands (4) (6)
+
+N:73:Acidic
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:B:24:15
+W:0:4:44:5000
+R:100
+F:BRAND_ACID | RES_ACID | IGNORE_ACID
+f:BRAND_ACID
+
+N:74:Shocking
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:B:24:20
+W:0:4:44:4500
+R:100
+F:BRAND_ELEC | RES_ELEC | IGNORE_ELEC
+f:BRAND_ELEC
+
+N:75:Fiery
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:B:24:20
+W:0:4:44:3500
+R:100
+F:BRAND_FIRE | RES_FIRE | IGNORE_FIRE | LITE1
+f:BRAND_FIRE |
+
+N:76:Frozen
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:B:24:15
+W:0:4:44:3000
+R:100
+F:BRAND_COLD | RES_COLD | IGNORE_COLD
+f:BRAND_COLD |
+
+N:77:Venomous
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:B:24:20
+W:0:4:44:4000
+R:100
+F:BRAND_POIS | RES_POIS
+f:BRAND_POIS |
+
+N:78:Chaotic
+T:125:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:29
+T:23:31:99
+T:24:0:99
+T:115:55:55
+X:B:24:28
+W:0:1:44:10000
+R:100
+F:CHAOTIC | RES_CHAOS | IGNORE_ELEC | IGNORE_ACID | IGNORE_FIRE
+f:CHAOTIC
+F:R_ANY
+
+N:79:Sharp
+T:125:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:B:24:20
+W:0:2:44:5000
+R:100
+F:VORPAL
+f:VORPAL
+
+N:80:of Earthquakes
+T:125:0:99
+T:21:0:99
+T:115:55:55
+X:A:24:20
+W:0:1:44:4000
+C:10:10:0:6
+R:100
+F:IMPACT | STR | TUNNEL | HIDE_TYPE
+f:IMPACT
+
+# The "Slay" brands (8)
+
+N:81:of Slay Animal
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:18
+W:0:6:44:3500
+R:100
+F:SLAY_ANIMAL
+f:SLAY_ANIMAL
+
+N:82:of Slay Evil
+T:15:0:99
+T:125:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:18
+W:0:6:44:3500
+R:100
+F:SLAY_EVIL
+f:SLAY_EVIL
+
+N:83:of Slay Undead
+T:15:0:99
+T:21:0:19
+T:21:21:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:18
+W:0:6:44:3500
+R:100
+F:SLAY_UNDEAD
+f:SLAY_UNDEAD
+
+N:84:of Slay Demon
+T:15:0:99
+T:125:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:14
+W:0:6:44:2500
+R:100
+F:SLAY_DEMON
+f:SLAY_DEMON
+
+N:85:of Slay Orc
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:10
+W:0:6:44:2500
+R:100
+F:SLAY_ORC
+f:SLAY_ORC
+
+N:86:of Slay Troll
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:10
+W:0:6:44:2500
+R:100
+F:SLAY_TROLL
+f:SLAY_TROLL
+
+N:87:of Slay Giant
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:14
+W:0:6:44:2500
+R:100
+F:SLAY_GIANT
+f:SLAY_GIANT
+
+N:88:of Slay Dragon
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:18
+W:0:6:44:3500
+R:100
+F:SLAY_DRAGON
+f:SLAY_DRAGON
+
+# The "Kill" brands (8)
+
+N:89:of *Slay Animal*
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:20
+W:0:2:44:6000
+C:0:0:0:2
+R:100
+F:INT | SLAY_ANIMAL | SLOW_DIGEST | STEALTH | ESP_ANIMAL
+f:SLAY_ANIMAL | STEALTH
+
+N:90:of *Slay Evil*
+T:125:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:20
+W:0:2:44:6000
+C:0:0:0:2
+R:100
+F:WIS | SLAY_EVIL | BLESSED | ESP_EVIL | RES_FEAR | ABILITY
+f:SLAY_EVIL |
+
+N:91:of *Slay Undead*
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:24
+W:0:2:44:8000
+C:0:0:0:2
+R:100
+F:WIS | KILL_UNDEAD | SEE_INVIS | ESP_UNDEAD | RES_NETHER
+f:KILL_UNDEAD |
+
+N:92:of *Slay Demon*
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:16
+W:0:2:44:8000
+C:0:0:0:2
+R:100
+F:INT | KILL_DEMON | ESP_DEMON | RES_FIRE | RES_CHAOS
+f:KILL_DEMON |
+
+N:93:of *Slay Orc*
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:14
+W:0:2:44:4000
+C:0:0:0:2
+R:100
+F:DEX | SLAY_ORC | ESP_ORC | SUST_DEX |
+f:SLAY_ORC |
+
+N:94:of *Slay Troll*
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:14
+W:0:2:44:4000
+C:0:0:0:2
+R:100
+F:STR | SLAY_TROLL | ESP_TROLL | REGEN | SUST_STR
+f:SLAY_TROLL |
+
+N:95:of *Slay Giant*
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:16
+W:0:2:44:4000
+C:0:0:0:2
+R:100
+F:STR | SLAY_GIANT | ESP_GIANT | RES_SHARDS | SUST_STR
+f:SLAY_GIANT |
+
+N:96:of *Slay Dragon*
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:24
+W:0:2:44:8000
+C:0:0:0:2
+R:100
+F:CON | KILL_DRAGON | ESP_DRAGON | RES_FEAR |
+f:KILL_DRAGON
+F:R_LOW | R_ELEM
+R:20
+F:RES_POIS
+
+N:97:Vampiric
+T:125:0:99
+T:23:0:99
+T:115:55:55
+X:B:24:25
+W:0:2:44:10000
+C:0:0:0:-2
+R:100
+F:LIFE | VAMPIRIC | HOLD_LIFE
+f:LIFE | VAMPIRIC
+
+N:98:(*Defender*)
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:35
+W:0:1:100:50000
+C:-15:-15:20:4
+R:100
+F:STEALTH | RES_POIS | DEX | CON | WIS | HOLD_LIFE |
+f:STEALTH
+F:FREE_ACT | SEE_INVIS | FEATHER | REGEN |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:R_ANY | R_LOW | SUSTAIN
+R:30
+F:R_ANY | R_LOW | SUSTAIN
+R:20
+F:R_ANY | R_LOW | SUSTAIN | R_HIGH
+R:10
+F:R_IMMUNITY | R_ANY
+
+# 'of the Thunderlords' renamed to 'of Tulkas' and picked up some new flags:) --furiosity
+N:99:of Tulkas
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:22
+W:10:6:90:45000
+C:4:4:0:2
+a:HARDCORE=TELEPORT
+R:100
+F:SLAY_EVIL | KILL_DRAGON | TELEPORT | FREE_ACT | SEARCH | BRAND_ELEC
+F:REGEN | SLOW_DIGEST | RES_MORGUL | ACTIVATE | ESP_DRAGON
+R:50
+F:RES_NEXUS | HOLD_LIFE
+R:30
+F:R_HIGH | KILL_UNDEAD
+R:12
+F:ABILITY | KILL_DEMON
+R:2
+F:R_P_ABILITY | PVAL_M3 | LIMIT_BLOWS
+
+N:100:of Gondolin
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:26
+W:0:1:44:25000
+C:7:7:0:3
+R:100
+F:STR | CON | ESP_EVIL | RES_FEAR |
+F:SLAY_EVIL | SLAY_TROLL | SLAY_DRAGON | SLAY_DEMON |
+F:FREE_ACT | SEE_INVIS | LITE1 | RES_DARK | ABILITY |
+F:IGNORE_ACID | IGNORE_FIRE
+R:33
+F:R_HIGH
+R:33
+F:HOLD_LIFE
+R:22
+F:DEX
+
+# Diggers only
+
+N:101:of Digging
+T:20:0:99
+X:A:24:4
+W:0:1:2:500
+C:0:0:0:5
+R:100
+F:TUNNEL |
+f:TUNNEL |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+# More weapons
+
+N:102:Spectral
+T:125:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:B:24:30
+W:0:1:5:5000
+R:100
+F:SLAY_UNDEAD | SEE_INVIS | HOLD_LIFE | DRAIN_HP
+F:ACTIVATE
+a:HARDCORE=SPECTRAL
+
+N:103:of Morgul
+T:125:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:0
+W:0:1:1:0
+C:-20:-20:-10:-10
+R:100
+F:LUCK
+F:SEE_INVIS | AGGRAVATE | HEAVY_CURSE | CURSED | BLACK_BREATH | DRAIN_EXP |
+F:AUTO_CURSE | WOUNDING
+# No CURSE_NO_DROP here, players seems to unlike surprises
+
+N:104:of Angmar
+T:125:0:99
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:0
+W:0:1:2:0
+C:-100:-100:0:0
+R:100
+F:NEVER_BLOW | HEAVY_CURSE | CURSED | AUTO_CURSE
+
+
+### Missile Launchers ###
+
+N:105:of Accuracy
+T:19:0:99
+T:15:0:99
+X:A:25:10
+W:0:8:21:1000
+C:15:5:0:0
+
+N:106:of Power
+T:19:0:99
+T:15:0:99
+X:A:25:10
+W:0:8:21:1000
+C:5:15:0:0
+
+N:107:of Extra Might
+T:19:0:99
+X:A:25:20
+W:0:4:21:10000
+C:5:10:0:1
+R:100
+F:XTRA_MIGHT | PVAL_M3 | R_ANY
+f:XTRA_MIGHT |
+
+N:108:of Extra Shots
+T:19:0:99
+X:A:25:20
+C:10:5:0:1
+W:0:4:21:10000
+R:100
+F:XTRA_SHOTS | PVAL_M2
+f:XTRA_SHOTS |
+
+# Bows only
+N:109:of Lothlorien
+T:19:12:13
+X:A:25:20
+W:50:2:21:30000
+C:10:10:0:2
+R:100
+F:DEX | XTRA_MIGHT | FREE_ACT | IGNORE_ACID | IGNORE_FIRE | HIDE_TYPE |
+F:BLESSED | ABILITY
+
+# Crossbows only
+N:110:of the Haradrim
+T:19:23:24
+X:A:25:30
+W:50:2:21:20000
+C:5:15:0:1
+R:100
+F:XTRA_MIGHT | XTRA_SHOTS | IGNORE_ACID | IGNORE_FIRE | HIDE_TYPE
+
+# Slings only
+N:111:of Buckland
+X:A:25:25
+W:40:2:21:20000
+C:8:8:0:2
+T:19:1:1
+R:100
+F:DEX | XTRA_SHOTS | XTRA_MIGHT | IGNORE_ACID | IGNORE_FIRE | HIDE_TYPE
+
+
+### Ammo ###
+
+N:112:of Slay Animal
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+W:0:2:12:25
+R:100
+F:SLAY_ANIMAL
+f:SLAY_ANIMAL
+
+N:113:of Slay Evil
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+W:0:2:12:25
+R:100
+F:SLAY_EVIL
+f:SLAY_EVIL
+
+N:114:of Slay Undead
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+W:0:1:12:35
+R:100
+F:SLAY_UNDEAD
+f:SLAY_UNDEAD
+
+N:115:of Venom
+T:16:0:99
+T:17:0:2
+T:18:0:2
+X:A:23:10
+R:100
+F:BRAND_POIS
+f:BRAND_POIS
+W:0:2:12:25
+
+N:116:of Acid
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:BRAND_ACID | IGNORE_ACID
+f:BRAND_ACID |
+W:0:1:12:30
+
+# 117 All Elements at once - melee weapon
+N:117:Elemental
+X:B:24:30
+W:10:1:50:26000
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+R:100
+F:BRAND_ACID | RES_ACID | IGNORE_ACID
+F:BRAND_ELEC | RES_ELEC | IGNORE_ELEC
+F:BRAND_FIRE | RES_FIRE | IGNORE_FIRE
+F:BRAND_COLD | RES_COLD | IGNORE_COLD
+F:BRAND_POIS | RES_POIS | DRAIN_MANA
+f:BRAND_ACID |
+f:BRAND_ELEC |
+f:BRAND_FIRE |
+f:BRAND_COLD |
+f:BRAND_POIS |
+
+N:118:of Slay Demon
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+W:0:1:12:35
+R:100
+F:SLAY_DEMON
+f:SLAY_DEMON
+
+N:119:of Slay Dragon
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:SLAY_DRAGON
+f:SLAY_DRAGON
+W:0:1:12:35
+
+N:120:of Slaying
+X:A:23:15
+W:0:1:12:20
+C:12:12:0:0
+R:100
+F:DAM_DIE
+
+N:121:of Lightning
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:BRAND_ELEC | IGNORE_ELEC
+f:BRAND_ELEC |
+W:0:1:12:30
+
+N:122:of Flame
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:BRAND_FIRE | IGNORE_FIRE
+f:BRAND_FIRE |
+W:0:2:12:25
+
+N:123:of Frost
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:10
+R:100
+F:BRAND_COLD | IGNORE_COLD
+f:BRAND_COLD |
+W:0:2:12:25
+
+N:124:of Wounding
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:5
+W:0:3:12:20
+C:6:6:0:0
+
+N:125:of Backbiting
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:23:0
+W:0:1:2:0
+C:-50:-50:0:0
+
+
+### Special Broken Items ###
+
+# Destroyed Weapon
+N:126:Shattered
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:B:24:0
+W:0:1:2:0
+C:-5:-5:0:0
+
+# Destroyed Body Armor
+
+N:127:Blasted
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:B:30:0
+W:0:1:2:0
+C:0:0:-10:0
+
+
+# Instruments
+
+N:128:of the Eldar
+T:14:0:59
+T:14:61:99
+X:A:25:20
+W:0:2:3:1000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+F:RES_ACID | CHR | SEE_INVIS
+F:R_ANY | PVAL_M2
+R:25
+F:PVAL_M1
+
+N:129:of Power
+T:14:0:59
+T:14:61:99
+X:A:25:20
+W:0:1:3:2000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | SUST_CHR |
+F:RES_FIRE | RES_COLD | RES_ELEC | RES_ACID | CHR | SEE_INVIS
+F:R_ANY | PVAL_M3
+R:50
+F:PVAL_M1
+R:35
+F:PVAL_M1
+
+# Horn, now four different ego items (for different GF_ values)
+# see items 181, 182 & 183.
+N:130:Dragon
+T:14:60:60
+X:B:25:20
+W:0:1:2:2000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | ACTIVATE
+F:R_ANY | PVAL_M2
+R:50
+F:PVAL_M1
+R:25
+F:PVAL_M1
+a:HARDCORE=BA_ACID_H
+
+# Rods ego
+N:131:Capacity of
+T:67:0:99
+X:A:51:10
+W:0:2:10:1000
+C:0:0:0:0
+R:100
+F:CAPACITY
+f:CAPACITY
+
+N:132:Cheapness of
+T:67:0:99
+X:A:51:10
+W:0:2:10:700
+C:0:0:0:0
+R:100
+F:CHEAPNESS
+f:CHEAPNESS
+
+N:133:Quickness of
+T:67:0:99
+X:A:51:15
+W:0:3:10:1100
+C:0:0:0:0
+R:100
+F:FAST_CAST
+f:FAST_CAST
+
+N:134:Charging of
+T:67:0:99
+X:A:51:15
+W:0:2:10:1500
+C:0:0:0:0
+R:100
+F:CHARGING
+f:CHARGING
+
+N:135:the Istari of
+T:67:0:99
+X:A:51:10
+W:0:1:10:10000
+C:0:0:0:0
+R:100
+F:CAPACITY | CHARGING | CHEAPNESS | FAST_CAST |
+
+### Lights ###
+
+N:136:of Boldness
+X:A:0:5
+T:39:0:99
+W:0:1:5:1000
+Z:remove fear
+
+N:137:of Fearlessness
+X:A:0:5
+T:39:0:99
+W:0:1:10:1500
+R:100
+F:RES_FEAR
+
+N:138:of Illumination
+X:A:0:5
+T:39:0:99
+W:0:3:10:1000
+Z:illuminate
+R:10
+F:LITE1
+R:5
+F:LITE2
+R:2
+F:LITE3
+
+N:139:of Brightness
+X:A:0:5
+T:39:0:99
+W:0:3:10:1000
+R:100
+F:LITE1
+f:LITE1
+R:60
+F:LITE2
+R:30
+F:LITE3
+R:30
+F:RES_DARK
+
+N:140:of *Brightness*
+X:A:0:9
+T:39:0:99
+W:0:1:40:5000
+R:100
+F:LITE1
+F:LITE2
+F:LITE3
+f:LITE1
+f:LITE2
+f:LITE3
+F:RES_DARK
+
+N:141:of the Shadows
+X:A:0:6
+T:39:0:99
+W:0:1:20:3000
+C:0:0:0:2
+R:100
+F:INVIS
+R:70
+F:RES_DARK
+R:50
+F:RES_LITE
+
+N:142:of Infravision
+X:A:0:3
+T:39:0:99
+W:0:1:10:700
+C:0:0:0:3
+R:100
+F:INFRA
+f:INFRA
+
+N:143:of the Eternal Eye
+X:A:0:7
+T:39:0:99
+W:0:3:40:4000
+C:0:0:0:0
+R:100
+F:RES_BLIND | SEE_INVIS
+
+N:144:of the Ethereal Eye
+X:A:0:7
+T:39:0:99
+W:0:3:40:4000
+C:0:0:0:0
+Z:magic map
+
+N:145:of Fading
+X:A:0:0
+T:39:2:99
+W:0:1:1:0
+C:0:0:0:0
+R:100
+F:FUEL_LITE
+
+# Armor (dwarven): must be heavy metal, and not rusty chain mail
+
+N:146:Dwarven
+T:37:2:99
+X:B:30:18
+W:0:2:20:5000
+C:0:0:15:2
+R:100
+F:STR | CON | INFRA | FREE_ACT | HIDE_TYPE |
+F:RES_FEAR | RES_DARK | SUST_STR | SUST_CON |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+# Magical: affects soft armour, gloves, cloaks
+
+N:147:Magical
+X:B:0:2
+T:31:0:99
+T:35:0:99
+T:36:0:99
+T:40:0:99
+T:45:0:99
+W:5:1:10:2000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+f:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+R:50
+F:SPELL_CONTAIN | WIELD_CAST
+f:SPELL_CONTAIN | WIELD_CAST
+
+# Ring and Amulet egos
+
+N:148:Cursed
+X:B:0:0
+T:40:0:99
+T:45:0:99
+W:0:1:10:0
+C:0:0:0:0
+R:100
+F:AUTO_CURSE
+f:AUTO_CURSE
+
+# Scrolls & school spellbooks & staves
+N:149:Fireproof
+X:B:0:1
+T:70:0:99
+T:111:0:99
+T:55:0:99
+W:0:1:10:1000
+C:0:0:0:0
+R:100
+F:IGNORE_FIRE
+f:IGNORE_FIRE
+
+# Wands & Staffs(NOT wishing nor nothing)
+N:150:of Plenty
+X:A:0:1
+T:55:0:29
+T:55:32:99
+T:65:0:29
+T:65:31:99
+W:0:1:20:1000
+C:0:0:0:3
+R:100
+F:PVAL_M5 | PVAL_M3
+R:50
+F:PVAL_M5 | PVAL_M3
+R:10
+F:PVAL_M5 | PVAL_M3
+R:1
+F:PVAL_M5 | PVAL_M3
+
+
+### Trapping Kits ###
+
+N:151:of Extra Might
+X:A:0:5
+T:46:1:3
+W:0:1:10:1000
+C:20:20:0:2
+R:100
+F:XTRA_MIGHT
+f:XTRA_MIGHT
+
+N:152:of Extra Shots
+X:A:0:10
+T:46:0:99
+W:0:1:10:2000
+C:20:20:0:3
+R:100
+F:XTRA_SHOTS
+f:XTRA_SHOTS
+
+N:153:Automatic
+X:B:0:15
+T:46:0:99
+W:0:1:10:3000
+C:10:10:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_COLD | IGNORE_FIRE |
+F:AUTOMATIC_5
+f:AUTOMATIC_5
+
+N:154:Fully Automatic
+X:B:0:15
+T:46:0:99
+W:0:1:15:5000
+C:10:10:0:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_COLD | IGNORE_FIRE |
+F:AUTOMATIC_99
+f:AUTOMATIC_99
+
+N:155:Well-hidden
+X:B:0:5
+T:46:0:99
+W:0:1:8:1000
+C:15:15:5:12
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_COLD | IGNORE_FIRE |
+F:STEALTH | HIDE_TYPE
+f:STEALTH
+
+N:156:Complicated
+X:B:0:10
+T:46:0:99
+W:0:1:12:2000
+C:15:15:30:0
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_COLD | IGNORE_FIRE
+
+N:157:Obvious
+X:B:0:0
+T:46:0:99
+W:0:1:1:0
+C:-20:-20:-20:-20
+R:100
+F:STEALTH | CURSED | HIDE_TYPE
+f:STEALTH
+
+N:158:for Dragons
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_DRAGON | HIDE_TYPE | XTRA_SHOTS |
+F:IGNORE_ACID | IGNORE_FIRE
+
+N:159:for Demons
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_DEMON | HIDE_TYPE | XTRA_SHOTS
+F:IGNORE_ACID | IGNORE_FIRE
+
+N:160:for Animals
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_ANIMAL | HIDE_TYPE | XTRA_SHOTS
+
+N:161:for Undead
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_UNDEAD | HIDE_TYPE | XTRA_SHOTS | KILL_GHOST
+
+N:162:for Evil
+X:A:0:5
+T:46:0:99
+W:0:3:10:500
+C:20:20:10:4
+R:100
+F:STEALTH | ONLY_EVIL | HIDE_TYPE | XTRA_SHOTS | KILL_GHOST
+
+# Lite ego
+N:163:of the Magi
+X:A:0:0
+T:39:1:99
+W:0:1:150:2000
+C:0:0:0:3
+Z:magic map
+R:100
+F:INT | WIS | CHR
+R:60
+F:INVIS | RES_BLIND
+R:30
+F:R_HIGH
+R:30
+F:PVAL_M2
+R:50:
+F:SPELL_CONTAIN | WIELD_CAST
+
+### New ego-items added by JLE
+
+# Armor of Vulnerability (the only cursed armor) [not in Theme, it isn't!]
+N:164:of Vulnerability
+X:A:30:0
+W:0:2:20:0
+C:0:0:-50:0
+T:36:0:99
+T:37:0:99
+R:100
+F:AGGRAVATE | CURSED
+
+# Shield of Vulnerability (the only cursed shield) [not in Theme, it isn't!]
+N:165:of Vulnerability
+X:A:32:0
+W:0:2:22:0
+C:0:0:-50:0
+T:115:56:56
+T:34:0:99
+R:100
+F:AGGRAVATE | CURSED
+
+# Shield of Preservation -
+N:166:of Preservation
+X:A:32:25
+W:40:2:44:20000
+C:-10:-10:20:0
+T:115:56:56
+T:34:0:99
+R:100
+F:RES_DISEN | SUST_STR | SUST_CON | SUST_DEX | HOLD_LIFE | R_HIGH |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+R:33
+F:R_LOW
+R:33
+F:R_LOW
+
+# Helm/Crown of Serenity
+N:167:of Serenity
+X:A:33:20
+W:35:1:15:4000
+T:32:0:6
+T:32:8:99
+T:33:0:99
+R:100
+F:RES_SOUND | RES_CONF | RES_FEAR
+
+# Crown of Night and Day
+N:168:of Night and Day
+X:A:33:18
+W:35:1:15:4000
+T:33:0:99
+R:100
+F:RES_LITE | RES_DARK | LITE1 | SEE_INVIS | RES_BLIND | IGNORE_ACID
+
+# Cloak of the Magi
+N:169:of the Magi
+X:A:31:15
+W:30:1:18:2000
+C:-5:-5:5:3
+T:35:0:99
+R:100
+F:INT | SPEED | SUST_INT | FREE_ACT | STEALTH | HIDE_TYPE | IGNORE_ACID
+R:30
+F:SPELL_CONTAIN | WIELD_CAST
+
+# Cloak of Invisibility
+N:170:of Invisibility
+X:A:31:20
+W:40:1:18:3000
+C:0:0:10:5
+T:35:0:99
+R:100
+F:STEALTH | HIDE_TYPE | INVIS
+f:INVIS
+
+# Cloak of the Bat
+N:171:of the Bat
+X:A:31:15
+W:50:1:35:3000
+C:-10:-10:10:3
+T:35:0:99
+R:100
+F:SPEED | FLY | RES_DARK | SEE_INVIS | INFRA | HIDE_TYPE | STEALTH
+
+# Leather Gloves of Thievery
+N:172:of Thievery
+X:A:34:22
+W:40:1:15:5000
+C:8:3:0:5
+T:31:1:1
+R:100
+F:DEX | SEARCH | SHOW_MODS | FEATHER | FREE_ACT | HIDE_TYPE | IGNORE_ACID
+R:10
+F:SPEED
+
+# Gauntlets and Cesti of Combat
+N:173:of Combat
+X:A:34:22
+W:50:1:15:7000
+C:6:8:-20:2
+T:31:2:99
+R:100
+F:STR | CON | SHOW_MODS | AGGRAVATE | HIDE_TYPE | IGNORE_ACID | RES_FEAR |
+F:DRAIN_HP
+R:25
+F:BLOWS
+
+# Boots of Stability
+N:174:of Stability
+X:A:35:20
+W:0:3:27:5000
+T:30:0:99
+R:100
+F:RES_NEXUS | FEATHER
+
+# Boots of Elvenkind (leather boots only)
+N:175:of Elvenkind
+X:A:35:30
+W:60:1:36:200000
+C:0:0:0:4
+T:30:2:3
+R:100
+F:STEALTH | HIDE_TYPE | FEATHER | IGNORE_ACID | IGNORE_FIRE | ABILITY
+R:50
+F:SPEED
+
+# Weapon of Fury (must be big heavy type of weapon, no daggers or whips)
+N:176:of Fury
+X:A:24:30
+W:40:1:66:20000
+T:21:12:99
+T:22:10:99
+T:23:16:99
+T:24:8:99
+T:125:0:99
+C:10:10:-20:2
+R:100
+F:STR | BLOWS | AGGRAVATE | RES_FEAR | HIDE_TYPE |
+F:IGNORE_ACID | IGNORE_FIRE | DRAIN_MANA
+
+# Staffs of wishing
+N:177:of Plenty
+X:A:0:1
+T:55:31:31
+W:0:1:20:1000
+C:0:0:0:2
+R:100
+F:PVAL_M2
+
+
+# Diggers only
+
+N:178:Magical
+T:20:0:99
+X:B:24:4
+W:0:1:10:500
+C:0:0:0:0
+Z:stone to mud
+R:100
+
+# Rod
+N:179:Simplicity of
+T:67:0:99
+X:A:51:8
+W:3:2:8:1000
+C:0:0:0:0
+R:100
+F:EASY_USE
+f:EASY_USE
+
+# Lite ego
+N:180:of Warmth
+X:A:0:0
+T:39:1:99
+W:0:1:10:500
+C:0:0:0:0
+R:100
+F:RES_COLD
+
+#Three more horn types, for different activation types...
+N:181:Dragon
+T:14:7:7
+X:B:25:20
+W:0:1:2:2000
+C:0:0:0:0
+a:HARDCORE=BA_COLD_3
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+
+N:182:Dragon
+T:14:7:7
+X:B:25:20
+W:0:1:2:2000
+C:0:0:0:0
+a:HARDCORE=BA_ELEC_3
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+
+N:183:Dragon
+T:14:7:7
+X:B:25:20
+W:0:1:2:2000
+C:0:0:0:0
+a:HARDCORE=BA_FIRE_H
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD |
+
+# Helm of water breathing
+N:184:of Water Breathing
+X:A:33:13
+C:0:0:0:2
+W:15:1:25:1000
+T:32:5:10
+R:100
+F:WATER_BREATH | IGNORE_ACID
+f:WATER_BREATH
+
+# A second of life for non MUST2H weapons, much lower value tho
+N:185:of Life
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+T:115:55:55
+X:A:24:20
+W:0:1:50:30000
+C:5:5:0:1
+r:F:MUST2H
+R:100
+F:LIFE | HOLD_LIFE
+f:LIFE
+
+# Cloak of Air
+N:186:of Air
+X:A:31:10
+W:30:1:35:1500
+C:0:0:0:0
+T:35:0:99
+R:100
+F:MAGIC_BREATH
+
+# Ego DSM
+N:187:Polished
+T:38:0:99
+X:B:30:5
+W:40:25:100:25000
+C:0:0:0:0
+R:100
+F:REFLECT
+
+# Ego Heavy Crossbow
+N:188:of Siegecraft
+T:19:24:24
+X:A:25:30
+W:60:5:30:30000
+C:10:15:20:2
+R:120
+F:XTRA_MIGHT | XTRA_SHOTS | REFLECT | IMMOVABLE
+
+### New ego-items from T-Plus by Ingeborg S. Norden ###
+
+# Rogue's Boots, no Metal-Shod or cursed ones allowed // Reworked to balance in Theme 1.1.5
+
+N:189:Rogue's
+X:B:35:15
+W:15:10:25:2500
+C:-5:-5:0:2
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE |
+T:30:2:3
+Z:panic hit
+R:100
+F:SEARCH
+f:SEARCH
+R:50
+F:STEALTH
+f:STEALTH
+R:25
+F:LUCK
+f:LUCK
+R:10
+F:R_HIGH |
+
+### Egos for rings, amulets and crowns (partly inspired by Multiband)
+
+# Glowing (no "Nothings", Amulets of Brilliance, or Rings of
+# Light and Darkness Resistance)
+
+N:190:Glowing
+X:B:0:5
+T:33:0:99
+T:40:0:5
+T:40:7:15
+T:45:0:38
+W:5:1:10:1250
+C:0:0:0:0
+R:100
+F:LITE1 |
+f:LITE1 |
+
+# Dazzling (as above, with more light plus resistance/granted ability)
+
+N:191:Dazzling
+X:B:0:7
+T:33:0:99
+T:40:0:5
+T:40:7:15
+T:45:0:38
+W:10:3:12:2500
+C:0:0:0:0
+Z:illuminate
+R:100
+F:LITE2 | RES_LITE |
+f:LITE2 |
+R:50
+F:LITE1 |
+f:LITE1 |
+R:25
+F:LITE3 |
+f:LITE3 |
+
+# Radiant (Dazzling with some extras;
+# no cursed jewelry)
+
+N:192:Radiant
+X:B:0:12
+T:33:0:99
+T:40:17:99
+T:45:0:38
+T:45:40:49
+T:45:51:99
+W:15:5:15:3500
+C:0:0:0:0
+Z:illuminate
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE |
+R:100
+F:LITE3 | RES_LITE |
+f:LITE3 |
+R:50
+F:LITE2 |
+f:LITE2 |
+R:25
+F:LITE1 |
+f:LITE1 |
+R:20
+F:RES_BLIND |
+R:2
+F:REFLECT |
+
+# Blazing (Glowing plus fiery sheath, resistance, undamaged by
+# fire; restrictions as per Glowing, but no Cold Resistance/Ice
+# rings either)
+
+N:193:Blazing
+X:B:0:15
+T:33:0:99
+T:40:17:99
+T:45:20:38
+T:45:40:49
+T:45:51:99
+W:15:5:15:3000
+C:0:0:0:0
+R:100
+F:LITE1 | RES_FIRE | SH_FIRE |
+f:LITE1 | SH_FIRE | IGNORE_FIRE
+R:25
+F:LITE2 |
+f:LITE2 |
+R:10
+F:LITE3 |
+f:LITE3 |
+R:2
+F:IM_FIRE |
+
+# Lucky (amulets only--resists cursing, undamaged by elements, luck
+# bonus added; no inherently cursed types or Nothing amulets)
+
+N:194:Lucky
+X:B:0:12
+T:40:2:15
+T:40:17:99
+W:15:5:15:2750
+C:0:0:0:5
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE |
+R:100
+F:BLESSED | LUCK |
+
+# Unlucky (amulets only; no Prot/Evil, Doom, or Nothing amulets)
+N:195:Unlucky
+X:B:0:0
+T:40:3:15
+T:40:17:99
+W:0:3:10:0
+C:-5:-5:-5:-5
+R:100
+F:CURSED | AUTO_CURSE | LUCK | AGGRAVATE
+R:20
+F:HEAVY_CURSE |
+
+# Armour of the Maiar (of the Chosen in T-Plus)
+
+N:196:of the Maiar
+T:36:2:99
+T:37:2:99
+X:A:30:30
+W:10:3:45:15000
+C:0:0:15:0
+R:100
+F:BLESSED | ESP_EVIL | ESP_GIANT | ESP_TROLL |
+F:FREE_ACT | RES_FEAR |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:OLD_RESIST |
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+f:FREE_ACT | IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+Z:berserk
+R:25
+F:R_HIGH | SUSTAIN |
+
+### Weapons of the Maiar (of the Chosen in T-Plus)
+N:197:of the Maiar
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:35
+W:10:5:45:30000
+C:6:6:4:3
+R:100
+F:SLAY_GIANT | SLAY_TROLL |
+F:SEE_INVIS | FREE_ACT | BLESSED | RES_FEAR |
+F:ESP_GIANT | ESP_TROLL |
+F:LIMIT_BLOWS |
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+f:FREE_ACT | IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+R:33
+F:ESP_EVIL | SLAY_EVIL | R_ANY |
+R:10
+F:BLOWS
+R:1
+F:PVAL_M1
+r:F:CHAOTIC | DRAIN_HP | VAMPIRIC | CURSED | HEAVY_CURSE |
+
+# Robe of Ithryn (of the Archmagi in T-Plus)
+N:198:of the Ithryn
+T:36:2:2
+X:A:30:30
+W:15:3:45:15000
+C:-5:-5:15:2
+R:100
+F:FREE_ACT | RES_BLIND | RES_CONF | R_HIGH | SUST_INT |
+F:SPELL_CONTAIN | WIELD_CAST |
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+f:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | SUST_INT |
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE |
+R:33
+F:RES_DISEN | SPELL |
+R:10
+F:MANA |
+
+# Robe of Sanctity
+
+N:199:of Sanctity
+T:36:2:2
+X:A:30:30
+W:15:3:45:15000
+C:0:0:15:2
+R:100
+F:FREE_ACT | RES_BLIND | RES_CONF | R_HIGH | SUST_WIS |
+F:BLESSED | ACTIVATE |
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+f:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | SUST_WIS |
+a:HARDCORE=PROT_EVIL
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE |
+R:33
+F:ESP_EVIL |
+R:10
+F:SPELL |
+
+N:200:Ethereal
+T:35:0:99
+T:36:2:2
+X:B:25:25
+W:15:2:20:27500
+C:0:0:20:0
+R:100
+F:FREE_ACT | SEE_INVIS | HOLD_LIFE |
+F:ACTIVATE |
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+f:FREE_ACT | IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE |
+a:HARDCORE=SPECTRAL
+R:33
+F:RES_NETHER |
+R:5
+F:MAGIC_BREATH |
+f:MAGIC_BREATH |
+
+### More new ego-items from Annals of Ea by Feanor:
+
+# Mage staff of the Sindar
+N:201:of the Sindar
+T:6:0:99
+X:A:24:80
+W:40:25:100:25000
+C:0:0:0:5
+R:100
+F:ESP_EVIL | SPELL | MANA
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+# Swords of the Noldor
+N:202:of the Noldor
+T:23:0:99
+X:A:24:35
+W:40:25:100:50000
+C:15:15:20:4
+R:100
+F:STEALTH | RES_POIS | DEX | CON | WIS | HOLD_LIFE |
+f:STEALTH
+F:FREE_ACT | SEE_INVIS | FEATHER | REGEN |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:R_ANY | R_LOW | SUSTAIN
+F:SLAY_EVIL | BLESSED | WOUNDING
+R:30
+F:R_ANY | R_LOW | SUSTAIN
+R:20
+F:R_ANY | R_LOW | SUSTAIN | R_HIGH
+R:10
+F:R_IMMUNITY | R_ANY
+
+# Spear of Vanyar
+N:203:of the Vanyar
+T:22:0:99
+R:100
+X:A:24:35
+W:40:25:100:50000
+C:15:15:20:4
+F:STEALTH | HOLD_LIFE | SEE_INVIS | WIS | INT |
+F:REGEN | RES_FEAR | RES_DARK | RES_LITE | RES_BLIND |
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_ELEC | IGNORE_COLD |
+F:SLAY_DEMON | SLAY_UNDEAD | BLESSED |
+F:R_ANY | R_LOW | SUSTAIN
+R:30
+F:R_ANY | R_LOW | SUSTAIN
+R:20
+F:R_ANY | R_LOW | SUSTAIN | R_HIGH
+R:10
+F:R_IMMUNITY | R_ANY
+
+# Axe of the Nandor
+N:204:of the Nandor
+T:24:0:99
+R:100
+X:A:24:35
+W:40:25:100:50000
+C:15:15:20:5
+F:STEALTH | SPEED | SEE_INVIS | RES_COLD | RES_ELEC |
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC |
+F:SLAY_ORC | SLAY_ANIMAL | RES_POIS |
+F:R_ANY | R_LOW | SUSTAIN
+R:30
+F:R_ANY | R_LOW | SUSTAIN
+R:20
+F:R_ANY | R_LOW | SUSTAIN | R_HIGH
+R:10
+F:R_IMMUNITY | R_ANY
+
+# Arrow of Teleri
+N:205:of the Teleri
+T:17:0:99
+X:A:23:10
+W:40:25:100:5000
+R:100
+F:R_ANY | WOUNDING | BLESSED
+
+# Hafted of Avari
+N:206:of the Avari
+T:21:0:99
+R:100
+X:A:24:35
+W:40:25:100:50000
+C:15:15:20:5
+F:STEALTH | INVIS | SEE_INVIS | INFRA | RES_DARK |
+F:RES_BLIND | SLAY_UNDEAD |
+F:R_ANY | R_LOW | SUSTAIN
+R:30
+F:R_ANY | R_LOW | SUSTAIN
+R:20
+F:R_ANY | R_LOW | SUSTAIN | R_HIGH
+R:10
+F:R_IMMUNITY | R_ANY
+
+### Ravenred's Weapons of Unmagic
+
+N:207:of Unmagic
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:24
+W:0:2:44:8000
+C:-10:-10:0:0
+R:100
+F:ANTIMAGIC_50
+f:ANTIMAGIC_50
+
+### Amulet and ring egos suggested by power
+
+#Blessed - anything but Doom
+N:208:Blessed
+T:40:0:99
+T:45:1:99
+X:B:0:10
+W:0:5:100:2000
+C:0:0:10:2
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE |
+R:100
+F:WIS | SEE_INVIS | HOLD_LIFE | BLESSED
+f:WIS | SEE_INVIS | HOLD_LIFE | BLESSED
+
+#Demonic - anything but Devotion and Protection from Evil
+N:209:Demonic
+T:40:0:1
+T:40:3:24
+T:40:26:99
+T:45:0:99
+X:B:0:10
+W:0:5:100:2000
+C:0:0:0:2
+r:F:BLESSED
+R:100
+F:ESP_DEMON | RES_FIRE
+f:ESP_DEMON | RES_FIRE
+
+# Jewellery of the Rohirrim - no speed rings
+N:210:Rohirric
+T:40:0:99
+T:45:0:30
+T:45:32:99
+X:B:0:10
+W:0:5:100:20000
+C:0:0:0:3
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE |
+R:100
+F:RES_FEAR | SPEED
+f:RES_FEAR | SPEED
+
+# Draconic - anything but Devotion and Protection from Evil
+N:211:Draconic
+T:40:0:1
+T:40:3:24
+T:40:26:99
+T:45:0:99
+X:B:0:10
+W:0:5:100:2000
+C:5:5:10:1
+r:F:BLESSED
+R:100
+F:ESP_DRAGON
+f:ESP_DRAGON
+
+#Elemental - the ones that already give resists are obviously not eligible
+N:212:Elemental
+T:40:16:28
+T:40:30:99
+T:45:10:16
+T:45:20:99
+X:B:0:30
+W:25:5:50:1000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC |
+F:RES_ACID | RES_FIRE | RES_COLD | RES_ELEC | R_ANY
+R:20
+F:IM_FIRE | R_HIGH
+R:15
+F:IM_COLD | R_HIGH
+R:10
+F:IM_ELEC | R_HIGH
+R:5
+F:IM_ACID | R_HIGH
+R:1
+F:IM_NETHER
+
+### New ego-items unique to Theme module ###
+
+#Musical instruments of Melkor
+
+N:213:of Melkor
+T:14:0:59
+T:14:61:99
+X:A:0:30
+W:0:5:30:0
+C:0:0:0:-10
+R:100
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC |
+F:CURSED | HEAVY_CURSE | AUTO_CURSE | AGGRAVATE
+R:50
+F:R_STAT | CURSED | HEAVY_CURSE | AUTO_CURSE
+
+#Horns of Ulmo (Ulumuri)
+
+N:214:of Ulmo
+T:14:60:60
+X:A:0:80
+W:0:5:80:5000
+C:0:0:0:0
+R:100
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC |
+F:PVAL_M5 | R_IMMUNITY
+
+# Reverse Armour of the Maiar (of the Chosen in T-Plus)
+N:215:of the Fallen
+T:36:2:99
+T:37:2:99
+X:A:30:30
+W:0:3:45:0
+C:0:0:-15:0
+R:25
+F:CURSED | AUTO_CURSE | ESP_GOOD |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+R:50
+F:CURSED | AUTO_CURSE | R_LOW | SUSTAIN | AGGRAVATE
+R:75
+F:CURSED | AUTO_CURSE | WRAITH | DRAIN_EXP |
+R:100
+F:CURSED | AUTO_CURSE | DRAIN_MANA | DRAIN_HP | BLACK_BREATH
+
+###Reverse Weapons of the Maiar (of the Chosen in T-Plus)
+N:216:of the Fallen
+T:15:0:99
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:24:35
+W:0:5:45:0
+C:+6:+6:-5:-3
+R:100
+F:NEVER_BLOW | IM_NETHER | PERMA_CURSE
+R:50
+F:CURSED | HEAVY_CURSE | AUTO_CURSE | NO_MAGIC | CLONE
+R:33
+F:CURSED | HEAVY_CURSE | AUTO_CURSE | DRAIN_EXP | DRAIN_MANA
+R:10
+F:CURSED | HEAVY_CURSE | AUTO_CURSE | CHAOTIC | DRAIN_HP
+R:1
+F:R_STAT | CURSED | AUTO_CURSE | ESP_GOOD |
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD |
+
+# Robe of Fools (reverse of Ithryn/Archmagi in T-Plus)
+N:217:of the Fools
+T:36:2:2
+X:A:30:30
+W:0:3:45:0
+C:-5:-5:-15:-2
+R:100
+F:CURSED | HEAVY_CURSE | AUTO_CURSE | LIFE
+R:33
+F:CURSED | HEAVY_CURSE | AUTO_CURSE | RES_DISEN | SPELL | NO_MAGIC |
+R:10
+F:CURSED | HEAVY_CURSE | AUTO_CURSE | MANA |
+
+# Robe of Vice (reverse of Sanctity in T-Plus)
+N:218:of Vice
+T:36:2:2
+X:A:30:30
+W:0:3:45:0
+C:0:0:-15:-2
+R:100
+F:CURSED | HEAVY_CURSE | AUTO_CURSE | LIFE | AGGRAVATE
+R:33
+F:ESP_GOOD | ANTIMAGIC_50
+
+# Soft and Hard Armour of Sensitivity, no paper armour
+N:219:of Sensitivity
+T:30:0:99
+T:31:0:99
+T:32:0:99
+T:33:0:99
+T:34:0:99
+X:A:30:30
+W:0:3:45:0
+C:0:0:-5:-2
+R:100
+F:CURSED | SENS_FIRE | R_STAT |
+
+# Elemental ammo
+N:220:Elemental
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:B:30:30
+W:0:1:50:1000
+C:5:5:0:0
+R:100
+F:BRAND_ACID | IGNORE_ACID
+F:BRAND_ELEC | IGNORE_ELEC
+F:BRAND_FIRE | IGNORE_FIRE
+F:BRAND_COLD | IGNORE_COLD
+F:BRAND_POIS |
+f:BRAND_ACID |
+f:BRAND_ELEC |
+f:BRAND_FIRE |
+f:BRAND_COLD |
+f:BRAND_POIS |
+
+# Cursed ammo
+
+N:221:of Angmar
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:A:30:30
+W:0:1:50:0
+C:-10:-10:0:0
+R:100
+F:CURSED | IMMOVABLE
+
+# Bows of Numenor
+
+N:222:of Numenor
+T:19:12:34
+X:A:50:50
+W:0:1:50:0
+C:10:10:0:3
+R:100
+F:DEX | XTRA_MIGHT | XTRA_SHOTS |
+F:RES_FEAR | RES_POIS | RES_DARK | FREE_ACT
+
+# Lights of Valinor (no refillable lights)
+
+N:223:of Valinor
+T:39:2:4
+X:A:60:60
+W:0:2:60:45000
+C:0:0:0:2
+R:100
+F:STR | INT | WIS | DEX | CON | CHR
+F:ESP_ALL
+f:STR | INT | WIS| DEX | CON | CHR | ESP_ALL
+
+# Lucky weapons - named after smith of legend
+N:224:of Telchar
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:70:70
+W:10:2:70:3000
+C:10:10:0:2
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE
+R:100
+F:LUCK
+f:LUCK
+
+# Unlucky weapons - of the Din-horde (Orcs)
+N:225:of the Glamhoth
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:50:50
+W:0:2:50:0
+C:5:5:0:-2
+R:100
+F:LUCK | CURSED | HEAVY_CURSE | AUTO_CURSE | AGGRAVATE
+f:LUCK | CURSED | HEAVY_CURSE | AUTO_CURSE | AGGRAVATE
+
+# Holy ammo - based on 'Of Holy Might' from Hengband
+N:226:Blessed
+T:16:0:99
+T:17:0:99
+T:18:0:99
+X:B:30:30
+W:0:5:60:600
+C:5:10:0:0
+R:100
+F:SLAY_EVIL | SLAY_DEMON | SLAY_UNDEAD | BRAND_FIRE | BLESSED
+F:IGNORE_FIRE | IGNORE_ACID
+
+# Holy Avenger weapons brought back, modified
+N:227:(Holy Avenger)
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:50:50
+W:0:2:60:20000
+C:5:5:0:3
+R:100
+F:WIS | SUSTAIN |
+F:SLAY_EVIL | SLAY_UNDEAD | SLAY_DEMON |
+F:SEE_INVIS | BLESSED
+
+# A Whip of the Balroeg, adapted from Oangband
+N:228:of the Balroeg
+T:21:2:2
+X:A:50:50
+W:0:3:50:12000
+C:-10:10:0:-3
+R:100
+F:STEALTH | BRAND_FIRE | RES_FIRE | LITE2 |
+F:IGNORE_FIRE | ESP_GOOD |
+R:5
+F:IM_FIRE
+
+# Bows of the Nazgul, adapted from Angband
+N:229:of the Nazgul
+T:19:0:99
+T:15:0:99
+R:80
+X:A:25:10
+W:0:3:50:0
+C:0:0:0:-1
+r:F:BLESSED
+F:DRAIN_EXP | SEE_INVIS | CHR
+
+# Magical missile launchers
+# Tiny mana boost for magic-using archers or warrior-types
+N:230:Magical
+T:19:0:99
+T:15:0:99
+X:B:25:10
+W:25:9:30:8000
+C:0:0:0:1
+R:100
+F:MANA
+f:MANA
+
+# Magical jewelry (no rings/amulets of spell, anti-magic, cursed items)
+N:231:Magical
+X:B:0:2
+T:40:0:12
+T:40:14:26
+T:40:28:99
+T:45:0:56
+T:45:59:99
+W:5:1:10:2000
+C:0:0:0:0
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE
+R:100
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+f:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+R:50
+F:SPELL_CONTAIN | WIELD_CAST
+f:SPELL_CONTAIN | WIELD_CAST
+
+# Magestaves of Sorcery, added in Theme 1.0.1
+N:232:of Sorcery
+X:A:24:60
+T:6:0:99
+W:30:1:8:100000
+C:-80:-80:0:3
+r:F:CURSED | HEAVY_CURSE | PERMA_CURSE
+R:100
+F:MANA | SPELL | LIFE
+R:50
+F:PVAL_M2
+
+# Sentient weapons, added in Theme 1.0.2
+N:233:of Doriath
+T:21:0:99
+T:22:0:99
+T:23:0:99
+T:24:0:99
+X:A:70:70
+W:0:2:70:50000
+C:1:1:0:0
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE
+R:100
+F:LEVELS
+f:LEVELS
+
+# Bows of Mirkwood, added in Theme 1.0.2
+N:234:of Mirkwood
+T:19:12:13
+X:A:25:20
+W:50:2:21:50000
+C:10:10:0:2
+R:100
+F:CON | XTRA_MIGHT | XTRA_SHOTS | RES_POIS | STEALTH
+F:IGNORE_ACID | IGNORE_FIRE | HIDE_TYPE | SEE_INVIS
+
+# Spear of Mirkwood, added in Theme 1.0.2
+N:235:of Mirkwood
+T:22:2:2
+X:A:24:35
+W:40:25:100:50000
+C:15:15:20:3
+r:F:CURSED | HEAVY_CURSE | AUTO_CURSE
+R:100
+F:STEALTH | HOLD_LIFE | SEE_INVIS | CON |
+F:RES_FEAR | RES_DARK | RES_LITE | RES_BLIND |
+F:IGNORE_ACID | IGNORE_FIRE |
+F:R_ANY | R_LOW | SUSTAIN
+R:30
+F:R_ANY | R_LOW | SUSTAIN
+R:20
+F:R_ANY | R_LOW | SUSTAIN | R_HIGH
+
+# Dwarven jewelry - no speed rings; added in Theme 1.1.4
+N:236:Dwarven
+T:40:0:99
+T:45:0:30
+T:45:32:99
+X:B:0:5
+W:5:1:10:1250
+C:0:0:10:1
+R:100
+F:INFRA
+Z:stone to mud
+R:50
+F:SUSTAIN
+R:25
+F:R_ANY | SUSTAIN
+R:5
+F:CON
+
+# Sharpened arrows and bolts; added in Theme 1.1.5
+# Separating from 'Sharp' weapons to avoid cost of 5000 AU per missile
+N:237:Sharpened
+T:17:0:99
+T:18:0:99
+X:B:23:10
+W:5:2:30:400
+R:100
+F:VORPAL
+f:VORPAL
+
+# N: serial number : ego type
+# D: description
+# T: tval : min sval : max sval
+# R: rarity
+# X: position : slot : rating
+# W: depth : rarity1 : rarity2 : cost
+# C: to-hit : to-dam : to-ac : pval
+# r:N:needed flags on the base object
+# r:F:forbidden flags on the base object
+# Z: granted_power
+# F: flags
diff --git a/lib/mods/theme/edit/evil.map b/lib/mods/theme/edit/evil.map
new file mode 100644
index 00000000..a2f00914
--- /dev/null
+++ b/lib/mods/theme/edit/evil.map
@@ -0,0 +1,52 @@
+# permanent wall
+F:X:61:0
+
+# granite
+F:#:57:0
+
+# Mountain Chain
+F:^:97:0
+
+# up staircase
+F:<:6:0
+
+# Dirt
+F:.:88:0
+
+# Lesser Balrog
+F:b:88:0:996:0:0:0:0:0:0:2
+
+# Greater Balrog
+F:B:88:0:807:0:0:0:0:0:0:2
+
+# Pit Fiend
+F:P:88:0:812:0:0:0:0:0:0:2
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X^..^^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:X^..^^^^^^^^^..^^^^^^^^^^^^^^^^^X
+D:X^...^^^^^^.........^^^^^^^^^^^^X
+D:X^^..^^^^^..^^^^..^B^^^^^^^^^^^^X
+D:X^...^^^^...^^^^^..^^^^^^^^^^^^^X
+D:X^^..^^^..^^.^^^^^^^^^^^^^^^^^^^X
+D:X^..^^^^^.....^^^^^.^^^^^^^^^^^^X
+D:X^^..^^^^..^^.^^^.^......^^^^^^^X
+D:X^..^^^^..^^...^^...^..^.^^^^^^^X
+D:X^^..^^^..^^^..^...^^^....^^^^^^X
+D:X^^^...^.^^^.....^^^^P...<^^^^^^X
+D:X^^^.....^^^^..^^^^^^^^..^^^^^^^X
+D:X^^^^^^.^^^^..^^^^^^^^^^^^^^^^^^X
+D:X^^^^^^^^^^^...^^^^^^^^^^^^^^^^^X
+D:X^^^^^.^^^^.^..^^^^^^^^^^^^^^^^^X
+D:X^^^^...^^...^^^...^^^^^^...^^^^X
+D:X^^^^.^....^^^^.^.....^..^..^^^^X
+D:X^^^^..^^^^^.....^...^..^^^B^^^^X
+D:X^^^P........^.....^^^^^^^^^^^^^X
+D:X^^^^^^...^^^^^^^^^^^^^^^^^^^^^^X
+D:X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:4
+
diff --git a/lib/mods/theme/edit/f_info.txt b/lib/mods/theme/edit/f_info.txt
new file mode 100644
index 00000000..dbfec51a
--- /dev/null
+++ b/lib/mods/theme/edit/f_info.txt
@@ -0,0 +1,1245 @@
+# File: f_info.txt
+
+
+# This file is used to initialize the "lib/raw/f_info.raw" file, which is
+# used to initialize the "terrain feature" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/f_info.raw" file.
+
+# Note that the terrain feature are grouped into very regular groups,
+# such that each of the bits in the feature type conveys information.
+
+# Note that terrain feature zero contains the "darkness" picture.
+
+
+# Version stamp (required)
+
+V:2.0.0
+
+
+# 0x00 --> nothing
+
+N:0:nothing
+G: :w
+F:FLOOR
+
+# 0x01 --> open floor
+
+N:1:open floor
+G:.:w
+F:FLOOR | DONT_NOTICE_RUNNING | SUPPORT_LIGHT | CAN_RUN
+F:SUPPORT_GROWTH
+
+# 0x02 -> fountain
+N:2:fountain
+G:_:w
+F:FLOOR | NOTICE | REMEMBER | CAN_RUN
+D:0:The liquid here seems magical.
+
+# 0x03 --> glyph of warding
+
+N:3:glyph of warding
+G:;:y
+F:FLOOR | NOTICE | SUPPORT_LIGHT | CAN_RUN | REMEMBER
+D:0:There is a mighty spell of protection here.
+
+# 0x04 --> open door
+
+N:4:open door
+G:':U
+F:FLOOR | NOTICE | REMEMBER | CAN_RUN | DOOR
+
+# 0x05 --> broken door
+
+N:5:broken door
+G:':U
+F:FLOOR | NOTICE | REMEMBER | CAN_RUN | DOOR
+
+# 0x06 --> up stairs (perm)
+
+N:6:up staircase
+G:<:w
+F:FLOOR | PERMANENT | NOTICE | SUPPORT_LIGHT | REMEMBER | CAN_RUN
+D:0:There is an up staircase here.
+D:1:You cannot tunnel a stair.
+
+# 0x07 --> down stairs (perm)
+
+N:7:down staircase
+G:>:w
+F:FLOOR | PERMANENT | NOTICE | SUPPORT_LIGHT | REMEMBER | CAN_RUN
+D:0:There is a down staircase here.
+D:1:You cannot tunnel a stair.
+
+N:8:quest entrance
+G:>:y
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+D:1:You cannot tunnel a quest entrance.
+
+N:9:quest exit
+G:<:y
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+D:1:You cannot tunnel a quest exit.
+
+N:10:quest down level
+G:>:r
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+
+N:11:quest up level
+G:<:r
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+
+N:12:town exit
+G:>:g
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+
+N:13:shaft down
+G:>:U
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+D:0:There is a shaft down here.
+D:1:You cannot tunnel a shaft.
+
+N:14:shaft up
+G:<:U
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+D:0:There is a shaft up here.
+D:1:You cannot tunnel a shaft.
+
+# 0x0F -> empty fountain
+N:15:fountain
+G:_:D
+F:FLOOR | NOTICE | REMEMBER | CAN_RUN
+D:0:The fountain seems empty.
+
+N:16:web
+G:+:y
+F:CAN_PASS | NOTICE | WEB | NOTICE | TUNNELABLE
+D:1:You tunnel through the web.
+D:2:a web blocking your way
+
+# Trap -- the flags are not used by the program
+N:17:trap
+G:^:w
+F:FLOOR | NOTICE | REMEMBER
+
+# 0x12 --> 0x1F -- UNUSED
+
+# 0x2x --> locked door (power 0)
+
+N:32:door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 1)
+
+N:33:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 2)
+
+N:34:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 3)
+
+N:35:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 4)
+
+N:36:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 5)
+
+N:37:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 6)
+
+N:38:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> locked door (power 7)
+
+N:39:locked door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | REMEMBER | DOOR
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 0)
+
+N:40:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 1)
+
+N:41:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 2)
+
+N:42:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 3)
+
+N:43:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 4)
+
+N:44:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 5)
+
+N:45:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 6)
+
+N:46:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x2x --> jammed door (power 7)
+
+N:47:jammed door
+G:+:U
+M:32
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | REMEMBER | NOTICE
+F:TUNNELABLE
+D:1:You bash the boor.
+
+# 0x30 --> secret door
+
+N:48:secret door
+G:#:w
+M:56
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | DOOR
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel.
+
+# 0x31 --> rubble
+
+N:49:pile of rubble
+G:::w
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE
+F:CAN_FLY | SUPPORT_LIGHT
+F:TUNNELABLE
+D:1:You dig in the rubble.
+
+# 0x32 --> magma vein
+
+N:50:magma vein
+G:%:s
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the magma vein.
+
+# 0x33 --> quartz vein
+
+N:51:quartz vein
+G:%:w
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the quartz vein.
+
+# 0x34 --> magma vein + treasure
+
+N:52:magma vein
+G:%:s
+M:50
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the magma vein.
+
+# 0x35 --> quartz vein + treasure
+
+N:53:quartz vein
+G:%:w
+M:51
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the quartz vein.
+
+# 0x36 --> magma vein + known treasure
+
+N:54:magma vein with treasure
+G:*:o
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the magma vein.
+
+# 0x37 --> quartz vein + known treasure
+
+N:55:quartz vein with treasure
+G:*:o
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the quartz vein.
+
+# 0x38 --> granite wall -- basic
+
+N:56:granite wall
+G:#:w
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the granite wall.
+
+# 0x39 --> granite wall -- inner
+
+N:57:granite wall
+G:#:w
+M:56
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the granite wall.
+
+# 0x3A --> granite wall -- outer
+
+N:58:granite wall
+G:#:w
+M:56
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the granite wall.
+
+# 0x3B --> granite wall -- solid
+
+N:59:granite wall
+G:#:w
+M:56
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the granite wall.
+
+# 0x3C --> permanent wall -- basic (perm)
+
+N:60:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+# 0x3D --> permanent wall -- inner (perm)
+
+N:61:permanent wall
+G:#:w
+M:60
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+# 0x3E --> permanent wall -- outer (perm)
+
+N:62:permanent wall
+G:#:w
+M:60
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+# 0x3F --> permanent wall -- solid (perm)
+
+N:63:permanent wall
+G:#:w
+M:60
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:64:explosive rune
+G:*:R
+F:FLOOR | CAN_LEVITATE | CAN_FLY | NOTICE | SUPPORT_LIGHT
+D:0:This rune seems unstable.
+
+N:65:Straight Road startpoint
+G:*:w
+F:FLOOR | REMEMBER | NOTICE
+
+N:66:section of the Straight Road
+G:*:B
+F:FLOOR | REMEMBER | NOTICE
+
+N:67:section of the Straight Road
+G:*:b
+F:FLOOR | REMEMBER | NOTICE
+
+N:68:section of the Straight Road
+G:*:B
+F:FLOOR | REMEMBER | NOTICE
+
+N:69:section of the Straight Road
+G:*:b
+F:FLOOR | REMEMBER | NOTICE
+
+N:70:section of the Straight Road
+G:*:W
+F:FLOOR | REMEMBER | NOTICE
+
+N:71:section of the Straight Road (discharged)
+G:*:W
+F:FLOOR | REMEMBER | NOTICE
+
+N:72:Straight Road exit
+G:*:w
+F:FLOOR | REMEMBER | NOTICE
+
+N:73:corrupted section of the Straight Road
+G:*:D
+F:FLOOR | REMEMBER | NOTICE
+
+# 74 --> shop
+
+N:74:Building
+G:1:U
+F:FLOOR | PERMANENT | REMEMBER | NOTICE | CAN_RUN
+
+# 75 --> 78 Quests index
+
+N:75:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:76:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:77:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:78:permanent wall
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+#Elanor
+N:79:grass with Elanor flowers
+G:&:y
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+#Fumellar
+N:80:grass with Fumella flowers
+G:;:r
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+#Anemones
+N:81:grass with anemones
+G:;:v
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+#Niphredil
+N:82:grass with Niphredil flowers
+G:;:w
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+#Iris
+N:83:grass with irises
+G:;:b
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+N:84:stream of shallow water
+G:~:B
+S:B:B:B:B:B:B:b
+F:ATTR_MULTI
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+F:SUPPORT_GROWTH
+
+# -1 = player level
+N:85:pool of deep lava
+G:.:R
+E:-1d2:1:FIRE
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+D:0:You move across the deep lava.
+
+N:86:stream of shallow lava
+G:.:r
+E:-1d1:1:FIRE
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+D:0:You move across the shallow lava.
+
+N:87:dark pit
+G:#:D
+F:CAN_LEVITATE | CAN_FLY
+F:NO_WALK | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+D:0:Ohhh, it is dark and deep.
+
+N:88:dirt
+G:.:U
+F:FLOOR | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+F:SUPPORT_GROWTH
+
+N:89:patch of grass
+G:.:G
+F:FLOOR | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+F:SUPPORT_GROWTH
+
+N:90:ice
+G:.:W
+E:1d1:50:ICE
+F:FLOOR | NOTICE
+
+N:91:sand
+G:.:y
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+N:92:dead tree
+G:#:D
+F:CAN_FLY | CAN_PASS
+F:WALL | NO_WALK | NO_VISION | NOTICE
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You chop away at the dead tree.
+D:2:a tree blocking your way
+
+N:93:ash
+G:.:s
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+N:94:puddle of mud
+G:.:u
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+N:95:ice wall
+G:#:W
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the ice wall... #BOh, chilly#w.
+D:2:an ice wall blocking your way
+
+N:96:tree
+G:#:G
+F:CAN_FLY | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You chop away at the tree.
+D:2:a tree blocking your way
+
+N:97:mountain chain
+G:^:U
+F:CAN_CLIMB | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION
+F:DONT_NOTICE_RUNNING
+F:PERMANENT
+D:1:You cannot tunnel into such a hard stone.
+D:2:a hard stone block blocking your way
+
+# 0x62 --> sandwall
+
+N:98:sandwall
+G:#:y
+F:WALL | NO_WALK | CAN_PASS | NO_VISION
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You easily dig into the sandwall.
+D:2:a sandwall blocking your way
+
+# 0x63 --> sandwall + treasure
+
+N:99:sandwall
+G:%:y
+M:98
+F:WALL | NO_WALK | CAN_PASS | NO_VISION
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You easily dig into the sandwall.
+D:2:a sandwall blocking your way
+
+# 0x64 --> sandwall + known treasure
+
+N:100:sandwall with treasure
+G:*:o
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You easily tunnel into the sandwall.
+D:2:a sandwall blocking your way
+
+N:101:high mountain chain
+G:^:W
+F:WALL | NO_WALK | NO_VISION | PERMANENT
+F:DONT_NOTICE_RUNNING
+D:1:This rock is far too hard.
+D:2:a very hard stone block blocking your way
+
+N:102:nether mist
+G:.:v
+S:v:R:r:v:R:r:D
+E:1d1:40:NETHER
+F:ATTR_MULTI
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+
+# A diggable glass wall.
+N:103:molten glass wall
+G:.:B
+F:NO_WALK | WALL | CAN_PASS | TUNNELABLE | NOTICE
+F:DONT_NOTICE_RUNNING
+D:1:You tunnel into the molten glass wall...
+D:2:a molten glass wall blocking your way
+
+N:159:Void Jumpgate
+G:+:v
+F:FLOOR | REMEMBER | NOTICE | PERMANENT | CAN_RUN
+D:0:A dark rift opens to the void here.
+
+N:160:Void Jumpgate
+G:+:v
+F:FLOOR | REMEMBER | NOTICE | PERMANENT | CAN_RUN
+D:0:A dark rift opens to the void here.
+
+###### Here are the altars. ######
+
+N:161:Altar of Being
+G:0:W
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You feel at peace.
+
+N:162:Altar of Winds
+G:0:B
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You grow a desire to become a bird.
+
+N:163:Altar of Force
+G:0:R
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You grow a desire to fight evil.
+
+N:164:Altar of Darkness
+G:0:D
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:Images of pain and death fill your mind.
+
+N:165:Altar of Nature
+G:0:g
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You feel the desire to walk in a great forest.
+
+N:166:Altar of Stone
+G:0:s
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You grow a desire to forge items.
+
+N:167:Altar of Light
+G:0:y
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You grow a desire to light up dark places.
+
+N:168:Altar of Waters
+G:0:b
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You grow a desire to bathe in the ocean.
+
+N:169:Altar of Doom
+G:0:o
+F:FLOOR | REMEMBER | NOTICE | CAN_RUN
+D:0:You grow a desire to do justice.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+# Used as a marker for random quests
+N:172:open floor
+G:.:w
+F:FLOOR | CAN_RUN | DONT_NOTICE_RUNNING
+F:SUPPORT_GROWTH
+
+# Underground Tunnel
+N:173:Underground Tunnel
+G:#:s
+F:FLOOR | REMEMBER | SUPPORT_LIGHT | DONT_NOTICE_RUNNING | CAN_RUN
+D:0:Oh, an underground tunnel!
+
+# Tainted water
+N:174:stream of tainted water
+G:~:u
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:175:monster trap
+G:;:v
+F:FLOOR
+
+N:176:Void Jumpgate
+G:+:v
+F:FLOOR | REMEMBER | NOTICE | PERMANENT | CAN_RUN
+D:0:A dark rift opens to the void here.
+
+N:177:lava wall
+G:#:R
+S:R:R:r:r:U:u:R
+F:ATTR_MULTI
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+D:1:The lava is far too hot to tunnel into it.
+D:2:a lava wall blocking your way
+
+N:178:Great Fire
+G:%:v
+S:R:R:y:v:y:v:R
+E:150d2:1:HELL_FIRE
+F:ATTR_MULTI
+F:FLOOR | REMEMBER | NOTICE | PERMANENT
+D:0:This fire is so powerful it could destroy even the most powerful artifacts.
+
+N:179:path to the next area
+G:>:w
+F:FLOOR | PERMANENT | NOTICE | REMEMBER | CAN_RUN
+D:0:There is a path leading to the next area here.
+D:1:You cannot tunnel a path.
+
+N:180:path to the previous area
+G:<:w
+F:FLOOR | PERMANENT | NOTICE | REMEMBER | CAN_RUN
+D:0:There is a path leading to the previous area here.
+D:1:You cannot tunnel a path.
+
+N:181:field
+G:::g
+F:FLOOR | PERMANENT | NOTICE | REMEMBER
+F:DONT_NOTICE_RUNNING
+D:1:You cannot tunnel a field.
+
+N:182:Ekkaia, the Encircling Sea
+G:*:b
+S:b:b:b:b:b:b:B
+F:ATTR_MULTI
+F:WALL | NO_WALK | NO_VISION | PERMANENT | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+N:183:void
+G: :d
+F:FLOOR
+
+# XXX 182 - 186
+
+# 187 --> terrain -- deep water
+
+N:187:pool of deep water
+G:~:b
+S:b:b:b:b:b:b:B
+F:ATTR_MULTI
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+
+# Glass wall -- can see but not pass
+N:188:glass wall
+G:.:B
+F:NO_WALK | WALL | PERMANENT | NOTICE
+F:DONT_NOTICE_RUNNING
+D:1:This glass seems to be totaly impenetrable.
+D:2:a glass wall blocking your way
+
+# Illusion wall -- can't see but can pass
+N:189:illusion wall
+G:#:w
+F:FLOOR | NO_VISION | REMEMBER | SUPPORT_LIGHT | DONT_NOTICE_RUNNING
+D:0:Looks like this wall is not so real.
+
+# Grass roof
+N:190:Grass roof
+G:#:y
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# grass roof top
+N:191:grass roof top
+G:#:y
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# grass roof chimney
+N:192:grass roof chimney
+G:#:y
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# brick roof
+N:193:brick roof
+G:#:r
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# brick roof top
+N:194:brick roof top
+G:#:r
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# brick roof chimney
+N:195:brick roof chimney
+G:#:r
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# window
+N:196:window
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# small window
+N:197:small window
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# rain barrel
+N:198:rain barrel
+G:#:w
+F:WALL | NO_WALK | NO_VISION | PERMANENT | DONT_NOTICE_RUNNING
+
+# grass with Kingsfoil flowers
+N:199:grass with Kingsfoil flowers
+G:;:G
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+# cobblestone road
+N:200:cobblestone road
+G:.:w
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+
+# cobblestone with outlet
+N:201:cobblestone with outlet
+G:.:w
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+
+N:202:small tree
+G:#:g
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN | SUPPORT_LIGHT | REMEMBER
+F:NO_VISION
+
+# Just to have a town entrance picture
+N:203:town
+G:*:w
+F:FLOOR | NOTICE
+
+# Underground Tunnel
+N:204:Underground Tunnel
+G:^:U
+F:FLOOR | REMEMBER | SUPPORT_LIGHT | DONT_NOTICE_RUNNING | CAN_RUN
+D:0:Oh, an underground tunnel!
+
+# Fire
+N:205:a blazing fire
+G:%:y
+S:y:y:y:R:r:y:R
+E:-1d2:1:FIRE
+D:0:The blazing fire burns you!
+F:ATTR_MULTI
+F:FLOOR | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+
+# Permanent rubble -- town use
+N:206:pile of rubble
+G:::w
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE
+F:CAN_FLY | SUPPORT_LIGHT | PERMANENT
+D:1:Looks like this pile of rubble is quite hard.
+
+# Rocky ground - rougher terrain.
+N:207:rocky ground
+G:.:s
+F:FLOOR | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+
+# cloud-like vapour. Floor for Eru's temple
+N:208:cloud-like vapour
+G:.:W
+S:W:B:B:W:w:W:B
+F:FLOOR | CAN_LEVITATE | CAN_FLY | SUPPORT_LIGHT
+F:ATTR_MULTI | CAN_RUN | DONT_NOTICE_RUNNING
+
+# condensing water
+N:209:condensing water
+G:~:B
+S:B:B:B:B:B:B:b
+F:ATTR_MULTI
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING
+
+# Dense mist. Can pass through, but not see through
+N:210:dense mist
+G:#:w
+S:w:W:s:s:s:w:w
+F:FLOOR | NO_VISION | REMEMBER | SUPPORT_LIGHT
+F:ATTR_MULTI | DONT_NOTICE_RUNNING
+D:0:You wander through the mist.
+D:1:You cannot tunnel through mist!
+
+# Hail-stone wall
+N:211:hail-stone wall
+G:#:W
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You tunnel into the hail-stone wall.
+
+N:212:dead small tree
+G:#:D
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN | SUPPORT_LIGHT | REMEMBER
+F:NO_VISION
+
+# Low hill
+N:213:low hill
+G:^:g
+F:FLOOR | DONT_NOTICE_RUNNING| CAN_RUN | SUPPORT_LIGHT | NO_VISION
+D:0:You go over the hill.
+D:1:You cannot tunnel through that.
+
+#Angband and Mordor (Ered Lithui, Ephel Duath) mountains
+N:214:dark mountain chain
+G:^:D
+F:WALL | NO_WALK | NO_VISION | PERMANENT
+F:DONT_NOTICE_RUNNING
+D:1:This rock is far too hard.
+D:2:a very hard stone block blocking your way
+
+#Ered Luin - Blue Mountains
+N:215:blue mountain chain
+G:^:B
+F:CAN_CLIMB | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION
+F:DONT_NOTICE_RUNNING
+F:PERMANENT
+D:1:You cannot tunnel into such a hard stone.
+D:2:a hard stone block blocking your way
+
+#Ered Mithrin - Grey Mountains
+N:216:grey mountain chain
+G:^:s
+F:CAN_CLIMB | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION
+F:DONT_NOTICE_RUNNING
+F:PERMANENT
+D:1:You cannot tunnel into such a hard stone.
+D:2:a hard stone block blocking your way
+
+#Orodruin - Mount Doom
+N:217:part of Mount Doom
+G:^:R
+F:WALL | NO_WALK | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+F:PERMANENT
+D:1:You cannot tunnel through that.
+D:2:a stream of searing lava barring your way
+
+#Snow-capped peak
+N:218:snow-capped peak
+G:^:w
+F:WALL | NO_WALK | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING | PERMANENT
+D:1:The ice is too cold to tunnel into it.
+D:2:an unusually thick wall of ice barring your way
+
+#Fir tree
+#BUG - these do not burn.
+N:219:fir tree
+G:#:g
+F:CAN_FLY | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION
+F:DONT_NOTICE_RUNNING
+F:TUNNELABLE
+D:1:You chop away at the fir tree.
+D:2:a fir tree blocking your way
+
+#section of a flet (wooden platforms built high up in the trees of Lothlórien)
+N:220:section of a flet
+G:_:u
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+
+#light post
+N:221:light post
+G:|:w
+F:WALL | NO_WALK | CAN_FLY | CAN_PASS
+F:SUPPORT_LIGHT | REMEMBER
+D:1:You cannot tunnel a light post.
+D:2:A light post blocking your way
+
+#Water lily
+N:222:water lily
+G:;:B
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+#Dead Marshes swamp water
+N:223:part of the Dead Marshes
+G:~:G
+E:10d10:6:CONFUSION
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+
+#Morannon
+N:224:Black Gate
+G:+:D
+F:CAN_CLIMB | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION | NOTICE
+F:DONT_NOTICE_RUNNING
+F:PERMANENT
+D:1:You cannot tunnel through that.
+D:2:a closed Black Gate blocking your way
+
+#River (overland view only)
+N:225:river
+G:~:w
+S:w:w:w:B:w:w:B
+F:ATTR_MULTI
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT | CAN_RUN
+F:DONT_NOTICE_RUNNING | SUPPORT_GROWTH
+
+#Swamp
+N:226:swamp pool
+G:~:g
+E:1d1:1:POISON
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT
+
+#Anduin river
+N:227:stream of the Anduin river
+G:~:B
+E:1d1:1:WATER
+S:w:w:w:b:w:w:b
+F:ATTR_MULTI
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT | SUPPORT_GROWTH
+
+#Road sign to Gondolin to avoid Maeglin quest silliness somewhat
+N:228:road sign that says 'Find Gondolin!'
+G:?:v
+S:v:R:B:G:w:v:R
+F:ATTR_MULTI
+F:WALL | PERMANENT | NOTICE | SUPPORT_LIGHT | REMEMBER |
+
+### New terrain features for town use ###
+
+#Beehive
+N:229:beehive
+G:*:o
+E:1d1:1:POISON
+F:WALL | PERMANENT | CAN_FLY | REMEMBER | SUPPORT_LIGHT |
+F:CAN_PASS | NO_WALK | NO_VISION | DONT_NOTICE_RUNNING |
+D:0:Ouch! A bee stung you!
+D:1:You'll just get stung.
+D:2:a beehive blocking your way
+
+#Dirt road - same as dirt but more appropriate for towns
+N:230:dirt road
+G:.:U
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN
+F:SUPPORT_GROWTH
+
+#Wide gate
+N:231:wide gate
+G:-:D
+F:WALL | PERMANENT | CAN_FLY | SUPPORT_LIGHT | NOTICE |
+F:CAN_PASS | NO_WALK | NO_VISION | DONT_NOTICE_RUNNING |
+D:1:You cannot tunnel through that.
+D:2:a closed gate barring your way
+
+#Same gate, but opened
+N:232:open gate
+G:':D
+F:FLOOR | DONT_NOTICE_RUNNING | CAN_RUN | SUPPORT_LIGHT |
+
+### For wood houses, bridges, etc:
+
+#Wooden board - horizontal
+N:233:wooden board
+G:-:u
+F:WALL | PERMANENT | SUPPORT_LIGHT | NO_WALK | NO_VISION | CAN_FLY
+D:1:You cannot tunnel through that.
+D:2:a wooden board blocking your way
+
+#Wooden board - vertical
+N:234:wooden board
+G:|:u
+F:WALL | PERMANENT | SUPPORT_LIGHT | NO_WALK | NO_VISION | CAN_FLY
+D:1:You cannot tunnel through that.
+D:2:a wooden board blocking your way
+
+#Light wooden board - horizontal
+N:235:wooden board
+G:-:U
+F:WALL | PERMANENT | SUPPORT_LIGHT | NO_WALK | NO_VISION | CAN_FLY
+D:1:You cannot tunnel through that.
+D:2:a wooden board blocking your way
+
+#Light wooden board - vertical
+N:236:wooden board
+G:|:U
+F:WALL | PERMANENT | SUPPORT_LIGHT | NO_WALK | NO_VISION | CAN_FLY
+D:1:You cannot tunnel through that.
+D:2:a wooden board blocking your way
+
+#White tree
+#BUG - these do not burn.
+N:237:white tree
+G:#:w
+F:CAN_FLY | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION | PERMANENT
+F:DONT_NOTICE_RUNNING
+D:1:You cannot tunnel through that.
+D:2:a white tree blocking your way
+
+#Swift waterfall
+N:238:swift waterfall
+G:|:B
+E:25d10:1:WATER
+S:w:w:w:b:w:w:b
+F:ATTR_MULTI
+F:FLOOR | CAN_LEVITATE | CAN_FLY | REMEMBER | SUPPORT_LIGHT |
+F:DONT_NOTICE_RUNNING | SUPPORT_GROWTH |
+
+#Slippery rock ledge
+N:239:slippery rock ledge
+G:&:s
+E:5d10:1:COLD
+F:FLOOR | CAN_LEVITATE | CAN_FLY | SUPPORT_LIGHT |
+F:SUPPORT_GROWTH
+
+#Stable
+N:240:stable
+G:#:u
+F:WALL | NO_WALK | NO_VISION | PERMANENT | CAN_FLY
+D:1:You cannot tunnel through that.
+D:2:a stable wall blocking your way
+
+#Wooden plank
+N:241:wooden plank
+G:%:U
+F:FLOOR | CAN_RUN | DONT_NOTICE_RUNNING | SUPPORT_LIGHT |
+F:SUPPORT_GROWTH |
+
+#Fosse (dry moat)
+N:242:fosse pit
+G:&:g
+F:CAN_LEVITATE | CAN_FLY
+F:NO_WALK | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING
+D:1:You cannot tunnel through that.
+D:2:a dry moat blocking your way
+
+#Mallorn
+N:243:Mallorn
+G:*:y
+S:y:W:W:y:w:W:y
+F:CAN_FLY | CAN_PASS | SUPPORT_LIGHT
+F:WALL | NO_WALK | NO_VISION
+F:DONT_NOTICE_RUNNING
+D:1:It isn't a good idea to harm a Mallorn.
+D:2:a Mallorn blocking your way
+
+# New features for the Maps of Lord Dimwit
+
+N:244:copper pillar
+G:#:u
+S:u:u:u:o:u:u:u
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING | ATTR_MULTI
+D:1:The copper is too tough to tunnel through.
+D:2:a copper pillar blocking your way
+
+N:245:ethereal wall
+G:.:w
+F:WALL | NO_WALK | PERMANENT | NOTICE | DONT_NOTICE_RUNNING
+D:1:You can't even see your obstruction!
+D:2:an unseen force blocking your way
+
+N:246:glacial wall
+G:#:B
+F:WALL | NO_WALK | CAN_PASS | NO_VISION | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING | TUNNELABLE
+D:1:You tunnel into the glacial wall... #BOh, chilly!#w.
+D:2:a hard glacial wall blocking your way
+
+N:247:battlement
+G:#:w
+F:NO_WALK | CAN_PASS | NOTICE | SUPPORT_LIGHT
+F:DONT_NOTICE_RUNNING | TUNNELABLE
+D:1:You tunnel into the battlement.
+D:2:a hard stone battlement blocking your way
+
+N:248:door of Orthanc
+G:':r
+F:FLOOR | NOTICE | REMEMBER | CAN_RUN
+F:SUPPORT_LIGHT | DONT_NOTICE_RUNNING
+D:0:The Key of Orthanc allows you to pass. \ No newline at end of file
diff --git a/lib/mods/theme/edit/fireprof.map b/lib/mods/theme/edit/fireprof.map
new file mode 100644
index 00000000..35f6bec4
--- /dev/null
+++ b/lib/mods/theme/edit/fireprof.map
@@ -0,0 +1,60 @@
+# Created by fearoffours (fearoffours@moppy.co.uk)
+# Made for ToME 2.1.x on 03/09/02
+
+# Permanent wall
+F:X:63:3
+
+# Floor with dirt
+F:.:88:3
+
+# shallow lava
+F:f:86:3
+
+# Deep lava
+F:F:85:3
+
+### Random Monsters and/or Items
+# Random object (upto 3 levels ood)
+F:!:88:5:0:*21
+
+# red mold
+F:m:88:5:324
+
+# Chimaera
+F:H:88:5:341
+
+# Red dragon bat
+F:b:88:5:377
+
+# Hellhound and
+# Random object (upto 7 levels ood) on normal floor
+F:C:88:5:613:*25
+
+# Quest exit
+F:<:6:3
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X......m.................H.........b...m......X
+D:X.............b...............................X
+D:X.......................m.....m.......H...b.C.X
+D:X...............m.!........b.............FFFf.X
+D:X.........m!............H....!........fffFFFffX
+D:X..................................fffFFFFFFfFX
+D:XFFf..............................fFFFFff..fffX
+D:XFFFff........FFFFFF...........fffFFFfff......X
+D:XfFFFFfff....FFFFFFFf.......fffFFFFFf.........X
+D:X.fFFFFFFff.FFFFFFFFFfF..fffFFFFFFff..........X
+D:X..fFFFFFFFffFFFfffFFFfffFFFFFFFFf............X
+D:X...fFFFFFFFFFFff.ffFFFFFFFFFFFff.............X
+D:X....fffFFFFFFff...ffFFFFFFFFFf...............X
+D:X.......ffFFFf.......ffffFFfff................X
+D:X.........fff.................................X
+D:X.............................................X
+D:X.............................................X
+D:X.............................................X
+D:X..................................<..........X
+D:X.............................................X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:22:26
diff --git a/lib/mods/theme/edit/haunted.map b/lib/mods/theme/edit/haunted.map
new file mode 100644
index 00000000..49f72d5b
--- /dev/null
+++ b/lib/mods/theme/edit/haunted.map
@@ -0,0 +1,49 @@
+# permanent wall
+F:X:61:0
+
+# granite
+F:#:57:0
+
+# up staircase
+F:<:6:0
+
+# Floor
+F:.:1:0
+
+# Locked Door
+F:D:38:0
+
+# Secret Door
+F:S:48:0
+
+# Great item
+F:g:1:0:0:*:*
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXX...D.........................X
+D:XXX...XXXXXXXXXXXXXXXXXXXXXXXXX.X
+D:XXX...X....X....X....X....X...X.X
+D:XXX...X....X....X....X....X...X.X
+D:XXX...X....X....X....X....X...X.X
+D:XXXDXXXDXXXXDXXXXDXXXXDXXXXDXXX.X
+D:XXX.............................X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.X
+D:X.S.....X.....X.....X.....X...X.X
+D:X.X.....X.....X.....X.....X...X.X
+D:X.X.....X.....X.....X.....X...X.X
+D:X.X.....X.....X.....X.....X...X.X
+D:XgX.....X.....X.....X.....X...X.X
+D:XXXDXXXXXDXXXXXDXXXXXDXXXXXDXXX.X
+D:XXX.............................X
+D:XXXXXXXDXXXXXDXXXXXDXXXXXDXXXXXDX
+D:XgX<....X.....X.....X.....X.....X
+D:X.X.....X.....X.....X.....X.....X
+D:X.X.....X.....X.....X.....X.....X
+D:X.X.....X.....X.....X.....X.....X
+D:X.S.....X.....X.....X.....X.....X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:5
+
diff --git a/lib/mods/theme/edit/k_info.txt b/lib/mods/theme/edit/k_info.txt
new file mode 100644
index 00000000..07e4bbe2
--- /dev/null
+++ b/lib/mods/theme/edit/k_info.txt
@@ -0,0 +1,6865 @@
+# File: k_info.txt
+
+
+# This file is used to initialize the "lib/data/k_info.raw" file, which is
+# used to initialize the "object kind" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/data/k_info.raw" file.
+
+# Available slots are marked with # XXX: 294, 299, 444-464, ...
+
+# XXX XXX Add some "IGNORE_XXX" flags to Rings, Amulets, etc.
+
+# The old "MULTI_HUED" objects are now "violet", and no other object
+# is violet, so all six violet objects can be made "multi-hued", though
+# this would be a heinous hack. XXX XXX
+
+# Note that object zero is used for the "stack" picture (unused).
+
+# N: serial number : & object name~
+# G: symbol : color
+# I: tval : sval : pval
+# W: depth : rarity : weight : cost
+# P: base armor class : base damage : plus to-hit : plus to-dam : plus to-ac
+# A: depth/rarity : depth/rarity : etc
+# F: flag | flag | etc
+
+# Version stamp (required)
+
+V:2.0.0
+
+
+##### Something special #####
+
+N:0:something
+G:&:w
+
+
+##### Mushrooms #####
+
+N:1:Blindness
+G:,:d
+I:80:1:500
+W:5:0:1:0
+A:5/1
+D:'E'ating this mushrooms will blind you. You cannot cast magic
+D:or see monsters when you are blinded. You can still use magic items or
+D:quaff potions.
+
+N:2:Fear
+G:,:d
+I:80:2:500
+W:5:0:1:0
+A:5/1
+D:'E'ating this mushroom will make you scared.
+D:You will not be able to hit your enemies in combat if you're scared.
+
+N:3:Confusion
+G:,:d
+I:80:3:500
+W:5:0:1:0
+A:5/1
+D:'E'ating this mushroom will confuse you. You will not be able to cast spells,
+D:use wands, staves or scrolls. You can still quaff potions, though.
+
+N:4:Hallucination
+G:,:d
+I:80:4:500
+W:10:0:1:0
+A:10/1
+D:'E'ating this mushroom will make you hallucinate.
+D:You will not be able to recognise any monster or item.
+
+N:5:Cure Poison
+G:,:d
+I:80:12:500
+W:10:0:1:60
+A:10/1
+D:'E'ating this mushroom will cure you from poison.
+
+N:6:Cure Blindness
+G:,:d
+I:80:13:500
+W:10:0:1:50
+A:10/1
+D:'E'ating this mushroom will cure you from blindness.
+
+N:7:Cure Fear
+G:,:d
+I:80:14:500
+W:10:0:1:25
+A:10/1
+D:'E'ating this mushroom will cure your paranoia. Paranoia is the state when you are
+D:too afraid to attack monsters.
+
+N:8:Cure Confusion
+G:,:d
+I:80:15:500
+W:10:0:1:50
+A:10/1
+D:'E'ating this mushroom will cure your confusion. Confusion is when you are too confused
+D:to cast spells, zap staves, aim wands or read scrolls.
+
+N:9:Weakness
+G:,:d
+I:80:6:500
+W:10:0:1:0
+A:10/1
+P:0:5d5:0:0:0
+D:'E'ating this mushroom will reduce your strength by one point.
+
+N:10:Unhealth
+G:,:d
+I:80:10:500
+W:15:0:1:50
+A:15/1
+P:0:10d10:0:0:0
+D:'E'ating this mushroom will reduce your constitution by one point.
+
+N:11:Restore Constitution
+G:,:d
+I:80:18:500
+W:20:0:1:350
+A:20/1
+D:'E'ating this mushroom will restore your constitution. Your constitution
+D:needs restoring when it is displayed in yellow.
+
+N:12:Restoring
+G:,:d
+I:80:19:500
+W:20:0:1:1000
+A:20/8:30/4:40/1
+D:'E'ating this mushroom will restore your strength, dexterity, constitution,
+D:intelligence, wisdom and charisma. These need restoring when they
+D:are displayed in yellow.
+
+N:13:Stupidity
+G:,:d
+I:80:8:500
+W:15:0:1:0
+A:15/1
+D:'E'ating this mushroom will reduce your intelligence by one point.
+D:That's a bad thing.
+
+N:14:Naivety
+G:,:d
+I:80:9:500
+W:15:0:1:0
+A:15/1
+D:'E'ating this mushroom will reduce your wisdom by one point.
+D:That's a bad thing.
+
+N:15:Poison
+G:,:d
+I:80:0:500
+W:5:0:1:0
+A:5/1:5/1
+P:0:4d4:0:0:0
+D:'E'ating this mushroom will poison you. Poisoning makes you lose one hitpoint
+D:per turn until you magically stop the poison or until your body has
+D:fought off the poison.
+D:That's a bad thing.
+
+N:16:Sickness
+G:,:d
+I:80:7:500
+W:10:0:1:0
+A:10/1
+P:0:4d4:0:0:0
+D:'E'ating this mushroom will reduce your constitution by one point.
+D:It will also damage you quite severely in the process.
+D:That's a bad thing.
+
+N:17:Paralysis
+G:,:d
+I:80:5:500
+W:20:0:1:0
+A:20/1
+D:'E'ating this mushroom will paralyse you for a certain time.
+D:Any nearby monsters will take this opportunity to kill you.
+D:That's a bad thing.
+
+N:18:Restore Strength
+G:,:d
+I:80:17:500
+W:20:0:1:350
+A:20/1
+D:'E'ating this mushroom will restore your strength. Your strength
+D:needs restoring when it is displayed in yellow.
+
+N:19:Disease
+G:,:d
+I:80:11:500
+W:20:0:1:50
+A:20/1
+P:0:10d10:0:0:0
+D:'E'ating this mushroom will reduce your strength by one point.
+D:It will also damage you quite severely in the process.
+D:That's a bad thing.
+
+N:20:Cure Serious Wounds
+G:,:d
+I:80:16:500
+W:15:0:1:75
+A:15/1
+D:'E'ating this mushroom will heal several hit points. Your hit points
+D:need healing when they are displayed in yellow or red.
+
+##### Normal Food #####
+
+N:21:& Ration~ of Cram
+G:,:U
+I:80:35:5000
+W:0:0:10:3
+A:0/1:5/1:10/1
+D:It is biscuitish, keeps good indefinitely, is supposed to be sustaining but
+D:certainly not entertaining. Its origin is Esgaroth, the city of Lake-men.
+D:You can 'E'at it.
+
+N:22:& Round Seed-Cake~
+G:,:U
+I:80:32:500
+W:0:0:2:1
+D:It's a treat, but 'E'ating it will only fill your stomach for a short time.
+
+N:23:& Strip~ of Venison
+G:,:u
+I:80:33:1500
+W:0:0:2:2
+D:It looks great, and 'E'ating it will fill your stomach well.
+
+N:24:& Slime Mold~
+G:,:g
+I:80:36:3000
+W:1:0:5:2
+A:1/1
+D:It looks disgusting, but if you really want to you can 'E'at it.
+D:Not an incredible taste experience, but that'd be asking a bit much.
+
+# New - now Lembas works as a scroll of Satisfy Hunger
+N:25:& Lembas~
+G:,:B
+I:80:37:0
+W:5:0:3:10
+A:5/1:10/1:20/1
+D:Small golden-brown wafers wrapped in silver leaves. Its fabrication is a
+D:secret of the Elves, and it sustains life where nothing else can. If you
+D:'E'at it, you will be full.
+
+N:26:& Pint~ of Fine Ale
+G:,:y
+I:80:38:500
+W:0:0:5:1
+D:A bottle of a dark beer-like beverage from Eriador. You can drink it by pressing 'E'.
+
+N:27:& Pint~ of Old Winyards
+G:,:r
+I:80:39:1000
+W:0:0:10:2
+D:A bottle of fine wine from Eriador. You can drink it by pressing 'E'.
+
+##### Extra digger #####
+
+N:28:& Mattock~
+G:\:D
+I:20:7:3
+W:50:0:250:700
+A:50/2
+P:0:1d8:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:This is a digging tool. Use it to dig in walls, destroy doors, or cut wood.
+
+# The Blue Stone 'Coimir' -- see artifact list
+
+N:29:& Blue Stone~
+G:":B
+I:40:18:0
+W:60:0:3:90000
+F:INSTA_ART | SPECIAL_GENE
+
+##### Edged Weapons #####
+
+N:30:& Broken Dagger~
+G:|:D
+I:23:1:0
+W:0:0:5:1
+A:0/2:5/2
+P:0:1d1:-2:-4:0
+F:SHOW_MODS
+D:The blade itself is a foot long and broken off not far above the hilt.
+
+N:31:& Bastard Sword~
+G:|:W
+I:23:21:0
+W:15:0:140:350
+A:15/1
+P:0:3d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This is a long, double-edged sword with a plain hilt that could
+D:be wielded in one or two hands. It's called a "bastard sword" because in
+D:size, it falls between the broad sword and the two-handed sword, thus not
+D:having a family of its own. It's typically around 51 inches long.
+D:It is effective for cutting through tougher armours. It could be used for
+D:thrusting, but most wielders swing it like a bat.
+
+N:32:& Scimitar~
+G:|:W
+I:23:18:0
+W:10:0:130:250
+A:10/1
+P:0:2d5:0:0:0
+F:SHOW_MODS
+D:This oriental blade has 2 edges and is deeply curved. It has a wide
+D:and very sharp end. It is the forefather of the sabre.
+
+N:33:& Tulwar~
+G:|:W
+I:23:15:0
+W:5:0:100:200
+A:5/1
+P:0:2d4:0:0:0
+F:SHOW_MODS
+D:This vicious sword is half sword and half club, with a slight hook on the tip.
+
+N:34:& Broad Sword~
+G:|:W
+I:23:16:0
+W:10:0:150:255
+A:10/1:15/1
+P:0:2d5:0:0:0
+F:SHOW_MODS
+D:This broader version of the long sword is a standard weapon in the army
+D:of Gondolin.
+
+N:35:& Short Sword~
+G:|:W
+I:23:10:0
+W:5:0:80:90
+A:5/1
+P:0:1d7:0:0:0
+F:SHOW_MODS
+D:This shorter version of the long sword is a common weapon for rogues
+D:and mages.
+
+N:36:& Blade~ of Chaos
+G:|:v
+I:23:30:0
+W:70:0:180:4000
+A:70/8
+P:0:6d5:0:0:0
+F:ATTR_MULTI
+F:RES_CHAOS | CHAOTIC | SHOW_MODS
+f:RES_CHAOS | CHAOTIC
+D:A mighty sword which seems to be completely blunt. However, it is a conduit
+D:into the realms of pure chaos and strikes its victims with the devastating
+D:might of chaos itself whenever it connects. It gives you resistance to chaos
+D:and it can polymorph, teleport, confuse or drain hit points from the monster
+D:you hit. It occasionally causes earthquakes as well.
+
+N:37:& Two-Handed Sword~
+G:|:W
+I:23:25:0
+W:30:0:200:775
+A:30/1:40/1
+P:0:3d6:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This blade is lot longer, wider and heavier than a long sword. You have to
+D:wield it with two hands. This means that wielding a shield makes fighting
+D:very difficult.
+
+N:38:& Main Gauche~
+G:|:W
+I:23:5:0
+W:3:0:30:25
+A:3/1
+P:0:1d5:0:0:0
+F:SHOW_MODS
+D:This blade is sinuously curved and tipped with a harpoon-like end.
+D:This blade has a large handguard and was designed as an off-hand weapon.
+D:This short but cruel blade is a favourite among orcs.
+
+N:39:& Cutlass~
+G:|:W
+I:23:12:0
+W:5:0:110:85
+A:5/1
+P:0:1d7:0:0:0
+F:SHOW_MODS
+D:This oriental weapon is a short, thick, curving sword
+D:with a single cutting edge. This simple slashing weapon
+D:is typically carried by buccaneers, pirates, and sailors.
+
+N:40:& Executioner's Sword~
+G:|:r
+I:23:28:0
+W:40:0:260:850
+A:40/1
+P:0:4d5:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:These weapons have been built in all sizes. They are custom-made
+D:for warriors that want to set out and kill their archenemy. These
+D:blades are rare, costly and very deadly.
+
+N:41:& Katana~
+G:|:W
+I:23:20:0
+W:20:0:120:400
+A:20/1
+P:0:3d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:The katana is a long blade with only a small disk for a guard.
+D:Its hilt is long enough for two hands, though it could be used
+D:with only one hand, and is usually wrapped in cloth or leather.
+D:The art of forging such swords is largely unknown in this part
+D:of Middle-earth, and such weapons are typically imported from
+D:distant lands.
+
+N:42:& Long Sword~
+G:|:W
+I:23:17:0
+W:10:0:130:300
+A:10/1:20/1
+P:0:2d5:0:0:0
+F:SHOW_MODS
+D:A long straight sword, tapering to a pronounced point. Mainly good for
+D:piercing attacks, but it can be used for slashing, too. It is a very
+D:popular design and has become standard issue in many armies.
+
+N:43:& Dagger~
+G:|:W
+I:23:4:0
+W:0:0:12:10
+A:0/1:5/1:10/1:20/1
+P:0:1d4:0:0:0
+F:SHOW_MODS
+D:It's the standard weapon of rogues and thieves. The blade is
+D:a foot long.
+
+N:44:& Rapier~
+G:|:W
+I:23:7:0
+W:5:0:40:42
+A:5/1
+P:0:1d6:0:0:0
+F:SHOW_MODS
+D:The rapier's hilt consisted of a pair of oval guards pierced with holes,
+D:recurved quillions, and a knuckle guard. The guard is very intricate
+D:and very effective as protection.
+
+N:45:& Sabre~
+G:|:W
+I:23:11:0
+W:5:0:50:50
+A:5/1
+P:0:1d7:0:0:0
+F:SHOW_MODS
+D:A long, one-edged, slightly curved sword with a knuckle guard and short
+D:hilt. It is two-edged in its lower part.
+
+N:46:& Small Sword~
+G:|:W
+I:23:8:0
+W:5:0:75:48
+A:5/1
+P:0:1d6:0:0:0
+F:SHOW_MODS
+D:It's the favourite weapon of strong mages and thieves. The blade is
+D:about twenty inches long. It's very easy to handle, although it is a lot less
+D:efficient than the longer and heavier designs.
+
+N:47:& Broken Sword~
+G:|:D
+I:23:2:0
+W:0:0:30:2
+A:0/2:5/2
+P:0:1d2:-2:-4:0
+F:SHOW_MODS
+D:Just a hilt and a few inches of blade, broken off in a jagged stump.
+D:Probably worthless.
+
+##### Hafted Weapons #####
+
+N:48:& Ball-and-Chain~
+G:\:D
+I:21:6:0
+W:20:0:150:200
+A:20/1
+P:0:2d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This weapon has a ball linked with a chain to a wooden handle.
+D:Preferred tactic is smashing the brains of your opponent.
+
+N:49:& Whip~
+G:\:D
+I:21:2:0
+W:3:0:30:30
+A:3/1
+P:0:1d6:0:0:0
+F:SHOW_MODS
+D:This weapon is light and easy to fight with. It has nasty barbs and
+D:hooks fixed to the thong to make it useful in combat.
+D:Whips easily give multiple attacks.
+
+N:50:& Flail~
+G:\:D
+I:21:13:0
+W:10:0:150:353
+A:10/1
+P:0:2d6:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This weapon was originally used to cut corn. More warlike versions
+D:sport a large blade stuck on a wooden handle. The hinge allows it to get
+D:past enemy defences or to strike with added momentum when used skillfully.
+
+N:51:& Two-Handed Flail~
+G:\:y
+I:21:18:0
+W:45:0:280:590
+A:45/1
+P:0:3d6:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This two-handed version of the flail gives the fighter a fearsome
+D:weapon that can do a fair amount of damage. It typically has several
+D:spiked metal lumps on chains.
+
+N:52:& Morning Star~
+G:\:D
+I:21:12:0
+W:10:0:150:396
+A:10/1
+P:0:2d6:0:0:0
+F:SHOW_MODS
+D:This weapon consists of a large club with chains that have wooden balls
+D:with metal spikes on the end.
+
+N:53:& Mace~
+G:\:D
+I:21:5:0
+W:5:0:120:130
+A:5/1
+P:0:2d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This weapon is a club ending in a sphere. The sphere is studded
+D:with metal shards, and thus can both crush and cut your adversary.
+
+N:54:& Quarterstaff~
+G:\:U
+I:21:3:0
+W:10:0:150:200
+A:10/1
+P:0:1d9:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A long, wooden pole, usually the height of the wielder. Four of them can be
+D:made out of the trunk of one young tree, hence the name. The quarterstaff
+D:is an excellent weapon for travellers as it doubles both as a walking staff
+D:and as a deterrent against brigands. The quarterstaff is used more in
+D:fencing and brawling than melee combat.
+
+N:55:& War Hammer~
+G:\:D8
+I:21:8:0
+W:5:0:120:225
+A:5/1
+P:0:3d3:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A large hammer, designed to crush skulls with mighty strikes.
+
+N:56:& Lead-Filled Mace~
+G:\:D
+I:21:15:0
+W:15:0:180:502
+A:15/1
+P:0:3d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A large, mean mace filled with lead in order to wreak a maximum of havoc.
+
+N:57:& Mace~ of Disruption
+G:\:v
+I:21:20:0
+W:80:0:400:4300
+A:80/5
+P:0:5d8:0:0:0
+F:SLAY_UNDEAD | SHOW_MODS | MUST2H
+f:MUST2H | SLAY_UNDEAD
+D:This mace is custom-made for priests that go out to destroy evil.
+D:It is deadly, especially for undead.
+
+N:58:& Lucerne Hammer~
+G:\:B
+I:21:10:0
+W:10:0:120:376
+A:10/1
+P:0:2d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A war hammer combined with a spearpoint, mounted on a long pole.
+
+##### Polearms #####
+
+N:59:& Beaked Axe~
+G:/:s
+I:22:10:0
+W:15:0:180:408
+A:15/1
+P:0:2d6:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This polearm has a beak mounted opposite the blade.
+
+N:60:& Glaive~
+G:/:s
+I:22:13:0
+W:20:0:190:363
+A:20/1
+P:0:2d6:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A polearm with a long, slightly curved knife-like blade. It has spurs on
+D:the dull side of the blade. It's primarily a slashing and chopping weapon. Glaives
+D:are often used to protect archers, crossbowmen, and gunners while they reload.
+D:Outside of combat they are a popular processional weapon and therefore many
+D:have ornately carved blades.
+
+N:61:& Halberd~
+G:/:s
+I:22:15:0
+W:25:0:190:430
+A:25/1
+P:0:3d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:The halberd has a broad, short axe blade on a 5-6 ft long haft, with a
+D:spearpoint at the top, often a back-spike and occasionally a butt-spike. Used to
+D:combat heavier armour. It's usually used for cutting and stabbing. It's the most
+D:versatile polearm in Middle-earth. The axe is used in general melee. The top
+D:pike is used to pierce armour, or is set against a cavalry charge. The back
+D:hook could unseat horses, trip opponents, parry a blow, or be a general
+D:piercing weapon.
+
+N:62:& Awl-Pike~
+G:/:s
+I:22:4:0
+W:10:0:160:340
+A:10/1
+P:0:1d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This is a polearm with a long square-sectioned spike on the end.
+
+N:63:& Pike~
+G:/:s
+I:22:8:0
+W:15:0:160:358
+A:15/1
+P:0:2d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A staff, 16-18 feet long, that has a small piercing head about 10 inches
+D:long. The pike is often used by infantry to fend off cavalry. It is very
+D:effective against mounted troops.
+
+N:64:& Spear~
+G:/:s
+I:22:2:0
+W:5:0:50:36
+A:5/1
+P:0:1d6:0:0:0
+F:SHOW_MODS
+D:Spears tend to have a strong, wide, leaf-shaped head with a ridge down the
+D:middle. The spearhead is attached to the wooden shaft by a socket. The
+D:sockets are usually riveted to the shaft and some have two small lugs near
+D:the base of the socket to allow the head to be possibly bound on as well.
+D:This spear is 7 feet long.
+
+N:65:& Trident~
+G:/:y
+I:22:5:0
+W:5:0:70:120
+A:5/1
+P:0:1d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:The trident is based on the pitchfork. In fact, when not used as a weapon,
+D:it is often employed as a pitchfork. It is famous for its uses in
+D:gladiatorial arenas. It is used much like a spear and could even be thrown
+D:like one in desperate situations.
+
+N:66:& Lance~
+G:/:s
+I:22:20:0
+W:10:0:300:230
+A:10/1
+P:0:2d8:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This is the original polearm. It is shaped like a spear but is bigger. It's
+D:meant to fend off enemies, not to be thrown.
+
+N:67:& Great Axe~
+G:/:s
+I:24:25:0
+W:40:0:230:500
+A:40/1
+P:0:4d4:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:A huge and heavy two-headed axe.
+
+N:68:& Battle Axe~
+G:/:s
+I:22:22:0
+W:15:0:170:334
+A:15/1
+P:0:2d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:Nordic polearm with a broad blade and a hook mounted on the end of the shaft.
+D:The Nordics' take on the halberd. The polearm of choice for many Nordics,
+D:ideally suited for slashing, thrusting, and unseating cavalry.
+
+N:69:& Lochaber Axe~
+G:/:D
+I:22:28:0
+W:45:0:250:750
+A:45/1
+P:0:3d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:Nordic polearm with a broad blade and a hook mounted on the end of the shaft.
+D:Another Nordic version of the halberd. The polearm of choice for many Nordics,
+D:this weapon is ideally suited for slashing, thrusting, and unseating cavalry.
+
+N:70:& Broad Axe~
+G:/:s
+I:24:11:0
+W:15:0:160:304
+A:15/1
+P:0:2d6:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A one-headed axe made for combat, with an elongated moon-shaped blade.
+
+N:71:& Scythe~
+G:/:s
+I:22:17:0
+W:45:0:250:800
+A:45/1
+P:0:5d3:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A simple farm implement, converted into a weapon by slightly straightening
+D:its blade and putting it in line with its pole, instead of the typical
+D:right angle.
+
+N:72:& Scythe~ of Slicing
+G:/:r
+I:22:30:0
+W:80:0:250:10000
+A:80/20
+P:0:8d4:0:0:0
+F:SHOW_MODS | MUST2H | WOUNDING | VORPAL
+f:MUST2H | VORPAL | WOUNDING
+D:The simple design of the war scythe, but this one uses a finely crafted and
+D:incredibly sharp steel blade which causes terrible wounds when it hits.
+
+##### Bows, Crossbows, Slings #####
+
+N:73:& Short Bow~
+G:}:U
+I:19:12:0
+W:3:0:30:50
+A:3/1:50/2
+F:SHOW_MODS
+D:A piece of bent wood, fitted with a string. Easy to transport and use, but
+D:its effect is not very impressive. You can 'f'ire it after you 'w'ield it.
+
+N:74:& Long Bow~
+G:}:U
+I:19:13:0
+W:10:0:40:120
+A:10/1:70/2
+F:SHOW_MODS
+D:A bow almost as long as a human. It takes considerable strength and skill to
+D:use and is rather awkward to carry around inside buildings. Nevertheless, it
+D:shoots arrows with astonishing force. You can 'f'ire it after you 'w'ield it.
+
+N:75:& Light Crossbow~
+G:}:s
+I:19:23:0
+W:15:0:110:140
+A:15/1:60/2
+F:SHOW_MODS
+D:A metal bow mounted on a wooden stock. It is used for shooting bolts. This
+D:design is relatively light and not too difficult to cock, but also shoots its
+D:quarrels with less force. You can 'f'ire with it after you 'w'ield it.
+
+N:76:& Heavy Crossbow~
+G:}:s
+I:19:24:0
+W:30:0:200:300
+A:30/1:80/2
+F:SHOW_MODS
+D:A metal bow mounted on a wooden stock, with attached cocking mechanism. It
+D:takes considerable time and strength to cock it and it's rather heavy.
+D:However, it hurls its ammunition with incredible force. You can 'f'ire with
+D:it after you 'w'ield it.
+
+N:77:& Sling~
+G:}:u
+I:19:2:0
+W:1:0:5:5
+A:1/1:40/2
+F:SHOW_MODS
+D:A simple cloth or leather pouch with two strings attached. It is used to hurl
+D:pebbles or iron shots. You can 'f'ire with it after you 'w'ield it.
+
+##### Missiles #####
+
+N:78:& Arrow~
+G:{:U
+I:17:1:0
+W:3:0:2:1
+A:3/1:15/1:50/1
+P:0:1d4:0:0:0
+F:SHOW_MODS
+D:A simple metal head on a piece of wood or bamboo, fitted with some feathers.
+D:You can use it for 'f'iring a bow.
+
+N:79:& Seeker Arrow~
+G:{:G
+I:17:2:0
+W:55:0:2:20
+A:55/2:80/2
+P:0:4d4:0:0:0
+F:SHOW_MODS
+D:A precision-made arrow, which allows you to hit precisely the most vulnerable
+D:place of an opponent. You can use it for 'f'iring a bow.
+
+N:80:& Bolt~
+G:{:s
+I:18:1:0
+W:3:0:3:2
+A:3/1:25/1:60/1
+P:0:1d5:0:0:0
+F:SHOW_MODS
+D:Short metal arrows, to be fired with crossbows. You can use it for 'f'iring a
+D:crossbow.
+
+N:81:& Seeker Bolt~
+G:{:B
+I:18:2:0
+W:65:0:3:25
+A:65/2:90/2
+P:0:4d5:0:0:0
+F:SHOW_MODS
+D:A precision-made bolt, which allows you to hit exactly the most vulnerable
+D:place of an opponent. You can use it for 'f'iring a crossbow.
+
+N:82:& Rounded Pebble~
+G:{:s
+I:16:0:0
+W:0:0:4:1
+A:0/1:10/2
+P:0:1d2:0:0:0
+F:SHOW_MODS
+D:Small round stones. When fired with a sling, they could even hurt a giant.
+D:You can use them for 'f'iring a sling.
+
+N:83:& Iron Shot~
+G:{:s
+I:16:1:0
+W:3:0:5:2
+A:3/1:40/2
+P:0:1d4:0:0:0
+F:SHOW_MODS
+D:Metal balls, made for shooting with slings. You can use them for 'f'iring a
+D:sling.
+
+##### Shovels and Picks #####
+
+N:84:& Shovel~
+G:\:s
+I:20:1:1
+W:1:0:60:10
+A:5/2
+P:0:1d2:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:A simple digging tool for shovelling away rubble and maybe even soft rock.
+
+N:85:& Gnomish Shovel~
+G:\:G
+I:20:2:2
+W:20:0:60:100
+A:20/3
+P:0:1d2:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:Crafted by the gnomes, its design profits greatly from the gnomes' expertise
+D:honed in the burrowing of their hovels.
+
+N:86:& Dwarven Shovel~
+G:\:B
+I:20:3:3
+W:40:0:120:200
+A:40/4
+P:0:1d3:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:The lighter digging tool used by dwarves to remove debris, but also good
+D:enough to clear away bits of rock when no pick is easily available.
+
+N:87:& Pick~
+G:\:s
+I:20:4:1
+W:5:0:150:50
+A:10/2
+P:0:1d3:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:A heavy digging tool, primarily for earthworking, but also good for tunnelling
+D:through stone, if one is willing to perform the time-consuming labour.
+
+N:88:& Orcish Pick~
+G:\:g
+I:20:5:2
+W:30:0:180:300
+A:30/3
+P:0:1d3:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:Although orcs tend to dig rather untidy mines and overcome difficulties in
+D:this work less by skill than mere stubbornness, they have amassed
+D:quite some expertise in mining, which has gone into this digging tool.
+
+N:89:& Dwarven Pick~
+G:\:b
+I:20:6:3
+W:50:0:200:600
+A:50/4
+P:0:1d4:0:0:0
+F:TUNNEL
+f:TUNNEL
+D:The dwarves, miners of legend, have made this pick, which is so expertly
+D:crafted that even weaklings can bore through solid rock with it.
+
+##### Armour #####
+
+N:90:& Elven Cloak~
+G:(:G
+I:35:2:0
+W:30:0:5:1500
+A:30/4
+P:4:0d0:0:0:4
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_FIRE | IGNORE_ELEC
+F:STEALTH | SEARCH | LUCK
+f:STEALTH
+D:A wonderfully light cloak coloured in brown and green hues. Its colouring
+D:greatly helps the wearer to avoid undesired attention. Wearing it makes you
+D:feel lucky and somehow you seem to see what was meant to stay unseen.
+
+N:91:& Pair~ of Soft Leather Boots
+G:]:U
+I:30:2:0
+W:3:0:20:7
+A:3/1
+P:2:1d1:0:0:0
+D:A pair of low boots, comfortable to wear.
+
+N:92:& Pair~ of Hard Leather Boots
+G:]:U
+I:30:3:0
+W:5:0:40:12
+A:5/1
+P:3:1d1:0:0:0
+D:A pair of boots, with hardened leather at the caps, offering a little
+D:extra protection for the feet.
+
+N:93:& Pair~ of Metal Shod Boots
+G:]:s
+I:30:6:0
+W:20:0:80:50
+A:20/1
+P:6:1d1:0:0:0
+D:Heavy boots, with metal strips at the toes, heels and other vulnerable parts,
+D:to better protect the wearer's feet from harm.
+
+N:94:& Hard Leather Cap~
+G:]:u
+I:32:2:0
+W:3:0:15:12
+A:3/1
+P:2:0d0:0:0:0
+D:A piece of protective headgear made from hardened leather, just covering the
+D:skull.
+
+N:95:& Metal Cap~
+G:]:s
+I:32:3:0
+W:10:0:20:30
+A:10/1
+P:3:1d1:0:0:0
+D:A metal skullcap with nose and cheekguards.
+
+N:96:& Iron Helm~
+G:]:s
+I:32:5:0
+W:20:0:75:75
+A:20/1
+P:5:1d3:0:0:0
+D:A large helmet that can protect the entire head. Ventilation and bad vision
+D:can be a problem, however.
+
+N:97:& Steel Helm~
+G:]:W
+I:32:6:0
+W:40:0:60:200
+A:40/1
+P:6:1d3:0:0:0
+D:A helmet which protects the entire head. The expensive steel as base material
+D:allows it to offer very good protection while being fairly light.
+
+N:98:& Iron Crown~
+G:]:s
+I:33:10:0
+W:45:0:20:500
+A:45/1
+P:0:1d1:0:0:0
+D:An iron circlet which might be worn, but which is purely ornamental unless it
+D:has special powers.
+
+N:99:& Golden Crown~
+G:]:y
+I:33:11:0
+W:45:0:30:1000
+A:45/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID
+D:A gilded crown, which just looks good. Sometimes such headgear also has
+D:additional properties which might make it worth wearing.
+
+N:100:& Jewel Encrusted Crown~
+G:]:v
+I:33:12:0
+W:50:0:40:2000
+A:50/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID
+D:A gorgeous-looking silver crown, adorned with several gems. You might wear it
+D:on your head, if you really think you're worthy.
+
+N:101:& Robe~
+G:(:b
+I:36:2:0
+W:1:0:20:4
+A:1/1:50/1
+P:2:0d0:0:0:0
+D:A full-length garment which can be worn on the body. It is not really
+D:armour, but mages often wear them as they are very light and don't hinder
+D:movement much.
+
+N:102:& Filthy Rag~
+G:(:D
+I:36:1:0
+W:0:0:20:1
+A:0/1
+P:1:0d0:0:0:-1
+D:A piece of discarded cloth, smelly and dirty. Probably worthless.
+
+N:103:& Soft Leather Armour~
+G:(:U
+I:36:4:0
+W:3:0:80:18
+A:3/1
+P:4:0d0:0:0:0
+D:A suit of soft armour, light and unencumbering, but not very protective.
+
+N:104:& Soft Studded Leather~
+G:(:U
+I:36:5:0
+W:3:0:90:35
+A:3/1
+P:5:1d1:0:0:0
+D:A leather jerkin with metal studs in critical places offering slightly better
+D:protection.
+
+N:105:& Hard Leather Armour~
+G:(:U
+I:36:6:0
+W:5:0:100:150
+A:5/1
+P:6:1d1:-1:0:0
+D:A leather armour covering only the body. It is made of hardened leather to
+D:make it harder to penetrate. It's also a bit harder to move in, as it is
+D:rather stiff.
+
+N:106:& Hard Studded Leather~
+G:(:U
+I:36:7:0
+W:10:0:110:200
+A:10/1
+P:7:1d2:-1:0:0
+D:A suit of hardened leather armour, reinforced with metal studs.
+
+N:107:& Leather Scale Mail~
+G:(:U
+I:36:11:0
+W:15:0:140:450
+A:15/1
+P:11:1d1:-1:0:0
+D:A suit of armour made of overlapping hardened leather scales. It offers good
+D:protection while still being rather lightweight.
+
+N:108:& Metal Scale Mail~
+G:[:s
+I:37:3:0
+W:25:0:250:550
+A:25/1
+P:13:1d4:-2:0:0
+D:A suit of overlapping metal scales, sewn onto a leather or cloth jerkin.
+
+N:109:& Chain Mail~
+G:[:s
+I:37:4:0
+W:25:0:220:750
+A:25/1
+P:14:1d4:-2:0:0
+D:A suit of interlinked metal rings, to be worn over a woollen garment.
+
+N:110:& Rusty Chain Mail~
+G:[:r
+I:37:1:0
+W:25:0:200:550
+A:25/1
+P:14:1d4:-5:0:-8
+D:This chain mail has rusted beyond repair. It can still be worn, but some of
+D:the rings have gone missing and the rust has made the suit inflexible.
+D:Consequently, it offers very poor protection and is cumbersome to move in.
+
+N:111:& Augmented Chain Mail~
+G:[:s
+I:37:6:0
+W:30:0:270:900
+A:30/1
+P:16:1d4:-2:0:0
+D:A suit of interlinked metal rings, with additional metal plates or scales
+D:covering vulnerable parts of the wearer.
+
+N:112:& Bar Chain Mail~
+G:[:s
+I:37:8:0
+W:35:0:280:950
+A:35/1
+P:18:1d4:-2:0:0
+D:A suit of interlinked metal rings, with additional short metal bars added in
+D:many places to prevent penetration of the armour by piercing attacks.
+
+N:113:& Metal Brigandine Armour~
+G:[:s
+I:37:9:0
+W:35:0:290:1100
+A:35/1
+P:19:1d4:-3:0:0
+D:This is a leather armour with many small metal plates fixed to it, covering
+D:it entirely.
+
+N:114:& Partial Plate Armour~
+G:[:W
+I:37:12:0
+W:45:0:260:1200
+A:45/1
+P:22:1d6:-3:0:0
+D:An armour made of steel plates, covering only the body of the wearer.
+
+N:115:& Metal Lamellar Armour~
+G:[:W
+I:37:13:0
+W:45:0:340:1250
+A:45/1
+P:23:1d6:-3:0:0
+D:Lamellar consists of small rectangular plates (lames) attached to each other
+D:at each edge or corner with leather lacings through small holes in the plates.
+
+N:116:& Full Plate Armour~
+G:[:W
+I:37:15:0
+W:45:0:380:1350
+A:45/1
+P:25:2d4:-3:0:0
+D:A suit of armour made of metal plates, covering the body, arms and upper legs.
+D:A very effective but very heavy armour.
+
+N:117:& Ribbed Plate Armour~
+G:[:W
+I:37:18:0
+W:50:0:380:1500
+A:50/1
+P:28:2d4:-3:0:0
+D:This full suit of armour has been strengthened in places to better deflect or
+D:absorb blows.
+
+N:118:& Galvorn Plate Mail~
+G:[:g
+I:37:30:0
+W:75:0:420:20000
+A:75/4
+P:40:2d4:-4:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+D:A suit of plate armour fashioned from a metal whose secret is only known to Eol,
+D:the dark Elvensmith. It is practically unbreakable.
+
+N:119:& Mithril Plate Mail~
+G:[:B
+I:37:25:0
+W:60:0:300:15000
+A:60/3
+P:35:2d4:-3:0:0
+F:IGNORE_ACID
+D:A full suit of plate armour, fashioned from the rare true-silver. Only the
+D:dwarves know the secret of making armour or weapons of this metal.
+
+N:120:& Mithril Chain Mail~
+G:[:B
+I:37:20:0
+W:55:0:150:7000
+A:55/3
+P:28:1d4:-1:0:0
+F:IGNORE_ACID
+D:A suit of chain mail, made by dwarven smiths from the rare and precious metal
+D:also called true-silver.
+
+N:121:& Double Chain Mail~
+G:[:s
+I:37:7:0
+W:30:0:250:850
+A:30/1
+P:16:1d4:-2:0:0
+D:A suit of chain mail, with an additional layer of mail in some places.
+
+# This shield does not belong here
+
+N:122:& Shield~ of Deflection
+G:[:B
+I:34:10:0
+W:70:0:100:10000
+A:70/3
+P:10:1d1:0:0:10
+F:IGNORE_ACID
+D:A large shield fashioned from a metal alloy that is not subject to corrosion.
+D:It was especially crafted to better deflect attacks.
+
+### The Cloaks ###
+
+N:123:& Cloak~
+G:(:g
+I:35:1:0
+W:1:0:10:3
+A:1/1:20/1
+P:1:0d0:0:0:0
+D:A cloth coat typically worn as a loose outer garment. It is spacious enough
+D:to be worn even over bulky metal armour.
+
+N:124:& Shadow Cloak~
+G:(:D
+I:35:6:1
+W:60:0:5:7500
+A:75/4
+P:6:0d0:0:0:4
+F:RES_DARK | RES_LITE | STEALTH
+f:STEALTH
+D:A rare cloak imbued with magic to radiate a strange twilight, absorbing both
+D:extreme brightness and darkness.
+
+### The Gloves ###
+
+N:125:& Set~ of Leather Gloves
+G:]:U
+I:31:1:0
+W:1:0:5:3
+A:1/1
+P:1:0d0:0:0:0
+D:Light gloves which do not seriously hinder finger movements, while still
+D:protecting the hands somewhat.
+
+N:126:& Set~ of Gauntlets
+G:]:U
+I:31:2:0
+W:10:0:25:35
+A:10/1
+P:2:1d1:0:0:0
+D:Metal gloves protecting the hands up to the middle of the lower arm.
+
+N:127:& Set~ of Cesti
+G:]:W
+I:31:5:0
+W:50:0:40:100
+A:50/1
+P:5:1d1:0:0:0
+D:A set of metal gloves with nasty spikes and barbs. Though originally made to
+D:help in combat, the additional metal on the backs of the hands also offers a
+D:lot more protection.
+
+### The shields ###
+
+N:128:& Small Leather Shield~
+G:):U
+I:34:2:0
+W:3:0:50:30
+A:3/1
+P:2:1d1:0:0:0
+D:A small disc of lindenwood, with a leather covering on one side.
+
+N:129:& Large Leather Shield~
+G:):U
+I:34:4:0
+W:15:0:100:120
+A:15/1
+P:4:1d2:0:0:0
+D:A large oval or rectangular shield. It is made of wood, typically linden, and
+D:covered with a layer of hardened leather to offer better protection.
+
+N:130:& Small Metal Shield~
+G:):s
+I:34:3:0
+W:10:0:65:50
+A:10/1
+P:3:1d2:0:0:0
+D:A small shield strengthened with a layer of metal.
+
+N:131:& Large Metal Shield~
+G:):s
+I:34:5:0
+W:30:0:120:200
+A:30/1
+P:5:1d3:0:0:0
+D:A large piece of wood, rectangular or oval in shape, and covered with metal
+D:to strengthen it. It's to be worn strapped to the arm not occupied by the
+D:weapon when fighting.
+
+##### Rings #####
+
+N:132:Strength
+G:=:d
+I:45:24:0
+W:30:0:2:500
+A:30/1
+F:STR | HIDE_TYPE | SUST_STR
+f:STR
+D:This bauble magically improves your strength.
+
+N:133:Dexterity
+G:=:d
+I:45:26:0
+W:30:0:2:500
+A:30/1
+F:DEX | HIDE_TYPE | SUST_DEX
+f:DEX
+D:This piece of jewellery magically improves your agility.
+
+N:134:Constitution
+G:=:d
+I:45:27:0
+W:30:0:2:500
+A:30/1
+F:CON | HIDE_TYPE | SUST_CON
+f:CON
+D:This ring magically grants you health, improving your constitution.
+
+N:135:Intelligence
+G:=:d
+I:45:25:0
+W:30:0:2:500
+A:30/1
+F:INT | HIDE_TYPE | SUST_INT
+f:INT
+D:This magical piece of jewellery makes you smarter.
+
+N:136:Speed
+G:=:d
+I:45:31:0
+W:75:0:2:100000
+A:75/1
+F:SPEED | HIDE_TYPE
+f:SPEED
+D:This wonderful ring grants you additional energy, allowing you to act faster.
+
+N:137:Searching
+G:=:d
+I:45:23:0
+W:5:0:2:250
+A:5/1
+F:SEARCH | HIDE_TYPE
+f:SEARCH
+D:This ring magically improves your attention, so you can detect hidden things better.
+
+# New : It can be activated but at the cost of its destruction
+N:138:Teleportation
+G:=:d
+I:45:4:0
+W:5:0:2:250
+A:5/1
+a:HARDCORE=DEST_TELE
+F:CURSED | TELEPORT | EASY_KNOW | ACTIVATE
+f:TELEPORT
+D:This ring will uncontrollably send you to different places at its whim.
+D:You can use its power once at your will, but it will destroy the ring.
+
+N:139:Slow Digestion
+G:=:d
+I:45:6:0
+W:5:0:2:250
+A:5/1
+F:SLOW_DIGEST | EASY_KNOW
+f:SLOW_DIGEST
+D:This magical bauble grants you some sustenance, allowing you to subsist on less food.
+
+N:142:Levitation
+G:=:d
+I:45:7:0
+W:5:0:2:200
+A:5/1
+F:FEATHER | EASY_KNOW
+f:FEATHER
+D:When you put on this ring, you will be able to float just above the floor.
+D:It prevents you from drowning, and all your falls will be painless.
+
+N:143:Poison Resistance
+G:=:d
+I:45:20:0
+W:60:0:2:16000
+A:60/2
+F:RES_POIS | EASY_KNOW
+f:RES_POIS
+D:This magical ring grants protection from poison.
+D:It is rumoured that in deep dungeons monsters can kill you at once if you
+D:don't have poison resistance.
+
+N:144:Free Action
+G:=:d
+I:45:21:0
+W:20:0:2:1500
+A:20/1
+F:FREE_ACT | EASY_KNOW
+f:FREE_ACT
+D:This magical bauble prevents you from being held.
+D:Some monsters will paralyse you and then kill you if you lack free action.
+
+N:145:Weakness
+G:=:d
+I:45:2:-5
+W:5:0:2:0
+A:5/1
+F:CURSED | STR | HIDE_TYPE
+f:STR
+D:This accursed ring will sap your strength, rendering you much weaker as long as you wear it.
+
+N:146:Flames
+G:=:d
+I:45:18:0
+W:50:0:2:3000
+A:50/1
+P:0:0d0:0:0:15
+a:HARDCORE=BA_FIRE_4
+F:RES_FIRE | ACTIVATE
+f:RES_FIRE | IGNORE_FIRE
+D:This fiery circlet grants you protection, makes fire less dangerous and even
+D:allows you to call forth a ball of flame.
+
+N:147:Acid
+G:=:d
+I:45:17:0
+W:50:0:2:3000
+A:50/1
+P:0:0d0:0:0:15
+a:HARDCORE=BA_ACID_4
+F:RES_ACID | ACTIVATE
+f:RES_ACID | IGNORE_ACID
+D:This magical ring is imbued with spells of devouring acid, granting protection against such
+D:assaults and the ability to shoot acid at your foes.
+
+N:148:Ice
+G:=:d
+I:45:19:0
+W:50:0:2:3000
+A:50/1
+a:HARDCORE=BA_COLD_4
+P:0:0d0:0:0:15
+F:RES_COLD | ACTIVATE
+f:RES_COLD | IGNORE_COLD
+D:This ring is imbued with supernatural cold, which makes you less vulnerable to such effects
+D:and occasionally allows you to throw balls of ice at your foes.
+
+N:149:Woe
+G:=:d
+I:45:0:-5
+W:50:0:2:0
+A:50/1
+F:CURSED | TELEPORT | WIS | CHR | HIDE_TYPE | AUTO_CURSE
+D:This accursed ring will turn you into a bumbling fool and, in addition, magically
+D:transports you to places you never wanted to see. It can recurse itself if
+D:you leave it on too long.
+
+N:150:Stupidity
+G:=:d
+I:45:3:-5
+W:5:0:2:0
+A:5/1
+F:CURSED | INT | HIDE_TYPE
+f:INT
+D:This wicked ring feeds off your intellect, magically making you stupid.
+
+N:151:Damage
+G:=:d
+I:45:29:0
+W:20:0:2:500
+A:20/1
+F:HIDE_TYPE
+D:This ring makes your hands magically strong in combat, allowing you to inflict
+D:greater pain with your hand-to-hand attacks.
+
+N:152:Accuracy
+G:=:d
+I:45:28:0
+W:20:0:2:500
+A:20/1
+F:HIDE_TYPE | EASY_USE | ACTIVATE |
+a:HARDCORE=WHIRLWIND
+D:This ring magically improves your control in combat, allowing you to hit more often.
+D:It can also sometimes be used to hit several nearby opponents with deadly accuracy.
+
+N:153:Protection
+G:=:d
+I:45:16:0
+W:10:0:2:500
+A:10/1
+D:This ring creates a magical aura around you, protecting you against the blows of your enemies.
+
+N:154:Aggravate Monster
+G:=:d
+I:45:1:0
+W:5:0:2:0
+A:5/1
+F:CURSED | AGGRAVATE | EASY_KNOW | AUTO_CURSE
+f:AGGRAVATE
+D:This faithless ring will draw opponents' attention towards its hapless owner.
+D:If you have any pets, it will also make them turn against you.
+
+N:155:See Invisible
+G:=:d
+I:45:22:0
+W:30:0:2:340
+A:30/1
+F:SEE_INVIS | EASY_KNOW
+f:SEE_INVIS
+D:This magical piece of jewellery allows your eyes to perceive beings otherwise unseen.
+
+N:162:Slaying
+G:=:d
+I:45:30:0
+W:40:0:2:1000
+A:40/1
+F:SHOW_MODS
+D:This ring magically improves your fighting prowess, allowing to hit more often and harder.
+
+##### Amulets #####
+
+N:163:Brilliance
+G:":d
+I:40:6:0
+W:50:0:3:1000
+A:50/4
+F:INT | WIS | HIDE_TYPE | LITE1
+D:This talisman grants a sharper wit, greater insight and brightness to light dark places.
+
+N:164:Charisma
+G:":d
+I:40:7:0
+W:30:0:3:500
+A:30/1
+F:CHR | HIDE_TYPE
+f:CHR
+D:This amulet grants beauty beyond mere looks.
+
+N:165:Searching
+G:":d
+I:40:5:0
+W:15:0:3:600
+A:15/1
+F:SEARCH | HIDE_TYPE
+f:SEARCH
+D:This amulet grants keen sight, finding things that are hidden.
+
+N:166:Teleportation
+G:":d
+I:40:1:0
+W:10:0:3:250
+A:10/1
+F:CURSED | TELEPORT | EASY_KNOW
+f:TELEPORT
+D:This amulet nastily throws you all over the place.
+
+# Replacing Adornment with Protection from Evil from T-Plus by Ingeborg S. Norden
+
+N:169:Protection from Evil
+G:":d
+I:40:2:0
+W:25:0:3:10000
+A:25/1
+F:EASY_KNOW | ACTIVATE | BLESSED | ESP_EVIL
+a:HARDCORE=PROT_EVIL
+D:This blessed amulet fends off evil beings and warns the wearer
+D:of their presence.
+
+##### Extra armour #####
+
+N:170:& Double Ring Mail~
+G:[:s
+I:37:5:0
+W:25:0:230:700
+A:25/1
+P:15:1d4:-2:0:0
+D:A suit of leather armour with metal rings sewn onto it. In addition, in important parts it is
+D:reinforced with mail.
+
+##### Additional amulets #####
+
+N:171:the Magi
+G:":d
+I:40:8:0
+W:70:0:3:30000
+A:70/8
+P:0:0d0:-4:-4:0
+F:INT | SUST_INT | SEARCH | SPELL_CONTAIN | WIELD_CAST
+F:FREE_ACT | RES_BLIND | RES_CONF |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This rare amulet is highly desirable for mages, as it makes its wearer smarter, more attentive
+D:and impervious to magics which would make their own magic-use impossible.
+
+N:172:Doom
+G:":d
+I:40:0:-5
+W:50:0:3:0
+A:50/1
+F:CURSED | STR | INT | WIS | DEX | CON | CHR | HIDE_TYPE
+F:AUTO_CURSE | CURSE_NO_DROP
+D:This wicked amulet will drain all your abilities, turning you into a mere shadow of yourself. It
+D:is exceedingly hard to get rid of.
+
+##### Scrolls #####
+
+N:173:Enchant Weapon To-Hit
+G:?:d
+I:70:17:0
+W:15:0:5:125
+A:15/1
+D:This magical scroll will allow you to improve the accuracy of a weapon in your possession.
+D:However, weapons which are already very highly enchanted are more difficult to improve
+D:further.
+
+N:174:Enchant Weapon To-Dam
+G:?:d
+I:70:18:0
+W:15:0:5:125
+A:15/1
+D:Upon reading this scroll, a magical enchantment will be placed on a weapon in your
+D:possession, increasing the pain it inflicts when hitting. On very highly enchanted weapons this
+D:enchantment may fail, wasting the scroll.
+
+N:175:Enchant Armour
+G:?:d
+I:70:16:0
+W:15:0:5:125
+A:15/1
+D:This scroll will try to enchant a piece of armour in your possession, making it more effective
+D:in protecting you. Highly enchanted armour is likely not to accept this enchantment, however.
+
+N:176:Identify
+G:?:d
+I:70:12:0
+W:1:0:5:50
+A:1/1:5/1:10/1:30/1
+D:If you read this scroll, the identity of an item you specify will be laid open to you.
+
+N:177:*Identify*
+G:?:d
+I:70:13:0
+W:30:0:5:1000
+A:30/1:50/2:80/1:100/1
+D:This scroll will allow you to gain insight into an object's special properties.
+D:Only the highly magical objects, like rare rings and amulets or very unusual weapons
+D:and armour possess abilities which warrant the use of this magic.
+
+N:178:Rumour
+G:?:d
+I:70:51:0
+W:1:0:5:10
+A:1/1
+D:A piece of paper inscribed with a little text. You may meditate over it or ignore it at your
+D:leisure.
+
+N:179:Chaos
+G:?:d
+I:70:50:0
+W:100:0:5:10000
+A:100/8
+F:IGNORE_FIRE | IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC
+D:A piece of paper inscribed with strange shifting runes. Upon reading them, they will release
+D:a blast of chaotic forces.
+
+N:180:Remove Curse
+G:?:d
+I:70:14:0
+W:10:0:5:100
+A:10/1:20/2:40/2
+D:A scroll inscribed with a beneficial formula. Upon reading it, evil magics will be removed
+D:from your possessions.
+
+N:181:Light
+G:?:d
+I:70:24:0
+W:0:0:5:15
+A:0/1:3/1:10/1
+D:A scroll which will create a permanent magical light, illuminating your surroundings.
+
+N:182:Fire
+G:?:d
+I:70:48:0
+W:50:0:5:1000
+A:50/4
+F:IGNORE_FIRE
+D:A piece of paper inscribed with runes glowing brightly red. Upon reading them, a large blast
+D:of fire will be released.
+
+N:183:Ice
+G:?:d
+I:70:49:0
+W:75:0:5:5000
+A:75/6
+F:IGNORE_COLD
+D:A piece of paper inscribed with light-blue runes that radiate a strange cold. Upon reading them,
+D:a large icy blast will be released.
+
+N:184:Summon Monsters
+G:?:d
+I:70:4:0
+W:1:0:5:0
+A:1/1
+D:This scroll was made by mischievous sorcerers. If it is read, a few creatures will appear to fight
+D:you.
+
+N:185:Phase Door
+G:?:d
+I:70:8:0
+W:1:0:5:15
+A:1/1
+D:Upon reading this scroll, you will be translocated over a short distance.
+
+N:186:Teleportation
+G:?:d
+I:70:9:0
+W:10:0:5:40
+A:10/1
+D:If you read this scroll, you will immediately be transported to another place on the level.
+
+N:187:Teleport Level
+G:?:d
+I:70:10:0
+W:20:0:5:50
+A:20/1
+D:This scroll will magically transport you to the level directly above or below, when read.
+
+N:188:Monster Confusion
+G:?:d
+I:70:36:0
+W:5:0:5:30
+A:5/1
+D:Reading this scroll will cause your hands to glow with a strange mesmerising light that will
+D:attempt to confuse the next creature you hit with a hand or weapon attack.
+
+N:189:Magic Mapping
+G:?:d
+I:70:25:0
+W:5:0:5:40
+A:5/1
+D:Reading this scroll will reveal the layout of your immediate surroundings to you.
+
+N:190:Rune of Protection
+G:?:d
+I:70:38:0
+W:50:0:5:500
+A:50/2:90/4
+D:This scroll is inscribed with a powerful protective incantation. When read, this will erect a
+D:strong magical ward around the location you currently stand on. Be aware that this magic is
+D:easily disturbed by already present structures and thus cannot work where an object is lying, or
+D:on a trap.
+
+N:191:*Remove Curse*
+G:?:d
+I:70:15:0
+W:50:0:5:8000
+A:50/2:75/2:85/2:95/1
+D:This valuable scroll is inscribed with a powerful blessing capable of dispelling all but the
+D:mightiest curses which may have been laid on your possessions.
+
+N:192:Treasure Detection
+G:?:d
+I:70:26:0
+W:0:0:5:15
+A:0/1
+D:This scroll magically reveals the locations of nearby loose change to you.
+
+N:193:Object Detection
+G:?:d
+I:70:27:0
+W:0:0:5:15
+A:0/1
+D:This scroll shows nearby objects to you. It only makes you aware of items on the floor,
+D:however, not those carried by creatures.
+
+N:194:Trap Detection
+G:?:d
+I:70:28:0
+W:5:0:5:35
+A:5/1:10/1
+D:This scroll is very helpful, because it reveals the locations of nearby snares and traps which you
+D:might otherwise blunder into.
+
+##### Extra ammunition #####
+
+N:195:& Sheaf Arrow~
+G:{:o
+I:17:1:0
+W:10:0:4:3
+A:15/2:50/2
+P:0:1d5:0:0:0
+F:SHOW_MODS
+D:These arrows have bigger arrowheads and bigger feathers.
+D:They also make bigger holes.
+
+N:196:& Mithril Shot~
+G:{:B
+I:16:2:0
+W:40:0:4:20
+A:40/2:65/1
+P:0:3d4:5:5:0
+F:SHOW_MODS | IGNORE_ACID
+D:Sling bullets made from the slags of mithril smelting. They are unusually heavy, hitting
+D:with great force, and are almost imperishable.
+
+##### Additional scrolls #####
+
+N:197:Door/Stair Location
+G:?:d
+I:70:29:0
+W:5:0:5:35
+A:5/1:10/1:15/1
+D:This scroll will reveal nearby doors and stairs.
+
+N:198:Acquirement
+G:?:d
+I:70:46:0
+W:20:0:5:100000
+A:20/8
+D:A great treasure is magically stored within the shimmering runes of this scroll. Reading the
+D:words will release it.
+
+N:199:*Acquirement*
+G:?:d
+I:70:47:0
+W:60:0:5:200000
+A:60/16
+D:Several great treasures have been hidden in a magical compartment. This scroll serves as the
+D:key and will release them when read.
+
+N:200:Mass Genocide
+G:?:d
+I:70:45:0
+W:50:0:5:1000
+A:50/4:100/4
+D:An astoundingly powerful death spell is stored in the runes of this spell. Reading
+D:it will annihilate all nearby creatures. Only a few beings of legendary stature
+D:can withstand it.
+
+N:201:Detect Invisible
+G:?:d
+I:70:30:0
+W:1:0:5:15
+A:1/1
+D:A minor detection spell is stored in this scroll, showing you the locations of otherwise
+D:unseen beings for a brief moment.
+
+N:202:Aggravation
+G:?:d
+I:70:1:0
+W:5:0:5:0
+A:5/1
+D:This nasty scroll will make a loud noise when read, waking up foes in your vicinity.
+
+N:203:Trap Creation
+G:?:d
+I:70:7:0
+W:10:0:5:0
+A:10/1
+D:If you read this rather annoying scroll, snares and pitfalls will magically be planted all around
+D:you, ready to do nasty things to you once you walk onto them.
+
+N:204:Trap/Door Destruction
+G:?:d
+I:70:39:0
+W:10:0:5:50
+A:10/1
+D:A very specifically destructive spell is written on this scroll. It will smash all traps and all
+D:doors immediately next to you.
+
+N:205:Artifact Creation
+G:?:d
+I:70:52:0
+W:70:0:5:200000
+A:70/16
+D:The mighty magic on this scroll will imbue a mundane item you possess with supernatural powers,
+D:also rendering the object indestructible.
+
+N:206:Recharging
+G:?:d
+I:70:22:0
+W:40:0:5:200
+A:40/1
+D:This scroll is inscribed with a spell releasing the enchantments used to give wands and
+D:staves their power, allowing you to replenish their spent charges.
+
+N:207:Genocide
+G:?:d
+I:70:44:0
+W:40:0:5:750
+A:40/4:80/4
+D:This rare and powerful scroll will annihilate all members of a specified race of monsters in
+D:your current location, but this will also exact a price of pain from you.
+
+N:208:Darkness
+G:?:d
+I:70:0:0
+W:1:0:5:0
+A:1/1
+D:This scroll will create a blast of utter darkness, which then fades to leave the immediate
+D:surroundings in a lasting gloom. The extreme darkness can blind those who are not used to
+D:it.
+
+N:209:Protection from Evil
+G:?:d
+I:70:37:0
+W:30:0:5:250
+A:30/1
+D:Upon reading the runes on this piece of paper, a faint aura of holiness will spring into existence
+D:around you, protecting you from blows of evil creatures, unless they are more powerful than you.
+
+N:210:Satisfy Hunger
+G:?:d
+I:70:32:0
+W:5:0:5:10
+A:5/1:20/1:50/1:75/1
+D:Reading this scroll will create a nutritious mass in your stomach, satisfying your hunger.
+
+N:211:Dispel Undead
+G:?:d
+I:70:42:0
+W:40:0:5:200
+A:40/1
+D:A powerful exorcism is inscribed on this scroll. When read it will hurt undead abominations
+D:nearby, possibly even destroying them.
+
+N:212:*Enchant Weapon*
+G:?:d
+I:70:21:0
+W:50:0:5:500
+A:50/1
+D:Reading this scroll will magically infuse a weapon of your choice, making it more effective
+D:in combat. It may not work on weapons that are already powerful or unique.
+
+N:213:Curse Weapon
+G:?:d
+I:70:3:0
+W:50:0:5:0
+A:50/1
+D:This scroll will ruin your weapon beyond repair. Only weapons of legend have a hope of
+D:escaping destruction, but even they will often be shattered.
+
+N:214:*Enchant Armour*
+G:?:d
+I:70:20:0
+W:50:0:5:500
+A:50/1:50/1
+D:This scroll will place a great enchantment on a piece of armour of your choice, making it much
+D:better at protecting you. Mark that improving armours which are already highly enchanted is very
+D:difficult and will often fail.
+
+N:215:Curse Armour
+G:?:d
+I:70:2:0
+W:50:0:5:0
+A:50/1
+D:This scroll bears a curse that will tear your armour to shreds.
+
+N:216:Summon Undead
+G:?:d
+I:70:5:0
+W:15:0:5:0
+A:15/1
+D:These spells scribed by ancient necromancers will call their horrible creatures to haunt you.
+
+N:217:Blessing
+G:?:d
+I:70:33:0
+W:1:0:5:15
+A:1/1
+D:The recitation of this scroll will grant you a blessing of the Valar, making you more confident
+D:in attack and defence for a few moments.
+
+N:218:Holy Chant
+G:?:d
+I:70:34:0
+W:10:0:5:40
+A:10/1
+D:This blessing will give you a holy warrior's prowess in battle for a while.
+
+N:219:Holy Prayer
+G:?:d
+I:70:35:0
+W:25:0:5:80
+A:25/1
+D:This incantation lets you fight as a warrior of Valinor for quite a while, supreme in attack and
+D:defence.
+
+N:220:Word of Recall
+G:?:d
+I:70:11:0
+W:5:0:5:150
+A:5/1
+D:The spell on this scroll will slowly build an ethereal conduit to the surface for you if you are in
+D:a dungeon, and into the dungeon if you are above ground. Upon completion, which takes a while, you
+D:will suddenly be translocated to the other place.
+
+N:221:*Destruction*
+G:?:d
+I:70:41:0
+W:40:0:5:250
+A:40/1
+D:This scroll is inscribed with a mighty conjuration which wrecks the dungeon all around you.
+D:Monsters and objects will be annihilated by this blast; only completely indestructible things can
+D:withstand it.
+
+##### Potions #####
+
+N:222:Slime Mold Juice
+G:!:d
+I:71:2:400
+W:0:0:4:2
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A strange sort of yellowish-green slime, too viscous to even slosh in the bottle.
+
+N:223:Apple Juice
+G:!:d
+I:71:1:250
+W:0:0:4:1
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A healthy fruit beverage.
+
+N:224:Water
+G:!:d
+I:71:0:200
+W:0:0:4:1
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A small bottle filled with pure water.
+
+N:225:Strength
+G:!:d
+I:71:48:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:This beneficial potion will permanently improve your physical strength.
+
+N:226:Weakness
+G:!:d
+I:71:16:0
+W:3:0:4:0
+A:3/1
+P:0:3d12:0:0:0
+F:FOUNTAIN
+D:This nasty potion will sap your strength, making you weaker.
+
+N:227:Restore Strength
+G:!:d
+I:71:42:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical potion will bring back your physical power to its full extent, should it be drained.
+
+N:228:Intelligence
+G:!:d
+I:71:49:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:This beneficial potion will magically enhance your wit, permanently improving your intellect.
+
+N:229:Stupidity
+G:!:d
+I:71:17:0
+W:20:0:4:0
+A:20/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This accursed potion will cloud your intellect, making you stupid.
+
+N:230:Restore Intelligence
+G:!:d
+I:71:43:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This beneficial potion will magically heal your brain, restoring drained intelligence.
+
+N:231:Wisdom
+G:!:d
+I:71:50:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:This potion grants great insight, making you permanently wiser.
+
+N:232:Naivety
+G:!:d
+I:71:18:0
+W:20:0:4:0
+A:20/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion casts a shadow on your knowledge, making you naive.
+
+N:233:Restore Wisdom
+G:!:d
+I:71:44:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion benefits the naive, bringing back their wisdom to what it once was.
+
+N:234:Charisma
+G:!:d
+I:71:53:0
+W:20:0:4:1000
+A:20/1:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion infuses you with permanent beauty and charm.
+
+N:235:Ugliness
+G:!:d
+I:71:21:0
+W:20:0:4:0
+A:20/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This wicked potion slightly twists your features, making you appear less fair.
+
+N:236:Restore Charisma
+G:!:d
+I:71:47:0
+W:20:0:4:300
+A:20/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This useful potion restores drained charm.
+
+N:237:Curing
+G:!:d
+I:71:61:100
+W:18:0:4:250
+A:18/1:40/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This blessed potion helps to recover from a wide variety of ailments.
+
+### Note! Invulnerability decreases your food... ###
+
+N:238:Invulnerability
+G:!:d
+I:71:62:-2500
+W:90:0:4:100000
+A:90/9
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This immensely powerful potion makes your physique almost indestructible for a very short
+D:time. Very rarely, an attempt to hurt you will still succeed, so don't be too confident.
+
+N:239:New Life
+G:!:d
+I:71:63:100
+W:50:0:4:750000
+A:50/20:100/10:120/5
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion fundamentally twists your physical features, as if you were another mother's child.
+D:Your physique will be shaped anew. This may make you more or less hardy in battle.
+
+N:240:Cure Serious Wounds
+G:!:d
+I:71:35:100
+W:3:0:4:40
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This beneficial potion will cure some wounds and other inhibiting ailments.
+
+N:241:Cure Critical Wounds
+G:!:d
+I:71:36:100
+W:5:0:4:100
+A:5/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion will cure a good bit of hurt you have suffered and also allows you to recover
+D:from unhealthy conditions like blood poisoning, confusion or blindness.
+
+N:242:Healing
+G:!:d
+I:71:37:200
+W:15:0:4:300
+A:15/1:30/1:60/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This blessed potion greatly heals you and also cures many other ailments from
+D:which you might suffer.
+
+N:243:Constitution
+G:!:d
+I:71:52:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:This magical concoction greatly improves your health, making you permanently tougher.
+
+N:244:Experience
+G:!:d
+I:71:59:0
+W:65:0:4:25000
+A:65/1
+P:0:1d1:0:0:0
+D:This exceptional drink instills into you knowledge, allowing you to advance further in your trade.
+
+N:245:Sleep
+G:!:d
+I:71:11:100
+W:0:0:4:0
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion will make you fall asleep for some turns, allowing monsters
+D:to attack you with impunity.
+
+N:246:Blindness
+G:!:d
+I:71:7:0
+W:0:0:4:0
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This slightly poisonous potion temporarily impedes your eyesight, making you unable to see.
+
+N:247:Booze
+G:!:d
+I:71:9:50
+W:0:0:4:0
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A small bottle of a dark brown distilled beverage. It will impede your ability to see clearly.
+
+N:248:Poison
+G:!:d
+I:71:6:0
+W:3:0:4:0
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This bottle is filled with a mild but still dangerous liquid poison. Drinking it would be highly
+D:unwise.
+
+N:249:Speed
+G:!:d
+I:71:29:0
+W:1:0:4:75
+A:1/1:40/1:60/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A magical drink which temporarily allows you to act much faster.
+
+N:250:Slowness
+G:!:d
+I:71:4:50
+W:1:0:4:0
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A magical concoction that will temporarily force you to move and act a lot slower.
+
+N:251:Dexterity
+G:!:d
+I:71:51:0
+W:20:0:4:8000
+A:20/6:25/3:30/1
+P:0:1d1:0:0:0
+D:A strange magical drink which permanently improves your agility.
+
+N:252:Restore Dexterity
+G:!:d
+I:71:45:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical brew brings your agility back to its former glory should it have been reduced.
+
+N:253:Restore Constitution
+G:!:d
+I:71:46:0
+W:25:0:4:300
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A beneficial magical concoction, restoring your damaged health.
+
+N:254:Lose Memories
+G:!:d
+I:71:13:0
+W:10:0:4:0
+A:10/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This wicked potion will make you lose a lot of the experience you've gained.
+
+N:255:Salt Water
+G:!:d
+I:71:5:0
+W:0:0:4:1
+A:0/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A solution of salt in water, made for curing meat. Drinking it causes violent nausea.
+
+N:256:Enlightenment
+G:!:d
+I:71:56:0
+W:25:0:4:800
+A:25/1:50/1:100/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:An exceptional magical drink which lets you "remember" your current location as if you had
+D:already seen all of it.
+
+N:257:Heroism
+G:!:d
+I:71:32:0
+W:1:0:4:35
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:Quaffing this potion will temporarily make you fight like a hero of great might.
+
+N:258:Berserk Strength
+G:!:d
+I:71:33:0
+W:3:0:4:100
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This strange drink will instill in you a wild battle rage for a while.
+
+N:259:Boldness
+G:!:d
+I:71:28:0
+W:1:0:4:10
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This drink will improve your courage, dispelling all fear.
+
+N:260:Restore Life Levels
+G:!:d
+I:71:41:0
+W:40:0:4:400
+A:40/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:If your life force has been drained, this blessed brew will bring it back.
+
+N:261:Resist Heat
+G:!:d
+I:71:30:0
+W:1:0:4:30
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical potion will render you less vulnerable to outward heat.
+
+N:262:Resist Cold
+G:!:d
+I:71:31:0
+W:1:0:4:30
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical potion will for a short while grant you a familiarity with frost, so that you take
+D:less harm from extreme cold.
+
+N:263:Detect Invisible
+G:!:d
+I:71:25:0
+W:3:0:4:50
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical concoction will temporarily improve your eyesight so that you can see creatures
+D:otherwise unseen.
+
+N:264:Slow Poison
+G:!:d
+I:71:26:0
+W:1:0:4:25
+A:1/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This healthy potion will dilute poisons in your blood and reduce the damage they cause.
+
+N:265:Neutralise Poison
+G:!:d
+I:71:27:0
+W:5:0:4:75
+A:5/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This powerful antidote will negate the effect of all poisons currently affecting you.
+
+N:266:Restore Mana
+G:!:d
+I:71:40:0
+W:25:0:4:350
+A:25/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion infuses the drinker with pure magic force, bringing their magical potential back to
+D:its full extent.
+
+N:267:Infra-vision
+G:!:d
+I:71:24:0
+W:3:0:4:20
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This potion temporarily grants or improves the ability to optically perceive heat sources.
+
+N:268:Resistance
+G:!:d
+I:71:60:100
+W:20:0:4:250
+A:20/1:45/1:80/1:100/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+F:FOUNTAIN
+D:This great potion infuses you with the power of the elements, so that you can better
+D:withstand their ravages.
+
+##### Wands #####
+
+# Wand of school spells
+N:269:Spell
+G:-:d
+I:65:1:0
+W:3:0:10:100
+A:3/1:13/1:23/1:43/1:63/1:83/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE
+
+N:270:Manathrust
+G:-:d
+I:65:3:-1:SPELL=Manathrust
+W:3:0:10:100
+A:3/1
+P:0:1d1:0:0:0
+
+N:271:Fireflash
+G:-:d
+I:65:4:-1:SPELL=Fireflash
+W:10:0:10:100
+A:10/2
+P:0:1d1:0:0:0
+
+N:272:Firewall
+G:-:d
+I:65:5:-1:SPELL=Firewall
+W:20:0:10:100
+A:20/1
+P:0:1d1:0:0:0
+
+N:273:Tidal Wave
+G:-:d
+I:65:6:-1:SPELL=Tidal Wave
+W:20:0:10:100
+A:20/1
+P:0:1d1:0:0:0
+
+N:274:Ice Storm
+G:-:d
+I:65:7:-1:SPELL=Ice Storm
+W:15:0:10:100
+A:15/1
+P:0:1d1:0:0:0
+
+N:275:Noxious Cloud
+G:-:d
+I:65:8:-1:SPELL=Noxious Cloud
+W:5:0:10:100
+A:5/2
+P:0:1d1:0:0:0
+
+N:276:Poison Blood
+G:-:d
+I:65:9:-1:SPELL=Poison Blood
+W:30:0:10:100
+A:30/2
+P:0:1d1:0:0:0
+
+N:277:Thunderstorm
+G:-:d
+I:65:10:-1:SPELL=Thunderstorm
+W:40:0:10:100
+A:40/2
+P:0:1d1:0:0:0
+
+N:278:Dig
+G:-:d
+I:65:11:-1:SPELL=Dig
+W:15:0:10:100
+A:15/1
+P:0:1d1:0:0:0
+
+N:279:Stone Prison
+G:-:d
+I:65:12:-1:SPELL=Stone Prison
+W:50:0:10:100
+A:50/3
+P:0:1d1:0:0:0
+
+N:280:Strike
+G:-:d
+I:65:13:-1:SPELL=Strike
+W:30:0:10:100
+A:30/1
+P:0:1d1:0:0:0
+
+N:281:Teleport Away
+G:-:d
+I:65:14:-1:SPELL=Teleport Away
+W:20:0:10:100
+A:20/1
+P:0:1d1:0:0:0
+
+N:282:Summon Animal
+G:-:d
+I:65:15:-1:SPELL=Summon Animal
+W:60:0:10:100
+A:60/1
+P:0:1d1:0:0:0
+
+N:283:Magelock
+G:-:d
+I:65:16:-1:SPELL=Magelock
+W:1:0:10:100
+A:3/2
+P:0:1d1:0:0:0
+
+N:284:Slow Monster
+G:-:d
+I:65:17:-1:SPELL=Slow Monster
+W:3:0:10:100
+A:3/2
+P:0:1d1:0:0:0
+
+N:285:Essence of Speed
+G:-:d
+I:65:18:-1:SPELL=Essence of Speed
+W:25:0:10:100
+A:25/2
+P:0:1d1:0:0:0
+
+N:286:Banishment
+G:-:d
+I:65:19:-1:SPELL=Banishment
+W:45:0:10:100
+A:45/2
+P:0:1d1:0:0:0
+
+N:287:Disperse Magic
+G:-:d
+I:65:20:-1:SPELL=Disperse Magic
+W:10:0:10:100
+A:10/2
+P:0:1d1:0:0:0
+
+N:288:Charm
+G:-:d
+I:65:21:-1:SPELL=Charm
+W:15:0:10:100
+A:15/1
+P:0:1d1:0:0:0
+
+N:289:Confuse
+G:-:d
+I:65:22:-1:SPELL=Confuse
+W:7:0:10:100
+A:7/2
+P:0:1d1:0:0:0
+
+N:290:Demon Blade
+G:-:d
+I:65:23:-1:SPELL=Demon Blade
+W:60:0:10:100
+A:60/1
+P:0:1d1:0:0:0
+
+N:291:Heal Monster
+G:-:d
+I:65:24:-1:SPELL=Heal Monster
+W:1:0:10:0
+A:1/4
+P:0:1d1:0:0:0
+
+N:292:Haste Monster
+G:-:d
+I:65:25:-1:SPELL=Haste Monster
+W:1:0:10:0
+A:1/4
+P:0:1d1:0:0:0
+
+
+##### Extra ammunition #####
+
+N:293:& Flight Arrow~
+G:{:y
+I:17:1:0
+W:3:0:1:1
+A:3/2
+P:0:1d3:0:0:0
+F:SHOW_MODS
+D:An arrow designed for longer flight. Consequently, it is lighter and hits with less force. You can use it for 'f'iring a bow.
+
+# XXX
+
+N:295:& Boulder~
+G:*:W
+I:11:1:0
+W:3:0:50:1
+A:3/200
+P:0:5d5:0:0:0
+F:SPECIAL_GENE
+D:A big nasty-looking piece of rock.
+
+# Used for a quest
+N:296:& Flame~ Imperishable
+G:~:v
+I:11:255:0
+W:127:0:4:0
+A:127/255
+P:0:1d1:0:0:0
+T:39:2
+F:NORM_ART | FULL_NAME | SPECIAL_GENE
+F:ACTIVATE | ACTIVATE_NO_WIELD
+a:SPELL=Artifact Eternal Flame
+D:An impossibly bright, flickering living flame. It can be used
+D:once to imbue an object with the power of Eru Iluvatar himself.
+
+N:297:& Necromantic Teeth~
+G:|:D
+I:23:34:0
+W:0:0:7:10
+A:0/1:5/1:10/1:20/1
+P:0:1d4:0:0:0
+F:SHOW_MODS | VAMPIRIC | SPECIAL_GENE
+D:A temporary weapon that only a necromancer can use.
+
+# The Horn of the Thunderlords
+N:298:& Golden Horn~ of the Thunderlords
+G:_:d
+I:55:23:-1:SPELL=Artifact Thunderlords
+W:50:10:10:12000
+P:0:1d4:0:0:0
+A:50/200
+T:55:8
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_ELEC | IGNORE_COLD |
+F:NO_RECHARGE | EASY_USE | RECHARGED | NORM_ART | FULL_NAME | SPECIAL_GENE
+D:This horn was given to you as a reward. Blow it if you are in dire need
+D:of leaving your current location fast.
+
+# XXX
+
+##### Staves #####
+
+N:300:Spell
+G:_:d
+I:55:1:0
+W:5:0:50:100
+A:5/1:15/1:35/1:45/1:65/1:75/1:85/1:95/1
+P:0:1d2:0:0:0
+F:SPECIAL_GENE
+
+N:301:Nothing
+G:_:d
+I:55:2:-1:SPELL=Nothing
+W:5:0:50:100
+A:5/1
+P:0:1d2:0:0:0
+
+N:302:Globe of Light
+G:_:d
+I:55:3:-1:SPELL=Globe of Light
+W:7:0:50:100
+A:7/1
+P:0:1d2:0:0:0
+
+N:303:Fiery Shield
+G:_:d
+I:55:4:-1:SPELL=Fiery Shield
+W:15:0:50:100
+A:15/2
+P:0:1d2:0:0:0
+
+N:304:Remove Curses
+G:_:d
+I:55:5:-1:SPELL=Remove Curses
+W:10:0:50:100
+A:10/1
+P:0:1d2:0:0:0
+
+N:305:Wings of Winds
+G:_:d
+I:55:6:-1:SPELL=Wings of Winds
+W:25:0:50:100
+A:25/2
+P:0:1d2:0:0:0
+
+N:306:Shake
+G:_:d
+I:55:7:-1:SPELL=Shake
+W:30:0:50:100
+A:30/1
+P:0:1d2:0:0:0
+
+N:307:Disarm
+G:_:d
+I:55:8:-1:SPELL=Disarm
+W:2:0:50:100
+A:2/1
+P:0:1d2:0:0:0
+
+N:308:Teleportation
+G:_:d
+I:55:9:-1:SPELL=Teleportation
+W:20:0:50:100
+A:20/1
+P:0:1d2:0:0:0
+
+N:309:Probability Travel
+G:_:d
+I:55:10:-1:SPELL=Probability Travel
+W:50:0:50:100
+A:50/3
+P:0:1d2:0:0:0
+
+N:310:Recovery
+G:_:d
+I:55:11:-1:SPELL=Recovery
+W:20:0:50:100
+A:20/1
+P:0:1d2:0:0:0
+
+N:311:Healing
+G:_:d
+I:55:12:-1:SPELL=Healing
+W:25:0:50:100
+A:25/2
+P:0:1d2:0:0:0
+
+N:312:Vision
+G:_:d
+I:55:13:-1:SPELL=Vision
+W:30:0:50:100
+A:30/1
+P:0:1d2:0:0:0
+
+N:313:Identify
+G:_:d
+I:55:14:-1:SPELL=Identify
+W:10:0:50:100
+A:10/1
+P:0:1d2:0:0:0
+
+N:314:Sense Hidden
+G:_:d
+I:55:15:-1:SPELL=Sense Hidden
+W:10:0:50:100
+A:10/1
+P:0:1d2:0:0:0
+
+N:315:Reveal Ways
+G:_:d
+I:55:16:-1:SPELL=Reveal Ways
+W:5:0:50:100
+A:5/1
+P:0:1d2:0:0:0
+
+N:316:Sense Monsters
+G:_:d
+I:55:17:-1:SPELL=Sense Monsters
+W:5:0:50:100
+A:5/1
+P:0:1d2:0:0:0
+
+N:317:Genocide
+G:_:d
+I:55:18:-1:SPELL=Genocide
+W:55:0:50:100
+A:55/2
+P:0:1d2:0:0:0
+
+N:318:Summon
+G:_:d
+I:55:19:-1:SPELL=Summon
+W:5:0:50:100
+A:5/1
+P:0:1d2:0:0:0
+
+N:319:Sterilization
+G:_:d
+I:55:24:-1:SPELL=Sterilize
+W:20:0:50:100
+A:20/3
+P:0:1d2:0:0:0
+
+N:320:Wish
+G:_:d
+I:55:20:-1:SPELL=Wish
+W:95:0:50:10000
+A:95/40
+P:0:1d2:0:0:0
+F:NO_RECHARGE
+
+N:321:Mana
+G:_:d
+I:55:21:-1:SPELL=Mana
+W:60:0:50:100
+A:60/2
+P:0:1d2:0:0:0
+
+# XXX
+# ...
+# XXX
+
+##### School Books #####
+
+N:330:& Tome~ of Magical Energy
+G:?:B
+I:111:0:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:The slick black cover of this tome seems to glow
+D:with an inner violet light. You feel more attuned
+D:to raw magic as you hold it.
+
+N:331:& Tome~ of the Eternal Flame
+G:?:R
+I:111:1:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | IGNORE_FIRE
+D:The cover of this tome is bright red, with flickering
+D:flames dancing across it once in a while. As you hold
+D:it, you begin to gain a much closer knowledge of all
+D:that is fiery.
+
+N:332:& Tome~ of the Blowing Wind
+G:?:b
+I:111:2:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | IGNORE_ELEC
+D:The pages of this tome have a tendency to turn themselves,
+D:as though flipped by an errant wind. As you hold it,
+D:you start feeling wind at your fingertips.
+
+N:333:& Tome~ of the Impenetrable Earth
+G:?:U
+I:111:3:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | IGNORE_ACID
+D:The solid leather cover of this tome seems permanently
+D:stained with caked mud and grass. Heavy it is to lift,
+D:yet strangely comforting to hold - you feel stronger
+D:and better supported.
+
+N:334:& Tome~ of the Everrunning Wave
+G:?:B
+I:111:4:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:The cover and pages of this tome seem to be perpetually
+D:wet, though they are not wet to the touch. As you hold
+D:it, you begin to understand ocean storms better.
+
+N:335:& Tome~ of Translocation
+G:?:B
+I:111:5:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This book seems to flicker strangely. It's one of those books
+D:with an annoying tendency to disappear when you need it and
+D:reappear in the unlikeliest places. As you hold it, you start
+D:to understand what conveyance really means.
+
+N:336:& Tome~ of the Tree
+G:?:G
+I:111:6:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:The cover of this tome is a bright shade of green, and it gives off
+D:a healthy, zesty scent that makes your thoughts clearer. As you
+D:hold it, your heart goes out to all living things upon Arda.
+
+N:337:& Tome~ of Knowledge
+G:?:D
+I:111:7:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:A thick book with solid leather binding. It looks entirely
+D:unremarkable, but as you hold it, you feel strangely able
+D:to learn the inner workings of things and creatures.
+
+##### Chests #####
+
+N:338:& Small wooden chest~
+G:~:s
+I:7:1:0
+W:5:0:250:20
+A:5/1
+P:0:2d3:0:0:0
+D:A small wooden box, locked and possibly trapped.
+
+N:339:& Large wooden chest~
+G:~:s
+I:7:5:0
+W:15:0:500:60
+A:15/1
+P:0:2d5:0:0:0
+D:A large wooden box, locked and possibly trapped
+
+N:340:& Small iron chest~
+G:~:s
+I:7:2:0
+W:25:0:300:100
+A:25/1
+P:0:2d4:0:0:0
+D:A small rectangular container made of wood and reinforced with iron corners and latches.
+D:It is locked and possibly trapped.
+
+N:341:& Large iron chest~
+G:~:s
+I:7:6:0
+W:35:0:1000:150
+A:35/1
+P:0:2d6:0:0:0
+D:A large container made of wood, with a heavy iron lock, and probably a trap.
+
+N:342:& Small steel chest~
+G:~:s
+I:7:3:0
+W:45:0:500:200
+A:45/1
+P:0:2d4:0:0:0
+D:A small wooden box with strong steel locks and reinforcements. It's likely to be trapped.
+
+N:343:& Large steel chest~
+G:~:s
+I:7:7:0
+W:55:0:1000:250
+A:55/1
+P:0:2d6:0:0:0
+D:A nearly indestructible chest of wood and steel. The lock doesn't look impenetrable, but it
+D:might be trapped.
+
+N:344:& Ruined chest~
+G:~:s
+I:7:0:0
+W:0:0:250:0
+A:75/1
+D:A broken, empty chest.
+
+##### Various Stuff #####
+
+N:345:& Iron Spike~
+G:~:W
+I:5:0:0
+W:1:0:10:1
+A:1/1
+P:0:1d1:0:0:0
+D:A small spur of iron. Ramming one between a door and its frame might jam it.
+
+N:346:& Wooden Torch~
+G:~:u
+I:39:0:0:4000
+W:1:0:30:2
+A:1/1
+P:0:1d1:0:0:0
+F:EASY_KNOW | LITE1 | FUEL_LITE
+f:LITE1 | FUEL_LITE
+D:A piece of wood with an oily rag wrapped around it. When lit, it will give off a little light and
+D:much smoke.
+
+N:347:& Brass Lantern~
+G:~:U
+I:39:1:0:7500
+W:3:0:50:35
+A:3/1
+P:0:1d1:0:0:0
+F:EASY_KNOW | IGNORE_FIRE | LITE2 | FUEL_LITE
+f:LITE2 | FUEL_LITE
+D:A brass container with a wick emerging from it, protected from draughts by a sheet of greased
+D:paper. It can be carried by a handle.
+
+N:348:& Flask~ of oil
+G:!:y
+I:77:0:7500
+W:1:0:10:3
+A:1/1
+P:0:2d6:0:0:0
+D:A small clay container, filled with thick oil. The oil is flammable and can be used as lantern
+D:fuel.
+
+N:349:& Empty Bottle~
+G:!:w
+I:2:1:0
+W:0:0:2:1
+A:0/1
+P:0:1d1:0:0:0
+D:A small glass bottle. It's empty.
+
+
+##### Here are the Rod Tips #####
+
+N:350:Havoc
+G:-:d
+I:66:28:90
+W:95:0:15:150000
+A:100/16
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This powerful rod will release great blasts of destructive energy, but there's no knowing what
+D:this effect will concentrate on.
+
+N:351:Door/Stair Location
+G:-:d
+I:66:1:10
+W:15:0:15:1000
+A:15/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:When fuelled with enough ambient mana, this rod can detect nearby passages.
+
+N:352:Trap Location
+G:-:d
+I:66:29:8
+W:5:0:15:100
+A:5/1:10/1:20/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:Zapping this rod will release a minor detection magic, alerting you of nearby pits and snares.
+
+N:353:Probing
+G:-:d
+I:66:7:50
+W:40:0:15:4000
+A:40/4
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:A rod of knowledge which will tell you about nearby creatures' health.
+D:If they are sleeping, the intrusion will wake them.
+
+N:354:Recall
+G:-:d
+I:66:3:80
+W:30:0:15:4500
+A:30/4
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:A rod which can transport you from the depths to your home and back.
+
+N:355:Illumination
+G:-:d
+I:66:4:8
+W:20:0:15:1000
+A:20/1
+P:0:1d1:0:0:0
+F:EASY_KNOW
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod carries a minor spell of brightness, lighting your immediate surroundings whenever
+D:activated.
+
+N:356:Light
+G:-:d
+I:66:15:15
+W:10:0:15:500
+A:10/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod can shoot a lance of bright light, hurting creatures which lurk in the dark.
+
+N:357:Lightning Bolts
+G:-:d
+I:66:21:30
+W:20:0:15:2000
+A:20/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod shoots a small spark of lightning, zapping the creature it hits.
+
+N:358:Frost Bolts
+G:-:d
+I:66:23:35
+W:25:0:15:2500
+A:25/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:A small but extremely cold shard of ice will fly from this rod to the enemy you zap it at.
+
+N:359:Fire Bolts
+G:-:d
+I:66:22:40
+W:30:0:15:3000
+A:30/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod fires a magical flaming arrow at your foe, burning them.
+
+N:360:Polymorph
+G:-:d
+I:66:19:25
+W:35:0:15:1200
+A:35/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod of change will cause its target creature to mutate into someone else.
+D:Beware, it can make a weak enemy into a more powerful one.
+
+N:361:Slow Monster
+G:-:d
+I:66:17:25
+W:30:0:15:1500
+A:30/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This obstructive rod will slow the creature its spell hits.
+
+N:362:Sleep Monster
+G:-:d
+I:66:16:25
+W:30:0:15:1500
+A:30/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This sorcerous rod will cause its target to stop in its tracks.
+
+N:363:Drain Life
+G:-:d
+I:66:18:30
+W:75:0:15:3600
+A:75/4
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This necromantic magical rod will hurt a living creature struck by its spell.
+
+N:364:Teleport Other
+G:-:d
+I:66:13:60
+W:45:0:15:1400
+A:45/2
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod of movement will displace its target to another location.
+
+N:365:Disarming
+G:-:d
+I:66:14:50
+W:35:0:15:2100
+A:35/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod will clear a path for you, triggering and thus rendering harmless all traps on the way.
+
+N:366:Lightning Balls
+G:-:d
+I:66:25:50
+W:55:0:15:4000
+A:55/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod will hurl a large ball of lightning at its target, electrifying all it engulfs.
+
+N:367:Cold Balls
+G:-:d
+I:66:27:55
+W:60:0:15:4500
+A:60/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod will call forth a minor storm of ice which freezes everything in the area of its blast.
+
+N:368:Fire Balls
+G:-:d
+I:66:26:60
+W:75:0:15:5000
+A:75/1
+P:0:1d1:0:0:0
+D:This rod will cause a small storm of flame to rage in a small circular area of your choice.
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+
+N:369:Acid Balls
+G:-:d
+I:66:24:60
+W:70:0:15:5500
+A:70/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This destructive rod will drown its target and its immediate surroundings in caustic acid.
+
+N:370:Acid Bolts
+G:-:d
+I:66:20:40
+W:40:0:15:3500
+A:40/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod will shoot a small glob of powerful acid at its target.
+
+N:371:Enlightenment
+G:-:d
+I:66:5:40
+W:65:0:15:10000
+A:65/4
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod grants you knowledge of your surroundings.
+
+N:372:Perception
+G:-:d
+I:66:2:20
+W:50:0:15:13000
+A:50/8:100/8
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod makes you insightful, laying open the identity of your possessions.
+
+N:373:Curing
+G:-:d
+I:66:8:35
+W:65:0:15:15000
+A:65/8
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This is a rod with minor healing powers, alleviating many disabling conditions.
+
+N:374:Healing
+G:-:d
+I:66:9:120
+W:80:0:15:20000
+A:80/8
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod has major healing powers and can restore your health if you have been wounded.
+
+N:375:Detection
+G:-:d
+I:66:6:80
+W:30:0:15:5000
+A:30/8
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod grants knowledge about all things worthy of notice in your vicinity.
+
+N:376:Restoration
+G:-:d
+I:66:10:140
+W:80:0:15:25000
+A:80/16
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This rod lets you remember and gain back previously reduced abilities.
+
+N:377:Speed
+G:-:d
+I:66:11:100
+W:95:0:15:50000
+A:95/16
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE
+D:This energising rod will allow you to act a lot faster for some time.
+
+# Ring of Spell
+
+N:378:Spell
+G:=:d
+I:45:58:0
+W:10:0:2:1000
+A:10/1
+F:SPELL_CONTAIN | WIELD_CAST
+f:SPELL_CONTAIN
+D:This ring is a container for spells. Those that are skilled in copying spells can inscribe a
+D:spell onto it.
+
+# Amulet of Spell
+
+N:379:Spell
+G:":d
+I:40:27:0
+W:10:0:2:1000
+A:10/1
+F:SPELL_CONTAIN | WIELD_CAST
+f:SPELL_CONTAIN
+D:This amulet is a container for spells. Those that are skilled in copying spells can inscribe a
+D:spell onto it.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+##### Skeletons #####
+
+N:391:& Broken Skull~
+G:~:w
+I:1:1:0
+W:0:0:1:0
+A:0/1
+P:0:1d1:0:0:0
+D:A yellowing, mud-stained, cracked skull.
+
+N:392:& Broken Bone~
+G:~:w
+I:1:2:0
+W:0:0:2:0
+A:0/1
+P:0:1d1:0:0:0
+D:A yellowish bone, broken off.
+
+N:393:& Canine Skeleton~
+G:~:w
+I:1:4:0
+W:1:0:10:0
+A:1/1
+P:0:1d1:0:0:0
+D:The only thing this dog has is its bones.
+
+N:394:& Rodent Skeleton~
+G:~:w
+I:1:3:0
+W:1:0:10:0
+A:1/1
+P:0:1d1:0:0:0
+D:A dead critter's remains.
+
+N:395:& Human Skeleton~
+G:~:w
+I:1:8:0
+W:5:0:60:0
+A:5/1
+P:0:1d2:0:0:0
+D:The remains of a human who met his or her demise here.
+
+N:396:& Dwarf Skeleton~
+G:~:w
+I:1:7:0
+W:5:0:50:0
+A:5/1
+P:0:1d2:0:0:0
+D:The remains of a dwarf who met his or her demise here.
+
+N:397:& Elf Skeleton~
+G:~:w
+I:1:6:0
+W:5:0:40:0
+A:5/1
+P:0:1d2:0:0:0
+D:The remains of an elf who met his or her demise here.
+
+N:398:& Gnome Skeleton~
+G:~:w
+I:1:5:0
+W:5:0:30:0
+A:5/1
+P:0:1d2:0:0:0
+D:The remains of a gnome who met his or her demise here.
+
+##### Additional weapon #####
+
+N:399:& Great Hammer~
+G:\:D
+I:21:19:0
+W:45:0:300:350
+A:45/3
+P:0:4d6:0:0:0
+F:SHOW_MODS
+D:A massive smith's hammer, so large and heavy it can be used as a weapon.
+
+##### Dragon Scale Mail #####
+
+N:400:& Black Dragon Scale Mail~
+G:[:s
+I:38:1:0
+W:60:0:200:50000
+A:60/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_ACID
+F:RES_ACID | FLY |
+f:RES_ACID |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A pitch-black armour made from a black dragon's hide.
+D:It contains some of the dead beast's powers.
+
+N:401:& Blue Dragon Scale Mail~
+G:[:b
+I:38:2:0
+W:50:0:200:40000
+A:50/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_ELEC
+F:RES_ELEC | FLY |
+f:RES_ELEC |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A shimmering bright blue armour made from a blue dragon's hide.
+D:It contains some of the dead beast's powers.
+
+N:402:& White Dragon Scale Mail~
+G:[:w
+I:38:3:0
+W:50:0:200:40000
+A:50/8
+a:HARDCORE=BR_COLD
+P:30:2d4:-2:0:10
+F:RES_COLD | FLY |
+f:RES_COLD |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A gleaming white armour made from a white dragon's hide.
+D:It contains some of the dead beast's powers.
+
+N:403:& Red Dragon Scale Mail~
+G:[:r
+I:38:4:0
+W:60:0:200:50000
+A:60/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_FIRE
+F:RES_FIRE | FLY |
+f:RES_FIRE |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A glowing red armour made from a red dragon's hide.
+D:It contains some of the dead beast's powers.
+
+N:404:& Green Dragon Scale Mail~
+G:[:g
+I:38:5:0
+W:50:0:200:40000
+A:50/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_POIS
+F:RES_POIS | FLY |
+f:RES_POIS |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A dirty green, foul-smelling armour made from a green dragon's hide.
+D:It contains some of the dead beast's powers.
+
+N:405:& Multi-Hued Dragon Scale Mail~
+G:[:v
+I:38:6:0
+W:90:0:200:150000
+A:90/32
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_MANY
+F:ATTR_MULTI
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS | FLY |
+f:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD | RES_POIS |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A powerful armour glowing red, blue, green, black, and white.
+D:made from a multihued dragon's hide, it contains some of the dead beast's powers.
+
+N:406:& Pseudo Dragon Scale Mail~
+G:[:v
+I:38:10:0
+W:70:0:200:70000
+A:70/16
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_LIGHT
+F:RES_LITE | RES_DARK | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A strangely glowing armour made from a pseudo-dragon's hide.
+D:It contains some of the dead beast's powers.
+
+N:407:& Law Dragon Scale Mail~
+G:[:B
+I:38:12:0
+W:80:0:200:80000
+A:80/16
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_SHARD
+F:RES_SOUND | RES_SHARDS | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A sharp-scaled armour that seems to roar, made from a law dragon's hide.
+D:It contains some of the dead beast's powers.
+
+N:408:& Bronze Dragon Scale Mail~
+G:[:U
+I:38:14:0
+W:50:0:200:40000
+A:50/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_CONF
+F:RES_CONF | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A brownish armour glittering in a dazzling light, made from a bronze dragon's hide.
+D:It contains some of the dead beast's powers.
+
+N:409:& Gold Dragon Scale Mail~
+G:[:y
+I:38:16:0
+W:60:0:200:50000
+A:60/8
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_SOUND
+F:RES_SOUND | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour with rustling scales, made from a gold dragon's hide.
+D:It contains some of the dead beast's powers.
+
+N:410:& Chaos Dragon Scale Mail~
+G:[:v
+I:38:18:0
+W:80:0:200:80000
+A:80/16
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_CHAOS
+F:ATTR_MULTI
+F:RES_CHAOS | RES_DISEN | FLY |
+f:RES_CHAOS |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour made of dragon hide. It glows in colours you have never seen before. As you
+D:put it on, you feel like you could change the world and are no longer afraid of your equipment
+D:losing its magic.
+
+N:411:& Balance Dragon Scale Mail~
+G:[:v
+I:38:20:0
+W:95:0:200:100000
+A:95/32
+P:30:2d4:-2:0:10
+a:HARDCORE=BR_BALANCE
+F:RES_CHAOS | RES_DISEN | RES_SOUND | RES_SHARDS | FLY |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour made of the hide of a dead dragon. When wearing it, you feel like you
+D:understand the principles of law and chaos, and no longer fear either.
+
+N:412:& Power Dragon Scale Mail~
+G:[:v
+I:38:30:0
+W:100:0:250:350000
+A:100/64
+P:40:2d4:-3:0:15
+a:HARDCORE=BR_POWER
+F:ATTR_MULTI
+F:RES_ACID | RES_FIRE | RES_COLD | RES_ELEC | RES_POIS | FLY |
+F:RES_NETHER | RES_NEXUS | RES_CHAOS | RES_LITE | RES_DARK |
+F:RES_SHARDS | RES_SOUND | RES_DISEN | RES_CONF |
+F:ACTIVATE | IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:A suit of armour made of a very thick richly coloured dragonhide. You think you'll never have
+D:to fear dragons if you put it on.
+
+#### PDSM has been restored to (almost) its former glory in Zangband
+
+N:413:& Dragon Helm~
+G:]:G
+I:32:7:0
+W:45:0:50:10000
+A:80/4
+P:8:1d3:0:0:10
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_ELEC | IGNORE_COLD
+D:An iron helmet, covered with a layer of dragonhide. It offers great protection and may grant
+D:protection against some dragon's attacks, based on the dragon the hide was taken from.
+
+N:414:& Dragon Shield~
+G:[:G
+I:34:6:0
+W:70:0:100:10000
+A:80/4
+P:8:1d3:0:0:10
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_ELEC | IGNORE_COLD
+D:A large shield, with a dragonskin cover. Depending on which dragon the hide came from, it
+D:might grant protection against some sorts of dragon breath.
+
+##### Extra potions #####
+
+N:415:Death
+G:!:d
+I:71:23:0
+W:55:0:4:0
+A:55/4
+P:0:20d20:0:0:0
+F:FOUNTAIN
+D:A potent and very quickly working poison, sometimes utilised by those who wish to end their
+D:lives. It is immensely toxic and will seriously hurt you even if you just get some of it on your
+D:hands.
+
+N:416:Ruination
+G:!:d
+I:71:15:0
+W:40:0:4:0
+A:40/8
+P:0:20d20:0:0:0
+F:FOUNTAIN
+D:This wicked potion will seriously damage your abilities beyond the powers of magical
+D:restoration.
+
+N:417:Detonations
+G:!:d
+I:71:22:0
+W:60:0:4:10000
+A:60/8
+P:0:25d25:0:0:0
+F:FOUNTAIN
+D:This bottle is filled with a strange substance which will violently explode if strongly agitated.
+
+N:418:Augmentation
+G:!:d
+I:71:55:0
+W:40:0:4:60000
+A:40/16
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This blessed potion will greatly improve all your abilities if they can still be improved.
+
+N:419:*Healing*
+G:!:d
+I:71:38:0
+W:40:0:4:1500
+A:40/4:60/2:80/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This highly desirable potion will greatly help recovering from wounds, typically healing you
+D:fully.
+
+N:420:Life
+G:!:d
+I:71:39:0
+W:60:0:4:5000
+A:60/4:100/2
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This wonderful potion will fully heal you no matter how badly you're hurt, allow drained
+D:abilities to recover and remove various other ailments.
+
+N:421:Self Knowledge
+G:!:d
+I:71:58:0
+W:40:0:4:2000
+A:40/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A drink of insight that lets you know yourself better.
+
+N:422:*Enlightenment*
+G:!:d
+I:71:57:0
+W:70:0:4:80000
+A:70/4
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical concoction will grant you great insight, magically improving your wits and
+D:wisdom, letting you know precisely who and where you are and what you possess.
+
+# XXX
+# XXX
+
+N:425:Fear Resistance
+G:=:d
+I:45:38:0
+W:10:0:2:300
+A:10/2
+F:RES_FEAR | EASY_KNOW
+f:RES_FEAR |
+D:This ring grants courage, so that you can never become afraid.
+
+N:426:Light and Darkness Resistance
+G:=:d
+I:45:39:0
+W:30:0:2:3000
+A:30/2
+F:RES_LITE | RES_DARK | EASY_KNOW
+f:RES_LITE | RES_DARK |
+D:This ring protects against fluctuations of the light.
+
+N:427:Nether Resistance
+G:=:d
+I:45:40:0
+W:34:0:2:14500
+A:34/2
+F:RES_NETHER | HOLD_LIFE | EASY_KNOW
+f:RES_NETHER |
+D:This blessed ring improves your life force, protecting you from the draining forces of nether
+D:and other attempts to suck your lifeblood.
+
+N:428:Nexus Resistance
+G:=:d
+I:45:41:0
+W:24:0:2:3000
+A:24/2
+F:RES_NEXUS | EASY_KNOW
+f:RES_NEXUS |
+D:This ring of stability protects you from the warping forces of nexus.
+
+N:429:Sound Resistance
+G:=:d
+I:45:42:0
+W:26:0:2:3000
+A:26/2
+F:RES_SOUND | EASY_KNOW
+f:RES_SOUND |
+D:This ring projects an aura of quiet around you, protecting you from loud noise.
+
+N:430:Confusion Resistance
+G:=:d
+I:45:43:0
+W:22:0:2:3000
+A:22/2
+F:RES_CONF | EASY_KNOW
+f:RES_CONF |
+D:This ring stabilises your mind, protecting you from all kinds of befuddlement.
+
+N:431:Shard Resistance
+G:=:d
+I:45:44:0
+W:25:0:2:3000
+A:25/2
+F:RES_SHARDS | EASY_KNOW
+f:RES_SHARDS |
+D:This piece of jewellery magically toughens your skin, protecting you from flying shrapnel.
+
+N:432:Disenchantment Resistance
+G:=:d
+I:45:45:0
+W:90:0:2:15000
+A:90/10
+F:RES_DISEN | EASY_KNOW
+f:RES_DISEN |
+D:This rare ring of preservation protects your equipment from attempts to sap its magic, also
+D:causing you to suffer less pain from such attacks.
+
+N:433:Chaos Resistance
+G:=:d
+I:45:46:0
+W:50:0:2:13000
+A:50/2
+F:RES_CHAOS | RES_CONF | EASY_KNOW
+f:RES_CHAOS |
+D:This ring protects you from the horribly warping forces of chaos.
+
+N:434:Blindness Resistance
+G:=:d
+I:45:47:0
+W:60:0:2:7500
+A:60/2
+F:RES_BLIND | EASY_KNOW
+f:RES_BLIND |
+D:This ring magically preserves your eyesight, making you impervious to any attempt to blind
+D:you.
+
+N:435:Arnor
+G:=:d
+I:45:48:0
+W:100:0:2:100000
+A:100/5
+F:RES_DISEN | RES_POIS | HOLD_LIFE | FREE_ACT
+f:RES_DISEN | RES_POIS | HOLD_LIFE | FREE_ACT
+D:This blessed ring will protect you from disenchantment, poison, attempts to drain your life
+D:force and holding magic.
+
+N:436:Extra Attacks
+G:=:d
+I:45:49:0
+W:50:0:2:100000
+A:50/2
+F:BLOWS | ACTIVATE | EASY_USE |
+f:BLOWS | ACTIVATE
+a:HARDCORE=SPIN
+D:This powerful ring of fighters greatly enhances your fighting speed, allowing you to attack
+D:more often in a round of combat.
+
+N:437:Cure Light Wounds
+G:!:d
+I:71:34:50
+W:0:0:4:15
+A:0/1:1/1:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This healthy drink heals a little damage you have taken.
+
+N:438:Clumsiness
+G:!:d
+I:71:19:0
+W:5:0:4:0
+A:5/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This nasty concoction will numb your nerves, making you clumsier.
+
+N:439:Sickliness
+G:!:d
+I:71:20:0
+W:10:0:4:0
+A:10/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This unhealthy drink damages your health, reducing your physical constitution.
+
+###### Here start the maps #####
+
+# Map of Bree
+N:440:Map of Bree
+G:?:s
+I:8:200:0
+W:3:100:5:100
+A:3/3
+D:A map, showing the town of Bree and the landscape around it.
+
+# Map of Gondolin
+N:441:Map of Gondolin
+G:?:s
+I:8:201:0
+W:70:100:5:50000
+A:70/3
+D:A map detailing the place of the hidden city of Gondolin.
+
+# Map of Lothlorien
+N:442:Map of Lothlorien
+G:?:s
+I:8:202:0
+W:6:100:5:1000
+A:6/3
+D:A map vaguely describing the forest of Lothlorien and the elven settlements therein.
+
+# Map of Minas Anor
+N:443:Map of Minas Anor
+G:?:s
+I:8:203:0
+W:36:100:5:10000
+A:36/3
+D:A map of the great city of Gondor.
+
+# XXX Numbers 444-464 unused #
+
+N:465:& Silver Arrow~
+G:{:W
+I:17:3:0
+W:55:0:2:35
+A:50/4:90/2
+P:0:3d4:0:0:0
+F:SHOW_MODS | SLAY_EVIL | IGNORE_ACID | IGNORE_FIRE
+D:An arrow to be shot with a bow, its iron head coated with hallowed silver,
+D:a material that sears the flesh of all evil creatures.
+
+N:466:& Silver Bolt~
+G:{:w
+I:18:3:0
+W:50:0:2:40
+A:60/4:95/2
+P:0:3d5:0:0:0
+F:SHOW_MODS | SLAY_EVIL | IGNORE_ACID | IGNORE_FIRE
+D:This crossbow bolt has a silver tip, blessed by the Valar for fighting evil.
+
+N:468:Wisdom
+G:":d
+I:40:28:0
+W:30:0:3:500
+A:30/1
+F:WIS | SUST_WIS | HIDE_TYPE
+f:WIS |
+D:This magical amulet will magically make you wiser, and fend off
+D:attacks that would reduce your wisdom. Beware: if cursed, the
+D:amulet will do the opposite.
+
+N:469:Regeneration
+G:":d
+I:40:30:0
+W:30:0:3:600
+A:30/3
+F:REGEN | EASY_KNOW
+f:REGEN |
+D:Wearing this amulet will trigger your body's regenerational
+D:processes quicker and make them proceed faster.
+
+N:470:Infravision
+G:":d
+I:40:26:0
+W:10:0:3:200
+A:10/1
+F:INFRA | HIDE_TYPE
+f:INFRA |
+D:This amulet will increase your ability to sense warm-blooded
+D:creatures in your vicinity. Beware: if cursed, it will do
+D:just the opposite.
+
+N:471:Devotion
+G:":d
+I:40:25:0
+W:70:0:3:30000
+A:70/8
+F:WIS | CHR | SUST_WIS | SUST_CHR | LITE1 | HIDE_TYPE |
+F:RES_DARK | RES_LITE | RES_FIRE | HOLD_LIFE |
+D:This blessed amulet will protect your wisdom and charms from
+D:diminishing, often adding to them as well. It also grants
+D:some extra protective magics by the grace of the Valar.
+
+N:472:Weaponmastery
+G:":d
+I:40:24:0
+W:70:0:3:30000
+A:70/8
+F:STR | CON | SUST_STR | SUST_CON | FREE_ACT | HIDE_TYPE |
+F:RES_FEAR | RES_DISEN |
+D:The ultimate amulet for a warrior, it will grant protection
+D:in the face of some evil magics, protect your strength and health,
+D:also increasing them. Beware: if cursed, the amulet will
+D:sap your strength and health instead.
+
+N:473:Trickery
+G:":d
+I:40:23:0
+W:70:0:3:30000
+A:70/8
+F:DEX | SUST_DEX | STEALTH | SPEED | INFRA | HIDE_TYPE |
+F:RES_NEXUS | RES_POIS
+D:The ultimate amulet for a rogue or assassin, it protects the
+D:wearer against some evil magics, granting improvements in
+D:the abilities vital to these adventurers. Beware: if cursed,
+D:the amulet will do just the opposite.
+
+N:474:Telepathy
+G:":d
+I:40:22:0
+W:50:0:3:25000
+A:50/6
+F:ESP_ALL |
+f:ESP_ALL |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This rare and powerful amulet lays bare the minds of monsters
+D:before the wearer.
+
+N:475:Sustenance
+G:":d
+I:40:21:0
+W:60:0:3:20000
+A:60/4
+F:SUST_STR | SUST_INT | SUST_WIS | SUST_DEX | SUST_CON | SUST_CHR |
+F:HOLD_LIFE | SLOW_DIGEST | EASY_KNOW |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This blessed amulet will make the wearer impervious to evil magics
+D:that would sap innate abilities. It also slows down the digestive
+D:system, making food less necessary on long journeys.
+
+# The Palantir of Minas Ithil -- see artifact list
+
+N:476:& Palantir~
+G:~:y
+I:39:107:0
+W:75:0:200:0
+P:0:10d10:0:0:0
+F:INSTA_ART
+
+# The Elfstone 'Elessar' -- see artifact list
+
+N:477:& Elfstone~
+G:":g
+I:40:19:0
+W:60:0:3:50000
+F:INSTA_ART
+
+# The Jewel 'Evenstar' -- see artifact list
+
+N:478:& Jewel~
+G:":w
+I:40:20:0
+W:50:0:3:35000
+F:INSTA_ART
+
+# The Ring of Durin -- see artifact list
+
+N:479:& Ring~
+G:=:d
+I:45:57:0
+W:70:0:2:65000
+F:INSTA_ART | SPECIAL_GENE
+
+##### And here starts the gold/gems #####
+
+N:480:copper
+G:$:u
+I:100:1:0
+W:1:0:0:3
+
+N:481:copper
+G:$:u
+I:100:2:0
+W:1:0:0:4
+
+N:482:copper
+G:$:u
+I:100:3:0
+W:1:0:0:5
+
+N:483:silver
+G:$:s
+I:100:4:0
+W:1:0:0:6
+
+N:484:silver
+G:$:s
+I:100:5:0
+W:1:0:0:7
+
+N:485:silver
+G:$:s
+I:100:6:0
+W:1:0:0:8
+
+N:486:garnets
+G:$:r
+I:100:7:0
+W:1:0:0:9
+
+N:487:garnets
+G:$:r
+I:100:8:0
+W:1:0:0:10
+
+N:488:gold
+G:$:y
+I:100:9:0
+W:1:0:0:12
+
+N:489:gold
+G:$:y
+I:100:10:0
+W:1:0:0:14
+
+N:490:gold
+G:$:y
+I:100:11:0
+W:1:0:0:16
+
+N:491:opals
+G:$:W
+I:100:12:0
+W:1:0:0:18
+
+N:492:sapphires
+G:$:b
+I:100:13:0
+W:1:0:0:20
+
+N:493:rubies
+G:$:r
+I:100:14:0
+W:1:0:0:24
+
+N:494:diamonds
+G:$:w
+I:100:15:0
+W:1:0:0:28
+
+N:495:emeralds
+G:$:g
+I:100:16:0
+W:1:0:0:32
+
+N:496:mithril
+G:$:B
+I:100:17:0
+W:1:0:0:40
+
+N:497:adamantite
+G:$:G
+I:100:18:0
+W:1:0:0:80
+
+
+##### Objects 498 and 499 are the "Morgoth Artifacts" #####
+
+# These objects, like objects 500 to 511, are never created
+# without being turned into artifacts. This simplifies the
+# code for "killing the winner monster".
+
+N:498:& Mighty Hammer~
+G:\:D
+I:21:50:0
+W:15:0:200:1000
+P:0:3d9:0:0:0
+F:SHOW_MODS | INSTA_ART | MUST2H | SPECIAL_GENE
+f:MUST2H
+
+N:499:& Massive Iron Crown~
+G:]:D
+I:33:50:0
+W:44:0:20:1000
+P:0:1d1:0:0:0
+F:INSTA_ART | SPECIAL_GENE
+
+
+##### Objects 500 to 511 are "Special Artifacts" #####
+
+# These objects do not specify "full names" because the artifact name
+# is added in "obj-desc.c" based on the artifact index ("i_ptr->name1").
+#
+# These objects do specify a "base name", which is used when the object
+# is "aware" (always true for lites)
+#
+# The Lites (and the One Ring) specify "physical colors", which
+# over-ride the "flavor" colors, if any. Note that the "One Ring"
+# also has a specific check for "unknown" in which it changes its
+# name to "a plain gold ring". See "object1.c"
+#
+# Note that ALL artifacts are given "IGNORE_ACID/ELEC/FIRE/COLD",
+# so we do not need to specify that here.
+#
+# Note that the "INSTA_ART" flag is used to prevent these objects from
+# being created without also turning them into artifacts. This flag
+# must be specified both here and in the artifact template.
+#
+# The only reason for having six different "ring" templates and three
+# different "amulet" templates is to allow each "special artifact" to
+# have a different "color" and "flavor", and also to allow the use of
+# special "base names" (such as "Necklace").
+
+
+# The Phial of Galadriel -- see artifact list
+
+N:500:& Phial~
+G:~:y
+I:39:100:0
+W:20:0:10:10000
+P:0:1d1:0:0:0
+F:INSTA_ART
+
+# The Star of Elendil -- see artifact list
+
+N:501:& Star~
+G:~:B
+I:39:101:0
+W:30:0:5:25000
+P:0:1d1:0:0:0
+F:INSTA_ART
+
+# The Arkenstone of Thrain -- see artifact list
+
+N:502:& Arkenstone~
+G:~:R
+I:39:102:0
+W:60:0:5:60000
+P:0:1d1:0:0:0
+F:INSTA_ART
+
+
+# The Amulet of Annatar -- see artifact list
+
+N:503:& Amulet~
+G:":d
+I:40:10:0
+W:70:0:3:90000
+F:INSTA_ART
+
+# The Amulet of Ingwe -- see artifact list
+
+N:504:& Amulet~
+G:":d
+I:40:11:0
+W:60:0:3:90000
+F:INSTA_ART
+
+# The Necklace 'Nauglamir' -- see artifact list
+
+N:505:& Necklace~
+G:":d
+I:40:12:0
+W:70:0:3:75000
+F:INSTA_ART
+
+
+# The Ring of Barahir -- see artifact list
+
+N:506:& Ring~
+G:=:d
+I:45:32:0
+W:50:0:2:65000
+F:INSTA_ART
+
+# The Ring of Tulkas -- see artifact list
+# Gone in Theme
+#N:507:& Ring~
+#G:=:d
+#I:45:33:0
+#W:90:0:2:150000
+#F:INSTA_ART
+
+# The Ring of Power 'Narya' -- see artifact list
+
+N:508:& Ring~
+G:=:d
+I:45:34:0
+W:80:0:2:100000
+F:INSTA_ART | SPECIAL_GENE
+
+# The Ring of Power 'Nenya' -- see artifact list
+
+N:509:& Ring~
+G:=:d
+I:45:35:0
+W:90:0:2:200000
+F:INSTA_ART
+
+# The Ring of Power 'Vilya' -- see artifact list
+
+N:510:& Ring~
+G:=:d
+I:45:36:0
+W:100:0:2:300000
+F:INSTA_ART
+
+# The Ring of Power 'The One Ring' -- see artifact list
+
+N:511:& Ring~
+G:=:y
+I:45:37:0
+W:110:0:2:5000000
+F:INSTA_ART
+
+
+### Room for new objects added after 511 (Zangband 2.1.0): 512-575
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+N:520:Reflection
+G:":d
+I:40:9:0
+W:60:0:3:30000
+A:60/4
+F:REFLECT | EASY_KNOW
+f:REFLECT |
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This wondrous amulet will magically make the wearer
+D:reflect arrows and bolts launched by adversaries.
+
+#521 and 522 cannot have EASY_KNOW because they may be cursed
+
+N:521:Anti-Magic
+G:":d
+I:40:13:0
+W:40:0:3:30000
+A:40/4
+F:NO_MAGIC
+f:NO_MAGIC
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This amulet wards off magic of any kind, good or bad.
+
+N:522:Anti-Teleportation
+G:":d
+I:40:14:0
+W:30:0:3:15000
+A:30/4
+F:NO_TELE
+f:NO_TELE
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This amulet will prevent the space-time continuum from
+D:being disrupted around the wearer.
+
+#523 cannot have EASY_KNOW because it can get random resistances
+
+N:523:Resistance
+G:":d
+I:40:15:0
+W:50:0:3:25000
+A:50/4
+F:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD
+f:RES_ACID | RES_ELEC | RES_FIRE | RES_COLD
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This amulet will make the wearer resist the elements.
+
+##### New arms #####
+
+N:524:& Zweihander~
+G:|:w
+I:23:29:0
+W:40:0:280:580
+A:40/3
+P:0:4d6:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This great sword of foreign origin is approximately 6 feet long. The hilt is
+D:long enough for even four hands to grip. A mighty weapon for a warrior.
+
+# Dwarven lantern
+N:525:& Dwarven Lantern~
+G:~:b
+I:39:3:0
+W:15:0:50:5000
+A:15/2
+P:0:1d1:0:0:0
+F:EASY_KNOW | IGNORE_FIRE | LITE2
+f:LITE2
+D:Made by the Dwarves, this lantern provides light in the
+D:darkest recesses of the earth.
+
+N:526:& Splint Mail~
+G:[:D
+I:37:10:0
+W:35:0:250:950
+A:35/1
+P:19:1d4:-2:0:0
+D:A variant of banded mail. The metal strips are applied to the backing of chain,
+D:leather, or cloth rather than horizontally.
+
+# Everburning torch
+N:527:& Everburning Torch~
+G:~:R
+I:39:2:0
+W:5:0:50:2500
+A:5/1
+P:0:1d1:0:0:0
+F:EASY_KNOW | IGNORE_FIRE | LITE1
+f:LITE1
+D:This enchanted torch never needs to be fuelled.
+
+N:528:& Trifurcate Spear~
+G:/:o
+I:22:26:0
+W:35:0:140:400
+A:35/3
+P:0:2d9:0:0:0
+F:SHOW_MODS
+D:This deadly spear's point has three branches, suited for inflicting
+D:slightly greater damage per hit than a regular spear.
+
+N:529:& Three Piece Rod~
+G:\:u
+I:21:11:0
+W:20:0:120:350
+A:20/3
+P:0:3d3:0:0:0
+F:SHOW_MODS
+D:A descendant of the threshing flail, consisting of three short wooden
+D:pieces linked by chain or rope.
+
+# Feanorian Lamp
+N:530:& Feanorian Lamp~
+G:~:B
+I:39:4:0
+W:25:0:50:15000
+A:25/3
+P:0:1d1:0:0:0
+F:EASY_KNOW | IGNORE_FIRE | LITE3
+f:LITE3
+D:Made by the descendants of the Noldo craftsman, this lamp
+D:contains a part of the flame which burned inside Feanor.
+
+N:531:& Fur Cloak~
+G:(:W
+I:35:3:0
+W:20:0:30:100
+A:20/2:30/2
+P:3:0d0:0:0:0
+F:RES_COLD
+D:A coat made from the fur of various wild animals - it is
+D:somewhat bulky, but still spacious enough to wear over armour.
+D:It is ideal for cold weather conditions.
+
+N:532:Water Curing
+G:!:d
+I:72:18:80
+W:0:0:4:0
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE
+D:It is a magical component that can purify water.
+
+N:533:& Hatchet~
+G:/:s
+I:24:1:0
+W:10:0:60:120
+A:10/2
+P:0:1d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:This is a larger version of a throwing axe. It has a single
+D:blade with a pick on the reverse, designed for armour piercing.
+
+##### New armour #####
+
+N:535:& Mumak Hide Armour~
+G:(:s
+I:36:8:0
+W:15:0:110:400
+A:15/1
+P:8:1d1:-1:0:0
+D:This suit of armour is fashioned from the hide of a dead Mumak,
+D:or Oliphaunt. It is tough, leathery, and a bit cumbersome.
+
+N:536:& Leather Jerkin~
+G:(:U
+I:36:12:0
+W:20:0:70:550
+A:20/3
+P:7:1d2:0:0:0
+D:A kind of vest with a colarless neck, made from roughout leather. This
+D:is what Middle-earth rangers usually wear on their travels.
+
+##### New weapons #####
+
+N:537:& Sickle~
+G:/:s
+I:22:3:0
+W:10:0:70:110
+A:10/3
+P:0:2d3:0:0:0
+F:SHOW_MODS
+D:A semicircular blade attached to a short handle, good for chopping
+D:things up into pieces.
+
+# XXX
+# XXX
+# XXX
+# XXX
+
+N:542:& Club~
+G:\:u
+I:21:1:0
+W:0:0:100:3
+A:0/1
+P:0:1d4:0:0:0
+F:SHOW_MODS
+D:A stout heavy stick, thicker at one end. Useful for
+D:shattering and smashing things.
+
+N:543:& Broad Spear~
+G:/:w
+I:22:7:0
+W:14:0:100:240
+A:14/3
+P:0:1d9:0:0:0
+F:SHOW_MODS
+D:It looks like it has just come from the forge. Designed specifically for
+D:foot soldiers combatting mounted cavalry, it is too heavy to be effective
+D:when thrown.
+
+N:544:& Khopesh~
+G:|:W
+I:23:14:0
+W:10:0:130:190
+A:10/2
+P:0:2d4:0:0:0
+F:SHOW_MODS
+D:This sword comes from the regions of Far Harad. The blade is straight
+D:for 18 inches, and then it curves for another 2 feet.
+
+N:545:& Flamberge~
+G:|:W
+I:23:26:0
+W:40:0:230:600
+A:40/2
+P:0:3d7:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:A large, two-handed sword with a blade that weaves
+D:left and right until it reaches the hilt.
+
+N:546:& Claymore~
+G:|:W
+I:23:23:0
+W:40:0:200:600
+A:40/2
+P:0:2d8:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:Also known as a Claidhmore, or Greatsword, this weapon is favoured
+D:by powerful mercenaries. The blade is large, straight, and broad,
+D:almost as large as a two-handed sword.
+
+N:547:& Espadon~
+G:|:W
+I:23:24:0
+W:40:0:200:600
+A:40/3
+P:0:2d9:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This is the strictly two-handed version of the bastard sword.
+D:The blade is of medium length, double-edged, and considerably
+D:heavy to wield.
+
+N:548:& Great Scimitar~
+G:|:W
+I:23:22:0
+W:40:0:240:500
+A:40/3
+P:0:4d5:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This is a larger version of the curved oriental blade.
+D:Runes of war decorate its golden hilt.
+
+
+### Trapping Kits
+
+N:549:Arrow
+G:`:r
+I:46:2:0
+W:10:0:60:150
+A:10/2:50/2
+F:SHOW_MODS
+D:It must be loaded with arrows, which will be
+D:fired at the monster who triggers the trap.
+
+N:550:Bolt
+G:`:o
+I:46:3:0
+W:20:0:220:300
+A:20/2:50/2
+F:SHOW_MODS
+D:It must be loaded with crossbow bolts, which will
+D:be fired at the monster who triggers the trap.
+
+N:551:& Fauchard~
+G:/:s
+I:22:6:0
+W:18:0:155:301
+A:18/2
+P:0:1d10:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:It is a type of glaive with two ornate hooks on the back
+D:of the blade. It is typically 8 to 9 feet long.
+
+N:552:& Guisarme~
+G:/:s
+I:22:16:0
+W:21:0:165:320
+A:21/1
+P:0:2d5:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:Mounted on a long shaft for maximum reach, this weapon is
+D:effective at repelling both cavalry and infantry.
+
+N:553:& Heavy Lance~
+G:/:s
+I:22:29:0
+W:43:0:400:700
+A:43/2
+P:0:4d8:0:0:0
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:This is a shock weapon. Its purpose is to unhorse a rider
+D:in single combat, or smash through the armour of opposing lines.
+
+N:554:& Basilard~
+G:|:w
+I:23:9:0
+W:15:0:80:220
+A:15/3
+P:0:1d8:0:0:0
+F:SHOW_MODS
+D:This is a two-edged dagger with a long blade. A favourite among travellers
+D:and warriors alike, because it can be worn comfortably with plain clothes
+D:as well as armour.
+
+### Trapping Kits
+
+N:555:Catapult
+G:`:R
+I:46:1:0
+W:1:0:50:40
+A:1/2:20/2
+F:SHOW_MODS
+D:It must be loaded with sling bullets, which will
+D:be fired at the monster who triggers the trap.
+
+N:556:& Ring Mail~
+G:[:s
+I:37:2:0
+W:20:0:200:500
+A:20/1
+P:12:1d4:-2:0:0
+D:A suit of non-overlapping metal rings sewn onto a
+D:heavy leather backing.
+
+N:557:& Cord Armour~
+G:(:y
+I:36:9:0
+W:5:0:80:40
+A:5/1
+P:6:1d1:0:0:0
+D:Fibres of hemp or other natural material woven and knotted
+D:into a thick, tough fabric.
+
+N:558:& Paper Armour~
+G:(:w
+I:36:3:0
+W:5:0:30:40
+A:5/2
+P:4:1d1:0:0:0
+F:SENS_FIRE
+D:Thickly pleated sheets of paper assembled together into
+D:a suit of armour. It is useful against arrows, but it may
+D:catch on fire quite easily.
+
+N:559:& Padded Armour~
+G:(:y
+I:36:10:0
+W:2:0:60:40
+A:2/1
+P:4:1d1:0:0:0
+D:Heavy, multi-layered cloth sewn together to cover the body,
+D:with extra padding between layers.
+
+### Trapping Kits
+
+N:560:Fumes
+G:`:G
+I:46:4:0
+W:2:0:20:50
+A:2/2:30/2
+D:It must be loaded with potions, which will splatter
+D:over the monster who triggers the trap.
+
+N:561:& Golden Ring Mail~
+G:(:y
+I:36:15:0
+W:35:0:150:500
+A:35/7
+P:8:1d4:-1:0:0
+D:A suit of non-overlapping thin golden rings sewn onto a soft leather
+D:backing. It looks beautiful, and is worn on special occasions.
+
+### Trapping Kits
+
+N:562:Magic
+G:`:g
+I:46:5:0
+W:5:0:20:50
+A:5/2:40/2
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC
+D:It must be loaded with scrolls, which will release
+D:their spells at the monster who triggers the trap.
+
+N:563:Device
+G:`:v
+I:46:6:0
+W:20:0:20:50
+A:20/2:40/2:60/2
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC
+D:It must be loaded with a magic device (wand, staff, or rod), which
+D:will fire its spell at the monster who triggers the trap.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+N:569:Nothing
+G:-:d
+I:66:0:1
+W:5:0:10:50
+A:5/1
+P:0:1d1:0:0:0
+
+
+#Artifact Potion
+N:573:& Blood~ of Life
+G:!:d
+I:71:3:200
+W:70:0:4:10000
+A:70/16
+P:0:1d1:0:0:0
+T:71:2
+F:NORM_ART | FULL_NAME
+D:This magical potion contains a small part of the power of
+D:Eru Iluvatar on Middle-Earth.
+
+# XXX
+# XXX
+# XXX
+
+# Mage staffs (for Sorcerers to wield.)
+
+N:577:& Mage Staff~
+G:\:B
+I:6:1:0
+W:5:0:12:300
+A:5/1:20/1:50/1:80/1
+P:0:1d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:It looks like a simple walking stick, plain and nondescript.
+D:In the hands of a spellcaster, it can be a deadly weapon.
+
+# An extra ring, out of place
+
+N:578:Lightning
+G:=:d
+I:45:56:0
+W:50:0:2:3000
+A:50/1
+P:0:0d0:0:0:15
+a:HARDCORE=BA_ELEC_4
+F:RES_ELEC | ACTIVATE
+f:RES_ELEC | IGNORE_ELEC
+D:This sparkling circlet grants you protection, makes electricity less
+D:dangerous and even allows you to call forth a ball of lightning.
+
+# XXX
+# XXX
+# XXX
+
+# The Ring of Flare -- see artifact list
+# Gone in Theme.
+#N:582:& Ring~
+#G:=:y
+#I:45:52:5
+#W:50:25:2:75000
+#F:INSTA_ART
+
+N:583:Invisibility
+G:!:d
+I:71:8:0
+W:3:0:4:50
+A:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This magical brew will temporarily hide you from sight, and also attunes you to this state so
+D:that your eyes can still perceive your hidden form.
+
+# Potion of Corruption
+
+N:585:Corruption
+G:!:d
+I:71:10:0
+W:10:0:4:0
+A:10/1:17/1:27/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This concoction of toxic wastes will strangely warp your shape.
+
+# Ring of Invisibility
+
+N:586:Invisibility
+G:=:d
+I:45:53:4
+W:50:0:2:10000
+A:50/1
+F:INVIS | HIDE_TYPE
+f:INVIS |
+D:This magical bauble will hide you from sight.
+
+# XXX
+
+######### Here are the parchments ########
+
+N:588:Deep Thoughts
+G:?:o
+I:8:0:0
+W:3:0:5:50
+A:3/1
+D:This parchment contains the thoughts of a powerful
+D:wizard who departed Middle-earth long ago.
+
+N:589:More Deep Thoughts
+G:?:o
+I:8:1:0
+W:4:0:5:50
+A:4/1
+D:This parchment contains the thoughts of a powerful
+D:wizard who departed Middle-earth long ago.
+
+N:590:Compendium of Deep Thoughts
+G:?:o
+I:8:2:0
+W:5:0:5:50
+A:5/1
+D:This parchment contains the thoughts of a powerful
+D:wizard who departed Middle-earth long ago.
+
+# Artifact Lore - Edged weapons
+N:591:Artifact Lore Vol. I
+G:?:o
+I:8:6:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Hafted weapons
+N:592:Artifact Lore Vol. II
+G:?:o
+I:8:7:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Polearms
+N:593:Artifact Lore Vol. III
+G:?:o
+I:8:8:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+N:594:Monstrous Compendium 1
+G:?:o
+I:8:9:0
+W:10:0:5:100
+A:10/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:595:Monstrous Compendium 2
+G:?:o
+I:8:10:0
+W:11:0:5:200
+A:11/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:596:Monstrous Compendium 3
+G:?:o
+I:8:11:0
+W:12:0:5:300
+A:12/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:597:Monstrous Compendium 4
+G:?:o
+I:8:12:0
+W:13:0:5:400
+A:13/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:598:Monstrous Compendium 5
+G:?:o
+I:8:13:0
+W:14:0:5:500
+A:14/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:599:Monstrous Compendium 6
+G:?:o
+I:8:14:0
+W:15:0:5:600
+A:15/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:600:Monstrous Compendium 7
+G:?:o
+I:8:15:0
+W:16:0:5:700
+A:16/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:601:Monstrous Compendium 8
+G:?:o
+I:8:16:0
+W:17:0:5:800
+A:17/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:602:Monstrous Compendium 9
+G:?:o
+I:8:17:0
+W:18:0:5:900
+A:18/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:603:Monstrous Compendium 10
+G:?:o
+I:8:18:0
+W:19:0:5:1000
+A:19/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+N:604:Monstrous Compendium 11
+G:?:o
+I:8:19:0
+W:20:0:5:1200
+A:20/2
+D:This parchment contains a small part of the collected
+D:lore concerning monsters inhabiting Arda.
+
+#### Here come the shape-shifting potions. ####
+
+N:605:& Morphic Oil~ of #
+G:!:d
+I:72:1:0
+W:5:0:4:100
+A:1/3:5/1:10/1
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This concoction can transform your body for a short period of time.
+
+### New Parchments for Theme - monster and artifact spoilers
+
+# XXX
+
+# Artifact Lore - Axes
+N:607:Artifact Lore Vol. IV
+G:?:o
+I:8:22:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Shooters and missiles
+N:608:Artifact Lore Vol. V
+G:?:o
+I:8:23:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Musical instruments
+N:609:Artifact Lore Vol. VI
+G:?:o
+I:8:24:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Body armour
+N:610:Artifact Lore Vol. VII
+G:?:o
+I:8:25:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Cloaks
+N:611:Artifact Lore Vol. VIII
+G:?:o
+I:8:26:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Shields and Boots
+N:612:Artifact Lore Vol. IX
+G:?:o
+I:8:27:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Headgear and Gloves
+N:613:Artifact Lore Vol. X
+G:?:o
+I:8:28:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Gothmog's set and other sets
+N:614:Artifact Lore Vol. XI
+G:?:o
+I:8:29:0
+W:40:0:5:1000
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Light sources
+N:615:Artifact Lore Vol. IX
+G:?:o
+I:8:30:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Amulets and Rings
+N:616:Artifact Lore Vol. X
+G:?:o
+I:8:31:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# Artifact Lore - Tools
+N:617:Artifact Lore Vol. XI
+G:?:o
+I:8:32:0
+W:40:0:5:500
+A:40/3
+D:This parchment contains information about unique
+D:artifacts that are rumoured to exist upon Arda.
+
+# The Mimic's cloaks
+
+N:618:& #~
+G:(:y
+I:35:100:0:50
+W:5:130:30:100
+A:5/1:15/1:35/1:55/1:75/1
+P:1:1d1:0:0:0
+D:Combined with proper skill, this cloak can make you seem
+D:like a different creature. Otherwise, it just provides some
+D:extra protection.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+# Here are the corpses
+
+N:641:corpse
+G:~:U
+I:9:1:3000
+W:20:0:80:0
+A:30/1
+P:0:1d1:0:0:0
+F:DECAY
+D:A decaying corpse.
+
+N:642:skeleton
+G:~:U
+I:9:2:800
+W:20:0:2:0
+A:30/1
+P:0:1d1:0:0:0
+D:The bony remains of some creature.
+
+N:643:head
+G:~:U
+I:9:3:600
+W:20:0:10:0
+A:30/1
+P:0:1d1:0:0:0
+F:DECAY
+D:A severed head.
+
+N:644:skull
+G:~:U
+I:9:4:1000
+W:20:0:20:0
+A:30/1
+P:0:1d1:0:0:0
+D:A white bony skull.
+
+N:645:raw meat
+G:~:U
+I:9:5:1200
+W:20:0:10:2
+A:30/1
+P:0:1d1:0:0:0
+F:DECAY
+D:A piece of raw meat.
+
+N:646:& Great Eagle Down Coat~
+G:(:y
+I:36:16:0
+W:5:0:60:400
+A:25/1
+P:9:1d1:0:0:0
+F:RES_FIRE | RES_COLD |
+D:This coat is made from the down of Manwe's Great Eagles,
+D:gathered painstakingly from nests. It is magical, protecting
+D:the wearer from extremes of temperatures.
+
+# The Key to Orthanc -- see artifact list
+N:647:& Key~
+G:~:g
+I:39:106:0
+W:15:0:15:20000
+F:INSTA_ART | SPECIAL_GENE
+
+# Here are the boomerangs
+
+N:648:& Small Wooden Boomerang~
+G:{:y
+I:15:1:0
+W:1:0:60:10
+A:1/1:5/2:10/2:20/2
+P:0:1d4:0:0:0
+D:A small curved piece of wood.
+
+N:649:& Wooden Boomerang~
+G:{:y
+I:15:2:0
+W:10:0:60:100
+A:10/1:20/2
+P:0:1d8:0:0:0
+D:A curved leaf-shaped piece of wood.
+
+N:650:& Small Metal Boomerang~
+G:{:y
+I:15:3:0
+W:20:0:60:400
+A:20/1:30/2
+P:0:3d4:0:0:0
+D:A small curved piece of wood with metal blades on the "forward" edges.
+
+N:651:& Metal Boomerang~
+G:{:y
+I:15:4:0
+W:30:0:60:800
+A:30/1:50/2
+P:0:4d5:0:0:0
+D:A curved leaf-shaped piece of wood, its "forward" edges enhanced with metal blades.
+
+# The Space-Time Anchor -- see artifact list
+N:652:& Anchor~
+G:~:v
+I:39:105:0
+W:30:0:15:50000
+F:INSTA_ART
+
+# To convert monsters into objects for wielding them ! ! ! :)
+# Funny, funny, funny :)
+# pval the monster idx, pval2 for the monster hp
+N:653:& ~
+G:~:y
+I:99:1:0
+W:127:200:60:0
+A:127/255
+P:0:0d0:0:0:0
+
+N:654:Summon Never-Moving Pet
+G:?:d
+I:70:6:0
+W:5:0:5:125
+A:5/1:15/1:25/1:35/1:65/1:85/1:95/1
+D:A piece of paper, inscribed with runes which will summon an immobile creature to your aid.
+
+# XXX
+# XXX
+
+###The potions of cure insanity, in light, medium, regular, and full
+###versions. Cure light's W:x entry reduced to 1, so it doesn't boost level rating when appearing
+###at 50' - nyra
+
+N:657:Cure Light Insanity
+G:!:d
+I:72:14:0
+W:1:5:4:15
+A:5/1:1/1:3/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A magical potion which drives away irrational quirks of behaviour.
+
+N:658:Cure Serious Insanity
+G:!:d
+I:72:15:0
+W:10:5:4:40
+A:10/1
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:A magical brew which will lift shadows that have been cast on your soul.
+
+N:659:Cure Critical Insanity
+G:!:d
+I:72:16:0
+W:15:5:4:100
+A:15/3
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This drink will cure you even of serious mental disorders.
+
+N:660:Cure Insanity
+G:!:d
+I:72:17:0
+W:25:5:4:300
+A:25/3
+P:0:1d1:0:0:0
+F:FOUNTAIN
+D:This blessed potion can make you completely sane and healthy, even if you have only the
+D:faintest shred of sanity left.
+
+# The Phial of Undeath -- see artifact list. He he he he...
+
+#N:661:& Phial~
+#G:~:y
+#I:39:103:0
+#W:1:0:10:0
+#P:0:1d1:0:0:0
+#F:INSTA_ART
+
+# Here is the random artifact type.
+# This is used as a template -- the sval will be chosen later
+# on in the game to be an index to the random_artifacts array,
+# which in turn determines:
+#
+# Name
+# Color
+# Level
+# Cost
+
+N:662:Random Artifact
+G:~:o
+I:102:0:0
+W:1:0:50:0
+A:1/1:10/1:20/1:30/1
+F:INSTA_ART | ACTIVATE | ACTIVATE_NO_WIELD
+
+N:663:Craftsmanship
+G:?:d
+I:70:19:0
+W:80:0:5:200000
+A:80/16
+D:A powerful scroll, desired by many, as it can magically improve the special powers of magical
+D:weaponry.
+
+# A Parchment, not the Artifact
+N:664:The One Ring
+G:?:s
+I:8:4:0
+W:10:100:5:50
+A:10/2
+D:This parchment contains words in the Black Speech and Westron,
+D:and they seem to speak of a powerful Ring... could it be true?
+
+# XXX 665 - 668 were the old music books
+
+### Musical Instruments ###
+
+N:669:& Horn~
+G:/:W
+I:14:60:1
+W:7:0:30:400
+A:7/2:20/1:40/1:80/1
+P:0:1d1:0:0:0
+F:CON | ACTIVATE | WIELD_CAST
+D:A simple wind instrument made from brass. If used by inexperienced musicians it sounds
+D:like somebody making "prbbt!" noises down a drainpipe.
+
+N:670:& Drum~
+G:/:W
+I:14:58:1
+W:7:0:30:400
+A:7/2:20/1:40/1:80/1
+P:0:1d1:0:0:0
+F:STR | WIELD_CAST
+D:A sort of clay pot with a bit of skin stretched over its mouth.
+
+N:671:& Harp~
+G:/:W
+I:14:59:1
+W:7:0:30:400
+A:7/2:20/1:40/1:80/1
+P:0:1d1:0:0:0
+F:CHR | WIELD_CAST
+D:A number of strings held by a wooden frame.
+
+# XXX
+# XXX
+
+# The Palantir of Orthanc -- see artifact list
+
+N:675:& Palantir~
+G:~:y
+I:39:104:0
+W:75:0:200:100000
+P:0:10d10:0:0:0
+F:INSTA_ART
+
+### The Monster Egg template; note the theoretical weight of 3 lbs ###
+
+N:676:Egg
+G:,:W
+I:10:1:0
+W:5:0:30:100
+A:5/1:15/1:25/1:35/1
+P:0:1d1:0:0:0
+F:ACTIVATE | ACTIVATE_NO_WIELD
+
+### Two more scrolls ###
+
+N:677:Reset Recall
+G:?:d
+I:70:23:0
+W:20:0:5:125
+A:20/1:25/1:35/1
+D:A strange formula is inscribed on this scroll, which allows you to define another place as the
+D:location to which recalls shall move you.
+
+N:678:Divination
+G:?:d
+I:70:31:0
+W:20:0:5:600
+A:30/1:45/1:55/1
+D:This scroll is inscribed with a ritual which allows you to discern what fate holds in store for
+D:you.
+
+### Here comes the Runes ###
+
+N:679:Self
+G:?:b
+I:105:0:0
+W:3:5:2:40
+A:3/1
+P:0:1d1:0:0:0
+F:EASY_KNOW
+D:A rune signifying the caster.
+
+N:680:Ray
+G:?:b
+I:105:2:0
+W:10:5:2:300
+A:10/1
+P:0:1d1:0:0:0
+F:IGNORE_COLD | IGNORE_ELEC | EASY_KNOW
+D:A rune signifying a beam or ray.
+
+N:681:Sphere
+G:?:b
+I:105:3:0
+W:15:5:2:1000
+A:15/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | EASY_KNOW
+D:A rune signifying a ball or sphere.
+
+N:682:Knowledge
+G:?:b
+I:104:91:0
+W:6:5:2:200
+A:6/1
+P:0:1d1:0:0:0
+F:EASY_KNOW
+D:A rune signifying knowledge.
+
+N:683:Life
+G:?:D
+I:104:53:0
+W:3:5:2:200
+A:3/1
+P:0:1d1:0:0:0
+F:EASY_KNOW
+D:A rune signifying life.
+
+N:684:Fire
+G:?:r
+I:104:5:0
+W:10:5:2:300
+A:10/1
+P:0:1d1:0:0:0
+F:IGNORE_FIRE | EASY_KNOW
+D:A rune signifying flame.
+
+N:685:Cold
+G:?:b
+I:104:4:0
+W:12:5:2:300
+A:12/1
+P:0:1d1:0:0:0
+F:IGNORE_COLD | EASY_KNOW
+D:A rune signifying cold.
+
+N:686:Lightning
+G:?:W
+I:104:1:0
+W:13:5:2:300
+A:13/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC | EASY_KNOW
+D:A rune signifying a lightning beam.
+
+N:687:Acid
+G:?:B
+I:104:3:0
+W:16:5:2:300
+A:16/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | EASY_KNOW
+D:A rune signifying acid.
+
+N:688:Element
+G:?:g
+I:104:10:0
+W:23:5:2:1000
+A:23/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | EASY_KNOW
+D:A rune signifying an element.
+
+N:689:Chaos
+G:?:v
+I:104:30:0
+W:26:5:2:2000
+A:26/1
+P:0:1d1:0:0:0
+F:ATTR_MULTI
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | EASY_KNOW
+D:A rune signifying raw chaos.
+
+N:690:Mind
+G:?:D
+I:104:85:0
+W:19:5:2:3000
+A:19/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC | EASY_KNOW
+D:A rune signifying the mind.
+
+N:691:Holding
+G:?:B
+I:104:75:0
+W:5:5:2:500
+A:5/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | EASY_KNOW
+D:A rune signifying the action of holding, or sleep.
+
+N:692:Arrow
+G:?:b
+I:105:1:0
+W:6:5:2:100
+A:6/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC | EASY_KNOW
+D:A rune signifying an arrow.
+
+N:693:Power Surge
+G:?:b
+I:105:4:0
+W:50:5:2:5000
+A:50/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | IGNORE_ACID | EASY_KNOW
+D:A rune signifying a powerful surge.
+
+N:694:Armageddon
+G:?:b
+I:105:5:0
+W:30:5:2:4000
+A:30/1
+P:0:1d1:0:0:0
+F:IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | IGNORE_ACID | EASY_KNOW
+D:A rune signifying a powerful blast.
+
+N:695:Gravity
+G:?:G
+I:104:35:0
+W:16:5:2:300
+A:16/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | EASY_KNOW
+D:A rune signifying the forces of gravity.
+
+# XXX
+
+N:697:Undeath
+G:?:G
+I:104:92:0
+W:35:5:2:1000
+A:35/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | EASY_KNOW
+D:A rune signifying undeath.
+
+N:698:Protection
+G:?:G
+I:104:74:0
+W:45:5:2:1500
+A:45/1
+P:0:1d1:0:0:0
+F:IGNORE_ACID | EASY_KNOW
+D:A rune signifying protection.
+
+# XXX
+
+# The Ring of Precognition (now a k_info.txt artifact)
+N:700:& Ring~ of Precognition
+G:=:d
+I:45:51:0
+W:90:0:2:300000
+A:90/100
+T:45:23
+F:PRECOGNITION |
+f:PRECOGNITION |
+F:NORM_ART | FULL_NAME
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:This magical ring allows you to know what you will encounter in the near future.
+
+# Athelas, cures Black Breath
+
+N:701:& Sprig~ of Athelas
+G:,:g
+I:80:40:0
+W:25:5:2:450
+A:25/2:55/1:85/1
+D:A sprig of a healing plant brought to Middle-Earth by the Numenoreans. Also known
+D:as Kingsfoil, it will cure you from the ravages of the Black Breath.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+# The Scroll of Deincarnation (now an artifact)
+
+N:720:& Old Scroll~ of Deincarnation
+G:?:d
+I:70:40:0
+W:90:0:5:160000
+A:90/140
+T:70:51
+F:NORM_ART | FULL_NAME
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:It allows you to leave your body to reincarnate into
+D:another one. However, your current body is lost in the process.
+
+N:721:& Dark Sword~
+G:|:D
+I:23:33:0
+W:25:0:70:500
+A:25/1:80/2
+P:0:3d7:0:0:0
+F:SHOW_MODS | ANTIMAGIC_50
+f:ANTIMAGIC_50
+D:A strange, very sharp long sword, which seems to drain light from its surroundings. As you
+D:wield it, you feel much less attuned to magic.
+
+N:722:Numenorean for Beginners (I)
+G:?:s
+I:8:101:0
+W:10:100:5:100
+A:10/2
+D:These ancient words still contain magic.
+
+N:723:Numenorean for Beginners (II)
+G:?:s
+I:8:102:0
+W:5:100:5:150
+A:5/2
+D:These ancient words still contain magic.
+
+N:724:Advanced Lessons of Numenorean
+G:?:s
+I:8:103:0
+W:20:100:5:300
+A:20/2
+D:These ancient words still contain magic.
+
+N:725:Advanced Lessons of Sindarin
+G:?:s
+I:8:104:0
+W:20:100:5:400
+A:20/2
+D:These ancient words still contain magic.
+
+##### Junk #####
+
+N:726:& Shard~ of Pottery
+G:~:r
+I:11:3:0
+W:0:0:5:0
+A:0/1
+P:0:1d1:0:0:0
+F:EASY_KNOW
+D:A piece of clay that looks like it got broken off something.
+
+N:727:& Broken Stick~
+G:~:r
+I:11:6:0
+W:0:0:3:0
+A:0/1
+P:0:1d1:0:0:0
+F:EASY_KNOW
+D:A piece of rotten wood.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+N:738:& Book~ of Beginner Cantrips
+G:?:w
+I:111:50:0
+W:5:0:30:100
+A:5/1
+P:0:1d1:0:0:0
+D:A standard beginner's spellbook with some useful spells.
+D:The cover is blood-stained and weather-worn.
+
+N:739:& Book~ of Teleportation
+G:?:w
+I:111:51:0
+W:10:0:30:1000
+A:10/1
+P:0:1d1:0:0:0
+D:A standard spellbook with a few spells.
+D:The smell of the cover makes you think of wind.
+
+# XXX
+
+N:741:& Book~ of Summoning
+G:?:w
+I:111:52:0
+W:7:0:30:700
+A:7/1
+P:0:1d1:0:0:0
+D:A standard spellbook with a few spells.
+D:It smells like camel.
+
+# XXX
+
+# The Potion of Learning - no longer an artifact in Theme
+
+N:743:Learning
+G:!:d
+I:71:12:200
+W:99:2:2:100000
+A:99/10
+P:0:1d1:0:0:0
+F:EASY_KNOW
+D:This old potion is supposed to grant more learning power
+D:to its user.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+N:751:Khuzdul - The Hidden Tongue of the Dwarves
+G:?:s
+I:8:105:0
+W:2:100:5:50
+A:2/2
+D:These ancient words still contain magic.
+
+N:752:Nandorin for Dummies
+G:?:s
+I:8:106:0
+W:20:100:5:100
+A:20/2
+D:These ancient words still contain magic.
+
+N:753:Advanced Lessons of Orcish
+G:?:s
+I:8:107:0
+W:30:100:5:200
+A:30/2
+D:These ancient words still contain magic.
+
+# Here's the Ring of Flying
+N:755:Flying
+G:=:d
+I:45:54:0
+W:20:0:2:16000
+A:20/3
+F:FLY | EASY_KNOW
+f:FLY |
+D:This ring is imbued with the power of eagles. It grants you the power of flight.
+
+N:756:& Tome~ of the Time
+G:?:b
+I:111:8:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This tome seems to have trouble deciding whether it really exists now. Its flickering pages
+D:contain all that is known about the currents of time.
+
+N:757:& Spellbook~ of #
+G:?:w
+I:111:255:0
+W:10:0:30:200
+A:10/1:20/1:30/1:40/1:50/1:60/1:70/1
+P:0:1d1:0:0:0
+D:This book contains a single spell within its pages.
+
+N:758:& Tome~ of Meta Spells
+G:?:v
+I:111:9:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | IGNORE_FIRE | ATTR_MULTI
+D:This tome gives you deeper insights on the works of magic.
+
+N:759:& Tome~ of the Mind
+G:?:B
+I:111:10:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This tome has no pages; knowledge is transferred to you if you simply
+D:hold it.
+
+N:760:& Holy Tome~ of Eru Iluvatar
+G:?:G
+I:111:20:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This dusty tome is filled with ancient rituals,
+D:designed to uncover all that is hidden.
+
+N:761:& Holy Tome~ of Manwe Sulimo
+G:?:B
+I:111:21:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:A large jewel-encrusted tome that transfers
+D:wisdom and understanding to its bearer.
+
+N:762:& War Tome~ of Tulkas
+G:?:R
+I:111:22:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This tome fills you with glorious visions of total devastation.
+D:Anyone in your way shall be destroyed.
+
+N:763:& Unholy Tome~ of the Hellflame
+G:?:v
+I:111:11:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | ATTR_MULTI
+D:This singed book smells like burned flesh. Its power is as evident
+D:as its thirst for your blood.
+
+N:764:& Corrupted Tome~ of Melkor
+G:?:D
+I:111:23:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:A black and scarlet flame springs from this tome, issuing
+D:a thunderous roar, and you hear the screams of tormented souls.
+
+N:765:& Ironclad Tome~ of Aule
+G:?:s
+I:111:63:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:The sleek black cover of this tome is covered with intricate
+D:carved decorations, inset with rubies that sparkle like fire.
+
+N:766:& Shining Tome~ of Varda
+G:?:y
+I:111:64:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This tome's cover and pages radiate a soft white light.
+
+N:767:& Ocean Tome~ of Ulmo
+G:?:B
+I:111:65:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:This book smells faintly of seaweed and appears to be wet.
+
+N:768:& Forest Tome~ of Yavanna
+G:?:G
+I:111:24:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:The cover of this tome reminds you of tree bark.
+D:You feel the smell of grass and flowers as you read it.
+
+# for the Library Quest
+# Tome of PLAYER
+N:769:Tome of#
+G:?:v
+I:111:61:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW | ATTR_MULTI | SPECIAL_GENE
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD | NORM_ART
+D:This book has some of your favourite spells inside.
+
+# The Ring of Phasing -- see artifact list
+
+N:770:& Ring~
+G:=:d
+I:45:55:0
+W:110:0:2:300000
+A:110/5
+F:INSTA_ART | SPECIAL_GENE
+
+N:771:& Holy Tome~ of Mandos
+G:?:w
+I:111:66:0
+W:50:0:30:25000
+A:50/4
+P:0:1d1:0:0:0
+F:FULL_NAME | EASY_KNOW
+D:Just holding this tome makes you fill with quiet strength.
+
+# XXX #
+# XXX #
+# XXX #
+# XXX #
+
+# Rod Tip of Home Summoning: now an artifact
+#N:776:& Great Rod Tip~ of Home Summoning
+N:776:Home Summoning
+G:-:d
+I:66:30:75
+W:90:0:15:150000
+A:100/14
+P:0:1d1:0:0:0
+T:66:1
+F:NORM_ART | FULL_NAME
+F:IGNORE_FIRE | IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC
+D:This rod creates a little hatch, allowing access to your home no matter how far away it is.
+
+# Additional swords
+N:777:& Shadow Blade~
+G:|:D
+I:23:32:1
+W:50:900:45:2000
+A:48/4:60/2:80/1
+P:0:4d4:-2:2:0
+F:IGNORE_ACID | RES_DARK | STEALTH
+f:STEALTH
+D:A thin long sword made of a completely black metal, which reflects no light.
+
+N:778:& Bluesteel Blade~
+G:|:b
+I:23:31:0
+W:60:1800:50:6000
+A:60/20
+P:0:1d6:4:0:0
+F:SHOW_MODS | VORPAL
+D:A small sword made of a blueish metal with a strangely rough surface. As anything is hurt
+D:with it, the weapon will stick inside the wound and cause horrible wounds when torn away.
+
+# Amulet
+N:779:the Serpents
+G:":G
+I:40:17:0
+W:25:0:3:10000
+A:25/1
+a:HARDCORE=BA_POIS_4
+F:RES_POIS | DEX | ACTIVATE
+D:A petrified serpent's tongue, hung on a thin chain to be clasped around your neck. It makes you
+D:like a snake, able to wriggle out of tight corners, impervious to poisons and poisonous
+D:yourself.
+
+# XXX
+# XXX
+# XXX
+# XXX
+# XXX
+
+# The Nine Rings for mortal men doomed to die! When a Nazgul is
+# destroyed, it drops a Ring of Power with random powers.
+
+N:785:Ring~ of Power
+G:=:d
+I:45:5:0
+W:100:0:2:1
+A:100/100
+F:INVIS | DRAIN_EXP | CURSED | HEAVY_CURSE | CURSE_NO_DROP
+f:INVIS
+F:SPECIAL_GENE | FULL_NAME
+
+# To help people climb mountains...
+
+N:786:& Climbing Set~
+G:`:B
+I:12:0:0
+W:40:0:2:50000
+A:40/3
+F:CLIMB
+f:CLIMB
+D:A bunch of screws and hooks, a small pick and a very long rope. As long as a wall or rock face
+D:isn't really high, this collection of tools should help you across it.
+
+# Parchment to help beginners
+N:787:Adventurer's Guide to Middle-earth
+G:?:o
+I:8:20:0
+W:0:0:5:1
+A:0/1
+D:This parchment contains vital information no adventurer can live without.
+
+##### Demonblades #####
+N:788:& Demonblade~
+G:|:R
+I:115:55:0
+W:10:0:150:500
+A:10/1
+P:0:4d6:0:0:0
+F:SHOW_MODS | SLAY_DEMON | WIELD_CAST
+D:This blade has been taken from the corpse of a demon.
+D:Some demonic energy is still coursing through it, helping
+D:you slay other demons.
+
+N:789:& Demonshield~
+G:]:R
+I:115:56:0
+W:15:0:70:500
+A:15/1
+P:5:1d1:0:0:0
+F:REGEN | WIELD_CAST
+D:This shield has been taken from the corpse of a demon.
+D:Some demonic energy is still coursing through it, giving
+D:life to any that wield it.
+
+N:790:& Demonhorn~
+G:[:R
+I:115:57:0
+W:20:0:30:500
+A:20/1
+P:2:1d1:0:0:0
+F:LITE2 | WIELD_CAST
+D:This horn is about six feet long, and originates from a demon.
+D:Some demonic energy is still coursing through it.
+
+# XXX
+# XXX
+
+### Rods ###
+
+N:793:& Wooden Rod~ of#
+G:-:u
+I:67:10:0
+W:10:0:15:100
+A:5/1:10/1
+P:0:1d1:0:0:0
+D:The most common rod of all. It's the wood of oak, cut at midnight by a fair maiden.
+
+N:794:& Copper Rod~ of#
+G:-:s
+I:67:20:0
+W:15:0:15:200
+A:15/1
+P:0:1d1:0:0:0
+D:This is the common rod of the dwarves. It is created by chanting incessantly for 48 hours.
+
+N:795:& Iron Rod~ of#
+G:-:D
+I:67:50:0
+W:20:0:15:500
+A:20/1
+P:0:1d1:0:0:0
+D:This is the better version of the copper rod. It has been forged with iron that comes from
+D:the greatest depths, where even the Dwarves fear to go.
+
+N:796:& Moonstone Rod~ of#
+G:-:U
+I:67:75:0
+W:25:0:15:750
+A:25/1
+P:0:1d1:0:0:0
+D:This rod has been fashioned from moonrock. Its alien nature gives it quite a bit of capacity.
+
+N:797:& Silver Rod~ of#
+G:-:s
+I:67:100:0
+W:30:0:15:1000
+A:30/1
+P:0:1d1:0:0:0
+D:This rod is used often used by court mages. Its creation costs an insane amount of gold.
+
+N:798:& Golden Rod~ of#
+G:-:y
+I:67:125:0
+W:40:0:15:1250
+A:40/2
+P:0:1d1:0:0:0
+D:These rods are rare, since finding gold that can withstand the great magic
+D:capacity that this rod holds is very difficult.
+
+N:799:& Mithril Rod~ of#
+G:-:B
+I:67:160:0
+W:50:0:15:1600
+A:50/5
+P:0:1d1:0:0:0
+D:The mithril of this rod comes from very deep, too deep. Unknown powers have been
+D:infused in this rod, making it the second most powerful type of rod on Middle-earth.
+
+N:800:& Tilkal Rod~ of#
+G:-:v
+I:67:200:0
+W:70:0:15:2000
+A:70/30
+P:0:1d1:0:0:0
+F:ATTR_MULTI
+F:IGNORE_ACID | IGNORE_FIRE | IGNORE_COLD | IGNORE_ELEC
+D:This is the rarest and most powerful kind of rod there is. Its material was once used
+D:to chain Melkor Bauglir in the Halls of Mandos, and only Aule knows the secret of its
+D:making. Treasure this rod greatly.
+
+N:801:& Greater Ration~ of Health
+G:,:g
+I:80:41:0
+W:90:0:2:60000
+A:90/70
+D:This food will, once eaten, permanently add 70 HP.
+
+# Scroll of Mass Resurrection - artifact scroll
+N:802:& Crumpled Scroll~ of Mass Resurrection
+G:?:d
+I:70:43:0
+W:55:0:5:0
+A:55/1
+T:70:1
+F:NORM_ART | FULL_NAME
+F:IGNORE_FIRE | IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC
+D:This magical scroll sends a call to the halls of Mandos, issuing forth all those who have been
+D:slain by the reader.
+
+### Axes ###
+
+N:803:& Cleaver~
+G:/:s
+I:24:2:0
+W:13:0:110:175
+A:13/1
+P:0:2d4:0:0:0
+F:SHOW_MODS
+D:A small axe with a heavy rectangular blade.
+
+N:804:& Light War Axe~
+G:/:s
+I:24:8:0
+W:16:0:140:300
+A:16/1
+P:0:2d5:0:0:0
+F:SHOW_MODS
+D:A broad-bladed axe, suited for battle.
+
+N:805:& Slaughter Axe~
+G:/:G
+I:24:30:0
+W:70:0:300:6000
+A:70/8
+P:0:5d7:0:0:0
+F:SLAY_ANIMAL | SHOW_MODS
+D:A huge axe, the sort used for slaughtering animals, this weapon is unusually deadly against
+D:natural creatures.
+
+N:806:& Runestone~
+G:?:v
+I:105:255:0
+W:10:5:2:300
+A:10/3:20/2:30/1:60/1
+P:0:1d1:0:0:0
+F:IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:A small oval stone. One surface is flat, as if something ought to be scratched or inscribed into
+D:it.
+
+N:807:& Fortune cookie~
+G:,:U
+I:80:42:500
+W:0:0:2:10
+A:0/1:5/1:10/1
+D:A small, sweet bakery product, with a scrap of paper inside.
+
+# 808 was Portable hole
+
+N:809:Critical Hits
+G:=:d
+I:45:59:0
+W:50:0:2:10000
+A:50/3
+F:CRIT
+f:CRIT
+D:A magical ring to make it likelier for the wearer to hit exceptionally heavily.
+
+# The Wand of Stone to Mud of Thrain
+N:810:& Wand~ of Digging of Thrain
+G:-:d
+I:65:26:-1:SPELL=Dig
+W:10:10:10:3200
+A:10/200
+P:0:10d10:0:0:0
+T:65:6
+F:RECHARGE | SPECIAL_GENE | EASY_USE | RECHARGED | NORM_ART | FULL_NAME
+D:The miner's friend. This wand was used by Thrain to dig into the
+D:walls of the dungeon. Its indestructible nature makes it quite useful.
+
+# The Staff of Holy Fire of Mithrandir
+N:811:& Gnarled Staff~ of Holy Fire of Mithrandir
+G:_:d
+I:55:22:-1:SPELL=Holy Fire of Mithrandir
+W:50:10:10:12000
+P:0:10d4:0:0:0
+A:50/200
+T:55:8
+F:RECHARGE | EASY_USE | RECHARGED | NORM_ART | FULL_NAME
+D:Mithrandir's staff that throws powerful fire attacks at all enemies. It
+D:can be recharged without blowing up, for it is built to hold
+D:much magical energy.
+
+### Summoner totems ###
+
+N:812:Partial Totem
+G:":v
+I:54:1:0
+W:10:10:10:120
+P:0:1d1:0:0:0
+A:10/200
+F:SPECIAL_GENE
+D:An item which a Summoner can use to animate a copy of a creature that
+D:only exists by the will of its master.
+
+N:813:True Totem
+G:":v
+I:54:2:0
+W:10:10:10:120
+P:0:1d1:0:0:0
+A:10/200
+F:SPECIAL_GENE
+D:An item which a Summoner can use to revive a true copy of a creature.
+
+### Holy relics for God Quests ###
+
+N:814:& Piece~ of the Relic of Eru
+G:~:v
+I:11:7:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to Priests of Eru. The relic now lies in pieces, hidden
+D:from all but but his most dedicated followers.
+
+N:815:& Piece~ of the Relic of Manwe
+G:~:v
+I:11:8:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to Priests of Manwe. The relic now lies in pieces, hidden
+D:from all but his most dedicated followers.
+
+N:816:& Piece~ of the Relic of Tulkas
+G:~:v
+I:11:9:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to worshippers of Tulkas. The relic now lies in pieces,
+D:hidden from all but his most dedicated followers.
+
+N:817:& Piece~ of the Relic of Melkor
+G:~:v
+I:11:10:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to Dark Priests. The relic now lies in pieces, hidden
+D:from all but the most faithful followers of Melkor.
+
+N:818:& Piece~ of the Relic of Yavanna
+G:~:v
+I:11:11:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | IGNORE_ACID
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to Druids. The relic now lies in pieces, hidden
+D:from all but the most faithful followers of Yavanna.
+
+### Dwarven Rings of Power were here
+
+# XXX #
+# XXX #
+# XXX #
+# XXX #
+# XXX #
+# XXX #
+
+### More God relics ###
+
+N:825:& Piece~ of the Relic of Aule
+G:~:v
+I:11:16:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | FULL_NAME
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to the Stonewrights. The relic now lies in pieces, hidden
+D:from all but the most faithful followers of Aule.
+
+N:826:& Piece~ of the Relic of Varda
+G:~:v
+I:11:17:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | FULL_NAME
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to the Priests of Varda. The relic now lies in pieces,
+D:hidden from all but the most faithful followers of Varda.
+
+N:827:& Piece~ of the Relic of Ulmo
+G:~:v
+I:11:18:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | FULL_NAME
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to the Priests of Ulmo. The relic now lies in pieces, hidden
+D:from all but the most faithful followers of Ulmo.
+
+N:828:& Piece~ of the Relic of Mandos
+G:~:v
+I:11:19:0
+W:0:0:0:1000
+A:0/1
+P:0:1d1:0:0:0
+F:SPECIAL_GENE | FULL_NAME
+F:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE |
+D:Although it looks like a piece of junk, it is actually part of an ancient
+D:relic belonging to the Priests of Mandos. The relic now lies in pieces,
+D:hidden from all but the most faithful followers of Mandos.
+
+# XXX Orome's relic goes here #
+# XXX Lorien/Nienna's relic goes here #
+
+### New items for the Theme module ###
+
+### Food ###
+
+N:831:& Pinch~ of Longbottom Leaf
+G:.:g
+I:80:45:10
+#Prized at stores :P
+W:1:1:1:300
+A:1/1
+D:It's chewing tobacco, and not very nutritious. It is said to
+D:contain great stress-relieving properties.
+
+# XXX #
+# XXX #
+# XXX #
+# XXX #
+
+N:836:& Jar~ of Honey
+G:~:y
+I:80:43:1000
+W:1:1:10:50
+A:1/1:5/1:10/1:15/1
+D:A clay jar filled with pure honey. You can 'E'at it.
+
+N:837:& Jug~ of Milk
+G:~:w
+I:80:44:1000
+W:1:1:10:50
+A:1/1
+D:A clay jug filled with fresh milk. You wonder how that is
+D:possible in the dungeon. You can drink it by pressing 'E'.
+
+### Amulets and rings ###
+
+N:838:of War
+G:":d
+I:40:3:3
+W:70:12:3:55000
+A:70/12
+F:BLOWS | STR | DEX
+F:AGGRAVATE | DRAIN_MANA | DRAIN_EXP
+D:This rare amulet will magically improve your fighting prowess
+D:greatly, but this improvement comes at a cost. Nothing can
+D:ignore the challenge this amulet magically issues when worn.
+
+N:839:of Life
+G:":d
+I:40:16:1
+W:70:12:3:100000
+A:70/12
+F:LIFE | SUST_CON | HOLD_LIFE | DRAIN_MANA
+D:This rare amulet will magically increase your life force and
+D:even prevent it from being sapped. However, wearing this
+D:amulet makes you feel less adept at using magic.
+
+# New jewelry from T-Plus by Ingeborg S. Norden
+# They reuse some svals and so colours will match. This will change when ToME3 comes out.
+
+N:840:Wizardry
+G:=:d
+I:45:10:2
+W:100:0:2:125000
+A:100/10
+F:MANA | SPELL | SPELL_CONTAIN | WIELD_CAST | HIDE_TYPE |
+f:IGNORE_ACID | IGNORE_COLD | IGNORE_ELEC | IGNORE_FIRE | SPELL |
+D:This powerful ring not only stores a chosen spell (which must be
+D:engraved by 'copying' it); it also improves the power of cast spells
+D:and augments the wearer's magical reserves.
+
+N:841:Vitality
+G:=:d
+I:45:11:2
+W:100:0:2:125000
+A:100/10
+F:SUST_STR | SUST_DEX | SUST_CON | REGEN |
+F:HOLD_LIFE | LIFE |
+F:HIDE_TYPE | ACTIVATE |
+a:HARDCORE=CURE_HUNGER
+f:SUST_STR | SUST_DEX | SUST_CON | REGEN |
+D:This valuable ring enhances and protects the wearer's life force in every way.
+
+N:842:Clear Thought
+G:=:d
+I:45:12:0
+W:100:0:2:125000
+A:100/10
+F:SUST_INT | SUST_WIS | RES_FEAR | RES_CONF |
+F:ACTIVATE | EASY_KNOW |
+a:HARDCORE=CURE_INSANITY
+f:SUST_INT | SUST_WIS |
+D:This valuable ring protects the wearer's intellect and intuition, as well as
+D:guarding him from most mental attacks. From time to time, the wearer can
+D:even purge himself of insanity.
+
+### New scroll ###
+N:846:Sterilise
+G:?:d
+I:70:54:0
+W:40:0:5:200
+A:30/1
+D:This scroll humanely neuters all nearby monsters.
+
+### Maps ###
+
+### Massimiliano Marangio's map ###
+N:847:Map of Middle-earth
+G:?:s
+I:8:204:0
+W:70:100:30:100000
+A:70/3
+D:A large map describing all lands of Middle-earth.
+
+# Map of Edoras
+N:848:Map of Edoras
+G:?:s
+I:8:205:0
+W:10:100:5:500
+D:A map of the capital city of Rohan.
+
+# Map of Esgaroth
+N:849:Map of Esgaroth
+G:?:s
+I:8:206:0
+W:15:100:5:1500
+D:A map of the city upon the Long Lake at the foot
+D:of the Lonely Mountain.
+
+# Map of Hobbiton
+N:850:Map of Hobbiton
+G:?:s
+I:8:207:0
+W:5:100:5:150
+D:A map of the famous Halfling village.
+
+# Map of Osgiliath
+N:851:Map of Osgiliath
+G:?:s
+I:8:208:0
+W:25:100:5:10000
+D:A map of the proud stronghold of Gondor.
+
+# Map of Pelargir
+N:852:Map of Pelargir
+G:?:s
+I:8:209:0
+W:25:100:5:10000
+D:A map of the great city of Men at the mouth
+D:of the Anduin river.
+
+# Map of Beorn's domain
+N:853:Map of Beorn's domain
+G:?:s
+I:8:210:0
+W:20:100:5:3000
+D:A map showing the location of the house of Beorn.
+
+# Map of Dale
+N:854:Map of Dale
+G:?:s
+I:8:211:0
+W:10:100:5:200
+D:A map of the area where Dale is being rebuilt.
+
+# Map of Henneth Annun
+N:855:Map of Henneth Annun
+G:?:s
+I:8:212:0
+W:70:100:5:30000
+D:A map showing the secret location of the Ranger
+D:outpost in Ithilien.
+
+# Map of Helm's Deep
+N:856:Map of Helm's Deep
+G:?:s
+I:8:213:0
+W:50:100:5:3000
+D:A map showing the location of the greatest
+D:fortress in Rohan.
+
+# Map of Thranduil's realm
+N:857:Map of Thranduil's realm
+G:?:s
+I:8:214:0
+W:60:100:5:8000
+D:A map showing the location of the secret realm
+D:of the Wood-elves.
+
+# Map of Imladris
+N:858:Map of Imladris
+G:?:s
+I:8:215:0
+W:60:100:5:9000
+
+### Axes from T-Plus ###
+
+N:859:& Bearded Axe~
+G:\:s
+I:24:3:0
+W:8:0:35:100
+P:0:1d6:0:0:0
+A:8/1:15/1
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A throwing-length axe with a "beard", an increased depth at the lower
+D:end of the blade. Surprisingly light and durable, it doubles as a
+D:wood-chopping implement in times of peace.
+
+N:860:& Double Axe~
+G:\:s
+I:24:4:0
+W:25:0:200:450
+P:0:3d6:0:0:0
+A:25/1:40/1
+F:SHOW_MODS | MUST2H
+f:MUST2H
+D:A mighty axe with two moon-shaped blades on each side of the headpiece,
+D:the immense weight leads to slow but powerful swings.
+
+N:861:& Crusader Axe~
+G:\:W
+I:24:6:0
+W:10:0:130:300
+A:10/1:20/1
+P:0:2d5:0:0:0
+F:SHOW_MODS
+D:The predecessor of the Battle Axe. Shorter and lighter, it delivers less
+D:of a punch, but is favored by mounted cavalry.
+
+N:862:& Reaper Axe~
+G:\:W
+I:24:7:0
+W:22:0:150:420
+A:22/1
+P:0:3d4:0:0:0
+F:SHOW_MODS | COULD2H
+f:COULD2H
+D:A large axe with an elongated moon shaped blade. Strikes a good balance
+D:between swinging power and speed.
+
+### New armour adapted from T-Plus (well, I had Mithril Helms before T-Plus
+### did, but they didn't work, so I took them out. :P)
+
+N:863:& Mithril Helm~
+G:]:B
+I:32:8:0
+W:50:0:60:2500
+P:7:1d2:0:0:5
+F:IGNORE_ACID
+D:A cone-shaped helm with cheekguards, made of True-silver.
+
+N:864:& Set~ of Mithril Gauntlets
+G:]:B
+I:31:4:0
+W:50:0:25:3500
+A:50/2
+P:4:1d2:0:0:5
+F:IGNORE_ACID
+D:Flexible and strong set of handguards, with a gripping
+D:surface and surprisingly smooth interior.
+
+N:865:& Small Mithril Shield~
+G:):B
+I:34:7:0
+W:50:0:65:5000
+A:50/2
+P:5:1d2:0:0:5
+F:IGNORE_ACID
+D:A light shield made of a metal alloy, with a mithril
+D:coating.
+
+### Added in Theme
+N:866:& Large Mithril Shield~
+G:):B
+I:34:8:0
+W:50:0:80:7000
+A:50/2
+P:8:1d2:0:0:10
+F:IGNORE_ACID
+D:A sturdy shield made of a metal alloy, with a mithril
+D:coating.
+
+### Artifacts ###
+
+# New artifacts needed for Erebor quest
+
+N:867:Map
+G:?:U
+I:8:33:0
+W:70:100:30:50000
+F:INSTA_ART |
+D:At first glance, this looks like another crumpled piece of paper.
+D:As you smooth out the parchment, you see the faint outline of a
+D:map... You have a feeling you might find use for this map one day.
+D:Better hang on to it, you never know when you might need it.
+
+N:868:& Key~
+G:-:W
+I:11:13:0
+W:70:100:5:50000
+F:INSTA_ART |
+D:As you clear away some mud from this item, you notice that it is
+D:actually a small silver key. You wonder what it opens. Perhaps
+D:you should hang on to this key, you might find it useful later.
+D:Better hang on to it, you never know when you might need it.
+
+# New artifact that acts as a junkart
+N:869:& Cup~
+G:+:y
+I:11:14:0
+W:70:100:50:100000
+F:INSTA_ART |
+D:It looks like a lump of clay, and as you prepare to throw it
+D:away, a piece breaks off, and you see a faint gleam of gold.
+D:Taking off the rest of the caked-on mud, you see that it is
+D:a golden cup with ornate jewels. It may hold hidden powers.
+
+# The Red Arrow of Gondor - see artifact list
+N:870:& Red Arrow~
+G:{:R
+I:11:15:0
+W:40:70:2:70000
+F:INSTA_ART
+D:As you clear away some dirt from this object, you notice that it is an arrow
+D:with steel barbs, black flights, and a red tip. Perhaps it isn't so useless.
+
+# The Sceptre of Numenor - see artifact list
+N:871:& Sceptre~
+G:|:B
+I:12:2:4
+W:50:40:24:80000
+F:INSTA_ART
+D:A beautiful golden sceptre of kings, encrusted with shining gems.
+
+# The Rod of Annuminas - see artifact list
+N:872:& Rod~
+G:|:G
+I:12:3:4
+W:60:50:24:80000
+F:INSTA_ART
+D:A royal sceptre made of gold and silver, inlaid with emeralds.
+
+# The Necklace of Girion - see artifact list
+N:873:& Necklace~
+G:":G
+I:40:4:5
+W:20:5:2:15000
+F:INSTA_ART
+
+# The Amulet of Faramir - see artifact list
+N:874:& Amulet~
+G:":B
+I:40:29:5
+W:10:2:2:10000
+F:INSTA_ART
+
+# The Black Banner of Gondor - see artifact list
+N:875:& Black Banner~
+G:~:D
+I:39:108:0
+W:60:30:50:50000
+F:LITE1 | INSTA_ART
+D:A strange banner of black thread rolled up as though it were a scroll.
+
+# The Pearl 'Nimphelos' - see artifact list
+N:876:& Pearl~
+G:~:w
+I:39:109:1
+W:20:10:10:40000
+P:0:1d1:0:0:0
+F:LITE3 | INSTA_ART | FULL_NAME
+D:A beautiful shining pearl, about the size of a dove's egg.
+
+# The Silmaril of Flames - see artifact list
+N:877:& Silmaril~
+G:*:R
+I:39:110:2
+W:75:90:200:100000
+P:0:10d10:0:0:0
+F:LITE2 | LITE3 | INSTA_ART | FULL_NAME
+D:A dazzling, mesmerizingly beautiful jewel, shining in pure white
+D:light with a slight tinge of red. It hurts your eyes to look at it,
+D:yet you cannot bear to turn away from it, either.
+
+# The Silmaril of the Seas - see artifact list
+N:878:& Silmaril~
+G:*:B
+I:39:111:2
+W:75:90:200:100000
+P:0:10d10:0:0:0
+F:LITE2 | LITE3 | INSTA_ART
+D:A dazzling, mesmerizingly beautiful jewel, shining in pure white
+D:light with a slight tinge of blue. It hurts your eyes to look at it,
+D:yet you cannot bear to turn away from it, either.
+
+### Golden Harp of Thorin - see artifact list.
+N:879:& Golden Harp~
+G:/:y
+I:14:59:2
+W:50:0:30:40000
+P:0:1d1:0:0:0
+F:INSTA_ART
+D:A musical instrument made of pure shining gold.
+
+### Map of the Northern Reaches
+
+N:880:Map of Forodwaith
+G:?:s
+I:8:216:0
+W:40:100:30:40000
+A:40/3
+D:A map showing the northern reaches of Middle-earth.
+
+N:881:& Ranger's Arrow~
+G:{:g
+I:17:3:0
+W:5:7:1:3
+P:0:2d6:0:0:0
+A:5/7:20/7:50/7
+F:SHOW_MODS
+F:SLAY_ANIMAL | ESP_ANIMAL
+D:A sharpened metal head on a piece of wood, fitted with decorative
+D:green feathers. You can use it for 'f'iring a bow.
+
+N:882:& Throwing Axe~
+G:/:s
+I:24:7:0
+A:0/2:5/2:10/2:20/2
+W:0:0:15:30
+P:0:1d3:0:0:0
+F:SHOW_MODS
+D:The smallest and lightest of its kind, this axe has a single blade
+D:with a sharp steel tip, counterbalanced by a pointed fluke.
+
+# Buckler adapted from FuryMod in Theme 1.1.5
+
+N:883:& Buckler~
+G:):U
+I:34:1:1
+W:10:9:50:10
+P:-30:1d1:0:0:0
+A:10/2:15/2:20/2
+F:BLOWS
+f:BLOWS
+D:A small, round fist-shield made of wood, with a central dome
+D:under which there is a handle. Generally used with smaller
+D:arms; the buckler does not afford much protection. Its chief
+D:use is as an aid in fighting.
+
+# Mithril boomerangs adapted from FuryMod in Theme 1.1.5
+
+N:884:& Small Mithril Boomerang~
+G:{:B
+I:15:3:0
+W:25:0:40:300
+A:25/1:35:/2
+P:0:2d5:0:0:0
+F:SHOW_MODS | IGNORE_ACID
+D:A small curved piece of wood with mithril blades on the "forward" edges.
+
+N:885:& Mithril Boomerang~
+G:{:B
+I:15:4:0
+W:35:5:40:1000
+A:35/1:50/2
+P:0:5d6:0:0:0
+F:SHOW_MODS | IGNORE_ACID
+D:A curved leaf-shaped piece of wood, its "forward" edges enhanced with mithril blades.
+
+# N: serial number : & object name~
+# G: symbol : color
+# I: tval : sval : pval
+# W: depth : rarity : weight : cost
+# P: base armor class : base damage : plus to-hit : plus to-dam : plus to-ac
+# A: depth/rarity : depth/rarity : etc
+# F: flag | flag | etc \ No newline at end of file
diff --git a/lib/mods/theme/edit/library.map b/lib/mods/theme/edit/library.map
new file mode 100644
index 00000000..2369fbd6
--- /dev/null
+++ b/lib/mods/theme/edit/library.map
@@ -0,0 +1,62 @@
+# Permanent wall
+F:X:63:3
+
+# Granite Wall
+F:#:57:3
+
+# Cobblestone Road
+F:O:200:3
+
+# Floor
+F:.:1:3
+
+# Lich
+F:l:200:3:518
+
+# Master lich
+F:L:200:3:658
+
+# Quest exit
+F:<:6:3
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X###############################################################X
+D:X#<OlOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#O#.###.#.###.#.###.#.###.#.###.O.###.#.###.#.###.#.###.#.###O#X
+D:X#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOL#X
+D:X###############################################################X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:4:4
diff --git a/lib/mods/theme/edit/maeglin.map b/lib/mods/theme/edit/maeglin.map
new file mode 100644
index 00000000..e3be9972
--- /dev/null
+++ b/lib/mods/theme/edit/maeglin.map
@@ -0,0 +1,85 @@
+# Created by Mynstral (mynstral@thehelm.com)
+# Made for PernAngband on 26/07/2001
+
+# Monsters starts awake
+N:0
+
+# Permanent wall
+F:X:63:3
+
+# Marker
+F:<:172:3
+
+# up stairs with maeglin
+F:{:6:3:825:0:0:0:0:0:0:2
+
+# Floor with dirt
+F:.:88:5
+
+# Floor with dirt with an Ettin
+F:e:88:5:621
+
+# Floor with dirt with a War Troll
+F:w:88:5:631
+
+# Floor with dirt with a Troll Chieftan
+F:t:88:5:799
+
+# Floor with dirt with a Snagga sapper
+F:s:88:5:251
+
+# Floor with dirt with an Orc Captain
+F:o:88:5:285
+
+# Floor with dirt with an Elite Uruk
+F:u:88:5:866
+
+# Floor with dirt with an Ancient blue dragon
+F:L:88:5:601
+
+# Floor with dirt with an Ancient bronze dragon
+F:Z:88:5:602
+
+# Floor with dirt with an Ancient white dragon
+F:W:88:5:617
+
+# Floor with dirt with an Ancient green dragon
+F:G:88:5:618
+
+# Floor with dirt with an Ancient black dragon
+F:B:88:5:624
+
+# Floor with dirt with an Ancient red dragon
+F:R:88:5:644
+
+# Floor with dirt with an Ancient gold dragon
+F:O:88:5:645
+
+# Floor with dirt with a Lesser Balrog
+F:U:88:5:996:0:0:0:0:0:0:2
+
+# Granite wall
+F:#:56:5
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X##..#########...#........###..R.....###.e...{X
+D:X#.wt.######..O....#s..#..##w.#..###.....#.t..X
+D:X#wBLe.####.U.###....##.U.#...##..u####.#####.X
+D:X#eRe.####..#..######.B...w...#.U#uuu##.#U...eX
+D:X##...#...G###s...##....##..####..##uu#B..##..X
+D:X####...e...#####.t...####...####.###u#####.w#X
+D:X###....##.w.######.e.#..##...###..##uu#e...##X
+D:X##..W#####...###.....#...##.e####.L##...#####X
+D:X##...######e.##Z..w.###.......####.###t.#####X
+D:X....########s....#s...##R..#.U.##..####..####X
+D:Xs..####....##.tU####...#####t...#.######..###X
+D:X#...##..##..#..######.t..e..##.w...#####w.###X
+D:X##.....####s..######.e.#.#t...#.#U.####..####X
+D:X#...####uu##.t..#####...e####s#........w.####X
+D:X...####uou...##...#####.....###..#####...####X
+D:X..#####uu##...###s.##........##..#####..#####X
+D:X.o.#######...e.###.....o.###s.##..###s...#..#X
+D:X#s..o#......#s.......u...####..#s.##...o.G...X
+D:Xsss##o....u###....u..o.o.#####........###.OZ.X
+D:X<ss...###############...##################U.#X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
diff --git a/lib/mods/theme/edit/misc.txt b/lib/mods/theme/edit/misc.txt
new file mode 100644
index 00000000..2d380202
--- /dev/null
+++ b/lib/mods/theme/edit/misc.txt
@@ -0,0 +1,91 @@
+# File: misc.txt
+
+# Maximum number of towns
+M:T:100
+
+# Maximum number of non random towns(must be < 20)
+M:t:17
+
+# Maximum x size of the wilderness
+M:X:101
+
+# Maximum y size of the wilderness
+M:Y:66
+
+# Maximum number of randart parts in ra_info.txt
+M:Z:519
+
+# Maximum number of monsters in r_info.txt
+# WARNING ! add one more to the real count for the player ghost !!
+M:R:1081
+
+# Maximum number of monsters in re_info.txt
+# WARNING ! Use the exact amount of ego types used, if not you
+# will get weird results !
+M:r:14
+
+# Maximum number of items in k_info.txt
+M:K:886
+
+# Maximum number of vaults in v_info.txt
+M:V:108
+
+# Maximum number of terrain features in f_info.txt
+M:F:249
+
+# Maximum number of alchemist recipes
+M:a:1000
+
+# Maximum number of artifacts in a_info.txt
+M:A:257
+
+# Maximum number of sets types in set_info.txt
+M:s:17
+
+# Maximum number of ego-items in e_info.txt
+M:E:238
+
+# Maximum number of dungeon types in d_info.txt
+M:D:41
+
+# Maximum number of trap types in tr_info.txt
+M:U:176
+
+# Maximum number of terrain types in wf_info.txt
+M:W:64
+
+# Maximum number of owners types in ow_info.txt
+M:N:215
+
+# Maximum number of building actions in ba_info.txt
+M:B:70
+
+# Maximum number of store types in st_info.txt
+M:S:89
+
+# Maximum size for "o_list[]"
+M:O:1024
+
+# Maximum size for "m_list[]"
+M:M:768
+
+# Maximum number of race types in p_info.txt
+M:P:R:24
+
+# Maximum number of subrace types in p_info.txt
+M:P:S:26
+
+# Maximum number of class types in p_info.txt
+M:P:C:50
+
+# Maximum number of meta class types in p_info.txt
+M:P:M:1
+
+# Maximum number of histories types in p_info.txt
+M:P:H:294
+
+# Maximum number of skills in s_info.txt
+M:k:60
+
+# Maximum number of traits in ab_info.txt
+M:b:50
diff --git a/lib/mods/theme/edit/nirnaeth.map b/lib/mods/theme/edit/nirnaeth.map
new file mode 100644
index 00000000..a8c06999
--- /dev/null
+++ b/lib/mods/theme/edit/nirnaeth.map
@@ -0,0 +1,64 @@
+# Permanent wall
+F:X:63:3
+
+# up stairs
+F:<:6:3
+
+# Floor with dirt
+F:.:1:5
+
+# Dirt (no-tele)
+F:s:88:5
+
+# Shallow water
+F:V:84:5
+
+# Dirt with Olog
+F:a:88:5:538:0:0:0:0:0:0:2
+
+# Dirt with Cave Troll
+F:b:88:5:496:0:0:0:0:0:0:2
+
+# Dirt with with Eldrak
+F:c:88:1:620:0:0:0:0:0:0:2
+
+# Dirt with with Ettin
+F:e:88:1:621:0:0:0:0:0:0:2
+
+# Dirt with with War troll
+F:f:88:1:631:0:0:0:0:0:0:2
+
+# Dirt with with Hru
+F:g:88:1:709:0:0:0:0:0:0:2
+
+# Dirt with Ulik the Troll
+F:h:88:5:729:0:0:0:0:0:0:2
+
+# Dirt with Ancient green dragon
+F:i:88:5:618:0:0:0:0:0:0:2
+
+# Dungeon
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X...a.bab....f.....f.XXXXXXXXXXX
+D:X..ab...b..ff..aa..b..XXXXXXXXXX
+D:X.aa..b..fff...a..g.f.b.XXXXXXXX
+D:Xab.....b....f.......f..bf..XXXX
+D:X..b.f......ff.f..aa...f..b.XXXX
+D:X...ff..f..ff.c.a..f.g.a..fXXXXX
+D:Xb.f....fff.ff...aaa....f..XXXXX
+D:X...ff...ff...f......aa..a..XXXX
+D:Xb.ff.a...f...bbb..a..aa.....XXX
+D:X.f.a...a....bbebb......f.fa.XXX
+D:X.....a.....bbecebb..g.a.a....XX
+D:X.a.a....aa.beccceb....f.a..c.XX
+D:X......a..f.bbecebba.f....ea...X
+D:XX.b.aa.f..f.bbebb...a.aa...g.aX
+D:XX..bb...a..f.bbb..a..a..aae..iX
+D:XXX....aa.aa.f...aa...e..b..h..X
+D:XXXXXX........bb...g....aa...gcX
+D:XXXXXXXX.g..aa...a...a.e...ac.<X
+D:XXXXXXXX........bb....e.c.i.e.iX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:3
diff --git a/lib/mods/theme/edit/numenor.txt b/lib/mods/theme/edit/numenor.txt
new file mode 100644
index 00000000..ec8621b1
--- /dev/null
+++ b/lib/mods/theme/edit/numenor.txt
@@ -0,0 +1,80 @@
+# File: numenor.txt
+
+# Way to the lost land of Numenor
+F:>:7:3:0:0:0:0:0:7
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW>VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:######################################################################################################################################################################################################
+
+
+############### Starting positions ###############
+
+# Standard starting position for normal races
+?:[EQU $LEAVING_QUEST 0]
+P:46:128
diff --git a/lib/mods/theme/edit/ow_info.txt b/lib/mods/theme/edit/ow_info.txt
new file mode 100644
index 00000000..bf1283fb
--- /dev/null
+++ b/lib/mods/theme/edit/ow_info.txt
@@ -0,0 +1,1419 @@
+# File: ow_info.txt
+
+
+# This file is used to initialize the "lib/raw/ow_info.raw" file, which is
+# used to initialize the "owner info type" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# N:<index>:<name>
+# I:<max_cost>:<max_inflate>:<min_inflate>:<haggle_per>:<insult_max>
+# C:<hated cost>:<normal cost>:<liked cost>
+# L:liked races
+# H:hated races
+
+# Version stamp (required)
+
+V:2.0.0
+
+# The zero index owner. If she owns a shop, there is a problem. :P
+N:0:Bell Goodchild(Hobbit)
+I:20000:170:108:5:15
+C:120:100:80
+L:Elf | Half-Elf | High-Elf | Dunadan | Hobbit | Dwarf | RohanKnight
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Druadan | Dark-Elf
+
+### The General Store - 1 ###
+
+N:1:Balin(Dwarf)
+I:25000:180:108:2:2
+C:150:100:50
+L:Dwarf | Petty-Dwarf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Troll
+
+N:2:Berylla Boffin(Hobbit)
+I:20000:190:109:3:4
+C:125:100:70
+L:Human | Hobbit
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+N:3:Adrahil(Half-Elf)
+I:30000:170:107:1:1
+C:110:100:80
+L:Half-Elf | High-Elf | Dunadan | Elf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll
+
+N:4:Aegnor(Wood-Elf)
+I:10000:200:110:4:8
+C:110:100:80
+L:High-Elf | Dunadan | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll | Easterling
+
+### The Armoury - 2 ###
+
+N:5:Bifur(Dwarf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Hobbit | Petty-Dwarf | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:6:Lalia Clayhanger(Hobbit)
+I:25000:180:108:2:2
+C:125:100:50
+L:Human | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:7:Alcarin(Human)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | Half-Elf | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Petty-Dwarf | Troll | Easterling
+
+N:8:Alatariel(High-Elf)
+I:30000:170:107:1:1
+C:110:100:80
+L:High-Elf | Dunadan | Elf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll | Easterling
+
+### The Weaponsmith - 3 ###
+
+N:9:Bofur(Dwarf)
+I:30000:170:107:1:1
+C:125:100:70
+L:Human | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:10:Daisy Gamgee(Hobbit)
+I:20000:190:109:3:4
+C:110:100:80
+L:Human | Hobbit
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:11:Beregond(Dunadan)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | High-Elf | Dunadan | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+N:12:Amarie(Dark-Elf)
+I:10000:200:110:4:8
+C:125:100:50
+L:Dark-Elf | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Dwarf | Troll | Easterling
+
+### The Temple - 4 ###
+
+N:13:Bombur(Dwarf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Half-Elf | Petty-Dwarf | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:14:Dora Baggins(Hobbit)
+I:30000:170:107:1:1
+C:110:100:80
+L:Human | High-Elf | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:15:Bergil(Half-Elf)
+I:10000:200:110:4:8
+C:125:100:50
+L:Human | Half-Elf | Dunadan | Elf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Troll | Easterling
+
+N:16:Amdir(Wood-Elf)
+I:25000:180:108:2:2
+C:110:100:80
+L:High-Elf | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll | Easterling
+
+### The Alchemist - 5 ###
+
+N:17:Borin(Dwarf)
+I:20000:190:109:3:4
+C:110:100:80
+L:Petty-Dwarf | Dwarf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Elf | Troll
+
+N:18:Elfstan Fairbairn(Hobbit)
+I:10000:200:110:4:8
+C:125:100:50
+L:Human | Half-Elf | High-Elf | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll
+
+N:19:Cemendur(Human)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | Half-Elf | RohanKnight | Dunadan | Elf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Troll | Easterling
+
+N:20:Annael(High-Elf)
+I:30000:170:107:1:1
+C:125:100:70
+L:Human | Half-Elf | High-Elf | Dunadan | Elf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll
+
+### The Magic Shop - 6 ###
+
+N:21:Dis(Dwarf)
+I:30000:170:107:1:1
+C:125:100:50
+L:Petty-Dwarf | Dwarf | Half-Elf | Dunadan
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Human | Troll | Eagle
+
+N:22:Folco Boffin(Hobbit)
+I:10000:200:110:4:8
+C:110:100:80
+L:Hobbit
+H:Dragon | Demon | Orc | Troll
+
+N:23:Ciryon(Dunadan)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | Half-Elf | High-Elf | RohanKnight | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+N:24:Arminas(Dark-Elf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Human | Dark-Elf | Elf
+H:Dragon | Demon | Beorning | Orc | High-Elf | Half-Ogre | Petty-Dwarf | Troll | Easterling
+
+### The Black Market - 7 ###
+
+N:25:Dori(Dwarf)
+I:30000:210:120:8:8
+C:110:100:90
+L:Dwarf | Easterling
+H:Dragon | Demon | Orc
+
+N:26:Halfred Greenhand(Hobbit)
+I:30000:210:120:8:8
+C:110:100:90
+L:Hobbit
+H:Dragon | Demon | Troll
+
+N:27:Deorwine(Half-Elf)
+I:30000:210:120:8:8
+C:110:100:90
+L:Half-Elf | Easterling
+H:Dragon | Demon | Dark-Elf
+
+N:28:Artanis(Wood-Elf)
+I:30000:210:120:8:8
+C:110:100:90
+L:High-Elf | Elf | Easterling
+H:Dragon | Demon | Orc | Troll
+
+### The Bookstore - 9 ###
+
+N:29:Dwalin(Dwarf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Human | Petty-Dwarf | Dwarf
+H:Dragon | Demon | Orc | Elf | Half-Ogre | Troll
+
+N:30:Tanta Hornblower(Hobbit)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Troll
+
+N:31:Dorlas(Human)
+I:30000:170:107:1:1
+C:150:100:50
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+N:32:Caranthir(High-Elf)
+I:25000:180:108:2:2
+C:110:100:80
+L:Half-Elf | High-Elf | Elf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll | Easterling
+
+### The Pet Shop - 0 ###
+
+N:33:Fili(Dwarf)
+I:20000:190:109:3:4
+C:125:100:70
+L:RohanKnight | Petty-Dwarf | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:34:Lalia Clayhanger(Hobbit)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Troll
+
+N:35:Elfwine(Dunadan)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | Half-Elf | High-Elf | RohanKnight | Dunadan | Elf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll
+
+N:36:Edrahil(Dark-Elf)
+I:30000:170:107:1:1
+C:150:100:50
+L:Dark-Elf | Elf | Easterling
+H:Dragon | Demon | Orc | High-Elf | Half-Ogre | Dwarf | Troll
+
+### The Mayors/Kings/Rulers ###
+
+#Bree
+N:37:Uldrik(Human)
+I:0:0:0:0:0
+C:0:0:0
+L:Human | RohanKnight | Dunadan | Hobbit |
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+#Minas Anor
+N:38:Aragorn (Dunadan)
+I:0:0:0:0:0
+C:0:0:0
+L:Human | High-Elf | RohanKnight | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Troll
+
+#Khazad-Dum
+N:39:Gimli(Dwarf)
+I:0:0:0:0:0
+C:0:0:0
+L:RohanKnight | Dunadan | Hobbit | Elf | Dwarf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+#Beorn's Halls
+N:40:Deor(Beorning)
+I:100:100:100:0:0
+C:110:100:90
+L:Beorning | Dwarf | Maia | Hobbit | Ent
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+#Dale
+N:41:Bard the Grim(Human)
+I:100:100:100:0:0
+C:110:100:90
+L:Human | Hobbit | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+#Henneth Annun
+N:42:Halbarad(Dunadan)
+I:100:100:100:0:0
+C:110:100:90
+L:Human | High-Elf | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+#Imladris
+N:43:Elrond Half-Elven
+I:100:100:100:0:0
+C:110:100:90
+L:Human | Half-Elf | High-Elf | RohanKnight | Dunadan | Hobbit | Elf | Dwarf | Ent
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+#Helm's Deep
+N:44:Erkenbrand(RohanKnight)
+I:100:100:100:0:0
+C:110:100:90
+L:Human | Maia | RohanKnight | Dunadan | Hobbit | Elf | Dwarf | Ent
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll
+
+#Thranduil's Halls
+N:45:Legolas Greenleaf(Wood-Elf)
+I:100:100:100:0:0
+C:110:100:90
+L:High-Elf | Dunadan | Ent | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Troll
+
+#Edoras
+N:46:Theoden(RohanKnight)
+I:100:100:100:0:0
+C:110:100:90
+L:Human | RohanKnight | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+#Esgaroth
+N:47:The Master(Human)
+I:100:100:100:0:0
+C:110:100:90
+L:Human
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Troll
+
+#Hobbiton
+N:48:Samwise Gamgee(Hobbit)
+I:100:100:100:0:0
+C:110:100:90
+L:Hobbit | Elf | High-Elf | Dark-Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+#Osgiliath
+N:49:Eldacar(Human)
+I:100:100:100:0:0
+C:110:100:90
+L:Human | Half-Elf | High-Elf | RohanKnight | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll
+
+#Pelargir
+N:50:Earnil(Dunadan)
+I:100:100:100:0:0
+C:110:100:90
+L:Human | Half-Elf | High-Elf | RohanKnight | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll
+
+### Caras Galadhon owners ###
+
+N:51:Galadriel(High-Elf)
+I:15000:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
+
+N:52:Celeborn(High-Elf)
+I:15000:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
+
+N:53:Aulendil(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+#L:Warrior |
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
+
+N:54:Valceronwe(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+#L:Mage | Thaumaturgist | Sorceror
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
+
+N:55:Voronwe(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+#L:Priest | Paladin
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
+
+N:56:Celegail(Elf)
+I:30000:140:105:6:12
+C:120:100:80
+#L:Ranger
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
+
+### Gondolin owners ###
+
+N:57:Turgon(High-Elf)
+I:30000:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:58:Pengolodh(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:59:Aerandir(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:60:Celebrimbor(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+#L:Warrior |
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:61:Lomelosse(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf |
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:62:Arlindel(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+#L:Harper | Ranger
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:63:Sulraen(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+#L:Mage | Sorceror
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:64:Firiel(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf |
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:65:Earendur(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf | Elf
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:66:Glorfindel(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf
+#L:Ranger
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+N:67:Ecthelion(High-Elf)
+I:0:120:105:6:16
+C:120:100:80
+L:High-Elf | Half-Elf
+#L:Paladin
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+### The Inn-Keepers (minus Gondolin) ###
+
+#Bree
+N:68:Barliman Butterbur(Human)
+I:100:170:108:4:10
+C:120:100:80
+L:Dunadan | Hobbit | Human |
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning | Easterling
+
+#Pelargir
+N:69:Ciryatur(Dunadan)
+I:100:170:108:4:10
+C:110:100:80
+L:Dunadan | Human | RohanKnight
+H:Dragon | Demon | Orc | Troll | Half-Ogre | Beorning
+
+#Caras Galadhon
+N:70:Celebor(Elf)
+I:100:170:108:4:10
+C:110:100:80
+L:High-Elf | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+#Minas Anor
+N:71:Bregolas(Human)
+I:100:170:108:4:10
+C:110:100:80
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+#Khazad-Dum
+N:72:Thror(Dwarf)
+I:100:170:108:4:10
+C:110:100:80
+L:Petty-Dwarf | Dwarf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | High-Elf | Troll
+
+#Dale
+N:73:Troin(Dwarf)
+I:100:170:108:4:10
+C:110:100:80
+L:Human | Dwarf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+#Edoras
+N:74:Theodwyn(Shieldmaiden)
+I:100:170:108:4:10
+C:110:100:80
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+#Esgaroth
+N:75:Garm(Human)
+I:100:170:108:4:10
+C:110:100:80
+L:Human | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Petty-Dwarf | Troll
+
+#Hobbiton
+N:76:Rose Cotton(Hobbit)
+I:100:170:108:4:10
+C:110:100:80
+L:Human | High-Elf | Hobbit
+H:Dragon | Demon | Orc | Half-Ogre | Troll | Easterling
+
+#Osgiliath
+N:77:Palantir(Human)
+I:100:170:108:4:10
+C:110:100:80
+L:Human | High-Elf | RohanKnight | Dunadan | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+### The Soothsayers ###
+
+N:78:Ori(Dwarf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Hobbit | Petty-Dwarf | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:79:Tolman Gardner(Hobbit)
+I:25000:180:108:2:2
+C:150:100:50
+L:Human | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:80:Inziladun(Human)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | Half-Elf | RohanKnight | Dunadan | Easterling
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Petty-Dwarf | Troll
+
+N:81:Gelmir(High-Elf)
+I:30000:170:107:1:1
+C:110:100:80
+L:High-Elf | Dunadan | Elf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll
+
+### The Eagles ###
+
+N:82:Palano(Eagle)
+I:30000:170:110:1:1
+C:125:100:50
+L:Eagle
+H:Dragon | Demon | RohanKnight
+
+N:83:Eglad(Eagle)
+I:30000:170:110:1:1
+C:125:100:50
+L:Eagle
+H:Dragon | Demon | Hobbit
+
+N:84:Hiron(Eagle)
+I:30000:170:110:1:1
+C:125:100:50
+L:Eagle
+H:Dragon | Demon | Dunadan
+
+N:85:Grada(Eagle)
+I:30000:170:110:1:1
+C:125:100:50
+L:Eagle
+H:Dragon | Demon | High-Elf
+
+### The Librarians ###
+
+N:86:Frerin(Dwarf)
+I:25000:180:108:2:2
+C:150:100:50
+L:Dwarf | Petty-Dwarf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Troll
+
+N:87:Malva Headstrong(Hobbit)
+I:20000:190:109:3:4
+C:125:100:70
+L:Human | Hobbit
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:88:Erendis(Half-Elf)
+I:30000:170:107:1:1
+C:110:100:80
+L:Half-Elf | High-Elf | Dunadan | Elf | Easterling
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll
+
+N:89:Elemmakil(Wood-Elf)
+I:10000:200:110:4:8
+C:110:100:80
+L:High-Elf | Dunadan | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+### The Casino Owners ###
+
+N:90:Fror(Dwarf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Hobbit | Petty-Dwarf | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:91:Marmadas Brandybuck(Hobbit)
+I:25000:180:108:2:2
+C:150:100:50
+L:Human | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:92:Fastred(Human)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | Half-Elf | RohanKnight | Dunadan | Easterling
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Petty-Dwarf | Troll
+
+N:93:Elured(High-Elf)
+I:30000:170:107:1:1
+C:110:100:80
+L:High-Elf | Dunadan | Elf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Troll
+
+### The Beastmasters ###
+
+N:94:Gloin(Dwarf)
+I:30000:170:107:1:1
+C:125:100:70
+L:Human | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:95:Milo Burrows(Hobbit)
+I:20000:190:109:3:4
+C:110:100:80
+L:Human | Hobbit
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:96:Findegil(Dunadan)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | High-Elf | Dunadan | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+N:97:Elurin(Dark-Elf)
+I:10000:200:110:4:8
+C:150:100:50
+L:Dark-Elf | Elf | Easterling
+H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Dwarf | Troll
+
+### Gondor/Rohan owners ###
+
+#Fighters Hall
+
+N:98:Tarcil(Human)
+I:30000:170:107:1:1
+C:150:100:50
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Orc | Half-Ogre | Troll | Easterling
+
+N:99:Ulbar(Easterling)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | RohanKnight | Dunadan
+L:Half-Elf | High-Elf | Elf | Easterling
+
+N:100:Brego(RohanKnight)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Dark-Elf | Petty-Dwarf | Troll | Easterling
+
+N:101:Ostoher(Dunadan)
+I:20000:190:109:3:4
+C:125:100:70
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll | Easterling
+
+#Tower of Magery
+
+N:102:Arveleg(Human)
+I:25000:180:108:2:2
+C:125:100:70
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Orc | Half-Ogre | Troll | Easterling
+
+N:103:Uldar(Easterling)
+I:30000:170:107:1:1
+C:110:100:80
+L:Human | RohanKnight | Dunadan | Easterling
+L:Half-Elf | High-Elf | Elf
+
+N:104:Aldor(RohanKnight)
+I:20000:190:109:3:4
+C:150:100:50
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Dark-Elf | Petty-Dwarf | Troll | Easterling
+
+N:105:Tarannon(Dunadan)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll | Easterling
+
+#Inner Temple
+
+N:106:Eradan(Human)
+I:30000:170:107:1:1
+C:125:100:70
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+N:107:Ulwise(Easterling)
+I:25000:180:108:2:2
+C:150:100:50
+L:Human | RohanKnight | Dunadan | Easterling
+L:Half-Elf | High-Elf | Elf
+
+N:108:Gram(RohanKnight)
+I:20000:190:109:3:4
+C:110:100:80
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Dark-Elf | Petty-Dwarf | Troll | Easterling
+
+N:109:Minalcar(Dunadan)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll
+
+#Paladins Guild
+
+N:110:Herion(Human)
+I:30000:170:107:1:1
+C:150:100:50
+L:Human | RohanKnight | Dunadan | Easterling
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+N:111:Ulgug(Easterling)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | RohanKnight | Dunadan | Easterling
+L:Half-Elf | High-Elf | Elf
+
+N:112:Walda(RohanKnight)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Dark-Elf | Petty-Dwarf | Troll | Easterling
+
+N:113:Calimehtar(Dunadan)
+I:20000:190:109:3:4
+C:125:100:70
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll | Easterling
+
+#Rangers Guild
+
+N:114:Egalmoth(Human)
+I:25000:180:108:2:2
+C:125:100:70
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Orc | Half-Ogre | Troll | Easterling
+
+N:115:Ulaf(Easterling)
+I:30000:170:107:1:1
+C:110:100:80
+L:Human | RohanKnight | Dunadan | Easterling
+L:Half-Elf | High-Elf | Elf
+
+N:116:Fengel(RohanKnight)
+I:20000:190:109:3:4
+C:150:100:50
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Dark-Elf | Petty-Dwarf | Troll | Easterling
+
+N:117:Telemnar(Dunadan)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll
+
+### Dungeon Markets ###
+
+### The Axesmiths ###
+
+N:118:Ris(Dwarf)
+I:30000:200:130:1:1
+C:150:100:50
+L:Dwarf
+H:Dragon | Demon | Orc
+
+N:119:Malach Aradan(Human)
+I:25000:300:150:2:2
+C:125:100:60
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:120:Indis(Half-Elf)
+I:20000:250:140:3:4
+C:115:100:70
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:121:Rogdug(Half-Orc)
+I:10000:150:120:4:8
+C:125:100:80
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Haftedsmiths ###
+
+N:122:Sogur(Dwarf)
+I:20000:250:140:3:4
+C:125:100:80
+L:Dwarf
+H:Dragon | Demon | Orc
+
+N:123:Manwendil(Human)
+I:25000:300:150:2:2
+C:115:100:70
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:124:Lenwe(Half-Elf)
+I:10000:150:120:4:8
+C:150:100:50
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:125:Ghaz(Half-Orc)
+I:30000:200:130:1:1
+C:125:100:60
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Polearmsmiths ###
+
+N:126:Tolin(Dwarf)
+I:10000:150:120:4:8
+C:115:100:70
+L:Dwarf
+H:Dragon | Demon | Orc
+
+N:127:Narmacil(Human)
+I:25000:300:150:2:2
+C:125:100:80
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:128:Lindir(Half-Elf)
+I:20000:250:140:3:4
+C:150:100:50
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:129:Stogash(Half-Orc)
+I:30000:200:130:1:1
+C:125:100:60
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Swordsmiths ###
+
+N:130:Tis(Dwarf)
+I:20000:250:140:3:4
+C:125:100:80
+L:Dwarf
+H:Dragon | Demon | Orc
+
+N:131:Nuneth(Human)
+I:10000:150:120:4:8
+C:125:100:60
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:132:Mahtan(Half-Elf)
+I:30000:200:130:1:1
+C:115:100:70
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:133:Rudak(Half-Orc)
+I:25000:300:150:2:2
+C:150:100:50
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Rare Jewellers ###
+
+N:134:Uin(Dwarf)
+I:25000:300:150:2:2
+C:115:100:70
+L:Dwarf
+H:Dragon | Demon | Orc
+
+N:135:Ornendil(Human)
+I:10000:150:120:4:8
+C:125:100:60
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:136:Malgalad(Half-Elf)
+I:30000:200:130:1:1
+C:125:100:80
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:137:Ghashuf(Half-Orc)
+I:20000:250:140:3:4
+C:150:100:50
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Jewellers ###
+
+N:138:Vali(Dwarf)
+I:25000:300:150:2:2
+C:150:100:50
+L:Dwarf
+H:Dragon | Demon | Orc
+
+N:139:Orodreth(Human)
+I:30000:200:130:1:1
+C:115:100:70
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:140:Theodred(Half-Elf)
+I:10000:150:120:4:8
+C:125:100:80
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:141:Rangush(Half-Orc)
+I:20000:250:140:3:4
+C:125:100:60
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Footwear Shop owners ###
+
+N:142:Nellas(Human)
+I:10000:150:120:4:8
+C:115:100:70
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:143:Tindomiel(Half-Elf)
+I:25000:300:150:2:2
+C:125:100:80
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:144:Ragnor(Half-Elf)
+I:20000:250:140:3:4
+C:150:100:50
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:145:Idrish(Half-Orc)
+I:30000:200:130:1:1
+C:125:100:60
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Rare Footwear Shop owners ###
+
+N:146:Nerwen(Human)
+I:20000:250:140:3:4
+C:125:100:80
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:147:Ulbar (Half-Elf)
+I:10000:150:120:4:8
+C:125:100:60
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:148:Pelendur(Half-Elf)
+I:30000:200:130:1:1
+C:115:100:70
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:149:Budgar(Half-Orc)
+I:25000:300:150:2:2
+C:150:100:50
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Dungeon Librarians ###
+
+N:150:Nom(Human)
+I:25000:300:150:2:2
+C:115:100:70
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:151:Urwen (Half-Elf)
+I:10000:150:120:4:8
+C:125:100:60
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:152:Rian(Half-Elf)
+I:30000:200:130:1:1
+C:125:100:80
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:153:Mosrog(Half-Orc)
+I:20000:250:140:3:4
+C:150:100:50
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Expensive Black Marketeers ###
+
+N:154:Olwe(Human)
+I:30000:300:150:8:8
+C:125:100:90
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:155:Valacar(Half-Elf)
+I:30000:300:150:8:8
+C:125:100:90
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:156:Silmarien(Half-Elf)
+I:30000:300:150:8:8
+C:125:100:90
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:157:Ghaz(Half-Orc)
+I:30000:300:150:8:8
+C:125:100:90
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Common Shop Owners ###
+
+N:158:Ioreth(Human)
+I:25000:300:150:2:2
+C:150:100:50
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:159:Vidugavia(Half-Elf)
+I:30000:200:130:1:1
+C:115:100:70
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:160:Soronto(Half-Elf)
+I:10000:150:120:4:8
+C:125:100:80
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:161:Nazg(Half-Orc)
+I:20000:250:140:3:4
+C:125:100:60
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Dragon Hunters ###
+
+N:162:Oropher(Human)
+I:10000:150:120:4:8
+C:115:100:70
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:163:Walda(Half-Elf)
+I:25000:300:150:2:2
+C:125:100:80
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:164:Mithrellas(Half-Elf)
+I:20000:250:140:3:4
+C:150:100:50
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:165:Urbag(Half-Orc)
+I:30000:200:130:1:1
+C:125:100:60
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Speed Ring Market Owners ###
+
+N:166:Orophin(Human)
+I:20000:250:140:3:4
+C:125:100:80
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:167:Wulf(Half-Orc)
+I:10000:150:120:4:8
+C:125:100:60
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+N:168:Baguk(Half-Troll)
+I:30000:200:130:1:1
+C:115:100:70
+L:Troll | Easterling
+H:Dragon | Demon | Human
+
+N:169:Zikram(Half-Orc)
+I:25000:300:150:2:2
+C:150:100:50
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Scribes ###
+
+N:170:Rumil(Human)
+I:25000:300:150:2:2
+C:115:100:70
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:171:Saeros(Half-Elf)
+I:10000:150:120:4:8
+C:125:100:60
+L:Half-Elf | Easterling
+H:Dragon | Demon | Half-Ogre
+
+N:172:Zartosh(Half-Orc)
+I:30000:200:130:1:1
+C:125:100:80
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+N:173:Shog(Half-Troll)
+I:20000:250:140:3:4
+C:150:100:50
+L:Troll | Easterling
+H:Dragon | Demon | Human
+
+### The Potion Peddlers ###
+
+N:174:Zamin(Human)
+I:25000:300:150:2:2
+C:150:100:50
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:175:Algosh(Half-Orc)
+I:30000:200:130:1:1
+C:115:100:70
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+N:176:Seghash(Half-Troll)
+I:10000:150:120:4:8
+C:125:100:80
+L:Troll | Easterling
+H:Dragon | Demon | Human
+
+N:177:Kabbug(Half-Orc)
+I:20000:250:140:3:4
+C:125:100:60
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+### The Master Archers ###
+
+N:178:Palin(Dwarf)
+I:30000:170:107:1:1
+C:125:100:70
+L:Human | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+N:179:Wilcome Cotton(Hobbit)
+I:20000:190:109:3:4
+C:110:100:80
+L:Human | Hobbit
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+N:180:Inzilbeth(Dunadan)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | High-Elf | Dunadan | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll
+
+N:181:Gildor Inglorion(Dark-Elf)
+I:10000:200:110:4:8
+C:150:100:50
+L:Dark-Elf | Elf | Easterling
+H:Dragon | Demon | Orc | Half-Ogre | Petty-Dwarf | Dwarf | Troll
+
+### Theme stores ###
+
+### The Miners / Builders ###
+
+N:182:Gror(Dwarf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Half-Elf | Petty-Dwarf | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:183:Saradoc Oldbuck(Hobbit)
+I:30000:170:107:1:1
+C:110:100:80
+L:Human | High-Elf | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:184:Gloredhel(Half-Elf)
+I:10000:200:110:4:8
+C:150:100:50
+L:Human | Half-Elf | Dunadan | Elf | Easterling
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Troll
+
+N:185:Erellont(Wood-Elf)
+I:25000:180:108:2:2
+C:110:100:80
+L:High-Elf | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll | Easterling
+
+### The Hunters ###
+
+N:186:Kili(Dwarf)
+I:20000:190:109:3:4
+C:110:100:80
+L:Petty-Dwarf | Dwarf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Elf | Troll
+
+N:187:Ruby Bolger(Hobbit)
+I:10000:200:110:4:8
+C:150:100:50
+L:Human | Half-Elf | High-Elf | Hobbit | Elf | Easterling
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll
+
+N:188:Goldwine(Human)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | Half-Elf | RohanKnight | Dunadan | Elf | Easterling
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Troll
+
+N:189:Erestor(High-Elf)
+I:30000:170:107:1:1
+C:125:100:70
+L:Human | Half-Elf | High-Elf | Dunadan | Elf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll | Easterling
+
+### The Runecrafters ###
+
+N:190:Nori(Dwarf)
+I:30000:170:107:1:1
+C:150:100:50
+L:Petty-Dwarf | Dwarf | Half-Elf | Dunadan
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Human | Troll | Eagle
+
+N:191:Camellia Sackville(Hobbit)
+I:10000:200:110:4:8
+C:110:100:80
+L:Hobbit | Easterling
+H:Dragon | Demon | Orc | Troll
+
+N:192:Hador Lorindol(Dunadan)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | Half-Elf | High-Elf | RohanKnight | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Orc | Half-Ogre | Troll | Easterling
+
+N:193:Galathil(Dark-Elf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Human | Dark-Elf | Elf
+H:Dragon | Demon | Beorning | Orc | High-Elf | Half-Ogre | Petty-Dwarf | Troll
+
+### The Musicians ###
+
+N:194:Oin(Dwarf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Human | Petty-Dwarf | Dwarf
+H:Dragon | Demon | Orc | Elf | Half-Ogre | Troll | Easterling
+
+N:195:Robin Smallburrow(Hobbit)
+I:10000:200:110:4:8
+C:110:100:80
+L:Human | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Troll | Easterling
+
+N:196:Hareth(Half-Elf)
+I:30000:170:107:1:1
+C:150:100:50
+L:Human | RohanKnight | Dunadan
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+N:197:Galdor(Wood-Elf)
+I:25000:180:108:2:2
+C:110:100:80
+L:Half-Elf | High-Elf | Elf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Petty-Dwarf | Dwarf | Troll | Easterling
+
+### The Precious Metalsmiths ###
+
+N:198:Gabil(Dwarf)
+I:10000:150:120:4:8
+C:115:100:70
+L:Dwarf
+H:Dragon | Demon | Orc
+
+N:199:Isil(Human)
+I:25000:300:150:2:2
+C:125:100:80
+L:Human | Easterling
+H:Dragon | Demon | Troll
+
+N:200:Grima(Half-Orc)
+I:20000:250:140:3:4
+C:150:100:50
+L:Orc | Easterling
+H:Dragon | Demon | Elf
+
+N:201:Kosh(Half-Troll)
+I:30000:200:130:1:1
+C:125:100:60
+L:Troll | Easterling
+H:Dragon | Demon | Human
+
+### The Mapmakers ###
+
+N:202:Pas(Dwarf)
+I:20000:190:109:3:4
+C:125:100:70
+L:Half-Elf | Petty-Dwarf | Dwarf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll
+
+N:203:Isumbras Took(Hobbit)
+I:30000:170:107:1:1
+C:110:100:80
+L:Human | High-Elf | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+N:204:Labadal(Half-Elf)
+I:10000:200:110:4:8
+C:150:100:50
+L:Human | Half-Elf | Dunadan | Elf | Easterling
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Troll
+
+N:205:Guilin(Wood-Elf)
+I:25000:180:108:2:2
+C:110:100:80
+L:High-Elf | Dunadan | Hobbit | Elf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll
+
+### The Farmers ###
+
+N:206:Rili(Dwarf)
+I:20000:190:109:3:4
+C:110:100:80
+L:Petty-Dwarf | Dwarf
+H:Dragon | Demon | Orc | Dark-Elf | Half-Ogre | Elf | Troll
+
+N:207:Wiseman Gamwich(Hobbit)
+I:10000:200:110:4:8
+C:150:100:50
+L:Human | Half-Elf | High-Elf | Hobbit | Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Dwarf | Troll
+
+N:208:Lalaith(Human)
+I:25000:180:108:2:2
+C:110:100:80
+L:Human | Half-Elf | RohanKnight | Dunadan | Elf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Troll | Easterling
+
+N:209:Gwindor(High-Elf)
+I:30000:170:107:1:1
+C:125:100:70
+L:Human | Half-Elf | High-Elf | Dunadan | Elf
+H:Dragon | Demon | Beorning | Orc | Dark-Elf | Half-Ogre | Dwarf | Troll
+
+### The Old Mage in Minas Anor ###
+
+N:210:Malbeth the Seer
+I:20000:170:110:4:4
+C:110:100:80
+L:Human | RohanKnight | Dunadan | High-Elf
+H:Dragon | Demon | Beorning | Orc | Half-Ogre | Troll | Easterling
+
+### For the Merchants' Guild ###
+N:211:Worm(Human)
+I:30000:180:110:0:0
+C:110:100:90 \ No newline at end of file
diff --git a/lib/mods/theme/edit/p_info.txt b/lib/mods/theme/edit/p_info.txt
new file mode 100644
index 00000000..49832c32
--- /dev/null
+++ b/lib/mods/theme/edit/p_info.txt
@@ -0,0 +1,2855 @@
+# File: p_info.txt
+
+
+# This file is used to initialize the "lib/raw/p_info.raw" file, which is
+# used to initialize the "player race/race mod/class" information for the
+# Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+V:2.0.0
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# General skills, that everybody starts with
+# G:k:value:modifier:skill name
+G:k:+0:+500:Monster-lore
+G:k:+1000:+0:Spell-learning
+G:k:+0:+500:Prayer
+G:k:+0:+400:Udun
+G:k:+1000:+1000:Magic-Device
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# C:N:index:name
+# C:D:0:class desc
+# C:D:1:titles
+# C:S:str:int:wis:dex:con:chr:mana:bonus blows
+# C:K:dis:dev:sav:stl:srh:fos:thn:thb
+# C:X:dis:dev:sav:stl:srh:fos:thn:thb
+# C:P:hitdie:xp%
+# C:B:num:wgt:mul
+# C:C:(H|L):(H|L):base:pl:plus
+# first (H|L) is for weapons/.. second is for magic things
+# H = heavy sensing, L = light sensing; result(lower = better) = base / (pl * plev + plus)
+# C:G:class flags
+# C:R:level:pval
+# C:F:flags
+# C:Z:power
+# C:E:weapons:torso:arms:finger:head:legs
+# C:O:tval:sval:xdy
+# C:k:value:modifier:skill name
+# C:b:level:ability
+
+# Specialities, autoskiller
+# C:a:N:Name
+# C:a:D:Desc
+# C:a:K:lvl 50 skill value:skill name
+# C:a:k:value:mod:skill name
+# C:a:b:level:ability
+# C:a:O:tval:sval:xdy
+
+C:N:0:Warrior
+C:D:0:Simple fighters, they hack away with their trusty weapon.
+C:D:1:Rookie
+C:D:1:Soldier
+C:D:1:Mercenary
+C:D:1:Veteran
+C:D:1:Swordsman
+C:D:1:Champion
+C:D:1:Hero
+C:D:1:Baron
+C:D:1:Duke
+C:D:1:Lord
+C:S:5:-2:-2:2:2:-1:0:3
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:30:5
+C:C:H:L:9000:2:40
+C:P:9:0
+C:R:30:0
+C:F:RES_FEAR
+C:E:0:0:0:0:0:0
+C:O:45:38:1d1
+C:O:37:4:1d1
+C:k:+2000:+800:Combat
+C:k:+1000:+850:Weaponmastery
+C:k:+0:+400:Sword-mastery
+C:k:+0:+400:Axe-mastery
+C:k:+0:+400:Hafted-mastery
+C:k:+0:+400:Polearm-mastery
+C:k:+1000:+600:Archery
+C:k:+1000:+900:Sneakiness
+C:k:+0000:+400:Stealth
+C:k:+1000:+900:Disarming
+C:k:+1000:+300:Magic
+C:k:+1000:+400:Spirituality
+C:k:+0:+550:Antimagic
+C:k:+0:+150:Magic-Device
+C:b:25:Spread blows
+C:b:1:Extra Max Blow(1)
+C:b:1:Extra Max Blow(2)
+
+# Specialities, autoskiller
+C:a:N:Warrior
+C:a:D:Simple fighters, they hack away with their trusty weapon.
+C:a:O:23:16:1d1
+C:a:g:All Gods
+
+C:a:N:Swordmaster
+C:a:D:Fighters specialised in the use of swords
+C:a:k:+1000:+300:Sword-mastery
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+0:-100:Axe-mastery
+C:a:k:+0:-100:Hafted-mastery
+C:a:k:+0:-100:Polearm-mastery
+C:a:O:23:16:1d1
+C:a:g:Nobody
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Melkor Bauglir
+C:a:g:Yavanna Kementari
+C:a:g:Varda Elentari
+C:a:g:Aule the Smith
+C:a:g:Ulmo
+C:a:g:Mandos
+
+C:a:N:Axemaster
+C:a:D:Fighters specialised in the use of axes
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+1000:+300:Axe-mastery
+C:a:k:+0:-100:Sword-mastery
+C:a:k:+0:-100:Hafted-mastery
+C:a:k:+0:-100:Polearm-mastery
+C:a:O:24:1:1d1
+C:a:g:Nobody
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Melkor Bauglir
+C:a:g:Yavanna Kementari
+C:a:g:Varda Elentari
+C:a:g:Aule the Smith
+C:a:g:Ulmo
+C:a:g:Mandos
+
+C:a:N:Haftedmaster
+C:a:D:Fighters specialised in the use of hafted weapons
+C:a:k:+1000:+300:Hafted-mastery
+C:a:k:+0:+500:Stunning-blows
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+0:-100:Axe-mastery
+C:a:k:+0:-100:Sword-mastery
+C:a:k:+0:-100:Polearm-mastery
+C:a:O:21:13:1d1
+C:a:g:All Gods
+
+C:a:N:Polearmmaster
+C:a:D:Fighters specialised in the use of polearms
+C:a:k:+1000:+300:Polearm-mastery
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+0:-100:Axe-mastery
+C:a:k:+0:-100:Hafted-mastery
+C:a:k:+0:-100:Sword-mastery
+C:a:O:22:8:1d1
+C:a:b:20:Far reaching attack
+C:a:g:All Gods
+
+C:a:N:Unbeliever
+C:a:D:They don't believe in magic and can even prevent its usage around them
+C:a:k:=0:=0:Prayer
+C:a:k:=0:=0:Magic
+C:a:k:=0:=0:Magic-Device
+C:a:k:=0:=0:Spirituality
+C:a:k:+1000:+100:Antimagic
+C:a:O:23:33:1d1
+C:a:g:Nobody
+
+C:a:N:Demonologist
+C:a:D:Masters of the school of demonology, they are trained in both melee
+C:a:D:fighting and using demon spells to enhance their combat potential.
+C:a:O:115:55:1d1
+C:a:k:+0:-50:Combat
+C:a:k:+0:-100:Weaponmastery
+C:a:k:+0:+200:Sword-mastery
+C:a:k:=0:=0:Axe-mastery
+C:a:k:=0:=0:Hafted-mastery
+C:a:k:=0:=0:Polearm-mastery
+C:a:k:+1000:-200:Archery
+C:a:k:+1000:+900:Sneakiness
+C:a:k:+1000:+900:Disarming
+C:a:k:+1000:+400:Magic
+C:a:k:+1000:+300:Spirituality
+C:a:k:=0:=0:Antimagic
+C:a:k:+1000:+1000:Demonology
+C:a:g:Nobody
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Melkor Bauglir
+
+C:a:N:Wainrider
+C:a:D:A proud warrior riding a majestic chariot.
+C:a:D:Wainriders are traditionally aligned with Melkor.
+C:a:O:71:10:1d1
+C:a:O:23:32:1d1
+C:a:g:Melkor Bauglir
+C:a:k:+0:+600:Sword-mastery
+C:a:k:=0:=0:Axe-mastery
+C:a:k:=0:=0:Hafted-mastery
+C:a:k:=0:=0:Polearm-mastery
+C:a:k:+0:+500:Critical-hits
+C:a:k:+0:+500:Magic
+C:a:k:+0:+500:Spirituality
+C:a:k:+1000:+200:Prayer
+C:a:k:=0:=0:Antimagic
+
+C:N:1:Mage
+C:D:0:The basic spellcaster with lots of different skills
+C:D:1:Apprentice
+C:D:1:Trickster
+C:D:1:Illusionist
+C:D:1:Spellbinder
+C:D:1:Evoker
+C:D:1:Conjurer
+C:D:1:Warlock
+C:D:1:Sorcerer
+C:D:1:Ipsissimus
+C:D:1:Archimage
+C:S:-5:3:0:1:-2:1:50:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:40:2
+C:C:L:H:240000:1:5
+C:P:0:30
+C:E:0:0:0:0:0:0
+C:k:+1000:+900:Magic
+C:k:+0:+200:Magic-Device
+C:k:+0:+600:Spell-power
+C:k:+1000:+600:Mana
+C:k:+0:+700:Fire
+C:k:+0:+700:Water
+C:k:+0:+700:Air
+C:k:+0:+700:Earth
+C:k:+0:+700:Temporal
+C:k:+0:+700:Divination
+C:k:+0:+700:Conveyance
+C:k:+0:+700:Nature
+C:k:+0:+700:Meta
+C:k:+0:+700:Mind
+C:k:+0:+700:Necromancy
+C:k:+0:+700:Runecraft
+C:k:+0:+700:Thaumaturgy
+C:k:+1000:+550:Spirituality
+C:k:+1000:+200:Combat
+C:k:+700:+500:Weaponmastery
+C:k:+1000:+900:Sneakiness
+C:k:+0000:+400:Stealth
+C:b:1:Perfect casting
+C:g:All Gods
+
+C:a:N:Mage
+C:a:D:The basic unspecialized warrior-spellcaster
+C:a:k:+0:+300:Combat
+C:a:k:+0:+200:Sorcery
+C:a:k:+0:+300:Mana
+C:a:k:+0:+200:Fire
+C:a:k:+0:+200:Water
+C:a:k:+0:+200:Air
+C:a:k:+0:+200:Earth
+C:a:k:+0:+200:Conveyance
+C:a:k:+0:+200:Nature
+C:a:k:+0:+200:Temporal
+C:a:k:+0:+200:Divination
+C:a:k:+0:+200:Meta
+C:a:k:+0:+200:Mind
+C:a:O:23:4:1d1
+C:a:O:111:50:1d1
+
+C:a:N:Geomancer
+C:a:D:The master of the four elements
+C:a:k:+0:-150:Magic-Device
+C:a:k:+1000:+100:Spell-power
+C:a:k:-1000:-600:Mana
+C:a:k:+1000:+700:Geomancy
+C:a:k:+1000:+350:Fire
+C:a:k:+1000:+350:Water
+C:a:k:+1000:+350:Air
+C:a:k:+1000:+350:Earth
+C:a:k:+0:-100:Weaponmastery
+C:a:O:6:1:1d1
+
+C:a:N:Warper
+C:a:D:The master of space and time
+C:a:k:+0:-150:Magic-Device
+C:a:k:+1000:+100:Spell-power
+C:a:k:+0:+100:Mana
+C:a:k:+0:+100:Fire
+C:a:k:+0:+100:Water
+C:a:k:+0:+100:Air
+C:a:k:+0:+100:Earth
+C:a:k:+0:+500:Conveyance
+C:a:k:+0:+100:Nature
+C:a:k:+0:+500:Temporal
+C:a:k:+0:+500:Divination
+C:a:k:+0:+100:Meta
+C:a:k:+0:-100:Weaponmastery
+C:a:O:23:4:1d1
+C:a:O:111:50:1d1
+
+C:a:N:Sorceror
+C:a:D:The master of all magic schools
+C:a:k:+0:-200:Magic-Device
+C:a:k:=0:=0:Weaponmastery
+C:a:k:=0:=0:Combat
+C:a:k:+1000:+700:Sorcery
+C:a:k:+0:+100:Magic
+C:a:k:-1000:+300:Mana
+C:a:k:+0:+300:Fire
+C:a:k:+0:+300:Water
+C:a:k:+0:+300:Air
+C:a:k:+0:+300:Earth
+C:a:k:+0:+300:Conveyance
+C:a:k:+0:+300:Nature
+C:a:k:+0:+300:Temporal
+C:a:k:+0:+300:Divination
+C:a:k:+0:+300:Meta
+C:a:k:+0:+300:Mind
+C:a:k:+0:+200:Necromancy
+C:a:k:+0:+200:Runecraft
+C:a:k:+0:+200:Thaumaturgy
+C:a:O:36:2:1d1
+C:a:O:111:50:1d1
+
+C:a:N:Necromancer
+C:a:D:The master of death, and undeath
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+200:Combat
+C:a:k:+1000:+300:Necromancy
+C:a:k:-1000:+0:Mana
+C:a:k:+0:+100:Fire
+C:a:k:+0:+100:Earth
+C:a:k:+0:-200:Nature
+C:a:k:+0:+100:Temporal
+C:a:k:+0:+200:Mind
+C:a:k:+1000:+600:Monster-lore
+C:a:k:+5000:+900:Corpse-preservation
+C:a:O:23:4:1d1
+C:a:O:111:50:1d1
+C:a:b:25:Undead Form
+
+C:a:N:Runecrafter
+C:a:D:Runecrafters use the runes found in Middle-earth to create
+C:a:D:finely tuned spells for each specific situation.
+C:a:k:+1000:+50:Magic
+C:a:k:+1000:+300:Runecraft
+C:a:k:+0:-100:Weaponmastery
+C:a:O:111:50:1d1
+C:a:O:105:1:1d1
+C:a:O:104:5:1d1
+C:a:O:23:4:1d1
+
+C:a:N:Thaumaturgist
+C:a:D:Thaumaturgy spells come from within and are different for each character.
+C:a:D:Since attack is the best defence, all their spells are offensive.
+C:a:k:+2000:+50:Magic
+C:a:k:=0:=0:Spell-power
+C:a:k:=0:=0:Mana
+C:a:k:=0:=0:Fire
+C:a:k:=0:=0:Water
+C:a:k:=0:=0:Air
+C:a:k:=0:=0:Earth
+C:a:k:=0:=0:Temporal
+C:a:k:=0:=0:Divination
+C:a:k:=0:=0:Conveyance
+C:a:k:=0:=0:Nature
+C:a:k:=0:=0:Meta
+C:a:k:=0:=0:Mind
+C:a:k:=0:=0:Necromancy
+C:a:k:=0:=0:Runecraft
+C:a:k:+1000:+300:Thaumaturgy
+C:a:k:+0:-100:Weaponmastery
+C:a:k:+0:-150:Magic-Device
+C:a:O:23:4:1d1
+C:a:O:111:50:1d1
+
+### Clairvoyant - new class added in Theme
+
+C:a:N:Clairvoyant
+C:a:D:The master of the mind who sacrifices breadth of
+C:a:D:ability for additional favour with their deity.
+C:a:k:=0:=0:Mana
+C:a:k:=0:=0:Fire
+C:a:k:=0:=0:Water
+C:a:k:=0:=0:Air
+C:a:k:=0:=0:Earth
+C:a:k:=0:=0:Conveyance
+C:a:k:=0:=0:Nature
+C:a:k:=0:=0:Temporal
+C:a:k:=0:=0:Meta
+C:a:k:=0:=0:Necromancy
+C:a:k:=0:=0:Runecraft
+C:a:k:=0:=0:Thaumaturgy
+C:a:k:+1000:+300:Divination
+C:a:k:+1000:+300:Mind
+C:a:k:+0:+500:Spirituality
+C:a:k:+0:+500:Prayer
+C:a:k:+1000:+700:Mindcraft
+C:a:O:111:50:1d1
+C:a:O:21:3:1d1
+
+C:N:2:Archer
+C:D:0:'Kill them before they see you' could be the motto of the archer class.
+C:D:0:As deadly with a bow as a warrior is with a sword.
+C:D:1:Rock Thrower
+C:D:1:Slinger
+C:D:1:Great Slinger
+C:D:1:Tosser
+C:D:1:Bowman
+C:D:1:Great Bowman
+C:D:1:Great Bowman
+C:D:1:Archer
+C:D:1:Archer
+C:D:1:Great Archer
+C:S:2:1:0:2:1:1:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:35:4
+C:C:H:L:9000:2:40
+C:P:4:30
+C:E:0:0:0:0:0:0
+C:k:+1000:+800:Combat
+C:k:+1000:+500:Weaponmastery
+C:k:+1000:+750:Archery
+C:k:+0:+300:Bow-mastery
+C:k:+0:+300:Crossbow-mastery
+C:k:+0:+300:Sling-mastery
+C:k:+0:+300:Boomerang-mastery
+C:k:+0:%150:Boulder-throwing
+C:k:+1000:+900:Sneakiness
+C:k:+0000:+400:Stealth
+C:k:+1000:+900:Disarming
+C:k:+1000:+300:Magic
+C:k:+0:+100:Magic-Device
+C:k:+1000:+400:Spirituality
+C:b:2:Ammo creation
+
+C:a:N:Archer
+C:a:D:'Kill them before they see you' could be the motto of the archer class.
+C:a:D:As deadly with a bow as a warrior is with a sword.
+C:a:k:+0:+100:Archery
+C:a:k:+0:+200:Bow-mastery
+C:a:k:+0:+200:Crossbow-mastery
+C:a:k:+0:+200:Sling-mastery
+C:a:k:+0:+200:Boomerang-mastery
+C:a:k:-1000:-100:Magic
+C:a:O:19:12:1d1
+C:a:O:19:2:1d1
+C:a:O:17:1:10d3
+C:a:O:17:1:10d3
+C:a:g:All Gods
+
+C:a:N:Ranger
+C:a:D:Rangers are capable archers but are also trained in hand-to-hand combat,
+C:a:D:the nature and divination magic schools, and trapping.
+C:a:k:+0:+200:Weaponmastery
+C:a:k:+0:+400:Magic
+C:a:k:+0:+500:Nature
+C:a:k:+0:+500:Divination
+C:a:k:+0:+700:Disarming
+C:a:k:+0:+50:Sneakiness
+C:a:k:+0:+200:Monster-lore
+C:a:k:+0:+300:Summoning
+C:a:O:19:12:1d1
+C:a:O:17:1:10d3
+C:a:O:23:10:1d1
+C:a:O:46:1:1d1
+C:a:g:Nobody
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Yavanna Kementari
+C:a:g:Varda Elentari
+C:a:g:Aule the Smith
+C:a:g:Ulmo
+C:a:g:Mandos
+C:a:b:1:Trapping
+
+C:a:N:Sniper
+C:a:D:Snipers are very stealthy archers without much hand-to-hand combat
+C:a:D:ability, but with a penchant to disappear when it suits them.
+C:a:k:+0:-300:Combat
+C:a:k:+1000:+100:Sneakiness
+C:a:k:+1000:+700:Stealth
+C:a:k:+0:+100:Disarming
+C:a:k:+1000:+700:Backstab
+C:a:k:+0:+300:Magic
+C:a:k:+1000:+500:Conveyance
+C:a:O:19:12:1d1
+C:a:O:17:1:10d3
+C:a:g:All Gods
+
+C:N:3:Rogue
+C:D:0:Rogues are masters of tricks. They can steal from shops and monsters,
+C:D:0:and lure monsters into deadly monster traps.
+C:D:1:Cutpurse
+C:D:1:Robber
+C:D:1:Burglar
+C:D:1:Filcher
+C:D:1:Sharper
+C:D:1:Low Thief
+C:D:1:High Thief
+C:D:1:Master Thief
+C:D:1:Assassin
+C:D:1:Guildmaster
+C:S:2:1:-2:3:1:-1:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:30:3
+C:C:H:H:20000:2:40
+C:P:6:25
+C:O:23:4:1d1
+C:G:EASE_STEAL
+C:R:3:1
+C:F:CRIT
+C:R:6:1
+C:F:CRIT
+C:R:9:1
+C:F:CRIT
+C:R:12:1
+C:F:CRIT
+C:R:15:1
+C:F:CRIT
+C:R:18:1
+C:F:CRIT
+C:R:21:1
+C:F:CRIT
+C:R:24:1
+C:F:CRIT
+C:R:27:1
+C:F:CRIT
+C:R:30:1
+C:F:CRIT
+C:R:33:1
+C:F:CRIT
+C:R:36:1
+C:F:CRIT
+C:R:39:1
+C:F:CRIT
+C:R:42:1
+C:F:CRIT
+C:R:45:1
+C:F:CRIT
+C:R:48:1
+C:F:CRIT
+C:E:0:0:0:0:0:0
+C:k:+1000:+700:Combat
+C:k:+1000:+700:Weaponmastery
+C:k:+1000:+300:Sword-mastery
+C:k:+1000:+500:Critical-hits
+C:k:+1000:+700:Magic
+C:k:+0:+550:Magic-Device
+C:k:+0:+500:Conveyance
+C:k:+0:+500:Divination
+C:k:+0:+500:Temporal
+C:k:+1000:+700:Spirituality
+C:k:+1000:+2000:Sneakiness
+C:k:+1000:+1500:Stealth
+C:k:+1000:+2000:Disarming
+C:k:+1000:+1000:Backstab
+C:k:+1000:+2000:Stealing
+C:k:+1000:+2000:Dodging
+C:g:All Gods
+C:b:10:Extra Max Blow(1)
+
+C:a:N:Rogue
+C:a:D:Rogues are masters of tricks. They can steal from shops and monsters,
+C:a:D:and lure monsters into deadly monster traps.
+C:a:b:1:Trapping
+C:a:O:46:1:1d1
+
+C:a:N:Assassin
+C:a:D:Assassins are stealthy killers.
+C:a:k:+0:+100:Combat
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+300:Sword-mastery
+C:a:k:+1000:+300:Critical-hits
+C:a:k:+1000:+300:Boomerang-mastery
+C:a:k:+0:-500:Magic
+C:a:k:+0:-400:Conveyance
+C:a:k:+0:-400:Divination
+C:a:k:+0:-300:Temporal
+C:a:k:+0:+500:Stealth
+C:a:k:+0:-1000:Disarming
+C:a:k:+0:+1000:Backstab
+C:a:k:+0:-1800:Stealing
+C:a:k:+0:-550:Magic-Device
+
+C:a:N:Mercenary
+C:a:D:Mercenaries are daring swashbucklers, masters of the blade.
+C:a:k:+0:+200:Weaponmastery
+C:a:k:+0:+400:Sword-mastery
+C:a:k:+0:+200:Critical-hits
+C:a:k:+0:+050:Magic-Device
+C:a:k:=0:=0:Conveyance
+C:a:k:=0:=0:Divination
+C:a:k:+0:+500:Temporal
+C:a:b:15:Extra Max Blow(2)
+C:a:O:23:7:1d1
+C:a:O:35:1:1d1
+
+C:N:4:Loremaster
+C:D:0:Loremasters are skilled in most combat and monster skills.
+C:D:1:Apprentice
+C:D:1:Apprentice
+C:D:1:Initiate
+C:D:1:Initiate
+C:D:1:Sage
+C:D:1:Sage
+C:D:1:Lorekeeper
+C:D:1:Lorekeeper
+C:D:1:Loremaster
+C:D:1:Loremaster
+C:S:1:-2:1:1:0:1:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:30:3
+C:C:H:L:9000:2:40
+C:P:8:40
+C:E:0:0:0:0:0:0
+C:k:+1000:+700:Combat
+C:k:+1000:+700:Weaponmastery
+C:k:+1000:+700:Archery
+C:k:+1000:+700:Barehand-combat
+C:k:+0:+600:Magic
+C:k:+1000:+700:Sneakiness
+C:k:+1000:+700:Stealth
+C:k:+1000:+700:Disarming
+C:k:+1000:+700:Spirituality
+C:k:+1000:+600:Monster-lore
+C:k:+0:+500:Possession
+C:k:+1000:+700:Corpse-preservation
+C:k:+0:+500:Summoning
+C:k:+0:+500:Symbiosis
+C:k:+0:+500:Mimicry
+C:k:+0:+300:Music
+
+C:a:N:Loremaster
+C:a:D:Loremasters are skilled in most combat and monster skills.
+C:a:O:21:3:1d1
+C:a:O:36:6:1d1
+C:a:O:19:2:1d1
+C:a:O:16:0:3d10
+C:a:g:All Gods
+
+C:a:N:Possessor
+C:a:D:Only the soul matters; a possessor can abandon his/her current body to
+C:a:D:incarnate in the body of a dead monster, thus gaining its powers
+C:a:D:and weaknesses.
+C:a:O:71:37:1d1
+C:a:O:23:10:1d1
+C:a:O:36:6:1d1
+C:a:k:+0:-100:Combat
+C:a:k:+0:-100:Weaponmastery
+C:a:k:+0:-300:Archery
+C:a:k:-1000:-700:Barehand-combat
+C:a:k:+0:-200:Disarming
+C:a:k:+0:-200:Spirituality
+C:a:k:+1000:+300:Possession
+C:a:k:+0:+200:Corpse-preservation
+C:a:k:+0:-500:Summoning
+C:a:k:+0:-500:Symbiosis
+C:a:k:+0:-500:Mimicry
+C:a:g:All Gods
+
+C:a:N:Mimic
+C:a:D:Disguise is the way of the mimic. Through the use of cloaks of mimicry
+C:a:D:they can change shape for a limited time. They also can temporarily
+C:a:D:change part of their anatomy.
+C:a:O:71:37:1d1
+C:a:O:23:4:1d1
+C:a:k:+0:+100:Combat
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:-100:Barehand-combat
+C:a:k:+1000:+100:Magic
+C:a:k:+0:+100:Sneakiness
+C:a:k:+0:+100:Stealth
+C:a:k:+0:-200:Spirituality
+C:a:k:+0:-400:Possession
+C:a:k:+0:+200:Corpse-preservation
+C:a:k:+0:-500:Summoning
+C:a:k:+0:-500:Symbiosis
+C:a:k:+1000:+300:Mimicry
+C:a:g:All Gods
+
+C:a:N:Symbiant
+C:a:D:A symbiant can merge his/her body with one of a monster unable to move
+C:a:D:by itself. They also have a few spells to help the symbiosis.
+C:a:O:23:4:1d1
+C:a:O:70:6:1d1
+C:a:k:+0:+100:Combat
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:-100:Barehand-combat
+C:a:k:+1000:+100:Magic
+C:a:k:+0:+100:Sneakiness
+C:a:k:+0:+100:Stealth
+C:a:k:+0:-200:Spirituality
+C:a:k:+0:-400:Possession
+C:a:k:+0:+200:Corpse-preservation
+C:a:k:+0:-500:Summoning
+C:a:k:+1000:+300:Symbiosis
+C:a:k:+0:-500:Mimicry
+C:a:g:All Gods
+
+C:a:N:Summoner
+C:a:D:The summoner can conjure monsters from totems made from defeated foes.
+C:a:O:71:37:1d1
+C:a:O:23:10:1d1
+C:a:O:36:6:1d1
+C:a:k:+0:-100:Combat
+C:a:k:+0:-100:Weaponmastery
+C:a:k:+0:-300:Archery
+C:a:k:-1000:-700:Barehand-combat
+C:a:k:+1000:+200:Magic
+C:a:k:+0:+0:Sneakiness
+C:a:k:+0:+0:Stealth
+C:a:k:+0:-200:Disarming
+C:a:k:+0:-200:Spirituality
+C:a:k:+15000:+100:Monster-lore
+C:a:k:+0:-500:Possession
+C:a:k:+0:+300:Corpse-preservation
+C:a:k:+1000:+200:Summoning
+C:a:k:+0:-500:Symbiosis
+C:a:k:+0:-500:Mimicry
+C:a:g:All Gods
+
+C:a:N:Monk
+C:a:D:Barehanded, lightly armoured fighters, they wreak havoc with
+C:a:D:their bare fists, and can also use a few prayers.
+C:a:O:71:37:1d1
+C:a:O:36:4:1d1
+C:a:k:-1000:+200:Combat
+C:a:k:-1000:-400:Weaponmastery
+C:a:k:-1000:-300:Archery
+C:a:k:+0:+200:Barehand-combat
+C:a:k:+0:+0:Magic
+C:a:k:+0:+200:Sneakiness
+C:a:k:+0:+200:Stealth
+C:a:k:+0:+200:Disarming
+C:a:k:+0:+200:Spirituality
+C:a:k:+0:-400:Possession
+C:a:k:+0:-200:Corpse-preservation
+C:a:k:+0:-500:Summoning
+C:a:k:+0:-500:Symbiosis
+C:a:k:+0:-500:Mimicry
+C:a:k:+0:+500:Meta
+C:a:k:+0:+500:Mind
+C:a:k:+0:+500:Temporal
+C:a:k:+0:+700:Dodging
+C:a:g:All Gods
+
+C:a:N:Bard
+C:a:D:Bards sing and play songs full of power, beauty or sadness to affect
+C:a:D:everything that can hear them, using music instruments of various types.
+C:a:O:71:37:1d1
+C:a:O:23:10:1d1
+C:a:O:36:2:1d1
+C:a:O:14:59:1d1
+C:a:k:+1000:+0:Magic
+C:a:k:-1000:-700:Archery
+C:a:k:+0:-100:Barehand-combat
+C:a:k:+0:-100:Disarming
+C:a:k:+0:+100:Spirituality
+C:a:k:+0:-500:Possession
+C:a:k:+0:-100:Summoning
+C:a:k:+0:-100:Symbiosis
+C:a:k:+0:-100:Mimicry
+C:a:k:+1000:+500:Music
+C:a:g:All Gods
+
+C:a:N:Ascetic
+C:a:D:The monk who has sworn off all worldly things.
+C:a:D:The ascetics do not believe in magic or gods.
+C:a:k:+0:+200:Combat
+C:a:k:=0:=0:Weaponmastery
+C:a:k:+0:+200:Barehand-combat
+C:a:k:+1000:+1000:Antimagic
+C:a:k:+0:+200:Disarming
+C:a:k:+0:+300:Stealth
+C:a:k:+0:+1000:Dodging
+C:a:k:=0:=0:Magic
+C:a:k:=0:=0:Magic-Device
+C:a:k:=0:=0:Spell-power
+C:a:k:=0:=0:Meta
+C:a:k:=0:=0:Conveyance
+C:a:k:=0:=0:Divination
+C:a:k:=0:=0:Temporal
+C:a:k:=0:=0:Nature
+C:a:k:=0:=0:Prayer
+C:a:k:=0:=0:Music
+C:a:k:=0:=0:Summoning
+C:a:k:=0:=0:Symbiosis
+C:a:k:=0:=0:Possession
+C:a:k:=0:=0:Mimicry
+C:a:b:10:Spread blows
+C:a:b:1:Extra Max Blow(1)
+C:a:b:5:Extra Max Blow(2)
+C:a:O:71:37:1d1
+C:a:g:Nobody
+
+C:N:5:Pacifist
+C:D:0:Pacifists do not believe in violence and do not want to kill
+C:D:0:everything in sight.
+C:D:1:Novice
+C:D:1:Appeaser
+C:D:1:Arbitrator
+C:D:1:Elf-Friend
+C:D:1:Conciliator
+C:D:1:Diplomat
+C:D:1:Mediator
+C:D:1:Negotiator
+C:D:1:Pacifist
+C:D:1:Peacemaker
+C:S:0:2:2:2:0:4:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:P:0:0
+C:B:0:0:0
+C:C:H:H:20000:2:40
+C:Z:detect doors and traps
+C:E:-1:0:0:0:0:0
+C:k:=0:=0:Combat
+C:k:=0:=0:Weaponmastery
+C:k:=0:=0:Archery
+C:k:=0:=0:Barehand-combat
+C:k:+0:+600:Sneakiness
+C:k:+0:+600:Stealth
+C:k:+1000:+700:Dodging
+C:k:+1000:+600:Disarming
+C:k:+1000:+600:Magic
+C:k:=0:=0:Magic-Device
+C:k:+0:+500:Spell-power
+C:k:+1000:+1000:Nature
+C:k:+0:+700:Spirituality
+C:k:+1000:+400:Monster-lore
+C:k:=0:=0:Possession
+C:k:=0:=0:Corpse-preservation
+C:k:=0:=0:Mimicry
+C:k:=0:=0:Music
+C:b:15:Perfect casting
+C:g:All Gods
+
+C:a:N:Trapper
+C:a:D:These pacifists use traps to snare monsters, and
+C:a:D:make totems from corpses to summon aid.
+C:O:46:1:1d1
+C:a:k:+1000:+600:Summoning
+C:a:b:1:Trapping
+C:a:b:10:Ammo creation
+
+C:a:N:Peace-mage
+C:a:D:These pacifists use magic to escape danger, and
+C:a:D:rely on symbiotic relationships to defend themselves.
+C:a:O:70:6:1d1
+C:a:k:+0:+700:Meta
+C:a:k:+1000:+700:Conveyance
+C:a:k:+0:+700:Divination
+C:a:k:+0:+700:Temporal
+C:a:k:+1000:+600:Symbiosis
+
+C:N:6:Priest
+C:D:0:A priest serves a god (Vala, Maia or Eru himself) to bring down
+C:D:0:the empire of fear and shadows of Morgoth.
+C:D:1:Believer
+C:D:1:Acolyte
+C:D:1:Adept
+C:D:1:Curate
+C:D:1:Canon
+C:D:1:Priest
+C:D:1:High Priest
+C:D:1:Cardinal
+C:D:1:Inquisitor
+C:D:1:Pope
+C:S:-1:-3:3:-1:0:2:0:0
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:4:35:3
+C:C:L:H:10000:2:40
+C:P:2:20
+C:Z:detect curses
+C:G:GOD_FRIEND |
+C:E:0:0:0:0:0:0
+C:k:+1000:+900:Magic
+C:k:+0:+600:Spell-power
+C:k:+0:+600:Necromancy
+C:k:+0:+600:Mindcraft
+C:k:+1000:+1000:Spirituality
+C:k:+1000:+700:Prayer
+C:k:+2000:+700:Combat
+C:k:+1000:+700:Weaponmastery
+C:k:+1000:+900:Sneakiness
+C:k:+0000:+900:Disarming
+C:k:+0000:+400:Stealth
+C:k:+0:+50:Magic-Device
+C:b:1:Perfect casting
+
+C:a:N:Priest(Eru)
+C:a:D:A priest that serves Eru Iluvatar to bring down
+C:a:D:the empire of fear and shadows of Morgoth.
+C:a:O:21:5:1d1
+C:a:g:Eru Iluvatar
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+100:Spell-power
+
+C:a:N:Priest(Manwe)
+C:a:D:A priest that serves Manwe Sulimo to bring down
+C:a:D:the empire of fear and shadows of Morgoth.
+C:a:O:21:5:1d1
+C:a:g:Manwe Sulimo
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+50:Weaponmastery
+
+C:a:N:Druid
+C:a:D:A priest that serves Yavanna Kementari to protect
+C:a:D:and help the regrowth of nature on Arda.
+C:a:O:21:5:1d1
+C:a:g:Yavanna Kementari
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+50:Weaponmastery
+C:a:k:+1000:+700:Monster-lore
+C:a:k:+1000:+700:Summoning
+
+C:a:N:Dark-Priest
+C:a:D:A priest that serves Melkor Bauglir to bring chaos
+C:a:D:and destruction to Arda.
+C:a:O:21:5:1d1
+C:a:g:Melkor Bauglir
+C:a:k:+0:+200:Prayer
+C:a:k:+0:+200:Necromancy
+C:a:k:+0:-600:Mindcraft
+C:a:k:+0:+200:Spell-power
+C:a:k:+1000:+1000:Corpse-preservation
+
+C:a:N:Paladin
+C:a:D:A fighting priest that serves Tulkas to bring down
+C:a:D:the empire of fear and shadows of Morgoth.
+C:a:O:23:25:1d1
+C:a:g:Tulkas
+C:a:k:+0:+200:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+100:Weaponmastery
+C:a:k:+0:+100:Combat
+C:a:k:+0:+900:Barehand-combat
+C:a:b:1:Extra Max Blow(1)
+
+C:a:N:Mindcrafter
+C:a:D:A priest who has learned to tap in his own mental powers
+C:a:O:21:5:1d1
+C:a:g:Eru Iluvatar
+C:a:g:Manwe Sulimo
+C:a:g:Tulkas
+C:a:g:Melkor Bauglir
+C:a:g:Yavanna Kementari
+C:a:g:Varda Elentari
+C:a:g:Aule the Smith
+C:a:g:Ulmo
+C:a:g:Mandos
+C:a:k:+0:-300:Prayer
+C:a:k:+0:-200:Necromancy
+C:a:k:+1000:+300:Mindcraft
+C:a:k:+0:+200:Sneakiness
+C:a:k:+0:+100:Magic-Device
+
+C:a:N:Stonewright
+C:a:D:A war-priest of Aule who serves to protect and
+C:a:D:further the works of the Valarin Smith.
+C:a:O:24:8:1d1
+C:a:g:Aule the Smith
+C:a:k:+0:+400:Axe-mastery
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+100:Spell-power
+C:a:b:10:Extra Max Blow(1)
+
+C:a:N:Priest(Varda)
+C:a:D:A priest who serves Varda to bring light
+C:a:D:to all the reaches of the world.
+C:a:O:21:5:1d1
+C:a:g:Varda Elentari
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+100:Spell-power
+C:a:k:+0:+400:Archery
+
+C:a:N:Priest(Ulmo)
+C:a:D:A priest that serves Eru Iluvatar to bring down
+C:a:D:the empire of fear and shadows of Morgoth.
+C:a:O:22:5:1d1
+C:a:g:Ulmo
+C:a:k:+0:+400:Polearm-mastery
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+100:Spell-power
+
+C:a:N:Priest(Mandos)
+C:a:D:A priest that serves Eru Iluvatar to bring down
+C:a:D:the empire of fear and shadows of Morgoth.
+C:a:O:21:5:1d1
+C:a:g:Mandos
+C:a:k:+0:+400:Hafted-mastery
+C:a:k:+0:+300:Prayer
+C:a:k:+0:-600:Necromancy
+C:a:k:+0:+100:Spell-power
+
+###############################TEST###############################
+C:N:30:Test
+C:D:0:Simple testers.
+C:D:1:Rookie
+C:D:1:Soldier
+C:D:1:Mercenary
+C:D:1:Veteran
+C:D:1:Swordsman
+C:D:1:Champion
+C:D:1:Hero
+C:D:1:Baron
+C:D:1:Duke
+C:D:1:Lord
+C:S:5:-2:-2:2:2:-1:0:3
+C:K:10:10:0:1:10:10:10:10
+C:X:0:0:0:0:0:0:0:0
+C:B:6:30:5
+C:C:H:L:9000:2:40
+C:P:9:0
+C:R:30:0
+C:F:RES_FEAR
+C:E:0:0:0:0:0:0
+C:O:45:38:1d1
+C:O:37:4:1d1
+C:k:+1000:+800:Combat
+C:k:+1000:+850:Weaponmastery
+C:k:+0:+200:Sword-mastery
+C:k:+0:+200:Axe-mastery
+C:k:+0:+200:Hafted-mastery
+C:k:+0:+200:Polearm-mastery
+C:k:+1000:+600:Archery
+C:k:+1000:+900:Sneakiness
+C:k:+1000:+900:Disarming
+C:k:+1000:+300:Magic
+C:k:+0:+550:Antimagic
+
+C:a:N:Shinny test
+C:a:D:Simple testers, they test all with their shiny hacks !
+C:a:O:23:16:1d1
+###############################TEST###############################
+
+
+
+
+
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# R: Race definition
+# R:N:index:name
+# R:D:race desc
+# R:S:str:int:wis:dex:con:chr:luck
+# R:K:dis:dev:sav:stl:srh:fos:thn:thb
+# R:P:hitdie:xp%:infra:history chart
+# R:M:b_age:m_age:m_b_ht:m_m_ht:m_b_wt:m_m_wt:f_b_ht:f_m_ht:f_b_wt:f_m_wt
+# R:E:weapons:torso:arms:finger:head:legs
+# R:C:allowed classes
+# R:G:race flags
+# R:R:level:pval
+# R:F:flags
+# R:k:value:modifier:skill name
+# R:b:level:ability
+
+I:
+
+R:N:0:Human
+R:D:Humans are the second born, the Edain.
+R:D:They are the basic race to which all others are compared.
+R:D:Average in ability, they can be any class.
+R:S:0:0:0:0:0:0:0
+R:K:0:0:0:0:0:10:0:0
+R:P:10:100:0:1
+R:M:14:6:72:6:180:25:66:4:150:20
+R:E:1:1:1:2:1:1
+R:C:Warrior | Archer | Mage | Rogue | Priest | Loremaster | Pacifist
+
+R:N:1:Half-Elf
+R:D:A crossbreed of elf and human, they get the best of the two races.
+R:S:0:1:1:1:-1:1:0
+R:K:2:3:3:1:6:11:-1:5
+R:P:9:110:2:4
+R:M:24:16:66:6:130:15:62:6:100:10
+R:E:1:1:1:2:1:1
+R:C:Warrior | Archer | Mage | Rogue | Priest | Loremaster | Pacifist
+R:G:ELF
+R:k:+200:+000:Disarming
+R:k:+300:+000:Magic-Device
+R:k:+1500:+000:Spirituality
+R:k:+1000:+000:Stealth
+R:k:+600:+000:Sneakiness
+R:k:-100:+000:Weaponmastery
+R:k:+500:+000:Archery
+
+R:N:2:Elf
+R:D:Elves are the first born, the Eldar.
+R:D:More spiritual than physical beings, they are weaker than humans
+R:D:but are more intelligent.
+R:S:-1:2:2:1:-2:2:0
+R:K:5:6:6:2:8:12:-5:15
+R:P:8:120:3:5
+R:M:75:75:60:4:100:6:54:4:80:6
+R:E:1:1:1:2:1:1
+R:R:1:0
+R:F:RES_LITE |
+R:C:Warrior | Archer | Mage | Priest | Loremaster | Pacifist
+R:G:ELF
+R:k:+500:+000:Disarming
+R:k:+600:+000:Magic-Device
+R:k:+3000:+000:Spirituality
+R:k:+2000:+000:Stealth
+R:k:+800:+000:Sneakiness
+R:k:-500:+000:Weaponmastery
+R:k:+1500:+000:Archery
+
+R:N:3:Hobbit
+R:D:An old but quiet race related to humans.
+R:D:They are small and quite weak but good at many things.
+R:S:-2:2:1:3:2:1:5
+R:K:15:18:18:5:12:15:-10:20
+R:P:7:110:4:10
+R:M:21:12:36:3:60:3:33:3:50:3
+R:E:1:1:1:2:1:0
+R:Z:create food
+R:G:RESIST_BLACK_BREATH | XTRA_MIGHT_SLING |
+R:R:1:0
+R:F:SUST_DEX |
+R:C:Warrior | Archer | Mage | Rogue | Loremaster | Pacifist
+R:k:+0:+300:Sling-mastery
+R:k:+1500:+000:Disarming
+R:k:+1800:+000:Magic-Device
+R:k:+9000:+000:Spirituality
+R:k:+6000:+000:Stealth
+R:k:+1200:+000:Sneakiness
+R:k:-1000:+000:Weaponmastery
+R:k:+2000:+000:Archery
+
+R:N:4:Gnome
+R:D:Related to dwarves, Gnomes are between Dwarves and Hobbits in size.
+R:D:Very good at magic use, they are poor as fighters.
+R:S:-1:2:0:2:1:-2:2
+R:K:10:12:12:3:6:13:-8:12
+R:P:8:135:4:13
+R:M:50:40:42:3:90:6:39:3:75:3
+R:E:1:1:1:2:1:1
+R:Z:blink
+R:R:1:0
+R:F:FREE_ACT |
+R:C:Warrior | Mage | Rogue | Pacifist
+R:k:+1000:+000:Disarming
+R:k:+1200:+000:Magic-Device
+R:k:+6000:+000:Spirituality
+R:k:+3000:+000:Stealth
+R:k:+600:+000:Sneakiness
+R:k:-800:+000:Weaponmastery
+R:k:+1200:+000:Archery
+
+R:N:5:Dwarf
+R:D:The children of Aule, a strong but small race.
+R:D:Miners and fighters of legend.
+R:S:2:-2:2:-2:2:-3:0
+R:K:2:9:10:-1:7:10:15:0
+R:P:11:125:5:16
+R:M:35:15:48:3:150:10:46:3:120:10
+R:E:1:1:1:2:1:1
+R:Z:find secret passages
+R:R:1:0
+R:F:RES_BLIND | LITE1
+R:C:Warrior | Priest | Pacifist
+R:k:+0:+200:Axe-mastery
+R:k:+200:+000:Disarming
+R:k:+900:+000:Magic-Device
+R:k:+5000:+000:Spirituality
+R:k:-1000:+000:Stealth
+R:k:+700:+000:Sneakiness
+R:k:+1500:+000:Weaponmastery
+R:k:+500:+000:Archery
+
+R:N:6:Orc
+R:D:Quite strong but not very smart.
+R:S:2:-1:0:1:1:-4:-3
+R:K:-3:-3:-3:-1:0:7:12:-5
+R:P:10:110:3:25
+R:M:11:4:66:1:150:5:62:1:120:5
+R:E:1:1:1:2:1:1
+R:Z:remove fear
+R:R:1:0
+R:F:RES_DARK |
+R:C:Warrior | Archer | Rogue | Priest
+R:k:-300:+000:Disarming
+R:k:-300:+000:Magic-Device
+R:k:-1000:+000:Spirituality
+R:k:-1000:+000:Stealth
+R:k:+000:+000:Sneakiness
+R:k:+1200:+000:Weaponmastery
+R:k:-500:+000:Archery
+
+R:N:7:Troll
+R:D:They can bear the light of the sun.
+R:D:They are extremely strong and dumb.
+R:S:4:-4:-2:-4:3:-6:-4
+R:K:-5:-8:-8:-2:-1:5:20:-10
+R:P:12:137:3:22
+R:M:20:10:96:10:250:50:84:8:225:40
+R:E:1:1:1:2:1:1
+R:Z:berserk
+R:R:1:0
+R:F:SUST_STR |
+R:R:15:0
+R:F:REGEN |
+R:C:Warrior
+R:k:-500:+000:Disarming
+R:k:-800:+000:Magic-Device
+R:k:-4000:+000:Spirituality
+R:k:-2000:+000:Stealth
+R:k:-100:+000:Sneakiness
+R:k:+2000:+000:Weaponmastery
+R:k:+0:+200:Hafted-mastery
+R:k:-1000:+000:Archery
+
+R:N:8:Dunadan
+R:D:The greatest of the Edain, humans in all respects but
+R:D:stronger, smarter and wiser.
+R:S:1:2:2:2:3:2:2
+R:K:4:5:5:2:3:13:15:10
+R:P:10:180:0:1
+R:M:50:50:82:5:190:20:78:6:180:15
+R:E:1:1:1:2:1:1
+R:R:1:0
+R:F:SUST_CON | REGEN |
+R:C:Warrior | Archer | Mage | Rogue | Priest | Loremaster | Pacifist
+R:k:+400:+000:Disarming
+R:k:+500:+000:Magic-Device
+R:k:+2500:+000:Spirituality
+R:k:+2000:+000:Stealth
+R:k:+800:+000:Sneakiness
+R:k:+1500:+000:Weaponmastery
+R:k:+1000:+000:Archery
+
+R:N:9:High-Elf
+R:D:Elves are the first born, the Eldar.
+R:D:High elves are the best of the Eldar, strong, fast, intellectual, though
+R:D:they sometimes lack wisdom.
+R:S:1:3:2:3:1:5:0
+R:K:4:20:20:4:3:14:10:25
+R:P:10:200:4:7
+R:M:100:30:90:10:190:20:82:10:180:15
+R:E:1:1:1:2:1:1
+R:R:1:0
+R:F:SEE_INVIS |
+R:F:RES_LITE |
+R:G:ELF
+R:C:Warrior | Archer | Mage | Priest | Loremaster | Pacifist
+R:k:+400:+000:Disarming
+R:k:+2000:+000:Magic-Device
+R:k:+10000:+000:Spirituality
+R:k:+4000:+000:Stealth
+R:k:+300:+000:Sneakiness
+R:k:+1000:+000:Weaponmastery
+R:k:+2500:+000:Archery
+
+R:N:10:Half-Ogre
+R:D:A crossbreed between a human and an ogre.
+R:D:They are similar to half-trolls, strong and dumb.
+R:S:3:-1:-1:-1:3:-3:-2
+R:K:-3:-5:-5:-2:-1:5:20:0
+R:P:12:130:3:74
+R:M:40:10:92:10:255:60:80:8:235:60
+R:E:1:1:1:2:1:1
+R:Z:set explosive rune
+R:R:1:0
+R:F:SUST_STR | RES_DARK |
+R:C:Warrior | Priest | Pacifist
+R:k:-300:+000:Disarming
+R:k:-500:+000:Magic-Device
+R:k:-2500:+000:Spirituality
+R:k:-2000:+000:Stealth
+R:k:-100:+000:Sneakiness
+R:k:+2000:+000:Weaponmastery
+R:k:+000:+000:Archery
+
+R:N:11:Beorning
+R:D:A race of men shapeshifters.
+R:D:They have the unique power of being able to polymorph to bear forms.
+R:S:4:-2:-2:-1:3:-5:1
+R:K:-6:-8:-6:-2:-1:5:25:5
+R:P:12:150:3:75
+R:M:40:10:100:10:255:65:80:10:240:64
+R:E:1:1:1:2:1:1
+R:Z:turn into a bear
+R:R:1:0
+R:F:SUST_STR |
+R:R:20:1
+R:F:STR |
+R:C:Warrior | Rogue | Loremaster
+R:k:+1000:+1000:Bearform-combat
+R:k:-600:+000:Disarming
+R:k:-800:+000:Magic-Device
+R:k:-3000:+000:Spirituality
+R:k:-2000:+000:Stealth
+R:k:-100:+000:Sneakiness
+R:k:+2500:+000:Weaponmastery
+R:k:+500:+000:Archery
+
+### Druedain - replace Kobolds in Theme
+
+R:N:12:Druadan
+R:D:Druedain are an ancient branch of the race of Men.
+R:D:Wiser and quicker than the Edain, but weaker and less intelligent.
+R:D:Not as pretty as their common human cousins, but sturdier.
+R:S:-2:-3:2:3:2:-2:1
+R:K:5:0:0:5:15:15:0:5
+R:P:9:115:0:82
+R:M:14:6:65:6:162:25:58:4:145:20
+R:E:1:1:1:2:1:1
+R:Z:poison dart
+R:R:1:0
+R:F:RES_POIS |
+R:C:Warrior | Archer | Rogue | Loremaster | Pacifist
+R:k:+0:+250:Boomerang-mastery
+R:k:-200:+000:Disarming
+R:k:-300:+000:Magic-Device
+R:k:-1000:+000:Spirituality
+R:k:+1000:+000:Stealth
+R:k:+100:+000:Sneakiness
+R:k:+1000:+000:Weaponmastery
+R:k:+800:+000:Archery
+
+R:N:13:Petty-Dwarf
+R:D:A nearly extinct subrace of dwarves.
+R:D:They prefer to live in the darkness.
+R:S:1:-1:2:0:2:-4:-5
+R:K:3:5:10:1:5:10:9:0
+R:P:11:135:5:87
+R:M:40:12:43:3:92:6:40:3:78:3
+R:E:1:1:1:2:1:1
+R:Z:detect doors and traps
+R:R:1:0
+R:F:RES_DARK | RES_DISEN | LITE1
+R:C:Warrior | Rogue
+R:k:+300:+000:Disarming
+R:k:+500:+000:Magic-Device
+R:k:+5000:+000:Spirituality
+R:k:+1000:+000:Stealth
+R:k:+500:+000:Sneakiness
+R:k:+000:+000:Weaponmastery
+R:k:+000:+000:Archery
+
+R:N:14:Dark-Elf
+R:D:Elves are the first born, the Eldar.
+R:D:Dark elves are rare on Middle-earth and even though not evil
+R:D:they are not good.
+R:S:-1:3:2:2:-2:1:-2
+R:K:5:15:20:3:8:12:-5:10
+R:P:9:150:5:69
+R:M:75:75:60:4:100:6:54:4:80:6
+R:E:1:1:1:2:1:1
+R:Z:magic missile
+R:R:1:0
+R:F:RES_DARK |
+R:R:20:0
+R:F:SEE_INVIS |
+R:C:Warrior | Archer | Mage | Rogue | Priest
+R:G:ELF
+R:k:+0:+200:Magic
+R:k:+500:+000:Disarming
+R:k:+1500:+000:Magic-Device
+R:k:+10000:+000:Spirituality
+R:k:+3000:+000:Stealth
+R:k:+800:+000:Sneakiness
+R:k:-500:+000:Weaponmastery
+R:k:+1000:+000:Archery
+
+R:N:15:Ent
+R:D:Guardian of the forests of Middle-earth, summoned by Yavanna before
+R:D:even the elves awoke. It is said 'Trolls are strong, Ents are STRONGER'.
+R:S:10:-3:2:-5:11:-3:-2
+R:K:5:5:20:-6:5:4:15:5
+R:P:14:210:5:95
+R:M:255:70:72:6:100:25:66:4:100:20
+R:E:1:1:1:2:1:1
+R:Z:grow trees
+R:G:NO_STUN | NO_FOOD |
+R:G:AC_LEVEL |
+R:R:1:-5
+R:F:SPEED | SENS_FIRE | SLOW_DIGEST | RES_POIS
+R:R:5:0
+R:F:SEE_INVIS |
+R:R:20:0
+R:F:ESP_ORC |
+R:F:ESP_TROLL | ESP_EVIL |
+R:C:Warrior | Priest | Loremaster | Pacifist
+R:O:70:32:2d3
+R:b:1:Tree walking
+R:k:+0:+200:Barehand-combat
+R:k:+0:+600:Boulder-throwing
+R:k:+500:+000:Disarming
+R:k:+500:+000:Magic-Device
+R:k:+10000:+000:Spirituality
+R:k:-6000:+000:Stealth
+R:k:+500:+000:Sneakiness
+R:k:-300:+000:Weaponmastery
+R:k:-200:+000:Archery
+
+R:N:16:RohanKnight
+R:D:Humans from the land of Rohan, riding the great Mearas.
+R:D:Fast and powerful in battle.
+R:S:4:-2:3:1:4:2:0
+R:K:10:5:5:-8:1:1:5:5
+R:P:10:220:0:84
+R:M:20:3:60:3:80:4:54:3:70:4
+R:E:1:1:1:2:1:1
+R:Z:Rohan Knight's Powers
+R:R:1:3
+R:F:SPEED |
+R:R:5:1
+R:F:SPEED |
+R:R:10:1
+R:F:SPEED |
+R:R:15:1
+R:F:SPEED |
+R:R:20:1
+R:F:SPEED |
+R:R:25:1
+R:F:SPEED |
+R:R:30:1
+R:F:SPEED |
+R:R:35:1
+R:F:SPEED |
+R:R:40:1
+R:F:SPEED |
+R:R:45:1
+R:F:SPEED |
+R:C:Warrior | Priest | Pacifist
+R:k:+1000:+000:Disarming
+R:k:+500:+000:Magic-Device
+R:k:+2500:+000:Spirituality
+R:k:-8000:+000:Stealth
+R:k:+100:+000:Sneakiness
+R:k:+100:+200:Weaponmastery
+R:k:+500:+000:Archery
+
+### Eagles - replace Thunderlords
+
+R:N:17:Eagle
+R:D:A Great Eagle of Manwe, his most faithful servant.
+R:D:They have been given many gifts from their master.
+R:S:6:2:1:-2:3:6:4
+R:K:6:0:10:-16:30:10:0:0
+R:P:12:300:5:89
+R:M:14:6:180:6:255:25:150:4:230:20
+R:E:0:1:0:4:1:1
+R:R:1:0
+R:F:FEATHER | FLY
+R:R:4:0
+R:F:ESP_DRAGON |
+R:R:5:0
+R:F:RES_ELEC |
+R:R:10:0
+R:F:RES_COLD |
+R:R:15:0
+R:F:RES_ACID |
+R:R:17:0
+R:F:RES_FIRE |
+R:R:35:0
+R:F:RES_POIS |
+R:R:45:0
+R:F:IM_ELEC |
+R:R:50:0
+R:F:CLIMB
+R:k:+1000:+300:Barehand-combat
+R:C:Loremaster | Mage | Priest | Pacifist
+R:k:+600:+000:Disarming
+R:k:+000:+000:Magic-Device
+R:k:+5000:+000:Spirituality
+R:k:-16000:+000:Stealth
+R:k:+3000:+000:Sneakiness
+
+### Base race characteristics tweaked from Annals of Ea for Theme.
+
+R:N:18:Dragon
+R:D:One of Morgoth's favourite pets.
+R:D:Very strong and smart, but unstealthy.
+R:D:They cannot play instruments or wield weapons.
+# R:S:str:int:wis:dex:con:chr:luck
+R:S:3:2:2:-2:2:-5:-2
+R:K:5:5:5:-10:5:5:5:-20
+R:P:9:250:5:100
+R:M:50:150:200:-200:80:120:54:-50:100:60
+# R:E:weapons:torso:arms:finger:head:legs
+R:E:0:1:0:6:1:1
+R:R:1:0
+R:k:=0:=0:Weaponmastery
+R:k:+0:+400:Barehand-combat
+R:k:=0:=0:Geomancy
+R:F:FLY
+R:C:Loremaster | Mage | Priest | Pacifist
+#R:G:EVIL
+R:k:+1000:+000:Disarming
+R:k:+500:+000:Magic-Device
+R:k:-4000:+000:Spirituality
+R:k:-10000:+000:Stealth
+R:k:+000:+000:Sneakiness
+
+R:N:19:Yeek
+R:D:The weakest of all the races, bad at everything except gaining levels quickly.
+R:S:-5:-5:-5:-5:-5:-5:-5
+R:K:-5:-5:-10:0:-5:0:-10:-10
+R:P:6:25:2:29
+R:M:10:4:40:5:50:10:35:4:45:10
+R:E:1:1:1:2:1:1
+R:C:Warrior | Archer | Mage | Rogue | Priest | Loremaster | Pacifist
+R:k:-500:+000:Disarming
+R:k:-500:+000:Magic-Device
+R:k:-2500:+000:Spirituality
+R:k:-5000:+000:Stealth
+R:k:-500:+000:Sneakiness
+R:k:-500:+000:Weaponmastery
+R:k:-500:+000:Archery
+
+### Wood-Elves tweaked in Theme.
+
+R:N:20:Wood-Elf
+R:D:Elves are the first born, the Eldar.
+R:D:Wood Elves live in the great forests of Middle-earth.
+R:D:They are more dangerous but less wise than High Elves.
+R:S:2:2:-3:5:0:1:0
+R:K:5:6:6:5:8:12:-5:40
+R:P:7:130:4:5
+R:M:75:75:60:4:100:6:54:4:80:6
+R:E:1:1:1:2:1:1
+R:G:XTRA_MIGHT_BOW |
+R:R:1:1
+R:F:XTRA_MIGHT | RES_LITE |
+R:C:Warrior | Archer | Mage | Priest | Loremaster | Pacifist
+R:G:ELF
+R:k:+0:+200:Archery
+R:b:1:Tree walking
+R:k:+500:+000:Disarming
+R:k:+600:+000:Magic-Device
+R:k:+3000:+000:Spirituality
+R:k:+5000:+000:Stealth
+R:k:+800:+000:Sneakiness
+R:k:+1000:+000:Weaponmastery
+R:k:+4000:+000:Archery
+
+### Maiar heavily tweaked in Theme
+
+R:N:21:Maia
+R:D:An old race, dating from before the creation of Arda, the Maiar were
+R:D:created by Eru to help the Valar in their task.
+R:S:0:0:0:0:0:0:4
+R:K:0:0:0:0:0:10:0:0
+R:P:10:100:0:91
+R:M:14:6:72:6:180:25:66:4:150:20
+R:E:1:1:1:2:1:1
+R:G:NO_GOD
+R:R:20:0
+R:F:DRAIN_EXP |
+R:R:6:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:12:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:18:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:24:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:30:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:36:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:42:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:R:48:1
+R:F:STR | INT | WIS | DEX | CON | CHR |
+R:C:Warrior | Archer | Mage | Pacifist
+R:k:+000:+000:Disarming
+R:k:+000:+000:Magic-Device
+R:k:+000:+000:Spirituality
+R:k:=0:=0:Prayer
+R:k:+000:+000:Stealth
+R:k:+000:+000:Sneakiness
+R:k:+000:+000:Weaponmastery
+R:k:+000:+000:Archery
+
+### Easterling -- new race added in Theme.
+
+R:N:22:Easterling
+R:D:The humans of the Southeast, servants of the Dark.
+R:D:They are traditional masters of many combat skills.
+R:D:Fanatical warriors, they do not trust magic.
+R:S:2:-2:-2:-2:2:-1:-1
+R:K:0:-5:-1:0:0:10:5:5
+R:P:10:140:0:105
+R:M:14:6:72:6:180:25:66:4:150:20
+R:E:1:1:1:2:1:1
+R:C:Warrior | Archer
+R:G:XTRA_MIGHT_XBOW | NO_STUN
+R:R:5:0
+R:F:FREE_ACT
+R:R:15:0
+R:F:RES_CONF
+R:k:+1000:+100:Combat
+R:k:+500:+100:Weaponmastery
+R:k:+0:+200:Sword-mastery
+R:k:+0:+200:Axe-mastery
+R:k:+0:+200:Hafted-mastery
+R:k:+0:+200:Polearm-mastery
+R:k:+2000:+200:Archery
+R:k:+1000:+300:Sneakiness
+R:k:+1000:+200:Stealth
+R:k:+1000:+200:Disarming
+R:k:=0:=0:Magic
+R:k:=0:=0:Magic-Device
+R:k:=0:=0:Spell-power
+R:k:+2500:+300:Spirituality
+
+### Demon -- new race added in Theme
+
+R:N:23:Demon
+R:D:Demons (Roeg) are minor servants of the Dark,
+R:D:they were once natural creatures and have been
+R:D:corrupted by Melkor to serve his ends.
+# They all get an inherent CHR penalty, other stats depend on subrace.
+R:S:0:0:0:0:0:-1:0
+# Again, here everything depends on subrace
+R:K:0:0:0:0:0:0:0:0
+R:P:10:170:3:109
+R:M:14:6:72:6:180:25:66:4:150:20
+# Everything at zero here, depends on type of demon.
+R:E:0:0:0:0:0:0
+R:C:Warrior | Archer | Mage | Rogue | Priest | Loremaster
+R:G:CORRUPT
+R:F:RES_FEAR | HOLD_LIFE | RES_DARK
+R:Z:spear of darkness
+R:k:+500:+000:Disarming
+R:k:+050:+000:Magic-Device
+R:k:-5000:+000:Spirituality
+R:k:+000:+000:Stealth
+R:k:+000:+000:Sneakiness
+R:k:+000:+000:Weaponmastery
+R:k:+000:+000:Archery
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# S: Subrace definition
+# S:N:index:name
+# S:D:'A'fter/'B'efore:subrace desc
+# S:S:str:int:wis:dex:con:chr:luck:mana
+# S:K:dis:dev:sav:stl:srh:fos:thn:thb
+# S:P:hitdie:xp%:infra
+# S:M:b_age:m_age:m_b_ht:m_m_ht:m_b_wt:m_m_wt:f_b_ht:f_m_ht:f_b_wt:f_m_wt
+# S:E:weapons:torso:arms:finger:head:legs
+# S:A:allowed races
+# S:C:'A'llow/'F'orbid:allowed/forbiden classes
+# S:G:subrace flags
+# S:R:level:pval
+# S:F:flags
+# S:k:value:modifier:skill name
+# S:b:level:ability
+
+# Make the parser actually work :)
+I:
+
+S:N:0:
+S:D:A:A normal member of the race.
+S:S:0:0:0:0:0:0:0:100
+S:K:0:0:0:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Orc | Troll | Dunadan | High-Elf | Half-Ogre | Beorning |
+S:A:Druadan | Petty-Dwarf | Dark-Elf | Ent | RohanKnight | Eagle |
+S:A:Yeek | Wood-Elf | Maia | Easterling
+
+# Just a place holder, the actualy setting are done with corruptions, see
+# corrupt.lua and player.lua
+S:N:1:Vampire
+S:D:B:Vampires are powerful undead, wielding great powers. They still fear the
+S:D:B:sunlight and cannot easily satiate their hunger.
+S:S:0:0:0:0:0:0:0:100
+S:K:0:0:0:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Hobbit | Gnome | Dwarf | Orc |
+S:A:Troll | Dunadan | Half-Ogre | Beorning | Druadan | Petty-Dwarf |
+S:A:Dark-Elf | RohanKnight | Yeek | Easterling
+S:C:A:Mage
+S:O:70:0:5d3
+S:O:70:32:2d3
+
+S:N:2:Spectre
+S:D:B:Spectres only partially exist in the mortal world and so they can
+S:D:B:pass through walls. They are somewhat physically weak.
+S:S:-5:1:1:2:-3:-6:-3:105
+S:K:2:8:7:2:2:7:-5:-2
+S:P:-4:80:3
+S:M:50:15:0:0:-10:-5:0:0:-10:-5
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Orc | Troll | Dunadan | High-Elf | Half-Ogre | Beorning | Easterling |
+S:A:Druadan | Petty-Dwarf | Dark-Elf | RohanKnight | Yeek | Wood-Elf |
+S:C:F:Warrior | Archer
+S:G:UNDEAD | NO_CUT | NO_FOOD | SEMI_WRAITH | NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SEE_INVIS | HOLD_LIFE |
+S:F:SLOW_DIGEST | RES_COLD | RES_POIS | RES_NETHER |
+S:O:70:32:2d3
+S:k:+200:+000:Disarming
+S:k:+800:+000:Magic-Device
+S:k:+700:+000:Spirituality
+S:k:+2000:+000:Stealth
+S:k:+200:+000:Sneakiness
+S:k:-500:+000:Weaponmastery
+S:k:-200:+000:Archery
+
+S:N:3:Skeleton
+S:D:B:Yet an other kind of undead. Their physical 'body' is not very vulnerable
+S:D:B:to sharp things.
+S:S:0:-2:-2:0:1:-4:-3:70
+S:K:-5:-5:5:-1:-1:8:8:0
+S:P:0:45:1
+S:M:50:15:0:0:-10:-5:0:0:-10:-5
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Orc | Troll | Dunadan | High-Elf | Half-Ogre | Beorning | Easterling |
+S:A:Druadan | Petty-Dwarf | Dark-Elf | RohanKnight | Yeek | Wood-Elf |
+S:G:UNDEAD | NO_CUT | NO_FOOD | NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SEE_INVIS | HOLD_LIFE |
+S:F:RES_POIS | RES_SHARDS |
+S:R:10:0
+S:F:RES_COLD |
+S:O:70:32:2d3
+S:k:-500:+000:Disarming
+S:k:-500:+000:Magic-Device
+S:k:+500:+000:Spirituality
+S:k:-1000:+000:Stealth
+S:k:-100:+000:Sneakiness
+S:k:+800:+000:Weaponmastery
+S:k:+000:+000:Archery
+
+S:N:4:Zombie
+S:D:B:Strong and dumb is a zombie.
+S:S:2:-6:-6:1:4:-5:-4:70
+S:K:-2:-2:5:-1:-1:2:5:0
+S:P:3:45:1
+S:M:50:15:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Orc | Troll | Dunadan | High-Elf | Half-Ogre | Beorning | Easterling |
+S:A:Druadan | Petty-Dwarf | Dark-Elf | RohanKnight | Yeek | Wood-Elf |
+S:C:F:Mage
+S:G:UNDEAD | NO_FOOD | NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SEE_INVIS | HOLD_LIFE |
+S:F:SLOW_DIGEST | RES_POIS |
+S:R:5:0
+S:F:RES_COLD |
+S:O:70:32:2d3
+S:k:-200:+000:Disarming
+S:k:-200:+000:Magic-Device
+S:k:+500:+000:Spirituality
+S:k:-1000:+000:Stealth
+S:k:-100:+000:Sneakiness
+S:k:+500:+000:Weaponmastery
+S:k:+000:+000:Archery
+
+S:N:5:Barbarian
+S:D:A:Hardy members of their race, they are strong fighters but poor spellcasters.
+S:S:2:-3:-2:1:1:-3:1:50
+S:K:-2:-10:2:-2:0:1:12:5
+S:P:1:25:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Dwarf | Orc | Troll | Half-Ogre | Beorning | Druadan | Easterling
+S:C:F:Mage
+S:R:10:0
+S:F:RES_FEAR |
+S:k:-200:+000:Disarming
+S:k:-1000:+000:Magic-Device
+S:k:+200:+000:Spirituality
+S:k:-2000:+000:Stealth
+S:k:+000:+000:Sneakiness
+S:k:+1200:+000:Weaponmastery
+S:k:+500:+000:Archery
+
+S:N:6:Hermit
+S:D:A:Through years of isolation hermits can manage to increase their mana
+S:D:A:reserves but at the cost of an increased physical weakness.
+S:S:-3:1:1:-3:-3:1:0:120
+S:K:5:10:5:3:4:10:-5:-5
+S:P:-3:20:1
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Human | Half-Elf | Elf | Hobbit | Gnome | Dwarf |
+S:A:Dunadan | High-Elf | Petty-Dwarf | Dark-Elf | Ent | RohanKnight |
+S:A:Eagle | Yeek | Wood-Elf | Maia |
+S:C:F:Warrior | Archer
+S:k:+500:+000:Disarming
+S:k:+1000:+000:Magic-Device
+S:k:+500:+000:Spirituality
+S:k:+3000:+000:Stealth
+S:k:+400:+000:Sneakiness
+S:k:-500:+000:Weaponmastery
+S:k:-500:+000:Archery
+
+S:N:8:LostSoul
+S:D:A:In some very rare occasions souls can come back from the Halls of Mandos.
+S:S:0:0:0:0:0:0:0:100
+S:K:0:0:0:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:G:ASTRAL | NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SEE_INVIS
+S:A:Half-Elf | Elf | High-Elf | Dark-Elf | Wood-Elf | Maia |
+S:A:Hobbit | Gnome | Dwarf | Petty-Dwarf | Ent | Eagle |
+S:O:70:32:25d2
+S:O:70:12:25d3
+
+# Used for corruptions that can change your subrace
+S:N:9:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+S:D:A:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+S:S:0:0:0:0:0:0:0:100
+S:K:0:0:0:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+
+### Dragon subraces added for Theme
+
+S:N:10:Red
+S:D:B:These majestic creatures are surrounded by a furious blaze.
+S:D:B:They are especially resistant to fire and with time learn
+S:D:B:to resist its effects entirely. They are stronger than other
+S:D:B:dragons and can prevent attacks from sapping their strength.
+S:S:3:0:0:0:0:0:0:100
+S:K:0:0:0:0:-2:2:5:0
+S:P:0:0:1
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Dragon
+S:C:F:Warrior | Archer
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SUST_STR | SH_FIRE | RES_FIRE
+S:R:5:1
+S:F:STR
+S:R:10:1
+S:F:STR
+S:R:15:1
+S:F:STR
+S:R:20:1
+S:F:STR
+S:R:30:1
+S:F:STR
+S:R:40:1
+S:F:STR
+S:R:45:0
+S:F:IM_FIRE
+S:R:50:1
+S:F:STR | CLIMB
+S:Z:fire breath
+S:k:+1000:+600:Fire
+
+S:N:11:Black
+S:D:B:The hide of these dragons glistens with droplets of viscous
+S:D:B:liquid. They are especially resistant to acid and with time
+S:D:B:will come to resist its effects entirely. They look more
+S:D:B:beautiful than other dragons and are expert at protecting that.
+S:S:0:0:0:0:0:3:0:100
+S:K:2:0:1:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Dragon
+S:C:F:Archer | Warrior
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SUST_CHR | | RES_ACID
+S:R:5:1
+S:F:CHR
+S:R:10:1
+S:F:CHR
+S:R:15:1
+S:F:CHR
+S:R:20:1
+S:F:CHR
+S:R:30:1
+S:F:CHR
+S:R:40:1
+S:F:CHR
+S:R:45:0
+S:F:IM_ACID
+S:R:50:1
+S:F:CHR | CLIMB
+S:Z:spit acid
+S:k:+1000:+600:Water
+
+S:N:12:Green
+S:D:B:The entire forms of these creatures give off sickly greenish.
+S:D:B:vapours. They are especially resistant to poison and resist
+S:D:B:poison attacks exceptionally well. They are healthier and sturdier
+S:D:B:than other dragons and are not as susceptible to diseases.
+S:S:0:0:0:0:3:0:0:100
+S:K:0:0:2:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Dragon
+S:C:F:Archer | Warrior
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SUST_CON | RES_POIS
+S:R:5:1
+S:F:CON
+S:R:10:1
+S:F:CON
+S:R:15:1
+S:F:CON
+S:R:20:1
+S:F:CON
+S:R:30:1
+S:F:CON
+S:R:40:1
+S:F:CON
+S:R:50:1
+S:F:CON | CLIMB
+S:Z:poison dart
+S:k:+1000:+600:Air
+
+S:N:13:Blue
+S:D:B:These enormous creatures are wreathed in living lightning.
+S:D:B:They are especially nimble and agile, and their dexterity
+S:D:B:is not sapped easily.
+S:S:0:0:0:3:0:0:0:100
+S:K:3:0:0:2:1:0:0:0
+S:P:0:0:1
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Dragon
+S:C:F:Archer | Warrior
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SUST_DEX | RES_ELEC | SH_ELEC
+S:R:5:1
+S:F:DEX
+S:R:10:1
+S:F:DEX
+S:R:15:1
+S:F:DEX
+S:R:20:1
+S:F:DEX
+S:R:30:1
+S:F:DEX
+S:R:40:1
+S:F:DEX
+S:R:45:0
+S:F:IM_ELEC
+S:R:50:1
+S:F:DEX | CLIMB
+S:Z:dazzle
+S:k:+1000:+600:Earth
+
+S:N:14:White
+S:D:B:These enormous dragons look like they'd been hewed from ice.
+S:D:B:They are the most cunning and calculating among their kind,
+S:D:B:and attacks against their intelligence are unlikely to succeed.
+S:S:0:3:0:0:0:0:0:100
+S:K:0:2:0:0:0:0:0:0
+S:P:0:0:0
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Dragon
+S:C:F:Archer | Warrior
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SUST_INT | RES_COLD | SENS_FIRE
+S:R:5:1
+S:F:INT
+S:R:10:1
+S:F:INT
+S:R:15:1
+S:F:INT
+S:R:20:1
+S:F:INT
+S:R:30:1
+S:F:INT
+S:R:40:1
+S:F:INT
+S:R:45:0
+S:F:IM_COLD
+S:R:50:1
+S:F:INT | CLIMB
+S:Z:cold breath
+S:k:+1000:+600:Divination
+
+S:N:15:Ethereal
+S:D:B:These dragons' body surfaces seem to be in constant flux.
+S:D:B:They are powerful undead beings and are thus wiser than other
+S:D:B:dragons. Wisdom-sapping and life-draining attacks are not
+S:D:B:very effective against them.
+S:S:0:0:3:0:0:0:0:100
+S:K:0:0:1:5:2:2:0:0
+S:P:0:0:3
+S:M:0:0:0:0:0:0:0:0:0:0
+S:E:0:0:0:0:0:0
+S:A:Dragon
+S:C:F:Archer | Warrior
+S:G:NO_SUBRACE_CHANGE | UNDEAD | SEMI_WRAITH
+S:R:1:0
+S:F:SUST_WIS | HOLD_LIFE
+S:R:5:1
+S:F:WIS
+S:R:10:1
+S:F:WIS
+S:R:15:1
+S:F:WIS
+S:R:20:1
+S:F:WIS
+S:R:30:1
+S:F:WIS
+S:R:40:1
+S:F:WIS
+S:R:50:1
+S:F:WIS | CLIMB
+S:Z:chaos breath
+S:k:+1000:+600:Meta
+
+### Demon subraces for Theme module
+
+S:N:16:(Narrog)
+S:D:A:These ratlike demons have fangs that drip with venom,
+S:D:A:quick, scurrying feet, and winglike appendages on their
+S:D:A:slick, black backs. They are somewhat weak and sickly,
+S:D:A:but sly, cunning, and agile.
+S:S:-1:1:1:1:-1:-2:0:100
+S:K:2:0:1:2:2:20:0:0
+S:P:1:20:1
+S:M:14:6:72:6:180:25:66:4:150:20
+S:E:1:1:1:2:1:1
+S:A:Demon
+S:C:F:Priest
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:RES_POIS
+S:R:10:2
+S:F:SPEED
+S:R:30:2
+S:F:SPEED
+S:R:45:0
+S:F:FLY
+S:R:50:2
+S:F:SPEED
+S:Z:poison dart
+R:k:-200:+000:Weaponmastery
+R:k:+1000:+300:Archery
+R:k:+1000:+000:Sneakiness
+R:k:+500:+200:Disarming
+S:k:+1000:+500:Stealth
+R:k:+050:+000:Magic-Device
+S:k:+0:+200:Magic
+S:k:+1000:+300:Conveyance
+R:k:-500:+000:Spirituality
+
+S:N:17:(Aewrog)
+S:D:A:These birdlike demons' wings flap with blinding speed.
+S:D:A:They are somewhat physically weak, but may befuddle enemies
+S:D:A:so that they believe they'd never seen anything so beautiful.
+S:S:-2:0:0:0:0:+3:0:100
+S:K:0:0:1:-2:0:10:0:0
+S:P:1:0:1
+S:M:14:6:72:6:180:25:66:4:150:20
+# R:E:weapons:torso:arms:finger:head:legs
+S:E:0:1:2:4:1:1
+S:A:Demon
+S:C:F:Warrior | Archer | Priest
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:SUST_CHR | FLY
+S:R:5:0
+S:F:FREE_ACT
+S:R:10:0
+S:F:RES_FIRE
+S:R:50:0
+S:F:CLIMB
+R:k:-400:+000:Weaponmastery
+R:k:+000:+300:Archery
+R:k:+1000:+000:Sneakiness
+R:k:+500:+100:Disarming
+S:k:+500:+200:Stealth
+S:k:+0:+200:Magic
+S:k:+1000:+300:Mind
+S:Z:dazzle
+
+S:N:18:(Hurog)
+S:D:A:These doglike demons are one of the lowest forms of Morgoth's
+S:D:A:corrupted races, though their sense of smell is uncanny, and
+S:D:A:increases with experience.
+S:S:-1:0:0:0:-1:0:0:100
+S:K:2:0:2:0:5:30:0:0
+S:P:0:-10:2
+S:M:14:6:72:6:180:25:66:4:150:20
+S:E:1:1:1:2:1:1
+S:A:Demon
+S:C:F:Priest
+S:G:NO_SUBRACE_CHANGE
+S:R:5:0
+S:F:ESP_ANIMAL
+S:R:10:1
+S:F:ESP_ORC | SEARCH
+S:R:15:0
+S:F:ESP_TROLL
+S:R:20:1
+S:F:ESP_DRAGON | SEARCH
+S:R:25:0
+S:F:ESP_UNDEAD
+S:R:30:1
+S:F:ESP_NONLIVING | SEARCH
+S:R:35:0
+S:F:ESP_EVIL
+S:R:40:1
+S:F:ESP_GOOD | SEARCH
+S:R:45:0
+S:F:ESP_DEMON
+S:R:50:1
+S:F:ESP_ALL | SEARCH
+S:Z:smell monsters
+S:Z:smell metal
+R:k:+500:+300:Stealth
+R:k:+500:+200:Sneakiness
+R:k:+000:+000:Weaponmastery
+R:k:+000:+000:Archery
+
+S:N:19:(Sarnrog)
+S:D:A:Medium-sized winged humanoids that look like living stone.
+S:D:A:They are clumsy and dumb, but very strong and stout, and
+S:D:A:resist the elements fairly well.
+S:S:2:-1:-2:-2:2:-1:0:100
+# S:K:dis:dev:sav:stl:srh:fos:thn:thb
+S:K:-1:0:0:-8:-2:-10:5:0
+S:P:2:20:0
+S:M:14:6:72:6:180:25:66:4:150:20
+S:E:1:1:1:2:1:1
+S:A:Demon
+S:C:F:Priest | Mage
+S:G:NO_SUBRACE_CHANGE | NO_STUN
+S:R:1:0
+S:F:RES_POIS
+S:R:10:1
+S:F:RES_FIRE | TUNNEL
+S:R:20:1
+S:F:RES_ACID | TUNNEL
+S:R:30:1
+S:F:RES_ELEC | TUNNEL
+S:R:40:1
+S:F:RES_COLD | TUNNEL
+S:R:45:1
+S:F:RES_SHARDS | TUNNEL
+S:R:50:1
+S:F:RES_SOUND | TUNNEL
+S:k:+1000:+500:Boulder-throwing
+S:Z:eat rock
+R:k:-800:+000:Stealth
+R:k:-500:+000:Sneakiness
+R:k:-500:+000:Archery
+
+S:N:20:(Caborrog)
+S:D:A:Among the foulest of Morgoth's servants, these froglike
+S:D:A:demons are fast and smart, but not very strong or stealthy.
+S:D:A:As a result of their corruption, they develop a strange
+S:D:A:protective layer around them as they mature.
+S:S:-1:2:1:0:0:-3:0:100
+# S:K:dis:dev:sav:stl:srh:fos:thn:thb
+S:K:0:0:1:-10:2:10:0:0
+S:P:2:10:0
+S:M:14:6:72:6:180:25:66:4:150:20
+S:E:1:1:1:2:1:1
+S:A:Demon
+S:C:F:Archer | Priest
+S:G:NO_SUBRACE_CHANGE | NO_STUN | AC_LEVEL
+S:R:1:0
+S:F:RES_POIS
+S:R:1:7
+S:F:SPEED
+S:R:10:2
+S:F:INT
+S:R:30:2
+S:F:INT
+S:R:50:2
+S:F:INT
+S:k:+1000:+400:Dodging
+S:k:+0:+200:Magic
+S:k:+0:+300:Conveyance
+S:k:+0:+300:Temporal
+S:Z:panic hit
+R:k:-1000:+000:Stealth
+R:k:-500:+000:Sneakiness
+
+S:N:21:(Draugrog)
+S:D:A:These doglike demons are of a higher order than the Huroeg,
+S:D:A:they learn more quickly and have more sophisticated magical
+S:D:A:powers. Their arrogant snarling, however, makes them quite
+S:D:A:unstealthy.
+S:S:1:1:1:1:1:-1:0:100
+S:K:2:0:2:-20:5:30:0:0
+S:P:0:-20:2
+S:M:14:6:72:6:180:25:66:4:150:20
+S:E:1:1:1:2:1:1
+S:A:Demon
+S:C:F:Priest
+S:G:NO_SUBRACE_CHANGE
+S:R:4:0
+S:F:ESP_ANIMAL
+S:R:8:1
+S:F:ESP_ORC | SEARCH
+S:R:12:0
+S:F:ESP_TROLL
+S:R:16:1
+S:F:ESP_DRAGON | SEARCH
+S:R:20:0
+S:F:ESP_UNDEAD
+S:R:24:1
+S:F:ESP_NONLIVING | SEARCH
+S:R:28:0
+S:F:ESP_EVIL
+S:R:32:1
+S:F:ESP_GOOD | SEARCH
+S:R:36:0
+S:F:ESP_DEMON
+S:R:40:1
+S:F:ESP_ALL | SEARCH
+S:R:50:0
+S:F:PRECOGNITION
+S:Z:smell monsters
+S:Z:smell metal
+S:k:+0:+200:Magic
+S:k:+0:+200:Spirituality
+S:k:+1000:+500:Mindcraft
+R:k:-10000:+000:Stealth
+R:k:-500:+200:Sneakiness
+R:k:+300:+000:Weaponmastery
+R:k:+200:+000:Archery
+
+### This is Theme's implementation of the Avatar subrace from T-Plus by Ingeborg S. Norden, with obvious limitations.
+
+S:N:22:(Lygrog)
+S:D:A:These slithering snakelike forms lack many physical
+S:D:A:advantages, but are no less deadly for it. Their magical
+S:D:A:abilities, stealth, and cunning are legendary.
+S:S:-3:5:5:5:-1:-6:0:200
+S:K:5:5:5:10:5:50:0:0
+S:P:2:40:3
+S:M:14:6:72:6:180:25:66:4:150:20
+S:E:0:1:0:1:1:0
+S:A:Demon
+S:C:F:Warrior | Archer | Priest | Rogue
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:FEATHER | FREE_ACT | LITE1 | RES_POIS |
+S:R:1:0
+S:F:REGEN | SEE_INVIS | SLOW_DIGEST | SUST_CHR |
+S:R:1:10
+S:F:SPEED |
+S:R:5:0
+S:F:ESP_ANIMAL | RES_FIRE | RES_COLD | SUST_WIS |
+S:R:5:1
+S:F:LUCK | SPEED |
+S:R:10:0
+S:F:ESP_ORC | RES_ELEC | RES_ACID | SUST_INT | WATER_BREATH |
+S:R:10:1
+S:F:LUCK | SPEED |
+S:R:15:0
+S:F:ESP_TROLL | FLY | RES_CONF | RES_LITE | SUST_CON |
+S:R:15:1
+S:F:LUCK | SPEED | SPELL |
+S:R:20:0
+S:F:ESP_DRAGON | ESP_GIANT | LITE2 | RES_BLIND | SUST_DEX |
+S:R:20:1
+S:F:LUCK | SPEED |
+S:R:25:0
+S:F:ESP_UNDEAD | ESP_NONLIVING | RES_DISEN | RES_CHAOS | SUST_STR |
+S:R:25:1
+S:F:LUCK | SPEED |
+S:R:30:0
+S:F:ESP_EVIL | ESP_DEMON | RES_SOUND |
+S:R:30:1
+S:F:LUCK | SPEED | SPELL |
+S:R:35:0
+S:F:CLIMB | ESP_GOOD | ESP_THUNDERLORD | RES_SHARDS |
+S:R:35:1
+S:F:LUCK | SPEED |
+S:R:40:0
+S:F:ESP_UNIQUE | LITE3 | PRECOGNITION | RES_NEXUS | RES_NETHER |
+S:R:40:1
+S:F:LUCK | SPEED |
+S:R:45:0
+S:F:ESP_ALL | IM_ACID | IM_ELEC | IM_FIRE | IM_COLD | MAGIC_BREATH |
+S:R:45:1
+S:F:SPEED | SPELL |
+S:R:50:0
+S:F:IM_NETHER | REFLECT | WRAITH |
+S:R:50:1
+S:F:LUCK | SPEED |
+R:k:+25000:+500:Stealth
+R:k:+2000:+200:Sneakiness
+R:k:+2000:+300:Magic-Device
+
+S:N:23:(Limrog)
+S:D:A:Humanoid creatures with gill slits at the necks,
+S:D:A:they seem to flit in and out of existence.
+S:S:-2:1:1:3:-1:-1:2:150
+# S:K:dis:dev:sav:stl:srh:fos:thn:thb
+S:K:2:2:2:2:2:30:0:0
+S:P:1:50:2
+S:M:14:6:72:6:180:25:66:4:150:20
+S:E:1:1:1:2:1:1
+S:A:Demon
+S:C:F:Priest
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:WATER_BREATH
+S:R:50:0
+S:F:MAGIC_BREATH
+R:k:+3000:+300:Stealth
+R:k:+500:+200:Sneakiness
+R:k:+2000:+200:Disarming
+S:k:+0:+200:Magic
+S:k:+0:+500:Conveyance
+S:k:+0:+500:Temporal
+S:k:+0:+500:Meta
+S:Z:teleport
+S:Z:blink
+S:Z:panic hit
+S:Z:find secret passages
+
+S:N:24:(Rawrog)
+S:D:A:These creatures resemble lions standing on two legs.
+S:D:A:Very strong and smart, they instill fear in all who
+S:D:A:encounter them and are afraid of nothing.
+S:S:2:1:1:-1:2:1:1:100
+S:K:0:0:4:-3:0:10:10:10
+S:P:2:30:0
+S:M:14:6:72:6:180:25:66:4:150:20
+S:E:1:1:1:2:1:1
+S:A:Demon
+S:C:F:Priest | Mage
+S:G:NO_SUBRACE_CHANGE
+S:R:5:0
+S:F:RES_FIRE | RES_COLD
+S:R:10:0
+S:F:RES_ELEC | RES_ACID
+S:R:15:0
+S:F:RES_POIS | RES_CONF
+S:k:+1000:+100:Combat
+S:k:+1000:+100:Weaponmastery
+R:k:+1000:+100:Archery
+R:k:-300:+000:Stealth
+R:k:+500:+200:Sneakiness
+R:k:+500:+100:Disarming
+S:Z:scare monster
+S:Z:berserk
+
+S:N:25:(Adanrog)
+S:D:A:Horrifying humanoids wreathed in flames.
+S:D:A:They can be equally skilled in combat and
+S:D:A:magic; and they can temporarily assume the
+S:D:A:forms of true Balrogs.
+S:S:1:1:1:1:1:1:0:150
+S:K:1:1:1:1:1:20:15:10
+S:P:3:50:2
+S:M:14:6:72:6:180:25:66:4:150:20
+S:E:1:1:1:2:1:1
+S:A:Demon
+S:C:F:Priest | Loremaster | Rogue
+S:G:NO_SUBRACE_CHANGE
+S:R:1:0
+S:F:IM_FIRE | SH_FIRE
+S:k:+0:+300:Combat
+S:k:+0:+300:Magic
+S:Z:turn into a Balrog
+R:k:+1000:+300:Weaponmastery
+R:k:+1000:+300:Archery
+R:k:+1000:+200:Stealth
+R:k:+500:+200:Sneakiness
+R:k:+1000:+200:Disarming
+R:k:+500:+200:Magic
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# H: Race history
+# H:index:chance:chart:next chart:social class bonus:desc
+
+# Dunadan, Human: 1 -> 2 -> 3 -> 50 -> 51 -> 52 -> 53.
+# RohanKnight: 84 -> 85 -> 50 -> 51 -> 52 -> 53.
+# Half-Ogre: 74 -> 20 -> 2 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Beorning: 75 -> 76 -> 20 -> 2 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Half-elf: 4 -> 1 -> 2 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Elf, Wood-elf: 5 -> 6 -> 9 -> 54 -> 55 -> 56.
+# High-elf: 7 -> 8 -> 9 -> 54 -> 55 -> 56.
+# Dark-elf: 69 -> 70 -> 71 -> 72 -> 73.
+# Hobbit: 10 -> 11 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Gnome: 13 -> 14 -> 3 -> 50 -> 51 -> 52 -> 53.
+# Dwarf: 16 -> 17 -> 18 -> 57 -> 58 -> 59 -> 60 -> 61.
+# Petty-Dwarf: 87 -> 88 -> 18 -> 57 -> 58 -> 59 -> 60 -> 61.
+# Eagle: 89 -> 90.
+# Maia: 91 -> 92 -> 93 -> 94.
+# Ent: 95 -> 96.
+# Troll: 22 -> 23 -> 24 -> 62 -> 63 -> 64 -> 65 -> 66.
+# Orc 25 -> 26 -> 27 -> 28 -> 80 -> 81 -> 65 -> 66.
+# Yeek: 29 -> 3 -> 50 -> 51 -> 52 -> 53.
+# (not used: 78 -> 79 -> 80 -> 81 -> 65 -> 66.)
+# Druadan: 82 -> 83 -> 71 -> 72 -> 73.
+# Dragon: 100 -> 101 -> 102 -> 103 -> 104.
+# Easterling: 105 -> 106 -> 107 -> 108.
+# Demon: 109 -> 110 -> 111 -> 112.
+
+H:0:10:1:2:25:You are the illegitimate and unacknowledged child
+H:1:20:1:2:35:You are the illegitimate but acknowledged child
+H:2:95:1:2:45:You are one of several children
+H:3:100:1:2:50:You are the first child
+
+H:4:40:2:3:65:of a Serf.
+H:5:65:2:3:80:of a Yeoman.
+H:6:80:2:3:90:of a Townsman.
+H:7:90:2:3:105:of a Guildsman.
+H:8:96:2:3:120:of a Landed Knight.
+H:9:99:2:3:130:of a Noble Lord.
+H:10:100:2:3:140:of the Royal Blood Line.
+
+H:11:20:3:50:20:You are the black sheep of the family.
+H:12:80:3:50:55:You are a credit to the family.
+H:13:100:3:50:60:You are a well-liked child.
+
+H:14:25:4:1:40:Your mother was of the Avari.
+H:15:40:4:1:50:Your father was of the Avari.
+H:16:65:4:1:60:Your mother was of the Nandor.
+H:17:80:4:1:60:Your father was of the Nandor.
+H:18:96:4:1:70:Your mother was of the Sindar.
+H:19:99:4:1:70:Your father was of the Sindar.
+H:20:100:4:1:100:Your ancestry traces to Elrond.
+
+H:21:60:5:6:50:You are one of several children
+H:22:100:5:6:55:You are the only child
+
+H:23:40:6:9:40:of an Avarin
+H:24:70:6:9:50:of a Nandorin
+H:25:100:6:9:60:of a Sindarin
+
+H:26:60:7:8:50:You are one of several children
+H:27:100:7:8:55:You are the only child
+
+H:28:75:8:9:50:of a Telerin
+H:29:95:8:9:55:of a Noldorin
+H:30:100:8:9:60:of a Vanyarin
+
+H:31:40:9:54:80:Ranger.
+H:32:70:9:54:90:Archer.
+H:33:87:9:54:110:Warrior.
+H:34:95:9:54:125:Mage.
+H:35:99:9:54:140:Prince.
+H:36:100:9:54:145:King.
+
+H:37:85:10:11:45:You are one of several children of a Hobbit
+H:38:100:10:11:55:You are the only child of a Hobbit
+
+H:39:20:11:3:55:Bum.
+H:40:30:11:3:80:Tavern Owner.
+H:41:40:11:3:90:Miller.
+H:42:50:11:3:100:Home Owner.
+H:43:80:11:3:110:Burglar.
+H:44:95:11:3:115:Warrior.
+H:45:99:11:3:125:Mage.
+H:46:100:11:3:140:Clan Elder.
+
+H:47:85:13:14:45:You are one of several children of a Gnome
+H:48:100:13:14:55:You are the only child of a Gnome
+
+H:49:20:14:3:55:Beggar.
+H:50:50:14:3:70:Braggart.
+H:51:75:14:3:85:Prankster.
+H:52:95:14:3:100:Warrior.
+H:53:100:14:3:125:Mage.
+
+H:54:25:16:17:40:You are one of two children of a Dwarven
+H:55:100:16:17:50:You are the only child of a Dwarven
+
+H:56:10:17:18:60:Thief.
+H:57:35:17:18:80:Smith.
+H:58:75:17:18:90:Miner.
+H:59:90:17:18:110:Warrior.
+H:60:99:17:18:130:Priest.
+H:61:100:17:18:150:King.
+
+H:62:15:18:57:10:You are the black sheep of the family.
+H:63:85:18:57:50:You are a credit to the family.
+H:64:100:18:57:55:You are a well liked child.
+
+H:65:100:20:2:50:You are the adopted child
+
+H:66:100:22:23:50:You are the offspring of a
+
+H:67:30:23:24:20:Forest-Troll
+H:68:60:23:24:25:Cave-Troll
+H:69:75:23:24:30:Hill-Troll
+H:70:90:23:24:35:Stone-Troll
+H:71:95:23:24:40:Snow-Troll
+H:72:100:23:24:45:Water-Troll
+
+H:73:25:24:62:50:Worker.
+H:74:95:24:62:55:Warrior.
+H:75:99:24:62:65:Shaman.
+H:76:100:24:62:80:Clan Chief.
+
+H:77:100:25:26:50:You are one of several children of
+
+H:78:40:26:27:40:a Snaga
+H:79:80:26:27:50:an Orc
+H:80:100:26:27:60:an Uruk
+
+H:81:30:27:28:20:Slave
+H:82:60:27:28:50:Archer
+H:83:90:27:28:60:Warrior
+H:84:95:27:28:80:Shaman
+H:85:100:27:28:100:Chieftain
+
+H:86:30:28:80:50:from the Misty Mountains.
+H:87:60:28:80:50:from the Grey Mountains.
+H:88:90:28:80:70:from the orc-hold of Mount Gundabad.
+H:89:100:28:80:80:from the Pits of Angband.
+
+H:90:25:29:3:50:You are one of five children of a blue Yeek.
+H:91:75:29:3:75:You are one of five children of a brown Yeek.
+H:92:100:29:3:100:You are one of five children of a master Yeek.
+
+H:93:20:50:51:50:You have dark brown eyes,
+H:94:60:50:51:50:You have brown eyes,
+H:95:70:50:51:50:You have hazel eyes,
+H:96:80:50:51:50:You have green eyes,
+H:97:90:50:51:50:You have blue eyes,
+H:98:100:50:51:50:You have blue-gray eyes,
+
+H:99:70:51:52:50:straight
+H:100:90:51:52:50:wavy
+H:101:100:51:52:50:curly
+
+H:102:30:52:53:50:black hair,
+H:103:70:52:53:50:brown hair,
+H:104:80:52:53:50:auburn hair,
+H:105:90:52:53:50:red hair,
+H:106:100:52:53:50:blond hair,
+
+H:107:10:53:0:50:and a very dark complexion.
+H:108:30:53:0:50:and a dark complexion.
+H:109:80:53:0:50:and an average complexion.
+H:110:90:53:0:50:and a fair complexion.
+H:111:100:53:0:50:and a very fair complexion.
+
+H:112:85:54:55:50:You have light grey eyes,
+H:113:95:54:55:50:You have light blue eyes,
+H:114:100:54:55:50:You have light green eyes,
+
+H:115:75:55:56:50:straight
+H:116:100:55:56:50:wavy
+
+H:117:75:56:0:50:black hair, and a fair complexion.
+H:118:85:56:0:50:brown hair, and a fair complexion.
+H:119:95:56:0:50:blond hair, and a fair complexion.
+H:120:100:56:0:50:silver hair, and a fair complexion.
+
+H:121:99:57:58:50:You have dark brown eyes,
+H:122:100:57:58:60:You have glowing red eyes,
+
+H:123:90:58:59:50:straight
+H:124:100:58:59:50:wavy
+
+H:125:75:59:60:50:black hair,
+H:126:100:59:60:50:brown hair,
+
+H:127:25:60:61:50:a one foot beard,
+H:128:60:60:61:51:a two foot beard,
+H:129:90:60:61:53:a three foot beard,
+H:130:100:60:61:55:a four foot beard,
+
+H:131:100:61:0:50:and a dark complexion.
+
+H:132:60:62:63:50:You have slime green eyes,
+H:133:85:62:63:50:You have puke yellow eyes,
+H:134:99:62:63:50:You have blue-bloodshot eyes,
+H:135:100:62:63:55:You have glowing red eyes,
+
+H:136:33:63:64:50:dirty
+H:137:66:63:64:50:mangy
+H:138:100:63:64:50:oily
+
+H:139:33:64:65:50:sea-weed green hair,
+H:140:66:64:65:50:bright red hair,
+H:141:100:64:65:50:dark purple hair,
+
+H:142:25:65:66:50:and green
+H:143:50:65:66:50:and blue
+H:144:75:65:66:50:and white
+H:145:100:65:66:50:and black
+
+H:146:33:66:0:50:ulcerous skin.
+H:147:66:66:0:50:scabby skin.
+H:148:100:66:0:50:leprous skin.
+
+H:149:85:69:70:45:You are one of several children of a Dark Elven
+H:150:100:69:70:55:You are the only child of a Dark Elven
+
+H:151:50:70:71:60:Warrior.
+H:152:80:70:71:75:Warlock.
+H:153:100:70:71:95:Noble.
+
+H:154:100:71:72:50:You have black eyes,
+
+H:155:70:72:73:50:straight
+H:156:90:72:73:50:wavy
+H:157:100:72:73:50:curly
+
+H:158:100:73:0:50:black hair and a very dark complexion.
+
+H:159:25:74:20:25:Your mother was an Ogre, but it is unacknowledged.
+H:160:100:74:20:25:Your father was an Ogre, but it is unacknowledged.
+
+H:161:90:75:76:50:You are a descendant of Beorn to the
+H:162:100:75:20:100:Your father was Beorn.
+
+H:163:13:76:20:55:9th degree.
+H:164:25:76:20:60:8th degree.
+H:165:38:76:20:65:7th degree.
+H:166:50:76:20:70:6th degree.
+H:167:63:76:20:75:5th degree.
+H:168:75:76:20:80:4th degree.
+H:169:88:76:20:85:3rd degree.
+H:170:100:76:20:90:2nd degree.
+
+H:171:100:78:79:50:You are one of several children of
+
+H:172:50:79:80:50:a Brown Yeek.
+H:173:75:79:80:50:a Blue Yeek.
+H:174:95:79:80:85:a Master Yeek.
+H:175:100:79:80:120:Boldor, the King of the Yeeks.
+
+H:176:25:80:81:50:You have pale eyes,
+H:177:50:80:81:50:You have glowing eyes,
+H:178:75:80:81:50:You have tiny black eyes,
+H:179:100:80:81:50:You have shining black eyes,
+
+H:180:20:81:65:50:no hair at all,
+H:181:40:81:65:50:short black hair,
+H:182:60:81:65:50:long black hair,
+H:183:80:81:65:50:bright red hair,
+H:184:100:81:65:50:colourless albino hair,
+
+### Kobold histories replaced by Druadan histories
+
+H:185:100:82:83:50:You are one of several children of
+
+H:186:40:83:71:50:a Druadan Gatherer.
+H:187:75:83:71:55:a Druadan Hunter.
+H:188:95:83:71:65:a Druadan Shaman.
+H:189:100:83:71:100:Ghan-buri-Ghan.
+
+H:190:85:84:85:45:You are one of several children
+H:191:100:84:85:50:You are the first child
+
+H:192:60:85:50:40:of a Serf.
+H:193:85:85:50:55:of a Devoted Mercenary.
+H:194:96:85:50:60:of a Landed Knight.
+H:195:99:85:50:100:of a Marshal of the Riddermark.
+H:196:100:85:50:120:of a King of the Mark.
+
+H:197:100:87:88:89:You are one of several children of
+
+H:198:30:88:18:20:a Petty-Dwarf Slave.
+H:199:50:88:18:40:a Petty-Dwarf Thief.
+H:200:70:88:18:60:a Petty-Dwarf Smith.
+H:201:90:88:18:75:a Petty-Dwarf Miner.
+H:202:95:88:18:100:a Petty-Dwarf Shaman.
+H:203:100:88:18:100:Mim, Betrayer of Turin.
+
+H:204:85:89:90:50:You are one of many Eagles of Manwe.
+H:205:100:89:90:60:You are the one of the most known Eagles of Manwe.
+
+H:206:90:90:0:100:Your back and breast are dark brown, and you have very large wings.
+H:207:100:90:0:120:Your back and breast are dazzling white, your wings magnificent.
+
+H:208:10:91:92:20:You are a unnoticed minion of
+H:209:25:91:92:30:You are a minor servant of
+H:210:45:91:92:40:You are a subject of
+H:211:65:91:92:50:You have attached yourself to
+H:212:85:91:92:65:You are associated with
+H:213:95:91:92:80:You are a notable follower of
+H:214:100:91:92:100:You are a celebrated assistant to
+
+H:215:20:92:93:55:Nessa.
+H:216:40:92:93:60:Vana.
+H:217:50:92:93:65:Tulkas.
+H:218:80:92:93:75:Mandos.
+H:219:90:92:93:80:Nienna.
+H:220:95:92:93:90:Varda.
+H:221:100:92:93:95:Manwe.
+
+H:222:100:93:94:50:In the past you dwelt on earth in the form of
+
+H:223:25:94:0:50:various animals.
+H:224:55:94:0:55:a spirit of forest and river.
+H:225:70:94:0:60:a beneficent but unseen force.
+H:226:96:94:0:70:a wise and ancient counsellor.
+H:227:100:94:0:80:a Wizard of legend.
+
+H:228:30:95:96:30:You are of an unknown generation of the Ents.
+H:229:40:95:96:50:You are of the third generation of the Ents.
+H:230:60:95:96:60:You are of the second generation of the Ents.
+H:231:100:95:96:80:You are one of the first beings who awoke on Arda.
+
+H:232:50:96:0:50:You have green skin and inflexible members.
+H:233:100:96:0:50:You have brown skin and inflexible members.
+
+### Death Mold histories have been replaced by Dragon histories.
+
+H:234:10:100:101:30:You were born in the land of Rhun,
+H:235:20:100:101:35:You were born in the Misty Mountains,
+H:236:30:100:101:40:You were born in the Blue Mountains,
+H:237:40:100:101:45:You were born in Dol Guldur,
+H:238:50:100:101:50:You were born in Angmar,
+H:239:60:100:101:50:You were born in Barad-dur,
+H:240:70:100:101:55:You were born at the foot of the Orodruin,
+H:241:80:100:101:60:You were born in Angband,
+H:242:90:100:101:65:You were born in Utumno,
+H:243:100:100:101:70:You were born in the Void,
+
+H:244:10:101:102:30:awakened by accident.
+H:245:20:101:102:35:awakened by hunger.
+H:246:30:101:102:40:awakened by the glint of jewels.
+H:247:40:101:102:45:awakened by an unsuspecting traveler.
+H:248:50:101:102:50:awakened by a corrupt Mage.
+H:249:60:101:102:50:awakened by an evil Sorcerer.
+H:250:70:101:102:55:awakened by a powerful evil Wizard.
+H:251:80:101:102:60:awakened by the Witch-King of Angmar.
+H:252:90:101:102:65:awakened by Gorthaur.
+H:253:100:101:102:70:awakened by Melkor Bauglir.
+
+H:254:100:102:103:50:Since then you have destroyed
+
+H:255:10:103:104:30:no
+H:256:20:103:104:35:one weak-willed
+H:257:30:103:104:40:two
+H:258:40:103:104:45:three
+H:259:50:103:104:50:four
+H:260:60:103:104:50:five
+H:261:70:103:104:55:about twenty
+H:262:80:103:104:60:dozens of
+H:263:90:103:104:65:hundreds of
+H:264:100:103:104:70:uncounted multitudes of
+
+H:265:100:104:0:50:enemies of the Dark.
+
+### Easterling histories added in the Theme module
+
+H:266:50:105:106:50:You are one of many children of
+H:267:100:105:106:50:You are the only child of
+
+H:268:20:106:107:35:an Easterling slave.
+H:269:30:106:107:40:an Easterling landlord.
+H:270:40:106:107:45:an Easterling squire.
+H:271:50:106:107:50:an Easterling warrior.
+H:272:60:106:107:55:a Wainrider from Near Harad.
+H:273:70:106:107:60:a warlord from Far Harad.
+H:274:80:106:107:65:a Corsair of Umbar.
+H:275:90:106:107:70:Ulfast, son of Ulfang.
+H:276:100:106:107:75:Ulwarth, son of Ulfang.
+
+H:277:25:107:108:10:You have brown eyes,
+H:278:50:107:108:30:You have piercing black eyes,
+H:279:100:107:108:60:You have alert yellow eyes,
+
+H:280:50:108:0:25:chestnut brown hair, and a dark complexion.
+H:281:100:108:0:50:jet-black hair, and a dark complexion.
+
+H:282:40:109:110:60:You have only recently been corrupted,
+H:283:60:109:110:70:You've been corrupted for quite a while,
+H:284:100:109:110:80:You were one of the first beings to be corrupted,
+
+H:285:40:110:111:60:and your entire being detests this fact.
+H:286:60:110:111:70:but you don't mind it so much anymore.
+H:287:100:110:111:80:and you consider that to have been your true birth.
+
+H:288:40:111:112:60:Your watery green eyes
+H:289:60:111:112:70:Your piercing black eyes
+H:290:100:111:112:80:Your glowing red eyes
+
+H:291:40:112:0:60:radiate miserable servility.
+H:292:60:112:0:70:radiate contempt.
+H:293:100:112:0:80:radiate pure evil.
+
+##############################################################################
+##############################################################################
+##############################################################################
+##############################################################################
+# M:N:idx:color:Meta class name
+# M:C:class name
+
+I:
+
+M:N:0:U:Classes -- The Classes of Middle-earth
+M:C:Warrior
+M:C:Archer
+M:C:Rogue
+M:C:Mage
+M:C:Priest
+M:C:Loremaster
+M:C:Pacifist
+#M:C:Test
+#M:C:Chaos-Warrior
+
+#M:N:1:B:Spellcasters -- Magic is The One True Way
+
+#M:N:2:y:Priests -- Hail the powers of the Ainur
+#M:C:Mindcrafter
+
+#M:N:3:G:Beastfriends -- Monsters are fun
+#M:C:BeastMaster
+
+#M:N:4:v:Others -- The way to your independence
+#M:C:Harper
+#M:C:Merchant
+
+#M:N:5:o:Tests -- Test is you dare !
+#M:C:Test
+#M:C:Blade
+#M:C:Black-Knight
diff --git a/lib/mods/theme/edit/qrand1.map b/lib/mods/theme/edit/qrand1.map
new file mode 100644
index 00000000..f42cbf1c
--- /dev/null
+++ b/lib/mods/theme/edit/qrand1.map
@@ -0,0 +1,32 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep lava
+F:F:85:12
+
+# Dungeon layout
+D:
+D: xxxxxxx
+D: xpGF..x
+D: xGGF,.D
+D: xFFF..x
+D: xxxxxxx
+D:
diff --git a/lib/mods/theme/edit/qrand10.map b/lib/mods/theme/edit/qrand10.map
new file mode 100644
index 00000000..ae45b9cb
--- /dev/null
+++ b/lib/mods/theme/edit/qrand10.map
@@ -0,0 +1,36 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:2056:0:0:0:0:*
+
+# Deep lava
+F:F:85:12
+
+# Dungeon layout
+D:
+D: xxxxxxx
+D: xFFFFFx
+D: xxxxxx,t.ttxxxx
+D: xFFG,t....t,,,xxx
+D: xFpG.......t.t.DD
+D: xFFG,t....t,,,xxx
+D: xxxxxx,t.ttxxxx
+D: xFFFFFx
+D: xxxxxxx
+D:
diff --git a/lib/mods/theme/edit/qrand11.map b/lib/mods/theme/edit/qrand11.map
new file mode 100644
index 00000000..4af3c266
--- /dev/null
+++ b/lib/mods/theme/edit/qrand11.map
@@ -0,0 +1,36 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep lava
+F:L:85:6
+
+# Shallow lava
+F:l:86:6
+
+# Dungeon layout
+D: ,llllllll ,
+D:, llLLLLLllll,
+D:llLLLGGGLLLlll,
+D:llLLLGpGLLLLlll
+D:lllLLGGGLLLllll
+D:lllllLLLLlllll,
+D:,lllllllllll,
+D: , ,llllll,
diff --git a/lib/mods/theme/edit/qrand12.map b/lib/mods/theme/edit/qrand12.map
new file mode 100644
index 00000000..4621ef0b
--- /dev/null
+++ b/lib/mods/theme/edit/qrand12.map
@@ -0,0 +1,36 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep water
+F:W:187:6
+
+# Shallow water
+F:w:84:6
+
+# Dungeon wayout
+D: ,wwwwwwww ,
+D:,,wwWWWWWwwww,
+D:wwWWWGGGWWWwww,
+D:wwWWWGpGWWWWwww
+D:wwwWWGGGWWWwwww
+D:wwwwwWWWWwwwww,
+D:,wwwwwwwwwww,
+D: , ,wwwwww,
diff --git a/lib/mods/theme/edit/qrand14.map b/lib/mods/theme/edit/qrand14.map
new file mode 100644
index 00000000..9f339db0
--- /dev/null
+++ b/lib/mods/theme/edit/qrand14.map
@@ -0,0 +1,37 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep water
+F:W:84:6
+
+# Shallow water
+F:w:187:6
+
+# Dungeon wayout
+D:
+D: xxxx xxxx
+D: x,,x x,,x
+D: xxDxxxxxxxDxx
+D: D,,,GpG,,,D
+D: xxDxxxxxxxDxx
+D: x,,x x,,x
+D: xxxx xxxx
+D:
diff --git a/lib/mods/theme/edit/qrand5.map b/lib/mods/theme/edit/qrand5.map
new file mode 100644
index 00000000..cc5d79ee
--- /dev/null
+++ b/lib/mods/theme/edit/qrand5.map
@@ -0,0 +1,27 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Dungeon layout
+D:
+D: xxxx.xxxx
+D: xx.......xx
+D: xxx..,...,..xxx
+D: xx.....GGG.....xx
+D: x......GpG......x
+D: xx..,..GGG..,..xx
+D: xxx....,....xxx
+D: xx.......xx
+D: xxxx.xxxx
+D:
diff --git a/lib/mods/theme/edit/qrand6.map b/lib/mods/theme/edit/qrand6.map
new file mode 100644
index 00000000..3b55e985
--- /dev/null
+++ b/lib/mods/theme/edit/qrand6.map
@@ -0,0 +1,37 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep water
+F:W:84:6
+
+# Shallow water
+F:w:187:6
+
+# Dungeon wayout
+D:
+D: xxxx xxxx
+D: xxxx xxxx
+D: xxxxxxxxxxDxx
+D: D,,,GpG,,,D
+D: xxxxxxxxxxDxx
+D: xxxx xxxx
+D: xxxx xxxx
+D:
diff --git a/lib/mods/theme/edit/qrand7.map b/lib/mods/theme/edit/qrand7.map
new file mode 100644
index 00000000..a7c0607f
--- /dev/null
+++ b/lib/mods/theme/edit/qrand7.map
@@ -0,0 +1,35 @@
+# Floor
+F:.:1:6
+
+# Marker
+F:,:172:6
+
+# Princess
+F:p:1:6:969
+
+# Lit permanent wall
+F:x:61:6
+
+# Lit glass wall
+F:G:188:6
+
+# Door
+F:D:38:6
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep water
+F:W:84:6
+
+# Shallow water
+F:w:187:6
+
+# Dungeon wayout
+D:ttttt
+D:tGGGt ,x,
+D:tGpGt x,x
+D:tGGGt ,x,
+D:ttttt
+D: ,x,
+D:
diff --git a/lib/mods/theme/edit/r_info.txt b/lib/mods/theme/edit/r_info.txt
new file mode 100644
index 00000000..bcc46bd5
--- /dev/null
+++ b/lib/mods/theme/edit/r_info.txt
@@ -0,0 +1,19013 @@
+# File: r_info.txt
+# With new monsters for Zangband 2.2 (or 2.3)
+# With new monsters for PernAngband 3.x.x
+# With lots of monsters for PernAngband 4.x.x
+# With Spirits for ToME 2.1.x
+# With many new monsters replacing old ones for Theme (ToME module)
+
+# This file is used to initialize the "lib/raw/r_info.raw" file, which is
+# used to initialize the "monster race" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/r_info.raw" file.
+
+# PernAngband notes:
+
+# Currently, "unique" monsters are just "special" monster races, with
+# the requirement that only one monster of that race can exist at a time,
+# and when it is killed, it can never again be generated.
+
+# ATTR_CLEAR monsters acquire their attr from the item/floor below them,
+# and use "white" for the recall window. See "cave.c" for info.
+
+# ATTR_MULTI monsters have a "flickering" attr, and use "violet" for the
+# recall window. See "cave.c" for info.
+
+# CHAR_CLEAR monsters use special symbols (.) as given below,
+# and use those symbols for the recall window. In theory, normally,
+# these monsters cannot be targetted, and when examined look like normal
+# floors, until the player "notices" them (perhaps check "awake").
+
+# CHAR_MULTI monsters use special symbols (!, ?, =) as given below,
+# and use those symbols for the recall window. In theory, normally,
+# these monsters cannot be targetted, and when examined look like normal
+# objects, until the player "notices" them (perhaps check "awake").
+
+# Note that there are (a few) normal monsters who are "violet" but not
+# ATTR_MULTI, and a lot of monsters which are "white" but not ATTR_CLEAR.
+
+# Note that currently both CHAR_CLEAR and CHAR_MULTI monsters are treated
+# as normal monsters that are just a little hard to see.
+
+# Note that the monster list underwent several changes for Angband 2.7.9,
+# including some monster name changes, some symbol redistributions, and
+# some color changes.
+
+# The Umber Hulk joined the Xorn/Xaren (X). The ticks (t) joined the
+# spiders (S). The townspeople (t) left the people (p). The "Jabberwock"
+# became the "Chaos beetle" (K). The major demons (&) became (U) and the
+# minor demons (I) became (u). Multiplying insects (fleas, fruit flies,
+# hummerhorns) became (I), visually "matching" the multiplying lice (l).
+# The "ant lions" (a) became "ants" (a). The mummified monsters (M)
+# joined the zombified monsters (z). The multi-headed hydras (M) left
+# the reptiles (R). The snakes (J) left the reptiles (R).
+
+# Some of the old "red" or "brown" monsters became "pink" if they lower
+# strength, while some of the old "fire" monsters became simply "red"
+# monsters. The "dragons" and "hounds" and related monsters underwent
+# a "color scheme regularization" ('w' = White/Cold, 's' = Black/Acid,
+# 'o' = Lite/Dark, 'r' = Red/Fire, 'g' = Green/Poison, 'b' = Blue/Elec,
+# 'u' = Brown/Earth/Force, 'D' = Dark/etc, 'W' = Stone/Inertia/Gravity/etc,
+# 'v' = Multihued/Chaos/Disenchantment/etc, 'y' = Gold/Sound, 'R' = Nexus,
+# 'G' = Nether, 'B' = Left-overs, and 'U' = Bronze/Confusion).
+
+# In several situations, two or more monsters with identical symbols and
+# colors were changed so that maximal information is conveyed by the symbol
+# and color.
+
+# The "people" (p), with more than 50 entries, got a new "color scheme"
+# ('w' = Paladin, 's' = Knight, 'o' = Mystic, 'r' = Mage, 'g' = High Priest,
+# 'b' = Thief, 'u' = Warrior, 'D' = Death knight, 'W' = Ranger/Archer,
+# 'v' = Sorcerer, 'y' = Ninja, 'R' = High Mage, 'G' = Priest, 'B' = High
+# Thief, 'U' = High Warrior). Note that most non-unique "people" already
+# had these colors, or colors close to these colors. A similar color scheme
+# was enforced for the "humanoid" (h) monsters as well, more or less.
+
+# TY: This is no longer entirely accurate. The monster coloring has been
+# changed 'back' to pre-2.7.* coloring in several cases. For example, I
+# prefer "black" thief characters. Also color can be (and should) be used to
+# convey information, but more importantly it is a visual presentation
+# of the creature and should be what the creature "looks" like.
+
+# Many of the "unique" monsters were changed to "match" the "base" monster
+# from which they were derived. Angband 2.8.0 may require every "unique"
+# monster to be based on a "normal" monster, and may enforce color matching.
+# This may result in the addition of some new monsters, to serve as "base"
+# monsters, possibly including Ogre captains, Greater Balrogs, Black Trolls,
+# Vampire Queens, Giant Werewolves, and others. This may be accompanied by
+# a separation of the monster list into a "normal" monster list (r_info)
+# with 512 entries, and a "unique" monster list (u_info) with 128 entries,
+# which will require reorganization of the list. Some new "player ghost"
+# unique monsters will probably be added at the same time.
+
+# Mushrooms look just like food (and use the "," symbol for both the recall
+# window and for normal display), Creeping coins look just like coins (and
+# use the "$" symbol for both the recall window and for normal display), and
+# Trappers/Lurkers can never be seen (and use the "." symbol for the recall
+# window). All other monsters use "alphabetic" symbols, and "alphabetic"
+# symbols are used only for monsters.
+
+# The "0" and "9" symbols are reserved for internal debugging use.
+
+# The "&" symbol is reserved for future use as a special "terrain feature".
+
+# The "`" symbol is reserved as an "alternate" open door picture, since
+# the "'" symbol looks like the "," symbol in some fonts (esp. IBM).
+
+# The "x" symbol is free for use as an "attr/char mapping" for annoying
+# monsters, such as magic mushrooms, drolems, etc.
+
+# Certain symbols ("X", "Y", "B", "l", "I", etc) are used by
+# very few monsters, and could be reorganized somewhat.
+
+# There are still too many "p" monsters, perhaps they should be broken up.
+
+# As always, you can enforce any "visual picture" you want with a "pref file".
+
+
+###### Understanding the entries ######
+
+# N: serial number : monster name
+# G: symbol : color
+# I: speed : hit points : vision : armor class : alertness
+# W: depth : rarity : corpse weight : experience for kill
+# E: weapons : torso : arms : finger : head : leg
+# O: treasure : combat : magic : tool
+# B: attack method : attack effect : damage
+# F: flag | flag | etc
+# S: spell frequency |
+# S: spell type | spell type | etc
+# D: Description
+
+# 'N' indicates the beginning of an entry. The serial number must
+# increase for each new item. Entry 0 is used for the player.
+
+# 'G' is for graphics - symbol and color. There are 16 colors, as
+# follows:
+
+# D - Dark Gray w - White s - Gray o - Orange
+# r - Red g - Green b - Blue u - Brown
+# d - Black W - Light Gray v - Violet y - Yellow
+# R - Light Red G - Light Green B - Light Blue U - Light Brown
+
+# 'I' is for information - speed, health, vision in tens of feet,
+# armor class, and alertness. 110 is normal speed. Alertness ranges
+# from 0 (ever vigilant for intruders) to 255 (prefers to ignore
+# intruders).
+
+# 'W' is for more information - level, rarity, corpse weight (expressed
+# in deci-pounds) [19 deci-pounds seem to get added to these number
+# in practice], and experience for killing.
+
+# 'E' is for equipment slots - weapon slots, torso slots (the "on body"
+# and "about body" equipment slots), arm slots (expressed in number
+# of pairs), finger slots, head slots, and leg slots (expressed
+# in number of pairs).
+
+# 'O' is for object drop chances - % chance to drop treasure, % chance
+# to drop combat items, % chance to drop magic type items (not
+# items of good blessing), and % chance to drop tools. The four
+# percents added together must be equal to or less than 100. If
+# the percent is less than 100, that is the chance for the monster
+# to drop junk.
+
+# 'B' is for blows - method of attack, effect of attack, and damage
+# from attack. There may be up to four of these lines; effect and
+# damage are optional.
+
+# 'S' is for spells. The first S: line must be S:1_IN_X with X the
+# number of monster turns, on average, before the monster will cast
+# one of its spells. X must not be zero.
+
+# 'F' is for flags. These are fairly self-explanatory. As many F:
+# lines may be used as are needed to specify all the flags and flags
+# are separated by the '|' symbol. The '|' symbol must also be used
+# to end all but the last line.
+
+# 'D' is for description. As many D: lines may be used as are needed
+# to describe the monster. Note that lines may need spaces at their
+# ends to prevent words from running together in the monster memory.
+
+
+# Note that monster zero is used for the "player" picture.
+
+# Version stamp (required)
+
+V:2.2.0
+
+##### The Player #####
+
+N:0:Player
+G:@:w
+E:1:1:1:2:1:1
+O:0:0:0:0
+
+##### Town monsters #####
+
+N:1:Filthy street urchin
+G:t:D
+I:110:1d4:4:1:40
+W:0:2:1200:0
+E:1:1:1:2:1:1
+O:1:1:1:1
+B:BEG:*
+B:TOUCH:EAT_GOLD
+F:MALE | EVIL | WILD_TOWN | WILD_ONLY |
+F:RAND_25 | FRIENDS |
+F:TAKE_ITEM | OPEN_DOOR | DROP_CORPSE | DROP_SKELETON |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He looks squalid and thoroughly revolting.
+
+N:2:Scrawny cat
+G:f:W
+I:110:1d2:30:1:255
+W:0:3:100:0
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d1
+F:RAND_25 | WILD_GRASS | WILD_TOWN | WILD_ONLY |
+F:ANIMAL | DROP_CORPSE | DROP_SKELETON |
+F:MORTAL | BASEANGBAND | NEUTRAL | NO_TARGET
+D:A skinny little furball with sharp claws.
+
+N:3:Sparrow
+G:B:W
+I:110:1d1:30:1:255
+W:0:3:90:0
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_25 | CAN_FLY | WILD_TOWN | WILD_ONLY |
+F:ANIMAL | DROP_SKELETON | HAS_EGG | IMPRESED |
+F:MORTAL | BASEANGBAND | NEUTRAL | NO_TARGET | AQUATIC
+D:Utterly harmless, except when angry.
+
+N:4:Chaffinch
+G:B:R
+I:110:1d1:30:1:255
+W:0:3:80:0
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_25 | CAN_FLY | WILD_ONLY | WILD_WOOD | WILD_GRASS |
+F:ANIMAL | DROP_SKELETON | HAS_EGG | IMPRESED | AQUATIC
+F:MORTAL | BASEANGBAND | NEUTRAL | NO_TARGET
+D:Utterly harmless, except when angry.
+
+N:5:Wild rabbit
+G:r:U
+I:110:1d2:30:1:255
+W:0:3:100:0
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_50 | WILD_ONLY | WILD_GRASS | WILD_WOOD |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | NEUTRAL | NO_TARGET
+D:It is not a carnivore, but will defend itself if you stray too
+D:close.
+
+N:6:Woodsman
+G:t:g
+I:110:3d3:10:1:255
+W:0:1:1000:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d6
+F:MALE | WILD_ONLY | WILD_WOOD |
+F:RAND_25 | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | HAS_LITE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | NEUTRAL | NO_TARGET |
+D:He has a strong axe with a sharp edge.
+
+N:7:Scruffy little dog
+G:C:s
+I:110:1d3:20:1:255
+W:0:3:300:0
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_25 | DROP_SKELETON | DROP_CORPSE | WILD_TOWN | WILD_ONLY |
+F:ANIMAL | MORTAL | BASEANGBAND | NEUTRAL | NO_TARGET
+D:A thin flea-ridden mutt, growling as you get close.
+
+N:8:Farmer Maggot
+G:h:w
+I:110:35d10:40:10:3
+W:0:4:730:0
+E:0:1:1:2:1:1
+O:0:100:0:0
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:FORCE_MAXHP | WILD_TOWN | WILD_ONLY | NO_TARGET
+F:NEVER_MOVE
+F:OPEN_DOOR | BASH_DOOR | SPECIAL_GENE
+F:NEUTRAL | NO_TARGET | NO_DEATH
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A broad and thick-set hobbit with a round red face. "There's earth under
+D:his old feet, and clay on his fingers; wisdom in his bones, and both his
+D:eyes are open." He seems sad about something.
+
+N:9:Blubbering idiot
+G:t:W
+I:110:1d2:6:1:255
+W:0:1:1500:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:DROOL:*
+F:MALE | DROP_CORPSE | DROP_SKELETON | WILD_TOWN | WILD_ONLY |
+F:RAND_25 | DROP_1D2 | TAKE_ITEM | NEUTRAL | NO_TARGET |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He tends to blubber a lot.
+
+N:10:Boil-covered wretch
+G:t:R
+I:110:1d2:6:1:255
+W:0:1:1400:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:DROOL:*
+F:MALE | DROP_SKELETON | DROP_CORPSE | WILD_TOWN | WILD_ONLY |
+F:RAND_25 | DROP_1D2 | NEUTRAL | NO_TARGET
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:Ugly doesn't begin to describe him.
+
+N:11:Village idiot
+G:t:G
+I:120:4d4:6:1:255
+W:0:1:1400:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:DROOL:*
+F:MALE | DROP_CORPSE | DROP_SKELETON | WILD_TOWN | WILD_ONLY |
+F:RAND_25 | DROP_1D2 | TAKE_ITEM | NEUTRAL | NO_TARGET
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:Drooling and comical, he runs around town with a stupid grin.
+
+N:12:Pitiful-looking beggar
+G:t:U
+I:110:1d4:10:1:255
+W:0:1:1300:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BEG:*
+F:MALE | DROP_SKELETON | DROP_CORPSE |
+F:RAND_25 | WILD_TOWN | WILD_ONLY | DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | NEUTRAL | NO_TARGET
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:You just can't help feeling sorry for him.
+
+N:13:Mangy-looking leper
+G:t:u
+I:110:1d1:10:1:255
+W:0:1:1300:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BEG:*
+B:TOUCH:DISEASE
+F:MALE | DROP_CORPSE | DROP_SKELETON |
+F:RAND_25 | WILD_TOWN | WILD_ONLY | DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | NEUTRAL | NO_TARGET
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:You feel it isn't safe to touch him.
+
+N:14:Agent of the black market
+G:t:b
+I:110:2d8:10:8:99
+W:0:1:1200:0
+E:1:1:1:2:1:1
+O:25:50:20:5
+B:HIT:HURT:1d6
+B:TOUCH:EAT_ITEM
+B:INSULT:*
+F:MALE | DROP_CORPSE | DROP_SKELETON |
+F:DROP_60 | WILD_TOWN |
+F:WILD_WOOD | WILD_GRASS | WILD_MOUNTAIN | WILD_ONLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:He 'finds' new wares for the Black Market. From unwary adventurers.
+
+N:15:Singing, happy drunk
+G:t:y
+I:110:2d3:10:1:0
+W:0:1:1100:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BEG:*
+F:MALE |
+F:RAND_50 | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | WILD_TOWN | WILD_ONLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE | NEUTRAL | NO_TARGET
+D:He makes you glad to be sober.
+
+N:16:Aimless-looking merchant
+G:t:o
+I:110:3d3:10:1:255
+W:0:1:1500:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d3
+F:MALE | RAND_50 |
+F:ONLY_GOLD | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_TOWN | WILD_ONLY |
+F:MORTAL | BASEANGBAND | HAS_LITE | NEUTRAL | NO_TARGET
+D:The typical ponce around town, with purse jingling, and looking for more
+D:amulets of adornment to buy.
+
+N:17:Mean-looking mercenary
+G:t:r
+I:110:5d8:10:20:250
+W:0:1:1700:0
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d10
+F:MALE | DROP_SKELETON | DROP_CORPSE |
+F:RAND_50 | DROP_90 | WILD_GRASS | WILD_TOWN | WILD_WOOD | WILD_ONLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:No job is too low for him.
+
+N:18:Battle-scarred veteran
+G:t:B
+I:110:7d8:10:30:250
+W:0:1:1650:0
+E:1:1:1:2:1:1
+O:25:50:25:0
+B:HIT:HURT:2d6
+F:MALE | DROP_SKELETON | DROP_CORPSE |
+F:RAND_50 | DROP_90 | WILD_TOWN | WILD_ONLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He doesn't take to strangers kindly.
+
+N:19:The Squint-eyed Southerner
+G:t:s
+I:120:8d20:20:15:400
+W:10:4:1700:50
+E:1:1:1:2:1:1
+O:0:50:0:50
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:PUNCH:HURT:3d8
+B:PUNCH:HURT:3d8
+F:UNIQUE | MALE | CAN_SPEAK | BASEANGBAND | HAS_LITE |
+F:FORCE_MAXHP | DROP_CORPSE | WILD_TOWN | WILD_ONLY | DROP_1D2 |
+F:ONLY_ITEM | DROP_GOOD | DROP_GREAT | DROP_RANDART | MORTAL
+D:He doesn't look like he's from around here, and a gut
+D:feeling tells you he's a spy.
+
+##### Normal monsters #####
+
+N:20:Grey mold
+G:m:s
+I:110:1d2:2:1:0
+W:1:1:20:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:HURT:1d4
+B:SPORE:HURT:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+D:A small strange growth.
+
+N:21:Large white snake
+G:J:w
+I:100:3d6:4:30:99
+W:1:1:600:2
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+B:CRUSH:HURT:1d1
+F:RAND_50 | WILD_TOO |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | HAS_EGG | MORTAL | BASEANGBAND
+D:It is about eight feet long.
+
+N:22:Grey mushroom patch
+G:,:s
+I:110:1d2:2:1:0
+W:1:1:10:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:CONFUSE:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+N:23:Newt
+G:R:y
+I:110:2d6:8:12:30
+W:1:1:10:2
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:BITE:HURT:1d3
+F:WEIRD_MIND | CAN_SWIM | WILD_TOO | DROP_CORPSE |
+F:WILD_GRASS | WILD_WASTE | WILD_SHORE | WILD_MOUNTAIN |
+F:ANIMAL | HAS_EGG | MORTAL | BASEANGBAND |
+D:A small, harmless lizard.
+
+# New monster added by furiosity for the Theme module
+N:24:Ox
+G:c:D
+I:50:10d10:0:50:255
+W:0:1:4000:0
+E:0:1:0:2:1:2
+O:0:0:0:0
+B:KICK:HURT:10d10
+B:KICK:HURT:10d10
+B:BUTT:HURT:10d10
+B:BUTT:HURT:10d10
+F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_ONLY | WILD_GRASS
+F:FRIEND | FRIENDS | FORCE_SLEEP | STUPID | WEIRD_MIND |
+F:SUSCEP_POIS | KILL_BODY | NEUTRAL | NO_TARGET | KILL_ITEM |
+D:A strong and powerful animal with sharp-looking horns. Large cattle
+D:used to carry and draw burdens, and for milk and meat. It is domestic and
+D:utterly harmless, except when angry.
+
+# New monster added by furiosity for the Theme module
+N:25:Kine of Araw
+G:c:r
+I:80:20d20:0:50:255
+W:0:1:5000:0
+E:0:1:0:2:1:2
+O:0:0:0:0
+B:KICK:HURT:20d20
+B:KICK:HURT:20d20
+B:KICK:HURT:20d20
+B:KICK:HURT:20d20
+F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_ONLY | WILD_GRASS |
+F:FRIEND | FRIENDS | FORCE_SLEEP | WEIRD_MIND | SUSCEP_POIS | GOOD |
+F:KILL_BODY | NEUTRAL | NO_TARGET | KILL_ITEM |
+D:The oxen that live on the lands around the Sea of Rhun are hardier
+D:and wilder than any others in Middle-earth. Legends claim that they
+D:are descended from the cattle of the Huntsman of the Valar, Orome
+D:himself, and so they are named the Kine of Araw (Araw being the Sindarin
+D:form of Orome's name). It is a huge four-legged beast that won't attack
+D:unless provoked.
+
+# New monster added by furiosity for the Theme module
+N:26:Sheep
+G:c:w
+I:70:5d5:0:30:255
+W:0:1:2000:0
+E:0:1:0:2:1:2
+O:0:0:0:0
+B:KICK:HURT:5d5
+B:KICK:HURT:5d5
+B:KICK:HURT:5d5
+B:KICK:HURT:5d5
+F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_ONLY | WILD_GRASS |
+F:FRIEND | FRIENDS | FORCE_SLEEP | WEIRD_MIND | SUSCEP_POIS | NEUTRAL | NO_TARGET |
+D:Woolly grazing animals, especially common on the Barrow-downs
+D:and in the Vales of Anduin. Utterly harmless unless angered.
+
+N:27:Giant white mouse
+G:r:w
+I:110:1d3:8:4:20
+W:1:1:600:1
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | WILD_TOO | WILD_GRASS |
+F:CAN_SWIM |
+F:ANIMAL | DROP_CORPSE |
+F:MORTAL | BASEANGBAND |
+S:MULTIPLY
+D:It is about three feet long, with large teeth.
+
+N:28:Large brown snake
+G:J:u
+I:100:4d6:4:35:99
+W:1:1:800:3
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:CRUSH:HURT:1d4
+F:RAND_25 | CAN_SWIM |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | HAS_EGG | MORTAL | BASEANGBAND
+D:It is about eight feet long.
+
+# New monster added by furiosity for the Theme module
+N:29:Meara
+G:c:W
+I:130:10d12:0:70:255
+W:0:1:3500:0
+E:0:1:0:2:1:2
+O:0:0:0:0
+B:KICK:HURT:10d12
+B:KICK:HURT:10d12
+B:KICK:HURT:10d12
+B:KICK:HURT:10d12
+F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_ONLY |
+F:WILD_GRASS | FORCE_SLEEP | WEIRD_MIND | NEUTRAL | NO_TARGET | GOOD |
+D:The great Mearas are legendary horses bred by the Rohirrim.
+D:Swift and sure they are, but only members of the royal
+D:family of Rohan are allowed to ride them. This animal will
+D:not attack unless angered.
+
+# New monster added by furiosity for the Theme module
+N:30:Horse
+G:c:s
+I:120:8d10:0:50:255
+W:0:1:3000:0
+E:0:1:0:2:1:2
+O:0:0:0:0
+B:KICK:HURT:8d10
+B:KICK:HURT:8d10
+B:KICK:HURT:8d10
+B:KICK:HURT:8d10
+F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_ONLY | WILD_GRASS |
+F:FORCE_SLEEP | WEIRD_MIND | SUSCEP_POIS | WILD_TOWN | NEUTRAL | NO_TARGET |
+D:Beasts of burden and transport used by Elves and Men through the ages.
+D:A noble animal, it can be quite a sight as it prances gracefully
+D:through the fields. It won't attack you unless provoked.
+
+N:31:White worm mass
+G:w:w
+I:100:4d4:7:1:10
+W:1:1:30:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:POISON:1d2
+F:RAND_50 | RAND_25 | CAN_SWIM |
+F:STUPID | WEIRD_MIND |
+F:ANIMAL | IM_POIS | HURT_LITE | NO_FEAR
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:32:Floating eye
+G:e:o
+I:110:3d6:2:6:10
+W:1:1:500:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:PARALYZE
+F:NEVER_MOVE | CAN_FLY | DROP_CORPSE |
+F:HURT_LITE | NO_FEAR | BASEANGBAND
+D:A disembodied eye, floating a few feet above the ground.
+
+N:33:Rock lizard
+G:R:U
+I:110:3d4:20:4:15
+W:1:1:100:2
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:ANIMAL | CAN_SWIM | WILD_TOO | WILD_MOUNTAIN |
+F:DROP_CORPSE | HAS_EGG |
+F:MORTAL | BASEANGBAND
+D:It is a small lizard with a hardened hide.
+
+# New monster added by furiosity for the Theme module
+N:34:The Boar of Everholt
+G:c:R
+I:110:15d10:0:3:20
+W:5:1:1600:60
+E:0:1:0:2:1:2
+O:0:0:0:0
+B:BUTT:HURT:3d6
+B:BUTT:HURT:3d6
+B:BUTT:HURT:3d6
+F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_TOO |
+F:WILD_GRASS | FORCE_SLEEP | WEIRD_MIND | WILD_WOOD | UNIQUE |
+D:A monstrous beast that inhabited Everholt in the Firien Wood,
+D:around the feet of the Halifirien in the White Mountains. It
+D:is twice the size of a regular boar, and twice as aggressive.
+D:King Folca of Rohan met his end at the tusks of this creature.
+
+N:35:Jackal
+G:C:y
+I:110:1d4:10:3:10
+W:1:1:400:1
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:FRIENDS |
+F:WILD_TOO | WILD_WOOD | WILD_GRASS | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is a yapping snarling wild dog, dangerous when in a pack.
+
+N:36:Soldier ant
+G:a:u
+I:110:2d5:10:3:10
+W:1:1:300:3
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:WEIRD_MIND | BASH_DOOR | DROP_SKELETON |
+F:ANIMAL | WILD_TOO | WILD_GRASS |
+F:MORTAL | BASEANGBAND
+D:A large ant with powerful mandibles.
+
+N:37:Fruit bat
+G:b:o
+I:120:1d6:20:3:10
+W:1:1:20:1
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:ANIMAL | CAN_FLY | WILD_TOO | WILD_WOOD | DROP_CORPSE
+F:MORTAL | BASEANGBAND | AI_ANNOY
+D:A fast-moving pest.
+
+N:38:Insect swarm
+G:I:u
+I:120:1d5:20:4:10
+W:1:1:100:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+B:STING:HURT:1d1
+F:ANIMAL | WEIRD_MIND | CAN_FLY | RAND_25 | WILD_TOO | WILD_GRASS |
+F:WILD_WOOD |
+F:MORTAL | SUSCEP_FIRE | BASEANGBAND | NO_CUT
+D:A lone insect may be harmless, but there's a whole swarm of
+D:them here!
+
+# New monster added by furiosity for the Theme module
+N:39:Boar
+G:c:o
+I:110:3d6:0:3:20
+W:3:1:800:5
+E:0:1:0:2:1:2
+O:0:0:0:0
+B:BUTT:HURT:3d3
+B:BUTT:HURT:3d3
+F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_TOO |
+F:WILD_GRASS | FORCE_SLEEP | WEIRD_MIND | WILD_WOOD |
+D:Aggressive tusked beasts common to woodland regions.
+
+N:40:Shrieker mushroom patch
+G:,:R
+I:110:1d1:4:1:0
+W:2:1:40:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | NEVER_MOVE | NEVER_BLOW |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | WILD_TOO | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:SHRIEK
+D:Yum! It looks quite tasty. It doesn't sound so nice, though.
+
+# New monster added by furiosity for the Theme module
+N:41:Cow
+G:c:u
+I:70:7d7:0:50:255
+W:0:1:3500:0
+E:0:1:0:2:1:2
+O:0:0:0:0
+B:KICK:HURT:7d7
+B:BUTT:HURT:7d7
+B:KICK:HURT:7d7
+B:BUTT:HURT:7d7
+F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_ONLY | WILD_GRASS |
+F:FRIEND | FRIENDS | FORCE_SLEEP | WEIRD_MIND | SUSCEP_POIS | NEUTRAL | NO_TARGET |
+D:Domestic horned beasts kept throughout Middle-earth.
+D:Utterly harmless, unless angered.
+
+# New monster added by furiosity for the Theme module
+#N:42:Pony
+#G:c:y
+#I:120:4d5:0:200
+#W:0:1:1000:0
+#E:0:1:0:2:1:2
+#O:0:0:0:0
+#B:KICK:HURT:4d5
+#B:KICK:HURT:4d5
+#B:KICK:HURT:4d5
+#B:KICK:HURT:4d5
+#F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_ONLY | WILD_GRASS |
+#F:FORCE_SLEEP | WEIRD_MIND | SUSCEP_POIS | NEUTRAL | NO_TARGET | WILD_TOWN |
+#D:It's a short, stocky pack animal, related to the horse, but smaller.
+#D:A common beast of burden in Middle-earth, especially used by Hobbits
+#D:and Dwarves. It won't attack you unless provoked.
+
+N:43:Novice warrior
+G:p:u
+I:110:9d4:20:16:5
+W:2:1:1600:6
+E:1:1:1:2:1:1
+O:25:50:0:20
+B:HIT:HURT:1d7
+B:HIT:HURT:1d6
+F:MALE |
+F:DROP_60 | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He looks inexperienced but tough.
+
+N:44:Novice rogue
+G:p:b
+I:110:8d4:20:12:5
+W:2:1:1400:6
+E:1:1:1:2:1:1
+O:50:25:0:20
+B:HIT:HURT:1d6
+B:TOUCH:EAT_GOLD
+F:MALE |
+F:DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_TOO |
+F:EVIL | MORTAL | BASEANGBAND
+D:A rather shifty individual.
+
+N:45:Novice priest
+G:p:g
+I:110:7d4:20:10:10
+W:2:1:1500:6
+E:1:1:1:2:1:1
+O:25:0:50:20
+B:HIT:HURT:1d5
+F:MALE |
+F:FORCE_SLEEP | GOOD | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:HEAL | SCARE | CAUSE_1
+D:He is tripping over his priestly robes.
+
+N:46:Novice mage
+G:p:r
+I:110:6d4:20:6:5
+W:2:1:1400:6
+E:1:1:1:2:1:1
+O:25:0:70:0
+B:HIT:HURT:1d4
+F:MALE |
+F:FORCE_SLEEP | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:BLINK | BLIND | CONF | MISSILE
+D:He is leaving behind a trail of dropped spell components.
+
+N:47:Yellow mushroom patch
+G:,:y
+I:110:1d1:2:1:0
+W:2:1:30:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:TERRIFY:1d6
+F:NEVER_MOVE | WILD_TOO |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+N:48:White jelly
+G:j:w
+I:120:8d8:2:1:99
+W:2:1:2000:10
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:POISON:1d2
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It's a large pile of white flesh.
+
+N:49:Giant black ant
+G:a:D
+I:110:3d6:8:20:80
+W:2:1:500:8
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+F:RAND_25 |
+F:WEIRD_MIND | DROP_SKELETON |
+F:BASH_DOOR | WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is about three feet long.
+
+N:50:Salamander
+G:R:o
+I:110:4d6:8:20:80
+W:2:1:100:10
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:1d3
+F:RAND_25 | CAN_SWIM | WILD_TOO | WILD_VOLCANO | DROP_CORPSE |
+F:ANIMAL | IM_FIRE | SUSCEP_COLD |
+F:MORTAL | BASEANGBAND
+D:A small black and orange lizard.
+
+N:51:White harpy
+G:H:w
+I:110:2d5:16:17:10
+W:2:1:500:5
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d1
+B:CLAW:HURT:1d1
+B:BITE:HURT:1d2
+F:FEMALE | CAN_FLY | WILD_TOO | WILD_MOUNTAIN |
+F:RAND_50 | DROP_CORPSE | ANIMAL | EVIL | MORTAL | BASEANGBAND
+D:A flying, screeching bird with a woman's face.
+
+# New monster added by furiosity for the Theme module
+N:52:Deer
+G:c:U
+I:110:8d8:0:30:255
+W:0:1:3000:0
+E:0:1:0:0:1:2
+O:0:0:0:0
+B:KICK:HURT:8d8
+B:BUTT:HURT:8d8
+B:KICK:HURT:8d8
+B:BUTT:HURT:8d8
+F:BASEANGBAND | ANIMAL | MORTAL | DROP_CORPSE | WILD_ONLY | WILD_GRASS |
+F:FORCE_SLEEP | WEIRD_MIND | SUSCEP_POIS | NEUTRAL | NO_TARGET | WILD_WOOD |
+D:Graceful creature found throughout Middle-earth. Deer are
+D:traditionally dedicated to the Vala Nessa, and are said to
+D:follow her as she travels through the wild lands. They will
+D:never attack without provocation.
+
+N:53:Grip, Farmer Maggot's dog
+G:C:w
+I:120:7d5:30:30:0
+W:2:2:600:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:UNIQUE | SPECIAL_GENE
+F:FORCE_MAXHP | RAND_25 | DROP_CORPSE
+F:BASH_DOOR | ANIMAL
+F:MORTAL | BASEANGBAND
+D:A rather vicious dog belonging to Farmer Maggot. It thinks you are
+D:stealing mushrooms.
+
+N:54:Wolf, Farmer Maggot's dog
+G:C:w
+I:120:7d5:30:30:0
+W:2:2:650:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:UNIQUE | SPECIAL_GENE
+F:FORCE_MAXHP | RAND_25 | DROP_CORPSE
+F:BASH_DOOR
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A rather vicious dog belonging to Farmer Maggot. It thinks you are
+D:stealing mushrooms.
+
+N:55:Fang, Farmer Maggot's dog
+G:C:w
+I:120:7d5:30:30:0
+W:2:2:700:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:UNIQUE | SPECIAL_GENE
+F:FORCE_MAXHP | RAND_25 | DROP_CORPSE
+F:BASH_DOOR
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A rather vicious dog belonging to Farmer Maggot. It thinks you are
+D:stealing mushrooms.
+
+N:56:Giant green frog
+G:R:g
+I:110:2d8:12:8:30
+W:2:1:200:6
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+F:RAND_25 | WILD_ONLY | WILD_SHORE | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is as big as a wolf.
+
+# New monster added by furiosity for the Theme module
+N:57:Lion
+G:f:R
+I:120:14d20:50:60:0
+W:24:2:3000:80
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:TERRIFY:2d8
+B:CLAW:HURT:2d16
+B:CLAW:HURT:2d16
+F:BASH_DOOR | WILD_TOO | WILD_GRASS | WILD_WOOD | WILD_MOUNTAIN |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE | MORTAL | BASEANGBAND
+D:Master of all felines, it's a huge cat with enormous paws
+D:and a thick mane. Its roar is deafeningly terrifying.
+
+N:58:Green worm mass
+G:w:g
+I:100:6d4:7:3:10
+W:2:1:40:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:ACID:1d3
+F:RAND_50 | RAND_25 |
+F:STUPID | WEIRD_MIND |
+F:ANIMAL | IM_ACID | CAN_SWIM |
+F:HURT_LITE | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:59:Large yellow snake
+G:J:y
+I:100:4d8:5:38:75
+W:2:1:1000:9
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:CRUSH:HURT:1d6
+F:RAND_25 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE
+F:BASH_DOOR | HAS_EGG | ANIMAL | MORTAL | BASEANGBAND
+D:It is about ten feet long.
+
+N:60:Cave spider
+G:S:D
+I:120:2d6:8:16:80
+W:2:1:400:7
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+F:FRIENDS |
+F:WEIRD_MIND | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | SPIDER | HURT_LITE |
+F:MORTAL | BASEANGBAND
+D:It is a black spider that moves in fits and starts.
+
+N:61:Crow
+G:B:s
+I:120:3d5:40:12:0
+W:2:2:300:8
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:BITE:HURT:1d3
+F:ANIMAL | WILD_TOO | WILD_WOOD | CAN_FLY | DROP_CORPSE
+F:MORTAL | HAS_EGG | BASEANGBAND | AQUATIC
+D:It is a hooded crow, gray except for the black wings and head.
+
+N:62:Wild cat
+G:f:U
+I:120:3d5:40:12:0
+W:2:2:200:8
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+F:BASH_DOOR | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A larger than normal feline, hissing loudly. Its velvet claws conceal a
+D:fistful of needles.
+
+N:63:Smeagol
+G:h:B
+I:130:20d20:20:12:5
+W:7:2:670:16
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:TOUCH:EAT_GOLD
+B:BITE:HURT:2d4
+F:UNIQUE | MALE | CAN_SWIM | DROP_SKELETON | DROP_CORPSE | DROP_CHOSEN |
+F:FORCE_MAXHP | CAN_SPEAK | SMART |
+F:RAND_50 | RAND_25 | WILD_TOO |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD | DROP_GREAT |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | INVISIBLE
+F:EVIL | BASEANGBAND
+S:1_IN_25 |
+S:S_SPIDER
+D:Also known as Gollum. He is of the Periannath, but does not look it.
+D:He is thin and frail, sneaking around in dark corners, hoping to
+D:reclaim his "precious," and he'll use any means necessary to do so.
+
+N:64:Green ooze
+G:j:g
+I:120:3d4:8:16:80
+W:3:2:300:4
+E:0:0:0:0:0:0
+O:50:0:25:20
+B:CRAWL:ACID:1d3
+F:RAND_50 | RAND_25 | DROP_90 |
+F:STUPID | EMPTY_MIND |
+F:IM_ACID | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It's green and it's oozing.
+
+N:65:Poltergeist
+G:G:s
+I:130:2d5:8:15:10
+W:3:1:0:8
+E:0:0:0:0:0:0
+O:50:5:30:10
+B:TOUCH:TERRIFY
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:DROP_60 | DROP_90 |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | TAKE_ITEM |
+F:EVIL | UNDEAD |
+F:IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLINK
+D:It is a ghastly, ghostly form.
+
+N:66:Yellow jelly
+G:j:y
+I:120:10d8:2:1:99
+W:3:1:2000:12
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:POISON:1d3
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:DRAIN_MANA
+D:It's a large pile of yellow flesh.
+
+# New monster added by furiosity for the Theme module
+N:67:Squirrel
+G:r:o
+I:110:1d2:30:1:10
+W:0:3:100:0
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:WILD_ONLY | WILD_GRASS | WILD_WOOD |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE | NEUTRAL | NO_TARGET |
+F:MORTAL | BASEANGBAND
+D:A funny chittering creature, looking for nuts.
+
+N:68:Raven
+G:B:W
+I:120:4d5:40:12:0
+W:4:2:500:8
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:BITE:HURT:1d4
+F:ANIMAL | WILD_ONLY | WILD_WOOD | CAN_FLY | DROP_CORPSE
+F:MORTAL | HAS_EGG | NEUTRAL | NO_TARGET | IMPRESED | BASEANGBAND | AQUATIC
+D:Larger than a crow, and pitch black.
+
+N:69:White midge
+G:I:w
+I:120:1d1:6:5:10
+W:3:1:100:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:WEIRD_MIND | ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is an evil relative of the moth, native to marshlands.
+
+# New monster added by furiosity for the Theme module
+# Based on the Vorpal bunny from Zangband
+N:70:Squirrel of Mirkwood
+G:r:g
+I:120:10d10:40:40:0
+W:13:1:600:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:6d1
+B:BITE:HURT:7d1
+F:WILD_TOO | WILD_WOOD | DROP_CORPSE | CAN_FLY |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:An ominous-looking squirrel with dark fur, covered in
+D:leaves for better masquerade. It has glowing eyes and
+D:unusually sharp teeth. It is a horrific creation of the
+D:Necromancer in Dol Guldur, a corrupted form of a normal
+D:squirrel.
+
+N:71:Black naga
+G:n:D
+I:110:6d8:16:40:120
+W:3:1:1700:20
+E:0:0:0:0:1:0
+O:0:75:20:5
+B:CRUSH:HURT:1d8
+F:FEMALE |
+F:RAND_25 | DROP_60 | DROP_CORPSE |
+F:BASH_DOOR | CAN_SWIM |
+F:EVIL | MORTAL | BASEANGBAND
+D:A large black serpent's body with a female torso.
+
+N:72:Spotted mushroom patch
+G:,:o
+I:110:1d1:2:1:0
+W:3:1:30:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:2d4
+F:NEVER_MOVE | WILD_TOO |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+N:73:Silver jelly
+G:j:W
+I:120:10d8:2:1:99
+W:3:2:2000:12
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EAT_LITE:1d3
+B:TOUCH:EAT_LITE:1d3
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:DRAIN_MANA
+D:It is a large pile of silver flesh that sucks all light from its
+D:surroundings.
+
+N:74:Scruffy-looking hobbit
+G:h:s
+I:110:3d5:16:8:10
+W:3:1:1000:4
+E:1:1:1:2:1:1
+O:0:50:0:40
+B:HIT:HURT:1d4
+B:TOUCH:EAT_GOLD
+F:MALE |
+F:DROP_60 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A short little guy, in bedraggled clothes. He appears to be looking
+D:for a good tavern.
+
+N:75:Giant white ant
+G:a:w
+I:110:3d6:8:16:80
+W:3:1:800:7
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_GRASS |
+F:ANIMAL | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:It is about two feet long and has sharp pincers.
+
+N:76:Yellow mold
+G:m:y
+I:110:8d8:2:10:99
+W:3:1:30:9
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:HURT:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange growth on the dungeon floor.
+
+# New monster added by furiosity for the Theme module
+N:77:Ape
+G:q:y
+I:115:5d10:8:10:2
+W:8:10:800:10
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BITE:HURT:2d2
+B:BITE:DISEASE:1d1
+B:BITE:EAT_FOOD:1d1
+F:BASEANGBAND | ANIMAL | MORTAL | AI_ANNOY |
+F:RAND_50 | RAND_25 | SMART | WEIRD_MIND |
+S:1_IN_10
+S:SHRIEK
+D:A large humanoid form, relatively rare on Middle-earth.
+D:It is bounding toward you, noisy and dirty.
+
+N:78:Yellow worm mass
+G:w:y
+I:100:4d8:7:4:10
+W:3:2:200:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:LOSE_DEX:1d3
+F:RAND_50 | RAND_25 | CAN_SWIM |
+F:STUPID | WEIRD_MIND |
+F:ANIMAL | HURT_LITE | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:79:Clear worm mass
+G:w:B
+I:100:4d4:7:1:10
+W:3:2:200:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:POISON:1d2
+F:ATTR_CLEAR | CAN_SWIM |
+F:RAND_50 | RAND_25 |
+F:STUPID | WEIRD_MIND | INVISIBLE |
+F:ANIMAL |
+F:IM_POIS | HURT_LITE | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a disgusting mass of poisonous worms.
+
+N:80:Radiation eye
+G:e:R
+I:110:3d6:2:6:10
+W:3:1:500:6
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:LOSE_STR:1d6
+F:NEVER_MOVE | CAN_FLY | DROP_CORPSE |
+F:HURT_LITE | NO_FEAR | BASEANGBAND | HAS_LITE
+S:1_IN_11 |
+S:DRAIN_MANA
+D:A disembodied eye, crackling with energy.
+
+N:81:Yellow light
+G:*:y
+I:120:2d6:8:12:30
+W:4:1:0:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:BLIND
+F:EMPTY_MIND | CAN_FLY | NONLIVING | SUSCEP_ELEC |
+F:BASEANGBAND | HAS_LITE | RAND_50 | RAND_25 | NO_CUT
+D:A fast-moving bright light, apparently totally random in its movement.
+
+N:82:Cave lizard
+G:R:u
+I:110:3d6:8:16:80
+W:4:1:100:8
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d5
+F:ANIMAL | CAN_SWIM | DROP_CORPSE | HAS_EGG | WILD_ONLY
+F:MORTAL | NEUTRAL | NO_TARGET | IMPRESED | BASEANGBAND
+D:It is an armoured lizard with a powerful bite.
+
+N:83:Novice ranger
+G:p:W
+I:110:6d8:20:8:5
+W:4:1:1400:18
+E:1:1:1:2:1:1
+O:25:45:25:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+F:MALE |
+F:FORCE_SLEEP | DROP_SKELETON | DROP_CORPSE
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_WOOD |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:ARROW_2 | MISSILE
+D:An agile hunter, ready and relaxed.
+
+N:84:Blue jelly
+G:j:b
+I:110:12d8:2:1:99
+W:4:1:2000:14
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:COLD:1d6
+F:NEVER_MOVE | COLD_BLOOD |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:IM_COLD | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | SUSCEP_FIRE | BASEANGBAND | NO_CUT
+D:It's a large pile of pulsing blue flesh.
+
+N:85:Creeping copper coins
+G:$:u
+I:100:7d8:3:24:10
+W:4:3:0:9
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d4
+B:TOUCH:POISON:2d4
+F:ONLY_GOLD | DROP_1D2 | SUSCEP_ACID |
+F:COLD_BLOOD | BASH_DOOR |
+F:IM_ELEC | IM_POIS | CHAR_MULTI |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of copper coins, until it starts crawling towards you
+D:on tiny legs.
+
+N:86:Giant white rat
+G:r:W
+I:110:2d2:8:7:30
+W:4:1:200:1
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d3
+F:RAND_25 |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is a very vicious rodent.
+
+N:87:Snotling
+G:o:U
+I:110:5d5:20:32:30
+W:4:1:900:15
+E:1:1:1:2:1:1
+O:25:50:0:20
+B:HIT:HURT:1d6
+F:MALE |
+F:FRIENDS | DROP_60 | RAND_50 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_WOOD |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:Immature Orcling, running wild and screaming all the time.
+
+N:88:Swordfish
+G:~:W
+I:120:4d7:14:10:20
+W:4:2:800:15
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+F:ANIMAL | AQUATIC | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A fish with a swordlike "beak".
+
+N:89:Blue worm mass
+G:w:b
+I:100:5d8:7:12:10
+W:4:1:40:5
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:COLD:1d4
+F:RAND_50 | RAND_25 |
+F:STUPID | WEIRD_MIND | COLD_BLOOD |
+F:ANIMAL | IM_COLD | CAN_SWIM |
+F:HURT_LITE | NO_FEAR |
+F:MORTAL | SUSCEP_FIRE | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:90:Large grey snake
+G:J:s
+I:100:6d8:6:41:50
+W:4:1:1300:14
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d5
+B:CRUSH:HURT:1d8
+F:RAND_25 | CAN_SWIM | DROP_SKELETON | DROP_CORPSE | WILD_TOO |
+F:BASH_DOOR | HAS_EGG | ANIMAL | MORTAL | BASEANGBAND
+D:It is about ten feet long.
+
+# New monster added by furiosity for the Theme module
+# Ranger chieftain without the magic other than arrows
+N:91:Corsair of Umbar
+G:p:U
+I:120:50d20:20:60:10
+W:41:2:1800:1500
+E:1:1:1:2:1:1
+O:30:50:20:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | TAKE_ITEM |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP | IM_FIRE | IM_ELEC | IM_COLD | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:ARROW_2 | ARROW_3 | ARROW_4 | MISSILE |
+D:A person with no love for Gondor. He thinks you are a soldier in
+D:the King's army.
+
+# New monster added by furiosity for the Theme module
+# Master rogue with some tweaks
+N:92:Dunlending
+G:p:g
+I:120:15d9:20:30:40
+W:25:2:1600:130
+E:1:1:1:2:1:1
+O:80:10:10:0
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+B:HIT:POISON:2d8
+F:MALE | DROP_SKELETON | DROP_CORPSE |
+F:DROP_2D2 | SUSCEP_ELEC | FRIENDS |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:ARROW_1 |
+D:A person with no love for Rohan. He thinks you are a Rider of the
+D:Mark in disguise.
+
+N:93:Apprentice mage
+G:p:r
+I:110:6d4:20:6:10
+W:6:2:1400:6
+E:1:1:1:2:1:1
+O:25:0:70:0
+B:HIT:HURT:1d4
+F:MALE |
+F:FORCE_SLEEP |
+F:FRIENDS | DROP_60 | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:BLINK | BLIND | CONF | MISSILE
+D:He is leaving behind a trail of dropped spell components.
+
+N:94:Green naga
+G:n:g
+I:110:9d8:18:40:120
+W:5:1:1700:30
+E:0:0:0:0:1:0
+O:0:25:0:65
+B:CRUSH:HURT:1d8
+B:SPIT:ACID:2d6
+F:FEMALE |
+F:RAND_25 | TAKE_ITEM | DROP_60 | DROP_CORPSE |
+F:BASH_DOOR | CAN_SWIM | WILD_TOO | WILD_SHORE |
+F:EVIL | IM_ACID | MORTAL | BASEANGBAND
+D:A large green serpent with a female torso. Her green skin glistens with
+D:acid.
+
+N:95:Giant leech
+G:w:u
+I:120:6d8:10:20:50
+W:5:1:30:20
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:3d1
+B:BITE:HURT:3d1
+F:ANIMAL | AQUATIC | WEIRD_MIND | RAND_25 | BASEANGBAND
+D:Yech! The disgusting thing only wants your blood!
+
+N:96:Barracuda
+G:~:G
+I:120:6d8:20:45:20
+W:5:2:150:30
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d10
+B:BITE:HURT:1d10
+F:AQUATIC | ANIMAL | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A predatory fish with razor-sharp teeth.
+
+N:97:Novice paladin
+G:p:w
+I:110:6d8:20:16:5
+W:4:1:1700:18
+E:1:1:1:2:1:1
+O:0:70:25:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+F:MALE | GOOD | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:SCARE | CAUSE_1
+D:An adventurer both devoutly religious and skillful in combat.
+D:He seems to consider you an agent of Morgoth.
+
+# New monster added by furiosity for the Theme module
+N:98:Man of Harad
+G:p:u
+I:110:16d10:20:50:40
+W:17:1:3000:70
+E:1:1:1:2:1:1
+O:30:70:0:0
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+B:BITE:HURT:1d6
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_WOOD | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | MALE |
+F:EVIL | HURT_LITE | BASEANGBAND
+D:A dark-skinned human who worships Sauron. A powerful warrior,
+D:almost as strong as a troll. He has bizarre white eyes.
+
+N:99:Blue ooze
+G:j:b
+I:110:3d4:8:16:80
+W:5:1:300:7
+E:0:0:0:0:0:0
+O:45:20:20:0
+B:CRAWL:COLD:1d4
+F:RAND_50 | RAND_25 | DROP_60 |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:IM_COLD | SUSCEP_FIRE
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It's blue and it's oozing.
+
+N:100:Green glutton ghost
+G:G:g
+I:130:3d4:10:20:10
+W:5:1:0:15
+E:0:0:0:0:0:0
+O:30:30:30:5
+B:TOUCH:EAT_FOOD:1d1
+F:RAND_50 | RAND_25 |
+F:DROP_60 | DROP_90 | CAN_FLY |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It is a very ugly green ghost with a voracious appetite.
+
+N:101:Green jelly
+G:j:g
+I:120:22d8:2:1:99
+W:5:1:2500:18
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ACID:1d2
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:IM_ACID | HURT_LITE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a large pile of pulsing green flesh.
+
+# New monster added for the Theme module
+# From UnAngband
+N:102:Lurtz, Uruk Captain of the White Hand
+G:o:g
+I:110:72d10:20:95:50
+W:22:3:1800:550
+E:1:1:1:2:1:1
+O:0:50:0:50
+B:HIT:HURT:3d8
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:BASEANGBAND | UNIQUE | FORCE_MAXHP | CAN_SPEAK | SMART |
+F:EVIL | ORC | OPEN_DOOR | BASH_DOOR | IM_FIRE | IM_COLD |
+F:IM_POIS | ESCORT | ESCORTS | DROP_1D2 | DROP_GOOD | MALE |
+D:A strong and cunning orc warrior, a commander of Saruman's orcs.
+
+# New monster added for the Theme module
+# From T-Plus by Ingeborg S. Norden
+N:103:Munchkin
+G:l:B
+I:120:35d50:255:75:0
+W:60:5:330:20000
+E:1:1:1:2:1:1
+O:0:45:45:10
+B:INSULT:INSANITY:2d10
+B:INSULT:EAT_GOLD:2d10
+B:INSULT:EAT_ITEM:2d10
+F:MALE | SMART | CAN_SPEAK | JOKEANGBAND |
+F:FORCE_MAXHP |
+F:RAND_25 |
+F:DROP_90 | DROP_GOOD | DROP_GREAT |
+F:DROP_4D2 | DROP_2D2 | ONLY_ITEM | AI_ANNOY |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | KILL_BODY | RES_NETH | RES_DISE |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:RES_NEXU | RES_PLAS | HAS_LITE | NO_CUT | NO_STUN |
+F:REFLECTING |
+S:1_IN_5
+S:HEAL | HASTE | TPORT | TELE_AWAY | BLIND | CONF | SCARE |
+S:CAUSE_2 | FORGET | TRAPS |
+S:BO_MANA | ROCKET |
+D:This annoying little gnome won't stop bragging about his great
+D:magical powers and shiny new equipment--unless someone silences
+D:him permanently. Unfortunately, your own weapons and spells
+D:don't seem to work as well as they should on this fellow...
+
+N:104:Disenchanter eye
+G:e:v
+I:100:7d8:2:10:10
+W:5:2:500:20
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:UN_BONUS
+F:ATTR_MULTI | ATTR_ANY | RES_DISE | DROP_CORPSE |
+F:NEVER_MOVE | CAN_FLY |
+F:HURT_LITE | NO_FEAR | BASEANGBAND
+S:1_IN_9 |
+S:DRAIN_MANA
+D:A disembodied eye, crackling with magic.
+
+N:105:Red worm mass
+G:w:r
+I:100:5d8:7:12:10
+W:5:1:40:6
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:FIRE:1d6
+F:RAND_50 | RAND_25 | SUSCEP_COLD |
+F:STUPID | EMPTY_MIND | BASH_DOOR |
+F:ANIMAL | IM_FIRE | CAN_SWIM |
+F:HURT_LITE | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a large slimy mass of worms.
+
+N:106:Copperhead snake
+G:J:o
+I:110:4d6:6:20:1
+W:5:1:200:15
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:POISON:2d4
+F:RAND_50 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE | BASH_DOOR |
+F:ANIMAL | IM_POIS | HAS_EGG | MORTAL | BASEANGBAND
+D:It has a copper head and sharp venomous fangs.
+
+N:107:Death sword
+G:|:W
+I:130:6d6:20:40:0
+W:6:5:0:30
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:NEVER_MOVE | NONLIVING | NO_FEAR | SUSCEP_ACID |
+F:STUPID | EMPTY_MIND | COLD_BLOOD | CHAR_MULTI | NO_CONF | NO_SLEEP |
+F:DROP_90 | EVIL | IM_COLD | IM_FIRE | FORCE_MAXHP | IM_ELEC | IM_POIS |
+F:BASEANGBAND | HAS_LITE | NO_CUT
+D:A bloodthirsty blade lurking for prey. Beware!
+
+N:108:Purple mushroom patch
+G:,:v
+I:110:1d1:2:1:0
+W:6:2:40:15
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:LOSE_CON:1d2
+B:SPORE:LOSE_CON:1d2
+B:SPORE:LOSE_CON:1d2
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yuck! It doesn't look so tasty.
+
+N:109:Apprentice priest
+G:p:g
+I:110:7d4:20:10:5
+W:6:2:1500:6
+E:1:1:1:2:1:1
+O:20:50:20:5
+B:HIT:HURT:1d5
+F:MALE | GOOD |
+F:FORCE_SLEEP | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:HEAL | SCARE | CAUSE_1
+D:He is tripping over his priestly robes.
+
+N:110:Apprentice warrior
+G:p:u
+I:110:9d4:20:16:5
+W:6:2:1600:6
+E:1:1:1:2:1:1
+O:0:95:0:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d6
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He looks inexperienced but tough.
+
+# New monster added for the Theme module
+# Suggested by Atarlost in the t-o-m-e.net forums
+N:111:Petty-dwarf
+G:k:s
+I:110:6d6:25:80:200
+W:8:4:0:30
+B:HIT:HURT:3d4
+B:TOUCH:EAT_GOLD
+F:MALE
+F:DROP_1D2 | DROP_GOOD
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR
+F:EVIL
+S:1_IN_8
+S:ARROW_1
+D:A filthy little dwarf. He wants your purse, and judging by the
+D:size of his axe, he's quite likely to get it.
+
+# New monster added for the Theme module
+# Suggested by Atarlost in the t-o-m-e.net forums
+N:112:Petty-dwarf mage
+G:k:R
+I:120:7d10:20:16:20
+W:10:1:0:50
+B:HIT:HURT:1d6
+B:HIT:HURT:UN_BONUS:1d6
+F:MALE
+F:FORCE_SLEEP
+F:ONLY_ITEM | DROP_1D2
+F:OPEN_DOOR | BASH_DOOR
+F:EVIL
+S:1_IN_5
+S:BLIND | CONF | MISSILE | DARKNESS | BA_POIS
+D:A small dwarf in mage's robes. He looks comical, but he has slain any
+D:adventurer foolish enough to laugh at him.
+
+N:113:Brown mold
+G:m:u
+I:110:15d8:2:12:99
+W:6:1:50:20
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:CONFUSE:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A strange brown growth on the dungeon floor.
+
+N:114:Giant brown bat
+G:b:u
+I:130:3d8:10:15:30
+W:6:1:600:10
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+F:RAND_50 | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:ANIMAL | DROP_CORPSE | AI_ANNOY
+F:MORTAL | BASEANGBAND
+D:It screeches as it attacks.
+
+# New monster added by furiosity for the Theme module
+N:115:Butterfly
+G:I:B
+I:120:1d1:6:5:10
+W:3:1:100:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:RAND_50 | RAND_25 | NEUTRAL | NO_TARGET | WILD_ONLY | WILD_WOOD | NEVER_BLOW |
+F:WEIRD_MIND | ANIMAL | MORTAL | BASEANGBAND | WILD_GRASS |
+D:A large insect with beautiful fluttering wings.
+
+N:116:Apprentice rogue
+G:p:b
+I:110:8d4:20:12:5
+W:6:2:1400:6
+E:1:1:1:2:1:1
+O:50:25:0:20
+B:HIT:HURT:1d6
+B:TOUCH:EAT_GOLD
+F:MALE | FRIENDS |
+F:DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_TOO |
+F:EVIL | MORTAL | BASEANGBAND
+D:A rather shifty individual.
+
+N:117:Creeping silver coins
+G:$:s
+I:100:12d8:4:30:10
+W:6:3:0:18
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:TOUCH:POISON:2d6
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:COLD_BLOOD | BASH_DOOR | SUSCEP_ACID | CHAR_MULTI |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of silver coins, until it starts crawling towards you
+D:on tiny legs.
+
+N:118:Snaga
+G:o:o
+I:110:8d8:20:32:30
+W:6:1:1600:15
+E:1:1:1:2:1:1
+O:20:50:5:15
+B:HIT:HURT:1d8
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is one of the many weaker 'slave' orcs, often mistakenly known as a
+D:goblin.
+
+N:119:Rattlesnake
+G:J:r
+I:110:6d7:6:24:1
+W:6:1:200:20
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:POISON:2d5
+F:RAND_50 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR | HAS_EGG | ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+D:It is recognised by the hard-scaled end of its body that is often rattled
+D:to frighten its prey.
+
+N:120:Giant slug
+G:w:U
+I:100:12d9:10:25:25
+W:6:1:600:25
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:ACID:2d4
+B:BITE:ACID:2d6
+F:ANIMAL | EMPTY_MIND | KILL_ITEM | KILL_BODY | CAN_SWIM | WILD_TOO |
+F:DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10
+S:BR_ACID
+D:It is slowly making its way towards you, eating everything in
+D:its path...
+
+N:121:Giant pink frog
+G:R:r
+I:110:5d8:12:16:50
+W:7:1:200:16
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:LOSE_STR:2d4
+F:RAND_50 | WILD_ONLY | WILD_SHORE |
+F:BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It looks poisonous.
+
+N:122:Dark elf
+G:h:D
+I:110:7d10:20:16:20
+W:7:2:1200:25
+E:1:1:1:2:1:1
+O:20:20:50:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:MALE |
+F:FORCE_SLEEP |
+F:DROP_90 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:CONF | DARKNESS | MISSILE
+D:An elven figure with jet black skin and white hair, his eyes are large and
+D:twisted with evil.
+
+# New monster added by furiosity for the Theme module
+N:123:Moth
+G:I:W
+I:120:1d1:6:5:10
+W:3:1:100:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:EAT_LITE:1d1
+F:RAND_50 | RAND_25 | HURT_LITE | WILD_TOO | WILD_WOOD |
+F:WEIRD_MIND | ANIMAL | MORTAL | BASEANGBAND | WILD_GRASS |
+S:MULTIPLY
+D:Nocturnal insect of a kind closely related to butterflies.
+
+N:124:Crypt creep
+G:s:D
+I:110:6d8:20:12:14
+W:7:2:0:25
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:1d2
+B:CLAW:HURT:1d2
+B:BITE:POISON
+F:RAND_25
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | FRIENDS |
+F:EVIL | UNDEAD | IM_POIS | IM_COLD |
+F:NO_CONF | NO_SLEEP | HURT_LITE | BASEANGBAND | NO_CUT
+S:1_IN_10
+S:CAUSE_1 | S_UNDEAD
+D:A frightening skeletal figure in a black robe.
+
+N:125:Rotting corpse
+G:z:R
+I:110:8d8:20:20:20
+W:8:1:0:15
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:POISON:1d3
+B:CLAW:POISON:1d3
+F:OPEN_DOOR | BASH_DOOR | FRIENDS |
+F:NO_CONF | NO_SLEEP | UNDEAD | EVIL | NO_FEAR | IM_POIS |
+F:IM_COLD | COLD_BLOOD | EMPTY_MIND | BASEANGBAND | NO_CUT
+D:Corpses awakened from their sleep by dark sorcery.
+
+N:126:Cave orc
+G:o:G
+I:110:11d9:20:32:30
+W:7:1:1900:20
+E:1:1:1:2:1:1
+O:20:70:0:0
+B:HIT:HURT:1d8
+F:MALE |
+F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is often found in huge numbers in deep caves.
+
+N:127:Wood spider
+G:S:U
+I:120:3d6:8:16:80
+W:7:3:600:15
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:STING:POISON:1d4
+F:FRIENDS | DROP_SKELETON |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_WOOD |
+F:ANIMAL | SPIDER | IM_POIS |
+F:MORTAL | BASEANGBAND
+D:It scuttles towards you.
+
+N:128:Hurog
+G:u:r
+I:110:8d8:20:32:30
+W:7:2:300:16
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+F:FRIENDS |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | BASEANGBAND |
+S:1_IN_50 |
+S:BR_NETH
+D:A minor demonic servant of evil. Its features remind you of a dog - in fact,
+D:Huroeg are the result of the corruption of dogs by Morgoth.
+
+N:129:Bloodshot eye
+G:e:r
+I:110:10d8:2:6:10
+W:7:3:550:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:BLIND:2d6
+F:NEVER_MOVE | CAN_FLY | DROP_CORPSE |
+F:HURT_LITE | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:DRAIN_MANA
+D:A disembodied eye, bloodshot and nasty.
+
+N:130:Red naga
+G:n:R
+I:110:11d8:20:40:120
+W:7:2:1800:40
+E:0:0:0:0:1:0
+O:50:0:50:0
+B:CRUSH:HURT:1d10
+B:BITE:LOSE_STR:1d4
+F:FEMALE | CAN_SWIM | WILD_TOO | WILD_SHORE |
+F:RAND_25 | DROP_60 |
+F:TAKE_ITEM | BASH_DOOR | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND
+D:A large red snake with a woman's torso.
+
+N:131:Red jelly
+G:j:r
+I:110:26d8:2:1:99
+W:7:1:2500:26
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:LOSE_STR:1d5
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:HURT_LITE | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a large pulsating mound of red flesh.
+
+# New monster added by furiosity for the Theme module
+N:132:Nightingale
+G:B:B
+I:110:1d1:30:1:10
+W:0:3:80:0
+E:0:1:1:0:1:0
+O:0:0:0:0
+F:RAND_25 | CAN_FLY | WILD_ONLY | WILD_WOOD | WILD_GRASS |
+F:ANIMAL | DROP_SKELETON | NEVER_BLOW | NEUTRAL | NO_TARGET |
+F:MORTAL | BASEANGBAND | DG_CURSE |
+D:Small brown birds of thrush kind, famous for their clear
+D:singing, and the fact that they will sing during the night
+D:as well as the day (hence their name). Since the days of
+D:Luthien, the nightingales of Middle-earth are surrounded
+D:by a strange blue aura and are rumoured to be under great
+D:protection of the Valar.
+
+N:133:Lost soul
+G:G:W
+I:110:2d8:12:10:10
+W:7:2:0:18
+E:0:0:0:0:0:0
+O:60:0:25:0
+B:HIT:HURT:2d2
+B:TOUCH:LOSE_WIS
+F:RAND_50 | DROP_60 | DROP_90 | CAN_FLY |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD |
+F:IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:TPORT | DRAIN_MANA
+D:It is almost insubstantial.
+
+N:134:Night lizard
+G:R:b
+I:110:4d8:20:16:30
+W:7:2:400:35
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+B:BITE:HURT:1d6
+F:ANIMAL | CAN_SWIM | WILD_TOO | DROP_CORPSE
+F:MORTAL | HAS_EGG | BASEANGBAND
+D:It is a black lizard with overlapping scales and a powerful jaw.
+
+# New monster added by furiosity for the Theme module
+N:135:Gorcrow
+G:B:G
+I:120:3d5:40:12:0
+W:3:2:300:10
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:BITE:HURT:1d4
+B:BITE:DISEASE:1d4
+F:ANIMAL | WILD_TOO | WILD_WOOD | CAN_FLY | DROP_CORPSE | WILD_SHORE |
+F:MORTAL | HAS_EGG | BASEANGBAND | EVIL | WILD_SWAMP | IMPRESED |
+D:It is a hooded crow, camouflaged well for a swampland or forest.
+D:It is a carrion bird that often lives close alongside the mewlips,
+D:the remains of whose prey it devours.
+
+N:136:Skeleton orc
+G:s:W
+I:110:10d8:20:36:40
+W:8:1:1700:26
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:2d5
+F:COLD_BLOOD | EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is an animated orc skeleton.
+
+N:137:Grima the Wormtongue, Agent of Saruman
+G:p:B
+I:110:28d10:20:30:20
+W:9:2:1500:150
+E:1:1:1:2:1:1
+O:10:50:35:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+B:TOUCH:EAT_GOLD
+B:INSULT:*
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_GREAT |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON |
+F:EVIL | RES_TELE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:HEAL | SLOW | TRAPS | BO_COLD | BA_POIS
+D:He was once the chief counsellor to King Theoden of Rohan.
+D:He betrayed king and country by becoming a spy for the
+D:corrupted Istari Saruman.
+
+N:138:Robin Hood, the Outlaw
+G:p:G
+I:120:16d12:20:30:20
+W:10:2:1600:150
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+B:TOUCH:EAT_GOLD
+B:TOUCH:EAT_ITEM
+F:UNIQUE | MALE | FORCE_SLEEP | FORCE_MAXHP | CAN_SPEAK |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_GREAT | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | EVIL | DROP_SKELETON | DROP_CORPSE
+F:MORTAL | JOKEANGBAND | HAS_LITE
+S:1_IN_5
+S:ARROW_2 | HEAL | TRAPS
+D:The legendary archer who steals from the rich (you qualify).
+
+# New monster added by furiosity for the Theme module
+N:139:Gull
+G:B:o
+I:120:4d5:40:12:0
+W:4:2:500:8
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:BITE:HURT:1d4
+F:ANIMAL | WILD_ONLY | WILD_SHORE | CAN_FLY | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | WILD_OCEAN | NEUTRAL | NO_TARGET |
+D:A sea-bird found around the shores of Middle-earth. The sound of a
+D:gull mewing is said to awaken the Sea-longing in the heart of an Elf.
+
+N:140:Lagduf, the Snaga
+G:o:o
+I:110:22d10:20:32:30
+W:8:2:1700:80
+E:1:1:1:2:1:1
+O:10:80:0:0
+B:HIT:HURT:1d11
+B:HIT:HURT:1d11
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+F:UNIQUE | MALE | EVIL | ORC | FORCE_MAXHP | ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | SPECIAL_GENE |
+F:OPEN_DOOR | BASH_DOOR | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:An orc soldier who served under Shagrat in the garrison of the Tower of Cirith Ungol.
+
+# New monster added by furiosity for the Theme module
+N:141:Kirinki
+G:B:R
+I:110:1d1:30:1:10
+W:1:9:80:0
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_25 | CAN_FLY | WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:ANIMAL | DROP_SKELETON | HAS_EGG | IMPRESED |
+F:MORTAL | BASEANGBAND
+S:1_IN_10
+S:SHRIEK
+D:A tiny scarlet bird from Numenor, with a really high voice.
+
+N:142:Apprentice ranger
+G:p:W
+I:110:6d8:20:8:5
+W:8:2:1500:18
+E:1:1:1:2:1:1
+O:0:80:0:15
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+F:MALE |
+F:FORCE_SLEEP | FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:ARROW_2 | MISSILE
+D:An agile hunter, ready and relaxed.
+
+N:143:Giant salamander
+G:R:R
+I:110:6d7:6:40:1
+W:8:1:600:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:3d6
+F:FORCE_SLEEP | SUSCEP_COLD |
+F:RAND_25 |
+F:ANIMAL | IM_FIRE | CAN_SWIM | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_9
+S:BR_FIRE
+D:A large black and yellow lizard. You'd better run away!
+
+N:144:Space monster
+G:.:d
+I:110:21d8:30:14:20
+W:8:2:0:28
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:TERRIFY:1d4
+F:PASS_WALL | NO_CONF | NO_SLEEP | NONLIVING | IM_ACID | CAN_FLY | JOKEANGBAND | NO_CUT
+D:A black hole in the fabric of reality.
+
+# New monster added by furiosity for the Theme module
+N:145:Swan
+G:B:w
+I:120:9d10:8:100:255
+W:20:3:300:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+F:CAN_FLY | NEUTRAL | NO_TARGET | GOOD |
+F:MORTAL | NEVER_BLOW | DG_CURSE | WILD_ONLY |
+F:AQUATIC | WILD_SHORE | NO_TARGET | WILD_OCEAN
+D:Beautiful and graceful large white birds inhabiting aquatic
+D:regions. They never do any harm, and it is said that anyone
+D:who kills a swan incurs the wrath of the Valar.
+
+N:146:Green mold
+G:m:g
+I:110:21d8:2:14:75
+W:8:1:40:28
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:TERRIFY:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_ACID | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange growth on the dungeon floor.
+
+N:147:Apprentice paladin
+G:p:w
+I:110:6d8:20:16:5
+W:8:2:1500:18
+E:1:1:1:2:1:1
+O:30:55:10:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+F:MALE | GOOD | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:SCARE | CAUSE_1
+D:He thinks you are an agent of Morgoth.
+
+N:148:Caborrog
+G:u:U
+I:110:13d9:20:32:30
+W:8:3:1000:16
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:HIT:HURT:1d8
+F:FRIENDS |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | BASEANGBAND |
+S:1_IN_50 |
+S:BR_NETH
+D:A minor demonic servant of evil. It resembles a frog - in fact,
+D:Caborroeg are the result of Morgoth's corruption of frogs.
+
+N:149:Hill orc
+G:o:u
+I:110:13d9:20:32:30
+W:8:1:2000:25
+E:1:1:1:2:1:1
+O:10:70:10:0
+B:HIT:HURT:1d10
+F:MALE |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is a hardy well-weathered survivor.
+
+N:150:Bandit
+G:p:b
+I:110:8d8:20:24:10
+W:10:2:1500:26
+E:1:1:1:2:1:1
+O:25:60:0:0
+B:HIT:HURT:2d4
+B:TOUCH:EAT_GOLD
+F:MALE |
+F:DROP_1D2 | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:He is after your cash!
+
+N:151:Hunting hawk
+G:B:u
+I:120:8d8:30:25:10
+W:8:2:800:22
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d4
+F:ANIMAL | NO_FEAR | CAN_FLY | WILD_WOOD | WILD_TOO | DROP_CORPSE
+F:MORTAL | HAS_EGG | IMPRESED | BASEANGBAND | AQUATIC
+D:Trained to hunt and kill without fear.
+
+N:152:Phantom warrior
+G:G:B
+I:110:5d5:20:10:40
+W:8:1:0:15
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d11
+B:HIT:HURT:1d11
+F:PASS_WALL | NO_SLEEP | FRIENDS | COLD_BLOOD | NONLIVING |
+F:NO_FEAR | EMPTY_MIND | CAN_FLY | BASEANGBAND | NO_CUT
+D:Spectral creatures that are half real, half illusion.
+
+# New monster added by furiosity for the Theme module
+N:153:Thrush
+G:B:U
+I:120:3d5:40:12:0
+W:0:2:400:0
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:BITE:HURT:1d3
+F:ANIMAL | WILD_ONLY | WILD_WOOD | CAN_FLY | DROP_CORPSE |
+F:MORTAL | HAS_EGG | BASEANGBAND | NEUTRAL | NO_TARGET | WILD_GRASS |
+D:Large speckled brown birds with a special fondness for snails,
+D:whose shells they remove by breaking them against stones.
+
+N:154:Yeti
+G:Y:w
+I:110:11d9:20:24:10
+W:9:3:3500:30
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d4
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN | DROP_CORPSE |
+F:ANIMAL | IM_COLD |
+F:MORTAL | SUSCEP_FIRE | BASEANGBAND
+D:A large white figure covered in shaggy fur.
+
+# New monster added by furiosity for the Theme module
+N:155:Fox
+G:C:o
+I:120:7d7:30:30:20
+W:10:1:600:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:BASH_DOOR | WILD_TOO | WILD_WOOD | WILD_WASTE | WILD_MOUNTAIN |
+F:ANIMAL | DROP_CORPSE | MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:SHRIEK
+D:Dog-like carnivore of woodland and farmland, distinctive for
+D:its red-orange coats and its eerie plaintive cries.
+
+N:156:Giant grey rat
+G:r:s
+I:110:2d3:8:12:20
+W:9:1:250:2
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d4
+F:RAND_25 |
+F:ANIMAL | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is a rodent of unusual size.
+
+N:157:Black harpy
+G:H:D
+I:120:3d8:16:22:10
+W:9:1:600:19
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d2
+B:CLAW:HURT:1d2
+B:BITE:HURT:1d3
+F:FEMALE | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | DROP_CORPSE |
+F:RAND_25 | ANIMAL | EVIL | MORTAL | BASEANGBAND
+D:A woman's face on the body of a vicious black bird.
+
+# New monster added by furiosity for the Theme module
+N:158:Fly of Mordor
+G:I:U
+I:120:1d1:6:5:10
+W:3:1:100:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:RAND_50 | RAND_25 | EVIL |
+F:WEIRD_MIND | ANIMAL | MORTAL | BASEANGBAND
+S:SHRIEK
+D:An evil swarm of bloodsucking flies. They are grey, brown and black
+D:insects, together in a homogeneous mass. They are loud, hateful and
+D:hungry, and marked with a red eye-shape upon their backs.
+
+# New monster added by furiosity for the Theme module
+# Based on Serpent men from Zangband
+N:159:Limlug
+G:J:G
+I:120:15d10:20:40:20
+W:22:6:900:75
+E:1:1:1:2:1:1
+O:25:20:25:20
+B:BITE:POISON:5d5
+B:BITE:POISON:5d5
+F:MALE | CAN_SWIM | IM_POIS | IM_ACID | AQUATIC |
+F:DROP_60 | DROP_2D2 | FRIENDS | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | EVIL | MORTAL | BASEANGBAND
+F:WILD_TOO | WILD_OCEAN | WILD_SHORE |
+S:1_IN_8
+S:BA_POIS | SCARE | HOLD
+D:A sea-serpent of Elvish legend.
+
+N:160:Cave bear
+G:q:u
+I:110:8d8:10:35:10
+W:9:1:3000:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d6
+B:CLAW:HURT:1d6
+B:BITE:HURT:1d8
+F:BASH_DOOR | FORCE_MAXHP | FORCE_SLEEP | DROP_CORPSE |
+F:ANIMAL | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN |
+F:MORTAL | BASEANGBAND
+D:A large bear appears to have made its home in this cave. It is hungry,
+D:and you are trespassing in its territory.
+
+N:161:Rock mole
+G:r:u
+I:110:10d10:20:30:75
+W:9:2:60:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d10
+B:BITE:HURT:1d10
+F:WEIRD_MIND | BASH_DOOR | KILL_WALL | KILL_ITEM | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:Despite its unimpressive size, this mole creature has fangs powerful
+D:enough to bore through solid rock.
+
+N:162:Mindcrafter
+G:p:y
+I:110:9d8:20:15:20
+W:16:2:1700:50
+E:1:1:1:2:1:1
+O:30:40:30:0
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:MALE |
+F:FORCE_SLEEP | DROP_90 | WILD_TOO |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:CONF | BLIND | HOLD | SLOW | MIND_BLAST | S_MONSTER | BLINK
+D:A master of the mental arts, able to damage or dominate the
+D:minds of others.
+
+N:163:Hatchling blue dragon
+G:d:b
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 | HAS_EGG | IMPRESED |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_ELEC | BASEANGBAND | ATTR_MULTI | ATTR_MULTI
+S:1_IN_12 |
+S:BR_ELEC
+D:This newly-born dragon is still soft, its eyes unaccustomed to light and
+D:its scales a pale blue.
+
+N:164:Hatchling white dragon
+G:d:w
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | ATTR_MULTI
+F:EVIL | DRAGON | IM_COLD | SUSCEP_FIRE | HAS_EGG | IMPRESED | BASEANGBAND
+F:ATTR_MULTI
+S:1_IN_12 |
+S:BR_COLD
+D:This newly-born dragon is still soft, its eyes unaccustomed to light and
+D:its scales a pale white.
+
+N:165:Hatchling green dragon
+G:d:g
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY | DROP_CORPSE |
+F:EVIL | DRAGON | IM_POIS | HAS_EGG | IMPRESED | BASEANGBAND | ATTR_MULTI
+S:1_IN_12 |
+S:BR_POIS
+D:This newly-born dragon is still soft, its eyes unaccustomed to light and
+D:its scales a sickly green.
+
+N:166:Hatchling black dragon
+G:d:s
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID | HAS_EGG | IMPRESED | BASEANGBAND | ATTR_MULTI
+S:1_IN_12 |
+S:BR_ACID
+D:This newly-born dragon is still soft, its eyes unaccustomed to light and
+D:its scales a dull black.
+
+N:167:Hatchling red dragon
+G:d:r
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE | SUSCEP_COLD |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_FIRE | HAS_EGG | IMPRESED | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_11 |
+S:BR_FIRE
+D:This newly-born dragon is still soft, its eyes unaccustomed to light and
+D:its scales a pale red.
+
+N:168:Giant red ant
+G:a:r
+I:110:4d8:12:34:60
+W:9:2:600:22
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:STING:LOSE_STR:1d4
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_SKELETON
+F:ANIMAL | MORTAL | BASEANGBAND | HAS_LITE
+D:It is large and has venomous mandibles.
+
+N:169:Brodda, the Easterling
+G:p:U
+I:110:24d10:20:25:20
+W:9:2:2200:100
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:1d13
+B:HIT:HURT:1d13
+B:HIT:HURT:1d13
+B:HIT:HURT:1d13
+F:UNIQUE | MALE | EVIL
+F:FORCE_MAXHP | CAN_SPEAK | WILD_TOO | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A nasty piece of work, Brodda picks on defenceless women and children.
+
+# New monster added for the Theme module
+# From UnAngband
+N:170:Radbug, the Goblin
+G:o:y
+I:110:15d10:20:20:60
+W:7:3:1500:100
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+F:BASEANGBAND | UNIQUE | MALE | EVIL | ORC | FORCE_MAXHP |
+F:CAN_SPEAK | DROP_CORPSE | WILD_TOO | OPEN_DOOR | BASH_DOOR |
+F:HURT_LITE | ONLY_ITEM | DROP_1D2 | DROP_GOOD | ESCORT |
+D:Strong and powerful, for a goblin.
+
+N:171:King cobra
+G:J:g
+I:110:8d10:8:30:1
+W:9:2:300:28
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:SPIT:BLIND:1d2
+B:BITE:POISON:3d4
+F:RAND_50 | WILD_TOO | WILD_WOOD | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR | CAN_SWIM | ANIMAL | IM_POIS | HAS_EGG | MORTAL | BASEANGBAND
+D:It is a large snake with a hooded face.
+
+N:172:Eagle
+G:B:r
+I:120:9d9:30:25:10
+W:12:2:600:22
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d6
+F:ANIMAL | CAN_FLY | WILD_ONLY | WILD_WASTE | WILD_MOUNTAIN | WILD_WOOD |
+F:DROP_CORPSE | MORTAL | BASEANGBAND | NEUTRAL | NO_TARGET | IMPRESED | HAS_EGG | AQUATIC
+D:A magnificent huge predatory bird.
+
+N:173:War bear
+G:q:r
+I:110:10d10:10:35:10
+W:9:1:2000:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:HURT:1d6
+F:WEIRD_MIND | BASH_DOOR | FRIENDS | DROP_SKELETON | DROP_CORPSE
+F:ANIMAL
+F:MORTAL | BASEANGBAND
+D:A bear with tusks, trained to kill.
+
+N:174:Killer bee
+G:I:o
+I:120:2d4:12:34:10
+W:9:2:50:22
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:STING:POISON:1d4
+B:STING:LOSE_STR:1d4
+F:WEIRD_MIND | FRIENDS | CAN_FLY | WILD_TOO |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is poisonous and aggressive.
+
+N:175:Giant spider
+G:S:W
+I:110:10d10:8:16:80
+W:10:2:700:35
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d10
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+B:BITE:HURT:1d10
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_SKELETON |
+F:ANIMAL | SPIDER | IM_POIS |
+F:MORTAL | BASEANGBAND
+D:It is a large spider whose bulbous body is bloated with poison.
+
+N:176:Giant white tick
+G:S:w
+I:100:12d8:12:40:20
+W:10:2:200:27
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:2d6
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY |
+F:ANIMAL | IM_POIS |
+F:MORTAL | BASEANGBAND
+D:It is moving slowly towards you.
+
+# New monster added for the Theme module
+# Based on Nightshade from T-Plus by Ingeborg S. Norden
+N:177:The Lucky Hobbit
+G:h:D
+I:110:40d5:40:10:3
+W:10:2:660:0
+E:0:1:1:2:1:1
+O:0:40:10:40
+B:TOUCH:EAT_FOOD
+B:TOUCH:EAT_ITEM
+B:BEG:EAT_GOLD
+B:INSULT:*
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:FORCE_MAXHP | FORCE_DEPTH | WILD_TOWN | WILD_ONLY |
+F:OPEN_DOOR | BASH_DOOR | DROP_GOOD |
+F:RAND_25 | DROP_60 | DROP_2D2 | DROP_GREAT | ONLY_ITEM |
+F:MORTAL | JOKEANGBAND | HAS_LITE
+D:An obscenely lucky and very stealthy Halfling. You have an intense
+D:desire to kill this creature.
+
+N:178:Dark elven mage
+G:h:r
+I:120:7d10:20:16:20
+W:10:1:1200:50
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_POIS | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BLIND | CONF | MISSILE | DARKNESS | BA_POIS
+D:A dark elven figure, dressed all in black, hurling spells at you.
+
+# New monster added for the Theme module
+# Suggested by Atarlost in the t-o-m-e.net forums
+N:179:Dark dwarven warrior
+G:k:u
+I:110:2d100:25:120:30
+W:20:2:0:160
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+F:MALE
+F:FORCE_SLEEP | FRIENDS
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD
+F:OPEN_DOOR | BASH_DOOR
+D:The dwarves of Nogrod were ever greedy, and through this Morgoth was able to
+D:snare them. Now they act as slavemasters in his mines.
+
+# New monster added for the Theme module
+# Suggested by Atarlost in the t-o-m-e.net forums
+N:180:Dark dwarven smith
+G:k:w
+I:110:2d100:25:120:1
+W:22:1:0:175
+B:HIT:SHATTER:6d6
+F:MALE
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD
+F:OPEN_DOOR | BASH_DOOR
+F:EVIL
+D:The dwarves of Nogrod were ever greedy, and through this Morgoth was able to
+D:snare them. This smith has been forging blades for the Orcs.
+
+# New monster added for the Theme module
+# Suggested by Atarlost in the t-o-m-e.net forums
+N:181:Dark dwarven lord
+G:k:D
+I:110:5d100:25:150:180
+W:25:2:0:300
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:MALE | EVIL
+F:FORCE_SLEEP | FORCE_MAXHP
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD
+F:OPEN_DOOR | BASH_DOOR
+F:IM_FIRE | IM_COLD | NO_CONF | NO_SLEEP
+S:1_IN_8
+S:HEAL | BO_FIRE | BO_ACID
+D:The dwarves of Nogrod were ever greedy, and through this Morgoth was able to
+D:snare them. This is a lord among the dark dwarves.
+
+# New monster added by furiosity for the Theme module
+# Based on Atarlost's suggestions for dark dwarves
+# and on dark elven priests.
+N:182:Dark dwarven priest
+G:k:g
+I:120:2d100:20:30:30
+W:27:1:1200:50
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:HEAL | BLIND | CONF | CAUSE_2 | DARKNESS | MISSILE
+D:The dwarves of Nogrod were ever greedy, and through this Morgoth was able to
+D:snare them. This priest serves Melkor unquestioningly, and today it is your
+D:turn to die.
+
+N:183:Dark elven warrior
+G:h:u
+I:110:10d11:20:16:20
+W:10:1:1400:50
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:MALE |
+F:DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_12
+S:MISSILE
+D:A dark elven figure in armour, ready with his sword.
+
+N:184:Clear mushroom patch
+G:,:B
+I:120:1d1:4:1:0
+W:10:2:30:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:HURT:1d1
+F:ATTR_CLEAR |
+F:NEVER_MOVE | INVISIBLE | COLD_BLOOD |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:Yum! It smells quite tasty. If you could only see it.
+
+N:185:Quiver slot
+G:,:U
+I:120:1d1:4:1:0
+W:10:2:60:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:CONFUSE:1d1
+F:NEVER_MOVE | COLD_BLOOD |
+F:STUPID | EMPTY_MIND |
+F:NO_CONF | NO_SLEEP | NO_FEAR | JOKEANGBAND | NO_CUT
+S:MULTIPLY |
+S:1_IN_5 | ARROW_1
+D:What looks like the remains of a quiver dropped by a past adventurer
+D:has become overgrown with a strange mold intent on using the contents
+D:of the quiver to grab prey.
+
+N:186:Grishnakh, the Hill Orc
+G:o:y
+I:110:25d10:20:20:20
+W:10:3:2300:160
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d13
+B:HIT:HURT:1d11
+B:HIT:HURT:1d13
+B:HIT:HURT:1d11
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | SPECIAL_GENE |
+F:ESCORT | WILD_TOO |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is a cunning and devious orc. Short and broad, he has crooked
+D:legs and arms that hang almost to the ground.
+
+N:187:Giant tan bat
+G:b:U
+I:130:3d8:12:20:50
+W:10:2:600:18
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:TERRIFY:1d3
+B:CLAW:HURT:1d2
+B:CLAW:HURT:1d2
+F:RAND_50 | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:FORCE_SLEEP | ANIMAL | DROP_CORPSE | AI_ANNOY |
+F:MORTAL | BASEANGBAND
+D:The beating of its wings produces a strangely unnerving noise.
+
+N:188:Owlbear
+G:H:o
+I:110:12d12:20:20:20
+W:10:1:2000:35
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:CRUSH:HURT:1d10
+F:EVIL | ANIMAL | OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A bizarre bear with the claws and the face of an owl.
+
+# New monster added by furiosity for the Theme module
+N:189:Clear mewlip
+G:i:w
+I:110:2d5:12:6:10
+W:1:1:0:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:HURT:1d2
+F:BASEANGBAND | EMPTY_MIND | STUPID | ATTR_CLEAR |
+F:UNDEAD | RAND_50 | CAN_SWIM | INVISIBLE | EVIL |
+D:An evil cannibal spirit from the marshlands.
+
+N:190:Hairy mold
+G:m:o
+I:110:15d8:2:15:70
+W:10:1:50:32
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:1d3
+F:NEVER_MOVE | CAN_SWIM |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange hairy growth on the dungeon floor.
+
+N:191:Grizzly bear
+G:q:U
+I:110:15d15:10:35:10
+W:16:2:2600:55
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:1d12
+B:CRUSH:HURT:1d10
+F:WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:ANIMAL | BASH_DOOR |
+F:MORTAL | BASEANGBAND
+D:A huge, beastly bear, more savage than most of its kind.
+
+N:192:Disenchanter mold
+G:m:v
+I:110:16d8:2:20:70
+W:10:1:40:40
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:UN_BONUS:1d6
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND | RES_DISE |
+F:IM_POIS | ATTR_MULTI | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_11 |
+S:DRAIN_MANA
+D:It is a strange glowing growth on the dungeon floor.
+
+N:193:Pseudo-dragon
+G:d:o
+I:110:20d10:20:30:40
+W:10:2:10000:150
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE |
+F:DROP_60 | BASH_DOOR | HAS_EGG |
+F:EVIL | DRAGON | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_11 |
+S:CONF | SCARE | BR_LITE | BR_DARK
+D:A small relative of the dragon that inhabits dark caves.
+
+N:194:Limrog
+G:u:b
+I:120:16d9:20:32:30
+W:10:1:600:40
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | RES_TELE | CAN_FLY | BASEANGBAND
+S:1_IN_3 |
+S:BLINK | TELE_TO | TELE_AWAY | TPORT
+D:It is a fast-moving demon that blinks quickly in and out of existence; no
+D:other demon matches its teleporting mastery. It resembles a fish - Limroeg
+D:are actually fish that were corrupted by Morgoth.
+
+N:195:Creeping gold coins
+G:$:y
+I:100:18d8:5:36:10
+W:10:3:0:32
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d5
+B:TOUCH:POISON:3d5
+F:ONLY_GOLD | DROP_90 | DROP_1D2 |
+F:COLD_BLOOD | BASH_DOOR |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of gold coins, until it starts crawling towards you
+D:on tiny legs.
+
+N:196:Wolf
+G:C:u
+I:120:6d6:30:30:20
+W:10:1:600:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:RAND_25 | FRIENDS |
+F:BASH_DOOR | WILD_TOO | WILD_WOOD | WILD_WASTE | WILD_MOUNTAIN |
+F:ANIMAL | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:It howls and snaps at you.
+
+N:197:Giant fruit fly
+G:I:G
+I:120:2d2:8:14:10
+W:10:3:100:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | RAND_25 | CAN_FLY | WEIRD_MIND |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:A fast-breeding, annoying pest.
+
+N:198:Panther
+G:f:D
+I:120:10d8:40:30:0
+W:10:2:1300:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+F:BASH_DOOR | WILD_TOO | WILD_WOOD | WILD_GRASS | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A large black cat, stalking you with intent. It thinks you're its next
+D:meal.
+
+N:199:Brigand
+G:p:b
+I:110:9d8:20:32:10
+W:10:2:1700:35
+E:1:1:1:2:1:1
+O:25:60:0:0
+B:HIT:HURT:2d4
+B:TOUCH:EAT_ITEM
+F:MALE |
+F:DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | DROP_SKELETON |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is eyeing your backpack.
+
+# New monster added by furiosity for the Theme module
+N:200:Gray mewlip
+G:i:s
+I:110:4d7:12:9:10
+W:3:1:0:5
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:HURT:2d4
+F:BASEANGBAND | EMPTY_MIND | STUPID |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL |
+D:An evil cannibal spirit from the marshlands. It is
+D:especially aggressive.
+
+# New monster added by furiosity for the Theme module
+N:201:Orange mewlip
+G:i:o
+I:110:6d9:12:12:10
+W:5:1:0:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:POISON:2d4
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL |
+D:An evil cannibal spirit from the marshlands. It is
+D:surrounded by a foul stench.
+
+N:202:Undead mass
+G:j:D
+I:110:8d8:70:12:5
+W:10:2:200:33
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:DISEASE:1d6
+B:TOUCH:LOSE_CON:1d6
+F:UNDEAD | EMPTY_MIND | NO_CONF | NO_SLEEP | IM_POIS | IM_COLD | NO_FEAR |
+F:HURT_LITE | COLD_BLOOD | EVIL | NEVER_MOVE | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:A sickening mound of decaying flesh, bones, hands and other body parts.
+D:It seems to be growing.
+
+# New monster added by furiosity for the Theme module
+N:203:Bloodshot mewlip
+G:i:r
+I:110:6d9:12:12:10
+W:5:1:0:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:LOSE_STR:2d4
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL |
+D:An evil cannibal spirit from the marshlands. Its form seems
+D:infused with blood, surely that of its victims.
+
+N:204:Hatchling multi-hued dragon
+G:d:v
+I:110:13d10:20:30:70
+W:11:2:5000:45
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:HURT:1d6
+F:ATTR_MULTI |
+F:FORCE_MAXHP | FORCE_SLEEP |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | DRAGON | CAN_FLY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | HAS_EGG | IMPRESED |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_12 |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS
+D:This newly-born dragon is still soft, its eyes unaccustomed to light and
+D:its scales shimmering with a hint of colour.
+
+# New monster added by furiosity for the Theme module
+N:205:Green mewlip
+G:i:g
+I:110:6d9:12:12:10
+W:5:1:0:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:POISON:2d4
+B:TOUCH:CONFUSE:3d5
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL
+D:An evil cannibal spirit from the marshlands. It is
+D:surrounded by a foul stench and an aura of mystery.
+
+N:206:Old Man Willow
+G:#:s
+I:110:32d30:20:20:20
+W:25:5:3000:150
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:TOUCH:PARALYZE:1d14
+B:TOUCH:PARALYZE:1d14
+B:CRUSH:HURT:2d12
+F:ANIMAL | NEVER_MOVE | COLD_BLOOD | DROP_RANDART
+F:EMPTY_MIND | UNIQUE | FORCE_MAXHP | FORCE_SLEEP |
+F:RES_WATE | IM_POIS | IM_ACID | SUSCEP_FIRE | SPECIAL_GENE |
+F:DROP_1D2 | DROP_GOOD | ONLY_ITEM | BASEANGBAND | NO_CUT
+S:1_IN_10 |
+S:TELE_TO | HOLD |
+D:The ancient grey willow tree, ruler of the Old Forest. He despises
+D:trespassers in his territory. "...a huge willow-tree, old and hoary.
+D:Enormous it looked, its sprawling branches going up like racing arms
+D:with may long-fingered hands, its knotted and twisted trunk gaping in
+D:wide fissures that creaked faintly as the boughs moved."
+
+# New monster added by furiosity for the Theme module
+N:207:Blue mewlip
+G:i:b
+I:110:6d9:12:12:10
+W:5:1:0:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ELEC:3d5
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL | IM_ELEC |
+D:An evil cannibal spirit from the marshlands. It is
+D:surrounded by a barely noticeable aura of sparks.
+
+N:208:Zombified orc
+G:z:s
+I:110:11d8:20:24:25
+W:11:1:1800:30
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+F:COLD_BLOOD | EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a shambling orcish corpse leaving behind a trail of flesh.
+
+N:209:Hippogryph
+G:H:U
+I:110:20d9:12:14:10
+W:11:1:1500:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:HIT:HURT:2d5
+B:BITE:HURT:2d5
+F:BASH_DOOR | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_GRASS |
+F:ANIMAL | DROP_CORPSE | MORTAL | BASEANGBAND
+D:A strange hybrid of eagle and horse.
+
+N:210:Black mamba
+G:J:D
+I:120:10d8:10:32:1
+W:12:3:300:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:POISON:4d4
+F:RAND_50 | BASH_DOOR | CAN_SWIM |
+F:WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:ANIMAL | IM_POIS | DROP_SKELETON | DROP_CORPSE | HAS_EGG |
+F:MORTAL | BASEANGBAND
+D:It has glistening black skin, a sleek body, and highly venomous fangs.
+
+N:211:White wolf
+G:C:w
+I:120:7d7:30:30:20
+W:12:1:700:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d3
+B:BITE:HURT:1d4
+F:RAND_25 |
+F:FRIENDS | SUSCEP_FIRE |
+F:BASH_DOOR | WILD_TOO | WILD_WASTE |
+F:ANIMAL | IM_COLD | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A large and muscled wolf from the northern wastes. Its breath is cold and
+D:icy and its fur is coated with frost.
+
+N:212:Grape jelly
+G:j:v
+I:110:52d8:2:1:99
+W:12:3:2600:60
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EXP_10
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | HURT_LITE | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_11 |
+S:DRAIN_MANA
+D:Yum! It looks quite tasty. It is a pulsing mound of glowing flesh.
+
+N:213:Nether worm mass
+G:w:D
+I:100:5d8:10:15:3
+W:12:4:200:6
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EXP_10
+F:RAND_50 | RAND_25 | CAN_SWIM |
+F:STUPID | WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | HURT_LITE | NO_FEAR | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a disgusting mass of dark worms, eating each other, the floor,
+D:the air, you...
+
+# New monster added by furiosity for the Theme module
+N:214:Brown mewlip
+G:i:u
+I:110:6d9:12:12:10
+W:5:1:0:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:LOSE_CHR:3d5
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL | NO_CUT |
+D:An evil cannibal spirit from the marshlands. It seems to
+D:be rising straight from the earth to get you.
+
+N:215:Golfimbul, the Hill Orc Chief
+G:o:y
+I:110:26d10:20:60:20
+W:12:3:2200:230
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:1d13
+B:HIT:HURT:1d13
+B:HIT:HURT:1d11
+B:HIT:HURT:1d11
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | WILD_TOO | SPECIAL_GENE |
+F:ESCORT | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | CAN_SPEAK |
+F:EVIL | ORC | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A leader of a band of raiding orcs from the Misty Mountains
+D:He's been known to pick on Shire-folk.
+
+N:216:Swordsman
+G:p:u
+I:110:12d8:20:34:20
+W:12:1:1800:40
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:MALE | WILD_TOO |
+F:DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A warrior of considerable skill.
+
+# New monster added by furiosity for the Theme module
+N:217:Stone mewlip
+G:i:W
+I:110:7d10:12:25:10
+W:10:5:0:2
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:HURT:3d5
+B:TOUCH:SHATTER:1d1
+# Yes, I'm nasty. :P -furiosity
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL | NO_CUT | NO_STUN |
+D:An evil cannibal spirit from the marshlands. It seems to
+D:be coming from the walls.
+
+N:218:Hatchling bronze dragon
+G:d:U
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_CONF | HAS_EGG | IMPRESED | BASEANGBAND | ATTR_MULTI
+S:1_IN_12 |
+S:BR_CONF
+D:This newly-born dragon is still soft, its eyes unaccustomed to light and
+D:its scales a dull bronze.
+
+N:219:Hatchling gold dragon
+G:d:y
+I:110:10d10:20:30:70
+W:9:2:4000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | CAN_FLY | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_STUN | HAS_EGG | IMPRESED | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_12 |
+S:BR_SOUN
+D:This newly-born dragon is still soft, its eyes unaccustomed to light and
+D:its scales a pale gold.
+
+N:220:Evil eye
+G:e:D
+I:110:15d8:2:6:10
+W:18:3:600:80
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:EXP_10
+B:GAZE:EXP_10
+F:NEVER_MOVE | EVIL | CAN_FLY | DROP_CORPSE |
+F:HURT_LITE | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:HOLD | TELE_TO
+D:A huge disembodied eye. As you stare into the black nothingness of its pupil,
+D:you feel your will and vitality draining away, and are unable to do anything
+D:except approach it in horrified fascination.
+
+# New monster added by furiosity for the Theme module
+N:221:Yellow mewlip
+G:i:y
+I:110:7d10:12:25:10
+W:15:5:0:20
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EAT_LITE:3d5
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL | NO_CUT |
+D:An evil cannibal spirit from the marshlands. It seems to
+D:be surrounded with a strange aura of dark light.
+
+# New monster added by furiosity for the Theme module
+N:222:Pink mewlip
+G:i:R
+I:110:9d12:12:30:10
+W:20:5:0:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:LOSE_STR:4d4
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL | NO_CUT |
+D:An evil cannibal spirit from the marshlands. It glows
+D:an eerily unnatural pink colour.
+
+# New monster added by furiosity for the Theme module
+N:223:Tree mewlip
+G:i:G
+I:110:10d12:12:40:10
+W:25:3:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:POISON:5d5
+B:TOUCH:LOSE_DEX:5d5
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL | CAN_FLY |
+D:An evil cannibal spirit from the marshlands. It prefers
+D:to dwell in the trees and is rather stealthy.
+
+# New monster added by furiosity for the Theme module
+N:224:Air mewlip
+G:i:B
+I:110:11d12:12:45:10
+W:25:3:0:70
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:POISON:6d6
+B:TOUCH:BLIND:6d6
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL | IM_ELEC |
+D:An evil cannibal spirit from the marshlands. It seems to
+D:be materializing out of thin air.
+
+N:225:Priest
+G:p:g
+I:110:12d8:20:22:40
+W:12:1:1500:36
+E:1:1:1:2:1:1
+O:0:20:80:0
+B:HIT:HURT:2d3
+B:HIT:HURT:2d3
+F:MALE | GOOD |
+F:FORCE_SLEEP |
+F:DROP_1D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | SCARE | CAUSE_2 |
+S:S_MONSTER
+D:A robed man dedicated to his Vala. He believes you to be a
+D:servant of the Shadow.
+
+N:226:Dark elven priest
+G:h:g
+I:120:7d10:20:30:30
+W:12:1:1200:50
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:HIT:HURT:1d9
+B:HIT:HURT:1d10
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:HEAL | BLIND | CONF | CAUSE_2 | DARKNESS | MISSILE
+D:A dark elven figure, dressed all in black, chanting curses and waiting to
+D:deliver your soul to the Void.
+
+N:227:Air spirit
+G:E:B
+I:130:8d8:12:40:20
+W:12:2:0:40
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d3
+F:RAND_50 | RAND_25 | IM_ELEC | IM_POIS |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD | BASH_DOOR |
+F:IM_POIS | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A whirlwind of sentient air.
+
+N:228:Skeleton human
+G:s:W
+I:110:10d8:20:30:30
+W:12:1:1500:38
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is an animated human skeleton.
+
+N:229:Zombified human
+G:z:s
+I:110:12d8:20:24:20
+W:12:1:1500:34
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a shambling human corpse dropping chunks of flesh behind it.
+
+N:230:Tiger
+G:f:o
+I:120:12d10:40:40:0
+W:12:2:1500:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:1d6
+F:BASH_DOOR | WILD_TOO | WILD_GRASS | WILD_WOOD | WILD_MOUNTAIN |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:One of the largest of its species, a sleek orange and black shape creeps
+D:towards you, ready to pounce.
+
+N:231:Moaning spirit
+G:G:u
+I:120:5d8:14:20:10
+W:12:2:0:44
+E:0:0:0:0:0:0
+O:45:15:25:0
+B:WAIL:TERRIFY
+B:TOUCH:LOSE_DEX:1d8
+F:FORCE_SLEEP | RAND_25 |
+F:DROP_60 | DROP_90 | CAN_FLY |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:TPORT | SCARE
+D:A ghostly apparition that shrieks horribly.
+
+# New monster added by furiosity for the Theme module
+# Based on Plague worm mass from T-Plus by Ingeborg S. Norden
+N:232:Plague mewlip
+G:i:U
+I:110:100d11:15:70:20
+W:40:3:0:300
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:DISEASE:3d5
+B:TOUCH:PARASITE:6d5
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL |
+D:An evil cannibal spirit from the marshlands. Foul stench
+D:of decay surrounds it, and you are afraid to let it get
+D:near you.
+
+N:233:Spotted jelly
+G:j:o
+I:120:13d8:12:18:1
+W:12:3:2500:33
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:2d6
+B:TOUCH:ACID:2d6
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND | COLD_BLOOD |
+F:IM_ACID | IM_POIS | HURT_LITE | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A strange pile of flesh, covered in discoloured blotches.
+
+N:234:Drider
+G:S:b
+I:110:10d13:8:30:80
+W:13:2:2000:55
+E:1:1:1:2:1:0
+O:0:0:0:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:BITE:POISON:1d6
+F:FORCE_SLEEP |
+F:BASH_DOOR | DROP_SKELETON |
+F:EVIL | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:CONF | CAUSE_1 | DARKNESS | MISSILE | ARROW_2
+D:A dark elven torso merged with the bloated form of a giant spider.
+
+N:235:Mongbat
+G:b:B
+I:110:10d10:20:80:8
+W:13:2:800:65
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:POISON:1d8
+F:ANIMAL | EVIL | FRIENDS | CAN_FLY | FORCE_MAXHP |
+F:IM_COLD | IM_ELEC | IM_POIS | WEIRD_MIND | DROP_CORPSE
+F:MORTAL | BASEANGBAND
+D:They say it is notoriously difficult to kill.
+
+N:236:Killer brown beetle
+G:K:u
+I:110:13d8:10:40:30
+W:13:1:500:38
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is a vicious insect with a tough carapace.
+
+# New monster added by furiosity for the Theme module
+# Based on Charnel worm mass from T-Plus by Ingeborg S. Norden
+N:237:Death mewlip
+G:i:D
+I:130:44d100:255:75:10
+W:80:5:10:4000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EXP_20:7d5
+B:TOUCH:DISEASE:7d5
+B:TOUCH:PARASITE:14d10
+B:TOUCH:LOSE_ALL:7d5
+F:BASEANGBAND | EMPTY_MIND | STUPID | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL | NO_FEAR |
+F:FORCE_MAXHP | KILL_ITEM | KILL_BODY | NO_CONF |
+F:NO_SLEEP | NO_CUT | NO_STUN | REGENERATE | IM_COLD |
+F:RES_NETH | RES_PLAS | RES_WATE | RES_DISE | RES_NEXU |
+S:1_IN_5
+S:ANIM_DEAD |
+D:An evil cannibal spirit from the marshlands. It has been given
+D:additional power by necromantic magic, making it nearly invulnerable.
+# Wow, a dangerous icky thing :P
+
+N:238:Ogre
+G:O:U
+I:110:13d9:20:33:30
+W:13:2:2100:50
+E:1:1:1:2:1:1
+O:10:85:0:0
+B:HIT:HURT:2d8
+F:FRIENDS |
+F:DROP_60 | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A hideous, smallish giant that is often found near or with orcs.
+
+N:239:Creeping mithril coins
+G:$:B
+I:110:20d8:5:50:10
+W:13:3:0:45
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d5
+B:TOUCH:POISON:3d5
+F:ONLY_GOLD | DROP_90 | DROP_2D2 |
+F:COLD_BLOOD | BASH_DOOR | IM_ACID | CHAR_MULTI |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of sentient mithril coins that doesn't like being
+D:picked up.
+
+N:240:Illusionist
+G:p:R
+I:110:12d8:20:10:10
+W:13:2:1500:50
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:HIT:HURT:2d2
+F:MALE |
+F:FORCE_SLEEP | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HASTE | BLINK | TPORT | BLIND | HOLD | SLOW | CONF | DARKNESS
+D:A deceptive spellcaster.
+
+N:241:Druid
+G:p:G
+I:110:12d12:20:10:10
+W:13:2:1400:50
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:MALE | WILD_TOO | WILD_WOOD |
+F:FORCE_SLEEP | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HASTE | BLINK | BLIND | HOLD | SLOW | BO_FIRE | BO_ELEC | S_ANIMAL
+D:A priest devoted to Yavanna Kementari. He thinks you want to
+D:destroy the forests of Arda.
+
+# New monster added by furiosity for the Theme module
+# A Black Numenorean (hell knight) on steroids
+N:242:Fuinur, Lord of the Haradrim
+G:p:r
+I:140:80d100:50:300:0
+W:90:1:0:150000
+E:1:1:1:2:1:1
+O:0:40:60:0
+B:HIT:HURT:20d5
+B:HIT:EXP_80:20d5
+F:UNIQUE | MALE | MORTAL | BASEANGBAND | HAS_LITE |
+F:FORCE_MAXHP | SMART | IM_FIRE | IM_ELEC | IM_POIS |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GREAT |
+F:RES_NETH | RES_NEXU | RES_PLAS | RES_WATE |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | EVIL | SPECIAL_GENE |
+S:1_IN_5 |
+S:BLIND | SCARE | CAUSE_4 | BA_NETH | BA_FIRE | BO_PLAS
+S:S_HI_DEMON | S_HI_UNDEAD | HASTE |
+D:A Man of Numenor who fell under the influence of Sauron during the time
+D:the Dark Lord dwelt on that island. He sailed east to Middle-earth, with
+D:a companion named Herumor, and settled in the southern region of Harad.
+D:These two came to hold great power among the Haradrim. Fuinur has been
+D:appointed the task of guarding the realm of Angmar from intruders, in
+D:anticipation of Sauron's victory over the free People.
+
+N:243:Cloaker
+G:(:g
+I:130:7d7:20:40:0
+W:13:5:60:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:PARALYZE:5d5
+B:HIT:TERRIFY:5d5
+F:NEVER_MOVE | NO_FEAR |
+F:STUPID | EMPTY_MIND | COLD_BLOOD | CHAR_MULTI | NO_CONF | NO_SLEEP |
+F:DROP_90 | IM_COLD | FORCE_MAXHP | IM_ELEC | IM_POIS |
+F:BASEANGBAND | NO_CUT
+D:It resembles a normal cloak until some poor fool ventures too close.
+
+N:244:Black orc
+G:o:D
+I:110:12d10:20:36:20
+W:13:1:2000:45
+E:1:1:1:2:1:1
+O:10:50:20:15
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:MALE | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9
+S:ARROW_2
+D:He is a large orc with powerful arms and deep black skin.
+
+N:245:Ochre jelly
+G:j:U
+I:120:13d8:12:18:1
+W:13:3:2300:40
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:2d6
+B:TOUCH:ACID:2d6
+F:STUPID | EMPTY_MIND | COLD_BLOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A fast moving highly acidic pile of flesh. It is
+D:eating away the floor it rests on.
+
+N:246:Software bug
+G:I:R
+I:120:2d2:8:25:10
+W:14:1:0:4
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY |
+F:ANIMAL | MORTAL | JOKEANGBAND
+S:MULTIPLY
+D:Oh no! They are everywhere!
+
+N:247:Lurker
+G:.:w
+I:110:20d10:30:25:10
+W:14:3:0:80
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:CHAR_CLEAR | ATTR_CLEAR | CHAR_MULTI |
+F:NEVER_MOVE | FORCE_MAXHP |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+D:A strange creature that merges with the dungeon floor, trapping its
+D:victims by enveloping them within its perfectly disguised form.
+
+N:248:Tangleweed
+G:#:g
+I:100:5d5:5:5:5
+W:10:4:50:10
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:PARALYZE
+B:HIT:PARALYZE
+F:FORCE_SLEEP | NEVER_MOVE | STUPID | EMPTY_MIND | FRIENDS |
+F:KILL_TREES | SUSCEP_FIRE | ANIMAL |
+F:WILD_ONLY | COLD_BLOOD | WILD_WOOD | WILD_GRASS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | MORTAL | BASEANGBAND | DROP_60 | NO_CUT
+D:A mass of vegetation. As you pass near it, it reaches out tendrils to
+D:ensnare you. You can just make out skeletons of its previous victims
+D:deep within the thickets.
+
+# New monster added by furiosity for the Theme module
+N:249:Glorfindel of Rivendell
+G:h:b
+I:120:8d90:20:70:10
+W:25:3:1400:25000
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:10d8
+B:HIT:HURT:10d8
+B:HIT:HURT:10d8
+F:BASEANGBAND | WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:UNIQUE | MALE | FORCE_MAXHP | GOOD | CAN_SPEAK |
+F:SMART | PET | HAS_LITE | OPEN_DOOR | BASH_DOOR |
+F:DROP_CORPSE | DROP_SKELETON | MORTAL | CAN_SWIM |
+F:RES_WATE | RES_NETH | IM_COLD | IM_ACID | IM_POIS |
+S:1_IN_2 |
+S:ARROW_4 | S_KIN |
+D:A fair Elf in a travel cloak, wielding a longbow and short sword.
+D:Stately and graceful, he rides his steed Asfaloth with great speed.
+D:It is rumoured that he is none other but Glorfindel of Gondolin, who
+D:has been sent back from the halls of Mandos to serve the Free People
+D:of Middle-earth in this time of darkness and sorrow.
+
+N:250:Giant white dragonfly
+G:F:w
+I:110:3d8:12:20:50
+W:14:2:150:60
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:COLD:1d6
+F:FORCE_SLEEP | WILD_TOO | WILD_WASTE |
+F:RAND_50 | CAN_FLY | SUSCEP_FIRE |
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_COLD |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_COLD
+D:It is a large dragonfly that drips frost.
+
+N:251:Snaga sapper
+G:o:o
+I:111:8d8:20:32:30
+W:14:1:80:15
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:EXPLODE:HURT:20d2
+F:MALE |
+F:WILD_TOO | SUSCEP_FIRE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | HURT_LITE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is one of the many weaker 'slave' orcs, often mistakenly called a
+D:goblin. He is equipped with an explosive charge.
+
+# New monster added by furiosity for the Theme module
+# Powered-up high elf
+N:252:Finrod Felagund
+G:h:B
+I:120:50d50:20:80:10
+W:40:3:1400:1000
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:MALE | OPEN_DOOR | BASH_DOOR | UNIQUE |
+F:GOOD | DROP_SKELETON | DROP_CORPSE | SMART | PET |
+F:IM_ACID | IM_COLD | RES_WATE | RES_NETH |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:S_KIN
+D:The eldest son of Finarfin and brother to Galadriel, who founded
+D:Minas Tirith in the Pass of Sirion, and delved his citadel at
+D:Nargothrond on the River Narog. He went with Beren on the Quest
+D:of the Silmaril, and was lost in the pits of Sauron on Tol-in-Gaurhoth.
+D:His spirit tarried at the Halls of Waiting, and he was allowed to return
+D:to Middle-earth in this time of strife.
+
+N:253:Gibbering mouther
+G:j:R
+I:110:8d6:15:20:20
+W:14:4:2600:20
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:POISON:1d4
+F:NEVER_MOVE | EVIL | CAN_SWIM |
+F:IM_POIS | EMPTY_MIND | NO_FEAR | BASEANGBAND | NO_CUT
+S:MULTIPLY |
+S:1_IN_7 |
+S:SCARE | CONF | BR_LITE
+D:A chaotic mass of pulsating flesh, mouths and eyes.
+
+# New monster added by furiosity for the Theme module
+N:254:Maedhros the Tall
+G:h:u
+I:120:60d25:20:80:10
+W:45:10:2300:2500
+E:1:1:1:1:1:1
+O:20:80:0:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | KILL_BODY | FORCE_MAXHP |
+F:DROP_SKELETON | DROP_CORPSE | UNIQUE | SMART | DROP_4D2 |
+F:MORTAL | BASEANGBAND | HAS_LITE | DROP_GREAT | WILD_TOO | WILD_GRASS |
+S:1_IN_4 | HASTE | SCARE |
+D:The eldest of the Seven Sons of Feanor, and considered to be their
+D:leader. In Valinor he swore the Oath of Feanor, and followed his
+D:father back to Middle-earth. After Feanor's death, Morgoth captured
+D:Maedhros through trickery, and hung him by the wrist from the heights
+D:of Thangorodrim. Fingon succeeded in rescuing him, but he lost his right
+D:hand in their escape. He searches forever for the Silmarils of Feanor.
+
+N:255:Hill giant
+G:P:U
+I:110:30d15:20:45:50
+W:25:1:3500:150
+E:1:1:1:2:1:1
+O:20:50:20:5
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+F:DROP_60 | WILD_TOO | WILD_MOUNTAIN | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | MALE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A ten-foot-tall humanoid with powerful muscles.
+
+N:256:Flesh golem
+G:g:R
+I:110:12d8:12:30:10
+W:14:2:3000:50
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:EMPTY_MIND | BASH_DOOR | CAN_SWIM |
+F:IM_ELEC | IM_COLD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING |
+F:MORTAL | BASEANGBAND | NO_CUT
+D:A shambling humanoid monster with long scars.
+
+N:257:Warg
+G:C:D
+I:120:8d8:20:20:40
+W:16:2:700:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+B:BITE:HURT:1d6
+F:RAND_25 | BASH_DOOR | FRIENDS |
+F:WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | EVIL | MORTAL | BASEANGBAND
+D:It is a large wolf with eyes full of cunning. If you see
+D:one, it usually means orcs are nearby.
+
+N:258:Cheerful leprawn
+G:l:G
+I:120:2d5:8:6:6
+W:14:2:800:23
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:TOUCH:EAT_GOLD
+B:TOUCH:EAT_FOOD
+F:DROP_60 | ONLY_GOLD | RAND_50 | OPEN_DOOR | MALE |
+F:GOOD | MORTAL | BASEANGBAND | PET
+S:MULTIPLY |
+S:1_IN_6 |
+S:BLINK
+D:A merry little gnome.
+
+N:259:Giant flea
+G:I:s
+I:120:1d2:6:7:10
+W:14:3:90:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | CAN_FLY | WEIRD_MIND |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:Just looking at it makes you itchy all over.
+
+N:260:Ufthak of Cirith Ungol
+G:o:g
+I:110:34d10:20:50:20
+W:14:3:2600:250
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_COLD | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A strong orc guarding the pass of Cirith Ungol. He is mortally afraid of
+D:spiders: he was captured by Shelob once, but escaped when she forgot
+D:completely about him.
+
+N:261:Clay golem
+G:g:U
+I:110:14d8:12:30:10
+W:15:2:3200:60
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a massive animated statue made out of hardened clay.
+
+N:262:Black ogre
+G:O:D
+I:110:20d9:20:33:30
+W:15:2:2300:70
+E:1:1:1:2:1:1
+O:0:70:0:15
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+F:RAND_25 | WILD_TOO | WILD_MOUNTAIN | DROP_CORPSE |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A massive orc-like figure with black skin and powerful arms.
+
+# New monster added by furiosity for the Theme module
+N:263:Maglor the Mighty Singer
+G:h:g
+I:120:60d25:20:80:10
+W:45:10:2300:2500
+E:1:1:1:2:1:1
+O:0:20:80:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | KILL_BODY | FORCE_MAXHP |
+F:DROP_SKELETON | DROP_CORPSE | UNIQUE | SMART | DROP_4D2 |
+F:MORTAL | BASEANGBAND | HAS_LITE | DROP_GREAT | WILD_TOO | WILD_GRASS |
+S:1_IN_3 |
+S:HEAL | SCARE | CAUSE_2 | HOLD | CONF | S_ANIMALS |
+D:The second son of Feanor, who inherited more of his mother Nerdanel's
+D:gentle spirit than any of his brothers. Maglor was famed as a poet and
+D:bard, but he took the Oath of Feanor in Tirion and shared in the woes
+D:that came of it. He searches forever for the Silmarils of Feanor.
+
+N:264:Half-orc
+G:o:s
+I:110:16d10:20:40:20
+W:15:2:1700:50
+E:1:1:1:2:1:1
+O:30:30:30:5
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:MALE | WILD_TOO |
+F:FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | ORC | MORTAL | BASEANGBAND | HAS_LITE
+D:He is a hideous deformed cross-breed with man and orc, combining man's
+D:strength and cunning with orcish evil. The Dunlendings fighting on
+D:Saruman's side were first noted to mix their blood with the orcs.
+
+N:265:Dark naga
+G:n:s
+I:110:22d11:60:65:60
+W:15:2:1900:90
+E:0:0:0:0:1:0
+O:0:0:80:20
+B:STING:HURT:1d10
+B:BITE:HURT:1d10
+F:FEMALE |
+F:RAND_25 | DROP_60 | DROP_1D2 | IM_POIS | IM_COLD | RES_WATE |
+F:OPEN_DOOR | BASH_DOOR | EMPTY_MIND | CAN_SWIM | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND
+S:1_IN_8
+S:HOLD | CONF | BO_COLD | HEAL | DARKNESS
+D:A giant snake-like figure with a woman's torso, talented in magic.
+
+N:266:Poison ivy
+G:#:g
+I:100:5d5:5:5:5
+W:10:4:50:10
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:POISON:2d2
+B:HIT:POISON:2d2
+F:FORCE_SLEEP | NEVER_MOVE | STUPID | EMPTY_MIND | FRIENDS |
+F:KILL_TREES | SUSCEP_FIRE | ANIMAL |
+F:WILD_ONLY | COLD_BLOOD | WILD_WOOD | WILD_GRASS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | MORTAL | BASEANGBAND | DROP_60 | NO_CUT
+S:MULTIPLY
+D:A mass of vegetation. It seems to be growing.
+
+N:267:Magic mushroom patch
+G:,:B
+I:140:1d1:40:10:0
+W:15:2:50:10
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:CONFUSE
+B:SPORE:CONFUSE
+B:SPORE:HALLU
+B:SPORE:HALLU
+F:FORCE_SLEEP | NEVER_MOVE |
+F:STUPID | RES_TELE | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:BLINK | SLOW | SCARE | DARKNESS
+D:Yum! It looks quite tasty. It seems to glow with an unusual light.
+
+# New monster added by furiosity for the Theme module
+N:268:Celegorm the Fair
+G:h:o
+I:120:60d25:20:80:10
+W:45:10:2300:2500
+E:1:1:1:2:1:1
+O:0:20:80:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | KILL_BODY | FORCE_MAXHP |
+F:DROP_SKELETON | DROP_CORPSE | UNIQUE | SMART | DROP_4D2 |
+F:MORTAL | BASEANGBAND | HAS_LITE | DROP_GREAT | WILD_TOO | WILD_GRASS |
+S:1_IN_3 |
+S:S_MONSTER | S_ANIMAL | S_KIN | S_MONSTERS | S_ANIMALS | S_KIN |
+D:Celegorm the Fair was the third of the seven sons of Feanor.
+D:The most ambitious of the seven, he followed the oath of his father
+D:with the greatest ardour. He searches forever for the Silmarils.
+
+N:269:Guardian naga
+G:n:y
+I:110:24d11:20:65:120
+W:15:2:1900:80
+E:0:0:0:0:1:0
+O:0:0:80:20
+B:CRUSH:HURT:2d8
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+F:FEMALE |
+F:RAND_25 | DROP_60 | DROP_1D2 | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:EVIL
+F:MORTAL | BASEANGBAND
+D:A giant snake-like figure with a woman's torso.
+
+N:270:Wererat
+G:r:D
+I:110:20d8:10:10:10
+W:15:2:30:55
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:2d6
+F:FORCE_SLEEP |
+F:ONLY_GOLD | DROP_60 | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | EVIL
+F:MORTAL | BASEANGBAND
+S:1_IN_9 |
+S:BLINK | CAUSE_2 | BO_COLD | BA_POIS | S_KIN
+D:A large rat with glowing red eyes, which can also assume human form.
+D:It is a disgusting creature, relishing in filth and disease.
+
+N:271:Light hound
+G:Z:o
+I:110:6d6:30:30:0
+W:15:1:600:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:HURT:1d6
+F:FORCE_SLEEP | DROP_CORPSE |
+F:FRIENDS |
+F:BASH_DOOR |
+F:ANIMAL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BR_LITE
+D:A brilliant canine form whose light hurts your eyes, even at this distance.
+
+N:272:Dark hound
+G:Z:D
+I:110:6d6:30:30:0
+W:15:1:600:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:HURT:1d6
+F:FORCE_SLEEP | DROP_CORPSE |
+F:FRIENDS |
+F:BASH_DOOR | HURT_LITE |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_DARK
+D:A hole in the air in the shape of a huge hound. No light falls upon its
+D:form.
+
+N:273:Flying skull
+G:s:s
+I:110:10d10:30:30:20
+W:15:3:500:50
+E:0:0:0:0:1:0
+O:90:0:10:0
+B:BITE:POISON:1d3
+B:BITE:LOSE_STR:1d4
+F:UNDEAD | EVIL | IM_POIS | IM_COLD | WEIRD_MIND | NO_FEAR | CAN_FLY |
+F:NO_CONF | NO_SLEEP | DROP_60 | BASH_DOOR | FRIENDS | COLD_BLOOD |
+F:BASEANGBAND | NO_CUT
+D:A skull animated by necromantic spells. You'll seldom catch one alone.
+
+# New monster added by furiosity for the Theme module
+N:274:Caranthir the Dark
+G:h:D
+I:120:60d25:20:80:0
+W:45:10:2300:2500
+E:1:1:1:2:1:1
+O:0:20:80:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:TOUCH:EAT_ITEM:10d10
+F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | KILL_BODY | FORCE_MAXHP |
+F:DROP_SKELETON | DROP_CORPSE | UNIQUE | SMART | DROP_4D2 |
+F:MORTAL | BASEANGBAND | HAS_LITE | DROP_GREAT | WILD_TOO | WILD_GRASS |
+S:1_IN_3 |
+S:TRAPS | CONF | SCARE |
+D:The fourth son of Feanor, who turned on his own kind because of the
+D:Oath of his father. He searches forever for the Silmarils of Feanor.
+
+N:275:Giant tarantula
+G:S:o
+I:120:10d15:8:32:80
+W:15:3:1100:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | SPIDER | IM_POIS | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:A giant spider with hairy black and red legs.
+
+# New monster added by furiosity for the Theme module
+N:276:Curufin the Crafty
+G:h:y
+I:120:60d25:20:80:10
+W:45:10:2300:2500
+E:1:1:1:2:1:1
+O:0:80:0:20
+B:HIT:HURT:10d10
+B:HIT:EAT_ITEM:10d10
+B:HIT:EAT_ITEM:10d10
+B:HIT:EAT_ITEM:10d10
+F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | KILL_BODY | FORCE_MAXHP |
+F:DROP_SKELETON | DROP_CORPSE | UNIQUE | SMART | DROP_4D2 |
+F:MORTAL | BASEANGBAND | HAS_LITE | DROP_GREAT | WILD_TOO | WILD_GRASS |
+S:1_IN_3 |
+S:TELE_TO | TELE_AWAY | TPORT | BLINK | TRAPS |
+D:The fifth son of Feanor, closely associated with his elder
+D:brother Celegorm. Bound by the Oath of Feanor, he searches
+D:forever for the Silmarils.
+
+N:277:Mirkwood spider
+G:S:G
+I:120:9d8:15:25:80
+W:15:2:1200:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+F:FRIENDS | WILD_TOO | WILD_WOOD |
+F:WEIRD_MIND | BASH_DOOR | HURT_LITE |
+F:ANIMAL | SPIDER | EVIL | IM_POIS | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:A strong and powerful spider from Mirkwood forest. Cunning and evil, it
+D:seeks to taste your juicy insides.
+
+N:278:Frost giant
+G:P:w
+I:110:32d15:20:50:50
+W:28:1:4000:180
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:COLD:5d8
+B:HIT:COLD:5d8
+F:DROP_60 | WILD_TOO | WILD_WASTE | WILD_MOUNTAIN |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | GIANT | MALE | AURA_COLD | SUSCEP_FIRE |
+F:IM_COLD | BASEANGBAND | HAS_LITE | MORTAL
+D:A twelve-foot-tall giant covered in furs.
+
+N:279:Griffon
+G:H:u
+I:110:30d8:12:15:10
+W:15:1:2500:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:HIT:HURT:3d4
+B:BITE:HURT:2d6
+F:BASH_DOOR | CAN_FLY | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | WILD_GRASS |
+F:ANIMAL | DROP_CORPSE | MORTAL | BASEANGBAND
+D:It is half lion, half eagle. It flies menacingly towards you.
+
+N:280:Aewrog
+G:u:y
+I:110:8d8:20:32:30
+W:15:3:100:40
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:PARALYZE:1d2
+B:HIT:HURT:1d10
+F:OPEN_DOOR | BASH_DOOR | NONLIVING | CAN_FLY |
+F:EVIL | DEMON | IM_FIRE | NO_FEAR | BASEANGBAND | HAS_LITE
+S:1_IN_50 |
+S:BR_NETH
+D:A minor demonic servant of evil. It resembles a bird - in fact,
+D:the Aewroeg are the result of the corruption of smaller birds by Morgoth.
+
+N:281:Gnome mage
+G:l:R
+I:110:7d8:20:20:20
+W:15:2:900:40
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:HIT:HURT:1d5
+F:MALE |
+F:FORCE_SLEEP | FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLINK | DARKNESS | BO_COLD |
+S:S_MONSTER
+D:A mage of short stature.
+
+N:282:Clear hound
+G:Z:B
+I:110:6d6:30:30:0
+W:15:1:600:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d6
+B:CLAW:HURT:1d6
+B:BITE:HURT:1d8
+F:ATTR_CLEAR |
+F:FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:INVISIBLE | BASH_DOOR |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A faint sense of motion in the air, hound-shaped, stands before you.
+
+N:283:Umber hulk
+G:X:U
+I:110:20d10:20:50:10
+W:16:1:5000:75
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:HURT:2d6
+F:EMPTY_MIND | COLD_BLOOD |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL |
+F:IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock.
+
+N:284:Rust monster
+G:q:o
+I:110:20d15:12:55:10
+W:16:2:900:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:STUPID | WEIRD_MIND | KILL_ITEM |
+F:IM_ACID | IM_POIS | DROP_CORPSE |
+F:NO_CONF |
+F:MORTAL | BASEANGBAND
+D:It is a weird, small animal with two antennae popping forth from
+D:its forehead. It looks hungry.
+
+N:285:Ogrillon
+G:O:w
+I:110:22d9:20:33:30
+W:16:2:2400:75
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:2d10
+B:HIT:HURT:2d10
+F:FRIENDS | DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | ORC |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:An unnatural hybrid of ogre and orc.
+
+N:286:Gelatinous cube
+G:j:G
+I:110:36d10:12:18:1
+W:16:4:40000:80
+E:0:0:0:0:0:0
+O:40:30:20:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:FORCE_MAXHP |
+F:DROP_1D2 | DROP_4D2 |
+F:STUPID | EMPTY_MIND | COLD_BLOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange, vast gelatinous structure that assumes cubic proportions
+D:as it lines all four walls of the corridors it patrols. Through its
+D:transparent jelly structure you can see treasures it has engulfed, and a
+D:few corpses as well.
+
+N:287:Giant green dragonfly
+G:F:G
+I:110:3d8:12:20:50
+W:16:2:150:65
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 | WILD_TOO | WILD_SWAMP |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY |
+F:ANIMAL | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_POIS
+D:A large, foul-smelling dragonfly.
+
+N:288:Fire giant
+G:P:r
+I:110:34d16:20:60:50
+W:30:1:5000:220
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:FIRE:6d8
+B:HIT:FIRE:6d8
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_VOLCANO | SUSCEP_COLD |
+F:EVIL | GIANT | MALE | AURA_FIRE | DROP_SKELETON | DROP_CORPSE |
+F:IM_FIRE | BASEANGBAND | HAS_LITE | MORTAL
+D:A glowing fourteen-foot-tall giant. Flames surround his red skin.
+
+N:289:Hummerhorn
+G:I:y
+I:120:2d2:8:14:10
+W:16:4:100:4
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:CONFUSE:2d2
+F:RAND_50 | RAND_25 | CAN_FLY | WILD_TOO |
+F:WEIRD_MIND | ANIMAL | BASEANGBAND
+S:MULTIPLY
+D:A giant buzzing wasp, its stinger drips venom.
+
+N:290:Lizard man
+G:l:g
+I:110:16d10:20:40:20
+W:16:3:1300:55
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:4d4
+B:HIT:HURT:4d4
+F:MALE | CAN_SWIM | IM_ACID |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_SHORE |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON
+F:EVIL
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:Intelligent lizard being from the depths.
+
+N:291:Ulfast, Son of Ulfang
+G:p:U
+I:110:37d10:20:40:40
+W:16:3:1700:200
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:UNIQUE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:MALE |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:A short and swarthy Easterling. He professed to follow
+D:Caranthir, but turned on the Sons of Feanor, and so
+D:brought about their defeat.
+
+N:292:Crebain
+G:B:D
+I:120:3d5:40:12:0
+W:16:4:500:20
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+F:ANIMAL | EVIL | MORTAL | FRIENDS | BASEANGBAND | DROP_CORPSE | HAS_EGG |
+F:WILD_TOO | WILD_WASTE | WILD_MOUNTAIN | WILD_WOOD | WILD_VOLCANO |
+F:WILD_GRASS | WILD_SWAMP | WILD_SHORE | WILD_OCEAN | CAN_FLY | AQUATIC
+S:1_IN_8 | SHRIEK
+D:A type of crow, specially bred by the forces of evil as spies; their
+D:rudimentary intelligence guided by an evil mind has tracked you down,
+D:and now they seek to alert other evil creatures to your presence.
+
+N:293:Berserker
+G:p:u
+I:120:60d25:20:80:10
+W:45:2:2300:2500
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:7d7
+B:HIT:HURT:7d7
+B:HIT:HURT:7d7
+F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | KILL_BODY | FORCE_MAXHP |
+F:DROP_SKELETON | DROP_CORPSE
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 | HASTE | SCARE
+D:He can drive himself into such a terrible battle-frenzy that he
+D:can survive blows which should kill him, and still apparently feel
+D:no pain. He tramples weaker creatures underfoot in his eagerness
+D:to get to his real enemy, and his battle-cry strikes terror into
+D:his foes.
+
+N:294:Draugrog
+G:u:o
+I:110:6d8:20:30:20
+W:16:2:500:50
+E:1:1:1:2:1:1
+O:0:50:30:10
+B:BITE:LOSE_DEX:1d6
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+F:FORCE_SLEEP |
+F:RAND_25 |
+F:ONLY_ITEM | DROP_1D2 |
+F:SMART | INVISIBLE | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | NONLIVING | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BLINK | TPORT | TELE_TO | TELE_LEVEL | BLIND | CONF | SCARE
+D:Draugroeg are doglike demons, dogs corrupted by Morgoth.
+
+N:295:Sphinx
+G:H:G
+I:110:60d5:20:60:20
+W:17:2:6000:80
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+F:FORCE_SLEEP |
+F:ONLY_GOLD | DROP_1D2 | CAN_FLY | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_11 |
+S:SCARE | CONF
+D:It will eat you if you cannot answer its riddle.
+D:Unfortunately, you do not understand the language
+D:it speaks.
+
+N:296:Narrog
+G:u:g
+I:110:6d8:20:30:20
+W:17:2:400:55
+E:0:1:1:0:1:0
+O:30:20:50:0
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+F:FORCE_SLEEP | CAN_FLY |
+F:RAND_25 |
+F:ONLY_ITEM | DROP_1D2 |
+F:SMART | INVISIBLE | COLD_BLOOD | BASH_DOOR |
+F:EVIL | DEMON | IM_FIRE | RES_TELE | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BLINK | TPORT | TELE_TO | TELE_LEVEL | BLIND | CONF | SCARE | BO_FIRE
+D:A minor demonic servant of evil. It resembles a rat - in fact,
+D:the Narroeg are the result of the corruption of rats by Morgoth.
+
+N:297:Forest troll
+G:T:g
+I:110:20d10:20:50:40
+W:17:1:3000:70
+E:1:1:1:2:1:1
+O:30:70:0:0
+B:HIT:HURT:1d4
+B:HIT:HURT:1d4
+B:BITE:HURT:1d6
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_WOOD | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE | REGENERATE |
+F:EVIL | TROLL | HURT_LITE | BASEANGBAND
+D:Trolls were made by Melkor Bauglir in mockery of the Ents. This one
+D:is green-skinned and very ugly.
+
+N:298:Freezing sphere
+G:*:w
+I:120:6d6:100:30:0
+W:17:1:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:COLD:8d8
+F:FORCE_SLEEP | CAN_FLY | SUSCEP_FIRE | RAND_50 | RAND_25 |
+F:EMPTY_MIND | AURA_COLD |
+F:IM_COLD | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+D:A semi-sentient snowball, hurling itself at targets at random.
+
+N:299:Jumping fireball
+G:*:r
+I:120:6d6:100:30:0
+W:17:1:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:FIRE:8d8
+F:FORCE_SLEEP | CAN_FLY | SUSCEP_COLD |
+F:EMPTY_MIND | AURA_FIRE | RAND_50 | RAND_25 |
+F:IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+D:A semi-sentient fireball that moves around randomly.
+
+N:300:Ball lightning
+G:*:B
+I:120:6d6:100:30:0
+W:17:1:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:ELEC:8d8
+F:FORCE_SLEEP | CAN_FLY | RAND_25 | RAND_50 |
+F:EMPTY_MIND | AURA_ELEC |
+F:IM_ELEC | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | HAS_LITE |NO_CUT
+D:A crackling ball of energy, zooming about seemingly at random.
+
+N:301:2-headed hydra
+G:M:u
+I:110:100d3:20:60:20
+W:17:2:4000:80
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:ONLY_GOLD | DROP_1D2 | CAN_SWIM | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | HAS_EGG | IMPRESED |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_11 |
+S:SCARE
+D:A strange reptilian creature with two heads, guarding its hoard.
+
+N:302:Swamp thing
+G:H:g
+I:110:8d12:20:60:30
+W:17:2:2000:80
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:TERRIFY:2d5
+B:CLAW:TERRIFY:5d2
+F:CAN_SWIM | OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_SWAMP
+F:MORTAL | BASEANGBAND
+D:A creature that was once human, but is now as green as moss.
+
+N:303:Water spirit
+G:E:b
+I:120:9d8:12:28:40
+W:17:2:0:58
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:RAND_25 |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_POIS | IM_ACID | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A whirlpool of sentient liquid.
+
+N:304:Giant red scorpion
+G:S:r
+I:110:11d8:12:44:20
+W:17:1:1000:62
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d4
+B:STING:LOSE_STR:1d7
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:It is fast and poisonous.
+
+N:305:Earth spirit
+G:E:u
+I:120:13d8:10:40:50
+W:17:2:0:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:RAND_25 |
+F:EMPTY_MIND | COLD_BLOOD |
+F:PASS_WALL | CAN_FLY |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A whirling form of sentient rock.
+
+N:306:Fire spirit
+G:E:r
+I:120:10d9:16:30:20
+W:18:2:0:75
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:FIRE:2d6
+B:HIT:FIRE:2d6
+F:RAND_25 |
+F:EMPTY_MIND | BASH_DOOR | CAN_FLY | SUSCEP_COLD |
+F:IM_FIRE | IM_POIS | WILD_TOO | WILD_VOLCANO |
+F:NO_CONF | NO_SLEEP | NO_FEAR | AURA_FIRE | BASEANGBAND | HAS_LITE | NO_CUT
+D:A whirlwind of sentient flame.
+
+N:307:Fire hound
+G:Z:r
+I:110:10d6:30:30:0
+W:18:1:600:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:FIRE:2d6
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | SUSCEP_COLD |
+F:ANIMAL | IM_FIRE | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BR_FIRE
+D:Flames lick at its feet and its tongue is a blade of fire. You can feel a
+D:furnace heat radiating from this creature.
+
+N:308:Cold hound
+G:Z:w
+I:110:10d6:30:30:0
+W:18:1:600:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:COLD:2d6
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | IM_COLD | SUSCEP_FIRE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_COLD
+D:A hound as tall as a man, this creature appears to be composed of angular
+D:planes of ice. Cold radiates from it and freezes your breath in the air.
+
+N:309:Energy hound
+G:Z:b
+I:110:10d6:30:30:0
+W:18:1:600:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:ELEC:2d6
+F:FORCE_SLEEP |
+F:FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | IM_ELEC |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BR_ELEC
+D:An aura of lightning forms a ghostly halo around this hound, and
+D:sparks sting your fingers as energy builds up in the air around you.
+
+N:310:Lesser mimic
+G:m:y
+I:110:10d10:25:30:250
+W:18:3:100:60
+E:0:0:0:0:0:0
+O:10:10:10:10
+B:HIT:POISON:3d4
+B:HIT:HURT:2d3
+B:HIT:HURT:2d3
+F:MIMIC |
+F:FORCE_SLEEP | NEVER_MOVE | SUSCEP_COLD |
+F:EMPTY_MIND | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BLIND | CONF | SCARE | CAUSE_2 | BO_COLD
+D:A strange creature that disguises itself as some object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:311:Door mimic
+G:+:U
+I:110:10d10:25:30:0
+W:18:6:100:70
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:POISON:3d4
+B:HIT:CONFUSE:2d3
+B:HIT:PARALYZE:2d3
+F:CHAR_MULTI |
+F:FORCE_SLEEP | NEVER_MOVE |
+F:EMPTY_MIND | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BLIND | CONF | SCARE | CAUSE_2 | BO_COLD
+D:A strange creature that disguises itself as a door to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:312:Blink dog
+G:C:B
+I:120:8d8:20:20:10
+W:18:2:400:50
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+F:RAND_25 | FRIENDS | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | RES_TELE | MORTAL | BASEANGBAND
+S:1_IN_4 | BLINK | TELE_TO
+D:A strange magical member of the canine race, its form seems to shimmer and
+D:fade in front of your very eyes.
+
+N:313:Uruk
+G:o:B
+I:110:8d10:20:50:20
+W:16:1:2300:60
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:MALE |
+F:FORCE_MAXHP | FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:ARROW_2
+D:It is a cunning orc of power, as tall as a man, and stronger. It fears
+D:little. His armour bears the mark of Saruman - a large white hand.
+
+N:314:Shagrat, the Orc Captain
+G:o:g
+I:110:42d10:20:60:20
+W:19:2:2600:400
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d9
+B:HIT:HURT:3d9
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | SPECIAL_GENE
+F:ESCORT | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He has power and great cunning, as leader of the garrison at Cirith Ungol.
+D:He is a large Uruk with an evil face, protruding fangs and long arms.
+
+N:315:Gorbag, the Orc Captain
+G:o:g
+I:110:42d10:20:60:20
+W:19:2:2600:400
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d9
+B:HIT:HURT:3d9
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP |
+F:ESCORT | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is an orc of power and great cunning, leader of the garrison at Minas Morgul.
+
+N:316:Shambling mound
+G:,:g
+I:110:20d6:20:16:40
+W:18:2:3000:75
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:ONLY_GOLD | DROP_90 | WILD_TOO | WILD_SWAMP |
+F:STUPID | EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:SHRIEK
+D:A pile of rotting vegetation that slides towards you with a disgusting
+D:stench, waking all it nears.
+
+N:317:Venus Flytrap
+G:#:g
+I:120:10d10:20:5:0
+W:15:5:200:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:PARALYZE:3d3
+B:HIT:PARALYZE:3d3
+B:HIT:PARALYZE:3d3
+F:NEVER_MOVE | EMPTY_MIND | STUPID | CHAR_CLEAR | CHAR_MULTI | BASEANGBAND |
+F:WILD_ONLY | WILD_WOOD | WILD_SWAMP | ANIMAL | SUSCEP_FIRE | NO_CUT
+D:A carnivorous plant that is difficult to detect, until it suddenly snaps shut
+D:around its prey and releases paralysing enzymes to stop its struggles.
+
+# New monster added by furiosity for the Theme module
+N:318:Amrod, Son of Feanor
+G:h:W
+I:120:60d25:20:80:10
+W:45:10:2300:2500
+E:1:1:1:2:1:1
+O:0:80:0:20
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | KILL_BODY | FORCE_MAXHP |
+F:DROP_SKELETON | DROP_CORPSE | UNIQUE | SMART | DROP_4D2 |
+F:MORTAL | BASEANGBAND | HAS_LITE | DROP_GREAT | WILD_TOO | WILD_GRASS |
+S:1_IN_3 |
+S:ARROW_1 | ARROW_2 | ARROW_3 | ARROW_4 | MISSILE
+D:The youngest son of Feanor along with his twin brother Amras.
+D:He is bound by the Oath of Feanor and searches forever for the
+D:Silmarils.
+
+# New monster added by furiosity for the Theme module
+N:319:Amras, Son of Feanor
+G:h:w
+I:120:60d25:20:80:10
+W:45:10:2300:2500
+E:1:1:1:2:1:1
+O:0:80:0:20
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | KILL_BODY | FORCE_MAXHP |
+F:DROP_SKELETON | DROP_CORPSE | UNIQUE | SMART | DROP_4D2 |
+F:MORTAL | BASEANGBAND | HAS_LITE | DROP_GREAT | WILD_TOO | WILD_GRASS |
+S:1_IN_3 |
+S:ARROW_1 | ARROW_2 | ARROW_3 | ARROW_4 | MISSILE |
+S:TPORT | BLINK | TELE_TO | TELE_AWAY | S_MONSTER
+D:The youngest son of Feanor along with his twin brother Amrod.
+D:He is bound by the Oath of Feanor and searches forever for the
+D:Silmarils.
+
+N:320:Giant bronze dragonfly
+G:F:U
+I:120:3d8:12:20:50
+W:18:2:150:80
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:CONFUSE:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 | CAN_FLY |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_CONF
+D:This gleaming dragonfly's wings beat mesmerizingly fast.
+
+N:321:Stone giant
+G:P:W
+I:110:35d18:20:75:50
+W:33:1:7000:250
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:DROP_60 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | GIANT | MALE | WILD_TOO | WILD_MOUNTAIN | BASEANGBAND | HAS_LITE
+D:He is eighteen feet tall and looking at you.
+
+N:322:Giant black dragonfly
+G:F:s
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ACID:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | IM_ACID |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_ACID
+D:The size of a large bird, this dragonfly drips caustic acid.
+
+N:323:Stone golem
+G:g:W
+I:100:28d8:12:75:10
+W:19:2:3500:100
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+F:COLD_BLOOD | EMPTY_MIND | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+D:It is a massive animated statue of hard stone.
+
+N:324:Red mold
+G:m:r
+I:110:17d8:2:16:70
+W:19:1:40:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:FIRE:4d4
+F:NEVER_MOVE | SUSCEP_COLD |
+F:STUPID | EMPTY_MIND |
+F:IM_FIRE | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange growth on the dungeon floor, glowing red.
+
+N:325:Giant gold dragonfly
+G:F:y
+I:120:3d8:12:20:50
+W:22:2:150:75
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 | WILD_TOO | WILD_MOUNTAIN |
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_FIRE | CAN_FLY |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_SOUN
+D:Large beating wings support this dazzling insect. A loud buzzing noise
+D:pervades the air.
+
+# New monster added by furiosity for the Theme module
+# Anti-Naugladur
+N:326:Telchar the Smith
+G:k:w
+I:110:20d100:30:200:200
+W:70:1:0:12000
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | SMART | PET |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_GREAT
+F:OPEN_DOOR | BASH_DOOR
+F:GOOD | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
+D:A Dwarf of Nogrod in the Blue Mountains, and one of the
+D:greatest smiths in the history of Middle-earth. Among his
+D:works were Angrist, Narsil, and the Dragon-helm of Dor-lómin.
+D:He is he last among the Dwarves of Nogrod to be on the
+D:side of the Light.
+
+N:327:Ghast
+G:z:u
+I:120:30d10:40:40:20
+W:30:1:1500:130
+E:1:1:1:2:1:1
+O:20:35:25:10
+B:CLAW:PARALYZE:2d4
+B:CLAW:PARALYZE:2d4
+B:BITE:LOSE_CON:2d4
+B:BITE:LOSE_CHR:2d4
+F:DROP_60 | OPEN_DOOR | BASH_DOOR | ESCORT |
+F:NO_SLEEP | NO_CONF | UNDEAD | EVIL | IM_POIS | IM_COLD |
+F:COLD_BLOOD | HURT_LITE | CAN_SWIM | BASEANGBAND | NO_CUT
+D:This vile abomination is a relative of ghouls, and often leads packs
+D:of them. It smells foul, and its bite carries a rotting disease.
+
+N:328:Neekerbreeker
+G:I:g
+I:120:3d2:8:18:10
+W:19:4:100:4
+B:BITE:POISON:2d2
+F:RAND_50 | RAND_25 | CAN_FLY | WILD_SWAMP | WILD_TOO |
+F:WEIRD_MIND | ANIMAL | EVIL | BASEANGBAND
+S:MULTIPLY |
+S:1_IN_12 |
+S:SHRIEK
+D:Believed to be an evil relative of the cricket, this creature gets its name
+D:from its incessant squeaking, which can best be described as "neek-breek,
+D:neek-breek". The noise can drive people frantic, and worse still, can be
+D:heard for quite some distance, alerting other monsters to your presence.
+
+N:329:Huorn
+G:#:g
+I:110:50d10:40:45:20
+W:19:1:4000:75
+E:0:0:0:0:0:0
+O:30:30:30:5
+B:CRUSH:HURT:3d6
+B:CRUSH:HURT:3d6
+B:CRUSH:HURT:3d6
+B:CRUSH:HURT:3d6
+F:DROP_60 | NO_SLEEP | NO_CONF | ANIMAL | WEIRD_MIND | SUSCEP_FIRE |
+F:RES_WATE | IM_COLD | NEVER_MOVE | WILD_ONLY | WILD_WOOD |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9
+S:BLINK | TELE_TO
+D:A very strong near-sentient tree, which has become hostile to other living things.
+
+N:330:Bolg, Son of Azog
+G:o:R
+I:120:52d10:20:50:20
+W:20:4:2300:800
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d7
+B:HIT:HURT:3d7
+B:HIT:HURT:3d7
+B:HIT:HURT:3d7
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | SPECIAL_GENE |
+F:ESCORT | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A large and powerful orc, he looks just like his father. He is tall and
+D:fast, and he hates all dwarves and their friends.
+
+N:331:Phase spider
+G:S:B
+I:120:6d8:15:25:80
+W:20:2:500:60
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:BITE:POISON:1d6
+B:BITE:POISON:1d6
+F:FRIENDS | WILD_TOO | WILD_WOOD | DROP_SKELETON |
+F:WEIRD_MIND | BASH_DOOR | CAN_SWIM |
+F:ANIMAL | SPIDER | IM_POIS | RES_TELE |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BLINK | TELE_TO
+D:A spider that never seems quite there. Everywhere you look it is just
+D:half-seen in the corner of one eye.
+
+N:332:Lizard king
+G:l:r
+I:120:18d11:20:40:20
+W:20:3:1600:150
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:WAIL:TERRIFY
+F:MALE | CAN_SWIM | IM_ACID | IM_POIS | WILD_SHORE |
+F:DROP_60 | DROP_1D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | FORCE_MAXHP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A leader of lizard men, coming from the depths.
+
+N:333:Landmine
+G:.:w
+I:110:6d6:30:25:10
+W:20:5:300:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:HURT:25d2
+F:CHAR_CLEAR | ATTR_CLEAR | CHAR_MULTI |
+F:NEVER_MOVE | FORCE_MAXHP |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | JOKEANGBAND | NO_CUT
+D:It was left here to be used against intruders.
+
+# New monster added by furiosity for the Theme module
+N:334:Roac, son of Carc
+G:B:W
+I:120:30d10:40:12:0
+W:0:2:500:500
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:2d4
+B:BITE:HURT:2d4
+F:BASEANGBAND | UNIQUE | MALE | CAN_SPEAK | FORCE_MAXHP | PET |
+F:WILD_ONLY | WILD_WOOD | WILD_MOUNTAIN | WILD_GRASS | WILD_WASTE |
+F:ANIMAL | CAN_FLY | DROP_CORPSE | SMART | GOOD | MORTAL |
+S:1_IN_2
+S:S_MONSTER | S_MONSTERS
+D:One of the ravens who lived on Ravenhill, one of the foothills of Erebor,
+D:the Lonely Mountain. Roac is a very ancient bird indeed: his father Carc
+D:had seen Smaug descend on the mountain, and Roac was no less than 153 years
+D:old ('out of the egg', as he put it) when Smaug was destroyed. He is a
+D:leader among the ravens and his cunning is not to be underestimated.
+
+N:335:Great eagle
+G:B:r
+I:120:100d5:20:65:20
+W:20:2:1000:150
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:6d3
+B:CLAW:HURT:6d3
+B:BITE:HURT:3d6
+F:CAN_FLY | NEUTRAL | NO_TARGET |
+F:WILD_MOUNTAIN | WILD_VOLCANO | WILD_WASTE | WILD_WOOD | WILD_ONLY |
+F:ANIMAL | GOOD | DROP_CORPSE | BASEANGBAND | IMPRESED | HAS_EGG | AQUATIC |
+D:Greater and more intelligent than most of its kind, this eagle is
+D:a messenger between the forces of good. It answers to Manwe Sulimo.
+
+N:336:Livingstone
+G:#:W
+I:110:6d8:45:28:20
+W:20:4:1000:56
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d5
+B:HIT:HURT:2d5
+F:NEVER_MOVE | IM_COLD | COLD_BLOOD | IM_ACID | IM_ELEC | NO_FEAR |
+F:IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | FRIENDS | CHAR_MULTI | HURT_ROCK |
+F:BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:A sentient section of wall.
+
+N:337:Earth hound
+G:Z:u
+I:110:15d8:30:30:0
+W:20:1:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP |
+F:FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_10 |
+S:BR_SHAR
+D:A beautiful crystalline shape does not disguise the danger this hound
+D:clearly presents. Your flesh tingles as it approaches.
+
+N:338:Air hound
+G:Z:g
+I:110:15d8:30:30:0
+W:20:1:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d8
+B:BITE:POISON:1d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP |
+F:FRIENDS | CAN_FLY |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_POIS
+D:Swirling vapours surround this beast as it floats towards you, seemingly
+D:walking on air. Noxious gases sting your throat.
+
+N:339:Sabre-tooth tiger
+G:f:y
+I:120:20d14:40:50:0
+W:20:2:1800:120
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d10
+B:CLAW:HURT:1d10
+B:BITE:HURT:1d10
+B:BITE:HURT:1d10
+F:BASH_DOOR | WILD_WOOD | WILD_TOO | WILD_GRASS |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE
+F:MORTAL | BASEANGBAND
+D:A fierce and dangerous cat, its huge tusks and sharp claws would lacerate
+D:even the strongest armour.
+
+N:340:Acid hound
+G:Z:s
+I:110:15d8:30:30:0
+W:20:1:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ACID:1d8
+B:BITE:ACID:1d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | CAN_SWIM | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | IM_ACID | MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_ACID
+D:Footprints are burned in the ground behind this hound as it pads
+D:around the dungeon. An acrid smell of acid rises from its pelt.
+
+N:341:Chimaera
+G:H:r
+I:110:20d15:12:15:10
+W:20:2:1600:200
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BUTT:HURT:2d8
+B:BITE:HURT:2d10
+B:BITE:FIRE:2d6
+F:FORCE_SLEEP | CAN_FLY | DROP_CORPSE | SUSCEP_COLD |
+F:BASH_DOOR | WILD_TOO | WILD_MOUNTAIN |
+F:IM_FIRE | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 |
+S:BR_FIRE
+D:It is a strange hybrid of goat, lion and dragon, with the heads of all
+D:three beasts.
+
+N:342:Quylthulg
+G:Q:y
+I:110:6d8:10:1:0
+W:20:1:3000:250
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | NEVER_MOVE | NEVER_BLOW
+F:EMPTY_MIND | INVISIBLE | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_4 |
+S:BLINK |
+S:S_MONSTER
+D:It is a strange pulsing mound of flesh. It looks harmless.
+
+N:343:Sasquatch
+G:Y:W
+I:120:20d19:15:40:10
+W:20:3:3500:180
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:1d10
+B:CLAW:HURT:1d10
+B:BITE:HURT:2d8
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD | WILD_WASTE |
+F:ANIMAL | IM_COLD | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A tall shaggy, furry humanoid, related to the yeti.
+
+# New monster added by furiosity for the Theme module
+N:344:Carc of Ravenhill
+G:B:W
+I:120:6d100:40:12:0
+W:0:2:500:500
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:HURT:4d8
+B:BITE:HURT:4d8
+F:BASEANGBAND | UNIQUE | MALE | CAN_SPEAK | FORCE_MAXHP | PET |
+F:WILD_ONLY | WILD_WOOD | WILD_MOUNTAIN | WILD_GRASS | WILD_WASTE |
+F:ANIMAL | CAN_FLY | DROP_CORPSE | SMART | GOOD | MORTAL |
+S:1_IN_2
+S:S_ANIMAL | S_ANIMALS
+D:One of the ravens who lived on Ravenhill, one of the foothills of Erebor,
+D:the Lonely Mountain. Carc seems to have been the chief of those birds,
+D:and dwelt with his wife above the Dwarves' guard-chamber on the hill.
+D:He is a wise old bird who knows what is best for his folk and Arda.
+
+N:345:Ranger
+G:p:W
+I:110:15d11:20:40:40
+W:20:1:1700:55
+E:1:1:1:2:1:1
+O:20:50:20:0
+B:HIT:HURT:5d4
+B:HIT:HURT:5d4
+F:MALE |
+F:DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:DROP_SKELETON | DROP_CORPSE | BASEANGBAND | MORTAL | HAS_LITE
+S:1_IN_4 |
+S:ARROW_2 | MISSILE | BO_COLD | BO_ELEC | BLINK | S_ANIMAL
+D:A warrior who is at one with nature. A master of both bow and sword, with
+D:minor spellcasting skills.
+
+N:346:Paladin
+G:p:w
+I:110:15d11:20:40:40
+W:20:1:1700:55
+E:1:1:1:2:1:1
+O:20:60:0:10
+B:HIT:HURT:4d5
+B:HIT:HURT:4d5
+F:MALE | GOOD | DROP_SKELETON | DROP_CORPSE |
+F:DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:BASEANGBAND | MORTAL | HAS_LITE
+S:1_IN_4 |
+S:HEAL | CAUSE_2 | SLOW | SCARE | BLIND
+D:A warrior devoted to Tulkas Astaldo. He considers you to be an
+D:agent of Morgoth.
+
+N:347:Werewolf
+G:C:D
+I:110:20d22:15:30:70
+W:20:2:900:150
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d10
+F:RAND_25 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON |
+F:ANIMAL | EVIL | MORTAL | BASEANGBAND
+D:It is a huge wolf with eyes that glow with manly intelligence.
+
+N:348:Dark elven lord
+G:h:D
+I:120:18d15:20:40:30
+W:20:2:1400:500
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d5
+F:MALE | FORCE_SLEEP |
+F:ONLY_ITEM | DROP_2D2 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:HASTE | BLIND | CONF | DARKNESS | BO_FIRE | BO_COLD | MISSILE
+D:A dark elven figure in armour, radiating evil power.
+
+N:349:Cloud giant
+G:P:b
+I:110:35d20:20:60:50
+W:36:1:9000:500
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:ELEC:8d8
+B:HIT:ELEC:8d8
+F:DROP_90 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | GIANT | IM_ELEC | MALE | BASEANGBAND | HAS_LITE
+D:It is a twenty-foot-tall humanoid, wreathed in clouds.
+
+N:350:Ugluk, the Uruk
+G:o:R
+I:110:72d10:20:95:20
+W:21:3:2400:600
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_FIRE | IM_COLD | IM_POIS
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A strong and cunning orc warrior, the commander of Saruman's orcish horde.
+D:He was raised on man-flesh at Isengard, and bears the mark of the White Hand.
+
+N:351:Blue dragon bat
+G:b:b
+I:130:4d4:12:26:50
+W:21:1:100:54
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:ELEC:1d3
+F:FORCE_SLEEP |
+F:RAND_50 |
+F:BASH_DOOR | CAN_FLY |
+F:ANIMAL | IM_ELEC | AI_ANNOY
+F:MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:BR_ELEC
+D:It is a glowing blue bat with a sharp tail.
+
+N:352:Mimic
+G:m:y
+I:110:10d14:30:40:0
+W:21:3:100:70
+E:0:0:0:0:0:0
+O:20:20:20:20
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+B:HIT:HURT:2d3
+B:HIT:HURT:2d3
+F:MIMIC |
+F:FORCE_SLEEP | NEVER_MOVE |
+F:EMPTY_MIND | COLD_BLOOD | SUSCEP_FIRE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BLIND | CONF | SCARE | CAUSE_2 | BO_FIRE |
+S:S_MONSTER
+D:A strange creature that disguises itself as an object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:353:Ultimate mimic
+G:m:y
+I:110:15d40:30:40:0
+W:35:4:100:250
+E:0:0:0:0:0:0
+O:25:25:25:25
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+B:BUTT:CONFUSE:4d4
+B:SPIT:BLIND:4d4
+F:MIMIC |
+F:FORCE_SLEEP | NEVER_MOVE |
+F:EMPTY_MIND | COLD_BLOOD
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BLIND | CONF | SCARE | CAUSE_2 | BA_POIS |
+S:S_MONSTER
+D:A strange creature that disguises itself as an object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+
+N:354:Fire vortex
+G:v:r
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:FIRE:3d3
+F:FORCE_SLEEP | RAND_50 | CAN_FLY | WILD_VOLCANO | WILD_TOO | SUSCEP_COLD |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | AURA_FIRE |
+F:IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | HAS_LITE
+F:NO_CUT
+S:1_IN_6 |
+S:BR_FIRE
+D:A whirling maelstrom of fire.
+
+N:355:Acid vortex
+G:v:s
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:ACID:3d3
+F:FORCE_SLEEP | RAND_50 |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | CAN_FLY |
+F:IM_ACID | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_ACID
+D:A caustic spinning whirlpool of foaming, steaming water.
+
+N:356:Lugdush, the Uruk
+G:o:R
+I:110:66d10:20:90:20
+W:21:4:2500:550
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A large and powerful orc, captain of one of Saruman's orcish regiments.
+
+# New monster added by furiosity for the Theme module
+N:357:Alatar, the Blue Wizard
+G:p:b
+I:120:49d101:101:100:0
+W:110:7:1600:35000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:8d12
+B:HIT:TERRIFY:7d7
+F:BASEANGBAND | FORCE_DEPTH | FORCE_MAXHP | FORCE_SLEEP |
+F:UNIQUE | MALE | CAN_SPEAK | PET | DROP_CORPSE |
+F:REFLECTING | RES_TELE | SMART | GOOD |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | HAS_LITE | TAKE_ITEM |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS |
+F:RES_NETH | NO_CONF | NO_SLEEP | NO_FEAR |
+S:1_IN_2 |
+S:HEAL | HASTE | TPORT | TELE_AWAY | BLIND | CONF | SCARE |
+S:CAUSE_4 | BRAIN_SMASH | FORGET | TRAPS | CAUSE_4 |
+S:BA_FIRE | BA_MANA | BO_FIRE | BO_MANA | BO_PLAS | BR_PLAS |
+S:S_MONSTERS | S_HI_DRAGON | S_KIN | S_ANIMALS |
+D:He is dressed in blue from head to toe. He is one of the five Istari
+D:who came to the northwest of Middle-earth in the Third Age; he
+D:journeyed into the east with Pallando, and never returned to the western
+D:lands. They stumbled upon a magical portal to the remnants of Utumno and
+D:could not find their way back. Alatar is still trying to continue the
+D:task the Valar have appointed him.
+
+N:358:Cold vortex
+G:v:w
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:COLD:3d3
+F:FORCE_SLEEP | RAND_50 | AURA_COLD | COLD_BLOOD | SUSCEP_FIRE |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | CAN_FLY |
+F:IM_COLD | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_COLD
+D:A twisting whirlpool of frost.
+
+N:359:Energy vortex
+G:v:b
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:ELEC:3d3
+F:FORCE_SLEEP | RAND_50 | CAN_FLY | HAS_LITE |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | AURA_ELEC |
+F:IM_ELEC | NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_ELEC
+D:A shimmering tornado of air; sparks crackle along its length.
+
+N:360:Globefish
+G:~:w
+I:110:10d10:20:30:30
+W:21:1:600:111
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:POISON:10d5
+B:BITE:POISON:10d5
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | AQUATIC |
+F:IM_POIS | NO_STUN | WILD_TOO | COLD_BLOOD |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:BR_POIS
+D:This fish is among the most poisonous creatures there are.
+
+N:361:Giant firefly
+G:I:r
+I:120:3d2:8:18:10
+W:24:4:100:4
+B:BITE:BLIND:1d2
+F:RAND_50 | RAND_25 | CAN_FLY | HAS_LITE |
+F:WEIRD_MIND | ANIMAL | BASEANGBAND
+S:MULTIPLY
+D:Clouds of these monsters light up the dungeon - so brightly that you can
+D:barely see through them.
+
+N:362:Mummified orc
+G:z:w
+I:110:15d8:20:28:75
+W:21:1:1700:56
+E:1:1:1:2:1:1
+O:10:70:0:10
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:DROP_90 |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is an orc-like figure covered in wrappings.
+
+N:363:Wolf chieftain
+G:C:g
+I:120:22d22:20:20:5
+W:26:5:1000:120
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d10
+B:WAIL:TERRIFY
+F:ESCORTS | FORCE_MAXHP | IM_COLD | IM_ACID |
+F:SMART | ESCORT | ANIMAL | EVIL | MORTAL | BASEANGBAND |
+F:OPEN_DOOR | BASH_DOOR | NO_FEAR | MALE
+S:1_IN_8 | DARKNESS
+D:A great Wolf leader whose pack is in the service of the Dark Lord,
+D:and whose howls strike fear into the boldest hearts.
+
+# New monster added by furiosity for the Theme module
+N:364:Pallando, the Blue Wizard
+G:p:b
+I:120:49d101:101:100:0
+W:120:7:1600:45000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:10d14
+B:HIT:TERRIFY:9d9
+F:BASEANGBAND | FORCE_DEPTH | FORCE_MAXHP | FORCE_SLEEP |
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:REFLECTING | RES_TELE | SMART | EVIL |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | HAS_LITE | TAKE_ITEM |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS |
+F:RES_NETH | NO_CONF | NO_SLEEP | NO_FEAR |
+S:1_IN_2 |
+S:HEAL | HASTE | TPORT | TELE_AWAY | BLIND | CONF | SCARE |
+S:CAUSE_4 | BRAIN_SMASH | FORGET | TRAPS |
+S:BA_FIRE | BA_MANA | BO_FIRE | BO_MANA | BO_PLAS | BR_PLAS |
+S:S_HI_UNDEAD | S_HI_DRAGON | S_HI_DEMON |
+D:He is dressed in blue from head to toe. He is one of the five Istari
+D:who came to the northwest of Middle-earth in the Third Age; he
+D:journeyed into the east with Alatar, and never returned to the western
+D:lands. They stumbled upon a magical portal to the remnants of Utumno and
+D:could not find their way back. Pallando has fallen into the Shadow
+D:since being in Utumno, and has designs on ruling the free people.
+
+N:365:Vampiric mist
+G:#:D
+I:110:10d8:12:55:30
+W:22:1:0:40
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:EXP_20:1d6
+B:ENGULF:EXP_20:1d6
+F:RAND_25 | SUSCEP_ELEC | UNDEAD |
+F:IM_COLD | IM_POIS | IM_ACID | RES_NETH | WILD_TOO | WILD_SWAMP |
+F:EVIL | EMPTY_MIND | COLD_BLOOD | FRIENDS | BASEANGBAND | NO_CUT
+D:A cloud of evil, sentient mist.
+
+N:366:Killer stag beetle
+G:K:g
+I:110:15d8:12:55:30
+W:22:1:500:80
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d12
+B:CLAW:HURT:1d12
+F:RAND_25 | WILD_TOO | DROP_CORPSE |
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:It is a giant beetle with vicious claws.
+
+N:367:Iron golem
+G:g:s
+I:110:80d12:12:80:10
+W:22:2:3800:160
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d12
+F:FORCE_SLEEP | SUSCEP_ACID |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:SLOW
+D:It is a massive metal statue that moves steadily towards you.
+
+N:368:Auto-roller
+G:g:s
+I:120:70d12:10:80:12
+W:22:2:0:230
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:1d8
+B:CRUSH:HURT:1d8
+B:CRUSH:HURT:1d8
+B:CRUSH:HURT:1d8
+F:FORCE_SLEEP | RES_TELE
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
+F:NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | JOKEANGBAND | NO_CUT
+D:It looks like a huge spiked roller, moving on its own towards you.
+
+N:369:Giant yellow scorpion
+G:S:y
+I:110:12d8:12:38:20
+W:22:1:1200:60
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:STING:POISON:2d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO |
+F:ANIMAL | DROP_SKELETON |
+F:MORTAL | BASEANGBAND
+D:It is a giant scorpion with a sharp stinger.
+
+# New monster added by furiosity for the Theme module
+# Powered-up Lagduf
+N:370:Muzgash, the Snaga
+G:o:o
+I:110:33d10:20:32:30
+W:22:3:1700:80
+E:1:1:1:2:1:1
+O:10:80:0:0
+B:HIT:HURT:3d11
+B:HIT:HURT:3d11
+B:HIT:HURT:3d10
+B:HIT:HURT:3d10
+F:UNIQUE | MALE | EVIL | ORC | FORCE_MAXHP | ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | SMART | CAN_SPEAK |
+F:OPEN_DOOR | BASH_DOOR | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A friend of Lagduf's, he is no less evil but more cunning.
+
+N:371:Black ooze
+G:j:D
+I:90:6d8:10:6:1
+W:23:1:400:7
+E:0:0:0:0:0:0
+O:30:0:40:15
+B:TOUCH:ACID:2d6
+F:RAND_50 | DROP_60 | STUPID | EMPTY_MIND | CAN_SWIM |
+F:TAKE_ITEM | KILL_BODY | OPEN_DOOR | BASH_DOOR |
+F:IM_POIS | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:MULTIPLY
+S:1_IN_11 |
+S:DRAIN_MANA
+D:It is a strangely moving puddle.
+
+N:372:Hardened warrior
+G:p:u
+I:110:15d11:20:40:40
+W:23:1:1900:60
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d5
+B:HIT:HURT:6d5
+F:MALE |
+F:DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:A scarred warrior who moves with confidence.
+
+N:373:Azog, King of the Uruk-Hai
+G:o:R
+I:120:94d10:20:80:20
+W:23:5:2700:1111
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:5d6
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT | ESCORTS | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A large, strong and agile orc, the slayer of dwarven king Thror.
+
+# New monster added for the Theme module
+# From UnAngband
+N:374:Bill Ferny
+G:p:b
+I:120:6d10:16:8:5
+W:5:3:180:90
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+B:HIT:EAT_GOLD:1d8
+F:BASEANGBAND | UNIQUE | MALE | FORCE_MAXHP | CAN_SPEAK |
+F:OPEN_DOOR | BASH_DOOR | HAS_LITE | SMART | EVIL |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+D:A swarthy man of Bree. He has heavy black brows and dark scornful
+D:eyes; his large mouth is curled in a sneer. He sells anything to
+D:anybody and enjoys making mischief for his personal amusement.
+
+N:375:Dark elven warlock
+G:h:v
+I:120:7d10:20:16:20
+W:23:1:1700:75
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | FRIENDS
+F:EVIL | IM_POIS | HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:CONF | MISSILE | DARKNESS | BO_MANA
+D:A dark elven mage with spells of frighteningly destructive power.
+
+N:376:Master rogue
+G:p:b
+I:120:15d9:20:30:40
+W:23:2:1600:110
+E:1:1:1:2:1:1
+O:80:10:10:0
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+B:HIT:EAT_GOLD:4d4
+F:MALE | DROP_SKELETON | DROP_CORPSE |
+F:DROP_2D2 | SUSCEP_ELEC |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+D:A thief of great power and shifty speed.
+
+N:377:Red dragon bat
+G:b:r
+I:130:3d8:12:28:50
+W:23:1:100:60
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:FIRE:1d3
+F:FORCE_SLEEP | RAND_50 | SUSCEP_COLD |
+F:BASH_DOOR | CAN_FLY | DROP_CORPSE | AI_ANNOY
+F:ANIMAL | IM_FIRE | BASEANGBAND
+S:1_IN_4 |
+S:BR_FIRE
+D:It is a sharp-tailed bat, wreathed in fire.
+
+N:378:Killer white beetle
+G:K:w
+I:110:18d8:14:55:30
+W:23:1:500:85
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:4d5
+F:RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:It is looking for prey.
+
+N:379:Ice skeleton
+G:s:w
+I:110:16d9:20:34:60
+W:23:1:0:70
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:CLAW:COLD:2d3
+B:CLAW:COLD:2d3
+F:ONLY_ITEM | DROP_90 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a skeleton covered in frost.
+
+N:380:Angamaite of Umbar
+G:p:U
+I:110:82d10:25:80:25
+W:24:2:2400:400
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:HIT:HURT:4d7
+B:HIT:HURT:4d7
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_ELEC
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:SLOW | FORGET
+D:A Black Numenorean who hates the men of the West. He is a descendant
+D:of Castamir, the Usurper of Gondor.
+
+N:381:Forest wight
+G:W:g
+I:110:12d8:20:30:30
+W:24:1:0:140
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:TOUCH:EXP_20
+F:FORCE_SLEEP | RAND_25 |
+F:DROP_60 | DROP_90 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_10 |
+S:SCARE | DRAIN_MANA
+D:It is a ghostly apparition, arisen when a humanoid was killed violently
+D:in a forest. It remembers its past life and wants revenge.
+
+N:382:Khim, Son of Mim
+G:k:o
+I:110:84d10:20:80:10
+W:24:2:2300:300
+E:1:1:1:2:1:1
+O:10:80:0:10
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d7
+B:HIT:UN_BONUS
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_FIRE | IM_COLD
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:HEAL | SLOW | BO_FIRE
+D:One of the last of the Petty-Dwarves. Khim is a tricky sorcerous little
+D:being, full of mischief.
+
+N:383:Ibun, Son of Mim
+G:k:o
+I:110:84d10:20:80:10
+W:24:2:2300:300
+E:1:1:1:2:1:1
+O:10:80:0:5
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d7
+B:HIT:UN_BONUS
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_FIRE | IM_COLD
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:HEAL | SLOW | BO_FIRE
+D:One of the last of the Petty-Dwarves. Ibun is a tricky sorcerous little
+D:being, full of mischief.
+
+N:384:Meneldor the Swift
+G:B:v
+I:140:80d10:20:65:20
+W:24:6:1200:360
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:7d3
+B:CLAW:HURT:7d3
+B:BITE:HURT:3d7
+F:CAN_FLY | UNIQUE | FORCE_MAXHP | DROP_CORPSE | CAN_SPEAK |
+F:WILD_ONLY | WILD_MOUNTAIN | WILD_VOLCANO | PET |
+F:ANIMAL | GOOD | BASEANGBAND
+D:Among all the eagles of Middle-earth he is the swiftest, and in his time
+D:has borne messages between all of the Wise. It was Meneldor who bore the
+D:Ring-bearer away from the destruction of Mount Doom.
+
+N:385:Phantom beast
+G:G:B
+I:110:12d12:20:40:40
+W:24:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d33
+B:HIT:HURT:2d44
+F:PASS_WALL | NO_SLEEP | COLD_BLOOD | NONLIVING | NO_FEAR |
+F:FORCE_MAXHP | RES_TELE | EMPTY_MIND | CAN_FLY | BASEANGBAND | NO_CUT
+D:A creature that is half real, half illusion.
+
+N:386:Giant silver ant
+G:a:W
+I:110:9d8:10:38:40
+W:23:1:800:45
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ACID:4d4
+F:RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_SKELETON |
+F:ANIMAL | MORTAL | BASEANGBAND | HAS_LITE
+D:A giant silver ant with a caustic bite.
+
+N:387:4-headed hydra
+G:M:y
+I:120:100d6:20:70:20
+W:24:2:5000:450
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+F:FORCE_SLEEP |
+F:ONLY_GOLD | DROP_4D2 | WILD_TOO | WILD_SWAMP | WILD_SHORE |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_7 |
+S:SCARE
+D:A strange reptilian creature with four heads, guarding its hoard.
+
+# New monster added by furiosity for the Theme module
+N:388:Beruthiel, Queen of Cats
+G:f:B
+I:115:7d100:100:200:10
+W:33:5:0:30000
+E:0:1:0:2:1:0
+O:30:60:0:10
+B:CLAW:HURT:8d11
+B:CLAW:EAT_LITE:8d11
+B:CLAW:LOSE_INT:8d11
+F:BASEANGBAND | WILD_TOO | WILD_WOOD | WILD_GRASS | WILD_MOUNTAIN |
+F:UNIQUE | FEMALE | CAN_SPEAK | SMART | FORCE_MAXHP | EVIL | MORTAL |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | ANIMAL | FORCE_SLEEP |
+F:HURT_LITE | IM_FIRE | IM_POIS | RES_NETH | NO_SLEEP | NO_CONF |
+S:1_IN_5
+S:S_KIN | SHRIEK | S_ANIMALS | BLINK | S_MONSTERS
+D:The dark and mournful Queen to Tarannon Falastur, the twelfth King
+D:of Gondor. She owned ten marvellous and magical cats, that she set
+D:to spy on the doings of the people of Gondor. Her scheming was her
+D:undoing, though, since her husband set her adrift on the Great Sea,
+D:with only her cats for company. She sailed into the far south and
+D:encountered a mysterious wizard dressed in blue, who granted her
+D:one wish - to become a cat herself. She met Tevildo on her travels,
+D:and became his consort and a servant of Morgoth.
+
+# New monster added by furiosity for the Theme module
+N:389:The Hunter
+G:H:v
+I:130:10d500:60:150:0
+W:80:1:0:80000
+E:0:1:0:2:2:2
+O:20:40:20:10
+B:HIT:UN_BONUS:5d10
+B:HIT:EXP_80:5d10
+B:HIT:ABOMINATION:5d10
+B:HIT:DISEASE:5d10
+F:BASEANGBAND | UNIQUE | FORCE_MAXHP |
+F:ELDRITCH_HORROR | REFLECTING |
+F:NO_SLEEP | NO_CUT | NO_STUN | NO_CONF | NO_FEAR |
+F:ONLY_ITEM | DROP_4D2 | DROP_GREAT | DROP_RANDART |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_POIS | SPECIAL_GENE |
+F:RES_NETH | RES_PLAS | EVIL | EMPTY_MIND |
+D:A shadowy creature of Elvish legend, said to have plagued the
+D:newly-awakened Elves at Cuivienen. Those Elves captured by the
+D:Hunter were thought to have been corrupted by Melkor to form
+D:the race of Orcs. You sense corruption all around you as it
+D:approaches. Your heart fills with despair and anguish, and you
+D:can just barely resist fleeing as far away from it as possible.
+
+
+N:390:Mummified human
+G:z:w
+I:110:17d9:20:34:60
+W:24:1:1500:70
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:2d4
+B:HIT:HURT:2d4
+F:ONLY_ITEM | DROP_90 |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a human form encased in mouldy wrappings.
+
+N:391:Vampire bat
+G:b:D
+I:120:9d10:12:40:50
+W:24:2:50:150
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:EXP_40:1d4
+B:BITE:EXP_40:1d4
+F:RAND_50 | COLD_BLOOD | REGENERATE | CAN_FLY |
+F:EVIL | ANIMAL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:A blood-sucking bat that flies at your neck hungrily.
+
+N:392:Sangahyando of Umbar
+G:p:U
+I:110:82d10:25:80:25
+W:24:2:2400:400
+E:1:1:1:2:1:1
+O:0:90:10:0
+B:HIT:HURT:4d7
+B:HIT:HURT:4d7
+B:HIT:HURT:4d7
+B:HIT:HURT:4d7
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_ELEC
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:SLOW | FORGET
+D:A Black Numenorean with a blacker heart. He is a descendant
+D:of Castamir, the usurper of Gondor's throne.
+
+N:393:It
+G:.:W
+I:110:77d9:25:80:25
+W:24:3:500:400
+E:0:0:0:0:0:0
+O:10:0:90:0
+B:GAZE:BLIND:8d8
+B:TOUCH:TERRIFY
+B:GAZE:EXP_40
+B:TOUCH:EAT_ITEM
+F:ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD | DROP_GREAT | DROP_CORPSE |
+F:CHAR_MULTI | CHAR_CLEAR | ATTR_CLEAR | INVISIBLE | COLD_BLOOD |
+F:NO_CONF | UNIQUE | FORCE_MAXHP | NO_SLEEP | CAN_SPEAK | REFLECTING |
+F:IM_FIRE | IM_ELEC | EMPTY_MIND | EVIL | SMART | RES_TELE | CAN_FLY |
+F:JOKEANGBAND
+S:1_IN_4
+S:DRAIN_MANA | BLINK | BLIND | SCARE | CONF | S_UNDEAD | S_MONSTER |
+S:HEAL | TELE_AWAY | DARKNESS | S_HYDRA | TRAPS | FORGET | TELE_TO | SHRIEK
+D:Nobody has ever seen It.
+
+N:394:Banshee
+G:G:b
+I:120:6d8:20:24:10
+W:24:2:0:60
+E:0:0:0:0:0:0
+O:80:0:0:15
+B:WAIL:TERRIFY
+B:TOUCH:EXP_20
+F:FEMALE |
+F:RAND_50 | DROP_1D2 |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_15 |
+S:TPORT | DRAIN_MANA
+D:It is a ghostly woman's form that wails mournfully.
+
+# New monster added by furiosity for the Theme module
+# Basically an insanely OOD Black Numenorean (hell knight)
+N:395:Herumor, Lord of the Haradrim
+G:p:o
+I:120:50d100:40:160:0
+W:25:1:0:29000
+E:1:1:1:2:1:1
+O:0:40:60:0
+B:HIT:HURT:10d5
+B:HIT:EXP_80:10d5
+F:UNIQUE | MALE | MORTAL | BASEANGBAND | HAS_LITE | CAN_SPEAK |
+F:FORCE_MAXHP | SMART | IM_FIRE | IM_COLD | IM_POIS | IM_COLD |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | RES_NETH | RES_NEXU | RES_PLAS |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | EVIL | SPECIAL_GENE |
+S:1_IN_5 |
+S:BLIND | SCARE | CAUSE_3 | BA_NETH | BA_FIRE | BO_PLAS
+S:S_MONSTERS | S_DEMON
+D:One of the many Numenoreans who fell under the shadow of Sauron
+D:after Ar-Pharazon brought the Dark Lord to Numenor. With another
+D:named Fuinur, he settled among the Haradrim on Middle-Earth, and
+D:became a lord in the lands of Harad. From this, and his worship of
+D:Sauron's darkness, he must have taken taken his name: Herumor means
+D:'lord of the dark'.
+
+# New monster added by furiosity for the Theme module
+N:396:Fimbrethil
+G:#:s
+I:120:50d100:30:120:40
+W:42:3:6000:13500
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:CRUSH:HURT:12d12
+B:CRUSH:HURT:12d12
+B:CRUSH:HURT:12d12
+B:CRUSH:HURT:12d12
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | SUSCEP_FIRE |
+F:WILD_ONLY | WILD_WOOD | WILD_GRASS | WILD_MOUNTAIN | WILD_SHORE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY | DROP_CORPSE |
+F:SMART | TAKE_ITEM | BASH_DOOR | KILL_WALL | NO_SLEEP |
+F:GOOD | NEUTRAL | NO_TARGET | BASEANGBAND | NO_CUT | FEMALE | CAN_FLY |
+F:DG_CURSE | WYRM_PROTECT |
+D:She is one of the Ent-wives who disappeared into the East a
+D:long time ago. She was the wife of Fangorn the Treebeard when
+D:the separation occurred, and she seems to have taken it quite
+D:badly. Her leaves are all withered to a dull gray and she is
+D:just standing there and crying. You should leave her alone.
+
+N:397:Silent watcher
+G:g:s
+I:110:80d25:60:80:0
+W:35:3:4000:800
+E:3:0:3:3:2:0
+O:0:0:0:0
+B:GAZE:TERRIFY
+B:GAZE:PARALYZE
+B:GAZE:LOSE_STR
+B:GAZE:HALLU
+F:EMPTY_MIND | COLD_BLOOD | NONLIVING | NEVER_MOVE |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | EVIL |
+F:HURT_ROCK | COLD_BLOOD | HURT_LITE | NO_FEAR |
+F:NO_CONF | NO_SLEEP | NO_STUN | NONLIVING | RES_TELE | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:SHRIEK | S_MONSTER | S_MONSTERS | HOLD | CONF | MIND_BLAST | DRAIN_MANA
+D:A figure carved from stone, with three vulture faces whose eyes glow
+D:with a malevolent light. None escape its vigilance.
+
+N:398:Pukelman
+G:g:D
+I:110:80d12:12:80:10
+W:25:3:10000:600
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d12
+B:HIT:HURT:3d6
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:SLOW | CONF | BO_ACID
+D:A stumpy figure carved from stone, with glittering eyes.
+
+# New monster added by furiosity for the Theme module
+# Basically Lugdush with extra power.
+N:399:Mauhur, the Uruk
+G:o:y
+I:110:66d10:20:90:20
+W:31:4:2500:850
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A large and powerful orc, captain of one of Saruman's orcish regiments.
+
+N:400:Dark elven druid
+G:h:G
+I:120:20d20:15:75:10
+W:25:3:1200:500
+E:1:1:1:2:1:1
+O:10:0:80:10
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+B:HIT:HURT:3d8
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL | CONF | DARKNESS |
+S:S_MONSTER | S_SPIDER | S_ANIMAL
+D:A powerful dark elf, with mighty nature-controlling enchantments.
+
+N:401:Stone troll
+G:T:W
+I:110:23d10:20:50:50
+W:25:1:5000:85
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:HURT:3d4
+F:MALE |
+F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | TROLL | HURT_LITE | HURT_ROCK | BASEANGBAND | NO_CUT
+D:It is said that Melkor created trolls in mockery of the Ents.
+D:This giant creature has scabby black skin and powerful fists.
+
+# New monster added by furiosity for the Theme module
+N:402:Prince Imrahil the Proud
+G:p:w
+I:110:10d100:10:60:0
+W:35:1:1800:6000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT
+B:HIT:HURT
+B:WAIL:TERRIFY
+B:INSULT:*
+F:BASEANGBAND | SPECIAL_GENE | UNIQUE | MALE | CAN_SPEAK |
+F:OPEN_DOOR | BASH_DOOR | TAKE_ITEM | HAS_LITE | SUSCEP_POIS |
+F:ONLY_ITEM | DROP_3D2 | DROP_GOOD | DROP_RANDART | FORCE_MAXHP |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | RES_NETH | RES_WATE |
+S:1_IN_8 |
+S:S_UNDEAD | S_KIN | S_DEMON | S_DRAGON |
+D:The proud ruler of the gray-eyed Men of Dol Amroth, Imrahil
+D:had been aligned with the forces of good for most of his life.
+D:However, Sauron has managed to sway Imrahil to the Shadow by
+D:making him jealous of King Elessar and the splendour of Gondor.
+D:He now sits sullenly upon his throne in Dol Amroth, unable to
+D:resist Sauron's enchantments, and growing ever more bitter and
+D:vengeful against the Free People.
+
+N:403:Hill troll
+G:T:s
+I:110:21d10:20:65:40
+W:21:1:4000:75
+E:1:1:1:2:1:1
+O:30:70:0:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+B:BITE:HURT:2d6
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_WASTE | WILD_MOUNTAIN |
+F:DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE | REGENERATE |
+F:EVIL | TROLL | HURT_LITE | BASEANGBAND
+D:It is said that Melkor created trolls in mockery of the Ents.
+D:This creature has an extremely tough hide, covered with warts.
+
+N:404:Wereworm
+G:w:u
+I:110:100d11:15:70:20
+W:25:3:6000:300
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:GAZE:EXP_20
+B:CRAWL:ACID:2d4
+B:BITE:HURT:1d10
+B:BITE:POISON:1d6
+F:BASH_DOOR | EVIL | CAN_SWIM | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | IM_ACID | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A huge wormlike shape dripping acid, twisted by evil sorcery into a foul
+D:monster that breeds on death.
+
+N:405:Killer red beetle
+G:K:r
+I:110:20d8:14:50:30
+W:25:1:600:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:LOSE_STR:4d4
+F:RAND_25 | WILD_TOO |
+F:WEIRD_MIND | BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:A giant beetle with poisonous mandibles.
+
+N:406:Disenchanter bat
+G:b:v
+I:130:6d8:12:28:50
+W:26:4:50:75
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:HIT:UN_BONUS
+B:HIT:UN_BONUS
+F:FORCE_SLEEP | RAND_50 | ANIMAL | MORTAL | ATTR_MULTI |
+F:DROP_CORPSE | AI_ANNOY | CAN_FLY | BASEANGBAND | WEIRD_MIND
+D:A giant bat that feeds on raw magical energy.
+
+# New monster added for the Theme module
+# Adapted from UnAngband
+N:407:Umuiyan, Doorkeeper of Tevildo
+G:f:s
+I:120:48d100:100:200:2
+W:66:3:0:30000
+E:0:1:0:2:1:0
+O:30:60:0:10
+B:HIT:CONFUSE:12d12
+B:TOUCH:LOSE_CHR:2d12
+B:HIT:BLIND:10d5
+B:HIT:TERRIFY:15d1
+F:UNIQUE | MALE | CAN_SPEAK | FORCE_MAXHP |
+F:EVIL | OPEN_DOOR | BASH_DOOR | ANIMAL |
+F:INVISIBLE | NO_SLEEP | NO_FEAR | MORTAL |
+F:DROP_4D2 | DROP_GOOD | ONLY_ITEM |
+F:IM_FIRE | IM_COLD | IM_POIS | NO_CONF |
+S:1_IN_3
+S:TELE_AWAY | S_KIN |
+D:A giant cat, servant of Tevildo. His yellow eyes look
+D:upon you with a baleful stare.
+
+N:408:Giant grey ant
+G:a:s
+I:110:19d8:10:40:40
+W:26:1:700:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d12
+F:RAND_25 | KILL_BODY | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | BASEANGBAND
+D:It is an ant encased in shaggy grey fur.
+
+# New monster added for the Theme module
+# From UnAngband
+N:409:Oikeroi, Bodyguard of Tevildo
+G:f:r
+I:130:48d100:100:200:2
+W:66:3:0:30000
+E:0:1:0:2:1:0
+O:30:60:0:10
+B:HIT:CONFUSE:12d12
+B:TOUCH:LOSE_DEX:2d12
+B:HIT:BLIND:10d5
+B:HIT:PARALYZE:15d1
+F:UNIQUE | MALE | CAN_SPEAK | FORCE_MAXHP |
+F:EVIL | OPEN_DOOR | BASH_DOOR | ANIMAL |
+F:INVISIBLE | NO_STUN | NO_SLEEP | MORTAL |
+F:DROP_4D2 | DROP_GOOD | ONLY_ITEM |
+F:IM_FIRE | IM_COLD | IM_POIS | NO_CONF |
+S:1_IN_3 |
+S:TELE_TO | S_KIN |
+D:A fierce and warlike cat, serving as a bodyguard of Tevildo.
+D:This giant cat looks down upon you with disdain.
+
+N:410:Gwaihir the Windlord
+G:B:v
+I:130:85d10:20:65:20
+W:24:6:1200:360
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:15d2
+B:CLAW:HURT:15d2
+B:BITE:HURT:3d10
+F:CAN_FLY | UNIQUE | FORCE_MAXHP | DROP_CORPSE | CAN_SPEAK |
+F:WILD_ONLY | WILD_MOUNTAIN | WILD_VOLCANO | PET |
+F:ANIMAL | GOOD | BASEANGBAND
+D:The greatest of eagles in the Third Age of Middle-earth, Gwaihir rescued
+D:Gandalf the Wizard from Orthanc, and has twice brought his flock to the
+D:aid of Sauron's enemies in battle - first outside the gates of Erebor in
+D:the Battle of Five Armies, and then before the Black Gate of Mordor itself.
+
+N:411:Giant fire tick
+G:S:R
+I:110:16d8:14:54:20
+W:26:2:200:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:3d6
+F:RAND_25 | SUSCEP_COLD |
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_FIRE | CAN_FLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is smoking and burning with great heat.
+
+# New monster added by furiosity for the Theme module
+# From UnAngband
+N:412:Lotho Sackville-Baggins, Betrayer of the Shire
+G:h:s
+I:120:6d10:16:8:5
+W:5:3:800:90
+E:1:1:1:2:1:1
+O:40:60:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:BASEANGBAND | WILD_TOO | WILD_TOWN | MORTAL |
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:HAS_LITE | OPEN_DOOR | BASH_DOOR | EVIL |
+F:FORCE_MAXHP | FORCE_SLEEP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+D:The 'Chief Shiriff' of Bag End. Using money obtained from Isengard
+D:and the sale of pipe-weed, he bought up much property in the Shire
+D:and supported the ruffians known as `The Chief's Men'. After
+D:imprisoning Will Whitfoot, the rightful Mayor of the Shire, Lotho
+D:took over and began industrializing and regimenting life in the Shire.
+
+N:413:Ulwarth, Son of Ulfang
+G:p:U
+I:110:85d10:20:40:40
+W:26:4:1800:500
+E:1:1:1:2:1:1
+O:40:60:0:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:UNIQUE | MALE | CAN_SPEAK | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_MAXHP | WILD_TOO |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A short and swarthy Easterling, faithless and treacherous.
+D:Along with his brother, he brought about the fall of the
+D:Sons of Feanor.
+
+N:414:Werebear
+G:q:D
+I:110:25d25:20:50:20
+W:24:2:0:200
+E:0:1:0:2:1:0
+O:25:25:25:20
+B:CLAW:HURT:1d10
+B:CLAW:HURT:1d10
+B:BITE:HURT:2d8
+B:CRUSH:HURT:2d6
+F:BASH_DOOR | OPEN_DOOR |
+F:WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:ANIMAL | EVIL | DROP_1D2 | BASEANGBAND
+D:In the eyes of this bear, there glimmers the faintest light of intelligence.
+D:And then its form begins to change... The combination of animal cunning,
+D:human intelligence and the great physical strength of the bear makes for
+D:a dangerous enemy.
+
+N:415:Cave ogre
+G:O:u
+I:110:30d9:20:33:30
+W:26:2:2500:80
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:FRIENDS | DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A giant orc-like figure with an awesomely muscled frame.
+
+N:416:White wraith
+G:W:w
+I:110:15d8:20:40:10
+W:26:1:0:175
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:TOUCH:EXP_20
+F:FORCE_SLEEP |
+F:DROP_1D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:SCARE | CAUSE_2 | DARKNESS
+D:It is a tangible but ghostly form made of white fog.
+
+# New monster added for the Theme module
+# Adapted from UnAngband
+N:417:Thranduil, King of the Wood Elves
+G:h:G
+I:120:11d100:20:80:10
+W:32:4:0:1000
+E:1:1:1:2:1:1
+O:0:40:30:30
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+#Force him into Mirkwood:
+F:FORCE_DEPTH | ONLY_DEPTH |
+F:BASEANGBAND | WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:UNIQUE | MALE | CAN_SPEAK | MORTAL | TAKE_ITEM |
+F:CAN_SWIM | OPEN_DOOR | BASH_DOOR | HAS_LITE |
+F:PET | NO_CONF | NO_SLEEP | GOOD |
+F:ONLY_ITEM | DROP_2D2| DROP_GREAT | NO_FEAR |
+F:IM_POIS | IM_COLD | RES_WATE | RES_TELE |
+S:1_IN_5
+S:BO_FIRE | BO_COLD | BLIND | CONF | HASTE | S_KIN |
+S:DARKNESS | S_MONSTER | S_ANIMALS | S_SPIDER |
+D:A strong wood-elf with a penchant for treasure. He is
+D:wise and powerful, and it is said that even the independent
+D:dark elves will rally to his side when he travels.
+
+N:418:Ghoul
+G:z:U
+I:110:15d9:30:30:20
+W:25:1:0:95
+E:1:1:1:2:1:1
+O:0:45:35:10
+B:CLAW:DISEASE:1d4
+B:CLAW:DISEASE:1d4
+B:BITE:PARALYZE:1d5
+F:DROP_60 | OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:EVIL | UNDEAD | FRIENDS | IM_POIS | IM_COLD | NO_CONF | NO_SLEEP |
+F:COLD_BLOOD | HURT_LITE | BASEANGBAND | NO_CUT
+S:1_IN_9
+S:SCARE | HOLD
+D:Flesh is falling off in chunks from this decaying abomination.
+
+N:419:Mim, Betrayer of Turin
+G:k:o
+I:120:11d105:20:80:20
+W:27:4:1200:1000
+E:1:1:1:2:1:1
+O:10:80:10:0
+B:HIT:HURT:3d9
+B:HIT:HURT:3d9
+B:HIT:HURT:3d9
+B:HIT:UN_BONUS:3d12
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | FORCE_SLEEP | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_DISE | RES_TELE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL | SCARE | BO_ACID | BA_ACID | TPORT | S_MONSTER
+D:A Petty-Dwarf, one of the last of his race. He betrayed Turin
+D:Turambar and gave him up to Morgoth's forces.
+
+N:420:Hellblade
+G:|:v
+I:120:13d13:20:40:20
+W:27:2:0:130
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:EXP_20:2d13
+B:HIT:EXP_20:2d13
+F:CHAR_MULTI | EVIL | IM_POIS | IM_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | SUSCEP_ACID |
+F:COLD_BLOOD | BASH_DOOR | NONLIVING |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+D:A deadly blade of chaos, moving of its own volition.
+
+N:421:Killer fire beetle
+G:K:R
+I:110:22d8:14:45:30
+W:27:1:600:95
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:SPIT:FIRE:4d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_VOLCANO | DROP_CORPSE |
+F:ANIMAL | IM_FIRE | CAN_FLY | SUSCEP_COLD |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle wreathed in flames.
+
+# New monster added by furiosity for the Theme module
+# From UnAngband
+N:422:Denethor, Steward of Gondor
+G:p:r
+I:120:55d100:40:160:10
+W:61:3:0:25000
+E:1:1:1:2:1:1
+O:20:50:10:5
+B:HIT:FIRE:9d12
+B:HIT:HURT:10d10
+F:UNIQUE | MALE | SMART | CAN_SPEAK | MORTAL |
+F:BASEANGBAND | FORCE_MAXHP | WEIRD_MIND | EVIL |
+F:HAS_LITE | ESCORT | ESCORTS | ONLY_ITEM |
+F:DROP_4D2 | DROP_3D2 | DROP_GOOD | TAKE_ITEM |
+F:OPEN_DOOR | BASH_DOOR | DROP_USEFUL |
+F:IM_ACID | IM_ELEC | IM_FIRE | IM_POIS | RES_PLAS |
+S:1_IN_2 |
+S:BA_FIRE | BRAIN_SMASH | CAUSE_2 | BO_FIRE | BO_MANA |
+S:BO_PLAS | SCARE | CONF | HASTE | HEAL | TPORT |
+S:TELE_TO | TELE_AWAY | TRAPS | FORGET | S_KIN |
+D:The proud former 'king' of Gondor, he has been driven mad
+D:by his contact with Sauron through the Palantir. You see
+D:the glint of a terrible fire in his eyes.
+
+N:423:Creeping adamantite coins
+G:$:G
+I:120:20d25:5:50:10
+W:27:3:0:60
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:POISON:3d4
+B:TOUCH:POISON:3d5
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+F:ONLY_GOLD | DROP_90 | DROP_2D2 |
+F:COLD_BLOOD | BASH_DOOR | CHAR_MULTI |
+F:IM_ELEC | IM_ACID | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It appears to be a pile of coins made of precious adamant, slithering toward
+D:you on lots of tiny legs.
+
+N:424:Algroth
+G:T:o
+I:110:21d12:20:60:40
+W:27:1:6000:150
+E:1:1:1:2:1:1
+O:10:80:0:10
+B:CLAW:POISON:3d3
+B:CLAW:POISON:3d3
+B:BITE:HURT:1d6
+F:FRIENDS | DROP_60 | WILD_WOOD | WILD_MOUNTAIN | WILD_TOO | WILD_SWAMP |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | REGENERATE |
+F:EVIL | TROLL | BASEANGBAND
+D:Trolls were created by Melkor in mockery of the Ents. This one is
+D:a powerful troll form. Venom drips from its needle-like claws.
+
+# New monster added for the Theme module
+# From UnAngband
+
+N:425:Boromir, Son of Denethor
+G:p:W
+I:110:10d100:20:90:30
+W:34:5:0:1200
+E:1:1:1:2:1:1
+O:10:80:0:10
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:BASEANGBAND | WILD_TOO | WILD_WOOD |
+F:UNIQUE | MALE | CAN_SPEAK | SMART |
+F:FORCE_MAXHP | MORTAL | HAS_LITE | PET |
+F:OPEN_DOOR | BASH_DOOR | TAKE_ITEM |
+F:DROP_2D2 | DROP_GOOD | ONLY_ITEM |
+S:1_IN_10 |
+S:ARROW_2 | S_KIN |
+D:A noble son of the Steward of Gondor.
+
+N:426:Roper
+G:#:D
+I:115:30d10:30:60:255
+W:27:5:0:235
+E:0:0:0:6:0:0
+O:0:0:0:0
+B:CRUSH:PARALYZE:3d5
+B:CRUSH:PARALYZE:3d5
+B:CRUSH:PARALYZE:3d5
+B:CRUSH:PARALYZE:3d5
+F:FORCE_MAXHP | FORCE_SLEEP | NO_FEAR | NEVER_MOVE |
+F:ONLY_GOLD | DROP_2D2 | DROP_60 | DROP_1D2 | EVIL |
+F:IM_ACID | IM_POIS | NO_CONF | NO_SLEEP | IM_COLD | IM_FIRE | BASEANGBAND
+F:NO_CUT
+S:1_IN_5 |
+S:BA_FIRE | BA_ELEC | BA_POIS | HASTE |
+S:TRAPS | SHRIEK | HOLD | CONF
+D:This creature look like a pillar of rock. However, a closer
+D:inspection reveals a glaring eye and powerful tentacles,
+D:which crush its prey and feed it to the creature's hungry
+D:mouth.
+
+N:427:Headless
+G:H:W
+I:110:25d12:20:50:40
+W:27:1:1600:175
+E:1:1:1:2:0:1
+O:0:100:0:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:FRIENDS | DROP_60 | OPEN_DOOR | BASH_DOOR | WILD_TOO |
+F:WILD_MOUNTAIN | WILD_WASTE | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | BASEANGBAND
+S:1_IN_6
+S:SCARE
+D:Headless humanoid abomination, ever hungry for blood.
+
+N:428:Vibration hound
+G:Z:y
+I:110:25d10:30:30:0
+W:27:2:600:250
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_SOUN
+D:A blurry canine form which seems to be moving as fast as the eye can
+D:follow. You can feel the earth resonating beneath your feet.
+
+N:429:Nexus hound
+G:Z:v
+I:110:25d10:30:30:0
+W:27:2:600:250
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP | RES_NEXU | DROP_SKELETON | DROP_CORPSE |
+F:FRIENDS |
+F:BASH_DOOR |
+F:ANIMAL | RES_TELE | NO_SLEEP | MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_NEXU
+D:A locus of conflicting points coalesce to form the vague shape of a huge
+D:hound. Or is it just your imagination?
+
+N:430:Half-ogre
+G:O:o
+I:110:35d9:20:33:30
+W:27:2:2700:80
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+F:FRIENDS | DROP_60 | DROP_CORPSE | SMART |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A giant, brutish figure, as ugly as an orc, but with some of the
+D:intelligence of his half-human ancestry.
+
+N:431:Lokkak, the Ogre Chieftain
+G:O:v
+I:120:15d103:20:100:20
+W:32:2:3000:1500
+E:1:1:1:2:1:1
+O:5:85:0:5
+B:HIT:HURT:6d7
+B:HIT:HURT:6d7
+B:HIT:HURT:6d7
+F:UNIQUE | MALE | CAN_SPEAK | WILD_TOO | WILD_SWAMP | WILD_SHORE |
+F:FORCE_MAXHP | ESCORT |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:EVIL | GIANT | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:An ogre renowned for acts of surprising cruelty, Lokkak is the leader of a large
+D:band of violent ogres.
+
+N:432:Vampire
+G:V:W
+I:110:25d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is a humanoid with an aura of power. You notice a sharp set of front
+D:teeth.
+
+N:433:Gorgimaera
+G:H:R
+I:110:25d20:12:55:10
+W:27:2:2300:400
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BUTT:HURT:2d10
+B:BITE:FIRE:2d10
+B:GAZE:PARALYZE:2d6
+F:FORCE_SLEEP | SUSCEP_COLD |
+F:BASH_DOOR | CAN_FLY | DROP_CORPSE |
+F:IM_FIRE | BASEANGBAND
+S:1_IN_8 |
+S:BR_FIRE
+D:It has three heads - goat, dragon and gorgon - all attached to a
+D:lion's body.
+
+# New monster added for the Theme module
+# From UnAngband
+N:434:Faramir, Son of Denethor
+G:p:W
+I:110:10d100:20:90:30
+W:34:5:0:1200
+E:1:1:1:2:1:1
+O:20:50:10:5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:BASEANGBAND | UNIQUE | MALE | CAN_SPEAK | PET |
+F:WILD_TOO | WILD_WOOD | FORCE_MAXHP | MORTAL |
+F:OPEN_DOOR | BASH_DOOR | TAKE_ITEM | HAS_LITE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+S:1_IN_10 |
+S:ARROW_2 | S_KIN
+D:The noble son of the Steward of Gondor guards the depths
+D:of Ithilien against the Enemy.
+
+N:435:Colbran
+G:g:y
+I:120:80d12:12:80:10
+W:27:2:0:900
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:ELEC:3d8
+B:HIT:ELEC:3d8
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | CAN_FLY |
+F:IM_ELEC | IM_POIS | AURA_ELEC | REFLECTING |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BO_ELEC
+D:A man-shaped form of living lightning, sparks and shocks crackle all over
+D:this madly capering figure, as it leaps and whirls around and about you.
+
+N:436:Spirit naga
+G:n:w
+I:110:30d15:20:75:120
+W:28:2:0:60
+E:0:0:0:0:1:0
+O:20:0:80:0
+B:CRUSH:HURT:2d8
+B:CRUSH:HURT:2d8
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+F:FEMALE |
+F:FORCE_SLEEP | CAN_FLY |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | DROP_CORPSE |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:HEAL | BLIND | MIND_BLAST | DARKNESS
+D:A wraithly snake-like form with the torso of a beautiful woman, it is the
+D:most powerful of its kind.
+
+# New monster added by furiosity for the Theme module
+# from UnAngband
+N:437:Harry Goatleaf, Gatekeeper of Bree
+G:p:w
+I:100:8d10:40:10:5
+W:5:4:1200:0
+E:1:1:1:2:1:1
+O:20:20:20:20
+B:GAZE:*
+B:WAIL:*
+B:INSULT:*
+B:CHARGE:HURT:1d2
+F:BASEANGBAND | WILD_TOO | WILD_TOWN | WILD_WOOD |
+F:UNIQUE | CAN_SPEAK | MALE | HAS_LITE | MORTAL |
+F:OPEN_DOOR | BASH_DOOR | TAKE_ITEM |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+D:The suspicious and gruff keeper of the West-gate of Bree. He betrayed his
+D:people by letting Saruman's thugs into the city, and so has been turned out.
+
+# New monster added for the Theme module
+# Description from UnAngband
+# Basically just an upgrade on the silent watcher.
+N:438:The Watcher of Cirith Ungol
+G:g:s
+I:140:60d200:100:300:0
+W:60:10:4000:80000
+E:3:0:3:3:2:0
+O:0:0:0:0
+B:GAZE:TERRIFY:5d8
+B:GAZE:PARALYZE:5d8
+B:GAZE:LOSE_STR:5d8
+B:GAZE:HALLU:5d8
+F:UNIQUE | FORCE_MAXHP | INVISIBLE | WEIRD_MIND |
+F:EMPTY_MIND | COLD_BLOOD | NONLIVING | NEVER_MOVE |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | EVIL |
+F:HURT_ROCK | COLD_BLOOD | HURT_LITE | NO_FEAR |
+F:NO_CONF | NO_SLEEP | NO_STUN | NONLIVING | RES_TELE |
+F:BASEANGBAND | NO_CUT | REGENERATE |
+S:1_IN_3 |
+S:SHRIEK | S_SPIDER | S_HI_UNDEAD | MIND_BLAST | DRAIN_MANA
+D:It looks like a great figure seated upon a throne, with three joined
+D:bodies and three vulture-like heads. It seems to be carved out of huge
+D:blocks of stone, immovable, and yet strangely aware of your presence.
+D:The black stones of its eyes glitter with its dreadful will. Visible or
+D:invisible, none shall pass by this guardian.
+
+N:439:Stairway to Hell
+G:>:W
+I:120:15d8:90:40:20
+W:28:5:0:125
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:WAIL:UN_BONUS
+B:WAIL:EXP_20
+B:WAIL:EAT_GOLD
+B:WAIL:EAT_ITEM
+F:CHAR_MULTI | COLD_BLOOD | EVIL | NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING |
+F:UNDEAD | FORCE_MAXHP | IM_FIRE | IM_ELEC | IM_POIS | IM_ACID | EMPTY_MIND
+F:NEVER_MOVE | JOKEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_15
+S:S_DEMON | SHRIEK
+D:Often found in graveyards.
+
+N:440:5-headed hydra
+G:M:g
+I:120:100d8:20:80:20
+W:28:2:5500:650
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+F:FORCE_SLEEP |
+F:ONLY_GOLD | DROP_1D2 | DROP_4D2 | DROP_SKELETON | DROP_CORPSE
+F:BASH_DOOR | MOVE_BODY | CAN_SWIM |
+F:ANIMAL | IM_POIS | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:SCARE | BA_POIS
+D:A strange reptilian creature with five heads dripping venom.
+
+# New monster added for the Theme module
+# Adapted from UnAngband
+N:441:Tom Bombadil
+G:Y:b
+I:140:440d100:255:10000:0
+W:127:5:0:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:SHOW:*
+F:BASEANGBAND | WILD_ONLY | WILD_GRASS | WILD_WOOD | WILD_SHORE |
+F:UNIQUE | MALE | FORCE_MAXHP | GOOD | HAS_LITE | CAN_SPEAK |
+F:NO_THEFT | CAN_FLY | NO_CUT | DEATH_ORB |
+F:WYRM_PROTECT | DG_CURSE | GOOD | OPEN_DOOR | BASH_DOOR | SMART |
+F:RES_NETH | NEVER_BLOW | REFLECTING | WEIRD_MIND |
+F:REGENERATE | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_TELE | RES_WATE | RES_PLAS | RES_NEXU | RES_DISE | PET |
+F:NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP | CAN_SWIM | AQUATIC |
+S:1_IN_5 |
+S:CONF | MIND_BLAST | BRAIN_SMASH |
+S:BA_MANA | CAUSE_4 | MISSILE | SCARE | SLOW | HOLD | BO_MANA |
+S:HASTE | HAND_DOOM | HEAL | BLINK | BR_MANA | S_MONSTERS |
+D:A mysterious figure in a blue coat, his face creased in laughter.
+D:Legend has it that he is older than Arda itself, and will aid
+D:the forces of good in any way he can.
+
+N:442:Wainrider
+G:p:s
+I:120:30d10:20:70:10
+W:28:1:2400:240
+E:1:1:1:2:1:1
+O:0:90:10:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:MALE |
+F:FORCE_SLEEP | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:BLIND | SCARE | CAUSE_3 | DARKNESS
+D:He is a figure riding a majestic war chariot; he looks at you
+D:menacingly.
+
+N:443:Seahorse
+G:~:o
+I:120:111d7:20:60:20
+W:28:2:3000:360
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:PARALYZE:4d5
+B:BITE:LOSE_DEX:4d5
+B:BITE:LOSE_CON:4d5
+F:FORCE_SLEEP | AQUATIC | GOOD | ANIMAL | NEUTRAL | NO_TARGET |
+F:IM_COLD | IM_POIS | IM_FIRE | IM_ELEC | WILD_ONLY | WILD_OCEAN
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BO_WATE | BO_COLD | BO_ICEE | BO_MANA
+D:Your mind is filled with admiration as you view this wondrous,
+D:magical seahorse.
+
+N:444:Cyclops
+G:P:u
+I:120:60d20:20:90:20
+W:45:2:3500:1500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:9d9
+B:HIT:HURT:9d9
+F:FORCE_SLEEP |
+F:DROP_1D2 | TAKE_ITEM | WILD_TOO | WILD_SHORE | WILD_MOUNTAIN |
+F:BASH_DOOR | OPEN_DOOR | MOVE_BODY | DROP_CORPSE |
+F:EVIL | IM_POIS | IM_ACID | IM_FIRE | IM_COLD | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:ARROW_4
+D:A gigantic humanoid with only one eye.
+
+N:445:Clairvoyant
+G:p:y
+I:120:25d10:100:50:10
+W:28:3:1600:250
+E:1:1:1:2:1:1
+O:0:0:90:10
+B:HIT:CONFUSE:5d5
+B:HIT:TERRIFY:5d5
+F:MALE |
+F:FORCE_SLEEP | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | SMART |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:BLIND | MIND_BLAST | HOLD | CAUSE_3 | FORGET | S_MONSTER
+D:He is using his supernatural talents to bring about your
+D:destruction.
+
+N:446:Purple worm
+G:w:v
+I:110:65d8:14:65:30
+W:29:4:1000:400
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:HIT:HURT:1d8
+B:BITE:ACID:2d8
+B:STING:POISON:1d8
+F:BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | IM_ACID | IM_POIS | CAN_SWIM |
+F:MORTAL | BASEANGBAND
+D:It is a massive worm form, many feet in length. Its vast maw drips acid
+D:and poison.
+
+N:447:Catoblepas
+G:q:g
+I:110:30d10:15:55:40
+W:29:2:0:400
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:TERRIFY:2d4
+B:GAZE:BLIND:2d4
+B:BUTT:HURT:2d6
+B:BITE:HURT:2d12
+F:ONLY_GOLD | DROP_2D2 | DROP_CORPSE
+F:BASH_DOOR | CAN_SWIM | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | IM_POIS
+F:MORTAL | BASEANGBAND
+D:A strange ox-like form with a huge head but a thin, weak neck.
+
+N:448:Lesser wall monster
+G:#:W
+I:110:13d8:20:75:40
+W:28:4:0:600
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+F:FORCE_SLEEP | COLD_BLOOD | EMPTY_MIND | KILL_WALL | RAND_50 |
+F:BASH_DOOR | IM_COLD | IM_ACID | IM_FIRE | IM_ELEC | IM_POIS | NONLIVING |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | CHAR_MULTI | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:A sentient, moving section of wall.
+
+N:449:Mage
+G:p:r
+I:110:15d8:20:40:10
+W:28:1:1500:150
+E:1:1:1:2:1:1
+O:10:0:90:0
+B:HIT:HURT:2d5
+B:HIT:HURT:2d5
+F:MALE |
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HASTE | TPORT | TELE_TO | BLIND | CONF |
+S:BO_FIRE | BO_COLD | BO_ELEC |
+S:S_MONSTER
+D:A fat mage with glasses. And considerable power, too - as you can
+D:tell from the size of his hat.
+
+N:450:Mind flayer
+G:h:y
+I:110:15d10:20:60:10
+W:28:1:1400:200
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:CRUSH:LOSE_INT:2d6
+B:GAZE:INSANITY:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:ONLY_ITEM | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:BLIND | HOLD | SCARE | MIND_BLAST | BRAIN_SMASH | FORGET
+D:A humanoid form with a gruesome head, tentacular mouth, and piercing
+D:eyes. Claws reach out for you and you feel a presence invade your mind.
+
+N:451:The Ultimate Dungeon Cleaner
+G:g:D
+I:120:70d12:10:80:12
+W:28:2:0:555
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRUSH:HURT:2d10
+B:CRUSH:HURT:2d10
+B:CRUSH:HURT:2d10
+B:CRUSH:HURT:2d10
+F:FORCE_SLEEP | FORCE_MAXHP | KILL_BODY | KILL_ITEM | UNIQUE | REFLECTING |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
+F:NO_FEAR | NO_CONF | NO_SLEEP | NONLIVING | RES_TELE | JOKEANGBAND | NO_CUT
+D:It looks like a huge spiked roller. It was designed to keep this dungeon
+D:clean, and you are the biggest spot of dirt in sight.
+
+# New monster added by furiosity for the Theme module
+# Based partly on the Icky queen.
+N:452:The Mewlip Queen
+G:i:v
+I:120:3d100:30:100:15
+W:30:5:10:4000
+E:0:0:0:0:0:0
+O:40:30:10:10
+B:CRAWL:POISON:5d7
+B:CRAWL:EAT_FOOD:5d7
+F:BASEANGBAND | EMPTY_MIND | SMART | IM_POIS |
+F:UNDEAD | RAND_50 | CAN_SWIM | EVIL | NO_FEAR |
+F:FORCE_MAXHP | UNIQUE | FEMALE | REGENERATE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GREAT | ESCORT | ESCORTS |
+S:1_IN_5
+S:ANIM_DEAD | S_KIN
+D:A ruler of mewlips. She might not be the most powerful of
+D:them all, but she is the smartest, and has her minions
+D:at her beck and call.
+
+N:453:Basilisk
+G:R:s
+I:120:20d30:15:90:30
+W:28:3:400:350
+E:0:1:0:2:1:0
+O:50:0:30:20
+B:GAZE:PARALYZE
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+F:ONLY_ITEM | DROP_1D2 | WILD_TOO | WILD_MOUNTAIN |
+F:OPEN_DOOR | BASH_DOOR | EVIL | IM_POIS | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP | CAN_SWIM |
+F:MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:BR_POIS
+D:An evil reptile that preys on unsuspecting travellers. Its eyes stare
+D:deeply at you and your soul starts to wilt!
+
+N:454:Snow-troll
+G:T:w
+I:110:24d10:20:56:50
+W:28:1:5000:200
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d5
+B:HIT:HURT:1d5
+B:BITE:COLD:2d6
+B:BITE:COLD:2d6
+F:MALE |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_WASTE | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE | REGENERATE |
+F:EVIL | TROLL | IM_COLD | HURT_LITE | BASEANGBAND
+D:Melkor created trolls in mockery of Yavanna's Ents. This
+D:is a white troll with powerfully clawed hands.
+
+# New monster added for the Theme module
+# From UnAngband
+N:455:Fluithuin the Ogress, Consort of Morgoth
+G:O:b
+I:120:53d100:40:140:30
+W:69:3:3000:29000
+E:1:1:1:2:1:1
+O:5:85:0:5
+B:HIT:HURT:11d10
+B:HIT:HURT:11d10
+B:HIT:SHATTER:11d10
+F:UNIQUE | CAN_SPEAK | FEMALE |
+F:RAND_25 | EVIL | GIANT | FORCE_MAXHP |
+F:DROP_GOOD | ONLY_ITEM | DROP_4D2 |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | KILL_ITEM |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_POIS |
+S:1_IN_5
+S:BA_ACID | BA_WATE | BO_ICEE
+D:A powerful, fierce ogress, consort to Morgoth, rumoured to
+D:be the mother of Gothmog, high captain of Balrogs.
+
+# New monster added by furiosity for the Theme module
+# Based on UnAngband, though there Ulbandi is male and same as ToME's Lokkak
+
+N:456:Ulbandi the Ogress, Consort of Morgoth
+G:O:R
+I:110:15d100:20:100:50
+W:40:5:3000:15000
+E:1:1:1:2:1:1
+O:5:85:0:5
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+B:HIT:POISON:8d8
+F:UNIQUE | FEMALE | CAN_SPEAK |
+F:EVIL | GIANT | FORCE_MAXHP |
+F:DROP_GOOD | DROP_2D2 | ONLY_ITEM |
+F:OPEN_DOOR | ESCORTS | IM_POIS |
+S:1_IN_9 |
+S:CONF | SCARE | HEAL | SHRIEK | S_KIN
+D:A powerful ogress, consort to Morgoth, rumoured to be
+D:the mother of Gothmog, high captain of Balrogs, also
+D:rumoured to be related to Lokkak, the Ogre Chieftain.
+
+# New monster added for the Theme module
+# Suggested by Atarlost in the t-o-m-e.net forum
+N:457:Naugladur, Lord of Nogrod
+G:k:G
+I:110:20d100:30:200:200
+W:70:1:0:12000
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:UNIQUE | MALE | ESCORT | ESCORTS | CAN_SPEAK |
+F:FORCE_MAXHP | SMART | SPECIAL_GENE
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_GREAT
+F:OPEN_DOOR | BASH_DOOR
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
+D:The slayer of Thingol, and the thief of the Nauglamir. He leads the dark
+D:dwarves who escaped from Nogrod.
+
+N:458:Greater mimic
+G:m:y
+I:120:10d35:30:60:100
+W:29:3:100:200
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+F:MIMIC |
+F:FORCE_SLEEP | NEVER_MOVE | SUSCEP_ACID |
+F:EMPTY_MIND | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLIND | CONF | SCARE | CAUSE_2 | FORGET |
+S:BO_ACID | BO_FIRE | BO_COLD | BO_ELEC |
+S:S_MONSTER
+D:A strange creature that disguises itself as an object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:459:Young blue dragon
+G:d:b
+I:110:27d10:20:50:70
+W:29:1:20000:500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:DROP_2D2 | DROP_CORPSE | ATTR_MULTI
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_ELEC | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_ELEC
+D:It has a form that legends are made of. Its still-tender scales are a
+D:deep blue in hue. Sparks crackle along its length.
+
+N:460:Young white dragon
+G:d:w
+I:110:27d10:20:50:70
+W:29:1:20000:500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN | WILD_WASTE |
+F:DROP_2D2 | DROP_CORPSE | ATTR_MULTI
+F:OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE |
+F:EVIL | DRAGON | IM_COLD | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_COLD
+D:It has a form that legends are made of. Its still-tender scales are a
+D:frosty white in hue. Icy blasts of cold air come from it as it breathes.
+
+N:461:Young green dragon
+G:d:g
+I:110:27d10:20:50:70
+W:29:1:20000:500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN | WILD_SWAMP |
+F:DROP_2D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_POIS | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_POIS
+D:It has a form that legends are made of. Its still-tender scales are a
+D:deep green in hue. Foul gas seeps through its scales.
+
+N:462:Young bronze dragon
+G:d:U
+I:110:27d10:20:50:70
+W:29:1:20000:500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN |
+F:DROP_2D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | NO_CONF | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_CONF
+D:It has a form that legends are made of. Its still-tender scales are a
+D:rich bronze hue, and its shape masks its true form.
+
+# New monster added for the Theme module
+# From the Annals of Ea module (by Feanor)
+N:463:Androg the Outlaw
+G:p:b
+I:110:72d10:20:95:20
+W:21:3:2400:600
+E:1:1:1:2:1:1
+O:30:8:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ESCORT |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_COLD | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE |
+D:A member of a band of outlaws, he was spared his life when
+D:Neithan (that is, Turin) killed Forweg, the previous leader.
+
+N:464:Mithril golem
+G:g:B
+I:110:80d15:12:100:10
+W:30:4:10000:500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:ONLY_GOLD | DROP_2D2 |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | REFLECTING |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+D:It is a massive statue of pure mithril. It looks expensive.
+
+N:465:Skeleton troll
+G:s:W
+I:110:20d10:20:55:20
+W:30:1:5000:225
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:HURT:3d4
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | TROLL | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a troll skeleton animated by dark magic.
+
+# New monster added for the Theme module
+# From Annals of Ea module (by Feanor)
+
+N:466:Amlach, son of Imlach
+G:p:s
+I:110:28d10:20:30:20
+W:9:2:1500:150
+E:1:1:1:2:1:1
+O:10:50:35:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+B:TOUCH:EAT_GOLD
+B:INSULT:*
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_GREAT |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON |
+F:EVIL | RES_TELE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:HEAL | SLOW | TRAPS | BO_COLD | BA_POIS
+D:He's a trustworthy man... or is he? Morgoth seem's sending spies in
+D:disguise, and perhaps this is one of them.
+
+N:467:Beorn, the Shape-Changer
+G:q:D
+I:120:20d70:25:60:25
+W:28:3:0:1000
+E:0:1:0:2:1:0
+O:20:60:20:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d8
+B:CRUSH:HURT:3d6
+F:UNIQUE | MALE | FORCE_MAXHP | FORCE_SLEEP |
+F:BASH_DOOR | ANIMAL | MOVE_BODY | SMART | PET | CAN_SPEAK |
+F:WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | BASEANGBAND
+S:1_IN_6 | S_ANIMAL
+D:Beorn is only occasionally seen in human form these days, preferring to
+D:appear in the shape of a giant black bear: he also prefers the company of
+D:beasts to that of humans. He has never taken kindly to strangers, even in
+D:human form - and still less when in bear's shape, as he is now.
+
+N:468:Thorondor, Lord of Eagles
+G:B:v
+I:130:85d12:20:65:20
+W:30:6:1600:555
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:16d2
+B:CLAW:HURT:16d2
+B:BITE:HURT:4d10
+F:CAN_FLY | UNIQUE | FORCE_MAXHP | DROP_CORPSE | CAN_SPEAK |
+F:WILD_ONLY | WILD_MOUNTAIN | WILD_VOLCANO | PET |
+F:ANIMAL | GOOD | BASEANGBAND
+D:Among the mightiest of birds, Thorondor is the messenger of the Valar, and
+D:brings news of Middle-earth to Valinor itself. Nothing that can be seen
+D:from the airs of the world is hidden from him.
+
+N:469:Giant blue ant
+G:a:b
+I:110:8d8:10:50:60
+W:30:2:600:80
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ELEC:5d5
+F:RAND_25 | WILD_TOO | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_ELEC
+F:MORTAL | BASEANGBAND
+D:It is a giant ant that crackles with energy.
+
+N:470:Grave wight
+G:W:b
+I:110:12d10:20:50:30
+W:30:1:0:325
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+B:TOUCH:EXP_20
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_1D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | CAN_FLY |
+F:IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:SCARE | CAUSE_3 | DARKNESS
+D:It is a ghostly form with eyes that haunt you. It appeared when a
+D:humanoid creature died a violent death in a graveyard. It remembers
+D:its past life and seeks revenge.
+
+N:471:Shadow drake
+G:d:G
+I:110:30d10:20:70:70
+W:33:3:18000:1100
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:EXP_10:3d6
+F:FORCE_SLEEP | FORCE_MAXHP | PASS_WALL |
+F:ONLY_ITEM | DROP_3D2 | CAN_FLY | DROP_CORPSE |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:BR_NETH | SLOW | CONF | SCARE | DARKNESS
+D:It is a dragon-like form wrapped in shadow. Glowing red eyes shine out in
+D:the dark, and it is surrounded by an aura of unearthly cold that chills
+D:the soul rather than the body.
+
+N:472:Manticore
+G:H:y
+I:120:25d10:12:15:10
+W:30:2:1900:300
+E:1:1:1:2:1:0
+O:0:0:0:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:BASH_DOOR | CAN_FLY | WILD_TOO | WILD_WOOD | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:ARROW_4
+D:It is a winged lion's body with a human torso and a tail covered in
+D:vicious spikes.
+
+N:473:Giant army ant
+G:a:o
+I:120:19d6:10:40:40
+W:30:3:600:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d12
+F:RAND_25 | KILL_BODY | FRIENDS | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL
+F:MORTAL | BASEANGBAND
+D:An armoured form moving with purpose. Powerful on its own, flee when
+D:hordes of them march.
+
+N:474:Killer slicer beetle
+G:K:y
+I:110:25d10:14:60:30
+W:30:2:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:5d8
+B:BITE:HURT:5d8
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | WILD_GRASS | DROP_CORPSE
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:It is a beetle with deadly sharp cutting mandibles and a rock-hard
+D:carapace.
+
+N:475:Gorgon
+G:H:b
+I:110:30d20:12:88:20
+W:31:2:3000:275
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BUTT:HURT:3d9
+B:BUTT:HURT:3d9
+B:BITE:POISON:1d10
+B:KICK:HURT:2d4
+F:FORCE_SLEEP | ANIMAL | MOVE_BODY | WILD_TOO | WILD_WOOD |
+F:BASH_DOOR | IM_POIS | IM_ACID | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:BR_POIS
+D:A bull-like creature whose skin is made of steel plates.
+
+# New monster added for the Theme module
+# From T-Plus module by Ingeborg S. Norden
+
+N:476:Radagast the Brown
+G:p:u
+I:120:35d101:101:100:0
+W:55:7:1600:21000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:6d4
+B:HIT:HURT:6d4
+F:UNIQUE | MALE | CAN_SPEAK | PET | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | REFLECTING | RES_TELE | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:GOOD | IM_COLD | IM_FIRE |
+F:IM_ELEC | IM_POIS | RES_WATE | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL | HASTE | BLINK | TPORT | BLIND | CONF | SCARE |
+S:CAUSE_2 | FORGET | TRAPS |
+S:BA_ELEC | BA_COLD | BA_WATE | BO_WATE | BO_ICEE | BO_ELEC |
+S:S_ANIMAL |
+D:Sometimes belittled as a bird-loving fool, Radagast is weaker
+D:mentally and magically than his fellows among the Istari.
+D:Nonetheless, his knowledge of woodcraft and command over the
+D:sky-borne elements makes Radagast a force to be reckoned with.
+
+N:477:Ghost
+G:G:w
+I:120:13d8:20:30:10
+W:31:1:0:350
+E:0:0:0:0:0:0
+O:30:40:0:20
+B:WAIL:TERRIFY
+B:TOUCH:EXP_20
+B:CLAW:LOSE_INT:1d6
+B:CLAW:LOSE_WIS:1d6
+F:FORCE_SLEEP | RAND_25 | DROP_60 | DROP_1D2 |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | CAN_FLY |
+F:IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | DRAIN_MANA
+D:An apparition from beyond. It does not seem friendly.
+
+N:478:Death watch beetle
+G:K:D
+I:110:25d12:16:60:30
+W:31:3:800:220
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:5d4
+B:WAIL:TERRIFY:5d6
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | CAN_FLY | MORTAL | BASEANGBAND
+D:It is a giant beetle that produces a chilling sound.
+
+N:479:Mountain ogre
+G:O:s
+I:110:40d9:20:33:30
+W:30:2:3000:100
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:5d8
+B:HIT:HURT:5d8
+F:FRIENDS | DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:The largest breed of ogre, he is awesomely strong and awesomely ugly.
+
+N:480:Nexus quylthulg
+G:Q:v
+I:110:10d12:10:1:0
+W:32:1:3000:300
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | RES_NEXU | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | RES_TELE | BASEANGBAND
+S:1_IN_1 |
+S:BLINK | TELE_AWAY
+D:It is a very unstable, strange pulsing mound of flesh.
+
+N:481:Shelob, Spider of Darkness
+G:S:D
+I:120:35d100:30:120:80
+W:55:3:1400:27000
+E:0:1:0:2:1:0
+O:20:30:40:0
+B:CLAW:POISON:5d6
+B:CLAW:POISON:5d6
+B:BITE:PARALYZE:5d10
+B:STING:LOSE_STR:5d4
+F:UNIQUE | FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP | SPECIAL_GENE |
+F:ESCORT | ESCORTS | DROP_CORPSE |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD | DROP_RANDART
+F:SMART | BASH_DOOR | IM_POIS | IM_ACID |
+F:ANIMAL | SPIDER | EVIL | HURT_LITE | NO_SLEEP | BASEANGBAND
+S:1_IN_4 |
+S:HEAL | BLIND | SLOW | CONF | SCARE | CAUSE_3 | CAUSE_4 |
+S:TRAPS | BR_DARK | BR_POIS |
+S:S_SPIDER
+D:Shelob is an enormous bloated spider, the last daughter of Ungoliant the
+D:Unlight. She normally guards the pass through Cirith Ungol, but
+D:occasionally goes out foraging for food to feed her voracious appetite.
+
+N:482:Giant squid
+G:~:g
+I:110:80d10:8:80:80
+W:32:3:3000:600
+E:3:0:3:6:1:0
+O:0:0:0:0
+B:CRUSH:HURT:8d4
+B:CRUSH:HURT:8d4
+B:CRUSH:HURT:8d4
+F:IM_ACID | RES_WATE | AQUATIC | ANIMAL | IM_COLD | MOVE_BODY
+F:FORCE_MAXHP | WILD_TOO | WILD_OCEAN | BASEANGBAND | COLD_BLOOD
+S:1_IN_8
+S:BR_ELEC | BR_ACID | BR_POIS
+D:Besides being capable of dragging whole ships underwater,
+D:this creature can also reach you from a distance.
+
+N:483:Ghoulking
+G:z:D
+I:120:40d12:20:60:10
+W:32:2:0:340
+E:1:1:1:2:1:1
+O:20:40:30:0
+B:CLAW:LOSE_STR:3d4
+B:CLAW:DISEASE:3d4
+B:CLAW:DISEASE:3d4
+B:BITE:PARALYZE:3d5
+F:DROP_60 | OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:DROP_1D2 | FORCE_MAXHP | ESCORT | FORCE_SLEEP |
+F:EVIL | UNDEAD | IM_POIS | IM_COLD | NO_CONF | NO_SLEEP |
+F:COLD_BLOOD | HURT_LITE | BASEANGBAND | NO_CUT
+S:1_IN_7
+S:SCARE | HOLD | DARKNESS | SCARE | S_UNDEAD | ANIM_DEAD
+D:Flesh is falling off in chunks from this decaying abomination.
+
+N:484:Doombat
+G:b:R
+I:120:24d14:16:75:30
+W:32:2:150:250
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:FIRE:5d4
+B:BITE:FIRE:5d4
+B:BITE:FIRE:5d4
+F:WEIRD_MIND | BASH_DOOR | AURA_FIRE | CAN_FLY | DROP_CORPSE |
+F:IM_FIRE | AI_ANNOY |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is a fast moving creature of chaos, a gigantic black bat
+D:surrounded by flickering bright red flames.
+
+N:485:Easterling
+G:p:U
+I:120:13d12:20:60:10
+W:32:2:1600:300
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:POISON:3d4
+B:HIT:LOSE_STR:3d4
+B:HIT:LOSE_STR:3d4
+F:MALE |
+F:DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | NO_CONF | NO_SLEEP | FRIENDS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:One of the Swarthy Men, allied with the Dark since time
+D:immemorable.
+
+N:486:Memory moss
+G:,:b
+I:110:1d2:30:1:5
+W:32:3:50:150
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:CONFUSE:1d4
+B:HIT:CONFUSE:1d4
+F:FORCE_SLEEP | NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:FORGET
+D:A mass of vegetation. You don't remember seeing anything like it
+D:before.
+
+N:487:Storm giant
+G:P:B
+I:110:40d20:20:60:40
+W:40:1:13000:1000
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:ELEC:10d8
+B:HIT:ELEC:10d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_1D2 | WILD_TOO | WILD_MOUNTAIN |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | AURA_ELEC | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | GIANT | IM_COLD | IM_ELEC | MALE | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:BLINK | TELE_TO | CONF | SCARE | BO_ELEC | BA_ELEC
+D:It is a twenty-five-foot tall giant wreathed in lightning.
+
+N:488:Spectator
+G:e:B
+I:110:15d13:30:1:5
+W:28:2:1600:150
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:PARALYZE:1d4
+B:GAZE:CONFUSE:1d4
+B:BITE:HURT:1d8
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:STUPID | EMPTY_MIND | CAN_FLY | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND
+S:1_IN_6 |
+S:FORGET | CAUSE_2 | HOLD | SLOW
+D:A lesser relative of the beholder: a globular body with a large toothy mouth,
+D:a large central eye, and four smaller eyes on stalks protruding from the top
+D:of its body.
+
+# New monster added by furiosity for the Theme module
+N:489:Bjorn the Warper
+G:q:D
+I:115:22d10:6:92:0
+W:31:10:3040:2000
+E:0:1:0:2:1:0
+O:20:60:20:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d8
+B:CRUSH:HURT:3d6
+F:JOKEANGBAND | WILD_TOO | WILD_GRASS | WILD_WOOD | WILD_SHORE |
+F:UNIQUE | MALE | FORCE_MAXHP | HAS_LITE | CAN_SPEAK |
+F:ANIMAL | MOVE_BODY | GOOD | SMART | BASH_DOOR | ONLY_ITEM |
+F:DROP_2D2 | DROP_GOOD | DROP_GREAT | FORCE_SLEEP | NO_CUT |
+F:NO_SLEEP | IM_ACID | IM_ELEC | IM_COLD | SUSCEP_POIS | IM_FIRE |
+S:1_IN_5 |
+S:BLINK | TELE_TO | TELE_AWAY | TPORT
+D:He is a descendant of Beorn to the 3.79th degree (his mother was
+D:Swedish, hence his name). He has blue eyes, bleached blond hair,
+D:and a tanned complexion. He signed up at the Adventurer's Guild
+D:because he thought the advertised position was "Surfer". He thinks
+D:you're the one responsible for tricking him.
+
+# New monster added by furiosity for the Theme module
+N:490:Vaire, the Weaver
+G:A:W
+I:200:440d100:255:1000:0
+W:0:50:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:BASEANGBAND | WILD_ONLY | FORCE_DEPTH | WILD_TOWN |
+F:WILD_GRASS | WILD_MOUNTAIN | WILD_WOOD | WILD_SHORE |
+F:UNIQUE | FEMALE | FORCE_MAXHP | HAS_LITE | POWERFUL |
+F:NO_THEFT | CAN_FLY | NO_CUT | DEATH_ORB | CAN_SPEAK |
+F:WYRM_PROTECT | DG_CURSE | GOOD | SMART | NEUTRAL | NO_TARGET | NEVER_MOVE |
+F:RES_NETH | NEVER_BLOW | REFLECTING | WEIRD_MIND | NO_DEATH |
+F:REGENERATE | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_TELE | RES_WATE | RES_PLAS | RES_NEXU | RES_DISE |
+F:NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP | CAN_SWIM | AQUATIC |
+S:1_IN_1
+S:HAND_DOOM | BR_MANA | HAND_DOOM | BR_MANA | HAND_DOOM
+D:A Queen of the Valar, the spouse of Mandos, who weaves the
+D:tales of the history of Arda.
+
+N:491:Half-troll
+G:T:U
+I:110:25d14:20:50:50
+W:34:2:3000:400
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:CLAW:HURT:1d5
+B:CLAW:HURT:1d5
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+F:MALE |
+F:FRIENDS |
+F:ONLY_ITEM | DROP_90 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | TROLL | IM_POIS | BASEANGBAND
+D:An unwholesome breed between a human and a troll. It is
+D:somewhat smarter than regular trolls.
+
+# New monster added by furiosity for the Theme module
+N:492:Irmo of Lorien
+G:A:g
+I:200:440d100:255:1000:0
+W:0:50:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:BASEANGBAND | WILD_ONLY | FORCE_DEPTH | WILD_TOWN |
+F:WILD_GRASS | WILD_MOUNTAIN | WILD_WOOD | WILD_SHORE |
+F:UNIQUE | MALE | FORCE_MAXHP | HAS_LITE | POWERFUL |
+F:NO_THEFT | CAN_FLY | NO_CUT | DEATH_ORB | CAN_SPEAK |
+F:WYRM_PROTECT | DG_CURSE | GOOD | SMART | NEUTRAL | NO_TARGET | NEVER_MOVE |
+F:RES_NETH | NEVER_BLOW | REFLECTING | WEIRD_MIND | NO_DEATH |
+F:REGENERATE | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_TELE | RES_WATE | RES_PLAS | RES_NEXU | RES_DISE |
+F:NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP | CAN_SWIM | AQUATIC |
+S:1_IN_1
+S:HAND_DOOM | BR_MANA | HAND_DOOM | BR_MANA | HAND_DOOM
+D:A Vala more commonly called Lorien, from the gardens of
+D:Lorien in Valinor.
+
+
+N:493:Bert the Stone Troll
+G:T:W
+I:120:11d100:20:70:50
+W:34:7:5000:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:BITE:HURT:3d10
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ESCORT | SPECIAL_GENE | MOVE_BODY | REGENERATE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | HURT_ROCK | BASEANGBAND | NO_CUT
+D:Big, brawny, powerful and with a taste for hobbit. He has friends called
+D:Bill and Tom.
+
+N:494:Bill the Stone Troll
+G:T:W
+I:120:11d100:20:70:50
+W:34:7:5000:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:BITE:HURT:3d10
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ESCORT | SPECIAL_GENE | MOVE_BODY | REGENERATE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | HURT_ROCK | BASEANGBAND | NO_CUT
+D:Big, brawny, powerful and with a taste for hobbit. He has friends called
+D:Bert and Tom.
+
+N:495:Tom the Stone Troll
+G:T:W
+I:120:11d100:20:70:50
+W:34:7:5000:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:BITE:HURT:3d10
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ESCORT | SPECIAL_GENE | MOVE_BODY | REGENERATE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | WILD_TOO | WILD_WOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | HURT_ROCK | BASEANGBAND | NO_CUT
+D:Big, brawny, powerful and with a taste for hobbit. He has friends called
+D:Bert and Bill.
+
+N:496:Cave troll
+G:T:u
+I:110:24d12:20:50:50
+W:33:1:6000:350
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+F:MALE |
+F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | SUSCEP_FIRE | REGENERATE |
+F:EVIL | TROLL | IM_POIS | HURT_LITE | BASEANGBAND
+D:Trolls were created by Morgoth in mockery of the Ents.
+D:He is a vicious monster, feared for his ferocity.
+
+# New monster added by furiosity for the Theme module
+N:497:Este, the Gentle
+G:A:B
+I:200:440d100:255:1000:0
+W:0:50:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:BASEANGBAND | WILD_ONLY | FORCE_DEPTH | WILD_TOWN |
+F:WILD_GRASS | WILD_MOUNTAIN | WILD_WOOD | WILD_SHORE |
+F:UNIQUE | FEMALE | FORCE_MAXHP | HAS_LITE | POWERFUL |
+F:NO_THEFT | CAN_FLY | NO_CUT | DEATH_ORB | CAN_SPEAK |
+F:WYRM_PROTECT | DG_CURSE | GOOD | SMART | NEUTRAL | NO_TARGET | NEVER_MOVE |
+F:RES_NETH | NEVER_BLOW | REFLECTING | WEIRD_MIND | NO_DEATH |
+F:REGENERATE | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_TELE | RES_WATE | RES_PLAS | RES_NEXU | RES_DISE |
+F:NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP | CAN_SWIM | AQUATIC |
+S:1_IN_1
+S:HAND_DOOM | BR_MANA | HAND_DOOM | BR_MANA | HAND_DOOM
+D:A lady of the Valar, the spouse of Irmo.
+
+# New monster added by furiosity for the Theme module
+#N:498:Nienna, the Sorrowful
+#G:A:D
+#I:200:440d100:255:1000:0
+#W:0:50:0:0
+#E:0:0:0:0:0:0
+#O:0:0:0:0
+#F:BASEANGBAND | WILD_ONLY | FORCE_DEPTH | WILD_TOWN |
+#F:WILD_GRASS | WILD_MOUNTAIN | WILD_WOOD | WILD_SHORE |
+#F:UNIQUE | FEMALE | FORCE_MAXHP | HAS_LITE | POWERFUL |
+#F:NO_THEFT | CAN_FLY | NO_CUT | DEATH_ORB | CAN_SPEAK |
+#F:WYRM_PROTECT | DG_CURSE | GOOD | SMART | NEUTRAL | NO_TARGET | NEVER_MOVE |
+#F:RES_NETH | NEVER_BLOW | REFLECTING | WEIRD_MIND | NO_DEATH |
+#F:REGENERATE | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+#F:RES_TELE | RES_WATE | RES_PLAS | RES_NEXU | RES_DISE |
+#F:NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP | CAN_SWIM | AQUATIC |
+#S:1_IN_1
+#S:HAND_DOOM | BR_MANA | HAND_DOOM | BR_MANA | HAND_DOOM
+#D:A Queen of the Valar, the sister of Namo and Irmo, who dwells
+#D:alone on the western borders of the World. Nienna ranks as one of
+#D:the eight Aratar, the most powerful of the Valar. Grief and mourning
+#D:are Nienna's province; she weeps for the suffering of Arda. She teaches
+#D:pity and endurance; she often goes to the halls of Mandos to comfort
+#D:and counsel those in the Halls of Waiting. The Maia Olorin was her
+#D:student and learned much from her.
+
+N:499:Barrow wight
+G:W:B
+I:110:15d10:20:40:10
+W:33:3:0:375
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+B:TOUCH:EXP_40
+F:FORCE_SLEEP | FRIENDS | DROP_60 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:HOLD | SCARE | CAUSE_2 | DARKNESS
+D:An evil spirit sent to dwell in the Barrow-downs by the Witch-king
+D:of Angmar during his wars with Arnor.
+
+N:500:Skeleton ettin
+G:s:W
+I:110:45d10:20:50:20
+W:33:1:7000:325
+E:1:1:1:2:2:1
+O:0:0:0:0
+B:HIT:HURT:1d9
+B:HIT:HURT:1d9
+B:BITE:HURT:1d5
+B:BITE:HURT:1d5
+F:FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | TROLL | UNDEAD |
+F:IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is the animated skeleton of a massive two-headed troll.
+
+N:501:Chaos drake
+G:d:v
+I:110:50d10:20:70:70
+W:33:3:18000:1400
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:ATTR_MULTI | ATTR_ANY | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | RES_DISE |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | DRAGON |
+F:IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_DISE | BR_CHAO
+D:A dragon twisted by the forces of chaos. It seems first ugly, then fair,
+D:as its form shimmers and changes in front of your eyes.
+
+N:502:Law drake
+G:d:B
+I:110:50d10:20:70:70
+W:33:3:18000:1400
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | CAN_FLY |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:DRAGON | EVIL |
+F:IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT | ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_SOUN | BR_SHAR
+D:This dragon is clever and cunning. You hear strange humming and
+D:rustling sounds as it approaches.
+
+N:503:Balance drake
+G:d:v
+I:110:60d10:20:70:70
+W:33:3:18000:1600
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | RES_DISE |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE
+F:EVIL | DRAGON | CAN_FLY |
+F:IM_FIRE | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_SOUN | BR_SHAR | BR_DISE | BR_CHAO
+D:A mighty dragon, the balance drake seeks to maintain balance,
+D:and despises your efforts to upset it.
+
+N:504:Ethereal drake
+G:d:o
+I:110:40d10:20:70:70
+W:33:3:0:1200
+E:0:1:0:6:1:0
+O:40:50:10:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | CAN_FLY |
+F:INVISIBLE | PASS_WALL |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_LITE | BR_DARK | BR_CONF
+D:A dragon of great power with control over light and dark, the
+D:ethereal drake's eyes glare with white hatred from the shadows.
+
+N:505:Groo, the Wanderer
+G:p:U
+I:120:13d113:20:70:50
+W:35:7:5000:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:9d1
+B:HIT:HURT:6d5
+B:HIT:HURT:25d1
+B:HIT:HURT:6d5
+F:UNIQUE | MALE | WEIRD_MIND | CAN_SPEAK |
+F:FORCE_MAXHP | WILD_TOO | DROP_CORPSE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:DROP_CHOSEN |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_COLD | IM_POIS | JOKEANGBAND
+D:He who laughs at Groo's brains will find there is nothing to laugh
+D:about... erm, nobody laughs at Groo and lives.
+
+# New monster added by furiosity for the Theme module
+N:506:Nessa the Lithe
+G:A:b
+I:200:440d100:255:1000:0
+W:0:50:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:BASEANGBAND | WILD_ONLY | FORCE_DEPTH | WILD_TOWN |
+F:WILD_GRASS | WILD_MOUNTAIN | WILD_WOOD | WILD_SHORE |
+F:UNIQUE | FEMALE | FORCE_MAXHP | HAS_LITE | POWERFUL |
+F:NO_THEFT | CAN_FLY | NO_CUT | DEATH_ORB | CAN_SPEAK |
+F:WYRM_PROTECT | DG_CURSE | GOOD | SMART | NEUTRAL | NO_TARGET | NEVER_MOVE |
+F:RES_NETH | NEVER_BLOW | REFLECTING | WEIRD_MIND | NO_DEATH |
+F:REGENERATE | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_TELE | RES_WATE | RES_PLAS | RES_NEXU | RES_DISE |
+F:NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP | CAN_SWIM | AQUATIC |
+S:1_IN_1
+S:HAND_DOOM | BR_MANA | HAND_DOOM | BR_MANA | HAND_DOOM
+D:The spouse of Tulkas and sister to Orome, who delights in dancing
+D:on the green lawns of Valimar.
+
+N:507:Shade
+G:G:D
+I:120:14d20:20:30:10
+W:33:3:0:350
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:WAIL:TERRIFY
+B:TOUCH:EXP_40
+B:CLAW:LOSE_INT:1d10
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | CAN_FLY |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | DRAIN_MANA | FORGET
+D:A shadowy form clutches at you from the darkness. A powerful undead with
+D:a deadly touch.
+
+N:508:Spectre
+G:G:U
+I:120:14d20:20:30:10
+W:33:3:0:350
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:WAIL:TERRIFY
+B:TOUCH:EXP_40
+B:CLAW:LOSE_WIS:5d5
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | CAN_FLY |
+F:COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | DRAIN_MANA | FORGET
+D:A phantasmal shrieking spirit. Its wail drives the intense cold of pure
+D:evil deep within your body.
+
+N:509:Water troll
+G:T:B
+I:110:36d10:20:50:50
+W:35:1:4000:420
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d9
+B:HIT:HURT:1d9
+B:HIT:HURT:2d2
+B:HIT:HURT:2d2
+F:MALE | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:FRIENDS | DROP_60 | REGENERATE |
+F:OPEN_DOOR | BASH_DOOR | CAN_SWIM |
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | BASEANGBAND
+D:Trolls are said to have been created by Melkor in mockery of
+D:the Ents. He reeks of brackish water and mud.
+
+N:510:Fire elemental
+G:E:r
+I:110:30d8:12:50:50
+W:33:2:0:350
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:FIRE:4d6
+B:HIT:FIRE:4d6
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | CAN_FLY | WILD_TOO | WILD_VOLCANO |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL | AURA_FIRE |
+F:IM_FIRE | IM_POIS | IM_ELEC | IM_ACID |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BO_FIRE
+D:It is a towering inferno of flames.
+
+# New monster added by furiosity for the Theme module
+#N:511:Orome, the Huntsman of the Valar
+#G:A:G
+#I:200:440d100:255:1000:0
+#W:0:50:0:0
+#E:0:0:0:0:0:0
+#O:0:0:0:0
+#F:BASEANGBAND | WILD_ONLY | FORCE_DEPTH | WILD_TOWN |
+#F:WILD_GRASS | WILD_MOUNTAIN | WILD_WOOD | WILD_SHORE |
+#F:UNIQUE | MALE | FORCE_MAXHP | HAS_LITE | POWERFUL |
+#F:NO_THEFT | CAN_FLY | NO_CUT | DEATH_ORB | CAN_SPEAK |
+#F:WYRM_PROTECT | DG_CURSE | GOOD | SMART | NEUTRAL | NO_TARGET | NEVER_MOVE |
+#F:RES_NETH | NEVER_BLOW | REFLECTING | WEIRD_MIND | NO_DEATH |
+#F:REGENERATE | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+#F:RES_TELE | RES_WATE | RES_PLAS | RES_NEXU | RES_DISE |
+#F:NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP | CAN_SWIM | AQUATIC |
+#S:1_IN_1
+#S:HAND_DOOM | BR_MANA | HAND_DOOM | BR_MANA | HAND_DOOM
+#D:The brother of Nessa and one of the eight Aratar. In ancient times,
+#D:he rode often in the forests of Middle-earth, and it was he who first
+#D:discovered the Eldar at Cuivienen.
+
+N:512:Water elemental
+G:E:b
+I:110:25d8:12:40:50
+W:33:2:0:325
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | COLD_BLOOD | CAN_FLY |
+F:KILL_BODY | KILL_ITEM | BASH_DOOR | POWERFUL |
+F:IM_POIS | IM_ACID | IM_FIRE | IM_COLD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BO_COLD
+D:It is a towering tempest of water.
+
+N:513:Multi-hued hound
+G:Z:v
+I:110:30d10:25:40:0
+W:33:3:600:600
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d4
+B:BITE:HURT:4d4
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | ATTR_MULTI | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:IM_ELEC | IM_POIS | IM_ACID | IM_FIRE | IM_COLD |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BR_ACID | BR_POIS | BR_COLD | BR_FIRE | BR_ELEC
+D:Shimmering in rainbow hues, this hound is beautiful and deadly.
+
+N:514:Invisible stalker
+G:E:y
+I:130:19d12:20:46:20
+W:35:3:0:300
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:RAND_50 |
+F:RES_TELE |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING
+F:BASEANGBAND | NO_CUT
+D:It is impossible to define its form but its violence is legendary.
+
+# New monster added by furiosity for the Theme module
+N:515:Vana, the Ever-young
+G:A:y
+I:200:440d100:255:1000:0
+W:0:50:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:BASEANGBAND | WILD_ONLY | FORCE_DEPTH | WILD_TOWN |
+F:WILD_GRASS | WILD_MOUNTAIN | WILD_WOOD | WILD_SHORE |
+F:UNIQUE | FEMALE | FORCE_MAXHP | HAS_LITE | POWERFUL |
+F:NO_THEFT | CAN_FLY | NO_CUT | DEATH_ORB | CAN_SPEAK |
+F:WYRM_PROTECT | DG_CURSE | GOOD | SMART | NEUTRAL | NO_TARGET | NEVER_MOVE |
+F:RES_NETH | NEVER_BLOW | REFLECTING | WEIRD_MIND | NO_DEATH |
+F:REGENERATE | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_TELE | RES_WATE | RES_PLAS | RES_NEXU | RES_DISE |
+F:NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP | CAN_SWIM | AQUATIC |
+S:1_IN_1
+S:HAND_DOOM | BR_MANA | HAND_DOOM | BR_MANA | HAND_DOOM
+D:The sister of Yavanna and spouse of Orome.
+D:Flowers open and birds sing at her passing.
+
+N:516:Master thief
+G:p:b
+I:130:18d10:20:30:40
+W:34:2:1300:350
+E:1:1:1:2:1:1
+O:90:10:0:0
+B:HIT:HURT:2d8
+B:HIT:HURT:3d4
+B:HIT:EAT_GOLD:4d4
+B:HIT:EAT_ITEM:4d5
+F:MALE |
+F:DROP_90 | DROP_2D2 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_6
+S:TRAPS | ARROW_2 | BLINK
+D:Cool and confident, fast and lithe; protect your possessions quickly!
+
+N:517:The Watcher in the Water
+G:~:v
+I:120:27d100:30:100:80
+W:45:3:7000:12000
+E:3:0:3:6:1:0
+O:50:50:0:0
+B:CRUSH:ACID:8d8
+B:CRUSH:POISON:8d8
+B:CRUSH:PARALYZE:8d8
+F:UNIQUE | FORCE_SLEEP | FORCE_MAXHP | CAN_SWIM | AQUATIC | ANIMAL |
+F:IM_ACID | IM_COLD | IM_POIS | RES_WATE | RES_TELE | DROP_CORPSE |
+F:NO_CONF | NO_FEAR | EVIL | COLD_BLOOD | BASEANGBAND |
+F:ONLY_ITEM | DROP_GOOD | DROP_4D2 | DROP_1D2 | SPECIAL_GENE | DROP_RANDART
+S:1_IN_5 | BA_WATE | BO_WATE | HOLD | BR_POIS | BO_ICEE | TELE_TO
+D:A vile creature which seems to consist mostly of tentacles, it seeks to
+D:drag people to their doom in the water. Few have ever escaped its grasp.
+
+N:518:Lich
+G:L:o
+I:110:30d10:20:60:60
+W:34:2:0:1000
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:TOUCH:EXP_40
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:2d8
+B:TOUCH:LOSE_DEX:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_1D2 |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLINK | TELE_TO | TELE_AWAY | BLIND | HOLD | SLOW | SCARE |
+S:CAUSE_3 | DRAIN_MANA | BRAIN_SMASH
+D:It is a skeletal form dressed in robes. It radiates vast evil power.
+
+N:519:Gas spore
+G:e:g
+I:110:25d10:30:1:5
+W:34:4:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:DISEASE:30d2
+F:FORCE_SLEEP |
+F:STUPID | EMPTY_MIND | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It does not look dangerous, yet you don't want to get
+D:any closer.
+
+N:520:Master vampire
+G:V:g
+I:110:34d20:20:60:10
+W:36:1:1600:750
+E:1:1:1:2:1:1
+O:20:40:30:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:BITE:EXP_40:3d6
+B:BITE:EXP_40:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:TELE_TO | HOLD | CONF | SCARE | CAUSE_3 | MIND_BLAST | FORGET |
+S:DARKNESS | BO_NETH
+D:It is a humanoid form dressed in robes. Power emanates from its chilling
+D:frame.
+
+N:521:Oriental vampire
+G:V:s
+I:110:30d30:20:60:10
+W:40:3:0:750
+E:1:1:1:2:1:1
+O:10:45:35:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:BITE:EXP_40:3d6
+B:BITE:EXP_40:3d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_4D2 | CAN_FLY |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | INVISIBLE | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | RES_TELE |
+F:BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:TELE_TO | HOLD | CONF | SCARE | CAUSE_3 | MIND_BLAST | FORGET |
+S:DARKNESS | BO_NETH
+D:This ancient creature can transform into a mist at will.
+
+N:522:Greater mummy
+G:z:y
+I:110:34d10:30:68:255
+W:36:3:0:800
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:CLAW:LOSE_CON:3d6
+B:CLAW:DISEASE:3d6
+B:GAZE:EXP_40:3d4
+B:GAZE:TERRIFY:3d4
+F:FORCE_SLEEP | FORCE_MAXHP | NO_FEAR | EVIL | UNDEAD |COLD_BLOOD |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | RES_TELE |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:HEAL | HASTE | BLIND | SCARE | S_UNDEAD | ANIM_DEAD |
+S:BA_POIS | BA_NETH | BA_COLD | DRAIN_MANA |
+S:MIND_BLAST | CAUSE_3 | DARKNESS | FORGET
+D:Once a powerful ruler, now an even more powerful undead menace.
+
+# New monster added for the Theme module
+# From T-Plus module by Ingeborg S. Norden
+
+N:523:Ingeborg, the Runemistress
+G:p:y
+I:155:180d75:111:175:0
+W:127:7:1600:444444
+E:2:1:2:6:1:1
+O:20:20:20:20
+B:GAZE:EAT_GOLD:10d10
+B:CRUSH:HURT:10d10
+B:TOUCH:UN_BONUS
+B:TOUCH:UN_POWER
+F:UNIQUE | CAN_SPEAK | ATTR_MULTI | ATTR_ANY | FEMALE |
+F:FORCE_MAXHP | WEIRD_MIND | DROP_CORPSE | DROP_SKELETON |
+F:REFLECTING | AURA_FIRE | AURA_ELEC | AURA_COLD |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | INVISIBLE |
+F:SMART | MOVE_BODY | TAKE_ITEM | POWERFUL | RES_TELE |
+F:REGENERATE | CAN_FLY | CAN_SWIM | DG_CURSE | WYRM_PROTECT |
+F:GOOD | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_PLAS | RES_DISE | RES_NETH | RES_NEXU | RES_WATE |
+F:NO_CONF | NO_FEAR | NO_SLEEP | NO_STUN | RES_TELE
+F:MORTAL | PET | JOKEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:S_BUG | S_HI_DRAGON | S_KIN | S_RNG | S_UNIQUE |
+S:TELE_AWAY | TELE_LEVEL | TELE_TO | TPORT |
+S:HAND_DOOM | HEAL |
+S:BO_ICEE | BO_MANA | BO_PLAS |
+S:BA_COLD | BA_MANA | BA_WATE | ROCKET |
+S:BR_LITE | BR_DISE | BR_INER | BR_MANA | BR_NEXU | BR_SOUN | BR_TIME |
+S:BRAIN_SMASH | FORGET |
+D:A heavy-set, fair-haired figure who cruises through the dungeon in
+D:a strangely made magical cart of some kind. Wherever she travels,
+D:monsters and magical devices appear which no one on Arda has seen
+D:before. Rumor has it that she's planning to foil the Dark Lord
+D:by reshaping the entire world, and traveling through time to ensure
+D:that NO Rings of Power ever get forged.
+
+N:524:Giant grey scorpion
+G:S:s
+I:120:18d20:12:50:40
+W:34:4:1200:275
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+B:STING:POISON:1d4
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_SKELETON |
+F:ANIMAL
+F:MORTAL | BASEANGBAND
+D:It is a giant grey scorpion. It looks poisonous.
+
+N:525:Earth elemental
+G:E:u
+I:100:30d10:10:60:90
+W:34:2:0:375
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD |
+F:KILL_ITEM | KILL_BODY | PASS_WALL | POWERFUL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:BO_ACID
+D:It is a towering form composed of rock with fists of awesome power.
+
+N:526:Air elemental
+G:E:B
+I:120:30d5:12:50:50
+W:34:2:0:390
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d10
+B:HIT:CONFUSE:1d4
+B:HIT:HURT:1d10
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | COLD_BLOOD | CAN_FLY |
+F:KILL_BODY | KILL_ITEM | BASH_DOOR | POWERFUL |
+F:IM_ACID | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:BO_ELEC
+D:It is a towering tornado of winds.
+
+N:527:Shimmering mold
+G:m:b
+I:110:32d8:2:24:70
+W:27:1:0:140
+B:SPORE:ELEC:5d4
+B:SPORE:ELEC:5d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_ELEC | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange growth on the dungeon floor, glowing and crackling with sparks.
+
+N:528:Sarnrog
+G:u:s
+I:110:18d12:10:50:15
+W:34:2:3000:110
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:1d6
+F:DROP_60 | ONLY_GOLD | EVIL | DEMON | FRIENDS | HURT_LITE |
+F:WILD_TOO | WILD_MOUNTAIN | WILD_WASTE |
+F:IM_POIS | IM_FIRE | IM_COLD | IM_ELEC | HURT_ROCK | NONLIVING |
+F:BASEANGBAND | NO_CUT
+S:1_IN_12
+S:BR_ELEC | BR_FIRE
+D:A minor demonic servant of evil, it looks like it is made of stone.
+
+N:529:Malicious leprawn
+G:l:v
+I:120:4d5:8:13:8
+W:35:4:1200:85
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:TOUCH:EAT_GOLD
+B:TOUCH:EAT_ITEM
+F:INVISIBLE | RAND_25 | TAKE_ITEM | COLD_BLOOD |
+F:HURT_LITE | EVIL | OPEN_DOOR | MALE |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY |
+S:1_IN_6 |
+S:BLINK | TPORT | TELE_TO | CAUSE_1
+D:This little gnome has a fiendish gleam in his eyes.
+
+N:530:Eog golem
+G:g:u
+I:100:100d20:12:125:10
+W:34:4:12000:1200
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+F:ONLY_GOLD | DROP_2D2 |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR | REFLECTING |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+D:It is a massive deep brown statue, striding towards you with an
+D:all-too-familiar purpose.
+
+# New monster added by furiosity for the Theme module
+# Based on actual character's stats
+
+N:531:Lindal Lossehelin
+G:h:R
+I:123:8d80:4:105:0
+W:49:3:970:2000
+E:1:1:1:2:1:1
+O:25:25:25:25
+B:HIT:HURT:10d8
+B:HIT:HURT:10d8
+# Wearing a Greater Mimic for a symbiote
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+F:JOKEANGBAND | WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:UNIQUE | MALE | GOOD | DROP_CORPSE | SMART | PET |
+F:OPEN_DOOR | BASH_DOOR | MORTAL | HAS_LITE | CAN_SWIM |
+F:CAN_SPEAK | DROP_4D2 | DROP_GREAT | FORCE_MAXHP |
+F:NO_SLEEP | NO_CONF | NO_CUT | RES_NEXU | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_NETH | RES_DISE | AURA_FIRE | CAN_FLY |
+#Spells chez archery
+S:1_IN_3
+S:ARROW_1 | ARROW_2 | ARROW_3 | ARROW_4 |
+#Spells chez a Greater Mimic named Glorp
+S:CAUSE_3 | BO_ACID | BO_ELEC | BO_FIRE | BO_COLD |
+S:SCARE | BLIND | CONF | FORGET | S_MONSTER
+D:An elf cloaked in green wielding a crossbow. He has sky blue
+D:eyes, straight black hair, and a fair face. He is the only
+D:child of a Telerin mage, and serves in King Thranduil's army.
+D:He has been sent on a quest by a strange wizard, and his
+D:aims are not so different from your own.
+
+N:532:Variag
+G:p:r
+I:120:13d25:20:70:10
+W:35:4:1600:500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:POISON:3d4
+B:HIT:LOSE_STR:3d4
+B:HIT:LOSE_STR:3d4
+B:HIT:POISON:3d4
+F:MALE |
+F:DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A human warrior from Khand, moving with lightning speed.
+
+N:533:Headless ghost
+G:G:u
+I:120:20d25:20:30:10
+W:35:3:0:550
+E:0:0:0:0:0:0
+O:35:25:25:0
+B:TOUCH:TERRIFY
+B:TOUCH:EXP_40
+B:CLAW:LOSE_INT:5d5
+B:CLAW:LOSE_WIS:5d5
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | CAN_FLY |
+F:COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | DRAIN_MANA | SCARE | BO_COLD | FORGET
+D:A phantasmal apparition with no head.
+
+N:534:Dread
+G:G:o
+I:120:25d20:20:30:10
+W:35:2:0:600
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:LOSE_STR:3d4
+F:FORCE_SLEEP | RAND_25 |
+F:ONLY_ITEM | DROP_60 | DROP_2D2 |
+F:TAKE_ITEM | INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | CAN_FLY |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | CONF | DRAIN_MANA | BO_NETH
+D:Death incarnate, its hideous black body seems to struggle
+D:against reality as the universe itself struggles to banish it.
+
+# New monster added by furiosity for the Theme module
+# Based on character dump current as of May 7, 2004
+# http://www.killerbunnies.org/angband/ladder/zizzo/zizzo_15.html
+N:535:Zizzo, Last of the Yeeks
+G:y:G
+I:110:5d10:3:35:0
+W:26:3:240:2000
+E:1:1:1:2:1:1
+O:50:0:50:0
+# Poor at combat:
+B:BITE:HURT:1d1
+B:INSULT:*
+B:WAIL:*
+F:JOKEANGBAND | WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:UNIQUE | MALE | GOOD | DROP_CORPSE | SMART | ANIMAL |
+F:OPEN_DOOR | BASH_DOOR | MORTAL | HAS_LITE |
+F:CAN_SPEAK | DROP_4D2 | DROP_GREAT | FORCE_MAXHP |
+F:AI_ANNOY | WEIRD_MIND | TAKE_ITEM | IM_POIS |
+F:IM_ACID | IM_ELEC | IM_FIRE | IM_COLD | POWERFUL |
+S:1_IN_1 |
+# Good at sorcery:
+S:BO_MANA | BO_MANA | BR_ELEC | BR_ACID | BO_MANA |
+S:BR_LITE | BR_WALL | BR_FIRE | BR_COLD | BR_POIS |
+D:He is one of five children of a brown Yeek. He is a credit to the
+D:family. He has dark brown eyes, straight black hair, and a dark
+D:complexion. He has an annoying habit of making strange "zizz" noises,
+D:hence his nickname. He is a sorcerer of some renown, and he thinks
+D:you have just the thing he needs to make it to the next level.
+
+N:536:Gauth
+G:e:s
+I:110:15d20:20:50:20
+W:36:2:1600:600
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:UN_BONUS:5d2
+B:GAZE:UN_BONUS:5d2
+B:GAZE:UN_POWER:5d2
+B:GAZE:UN_POWER:5d2
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE |
+F:BASH_DOOR | EVIL | BASEANGBAND | MORTAL
+S:1_IN_5 |
+S:CAUSE_2 | TELE_AWAY | BA_COLD | BO_ELEC | HOLD | DRAIN_MANA
+D:This six-eyed creature feeds on magic.
+
+N:537:Smoke elemental
+G:E:R
+I:120:15d10:10:80:90
+W:36:3:0:375
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:HURT:2d6
+B:ENGULF:HURT:2d6
+F:FORCE_SLEEP |
+F:EMPTY_MIND |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | CAN_FLY | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:DARKNESS | BO_FIRE
+D:It is a towering blackened form, crackling with heat.
+
+N:538:Olog
+G:T:y
+I:110:42d10:20:50:50
+W:36:1:6000:450
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:BITE:HURT:2d3
+B:BITE:HURT:2d3
+F:FORCE_MAXHP | OPEN_DOOR | FRIENDS | DROP_60 | REGENERATE |
+F:SMART | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | TROLL | IM_POIS | BASEANGBAND
+D:They say Melkor created trolls in mockery of the Ents. This is a
+D:massive troll, more intelligent than most of its kind, with needle-
+D:sharp fangs.
+
+N:539:Halfling slinger
+G:h:U
+I:110:30d9:20:40:30
+W:35:1:900:330
+E:1:1:1:2:1:1
+O:100:0:0:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+F:FORCE_MAXHP | OPEN_DOOR | FRIENDS | DROP_90 |
+F:SMART | EVIL | IM_POIS | IM_COLD | MALE | DROP_SKELETON | DROP_CORPSE
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3
+S:ARROW_4
+D:A rebel halfling who has rejected the tradition of archery.
+
+N:540:Gravity hound
+G:Z:U
+I:110:35d10:30:30:0
+W:35:2:700:500
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_GRAV
+D:Unfettered by the usual constraints of gravity, these unnatural creatures
+D:are walking on the walls and even the ceiling! The earth suddenly feels
+D:rather less solid as you see gravity warp all round these monsters.
+
+N:541:Acidic cytoplasm
+G:j:B
+I:120:40d10:12:18:1
+W:35:5:3000:180
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:FORCE_MAXHP | TAKE_ITEM | COLD_BLOOD |
+F:DROP_1D2 | DROP_4D2 | CAN_SWIM |
+F:STUPID | EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_FEAR | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:A disgusting animated blob of destruction.
+
+N:542:Inertia hound
+G:Z:W
+I:110:35d10:30:30:0
+W:35:2:700:500
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FRIENDS | DROP_SKELETON | DROP_CORPSE |
+F:BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_INER
+D:Bizarrely, this hound seems to be hardly moving at all, yet it approaches
+D:you with deadly menace. It makes you tired just to look at it.
+
+N:543:Impact hound
+G:Z:u
+I:110:35d10:30:30:0
+W:35:2:700:500
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_WALL
+D:A deep brown shape is visible before you, its canine form strikes you with
+D:an almost physical force. The dungeon floor buckles as if struck by a
+D:powerful blow as it stalks towards you.
+
+N:544:Shardstorm
+G:v:u
+I:120:32d10:40:12:0
+W:37:1:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:HURT:6d6
+F:FORCE_SLEEP | RAND_50 | NONLIVING | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:NO_FEAR | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BR_SHAR
+D:A howling blast of razor-sharp mountain fragments.
+
+N:545:Ooze elemental
+G:E:g
+I:110:13d10:10:80:90
+W:36:3:0:300
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_ACID | IM_FIRE | CAN_SWIM | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BO_ACID | BA_ACID
+D:It is a towering mass of filth and ooze.
+
+N:546:Young black dragon
+G:d:s
+I:110:30d10:20:60:70
+W:31:1:20000:700
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_SWAMP |
+F:DROP_3D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_ACID | BASEANGBAND | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_ACID
+D:It has a form that legends are made of. Its still-tender scales are a
+D:darkest black hue. Acid drips from its body.
+
+N:547:Mumak
+G:q:s
+I:110:90d10:20:55:100
+W:35:3:150000:2100
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BUTT:HURT:8d6
+B:BUTT:HURT:8d6
+B:CRUSH:HURT:8d4
+F:BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:A massive elephantine form with eyes twisted by madness.
+
+N:548:Giant fire ant
+G:a:R
+I:110:20d10:14:49:40
+W:35:1:700:350
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+F:FORCE_MAXHP | KILL_BODY | FRIENDS | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR | SUSCEP_COLD |
+F:ANIMAL | IM_FIRE
+F:MORTAL | BASEANGBAND
+D:A giant ant covered in shaggy fur. Its powerful jaws glow with heat.
+
+N:549:Cold-drake
+G:d:w
+I:110:40d10:20:70:70
+W:34:1:110000:1200
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_4D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_WASTE | WILD_MOUNTAIN |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | SUSCEP_FIRE | BASEANGBAND |
+F:HAS_LITE | ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_COLD
+D:A large dragon, scales gleaming bright white.
+
+N:550:Xorn
+G:X:u
+I:110:16d10:20:80:10
+W:36:2:30000:650
+E:0:0:0:3:0:0
+O:0:0:0:0
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+F:FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD |
+F:KILL_ITEM | PASS_WALL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:A huge creature of the Earth. Able to merge with its element, it
+D:has four huge arms protruding from its enormous torso.
+
+N:551:Rogrog the Black Troll
+G:T:D
+I:120:15d100:20:70:50
+W:41:5:9000:5000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d7
+B:HIT:HURT:6d7
+B:BITE:HURT:4d10
+B:SPIT:ACID:4d8
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ESCORT | MOVE_BODY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | TROLL | IM_COLD | IM_POIS | BASEANGBAND
+D:Trolls are abominations created by Melkor in mockery of the Ents.
+D:A massive and cruel troll of great power, drool slides caustically down
+D:his muscular frame. Despite his bulk, he strikes with stunning speed.
+
+# New monster added by furiosity for the Theme module
+# Based on character dump as of May 7, 2004
+# http://angband.oook.cz/ladder-show.php?id=2884
+N:552:Erianyth, the Sorceress
+G:A:r
+I:120:40d100:0:130:0
+W:50:7:1830:2000
+E:1:1:1:2:1:1
+O:25:25:25:25
+B:HIT:HURT:5d12
+B:HIT:HURT:5d12
+B:HIT:SHATTER:5d12
+F:JOKEANGBAND | WILD_TOO | WILD_MOUNTAIN | WILD_WASTE |
+F:UNIQUE | FEMALE | GOOD | DROP_CORPSE | SMART |
+F:OPEN_DOOR | BASH_DOOR | HAS_LITE | CAN_SWIM |
+F:CAN_SPEAK | DROP_4D2 | DROP_GREAT | FORCE_MAXHP |
+F:NO_SLEEP | NO_CONF | NO_CUT | RES_NEXU | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_NETH | RES_DISE | CAN_FLY | NO_FEAR | PASS_WALL |
+F:REFLECTING | REGENERATE | WEIRD_MIND |
+F:KILL_BODY | RES_TELE | INVISIBLE | NO_STUN |
+S:1_IN_4 |
+# Spells chez Thaumaturgy, dead Morgy, and her being Maia:
+S:BR_POIS | ROCKET | SHRIEK | BR_WALL | BR_INER |
+# Spells chez Master Q named 'Fear' (though not all, she *is* Maia):
+S:BLINK | TELE_TO | S_MONSTERS | S_ANIMALS |
+D:A mighty Maia of legend, associated with Vana. In the past, she
+D:dwelt on Middle-earth in the form of a beneficent but unseen force.
+D:She looks like she is a wall. It is rumoured that she has once
+D:destroyed Morgoth Bauglir and is out to banish him from the Void as
+D:well. It is a matter of principle for this sorceress, and you are
+D:blocking her path to justice.
+
+N:553:Phantom
+G:G:v
+I:120:20d25:30:30:20
+W:36:3:0:400
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:EXP_80
+B:TOUCH:EXP_40
+B:CLAW:LOSE_INT:1d10
+B:CLAW:LOSE_WIS:1d10
+F:FORCE_SLEEP |
+F:ONLY_ITEM | DROP_1D2 |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_5 |
+S:FORGET | MIND_BLAST
+D:An unholy creature of darkness. The aura emanating from this evil being
+D:saps your very soul.
+
+N:554:Grey wraith
+G:W:s
+I:110:19d10:20:50:10
+W:36:1:0:700
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:TOUCH:EXP_40
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_60 | DROP_90 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | HURT_LITE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:HOLD | SCARE | CAUSE_3 | DARKNESS
+D:A tangible but ghostly form, made of grey fog. The air around it feels
+D:deathly cold.
+
+N:555:Revenant
+G:W:u
+I:110:2d111:20:50:10
+W:36:1:0:725
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:GAZE:PARALYZE
+B:CLAW:LOSE_CON:1d10
+B:CLAW:LOSE_CON:1d10
+B:GAZE:EXP_40
+F:FORCE_SLEEP | FORCE_MAXHP | REGENERATE |
+F:DROP_60 | DROP_90 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | HURT_LITE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:CONF | SCARE | CAUSE_3 | DARKNESS
+D:Back from the grave, to wreak vengeance upon the living. A skeletal figure
+D:wearing a black robe, with eyes that burn with undying hatred.
+
+N:556:Young multi-hued dragon
+G:d:v
+I:110:32d10:20:60:70
+W:32:1:20000:900
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:3d8
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:DROP_1D2 | DROP_3D2 | CAN_FLY |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC |
+F:IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:SCARE |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS
+D:It has a form that legends are made of. Beautiful scales of shimmering
+D:and magical colours cover it.
+
+# New monster added by furiosity for the Theme module
+# Based on "Day in the life Of..." forum thread:
+# http://www.t-o-m-e.net/forum/viewtopic.php?t=4377
+N:557:Karrazix the Brave
+G:D:u
+I:120:22d100:5:100:0
+W:29:3:20000:2000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:10d8
+B:CLAW:HURT:10d8
+B:CLAW:HURT:10d8
+F:JOKEANGBAND | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN |
+F:UNIQUE | FEMALE | CAN_SPEAK | GOOD | DROP_CORPSE |
+F:SMART | PET | OPEN_DOOR | BASH_DOOR | HAS_LITE |
+F:CAN_FLY | DROP_4D2 | DROP_GREAT | FORCE_MAXHP | DRAGON |
+F:NO_SLEEP | NO_CONF | NO_FEAR | MOVE_BODY | POWERFUL |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+S:1_IN_4 |
+S:BR_FIRE | BR_COLD | BR_ELEC | BR_ACID | BR_POIS |
+D:She is a small, but fierce dragon - so fierce that in her fury she
+D:appears to be one of the Great Worms. She has turned away from
+D:Morgoth and worships Tulkas Astaldo. She intensely dislikes vampires
+D:in general and Thuringwethil in particular. She has red eyes and
+D:glittering scales.
+
+N:558:Colossus
+G:g:G
+I:110:30d100:15:150:10
+W:36:4:35000:900
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+F:FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ELEC |
+F:IM_POIS | NONLIVING | REFLECTING |
+F:NO_CONF | NO_SLEEP | NO_FEAR
+F:MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_8
+S:ARROW_4
+D:An enormous construct resembling a titan made from stone. It strides
+D:purposefully towards you, swinging its slow fists with earth-shattering
+D:power.
+
+N:559:Young gold dragon
+G:d:y
+I:110:30d10:20:60:70
+W:31:1:20000:700
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_3D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOO | WILD_MOUNTAIN |
+F:EVIL | DRAGON | BASEANGBAND | NO_STUN | HAS_LITE | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_SOUN
+D:It has a form that legends are made of. Its still-tender scales are a
+D:tarnished gold hue, and light is reflected from its form.
+
+N:560:Blue drake
+G:d:b
+I:110:40d10:20:70:70
+W:34:1:110000:1200
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_4D2 | DROP_CORPSE
+F:BASH_DOOR | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:EVIL | DRAGON | IM_ELEC | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_ELEC
+D:A large dragon, scales tinted deep blue.
+
+N:561:Green drake
+G:d:g
+I:110:40d10:20:70:70
+W:34:1:110000:1200
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_4D2 | DROP_CORPSE |
+F:BASH_DOOR | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:EVIL | DRAGON | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_POIS
+D:A large dragon, scales tinted deep green.
+
+N:562:Bronze drake
+G:d:U
+I:110:40d10:20:70:70
+W:34:1:110000:1200
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d8
+B:CLAW:HURT:2d8
+B:BITE:HURT:4d8
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN |
+F:DROP_4D2 | CAN_FLY |
+F:BASH_DOOR | DROP_CORPSE |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_9 |
+S:CONF | SCARE |
+S:BR_CONF
+D:A large dragon with scales of rich bronze.
+
+N:563:Young red dragon
+G:d:r
+I:110:30d10:20:60:70
+W:31:1:20000:700
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | SUSCEP_COLD |
+F:DROP_3D2 | WILD_TOO | WILD_MOUNTAIN | WILD_VOLCANO |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE
+F:EVIL | DRAGON | IM_FIRE | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_10 |
+S:SCARE |
+S:BR_FIRE
+D:It has a form that legends are made of. Its still-tender scales are a
+D:deepest red hue. Heat radiates from its form.
+
+# New monster added by furiosity for the Theme module
+# Based on character dump as of May 10, 2004
+# http://angband.oook.cz/ladder-show.php?id=2933
+N:564:Sir Physt
+G:V:y
+I:140:20d100:0:170:0
+W:45:3:1940:2000
+E:1:1:1:2:1:1
+O:25:25:25:25
+B:CHARGE:HURT:10d8
+# Wearing an Ultimate Mimic for a symbiote
+B:BITE:POISON:4d4
+B:BUTT:CONFUSE:4d4
+B:SPIT:BLIND:4d4
+F:JOKEANGBAND | WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:WILD_WASTE | WILD_MOUNTAIN | WILD_SHORE |
+F:UNIQUE | MALE | GOOD | SMART | UNDEAD | REFLECTING |
+F:OPEN_DOOR | BASH_DOOR | HAS_LITE | CAN_SWIM |
+F:CAN_SPEAK | DROP_4D2 | DROP_GREAT | FORCE_MAXHP |
+F:NO_SLEEP | NO_CONF | NO_CUT | RES_NEXU | MOVE_BODY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_NETH | RES_DISE | AURA_FIRE | CAN_FLY | REGENERATE |
+F:NO_STUN | KILL_BODY | NO_FEAR | WEIRD_MIND |
+#Spells chez Mindcraft
+S:1_IN_3
+S:BRAIN_SMASH | FORGET | MIND_BLAST |
+#Spells chez an Ultimate Mimic:
+S:CAUSE_3 | BA_POIS | SCARE | BLIND | CONF | S_MONSTER
+D:He is the head of the unholy holy order of Nosferatu. His nephew
+D:Sir Otilc played with swords and died as a result. Sir Physt is
+D:out to rectify the situation with his fists and his mind. Tulkas
+D:Astaldo has given this former Dunadan his blessings to go and
+D:destroy Morgoth Bauglir, Lord of Darkness. He believes it is his
+D:job and no one else's, and he approaches you with a menacing stare.
+
+N:565:Trapper
+G:.:w
+I:120:60d10:30:75:10
+W:36:3:1300:580
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:PARALYZE:15d1
+B:HIT:PARALYZE:15d1
+F:CHAR_CLEAR | ATTR_CLEAR | CHAR_MULTI |
+F:NEVER_MOVE | FORCE_MAXHP |
+F:INVISIBLE | EMPTY_MIND | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | BASEANGBAND
+D:This creature traps unsuspecting victims
+D:and paralyzes them, to be slowly digested later.
+
+N:566:Adanrog
+G:u:R
+I:110:35d10:10:68:90
+W:36:2:0:750
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:FIRE:4d6
+B:HIT:FIRE:4d6
+B:GAZE:EXP_20
+F:FORCE_SLEEP |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | AURA_FIRE | NONLIVING |
+F:EVIL | DEMON | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:HAS_LITE
+S:1_IN_4 |
+S:BO_FIRE | BA_FIRE |
+S:S_DEMON |
+D:It is a humanoid form composed of flames and hatred. Adanroeg are
+D:humans corrupted by the evil forces of Morgoth into demonic slaves
+D:to evil.
+
+N:567:Time bomb
+G:.:w
+I:130:12d12:30:40:0
+W:36:5:0:50
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:TIME:30d2
+F:CHAR_CLEAR | ATTR_CLEAR | CHAR_MULTI |
+F:NEVER_MOVE | FORCE_MAXHP |
+F:EMPTY_MIND | INVISIBLE | COLD_BLOOD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | JOKEANGBAND | NO_CUT
+D:It was left here to be used against intruders.
+
+N:568:Rawrog
+G:u:B
+I:110:40d10:10:68:90
+W:36:2:0:750
+E:1:1:1:0:1:1
+O:0:0:0:0
+B:CLAW:HURT:5d6
+B:CLAW:HURT:5d6
+F:FORCE_SLEEP | PASS_WALL | INVISIBLE |
+F:IM_POIS | IM_COLD | IM_ACID | IM_FIRE |
+F:NO_SLEEP | NO_CONF | NO_STUN | NONLIVING |
+F:EVIL | DEMON | BASEANGBAND
+S:1_IN_4 |
+S:BLINK | DARKNESS | S_DEMON
+D:It resembles a lion standing on two feet. In fact, Rawroeg are
+D:lions corrupted by Morgoth into demonic servants of evil.
+
+# New monster added by furiosity for the Theme module
+# Based on character dump as of May 7, 2004
+# http://angband.oook.cz/ladder-show.php?id=2838
+N:569:Nick LeYeek, Second Last of the Yeeks
+G:y:o
+I:130:35d100:127:100:0
+W:50:6:650:2000
+E:1:1:1:2:1:1
+O:25:25:25:25
+# Not good at melee:
+B:HIT:HURT:1d1
+B:INSULT:*
+B:SHOW:*
+F:JOKEANGBAND | WILD_TOO | WILD_WOOD | WILD_GRASS |
+F:UNIQUE | MALE | GOOD | DROP_CORPSE | SMART | ANIMAL |
+F:OPEN_DOOR | BASH_DOOR | MORTAL | HAS_LITE | CAN_SWIM |
+F:CAN_SPEAK | DROP_4D2 | DROP_GREAT | FORCE_MAXHP |
+F:PASS_WALL | NO_SLEEP | REGENERATE | REFLECTING |
+F:AURA_FIRE | IM_ACID | IM_ELEC | IM_FIRE | IM_COLD |
+F:IM_POIS | NO_CONF | RES_PLAS | RES_DISE | RES_NEXU |
+F:RES_NETH | RES_WATE |
+S:1_IN_5
+# Spells chez symbiote skull druj:
+S:BA_WATE | MIND_BLAST | BRAIN_SMASH | CAUSE_2 |
+S:BO_PLAS | SLOW | TRAPS | S_UNDEAD | BO_NETH |
+# Spells chez thaumaturgy and having killed Morgy:
+S:BR_SOUN | BR_MANA | BR_NUKE | BR_DISI | ROCKET |
+D:A yeek bard more famous for his buff physique and marriage to the beautiful
+D:but dumb Jessica Yeekson than his music. The dark forces of Morgoth killed
+D:his friend Justin TimberYeek and kidnapped poor Jessica Yeekson, and Nick
+D:vowed revenge. He is the only yeek that could be called powerful. It is rumoured
+D:that he had been successful in defeating Morgoth in a previous incarnation, and
+D:now he is back to finish the job for good. You are all that he perceives to
+D:stand in his way.
+
+N:570:Ice elemental
+G:E:w
+I:110:35d10:10:60:90
+W:37:3:0:650
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:COLD:4d3
+B:HIT:HURT:4d6
+B:TOUCH:COLD:4d3
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD | AURA_COLD |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_COLD | IM_ELEC | CAN_SWIM | IM_POIS | IM_ACID |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BO_ICEE | BA_COLD
+D:It is a towering glacier.
+
+N:571:Necromancer
+G:p:R
+I:110:28d10:20:50:10
+W:36:2:1600:666
+E:1:1:1:2:1:1
+O:10:0:90:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HASTE | TPORT | TELE_TO | BLIND | HOLD | SCARE | CAUSE_3 |
+S:BO_NETH | MIND_BLAST | FORGET |
+S:S_UNDEAD | ANIM_DEAD
+D:A gaunt figure, clothed in black robes.
+
+# New monster added by furiosity for the Theme module
+# Based on oook character dump as of May 7, 2004
+# http://angband.oook.cz/ladder-show.php?id=2616
+N:572:Slappy, Abbess of Pain
+G:h:U
+I:120:39d10:4:128:0
+W:33:3:780:2000
+E:1:1:1:2:1:1
+O:34:0:33:33
+B:HIT:HURT:10d8
+B:PUNCH:HURT:10d8
+B:KICK:HURT:10d8
+B:CHARGE:HURT:10d8
+F:JOKEANGBAND | WILD_TOO | WILD_WOOD | WILD_GRASS|
+F:UNIQUE | FEMALE | GOOD | DROP_CORPSE | SMART |
+F:CAN_SPEAK | DROP_4D2 | DROP_GREAT | FORCE_MAXHP |
+F:OPEN_DOOR | BASH_DOOR | MORTAL | HAS_LITE |
+F:NO_SLEEP | NO_CONF | CAN_SWIM | REGENERATE |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_NEXU | MOVE_BODY | KILL_WALL | CAN_FLY |
+#Well, she has a boomerang:
+S:1_IN_4 |
+S:ARROW_2
+D:A lithe female wood-elf wearing no armour - she is
+D:a monk of Manwe Sulimo, one of the most feared of her order.
+D:She is one of several children of an Avarin Prince. She has
+D:light grey eyes, straight black hair, and a fair face. She
+D:has unfinished business with some Basilisks and then she's
+D:going after Morgoth's crown. You are in her way.
+
+N:573:Lorgan, Chief of the Easterlings
+G:p:v
+I:120:18d100:25:100:10
+W:36:2:0:1200
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:TELE_TO | S_MONSTERS
+D:A mighty warrior from the east, Lorgan hates everything that he cannot
+D:control.
+
+# New monster added by furiosity for the Theme module
+N:574:Snow tiger
+G:f:w
+I:120:12d10:40:40:0
+W:12:2:1500:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:1d6
+F:BASH_DOOR | WILD_TOO | WILD_GRASS | WILD_WOOD | WILD_MOUNTAIN |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE | IM_COLD |
+F:MORTAL | BASEANGBAND
+D:A large feline that is well-adapted to extremely cold
+D:environments.
+
+N:575:Mummified troll
+G:z:w
+I:110:25d10:20:50:50
+W:34:1:5000:420
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:FORCE_MAXHP |
+F:DROP_60 |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | TROLL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a massive figure clothed in wrappings. You are wary of its massive
+D:fists.
+
+N:576:Storm of Unmagic
+G:v:v
+I:130:32d20:50:40:0
+W:53:3:0:4000
+B:ENGULF:EXP_80:5d5
+B:ENGULF:UN_POWER:5d5
+B:ENGULF:UN_BONUS:5d5
+B:HIT:LOSE_ALL:5d5
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:RAND_50 | RAND_25 | NONLIVING | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_TIME | BR_DISE
+D:Howling through the disintegrating dungeon, this awesome whirlpool of Unmagic
+D:rips the enchantments from everything it touches.
+
+N:577:Crypt thing
+G:L:G
+I:120:80d10:20:60:60
+W:37:2:0:2500
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:TOUCH:EXP_40
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:2d10
+B:TOUCH:LOSE_DEX:2d10
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_1D2 | RES_TELE |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | TELE_AWAY | TELE_LEVEL |
+S:CAUSE_3 | DRAIN_MANA | BRAIN_SMASH
+D:It is a skeletal form dressed in robes. It looks evil and devious.
+
+N:578:Chaos butterfly
+G:I:v
+I:120:60d10:40:60:10
+W:37:2:0:1000
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:3d7
+B:CLAW:HURT:3d7
+B:CRUSH:HURT:10d5
+F:FORCE_SLEEP |
+F:CAN_FLY |
+F:WEIRD_MIND | BASH_DOOR | ATTR_MULTI | ATTR_ANY |
+F:NO_CONF | NO_SLEEP | MORTAL | JOKEANGBAND
+S:1_IN_9
+S:BR_CONF | BR_CHAO
+D:With fractal patterns on its wings, it is clearly one of those butterflies
+D:that mathematicians keep talking about - the ones that flap their wings on the
+D:other side of the world to cause storms here. Now's your chance to stop it.
+
+N:579:Time elemental
+G:E:G
+I:120:35d10:90:70:10
+W:39:2:0:1000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TIME:3d4
+B:TOUCH:TIME:3d4
+F:PASS_WALL | IM_POIS | IM_FIRE | IM_ELEC | IM_FIRE | IM_ACID | CAN_FLY |
+F:NO_CONF | NO_SLEEP | EMPTY_MIND | KILL_ITEM | RAND_50 |
+F:BASEANGBAND | NO_CUT
+S:1_IN_7
+S:SLOW | BR_TIME |
+D:You have not seen it yet.
+
+N:580:Blue yeek
+G:y:B
+I:110:2d6:18:14:10
+W:2:1:700:4
+E:1:1:1:2:1:1
+O:25:0:0:55
+B:HIT:HURT:1d5
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:ANIMAL | IM_ACID |
+F:MORTAL | BASEANGBAND
+D:A small humanoid figure.
+
+N:581:The Queen Ant
+G:a:v
+I:120:15d100:30:100:10
+W:37:2:2000:1000
+E:0:1:0:2:1:0
+O:50:50:0:0
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d8
+B:BITE:HURT:2d8
+F:UNIQUE | FEMALE | GOOD | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:WEIRD_MIND | OPEN_DOOR | BASH_DOOR |
+F:ANIMAL |
+F:MORTAL | BASEANGBAND
+S:1_IN_2 |
+S:S_KIN
+D:She's upset because she thinks you hurt her children.
+
+N:582:Will o' the wisp
+G:E:W
+I:130:20d10:30:150:0
+W:38:4:0:500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:1d9
+B:HIT:HURT:1d9
+B:HIT:HALLU:1d9
+B:HIT:HALLU:1d9
+F:FORCE_SLEEP | FORCE_MAXHP | RAND_50 |
+F:SMART | EMPTY_MIND | INVISIBLE |
+F:PASS_WALL | POWERFUL | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_2 |
+S:BLINK | TPORT | CONF | CAUSE_2
+D:A strange ball of glowing light. It disappears and reappears and seems to
+D:draw you to it. You seem somehow compelled to stand still and watch its
+D:strange dancing motion.
+
+N:583:Brown yeek
+G:y:u
+I:110:4d8:18:18:10
+W:8:1:800:11
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID |
+F:MORTAL | BASEANGBAND
+D:It is a strange small humanoid.
+
+N:584:Magma elemental
+G:E:o
+I:110:35d10:10:70:90
+W:37:3:0:950
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:FIRE:3d7
+B:HIT:HURT:4d6
+B:HIT:FIRE:3d7
+F:FORCE_SLEEP |
+F:EMPTY_MIND | AURA_FIRE | WILD_TOO | WILD_VOLCANO |
+F:KILL_ITEM | KILL_BODY | PASS_WALL | POWERFUL |
+F:IM_FIRE | IM_ELEC | IM_ACID | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_7 |
+S:BO_PLAS | BA_FIRE
+D:It is a towering glowing form of molten rock.
+
+N:585:Black pudding
+G:j:D
+I:110:40d10:12:18:1
+W:37:5:300:50
+E:0:0:0:0:0:0
+O:90:0:0:0
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+B:TOUCH:ACID:1d10
+F:FORCE_MAXHP |
+F:FRIENDS |
+F:DROP_60 | DROP_90 | DROP_1D2 |
+F:STUPID | EMPTY_MIND | COLD_BLOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | CAN_SWIM | BASEANGBAND | NO_CUT
+D:A lump of rotting black flesh that slurps across the dungeon floor.
+
+N:586:Killer iridescent beetle
+G:K:v
+I:110:25d15:16:60:30
+W:37:2:600:850
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:ELEC:1d12
+B:CLAW:ELEC:1d12
+B:GAZE:PARALYZE
+F:ATTR_MULTI | FORCE_MAXHP |
+F:WEIRD_MIND | BASH_DOOR | AURA_ELEC | DROP_CORPSE |
+F:ANIMAL | IM_ELEC | CAN_FLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle, whose carapace shimmers with vibrant energies.
+
+N:587:Nexus vortex
+G:v:v
+I:120:32d10:100:40:0
+W:37:1:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:HURT:5d5
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 | RES_NEXU | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BR_NEXU
+D:A maelstrom of potent magical energy.
+
+N:588:Plasma vortex
+G:v:R
+I:120:32d10:100:40:0
+W:37:1:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:FIRE:4d8
+B:ENGULF:ELEC:4d8
+F:FORCE_SLEEP | SUSCEP_COLD |
+F:RAND_50 | RAND_25 | RES_PLAS | AURA_FIRE | AURA_ELEC |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:IM_FIRE | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BR_PLAS
+D:A whirlpool of intense flame, charring the stones at your feet.
+
+N:589:Fire-drake
+G:d:r
+I:110:50d10:20:80:70
+W:36:1:110000:1500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d10
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN | WILD_VOLCANO |
+F:DROP_1D2 | DROP_4D2 | CAN_FLY | DROP_CORPSE | SUSCEP_COLD |
+F:BASH_DOOR |
+F:EVIL | DRAGON | IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_9 |
+S:CONF | SCARE |
+S:BR_FIRE
+D:A large dragon, scales tinted deep red.
+
+N:590:Golden drake
+G:d:y
+I:110:50d10:20:80:70
+W:36:1:110000:1500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d10
+F:FORCE_SLEEP | FORCE_MAXHP | WILD_TOO | WILD_MOUNTAIN |
+F:DROP_1D2 | DROP_4D2 | CAN_FLY | DROP_CORPSE |
+F:BASH_DOOR |
+F:EVIL | DRAGON | NO_STUN | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_9 |
+S:CONF | SCARE |
+S:BR_SOUN
+D:A large dragon with scales of gleaming gold.
+
+N:591:Crystal drake
+G:d:u
+I:110:45d10:20:70:70
+W:33:3:18000:1350
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:3d6
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:ONLY_ITEM | DROP_3D2 | REFLECTING |
+F:OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_SHAR
+D:A dragon of strange crystalline form. Light shines through it, dazzling
+D:your eyes with spectra of colour.
+
+N:592:Black drake
+G:d:s
+I:110:50d10:20:80:70
+W:36:1:110000:1500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d10
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE |
+F:DROP_1D2 DROP_4D2 | WILD_TOO | WILD_SWAMP | WILD_MOUNTAIN |
+F:BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_ACID
+D:A large dragon, with scales of deepest black.
+
+N:593:Multi-hued drake
+G:d:v
+I:110:60d10:20:80:70
+W:38:1:110000:1800
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d12
+B:CLAW:HURT:2d12
+B:BITE:HURT:4d12
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_2D2 | DROP_4D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_7 |
+S:BLIND | CONF | SCARE |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS
+D:A large dragon, scales shimmering many colours.
+
+N:594:Master yeek
+G:y:g
+I:110:12d9:18:24:10
+W:12:2:600:28
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:1d8
+F:FORCE_SLEEP |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | EVIL | IM_ACID | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:BLINK | TPORT | BLIND | SLOW | BA_POIS |
+S:S_MONSTER
+D:A small humanoid that radiates some power.
+
+N:595:Orfax, son of Boldor
+G:y:R
+I:120:14d10:18:20:10
+W:11:3:600:80
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d9
+B:INSULT:*
+B:INSULT:*
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS |
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | EVIL | IM_ACID |
+F:MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:HEAL | BLINK | TELE_TO | SLOW | CONF |
+S:S_MONSTER
+D:The son of the yeek King, he has some power, but he's still a yeek.
+
+N:596:Boldor, King of the Yeeks
+G:y:r
+I:120:20d10:18:24:10
+W:13:3:650:200
+E:1:1:1:2:1:1
+O:0:90:10:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:HIT:HURT:1d9
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS |
+F:ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR | CAN_SPEAK | DROP_CORPSE |
+F:ANIMAL | EVIL | IM_ACID |
+F:MORTAL | BASEANGBAND
+S:1_IN_2 |
+S:HEAL | BLINK | TPORT | BLIND | SLOW |
+S:S_KIN | S_MONSTER
+D:A great yeek, powerful in magic and sorcery, but a yeek all the same.
+
+N:597:Black Numenorean
+G:p:D
+I:120:60d10:20:100:10
+W:38:1:2700:1111
+E:1:1:1:2:1:1
+O:0:90:0:10
+B:HIT:EXP_20:6d6
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_NETH |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_COLD | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_5 |
+S:BLIND | SCARE | CAUSE_3 | BO_NETH |
+S:S_MONSTERS
+D:It is a humanoid figure dressed in armour of an ancient form. From beneath
+D:its helmet, eyes glow a baleful red and seem to pierce you like lances of
+D:fire. Ever a faithful servant of Sauron, he'll stop at nothing to destroy
+D:you.
+
+N:598:Castamir the Usurper
+G:p:R
+I:120:88d10:20:90:40
+W:38:5:0:1600
+E:1:1:1:2:1:1
+O:10:60:10:10
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | TAKE_ITEM | BASH_DOOR |
+F:EVIL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | TRAPS | BO_FIRE | BO_COLD | BO_ELEC | BO_ICEE
+D:A Black Numenorean who usurped the throne of Gondor, he is treacherous and
+D:evil.
+
+N:599:Time vortex
+G:v:B
+I:130:32d10:100:40:0
+W:38:4:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:TIME:5d5
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | CAN_FLY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_TIME
+D:You haven't seen it yet.
+
+N:600:Shimmering vortex
+G:v:o
+I:140:32d10:100:40:0
+W:38:4:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:BLIND:4d4
+B:ENGULF:BLIND:4d4
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_4 |
+S:BR_LITE | SHRIEK
+D:A strange pillar of shining light that hurts your eyes. Its shape changes
+D:constantly as it cuts through the air towards you. It is like a beacon,
+D:waking monsters from their slumber.
+
+N:601:Ancient blue dragon
+G:D:b
+I:120:72d10:20:90:80
+W:40:1:170000:2000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:ELEC:7d8
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_3D2 | DROP_4D2 | DROP_CORPSE |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
+F:EVIL | DRAGON | IM_ELEC | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_ELEC
+D:A huge draconic form. Lightning crackles along its length.
+
+N:602:Ancient bronze dragon
+G:D:U
+I:120:72d10:20:90:80
+W:40:1:170000:2000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:HURT:7d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_3D2 | DROP_4D2 | CAN_FLY |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_CONF
+D:A huge draconic form enveloped in a cascade of colour.
+
+N:603:Beholder
+G:e:U
+I:120:16d100:30:80:10
+W:40:3:1600:6000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:EXP_20:2d6
+B:GAZE:UN_POWER:2d6
+B:GAZE:INSANITY:2d6
+B:BITE:HURT:6d6
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | CAN_FLY |
+F:BASH_DOOR | DROP_CORPSE |
+F:EVIL | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_2 |
+S:BLIND | SLOW | CONF | SCARE | DRAIN_MANA | MIND_BLAST |
+S:FORGET | DARKNESS | BO_ACID | BO_FIRE | BO_COLD | BO_ELEC
+D:A vile creature with one huge central eye, twelve smaller eyes on stalks, and
+D:a huge mouth filled with sharp teeth.
+
+N:604:Emperor wight
+G:W:r
+I:120:38d10:20:40:10
+W:38:2:0:1600
+E:0:0:0:0:0:0
+O:0:40:60:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:TOUCH:EXP_80
+B:TOUCH:EXP_80
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_4D2 | CAN_FLY |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:HOLD | SCARE | CAUSE_3 | BO_NETH
+D:Your life force is torn from your body as this powerful unearthly being
+D:approaches.
+
+# New monster added by furiosity for the Theme module
+N:605:Giant tree ant
+G:a:G
+I:110:20d10:14:49:40
+W:35:1:700:350
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:3d12
+B:BITE:POISON:3d12
+F:FORCE_MAXHP | KILL_BODY | FRIENDS | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | IM_POIS |
+F:MORTAL | BASEANGBAND
+D:A giant ant covered in shaggy fur. Its powerful jaws drip venom.
+
+N:606:Vargo, Tyrant of Fire
+G:E:r
+I:120:24d100:12:50:50
+W:43:3:0:4000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:FIRE:6d6
+B:HIT:FIRE:6d6
+B:HIT:FIRE:6d6
+B:HIT:FIRE:6d6
+F:UNIQUE | SUSCEP_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP | RAND_25 | CAN_SPEAK |
+F:EMPTY_MIND | CAN_SPEAK | MALE | AURA_FIRE |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_ACID | IM_POIS | IM_ELEC | NO_STUN |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_4 |
+S:BO_PLAS | BA_FIRE
+D:A towering fire elemental, Vargo burns everything beyond recognition.
+
+N:607:Black wraith
+G:W:D
+I:120:50d10:20:55:10
+W:38:2:0:1700
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:TOUCH:EXP_40
+B:TOUCH:EXP_40
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP
+F:BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | BO_NETH
+D:A figure that seems made of void, its strangely human shape is cloaked in
+D:shadow. It reaches out at you.
+
+# New monster added by furiosity for the Theme module
+N:608:Giant yellow ant
+G:a:y
+I:110:20d10:14:49:40
+W:35:1:700:350
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:BLIND:3d12
+B:BITE:BLIND:3d12
+F:FORCE_MAXHP | KILL_BODY | FRIENDS | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR | ANIMAL |
+F:MORTAL | BASEANGBAND
+D:A giant ant covered in shaggy fur. Its powerful jaws click with blinding speed.
+
+# New monster added by furiosity for the Theme module
+N:609:Giant green ant
+G:a:g
+I:110:20d10:14:49:40
+W:35:1:700:350
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:CONFUSE:3d12
+B:BITE:CONFUSE:3d12
+F:FORCE_MAXHP | KILL_BODY | FRIENDS | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR | ANIMAL | NO_CONF |
+F:MORTAL | BASEANGBAND
+D:A giant ant covered in shaggy fur. Its powerful jaws make puzzling
+D:noises as they snap shut.
+
+# New monster added by furiosity for the Theme module
+N:610:Aquatic ant
+G:a:B
+I:110:20d10:14:49:40
+W:35:1:700:350
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d12
+B:BITE:HURT:3d12
+F:FORCE_MAXHP | KILL_BODY | FRIENDS | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR | CAN_SWIM |
+F:ANIMAL | RES_WATE | AQUATIC |
+F:MORTAL | BASEANGBAND
+S:1_IN_4
+S:BA_WATE
+D:A strange antlike creature, animated by a powerful wizard you
+D:cannot see.
+
+N:611:Monastic lich
+G:L:u
+I:120:12d100:30:80:30
+W:39:2:2000:5000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:KICK:HURT:24d1
+B:KICK:HURT:24d1
+B:CLAW:EXP_80:4d2
+B:CLAW:LOSE_DEX:4d2
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_TELE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | SMART |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | BLIND | HOLD | CONF | SCARE | CAUSE_3 | CAUSE_4 |
+S:DRAIN_MANA | BRAIN_SMASH | ANIM_DEAD
+D:A skeletal form wrapped in priestly robes. Before its un-death, it
+D:was a monk in an evil order.
+
+N:612:Nether wraith
+G:W:G
+I:120:48d10:20:55:10
+W:39:2:0:1700
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:HIT:HURT:1d12
+B:HIT:HURT:1d12
+B:TOUCH:EXP_80
+B:TOUCH:EXP_80
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_90 | DROP_4D2 |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BLIND | SCARE | CAUSE_3 | MIND_BLAST | DARKNESS | BO_NETH
+D:A form that hurts the eye, death permeates the air around it. As it nears
+D:you, a coldness saps your soul.
+
+N:613:Hellhound
+G:C:R
+I:120:48d10:25:80:30
+W:35:3:600:600
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:RAND_25 | FRIENDS | AURA_FIRE | SUSCEP_COLD |
+F:BASH_DOOR | MOVE_BODY |
+F:ANIMAL | EVIL | IM_FIRE | BASEANGBAND | HAS_LITE |
+S:1_IN_5 | BR_FIRE
+D:It is a giant dog that glows with heat. Flames pour from its nostrils.
+
+N:614:7-headed hydra
+G:M:G
+I:120:100d10:20:90:20
+W:39:2:7000:2000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:POISON:3d9
+B:BITE:POISON:3d9
+B:BITE:POISON:3d9
+B:SPIT:BLIND:1d2
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:ONLY_GOLD | DROP_2D2 | DROP_4D2 | CAN_SWIM | DROP_CORPSE
+F:BASH_DOOR | MOVE_BODY |
+F:ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:SCARE | BA_POIS |
+S:BR_POIS
+D:A strange reptilian creature with seven heads dripping venom.
+
+N:615:Waldern, King of Water
+G:E:b
+I:130:25d100:12:80:50
+W:43:3:0:4250
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:8d5
+B:HIT:HURT:8d5
+B:HIT:HURT:8d5
+B:HIT:HURT:8d5
+F:UNIQUE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_ACID | IM_FIRE | IM_POIS | IM_COLD |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BO_ICEE | BO_WATE | BA_COLD | BA_WATE
+D:A towering water elemental, Waldern is master of all things liquid.
+D:Wave after wave drowns your frail body.
+
+# New monster added by furiosity for the Theme module
+N:616:Termite
+G:a:U
+I:110:2d10:4:9:40
+W:20:1:1:100
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+B:BITE:HURT:1d6
+F:FORCE_MAXHP | KILL_BODY | FRIENDS | DROP_SKELETON
+F:WEIRD_MIND | BASH_DOOR | SUSCEP_FIRE |
+F:ANIMAL | AI_ANNOY | KILL_TREES |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY
+D:An extremely annoying antlike creature. Its bulbous eyes seem
+D:almost covetous as they focus on your wooden paraphernalia.
+
+N:617:Ancient white dragon
+G:D:w
+I:120:72d10:20:90:80
+W:40:1:170000:2000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:COLD:7d8
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_3D2 | DROP_4D2 | DROP_CORPSE |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | SUSCEP_FIRE | BASEANGBAND
+F:HAS_LITE | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_COLD
+D:A huge draconic form. Frost covers it from head to tail.
+
+N:618:Ancient green dragon
+G:D:g
+I:120:72d10:20:90:80
+W:40:1:170000:2000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:POISON:7d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_3D2 | DROP_4D2 | CAN_FLY |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_POIS
+D:A huge draconic form enveloped in clouds of poisonous vapour.
+
+# New monster added by furiosity for the Theme module
+N:619:Giant snow bat
+G:b:w
+I:130:3d8:12:20:50
+W:10:2:600:18
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:TERRIFY:1d3
+B:CLAW:COLD:1d2
+B:CLAW:COLD:1d2
+F:RAND_50 | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:FORCE_SLEEP | ANIMAL | DROP_CORPSE | AI_ANNOY | IM_COLD |
+F:SUSCEP_FIRE | MORTAL | BASEANGBAND
+D:A giant bat adapted to extremely cold temperatures.
+
+N:620:Eldrak
+G:T:r
+I:110:75d10:20:80:50
+W:38:3:7000:1500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:BITE:HURT:3d4
+B:BITE:HURT:3d4
+F:FORCE_MAXHP | MOVE_BODY |
+F:ONLY_ITEM | DROP_2D2 | REGENERATE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_SHORE | WILD_WOOD |
+F:EVIL | TROLL | IM_POIS | NO_CONF | NO_SLEEP | DROP_CORPSE | BASEANGBAND
+D:Melkor created trolls in mockery of the Ents. A massive troll of
+D:huge strength, extremely stupid and extremely violent.
+
+N:621:Ettin
+G:T:b
+I:110:15d100:20:100:30
+W:39:3:8000:2000
+E:1:1:1:2:2:1
+O:0:100:0:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:BITE:HURT:3d8
+B:BITE:HURT:3d8
+F:FORCE_MAXHP | REGENERATE | MOVE_BODY |
+F:ONLY_ITEM | DROP_1D2 | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD | WILD_SWAMP |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | TROLL | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+D:Melkor created trolls in mockery of the Ents. A massive two-headed troll,
+D:larger and stronger than many men together.
+
+N:622:Night mare
+G:q:G
+I:120:15d100:30:85:0
+W:39:3:6000:2900
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:EXP_80:2d6
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:CONFUSE:6d6
+F:FORCE_MAXHP |
+F:ONLY_GOLD | DROP_2D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:HAS_LITE | NO_CUT
+D:A fearsome skeletal horse with glowing eyes that watch you with little
+D:more than hatred for all that lives. Its flying hooves do not touch the
+D:ground.
+
+N:623:Vampire lord
+G:V:b
+I:120:20d100:20:70:10
+W:42:1:1700:1800
+E:1:1:1:2:1:1
+O:0:70:30:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:BITE:EXP_80:4d6
+B:BITE:EXP_80:4d6
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_60 | DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | RES_TELE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | DARKNESS | BO_NETH
+D:A foul wind chills your bones as this ghastly figure approaches.
+
+N:624:Ancient black dragon
+G:D:s
+I:120:10d100:20:90:80
+W:41:1:170000:2500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d9
+B:CLAW:HURT:4d9
+B:BITE:ACID:7d9
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_3D2 | DROP_4D2 | DROP_CORPSE |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_ACID | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_ACID
+D:A huge draconic form. Pools of acid melt the floor around it.
+
+N:625:Weird fume
+G:#:v
+I:120:35d10:100:40:0
+W:40:2:0:800
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:CONFUSE:8d4
+B:ENGULF:CONFUSE:8d4
+F:FORCE_SLEEP |
+F:RAND_50 | RAND_25 | RES_NEXU | AURA_ELEC | IM_FIRE | IM_ELEC |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:CAN_FLY | ATTR_MULTI | ATTR_ANY |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | JOKEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_CHAO | BR_NEXU | BR_NUKE
+D:A swirling spiral of mist, constantly changing its appearance.
+
+# New monster added by furiosity for the Theme module
+N:626:Giant grey bat
+G:b:s
+I:130:3d8:12:20:50
+W:10:2:600:18
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:TERRIFY:1d3
+B:CLAW:PARALYZE:1d2
+B:CLAW:HURT:1d2
+F:RAND_50 | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:FORCE_SLEEP | ANIMAL | DROP_CORPSE | AI_ANNOY |
+F:MORTAL | BASEANGBAND
+D:A giant bat whose very presence makes you feel weary.
+
+# New monster added by furiosity for the Theme module
+N:627:Giant silver bat
+G:b:W
+I:130:3d8:12:20:50
+W:10:2:600:18
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:LOSE_DEX:1d3
+B:CLAW:HALLU:1d2
+B:CLAW:HURT:1d2
+F:RAND_50 | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:FORCE_SLEEP | ANIMAL | DROP_CORPSE | AI_ANNOY |
+F:MORTAL | BASEANGBAND
+D:A giant bat, its wings shimmering a pale mesmerizing silver.
+
+# New monster added by furiosity for the Theme module
+N:628:Giant yellow bat
+G:b:y
+I:130:3d8:12:20:50
+W:10:2:600:18
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:LOSE_CHR:1d3
+B:CLAW:EAT_LITE:1d2
+B:CLAW:EAT_LITE:1d2
+F:RAND_50 | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:FORCE_SLEEP | ANIMAL | DROP_CORPSE | AI_ANNOY |
+F:MORTAL | BASEANGBAND
+D:A giant bat which seems to absorb all light as it passes.
+
+N:629:Shadowfax, steed of Gandalf
+G:c:v
+I:130:30d100:20:100:50
+W:40:3:2600:2000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:KICK:HURT:5d5
+B:KICK:HURT:5d5
+B:BITE:HURT:6d6
+F:FORCE_MAXHP | UNIQUE | ANIMAL | GOOD | NEUTRAL | NO_TARGET |
+F:REGENERATE | BASH_DOOR | IM_FIRE | IM_COLD | IM_ELEC |
+F:IM_POIS | NO_FEAR | DROP_CORPSE | WILD_ONLY | WILD_WOOD | WILD_GRASS |
+F:MORTAL | BASEANGBAND
+D:Shadowfax is the chief of the Mearas, the greatest of all horses that are
+D:bred in the fields of Rohan. Although the Mearas should technically be only
+D:ridden by the royal family of Rohan, only Gandalf the Wizard has ever
+D:succeeded in taming Shadowfax: and even then, Shadowfax will not be subjected
+D:to a bridle or saddle, but must be ridden bareback.
+
+N:630:Spirit troll
+G:G:G
+I:110:10d100:20:90:5
+W:40:3:0:900
+E:0:0:0:0:0:0
+O:10:90:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:FORCE_MAXHP |
+F:DROP_90 |
+F:INVISIBLE | PASS_WALL | CAN_FLY |
+F:EVIL | TROLL | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:A ghostly troll-like being from the ethereal plane.
+
+N:631:War troll
+G:T:R
+I:120:50d10:20:100:50
+W:40:3:6500:800
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:BITE:HURT:3d5
+B:BITE:HURT:3d5
+F:FORCE_MAXHP | SUSCEP_FIRE | REGENERATE |
+F:DROP_90 | REGENERATE | FRIENDS |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | TROLL | IM_POIS | NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+D:An corruption of Morgoth, it was made in mockery of the Ents.
+D:A massive troll, equipped with a scimitar and heavy armour.
+
+N:632:Disenchanter worm mass
+G:w:v
+I:100:10d8:7:5:10
+W:40:3:50:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CRAWL:UN_BONUS:1d4
+F:RAND_50 | RES_DISE | ATTR_MULTI | CAN_SWIM |
+F:STUPID | WEIRD_MIND | BASH_DOOR |
+F:ANIMAL | HURT_LITE | NO_FEAR | BASEANGBAND | NO_CUT
+S:MULTIPLY
+D:It is a strange mass of squirming worms. Magical energy crackles
+D:around its disgusting form.
+
+N:633:Rotting quylthulg
+G:Q:u
+I:120:48d10:20:1:0
+W:45:1:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_UNDEAD
+D:It is a pulsing flesh mound that reeks of death and putrefaction.
+
+N:634:Lesser titan
+G:P:y
+I:120:24d100:30:80:15
+W:56:3:30000:6000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:CONFUSE:9d9
+B:HIT:CONFUSE:9d9
+B:HIT:CONFUSE:9d9
+B:HIT:CONFUSE:9d9
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:DROP_GOOD | DROP_4D2 | DROP_SKELETON | DROP_CORPSE |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | MALE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | TELE_TO | SCARE |
+S:S_MONSTERS
+D:It is a humanoid figure thirty feet tall that gives off an aura of power
+D:and hate.
+
+N:635:9-headed hydra
+G:M:r
+I:120:100d12:20:95:20
+W:40:2:8000:3000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:FIRE:3d10
+B:BITE:FIRE:3d10
+B:BITE:FIRE:3d10
+B:BITE:FIRE:3d10
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:ONLY_GOLD | DROP_3D2 | DROP_4D2 | CAN_SWIM |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | DROP_CORPSE |
+F:ANIMAL | IM_FIRE | MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:SCARE | BO_FIRE | BR_FIRE
+D:A strange reptilian creature with nine smouldering heads.
+
+N:636:Enchantress
+G:p:R
+I:130:52d10:20:60:10
+W:40:4:1700:2100
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:HIT:HURT:2d8
+F:FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:BLIND |
+S:S_DRAGON
+D:This elusive female spellcaster has a special affinity for dragons, whom
+D:she rarely fights without.
+
+N:637:Ranger chieftain
+G:p:W
+I:120:50d20:20:60:10
+W:41:2:1800:1800
+E:1:1:1:2:1:1
+O:30:50:20:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:MALE | INVISIBLE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | TAKE_ITEM |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP | IM_FIRE | IM_ELEC | IM_COLD | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:S_MONSTERS |
+S:ARROW_2 | ARROW_3 | ARROW_4 | MISSILE | BO_FIRE | BO_ELEC | BA_COLD |
+S:HASTE | BLINK | S_ANIMALS
+D:A chieftain among the Rangers. His understanding of nature gives him
+D:powerful elemental spells to use against you, in addition to his skills
+D:as an archer and a warrior. Furthermore, he is a master of camouflage, so
+D:you will need magically enhanced seeing to spot him.
+
+N:638:Sorcerer
+G:p:R
+I:130:52d10:20:60:10
+W:40:2:1700:2150
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_90 | DROP_4D2 |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:BLINK | TELE_TO | BLIND | CONF | CAUSE_3 | TRAPS |
+S:BO_ACID | BA_FIRE | BA_COLD |
+S:S_MONSTER | S_UNDEAD | S_DRAGON
+D:A human figure in robes, he moves with magically improved speed, and his
+D:hands are ablur with spellcasting.
+
+N:639:Xaren
+G:X:s
+I:120:32d10:20:80:10
+W:40:1:500000:1200
+E:0:0:0:3:0:0
+O:0:0:0:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+F:FORCE_MAXHP | SUSCEP_ACID |
+F:EMPTY_MIND | COLD_BLOOD |
+F:ONLY_GOLD | DROP_2D2 |
+F:KILL_ITEM | PASS_WALL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It is a tougher relative of the Xorn. Its hide glitters with metal ores.
+
+# New monster added by furiosity for the Theme module
+N:640:Giant green bat
+G:b:G
+I:130:3d8:12:20:50
+W:20:2:600:18
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:TERRIFY:1d3
+B:CLAW:LOSE_INT:1d2
+B:CLAW:DISEASE:1d2
+F:RAND_50 | CAN_FLY | WILD_TOO | WILD_MOUNTAIN | WILD_WOOD |
+F:FORCE_SLEEP | ANIMAL | DROP_CORPSE | AI_ANNOY |
+F:MORTAL | BASEANGBAND
+D:A giant bat which is an expert at disguise in a forest.
+
+# New monster added by furiosity for the Theme module
+N:641:Death vortex
+G:v:D
+I:130:40d20:100:40:0
+W:60:2:0:6000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:LOSE_ALL:5d5
+B:ENGULF:EXP_80:5d5
+B:ENGULF:LOSE_ALL:5d5
+B:ENGULF:EXP_80:5d5
+F:FORCE_SLEEP | CAN_FLY |
+F:RAND_50 | RAND_25 | RES_DISE | RES_NETH | RES_NEXU |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | BASEANGBAND | NO_CUT
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | RES_PLAS |
+S:1_IN_6 |
+S:ANIM_DEAD | BO_MANA | DARKNESS | BA_DARK | DRAIN_MANA |
+D:A whirlpool of darkness that smells like death and decay.
+
+# New monster added by furiosity for the Theme module
+N:642:Gas vortex
+G:v:g
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:POISON:3d3
+F:FORCE_SLEEP | RAND_50 | CAN_FLY | WILD_WASTE |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | WILD_TOO |
+F:IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP |
+F:NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT |
+S:1_IN_6 |
+S:BR_POIS |
+D:A whirlpool of noxious gases.
+
+N:643:Death drake
+G:D:G
+I:120:21d100:25:100:80
+W:45:2:170000:10000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:EXP_80:7d10
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | RES_TELE
+F:INVISIBLE | TAKE_ITEM | CAN_FLY |
+F:PASS_WALL | POWERFUL | MOVE_BODY | RES_NETH |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_NETH
+D:It is a dragon-like form wrapped in darkness. You cannot make out its
+D:true form but you sense its evil.
+
+N:644:Ancient red dragon
+G:D:r
+I:120:10d100:20:90:80
+W:41:1:170000:2500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d9
+B:CLAW:HURT:4d9
+B:BITE:FIRE:7d9
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:DROP_3D2 | DROP_4D2 | CAN_FLY | SUSCEP_COLD |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_FIRE
+D:A huge draconic form. Wisps of smoke steam from its nostrils and the
+D:extreme heat surrounding it makes you gasp for breath.
+
+N:645:Ancient gold dragon
+G:D:y
+I:120:10d100:20:90:80
+W:41:1:170000:2500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d9
+B:CLAW:HURT:4d9
+B:BITE:HURT:7d9
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:DROP_3D2 | DROP_4D2 | CAN_FLY |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | NO_STUN | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN
+D:A huge draconic form wreathed in a nimbus of light. Its roar stuns and
+D:deafens you.
+
+N:646:Great crystal drake
+G:D:U
+I:120:21d100:25:100:80
+W:45:2:170000:10000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:HURT:7d10
+F:FORCE_SLEEP | FORCE_MAXHP | REFLECTING | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | CAN_FLY |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_6 |
+S:SLOW | CONF | SCARE |
+S:BR_SHAR
+D:A huge crystalline dragon. Its claws could cut you to shreds and its
+D:teeth are razor sharp. Strange colours ripple through it as it moves in
+D:the light.
+
+# New monster added by furiosity for the Theme module
+N:647:Mana vortex
+G:v:y
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:LOSE_ALL:3d3
+F:FORCE_SLEEP | RAND_50 | CAN_FLY | WILD_WASTE |
+F:EMPTY_MIND | BASH_DOOR | WILD_TOO | POWERFUL |
+F:IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP |
+F:NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT |
+S:1_IN_8 |
+S:BR_MANA |
+D:A whirlpool of pure magical energy.
+
+N:648:Helcungol
+G:U:W
+I:110:40d10:20:50:80
+W:40:2:2700:2000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:STING:POISON:3d4
+B:SPIT:COLD:3d4
+B:HIT:HURT:3d4
+B:CRUSH:HURT:8d12
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:FRIENDS |
+F:ONLY_ITEM | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | IM_FIRE |
+F:EVIL | DEMON | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_8 |
+S:BLIND | CONF | SLOW
+D:One of the spider demons, spawn of Ungoliant. It looks like
+D:a giant bloated spider and its claws are icy cold.
+
+N:649:Lygrog
+G:u:D
+I:130:44d10:20:80:0
+W:40:3:600:1000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:BITE:LOSE_DEX:3d6
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | DROP_4D2 | NONLIVING |
+F:SMART | INVISIBLE | PASS_WALL | CAN_FLY |
+F:EVIL | DEMON | IM_FIRE | IM_POIS | RES_TELE
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_10 |
+S:BLIND | CONF | SCARE | CAUSE_3 | FORGET |
+S:S_DEMON
+D:Lygroeg are corrupted demonic snakelike forms, an evil creation
+D:of Morgoth.
+
+# New monster added by furiosity for the Theme module
+N:650:Slow vortex
+G:v:W
+I:80:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:PARALYZE:3d3
+F:FORCE_SLEEP | RAND_50 | CAN_FLY | WILD_WASTE |
+F:EMPTY_MIND | BASH_DOOR | WILD_TOO | POWERFUL |
+F:NO_FEAR | NO_CONF | NO_SLEEP |
+F:NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT |
+S:1_IN_8 |
+S:BR_INER | BR_GRAV |
+D:A whirlpool of inertia and gravity, twisting slowly.
+
+# New monster added by furiosity for the Theme module
+N:651:Nether vortex
+G:v:G
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:EXP_40:3d3
+F:FORCE_SLEEP | RAND_50 | CAN_FLY | WILD_WASTE |
+F:EMPTY_MIND | BASH_DOOR | WILD_TOO | POWERFUL |
+F:IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP |
+F:NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT |
+S:1_IN_8 |
+S:BR_NETH |
+D:A whirlpool of nether forces.
+
+# New monster added by furiosity for the Theme module
+N:652:Puzzling vortex
+G:v:U
+I:110:9d9:100:30:0
+W:21:1:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:CONFUSE:3d3
+F:FORCE_SLEEP | RAND_50 | CAN_FLY | WILD_WASTE |
+F:EMPTY_MIND | BASH_DOOR | WILD_TOO | POWERFUL |
+F:IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP |
+F:NONLIVING | BASEANGBAND | HAS_LITE | NO_CUT |
+S:1_IN_8 |
+S:BR_CONF |
+D:A whirlpool of something strange.
+
+# New monster added by furiosity for the Theme module
+N:653:Dark yeek
+G:y:D
+I:110:4d8:18:18:10
+W:8:1:800:15
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:3d6
+F:DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID |
+F:MORTAL | BASEANGBAND
+S:1_IN_9
+S:S_KIN | CAUSE_1
+D:It is a strange small humanoid with a malevolent stare.
+
+N:654:Judge Fire
+G:s:R
+I:120:18d100:90:70:10
+W:41:3:0:12000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:FIRE:5d5
+B:HIT:FIRE:5d5
+B:GAZE:EXP_80
+B:WAIL:TERRIFY
+F:UNIQUE | MALE | CAN_SPEAK | SUSCEP_COLD |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | POWERFUL |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | SUSCEP_COLD | IM_POIS | IM_FIRE | RES_PLAS |
+F:NO_CONF | NO_SLEEP | JOKEANGBAND | HAS_LITE | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:CAUSE_3 | BO_FIRE | BA_FIRE | BR_FIRE | BO_PLAS
+S:DARKNESS | S_MONSTER | S_DEMON | S_UNDEAD | TPORT | BLINK | SCARE
+D:One of the Dark Judges, he has come to punish your crime of living.
+D:He looks like a skeleton enveloped in flames.
+
+# New monster added by furiosity for the Theme module
+N:655:White yeek
+G:y:w
+I:110:4d8:18:18:10
+W:8:1:800:11
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID | IM_COLD |
+F:MORTAL | BASEANGBAND
+S:1_IN_10
+S:BO_COLD | BO_ICEE |
+D:It is a strange small humanoid adapted to cold environments.
+
+N:656:Judge Mortis
+G:z:G
+I:120:18d100:90:70:10
+W:41:3:0:13000
+E:1:1:1:2:1:1
+O:0:75:0:15
+B:HIT:POISON:5d5
+B:HIT:DISEASE:5d5
+B:TOUCH:LOSE_ALL
+B:TOUCH:EXP_80
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | SUSCEP_FIRE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | JOKEANGBAND | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:BLIND | SCARE | CAUSE_3 | BO_ACID | BO_NETH | BR_POIS |
+S:BR_NETH | BO_NETH | BLINK | TPORT | ANIM_DEAD
+S:BO_POIS | S_UNDEAD
+D:Another Dark Judge, he is a rotting humanoid with a cow's skull as
+D:his head.
+
+N:657:Dark elven sorcerer
+G:h:R
+I:130:80d10:20:70:10
+W:41:2:1300:3000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+B:HIT:HURT:2d8
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
+F:ONLY_ITEM | DROP_90 | DROP_4D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | BLINK | TELE_TO | BLIND | CONF | CAUSE_3 | DARKNESS |
+S:BO_ACID | BA_FIRE | BA_COLD | ANIM_DEAD
+S:S_MONSTER | S_UNDEAD | S_DEMON | MISSILE
+D:A dark elven figure, dressed in deepest black. Power seems to crackle
+D:from his slender frame.
+
+N:658:Master lich
+G:L:r
+I:120:18d100:20:80:50
+W:41:2:1800:7000
+E:1:1:1:2:1:1
+O:10:45:25:10
+B:TOUCH:EXP_80
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:2d12
+B:TOUCH:LOSE_DEX:2d12
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_TELE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | BLIND | HOLD | CONF | SCARE | CAUSE_3 | CAUSE_4 |
+S:DRAIN_MANA | BRAIN_SMASH | S_UNDEAD
+D:A skeletal form wrapped in robes. Powerful magic crackles along its
+D:bony fingers.
+
+# New monster added by furiosity for the Theme module
+N:659:Gray yeek
+G:y:s
+I:110:4d8:18:18:10
+W:8:1:800:11
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID |
+F:MORTAL | BASEANGBAND
+S:1_IN_6
+S:BO_ACID |
+D:It is a strange small humanoid cloaked in gray. You notice
+D:some suspicious-looking vials in his pack.
+
+N:660:Eol, the Dark Elf
+G:h:D
+I:130:80d30:20:100:60
+W:49:2:1400:25000
+E:1:1:1:2:1:1
+O:10:40:40:10
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | CAN_SPEAK |
+F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GOOD | DROP_CHOSEN |
+F:SMART | IM_ELEC | IM_COLD | IM_POIS | IM_FIRE |
+F:REFLECTING | OPEN_DOOR | BASH_DOOR | SPECIAL_GENE |
+F:HURT_LITE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | BLINK | TELE_TO | BLIND | CONF | CAUSE_4 | DARKNESS |
+S:BA_NETH | BA_ELEC | BA_ACID | BA_FIRE | BA_COLD | BO_MANA |
+S:S_MONSTERS | S_UNDEAD | S_DRAGON | S_DEMON
+D:A lord of the Teleri, Eol is a mighty metalsmith, the first
+D:one to ever forge weapons of meteorite iron. His dark
+D:countenance glares at you in disdain.
+
+# New monster added by furiosity for the Theme module
+N:661:Yellow yeek
+G:y:y
+I:110:4d8:18:18:10
+W:8:1:800:11
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:1_IN_7 |
+S:BA_POIS
+D:It is a strange small humanoid. He's strangely stinky.
+
+# New monster added by furiosity for the Theme module
+# A brown yeek with the PET flag.
+N:662:Adventurer yeek
+G:y:U
+I:110:4d8:18:18:10
+W:8:1:800:11
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID | PET |
+F:MORTAL | BASEANGBAND
+D:It is a strange small humanoid, a fellow adventurer.
+
+# New monster added by furiosity for the Theme module
+N:663:Dark mushroom patch
+G:,:D
+I:110:1d2:2:1:0
+W:8:1:10:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:EXP_10:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_10 |
+S:DARKNESS
+D:Yum! It looks quite tasty.
+
+N:664:Undead beholder
+G:e:u
+I:120:27d100:30:100:10
+W:45:3:1600:8000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:EXP_40:3d6
+B:GAZE:UN_POWER:3d6
+B:GAZE:INSANITY:3d6
+B:BITE:EXP_40:7d6
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE |
+F:COLD_BLOOD | BASH_DOOR |
+F:EVIL | UNDEAD | CAN_FLY |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:SLOW | CONF | CAUSE_4 | DRAIN_MANA | MIND_BLAST | FORGET |
+S:BO_MANA | BO_NETH | BRAIN_SMASH | BA_FIRE | BA_COLD | BO_ACID |
+S:S_UNDEAD | ANIM_DEAD
+D:A beholder which has cheated death. Black nether storms rage around the
+D:bloodshot pupil of its central giant eye, and light seems to bend as it
+D:sucks its power from the very air around it. Your soul chills as it drains
+D:your vitality for its evil enchantments.
+
+N:665:Shadow
+G:G:D
+I:120:10d20:30:30:20
+W:37:3:0:400
+E:0:0:0:0:0:0
+O:90:10:0:0
+B:TOUCH:EXP_80
+B:TOUCH:EXP_40
+B:CLAW:LOSE_INT:1d10
+B:CLAW:LOSE_WIS:1d10
+F:FORCE_SLEEP | CAN_FLY |
+F:ONLY_ITEM | DROP_1D2 | POWERFUL | REGENERATE | HURT_LITE |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | RES_NETH |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_8 |
+S:BO_NETH | TELE_TO | SLOW
+D:A mighty spirit of darkness of vaguely humanoid form. Razor-edged claws
+D:reach out to end your life as it glides towards you, seeking to suck the
+D:energy from your soul to feed its power.
+
+N:666:Iron lich
+G:L:W
+I:120:22d100:30:100:10
+W:42:4:0:10000
+E:0:0:0:0:1:0
+O:0:0:100:0
+B:BUTT:COLD:3d6
+B:BUTT:FIRE:3d6
+B:BUTT:ELEC:3d6
+F:FORCE_SLEEP | FORCE_MAXHP | REFLECTING |
+F:COLD_BLOOD | BASH_DOOR | CAN_FLY | SUSCEP_ACID |
+F:EVIL | UNDEAD | POWERFUL | SMART |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | RES_TELE |
+F:ONLY_ITEM | DROP_60 | DROP_GOOD |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:BA_WATE | BA_FIRE | BO_ICEE | BA_ELEC | BA_COLD |
+S:CAUSE_4 | DRAIN_MANA | BRAIN_SMASH | S_UNDEAD
+D:It is a huge, twisted grey skull floating through the air. Its cold eyes
+D:burn with hatred towards all who live.
+
+N:667:Dread
+G:G:o
+I:120:25d20:20:30:10
+W:42:1:1000:600
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:LOSE_STR:3d4
+F:FORCE_SLEEP |
+F:RAND_25 | FRIENDS | CAN_FLY |
+F:ONLY_ITEM | DROP_60 |
+F:TAKE_ITEM | INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_15 |
+S:BLIND | HOLD | CONF | DRAIN_MANA | BO_NETH
+D:Death incarnate, its hideous black body seems to struggle against
+D:reality as the universe itself struggles to banish it.
+
+N:668:Greater basilisk
+G:R:D
+I:120:20d100:25:100:15
+W:42:2:3000:10000
+E:0:1:0:2:1:0
+O:0:50:50:0
+B:GAZE:PARALYZE:3d12
+B:GAZE:PARALYZE:3d12
+B:BITE:POISON:2d12
+B:BITE:POISON:2d12
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | POWERFUL |
+F:OPEN_DOOR | BASH_DOOR | EVIL | IM_POIS | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP | CAN_SWIM |
+F:MORTAL | BASEANGBAND
+S:1_IN_8
+S:BR_POIS | BR_DARK | BR_NEXU
+D:A large basilisk, whose shape resembles that of a great worm.
+
+# New monster added by furiosity for the Theme module
+N:669:White mushroom patch
+G:,:w
+I:110:1d2:2:1:0
+W:1:1:10:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:COLD:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+# New monster added by furiosity for the Theme module
+N:670:Brown mushroom patch
+G:,:u
+I:110:1d2:2:1:0
+W:1:1:10:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:DISEASE:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+# New monster added by furiosity for the Theme module
+N:671:Silver mushroom patch
+G:,:W
+I:110:1d2:2:1:0
+W:1:1:10:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:EAT_LITE:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+# New monster added by furiosity for the Theme module
+N:672:Green mushroom patch
+G:,:G
+I:110:1d2:2:1:0
+W:1:1:10:1
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:1d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:Yum! It looks quite tasty.
+
+N:673:Mumak
+G:q:s
+I:110:90d10:20:55:100
+W:63:2:150000:2100
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BUTT:HURT:8d6
+B:BUTT:HURT:8d6
+B:CRUSH:HURT:8d4
+F:FRIENDS | DROP_CORPSE |
+F:BASH_DOOR | ANIMAL | MORTAL | BASEANGBAND
+D:A massive elephantine form with eyes twisted by madness.
+
+N:674:Judge Fear
+G:W:y
+I:120:18d100:90:70:10
+W:43:4:0:12000
+E:1:1:1:2:1:1
+O:100:0:0:0
+B:GAZE:TERRIFY
+B:GAZE:EXP_40
+B:GAZE:EXP_40
+B:GAZE:HURT:2d20
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | JOKEANGBAND | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | MIND_BLAST | BRAIN_SMASH |
+S:S_UNDEAD | DRAIN_MANA | FORGET | ANIM_DEAD
+D:A Dark Judge, reputedly so frightening that his gaze can kill.
+
+N:675:Ancient multi-hued dragon
+G:D:v
+I:120:21d100:25:100:80
+W:43:1:170000:13000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:HURT:7d10
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_ACID | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BLIND | CONF | SCARE |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS
+D:A huge draconic form. Many colours ripple down its massive frame. Few
+D:live to see another.
+
+N:676:Ethereal dragon
+G:D:o
+I:120:21d100:25:100:80
+W:45:2:170000:10000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:HURT:7d10
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 |
+F:INVISIBLE | CAN_FLY |
+F:PASS_WALL | POWERFUL | MOVE_BODY |
+F:DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | CONF |
+S:BR_LITE | BR_DARK | BR_CONF
+D:A huge dragon emanating from the ethereal plane, this terrible dragon is
+D:a master of light and dark. Its form disappears from sight as it cloaks
+D:itself in unearthly shadows.
+
+# New monster added by furiosity for the Theme module
+N:677:Dark elemental
+G:E:D
+I:110:30d8:12:50:50
+W:33:2:0:350
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:BLIND:4d6
+B:HIT:EAT_LITE:4d6
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | CAN_FLY | WILD_TOO | WILD_VOLCANO |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_POIS | IM_ELEC | IM_ACID |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BR_DARK
+D:It is a twisting pillar of pure darkness.
+
+# New monster added by furiosity for the Theme module
+N:678:Slow elemental
+G:E:s
+I:100:30d8:12:50:50
+W:33:2:0:350
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:PARALYZE:4d6
+B:HIT:PARALYZE:4d6
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | CAN_FLY | WILD_TOO | WILD_VOLCANO |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_POIS | IM_ELEC | IM_ACID |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BR_INER
+D:It is a slowly twisting pillar of energy.
+
+N:679:Quaker, Master of Earth
+G:E:u
+I:110:28d100:10:97:90
+W:43:3:0:4500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:SHATTER:10d10
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:EMPTY_MIND | COLD_BLOOD | KILL_WALL |
+F:KILL_ITEM | KILL_BODY | PASS_WALL | POWERFUL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT | NO_STUN
+S:1_IN_6 |
+S:BO_ACID | BA_ACID
+D:A towering stone elemental stands before you. The walls and ceiling are
+D:reduced to rubble as Quaker advances.
+
+N:680:Death leprawn
+G:l:D
+I:120:6d6:8:13:8
+W:44:6:0:85
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:TOUCH:EXP_40:1d10
+B:TOUCH:EAT_GOLD
+B:TOUCH:EAT_ITEM
+F:INVISIBLE | RAND_25 | TAKE_ITEM | COLD_BLOOD | SMART |
+F:HURT_LITE | EVIL | OPEN_DOOR | MALE | UNDEAD | RES_NETH | JOKEANGBAND | NO_CUT
+S:MULTIPLY |
+S:1_IN_6 |
+S:BLINK | TPORT | TELE_TO | CAUSE_3 | ANIM_DEAD
+D:Nasty undead little gnomes.
+
+# New monster added by furiosity for the Theme module
+N:681:Chaos elemental
+G:E:v
+I:110:30d8:12:50:50
+W:33:2:0:350
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:EXP_40:4d6
+B:HIT:INSANITY:4d6
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | CAN_FLY | WILD_TOO | WILD_VOLCANO |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_POIS | IM_ELEC | IM_ACID | ELDRITCH_HORROR |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BR_CHAO
+D:It is a massive tornado of raw chaos.
+
+# New monster added by furiosity for the Theme module
+N:682:Confusion elemental
+G:E:U
+I:110:30d8:12:50:50
+W:33:2:0:350
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:CONFUSE:4d6
+B:HIT:CONFUSE:4d6
+F:FORCE_SLEEP | RAND_25 |
+F:EMPTY_MIND | CAN_FLY | WILD_TOO | WILD_VOLCANO |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_FIRE | IM_POIS | IM_ELEC | IM_ACID |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6 |
+S:BR_CONF
+D:It is confusing sight to behold.
+
+# New monster added by furiosity for the Theme module
+N:683:Large blue snake
+G:J:b
+I:100:4d8:5:38:75
+W:4:1:1000:9
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:CRUSH:ELEC:1d6
+F:RAND_25 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE
+F:BASH_DOOR | HAS_EGG | ANIMAL | MORTAL | BASEANGBAND | IM_ELEC |
+D:It is about ten feet long, its lithe form crackling with sparks.
+
+# New monster added by furiosity for the Theme module
+N:684:Large silver snake
+G:J:W
+I:100:4d8:5:38:75
+W:4:1:1000:9
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:CRUSH:EAT_LITE:1d6
+F:RAND_25 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE
+F:BASH_DOOR | HAS_EGG | ANIMAL | MORTAL | BASEANGBAND
+D:It is about ten feet long, and seems to feed on light.
+
+# New monster added by furiosity for the Theme module
+N:685:Large purple snake
+G:J:v
+I:100:4d8:5:38:75
+W:2:1:1000:9
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:LOSE_CON:1d4
+B:CRUSH:HURT:1d6
+F:RAND_25 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE
+F:BASH_DOOR | HAS_EGG | ANIMAL | MORTAL | BASEANGBAND
+D:It is about ten feet long and looks diseased.
+
+N:686:Judge Death
+G:W:R
+I:120:45d50:90:90:10
+W:43:3:0:14000
+E:1:1:1:2:1:1
+O:0:20:80:0
+B:CLAW:POISON:10d5
+B:CLAW:POISON:10d5
+B:CLAW:EXP_40:10d1
+B:GAZE:TERRIFY
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_ELEC | IM_COLD | SUSCEP_FIRE |
+F:IM_POIS | NO_CONF | NO_SLEEP | JOKEANGBAND | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_4 | BA_FIRE | BA_NETH | ANIM_DEAD
+S:S_MONSTERS | S_UNDEAD | S_HI_UNDEAD | DRAIN_MANA |
+D:The most powerful Dark Judge, whose touch means death.
+
+N:687:Ariel, Queen of Air
+G:E:B
+I:130:27d100:12:50:50
+W:43:3:0:4750
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:4d6
+B:HIT:CONFUSE:4d4
+B:HIT:HURT:4d6
+B:HIT:CONFUSE:4d4
+F:UNIQUE | FEMALE | AURA_ELEC | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:RAND_25 | CAN_FLY |
+F:EMPTY_MIND | COLD_BLOOD |
+F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
+F:IM_ACID | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BO_ELEC | BA_COLD | BA_ELEC
+D:A towering air elemental, Ariel the sorceress avoids your blows
+D:with her extreme speed.
+
+N:688:11-headed hydra
+G:M:R
+I:120:100d18:20:100:20
+W:44:2:8500:6000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+B:BITE:FIRE:3d12
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:ONLY_GOLD | DROP_2D2 | DROP_4D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:ANIMAL | IM_FIRE | CAN_SWIM |
+F:MORTAL | BASEANGBAND
+S:1_IN_4 |
+S:SCARE | BO_FIRE | BO_PLAS | BA_FIRE | BR_FIRE
+D:A strange reptilian hybrid with eleven smouldering heads.
+
+N:689:Patriarch
+G:p:G
+I:120:52d10:20:60:10
+W:40:2:1800:1800
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:HIT:HURT:3d4
+B:HIT:HURT:3d4
+B:HIT:HURT:3d5
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | BLIND | HOLD | CAUSE_4 | CAUSE_3 | ANIM_DEAD |
+S:S_MONSTERS | S_UNDEAD
+D:An evil priest, dressed all in black. Deadly spells hit you at an
+D:alarming rate as his black spiked mace rains down blow after blow on your
+D:pitiful frame.
+
+N:690:Dreadmaster
+G:G:y
+I:120:12d100:20:100:10
+W:44:2:1000:8000
+E:0:0:0:0:0:0
+O:10:40:25:10
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:LOSE_STR:3d4
+B:HIT:LOSE_STR:3d4
+F:FORCE_SLEEP | FORCE_MAXHP | RAND_25 |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | CAN_FLY |
+F:SMART | TAKE_ITEM | INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_9 |
+S:TELE_LEVEL | BLIND | HOLD | CONF | CAUSE_4 | DRAIN_MANA | BO_NETH |
+S:S_UNDEAD
+D:It is an unlife of power almost unequalled. An affront to existence, its
+D:very touch abuses and disrupts the flow of life, and its unearthly limbs,
+D:of purest black, crush rock and flesh with ease.
+
+N:691:Drolem
+G:g:g
+I:120:30d100:25:130:30
+W:44:3:40000:12000
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d10
+B:CLAW:HURT:3d10
+B:BITE:POISON:5d10
+B:BITE:POISON:5d10
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE |
+F:EMPTY_MIND | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:DRAGON | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+F:ATTR_MULTI
+S:1_IN_6 |
+S:BLIND | SLOW | CONF | ARROW_3 |
+S:BR_POIS
+D:A constructed dragon, the drolem has massive strength. Powerful spells
+D:weaved during its creation make it a fearsome adversary. Its eyes show
+D:little intelligence, but it has been instructed to destroy all it meets.
+
+N:692:Scatha the Worm
+G:D:W
+I:120:22d100:30:130:70
+W:46:2:210000:17000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:COLD:4d14
+B:BITE:COLD:4d14
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | SUSCEP_FIRE |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_CORPSE
+F:BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
+F:EVIL | DRAGON | IM_COLD | NO_CONF | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:CONF | CAUSE_3 |
+S:BR_COLD
+D:An ancient and wise Dragon. Scatha has grown clever over the long years.
+D:His scales are covered with frost, and his breath sends a shower of ice
+D:into the air.
+
+N:693:Warrior of the Dawn
+G:p:R
+I:120:25d25:20:70:20
+W:45:2:1600:500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:IM_POIS | IM_FIRE | IM_ELEC | IM_ACID | IM_COLD |
+F:NO_SLEEP | NO_FEAR |
+F:FRIENDS |
+F:MALE | OPEN_DOOR | BASH_DOOR | JOKEANGBAND | HAS_LITE
+D:Fierce, barbaric warriors, armed with great spiked clubs, and surrounded
+D:in an aura of scarlet. Whenever one of them is slain, another appears
+D:out of nowhere to take his place.
+
+N:694:Lesser black reaver
+G:L:s
+I:120:25d100:20:120:50
+W:45:3:2600:12000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:HIT:UN_BONUS:4d8
+B:HIT:UN_BONUS:4d8
+B:HIT:LOSE_STR:4d6
+B:HIT:LOSE_STR:4d6
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | CAN_SWIM |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | RES_TELE
+F:NO_CONF | NO_SLEEP | KILL_WALL | NO_FEAR
+F:BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:TELE_TO | BLIND | HOLD | CONF | CAUSE_3 | DRAIN_MANA |
+S:MIND_BLAST | BA_NETH | ANIM_DEAD
+D:A humanoid form, black as night, advancing steadily and unstoppably.
+
+# New monster added by furiosity for the Theme module
+N:695:Large red snake
+G:J:R
+I:100:4d8:5:38:75
+W:4:1:1000:10
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:CRUSH:FIRE:1d6
+F:RAND_25 | CAN_SWIM | WILD_TOO | DROP_SKELETON | DROP_CORPSE
+F:BASH_DOOR | HAS_EGG | ANIMAL | MORTAL | BASEANGBAND
+D:It is about ten feet long, its form glowing with fire.
+
+N:696:Grand master thief
+G:p:b
+I:130:15d100:50:75:40
+W:46:2:0:1500
+E:1:1:1:2:1:1
+O:70:10:10:10
+B:HIT:EAT_ITEM:5d5
+B:HIT:EAT_ITEM:5d5
+B:HIT:EAT_GOLD:5d5
+B:HIT:EAT_GOLD:5d5
+F:MALE | DROP_2D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT | TELE_TO | CONF | TRAPS | ARROW_2
+D:A class of its own: you are already too late to protect your possessions -
+D:and he seems to have studied magic too, and is a master of setting traps.
+
+N:697:Smaug the Golden
+G:D:R
+I:120:24d100:30:150:80
+W:48:2:230000:23000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:FIRE:5d14
+B:BITE:FIRE:5d14
+F:UNIQUE | MALE | REFLECTING | CAN_FLY | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SPEAK | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:SMART | EVIL | DRAGON | IM_FIRE | BASEANGBAND
+F:HAS_LITE
+S:1_IN_4 |
+S:CONF | CAUSE_3 |
+S:BR_FIRE
+D:Smaug is one of the great dragons that still survive, a fire-drake of immense
+D:cunning and intelligence. His speed through air is matched by few other
+D:dragons, his dragonfire is what legends are made of, and his hide is
+D:armoured with diamonds: he is believed to be the greatest dragon still
+D:surviving into the Third Age.
+
+N:698:The Stormbringer
+G:|:D
+I:120:13d123:20:99:20
+W:45:2:0:13333
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:WAIL:TERRIFY
+B:HIT:EXP_80:64d1
+B:HIT:EXP_80:64d1
+B:HIT:EXP_80:8d8
+F:CHAR_MULTI | EVIL | IM_POIS | IM_COLD | IM_FIRE | RES_NETH |
+F:FORCE_SLEEP | UNIQUE | FORCE_MAXHP | CAN_FLY |
+F:COLD_BLOOD | BASH_DOOR | NONLIVING |
+F:NO_CONF | NO_SLEEP | NO_FEAR | JOKEANGBAND | HAS_LITE | NO_CUT | NO_STUN
+D:The mightiest of hellblades, a black runesword which thirsts for
+D:your soul.
+
+N:699:Knight Templar
+G:p:w
+I:120:60d20:20:60:10
+W:44:2:1800:2000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:IM_POIS | IM_FIRE | IM_ELEC | IM_ACID | IM_COLD | GOOD |
+F:RES_NETH | RES_NEXU | RES_DISE | RES_TELE | DROP_SKELETON | DROP_CORPSE
+F:NO_SLEEP | NO_CONF | NO_FEAR | NO_STUN |
+F:DROP_2D2 | DROP_90 | REFLECTING |
+F:MALE | OPEN_DOOR | BASH_DOOR | FORCE_MAXHP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:HEAL | CAUSE_3 | CAUSE_4 | HASTE | SCARE | BLIND |
+D:It seems that the more devout the person, the more likely they are to cross
+D:the boundary between piety and sanctimoniousness. And such is the case with
+D:the Order of the Knights Templar; they are among the most pious and
+D:powerful of the religious knightly orders, but noted for their intolerance.
+D:Thus it is Morgoth's will that is unwittingly done, as the forces of good
+D:are set against each other.
+
+# New monster added by furiosity for the Theme module
+N:700:Large eel
+G:J:U
+I:100:4d8:5:38:75
+W:2:1:1000:9
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d4
+B:CRUSH:TERRIFY:1d6
+F:RAND_25 | CAN_SWIM | WILD_ONLY | DROP_SKELETON | DROP_CORPSE | WILD_SHORE
+F:BASH_DOOR | HAS_EGG | ANIMAL | MORTAL | BASEANGBAND | NEUTRAL | NO_TARGET |
+D:It is about ten feet long. Its survival depends on being
+D:confused for a much more dangerous snake.
+
+N:701:Dracolich
+G:D:G
+I:120:35d100:25:120:80
+W:55:2:180000:18000
+E:0:1:0:6:1:0
+O:10:50:40:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:EXP_80:7d14
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | RES_TELE |
+F:COLD_BLOOD | CAN_FLY |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT | ATTR_MULTI
+S:1_IN_6 |
+S:CONF | SCARE |
+S:BR_COLD | BR_NETH
+D:The skeletal form of a once-great dragon, enchanted by magic most
+D:perilous. Its animated form strikes with speed and drains life from its
+D:prey to satisfy its hunger.
+
+N:702:Greater titan
+G:P:o
+I:120:38d100:30:125:15
+W:66:3:50000:23500
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:CONFUSE:12d12
+B:HIT:CONFUSE:12d12
+B:HIT:CONFUSE:12d12
+B:HIT:CONFUSE:12d12
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_4D2 | DROP_1D2 | DROP_GOOD | MOVE_BODY |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | MALE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | TELE_TO |
+S:S_MONSTERS
+D:A forty foot tall humanoid that shakes the ground as it walks. The power
+D:radiating from its frame shakes your courage, its hatred inspired by your
+D:defiance.
+
+N:703:Dracolisk
+G:D:R
+I:120:35d100:25:120:80
+W:55:2:180000:18000
+E:0:1:0:6:1:0
+O:0:50:40:10
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:FIRE:7d14
+B:GAZE:PARALYZE
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | RES_NEXU | RES_TELE |
+F:ANIMAL | EVIL | DRAGON | IM_ACID | IM_FIRE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:HOLD | SCARE |
+S:BR_FIRE | BR_NEXU
+D:A mixture of dragon and basilisk, the dracolisk stares at you with deep
+D:piercing eyes, its evil breath burning the ground where it stands.
+
+N:704:Winged Horror
+G:B:D
+I:120:25d80:30:80:5
+W:48:3:4500:4000
+B:CLAW:HURT:3d8
+B:CLAW:HURT:3d8
+B:BITE:EXP_40:4d6
+B:BITE:EXP_40:4d6
+F:ANIMAL | MORTAL | EVIL | CAN_FLY | BASH_DOOR | IM_COLD | IM_POIS
+F:WILD_TOO | WILD_WASTE | WILD_WOOD | WILD_SWAMP | BASEANGBAND
+S:1_IN_6
+S:BR_NETH | BR_DARK | BR_POIS
+D:A terrifying sight: a winged creature greater than any bird you have ever
+D:seen, and with no feathers on its horrid black leathery wings. Descended
+D:from a creature of an older world perhaps, bred by Sauron to be a winged
+D:steed for his Ringwraiths.
+
+# New monster added by furiosity for the Theme module
+N:705:Killer gray beetle
+G:K:s
+I:110:22d8:14:45:30
+W:27:1:600:95
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:SPIT:ACID:4d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | IM_ACID | CAN_FLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle surrounded by droplets of acid.
+
+# New monster added by furiosity for the Theme module
+N:706:Killer orange beetle
+G:K:o
+I:110:22d8:14:45:30
+W:27:1:600:95
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:SPIT:BLIND:4d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | CAN_FLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle with a corrosive spit.
+
+# New monster added by furiosity for the Theme module
+N:707:Killer blue beetle
+G:K:b
+I:110:22d8:14:45:30
+W:27:1:600:95
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:SPIT:ELEC:4d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | IM_ELEC | CAN_FLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle surrounded by sparks.
+
+N:708:Ent
+G:#:G
+I:110:40d100:30:120:15
+W:46:3:0:12500
+E:1:1:1:2:1:1
+O:30:50:20:0
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+F:FORCE_SLEEP | FORCE_MAXHP | PET | SUSCEP_FIRE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
+F:SMART | TAKE_ITEM | KILL_WALL | BASH_DOOR |
+F:GOOD | BASEANGBAND | NO_CUT
+D:Ents are some of the oldest creatures that awoke on Arda. It is a
+D:tree-herd: a sentient, moving tree. Its wrath is fearsome, and it could
+D:split stones and even the very rock of Isengard with its roots.
+
+N:709:Rock giant
+G:P:s
+I:120:40d100:30:150:15
+W:54:3:40000:14500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:SHATTER:12d13
+B:HIT:SHATTER:12d13
+B:HIT:SHATTER:12d13
+B:HIT:SHATTER:12d13
+F:FORCE_SLEEP | FORCE_MAXHP | HURT_ROCK |
+F:ONLY_GOLD | DROP_4D2 | MOVE_BODY | KILL_WALL |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | GIANT | MALE | HAS_LITE | NO_CUT
+D:A being made of living stone.
+
+N:710:Itangast the Fire Drake
+G:D:R
+I:120:22d100:30:120:70
+W:47:2:220000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d10
+B:CLAW:HURT:4d10
+B:BITE:FIRE:4d14
+B:BITE:FIRE:4d14
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | SUSCEP_COLD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | IM_FIRE | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:CONF | CAUSE_3 |
+S:BR_FIRE
+D:A mighty ancient dragon, Itangast's form scorches your flesh. Wisps of
+D:smoke curl up from his nostrils as he regards you with disdain.
+
+N:711:Death mold
+G:m:D
+I:140:100d20:200:60:0
+W:47:1:100:1000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:UN_BONUS:7d7
+B:SPORE:UN_BONUS:7d7
+B:SPORE:UN_BONUS:7d7
+B:SPORE:EXP_80:5d5
+F:FORCE_SLEEP | NEVER_MOVE | CAN_SWIM |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is the epitome of all that is evil, in a mold. Its lifeless form draws
+D:power from sucking the souls of those that approach it, a nimbus of pure
+D:evil surrounds it. Luckily for you, it can't move...
+
+# New monster added by furiosity for the Theme module
+N:712:Killer silver beetle
+G:K:W
+I:110:22d8:14:45:30
+W:27:1:600:95
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:SPIT:EAT_LITE:4d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | HURT_LITE | CAN_FLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle surrounded by a strange dark light.
+
+# New monster added by furiosity for the Theme module
+N:713:Killer green beetle
+G:K:G
+I:110:22d8:14:45:30
+W:27:1:600:95
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:SPIT:CONFUSE:4d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | NO_CONF | CAN_FLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle surrounded by a puzzling green aura.
+
+N:714:Quickbeam, the Ent
+G:#:G
+I:120:40d100:30:120:15
+W:47:3:0:13500
+E:1:1:1:2:1:1
+O:10:50:20:10
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+B:CRUSH:HURT:12d13
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | CAN_SPEAK |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY | SUSCEP_FIRE |
+F:SMART | TAKE_ITEM | KILL_WALL | BASH_DOOR |
+F:GOOD | PET | BASEANGBAND | NO_CUT
+D:Also known as Bregalad. Unusually hasty, for an ent. He hates evil creatures,
+D:orcs in particular, since the destruction of his beloved rowan-trees to feed the
+D:fires of Orthanc.
+
+N:715:Glaurung, Father of the Dragons
+G:D:R
+I:130:120d100:20:125:70
+W:70:2:300000:50000
+E:0:1:0:6:1:0
+O:30:70:0:0
+B:CLAW:HURT:5d12
+B:CLAW:HURT:5d12
+B:BITE:FIRE:8d14
+B:BITE:POISON:8d14
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_RANDART | KILL_TREES |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:SMART | EVIL | DRAGON | IM_POIS | IM_FIRE |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BLIND | CONF | SCARE | BRAIN_SMASH |
+S:BR_FIRE | BR_POIS | BR_SOUN | S_HI_DRAGON
+D:Glaurung is the father of all dragons, and was for a long time the most
+D:powerful. Though this is no longer so, he still has full command over
+D:his brood and can command them to appear whenever he so wishes. He is
+D:the definition of dragonfire.
+
+N:716:Behemoth
+G:H:B
+I:120:50d100:25:180:30
+W:49:3:6000:16000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:5d8
+B:BITE:HURT:5d8
+B:CRUSH:HURT:3d15
+B:CRUSH:HURT:3d15
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SWIM | ANIMAL | AQUATIC |
+F:IM_FIRE | IM_ACID | IM_COLD | IM_POIS | DROP_CORPSE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NEUTRAL | NO_TARGET |
+F:WILD_ONLY | WILD_SHORE | WILD_OCEAN | MORTAL | BASEANGBAND
+D:A great water-beast, with an almost unpenetrable skin.
+
+# New monster added by furiosity for the Theme module
+N:717:Killer aquatic beetle
+G:K:B
+I:110:22d8:14:45:30
+W:27:1:600:95
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:SPIT:COLD:4d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | RES_WATE | CAN_FLY | SUSCEP_FIRE |
+F:MORTAL | BASEANGBAND | HAS_LITE | AQUATIC |
+D:It is a giant beetle that prefers to live in water.
+
+N:718:Greater wall monster
+G:#:W
+I:120:15d40:20:80:20
+W:44:4:0:900
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:FORCE_SLEEP | COLD_BLOOD | EMPTY_MIND | PASS_WALL | RAND_50 |
+F:BASH_DOOR | IM_COLD | IM_ACID | IM_FIRE | IM_ELEC | IM_POIS | NONLIVING |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | CHAR_MULTI | CAN_FLY | BASEANGBAND
+F:NO_CUT
+S:MULTIPLY |
+D:A sentient, moving section of wall.
+
+N:719:Menelrog
+G:U:U
+I:120:40d120:20:80:80
+W:60:3:0:10000
+E:1:1:1:2:1:1
+O:50:0:50:0
+B:GAZE:TERRIFY
+B:HIT:POISON:6d6
+B:SPIT:FIRE:6d6
+B:SPIT:ACID:6d6
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE | NONLIVING |
+F:REGENERATE | IM_ACID | IM_COLD | IM_FIRE | CAN_FLY |
+F:NO_SLEEP | NO_STUN | NO_CONF | EVIL | DEMON | SMART |
+F:KILL_WALL | WILD_TOO |
+F:ONLY_ITEM | DROP_GREAT | DROP_GOOD | BASEANGBAND
+S:1_IN_4 |
+S:HOLD | BLINK | CONF | S_DEMON | BRAIN_SMASH | BO_PLAS
+D:Morgoth's horrific corruption of Manwe's Great Eagles, with the feathers
+D:devolved into scales, and the talons so powerful they can tear down
+D:stone walls. This demon is a power to be reckoned with; it is powerful
+D:in both combat and magic, and it's the only demon which may roam the wild.
+
+N:720:Mornungol
+G:U:s
+I:120:120d10:25:60:80
+W:55:2:0:3000
+E:1:1:1:2:1:1
+O:20:40:20:20
+B:HIT:HURT:4d10
+B:HIT:LOSE_CHR:10d2
+B:SPIT:ACID:4d10
+B:STING:POISON:5d5
+F:FORCE_SLEEP | FORCE_MAXHP | FRIENDS |
+F:ONLY_ITEM | DROP_1D2 | NONLIVING | BASEANGBAND |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON | IM_POIS | NO_CONF | NO_SLEEP
+S:1_IN_7 |
+S:SCARE | CONF
+D:One of the spider demons, spawn of Ungoliant. It looks like
+D:a giant bloated spider, and its claws are dripping with acid.
+
+# New monster added by furiosity for the Theme module
+N:721:Killer tree beetle
+G:K:U
+I:110:22d8:14:45:30
+W:27:1:600:95
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:SPIT:HALLU:4d5
+F:WEIRD_MIND | BASH_DOOR | WILD_TOO | DROP_CORPSE |
+F:ANIMAL | KILL_TREES | CAN_FLY | SUSCEP_COLD |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:It is a giant beetle, a relative of the termite.
+
+N:722:Nightwing
+G:W:D
+I:120:60d60:20:120:10
+W:61:4:0:10000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:TOUCH:POISON:6d5
+B:TOUCH:POISON:6d5
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | RES_TELE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLIND | SCARE | CAUSE_4 | BRAIN_SMASH |
+S:BO_MANA | BO_NETH | BA_NETH | S_UNDEAD
+D:Everywhere colours seem paler and the air chiller. At the centre of the
+D:cold stands a mighty figure. Its wings envelop you in the chill of death
+D:as the nightwing reaches out to draw you into oblivion. Your muscles sag
+D:and your mind loses all will to fight as you stand in awe of this mighty
+D:being.
+
+# New monster added by furiosity for the Theme module
+# From EyAngband
+N:723:6-headed hydra
+G:M:w
+I:115:37d10:20:80:20
+W:29:2:6000:800
+E:0:1:0:2:3:0
+O:0:0:0:0
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+B:BITE:POISON:4d4
+F:BASEANGBAND | ANIMAL | MORTAL | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_SLEEP | CAN_SWIM | FORCE_SLEEP | DROP_CORPSE | MOVE_BODY |
+F:IM_POIS | SUSCEP_FIRE | ONLY_GOLD | DROP_4D2 | DROP_2D2 | IM_COLD |
+S:1_IN_5 |
+S:SCARE | BA_POIS | BR_POIS |
+D:A strange reptilian creature with 6 heads dripping venom. It has
+D:adapted to living in cold environments.
+
+N:724:Nether hound
+G:Z:G
+I:120:60d10:30:100:0
+W:51:2:800:5000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d12
+B:CLAW:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+F:FORCE_SLEEP |
+F:FRIENDS | RES_NETH | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BR_NETH
+D:You feel a soul-tearing chill upon viewing this beast, a ghostly form of
+D:darkness in the shape of a large dog.
+
+N:725:Time hound
+G:Z:B
+I:130:60d10:30:100:0
+W:51:2:800:5000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d12
+B:CLAW:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+F:FORCE_SLEEP |
+F:FRIENDS |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_TIME
+D:You get a terrible sense of deja vu, or is it a premonition? All at once
+D:you see a little puppy and a toothless old dog. Perhaps you should give
+D:up and go to bed.
+
+N:726:Plasma hound
+G:Z:R
+I:120:60d10:30:100:0
+W:51:2:800:5000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d12
+B:CLAW:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+F:FORCE_SLEEP | SUSCEP_COLD |
+F:FRIENDS | RES_PLAS |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | IM_FIRE | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_5 |
+S:BR_PLAS
+D:The very air warps as pure elemental energy stalks towards you in the
+D:shape of a giant hound. Your hair stands on end and your palms itch as
+D:you sense trouble.
+
+N:727:Demonic quylthulg
+G:Q:r
+I:120:48d10:20:1:0
+W:45:1:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_DEMON
+D:A pile of pulsing flesh that glows with an inner dark fire. The world
+D:itself seems to cry out against it.
+
+N:728:Great Storm Worm
+G:D:b
+I:120:40d100:30:150:80
+W:63:2:190000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:ELEC:6d14
+B:BITE:ELEC:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_ELEC | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | IM_ELEC | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_ELEC
+D:A vast dragon of power. Storms and lightning crash around its titanic
+D:form. Deep blue scales reflect the flashes and highlight the creature's
+D:great muscles. It regards you with contempt.
+
+N:729:Ulik the Troll
+G:T:v
+I:130:35d100:30:120:30
+W:51:4:16000:18000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:SHATTER:20d12
+B:HIT:SHATTER:20d12
+B:BITE:POISON:6d14
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:DROP_90 | REGENERATE | KILL_WALL | RES_TELE | KILL_BODY |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE |
+F:EVIL | TROLL | IM_POIS |
+F:IM_ELEC | IM_COLD | IM_FIRE | BASEANGBAND
+D:Trolls are said to be corruptions of Morgoth, made in mockery of Ents.
+D:Ulik is the strongest troll who has ever lived. He could challenge
+D:the immortals and pound them to dust with his great strength.
+
+# New monster added by furiosity for the Theme module
+# From UnAngband
+N:730:8-headed hydra
+G:M:s
+I:120:100d11:20:92:20
+W:39:2:6500:1000
+E:0:1:0:2:4:0
+O:0:0:0:0
+B:BITE:ACID:3d8
+B:BITE:ACID:3d8
+B:SPIT:ACID:3d4
+B:SPIT:ACID:3d4
+F:BASEANGBAND | ANIMAL | MORTAL | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_SLEEP | CAN_SWIM | FORCE_SLEEP | DROP_CORPSE | MOVE_BODY |
+F:IM_ACID | BASH_DOOR | ONLY_GOLD | DROP_4D2 | DROP_2D2 |
+S:1_IN_5 |
+S:SCARE | BR_ACID | BA_ACID
+D:A strange reptilian creature with eight heads spewing acid.
+
+N:731:Oathbreaker
+G:p:D
+I:120:15d100:20:100:10
+W:52:1:2200:10000
+E:1:1:1:2:1:1
+O:0:40:60:0
+B:HIT:HURT:10d5
+B:HIT:HURT:10d5
+B:HIT:EXP_80:10d5
+B:HIT:EXP_80:10d5
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | IM_FIRE | IM_COLD | IM_POIS |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | RES_NETH | RES_NEXU | RES_PLAS |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_COLD |
+F:UNDEAD | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:BLIND | SCARE | CAUSE_3 | BA_NETH | BA_FIRE | BO_PLAS
+S:S_MONSTERS | S_DEMON
+D:He is one of the warriors of old who broke their promise to the
+D:King of Gondor. A terrible curse now haunts all of them.
+
+# New monster added by furiosity for the Theme module
+# From UnAngband
+N:732:10-headed hydra
+G:M:b
+I:120:100d15:20:97:20
+W:42:2:6500:8000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:FIRE:3d9
+B:BITE:ACID:3d9
+B:BITE:ELEC:3d9
+B:BITE:COLD:3d9
+F:BASEANGBAND | ANIMAL | MORTAL | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_SLEEP | CAN_SWIM | FORCE_SLEEP | DROP_CORPSE | MOVE_BODY |
+F:IM_ACID | IM_ELEC | IM_FIRE | IM_COLD | BASH_DOOR |
+F:ONLY_GOLD | DROP_4D2 | DROP_2D2 |
+S:1_IN_4 |
+S:SCARE
+D:A strange reptilian creature with ten multicoloured heads.
+
+# New monster added by furiosity for the Theme module
+# From UnAngband
+N:733:12-headed hydra
+G:M:W
+I:120:100d27:20:110:20
+W:47:2:7000:10000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:FIRE:4d12
+B:BITE:FIRE:4d12
+B:BITE:POISON:4d12
+B:BITE:POISON:4d12
+F:BASEANGBAND | ANIMAL | MORTAL | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_SLEEP | CAN_SWIM | FORCE_SLEEP | DROP_CORPSE | MOVE_BODY |
+F:IM_FIRE | IM_POIS | RES_PLAS | BASH_DOOR | ONLY_GOLD | DROP_4D2 | DROP_2D2 |
+S:1_IN_4 |
+S:SCARE | BA_FIRE | BA_POIS | BO_FIRE | BO_PLAS |
+D:A strange reptilian creature with twelve smouldering heads.
+
+# New monster added by furiosity for the Theme module
+# From UnAngband
+N:734:13-headed hydra
+G:M:v
+I:120:36d100:20:120:20
+W:51:2:7500:15000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:POISON:8d6
+B:BITE:POISON:8d6
+B:BITE:FIRE:12d6
+B:BITE:FIRE:12d6
+F:BASEANGBAND | ANIMAL | MORTAL | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_SLEEP | CAN_SWIM | FORCE_SLEEP | DROP_CORPSE |
+F:IM_FIRE | IM_POIS | RES_PLAS | NO_CONF | NO_SLEEP | BASH_DOOR |
+F:ONLY_GOLD | DROP_4D2 | DROP_2D2 | DROP_2D2 | SMART |
+S:1_IN_3
+S:SCARE | BA_FIRE | BA_POIS | BO_FIRE | BO_PLAS | S_KIN
+D:A strange reptilian creature with thirteen smouldering heads dripping venom.
+
+# New monster added by furiosity for the Theme module
+N:735:14-headed hydra
+G:M:B
+I:120:40d100:20:130:20
+W:55:2:8000:20000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:FIRE:4d10
+B:BITE:ACID:4d10
+B:BITE:ELEC:4d10
+B:BITE:COLD:4d10
+F:BASEANGBAND | ANIMAL | MORTAL | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_SLEEP | CAN_SWIM | FORCE_SLEEP | DROP_CORPSE |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS | RES_PLAS | SMART |
+F:NO_CONF | NO_SLEEP | BASH_DOOR | ONLY_GOLD | DROP_4D2 | DROP_4D2 |
+S:1_IN_3
+S:SCARE | BA_FIRE | BA_POIS | BA_COLD | BA_ELEC | BA_ACID
+S:S_KIN |
+D:A cunning reptilian creature with fourteen multicoloured heads.
+
+# New monster added by furiosity for the Theme module
+N:736:15-headed hydra
+G:M:U
+I:120:44d100:20:140:20
+W:59:2:8500:25000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:FIRE:5d11
+B:BITE:ACID:5d11
+B:BITE:COLD:5d11
+B:BITE:ELEC:5d11
+F:BASEANGBAND | ANIMAL | MORTAL | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_SLEEP | CAN_SWIM | AQUATIC | DROP_CORPSE | WILD_OCEAN |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS | RES_PLAS | SMART |
+F:NO_CONF | NO_SLEEP | BASH_DOOR | ONLY_GOLD | DROP_4D2 | DROP_4D2 |
+S:1_IN_3
+S:SCARE | BA_FIRE | BA_POIS | BA_COLD | BA_ELEC | BA_ACID | CONF |
+S:BO_FIRE | BO_COLD | BO_ELEC | BO_ACID | S_KIN |
+D:A cunning reptilian creature with fifteen multicoloured heads.
+
+# New monster added by furiosity for the Theme module
+N:737:Killer hydra
+G:M:D
+I:120:50d100:20:150:20
+W:65:5:9000:40000
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:FIRE:6d12
+B:BITE:ACID:6d12
+B:BITE:COLD:6d12
+B:BITE:ELEC:6d12
+F:BASEANGBAND | ANIMAL | MORTAL | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:FORCE_SLEEP | CAN_SWIM | AQUATIC | DROP_CORPSE | WILD_OCEAN |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS | RES_PLAS | RES_NETH |
+F:RES_TELE | SMART | NO_CONF | NO_SLEEP | BASH_DOOR | ONLY_GOLD | DROP_4D2 |
+F:RES_NEXU | DROP_4D2 | RES_WATE | NO_STUN | EVIL |
+S:1_IN_3 |
+S:SCARE | BA_FIRE | BA_POIS | BA_COLD | BA_ELEC | BA_ACID | CONF |
+S:BO_FIRE | BO_COLD | BO_ICEE | BA_WATE | BO_ELEC | BO_ACID | BR_NETH |
+S:S_KIN | S_ANIMALS | S_MONSTERS |
+D:A cunning, evil reptile from the depths. It has so many heads that you
+D:give up after losing count twice.
+
+N:738:Old Sorcerer
+G:p:R
+I:130:52d25:20:60:10
+W:54:2:0:5000:0
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:6d8
+B:HIT:HURT:6d8
+B:HIT:HURT:6d8
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 |
+F:OPEN_DOOR | BASH_DOOR | TAKE_ITEM |
+F:EVIL | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:BLINK | TELE_TO | BLIND | CONF | CAUSE_3 | CAUSE_4 | TRAPS |
+S:BO_ACID | BA_FIRE | BA_COLD | BA_POIS |
+S:S_MONSTER | S_DEMON | S_HI_DRAGON | S_UNDEAD
+D:A human figure in robes, he moves with magically improved speed, and his
+D:hands are ablur with spellcasting. You stagger at the mighty sound of his
+D:spells as they echo hollowly through the dungeon.
+
+N:739:Ethereal hound
+G:Z:G
+I:120:60d15:30:100:0
+W:55:3:900:6000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:CLAW:HURT:2d12
+F:FORCE_SLEEP | FRIENDS |
+F:INVISIBLE | PASS_WALL |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BR_NETH
+D:A pale green hound. Pulsing red lines and strange fluorescent light
+D:hints at internal organs best left to the imagination.
+
+N:740:Lesser kraken
+G:~:G
+I:120:30d100:30:150:80
+W:54:2:8000:20000
+E:3:0:3:0:1:0
+O:25:25:50:0
+B:CRUSH:HURT:16d12
+B:CRUSH:HURT:16d12
+B:CRUSH:HURT:16d12
+B:CRUSH:HURT:16d12
+F:FORCE_SLEEP | FORCE_MAXHP | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:ONLY_ITEM | DROP_3D2 | DROP_GOOD | DROP_CORPSE |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | SMART | RES_WATE |
+F:EVIL | IM_ELEC | NO_CONF | NO_SLEEP | IM_POIS | IM_FIRE | BASEANGBAND
+S:1_IN_4 |
+S:BLIND | CONF | SCARE | CAUSE_4 | CAUSE_3 |
+S:BA_WATE | DARKNESS | BR_DARK | TELE_TO
+D:An enormously fearsome and powerful inhabitant of the depths. It
+D:resembles a gargantuan octopus and its evil is almost tangible.
+
+N:741:Great Ice Worm
+G:D:w
+I:120:40d100:30:150:80
+W:63:2:190000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:COLD:6d14
+B:BITE:COLD:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_COLD |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | SUSCEP_FIRE |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE
+F:EVIL | DRAGON | IM_COLD | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_COLD
+D:An immense dragon capable of awesome destruction. You have never felt
+D:such extreme cold, or witnessed such an icy stare. Begone quickly or feel
+D:its wrath!
+
+N:742:Demilich
+G:L:U
+I:120:35d100:20:100:50
+W:54:2:3000:12500
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:EXP_80
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:4d12
+B:TOUCH:LOSE_DEX:4d12
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_TELE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | BLIND | HOLD | CONF | SCARE | CAUSE_3 | CAUSE_4 |
+S:DRAIN_MANA | BRAIN_SMASH | S_HI_UNDEAD | S_UNDEAD | FORGET | S_DEMON |
+S:TPORT | HEAL | ANIM_DEAD
+D:A lich who is partially immaterial, on its way to a new, ethereal form.
+
+N:743:The Phoenix
+G:B:R
+I:120:36d100:60:130:0
+W:54:3:6000:40000
+E:0:1:1:0:1:0
+O:0:50:50:0
+B:BITE:FIRE:12d6
+B:BITE:FIRE:12d6
+B:HIT:FIRE:9d12
+B:HIT:FIRE:9d12
+F:UNIQUE | CAN_SPEAK | RES_PLAS | AURA_FIRE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | SUSCEP_COLD |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:ANIMAL | IM_ACID | IM_FIRE | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP
+F:JOKEANGBAND | HAS_LITE | REGENERATE
+S:1_IN_3 |
+S:BO_FIRE | BO_PLAS | BA_FIRE |
+S:BR_FIRE | BR_LITE | BR_PLAS
+D:A massive glowing eagle bathed in flames. The searing heat chars your
+D:skin and melts your armour.
+
+N:744:Nightcrawler
+G:W:D
+I:120:80d60:20:160:10
+W:69:3:10000:1500
+E:0:0:0:0:1:0
+O:40:0:50:10
+B:STING:LOSE_CON:8d8
+B:STING:LOSE_CON:8d8
+B:BITE:ACID:10d10
+B:BITE:ACID:10d10
+F:FORCE_SLEEP | SMART | KILL_WALL | CAN_SWIM | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS | RES_TELE |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLIND | SCARE | BRAIN_SMASH |
+S:BO_MANA | BO_NETH | BA_NETH | BR_NETH | S_UNDEAD
+D:This intensely evil creature bears the form of a gargantuan black worm.
+D:Its gaping maw is a void of blackness, acid drips from its steely hide.
+D:It is like nothing you have ever seen before, and a terrible chill runs
+D:down your spine as you face it.
+
+# New monster added by furiosity for the Theme module
+N:745:Forest ogre
+G:O:g
+I:110:13d10:20:37:30
+W:18:2:2100:70
+E:1:1:1:2:1:1
+O:10:85:0:0
+B:HIT:HURT:3d9
+B:BITE:POISON:2d8
+F:FRIENDS |
+F:DROP_60 | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | IM_POIS | CAN_FLY
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A hideous, smallish giant that is often found near or with orcs.
+D:This ogre prefers living in the forest and can pass through
+D:thick forests with ease.
+
+# New monster added by furiosity for the Theme module
+# A pet ogre without friends
+N:746:Rebel ogre
+G:O:y
+I:110:13d9:20:33:30
+W:13:2:2100:50
+E:1:1:1:2:1:1
+O:10:85:0:0
+B:HIT:HURT:2d8
+F:DROP_60 | WILD_TOO | WILD_WOOD | WILD_MOUNTAIN | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | PET |
+F:GOOD | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A rebel among ogres, who has joined the forces of the Light to
+D:fight agains the Shadow.
+
+# New monster added by furiosity for the Theme module
+# A pet hill giant
+N:747:Rebel giant
+G:P:R
+I:110:30d15:20:45:50
+W:25:3:3500:150
+E:1:1:1:2:1:1
+O:20:50:20:5
+B:HIT:HURT:4d8
+B:HIT:HURT:4d8
+F:DROP_60 | WILD_TOO | WILD_MOUNTAIN | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | PET |
+F:GOOD | GIANT | MALE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A ten foot tall humanoid with powerful muscles. This giant has
+D:abandoned the Darkness in favour of the forces of good. Thus he
+D:is a rebel and hated among his kind.
+
+N:748:Hand druj
+G:s:y
+I:130:60d10:20:110:10
+W:57:2:10:18000
+E:0:0:0:1:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW | RES_TELE |
+F:SMART | COLD_BLOOD | CAN_SWIM |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_1 |
+S:TELE_AWAY | BLIND | CONF | SCARE | CAUSE_3 | FORGET | DARKNESS |
+S:BO_FIRE | BO_ACID | BO_COLD | BO_ELEC
+D:A skeletal hand floating in the air, motionless except for its flexing
+D:fingers.
+
+N:749:Eye druj
+G:s:r
+I:130:10d100:20:90:10
+W:58:2:2:21000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW | RES_TELE |
+F:SMART | COLD_BLOOD |
+F:EVIL | UNDEAD | CAN_SWIM |
+F:IM_FIRE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_1 |
+S:BO_MANA | BO_NETH | BA_NETH | BRAIN_SMASH | S_UNDEAD
+D:A bloodshot eyeball floating in the air, you'd be forgiven for assuming it
+D:harmless.
+
+N:750:Skull druj
+G:s:o
+I:130:14d100:20:120:10
+W:59:2:1000:24000
+E:0:0:0:0:1:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | RES_TELE |
+F:SMART | COLD_BLOOD |
+F:EVIL | UNDEAD | CAN_SWIM |
+F:IM_FIRE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_1 |
+S:SLOW | CAUSE_4 | MIND_BLAST | BRAIN_SMASH | TRAPS | BO_PLAS |
+S:BO_NETH | BA_WATE | S_UNDEAD
+D:A glowing skull possessed by sorcerous power. It need not move, but
+D:merely blast you with mighty magic.
+
+N:751:Chaos vortex
+G:v:v
+I:140:32d20:100:80:0
+W:53:1:0:4000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:CONFUSE:5d5
+B:ENGULF:CONFUSE:5d5
+B:ENGULF:HURT:5d5
+B:ENGULF:HURT:5d5
+F:ATTR_MULTI | ATTR_ANY | FORCE_SLEEP |
+F:RAND_50 | RAND_25 | CAN_FLY |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_CHAO
+D:Void, nothingness, spinning destructively.
+
+N:752:Aether vortex
+G:v:v
+I:130:40d20:100:40:0
+W:54:2:0:5000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:ELEC:5d5
+B:ENGULF:FIRE:5d5
+B:ENGULF:ACID:5d5
+B:ENGULF:COLD:5d5
+F:ATTR_MULTI | ATTR_ANY | FORCE_SLEEP | CAN_FLY |
+F:RAND_50 | RAND_25 | AURA_COLD | RES_WATE | RES_DISE |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | RES_NETH | RES_NEXU |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | AURA_FIRE | AURA_ELEC |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | RES_PLAS | BASEANGBAND | NO_CUT
+S:1_IN_6 |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS | BR_LITE |
+S:BR_DARK | BR_SOUN | BR_CONF | BR_CHAO | BR_SHAR | BR_NETH |
+S:BR_WALL | BR_INER | BR_TIME | BR_GRAV | BR_PLAS | BR_NEXU
+D:An awesome vortex of pure magic, power radiates from its frame.
+
+# New monster added by furiosity for the Theme module
+N:753:Spider quylthulg
+G:Q:D
+I:120:48d10:20:1:0
+W:45:1:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_SPIDER
+D:It is a pulsing flesh mound that was once a spider.
+
+# New monster added by furiosity for the Theme module
+N:754:Canine quylthulg
+G:Q:s
+I:120:48d10:20:1:0
+W:45:1:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_HOUND
+D:It is a pulsing flesh mound that was once a hound.
+
+N:755:Thuringwethil, the Vampire Messenger
+G:V:v
+I:130:50d100:20:145:10
+W:67:3:1500:23000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:BITE:EXP_80:6d6
+B:BITE:EXP_80:6d6
+B:HIT:CONFUSE:6d6
+B:HIT:CONFUSE:6d6
+F:UNIQUE | FEMALE | SPECIAL_GENE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | CAN_SPEAK | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | NO_STUN
+F:RES_TELE | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | BA_NETH | S_KIN | S_HI_UNDEAD
+D:Chief messenger between Sauron and Morgoth, she is the most deadly of the
+D:vampire race on Middle-earth. At first she is charming to meet, but her
+D:wings and eyes give away her true form.
+
+N:756:Great Worm of Fire
+G:D:r
+I:120:50d100:30:150:80
+W:67:2:190000:23000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:FIRE:6d14
+B:BITE:FIRE:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | SUSCEP_COLD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | AURA_FIRE |
+F:EVIL | DRAGON | IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_FIRE
+D:A vast dragon of immense power. Fire leaps continuously from its huge
+D:form. The air around it scalds you. Its slightest glance burns you, and
+D:you realise how truly insignificant you are.
+
+# New monster added by furiosity for the Theme module
+N:757:Aquatic quylthulg
+G:Q:b
+I:120:48d10:20:1:0
+W:45:1:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | AQUATIC |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_HYDRA
+D:It is a pulsing flesh mound that was once a many-headed reptile.
+
+# New monster added by furiosity for the Theme module
+N:758:Adventurer quylthulg
+G:Q:w
+I:120:48d10:20:1:0
+W:45:3:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | PET |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_KIN
+D:It is a pulsing flesh mound that was once a fellow adventurer.
+
+N:759:Draconic quylthulg
+G:Q:g
+I:120:48d10:20:1:0
+W:45:1:3000:3000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TPORT |
+S:S_DRAGON
+D:It looks like it was once a dragon corpse, now deeply infected with
+D:bacteria that make it pulse in a foul way.
+
+# New monster added by furiosity for the Theme module
+N:760:White hulk
+G:X:w
+I:110:20d10:20:60:10
+W:20:1:5000:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:COLD:2d6
+B:HIT:HURT:2d6
+B:BITE:COLD:3d6
+F:EMPTY_MIND | COLD_BLOOD | IM_COLD |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL | SUSCEP_FIRE | AURA_COLD |
+F:IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock. It is adapted to extreme cold environments.
+
+# New monster added by furiosity for the Theme module
+N:761:Death hulk
+G:X:D
+I:110:99d10:20:80:10
+W:40:1:5000:1000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:EXP_40:3d8
+B:HIT:HURT:3d8
+B:BITE:HURT:3d8
+F:EMPTY_MIND | COLD_BLOOD | SMART |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL | RES_NETH | HURT_LITE |
+F:IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:DARKNESS | S_UNDEAD
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock. It seems to be surrounded by an impenetrable
+D:shadow.
+
+N:762:Fundin Bluecloak
+G:k:B
+I:130:50d100:25:195:10
+W:56:2:1400:20000
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:HIT:HURT:10d10
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP | PET |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:HEAL | BLIND | CONF | SCARE | CAUSE_3 | CAUSE_4 | BRAIN_SMASH |
+S:FORGET | S_MONSTERS | S_ANIMALS
+D:He is one of the greatest Dwarven priests to walk the earth. Fundin has
+D:earned a high position in the church, and his skill with both weapon and
+D:spell only justify his position further. His combination of Dwarven
+D:strength and priestly wisdom are a true match for any adventurer.
+
+N:763:Black Balrog
+G:U:D
+I:120:20d100:20:50:80
+W:61:4:9000:10000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:ACID:4d12
+B:HIT:ACID:4d12
+B:CRUSH:HURT:3d12
+B:TOUCH:UN_POWER
+F:FORCE_SLEEP | FORCE_MAXHP | KILL_WALL |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON | IM_ACID | NO_CONF | NO_SLEEP | NONLIVING |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLIND | CONF | SCARE | HASTE |
+S:BR_ACID |
+S:S_DEMON
+D:The greatest of the demons, potent in both magical might
+D:and sheer battle power. This corrupted Maia's form is
+D:surrounded by whirlpools of acid.
+
+# New monster added by furiosity for the Theme module
+N:764:Orange hulk
+G:X:o
+I:110:20d10:20:60:10
+W:20:1:5000:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:POISON:2d6
+B:HIT:HURT:2d6
+B:BITE:POISON:3d6
+F:EMPTY_MIND | COLD_BLOOD |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL |
+F:IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock. It looks poisonous.
+
+# New monster added by furiosity for the Theme module
+N:765:Fire hulk
+G:X:r
+I:110:20d10:20:60:10
+W:20:1:5000:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:FIRE:2d6
+B:HIT:HURT:2d6
+B:BITE:FIRE:3d6
+F:EMPTY_MIND | COLD_BLOOD | IM_FIRE |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL | SUSCEP_COLD | AURA_FIRE |
+F:IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock. It is surrounded by flames.
+
+N:766:Ancalagon the Black
+G:D:D
+I:140:180d100:40:170:70
+W:90:1:330000:60000
+E:0:1:0:6:1:0
+O:60:40:0:0
+B:CLAW:HURT:10d12
+B:CLAW:HURT:10d12
+B:BITE:HURT:10d14
+B:BITE:HURT:10d14
+F:UNIQUE | MALE | CAN_FLY | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BR_ACID | BR_FIRE | BR_DISI | BR_WALL | BR_TIME |
+S:S_HI_DRAGON | S_KIN
+D:"Rushing Jaws" is his name, and death is his game; the greatest and most
+D:terrible of all dragonkind, his power dismayed even the Valar for a time.
+
+# New monster added by furiosity for the Theme module
+N:767:Forest hulk
+G:X:g
+I:110:20d10:20:60:10
+W:20:1:5000:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:POISON:2d6
+B:HIT:HURT:2d6
+B:BITE:PARALYZE:3d6
+F:EMPTY_MIND | COLD_BLOOD |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL |
+F:IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock. Its preferred habitat is a forest, however.
+
+N:768:Nightwalker
+G:W:D
+I:130:80d70:20:175:10
+W:73:3:75000:20000
+E:1:1:1:2:1:1
+O:30:0:70:0
+B:HIT:UN_BONUS:10d10
+B:HIT:UN_BONUS:10d10
+B:HIT:UN_BONUS:7d7
+B:HIT:UN_BONUS:7d7
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | CAN_SWIM |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | RES_TELE |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:BLIND | SCARE | BRAIN_SMASH |
+S:BO_MANA | BO_NETH | BA_NETH | S_UNDEAD
+D:A huge giant garbed in black, more massive than a titan and stronger than
+D:a dragon. With terrible blows, it breaks your armour from your back,
+D:leaving you defenceless against its evil wrath. It can smell your fear,
+D:and you in turn smell the awful stench of death as this ghastly figure
+D:strides towards you menacingly.
+
+# New monster added by furiosity for the Theme module
+N:769:Night hulk
+G:X:b
+I:110:20d10:20:60:10
+W:20:1:5000:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:BLIND:2d6
+B:HIT:HURT:2d6
+B:BITE:EAT_LITE:3d6
+F:EMPTY_MIND | COLD_BLOOD |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL | HURT_LITE |
+F:IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock. It prefers to dwell in dark caves where there is
+D:no sun.
+
+# New monster added by furiosity for the Theme module
+N:770:Silver hulk
+G:X:W
+I:110:20d10:20:60:10
+W:20:1:5000:90
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:HALLU:2d6
+B:HIT:HURT:2d6
+B:BITE:INSANITY:3d6
+F:EMPTY_MIND | COLD_BLOOD | IM_COLD |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL |
+F:IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock. It is an extremely confusing sight to behold.
+
+N:771:Saruman of Many Colours
+G:p:v
+I:120:70d100:100:100:0
+W:60:1:1600:35000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+B:HIT:HURT:5d5
+B:HIT:HURT:5d5
+F:UNIQUE | MALE | ATTR_MULTI | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | REFLECTING | RES_TELE
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:DROP_GREAT | DROP_CHOSEN | SPECIAL_GENE
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | HASTE | TPORT | TELE_AWAY | BLIND | CONF | SCARE |
+S:CAUSE_4 | MIND_BLAST | FORGET | TRAPS | ANIM_DEAD | BO_MANA |
+S:BO_ICEE | BA_ACID | BA_FIRE | BA_COLD | BA_WATE | BA_CHAO |
+S:S_UNDEAD | S_DEMON | S_HI_DRAGON | S_ANIMALS |
+D:Originally known as the White, Saruman fell prey to Sauron's wiles. He
+D:searches forever for the One Ring, to become a mighty Sorcerer-King of the
+D:world.
+
+N:772:Harowen the Black Hand
+G:p:B
+I:140:25d100:30:36:0
+W:51:3:0:20000
+E:1:1:1:2:1:1
+O:90:10:0:0
+B:TOUCH:EAT_GOLD:5d5
+B:TOUCH:EAT_ITEM:5d5
+B:HIT:BLIND:10d5
+B:HIT:POISON:8d5
+F:UNIQUE | MALE | CAN_SPEAK | SMART |
+F:FORCE_SLEEP | FORCE_MAXHP | MOVE_BODY |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:IM_POIS | BASEANGBAND
+S:1_IN_6 |
+S:TELE_TO | TRAPS
+D:He is a master of disguise, an expert of stealth, a genius at traps, and
+D:moves with blinding speed.
+
+N:773:Blue Balrog
+G:U:b
+I:120:20d100:20:50:80
+W:61:4:9000:10000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:ELEC:4d12
+B:HIT:ELEC:4d12
+B:CRUSH:HURT:3d12
+B:TOUCH:UN_POWER
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_ELEC | KILL_WALL |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON | IM_ELEC | NO_CONF | NO_SLEEP | NONLIVING |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLIND | CONF | SCARE | HASTE |
+S:BR_ELEC |
+S:S_DEMON
+D:The greatest of the demons, potent in both magical might
+D:and sheer battle power. This corrupted Maia's form is
+D:surrounded by living lightning.
+
+N:774:Dreadlord
+G:G:r
+I:120:30d100:20:150:10
+W:62:2:0:20000
+E:0:0:0:0:0:0
+O:10:10:60:10
+B:HIT:EXP_40:6d6
+B:HIT:EXP_40:6d6
+B:HIT:LOSE_STR:4d6
+B:HIT:LOSE_STR:4d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL |
+F:EVIL | UNDEAD | CAN_FLY |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | RES_TELE | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:HOLD | DRAIN_MANA | BLIND | S_UNDEAD | CONF |
+S:SCARE | TELE_TO | TPORT | BRAIN_SMASH | ANIM_DEAD
+S:BA_NETH | DARKNESS
+D:It is a massive form of animated death, its colour deeper than black. It
+D:drinks in light, and space around it is twisted and torn by the weight of
+D:its evil. It is unlife and it knows nothing but the stealing of souls and
+D:the stench of death.
+
+N:775:Greater kraken
+G:~:G
+I:120:40d100:30:175:80
+W:60:2:10000:25000
+E:3:0:3:0:1:0
+O:10:80:0:10
+B:CRUSH:HURT:15d15
+B:CRUSH:HURT:15d15
+B:CRUSH:HURT:15d15
+B:CRUSH:HURT:15d15
+F:FORCE_SLEEP | FORCE_MAXHP | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:ONLY_ITEM | DROP_3D2 | DROP_GOOD | DROP_CORPSE |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | SMART | RES_WATE |
+F:EVIL | IM_ELEC | NO_CONF | NO_SLEEP | IM_POIS | IM_FIRE | BASEANGBAND
+S:1_IN_3 |
+S:BLIND | CONF | SCARE | CAUSE_4 | CAUSE_3 | TELE_TO | TELE_AWAY |
+S:BA_WATE | DARKNESS | BR_DARK | BR_ACID | BR_POIS
+D:An enormously fearsome and powerful inhabitant of the depths. It
+D:resembles a gargantuan octopus and its evil is almost tangible.
+
+N:776:Archlich
+G:L:B
+I:120:45d100:20:120:50
+W:64:2:0:20000
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:TOUCH:EXP_80
+B:TOUCH:UN_POWER
+B:TOUCH:LOSE_DEX:8d12
+B:TOUCH:LOSE_DEX:8d12
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | RES_TELE | CAN_FLY |
+F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:BLINK | TELE_TO | BLIND | HOLD | SCARE | CAUSE_4 |
+S:DRAIN_MANA | BRAIN_SMASH | S_HI_UNDEAD | FORGET |
+S:TPORT | HEAL | S_DEMON | BA_NETH | ANIM_DEAD
+D:A lich who has reached its ultimate evolutionary stage: a completely
+D:immaterial state.
+
+# Description of Tevildo taken from UnAngband
+N:777:Tevildo, Prince of Cats
+G:f:v
+I:130:48d100:100:200:0
+W:66:3:0:30000
+E:0:1:0:2:1:0
+O:30:60:0:10
+B:CLAW:CONFUSE:12d12
+B:CLAW:LOSE_DEX:2d12
+B:CLAW:BLIND:10d5
+B:BITE:PARALYZE:15d1
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_POIS | NO_CONF | BASEANGBAND
+S:1_IN_3 |
+S:TELE_TO | S_KIN
+D:Master of all things feline and mighty servant of Morgoth. A great cat, coal-black and evil to look upon. His eyes are long and very narrow and slanted, and gleam both red and green. His great grey whiskers are as stout and sharp as needles. His purr is like the roll of drums and his growl like thunder.
+
+N:778:Jabberwock
+G:H:v
+I:130:32d100:35:125:255
+W:68:3:2300:19000
+E:0:1:0:2:1:0
+O:20:50:20:0
+B:CLAW:HURT:10d10
+B:CLAW:HURT:10d10
+B:BITE:HURT:10d10
+B:BITE:HURT:10d10
+F:ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE |
+F:ONLY_ITEM | DROP_60 | DROP_90 |
+F:BASH_DOOR | CAN_FLY | DROP_CORPSE |
+F:ANIMAL | MORTAL | JOKEANGBAND |
+S:1_IN_5 |
+S:CAUSE_4 |
+S:BR_CHAO
+D:"Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
+
+N:779:Chaos hound
+G:Z:v
+I:120:60d30:30:100:0
+W:65:2:900:10000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:BITE:HURT:2d12
+B:CLAW:HURT:2d12
+F:ATTR_MULTI | ATTR_ANY | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP | FRIENDS | BASH_DOOR |
+F:ANIMAL | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_5 |
+S:BR_CHAO
+D:A constantly changing canine form, this hound rushes towards you as if
+D:expecting mayhem and chaos ahead. It appears to have an almost kamikaze
+D:relish for combat. You suspect all may not be as it seems.
+
+# New monster added by furiosity for the Theme module
+N:780:Chaos hulk
+G:X:v
+I:110:25d10:20:80:10
+W:30:1:5000:110
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:GAZE:CONFUSE
+B:HIT:HALLU:2d6
+B:HIT:LOSE_ALL:2d6
+B:BITE:EXP_40:3d6
+F:EMPTY_MIND | COLD_BLOOD |
+F:BASH_DOOR | KILL_WALL | DROP_SKELETON |
+F:ANIMAL | EVIL |
+F:IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:This bizarre creature has glaring eyes and large mandibles capable of
+D:slicing through rock. It is surrounded by an aura of chaotic forces.
+
+N:781:Beholder hive-mother
+G:e:y
+I:120:40d100:30:80:10
+W:67:3:2600:17000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:EXP_80:6d6
+B:GAZE:PARALYZE:5d5
+B:GAZE:INSANITY:5d5
+B:GAZE:UN_POWER:5d5
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | CAN_FLY |
+F:BASH_DOOR | FEMALE | SMART | DROP_CORPSE |
+F:EVIL | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_2 |
+S:BLIND | CONF | FORGET | SCARE | DRAIN_MANA | BRAIN_SMASH |
+S:BA_DARK | BO_MANA | BA_ACID | BA_FIRE | BA_COLD | BO_NETH |
+S:S_KIN
+D:A mother of the race of beholders, she can summon her brood to her aid
+D:whenever she wishes.
+
+N:782:Leviathan
+G:~:v
+I:120:50d100:40:180:30
+W:67:3:300000:28000
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:BITE:FIRE:5d12
+B:BITE:FIRE:5d12
+B:CRUSH:HURT:6d15
+B:CRUSH:HURT:6d15
+F:FORCE_SLEEP | FORCE_MAXHP | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:IM_FIRE | IM_ACID | IM_COLD | IM_POIS |
+F:ANIMAL | NO_CONF | NO_SLEEP | NO_FEAR | DROP_CORPSE | BASEANGBAND
+S:1_IN_9
+S:BR_FIRE | BR_ACID | BR_DARK | BR_POIS | BA_WATE |
+S:S_DRAGON | S_HYDRA | HEAL | CONF | DARKNESS
+D:An enormous, terrible sea-monster, the true master of the ocean.
+
+N:783:Great Worm of Chaos
+G:D:v
+I:120:60d100:40:170:100
+W:75:2:190000:29000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:5d12
+B:CLAW:HURT:5d12
+B:BITE:HURT:7d14
+B:BITE:HURT:7d14
+F:ATTR_MULTI | ATTR_ANY |
+F:FORCE_SLEEP | FORCE_MAXHP | RES_DISE | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_CHAO | BR_DISE |
+S:S_DRAGON | S_HI_DRAGON
+D:A massive dragon of changing form. As you watch, it appears first fair
+D:and then foul. Its body is twisted by chaotic forces as it strives to
+D:stay real. Its very existence distorts the universe around it.
+
+N:784:Great Worm of Law
+G:D:B
+I:120:60d100:40:170:100
+W:75:2:190000:29000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:5d12
+B:CLAW:HURT:5d12
+B:BITE:HURT:7d14
+B:BITE:HURT:7d14
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
+F:EVIL | DRAGON | NO_STUN | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN | BR_SHAR |
+S:S_DRAGON | S_HI_DRAGON
+D:A massive dragon of powerful intellect. It seeks to dominate the universe
+D:and despises all other life. It sees all who do not obey it as mere
+D:insects to be crushed underfoot.
+
+N:785:Great Worm of Balance
+G:D:v
+I:120:70d100:40:170:100
+W:80:2:190000:31000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:6d12
+B:CLAW:HURT:6d12
+B:BITE:HURT:8d14
+B:BITE:HURT:8d14
+F:DRAGON | EVIL | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | RES_DISE |
+F:NO_STUN | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | NO_CUT | ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN | BR_CHAO | BR_SHAR | BR_DISE |
+S:S_DRAGON | S_HI_DRAGON
+D:A massive dragon, it is thousands of
+D:years old and seeks to maintain the Cosmic Balance. It sees you as an
+D:upstart troublemaker without the wisdom to control your actions.
+
+# New monster added by furiosity for the Theme module
+N:786:Yellow hulk
+G:X:y
+I:120:32d10:20:80:10
+W:40:1:500000:1200
+E:0:0:0:3:0:0
+O:0:0:0:0
+B:HIT:ACID:3d4
+B:HIT:ACID:3d4
+B:HIT:ACID:3d4
+B:HIT:ACID:3d4
+F:FORCE_MAXHP | IM_ACID | HURT_LITE |
+F:EMPTY_MIND | COLD_BLOOD |
+F:ONLY_GOLD | DROP_2D2 |
+F:KILL_ITEM | PASS_WALL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It is a tougher relative of the Xorn. Its hide glitters with drops of acid.
+
+N:787:White Balrog
+G:U:w
+I:120:20d100:20:50:80
+W:61:4:9000:10000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:COLD:4d12
+B:HIT:COLD:4d12
+B:CRUSH:HURT:3d12
+B:TOUCH:UN_POWER
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_COLD | KILL_WALL |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON | IM_COLD | NO_CONF | NO_SLEEP | NONLIVING |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLIND | CONF | SCARE | HASTE |
+S:BR_COLD |
+S:S_DEMON
+D:The greatest of the demons, potent in both magical might
+D:and sheer battle power. This corrupted Maia's form is
+D:surrounded by frost.
+
+# New monster added by furiosity for the Theme module
+N:788:Red hulk
+G:X:R
+I:120:32d10:20:80:10
+W:40:1:500000:1200
+E:0:0:0:3:0:0
+O:0:0:0:0
+B:HIT:FIRE:3d4
+B:HIT:FIRE:3d4
+B:HIT:FIRE:3d4
+B:HIT:FIRE:3d4
+F:FORCE_MAXHP | IM_ACID | SUSCEP_COLD |
+F:EMPTY_MIND | COLD_BLOOD | HURT_LITE |
+F:ONLY_GOLD | DROP_2D2 | AURA_FIRE |
+F:KILL_ITEM | PASS_WALL |
+F:IM_FIRE | IM_ELEC | IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It is a tougher relative of the Xorn. Its hide is wreathed in flames.
+
+N:789:Trone, the Rebel Thunderlord
+G:B:D
+I:130:80d100:20:120:80
+W:72:2:400000:45000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:12d10
+B:HIT:HURT:12d10
+B:CHARGE:HURT:10d10
+B:CHARGE:HURT:10d10
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE | SPECIAL_GENE |
+F:FORCE_MAXHP | REGENERATE | THUNDERLORD | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | OPEN_DOOR | BASH_DOOR | DROP_CHOSEN |
+F:EVIL | IM_FIRE | IM_COLD | IM_POIS |
+F:MORTAL | HAS_LITE
+S:1_IN_4 |
+S:TELE_TO | SCARE | BR_TIME | BR_FIRE |
+S:BO_MANA | S_THUNDERLORD
+D:As the Thunderlords came from afar to help the Elves, Trone and his rebel
+D:wing came to defend Morgoth. He is an evil and powerful Thunderlord.
+
+N:790:Great Worm of Many Colours
+G:D:v
+I:120:70d100:40:170:255
+W:80:2:190000:31000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:6d12
+B:CLAW:HURT:6d12
+B:CLAW:HURT:8d14
+B:BITE:HURT:8d14
+F:ATTR_MULTI | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE | AURA_ELEC | RES_TELE |
+F:IM_FIRE | IM_ACID | IM_POIS | IM_COLD | IM_ELEC | AURA_COLD |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BR_POIS | BR_ELEC | BR_ACID | BR_FIRE | BR_COLD |
+S:CONF | SCARE | BLIND
+D:A huge dragon whose scales shimmer in myriad hues.
+
+N:791:Marda, rider of gold Laronth
+G:B:y
+I:130:100d85:100:100:50
+W:75:6:420000:35000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:12d15
+B:HIT:HURT:12d15
+B:HIT:HURT:12d15
+B:HIT:HURT:12d15
+F:UNIQUE | FEMALE | CAN_SPEAK | THUNDERLORD | ONLY_ITEM | RES_TELE |
+F:DROP_CHOSEN | DROP_CORPSE | DROP_SKELETON | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP | SPECIAL_GENE |
+F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 |
+F:EVIL | IM_POIS | IM_ELEC | SMART | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:MORTAL | HAS_LITE | AQUATIC |
+S:1_IN_4 |
+S:SCARE | BLIND | TPORT | BLINK | TELE_AWAY | TELE_TO |
+S:BR_FIRE | BA_MANA | S_THUNDERLORD
+D:Former leader among the Thunderlords, she and Trone have fallen under the
+D:control of Morgoth. Laronth, her eagle, can summon Thunderlords to her aid.
+D:She has somehow broken through to the Lonely Isle and is killing the swans
+D:The magic of the Valar is for some reason powerless against her, and they
+D:have opened a path to Tol Eressea in case a hero wants to try their luck
+D:at destroying her.
+
+N:792:Tselakus, the Dreadlord
+G:G:R
+I:130:65d100:20:150:10
+W:68:2:1000:35000
+E:1:1:1:2:1:1
+O:0:80:20:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:LOSE_STR:4d6
+B:HIT:LOSE_STR:4d6
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_SPEAK | CAN_FLY |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL |
+F:EVIL | UNDEAD | IM_COLD | AURA_COLD |
+F:IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT | NO_STUN
+S:1_IN_3 |
+S:BLIND | HOLD | CONF |
+S:BA_DARK | BA_NETH |
+S:S_WRAITH | S_HI_UNDEAD | S_KIN
+D:This huge affront to existence twists and tears at the fabric of space.
+D:Darkness itself recoils from the touch of Tselakus as he leaves a trail
+D:of death and destruction. Mighty claws rend reality as he
+D:annihilates all in his path to your soul!
+
+N:793:Sky Drake
+G:D:B
+I:130:60d100:40:200:255
+W:77:2:220000:40000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:6d12
+B:CLAW:HURT:6d12
+B:BITE:ELEC:8d14
+B:BITE:ELEC:8d14
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_ELEC | AURA_COLD | DROP_CORPSE |
+F:IM_ELEC | EVIL | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY |
+F:DRAGON | NO_CONF | NO_SLEEP | RES_TELE | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BR_ELEC | BR_GRAV | BR_LITE |
+S:S_DRAGON | S_HI_DRAGON |
+S:SCARE | BLIND
+D:The mightiest elemental dragon of air, it can destroy you with ease.
+
+N:794:Eilinel the Entrapped
+G:p:D
+I:120:90d10:10:40:1
+W:42:10:0:3500
+E:1:1:1:2:1:1
+O:20:20:50:10
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:TOUCH:UN_POWER:3d3
+B:TOUCH:UN_BONUS:3d3
+F:UNIQUE | FEMALE |
+F:FORCE_MAXHP |
+F:DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_FIRE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT | NO_STUN
+S:1_IN_2 |
+S:BLINK | TELE_TO | HEAL | S_MONSTER | BO_ACID | BO_MANA | CAUSE_3
+D:In life, she was the wife of Gorlim. In death, her shade was
+D:entrapped by Morgoth and used to trick her husband into betraying
+D:Barahir. Now she is totally entrapped by Morgoth's power, and uses
+D:her magic to do his bidding.
+
+N:795:Dagorrog
+G:U:u
+I:130:50d100:40:120:80
+W:72:3:0:18000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:11d11
+B:HIT:HURT:11d11
+B:HIT:HURT:11d11
+B:HIT:HURT:11d11
+F:FORCE_SLEEP | FORCE_MAXHP | REGENERATE | NONLIVING |
+F:ONLY_ITEM | DROP_GOOD | DROP_4D2 | DROP_2D2 | BASEANGBAND |
+F:OPEN_DOOR | BASH_DOOR | KILL_BODY | POWERFUL |
+F:EVIL | DEMON | NO_CONF | NO_SLEEP | CAN_FLY |
+F:IM_FIRE | IM_COLD | IM_POIS | IM_ACID | IM_ELEC
+S:1_IN_5 |
+S:HASTE | SLOW | SCARE | S_HI_DEMON
+D:Festooned with horns and fierce claws, these monstrous forms are the
+D:shock troops of Morgoth, known for their strength and fierce weapons.
+D:A giant humanoid demon wielding a massive, heavy and sharp scythe.
+D:Feared by foes and friends alike when it flies into one of its berserk
+D:rages, the War demon will cut down anything in its path between it and
+D:you.
+
+# New monster added by furiosity for the Theme module
+N:796:Green hulk
+G:X:G
+I:115:32d10:20:80:10
+W:40:1:500000:1200
+E:0:0:0:3:0:0
+O:0:0:0:0
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+B:HIT:POISON:3d4
+F:FORCE_MAXHP | IM_ACID | HURT_LITE |
+F:EMPTY_MIND | COLD_BLOOD |
+F:ONLY_GOLD | DROP_2D2 |
+F:KILL_ITEM | KILL_WALL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It is a tougher relative of the Xorn. Its hide glitters with drops of venom.
+
+# New monster added by furiosity for the Theme module
+N:797:Blue hulk
+G:X:B
+I:115:32d10:20:80:10
+W:40:1:500000:1200
+E:0:0:0:3:0:0
+O:0:0:0:0
+B:HIT:ELEC:3d4
+B:HIT:ELEC:3d4
+B:HIT:ELEC:3d4
+B:HIT:ELEC:3d4
+F:FORCE_MAXHP | IM_ACID | HURT_LITE |
+F:EMPTY_MIND | COLD_BLOOD |
+F:ONLY_GOLD | DROP_2D2 | AURA_ELEC |
+F:KILL_ITEM | KILL_WALL |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:HURT_ROCK | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+D:It is a tougher relative of the Xorn. It is surrounded by sparks.
+
+N:798:Black reaver
+G:L:D
+I:120:50d100:20:170:50
+W:74:3:1900:23000
+E:0:0:0:0:0:0
+O:0:60:40:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+B:HIT:LOSE_STR:4d6
+B:HIT:LOSE_STR:4d6
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | CAN_SWIM |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | RES_TELE |
+F:NO_CONF | NO_SLEEP | KILL_WALL | NO_FEAR |
+F:BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:TELE_TO | BLIND | HOLD | CONF | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | BA_MANA | BA_NETH | S_UNDEAD
+D:A humanoid form, black as night, advancing steadily and unstoppably, even
+D:the very rock of the dungeon cannot prevent it reaching you.
+
+N:799:Master mindcrafter
+G:p:y
+I:120:80d10:20:60:10
+W:40:2:1700:2000
+E:1:1:1:2:1:1
+O:20:40:40:0
+B:HIT:HURT:4d5
+B:HIT:HURT:4d5
+B:HIT:HURT:4d5
+F:MALE | ONLY_ITEM | FORCE_SLEEP | FORCE_MAXHP | DROP_4D2 |
+F:SMART | BASH_DOOR | TAKE_ITEM | MOVE_BODY |
+F:EVIL | IM_FIRE | IM_ELEC | IM_POIS | BASEANGBAND |
+F:NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR
+S:1_IN_2 |
+S:HEAL | BLIND | HOLD | CONF | SCARE | TPORT | BA_COLD | BA_FIRE |
+S:MIND_BLAST | BRAIN_SMASH | S_MONSTERS | TELE_AWAY | BLINK | BO_NETH
+D:A mindcrafter of the highest order. Powerful and evil, and a dangerous
+D:enemy: a master of mind over matter, of his own mind, and of the minds of
+D:others, who slavishly follow him into battle when he calls them.
+
+N:800:Greater demonic quylthulg
+G:Q:R
+I:120:15d100:20:1:0
+W:71:2:5000:10500
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TELE_TO |
+S:S_HI_DEMON
+D:A massive pulsating mound of flesh, glowing with an inner hellish light.
+
+N:801:Greater draconic quylthulg
+G:Q:G
+I:120:15d100:20:1:0
+W:71:2:5000:10500
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:BLINK | TELE_TO |
+S:S_HI_DRAGON
+D:A massive mound of scaled flesh, throbbing and pulsating with multi-hued
+D:light.
+
+N:802:Greater rotting quylthulg
+G:Q:U
+I:120:15d100:20:1:0
+W:71:2:5000:10500
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND |NO_CUT
+S:1_IN_2 |
+S:BLINK | TELE_TO |
+S:S_HI_UNDEAD
+D:A massive pile of rotting flesh. A disgusting stench fills the air as it
+D:throbs and writhes.
+
+# Joke monster added by furiosity for the Theme module
+
+N:803:Invisible Horror
+G:.:v
+I:100:4d9:20:1:0
+W:20:5:0:300
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:CHARGE:TERRIFY
+B:CHARGE:TERRIFY
+B:CHARGE:TERRIFY
+B:CHARGE:TERRIFY
+F:CHAR_CLEAR | ATTR_CLEAR | FORCE_MAXHP | SMART |
+F:INVISIBLE | COLD_BLOOD | EMPTY_MIND | WEIRD_MIND |
+F:PASS_WALL | UNDEAD | EVIL | NONLIVING | HURT_LITE |
+F:IM_POIS | RES_TELE | NO_FEAR | NO_STUN | NO_SLEEP |
+F:CAN_SWIM | NO_TARGET | AI_ANNOY | NO_CUT | CAN_SPEAK |
+F:JOKEANGBAND
+S:1_IN_2
+S:SCARE
+D:You can't see it.
+
+N:804:Feagwath, the Undead Sorcerer
+G:L:y
+I:130:60d100:20:85:50
+W:77:2:1900:30000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:TOUCH:EXP_80:6d12
+B:TOUCH:UN_POWER:6d12
+B:TOUCH:LOSE_DEX:6d12
+B:TOUCH:LOSE_DEX:6d12
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD |
+F:IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:BLINK | TELE_TO | HOLD | SCARE | CAUSE_4 |
+S:BRAIN_SMASH | TRAPS | BA_MANA |
+S:BO_MANA | BA_NETH |
+S:S_MONSTERS | S_UNDEAD | S_KIN | ANIM_DEAD
+D:A stench of corruption and decay surrounds this sorcerer, who has
+D:risen from the dead to continue his foul plots and schemes.
+
+# New monster added by furiosity for the Theme module
+N:805:Silver wraith
+G:W:B
+I:110:15d10:20:40:10
+W:33:3:0:375
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d8
+B:HIT:EAT_LITE:1d8
+B:TOUCH:EXP_40
+F:FORCE_SLEEP | DROP_60 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:HOLD | SCARE | CAUSE_2 | DARKNESS
+D:An almost imperceptible silvery shimmer in the air. It
+D:seems to absorb light wherever it goes.
+
+# New monster added by furiosity for the Theme module
+# Pet barrow wight, basically.
+N:806:Adventurer wraith
+G:W:U
+I:110:15d10:20:40:10
+W:33:3:0:375
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+B:TOUCH:EXP_40
+F:FORCE_SLEEP | DROP_60 | PET |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:GOOD | UNDEAD | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:HOLD | SCARE | CAUSE_2 | DARKNESS
+D:A fellow adventurer wraith.
+
+N:807:Balrog Captain
+G:U:G
+I:130:75d100:40:140:40
+W:80:3:0:25000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:FIRE:8d12
+B:HIT:FIRE:8d12
+B:CRUSH:HURT:7d12
+B:TOUCH:UN_POWER
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | NONLIVING |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | SMART |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | KILL_WALL |
+F:RES_NETH | RES_PLAS | REGENERATE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BLIND | CONF | BRAIN_SMASH |
+S:BR_FIRE | BA_NETH | BA_FIRE | BR_PLAS | BO_PLAS |
+S:S_HI_DEMON | S_DEMON |
+D:Originally of the semi-divine Maiar, this evil spirit swore allegiance
+D:to Morgoth at the beginning of time and is now one of his most terrible
+D:demonic servants. With its flaming whip and sword it seeks to destroy you.
+
+N:808:Ungoliant, the Unlight
+G:S:D
+I:130:130d100:8:160:80
+W:75:1:1500:35000
+E:0:1:0:2:1:0
+O:20:0:80:0
+B:CLAW:POISON:8d6
+B:CLAW:POISON:8d6
+B:BITE:PARALYZE:8d10
+B:STING:LOSE_STR:8d4
+F:UNIQUE | FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
+F:SMART | BASH_DOOR | IM_ACID |
+F:ANIMAL | SPIDER | EVIL | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP
+F:BASEANGBAND
+S:1_IN_3 |
+S:HEAL | BLIND | SLOW | CONF | SCARE | DARKNESS | BA_DARK |
+S:BR_POIS | BR_DARK | S_SPIDER
+D:This enormous, hideous spirit of void is in the form of a spider of
+D:immense proportions. She is surrounded by a cloud of Unlight as she sucks
+D:in all living light into her bloated body, and breathes out the blackest of
+D:darkness. She is always ravenously hungry and would even eat herself to
+D:avoid starvation.
+
+# New monster added by furiosity for the Theme module
+N:809:Vampire orc
+G:V:D
+I:110:25d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | FRIENDS |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 | ORC |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is an orc with an aura of power. You notice a sharp set of front
+D:teeth.
+
+# New monster added by furiosity for the Theme module
+N:810:Vampire yeek
+G:V:w
+I:110:16d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | STUPID |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is a yeek with an aura of power. You notice a sharp set of front
+D:teeth.
+
+N:811:Aether hound
+G:Z:v
+I:120:60d40:30:100:0
+W:74:3:1000:10000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:3d12
+B:BITE:HURT:3d12
+B:CLAW:HURT:3d12
+B:CLAW:HURT:3d12
+F:ATTR_MULTI | ATTR_ANY |
+F:FORCE_SLEEP | CAN_FLY |
+F:FRIENDS | RES_NETH | RES_PLAS | RES_NEXU | RES_DISE |
+F:BASH_DOOR | AURA_FIRE | AURA_ELEC | AURA_COLD |
+F:DROP_CORPSE | DROP_SKELETON |
+F:ANIMAL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_5 |
+S:BR_ACID | BR_FIRE | BR_COLD | BR_ELEC | BR_POIS |
+S:BR_LITE | BR_DARK | BR_SOUN | BR_CONF | BR_CHAO | BR_SHAR |
+S:BR_NETH | BR_DISE | BR_WALL | BR_INER | BR_TIME |
+S:BR_GRAV | BR_PLAS | BR_NEXU
+D:A shifting, swirling form. It seems to be all colours and sizes and
+D:shapes, though the dominant form is that of a huge dog. You feel very
+D:uncertain all of a sudden.
+
+N:812:Greater Balrog
+G:U:v
+I:130:60d100:30:120:75
+W:77:3:0:22000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:CLAW:FIRE:8d10
+B:CLAW:FIRE:8d10
+B:BITE:POISON:7d10
+B:BITE:LOSE_CON:7d10
+F:FORCE_SLEEP | FORCE_MAXHP | REGENERATE | NONLIVING | SMART |
+F:ONLY_ITEM | DROP_GOOD | DROP_4D2 | DROP_2D2 | BASEANGBAND |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | POWERFUL | CAN_FLY |
+F:EVIL | DEMON | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP
+S:1_IN_5 |
+S:S_HI_DEMON | S_HI_DRAGON | BR_FIRE | BR_POIS | BR_CHAO | BA_CHAO |
+S:SCARE | BA_FIRE | CAUSE_4 | ARROW_4 | MISSILE
+D:Appearing as a giant, clawed and winged humanoid with a scaly red body
+D:and massive fangs dripping a foul green liquid, the Greater Balrog is a
+D:dreadful enemy from the lowest depths of Morgoth's realm. They are often
+D:the commanders of vast demon and dragon armies.
+
+# New monster added by furiosity for the Theme module
+N:813:Vampire ogre
+G:V:o
+I:110:35d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | FRIENDS | STUPID |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 | GIANT |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is an ogre with an aura of power. You notice a sharp set of front
+D:teeth.
+
+# New monster added by furiosity for the Theme module
+N:814:Vampire troll
+G:V:u
+I:110:35d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | TROLL | STUPID |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is a troll with an aura of power. You notice a sharp set of front
+D:teeth.
+
+# New monster added by furiosity for the Theme module
+N:815:Vampire dwarf
+G:V:R
+I:110:30d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is a dwarf with an aura of power. You notice a sharp set of front
+D:teeth.
+
+# New monster added by furiosity for the Theme module
+N:816:Vampire elf
+G:V:G
+I:110:30d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is an elf with an aura of power. You notice a sharp set of front
+D:teeth.
+
+# New monster added by furiosity for the Theme module
+N:817:Vampire gnome
+G:V:B
+I:110:15d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP | STUPID |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is a gnome with an aura of power. You notice a sharp set of front
+D:teeth.
+
+N:818:The Mouth of Sauron
+G:p:v
+I:130:90d100:60:100:10
+W:78:3:1900:38000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+B:TOUCH:UN_POWER
+B:TOUCH:UN_POWER
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART |
+F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_COLD |
+F:IM_ELEC | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:TELE_TO | HOLD | CAUSE_3 | TRAPS | ANIM_DEAD |
+S:BO_PLAS | BA_DARK | BA_MANA | BA_FIRE | BA_WATE | BA_NETH
+S:S_HI_DEMON | S_HI_UNDEAD
+D:The Mouth of Sauron is a mighty spellcaster. So old that even he cannot
+D:remember his own name, his power and evil are undeniable. He believes
+D:unshakably that he is unbeatable and laughs as he weaves his awesome
+D:spells.
+
+N:819:The Necromancer of Dol Guldur
+G:p:v
+I:130:82d100:60:100:10
+W:75:3:1900:40000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_POWER:6d8
+B:HIT:BLIND:6d8
+B:HIT:CONFUSE:6d8
+F:UNIQUE | MALE | CAN_SPEAK | POWERFUL | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_1D2 | DROP_GREAT | DROP_GOOD | SPECIAL_GENE |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_FIRE | IM_COLD |
+F:IM_ELEC | NO_CONF | NO_SLEEP | BASEANGBAND
+S:1_IN_2 |
+S:CAUSE_3 | TELE_TO | BA_FIRE | DRAIN_MANA | HOLD |
+S:TRAPS | BA_WATE | BO_PLAS | BA_NETH |
+S:BA_MANA | BA_DARK | S_HI_UNDEAD | BA_CHAO | HAND_DOOM | ANIM_DEAD
+D:The dark master of the terrible fortress of southern Mirkwood. It is
+D:rumoured that this is in fact none other than Sauron in disguise:
+D:although if this is so, he has yet to reveal his full power - and perhaps
+D:will not do so while his deception lasts.
+
+N:820:Lisa, rider of gold Romth
+G:B:y
+I:130:65d100:100:100:15
+W:78:6:420000:35500
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:10d15
+B:HIT:HURT:10d15
+B:HIT:HURT:10d15
+B:HIT:HURT:10d15
+F:UNIQUE | FEMALE | THUNDERLORD | RES_TELE | CAN_FLY | GOOD |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | PET | AQUATIC |
+F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
+F:IM_COLD | IM_POIS | IM_ACID | IM_ELEC | REGENERATE |
+F:MORTAL | HAS_LITE
+S:1_IN_4 |
+S:TPORT | TELE_TO | BR_FIRE | S_THUNDERLORD |
+S:TELE_AWAY | HEAL | BA_NETH | BO_NETH | BA_FIRE | BO_FIRE
+D:A leader among the Thunderlords of good, she came to help you.
+
+N:821:Master quylthulg
+G:Q:B
+I:120:30d100:20:1:0
+W:76:2:7000:15000
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:INVISIBLE | EMPTY_MIND | ANIMAL | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_2 |
+S:S_MONSTERS | S_HI_UNDEAD | S_HI_DRAGON | S_HI_DEMON | S_ANIMALS | BLINK | TELE_TO
+D:A giant seething mass of flesh, overwhelming you with monster after monster.
+
+N:822:Qlzqqlzuup, the Lord of Flesh
+G:Q:o
+I:130:50d100:30:1:0
+W:79:3:10000:20000
+E:0:0:0:0:0:0
+O:20:20:20:20
+F:UNIQUE | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP | NEVER_MOVE | NEVER_BLOW |
+F:ONLY_ITEM | DROP_4D2 |
+F:INVISIBLE | EMPTY_MIND | ANIMAL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND
+S:1_IN_1 |
+S:S_MONSTERS | S_HOUND | S_HYDRA | S_SPIDER | S_ANT | S_ANIMALS |
+S:S_HI_UNDEAD | S_HI_DRAGON | S_HI_DEMON | S_WRAITH | S_UNIQUE | S_KIN
+D:A gigantic seething mass of flesh, Qlzqqlzuup changes colours in front
+D:of your eyes. Pulsating first one colour then the next, it knows only it
+D:must bring help to protect itself.
+
+# New monster added by furiosity for the Theme module
+N:823:Vampire adventurer
+G:V:U
+I:110:25d12:20:45:10
+W:27:1:1700:175
+E:1:1:1:2:1:1
+O:20:40:20:10
+B:HIT:HURT:1d6
+B:HIT:HURT:1d6
+B:BITE:EXP_20:2d6
+B:BITE:EXP_20:2d6
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:COLD_BLOOD | DROP_60 | DROP_1D2 | PET |
+F:OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
+F:GOOD | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9 |
+S:TELE_TO | HOLD | SCARE | CAUSE_2 | MIND_BLAST | FORGET | DARKNESS
+D:It is an adventurer with an aura of power. You notice a sharp set
+D:of front teeth.
+
+N:824:Flare, rider of bronze Moonth
+G:B:U
+I:130:70d100:100:100:15
+W:79:5:400000:38500
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:15d15
+B:HIT:HURT:15d15
+B:HIT:HURT:15d15
+B:HIT:HURT:15d15
+F:UNIQUE | MALE | THUNDERLORD | RES_TELE | CAN_FLY | CAN_SPEAK |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_SLEEP | FORCE_MAXHP | PET | GOOD | AQUATIC |
+F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
+F:IM_COLD | IM_POIS | IM_ACID | IM_ELEC | IM_FIRE | REGENERATE |
+F:MORTAL | HAS_LITE
+S:1_IN_4 |
+S:SCARE | TPORT | TELE_TO | S_THUNDERLORD |
+S:TELE_LEVEL | HEAL | BR_FIRE | BR_TIME | ROCKET
+D:A leader from afar, he has come with his eagle to help you in
+D:your battle. Having already saved his home, he now wants to save Arda.
+
+N:825:Maeglin, the Traitor of Gondolin
+G:h:D
+I:130:60d100:220:120:20
+W:81:2:1400:35000
+E:1:1:1:2:1:1
+O:30:70:0:0
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | CAN_SPEAK | SMART | EVIL | AI_SPECIAL |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | KILL_WALL | MOVE_BODY | TAKE_ITEM |
+F:IM_FIRE | IM_COLD | IM_POIS | SPECIAL_GENE |
+F:REGENERATE | REFLECTING | DROP_SKELETON | DROP_CORPSE | BASEANGBAND
+F:HAS_LITE
+S:1_IN_6 |
+S:S_MONSTERS | S_WRAITH | S_HI_UNDEAD |
+S:S_HI_DRAGON | S_HI_DEMON | S_UNIQUE | S_ANIMALS
+D:The son of Eol the Dark Elf, Maeglin is every bit as evil as his father
+D:and more. His greed for gold led him to betray the Hidden Kingdom of
+D:Gondolin to Morgoth's forces. He is a mighty warrior himself, and some
+D:of Morgoth's greatest servants answer to his call.
+
+# New monster added by furiosity for the Theme module
+N:826:Snow-frog
+G:R:w
+I:110:5d8:12:16:50
+W:7:1:200:16
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:COLD:2d4
+F:RAND_50 | WILD_TOO | WILD_SHORE | WILD_SWAMP |
+F:BASH_DOOR | DROP_CORPSE | IM_COLD | WILD_WASTE |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:It is a strange frog adapted to cold environments.
+
+# New monster added by furiosity for the Theme module
+N:827:Swamp lizard
+G:R:o
+I:110:3d4:20:4:15
+W:5:2:100:8
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+B:SPIT:POISON:2d4
+F:ANIMAL | CAN_SWIM | WILD_TOO | WILD_WOOD | WILD_SWAMP |
+F:DROP_CORPSE | HAS_EGG | IMPRESED | IM_POIS |
+F:MORTAL | BASEANGBAND
+D:It is a small lizard that usually lives in the
+D:marshlands. It looks poisonous.
+
+# New monster added by furiosity for the Theme module
+N:828:Giant silver frog
+G:R:W
+I:110:3d4:20:4:15
+W:5:2:100:8
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+B:SPIT:EAT_LITE:2d4
+F:ANIMAL | CAN_SWIM | WILD_TOO | WILD_WOOD | WILD_SWAMP |
+F:DROP_CORPSE | IM_POIS | HURT_LITE |
+F:MORTAL | BASEANGBAND
+D:A frog that seems to emit a strange dark light.
+
+N:829:Greater Hellhound
+G:C:r
+I:120:48d30:25:80:30
+W:78:2:600:600
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:5d12
+B:BITE:FIRE:5d12
+B:BITE:FIRE:5d12
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE
+F:RAND_25 | FRIENDS | AURA_FIRE | SUSCEP_COLD |
+F:BASH_DOOR | MOVE_BODY |
+F:ANIMAL | EVIL | IM_FIRE | BASEANGBAND | HAS_LITE |
+S:1_IN_5 | BR_FIRE
+D:It is a giant dog that glows with heat. Flames pour from its nostrils.
+
+N:830:Cantoras, the Skeletal Lord
+G:s:v
+I:140:75d100:20:120:80
+W:84:2:0:45000
+E:1:1:1:2:1:1
+O:50:0:50:0
+B:GAZE:EXP_80:5d5
+B:GAZE:EXP_80:5d5
+B:TOUCH:POISON:5d5
+B:TOUCH:POISON:5d5
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_FIRE | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:TELE_TO | SLOW | SCARE | CAUSE_4 | BRAIN_SMASH |
+S:BO_ICEE | BO_MANA | BA_WATE | BA_NETH |
+S:S_HI_UNDEAD | ANIM_DEAD
+D:A legion of evil undead druj animating the skeleton of a once mighty
+D:sorcerer. His power is devastating and his speed unmatched in the
+D:underworld.
+
+# New monster added by furiosity for the Theme module
+N:831:Blue lizard
+G:R:B
+I:110:3d4:20:4:15
+W:5:2:100:8
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+B:SPIT:ELEC:2d4
+F:ANIMAL | CAN_SWIM | WILD_TOO | WILD_WOOD | WILD_SWAMP |
+F:DROP_CORPSE | HAS_EGG | IMPRESED | IM_ELEC |
+F:MORTAL | BASEANGBAND
+D:It is a small lizard with powerful jaws which cause
+D:sparks to fly as they snap shut.
+
+# New monster added by furiosity for the Theme module
+N:832:Death dragonfly
+G:F:D
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:EXP_40:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | RES_NETH |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_NETH
+D:The size of a large bird, this fly carries with it the
+D:stench of decay.
+
+# New monster added by furiosity for the Theme module
+N:833:Giant swamp dragonfly
+G:F:o
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:TERRIFY:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_NUKE
+D:The size of a large bird, this fly comes from a dark swamp.
+
+# New monster added by furiosity for the Theme module
+N:834:Giant red dragonfly
+G:F:r
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ACID:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 | AURA_FIRE |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | IM_FIRE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_FIRE
+D:The size of a large bird, this fly is surrounded by flames.
+
+# New monster added by furiosity for the Theme module
+N:835:Giant forest dragonfly
+G:F:g
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:PARALYZE:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | IM_ACID | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_DARK
+D:The size of a large bird, this fly prefers to dwell in
+D:the forest, and is rather stealthy.
+
+# New monster added by furiosity for the Theme module
+N:836:Giant blue dragonfly
+G:F:b
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ELEC:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | IM_ELEC |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_ELEC
+D:The size of a large bird, this fly crackles with sparks.
+
+# New monster added by furiosity for the Theme module
+N:837:Giant brown dragonfly
+G:F:u
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | NO_CUT |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_SHAR
+D:The size of a large bird, this fly dives from the earth
+D:into the air, and back.
+
+N:838:The Tarrasque
+G:R:v
+I:130:130d100:50:185:20
+W:84:2:50000:35000
+E:1:1:1:2:1:1
+O:20:50:25:5
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:TOUCH:UN_POWER:10d10
+B:TOUCH:UN_POWER:10d10
+F:UNIQUE | ATTR_MULTI |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | IM_FIRE | IM_COLD | NO_SLEEP | BASEANGBAND
+S:1_IN_2 |
+S:BR_FIRE | BR_COLD | BR_DISE
+D:The Tarrasque is a massive reptile of legend, rumoured to be unkillable
+D:and immune to magic. Fear its anger, for its devastation is unmatched.
+
+N:839:Lungorthin, the Balrog of White Fire
+G:U:w
+I:130:80d100:20:125:80
+W:88:2:14000:37000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:FIRE:8d12
+B:HIT:FIRE:8d12
+B:CRUSH:HURT:8d12
+B:TOUCH:UN_POWER
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON | IM_FIRE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_FIRE | BR_PLAS |
+S:S_HI_DEMON | S_UNDEAD
+D:A massive form cloaked in flame. Lungorthin stares balefully at you with
+D:eyes that smoulder red. The dungeon floor where he stands is scorched by
+D:the heat of his body.
+
+N:840:Draugluin, Sire of All Werewolves
+G:C:v
+I:130:80d100:80:90:90
+W:83:2:1000:40000
+E:0:1:0:2:1:0
+O:0:0:100:0
+B:CLAW:HURT:6d8
+B:CLAW:HURT:6d8
+B:BITE:POISON:6d6
+B:BITE:POISON:6d6
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT | ESCORTS | DROP_CORPSE |
+F:RAND_25 |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:ANIMAL | EVIL | IM_POIS | BASEANGBAND
+S:1_IN_3 |
+S:SCARE | S_MONSTERS | S_HOUND
+D:Draugluin provides Sauron with a fearsome personal guard. He is an
+D:enormous wolf inhabited by a human spirit. He is chief of all his kind.
+
+# New monster added by furiosity for the Theme module
+N:841:Giant silver dragonfly
+G:F:W
+I:100:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:EAT_LITE:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | NO_CUT |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_INER
+D:The size of a large bird, this fly moves slowly.
+
+# New monster added by furiosity for the Theme module
+N:842:Giant violet dragonfly
+G:F:v
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:CONFUSE:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | NO_CUT |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_CHAO
+D:The size of a large bird, this fly is surrounded by an
+D:aura of raw chaos.
+
+# New monster added by furiosity for the Theme module
+N:843:Giant pink dragonfly
+G:F:u
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:LOSE_STR:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | NO_CUT |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BR_PLAS
+D:The size of a large bird, this fly seems to scorch the
+D:very air around it.
+
+N:844:Vecna, the Emperor Lich
+G:L:v
+I:130:80d100:100:100:0
+W:92:3:0:45000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:EXP_80:7d12
+B:HIT:LOSE_DEX:7d12
+B:HIT:UN_POWER:7d12
+B:HIT:UN_POWER:7d12
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ESCORT |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_SLEEP | BASEANGBAND
+F:NO_CUT
+S:1_IN_3 |
+S:TPORT | BLIND | SCARE | CAUSE_4 | BRAIN_SMASH |
+S:BA_MANA | BO_MANA | BA_FIRE | BA_NETH |
+S:S_MONSTERS | S_HI_DEMON | S_HI_UNDEAD | S_KIN | HAND_DOOM | ANIM_DEAD
+D:The greatest of all undead sorcerers, even the gods once feared him. This
+D:ancient shadow of death wilts every living thing it passes.
+
+# New monster added by furiosity for the Theme module
+N:845:Aquatic dragonfly
+G:F:B
+I:120:3d8:12:20:50
+W:20:2:150:70
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:FORCE_SLEEP | RAND_50 | RAND_25 |
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY | WILD_TOO | WILD_SWAMP |
+F:ANIMAL | NO_CUT | AQUATIC | RES_WATE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BA_WATE
+D:The size of a large bird, this fly prefers watery regions.
+
+# New monster added by furiosity for the Theme module
+N:846:Giant red mouse
+G:r:r
+I:110:1d3:8:4:20
+W:4:1:200:3
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:FIRE:1d2
+F:RAND_25 | SUSCEP_COLD | ANIMAL | IM_FIRE |
+F:DROP_CORPSE | MORTAL | BASEANGBAND | CAN_SWIM |
+S:MULTIPLY
+D:It is about three feet long with large teeth and red fur.
+D:It is a corrupted creature of Melkor.
+
+N:847:Great Wyrm of Power
+G:D:v
+I:130:111d111:40:160:70
+W:85:4:220000:47500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:8d12
+B:CLAW:HURT:8d12
+B:BITE:HURT:10d14
+B:BITE:HURT:10d14
+F:FORCE_SLEEP | FORCE_MAXHP | MOVE_BODY | AURA_FIRE | REFLECTING | AURA_ELEC |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | AURA_COLD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | RES_NETH | RES_DISE |
+F:DRAGON | GOOD | RES_TELE | DROP_CORPSE | AQUATIC |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:RES_NEXU | RES_PLAS | CAN_FLY | BASEANGBAND | HAS_LITE | NO_CUT
+F:ATTR_MULTI
+S:1_IN_4 |
+S:S_HI_DRAGON | S_DRAGON | S_KIN |
+S:BR_NUKE | BR_ACID | BR_ELEC | BR_FIRE |
+S:BR_COLD | BR_POIS | BR_NETH | BR_LITE | BR_DARK |
+S:BR_CONF | BR_SOUN | BR_CHAO | BR_DISE | BR_NEXU |
+S:BR_TIME | BR_INER | BR_GRAV | BR_SHAR | BR_PLAS |
+S:BR_WALL | BR_MANA | BR_DISI
+D:The mightiest of all dragonkind, a great worm of power is seldom
+D:encountered in our world. It can crush stars with its might.
+
+# New monster added by furiosity for the Theme module
+N:848:Giant blue mouse
+G:r:b
+I:110:1d3:8:4:20
+W:4:1:200:3
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ELEC:1d2
+F:RAND_25 | ANIMAL | IM_ELEC |
+F:DROP_CORPSE | MORTAL | BASEANGBAND | CAN_SWIM |
+S:MULTIPLY
+D:It is about three feet long with large teeth and blue fur.
+D:Its teeth produce sparks on impact.
+
+# New monster added by furiosity for the Theme module
+N:849:Giant yellow mouse
+G:r:y
+I:110:1d3:8:4:20
+W:4:1:200:3
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:ACID:1d2
+F:RAND_25 | ANIMAL | IM_ACID |
+F:DROP_CORPSE | MORTAL | BASEANGBAND | CAN_SWIM |
+S:MULTIPLY
+D:It is about three feet long with large teeth and yellow fur.
+D:Its teeth produce a corrosive substance.
+
+N:850:Carcharoth, the Jaws of Thirst
+G:C:D
+I:130:90d100:80:110:10
+W:94:1:3400:40000
+E:0:1:0:2:1:0
+O:30:10:60:0
+B:CLAW:POISON:9d12
+B:CLAW:POISON:9d12
+B:BITE:FIRE:9d12
+B:BITE:FIRE:9d12
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | AURA_FIRE |
+F:SMART | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:ANIMAL | EVIL | IM_FIRE | IM_POIS | BASEANGBAND
+S:1_IN_3 |
+S:BR_DARK | BR_POIS | BR_FIRE | BR_NETH | S_HOUND
+D:The first guard of Angband, Carcharoth, also known as 'The Red Maw', is
+D:the largest wolf to ever walk the earth. He is highly intelligent and a
+D:deadly opponent in combat.
+
+# New monster added by furiosity for the Theme module
+N:851:Giant pink rat
+G:r:R
+I:110:2d3:8:12:20
+W:9:1:250:2
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:LOSE_STR:1d4
+F:RAND_25 | ANIMAL | DROP_SKELETON |
+F:DROP_CORPSE | MORTAL | BASEANGBAND | CAN_SWIM |
+S:MULTIPLY
+D:It is a rodent of unusual size with no fur covering it.
+
+# New monster added by furiosity for the Theme module
+N:852:Giant tree rat
+G:r:G
+I:110:2d3:8:12:20
+W:9:1:250:3
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:1d4
+B:BITE:HURT:2d4
+F:RAND_25 | ANIMAL | DROP_SKELETON | IM_POIS | CAN_FLY |
+F:DROP_CORPSE | MORTAL | BASEANGBAND | CAN_SWIM |
+S:MULTIPLY
+D:A large rat that lives in the trees.
+
+N:853:Huan, Wolfhound of the Valar
+G:C:W
+I:130:90d100:50:160:10
+W:93:2:3400:40000
+E:0:1:0:2:1:0
+O:30:10:60:0
+B:CLAW:COLD:9d12
+B:CLAW:COLD:9d12
+B:BITE:COLD:9d12
+B:BITE:COLD:9d12
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | NEUTRAL | NO_TARGET |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | AURA_COLD |
+F:SMART | OPEN_DOOR | BASH_DOOR | KILL_BODY |
+F:ANIMAL | GOOD | WILD_ONLY | WILD_GRASS | WILD_GRASS |
+F:WILD_WASTE | WILD_WOOD | WILD_SHORE |
+F:IM_COLD | IM_ACID | IM_ELEC | BASEANGBAND
+S:1_IN_5 |
+S:BR_COLD | BR_SHAR | BR_SOUN | BR_LITE |
+D:The wolfhound of the Valar, Huan has served many masters in his time, from
+D:Celegorm son of Feanor to Beren son of Barahir: but now he runs wild and
+D:acknowledges no master save himself, as he hunts alone for his nemesis -
+D:Carcharoth, the terrible wolf of Angband.
+
+# New monster added by furiosity for the Theme module
+N:854:Polar bear
+G:q:w
+I:110:10d10:10:35:10
+W:9:1:2000:27
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+B:BITE:HURT:1d6
+F:WEIRD_MIND | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
+F:ANIMAL | MORTAL | BASEANGBAND | IM_COLD | WILD_TOO |
+D:A huge white bear, accustomed to extremely cold temperatures.
+
+# New monster added by furiosity for the Theme module
+N:855:Blue bear
+G:q:b
+I:110:10d10:10:35:10
+W:9:1:2000:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:2d4
+B:CLAW:HURT:2d4
+B:BITE:HURT:2d6
+F:WEIRD_MIND | BASH_DOOR | FRIENDS | DROP_SKELETON | DROP_CORPSE
+F:ANIMAL | HURT_LITE | IM_COLD |
+F:MORTAL | BASEANGBAND
+D:A huge blue-black bear with thick fur. It can withstand
+D:extremely cold temperatures and usually hunts at night,
+D:and always in packs.
+
+N:856:Gothmog, the High Captain of Balrogs
+G:U:v
+I:130:120d100:100:140:0
+W:95:1:17000:43000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:FIRE:9d12
+B:HIT:FIRE:9d12
+B:CRUSH:HURT:8d12
+B:TOUCH:UN_POWER
+F:UNIQUE | MALE | CAN_SPEAK | CAN_FLY |
+F:FORCE_SLEEP | FORCE_MAXHP | ATTR_MULTI |
+F:ESCORT | ESCORTS | KILL_WALL | AURA_FIRE | NONLIVING |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON |
+F:IM_FIRE | IM_ELEC | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BLIND | CONF | SCARE |
+S:BR_FIRE | S_KIN |
+S:S_HI_DEMON | S_HI_UNDEAD
+D:Gothmog is the offspring of Morgoth and an ogress. He is renowned
+D:for slaying three High Kings of the Noldor Elves, and he has never been
+D:defeated in combat. With his whip of flame and awesome fiery breath he
+D:saved his master from Ungoliant's rage.
+
+# New monster added by furiosity for the Theme module
+N:857:Old bear
+G:q:W
+I:110:20d10:10:35:255
+W:15:1:2000:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:4d4
+B:CLAW:HURT:4d4
+B:BITE:HURT:4d6
+F:WEIRD_MIND | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
+F:ANIMAL | NEUTRAL | NO_TARGET | WILD_ONLY | WILD_WOOD |
+F:WILD_GRASS | WILD_SHORE | MORTAL | BASEANGBAND
+D:An experienced bear whose fur is silvery white. It just
+D:wants to eat its dinner in peace.
+
+N:858:Sarko, rider of gold Foronth
+G:B:y
+I:145:99d111:100:165:0
+W:97:6:420000:65000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:12d12
+B:HIT:HURT:12d12
+B:HIT:FIRE:12d12
+B:HIT:FIRE:12d12
+F:UNIQUE | FEMALE | DROP_CORPSE |
+F:ATTR_MULTI | THUNDERLORD | RES_TELE | PET | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | GOOD | AQUATIC |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:DROP_CHOSEN | REFLECTING | AURA_FIRE | AURA_ELEC |
+F:SMART | OPEN_DOOR | BASH_DOOR | MOVE_BODY | REGENERATE |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | POWERFUL |
+F:MORTAL | HAS_LITE
+S:1_IN_4 |
+S:TPORT | TELE_TO | BR_FIRE | BR_TIME | S_THUNDERLORD | TELE_AWAY |
+D:Foronth is the first Eagle queen, and Sarko the first to discover
+D:the Firebirds, the ancestors of the Thunderlord eagles. She will try to
+D:help you.
+
+# New monster added by furiosity for the Theme module
+N:859:Teddy bear
+G:q:v
+I:110:10d10:10:35:10
+W:9:1:2000:25
+E:0:1:0:2:1:0
+O:0:0:0:0
+F:WEIRD_MIND | BASH_DOOR | NONLIVING | JOKEANGBAND | NEVER_BLOW |
+F:NO_CUT | NO_FEAR | NO_CONF | RES_TELE | NO_STUN | PET |
+S:1_IN_2
+S:CONF | BLINK |
+D:A cute cuddly creature made of a strange soft material. It has
+D:been animated by a jokester wizard, and searches for a child to
+D:play with.
+
+N:860:Sauron, the Sorcerer
+G:p:v
+I:130:100d225:100:160:0
+W:99:1:2300:50000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:10d12
+B:HIT:UN_BONUS:10d12
+B:HIT:UN_POWER:8d12
+B:HIT:UN_POWER:8d12
+F:UNIQUE | MALE | CAN_SPEAK | REFLECTING |
+F:FORCE_SLEEP | FORCE_MAXHP | FORCE_DEPTH |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:SMART | OPEN_DOOR | BASH_DOOR | MOVE_BODY | REGENERATE | NO_SLEEP | NO_FEAR | NO_CONF |
+F:EVIL | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_TELE | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:TPORT | TELE_LEVEL | BLIND | CONF | SCARE | CAUSE_4 |
+S:BRAIN_SMASH | FORGET | BO_ICEE | BO_MANA | BO_PLAS |
+S:BA_MANA | BA_FIRE | BA_WATE | BA_NETH | BA_DARK | BA_CHAO |
+S:S_MONSTERS | S_HI_DEMON | S_HI_UNDEAD | S_HI_DRAGON | S_WRAITH | S_UNIQUE |
+S:HAND_DOOM | ANIM_DEAD
+D:Mighty in spells and enchantments, he created the One Ring.
+D:His eyes glow with power and with his gaze he seeks to destroy
+D:your soul. He has many servants, and rarely fights without them.
+
+N:861:DarkGod, the Mighty Coder of Hell
+G:P:B
+I:155:180d100:111:175:0
+W:127:1:1600:66666
+E:2:0:2:6:1:1
+O:20:20:20:20
+B:GAZE:EAT_GOLD:20d10
+B:HIT:SHATTER:20d10
+B:BITE:LOSE_ALL:10d12
+B:TOUCH:UN_POWER
+F:UNIQUE | CAN_SPEAK | ATTR_MULTI | ATTR_ANY | MALE |
+F:FORCE_MAXHP | WEIRD_MIND | DROP_CORPSE | DROP_SKELETON |
+F:REFLECTING | AURA_FIRE | AURA_ELEC | AURA_COLD |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | RES_NETH | INVISIBLE |
+F:SMART | KILL_WALL | KILL_BODY | POWERFUL | RES_TELE |
+F:REGENERATE | CAN_FLY | CAN_SWIM | DG_CURSE | WYRM_PROTECT |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF |NO_FEAR | NO_STUN | RES_TELE
+F:MORTAL | JOKEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:S_THUNDERLORD | BR_CHAO | BA_CHAO | ROCKET | BRAIN_SMASH | S_HI_DEMON |
+S:BR_NETH | HASTE | BR_MANA | S_HI_UNDEAD | S_HI_DRAGON | TRAPS | FORGET |
+S:BR_NUKE | BR_POIS | BR_DISI | HAND_DOOM | HEAL | TPORT | TELE_TO |
+S:S_BUG | S_RNG |
+D:He is the master of coding; none can match his skill. He created the
+D:Variant Maintainer, the RNGs, and the software bugs. Bull Gates is
+D:nothing next to him. Do not think that since he loves the novels of
+D:Tolkien he is to be ignored! He wishes to translate your soul into
+D:assembler, the one hitch being that he must kill you first. If you
+D:encounter him, pray your deity holds you in good stead.
+
+N:862:Morgoth, Lord of Darkness
+G:P:D
+I:140:200d150:100:150:0
+W:100:1:200000:60000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:SHATTER:24d10
+B:HIT:SHATTER:24d10
+B:HIT:LOSE_ALL:10d12
+B:TOUCH:UN_POWER
+F:UNIQUE | CAN_SPEAK | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | FORCE_DEPTH |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | DROP_CHOSEN | RES_NETH |
+F:SMART | KILL_WALL | MOVE_BODY | AURA_COLD |
+F:REGENERATE | POWERFUL |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_STUN | NO_SLEEP | NO_FEAR | RES_TELE | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BRAIN_SMASH |
+S:BA_MANA | BO_MANA | BA_NETH | BA_CHAO | BA_DARK | ANIM_DEAD |
+S:S_MONSTERS | S_UNIQUE | S_HI_DEMON | S_HI_UNDEAD | S_HI_DRAGON |
+S:ROCKET | BR_NETH | BR_DISI | HAND_DOOM | S_WRAITH
+D:He was the most powerful of the Valar, the equal of Manwe.
+D:He is the Master of the Pits of Angband. His figure is like a black
+D:mountain crowned with Lightning. He rages with everlasting anger, his
+D:body scarred by Fingolfin's eight mighty wounds. He can never rest from
+D:his pain, but seeks forever to dominate all that is light and good in the
+D:world. He is the origin of man's fear of darkness and created many foul
+D:creatures with his evil powers. Orcs, Dragons, and Trolls are his most
+D:foul corruptions, causing much pain and suffering in the world to please
+D:him. His disgusting visage, twisted with evil, is crowned with iron.
+D:Grond, the mighty Hammer of the Underworld, cries defiance as he strides
+D:towards you to crush you to a pulp!
+
+N:863:Human Warrior
+G:p:u
+I:110:9d8:10:10:0
+W:0:20:1700:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:5d8
+F:MALE |
+F:PET | FRIENDS | WILD_ONLY |
+F:ONLY_GOLD | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR
+F:DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:They are used as the main assault force of the human kings.
+
+N:864:Elven archer
+G:h:W
+I:110:9d7:10:10:0
+W:0:20:1400:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:2d8
+F:MALE |
+F:PET | FRIENDS | WILD_ONLY |
+F:ONLY_GOLD | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR
+F:DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_1 |
+S:ARROW_2 | ARROW_1 | ARROW_2 | ARROW_1 |
+D:They are used as the main assault force of the elven kings.
+
+N:865:Dwarven warrior
+G:k:U
+I:110:8d8:10:10:0
+W:0:20:1500:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:6d8
+F:MALE |
+F:PET | FRIENDS | WILD_ONLY |
+F:ONLY_GOLD | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR
+F:DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:They are used as the main assault force of the dwarven kings.
+
+N:866:Elite uruk
+G:o:w
+I:110:10d10:20:50:0
+W:20:1:2000:70
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:8d5
+B:HIT:HURT:8d5
+F:MALE |
+F:FORCE_MAXHP | FRIENDS | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | ORC | IM_POIS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:ARROW_2
+D:It is a cunning orc of power, taller than a man, and stronger. It fears
+D:little.
+
+# New monster added by furiosity for the Theme module
+N:867:Fire bear
+G:q:R
+I:110:10d10:10:35:10
+W:13:2:2000:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:FIRE:1d4
+B:BITE:HURT:3d6
+F:WEIRD_MIND | BASH_DOOR | FRIENDS | DROP_SKELETON | DROP_CORPSE
+F:ANIMAL | IM_FIRE | SUSCEP_COLD |
+F:MORTAL | BASEANGBAND
+D:A fierce bear trained to withstand the hottest environments.
+
+N:868:The Variant Maintainer
+G:p:B
+I:160:10d10:30:50:0
+W:10:1:1700:3000
+E:1:1:1:2:1:1
+O:20:20:20:20
+B:INSULT:*
+B:HIT:INSANITY:1d8
+B:HIT:LOSE_WIS:1d8
+F:ONLY_ITEM | DROP_2D2 | UNIQUE | CAN_FLY |
+F:DROP_GOOD | WEIRD_MIND | CAN_SPEAK |
+F:RAND_50 | RAND_25 | INVISIBLE | EVIL |
+F:MORTAL | JOKEANGBAND | HAS_LITE
+S:1_IN_2
+S:S_BUG | S_RNG | BR_CONF
+D:A deranged programmer, scattering bizarre ideas and bad code everywhere.
+
+N:869:Random Number Generator
+G:I:b
+I:130:1d6:10:50:0
+W:10:1:0:10
+E:0:0:0:0:0:0
+O:20:20:20:20
+B:INSULT:*
+B:MOAN:*
+B:HIT:CONFUSE:1d6
+F:DROP_1D2 | EVIL |
+F:EMPTY_MIND | RAND_50 | RAND_25 | JOKEANGBAND
+S:MULTIPLY
+D:A feared creation of the Variant Maintainer, it tries to generate Morgoth
+D:in the town and the One Ring in the magic shop.
+
+N:870:Rocket mine
+G:.:R
+I:110:20d8:20:3:10
+W:50:10:0:100
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:10d5
+F:NEVER_MOVE | IM_POIS | NONLIVING | IM_ACID | STUPID |
+F:FORCE_MAXHP | UNDEAD | EVIL | JOKEANGBAND | NO_CUT
+S:1_IN_4
+S:ROCKET | ARROW_4
+D:It was left here to be used against intruders.
+
+N:871:Bouncing mine
+G:.:B
+I:120:20d15:50:5:10
+W:70:10:0:200
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:10d5
+F:NEVER_MOVE | IM_POIS | NONLIVING | IM_ACID | STUPID |
+F:FORCE_MAXHP | UNDEAD | EVIL | JOKEANGBAND | NO_CUT
+S:1_IN_3
+S:ROCKET | ARROW_4 | BLINK | BR_POIS | BR_CHAO | BR_NEXU
+D:It was left here to be used against intruders.
+
+N:872:Durin's Bane
+G:U:R
+I:130:30d100:20:100:80
+W:50:3:13000:30000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:FIRE:6d12
+B:HIT:FIRE:6d12
+B:CRUSH:HURT:5d12
+B:TOUCH:UN_POWER
+F:UNIQUE | MALE | SPECIAL_GENE | DROP_RANDART
+F:FORCE_SLEEP | FORCE_MAXHP | KILL_WALL |
+F:ESCORT | ESCORTS | DROP_CORPSE | NONLIVING |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_CHOSEN |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON | IM_FIRE |
+F:NO_CONF | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:CONF | SCARE |
+S:BR_FIRE |
+S:S_UNDEAD | S_DEMON
+D:A huge Balrog surrounded by raging pillars of fire, this is indeed a
+D:terrible opponent. Wielding a great whip of fire and a blazing sword, his
+D:fury blisters your skin and melts your flesh.
+
+# New monster added by furiosity for the Theme module
+N:873:Aquatic bear
+G:q:B
+I:110:10d10:10:35:10
+W:15:1:2000:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d4
+B:CLAW:CONFUSE:1d4
+B:BITE:PARALYZE:1d6
+F:WEIRD_MIND | BASH_DOOR | FRIENDS | DROP_SKELETON | DROP_CORPSE
+F:ANIMAL | RES_WATE | CAN_SWIM | AQUATIC |
+F:MORTAL | BASEANGBAND
+D:A strange bear the prefers to live in the water.
+
+N:874:Rot jelly
+G:j:u
+I:120:20d8:2:30:99
+W:5:1:2000:15
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:EAT_FOOD:2d3
+B:TOUCH:LOSE_CHR:2d3
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND | CAN_SWIM |
+F:HURT_LITE | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a large pile of rotting flesh, whose touch spoils your food. The terrible
+D:smell it exudes is also very hard to get rid of...
+
+N:875:Death
+G:G:D
+I:130:50d100:200:120:5
+W:80:6:3000:25000
+E:1:1:1:2:1:1
+O:10:80:20:0
+B:HIT:HURT:20d5
+B:HIT:HURT:20d5
+B:TOUCH:EXP_80:20d5
+B:TOUCH:EXP_80:20d5
+F:UNIQUE |
+F:FORCE_MAXHP | DROP_CORPSE |
+F:DROP_GOOD | DROP_GREAT | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | PASS_WALL | NO_SLEEP | NO_STUN | NO_CONF |
+F:EVIL | UNDEAD | JOKEANGBAND | NO_CUT
+D:The leader of the horsemen of the apocalypse, before you lies Death.
+D:A bony skeleton in a huge dark robe wielding a great scythe, Death rides
+D:a horse of purest black and comes to bring your death.
+
+N:876:Famine
+G:G:U
+I:130:50d100:200:120:5
+W:77:6:3000:25000
+E:1:1:1:2:1:1
+O:10:80:20:0
+B:TOUCH:EAT_FOOD:20d4
+B:GAZE:UN_BONUS:20d4
+B:WAIL:LOSE_INT:10d5
+B:WAIL:LOSE_DEX:10d5
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | DROP_CORPSE |
+F:DROP_GOOD | DROP_GREAT | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | PASS_WALL | NO_STUN | NO_SLEEP | NO_CONF |
+F:EVIL | UNDEAD | JOKEANGBAND | NO_CUT
+D:One of the horsemen of the apocalypse, before you lies Famine. A
+D:figure so gaunt that the shape of the bones beneath are revealed,
+D:Famine rides a pale grey mare that appears near death.
+
+N:877:Pestilence
+G:G:G
+I:130:50d100:200:120:5
+W:74:6:3000:25000
+E:1:1:1:2:1:1
+O:10:80:20:0
+B:TOUCH:POISON:20d4
+B:TOUCH:POISON:20d4
+B:TOUCH:DISEASE:16d5
+B:TOUCH:DISEASE:16d5
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | DROP_CORPSE |
+F:DROP_GOOD | DROP_GREAT | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | PASS_WALL | NO_SLEEP | NO_STUN | NO_CONF |
+F:EVIL | UNDEAD | JOKEANGBAND | NO_CUT
+S:1_IN_2 |
+S:S_ANT | S_SPIDER
+D:One of the horsemen of the apocalypse, before you lies Pestilence.
+D:At first, it looks like a human, but then you notice ants, worms, and
+D:worse peeking out of the flesh. Pestilence rides a purple horse with
+D:skin that bulges and occasionally gives hints of the vermin within.
+
+N:878:War
+G:G:r
+I:130:50d100:200:120:5
+W:71:6:3000:25000
+E:1:1:1:2:1:1
+O:10:80:20:0
+B:TOUCH:PARALYZE:20d4
+B:WAIL:CONFUSE:20d4
+B:GAZE:BLIND:20d4
+B:WAIL:TERRIFY:20d4
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | DROP_CORPSE |
+F:DROP_GOOD | DROP_GREAT | DROP_60 | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | PASS_WALL | NO_SLEEP | NO_STUN | NO_CONF | NO_FEAR |
+F:EVIL | UNDEAD | JOKEANGBAND | NO_CUT
+S:1_IN_2 |
+S:S_MONSTER
+D:One of the horsemen of the apocalypse, before you lies War. A healthy and
+D:hearty warrior, War grins a little too wide at you as he prepares for
+D:combat. War rides a large well-groomed yellow horse that leaves behind
+D:puddles of blood where its hooves touch the ground.
+
+##### Some aquatic monsters. #####
+
+N:879:Pike
+G:~:s
+I:125:2d7:80:35:0
+W:2:1:100:7
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:2d3
+F:ANIMAL | AQUATIC | STUPID | DROP_CORPSE | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:It's a common fresh-water predatory fish.
+
+N:880:Electric eel
+G:J:B
+I:110:15d15:15:40:70
+W:20:2:500:145
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:TOUCH:ELEC:2d7
+B:TOUCH:ELEC:2d7
+B:TOUCH:ELEC:2d7
+F:AQUATIC | ANIMAL | RAND_25 | IM_ELEC | RES_WATE |
+F:WILD_TOO | WILD_OCEAN | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:This serpentine creature can create a deadly voltage.
+
+N:881:Giant crayfish
+G:~:R
+I:90:4d10:6:100:20
+W:4:1:1200:10
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d4
+B:CLAW:HURT:3d4
+F:ANIMAL | AQUATIC | STUPID | WEIRD_MIND | DROP_CORPSE | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A man-sized, heavily armoured fresh-water relative of the lobster.
+
+N:882:Mermaid
+G:h:B
+I:110:5d8:50:30:0
+W:4:1:1600:20
+E:1:1:1:2:1:0
+O:20:50:10:5
+B:TOUCH:LOSE_WIS
+B:TOUCH:INSANITY:2d3
+B:TOUCH:CONFUSE
+F:FEMALE | RAND_25 | DROP_60 | SMART | AQUATIC | NO_CONF | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A green-skinned humanoid with a fishtail. Beware - there are rumours
+D:of adventures losing their minds under the fearsome charms of mermaids.
+
+N:883:Box jellyfish
+G:~:B
+I:110:10d10:20:30:75
+W:10:2:3000:25
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:PARALYZE:1d6
+B:TOUCH:PARALYZE:1d6
+F:ANIMAL | AQUATIC | IM_POIS | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A strange water creature whose touch can be deadly.
+
+N:884:Giant piranha
+G:~:R
+I:120:6d8:30:20:10
+W:10:2:300:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:5d1
+B:BITE:HURT:5d1
+F:NO_SLEEP | WILD_TOO | COLD_BLOOD |
+F:FRIENDS | AQUATIC | ANIMAL |
+F:MORTAL | BASEANGBAND
+D:A very large and bloodthirsty fish.
+
+N:885:Piranha
+G:~:R
+I:120:2d6:20:8:5
+W:3:1:200:8
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d6
+F:FRIENDS | AQUATIC | ANIMAL | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:Bloodthirsty fish who can smell your blood from a great distance.
+
+# New monster added by furiosity for the Theme module
+N:886:Swamp naga
+G:n:o
+I:110:11d8:20:40:120
+W:10:3:1800:60
+E:0:0:0:0:1:0
+O:50:0:50:0
+B:CRUSH:HURT:2d10
+B:BITE:POISON:2d4
+F:FEMALE | CAN_SWIM | WILD_TOO | WILD_SHORE |
+F:RAND_25 | DROP_90 | AQUATIC | IM_POIS |
+F:TAKE_ITEM | BASH_DOOR | DROP_CORPSE | IM_ACID |
+F:EVIL | MORTAL | BASEANGBAND
+D:A large orange snake with a woman's torso. She prefers to live
+D:in the swamp and can withstand marshland elements.
+
+# New monster added by furiosity for the Theme module
+N:887:Ocean naga
+G:n:b
+I:110:11d80:20:40:120
+W:30:10:1800:60
+E:0:0:0:0:1:0
+O:50:0:50:0
+B:CRUSH:HURT:4d10
+B:BITE:ACID:3d6
+F:FEMALE | CAN_SWIM | WILD_TOO | WILD_SHORE |
+F:DROP_90 | AQUATIC | WILD_OCEAN | IM_ACID |
+F:TAKE_ITEM | BASH_DOOR | DROP_CORPSE | RES_WATE |
+F:EVIL | MORTAL | BASEANGBAND
+S:1_IN_8
+S:BA_WATE | BO_ICEE |
+D:A large dark blue snake with a woman's torso. She prefers to live
+D:in deep water.
+
+# New monster added by furiosity for the Theme module
+N:888:Snail
+G:w:U
+I:30:12d9:1:5:255
+W:1:2:1:0
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:1d1
+F:ANIMAL | EMPTY_MIND | CAN_SWIM | WILD_ONLY | WILD_GRASS |
+F:DROP_CORPSE | MORTAL | BASEANGBAND | NEUTRAL | NO_TARGET |
+D:A harmless shell-bearing gastropod mollusc
+D:crawling slowly on the dungeon floor.
+D:It is a favourite prey of birds.
+
+N:889:Whale
+G:~:D
+I:110:22d22:15:50:70
+W:20:4:9000:175
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CRUSH:HURT:1d20
+B:CRUSH:HURT:1d20
+F:RAND_25 | FORCE_MAXHP | RES_WATE |
+F:ANIMAL | AQUATIC | WILD_TOO |
+F:MORTAL | BASEANGBAND
+D:Although it looks like a fish and lives in water, it is in fact
+D:a mammal. And it is huge.
+
+N:890:Sand mite
+G:~:B
+I:110:3d10:5:25:80
+W:10:2:500:25
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:POISON:3d6
+B:BITE:POISON:3d6
+F:AQUATIC | ANIMAL | IM_POIS | FRIENDS |
+F:CHAR_CLEAR | ATTR_CLEAR | DROP_CORPSE | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY
+D:A relative of crabs and shrimp, this is a tiny creature that inhabits sandy
+D:bottoms. It has a pair of dangerous-looking claws.
+
+N:891:Octopus
+G:~:g
+I:105:60d6:60:60:60
+W:15:2:1200:60
+E:3:0:3:6:1:0
+O:0:0:0:0
+B:SPIT:BLIND:1d3
+B:CRUSH:HURT:6d3
+B:CRUSH:HURT:6d3
+B:CRUSH:HURT:6d3
+F:RAND_25 | IM_COLD | RES_WATE | AQUATIC | ANIMAL | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:It doesn't move very fast, but when it does - watch out.
+
+N:892:Giant octopus
+G:~:g
+I:115:100d6:10:35:5
+W:30:1:1800:180
+E:3:0:3:6:1:0
+O:0:0:0:0
+B:SPIT:BLIND:1d4
+B:CRUSH:HURT:8d4
+B:CRUSH:HURT:8d4
+B:CRUSH:PARALYZE:8d4
+F:AQUATIC | SMART | IM_POIS | ANIMAL | NO_CONF | NO_SLEEP |
+F:NO_FEAR | SMART | WEIRD_MIND | DROP_CORPSE | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+S:1_IN_15 |
+S:DARKNESS | SLOW | CONF | SCARE
+D:A cunning and dangerous undersea opponent.
+
+N:893:Eye of the deep
+G:e:b
+I:120:16d100:10:20:40
+W:40:3:1600:6000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:EXP_20:2d6
+B:GAZE:UN_POWER:2d6
+B:GAZE:INSANITY:2d6
+B:BITE:HURT:6d6
+F:EVIL | IM_POIS | NO_CONF | NO_SLEEP | AQUATIC |
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY | RES_TELE |
+F:SMART | DROP_CORPSE | BASEANGBAND
+S:1_IN_2 |
+S:BLIND | SLOW | CONF | SCARE | DRAIN_MANA | MIND_BLAST |
+S:FORGET | DARKNESS | BO_WATE | BO_ICEE | BO_MANA | BO_COLD
+D:A beholder that inhabits the depths of the sea, sleeping and pondering
+D:alien thoughts for centuries. Occasionally, it will float to the
+D:surface to wreck the lives of surface dwellers.
+
+N:894:Murk dweller
+G:S:g
+I:110:200d5:70:30:0
+W:27:3:3000:800
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:5d10
+B:CLAW:PARALYZE
+B:STING:INSANITY:5d10
+B:STING:UN_BONUS
+F:AQUATIC | ANIMAL | WEIRD_MIND | FORCE_MAXHP | HURT_LITE |
+F:EVIL | SMART | NO_CONF | NO_SLEEP | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_5 |
+S:BA_POIS | BR_DARK | BLIND | BR_POIS | SLOW | CONF | MIND_BLAST |
+S:BRAIN_SMASH | DARKNESS
+D:A gigantic aquatic monster, somewhat resembling a cross between a
+D:lobster and a spider. It is coated in poisonous slime and noxious
+D:parasites. This foul creature hides in the silt of the deep ocean floor,
+D:waiting to trap unsuspecting prey.
+
+N:895:Drowned soul
+G:G:B
+I:110:9d8:5:33:50
+W:11:1:0:30
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:BLIND:3d3
+B:TOUCH:POISON:2d4
+B:WAIL:TERRIFY
+F:COLD_BLOOD | EMPTY_MIND | EVIL | AQUATIC | UNDEAD | IM_COLD | INVISIBLE |
+F:IM_POIS | NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_8
+S:BLIND | HOLD | CONF
+D:A ghastly victim of drowning, forever doomed to wander the ocean waters
+D:looking for revenge.
+
+N:896:Tiger shark
+G:~:o
+I:120:10d5:100:32:0
+W:12:1:3000:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:4d4
+F:RAND_25 | AQUATIC | ANIMAL | STUPID | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A small species of shark, although the teeth are still as deadly.
+
+N:897:Hammerhead shark
+G:~:W
+I:115:16d10:20:59:20
+W:16:3:1500:40
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:3d4
+B:BUTT:HURT:3d4
+B:BITE:HURT:3d4
+F:ANIMAL | AQUATIC | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A hungry shark with a strange head.
+
+N:898:Great white shark
+G:~:w
+I:120:100d6:20:70:20
+W:24:2:5000:250
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:4d6
+B:BITE:HURT:4d6
+B:BITE:HURT:4d6
+F:FORCE_SLEEP | AQUATIC | COLD_BLOOD |
+F:ANIMAL MORTAL | BASEANGBAND
+D:A very large carnivorous fish.
+
+N:899:Aquatic golem
+G:g:b
+I:100:25d10:35:75:10
+W:19:1:0:100
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:3d10
+B:HIT:HURT:3d10
+F:COLD_BLOOD | EMPTY_MIND | AQUATIC |
+F:IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:An ingenious gnomish invention -- a golem designed for underwater
+D:usage.
+
+# New monster added by furiosity for the Theme module
+N:900:Brown naga
+G:n:u
+I:110:14d8:20:40:120
+W:30:2:1800:80
+E:0:0:0:0:1:0
+O:50:0:50:0
+B:CRUSH:HURT:2d10
+B:BITE:LOSE_CHR:3d6
+F:FEMALE | CAN_SWIM | WILD_TOO | WILD_SHORE |
+F:RAND_25 | DROP_60 | NO_CUT | WILD_GRASS |
+F:TAKE_ITEM | BASH_DOOR | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND
+S:1_IN_7
+S:BR_SHAR
+D:A large brown snake with a woman's torso. It burrows deep into
+D:the ground.
+
+N:901:White shark
+G:~:W
+I:120:30d10:20:50:10
+W:18:1:3000:100
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:3d5
+B:BITE:HURT:3d5
+B:BITE:HURT:3d5
+F:ANIMAL | AQUATIC | WILD_TOO | COLD_BLOOD |
+F:MORTAL | BASEANGBAND
+D:A fast-moving hunter of the depths. When this creature moves,
+D:everybody in the water is in danger.
+
+N:902:Scrag
+G:T:B
+I:110:40d10:20:50:50
+W:35:1:5000:440
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:1d10
+B:HIT:HURT:1d10
+B:HIT:HURT:3d2
+B:HIT:HURT:3d2
+F:MALE |
+F:FORCE_MAXHP | AQUATIC | REGENERATE |
+F:FRIENDS | DROP_60 | WILD_TOO | WILD_OCEAN |
+F:OPEN_DOOR | BASH_DOOR | RES_WATE |
+F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | BASEANGBAND
+D:It is said that Morgoth created trolls in mockery of the Ents.
+D:A troll of the sea, he reeks of brine.
+
+N:903:Jaws
+G:~:w
+I:130:100d20:200:80:70
+W:40:2:7000:2000
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:11d2
+B:BITE:HURT:22d1
+B:BITE:HURT:11d2
+B:BITE:HURT:22d1
+F:FORCE_MAXHP | UNIQUE | MOVE_BODY |
+F:WILD_OCEAN | WILD_TOO | COLD_BLOOD |
+F:BASH_DOOR | IM_COLD | IM_ELEC | IM_POIS | ANIMAL | AQUATIC |
+F:NO_CONF | NO_SLEEP |
+F:MORTAL | JOKEANGBAND
+D:The biggest white shark who has ever lived, it is hunting for you now.
+
+# New monster added by furiosity for the Theme module
+N:904:Silver naga
+G:n:W
+I:110:18d11:20:65:120
+W:15:2:1900:80
+E:0:0:0:0:1:0
+O:0:0:80:20
+B:CRUSH:HURT:2d8
+B:BITE:POISON:1d8
+B:BITE:COLD:1d8
+F:FEMALE |
+F:RAND_25 | DROP_60 | DROP_1D2 | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | CAN_SWIM | IM_POIS |
+F:EVIL | MORTAL | BASEANGBAND | IM_COLD |
+S:1_IN_7
+S:BO_ICEE | BO_COLD |
+D:A giant snake-like figure with a woman's torso, partially covered
+D:in silvery scales.
+
+N:905:Aquatic elven warrior
+G:h:b
+I:110:20d8:40:35:5
+W:10:1:1500:35
+E:1:1:1:2:1:0
+O:20:60:10:10
+B:HIT:HURT:4d4
+B:HIT:HURT:4d4
+F:MALE | AQUATIC | FRIENDS | SMART | DROP_60 | DROP_CORPSE | BASEANGBAND |
+F:HAS_LITE | PET | GOOD
+D:An aquatic elf trained in all forms of combat.
+
+N:906:Aquatic elven mage
+G:h:o
+I:110:12d8:30:30:6
+W:10:1:1400:35
+E:1:1:1:2:1:0
+O:10:10:70:10
+B:TOUCH:UN_BONUS
+F:MALE | AQUATIC | SMART | DROP_2D2 | DROP_CORPSE | BASEANGBAND |
+F:HAS_LITE | PET | GOOD
+S:1_IN_12 |
+S:BO_MANA | BO_COLD | S_MONSTERS
+D:A wizened aquatic elf skilled in the magical arts. You can see an
+D:iridescent film coating the water around him.
+
+N:907:Stargazer
+G:~:y
+I:100:15d9:10:25:30
+W:21:1:800:60
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:GAZE:PARALYZE
+F:AQUATIC | ANIMAL | SMART | RAND_25 | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:S_MONSTER
+D:A giant fish shaped like a flounder. There are two enormous eyes
+D:occupying half of the creature's body.
+
+N:908:Elder stargazer
+G:~:U
+I:100:20d10:15:25:30
+W:29:1:1000:75
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:GAZE:PARALYZE
+B:GAZE:CONFUSE
+F:AQUATIC | ANIMAL | SMART | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:S_MONSTERS
+D:A stargazer a bit larger than average, covered with barnacles.
+
+N:909:Flounder
+G:~:s
+I:100:10d5:5:25:30
+W:13:1:700:55
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:2d6
+F:AQUATIC | ANIMAL | RAND_25 | INVISIBLE | ATTR_CLEAR | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A flattened fish which is able to change body colouring for
+D:camouflage.
+
+N:910:Giant turtle
+G:R:G
+I:110:5d8:10:14:30
+W:7:1:3000:30
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:2d2
+B:BITE:HURT:2d2
+F:ANIMAL | AQUATIC | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A giant turtle with flippers, adapted for life in the ocean.
+
+N:911:Hatchling dragon turtle
+G:d:W
+I:110:10d10:20:60:50
+W:9:1:20000:35
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d3
+B:CLAW:HURT:1d3
+B:BITE:HURT:1d5
+F:FORCE_MAXHP | FORCE_SLEEP | DROP_CORPSE |
+F:ONLY_GOLD | DROP_60 | DROP_1D2 |
+F:EVIL | DRAGON | AQUATIC | BASEANGBAND | ATTR_MULTI
+S:1_IN_12 |
+S:BR_SOUN
+D:A newly-hatched dragon turtle. It still hasn't grown a proper shell.
+
+N:912:Young dragon turtle
+G:d:W
+I:110:30d10:20:70:70
+W:31:1:80000:700
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d6
+B:CLAW:HURT:2d6
+B:BITE:HURT:2d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_3D2 |
+F:EVIL | DRAGON | AQUATIC | BASEANGBAND | ATTR_MULTI
+S:1_IN_11 |
+S:SCARE |
+S:BR_SOUN
+D:A dragon-like creature inhabiting lightless reaches of ocean caves. It has
+D:a long neck with a tiny head, and four massive flippers. It has a soft and
+D:flexible shell.
+
+N:913:Mature dragon turtle
+G:d:W
+I:110:50d10:20:80:70
+W:38:1:170000:1500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:2d10
+B:CLAW:HURT:2d10
+B:BITE:HURT:4d10
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_4D2 |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | AQUATIC | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_9 |
+S:SCARE |
+S:BR_SOUN
+D:A large dragon turtle, covered with a tough white shell.
+
+N:914:Ancient dragon turtle
+G:D:W
+I:120:70d10:20:90:80
+W:41:1:220000:2500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d8
+B:CLAW:HURT:4d8
+B:BITE:HURT:7d8
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE |
+F:DROP_1D2 | DROP_4D2 |
+F:SMART | AQUATIC | POWERFUL | MOVE_BODY |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_9 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN
+D:A huge dragon turtle. You can see many barnacles covering its body.
+
+N:915:Fastitocalon
+G:D:g
+I:120:40d100:25:150:30
+W:52:3:250000:16000
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:BITE:HURT:5d8
+B:BITE:HURT:5d8
+B:CRUSH:POISON:3d10
+B:CRUSH:POISON:3d10
+F:FORCE_SLEEP | FORCE_MAXHP | RES_TELE | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:IM_FIRE | IM_ACID | IM_COLD | IM_POIS |
+F:DRAGON | NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | ATTR_MULTI
+S:1_IN_6 |
+S:BR_FIRE | BR_ACID | BR_SOUN | BA_WATE
+D:A huge aquatic dragon-turtle, its shell is as large as a small island.
+
+N:916:Undead stargazer
+G:~:u
+I:100:18d9:10:25:30
+W:25:1:0:100
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:GAZE:PARALYZE
+B:GAZE:EXP_20
+F:AQUATIC | ANIMAL | SMART | INVISIBLE | UNDEAD | BASEANGBAND | NO_CUT
+S:1_IN_10 |
+S:S_UNDEAD | S_MONSTER
+D:A stargazer brought back from the dead under control of some evil
+D:sorceror.
+
+N:917:Killer whale
+G:~:w
+I:120:20d50:12:55:30
+W:25:1:9500:85
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:BITE:HURT:7d4
+B:BITE:HURT:7d4
+F:AQUATIC | WILD_TOO | WILD_OCEAN |
+F:ANIMAL | MORTAL | BASEANGBAND
+D:An almost beautiful, deadly beast.
+
+N:918:Merrow
+G:O:B
+I:110:30d9:20:33:30
+W:28:2:2300:80
+E:1:1:1:2:1:1
+O:20:70:0:10
+B:HIT:HURT:3d8
+B:HIT:HURT:3d8
+F:FRIENDS | DROP_60 | DROP_CORPSE | AQUATIC | WILD_TOO | WILD_OCEAN |
+F:OPEN_DOOR | BASH_DOOR | RES_WATE | IM_COLD | IM_POIS |
+F:EVIL | GIANT |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A great ogre of the sea, it is violent and stupid.
+
+N:919:Water naga
+G:n:B
+I:110:30d10:10:55:10
+W:24:1:1600:60
+E:0:0:0:0:1:0
+O:40:0:50:10
+B:CRUSH:HURT:2d8
+B:CRUSH:HURT:2d8
+B:BITE:POISON:1d8
+B:BITE:POISON:1d8
+F:FEMALE |
+F:AQUATIC | DROP_CORPSE |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 |
+F:EVIL | NO_CONF | NO_SLEEP | SMART |
+F:MORTAL | BASEANGBAND
+S:1_IN_7 |
+S:DARKNESS | CAUSE_3 | BO_ICEE
+D:A naga adapted to underwater life. She has a fish-like tail and a pair
+D:of gills.
+
+# New monster added by furiosity for the Theme module
+N:920:Night naga
+G:n:v
+I:110:30d15:20:75:120
+W:25:2:0:60
+E:0:0:0:0:1:0
+O:20:0:80:0
+B:CRUSH:TERRIFY:2d8
+B:CRUSH:HURT:2d8
+B:BITE:BLIND:1d8
+B:BITE:HURT:1d8
+F:FEMALE | CAN_SWIM |
+F:FORCE_SLEEP | CAN_FLY | HURT_LITE |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | DROP_CORPSE |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP | BASEANGBAND |
+S:1_IN_4 |
+S:BLIND | DARKNESS
+D:A dark snake-like form with the torso of a beautiful woman, it
+D:prefers to roam in the night.
+
+# New monster added by furiosity for the Theme module
+N:921:Tree naga
+G:n:G
+I:110:30d15:20:75:120
+W:28:2:0:60
+E:0:0:0:0:1:0
+O:20:0:80:0
+B:CRUSH:HURT:2d8
+B:CRUSH:HURT:2d8
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+F:FEMALE |
+F:FORCE_SLEEP | CAN_FLY | CAN_SWIM |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | DROP_CORPSE |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR | IM_POIS |
+F:EVIL | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:HEAL | BR_POIS | BA_POIS | DARKNESS
+D:A green snake-like form with the torso of a beautiful woman, it
+D:dwells in the trees.
+
+N:922:Moby Dick, the White Whale
+G:~:w
+I:120:100d25:200:80:70
+W:50:2:10000:2500
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CRUSH:HURT:10d10
+B:CRUSH:HURT:10d10
+B:CRUSH:HURT:10d10
+B:CRUSH:HURT:10d10
+F:FORCE_MAXHP | UNIQUE | MOVE_BODY |
+F:WILD_OCEAN | WILD_TOO | COLD_BLOOD |
+F:BASH_DOOR | IM_COLD | IM_ELEC | IM_POIS | ANIMAL | AQUATIC |
+F:MORTAL | JOKEANGBAND
+S:1_IN_6 | BA_WATE
+D:The mightiest whale of the seas, he has sunk many ships in his time. With
+D:a mere flick of his tail he can create a mighty whirlpool, to the ruin
+D:of all who would travel the ocean.
+
+N:923:Aquatic hound
+G:Z:B
+I:110:15d5:60:60:0
+W:20:1:600:200
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:CONFUSE:2d8
+B:BITE:HURT:2d8
+B:CLAW:POISON:2d8
+F:FRIENDS | DROP_CORPSE |
+F:ANIMAL | AQUATIC |
+F:MORTAL | BASEANGBAND
+S:1_IN_10 |
+S:BO_ICEE | BO_WATE
+D:A hound with a finned tail and large, muscular flippers for hind legs.
+D:It has a rubbery skin instead of fur.
+
+N:924:Gaurrog
+G:U:B
+I:110:35d20:30:50:10
+W:40:1:0:1000
+E:0:0:0:0:1:0
+O:20:60:20:0
+B:HIT:HURT:3d4
+B:GAZE:POISON:8d12
+B:CLAW:INSANITY:8d12
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:FRIENDS | SMART |
+F:ONLY_ITEM | DROP_60 |
+F:AQUATIC | POWERFUL |
+F:EVIL | DEMON | IM_ACID | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+S:1_IN_8 |
+S:BO_ICEE | BA_WATE
+D:A hideous scaled demon, it is a sleek form with many fins but no visible
+D:arms or legs. It has a toothed gaping maw, reminiscent of a caricature
+D:of a shark's jaws.
+
+# New monster added by furiosity for the Theme module
+N:925:Adventurer naga
+G:n:U
+I:110:30d15:20:75:120
+W:28:2:0:60
+E:0:0:0:0:1:0
+O:20:0:80:0
+B:CRUSH:HURT:2d8
+B:CRUSH:HURT:2d8
+B:BITE:HURT:1d8
+B:BITE:HURT:1d8
+F:FEMALE |
+F:FORCE_SLEEP | CAN_FLY |
+F:ONLY_ITEM | DROP_90 | DROP_2D2 | DROP_CORPSE |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR | NO_STUN | PET |
+F:EVIL | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:HEAL | BLIND | CONF | DARKNESS
+D:A large brown snake with a woman's torso. She is a fellow
+D:adventurer.
+
+# New monster added by furiosity for the Theme module
+N:926:White mold
+G:m:w
+I:110:17d8:2:16:70
+W:19:1:40:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:COLD:4d4
+F:NEVER_MOVE | SUSCEP_FIRE |
+F:STUPID | EMPTY_MIND |
+F:IM_COLD | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange white growth on the dungeon floor; it seems to sparkle
+D:with ice.
+
+# New monster added by furiosity for the Theme module
+N:927:Silver mold
+G:m:W
+I:110:17d8:2:16:70
+W:19:1:40:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:EAT_LITE:4d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange silvery growth on the dungeon floor; it seems to glow with
+D:a dark light.
+
+N:928:Mathilde
+G:h:y
+I:110:220d100:40:10:3
+W:0:4:1100:0
+E:0:1:1:2:1:1
+O:20:20:20:20
+F:UNIQUE | FEMALE | CAN_SPEAK | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_MAXHP | WILD_TOWN | WILD_ONLY | RAND_25
+F:ONLY_ITEM | DROP_90 | DROP_GOOD |
+F:OPEN_DOOR | DG_CURSE |
+F:MORTAL | JOKEANGBAND | HAS_LITE
+D:She loves joking, and she's constantly giggling. A very happy girl.
+D:Beware, it is rumoured that DarkGod has put a mighty curse on her.
+
+N:929:Child spirit
+G:G:W
+I:120:5d5:8:15:10
+W:5:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:3d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD | GOOD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:930:Young spirit
+G:G:W
+I:120:8d8:8:15:10
+W:10:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:9d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD | GOOD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:931:Mature spirit
+G:G:W
+I:120:16d16:8:15:10
+W:40:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:18d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD | GOOD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:932:Experienced spirit
+G:G:W
+I:120:18d18:8:15:10
+W:60:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:20d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD | GOOD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:933:Wise spirit
+G:G:W
+I:120:25d25:8:15:10
+W:90:3:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:TERRIFY
+B:TOUCH:HURT:30d4
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | UNDEAD | GOOD |
+F:IM_COLD | IM_POIS | NO_CONF | NO_SLEEP | SMART | PET | UNDEAD |
+F:BASEANGBAND | NO_CUT
+D:A helpful spirit from beyond the grave.
+
+N:934:Fangorn the Treebeard, Lord of the Ents
+G:#:G
+I:120:50d100:30:120:15
+W:52:3:6000:15500
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:CRUSH:HURT:13d13
+B:CRUSH:HURT:13d13
+B:CRUSH:HURT:13d13
+B:CRUSH:HURT:13d13
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | CAN_SPEAK | SUSCEP_FIRE |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY | DROP_CORPSE |
+F:SMART | TAKE_ITEM | BASH_DOOR | KILL_WALL | NO_SLEEP |
+F:GOOD | PET | BASEANGBAND | NO_CUT
+D:The first being to awoke on Arda, apart from the Valar themselves. He is the
+D:first, oldest, greatest and most respected of all the Ents: and though he is
+D:slow to anger, he is a terrible foe when roused.
+
+N:935:Gandalf the Grey
+G:p:s
+I:120:49d101:101:100:0
+W:60:7:1600:35000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+B:HIT:TERRIFY:5d5
+B:HIT:TERRIFY:5d5
+F:UNIQUE | MALE | CAN_SPEAK | PET | DROP_CORPSE |
+F:FORCE_SLEEP | FORCE_MAXHP | REFLECTING | RES_TELE |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:GOOD | IM_FIRE | IM_COLD |
+F:IM_ELEC | IM_POIS | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | HASTE | TPORT | TELE_AWAY | BLIND | CONF | SCARE |
+S:CAUSE_4 | BRAIN_SMASH | FORGET | TRAPS |
+S:BA_FIRE | BO_FIRE | BO_PLAS | BO_MANA | CAUSE_4 |
+S:S_MONSTERS | S_DRAGON | S_KIN
+D:The wizard who opposed Sauron and, in the end, was the only
+D:one of the Istari to succeed in his task. Gandalf is very
+D:wise and specialises in fire magic.
+
+N:936:Nar, the Dwarf
+G:k:y
+I:110:45d10:25:70:25
+W:17:2:1400:250
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+B:HIT:HURT:3d5
+F:UNIQUE | MALE |
+F:FORCE_MAXHP | FORCE_SLEEP |
+F:OPEN_DOOR | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_POIS |
+F:DROP_CORPSE | DROP_SKELETON | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL | BLIND | CONF | CAUSE_2 | MIND_BLAST
+D:The friend and companion of the dwarven king Thror, he went mad with
+D:grief after Thror's death at the hands of Azog the Orc. With torn beard
+D:and ragged clothes, he seems to have fixed on you as a convenient target
+D:to vent his anger.
+
+N:937:Apprentice mindcrafter
+G:p:y
+I:110:6d8:20:10:5
+W:8:1:900:18
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | WILD_TOO | FRIENDS |
+F:OPEN_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE | NO_CONF | NO_SLEEP
+S:1_IN_12 | BLIND | SLOW | CONF | SCARE
+D:A novice in the arts of mind over matter.
+
+N:938:Great Swamp Worm
+G:D:g
+I:120:40d100:30:150:80
+W:63:2:190000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:POISON:6d14
+B:BITE:POISON:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_POIS
+D:A truly enormous dragon with great powers. The foul gases issuing
+D:from the beast nearly make you vomit; and while you may try to hold
+D:your breath as you fight it, it sees no reason to do likewise.
+
+N:939:Great Bile Worm
+G:D:s
+I:120:50d100:30:150:80
+W:67:2:190000:23000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:ACID:6d14
+B:BITE:ACID:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | IM_ACID | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_ACID
+D:A huge and very powerful dragon. Great steaming pools of acid drip from
+D:its form onto the ground. You shudder when you see the acid eating away
+D:the very stones of the dungeon - what could it do to you?
+
+N:940:Blue Firebird
+G:B:b
+I:120:4d5:8:15:10
+W:5:3:100:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d4
+B:CLAW:FIRE:5d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD | AQUATIC |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:941:Green Firebird
+G:B:g
+I:120:4d5:10:15:10
+W:7:3:110:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:4d4
+B:CLAW:FIRE:5d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD | AQUATIC |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:942:Brown Firebird
+G:B:u
+I:120:5d5:10:15:10
+W:10:3:120:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:5d4
+B:CLAW:FIRE:7d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD | AQUATIC |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:943:Bronze Firebird
+G:B:U
+I:120:6d5:15:15:10
+W:13:3:130:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:6d4
+B:CLAW:FIRE:7d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD | AQUATIC |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:944:Gold Firebird
+G:B:y
+I:120:6d5:20:15:10
+W:15:3:140:0
+E:0:1:0:6:1:0
+O:0:0:0:0
+B:CLAW:HURT:6d4
+B:CLAW:FIRE:8d4
+F:IM_COLD | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP | IMPRESED |
+F:CAN_FLY | SMART | PET | DROP_CORPSE | HAS_EGG | GOOD | AQUATIC |
+F:MORTAL | HAS_LITE
+S:1_IN_10
+S:TELE_TO |
+D:The ancestors of the Eagles of the Thunderlords, these are
+D:friendly funny flying creatures with power.
+
+N:945:High-elven ranger
+G:h:w
+I:120:50d30:20:70:0
+W:40:3:1400:500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:10d8
+B:HIT:HURT:10d8
+F:MALE | FRIENDS | OPEN_DOOR | BASH_DOOR |
+F:GOOD | DROP_SKELETON | DROP_CORPSE | SMART | PET |
+F:IM_ACID | IM_COLD | RES_WATE | RES_NETH |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:ARROW_4
+D:An elf cloaked in green wielding a longbow.
+
+N:946:Uvatha the Horseman
+G:N:D
+I:120:24d100:90:60:10
+W:40:13:0:10000
+E:0:0:0:0:0:0
+O:30:30:30:10
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:HIT:EXP_80:4d6
+B:HIT:EXP_80:4d6
+F:UNIQUE | MALE |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | NAZGUL | SUSCEP_FIRE |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | DROP_CHOSEN |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | SPECIAL_GENE | NO_CUT
+D:A tall black Ringwraith, he is a master of horsemanship. He longs
+D:to taste your blood.
+
+N:947:Adunaphel the Quiet
+G:N:D
+I:120:27d100:90:60:10
+W:43:13:0:13000
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:HIT:HURT:6d6
+B:HIT:HURT:6d6
+B:TOUCH:EXP_80:5d6
+B:TOUCH:EXP_80:5d6
+F:UNIQUE | FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP | NAZGUL | DROP_CHOSEN |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | SUSCEP_FIRE |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | MOVE_BODY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | FORGET |
+S:BO_ACID | BO_COLD | BO_NETH |
+S:S_MONSTER
+D:A sorceress in life, Adunaphel quickly fell under Sauron's sway and the
+D:power of the Rings of Power.
+
+N:948:Akhorahil the Blind
+G:N:D
+I:120:30d100:90:70:10
+W:45:13:0:15000
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:HIT:HURT:7d6
+B:HIT:HURT:7d6
+B:GAZE:EXP_80:6d6
+B:WAIL:TERRIFY:6d6
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | NAZGUL | DROP_CHOSEN |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | SUSCEP_FIRE |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | DARKNESS |
+S:BO_COLD | BO_NETH |
+S:S_MONSTERS
+D:A mighty sorcerer king, Akhorahil was blind in life. With powerful
+D:enchantments, he created jewelled eyes that enabled him to see better than
+D:any ordinary man ever could.
+
+N:949:Ren the Unclean
+G:N:D
+I:120:35d100:90:70:10
+W:48:13:0:18000
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:HIT:HURT:7d7
+B:HIT:HURT:7d7
+B:TOUCH:EXP_80:6d7
+B:WAIL:TERRIFY:6d7
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | NAZGUL | DROP_CHOSEN |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | SUSCEP_FIRE |
+F:INVISIBLE | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | BO_FIRE | BO_NETH |
+S:S_MONSTER
+D:Ren was an insane eastern king who believed himself to be the son of a
+D:volcano god. At an early age his sanity was destroyed by a plague that
+D:wiped out his family, and he never recovered.
+
+N:950:Ji Indur Dawndeath
+G:N:D
+I:120:40d100:90:70:10
+W:52:13:0:22000
+E:0:0:0:0:0:0
+O:30:30:30:10
+B:HIT:HURT:8d7
+B:HIT:HURT:8d7
+B:TOUCH:EXP_40:6d7
+B:TOUCH:EXP_40:6d7
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | NAZGUL | DROP_CHOSEN |
+F:INVISIBLE | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | SUSCEP_FIRE |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 |
+S:BA_NETH | BA_COLD | BA_ELEC | BA_ACID |
+S:S_UNDEAD
+D:This Ringwraith was a weak-minded sorcerer-king who fell easily under
+D:Sauron's power.
+
+N:951:Dwar, Dog Lord of Waw
+G:N:D
+I:120:45d100:90:90:10
+W:56:13:0:25000
+E:0:1:0:2:1:0
+O:30:30:30:10
+B:HIT:HURT:8d8
+B:HIT:HURT:8d8
+B:BITE:EXP_40:6d7
+B:WAIL:TERRIFY:6d7
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | NAZGUL | DROP_CHOSEN |
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | SUSCEP_FIRE |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | BA_NETH |
+S:S_MONSTERS | S_UNDEAD | S_HOUND
+D:Dwar had a special affinity for dogs in life, and can still command them
+D:at will. He howls manically as he reaches out to destroy you.
+
+N:952:Hoarmurath of Dir
+G:N:D
+I:130:60d100:90:100:10
+W:64:13:0:30000
+E:0:0:0:0:0:0
+O:30:30:30:10
+B:HIT:HURT:9d9
+B:HIT:HURT:9d9
+B:TOUCH:EXP_80:6d7
+B:WAIL:TERRIFY:6d7
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | SUSCEP_FIRE |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | NAZGUL | DROP_CHOSEN |
+F:HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | MIND_BLAST |
+S:BO_COLD | BA_COLD | BA_NETH |
+S:S_UNDEAD
+D:A Ringwraith powerful in fell sorcery, he yearns for the life he has
+D:exchanged for an unlife of everlasting torment.
+
+N:953:Khamul, the Black Easterling
+G:N:D
+I:130:70d100:90:100:10
+W:72:13:2600:40000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:9d10
+B:HIT:HURT:9d10
+B:TOUCH:EXP_80:7d7
+B:TOUCH:EXP_80:7d7
+F:UNIQUE | MALE | CAN_SPEAK |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | NAZGUL | DROP_CHOSEN |
+F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:EVIL | UNDEAD | IM_ACID | IM_COLD | IM_POIS | SUSCEP_FIRE |
+F:HURT_LITE | NO_CONF | NO_SLEEP | RES_TELE | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:TELE_LEVEL | BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | BO_MANA |
+S:BA_COLD | BA_NETH | ANIM_DEAD |
+S:S_HI_UNDEAD | S_KIN
+D:He was the warrior-king of the East, now a ringwraith. Khamul is a powerful opponent, his skill in
+D:combat awesome and his form twisted by evil cunning.
+
+N:954:The Witch-King of Angmar
+G:N:D
+I:130:90d100:90:120:10
+W:80:14:1800:60000
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:EXP_80:7d7
+B:HIT:EXP_80:7d7
+F:UNIQUE | MALE | CAN_SPEAK | RES_TELE
+F:FORCE_SLEEP | FORCE_MAXHP | SMART | SUSCEP_FIRE |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | NAZGUL |
+F:EVIL | UNDEAD | DROP_CHOSEN |
+F:IM_COLD | IM_POIS | HURT_LITE | NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:TELE_AWAY | BLIND | HOLD | SCARE | CAUSE_3 | BRAIN_SMASH |
+S:BO_MANA | BA_NETH | S_WRAITH |
+S:S_KIN | S_HI_UNDEAD | S_HI_DRAGON | S_MONSTERS | ANIM_DEAD
+D:The Chief of the Ringwraiths. A fell being of devastating power. His
+D:spells are lethal and his combat blows crushingly hard. He moves at
+D:speed, and commands legions of evil to do his bidding. It is said that he
+D:is fated never to die by the hand of mortal man.
+
+N:955:Green Thunderlord
+G:B:g
+I:120:50d50:20:100:50
+W:30:4:30000:10000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+F:FEMALE |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | AQUATIC |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE |
+S:BLINK | TELE_AWAY
+D:A Thunderlord. Among the weaker breeds, but still dangerous.
+
+N:956:Blue Thunderlord
+G:B:b
+I:120:60d60:20:100:50
+W:40:4:30000:20000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:8d7
+B:HIT:HURT:8d7
+F:MALE | SMART |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | AQUATIC |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE |
+S:TPORT | BLINK
+D:A Thunderlord. Among the weaker breeds, but still dangerous.
+
+N:957:Brown Thunderlord
+G:B:u
+I:130:70d70:30:100:50
+W:50:4:30000:20000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:8d9
+B:HIT:HURT:8d9
+F:MALE | SMART |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | AQUATIC |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE |
+S:TPORT | BLINK
+D:A Thunderlord. Beware its flame.
+
+N:958:Bronze Thunderlord
+G:B:U
+I:130:80d80:30:100:50
+W:60:5:30000:20000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:10d9
+B:HIT:HURT:10d9
+F:MALE | SMART |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | AQUATIC |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE | BR_TIME |
+S:TPORT | BLINK
+D:A Thunderlord, mightiest among the males.
+
+N:959:Gold Thunderlord
+G:B:y
+I:130:90d90:30:100:50
+W:70:5:30000:20000
+E:1:1:1:2:1:1
+O:50:50:0:0
+B:HIT:HURT:10d9
+B:HIT:HURT:10d9
+B:HIT:HURT:10d9
+B:HIT:HURT:10d9
+F:FEMALE | SMART |
+F:THUNDERLORD | DROP_SKELETON | DROP_CORPSE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | AQUATIC |
+F:IM_FIRE | REGENERATE | OPEN_DOOR | BASH_DOOR |
+F:RES_TELE | NO_CONF | NO_SLEEP | CAN_FLY | HAS_LITE
+S:1_IN_4 |
+S:BR_FIRE | BR_TIME |
+S:TPORT | BLINK | TELE_TO | TELE_AWAY |
+S:S_THUNDERLORD
+D:A Thunderlord, among the queens of their kind.
+
+N:960:Blood Sprout
+G:,:r
+I:140:3d5:10:1:0
+W:50:1:50:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:HURT:3d15
+B:TOUCH:HURT:3d15
+B:TOUCH:HURT:3d15
+B:TOUCH:HURT:3d15
+F:STUPID | EMPTY_MIND | KILL_TREES |
+F:IM_POIS | IM_ELEC | IM_ACID | IM_COLD |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL
+S:MULTIPLY
+D:A kind of giant mycorrhiza, corrupted into a carnivore by Morgoth.
+
+N:961:Gorlim the Unhappy
+G:p:s
+I:120:16d100:20:120:40
+W:41:3:1800:7000
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:8d6
+B:HIT:HURT:8d6
+B:HIT:UN_BONUS:6d8
+B:HIT:UN_BONUS:6d8
+F:UNIQUE | MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP | BASEANGBAND
+F:HAS_LITE
+S:1_IN_2 |
+S:CAUSE_3 | BO_WATE | BO_MANA
+D:This sad creature - once a mighty warrior - betrayed his former friends to
+D:Morgoth's army in return for, he thought, safety for himself and his wife.
+D:And so he fell under Morgoth's power and became little more than a mindless
+D:servant of evil, even though the other side of his "bargain" was not kept.
+
+# New monster added by furiosity for the Theme module
+N:962:Pink mold
+G:m:R
+I:110:17d8:2:16:70
+W:19:1:40:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:LOSE_STR:4d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange red growth on the dungeon floor; it seems to glow with
+D:an eerie pink aura.
+
+N:963:Aranea
+G:S:r
+I:120:20d10:20:45:50
+W:30:2:1000:250
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:POISON:2d8
+B:CLAW:POISON:2d8
+B:BITE:POISON:2d6
+B:BITE:POISON:2d6
+F:DROP_SKELETON | FORCE_MAXHP | FRIENDS |
+F:OPEN_DOOR | BASH_DOOR | HURT_LITE |
+F:ANIMAL | SPIDER | EVIL | IM_POIS | BASEANGBAND
+S:1_IN_4
+S:BO_FIRE | SLOW | HOLD | CAUSE_3 | MISSILE
+D:A red arachnid with legs weaving spells in the air.
+
+N:964:Elder aranea
+G:S:v
+I:120:30d20:20:65:50
+W:40:3:1800:2500
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:POISON:5d8
+B:CLAW:POISON:5d8
+B:BITE:HALLU:5d6
+B:BITE:HALLU:5d6
+F:DROP_SKELETON | FORCE_MAXHP |
+F:OPEN_DOOR | BASH_DOOR | HURT_LITE | SMART |
+F:ANIMAL | SPIDER | EVIL | IM_FIRE | IM_POIS | BASEANGBAND
+S:1_IN_6
+S:SLOW | HOLD | DRAIN_MANA | MIND_BLAST | HEAL |
+S:BA_FIRE | BO_FIRE | CAUSE_3 | S_SPIDER
+D:A vast, bloated arachnid, master of its brood: among the more terrible of
+D:Ungoliant's descendants, this is a monster such as those who haunted the dread
+D:valley of Nan Dungortheb long ago.
+
+N:965:Giant brown tick
+G:S:u
+I:110:16d8:12:50:20
+W:25:2:400:27
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:POISON:2d6
+B:STING:BLIND:1d1
+F:WEIRD_MIND | BASH_DOOR | CAN_FLY |
+F:ANIMAL | IM_POIS | MORTAL | BASEANGBAND
+D:It is moving slowly towards you.
+
+N:966:Wavelord
+G:p:B
+I:120:16d100:30:120:40
+W:61:3:1800:7000
+E:1:1:1:2:1:1
+O:20:50:10:5
+B:HIT:HURT:8d9
+B:HIT:COLD:8d9
+B:HIT:HURT:8d9
+B:HIT:COLD:8d9
+F:SMART | PET | DROP_CORPSE | FRIENDS | WILD_SHORE | WILD_OCEAN | WILD_TOO |
+F:IM_POIS | AQUATIC | CAN_SWIM | DROP_USEFUL |
+F:NO_CONF | NO_SLEEP | NO_FEAR | DROP_GOOD | DROP_3D2 |
+F:MORTAL | REGENERATE | TAKE_ITEM | GOOD | SUSCEP_FIRE |
+F:RES_WATE | RES_NEXU | HAS_LITE
+S:1_IN_4
+S:BO_WATE | BA_WATE | BO_ICEE
+D:The Dolphiners came with the Thunderlords from their far home.
+D:These friendly beings ride their sharks into combat to assist you.
+
+N:967:Novice possessor (soul)
+G:G:D
+I:110:1d1:30:1:10
+W:10:3:10:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:SMART | POSSESSOR |
+F:BASEANGBAND | NO_CUT
+D:It does not look that powerful.
+
+N:968:Bat of Gorgoroth
+G:b:g
+I:120:20d10:20:30:30
+W:28:3:150:100
+E:0:1:1:0:1:0
+O:0:0:0:0
+B:BITE:POISON:1d10
+B:CLAW:HURT:1d4
+F:DROP_60 | RAND_25 | MOVE_BODY | CAN_FLY | DROP_CORPSE |
+F:BASH_DOOR | MOVE_BODY | FRIENDS | WEIRD_MIND |
+F:ANIMAL | IM_POIS | AI_ANNOY | MORTAL | BASEANGBAND
+S:1_IN_8 |
+S:SCARE | BR_POIS | BR_DARK
+D:Fed with horrid meats and grown to enormous size, this slavering creature
+D:seeks livelier prey.
+
+N:969:The Princess
+G:p:y
+I:110:1d1:40:250:3
+W:0:4:730:0
+E:0:1:1:2:1:1
+O:0:0:1:0
+F:FEMALE | CAN_SPEAK
+F:FORCE_MAXHP | SPECIAL_GENE | NO_TARGET
+F:NEVER_MOVE | NEVER_BLOW | GOOD | NO_DEATH | RES_TELE
+F:MORTAL | BASEANGBAND | UNIQUE | PET |
+D:The princess of an unknown kingdom, you need to save her.
+
+N:970:Merton Proudfoot, the lost hobbit
+G:h:v
+I:110:1d1:40:250:3
+W:0:0:730:0
+E:0:1:1:2:1:1
+O:0:0:0:1
+F:MALE | CAN_SPEAK
+F:FORCE_MAXHP | NEVER_GENE | WILD_ONLY | WILD_TOWN |
+F:NEVER_MOVE | NEVER_BLOW | GOOD | NO_TARGET
+F:MORTAL | BASEANGBAND | UNIQUE | PET | NO_DEATH
+D:The poor hobbit got lost in the dreadful maze.
+
+N:971:The Wight-King of the Barrow-downs
+G:W:v
+I:120:38d22:30:45:0
+W:46:3:0:22000
+E:0:0:0:0:0:0
+O:15:55:15:0
+B:HIT:HURT:2d10
+B:WAIL:PARALYZE:2d6
+B:TOUCH:EXP_80:4d8
+B:TOUCH:EXP_80:4d8
+F:SPECIAL_GENE | FORCE_MAXHP | SMART | CAN_SPEAK |
+F:DROP_4D2 | DROP_2D2 | COLD_BLOOD | UNIQUE |
+F:CAN_SWIM | CAN_FLY | EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_4 |
+S:HOLD | SCARE | CAUSE_3 | BA_NETH
+D:He has lived in the Barrow-Downs for centuries after his first death at the
+D:hands of the Witch-King of Angmar. A once loyal captain under the
+D:Witch-King's command, he now awaits a time when his undead forces shall
+D:rise again to avenge their deaths.
+
+N:972:Adventurer
+G:@:U
+I:115:3d20:50:50:10
+W:0:3:100:0
+O:50:50:0:0
+B:HIT:HURT:2d6
+B:PUNCH:HURT:1d7
+B:KICK:HURT:1d8
+F:SPECIAL_GENE | SMART | OPEN_DOOR
+F:FORCE_MAXHP | CAN_SWIM | BASEANGBAND |
+F:NO_SLEEP | NO_CONF
+D:A great warrior who misplaces his sword once in a while.
+
+N:973:Experienced possessor (soul)
+G:G:D
+I:120:5d5:30:50:10
+W:30:3:10:0
+O:0:0:0:0
+F:SMART | POSSESSOR |
+F:BASEANGBAND | NO_CUT
+S:1_IN_9
+S:S_KIN
+D:It does not look that powerful.
+
+N:974:Old possessor (soul)
+G:G:D
+I:130:10d10:30:100:10
+W:95:3:10:0
+O:0:0:0:0
+F:SMART | POSSESSOR |
+F:BASEANGBAND | NO_CUT
+S:1_IN_4
+S:S_KIN
+D:It does not look that powerful.
+
+# New monster added by furiosity for the Theme module
+N:975:Tree mold
+G:m:G
+I:110:17d8:2:16:70
+W:19:1:40:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:POISON:4d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange green growth that likes to live in
+D:the trees.
+
+N:976:Bronze dragon worm
+G:w:U
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_CONF |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_CONF
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Its scales glitter in
+D:a multitude of perplexing and distracting ways.
+
+N:977:Gold dragon worm
+G:w:y
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | NO_STUN |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_SOUN
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. You can feel the air itself
+D:vibrating as you near it.
+
+N:978:Defenceless Mold
+G:m:v
+I:100:1d1:1:1:0
+W:1:1:20:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:NEVER_MOVE | UNIQUE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | FORCE_DEPTH |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:MORTAL | WYRM_PROTECT | ONLY_DEPTH | JOKEANGBAND | NO_CUT
+D:A small strange growth. It seems to be defenceless.
+
+# New monster added by furiosity for the Theme module
+N:979:Blue mold
+G:m:B
+I:110:17d8:2:16:70
+W:19:1:40:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:HALLU:4d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND |
+F:IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a strange blue growth on the dungeon floor; it seems to glow with
+D:a puzzling aura.
+
+N:980:Ar-Pharazon the Golden
+G:p:y
+I:130:50d100:30:45:255
+W:55:1:0:2500
+E:1:1:1:2:1:1
+O:20:70:10:0
+B:HIT:HURT:8d12
+B:HIT:HURT:8d12
+B:HIT:HURT:8d12
+B:HIT:HURT:8d12
+F:FORCE_SLEEP | FORCE_MAXHP | UNIQUE | CAN_SPEAK | SPECIAL_GENE | AQUATIC |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD | DROP_SKELETON | DROP_CORPSE |
+F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | MOVE_BODY | BASEANGBAND |
+F:HAS_LITE | CAN_SWIM | MALE |
+S:1_IN_6 |
+S:HEAL | HASTE | TELE_AWAY | S_MONSTERS | S_KIN
+D:Last and proudest king of ancient Numenor. Corrupted by power and
+D:avarice, he fell victim to Sauron's wiles, tried to fight the immortals
+D:themselves, and condemned Numenor to oblivion.
+
+N:981:Doppleganger
+G:@:w
+I:110:1d1:1:1:1
+W:1:1:0:0
+E:0:0:0:0:0:0
+O:0:0:0:0
+F:AI_ANNOY | NEVER_BLOW | DOPPLEGANGER | JOKEANGBAND | HAS_LITE |
+D:It looks like you.
+
+N:982:Marylene, Heartbreakeress of the Netherworld
+G:P:W
+I:155:200d120:155:175:0
+W:127:1:1600:66666
+E:1:1:1:2:1:1
+O:30:30:30:10
+B:GAZE:PARALYZE:20d15
+B:HIT:EXP_80:20d17
+B:BITE:LOSE_ALL:10d12
+B:TOUCH:INSANITY:12d9
+F:UNIQUE | CAN_SPEAK | ATTR_MULTI | ATTR_ANY | FEMALE |
+F:FORCE_MAXHP | WEIRD_MIND | DROP_CORPSE | DROP_SKELETON |
+F:REFLECTING | AURA_FIRE | AURA_ELEC | AURA_COLD |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | RES_NETH | INVISIBLE |
+F:SMART | KILL_WALL | KILL_BODY | POWERFUL | RES_TELE |
+F:REGENERATE | CAN_FLY | CAN_SWIM | WYRM_PROTECT |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_STUN | RES_TELE | DEMON |
+F:MORTAL | DG_CURSE | JOKEANGBAND | HAS_LITE
+S:1_IN_1 |
+S:BR_CHAO | BA_CHAO | BRAIN_SMASH | SHRIEK | BR_CONF | BR_SOUN |
+S:BR_NETH | HASTE | TRAPS | FORGET | BR_DISE | BR_TIME | MIND_BLAST |
+S:HEAL | TPORT | TELE_TO | CAUSE_1 | CAUSE_2 | CAUSE_3 | CAUSE_4 | BLIND |
+S:CONF | SLOW | HOLD | S_UNIQUE
+D:A woman of mind-shattering beauty, none can match her beauty. She is perfect,
+D:and totaly evil. She loves nothing but herself and her evilness is as
+D:great as her beauty. No one can stand against her, even DarkGod.
+D:As you see her approaching, you feel your heart breaking.
+D:She is the perfection, don't even try against her; you will surely lose
+D:your mind...
+
+# New monster added by furiosity for the Theme module
+N:983:Adventurer mold
+G:m:U
+I:110:17d8:2:16:70
+W:19:1:40:64
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:SPORE:HURT:4d4
+B:SPORE:HURT:4d4
+F:NEVER_MOVE |
+F:STUPID | EMPTY_MIND | PET |
+F:IM_FIRE | IM_POIS | CAN_SWIM |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+D:It is a fellow adventurer, mold though it is.
+
+# New monster added by furiosity for the Theme module
+# Based on novice paladin
+N:984:Gnome paladin
+G:l:w
+I:110:7d8:20:20:20
+W:15:2:900:40
+E:1:1:1:2:1:1
+O:0:70:25:0
+B:HIT:HURT:1d7
+B:HIT:HURT:1d7
+F:MALE | GOOD | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | FRIENDS |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_9 |
+S:SCARE | CAUSE_2 | DARKNESS |
+D:A paladin of short stature. He considers you a spy for Morgoth.
+
+N:985:Bandobras Took
+G:h:U
+I:120:6d10:16:8:10
+W:5:3:1000:90
+E:1:1:1:2:1:1
+O:25:55:0:20
+B:HIT:HURT:1d8
+B:HIT:HURT:1d8
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He is a sturdy hobbit who is renowned for his unusual strength and
+D:vigour. He can prove a troublesome opponent.
+
+N:986:3-headed hydra
+G:M:o
+I:120:100d5:20:65:20
+W:20:2:4500:350
+E:0:1:0:2:2:0
+O:0:0:0:0
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+B:BITE:HURT:2d6
+F:FORCE_SLEEP | WILD_TOO | WILD_SHORE | WILD_SWAMP | CAN_SWIM |
+F:DROP_CORPSE | DROP_SKELETON | ONLY_GOLD | DROP_2D2 |
+F:OPEN_DOOR | BASH_DOOR | MOVE_BODY |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:1_IN_9 |
+S:SCARE
+D:A strange reptilian creature with three heads, guarding its hoard.
+
+N:987:Uldor the Accursed
+G:p:U
+I:110:10d100:20:70:40
+W:28:4:2000:600
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 | S_KIN
+D:An evil and cunning man from the East. Having once sworn allegiance to the
+D:sons of Feanor, it was Uldor's treachery that turned the tide of the Battle
+D:of Unnumbered Tears in Morgoth's favour.
+
+N:988:Mystic
+G:p:o
+I:120:35d10:30:50:5
+W:33:3:1400:500
+E:1:1:1:2:1:1
+O:30:0:60:10
+B:KICK:HURT:10d2
+B:KICK:HURT:10d2
+B:KICK:HURT:10d2
+B:KICK:HURT:10d2
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_1D2 |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_POIS | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL |
+S:S_SPIDER | S_ANIMAL
+D:An adept at unarmed combat, the mystic strikes with stunning power. He
+D:can summon help from nature and is able to focus his power to ease any
+D:pain.
+
+N:989:Elder vampire
+G:V:r
+I:120:34d100:20:90:10
+W:54:3:1700:4500
+E:1:1:1:2:1:1
+O:0:70:30:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:BITE:EXP_80:5d6
+B:BITE:EXP_80:5d6
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:DROP_60 | DROP_4D2 | DROP_GOOD |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | RES_TELE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_7 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | DARKNESS | BO_NETH | S_UNDEAD
+D:A terrible robed undead figure, this creature has existed in its
+D:unlife for many centuries by stealing the life of others. It can
+D:summon the very shades of its victims from beyond the grave to
+D:come enslaved to its aid.
+
+N:990:Ulfang the Black
+G:p:U
+I:120:25d100:20:90:40
+W:44:5:2100:1200
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:5d8
+B:HIT:HURT:5d8
+B:HIT:HURT:5d8
+B:HIT:HURT:5d8
+F:UNIQUE | MALE | CAN_SPEAK | DROP_CORPSE | DROP_SKELETON |
+F:FORCE_MAXHP | IM_FIRE | IM_COLD | IM_ELEC | SPECIAL_GENE |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_RANDART
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_10 | S_KIN | S_MONSTERS
+D:A short and swarthy Easterling dressed in black. He and his three sons
+D:once openly swore allegiance to the High Elves, but were secretly in the
+D:pay of Morgoth.
+
+N:991:Demonologist
+G:p:R
+I:120:28d10:20:50:10
+W:36:2:1100:700
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON
+F:RES_NETH | RES_NEXU |
+F:ONLY_ITEM | DROP_1D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:TPORT | HOLD |
+S:S_DEMON | BO_FIRE
+D:A figure twisted by evil standing in robes of deepest crimson.
+
+N:992:Ungorrog
+G:U:g
+I:110:52d10:20:40:80
+W:51:3:2100:2500
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:3d4
+B:STING:POISON:3d4
+B:SPIT:FIRE:3d4
+B:SPIT:ELEC:3d4
+F:FORCE_SLEEP | FORCE_MAXHP | ESCORTS |
+F:ONLY_ITEM | DROP_GREAT | AURA_FIRE | AURA_ELEC |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | NONLIVING
+F:BASEANGBAND
+S:1_IN_9 |
+S:BLIND | CONF | SCARE | HOLD
+S:S_DEMON | BO_COLD | BO_ACID
+D:The most powerful of the spider demons, Morgoth's corrupted
+D:spiders. It looks like a huge bloated spider, with claws
+D:that sparkle with all the elements.
+
+N:993:Faunungol
+G:U:B
+I:110:70d10:20:40:80
+W:43:2:2300:3000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:3d4
+B:STING:POISON:3d4
+B:SPIT:ELEC:3d4
+B:CRUSH:HURT:6d8
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_90 | AURA_ELEC |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | IM_ELEC |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | NONLIVING |
+F:BASEANGBAND
+S:1_IN_9 |
+S:BLIND | CONF |
+D:One of the spider demons, spawn of Ungoliant. It looks like
+D:a giant bloated spider surrounded by blazing sparks.
+
+N:994:Naurungol
+G:U:r
+I:110:90d10:20:50:80
+W:45:2:6000:5000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:3d4
+B:STING:POISON:3d4
+B:SPIT:FIRE:3d4
+B:HIT:LOSE_STR:3d4
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE |
+F:ONLY_ITEM | DROP_1D2 |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON |
+F:IM_FIRE | NO_CONF | NO_SLEEP |
+F:BASEANGBAND
+S:1_IN_9 |
+S:BLIND | CONF |
+D:One of the spider demons, spawn of Ungoliant. It looks like
+D:a giant bloated spider glowing with malevolent flames.
+
+N:995:Sererrog
+G:U:y
+I:120:20d70:20:75:80
+W:47:2:3000:7000
+E:3:0:3:4:1:0
+O:0:50:50:0
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+B:HIT:HURT:3d6
+F:FEMALE |
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_1D2 | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | NONLIVING |
+F:BASEANGBAND
+S:1_IN_9 |
+S:BLIND | CAUSE_2 | SCARE |
+S:S_DEMON
+D:A corrupted Maia of female form, whose skin drips with blood.
+D:It has several arms, and fights with three grim daggers.
+
+N:996:Red Balrog
+G:U:R
+I:120:20d100:20:50:80
+W:61:4:9000:10000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:FIRE:4d12
+B:HIT:FIRE:4d12
+B:CRUSH:HURT:3d12
+B:TOUCH:UN_POWER
+F:FORCE_SLEEP | FORCE_MAXHP | AURA_FIRE | KILL_WALL |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:EVIL | DEMON | IM_FIRE | NO_CONF | NO_SLEEP | NONLIVING |
+F:BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:BLIND | CONF | SCARE | HASTE |
+S:BR_FIRE |
+S:S_DEMON
+D:The greatest of the demons, potent in both magical might
+D:and sheer battle power. This corrupted Maia's form is
+D:surrounded by roaring flames.
+
+N:997:Master mystic
+G:p:o
+I:130:11d100:30:60:5
+W:50:3:1600:6000
+E:1:1:1:2:1:1
+O:40:0:40:20
+B:KICK:HURT:10d2
+B:KICK:HURT:10d2
+B:HIT:POISON:20d1
+B:HIT:PARALYZE:15d1
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL |
+S:S_SPIDER | S_ANIMALS
+D:A lord of all that is natural, skilled in the mystic ways. He is a master
+D:of martial arts and is at one with nature, able to summon help from the
+D:wild if need be.
+
+N:998:Grand master mystic
+G:p:o
+I:130:22d100:30:80:5
+W:57:3:1800:15000
+E:1:1:1:2:1:1
+O:40:0:40:20
+B:KICK:HURT:20d2
+B:KICK:HURT:10d2
+B:HIT:POISON:20d1
+B:HIT:PARALYZE:15d1
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_4D2 |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HEAL | MIND_BLAST |
+S:S_SPIDER | S_HOUND | S_ANIMALS
+D:He is one of the few true masters of the art, being extremely skillful in
+D:all forms of unarmed combat and controlling the world's natural creatures
+D:with disdainful ease.
+
+N:999:Morgulrog
+G:U:o
+I:110:24d100:20:50:80
+W:42:2:0:1000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:HURT:3d4
+B:HIT:UN_BONUS:3d4
+B:HIT:UN_POWER:1d5
+F:FORCE_SLEEP | FORCE_MAXHP |
+F:ONLY_ITEM | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:EVIL | DEMON | NO_CONF | NO_SLEEP |
+F:IM_FIRE | IM_POIS | IM_ELEC | IM_COLD |
+F:BASEANGBAND
+S:1_IN_9 |
+S:BLIND | CONF | SCARE | HASTE | HEAL | S_KIN
+S:TRAPS | SLOW | HOLD | SHRIEK | BLINK
+D:A twisted elemental spirit, this creature serves the Dark with
+D:perversions of the magics of nature.
+
+N:1000:Novice mindcrafter
+G:p:y
+I:110:6d8:20:10:5
+W:4:1:900:18
+E:1:1:1:2:1:1
+O:0:50:0:30
+B:HIT:HURT:1d6
+F:DROP_60 | WILD_TOO |
+F:OPEN_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE | NO_CONF | NO_SLEEP
+S:1_IN_9 | BLIND | SLOW | CONF | SCARE
+D:A novice in the arts of mind over matter.
+
+# New monster added by furiosity for the Theme module
+# Based on dark elven lord
+N:1001:Gnome lord
+G:l:s
+I:110:8d10:20:20:20
+W:20:2:900:40
+E:1:1:1:2:1:1
+O:0:70:25:0
+B:HIT:HURT:3d8
+B:HIT:HURT:3d5
+F:MALE | EVIL | WILD_TOO | DROP_SKELETON | DROP_CORPSE |
+F:FORCE_SLEEP |
+F:DROP_60 |
+F:OPEN_DOOR | BASH_DOOR |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_5 |
+S:HASTE | BLIND | CONF | DARKNESS | MISSILE
+D:A lord among gnomes.
+
+N:1002:Great Worm of Perplexity
+G:D:U
+I:120:40d100:30:150:80
+W:63:2:190000:20000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:CONFUSE:6d14
+B:BITE:CONFUSE:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:SMART | BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | BASEANGBAND | HAS_LITE | ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_CONF
+D:A dragon of great size and power. Its polished bronze scales reflect the
+D:light in strange and confusing patterns, and you find it hard to keep your
+D:mind on the job of fighting for your life.
+
+# New monster added by furiosity for the Theme module
+# Based on mystic
+N:1003:Gnome mystic
+G:l:o
+I:120:25d10:30:40:5
+W:33:3:1000:400
+E:1:1:1:2:1:1
+O:30:0:60:10
+B:KICK:HURT:8d2
+B:KICK:HURT:8d2
+B:KICK:HURT:8d2
+B:KICK:HURT:8d2
+F:MALE |
+F:FORCE_SLEEP | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
+F:ONLY_ITEM | DROP_1D2 |
+F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
+F:IM_ACID | IM_POIS | NO_CONF | NO_SLEEP |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_6 |
+S:HEAL |
+S:S_ANIMAL
+D:A mystic of short stature. He is quite skilled at unarmed
+D:combat and even has some control over the forces of nature.
+
+N:1004:Great Worm of Thunder
+G:D:y
+I:120:50d100:30:150:80
+W:67:2:190000:23000
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:4d12
+B:CLAW:HURT:4d12
+B:BITE:HURT:6d14
+B:BITE:HURT:6d14
+F:FORCE_SLEEP | FORCE_MAXHP | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
+F:BASH_DOOR | POWERFUL | MOVE_BODY | DROP_CORPSE |
+F:EVIL | DRAGON | NO_CONF | NO_SLEEP | NO_STUN | BASEANGBAND | HAS_LITE
+F:ATTR_MULTI
+S:1_IN_4 |
+S:BLIND | CONF | SCARE |
+S:BR_SOUN
+D:A dragon of gigantic proportions, with destructive abilities to match. The
+D:sheer loudness of its roar leaves you stunned and unable to think clearly
+D:enough to defend yourself adequately.
+
+N:1005:Silver mouse
+G:r:B
+I:110:1d3:8:4:20
+W:4:1:200:1
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:EAT_LITE:1d2
+F:RAND_25 | CAN_SWIM | ANIMAL |
+F:DROP_CORPSE | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is about three feet long with large teeth. As the light of your lamp falls
+D:on it, it seems to grow stronger.
+
+N:1006:The Rat King
+G:r:v
+I:120:20d12:30:30:0
+W:18:1:950:32
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:CLAW:HURT:3d2
+B:CLAW:HURT:3d2
+B:BITE:DISEASE:4d2
+B:BITE:DISEASE:4d2
+F:UNIQUE | ESCORT | ESCORTS | FORCE_MAXHP |
+F:BASH_DOOR | ANIMAL | NO_CONF | NO_SLEEP
+F:MORTAL | BASEANGBAND
+D:A massive rat. He's the leader of the pack.
+
+# New monster added by furiosity for the Theme module
+# Based on Priest
+N:1007:Gnome priest
+G:l:r
+I:110:10d8:20:22:40
+W:15:1:1000:25
+E:1:1:1:2:1:1
+O:0:20:80:0
+B:HIT:HURT:2d3
+B:HIT:HURT:2d3
+F:MALE | GOOD |
+F:FORCE_SLEEP |
+F:DROP_1D2 |
+F:SMART | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:HEAL | SCARE | CAUSE_2 |
+S:S_MONSTER
+D:A priest of short stature. He looks comically solemn.
+
+N:1008:Black midge
+G:I:D
+I:120:1d2:6:7:10
+W:14:1:100:3
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:BITE:HURT:1d2
+F:RAND_50 | RAND_25 | CAN_FLY | WEIRD_MIND |
+F:ANIMAL | MORTAL | BASEANGBAND
+S:MULTIPLY
+D:It is an evil relative of the moth, native to marshlands.
+
+N:1009:Fire Phantom
+G:G:r
+I:120:10d100:20:90:40
+W:34:5:0:1200
+E:0:0:0:0:0:0
+O:0:0:100:0
+B:HIT:HURT:5d5
+F:UNIQUE | MALE | CAN_SPEAK
+F:FORCE_MAXHP | UNDEAD | NO_CONF | NO_SLEEP | REGENERATE | NO_STUN |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | PASS_WALL |
+F:MORTAL | JOKEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_6
+S:BR_FIRE | HOLD | CONF | SCARE | MIND_BLAST
+D:He's back from the grave for vengeance on those who
+D:burnt him. He has no mercy for those in his way.
+
+N:1010:The Insane Player
+G:p:v
+I:120:18d100:25:100:10
+W:36:2:1500:1200
+E:1:1:1:2:1:1
+O:20:20:20:20
+B:HIT:HURT:3d8
+F:UNIQUE | MALE | CAN_SPEAK | ATTR_MULTI |
+F:FORCE_MAXHP |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_SKELETON | DROP_CORPSE
+F:OPEN_DOOR | BASH_DOOR | RAND_25 |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR
+F:JOKEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:TELE_TO | SHRIEK | SCARE
+D:Once a powerful adventurer, this poor fighter has seen a few too many
+D:software bugs in his time. Any shred of lucidity is long gone, but
+D:he still remains dangerous. He wanders aimlessly through the dungeon
+D:randomly striking at foes both real and imagined, all the while screaming
+D:out at the world that caused his condition.
+
+# New monster added by furiosity for the Theme module
+# Based on Master thief
+N:1011:Gnome rogue
+G:l:b
+I:130:15d10:20:30:40
+W:28:2:1000:350
+E:1:1:1:2:1:1
+O:90:10:0:0
+B:HIT:HURT:1d7
+B:HIT:HURT:2d3
+B:HIT:EAT_GOLD:5d5
+B:HIT:EAT_ITEM:5d6
+F:MALE |
+F:DROP_90 | DROP_2D2 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_6
+S:TRAPS | ARROW_2 | BLINK
+D:A little gnome, fast and stealthy. He is eyeing your backpack.
+
+N:1012:Vermicious Knid
+G:j:s
+I:110:90d10:20:55:100
+W:44:2:1400:2100
+E:0:0:0:0:0:0
+O:40:30:20:10
+B:TOUCH:TERRIFY:4d6
+B:CRAWL:HURT:4d6
+B:ENGULF:HURT:4d6
+F:FRIENDS | EVIL | IM_COLD | SMART |
+F:COLD_BLOOD | NO_FEAR | WEIRD_MIND |
+F:OPEN_DOOR | ONLY_ITEM | DROP_2D2 | HURT_ROCK |
+F:NONLIVING |
+F:JOKEANGBAND | NO_CUT
+D:An amorphous shape that looks like wet grey clay with two pale eyes.
+D:It is totally silent as it oozes towards you.
+
+N:1013:Bone golem
+G:g:w
+I:120:35d100:20:170:50
+W:61:3:5000:23000
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:UN_BONUS:8d8
+B:HIT:UN_BONUS:8d8
+B:HIT:LOSE_STR:6d6
+B:HIT:LOSE_STR:6d6
+F:FORCE_SLEEP | FORCE_MAXHP | EMPTY_MIND |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | IM_FIRE | IM_ELEC | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:TELE_TO | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | BA_NETH | S_HI_UNDEAD
+D:A skeletal form, black as night, constructed from the bones of its
+D:previous victims.
+
+# New monster added by furiosity for the Theme module
+# Based on hardened warrior
+N:1014:Gnome warrior
+G:l:u
+I:110:15d11:20:40:40
+W:22:1:1000:60
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:HURT:4d3
+B:HIT:HURT:4d3
+F:MALE |
+F:DROP_1D2 |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE | KILL_BODY |
+D:A warrior of short stature but great ferocity.
+
+N:1015:Bronze golem
+G:g:o
+E:2:1:2:4:1:1
+O:0:0:0:0
+I:120:40d100:25:170:50
+W:65:3:5500:26000
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:FORCE_MAXHP | FORCE_SLEEP | EMPTY_MIND | COLD_BLOOD |
+F:OPEN_DOOR | BASH_DOOR | IM_FIRE | IM_ELEC | IM_POIS | RES_TELE |
+F:NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR | NONLIVING | BASEANGBAND | NO_CUT
+S:1_IN_3 |
+S:BO_PLAS | BA_FIRE | BR_FIRE | BA_ELEC | S_HI_DEMON | TELE_TO
+D:A gigantic four-armed animated bronze statue, glowing with great heat.
+
+# New monster added by furiosity for the Theme module
+# Multiplying gnome mage. Heh.
+N:1016:Wizard leprawn
+G:l:W
+I:90:7d8:20:20:20
+W:14:2:900:50
+E:1:1:1:2:1:1
+O:20:0:80:0
+B:HIT:HURT:1d5
+F:MALE |
+F:FORCE_SLEEP | DROP_60 |
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON |
+F:EVIL | MORTAL | BASEANGBAND | HAS_LITE
+S:1_IN_4 |
+S:DARKNESS | BO_COLD |
+S:S_MONSTER
+S:MULTIPLY
+D:A short little gnome, waving his hands in the air.
+
+# New monster added by furiosity for the Theme module
+N:1017:Kender
+G:l:y
+I:115:8d9:20:20:20
+W:15:3:900:40
+E:1:1:1:2:1:1
+O:25:25:25:25
+B:TOUCH:EAT_ITEM:5d5
+B:TOUCH:EAT_ITEM:5d5
+B:TOUCH:EAT_ITEM:5d5
+B:TOUCH:EAT_ITEM:5d5
+F:JOKEANGBAND | WILD_TOO | WILD_GRASS | WILD_WOOD |
+F:MORTAL | GOOD | HAS_LITE | FORCE_SLEEP |
+F:DROP_60 | DROP_GREAT | OPEN_DOOR | RES_TELE |
+D:A funny, smiling humanoid of short stature, with a pony-
+D:tail and an enormous pouch. He is very polite, but also
+D:very curious. So curious, in fact, that the contents of
+D:your backpack are making their way into his pouch!
+
+# New monster added by furiosity for the Theme module
+# Based on Human warrior
+N:1018:Adventurer gnome
+G:l:U
+I:110:9d8:10:10:3
+W:15:3:1000:0
+B:HIT:HURT:5d8
+B:HIT:HURT:5d8
+F:BASEANGBAND | WILD_TOO | WILD_GRASS | WILD_WOOD |
+F:MORTAL | GOOD | HAS_LITE | FORCE_SLEEP | NO_FEAR |
+F:PET | FRIENDS | DROP_60 | OPEN_DOOR | BASH_DOOR |
+D:A fellow adventurer of rather short stature.
+
+# New monster added by furiosity for the Theme module
+N:1019:Tree cat
+G:f:g
+I:120:12d10:40:40:0
+W:12:2:1500:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:BITE:HURT:1d8
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:1d6
+F:BASH_DOOR | WILD_TOO | WILD_GRASS | WILD_WOOD | WILD_MOUNTAIN |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE | MORTAL | BASEANGBAND |
+F:IM_POIS | CAN_FLY |
+D:A large cat that prefers to dwell in the trees and is very
+D:adept at navigating through the thickest forests while it
+D:stalks its prey.
+
+# New monster added by furiosity for the Theme module
+N:1020:Night cat
+G:f:b
+I:120:12d10:40:40:0
+W:15:2:1500:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:1d6
+F:BASH_DOOR | WILD_TOO | WILD_GRASS | WILD_WOOD | WILD_MOUNTAIN |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE | MORTAL | BASEANGBAND |
+F:EMPTY_MIND | KILL_BODY | HURT_LITE |
+D:A huge dark shape pouncing on you from the darkness, this cat
+D:mostly hunts at night and is extremely good at evading detection.
+
+# New monster added by furiosity for the Theme module
+N:1021:Leopard
+G:f:u
+I:130:12d10:40:40:0
+W:18:2:1500:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:1d6
+F:BASH_DOOR | WILD_TOO | WILD_GRASS | WILD_WOOD | WILD_MOUNTAIN |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE |
+F:MORTAL | BASEANGBAND
+D:A large cat with sleek brown spotted fur. It is fast and lithe,
+D:and none escape its notice.
+
+# New monster added by furiosity for the Theme module
+N:1022:Cheshire cat
+G:f:G
+I:120:12d10:40:40:0
+W:20:2:1500:40
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:CLAW:HURT:1d8
+B:CLAW:HURT:1d8
+B:BITE:HURT:1d6
+F:BASH_DOOR | WILD_TOO | WILD_GRASS | WILD_WOOD | WILD_MOUNTAIN |
+F:ANIMAL | DROP_SKELETON | DROP_CORPSE | SMART | PET |
+F:MORTAL | JOKEANGBAND | IM_POIS | WEIRD_MIND | INVISIBLE |
+D:A large cat with a huge smile. In fact, sometimes the smile
+D:is all you see of it.
+
+N:1023:Blue dragon worm
+G:w:B
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ELEC |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_ELEC
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Sparks fly from its jaws.
+
+N:1024:White dragon worm
+G:w:W
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_COLD |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_COLD
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Its breath condenses in the air.
+
+N:1025:Green dragon worm
+G:w:G
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_POIS |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_POIS
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. You can smell foul gases
+D:on its breath.
+
+N:1026:Black dragon worm
+G:w:s
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ACID |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_ACID
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Acidic drool drips from its jaws.
+
+N:1027:Red dragon worm
+G:w:R
+I:100:10d15:10:40:80
+W:20:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_FIRE |
+F:MORTAL | BASEANGBAND | ATTR_MULTI
+S:MULTIPLY |
+S:1_IN_6 | BR_FIRE
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Smoke comes from its mouth.
+
+N:1028:Multi-hued dragon worm
+G:w:v
+I:100:10d20:10:40:80
+W:23:3:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:HURT:3d3
+B:CLAW:HURT:3d3
+B:BITE:HURT:3d5
+F:RAND_50 | RAND_25 | ATTR_MULTI |
+F:DROP_60 | ONLY_GOLD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | DRAGON | IM_ELEC | IM_FIRE | IM_ACID | IM_COLD | IM_POIS |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY |
+S:1_IN_6 | BR_ELEC | BR_COLD | BR_FIRE | BR_ACID | BR_POIS
+D:You thought dragons used eggs, but this worm has the scales, and the bad
+D:breath, and the fiery eyes, of a real dragon. Its scales shimmer different
+D:colours as you watch.
+
+N:1029:The Minotaur of the Labyrinth
+G:H:v
+I:130:150d10:13:25:10
+W:40:2:17500:3100
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:BUTT:HURT:4d6
+B:BUTT:HURT:4d6
+B:BUTT:HURT:3d6
+B:BUTT:HURT:3d6
+F:BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:EVIL | UNIQUE | SPECIAL_GENE |
+F:MORTAL | BASEANGBAND
+D:It is a cross between a human and a bull. The last of its kind,
+D:it guards its treasure jealously.
+
+N:1030:The Sandworm Queen
+G:w:v
+I:120:30d20:10:40:80
+W:30:3:4500:12
+E:0:0:0:0:1:0
+O:30:60:0:10
+B:CLAW:ACID:5d4
+B:CLAW:POISON:5d4
+B:BITE:FIRE:5d4
+B:BITE:ELEC:5d4
+F:FORCE_MAXHP | DROP_60 | ONLY_ITEM | DROP_GREAT | DROP_GOOD | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | FEMALE | POWERFUL | SPECIAL_GENE | REFLECTING |
+F:EVIL | ANIMAL | IM_ELEC | IM_FIRE | IM_ACID | IM_POIS | ESCORT |
+F:MORTAL | BASEANGBAND | EMPTY_MIND | UNIQUE | NO_CONF
+S:1_IN_2 | BR_POIS | S_KIN
+D:Queen and Mother of the sandworms, fear her and her prolific children.
+
+N:1031:Sandworm
+G:w:y
+I:115:10d15:10:40:80
+W:27:6:4500:12
+E:0:0:0:0:1:0
+O:0:0:0:0
+B:CLAW:POISON:4d4
+B:CLAW:POISON:4d4
+B:CLAW:POISON:4d4
+B:BITE:HURT:5d5
+F:RAND_25 |
+F:FORCE_MAXHP | DROP_CORPSE | POWERFUL |
+F:EVIL | IM_ELEC | IM_FIRE | IM_POIS | EMPTY_MIND |
+F:MORTAL | BASEANGBAND
+S:MULTIPLY
+D:Offbreed of the Sandworm Queen, it is harmless alone.
+
+N:1032:Tik'srvzllat
+G:G:v
+I:142:180d100:200:170:0
+W:127:2:1000:350000
+E:1:1:1:2:1:1
+O:50:0:50:0
+B:GAZE:UN_BONUS:10d10
+B:GAZE:TIME:10d10
+B:GAZE:INSANITY:10d10
+B:GAZE:INSANITY:10d5
+F:UNIQUE | SPECIAL_GENE |
+F:FORCE_MAXHP | POWERFUL |
+F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_GREAT |
+F:INVISIBLE | COLD_BLOOD | PASS_WALL | WEIRD_MIND |
+F:EVIL | UNDEAD | IM_COLD | IM_FIRE | IM_ACID | IM_ELEC | AURA_COLD |
+F:IM_POIS | RES_NETH | BASEANGBAND | NO_CUT
+S:1_IN_2 |
+S:S_UNDEAD | S_DEMON | S_DRAGON |
+S:S_UNIQUE | S_WRAITH | S_HI_DEMON |
+S:S_HI_UNDEAD | S_HI_DRAGON | S_KIN |
+S:BR_DISE | BA_NETH
+D:A disembodied and barely sentient mind, Tik'srvzllat floated
+D:through the void for eons before being awakened by sorcery, pulled
+D:into the nether realm, and shaped into the being you see before you.
+D:A flickering purple outline of a sphere, with eerie yellow-purple
+D:mist circling rapidly around it, Tik'srvzllat threatens your sanity
+D:with its appearance alone.
+
+N:1033:The Glass Golem
+G:g:W
+I:130:100d15:200:170:0
+W:52:4:0:2000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:HIT:INSANITY:5d6
+B:HIT:INSANITY:6d6
+B:HIT:INSANITY:7d6
+B:HIT:INSANITY:6d6
+F:COLD_BLOOD | EMPTY_MIND | KILL_WALL | FORCE_MAXHP | POWERFUL | SPECIAL_GENE |
+F:BASH_DOOR | IM_COLD | IM_ACID | IM_FIRE | IM_ELEC | IM_POIS | NONLIVING |
+F:ESCORTS | ESCORT | UNIQUE | NO_SLEEP | NO_CONF | NO_FEAR | NO_STUN
+F:CHAR_MULTI | CAN_FLY | BASEANGBAND | NO_CUT
+S:1_IN_4
+S:BR_CONF | BR_LITE | BR_DARK | BR_WALL
+S:S_KIN | TELE_LEVEL | SHRIEK
+D:One of the last creations of the Petty-Dwarves of Ludarin, its existence
+D:explains their destruction. A creation of finest glass, the body of this
+D:creature bends and amplifies light in a way that makes you unsure of its
+D:position. You feel somewhat dizzy as the radiant light reflects off the
+D:walls, the ceiling and your gear.
+
+N:1034:Elenwe the Lost
+G:U:W
+I:120:25d100:20:100:100
+W:50:3:12000:25000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:COLD:4d12
+B:HIT:COLD:4d12
+B:CRUSH:HURT:3d12
+B:TOUCH:UN_POWER
+F:UNIQUE | FORCE_SLEEP | FORCE_MAXHP | AURA_COLD | CAN_FLY |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | NONLIVING | DROP_RANDART
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | SMART |
+F:EVIL | DEMON | IM_COLD | NO_CONF | KILL_WALL | BASEANGBAND |
+F:HAS_LITE | FEMALE | SPECIAL_GENE
+S:1_IN_4 |
+S:BLIND | CONF | BRAIN_SMASH |
+S:BR_COLD | BO_COLD | BA_NETH | S_UNDEAD | S_DEMON
+D:She was once the wife of Turgon and mother of Idril Celebrindal. She was
+D:lost when the Noldor crossed the Grinding Ice after Feanor and his sons
+D:betrayed Fingolfin's host by burning the white ships of Alqualonde.
+D:Melkor corrupted her spirit and granted her balrog form, and she has
+D:guarded this pass ever since.
+
+N:1035:Golgarach, the Living Rock
+G:#:W
+I:120:50d30:20:100:40
+W:45:2:0:1500
+E:0:0:0:0:0:0
+O:60:0:40:0
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+B:HIT:HURT:4d6
+F:FORCE_SLEEP | COLD_BLOOD | EMPTY_MIND | PASS_WALL | KILL_BODY | ESCORT |
+F:BASH_DOOR | IM_COLD | IM_ACID | IM_ELEC | IM_POIS | NONLIVING | UNIQUE
+F:HURT_ROCK | NO_CONF | NO_SLEEP | NO_CUT | CHAR_MULTI | BASEANGBAND | SPECIAL_GENE
+F:NO_CUT | DROP_RANDART
+S:1_IN_10 | S_KIN | BO_ACID | BA_FIRE
+D:Deep in the heart of the earth, even the rock itself is sentient
+D:and has learned to despise intruders.
+
+# New monster added by furiosity for the Theme module
+N:1036:Sanctimonious-looking preacher
+G:t:w
+I:110:3d3:10:1:255
+W:0:1:1500:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:INSULT:*
+F:MALE | RAND_50 | CAN_SPEAK | NEUTRAL | NO_TARGET |
+F:ONLY_GOLD | DROP_60 | DROP_SKELETON | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | WILD_TOWN | WILD_ONLY |
+F:MORTAL | BASEANGBAND | HAS_LITE | AI_ANNOY |
+D:He thinks you are not pious enough. He will try to
+D:get you to change your ways.
+
+# New monster added by furiosity for the Theme module
+N:1037:Weary-looking traveller
+G:t:v
+I:110:3d3:10:1:255
+W:0:1:1500:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:1d3
+F:MALE | NEUTRAL | NO_TARGET |
+F:ONLY_ITEM | DROP_90 | DROP_SKELETON | DROP_CORPSE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_TOWN | WILD_ONLY |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:He's wearing fancy clothes of foreign make. He looks tired.
+
+N:1038:Water hound
+G:Z:r
+I:110:12d6:30:30:0
+W:43:1:600:150
+B:BITE:HURT:1d6
+B:CLAW:HURT:1d4
+B:CLAW:HURT:1d4
+E:0:1:0:2:1:0
+O:0:0:0:0
+F:FORCE_SLEEP | BASH_DOOR | DROP_CORPSE | FRIENDS
+F:ANIMAL | IM_COLD | MORTAL | BASEANGBAND | RES_WATE | NO_CUT
+S:1_IN_5 | BA_WATE
+D:The sound of a hundred waterfalls rushes through your ears as
+D:a huge wave of water, vaguely hound-shaped, rushes towards you.
+
+N:1039:Improv, the mighty MoLD
+G:m:v
+I:150:170d100:40:140:0
+W:127:2:3000:50000
+E:3:0:3:6:1:0
+O:20:20:20:20
+B:SPORE:UN_BONUS:10d10
+B:SPORE:EXP_80:10d10
+B:SPORE:TIME:10d10
+B:SPORE:TIME:10d10
+F:UNIQUE | NEVER_MOVE | CAN_SWIM | CAN_SPEAK |
+F:FORCE_MAXHP | WEIRD_MIND | DROP_CORPSE |
+F:REFLECTING | AURA_ELEC | ONLY_ITEM | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | FORCE_SLEEP | RES_NETH |
+F:SMART | POWERFUL | RES_TELE | REGENERATE | CAN_FLY |
+F:DG_CURSE | WYRM_PROTECT | EVIL |
+F:IM_ACID | IM_FIRE | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_STUN |
+F:JOKEANGBAND | HAS_LITE | RES_WATE | NO_CUT
+S:1_IN_2 |
+S:S_HI_DRAGON | S_KIN | BR_DISI | HEAL | TPORT |
+S:TELE_LEVEL | TELE_TO
+D:An assistant to DarkGod, Improv has chosen the form of a dense
+D:purple smog for his incarnation into Middle-earth. It travels the
+D:dungeons, killing software bugs and creating random artifacts for
+D:guests to find.
+
+N:1040:Emperor mimic
+G:m:y
+I:120:50d50:30:60:100
+W:40:3:100:200
+E:0:0:0:0:0:0
+O:25:25:25:25
+B:HIT:POISON:5d5
+B:HIT:POISON:5d5
+B:HIT:POISON:5d5
+B:HIT:POISON:5d5
+F:MIMIC | UNIQUE
+F:FORCE_SLEEP |
+F:EMPTY_MIND | COLD_BLOOD |
+F:IM_ACID | IM_FIRE | IM_ELEC | IM_COLD | IM_POIS |
+F:NO_CONF | NO_SLEEP | NO_FEAR | BASEANGBAND | NO_CUT
+S:1_IN_1 |
+S:BLIND | CONF | SCARE | CAUSE_4 | CAUSE_3 | FORGET |
+S:BA_ACID | BA_FIRE | BA_COLD | BA_ELEC |
+S:S_MONSTER | S_KIN | SHRIEK | BRAIN_SMASH | TRAPS
+D:A strange creature that disguises itself as an object to lure
+D:unsuspecting adventurers within reach of its venomous claws.
+
+N:1041:Melinda Proudfoot
+G:h:v
+I:110:1d1:40:250:3
+W:0:0:730:0
+E:0:1:1:2:1:1
+O:0:0:0:1
+F:FEMALE | CAN_SPEAK | WILD_ONLY | WILD_TOWN |
+F:FORCE_MAXHP | NEVER_GENE
+F:NEVER_MOVE | NEVER_BLOW | GOOD | NO_TARGET
+F:MORTAL | BASEANGBAND | UNIQUE | NEUTRAL | NO_TARGET | NO_DEATH
+D:She seems to seek someone, you may help.
+
+N:1042:Thrain, the King Under the Mountain
+G:k:B
+I:110:1d1:40:250:3
+W:60:1:730:0
+E:0:1:1:2:1:1
+O:0:0:0:1
+F:MALE | CAN_SPEAK
+F:FORCE_MAXHP | SPECIAL_GENE
+F:NEVER_MOVE | NEVER_BLOW | GOOD | NO_TARGET
+F:MORTAL | BASEANGBAND | UNIQUE | NEUTRAL | NO_TARGET | NO_DEATH
+D:He must have suffered horrible tortures.
+
+N:1043:Fire golem
+G:g:r
+I:115:3d20:50:50:10
+W:0:3:100:0
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:2d6
+B:HIT:HURT:2d6
+B:HIT:FIRE:3d6
+B:HIT:FIRE:3d6
+F:BASH_DOOR | AURA_FIRE | HAS_LITE
+F:IM_FIRE | SPECIAL_GENE
+F:NO_CONF | NO_SLEEP | NO_FEAR | NONLIVING | NO_STUN
+F:MORTAL | BASEANGBAND | NO_CUT | AI_PLAYER
+S:1_IN_10 |
+S:BR_FIRE
+D:A sentient mass of pure fire.
+
+N:1044:Melkor, Lord of Darkness
+G:G:v
+I:150:300d300:100:150:0
+W:150:1:200000:60000
+E:1:1:1:2:1:1
+O:25:25:25:25
+B:HIT:ABOMINATION:3d10
+B:HIT:TIME:24d10
+B:HIT:INSANITY:24d10
+B:HIT:LOSE_ALL:24d10
+F:UNIQUE | CAN_SPEAK | MALE |
+F:FORCE_MAXHP | SPIRIT
+F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 |
+F:DROP_GOOD | DROP_GREAT | DROP_CHOSEN | RES_NETH |
+F:SMART | KILL_WALL | MOVE_BODY | AURA_FIRE |
+F:REGENERATE | POWERFUL | SPECIAL_GENE | CAN_FLY | KILL_TREES
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:NO_CONF | NO_STUN | NO_SLEEP | NO_FEAR | RES_TELE | BASEANGBAND |
+S:1_IN_4 |
+S:BRAIN_SMASH |
+S:BA_MANA | BO_MANA | BA_NETH | BA_CHAO | BA_DARK | ANIM_DEAD | S_KIN |
+S:S_MONSTERS | S_UNIQUE | S_HI_DEMON | S_HI_UNDEAD | S_HI_DRAGON |
+S:BR_NETH | BR_DISI | HAND_DOOM | S_WRAITH | HEAL | BRAIN_SMASH |
+S:DRAIN_MANA | TELE_TO | DARKNESS | SHRIEK
+D:He was the most powerful of the Valar, the equal of Manwe.
+D:You banned him here, in the Void, and now you must destroy him
+D:forever. However here in the Void, his spirit gained much power
+D:for he is closer to the Flame Imperishable. He is coming to you in pure
+D:madness, which makes him even more dangerous. You are on the verge
+D:of dying!
+
+## Here are the Spirits, inhabitants of the Void, all called "Spirit" making it hard to know what we are up against ##
+## Note: I am nasty heheh :)
+
+# Spirit of nether
+N:1045:Spirit
+G:G:v
+I:120:40d80:30:50:20
+W:128:2:0:5000
+E:0:1:1:2:0:0
+O:25:0:75:0
+B:TOUCH:EXP_80:10d10
+B:TOUCH:EXP_80:10d10
+F:SPIRIT | BASEANGBAND | NEVER_MOVE | EMPTY_MIND | NO_CUT |
+F:COLD_BLOOD | INVISIBLE
+S:1_IN_1 |
+S:BA_NETH
+D:This strange, almost intangible spirit keeps assaulting you!
+
+# Spirit of annoyance (hahaha AI_ANNOY and MULTIPLY)
+N:1046:Spirit
+G:G:B
+I:130:40d20:30:70:70
+W:144:4:0:500
+E:0:0:0:0:0:0
+O:5:5:5:0
+B:TOUCH:POISON:10d10
+B:CRAWL:POISON:10d10
+B:CRAWL:EAT_ITEM:10d9
+B:BITE:UN_BONUS:9d9
+F:SPIRIT | BASEANGBAND | WEIRD_MIND | FRIENDS |
+F:AI_ANNOY | PASS_WALL
+S:MULTIPLY
+D:These things multiply at an apparently unstoppable rate!
+
+# Spirit of movement
+N:1047:Spirit
+G:G:B
+I:130:10d80:50:65:10
+W:132:1:10:5500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:TOUCH:LOSE_DEX:2d3
+B:TOUCH:PARALYZE:1d12
+B:TOUCH:PARALYZE:1d12
+F:SPIRIT | BASEANGBAND | NO_SLEEP | PASS_WALL | WEIRD_MIND
+S:1_IN_2 |
+S:SLOW | BLINK | HOLD | HASTE
+D:Coming towards you quickly, it seems intent on moving faster than you.
+
+# Spirit of confusion
+N:1048:Spirit
+G:G:v
+I:120:40d80:80:85:0
+W:135:2:0:5500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:ENGULF:HALLU:16d8
+B:ENGULF:HALLU:16d8
+B:ENGULF:CONFUSE:16d8
+B:ENGULF:CONFUSE:16d8
+F:SPIRIT | BASEANGBAND | RES_NEXU | AURA_ELEC | IM_FIRE | IM_ELEC |
+F:EMPTY_MIND | BASH_DOOR | POWERFUL | CAN_FLY | ATTR_MULTI |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_CUT
+S:1_IN_3 |
+S:BR_CHAO | BR_NEXU | BR_NUKE | BR_CONF
+D:A swirling mass, constantly changing its appearance.
+
+# Spirit of brawn
+N:1049:Spirit
+G:G:U
+I:130:140d100:50:180:30
+W:145:3:10000:8000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:SHATTER:18d18
+B:HIT:CONFUSE:18d18
+B:HIT:SHATTER:18d18
+B:HIT:CONFUSE:18d18
+F:SPIRIT | BASEANGBAND | DROP_4D2 | KILL_BODY | KILL_WALL |
+F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | KILL_TREES |
+F:EVIL | GIANT | HURT_ROCK | BASEANGBAND | HAS_LITE |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+D:Strong and swarthy, this spirit could bend metal with his bare hands.
+
+# Spirit of Wyrms
+N:1050:Spirit
+G:G:v
+I:130:151d151:50:190:50
+W:147:8:10000:87500
+E:0:1:0:6:1:0
+O:50:50:0:0
+B:CLAW:HURT:10d15
+B:CLAW:HURT:10d15
+B:BITE:HURT:14d18
+B:BITE:HURT:14d18
+F:SPIRIT | FORCE_MAXHP | MOVE_BODY | AURA_FIRE | REFLECTING | AURA_ELEC |
+F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | AURA_COLD |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | RES_NETH | RES_DISE |
+F:DRAGON | GOOD | RES_TELE | DROP_CORPSE | KILL_TREES |
+F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP |
+F:RES_NEXU | RES_PLAS | CAN_FLY | BASEANGBAND | HAS_LITE | NO_CUT
+S:1_IN_3 |
+S:S_HI_DRAGON | S_DRAGON | S_KIN |
+S:BR_NUKE | BR_ACID | BR_ELEC | BR_FIRE |
+S:BR_COLD | BR_POIS | BR_NETH | BR_LITE | BR_DARK |
+S:BR_CONF | BR_SOUN | BR_CHAO | BR_DISE | BR_NEXU |
+S:BR_TIME | BR_INER | BR_GRAV | BR_SHAR | BR_PLAS |
+S:BR_WALL | BR_MANA | BR_DISI
+D:This spirit bears a remarkable similarity to some of the most powerful
+D:types of dragonkind found in Middle-earth. It appears to be even more
+D:fearsome, though!
+
+# Spirit of snakes
+N:1051:Spirit
+G:G:g
+I:130:150d100:40:80:20
+W:133:3:90:750
+E:1:1:1:2:1:1
+O:25:20:25:20
+B:BITE:POISON:15d15
+B:BITE:POISON:15d15
+B:BITE:LOSE_ALL:10d12
+F:SPIRIT | CAN_SWIM | IM_POIS | IM_ACID |
+F:DROP_60 | DROP_2D2 | FRIENDS | DROP_CORPSE |
+F:OPEN_DOOR | BASH_DOOR | EVIL | BASEANGBAND
+S:1_IN_4 |
+S:BA_POIS | S_MONSTER | SCARE | HOLD
+D:It slides towards you, a horrible scaly, slidy thing.
+
+# Spirit of seeing
+N:1052:Spirit
+G:G:v
+I:130:95d110:60:130:10
+W:141:3:60:50000
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:GAZE:UN_BONUS:12d12
+B:GAZE:UN_POWER:12d10
+B:GAZE:INSANITY:12d14
+B:GAZE:LOSE_ALL:6d6
+F:SPIRIT | BASH_DOOR | EVIL | IM_POIS |
+F:CAN_FLY | BASEANGBAND
+S:1_IN_2 |
+S:BLIND | CONF | FORGET | SCARE | DRAIN_MANA | BRAIN_SMASH |
+S:BA_DARK | BO_MANA | BA_NETH | BA_ACID | BA_FIRE | BA_COLD
+D:You will find it difficult to avoid being seen by this spirit! And
+D:once it has you in its sight, beware!
+
+# Spirit of unseeing
+N:1053:Spirit
+G:.:W
+I:120:55d50:20:130:80
+W:142:6:60:4000
+E:0:0:0:0:0:0
+O:10:0:90:0
+B:TOUCH:UN_BONUS:12d12
+B:TOUCH:UN_POWER:12d10
+B:TOUCH:INSANITY:12d14
+B:TOUCH:LOSE_ALL:6d6
+F:SPIRIT | CAN_FLY | REFLECTING |
+F:SMART | BASH_DOOR | COLD_BLOOD | INVISIBLE | EMPTY_MIND |
+F:EVIL | BASEANGBAND | CHAR_MULTI | CHAR_CLEAR | ATTR_CLEAR
+S:1_IN_3 |
+S:DRAIN_MANA | BLINK | BLIND | SCARE | CONF |
+S:HEAL | TELE_AWAY | DARKNESS | TRAPS | FORGET | SHRIEK
+D:Hopefully you will kill this spirit before you realise it exists.
+
+# Spirit of ickyness
+N:1054:Spirit
+G:G:g
+I:130:80d80:30:60:10
+W:138:4:300:40000
+E:0:0:0:0:0:0
+O:40:30:10:10
+B:CRAWL:POISON:12d14
+B:CRAWL:EAT_FOOD:12d14
+B:TOUCH:ACID:13d15
+B:HIT:HURT:13d15
+F:SPIRIT | BASEANGBAND |
+F:EMPTY_MIND | OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_ELEC | IM_FIRE | IM_COLD | IM_POIS |
+F:EMPTY_MIND
+S:1_IN_4 |
+S:DRAIN_MANA | BLIND | CONF | SCARE | S_KIN
+D:A horrible slimy spirit, that seems to ooze evilness. I wouldn't get
+D:too close to it if I were you.
+
+# Spirit of friendship
+N:1055:Spirit
+G:G:W
+I:130:35d100:40:150:100
+W:136:3:200:10000
+E:0:1:0:2:1:0
+O:50:50:0:0
+B:BITE:HURT:12d12
+B:BITE:HURT:12d12
+B:BITE:HURT:12d8
+B:BITE:HURT:12d8
+F:SPIRIT | BASEANGBAND |
+F:ESCORT | ESCORTS |
+F:OPEN_DOOR | BASH_DOOR
+S:1_IN_2 |
+S:S_KIN
+D:This spirit appears to have lots of friends!
+
+# Spirit of abomination
+N:1056:Spirit
+G:G:d
+I:130:40d80:30:125:125
+W:134:2:200:5000
+E:0:0:0:0:0:0
+O:50:0:50:0
+B:WAIL:TERRIFY:8d9
+B:HIT:HURT:10d10
+B:HIT:ABOMINATION:6d10
+B:HIT:ABOMINATION:6d10
+F:SPIRIT | BASEANGBAND |
+F:EVIL | UNDEAD | IM_POIS | IM_COLD | NO_CONF | NO_SLEEP |
+F:COLD_BLOOD | HURT_LITE | NO_CUT
+S:1_IN_3 |
+S:SCARE | HOLD | DARKNESS | SCARE
+D:It seems to have been woken from the dead, this spirit. It lumbers
+D:towards you, seeking to turn you into a form as hideous as its own!
+
+### Here come the spirits of <player stat> ###
+#
+# Spirit of strength
+N:1057:Spirit
+G:G:u
+I:120:140d100:50:180:170
+W:129:2:10000:8000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:LOSE_STR:4d8
+B:HIT:LOSE_STR:4d8
+B:HIT:LOSE_STR:4d8
+F:SPIRIT | BASEANGBAND | DROP_2D2 | KILL_BODY | KILL_WALL |
+F:BASH_DOOR | EVIL | GIANT | HURT_ROCK |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+D:It is coming for you, this massive imposing tower of strength.
+D:It appears almost unstoppable!
+
+# Spirit of intelligence
+N:1058:Spirit
+G:G:r
+I:140:80d100:50:100:10
+W:131:2:10000:8000
+E:1:1:1:2:1:1
+O:0:0:100:0
+B:HIT:LOSE_INT:4d8
+B:HIT:LOSE_INT:4d8
+B:HIT:LOSE_INT:4d8
+F:EVIL | SPIRIT | BASEANGBAND | DROP_2D2 |
+F:OPEN_DOOR | SMART |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+S:1_IN_2 |
+S:HASTE | TPORT | TELE_TO | BLIND | CONF |
+S:BO_MANA | BO_FIRE | BO_COLD | BO_ELEC |
+D:This spirit looks very clever, cunning almost.
+
+# Spirit of wisdom
+N:1059:Spirit
+G:G:G
+I:130:120d100:50:200:130
+W:137:2:10000:8000
+E:1:1:1:2:1:1
+O:0:50:50:0
+B:HIT:LOSE_WIS:4d8
+B:HIT:LOSE_WIS:4d8
+B:HIT:LOSE_WIS:4d8
+F:EVIL | SPIRIT | BASEANGBAND | DROP_2D2 |
+F:OPEN_DOOR |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+S:1_IN_2 |
+S:HEAL | MIND_BLAST | CAUSE_4 | SCARE |
+S:DRAIN_MANA | BRAIN_SMASH | FORGET |
+D:This spirit has something of a priestly look about it.
+
+# Spirit of dexterity
+N:1060:Spirit
+G:G:W
+I:160:120d100:50:160:50
+W:139:2:10000:8000
+E:1:1:1:2:1:1
+O:0:50:25:25
+B:HIT:LOSE_DEX:4d8
+B:HIT:LOSE_DEX:4d8
+B:HIT:LOSE_DEX:4d8
+F:EVIL | SPIRIT | BASEANGBAND | DROP_2D2 |
+F:OPEN_DOOR | SMART |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+S:1_IN_1 |
+S:ARROW_4
+D:This spirit moves almost too quickly for you to see him.
+
+# Spirit of constitution
+N:1061:Spirit
+G:G:s
+I:120:140d100:50:180:50
+W:143:2:10000:8000
+E:1:1:1:2:1:1
+O:0:50:0:50
+B:HIT:LOSE_CON:4d8
+B:HIT:LOSE_CON:4d8
+B:HIT:LOSE_CON:4d8
+F:EVIL | SPIRIT | BASEANGBAND | DROP_2D2 | BASH_DOOR |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+D:This spirit moves slower than most, but thunders on and on
+D:towards you.
+
+# Spirit of charisma
+N:1062:Spirit
+G:G:b
+I:140:80d100:50:120:90
+W:146:2:10000:8000
+E:1:1:1:2:1:1
+O:70:10:10:10
+B:HIT:LOSE_CHR:4d8
+B:HIT:LOSE_CHR:4d8
+B:HIT:LOSE_CHR:4d8
+F:SPIRIT | BASEANGBAND | DROP_2D2 |
+F:OPEN_DOOR | EVIL | TAKE_ITEM |
+F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS
+S:1_IN_2 |
+S:TRAPS | ARROW_3 | BLINK | TELE_TO | CONF
+D:There is something attractive about this spirit, and it seems
+D:to have a full purse.
+
+### Here come some elemental spirits ###
+#
+# Spirit of flickering fire
+N:1063:Spirit
+G:G:r
+I:120:60d100:50:65:80
+W:130:1:5:6000
+E:1:1:1:2:1:1
+O:25:60:0:15
+B:HIT:FIRE:10d8
+B:HIT:FIRE:10d8
+B:HIT:FIRE:10d8
+F:SPIRIT | BASEANGBAND | AI_ANNOY | IM_FIRE | AURA_FIRE | HAS_LITE
+S:1_IN_2 |
+S:BO_FIRE | BA_FIRE
+D:Flickering towards you, and then away, this spirit will burn you badly!
+
+# Spirit of icy cold
+N:1064:Spirit
+G:G:w
+I:120:60d100:50:65:80
+W:148:1:5:6000
+E:1:1:1:2:1:1
+O:25:60:0:15
+B:HIT:COLD:10d8
+B:HIT:COLD:10d8
+B:HIT:COLD:10d8
+F:SPIRIT | BASEANGBAND | IM_COLD | AURA_COLD |
+F:COLD_BLOOD | BASH_DOOR
+S:1_IN_2 |
+S:BO_COLD | BA_COLD
+D:The temperature around you drops as soon as you set eyes on this spirit.
+
+# Spirit of corrosion (acid)
+N:1065:Spirit
+G:G:s
+I:120:60d100:50:65:80
+W:146:1:5:6000
+E:1:1:1:2:1:1
+O:25:60:0:15
+B:HIT:ACID:10d8
+B:HIT:ACID:10d8
+B:HIT:ACID:10d8
+F:SPIRIT | BASEANGBAND | IM_ACID | BASH_DOOR | KILL_TREES
+S:1_IN_2 |
+S:BO_ACID | BA_ACID
+D:The very fabric of the void heals itself where this spirit walks.
+
+# Spirit of shocking (electricity)
+N:1066:Spirit
+G:G:b
+I:120:60d100:50:65:80
+W:149:1:5:6000
+E:1:1:1:2:1:1
+O:25:60:0:15
+B:HIT:ELEC:10d8
+B:HIT:ELEC:10d8
+B:HIT:ELEC:10d8
+F:SPIRIT | BASEANGBAND | IM_ELEC | AURA_ELEC | BASH_DOOR
+S:1_IN_2 |
+S:BO_ELEC | BA_ELEC
+D:The air crackles as this spirit approaches, and you smell singed flesh.
+
+# Spirit of Valaraukar (Balrogs)
+N:1067:Spirit
+G:G:v
+I:130:130d100:100:140:10
+W:149:1:170:43000
+E:1:1:1:2:1:1
+O:0:100:0:0
+B:HIT:FIRE:11d12
+B:HIT:FIRE:11d12
+B:CRUSH:HURT:10d12
+B:TOUCH:UN_POWER
+F:SPIRIT | CAN_FLY | KILL_WALL | AURA_FIRE | NONLIVING |
+F:ONLY_ITEM | DROP_2D2 | EVIL | DEMON |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
+F:IM_FIRE | IM_ELEC | BASEANGBAND | HAS_LITE
+S:1_IN_3 |
+S:BLIND | CONF | SCARE | BR_FIRE
+D:Carrying a whip of fire, this spirit looks not dissimilar to a certain
+D:Balrog.
+
+# Spirit of shadows
+N:1068:Spirit
+G:G:d
+I:130:30d100:70:150:4
+W:140:4:2300:10000
+E:1:1:1:2:1:1
+O:20:80:0:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:TOUCH:EXP_80:20d8
+B:TOUCH:EXP_40:20d8
+F:SPIRIT | BASEANGBAND | REFLECTING | REGENERATE |
+F:IM_ACID | IM_ELEC | IM_COLD | IM_FIRE | IM_POIS | RES_TELE |
+F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | SMART | POWERFUL
+S:1_IN_3 |
+S:BLIND | HEAL | BA_DARK | HASTE | CONF
+D:Deriving his strength from the shadows, this spirit
+D:steals only for the challenge.
+
+# Spirit of vampire or something
+N:1069:Spirit
+G:G:W
+I:130:50d50:30:90:10
+W:143:2:1700:18000
+E:1:1:1:2:1:1
+O:0:70:30:0
+B:HIT:HURT:10d9
+B:HIT:HURT:9d9
+B:BITE:EXP_80:9d9
+B:BITE:EXP_80:9d9
+F:SPIRIT | FORCE_SLEEP | CAN_FLY |
+F:DROP_60 | DROP_4D2 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | RES_TELE |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT | SPIRIT
+S:1_IN_3 |
+S:BLIND | HOLD | SCARE | CAUSE_3 | CAUSE_4 | DRAIN_MANA |
+S:BRAIN_SMASH | DARKNESS | BO_NETH
+D:Your blood curdles and your bones chill as this spirit approaches.
+
+# Spirit of unresistability (hehehehe)
+N:1070:Spirit
+G:G:v
+I:140:40d100:40:70:20
+W:149:4:1200:20000
+E:1:1:1:2:1:1:
+O:0:0:0:100
+B:HIT:SHATTER:18d10
+B:HIT:SHATTER:18d10
+B:HIT:LOSE_ALL:8d8
+B:TOUCH:UN_POWER
+F:BASEANGBAND | SPIRIT | SMART |
+F:OPEN_DOOR | BASH_DOOR | POWERFUL |
+F:RES_NEXU | RES_NETH |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:IM_POIS | IM_ELEC | IM_ACID | IM_COLD |
+S:1_IN_2 |
+S:BA_MANA | BR_PLAS | BR_TIME | ROCKET | HAND_DOOM | FORGET | BA_WATE
+D:This spirit appears to be afraid of very little, and confident in its
+D:ability to destroy you.
+
+# Spirit of time
+N:1071:Spirit
+G:G:G
+I:130:80d100:40:110:0
+W:150:3:800:50000
+E:0:1:0:2:1:0
+O:0:0:0:0
+B:TOUCH:TIME:6d12
+B:TOUCH:TIME:6d12
+B:TOUCH:TIME:6d12
+B:TOUCH:TIME:6d12
+F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
+F:ANIMAL | NO_CONF | NO_SLEEP |
+F:SPIRIT | BASEANGBAND
+S:1_IN_2 |
+S:BR_TIME | SLOW | HASTE | HOLD
+D:All at once you see that which is to come and that which has gone before.
+
+# Spirit of Gold
+N:1072:Spirit
+G:G:y
+I:130:50d80:20:110:100
+W:130:4:80:8000
+E:0:1:0:2:1:0
+O:100:0:0:0
+B:TOUCH:EAT_GOLD:7d15
+B:TOUCH:EAT_GOLD:7d15
+B:HIT:POISON:6d12
+B:HIT:POISON:6d12
+F:ONLY_GOLD | SPIRIT | BASEANGBAND |
+F:DROP_4D2 | DROP_4D2 | DROP_4D2 | REFLECTING | COLD_BLOOD | REGENERATE |
+F:BASH_DOOR | MOVE_BODY | IM_ELEC | IM_COLD | IM_POIS |
+F:RES_TELE | NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP
+S:1_IN_4 |
+S:ARROW_4 | HEAL | FORGET
+D:It is the very essence of financial greed...
+
+# Spirit of doom
+N:1073:Spirit
+G:G:D
+I:136:60d70:40:70:30
+W:134:2:60:8000
+E:1:1:1:2:1:1
+O:0:10:90:0
+B:HIT:HURT:14d14
+B:HIT:HURT:14d14
+B:HIT:HURT:14d14
+F:SMART | OPEN_DOOR | BASH_DOOR |
+F:EVIL | NO_CONF | NO_SLEEP |
+F:SPIRIT | BASEANGBAND | HAS_LITE
+S:1_IN_2 |
+S:HAND_DOOM | CAUSE_4 | DARKNESS
+D:The very presence of this creature fills the air with an aura of doom.
+D:You feel waves of depression descending on you as it approaches.
+
+# Spirit of etherealism (?)
+N:1074:Spirit
+G:G:o
+I:120:40d100:30:120:40
+W:141:3:1700:10000
+E:0:1:0:6:1:0
+B:CLAW:HURT:14d10
+B:CLAW:HURT:14d10
+B:BITE:HURT:17d10
+F:INVISIBLE | CAN_FLY | SPIRIT | WEIRD_MIND |
+F:PASS_WALL | POWERFUL | MOVE_BODY |
+F:EVIL | NO_CONF | NO_SLEEP | BASEANGBAND | SPIRIT
+S:1_IN_2 |
+S:BLIND | CONF |
+S:BR_LITE | BR_DARK | BR_CONF
+D:This sprit seems to flicker in and out of this plane, and is a master
+D:of light and dark.
+
+# Spirit of orc (boring huh)
+N:1075:Spirit
+G:G:v
+I:120:90d10:30:160:100
+W:142:3:2700:11111
+E:1:1:1:2:1:1
+O:10:90:0:0
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+B:HIT:HURT:10d10
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | ORC | IM_POIS | ONLY_ITEM |
+F:MORTAL | BASEANGBAND | HAS_LITE | SPIRIT
+D:Stupid but strong, this spirit has an orcish aura about him.
+
+### Here endeth the Spirits ###
+
+N:1076:Neil, the Sorceror
+G:h:v
+# *Not* enough hitpoints
+I:110:50d100:20:30:30
+# Bottom of Erebor
+W:72:100:330:50000
+E:1:1:1:2:1:1
+O:0:5:90:5
+# Sorceror, not warrior
+B:HIT:HURT:1d1
+B:HIT:HURT:1d1
+F:OPEN_DOOR | SMART | MALE | DROP_SKELETON | DROP_CORPSE
+F:MORTAL | HAS_LITE | JOKEANGBAND | UNIQUE
+# Trone, of course
+F:CAN_FLY | REFLECTING | IM_FIRE
+# Thorin
+F:IM_ACID | FORCE_MAXHP
+# No cold or random gen... waiting on elven rings only at bottom of Erebor
+F:SPECIAL_GENE
+# Dig
+F:KILL_WALL
+# Obvious resistances
+F:NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR
+# Well, he's been there a while
+F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | DROP_GREAT
+# Essence of speed, Manathrust, Noxious Cloud, and Fireflash
+S:1_IN_1 |
+S:HASTE | BO_MANA | BA_POIS | BA_FIRE
+D:He looks like he is looking for something, and the flecks of dragon
+D:blood on his face tell you he means business!
+
+### Theme monsters, cont. ###
+
+N:1077:Swamp wight
+G:W:o
+I:110:25d10:20:40:10
+W:45:3:0:400
+E:0:0:0:0:0:0
+O:0:50:50:0
+B:HIT:HURT:1d8
+B:HIT:POISON:1d8
+B:TOUCH:EXP_40
+F:FORCE_SLEEP | FRIENDS | DROP_60 |
+F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | CAN_FLY |
+F:EVIL | UNDEAD | IM_COLD | IM_POIS | HURT_LITE |
+F:NO_CONF | NO_SLEEP | BASEANGBAND | NO_CUT
+S:1_IN_8 |
+S:HOLD | SCARE | CAUSE_3 | DARKNESS
+D:An evil spirit from the marshlands, related to the mewlips.
+
+N:1078:Knight of the Swan
+# Basically a high-elven ranger with more melee and no distance attacks.
+G:p:w
+I:120:50d30:20:70:0
+W:40:3:1400:500
+E:1:1:1:2:1:1
+O:0:0:0:0
+B:HIT:HURT:10d8
+B:HIT:HURT:10d8
+B:HIT:HURT:10d8
+B:HIT:HURT:10d8
+F:MALE | FRIENDS | OPEN_DOOR | BASH_DOOR |
+F:GOOD | DROP_SKELETON | DROP_CORPSE | SMART | PET |
+F:IM_ACID | IM_COLD | RES_WATE | RES_NETH |
+F:MORTAL | BASEANGBAND | HAS_LITE
+D:A stately man dressed in armour emblazoned with a picture of a beautiful
+D:white swan, from Dol Amroth of old.
+
+# Infernal Device -- created for the Orthanc special level in Isengard by Burb Lulls
+# Heavily tweaked by furiosity for the Theme module
+N:1079:Infernal Device
+G:*:R
+I:110:75d20:20:80:50
+W:38:3:7000:1500
+E:0:0:0:0:0:0
+O:0:0:0:0
+B:EXPLODE:HURT:20d20
+B:EXPLODE:HURT:20d20
+B:EXPLODE:HURT:20d20
+B:EXPLODE:HURT:20d20
+F:FORCE_MAXHP | NEVER_MOVE | IM_FIRE | IM_POIS | BASEANGBAND
+F:NO_FEAR | NO_STUN | NO_CUT | NO_SLEEP | NO_CONF | RES_TELE
+F:RES_NETH | AURA_FIRE | STUPID | EMPTY_MIND | NONLIVING
+F:SPECIAL_GENE | FORCE_DEPTH | SUSCEP_COLD
+D:An ensorcelled machine of Saruman's creation, this gnarled
+D:totem of blackened steel defends Orthanc from intruders. \ No newline at end of file
diff --git a/lib/mods/theme/edit/ra_info.txt b/lib/mods/theme/edit/ra_info.txt
new file mode 100644
index 00000000..705db243
--- /dev/null
+++ b/lib/mods/theme/edit/ra_info.txt
@@ -0,0 +1,1985 @@
+# File: ra_info.txt
+
+
+# This file is used to initialize the "lib/raw/ra_info.raw" file, which is
+# used to initialize the "randart parts" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/ra_info.raw" file.
+
+# N:index
+# X:power value:max number of time it can appear on one object
+# T:tval:min sval:max sval (up to 20 T: lines)
+# W:mininum player level to create it:rarity1:rarity2
+# C:max to dam:max to hit:max to AC:max to pval
+# F:flags
+
+# Version stamp (required)
+
+V:2.0.0
+
+# General info, number of powers
+G:100:1d5:1
+G:14:0d0:1
+G:10:0d0:1
+G:3:0d0:1
+
+### Mage Staff randarts ###
+
+N:1
+X:10:1
+T:6:0:255
+W:5:1:4
+C:-5:-5:0:5
+F:MANA
+
+N:2
+X:14:1
+T:6:0:255
+W:10:1:8
+C:-10:-10:0:5
+F:SPELL
+
+N:3
+X:5:1
+T:6:0:255
+W:1:1:4
+C:-3:-3:0:5
+F:INT
+
+### Weapons ###
+
+# + To damage
+N:4
+X:5:2
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:19:0:255
+T:22:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:2
+C:10:0:0:0
+
+# + To Damage for swords
+N:5
+X:5:2
+T:23:0:255
+T:115:55:55
+W:1:1:2
+C:9:0:0:0
+
+# + To damage for hafted weapons
+N:6
+X:5:2
+T:21:0:255
+W:1:1:2
+C:11:0:0:0
+
+# + To hit
+N:7
+X:5:2
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:19:0:255
+T:22:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:2
+C:0:10:0:0
+
+# + To Hit for swords
+N:8
+X:5:2
+T:23:0:255
+T:115:55:55
+W:1:1:2
+C:0:11:0:0
+
+# + To Hit for hafted weapons
+N:9
+X:5:2
+T:21:0:255
+W:1:1:2
+C:0:9:0:0
+
+N:10
+X:15:1
+T:24:0:255
+T:115:55:55
+W:15:1:25
+C:4:0:0:0
+F:VORPAL
+
+N:11
+X:15:1
+T:23:2:2
+T:23:9:9
+T:23:11:33
+T:115:55:55
+W:15:1:25
+C:2:2:0:0
+F:VORPAL
+
+N:12
+X:15:1
+T:22:30:30
+W:10:1:16
+C:6:-2:0:0
+F:VORPAL
+
+N:13
+X:15:1
+T:22:17:17
+T:22:3:3
+T:22:0:15
+W:15:1:25
+C:4:0:0:0
+F:VORPAL
+
+N:14
+X:10:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+T:115:55:55
+W:4:1:10
+C:5:2:0:0
+F:BRAND_POIS
+
+N:15
+X:10:1
+T:23:0:255
+T:115:55:55
+W:4:1:10
+C:4:3:0:0
+F:BRAND_POIS
+
+N:16
+X:10:1
+T:21:0:255
+W:4:1:10
+C:5:2:0:0
+F:BRAND_POIS
+
+N:17
+X:11:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:5:1:11
+C:3:1:0:0
+F:BRAND_FIRE
+A:BRAND_COLD
+
+N:18
+X:11:1
+T:23:0:255
+T:115:55:55
+W:5:1:11
+C:2:2:0:0
+F:BRAND_FIRE
+A:BRAND_COLD
+
+N:19
+X:11:1
+T:21:0:255
+W:5:1:11
+C:4:0:0:0
+F:BRAND_FIRE
+A:BRAND_COLD
+
+N:20
+X:12:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:5:1:11
+C:5:1:0:0
+F:BRAND_COLD
+A:BRAND_FIRE
+
+N:21
+X:12:1
+T:23:0:255
+T:115:55:55
+W:5:1:11
+C:4:2:0:0
+F:BRAND_COLD
+A:BRAND_FIRE
+
+N:22
+X:12:1
+T:21:0:255
+W:5:1:11
+C:6:0:0:0
+F:BRAND_COLD
+A:BRAND_FIRE
+
+N:23
+X:13:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:5:1:13
+C:4:0:0:0
+F:BRAND_ELEC
+
+N:24
+X:13:1
+T:23:0:255
+T:115:55:55
+W:5:1:13
+C:3:1:0:0
+F:BRAND_ELEC
+
+N:25
+X:13:1
+T:21:0:255
+W:5:1:13
+C:5:-1:0:0
+F:BRAND_ELEC
+
+N:26
+X:15:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:7:1:15
+C:3:0:0:0
+F:BRAND_ACID
+
+N:27
+X:15:1
+T:23:0:255
+T:115:55:55
+W:7:1:15
+C:2:1:0:0
+F:BRAND_ACID
+
+N:28
+X:15:1
+T:21:0:255
+W:7:1:15
+C:4:0:0:0
+F:BRAND_ACID
+
+N:29
+X:5:1
+T:21:0:255
+W:15:1:35
+C:15:2:0:0
+F:IMPACT
+
+N:30
+X:5:1
+T:18:0:255
+T:19:0:255
+T:22:0:255
+T:24:0:255
+W:2:1:9
+C:2:2:0:6
+F:STR
+
+N:31
+X:5:1
+T:23:0:255
+T:115:55:55
+W:2:1:9
+C:0:4:0:6
+F:STR
+
+N:32
+X:5:1
+T:21:0:255
+W:1:1:7
+C:4:0:0:6
+F:STR
+
+N:33
+X:3:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:1:1:6
+C:0:0:0:6
+F:CHR
+
+N:34
+X:3:1
+T:23:0:255
+T:115:55:55
+W:2:1:6
+C:-1:1:0:6
+F:CHR
+
+N:35
+X:2:1
+T:21:0:255
+W:2:1:6
+C:1:-1:0:5
+F:CHR
+
+N:36
+X:4:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:2:1:8
+C:0:0:0:4
+F:INT
+
+N:37
+X:4:1
+T:21:0:255
+W:2:1:8
+C:1:-1:0:4
+F:INT
+
+N:38
+X:4:1
+T:23:0:255
+T:115:55:55
+W:2:1:8
+C:-1:1:0:4
+F:INT
+
+N:39
+X:6:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:3:1:10
+C:0:0:0:6
+F:CON
+
+N:40
+X:6:1
+T:23:0:255
+T:115:55:55
+W:3:1:10
+C:-1:1:0:6
+F:CON
+
+N:41
+X:6:1
+T:21:0:255
+C:1:-1:0:6
+F:CON
+
+N:42
+X:4:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:2:1:8
+C:0:0:0:5
+F:WIS
+
+N:43
+X:4:1
+T:21:0:255
+W:2:1:9
+C:1:-1:0:6
+F:WIS
+
+N:44
+X:4:1
+T:23:0:255
+T:115:55:55
+W:2:1:9
+C:-1:1:0:5
+F:WIS
+
+N:45
+X:4:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:22:0:255
+T:24:0:255
+W:2:1:7
+C:0:0:0:5
+F:DEX
+
+N:46
+X:4:1
+T:23:0:255
+T:115:55:55
+W:2:1:7
+C:-1:1:0:6
+F:DEX
+
+N:47
+X:4:1
+T:21:0:255
+W:2:1:7
+C:1:-1:0:5
+F:DEX
+
+N:48
+X:4:1
+T:21:0:255
+W:9:1:14
+C:3:0:0:6
+F:TUNNEL
+
+N:49
+X:40:1
+T:22:0:255
+T:24:0:255
+W:30:1:100
+C:0:-4:0:3
+F:BLOWS
+
+N:50
+X:40:1
+T:23:0:255
+T:115:55:55
+W:30:1:100
+C:-1:-3:0:3
+F:BLOWS
+
+N:51
+X:40:1
+T:21:0:255
+W:30:1:100
+C:1:-5:0:3
+F:BLOWS
+
+N:52
+X:50:1
+T:18:0:255
+T:19:0:255
+T:22:0:255
+T:24:0:255
+W:40:1:90
+C:-2:-2:0:5
+F:SPEED
+
+N:53
+X:50:1
+T:21:0:255
+W:40:1:90
+C:-1:-3:0:5
+F:SPEED
+
+N:54
+X:50:1
+T:23:0:255
+T:115:55:55
+W:40:1:90
+C:-3:-1:0:5
+F:SPEED
+
+N:55
+X:12:1
+T:18:0:255
+T:22:0:255
+T:21:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:11:1:20
+C:10:10:0:0
+F:CHAOTIC
+
+N:56
+X:8:1
+T:18:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:11:1:20
+C:-10:-10:0:0
+F:CHAOTIC
+
+N:57
+X:12:1
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:15:1:20
+C:4:0:0:4
+F:VAMPIRIC
+
+N:58
+X:12:1
+T:21:0:255
+W:15:1:20
+C:5:-1:0:0
+F:VAMPIRIC
+
+N:59
+X:12:1
+T:23:0:19
+T:115:55:55
+W:15:1:20
+C:3:1:0:4
+F:VAMPIRIC
+
+N:60
+X:11:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:10:1:10
+C:0:0:0:0
+F:SLAY_ANIMAL
+
+N:61
+X:11:1
+T:21:0:255
+W:10:1:10
+C:1:-1:0:0
+F:SLAY_ANIMAL
+
+N:62
+X:11:1
+T:23:0:255
+T:115:55:55
+W:10:1:10
+C:-1:1:0:0
+F:SLAY_ANIMAL
+
+N:63
+X:19:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:15:1:17
+C:0:0:0:0
+F:SLAY_EVIL
+
+N:64
+X:19:1
+T:21:0:255
+W:15:1:15
+C:1:-1:0:0
+F:SLAY_EVIL
+
+N:65
+X:19:1
+T:23:0:255
+T:115:55:55
+W:15:1:17
+C:-1:1:0:0
+F:SLAY_EVIL
+
+N:66
+X:15:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:13:1:15
+C:0:0:0:0
+F:SLAY_UNDEAD
+A:KILL_UNDEAD
+
+N:67
+X:15:1
+T:21:0:255
+W:13:1:15
+C:1:-1:0:0
+F:SLAY_UNDEAD
+A:KILL_UNDEAD
+
+N:68
+X:15:1
+T:23:0:255
+T:115:55:55
+W:13:1:15
+C:-1:1:0:0
+F:SLAY_UNDEAD
+A:KILL_UNDEAD
+
+N:69
+X:5:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:11:1:25
+C:0:0:0:0
+F:SLAY_DEMON
+A:KILL_DEMON
+
+N:70
+X:5:1
+T:21:0:255
+W:11:1:25
+C:1:-1:0:0
+F:SLAY_DEMON
+A:KILL_DEMON
+
+N:71
+X:5:1
+T:23:0:255
+T:115:55:55
+W:11:1:25
+C:-1:1:0:0
+F:SLAY_DEMON
+A:KILL_DEMON
+
+N:72
+X:10:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:3:1:10
+C:0:0:0:0
+F:SLAY_ORC
+
+N:73
+X:10:1
+T:21:0:255
+W:3:1:10
+C:1:-1:0:0
+F:SLAY_ORC
+
+N:74
+X:10:1
+T:23:0:255
+T:115:55:55
+W:3:1:10
+C:-1:1:0:0
+F:SLAY_ORC
+
+N:75
+X:11:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:15:2:17
+C:0:0:0:0
+F:SLAY_TROLL
+
+N:76
+X:11:1
+T:21:0:255
+W:15:2:17
+C:1:-1:0:0
+F:SLAY_TROLL
+
+N:77
+X:11:1
+T:23:0:255
+T:115:55:55
+W:15:2:17
+C:-1:1:0:0
+F:SLAY_TROLL
+
+N:78
+X:10:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:20:1:20
+C:0:0:0:0
+F:SLAY_GIANT
+
+N:79
+X:10:1
+T:21:0:255
+W:20:1:20
+C:-1:1:0:0
+F:SLAY_GIANT
+
+N:80
+X:10:1
+T:23:0:255
+T:115:55:55
+W:20:1:20
+C:0:0:0:0
+F:SLAY_GIANT
+
+N:81
+X:20:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:17:1:20
+C:0:0:0:0
+F:SLAY_DRAGON
+A:KILL_DRAGON
+
+N:82
+X:20:1
+T:21:0:255
+W:17:1:20
+C:1:-1:0:0
+F:SLAY_DRAGON
+A:KILL_DRAGON
+
+N:83
+X:20:1
+T:23:0:255
+T:115:55:55
+C:-1:1:0:0
+W:17:1:20
+F:SLAY_DRAGON
+A:KILL_DRAGON
+
+N:84
+X:31:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:17:1:35
+C:0:0:0:0
+F:KILL_DRAGON
+A:SLAY_DRAGON
+
+N:85
+X:31:1
+T:21:0:255
+W:17:1:35
+C:1:-1:0:0
+F:KILL_DRAGON
+A:SLAY_DRAGON
+
+N:86
+X:31:1
+T:23:0:255
+T:115:55:55
+W:17:1:35
+C:-1:1:0:0
+F:KILL_DRAGON
+A:SLAY_DRAGON
+
+N:87
+X:15:1
+T:18:0:255
+T:22:0:255
+T:24:0:255
+W:5:1:10
+C:-2:-2:0:0
+F:BLESSED
+A:CURSED
+
+N:88
+X:15:1
+T:21:0:255
+W:5:1:7
+C:-1:-3:0:0
+F:BLESSED
+A:CURSED
+
+N:89
+X:15:1
+T:23:0:255
+T:115:55:55
+W:5:1:10
+C:-3:-1:0:0
+F:BLESSED
+A:CURSED
+
+N:90
+X:-5:1
+T:15:0:255
+T:16:0:255
+T:18:0:255
+T:19:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:20
+C:0:0:0:0
+F:CURSED
+A:BLESSED
+
+N:93
+X:-10:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:20
+C:0:0:0:0
+F:AGGRAVATE
+A:STEALTH
+
+N:94
+X:13:1
+T:18:0:255
+T:19:0:255
+T:20:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:1:1:15
+C:0:0:0:0
+F:LITE1
+A:RES_LITE
+
+N:95
+X:40:1
+T:19:0:255
+W:20:1:38
+C:0:0:0:3
+F:XTRA_MIGHT
+
+N:96
+X:40:1
+T:19:0:255
+W:20:1:38
+C:0:0:0:0
+F:XTRA_SHOTS
+
+N:97
+X:25:1
+T:23:0:255
+T:24:0:255
+T:22:17:17
+T:22:3:3
+T:22:0:15
+T:115:55:55
+W:14:1:23
+C:3:0:0:0
+F:WOUNDING
+
+N:98
+X:60:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:27:1:50
+C:0:0:0:0
+F:KILL_UNDEAD
+A:SLAY_UNDEAD
+
+N:99
+X:45:1
+T:15:0:255
+T:16:0:255
+T:17:0:255
+T:18:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:25:1:34
+C:0:0:0:0
+F:KILL_DEMON
+A:SLAY_DEMON
+
+N:100
+X:20:1
+T:18:0:255
+T:21:0:255
+T:22:0:255
+T:23:0:255
+T:24:0:255
+T:115:55:55
+W:15:1:25
+C:2:0:0:0
+Z:BERSERK
+
+N:101
+X:15:1
+T:20:0:255
+T:21:0:255
+W:20:1:35
+C:0:0:0:0
+Z:EARTHQUAKE
+
+N:102
+X:5:1
+T:20:0:255
+W:2:1:9
+C:0:0:0:6
+F:STR
+
+
+### Armor ###
+
+N:295
+X:60:1
+T:36:0:255
+T:37:0:255
+W:20:1:90
+C:-70:-70:0:2
+F:LIFE
+
+N:296
+X:7:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:1:1:14
+C:0:0:0:0
+F:SUST_STR
+
+N:297
+X:6:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:6:0:255
+W:1:1:12
+C:0:0:0:0
+F:SUST_INT
+
+N:298
+X:6:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:6:0:255
+W:1:1:12
+C:0:0:0:0
+F:SUST_WIS
+
+N:299
+X:5:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:1:1:11
+C:0:0:1:0
+F:SUST_DEX
+
+N:300
+X:9:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:1:1:16
+C:0:0:0:0
+F:SUST_CON
+
+N:301
+X:4:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:1:1:9
+C:0:0:0:0
+F:SUST_CHR
+
+N:302
+X:50:1
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:30:1:70
+C:0:0:0:0
+F:IM_ACID
+
+N:303
+X:50:1
+T:34:0:255
+T:115:56:56
+W:30:1:90
+C:0:0:0:0
+F:IM_ACID
+
+N:304
+X:50:1
+T:35:0:255
+W:30:1:80
+C:0:0:0:0
+F:IM_ACID
+
+N:305
+X:45:1
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:30:1:78
+F:IM_ELEC
+
+N:306
+X:45:1
+T:34:0:255
+T:115:56:56
+W:30:1:98
+C:0:0:0:0
+F:IM_ELEC
+
+N:307
+X:45:1
+T:35:0:255
+W:30:1:88
+C:0:0:0:0
+F:IM_ELEC
+
+N:308
+X:55:1
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:30:1:86
+C:0:0:0:0
+F:IM_FIRE
+
+N:309
+X:55:1
+T:34:0:255
+T:115:56:56
+T:35:0:255
+W:30:1:95
+C:0:0:0:0
+F:IM_FIRE
+
+N:310
+X:47:1
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:30:1:90
+C:0:0:0:0
+F:IM_COLD
+
+N:311
+X:47:1
+T:34:0:255
+T:115:56:56
+T:35:0:255
+W:30:1:90
+C:0:0:0:0
+F:IM_COLD
+
+N:312
+X:47:1
+T:35:3:3
+W:30:1:100
+C:0:0:0:0
+F:IM_COLD
+
+N:313
+X:35:1
+T:34:0:255
+T:38:0:255
+T:115:56:56
+W:20:1:45
+C:0:0:0:0
+F:REFLECT
+
+N:314
+X:35:1
+T:34:10:10
+T:115:56:56
+W:10:1:15
+C:0:0:0:0
+F:REFLECT
+
+N:315
+X:17:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+T:6:0:255
+W:5:1:7
+C:0:0:0:0
+F:FREE_ACT
+
+N:316
+X:23:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+W:8:1:14
+C:0:0:0:0
+F:HOLD_LIFE
+
+N:317
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:1:1:10
+C:0:0:0:0
+F:RES_ACID
+
+N:318
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:1:1:10
+C:0:0:0:0
+F:RES_FIRE
+
+N:319
+X:13:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:1:1:9
+C:0:0:0:0
+F:RES_ELEC
+
+N:320
+X:12:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:1:1:8
+C:0:0:0:0
+F:RES_COLD
+
+N:321
+X:20:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:5:1:18
+C:0:0:0:0
+F:RES_POIS
+
+N:322
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:6:1:15
+C:0:0:0:0
+F:RES_FEAR
+
+N:323
+X:10:1
+T:30:0:255
+T:31:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:56
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:5:1:10
+C:0:0:0:0
+F:RES_LITE
+
+N:324
+X:10:1
+T:32:0:255
+T:115:57:57
+W:1:1:7
+C:0:0:0:0
+F:RES_LITE
+
+N:325
+X:15:1
+T:32:0:255
+T:115:57:57
+W:5:1:15
+C:0:0:0:0
+F:LITE1
+A:RES_LITE
+
+N:326
+X:17:1
+T:32:0:255
+T:115:57:57
+W:10:1:20
+C:0:0:0:0
+F:LITE2
+A:RES_LITE
+
+N:327
+X:20:1
+T:32:0:255
+T:115:57:57
+W:15:1:25
+C:0:0:0:0
+F:LITE3
+A:RES_LITE
+
+N:328
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:10:1:15
+C:0:0:0:0
+F:RES_DARK
+
+N:329
+X:20:1
+T:115:57:57
+T:32:0:255
+T:40:0:255
+T:45:0:255
+T:6:0:255
+W:13:1:27
+C:0:0:0:0
+F:RES_BLIND
+
+N:330
+X:17:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:13:1:18
+C:0:0:0:0
+F:RES_SOUND
+
+N:331
+X:15:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:115:56:57
+T:34:0:255
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:17:1:15
+C:0:0:0:0
+F:RES_NEXUS
+
+N:332
+X:19:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:16:1:19
+C:0:0:0:0
+F:RES_SHARDS
+
+N:333
+X:30:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:30:1:50
+C:0:0:0:0
+F:RES_NETHER
+
+N:334
+X:25:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+W:25:1:30
+F:RES_CHAOS
+
+N:335
+X:20:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+T:6:0:255
+W:25:1:35
+C:0:0:0:0
+F:RES_CONF
+
+N:336
+X:25:1
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:40:0:255
+T:45:0:255
+C:0:0:0:0
+W:23:1:32
+F:RES_DISEN
+
+N:337
+X:20:1
+T:35:0:255
+W:10:1:17
+C:0:0:0:0
+F:SH_FIRE | RES_FIRE
+
+N:338
+X:22:1
+T:35:0:255
+W:10:1:20
+C:0:0:0:0
+F:SH_ELEC | RES_ELEC
+
+N:339
+X:18:1
+T:115:57:57
+T:32:0:255
+T:33:0:255
+T:40:0:255
+T:45:0:255
+T:6:0:255
+W:5:1:15
+C:0:0:0:0
+F:SEE_INVIS
+
+N:340
+X:14:1
+T:30:0:255
+T:40:0:255
+T:45:0:255
+W:5:1:13
+C:0:0:0:0
+F:FEATHER
+A:FLY
+
+N:341
+X:80:1
+T:35:0:255
+T:30:0:255
+T:6:0:255
+W:40:1:90
+C:0:0:0:0
+F:FLY
+A:FEATHER
+
+N:342
+X:30:1
+T:115:57:57
+T:32:0:255
+T:33:0:255
+W:20:1:30
+C:0:0:0:0
+Z:MIND BLAST
+
+N:343
+X:30:1
+T:115:57:57
+T:32:0:255
+T:33:0:255
+W:20:1:30
+C:0:0:0:0
+Z:TELEKINESIS
+
+N:344
+X:35:1
+T:31:0:255
+W:25:1:40
+C:0:0:0:0
+Z:MIDAS TOUCH
+
+N:345
+X:15:1
+T:31:0:255
+C:0:0:0:0
+Z:COLD TOUCH
+
+N:346
+X:30:1
+T:35:0:255
+W:20:1:27
+C:0:0:0:0
+Z:BLINK
+A:RES_NEXUS
+
+### + To AC ###
+N:347
+X:15:4
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:115:56:57
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:6:0:255
+W:1:1:5
+C:0:0:5:0
+
+### + To Dam (Only Gloves) ###
+N:348
+X:40:1
+T:31:0:255
+W:1:1:45
+C:10:0:0:0
+
+### + To Hit (Only Gloves) ###
+N:349
+X:35:1
+T:31:0:255
+W:1:1:40
+C:0:10:0:0
+
+# N:index
+# X:power value:max number of time it can appear on one object
+# T:tval:min sval:max sval (up to 20 T: lines)
+# W:mininum player level to create it:rarity1:rarity2
+# C:max to dam:max to hit:max to AC:max to pval
+# F:flags
+
+# Helm of water breathing
+N:350
+X:50:1
+T:32:5:10
+W:20:1:25
+C:0:0:0:0
+F:WATER_BREATH
+
+
+### Amulets And Rings ###
+N:442
+X:15:1
+T:40:0:255
+T:45:0:255
+W:5:1:17
+C:0:0:0:5
+F:STR
+
+N:443
+X:11:1
+T:40:0:255
+T:45:0:255
+W:3:1:12
+C:0:0:0:5
+F:DEX
+
+N:444
+X:13:1
+T:40:0:255
+T:45:0:255
+W:5:1:15
+C:0:0:0:5
+F:WIS
+
+N:445
+X:13:1
+T:40:0:255
+T:45:0:255
+W:1:1:15
+C:0:0:0:5
+F:INT
+
+N:446
+X:7:1
+T:40:0:255
+T:45:0:255
+W:1:1:15
+C:0:0:0:5
+F:CHR
+
+N:447
+X:18:1
+T:40:0:255
+T:45:0:255
+W:7:1:20
+C:0:0:0:5
+F:CON
+
+N:448
+X:15:1
+T:40:0:255
+T:45:0:255
+W:5:1:15
+C:0:0:0:0
+F:SUST_STR
+
+N:449
+X:20:1
+T:40:0:255
+T:45:0:255
+W:7:1:20
+C:0:0:0:0
+F:SUST_CON
+
+N:450
+X:7:1
+T:40:0:255
+T:45:0:255
+W:1:1:15
+F:SUST_CHR
+
+N:451
+X:11:1
+T:40:0:255
+T:45:0:255
+W:1:1:11
+F:SUST_DEX
+
+N:452
+X:13:1
+T:40:0:255
+T:45:0:255
+W:5:1:13
+F:SUST_INT
+
+N:453
+X:13:1
+T:40:0:255
+T:45:0:255
+W:5:1:13
+F:SUST_WIS
+
+N:454
+X:40:1
+T:45:0:255
+C:0:0:0:5
+W:25:1:55
+F:INVIS
+
+N:455
+X:70:1
+T:45:0:255
+C:0:0:0:5
+W:40:1:90
+F:SPEED
+
+N:456
+X:17:1
+T:40:0:255
+T:45:0:255
+W:5:1:16
+C:0:0:0:0
+F:SLOW_DIGEST
+A:REGEN
+
+N:457
+X:20:1
+T:40:0:255
+T:45:0:255
+W:7:1:19
+C:0:0:0:0
+F:REGEN
+A:SLOW_DIGEST
+
+N:458
+X:15:1
+T:40:0:255
+T:45:0:255
+T:35:0:255
+W:10:1:16
+C:0:0:0:4
+F:STEALTH
+A:AGGRAVATE
+
+N:459
+X:7:1
+T:40:0:255
+T:45:0:255
+W:1:1:12
+C:0:0:0:6
+F:SEARCH
+
+N:460
+X:10:1
+T:40:0:255
+T:45:0:255
+W:1:1:12
+C:0:0:0:4
+F:INFRA
+
+N:461
+X:80:1
+T:45:0:255
+W:40:1:95
+C:0:0:0:3
+F:BLOWS
+
+N:462
+X:70:1
+T:45:0:255
+W:38:1:75
+C:0:0:0:0
+F:FLY
+A:FEATHER
+
+N:463
+X:80:1
+T:45:0:255
+W:43:1:85
+C:0:0:0:5
+F:CRIT
+
+
+### Lights ###
+
+N:501
+X:15:1
+T:39:0:255
+T:6:0:255
+W:5:1:15
+F:LITE1
+
+N:502
+X:20:1
+T:39:0:255
+W:10:1:25
+C:0:0:0:0
+F:LITE2
+
+N:503
+X:30:1
+T:39:0:255
+W:20:1:35
+C:0:0:0:0
+F:LITE3
+
+N:504
+X:15:1
+T:39:0:255
+W:10:1:15
+C:0:0:0:0
+F:RES_LITE
+
+N:505
+X:18:1
+T:39:0:255
+W:11:1:17
+C:0:0:0:0
+F:RES_DARK
+
+N:506
+X:20:1
+T:39:0:255
+W:15:1:22
+C:0:0:0:0
+F:SEE_INVIS
+
+N:507
+X:12:1
+T:39:0:255
+W:1:1:10
+C:0:0:0:4
+F:SEARCH
+
+N:508
+X:12:1
+T:39:0:255
+W:1:1:15
+C:0:0:0:4
+F:INFRA
+
+N:509
+X:21:1
+T:39:0:255
+W:5:1:20
+C:0:0:0:0
+Z:illuminate
+
+N:510
+X:35:1
+T:39:0:255
+W:20:1:27
+C:0:0:0:0
+Z:magic map
+
+N:511
+X:30:1
+T:39:0:255
+W:20:1:24
+C:0:0:0:0
+Z:detect curses
+
+N:512
+X:25:1
+T:39:0:255
+W:20:1:17
+C:0:0:0:0
+Z:dazzle
+
+N:513
+X:40:1
+T:39:0:255
+W:20:1:50
+C:0:0:0:0
+Z:detect doors and traps
+
+# Magestaves can get % to life - Theme
+N:514
+X:10:1
+T:6:0:255
+W:10:1:45
+C:-40:-40:0:3
+F:LIFE
+
+# Magestaves, armour, lights and jewelry can get ability to store a spell - Theme
+N:515
+X:10:1
+T:6:0:255
+T:30:0:255
+T:31:0:255
+T:32:0:255
+T:33:0:255
+T:34:0:255
+T:35:0:255
+T:36:0:255
+T:37:0:255
+T:38:0:255
+T:39:0:255
+T:40:0:255
+T:45:0:255
+W:5:1:15
+C:0:0:0:0
+F:SPELL_CONTAIN | WIELD_CAST
+
+# High-level soft and hard armour and DSM can get nether immunity - Theme, adapted from FuryMod
+N:516
+X:50:1
+T:36:11:255
+T:37:15:255
+T:38:0:255
+W:30:1:90
+C:0:0:0:0
+F:IM_NETHER
+
+# Light weapons (no broken ones) can gain sentience - Theme, adapted from FuryMod
+N:517
+X:20:1
+T:21:1:3
+T:22:2:4
+T:23:4:10
+T:24:1:1
+T:24:7:7
+W:10:1:60
+C:0:0:0:0
+F:LEVELS
+
+# N:index
+# X:power value:max number of time it can appear on one object
+# T:tval:min sval:max sval (up to 20 T: lines)
+# W:mininum player level to create it:rarity1:rarity2
+# C:max to dam:max to hit:max to AC:max to pval
+# F:flags \ No newline at end of file
diff --git a/lib/mods/theme/edit/re_info.txt b/lib/mods/theme/edit/re_info.txt
new file mode 100644
index 00000000..c0e36a92
--- /dev/null
+++ b/lib/mods/theme/edit/re_info.txt
@@ -0,0 +1,183 @@
+# File: re_info.txt
+
+# This file is used to initialize the "lib/raw/re_info.raw" file, which is
+# used to initialize the "monster ego race" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# Version stamp (required)
+
+# Most values can be used with the +, -, % and = operators, = will set the
+# monster value, + and - will modify it based on the normal monster
+# % will apply that percentage to the monster value
+# defaults : NO DEFAULT, MUST precise one
+
+# N:x:ego name
+# G:x:y (x=monster letter, y=colour, use * to use the same as the standard monster)
+# I:speed:(dice)d(side):aaf:ac:sleep
+# W:lev:rarity:weight:xp:place('B'efore or 'A'fter)
+# E:weapon:torso:arms:finger:head:legs
+# B:method:effect:(dice)d(side) (up to x4 lines)
+# F:flags that the standard monster MUST have - at least ONE of the R_CHAR_x
+# flags (if present, to determine which monster letters can have this ego
+# type), plus ALL of the rest
+# H:flags that the standard monster MUST NOT have
+# M:monster flags to add for the ego-type
+# O:monster flags to remove, use MF_ALL for all
+# S:monster spells to add for the ego-type
+# T:monster spells to remove, use MF_ALL for all
+
+V:2.0.0
+
+# A few undeads, to be created by the ANIM_DEAD spell
+
+N:1:Skeleton
+G:s:*
+I:%100:+1d+1:+0:+5:-5
+W:+5:13:%30:%95:B
+F:DROP_SKELETON
+H:UNDEAD | NONLIVING | R_CHAR_Z | R_CHAR_A | R_CHAR_E | R_CHAR_g
+M:DROP_SKELETON | UNDEAD | IM_COLD | IM_POIS | NO_FEAR | NO_CONF |
+M:NO_SLEEP | EMPTY_MIND | COLD_BLOOD | STUPID | EVIL
+O:GOOD | DROP_CORPSE | FRIEND | FRIENDS | ESCORT | ESCORTS | SMART |
+O:DROP_GREAT | DROP_GOOD | RAND_25 | RAND_50 | MORTAL
+T:MF_ALL
+
+N:2:Zombie
+G:z:*
+I:%95:%110d%100:%90:+10:-5
+W:+10:14:%70:%100:B
+F:DROP_CORPSE
+H:UNDEAD | NONLIVING | R_CHAR_Z | R_CHAR_A | R_CHAR_E | R_CHAR_g
+M:DROP_CORPSE | UNDEAD | IM_COLD | IM_POIS | NO_FEAR | NO_CONF
+M:NO_SLEEP | EVIL | EMPTY_MIND | COLD_BLOOD | STUPID | EVIL
+O:GOOD | DROP_SKELETON | FRIEND | FRIENDS | ESCORT | ESCORTS | SMART
+O:DROP_GREAT | DROP_GOOD | RAND_25 | RAND_50 | MORTAL
+T:MF_ALL
+
+N:3:Lich
+G:L:*
+I:%100:+0d+1:+10:+20:-10
+W:+30:22:+0:%200:B
+B:TOUCH:LOSE_DEX:+0d+0
+B:TOUCH:LOSE_DEX:+0d+0
+B:TOUCH:UN_POWER:+0d+0
+B:TOUCH:EXP_40:+0d+0
+F:DROP_SKELETON | SMART | R_CHAR_h | R_CHAR_p | R_CHAR_P | R_CHAR_O
+H:UNDEAD | NONLIVING | R_CHAR_Z | R_CHAR_A | R_CHAR_E | R_CHAR_g
+M:UNDEAD | IM_COLD | IM_POIS | NO_FEAR | NO_CONF
+M:NO_SLEEP | SMART | EVIL | COLD_BLOOD
+O:DROP_SKELETON | GOOD | DROP_CORPSE | FRIEND | FRIENDS | ESCORT | ESCORTS |
+O:DROP_GREAT | RAND_25 | RAND_50 | MORTAL
+S:1_IN_4 |
+S:BLINK | TELE_TO | TELE_AWAY | BRAIN_SMASH | DRAIN_MANA | CAUSE_3 |
+S:BLIND | HOLD | SLOW | SCARE
+
+N:4:Spectral
+G:G:*
+I:+10:%80d%100:+10:+20:-5
+W:+20:20:%10:%110:B
+B:*:EXP_20:+0d+0
+B:*:EXP_20:+0d+0
+F:DROP_CORPSE
+H:UNDEAD | NONLIVING | R_CHAR_Z | R_CHAR_A | R_CHAR_E | R_CHAR_g
+M:UNDEAD | IM_COLD | IM_POIS | NO_FEAR | NO_CONF
+M:NO_SLEEP | PASS_WALL | EVIL | COLD_BLOOD
+O:GOOD | DROP_CORPSE | FRIEND | FRIENDS | ESCORT | ESCORTS |
+O:DROP_GREAT | EMPTY_MIND | RAND_50 | MORTAL
+S:1_IN_5 | BLIND | HOLD | SCARE
+T:MF_ALL
+
+N:5:Captain
+G:*:v
+I:+5:%150d%100:+5:%120:-2
+W:+5:4:%120:%150:A
+B:*:*:+0d+1
+B:*:*:+0d+1
+B:*:*:+0d+1
+B:*:*:+0d+1
+F:R_CHAR_o | R_CHAR_y | R_CHAR_k | BASEANGBAND
+M:FORCE_MAXHP | FRIENDS | SMART | DROP_1D2
+
+N:6:Chieftain
+G:*:*
+I:+10:%200d%100:+10:%120:-3
+W:+5:4:%120:%200:A
+B:*:*:+1d+2
+B:*:*:+1d+2
+B:*:*:+1d+2
+B:*:*:+1d+2
+F:R_CHAR_T | R_CHAR_P | R_CHAR_O | BASEANGBAND
+M:FORCE_MAXHP | FRIENDS | SMART | DROP_1D2
+
+N:7:Shaman
+G:*:r
+I:+0:%90d%100:+10:%90:+0
+W:+2:1:%90:%120:A
+F:R_CHAR_o | R_CHAR_k | R_CHAR_n | BASEANGBAND
+M:SMART | FORCE_MAXHP | DROP_1D2
+O:FRIENDS
+S:1_IN_6 | MISSILE | CAUSE_1 | CONF | BLINK
+
+N:8:Priest
+G:*:G
+I:+0:%90d%100:+10:%90:+0
+W:+3:2:%90:%120:A
+F:R_CHAR_T | R_CHAR_P | R_CHAR_O | BASEANGBAND
+M:FRIENDS | SMART | FORCE_MAXHP | DROP_1D2
+S:1_IN_6 | CAUSE_2 | MISSILE | DARKNESS | CONF | SCARE | BLINK
+
+N:9:Mage
+G:*:r
+I:+0:%150d%100:+10:%120:+0
+W:+5:4:%120:%150:A
+B:*:*:+0d+0
+B:*:*:+0d+0
+B:HIT:HURT:=2d=8
+B:HIT:HURT:=2d=8
+F:R_CHAR_O | BASEANGBAND
+M:SMART | FORCE_MAXHP | DROP_1D2
+O:FRIENDS
+S:1_IN_6 | BA_COLD | BO_FIRE | TRAPS | HEAL | HOLD | S_MONSTER | TPORT
+
+N:10:Archer
+G:*:W
+I:+0:+0d+0:+0:+0:+0
+W:+1:1:%100:%110:A
+F:R_CHAR_y | R_CHAR_k | R_CHAR_O | R_CHAR_o | BASEANGBAND
+S:1_IN_4 | ARROW_2
+
+N:11:Rogue
+G:*:b
+I:+2:+0d+0:+0:+10:-30
+W:+1:2:%90:%100:A
+B:*:EAT_GOLD:+0d+0
+F:R_CHAR_y | R_CHAR_k | R_CHAR_o
+
+# For townpeople
+N:12:Elven
+G:*:*
+I:+2:+0d+0:+0:+0:+0
+W:+0:15:+0:+0:B
+F:WILD_TOWN
+H:ANIMAL
+
+# For townpeople
+N:13:Dwarven
+G:*:*
+I:+2:+0d+0:+0:+0:+0
+W:+0:15:+0:+0:B
+F:WILD_TOWN
+H:ANIMAL
+
+# N:x:ego name
+# G:x:y x is the char, y the attribute, * means the normal one
+# I:speed:(dice)d(side):aaf:ac:sleep
+# W:lev:rarity:weight:xp:place('B'efore or 'A'fter)
+# F:flags that the normal monster *must* have
+# H:flags that the normal monster *must not* have
+# M:monster flags that the ego-monster adds
+# O:monster flags to remove (use MF_ALL for all)
+# S:monster spells that the ego-monster adds
+# T:monster spells to remove (use MF_ALL for all)
diff --git a/lib/mods/theme/edit/readme.txt b/lib/mods/theme/edit/readme.txt
new file mode 100644
index 00000000..4c0ecbe7
--- /dev/null
+++ b/lib/mods/theme/edit/readme.txt
@@ -0,0 +1,96 @@
+# File: a_info.txt
+# This file is used to initialize the "artifact" information for the Angband game.
+# This is were you find Cubragol, The Phial , Ringil etc.
+
+# File: ba_info.txt
+# This file is used used to initialize the "store/building actions type" information for the Angband game.
+# This is where you find the ID numbers for 'Presage fate', 'Play craps' , 'Sell an item' etc.
+
+# File: d_info.txt
+# This file is used to used to set the dungeons for the Angband game.
+# This is where you find 'Barrow Downs', 'The Maze' , 'Mordor' etc.
+
+# File: e_info.txt
+# This file is used to initialize the "ego-item" information for the Angband game.
+# This is where you find 'Helms of the Noldor' , 'Filthy rags of leprousness' , 'Boots of Jumping' etc.
+
+# File: f_info.txt
+# This file is used to used to initialize the "terrain feature" information for the Angband game.
+# This is where you find the ID numbers for 'Underground tunnel' , 'grass with flowers' , 'open floor' etc.
+
+# File: k_info.txt
+# This file is used to initialize the "object kind" information for the Angband game.
+# This is where you find 'Katanas' , 'Mushrooms of Sickness' , 'Jewel Encrusted Crowns' etc.
+
+# File: misc.txt
+# This file contains a lot of 'maximums ' for the Angband game.
+# This is where you find 'Maximum number of skills in s_info.txt' ,
+#'Maximum number of items in k_info.txt' , 'Maximum number of artifacts in a_info.txt' etc.
+
+# File: ow_info.txt
+# This file is used to initialize the "owner info type" information for the Angband game.
+# This is where you find 'Bilbo the Friendly(Hobbit)' , 'Raistlin the Chicken(Human)' ,
+# Inglorian the Mage(Human) etc.
+
+# File: p_info.txt
+# This file is used to initialize the "player race/race mod/class" information for the Angband game.
+# You will find here races like 'Humans' , subraces like 'Vampire', classes like 'Monk'
+
+# File: r_info.txt
+# This file is used to initialize the "monster race" information for the Angband game.
+# You will find here monsters like 'Marylene, Heartbreakeress of the Netherworld',
+# 'The Minotaur of the Labyrinth' , 'Morgoth, Lord of Darkness' etc.
+
+# File: ra_info.txt
+# This file is used to initialize the "randart parts" information for the Angband game.
+# Here you will find info for random artefacts made of 'Mage Staves' , 'Lights' , 'Gloves' etc.
+
+# File: re_info.txt
+# This file is used to initialize the "monster ego race" information for the Angband game.
+# Here you will find ego monster types like 'Spectral','Skeleton','Archer' etc.
+
+# File: s_info.txt
+# This file is used to initialize the "skills" information for the ToME game.
+# Here you will find player & monster skills, 8you can use their IDs in other files(?),
+# You will find skills like 'Bearform-combat' , 'Necromancy' , 'Spell-power' etc.
+
+# File: set_info.txt
+# This file is used to initialize the "lib/raw/set_info.raw" file, which is
+# used to initialize the "item set" information for the Angband game.
+# You find linked Items like 'The bow of Bard' & 'The arrow of Bard'
+# It is like totally unclear to me what this does, especially because
+# the big spider doesnt drop Sting, hint hint !
+
+# File: special.txt
+# Contains terrain parsings for the special levels now being kept in seperate map files
+# You will find there entries as in f_info.txt
+
+# File: st_info.txt
+# This file is used to initialize the "store info type" information for the Angband game.
+# You will find there stores like 'Armoury' , 'Temple' , 'The Mathom-house' etc.
+
+# File: t_info.txt
+# Includes the town definitions of the game Angband
+# You will find here the towns like 'Gondor' , 'Bree' , 'Lothlorien' etc.
+
+# File: t_pref.txt
+# Defines the preferences for the town features
+# You will find there entries as in f_info.txt
+
+# File: tr_info.txt
+# This file comes from Angband64 written by Jurriaan Kalkman
+# and describes the traps items can have
+# You will find traps like 'Summon Fast Quylthulgs Trap' , 'Wisdom Trap' etc.
+
+# File: v_info.txt
+# This file is used to initialize the "vault template" information for the Angband game.
+# You will find vaults like 'The I in the Storm' , 'Greater vault (mortuary temple of sety)' ,
+# 'Lesser vault (amenhotep I)' etc.
+
+# File: W_info.txt
+# This is the wilderness
+# Change the dimensions at your perils, most likely the game will crash !!!
+
+# File: wf_info.txt
+# This file is used to initialize the "wilderness feats" information for the Angband game.
+# You will stuff like 'Ekkaia, the Encircling Sea' , 'mountain' , 'Minas Anor' etc.
diff --git a/lib/mods/theme/edit/s_bilbo.map b/lib/mods/theme/edit/s_bilbo.map
new file mode 100644
index 00000000..12c857e2
--- /dev/null
+++ b/lib/mods/theme/edit/s_bilbo.map
@@ -0,0 +1,58 @@
+# Bilbo's Trail level with Thror's map and a few surprises. Copied from Cyclone vault and tweaked to suit the dungeon.
+# You NEED a digger to pass this level, though flight/climbing will do in a pinch.
+# There is no excuse for being on BDw10 without a digger. :-P
+# Map by furiosity <furiosity@gmail.com>
+
+%:special.txt
+
+# Grass
+F:,:89:0
+
+F:+:33:0
+
+# Grass with Thror's Map
+F:1:89:0:0:0:0:209
+
+# Random monster and random object on grass
+F:2:89:0:*13:*15
+
+# Random trap on grass
+F:3:89:0:0:0:0:0:*
+
+### Previous adventurers
+F:a:89:0:0:391
+F:b:89:0:0:392
+F:c:89:0:0:393
+F:d:89:0:0:394
+F:e:89:0:0:395
+F:f:89:0:0:396
+F:g:89:0:0:397
+F:h:89:0:0:398
+
+### Dungeon Design
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMX
+D:XMMMM,g*,,,,,,MMM2,,,,,,,,MMM,,3TMMM,,M,3,M,3,M,,,M+,,,,,,,,,,,,,MM,,,,,,,,,,,,,,,,,,,,T,MX
+D:XMM,,,MMM,,,MMM,,,MMM,,,MMM,,,MMM,,M,,M,M,M,M,M,M,,MMMMMMMMMMMMM,,MM,,MMMMMMMMMMMMMMMMMMTMX
+D:XM,,MMM,,,MMM,,3MMM,,,MMM,,,MMM,,,,M,,M,M,M,M,M,M,,,MM,,,*,,,,,MM,3MM,,,,,a,,,,,,,c,,,*M,MX
+D:XMMMM,,,MMM,,,MMM,,,MMM,,,MMM,,,,,,M,,M,M,M,M,M,M,,,,M,a,b,c,,,,M,,,M,,,,,,,,,,3,3,,,,,M,MX
+D:XMM,,,MMM,3,MMM,,,MMM,,,MMM,,,,,,,,M,,M,M,M,M,M,M,,,,M,,33,,,,,MM,,MMMM,,,,,,,,,2,,,,,,M,MX
+D:XM,,MMM,3,MMM,,,MMM,,,MMM,,,,,,,,,,M,,,,M,3,M,3,M,,,MM,,,2,,,MMM,MMM,,MMM,,,,,,3,3,,,,,M,MX
+D:XM,MM,,,MMM,,,MMM,,,MMM,,,,,,,,,MM+MMMMMMMMMMMMMM,,MM,,,,33,MMM,MMMMMM,,MMM,,,,,,,,,,,,M,MX
+D:XM,,3,MMM,,,,,,,,,MMM,,,,,,,,,,MM,,M,,,,,3,,,,TM,,MM,,,,,,MMM,,MMM,,MTM,,,MM,,,,b,,,,,*M,MX
+D:XMMMM,MMMMMMMMMMMMM,,,,,,,3,,,,M,h,M,MMMMMMMMMM,,MM,,,,,MMM,,MMM,,h,,MMM,,,MMMMMMMMMMMMM,MX
+D:XM>1M,,,,,,3,,,,,,MMM,*g,323,,,M,23T,,,,,3h,,MMMMM,,,,MMT,,MMT,,,,*3,,MMM,,+,,,,,,,,,,,+,MX
+D:XMM,MMMMMMMMMMMM,MM,,,,,,,3,,,,M,*,M,MMMMMMMMMM,,MM,,,,,MMM,,MMM,,2,,MMM,,,MMMMMMMMMMMMM,MX
+D:XM,,,,MMM,,,,,,,,,MMM,,,,,,,,,,MM,,M,,,,,3,,,,TM,,MM,,,,,,MMM,,MMM,,MTM,,,MM,,,,e,,,,,*M,MX
+D:XM,MMM,,MMM,,,MMM,,,MMM,,,,,,,,,MM+MMMMMMMMMMMMMM,,MM,,,,33,MMM,MMMMMM,,MMM,,,,3,3,,,,,M,MX
+D:XM,,MMM,,,MMM,,,MMM,,,MMM,,,,,,,,,,M,,,,M,3,M,3,M,,,MM,,,2,,,MMM,MMM,,MMM,,,,,,,2,,,,,,M,MX
+D:XMM,3,MMM,,,MMM,,,MMM,,,MMM,,,,,,,,M,,M,M,M,M,M,M,,,,M,,33,,,,,MM,,MMMM,,,,,,,,3,3,,,,,M,MX
+D:XMMMM,,,MMM,,,MMM,,,MMM,,,MMM,,,,,,M,,M,M,M,M,M,M,,,,M,d,e,f,,,,M,,,+,,,,,,,,,,,,,,,,,,M,MX
+D:XMg3MMM,3,MMM,,,MMM,,,MMM,,,MMM,,,,M,,M,M,M,M,M,M,,,MM,,,*,,,,,MM3,MM,,,,d,,,,,,,f,,,,*M,MX
+D:XMM*,,MMM,,,MMM,,,MMM,,,MMM,,,MMM,,M,,M,M,M,M,M,M,,MMMMMMMMMMMMM,,MM,,MMMMMMMMMMMMMMMMMM,MX
+D:XMMMM2,,,,3,,,MMM,,,,,,,,,MMM,,3MMMM,,M,3,M,3,M,,,M+,,,,,,,,,,,,,MM,,,,,,,,,,,,,,,,,,,,M,MX
+D:XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+P:22:90 \ No newline at end of file
diff --git a/lib/mods/theme/edit/s_bridge.map b/lib/mods/theme/edit/s_bridge.map
new file mode 100644
index 00000000..dd1367ef
--- /dev/null
+++ b/lib/mods/theme/edit/s_bridge.map
@@ -0,0 +1,104 @@
+# Special level "Bridge Of Khazad-Dum" in Moria (lvl50)
+# Made by Burb Lulls, reworked later for Theme by furiosity <furiosity@gmail.com>
+
+%:special.txt
+
+# chasm
+F:-:87:0
+
+# rubble
+F:;:49:0
+
+# Random monster (up to 5 levels ood) on normal floor
+F:a:1:0:*55
+
+# Random monster (up to 11 levels ood) on normal floor
+F:b:1:0:*61
+
+# Random monster (up to 9 levels ood)
+F:c:1:0:*59
+
+# Random monster (up to 40 levels ood)
+# Random object (up to 20 levels ood
+# These are behind granite walls, only go after them if you really want to!
+F:d:1:0:*90:*70
+
+# Random monster (up to 3 levels ood)
+F:e:1:0:*53
+
+# Random monster (up to 7 levels ood)
+F:f:1:0:*57
+
+### Guardian -- Durin's Bane on normal floor
+F:@:1:0:872
+
+### Escorts (since these can't appear due to the SPECIAL_GENE flag on Durin's bane)
+
+# Mornungol on normal floor
+F:g:1:0:720
+
+# Ungorrog on normal floor
+F:h:1:0:992
+
+# Sererrog on normal floor
+F:i:1:0:995
+
+# Naurungol on normal floor
+F:j:1:0:994
+
+# Faunungol on normal floor
+F:k:1:0:993
+
+# Morgulrog on normal floor
+F:m:1:0:999
+
+# Helcungol on normal floor
+F:n:1:0:648
+
+### Dungeon Design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X----------------------------------------------------------------------------LLLLLLLLLLLLLL-----------------------------------X
+D:X----------------------------------------------------------------------------LXXXXXXXXXXXXLLLLLLLLLLLLLLLLLLLLLLLLL-----------X
+D:X----------------------------------------------------------------------------LX;........;XXXXXXXXXXXXXXXXXXXXXXXXXL-----------X
+D:X----------------------------------------------------------------------------LX...c...f..........e.....f......c..XL-----------X
+D:X----------------------------------------------------------------------------LX;.........XXXXXXXXXXXXXXXXDDXXXXDDXL-----------X
+D:X----LLLLLLLLLLLLLL--------------------------LLLLL---------------------------LXXXXXXXXX..XLLLLLLLLLLLLLLX..D.cX..XL-----------X
+D:X--LLLXXXXXXXXXXXXLLL----------------------LLXXXXXLL-----------LLLLLLLL------LLLLLLLLLX..XXLLLLLLLLLLLLLXXXXXXXDDXL-----------X
+D:X-LLXXX..........XXXLLL------------------LLXXX..aXXXLLL-----LLLXXXXXXXLL-------------LXX..XXLLLLLLLLLLLLX..D..D..XL-----------X
+D:XLXXX..............XXXLL----------------LXXX;......XXXLL--LLXXXX;.f..XXLLLLLLLLLLLLLLLLXX..XXXXXXXXXXXXLXDDXXXXDDXL-----------X
+D:XLX;.................XXL--LLLLLLLLLLLLLLLX...XXXXa..;XXLLLXXX......X..XXXXXXXXXXXXXXXXXXXX.;XX;......;XLX..Xb.D..XL-----------X
+D:XLXXX................;XL--LXXXXXXXXXXXXXXDDXXXLLXXX.;.XXXXX....XXXXXX.D............;XXXXX...XX...XX...XLXDDXXXXXXXL-----------X
+D:XLLLXXX............X..XL--LX;...........a..a;XLLLLXXX..f;...;XXXLLLLXXX...f.....e...XXXXX..XXX...XX...XLX..D.bD..XL-----------X
+D:X--LLLXXXXX..XXXXXXX..XLLLLX.................XLLLLLLXX..D..XXXLLLLLLLLX......a......D............XX...XLXDDXXXXDDXL-----------X
+D:X----LLLLLXDDXLLLLLX..XXXXXXa................XLLLLLLLXXXX...XLLLLLLLLLX...c.....f...XXXXXXXXXX..bXXc..XLX..Db.X..XL-----------X
+D:X--------LX..XLLLLLX.......D........f........XLLLLLLLLLLXX.cXLLLLLLLLLX;...........;XLLLLLLLLX.XXXXXX.XLXXXXXXXDDXLLLLL-------X
+D:X--LLLLLLLX.eXLLLLLXXXXXXXXX;...............;XLLLLLLLLLLXXXDXLLLLLLLLLXXDXXXXXXXXXXXXLLLLLLLLX..XXXXf.XLX...a....XXXXXLL------X
+D:X--LXXXXXXX..XXXXXXXXXXLLLLXXXXXXXXXDDXXXXXXXXLLLLLLLLLXX..bXLLLLLLLLLX..XLLLLLLLLLLLLLLLLLLLX..eXX...XLX..b..b..D...XXLL-----X
+D:X--LX..e..............XLLLLLLLLXXXXX..XXXXXXLLLLLLLLLLXX...XXLLLLLLLLLX##XLLLLLLLLLLLLLLLLLLLX;......;XLX....e...XX..fXXL-----X
+D:X--LXDDXXXXXXXXXXXXX..XLLLLLLXXX;..f......;XLLLLLLLLLXXc.XXXLLLLLLLXXXX..XXXXLLLLLLLLLLLLLLLLXXXX..XXXXLXXXXXXXXXXXX...XL-----X
+D:X--LX..XLLLLLLLLLLLX.eXLLLLLXX.D.......c...XLLLLLLLXXX..XXLLLLLLLXXX........XXXLXXXXXXXXXXXXXXXXXDDXXXXXXXXXXXLLLLLXX.eXL-----X
+D:X--LX..XLLXXXXXLLLLXDDXLLLLXX.eX;...b.....;XLLLLLLLX..fXXLLLLLLLLX...d.....d..XLX.e..b...e...c...f...c...b...XLLLLXX..XXLL----X
+D:X--LX..XLLXXccXLLLLX..XLLLXX..XXXXXXXXXXXXXXLXXXXXXXDDXXXXXXLLLLLXX.....d....XXLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLXXXX..XXXXL----X
+D:X--LX..XLLXX..XLLLLX..XLLXX..XXLLLLLLLLLLLLLLX;....f..f...;XLLLLLLXX;......;XXLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLX;a..f..;XL----X
+D:X--LX..XLLXXDDXXXXXX..XLXX..XXLLLLLLLLLLLLLLLX.............XLLLLLLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLLLXXXX..XXXXL----X
+D:X--LX.aXLLXX..........XLX..XXLLLLLLLLLLLLLLLLX..c...cc..c..XLLLLXXX-------------------------------------XXXLLLLLLX...cXLLL----X
+D:X--LX..XLLXXXXXXXXXXXXXXX..XLLLLLLLLLLLLLLLLLX;...........;XLLLXX-----------------------------------------XXLLLLLXX.;XXL------X
+D:X--LX..XLLLLLLLLLLLLLLLLXDDXLLLLLLLLLLLLLLLLLXXXXXXXXXXXXXXXLLLX-------------------------------------------XLLLLLLX;.XLL------X
+D:X--LX..XXXXXXXXXXXXXXXXXX.eXLLLLLLLLLLLLLLLLLLLLLLLXXXL.l.XXLLLX-------------------------------------------XLLLLLLX.;XL-------X
+D:X--LX;...a.........a.......XLLLLLLLLLLLLLLLLLLLLLXXX.l.X.l.XXLLX----LLLLLLL---------------------..;....XXXXXXXXLLLX;.XL-------X
+D:X--LXXXXXXXXXXXXXDDXXXXXXXXXXLLLLLLLLLLLLLLLLLLLLX.l.XXXXXl.XXLX-LLLLX-X-;-;-X-X-X-;-X-X-X-;-X-X-X-X-X....XXaaXXLLXc;XL-------X
+D:X--LLLLLLLLLLLLLX.fXLLLLLLLLLXXXXXXXLLLLLLLLLLLLLXX.lXXXLXL.lXXXlllLLkX-X-X-X-X-;-X-X-X-;-X-X-;-X-X-X-.....XX..XXLX;.XLLLLLLL-X
+D:X------LLLLLLLLLX..XLLLLLLLLLX..d..XLLLLLLLLLLLLLLXX..lXXXXL.lXXlljjhkmmnn....................c...a........XXX..XXX..XXXXXXXLLX
+D:X------LXXXXXXXXX..XXXXXXXXXXX#####XXLLLLLLLLLLLLLLXXX.lXLXX..l#ljgiikmmmnnn....................f...e......#...........f..cXXLX
+D:X------LX;................;XX;.....;XLLLLLLLLLLXXXXX..lXXLLXL..#lj@ihkkkmnnn..................c...a........#.b..X.XXXXXXXX.fXLX
+D:X------LX....e.........a...XX..c....XLLLLLLLLLLXLl..lXXXLXLXL..#ljgiikmmmnnn....................f...e......#....X.XXXXXXXX.fXLX
+D:X------LX.......f...c......XX...e.f.XLLLLLLLLLLXL..LXXLLXXLXXL.#lljjhkmmnn....................c...a........#...........f..cXXLX
+D:X------LX....c....b....c...DD;.....;XLLLLLLLLLXXXDXXXLLLLLLLXXXXlllLLkX-X-X-X-X-X-;-X-X-X-;-X-X-X-;-X-.....XXX..XXXXXXXXXXXXLLX
+D:X------LX;................;XXXXXXXXXXLLLLLLLLLXLlelLXLLLLLLLLLLX-LLLLX-;-X-X-;-X-X-X-;-X-X-X-;-;-X-X-X....-XX..XXLLLLLLLLLLLL-X
+D:X------LXXXXXXXXXXXXXXXXXXXXLLLLLLLLLLLLLLLLLLXLl>lLXLL------LLX----LLLLLLL---------------------.......----XeeXXLL------------X
+D:X------LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLXLlllLXL--------LX-------------------------------------------XXXXLL-------------X
+D:X-----------------------------LLL-----------LLXXLLLXXL--------LXX-----------------------------------------XXLLLL--------------X
+D:X-------------------------------LL-----------LLXXXXXLL--------LLXXX-------------------------------------XXXLL-----------------X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+### Starting Location
+P:10:10 \ No newline at end of file
diff --git a/lib/mods/theme/edit/s_crypt.map b/lib/mods/theme/edit/s_crypt.map
new file mode 100644
index 00000000..3d6ce71c
--- /dev/null
+++ b/lib/mods/theme/edit/s_crypt.map
@@ -0,0 +1,109 @@
+# Special level "The Forgotten Crypt" in The Pits of Angband
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Written by Mynstral (mynstral@thehelm.com)
+
+%:special.txt
+
+### Guaranteed Monsters
+# Vampire on normal floor
+F:a:1:0:432
+
+# Ghoul on normal floor
+F:b:1:0:418
+
+# Rotting Quylthulg on normal floor
+F:c:1:0:633
+
+# Master Vampire on normal floor
+F:d:1:0:520
+
+# Vampire Lord on normal floor
+F:e:1:0:623
+
+# Greater Rotting Quylthulg on normal floor
+F:f:1:0:802
+
+# Ghast on normal floor
+F:g:1:0:327
+
+# Undead Beholder on normal floor
+F:h:1:0:664
+
+# Thuringwethil, the Vampire Messenger on normal floor
+F:i:1:0:755
+
+# Black Reaver on normal floor
+F:j:1:0:798
+
+### Random Monsters and/or Items
+# Random monster (upto 5 levels ood) on normal floor
+F:&:1:0:*75
+
+# Random monster (upto 11 levels ood) on normal floor
+F:@:1:0:*81
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on normal floor
+F:8:1:0:*79:*77
+
+# Random monster (upto 40 levels ood) and
+# Random object (upto 20 levels ood
+F:9:1:0:*110:*90
+
+# Random monster (upto 3 levels ood)
+F:-:1:0:*73
+
+# Random object (upto 7 levels ood)
+F:=:1:0:0:*77
+
+### Guaranteed Items
+# The Shadow Cloak of Luthien on normal floor
+F:1:1:0:0:0:0:49
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XA.%@=-=-X8XX6...XX.XXLLL..c..LLLXX.XX...7XX8X=-=-...5X
+D:X.%%@=-=-X99X.....X..XLL..X%X..LLX..XhVV..X99X=-=-..GGX
+D:X%%@@...XXX9XX....XX.XX...X.X...XX.XXVVVVXX9XXX=-=.XGGX
+D:X@@@....X8X-=XgggggX..X..dX4Xd..X..XWWWWWX-=X8X-=-.XGGX
+D:X......XX%XX=XXgddgXX.XX8GXXXG8XX.XXWWWWXX-XX%XX...XGGX
+D:XIXIXXIX*X=X-=XgddggX..X8G^.^G8X..XWWWWWX-=X.X.X&&&XGGX
+D:XXXIXIXX*X-XX=XXggggXX.XXG^.^GXX.XXWWWWXX-XX.X.XX&&XGGX
+D:XXXXXIX**X=-X=-XIIXXXX..XG^.^GX..XVWWWVX=-XX.XddX@@XGGX
+D:X^^^^XX**X=-XX=XXIXIIXX.XX^.^XX.XXVVVVXX-XX%.XedXX@XGGX
+D:X^^f^Xe**X%%.X=-XXIXXIXbbX^.^XbbX.VV.XX=-XbX.XXXIX@IIGX
+D:X^^^XXe..X...XX=-XXXIXXXbXX.XXbXX...XX=-XXbX.XaaaXXXIGX
+D:X^^XXbbb.XGGG.XX=-XXIIXXbbXDXbbX...XX=-XXbbX.XaaaaXXIGX
+D:X^XXcbab.XVdG.cXX=-XXXIXXabXbaXX.XXX=-XXbbbX.XaaaaaXXfX
+D:X%XbbbbbbXVWG.%.XX.DbXDXXXbXbXXXDXbD.XX....G.XGGGGGGX%X
+D:XX.bababa%eWG.%.BXXXbcbbbbX.XbbbbcbXXXC...fX.%.......XX
+D:X%XbbbbbbXVWG.%.XX.DbXDXXXbXbXXXDXbD.XX....G.XGGGGGGX%X
+D:X8XXcbab.XVdG.cXX=-XXX.XXabXbaXXLXXX=-XXbbbX.XaaaaaXX.X
+D:X88XXbbb.XGGG.XX=-XX...XbbXDXbbXLLLXX=-XXbbX.XaaaaXXX.X
+D:XXXIXXe..X...XX=-XX.GGXXbXX.XXbXXILIXX=-XXbX.XaaaXXXX.X
+D:X9889Xe**X%%.X=-XXG.GdXbbX^.^XbbXILLIXX=-XbX.XXXIXhGG.X
+D:XXIXXXX**X=-XX=XXdG.GXX.XX^.^XX.XXILIIXX-XX%.XedXXXXX.X
+D:X99999X**X=-X=-XGGG..X..XI^a^IX..XILLIIX=-XX.XddX..eeeX
+D:XXXXIXXX*X=XX-XX....XX.XXI^a^IXX.XXILLIXX=XX.X.XX.GGGGX
+D:X^^^^^cX*X-X=-X.....X..X.I^a^I.X..XIILLIX=-X.X.Xdddd..X
+D:XllllX^XX%XX=XXG.GGXX.XX.IXXXI.XX.XXIILIXX-XX%XXXXXXX.X
+D:X^^^cl^=X8X-=XeG.GeX..X...X4X...X..XILLLIX-=X8X.aaaaaaX
+D:XLLX^l^-XXX9XXGG.GXX.XX...X.X...XX.XXLLLLXX9XXX.GGGGGGX
+D:X..L^l^=-X99X.....X..XWW..X%X..WWX..XLLLL.X99XXbbbbb..X
+D:X7.L^l^=-X8XX5...XX.XXWWW..c..WWWXX.XXLL.AXX8XXbbbbb.6X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXIIIIXIIIIXXIIIXIIIIXXIIIXXXXggggXc..cXaaaaXbb.CX
+D:XIIIIIXIXXIIIXXIIXIXIXIXXIXXIXIXXXXgddg%....%aaaa%bb..X
+D:XIXXXIXIXXXXXXXXIIIXIXIIXIXXIXIXXXXggggXc..cXaaaaXbbbbX
+D:XIXXXIIIXIIIIIIXXXXXIXXIXIXIIXIXXXXXXXXXXIIXXXXXXXXXXXX
+D:X..XXXXXXIXXXXIXIIIXIXIIXIXIXXIXXXXVVVjXddddXe..eX....X
+D:XB.IIIIIXIIIXIIXIXIXIIIXXIXIXIIXIIIVVVEX....%.ee.%.hh.X
+D:X..XXXXIXXXIXIXXIXIXXXXXIIXIXIXXIXXVVVjXddddXe..eX....X
+D:XIXXXIXIIIXIXIIIIXIIIIXIIXXIXIXXIXXXXXXXXXXXXXXXXXXDDXX
+D:XIXXXIXXXIIIXXXXXXXXXIXIXXIIXIIIIXXGGGGXgggdddeIVX....X
+D:XIIXXIXXXXXXXIIIIXXIXXXIIIIXXXXXXXXE.heDgggaaaiG1X....X
+D:XXIIIIIIIIIIIIXXIIIIXIIIXXXXXXXXXXXGGGGXgggdddeIVX..j>X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting location
+P:17:29
diff --git a/lib/mods/theme/edit/s_death.map b/lib/mods/theme/edit/s_death.map
new file mode 100644
index 00000000..398b5fd1
--- /dev/null
+++ b/lib/mods/theme/edit/s_death.map
@@ -0,0 +1,104 @@
+# Special level "Deathwatch" in the Orc Caves
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Altered by Mynstral (mynstral@thehelm.com)
+
+%:special.txt
+
+### Guaranteed monsters
+# Snaga on normal floor
+F:a:1:0:118
+
+# Cave orc on normal floor
+F:b:1:0:126
+
+# Hill orc on normal floor
+F:c:1:0:149
+
+# Black orc on normal floor
+F:d:1:0:244
+
+# Half-orc on normal floor
+F:e:1:0:264
+
+# Uruk on normal floor
+F:f:1:0:313
+
+# orc captain on normal floor
+F:g:1:0:285
+
+# Lagduf on normal floor
+F:h:1:0:140
+
+# Grishnakh on normal floor
+F:i:1:0:186
+
+# Golfimbul on normal floor
+F:j:1:0:215
+
+### Guaranteed items
+# Thalkettoth on normal floor
+F:1:1:0:0:0:0:28
+
+# Maedhros on normal floor
+F:2:1:0:0:0:0:64
+
+# Cammithrim on normal floor
+F:3:1:0:0:0:0:53
+
+### Dungeon Design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X XXXXXXXXXXXX X
+D:X X..........X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X
+D:X X....>.....X X.XdX.X.X.XcX.X.X...XcX.X.XcX.X.XgXd+2X X
+D:X X..........X XDXDXDXDXDXDXDXDX...XDXDXDXDXDXDXDXDXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X
+D:X XXXXXDXXXXXX X...............D...D...............X X...f............a...XXXXX.......b..f....a....+1X X
+D:X X.X XDXDXDXDXDXDXDXDX..cXDXDXDXDXDXDXDXDX X........b...........XXXXX...a..........b.....XXX X
+D:X X.X X.XcX.XcXdX.X.X.X...XcX.XdXcX.X.X.XgX XXXXXXXXXXDDXXXXXXXXXXXXXXXXXXXXXXXXDDXXXXXXXXX X
+D:X X.X XXXXXXXXXXXXXXXXX.c.XXXXXXXXXXXXXXXXX XXXXXXXXXXDDXXXXXXXXXXXXXXXXXXXXXXXXDDXXXXXXXXX X
+D:X X.X XXX X...X X...........f...a....XXXXX....b.a...........b.X X
+D:X XX.XX X.XXXXXXXXXXXXDDDXXXXX X..f...b.............XXXXX..a....f.....b..a...X X
+D:X XX...XX XXXDXXXXXXXXX.......c.XX XXXXXXXXXXDDXXXXXXXXXXXXXXXXXXXXXXXXDDXXXXXXXXX X
+D:X XX.....XX XdD........D...c......dX X........a...............a....................X X
+D:X XX.......XX XXXDXXXXXXXX......c....X Xf....b..........f............a.........f.....X X
+D:X X.........X XeX XX.........XX X.............a.......b...........a...........X X
+D:X XXXXX.XXXXX X.X XXXXDDDXXXX X....a...............................a........X X
+D:X X.X X.X X...X XXXXXXXXXXXXXXXXXXXXX...XXXXXXXXXXXXXXXXXXXXXXX X
+D:X X.X X.X X...X X...X X
+D:X X.X X.X XX...XX X.b.X X
+D:X X.X X.X XX.....XX X...X X
+D:X XXDXX XXXX X.X XX.......XX X..bX X
+D:X X...XXXX..X XdX XX...ccc...XX X...X X
+D:X X...+..D..X X.X XX....ccc...dXX X...X X
+D:X X...XXXX..X X.X XX.d..ccicc....XX XXXXXXXXXXXXXDDDXXXXXXXXXXXX X
+D:X XX.XX XXXX X.X XX......ccc..g...XX XX......a...............f...XX X
+D:X X.X X.X XX...g...ccc.......XX XXX..f.........................XX XXXXX X
+D:X X.X X.X X......g.........g..X XX..................b....a.......XX Xa.aX X
+D:X X.X XgX XXXX..XXXXXXX..XXXXXX XX.....a.........a..............a..XX X.a.X X
+D:X X.X X.X X..X X..X XXXXXXXX..........f........................XX XDXXX X
+D:X X.X X.X Xd.XXXXXXX..XXXXXXX X.....D...b.................b...f...........XXXXXXXXXXX.X X
+D:X X.X X.X X...c.......D.....X X.....D...........a..h.............a........D......a....X X
+D:X X.X X.X X.......c.g.D.....X X...XXXX.....b.............................XXXXXXXXXXXX.X X
+D:X XXXX.XXXX X.X XXXXXXXXXXXXXXXX..XXXXXXX X...X XX..............a......a...........XX X.X X
+D:X X.......X X.X X........XXXXXXX...X XX.........f.............f.......XX X.X X
+D:X XXX...XXX X.X X..d...............X XX.....b...........b.........f.XX XaX X
+D:X X.......X X.X X........XXXXXXX...X XX..........b................XX X.X X
+D:X XXXX.XXXX X.X XXXXXXXXXX XXXXX XXXXXXXXXXXXDDDDDXXXXXXXXXXXX X.X X
+D:X X.X XDXXXXXXXXXXXXXXX X.....X X.X X
+D:X X.X X..d...e......d.XXXXXXXXXXX XXXXXXXXXXXX X.b...X X.X X
+D:X X.X X....e..g.......D.........X X.d..gg..eeX XXX.....XX X.X X
+D:X X.X XXXXX X..g..d.....e...XXXXXXXXDDXXXXXXXX....gg..eeXXXXX XX...XXX..XXX XXXXXXDXX X
+D:X X.X XeeeX XDXXXXXXXXXXXXXXX Xg.d.......D.e..e..gg..eej+3+% XX....XXX....XXXXXX XXX...D..aX X
+D:X X.X Xeg.X XX.XX X....e....eD.e.....gg..eedXXX% X.............X...X XaD...X...X X
+D:X XXXX.XXX XX+XXXX...X X.d........XXXX....gg..eeXX % XXXXX XXXXXXXXXXXX..D...X XXX..aX...X X
+D:X X......X XX.......X XXXX...e...d..XXXX...dgg..eeX % X...X XX.....D..XXXXXX XXXXXXXDXX X
+D:X X......X X.g.....XXXXXX X..D....g..e..Dd.XXXXXXXXXXXX % XXXDXX X......X..X....X X...X X
+D:X X......X X...d...DeeeeX X..XXXXXXXXXXXX..X + X...X XXXXXXXX..X....X X...X X
+D:X X......X X.....e.XXXXXX XXXX XXXX % X...XXXXXX X....D..D....X XXXXXXXXDXDXXXX X
+D:X XXXDDXXXXXXXXXXXXXX+XXXXXX % X....X...X X..XXX..XXXXXXXXX X.....a..X....X X
+D:X X........%........X %+%%....D...XXXXXX.D..D.....+.X X........X....X X
+D:X XXXXXXXXXXXXXXXXXXX XXXXXX..........X..X.....XXX XXXXXXXXXXXXXXX X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting Location
+P:51:125
diff --git a/lib/mods/theme/edit/s_doom.map b/lib/mods/theme/edit/s_doom.map
new file mode 100644
index 00000000..5be3b67d
--- /dev/null
+++ b/lib/mods/theme/edit/s_doom.map
@@ -0,0 +1,226 @@
+# Mount Doom
+
+### Terrain Features
+# Permanent Wall
+F:X:177:0
+
+# Lava Wall
+F:#:177:0
+F: :177:0
+
+# Great Fire
+F:$:178:0
+
+# Fire
+F:%:205:0
+
+# Hidden Door
+F:+:48:0:0:0:0:0:0:0:177
+
+# Normal Door
+F:D:32:0
+
+# Shallow Lava
+F:.:86:0
+
+# Deep Lava
+F:L:85:0
+
+# Treasure (random) on shallow lava
+F:*:86:0:0:*
+
+# Trap (random) on deep lava
+F:^:85:0:0:0:0:0:*
+
+# Trap (random) on shallow lava
+F:t:86:0:0:0:0:0:*
+
+# up staircase
+F:<:6:0
+
+### Guaranteed Monsters
+# Greater Balrog on deep lava
+F:A:85:0:807
+
+# Greater Balrog on shallow lava
+F:a:86:0:807
+
+# Lesser Balrog on deep lava
+F:B:85:0:996
+
+# Lesser Balrog on shallow lava
+F:b:86:0:996
+
+# Pit Fiend on deep lava
+F:C:85:0:812
+
+# Pit Fiend on shallow lava
+F:c:86:0:812
+
+# Great Wyrm of Power on deep lava
+F:E:85:0:847
+
+# Great Wyrm of Power on shallow lava
+F:e:86:0:847
+
+# Bone Golem on deep lava
+F:F:85:0:1013
+
+# Bone Golem on shallow lava
+F:f:86:0:1013
+
+# Dracolisk on deep lava
+F:G:85:0:703
+
+# Dracolisk on shallow lava
+F:g:86:0:703
+
+# Nycadaemon on deep lava
+F:H:85:0:719
+
+# Nycadaemon on shallow lava
+F:h:86:0:719
+
+# Barbazu on deep lava
+F:I:85:0:720
+
+# Barbazu on shallow lava
+F:i:86:0:720
+
+# Plasma Hounds on deep lava
+F:J:85:0:726
+
+# Plasma Hounds on shallow lava
+F:j:86:0:726
+
+# Hell knight on deep lava
+F:K:85:0:731
+
+# Hell knight on shallow lava
+F:k:86:0:731
+
+# Nightcrawler on deep lava
+F:M:85:0:744
+
+# Nightcrawler on shallow lava
+F:m:86:0:744
+
+# Aether Hound on deep lava
+F:N:85:0:811
+
+# Aether Hound on shallow lava
+F:n:86:0:811
+
+# Eye druj on deep lava
+F:O:85:0:749
+
+# Eye druj on shallow lava
+F:o:86:0:749
+
+# Skull druj on deep lava
+F:P:85:0:750
+
+# Skull druj on shallow lava
+F:p:86:0:750
+
+# Great Hell Wyrm on deep lava
+F:Q:85:0:756
+
+# Great Hell Wyrm on shallow lava
+F:q:86:0:756
+
+# Nightwalker on deep lava
+F:R:85:0:768
+
+# Nightwalker on shallow lava
+F:r:86:0:768
+
+# Osyluth on deep lava
+F:S:85:0:773
+
+# Osyluth on shallow lava
+F:s:86:0:773
+
+# Great Wyrm of Many Colours on deep lava
+F:U:85:0:790
+
+# Great Wyrm of Many Colours on shallow lava
+F:u:86:0:790
+
+# Horned Reaper on deep lava
+F:V:85:0:811
+
+# Horned Reaper on shallow lava
+F:v:86:0:811
+
+# Bronze Golem on deep lava
+F:W:85:0:1015
+
+# Bronze Golem on shallow lava
+F:w:86:0:1015
+
+### Random Monsters and/or Items
+# Random monster on deep lava
+F:!:85:0:*99
+
+# Random monster on shallow lava
+F:1:86:0:*99
+
+# Random monster (upto 10 levels ood) on deep lava
+F:@:85:0:*109
+
+# Random monster (upto 10 levels ood) on shallow lava
+F:2:86:0:*109
+
+# Random monster and
+# Random object on deep lava
+F:&:85:0:*99:*99
+
+# Random monster and
+# Random object on shallow lava
+F:7:86:0:*99:*99
+
+# Random monster (upto 10 levels ood) and
+# Random object (upto 5 levels ood) on deep lava
+F:(:85:0:*109:*104
+
+# Random monster (upto 10 levels ood) and
+# Random object (upto 5 levels ood) on shallow lava
+F:9:86:0:*109:*104
+
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X #%%NNLL...JJJ....LL# ############## X
+D:X ##### #NNNN...Ljjjjj..LLL# #############################################..1!!!!...L### X
+D:X##.LL## #nNNN...LLJJj.LLLLL# #L....&!&!&....L%%%%%%%L..mRR%R%%M%MML%LL...DL...!1&..@L%%# X
+D:X#LL<..# #nn.LL.LLLL...%%%LL# #..##########################################LLL....LLL%%%# X
+D:X##%LL## #....LLL%%LLL..^LLL# #.L# #LL2.t..q.LLL## X
+D:X ###+# #D##############+#######.L# ##%%.LLLL&L...# X
+D:X #!# #.# #.......L%%# ##%%LL..2...t.## X
+D:X #^# #.############ ##########+# XXXXXXXXXX ##.9.t.LLLLL## X
+D:X #.# #LL%%%%LL...p# #11111# X########X ###############.2..LQ#+# X
+D:X ##.# ############D## #11211# X#9....9#X #o.....t...# ###^L..#(# X
+D:X #L## ##%%V## #12221# XXXXXX#..$$..#XXXXXX#LLLLKkk...# ###D#### X
+D:X ##!# ##.VH^%## #12221# X######t....m######X#LLLLkkk.LL# #.# X
+D:X #.# ##.iH%%hv## #11211### X#sSSSrrt%.mVVVLLe#X#.LL.kkk...# ##.# X
+D:X ###D######### #tiI%HHhvL# #11111+9# X#rRssRr.%.mVvvm..#X#%...LLL...# ##Lo###### X
+D:X #.^t^LLL...L## #.LIH%Hc..# ######### X#.MmmM..%..MMLLL.#X#%%......L&# ##.L##EBBB# X
+D:X #.jJ%%%L....L# ##..ICCL.## X#.L..L..%ttL.....#X########D### #.####LAAB## X
+D:X #JJJJL%LLL&..# ##..L.L## X#9LLL...%..LL(LLq#X #..L..# #.LL..LB%%L# X
+D:X #J%J..LLL%%LL## ##.t.## X######......######X #L.#### ###..LL%%%L## X
+D:X #jJJ^..bL%LL..## ##D################# XXXXXX#.LUUL.#XXXXXX #.L# #.PL%%%@(L# X
+D:X ##....BABLL..L.## #.uLL^L..L%^^..L%%# X#.L%%LL#X #L.#### ###.L%LL..##X
+D:X ##....B%%L.....## #################L# X#LLL..t#X #..twW# #L..LL...+pX
+D:X ###....LLL...LLL####################.# X#%L..7.#X #####L# ###LL...1###oX
+D:X #9+L%%L...LLL....D.+..%%oF.%%^..%%LL.# X#LLLLt.#X #p# #%%%!@..## #tX
+D:X ##################L###.L###..###.L#### X#7tt.LL#X #.# ######### #EX
+D:X ##################.# ############## X#.LLLL.#X ######D###################LX
+D:X ##11!!!&LL.+(#L# X#LL%%LL#X #G..LLL.LL...D..LL....^LLL%X
+D:X ##1!!!%%%%Lp###L# X#L%%%%Q#X #..LF....K...##############X
+D:X ##!!%%%%%LLL..#.# XXXXDDXXXX########.LLLL..KKK..#### X
+D:X ##.LLLLLLL...+.# #%%%%%%%%%%%%%+LL7..LL.k..L+o7# X
+D:X ############### ############################### X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting location
+P:6:6
diff --git a/lib/mods/theme/edit/s_factory.map b/lib/mods/theme/edit/s_factory.map
new file mode 100644
index 00000000..0cc3de1b
--- /dev/null
+++ b/lib/mods/theme/edit/s_factory.map
@@ -0,0 +1,238 @@
+# Map "s_factory.map"
+#
+# Special Level "Foul Factory" in the Illusory Castle
+#
+# Created for ToME 3.x on 11/11/2003
+# Written by Lord Dimwit (lorddimwit@hotmail.com)
+#
+# Middle-game dungeon
+# Comments: This level isn't designed to kill the player, really, just
+# induce such severe aggravation that their head explodes. There are
+# two parts of it, the "abusive trickery" part that leads the player
+# through a horrendous maze of strategically placed glass walls, permanent
+# walls, and ethereal walls (like permanent walls only invisible, very awful),
+# followed by a "Factory" stage that follows more traditional patterns of
+# throwing monsters systematically at the player.
+
+# Backported to ToME 2.x by Massimiliano Marangio on 02/07/2004
+
+# Replaced the letter : by R for Rubble
+# Changed the starting position to 21:51
+# Corrected the exits of the jumpgates
+
+### F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>:<mimic>
+
+### Terrain Features
+
+
+# Permanent wall
+F:X:61:4
+
+# Fake wall
+F:I:189:0
+
+# Ethereal wall
+F:#:245:0
+
+# Copper Pillar
+F:;:244:0
+
+# Mountains
+F:M:97:0
+
+# granite
+F:G:57:4
+
+# Floor
+F:.:1:0
+
+# Deep Water
+F:~:187:4
+
+# Ash
+F:,:93:4
+
+# Fire
+F:%:205:0
+
+# Deep lava
+F:L:85:0
+
+# Shallow lava
+F:l:86:0
+
+# Glass Wall
+F:_:188:0
+
+# Rubble
+F:R:49:0
+
+# Trees
+F:T:96:0
+
+# Tainted water
+F:t:174:0
+
+# Chasm
+F:C:87:0
+
+# up staircase
+F:<:6:0
+
+# down staircase
+F:>:7:0
+
+# between gate 1
+F:1:160:6:0:0:0:0:0:845
+
+# between gate 2
+F:2:160:6:0:0:0:0:0:846
+
+# between gate 3
+F:3:160:6:0:0:0:0:0:4370
+
+# between gate 4
+F:4:160:6:0:0:0:0:0:3339
+
+# between gate 5
+F:5:160:6:0:0:0:0:0:4119
+
+# between gate 6
+F:6:160:6:0:0:0:0:0:6659
+
+# between gate 7
+F:7:160:6:0:0:0:0:0:9257
+
+# between gate 8
+F:8:160:6:0:0:0:0:0:8018
+
+# between gate 9
+F:9:160:6:0:0:0:0:0:9298
+
+# between gate A
+F:A:160:6:0:0:0:0:0:805
+
+# between gate B
+F:B:160:6:0:0:0:0:0:831
+
+# between gate D
+F:D:160:6:0:0:0:0:0:809
+
+# between gate E
+F:E:160:6:0:0:0:0:0:2826
+
+# between gate F
+F:F:160:6:0:0:0:0:0:2831
+
+# between gate H
+F:H:160:6:0:0:0:0:0:4631
+
+# between gate J
+F:J:160:6:0:0:0:0:0:7198
+
+# between gate K
+F:K:160:6:0:0:0:0:0:7990
+
+# between gate N
+F:N:160:6:0:0:0:0:0:9253
+
+# Treasure on floor
+F:$:1:0:0:*65
+
+# Trap (random) on floor
+F:^:1:0:0:0:0:0:*
+
+
+### Monsters
+
+# Eog Golem on floor
+F:g:1:0:530
+
+# Clay Golem on floor
+F:a:1:0:261
+
+# Aquatic Golem in water (OK, just for show)
+F:?:187:0:899
+
+# Stone Golem on floor
+F:b:1:0:323
+
+# Iron Golem on floor
+F:c:1:0:367
+
+# Colbran on floor
+F:d:1:0:435
+
+# Mithril golem on floor
+F:e:1:0:464
+
+# Colossus on floor
+F:f:1:0:558
+
+# Drolem on floor
+F:h:1:0:691
+
+# Demonic Q on shallow lava
+F:Q:86:0:727
+
+# Livingstone on floor
+F:i:1:0:336
+
+# Random monster (upto 8 levels ood) on normal floor
+F:&:1:0:*58
+
+
+### Items
+
+# Broken Stick
+F:s:1:0:0:727
+
+
+### Guaranteed Items
+
+# The Boots of the Machine
+F:*:205:0:0:0:0:218
+
+
+### Level layout
+
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X..e.e...I.......Xe..c.a..ca.c.....1X..3..XQQX,llllllllllllll2XX#Gi.X.X..XLABLX..X
+D:X.XXX...XXX.....XXXe.c..XXX__XX__XXXX.;.;.XllX,ll,ll,XXXXXXXXXXi.X#.XiXXXXL%%LXXXX
+D:X&XXXe.XX~XXeeeXX~XXe..XX~~~~~~ttttXX.....X,,,,Ll,ll,X..XII.X.X.i.XXG_XXXXL%%LXXXX
+D:X..&..XX~~~XXeXX~?~XX.&X~~~~t~ttttttX.;.;.X,lllll,ll,XX_..XX.XX#X..X#XXf.X_GG_X.fX
+D:XGXGXGX?~~~~_c_~~~~~X.&XX~~~~t~ttttXX.....X,L,,,,,lL,.X.#XXi..G.XXiX..XX.........X
+D:X.....XX~~?XXcXX~~~XXa..XXX__XX__XXXX.;.;.X,L,.XXX%L%XXXXcXX.XXX.X.X.X.XX.X.ff.X.X
+D:XXgXgXgXX~XXcccXX?XXXXX.a^^a.^^a...bXXXGXXX%L%XX.XX%XXa.aXIX.Xi#.XiXI.X.X........X
+D:XgXgXgXgXXX^^^^^XXX,ccXXXXXXXXXXXb.XX#...#XX%XX.XI_XX....X.X.#XXXIX.#GX.X.X....X.X
+D:X.......4X.^^5^^.X.c.c..c..c.c..c.XX.#...#.XXXIXX.X.a.c..XXi..I.X._.X.XXX...&&...X
+D:X..&&...XXXXXXXXXXc,c,c.XX_XX..ccXX..#...#..XX#iiX.X.a..a.XX.#XX._X.XX.XX.X....X.X
+D:X......XXEX,,,c,c,cc,ccXXMRMXXc.XX...#...#...XXX#iXXXXXc..IXGX.XXiX.....X........X
+D:XXXXXXXX..X,,,,,,,,,,,XXM..RMXXXX$$XXX...XXX$$XX..XX_GXXXXXX.Ii.X_X.X#XXX.X....X.X
+D:XT.T._.g.gXX,C,,,.,C,c_M.R.R.MXX$$$XXX...XXX$$$XX..XIXIXII.i.XX_.X.XX.XXXXGGGGGGXX
+D:X.T.T_.....XXlXXXXXlXFXXM..RMXX$$XXXXX...XXXXX$$XX.#.XX.X_X_XXI#.XXIIX.Xeee...eeeX
+D:X..T._.g..g.XlX_D_XlXXXXXM.MXX$$$#....%%%....#$$$X.X..XX_G.#.X.XXIXX..cXXXX...XXXX
+D:XMMMMX...&..XlX_._XlX6..XXXXXX$$$#....%*%....#$$$X._X#iX.XX..G_Xi.XXd..XLl#_._#lLX
+D:Xs.s._..&.&.XlX_._XlX..gg....X$$$#....%%%....#$$$X.IIX.X..XIXX.X.G#X..dXLl#_._#lLX
+D:X.s.s_g....XXlXXGXXlXX.g..d&.XX$$XXXXX...XXXXX$$XXXX._XG#X.XX.X_X.XX.c.XXXX...XXXX
+D:XXXXXXXXXXIXLLLXGXLLLXgg.g.d..XX$$$XXX...XXX$$$XX<...XiXX.X.Xi.X.X.Xd..X.........X
+D:Xgg.gXg.gXIXL%LXGXL%LXGXXX__XXXXX$$XXX...XXX$$XXXXXXIXXiX#XX#XX#X_XX...XXXXXXXIXXX
+D:X^^X^X^X^X^XX_XXGXX_XXGXXg..g.%.XX...X...X...XX.GI.X._iXXG...I..I.GX..dIX#I#I#I#IX
+D:X^^X^X^X^X^Xhl,&c.a&g.l.XX.g.g%RRXX..X###X..XX..#_X..XXX_iXXIXiXi_.Xc..X.IX.XXXIXX
+D:X^^X^X^X^X^X&,,,l&,lac.&.__.g.%.R.XX...>...XX#X.X..XX#.._X.X.X.#.XGX.X.XX_XX.X#i.X
+D:XH.Xg.gXg.gXla,ca&,f.fl.leXX..%R.RRXX.....XX.G.XX#XXI.XX.#.XGXXXiX.#X.XX.i._X.XGX#
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXGXXXXXXXG.X..X#XXX.XX.XXI._XIX.XIXXI#.XXX.X
+D:X,.,G,&&,ee,ff,hgg,&&,,,.,,I7XXXc..aX.;.;.X&..XXXG#XX.G.XXX..XG######.G.#..##..iXX
+D:X^X,G.&&.ee,ff..gg,&&,.,,,,XXX..MRM.X.....X.....XXX.IIX.XGI.XX..IXXXXXXXXXXX._.X._
+D:X^X,XXXXXXXXXXX.XXXXXX,,.XXX..$.....X.;.;.Xh..&...GXXXGXi#IXX.IXX..#.....#.XX##XXX
+D:X^X,llL,LlLL,LXXXlll,XXXXX..aMR..$.cX.....X.....XXXX8XXXXXXXX#IX###..##.#..#XI.XKX
+D:X^XlLCCCCCCCCLllll%%l.R.R.R.R..M.R..X.;.;.X&..XXX.#X#.i.#.XXX#X...###.#.##.#.X#IXX
+D:X^X,lL,llL,Ll,XXX,lllXXXXXc.M..R.c..X.....XXXXX#.#.XIX#Xi.X...X###.#####.#...X#XXX
+D:X^X,XXXXXXXXXXX.XXXXXX,.,XXX...$.M..X.;.;.Xh.##i#.#XX_IX.#X.##I....#.#.###.##X#I.X
+D:X^X.G,&&,,gg.&.,ee,ff,,.,.,XXXa..R..X.....X..#.###.XIXX.X.X.##XX####..#..###II.X.X
+D:X,,,G,&&,,gg.&h.ee,ff,..,.,I^XXXM..9X.;J;.Xh.##.###..iiX#.X....II.....#....IX..XNX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+
+### Starting location
+P:21:51
diff --git a/lib/mods/theme/edit/s_gates.map b/lib/mods/theme/edit/s_gates.map
new file mode 100644
index 00000000..3ac7ccbf
--- /dev/null
+++ b/lib/mods/theme/edit/s_gates.map
@@ -0,0 +1,117 @@
+# Special Level "The Dimensional Gates" in the Pits of Angband
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Written by Mynstral (mynstral@thehelm.com)
+
+%:special.txt
+
+### Gauranteed monsters
+
+# Quylthulg on normal floor
+F:a:1:0:342
+
+# Demonic Quylthulg on normal floor
+F:b:1:0:727
+
+# Draconic Quylthulg on normal floor
+F:c:1:0:759
+
+# Rotting Quylthulg on normal floor
+F:d:1:0:633
+
+# Greater Draconic Quylthulg on normal floor
+F:e:1:0:801
+
+# Greater Rotting Quylthulg on normal floor
+F:f:1:0:802
+
+# Great Hell Wyrm on normal floor
+F:g:1:0:756
+
+# Master Quythulg on normal floor
+F:h:1:0:821
+
+### Random monsters and/or items
+
+# Random monster (upto 5 levels ood) on normal floor
+F:&:1:0:*90
+
+# Random monster (upto 11 levels ood) on normal floor
+F:@:1:0:*96
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on normal floor
+F:8:1:0:*94:*92
+
+# Random monster (upto 40 levels ood) and
+# Random object (upto 20 levels ood
+F:9:1:0:*125:*105
+
+### Guaranteed items
+
+# The Ring of Power 'Narya' on normal floor
+F:1:1:0:0:0:0:10
+
+
+### Level design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X*****...@%...aX.X9@********%%%%%%X9.VV....Xd.............A^^.......dX
+D:X*****...@%...aX.X@@********%%%%%%X.VVVV.X.XX.............B^^........X
+D:X*****...@%...aX.X99*XXX****%%88%%XVVWWVVX..XX.............^^.......9X
+D:X*****...@%...aX.X@@XXdXX***%%88%%XVVWWVVX...XX............^^.......CX
+D:X*****...@%...aX.X@XX...XX**%%%%%%X.VVVV.X.X..XX..........5^^........X
+D:X........@%...aX.XXX.....XX*%%%%%%X9.VV..X.XX..XX.........F^^.......dX
+D:X%X......@%...aX.X........XIXXXXXXXXXXX..X..XX..XXXXIXXXXXXXXXXXXXXXXX
+D:X.XXX....@%...aX.X..........XXX..>X...X..X...XX..XXXaXaXaXaXaXaXaXaXaX
+D:X...XXX..@%...aI.X..........XXX7..X...D..X.X..XX..XX.................X
+D:X.....XXX@%...aX.X..........XXXXXXXXXXX..X.XX..XX..XX................X
+D:X.......XXX...aX.X..........XXXXXXXaG....X..XX..XX..XX...............X
+D:X..X......XXX.XX%XX^^^^^X...XXXXXXXaG....X...XX..XX..XX..............X
+D:X^^XX.......XXX***X^^^^^X...XIIII7XXXXXXXXXX..XX..XX..XXXXXXXXXXXX+X8X
+D:X^^XX.........X.6.X^^^^^X...XIXXXXX&&&&&&&&XX..XX..XX...........cX.XXX
+D:X..XXX........X***X^^^^^X...XIXXXXX.........XX..XX..XXXXXXXXXXXXXX..XX
+D:X^^X8X........XXXXX^^^^^X...XIIIIIXVVV.......XX..XX.............bXX..X
+D:X..X8XX................XX...XXXXXIXVVVV.......XX..XXXXXXXXXXXXXXXXXX+X
+D:X^^X88X................XX...XIIIIIXVVVVVV..@...XX.^^^^^^^^^^^^^a.....X
+D:X^^X99XX...............XX...XIXXXXX4..VVVV......XXXXXXXXXXXXXXXXXXXXXX
+D:X..X999X...............XX...XIXXXXXXXXX.VVVV....***********.........bX
+D:X^^XIIIXX..............XX...XIX...5..fX...VVVVV.@....................X
+D:X..X....X........d.....XX...XIXf......X...VVVVVVV...............@....X
+D:X^^X....XX............XXX...XIXXXXXXXXX.......VVVVVVV................X
+D:X^^X&&&&&X............XXX...XIIIIIXe...........VVVVVVVVVVVV..........X
+D:X..X%%%.%XX..........XXX....XXXXXIX.............@VVVVVVVVVVVV@.......X
+D:X^^X88%.%8X.........XXX.....XXXXXIX...................VVVVVVVVVV.....X
+D:X..X%%%.%%XX........XX......XXXXXIX@.....................VVVVVVVVVVVVX
+D:X^^X......cX......XXXX......XXXXXIX........@..........@....VVVVVVVVVVX
+D:X^^^......cXX888XXXXX......dIIIIIIX.........................b.VVV...6X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXgLLLLLgXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLLLXXLLLLLLXXXXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXgLLLLLXXXXXgLLLLLLLXXgXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXLLLLgXXXXXXXXXXXXXXLLLLLLLXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXLLXXXXXXXXXXXXXXXXXXgXXXLLLgXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXLgXXXXXXXXXXXXXXXXXXXXXXXXLLLLXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXfXXXXXXXXLXXXXXXXXXXXXXXXXXXXXXXXXXgLLLLXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXX.XXXXXXXghgXXXXbXXXXXXXXaXXXXXXXXXXXXXXLLLLgXXXXXXX
+D:XXXXXXXXXXXXXXXXXXX.XXXXXXXg1gXXXX.XXXXXXXX.XXXXXXXXXXXXXXXXgLLXXXXXXX
+D:XXXXXXXXXXXXXXXXXXX^XXXXXXXXXXXXXX^XXXXXXXX^XXXXXXXXXXXXXXXXXXLXXXXXXX
+D:XXXXXXXXXXXXXXX4..^^^..^^^.......^^^......^^^.........EXXXXXXXLXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXX^XXXXXXXXX^XXXXXXXX^XXXXXXXXXXXXXXXXXLLXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXX.XXXXXXXX.XXXXXXXXXXXXXXXXLLLXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXcXXXXXXXXaXXXXXXXXXXXXXXXLLXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXeXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXgLLLXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLLXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLXgXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXLLXXXXXXXXXXXXXXX
+D:X...dXXXXXXXXXXe..0XXXXXXXXXXXXXXXD..EXXXXXXXXXXXXXXLLXXXXXXXXXXXcc..X
+D:X...dXXXXXXXXXX....XXXXXXXXXXXXXXX....XXXXXXXXXXXXXX.XXXXXXXXXXXX....X
+D:XA...XXXXXXXXXXF..eXXXXXXXXXXXXXXXC...XXXXXXXXXXXXXX0XXXXXXXXXXXX...BX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+
+# Starting location
+P:11:37
diff --git a/lib/mods/theme/edit/s_info.txt b/lib/mods/theme/edit/s_info.txt
new file mode 100644
index 00000000..40c0d41e
--- /dev/null
+++ b/lib/mods/theme/edit/s_info.txt
@@ -0,0 +1,542 @@
+# File: s_info.txt
+
+
+# This file is used to initialize the "lib/data/s_info.raw" file, which is
+# used to initialize the "skills" information for the PernAngband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/data/s_info.raw" file.
+
+# The skill indexes are defined in "defines.h", and must not be changed.
+
+# N:idx:name
+# D:desc
+# A:action mkey:action desc
+# I:rate
+
+# E:exclusive skill:exclusive skill
+# O:skill:opposing skill%percent
+# A:skill:friendly skill%percent
+
+# T:father:child
+
+# Version stamp (required)
+
+V:2.0.0
+
+################################## MAGIC ##################################
+
+N:56:Magic-Device
+D:Eases the use of magical devices, such as wands, staves and rods
+D:It also helps pseudo-id of magic objects
+I:1000
+F:RANDOM_GAIN
+
+N:54:Spell-learning
+D:You should not see that ! that is a BUG!
+#A:18:Learn a spell from a realm
+I:1000
+F:HIDDEN
+
+N:41:Sorcery
+D:Ability to use all the magic schools as if their skill was sorcery
+D:But the price to channel that much magic is your health
+A:17:Cast a spell
+I:1000
+
+N:1:Conveyance
+D:Ability to learn and use spells from the Conveyance school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+F:RANDOM_GAIN
+
+N:2:Mana
+D:Ability to learn and use spells from the Mana school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:3:Fire
+D:Ability to learn and use spells from the Fire school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:4:Air
+D:Ability to learn and use spells from the Air school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:5:Water
+D:Ability to learn and use spells from the Water school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:6:Nature
+D:Ability to learn and use spells from the Nature school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+F:RANDOM_GAIN
+
+N:7:Earth
+D:Ability to learn and use spells from the Earth school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:10:Divination
+D:Ability to learn and use spells from the Divination school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+F:RANDOM_GAIN
+
+N:11:Temporal
+D:Ability to learn and use spells from the Temporal school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:14:Meta
+D:Ability to learn and use spells from the Meta school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:51:Mind
+D:Ability to learn and use spells from the Mind school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:55:Udun
+D:Ability to learn and use spells from the Udun school
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+F:HIDDEN
+
+N:13:Demonology
+D:Ability to use incantations from the Demonblades
+D:Spells use the intelligence stat
+A:17:Cast a spell
+I:1000
+
+N:31:Necromancy
+D:Ability to harness the powers of the dead
+D:Spells use the intelligence stat
+A:7:Use Necromancy
+I:1000
+F:RANDOM_GAIN
+G:60
+
+N:34:Runecraft
+D:Ability to combine magic runes to create your own spells
+D:Runespells use the dexterity stat
+A:9:Use Runespells
+I:1000
+
+N:43:Thaumaturgy
+D:Ability to gain and cast innate spells
+D:Spells use the intelligence stat
+A:8:Cast a thaumaturgy spell
+I:1000
+F:RANDOM_GAIN
+
+N:15:Magic
+D:General ability to do magic, also affects mana reserves and
+D:magic device ability. Helps pseudo-id of magic objects
+A:19:Copy a spell
+I:1000
+F:RANDOM_GAIN
+
+N:45:Spell-power
+D:Ability to increase the power of spells
+I:1000
+
+N:59:Geomancy
+D:Ability to understand the raw elemental forces of nature and use
+D:them to your advantage. Most spells need Fire/Water/Earth/Air skills
+A:101:Use Geomancy
+I:1000
+
+# All magic skills affect magic skill
+f:Magic-Device:Magic%7
+f:Spell-power:Magic%20
+f:Sorcery:Magic%20
+f:Mana:Magic%10
+f:Fire:Magic%10
+f:Air:Magic%10
+f:Water:Magic%10
+f:Earth:Magic%10
+f:Geomancy:Fire%45
+f:Geomancy:Earth%45
+f:Geomancy:Air%45
+f:Geomancy:Water%45
+f:Conveyance:Magic%10
+f:Divination:Magic%10
+f:Nature:Magic%10
+f:Temporal:Magic%10
+f:Meta:Magic%10
+f:Mind:Magic%10
+f:Udun:Magic%10
+f:Demonology:Magic%10
+f:Necromancy:Magic%4
+f:Runecraft:Magic%12
+f:Thaumaturgy:Magic%6
+
+
+
+################################## COMBAT ##################################
+
+N:16:Combat
+D:General ability to fight and to pseudo-id armour and weapons
+D:It also allows the use of heavier armour without penalties
+I:1000
+F:RANDOM_GAIN
+
+N:17:Weaponmastery
+D:General ability to use melee weapons
+I:1000
+F:RANDOM_GAIN
+
+N:18:Sword-mastery
+D:Ability to use swords
+I:1000
+
+N:19:Axe-mastery
+D:Ability to use axes
+I:1000
+
+N:20:Polearm-mastery
+D:Ability to use polearms
+I:1000
+
+N:21:Hafted-mastery
+D:Ability to use hafted weapons
+I:1000
+
+N:22:Backstab
+D:Ability to backstab fleeing and sleeping monsters to increase damage
+I:1000
+
+N:23:Archery
+D:General ability to use ranged weapons
+I:1000
+F:RANDOM_GAIN
+
+N:24:Sling-mastery
+D:Ability to use slings
+A:23:Fire piercing shots
+I:1000
+
+N:25:Bow-mastery
+D:Ability to use bows
+A:23:Fire piercing shots
+I:1000
+
+N:26:Crossbow-mastery
+D:Ability to use crossbows
+A:23:Fire piercing shots
+I:1000
+
+N:27:Boomerang-mastery
+D:Ability to use boomerangs
+I:1000
+
+N:58:Boulder-throwing
+D:Ability to make and throw boulders
+A:21:Tear down a wall to create boulders
+I:1000
+F:RANDOM_GAIN
+
+N:42:Barehand-combat
+D:Ability to fight barehanded
+I:1000
+F:RANDOM_GAIN
+G:70
+
+N:47:Bearform-combat
+D:Ability to fight in bear form
+I:1000
+F:HIDDEN | AUTO_HIDE
+
+N:52:Critical-hits
+D:Ability to deal critical hits with swords < 5lb
+I:1000
+
+N:57:Stunning-blows
+D:Ability to stun opponents when doing critical hits with hafted weapons > 5 lb
+I:1000
+
+# List of combat friendly skills
+
+# Melee: Specific masteries improve generic mastery
+f:Critical-hits:Sword-mastery%5
+f:Sword-mastery:Weaponmastery%25
+f:Axe-mastery:Weaponmastery%25
+f:Polearm-mastery:Weaponmastery%25
+f:Stunning-blows:Hafted-mastery%5
+f:Hafted-mastery:Weaponmastery%25
+
+# Ranged: Specific masteries improve generic mastery
+f:Sling-mastery:Archery%25
+f:Bow-mastery:Archery%25
+f:Crossbow-mastery:Archery%25
+f:Boomerang-mastery:Archery%25
+
+# All combat skills improve Combat
+f:Weaponmastery:Combat%50
+f:Sword-mastery:Combat%7
+f:Axe-mastery:Combat%7
+f:Polearm-mastery:Combat%7
+f:Hafted-mastery:Combat%7
+f:Archery:Combat%50
+f:Sling-mastery:Combat%7
+f:Bow-mastery:Combat%7
+f:Crossbow-mastery:Combat%7
+f:Boomerang-mastery:Combat%7
+f:Barehand-combat:Combat%50
+f:Boulder-throwing:Combat%40
+
+# No more, let's see how it turns out
+# Sorcery and Weaponmastery aren't exactly friendly to each other
+#O:Sorcery:Weaponmastery%100
+#O:Sorcery:Archery%100
+#O:Sorcery:Barehand-combat%100
+#O:Weaponmastery:Sorcery%100
+#O:Archery:Sorcery%100
+#O:Barehand-combat:Sorcery%100
+
+
+
+############################### SPIRITUALITY SKILLS ###########################
+
+N:28:Spirituality
+D:General ability to use spiritual skills and also influence your Saving Throw
+I:1000
+F:RANDOM_GAIN
+
+N:53:Prayer
+D:Ability to learn and use spells from the gods' schools
+D:Spells use the wisdom stat and cost piety instead of mana
+A:17:Cast a spell
+I:1000
+
+N:12:Druidistic
+D:Ability to learn and use prayers from the Druidistic realm
+D:Nature powers use the wisdom stat
+A:1:Cast a druidistic spell
+I:1000
+
+N:29:Mindcraft
+D:Ability to focus the powers of the mind
+D:Mindpowers use the wisdom stat
+A:2:Use Mindcraft
+I:1000
+F:RANDOM_GAIN
+G:50
+
+N:9:Music
+D:Ability to learn and sing songs
+D:Songs use the charisma stat
+A:17:Cast a spell
+I:1000
+
+f:Prayer:Spirituality%10
+f:Druidistic:Spirituality%10
+f:Mindcraft:Spirituality%10
+f:Music:Spirituality%10
+
+f:Prayer:Magic%10
+f:Druidistic:Magic%10
+f:Mindcraft:Magic%10
+f:Music:Magic%10
+
+
+################################## MISC SKILLS ###############################
+
+N:30:Misc
+D:Not a real skill, it is only used to regroup some skills
+I:0
+
+N:33:Antimagic
+D:Ability to generate an antimagic field
+A:3:Use antimagic
+I:1000
+F:RANDOM_GAIN
+G:80
+
+# Antimagic exclude all magic
+E:Magic-Device:Antimagic
+E:Mana:Antimagic
+E:Geomancy:Antimagic
+E:Fire:Antimagic
+E:Air:Antimagic
+E:Water:Antimagic
+E:Earth:Antimagic
+E:Conveyance:Antimagic
+E:Divination:Antimagic
+E:Temporal:Antimagic
+E:Meta:Antimagic
+E:Mind:Antimagic
+E:Nature:Antimagic
+E:Udun:Antimagic
+E:Sorcery:Antimagic
+E:Demonology:Antimagic
+E:Runecraft:Antimagic
+E:Necromancy:Antimagic
+E:Mindcraft:Antimagic
+E:Music:Antimagic
+E:Prayer:Antimagic
+E:Druidistic:Antimagic
+E:Thaumaturgy:Antimagic
+
+################################## SNEAKINESS SKILLS ###############################
+
+N:35:Sneakiness
+D:General ability at the sneakiness skills.
+D:It also affects the searching abilities
+I:0
+F:RANDOM_GAIN
+
+N:36:Stealth
+D:Ability to move unnoticed, silently
+I:0
+F:RANDOM_GAIN
+
+N:37:Disarming
+D:Ability to disarm the various traps
+I:0
+F:RANDOM_GAIN
+
+N:40:Stealing
+D:Ability to steal objects
+A:15:Steal object
+I:0
+
+N:46:Dodging
+D:Ability to dodge blows and bolts
+A:16:Check dodge chance
+I:0
+
+f:Stealth:Sneakiness%15
+f:Disarming:Sneakiness%10
+f:Backstab:Sneakiness%5
+f:Stealing:Sneakiness%15
+f:Dodging:Sneakiness%10
+
+
+################################## MONSTER SKILLS ################################
+
+N:48:Monster-lore
+D:General ability at the monster related skills, ability to gain experience
+D:from friendly kills. It also affects the number of companions you can have
+I:0
+A:22:Turn pet into companion
+F:RANDOM_GAIN
+
+N:44:Summoning
+D:Ability to create totems from monsters and use them to summon monsters
+A:13:Manipulate totems
+I:1000
+F:RANDOM_GAIN
+G:60
+
+N:49:Corpse-preservation
+D:Ability not to destroy the monsters' corpses when killing them
+I:0
+
+N:50:Possession
+D:Ability to incarnate into monsters
+A:11:Use the possession skill
+I:0
+
+N:8:Symbiosis
+D:Ability to enter in symbiosis with monsters unable to move by themselves
+D:Spells use the intelligence stat
+A:20:Use symbiotic powers
+I:1000
+F:RANDOM_GAIN
+G:70
+
+N:32:Mimicry
+D:Ability to use cloaks of mimicry to change form
+A:6:Use Mimicry
+I:1000
+F:RANDOM_GAIN
+G:80
+
+f:Possession:Monster-lore%10
+f:Corpse-preservation:Monster-lore%10
+f:Summoning:Monster-lore%10
+f:Symbiosis:Monster-lore%10
+f:Mimicry:Monster-lore%10
+
+################################## SKILL TREE ################################
+
+T:Main:Combat
+T:Combat:Weaponmastery
+T:Weaponmastery:Sword-mastery
+T:Sword-mastery:Critical-hits
+T:Weaponmastery:Axe-mastery
+T:Weaponmastery:Hafted-mastery
+T:Hafted-mastery:Stunning-blows
+T:Weaponmastery:Polearm-mastery
+T:Combat:Archery
+T:Archery:Sling-mastery
+T:Archery:Bow-mastery
+T:Archery:Crossbow-mastery
+T:Archery:Boomerang-mastery
+T:Combat:Barehand-combat
+T:Combat:Bearform-combat
+T:Combat:Boulder-throwing
+T:Combat:Antimagic
+
+T:Main:Sneakiness
+T:Sneakiness:Stealth
+T:Sneakiness:Disarming
+T:Sneakiness:Backstab
+T:Sneakiness:Stealing
+T:Sneakiness:Dodging
+
+T:Main:Magic
+T:Magic:Magic-Device
+T:Magic:Spell-power
+T:Magic:Sorcery
+T:Magic:Mana
+T:Magic:Geomancy
+T:Magic:Meta
+T:Magic:Conveyance
+T:Magic:Divination
+T:Magic:Temporal
+T:Magic:Mind
+T:Magic:Nature
+T:Magic:Udun
+T:Magic:Demonology
+T:Magic:Necromancy
+T:Magic:Runecraft
+T:Magic:Thaumaturgy
+
+T:Geomancy:Fire
+T:Geomancy:Water
+T:Geomancy:Air
+T:Geomancy:Earth
+
+T:Main:Spirituality
+T:Spirituality:Prayer
+T:Spirituality:Mindcraft
+T:Spirituality:Music
+
+T:Main:Monster-lore
+T:Monster-lore:Summoning
+T:Monster-lore:Corpse-preservation
+T:Monster-lore:Possession
+T:Monster-lore:Symbiosis
+T:Monster-lore:Mimicry
diff --git a/lib/mods/theme/edit/s_name.map b/lib/mods/theme/edit/s_name.map
new file mode 100644
index 00000000..795d8786
--- /dev/null
+++ b/lib/mods/theme/edit/s_name.map
@@ -0,0 +1,110 @@
+# Special level "The Nameless Level" in the Pits of Angband
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Written by Mynstral (mynstral@thehelm.com)
+
+%:special.txt
+
+# Great Storm Wyrm on normal floor
+F:a:1:0:728
+
+# Mature Red Dragon on normal floor
+F:b:1:0:589
+
+# Mature White Dragon on normal floor
+F:c:1:0:549
+
+# Ancient Blue Dragon on normal floor
+F:d:1:0:601
+
+# Ancient Black Dragon on normal floor
+F:e:1:0:624
+
+# Ancient Multi-hued Dragon on normal floor
+F:f:1:0:675
+
+# Great Hell Wyrm on normal floor
+F:g:1:0:756
+
+# Great Wyrm of Many Colours on normal floor
+F:h:1:0:790
+
+# Great Ice Wyrm on normal floor
+F:i:1:0:741
+
+# Sky Drake on normal floor
+F:j:1:0:793
+
+### Random Monsters and/or Items
+# Random monster (upto 5 levels ood) on normal floor
+F:&:1:0:*100
+
+# Random monster (upto 11 levels ood) on normal floor
+F:@:1:0:*106
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on normal floor
+F:8:1:0:*104:*102
+
+# Random monster (upto 40 levels ood) and
+# Random object (upto 20 levels ood
+F:9:1:0:*135:*115
+
+# Random monster (upto 3 levels ood)
+F:-:1:0:*98
+
+# Random object (upto 7 levels ood)
+F:=:1:0:0:*102
+
+### Guaranteed Items
+# The Multi-Hued Dragon Scale Mail 'Razorback' on normal floor
+F:1:1:0:0:0:0:16
+
+### Level Design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X.....LLLLLLLLL.....XXX.G=-&&=-G^.........>X
+D:X.LLL...........LLLXX...G=-&.=-G^........1.X
+D:X.L9L.LLLLLLLLLLLLX%...EGE.=&.FG^..........X
+D:X.L99.L&..........X%....G..&-..G^....j.....X
+D:X.LLLLL&LLLLLLLLL.LXX...G=-=&-=G^..........X
+D:X....&&&L.......L.L*XXX.G-=&&-=G^^^^^^^^^^^X
+D:XLLLLLLLL.LLLLL..&L**XXXXXXXGGGG%XXXXXXXXXXX
+D:XXXXXXLL..L***LLLLLLLX^^^^8Xi....%@@^^.^^@@X
+D:X5..8X.&.XXXXXX......D^^^^8XIIIIIXbb^^.^^ccX
+D:X...8X...XA...X.LLLLLX^^^^8X.....X..^^.^^..X
+D:X...8X.XXXC...X.LL...XXXIXXX^^^^^X..^^.^^..X
+D:XGXXXX.LfX7...X&LL.L.Xa^^^aXf...fX..^^.^^..X
+D:X.X5XL.L*XB...X&&..L.X^b^b^X^^^^^X..^^.^^..X
+D:X.X^XL.L*XXXXXXLLLLL.X^^7^^X.....X..^^.^^..X
+D:X.X^XL.L***fXL.....&&X^b^b^XIIIIIX..^^.^^..X
+D:X.X^XL.LLLLLXL.LLLLLLXa^^^aXi....X..^^.^^..X
+D:X.X^XL.........XXXXXXXXX%XXXXXXXXX..^^.^^..X
+D:X.X^XXXXXXXXXXLX^...^Xe-^=dX^^..&X..^^.^^..X
+D:X.X^^^^^^^^^^XLX.^^^.X-^^^=X^^..&X..^^.^^..X
+D:X.XXXXXXXXXX^X8Xf^B^.%^^6^^%^^C.&X..^^.^^..X
+D:X.LLLLLLLLL+^XXX.^^^.X-^^^=X^^..&X..^^.^^..X
+D:X.XXXXXXXXXXXXXX^...^Xd-^=eX^^..&X..^^.^^..X
+D:X.Xbbbbb......XXXXXXXXXX%XXXXXXXXX..^^.^^..X
+D:X.XbbbbXXXX^^^^XX....X^^^^^X...h.X..^^.^^..X
+D:X.XbbbXX^^XXX^^^XX...X^ccc^X....0X..^^.^^..X
+D:X.XbbXX.^X%bXX^^^XX..X^.A.^X.....X..^^0^^..X
+D:X.IbXX..XXbbbXX^^^XX.X^ccc^XIXXXXXXXXXXXXXXX
+D:X.XXX..XX.....X%^^^XXX^^^^^XlllllllllllllllX
+D:X.X99.XXW......XX^^^XXXXXXXXlllllllllllllllX
+D:X.X99XXWWW...a..XX^^.XXllllllLLLLLlXXXX%XXXX
+D:X.XXXX..WWW.....cXX^.XXXXXlllllllllXVVVVVVVX
+D:X.X8.....WWW....ccX^.X^^^XLLLlLLLLLXVVVVVVVX
+D:X.X%XXXXXXXWW...cXXX.X+X^XlllllllllXV%%%%%VX
+D:X.X.......XWWW..X%^X.XLX^XlLLLLLLLLXV%8^8%VX
+D:X.XXXXXX%.X.WWWXX^^X.XLX^XlllllllllXV%^a^%VX
+D:X.X.IIIIX.X..WXX..XXcXLX^XLLLlLLLLlXV%^^^%VX
+D:X.X%XXXIX.X..XX..XXccXLX^XlglllLgllXV%^^^%VX
+D:X.Xa.6XIX.X.XX..XXcccXLX^XlllllXXXXXV%^a^%VX
+D:X+XXX.XIX.X.X99XXccccXLX^XXXXXXX888XV%8^8%VX
+D:X%%%Xa%.X.%8X99XcccccXLX^^^^^^4X...XV%%%%%VX
+D:X%.%XXXXXXXXXXXXIXXXXXLXXXXXXXXX...XVVVVVVVX
+D:X.%%+..........................G..4X...F...X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting Location
+P:43:4
diff --git a/lib/mods/theme/edit/s_orc.map b/lib/mods/theme/edit/s_orc.map
new file mode 100644
index 00000000..62852d47
--- /dev/null
+++ b/lib/mods/theme/edit/s_orc.map
@@ -0,0 +1,109 @@
+# Special level "The Orc Barracks" in the Pits of Angband
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+
+%:special.txt
+
+#Y:40:118:126:149:264:238:285:313:330:404:15:0:0:35:22
+# Shrieker
+F:a:1:0:40
+
+# snaga
+F:b:1:0:118
+
+# cave orc
+F:c:1:0:126
+
+# hill orc
+F:d:1:0:149
+
+# half orc
+F:e:1:0:264
+
+# ogre
+F:f:1:0:238
+
+# ogrillion
+F:g:1:0:285
+
+# bolg
+F:h:1:0:330
+
+# uruk
+F:i:1:0:313
+
+# black orc
+F:j:1:0:244
+
+### Random Monsters and/or Items
+# Random monster (upto 5 levels ood) on normal floor
+F:&:1:0:*35
+
+# Random monster (upto 11 levels ood) on normal floor
+F:@:1:0:*46
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on normal floor
+F:8:1:0:*44:*42
+
+# Random monster (upto 40 levels ood) and
+# Random object (upto 20 levels ood
+F:9:1:0:*75:*55
+
+# Random monster (upto 3 levels ood)
+F:-:1:0:*38
+
+# Random object (upto 7 levels ood)
+F:=:1:0:0:*42
+
+### Guaranteed Items
+
+# The Key of Orthanc
+F:1:1:0:0:0:0:15
+
+### Level Design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:Xa.......................ccccccccc.......................aX
+D:X.lllllllllllllllllllllllllllllllllllllllllllllllllllllll.X
+D:X.l......................ccccccccc.....g.g..............l.X
+D:X.l.XXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXDXXXXXXXXXXXXXX.l.X
+D:X.l.Xa.......efX1Xfe.......aX.X.aaa.D.gX.XacbdddccjjjaX.l.X
+D:X.l.D........efG.Gfe........D.D.bbb.XXXX.XcfbcbcbbjjeeX.l.X
+D:X.l.X........efX.Xfe........X.X.bbb.D.gX.XfbbgdcbdbjjjX.l.X
+D:X.l.XXXXXX...efG.Gfe...XXXXXX.X.bbb.XXXX.XebdcfbdccejjX.l.X
+D:X.l.X.c..XXX.efX.Xfe.XXXcc.aX.D.ccc.D.gX.XcfcbgeebdebfX.l.X
+D:X.l.D..d..aXXXfX.XfXXXe.....D.X.ccc.XXXX.XedbcdbcdcggeX.l.X
+D:X.l.X........XXX.XXX..bbb.ddX.X.ddd.D.gX.XdgfcfegbeebcX.l.X
+D:X.l.X..f.c.bf.G...G.c..cc...X.D.ddd.XXXX.XcbeefccbfbdbX.l.X
+D:X.l.X.d..bb.d.Gi.iG...cbb.bdX.X.eee.D.gX.XbgcfbgcfdebcX.l.X
+D:X.l.X.cc...c..G.7.G.cc..d.e.X.X.eee.XXXX.XcbdfeccdbcdbX.l.X
+D:X.l.X..b.f.bbXGGGGGX.bbb.bb.X.D.f.f.D.gX.XfdebbdgeefgdX.l.X
+D:X.l.D.c..dbbXXa...aXXX..d...D.X.f.f.XXXX.DdefddbcbdbddX.l.X
+D:X.l.X...c.XXX..g.g...XXX...bX.X.....D..XGXXeegcefdcefcX.l.X
+D:X.l.Xbb..aXg.gggjgggg.gX.bbaXDXaaa..XXjIa8XacbddbegbdaX.l.X
+D:X.l.XXXXXXXXDXXXXXXXXDXXXXXXXaXXXXXXXXXXXXXXXXXXXXXXXXX.l.X
+D:X.l........................Da.aD........................l.X
+D:X.l.XXXXXXXXXXXXXXXXXXXXXXXXXaXXXXXXXXXXXXXXXXXXXXXXXXX.l.X
+D:X.l.....eeeeee.........fffXXXDXXXfff.........eeeeee.....l.X
+D:X.l.....eeeeee.........fffX.....Xfff.........eeeeee.....l.X
+D:X.llllllllllllllllllllllllX.....Xllllllllllllllllllllllll.X
+D:Xa.....................XXXXGGGGGXXXX.....................aX
+D:XXXXXXXXXXIXXXXXXXXXXXXXgafff>fffagXXXXXXXXXXXXXIXXXXXXXXXX
+D:XjjjX.#########.XfffXXgggfffffffffgggXXfffX.#########.XjjjX
+D:XfffX...........XeeeXggggjjj...jjjggggXgggX...........XfffX
+D:XfffXGGGDX.XXXXXX...Xgggg....h....ggggX...XXXXXX.XDGGGXfffX
+D:Xgg......X.X........Xgggg.........ggggX........X.X......eeX
+D:Xgg....ggX.X.XXXXXX.XXgggggggggggggggXX.XXXXXX.X.Xee....eeX
+D:Xgg....ggX.X.X......XXXXgggggggggggXXXX......X.X.Xee....eeX
+D:Xgg....ggX.X.X.XXXXXX..XXXXfffffXXXX..XXXXXX.X.X.Xee....eeX
+D:Xgg....ggX.X.X.........#.4XXXDXXX4.#.........X.X.Xee....eeX
+D:Xgg....ggX.X.XXXXXXXXXIXXXXa...aXXXXIXXXXXXXXX.X.Xee....eeX
+D:Xgg....ggX.X.Xigfedcba.XiX..X#X..XiX.abcdefgiX.X.Xee....eeX
+D:Xgg....ggX.X.XGGGGGGGGGX....X.X....IGGGGGGGGGX.X.Xee....eeX
+D:XggggggggX.X.X@@@@@@@@@IXXXaX7XaXXXX@@@@@@@@@X.X.XeeeeeeeeX
+D:XggggggggI.X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X.IeeeeeeeeX
+D:XaaaaagggX.......................................XeeeaaaaaX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting Location
+P:22:31
diff --git a/lib/mods/theme/edit/s_orthanc.map b/lib/mods/theme/edit/s_orthanc.map
new file mode 100644
index 00000000..fd14d3d4
--- /dev/null
+++ b/lib/mods/theme/edit/s_orthanc.map
@@ -0,0 +1,99 @@
+# Special level "Orthanc" in Isengard
+# Created by Burb Lulls; reworked for Theme by furiosity <furiosity@gmail.com>
+
+%:special.txt
+
+### Terrain
+
+# Fire
+F:$:205:0
+
+# Copper Pillar
+F:!:244:0
+
+# Dead Tree
+F:;:92:0
+
+# Tainted Water
+F:~:174:0
+
+# Orthanc's Door
+F:[:248:0
+
+# Ash
+F:,:93:0
+
+### Random Monsters (all lvl80)
+
+# Random monster on ash
+F:a:93:0:*40
+
+# Random monster on normal floor
+F:b:1:0:*40
+
+### Guaranteed Monsters
+
+# Ent on ash
+F:&:93:0:708
+
+# Infernal Device on normal floor
+F:2:1:0:1079
+
+# Guardian - Saruman on normal floor
+F:@:1:0:771
+
+### Guaranteed Item
+
+# The Palantir Of Orthanc on normal floor
+F:1:1:0:0:0:0:202
+
+### Dungeon Design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X;;;;;;;;;;;;;;;;;;;;;;;,,,,,,,,,,a,4,a,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;a;&,a,,,,,~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,X
+D:X;;;;;;;;;;;;;;;;;,,,,,,,,,,,,,,,,,a,a,,,,,,,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;,,,a,a,,,,~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,X
+D:X;;;;;;;;;;;;;;;,,,,,,,,XXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;,,,,,,,,,,,,~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,X
+D:X;;;;;;;;;;;;;,,,,,,XXXXX2^b^.^.^b^.^.^b^.^.^b^.2XXXXX,,,,,,,,,,,,,,,,,,;;;,,,,,,,,,,,,,,,~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,,X
+D:X;;;;;;;;;;,,,,,,XXXX2.^.^.^.XX^.^.^.^.^.^.XX^.^.^.^2XXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,~~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,,,X
+D:X;;;;;;;a,a,,,,XXX2.^.^.^b^.^XX.^.^.^b^.^.^XX.^.^b^.^.^2XXX,,,,,,,,,,,,,a,a,,,,,,,,,,,~~~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,,,,X
+D:X;;;;;;a,7,a,XXX2^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.2XXX~~~~~,,,,,a,&,a,,,,,,,,,~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,,,,,,,X
+D:X;;;;;;,a,aXXX2.^.^XXXXXXXXXXXXXXXXXXDDDXXXXXXXXXXXXXXXGGGGGXXX~~~~,,,,,a,a,,,,,,,,,~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,,,,,,,,X
+D:X;;;;;;,,XXX2^.^.XXX.^.^.^.^.^.XX^.^.^2^.^.^XX.^b^.^.^XXX.^.^.XXX~~~,,,,,,,,,,,,,,,~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,,,,,,,,,,,,X
+D:X;;;;;,,XX2.^.^bXX^.^b^.^.^.^.^XX.^!^.!^.!^.XX^.^.^.^b^.XX.^b^.^XX~~~~,,,,,,,,,,,,,~~~~~~~~~~~~~~~~~,,,,,,,,,,,,,,;;;;;,,,,,,,X
+D:X;;;;;,XX2.^.^.XX^.^.^.GGGG^.^.XX^.^.^.^.^.^XX.^.^GGGG.^.XX.^.^.^XX~~~~~~~~,,,,,,,~~~~~~~~~~~~~~~,,,,,,,,,,,,,,,;;;;;,,,,,,,,,X
+D:X;;;;,,XX.^b^.XX^.^.^.^G$$G.^.^XX.^.^b^.^b^.XX^.^.G$$G^.^.XX.^b^.XX~~~~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,,,,,,,;;;;,,,,,,,,,,,X
+D:X;;;,,XX2^.^.XX^.^.^.^.G$$G^b^.XX^.^.^.^.^.^XX.^b^G$$G.^b^.XX.^.^.XX~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,,,,,,,,;;;;;,,,,,,,,,,,,X
+D:X;;;,,XX^.^.^XX.^.^b^.^GGGG.^.^XX^b!^.!b^!^.XX^.^.GGGG^.^.^XX^.^b^XX.~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,a,a,,,,,,;;;;;;,,,,,,,,,,,,X
+D:X;;,,XX2.^b^XX.^.^.^.^.^.^.^.^.XX^.^.^.^.^.^DD.^.^.^.^.^.^.^XX^.^.^XX,,~~~~~~~~~~~~~~~~~~,,,,,a,a,a,&,a,,,,;;;;;;;;,,,,,,,,,,,X
+D:X;;,,XX^.!.^XX^.^.^.^.^.^.^XXXXXXXXXXXXXXXXXXXXX^.^b^.^.^b^.XX.^!^.XX,,,~~~~~~~~~~~~~~~~~~~,,a,a,&,a,a,,,,,;;;;;;;;;,,,,,,,,,,X
+D:X;,,,XX.^.^.XX.^b^.^.^b^.^XG.^.^.^.^.^.^.^.^.^.XX^.^.^.^.^.^XX^.^b^XX,,,,~~~~~~~~~~~~~~~~~~~a,a,&,&,a,,,,,,;;;;;;;;;;,,,,,,,,,X
+D:X;,,,XX^b!.^XX^.^.^.^.^.^XG.^.lllllll2lllllll.^.XX^.^GGGGG^.GG.^!^.[[,,a,,~~~~~~~~~~~~~~~~~~,a,a,a,a,,,,,,;;;;;;;;;;;;,,,,,,,,X
+D:X;;,,XX.^.^.XX.^.!.^!^.^XG.^.l!^.^.^l^l^.^.^!l.^.XX^.G$$$G.^GG^.^b^[[,,,,,,~~~~~~~~~~~~~~~~~~,a,a,a,,,,,,;;;;;;;;;;;;;;,,,,,,,X
+D:X;;,,XX^.!b^XX^.^.^b^.!.XX^.ll^.^.^.^.^.^.^.^ll.^XX.^G$$$G^.XX.^!^.[[,,,a,,~~~~~~~~~~~~~~~~~~,,,,,,,,,,,;;;;;;;;;;;;;;,,,,,,,,X
+D:X;;,,XX.^.^.XX.^.^2^!^.2GG.^l$$ll.GGG^GGG.ll$$l^.XX^.G$$$G.^XX^.^b^[[,,,,,,~~~~~~~~~~~~~~~~~~~,,,,,,,,,,;;;;;;;;;;;;;,,,,,,,,,X
+D:X;;,,XX^.4.^XX^.^.^.^.^.DD^.ll^.^GG^$@$^GG^.^ll.^XX.^G$$$G^.XX.^.^.[[,,,a,,~~~~~~~~~~~~~~~~~~~,,,,,,,,,;;;;;;;;;;;;;,,,,,,,,,,X
+D:X;;,,XX.^5^.XX.^b^2^.^b^DD.^ll.^.GG^$1$^GG.^.ll^.XX^.G$$$G.^XX^.^b^[[,,,,,~~~~~~~~~~~~~~~~~~~,,,,,,,,,;;;;;;;;;;;;;;,,,,,,,,,,X
+D:X;;,,XX^.^.^XX^.^.^.!.^2GG^.l$$ll2GGG>GGG2ll$$l.^XX.^G$$$G^.XX.^.^.[[,,,a,~~~~~~~~~~~~~~~~~~,,,,,,,,,,,;;;;;;;;;;;;,,,,,,,,,,,X
+D:X;;,,XX.^!^.XX.^.^2^.^!^XX.^ll.^.^.^GGG^.^.^.ll^.XX^.G$$$G.^XX^.!b^[[,,,,~~~~~~~~~~~~~~~~~~,,,,,,,,,,,,;;;;;;;;;;;,,,,,,,,,,,,X
+D:X;,,,XX^b^.^XX^.^.^b^.^.XG^.^l!.^.^.lll.^.^.!l^.^XX.^G$$$G^.GG.^.^.[[,a,~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,;;;;;;;;;;;;,,,,,,,,,,,X
+D:X;;,,XX.^!^.XX.^.!.^!^.^.XG^.^lllllll$lllllll^.^XX.^.GGGGG.^GG^.!b^[[,~~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,;;;;;;;;;;;;;,,,,,,,,,,X
+D:X;;,,XX^.^b^XX^.^.^.^.^.^.XG^.^.^.^.^.^.^.^.^.^XX.^b^.^.^b^.XX.^.^.XX~~~~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,;;;;;;;;;;;;,,,,,,,,,,X
+D:X;;,,XX.^!^.XX.^b^.^.^b^.^.XXXXXXXXXXXXXXXXXXXXX.^.^.^.^.^.^XX^.!b^XX~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,;;;;;;;;;;;,,,,,,,,;X
+D:X;,,,XX2.^.^XX^.^.^.^.^.^.^.^.^XX.^.^.^.^.^.XX6.^.^.^.^.^.^.XX.^.^.XX~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,,,;;;;;;;;;;,,,,,,,,,;X
+D:X;;,,,XX^b^.^XX^.^.^.^.GGGG^.^.XX^.!.^!^.!.^XX7^b^GGGG.^b^.XX.^b^.XX~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,,;;;;;;;;;;;,,,,,,,;;X
+D:X;;;,,XX2^.^.XX.^.^b^.^G$$G.^.^XX.^A2.^.26^.XXA.^.G$$G^.^.^XX^.^.^XX~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,;;;;;;;;;;;,,,,,,;;X
+D:X;;;,,,XX.^.^.XX.^.^.^.G$$G^.^FXX^2^.^C^.^2^XXB^.^G$$G.^.^XX^b^.^XX~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,;;;;;;;;;;;,,,,;;;X
+D:X;;;;,,XX2.^b^.XX.^.^.^GGGG.^.^XX.^52.^.2B^.XXC.^.GGGG^b^XX^.^.^.XX~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,,,;;;;;;;;;;;;;;;X
+D:X;;;;,,,XX2.^.^.XX.^.^b^.^.^b^.XX^.!.^!^.!.^XXE^.^.^.^.^XX^b^.^.XX~~~~~~~~~~~~~~~,,,,,,,~~~~~~~~~~~~~~~~~~,,,,a,a;;;;;;;;;;;;;X
+D:X;;;;,,,,XXX2^.^.XXX^.^.^.^.^.^XX.^.^.^.^.^.XXF.^b^.^.XXX^.^.^XXX~~~~~~~~~,,,,,a,a,,,,,,,~~~~~~~~~~~~~~~~~~,,a,&,a;;;;;;;;;;;;X
+D:X;;;;;,,,,,XXX2^b^.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.^b^.XXX~~~~~~~~~a,a,,,a,&,a,,,,,~~~~~~~~~~~~~~~~~~~~,,a,a,,,,,;;;;;;;;X
+D:X;;;;;;,,,,,,XXX2^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.2XXX~~~~~~~~,,a,&,a,,;a;a,,,,~~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,;;;;;;;X
+D:X;;;;;;;;,,,a,aXXX2.^b^.^b^.^XX.^.^b^.^b^.^XX.^b^.^b^.^2XXX~~~~~~~~,,,,,a,a,;;;;;;,,,~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,,,,,,,,;;X
+D:X;;;;;;;;;;a,&,a,XXXX2.^.^.^.XX^.^.^.^.^.^.XX^.^.^.^2XXXX~~~~~~~~~~~~,,,,,,;;;;;;,,,~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,,,,a,a,X
+D:X;;;;;;;;;;;a,a,,,,,XXXXX2^.^b^.^b^.^b^.^b^.^.^.2XXXXX~~~~~~~~~~~~~~~~~,,,;;;;;,,,,~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,a,&,aX
+D:X;;;;;;;;;;;;;;,,,,,,,,,XXXXXXXXXXXXXXXXXXXXXXXXXX,,~~~~~~~~~~~~~~~~,,,,;;;;;;;;,,,~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,a,a,X
+D:X;;;;;;;;;;;;;;;;;,,,,,,,,,,,,,,,,,a,a,,,,,,,,,,~~~~~~~~~~~~~~~,,,,;;;;;;;;;;;;;,,,~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,,X
+D:X;;;;;;;;;;;;;;;;;;;;;,,,,,,,,,,,,a,E,a,,,,,~~~~~~~~~~~~~~~~~,,;;;;;;;;;;;;;;;;;,,~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting Location
+P:31:125 \ No newline at end of file
diff --git a/lib/mods/theme/edit/s_ship.map b/lib/mods/theme/edit/s_ship.map
new file mode 100644
index 00000000..dbbbe50d
--- /dev/null
+++ b/lib/mods/theme/edit/s_ship.map
@@ -0,0 +1,239 @@
+# s_ship.map
+#
+# Special Level "Arvedui's Galleon" in the Helcaraxe#
+#
+# Created for ToME 3.x on 9/11/03
+#
+# Written by Lord Dimwit (lorddimwit@hotmail.com)
+# Middle-game dungeon
+# Comments: This large level is a variation on the classic 'ghost ship' theme;
+# the ship was caught in the Helcaraxe and everyone on board died. The polar waters
+# surrounding the ship contain some unpleasant surprises for inquisitive and unwary
+# adventurers--the hardest monsters on the map are actually there.
+
+# Ported to ToME 2.x on 6/6/04 by masmarangio
+#
+# Changed the starting position to 28:122
+# Replaced the undefined letter 'c' with '.'
+# The exits of the between gates pointed to incorrect positions.
+# I'm not sure esp. about the correct exit of gate #3.
+
+
+#%:special.txt
+
+
+### Terrain Features
+
+# up staircase
+F:<:6:0
+
+# down staircase
+F:>:7:0
+
+# Permanent wall
+F:X:61:4
+
+# Glacial Wall
+F:#:246:4
+
+# Ice Wall
+F:M:95:4
+
+# Deep Water
+F: :187:4
+
+# Fog
+F:*:210:4
+
+# Shallow water
+F:~:84:4
+
+# Ice
+F:.:90:4
+
+# Hidden Door
+F:+:48:0
+
+# Normal Door
+F:=:32:0
+
+# Ash
+F:,:93:4
+
+# Fake wall
+F:I:189:4
+
+
+### Monsters
+
+# Leviathan in deep water
+F:L:187:0:782
+
+# Greater Kraken in deep water
+F:K:187:0:775
+
+# Lesser Kraken in deep water
+F:k:187:0:740
+
+# Giant Squid in deep water
+F:s:187:0:482
+
+# Killer Whale in deep water
+F:w:187:0:917
+
+# Drowned Soul in shallow water
+F:G:84:0:895
+
+# Ancient White Dragon on ice
+F:D:90:0:617
+
+# Mature White Dragon on ice
+F:d:90:0:549
+
+# Ice Troll on ice
+F:T:90:0:454
+
+# Headless Ghost on ice
+F:H:90:0:533
+
+# Shadow on ice
+F:g:90:0:665
+
+# Young White Dragon on ice
+F:b:90:0:460
+
+# Zombified Human on ice
+F:z:90:0:229
+
+# Greater mummy on ice
+F:m:90:0:522
+
+# Cold Hound on ice
+F:Z:90:0:308
+
+# Giant White Dragon Fly on ice
+F:F:90:0:250
+
+# Ice Elemental on ice
+F:E:90:0:570
+
+# Yeti on ice
+F:Y:90:0:154
+
+# Ice skeleton on ice
+F:i:90:0:379
+
+# Skeleton human on ice
+F:h:90:0:228
+
+# Ghost on ice (apologies to Eldridge Cleever)
+F:W:90:0:477
+
+# Hand druj on ice
+F:S:90:0:748
+
+# Eye druj on ice
+F:J:90:0:749
+
+# Dread on ice
+F:o:90:0:534
+
+# Dreadmaster on ice
+F:O:90:0:690
+
+# Night mare on ice
+F:q:90:0:622
+
+# Random monster (upto 5 levels ood) on ice
+F:&:90:0:*40
+
+# Random monster (upto 9 levels ood) and
+# Random object (upto 7 levels ood) on ice
+F:8:90:0:*44:*42
+
+# Treasure (random) on ice
+F:$:90:0:0:*47
+
+# Treasure (good) on ice
+F:%:90:0:0:*60
+
+# Trap (random) on ice
+F:^:90:0:0:0:0:0:*
+
+# Trap (random) on shallow water
+F:t:84:0:0:0:0:0:*
+
+# Trap (random) on fog
+F:@:210:0:0:0:0:0:*
+
+# Human skeleton on ice
+F:x:90:0:0:395
+
+
+### Between Gates
+
+# between gate 3: was 711
+F:3:160:6:0:0:0:0:0:1136
+
+# between gate A: was 6247
+F:A:160:6:0:0:0:0:0:6761
+
+# between gate 4: was 3339
+F:4:160:6:0:0:0:0:0:3853
+
+# between gate B: was 3085
+F:B:160:6:0:0:0:0:0:3599
+
+
+### Guaranteed Items
+
+# The Mage Staff of Forochel
+F:!:90:0:0:0:0:213
+
+
+### Level Design
+
+D:XXXXXXXXXXXXXXXX XXXXXXXXXXXX XXXXXXX XXXXXXXXXXXXXXX XXXX
+D:X###############..~ .#. k w ~.#XX######### .~~ s G..#####.. w .###.######X##~~ .GX.###
+D:X####%####...~ ~.~ s .#.X#~~.##### .~ s w G..#.##.#.XGG~XXk~.####A####.~X ~~.X...
+D:X##%#$#######...~ w wXXXXXX#XXXX###XXX #~XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..XX....~.XX X#xX.#..#.#G. w ~X G~~
+D:X##$#########.... s XXXTT^...~.~#####w~###~~~~8....**.tE.&E ^^.M^.xx.....x..ZZ..^XTTTT M...GG.~.. w G.###~XX~~#XX . s X
+D:X#########...~ w XXXTTTT.^..x~.H#### ###~~D....8**.~M~.E..M^.MM^..xh.h...ZZZZ^~M.,.,.,.~~ .G...~~ ~###. w . w M.d.
+D:X#####.x.x~~~ XXXTTTXXXMxx.H.####### ~##~~~8...#.**.~tE&EE^^~%M^.h.x.E.xh.ZZ..^X.,.^....~ ...G.~ s ~# XX ~~ w X
+D:X######...~~ MM~ w XXX^^XXX.MMMxx...G#####w ~#~.~..&...**E.MEt.^^.MM^~..i.....ZZZZ^~M.,.,,.gM.~.,~.,G.G~~ G~. G~.MM XX..~
+D:X##.....~~ XXX^E=^XX$b.MMMMxH..HG#.## w ~#~##~8....*E~.&EM^^.M^h..i..x.x..ZZ..^XTTTTX.,.,~........~.G~~..w . G~...G~X
+D:X...~~~ K XXX^^EXXXX$$$..MMXXXXXXX#### #####XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..,.X..M~.........~G..G ~~.G...G~
+D: ~~~ w XXX^^EXXXdX%d$$b$$XXd~~~~##### s ###.,.W.**,.x.,.,.,.,.,.***,,....,x....,,.SX.,.,.,..,o.,.,.~~.G..~.G..G..~X k
+D: w MMM. w XXX^E^XXX.,*XDDd$$$XXd$..~~~~#### ###.,.,.,.**..,.,i.,.,W,.,**..z.,.,.q...g.,......~.,.,.,.,.~.~..F.~M~......~
+D: MM. XXX4EEXXXi^**.XX%%$dXX$d$.H#####~G~~####.~.,~..,.h*,,~,.,.,.,~,.,.,.H.,.~.,..~,.,,,.~,.,.~.,.,.X.~,g.~~..~.~..,..,X
+D: s XXXBXXXXX^.**.W.,XDD%XXb$$b####..G~~~G###~.,,.,.,.,...,,.x,.~.,.,~..,.~.,.,~,.,.,,.,.,~,.,.,.~,.,..,X.,.***.~***,W.,X
+D: XXX.o..X.g***i.*.,.XX%XX######^^^^t ##ttt^^^^^t^^^^^^t^^^^^t^^^^^^^t^^^^^^t^^^^t^^tt^^^tt^^^^t^tXo..x************X
+D: k XXX^E..o.XX8.****,.g..XXX..#........~~~~~ttt###~~.,.G~.......XXXXX..~,..,,..,,.~.,..,.,..,,..,.,x..,.ooX******W***g.*.g*X
+D: XXX%S^^E..ooX,*****,..,.X.....h........XXX~~~tt#tt w ~~G~...XXXXXXX.,**.,..D.**.G.,~,..XXX...~~~.....o8X***.~.,.****$$..X
+D: XX%%%^mm.E..oXH**.^.*i.....#.....i..*..XXXXX~~ G~~.XXXXXXXXX~.*..,.,*..~,..,.,XXXXX...~..,.XXXXXo.W.$$.g.x....o.X
+D: XXX%S^^E..ooX8.*~~...,~~##...,..,.***,.XXX~G~ k ~~~~XXXXXXX.,.*. g...*..x..W.~.XXX.***.,,o..oO8X.o.,.o.xx$$$XXXXX
+D: XXX^E..o.XXH.###....###~~~.,h..,.*.,..~~.~~ s ~~.XXXXX.~..**...i~**.....~.,,.,,.***~,,,.oXXXXXXXXXXXXXXXX.!.X
+D: s XXX.o..X&..w~##..##~~~X~^^^^^^^^^^t^ttt^tt w tt^tttt^^tt^^^^^ttt^^^^ttt@@^^^^ttt^^^^^ttt@^^ttXXXW ^^.M*.t^oo.^^...X s
+D: ~~~ XXX>XXH~G..#####~G~~Gt..,.,..,.,xx..x ~~~ i~~xx.~...x....~.~..~..,~..***..~..~...,~.~*.~.XXXE.^^H..SM.~^.oo....JX
+D: ~~....~~ XXX$8w~.^####G~G ~i.XX.,,.,...........G~~~s~~ iiF~...........~.......x.,.**~....,~....~.*XXX.EE.W.^^.M*.~^^^o^O^..X
+D: ~.#..#..~~ XXX8##t..##~#.G.t..XX..,H...,.W...,...,~~...,...*,,.x...,.i.....g.....**.........XXXXXXX...EE.^^H..SM.~.^oo...^JX
+D: ~.##.##..~ XXX###GG~~~*h~.^..XX.....,....,.W...,.G....W.***...,...,...,....,...,**..q....SX3tttW#...EE.W.^^.M*.t.oo.^.^.XX
+D: ~~.###..~~ X##.##~~G^~~~~i*^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX~~
+D: ~~...###.~ k ~###X.G~~@Gh~x*~^..^i.zX8~i.~..h....zzzXiX..^$.T.t$......F.t..XX..^TTT*..M..Y....^.Y.^*.^..~....X.x..x~.<XX~.
+D: ~.....####.....#####XXXx@@~i~.z..z.it,#**t..h..Gzh.zzX@.@Xd*t.~...*~.t......^X..T.^T*@*TXMM...^....^**@.^.x*...+..~....XX..~
+D: ~~.#$%#########....XXX~h~i.HH...h,i^X*.H..h.^G..WX@.E.^X**8..Y.~*8...Y...^+XXXXXXXXXXXMF...~....^.*..x.***..X..x..~XX...~~w
+D: ~~.#$$######.~ ~w XXX$~.x..~G^..,i.,.~.h.^~~..zzX@.@Xd*......F**..~....^XbM..^~ZZZZXMM..*.....~^......*.XXXXXXXIXX.~~#~w
+D: L ~~xx########.~~ XXX$$.G#GX#.i,,^ih.^W.zG^zzzXiX.$.t88.~..^**F..T...tXX~~.^^ZZZZM~..**@~~.Y~..^#^..xXI&X8&..XX ~~~## w
+D: ~.########..~~ XXXXX~#X~X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ~###~w
+D: ~~.#########..~ w K w ~##### w ~.M.~ ~..####.~ s~~~~.~~ s K ~##..~
+D: ~..#########.~ ~##### ~...~ k ~..###.~ ~~####~~~ w w ~###..~
+D: XXXXXXXXXXXX XXXXXX XXXXXX XXXXXXXXX XXXXXX
+
+
+### Starting Location
+P:28:122
+
+
+
+
+
diff --git a/lib/mods/theme/edit/s_smaug.map b/lib/mods/theme/edit/s_smaug.map
new file mode 100644
index 00000000..f1829e6f
--- /dev/null
+++ b/lib/mods/theme/edit/s_smaug.map
@@ -0,0 +1,78 @@
+# Special level "Lower Halls" in Erebor
+# Created for Theme on 29/09/2004 by furiosity (furiosity@gmail.com)
+
+### Level features ###
+
+# Floor with dirt
+F:,:88:3
+
+# Mountain
+F:M:97:3
+F:X:97:3
+
+# Shallow Water
+F:V:84:3
+
+# down staircase
+F:>:7:3
+
+### Guaranteed monsters (on dirt)###
+
+# Creeping adamantite coins
+F:a:88:5:423
+
+# Creeping mithril coins
+F:b:88:5:239
+
+# Creeping gold coins
+F:c:88:5:195
+
+# Creeping silver coins
+F:d:88:5:117
+
+# Smaug on normal floor
+F:e:88:5:697
+
+### Guaranteed items ###
+# Cup of Thror on dirt
+F:1:88:0:0:0:0:211
+
+# The Arkenstone of Thrain on dirt
+F:2:88:0:0:0:0:3
+
+### Dungeon Design
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X,,,,,,MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMX
+D:X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X
+D:X,M,M,M,M,M,M,MMM,M,M,M,M,M,M,M,M,M,M,M,M,M,MM,,,,,,,,,X
+D:XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,,,,,,,,,X
+D:XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,,,,,,,MMMMMX
+D:XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMdddddddddMMMMMMMX
+D:XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMddddccccddddMMMMMMMMX
+D:XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMddddcccccccddddMMMMMMMMMMX
+D:XMMMMMMMMMMMMMMMMMMMMMMMMMddddaabbbbbaaaccddddMMMMMMMMMX
+D:XMMMMMMMMMMMMMMMMMMMMMMMddddaaabbbbbbbaaaccddddMMMMMMMMX
+D:XMMMMMMMMMMMMMMMMMMMMMddddcaaabbbaaabbbaaaccddddMMMMMMMX
+D:XMMMMMMMMMMMMMMMMMM1ddddccaaabbbaaaaabbbaaacddddMMMMMMMX
+D:XMMMMMMMMMMMMMMVVVMMMddddccaaabbaaeaabbaaacddddMMMMMMMMX
+D:XMMMMMMMMMMMMVVVMMMMddddccaaabbbaaaaabbbaaaccddddMMMMMMX
+D:XMMMMMMMMMMMMMVVVMMddddccccaaabbbaaabbbaaaccddddMMMMMMMX
+D:XMMMMMMMMMMMMMMVVVMMddddccccaaabbbbbbbaaaccccddddMMMMMMX
+D:XMMMMMMMMMMMMVVVMMMMMMddddcccaaabbbbbaaaccccccddddMMMMMX
+D:XMMMMMMMMMMVVVMMMMMMMMMddddcccccccccccccccccccccddddMMMX
+D:XMMMMMMMMMVVVMMMMMMMMMMMddddccccddddMMdMdMMdMM2Mddd,,,,X
+D:XMMMMMMMMMMVVVMMMMMMMMMMMMMddddddddMMMMMMMMMMMMMM,,,,,,X
+D:XMMMMMMMMMVVVMMMMMMMMMMMMMMddddddMMMMMMMMMMMMMMMMMMM,,,X
+D:XMMMMMMMVVVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,X
+D:XMMMMMMMMMVVVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,,X
+D:XMMMMMMMMMMMVVVVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,X
+D:XMMMMMMMMMMMMMVVVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,,X
+D:XMMMMMMMMMMMMMMMVVVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,X
+D:XMMMMMMMMMMMMMMMMVVVVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,X
+D:XMMMMMMMMMMMMMMMMMMVVVVMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,,X
+D:XMMMMMMMMMMMMMMMMMMMMVVVVMMMMMMMMMMMMMMMMMMMMMMMMMMMM,,X
+D:XMMMMMMMMMMMMMMMMMMMMMMMVVVMMMMMMMMMMMMMMMMMMMMMMMMMM,>X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+### Starting Location
+P:3:3 \ No newline at end of file
diff --git a/lib/mods/theme/edit/s_thorin.map b/lib/mods/theme/edit/s_thorin.map
new file mode 100644
index 00000000..52a795e7
--- /dev/null
+++ b/lib/mods/theme/edit/s_thorin.map
@@ -0,0 +1,47 @@
+# Thorin's Trail level with Thorin's key and a bunch of dwarves.
+# Based on Lesser Vault (Cross), tweaked to suit parent dungeon.
+# Map by furiosity <furiosity@gmail.com>
+# Arena-style level (no random treasure except monster drops)
+
+%:special.txt
+
+# Grass with Thorin's key
+F:1:89:0:0:0:0:210
+
+# Grass
+F:,:89:0
+
+# Small tree
+F:t:202:0
+
+### Guaranteed monsters
+
+# Dark dwarven warrior on grass
+F:a:89:0:179
+
+# Dark dwarven smith on grass
+F:b:89:0:180
+
+# Dark dwarven lord on grass
+F:c:89:0:181
+
+# Dark dwarven priest on grass
+F:d:89:0:182
+
+### Dungeon Design
+
+D:XXXXXXXXXXXXXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXX
+D:XXTTc,d,,,,,,,,b,cTTXX
+D:XXTt,d,VXXDXXV,,b,tTXX
+D:XX,,d,VWXa,aXWV,,b,,XX
+D:XX,XXXXXXdcdXXXXXXX,XX
+D:XX,,,,,,Xc1cX,,,,,,,XX
+D:XXXXXXX,XdcdX,XXXXXXXX
+D:XX,,,c,,XbbbXWV,,a,,XX
+D:XXTt,,cVXXXXXV,,a,tTXX
+D:XX>T,,VWX,,,,,,a,cTTXX
+D:XXXXXXXXXX,XXXXXXXXXXX
+D:XXXXXXXXXXXXXXXXXXXXXX
+
+P:13:13 \ No newline at end of file
diff --git a/lib/mods/theme/edit/set_info.txt b/lib/mods/theme/edit/set_info.txt
new file mode 100644
index 00000000..4b745e4b
--- /dev/null
+++ b/lib/mods/theme/edit/set_info.txt
@@ -0,0 +1,254 @@
+# File: set_info.txt
+
+
+# This file is used to initialize the "lib/raw/set_info.raw" file, which is
+# used to initialize the "item set" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# Version stamp (required)
+
+# N:idx:name
+# D:description
+# P:artifact index:number of item needed:pval
+# F:flags
+
+V:2.0.0
+
+# The Elven Gifts, took from Oangband
+
+N:0:Elven Gifts
+D:It is one of two Elven items once entrusted to Hobbits.
+# Phial of Galadriel
+P:1:2:1
+F:WIS | CHR | RES_DARK
+# Sting
+P:88:2:2
+F:STEALTH | REGEN
+
+
+# The Dragon Slayer
+
+N:1:Dragon Slayer
+D:It is one of two items rumoured to be the bane of dragons.
+# Bow of bard
+P:125:2:3
+F:DEX | CON | RES_FIRE
+# Arrow of Bard
+P:63:2:5
+F:SPEED
+
+
+# The Trinity -- Possessor set
+
+N:2:The Trinity
+D:It is one of the 3 legendary daggers.
+# Dagger of Samwise
+P:66:3:1
+F:STR | KILL_DRAGON | REGEN | SH_FIRE
+# Dagger of Peregrin
+P:67:3:1
+F:KILL_DEMON | IM_COLD | CON
+# Dagger of Meriadoc
+P:68:3:1
+F:KILL_UNDEAD | SH_ELEC | FLY | DEX
+
+
+# Gothmog's Armoury -- Demonologists' set
+
+N:3:Gothmog's Armoury
+D:It is one of three items that once belonged to Gothmog,
+D:the High Captain of the Balrogs.
+# The demonblade of Gothmog
+P:181:3:7
+F:STR | CON | SPEED | VAMPIRIC
+# The demonshield of Gothmog
+P:182:3:0
+F:IM_FIRE | IM_COLD | SH_ELEC
+# The demonhorn of Gothmog
+P:183:3:0
+F:ESP_EVIL | ESP_GOOD | AUTO_ID
+
+### New sets added in Theme ###
+
+# Thorin Oakenshield's gear - bards might find this useful :)
+
+N:4:Thorin's Gear
+D:It is one of three items that once belonged to
+D:Thorin Oakenshield, King under the Mountain.
+# The small metal shield of Thorin
+P:30:3:2
+F:CHR | ESP_TROLL
+# The golden harp of Thorin
+P:135:3:4
+F:INT | SUST_INT
+# The mithril helm of Thorin
+P:136:3:4
+F:WIS | SUST_WIS
+
+# Peregrin Took's gear - adapted from T-Plus by Ingeborg S. Norden
+
+N:5:Peregrin's Gear
+D:It is one of two items that once belonged to the hobbit
+D:hero, Peregrin Took.
+# Chain Mail of Peregrin Took
+P:165:2:0
+F:RES_CONF | RES_NEXUS | SUST_STR
+# Elven Cloak of Peregrin Took
+P:184:2:2
+F:DEX | SUST_DEX | CHR | SUST_CHR | SLOW_DIGEST |
+
+# Ghan-buri-Ghan's Garb - suggested by ShinesmanOffWhite in the forums
+
+N:6:Ghan-buri-Ghan's Garb
+D:It is one of two items that once belonged to
+D:the leader of the Druedain.
+# The Filthy Rag of Ghan-Buri-Ghan
+P:189:2:0
+F:IM_COLD | IM_ACID
+# The Cloak of Ghan-buri-Ghan
+P:190:2:0
+F:ESP_ALL
+
+# Requisites of the King of Gondor - suggested by ShinesmanOffWhite in the forums
+
+N:7:The Glory of the King
+D:It is one of three items belonging to the Kings of
+D:Gondor.
+# The Long Sword 'Anduril'
+P:83:3:0
+F:BRAND_ELEC | KILL_DEMON | KILL_DRAGON | SLAY_UNDEAD | IM_FIRE |
+# The Black Banner of Gondor
+P:191:3:0
+F:LITE3
+# The Golden Crown of Gondor
+P:42:3:0
+F:ESP_ALL
+
+# Saruman's stuff - suggested by ShinesmanOffWhite in the forums
+
+N:8:Saruman's Travel Gear
+D:It is one of three items belonging to the Istari wizard Saruman.
+# The Mage Staff of Saruman
+P:192:3:0
+F:REFLECT | FREE_ACT
+# The Robe of Curunir
+P:193:3:0
+F:RES_FIRE | RES_ACID | RES_POIS | RES_DARK | RES_BLIND | RES_SOUND |
+# The Palantir of Orthanc
+P:202:3:0
+F:AUTO_ID
+
+# Heirlooms of the House of Elendil - set suggested by Massimiliano Marangio in the forums
+
+N:9:Elendil's Heirlooms
+D:It is one of three items belonging to the House of Elendil.
+# The Ring of Barahir
+P:8:3:0
+F:RES_LITE | RES_BLIND |
+# The Star of Elendil
+P:2:3:1
+F:STR | INT | WIS | DEX | CON | CHR | LUCK |
+# The Rod of Annuminas
+P:199:3:0
+F:RES_FEAR | ESP_EVIL
+
+# Flame of Wrath - from Oangband
+
+N:10:Flame of Wrath
+D:It is one of two items infused with holy fire.
+# The Amulet of Annatar
+P:4:2:1
+F:WIS | IM_FIRE | RES_FEAR
+# The Morning Star 'Naurgil'
+P:115:2:4
+F:STR | SLAY_EVIL | SLAY_UNDEAD
+
+# Light/Dark Set - from Oangband
+
+N:11:Shadow Ward
+D:It is one of two items rumoured to defy the Shadow.
+# The Soft Leather Armour 'Hithlomir'
+P:168:2:2
+F:SEARCH | RES_BLIND
+# The Set of Leather Gloves 'Cammithrim'
+P:53:2:2
+F:DEX | SUST_DEX
+
+# Eorl/Rohan Set - from Oangband
+
+N:12:Eorl's Arms
+D:It is one of two items that once belonged to Eorl the Young,
+D:valiant hero of the Mark.
+# Lance of Eorlingas
+P:100:2:1
+F:FREE_ACT
+# The Metal Brigandine Armour of the Rohirrim
+P:21:2:0
+F:CON | REGEN
+
+# Gil-Galad's Set - from Oangband
+
+N:13:Gil-Galad's Battle Gear
+D:It is one of three pieces of the battle gear of Gil-Galad,
+D:mighty Elven king of old.
+# The Shield of Deflection of Gil-Galad
+P:169:3:0
+F:RES_FIRE | RES_POIS | SUST_CON
+# The Spear 'Aiglos'
+P:97:3:0
+F:SLAY_DEMON | RES_NETHER
+# The Mithril Helm of Gil-Galad
+P:26:3:0
+#Why *shouldn't* warrior-types get a chance for AUTO_ID without penalties to luck before they kill Morgy?
+F:AUTO_ID
+
+# Dwarven Heritage
+# http://wiki.t-o-m-e.net/IdeaArchive_2fNew_20Item_20Set_3a_20Heritage_20of_20Khazad
+
+N:14:Dwarven Heritage
+D:It is one of three Dwarven items of legend.
+# The Arkenstone of Thrain
+P:3:3:0
+F:SUST_STR | FREE_ACT | SUST_CON
+# Mattock of Nain
+P:174:3:6
+F:CON
+# Lochaber Axe of the Dwarves
+P:105:3:0
+F:IM_ACID | RES_SHARDS | SUST_DEX | SUST_WIS | REFLECT
+
+# Woodland Realm (bow of Legolas, staff of Thranduil, cap of Thranduil)
+
+N:15:Woodland Realm
+D:It is one of three items belonging to the Wood-elves of Mirkwood.
+# The Hard Leather Cap of Thranduil
+P:36:3:1
+F:SUST_INT | SUST_WIS | SPEED
+# The Long Bow of Legolas
+P:224:3:2
+F:SUST_DEX | SPEED
+# The Quarterstaff of Thranduil
+P:74:3:0
+# What can I say. I love archers. :P
+F:AUTO_ID
+
+# Gimli's Gear (Gimli's shield, boots and axe)
+
+N:16:Gimli's Gear
+D:It is one of three items belonging to Gimli the dwarf.
+# The Small Metal Shield of Gimli
+P:132:3:0
+F:SUST_STR | SUST_CON | SUST_INT
+# The Bearded Axe of Gimli
+P:133:3:0
+F:SLAY_EVIL | SLAY_GIANT | BRAND_FIRE
+# The Pair of Metal Shod Boots of Gimli
+P:180:3:5
+F:LUCK
+
+# N:idx:name
+# D:description
+# P:artifact index:number of item needed:pval
+# F:flags
diff --git a/lib/mods/theme/edit/special.txt b/lib/mods/theme/edit/special.txt
new file mode 100644
index 00000000..8d1c94b9
--- /dev/null
+++ b/lib/mods/theme/edit/special.txt
@@ -0,0 +1,67 @@
+# Contains terrain parsings for the special levels now being kept in seperate map files
+#
+# Created for PernAngband 5.0.1 on 18/8/01
+# Written by Mynstral (mynstral@thehelm.com)
+
+# Permanent Wall
+F:X:63:0
+F: :63:0
+
+# Granite Wall
+F:#:57:0
+F:%:57:0
+
+# Hidden Door
+F:+:48:0
+
+# Normal Door
+F:D:32:0
+
+# Floor
+F:.:1:0
+
+# Tree
+F:T:96:0
+
+# Mountain
+F:M:97:0
+
+# Shallow Water
+F:w:84:0
+F:V:84:0
+
+# Deep Water
+F:W:187:0
+
+# Shallow Lava
+F:l:86:0
+
+# Deep Lava
+F:L:85:0
+
+# Glass Wall
+F:G:188:0
+
+# Illusion Wall
+F:I:189:0
+
+# Treasure (random) on normal floor
+F:*:1:0:0:*
+
+# Trap (random) on normal floor
+F:^:1:0:0:0:0:0:*
+
+# down staircase
+F:>:7:0
+
+# between gates
+F:4:160:0:0:0:0:0:0:-1
+F:5:160:0:0:0:0:0:0:-1
+F:6:160:0:0:0:0:0:0:-1
+F:7:160:0:0:0:0:0:0:-1
+F:A:160:0:0:0:0:0:0:-1
+F:B:160:0:0:0:0:0:0:-1
+F:C:160:0:0:0:0:0:0:-1
+F:E:160:0:0:0:0:0:0:-1
+F:F:160:0:0:0:0:0:0:-1
+F:0:160:0:0:0:0:0:0:-1
diff --git a/lib/mods/theme/edit/spiders.map b/lib/mods/theme/edit/spiders.map
new file mode 100644
index 00000000..146c152c
--- /dev/null
+++ b/lib/mods/theme/edit/spiders.map
@@ -0,0 +1,66 @@
+# Lit permanent wall
+F:X:61:6
+
+# up staircase
+F:<:6:8
+
+# Grass
+F:-:89:3
+
+# Trees
+F:t:96:3
+
+# Grass with Giant spider
+F:a:89:3:175
+
+# Grass with Giant tarantula
+F:b:89:3:275
+
+# Grass with Mirkwood Spider
+F:c:89:3:277
+
+# Grass with Aranea
+F:d:89:3:963:0:0:0:0:0:0:2
+
+# Grass with Elder aranea
+F:e:89:3:964:0:0:0:0:0:0:2
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X<---tttttttttttttttttttttttttttttttttttttttttttttttttttttttX
+D:X---ttttttttttttttttttttttttttta--ctttttttttttttttttttttttttX
+D:Xtt---------------ttttttttttttt--tttttttttttttttttttttttttttX
+D:Xttttttttt--------------cttttttt--ttttttttttttttttttttttttttX
+D:Xtttttttttttttt--tttttt---------c--tttttttttttttttttttttttttX
+D:Xttttttttttttta-bttt---cttttttttttttttttttttttttttttttttttttX
+D:Xttttttttttttttttttttt---tttt-ttd--c-ttt---c---tttttttttttttX
+D:Xtttttttttttttttttttc---btttttttt-----ttc-----ttttttttttttttX
+D:Xtttttttttttttttttt----tttttttttc-c---------d---c-ctttttttttX
+D:Xtttttttttttttttttb-tttt---c---t----tttttt----------ctttttttX
+D:Xtttttttttttttttttt----ttttt-----c---tttttt-c--cttttttttttttX
+D:Xttttttttttttttttc--at----c---ttttttttttttttttttttttttttttttX
+D:Xttttttttttttta----ttttt-b--tttttttttd--etttttttttttttttttttX
+D:Xtttttttttttt---c--ttttt------tttt-c-tttttttte----dtttttttttX
+D:Xttttttttttttttttttt----c--d----tttt---ttttttt--d----ettttttX
+D:Xttttttttttttttttttttt-c-d---tttttttc--cttttttt-----ttttttttX
+D:Xttttttttttta-c--ttt-------tttt-------ttttt----d--ttttttttttX
+D:Xtttttttttttt----ttttt--ttt--c--c--t-----c--ttttttttttttttttX
+D:Xttttttttttt--c---ttt--c--c---ttttt--c----t----tttttttttttttX
+D:Xtttttttttt-c----c---t-----tttttttt-----ttt-------dtttttttttX
+D:Xttttttttttt---c---tttt--c--ttttttttt-ttttttttt-d---ttttttttX
+D:Xtttttttttttta-----tttttt---d---dttd----cttttt-----tttttttttX
+D:Xtttttttttttttttttttt---c-----ttttt---c----ettd--tttttttttttX
+D:Xtttttttttttttttt----d----tttttttttttttttttttttt---tttttttttX
+D:Xttttttt-------c---tttt-d----c--ettttttttttttd-----dttttttttX
+D:Xtttttc--c-c------tttttt-------------ettttttt----tttttttttttX
+D:Xttttttt------ttttttt--c---d---ttttttttttttt--d--tttttttttttX
+D:Xttttt----cc-tttttttttttte----d-ttttttttttttttt----tttttttttX
+D:Xttttt--c------ttttttttttttttttttttttttttte--tt------ettttttX
+D:Xttt--c----ctttttttttttttttttttttttttte------------tttttttttX
+D:Xtttttttttttttttttttttttttttttttttttttttttt--e--ttttttttttttX
+D:XtttttttttttttttttttttttttttttttttttttttttttttttttttttttttttX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:3
+
diff --git a/lib/mods/theme/edit/st_info.txt b/lib/mods/theme/edit/st_info.txt
new file mode 100644
index 00000000..29ca49fc
--- /dev/null
+++ b/lib/mods/theme/edit/st_info.txt
@@ -0,0 +1,1157 @@
+# File: st_info.txt
+
+# Fixed Potions of Cure Light/Serious Wounds in the Temple, Potions of
+# Restore Str/Con in the Alchemist
+# Magic Shop - Amulet of Slow Digestion, Wand of Light, Staffs of Enlightenment,
+# Door/Stair Location, Detect Invis/Evil, and Remove Curse
+
+# This file is used to initialize the "lib/raw/st_info.raw" file, which is
+# used to initialize the "store info type" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# Some store indexes are defined in "defines.h", and must not be
+# changed.
+
+# N:<index>:<name>
+# I:<proba>:<item name>
+# T:<proba>:<tval>:<sval>
+# G:char:attr
+# W:max number of items in the store
+
+# proba is the chance(out of 100) of the item being generated
+
+# Version stamp (required)
+
+V:2.0.0
+
+N:0:General Store
+I:100:& Wooden Torch~
+I:95:& Brass Lantern~
+I:95:& Flask~ of oil
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:90:& Strip~ of Venison
+I:70:& Pint~ of Old Winyards
+I:80:& Pint~ of Fine Ale
+I:60:& Shovel~
+I:50:& Pick~
+I:100:& Iron Spike~
+I:70:& Iron Shot~
+I:70:& Bolt~
+I:70:& Arrow~
+I:98:& Cloak~
+I:46:& Fur Cloak~
+A:0:0:1:2:3:4
+O:1:2:3:4
+G:1:U
+W:24
+
+N:1:Armoury
+I:70:& Pair~ of Soft Leather Boots
+I:60:& Pair~ of Hard Leather Boots
+I:80:& Hard Leather Cap~
+I:70:& Metal Cap~
+I:65:& Iron Helm~
+I:100:& Robe~
+I:90:& Soft Leather Armour~
+I:90:& Soft Studded Leather~
+I:90:& Hard Leather Armour~
+I:85:& Hard Studded Leather~
+I:90:& Leather Scale Mail~
+I:80:& Metal Scale Mail~
+I:75:& Chain Mail~
+I:80:& Augmented Chain Mail~
+I:75:& Metal Brigandine Armour~
+I:68:& Bar Chain Mail~
+I:100:& Set~ of Leather Gloves
+I:80:& Set~ of Gauntlets
+I:100:& Small Leather Shield~
+I:90:& Large Leather Shield~
+I:80:& Small Metal Shield~
+A:0:0:1:2:3:4
+O:5:6:7:8
+G:2:s
+W:24
+
+N:2:Weaponsmith
+I:100:& Dagger~
+I:100:& Main Gauche~
+I:100:& Rapier~
+I:100:& Small Sword~
+I:100:& Short Sword~
+I:100:& Sabre~
+I:100:& Cutlass~
+I:100:& Tulwar~
+I:100:& Broad Sword~
+I:100:& Long Sword~
+I:100:& Scimitar~
+I:100:& Katana~
+I:100:& Bastard Sword~
+I:100:& Spear~
+I:100:& Awl-Pike~
+I:100:& Trident~
+I:100:& Pike~
+I:100:& Beaked Axe~
+I:100:& Broad Axe~
+I:100:& Lance~
+I:100:& Battle Axe~
+I:100:& Hatchet~
+I:100:& Sling~
+I:100:& Short Bow~
+I:100:& Long Bow~
+I:100:& Light Crossbow~
+I:100:& Iron Shot~
+I:100:& Arrow~
+I:100:& Bolt~
+I:100:& Whip~
+I:100:& Small Wooden Boomerang~
+A:23:0:1:2:3:4
+O:9:10:11:12
+G:3:w
+W:24
+
+N:3:Temple
+I:100:& Quarterstaff~
+I:100:& Mace~
+I:100:& War Hammer~
+I:100:& Lucerne Hammer~
+I:100:& Morning Star~
+I:100:& Flail~
+I:100:& Lead-Filled Mace~
+I:100:Remove Curse
+I:100:Blessing
+I:100:Holy Chant
+I:100:Heroism
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Word of Recall
+#I:100:Cure Light Wounds
+T:100:71:34
+#I:100:Cure Serious Wounds
+#I:100:Cure Serious Wounds
+T:100:71:35
+T:100:71:35
+I:100:Cure Critical Wounds
+I:100:Cure Critical Wounds
+I:100:Restore Life Levels
+I:100:Restore Life Levels
+I:100:Restore Life Levels
+I:100:& Whip~
+I:100:& Mace~
+I:100:& Ball-and-Chain~
+I:100:& War Hammer~
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Cure Critical Wounds
+I:100:Cure Critical Wounds
+I:100:Restore Life Levels
+I:100:Restore Life Levels
+I:100:Restore Life Levels
+I:100:Remove Curse
+I:100:Remove Curse
+I:100:*Remove Curse*
+I:100:*Remove Curse*
+A:0:0:1:2:3:4
+O:13:14:15:16
+G:4:g
+W:24
+
+N:4:Alchemy shop
+I:100:Enchant Weapon To-Hit
+I:100:Enchant Weapon To-Dam
+I:100:Enchant Armour
+I:100:Identify
+I:100:Identify
+I:100:Identify
+I:100:Identify
+I:100:Light
+I:100:Phase Door
+I:100:Phase Door
+T:100:70:9
+I:100:Monster Confusion
+I:100:Magic Mapping
+I:100:Treasure Detection
+I:100:Object Detection
+I:100:Trap Detection
+I:100:Detect Invisible
+I:100:Recharging
+I:100:Satisfy Hunger
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Word of Recall
+I:100:Word of Recall
+T:100:70:9
+T:100:70:9
+#I:100:Restore Strength
+T:100:71:42
+I:100:Restore Intelligence
+I:100:Restore Wisdom
+I:100:Restore Dexterity
+#I:100:Restore Constitution
+T:100:71:46
+I:100:Restore Charisma
+I:100:Identify
+I:100:*Identify*
+I:100:*Identify*
+I:100:*Identify*
+I:100:*Identify*
+I:100:*Identify*
+I:100:*Identify*
+I:100:Light
+#I:100:Restore Strength
+T:100:71:42
+I:100:Restore Intelligence
+I:100:Restore Wisdom
+I:100:Restore Dexterity
+#I:100:Restore Constitution
+T:100:71:46
+I:100:Restore Charisma
+I:100:Enchant Armour
+I:100:Enchant Armour
+I:100:Recharging
+I:100:Satisfy Hunger
+I:100:Satisfy Hunger
+I:100:Satisfy Hunger
+A:0:0:1:2:3:4
+O:17:18:19:20
+G:5:b
+W:24
+
+N:5:Magic shop
+I:100:Protection
+I:100:Levitation
+I:100:Protection
+I:100:Charisma
+I:100:Slow Digestion
+T:100:40:7
+I:100:Searching
+I:100:Cure Light Wounds
+# Rods
+I:100:Probing
+I:25:& Wooden Rod~ of#
+# Book
+T:100:111:50
+# Wands
+T:100:65:3
+T:100:65:8
+T:100:65:11
+T:100:65:16
+T:100:65:22
+# Staves
+T:100:55:3
+T:100:55:5
+T:100:55:8
+T:100:55:9
+T:100:55:14
+T:60:55:15
+T:60:55:16
+T:60:55:17
+T:70:55:22
+A:0:0:1:2:3:4
+O:21:22:23:24
+G:6:r
+W:24
+
+N:6:Black Market
+A:30:0:1:2:3:4
+O:25:26:27:28
+G:7:D
+F:ALL_ITEM | MEDIUM_LEVEL
+W:24
+
+N:7:Home
+A:0:0:54:55:3:62
+O:0:0:0:0
+G:8:y
+W:24
+
+N:8:Book Store
+# & Book~ of Beginner Cantrips
+T:100:111:50
+T:100:111:50
+T:100:111:255
+T:100:111:255
+T:100:111:255
+T:100:111:255
+T:100:111:255
+T:100:111:255
+A:0:0:1:2:3:4
+O:29:30:31:32
+G:9:o
+W:24
+
+N:9:Pet Shop
+I:100:Egg
+T:100:70:6
+I:100:& Round Seed-Cake~
+A:0:0:1:2:3:4
+O:33:34:35:36
+G:+:b
+F:MEDIUM_LEVEL
+W:12
+
+#Bree Mayor
+N:10:Mayor's Office
+A:0:0:16:0:35:0
+O:37:37:37:37
+G:+:o
+W:0
+
+#Minas Anor Inn
+N:11:The Crowing Rooster
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:71:71:71:71
+G:+:w
+W:8
+
+N:12:The Soothsayer
+I:20:Divination
+I:20:Divination
+I:20:Divination
+I:20:Divination
+I:20:Divination
+I:20:Divination
+A:0:0:2:0:8:0
+O:78:79:80:81
+G:+:B
+F:RANDOM
+W:2
+
+N:13:Library
+I:100:Identify
+I:100:Identify
+I:100:Identify
+I:100:Identify
+I:100:Identify
+# starting parchment
+T:40:8:20
+# Khuzdul
+T:35:8:105
+# Nandorin
+T:30:8:106
+# Numenorean (I)
+T:30:8:101
+# Numenorean (II)
+T:20:8:102
+# Orcish
+T:15:8:107
+# Advanced Numenorean
+T:10:8:103
+# Advanced Sindarin
+T:5:8:104
+A:2:3:14:15:16:27
+O:86:87:88:89
+G:+:U
+W:2
+
+#Minas Anor
+N:14:Castle
+A:0:0:16:35:39:0
+O:38:38:38:38
+G:+:o
+W:0
+
+N:15:Casino
+A:13:0:9:10:0:12
+O:90:91:92:93
+G:+:s
+W:0
+
+N:16:Beastmaster Shanty
+# Monstrous Compendium 1
+T:100:8:9
+# Monstrous Compendium 2
+T:100:8:10
+# Monstrous Compendium 3
+T:95:8:11
+# Monstrous Compendium 4
+T:90:8:12
+# Monstrous Compendium 5
+T:85:8:13
+# Monstrous Compendium 6
+T:80:8:14
+# Monstrous Compendium 7
+T:75:8:15
+# Monstrous Compendium 8
+T:70:8:16
+# Monstrous Compendium 9
+T:65:8:17
+# Monstrous Compendium 10
+T:60:8:18
+# Monstrous Compendium 11
+T:55:8:19
+A:18:2:21:22:3:0
+O:94:95:96:97
+G:+:g
+W:24
+
+N:17:Fighters Hall
+A:0:0:24:25:0:0
+O:98:99:100:101
+G:+:s
+W:0
+
+N:18:Tower of Magery
+A:0:0:26:27:0:0
+O:102:103:104:105
+G:+:b
+W:0
+
+N:19:Inner Temple
+# Cure Light Insanity
+T:20:72:14
+# Cure Serious Insanity
+T:15:72:15
+# Cure Critical Insanity
+T:10:72:16
+# Cure Insanity
+T:5:72:17
+A:2:3:28:29:0:0
+O:106:107:108:109
+G:+:G
+W:8
+
+N:20:Paladins Guild
+A:0:0:28:25:0:0
+O:110:111:112:113
+G:+:g
+W:0
+
+N:21:Rangers Guild
+A:0:0:31:32:0:0
+O:114:115:116:117
+G:+:u
+W:0
+
+N:22:Thunderlords' Nest
+A:0:0:33:2:34:0
+O:82:83:84:85
+G:+:U
+W:0
+
+N:23:The Mirror
+A:0:0:44:15:16:43
+O:51:51:51:51
+G:+:U
+W:0
+
+N:24:Seat of Ruling
+A:0:0:17:35:0:0
+O:52:52:52:52
+G:+:U
+W:0
+
+N:25:Wizards Spire
+A:60:0:26:27:0:0
+O:54:54:54:54
+G:+:U
+W:0
+
+N:26:Priests Circle
+# Cure Light Insanity
+T:20:72:14
+# Cure Serious Insanity
+T:15:72:15
+# Cure Critical Insanity
+T:10:72:16
+# Cure Insanity
+T:5:72:17
+A:2:3:28:29:0:0
+O:55:55:55:55
+G:+:o
+W:8
+
+N:27:Tower of the King
+A:0:0:17:35:0:0
+O:57:57:57:57
+G:+:U
+W:0
+
+N:28:Library
+I:100:Identify
+# starting parchment
+T:40:8:20
+# Khuzdul
+T:35:8:105
+# Nandorin
+T:30:8:106
+# Numenorean (I)
+T:30:8:101
+# Numenorean (II)
+T:20:8:102
+# Orcish
+T:15:8:107
+# Advanced Numenorean
+T:10:8:103
+# Advanced Sindarin
+T:5:8:104
+A:0:0:14:15:16:2
+O:58:58:58:58
+G:+:U
+W:12
+
+N:29:The White Tree
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:59:59:59:59
+G:+:w
+W:8
+
+N:30:Craftsmaster
+A:0:0:24:25:0:0
+O:60:60:60:60
+G:+:s
+W:0
+
+N:31:Earth-Dome (Nature)
+# Cure Light Insanity
+T:20:72:14
+# Cure Serious Insanity
+T:15:72:15
+# Cure Critical Insanity
+T:10:72:16
+# Cure Insanity
+T:5:72:17
+A:2:3:39:0:0:0
+O:61:61:61:61
+G:+:U
+W:8
+
+N:32:Minstrels Haven
+A:0:0:40:41:0:0
+O:62:62:62:62
+G:+:U
+W:0
+
+N:33:Star-Dome
+A:0:0:46:47:0:0
+O:63:63:63:63
+G:+:U
+W:0
+
+N:34:Valarin Temple
+# Cure Light Insanity
+T:20:72:14
+# Cure Serious Insanity
+T:15:72:15
+# Cure Critical Insanity
+T:10:72:16
+# Cure Insanity
+T:5:72:17
+A:2:3:28:48:0:0
+O:64:64:64:64
+G:+:U
+W:8
+
+N:35:Sea-Dome
+# Cure Light Insanity
+T:20:72:14
+# Cure Serious Insanity
+T:15:72:15
+# Cure Critical Insanity
+T:10:72:16
+# Cure Insanity
+T:5:72:17
+A:2:3:49:35:0:0
+O:65:65:65:65
+G:+:U
+W:8
+
+N:36:The Golden Flower
+A:0:0:50:51:0:0
+O:66:66:66:66
+G:+:U
+W:0
+
+N:37:The Fountain
+# Cure Light Insanity
+T:20:72:14
+# Cure Serious Insanity
+T:15:72:15
+# Cure Critical Insanity
+T:10:72:16
+# Cure Insanity
+T:5:72:17
+A:2:3:52:53:0:0
+O:67:67:67:67
+G:+:U
+W:8
+
+# Here begins the random shops, for the random towns
+N:38:Axe Smith
+T:100:24:256
+A:0:0:1:2:3:4
+O:118:119:120:121
+G:3:w
+F:RANDOM | MEDIUM_LEVEL
+W:12
+
+N:39:Hafted Smith
+T:100:21:256
+A:0:0:1:2:3:4
+O:122:123:124:125
+G:3:w
+F:RANDOM | MEDIUM_LEVEL
+W:12
+
+N:40:Polearm Smith
+T:100:22:256
+A:0:0:1:2:3:4
+O:126:127:128:129
+G:3:w
+F:RANDOM | MEDIUM_LEVEL
+W:12
+
+N:41:Sword Smith
+T:100:23:256
+A:0:0:1:2:3:4
+O:130:131:132:133
+G:3:w
+F:RANDOM | MEDIUM_LEVEL
+W:12
+
+N:42:Rare Jewelry Shop
+T:100:40:256
+T:100:45:256
+A:0:0:1:2:3:4
+O:134:135:136:137
+G:6:v
+F:RANDOM | DEPEND_LEVEL | DEEP_LEVEL | FORCE_LEVEL
+F:VERY_RARE
+W:10
+
+N:43:Jewelry Shop
+T:100:40:256
+T:100:45:256
+A:0:0:1:2:3:4
+O:138:139:140:141
+G:6:y
+F:RANDOM | DEPEND_LEVEL | MEDIUM_LEVEL | FORCE_LEVEL
+F:RARE
+W:20
+
+N:44:Footwear Shop
+T:100:30:256
+A:0:0:1:2:3:4
+O:142:143:144:145
+G:2:r
+F:RANDOM | MEDIUM_LEVEL
+F:COMMON
+W:12
+
+N:45:Rare Footwear Shop
+T:100:30:256
+A:0:0:1:2:3:4
+O:146:147:148:149
+G:2:r
+F:RANDOM | DEEP_LEVEL | MEDIUM_LEVEL
+F:VERY_RARE
+W:8
+
+N:46:Library
+T:100:110:256
+T:100:111:256
+T:100:112:256
+T:100:113:256
+T:100:114:256
+T:100:115:256
+T:100:116:256
+T:100:117:256
+T:100:118:256
+T:100:119:256
+T:100:120:256
+T:100:121:256
+T:100:122:256
+T:100:123:256
+T:100:124:256
+T:100:125:256
+A:27:0:1:2:3:4
+O:150:151:152:153
+G:9:y
+F:RANDOM | DEPEND_LEVEL | MEDIUM_LEVEL
+W:24
+
+N:47:Forbidden Library
+T:100:110:256
+T:100:111:256
+T:100:112:256
+T:100:113:256
+T:100:114:256
+T:100:115:256
+T:100:116:256
+T:100:117:256
+T:100:118:256
+T:100:119:256
+T:100:120:256
+T:100:121:256
+T:100:122:256
+T:100:123:256
+T:100:124:256
+T:100:125:256
+A:27:0:1:2:3:4
+O:150:151:152:153
+G:9:v
+F:RANDOM | DEPEND_LEVEL | DEEP_LEVEL
+F:RARE
+W:12
+
+N:48:Expensive Black Market
+A:0:0:1:2:3:4
+O:154:155:156:157
+G:7:v
+F:RANDOM | ALL_ITEM | DEEP_LEVEL | DEPEND_LEVEL | MEDIUM_LEVEL
+W:12
+
+N:49:Common Shop
+I:95:& Brass Lantern~
+I:100:& Flask~ of oil
+I:100:& Ration~ of Cram
+I:60:& Shovel~
+I:50:& Pick~
+I:100:& Iron Spike~
+I:70:& Iron Shot~
+I:70:& Bolt~
+I:70:& Arrow~
+I:98:& Cloak~
+I:46:& Fur Cloak~
+I:100:Word of Recall
+I:100:Cure Critical Wounds
+A:0:0:1:2:3:4
+O:158:159:160:161
+G:1:U
+W:12
+F:RANDOM
+
+N:50:Dragon Hunter
+T:100:38:256
+A:0:0:1:2:3:4
+O:162:163:164:165
+G:2:v
+F:RANDOM | DEEP_LEVEL | DEPEND_LEVEL
+F:VERY_RARE
+W:12
+
+N:51:Speed Ring Market
+T:100:45:31
+A:0:0:1:2:3:4
+O:166:167:168:169
+G:6:G
+F:RANDOM | SHALLOW_LEVEL | DEPEND_LEVEL
+F:VERY_RARE
+W:6
+
+N:52:Scribe
+T:100:70:256
+A:0:0:1:2:3:4
+O:170:171:172:173
+G:5:B
+F:RANDOM | MEDIUM_LEVEL | DEPEND_LEVEL
+W:12
+
+N:53:Potion Store
+T:100:71:256
+T:100:72:256
+A:0:0:1:2:3:4
+O:174:175:176:177
+G:5:B
+F:RANDOM | MEDIUM_LEVEL | DEPEND_LEVEL
+W:12
+
+N:54:Recaller
+I:100:Word of Recall
+A:33:0:1:2:3:0
+O:82:83:84:85
+G:+:b
+F:RANDOM | COMMON
+W:2
+
+N:55:Master Archer
+T:100:19:2
+T:100:19:12
+T:20:19:13
+T:100:19:23
+T:20:19:24
+T:50:16:256
+T:50:17:256
+T:50:18:256
+A:0:0:1:2:3:4
+O:178:179:180:181
+G:3:g
+F:RANDOM | MEDIUM_LEVEL | DEPEND_LEVEL
+F:RARE
+W:24
+
+N:56:Merchants Guild
+A:0:0:56:57:58:0
+O:211:211:211:211
+G:+:g
+W:0
+
+N:57:The Museum
+A:0:0:59:0:3:0
+O:0:0:0:0
+G:+:g
+F:MUSEUM
+W:255
+
+N:58:The Prancing Pony
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:68:68:68:68
+G:+:w
+W:8
+
+##### Mining equipment for Khazad-Dum #####
+
+N:59:Mining Supply store
+T:100:20:256
+I:100:& Wooden Torch~
+I:95:& Brass Lantern~
+I:95:& Flask~ of oil
+I:75:& Dwarven Lantern~
+I:60:& Feanorian Lamp~
+T:60:65:6
+T:70:71:22
+A:0:0:1:2:3:4
+O:182:183:184:185
+F:MEDIUM_LEVEL
+G:+:s
+W:24
+
+## Library quest in Minas Anor
+
+N:60:Library
+I:100:Identify
+I:100:Identify
+I:100:Identify
+I:100:Identify
+I:100:Identify
+I:100:Identify
+# starting parchment
+T:40:8:20
+# Khuzdul
+T:35:8:105
+# Nandorin
+T:30:8:106
+# Numenorean (I)
+T:30:8:101
+# Numenorean (II)
+T:20:8:102
+# Orcish
+T:15:8:107
+# Advanced Numenorean
+T:10:8:103
+# Advanced Sindarin
+T:5:8:104
+A:61:0:14:15:16:2
+O:210:210:210:210
+G:+:U
+W:12
+
+### New shops in Theme ###
+
+# Hunting Store
+N:61:Hunting Supply Store
+I:100:& Morphic Oil~ of #
+T:50:35:255
+T:100:46:255
+T:100:19:2
+T:100:19:12
+T:20:19:13
+T:100:19:23
+T:20:19:24
+T:50:16:255
+T:50:17:255
+T:50:18:255
+A:0:0:1:2:3:4
+O:186:187:188:189
+G:*:w
+W:24
+
+# Rune Shop
+N:62:Runic Magic Shop
+T:100:104:256
+T:100:104:256
+T:100:104:256
+T:50:105:256
+T:50:105:256
+T:50:105:256
+A:0:0:1:2:3:4
+O:190:191:192:193
+G:6:w
+W:24
+
+# based on Mining Supply store in Khazad-Dum
+N:63:Construction Supply Store
+T:100:20:256
+I:100:& Wooden Torch~
+I:95:& Brass Lantern~
+I:95:& Flask~ of oil
+I:75:& Dwarven Lantern~
+I:60:& Feanorian Lamp~
+T:60:65:6
+T:70:71:22
+A:0:0:1:2:3:4
+O:182:183:184:185
+G:1:w
+W:24
+
+# Music store
+N:64:Music Store
+I:20:& Horn~
+I:20:& Drum~
+I:20:& Harp~
+A:0:0:1:2:3:4
+O:194:195:196:197
+G:+:o
+W:12
+
+# Rod shop
+N:65:Magic Rod Market
+T:100:67:50
+T:75:67:75
+T:75:67:75
+T:50:67:100
+T:50:67:100
+T:50:67:100
+T:50:67:100
+T:50:67:125
+T:25:67:160
+T:5:67:200
+A:0:0:1:2:3:4
+O:198:199:200:201
+F:RANDOM | MEDIUM_LEVEL | DEPEND_LEVEL
+G:6:b
+W:12
+
+# Map store
+# No stealing; will buy nothing - this is a map maker, they don't need to buy maps.
+N:66:Map store
+I:100:Map of Bree
+I:100:Map of Hobbiton
+I:50:Map of Lothlorien
+I:50:Map of Edoras
+I:50:Map of Esgaroth
+I:40:Map of Dale
+I:30:Map of Pelargir
+I:30:Map of Osgiliath
+I:30:Map of Minas Anor
+I:15:Map of Forodwaith
+I:5:Map of Middle-earth
+A:0:0:1:2:3:0
+O:202:203:204:205
+G:9:w
+W:12
+
+# Farm
+# Farms buy nothing - anything they might want, they can produce themselves.
+N:67:Farm
+I:100:& Pinch~ of Longbottom Leaf
+I:100:& Jar~ of Honey
+I:100:& Jug~ of Milk
+I:100:Apple Juice
+I:100:Water
+I:100:Salt Water
+I:20:Cure Poison
+I:20:Cure Blindness
+I:20:Cure Fear
+I:20:Cure Confusion
+A:0:0:1:2:3:4
+O:206:207:208:209
+G:1:G
+W:12
+
+### Themed Inns ###
+
+#Pelargir
+N:68:The Grey Swan
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:69:69:69:69
+G:+:w
+W:8
+
+#Caras Galadhon
+N:69:The Garden
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:70:70:70:70
+G:+:w
+W:8
+
+#Khazad Dum
+N:70:The Mithril Lode
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:72:72:72:72
+G:+:w
+W:8
+
+#Dale
+N:71:The Builder Barracks
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:73:73:73:73
+G:+:w
+W:8
+
+#Edoras
+N:72:The Horse and Ox
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:74:74:74:74
+G:+:w
+W:8
+
+#Esgaroth
+N:73:The Dancing Dragon
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:75:75:75:75
+G:+:w
+W:8
+
+#Hobbiton
+N:74:The Green Dragon
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:76:76:76:76
+G:+:w
+W:8
+
+#Osgiliath
+N:75:The Twinkling Star
+I:100:& Ration~ of Cram
+I:100:& Round Seed-Cake~
+I:100:& Strip~ of Venison
+I:100:& Pint~ of Old Winyards
+I:100:& Pint~ of Fine Ale
+A:2:4:5:6:7:0
+O:77:77:77:77
+G:+:w
+W:8
+
+### Abodes ###
+
+N:76:The House of Beorn
+A:17:63:65:0:0:0
+O:40:40:40:40
+G:+:U
+W:0
+
+N:77:Bard's Hut
+A:17:66:0:0:0:0
+O:41:41:41:41
+G:+:U
+W:0
+
+N:78:The Ranger Conclave
+A:17:63:65:0:0:0
+O:42:42:42:42
+G:+:U
+W:0
+
+N:79:Imladris
+A:17:63:65:0:0:0
+O:43:43:43:43
+G:+:U
+W:0
+
+N:80:The Hornburg
+A:17:63:65:0:0:0
+O:44:44:44:44
+G:+:U
+W:0
+
+N:81:Thranduil's Hall
+A:17:63:65:0:0:0
+O:45:45:45:45
+G:+:U
+W:0
+
+N:82:Meduseld
+A:17:0:0:0:0:0
+O:46:46:46:46
+G:+:U
+W:0
+
+N:83:The Master's House
+A:17:0:0:0:0:0
+O:47:47:47:47
+G:+:U
+W:0
+
+N:84:Bag End
+A:17:0:0:0:0:0
+O:48:48:48:48
+G:+:U
+W:0
+
+N:85:The Castle of Stars
+A:17:0:0:0:0:0
+O:49:49:49:49
+G:+:U
+W:0
+
+N:86:The Prince's Tower
+A:17:0:0:0:0:0
+O:50:50:50:50
+G:+:U
+W:0
+
+N:87:The Seat of Durin
+A:17:0:0:0:0:0
+O:39:39:39:39
+G:+:U
+W:0
+
+### The forge in Imladris
+N:88:Forge
+A:23:24:25:32:64:0
+O:43:43:43:43
+G:+:y
+W:0 \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_basic.txt b/lib/mods/theme/edit/t_basic.txt
new file mode 100644
index 00000000..8153f6fe
--- /dev/null
+++ b/lib/mods/theme/edit/t_basic.txt
@@ -0,0 +1,66 @@
+D:######################################################################################################################################################################################################
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_beorn.txt b/lib/mods/theme/edit/t_beorn.txt
new file mode 100644
index 00000000..e60c5d29
--- /dev/null
+++ b/lib/mods/theme/edit/t_beorn.txt
@@ -0,0 +1,108 @@
+# File: t_beorn.txt
+
+# Beorn's Halls map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain features ###
+
+# Beehive
+F:b:229:3
+
+# Dirt road
+F:,:230:3
+
+# Bush
+F:h:202:3
+
+# Closed gate
+F:g:231:3
+
+# Open gate
+F:+:232:3
+
+# Wooden boards (4 kinds)
+F:=:233:3
+F:[:234:3
+F:_:235:3
+F:]:236:3
+
+### Buildings ###
+
+#The House of Beorn
+F:a:74:3:0:0:0:0:0:76
+
+#The Farm
+F:f:74:3:0:0:0:0:0:67
+
+#The Beastmaster
+F:r:74:3:0:0:0:0:0:16
+
+D:######################################################################################################################################################################################################
+D:# ------TT-TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT--T-TTT------------------ #
+D:#---- ------ ------ ---------------TTTT-TThh-hh-----------------@WW@---------------TTTTT----TTT------------- #
+D:# -------------------- ---TTT---TTTT-TT---------------hhhhhhhWWhhhhhhhhh-----------TTTTT-----TTTT-------- #
+D:# -------- ---- ---------- ---TTTTT---TT-TT--------------hhhhh--@WW@--hhhhhhhhhhhhhhhh------TTT--TTTTTT------ -- #
+D:# --TTT------TT--------------hhh----@WW@---RRRRRRR----hhhhhhhhh----TTT-TTTT---T---- #
+D:#-------- ----------TTT--------------hhh----@WW@---RRRRRRRRR---------hhhhhh---TT-----TTTTT-------- #
+D:#---- -----------------T----TTT--------------hhh-----@WW@---RRNNNNNNNRR-----------hhhh---TTT-----T-------- #
+D:#---- -------- ---TTTTT-TTT--------------hhh------@WW@--ANNNNFFFNNNNA------------hhh----TT------------ #
+D:# ------ -------- -------- -----TTTTT-TT--------------hhh------@WW@--AANNFFFFFFFNNAA------------hhh----TT---TTT---- #
+D:#-- -------- ------ ---T--TTT-TT--------------hhh-------@WW@-AAANFFFEEEFFFNAAA------------hhh----TT-TTTTT---- #
+D:# ------ ---- ---- ---------TTTTT---TT--------------hhh-------@WW@--AAANFFEEEEEFFNAAA-------------hhh----TT-TTT------- #
+D:# ------------ ------ ----------TTT--TTT----------------hhh-----@WW@---AAANFFFEEEFFFNAAA------------hhh--T---TT----TTTT--- #
+D:#------ ---------------------------------TTT---------------hhh-------@WW@---AANNFFFFFFFNNAA------------hhh---TT--TT---TTTTTT-- #
+D:#---- -------- -------- -----------T---TT-----------------hhh-------@WW@---ANNNNFFFNNNNA--------------hhh--TT---TT---TTTT---- #
+D:#-- -------- ------ ---TTTTT-TT----------------hhh--------@WW@----RRNNNNNNNRR----------------hhh--T----hT---------- #
+D:# ------------ --------TTT-TTT ----------------hhh-----N--@WW@----RRRRRRRRR----------------hhh---T-----TTT-TTTT-- #
+D:#---- ---- -------------T--T@b@---------------hhh-----NRN--@WW@----RRRRRRR------------------hhh--TT----TTT-T------ #
+D:# ---------- ------ ----TTTT---TTT@b@---------------hhh---NRRRN--@WW@-----------------------------hhh-T-----TT--TT---- #
+D:# ------ ---- ---TTTTTT--TT--@b@-------------hhh-----NRN--@WW@-----------------------------hhh--TTT----TT---TTT-- #
+D:#---- ------ ---------- ------------TTTT---TTT-@b@--------------hhh-----N----@WW@-------NNN-------EEREE-------hhh--------TT--TTTTT-- #
+D:#-- ---- -------- ---------TTT--@b@------------hhh----------@WW@------NFFFFFN----EERRREE----hhh---TTT----TT---TTT---- #
+D:# ---- ---- -- ------TTTTTT----@b@-------------hhh--------@WW@-----NFFFFFN-------EEREE---hhhh---TTT-----TT------- #
+D:# -------- -- -- ---------TTT---TTT--@b@------------hhh--------@WW@----NFFFFFN---------------hhhh----TTT------TT--TTT-- #
+D:#-- -------- -------- ----TTTT-TTT--@b@-------------hhh------@WW@-------NNN---------UUUYUUUUhh---------------TT-TTTTT-- #
+D:#-- ---- ---- -------------------T-----TTT--@b@------------hhh------@WW@--------------------XXXXXXXXh----------------TT--TTT-- #
+D:# ------ ------ -------TTTTT----TT--@b@-------------hhh------@WW@---UUUYU-----------________h---------TT-----TT-------- #
+D:#-- ---------- ---- ---TTTTT--T-TT--@b@------------hhh------@WW@----XXXXXNNNNNNNNNNN________h----------TT----TTT--TTT---- #
+D:#---- ----T----T-TT--@b@-------------hhh------@WW@---_____,,,,,,,,,,,f]]]]]]]T-T---------TTT--TTT-TTTTT---- #
+D:# ---------- ----TTTT-TTT--@b@------------hhh------@WW@----]]]]]NNNNNNNNNNN----------------TTT------TT----TTT--- #
+D:# ---- ------ -----TTTTTT-TT--@b@-------------hhh-----@WW@-----F,F---------[================[-T---------TT--T---- #
+D:# ------ ---------- ------TTTT---T--@b@------------hhh----TT-@WW@----F,F---------[================[-T----TTT--TT-TTT--- #
+D:# ----------------------------------------TT--@b@-----------hhh-------@WW@-----F,F---------[================[AT----T-T--TT-TTT--- #
+D:#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,g,,,,,,,,,,,,,,,,,,,,,,,,,,WW,,,,,,,,,,,,,,,,,,,,,,,,,,,aUUUUUUUU[,,,A--T----TT--T------ #
+D:#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,,,,,,,,,,,,,,,,,,,,,,,,,WW,,,,,,,,,,,,,,,,,,,,,,,,,,,,aUUUUUUUU[AT,,A-TTTT-TT---TTT----- #
+D:#-- --------------------------------------------TT--@b@------------hhh----@WW@-----------,-,,,---[================[-T-,A----T-TT--TTTTT-- #
+D:# -------- ------TT-TTT--@b@-------------hhh--@WW@----------E,E--,,,,-[================[-T-,A-TTTT-TT---TTT---- #
+D:#-- -------- -------- ---TTTT-TT--@b@--------TTT---hhh@WW@----------E,E------,,[================[-T-,A---TT-TT--------- #
+D:#------ ---------- ----------TT--TT--@b@------TTT-----hh@WW@----------E,E--------hA,-----------------A,,A-TT--TTT--TTT-- #
+D:#-- ------ -------- ----TTT-----TT--@b@-------TTT---hhhWW@----------E,E---------hhA,,,A-----------A,,,A-------TT--TTT-- #
+D:# ---- ------ ---------TTTTT---TTT--@b@--------TTT-hhhhWW@---------E,E-----------hh-A,,,,,AAAA,,,,,AA---------TT TTTTT-- #
+D:# ---- ---- -------TT-TT---TTT--@b@-------------hhWW@---------E,E------------hhhh--A,,,,,,,,,A--TTT------TT---TTT-- #
+D:# -------- ------------ ------------T--TTT---@b@-------------hWWh----------R,R------------hhhh--AAAAAAAAA----TTTTT---TT---TTT-- #
+D:# -- -- ------ ----TTTTT-TT---@b@------------@WWhhh---UUUYUUU,,R-------------hhhh--------TT-----TTT---TT-------- #
+D:# ------ -------TTT---TT--@b@-----------@WW@-hhh--XXXXXXX,-,R-------------hhhhh-----TTTTT-----TTT-TT------- #
+D:# ------------ ---------------- ----------TTT--@b@------------@WWhhh---_______,-,,R---------------hhhh-----------------TT--T----- #
+D:# ------------ -------------TTTT---TTT--@b@-----------@WW@-hhh--_______,-,UUYU----------------hhhThTh----------TTT-TTT---- #
+D:# ------ ------TTTTTT---TT--@b@------------@WWhhhh--]]]]0]],-,XXXX--------------------hhhhhh--T-----TT--T----- #
+D:# ------ ---- ---TTTT---TTTT-@b@------------@WW@hhhh-----,,,,-,____---------------FFF------hhh------TT--------- #
+D:#------ ---------- ------ -----------TT--TTT-@b@-------------@WW@hhhh---------,]rr]--------------FVVVVF-----hhh-----T---------- #
+D:# ------ ------ ------ ------TTTT--TT@b@-------------@WW@--hhh---------,,,-----------------FVVVVF----hhhh---TT---TTT--- #
+D:#---- -------------- ------------ ---------TT--TTTb@-------------@WW@----hhh-----------------------------FVVVVF--hhhh----TT--TTTTT-- #
+D:#-- ---------- ---- ----------------TTT-------------@WW@------hhh-------------------N---------FFFF--hhhh----TT----T-T-- #
+D:# ---- -------- -------- ---------TTT-TTTT-----------@WWW@--------hhh----------------ENANE------------hhhh-----TT------- #
+D:# ---------- ---------- -------- ------TTTTT--TT------------@WWW@--------hhh--------------EEAAAEE----------hhhh----TTT------------ #
+D:# ------ ------ ---- ---- ----TTTTT---TT---------@WWW@-----------hhh--------------ENANE----------hhhh----TT------------ #
+D:# -------- ------ ---------TTT-TT---------@WWW@----------hhhh---------------N-----------hhh-----TT------------- #
+D:# ------ ------ ------TTTTT-TT-------@WWW@TTT---------hhhhh-----------------------hh---T-TTTT--TTTTT------ #
+D:# -- ---- -------- -------TTT---TT------@WW@TTT------------hhhhhhh------------hhhhhhhhh------TTT----TTTTT----T-- #
+D:# -------- ------------ ------ -----T---TT----@WW@----------TTT------hhhhhhhhhhhhhhhhhhhhhhh-------TT -TTT--TTT---- #
+D:# ------ -------- ---------- ------ TTTTTT--TT--@WW@-------------------------hhhhhhhhhh--------------hT--TTTTT---- #
+D:#------------ -------------- ------------ TTTTT--TTTTTWW@-------------------------------------------------TT----TTT------------- #
+D:# ---------- ------ ------ ---------- TTT-TTTThTTT------------------------------------------------hTT---------------- #
+D:#------ ------ -------- -------- ---------TTTTThhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhTh--TTTTT--------- #
+D:#------ -------- -------------- ---TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT-------------- #
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_bree.txt b/lib/mods/theme/edit/t_bree.txt
new file mode 100644
index 00000000..e5fe559a
--- /dev/null
+++ b/lib/mods/theme/edit/t_bree.txt
@@ -0,0 +1,137 @@
+# File: t_bree.txt
+
+# Bree
+
+############### Additional default terrain settings ###############
+
+# Default for Quest 1 = entrance is quest entrance
+F:z:8:3:0:0:0:0:0:4
+
+# Default for Quest 18 = entrance is tree
+F:y:96:3
+
+# Default for Quest 18 = entrance is tree
+F:x:96:3
+
+############### Quest 4 - Thieves Hideout finished = house ###############
+?:[EQU $QUEST4 2]
+F:z:74:3:0:0:0:0:0:7
+?:[EQU $QUEST4 5]
+F:z:74:3:0:0:0:0:0:7
+?:1
+
+############### Quest 8 - Troll Glade ###############
+?:[AND [EQU $QUEST8 1] [EQU $DAYTIME 0] ]
+F:y:8:3:0:0:0:0:0:8
+?:1
+
+############### Quest 9 - Wights Grave ###############
+?:[EQU $QUEST9 1]
+F:x:8:3:0:0:0:0:0:9
+?:1
+
+###### Additionnal buildings #######
+
+# Castle: Plot Bree
+F:B:75:3:0:0:0:0:0:1
+
+# Mayor's house
+F:b:74:3:0:0:0:0:0:10
+
+# The Prancing Pony
+F:a:74:3:0:0:0:0:0:58
+
+# Soothsayer
+F:c:74:3:0:0:0:0:0:12
+
+# Music Store
+F:d:74:3:0:0:0:0:0:64
+
+# The Museum
+F:e:74:3:0:0:0:0:0:57
+
+# Map store
+F:f:74:3:0:0:0:0:0:66
+
+# The Library
+F:g:74:3:0:0:0:0:0:13
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:# VV -- #
+D:# V -- #
+D:# VV -- #
+D:# VVV -- #
+D:# VV -- #
+D:#OOOO V -- #
+D:# OOOO V -- #
+D:#--- OOOOO VVV --- VV #
+D:#------ OOOOOO V -- VVVV #
+D:#---------- OO V -- VVWWVVV #
+D:#-------------- OO VVV -- VVVWWWWWVVV #
+D:#--------------- OOO VVV -- VVWWWWWWWWWVV #
+D:#----------------- OO VVVVVVV VVWWWWWWWWWWWV #
+D:#------------------- OOOOO --VVVV VVVVV VVWWWWWWWWWWWVV #
+D:###------------------ OO ,,,,,,,,,,,,,,,,,, -- VVVVV VV VVVVVVVWWWWWWWVVV #
+D:#CC####------------------ OOO ,,,,,CCCCCCCCCCCCCCCCCC,,,,,,,,, -- VVVVVV VVVVWWVVV #
+D:#TTCCCC###---------------,, OO ,,,CCCCCCTTTTTTTTTTTTTTTTCCCCCCCCCC,,,, -- VVVV #
+D:#--TTTTCCC###---------,,,-- OO ,,CCCCTTTTTT--------------TTTTTTTTTTCCCCC,,,,, ^-- #
+D:#------TTTCCC##-----,,------ O ,,CCCTTTT..................----------TTTTTCCCCCC,, ^^^ -- #
+D:#---------TTTCC##,,,-------- OO ,CCCTTT....--ssssssss-..---..........-----TTTTTTCCC,,, ^^ -- #
+D:#------------TC,,###- --- OO ,CCTTT...-----SSSSSSSS--.----------,,.....------TTTCCCC,, ^^ -- #
+D:#-------------,TTCCC### -- OOO ,,CCTT...-,,,,--ssssssss-..-sssssssssss,---......---TTTTCCT,, ^^ -- #
+D:#--------- ,,,--TTTCCC -- OO ,,CCCTT..-------,,##9#####-.--sssssssssss-,-------...----TTCCTT, ^^^ -- #
+D:#-------- ,, ,,----TTTCC O ,CCC T..--sssSsss,,,,------.--StSStSSSStS--,------.-....--TTCCTT,^^^ -- #
+D:#------ ,, , OO ,CCTTT...---ssstSSS---,,,----.--sssssssssss---,---...----..--TTCCT^^^^ ^^ -- #
+D:#------- x, ,, OO ,CCTT...-----sssssss--,,-,,---.--sssssssssss---,-...-------..--TTC^^^ ^ ---- #
+D:#------- {, OO ,CTT..---,,,,###6###,,,---,,--.--###########----..----------..--T^^^^ ^ --- -- #
+D:#--------- OOO ,CT..,,,,----,,,,,,,,------,,-.--###b###e###-....,---sssss---.--T^^ ^ -- -- #
+D:#---------- OO ,CCT.,sssssss----,-----------,,.-----.-----....-,--,,-StSSS---.-T^^^ ^ -- ----- #
+D:#------------- OO ,CCTT.-StStSSS---,-----ssssss--..-----.--....--,,,,,,-,sssss---.-T^^^ ^ -- -- ,,, #
+D:#----------- OOOOO ,CTT-.-sssssss---,-----SSSSSS--.------.-..--,,,-ssss--,##f##---.-T^^ ^ -- ----- ,, #
+D:#-------- OO ,CCT-..-##5####----,----ssssss-..........--XXXX,-ssss--,------...-^^^ ^ ^^ ^ --- ---- ,,, #
+D:#- ---- OOOOOOOO ,C OOOO--OOOOO----,----#c##4#-.---.,----,-UUUU,-SSSS--,-----..---^^ ^ ^ --- -----, OOOOOOOOOOOOOO#
+D:#- ---- OOOOOOO ,CT-OssOOOO---OOOOOOOOO--OOOO--.-T-.-sss--,XXXX,-ssss---,---..--T^^ -- -- OOO #
+D:#- ----- OOOOOOOOSt.--------XXXXX-OOOO--OOOO---.-StS--,#0##,-ssss---,---.---^^ ^ ^ -- --- OOOO #
+D:#- --- ----- ,,CT--.ss.-sssss--XXXXX,---------OOOO.-sss---,,,,,-####--,---..-T^^ ^ ^ -- --- OO #
+D:# ---- ---- ,,CT--.B#.-SStSS--##g##,------------OO-#z#-ssssss-,,,---,----.--T^^ ^ -,- OOOOO #
+D:# ------- ---- ,,CTT-....-sssss--,,,,,,-------------OO-,--SSSSSt-sss,-,---...-T^^ ^ ^ -, OOOO #
+D:# ------- ------ ,,CCTT---..#2###-,sssss,-SSSSSSSS-----OO,--ssssss-tSS-,.....---^^ ^^ ^^^ -, OOOOOOOO #
+D:# ----- ----- ,,CCT----..,,,,,-StSSS,-ssssssss------OOO-#1##a#-sss...-----T^^ ^^ -,- OOOOO #
+D:# ---- -------- ,,CCTT----..----,sssss,-###d####--------OO,.,,.,-#7#----TTTT^^ ^ ^^ -, OOOOO #
+D:# --------------- ,,,CCTTTT--..---,##3##-,--,,,---------...OOOOOOOOOOOTTTTTCC^^^ ^^ ^^ ,- OOO #
+D:# -------- ,,,CCCC --..........,-,,---,--.......-------TTTTTOCCCCC,,^^^^^^^^^^^ -.- OOOOO #
+D:# ---------- ,, ,,CCCTT----------.....-......-------TTTTTTTCCCCO,,,,, ^^^^^^^ -.- O #
+D:# ------- ,, ,,CCTTTTTTTTTT-----...------TTTTTTTCCCCCC,,,,OOO -.- OOOO #
+D:# ---- ,,, ,CCCCCCCCCCTTTTT-----TTTTTTCCCCCC,,,,,, OOO OOOOOOOOO #
+D:# ^^ ---- ,, ,,,,,,,,,,CCCCCTTTTTTCCCCC,,,,,, OO OOO-- #
+D:# ^^^^^ ,,, ,,,,,CCCCCC,,,,, OOOO OOO-- #
+D:# ^^^^^^^^^ ,, ,,,,,, OOOOOOO OOO--- #
+D:# ^^^^^^^^^ ,, OOOOOOO---- #
+D:# ^^^^^^^^^^^^^^^ ,,, ..------ #
+D:# ^^^^^^^^^^^^^^ ,,, ...... ....----- #
+D:# ^^^^^^^^^^^^^^^ ,,, ........... ............ ............-------,,,, #
+D:#^^^^^^^^^^^^^^^^^ ,, ... .........-------------- ,,,,,,, ,,,,,,,,, #
+D:# ^^^^^^^^^^^^^ ,, . ,,,,,, ,,,,,,,,, #
+D:# ^^^^^^^^^^^^^^ ,, ... ,,,,, ------ --- #
+D:# ^^^^^^^^^^^^^^^ ,, . ,,,,,,,,------- ----- #
+D:# ^^^^^^^^^^^^^^ , .. ---------------- #
+D:# ^^^^^^^^^^^^^^^^ ,, .. ---------y-------- #
+D:# ^^^^^^^^^^^^^^^ , .. ----------------- #
+D:# ^^^^^^^^^^^^^^^^ ,,. --- ---- ---- #
+D:# ^^^^^^^^^^^^^ ,. - -- -- #
+D:# ^^^^^^^^^^^^^^ . #
+D:# ^^^^^^^^^^^^^^ . #
+D:######################################################################################################################################################################################################
+
+
+############### Starting positions ###############
+
+# Standard starting position for normal races
+?:[AND [EQU $LEAVING_QUEST 0] [NOT [EQU $RACE Vampire] ] ]
+P:33:131
+
+# Standard starting position for vampires (at the dungeon entrance)
+?:[AND [EQU $LEAVING_QUEST 0] [EQU $RACE Vampire] ]
+P:31:150
diff --git a/lib/mods/theme/edit/t_cerin.txt b/lib/mods/theme/edit/t_cerin.txt
new file mode 100644
index 00000000..0a87d3bb
--- /dev/null
+++ b/lib/mods/theme/edit/t_cerin.txt
@@ -0,0 +1,98 @@
+# File: t_cerin.txt
+
+# Cerin Amroth map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain features ###
+
+# Mallorn
+F:m:243:3
+
+# Flet
+F:f:220:3
+
+# White tree
+F:w:237:3
+
+# Low hill
+F:h:213:3
+
+# Altars
+F:i:161:3
+F:j:162:3
+F:k:163:3
+F:l:165:3
+F:n:166:3
+F:o:167:3
+F:p:168:3
+F:q:169:3
+
+D:######################################################################################################################################################################################################
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#-----------------------------------------------------------------------------------------NNNNNNNNN--------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------NNwwwwwwwNN-------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------NNwwhhhhhwwNN------------------------------------------------------------------------------------------------#
+D:#--------------------------------------------------------------------------------------NNwwhmmmmmhwwNN-----------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------------------------------------------NNwwhmmhhhmmhwwNN----------------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------------------------NNwwhmmh---hmmhwwNN---------------------------------------------------------------------------------------------#
+D:#-----------------------------------------------------------------------------------NNwwhmmh--o--hmmhwwNN--------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------ENwwhmmh-i-N-j-hmmhwwNE-------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------ENwwhmmhp-NEN-qhmmhwwNE-------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------ENwwhmmh-l-N-k-hmmhwwNE-------------------------------------------------------------------------------------------#
+D:#-----------------------------------------------------------------------------------NNwwhmmh--n--hmmhwwNN--------------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------------------------NNwwhmmh---hmmhwwNN---------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------------------------------------------NNwwhmmm@mmmhwwNN----------------------------------------------------------------------------------------------#
+D:#--------------------------------------------------------------------------------------NNwwhmm@mmhwwNN-----------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------NNwwhm@mhwwNN------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------NNwww@wwwNN-------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@------------------------------------------------------------------------------------------------------#
+D:#---------------------------------------------------------------------------------------------@@@@@@-------------------------------------------------------------------------------------------------#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_beorn.txt b/lib/mods/theme/edit/t_d_beorn.txt
new file mode 100644
index 00000000..75235407
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_beorn.txt
@@ -0,0 +1,75 @@
+# File: t_d_beorn.txt
+
+# Beorn's Halls map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:# HHHHHHDDHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHDHDDDHHHHHHHHHHHHHHHHHH #
+D:#HHHH HHHHHH HHHHHH HHHHHHHHHHHHHHHDDDDHDDDDHDDHHHHHHHHHHHHHHHHH@%%@HHHHHHHHHHHHHHHDDDDDHHHHDDDHHHHHHHHHHHHH #
+D:# HHHHHHHHHHHHHHHHHHHH HHHDDDHHHDDDDHDDHHHHHHHHHHHHHHHDDDDDDD%%DDDDDDDDDHHHHHHHHHHHDDDDDHHHHHDDDDHHHHHHHH #
+D:# HHHHHHHH HHHH HHHHHHHHHH HHHDDDDDHHHDDHDDHHHHHHHHHHHHHHDDDDDHH@%%@HHDDDDDDDDDDDDDDDDHHHHHHDDDHHDDDDDDHHHHHH HH #
+D:# HHDDDHHHHHHDDHHHHHHHHHHHHHHDDDHHHH@%%@HHH@@@@@@@HHHHDDDDDDDDDHHHHDDDHDDDDHHHDHHHH #
+D:#HHHHHHHH HHHHHHHHHHDDDHHHHHHHHHHHHHHDDDHHHH@%%@HHH@@@@@@@@@HHHHHHHHHDDDDDDHHHDDHHHHHDDDDDHHHHHHHH #
+D:#HHHH HHHHHHHHHHHHHHHHHDHHHHDDDHHHHHHHHHHHHHHDDDHHHHH@%%@HHH@@@@@@@@@@@HHHHHHHHHHHDDDDHHHDDDHHHHHDHHHHHHHH #
+D:#HHHH HHHHHHHH HHHDDDDDHDDDHHHHHHHHHHHHHHDDDHHHHHH@%%@HH@@@@@@@@@@@@@HHHHHHHHHHHHDDDHHHHDDHHHHHHHHHHHH #
+D:# HHHHHH HHHHHHHH HHHHHHHH HHHHHDDDDDHDDHHHHHHHHHHHHHHDDDHHHHHH@%%@HH@@@@@@@@@@@@@@@HHHHHHHHHHHHDDDHHHHDDHHHDDDHHHH #
+D:#HH HHHHHHHH HHHHHH HHHDHHDDDHDDHHHHHHHHHHHHHHDDDHHHHHHH@%%@H@@@@@@@@@@@@@@@@@HHHHHHHHHHHHDDDHHHHDDHDDDDDHHHH #
+D:# HHHHHH HHHH HHHH HHHHHHHHHDDDDDHHHDDHHHHHHHHHHHHHHDDDHHHHHHH@%%@HH@@@@@@@@@@@@@@@@@HHHHHHHHHHHHHDDDHHHHDDHDDDHHHHHHH #
+D:# HHHHHHHHHHHH HHHHHH HHHHHHHHHHDDDHHDDDHHHHHHHHHHHHHHHHDDDHHHHH@%%@HHH@@@@@@@@@@@@@@@@@HHHHHHHHHHHHDDDHHDHHHDDHHHHDDDDHHH #
+D:#HHHHHH HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHHHHHHHDDDHHHHHHH@%%@HHH@@@@@@@@@@@@@@@HHHHHHHHHHHHDDDHHHDDHHDDHHHDDDDDDHH #
+D:#HHHH HHHHHHHH HHHHHHHH HHHHHHHHHHHDHHHDDHHHHHHHHHHHHHHHHHDDDHHHHHHH@%%@HHH@@@@@@@@@@@@@HHHHHHHHHHHHHHDDDHHDDHHHDDHHHDDDDHHHH #
+D:#HH HHHHHHHH HHHHHH HHHDDDDDHDDHHHHHHHHHHHHHHHHDDDHHHHHHHH@%%@HHHH@@@@@@@@@@@HHHHHHHHHHHHHHHHDDDHHDHHHHDDHHHHHHHHHH #
+D:# HHHHHHHHHHHH HHHHHHHHDDDHDDD HHHHHHHHHHHHHHHHDDDHHHHH@HH@%%@HHHH@@@@@@@@@HHHHHHHHHHHHHHHHDDDHHHDHHHHHDDDHDDDDHH #
+D:#HHHH HHHH HHHHHHHHHHHHHDHHD@H@HHHHHHHHHHHHHHHDDDHHHHH@@@HH@%%@HHHH@@@@@@@HHHHHHHHHHHHHHHHHHDDDHHDDHHHHDDDHDHHHHHH #
+D:# HHHHHHHHHH HHHHHH HHHHDDDDHHHDDD@H@HHHHHHHHHHHHHHHDDDHHH@@@@@HH@%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHDHHHHHDDHHDDHHHH #
+D:# HHHHHH HHHH HHHDDDDDDHHDDHH@H@HHHHHHHHHHHHHDDDHHHHH@@@HH@%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHDDDHHHHDDHHHDDDHH #
+D:#HHHH HHHHHH HHHHHHHHHH HHHHHHHHHHHHDDDDHHHDDDH@H@HHHHHHHHHHHHHHDDDHHHHH@HHHH@%%@HHHHHHH@@@HHHHHHH@@@@@HHHHHHHDDDHHHHHHHHDDHHDDDDDHH #
+D:#HH HHHH HHHHHHHH HHHHHHHHHDDDHH@H@HHHHHHHHHHHHDDDHHHHHHHHHH@%%@HHHHHH@@@@@@@HHHH@@@@@@@HHHHDDDHHHDDDHHHHDDHHHDDDHHHH #
+D:# HHHH HHHH HH HHHHHHDDDDDDHHHH@H@HHHHHHHHHHHHHDDDHHHHHHHH@%%@HHHHH@@@@@@@HHHHHHH@@@@@HHHDDDDHHHDDDHHHHHDDHHHHHHH #
+D:# HHHHHHHH HH HH HHHHHHHHHDDDHHHDDDHH@H@HHHHHHHHHHHHDDDHHHHHHHH@%%@HHHH@@@@@@@HHHHHHHHHHHHHHHDDDDHHHHDDDHHHHHHDDHHDDDHH #
+D:#HH HHHHHHHH HHHHHHHH HHHHDDDDHDDDHH@H@HHHHHHHHHHHHHDDDHHHHHH@%%@HHHHHHH@@@HHHHHHHHHHHHHHHHHDDHHHHHHHHHHHHHHHDDHDDDDDHH #
+D:#HH HHHH HHHH HHHHHHHHHHHHHHHHHHHDHHHHHDDDHH@H@HHHHHHHHHHHHDDDHHHHHH@%%@HHHHHHHHHHHHHHHHHHHHXXXXXXXXDHHHHHHHHHHHHHHHHDDHHDDDHH #
+D:# HHHHHH HHHHHH HHHHHHHDDDDDHHHHDDHH@H@HHHHHHHHHHHHHDDDHHHHHH@%%@HHHHHHHHHHHHHHHHHHH========DHHHHHHHHHDDHHHHHDDHHHHHHHH #
+D:#HH HHHHHHHHHH HHHH HHHDDDDDHHDHDDHH@H@HHHHHHHHHHHHDDDHHHHHH@%%@HHHHXXXXX@@@@@@@@@@@========DHHHHHHHHHHDDHHHHDDDHHDDDHHHH #
+D:#HHHH HHHHDHHHHDHDDHH@H@HHHHHHHHHHHHHDDDHHHHHH@%%@HHH=====,,,,,,,,,,,,=======DHDHHHHHHHHHDDDHHDDDHDDDDDHHHH #
+D:# HHHHHHHHHH HHHHDDDDHDDDHH@H@HHHHHHHHHHHHDDDHHHHHH@%%@HHHH==,==@@@@@@@@@@@HHHHHHHHHHHHHHHHDDDHHHHHHDDHHHHDDDHHH #
+D:# HHHH HHHHHH HHHHHDDDDDDHDDHH@H@HHHHHHHHHHHHHDDDHHHHH@%%@HHHHH@,@HHHHHHHHH==================HDHHHHHHHHHDDHHDHHHH #
+D:# HHHHHH HHHHHHHHHH HHHHHHDDDDHHHDHH@H@HHHHHHHHHHHHDDDHHHHDDH@%%@HHHH@,@HHHHHHHHH==================HDHHHHDDDHHDDHDDDHHH #
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDHH@H@HHHHHHHHHHHDDDHHHHHHH@%%@HHHHH@,@HHHHHHHHH==================@DHHHHDHDHHDDHDDDHHH #
+D:#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,gg,,,,,,,,,,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,=HHHHHHHH=,,,@HHDHHHHDDHHDHHHHHH #
+D:#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,++,,,,,,,,,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,=HHHHHHHH=@D,,@HDDDDHDDHHHDDDHHHHH #
+D:#HH HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDHH@H@HHHHHHHHHHHHDDDHHHH@%%@HHHHHHHHHHH,H,,,HHH==================HDH,@HHHHDHDDHHDDDDDHH #
+D:# HHHHHHHH HHHHHHDDHDDDHH@H@HHHHHHHHHHHHHDDDHH@%%@HHHHHHHHHH@,@HH,,,,H==================HDH,@HDDDDHDDHHHDDDHHHH #
+D:#HH HHHHHHHH HHHHHHHH HHHDDDDHDDHH@H@HHHHHHHHDDDHHHDDD@%%@HHHHHHHHHH@,@HHHHHH,,==================HDH,@HHHDDHDDHHHHHHHHH #
+D:#HHHHHH HHHHHHHHHH HHHHHHHHHHDDHHDDHH@H@HHHHHHDDDHHHHHDD@%%@HHHHHHHHHH@,@HHHHHHHHD@,HHHHHHHHHHHHHHHHH@,,@HDDHHDDDHHDDDHH #
+D:#HH HHHHHH HHHHHHHH HHHHDDDHHHHHDDHH@H@HHHHHHHDDDHHHDDD%%@HHHHHHHHHH@,@HHHHHHHHHDD@,,,@HHHHHHHHHHH@,,,@HHHHHHHDDHHDDDHH #
+D:# HHHH HHHHHH HHHHHHHHHDDDDDHHHDDDHH@H@HHHHHHHHDDDHDDDD%%@HHHHHHHHH@,@HHHHHHHHHHHDDH@,,,,,@@@@,,,,,@@HHHHHHHHHDD DDDDDHH #
+D:# HHHH HHHH HHHHHHHDDHDDHHHDDDHH@H@HHHHHHHHHHHHHDD%%@HHHHHHHHH@,@HHHHHHHHHHHHDDDDHH@,,,,,,,,,@HHDDDHHHHHHDDHHHDDDHH #
+D:# HHHHHHHH HHHHHHHHHHHH HHHHHHHHHHHHDHHDDDHHH@H@HHHHHHHHHHHHHD%%DHHHHHHHHHH@,@HHHHHHHHHHHHDDDDHH@@@@@@@@@HHHHDDDDDHHHDDHHHDDDHH #
+D:# HH HH HHHHHH HHHHDDDDDHDDHHH@H@HHHHHHHHHHHH@%%DDDHHHHHHHHHH,,@HHHHHHHHHHHHHDDDDHHHHHHHHDDHHHHHDDDHHHDDHHHHHHHH #
+D:# HHHHHH HHHHHHHDDDHHHDDHH@H@HHHHHHHHHHH@%%@HDDDHHXXXXXXX,H,@HHHHHHHHHHHHHDDDDDHHHHHDDDDDHHHHHDDDHDDHHHHHHH #
+D:# HHHHHHHHHHHH HHHHHHHHHHHHHHHH HHHHHHHHHHDDDHH@H@HHHHHHHHHHHH@%%DDDHHH=======,H,,@HHHHHHHHHHHHHHHDDDDHHHHHHHHHHHHHHHHHDDHHDHHHHH #
+D:# HHHHHHHHHHHH HHHHHHHHHHHHHDDDDHHHDDDHH@H@HHHHHHHHHHH@%%@HDDDHH=======,H,HHHHHHHHHHHHHHHHHHHHDDDDDDDHHHHHHHHHHDDDHDDDHHHH #
+D:# HHHHHH HHHHHHDDDDDDHHHDDHH@H@HHHHHHHHHHHH@%%DDDDHH====,==,H,XXXXHHHHHHHHHHHHHHHHHHHHDDDDDDHHDHHHHHDDHHDHHHHH #
+D:# HHHHHH HHHH HHHDDDDHHHDDDDH@H@HHHHHHHHHHHH@%%@DDDDHHHHH,,,,H,====HHHHHHHHHHHHHHH@@@HHHHHHDDDHHHHHHDDHHHHHHHHH #
+D:#HHHHHH HHHHHHHHHH HHHHHH HHHHHHHHHHHDDHHDDDH@H@HHHHHHHHHHHHH@%%@DDDDHHHHHHHHH,=,==HHHHHHHHHHHHHH@VVVV@HHHHHDDDHHHHHDHHHHHHHHHH #
+D:# HHHHHH HHHHHH HHHHHH HHHHHHDDDDHHDD@H@HHHHHHHHHHHHH@%%@HHDDDHHHHHHHHH,,,HHHHHHHHHHHHHHHHH@VVVV@HHHHDDDDHHHDDHHHDDDHHH #
+D:#HHHH HHHHHHHHHHHHHH HHHHHHHHHHHH HHHHHHHHHDDHHDDDH@HHHHHHHHHHHHH@%%@HHHHDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@VVVV@HHDDDDHHHHDDHHDDDDDHH #
+D:#HH HHHHHHHHHH HHHH HHHHHHHHHHHHHHHHDDDHHHHHHHHHHHHH@%%@HHHHHHDDDHHHHHHHHHHHHHHHHHHH@HHHHHHHHH@@@@HHDDDDHHHHDDHHHHDHDHH #
+D:# HHHH HHHHHHHH HHHHHHHH HHHHHHHHHDDDHDDDDHHHHHHHHHHH@%%%@HHHHHHHHDDDHHHHHHHHHHHHHHHH@@@@@HHHHHHHHHHHHDDDDHHHHHDDHHHHHHH #
+D:# HHHHHHHHHH HHHHHHHHHH HHHHHHHH HHHHHHDDDDDHHDDHHHHHHHHHHHH@%%%@HHHHHHHHDDDHHHHHHHHHHHHHH@@@@@@@HHHHHHHHHHDDDDHHHHDDDHHHHHHHHHHHH #
+D:# HHHHHH HHHHHH HHHH HHHH HHHHDDDDDHHHDDHHHHHHHHH@%%%@HHHHHHHHHHHDDDHHHHHHHHHHHHHH@@@@@HHHHHHHHHHDDDDHHHHDDHHHHHHHHHHHH #
+D:# HHHHHHHH HHHHHH HHHHHHHHHDDDHDDHHHHHHHHH@%%%@HHHHHHHHHHDDDDHHHHHHHHHHHHHHH@HHHHHHHHHHHDDDHHHHHDDHHHHHHHHHHHHH #
+D:# HHHHHH HHHHHH HHHHHHDDDDDHDDHHHHHHH@%%%@DDDHHHHHHHHHDDDDDHHHHHHHHHHHHHHHHHHHHHHHDDHHHDHDDDDHHDDDDDHHHHHH #
+D:# HH HHHH HHHHHHHH HHHHHHHDDDHHHDDHHHHHH@%%@DDDHHHHHHHHHHHHDDDDDDDHHHHHHHHHHHHDDDDDDDDDHHHHHHDDDHHHHDDDDDHHHHDHH #
+D:# HHHHHHHH HHHHHHHHHHHH HHHHHH HHHHHDHHHDDHHHH@%%@HHHHHHHHHHDDDHHHHHHDDDDDDDDDDDDDDDDDDDDDDDHHHHHHHDD HDDDHHDDDHHHH #
+D:# HHHHHH HHHHHHHH HHHHHHHHHH HHHHHH DDDDDDHHDDHH@%%@HHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDHHHHHHHHHHHHHHDDHHDDDDDHHHH #
+D:#HHHHHHHHHHHH HHHHHHHHHHHHHH HHHHHHHHHHHH DDDDDHHDDDDD%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDHHHHDDDHHHHHHHHHHHHH #
+D:# HHHHHHHHHH HHHHHH HHHHHH HHHHHHHHHH DDDHDDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHHHHHHHH #
+D:#HHHHHH HHHHHH HHHHHHHH HHHHHHHH HHHHHHHHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHDDDDDHHHHHHHHH #
+D:#HHHHHH HHHHHHHH HHHHHHHHHHHHHH HHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHHHHHHHHHHH #
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_bree.txt b/lib/mods/theme/edit/t_d_bree.txt
new file mode 100644
index 00000000..92fde41f
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_bree.txt
@@ -0,0 +1,91 @@
+# File: t_d_bree.txt
+#
+# Destroyed Bree
+
+# original town by someone else
+# screwing up by fearoffours (fearoffours@moppy.co.uk)
+#
+# Created for ToME
+
+# Permanent rubble
+F:R:206:3
+
+############### Town Layout ###############
+
+D:###########################################################################################################=##########################################################################################
+D:#DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD=DDDDDDDDDDDDDDD VVDDDDDDDDDDDDDD--DDDDDDDD==DDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:# DDD DDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD VDDDDDDDDDDDDDD--DDDDDDDDDDDDDDDDD D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDDDDDDDDDDDD D D DDDDDDDDDDDDDDDDDDDDDDDDDD DD D D D DDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDVVDDDDDDD --DDDDDDD====DDDDD DDDDDDDDDDDDDD DDD DD DDDDDDDDDDDDDDDD #
+D:#DDDDDDD D DDDDDDDDDDDDDDDDD DDDDDDDD DD D HHDD D D DDDD D D D D D D DDHHDDDD=DDDDDDDDDDDDDDDDDDDDDDDVV===DDDDD --DDDDDHHHDDDDDD =DDDD=DDDD===DDDDDDDDDDDDDDDDDDDD DDDDDDDDDDD#
+D:# DDDD DDD DD DDDDDDDDDDDDDDDDD D DD DDDDDDDDD D D DDDDDDDDDDDDDDDDDDDDDDDDDHHHDDDDDDDDDDDD VVDDDDDDD --DDDDDDDDDDDDDDDDDDDDDDHHH DDDDDDDDDDDDDDHHHDDDDDDD=DDDDDDD #
+D:#OOOODDDDDDD D D DDDDDDDD D DDDDDDDDD D DD D DDDDDDDDDDDDD D DDDDDDDDDDDDDDDHHDDDDDDD DDDDDDDDDDDDDDD VDDDDDDD --DDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDD===HDDDDDDDDDDDD #
+D:# OOOODDDDDDD DDDDDDDDDDDDDDDDDDDDDDD HH DDDDDDDDD HDD DDDDDDDDDDDDD D DDDDDHHHHHHDDDDDDDDDDDDHHHDDDDDDDDDDDDDDD VDDDDDDD --DDDDDDDDDDDD DDDDDHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD== #
+D:#--- OOOOODDDDDDDDDDDDDDDDD DDDDDDDD D DD D HHHDDHHDDDDDDDDD D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD==DDDD VVV ---DDDDDDDDDDDD DDDDDDDDD VVDDDDDHDDDDDDDDDDDDDDDDD #
+D:#------ OOOOOO DD D D DDDDDDDDDD DDD DDDDDDDDDDDHHHH = D DDDDDDDDDDDDDDDDDDDDHHHDDDDDDDDDDDDDDDDDDDDDDDD V --DDDDDDDDDDDDD DDDDHD VVVVDDDDDDDDD== DDDDDDDDDDD #
+D:#---------- OO DDD HDHHHDDD DDDDDDDDDDDDDDDDD D D DDDDHHHDDDDDDDDDDDDD D HDDDDDDD =DDDDDDDDDDDDDD===DDDDDDDDDDDDD V -- DDDDDDDDDDD DD VVWWVVVDDDDDHHH DDDDDDDDDDDDDD #
+D:#-------------- OO DDDDDDDDDDDDDDDDD H D D D DDDDDHHHDDDDDDDDDDDDDD DDD D DDDDDDDDDDDDDDDDDDDDDDH==HDDHHDDDDDDDDDDVVV --DDDDDDDDHHHHDDDDDD DDD VVVWWWWWVVVDDDDDDDDDDDDDDDDDDDDDDD#
+D:#------D-------- OOODDDDDDD D DDDDHHHDDD HHD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDD =DDDDDDDDDDDDDDDD VVV --DDDDDDDDDDDDDDDD VVWWWWWWWWWVVDDDDDDDDDDDDDDDD #
+D:#----------------- OO H DDDDDDDDDDDDDDDDD HHH D DDDD DD DDDDDDDDDDDDDDDDDDDDD DDDDDD DDDDDDDDDDDDDDDDHDDDDDDDDDDDDDDDDDD VVVVVVVDDDDDDDDDDDDDDDD VVWWWWWWWWWWWVDDDDDD DDDDDDDD #
+D:#------------------- OOOOO DD DDDDDDDDDD DDDDDDDD D DDDDDDDDDDD DDD DDD DD DDD DDDDD DDDDDDDDDDDDDDDDD=DDDDDDDDDDDDDDDD--VVVV VVVVVDDDDDDD VVWWWWWWWWWWWVVDDDDDDDDD DDDDD #
+D:###------------------ OOH D HH DDD DDDDDDDDD DDDDDDDDDDDDDDDDD DDDD DDD ,,,,,,,,,,,,,,,HH,DDDDDDDDDDDDDDDDDDDDD==DDDDDDDDD -- VVVVV VV VVVVVVVWWWWWWWVVVDDDDDDD DDDDDDDD #
+D:#CC####------------------ OOODDDDDDD DDD DDDDDDDDD DD D DDDD DD DDDD,,,,CCCCCCCCCCCCCCCCCC,,,,,,,H,DDDDDDDDDDDDDDDDDDDDDDD --DDDDDDD VVVVVV VVVVWWVVVDDDDDDDDDDDDDDDDDDDDDDD #
+D:#TTCCCC###----D----------,, OO DDDDDDDDDDDDDDD=DDDDDDDDDDDDDDDDDDDDDDD DD ,,,CCCCCCTTTDDTTTDD TTDDTCCCCCCCCCC,,,,DDDDDDD=DDDDD==DDDDDDDD --DDDDDDDDDDDDDDDDDDDDDDDVVVVDDDDDD===HHHDDDD=DDDDDD #
+D:#--TTTTCCC###---------,,,-- OO = DDD D DDDDDDDD DD D DDD DDDD,CCCCTTTTTD---$----------TT T TDDDTCCCCC,,,,,DDDDDDDDDDDDDD H ^--DDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:#------TTTCCC##-----,,------ ODDDDDDDDDDDDDDDD DDDDDDDDD DDDDDDDD DD ,,CCCTTDDD....$$$........D.----H-----TDDTTCCCCCC,,DDDDDDDDDDDDDD^^^ --DDDDDDDDDDDDD==DD DDDDDDDDDD DDDDDDDDDDDDDDDDDD #
+D:#---------TTTCC##,,,-------- OO D DDHHHHDDDDDD DDDDDDDDDD D DD ,CCC TD....--ssss-sss-D.--H.......H..--$--TTDDDTCCC,,,DDDDDDD ^^ --DDDHHHD DDDDDDDD DDDDDDDDDDDDDDD DDDDD =DDDDDDD #
+D:#------------TC,,###- --- OODDDDDDD DDDD H =DDDDDDD DD D,CCTTT.DDH=---S.S=$S$S#-.------DD-$,,.....------TDDDCCC,,DDDDDDD^^ --DDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDD=DDDDDDDD #
+D:#-------------,TTCCC### -- OOO DDD DDD DDDD D D DD DD ,,CCTD...=,,,,H-ssss.ss-...-ss=s--sssss,---...H..---TDDDCCT,H ^^DDDDDDD--DDDDDDDDDDDD DDDDD DDDDDDDDDDDD==DDDDDDDDDDD #
+D:#--------- ,,,--TTTCCC -- OODDDDDDDDDDDHDDDDDDDDDDDDDDDDDD D ,,CCCTT..-------,,#.,##,-#-.--sss.s$$$ssss,--$HH--..$----TDCCTT, ^^^DDDDDDD --DDDDDDDDDDDD===DDDDDD DDDDDDDDDDDDDDDDDDDDDDDD #
+D:#-------- ,, ,,----TTTCCDDDDDDD O =DDDDDDDDD DDDDDHHDDDDD DDDDCCC D=.H-sssSss$S,,,------.--S.SSSS=SS$$--,----DD.-....--=DCCTT,^^^DDDDDDD --DDDD=HHHDDDD DDDDDD DDDDDDDDDD=DDDDDDDDDDDDDDD#
+D:#------ ,, ,DDDDDDDDDDDDDDDD OO DDDDDDDDDD DHDDDDDDDD DDD,CCTDT.=.---ss$sSSS---,,,--H-.--ss,s$s=sss=s--,-$-.==-$--..--TDCCT^^^^ ^^DDDDDDD --=DDDDDDDDDDDDDD DD DD =DDDDDDDDDDDDDDDD #
+D:#------- ,, ,,DDDDDDDDHHHDDDDD OODDDDDDDDDDDDDHDDDDDDDDDDD D ,CCTT...-----s,,-sss#-,,-,DD-$.--.ssssHsss,s#--,-...-------..-==TC^^^ ^DDDDDDD ----DDDDDDDDDDDDDDDDDDDD DDDDDD DDDDDDDD #
+D:#------- {,DDDDDDDDDDDDDDDD = OODDDDDDD DDDDDDDDDD DDD,CTT..-DD,H,,####$###$,-$-,,--.--#####=.#$#H----..-DD---H---$.--D^^^^ ^DDDDDDD--- --DDDDDDDDDDDDDDDDDD DDDDDD DDDD #
+D:#-=-------DDDDDDD DDDDDHDDDDDDDDDDDOOO D DDDDDDDD DDD D ,CT..,,,,----,,,,,#,,------,H-$--#.-#.##.##$-...$,---.sss----.--T^^ ^DDDDDDD -- --DDDDDDD HDDDDDDDDDDDDDDDDDDDDDDD===DDDDDD#
+D:#----------DDDDDDDDDDDDDDDDDDDDDDD OO DDDDDDDD DDD,CCT.,ss$sss#----,$---DD---#-,==-----.----#....-,--,,sStSSS--$.-D^^^ ^DDDDDDD -- -----DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD#
+D:#-------------DDDDDDD HDDDDDDD = OODDDDDDDDDDDDDDDD D ,CCTT.-StS,$S----,-----$s$sH,--..-=H-----....--,,,$,,-.s.sss#--.-D^^^ ^ --DDDDDDD --DDDDDDD ,,DDDDDDDDDD DDDD #
+D:#----------=DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDOOOOO DD D ,CTT-.--s=s,ss#-$,-----S$SSSS--.------$-..==,,,-sssss-,##==#---.-T^^ ^DDDDDDD --DDDD==D -----DDDDDDD ,,DDDDDDDDDDDDDDDDDDDDDDD #
+D:#--------DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD OO D DD D DD,CCT-..-#####,#---HH---$sss$s,-...$...H.$--$XXX,-$ss---,------..=-^^^ ^ ^^ ^ ---DDDDDDD D---D ,,, HDDDDDDDDDDDDDDDD #
+D:#- ----DDDDDDD =DHHDDDDDDDDDDDDD =DDDDDDD OOOOOOOO$ DD $D ,C OOOO--OOOOO----,----######-.---.,----,-UUUUs-SSS$--,--H--..---^^ ^ ^ H ---DDDDDHHDDDDDDDDD -----,DDDDDDD OOOOOOOOOOOOOO#
+D:#- ----DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDOOOOOOO==,CT-OssOOOO---OOOOOOOOO--OOOO--.-D-.-s$s--,XXXX,-=sss-$-,---$$-=D^^DDDDDDDDDDDDDD--DDDDDDDHHHDDDDDD --DDDDDDD OOHDDDDDDD #
+D:#- -----DDDDDDDDDDDDHHDD =DDDDD DDDDDDDDDDDDDDDD OOOOOOOOSt.---------XXX$-OOOO--OOOO---.SStS--,####,--s$s-=-,DD-.--=^^ ^ ^ --DDDDDDDDDDHHHDDDDDDDDDD--- OOOO HDDDDDDD #
+D:#- --- -----DDDDDDHHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,,CT--.ss.-$sHs$---$XXs,---------OOOO.-s$s---,,,,,-###.--,---..-T^^ ^ ^DDDDDDD --DDDDDDDHDDDDDDDDDDDDDDDD --- OOHDDDDDDDDDDDDDDDD #
+D:# ---D ----DDDDDDDDDDDDDDDDDDDDDDD = =DDDDDDD ,,CT--.s#.-SSt,S-HH##H#,---H-$------OO-#$#-ss,,ss-,,,---,---D.--DH^ ^DDDDDDD -,-DDDDDDDDDDDDDDDDDDDDDDD OOOOODDDDHHHDDDDDDDDD #
+D:# ------- ---- HDDDDDDDDDDDDDDDDDDD DDDDDDDDDDD ,,CTT-..$$-=sss$--,,,,,,---------DDH-OO-,--SSS$St-ss-,-$$--...-T^^ ^ ^DDDDDDD -,DDDDDDD =DDDDDDDDDDDDDDOOOODDDDDDDDDDDDHD DDDDDDD#
+D:# ------- ------DDDDDDDDD DD DDDDDDDDDDD DDDDDDDDDD ,,CCTD---.$#,#$,-,sss,,S-S,SSSSS--$---OO,--s-ss----S--,.....---^^ ^^ ^^^ -,DDDDDDDDDDDDDDDD OOOOOOOODDDDDDDDDDDDD DDDDDDDDD #
+D:# -----DDDDDDD -----DDDDDDDDDDDDDDDD =DDDDDDDDDDDDDDDD ,,CCT----..,,,,,-St$SS,-s,s,s$ss--==--OOO-#,##-$-ss....-==--T^^DDDDDDD ^^ -,-DDDDDDDDDDDDDD OOOOODDDDDDDDDDDDDDDDDDD DDDDDDDDDDD #
+D:# ---- --------DDDDDDDDDDDDDDDDDDDDDDHHDDDDDDDD H ,,CCTD--DD $--$$sss$,-##,##,#=--------OO,.,,.,-##.----DDDT^^ ^ ^^DDDDDDD-,DDDDDDD OOOOODDDDDDD DDDDD HDDDDDDDDD===DDDD#
+D:# ---------------DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD D ,,,CCTTTT--..---,##,###,--,,,--HH-----...OOOOOOOOOOOTTDDDCC^^^ ^^ ^^DDDDDDD ,-DDDDDDD OOODDDDDDDDDDDDDDDDDDDDDDDHHDDDDDDDDDDDDDD #
+D:#DDDDDDD --------DDDDDDDD DDDDDDDDDDDDDDHHDDDDDDDDDDDDDDDDDDH,,CCCC --.DD.....HH,-,==--,--==..H..--H----TDDTTOCCCCC,,^^^^^^^^^=^DDDDDDD -.- OOOOODDDDDD DDDDDDDDDDDDDDDDHHHDDDDDDDDDDDD #
+D:# ----------DDDDDDDDDDDDDD = HDDDDDHHHDDDDDDDDDDDDDDD ,, ,,CCCTT-------D--.....$....H.-------TTTDDTTCCCCO,,,,, ^^^^^^^DDDDDDD -.- ODDDDDDDDDDDDDDDDDDHHDD DDDDDDDDDDDDDDDDDDDD #
+D:#DDDDDDD -----D-DDDDDDDDDDDDDDDDDDDDDDDDDDDHHDDDDDDDDDDDDDDDDD ,, ,,CCTTT TTDTTDD-D--...------DTTTDDDCCCCCC,,,,OOOHDDDDDDDDDDDDDDDD -.- OOOODDDDDDDDDDDDD DDHHHDDDDDDDDD DDDDDD D #
+D:#DDDDDDD ----DDDDDDDDDDDDDDDDHHDDDDDDDDDDDDDHHH =DDDDDDD ,,, ,CCCCCCCCCCTTDDT--==-TTTTDTCCCCCC,,,,,, OOODDDDDDDDDDDDDDDD OOOOOOOOODDDDDDDD DDDDDDDDDDDDDDDDHHDDDDDDDDDDDDDDDDDDDD #
+D:# ^^ ----DDDDDDDDDDDDDDDDDDDDDDDDDDDHDDDDDDDDDDDDDDDDDDD ,, ,H,,,,,,,,CCCCCTTTDDTCCCCC,,,,,,DDDDDDDDDDDDDDOODDDDDDD DDDDDDDDDOOO--DDDDDDDDDDDDDDDDDDDDDDDDDDDDHDDDDDD DDDDD DHHDDDDDDDD #
+D:# ^^^^^DDDDDDDDDDDDDDDD DDDDDDDDDDDD DDDDDDDDDDDDDDDDD ,,,DDDDDDDDDDDDDD,,,,,CCCCCC,,,,, HDDDDDDD D OOOODDDDDDD OOO--DDDDDDDHHHDDDDDDDDDD DDDHHDDDD DDDDDDDDDDDD #
+D:# ^^^^^^^^^DDDDDDDDDDHHHHDDDDDDDDDDDHD DDDHHHDDDDDDDDDDDDDD ,,DDDDDDDDDDDDDDDD ,,,,,,DDDDDDDDDDDDDDDDDDDDDDD OOOOOOO OOO---DDDDDDDDDDDDDDDD HDDDDDDDDDDDDDD DDDDDDDDDDDDD #
+D:# ^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,,DDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDOOOOOOO----DDDDD=== DDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:# ^^^^^^^^^^^^^^^DDDDDDDDD DDDDDDDDDDDDDDDDDDDD HH =DDDDDDD ,,,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD =DDDDDDDDDDDDDDDDDDDDDDD ..------DDDDDDDDDDDDDDDDDDDDDDDDDDDD DDD DDDDDDDDDHHHDDDDDDDD #
+D:# ^^^^^^^^^^^^^^DDDDDDDDDDDDDDDD DDDDDDDDDDD DDDDDDDDDDD ,,,=DDDDDDDDDDDDDDDD HH......DDDDDDDDDDDDDDDDDDDDDDD ....-----DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHH==DDDDDD #
+D:# ^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDD DDDDDDDDDDDD DDDDDDDDDDDD,,,DDDDDDD ........... ............DDDDDDD....=.......-------,,,,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDHHDDD #
+D:#^^^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,,DDDDDDD .HHDDDDDDDDDDDDDDDDDDDDDDD .........--------HH----DDDDDDD,,,,,,, ,,,,,,,,,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD==DDD #
+D:# ^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDD DDDDDDDD DDDDDDDDDDDDDDD ,, H .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHH==DDDDDDDDDDD ,,,,,,DDDDDDD,,,,,,,,,DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:# ^^^^^^^^^^^^^^DDDDDDDDDDDDD DDDDD DD DDDDDDDDDDDDDDDDDDDDD ,, HH... HDDDDDDDDDDDDDD=DHHHDDDDDDDDD DDDDDDDDD DDD DDDDDDDDDDDDDDDDDDDDDDDDDDD,,,,,DDDDDDD ------ ---DDDDDDD #
+D:# ^^^^^^H^^^^^^^^DDDDDDD DDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDD,, .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ,,,,,,,,------- -----DDDDDDD#
+D:# ^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDHHHDDDDDDDDDDDDDDDDDDDDD , ..HDDDDDDDDDDDDDD==DDDDDDDDDDDDDDDDDDDDDDDDDDHHDHDDDDDHDDDDD DDDD DDDDDDDDDDDDDDDDDDDDDDDD H---------------- #
+D:# ^^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDD ,, ..DDDDDDDDDDDDDDDDDDHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD---------D--------DDDDDDD#
+D:# ^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDD DDDDHHHD DDDDDDDDDDDDD , ..DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDHDDDDDDDDDDDD====DDDDDDDDDDDDDDDDDDDDDDDDD -----------------DDDDDDD #
+D:# ^^^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDHHHD DDDDDDDDDDDDDDDDDDDDDDDD ,,.DDDDDDDDDDDDDDDDDDD ===DDDDDD DDDDHHDDDDDDDDDDHH==DDDDDDDDDDDDHHHDDDDDDDDDDDDD DDDDDDDDDDDDD --- ---- ----DDDDDDD#
+D:# ^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDDDDDDDD ,.DDDDDDDDDDDD==DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDD===DDDDDDDDDDDDDDDDDDDD - -- --DDD==DD #
+D:# ^^^^^^^^^^^^^^DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDD .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHDD==DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHDDDDDDDDDDDDDDDDDDDDDDDDDDHHHDDD #
+D:# ^^^^^^^^^^^^^^ HDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD .DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD #
+D:######################################################################################################################################################################################################
+
+
+############### Starting positions ###############
+
+# Standard starting position for normal races
+?:[AND [EQU $LEAVING_QUEST 0] [NOT [EQU $RACE Vampire] ] ]
+P:33:131
+
+# Standard starting position for vampires (at the dungeon entrance)
+?:[AND [EQU $LEAVING_QUEST 0] [EQU $RACE Vampire] ]
+P:31:150
diff --git a/lib/mods/theme/edit/t_d_cerin.txt b/lib/mods/theme/edit/t_d_cerin.txt
new file mode 100644
index 00000000..02d9ca05
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_cerin.txt
@@ -0,0 +1,75 @@
+# File: t_d_cerin.txt
+
+# Cerin Amroth map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNNNNNNNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDDDDDDDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^^^^^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^DDDDD^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^DD^^^DD^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^DD^HHH^DD^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^DD^HHHHH^DD^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHENDD^DD^HCH=HCH^DD^DDNEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHENDD^DD^HH===HH^DD^DDNEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHENDD^DD^HCH=HCH^DD^DDNEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^DD^HHHHH^DD^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^DD^HHH^DD^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^DDD@DDD^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^DD@DD^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDD^D@D^DDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHNNDDD@DDDNNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_dale.txt b/lib/mods/theme/edit/t_d_dale.txt
new file mode 100644
index 00000000..1162c294
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_dale.txt
@@ -0,0 +1,75 @@
+# File: t_d_dale.txt
+
+# Dale map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# @@@@@@@@@@@@@@@@ #
+D:# @@%%%%%%%%%%%%%%%%@@ #
+D:# @@@%%%%%%%%%%%%%%%%%%%%@ #
+D:# @%%%%%%%%%%%%%%%%%%%%%%%%@ #
+D:# @%%%%%%%%%%%%%%%%%%%%%%%@$$$$$$$$$$$$$$$ #
+D:# @@@@%%%%%%%%%%%%%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# @%%%%%%%%%%%@@@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# @%@@@@@@@@@@@@HHStSSSSSHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH @@@@@@ #
+D:# @%#HHHHHHHHHHHHHsssssssHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH @@%%%%%%@ #
+D:# @%#HHHHHHHHHHHHH#######HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH @@%%%%%%%%%%@@@ #
+D:# @%#HHHHHHHHHHHHH###@###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH @%%%%%%%%%%%%%%%@@ #
+D:# @%#HHHHHHHHHHH$HHHH@HHHH$HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%%%%%%%@ #
+D:# ##HHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH$HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==================@ #
+D:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@#
+D:# #HHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHSSSDSHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@==================@ #
+D:# #HHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HEHsssssHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%%%%%%%@@@ #
+D:# #HHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HH#H###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@%%%%%%%%%%%%%%@ #
+D:# #HHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@H##@##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@%%%%%%%%%@@ #
+D:# #HHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@HHH$HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@@@@@@@ #
+D:# #HHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# #HHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHSSSHHHHHHHHHHHHHHH@HHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# #HHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHsssssHHHHHHHHHHHHHH@HHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHH$########HHHHHHHHHHHHH@HHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# $HHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHH$########HHHHHHHHHHHH@HHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# $HHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHH@HHHHHHHHHHHHHHH,@@@@@HHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH$HHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@$HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH #
+D:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH$H@HHHHHHHHHHHHHHUUUUUUYUUUUHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHHHXXXXXXXXXXXHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@HHHHHHHHHHHH===========HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@$HHHHHHHHHH=====@=====HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# #HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH$@@@@@@@@@@@@@@@@@HHHHHH$HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HH#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHH#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHD#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHDD#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_edoras.txt b/lib/mods/theme/edit/t_d_edoras.txt
new file mode 100644
index 00000000..17d7abbd
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_edoras.txt
@@ -0,0 +1,75 @@
+# File: t_d_edoras.txt
+
+# Edoras map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#####,,,,,,,#####HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########,,,,,,,,,,,,,,,#########HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH######,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#######HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#####,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#####HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########,,,,,,,#####$$################################HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#####HHHHHHH,,,HHHH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHH,,,HHHHHH,,HHHHHHHHHHHHHHHHHHHH,,,,,,,,,,,,,,,,,,H###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH####HHHHHHHHHH,,,HHHHHHHHH,,HHHHHHHHHHHHHHHHHHH,################,HHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHHHHHHHH,,,,,,,,,,,,,,,,HHHHHH,################,HHHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,,,HHHHHHHHHH,#########,HHHH,,HHHHH,################,HHHHHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HH,,HHHHHHHHHH,#########,HHHHH,,HHHH,################,HHHHHHHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHH,,HHHHHHHHHH,#########,HHHHHH,,,,,,,,,,,,,,,,,,,,,,,HHHHHHHHHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHHH,,HHHHHHHHHH,#########,HHHHHHHHHHHHHHHHHHHHHHHHH,,HH,,HH######HH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHHHH,,HHHHHHHHHH,,,,,,,,,,,HHHHHHHHHHHHHHHHHHHHHHHHHH,,HH,,H######HHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HH,,,,,,,,,,,,,,,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHH######,,,,,HH,,######HHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHH,$#######$,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH######HHHH,,HH,,HHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHH,#$#####$$,HHHHHHHHHHH####################HHHH######HHHHH,,HH,,HHHH######HH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHHH,####$####,HHHHHHHHH####HHH,,,,,,,,,,,,,####HHHHHHHHHHHHHH,,HH,,,,,######HHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHHHH,########$,HHHHHHH####HHHH,,HHHHHHHHHHH,,,,###HHHHHH######,,,HH,,HH######HHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHHHHH,,,,,,,,,,,HHHHH####HHHHHH,,HHHHHHHHHHHHH,,,,###HHHH######HH,,HH,,HHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHHHHHH,HHHHHHHHHHHHHH###HHHHHHHH,,HHHHHHHHHHHHHHH,,,,###HH######HHH,,HH,,,,######HHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHH,,,HHHHHHHHHH,HHHHHHHHHHH###HHHHHHHHHH,,HHHHHHHHHHHHHHHHH,,,,##HHHHHHHHHHH,,HH,,H######HHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHH,,,H,,,,,,,,,,,,,HHHHHHHH##HHHHHHHHHHHH,,HHHHHHHHHHHHHHHHHHH,,,##HHHH######,,,HH,,######HHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHH,,,HH,$$#########,HHHHHH###HHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHHHHHH,,##HHH######HH,,,,,,,HHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHH,,,,,,,$$#########,HHHHH##HHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHHHHHHH,,##HH######HHH######HHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHH,,,,,,,##$########,HHHH###HHHHHHHHHHHHHHH,,#########HHHHHHHHHHHHHH,,##HHHHHHHHHH######HHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHH,,,HHH,###########,HHH###HHHHHHHHHHHHHHHH,,HHHHH######HHHHHHHHHHHHH,,##HHHHHHHHH######HHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHH,,,,HHH,,,,,,,,,,,,,HHH##HHHHHHHHHHHHHHHHH,,HHHHHHHHH####HHHHHHHHHHHH,,##HHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########CCCC########$############HHHHHHHHHHHHHHHHH,,HHHHHHHHHHH###HHHHHHHHHHH,,###############$############HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########CCCC########$############HHHHHHHHHHHHHH$$$,,###HHHHHHHHH###HHHHHHHHHH,,##############$#############HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########CCCC#########$###########HHHHHHHHHHHHHH#$###$##HHHHHHHHHH##HHHHHHHHHHH,,#############$#############HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########CCCC##########$###$######HHHHHHHHHHHHHH#####$$#HHHHHHHHHH##HHHHHHHHHHH,,##############$############HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########CCCC###########$##$######HHHHHHHHHHHHHH########HHHHHHHHHH##HHHHHHHHHHHH,,#############$############HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########CCCC####$#######$########HHHHHHHHHHHHHH###$####HHHHHHHHHH##HHHHHHHHHHHH,,##############$#####$#####HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########CCCC#############$########HHHHHHHHHHHHH########HHHHHHHHHH##H#######HHHH,,##############$###########HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########CCCC##############$#######HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HH#######,,,,,,#############$$$#$########HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHH,,,,,,,,,HHHHHHHHHHHHHHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHH###HH#######,,,,,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHH##,,HHHHHH#######HHHH###HHHHHHHHHHHHHHHHHHHHHHHHH###HHH#######HHH,,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHH##,,,,,,,,#######HHHHH###HHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHHHHHH,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHH##,,,,,,,#######HHHHHH###HHHHHHHHHHHHHHHHHHHH####HHHHHHHHHHHHHHHH,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHH##,HHHHHH#######HHHHHHHH###HHHHHHHHHHHHHHHH####HHH$######HHHHHHH,,,##HHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHH##,,HHHHHHHHHHHHHHHHHHHHHH###################HHHHH$######HHHHHH,,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHH##,,HHHHHHHHHHHHHHHHHHHHHHHHH###########HHHHHHHHH$######HHHHH,,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHH##,,HHHHHHHHHHHH####$$$HHHHHHHHHHHHHHHHH#######HHHH,,,,HHHH,,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHH##,,,HHHHHHHHHH#######HHHHHHHHHHHHHHHHH#######HHHHHHH,,H,,,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHH##,,,,HHHHHHHH#######HHHHHHHHHHHHHHHHH#######HHHHHHHH,,,,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHHHHH##,,,,HHHHHHHHHH,HHHHHHHHH#######HHHHHHH,,,,,HHHHHHH,,,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHHHHH###,,,,HHHHHHHH,HHHHHHHHH###$#$$HHHHHHHHHHH,,HHHHH,,,,##HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHHHHHH###,,,,HHHHHH,HHHHHHHHH#######HHHHHHHHHHHH,,HH,,,,###HHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHHHHHHH####,,,,HHH,HHHHHHHHHHHH,HHHHHHHHHHHHHHHH,,,,,###HHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHHHHHHHHH###,,,,,,,HHHHHHHHHHH,HHHHHHHHHHHH,,,,,,####HHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHHHHHHHHHHHHHHHHH######,,,,,,,,,,,,,,,,,,,,,,,,,,,,#####HHHHHHHHHHHHHHHHHHHHHHHHHH##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##HHH==============HHHHHH######,,,,,,,,,,,,,,,,,,,######HHHHHH=================HHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHH=================HHHH###########,,,,,#########HHHHHH===================HHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHH==================HHHHHHHHHHHH,,,,,HHHHHHHHHHH======================HHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHH================================================================HHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHH===========================================================HHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH####HHH=====================================================HHHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###HHHH==============================================HHHHHHH###HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH####HHHHH=======================================HHHHHH#####HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#####HHHHHHH==========================HHHHHHHHHH#####HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH######HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#########HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH###########HHHHHHHHHHHHHHHH############HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH########################HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_esga.txt b/lib/mods/theme/edit/t_d_esga.txt
new file mode 100644
index 00000000..319eff22
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_esga.txt
@@ -0,0 +1,75 @@
+# File: t_d_esga.txt
+
+# Esgorath map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%==%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%===,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%===,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%===,,,,SSS,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%===,,,,,,ssss,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%===,,,,,,,,$#@##,,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%===@,,,,,,,,,,,,@,,,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%=%%%%===,,,,@,,,##@#$,,,@,,,,,,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%=%%%%===,,,,,,,,@@@@@@,,,,,@,,,,,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%=%%%%===,,,,,,,,,,S,S,,,@,,,,,@,,##@##,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%=%%%%===,,,,,,,t,,,sssss,,,@,,,,,@@@@@@@@,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%=%%%%===,,,,SSS,S,,,,,##5##,,,@,,,,,,,,,,,,@,,,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%=%%%%===,,,,,,,sssss,,,,,,,@,,,,,@,,,,,,,,,,,,@,,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%=%%%%===,,,,,,,,,,##@##,,,,,,,@,,,,@,,,,,,,,,,,,,@,,SStSS,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%=,,,,,,,,,,,,,,@,,,,,,,,,@,,,@,,SSSStSSS,SS,@,,sssss,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%=%%%%=,,,,$#@$$,,,,@,,,,,,,,,@,,@,,,$ssssss,sss,@,,$#,##,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%=,,,,,@@@@@@@@@@@@@@@@@@,@,,,,$$###@$$###,@,,,,@,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%=%%%%=,,,,,,,,,,,@,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%=,,,,,,,,,,@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@,,,,,,,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%=%%%%=,,,,,,,,,@,,,,StS,,,,,,,=========,,,,,,,@,,,,,,,,,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%=,#$@$$,,@,,,ssss,,,,,==%%%%%%%%==,,,,,,,@,,,,,,,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%=%%%%=,,@@@@@@,,$#,##,,,,=%%%%%%%%%%%%=,,,,,,,@,#$@$#,,,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%=,,,,,,,@,,,@,,,,,=%%%%%%%%%%%%%%=,,,,,,,@,,@,,,,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%=%%%%=,,,,,,,@@@@,,,,=%%%%%%%%%%%%%%%%=,,,,,,,@,@,,SS,,,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%=,,,,,,,@,,,,,,=%%%%%%%%%%%%%%%%%=,,,,,,,@,,,sss,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%=%%%%=,,,,,,,@,,,,,=%%%%%%%%%%%%%%%%%%=,,,,,,,@,,$#@##,,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%=,,,,,,,@,,,,,=%%%%%%%%%%%%%%%%%=,,,,,,,,@,,,@,,,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%=%%%%=,,,,,,,@,,,,,=%%%%%%%%%%%%%%%=@,,,,,,,,,@,,@,,,,,,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%========@,,,,,=%%%%%%%%%%%%%=,,@,,,,,,,,,@,@,,,,,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%=%%%%=@@@@@@@@,,,,,=%%%%%%%%%%=,,,,,@,,,,,,,,,@,,,$#@##,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%%%%========@,,,,,=%%%%%%%==,,,,,,,@,,,,,,,,,@,,,,@,,,,,,,=%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#%%%%%%%%%%%%%%%%%%%%%%%=%%%%=,,,,,,,@,,,,,====CCC==,,,,,,S,,StSSSS,,,@,,,@,,,,,,,,=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#H%%%%%%%%%%%%%%%%%%%%%%%%%%%%=,,,,,,,@,,,,,,,==CCC==,,,,,s,sssssss,,,,@,@,,,,,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HH%%%%%%%%%%%%%%%%%%%%%%%=%%%%=,,,,,,,@,,,,,,,==CCC==,,,,#$,#@$$##,,@@@@,,,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=,,,,,,,@,,,,,,,==CCC==,,,,,$$,@@@@@@@,,,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHH%%%%%%%%%%%%%%%%%%%%%%%%=%%%%=,,,,,,,@,,,,,,,==CCC==,,,,,,,,@,,,,,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=,,,,,,,,@@@,,,,,==CCC==,,,,,,,,@,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHH%%%%%%%%%%%%%%%%%%%%%%%%%%%==,@@@@@@@,,,@,,,,,==CCC==,,,,,,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHH%%%%%%%%%%%%%%%%%%%%%%%%==@@@@,,,,@,tSSS@,,,,,==CCC==,,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHH%%%%%%%%%%%%%%%%%%%%%%==@@@@=====,@sssss@,,,,,,==CCC====%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHH%%%%%%%%%%%%%%%%%%%==@@@@==%%%==,@#####@,,,,,,,==CCC%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHH%%%%%%%%%%%%%%%==@@@@==%%%=%%%==@##,##@,,,,,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHH%%%%%%%%%%%%==@@@@==%%%%%%%%%%%==@@@@@@,,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHH%%%%%%%%%%==@@@@==%%%%%%%%%%=%%%==,,,,,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHH%%%%%%==@@@@==%%%%%%%%%%%%%%%%%%==,===%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHH%%%==@@@@==%%%%%%%%%%%%%%%%%%=%%%==%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHH==@@@@@==%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHHHH@@==%%%%%%%%%%%%%%%%%%%%%%%%%%%%=%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHHHH==%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHSSSSHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHssssHHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHH$#@##HHHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHHHHHHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHHHHHHHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHHHHHHHHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHHHHHHHHHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHHHHHHHHHHHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHHHHHHHHHHHHH%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_gond.txt b/lib/mods/theme/edit/t_d_gond.txt
new file mode 100644
index 00000000..18bb7c10
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_gond.txt
@@ -0,0 +1,100 @@
+# File: t_d_gond.txt
+
+# Destroyed Gondolin: Your failure has left the city in ruins.
+# Created by Mynstral (mynstral@thehelm.com)
+
+# Decoration = Straight Road (B)
+F:":66:3
+
+# Decoration = Straight Road (W)
+F:$:70:3
+
+
+# Town Layout
+
+D:######################################^^^^^^^^^^^^$ ####
+D:######################################^^^^^^^^^^^^$ ####
+D:######################################^^^^^^^^^^^^$ ####
+D:######################################^^^^^^^^^^^^$ ####
+D:######################################^^^^^^^^^^^^$ ####
+D:####################################^^^^^^^^^^^$ ####
+D:##################################^^^^^^^ $ $ $ ###
+D:#################################^^^^^^^^$ C C $ CC$ CC CC C CC$C C$ $ ###
+D:################################^^^$^^^^^^^ C $C$C$#$######$#$#####$#####CC$ CC$ $ $ ###
+D:###############################^^^^^^^^^^^^ C$$$ C# ###### DD D ####$D$D D D ###$###CC C $ ^^^^^ ###
+D:##############################^^^^^^$^^^$ C $####$##$D DDD $.$## $.DD DDD#$$#####C $ $^^^^^^^ $ ###
+D:#############################^^^^^^^^^^ # $##########D $######### .D##########$ $ ^^^^^^^^^^^^ ###
+D:############################^^$$^^ $ ############ ..$###########$ ..D############C $ ^^^^^^^^^^^^^^$ ###
+D:############################ C #############D$ .###%%#####%%### .D#############C$ ^^^^^^^^^^^^^ ###
+D:########################### $$ $ #############DD .#%%%%#$###%%$%# $.$$############# $ ^^^^^^^^^^^ ###
+D:########################### $ . $ $$ C#$###########D$ .%%###$###%% .D$############C $ $ ^^^^^^^ $ $ ###
+D:########################## $ ##### $$ $ #### $ $ C######%%%%### ..%## $##$ ..D####%%%%#####C$ ####### # $ ^^^^ ###
+D:########################## $ #$##### $ ##$## ####### C#$####D DD%%#D$ # .$# D$$%D DD######C $## ##$#$$ ###
+D:####$#################$#%# ### ###$ ### $ ####### ###### DD%#$ D#%DD D####$ ##$#### ###
+D:####%$#%###$#$#####$#$%%%# $####$### #$##$ ####### $######D $ $$..$######$ ###
+D:#####%$##%#%##$##%$%%%#%## #####$### # ### #########$ ######D $ .. DD DD ..$$D######C$ $ ###
+D:#####$%$%$%%%##$%$%%%#$$## $######$# $ ##$ $##$#### $$ $ $C#######$% ..DD D####### DD ..%%#$##### C # $ ###
+D:######%##%%#%%#%%%%%#$#### . $ $ $# $# #######$## D ##### $###### DD ########## $ ## ## ### $ $$ ###
+D:######%%%#%%%$%$%$%%$%#### .. $ C$####### .. D###### $# # ##### .. ########$ #$#######$###$#### ###
+D:#######$%%%%$%%%$%%$#%%### $ #####D DD .. D###$.$#$# #$## .###D ..DDD$#####C$ $ #### # #######$ ###
+D:########$%%$%%$%%%$#%###### # ###### $ $## #####$ C# D ..D## ..## $$ ..# $ .. D DD# $ $$#$#######$## ###
+D:#########$#%%%%$%%########## #$#$####$ ############ $#D $ .$#$ ## $ ..$ $.. ..## D $# # ..D#C $ $ ###$### $## ###
+D:##########$#################### # ####### ############ $ #D $ $####$ D## $# $ ..# @ @ ## .#$##$ $ $D# ## #$#$#$## @ @ ###
+D:#### $#################### ####$# ##$ #####$####### $C#D # #$ $. D## @@@ @ .##D ..$## $ .D #$C #### $ @@@@@@ ###
+D:#### ####$$$C##%#LL#""## #######$ ## $##$#$ ## C### $ ###$ . D ### $ @%@@..###D D .#### ###$ @ @ @@@@%%%%@@@ ###
+D:#### $####$##$C# $#LL#""# # . $ $ ###D $##$ D###.### .#####%@ @###.## $###$ $### $ @@ @@%%%%%%%@ ###
+D:##### ################### . $ C### ## #$ D## ..##.$##%$%%#..## ..# D ## $ D###C @@@@%%%%%%%%%@ ###
+D:# $#### D# .#..#%%#$%#..# .#D $## .. @%%%%%%%%%%%%@@ ###
+D:#.. ..#%#%#%# $ @%%%%%%%%%%%%@ @ ###
+D:# .##$# D# .#.$#%%#%$#..# .#D ####$ .. @@%%%%%%%%%%%@@ @ $ ###
+D:############ ########## # . . . $###D ..#$###$ ## ..##..##%%%##..## ..## #$ # $ $##C @%%%%%%%%%%@@@@ ^^###
+D:#### #### K# C# #LL# "# $ . $ . . ### ##$# DD###.### .##### $###.###D $### . D#$# @@@%%%%%%%@@@@@@ $ ^^###
+D:#### ### K CC %%# L# "## ##### # $ ## #### # # #### C$##D .. DD### ..###DD .###$ DD####$C @@%%%%%@@ @ @ ^^^^###
+D:#### ####KK#CC#%%#L # "### ## ###### ###$ ###$# $# ##### $#DD D## $ .##D ..$# # D #####C$ @@%%%%@ $ $^^^^^^###
+D:######## ###################### ######### $####$#$### # ## $# C$D ..D## $#$ .$$ ## .#$##$ .D##### $ DD @@@@@@@ ^^^^^^^###
+D:####### #####$$$$#$#### #### ### ###$# $ ## ########$# # # # %% %% .DD## $ $.##$$ ## $$## D #$# $###### DD DD DD DD DD ^^^^^^^^^###
+D:########$$$$$#$$$$$##### ## $##$###### ##$# ### $### $## $ C$$..%%# $ #$% D####.#########$#$####D ..######C D DD DDD D D DD DDD ^^^^^^^^^###
+D:######$$$#$$$$#$#$##$#$### $ C D..%#$ .###% . DD#################D D .D$#####$ DD DDD########DDD DDDD ^^^^^^^###
+D:#######$#$##$$$#$#$$$$#### C#D .%###.$# $ D D### #########DD D #$###$ DDD###DD D D### D DD $ ^^^^^^###
+D:######$$$$$$#$#$#$$$$$$$# $ $ $$ $C##D.%##$ # $% ..D D ####### D D ### DDD##DD D ##DDDDDD ^^^^###
+D:#####$$$$#$$$#$$$$$$$$$### ###### # $$### $###$$ $C#D.%%#####%% $ $$ DD#C DD#DD D DD## D DD $ ^^^^###
+D:#####$$$#$$$#####$$$$$$### ## ####$ $ #$## ##### ##$ $ ..%%###%%$ ..D D$ $DDD$ $ $ .DD $ $ D D$ $. D$ $ D ##D DDD ^^^^###
+D:####$$$###$########$#$$$$# ###$#####$ ## ####### # C %%%$% .DD$######$#$D$D $DDD#$###$#$#DDD $$ $ $ D#DD D DD##D ^^^^^^###
+D:###$$#################$### # ## ## # ###########$# C$DD .DD###%%%%%%####$ . $#$##%%%%%%### D .DD#C $ DDD##DDD D D##DD D ^^^^^^^###
+D:#######################$## $#### #$ ############# $# .D##%%% .%$%###DDD###%%% .%%%#$D$ .D#$ DDDD D D D###DD D $ ^^^^^^^###
+D:########################### $ # $ $ C$# .D#%% ..%%#######%% $.%%#D D#$ DD D DD# ## ## DDD DD ^^^^^###
+D:########################### $ $# C#D $ ..####### $ ..DD#$ DD D DDD DDD DD D ^^^^###
+D:############################ ##$ #$ $#D ..D#%% $ $..%%#######%$ $ ..%%#D .. D$# $ DDDD DD D D $ $ ^^^^^^###
+D:############################ ######### C ##DD .D##%%% .%%%#########%%% $.%%%##D . $## DDD D DD D ^^^^^^^^^###
+D:############################# #####$# $#D DD DD ##%%%%%%## #### #####%%%%%%###D DD D##$C ^^^^^^^^^^^^###
+D:############################## $ ###$ #### DD DDD ##### # ######$ # ########DDDD $D$D ###$C $ ^^^^^^^^^^^^^^###
+D:############################### ### $$ C$ $#$#$##DDD $D$ DD##############D D$$D D D## #$#CC$$ $^^^^^^^^^^^^^^^^^###
+D:################################ $ # CC $ ##$# #$#####$###$#$#$#####$###$###$C$C C$ $ ^^^^^^^^^^^^^^^^^###
+D:################################# $ $ $ # $ C$C$ CCC$CC C$$C$CCC C $ #C C C$ $C C $ ^^^^^^^^^^^^^^^^^^####
+D:################################## #### $ $ $ # $ ^^^^^^^^^^^^^^^^^^^^^####
+D:#################################### $ ##### $ ^^^^^^^^^^^^^^^^^^^######
+D:###################################### #### ######## $ ^^^^^^^^^^^^^^^^^^########
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+
+# Default starting position
+?:[EQU $LEAVING_QUEST 0]
+P:33:50
+
+# Starting position when coming from quest 19
+?:[EQU $LEAVING_QUEST 19]
+P:51:190
+
+# Starting position when coming from quest 20
+?:[EQU $LEAVING_QUEST 20]
+P:33:13
+
+# Starting position when coming from quest 21
+?:[EQU $LEAVING_QUEST 21]
+P:27:168
+
+# Starting position when coming from quest 22
+?:[EQU $LEAVING_QUEST 22]
+P:6:42
diff --git a/lib/mods/theme/edit/t_d_helm.txt b/lib/mods/theme/edit/t_d_helm.txt
new file mode 100644
index 00000000..ef922a16
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_helm.txt
@@ -0,0 +1,75 @@
+# File: t_d_helm.txt
+
+# Helm's Deep map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:#DD,,,,DDDDDDDDDDDDDDDDDDDDDDDD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDD,,,,DDDDDDDDDDDDDDDDDDDDDDDHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDD,,,,DDDDDDDDDDDDDDDDDDDDDDHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#@DDDD,,,,DDDDDDDDDDDDDDDDDDDDHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#%@DDD,,,,DDDDDDDDDDDDDDDDDDDHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#%%@DDDD,,,,DDDDDDDDDDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#%%%@DDD,,,,DDDDDDDDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#%%%%@DDDD,,,,DDDDDDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#%%%%%@DDD,,,,DDDDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#@%%%%%@DDDD,,,,DDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#D@%%%%%@DDD,,,,DDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DD@%%%%%@DDDD,,,,DDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^HHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDD@%%%%%@DDD,,,,DDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^HHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDD@%%%%%@@DDD,,,,DHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^HHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDD@@%%%%%@HHH,,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^HHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDD@%%%%%@@HHHH,,,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^HHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDD@@%%%%%@@HHHHH,,,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDD@@%%%%%@@@HHHHH,,,,,,HHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDDDD@@@%%%%%@@@@HHHHH,,,,,HHHHHHHHHHHHHHHHHHHHHHH^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDDDDDDD@@%%%%%%@@@@@HHHH,,,,,HHHHHHHHHHHHHHHHHHH^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDDDDDDHHH@@@%%%%%%%%@@@@HHH,,,,,HHHHHHHHHHHHHHH^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDDDDDHHHHHHHH@%%%%%%%%%%@@@HHH,,,,,HHHHHHHHHHH^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDDDDDHHHHHHHHH@@@@@%%%%%%%%@@@HHH,,,,HHHHHHHH^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDDDDHHHHHHHHHHHHHHH@@@@@%%%%%%@HHHHH,,,,HHHH^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDDDDHHHHHHHHHHHHHHHHHHHH@@@%%%%%@HHHHHH,,,H^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@@@HHHH,,,,^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%@@@@HH,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%@@@@,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@@%%%%%%%@H,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@%%%%%@HH,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH$$##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^@%%%%%@H,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH$$@@##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^HH@%%%%@H,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^HH@%%%@HH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@#$HHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^HHH@%%%@HH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##@@$$HHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^HHH@%%%%@H,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##@@@@HHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^HHHH@%%%%@H,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##@@@@HHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^HHHHHH@%%%@H,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##@@#$HHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#DDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^HHHHH@%%%%@H,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##@@##HHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^HHHHH@%%%%@H,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH##@@##HHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^HHHHH@%%%%%@H,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHH##@@##HHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^HHHHHH@%%%%@HH,,HHHHHHHHHHHHHHHHHHHHH@@@@HHH##@@##HHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^HHHHHH@%%%@HHH,,HHHHHHHHHHHHHHHHHHHH@%%%%@^##@@##@@HHHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^HHHHH@%%%%@HHH,,HHHHHHHHHHHHHHHHHH@%%%%%%%##@@##%%%@HHHHHHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^^HHHHHH@%%%@HHHHH,,HHHHHHHHHHHHHHH@%%%%@@@@##@@##%%%%@@@@@HHHHHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHH^^^^^^HHHHHH@%%%%@HHHHHH,,HHHHHHHHHHHHH@%%%%@^^^##@@##^@%%%%%%%%@@@HHHHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^HHHHHHHHH^HHHHHHHHHHHHHHH^^^^^^HHHHHHH@%%%%@HHHHHHH,,,HHHHHHHHHHH@%%%@^^^##@@##^^^@@@@%%%%%%%@@HHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^HHHHHHHHHH^^^^^^^HHHHHHHHHHHH^^^^^^^HHHHHH@%%%@HHHHHHHHH,,,,HHHHHHHH@%%%@^^^##@@####^^^^^^@@@%%%%%%@@HHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^HHHHHHHHHHH^^^^^^^^^^HHHHHHH^^^^^HHHHHHHH@%%%@HHHHHHHHHHH,,,,HHHHH@%%%@^^^##@@@@@@####^^^^^^^@%%%%%%@HHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^HHHHHHHHHHH^^^^^^^^^^^^^^^^HHH^^^^^^^HHHHHH@%%%%@HHHHHHHHHHHHH,,,,,$$$@%%%@^##@@@@@@@@@@####^^^^^@@@%%%%@HHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#HHHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^HHHHHHH@%%%@HHHHHHHHHHHHHHH,,,@@%%%%$#$#@@@@@@@@@@@@@@####^^^^^^@%%%@HHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#HHHHHHHHHHHH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^HHHHHHH@%%%%@HHHHHHHHHHHHHH$$$@%%%%@@@@@@@@@@@@@@@@@@@@@@####^^^@%%%%@H^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^HHHHHHH@%%%%@HHHHHHHHHHHHHHH$%%%%#####@@@@@@@@@@@@@@@@@@@@@###$^@%%@HH^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^HHHHH@%%%%%@HHHHHHHHHHHH@%%%%@^^##@@@@@@@@$###@@@@@@@@@@@@#$^@%%@H^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^HHHH@%%%%%%%@@@@@@@@@@%%%%%^^@@@@@@@@@@$#####@@@@@@@@@@##^^@%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^HH@%%%%%%%%%%%%%%%%%%@^^@@@@@@@@@@@$$$###@@@@@@@@@##^^@%%%@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^HH@@@@@%%%%%%%%%%@^^^@@@@@@@@@@@@$$####@@@@@@@@##^^^^@%%%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^H@@@@@@@@@@^^^$$@@@@@@@@@@@@####@@@@@@@@##^^^^^^@%%%%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^HHHHHH^^^^$###@@@@@@@@@@@@@@@@@@@@@##^^^^^^^@%%%%%@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#$##@@@@@@@@@@@@@@@@@##^^^^^^^^^@@@%%%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####@@@@@@@@@@@@@##^^^^^^^^^^^^@%%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####@@@@@@@@@##^^^^^^^^^^^^^^@@%%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####@@@@@##^^^^^^^^^^^^^^^^^@%%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####@@##^^^^^^^^^^^^^^^^^^^@%%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####^^^^^^^^^^^^^^^^^^^@%%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_henn.txt b/lib/mods/theme/edit/t_d_henn.txt
new file mode 100644
index 00000000..4fa033c4
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_henn.txt
@@ -0,0 +1,75 @@
+# File: t_d_henn.txt
+
+# Henneth Annun map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%DD%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%D%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%D%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%==^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=%%%%%%%%,==^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@%%%%%%%%=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@%%%%%%%%@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@%%%%%%%%@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@%%%%%%%%@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=^=@@@@@%%%%%%%%@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=^=@@@@@%%%%%%%%@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@%%%%%%%%@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@%%%%%%%%@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^===@@@@@@@@@@%%%%%%%%@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@==^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@==^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@==^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@==^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@==^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^===@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@==^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==^==@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=^^=@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^===@@@@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@==^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^==@@@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@=^^^^^^^^^^^^^^^^^^^^^^^^@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@===^^^^^^^^^^^^^^^^^^^^^^^^@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^=@@@@%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^@^@^@^@^@^@^@^@^@^@^@^@^^^^=@@@@@%%%%%%%%@@@^^^^^^^^^^^^^^^^^^@@@@@@@@@@@^^^^^^^^^^@@^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@@@@^@^@^@^@^@^@^@^@^@^@^@^@^@@@^^^@@@%%%%%%%%@@@@^^^^@@@@@@@@@@@@@@@@@@^^^^^^^@@@@@@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^lllll@@%%%%%%%%@llllllDDDDDDDDDDDDDDDDDDDDDDDDDD^^^^^^^^^^^^^^^DD^D^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^CC^^^^^^^^^^^^^^^^^^^^^^^^^^lllllllllll%llllll^^^^^^^^^^^^^^^^^^^^^^^^^D%%%%%%%DD^D^D^D^^^^^DDD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^CCCCCCCCCCCCCCCCCCCCCCCCCfffffffflllllll%llllllffffff^^^^^^^^CCCCCCCCC^^^^%%%%%DD^^^^^^^^^^^^DD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^CCCCCCCCCCCCCCCCCCCCCCCCCffffffffffllllll%lllffffffffffCCCC^^CCCCCCCCCCCCC^^^^^DDDDDDDDDDDDDDD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^CCCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffffffffCCCCCCCCCCCCCCCCCCCC^C^^^^^^^^^^DDDDDD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^CCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffffffffffCCC^CCCCCCCCCCCCCCC^^CCCCC^C^^^D^^^^^DD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^CCCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffffffffCCCC^CCCCCCCCCCCCCCCCC^^^^CCCCC^^^CCC^^^D^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^CCCCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffffffCCCCC^CCCCCCCCCCCCCCC^CCCCCCCCC^^CCCCCC^D^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@^^^^^^^^^^CCCCCCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffCCCCCCC^CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC^D^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_hobb.txt b/lib/mods/theme/edit/t_d_hobb.txt
new file mode 100644
index 00000000..9bc22a10
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_hobb.txt
@@ -0,0 +1,75 @@
+# File: t_d_hobb.txt
+
+# Hobbiton map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:#DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD==========================,=======ccccc==,,=========================================================================================#
+D:#D==============================================================DDHHHHHHHHHHHHHHHHHHHHHHHH,,HHHHHHH==D==D,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHHHHHHHHHHHHHHH,,HHHHHHHH====D,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHHHHHHHHHHHHHH,,HHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHH,,DHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHH,,DHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHHHHHHHHH,,C$###########$HHH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHHH,,,,,,,,,,,,,,,,,,,,,#HHH,,DHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHH,,HHH#,,,,,,,,,,,,,,,,#HHH,,DHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#D==============================================================DDHHHHHHHHHH,,HHH#,,,==========,,,#HHH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHH,,HHH#,,,==========,,,#HHH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHH,,HHH#,,,,=========,,,,,,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHH,,HHH#,,,==========,,,#HH,,=HHHHDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHH,,HH#,,,==========,,,#HH,,HHDDHDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHH,,HH#,,,,,,,,,,,,,,,,#HH,,HDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHH,,H,,,,,,,,,,,,,,,,,#HH,,=DDHHHHHHDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHH,,,#################HH,,=DDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHHH,,,,,,,,,,,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHH,,=HH#####HH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHH,,=HH#######,,$#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHH,,HHHHHHHHHHHDHH,,=HH######$$$##HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHDDDD,,HHHHHHHHDDDH,,=HHH###########HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHDDHH,,HHHHHHHHHHH,,=HHH#####HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHDDH,,HHHHHDDDHH,,=HHH#####HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHDDHH,,HHHHHDHHH,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHDDDH,,HHDDHHH,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHDDDDH,,DDDHH,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHHHDDDH,,HH=,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHHHHDDDH,,,,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHHHHHDDHH,,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHHHHDDDH,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHHHHDDH=,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHHHHDDH,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHHHHDDH,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHHHDDDH,,=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHHHHHDHH,,=H$$############HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHDDDHDDDH,,HH$#############HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#=================================================================HHHHHHHHHHHHHHHHHHDHDDDDH,,,,,#############HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#==========================================================================================,,HH$C############@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
+=:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%a,,a%$#############%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+=:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%a,,a%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+=:#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%a,,a%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+=:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH====HHH,,HHHHHHHH===HHHHH===HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDHHHHHHDDHHHHHHDDHHHHH====HHHHHH======HH,,HHHHHHH=====HHH=====HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDHHHDHHHHHHHDHHDHHH======HHHH========H,,HHHHHH=======HH==H==HHHDHHHDHHHHDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDHHHHHDDHHHHHHDDHHH===HH===HHH===HH===H,,HHHHHH===H===HHHHHHHHDDDDHDDDDHDHHDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
+=:#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===HH===HHHHHH==H,,H==HHHHH=HH=HHHH=HH=HDDDDHDDHHHHHHDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH======HHHHHHHH==,,H===HHHHH==HHHHH====HHDHHHHDDHHHDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH====HHHHHHHHHH=,,H===HHHHHHHHHHHHH==HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH,,H==HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=====HHHHH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=======HHHH,,HHH==HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH====H====HHH,,HH====HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH,,H======HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===HH,,H==HH==HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=====H,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==H==H,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH,,HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+=:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_imlad.txt b/lib/mods/theme/edit/t_d_imlad.txt
new file mode 100644
index 00000000..c1c10fd7
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_imlad.txt
@@ -0,0 +1,75 @@
+# File: t_d_imlad.txt
+
+# Imladris map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:# @^^^@ @@%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%^#
+D:# @^^^@ @@%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^HHH#####HHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%^#
+D:# @^^^@ @@%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^HHHHHH#####HHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%^^#
+D:# @^^^@ @@%%%%%%%%%%^^^^^^^^^^^^^^^^HHHH###HH#####HHHHHHHHHHHHHHHHHHHHHHHDDDDDDDD DDDDDDD^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%^^^#
+D:# @^^^@ @@%%%%%%%%%%^^^^^^^^^^^^^^HH######HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDD DDDDDD^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%^^^^#
+D:# @^^^@ @@%%%%%%%%%%^^^^^^^^HHHHH#######HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDD DDDDDDD^^^^^^^^^^^^^^^^^^^^^^^^^%%%%^^^^^#
+D:# @^^^@ @@%%%%%%%%%%^^^^^^^^^HHH####HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDD DDDDDDDDDDDD^^^^^^^^^^^^^^^^^^^^^%%%^^^^^^^#
+D:# @^^^@ @@%%%%%%%%%%^^^^^^%%^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDD DDDDDDDDDDDD^^^^^^^^^^^^^^^^^^%%%^^^^^^^^^#
+D:# @^^^@ @@%%%%%%%%%%^^^^^^^%^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDDDDDDD DDDD^^^^^^^^^^^^^^^^^^^^^^%%%%^^^^^^^^^^#
+D:# @^^^@ @@%%%%%%%%%^^^^^^%@^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDD^^^^^^^^^^^^^^^^^^^^%%%%^^^^^^^^^^^^#
+D:# @^^^@ @@%%%%%%%%%^^^^^^%@^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDD^^^^^^^^^^^^^^^^%%%%^^^^^^^^^^^^^^#
+D:# @^^^@ @@%%%%%%%%%%%%C%%@@^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDDDD^^^^^^^^^^,^^@%%%%^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@%%%%%%%%%%CC%@@@@^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDDDD^^^^^,,,,^^@%%%%^^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@%%%%%%%%CC%%@@@@@^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDDDD^^,,^^^@@%%%%^^^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@%%%%%%CC%%%%%@@@@^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDDDDDDDDDDDDDDDD,,^^^^@%%%%%^^^^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@%%%%CC%%%%%%%@@@@@^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHCCCCCCCCCCCCCCCCCCCCCCCHHHHDDDDDDDDDDDDDD,,,^^^@@%%%%@^^^^^^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@%%CC%%%%%%%%%%@@@@@@^^HHHHHHHHHHHHHHHHHHHHHHHHHCCCCCCCCCCCCCCCCCCCCCCCHHHHHHHHHHHHDDDHH,,^^^@@%%%%%@^^^^^^^^^^^^^^^^^^^^^^#
+D:# DDDDDD @^^^@ @^^CC%%%%%%%%%%%%%@@@@@^^HHHHHHHHHHHHHHHHHHHHHHHHCCCCCCCCCCCCCCCCCCCCCCCHHHHHHHHHHHHH,,,,^^^@@%%%%%^^^^D^^^^^^^^^^^^^^^^^^^^#
+D:# DDDDDDD DDD @^^^@ @^^^^^^^%%%%%%%%%%%%%%%%@@@@^^HHHHHHHHHH,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCCC,HHHHHHHHHH,,^^^^^@@%%%%%^^^DDDDD^^^^^^^^^^^^^^^^^^^#
+D:# DDDD DDD @^^^@^@@^^@^^^^@ @@%%%%%%%%%%%%%%%%%%@@^^^^HHHH,,,,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCCC,HHHHHHHHH,,^^^@@@%%%%%@^^DDD DDD^^^^^^^^^^^^^^^^^^#
+D:# DDD DDD D DDD @^^^^^^^^^^^@ @@@%%%%%%%%%%%%%%%%%@@@^^,,,,,,HHHHHHHHHHHHH,CCCCCCCCCCCCCCCCCCCCCCC,HHHHHH,,,^^^@@%%%%%%%@^^DDD DDD^^^^^^^^^^^^^^^^^^^#
+D:# DDD D DDD D DD @^^@ @@@@@%%%%%%%%%%%%%%@#,,,,,^^^HHHHHHHHHHHH,CCCCCCCCCCCCCCCCCCCCCCC,HHHHH,,^^^@@%%%%%%%%@^^DDD DDD^^^^^^^^^^^^^^^^^^^^#
+D:# DDD D DDDDDDD DD @@@@@%%%%%%%%%%%#,,,,,#@@^^^^^^^^HHHHHHCCCCCCCCCCCCCCCCCCCCCCC,H,,,,^^^@@%%%%%%%%%@^^DD DDD^^^^^^^^^^^^^^^^^^^^^^#
+D:# DD DDDDDD,,DD,,DD,, @@@@%%%%%%%#,,,,,#%%%@@@@@@@^^HHHHHH,HHHHHHHHHHHHHHHHHHHH,,,,^^^^@@%%%%%%%%%%@^^DD DDD^^^^^^^^^^^^^^^^^^^^^^^#
+D:# DD DDD DD ,,,DD,,DD,,D,, ,,,,,,, @@@@%%%#,,,,,#%%%%%%%%%%@@@^^^^^^,,,,,,,,,,,,,,,,,,,,,,^^^^@@@%%%%%%%%%%@@^^DD DDD^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# DDD D ,,DDD DDD DDDDD,, ,,,,,,,,,,,,,,, @@%#,,,,,#%%%%%%%%%%%%%%@@@@@^^^^^^^^^^^^^^^^^^^^^^^^@@@%%%%%%%%%%%@@@^^DD DDD^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# DDDD ,,DD DDDD,,,,,, ,,,, ,,,,, ,,,,,,,,,,@#,,,,,#%%%%%%%%%%%%%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%%%%@@@@^^DD DD^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# D DDD D,,DD D DD DD,,,,^^,,,, ,,,, ,,,, ,,,, ,,,, ,,,,,,,,@@#@@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@@^^^^DD DD^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# DDD D,,DD DD DD,,,,^^^^^^,,,, ,,,, ,,,,, ,,,, ,,,,@@@ @@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@^^^^DDD DD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# D,,DDD D,,,,^^@@^^^^@ @^@,,,,, ,,,, @@@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@@DDDDDDDD DD^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ,,,,,,DDDD DDDD DDDD,,,,^^@ @^^^@ ,,,,,,,,,, @@@@@@@@%%%%%%%%%%%%%%%%%%%%%@@@@@@ DDDDDDDDD^^@@^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ,,,,^^^^^^DDD DDD^^,,,,^^@ @^^^^^@ ,,,,, @@@@@@@@@@@@@@@@@@@@@@@ @^@DDDD^^@ @^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ,,,,,^^^^@ @^^^DDDDDDDD^^^^,,,,^^@ @^^^^^^@ ,,, @^^^@ ^^^^^^^^^^^^^^^^^^^^^^#
+D:# ,,,,^^^^@ @^^^^^^^^^^^^^,,,,^^@ @^^^^^^^^^@ @^^^^@^^^^^@^^^^^^^^^@ @^^^@ ^^^^^^^^^^^^^^^^^#
+D:#,,,,,^^^^@ @^^^^^^^^^,,,,^^@ @^^^^^^^^^^^^^^^^@ @^^^@ @^^^@ @^^^^@^^^@ @^^^@ ^^^^^^^^^^^^^#
+D:#^^^^^^@ @^^^^^^^,,,,^^@ @^^^@ @^^^@^^^@@^^^^^^^^^^^^^^^^^^^^@@^^^@^^^@^^^@^^^@^^^@^^^@@^^^@@^^^@@^^^@ ^^^^^^^^^#
+D:# @^^^^^,,,,^^@ @^^^^@ @^^^@ @^^^@ @^^^@^^^@^^^@^^^@^^^@^^^@^^^@^^^@@^^^@@^^^@ ^^^^^^#
+D:# @^^^,,,,^^@ ^^^#
+D:# @^^,,,,^^@ ^^#
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_khaz.txt b/lib/mods/theme/edit/t_d_khaz.txt
new file mode 100644
index 00000000..50e8b124
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_khaz.txt
@@ -0,0 +1,79 @@
+# Town Name: Destroyed Khazad-Dum
+# by fearoffours (fearoffours@moppy.co.uk)
+#
+# Created for ToME
+
+# Rocky ground
+F:o:207:3
+
+# Town Layout
+D:######################################################################################################################################################################################################
+D:#ooooooooooooo####^^^^^^^^^#######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#####oooo#######oo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^##########oooooooooo CCCCCCC #
+D:#ooo##ooooooooo#####^^^^^##########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^########ooo########ooo##########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^################oooooooooooo CCCCCCCC #
+D:##oo###oo####oo##############################^^^^^^^^^^^^^^^^^########################oooo#########oo#### ###########^^^^^^^^^^^^^^^^^^^^^^^^####### #######oooo########## CCCCCCCC #
+D:##############o#########oo###oo###################^^^^^^^############################oooo#########oo###### ################################# #####ooooooooo############# CCCCCCCC ; #
+D:#^^^^########oooooooooooooo##ooooooooo############################# #################oooo########oo########### ########################## ######ooooooooo################ CCCCCCCC ; #
+D:#############ooooooooooooooooooooooooooo###### ########### ###### ############## ####oooo#######o##o############# ################### ###########ooo######################## CCCCCCCC ; #
+D:#^#############ooooo##################oo### # #### # ##### #### ############### ###ooo########ooo## ## ###### # ## ## ## # #######ooooo########################### CCCCCCCC #
+D:#^^################oo#################ooooo#### ## ; ## ;; o ; o ## # ooooooooo############################ CCCCCCCC #
+D:#^^^^################o##########o#####oooooooooooooooooooooo HHHHHHHH # o ; oooooooooooooooooooooooo##ooo############################ CCCCCCC #
+D:#^^^^^^################################# ## ; o ; HH=====HH H o ; o $#o################################### CCCCCCC#
+D:#^^^^^^################################ ### o ### HH====HHHH ## o ###; o ##H ######################################## CCCCCC#
+D:#^^^^^################################# ### o ### ### ## HH=====HHo ### o ### o #HH==H $$###################################### CCCCCC#
+D:#^^^^^^^################################ ###### ;; o ######### HHH=====Ho ###### o ## ### o ## #H=H #$##################################### ; CCCCCC#
+D:#^^^^^^^^################################ # ## #### o ; ## # # HHHHHHHHH ####### # #### # o ## ###==# ###$#$################################## CCCCCC #
+D:#^^^^^^^################################### ## ## o ; ;### # HHHHo # # ##o # ## ; o # ##== ;#$##$$################################# CCCCCCC #
+D:#^^^^^^^^^################################ ## HHHHHHHH ### o ### o # # o ## # #$################################## CCCCCC ; #
+D:#^^^^^^^^^################################# HH======HH o o o #$ ################################## CCCCCC #
+D:#^^^^^^^^^^################################ ; HH=======HHoooooooo o o oooooooooooo HHHH $################################# CCCCCC ; #
+D:#^^^^^^^^^^^^^########################### HHH=====HH o o o o ===== H ################################# CCCCCCC #
+D:#^^^^^^^^^^^^^^^########################## HHHHHHHHHHHHHH== o ### # o o ;### o ### # H= =HH #$############################## CCCCCCC ; #
+D:#^^^^^^^^^^^^############################# H===HH #####; o # ## o o # ### o # # # == ; ###############################; CCCCCCC ; #
+D:#^^^^^^^^^############################### HH===H; ## ## # o #### ## o ; o ####### o ### #H HHH ############################ CCCCCCC #
+D:#^######################################### H=HH; ## ### oooooooo #### # #o o ###### oooooo ###HH== o ; $#############################; CCCCCCC #
+D:#################ooo###################### HH ; ### # o # ## o o ##### o ## H==H# $$#############oo############## CCCCC; #
+D:####oo##ooo#####o#######o###ooo########### ## ; o ## o o ### o ; ###==HH ;; $########oo###oooooo#####oo###### CCCCC ; #
+D:#ooooooooooooooooooooooooooooooo##oooooooo ; o ; o o o ; # ;; ; oooooooooooo##oooooooo##oooooooooo CCCCC ; #
+D:#ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooHHH=ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo CCCCCC #
+D:#oooooooooooooooooo##oooooo##oooooo##ooooo HH ; o o HH ==H ; $oooooooo#oooooooooooooooooooooooo CCCCC #
+D:#^#######################oo####ooooo####### ##### ==H=H # # o o H===### # ######o####oo####oo######oo######; CCCCC #
+D:#^^#######################o########### #### HH===HH# oH o H =H## # ## ## ## $$####o####################oo#### CCCCC #
+D:#^####################################### ## ### ;; ; HH==HH##### oH ===HH ### ### ## #### $####oo######################### CCCCCC #
+D:#^^######################################## ####### ; #H##### oH o # #### # # ### $$$###o############oo########## CCCCCCC #
+D:#^^^###############ooo################### ### # ; ;# ## oH HH o =H ##### ; ### ## ;; $#####oo########ooooo####### CCCCCCCC #
+D:#####oo##oo#####oooooooo##############oo## ### ; #### o HH o = H ### ### $#######oooo##oooooo####### CCCCCCCCC ; #
+D:#ooooooooooo###ooooooooooooooooooooooooooo # o H o= # ooooooooooooooooooooooooooo CCCCCCCC #
+D:#oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo=ooo=ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo CCCCCCCC ; #
+D:#^ooooooooooooooooo###oooooooooo##oooooooo o #o H o o HH # ooooooo####ooooooooooooo CCCCCCCC #
+D:#^^#o###ooo#####ooo#####ooooo########oo# # # ; o ### o H =o ;### o H ### o$#########ooooo###oo# CCCCCCCC ; #
+D:#^^^^^###o################oo############# # # # ; o ###### # H= o ## # o #### ; $###########oo######## CCCCCCCC ; #
+D:#^^^^^^^##################################$ ; #### ooooooo ##### o ; H o ###### ooooo H ####### ######################## CCCCCCCCC #
+D:#^^^^^^^^^^##############################$$ HH; ## ##### o ; ####### o Ho ### # o === # ## # o ; #$######################## CCCCCCCC #
+D:#^^^^^^^^^^^^^^^######################### $ HH == H ; ## ## o #### o H ##### o H== ### # ############################ CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^###################$$ HHH===HH ## ; o ### o o # # o ; H ### ; ;; $$########################## CCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^#################### $ HHH===HH ; o ;; o ; o o H ; $########################### CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^######################$ HH==H H ooooooooooo o o oooooooooooo ;; ;$ ############################ CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^^^^#################$$$ ; H==H o ; ; o o ; H o $############################ CCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^##############$ ### o # # o ### o ###; == H o #### $$############################ CCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^############$$$ ### # o HHH H # ### o ## # o # # # HH== Ho # ## $ ######################## CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^##########$ $ ### # #;; ; o HHHH ## #### o ## #### o ### ### ==Ho ####### $########################### CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^##########$$ ## ### o ;H H #### ## H H o ### # # o # ## ### HH= HH ####### ############################ CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^########### ### o ; ;## ## HHH o # ### o ##### ; ==HH #### ; ############################## CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^############## $ ### ; o ## HHHH o # # o H ## H o=H ### $############################## CCCCCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^^^^#################$ o H HoHH H Ho H H HHHHH === $#########oo###oo################# CCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^#############o#######oooooooooooooooooooooo ## HH H o H H H H$ HH===H=H ooooooooooooooooo$oooooooooooooooooo################## CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^############ooooooooooo# ### $$$ $$ # ### $$ $ o $$## HH$ = ==H#== H HH ====$$ $ ## $ oooooo##oooooooooo################### CCCCCCC #
+D:#^^^^^^^^^^^#################ooooooooooo####$######$ ## $$### ######### ###$$####o $$##### #ooo# ### $#=#=#$$$$ H ==##$#$ ##### ####################ooo##################### CCCCCCC #
+D:#^^^^^^^^^^###################oo######oo### ########### ######## ## #### ###########oooo########ooo ##########$#H##H H ######$# ###### ####################oo###################### CCCCCCC #
+D:#^^^^^^^##########oo####oo####ooo######### ############ ######### ###^^^ #########ooooo########oo##################H################### #########^######oooo##ooo################## CCCCCCC #
+D:##^^^^^#########oooooooooooooooo#################^^####### ###########^^^^^###########ooooo######ooo####################################### #####^^^#######ooooooooooooo############# ; CCCCCCC#
+D:#^^^##########ooooooooooo##ooooo######^#########^^^^##################^^^^^^^^^^^######ooo#######oooo#########^^^^^^^^^^^^^^^^^^^########### #####^^^#######oo##oooooooo############# CCCCCC#
+D:##############ooooo##########oo######^^^#####^^^^^^^^###############^^^^^^^^^^^^^^#####oooo#######ooo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^###### ####^^^^^###############ooo############## CCCCC#
+D:########ooo#####oo##################^^^^^^^^^^^^^^^^^#############^^^^^^^^^^^^^^^^^####oo########oooo#####^^^^^^^^^^^^^^^^^^^^^^^^^^^########### #######^^^^^#############ooo#ooo######## CCCCCC#
+D:#o##oooooooooooooooo##############^^^^^^^^^^^^^^^^^^^^^^#########^^^^^^^^^^^^^^^^^^#####oo########oo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####### # ######^^^^^^^^^^^^########oooooooooooooo CCCCC #
+D:#oooooooooooooooooo########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^########oooo#######ooooo###^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^##############^^^^^^^^^^^^^^^#######ooooooooooo CCCCC #
+D:######################################################################################################################################################################################################
+
+# Default starting position
+# ?:[EQU $LEAVING_QUES 0]
+# P:31:32
diff --git a/lib/mods/theme/edit/t_d_lori.txt b/lib/mods/theme/edit/t_d_lori.txt
new file mode 100644
index 00000000..967441e9
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_lori.txt
@@ -0,0 +1,75 @@
+# File: t_d_lori.txt
+
+# Caras Galadhon map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:# ,,, #
+D:# ,,,,,,,,,,,,,,,,,,,,,,,,, #
+D:# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, #
+D:# ,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCC,,,,,,,,,,,, #
+D:# ,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC,,,,,,,, #
+D:# ,,,,,,,CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC,,,,,,,y #
+D:# ,,,,,,CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC,,,,,, #
+D:# ,,,,,CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC,,,,,, #
+D:# ,,,,,CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC,,,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDD,DDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCC,,,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCCCCCDDDDD D,@,D DDDDDCCCCCCCCCCCCCCCCCCCC,,,, #
+D:# ,,,,,CCCCCCCCCCCCCCCCCCCDDD D,D DDDCCCCCCCCCCCCCCCCCCC,,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCCDDD D,,,D DDDCCCCCCCCCCCCCCCCCC,,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCDDD DDDDDDD,,,DDDDDDDDD DDDCCCCCCCCCCCCCCCC,,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCDDD DDD,,,,,,,,,,,,,,,,,,,DDD D,DDCCCCCCCCCCCCCCCCC,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCD= DDD,,,,,,,,,,,,,,,,,,,,,,,,,DD D,=,DDCCCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCCDD,D DD,,,,DDDDDDDDD,,,DDDD,DDDDD,,,,D D,,,D DDCCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCCDD,=,D D,,,DDD D,,,D ,=, DD,,,D D,,DD DDCCCCCCCCCCCCCCC,,, #
+D:# ,,,,CCCCCCCCCCCCCCDD D,,,D D,,D D,,,D , DD,,D,,D DCCCCCCCCCCCCCCC,,, #
+D:# ,,,,CCCCCCCCCCCCCCDD DD,,D D,,D D,,,D D,,,D DCCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCDD D,,D,,D D,,,D DD,,,D DCCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCD D,,,D DD,,,,,DD D,,D,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCD D,,,DDD D,,D,,,D,,D DD,,D D,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,,,CCCCCCCCCCCCCCD D,,=,,,,DD D,,DD,,,DD,,D D,,,D D,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCDD D,,D,DDD,,,D D,,D D,,,D D,,D DD,,DD D,,D DCCCCCCCCCCCCCC,, #
+D:# ,,,CCCCCCCCCCCCCCD D,,D DD,,DD D,,D D,,,D D,,D,,,D ,,,D DCCCCCCCCCCCCCC,, #
+D:# ,,,CCCCCCCCCCCCCDD D,,D D,,,DD,,D D,,,D DD,,D ,=,,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCD D,,D DD,,,,DD DD,DD DD,,,,D , D,,D DCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCD D,,D D,,,,,DDD-----DD,,,DD,,D D,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,CCCCCCCCCCCCCCDD D,,D D,,DD,,,DD-----DD,DD D,,D D,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,CCCCCCCCCCCCCCDDD D,,D D,,D D,,---@@@---DD D,,D D,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,CCCCCCCCCCCCCCDD,DDDDDD,,DDDDDDDDDDDDD,,DDDDDDD--@@%@@--DDDDDDDD,,DDDDDDDDDDD,,DDDDDDDD,DDCCCCCCCCCCCCCC,,, #
+D:# ,,CCCCCCCCCCCCCCD,=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--@%=%@--,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=,DCCCCCCCCCCCCCC,,, #
+D:# ,,CCCCCCCCCCCCCCDD,DDDDDD,,DDDDDDDDDDDDD,,DDDDDDD---@%@@@-DDD D,,DDDDDDDDDDD,,DDDDDDDD,DDCCCCCCCCCCCCCC,,, #
+D:# ,,CCCCCCCCCCCCCCDDD D,,D D,,D DD,-----%%@,,,DD D,,D D,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCD D,,, D,,D D,DDD--,-@%%@D,,,DD,,D D,,D DCCCCCCCCCCCCCC,, #
+D:# ,,,CCCCCCCCCCCCCCD D,,=, D,,D,,D DD,=,D@%%@DD,,,DD ,,,D DCCCCCCCCCCCCCC,, #
+D:# ,,,CCCCCCCCCCCCCCD D,,D D,,,D DD,DD@%%%@ D,,,,DD ,=,,D DDCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCD D,,D DD,,,DD D,,,D @@%%@@DDD,,,DD ,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCD D,,D DD,,,DD,,D D,,,D @%%%@ DD,,,DD D,,D DDCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCD D,,D D,,,DD D,,D D,,,D D,@%%@ DD,,,D D,,D DCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCDD D,,D DDD,,DD D,,DD,,,D D,,D@%%@ DD,,D,,D DCCCCCCCCCCCCCCC,, #
+D:# ,,,CCCCCCCCCCCCCCCD D,,DD,,,,D D,,D,,,DD,,D @%%%@ DD,,DD DDCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCDD D,,,,,DD D,,,,,,,,D @%%@@ D,,D,,DD DDCCCCCCCCCCCCCCC,, #
+D:# ,,,CCCCCCCCCCCCCCCD D,,,DD DD,,,=,D @%%%@ D,,D DD,,D DDCCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCCD DD,,D,,D D,,,,D D,@%%@ D,,D DD,, DDCCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCCDD D,,,D D,,D , D,,,D D,,D@%%@,,D ,=,DDCCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCCDDD,=,D D,,DD,=,DDDDDDDDD,,,DDDDDDD,,,,@%%%@D ,DCCCCCCCCCCCCCCCC,,, #
+D:# ,,,CCCCCCCCCCCCCCCCCDD,D D,,,,,,,,,,,,,,,,,,,,,,,,,,DDD%@@%%@ DDCCCCCCCCCCCCCCCC,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCDD DDD,,,,,,,,,,,,,,,,,,,,,,D @%%%@@%%@@ DDCCCCCCCCCCCCCCCCC,,, #
+D:# $$=,,,,CCCCCCCCCCCCCCCCCDDD DDDDDDDDD,DD,,,DDDDDDD @%%=%%@@%%%@ DDCCCCCCCCCCCCCCCCCC,,, #
+D:# $## ,,,CCCCCCCCCCCCCCCCCCDDD ,=,D,,,D @%%%@ @%%@DCCCCCCCCCCCCCCCCCC,,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCCCDDD , D,,,DDDDD @@ DD@%%@CCCCCCCCCCCCCCCCC,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCCCCCDDDD D,,,,,,,,D DDDDDC@%%%@CCCCCCCCCCCCCC,,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCCCCCCCDDDDDDD D,,,,,,,,DDDDDDDCCCCCC@@%%@@CCCCCCCCCC,,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDD,,,CCCCCCCCCCCCCCC@%%%@CCCCCCC,,,,, #
+D:# ,,,,CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC,,,CCCCCCCCCCCCCCCCC@%%@CCCCC,,,,, #
+D:# ,,,,,CCCCCCCCCCCCCCCCCCCCCCCCCCCCC,,,CCCCCCCCCCCCCCCCCCC@%%@CC,,,,, #
+D:# ,,,,,,CCCCCCCCCCCCCCCCCCCCCCCCC,,,CCCCCCCCCCCCCCCCCCCC@%%%@,,, #
+D:# ,,,,,,CCCCCCCCCCCCCCCCCCCCC,,,CCCCCCCCCCCCCCCCCCCC,,@@%%@@ #
+D:# ,,,,,,,CCCCCCCCCCCCCCCCC,,,CCCCCCCCCCCCCCCC,,,,,,,,@%%%@ #
+D:# ,,,,,,,,,,CCCCCCCCCCC,,,CCCCCCCCCCC,,,,,,,,, @%%@ #
+D:# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, @%%%@ #
+D:# ,,,,,,,,,,,,,,,,,,,,,,, @@%%%@ #
+D:######################################################################################################################################################################################################
diff --git a/lib/mods/theme/edit/t_d_mina.txt b/lib/mods/theme/edit/t_d_mina.txt
new file mode 100644
index 00000000..4018efc6
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_mina.txt
@@ -0,0 +1,79 @@
+# File: t_d_mina.txt
+
+# Minas Anor: The Royal City of Gondor (destroyed)
+# original town by Mynstral (mynstral@thehelm.com)
+#
+# screwing up by fearoffours (fearoffours@moppy.co.uk)
+#
+# Created for ToME
+
+# Completed: 23/07/02
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:#^^########------------------HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=@@@@@@@HHHHHHHHHHHHHHHHHH=@@@@@@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==#
+D:#^^^----#####H=------##==-------HHHHHHHHHH===^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=@@%%%%%@@HHHHHHHHHHHHHH===@@%%%%%%%@@@@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=,,,HHHHHHHHHHHHHHHHHHHHHHHH=#
+D:#^^^----------#$##---###=###-------HHHHHHHH=^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHHHH@%%%%%%%@@@@@HHHHHHHHHH==@@%%@@@@@@%%%%%%@@@@HHHHHHHHHDDDHHHDDDHHHHHHHHHHHHH=,,HHHHHHHHHHHHHHHHHHHHHHHH===#
+D:#^^----ssss-----#$#--------###==-----HHHHHHHH^^^^^^HHHHHHHHHHHHHHHHHHHHHHHDDHHHHHHHHHHHHH==@%%%%%%@@%%%@@@HHHHHHHHHH@%%@@HHHH@@@@@@%%%%@@HHHHHHHHHDDDDDHHHHHHHHHHHHH===,,HHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^^^---St-$=--------=--#ssss--###-------HHHH==^^^^^^^^HHHHHHHHHH==HHHHHHHHHH===HHHHHHHHH===@@%%%%%%%%@%%%@@@@@@@@=@@@%@@HHHHHHHHHH@@@@%%@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHH,HHHHHHHHHHH==HHHHHHHHHHHHHHHH#
+D:#^^----s=ss----OO---##--#StSS--===##=-----HHHH=^^^^^^^^HHHHHHHHH===HHHHHHHHHHH===HHHHHHHH===@@%@%,@@@@@@%%%%%%%%@@@%%%@HHHHHHHHHHHHHH@@%%%%@@HHHHHHHHHHHHHHHHHHHHHHHHH,,HHHHHHHHHHH==HDDDHHHHHHHHHHHH#
+D:#^^----##-#-----OOO--#---#s--$=----###------HHHH^^^^^^^^HHHHHHHHHH==HHHHHHHHHHHHHHHHHHHHHH===@@@@@HHHH=@@@@@@@@%%%%%@@@HHHHHHHHHHHHHH=@@@@%%@@@HHHHHHHHHHDDHHHHHHHHH,,,HHHHHDDDHHHHH==HHHHHHHHHHHHHH=#
+D:#^=---------------OO---#-####-#------HHHH----===^^^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=@%%%@@HHHHHHHHHHHHHHHHH@@%%%@@HHHHHHHHHHHHHHHHH===,O,HHHHHHHHHDDDDHHHHHHH=HHHHHHHHHHH=#
+D:#^=StSSSS-----ss---OO---##-----OOOOO---###----===^^^^^^^^^^^HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@HHHHHHHHHHHHHHHHH===@@%%%@@HHHHHHHHHHHHHHHHH==OOHHHHHHHHHHHHHHHHHHHHHHH=HHHHHHHH==#
+D:#^^ss-H==----Ssss---H=O--#-=--$#O-O-OO---##----===HD^^^^^^^HHHHHHHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHHHHHHHHHHHHHHHHHHH=@@%%%@HHHHHHHHHHHHHHHHH==OOHHHHHHHHHHHHHHHHHHHHHHHHHHDDHHHHHHH===#
+D:#^=#-$###---sH=$--=--OOO--=#-OOOOOOO-OOO--##----HHHH^^^^^HHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==@@%%%@@HHHHHHHHHHHHHHHHH=OOHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^^^-------##sssSss---HHO--#OOO--s--OOOOO--###=--HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@@@@@@@HHHH=@@%%%@@HHHHHHHHHHHHHHHHH=OOHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHHH=#
+D:#^^^##$$##---##H=H--s--OOO-OOO--StS#-OOOO----#==--HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==@@%%%%%%%%@@@@@@@%@@@@HHHHHHHHHHHHHHHHH=OOHHHHHHHHHHHHHHHHHHHHHHH=HHHHHHHHHHHH==#
+D:#^HH^----###---##--ssS--OOO--##-ssss--OOOOOO--#$---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH====HHHHHHHHDDDDHHHH=@%%%%%%%%%%%%@@%%@@HHHH==OOOHHHHHHHHHHHHHHOOHHHHHHHHHHHHHHHHHH==HHHHHHHHHHHHH===#
+D:#^^--------#$-----ssSs#--H=#-#--#H=H=#-OOHHHO--##-HHHHHHHHHHHHHH----HHHHHHHHHHHHHHHHHHHHHHHH=========HHHHHHHHHHHHHHHHHHH@%%%%@@@@%%%%%%%@@HHHH==OOOOOHHHHHHHH=OOOOOHHHHHHHHHHHH=HHHHHHHHHHDDDHHHHHHHH#
+D:#^=-----------#--#s-$$=-OO-O--#---------OOOOOO--==-----HHHH===--------HHHHHHHHHHHHHHHHHHHHHHHHH====HHHHHHHHHHHHDHHHHHH=@@%%%@@==@@%%%@@@@HHHH===OO==OOHHHH===OOHHHHHHHHHHHHHHHHHH=HHHHHHHHHHHHHHHHH==#
+D:#^^----HHH----$---###--OOOOOO-#--#sss#$=-OOOOOO,#====---HHHH=---#-------HHHHHHHHHHHHHHHHHHHHHHHH==HHHHHHHHHHHHHHHHHH==@@%%%@@HHHH@@@@@HHHHHHHH=OO-===OOOOOOOOOHHHHHHHHHHHHHHHHHHH=HHHHHHHHHHHHHHHH===#
+D:#^^-------------##-#-#-O#-OOO--#--ssssss----OOO,,,,,#----==-HHssH=--$----HHHHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHDDDHHHHHH=@%%%@@HHHHHHHHHHHHHH===-O$HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==HHHHHHH=#
+D:#^^-------------$#---O-O-t-OOO-=#-#SS-##--OOOOOO,##,##--------sssssssHHH-#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHH@%%@@HHHHHHHHHHHHHH==--OO-HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===HHHHH=#
+D:#^^^-=H=--HH-----##-OOO-sssOOHH-#--ssssss-OOOOOO--#,#$$##-----SS$---SS-----HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDHHHHHHH@@%%@HHHHHHHHHHHHHH==--O$-HHHHHHHHHHH==HHHHHHHHDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^^^--H=----------#OOO$H#-$=OOO-#--ss#sss--OHHOOO==HHH=##==---s===H=ss--O---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==@@%%%@HHHHHHHHHHHHHH==-OO--HHHHHHHHHHHHHHHHHHHHHHH==HHHHH===HHHHHHHHHHHHHHHHHHHHH#
+D:#^^--###--HHHH--HH--O-------OOHHH--####HHH-OOOOOO-##,###,,##--sss=H=Hs--HHH-HHHHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHH=@%%%@@HHHHHHHHHHHHHH=--O--HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==HHHHHHHHHHHHHHHH=#
+D:#^^^-##H=H-------OOO#--SSStS---OHHHHH----HHHOOOO---#HHHHHH=#=-ssss$-#=--O-----HHHHHHHHHHHHHHHHHHHHHHHHH==HHHHHHH===@@%%@@HHHHHHHHHHHHHH=--O$-HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==#
+D:#^^-####$-------OOO-#--sssss-OOO-##---#s--OOOOO--T-#,--HHHHH--H=H##HH#--O---HH-HHHHHHHHHHHHHHHHHHHH==HHHHHHHHHHHH==@%%%@HHHHHHHHHHHHHH=--OO--HHHHHHHHHH==HHHHHHHHDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^^#######------OO--##-###$-HHHO-##-ssss---OOOO-TT-=HH-HHH,#----HHH,,,,,O------HHHHHHHHHH===HHHHHHHHH====HHHHHHHH=@@%%@@HHHHHHHHHHHHHH--OO--HHHHHHHHHHHHHHHHHHHHHDH==HHHHDDDHHHHHHHHHHHHHHHHHHHHHHHH=#
+D:#^^^###H=H=#----OOO--#---$---OOO--HHS#-$--OOOOHHHT-#---HH,,###----------O---HH--HHHHHHHHH==H=HHHHHHHHHH===HHHHHHHH@%%%@@HHHHHHHHHH===--OO--HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==HHHHHHHHHHHHHHHHHH==#
+D:#^^#####$--####-O$---##-StSSS-HHO-#-sss-$=OOOOO--T-#=---,,##==-s-ssH==--O--------HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@%%@@HHHHHHHHHH===--OD$--HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=#
+D:#^^^#########---OOOHHH#-sss-$=--O---ssss-HHOOOOO---==,HHH#==---SSSH=H==-O--HHH-HH-HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=@@@%%%@HHHHHHHHHH===--O$O--HHHHHHHHH=HHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHHHH===HHHHHH===#
+D:#^^###HHH###----OOO#--#-###H##OOO-#-##H#---OOOOOO--##==#H#-----s$-ssss--O----------HHHHHHHH===HHHHHHHHHHHHHHHHHHHH@%%%%@@HHHHHHHHHH=---OOO--HHHHHHHHHHHHHHHHHHH=HHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHH#
+D:#^^^##$##-------OOO---#-#--^--OOO-#----#----OO--$$OO=OOOOOOOO--####--$#-O-----------HHHHHHHH==HHHHHHHHHHHHHHHHH==@@%%%@@HHHHHHHH=-H----OO--HHHHHHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHHHHHHH===HHHHHHHH=#
+D:#^^######-##OOO$OOO-^^^^^^^^-^MMM^^^^^^^^#^^^OOOOOO-$OOOO-$OOHOOOOOOOHHOO----HHH----HHHHHHHHHH=HHHHHHHHHHHHHHHH@@@%%%@@HHHHHHHH=H-HOOOOOO--HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDD=HHHH==H===HHHHHHHH=#
+D:#^^####H==HHO$OOOO######H#####III##-#########^OOHHHOOOOOOO#OOOOOOOOOO#OOOOO-------HHHHHHHHHHHHHHHHHHHHHHHHHHH=@@%%%%@@HHHHHHHH=---OOOOOO--HHHHHHHHHHHHHHHHHHHHHHH====HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=#
+D:#^=######-##OOOO-##-####HH#HH#III#####-##--##^OOOO$-OOOOOOOOHHHOO-OOOOOOOOOO------H--HHHHHHHHHHHHHHHHHHHHHHHHH@%%%%@@HHHHHHHH----OOO$$O----HHHHHHHHHHHHHHHHHHHHHHH====HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^=###-H##-OOOOOOOO-^#^^^^^#H^MM#^^^^#^^#^^-#H=OOH=OOOOO$-OOOOHOOOOOOOOOOOOOOO--HH---HHHHHHHHHHHHHHHHHHHHHHHHH@%%%@@HHHH==H--HD-OOO$-----HHHHHHHHHH=HHHHHHHHHHHHHHHH=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==#
+D:#^^^#######-----OOO---H-sHH#--OOO##--##-----$--OOOOOOOOOOOOOO-----------OOO-$-O----HHHHHHHHHHHHHHHH===---------##@%%%$##=--------OOOOO-----HHHHHHHHHHHHHHHHH=HHHHHHHHHHHHHHHHHHHHHHHHH=====HHHHHHHHHH#
+D:#^^#########----OHO---#-sSss--OOO---ssss#--OOOOOO--##==###---HH---ss-#-#O-OOOOO-HH--HHHHHHHHHHHHHH===--OOOO-----######$--------OOOOOO-----HHHHHHHHHHHHHDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHH=#
+D:#^^####$-H=H#---OO$--$--sts##-O-$-#-SSHSS-OOOOOO---##=##H==---------t-S-O-OO$OO----HHHHHHHHHHHHHH===--OOOOOOOOOOOOO#OOOO$OOOOOOOOOOO-HHH-HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=DDHHHH==HHHHHHHHHHH#
+D:#^^###########--OOO--##-sS=$--OOO-$-s-#---H=OOO--T==#=#,,,##=#--H-sssss-O--OOOOO---HHHHHHHHHHHHHH==--$OOOOOOOOOOOOOOOOOOOOOOOOO#HOO-----HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=HDDDHHHHH=#
+D:#^^#$--$--##----OOO--#--####-OOO--#-sssss-OOHOO-TT-#,,,,-HH==-----sHH=H-$---O$-O---HHHHHHHHHHHHHH=--OOOHH-OOOOOOO$HHO#OOOOOOOOOOO------HHHHHHHHH=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH====HHHHHHHHH=#
+D:#^^#######------O-$-##-------OO---#-###H#-OOOOO-TT-=#----H==#=----###$--O-HHOOOOHH--HHHHHHHHHH===--OOOO---------#######------------H--HHHHHHHHHHHHHHHHHHH=HHHHHDDHHHHHHDDHHHHHHHHHHHHHDDDHHHHHHHHH===#
+D:#^^-###$-#-HH---OOO-#--S-ss##OOO-#--------OOOOO--T-##-----HHH----H------H----OOOO----HHHHHHHHHH=--OOOH----DD---##@%%%@##-D-----H---HHHHHHHHHHHH===HHHHHHHHHHHHHHHH=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==#
+D:#^^^-###---------OO-#-#stss--OOO-#-ssssss--O$-$O---#,--HH,H#----sss-#s--O-----OOOO--H-HHHHHHHH---OOOO---HHHHHHHH=@%%%@@HHHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHHHH=HHHHHHHHHHHHH==HHHHHHHHHH#
+D:#^^--####---------OOO--#s#s-OOO--=$StS##---OH=HOO-#==-,,#=##----S--#HH--O------OO$-----HHHH==--OOOOO----HHHHHHHH=@%%%@@HHHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=#
+D:#^^---#HH--HH-----#OOO--##--OOO-###ssssss--OOOOOO-#,,,##==#------$sH=H--O--H----OO$#----HHHH--OOOOO----HHHHHHHHHH@%%%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^^^--#------H==-$--H=HHH--OO----#-###H##-OO$-OO--#=####HHH-HH--ss#-ss-OO----D---OOOO----HH--OOOOO---===HHHHHHHH=@@%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=@@@@HHHHHHHHHHHHHHHHHHHH===#
+D:#^^^-------------#---OOO---OOO--#=------##OOOOOO##HHHH=-HH--HH--#-##-HHH-$-HH-----$--H----OOOOOO-HH--HHHHHHHHHH===@@%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=@@@@@@HHHHHHHHHHDDHHHHHHHH===#
+D:#^^----------H==H-----H=HHOOO-----ss------OO$-O,,##=HHH--------HHH-----HHH--H--HHH-OOOOOOOO$OO-----HHHHHHHHHHHHHH==@@@%%%%@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@@@@@@@%@@@HHHHHHHHHHHHDDDDHHHH==#
+D:#^^^----HHHH-$-##-#ss--OOO#OO-##=-#Ss----OOOH-O,=#HHH---HHHHH-------HH-O--------=---OOO#OOOOO--HHHH===HHHHHHHHHHHHHH=@@%%%%@@HHHHHHHHHHHHHHHHHHHH@@@@@HHHHHHHHHH@@@@@@@@@@@@@HHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^^^---------##---ss-s--OOOO----=sst#DD-OOOOOO--#=-----=------ssss-s--O$---H--HHHH---OOOOO-H--HH==HHHHHHHHHHHHHHHHH===@@%%%%@@@HHHHHHHHHHHHHH==@@@%%%@@@HHHHHHHH@@@%@@@@@@@@HHHHHHHHHHHHHHHHHHHHHHHH=#
+D:#^^--------##$---sstss#--OOO-##=ssS-#--OOO#OO--##=----HHHH-----#S--$$-OH-----HHHH==----------HHHHHHHHHHHHHHHHHHHHHHHHH=@@@%%%%@@@@@HHHHHHHH=@@@@%%%%%%%@@===@@@@@%@@%@@@%@@HHHHHHHHHHHHHHHHHHHHHHHH==#
+D:#^^-HHHH-###-----#Ss-$--OOOOO###sSs#--OOOOOO--##-----HHHH==---ssssss--O-----HHHHHHHHHHH-HH-HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@@@%%%%%%@@@@@@@@@@@%%%%%@@@%%%@@@@@%%%%@@@@=@@@@HHHHHHHHHHHHHHHHHHHHHHHH===#
+D:#^^^######----#---#s#--OOO-OOO--Ss#--#OHH#---##-#HHHHHHHHHHH--##--##-OO--DHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===@@%%%%%%%%%%%%%%%%%@@@@@=@@@%%%%%%%@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHDDHHHHH=#
+D:#^^^-------ss-#S---#--OOO---HH#--#--OOOO$--#-------HHHHHHHHHH--------O-----HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=@@@@@@@@@@@@@@@@@@@HHHH===@@@@@@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^^-sssss-#sssts-----OOO--#--OOO---OOOOO---#H=-HHHHHHHHHHHHHH=------OO-HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===#
+D:#^^-SSStH--#sSH=s#--OOO--#----HOOOOOOHH--#-------HHHH==HHH==HHH=HH--O----HHHHHDDHHHHHHHHHHHHHHHHHHHHH======HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^^-s=H=----#ss-$--OO----#--H=-OHOOO------------HHHHHHHH=HHH==HH---O---HHHHHHHDDDHHHHH====HHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHDDHHHHHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHH==#
+D:#^^^#####----##---OO--###--XXX-OOO----#-------HHHHHHHHHHHHH=HHHH==---HHHHHHHHHHHHHHHHHHHHHHHHDDHHHHDDD==HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDHHHHH=H===HHHHHHHHHHHHHHHH=======HHHHHH===HHHHHHHHHHHHHH#
+D:#^^^------------OOO--###--XXX#----=H==H----HHHHHHHHHDDDDHH=HHH=HHHHHHHHHHHHDDDHHHHHHHHHDDHHHDDHHHHH=DD=HHHHHHDDHHHHHH===HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDDHHHHHHHHHHHHH==H==HHHHHHHH====HHHHHHHHHH===#
+D:#^^--SStSSHHH--OO-HHH#--XXHH#---#H=H-HHH-HHHHHHHDDDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHHHHHHHH====HHHHHHHHHHHHHHHHHHH====HHHHHHHHHHHHHHHHHHHH==H==HHHHHH=====HDDHHHHHDDDHHHH=#
+D:#^^^-sss-$----------#--###-----H=#-----HHHHHHHHHDDDDH=HH=HHH=HHH=HHHDDDHHHHHHHHHHDDHHHHHDDDHHHHHHHHHHHHHHHHDDDHHHHHHHHH===HHHHHHHHHHHHHHHHHHHH===HHHHHHHHHDDHDDDHHHHH=====HHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#^^--####-------###--------###-#-#---HHHHHHHHHHHHHHHHHH=HH=HH=HHHHHHDDDDHHHHHHHHH==HHHDDDHHHHHH==H=====HHDDHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH==#
+D:#^^^----------##-----##-#-#-H==---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH====HHHHHHHHHHHHH====HHHHHHHHHHHHHHHHHDDDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH===#
+D:#^^^------##-#--##-###--#-------HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDDDHHHHHH=====HHHHHHHHHHHHH===HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=#
+D:#^^######-#-----------------HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH=#
+D:######################################################################################################################################################################################################
diff --git a/lib/mods/theme/edit/t_d_osgili.txt b/lib/mods/theme/edit/t_d_osgili.txt
new file mode 100644
index 00000000..bb21607b
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_osgili.txt
@@ -0,0 +1,78 @@
+# File: t_d_osgili.txt
+
+# Osgiliath map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+#Anduin river
+F:a:227:3
+
+D:######################################################################################################################################################################################################
+D:# #################@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@########################## #
+D:# ######@@@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@@@@@@@@@@@@@@@#### ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
+D:# #####@@@@@@@########@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@#####@@@#####@@@#####@@###### ,,, #
+D:# ####@@@@@@@@@,########@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@#####,,,#####,,,#####,@@@@@##### ,,, #
+D:# ####@@@@@@@@@@,,########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@#####@@@#####@@@#####@,@@@@@@@##### ,,, #
+D:# ####@@@@########,@,@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@,@@@@@@@,@@@@@@@,@@@@,,,,,@@@@@#### ,,, #
+D:# ####@@@@@,########,@,@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@,,,,@@@@,,,,@@@@,,,,@@@@@,,,,@@@#### ,,, #
+D:# $###@@@@@@@,@########@@,@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@#####@@@#####@@@#####@@@@#####@@@#### ,,, #
+D:# $$$@@@@@@@@@@@,,@@@@@@@@@,########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@#####,,,#####,,,#####,,,@#####@@@@#####,,, #
+D:# $,,=@@@@@@########,@@@@@@@@,########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@#####@@@#####@@@#####@@@@#####@@@@@@@#,,, #
+D:# ##=,,D@@@@@########,@@@@@@@@,########@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@,@@@@@@@,@@@@@@@,@@@@@@@@,@@@@@@@@=,,=### #
+D:# ###@D,,D@@@@########@,@@@@@@@,@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@,,,@@@@@,,,,@@@@,@@@@@@@,@@@@@@@=,,= ### #
+D:# ##@@@@D,,D@@@@@@@@@@@@@,@@@@D@@,@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@#####@@@#####@@@D@@@@#####@@@@=,,= ## #
+D:# ##@@@@@@D,,D@@@@@@@@@@@@@,@@DDD@@,@########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@#####,,,#####,,DDD,,,#####@@@=,,= ## #
+D:# ##@@@@@#@@D,,D@@@@@########,@@D@@@@,########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@#####@@@#####@@@D@@@@#####@@=,,= ## #
+D:# ##@@@@@@#@@@D,,D@@@@########,@@@@@@@,########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@,@@@@@@@,@@@@@@@@@@@@,@@@=,,= DDDDD ## #
+D:# ##@@@@@@###@@@D,,D@@@########@,@@@@@@,@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@,@@@@@@@,@@@@@@,,,,,@@@=,,= DDDDDDD ## #
+D:# ##@@@@@@@###@@@@D,,D@@@@@@@@@@@@,@@@@@,@@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@#####@@@#####@@#####@@@@=,,= DDDDD ## #
+D:# ##@@@@@@@#####@@@@D,,D@@@@@@@@@@@@,,,@@@,@########@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@#####,,,#####@@#####@@@=,,= ## #
+D:# ##@@@@@@@@#####@@@@@D,,D@@@@@@########,@@@,########@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@#####@@@#####@@#####@@=,,=,,,,,,,,,,,,,,,,,,,## #
+D:# ##@@@@@@###########@@@D,,D@@@@@########,@@@,########@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@,@@@@@@@,@@@@@@,@@@=,,= ,,$$,,,#####,,###,, ## #
+D:# ##@@@@@@###########@@@@D,,D@@@@########@,@,@@@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@,,@@@@@@@@@,,,,,,@@@=,,= ,,#$$,,#####,,###,, ## #
+D:# ##@@@#################@@D,,D@@@@@@@@@@@@@,,,@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@#####@@@@@@@#####@@@@=,,= H ,,###############,, ## #
+D:# ##@@@@#################@@@D,,D@@@@@@@########,@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@#####,,,,,,,#####@@@=,,= HH ,,###############,, ## #
+D:# ##@@@@#################@@@@D,,D@@@@@@########,@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@#####@@@@@@@#####@@=,,= HHH ,,,#############,,, ## #
+D:# ##@@@@@@@@@@@@@@@@@@@@@@@@@@D,,D@@@@@########@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@@@@@@@@@@@@@=,,= HHHH ,,,#############,,, ## #
+D:# ################@@@@@@@@@@@@@@=,,=@@@@@@@@@@@@@@@@@@@@=##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@##=@@@@@@@@@@@@@@@@@=,,= HHHHH ,,,#########$$$$,,, ## #
+D:# ##D DDDDDDDDDDDDDDDD,,DDDDDDDDDDDDDDDDDDDDDD#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###DDDDDDDDDDDDDDDDDDD,,= ,,,###########$$,,, #
+D:# ##D,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,$$###########$$,, #
+D:# ##D,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,$############$$,, #
+D:# ##D,,cccccccccccDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD,,DDD#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#DDDDDDDDDDDDDDDDDDD,,= ,,$##############,, CC #
+D:# ##D,,c %%%%% c@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=,,=@=##@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@##=@@@@@@@@@@@@@@@@=,,=DDDDDDD ,,,##############,, #
+D:# ##D,,c %%=%=%% c@@@######@@@@@@@@@@@@@@@@@D@@@@@D,,D@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@@@@@@@@@=,,=D,,,,,D ,,$$#############,, #
+D:# ##D,,c%%%%%%%%%c@@@######@@@@@@@@@@@@@@@@DDD@@@D,,D@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@=HHHHHHHHH=@@@@=,,=D,%%%,D ,,$$#############,, ## #
+D:# ##D,,c %%=%=%%,c@@@######@@@@@@@@@@@@@@@@@D@@@D,,D@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@HHHHHHHHHHHHH@@@=,,=D,%%%DD ,,$$############$$, ## #
+D:# ##D,,c %%%%% ,c@@@######@@@@@@@@######@@@@@@D,,D@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@=HHHHHHHHH=@@@@=,,=D,,,,,,,,,,############$$$, ## #
+D:# ##D,,ccccccccc,@@@@@@,@@@@@@@@@@@######@@@@@D,,D@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@@@@@@@@@@@=,,=DDDDDDD ,,,###########$$,,, ## #
+D:# ##D,,,,,,,,,,,,@@@@@@,@@@@@DD@@@@######@@@@D,,D##########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=DDDDDDDDDDDDDDDDDDDDDD,, ,,,#############,,, ## #
+D:# ################@@@@@@,@@@DDDD@@@######@@@D,,D@##########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#############,,, ## #
+D:# ##@@@@@@@@@@@@@@######,@@@DD@@@@@@,@@@@@D,,D@@##########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=DDDDDDDDDDDDDDDDDDDDDDD,, ,,#############$$,, ## #
+D:# ##@@@@@@@@@@@@@@######@,@@@@@@@@@,@@@@@D,,D@@@##,####,##@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@@@@@@@@@@@@@@@=,,=HHHHH ,,###############,, ## #
+D:# ##@@@######@@@@######@@,@@######,@@@@D,,D@@@@@@,@@@@,@@@=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@=HHHHHHHHHHH=@@@@@@=,,=HHHH ,,###,,#$$##,,#$$,, ## #
+D:# ##@@@######@@@@######@@@,@######,@@@D,,,,,,,,,,,,,,,,,,,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@HHHHHHHHHHHHH@@@@@@@=,,=HHH ,,$$#,,$$###,,$$#,, ## #
+D:# ##@@######@@@@@@,@@@@@@@,######,@@D,,D@@@@@@@@@@@@@@@@@=#########aaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@=HHHHHHHHHHH=@@@@@@@@=,,=HH ,,,,,,,,,,,,,,,,,,,## #
+D:# ##@######@@@@@@@,@@@@@@,######,@D,,D@@@@@@@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=,,=H , ## #
+D:# ##@@@,@@@@@@@@@@,@@@@@@@,,,,,,,D,,=DDDDDDDDDDDDDDDDDD=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD,,= , DDDDD ## #
+D:# ##@@@,@@@@@@@@@,@@@@@@@@,@@@@D,,,,,,,,,,,,,,,,,,,,,,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, DDDDDDD ### #
+D:# ##@@@@,######@,@######,@@@@D,,=DD,DDDDDDDDDDDDDDDDD=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD,, DDDDD ## #
+D:# ##@@@,######@,@######,@@@D,,D@@D,D@@@@@@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=,,= ## #
+D:# ##@@,######@,@######,@@D,,D@@@D,D@@@@@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@#####@@@@@@@@@@@@@@@@@@@@#####@@@=,,= ## #
+D:# ##@,######@,@######,@D,,D#####,#####@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@#####,,,,,,,,,,,,,,,,,,,,#####@@@@=,,= ### #
+D:# ##@,,,@@@@,@@@,,,,@D,,D@#k@=H,H=@m#@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@#####@@@@@@@@@@@@@@@@@@@@#####@@@@@=,,= ## #
+D:# ##@@@,,,,,,,,@@@@D,,D@@#@@#H,H#@@#@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@,@@@@@@@@@@@@@@@@@@@@@@@@,,,,@@@@@=,,= ## #
+D:# ###@@@@@@@D@@@@D,,D@@@#@@#H,H#@@#@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@#####@@@@@@@@=@@@@@@@@@@@@@@#####@@@@=,, =##$ #
+D:# ###@@@@DDD@@D,,D@####@##H,H##@####@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@#####@@@@@@@@@@@@@@@,,,,,,,,#####@@@@@=,,,,, #
+D:# ###@@@D@@D,,D@@#@@@@# H,H #@@@@#@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@#####@@@@@@@@@@@@@@,@#####@@#####@@@@@##$$ #
+D:# ###@@@D,,D@@@#@@@@# H,H #@@@@#@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@,@@@@@@@@@@,,,,,,@@#####@@@@@@@@@#### #
+D:# ##$=,,D@@@@####@##H,H##@####@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@#####@@@@@@@,@#####@@#####@@@@@@@#### #
+D:# ,=@@@@@@@@#@@#H4H#@@#@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@#####@@,,,,,@@#####@@@@@@@@@@@@#### #
+D:# $##@@@@@@@#@@#####@@#@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@#####@,#####@@#####@@@@@@@@@#### #
+D:# ###@@@@@#l@@@@@@@H#@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@,@@,@#####@@@@@@@@@@@@@##### #
+D:# ###@@@###########@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@@@@@,@@@#####@@@@@@@@@@#### #
+D:# ###@@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@@@@@@@@@@@@@@@@@@@@@@@@@@###### #
+D:# ###############@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@############################## #
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_pelar.txt b/lib/mods/theme/edit/t_d_pelar.txt
new file mode 100644
index 00000000..246f2d34
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_pelar.txt
@@ -0,0 +1,78 @@
+# File: t_d_pelar.txt
+
+# Pelargir map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+#Anduin river
+F:a:227:3
+
+D:######################################################################################################################################################################################################
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@##%%%%%@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH# #
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####%%%%%@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@######%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@###%%%%%@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@####%%%%%@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@####@@@@#####%%%%%@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@####@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@####@@@@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%###@@@@@@@DDDD@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%##@@@@DDDD@DDDD@@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%@@@DDDD@@@DDDD@@@@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%@@DDDD@@@@@@@@@@@@@@@@@@@@#####%%%%%@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%@DDDD@@@@###@@@@@@#######@@@@@#####%%%%%@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%@@@@@@@@@####@@@@@#######@@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%@@@@@@@@@@####@@@@#######@@@@@@,,,,#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%@@@@@@@@@@@####@@@@@@@@@@@@@,,,,@@@@@@##%%%%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%#@@@@@@@@@@@@####@@@@@@@@@,,,,@@@@@@@@@#%%%%###%%%%%@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%##@@#######@@@@#######@@,,,,@@@@@@@@@@@#%%%%#@@#####%%%%%@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#######@@@@#####,,,,,@@@@DDD@@@@@@#%%%%#@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#######@@@@###,,,.@@@@@@DDDDD@@@@#%%%%#@@@@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#######@@@@#,,,##,###@@@@DDD@@@@#%%%%#@@@@####@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@@@@@@@@@@,,,,##,,,####@@@@@@@#%%%%#,@@@@####@@@@@@@@#####%%%%%@@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@@@@@@@,,,,@@@##,,,,,,####@@@#%%%%#@@,@@@####@@@@@@@@@,@#####%%%%%@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@@@@,,,,@@@@@@##,,,,,,,,,####%%%%#@@@@,,,,@@@@@@@@@@@@@,@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@,,,,@@@DDD@@@##,,,,,,,,,,,,,,,,#@@@@@@@@,,,,@@@@@@@@@@,,,,,,,#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@,,,,@@@@@DDDDD@,##,,,,,,,,,,,,,,,$###@@@@@@@@@,,,@@@@@@@@,@@@@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHHHHHHHHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH,,,,,,,,,,,,,@@@@@@@@@DDD@@@##,,,,,,,,,,,,,,,,,,####@@@@@@,@@,,,@@@@@,@@@@@@@@@@@@#####%%%%%@@@HHHHHHHHHHHHHHHHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@@@@@@@@@@@@@@##,,,,,,@####,,,,,,,,,,####@@@,@@@@@,@#######@@@@@@@@@@@@#####%%%%%@@@HHHHHHHHHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@#######################,,,,,########,,,,,,,,,,,####,@@@@@@,#######@@@@@@@@@@@@@@@#####%%%%%@HHHHHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH,%%%%%%%%%%%%%%%%%%%%%%%%%%%,,,,,,##########,,,,,,,,,,,,,CCCC@@#############@@@@@@@#####@@@#####%%%%%@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH,%%%%%%%%%%%%%%%%%%%%%%%%%%%,,,,,,,########,,,,,,,,,,,,,,,,,,,,#############,,,,,,,,,$@@@@@@@@#####%%%@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%%%%%%%%%%%%%%%%%%%%%%%,,,,,,,,,####,,,,,,,,,,aaaaaa$###@@#############@@@@@@@#####@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@#####################CC,,,,,,,,,,,,,,,,,,,,,,aaaaaaaaa@@@@@#######@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@@@@@@@@@,,,,,CC,,,,,,,,,,,,,,,,,,,,####aaaaaaaa@@@@#######@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#####@@@@,@@@@@CC,,,,,,,,,,,,,,,,,,###@@@@@aaaaaaaa@@@@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#####,,@,@@@@@@CC,,,,,,,,,,,,,,,,,###@@@@@####aaaaaaaa@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#####@@,@@####@CC,,,,,,,,,,,,,,,,aaa##@@@@#######@aaaaaaaa@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@,@@@@,,,####@CC,,,,,,,,,####aaaaaaa##@@@#######@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@,@@@@,@@####@CC,,,,,$$###@@##aaaaaaa##@@@@@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@##@@@@@@,@@@@@@CC,,####@@@@@@@##aaaaaaa##@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#@@@$@@@@,@@@@@CC,###@@@@@@@@@@##aaaaaaa##@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@####$@@@@@,@@@@#,###@@@@@@@@@@@@##aaaaaaa##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@,@@@@@@@@,@@@,,@@@@@#######@@@@##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@,@@@@@,@@,,,,@,@@@@@#######@@@@@#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@@$,@@@@@,##$$$@,@@@@#######@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@##@@@@@@@,@##$##@@,@@@#######@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#####@@@,@@#####@@@,@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@,@@@@,@@@@@@@@@@@@,@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@,@@@,@@@@@@@@@@@@@@,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#####@,@@####$@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@###@,@@#@@@@@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@###@@@,@@###@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@,@@@@,@@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@#@@@@@,@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@#@@@,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@@@@#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####@@@#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@##########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH@%%%%%@##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_d_thrand.txt b/lib/mods/theme/edit/t_d_thrand.txt
new file mode 100644
index 00000000..156dbb43
--- /dev/null
+++ b/lib/mods/theme/edit/t_d_thrand.txt
@@ -0,0 +1,75 @@
+# File: t_d_thrand.txt
+
+# Thranduil's Halls map and destruction by furiosity <furiosity@zionmainframe.net>
+
+# NB! This file assumes usage of the following files from the 'theme' module:
+# f_info.txt and t_pref.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+D:######################################################################################################################################################################################################
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#%%%%%%%%%%%%%%%%%%%%%%%%===^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#%%%%%%%%%%%%%%%%%%%%%===^^^^===%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^%%%%===^^^^===%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ===^^^===%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ===^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^^^^^^CCC^^^^^^#
+D:# ^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^^^^^CCC^^^^^#
+D:# ^^^^^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^^^^^CCC^^^^#
+D:# ^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^^^CCC^^^#
+D:# ^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^^^^^^CCC^^#
+D:# ^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%^^^^CCC^#
+D:# ^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_dale.txt b/lib/mods/theme/edit/t_dale.txt
new file mode 100644
index 00000000..5c2dcf6c
--- /dev/null
+++ b/lib/mods/theme/edit/t_dale.txt
@@ -0,0 +1,96 @@
+# File: t_dale.txt
+
+# Dale (rebuilding) map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain features ###
+
+#light post
+F:l:221:3
+
+# Wooden boards (4 kinds)
+F:=:233:3
+F:[:234:3
+F:_:235:3
+F:]:236:3
+
+### Buildings ###
+
+# Bard's Hut
+F:b:74:3:0:0:0:0:0:77
+
+# Construction Supply Store
+F:c:74:3:0:0:0:0:0:63
+
+# Builder Barracks
+F:i:74:3:0:0:0:0:0:71
+
+D:######################################################################################################################################################################################################
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# #
+D:# @@@@@@@@@@@@@@@@ #
+D:# @@WWWWWWWWWWWWWWWW@@ #
+D:# @@@WWWWWWWWWWVWWWWWWWWW@ #
+D:# @WWWWWWWWWWWVVVWWWWWWWWWW@ #
+D:# @WWWWWWWWWWWVWWWWWWWWWWW@############### #
+D:# @@@@WWWWWWWWWWWWWWWWW@@@-------------------------------------------------------------------------------------- #
+D:# @WWWWWWWWWWW@@@@@@------------------------------------------------------------------------------------------ #
+D:# @W@@@@@@@@@@@@--StSSSSS--------------------------------------------TTT----------------------------------------- @@@@@@ #
+D:# @W#-------------sssssss-------------------------------------------TTTTT------------------------------------------- @@WWWWWW@ #
+D:# @W#-------------#######--------------------------------------------TTT----------------------------------------- @@WWWWWWWWWW@@@ #
+D:# @W#-------------###c###------------------------------------------------------------------------------------------------- @WWWWWWWWWWWWWWW@@ #
+D:# @W#-----------l----@----l-----------------------------------------------------------------------------------------------------@WWWWWWWWWWWWWWWW@ #
+D:# ##----------------@---------------------------------------l-----------------------------------------------------------------]]]]]]]]]]]]]]]]]]@ #
+D:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@#
+D:# #-----------------@---------------------------------------@----SSStS------------------------------------------------------@]]]]]]]]]]]]]]]]]]@ #
+D:# #------------------@---------------------------------------@-E-sssss-----------------------------------------------------@WWWWWWWWWWWWWWWW@@@ #
+D:# #-------------------@---------------------------------------@--#####------------------------------------------------------@@@WWWWWWWWWWWWWW@ #
+D:# #--------------------@---------------------------------------@-##b##---------------------------------------------------------@@@WWWWWWWWW@@ #
+D:# #---------------------@---------------------------------------@@@@---l----------------------------------------------------------@@@@@@@@@@ #
+D:# #----------------------@-------------------------------------@----@---------------------------------------------------------------------- #
+D:# #-----------------------@-----------------SSS---------------@------@---------------------------------------------------------------------- #
+D:# #------------------------@--------------sssss--------------@--------@---------------------------------------------------------------------- #
+D:# #-------------------------@---------#########-------------@----------@---------------------------------------------------------------------- #
+D:# #--------------------------@--------#########------------@------------@---------------------------------------------------------------------- #
+D:# #---------------------------@------@---------------,@@@@@--------------@---------------------------------------------------------------------- #
+D:# #----------------------------@@@@@@@------------------------------------@---------------------------------------------------------------------- #
+D:# #--------------------------------------------l---------------------------@---------------------------------------------------------------------- #
+D:# #-------------------------------------------------------------------------@---------------------------------------------------------------------- #
+D:# #--------------------------------------------------------------------------@l--------------------------------------------------------------------- #
+D:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
+D:# #--------------------------------------------------------------------------l-@--------------UUUUUUYUUUU-----------------------------------------------------------#
+D:# #-----------------------------------------------------------------------------@-------------XXXXXXXXXXX-----------------------------------------------------------#
+D:# #------------------------------------------------------------------------------@------------___________-----------------------------------------------------------#
+D:# #-------------------------------------------------------------------------------@l----------]]]]]i]]]]]-----------------------------------------------------------#
+D:# #-------------------------------------------------------------------------------l@@@@@@@@@@@@@@@@@------l---------------------------------------------------------#
+D:# --#---------------------------------@@@@@---------------------------------------------------------------------------------------------------------------------------#
+D:# ----#--------------------------------@WWWWW@--------------------------------------------------------------------------------------------------------------------------#
+D:# -----T#-------------------------------@WWWWWWW@-------------------------------------------------------------------------------------------------------------------------#
+D:# -------TT#------------------------------@WWWWWWWWW@------------------------------------------------------------------------------------------------------------------------#
+D:# ----------------------------------------------@WWWWWWWWWWW@-----------------------------------------------------------------------------------------------------------------------#
+D:# --------------------------------------------@WWWWWWWWW@------------------------------------------------------------------------------------------------------------------------#
+D:# ------------------------------------------@WWWWWWW@-------------------------------------------------------------------------------------------------------------------------#
+D:# ----------------------------------------@WWWWW@--------------------------------------------------------------------------------------------------------------------------#
+D:# --------------------------------------@@@@@---------------------------------------------------------------------------------------------------------------------------#
+D:# --------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:# ------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:# ------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:# -------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_edoras.txt b/lib/mods/theme/edit/t_edoras.txt
new file mode 100644
index 00000000..a4257661
--- /dev/null
+++ b/lib/mods/theme/edit/t_edoras.txt
@@ -0,0 +1,117 @@
+# File: t_edoras.txt
+
+# Edoras map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain feature ###
+
+# Stable
+F:m:240:3
+
+### Buildings ###
+
+#Meduseld
+F:k:74:3:0:0:0:0:0:82
+
+#Inn
+F:i:74:3:0:0:0:0:0:72
+
+#Map store
+F:a:74:3:0:0:0:0:0:66
+
+#Music store
+F:c:74:3:0:0:0:0:0:64
+
+#The Library
+F:g:74:3:0:0:0:0:0:13
+
+#Rune shop
+F:r:74:3:0:0:0:0:0:62
+
+#The Beastmaster
+F:b:74:3:0:0:0:0:0:16
+
+#Fighters Hall
+F:d:74:3:0:0:0:0:0:17
+
+#Tower of Magery
+F:h:74:3:0:0:0:0:0:18
+
+#Inner Temple
+F:j:74:3:0:0:0:0:0:19
+
+#Paladins Guild
+F:l:74:3:0:0:0:0:0:20
+
+#Rangers Guild
+F:n:74:3:0:0:0:0:0:21
+
+D:######################################################################################################################################################################################################
+D:#-----------------------------------------------------------------------------------------#####OOOOOOO#####,,,,,,,,----------------------------------------------------------------------------------#
+D:#-------------------------------------------------------------------------------###########OOOOOOOOOOOOOOO#########,,,,,,,,,,,,,,,,,-----------------------------------------------------------------#
+D:#----------------------------------------------------------------------------######OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#######------------,,---------------------------------------------------------------#
+D:#-------------------------------------------------------------------------#####OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO######----------,,-------------------------------------------------------------#
+D:#---------------------------------------------------------------------###########OOOOOOO#######################################---------,,-----------------------------------------------------------#
+D:#------------------------------------------------------------------#####-------OOO----OO--------------------------------------###---------,,---------------------------------------------------------#
+D:#----------------------------------------------------------------###----------OOO------OO--------------------OOOOOOOOOOOOOOOOOO-###---------,,-------------------------------------------------------#
+D:#-------------------------------------------------------------####----------OOO---------OO-------------------O################O---###---------,,-----------------------------------------------------#
+D:#-----------------------------------------------------------###-----------OOO----------OOOOOOOOOOOOOOOO------O################O-----###---------,,---------------------------------------------------#
+D:#---------------------------------------------------------###-----------OOOOO----------O####2####O----OO-----O################O-------###---------,,-------------------------------------------------#
+D:#-------------------------------------------------------###-----------OOO--OO----------O#########O-----OO----O###1########i###O---------###---------,,-----------------------------------------------#
+D:#-----------------------------------------------------###-----------OOO----OO----------O#########O------OOOOOOOOOOOOOOOOOOOOOOO-----------###---------,,---------------------------------------------#
+D:#----------------------------------------------------###-----------OOO-----OO----------O####2####O-------------------------OO--OO--######--###---------,---------------------------------------------#
+D:#---------------------------------------------------###-----------OOO------OO----------OOOOOOOOOOO--------------------------OO--OO-######----###-------,---------------------------------------------#
+D:#--------------------------------------------------###-----------OOO--OOOOOOOOOOOOOOOOO-----------------------------#####6OOOOO--OO4#####------##-------,,-------------------------------------------#
+D:#-------------------------------------------------###-----------OOO---O####3####O-----------------------------------######----OO--OO------------##--------,,-----------------------------------------#
+D:#------------------------------------------------###-----------OOO----O#########O-----------####################----######-----OO--OO----######--##---------,,---------------------------------------#
+D:#-----------------------------------------------###-----------OOO-----O#########O---------####---OOOOOOOOOOOOO####--------------OO--OOOOO######---##----------,,-------------------------------------#
+D:#----------------------------------------------###-----------OOO------O####3####O-------####----OO-----------OOOO###------#####9OOO--OO--5#####----##-----------,,-----------------------------------#
+D:#---------------------------------------------###-----------OOO-------OOOOOOOOOOO-----####------OO-------------OOOO###----######--OO--OO-----------##-------------,,---------------------------------#
+D:#--------------------------------------------###-----------OOO--------O--------------###--------OO---------------OOOO###--######---OO--OOOO0#####---##-------------,---------------------------------#
+D:#-------------------------------------------###-----------OOO----------O-----------###----------OO-----------------OOOO##-----------OO--OO-######----##------------,---------------------------------#
+D:#-------------------------------------------##-----------OOO-OOOOOOOOOOOOO--------##------------OO-------------------OOO##----#####aOOO--O-######----##------------,---------------------------------#
+D:#------------------------------------------##-----------OOO--O###########O------###-------------OO---------------------OO##---######--OOOOOOO---------##-----------,---------------------------------#
+D:#------------------------------------------##----------OOOOOOOr#########rO-----##---------------OO----------------------OO##--######---#c##g#---------##-----------,---------------------------------#
+D:#------------------------------------------##----------OOO---O###########O----###---------------OO#########--------------OO##----------######---------##-----------,---------------------------------#
+D:#------------------------------------------##----------OOO---OOOOOOOOOOOOO---###----------------OO-----######-------------OO##---------######----------##----------,,--------------------------------#
+D:#------------------------------------------##---------OOOO-------------------##-----------------OO---------####------------OO##------------------------##-----------,--------------------------------#
+D:#------------------------------------------###########MMMM#####################-----------------OO-----------###-----------OO############################-----------,--------------------------------#
+D:#------------------------------------------###########IIII#####################--------------###kk###---------###----------OO############################-----------,--------------------------------#
+D:#------------------------------------------###########IIII#####################--------------########----------##-----------OO###########################-----------,,-------------------------------#
+D:#------------------------------------------###########IIII#####################--------------########----------##-----------OO###########################------------,-------------------------------#
+D:#------------------------------------------###########IIII#####################--------------########----------##------------OO##########################------------,-------------------------------#
+D:#------------------------------------------###########IIII#####################--------------########----------##------------OO##########################------------,,------------------------------#
+D:#------------------------------------------###########IIII######################-------------########----------##-#######----OO##########################-------------,,-----------------------------#
+D:#------------------------------------------###########MMMM######################------------------------------##--######dOOOOOO##########################--------------,-----------------------------#
+D:#-------------------------------------------##--------OOOOOOOOO----------------###---------------------------###--######dOOOOOO##----------------------##--------------,-----------------------------#
+D:#-------------------------------------------##-------------##OO------#######----###-------------------------###---#######---OOO##----------------------##--------------,-----------------------------#
+D:#-------------------------------------------##-------------##OOOOOOOO#######-----###-----------------------###---------------OO##----------------------##--------------,-----------------------------#
+D:#-------------------------------------------##--------------##OOOOOOO#######------###--------------------####----------------OO##----------------------##--------------,,----------------------------#
+D:#--------------------------------------------##-------------##O------#######--------###----------------####---#######-------OOO##---------------------##-----------------,,--------------------------#
+D:#--------------------------------------------##-------------##OO----------------------###################-----#######------OOO##----------------------##------------------,,-------------------------#
+D:#---------------------------------------------##-------------##OO-------------------------###########---------###n###-----OOO##----------------------##--------------------,-------------------------#
+D:#---------------------------------------------##--------------##OO------------#######-----------------#######----OOOO----OOO##----------------------##---------------------,-------------------------#
+D:#----------------------------------------------##--------------##OOO----------#######-----------------#######-------OO-OOOO##----------------------##----------------------,-------------------------#
+D:#-----------------------------------------------##--------------##OOOO--------###h###-----------------###l###--------OOOOO##----------------------##-----------------------,-------------------------#
+D:#-----------------------------------------------###--------------##OOOO----------O---------#######-------OOOOO-------OOOO##----------------------##------------------------,,------------------------#
+D:#------------------------------------------------###--------------###OOOO--------O---------#######-----------OO-----OOOO##----------------------##--------------------------,------------------------#
+D:#-------------------------------------------------###---------------###OOOO------O---------###j###------------OO--OOOO###----------------------##---------------------------,,-----------------------#
+D:#--------------------------------------------------###----------------####OOOO---O------------O----------------OOOOO###-----------------------##-----------------------------,-----------------------#
+D:#---------------------------------------------------###------------------###OOOOOOO-----------O------------OOOOOO####------------------------##------------------------------,-----------------------#
+D:#----------------------------------------------------###-------------------######OOOOOOOOOOOOOOOOOOOOOOOOOOOO#####--------------------------##-------------------------------,--TTT------------------#
+D:#------------------------------------------------------##---mmmmmmmmmmmmmm------######OOOOOOOOOOOOOOOOOOO######------mmmmmmmmmmmmmmmmm----###--------------------------------,----TTT----------------#
+D:#-------------------------------------------------------###---mmmmmmmmmmmmmmmmm----###########OOOOO#########------mmmmmmmmmmmmmmmmmmm----###---------------------------------,-#####-TT--------------#
+D:#---------------------------------------------------------###---mmmmmmmmmmmmmmmmmm------------OOOOO-----------mmmmmmmmmmmmmmmmmmmmmm---###-----------------------------------,,7####-TT--------------#
+D:#-----------------------------------------------------------###---mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmbmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm---###---------------------------------TTTT--#####-TT--------------#
+D:#-------------------------------------------------------------###----mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm---###------------------------------------TTTT----TTT----------------#
+D:#---------------------------------------------------------------####---mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm-----###----------------------------------------TTT--TTT-----------------#
+D:#------------------------------------------------------------------###----mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm-------###-------------------------------------------------------------------#
+D:#--------------------------------------------------------------------####-----mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm------#####---------------------------------------------------------------------#
+D:#-----------------------------------------------------------------------#####-------mmmmmmmmmmmmmmmmmmmmmmmmmm----------#####------------------------------------------------------------------------#
+D:#--------------------------------------------------------------------------######--------------------------------#########---------------------------------------------------------------------------#
+D:#-----------------------------------------------------------------------------###########----------------############--------------------------------------------------------------------------------#
+D:#-----------------------------------------------------------------------------------########################-----------------------------------------------------------------------------------------#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_esga.txt b/lib/mods/theme/edit/t_esga.txt
new file mode 100644
index 00000000..6665e914
--- /dev/null
+++ b/lib/mods/theme/edit/t_esga.txt
@@ -0,0 +1,105 @@
+# File: t_esga.txt
+
+# Esgaroth map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain features ###
+
+#Wooden board - horizontal
+F:a:233
+
+# Wooden board - vertical
+F:b:234
+
+#Light wooden board - horizontal
+F:c:235
+
+#Wooden plank
+F:e:241
+
+### Buildings ###
+
+#The Dancing Dragon
+F:i:74:3:0:0:0:0:0:73
+
+#The Master's House
+F:k:74:3:0:0:0:0:0:83
+
+#The Library
+F:l:74:3:0:0:0:0:0:13
+
+#The Music Store
+F:m:74:3:0:0:0:0:0:64
+
+#The Hunter store
+F:n:74:3:0:0:0:0:0:61
+
+D:######################################################################################################################################################################################################
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWccc,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWccc,,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWccc,,StSSS,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWccc,,,,,sssss,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWccc,,UUUUU,##9##,,,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWeeeO,,,,XXXXX,,,O,,,,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWbWWWWccc,,,,O,,,##6##,,,O,,UUUUU,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWbWWWWccc,,,,,,,,OOOOOO,,,,,O,,XXXXX,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWbWWWWccc,,,,,,,,SSStS,,,O,,,,,O,,##4##,,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWbWWWWccc,,,,,,,,,,,sssss,,,O,,,,,OOOOOOOO,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWbWWWWccc,,,,SSStS,,,,,##5##,,,O,,,,,,,,,,,,O,,,,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWbWWWWccc,,,,,,,sssss,,,,,,,O,,,,,O,,,,,,,,,,,,O,,,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWbWWWWccc,,,UUUUU,,##2##,,,,,,,O,,,,O,,,,,,,,,,,,,O,,SStSS,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWc,,,,,XXXXX,,,,O,,,,,,,,,O,,,O,,SSSStSSSSSS,O,,sssss,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWbWWWWc,,,,##3##,,,,O,,,,,,,,,O,,O,,,sssssssssss,O,,##0##,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWc,,,,,OOOOOOOOOOOOOOOOOO,O,,,,#####k#####,O,,,,O,,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWbWWWWc,,,,,,,,,,,O,,,,,,,,,,OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOeWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWc,,,UUUUU,,O,,,,,,,,,,,,,,,,,,,,,,,,,,,,,O,,,,,,,,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWbWWWWc,,XXXXX,,O,,SSStS,,,,,,,eeeeeeeee,,,,,,,O,,,UUUUU,,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWc,#####,,O,,sssss,,,,,eeWWWWWWWWee,,,,,,,O,,XXXXX,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWbWWWWc,,OOOOOO,,##m##,,,,eWWWWWWWWWWWWe,,,,,,,O,##n##,,,,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWc,,,,,,,O,,,O,,,,,eWWWWWWWWWWWWWWe,,,,,,,O,,O,,,,,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWbWWWWc,,,,,,,OOOO,,,,eWWWWWWWWWWWWWWWWe,,,,,,,O,O,,SSSSS,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWc,,,,,,,O,,,,,,eWWWWWWWWWWWWWWWWWe,,,,,,,O,,,sssss,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWbWWWWc,,,,,,,O,,,,,eWWWWWWWWWWWWWWWWWWe,,,,,,,O,,#####,,,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWc,,,,,,,O,,,,,eWWWWWWWWWWWWWWWWWe,,,,,,,,O,,,O,,,,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWbWWWWc,,,,,,,O,,,,,eWWWWWWWWWWWWWWWeO,,,,,,,,,O,,O,,UUUUU,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWaaaaaaaaO,,,,,eWWWWWWWWWWWWWe,,O,,,,,,,,,O,O,,XXXXX,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWbWWWWeOOOOOOOO,,,,,eWWWWWWWWWWe,,,,,O,,,,,,,,,O,,,##1##,,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWWWWWaaaaaaaaO,,,,,eWWWWWWWee,,,,,,,O,,,,,,,,,O,,,,O,,,,,,,cWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#WWWWWWWWWWWWWWWWWWWWWWWbWWWWc,,,,,,,O,,,,,eeccMMMcc,,,,,,SSSStSSSS,,,O,,,O,,,,,,,,cWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#-WWWWWWWWWWWWWWWWWWWWWWWWWWWWc,,,,,,,O,,,,,,,aaIIIaa,,,,,sssssssss,,,,O,O,,,,,,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#--WWWWWWWWWWWWWWWWWWWWWWWbWWWWc,,,,,,,O,,,,,,,aaIIIaa,,,,####i####,,OOOO,,,,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#--WWWWWWWWWWWWWWWWWWWWWWWWWWWWWc,,,,,,,O,,,,,,,aaIIIaa,,,,,,,,OOOOOOO,,,,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#---WWWWWWWWWWWWWWWWWWWWWWWWbWWWWc,,,,,,,O,,,,,,,aaIIIaa,,,,,,,,O,,,,,,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#---WWWWWWWWWWWWWWWWWWWWWWWWWWWWWa,,,,,,,,OOO,,,,,aaIIIaa,,,,,,,,O,,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#----WWWWWWWWWWWWWWWWWWWWWWWWWWWaa,OOOOOOO,,,O,,,,,aaIIIaa,,,,,,,eeeWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#-----WWWWWWWWWWWWWWWWWWWWWWWWaaOOOO,,,,OStSSSO,,,,,aaIIIaa,,,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#-----WWWWWWWWWWWWWWWWWWWWWWaaOOOOaaccc,OsssssO,,,,,,aaIIIccccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#------WWWWWWWWWWWWWWWWWWWaaOOOOaaWWWcc,O#####O,,,,,,,ccMMMWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#-------WWWWWWWWWWWWWWWaaOOOOaaWWWbWWWccO##l##O,,,,,,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#-------WWWWWWWWWWWWaaOOOOaaWWWWWWWWWWWccOOOOOO,,,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#-------WWWWWWWWWWaaOOOOaaWWWWWWWWWWbWWWcc,,,,,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#--------WWWWWWaaOOOOaaWWWWWWWWWWWWWWWWWWcc,cccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#--------WWWaaOOOOaaWWWWWWWWWWWWWWWWWWbWWWccWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#--------aaOOOOOaaWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#----------OOaaWWWWWWWWWWWWWWWWWWWWWWWWWWWWbWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#----------aaWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#---SSSSS--WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#---sssss---WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#---##7##----WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#-------------WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#--------------WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#---------------WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#----------------WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#------------------WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#-------------------WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_gondol.txt b/lib/mods/theme/edit/t_gondol.txt
new file mode 100644
index 00000000..6b0a32cd
--- /dev/null
+++ b/lib/mods/theme/edit/t_gondol.txt
@@ -0,0 +1,219 @@
+# File: Gondolin.txt
+
+# Gondolin: The Hidden Kingdom of the Noldor
+# Created by Akhronath (zzhou22876@aol.com)
+
+############### Additional default terrain settings ###############
+
+# Default for Quest 13 = entrance is mountain
+F:z:97:3
+
+# Default for Quest 14 = entrance is floor
+F:y:1:3
+
+# Default for Quest 15 = entrance is floor
+F:x:1:3
+
+# Default for Quest 23 = entrance is quest entrance
+F:w:8:3:0:0:0:0:0:23
+
+# Decoration = Straight Road (B)
+F:":66:3
+
+# Decoration = Straight Road (W)
+F:$:70:3
+
+# Rare jewelry shop -- unusable yet, need finish quest
+F:!:63:3
+
+# Between gate to minas anor -- unusable yet, need finish quest
+F:Z:63:3
+
+#################### Quest 13 - Eol the Dark Elf ####################
+
+# Quest 13 assigned, entrance is quest entrance
+?:[EQU $QUEST13 1]
+F:z:8:3:0:0:0:0:0:13
+
+?:1
+
+#################### Quest 14 - Nirnaeth Arnoediad ####################
+
+# Quest 14 assigned, entrance is quest entrance
+?:[EQU $QUEST14 1]
+F:y:8:3:0:0:0:0:0:14
+
+# Quest 14 finished, reward is a rare jewelry shop
+?:[EQU $QUEST14 5]
+F:!:74:3:0:0:0:0:0:42
+
+?:1
+
+#################### Quest 15 - Invasion of Gondolin ####################
+
+# Quest 15 assigned, entrance is quest entrance
+?:[EQU $QUEST15 1]
+F:x:8:3:0:0:0:0:0:15
+
+?:1
+
+#################### Quest 16 - The last Alliance ####################
+
+# Quest 16 finished, reward is a between gate
+?:[EQU $QUEST16 5]
+F:Z:176:3:0:0:0:0:0:1
+
+?:1
+
+############### Quest 23 - Wolves hut finished = house ###############
+?:[EQU $QUEST23 2]
+F:w:74:3:0:0:0:0:0:7
+?:[EQU $QUEST23 5]
+F:w:74:3:0:0:0:0:0:7
+?:1
+
+#################### Buildings ####################
+
+# h: Orange (Minstrel)
+# i: Red (Sorcery)
+# j: Green (Temple)
+# k: Violet (Chaos)
+# l: Dark Brown (Ranger)
+# m: White (Paladin)
+
+# Tower of the King
+F:a:74:3:0:0:0:0:0:27
+
+# Library
+F:b:74:3:0:0:0:0:0:28
+
+# Castle: Gondolin Plot
+F:B:75:3:0:0:0:0:0:4
+
+# The White Tree:Aerandir:High-Elf
+F:c:74:3:0:0:0:0:0:29
+
+# Craftsmaster
+F:d:74:3:0:0:0:0:0:30
+
+# Earth-Dome
+F:e:74:3:0:0:0:0:0:31
+
+# Prophet
+F:f:74:3:0:0:0:0:0:12
+
+# Minstrels Haven
+F:h:74:3:0:0:0:0:0:32
+
+# Star-Dome:Sulraen:High-Elf
+F:i:74:3:0:0:0:0:0:33
+
+# Valarin Temple
+F:j:74:3:0:0:0:0:0:34
+
+# Sea-Dome
+F:k:74:3:0:0:0:0:0:35
+
+# The Golden Flower
+F:l:74:3:0:0:0:0:0:36
+
+# The Fountain
+F:m:74:3:0:0:0:0:0:37
+
+# Thunderlord's Hide
+F:n:74:3:0:0:0:0:0:22
+
+# Merchant guild
+F:o:74:3:0:0:0:0:0:56
+
+# Force elven monsters
+f:ELVEN
+
+# Town Layout
+
+D:######################################################################################################################################################################################################
+D:#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#
+D:###################################################################################################################OOOOO##############################################################################
+D:###################################################################################################################OOOOO##############################################################################
+D:######################################^^^^^^^^^^^^^,,, OOOOO ####
+D:####################################^^^^^^^^^^^^,,,, OOOOO ####
+D:##################################^^^^^^^^,,,,,,,, OOOOOOOOOOOOOOOOOOOOOOOOOOO ####
+D:###########B#####################^^^^^^^^^,,,,,, OOOOOOOOCCCCCCCCCCCCCCCCCCCCCCCCCOOOOOOOO ,,,,,,, ,,,,###
+D:################################^^^^^^^^^^^,,, OOOOOOOCCCCCCCC#######################CCCCCCCCOOOOOO ,,,,,,,,,,, ,,,,,###
+D:###############################^^^^^^^^^^^^,, OOOOCCCCCCC########TTTTTTTT#####TTTTTTTT########CCCCCCOOO ,,,,,^^^^^,,,, ,,,,###
+D:##############################^^^^^^^^^^^,,, OCCCC########TTTTTT........#####......TTTTTT########CCCCOOO ,,,,^^^^^^^,,,,,, ,,,,,###
+D:#############################^^^^^^^n^^,,, OOCC###########T..........#########..........T###########CCOO ,,,,^^^^^^^^^^^^,,,,,,,,,,,###
+D:############################^^^^^^,,,,,, ......................... OOCC############T........#############........T############CCOO ,,,,^^^^^^^^^^^^^^,,,,,,,,,###
+D:############################,,,,,,,,, ......................... OCC#############T.......###WW#####WW###.......T#############CCO ,,,,^^^^^^^^^^^^^,,,,,,,,,###
+D:###########################,,,,,, ... . ... OC#############TT.......#WWWW##h##WWWW#.......TT#############CO ,,,,,^^^^^^^^^^^,,,,,,,,,###
+D:########################### ... . #### ... #### OOC#############T..........VV###.###VV..........T#############COO ,,,,,,^^^^^^^,,, ,,,,,###
+D:########################## ... ##### ####5#### OCC######WWWW###T...........V##...##V...........T####WWWW#####CCO######### ,,,,,,^^^^,,, ,,,,###
+D:########################## ######### ... ##### ####### OC######TTTTWW#TT............#.....#............TT#WWTTTT######CO######### ,,,,,,,,,, ,,,,###
+D:####W###################W# ######### ... ##### ####### OC#####l...TTW#T.................................T#WTT...T#####CO######### ,,,,,,,, ,,,,,,###
+D:####WWWW#############WWWW# ######### ... ##### ####### OC######T...............................................T######CO ,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,###
+D:#####WWWWWWW#####WWWWWWW## ######### ... ##### ######### OOC######TTT.................TTTTTTTTT.................TTT######CO , ,,,,,,,,,, ,,,,,,,,,###
+D:#####WWWWWWWWWWWWWWWWWWW## ####w#### ... ##### ######5###### OCC#######WW..............TTTT#######TTTT..............WW#######CCO , ### ,,,,,,,,,,,,,,,,###
+D:######WWWWWWWWWWWWWWWWW### . ... ##...## OC##########............TTT#############TTT............##########CO , ########## ,,, ,,,,,,,,###
+D:######WWWWWWWWWWWWWWWWW### ........... ... OC########TT...........TT#################TT...........TT########CO , ################### ,,,,,###
+D:######WWWWWWWWWWWWWWWWW### ... ... OC#####TTTT...........TT###..###aaa###..###TT...........TTTT#####CO , ############### ,,,,,,###
+D:########WWWWWWWWWWWWW###### ######### ... ############# ... OC#TTTTT..............T##.....#!...Z#.....##T..............TTTTT#CO , ############## ,,,,###
+D:###########WWWWWWW########## ######### ... ############# ... OC#T...........###...TT##.....#.....#.....##TT...###...........T#CO , ############## ,,,###
+D:############################### ######### ... ############# ... OC#T.........####....T##......#.....#......##T....####.........T#CO , ########### ,,,,###
+D:####--####KK#CC#VV#LL#""## ######### ... ############# ... OCC#TT.......####.....T##...................##T.....####.......TT#CCO , #### , ## ,,,###
+D:####--####KK#CC#VV#LL#""## ######### ... ######9###### ... OC###T......####....TTT###.................###TTT....####......T###CO , , VVVVV ,,,,###
+D:####--####KK#CC#VV#LL#""# ... . ... OC###T......d###...TT###.###....#####....###.###TT...###b......T###CO ,,,,,,,,,,,,,,, VVWWWVV ,,,###
+D:######################### ... . ... OC###T......d###...T##.....##..##WWW##..##.....##T...###b......T###CO , VVVWWWWWV ,,,,###
+D:#..............................................................................................####...T#.......#..#WV#VW#..#.......#T...####...........O , VVVVWWWWWWWV ,,,,,###
+D:#.x.........y.....................................................................................................#W#V#W#..............................,,,, VWWWWWWWWWWV ,,,,###
+D:#..............................................................................................####...T#.......#..#WV#VW#..#.......#T...####...........O , VVWWWWWWWVVV ,,,,,###
+D:######################### . ... . . OC###T......c###...T##.....##..##WWW##..##.....##T...####......T###CO , VWWWWWVVVV ,,,,,^^###
+D:####--####KK#CC#VV#LL#""# . ... . . OC###T......####...TT###.###....#####....###.###TT...####....TTT###CO , VVWWWVV ,,,,,,^^###
+D:####--####KK#CC#VV#LL#""## ####1#### ... ######2###### ##3## OC###T..............TTT###.................###TTT....####...TT#####CO , VVWWV ,,,,,,^^^^###
+D:####--####KK#CC#VV#LL#""### ######### ... ############# ##### OCC#TT................T##...................##T.....####...TT#####CCO , VVVV ,,,,,,^^^^^^###
+D:############################### ########1...... ############# ##### OOC#T.................T##......#.....#......##T....####....T######COO , ------TT------------ ,,,,,^^^^^^^###
+D:###########$$$$$$$########## ######### ... ############# ##### OC#T...VV...VV.......TT##.....##...##.....##TT...###.......f#####CO ,------TT-TTT--TT-TT-TT---- ,,,,^^^^^^^^^###
+D:########$$$$$$$$$$$$$###### ######### ... ############# ##### OC#T..VV#...#VV.......T####.#####m#####.####T..............f#####CO -,--TTTTTTTTTTTTTTT-TT-TTT---,,,,^^^^^^^^^###
+D:######$$$$$$$$$$$$$$$$$### ... OC#T..V###.###V.......TTT#################TTT.............T######CO---,--TT-TTT########TTT-TTTT----,,,,,^^^^^^^###
+D:######$$$$$$$$$$$$$$$$$### ... OC#TT.V##4.j##V.........TTT#############TTT...............TT#####CO---,---TTT###TTTTTT###TT-T-TT----,,,,,^^^^^^###
+D:######$$$$$$$$$$$$$$$$$$## ... OC##T.V#######V...........TTTT#######TTTT..................TT####CO---,--TTT##TTT----TTT##TTTTTT------,,,,,^^^^###
+D:#####$$$$$$$$$$$$$$$$$$$## ######### ... ############# OCC#T.VV#####VV.............................................TTT#CCO---,---TT#TT--------TT##T-T-TT------,,,,^^^^###
+D:#####$$$$$$$#####$$$$$$$## ######### ... ############# OOC#T..VV###VV.....TTTTTTTTTTT.......TTTTTTTTTTT..............T#COO---,,,,,,,,,,,,,,,,,,,e#TT-TTT------,,,,^^^^###
+D:####$$$$#############$$$$# ########o.........7############ OC#T...VVVVV....TTT#########TTT...TTT#########TTT............T#CO---------T#TT--------TT##TTT-------,,,,^^^^^^###
+D:####$###################$# ######### ... ############# OC#TT..........TT###VVVVVV####TT.TT####WWWWWW###TT..........TT#CO-------TTT##TTT----TTT##TTTTT-----,,,,^^^^^^^###
+D:########################## ######### ... ############# OC##T..........T##VVV....VVV###TTT###WWW....WWW##T..........T##CO------TTTTT###TTTTTT###TTTTT-----,,,,,^^^^^^^###
+D:########################### ... OCC#T..........T#VV........VV#######WW........WW#T..........T#CCO-----TTTT-TTT########TTTTTT------,,,,,,,^^^^^###
+D:########################### #...# OOC#TT.......................i#####k.......................TT#COO -T---TTTTT-TTTTTTTTTT-TT------ ,,,,,,,z^^^###
+D:############################ ##...## OC##TT........T#VV........VV#######WW........WW#T........TT##CO ------TTTT-TT--TT---T----- ,,,,,,,^^^^^^###
+D:############################ ####6#### OCC##TT.......T##VVV....VVV#########WWW....WWW##T.......TT##CCO ------TTT-TTTT--T----- ,,,,,,,^^^^^^^^^###
+D:############################# ####### OOCC##TTTT...TTT###VVVVVV#############WWWWWW###TTT...TTTT##CCOO ------T-------- ,,,,,,^^^^^^^^^^^^###
+D:############################## ##### OOCC####TTTTTTTTT###########################TTTTTTTTT####CCOO ,,,,,,^^^^^^^^^^^^^^###
+D:############################### ##### OOCCCC######TTTTTTTTTTT##############TTTTTTTTTT######CCCCOO ,,,,,,^^^^^^^^^^^^^^^^^###
+D:################################ ##### OOOOCCCCCC#####################################CCCCCCOOOO ,,,,,,,,,,^^^^^^^^^^^^^^^^^###
+D:################################# ##### OOOOOOCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOOOOO ,,,,,,,,,,^^^^^^^^^^^^^^^^^^####
+D:################################## ####### OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO ,,,,,,,,,,,^^^^^^^^^^^^^^^^^^^^^####
+D:#################################### ######### ,,,,,,,,,,,,,^^^^^^^^^^^^^^^^^^^######
+D:###################################### ############# ,,,,,,,,,,,,,,,^^^^^^^^^^^^^^^^^^########
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+D:######################################################################################################################################################################################################
+
+# Default starting position
+?:[EQU $LEAVING_QUEST 0]
+P:33:50
+
+# Starting position when coming from quest 19
+?:[EQU $LEAVING_QUEST 19]
+P:51:190
+
+# Starting position when coming from quest 20
+?:[EQU $LEAVING_QUEST 20]
+P:33:13
+
+# Starting position when coming from quest 21
+?:[EQU $LEAVING_QUEST 21]
+P:27:168
+
+# Starting position when coming from quest 22
+?:[EQU $LEAVING_QUEST 22]
+P:6:42
diff --git a/lib/mods/theme/edit/t_helm.txt b/lib/mods/theme/edit/t_helm.txt
new file mode 100644
index 00000000..0ecaf913
--- /dev/null
+++ b/lib/mods/theme/edit/t_helm.txt
@@ -0,0 +1,73 @@
+# File: t_helm.txt
+
+# Helm's Deep map by furiosity <furiosity@zionmainframe.net>
+
+#The Hornburg
+F:k:74:3:0:0:0:0:0:80
+
+D:######################################################################################################################################################################################################
+D:#TT,,,,TTTTTTTTTTTTTTTTTTTTTTTT^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTT,,,,TTTTTTTTTTTTTTTTTTTTTTT----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTT,,,,TTTTTTTTTTTTTTTTTTTTTT--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#@TTTT,,,,TTTTTTTTTTTTTTTTTTTT-------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#W@TTT,,,,TTTTTTTTTTTTTTTTTTT-----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#WW@TTTT,,,,TTTTTTTTTTTTTTTT---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#WWW@TTT,,,,TTTTTTTTTTTTTT--------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#WWWW@TTTT,,,,TTTTTTTTTTTT-------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#WWWWW@TTT,,,,TTTTTTTTTT------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#@WWWWW@TTTT,,,,TTTTTTTT--------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#T@WWWWW@TTT,,,,TTTTTTTT-------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TT@WWWWW@TTTT,,,,TTTTTT------------------------------------------^^^^^^^---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTT@WWWWW@TTT,,,,TTTT------------------------------------------^^^^^^^^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTT@WWWWW@@TTT,,,,T------------------------------------------^^^^^^^^-------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTT@@WWWWW@---,,,,-----------------------------------------^^^^^^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTT@WWWWW@@----,,,,,------------------------------------^^^^^^^----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTT@@WWWWW@@-----,,,,,--------------------------------^^^^^^^^-----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTTT@@WWWWW@@@-----,,,,,,---------------------------^^^^^^^-------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTTTTT@@@WWWWW@@@@-----,,,,,-----------------------^^^^^^---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTTTTTTTT@@WWWWWW@@@@@----,,,,,-------------------^^^^^^^----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTTTTTTT---@@@WWWWWWWW@@@@---,,,,,---------------^^^^^^^------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTTTTTT--------@WWWWWWWWWW@@@---,,,,,-----------^^^^^^^------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTTTTTT---------@@@@@WWWWWWWW@@@---,,,,--------^^^^^^^------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTTTTT---------------@@@@@WWWWWW@-----,,,,----^^^^^^--------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTTTTT--------------------@@@WWWWW@------,,,-^^^^^^------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTTTT-------------------------@WWWWW@@@----,,,,^^^----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTT-----------------------------@WWWWWW@@@@--,,,-------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTTTTT-------------------------------@WWWWWWWW@@@@,,,----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTT-----------------------------------@@@@@WWWWWWW@-,,,---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTT----------------------------------------@@@WWWWW@--,,,---------------------------------------####^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTTT------------------------------------------^^@WWWWW@-,,,-------------------------------------##OO##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTTT-----------------------------------------^^^^--@WWWW@-,,,------------------------------------##OO##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTT-----------------------------------------^^^^^^--@WWW@--,,------------------------------------##OO##-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTTT----------------------------------------^^^^^^---@WWW@--,,-----------------------------------##OO##--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TTT-----------------------------------------^^^^^^---@WWWW@-,,,---------------------------------##OO##--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TT------------------------------------------^^^^^----@WWWW@-,,---------------------------------##OO##----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TT----------------------------------------^^^^^^------@WWW@-,,--------------------------------##OO##-----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#TT----------------------------------------^^^^^^-----@WWWW@-,,-------------------------------##OO##------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^---------------------------------^^^^^^^-----@WWWW@-,,------------------------------##OO##--------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^--------------------------------^^^^^^-----@WWWWW@-,,-----------------------------##OO##----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^------------------------------^^^^^^------@WWWW@--,,---------------------@@@@---##OO##------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^-----------------------------^^^^^^------@WWW@---,,--------------------@WWWW@^##OO##@@-----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^---------------------------^^^^^^^-----@WWWW@---,,------------------@WWWWWWW##OO##WWW@----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^-------------------------^^^^^^^------@WWW@-----,,---------------@WWWW@@@@##OO##WWWW@@@@@------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^--------------------------^^^^^^------@WWWW@------,,-------------@WWWW@^^^##OO##^@WWWWWWWW@@@---------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^---------^---------------^^^^^^-------@WWWW@-------,,,-----------@WWW@^^^##OO##^^^@@@@WWWWWWW@@------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^----------^^^^^^^------------^^^^^^^------@WWW@---------,,,,--------@WWW@^^^##OO####^^^^^^@@@WWWWWW@@---------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^-----------^^^^^^^^^^-------^^^^^--------@WWW@-----------,,,,-----@WWW@^^^##OOOOOO####^^^^^^^@WWWWWW@-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^-----------^^^^^^^^^^^^^^^^---^^^^^^^------@WWWW@-------------,,,,,###@WWW@^##OOOOOOOOOO####^^^^^@@@WWWW@-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#-------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------@WWW@---------------,,,OO########OOOOOOOOOOOOOO####^^^^^^@WWW@---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------@WWWW@--------------###OOOOOOOOOOOOOOOOOOOOOOOOOOO####^^^@WWWW@-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------@WWWW@---------------##########OOOOOOOOOOOOOOOOOOOOO####^@WW@--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----@WWWWW@------------@WWWW@^^##OOOOOOOO####OOOOOOOOOOOO##^@WW@-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----@WWWWWWW@@@@@@@@@@WWWWW^^##OOOOOOOO######OOOOOOOOOO##^^@WW@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--@WWWWWWWWWWWWWWWWWW@^^##OOOOOOOOOk####kOOOOOOOOO##^^@WWW@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--@@@@@WWWWWWWWWW@^^^##OOOOOOOOOO######OOOOOOOO##^^^^@WWWW@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-@@@@@@@@@@^^^##OOOOOOOOOOOO####OOOOOOOO##^^^^^^@WWWWW@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^####OOOOOOOOOOOOOOOOOOOOO##^^^^^^^@WWWWW@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####OOOOOOOOOOOOOOOOO##^^^^^^^^^@@@WWWW@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####OOOOOOOOOOOOO##^^^^^^^^^^^^@WWW@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####OOOOOOOOO##^^^^^^^^^^^^^^@@WWW@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####OOOOO##^^^^^^^^^^^^^^^^^@WWW@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####OO##^^^^^^^^^^^^^^^^^^^@WWW@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####^^^^^^^^^^^^^^^^^^^@WWW@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_henn.txt b/lib/mods/theme/edit/t_henn.txt
new file mode 100644
index 00000000..49e91867
--- /dev/null
+++ b/lib/mods/theme/edit/t_henn.txt
@@ -0,0 +1,96 @@
+# File: t_henn.txt
+
+# Henneth Annun map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain features ###
+
+# Low hill
+F:h:213:3
+
+# Swift waterfall
+F:f:238:3
+
+# Slippery ledge
+F:l:239:3
+
+### Buildings ###
+
+# Ranger Conclave
+F:k:74:3:0:0:0:0:0:78
+
+# Fighters Hall
+F:a:74:3:0:0:0:0:0:17
+
+# Rangers Guild
+F:b:74:3:0:0:0:0:0:21
+
+D:######################################################################################################################################################################################################
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhWWWWWWWWWWhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhWWTTWWWWWhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhh^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhWWWWWTWWWh^hhhhhhhhhhhh^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^hhhhhhhhhhh#
+D:#hhhhhhhhhhhh^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhh^hWWWWWTWWWhhhhhhhhhhhh^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^hhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^WhWWWTWWhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^W^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^hh^^^@@@@@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^hh^@@,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^h^^@,,,,,,@@^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^h^^^@,,,,,,,,,@@^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^@@,,,,,,,,,,^@^hh^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,^^^^^^hhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^#
+D:#hhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^^,^h#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^h^^@,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@^@,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@^@,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^@,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^hhhhhhhhhhh^,^hhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^@@,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^h^h^^@@@a,,,,,,,,,,,,,,,,,,,,,,,,@^^^^hhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^hhhhh^,^hhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^h^^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b@@^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@^^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhh^hhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhh^^,^hhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhh^hhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^@@@3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,k@^^hhhhhhhhhh^^hhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@^^hhhhh^hhhhhhhhhh^^h^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^@@^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^^hhhhhh^hhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^@^^@2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^hhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@^^hhhhhhhhhhhhhhhhhhhh^,^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^^hhhhhhhhhhhh^h^hhhhh^,,^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@@^^^hh^hhhhhhhhhh^h^hhh^^,,^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,^^^^^^^^^^^^^h^hhhhhhhh^^,,^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^^^^,^,^,^,^,^,^,^,^,^,^,^,^,^^^^@,,,,,,,,,,,,,,,,^^^^^^^^^^^^^^^^^^,,,,,,,,,,,^^^^^^^^^^,,^^,hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,,,,^,^,^,^,^,^,^,^,^,^,^,^,^,,,^^^,,,,,,,,,,,,,,,^^^^,,,,,,,,,,,,,,,,,,^^^^^^^,,,,,,,,,,,,,,^^hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,^,,,,,,,,,,,,,,,,,,,TTTTTTTTTTTTTTTTTTTTTTTTTT^^^^^^^^^^^^^7hTThThhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,hh^^CC^^^^^^^^^^^^^^^^^^^^^^^^^^,,,lllllllllllllll^^^^^^^^^^^^^^^^^^^^^^^^^TWWWWWWWTT^T^ThThhhhhTTThhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,hhh^CCCCCCCCCCCCCCCCCCCCCCCCCffffffffllllllllllllllffffff^^^^^^^^CCCCCCCCC^^^^WWWWWTThhhhhhhhhhhhTThhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,hhhh^CCCCCCCCCCCCCCCCCCCCCCCCCffffffffffllllllllllffffffffffCCCC^^CCCCCCCCCCCCC^^^^^TTTTTTTTTTTTTTThhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,hhhhh^CCCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffffffffCCCCCCCCCCCCCCCCCCCC^C^^^^^^^^^^TTTTTThhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,hhhhhh^CCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffffffffffCCC^CCCCCCCCCCCCCCC^^CCCCC^C^^^T^^^^^TThhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,hhhhhhh^CCCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffffffffCCCC^CCCCCCCCCCCCCCCCC^^^^CCCCC^^^CCC^^^Thhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,hhhhhhhh^CCCCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffffffCCCCC^CCCCCCCCCCCCCCC^CCCCCCCCC^^CCCCCC^Thhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh^^,hhhhhhhhh^CCCCCCCCCCCCCCCCCCCCCCCCCffffffffffffffffffffffffffffCCCCCCC^CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC^Thhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_hobb.txt b/lib/mods/theme/edit/t_hobb.txt
new file mode 100644
index 00000000..6043f188
--- /dev/null
+++ b/lib/mods/theme/edit/t_hobb.txt
@@ -0,0 +1,108 @@
+# File: t_hobb.txt
+
+# Hobbiton map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain features ###
+
+#Wooden board
+F:a:235:3
+
+#Small tree
+F:b:202:3
+
+#Field
+F:c:181:3
+
+#Stable
+F:d:240:3
+
+#Low hill
+F:h:213:3
+
+#Mallorn
+F:m:243:3
+
+### Buildings ###
+
+# Farm
+F:f:74:3:0:0:0:0:0:67
+
+# Green Dragon
+F:g:74:3:0:0:0:0:0:74
+
+# Bag End
+F:i:74:3:0:0:0:0:0:84
+
+# Beastmaster
+F:j:74:3:0:0:0:0:0:16
+
+D:######################################################################################################################################################################################################
+D:#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbhhhhhhhhhhhhhhhhhhhhhhhhhhihhhhhhhccccchhOOhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb------------------------OO-------ccmccTOO------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-----------------------OO--------ccccTOO-------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------------------OO-------------OO--------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb---------------------OO---------------OO-------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb--------------------OO---------------OO--------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-------------------OO-----------------OOb------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb------------------OO-----------------OOb-------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-----------------OO##############---OO---------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-----------OOOOOOOOOOOOOOOOOOOOO#---OOb--------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------OO---#OOOOOOOOOOOOOOOO#---OOb--------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------OO---#OOOddddddddddOOO#---OO---------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------OO---#OOOddddddddddOOO#---OO---------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------OO---#OOOOddddddddjOOOOOOOO----------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------OO---#OOOddddddddddOOO#--OOb----TT---------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-----------OO--#OOOddddddddddOOO#--OO--TT-TTT--------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-----------OO--#OOOOOOOOOOOOOOOO#--OO-TT-------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb------------OO-OOOOOOOOOOOOOOOOO#--OObTT------T------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-------------OOO#################--OObTT-------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb--------------OO------------------OOOOOOOOOOOO-------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb---------------OO-----------------OOb--#####--OO-----------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-----------------OO---------------OOb--#######ff##---------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb------------------OO-----------T--OOb--###########---------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb---------------TTTTOO--------TTT-OOb---###########---------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------------TT--OO-----------OOb---#####---------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb------------------TT-OO-----TTT--OOb---#####---------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb------------------TT--OO-----T---OOb-----------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-------------------TTT-OO--TT---OOb------------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-------------------TTTT-OOTTT--OOb-------------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb---------------------TTT-OO--bOOb--------------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------------------TTT-OOOOOb---------------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-----------------------TT--OOOb----------------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------------------TTT-OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------------------TT-bOOb------------------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------------------TT-OOb-------------------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------------------TT-OOb-------------------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb---------------------TTT-OOb-------------------------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb----------------------T--OOb-##############----------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb-----------------TTT-TTT-OO--##############----------------------------------------------------------------------------------------#
+D:#bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb------------------T-TTTT-OOOO1#############----------------------------------------------------------------------------------------#
+D:#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbOO--##############@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
+D:#VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVaOOaV##############VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#
+D:#VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVaOOaVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#
+D:#VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVaOOaVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#
+D:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@bOO@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
+D:#-----------------------------------------------------------------------------------------bOO--------------------------------------------------------------------------------------------------------#
+D:#-----------------------------------------------------------------------------------hhhh---OO--------hhh-----hhh-------------------------------------------------------------------------------------#
+D:#--------------------------------------------------TT-----TT------TT-----hhhh------hhhhhh--OO-------hhhhh---hhhhh------------------------------------------------------------------------------------#
+D:#-------------------------------------------------TTTT---TTTT----TTTT---hhhhhh----hhhhhhhh-OO------hhhhhhh--hh5hh--TT---TT---TT----------------------------------------------------------------------#
+D:#--------------------------------------------------TT-----TT------TT---hhh3hhhh---hhhh2hhh-OO------hhh0hhh--------TTTT-TTTT-TTTT---------------------------------------------------------------------#
+D:#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#
+D:#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#
+D:#------------------------------------------------------------------######-hhhh-hhh------hhhOO-hh-----hhhh----h-hh-TTTT-TTTT-TTTT---------------------------------------------------------------------#
+D:#------------------------------------------------------------------######--hhhhhh--------hhOO-hhh-----hh-----hhhh--TT---TT---TT----------------------------------------------------------------------#
+D:#------------------------------------------------------------------######---hhhh----------hOO-hhh-------------hh-------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------######------------------OO-hh-------#####-----------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------######--------hhhhh-----OO----------#####-----------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------######-------hhhhhhh----OO---hh-----g####-----------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------------------hhhh4hhhh---OO--hhhh----#####-----------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------------------------------OO-hhhhhh---#####-----------------------------------------------------------------------------------------#
+D:#-------------------------------------------------------------------------------------hhh--OO-hh6hhh-------------------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------------------------hhhhh-OO--------------------------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------------------------hh7hh-OO--------------------------------------------------------------------------------------------------------#
+D:#------------------------------------------------------------------------------------------OO--------------------------------------------------------------------------------------------------------#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_imlad.txt b/lib/mods/theme/edit/t_imlad.txt
new file mode 100644
index 00000000..af06a709
--- /dev/null
+++ b/lib/mods/theme/edit/t_imlad.txt
@@ -0,0 +1,90 @@
+# File: t_imlad.txt
+
+# Rivendell/Imladris map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain features ###
+
+# Swift waterfall
+F:f:238:3
+
+### Buildings ###
+
+# Imladris
+F:a:74:3:0:0:0:0:0:79
+
+# Forge
+F:b:74:3:0:0:0:0:0:88
+
+# Stable (Beastmaster)
+F:c:74:3:0:0:0:0:0:16
+
+D:######################################################################################################################################################################################################
+D:# @^^^@ @@WWWWWWWWWW^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^WWW^#
+D:# @^^^@ @@WWWWWWWWWW^^^^^^^^^^^^^^^^^^^^^^^^---#####----------------------TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^WWWW^#
+D:# @^^^@ @@WWWWWWWWWW^^^^^^^^^^^^^^^^^^^^------#####----------------------TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT^^^^^^^^^^^^^^^^^^^^^^^^^^^^^WWWW^^#
+D:# @^^^@ @@WWWWWWWWWW^^^^^^^^^^^^^^^^----###--##b##-----------------------TTTTTTTT TTTTTTT^^^^^^^^^^^^^^^^^^^^^^^^^^^^WWWW^^^#
+D:# @^^^@ @@WWWWWWWWWW^^^^^^^^^^^^^^--######------------------------------TTTTTTTTTTTT TTTTTT^^^^^^^^^^^^^^^^^^^^^^^^^^WWWW^^^^#
+D:# @^^^@ @@WWWWWWWWWW^^^^^^^^-----####c##----------------------------------TTTTTTTTTTT TTTTTTT^^^^^^^^^^^^^^^^^^^^^^^^^WWWW^^^^^#
+D:# @^^^@ @@WWWWWWWWWW^^^^^^^^^---####----------------------------------TTTTTTTT TTTTTTTTTTTT^^^^^^^^^^^^^^^^^^^^^WWW^^^^^^^#
+D:# @^^^@ @@WWWWWWWWWW^^^^^^WW^-----------------------------------------TTTTTTTTTTTTTTT TTTTTTTTTTTT^^^^^^^^^^^^^^^^^^WWW^^^^^^^^^#
+D:# @^^^@ @@WWWWWWWWWW^^^^^^^W^------------------------------------TTTTTTTTTTTTTTTTTTTTTTTT TTTT^^^^^^^^^^^^^^^^^^^^^^WWWW^^^^^^^^^^#
+D:# @^^^@ @@WWWWWWWWW^^^^^^W@^^------------------------------------TTTTTTTTTTTTTTTTTTTTTTTTTT TTTTT^^^^^^^^^^^^^^^^^^^^WWWW^^^^^^^^^^^^#
+D:# @^^^@ @@WWWWWWWWW^^^^^^W@^^-------------------------------------TTTTTTTTTTTTTTTTTTTTTTTTTT TTTTTTT^^^^^^^^^^^^^^^^WWWW^^^^^^^^^^^^^^#
+D:# @^^^@ @@WWWWWWWWWWWWfWW@@^^-----------------------------------------------------TTTTTTTTTTTTTTTTTTTTT^^^^^^^^^^,^^@WWWW^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@WWWWWWWWWWffW@@@@^^-----------------------------------------------------TTTTTTTTTTTTTTTTTTTTT^^^^^,,,,^^@WWWW^^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@WWWWWWWWffWW@@@@@^^------------------------------------------------------TTTTTTTTTTTTTTTTTTTTT^^,,^^^@@WWWW^^^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@WWWWWWffWWWWW@@@@^^^------------------------------------------------------TTTTTTTTTTTTTTTTTTT,,^^^^@WWWWW^^^^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@WWWWffWWWWWWW@@@@@^^^^-----------------------------#################-------TTTTTTTTTTTTTT,,,^^^@@WWWW@^^^^^^^^^^^^^^^^^^^^^#
+D:# @^^^@ @@WWffWWWWWWWWWW@@@@@@^^----------------------------#################---------------TTT--,,^^^@@WWWWW@^^^^^^^^^^^^^^^^^^^^^^#
+D:# TTTTTT @^^^@ @^^ffWWWWWWWWWWWWW@@@@@^^------------------------#######################-------------,,,,^^^@@WWWWW^^^^T^^^^^^^^^^^^^^^^^^^^#
+D:# TTTTTTT TTT @^^^@ @^^^^^^^WWWWWWWWWWWWWWWW@@@@^^----------,,,,,,,,,,,,,a#####################a,----------,,^^^^^@@WWWWW^^^TTTTT^^^^^^^^^^^^^^^^^^^#
+D:# TTTT TTT @^^^@^@@^^@^^^^@ @@WWWWWWWWWWWWWWWWWW@@^^^^----,,,,,,,,,,,,,,,,a#####################a,---------,,^^^@@@WWWWW@^^TTT TTT^^^^^^^^^^^^^^^^^^#
+D:# TTT TTT T TTT @^^^^^^^^^^^@ @@@WWWWWWWWWWWWWWWWW@@@^^,,,,,,-------------,#######################,------,,,^^^@@WWWWWWW@^^TTT TTT^^^^^^^^^^^^^^^^^^^#
+D:# TTT T TTT T TT @^^@ @@@@@WWWWWWWWWWWWWW@#,,,,,^^^------------,---#################---,-----,,^^^@@WWWWWWWW@^^TTT TTT^^^^^^^^^^^^^^^^^^^^#
+D:# TTT T TTTTTTT TT @@@@@WWWWWWWWWWW#,,,,,#@@^^^^^^^^------,--#################---,-,,,,^^^@@WWWWWWWWW@^^TT TTT^^^^^^^^^^^^^^^^^^^^^^#
+D:# TT TTTTTT,,TT,,TT,, @@@@WWWWWWW#,,,,,#WWW@@@@@@@^^------,--------------------,,,,^^^^@@WWWWWWWWWW@^^TT TTT^^^^^^^^^^^^^^^^^^^^^^^#
+D:# TT TTT TT ,,,TT,,TT,,T,, ,,,,,,, @@@@WWW#,,,,,#WWWWWWWWWW@@@^^^^^^,,,,,,,,,,,,,,,,,,,,,,^^^^@@@WWWWWWWWWW@@^^TT TTT^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# TTT T ,,TTT TTT TTTTT,, ,,,,,,,,,,,,,,, @@W#,,,,,#WWWWWWWWWWWWWW@@@@@^^^^^^^^^^^^^^^^^^^^^^^^@@@WWWWWWWWWWW@@@^^TT TTT^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# TTTT ,,TT TTTT,,,,,, ,,,, ,,,,, ,,,,,,,,,,@#,,,,,#WWWWWWWWWWWWWWWWWWWW@@@@@@@@@@@@@@@@@@@@@@@@WWWWWWWWWWWW@@@@^^TT TT^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# T TTT T,,TT T TT TT,,,,^^,,,, ,,,, ,,,, ,,,, ,,,, ,,,,,,,,@@#@@@@@WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW@@@@^^^^TT TT^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# TTT T,,TT TT TT,,,,^^^^^^,,,, ,,,, ,,,,, ,,,, ,,,,@@@ @@@@@WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW@@@^^^^TTT TT^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# T,,TTT T,,,,^^@@^^^^@ @^@,,,,, ,,,, @@@@@@WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW@@@@TTTTTTTT TT^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ,,,,,,TTTT TTTT TTTT,,,,^^@ @^^^@ ,,,,,,,,,, @@@@@@@@WWWWWWWWWWWWWWWWWWWWW@@@@@@ TTTTTTTTT^^@@^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ,,,,^^^^^^TTT TTT^^,,,,^^@ @^^^^^@ ,,,,, @@@@@@@@@@@@@@@@@@@@@@@ @^@TTTT^^@ @^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# ,,,,,^^^^@ @^^^TTTTTTTT^^^^,,,,^^@ @^^^^^^@ ,,, @^^^@ ^^^^^^^^^^^^^^^^^^^^^^#
+D:# ,,,,^^^^@ @^^^^^^^^^^^^^,,,,^^@ @^^^^^^^^^@ @^^^^@^^^^^@^^^^^^^^^@ @^^^@ ^^^^^^^^^^^^^^^^^#
+D:#,,,,,^^^^@ @^^^^^^^^^,,,,^^@ @^^^^^^^^^^^^^^^^@ @^^^@ @^^^@ @^^^^@^^^@ @^^^@ ^^^^^^^^^^^^^#
+D:#^^^^^^@ @^^^^^^^,,,,^^@ @^^^@ @^^^@^^^@@^^^^^^^^^^^^^^^^^^^^@@^^^@^^^@^^^@^^^@^^^@^^^@@^^^@@^^^@@^^^@ ^^^^^^^^^#
+D:# @^^^^^,,,,^^@ @^^^^@ @^^^@ @^^^@ @^^^@^^^@^^^@^^^@^^^@^^^@^^^@^^^@@^^^@@^^^@ ^^^^^^#
+D:# @^^^,,,,^^@ ^^^#
+D:# @^^,,,,^^@ ^^#
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^,,,,^^@ #
+D:# @^^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:# @^^,,,, #
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_info.txt b/lib/mods/theme/edit/t_info.txt
new file mode 100644
index 00000000..8a525ede
--- /dev/null
+++ b/lib/mods/theme/edit/t_info.txt
@@ -0,0 +1,125 @@
+# File: t_info.txt
+
+# Includes the town definitions
+
+# Preferences for the town features
+%:t_pref.txt
+
+# Town Bree
+?:[AND [EQU $TOWN 1] [EQU $TOWN_DESTROY1 1] ]
+%:t_d_bree.txt
+?:[AND [EQU $TOWN 1] [NOT [EQU $TOWN_DESTROY1 1] ] ]
+%:t_bree.txt
+?:1
+
+# Town Gondolin
+?:[AND [EQU $TOWN 2] [EQU $TOWN_DESTROY2 1] ]
+%:t_d_gond.txt
+?:[AND [EQU $TOWN 2] [NOT [EQU $TOWN_DESTROY2 1] ] ]
+%:t_gondol.txt
+?:1
+
+# Minas Anor
+?:[AND [EQU $TOWN 3] [EQU $TOWN_DESTROY3 1] ]
+%:t_d_mina.txt
+?:[AND [EQU $TOWN 3] [NOT [EQU $TOWN_DESTROY3 1] ] ]
+%:t_minas.txt
+?:1
+
+# Town Caras Galadhon
+?:[AND [EQU $TOWN 4] [EQU $TOWN_DESTROY4 1] ]
+%:t_d_lori.txt
+?:[AND [EQU $TOWN 4] [NOT [EQU $TOWN_DESTROY4 1] ] ]
+%:t_lorien.txt
+?:1
+
+# Khazad-Dum
+?:[AND [EQU $TOWN 5] [EQU $TOWN_DESTROY5 1] ]
+%:t_d_khaz.txt
+?:[AND [EQU $TOWN 5] [NOT [EQU $TOWN_DESTROY5 1] ] ]
+%:t_khazad.txt
+?:1
+
+# Beorn's Halls
+?:[AND [EQU $TOWN 6] [EQU $TOWN_DESTROY6 1] ]
+%:t_d_beorn.txt
+?:[AND [EQU $TOWN 6] [NOT [EQU $TOWN_DESTROY6 1] ] ]
+%:t_beorn.txt
+?:1
+
+# Cerin Amroth
+?:[AND [EQU $TOWN 7] [EQU $TOWN_DESTROY7 1] ]
+%:t_d_cerin.txt
+?:[AND [EQU $TOWN 7] [NOT [EQU $TOWN_DESTROY7 1] ] ]
+%:t_cerin.txt
+?:1
+
+# Dale
+?:[AND [EQU $TOWN 8] [EQU $TOWN_DESTROY8 1] ]
+%:t_d_dale.txt
+?:[AND [EQU $TOWN 8] [NOT [EQU $TOWN_DESTROY8 1] ] ]
+%:t_dale.txt
+?:1
+
+# Edoras
+?:[AND [EQU $TOWN 9] [EQU $TOWN_DESTROY9 1] ]
+%:t_d_edoras.txt
+?:[AND [EQU $TOWN 9] [NOT [EQU $TOWN_DESTROY9 1] ] ]
+%:t_edoras.txt
+?:1
+
+# Esgaroth
+?:[AND [EQU $TOWN 10] [EQU $TOWN_DESTROY10 1] ]
+%:t_d_esga.txt
+?:[AND [EQU $TOWN 10] [NOT [EQU $TOWN_DESTROY10 1] ] ]
+%:t_esga.txt
+?:1
+
+# Helm's Deep
+?:[AND [EQU $TOWN 11] [EQU $TOWN_DESTROY11 1] ]
+%:t_d_helm.txt
+?:[AND [EQU $TOWN 11] [NOT [EQU $TOWN_DESTROY11 1] ] ]
+%:t_helm.txt
+?:1
+
+# Henneth Annun
+?:[AND [EQU $TOWN 12] [EQU $TOWN_DESTROY12 1] ]
+%:t_d_henn.txt
+?:[AND [EQU $TOWN 12] [NOT [EQU $TOWN_DESTROY12 1] ] ]
+%:t_henn.txt
+?:1
+
+# Hobbiton
+?:[AND [EQU $TOWN 13] [EQU $TOWN_DESTROY13 1] ]
+%:t_d_hobb.txt
+?:[AND [EQU $TOWN 13] [NOT [EQU $TOWN_DESTROY13 1] ] ]
+%:t_hobb.txt
+?:1
+
+# Imladris
+?:[AND [EQU $TOWN 14] [EQU $TOWN_DESTROY14 1] ]
+%:t_d_imlad.txt
+?:[AND [EQU $TOWN 14] [NOT [EQU $TOWN_DESTROY14 1] ] ]
+%:t_imlad.txt
+?:1
+
+# Osgiliath
+?:[AND [EQU $TOWN 15] [EQU $TOWN_DESTROY15 1] ]
+%:t_d_osgili.txt
+?:[AND [EQU $TOWN 15] [NOT [EQU $TOWN_DESTROY15 1] ] ]
+%:t_osgili.txt
+?:1
+
+# Pelargir
+?:[AND [EQU $TOWN 16] [EQU $TOWN_DESTROY16 1] ]
+%:t_d_pelar.txt
+?:[AND [EQU $TOWN 16] [NOT [EQU $TOWN_DESTROY16 1] ] ]
+%:t_pelar.txt
+?:1
+
+# Thranduil's Halls
+?:[AND [EQU $TOWN 17] [EQU $TOWN_DESTROY17 1] ]
+%:t_d_thrand.txt
+?:[AND [EQU $TOWN 17] [NOT [EQU $TOWN_DESTROY17 1] ] ]
+%:t_thrand.txt
+?:1 \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_khazad.txt b/lib/mods/theme/edit/t_khazad.txt
new file mode 100644
index 00000000..73e93956
--- /dev/null
+++ b/lib/mods/theme/edit/t_khazad.txt
@@ -0,0 +1,114 @@
+# Town Name: Khazad-Dum
+# by fearoffours (fearoffours@moppy.co.uk)
+#
+# Created for ToME
+
+F:o:207:3
+
+###################### Buildings ########################
+
+# Fighters Hall
+F:f:74:3:0:0:0:0:0:17
+
+# Paladins Guild
+F:g:74:3:0:0:0:0:0:20
+
+# Inner Temple
+F:h:74:3:0:0:0:0:0:19
+
+# Mining Supplies
+F:i:74:3:0:0:0:0:0:59
+
+# Default for Quest 25 = entrance is quest entrance
+F:w:8:3:0:0:0:0:0:25
+
+# Seat of Durin
+F:k:74:3:0:0:0:0:0:87
+
+# Inn
+F:n:74:3:0:0:0:0:0:70
+
+# Eagles
+F:p:74:3:0:0:0:0:0:22
+
+# Force dwarven monsters
+f:DWARVEN
+
+############### Quest 25 - Evil cave finished = house ###############
+?:[EQU $QUEST25 2]
+F:w:74:3:0:0:0:0:0:7
+?:[EQU $QUEST25 5]
+F:w:74:3:0:0:0:0:0:7
+?:1
+
+# Town Layout
+D:######################################################################################################################################################################################################
+D:#ooooooooooooo####^^^^^^^^^#######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#####oooo#######oo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^##########oooooooooo CCCCCCC #
+D:#ooo##ooooooooo#####^^^^^##########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^########ooo########ooo##########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^################oooooooooooo CCCCCCCC #
+D:##oo###oo####oo##############################^^^^^^^^^^^^^^^^^########################oooo#########oo#### ###########^^^^^^^^^^^^^^^^^^^^^^^^####### #######oooo########## CCCCCCCC #
+D:##############o#########oo###oo###################^^^^^^^############################oooo#########oo###### ################################# #####ooooooooo############# CCCCCCCC ; #
+D:#^^^^########oooooooooooooo##ooooooooo############################# ##################oooo########oo########### ########################## ######ooooooooo################ CCCCCCCC ; #
+D:#############ooooooooooooooooooooooooooo###### ###########1###### ##############2####oooo#######o##o##3####f##### ##g####4####h###### ###########ooo######################## CCCCCCCC ; #
+D:#^#############ooooo##################oo### # #### # ##### #### ############### ###ooo########ooo## ## ###### # ## ## ## # #######ooooo########################### CCCCCCCC #
+D:#^^################oo#################ooooo#### ## ; ;; o ; o ## # ooooooooo############################ CCCCCCCC #
+D:#^^^^################o##########o#####oooooooooooooooooooooo o o ; oooooooooooooooooooooooo##ooo############################ CCCCCCC #
+D:#^^^^^^################################# ## ; o ; ; o o ; o ##o################################### CCCCCCC#
+D:#^^^^^^################################ ### o ### o ### o ###; o ### ######################################## CCCCCC#
+D:#^^^^^################################# ##### o ##### o ##### o ##### o ##### ######################################## CCCCCC#
+D:#^^^^^^^################################ #######;; o ####### o ####### o ####### o ####### ####################################### ; CCCCCC#
+D:#^^^^^^^^################################ # ####### o ; ####### o ####### o ####### o ####### ######################################## CCCCCC #
+D:#^^^^^^^################################### ##### o ; ;##### o ##### o ##### ; o ##### ;####################################### CCCCCCC #
+D:#^^^^^^^^^################################ ### o ### o ### o ### o ### # #################################### CCCCCC ; #
+D:#^^^^^^^^^################################# o o o o ## ################################## CCCCCC #
+D:#^^^^^^^^^^################################ ; oooooooooooo o o oooooooooooo 5################################ CCCCCC ; #
+D:#^^^^^^^^^^^^^########################### o o o o ################################# CCCCCCC #
+D:#^^^^^^^^^^^^^^^########################## ### o ### o o ;### o ### ################################ CCCCCCC ; #
+D:#^^^^^^^^^^^^############################# ##### ; o ##### o o ##### o ##### ; ###############################; CCCCCCC ; #
+D:#^^^^^^^^^############################### ; ####### o ####### o ; o ####### o ####### ############################ CCCCCCC #
+D:#^######################################### ; ####### oooooooo ####### o o ####### oooooo ####### o ; ##############################; CCCCCCC #
+D:#################ooo###################### ; ##### o ##### o o ##### o ##### ###############oo############## CCCCC; #
+D:####oo##ooo#####o#######o###ooo########### ### ; o ### o o ### o ; ### ; ;; #########oo###oooooo#####oo###### CCCCC ; #
+D:#ooooooooooooooooooooooooooooooo##oooooooo ; o ; o o o ; ;; ; oooooooooooo##oooooooo##oooooooooo CCCCC ; #
+D:#ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo CCCCCC #
+D:#oooooooooooooooooo##oooooo##oooooo##ooooo ; o o ; ooooooooo#oooooooooooooooooooooooo CCCCC #
+D:#p#######################oo####ooooo####### ### ### o o ###; ### ######o####oo####oo######oo######; CCCCC #
+D:#^^#######################o########### ##### ##### o o ##### ##### ######o####################oo#### CCCCC #
+D:#^####################################### #######;; ; ####### o k o ####### ####### ####oo######################### CCCCCC #
+D:#^^######################################## ####### ; ####### o o ####### ####### ######o############oo########## CCCCCCC #
+D:#^^^###############ooo################### ##### ; ;##### o o ##### ; ##### ;; ######oo########ooooo####### CCCCCCCC #
+D:#####oo##oo#####oooooooo##############oo## ### ; ### o o ### ### ########oooo##oooooo####### CCCCCCCCC ; #
+D:#ooooooooooo###ooooooooooooooooooooooooooo o o ooooooooooooooooooooooooooo CCCCCCCC #
+D:#oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo CCCCCCCC ; #
+D:#^ooooooooooooooooo###oooooooooo##oooooooo o o o o ooooooo####ooooooooooooo CCCCCCCC #
+D:#^^#o###ooo#####ooo#####ooooo########oo# ### ; o ### o o ;### o ### oo#########ooooo###oo# CCCCCCCC ; #
+D:#^^^^^###o################oo############# ##### ; o ##### o o ##### o ##### ; ###########oo######## CCCCCCCC ; #
+D:#^^^^^^^################################## ; ####### ooooooo ####### o ; o ####### ooooo ####### ######################## CCCCCCCCC #
+D:#^^^^^^^^^^############################## ; ####### o ; ####### o o ####### o ####### o ; ########################## CCCCCCCC #
+D:#^^^^^^^^^^^^^^^######################### ; ##### o ##### o o ##### o ##### ############################ CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^################### ### ; o ### o o ### o ; ### ; ;; ############################ CCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^#################### ; o ;; o ; o o ; ############################ CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^###################### ooooooooooo o o oooooooooooo ;; ; 7########################### CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^^^^################# ; o ; ; o o ; o ############################# CCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^############## ### o ### o ### o ###; o ### ############################# CCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^############ ##### o ##### o ##### o ##### o ##### ######################## CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^########## #######;; ; o ####### o ####### o ####### o ####### ########################### CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^#########i ####### o ; ####### o ####### o ####### o ####### ############################ CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^########### ##### o ; ;##### o ##### o ##### ; o ##### ; ############################## CCCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^^^^^^############## ### ; o ### o ### o ### o ### ############################## CCCCCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^^^^^^################# o o o o #########oo###oo################# CCCCCCCCCC #
+D:#^^^^^^^^^^^^^^^^^^#############o#######oooooooooooooooooooooo ## o o oooooooooooooooooooooooooooooooooooo################## CCCCCCCC ; #
+D:#^^^^^^^^^^^^^^^^^############ooooooooooo# ### ## ######## o o ## o ## ## oooooo##oooooooooo################### CCCCCCC #
+D:#^^^^^^^^^^^#################ooooooooooo#### ###### ### #### ############# ####oooo###### #ooo# ### ###### # ### ## ##### ####################ooo##################### CCCCCCC #
+D:#^^^^^^^^^^###################oo######oo### ########### #######9####################oooo########oooo############w### #####n## ###### ####################oo###################### CCCCCCC #
+D:#^^^^^^^##########oo####oo####ooo######### ############# ##############^^^##########ooooo########oo###################################### #########^######oooo##ooo################## CCCCCCC #
+D:##^^^^^#########oooooooooooooooo#################^^####### ###########^^^^^###########ooooo######ooo####################################### #####^^^#######ooooooooooooo############# ; CCCCCCC#
+D:#^^^##########ooooooooooo##ooooo######^#########^^^^##################^^^^^^^^^^^######ooo#######oooo#########^^^^^^^^^^^^^^^^^^^########### #####^^^#######oo##oooooooo############# CCCCCC#
+D:##############ooooo##########oo######^^^#####^^^^^^^^###############^^^^^^^^^^^^^^#####oooo#######ooo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^###### ####^^^^^###############ooo############## CCCCC#
+D:########ooo#####oo##################^^^^^^^^^^^^^^^^^#############^^^^^^^^^^^^^^^^^####oo########oooo#####^^^^^^^^^^^^^^^^^^^^^^^^^^^########### #######^^^^^#############ooo#ooo######## CCCCCC#
+D:#o##oooooooooooooooo##############^^^^^^^^^^^^^^^^^^^^^^#########^^^^^^^^^^^^^^^^^^#####oo########oo######^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^####### # ######^^^^^^^^^^^^########oooooooooooooo CCCCC #
+D:#oooooooooooooooooo########^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^########oooo#######ooooo###^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^##############^^^^^^^^^^^^^^^#######ooooooooooo CCCCC #
+D:######################################################################################################################################################################################################
+
+# Default starting position
+# ?:[EQU $LEAVING_QUES 0]
+# P:31:32
diff --git a/lib/mods/theme/edit/t_lorien.txt b/lib/mods/theme/edit/t_lorien.txt
new file mode 100644
index 00000000..a4a63172
--- /dev/null
+++ b/lib/mods/theme/edit/t_lorien.txt
@@ -0,0 +1,185 @@
+# File: t_lorien.txt
+
+# Caras Galadhon map by furiosity <furiosity@zionmainframe.net>
+# Original Lothlorien map by Akhronath <zzhou22876@aol.com>
+
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+# Default for Mage/Fireproof Quest = entrance is tree
+F:z:96:3
+
+# Default for Quest 10 = entrance is tree
+F:y:96:3
+
+# Default for Quest 11 = entrance is tree
+F:x:96:3
+
+# Default for entrance to the Void, entrance is dirt
+F:v:88:3
+
+# Default for Quest 22 = entrance is quest entrance
+F:w:8:3:0:0:0:0:0:22
+
+############### Quest 22 - Wolves hut finished = house ###############
+?:[EQU $QUEST22 2]
+F:w:74:3:0:0:0:0:0:7
+?:[EQU $QUEST22 5]
+F:w:74:3:0:0:0:0:0:7
+?:1
+
+############### Entrance to the Void ###############
+?:[EQU $QUEST20 1]
+F:v:7:3:0:0:0:0:0:11
+?:1
+
+############### Quest 10 - Spiders of Mirkwood ###############
+# Quest 10 taken, entrance is quest entrance
+?:[EQU $QUEST10 1]
+F:y:8:3:0:0:0:0:0:10
+?:1
+
+############### Quest - Mage/Fireroof quest ###############
+# Mage/Fireproof Quest taken, entrance is quest entrance
+?:[EQU $QUEST"Old Mages quest" 1]
+F:z:8:3:0:0:0:0:0:"Old Mages quest"
+?:1
+
+### Additional terrain features ###
+
+# Flet
+F:o:220:3
+
+# Fosse (dry moat)
+F:p:242:3
+
+#Mallorn
+F:m:243:3
+
+#Small tree
+F:l:202:3
+
+###################### Buildings ########################
+
+# The Mirror
+F:a:74:3:0:0:0:0:0:23
+
+# Castle: Plot Lorien
+F:B:75:3:0:0:0:0:0:2
+
+# Seat of Ruling
+F:b:74:3:0:0:0:0:0:24
+
+# Inn
+F:c:74:3:0:0:0:0:0:69
+
+# Beastmaster Shanty
+F:d:74:3:0:0:0:0:0:16
+
+# Fighters Hall
+F:f:74:3:0:0:0:0:0:17
+
+# Wizards Spire
+F:g:74:3:0:0:0:0:0:25
+
+# Priests Circle
+F:h:74:3:0:0:0:0:0:26
+
+# Rangers Guild
+F:i:74:3:0:0:0:0:0:21
+
+# Nest
+F:j:74:3:0:0:0:0:0:22
+
+# Hunter store
+F:k:74:3:0:0:0:0:0:61
+
+# Museum
+F:q:74:3:0:0:0:0:0:57
+
+# Music shop
+F:r:74:3:0:0:0:0:0:64
+
+# Force elven monsters
+f:ELVEN
+
+# Town Layout
+
+D:######################################################################################################################################################################################################
+D:# OOO #
+D:# OOOOOOOOOOOOOOOOOOOOOOOOO #
+D:# OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO #
+D:# OOOOOOOOOOOppppppppppppppppppppppOOOOOOOOOOOO #
+D:# OOOOOOOOOpppppppppppppppppppppppppppppppppppOOOOOOOO #
+D:# OOOOOOOppppppppppppppppppppppppppppppppppppppppppppOOOOOOOy #
+D:# OOOOOOpppppppppppppppppppppppppppppppppppppppppppppppppppOOOOOO #
+D:# OOOOOppppppppppppppppppppppppppppppppppppppppppppppppppppppppOOOOOO #
+D:# OOOOOpppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppOOOOO #
+D:# OOOOppppppppppppppppppppppppTTTTTTTToxTTTTTTTTTpppppppppppppppppppppppOOOOO #
+D:# OOOOpppppppppppppppppppppTTTTT lo9ol TTTTTppppppppppppppppppppOOOO #
+D:# OOOOOpppppppppppppppppppTTT lol TTTpppppppppppppppppppOOOO #
+D:# OOOOppppppppppppppppppTTT l,,,l TTTppppppppppppppppppOOOO #
+D:# OOOOpppppppppppppppppTTT lllllll,,,lllllllll TTTppppppppppppppppOOOO #
+D:# OOOOppppppppppppppppTTT lll,,,,,,,,,,,,,,,,,,,lll loTTpppppppppppppppppOOO #
+D:# OOOOppppppppppppppppTz lll,,,,,,,,,,,,,,,,,,,,,,,,,ll lodoTTppppppppppppppppOOO #
+D:# OOOppppppppppppppppTTol ll,,,,lllllllll,,,llllolllll,,,,l l,,ol TTpppppppppppppppOOO #
+D:# OOOppppppppppppppppTTogol l,,,lllo l,,,l o0o ll,,,l l,,ll TTpppppppppppppppOOO #
+D:# OOOOppppppppppppppTT lo,,l l,,l oko l,,,l o ll,,l,,l TpppppppppppppppOOO #
+D:# OOOOppppppppppppppTT ll,,l l,,l o l,,,l l,,,l TpppppppppppppppOOO #
+D:# OOOppppppppppppppTT l,,l,,l l,,,l ll,,,l TpppppppppppppppOOO #
+D:# OOOpppppppppppppppT l,,,l ll,,,,,ll l,,l,,l TppppppppppppppOOO #
+D:# OOOpppppppppppppppT l,o,lll l,,l,,,l,,l ll,,l l,,l TppppppppppppppOOO #
+D:# OOOOppppppppppppppT l,o2o,,,ll l,,ll,,,ll,,l l,,,l l,,l TppppppppppppppOOO #
+D:# OOOppppppppppppppTT l,,lolll,,,l l,,l l,,,l l,,l ll,,ll l,,l TppppppppppppppOO #
+D:# OOOppppppppppppppT l,,l ll,,ll l,,l l,,,l l,,l,,,l o,,l TppppppppppppppOO #
+D:# OOOpppppppppppppTT l,,l l,,,ll,,l l,,,l ll,,l o6o,,l TppppppppppppppOOO #
+D:# OOOppppppppppppppT l,,l ll,,,,ll mm,mm ll,,,,l o l,,l TpppppppppppppOOO #
+D:# OOOppppppppppppppT l,,l o l,,,,,lmm-----mm,,,ll,,l l,,l TppppppppppppppOOO #
+D:# OOppppppppppppppTT l,,l oro l,,ll,,,mm-----mm,ll l,,l l,,l TppppppppppppppOOO #
+D:# OOppppppppppppppTTl l,,l o l,,l l,,---@@@---mm l,,l l,,l TppppppppppppppOOO #
+D:# OOppppppppppppppTlollllll,,lllllllllllll,,lllllmm--@@V@@--mmllllll,,lllllllllll,,llllllllolTppppppppppppppOOO #
+D:# OOppppppppppppppToio,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--@VWV@--,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ohoTppppppppppppppOOO #
+D:# OOppppppppppppppTlollllll,,lllllllllllll,,lllllmm---@V@@@-mml l,,lllllllllll,,llllllllolTppppppppppppppOOO #
+D:# OOppppppppppppppTTl l,,l l,,l mm,-----VV@,,,ll l,,l l,,l TppppppppppppppOOO #
+D:# OOOppppppppppppppT l,,o l,,l l,mmm--o-@VV@m,,,ll,,lo l,,l TppppppppppppppOO #
+D:# OOOppppppppppppppT l,o4o l,,l,,l mmobom@VV@ll,,,lloqo o,,l TppppppppppppppOO #
+D:# OOOppppppppppppppT l,ol l,,,l mmomm@VVV@ l,,,,lo o5o,l TTpppppppppppppOOO #
+D:# OOOpppppppppppppppT l,,l ll,,,ll l,,,l @@VV@@lll,,,ll o,l TppppppppppppppOOO #
+D:# OOOppppppppppppppT l,,l ll,,,ll,,l l,,,l @VVV@ ll,,,ll l,,l TTpppppppppppppOOO #
+D:# OOOpppppppppppppppT l,,l l,,,ll l,,l l,,,l l,@VV@ ll,,,l l,,l TppppppppppppppOOO #
+D:# OOOppppppppppppppTT l,,l lll,,ll l,,ll,,,l l,,l@VV@ ll,,l,,l TpppppppppppppppOO #
+D:# OOOpppppppppppppppT l,,ll,,,,l l,,l,,,ll,,l @VVV@ ll,,ll TTppppppppppppppOOO #
+D:# OOOpppppppppppppppTT l,,,,,ll l,,,,,o,,l @VV@@ l,,l,,ll TTpppppppppppppppOO #
+D:# OOOpppppppppppppppT l,,,ll ll,,o1ol @VVV@ l,,l ll,,l TTpppppppppppppppOOO #
+D:# OOOppppppppppppppppT ll,,l,,l l,,,ol l,@VV@ l,,l ll,o TTpppppppppppppppOOO #
+D:# OOOppppppppppppppppTT lo,,l l,,l o l,,,l l,,l@VV@,,l owoTTpppppppppppppppOOO #
+D:# OOOppppppppppppppppTTlofol l,,llo3olllllllll,,,lllllll,,,,@VVV@l oTppppppppppppppppOOO #
+D:# OOOpppppppppppppppppTTol l,,,,o,,,,,,,,,,,,,,,,,,,,,lllv@@VV@ TTppppppppppppppppOOO #
+D:# OOOOpppppppppppppppppTT lll,,,,,,,,,,,,,,,,,,,,,,l @VVV@@VV@@ TTpppppppppppppppppOOO #
+D:# ##7OOOOpppppppppppppppppTTT llllllllloll,,,lllllll @VWaWV@@VVV@ TTppppppppppppppppppOOO #
+D:# B## OOOppppppppppppppppppTTT ocol,,,l @VVV@ @VV@TppppppppppppppppppOOOO #
+D:# OOOOpppppppppppppppppppTTT o l,,,lllll @@ TT@VV@pppppppppppppppppOOO #
+D:# OOOOpppppppppppppppppppppTTTT l,,,,,,,,l TTTTTp@VVV@ppppppppppppppOOOO #
+D:# OOOOpppppppppppppppppppppppTTTTTTT l,,,,,,,,TTTTTTTpppppp@@VV@@ppppppppppOOOO #
+D:# OOOOppppppppppppppppppppppppppppTTTTTTTTOOOppppppppppppppp@VVV@pppppppOOOOO #
+D:# OOOOpppppppppppppppppppppppppppppppppOOOppppppppppppppppp@VV@pppppOOOOO #
+D:# OOOOOpppppppppppppppppppppppppppppOOOppppppppppppppppppp@VV@ppOOOOO #
+D:# OOOOOOpppppppppppppppppppppppppOOOpppppppppppppppppppp@VVV@OOO #
+D:# OOOOOOpppppppppppppppppppppOOOppppppppppppppppppppOO@@VV@@ #
+D:# OOOOOOOpppppppppppppppppOOOppppppppppppppppOOOOOOOO@VVV@ #
+D:# OOOOOOOOOOpppppppppppOOOpppppppppppOOOOOOOOO @VV@ #
+D:# OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO @VVV@ #
+D:# OOOOOOOOOOOOOOOOOOOOOOO @@VVV@ #
+D:######################################################################################################################################################################################################
+
+# Default starting position
+?:[EQU $LEAVING_QUES 0]
+P:13:99
+
+# Starting position when coming from quest 12
+?:[EQU $LEAVING_QUES 12]
+P:26:109
+
+
diff --git a/lib/mods/theme/edit/t_minas.txt b/lib/mods/theme/edit/t_minas.txt
new file mode 100644
index 00000000..b96481d8
--- /dev/null
+++ b/lib/mods/theme/edit/t_minas.txt
@@ -0,0 +1,141 @@
+# File: t_minas.txt
+
+# Minas Anor: The Royal City of Gondor
+# Created by Mynstral (mynstral@thehelm.com)
+
+# Completed: 22/06/01
+
+# Between gate to gondolin -- need to finish the quest
+F:Z:63:3
+
+# Default for Quest 24 = entrance is quest entrance
+F:w:8:3:0:0:0:0:0:24
+
+#################### Quest 16 - The last Alliance ####################
+
+# Quest 16 finished, reward is a between gate
+?:[EQU $QUEST16 5]
+F:Z:176:3:0:0:0:0:0:0
+
+?:1
+
+############### Quest 24 - Haunted House finished = house ###############
+?:[EQU $QUEST24 2]
+F:w:74:3:0:0:0:0:0:7
+?:[EQU $QUEST24 5]
+F:w:74:3:0:0:0:0:0:7
+?:1
+
+#################### Buildings ####################
+
+# Library
+F:a:74:3:0:0:0:0:0:60
+
+# Castle
+F:b:74:3:0:0:0:0:0:14
+
+# Casino
+F:d:74:3:0:0:0:0:0:15
+
+# Inn
+F:e:74:3:0:0:0:0:0:11
+
+# Beastmaster Shanty
+F:f:74:3:0:0:0:0:0:16
+
+# Fighters hall
+F:g:74:3:0:0:0:0:0:17
+
+# Tower of Magery
+F:h:74:3:0:0:0:0:0:18
+
+# Inner temple
+F:i:74:3:0:0:0:0:0:19
+
+# Paladin guild
+F:j:74:3:0:0:0:0:0:20
+
+# Ranger guild
+F:k:74:3:0:0:0:0:0:21
+
+# Thunderlord's Hide
+F:l:74:3:0:0:0:0:0:22
+
+# Castle: Plot Minas Anor
+F:B:75:3:0:0:0:0:0:5
+
+# Library Quest
+F:x:63:3
+
+?:[EQU $QUEST"Library quest" 1]
+F:x:8:3:0:0:0:0:0:"Library quest"
+?:1
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:#^^########------------------ @@@@@@@ @@@@@@@@@ #
+D:#^^^------############---------- ^ @@VVVVV@@ @@VVVVVVV@@@@@@@ ,,, #
+D:#^^^----------###----#######------- ^^^^^ @VVVVVVV@@@@@ @@VV@@@@@@VVVVVV@@@@ ,, #
+D:#^^----ssss-----###--------####------ ^^^^^^ @VVVVVV@@VVV@@@ @VV@@ @@@@@@VVVV@@ ,, #
+D:#^^^---StSS-------###--#ssss--###------- ^^^^^^^^ @@VVVVVVVV@VVV@@@@@@@@ @@@V@@ @@@@VV@@@@ , #
+D:#^^----ssss----OO---##--#StSS---####------ ^^^^^^^^ @@V@V,@@@@@@VVVVVVVV@@@VVV@ @@VVVV@@ ,, #
+D:#^^----x#a#-----OOO--##--#sssss----###------ ^^^^^^^^ @@@@@ @@@@@@@@VVVVV@@@ @@@@VV@@@ ,,, #
+D:#^ ---------------OO--###-##d##------###----- ^^^^^^^^^^ @VVV@@ @@VVV@@ ,O, #
+D:#^ StSSSS-----ss---OO---##-----OOOOO---###---- ^^^^^^^^^^^ @@@ @@VVV@@ OO #
+D:#^^ssssss----Ssss---OOO--##---OOOOOOOO---##---- ^l^^^^^^^ @@VVV@ OO #
+D:#^ ####9#---sstSss---OOO--##-OOOOOOOOOOO--##---- ^^^^^ @@VVV@@ OO #
+D:#^^^-------##sssSss---OOO--#OOO--s--OOOOO--###--- @@@@@@@@@@ @@VVV@@ OO #
+D:#^^^######---##ssh--s--OOO-OOO--StS--OOOOO---##--- @@VVVVVVVV@@@@@@@V@@@@ OO #
+D:#^^^^----###---##--ssS--OOOOO#--ssss--OOOOOO--##--- @VVVVVVVVVVVV@@VV@@ OOO OO #
+D:#^^--------###----ssSs#--OOO-##-#####--OOOOOO--##--- ---- @VVVV@@@@VVVVVVV@@ OOOOO OOOOO #
+D:#^ ----------##--#stsi--OOOO--#---------OOOOOO--#------ -------- @@VVV@@ @@VVV@@@@ OO OO OO #
+D:#^^-----------###-#s#--OOOOOO-##-#sssss--OOOOOO,#####--- ----------- @@VVV@@ @@@@@ OO- OOOOOOOOO #
+D:#^^-------------##-#--OOO-OOO--#--ssssss--OOOOO,,,,,#---- ---ssssssss--- @VVV@@ -OO #
+D:#^^--------------#---OOO-t-OOO-##-#SStSS--OOOOOO,##,#---------ssssssss---- @VV@@ --OO- #
+D:#^^^--#----------##-OOO-sssOOO--#--ssssss-OOOOOO--#,#####-----SStSSSSS----- @@VV@ --OO- #
+D:#^^^--#-----------#OOO-##4##OOO-##-ssssss--OOOOOO-#,,######---ssssssss--O--- @@VVV@ -OO-- #
+D:#^^--###----------OOO-------OOO--#-####2#--OOOOOO-##,#k#,,##--ssssssss--O---- @VVV@@ --O-- #
+D:#^^^-###---------OOO#--SSStS-OOO-#---------OOOOO---#,,,,,,,#--ssssssss--O----- @@VV@@ --OO- #
+D:#^^-#####-------OOO-#--sssss-OOO-#--ssss--OOOOO--T-#,-----,#--#####7##--O------ @VVV@ --OO-- #
+D:#^^#######------OOO-##-###j#-OOO-##-ssss--OOOOO-TT-#------,#-------,,,,,O------ @@VV@@ --OO-- #
+D:#^^^########----OOO--#-------OOO--#-StSS--OOOOO-TT-#-----,,#------------O------- @VVV@@ --OO-- #
+D:#^^############-OOO--##-StSSS-OOO-#-ssss--OOOOO--T-#----,,##---ssssssss-O-------- @@VV@@ --OOO-- #
+D:#^^^#########---OOO---#-sssss-OOO-#-ssss--OOOOOO---#,,,,,##----SSSSStSS-O--------- @@@VVV@ --OOO-- #
+D:#^^#####B###----OOO---#-###6#-OOO-#-##g#---OOOOOO--#######-----ssssssss-O---------- @VVVV@@ ---OOO-- #
+D:#^^^#######-----OOO---#-------OOO-#---------OOOOOOOOOOOOOOOOO--###e####-O----------- @@VVV@@ ------OO-- #
+D:#^^#######bOOOOOOOO-^^^^^^^^^^MMM^^^^^^^^^^^^OOOOOOOOOOOOOOOOOOOOOOOOOOOO----------- @@@VVV@@ ---OOOOOO-- #
+D:#^^#######bOOOOOOO############III############^OOOOOOOOOOOOOOOOOOOOOOOOOOOOO--------- @@VVVV@@ ---OOOOOO-- #
+D:#^ #######bOOOOOOO############III############^OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO--------- @VVVV@@ ----OOOOOO---- #
+D:#^ #######bOOOOOOOO-^^^^^^^^^^MMM^^^^^^^^^^^^OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO------- @VVV@@ ------OOOO------ #
+D:#^^^######Z-----OOO---#-sSss--OOO-#---------OOOOOOOOOOOOOOOOO-----------OOOOOOO------ ---------##@VVV@## --------OOOOO----- #
+D:#^^#########----OOO---#-sSss--OOO-#-sssss--OOOOOO--#######--------sssss-O-OOOOO----- --OOOO-----#######--------OOOOOO----- #
+D:#^^##########---OOO---#-stss--OOO-#-SStSS-OOOOOO---####,,##-------SStSS-O-OOOOO---- --OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO----- #
+D:#^^############-OOO--##-sSss--OOO-#-sssss-OOOOO--T-##k#,,,##------sssss-O--OOOOO--- --OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO----- #
+D:#^^#########----OOO--#--####-OOO--#-sssss-OOOOO-TT-#,,,,-,,#------sssss-O---OOOO--- --OOOOO-OOOOOOOOOOOOOOOOOOOOOOO------- #
+D:#^^#######------OOO-##-------OOO-##-###3#-OOOOO-TT-#,-----,#------###0#-O---OOOOO--- --OOOO---------#######--------------- #
+D:#^^-#####-------OOO-#--Ssss--OOO-#--------OOOOO--T-#,-----,#------------O----OOOO---- --OOOO---------##@VVV@##----------- #
+D:#^^^-###---------OOO#-#stss--OOO-#-ssssss--OOOOO---#,----,,#----ssssss--O-----OOOO---- ---OOOO--- @VVV@@ #
+D:#^^--###----------OOO--#sSs-OOO--#-StSSSS--OOOOOO-##,-,,,,##----SStSSS--O------OOOO---- --OOOOO---- @VVV@@ #
+D:#^^---#-----------#OOO--###-OOO-##-ssssss--OOOOOO-#,,,,####-----ssssss--O-------OOOO---- --OOOOO---- @VVVV@ #
+D:#^^^--#----------##-OOO----OOO--#--###5##-OOOOOO--#,#####-------ssssss-OO--------OOOO--------OOOOO---- @@VVV@@@ @@@@ #
+D:#^^^-------------#---OOO---OOO-##---------OOOOOO,##,#-----------####1#-O----------OOOO----OOOOOO----- @@VVVV@@@ @@@@@@ #
+D:#^^-------------##----OOO-OOO--#--ss------OOOOO,,,,,#------------------O-----------OOOOOOOOOOO----- @@@VVVV@@ @@@@@@@@@V@@@ #
+D:#^^^----------###--ss--OOOOOO-##-ssSs----OOOOOO,#####------------------O-------- ---OOOOOOOOO--- @@VVVV@@ @@@@@ @@@@@@@@@@@@@ #
+D:#^^^---------##---ssSs--OOOO--#--ssts#--OOOOOO--#------ ------ssssss--OO------ ---OOOOO----- @@VVVV@@@ @@@VVV@@@ @@@V@@@@@@@@ #
+D:#^^--------###---sstss#--OOO-##-ssSs#--OOOOOO--##----- ----StSSSS--O------ ----------- @@@VVVV@@@@@ @@@@VVVVVVV@@ @@@@@V@@V@@@V@@ #
+D:#^^------###-----#Sss#--OOOOO#--sSsf--OOOOOO--##----- ---ssssss--O----- ------- @@@VVVVVV@@@@@@@@@@@VVVVV@@@VVV@@@@@VVVV@@@@ @@@@ #
+D:#^^^######---ss---#s#--OOO-OOO--Ss#--OOOOO---##----- --###w##-OO----- @@VVVVVVVVVVVVVVVVV@@@@@ @@@VVVVVVV@@@@ #
+D:#^^^-------ssssS---#--OOO--#OOO--#--OOOOO--###----- --------O----- @@@@@@@@@@@@@@@@@@@ @@@@@@@@@ #
+D:#^^-sssss-#ssstss----OOO--##-OOO---OOOOO--##------ ------OO---- #
+D:#^^-SSStS--#sSsss#--OOO--##---OOOOOOOO---##------ ----O---- #
+D:#^^-sssss---#ss##--OO---##--X--OOOOO---###------ ---O--- #
+D:#^^^#####----##---OO--###--XXX-OOO---###------ --- #
+D:#^^^------------OOO--##---XXX#-----###----- #
+D:#^^--SStSS-----OO---##--XX###---####----- #
+D:#^^^-sssss--------###--###----###------ #
+D:#^^--#####------###--------####------ #
+D:#^^^----------###----#######------ #
+D:#^^^------############---------- #
+D:#^^########----------------- #
+D:######################################################################################################################################################################################################
diff --git a/lib/mods/theme/edit/t_osgili.txt b/lib/mods/theme/edit/t_osgili.txt
new file mode 100644
index 00000000..ea74d660
--- /dev/null
+++ b/lib/mods/theme/edit/t_osgili.txt
@@ -0,0 +1,136 @@
+# File: t_osgili.txt
+
+# Osgiliath map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain features ###
+
+#Anduin river
+F:a:227:3
+
+#Small tree
+F:b:202:3
+
+#Wooden board
+F:c:235:3
+
+#light post
+F:d:221:3
+
+# Altars
+F:k:161:3
+F:l:162:3
+F:m:163:3
+F:n:165:3
+F:w:166:3
+F:x:167:3
+F:y:168:3
+F:z:169:3
+
+### Buildings ###
+
+# The Twinkling Star inn
+F:e:74:3:0:0:0:0:0:68
+
+# The Castle of Stars
+F:f:74:3:0:0:0:0:0:85
+
+# Map store
+F:g:74:3:0:0:0:0:0:66
+
+# Museum
+F:h:74:3:0:0:0:0:0:57
+
+# Soothsayer
+F:i:74:3:0:0:0:0:0:12
+
+# Library
+F:j:74:3:0:0:0:0:0:13
+
+# Casino
+F:o:74:3:0:0:0:0:0:15
+
+# Fighters Hall
+F:p:74:3:0:0:0:0:0:17
+
+# Tower of Magery
+F:q:74:3:0:0:0:0:0:18
+
+# Inner Temple
+F:r:74:3:0:0:0:0:0:19
+
+# Paladins Guild
+F:u:74:3:0:0:0:0:0:20
+
+# Rangers Guild
+F:v:74:3:0:0:0:0:0:21
+
+D:######################################################################################################################################################################################################
+D:#---------------------------------------------------------#################@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##########################---------------------------------------------------------#
+D:#OOOOOOOOOOOOOOOOOOOOOOOOOOOO-------------------------######,,,,,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@,,,,,,,,,,,,,,,,,,,,,,,,####-------------------------OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#
+D:#---------------------------OO--------------------#####,,,,,,,########,,,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,#####,,,#####,,,#####,,######---------------------OOO----------------------------#
+D:#----------------------------OO-----------------####,,,,,,,,,O7#######,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@,,#####OOO#####OOO#####O,,,,,#####-----------------OOO-----------------------------#
+D:#-----------------------------OO--------------####,,,,,,,,,,OO########,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,#####,,,#####,,,#####,O,,,,,,,#####-------------OOO------------------------------#
+D:#------------------------------OO----------####,,,,########O,O,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,O,,,,,,,O,,,,,,,O,,,,OOOOO,,,,,####----------OOO-------------------------------#
+D:#-------------------------------OO-------####,,,,,Og#######O,O,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,OOOO,,,,OOOO,,,,OOOO,,,,,OOOO,,,####------OOO---------------------------------#
+D:#--------------------------------OO---####,,,,,,,O,########,,O,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,#####,,,#####,,,#####,,,,#####,,,####---OOO----------------------------------#
+D:#---------------------------------OO###,,,,,,,,,,,OO,,,,,,,,,O########,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@,,,,#####OOO#####OOO#####OOO,#####,,,,#####OOO-----------------------------------#
+D:#---------------------------------#OOd,,,,,,########O,,,,,,,,O3#######,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@,#####,,,#####,,,#####,,,,#####,,,,,,,#OOO------------------------------------#
+D:#--------------------------------##dOOb,,,,,#######2O,,,,,,,,O########,,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,O,,,,,,,O,,,,,,,O,,,,,,,,O,,,,,,,,dOOd###----------------------------------#
+D:#-------------------------------###,bOOb,,,,########,O,,,,,,,O,,,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,OOO,,,,,OOOO,,,,O,,,,,,,O,,,,,,,dOOd--###---------------------------------#
+D:#------------------------------##,,,,bOOb,,,,,,,,,,,,,O,,,,T,,O,,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,#####,,,#####,,,T,,,,#####,,,,dOOd-----##--------------------------------#
+D:#-----------------------------##,,,,,,bOOb,,,,,,,,,,,,,O,,TTT,,O,########,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@,,#####OOO#####OOTTTOOO#####,,,dOOd-------##-------------------------------#
+D:#----------------------------##,,,,,#,,bOOb,,,,,########O,,T,,,,Oo#######,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,#####,,,#####,,,T,,,,#####,,dOOd---------##------------------------------#
+D:#---------------------------##,,,,,,#,,,bOOb,,,,#######5O,,,,,,,O########,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@,,,,O,,,,,,,O,,,,,,,,,,,,O,,,dOOd---TTTTT---##-----------------------------#
+D:#--------------------------##,,,,,,###,,,bOOb,,,########,O,,,,,,O,,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@,,,,O,,,,,,,O,,,,,,OOOOO,,,dOOd---TTTTTTT---##----------------------------#
+D:#-------------------------##,,,,,,,###,,,,bOOb,,,,,,,,,,,,O,,,,,O,,,,,,,,,,,,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,#####,,,#####,,#####,,,,dOOd-----TTTTT-----##---------------------------#
+D:#------------------------##,,,,,,,#####,,,,bOOb,,,,,,,,,,,,OOO,,,O,########,,,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,#####OOO#####,,#####,,,dOOd-----------------##--------------------------#
+D:#-----------------------##,,,,,,,,#####,,,,,bOOb,,,,,,########O,,,O0#######,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,#####,,,#####,,#####,,dOOdOOOOOOOOOOOOOOOOOOO##-------------------------#
+D:#----------------------##,,,,,,###########,,,bOOb,,,,,#######6O,,,O########,,,,,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,O,,,,,,,O,,,,,,O,,,dOOd-O.###..#####..###.O-##------------------------#
+D:#----------------------##,,,,,,###########,,,,bOOb,,,,########,O,O,,,,,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,OO,,,,,,,,,OOOOOO,,,dOOd--O.###..#####..###.O-##------------------------#
+D:#----------------------##,,,#################,,bOOb,,,,,,,,,,,,,OOO,,,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,#####,,,,,,,#####,,,,dOOd-F-O.###############.O--##-----------------------#
+D:#---------------------##,,,,#################,,,bOOb,,,,,,,#######9O,,,,,,,,,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@,,#####OOOOOOO#####,,,dOOd-FF-O.###############.O--##-----------------------#
+D:#---------------------##,,,,########q########,,,,bOOb,,,,,,########O,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,#####,,,,,,,#####,,dOOd-FFF-O..#############..O--##-----------------------#
+D:#---------------------##,,,,,,,,,,,,,,,,,,,,,,,,,,bOOb,,,,,########,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@,,,,,,,,,,,,,,,,,,,,,dOOd-FFFF-O..#############..O---##----------------------#
+D:#--------------------################,,,,,,,,,,,,,,dOOd,,,,,,,,,,,,,,,,,,,,d##@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,##d,,,,,,,,,,,,,,,,,dOOd-FFFFF-O..#############..O---##----------------------#
+D:#--------------------##T-------------bbbbbbbbbbbbbbbbOObbbbbbbbbbbbbbbbbbbbbb############################################bbbbbbbbbbbbbbbbbbbOOd--------O..#############..O----##---------------------#
+D:#--------------------##TOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.###############.O----##---------------------#
+D:#--------------------##TOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.###############.O----##---------------------#
+D:#--------------------##TOOcccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbOObbb############################################bbbbbbbbbbbbbbbbbbbOOd--------O.f##############.O----##---------------------#
+D:#--------------------##TOOc--VVVVV--c,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,dOOd,d##@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@##d,,,,,,,,,,,,,,,,dOOdbbbbbbb-O.f##############.O----##---------------------#
+D:#--------------------##TOOc-VVdWdVV-c,,,######,,,,,,,,,,,,,,,,,T,,,,,bOOb,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,,,,,,,,,,,,,,dOOdbOOOOOb-O.f##############.O----##---------------------#
+D:#--------------------##TOOcVVVWWWVVVc,,,######,,,,,,,,,,,,,,,,TTT,,,bOOb,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,dAAAAAAAAAd,,,,dOOdbOVVVOb-O.###############.O----##---------------------#
+D:#--------------------##TOOc-VVdWdVVOc,,,######,,,,,,,,,,,,,,,,,T,,,bOOb,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,AAAAAAAAAAAAA,,,dOOdbOVVVbb-O.###############.O----##---------------------#
+D:#--------------------##TOOc--VVVVV-Oc,,,##h###,,,,,,,,######,,,,,,bOOb,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,dAAAAAAAAAd,,,,dOOdbOOOOOOOO..#############..O----##---------------------#
+D:#--------------------##TOOcccccccccO,,,,,,O,,,,,,,,,,,######,,,,,bOOb,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,,,,,,,,,,,,,,,,dOOdbbbbbbb-O..#############..O----##---------------------#
+D:#--------------------##TOOOOOOOOOOOO,,,,,,O,,,,,TT,,,,######,,,,bOOb##########,,,@aaaaaaaaaaaaaaaaaaaaaaaa###########dbbbbbbbbbbbbbbbbbbbbbbOO---------O..#############..O---##----------------------#
+D:#--------------------################,,,,,,O,,,TTTT,,,##pp##,,,bOOb,##########,,,@aaaaaaaaaaaaaaaa@@######OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO..#############..O---##----------------------#
+D:#---------------------##,,,,,,,,,,,,,,######O,,,TT,,,,,,O,,,,,bOOb,,##########,,,@aaaaaaaaaaaa######OOOOOO###########dbbbbbbbbbbbbbbbbbbbbbbbOO--------O.###############.O---##----------------------#
+D:#---------------------##,,,,,,,,,,,,,,######,O,,,,,,,,,O,,,,,bOOb,,,##1####e##,,@aaaaaaa######OOOOOO#######aaaaaaaa@,,,,,,,,,,,,,,,,,,,,,,,,,dOOdFFFFF-O.###############.O--##-----------------------#
+D:#----------------------##,,,######,,,,######,,O,,######O,,,,bOOb,,,,,,O,,,,O,,,d########OOOOOO#######aaaaaaaaaaaaaa@,,,,,,,dRRRRRRRRRRRd,,,,,,dOOdFFFF-O.###..#####..###.O--##-----------------------#
+D:#----------------------##,,,######,,,,##jj##,,,O,######O,,,bOOOOOOOOOOOOOOOOOOOOOOOOOOOO#######aaaaaaaaaaaaaaaaaaaa@,,,,,,,RRRRRRRRRRRRR,,,,,,,dOOdFFF-O.###..#####..###.O-##------------------------#
+D:#-----------------------##,,######,,,,,,O,,,,,,,O######O,,bOOb,,,,,,,,,,,,,,,,,d#########aaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,,dRRRRRRRRRRRd,,,,,,,,dOOdFF-OOOOOOOOOOOOOOOOOOO##-------------------------#
+D:#------------------------##,##i###,,,,,,,O,,,,,,Or#####O,bOOb,,,,,,,,,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,dOOdF-O------------------##-------------------------#
+D:#------------------------##,,,O,,,,,,,,,,O,,,,,,,OOOOOOObOOdbbbbbbbbbbbbbbbbbbd####################################dbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbOOd-O------TTTTT------##--------------------------#
+D:#-------------------------##,,,O,,,,,,,,,O,,,,,,,,O,,,,bOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO-----TTTTTTT----###--------------------------#
+D:#--------------------------##,,,,O######,O,######O,,,,bOOdbbObbbbbbbbbbbbbbbbbd####################################dbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbOO------TTTTT-----##---------------------------#
+D:#---------------------------##,,,O######,O,######O,,,bOOb,,bOb,,,,,,,,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,dOOd-------------##----------------------------#
+D:#----------------------------##,,O######,O,######O,,bOOb,,,bOb,,,,,,,,,,,,,,@@@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@,,,#####,,,,,,,,,,,,,,,,,,,,#####,,,dOOd-----------##-----------------------------#
+D:#-----------------------------##,O##u###,O,##v###O,bOOb####bOb####,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,#####OOOOOOOOOOOOOOOOOOOO#####,,,,dOOd--------###------------------------------#
+D:#------------------------------##,OOO,,,,O,,,OOOO,bOOb,#k,,dOd,,m#,,,,,,,,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@,,#####,,,,,,,,,,,,,,,,,,,,#####,,,,,dOOd------##--------------------------------#
+D:#-------------------------------##,,,OOOOOOOO,,,,bOOb,,#,,#NON#,,#,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,O,,,,,,,,,,,,,,,,,,,,,,,,OOOO,,,,,dOOd----##---------------------------------#
+D:#--------------------------------###,,,,,,,T,,,,bOOb,,,#,,#NON#,,#,,,,,,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,#####,,,,,,,,d,,,,,,,,,,,,,,#####,,,,dOO-d###----------------------------------#
+D:#----------------------------------###,,,,TTT,,bOOb,####,##NON##,####,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,#####,,,,,,,,,,,,,,,OOOOOOOO#####,,,,,dOOOOO-----------------------------------#
+D:#------------------------------------###,,,T,,bOOb,,#y,,,#-NON-#,,,z#,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@,,,#####,,,,,,,,,,,,,,O,#####,,#####,,,,,####OOOOO--------------------------------#
+D:#--------------------------------------###,,,bOOb,,,#w,,,#-NON-#,,,x#,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,,,O,,,,,,,,,,OOOOOO,,#####,,,,,,,,,####-----OOOOO------------------------------#
+D:#----------------------------------------###dOOb,,,,####,##NON##,####@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,#####,,,,,,,O,#####,,#####,,,,,,,####---------OOOOO----------------------------#
+D:#------------------------------------------OOOd,,,,,,,,#,,#N4N#,,#,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,,#####,,OOOOO,,#####,,,,,,,,,,,,####-------------OOOOO--------------------------#
+D:#-----------------------------------------OOO###,,,,,,,#,,#####,,#,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,#####,O#####,,#####,,,,,,,,,####-------------------OOOO------------------------#
+D:#----------------------------------------OOO---###,,,,,#l,,,,,,,n#,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@,,,,,,,,,O,,O,#####,,,,,,,,,,,,,#####------------------------OOOO---------------------#
+D:#---------------------------------------OOO------###,,,###########,,@@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@@,,,,,,,,,,,,,O,,,#####,,,,,,,,,,####-------------------------------OOOO------------------#
+D:#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO--------###,,,,,,,,,,,,,,@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@,,,,,,,,,,,,,,,,,,,,,,,,,,,######-------------------------------------OOOOOOOOOOOOOOOOOOOO#
+D:#--------------------------------------------------###############@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##############################------------------------------------------------------------#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_pelar.txt b/lib/mods/theme/edit/t_pelar.txt
new file mode 100644
index 00000000..0057518b
--- /dev/null
+++ b/lib/mods/theme/edit/t_pelar.txt
@@ -0,0 +1,105 @@
+# File: t_pelar.txt
+
+# Pelargir map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+### Additional terrain features ###
+
+#Anduin river
+F:a:227:3
+
+### Buildings ###
+
+# The Grey Swan inn
+F:b:74:3:0:0:0:0:0:68
+
+# The Prince's Tower
+F:c:74:3:0:0:0:0:0:86
+
+# Music store
+F:d:74:3:0:0:0:0:0:64
+
+# Rune Shop
+F:e:74:3:0:0:0:0:0:62
+
+# Hunting Store
+F:f:74:3:0:0:0:0:0:61
+
+# Library
+F:i:74:3:0:0:0:0:0:13
+
+# Casino
+F:j:74:3:0:0:0:0:0:15
+
+# Beastmaster
+F:k:74:3:0:0:0:0:0:16
+
+D:######################################################################################################################################################################################################
+D:#-------------------------------------------------@VVVVV@##VVVVV@@-----------------------------------------------------------------------------------------------------------------------------------# #
+D:#-------------------------------------------------@VVVVV@####VVVVV@----------------------------------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@######VVVV@@@-------------------------------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,###VVVVV@@-----------------------------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,####VVVVV@@---------------------------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,,,####VVVVV@@@------------------------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,,,,,#####VVVVV@@@---------------------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,####,,,,#####VVVVV@@-------------------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,####,,,,,,#####VVVVV@@@----------------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,###7,,,,,,,,,#####VVVVV@@@-------------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,,,,,,TTTT,,,,,,#####VVVVV@@@----------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,,,TTTT,TTTT,,,,,,,#####VVVVV@@@-------------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,,TTTT,,,TTTT,,,,,,,,,#####VVVVV@@@----------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,TTTT,,,,,,,,,,,,,,,,,,,,#####VVVVV@@@@------------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,TTTT,,,,###,,,,,,#######,,,,,#####VVVVV@@----------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,,,,,,,,####,,,,,#######,,,,,,,#####VVVVV@@@-------------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,,,,,,,,,####,,,,###2###,,,,,,OOOO#####VVVVV@@@----------------------------------------------------------------------------------------#
+D:#-------------------------------------------------@VVVVV@####,,,,,,,,,,,####,,,,,,,O,,,,,OOOO,,,,,,##VVVVVVVV@@@-----------------------------------------------------------------------------------aa#
+D:#-------------------------------------------------@VVVVV@####,,,,,,,,,,,,####,,,,,,,O,OOOO,,,,,,,,,#VVVV###VVVVV@@@@----------------------------------------------------------------------------aaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#######,,,,#######,,OOOO,,,,,,,,,,,#VVVV#@@#####VVVVV@@------------------------------------------------------------------------aaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#######,,,,##4##OOOOO,,,,TTT,,,,,,#VVVV#,,,,,#####VVVVV@@@-----------------------------------------------------------------aaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#######,,,,###OOO.,,,,,,TTTTT,,,,#VVVV#,,,,,,,,,#####VVVVV@@@-----------------------------------------------------------aaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,###3###,,,,#OOO##.###,,,,TTT,,,,#VVVV#,,,,####,,,,,#####VVVVV@@@-----------------------------------------------------aaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,,O,,,,,,,OOOO##...####,,,,,,,#VVVV#O,,,,####,,,,,,,,#####VVVVV@@@@-----------------------------------------------aaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,,,O,,,OOOO,,,##......####,,,#VVVV#,,O,,,5###,,,,,,,,,O,#####VVVVV@@------------------------------------------aaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,,,,OOOO,,,,,,##.........####VVVV#,,,,OOOO,,,,,,,,,,,,,O,,,#####VVVVV@@@------------------------------------aaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,OOOO,,,TTT,,,##................#,,,,,,,,OOOO,,,,,,,,,,OOOOOOO#####VVVVV@@@------------------------------aaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,OOOO,,,,,TTTTT,.##...............####,,,,,,,,,OOO,,,,,,,,O,,,,,,,,,#####VVVVV@@@-----------------------aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------OOOOOOOOOOOOO,,,,,,,,,TTT,,,##..................####,,,,,,O,,OOO,,,,,O,,,,,,,,,,,,#####VVVVV@@@----------------aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,,,,,,,,,,,,,,##......,#cc#..........####,,,O,,,,,O,###d###,,,,,,,,,,,,#####VVVVV@@@---------aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@#######################.....########...........####O,,,,,,O#######,,,,,,,,,,,,,,,#####VVVVV@-----aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------OVVVVVVVVVVVVVVVVVVVVVVVVVVV......c########c.............####,,#############,,,,,,,#####,,,#####VVVVV@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------OVVVVVVVVVVVVVVVVVVVVVVVVVVV.......########................OOOO6###########9OOOOOOOOO#,,,,,,,,#####VVV@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVVVVVVVVVVVVVVVVVVVVVVVV.........#cc#...............#####,O#############O,,,,,,#####,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@#######################.......................####,,,,,,O,,#######,OO,,,,,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,,,,,,,,,OOOOO##....................#####,,,,,,,,,O,###e###O,,,,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#####,,,,O,,,,,##..................###,,,,,,,,,,,,,,OOOOOOOO,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,####bOO,O,,,,,,##.................###,,,,,#######,,,,,,,,,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#####,,O,,####,##................aaa##,,,,#######,,,,,,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,O,,,,OOO1###,##.........####aaaaaaa##,,,#######,,,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,O,,,,O,,####,##.....#####,,##aaaaaaa##,,,,,,,,,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,##f##,,,O,,,,,,##..####,,,,,,,##aaaaaaa##,,,,,,,,,,,,,######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#####,,,,O,,,,,##O###,,,,,,,,,,##aaaaaaa##,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#####,,,,,O,,,,#O###,,,,,,,,,,,,##aaaaaaa##,,,######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,O,,,,,,,,O,,,OO,,,,,#######,,,,##aaaaaaa#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,O,,,,,.,,OOOO,O,,,,,#######,,,,,##aaaaaaa##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,##k##,,,,,O##j##,O,,,,#######,,,,,,##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#####,,,,O,#####,,O,,,#######,,,,,,###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#####,,,O,,#####,,,O,,,,,,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,O,,,,O,,,,,,,,,,,,O,,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,O,,,O,,,,,,,,,,,,,,O,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,##i##,OOO0####,,,,,,,,O,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#####,O,,#####,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,#####,O,,#####,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,O,,,,O,,,,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,###,,,O,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,###,,,O,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,,,,,O#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####,,,#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@##########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:#-------------------------------------------------@VVVVV@##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_pref.txt b/lib/mods/theme/edit/t_pref.txt
new file mode 100644
index 00000000..1159e817
--- /dev/null
+++ b/lib/mods/theme/edit/t_pref.txt
@@ -0,0 +1,145 @@
+# File: t_pref.txt
+
+# Defines the preferences for the town features
+# letter:feature:cave_info:monster:object:ego:artifact:trap:special
+
+# Barrow-Downs entrance
+F:{:7:3:0:0:0:0:0:4
+
+# Mirkwood Forest entrance
+F:~:7:3:0:0:0:0:0:1
+
+# Land of Mordor entrance
+F:|:7:3:0:0:0:0:0:2
+
+# Angband Dungeon entrance
+F:>:7:3:0:0:0:0:0:3
+
+# Mountain chain
+F:^:97:3
+
+# Floor
+F:.:1:3
+
+# Trees
+F:T:96:3
+
+# Deep water
+F:W:187:3
+
+# Shallow water
+F:V:84:3
+
+# Deep Lava
+F:L:85:3
+
+# Shallow Lava
+F:K:86:3
+
+# Chasm
+F:C:87:3
+
+# Dirt
+F:,:88:3
+
+# Mud
+F:@:94:3
+
+# Rubble
+F:;:49:3
+
+# Grass
+F:-:89:3
+
+# Permanent wall
+F:#:63:3
+
+# Brick Roof
+F:s:193:3
+# Brick Roof Top
+F:S:194:3
+# Brick Roof Chimney
+F:t:195:3
+
+# Grass Roof
+F:X:190:3
+# Grass Roof Top
+F:U:191:3
+# Grass Roof Chimney
+F:Y:192:3
+
+# Cobblestone Road
+F:O:200:3
+
+# General Store
+F:1:74:3:0:0:0:0:0:0
+
+# Armoury
+F:2:74:3:0:0:0:0:0:1
+
+# Weapons Smith
+F:3:74:3:0:0:0:0:0:2
+
+# Temple
+F:4:74:3:0:0:0:0:0:3
+
+# Alchemy Shop
+F:5:74:3:0:0:0:0:0:4
+
+# Magic Shop
+F:6:74:3:0:0:0:0:0:5
+
+# Black Market
+F:7:74:3:0:0:0:0:0:6
+
+# Home
+F:8:74:3:0:0:0:0:0:7
+
+# Bookstore
+F:9:74:3:0:0:0:0:0:8
+
+# Pet Shop
+F:0:74:3:0:0:0:0:0:9
+
+# Underground Tunnels -- used for tunnels in towns
+F:I:173:3
+
+# Underground Tunnels -- used for tunnels in towns
+F:M:204:3
+
+# Fake blank feature
+F: :0:3
+
+### Flowers for Theme ###
+
+#Elanor (yellow)
+F:E:79:3
+
+#Fumellar (red)
+F:F:80:3
+
+#Anemones (purple)
+F:A:81:3
+
+#Niphredil (white)
+F:N:82:3
+
+#Iris (blue)
+F:R:83:3
+
+### Destroyed town features ###
+
+# Dead/burnt tree
+F:D:92:3
+
+# Ash
+F:H:93:3
+
+# Fire
+F:=:205:3
+
+# Permanent rubble
+F:$:206:3
+
+# Tainted water
+F:%:174:3 \ No newline at end of file
diff --git a/lib/mods/theme/edit/t_thrand.txt b/lib/mods/theme/edit/t_thrand.txt
new file mode 100644
index 00000000..cce9d684
--- /dev/null
+++ b/lib/mods/theme/edit/t_thrand.txt
@@ -0,0 +1,103 @@
+# File: t_thrand.txt
+
+# Thranduil's Halls map by furiosity <furiosity@zionmainframe.net>
+# NB! The additional terrain features and stores (if any) assume usage of the following files from the 'theme' module:
+# f_info.txt, t_pref.txt, st_info.txt, and ba_info.txt
+# Please download the module and refer to the files for the terrain feature definitions http://modules.t-o-m-e.net/
+# Don't forget to modify the maximum number of terrain features, etc. in misc.txt as well.
+
+#Wooden board - horizontal
+F:a:233:3
+
+#Mallorn
+F:m:243:3
+
+#Force Elven monsters
+f:ELVEN
+
+### Buildings ###
+
+# Thranduil's Hall
+F:b:74:3:0:0:0:0:0:81
+
+# Beastmaster
+F:d:74:3:0:0:0:0:0:16
+
+# Hunter
+F:e:74:3:0:0:0:0:0:61
+
+# Music Store
+F:f:74:3:0:0:0:0:0:64
+
+# Map store
+F:g:74:3:0:0:0:0:0:66
+
+#The Library
+F:h:74:3:0:0:0:0:0:13
+
+D:######################################################################################################################################################################################################
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@@@@@@@@^^^^^^^^^^^^^^^^^^^^^@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@,,,,,,,,@^^^^^^^^^^^^^^^^^^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@,,,,,,,,@^^^^^^^^^^^^^^^^^^^@,,,,,,,,,,,,,,A,,,,,,,,,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@,,,3,,,,@^^^^^^^^^^^^^^^^^^^@,,,,TTT,,,,,A,b,A,,,,,,TTT,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,,,,@^^^^^^^^^^^^^^^^^^^@,,,TTmTT,,,,,F,F,,,,,,TTmTT,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,,,,,,,,@^^^^^^^^^^^^^^^^^^^@,,,,TTT,,,,,,R,R,,,,,,,TTT,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^,,,,,,^^^@@@@@@@,,,^^^^^^^^^^^^^^^^^^@,,,,,,,NE,,,,F,F,,,,,EN,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^,,,,,,,^^^^^^^^^^^^^^^^,,^^^^^^^^^^^^^^^^^@,,,,,,,,NE,,,R,R,,,,EN,,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^,,,,,,^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^@,,,,,,,,,NE,,F,F,,,EN,,,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^,,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^@@@@@@,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@^^^^^^^^^^^^^^^^@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^@,,,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^@,,@@@@@@@@@@@,@@@@@@@@@@@@@@@,^^^^^^^^^^^^@@@@,,,,,,,@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^@,,,,2,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^,,,^^^^^^^^^^^,^^^^^^^^^^^^^^^^,^^^^^^^^@@@,,,,,,,,,,,,,,,@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^@,,,,,,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^,,,,,,,,^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^,^^^^^^^@,,,,,,,,,,,,,,,,,,5@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,^^,,,,,,^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^,,,,,,,,,,,,,,,,,,,,,,,,,@@@^^^^^^^@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^^^^^^@@@@,,,,,,,@@@@,,^^^^@@@@@,,,,,,h@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@@@@@@@^^^^^^,,^^,,,,,,,,,,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,,,,,,,,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@@@@@4,,,,,,@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^,,^^^^^,,,,^^^^^^^^^^^^^^^^^^@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^,,,,^^^^^^^^^^^^^^^@9,,,,,,,6@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^^^@@@@@@^^,^^^^^^^^^^^^,,,,,,,,,,,,,,,,,,,,,,,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^@e,,,,,,,^^^^^^^^^^^^^^^^^,,^^^^^^^^^^^@@@@@@@@@^,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@@@@@@@^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#VVVVVV@@@@@@@@@@@@@@@@@@@,,,,,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,@@@@@^^^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#VVVVVVVVVVVVVVVVVVVVVVVVaaa,,,@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@,,,,d@@@@^^^^^^^^^^^^^^^,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#VVVVVVVVVVVVVVVVVVVVVaaa,,,,aaaVVVV@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@@@0,,,,,,,,,,,,,,,,,,,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#@@@@@@@@@@@@@@VVVVaaa,,,,aaaVVVVVVVVVVVVVV@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@@@@@@@^^^^^^^^^^^^^^,,,,,,^^^^^^^^^^^^^^@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @@@aaa,,,aaaVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,^^^^^^^^^^^@,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@aaa@@@@@@@VVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,^^^^^^^@,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@@@@VVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,,^^,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@VVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,,,,,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^,,,,,,,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@,,,,,f@^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@,,,,@^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@@@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@,,,,,@^^^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@g,,,,,@^^^^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@,,,,,@^^^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@@@@@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@@@@^^^^^^^^^^^^^^^^^^^^^^^^@,,,,,,@^^^^^^^^^^^^^^^^^#
+D:# @,,,,,@ @@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@^^^^^^^^^^^^^^^^^^^^@,,,,,,@^^^^^^^^^^^^^^^#
+D:#@,,,,,@ @@@@@@@@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@@^^^^^^^^^^^^^^^^^@,,,,,,@^^^^^^^^^^^#
+D:#,,,,,@ @@@@@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@^^^^^^^^^^^^^^^^@,,,,@^^^^^^^^^#
+D:#,,,,@ @@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@@^^^^^^^^^^^^,,,,MMM^^^^^^#
+D:#,,,@ @@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@^^^^^^^^^^^^III^^^^^#
+D:#,,@ @@@@@@@@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@^^^^^^^^III^^^^#
+D:#,@ @@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@^^^^^^III^^^#
+D:#@ @@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@@@@^^III^^#
+D:# @@@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVV@@@@MMM^#
+D:# @@@@@@@@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#
+D:###################################################################################################################################################################################################### \ No newline at end of file
diff --git a/lib/mods/theme/edit/thieves.map b/lib/mods/theme/edit/thieves.map
new file mode 100644
index 00000000..ba025ff6
--- /dev/null
+++ b/lib/mods/theme/edit/thieves.map
@@ -0,0 +1,64 @@
+# Floor
+F:.:1:6
+
+# Dark floor
+F:,:1:4
+
+# Permanent wall
+F:X:61:4
+
+# Lit permanent wall
+F:x:61:6
+
+# Magically locked door
+F:M:38:22
+
+# Locked door
+F:D:38:6
+
+# Open door
+F:d:4:6
+
+# up staircase
+F:<:6:8
+
+# Floor with Novice rogue
+F:a:1:6:44:0:0:0:0:0:0:2
+
+# Floor with Bandit
+F:b:1:6:150:43:*:0:0:0:0:2
+
+# Dark floor with novice rogue
+F:f:1:4:44:0:0:0:0:0:0:2
+
+# Floor with human skeleton
+F:z:1:6:0:395
+
+# Dungeon layout
+D:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+D:x.....x....zx.....x.............x
+D:x.....x.....x.....x.............x
+D:x.....x.....x.....x.............x
+D:xxxMxxxxxdxxxxxdxxxxxxxxxDxxxxxxx
+D:XXx..........................xXXX
+D:XXx.xxxxx.xxxxx.xxxxxxxxx.xx,xXXX
+D:XXxxxXXXxxxXXXxxxXXXXXXXxxx,,,XXX
+D:XXXXxxxxxxxxxxxxxxxxxXXXXX,,,,,XX
+D:XXXXxa..xb..x...x...xXXXX,,,,,,,X
+D:XXXXx...x...xa..x...xXXXX,,,,,,,X
+D:XXXXx..ax...x...x.a.xXXXX,,,,,,,X
+D:xxxxxxDxxxDxxxDxxxDxxXXXXX,,,,,XX
+D:x,,,x...............xXXXXXX,,,XXX
+D:x,,,x..x.........x..xXXXXXXX,XXXX
+D:x,,,D.....x...x.....D,,,,,,,,XXXX
+D:x,,,x..x.........x..xXXXXXXXXXXXX
+D:x,,,x...............xXXXXXXXXXXXX
+D:x,,,xxDxxxDxxxDxxxDxxXXXXXXXXXXXX
+D:x,,,x...x...x.a.xa..xXXXXXXXXXXXX
+D:x,,,xa.ax.a.x...x...xXXXXXXXXXXXX
+D:xf,fx...x...x...x...xXXXXXXXXXXXX
+D:xxxxxxxxxxxxxxxxxxxxxXXXXXXXXXXXX
+
+# Starting position
+P:4:4
+
diff --git a/lib/mods/theme/edit/thrain.map b/lib/mods/theme/edit/thrain.map
new file mode 100644
index 00000000..8adc41be
--- /dev/null
+++ b/lib/mods/theme/edit/thrain.map
@@ -0,0 +1,35 @@
+# Floor
+F:.:1:0:0:0:0:0:0:0:61
+
+# Some Nazguls
+F:1:1:0:951:0:0:0:0:0:61:2
+F:2:1:0:952:0:0:0:0:0:61:2
+F:o:1:0:866:0:0:0:0:0:61
+
+# Marker
+F:,:172:6:0:0:0:0:0:0:61
+
+# Lit permanent wall
+F:x:61:6
+
+# Door
+F:D:48:0:0:0:0:0:0:0:61
+
+# Floor with Trap
+F:t:1:8:0:0:0:0:*
+
+# Deep lava
+F:l:85:0:0:0:0:0:0:0:61
+
+# Dungeon layout
+D:
+D: xxxxxxxx
+D: xoooo..x
+D: xo2oo..x
+D: xlloo..x
+D: x,loo..D
+D: xlloo..x
+D: xo1oo..x
+D: xoooo..x
+D: xxxxxxxx
+D:
diff --git a/lib/mods/theme/edit/tr_info.txt b/lib/mods/theme/edit/tr_info.txt
new file mode 100644
index 00000000..d181487a
--- /dev/null
+++ b/lib/mods/theme/edit/tr_info.txt
@@ -0,0 +1,817 @@
+# This file comes from Angband64 written by Jurriaan Kalkman
+# and describes the traps items can have
+#
+# byte type; /* this goes into sval */
+# s16b probability; /* probability of existence in 1000 */
+# s16b another; /* does this trap easily combine in 1000 */
+# s16b pvalinc; /* how much does this trap attribute to pval */
+# byte difficulty; /* how difficult to disarm */
+# byte level; /* minimum level - disenchantment trap at 200' is */
+# /* not so nice */
+# byte color;
+# cptr name; /* what name does this trap have */
+#
+# d TERM_DARK |r TERM_RED |D TERM_L_DARK |R TERM_L_RED
+# w TERM_WHITE |g TERM_GREEN|W TERM_L_WHITE|G TERM_L_GREEN
+# s TERM_SLATE |b TERM_BLUE |v TERM_VIOLET |B TERM_L_BLUE
+# o TERM_ORANGE|u TERM_UMBER|y TERM_YELLOW |U TERM_L_UMBER
+#
+# b blue for stat traps
+# w white for teleport traps
+# o orange for dungeon rearrangement traps
+# v violet for summoning traps
+# y yellow for stealing/equipment traps
+# r red for other character affecting traps
+# g green for elemental bolt trap
+# B umber for elemental ball trap
+# R l red for arrow/dagger traps
+# W for compound trap!!!
+# don't use U or you'll get trapped doors that are indistinguishable from untrapped doors!
+#
+# an unknown character is multi-hued!
+#
+# N:type:name
+# I:diff:prob:another:pval:minlevel:damage:color
+# I:diff:prob: :minlevel: :color
+# D:description
+
+V:2.0.0
+
+#
+# stat traps
+#
+
+N:1:Weakness Trap
+I:2:100:5:5:2:0d0:b
+D:A poisoned needle weakens you!
+F:FLOOR | CHEST | DOOR
+
+N:2:Weakness Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle seriously weakens you!
+F:FLOOR | CHEST | DOOR
+
+N:3:Weakness Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle permanently weakens you!
+F:FLOOR | CHEST | DOOR
+
+N:4:Intelligence Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle makes you feel stupid!
+F:FLOOR | CHEST | DOOR
+
+N:5:Intelligence Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle makes you feel very stupid!
+F:FLOOR | CHEST | DOOR
+
+N:6:Intelligence Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle makes you feel permanently stupid!
+F:FLOOR | CHEST | DOOR
+
+N:7:Wisdom Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle makes you feel naive!
+F:FLOOR | CHEST | DOOR
+
+N:8:Wisdom Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle makes you feel very naive!
+F:FLOOR | CHEST | DOOR
+
+N:9:Wisdom Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle makes you feel permanently naive!
+F:FLOOR | CHEST | DOOR
+
+N:10:Fumbling Fingers Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle makes you feel clumsy!
+F:FLOOR | CHEST | DOOR
+
+N:11:Fumbling Fingers Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle makes you feel very clumsy!
+F:FLOOR | CHEST | DOOR
+
+N:12:Fumbling Fingers Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle makes you feel permanently clumsy!
+F:FLOOR | CHEST | DOOR
+
+N:13:Wasting Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle makes you feel sickly!
+F:FLOOR | CHEST | DOOR
+
+N:14:Wasting Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle makes you feel very sickly!
+F:FLOOR | CHEST | DOOR
+
+N:15:Wasting Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle makes you feel permanently sickly!
+F:FLOOR | CHEST | DOOR
+
+N:16:Beauty Trap
+I:2:100:5:2:2:0d0:b
+D:A poisoned needle scars you!
+F:FLOOR | CHEST | DOOR
+
+N:17:Beauty Trap
+I:5:100:5:5:20:0d0:b
+D:A poisoned needle scars you horribly!
+F:FLOOR | CHEST | DOOR
+
+N:18:Beauty Trap
+I:7:100:5:8:40:0d0:b
+D:A poisoned needle scars you permanently!
+F:FLOOR | CHEST | DOOR
+
+#
+# miscellaneous traps
+#
+
+N:20:Trap of Curse Weapon
+I:5:10:0:12:20:0d0:y
+D:Your weapon will never be the same...
+F:FLOOR | CHEST | DOOR
+
+N:21:Trap of Curse Armour
+I:5:15:0:12:20:0d0:y
+D:Your armour doesn't exactly get better by setting off this trap...
+F:FLOOR | CHEST | DOOR
+
+N:22:Earthquake Trap
+I:5:20:0:10:10:0d0:o
+D:The ceiling collapses around you!
+F:FLOOR | CHEST | DOOR
+
+N:23:Poison Needle Trap
+I:1:50:50:3:2:0d0:r
+D:A poisoned needle pricks you!
+F:FLOOR | CHEST | DOOR
+
+N:24:Summon Monster Trap
+I:2:50:40:4:2:0d0:v
+D:Monsters defend the memory of the owner...
+F:FLOOR | CHEST | DOOR
+
+N:25:Summon Undead Trap
+I:4:25:40:6:10:0d0:v
+D:Undead rise from the grave to defend this!
+F:FLOOR | CHEST | DOOR
+
+N:26:Summon Greater Undead Trap
+I:8:10:50:20:20:0d0:v
+D:Greater undead defend this!
+F:FLOOR | CHEST | DOOR
+
+N:27:Teleport Trap
+I:3:100:50:3:2:0d0:w
+D:Now you know why nobody ever got close enough to disarm this trap...
+F:FLOOR | CHEST | DOOR
+
+N:28:Paralysing Trap
+I:1:100:20:2:2:0d0:r
+D:You suddenly cannot move!
+F:FLOOR | CHEST | DOOR
+
+N:29:Explosive Device
+I:3:100:80:0:3:3d8:r
+D:Ha! It explodes before your hands can illegally touch it!
+F:FLOOR | CHEST | DOOR
+
+N:30:Teleport Item Trap
+I:3:50:50:3:5:0d0:w
+D:The item magically disappears from your greedy hands!
+F:FLOOR | CHEST
+
+N:31:Lose Memory Trap
+I:6:30:30:6:10:0d0:r
+D:You suddenly can't remember what you were doing here...
+F:FLOOR | CHEST | DOOR
+
+N:32:Bitter Regret Trap
+I:9:15:20:9:20:0d0:r
+D:You already regret trying this...
+F:FLOOR | CHEST | DOOR
+
+N:33:Bowel Cramps Trap
+I:1:90:20:1:6:0d0:r
+D:Your stomach twists with a sharp pang!
+F:FLOOR | CHEST | DOOR
+
+N:34:Blindness/Confusion Trap
+I:4:100:50:4:6:0d0:r
+D:You suddenly can't see, and thinking is difficult too....
+F:FLOOR | CHEST | DOOR
+
+N:35:Aggravation Trap
+I:2:100:50:2:3:0d0:o
+D:Your hear a high-pitched humming noise...
+F:FLOOR | CHEST | DOOR
+
+N:36:Multiplication Trap
+I:3:90:0:3:5:0d0:o
+D:The floor around you doesn't seem the same...
+F:FLOOR | CHEST | DOOR
+
+N:37:Steal Item Trap
+I:3:100:50:3:6:0d0:y
+D:The chest seems to swell, while your backpack feels lighter..
+F:FLOOR | CHEST
+
+N:38:Summon Fast Quylthulgs Trap
+I:8:50:10:10:25:0d0:v
+D:Parts of the owner seem to return from somewhere else, as you slow in awe.
+F:FLOOR | CHEST | DOOR
+
+N:39:Trap of Sinking
+I:2:50:0:0:3:0d0:w
+D:A trapdoor opens up under you!
+F:FLOOR | DOOR
+
+N:40:Trap of Mana Drain
+I:4:100:50:3:4:0d0:r
+D:You suddenly can't think so clearly any more...
+F:FLOOR | CHEST | DOOR
+
+N:41:Trap of Missing Money
+I:2:100:50:2:2:0d0:y
+D:Money isn't everything, they say...
+F:FLOOR | CHEST | DOOR
+
+N:42:Trap of No Return
+I:5:20:10:4:8:0d0:y
+D:Do stay a while!
+F:FLOOR | CHEST | DOOR
+
+N:43:Trap of Silent Switching
+I:4:100:50:3:6:0d0:y
+D:You suddenly are a different person!
+F:FLOOR | CHEST | DOOR
+
+N:44:Trap of Walls
+I:6:100:50:2:10:0d0:o
+D:The room seems to shrink!
+F:FLOOR | CHEST | DOOR
+
+N:45:Trap of Calling Out
+I:10:100:100:5:15:0d0:v
+D:You hear something coming closer, much closer.
+F:FLOOR | CHEST | DOOR
+
+N:46:Trap of Sliding
+I:8:50:50:4:8:0d0:r
+D:Your feet seem to have a life of their own!
+F:FLOOR | CHEST | DOOR
+
+N:47:Trap of Charges Drain
+I:6:100:70:2:3:0d0:y
+D:You feel as if you've just lost something...
+F:FLOOR | CHEST | DOOR
+
+N:48:Trap of Stair Movement
+I:6:100:50:3:4:0d0:o
+D:The dungeon seems different...
+F:FLOOR | CHEST | DOOR
+
+N:49:Trap of New Trap
+I:5:100:5:0:4:0d0:o
+D:Somehow, disarming isn't over, you feel...
+F:FLOOR | CHEST | DOOR
+
+N:50:Trap of Scatter Items
+I:10:50:50:6:12:0d0:w
+D:You hear crashing sounds from all over the dungeon!
+F:FLOOR | CHEST | DOOR
+
+N:51:Trap of Decay
+I:4:100:50:4:4:0d0:r
+D:Your stomach isn't empty, but suddenly you think of food.
+F:FLOOR | CHEST | DOOR
+
+N:52:Trap of Wasting Wands
+I:6:100:40:4:5:0d0:y
+D:Your wands seem different...
+F:FLOOR | CHEST | DOOR
+
+N:53:Trap of Filling
+I:10:100:0:10:25:0d0:o
+D:The whole room vibrates in a strange way...
+F:FLOOR | CHEST | DOOR
+
+N:54:Trap of Drain Speed
+I:8:50:10:25:80:0d0:y
+D:You suddenly seem to have more time to self-reflect...
+F:FLOOR | CHEST | DOOR
+
+#
+# bolt traps
+#
+
+N:60:Lightning Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:You are jolted with electricity!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:61:Poison Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:A blast of poison gas hits you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:62:Acid Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:A jet of acid shoots out at you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:63:Cold Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:You are suddenly very cold!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:64:Fire Bolt Trap
+I:2:80:5:3:2:2d8:g
+D:You are suddenly very hot!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:65:Plasma Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A bolt of plasma hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:66:Water Bolt Trap
+I:4:80:5:5:8:5d10:g
+D:A gush of water hits you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:67:Light Bolt Trap
+I:4:80:5:5:8:5d10:g
+D:There is a sudden flash of light around you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:68:Dark Bolt Trap
+I:4:80:5:5:8:5d10:g
+D:A bolt of pure elemental darkness hits you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:69:Shards Bolt Trap
+I:6:80:5:6:15:6d10:g
+D:A blast of crystal shards hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:70:Sound Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A sudden roar of sound hurts your eardrums!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:71:Confusion Bolt Trap
+I:4:80:5:5:8:6d10:g
+D:A blast of confusion gas engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:72:Force Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A bolt of pure force hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:73:Inertia Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:Your feet feel like lead!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:74:Mana Bolt Trap
+I:8:80:5:9:25:15d16:g
+D:A bolt of pure magic hits you!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:75:Ice Bolt Trap
+I:4:80:5:5:8:5d10:g
+D:A bolt of ice hits you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:76:Chaos Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A blast of raw chaos hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:77:Nether Bolt Trap
+I:8:80:5:9:25:15d16:g
+D:A bolt of negative energy hits you!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:78:Disenchantment Bolt Trap
+I:8:80:5:9:25:15d16:g
+D:There is a static feeling in the air...
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:79:Nexus Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:A bolt of nexus hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:80:Time Bolt Trap
+I:8:80:5:9:25:15d16:g
+D:Suddenly, several months pass by in a second!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:81:Gravity Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:Gravity suddenly warps around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+#
+# ball traps
+#
+
+N:82:Lightning Ball Trap
+I:3:60:5:5:8:3d10:B
+D:A massive electrical charge shoots through you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:83:Poison Ball Trap
+I:3:60:5:5:8:3d10:B
+D:A large cloud of poison gas envelops you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:84:Acid Ball Trap
+I:3:60:5:5:8:3d10:B
+D:You are suddenly drenched in acid!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:85:Cold Ball Trap
+I:3:60:5:5:8:3d10:B
+D:A blast of hideously cold air envelops you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:86:Fire Ball Trap
+I:3:60:5:5:8:3d10:B
+D:You are suddenly in the centre of a raging inferno!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:87:Plasma Ball Trap
+I:8:60:5:8:20:12d18:B
+D:You are engulfed in plasma!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:88:Water Ball Trap
+I:5:60:5:6:15:8d12:B
+D:A whirlpool engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:89:Light Ball Trap
+I:5:60:5:6:15:8d12:B
+D:A massive flash of light erupts around you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:90:Darkness Ball Trap
+I:5:60:5:6:15:8d12:B
+D:A large patch of darkness erupts around you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:91:Shards Ball Trap
+I:8:60:5:8:20:12d18:B
+D:A violent blast of crystal shards hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:92:Sound Ball Trap
+I:8:60:5:8:20:12d18:B
+D:BOOM! Your eardrums nearly explode!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:93:Confusion Ball Trap
+I:5:60:5:6:15:8d12:B
+D:You are enveloped in a cloud of confusion gas!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:94:Force Ball Trap
+I:8:60:5:8:20:12d18:B
+D:A violent blast of pure force smashes down around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:95:Inertia Ball Trap
+I:8:60:5:8:20:12d18:B
+D:Suddenly, your entire body feels like lead!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:96:Mana Ball Trap
+I:10:60:5:10:30:16d20:B
+D:You are hit by a blast of pure magic!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:97:Ice Ball Trap
+I:5:60:5:6:15:8d12:B
+D:A massive blast of ice crystals engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL2
+
+N:98:Chaos Ball Trap
+I:8:60:5:8:20:12d18:B
+D:A violent blast of raw chaos engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:99:Nether Ball Trap
+I:10:60:5:10:30:16d20:g
+D:A blast of energy from the netherworld engulfs you!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+# N:type:name
+# I:diff:prob:another:pval:minlevel:color
+# D:description
+
+N:100:Disenchantment Ball Trap
+I:10:60:5:10:30:16d20:B
+D:You are hit by a blast of pure anti-magic!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:101:Nexus Ball Trap
+I:8:60:5:8:20:12d18:B
+D:A ball of nexus hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:102:Time Ball Trap
+I:10:60:5:10:30:16d20:B
+D:Suddenly, several years pass by in a second!
+F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:103:Gravity Ball Trap
+I:8:60:5:8:20:12d18:B
+D:You suddenly feel gravity warp violently around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:110:Arrow Trap
+I:2:100:0:5:2:0d0:R
+D:An arrow shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:111:Bolt Trap
+I:2:100:0:5:5:0d0:R
+D:A bolt shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:112:Seeker Arrow Trap
+I:2:100:0:6:10:0d0:R
+D:A seeker arrow shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:113:Seeker Bolt Trap
+I:2:100:0:6:12:0d0:R
+D:A seeker bolt shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:114:Poison Arrow Trap
+I:2:100:0:5:4:0d0:R
+D:A poisoned arrow shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:115:Poison Bolt Trap
+I:2:100:0:6:6:0d0:R
+D:A poisoned bolt shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:116:Poison Seeker Arrow Trap
+I:2:100:0:7:12:0d0:R
+D:A poisoned seeker arrow shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:117:Poison Seeker Bolt Trap
+I:2:100:0:7:15:0d0:R
+D:A poisoned seeker bolt shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:118:Broken Dagger Trap
+I:2:100:0:5:2:0d0:R
+D:An broken dagger shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:119:Dagger Trap
+I:2:100:0:5:5:0d0:R
+D:A dagger shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:120:Poison Broken Dagger Trap
+I:2:100:0:5:4:0d0:R
+D:A poisoned broken dagger shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+N:121:Poison Dagger Trap
+I:2:100:0:6:6:0d0:R
+D:A poisoned dagger shoots out at you.
+F:FLOOR | CHEST | DOOR
+
+#
+# multiple arrows/daggers traps
+#
+
+N:122:Arrows Trap
+I:4:100:0:7:16:0d0:R
+D:Some arrows shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:123:Bolts Trap
+I:4:100:0:7:18:0d0:R
+D:Some bolts shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:124:Seeker Arrow Trap
+I:5:100:0:8:20:0d0:R
+D:Some seeker arrows shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:125:Seeker Bolt Trap
+I:5:100:0:8:24:0d0:R
+D:Some seeker bolts shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:126:Poison Arrows Trap
+I:5:100:0:8:18:0d0:R
+D:Some poisoned arrows shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:127:Poison Bolt Trap
+I:6:100:0:8:20:0d0:R
+D:Some poisoned bolts shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:128:Poison Seeker Arrows Trap
+I:7:100:0:9:27:0d0:R
+D:Some poisoned seeker arrows shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:129:Poison Seeker Bolts Trap
+I:9:100:0:9:30:0d0:R
+D:Some poisoned seeker bolts shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:130:Broken Daggers Trap
+I:4:100:0:6:12:0d0:R
+D:Some broken daggers shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:131:Dagger Trap
+I:4:100:0:6:15:0d0:R
+D:Some daggers shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:132:Poison Broken Daggers Trap
+I:5:100:0:7:18:0d0:R
+D:Some poisoned broken daggers shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:133:Poison Daggers Trap
+I:6:100:0:7:23:0d0:R
+D:Some poisoned daggers shoot out at you.
+F:FLOOR | CHEST | DOOR
+
+N:140:Trap of Drop Item
+I:3:50:0:2:5:0d0:y
+D:A sudden sound startles you and you drop something!
+F:FLOOR | CHEST | DOOR
+
+N:141:Trap of Drop Items
+I:5:50:0:5:12:0d0:y
+D:A sudden sound startles you and you drop several things!
+F:FLOOR | CHEST | DOOR
+
+N:142:Trap of Drop Everything
+I:8:50:0:8:20:0d0:y
+D:A sudden sound startles you and you drop everything!
+F:FLOOR | CHEST | DOOR
+
+#-SC-
+N:150:Trap of Femininity
+I:4:30:5:0:10:2d8:r
+D:You feel like a new woman!
+F:FLOOR | CHEST | DOOR
+
+N:151:Trap of Masculinity
+I:4:30:5:0:10:2d8:r
+D:You feel like a new man!
+F:FLOOR | CHEST | DOOR
+
+N:152:Trap of Neutrality
+I:4:30:5:0:10:2d8:r
+D:You feel like a new woman... erm, a new man... er, WHAT did you say???
+F:FLOOR | CHEST | DOOR
+
+N:153:Trap of Aging
+I:5:50:5:0:15:1d8:r
+D:You suddenly age very fast!
+F:CHEST | DOOR
+
+N:154:Trap of Growing
+I:3:75:5:0:5:1d8:r
+D:You begin to grow!
+F:FLOOR | CHEST | DOOR
+
+N:155:Trap of Shrinking
+I:3:75:5:0:5:1d8:r
+D:You begin to shrink!
+F:FLOOR | CHEST | DOOR
+
+#N:156: UNUSED
+
+#N:157: UNUSED
+
+N:158:Trap of Divine Anger
+I:6:100:5:0:15:0d0:G
+D:A voice booms out "Have a care, mortal!"
+F:FLOOR | CHEST | DOOR
+
+N:159:Trap of Divine Wrath
+I:9:50:5:0:30:0d0:G
+D:A voice booms out "Sacrilege!"
+F:FLOOR | CHEST | DOOR
+
+N:160:Hallucination Trap
+I:3:100:10:0:4:0d0:r
+D:Your vision is clouded by a blast of kaleidoscopic light!
+F:FLOOR | CHEST | DOOR
+
+# Bolt traps
+N:161:Greater Magic Missile Trap
+I:6:80:5:6:75:25d20:g
+D:A greater magic missile hits you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+#N:162:Foulness Trap
+#I:6:80:5:6:15:10d12:g
+#D:You feel foul!
+#F:FLOOR | CHEST | DOOR | LEVEL3
+
+#N:163:Trap of Death Ray
+#I:8:80:5:9:25:15d16:g
+#D:A Ray of Death hits you!
+#F:FLOOR | CHEST | DOOR | LEVEL4
+
+N:164:Trap of Holy Fire
+I:6:80:5:6:15:10d12:g
+D:Holy fire rises around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:165:Trap of Hell Fire
+I:6:80:5:6:15:10d12:g
+D:Hellfire rises around you!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:166:Psi Bolt Trap
+I:6:80:5:6:15:10d12:g
+D:Your mind is suddenly blasted!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:167:Psi Drain Trap
+I:6:80:5:6:15:8d10:r
+D:You suddenly can't think clearly any more...
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+# Ball Traps
+
+### this one *ought* to be a Nuke Ball trap, not plasma ball, as trap 87
+### is also plasma ball. I've put the description right in advance.
+
+#N:168:Plasma Ball Trap
+#I:8:60:5:8:20:12d18:B
+#D:A blast of radiation engulfs you!
+#F:FLOOR | CHEST | DOOR | LEVEL3
+
+N:169:Psi Ball Trap
+I:8:60:5:8:20:12d18:B
+D:Your brain is suddenly blasted!
+F:FLOOR | CHEST | DOOR | LEVEL3
+
+# Useful traps
+
+N:170:Acquirement Trap
+I:1:40:5:5:18:0d0:v
+D:Whoa!
+F:FLOOR | DOOR
+
+# More bolt traps
+
+N:171:Greater Lightning Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:You are jolted with electricity!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:172:Greater Poison Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:A blast of deadly poison gas hits you!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:173:Greater Acid Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:A jet of acid shoots out at you! It burns severely!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:174:Greater Cold Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:You are suddenly extremely cold!
+F:FLOOR | CHEST | DOOR | LEVEL1
+
+N:175:Greater Fire Bolt Trap
+I:3:60:5:3:6:6d6:g
+D:You are suddenly extremely hot!
+F:FLOOR | CHEST | DOOR | LEVEL1
diff --git a/lib/mods/theme/edit/trolls.map b/lib/mods/theme/edit/trolls.map
new file mode 100644
index 00000000..e5d104fd
--- /dev/null
+++ b/lib/mods/theme/edit/trolls.map
@@ -0,0 +1,58 @@
+# Permanent wall
+F:X:63:3
+
+# up stairs
+F:<:6:3
+
+# Floor with tree
+F:T:96:3
+
+# Floor with tree(marked)
+F:H:96:1027
+
+# Floor with dirt
+F:.:88:3
+
+# Floor with grass
+F:;:89:3
+
+# Floor with forest troll
+F:f:89:3:297:0:0:0:0:0:0:2
+
+# Floor with stone troll
+F:s:89:3:401:0:0:0:0:0:0:2
+
+# Floor with algroth
+F:a:89:3:424:0:0:0:0:0:0:2
+
+# Floor with Bert
+F:b:89:3:493:0:0:0:0:0:0:2
+
+# Floor with Bill
+F:i:89:3:494:0:0:0:0:0:0:2
+
+# Floor with a Dwarven skeleton
+F:k:89:8:0:396
+
+# Marker
+F:,:172:6
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X..HTTTTTTTTTTTTTTTTTTTTTTTX
+D:XH...;TTTTTTTTTTTTTTTTTTTTTX
+D:XTTT;;HTTTTTTTTTTTTTa.TTTTTX
+D:XTTH.k...TTTHHkTHTs.fTTTTTTX
+D:XTTTT;..f.TT.;...HTTTTaTTTTX
+D:XTTTTTHT...;......TTT..HTTTX
+D:XTTTTTTT;;.k..;k.HH.i.TTTTTX
+D:XTTTTTTH.HTHTT..TH.,.HTTTTTX
+D:XTTTTT;THTTTTTHTH.bTTTTTTTTX
+D:XTTT.f.TTTTTTTaTTs;TTTTTTTTX
+D:XTTs..TTTTTTT...fHTTTTTTTTTX
+D:XTTTas.TTTTTTTTTTTTTTTTTTTTX
+D:XTTTTTTTTTTTTTTTTTTTTTTTTTTX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:3
diff --git a/lib/mods/theme/edit/v_info.txt b/lib/mods/theme/edit/v_info.txt
new file mode 100644
index 00000000..fb4a4d20
--- /dev/null
+++ b/lib/mods/theme/edit/v_info.txt
@@ -0,0 +1,2287 @@
+# File: v_info.txt
+
+
+# This file is used to initialize the "lib/raw/v_info.raw" file, which is
+# used to initialize the "vault template" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/v_info.raw" file.
+
+# Note that the "spacing" in the "description" lines is very important!
+
+
+# New vault types added for Zangband -TY
+
+# Quest vaults added - rr9
+
+# Version stamp (required)
+
+V:2.0.0
+
+
+### Simple Vaults (type 7) -- maximum size 44x22 ###
+
+
+N:0:Lesser vault (round)
+X:7:5:12:20
+D: %%%%%%
+D: %%%..##..%%%
+D: %%....####....%%
+D: %......#**#......%
+D:%...,.##+##+##.,...%
+D:%.,.,.#*#*&#*#.,.,.%
+D:%.,.,.#*#&*#*#.,.,.%
+D:%...,.##+##+##.,...%
+D: %......#**#......%
+D: %%....####....%%
+D: %%%..##..%%%
+D: %%%%%%
+
+
+N:1:Lesser vault (octagon)
+X:7:5:14:20
+D: %%%%%%%%%%%%%%
+D: %%.##########.%%
+D: %%..#..,,,,..#..%%
+D:%%,..#.,####,.#..,%%
+D:%....#.,#**#,.#....%
+D:%.###+,##&&##,+###.%
+D:%.#..,,#*&**#,,..#.%
+D:%.#..,,#**&*#,,..#.%
+D:%.###+,##&&##,+###.%
+D:%....#.,#**#,.#....%
+D:%%,..#.,####,.#..,%%
+D: %%..#..,,,,..#..%%
+D: %%.##########.%%
+D: %%%%%%%%%%%%%%
+
+
+N:2:Lesser vault (octagon)
+X:7:5:12:20
+D: %%%%%%%%%%%%
+D: %%%%..........%%%%
+D: %...###+##+###...%
+D:%%...#,,#,,#,,#...%%
+D:%.###+##+##+##+###.%
+D:%.#,,#&&#**#&&#,,#.%
+D:%.#,,#&&#**#&&#,,#.%
+D:%.###+##+##+##+###.%
+D:%%...#,,#,,#,,#...%%
+D: %...###+##+###...%
+D: %%%%..........%%%%
+D: %%%%%%%%%%%%
+
+
+N:3:Lesser vault (square)
+X:7:5:12:20
+D:%%%%%%%%%%%%%%%%%%%%
+D:%*.......&........*%
+D:%.################.%
+D:%.#,.,.,.,.,.,.,.#.%
+D:%.#.############,#.%
+D:%.#,+,&&+**#&*,#.#&%
+D:%&#.#,*&#**+&&,+,#.%
+D:%.#,############.#.%
+D:%.#.,.,.,.,.,.,.,#.%
+D:%.################.%
+D:%*........&.......*%
+D:%%%%%%%%%%%%%%%%%%%%
+
+
+N:4:Lesser vault (diagonal)
+X:7:5:12:20
+D:%%%%%%%%%%%%%%%%%
+D:%,,,##,,,,##....%%
+D:%,,,,##,,,,##....%%
+D:%#,,,,##,,,,##....%%
+D:%##,,,,##,,,,##....%
+D:%.##,,,,,,,,,,#+...%
+D:%..#+,,,,,,,,,,##..%
+D:%...##,,,,##,,,,##.%
+D:%%...##,,,,##,,,,##%
+D: %%...##,,,,##,,,,#%
+D: %%...##,,,,##,,,,%
+D: %%%%%%%%%%%%%%%%%
+
+
+N:5:Lesser vault (diagonal)
+X:7:5:12:20
+D: %%%%%%%%%%%%%%%%%
+D: %%....##,,,,##,,,%
+D: %%....##,,,,##,,,,%
+D:%%....##,,,,##,,,,#%
+D:%....##,,,,##,,,,##%
+D:%...+#,,,,,,,,,,##.%
+D:%..##,,,,,,,,,,+#..%
+D:%.##,,,,##,,,,##...%
+D:%##,,,,##,,,,##...%%
+D:%#,,,,##,,,,##...%%
+D:%,,,,##,,,,##...%%
+D:%%%%%%%%%%%%%%%%%
+
+
+N:6:Lesser vault (square)
+X:7:5:12:20
+D:%%%%%%%%%%%%%%%%%%%%
+D:%,################,%
+D:%^#.*...&..,....,#^%
+D:%^#...,......&...#^%
+D:%^#######++#######^%
+D:%^+.,..&+,*+*....+^%
+D:%^+..*.,+.&+.,.&.+^%
+D:%^#######++#######^%
+D:%^#....,.,.....,.#^%
+D:%^#..&......*....#^%
+D:%,################,%
+D:%%%%%%%%%%%%%%%%%%%%
+
+N:7:Lesser vault (spiral)
+X:7:5:19:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.+################.%
+D:%.#^#*&..,.......*#.%
+D:%.#.#.###########.#.%
+D:%.#.#.#*.,.....*#.#.%
+D:%.#.#.#.#######.#.#.%
+D:%.#.#.#.#,...*#.#.#.%
+D:%.#.#.#.#,###.#.#.#.%
+D:%.#,#,#,#,,*#,#,#,#.%
+D:%.#.#.#.###,#.#.#.#.%
+D:%.#.#.#*.,.*#.#.#.#.%
+D:%.#.#.#######.#.#.#.%
+D:%.#.#*...,...*#.#.#.%
+D:%.#.###########.#.#.%
+D:%.#*.....,....&*#^#.%
+D:%.################+.%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+N:8:Lesser vault (layers)
+X:7:5:21:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.########+########.%
+D:%.#.......,.......#.%
+D:%.#.#############.#.%
+D:%.#.#....+.#*...#.#.%
+D:%.#.#.####+####.#.#.%
+D:%.#.#.#...&...#.#.#.%
+D:%.#.#.#.#####.#.#.#.%
+D:%.#.#.#.#*,*#.#.#.#.%
+D:%.#^#^#^#,,,#^#^#.#.%
+D:%.#.#.#.#*,*#.#.#.#.%
+D:%.#.#.#.##+##.#.#.#.%
+D:%.#.#.#..+,#*.#.#.#.%
+D:%.#.#.#########.#.#.%
+D:%.#.#.....,.....#.#.%
+D:%.#.######+######.#.%
+D:%.#.....*#.+......#.%
+D:%.#################.%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+N:9:Lesser vault (bank)
+X:7:7:9:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.&XXXXXXXXXXXXXXXXX%
+D:%&&XXXXX+XXX+XX*,XXX%
+D:%&&+###########,*XXX%
+D:%.&XXX+XXX+XXX+XXXXX%
+D:%.&XXXXXXXXXXXXXXXXX%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+N:10:Lesser vault (mine)
+X:7:7:9:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.XXXXXXXXXXXXXXXXXX%
+D:%.XX##XXXX*,,XX,*,XX%
+D:%.*#XX,*##X*#XX***XX%
+D:%.XXXX*,XXXXX##,*,XX%
+D:%.XXXXXXXXXXXXXXXXXX%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+N:11:Lesser vault (maze)
+X:7:5:22:22
+D:%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXX............%
+D:%.XX,,.XXXXXXXXXXXXX.%
+D:%.XXXX*...&........X.%
+D:%.X.,,XXXXXXXXXXXX*X.%
+D:%.X.XXX.....*......X.%
+D:%.X..XX.XXXXXXXXXX.X.%
+D:%.XX.X.&.XX.X.....*X.%
+D:%.XX.XXX...*X,XXXX.^.%
+D:%.X.XX,XXXX.XXXX,XXX.%
+D:%.X.XX.....*..&.*X,X.%
+D:%.X.,XXXXXXXXXXX.X,X.%
+D:%.XXXX....*..X,X.X,X.%
+D:%.X....XXX.X.X.X.X.X.%
+D:%.X.XXXX,X.X.&.X.X.X.%
+D:%.X.X...*X.XXXXX.X.X.%
+D:%.X.X,XX&X....&..X.X.%
+D:%.X.XXXX.XXXXXXXXX.X.%
+D:%.X.....*...X*X*X..X.%
+D:%.XX^XXXXXX..X*X,XXX.%
+D:%........XXXXXXXXXXX.%
+D:%%%%%%%%%%%%%%%%%%%%%%
+
+N:12:Lesser vault (prison)
+X:7:10:16:35
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.+..&..+..&..+..&..+..&..+..&..+.%
+D:%.###.#####.#####.#####.#####.###.%
+D:% #,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%.#,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%.#,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%.#,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%.#,+.+,#,+.+,#,+.+,#,+.+,#,+.+,#.%
+D:%.###.#####.#####.#####.#####.###.%
+D:%&+..&..+..&..+..&..+..&..+..&..+.%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:13:Lesser vault (camp)
+X:7:10:15:37
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...................................%
+D:%.####^^^^^^^^^^^^^^^^^^^^^^^^^####.%
+D:%.#,&############+++############&,#.%
+D:%.###+.........................+###.%
+D:%.^#....##+#.....#+#....##+#....#^..%
+D:%.^+....#,,#.....#,#....#,,#....+^..%
+D:%.^+....+&&+..&..+&+..&.+&&+....+^..%
+D:%.^+....#,,#.....#,#....#,,#....+^..%
+D:%.^#....#+##.....#+#....#+##....#^..%
+D:%.###+.........................+###.%
+D:%.#,&############+++############&,#.%
+D:%.####^^^^^^^^^^^^^^^^^^^^^^^^^####.%
+D:%...................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:14:Lesser vault (serpent)
+X:7:10:17:32
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..............................%
+D:%..##########################..%
+D:%.##...#.^.#.^.#...#...#.,.###.%
+D:%.#..#.*.#...#...#.^.#...#...+.%
+D:%.#.##########################.%
+D:%.#..#..#.,.#.^.#.^.#.*.#...##.%
+D:%.##^#.#..#...#...#...#...#..#.%
+D:%.#..#.####################..#.%
+D:%.#,##.&+,,,,,,,,,,,,,,,,,#*##.%
+D:%.#..##&+,,,,,,,,,,,,,,,,,#..#.%
+D:%.##^#######################.#.%
+D:%.#..#...#...#...#...#.^.#...#.%
+D:%.##...#.^.#.,.#.*.#.^.#...###.%
+D:%..##########################..%
+D:%..............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:15:Lesser vault (zelazny)
+X:7:5:18:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%.###############.%
+D:%.+,,,,,,,,,,,,,#.%
+D:%.###########,,,#.%
+D:%.#,,,,+..##,,,##.%
+D:%.#,,,##.##,,,##..%
+D:%.#,*##.##,,,##...%
+D:%.#&##.##,,,##.##.%
+D:%.###.##,,,##.###.%
+D:%.##.##,,,##.##&#.%
+D:%...##,,,##.##*,#.%
+D:%..##,,,##..+,,,#.%
+D:%.##,,,##########.%
+D:%.#,,,,,,,,,,,,,+.%
+D:%.###############.%
+D:%.................%
+D:%%%%%%%%%%%%%%%%%%%
+
+N:16:Lesser vault (overlap)
+X:7:5:12:18
+D:%%%%%%%%%%%%%%%%%%
+D:%................%
+D:%.##########.....%
+D:%.#,,,^^^^^+&....%
+D:%.#,,,##########.%
+D:%.#,,,#****+,,,#.%
+D:%.#,,,+****#,,,#.%
+D:%.##########,,,#.%
+D:%....&+^^^^^,,,#.%
+D:%.....##########.%
+D:%................%
+D:%%%%%%%%%%%%%%%%%%
+
+N:17:Lesser vault (celtic)
+X:7:5:17:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.#####..#+#..#####.%
+D:%.#&,##.##&##.##,&#.%
+D:%.#+##..#*^*#..##+#.%
+D:%.#....###.###....#.%
+D:%...####..&..####...%
+D:%.###*##.#+#.##*###.%
+D:%.+&.^..&+*+&..^.&+.%
+D:%.###*##.#+#.##*###.%
+D:%...####..&..####...%
+D:%.#....###.###....#.%
+D:%.#+##..#*^*#..##+#.%
+D:%.#&,##.##&##.##,&#.%
+D:%.#####..#+#..#####.%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+
+N:18:Lesser vault (mirror)
+X:7:5:17:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%.+#############+.%
+D:%.##&,,,,#,,,,&##.%
+D:%.#&#,,,###,,,#&#.%
+D:%.#,,,,,,#,,,,,,#.%
+D:%.##,,,,,#,,,,,##.%
+D:%.###,,,^#^,,,###.%
+D:%.#######+#######.%
+D:%.###,,,^#^,,,###.%
+D:%.##,,,,,#,,,,,##.%
+D:%.#,,,,,,#,,,,,,#.%
+D:%.#&#,,,###,,,#&#.%
+D:%.##&,,,,#,,,,&##.%
+D:%.+#############+.%
+D:%.................%
+D:%%%%%%%%%%%%%%%%%%%
+
+
+N:19:Lesser vault (tower)
+X:7:5:18:15
+D:%%%%%%%%%%%%%%%
+D:%.............%
+D:%..XXX...XXX..%
+D:%..X&XXXXX&X..%
+D:%..XX*****XX..%
+D:%...XX***XX...%
+D:%....X#+#X....%
+D:%....X&&&X....%
+D:%....X^^^X....%
+D:%....X#+#X....%
+D:%....X,,,X....%
+D:%....X^^^X....%
+D:%...XX+#+XX...%
+D:%..XX,&,&,XX..%
+D:%..X^^^*^^^X..%
+D:%.##+#####+##.%
+D:%...&.....&...%
+D:%%%%%%%%%%%%%%%
+
+
+### Greater vaults (type 8) -- maximum size 66x44 ###
+
+N:20:Greater vault (huge)
+X:8:20:17:39
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%+&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8#&#8#&#8#&#88888888888#8#&#8#&#8#&X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#8#&#&+%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:21:Greater vault (large)
+X:8:35:18:40
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X,#,#,#,#,#,#,#,#*@@*#,#,#,#,#,#,#,#,X%
+D:%X+XXXXXXXXXXXXXXXX##XXXXXXXXXXXXXXXX+X%
+D:%X.,..,.X&.&.,*XX******XX*,.&.&X.,...,#%
+D:%X..,.^^X....,XX***@@***XX,....X^^..,.#%
+D:%XXXXXX+X^&.&XX***@##@***XX&.&^X+XXXXXX%
+D:%X,.&.^^X+XXXX***@#XX#@***XXXX+X^^.,..X%
+D:%X..,&,.X^^^@X**@#X88X#@**#@^^^X.,..&,X%
+D:%X.,....X^^^@#**@#X88X#@**X@^^^X.&.,..X%
+D:%X...,^^X+XXXX***@#XX#@***XXXX+X^^..,.X%
+D:%XXXXXX+X^&.&XX***@##@***XX&.&^X+XXXXXX%
+D:%#.,..^^X.....XX***@@***XX,....X^^.,..X%
+D:%#...,..X&.&.,*XX******XX*,.&.&X..,..,X%
+D:%X+XXXXXXXXXXXXXXXX##XXXXXXXXXXXXXXXX+X%
+D:%X,#,#,#,#,#,#,#,#*@@*#,#,#,#,#,#,#,#,X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:22:Greater vault (butterfly)
+X:8:25:18:40
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X*9..&XX***++^^^^^^^^^^^^++***XX&..*9X%
+D:%X9..&XX,,,,,XX^^^^^^^^^^XX,,,,,#X&..*X%
+D:%X..&#X.....,.XX^^^^^^^^XX..&....XX&..X%
+D:%X.&XX..,.&....XX^^^^^^XX..,...&..XX&.X%
+D:%X&XX..*...&.^..XX^^^^XX..*....,..,XX&X%
+D:%XXXX+XXXXXXXXXXXXX++XXXXXXXXXXXXX+XXXX%
+D:%+....,.,.X&&&&***+99+***&&&&X,.,.,...+%
+D:%+...,.,.,X&&&&***+99+***&&&&X.,.,....+%
+D:%XXXX+XXXXXXXXXXXXX++XXXXXXXXXXXXX+XXXX%
+D:%X&XX..*....&...XX^^^^XX...*...&,..#X&X%
+D:%X.&XX..&.^....XX^^^^^^XX....&....XX&.X%
+D:%X..&XX....&..XX^^^^^^^^XX..,..*.XX&..X%
+D:%X*..&#X,,,,,XX^^^^^^^^^^XX,,,,,XX&..9X%
+D:%X9*..&XX***++^^^^^^^^^^^^++***XX&..*9X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+N:23:Greater vault (castle)
+X:8:35:27:27
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.........................%
+D:%..XXXXX..XXX+XXX..XXXXX..%
+D:%..X,,,X..X.,,,.X..X,,,X..%
+D:%..X,,*XXXX.&&&.XXXX*,,X..%
+D:%..XXXX+....&&&....+XXXX..%
+D:%.....X.....,,,.....X.....%
+D:%.....X..,XXX+XXX,..X.....%
+D:%.....X.XXX^^^^^XXX.X.....%
+D:%.&...X.X,,*****,,X.X..&..%
+D:%....XX.X,XXX+XXX,X.XX....%
+D:%....X..X,X@@@@@X,X..X....%
+D:%....X..X,X@999@X,X..X....%
+D:%....X..X,X@989@X,X..X....%
+D:%....X..X,X@999@X,X..X....%
+D:%....X..X,X@@@@@X,X..X....%
+D:%....XX.X,XXX+XXX,X.XX....%
+D:%.....X.X,,*****,,X.X.....%
+D:%.....X.XXX^^^^^XXX.X.....%
+D:%.....X..,XXX+XXX,..X.....%
+D:%.....X.....&&&.....X.....%
+D:%..XXXX+....&&&....+XXXX..%
+D:%..X,,*XXXX.&&&.XXXX*,,X..%
+D:%..X,,,X..X.,,,.X..X,,,X..%
+D:%..XXXXX..XX^^^XX..XXXXX..%
+D:%.........................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:24:Greater vault (chambers)
+X:8:25:15:40
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%&+.^..^..^..^..^..^..^..^..^..^..^..+&%
+D:%+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+%
+D:%.X.&.^,X&^&^X****+^*^@^X.*.&..X..*.,X.%
+D:%^X.,.&^+^&^@X^^^^X@^*^*X....*^+.^...X^%
+D:%.X*..,.XXX+XXXX+XXXX+XXX.&.^..X..&,.X.%
+D:%^X..^.*X*..^&&@@*X,,,,,XXXX+XXX,....X^%
+D:%.XX+XXXXXXXXXXXXXX,*8*,X,,,,,,XXX+XXX.%
+D:%^X*&X.&,*.X,*&^*^X,,,,,X,,,,,,X....,X^%
+D:%.X&,+....*+,*&^*^XXXXXXXXXX+XXX.,...+.%
+D:%^X.,X.*.&.X,*&^*^+.,.&.^*.&^&^X.....X^%
+D:%.X^*X.,..,X,*&^*^X*.^*.,..&&&^X,..,.X.%
+D:%+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+%
+D:%&+..^..^..^..^..^..^..^..^..^..^..^.+&%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:25:Greater vault (Sierpinski)
+X:8:35:28:39
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..................X..................%
+D:%.................XXX.................%
+D:%.................X8X.................%
+D:%.....&..........XX+XX................%
+D:%...............XX999XX........&......%
+D:%......&........X@X9X@X...............%
+D:%..............XXXX+XXXX..............%
+D:%.............XX*@*@*@*XX....&........%
+D:%.............X@X*@*@*X@X.............%
+D:%............XXXX**@**XXXX............%
+D:%..........&XX,,,X***X,,,XX&..........%
+D:%..........XX,X@X,X,X,X@X,XX..........%
+D:%.........XXXXX+XXXXXXX+XXXXX.........%
+D:%........XX+,,,,,,,,,,,,,,,+XX........%
+D:%........X@X,,,,,,,,,,,,,,,X@X........%
+D:%.......XX+XX,,,,,,,,,,,,,XX+XX.......%
+D:%......XX,,,XX,,,,,,,,,,,XX,,,XX......%
+D:%......X,X,X,X,,,,,,,,,,,X,X,X,X......%
+D:%.....XXXX+XXXX,,,,,,,,,XXXX+XXXX.....%
+D:%....XX*******XX,,,,,,,XX*******XX....%
+D:%....X,X*****X,X,,,,,,,X,X*****X,X....%
+D:%...XXXX*****XXXX,,,,,XXXX*****XXXX...%
+D:%..XX,,,X***X,,,XX,,,XX,,,X***X,,,XX..%
+D:%..X,X,X,X*X,X,X,X,,,X,X,X,X*X,X,X,X..%
+D:%.XXXXXXXX+XXXXXXXXXXXXXXXXX+XXXXXXXX.%
+D:%.........&.................&.........%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:26:Greater vault (swastika)
+X:8:25:23:29
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....^^^^^^^^^^^^^^^^^^^^^..%
+D:%^^^^^###################^..%
+D:%^####+..#..............#^..%
+D:%^#.....####.XXXXXXXXXX.#^..%
+D:%^#...&.#,&..X,,,@,@,9X.#^..%
+D:%^#.XXX.####.X,XXXXXXXX.#^..%
+D:%^#.X9X..&,#.X,X......&.#^^^%
+D:%^#.X,X.####.X,X.#######+##^%
+D:%^#.X@X.....^X^X^.........#^%
+D:%^#.X@XXXXXXX+*+XXXXXXXXX.#^%
+D:%^#.X,,,,,,,^*X*^,,,,,,,X.#^%
+D:%^#.XXXXXXXXX+*+XXXXXXX@X.#^%
+D:%^#.........^X^X^.....X@X.#^%
+D:%^##+#######.X,X.####.X,X.#^%
+D:%^^^#.&......X,X.#,&..X9X.#^%
+D:%..^#.XXXXXXXX,X.####.XXX.#^%
+D:%..^#.X9,@,@,,,X..&,#.&...#^%
+D:%..^#.XXXXXXXXXX.####.....#^%
+D:%..^#..............#..+####^%
+D:%..^###################^^^^^%
+D:%..^^^^^^^^^^^^^^^^^^^^^....%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:27:Greater vault (great spiral)
+X:8:40:39:39
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.....................................%
+D:%.X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X@X.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^^+.%
+D:%.X.X^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X.X.X,..,..,..,..,..,..,..,..,..,.X.%
+D:%.X.X^X.XXXXXXXXXXXXXXXXXXXXXXXXXXX.X.%
+D:%.X.X.X.X......&...&...&...&...@..X,X.%
+D:%.X.X^X,X@XXXXXXXXXXXXXXXXXXXXXXX.X.X.%
+D:%.X.X.X.X.X&.........8.........&X*X.X.%
+D:%.X.X^X.X.X.XXXXXXXXXXXXXXXXXXX.X.X,X.%
+D:%.X.X.X,X.X.X.^.^.^.^.^.^.^.^.X.X.X.X.%
+D:%.X.X^X.X.X.X^XXXXXXXXXXXXXXX*X.X*X.X.%
+D:%.X.X.X.X&X.X.X,..,..,..,..,X.X.X.X,X.%
+D:%.X.X^X,X.X.X^X.XXXXXXXXXXX.X*X.X.X.X.%
+D:%.X.X.X.X.X.X.X.X..&..&..9X.X.X.X*X.X.%
+D:%.X.X^X.X&X.X^X,X9XXXXXXX.X,X*X.X.X,X.%
+D:%.X.X.X,X.X.X.X.X&X@@..&X.X.X.X.X.X.X.%
+D:%.X.X^X.X.X9X^X.X*X+XXX.X&X.X*X.X*X.X.%
+D:%.X.X.X.X.X.X.X,X^+8+^X.X.X,X.X.X.X,X.%
+D:%.X9X^X,X.X.X^X.XXX+X^X.X*X.X*X.X.X.X.%
+D:%.X.X.X.X&X.X.X.,.,,X.X9X.X.X.X.X*X.X.%
+D:%.X.X^X.X.X.X^XXXXXXX^X.X*X,X*X9X.X,X.%
+D:%.X.X.X,X.X.X.^.^.^.^.X.X.X.X.X.X.X.X.%
+D:%.X.X^X.X.X.XXXXXXXXXXX.X^X.X^X.X*X.X.%
+D:%.X.X.X.X8X&.....9.....&X.X,X.X.X.X,X.%
+D:%.X.X^X,X.XXXXXXXXXXXXXXX^X.X^X.X.X.X.%
+D:%.X.X.X.X..&....8......@..X.X.X.X*X.X.%
+D:%.X.X^X.XXXXXXXXXXXXXXXXXXX,X^X.X.X,X.%
+D:%.X.X.X,..,..,..,..,..,..,..X.X.X.X.X.%
+D:%.X.X^XXXXXXXXXXXXXXXXXXXXXXX^X.X*X.X.%
+D:%.X.X.*.^.*.*.*.*.*.*.*.*.*.^.X.X.X,X.%
+D:%.X.XXXXXXXXXXXXXXXXXXXXXXXXXXX.X.X.X.%
+D:%.X&.............9.............&X*X.X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.X,X.%
+D:%.+^^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.X,X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X.%
+D:%.....................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:28:Greater vault (greater castle)
+X:8:40:25:51
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.................................................%
+D:%...XXXXXX...............................XXXXXX...%
+D:%..XX,,,,XX.............................XX,,,,XX..%
+D:%.XX,*99*,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,*99*,XX.%
+D:%.XX,*99*,+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+,*99*,XX.%
+D:%..XX,,,,XXXXXXXXXXXXXXX+X+XXXXXXXXXXXXXXX,,,,XX..%
+D:%...XX++XX...............X...............XX++XX...%
+D:%....X^^X.............XXXXXXX.............X^^X....%
+D:%....X^^X.X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X.X^^X....%
+D:%....X^^X.X^^^XXXXXXXXXXXXXXXXXXXXXXX^^^X.X^^X....%
+D:%....X^^+&X^^XX@.+***************+.@XX^^X&+^^X....%
+D:%....X^^XXX^^+@.@X*9999988899999*X@.@+^^XXX^^X....%
+D:%....X^^+.X^^XX@.+***************+.@XX^^X.+^^X....%
+D:%....X^^X.X^^^XXXXXXXXXXXXXXXXXXXXXXX^^^X.X^^X....%
+D:%....X^^X.X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X.X^^X....%
+D:%....X^^X............XXXX+XXXX............X^^X....%
+D:%...XX++XX..........XX&.&.&.&XX..........XX++XX...%
+D:%..XX,,,,XXXXXXXXXXXX&.&.&.&.&XXXXXXXXXXXX,,,,XX..%
+D:%.XX,*99*,+********9XXXXX+XXXXX9********+,*99*,XX.%
+D:%.XX,*99*,XXXXXXXXXXX&.&.&.&.&XXXXXXXXXXX,*99*,XX.%
+D:%..XX,,,,XX.........XX&.&.&.&XX.........XX,,,,XX..%
+D:%...XXXXXX...........XXXX+XXXX...........XXXXXX...%
+D:%.................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:29:Lesser vault (x-factor)
+X:8:25:25:26
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%^^^^^^^^^^^^^^^^^^^^^^^^%
+D:%^##########++##########^%
+D:%^#XX,,,,,,,,,,,,,,,,XX#^%
+D:%^#,XX,,,,,,,,,,,,,,XX,#^%
+D:%^#,,XX,,,,,,,,,,,,XX,,#^%
+D:%^#,,,XX,,,,,,,,,,XX,,,#^%
+D:%^#,,,,XX,,,,,,,,XX,,,,#^%
+D:%^#,,,,,XX,,,,,,XX,,,,,#^%
+D:%^#,,,,,,XX,,,,XX,,,,,,#^%
+D:%^#,,,,,,,X+XX+X,,,,,,,#^%
+D:%^+,,,,,,,,X99X,,,,,,,,+^%
+D:%^+,,,,,,,,X99X,,,,,,,,+^%
+D:%^+,,,,,,,,X99X,,,,,,,,+^%
+D:%^#,,,,,,,X+XX+X,,,,,,,#^%
+D:%^#,,,,,,XX,,,,XX,,,,,,#^%
+D:%^#,,,,,XX,,,,,,XX,,,,,#^%
+D:%^#,,,,XX,,,,,,,,XX,,,,#^%
+D:%^#,,,XX,,,,,,,,,,XX,,,#^%
+D:%^#,,XX,,,,,,,,,,,,XX,,#^%
+D:%^#,XX,,,,,,,,,,,,,,XX,#^%
+D:%^#XX,,,,,,,,,,,,,,,,XX#^%
+D:%^##########++##########^%
+D:%^^^^^^^^^^^^^^^^^^^^^^^^%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:30:Greater vault (university)
+X:8:30:29:38
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....................................%
+D:%.##################################.%
+D:%.#*+..&#..,#,#..,#,#..,#,#.,#&+*#*#.%
+D:%.#####.#.###.#.###.#.###.#.##.###+#.%
+D:%.#***#.#.#*..#.#*..#.#*..#.#..#..&#.%
+D:%.#+###+#+###+#+###+#+###+#+##+###+#.%
+D:%.#...+&......................&+...#.%
+D:%.#.###.##########++##########.###.#.%
+D:%.#,#.+.#,,,,,,,,,,,,,,,,,,,,#.#*#,#.%
+D:%.###.#.#,.,..,..,@.,..,..,.,#.#.###.%
+D:%.#,..#.#,..,..,..,..,..,..,,#.+..,#.%
+D:%.#####.#,9&,,,9,,&,,&,,.,,,,#.#####.%
+D:%.+^^^+.+,,,&,,,&,,,9,,&,,&,,+.+^^^+.%
+D:%.+^^^+.+,.,...,...,...,...,,+.+^^^+.%
+D:%.###+#.#,,,,&,,&,,,9,&,,,&,,#.#####.%
+D:%.#*#&#.#,,,&,,,9,&,,&,,,,,9,#.#..,#.%
+D:%.#+#*#.#,.,...,....,....,..,#.#.###.%
+D:%.#.###.#,,,&,,,,&,9,,&,,,&,,#.+.#,#.%
+D:%.#&..+.#,,,,,,,,.,,,,,,,,,,,#.###.#.%
+D:%.#####.##########++##########.+...#.%
+D:%.#&..+&......................&#+###.%
+D:%.#.###+#+###+#+###+#+###+#+##+#...#.%
+D:%.#.+*#.#.#*..#.#*..#.#*..#.#..###,#.%
+D:%.#####.#.###.#.###.#.###.#.##&#*###.%
+D:%.#*+..&#..,#,#..,#,#..,#,#.,#.+,*,#.%
+D:%.##################################.%
+D:%....................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:31:Greater vault (nethack castle (almost))
+X:8:35:19:62
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%............................................................%
+D:%.XXXXXXX............................................XXXXXXX.%
+D:%.X,,9,,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,9,,X.%
+D:%.X,,,,,+.......^....*....^ ..........^.......*...^..+,,,,,X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%......X,.,9,,,,X,,,,,,,,,+,.,.,.,.,.,X,.,.,.+^+,.,.,.X......%
+D:%......X,.9*9,.,X,,,,,,,,,X,.,..,..,.,X,.,.,.X^X,.,.,.X......%
+D:%....&.X.&*@*&,.XXXXXXXXXXX,.,.,9,.,.,XXXXXXXX+XXXXXXXX......%
+D:%......+9*@8@*9.+^^^^^^^^^+,.,,9@9,,.,+^^^^^^^^^^^^^^^+......%
+D:%....&.X.&*@*&,.XXXXXXXXXXX,.,.,9,.,.,XXXXXXXX+XXXXXXXX......%
+D:%......X,.9*9,.,X,,,,,,,,,X,.,.,,,.,.,X.,.,.,X^X.,.,.,X......%
+D:%......X,.,9,,,,X,,,,,,,,,+,.,.,.,.,.,X.,.,.,+^+.,.,.,X......%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X,,,,,+.......^....*....^...........^.......*...^..+,,,,,X.%
+D:%.X,,9,,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,9,,X.%
+D:%.XXXXXXX............................................XXXXXXX.%
+D:%............................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:32:Greater vault (another nethack-style castle)
+X:8:30:18:52
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..................................................%
+D:%.XXXXX......................................XXXXX.%
+D:%.X9,,X......................................X,,9X.%
+D:%.XXX+XXXXXXXXXXXXXXXXXXX++XXXXXXXXXXXXXXXXXXX+XXX.%
+D:%...X^^^^^^^^^^^^^^^^^^^+..+^^^^^^^^^^^^^^^^^^^X...%
+D:%...X^XXXXXXXXXXXXXXXXXXX++XXXXXXXXXXXXXXXXXXX^X...%
+D:%...X^X,,,,,,,,,,,,,,,,,X..X,,,,,,,,,X,,@@@@,X^X...%
+D:%...X^X,,,,,,,,,,,,,,,,,+..+,,,,,,,,,+,,,,998X^X...%
+D:%...X^X,,,,,,,,,,,,,,,,,+..+,,,,,,,,,+,,,,998X^X...%
+D:%...X^X,,,,,,,,,,,,,,,,,X..X,,,,,,,,,X,,@@@@,X^X...%
+D:%...X^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX^X...%
+D:%...X^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^X...%
+D:%.XXX+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+XXX.%
+D:%.X9,,X......................................X,,9X.%
+D:%.XXXXX......................................XXXXX.%
+D:%..................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:33:Lesser vault (nethack-style tower)
+X:7:5:15:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%...###.###.###...%
+D:%...#&#.#&#.#&#...%
+D:%.###+###+###+###.%
+D:%.#.,.,.,.+.+,,,#.%
+D:%.###+#####.#####.%
+D:%...+*&*&*#.+,#...%
+D:%.###+#####.#####.%
+D:%.#.,.,.,.+.+,,,#.%
+D:%.###+###+###+###.%
+D:%...#&#.#&#.#&#...%
+D:%...###.###.###...%
+D:%.................%
+D:%%%%%%%%%%%%%%%%%%%
+
+
+N:34:Lesser vault (nethack, rooms)
+X:7:5:14:27
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.........................%
+D:%.#+#####################.%
+D:%.#.^.^.^.+^+^...^#,,,,,#.%
+D:%.#^###+###^#####.+,,,,,#.%
+D:%.#.#,,,,,#.#,,,#^#,,,,,#.%
+D:%.#^#,,,,,#^+,,,#+#######.%
+D:%.#.#######.#,,,#.......#.%
+D:%.#^#,,,,,#^#,,,#..&.&..#.%
+D:%.#.#,,,,,#.#####.......#.%
+D:%.#^+,,,,,#^.^.^+..&.&.^+.%
+D:%.#######################.%
+D:%.........................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:35:Lesser vault (nethack city)
+X:7:9:17:33
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...............................%
+D:%.############.....############.%
+D:%.#,,,#,,,#,,#.....#**#,,,#***#.%
+D:%.#,,,#,,,#,,#.....+**#,,,#***#.%
+D:%.#,,,#,,,#,,#.....#**#,,,#&&&#.%
+D:%.#^,,#,,,#+##.....####+###+###.%
+D:%.#+####+##.....................%
+D:%...............................%
+D:%.#+###+###....###+##...........%
+D:%.#^,,#^,,####.#,,,,#.######+##.%
+D:%.#,,,#,,,#**#.#,&&,#.+^^#,,,,#.%
+D:%.#,,,#,,,#*^+.#,&@,#.#^^#,,,,#.%
+D:%.#,,,#,,,#**#.#,,,,#.#**#,,,,#.%
+D:%.############.######.#########.%
+D:%...............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:36:Greater vault (nethack, large city)
+X:8:25:21:54
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....................................................%
+D:%.##################################################.%
+D:%.#................................................#.%
+D:%.#.####################.########..#####.#########.#.%
+D:%.#.#^,,,,^#^****^#^,,^#.#^,,,,^#..#^^^#.#^,,,,,^#.#.%
+D:%.#.#^,,,,^#^****^#^,,^#.#^,,,,^#..+^**#.#^,,,,,^#.#.%
+D:%.#.#^,,,,^#^,,,,^#^^^^#.#^^^^^^#..#^^^#.#^,,,,,^#.#.%
+D:%.#.#^^^^^^#^^^^^^###+##.###+####..#####.#^^^^^^^#.#.%
+D:%.#.#+#########+###......................######+##.#.%
+D:%.#................................................#.%
+D:%.#.###+######+####......###+########..............#.%
+D:%.#.#^^^^^^#^^^^^^######.#^^^^^^^^^^#...###+#####..#.%
+D:%.#.#^,,,,^#^,,,,^#^^^^+.#^,,,,,,,,^#...#^^^^^^^#..#.%
+D:%.#.#^****^#^,,,,^#,,,^#.#^@999999@^#...#^,,,,,^#..#.%
+D:%.#.#^****^#^,,,,^#,,,^#.#^^^^^^^^^^#...#^,,,,,^#..#.%
+D:%.+.####################.############...#########..#.%
+D:%.#................................................#.%
+D:%.##################################################.%
+D:%....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:37:Lesser vault (nethack, tiny castle)
+X:7:5:14:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................................%
+D:%.#####....................#####.%
+D:%.#*,&#....................#&,*#.%
+D:%.###+######################+###.%
+D:%...#,,,,,,,,,,,,,#,,,,,,,,,,#...%
+D:%...+,,,,,,,,,,,,,+,,,,,,,,,,+...%
+D:%...+,,,,,,,,,,,,,+,,,,,,,,,,+...%
+D:%...#,,,,,,,,,,,,,#,,,,,,,,,,#...%
+D:%.###+######################+###.%
+D:%.#*,&#....................#&,*#.%
+D:%.#####....................#####.%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:38:Greater vault (nethack mirror)
+X:8:25:22:41
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................................%
+D:%...............XXXX+XXXX...............%
+D:%...............X**X^X**X...............%
+D:%....XXXXXXXXXXXX**X^X**XXXXXXXXXXXX....%
+D:%....X^+99999999X+XX^XX+X99999999+^X....%
+D:%....X^X9*******X,,X^X,,X*******9X^X....%
+D:%....X^X9*******X,,X^X,,X*******9X^X....%
+D:%.XXXX+XXXXXXXXXXX+X+X+XXXXXXXXXXX+XXXX.%
+D:%.X**X,,,,,,,,,,X,,,,,,,X,,,,,,,,,,X**X.%
+D:%.X*@+,,,,,,,,,,+,,,,8,,X,,,,,,,,,,+@*X.%
+D:%.X*@+,,,,,,,,,,X,,,8,,,+,,,,,,,,,,+@*X.%
+D:%.X**X,,,,,,,,,,X,,,,,,,X,,,,,,,,,,X**X.%
+D:%.XXXX+XXXXXXXXXXX+X+X+XXXXXXXXXXX+XXXX.%
+D:%....X^X9*******X,,X^X,,X*******9X^X....%
+D:%....X^X9*******X,,X^X,,X*******9X^X....%
+D:%....X^+99999999X+XX^XX+X99999999+^X....%
+D:%....XXXXXXXXXXXX**X^X**XXXXXXXXXXXX....%
+D:%...............X**X^X**X...............%
+D:%...............XXXX+XXXX...............%
+D:%.......................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:39:Greater vault (nethack tomb)
+X:8:25:13:57
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................................................%
+D:%..........XXXXX.XXXXX.XXXXX.XXXXX.XXXXX................%
+D:%..........X,,,X.X,,,X.X,,,X.X,,,X.X,,,X................%
+D:%.XXXXXXXXXX,&,XXX,&,XXX,&,XXX,&,XXX,&,XXXXXXXXXXXXXXXX.%
+D:%.X&^&X....^...^...^...^...^...^...^..^..X,,,,,,,,X,,9X.%
+D:%.+^^^+..^...^...^...^...^...^...^...^.@.+,,,,,,,,+,98X.%
+D:%.X&^&X....^...^...^...^...^...^...^.....X,,,,,,,,X,,9X.%
+D:%.XXXXXXXXXX,&,XXX,.,XXX,.,XXX,&,XXX,&,XXXXXXXXXXXXXXXX.%
+D:%..........X,,,X.X,,,X.X,,,X.X,,,X.X,,,X................%
+D:%..........XXXXX.XXXXX.XXXXX.XXXXX.XXXXX................%
+D:%.......................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:40:Greater vault (nethack hell level #1)
+X:8:30:17:55
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.....................................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.XX*XXXXXXXXXX**XXXXXXXXXXXX***********************X.%
+D:%.XX*X,,,,X***X+XX,,,,,,X***XXXXXXXXXXXX^^^^^^^^^^^^X.%
+D:%.XX,X,,,,+***X@^+,,,,,,X***+,,,,,,,,,,X^^^^^^^^^^^^X.%
+D:%.XX&X,,,,XXXXXXXX^^^^^^^^^^X,,,XXXXXXXXXXXXXX^^^^^^X.%
+D:%.XX+X....XXXX.............^X,,,+,,,,,,,,,,,9XXXXX^^X.%
+D:%.+^^^^^^^^^^+^^^^^^^^^^^^^^XXXXX,,,,,,,,,,,9+888+@@X.%
+D:%.XX+X....XXXX.............^X,,,+,,,,,,,,,,,9XXXXX^^X.%
+D:%.XX&X,,,,XXXXXXXX^^^^^^^^^^X,,,XXXXXXXXXXXXXX^^^^^^X.%
+D:%.XX,X,,,,+***X@^+,,,,,,X***+,,,,,,,,,,X^^^^^^^^^^^^X.%
+D:%.XX*X,,,,X***X+XX,,,,,,X***XXXXXXXXXXXX^^^^^^^^^^^^X.%
+D:%.XX*XXXXXXXXXX**XXXXXXXXXXXX***********************X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:41:Greater vault (nethack hell level #2)
+X:8:30:15:54
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....................................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...%
+D:%.+^XX,+^^^^^X^^^^^^^^^^^^^^^^^^^^^X,,,X,@^X*^*+9X...%
+D:%.X^XX,X^XXX,X@XXXXXXXXXXXXXXXXXXX^X,X,X,X^X*X*X9X...%
+D:%.X^XX,X^^^X,X^^^^^^^^^^^^^^^^^^@X^X,X,X,X^X*X*X9X...%
+D:%.X^XXXXXX^X,XXXXXXXXXXXXXXXXXXX^X^X,X,X,X^X*X*X+XXX.%
+D:%.X^^^^^^X^X,X,,,,,,,,,,,,,,,,,X^X^X,X,X,X^X*X*X888X.%
+D:%.X+XXXX^X^X,X,XXXXXXXXXXXXXXX,X^X^X,X,X,X^X*X*X+XXX.%
+D:%.X,XX,X^X^X,X,X,,,,,,,,,,,,,,,X^X^X,X,X,X^X*X*X9X...%
+D:%.X,XX,X^X&X,X,X,XXXXXXXXXXXXXXX^X^X,X,X,X^X*X*X9X...%
+D:%.X,XX,+^^^X,,,X^^^^^^^^^^^^^^^^^X^@,X,,,X^@*X*+9X...%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...%
+D:%....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:42:Greater vault (nethack hell level #3)
+X:8:30:17:55
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.....................................................%
+D:%...XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.........%
+D:%...X,,,,,,,,,,,,,,,,,,,,,XXX^^^^^^^^^^^^^^^X.........%
+D:%...X,^^^^^^^^^^XXXX,,,,,,+&&^XXXXXXXXXXXX^^+.........%
+D:%...X,^XXXXXX******X,,XXXXXXXXX^^^^******XXXX.........%
+D:%...X,^X****X@*XXXXXXXX,,,,,,,,,,,XXXXXXXXXXXXXX......%
+D:%.XXXX+X,,,,XXXX,,,,,,,,,,,,,,,,,^+************XXXXX..%
+D:%.X@,,,,,XX,,,,+,,XXXXXXXXXXXXXXXXX****9999****+888X..%
+D:%.XXXX+X,,,,XXXX,,,,,,,,,,,,,,,,,^+************XXXXX..%
+D:%...X,^X****X@*XXXXXXXX,,,,,,,,,,,XXXXXXXXXXXXXX......%
+D:%...X,^XXXXXX******X,,XXXXXXXXX^^^^******XXXX.........%
+D:%...X,^^^^^^^^^^XXXX,,,,,+&&^^XXXXXXXXXXXX^^+.........%
+D:%...X,,,,,,,,,,,,,,,,,,,,XXX^^^^^^^^^^^^^^^^X.........%
+D:%...XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.........%
+D:%.....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:43:Lesser vault (easter egg)
+X:7:5:14:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%.###############.%
+D:%.#,^,^,^,^,^,^,#.%
+D:%.#+###########^#.%
+D:%.#,^,^,^,^,^,#,#.%
+D:%.###########,#^#.%
+D:%.#,^,^,^,^,#^#,#.%
+D:%.#+#######,#,#^#.%
+D:%.#,,,,,,,#^#^#,#.%
+D:%.#,,,,,,,#,+,#^+.%
+D:%.###############.%
+D:%.................%
+D:%%%%%%%%%%%%%%%%%%%
+
+N:44:Greater vault (nethack samurai castle)
+X:8:35:20:59
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.........................................................%
+D:%.XXXXX.............................................XXXXX.%
+D:%.X***X.............................................X***X.%
+D:%.X***XXX.....XX+XXXXXXXXXXXXXXXXXXXXXXXXX+XX.....XXX***X.%
+D:%.XXX@,,X.....X^&^X,,,X***X,,,X***X^^^+8X^&^X.....X,,@XXX.%
+D:%...X,,,XXXXXXX^^^X,,,X^^^X,,,X^^^X@@^X8X^^^XXXXXXX,,,X...%
+D:%...XXX^^^^^^^^^XXXXX+XXX+X+XXXXX+X+XXXXXXX^^^^^^^^^XXX...%
+D:%.....X^^XXXXXXXX*X,,,,,,,,,,,,,,,,,,,,,X*XXXXXXXX^^X.....%
+D:%.....X^^+,,,,,,,,+,,,,,,,,,99,,,,,,,,,,+,,,,,,,,+^^X.....%
+D:%.....X^^+,,,,,,,,+,,,,,,,,,99,,,,,,,,,,+,,,,,,,,+^^X.....%
+D:%.....X^^XXXXXXXX*X,,,,,,,,,,,,,,,,,,,,,X*XXXXXXXX^^X.....%
+D:%...XXX^^^^^^^^^XXXXXXX+X+XXXXX+X+XXX+XXXXX^^^^^^^^^XXX...%
+D:%...X,,,XXXXXXX^^^X8X^@@X^^^X^^^X,,,X,,,X^^^XXXXXXX,,,X...%
+D:%.XXX@,,X.....X^&^X8+^^^X***X***X,,,X,,,X^&^X.....X,,@XXX.%
+D:%.X***XXX.....XX+XXXXXXXXXXXXXXXXXXXXXXXXX+XX.....XXX***X.%
+D:%.X***X.............................................X***X.%
+D:%.XXXXX.............................................XXXXX.%
+D:%.........................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:45:Greater vault (nethack samurai castle #2)
+X:8:35:20:61
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...........................................................%
+D:%.XXXXXXXXXXXXX...............................XXXXXXXXXXXXX.%
+D:%.X,,^^^^^^^,,X...............................X,,^^^^^^^,,X.%
+D:%.X,,^XXXXX^,,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,^XXXXX^,,X.%
+D:%.X,,^+999X^,,X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X,,^X999+^,,X.%
+D:%.X,,^XXXXX^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^XXXXX^,,X.%
+D:%.X^^^^^^^^^^^XXXXXX+XXXXXXXXXXXXXXXXXXX+XXXXXX^^^^^^^^^^^X.%
+D:%.XXXX^^^XXXXXXXX*X,,,,,,,,,,,,,,,,,,,,,,,X*XXXXXXXX^^^XXXX.%
+D:%....+^^^X********+,,,,,,,,,,,,,,,,,,,,,,,+********X^^^+....%
+D:%....+^^^X********+,,,,,,,,,,,,,,,,,,,,,,,+********X^^^+....%
+D:%.XXXX^^^XXXXXXXX*X,,,,,,,,,,,,,,,,,,,,,,,X*XXXXXXXX^^^XXXX.%
+D:%.X^^^^^^^^^^^XXXXXX+XXXXXXXXXXXXXXXXXXX+XXXXXX^^^^^^^^^^^X.%
+D:%.X,,^XXXXX^,,^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^XXXXX^,,X.%
+D:%.X,,^+999X^,,X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X,,^X999+^,,X.%
+D:%.X,,^XXXXX^,,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,^XXXXX^,,X.%
+D:%.X,,^^^^^^^,,X...............................X,,^^^^^^^,,X.%
+D:%.XXXXXXXXXXXXX...............................XXXXXXXXXXXXX.%
+D:%...........................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:46:Greater vault (nethack spiral)
+X:8:30:19:38
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.........XXXXXXXXX+XXXXXXXXX........%
+D:%......XXXX^^^^^^^^^^^^^^^^^XXXX.....%
+D:%...XXXX^^^^^XXXXXXXXXXXXX^^^^^XXXX..%
+D:%..XX^^^^^XXXX^^^^^^^^^^^XXXX^^^^^XX.%
+D:%.XX^^^^XXX^^^^XXXXXXXXX^^^^XXX^^^^XX%
+D:%.X^^^^XX^^^^XXX,^^^^^,XXX^^^^XX^^^^X%
+D:%.X,,,XX,,,XXX,,^XX+XX^,,XXX,,,XX,,,X%
+D:%.X,,,X,,,,X,,,^XX***XX^,,,X,,,,X,,,X%
+D:%.X,,,X,99,X,,,^+@888@+^,,,X,,,,+,,,X%
+D:%.X,,,X,,,,X,,,^XX***XX^,,,X,,,,X,,,X%
+D:%.X,,,XX,,,XXX,,^XX+XX^,,XXX,,,XX,,,X%
+D:%.X,,,,XX^^^^XXX,^^^^^,XXX^^^^XX,,,,X%
+D:%.XX,,,,XXX^^^^XXXX+XXXX^^^^XXX,,,,XX%
+D:%..XX,,,**XXXX^^^^^^^^^^^XXXX,,,,,XX.%
+D:%...XXXX**,,,XXXXXXXXXXXXX,,,,,XXXX..%
+D:%......XXXX,,,,,,,,,,,,,,,,,XXXX.....%
+D:%.........XXXXXXXXXXXXXXXXXXX........%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:47:Greater vault (nethack building)
+X:8:30:16:41
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%...X^^^^^^^^^^^^^^^^X**@**X**@**X**@**X%
+D:%...X^^XXXXXXXXXXXX^^XXX+XXXXX+XXXXX+XXX%
+D:%...X^^X,,,,,,,,,,X^^X^^^^^^^^^^^^^^^^^X%
+D:%...X^^X,,,,,,,,,,X^^X+XXX+XXX+XXXXX+XXX%
+D:%.XXX^^X,,,,,,,,,,X^^^^^^X,,,X,,,X,,,,,X%
+D:%.+^&^^X,,,,,,,,,,+^^^^^^X,,,X,,,X,989,X%
+D:%.+^&^^X,,,,,,,,,,+^^^^^^X,,,X,,,X,989,X%
+D:%.XXX^^X,,,,,,,,,,X^^^^^^X,,,X,,,X,,,,,X%
+D:%...X^^X,,,,,,,,,,X^^X+XXXXX+XXX+XXX+XXX%
+D:%...X^^X,,,,,,,,,,X^^X^^^^^^^^^^^^^^^^^X%
+D:%...X^^XXXXXXXXXXXX^^XXX+XXXXX+XXXXX+XXX%
+D:%...X^^^^^^^^^^^^^^^^X**@**X**@**X**@**X%
+D:%...XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:48:Lesser vault (nethack, spiral rooms)
+X:7:5:13:32
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..............................%
+D:%....#######################...%
+D:%..###^+,,,,,,#^^^^^^^^^^+*###.%
+D:%..#,#^#,,,,,,#+############,#.%
+D:%..#^#^#,,,,,,#,,,+,,,,,,#^#^#.%
+D:%..+^+^#,,,,,,#,,,#,,,,,,#^+^+.%
+D:%..#^#^#,,,,,,+,,,#,,,,,,#^#^#.%
+D:%..#,############+#,,,,,,#^#,#.%
+D:%..###*+^^^^^^^^^^#,,,,,,+^###.%
+D:%....#######################...%
+D:%..............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:49:Greater vault (nethack building)
+X:8:30:17:54
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%....................................................%
+D:%........XXXXXXXXXXXXX.................XXXXXXXXXXXXX.%
+D:%........X***********X.................X***********X.%
+D:%.XXXXXXXX***********XXXXXXXXXXXXXXXXXXX***********X.%
+D:%.+^^^^^^X,,,,,,,,,,,X**X**X**X**X**X**X*,,,,,,,,,*X.%
+D:%.X^,,,,^X^,,,,,,,,,,X,@X,@X,@X,@X,@X,@X,,,,,,,,,,,X.%
+D:%.X^^^^^^+^^^^^^^^^^^XX+XX+XX+XX+XX+XX+X,,,,,,,,,,,X.%
+D:%.XXXXXXXX^^^^^^^^^^^+^^^^^^^^^^^^^^^^^+,,,,,89,,,,X.%
+D:%.X^^^^^^+^^^^^^^^^^^XX+XX+XX+XX+XX+XX+X,,,,,98,,,,X.%
+D:%.X^,,,,^X^,,,,,,,,,,X,@X,@X,@X,@X,@X,@X,,,,,,,,,,,X.%
+D:%.+^^^^^^X,,,,,,,,,,,X**X**X**X**X**X**X*,,,,,,,,,*X.%
+D:%.XXXXXXXX***********XXXXXXXXXXXXXXXXXXX***********X.%
+D:%........X***********X.................X***********X.%
+D:%........XXXXXXXXXXXXX.................XXXXXXXXXXXXX.%
+D:%....................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:50:Lesser vault (nethack, head)
+X:7:7:17:29
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%........###########........%
+D:%...#####################...%
+D:%...######,,,,,,,,,######...%
+D:%..#+^^^^#,,,,,,,,,#^^^^+#..%
+D:%..##^^^^#,,,,,,,,,+^,,^##..%
+D:%.#####+##,,,,,,,,,#^^^^###.%
+D:%.##^^^^^^,,,,,,,,,########.%
+D:%.####+###++#########*@+*##.%
+D:%.##^^^^^#^^#,,,#^@^####*##.%
+D:%.##^^,,^#^^#,###^#^#****##.%
+D:%..##^,,^#^^#,,,.^#^#@####..%
+D:%..#+^^^^#^^#####^#^^^^^##..%
+D:%...######^^^^^^^^#######...%
+D:%...#####################...%
+D:%........###########........%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:51:Lesser vault (maze of rooms)
+X:7:10:16:32
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..............................%
+D:%.#+##########################.%
+D:%.#^#,,,+^#*#^+,,+*#^+^#*#**@#.%
+D:%.#^+,,,#^+^+^######^#^#*###+#.%
+D:%.#########+###,,,,#^#,+@#,,,#.%
+D:%.#,,,,,,+^^+,,,,,,+^#######+#.%
+D:%.###+#######,,,,,#####,,+^^^#.%
+D:%.#,,,+**#**+,,,,,#^^^+,,#^,^#.%
+D:%.#############+###^,^#+##^^^#.%
+D:%.#***#^+,,#,,,,,,+^^^#^######.%
+D:%.#+###^#,,+,,,,,,#####^+,^^^#.%
+D:%.#,,,+^#,,########,,,+^#,^^^#.%
+D:%.##########################+#.%
+D:%..............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:52:Lesser vault (tetris tiles)
+X:7:5:20:13
+D:%%%%%%%%%%%%%
+D:%..#######..%
+D:%..#**#**#..%
+D:%..#,###,#..%
+D:%..#,#^#,#..%
+D:%.##+#^#+##.%
+D:%.#&,#^#,&#.%
+D:%.#,,+^+,,#.%
+D:%.####+####.%
+D:%.###,^,###.%
+D:%.#*##^##*#.%
+D:%.#,,#+#,,#.%
+D:%.##,#^#,##.%
+D:%.##+#^#+##.%
+D:%.#,,#^#,,#.%
+D:%.##,+^+,##.%
+D:%..#,#+#,#..%
+D:%..###.###..%
+D:%...........%
+D:%%%%%%%%%%%%%
+
+N:53:Lesser vault (hospital ward)
+X:7:5:14:20
+D:%%%%%%%%%%%%%%%%%%%%
+D:%..................%
+D:%.################.%
+D:%.#,,#,,#,,#,,#,,#.%
+D:%.#,,#,,#,,#,,#,,#.%
+D:%.##+##+##+##+##+#.%
+D:%.+..............+.%
+D:%.+..............+.%
+D:%.#+##+##+##+##+##.%
+D:%.#,,#,,#,,#,,#,,#.%
+D:%.#,,#,,#,,#,,#,,#.%
+D:%.################.%
+D:%..................%
+D:%%%%%%%%%%%%%%%%%%%%
+
+N:54:Lesser vault (lesser crypt)
+X:7:5:13:26
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................###.....%
+D:%................#,#.....%
+D:%......#######.###+###...%
+D:%..###.#,#,#,#.#^^^^^#...%
+D:%.##&###+#+#+###^###^###.%
+D:%.+^^^+^^^^^^^+^^#9#^+,#.%
+D:%.##&###+#+#+###^###^###.%
+D:%..###.#,#,#,#.#^^^^^#...%
+D:%......#######.###+###...%
+D:%................#,#.....%
+D:%................###.....%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:55:Lesser vault (arena)
+X:7:5:15:17
+D:%%%%%%%%%%%%%%%%%
+D:%...............%
+D:%.+###########+.%
+D:%.#...........#.%
+D:%.#.####^####.#.%
+D:%.#.#,,,,,,,#.#.%
+D:%.#.#,,,,,,,#.#.%
+D:%.#.^,,,,,,,^.#.%
+D:%.#.#,,,,,,,#.#.%
+D:%.#.#,,,,,,,#.#.%
+D:%.#.####^####.#.%
+D:%.#...........#.%
+D:%.+###########+.%
+D:%...............%
+D:%%%%%%%%%%%%%%%%%
+
+N:56:Lesser vault (monster wc)
+X:7:5:12:12
+D:%%%%%%%%%%%%
+D:%..#######.%
+D:%..#.&&&&#.%
+D:%..#^#####.%
+D:%.##...+,#.%
+D:%.#*...###.%
+D:%.#*...+,#.%
+D:%.#*...###.%
+D:%.##...+,#.%
+D:%..#+#####.%
+D:%..........%
+D:%%%%%%%%%%%%
+
+N:57:Lesser vault ('not' 'and')
+X:7:5:11:15
+D:%%%%%%%%%%%%%%%
+D:%.............%
+D:%..#########..%
+D:%.#+,,,#,,,+#.%
+D:%.#,#,#+#,#,#.%
+D:%.#,,#+*+#,,#.%
+D:%.#,#,#+#,#,#.%
+D:%.#+,,,#,,,+#.%
+D:%..#########..%
+D:%.............%
+D:%%%%%%%%%%%%%%%
+
+N:58:Lesser vault (brain's lair)
+X:7:5:18:17
+D:%%%%%%%%%%%%%%%%%
+D:%...............%
+D:%.#############.%
+D:%.#...........#.%
+D:%.#.####^####.#.%
+D:% #.#...&...#.#.%
+D:%.#.#.#####.#.#.%
+D:%.#.#.#,,,#.#.#.%
+D:%.#.#.#,,,#.#.#.%
+D:%.#.#.#,,,#.#.#.%
+D:%.#.#.##+##.#.#.%
+D:%.^.#..#^#..#.^.%
+D:%.####.#^#.####.%
+D:%.#,,#.#+#.#,,#.%
+D:%.#,,+..&..+,,#.%
+D:%.#############.%
+D:%...............%
+D:%%%%%%%%%%%%%%%%%
+
+N:59:Lesser vault (yin-yang)
+X:7:5:17:16
+D:%%%%%%%%%%%%%%%%
+D:%..............%
+D:%.#+##########.%
+D:%.#&#^^^^^^^^#.%
+D:%.#.#^######^#.%
+D:%.#&#^#****#^#.%
+D:%.#.#^#*,**#^#.%
+D:%.#&#^#****#^#.%
+D:%.#.#+####+#^#.%
+D:%.#&#,,,,#.#^#.%
+D:%.#.#,,*,#&#^#.%
+D:%.#&#,,,,#.#^#.%
+D:%.#.######&#^#.%
+D:%.#&.&.&.&.#^#.%
+D:%.##########+#.%
+D:%..............%
+D:%%%%%%%%%%%%%%%%
+
+N:60:Greater vault (der el bahri)
+X:8:35:28:45
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X***X,,X^^^^^^^^X9988899X^^^^^^^^+******X.%
+D:%.X***X,,+^..,...^X9999999X^...,..^XXXX***X.%
+D:%.X***XXXX^......^XXXX+XXXX^......^X**XXXXX.%
+D:%.X^^^X,,X^..,...^^^^^^^^^^^...,..^X******X.%
+D:%.X@@@X,,X^.......................^X,,,,,,X.%
+D:%.X^^^X,,X^..,..,..,..,..,..,..,..^X,,,,,,X.%
+D:%.X^^^X++X^.......................^X,,,,,,X.%
+D:%.X^^^X^^X^..,..,..,..,..,..,..,..^X,,,,,,X.%
+D:%.X^^^^^^+^.......................^X,,,,,,X.%
+D:%.X^^^^^^X^..,..,..,..,..,..,..,..^X,,,,,,X.%
+D:%.XXX+XXXX^.......................^X,,,,,,X.%
+D:%.X***X**X^..,..,..,..,..,..,..,..^X,,,,,,X.%
+D:%.XXXXX**X^.......................^X,,,,,,X.%
+D:%.X,,,,,,+^.......................^+,,,,,,X.%
+D:%.X,,,,,,+^^^^^^^^^^^^^^^^^^^^^^^^^+,,,,,,X.%
+D:%.XXXXXXXXXXXXXXXXXXX+++XXXXXXXXXXXXXXXXXXX.%
+D:%.X.............^^^^^^^^^^^^..............X.%
+D:%.X................^^^^^^^................X.%
+D:%.XXXXXXXXXXXXXXXXXXX^^^XXXXXXXXXXXXXXXXXXX.%
+D:%.X.................X.^.X.................X.%
+D:%.X.X.X.X.X.X.X.X.X.X^^^X.X.X.X.X.X.X.X.X.X.%
+D:%.X.................X.^.X.................X.%
+D:%.X.X.X.X.X.X.X.X.X.X^^^X.X.X.X.X.X.X.X.X.X.%
+D:%.X.................X.^.X.................X.%
+D:%...........................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:61:Lesser vault (der el bahri sanctuary)
+X:7:5:12:22
+D:%%%%%%%%%%%%%%%%%%%%%%
+D:%....................%
+D:%..........###.......%
+D:%..........#,#.......%
+D:%..###.###.#,#.......%
+D:%.##,###,###,#######.%
+D:%.+^^^^^^^+^^^+,,,,#.%
+D:%.+^^^^^^^+^^^+,,,,#.%
+D:%.######+###########.%
+D:%......###...........%
+D:%....................%
+D:%%%%%%%%%%%%%%%%%%%%%%
+
+N:62:Greater vault (hypostyle of ramses III)
+X:8:40:38:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X888888+*******X*******+88888X.%
+D:%.XXXXXXXXX+XXXXXXXXXXX+XXXXXXXX.%
+D:%.X99+***+^^^+^^^^^^^+^^^+**+99X.%
+D:%.XXXXXXXXXXXXXX+++XXXXXXXXXXXXX.%
+D:%.X**X,,X,,+^X^^^^^^^X^X,,,+***X.%
+D:%.X**X,,X,,X^X^X...X^X^X,,,XXXXX.%
+D:%.X+XX,,X,,X^X^..@..^X^X,,,X***X.%
+D:%.X,,X,,XXXX^X^X...X^X^X^^^X***X.%
+D:%.X,,X,,X,*X^X^^^^^^^X^XX+XXXX+X.%
+D:%.X+XXX+X+XX^XXX+++XXX^X^^X,,,,X.%
+D:%.X^^^^^X^^+^^^^^^^^^^^+^^X,**,X.%
+D:%.X+XXXXXXXX^X.X...X.X^XXXX,**,X.%
+D:%.X^^^^^X,,X^.........^X**X,**,X.%
+D:%.X^X,X^X,,X^X.X.@.X.X^X++X,,,,X.%
+D:%.X^^^^^X,,X^.........^+^^X^^^^X.%
+D:%.XXX+XXX++X^XXX...XXX^XXXX+XXXX.%
+D:%.X^^^^^^^^+^....&....^+****+^^X.%
+D:%.XXXXXXXXXX^X.X...X.X^XXXXXXX^X.%
+D:%.X^^^^^+^^X^.........^X^^^^^^^X.%
+D:%.X^#X#^X^^X^X.X.&.X.X^X^,*XXXXX.%
+D:%.X^X9X^X^^X^.........^X^,*X***X.%
+D:%.X^#X#^X^^X^X.X...X.X^X^,*XXX+X.%
+D:%.X^^^^^X^^X^^^^^^^^^^^X^^^X,,,X.%
+D:%.XXXXXXX++XXXXX+++XXXXXX+XX,,,X.%
+D:%.X*****+^^^^^^^^^^^^^^^^^+,,,,X.%
+D:%.XXXXXXX^.X.X.X...X.X.X.^XXXXXX.%
+D:%.X,,X,,X^...............^+,,,,X.%
+D:%.X,,X,,X^.X.X.X...X.X.X.^XXXXXX.%
+D:%.X++X++X^.....&.&.&.....^+,,,,X.%
+D:%.X^^^^^+^.X.X.X...X.X.X.^XXXXXX.%
+D:%.X++X++X^...............^+,,,,X.%
+D:%.X,,X,,X^.X.X.X...X.X.X.^XXXXXX.%
+D:%.X,,X,,X^^^^^^^^^^^^^^^^^+,,,,X.%
+D:%.XXXXXXXXXXXXXX+++XXXXXXXXXXXXX.%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:63:Lesser vault (amada temple)
+X:7:10:15:30
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%............................%
+D:%.######################.....%
+D:%.#**#,,,,+^^#.....&...#.....%
+D:%.#**#,,,,#^^#...&.....#.....%
+D:%.#+#######^^#..#.#.#.##.....%
+D:%.#,,,,,,,#^^#^^^^^^^^^#####.%
+D:%.#,,,,,,,+^^+^^^^^^^^^+^^^+.%
+D:%.#,,,,,,,#^^#^^^^^^^^^#####.%
+D:%.#+#######^^#..#.#.#.##.....%
+D:%.#**#,,,,#^^#...&..&..#.....%
+D:%.#**#,,,,+^^#.........#.....%
+D:%.######################.....%
+D:%............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:64:Lesser vault (amenhotep I)
+X:7:10:18:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................................%
+D:%...............######...........%
+D:%...............#.&&.#...........%
+D:%.###############.##.#...........%
+D:%.#**#,,,+^^^^^^^^##.###.........%
+D:%.#**#,,,#^^^^^^^^^^...#########.%
+D:%.##+#####^^#######^&#.#.......#.%
+D:%.#,,,,,,+^^+,*,*,+^^^^^^^^^^^^+.%
+D:%.#,,,,,,+^^+*,*,*+^^^^^^^^^^^^+.%
+D:%.##+#####^^#######^&#.#.......#.%
+D:%.#**#,,,#^^^^^^^^^^...#########.%
+D:%.#**#,,,+^^^^^^^^##.###.........%
+D:%.###############.##.#...........%
+D:%...............#.&&.#...........%
+D:%...............######...........%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:65:Lesser vault (hathor chapel)
+X:7:10:21:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%.................%
+D:%......##+###.....%
+D:%.######^^^######.%
+D:%.#,,#^#...#^#,,#.%
+D:%.#,,+^..*..^+,,#.%
+D:%.#,,#^#...#^#,,#.%
+D:%.####^.....^####.%
+D:%....#^^^^^^^#....%
+D:%....#.##+##.#....%
+D:%....#&#^^^#&#....%
+D:%....###,^,###....%
+D:%....#,,,,,,,#....%
+D:%....####+####....%
+D:%....#,,,,,,,#....%
+D:%....####+####....%
+D:%....#,,,,,,,#....%
+D:%....####+####....%
+D:%.....#*****#.....%
+D:%.....#######.....%
+D:%%%%%%%%%%%%%%%%%%%
+
+
+N:66:Lesser vault (osiris halls)
+X:7:10:17:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................................%
+D:%.###########################....%
+D:%.#*,+^^^^^#^^^^^^^^^^^^+,,*#....%
+D:%.####^#.#^#^#.#.#.#.#.^#####....%
+D:%.#*,+^.&.^+^..&...&...^+,,*#....%
+D:%.####^#.#^#^#.#.#.#.#.^#####....%
+D:%.#*,+^^^^^#^^^^^^^^^^^^+,,*#....%
+D:%.####################++########.%
+D:%.#,,#,,#,,#,,#,,#,,#....#,,#,,#.%
+D:%.#,,#,,#,,#,,#,,#,,#....#,,#,,#.%
+D:%.#,,#,,#,,#,,#,,#,,#.&..#,,#,,#.%
+D:%.#++#++#++#++#++#++#....#++#++#.%
+D:%.#^^^^^^^^^^^^^^^^^^^^^^^^^^^^+.%
+D:%.##############################.%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:67:Lesser vault (temple of sety)
+X:7:10:22:25
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.##########+##########.%
+D:%.#,,,,,,,#^^^#,,,,,,,#.%
+D:%.#,,,,,,,+^^^+,,,,,,,#.%
+D:%.#########^^^#########.%
+D:%.#,,,,,,,#^^^#,,,,,,,#.%
+D:%.#,,,,,,,+^^^+,,,,,,,#.%
+D:%.#########+###########.%
+D:%.#^^^+^^^+^^^^^#,.,.,#.%
+D:%.#.#^#^#.#^#.#.#.#.#.#.%
+D:%.#.&^#^.&#^.&..#,.,.,#.%
+D:%.#.#^+^#.#^#.#.#.#.#.#.%
+D:%.#^^^#^^^#^^^^^#,.,.,#.%
+D:%.#+#+###+###+###.#.#.#.%
+D:%.#,#^^^^^^^^^^^#,.,.,#.%
+D:%.#,#.#.#.#.#.#.#+###^#.%
+D:%.#,#...........#,**#^#.%
+D:%.#*#.#.#.#.#.#.#####+#.%
+D:%.#*#^^^^^^^^^^^+&^^^&#.%
+D:%.#######+#############.%
+D:%.......................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:68:Lesser vault (temple at abydos)
+X:7:10:21:23
+D:%%%%%%%%%%%%%%%%%%%%%%%
+D:%^^^^^^^^^^^^^^^^^^^^^%
+D:%^#+#+#####+#####+#+#^%
+D:%^#,#,#^^^^^^^^^#,#,#^%
+D:%^#,#,#^#.#.#.#^#,#,#^%
+D:%^#,#,#^...&...^#,#,#^%
+D:%^#####^#.#.#.#^#####^%
+D:%^#*,,+^^^^^^^^^+,,*#^%
+D:%^#########+#########^%
+D:%^#*,,+^^^^^^^^^+,,*#^%
+D:%^#####^#.#.#.#^#####^%
+D:%^#*,,+^...&...^+,,*#^%
+D:%^#####^#.#.#.#^#####^%
+D:%^#*,,+^^^^^^^^^+,,*#^%
+D:%^##+###+##+##+###+##^%
+D:%^#,,,,#,#^^^#,#,,,,#^%
+D:%^#,##,#,#,#,#,#,##,#^%
+D:%^#,,,,#,#***#,#,,,,#^%
+D:%^###################^%
+D:%^^^^^^^^^^^^^^^^^^^^^%
+D:%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:69:Greater vault (Spiral castle)
+X:8:35:31:25
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................%
+D:%.XXXXX...........XXXXX.%
+D:%.X,,,X...........X,,,X.%
+D:%.X,,,X...........X,,,X.%
+D:%.XXX+XXXXXXXXXXXXX+XXX.%
+D:%...X^^^^^^^^^^^^^^^X...%
+D:%...X^XXXXXXXXXXXXX^X...%
+D:%...X^X^^^^^^^^^^^+^X...%
+D:%...X^X^XXXXXXXXXXX^X...%
+D:%...X^X^X&..&....&X^X...%
+D:%...X^X^X.XXXXXXX.X^X...%
+D:%...X^X^X.X^^^^^X.X^X...%
+D:%...X^X^X&X+XXX^X.X^X...%
+D:%...X^X^X.X*9*X^X&X^X...%
+D:%...+^X^X,X989X^X.X^+...%
+D:%...X^X^X.X*9*X^X.X^X...%
+D:%...X^X^X.XXX+X^X,X^X...%
+D:%...X^X^X..&..X^X.X^X...%
+D:%...X^X.XXXXXXX^X.X^X...%
+D:%...X^X^^^^^^^^^X&X^X...%
+D:%...X^XXXXXXXXXXX.X^X...%
+D:%...X^+...&..&...,X^X...%
+D:%...X^XXXXXXXXXXXXX^X...%
+D:%...X^^^^^^^^^^^^^^^X...%
+D:%.XXX+XXXXXXXXXXXXX+XXX.%
+D:%.X,,,X...........X,,,X.%
+D:%.X,,,X...........X,,,X.%
+D:%.XXXXX...........XXXXX.%
+D:%.......................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:70:Lesser vault (temple of dendereh)
+X:7:10:20:22
+D:%%%%%%%%%%%%%%%%%%%%%%
+D:%....................%
+D:%.##################.%
+D:%.#***+^&#**#&^+***#.%
+D:%.#***#^^#,,#^^#***#.%
+D:%.#####++#++#++#####.%
+D:%.#,,,+^^^^^^^^+,,,#.%
+D:%.#####^######^#####.%
+D:%.#,,,+^#,,,,#^+,,,#.%
+D:%.#####^#,**,#^#####.%
+D:%.#,,,+^#,**,#^#***#.%
+D:%.#####^#,**,#^#^^^#.%
+D:%.#,,,+^#,**,#^##+##.%
+D:%.#####^#,,,,#^#,,,#.%
+D:%.#,,,#^##++##^#&,&#.%
+D:%.#,,,+^^^^^^^^##+##.%
+D:%.#,,,#^^^^^^^^^^^^#.%
+D:%.########++########.%
+D:%....................%
+D:%%%%%%%%%%%%%%%%%%%%%%
+
+
+N:71:Greater vault (Karnak, part I)
+X:8:35:24:44
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X*****+^+^^^^+^^^X,,,X***X***X***X,****X.%
+D:%.XXXXXXXXX^XX^X,,,X,X,X,X,X,X,X*X*X,X*X*X.%
+D:%.X,X,X,X,X^..^X,,,X,,,X^^^X^^^X**@+^,,,,X.%
+D:%.X^^^^^^^+^@.^X,,,XX+XX+XXXXX+XXXXX+XXXXX.%
+D:%.X,X^^^X,X^XX^X***X^^^+^^^^^^^+,,*X^^^^^X.%
+D:%.XXXX+XXXX^^^^X,,,XXXXX^X.X.X^XXXXX^X^X^X.%
+D:%.X^^^^^^^XXXXXX,,,X,,,X^..@..^+,,*X^^^^&X.%
+D:%.X^X,X,X^X,,,,X,,,X,X,X^X.X.X^XXXXX^XXXXX.%
+D:%.X^^^^^^^X,,,,X^^^X,,,X^^^^^^^+,,*X^+,,*X.%
+D:%.XXXX+XXXXX++XXX+XXX+XXXXX+XXXXXXXX^XXXXX.%
+D:%.X*,+^^^^^^^^^^^^^^^^^^^^^^^^^+,,*X^+,,*X.%
+D:%.XXXX^X.X.X.X.X.X.X.X.X.X.X.X^XXXXX^XXXXX.%
+D:%.X*,+^.........&.....&.......^X,,*X^+,,*X.%
+D:%.XXXX^X.X.X.X.X.X.X.X.X.X.X.X^+,X*X^XXXXX.%
+D:%.X**X^.......................^X,,*X^+,,*X.%
+D:%.X,,+^X.X.X.X.X.X.X.X.X.X.X.X^XXXXX^XXXXX.%
+D:%.XXXX^.........&.....&.......^+^^^^^+,,*X.%
+D:%.X,,+^X.X.X.X.X.X.X.X.X.X.X.X^X,X,X^XXXXX.%
+D:%.X**X^^^^^^^^^^^^^^^^^^^^^^^^^X.*.X^+,,*X.%
+D:%.XXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXXXXXX.%
+D:%..........................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:72:Lesser vault (Karnak, part II)
+X:7:10:20:29
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%...........................%
+D:%.###+######################%
+D:%.#,+^#,,#,,#^+^+^#*#,#^+,#.%
+D:%.###.#,,#,,#^#^#^#*#,#^###.%
+D:%.#,+^#,,#,,#^#^#^#*#+#^+,#.%
+D:%.###.#++#++#^#^#^#+#.#^###.%
+D:%.#,+^#^^^^^+^#^#^+,,,#^+,#.%
+D:%.###.#^^^^^+^#^#+#+###^###.%
+D:%.#,+^#+#+#+#^#^#,#^+,#^+,#.%
+D:%.###.#,#,#,#^#^#######^###.%
+D:%.#,+^#######+#,,+,,,,,^+,#.%
+D:%.###^^^^^^#,^#,,+,,,,#^###.%
+D:%.#,+^#,#*^##+####,,,,,^+,#.%
+D:%.###^,,,*^#^^^^^#,,,,#^###.%
+D:%.#,+^#,#*^#,,,,^+,,,,,^+,#.%
+D:%.###^^^^^^#^^^^^#,,,,,^###.%
+D:%...##########+##########...%
+D:%...........................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:73:Greater vault (mortuary temple of sety)
+X:8:35:25:34
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X^+,,***X,,+^^^^^+,,X*X,,X*X9X.%
+D:%.X^XXXXXXX,,X^X*X^X,,X,X,,X*X9X.%
+D:%.X^+,,***XXXX^*@*^X,,X^X,,X@X9X.%
+D:%.X^XXXXXXX,,X^X*X^XXXX^X,,X^X9X.%
+D:%.X^+,,***X,,+^^^^^+..X^X,,X^X^X.%
+D:%.X^XXXXXXXXXXXX+XXXXXX+X++X+X+X.%
+D:%.X^X*X*X*X**X,+.+,X**X^^^^+^^^X.%
+D:%.X+X,X,X,X,,XXX.XXX,,X^^^^+^^^X.%
+D:%.X^X^X^X^X,,X,X.X,X,,X^^XXXXXXX.%
+D:%.X^X+X+X+X^^X,X.X,X^^X^^X,,,,,X.%
+D:%.X^+^^^^^X++X+X+X+X++X^^X,X,X,X.%
+D:%.X^XXXXXXX^^^^^^^^^^^X^^X,,,,,X.%
+D:%.X^X*X*X*XXXX^...^XXXX^^X,X,X,X.%
+D:%.X^X,X,X,X,,+^X*X^+,,X^^X,,,,,X.%
+D:%.X^X^X^X^XXXX^.&.^XXXX^^X,X,X,X.%
+D:%.X^X+X+X+X,,+^X*X^+,,X^^X,,,,,X.%
+D:%.X^X^^^^^XXXX^...^XXXX^^X,X,X,X.%
+D:%.X^X*X,X*X,,X^X*X^X,,X^^X,,,,,X.%
+D:%.X^+^^^^^+^^+^^^^^+^^+^^X,,,,,X.%
+D:%.XXXXXXXXXXXXXX+XXXXXXXXXXX+XXX.%
+D:%................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:74:Lesser vault (edfu)
+X:7:5:15:15
+D:%%%%%%%%%%%%%%%
+D:%.............%
+D:%.###########.%
+D:%.#,+^#,#^+,#.%
+D:%.###+#+#+###.%
+D:%.#,+^...^+,#.%
+D:%.###.###.###.%
+D:%.#,+.#*#.+,#.%
+D:%.###.#,#.###.%
+D:%.#,+.#^#.#,#.%
+D:%.###^...^#+#.%
+D:%.#,+,#+#,+,#.%
+D:%.#####^#####.%
+D:%.............%
+D:%%%%%%%%%%%%%%%
+
+N:75:Greater vault (kom ombo)
+X:8:40:36:30
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X****X,99,X9889X,99,X****X.%
+D:%.X****X,,,,X9999X,,,,X****X.%
+D:%.X+XXXX+XXXX+XXXX+XXXX+XXXX.%
+D:%.X@^^^^^^^^^^^^^^^^^^^^^^@X.%
+D:%.X^XXXXXXXXXXXXXXXXXXXXXX^X.%
+D:%.X^X**X,,X,,X,,X,,X,,X**X^X.%
+D:%.X^X,,X+XX+XX+XXX+XX+X,,X^X.%
+D:%.X^X,^+^^^^^^^^^^^^^^+^,X^X.%
+D:%.X^XXXX^XX+XX^^XX+XX^XXXX^X.%
+D:%.X^X,,X^X,,,X^^X,,,X^+^,X^X.%
+D:%.X^X,,X^X***X^^X***X^X,*X^X.%
+D:%.X^X,,X^X9X9X^^X9X9X^XXXX^X.%
+D:%.X^X,,X^X***X^^X***X^+^,X^X.%
+D:%.X^X++X^X,,,X^^X,,,X^X,*X^X.%
+D:%.X^X^^X^XX+XX^^XX+XX^XXXX^X.%
+D:%.X^X^^+^^^^^^^^^^^^^^X,*X^X.%
+D:%.X^X,,X^^^^^^^^^^^^^^+^,X^X.%
+D:%.X^XXXXXXX+XXXXXX+XXXXXXX^X.%
+D:%.X^X,X,X,,,,,XX,,,,,X***X^X.%
+D:%.X^X,X^X,***,++,***,+*@*X^X.%
+D:%.X^X,+^+,,,,,XX,,,,,X***X^X.%
+D:%.X^XXX+XXX+XXXXXX+XXXX+XX^X.%
+D:%.X^X*,^X,,,,,XX,,,,,+^^*X^X.%
+D:%.X^X,,^+,,*,,++,,*,,XX+XX^X.%
+D:%.X^X*,*X,,,,,XX,,,,,X,,,X^X.%
+D:%.X^XXXXXXX+XXXXXX+XXXXXXX^X.%
+D:%.X^X^^^^^^^^^^^^^^^^^^^^X^X.%
+D:%.X^X^^XX,XX^^XX^^XX,XX^^X^X.%
+D:%.X^X^^^^^^^^^^^^^^^^^^^^X^X.%
+D:%.X^+^^XX,XX^^XX^^XX,XX^^+^X.%
+D:%.X,X^^^^^^^^^^^^^^^^^^^^X,X.%
+D:%.XXXXXXXXX+XXXXXX+XXXXXXXXX.%
+D:%............................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:76:Lesser vault (belvoir keep)
+X:7:5:19:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%...................%
+D:%.###...........###.%
+D:%.#,######+######,#.%
+D:%.##+^^^^+&+^^^^+##.%
+D:%..#&^####+####^.#..%
+D:%..#.^#,^+^+,,#^.#..%
+D:%..#.^#,^#^#,,#^.#..%
+D:%..#.^#,*#^##+#^.#..%
+D:%..#.^#,^#^#,,#^&#..%
+D:%..#.^#,^+^#*,#^.#..%
+D:%..#.^####+####^.#..%
+D:%.##+^^^^^^^^^^^+##.%
+D:%.#,######+######,#.%
+D:%.###...#,*,#...###.%
+D:%.......#*,*#.......%
+D:%.......#####.......%
+D:%...................%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+#N:77:Lesser vault (Pattern)
+#X:8:30:31:47
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+#D:%X@&+.............................+&@X,,,,,,X.%
+#D:%XXXX.p...bad.bad.bad.bad.cbb.....XXXX,,,,,,X.%
+#D:%X@&X.a.dcb.dcb.dcb.dcb.dcc.baa...X&@X,,,,,,X.%
+#D:%XX+X.b.d.....................ad..X+XX,,,,,,X.%
+#D:%X....c.a.dabcdabcda...........dc....X,,,,,,X.%
+#D:%X....d.b.d........a..cbadcba...c....X,,,,,,X.%
+#D:%X...ad.c.c.dcbadcba..c.....ad..cb...X++XXX+X.%
+#D:%X...a..d.b.d.........cdabc..d...b...X^^X^^^X.%
+#D:%X...b.ad.a.a..abcd.......cd.dcb.a...X**X^X+X.%
+#D:%X..cb.a..d.b..a..d..adcb..d...b.ad..X,,X^X^X.%
+#D:%X..c..b..c.c..d.ad..a..ba.a...a..d..X&&X^X&X.%
+#D:%X.dc.cb..b.d..c.a..PPP..a.a.cda..dc.X^^X^X+X.%
+#D:%X.d..c...a.a..b.b.PPAPP.d.b.c.....c.+^^X^X*X.%
+#D:%X.da.cd..d.b..a.c.PABAP.c.b.cba..bc.X^^X^X*X.%
+#D:%X..a..d..c.c..d.d.PPAPP.b.c...a..b..X&&X^XXX.%
+#D:%X..ab.da.b.d..c.a..PPP..a.c...d.ab..X,,X^X,X.%
+#D:%X...b..a.a.a..b.ab.....da.d..cd.a...XXXX+X+X.%
+#D:%X...c..b.d.b..a..bcd.bcd..a.bc..d...X**^^^,X.%
+#D:%X...cd.bcd.c..ad...dab...ba.b..cd...X,,,,,,X.%
+#D:%X....d.....d...dc......dcb..a..c....X,,,XXXX.%
+#D:%X....da....da...cbadcbad...da.bc....X,,,+,,X.%
+#D:%X.....a.....abc...........cd..b.....X,,,X,,X.%
+#D:%XX+X..ab......cdabcdabcdabc..ab..X+XXXXXX,,X.%
+#D:%X@&X...bc...................da...X&@X,,,,,,X.%
+#D:%XXXX....cddaabbccddaabbcdabcd....XXXX,,,,,&+.%
+#D:%X@&+.............................+&@X****&&+.%
+#D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX++X.%
+#D:%.............................................%
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#
+#
+#N:78:Greater vault (Pattern 2)
+#X:8:30:29:45
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+#D:%X8+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+8X%
+#D:%X+XXXXXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXX+X%
+#D:%X^X.....................................X^X%
+#D:%X^X.................p...................X^X%
+#D:%X^X.........adcbadcba.dcbadcbad.........X^X%
+#D:%X@X......dcba.........d.......dcba......X@X%
+#D:%X,X...baad.....abcdab.dabcda.....addc...X,X%
+#D:%X,X..cb.....bcda....b......abcd.....cb..X,X%
+#D:%X,X.dc....dab....adcb.adcb....dab....ba.X,X%
+#D:%X,X.d....cd....cba....a..bad....bc....a.X,X%
+#D:%X,X.a...bc...adc...PPPPP...dcb...cd...d.X,X%
+#D:%X,X.b...b....a....PPPAPPP....b....d...c.X,X%
+#D:%X,X.c...a....b....PPABAPP....a....a...c.X,X%
+#D:%X,X.d...d....c....PPPAPPP....d....b...b.X,X%
+#D:%X,X.a...dc...cda...PPPPP...bcd...cb...b.X,X%
+#D:%X,X.b....cb....abc.......dab....dc....a.X,X%
+#D:%X,X.bc....bad....cddaabbcd....bad....da.X,X%
+#D:%X,X..cd.....dcba...........adcb.....cd..X,X%
+#D:%X,X...dabc.....adcbadcbadcba.....dabc...X,X%
+#D:%X^X......cdab.................abcd......X^X%
+#D:%X^X.........bccddaabcdabcdabcda.........X^X%
+#D:%X^X.....................................X^X%
+#D:%X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+#D:%X9+^^^@,,,,,&,,,,,,,,&,,,,,,,&,,,,,,@^^^+9X%
+#D:%XXXXXXXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXXXX%
+#D:%...........................................%
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#
+#
+#
+#N:79:Greater vault (Pattern 2)
+#X:8:30:30:42
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+#D:%.X9+^^^^^^^^^^^^^^^^^+,,,,,,,,,,,,,,,+8X%
+#D:%.X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+#D:%.X,X.................................X^X%
+#D:%.X,X....adcbadcbadcbadcbadcbadc......X^X%
+#D:%.X,X...ba.....................cbad...X^X%
+#D:%.X,X..cb..bad.bad.bad.bad.bad....d...X^X%
+#D:%.X,X..c..cb.dcb.dcb.dcb.dcb.dcba.dc..X^X%
+#D:%.X&X..d.dc.....................a..c..X^X%
+#D:%.X&X..d.d..bbcc...cbadcba..adc.ad.b..X^X%
+#D:%.X+X..a.a.ab..cd.dc.....ad.a.c..d.a..X+X%
+#D:%.X^X..a.b.a....d.d..PPP..d.b.c.cd.d..X@X%
+#D:%&X^X..b.c.ad...a.a.PPAPP.c.c.b.c..dc.X9X%
+#D:%.+^X..b.d..dc..a.b.PABAP.b.d.b.cb..c.+8X%
+#D:%&X^X..c.a...cb.b.c.PPAPP.a.a.a..b..b.X9X%
+#D:%.X^X..d.b....b.c.d..PPP..d.b.d.ab..a.X@X%
+#D:%.X+X..a.c.cdab.d.da..d...dcb.d.a..da.X+X%
+#D:%.X&X..b.d.c....a..abcd.......c.ad.d..X^X%
+#D:%.X&X..c.a.cbad.ab......abc..bc..d.c..X^X%
+#D:%.X,X..d.b....d..bcdabcda.cdab..cd.b..X^X%
+#D:%.X,X..a.bcda.c................bc..a..X^X%
+#D:%.X,X..b....abc..dab.dab.dab.dab..da..X^X%
+#D:%.X,X..bcda.....cd.bcd.bcd.bcd...cd...X^X%
+#D:%.X,X.....abcdabc..............pbc....X^X%
+#D:%.X,X.................................X^X%
+#D:%.X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+#D:%.X9+^^^^^^^^^^^^^^^^^+,,,,,,,,,,,,,,,+8X%
+#D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+#D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+# XXX
+
+# XXX
+
+N:82:Lesser vault (checkerboard)
+X:7:5:13:21
+D:%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXX%
+D:%X&#9#&#9#&#9#&#9#&+%
+D:%X#XXXXXXXXXXXXXXXXX%
+D:%X9#&#9#&#9#&#9#&#9X%
+D:%XXXXXXXXXXXXXXXXX#X%
+D:%X&#9#&#88888#&#9#&X%
+D:%X#XXXXXXXXXXXXXXXXX%
+D:%X9#&#9#&#9#&#9#&#9X%
+D:%XXXXXXXXXXXXXXXXX#X%
+D:%+&#9#&#9#&#9#&#9#&X%
+D:%XXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%
+
+
+N:83:Lesser vault (spiral checkers)
+X:7:5:14:17
+D:%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXX%
+D:%X&#9#&#9#&#9#&X%
+D:%+XXXXXXXXXXXX#X%
+D:%XXX@#9#@#9#@X9X%
+D:%X9#XXXXXXXX#X#X%
+D:%X#XXX98X89#9X&X%
+D:%X&X9#98X89XXX#X%
+D:%X#X#XXXXXXXX#9X%
+D:%X9X@#9#@#9#@XXX%
+D:%X#XXXXXXXXXXXX+%
+D:%X&#9#&#9#&#9#&X%
+D:%XXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%
+
+
+N:84:Greater vault (monstrosity)
+X:8:25:17:28
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X^@^@^@^@^@#X9X9X9X9X9X9XX%
+D:%X#XXXXXXXXXX9X9X9X9X9X9X9X%
+D:%XX9X9X9X9XXXXXXXXXXXXXXX#X%
+D:%X9X9X9X9X9X##############X%
+D:%XXXXXXXXX#X#XXXXXXXXXXXXXX%
+D:%X&,&X&,&X&X8888X&,&X&,&X&+%
+D:%X,X,X,X,X,XXXXXX,X,X,X,X,X%
+D:%+&X&,&X&,&X8888X&X&,&X&,&X%
+D:%XXXXXXXXXXXXXX#X#XXXXXXXXX%
+D:%X##############X9X9X9X9X9X%
+D:%X#XXXXXXXXXXXXXXX9X9X9X9XX%
+D:%X9X9X9X9X9X9X9XXXXXXXXXX#X%
+D:%XX9X9X9X9X9X9X#@^@^@^@^@^X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:85:Cyclone
+X:8:40:23:91
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%XXXX^^^^^^^^^XXX^^^^^^^^^XXX^^^#XXX8.X.&.X.&.X..*X+^.^.^.^.^.^..XX*^.^.^.^.^.^.^.^.^.^#8X%
+D:%XX***XXX...XXX...XXX...XXX...XXX^^X*.X^X^X^X^X^X.*XXXXXXXXXXXXX..XX^^XXXXXXXXXXXXXXXXXX#X%
+D:%X88XXX...XXX...XXX...XXX...XXX^^^,X*.X^X^X^X^X^X..*XX8@,,,,,,@XX,.XX^^..........@&.,**X.X%
+D:%XXXX@&@XXX@@@XXX&&&XXX&@&XXX^^^,..X*.X^X^X^X^X^X...@X@........@X,..X...........@&..,**X.X%
+D:%XX...XXX...XXX...XXX...XXX^^^,....X*.X^X^X^X^X^X...@X*..*9*..@XX^^XXXX*.......@&@..,**X.X%
+D:%X*.XXX...XXX...XXX...XXX^^^^....,,X*.&.X.&.X.&.X..*XX*.....,XXX.XXX@@XXX*....@&..@.,**X.X%
+D:%X*XX...XXX...XXX...XXX^^^,.^...XX+XXXXXXXXXXXXXX.*XX*....,,XXX.XXXXXX&&XXX*.@&....@8**X.X%
+D:%X^^^^XXX^^^^^^^^^XXX^^^,..*^.&XX.*X&^^*****^^#X.*XX*....,XXX&&XXX@@X#X*..XX@&.....8@**X.X%
+D:%XXXXXXXXXXXXXXXXXX^^^,...**^.&X8.*X@XXXXXXXXXX^.XX&....XXX&&XXX*****XXX*..XXXXXXXXXXXXX.X%
+D:%#^^^^^^^^^^^^^9#^^^.....*99^.@X8.*#^^^*****8XXXXX8@..XX#@@XX#@@@....8XXX*.+^.^.^.^.^.^+.X%
+D:%XXXXXXXXXXXXXXXXXX^^^,...**^.&X8.*X@XXXXXXXXXX^.XX&....XXX&&XXX*****XXX*..XXXXXXXXXXXXX.X%
+D:%X^^^^XXX^^^^^^^^^XXX^^^,..*^.&XX.*X&^^*****^^#X.*XX*....,XXX&&XXX@@X#X*..XX@&.....8@**X.X%
+D:%X*XX...XXX...XXX...XXX^^^,.^...XX+XXXXXXXXXXXXXX.*XX*....,,XXX.XXXXXX&&XXX*.@&....@8**X.X%
+D:%X*.XXX...XXX...XXX...XXX^^^^....,,X*.&.X.&.X.&.X..*XX*.....,XXX.XXX@@XXX*....@&..@.,**X.X%
+D:%XX...XXX...XXX...XXX...XXX^^^,....X*.X^X^X^X^X^X...@X*..*9*..@XX^^XXXX*.......@&@..,**X.X%
+D:%XXXX@&@XXX@@@XXX&&&XXX&@&XXX^^^,..X*.X^X^X^X^X^X...@X@........@X,..X...........@&..,**X.X%
+D:%X88XXX...XXX...XXX...XXX...XXX^^^,X*.X^X^X^X^X^X..*XX8@,,,,,,@XX,.XX^^..........@&.,**X.X%
+D:%XX***XXX...XXX...XXX...XXX...XXX^^X*.X^X^X^X^X^X.*XXXXXXXXXXXXX..XX^^XXXXXXXXXXXXXXXXXX#X%
+D:%XXXX^^^^^^^^^XXX^^^^^^^^^XXX^^^#XXX8.X.&.X.&.X..*X+^.^.^.^.^.^..XX*^.^.^.^.^.^.^.^.^.^#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:86:Miniature Cell
+X:7:5:5:5
+D:%%%%%
+D:%#8#%
+D:%888%
+D:%#8#%
+D:%%%%%
+
+N:87:Castle Death
+X:8:35:20:60
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+XX....+XX...X****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....XXX....@X****X%
+D:%X.........................................XXX....&.@X****X%
+D:%X+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX....@.&.@X*99*X%
+D:%X999X..9..X&&&&&X,,,,,X@@@@@X..&..X@@@XXX....&.@.&.@X*99*X%
+D:%X@@@X.&.&.X&&&&&X,,,,,X@@@@@X99.99X9XXX.X..@.&.@.&.@X****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...X..@.&.@.&.@XX##XX%
+D:%+^...&.&.&+...@.@.@+...@@@@@+.....99+...+..@.&.@.&.8+^^^^X%
+D:%+^...&.&.&+...@.@.@+...@@@@@+.....99+...+..@.&.@.&.8+^^^^X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...X..@.&.@.&.@XX##XX%
+D:%X@@@X.&.&.X&&&&&X,,,,,X@@@@@X99.99X9XXX.X..@.&.@.&.@X****X%
+D:%X999X..9..X&&&&&X,,,,,X@@@@@X..&..X@@@XXX....&.@.&.@X*99*X%
+D:%X+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX+XXXXX....@.&.@X*99*X%
+D:%X.........................................XXX....&.@X****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....XXX....@X****X%
+D:%X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+XX....+XX...X****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:88:Mirrored Quartet
+X:8:20:21:49
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X89@@@XXX,,,,XXX....^^^^^^^....XXX,,,,XXX@@@98X%
+D:%X9@@#XX....XXX**....XXX#XXX....**XXX....XX#@@9X%
+D:%X@XXX&&&&XXX**....@XX&&@&&XX@....**XXX&&&&XXX@X%
+D:%XXX....XXX**......@X**...**X@......**XXX....XXX%
+D:%X@...XXX**.......XXXXX...XXXXX.......**XXX...@X%
+D:%X@.#XX**.......9XX888XX^XX888XX9.......**XX#.@X%
+D:%XXXX&&&&&&&&&&&9#,,,,,X^X,,,,,#9&&&&&&&&&&&XXXX%
+D:%XXXXXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXX%
+D:%%,,,,,,,,,,,,,,,,,,,,,#8#,,,,,,,,,,,,,,,,,,,,,%%
+D:%XXXXXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXX%
+D:%XXXX&&&&&&&&&&&9#,,,,,X^X,,,,,#9&&&&&&&&&&&XXXX%
+D:%X@.#XX**.......9XX888XX^XX888XX9.......**XX#.@X%
+D:%X@...XXX**.......XXXXX...XXXXX.......**XXX...@X%
+D:%XXX....XXX**......@X**...**X@......**XXX....XXX%
+D:%X@XXX&&&&XXX**....@XX&&@&&XX@....**XXX&&&&XXX@X%
+D:%X9@@#XX....XXX**....XXX#XXX....**XXX....XX#@@9X%
+D:%X89@@@XXX,,,,XXX**..^^^^^^^..**XXX,,,,XXX@@@98X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:89:False Wall
+X:8:20:15:64
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%X+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+D:%X^+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXXXXXX+X##X+XXXXXXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+@*&*@*&*@*&*@*&*@*&*@*&*@*X@@X*@*&*@*&*@*&*@*&*@*&*@*&*@+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXXXXX+XX,,XX+XXXXXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+&.@.&.@.&.@.&.@.&.@.&.@.&X*..*X&.@.&.@.&.@.&.@.&.@.&.@.&+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXXXX+XX*..*XX+XXXXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+,,,,,,,,,,,,,,,,,,,,,,,,X,,..,,X,,,,,,,,,,,,,,,,,,,,,,,,+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXXX+XX##99##XX+XXXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+&.@.&.@.&.@.&.@.&.@.&.@X..####..X@.&.@.&.@.&.@.&.@.&.@.&+^X%
+D:%X^XXXXXXXXXXXXXXXXXXXXXX+XX...##...XX+XXXXXXXXXXXXXXXXXXXXXX^X%
+D:%X^+*&*@*&*@*&*@*&*@*&*@*&X&@&@88&@&@X&*@*&*@*&*@*&*@*&*@*&*+^X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:90:Hellpit
+X:8:20:19:60
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%..........................................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X@@&....#8.#9....^^&&&&&&&&&&&&###.^^,,......+8*9+,,,,,X.%
+D:%.X@&@.............^^................^^,,......+9*9+,,,,,X.%
+D:%.X&@@.............^^@@@@@@@@@@@###..^^,,......+9*9+,,,,,X.%
+D:%.X.....#8....#9...^^................^^,,......+9*9+,,,,,X.%
+D:%.X................^^&&&&&&&&&&&&###.^^,,.&&&&&+9*9+,,,,,X.%
+D:%.X.......@@@@.....^^................^^,,.&@@@&+9*9+,,,,,X.%
+D:%.#....#8.@@@@.#9..^^@@@@@@@@@@@###..^^,,.&@9@&+8*9+,,,,,X.%
+D:%.X.......@@@@.....^^................^^,,.&@@@&+9*9+,,,,,X.%
+D:%.X................^^&&&&&&&&&&&&###.^^,,.&&&&&+9*9+,,,,,X.%
+D:%.X.....#8....#9...^^................^^,,......+9*9+,,,,,X.%
+D:%.X&@@.............^^@@@@@@@@@@@###..^^,,......+9*9+,,,,,X.%
+D:%.X@&@.............^^................^^,,......+9*9+,,,,,X.%
+D:%.X@@&....#8.#9....^^&&&&&&&&&&&&###.^^,,......+8*9+,,,,,X.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%..........................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:91:Roundabout Three
+X:8:30:20:97
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X,&,,,,,,,,,,,^^^^^^^^^^......XX.#X.XXX.......X.X.......XXX.X#.XX......^^^^^^^^^^,,,,,,,,,,,&,X%
+D:%X,&,,,,,,,,,,,^^^^^^^^^^.....XX.XX.XXX..XXXX..X.X..XXXX..XXX.XX.XX.....^^^^^^^^^^,,,,,,,,,,,&,X%
+D:%X,&,,,,,,,,,,,XXXXXXXXXX....XX.XX.XXX^^XX@@XX.X&X.XX@@XX^^XXX.XX.XX....XXXXXXXXXX,,,,,,,,,,,&,X%
+D:%X,&&&&&&&&&&XXX********XXX..XX.XX.XXX^^X****X.X&X.X****X^^XXX.XX.XX..XXX********XXX&&&&&&&&&&,X%
+D:%X,,,,,,,,,,XXX..XXXXXX...XX+XX.XX.XXX^^XX&&...X@X...&&XX^^XXX.XX.XX+XX...XXXXXX..XXX,,,,,,,,,,X%
+D:%X@@@@@@@@XXX..XXX****XXX.....XX.XX.XXX..XX...XX+XX...XX..XXX.XX.XX.....XXX****XXX..XXX@@@@@@@@X%
+D:%X9988899XXX..XXX.XXXX@@XXXXXX.XX.XX.XXX..XXXXX^^^XXXXX..XXX.XX.XX.XXXXXX@@XXXX.XXX..XXX9998999X%
+D:%X######XXX**X##&&@**XX&&&@98X^^^^^XX.##X^^^^^^^^^^^^^^^X##.XX^^^^^X89@&&&XX**@&&##X**XXX######X%
+D:%X######XXX**X##&&@**XX&&&@98X^^^^^XX.##X^^^^^^^^^^^^^^^X##.XX^^^^^X89@&&&XX**@&&##X**XXX######X%
+D:%X9988899XXX..XXX.XXXX@@XXXXXX.XX.XX.XXX..XXXXX^^^XXXXX..XXX.XX.XX.XXXXXX@@XXXX.XXX..XXX9998999X%
+D:%X@@@@@@@@XXX..XXX****XXX.....XX.XX.XXX..XX...XX+XX...XX..XXX.XX.XX.....XXX****XXX..XXX@@@@@@@@X%
+D:%X,,,,,,,,,,XXX..XXXXXX...XX+XX.XX.XXX^^XX&&...X@X...&&XX^^XXX.XX.XX+XX...XXXXXX..XXX,,,,,,,,,,X%
+D:%X,&&&&&&&&&&XXX********XXX..XX.XX.XXX^^X****X.X&X.X****X^^XXX.XX.XX..XXX********XXX&&&&&&&&&&,X%
+D:%X,&,,,,,,,,,,,XXXXXXXXXX....XX.XX.XXX^^XX@@XX.X&X.XX@@XX^^XXX.XX.XX....XXXXXXXXXX,,,,,,,,,,,&,X%
+D:%X,&,,,,,,,,,,,^^^^^^^^^^.....XX.XX.XXX..XXXX..X.X..XXXX..XXX.XX.XX.....^^^^^^^^^^,,,,,,,,,,,&,X%
+D:%X,&,,,,,,,,,,,^^^^^^^^^^......XX.#X.XXX.......X.X.......XXX.X#.XX......^^^^^^^^^^,,,,,,,,,,,&,X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:92:The Reward is Worth It
+X:8:20:16:63
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXX##XXXXXXXXXXXXX#XXXXXXXXXXXXX##XXXXXXXXXXXXXXX%
+D:%X@@@@@@@@@@@.XX88XX.......,,,X^X,,,.......XX88XX.@@@@@@@@@@@X%
+D:%X@XXXXXXXXXX..XXXX...XXXX.,,,X^X,,,.XXXX...XXXX..XXXXXXXXXX@X%
+D:%X@X8888888XXX..XX...XXX@XX,,,X^X,,,XX@XXX...XX..XXX8888888X@X%
+D:%X@X88899999XXX.....XXX@@@X..&X^X&..X@@@XXX.....XXX99999888X@X%
+D:%X@X8899.....XXX...XXX@@@@@..&X^X&..@@@@@XXX...XXX.....9988X@X%
+D:%X@X899.......XXX...XXX......&X^X&......XXX...XXX.......998X@X%
+D:%X+XXX...XXX&&&XXX^^^XXX.....&X^X&.....XXX^^^XXX&&&XXX...XXX+X%
+D:%X@@XXX.XXXX&&&&XXX^^^XXX....&X^X&....XXX^^^XXX&&&&XXXX.XXX@@X%
+D:%X^^^^XXX88X^^^^^^XXX^^^XXX..&X^X&..XXX^^^XXX^^^^^^X88XXX^^^^X%
+D:%X&&&&&&&&XX^^^^^^^^XXX...XXX&X^X&XXX...XXX^^^^^^^^XX&&&&&&&&X%
+D:%X,,,,,,,XX,,,,,,,,,,,XXX&&&XXX^XXX&&&XXX,,,,,,,,,,,XX,,,,,,,X%
+D:%X,,,,,,X#@@@@@@@@@@@@@@XXX&&&&&&&&&XXX@@@@@@@@@@@@@@#X,,,,,,X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:93:Little League Treasure Hoard
+X:7:2:5:19
+D:%%%%%%%%%%%%%%%%%%%
+D:%....#...&...#....%
+D:%.#.#.##***##.#.#.%
+D:%....#...&...#....%
+D:%%%%%%%%%%%%%%%%%%%
+
+N:94:Mini Maze
+X:7:2:15:25
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................%
+D:%.X+XXXXXXXXXXXXXXXXXXX.%
+D:%.X.X,.......X........X.%
+D:%.X.X..XXX.X...XXXX.X.X.%
+D:%.X.XX.X...X.XXX..X...X.%
+D:%.X......X.X.X....XXX.X.%
+D:%.X.XXXXX..X.X.X..X,X.X.%
+D:%.X.X,..XXXX.X.X.XX.X.X.%
+D:%.X.XXX........X...XX.X.%
+D:%.X...XXXXXX.XXXXXXX..X.%
+D:%.X.X........X,.......X.%
+D:%.XXXXXXXXXXXXXXXXXXXXX.%
+D:%.......................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:95:Circlular Room
+X:7:2:8:9
+D:%%%%%%%%%
+D:%.......%
+D:%..###..%
+D:%.#+*+#.%
+D:%.#+*+#.%
+D:%..###..%
+D:%.......%
+D:%%%%%%%%%
+
+N:96:Minor Boss Vault
+X:7:3:10:10
+D:%%%%%%%%%%
+D:%........%
+D:%..XXXX..%
+D:%.XX.9XX.%
+D:%.X....X.%
+D:%.XX++XX.%
+D:%.XX^^XX.%
+D:%..X++X..%
+D:%........%
+D:%%%%%%%%%%
+
+N:97:(Lesser) Major Boss Vault
+X:7:20:10:10
+D:%%%%%%%%%%
+D:%........%
+D:%..XXXX..%
+D:%.XX.8XX.%
+D:%.X....X.%
+D:%.XX++XX.%
+D:%.XX^^XX.%
+D:%..X++X..%
+D:%........%
+D:%%%%%%%%%%
+
+N:98:(Greater) Majorly Bossy Vault
+X:8:37:10:10
+D:%%%%%%%%%%
+D:%........%
+D:%.@XXXX@.%
+D:%.XX88XX.%
+D:%.X8888X.%
+D:%.XX++XX.%
+D:%.XX^^XX.%
+D:%.@X++X@.%
+D:%........%
+D:%%%%%%%%%%
+
+N:99:Bubbles
+X:8:35:25:41
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXX#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X8X#X8XXX8XXX8XXX8XXX8XXX8XXX8XXX8XXX8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%XX.9.#.9.X.9.#.9.X.9.#.9.X.9.#.9.#.9.XX%
+D:%XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX%
+D:%X8XXX8X#X8X#X8X#X8X#X8X#X8X#X8X#X8X#X8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%XX.9.#.9.X.9.X.9.#.9.X.9.#.9.X.9.X.9..X%
+D:%XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX%
+D:%X8X#X8XXX8X#X8XXX8XXX8XXX8XXX8XXX8X#X8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%XX.9.X.9.#.9.X.9.#.9.#.9.#.9.#.9.X.9.XX%
+D:%XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX%
+D:%X8X#X8X#X8X#X8XXX8XXX8XXX8XXX8X#X8X#X8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%XX.9.#.9.X.9.#.9.#.9.#.9.#.9.#.9.X.9.XX%
+D:%XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX%
+D:%X8XXX8XXX8XXX8XXX8XXX8XXX8XXX8XXX8X#X8X%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%##.9.#.9.#.9.#.9.#.9.#.9.#.9.#.9.X.9.XX%
+D:%XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.XX#.#XX%
+D:%X8XXX8XXX8XXX8XXX8XXX8XXX8XXX8XXX8XXX8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:100:Lesser Vault (Cross)
+X:7:10:13:20
+D:%%%%%%%%%%%%%%%%%%%%
+D:%########++########%
+D:%#*....*#..#*....*#%
+D:%#....&,#^^#,&....#%
+D:%#....,##..##,....#%
+D:%#+#####*..*#####+#%
+D:%#^^.....,,.....^^#%
+D:%#+#####*..*#####+#%
+D:%#....,##..##,....#%
+D:%#....&,#^^#,&....#%
+D:%#*....*#..#*....*#%
+D:%########++########%
+D:%%%%%%%%%%%%%%%%%%%%
+
+N:101:The I in the Storm
+X:8:30:25:41
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXX%
+D:%X&&..^..#9X..^^^^^^^^^^^^^..X9#..^..&&X%
+D:%X&...#....X..XXXXXX^XXXXXX..X....#...&X%
+D:%X...&#..#.X9XX.@8XX^XX8@.XX9X.#..#&...X%
+D:%X..&9#....XXX...@X,,,X@...XXX....#9&..X%
+D:%X^####..#...XX..XX,.,XX..XX...#..####^X%
+D:%X........,#..XX^X,,.,,X^XX..#,........X%
+D:%X.......#.....^XX,...,XX^.....#.......X%
+D:%X........,#...9X,,...,,X9...#,........X%
+D:%X.......#.....XX.......XX.....#.......X%
+D:%X.#......,#..XX^.......^XX..#,......#.X%
+D:%X.9#....#....#^^...9...^^#....#....#9.X%
+D:%X.#......,#..XX^.......^XX..#,......#.X%
+D:%X.......#.....XX.......XX.....#.......X%
+D:%X........,#...9X,,...,,X9...#,........X%
+D:%X.......#.....^XX,...,XX^.....#.......X%
+D:%X........,#..XX^X,,.,,X^XX..#,........X%
+D:%X^####..#...XX..XX,.,XX..XX...#..####^X%
+D:%X..&9#....XXX...@X,,,X@...XXX....#9&..X%
+D:%X...&#..#.X9XX.@8XX^XX8@.XX9X.#..#&...X%
+D:%X&...#....X&&XXXXXX^XXXXXX&&X....#...&X%
+D:%X&&..^..#9X..^^^^^^^^^^^^^..X9#..^..&&X%
+D:%XXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:102:Roundabout Two
+X:8:30:25:40
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%#^X.^^+X@XX.+X^^^^^+.X...X8#@&*X*****X%
+D:%X^X.^XX@XX.XX^^^^^^X.X.X^XXX@.&+9....X%
+D:%X^X.XX&XX.XX^^^^^^^X.X.X^X8#@&*X99...X%
+D:%X^X.X^^X&.XXXXXXXXXX.X.X^XXXXXXXXXX++X%
+D:%X^X.X.*X&.X.......&..X.X^X........X^^X%
+D:%X^X&X.*X^^X.XXXXXXXXXX.X&X#XXXXXX.X^.X%
+D:%X^X.X..X^^X...@........X.X......X.X^^X%
+D:%X^X.X..X^^XXXXXXXXXXXXXX.XXXXXX.X.X.^X%
+D:%X^X.X..X^^X..,.....,....&X8#,*X.X.X^^X%
+D:%X^X&X,,X^^X^XXXXXXXXXXXXXX##,,X.X.X^.X%
+D:%X^+&X..+^^X^^^^^^^^^^^^^^^9...#.X.#^^X%
+D:%X^X&X,,X^^X^XXXXXXXXXXXXXX##,*X.X.X.^X%
+D:%X^X.X..X^^X..,.....,....&X8#,,X.X.X^^X%
+D:%X^X.X..X^^XXXXXXXXXXXXXX.XXXXXX.X.X^.X%
+D:%X^X.X..X^^X...@........X.X......X.X^^X%
+D:%X^X&X.*X^^X.XXXXXXXXXX.X&X#XXXXXX.X.^X%
+D:%X^X.X.*X&.X.......&..X.X^X........X^^X%
+D:%X^X.X^^X&.XXXXXXXXXX.X.X^XXXXXXXXXX++X%
+D:%X^X.XX&XX.XX^^^^^^^X.X.X^X8#@&*X99...X%
+D:%X^X.^XX@XX.XX^^^^^^X.X.X^XXX@.&+9....X%
+D:%#^X.^^+X@XX.+X^^^^^+.X...X8#@&*X*****X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:103:Modified Greater Vault (Huge)
+X:8:45:17:39
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8X.X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X#X%
+D:%X8X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8X8X.X%
+D:%X#X#XXXXXXXXXXXXXXXXXXXXXXXXXXX#X#X#X%
+D:%X8X8X8#8#8#8#8#8#8#8#8#8#8#8#8#8X8X.X%
+D:%X#X#X#XXXXXXXXXXXXXXXXXXXXXXXXXXX#X#X%
+D:%X8X8X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8X.X%
+D:%X#X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#X%
+D:%X8X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#.X%
+D:%X#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%X8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#8#%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+N:104:The Bank from Hell
+X:8:30:20:31
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%XXXXXXXXXXXXXX+XXXXXXXXXXXXXX%
+D:%X.&.&.&.&.&.#...#.&.&.&.&.&.X%
+D:%X.#.#.#.#.#.#...#.#.#.#.#.#.X%
+D:%X...........#...#...........X%
+D:%X##########+##+##+##########X%
+D:%X@........^^^^^^^^^........@X%
+D:%X@^^^.....^^^...^^^.....^^^@X%
+D:%X##+#######+#####+#######+##X%
+D:%X.^^^.#@..^^^...^^^..@#.^^^.X%
+D:%X#...##...............#.###.X%
+D:%X@...@#.&.&.&.&.&.&.&.#..@..X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXX+X%
+D:%X.+^*****X*******^+^******X.X%
+D:%X@X^....^X^......^X^.....*X@X%
+D:%X.X*****^+^*******X*******X.X%
+D:%X@XXXXXXXXXXXXXXXXXXXXXXXXX@X%
+D:%X.@.@.@.@.@.@.@.@.@.@.@.@.@.X%
+D:%XXXXXXXXXXXXXXXXXXXXXXXXXXXXX%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+# Between vaults from weisiger
+N:105:The Between Vault
+X:8:15:6:25
+D:XXXXXXXXXXXXXXXXXXXXXXXXX
+D:#,,,,,X&...@X..**&X....9X
+D:#...&1X.,,,2X..**&X3...9X
+D:#...&.X1,,,.X2.**3X....9X
+D:#,,,,,X&...@X..**&X....9X
+D:XXXXXXXXXXXXXXXXXXXXXXXXX
+
+N:106:Greater Vault (Mix&Match)
+X:8:35:28:73
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D:%.......................................................................%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X1.^^^^*&XX,,,9,,,XX...X...X...X&..X@..X@.8X7X8#X8#X8#X8#X8#X8#X8#.7X.%
+D:%.X..^^^*,XX@&@&@&@&X.X...X...X..#X&..X&..X@.#XXX#8XX8XX8XX8XX8XX8XXXXX.%
+D:%.X^^^^*,XXXX.......X6.X...X...X.#.X&..X@..X@.8X8XXXXXXXXXXXXXXXXXX88XX.%
+D:%.X^^^*,XX&&XX.....XXXXXXXX.X...X#..X&.#X&..X@.XX#9#9#9#9X88XX^^XX#8XXX.%
+D:%.X^^*,X#^^^^XX^XXX.X***&@XXXX...X...X&#.X@..X@X8X9X9X9X9X8#X^^XX8#X#8X.%
+D:%.X^*,XX^^^^^^XX^XX5X***@&,,XXX...X...X#..X&..XX#X#X#X#X#XXX^^XX##XX88X.%
+D:%.X*,XX........XX^XXX***&@,,,,XXX..X..#X&..X@..X8X8X8X8X8XX^^XX88XXXXXX.%
+D:%.X&XX..........XX^XX***@&,,,,#.XXX.X.#.X&..X&.X#X#X#X#X#X^^X#8XXXX,#.X.%
+D:%.XXX************XX6X@&@&@,,,,#...XXXX#..X&.#X@X8X8X8X8X8#XXXXXX,,,,#.X.%
+D:%.XX&,&,&,&,&,&,&,XXXX@&@&,,,,#.....XXX...X&#.XX8X8X8X8X8XXXX,,,,,,,#.X.%
+D:%.XX#************XX.^#X,,,,,,,#.......XXXXXXXXXX8X8X8XXXXX@&#,,,,,,XX#X.%
+D:%.X^XX..........XXX.XXXX,,,,,,#................X8XXXXX&&#&@&#,,XXXXX#.X.%
+D:%.X.XXX........XX3X^X99XXXXXXXXXXXXXXX#XXXXXXX.XXXX,#&&&#&@&XXXX,#^X#.X.%
+D:%.X.XXXX......XXX.X.X@@,,,,,,,,,,,,X1X.......X.X,,,,#&&&#XXXX,,,,#^X.#X.%
+D:%.X^XXXXX....XXXX.^.XXXXXXXXXXXXXX*X^X+XXXXX.X.X,,,,#&&XXX##9,,,,#^X.#X.%
+D:%.X.X^^.XX@@XXXXXXXXX9@&,,,,,,,,,X*X.X^^&,,X.X.X#####XXX#9@##@,,,#^X#.X.%
+D:%.X.X^X.XXXXX^^^XXXXXXXXXXXXXXXX,X*X.X^^^,,X.X.X&&&XXX@8##&@##@,,#^X#.X.%
+D:%.X^X.X2XXXX3^^^XXX.^..^..^..^.X,X*X^X&^^^&X.X.X##XX5.@89##9@##&,#^#.#X.%
+D:%.X.X^XXXXXXXXX^^XX.XXXXXXXXXX.X,X*X.X..^^^X.X.X^XXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X.X^^.^..^..X^^^X.^..^..^.4X^X,X*X.X2.&^^+.+.X.^.^.^.^.^.^.^.^.^.^.4X.%
+D:%.X^XXXXXXXXX^X^^^XXXXXXXXXXXX#X#X#X^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.X..^..^..^..X^^^#................X..^..^..^..^..^..^..^..^..^..^..^.+.%
+D:%.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.%
+D:%.......................................................................%
+D:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+# Wilderness vault test
+N:107:The Wilderness Vault
+X:10:1:3:7
+D:XXXXXXX
+D:T,,,,8X
+D:XXXXXXX
diff --git a/lib/mods/theme/edit/volcano.txt b/lib/mods/theme/edit/volcano.txt
new file mode 100644
index 00000000..1b89cf3d
--- /dev/null
+++ b/lib/mods/theme/edit/volcano.txt
@@ -0,0 +1,83 @@
+# File: volcano.txt
+
+# Stairway to the Hell
+F:$:7:3:0:0:0:0:0:6
+
+# Hole to the center of the Volcano
+F:>:7:3:0:0:0:0:0:5
+
+############### Town Layout ###############
+
+D:######################################################################################################################################################################################################
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL$LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^>^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^K^^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:#LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^K^LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#
+D:######################################################################################################################################################################################################
+
+
+############### SLarting positions ###############
+
+# Standard starting position for normal races
+?:[EQU $LEAVING_QUEST 0]
+P:64:80
diff --git a/lib/mods/theme/edit/w_info.txt b/lib/mods/theme/edit/w_info.txt
new file mode 100644
index 00000000..18cf7a0f
--- /dev/null
+++ b/lib/mods/theme/edit/w_info.txt
@@ -0,0 +1,141 @@
+# PernAngband wilderness definition file by DarkGod (darkgod@pernangband.org)
+# with the help form Gwidon S. Naskrent (naskrent@artemida.amu.edu.pl)
+# Designed to "look like" Middle-earth map
+# Updated to include a more accurate location of Angband/Gondolin and many new features by furiosity for Theme
+
+W:D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+W:D:Xg=====================gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:Xgggggg==============gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:Xggggggg==============ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:Xgggggggggg===========ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggX
+W:D:XWWAAWCCCWWWW===========WWWgggWWWWWgggggggggWWWWWWWWWWggggWWWWWWWWWWWWWggggWWWWWWWWggggWWWWWWWWWggggX
+W:D:XWWAAAACCCCWWWWAA========WWWWWWWWWWWWWggggggggWWWWWWWWWWWWWWWWWWWWWWWWWWggWWWWWWWWWWWWWWWWWWWWWWEEEEX
+W:D:XWWWWAAAAAW%AAAA========WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW.EEEEEEEEX
+W:D:XWWWWWWAAWAAAWW===========WWWWWWW...WWWWWWWWWW..........WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW.EEEEEEEEEEEX
+W:D:XWWWWWWWWWWWWWW==========..WWW....WWWWWWWW................WWWWGGGGWWWWWWWW......WWWWW.EEEEEEEEEEEEEEX
+W:D:XTM.MMMMWWWW===...====...........HHHH..................GGGGGGGWWWDWWWW.........WWWW.EEEEEEEEEEEEEEEEX
+W:D:XT.2MMM=======.BB.=............HHHHHHHH..&&&&&...J..GGGGGGGGGGGGG.................tEEEEEtEEEEttEEEEEX
+?:[EQU $TOWN_DESTROY2 1]
+W:M:0:1
+W:D:XT.PMMM=======.BB.=............HHHHHHHH..&&&&&......GGGGGGGGGGGGG.................tEEEEEtEEEEttEEEEEX
+?:1
+W:D:XMMMMM======..BB.===.............HHHH.......&&&&&&GG.._._.......................ttttttttttttttttttttX
+W:D:X======...._.BB._..._............................&....._._TTT................GG........tttttttttttttX
+W:D:X=====...._..BB.._.._..HHHH................&....&&&~~~~.TT_TTTT..........G.....GGG........tttttt^^^^X
+W:D:X===....._...BB..._._..HHH.......HHHHHH.....&&&&._&&..~.TTT_T_TT..^D......GGGGGG..............ttt^^^X
+W:D:X===...._..TBBB...._._..H.=....HHH|HH..........__.&&__~.TTTT_o_TT.D8........_.....................^^X
+W:D:X===...._....BB....._..HH.=_....H.|..........__...&&..~.TTTTTT_TT.=........_........................X
+W:D:X===..._...BBBB...._....HHHH__....|........._.....&&..~.TTTTTT____a........_........................X
+W:D:X===...._..TTBB..._........._.....|H......._......&q..~6TTTTT&&&T._........._.......................X
+W:D:X===....==..TBBB._......HH.._.TT..|.HH...._..TTT._&&..~..*TT&I&&&T._........._......................X
+W:D:X====...==.....==......HHd+-_TTTT-x1HH---------_Lq&&---------------_........_.......................X
+W:D:X=====..========....H....H|..____H|uH....._..._.._&...~..TTTTTTTTTT._........_......................X
+W:D:X==============....HHH....|..._TTH|......._.._.._&&^...~..TTTTTTTTT.._........_....................tX
+W:D:X======..==....BB...H.....|..._..H|HH...._.._...&&.....~..TTTTTTTT...._......_....................ttX
+W:D:X======........BB.........[---_...|.H...._._..^^&&^.I._~..TTTTTTTT....._......_..................tttX
+W:D:X======........BB............._[--|....._.._..^^&&___I.~~.TTTTTTTT......_.._._..................ttttX
+W:D:X======........BB....B......._....|....._._...^^&&.....~~.TTTTT.T........__.._.................tttttX
+W:D:X=======.....TBBB..BBBB....._.....|....._....^^&&&....~~...TTTT.............._...............tttttttX
+W:D:X==========..TBBBT........._......|...._.....^^&&.....~~...TTTT..............._...._.......TtTttttttX
+W:D:X==========..TTTBBTBB....._.......|II__.....^)^&&....~~....TTTTTTT............._.__._=...TTTTTTtttttX
+W:D:X==========...TTBTT......_........___II_..._^^^&&....~~..TTTTTTTTTT............._....==...T==TTtttttX
+W:D:X==========.....T.T....._........_.....____^___R__...~~.TTTTTTTTTT...................========TTtttttX
+W:D:X===========.=........._........_..........^^&&&_!7!~~..TT&TTTTTTT..................=========TttttttX
+W:D:X================....__........_..ttt......^M&&._!4!~~..TTTTTTTTT...................=========...ttttX
+W:D:X=================.==E........_....tt.....TTMM&..!!!~.....TTTTT..................^^.========......ttX
+W:D:X===================EE........._.........TTMMM.......~~.........................^^^^.=======.......tX
+W:D:X===================E==......._..........TTM)MTTTTT._..~~~~;;....................^^^.==...==.......tX
+W:D:X===================E==......_...........T&MWMMTTTT_I_.....~;;..................^^^^^.=...=........tX
+W:D:X=====================......_.ttt........T&M5MTTTTTT..__I~~;;...................^^^^^^.............tX
+W:D:X=====================.....=_.tt.........&&MMMTTTTT.....~...........................^^.............tX
+W:D:X======================...==..ttt........&&_&&&.._.......~~........................................tX
+W:D:X=======================.===..............^_^....._........~.......................................tX
+W:D:X===========================..............._......._......~........................................tX
+W:D:X==========================.tt......._._.._........_....H=HH...SSS.................................tX
+W:D:X==========================.tt._.._t_...__.........._..H===H.SSSS.................................ttX
+W:D:X==========================..__.__._._._..&&&b....._....H=HH..SS.A.A.............................tttX
+W:D:X============================....._..._.__.&&&......_....~~.....AAOAAA..A..AA..A..A..AA.........ttttX
+W:D:X===========================.............._&&&^^....._....~~I...AA''AAAAAAAAAAAAAAAAAAAAAAA......tttX
+W:D:X===========================.......^.&.^^&&&&&&&......__.~~III...AAVVVVVV$AVVVAVAA_"""_"""""".....ttX
+W:D:X===========================.....^^.&.&_&^&.&^&_&&&9...._..~~II..AAVVUVVVVVVVVVVA_"""""_"""""".....tX
+W:D:X===========================....^....__^^...^^^._^&&........~~.c.AAVVUUVVVVVVVAA_"""""""_"""".......X
+W:D:X===========================..^^^_.._.......^^._.^^&&&........~~.AAVVVVVVVVVVAA""_""""""_"""""""....X
+W:D:X============================.^T_.__._........_&^^^.&&&&&......e.AAsAAVAAAVVV"""""_""""_"""""""....DX
+W:D:X============================.T^_..._....HH.._&&&^^.._&&&&.&...~.AAA""A"A""""""""=="""_"""""""""".DDX
+W:D:X============================.T^._.HHHHHHHH...__...._^&^&&&&&.~..AA""""""""""""======_"""""""""""DDDX
+W:D:X===========================.^^._...H.H........._.._.^&^^._^3.~..sA"""_"_"""""=====""""""""""""DDDDDX
+W:D:X==========================..^^.._.....===.=====_._&^...._...^.~.AA"__"_"__======"""""AA""""DDDDDDDDX
+W:D:X==========================.H...._...===========_&&^...._._...~~.AA_""""""""""""_""A"AADDDDDDDDDDDDDX
+W:D:X========================.HHH=...=_.==========&^^^^.._._..._.~~..AAA""AAA""A"""AA_AAAADDDDDDDDDDDDDDX
+W:D:X======================....=====.==============^.^._=._.....~~...AAAAAAAAAAAAAAAAAAADDDDDDDDDDDDDDDDX
+W:D:X==============================================.^^^==....~~~~....................DDDDDDDDDDDDDDDDDDDX
+W:D:X===============================================..====~~~f~...............DDDDDDDDDDDDDDDDDDDDDDDDDDX
+W:D:X===============================================.==^==_............DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDX
+W:D:X=================================================^^===........DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDX
+W:D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Definition of all the entrances to the dungeons
+# W:E:<dungeon>:<y>:<x>
+
+#Orodruin
+W:E:5:50:70
+
+# Numenor
+W:E:7:25:1
+
+# Paths of the Dead
+W:E:16:49:38
+
+# Illusory Castle
+W:E:17:15:96
+
+# Maze
+W:E:18:57:28
+
+# Erebor
+W:E:20:15:66
+
+# Old Forest
+W:E:21:21:31
+
+# The Sacred Land Of Mountains
+W:E:25:37:80
+
+# The Wild Land Of Rhun
+W:E:26:28:92
+
+# The Withered Heath
+W:E:27:10:65
+
+# The Grinding Ice
+W:E:29:1:1
+
+# Dol Guldur
+W:E:23:33:58
+
+# The Northern Waste
+W:E:31:5:44
+
+# The Blue Mountains
+W:E:32:29:18
+
+# Dol Amroth
+W:E:33:60:48
+
+# Angmar
+W:E:34:13:48
+
+# Near Harad
+W:E:35:64:97
+
+# Isengard
+W:E:36:42:43
+
+# Tol Eressea
+W:E:37:64:1
+
+# Utumno
+W:E:38:1:99
+
+# Starting position
+W:P:35:21 \ No newline at end of file
diff --git a/lib/mods/theme/edit/wf_info.txt b/lib/mods/theme/edit/wf_info.txt
new file mode 100644
index 00000000..acdba872
--- /dev/null
+++ b/lib/mods/theme/edit/wf_info.txt
@@ -0,0 +1,394 @@
+# File: wf_info.txt
+
+
+# This file is used to initialize the "lib/raw/wf_info.raw" file, which is
+# used to initialize the "wilderness feats" information for the Angband game.
+
+# Do not modify this file unless you know exactly what you are doing,
+# unless you wish to risk possible system crashes and broken savefiles.
+
+# After modifying this file, delete the "lib/raw/wf_info.raw" file.
+
+# The wilderness feat indexes are defined in "defines.h", and must not be
+# changed.
+
+# N:<index>:<name>
+# D:<long name>
+# W:<level>:<entrance>:<road>:<feat>:<terrain_idx>:<character(must be unique)>
+# F:<flags>
+# X:<feat1>...<feat18>
+
+# Note for <road> :
+# 1 = NORTH
+# 2 = SOUTH
+# 4 = EAST
+# 8 = WEST
+
+# Note for <entrance> :
+# if < 1000 then it points to a town
+# if >= 1000 then it points to the x - 1000 dungeon type
+
+# <feat> is the feature from f_info that will be used to represent the tile
+# in the map
+
+# <terrain_idx> is one of the TERRAIN_foo defines of defines.h
+
+# define idx feature r_info flag
+
+# TERRAIN_EDGE 0 /* Edge of the World */ none
+# TERRAIN_TOWN 1 /* Town */ WILD_TOWN
+# TERRAIN_DEEP_WATER 2 /* Deep water */ WILD_OCEAN
+# TERRAIN_SHALLOW_WATER 3 /* Shallow water */ WILD_SHORE
+# TERRAIN_SWAMP 4 /* Swamp */ not implemented
+# TERRAIN_DIRT 5 /* Snow */ WILD_WASTE
+# TERRAIN_GRASS 6 /* Grass */ WILD_GRASS
+# TERRAIN_TREES 7 /* Trees */ WILD_WOOD
+# TERRAIN_DESERT 8 /* Desert */ not implemented
+# TERRAIN_SHALLOW_LAVA 9 /* Shallow lava */ WILD_VOLCANO
+# TERRAIN_DEEP_LAVA 10 /* Deep lava */ WILD_VOLCANO
+# TERRAIN_MOUNTAIN 11 /* Mountain */ WILD_MOUNTAIN
+
+# <character> is the character used to reference this wf_info entry on the
+# wilderness map file
+
+# X: list of f_info features used by the plasma generator to create the levels
+# corresponding to that wilderness tile (like, lots of mountain, some
+# trees, a bit of water...)
+
+# Version stamp (required)
+
+V:2.0.0
+
+N:0:Ekkaia
+D:the Encircling Sea
+W:1:0:0:182:0:X
+X:182:182:182:182:182:182:182:182:182:182:182:182:182:182:182:182:182:182
+
+N:1:Bree
+D:a small village
+W:1:1:0:203:1:1
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+N:2:Gondolin
+D:The hidden town of the Noldor
+W:1:2:0:203:1:2
+X:88:88:88:89:89:89:89:89:89:89:89:89:89:82:96:96:96:96
+
+N:3:Minas Anor
+D:The great town of Gondor
+W:1:3:0:203:1:3
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:83:96:96
+
+N:4:Caras Galadhon
+D:Lothlorien's chief city
+W:1:4:0:203:1:4
+X:88:88:96:96:96:96:199:96:80:96:96:96:96:96:96:89:89:89
+
+N:5:grass
+D:a plain of grass
+W:20:0:0:89:6:.
+X:89:89:89:89:89:89:199:89:81:89:89:89:89:89:89:89:96:96
+
+N:6:forest
+D:a forest
+W:40:0:0:96:7:T
+X:88:88:96:96:96:96:199:96:82:96:96:96:96:96:96:89:89:89
+
+N:7:road
+D:a west-east road
+W:5:0:12:200:6:-
+X:200:200:88:88:89:89:199:89:89:89:79:89:89:89:89:89:96:96
+
+N:8:road
+D:a north-south road
+W:5:0:3:200:6:|
+X:200:200:88:88:89:89:199:89:89:89:79:89:89:89:89:89:96:96
+
+N:9:mountain
+D:a mountain chain
+W:60:0:0:97:11:&
+X:1:1:89:89:88:96:96:97:97:97:97:97:97:97:97:97:97:97
+
+N:10:road
+D:a west-east-south road
+W:5:0:14:200:6:+
+X:200:200:88:88:89:199:89:89:89:89:79:89:89:89:89:89:96:96
+
+N:11:road
+D:a west-east-north road
+W:5:0:13:200:6:z
+X:200:200:88:88:89:199:89:89:89:89:79:89:89:89:89:89:96:96
+
+N:12:The Nether Realm
+D:the entrance to the netherworld
+W:127:1006:0:7:10:6
+X:88:88:88:86:86:86:85:85:85:85:85:85:85:85:85:97:97:97
+
+N:13:deep water
+D:a deep water area
+W:90:0:0:187:2:=
+X:187:187:187:187:187:187:187:187:187:187:187:187:84:84:84:84:84:84
+
+N:14:shallow water
+D:a shallow water area
+W:35:0:0:225:3:_
+X:187:187:187:84:84:84:84:84:222:222:84:84:84:84:84:1:88:89
+
+N:15:Mirkwood
+D:The Forest of Mirkwood
+W:13:1001:0:7:7:*
+X:88:88:96:96:82:96:96:96:96:79:96:96:96:96:96:89:89:89
+
+N:16:Barad-Dur
+D:Barad-Dur
+W:34:1002:0:7:11:$
+X:1:1:94:94:94:94:212:94:94:94:94:94:94:94:94:94:212:212
+
+N:17:Angband
+D:The Pits of Angband
+W:67:1003:0:7:11:%
+X:94:94:90:90:90:90:90:90:90:90:90:90:90:90:90:90:92:92
+
+N:18:mountain
+D:a mountain
+W:60:0:0:97:11:^
+X:1:1:89:89:94:96:96:97:97:97:97:97:97:97:97:97:97:97
+
+N:19:desert
+D:a desert
+W:44:0:0:91:5:D
+X:91:91:91:91:91:91:91:91:91:91:91:91:91:91:91:91:91:92
+
+N:20:jungle
+D:a jungle
+W:40:0:0:202:7:t
+X:88:88:202:96:202:96:202:96:81:96:202:96:202:96:96:89:89:89
+
+#The Dead Marshes replace 'swamp'
+# Ugly: I used a non-wilderness terrain_idx to force meaner monsters -furiosity
+N:21:Dead Marshes
+D:a part of the Dead Marshes
+W:127:0:0:223:174:S
+X:223:223:223:223:223:223:223:223:223:223:84:223:210:223:208:208:102:223
+
+N:22:glacier
+D:a glacier
+W:45:0:0:90:5:g
+X:94:94:90:90:90:90:90:90:90:90:90:90:90:90:90:90:92:92
+
+N:23:grass
+D:a plain of grass
+W:15:0:0:228:6:,
+X:1:1:88:88:228:228:228:228:228:79:228:228:228:228:228:228:96:96
+
+N:24:Moria
+D:The Doors of Moria
+W:50:1022:0:7:11:)
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96
+
+N:25:high mountain
+D:a high mountain chain
+W:80:0:0:101:11:M
+X:101:101:101:101:101:101:101:101:101:101:101:101:101:101:101:101:101:101
+
+N:26:Gondolin
+D:The pillaged city of the Noldor
+W:1:2:0:203:1:P
+X:49:49:49:88:88:88:92:92:92:92:93:93:94:94:94:174:205:205
+
+N:27:Khazad-dum
+D:The dwarven stronghold
+W:1:5:0:203:1:5
+X:1:1:1:1:1:1:1:1:1:1:88:88:88:88:88:88:88:88
+
+N:28:dark pit
+D:a dark pit
+W:60:0:0:87:5:C
+X:87:87:87:87:87:87:87:87:87:214:214:214:214:214:214:214:214:214
+
+N:29:low hill
+D:a low hill
+W:15:0:0:213:6:H
+X:1:1:89:89:88:96:96:213:213:213:213:213:213:213:213:213:213:213
+
+N:30:dark mountain
+D:a dark mountain
+W:80:0:0:214:11:A
+X:214:214:214:214:214:214:214:214:214:214:214:214:214:214:214:214:214:214
+
+N:31:blue mountain
+D:a blue mountain
+W:50:0:0:215:11:B
+X:1:1:89:89:88:96:96:215:215:83:215:215:215:215:215:215:215:215
+
+N:32:grey mountain
+D:a grey mountain
+W:40:0:0:216:11:G
+X:1:1:89:89:88:96:96:216:216:216:80:216:216:216:216:216:216:216
+
+N:33:Mount Doom
+D:a part of Mount Doom
+W:127:0:0:217:11:U
+X:217:217:217:217:217:217:217:217:217:217:217:217:217:217:217:217:217:217
+
+N:34:Mallorn forest
+D:a Mallorn forest
+W:5:0:0:243:7:!
+X:88:88:243:243:96:96:243:199:82:243:243:96:243:96:243:243:243:243
+
+N:35:Redhorn Pass
+D:Redhorn Pass
+W:30:0:0:218:6:R
+X:94:94:90:90:90:90:90:94:90:90:90:94:90:90:90:90:95:95
+
+N:36:Morannon
+D:Morannon (the Black Gate of Mordor)
+W:34:0:0:224:11:O
+X:224:224:224:224:224:224:224:224:224:224:224:224:224:224:224:224:224:224
+
+N:37:evergreen wood
+D:an evergreen wood
+W:40:0:0:202:7:E
+X:94:94:219:219:219:219:219:219:82:219:219:219:219:219:219:89:94:94
+
+N:38:Rivendell
+D:the valley of Rivendell
+W:5:14:0:96:1:L
+X:88:97:202:96:202:97:202:96:81:97:202:96:202:96:96:89:97:89
+
+N:39:Gorgoroth
+D:the valley of terror
+W:90:0:0:91:5:V
+X:91:91:91:86:94:94:94:86:91:91:94:94:86:94:94:86:91:94
+
+N:40:Northern Waste
+D:the northern wastelands
+W:30:0:0:93:5:W
+X:91:90:90:91:90:91:90:91:90:91:91:91:90:91:90:91:91:91
+
+N:41:crossroads
+D:a crossroads
+W:5:0:15:200:6:x
+X:200:200:88:88:89:199:89:89:89:89:79:89:89:89:89:89:96:96
+
+N:42:north-south-east road
+D:a north-south-east road
+W:5:0:7:200:6:[
+X:200:200:88:88:89:199:89:89:89:89:79:89:89:89:89:89:96:96
+
+N:43:swamp
+D:a swamp
+W:45:0:0:226:3:I
+X:226:226:174:84:84:226:174:226:84:84:174:226:226:174:226:174:84:174
+
+N:44:Nurn
+D:the valley of Nurn
+W:50:0:0:94:6:"
+X:94:93:94:89:93:89:94:89:93:94:94:93:89:93:89:93:94:94
+
+N:45:The Brown Lands
+D:the Brown Lands
+W:30:0:0:174:5:;
+X:174:174:89:89:174:174:89:89:174:94:93:174:174:94:174:89:89:94
+
+N:46:Udun
+D:the valley of Udun
+W:50:0:0:86:6:'
+X:94:93:86:86:94:93:86:86:94:93:86:86:94:93:86:86:94:93
+
+N:47:Anduin
+D:Anduin, the great river
+W:35:0:0:227:3:~
+X:187:227:187:84:84:227:84:84:222:227:84:84:227:84:84:227:88:94
+
+# Former location of Gondolin (to avoid silliness with Maeglin quest)
+N:48:Secret Valley
+D:the secret valley with directions to Gondolin
+W:0:0:12:89:1:J
+X:228:228:228:228:228:228:228:228:228:228:228:228:228:228:228:228:228:228
+
+### New Towns ###
+
+# Beorn's Halls
+N:49:Beorn's Halls
+D:the dwelling of Beorn the Shape-changer
+W:1:6:0:89:1:6
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+# Cerin Amroth
+N:50:Cerin Amroth
+D:a place of peace
+W:1:7:0:89:1:7
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+# Dale
+N:51:Dale
+D:a city of Men, being rebuilt
+W:1:8:0:91:1:8
+X:91:91:91:91:91:91:91:91:91:91:91:91:91:91:91:91:91:91
+
+# Edoras
+N:52:Edoras
+D:the capital of Rohan
+W:1:9:0:203:1:9
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+# Esgaroth
+N:53:Esgaroth
+D:the city of Lake-Men
+W:1:10:0:203:1:a
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+# Helm's Deep
+N:54:Helm's Deep
+D:the great fortress of the Rohirrim
+W:1:11:0:89:1:b
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+# Henneth Annun
+N:55:Henneth Annun
+D:a Ranger hideout
+W:1:12:0:89:1:c
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+# Hobbiton
+N:56:Hobbiton
+D:a Hobbit village
+W:1:13:0:203:1:d
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+# Osgiliath
+N:57:Osgiliath
+D:a stronghold of Men
+W:1:15:0:203:1:e
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+# Pelargir
+N:58:Pelargir
+D:the great city at the mouth of Anduin
+W:1:16:0:203:1:f
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+# Thranduil's Halls
+N:59:Thranduil's Halls
+D:the hidden realm of the Wood-elves
+W:1:17:0:213:1:o
+X:88:88:89:89:89:89:79:96:96:96:96:96:96:96:96:96:96:96
+
+### Cirith Ungol a 'defined' feature to allow it to have two entrances
+N:60:Cirith Ungol
+D:the dreaded Spider Pass
+W:25:1009:0:7:6:s
+X:91:91:91:86:94:94:94:86:91:91:94:94:86:94:94:86:91:94
+
+### Bree Swamp
+N:61:Bree Swamp
+D:The Bree Swamp
+W:1:0:0:225:6:u
+X:187:187:187:84:84:84:84:84:222:222:84:84:84:84:84:1:88:89
+
+### Orc Cave a 'defined' feature to allow it to have two entrances
+N:62:Orc Cave
+D:a dark tunnel leading to an Orc Cave
+W:15:1019:0:7:6:q
+X:1:1:88:88:89:89:89:89:89:89:89:89:89:89:89:89:96:96 \ No newline at end of file
diff --git a/lib/mods/theme/edit/wights.map b/lib/mods/theme/edit/wights.map
new file mode 100644
index 00000000..b67963ac
--- /dev/null
+++ b/lib/mods/theme/edit/wights.map
@@ -0,0 +1,82 @@
+# Permanent wall
+F:X:63:3
+
+# up stairs
+F:<:6:3
+
+# Floor with mountain
+F:^:97:3
+
+# Floor
+F:.:1:3
+
+# Floor with dirt
+F:;:88:3
+
+# Floor with forest wight
+F:f:88:3:381
+
+# Floor with grave wight
+F:g:88:3:470:0:0:0:0:0:0:2
+
+# Floor with barrow wight
+F:b:88:3:499:0:0:0:0:0:0:2
+
+# Floor with Emperor Wight
+F:e:88:3:604:0:0:0:0:0:0:2
+
+# Floor with a Human Skeleton
+F:k:88:8:0:395
+
+# Marker
+F:,:172:6
+
+# between gate 1
+F:1:160:6:0:0:0:0:0:2057
+
+# between gate 2
+F:2:160:6:0:0:0:0:0:1036
+
+# between gate 3
+F:3:160:6:0:0:0:0:0:3847
+
+# between gate 4
+F:4:160:6:0:0:0:0:0:2321
+
+# between gate 5
+F:5:160:6:0:0:0:0:0:1043
+
+# between gate 6
+F:6:160:6:0:0:0:0:0:3599
+
+# between gate 7
+F:7:160:6:0:0:0:0:0:2071
+
+# between gate 8
+F:8:160:6:0:0:0:0:0:3350
+
+# between gate 9
+F:9:160:6:0:0:0:0:0:771
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X..k^^^^^^^^^^^^^^^^^^^^^^^XX
+D:Xfkff^^^^^...^^^^..ff^^^^^^XX
+D:X^f1^^^^^^.ffg^^^^.fgg^^^^^XX
+D:X^^^^^^^^^^^fg4^^^^f6^^^^^^XX
+D:X^^^^^^^^^^^^f^^^^^^^^^fg8^XX
+D:X^^^^^^.f^^^^^^^^^^^^.ffg^^XX
+D:X^^^^.ff2^^^^^^.^^^^^^.f^^^XX
+D:X^^^^^3.^^^^^^^.^^^^^^^^^^^XX
+D:X^^^^^^^^^^^^ff.^^^^^^^^^^^XX
+D:X^^^^^^^^^^^7gfg^^^^^^^^f^^XX
+D:X^^^^^^^^^^^^^^^^^^^..^..^^XX
+D:X^^^^^^^^^^^^.^^^^^^....ff^XX
+D:X^^^^...^^^^^ff^^^^^^..fg^^XX
+D:X^^^.fff^^^^gfg^^^^...fgee^^X
+D:X^^^^g5^^^^..8^^^^^f^fgfe,9^X
+D:X^^^^^^^^^^^^^^^^^^^^^^^^^^^X
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:3
diff --git a/lib/mods/theme/edit/wolves.map b/lib/mods/theme/edit/wolves.map
new file mode 100644
index 00000000..0e3030ea
--- /dev/null
+++ b/lib/mods/theme/edit/wolves.map
@@ -0,0 +1,55 @@
+# permanent wall
+F:X:61:0
+
+# granite
+F:#:57:0
+
+# up staircase
+F:<:6:0
+
+# Grass
+F:-:89:0
+
+# Dirt
+F:.:88:0
+
+# Trees
+F:t:96:0
+
+# Open door
+F:D:4:0
+
+# Broken door
+F:d:5:0
+
+# Grass with elf skeleton
+F:z:89:0:0:397
+
+# Dungeon layout
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:X...t.---.......-.-.....-...#.--X
+D:X-..#..-......-.....--......t...X
+D:X...t.--.tt#ddt##t#dd#t#....#...X
+D:Xz-.t....#.--...#...-..#.--.t...X
+D:X#d##....#.z.z..t---...t....#tD#X
+D:X....---.t......t..-.z.#..z.....X
+D:X...--.-.#...z..#.--...t........X
+D:X##t#-z-.#####dd#dd##tt#....#t#tX
+D:X..-t.--.t....-.t...--.#.---t...X
+D:X.--t---.t......#..--z-#----#-..X
+D:X...D....#.--z...---.--t--.-d--.X
+D:X...#....#........---..#--..#z-.X
+D:X#t#t....t..-...t-z-...t....#tt#X
+D:X..-.....#-..-..#......#.....--.X
+D:X...-.--.#dd#ttt##t##Dd#.....--.X
+D:X#Dt#....#-.....#......#....##t#X
+D:X...#...-t----..#......t...-tz--X
+D:X.z.t...-#--.-..t......#.---#-..X
+D:X.--t.---#-z.--.#.....zt--..d-..X
+D:X---#....###dd#tt##dd###--..t...X
+D:X.z-t..-...-....-..-.--.....#<zzX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:3:4
+
diff --git a/lib/mods/theme/file/book-0.txt b/lib/mods/theme/file/book-0.txt
new file mode 100644
index 00000000..5f317ff2
--- /dev/null
+++ b/lib/mods/theme/file/book-0.txt
@@ -0,0 +1,86 @@
+
+ Ted Sandyman's Important Compendium of Deep Thought.
+ ------------------------------------------------
+
+If they ever come up with a swashbuckling School, I think one of the
+courses should be Laughing, Then Jumping Off Something.
+
+It takes a big man to cry, but it takes a bigger man to laugh at that man.
+
+The people in the village were real poor, so none of the children had
+any toys. But this one little boy had gotten an old enema bag and
+filled it with rocks, and he would go around and whap the other
+children across the face with it. Man, I think my heart almost
+broke. Later the boy came up and offered to give me the toy. This was
+too much! I reached out my hand, but then he ran away. I chased him
+down and took the enema bag. He cried a little, but that's the way of
+these people.
+
+Dad always thought laughter was the best medicine, which I guess is
+why several of us died of tuberculosis.
+
+Maybe in order to understand mankind, we have to look at the word
+itself: "Mankind". Basically, it's made up of two separate words -
+"mank" and "ind". What do these words mean? It's a mystery, and
+that's why so is mankind.
+
+Ambition is like a frog sitting on a Venus Flytrap. The flytrap can
+bite and bite, but it won't bother the frog because it only has little
+tiny plant teeth. But some other stuff could happen and it could be
+like ambition.
+
+I'd rather be rich than stupid.
+
+We tend to scoff at the beliefs of the ancients. But we can't scoff at
+them personally, to their faces, and this is what annoys me.
+
+Probably the earliest flyswatters were nothing more than some sort of
+striking surface attached to the end of a long stick.
+
+As the evening sky faded from a salmon color to a sort of flint gray,
+I thought back to the salmon I caught that morning, and how gray he
+was, and how I named him Flint.
+
+When I was a kid my favorite relative was Uncle Caveman. After school
+we'd all go play in his cave, and every once in a while he would eat
+one of us. It wasn't until later that I found out that Uncle Caveman
+was a bear.
+
+Why do there have to be rules for everything? It's gotten to the point
+that rules dominate just about every aspect of our lives. In fact, it
+might be said that rules have become the foot-long sticks of mankind.
+
+If I had a mine shaft, I don't think I would just abandon it. There's
+got to be a better way.
+
+If I had a nickname, I think I would want it to be "Prince of
+Weasels", because then I could go up and bite people and they would
+turn around and go, "What the-?" And then they would recognize me, and
+go, "Oh, it's you, the Prince of Weasels."
+
+It's amazing to me that one of the world's most feared diseases would
+be carried by one of the world's smallest animals: the real tiny
+dog.
+
+Sometimes life seems like a dream, especially when I look down and see
+that I forgot to put on my pants.
+
+I bet it was pretty hard to pick up girls if you had the Black Death.
+
+It's fascinating to think that all around us there's an invisible
+world we can't even see. I'm speaking, of course, of the World of the
+Invisible Scary Skeletons.
+
+Whenever I hear the sparrow chirping, watch the woodpecker chirp,
+catch a chirping trout, or listen to the sad howl of the chirp rat, I
+think: Oh boy! I'm going insane again.
+
+He was the kind of man who was not ashamed to show affection. I guess
+that's what I hated about him.
+
+The next time I have meat and mashed potatoes, I think I'll put a very
+large blob of potatoes on my plate with just a little piece of
+meat. And if someone asks me why I didn't get more meat, I'll just
+say, "Oh, you mean this?" and pull out a big piece of meat from inside
+the blob of potatoes, where I've hidden it. Good magic trick, huh?
+
diff --git a/lib/mods/theme/file/book-1.txt b/lib/mods/theme/file/book-1.txt
new file mode 100644
index 00000000..b1aa102f
--- /dev/null
+++ b/lib/mods/theme/file/book-1.txt
@@ -0,0 +1,83 @@
+
+ Ted Sandyman's Important Compendium of Deep Thought, Vol. 2
+ -------------------------------------------------------
+
+
+It makes me mad when people say I turned and ran like a scared
+rabbit. Maybe it was like an angry rabbit, who was running to go fight
+in another fight, away from the first fight.
+
+Perhaps, if I am very lucky, the feeble efforts of my lifetime will
+someday be noticed, and maybe, in a small way, they will be acknowledged
+as the greatest works of genius ever created by Man.
+
+Sometimes I think I'd be better off dead. No, wait, not me, you.
+
+If you ever catch on fire, try to avoid looking in a mirror, because I
+bet that will really throw you into a panic.
+
+Children need encouragement. If a kid gets an answer right, tell him
+it was a lucky guess. That way he develops a good, lucky feeling.
+
+The crows seemed to be calling his name, thought Caw.
+
+If your friend is already dead, and being eaten by vultures, I think
+it's okay to feed some bits of your friend to one of the vultures, to
+teach him to do some tricks. But only if you're serious about adopting
+the vulture.
+
+Broken promises don't upset me. I just think, why did they believe me?
+
+One thing vampire children have to be taught early on is, don't run
+with a wooden stake.
+
+Consider the daffodil. And while you're doing that, I'll be over here,
+looking through your stuff.
+
+I think my new thing will be to try to be a real happy guy. I'll just
+walk around being real happy until some jerk says something stupid to
+me.
+
+I hope some animal never bores a hole in my head and lays its eggs in
+my brain, because later you might think you're having a good idea but
+it's just eggs hatching.
+
+Whenever you read a good book, it's like the author is right there, in
+the room talking to you, which is why I don't like to read good books.
+
+What is it about a beautiful sunny afternoon, with the birds singing
+and the wind rustling through the leaves, that makes you want to get
+drunk?
+
+Instead of a trap door, what about a trap window? The guy looks out
+it, and if he leans too far, he falls out. Wait. I guess that's like a
+regular window.
+
+If I ever get real rich, I hope I'm not real mean to poor people, like
+I am now.
+
+Most of the time it was probably real bad being stuck down in a
+dungeon. But some days, when there was a bad storm outside, you'd look
+out your little window and think, "Boy, I'm glad I'm not out in that."
+
+Sometimes you have to be careful when selecting a new name for
+yourself. For instance, let's say you have chosen the nickname "Fly
+Head." Normally you would think that "Fly Head" would mean a person
+who has beautiful swept-back features, as if flying through the
+air. But think again. Couldn't it also mean "having a head like a
+fly"? I'm afraid some people might actually think that.
+
+I hope that after I die, people will say of me: "That guy sure owed me
+a lot of money."
+
+The tired and thirsty prospector threw himself down at the edge of the
+watering hole and started to drink. But then he looked around and saw
+skulls and bones everywhere. "Uh-oh," he thought. "This watering hole
+is reserved for skeletons."
+
+Anytime I see something screech across a room and latch onto someone's
+neck, and the guy screams and tries to get it off, I have to laugh,
+because what is that thing.
+
+I hope life isn't a big joke, because I don't get it.
+
diff --git a/lib/mods/theme/file/book-10.txt b/lib/mods/theme/file/book-10.txt
new file mode 100644
index 00000000..995c2453
--- /dev/null
+++ b/lib/mods/theme/file/book-10.txt
@@ -0,0 +1,75 @@
+ ------------------------
+ | Monstrous Compendium 2 |
+ | Mostly never-moving |
+ ------------------------
+
+ *** Floating eyes (e) ***
+
+Strange disembodied eyes, floating around the dungeon. Some
+of them are comparatively harmless (such as the [[[[[oFloating eyes],
+[[[[[RRadiation eyes], [[[[[rBloodshot eyes], and [[[[[vDisenchanter eyes]),
+others moderately dangerous (such as the [[[[[DEvil eyes], [[[[[sGauths],
+[[[[[gGas spores], and [[[[[BSpectators]), yet others extremely deadly -
+these include the [[[[[UBeholders], [[[[[uUndead beholders], [[[[[bEyes of the]
+[[[[[bdeep], and the [[[[[yBeholder hive-mothers]. Whatever you do, do
+not get too close to them
+
+
+ *** Jellies (j) ***
+
+You will sometimes encounter large quavering piles of flesh
+just lying around the dungeon or making their way along the
+walls. They all have different defense mechanisms, which with
+time an adventurer will learn to recognise by looking at their
+colour. Among the less dangerous types are [[[[[wWhite jellies], [[[[[rRed]
+[[[[[rjellies], [[[[[bBlue jellies], [[[[[vGrape jellies], [[[[[gGreen jellies], [[[[[WSilver]
+[[[[[Wjellies], [[[[[yYellow jellies], [[[[[oSpotted jellies], and [[[[[uRot jellies].
+Considerably more dangerous are the [[[[[DUndead masses] and [[[[[UOchre]
+[[[[[Ujellies], as well as [[[[[DBlack puddings]. Among the moving jellies,
+watch out for [[[[[gGreen oozes], [[[[[bBlue oozes], [[[[[DBlack oozes], [[[[[GGelatinous]
+[[[[[Gcubes], [[[[[RGibbering mouthers], and [[[[[BAcidic cytoplasms].
+
+ *** Molds (m) ***
+
+Molds are strange growths on the dungeon floor which have
+developed defense mechanisms to deal with anyone who tries
+to disturb them. They come in many varieties and prefer
+different habitats, and some of them can be quite dangerous
+because they have rudimentary mastery of the elements. The
+most common varieties of mold are the [[[[[sGrey mold], the [[[[[rRed]
+[[[[[rmold], the [[[[[oHairy mold], the [[[[[gGreen mold], the [[[[[uBrown mold],
+the [[[[[yYellow mold], the [[[[[wWhite mold], and the [[[[[WSilver mold].
+More rare are [[[[[vDisenchanter molds], [[[[[bShimmering molds], [[[[[RPink]
+[[[[[Rmolds], [[[[[GTree molds], and [[[[[BBlue molds]. A very rare and dire
+creature is the [[[[[DDeath mold] - unwary adventurers beware! The
+[[[[[UAdventurer molds] are friendly towards their fellows, but
+not very strong.
+
+ *** Mushroom patches (,) ***
+
+You'd think it safe to eat them - you'd be wrong. Mushroom
+patches are masters of disguise and can cause quite a bit
+of damage to unwary adventurers. Fortunately, most of them
+are extremely weak and can be destroyed quickly if you can
+just get close enough. The commonly found varieties include
+the [[[[[sgrey], [[[[[Bclear], [[[[[vpurple], [[[[[ospotted], [[[[[yyellow], [[[[[Rshrieker], [[[[[Ddark],
+[[[[[wwhite], [[[[[ubrown], [[[[[Wsilver], and [[[[[Ggreen] mushroom patches. More rare
+are [[[[[gshambling mounds], [[[[[Bmagic mushroom patches], [[[[[rblood sprouts],
+and [[[[[bmemory mosses].
+
+ *** Quylthulgs (Q) ***
+
+Strange pulsing mounds of flesh that looks utterly harmless.
+As with any other monster, however, looks are very deceiving
+when it comes to the [[[[[yQuylthulgs]. They are expert at asking
+for other creatures' help, as weall as conveyance magic. The
+only friendly type is the [[[[[wAdventurer quylthulg] - these have
+many friends among their own kin. The [[[[[vNexus quylthulg] is
+unmatched in conveyance magic; you will have trouble getting
+close to it. The other quylthulgs usually prefer to call for
+aid, and you can tell what kind of creatures are likely to
+come to its call, usually. There are [[[[[DSpider], [[[[[sCanine], [[[[[bAquatic],
+[[[[[uRotting], [[[[[gDraconic], [[[[[rDemonic], [[[[[UGreater rotting], [[[[[Ggreater]
+[[[[[GDraconic], [[[[[RGreater demonic], and [[[[[BMaster quylthulgs].
+
+
diff --git a/lib/mods/theme/file/book-101.txt b/lib/mods/theme/file/book-101.txt
new file mode 100644
index 00000000..e45865a7
--- /dev/null
+++ b/lib/mods/theme/file/book-101.txt
@@ -0,0 +1,4 @@
+nalo means shadow
+ure means sun
+ido means now
+nimir means shine or elf
diff --git a/lib/mods/theme/file/book-102.txt b/lib/mods/theme/file/book-102.txt
new file mode 100644
index 00000000..3b737923
--- /dev/null
+++ b/lib/mods/theme/file/book-102.txt
@@ -0,0 +1,4 @@
+gimli means star
+kadar means city
+izindi means starlight
+lomi means night
diff --git a/lib/mods/theme/file/book-103.txt b/lib/mods/theme/file/book-103.txt
new file mode 100644
index 00000000..0ffeea37
--- /dev/null
+++ b/lib/mods/theme/file/book-103.txt
@@ -0,0 +1,6 @@
+attu means father
+aru means king
+bawiba means wind
+dulgi means black
+balik means ships
+daira means Earth
diff --git a/lib/mods/theme/file/book-104.txt b/lib/mods/theme/file/book-104.txt
new file mode 100644
index 00000000..3b60e8ca
--- /dev/null
+++ b/lib/mods/theme/file/book-104.txt
@@ -0,0 +1,6 @@
+naur means fire
+mellon means friend
+Edain means Dunedain
+pedo means speak
+Pheriain means Halflings
+a minno means and enter
diff --git a/lib/mods/theme/file/book-105.txt b/lib/mods/theme/file/book-105.txt
new file mode 100644
index 00000000..f3667d64
--- /dev/null
+++ b/lib/mods/theme/file/book-105.txt
@@ -0,0 +1,7 @@
+baraz means red
+Baruk means Axes
+dum means halls
+Khazad means Dwarves
+gabil means great
+aimenu means upon you
+gathol means fortress
diff --git a/lib/mods/theme/file/book-106.txt b/lib/mods/theme/file/book-106.txt
new file mode 100644
index 00000000..81c4043c
--- /dev/null
+++ b/lib/mods/theme/file/book-106.txt
@@ -0,0 +1,5 @@
+dori means land
+hrassa means precipice
+Danas means Green-elves
+dunna means black
+garma means wolf
diff --git a/lib/mods/theme/file/book-107.txt b/lib/mods/theme/file/book-107.txt
new file mode 100644
index 00000000..1abc6d8e
--- /dev/null
+++ b/lib/mods/theme/file/book-107.txt
@@ -0,0 +1,6 @@
+nazg means ring
+ghash means fire
+snaga means slave
+burz means black
+ronk means pool
+bubhosh means great
diff --git a/lib/mods/theme/file/book-11.txt b/lib/mods/theme/file/book-11.txt
new file mode 100644
index 00000000..5d211818
--- /dev/null
+++ b/lib/mods/theme/file/book-11.txt
@@ -0,0 +1,51 @@
+ ------------------------
+ | Monstrous Compendium 3 |
+ | Insects |
+ ------------------------
+
+ *** Ants (a) ***
+
+Ants are worker six-legged insects, and adventurers will
+encounter many different kinds of these on their travels.
+The [[[[[uSoldier ants] and [[[[[oGiant army ants] are just your
+garden-variety ants, and there are also [[[[[UTermites], which
+breed very quickly, and [[[[[BAquatic ants], which have adapted
+to living underwater. The majority of ants, however, come
+from different families, with rudimentary mastery of the
+elements - they vary from [[[[[wwhite], [[[[[rred], [[[[[sgrey], [[[[[Wsilver],
+[[[[[Dblack], and [[[[[yyellow] to [[[[[bblue], [[[[[Rfire], [[[[[gtree], and
+[[[[[Ggreen].
+
+ *** Flying insects (I) ***
+
+There are many different kinds of flying insects in Middle-
+earth - some, like [[[[[BButterflies], are harmless, others are
+only slightly dangerous (like [[[[[WMoths], [[[[[uInsect swarms], and
+[[[[[sGiant fleas]). Yet others are serious nuisances due to their
+explosive breeding, among them are [[[[[gNeekerbreekers], [[[[[GGiant]
+[[[[[Gfruit flies], [[[[[DGiant black midges] and [[[[[wGiant white midges].
+Adventurers should be wary of [[[[[yHummerhorns], [[[[[oKiller bees],
+[[[[[rGiant fireflies], and [[[[[UFlies of Mordor].
+
+ *** Dragonflies (F) ***
+
+Large insects with dazzling wings, the dragonflies inhabit
+many different areas on Middle-earth. Among them are giant
+[[[[[Baquatic], [[[[[ygold], [[[[[sblack], [[[[[Ubronze], [[[[[Ggreen], [[[[[wwhite], [[[[[oswamp], [[[[[rred],
+[[[[[gforest], [[[[[bblue], [[[[[ubrown], [[[[[Wsilver], [[[[[vviolet], and [[[[[Rpink] ones -
+all with rudimentary command of some of the elements. The
+[[[[[DDeath dragonflies] are worth watching out for.
+
+ *** Spiders (S) ***
+
+Ugly eight-legged creatures, the spiders tend to travel in
+packs, and are thus to be reckoned with. The weaker species
+include the [[[[[BPhase spiders], [[[[[DCave spiders], [[[[[WGiant spiders], and
+[[[[[UWood spiders] - these are only dangerous to very inexperienced
+adventurers. The [[[[[RGiant fire ticks], uGiant brown ticks], [[[[[oGiant]
+[[[[[otarantulas], [[[[[wGiant white ticks], [[[[[sGiant grey scorpions], [[[[[rGiant]
+[[[[[rred scorpions], and [[[[[yGiant yellow scorpions] are more dangerous
+than their smaller cousins. The most dangerous of all spiders
+are the aquatic [[[[[gMurk dwellers], the [[[[[rAraneas], the [[[[[bDriders], the
+dreadful [[[[[GMirkwood spiders], and the powerful [[[[[vElder araneas].
+
diff --git a/lib/mods/theme/file/book-12.txt b/lib/mods/theme/file/book-12.txt
new file mode 100644
index 00000000..07b5267d
--- /dev/null
+++ b/lib/mods/theme/file/book-12.txt
@@ -0,0 +1,68 @@
+ ------------------------
+ | Monstrous Compendium 4 |
+ | Animals |
+ ------------------------
+
+
+ *** Cattle (c) ***
+
+Mostly domesticated four-legged beasts of burden, these
+animals will not bother you unless you bother them first.
+In fact, [[[[[wSheep], [[[[[uCows], [[[[[sHorses], [[[[[WMearas], [[[[[yPonies], [[[[[DOxen],
+[[[[[rKine of Araw], and [[[[[UDeer] will tend to ignore adventurers
+completely. [[[[[oBoars], however, are a different matter. They
+have strong legs and fierce tusks, which they will use
+against anyone who stumbles into their territory.
+
+ *** Canines (C) ***
+
+Four-legged animals with shaggy fur. Most of them are not
+very dangerous - in fact, the [[[[[sScruffy little dogs] will
+not do much except growl, and [[[[[yJackals] can be deadly against
+very weak adventurers, but will not hold their own against
+even moderately experienced ones. [[[[[oFoxes], [[[[[uWolves], [[[[[wWhite]
+[[[[[wwolves], and [[[[[BBlink dogs] can be a nuisance, but not overmuch.
+The evil [[[[[gWolf chieftains], [[[[[DWerewolves], [[[[[DWargs], [[[[[RHellhounds],
+and [[[[[rGreater Hellhounds], however, are very dangerous.
+
+ *** Felines (f) ***
+
+Lithe, four-legged animals with sleek fur and sharp claws.
+The [[[[[WScrawny cat] lives in the town and tends to walk by
+itself. The [[[[[UWild cats], [[[[[gTree cats], and [[[[[bNight cats] are all
+quite menacing, but only dangerous in packs. The powerful
+[[[[[DPanthers], [[[[[oTigers], [[[[[wSnow tigers], and [[[[[ySabre-tooth tigers]
+are not to be toyed with. The [[[[[uLeopards] and [[[[[RLions] are the
+strongest of all the feline monsters.
+
+ *** Quadrupeds (q) ***
+
+Four-legged creatures of varying breeds, these monsters
+are all quite large and fierce - their bulk alone is
+enough to intimidate you. The weakest are the [[[[[yApes], who
+make a lot of noise but aren't very dangerous. The [[[[[WOld]
+[[[[[Wbears] just want everyone to leave them alone. There are
+many other different kinds of bears, among them the
+[[[[[uCave bears], [[[[[rWar bears], [[[[[UGrizzly bears], [[[[[wPolar bears],
+[[[[[bBlue bears], [[[[[RFire bears], [[[[[BAquatic bears], and [[[[[DWerebears].
+The [[[[[sMumakil] are gigantic elephantine forms, stomping all
+over the dungeon and waving their tusks threateningly. The
+[[[[[GNight mares] are fearsome skeletal horses with glowing eyes.
+The [[[[[gCatoblepas] are strange ox-like forms with huge heads but
+thin, weak necks. The [[[[[oRust monsters] are weird, small animals
+that look perpetually hungry.
+
+ *** Birds (B) ***
+
+There are many different types of birds on Middle-earth,
+and the [[[[[RChaffinches], [[[[[WSparrows], [[[[[BNightingales], [[[[[UThrushes],
+[[[[[WRavens], [[[[[oGulls], [[[[[rEagles], and [[[[[rGreat eagles] will not harm
+anyone who does not harm them first. The [[[[[wSwans] hold a very
+special place with the Valar, and woe be to anyone who
+knowingly harms a Swan. However, not all birds are harmless.
+The [[[[[RKirinki] can wake up entire towns with their shrill cry,
+The [[[[[sCrows] and [[[[[DCrebain] are ever hungry for carrion, as are
+[[[[[GGorcrows]. The [[[[[uHunting hawks] seek prey without regard for
+friend or foe. The [[[[[DWinged Horrors] are not quite birds, they
+are Great Eagles corrupted by Morgoth to serve his ends.
+
diff --git a/lib/mods/theme/file/book-13.txt b/lib/mods/theme/file/book-13.txt
new file mode 100644
index 00000000..faa7071b
--- /dev/null
+++ b/lib/mods/theme/file/book-13.txt
@@ -0,0 +1,54 @@
+ ------------------------
+ | Monstrous Compendium 5 |
+ | Fliers and Crawlers |
+ ------------------------
+
+
+ *** Bats (b) ***
+
+Small flying creatures with webbed wings and sharp teeth.
+The [[[[[ofruit bats] are the weakest of them all. Other kinds
+include [[[[[Utan], [[[[[ubrown], [[[[[wsnow], [[[[[sgrey], [[[[[Wsilver], [[[[[yyellow], [[[[[Ggreen],
+[[[[[rred dragon], [[[[[bblue dragon], and [[[[[vdisenchanter bats]. The most
+dangerous of this race the [[[[[BMongbats], [[[[[dVampire bats], [[[[[gBats]
+[[[[[gof Gorgoroth], and [[[[[RDoombats].
+
+ *** Rodents (R) ***
+
+Small chittering creatures with quick feet and sharp teeth.
+The [[[[[Uwild rabbits] are utterly harmless unless angered, as
+are [[[[[oSquirrels]. The various giant mice ([[[[[wwhite], [[[[[Bsilver], [[[[[rred],
+[[[[[bblue], and [[[[[yyellow]) and rats ([[[[[Wwhite], [[[[[sgrey], [[[[[Rpink], and [[[[[Gtree])
+are somewhat dangerous, as they tend to run in large packs.
+The [[[[[urock moles], [[[[[Dwererats], and [[[[[gsquirrels of Mirkwood] are
+among the more dangerous rodents.
+
+
+ *** Snakes (J) ***
+
+Fast and stealthy creatures that slither along the floor. The
+[[[[[Ueels] are harmless, except when angered. The large [[[[[bblue], [[[[[Wsilver],
+[[[[[vpurple], [[[[[Rred], [[[[[sgrey], [[[[[yyellow], [[[[[ubrown], and [[[[[wwhite] snakes are
+somewhat dangerous. The [[[[[rRattlesnakes], [[[[[oCopperhead] snakes,
+[[[[[DBlack mambas], and [[[[[gKing cobras] are quite dangerous and fierce.
+The aquatic [[[[[BElectric eels] and [[[[[GLimlugs] (sea serpents) are
+among the most dangerous of their kind.
+
+ *** Beetles (K) ***
+
+Very large insects with tough carapaces. Most of them are not
+too dangerous. They come in the following varieties: [[[[[wwhite],
+[[[[[ubrown], [[[[[rred], [[[[[sgray], [[[[[oorange], [[[[[bblue], [[[[[Wsilver], [[[[[Ggreen], [[[[[Utree],
+[[[[[Rfire], [[[[[gstag], [[[[[Baquatic], [[[[[yslicer], [[[[[viridescent], and [[[[[Ddeath watch].
+
+
+ *** Reptiles (R) ***
+
+The majority of reptiles found on Middle-earth are not very
+dangerous - these include the [[[[[ynewts], [[[[[ucave lizards], [[[[[Urock lizards],
+[[[[[bnight lizards], [[[[[Bblue lizards], [[[[[oswamp lizards], [[[[[rgiant pink frogs],
+[[[[[ggiant green frogs], [[[[[wsnow-frogs], and [[[[[Wgiant silver frogs]. The
+[[[[[Rgiant salamanders] and [[[[[Ggiant turtles] should be approached
+with caution, while the [[[[[sbasilisks] and [[[[[Dgreater basilisks] are
+extremely dangerous and should not be toyed with!
+
diff --git a/lib/mods/theme/file/book-14.txt b/lib/mods/theme/file/book-14.txt
new file mode 100644
index 00000000..eb79aa38
--- /dev/null
+++ b/lib/mods/theme/file/book-14.txt
@@ -0,0 +1,55 @@
+ ------------------------
+ | Monstrous Compendium 6 |
+ | Morgoth's minions |
+ ------------------------
+
+ *** Orcs (o) ***
+
+Squat, swarthy creatures rumoured to have been Elves once.
+The [[[[[Usnotlings] and [[[[[osnaga] are the lowest form of Orc, weak
+but dangerous in packs. There are different breeds of Orc,
+depending on their dwelling-place: [[[[[uHill orcs], [[[[[GCave orcs],
+and [[[[[Dblack orcs]. The [[[[[sHalf-orcs] are a cross-breed of Orcs
+and humans. The [[[[[BUruk-hai] are a stronger breed, they can
+bear the light of the sun. The [[[[[wElite] uruks are the most
+dangerous kind of Orc there is.
+
+ *** Ogres (O) ***
+
+Monstrous and destructive creatures of legend and folklore.
+The [[[[[wOgrillon] is a cross-breed of an Orc and an Ogre, and
+the [[[[[oHalf-ogre] is a cross between an Ogre and a human. The
+garden-variety [[[[[UOgres] are more common than their [[[[[gForest]-
+dwelling, [[[[[sMountain]-dwelling, and [[[[[uCave]-dwelling cousins.
+The [[[[[DBlack ogres] shy away from the sun, the [[[[[BMerrows] live
+in or near water. There are some [[[[[yRebel ogres] who have
+turned against their plundering fellows and will try to aid
+adventurers.
+
+ *** Giants (P) ***
+
+Enormous humanoids with powerful muscles, aligned with evil.
+There are [[[[[WStone giants], [[[[[BStorm giants], [[[[[rFire giants], [[[[[wFrost]
+[[[[[wgiants], and [[[[[UHill giants] - while very large and dangerous,
+they pale in comparison to the much stronger [[[[[uCyclops], [[[[[bCloud]
+[[[[[bgiants], and the terrifying [[[[[sRock giants]. The [[[[[yLesser titans]
+and [[[[[oGreater titans] are in a class of their own, their power
+and magical abilities unmatched by any. The [[[[[RRebel giants] are
+those who have broken with the forces of Darkness.
+
+ *** Trolls (T) ***
+
+Lumbering evil creatures originated in mockery of the Ents.
+The [[[[[UHalf-trolls] are bizarre crosses between trolls and Men.
+The [[[[[uCave-trolls], [[[[[wSnow-trolls], [[[[[sHill trolls], [[[[[gForest trolls],
+[[[[[BWater trolls], and [[[[[WStone trolls] are dangerous and usually
+move in large groups. Even more dangerous are the [[[[[oAlgroths],
+the [[[[[yOlog-hai], and the [[[[[BScrags]. The [[[[[RWar trolls], [[[[[rEldraks], and
+[[[[[bEttins] can only be described as killing machines.
+
+ *** Yeeks (y) ***
+
+Small humanoid figures whose origin lies outside Middle-earth.
+There are [[[[[Bblue], [[[[[ubrown], [[[[[Ddark], [[[[[wwhite], [[[[[sgray], and [[[[[yyellow]
+Yeeks. The [[[[[gmaster yeeks] are somewhat proficient at magic, and
+[[[[[Uadventurer yeeks] will try to help you. \ No newline at end of file
diff --git a/lib/mods/theme/file/book-15.txt b/lib/mods/theme/file/book-15.txt
new file mode 100644
index 00000000..21983f48
--- /dev/null
+++ b/lib/mods/theme/file/book-15.txt
@@ -0,0 +1,68 @@
+ ------------------------
+ | Monstrous Compendium 7 |
+ | Dragons and Worms |
+ ------------------------
+
+ *** Worms (w) ***
+
+Large slimy masses of worms crawl all around dungeons.
+There are [[[[[Bclear], [[[[[rred], [[[[[bblue], [[[[[ggreen], [[[[[wwhite], [[[[[yyellow],
+[[[[[Dnether], and [[[[[vdisenchanter] worm masses. Additionally,
+there are [[[[[Ugiant slugs] and [[[[[ugiant leeches] which are more
+dangerous than the worm masses. The [[[[[vpurple worms] and
+[[[[[ysandworms] are even more dangerous, and then there are
+the [[[[[uwereworms], huge wormlike shapes dripping acid.
+
+ *** Dragon worms (w) ***
+
+These will eventually grow into dragons, unless killed.
+There are [[[[[Rred], [[[[[Bblue], [[[[[Ggreen], [[[[[Wwhite], [[[[[sblack], [[[[[ygold],
+[[[[[ubronze], and [[[[[vmulti-hued ones].
+
+ *** Hatchling dragons (d) ***
+
+The [[[[[opseudo-dragon] is a small relative of the dragon that
+inhabits dark caves. The hatchling dragons are newly-born,
+still soft, with eyes unaccustomed to light and scales
+shimmering with a hint of colour: [[[[[rred], [[[[[bblue], [[[[[ggreen],
+[[[[[wwhite], [[[[[sblack], [[[[[Ubronze], [[[[[ygold], and [[[[[vmulti-hued]. There are
+also the aquatic [[[[[WHatchling dragon turtles].
+
+
+ *** Young dragons (d) ***
+
+The young dragons sport still-tender scales, coloured more
+brightly than those of the Hatchling dragons: [[[[[rred], [[[[[bblue],
+[[[[[ggreen], [[[[[wwhite], [[[[[sblack], [[[[[Ubronze], [[[[[ygold], and [[[[[vmulti-hued].
+The [[[[[Wyoung dragon turtles] live in or near water.
+
+ *** Drakes (d) ***
+
+These dragons are already mature, and their scales are very
+brightly covered, according to the elements each dragon
+draws its power from. There are [[[[[rFire-drakes], [[[[[bBlue drakes],
+[[[[[gGreen drakes], [[[[[wCold-drakes], [[[[[sBlack drakes], [[[[[UBronze drakes],
+[[[[[yGolden drakes], [[[[[vMulti-hued drakes], [[[[[vBalance drakes], [[[[[vLaw]
+[[[[[vdrakes], [[[[[vChaos drakes], [[[[[uCrystal drakes], [[[[[oEthereal drakes],
+[[[[[GShadow drakes], and [[[[[sMature dragon turtles].
+
+
+ *** Ancient dragons (D) ***
+
+These dragons are very old, cunning, and powerful. They are
+considerably larger than the drakes, and they too draw their
+colouring from their elements: [[[[[rred], [[[[[bblue], [[[[[ggreen], [[[[[wwhite],
+[[[[[sblack], [[[[[Ubronze], [[[[[ygold], and [[[[[vmulti-hued]. In addition, there
+are the [[[[[GDeath drakes], [[[[[UGreat crystal drakes], [[[[[oAncient ethereal]
+[[[[[odrakes], [[[[[BSky drakes], and [[[[[WAncient dragon turtles].
+
+ *** Greater dragons (D) ***
+
+The mightiest and most powerful of dragonkind, these beasts
+are older than time itself. Their very names instill fear into
+your very soul: the [[[[[rGreat Worm of Fire], the [[[[[bGreat Storm Worm],
+the [[[[[gGreat Swamp Worm], the [[[[[wGreat Ice Worm], the [[[[[sGreat Bile Worm],
+the [[[[[UGreat Worm of Perplexity], the [[[[[yGreat Worm of Thunder],
+the [[[[[vGreat Worm of Many Colours], the [[[[[GFastitocalon], the [[[[[vGreat]
+[[[[[vWorm of Balance], the [[[[[RDracolisk], the [[[[[vGreat Worm of Chaos], the
+[[[[[GDracolich], the [[[[[BGreat Worm of Law], and the [[[[[vGreat Wyrm of Power].
diff --git a/lib/mods/theme/file/book-16.txt b/lib/mods/theme/file/book-16.txt
new file mode 100644
index 00000000..e19b7b0b
--- /dev/null
+++ b/lib/mods/theme/file/book-16.txt
@@ -0,0 +1,43 @@
+ -------------------------
+ | Monstrous Compendium 8 |
+ | Depth dwellers, hybrids |
+ -------------------------
+
+ *** Nagas (n) ***
+
+Giant snake-like figures with a woman's torso. There are
+[[[[[ggreen], [[[[[Rred], [[[[[Dblack], [[[[[Bwater], [[[[[oswamp], [[[[[ubrown], [[[[[Wsilver],
+[[[[[vnight], [[[[[Gtree], [[[[[sdark], [[[[[bocean], [[[[[yguardian], and [[[[[wspirit nagas].
+The [[[[[Uadventurer nagas] are friendly to their fellows.
+
+ *** Hydras (M) ***
+
+Strange reptilian creatures with several heads, guarding
+treasure hoards. There are [[[[[u2-headed], [[[[[o3-headed], [[[[[y4-headed],
+[[[[[g5-headed], [[[[[w6-headed], [[[[[G7-headed], [[[[[s8-headed], [[[[[r9-headed],
+[[[[[b10-headed], [[[[[R11-headed], [[[[[W12-headed], [[[[[v13-headed], [[[[[B14-headed],
+[[[[[U15-headed], as well as [[[[[DKiller hydras].
+
+ *** Hybrids (H) ***
+
+These creatures are all crosses between two (or sometimes
+more) different beings. The [[[[[wWhite harpies], [[[[[DBlack harpies],
+and [[[[[oOwlbears] are not very dangerous. The [[[[[UHippogryphs],
+[[[[[uGriffons], [[[[[RGorgimaerae], [[[[[BBehemoths], [[[[[rChimaerae], [[[[[yManticores],
+and [[[[[GSphinxes] are more dangerous and deadly. The [[[[[bGorgons],
+[[[[[WHeadless], [[[[[gSwamp things], and [[[[[vJabberwocks] are the deadliest.
+
+ *** Depth dwellers (~) ***
+
+These creatures inhabit the oceans, lakes, and seas of Arda.
+Along with the [[[[[BSand mites], [[[[[BBox jellyfish], [[[[[GBarracudas], and
+[[[[[RPiranhas] there are [[[[[yStargazers], [[[[[gOctopi], [[[[[WGlobefish], [[[[[sPikes],
+[[[[[sSwordfish], and [[[[[sFlounders]. More dangerous are [[[[[rGiant crayfish],
+[[[[[RGiant piranhas], and [[[[[gGiant squid]. Among the larger depth-
+dwellers, there are the [[[[[WHammerhead sharks], [[[[[oTiger sharks],
+[[[[[wWhite sharks], [[[[[oSeahorses], and [[[[[gGiant octopi]. The largest and
+more dangerous creatures include the [[[[[DWhales], [[[[[UElder stargazers],
+[[[[[wGreat white sharks], [[[[[uUndead stargazers], [[[[[GLesser Krakens],
+[[[[[wKiller whales], and [[[[[GGreater Krakens]. The most dangerous ocean
+dweller is the [[[[[vLeviathan].
+
diff --git a/lib/mods/theme/file/book-17.txt b/lib/mods/theme/file/book-17.txt
new file mode 100644
index 00000000..13aa439f
--- /dev/null
+++ b/lib/mods/theme/file/book-17.txt
@@ -0,0 +1,47 @@
+ ------------------------
+ | Monstrous Compendium 9 |
+ | Undead Creatures |
+ ------------------------
+
+ *** Mewlips (i) ***
+
+Mewlips are evil cannibal spirits from the marshlands.
+They come in different varieties: [[[[[wclear], [[[[[sgray], [[[[[oorange],
+[[[[[rbloodshot], [[[[[ggreen], [[[[[bblue], [[[[[ubrown], [[[[[Wstone], [[[[[yyellow], [[[[[Rpink],
+[[[[[Gtree], [[[[[Bair], [[[[[Uplague], and [[[[[Ddeath].
+
+
+ *** Golems (g) ***
+
+Massive animated statues made from different materials.
+There are [[[[[obronze], [[[[[wbone], [[[[[ueog], [[[[[Bmithril], [[[[[siron], [[[[[baquatic],
+[[[[[Wstone], [[[[[Uclay], [[[[[Rflesh], and [[[[[ffire golems], in addition to the
+more cunning [[[[[ycolbrans], [[[[[DPukelmen], [[[[[gdrolems], [[[[[Gcolossus], and
+[[[[[ssilent watchers].
+
+ *** Skeletons (s) ***
+
+There are skeletal forms of just about any monster that once
+inhabited Middle-earth. Some such forms, however, have never
+been alive in the first place - they are horrible abominations
+animated by powerful wizards. Among them are the [[[[[wice skeletons],
+[[[[[sflying skulls], [[[[[Dcrypt creeps], [[[[[yhand druj], [[[[[oskull druj], and
+[[[[[reye druj].
+
+ *** Zombies (z) ***
+
+Zombie forms of all living creatures may appear in the dungeons.
+However, some zombie-like undead from before the First Age do
+exist: [[[[[Ughouls], [[[[[ygreater mummies], [[[[[Dghoulkings], [[[[[ughasts], and
+[[[[[Rrotting corpses].
+
+ *** Vampires (V) ***
+
+There are vampire forms of just about any race - [[[[[Whuman], [[[[[Gelf], [[[[[Dorc],
+[[[[[wyeek], [[[[[oogre], [[[[[utroll], [[[[[Rdwarf], and [[[[[Bgnome]. The [[[[[sOriental vampires]
+come from beyond the land of Rhun. There are [[[[[bVampire lords], [[[[[rElder]
+[[[[[rvampires], and [[[[[gMaster vampires]. The [[[[[UAdventurer vampires] are those
+who have denounced the way of the Dark and attempt to follow a path
+of Light as best they can.
+
+
diff --git a/lib/mods/theme/file/book-18.txt b/lib/mods/theme/file/book-18.txt
new file mode 100644
index 00000000..36cbee04
--- /dev/null
+++ b/lib/mods/theme/file/book-18.txt
@@ -0,0 +1,55 @@
+ --------------------------
+ | Monstrous Compendium 10 |
+ | Demons and other Horrors |
+ --------------------------
+
+ *** Minor Demons (u) ***
+
+These demons (roeg) are corrupted forms of natural creatures.
+The individual types of demons are as follows: [[[[[bLimrog] (fish),
+[[[[[UCaborrog] (frog), [[[[[DLygrog] (snake), [[[[[oDraugrog] (wolf), [[[[[rHurog] (dog),
+[[[[[sSarnrog] (stone), [[[[[gNarrog] (rat), [[[[[yAewrog] (bird), [[[[[BRawrog] (lion),
+and [[[[[RAdanrog] (human).
+
+ *** Major Demons (u) ***
+
+The major demons are of two kinds - the spider demons, spawn of
+Ungoliant, and the Balroeg, corrupted Maiar. The spider demons
+are as follows: [[[[[gUngorrog] (power spider demon), [[[[[WHelcungol] (ice),
+[[[[[rNaurungol] (fire), [[[[[sMornungol] (black), and [[[[[BFaunungol] (cloud).
+There are also the [[[[[BGaurroeg] (water demons), [[[[[oMorgulroeg] (magic
+demons), [[[[[uDagorrog] (war demons), [[[[[ySererrog] (blood demons), and
+the [[[[[UMenelroeg] (sky demons). The Balroeg can be [[[[[RRed], [[[[[DBlack],
+[[[[[wWhite], and [[[[[bBlue] - commanded by [[[[[GBalrog Captains] and [[[[[vGreater]
+[[[[[vBalroeg].
+
+ *** Greater Undead (G) ***
+
+The ghosts are incorporeal beings with awesome magical powers.
+Some of them aren't very impressive, like the [[[[[gGreen glutton]
+[[[[[gghost] and the [[[[[sPoltergeist]. Others are deadlier - [[[[[wGhosts],
+[[[[[BPhantom beasts], [[[[[BDrowned souls], [[[[[BPhantom warriors], the [[[[[DShadows],
+[[[[[DPossessors], [[[[[DShades], and [[[[[USpectres]. The friendly [[[[[WSpirits] will
+try to help adventurers. The [[[[[bBanshee], [[[[[GSpirit troll], [[[[[vPhantom],
+[[[[[uHeadless ghost], and [[[[[uMoaning spirit] are all to be reckoned with.
+In a class of their own are the [[[[[oDreads], [[[[[rDreadlords], and the
+[[[[[yDreadmasters].
+
+ *** Liches (L) ***
+
+Yet another kind of powerful undead. Many things can take the form
+of a lich, but the [[[[[oLich], [[[[[GCrypt thing], [[[[[WIron lich], [[[[[rMaster lich],
+[[[[[uMonastic lich], [[[[[UDemilich], [[[[[BArchlich], [[[[[DBlack reaver], and [[[[[sLesser]
+[[[[[sblack reaver] all deserve special mention.
+
+
+ *** Wraiths (W) ***
+
+Wraiths are incorporeal beings frequently found in graveyards and
+at the sites of unavenged murders. There are [[[[[wWhite wraiths], [[[[[sGrey]
+[[[[[swraiths], [[[[[WSilver wraiths], [[[[[GNether wraiths], and [[[[[DBlack wraiths].
+The [[[[[UAdventurer wraiths] will try to help you. Fierce and magical
+are the many wights: [[[[[BBarrow wights], [[[[[gForest wights], [[[[[bGrave wights],
+[[[[[oSwamp wights], and [[[[[rEmperor wights]. The most dangerous among the
+wraith beings are the [[[[[uRevenant], [[[[[DNightwalker], [[[[[DNightcrawler], and
+[[[[[DNightwing]. \ No newline at end of file
diff --git a/lib/mods/theme/file/book-19.txt b/lib/mods/theme/file/book-19.txt
new file mode 100644
index 00000000..a36285f0
--- /dev/null
+++ b/lib/mods/theme/file/book-19.txt
@@ -0,0 +1,47 @@
+ -------------------------
+ | Monstrous Compendium 11 |
+ | Elemental creatures |
+ -------------------------
+
+ *** Vortices (v) ***
+
+These strange creatures are like localised tornadoes,
+carrying with them the various elements: [[[[[rfire], [[[[[benergy],
+[[[[[ggas], [[[[[wcold], [[[[[sacid], [[[[[ushards], [[[[[vnexus], [[[[[ymana], [[[[[Uconfusion],
+[[[[[Wslowness], [[[[[vchaos], [[[[[Gnether], [[[[[Rplasma], and [[[[[Btime]. Among
+these, the nastiest by far are the [[[[[vstorms of unmagic],
+as well as [[[[[oshimmering], [[[[[Ddeath], and [[[[[vaether] vortices.
+
+ *** Spirits (E) ***
+
+These are the spirits contained in various elements, they
+are weaker than the proper elementals. There are [[[[[rFire]
+[[[[[rspirits], [[[[[bWater spirits], [[[[[uEarth spirits], and [[[[[BAir spirits]
+alongside [[[[[WWill'o the wisps] and [[[[[yInvisible stalkers].
+
+ *** Elementals (E) ***
+
+Towering masses of raw elements, twisting and shaking all
+in their wake: [[[[[rfire], [[[[[bwater], [[[[[uearth], [[[[[Bair], [[[[[wice], [[[[[omagma],
+[[[[[Uconfusion], [[[[[Ddark], [[[[[Rsmoke], [[[[[gooze], [[[[[sslowness], [[[[[Gtime], and
+[[[[[vchaos].
+
+ *** Hulking figures (X, Y) ***
+
+These are strange hulking shapes that puzzle anyone who
+comes across them. They include the [[[[[sXaren], the [[[[[uXorn],
+[[[[[UUmber hulk], [[[[[DDeath hulk], [[[[[wWhite hulk], [[[[[oOrange hulk], [[[[[rFire]
+[[[[[rhulk], [[[[[gForest hulk], [[[[[bNight hulk], [[[[[WSilver hulk], [[[[[vChaos hulk],
+[[[[[yYellow hulk], [[[[[RRed hulk], [[[[[GGreen hulk], and [[[[[Bblue hulk]. The
+[[[[[sSasquatch] and [[[[[wYeti] resemble humans, but they are still
+quite strange.
+
+ *** Zephyr Hounds (Z) ***
+
+They are dog-like figures wreathed in the elements. They
+tend to move in packs, and are among the most vicious of
+all dungeon dwellers. The hounds may be: [[[[[Bclear], [[[[[rfire],
+[[[[[benergy], [[[[[gair], [[[[[wcold], [[[[[sacid], [[[[[vmulti-hued], [[[[[Ddark], [[[[[olight],
+[[[[[uearth], [[[[[Baquatic], [[[[[vnexus], [[[[[rwater], [[[[[Rplasma], [[[[[yvibration],
+[[[[[vchaos], [[[[[Gnether], [[[[[uimpact], [[[[[Winertia], [[[[[Ugravity], [[[[[Gethereal],
+[[[[[Btime], and [[[[[vaether]. \ No newline at end of file
diff --git a/lib/mods/theme/file/book-2.txt b/lib/mods/theme/file/book-2.txt
new file mode 100644
index 00000000..bfadd6ce
--- /dev/null
+++ b/lib/mods/theme/file/book-2.txt
@@ -0,0 +1,90 @@
+
+ Ted Sandyman's Important Compendium of Deep Thought, Vol. 3
+ -------------------------------------------------------
+
+
+I think my new thing will be to try to be a real happy guy. I'll just
+walk around being real happy until some jerk says something stupid to
+me.
+
+When you're going up the stairs and you take a step, kick the other
+leg up high behind you to keep people from following too close.
+
+I wonder if angels believe in ghosts.
+
+I don't understand people who say life is a mystery, because what is
+it they want to know?
+
+I think people tend to forget that trees are living creatures. They're
+sort of like dogs. Huge, quiet, motionless dogs, with bark instead of
+fur.
+
+Sometimes I think the world has gone completely mad. And then I think,
+"Aw, who cares?" And then I think, "Hey, what's for supper?"
+
+If a kid asks where rain comes from, I think a cute thing to tell him
+is "God is crying". And if he asks why God is crying, another cute
+thing to tell him is "Probably because of something you did".
+
+Contrary to popular belief, the most dangerous animal is not the lion
+or tiger or even the elephant. The most dangerous animal is a shark
+riding on an elephant, just trampling and eating everything they see.
+
+As I bit into the nectarine, it had a crisp juiciness about it that
+was very pleasurable- until I realized it wasn't a nectarine at all,
+but a HUMAN HEAD!!
+
+Anytime I see something screech across a room and latch onto someone's
+neck, and the guy screams and tries to get it off, I have to laugh,
+because what _is_ that thing?!
+
+If you define cowardice as running away at the first sign of danger,
+screaming and tripping and begging for mercy, then yes, Mister Brave
+Man, I guess I am a coward.
+
+Blow ye winds, like the trumpet blows, but without that noise.
+
+The face of a child can say it all, especially the mouth part of the face.
+
+When I heard that trees grow a new "ring" for each year they live, I
+thought, we humans are kind of like that; we grow a new layer of skin
+each year; and after many years we are thick and unwieldy from all our
+skin layers.
+
+It's too bad that whole families have been torn apart by something as
+simple as wild dogs.
+
+Even though he was an enemy of mine, I had to admit that what he had
+accomplished was a brilliant piece of strategy. First, he punched me,
+then he kicked me, then he punched me again.
+
+To me, truth is not some vague, foggy notion. Truth is real. And, at
+the same unreal. Fiction and fact and everything in-between, plus some
+things I can't remember, all rolled into one big "thing". This is
+truth, to me.
+
+If you're ever stuck in some thick undergrowth, in your underwear,
+don't stop and start thinking of what other words have "under" in
+them, because that's probably the first sign of jungle madness.
+
+Sometimes the beauty of the world is so overwhelming, I just want to
+throw back my head and gargle. Just gargle and gargle, and I don't
+care who hears me, because I am beautiful.
+
+We used to laugh at Grandpa when he'd head off to go fishing. But we
+wouldn't be laughing when he'd come back with some whore he picked up
+in town.
+
+I think in one of my previous lives I was a mighty king, because I
+like people that do what I say.
+
+A man doesn't automatically get my respect. He has to get down in the
+dirt and beg for it.
+
+People think it would be fun to be a bird because you could fly. But
+they forget the negative side, which is the preening.
+
+When I think back on all the blessings I have been given in my life, I
+can't think of a single one, unless you count that rattlesnake that
+granted me all those wishes.
+
diff --git a/lib/mods/theme/file/book-20.txt b/lib/mods/theme/file/book-20.txt
new file mode 100644
index 00000000..21418fe9
--- /dev/null
+++ b/lib/mods/theme/file/book-20.txt
@@ -0,0 +1,192 @@
+#####R /----------------------------------------\
+#####R < Adventurer's guide to the Middle-earth >
+#####R \----------------------------------------/
+
+Summary:
+*****/abook-20.txt*1[(a) The main towns and dungeons]
+*****/bbook-20.txt*2[(b) Other towns]
+*****/cbook-20.txt*3[(c) Other strange and frightening places]
+*****/dbook-20.txt*4[(d) Equipment issues]
+*****/ebook-20.txt*5[(e) Macros]
+
+#####GIntroduction:
+
+Middle-earth is vast and mysterious, full of dangers and rewards for
+the brave adventurer.
+
+New adventurers should know that pressing < and > can switch
+the wilderness view between a normal scale and a larger map. This map
+makes travelling faster, but you cannot enter wilderness dungeons from
+it, and chances of being ambushed are high. The wariest of adventurers
+will choose to take the well-worn roads when such roads are available,
+and grass fields when there are no roads. Beware of Belegaer and the
+Dead Marshes!
+
+
+~~~~~1
+#####G(a) The main towns and dungeons
+
+You start in a small village named Bree in the western part of Middle-earth.
+Here you will also find the entrance to the Barrow-Downs, a fairly safe and
+simple dungeon.
+
+When the Barrow-Downs become too easy for you, and Bree too small,
+you might consider going to Lothlorien, the land of Galadriel. [[[[[BNote that]
+[[[[[Byou should take a lot of food with you, for it is a long journey.]
+You'll have to head south-east following the Moria mountain's chain, then
+walk around the forest of Fangorn to head north to finally find your destination.
+Lothlorien is instantly recognisable by its Mallorn trees. The chief city of this
+land and the abode of Galadriel and Celebron is Caras Galadhon. The Forest of
+Mirkwood (another dungeon) can be found to the north-east of Lothlorien.
+
+If you survive this dangerous dungeon, you should head south, following
+the Anduin river. There, near the dark land of Mordor, you will find the
+great town of Gondor, Minas Anor. From there you may want to pay a visit
+to the land of Mordor, which is east of Minas Anor. You cannot pass through
+the Black Gate of Mordor without a means of climbing mountains, for the
+gate is guarded heavily, night and day. The only ways into Mordor are through
+the dreaded Spider Pass (Cirith Ungol), or the circuitous route through the
+valley of Nurnen and the horrid plains of Gorgoroth.
+
+After Mordor you should finally travel to Gondolin, the hidden town of the
+Noldor. From this city, you will be able to attack Angband, the
+dungeon of Morgoth, which is north-east of Gondolin. This city is well-
+protected by what remains of the Echoriath, and there is but one route
+into it that does not force you to travel by the sea. To be sure of finding
+Gondolin, travel north along the Blue Mountains, then take the north-eastern
+route from the second northernmost peak.
+
+
+~~~~~2
+#####G(b) Other towns
+
+To the west of Bree, in the middle of a land called the Shire, there is a
+small village called Hobbiton, inhabited by Halflings. Nested in some low
+hills, it isn't hard to find, and their hospitality is legendary.
+
+To the east of Bree, there is Rivendell - the hidden valley of the Elves,
+where Elrond lives in the Last Homely House (Imladris). Beyond the Misty
+Mountains, near the entrance to Mirkwood Forest, there is the house of
+Beorn.
+
+When you are in Lothlorien, be sure to pay your respects to the Valar at
+Cerin Amroth, which is immediately to the north of Caras Galadhon.
+
+Edoras, the capital of Rohan (home of the horse-lords, the Rohirrim) can be
+found to the south of Caras Galadhon. It is a well-protected fortress, second
+only to the fortress of Helm's Deep, which stands watch against Isengard.
+
+There are two cities near Minas Anor - Pelargir (the great city at the
+mouth of the Anduin River) and Osgiliath, the citadel of Stars. Pelargir is
+to the south-west of Minas Anor, and Osgiliath is to the north-east of
+Gondor's capital. Rumour has it that there is a Ranger outpost somewhere in
+Ithilien, immediately to the north of Osgiliath.
+
+If you travel north towards the Lonely Mountain, you will come upon
+Esgaroth, the city of Lake-men. Near Esgaroth is the construction site for
+Dale, and if you follow the river, you may find yourself a guest in the
+Halls of Thranduil, King of the Wood-Elves.
+
+Deep in the heart of the Misty Mountains, in a heavily guarded area that
+cannot be access but through the Mines of Moria, lies Khazad-dum, the
+greatest city ever built by Dwarves.
+
+~~~~~3
+#####G(c) Other strange and frightening places
+
+The Old Forest to the west of Bree (and east of Hobbiton) is what remains
+of the big forests of the First Age, but it has been corrupted. It is said
+that it is guarded by a living tree.
+
+You may also wish to investigate the Orc Caves east of Bree; they are
+another place suitable for those finished with the Barrow-Downs. They also
+are rumoured to hold great mysteries - these are the same caves where Bilbo
+had once found the One Ring of power.
+
+Durin's Bane, the Balrog of Moria, guards the Mines of Moria, to the south-east
+of Bree. The Mines are also the only means of access to the Dwarven
+stronghold of Khazad-dum.
+
+Nearly at the edge of land, there is a magical Maze. Many adventurers
+that ventured there never came back. It is rumoured that a Minotaur is
+lurking down there, guarding an ancient and powerful artifact.
+Bring along digging equipment and some means to recall.
+
+During the Second Age of the world there was a great island called
+Numenor. The people who dwelt there were wise and powerful, but as time
+passed their last kings fell under the power of Sauron. Under Sauron's
+orders, they tried to attack Valinor, the blessed land, and for this
+Numenor was destroyed, swallowed by the sea. The ruins are still
+accessible, far out to sea to the west of Bree. Any adventurer going
+there should be sure to bring equipment that enables underwater
+breathing, however - without it, you shall perish.
+
+Many other strange places wait to be explored by the valiant adventurer,
+but their locations are secret. You will have to find them yourself!
+Among them are the Grinding Ice of the Helcaraxe, Forodwaith, the caves
+beneath Isengard, the land of Rhun, and many others.
+
+
+~~~~~4
+#####G(d) Equipment issues
+
+Beware, adventurer! If you plan to go down into the dungeons, be prepared. Some
+items you will need badly.
+
+First, think of some light: maybe a lantern is better than the torches.
+
+Second things to mention are your combat equipment. Sometimes the weapon and
+armor you got from your mentor are not enough for the nasties inside the
+dungeons.
+
+And third and most important, [[[[[Balways carry a shovel or other digger with you],
+because there is much rubble in the dungeons, which you cannot clear with
+your hands.
+
+~~~~~5
+#####G(e) Macros
+
+Spellcasters might find that pressing 4 keys (at least) to cast a spell is a
+lot, they are right. That is why there are macros. You can access the macro
+screen by pressing @. You can find help on the *****macrofaq.txt*0[macros] in the docs.
+
+Now you either have the hard way or the easy way.
+
+**The Hard Way**
+
+What the fellow adventurer should know is how to create a basic spell macro.
+Press @ to enter the macro screen.
+Press 4 to create a new macro.
+Press the key to bind the macro to, usually one uses the F* keys(you can combine
+them with the ctrl, shift, ... keys too)
+Enter the key sequence to be done for the macro.
+Press 2 to save the macro.
+
+Now a problem that might arise, imagine your macro looks like: mcaa*t
+to cast manathrust spell('m' to use skill, 'c' for cast a spell skill,
+'a' for first book, 'a' for first spell, *t to… target the first monster).
+This macro will break if you gain a new skill so that "Cast a spell" is no more
+the skill 'c', or if you get a new book. There is a way around that.
+When the game asks for a skill or a spell it allows you to press @ to enter
+the skill/spell name directly, so your macro would become:
+m@Cast a spell\r@Manathrust\r*t
+Now this will always work as long as one of your books have the spell in it.
+
+
+**The Easy Way**
+
+This time you will only use the macro recorder. To do that:
+Press $ to start it
+Now each key you press will be recorded, so press all keys you want.
+It is recommended to start your macro by pressing Escape key a few time, so
+if there are messages when you use the macro it will first erase them instead
+of screwing your macro :)
+it is also recommended to take advantage of the @ key when selecting skills or
+objects whenever the possibility is offered to you. It will make sure you
+always use the good object/skill even if it moves in your inventory.
+Once all keys are pressed press $ again to stop it.
+It you are satisfied with your macro now you get to press the key to bind it
+to.
+
+As in the Hard Way you must use the macro screen if you want to permanently
+save your macros.
diff --git a/lib/mods/theme/file/book-200.txt b/lib/mods/theme/file/book-200.txt
new file mode 100644
index 00000000..75577e1a
--- /dev/null
+++ b/lib/mods/theme/file/book-200.txt
@@ -0,0 +1,5 @@
+4
+35
+21
+6
+0
diff --git a/lib/mods/theme/file/book-201.txt b/lib/mods/theme/file/book-201.txt
new file mode 100644
index 00000000..fdcae8aa
--- /dev/null
+++ b/lib/mods/theme/file/book-201.txt
@@ -0,0 +1,5 @@
+4
+3
+11
+8
+0
diff --git a/lib/mods/theme/file/book-202.txt b/lib/mods/theme/file/book-202.txt
new file mode 100644
index 00000000..3c61caee
--- /dev/null
+++ b/lib/mods/theme/file/book-202.txt
@@ -0,0 +1,5 @@
+4
+50
+34
+4
+0
diff --git a/lib/mods/theme/file/book-203.txt b/lib/mods/theme/file/book-203.txt
new file mode 100644
index 00000000..c169a628
--- /dev/null
+++ b/lib/mods/theme/file/book-203.txt
@@ -0,0 +1,5 @@
+4
+60
+56
+3
+0
diff --git a/lib/mods/theme/file/book-204.txt b/lib/mods/theme/file/book-204.txt
new file mode 100644
index 00000000..37b88559
--- /dev/null
+++ b/lib/mods/theme/file/book-204.txt
@@ -0,0 +1,5 @@
+4
+1
+1
+99
+64
diff --git a/lib/mods/theme/file/book-205.txt b/lib/mods/theme/file/book-205.txt
new file mode 100644
index 00000000..fecab40c
--- /dev/null
+++ b/lib/mods/theme/file/book-205.txt
@@ -0,0 +1,5 @@
+4
+51
+50
+3
+0
diff --git a/lib/mods/theme/file/book-206.txt b/lib/mods/theme/file/book-206.txt
new file mode 100644
index 00000000..ed1f1c17
--- /dev/null
+++ b/lib/mods/theme/file/book-206.txt
@@ -0,0 +1,5 @@
+4
+66
+18
+1
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-207.txt b/lib/mods/theme/file/book-207.txt
new file mode 100644
index 00000000..0a9fb804
--- /dev/null
+++ b/lib/mods/theme/file/book-207.txt
@@ -0,0 +1,5 @@
+4
+25
+21
+3
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-208.txt b/lib/mods/theme/file/book-208.txt
new file mode 100644
index 00000000..1a853553
--- /dev/null
+++ b/lib/mods/theme/file/book-208.txt
@@ -0,0 +1,5 @@
+4
+63
+53
+1
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-209.txt b/lib/mods/theme/file/book-209.txt
new file mode 100644
index 00000000..040cf93c
--- /dev/null
+++ b/lib/mods/theme/file/book-209.txt
@@ -0,0 +1,5 @@
+4
+57
+62
+3
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-210.txt b/lib/mods/theme/file/book-210.txt
new file mode 100644
index 00000000..7c1f25d5
--- /dev/null
+++ b/lib/mods/theme/file/book-210.txt
@@ -0,0 +1,5 @@
+4
+55
+19
+1
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-211.txt b/lib/mods/theme/file/book-211.txt
new file mode 100644
index 00000000..3806768d
--- /dev/null
+++ b/lib/mods/theme/file/book-211.txt
@@ -0,0 +1,5 @@
+4
+67
+16
+1
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-212.txt b/lib/mods/theme/file/book-212.txt
new file mode 100644
index 00000000..c2891872
--- /dev/null
+++ b/lib/mods/theme/file/book-212.txt
@@ -0,0 +1,5 @@
+4
+63
+51
+1
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-213.txt b/lib/mods/theme/file/book-213.txt
new file mode 100644
index 00000000..0716c26e
--- /dev/null
+++ b/lib/mods/theme/file/book-213.txt
@@ -0,0 +1,5 @@
+4
+45
+46
+3
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-214.txt b/lib/mods/theme/file/book-214.txt
new file mode 100644
index 00000000..d99dd3d8
--- /dev/null
+++ b/lib/mods/theme/file/book-214.txt
@@ -0,0 +1,5 @@
+4
+61
+16
+3
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-215.txt b/lib/mods/theme/file/book-215.txt
new file mode 100644
index 00000000..fc5b3ed3
--- /dev/null
+++ b/lib/mods/theme/file/book-215.txt
@@ -0,0 +1,5 @@
+4
+48
+21
+1
+0 \ No newline at end of file
diff --git a/lib/mods/theme/file/book-216.txt b/lib/mods/theme/file/book-216.txt
new file mode 100644
index 00000000..4acc56af
--- /dev/null
+++ b/lib/mods/theme/file/book-216.txt
@@ -0,0 +1,5 @@
+4
+1
+1
+99
+6
diff --git a/lib/mods/theme/file/book-22.txt b/lib/mods/theme/file/book-22.txt
new file mode 100644
index 00000000..99dd4e90
--- /dev/null
+++ b/lib/mods/theme/file/book-22.txt
@@ -0,0 +1,56 @@
+ -----------------------
+ | Artifact Lore Vol. IV |
+ | Axes |
+ -----------------------
+
+The Great Axe of Durin
+ The twin massive axe heads of this ancient demon's dread gleam with
+ mithril inlay, which tell sagas of endurance, invoking the powers of
+ Khazad-dum to protect the wearer and slay all evils found underground.
+
+The Great Axe of Eonwe
+ The axe of Eonwe, leader of the Hosts of the West before the gates of
+ Thangorodrim, strikes with icy wrath at the undead, disperses hosts of
+ evil at a word, and grants Maia-like powers of body and mind.
+
+The Broad Axe 'Barukkheled'
+ A royal heirloom of the southern coast, strong in combat against evil
+ creatures of the earth.
+
+The Bearded Axe of Gimli
+ "Gimli sensed the Dead behind following, but he continued on after
+ Aragorn." The trusty axe of Gimli son of Gloin, one of the Nine
+ Walkers of old.
+
+The Light War Axe 'Cam-tal-crist'
+ The Petty-dwarves of Bathak forged this blade, and it shares their thirst
+ for blood.
+
+The Broad Axe 'Orchast'
+ Forged by the dwarves of Khazad-dum in a time of desperation, this axe
+ turned many a battle against the invading orcs.
+
+The Hatchet of the Night
+ Found on an unmarked grave after a violent storm, this hatchet has a
+ sinister aura of darkness and decay.
+
+The Slaughter Axe 'Lavandagnir'
+ Used by the orcs in their battle at Dagor Bragollach against the elves,
+ this axe has a bloodthirst for nature.
+
+The Light War Axe of Helcar
+ Crafted of purest ice and held solid by powerful spells, this icy axe
+ delivers a chill of death to its victims.
+
+The Slaughter Axe 'Dramborleg'
+ The great axe of Tuor, Thudder-Sharp is its name. The axe that smote both
+ a heavy dint as of a club and cleft as a sword. When it was swung by the
+ hands of Tuor, it sang like the rush of eagle's wings in the air and took
+ death as it fell. Its name alone instills fear in Balrogs and other
+ corruptions of Morgoth.
+
+The Slaughter Axe 'Garachoth'
+ A ghastly axe with the soul of a demon lord trapped inside, this horrifying
+ creation reverberates with the screams of the damned. As you gaze into its
+ glassy, translucent blade, it seems that endless sulphurous wastelands
+ stretch away from you into the distance, obscured, by sheets of fire.
diff --git a/lib/mods/theme/file/book-23.txt b/lib/mods/theme/file/book-23.txt
new file mode 100644
index 00000000..5d5c22f9
--- /dev/null
+++ b/lib/mods/theme/file/book-23.txt
@@ -0,0 +1,81 @@
+ ----------------------
+ | Artifact Lore Vol. V |
+ | Missile Weapons |
+ ----------------------
+
+The Long Bow 'Belthronding'
+ The great bow of Beleg, made of black yew and strung with elven hair that
+ faintly shines a pale clear gold.
+
+The Long Bow of Bard
+ The great yew bow of grim-faced Bard, who shot the mightiest arrow that
+ songs record.
+
+The Light Crossbow 'Cubragol'
+ A crossbow that grants fiery speed to he who finds it, and from which
+ shoot bolts that blaze with flame unquenchable.
+
+The Sling of the Thain
+ This sling was crafted by Faramir I, Thain of the Shire, just in case the
+ nasties of his father's stories ever dare to enter the Shire again.
+
+The Sling of Farmer Maggot
+ This ordinary seeming leather sling has been raised to legendary status
+ amongst generations of hobbit children. Farmer Maggot's ability to notice
+ and strike any mushroom thief anywhere within his patch almost keeps young
+ poachers at bay, but once they get within range they soon flee for less
+ painful pastures, frequently with rounded pebbles stinging their
+ backsides...
+
+The Heavy Crossbow of Umbar
+ A great brazen arbalest with arms of gleaming steel, shooting quarrels
+ with speed and power for those brave enough to risk betrayal.
+
+The Short Bow of Amrod
+ This bow, and its twin, belonged to Feanor's last two twin sons, Amrod and
+ Amras, who both hunted with the Green-elves for a time. Like the twins,
+ the bows are similar, for both protect their wielders from the elementsand
+ strength, while the other gives quickness and subtlety.
+
+The Short Bow of Amras
+ This bow, and its twin, belonged to Feanor's last two twin sons, Amrod and
+ Amras, who both hunted with the Green-elves for a time. Like the twins,
+ the bows are similar, for both protect their wielders from the elementsand
+ subtlety, while the other gives endurance and strength.
+
+The Light Crossbow of Brand
+ The bow of Brand, last King of Dale. It was given to him as a gift by the
+ King under the Mountain of Erebor, and has access to an especially secret
+ realm of Dwarven lore.
+
+The Seeker Arrow of Bard
+ Deadliest of arrows, imbued with elemental strength, this shaft is feared
+ especially by the wyrmkin.
+
+The Seeker Arrow of Gondor
+ An arrow that was created to rid the world of demons.
+
+The Seeker Bolt of Feanor
+ Made during the war against Morgoth by Feanor, this powerful bolt is the
+ bane of Morgoth's power, and has especial strength against those foes who
+ are already dead.
+
+The Silver Bolt 'Dailir'
+ The beloved dart of Beleg Cuthalion. It never failed to be found unharmed,
+ until it broke when Beleg fell upon it while he was carrying Turin
+ Turambar away from an Orc-camp, the night Beleg met his end. Turin remade
+ the bolt and kept it to his dying day in memory of his friend.
+
+The Metal Boomerang of Beor
+ Beor's boomerang makes its wielder as agile as the winds, and as hard to
+ harm.
+
+The Metal Boomerang 'Glimdrir'
+ A powerful boomerang that makes one agile and fast, with a thirst for evil
+ and undead creatures, but demands its wielder not teleport, for fear of
+ desertion.
+
+The Long Bow of Legolas
+ The great bow of Legolas, one of the Nine Walkers of old. Handcrafted specially
+ for Thranduil's son in Lothlorien, this bow gives clarity of sight and agility
+ to the wielder.
diff --git a/lib/mods/theme/file/book-24.txt b/lib/mods/theme/file/book-24.txt
new file mode 100644
index 00000000..86d998b7
--- /dev/null
+++ b/lib/mods/theme/file/book-24.txt
@@ -0,0 +1,59 @@
+ -----------------------
+ | Artifact Lore Vol. VI |
+ | Instruments |
+ -----------------------
+
+The Harp of Thorin
+ This magical instrument once belonged to Thorin Oakenshield, a mighty
+ dwarf warrior of old. The sounds emanating from it once gave a frightened
+ hobbit a glimpse of beauty and helped allay his fears, and to this day the
+ harp preserves its magical powers to encourage when all seems horribly
+ wrong.
+
+The Harp of Maglor
+ This harp that once belonged to Maglor makes those who use it seem more
+ forceful and convincing. It is also said that those who have used it
+ found themselves walking faster, as if to an unheard beat.
+
+The Drum of the Sky
+ The drum is decorated with the images of the stars, the clouds, the Sun
+ guided by Arien and the Moon with Tilion. It imparts to the wearer an
+ echo of the beauty of the sky, and protects him from the elements day or
+ night. The beat of the drum marks the passage of time, and will make time
+ pass differently for the wearer.
+
+The Harp of Daeron
+ A pretty harp that makes those who play it beautiful, wise and fast.
+
+The Drum of the Druedain
+ The fabled Drum of the Druedain that will protect those who play it from
+ darkness and poison attacks. It also aids in the seeing of warm blooded
+ creatures.
+
+The Horn of Rohan
+ A horn carved from the bones of the Dragon of Ered-Mithrin, this heirloom
+ of the House of Eorl bestows to its user the gifts of courage and command.
+
+The Horn of Helm
+ Heedless of cold, fearless of darkness -- besiegers fled at the wind of
+ the solitary coming of King Helm Hammerhand, proclaimed by a single
+ horn-blast in the dead of winter.
+
+The Horn of Boromir
+ The great horn made of the horns of kine of Araw. It is inlaid with silver
+ and gold signs; when blown, it can be heard for miles over. The horn gives
+ courage and endurance to its wearer, provided that secrecy is not desired.
+ "Loud and clear it sounds in the valleys of the hills... and then let all
+ the foes of Gondor flee!"
+
+The Harp of Tom Bombadil
+ This small, serviceable wooden harp once belonged to Tom Bombadil - a
+ mysterious figure whose song prevented the Wight-King from attacking Frodo
+ and his companions. Its music still inspires boldness and strengthens the
+ life force of all who play it.
+
+The Horn 'Valaroma'
+ This heavenly instrument, wrought from gleaming silver, most often appears
+ in the hands of the Valarin huntsman Orome; yet he may lend mortal
+ champions the horn from time to time. Its music inspires courage and
+ clarity of mind in pure-hearted beings, but drives evil ones far away. \ No newline at end of file
diff --git a/lib/mods/theme/file/book-25.txt b/lib/mods/theme/file/book-25.txt
new file mode 100644
index 00000000..a8cfdadf
--- /dev/null
+++ b/lib/mods/theme/file/book-25.txt
@@ -0,0 +1,98 @@
+ ------------------------
+ | Artifact Lore Vol. VII |
+ | Body Armour |
+ ------------------------
+
+The Leather Scale Mail 'Thalkettoth'
+ A tunic and skirt sewn with thick, overlapping scales of hardened leather
+ whose wearer moves with agility and assurance.
+
+The Robe of Incanus
+ Gandalf's long, flowing robe. It provides insight and allows the wearer
+ to see things not seen by all.
+
+The Robe of Great Luck
+ Once created by a powerful wizard this robe to grant him incredible
+ luck... It seems he forgot to wear it.
+
+The Hard Leather Armour of Himring
+ Contained within this studded cuirass of pliable leather is the memory of
+ unvanquished Himring, defiant fortress surrounded by the legions of
+ Morgoth.
+
+The Soft Leather Armour 'Hithlomir'
+ Familiar with the secret ways hidden in darkness, this leather cuirass is
+ truly more than it appears.
+
+The Robe of Belegaer
+ This pearl-trimmed blue robe was created by a Maia loremaster in Ulmo's
+ service. No ocean storm can harm its wearer or anything he carries; the
+ pressure and darkness of deep water cannot hinder him, either.
+
+The Leather Jerkin of Tom Bombadil
+ This garment was once the property of Tom Bombadil - a strange being
+ rumoured to be older than Arda itself. It may be the explanation for how
+ Tom could always turn up when he was most needed.
+
+The Filthy Rag of Ghan-buri-Ghan
+ The wrappings of a leader among the wild Men of Druadan forest. It
+ contains a multitude of tiny pockets filled with small darts dripping with
+ venom.
+
+The Robe of Curunir
+ The white robe of the Istari wizard Curunir, known on Middle-earth as
+ Saruman the White and Saruman of Many Colours. Imbued with cold and
+ lightning used in the creation of the Fire of Orthanc, it grants the
+ wearer some mastery over these elements.
+
+The Galvorn Plate Mail of Eol
+ A suit of imperishable galvorn, with conquerable strength to endure evil
+ and disruptive magics, that protects the life force of its wearer like
+ nothing else can. Eol the Dark Elf made it in secret for his son, but
+ Maeglin left Nan Elmoth with his mother Aredhel and never got to wear it.
+
+The Full Plate Armour of Isildur
+ A gleaming steel suit covering the wearer from neck to foot, with runes of
+ warding and stability deeply engraved into its surface.
+
+The Metal Brigandine Armour of the Rohirrim
+ A stiff suit of armour composed of small metal plates sewn to an inner
+ layer of heavy canvas, and covered with a second layer of cloth. Within it
+ is the spirit of Eorl the Young, matchless in combat.
+
+The Mithril Chain Mail 'Belegennon'
+ This wondrous suit of fine-linked chain shimmers as though of pure silver.
+ It stands untouched amidst the fury of the elements, and a power of
+ concealment rests within.
+
+The Mithril Plate Mail of Celeborn
+ A shimmering suit of true-silver, forged long ago by dwarven smiths of
+ legend. It gleams with purest white as you gaze upon it, and mighty are
+ it powers to protect and banish.
+
+The Chain Mail of Arvedui
+ A hauberk, leggings, and sleeves of interlocking steel rings, well padded
+ with leather. You feel strong and tall as Arvedui, last king of Arnor, as
+ you put it on.
+
+The Augmented Chain Mail of Caspanion
+ A hauberk, leggings, and sleeves of interlocking steel rings,
+ strategically reinforced at vital locations with a second layer of chain.
+ Magics to enhance body and mind lie within, and no door can hope to resist
+ the wearer.
+
+The Chain Mail of Peregrin Took
+ This sturdy mail shirt was a gift from the nobility of Gondor to the
+ halfling Peregrin Took. It enables a warrior to fight more capably and
+ cling to life when others would be killed. It also reveals enemies
+ (especially trolls) hiding in the dark, and terrifies anyone who threatens
+ the wearer.
+
+The Multi-Hued Dragon Scale Mail 'Lothronfaun'
+ A massive suit of heavy dragon scales deeply saturated with many colours.
+ It throbs with angry energies. May-cloud it is called, after the element
+ lightning which courses with it with unusual vigour.
+
+The Power Dragon Scale Mail 'Loknare'
+ A mighty suit of dragon armour, set with the scales of dragons of both Law
+ and Chaos, and with power over both. Loknare means Dragonblaze. \ No newline at end of file
diff --git a/lib/mods/theme/file/book-26.txt b/lib/mods/theme/file/book-26.txt
new file mode 100644
index 00000000..a042b8b5
--- /dev/null
+++ b/lib/mods/theme/file/book-26.txt
@@ -0,0 +1,56 @@
+ -------------------------
+ | Artifact Lore Vol. VIII |
+ | Cloaks |
+ -------------------------
+
+The Cloak 'Holcolleth'
+ This elven-grey mantle possesses great powers of tranquility and of
+ concealment, and grants the wearer the knowledge and understanding of the
+ Sindar.
+
+The Cloak of Thingol
+ A sable-hued cloak, with glowing elven-runes to restore magic showing calm
+ and clear as moonlight on still water.
+
+The Cloak of Thorongil
+ A cloak of shimmering green and brown that grants sight beyond sight and
+ shakes off holding magics, worn by Aragorn son of Arathorn in his youth as
+ he adventured under the name of Thorongil.
+
+The Cloak 'Colannon'
+ A crystal-blue cape of fine silk worn by a silent messenger of the forces
+ of Law. Somehow, its wearer is always able to escape trouble.
+
+The Shadow Cloak of Luthien
+ The opaque midnight folds, inset with a multitude of tiny diamonds, of
+ this cloak swirl around you and you feel a hint, a fragment of the
+ knowledge and power to restore that lay in Luthien, the most beautiful
+ being that ever knew death.
+
+The Shadow Cloak of Tuor
+ From the ruin of Gondolin did Tuor escape, through secret ways and
+ travail, shielded by his cloak from a multitude of hostile eyes.
+
+The Elven Cloak of Peregrin Took
+ This simple-looking cloak, dyed in hues that blend into the woodlands, was
+ a gift from the elves of Lothlorien to the halfling Peregrin Took. Its
+ wearer has an uncanny knack for making friends, escaping bonds, moving
+ among enemies completely unseen - and finding food.
+
+The Cloak 'Menelcol'
+ This deep-blue velvet cloak, embroidered with silvery stars, sheds
+ acelestial light that reveals hidden things and bestows unearthly beauty.
+ It also wards off damage from elements of the skies, and allows the wearer
+ to fly unscathed even through airless space.
+
+The Cloak of Ghan-buri-Ghan
+ This dark-coloured cloak once belonged to the leader of the Druedain. As
+ you put it on, you feel safer from attempts to waylay you on your travels.
+
+The Cloak of Valinor
+ A magical cloak that grants the wearer ultimate protection.
+
+The Elven Cloak of Mellyrn
+ Bearing the same lyrical name as the great trees of Lothlorien and containing
+ in its close-woven folds the speed and skill of the Galadhrim, this grey cloak
+ is ideal for those who travel in forests.
diff --git a/lib/mods/theme/file/book-27.txt b/lib/mods/theme/file/book-27.txt
new file mode 100644
index 00000000..3e958d90
--- /dev/null
+++ b/lib/mods/theme/file/book-27.txt
@@ -0,0 +1,75 @@
+ -----------------------
+ | Artifact Lore Vol. IX |
+ | Shields and Boots |
+ -----------------------
+
+The Small Mithril Shield of Thorin
+ Invoking the strength and endurance of Thorin, King under the Mountain,
+ this little metal shield is proof against the Element of Earth.
+
+The Large Leather Shield of Celegorm
+ This shield emblazoned with a multitude of creatures not seen for ages
+ once protected Celegorm, lord of Himlad; around it lies a mystic balance
+ that contains the conflicts of the elements.
+
+The Large Metal Shield of Anarion
+ The great metal-bound shield of Anarion, son of Elendil, who Sauron found
+ himself powerless to wither or diminish.
+
+The Small Metal Shield of Gimli
+ A gift from the King of Rohan to Gimli the Dwarf, this shield combines the
+ cunning and stamina of Gimli Elf-friend, Gimli the Lock-bearer.
+
+The Shield of Deflection of Gil-galad
+ The legendary shield of Gil-Galad, who fought his way to the gates of the
+ Dark Tower, and with whom came light even to Gorgoroth.
+
+The Large Leather Shield of the Haradrim
+ A great shield from the far lands of the South, whose wielder will go
+ charging into battle heedless of danger, with the strength and endurance
+ of a madman. Nor will he fear poison, for the Southron barbarians handle
+ poisoned darts naturally.
+
+The Mithril Shield of Earendil
+ A shining shield, once borne by the great mariner Earendil, "scored with
+ runes to keep all wounds and harm from him".
+
+The Large Metal Shield of Erkenbrand
+ Tall and strong stood Erkenbrand, Lord of the Westfold, as he rode to combat
+ the forces of Isengard. The valour of Helm Hammerhand lived again in him.
+ This shield is painted red according to Rohan custom and it grants magical
+ protection against enemy projectiles, as well as lets the wearer sense
+ approaching enemy hordes.
+
+The Pair of Soft Leather Boots of Wormtongue
+ The pair of boots used by Grima son of Galmod, also named the Wormtongue - a
+ treacherous but persuasive counsellor, ever ready to betray, sneak, lie,
+ cheat and steal - but never ready to actually fight.
+
+The Pair of Hard Leather Boots of Feanor
+ This wondrous pair of leather boots once sped Feanor, creator of the
+ Silmarils and the mightiest of the Eldar, along the Grinding Ice and to
+ Middle-earth at last.
+
+The Pair of Soft Leather Boots 'Dal-i-thalion'
+ A pair of high-laced shoes, strong against the powers of corruption and
+ withering, that grant the wearer extraordinary agility.
+
+The Pair of Metal Shod Boots of Thror
+ Sturdy footwear of leather and steel as enduring as the long-suffering
+ Dwarven King-in-exile who wore them. Of dwarven make, the wearer of these
+ boots will be completely at home in the mountains.
+
+The Pair of Hard Leather Boots of Nevrast
+ Footgear made of bear leather and set with opals, which grant the wearer
+ silent, hasted movement.
+
+The Pair of Metal Shod Boots of Gimli
+ A set of iron-shod boots stamped by Gimli's combat prowess, a peerless
+ ally to those journeying through halls of stone under mountains.
+
+The Pair of Metal Shod Boots of the Machine
+ A massive pair of adamantite boots studded with gold, the final and greatest
+ product of the petty-dwarven magical forge. Despite the great powers they
+ contain, they are heavy and awkward enough to make quite a racket whenever
+ you move.
diff --git a/lib/mods/theme/file/book-28.txt b/lib/mods/theme/file/book-28.txt
new file mode 100644
index 00000000..b55cf360
--- /dev/null
+++ b/lib/mods/theme/file/book-28.txt
@@ -0,0 +1,102 @@
+ ----------------------
+ | Artifact Lore Vol. X |
+ | Headgear and Gloves |
+ ----------------------
+
+The Hard Leather Cap of Thranduil
+ The hunting cap of King Thranduil, to whose ears come all the secrets of
+ his forest domain.
+
+The Metal Cap of Thengel
+ A ridged helmet made of steel, and embossed with scenes of valour in
+ fine-engraved silver. It grants the wearer nobility, clearness of thought
+ and understanding.
+
+The Steel Helm of Hammerhand
+ A great helm as steady as the heroes of the Westdike. Mighty were the
+ blows of Helm, the Hammerhand!
+
+The Dragon Helm of Dor-Lomin
+ The legendary dragon helm of Turin Turambar, an object of dread to the
+ servants of Morgoth.
+
+The Iron Helm 'Holhenneth'
+ A famous helm of forged iron granting extraordinary powers of mind and
+ awareness.
+
+The Iron Helm of Gorlim
+ A headpiece, gaudy and barbaric, that betrayed a warrior when he most
+ needed succour.
+
+The Metal Cap of Thorin
+ Mighty was Thorin Oakenshield as he emerged from the Gate of the Lonely
+ Mountain on the day of the Battle of the Five Armies, clad in shining
+ armour, part of which was this helm. He gleamed like gold in the dying
+ fire of the day, red light leapt from his eyes, and his foes were
+ terrified at the mere sight of him.
+
+The Iron Helm of Knowledge
+ This helm, designed by Petty-Dwarves ages ago to act as the brain of a
+ long lost project, is made of finest glass. Its light banishes all
+ secrets, and makes audible whispers from the deceased.
+
+The Metal Cap of Celebrimbor
+ This once belonged to Celebrimbor, maker of the Rings of Power. One who
+ knows both fire and acid, from the business of forging and engraving, will
+ fear neitheraware of Sauron before Sauron became aware of him, when Sauron
+ put on the One Ring for the first time.
+
+The Steel Helm of Gil-galad
+ The shining helm that Gil-galad, legendary Elven-king, wore in battle.
+
+The Iron Crown of Beruthiel
+ The midnight-hued steel circlet of the sorceress-queen Beruthiel, which
+ grants extraordinary powers of sight and awareness at a terrible physical
+ cost.
+
+The Golden Crown of Gondor
+ The shining winged circlet brought by Elendil from dying Numenor, emblem
+ of Gondor though an age of the world.
+
+The Jewel-Encrusted Crown of Numenor
+ A crown of massive gold, set with wondrous jewels of thought and warding,
+ worn by the kings of ancient Numenor. Its wearer may go into battle
+ always knowing what he faces - unless his own folly blinds him to the
+ nature and magnitude of the task.
+
+The Set of Leather Gloves 'Cambeleg'
+ A hero's handgear that lends great prowess in battle.
+
+The Set of Leather Gloves 'Cammithrim'
+ These gloves glow so brightly as to light the way for their owner and cast
+ magical bolts with great frequency.
+
+The Set of Gauntlets 'Paurhach'
+ A fiery set of gauntlets that can even shoot fire from the user's hands.
+
+The Set of Gauntlets 'Paurnimmen'
+ A set of handgear so icy as to be able to fire frost bolts.
+
+The Set of Gauntlets 'Pauraegen'
+ A set of handgear with sparks surrounding it, able to fire bolts of
+ electricity.
+
+The Set of Gauntlets 'Paurnen'
+ A set of handgear so corrosive that it may fire bolts of acid.
+
+The Set of Gauntlets 'Camlost'
+ A pair of gauntlets that sap combat ability, named after the empty hand of
+ Beren that once clasped a Silmaril.
+
+The Set of Cesti of Fingolfin
+ The hand-sheathing of Fingolfin, warrior-king of Elves and Men, who gave
+ Morgoth seven mighty wounds and pain that will last forever.
+
+The Set of Gauntlets of Eol
+ The iron-shod gauntlets of the Dark Elven smith Eol, tingling with magics
+ that he could channel in battle.
+
+The Set of Cesti 'Skycleaver'
+ The handgear of a legendary dragonslaying hero. The wearer of these wyrmskin
+ gauntlets will be versed in all aerial ways, and will fear no dragon that walks
+ or flies. \ No newline at end of file
diff --git a/lib/mods/theme/file/book-29.txt b/lib/mods/theme/file/book-29.txt
new file mode 100644
index 00000000..750c68cf
--- /dev/null
+++ b/lib/mods/theme/file/book-29.txt
@@ -0,0 +1,75 @@
+ -----------------------
+ | Artifact Lore Vol. XI |
+ | Rumoured Item Sets |
+ -----------------------
+
+Rumour has it that if an item set is complete, the
+wearer shall gain additional magical powers.
+
+Gothmog's Armoury
+ The Demonblade of Gothmog
+ The Demonshield of Gothmog
+ The Demonhorn of Gothmog
+
+The Elven Gifts
+ Phial of Galadriel
+ Sting
+
+The Dragon Slayer
+ The Long Bow of bard
+ The Black Arrow of Bard
+
+The Trinity
+ The Dagger of Samwise
+ The Dagger of Meriadoc
+ The Dagger of Peregrin
+
+Thorin's Gear
+ The Small Metal Shield of Thorin
+ The Harp of Thorin
+ The Metal Cap of Thorin
+
+Peregrin's Gifts
+ The Chain Mail of Peregrin Took
+ The Elven Cloak of Peregrin Took
+
+Ghan-buri-Ghan's Garb
+ The Filthy Rag of Ghan-Buri-Ghan
+ The Cloak of Ghan-buri-Ghan
+
+The Glory of the King
+ The Long Sword 'Anduril'
+ The Black Banner of Gondor
+ The Golden Crown of Gondor
+
+Saruman's Travel Gear
+ The Mage Staff of Saruman
+ The Robe of Curunir
+ The Palantir of Orthanc
+
+Elendil's Heirlooms
+ The Ring of Barahir
+ The Star of Elendil
+ The Rod of Annuminas
+
+Flame of Wrath
+ The Amulet of Carlammas
+ The Morning Star 'Naurgil'
+
+Shadow Ward
+ The Soft Leather Armour 'Hithlomir'
+ The Set of Leather Gloves 'Cammithrim'
+
+Eorl's Arms
+ Lance of Eorlingas
+ The Metal Brigandine Armour of the Rohirrim
+
+Gil-Galad's Battle Gear
+ The Shield of Deflection of Gil-Galad
+ The Spear 'Aiglos'
+ The Steel Helm of Gil-Galad
+
+Dwarven Heritage
+ Arkenstone of Thrain
+ Mattock of Nain
+ Lochaber Axe of the Dwarves \ No newline at end of file
diff --git a/lib/mods/theme/file/book-30.txt b/lib/mods/theme/file/book-30.txt
new file mode 100644
index 00000000..bfd20631
--- /dev/null
+++ b/lib/mods/theme/file/book-30.txt
@@ -0,0 +1,58 @@
+ ------------------------
+ | Artifact Lore Vol. XII |
+ | Light sources |
+ ------------------------
+
+The Phial of Galadriel
+ A small crystal phial, with the light of Earendil's Star contained inside.
+ Its light is imperishable, and near it darkness cannot endure.
+
+The Star of Elendil
+ The shining Star of the West, a famed heirloom of Elendil's house.A white
+ diamond set as a star in a silver fillet to be bound at the forehead.
+
+The Arkenstone of Thrain
+ A great globe seemingly filled with moonlight, the famed Heart of the
+ Mountain, which splinters the light that falls upon it into a thousand
+ glowing shards.
+
+The Anchor of Space-Time
+ A powerful stone that provides a strong light for any who wields it. It is
+ rumoured that it may even protect the wearer from the passing of the time.
+
+The Key of Orthanc
+ The key to the tower of Saruman, which fills your mind with images of
+ knowledge and dreadful understanding. It is not a regular key - it is a
+ perfectly round stone that is meant to fit into a hole. It can be used to
+ light your way in the dungeon as well.
+
+The Feanorian Lamp of Taniquetil
+ This holy lamp once belonged to a seeress who warned Ar-Pharazon ofthe
+ dire fate Numenor would suffer for daring to break the ban against
+ mortals' entering the Blessed Realms alive. The king had the seeress
+ executed and discarded her possessions--but rumors persist that a source
+ of pure vision, untainted by Sauron's darkness, lies hidden away somewhere
+ on Arda.
+
+The Palantir of Orthanc
+ A shining white ball of unbreakable crystal, the ancient Palantiri were
+ used by kings of Numenor and later by the Exiles for rapid communication
+ between distant lands. Nothing is hidden from one who gazes into a
+ Palantirobserver, as was Sauron when Saruman tried to spy on him with this
+ particular Palantir.
+
+The Palantir of Minas Ithil
+ A shining white ball of unbreakable crystal, the ancient Palantiri were
+ used by kings of Numenor and later by the Exiles for rapid communication
+ between distant lands. This Palantir, however, was taken by Sauron long
+ ago, and mastered to his evil uses, to the destruction of all others who
+ would gaze into it.
+
+The Black Banner of Gondor
+ A large banner of pure black, strangely gleaming with a dark light that is
+ faint and at the same time so bright it attracts attention.
+
+The Pearl 'Nimphelos'
+ It was a gift from the Falas-Elves to the Naugrim who built Menegroth, the
+ abode of Thingol and Melian. It shines like starlight on the waves of the
+ sea.
diff --git a/lib/mods/theme/file/book-31.txt b/lib/mods/theme/file/book-31.txt
new file mode 100644
index 00000000..15f677e9
--- /dev/null
+++ b/lib/mods/theme/file/book-31.txt
@@ -0,0 +1,63 @@
+ -------------------------
+ | Artifact Lore Vol. XIII |
+ | Amulets and Rings |
+ -------------------------
+
+The Amulet of Carlammas
+ A fiery circle of bronze, with mighty spells to ward off evil.
+ It is one of two items infused with holy fire.
+
+The Amulet of Ingwe
+ The ancient heirloom of Ingwe, high lord of the Vanyar, against whom
+ nothing of evil could stand.
+
+The Necklace 'Nauglamir'
+ A carencet of gold, set with a multitude of shining gems of Valinor.
+ Despite its size, its weight seems as that of gossamer.
+
+The Blue Stone 'Coimir'
+ Called 'Life-jewel' by the Vanyar of old, this flawless sapphire pendant
+ bears potent runes that preserve body and soul.
+
+The Elfstone 'Elessar'
+ This green gem glows with inner light. Aragorn son of Arathorn wore it at
+ the Battle of the Pelennor Fields, and he was himself given the name of
+ 'Elessar' by the people of Gondor because of this.
+
+The Jewel 'Evenstar'
+ A pure white jewel, the last gift of Queen Arwen Undomiel to Frodo
+ Baggins, intended to be worn around his neck on the chain that had once
+ borne the One Ring.
+
+The Necklace of Girion
+ A necklace of emeralds, green as the grass. It once belonged to Girion,
+ King of Dale, and was given to the Dwarves of the Lonely Mountain as
+ payment for a mithril mail shirt for Girion's son. It seems to have
+ overgrown with a strange moss over the years.
+
+The Amulet of Faramir
+ A slim neckpiece of True-silver, with quiet spells of Ithilien to aid and
+ protect the wearer.
+
+The Ring of Barahir
+ A ring shaped into twinned serpents with eyes of emerald meeting beneath a
+ crown of flowers, an ancient treasure of Isildur's house.
+
+The Ring of Power 'Narya'
+ The Ring of Fire, set with a ruby that glows like flame. Narya is one of
+ the three Rings of Power created by the Elves and hidden by them from
+ Sauron.
+
+The Ring of Power 'Nenya'
+ The Ring of Adamant, with a pure white stone as centrepiece. Nenya is one
+ of the three Rings of Power created by the Elves and hidden by them from
+ Sauron.
+
+The Ring of Power 'Vilya'
+ The Ring of Sapphire, with clear blue gems that shine like stars,
+ glittering untouchable despite all that Sauron ever wrought. Vilya is one
+ of the three Rings of Power created by the Elves and hidden by them from
+ Sauron.
+
+Rumour speaks of other rings of Power, too, as well as of a single ring
+whose name is foul and history treacherous. \ No newline at end of file
diff --git a/lib/mods/theme/file/book-32.txt b/lib/mods/theme/file/book-32.txt
new file mode 100644
index 00000000..d06e2ce2
--- /dev/null
+++ b/lib/mods/theme/file/book-32.txt
@@ -0,0 +1,37 @@
+ ------------------------
+ | Artifact Lore Vol. XIV |
+ | Tools and Trapkits |
+ ------------------------
+
+The Sceptre of Numenor
+ The chief mark of royalty in Westernesse, it is said to have perishedin
+ the fall of Numenor. It once belonged to Ar-Pharazon the Golden and the
+ evilness of that fallen King still courses through it.
+
+The Rod of Annuminas
+ The chief mark of royalty in Arnor, possibly the oldest remaining work of
+ Men. It came from Numenor, but it belonged to the Lords of Andunie of whom
+ the first was Valandil son of Silmarien. It was passed down to Elendil and
+ thus survived the downfall of Numenor.
+
+The Dwarven Pick of Erebor
+ A pick that provides a magical light to see by while tunnelling.
+
+The Mattock of Nain
+ Wielded by Nain of the Iron Hills at the Battle of Azanulbizar, this great
+ mattock brought victory to the Dwarves over Azog's Orcs - though Nain
+ himself fell at the last, even with victory already assured.
+
+The Bolt Trap Set of the Edain
+ A trap that can almost never be detected. Its missiles may be mere
+ pebbles, but fired at an incredibly high velocity to penetrate even the
+ toughest hide or armour.
+
+The Device Trap Set of the Noegyth Nibin
+ A magical trap, armed with a wand. Unaccountably, its victims keep on
+ coming back for more.
+
+The Arrow Trap Set of the Naugrim
+ A snare set not for animals, or people, but for demons alone, and
+ enchanted so that whenever the demon sets foot or claw into the (hidden)
+ pentagram, its hide is immediately pierced by many magical crossbow bolts. \ No newline at end of file
diff --git a/lib/mods/theme/file/book-33.txt b/lib/mods/theme/file/book-33.txt
new file mode 100644
index 00000000..4846c707
--- /dev/null
+++ b/lib/mods/theme/file/book-33.txt
@@ -0,0 +1,21 @@
+ ---------------------------------------------------------------
+| ^ |
+| ^^^ |
+| ------------------------> ^^^^^ |
+| ^^^^^^^ |
+| ^^^^^^^^^ |
+| ^^^^^^^^^^^ |
+| ^^^^^^^^^^^^^ |
+| ^^^^^^^^^^^^^^^ |
+| ^^^^^^^^^^^^^^^^ |
+| ~~ |
+| ~~ |
+| ~~ |
+| ~~ |
+| ~~ |
+| ~~ |
+| ~~ |
+| ~~ |
+| |> \ |- \/ ~~ |
+| | /\ | \ ~~ |
+ --------------------------------------------------------------- \ No newline at end of file
diff --git a/lib/mods/theme/file/book-4.txt b/lib/mods/theme/file/book-4.txt
new file mode 100644
index 00000000..29501076
--- /dev/null
+++ b/lib/mods/theme/file/book-4.txt
@@ -0,0 +1,11 @@
+Ash nazg durbatuluk,
+ash nazg gimbatul,
+ash nazg thrakatuluk
+agh burzum-ishi krimpatul.
+
+-------------------------------
+
+One Ring to rule them all,
+One Ring to find them,
+One Ring to bring them all,
+And in the darkness bind them.
diff --git a/lib/mods/theme/file/book-6.txt b/lib/mods/theme/file/book-6.txt
new file mode 100644
index 00000000..83740e08
--- /dev/null
+++ b/lib/mods/theme/file/book-6.txt
@@ -0,0 +1,171 @@
+ ----------------------
+ | Artifact Lore Vol. I |
+ | Edged Weapons |
+ ----------------------
+
+The Main Gauche of Azaghal
+ The weapon of Azaghal when he wounded Glaurung. It is deadly when
+ fighting dragons and is said to make the breaths of fire completely
+ harmless.
+
+The Main Gauche of Maedhros
+ A short thrusting blade with a large guard worn by Maedhros the Tall,
+ eldest son of Feanor, and wielded with his left hand after the loss of his
+ right hand in the pits of Thangorodrim.
+
+The Broken Dagger 'Angrist'
+ The knife Beren Barahir`s son took from Curufin and with which he cut out
+ a Silmaril from the crown of Morgoth, The blade snapped and broke when he
+ tried to gain one more and the splint hit Morgoth at his chin. It was
+ made of Telchar the dwarf from Nogrod and it could cut through stone. Even
+ broken, it retains power.
+
+The Dagger of Samwise
+ A fiery dagger finely balanced for deadly throws.
+ It is one of the 3 legendary daggers.
+
+The Dagger of Peregrin
+ A frosty dagger finely balanced for deadly throws.
+ It is one of the 3 legendary daggers.
+
+The Dagger of Meriadoc
+ A dagger covered in sparks and finely balanced for deadly throws.
+ It is one of the 3 legendary daggers.
+
+The Dagger of Rilia
+ A large stiletto dagger that glistens with odourless poison, to which the
+ wearer seems oddly immune.
+
+The Dagger 'Belangil'
+ A frosty dagger surrounded in a nimbus of ice with a hilt of elk horn and
+ an edge to wound the wind.
+
+The Bastard Sword 'Calris'
+ This sword has runes of power incused on its ornate hilt, and a single
+ blood channel that gleams coldly blue as you grasp this mighty weapon of
+ peril.
+
+The Broad Sword 'Aranruth'
+ The beautiful sword of Thingol with a hilt of gold and silver inlay,
+ glistening icily enough to freeze the hearts of demons. You feel supple
+ and lightfooted as you hold it.
+
+The Broad Sword 'Glamdring'
+ This fiery, shining blade earned its sobriquet "Foe-Hammer" from dying
+ orcs who dared to come near hidden Gondolin. Inscribed upon the guard in
+ Cirth is the followinggd daedheloth, dam an Glamhoth." - "Turgon King of
+ Gondolin wields, has and holdsthe sword Glamdring, foe of Morgoth's realm,
+ hammer to the Din-horde."
+
+The Broad Sword 'Orcrist'
+ This coldly gleaming blade is called simply "Biter", by orcs who came to
+ know its power all too well.
+
+The Two-Handed Sword 'Anglachel'
+ A giant sword once wielded by mighty Turin, and a great dragonbane which
+ bathed in Glaurung's blood. Its blade once shone brightly, it can cleave
+ iron as though it is old wood. Beleg Cuthalion chose this sword from the
+ armoury of Thingol in Doriath. Turin son of Hurin slew his friend Beleg
+ with it by accident, and since then the blade is black and dull.
+
+The Two-Handed Sword 'Zarcuthra'
+ Dark and deadly runes stand stark against the naked steel of this awesome
+ weapon, and you feel a stunning power of slaying and rending as you slowly
+ approach.
+
+The Dark Sword 'Mormegil'
+ A foul, twisted sword with blackened spines and knobs, whose very name is
+ a curse upon the lips of Elves and Men.
+
+The Cutlass 'Gondricam'
+ Famed sea-defender of Lebennin. A short, slightly curved chopping blade
+ with a perfect edge shining cleanly in the sun, an object of hate to the
+ men of Umbar who met it in combat.
+
+The Executioner's Sword 'Crisdurian'
+ A giant's weapon, with a long blade tall and straight thrusting out from a
+ massive double-pronged hilt. On its blade are written doomspells against
+ both the living and undead.
+
+The Long Sword 'Ringil'
+ The weapon of Fingolfin, High King of the Noldor; it shines like a column
+ of ice lit by light unquenchable. Morgoth came but unwillingly to meet it
+ of old; his lame foot will remind him of its might should he meet it again.
+
+The Long Sword 'Anguirel'
+ Forged of black galvorn by the Dark-Elven smith Eol, this blade has the
+ living lightning trapped inside.
+
+The Long Sword 'Elvagil'
+ The "Singing Blade", whose wearer can slay Orcs and Trolls in the hidden
+ and secret places of the earth.
+
+The Rapier 'Forasgil'
+ A slender, tapered blade whose wielder strikes icy blows with deadly
+ accuracy.
+
+The Sabre 'Careth Asdriag'
+ An heirloom of the Lords of Rhun far to the east, and a name of dismay to
+ creatures natural and unnatural.
+
+The Short Sword 'Sting'
+ The perfect size for Bilbo, and stamped forever by the courage he found in
+ Mirkwood, this sturdy little blade grants the wearer combat prowess and
+ survival abilities they did not know they had. The blade is inscribed with
+ Tengwar writing "Sting is my name, I am the spiders' bane."
+
+The Scimitar 'Haradekket'
+ A damascened scimitar that seems wondrously easy to hold. Famed in song
+ as the "Sickle of Harad", and a deadly foe to the undead.
+
+The Short Sword 'Gilettar'
+ A stubby blade worn by Beren, whose horn sounded of old in the glades of
+ Brethil.
+
+The Blade of Chaos 'Daedheloth'
+ This weapon of wrath is named after the realm of Morgoth Bauglir. Cursed
+ with a violent anger, dives hungrily into the flesh of its enemies. It
+ gathers shadows of death into its owner as they inflict wounds that will
+ never heal.
+
+The Long Sword 'Sereghathol'
+ Blood-Sword it is called, after its thirst for the blood of foes.
+
+The Long Sword of Angmar
+ Dark flames wreath the naked steel of the Witch-King of Angmar. A mighty
+ curse to all those who wield it apart from its master, the torture of the
+ wraithworld awaits those who dare.
+
+The Broken Sword 'Narsil'
+ These are the shards of the mighty blade of Isildur, which deprived the
+ dark lord Sauron of The One Ring of Power. Legend has it that the sword
+ that was broken shall be reforged. You can barely make out a Tengwar
+ inscription on the pommel, reading "Narsil essenya, macil meletya;Telchar
+ carneron Navarotesse." - "Narsil is my name, a mighty sword;Telchar made
+ me in Nogrod."
+
+The Long Sword of Dernhelm
+ Eomer's sister Eowyn once wielded this shining sword when she battled
+ the Witch-King of Angmar, hiding her true identity to join the battle.
+ Others are less likely to notice the wielder immediately. Eowyn's sword
+ also allowed her to move swiftly, sense powerful enemies, inflict terrible
+ wounds, and partly withstand the worst attacks of the Nazgul.
+
+The Bluesteel Blade 'Ancanaur'
+ "The Jaws of Fire", this is the sword that Feanor forged in secret to do
+ battle against his enemies. The sword which threatened Fingolfin, the
+ sword which in the end did not prevent its owner's untimely death.
+
+The Broad Sword 'Guthwine'
+ The sword of Eomer, son of Eomund, leader of the Riders of the Mark. As
+ one flashed this sword with Anduril during a battle long ago. Legendary
+ are its powers in the rallying of desperate troops.
+
+The Long Sword 'Herugrim'
+ The ancient blade of Theoden, King of the Mark. It was taken from the king
+ by Grima the Wormtongue, and hidden from him in a dusty chest. It was once
+ instrumental in restoring the King's wits from evil bewitchment.
+
+The Bluesteel Blade of Ephel Duath
+ This filthy orc-blade is famed for vile deeds of torture and blood, and its
+ wielder will never cease to fear treachery.
diff --git a/lib/mods/theme/file/book-7.txt b/lib/mods/theme/file/book-7.txt
new file mode 100644
index 00000000..ea7d0df2
--- /dev/null
+++ b/lib/mods/theme/file/book-7.txt
@@ -0,0 +1,83 @@
+ -----------------------
+ | Artifact Lore Vol. II |
+ | Polearms |
+ -----------------------
+
+The Spear of Melkor
+ The mighty spear used once by Melkor to slay the trees of Valinor.
+
+The Beaked Axe of Hurin
+ Wielded by Hurin Thalion in the Fifth Battle of Beleriand, this troll-bane
+ smoked in the black blood of Gothmog's guards.
+
+The Beaked Axe of Dain Ironfoot
+ The narrow axe head of this weapon, finely balanced by a crow's beak,
+ would pierce even the armour of Smaug, and its wielder becomes aware of
+ the minds of their enemies.
+
+The Glaive of Pain
+ The massive chopper that crowns this glaive glows blood-red and black;
+ fell spells of annihilation swirl and dance as you swing death's myrmidon
+ down.
+
+The Halberd 'Osondir'
+ Lordly and tall did Osondir stand against the wrath of giants, and
+ clear-eyed in barrows fell, wielding a halberd glowing ruby red.
+
+The Pike 'Til-i-arc'
+ Within this long thrusting spear lie the spirits of frost giants and fire
+ demons, who war forever, trapped by magely spells.
+
+The Spear 'Aiglos'
+ The mighty spear of Gil-galad, famed as "Snow-point" in the songs of
+ Elves, against which all the foul corruptions of Sauron dashed in vain.The
+ spear is inscribed with Tengwar runes, reading "Gil-galad ech vae
+ vaegannen matha, / Aith heleg nin i orch gostatha; / Nin cniel na
+ nguruthos / Hon ess nn istathawell-made spear,/ The Orc will fear my point
+ of ice; / When he sees me, in fear of death / he will know my name.
+
+The Spear of Caradhras
+ A magical spear, rumoured to have been forged by Orome himself in the
+ coldest reach of the cruel Redhorn.
+
+The Spear 'Nimloth'
+ A thin spike of thrice-forged steel caps a straight sylvan shaft cut from
+ a legendary tree; spells to break the will of the undead and strike cold
+ fear into the hearts of foes lie on this perfectly balanced spear.
+
+The Lance of Eorlingas
+ "Forth Eorlingas!". To the field of Cormallen came Eorl the Young to save
+ beleaguered Gondor, and from his lance fled massive trolls and dire wolves.
+ It is one of two items that once belonged to Eorl the Young, valiant hero
+ of the Mark.
+
+The Battle Axe of Balli Stonehand
+ The twin blades of this weapon were forged in Belegost, and powerful
+ forces to resist and endure lie ready for he who shall wield it once more.
+
+The Battle Axe 'Lotharang'
+ A superbly crafted double-bladed axe that slays the creatures of earth and
+ allows rapid recovery from their blows.
+
+The Lochaber Axe of the Dwarves
+ A massive axe with twin razor-sharp heads, so large that it usually
+ requires two hands to wield, intricately engraved in gold with spells to
+ ward off the elements and smite evil.
+
+The Trident of Osse
+ The awesome weapon is imbued with some of the power of the Vala Ulmo, Lord of
+ Waters. It allows the wearer to laugh in scorn at the dread powers of the
+ undead, and be utterly in command of the element of water.
+
+The Scythe 'Avavir'
+ With elemental powers whose struggles turn this weapon red and purest
+ white, this shining reaper bears within it a power of going forth and
+ returning.
+
+The Lochaber Axe of Gothmog
+ The black axe of Gothmog, which struck Fingon at Nirnaeth. Mighty spells
+ of evil make it unsafe in any hands but of the original wielder.
+
+The Lochaber Axe 'Lhugdagnir'
+ Forged by the Dwarves to defend their home of Khazad-dum from dragons,
+ this axe has been lost to time... until now.
diff --git a/lib/mods/theme/file/book-8.txt b/lib/mods/theme/file/book-8.txt
new file mode 100644
index 00000000..bf99a12a
--- /dev/null
+++ b/lib/mods/theme/file/book-8.txt
@@ -0,0 +1,101 @@
+ ------------------------
+ | Artifact Lore Vol. III |
+ | Hafted Weapons |
+ ------------------------
+
+The Mighty Hammer 'Grond'
+ The mighty Hammer of the Underworld, blackened by doomspells of
+ shattering, whose wielder holds the lives of all Morgoth's servants in his
+ hand.
+
+The Flail 'Totila'
+ A flail whose head befuddles those who stare as you whirl it around, and
+ becomes a fiery comet as you bring it down.
+
+The Two-Handed Flail 'Thunderfist'
+ The long-lost weapon of Kzurin, Dwarven champion of ancient Belegost, with
+ runes of strength in its handle, and flames and sparks that roar and
+ crackle around its massive head.
+
+The Morning Star 'Maegnas-in-sereg'
+ You feel strong and firm of foot as you whip the chain-suspended spiked
+ orb around - and bathe it in the blood of your foes.
+
+The Morning Star 'Naurgil'
+ A famed battle-lord of old, with a ruddy head, coloured as embers are that
+ can yet rise up in wrath.
+
+The Mace 'Taratol'
+ A great ridged mace that calls around you a nimbus of living lightning;
+ you remain utterly untouched even as fat sparks arc around your fingers
+ and eyebrows.
+
+The War Hammer of Gamil Zirak
+ Gamil Zirak was a great craftsman, the master of Telchar of Nogrod. This
+ weapon was rescued from Thingol's treasury, and it is rumoured that its
+ wielder need not fear dragons or other fell beings of the Dark.
+
+The Quarterstaff 'Nar-i-vagil'
+ Named for a fiery star and set with gems of great worth binding mystic
+ virtues of protection and thought.
+
+The Quarterstaff 'Eriril'
+ The radiant golden staff of an Istari of legend, this wizard's companion
+ grants keen sight and the knowledge of many hidden things.
+
+The Quarterstaff of Olorin
+ A staff tall and sturdy, with rough-hewn runes that invoke the element of
+ Earth, and which strikes down all creatures who live in the shadow of
+ mountains.
+
+The Mace of Disruption 'Nguruthos'
+ A weapon so massive it seems beyond the strength of mortals, yet you feel
+ the might of giants within you as you heft it. As you grip the handle of
+ ebony and steel, coronas of fire blaze and mighty spells to preserve magic
+ activate around you. It is named 'Fear of Death' - you wield the Fear of
+ Dragons and the Despair of the Undead.
+
+The Lucerne Hammer 'Turmil'
+ Wielded by the High Priest of Meneltarma, this great mace gleams coldly as
+ though moonlit, and it can strike as mighty a blow spiritually as
+ physically.
+
+The Whip of Gothmog
+ With this unbearably bright whip of flame, the Balrog Gothmog has become
+ known for never having lost in combat.
+
+The Whip 'Lasher'
+ A powerful whip that is deadly against orcs. It poisons your foes and is
+ said to go "snicker snack".
+
+The Ball-and-Chain of Fundin Bluecloak
+ The weapon of one of the great dwarven priests, with powers to preserve
+ body, soul and enchantments, and the bane of those who seek life beyond
+ death.
+
+The Lead-Filled Mace 'Dolcrist'
+ This mighty bludgeon brings destruction to all around it, and is the bane
+ of dragons and magic. Skull-cleaver (or head-cleaver) it is called.
+
+The Quarterstaff of Radagast
+ Rumored to be a gift from Yavanna to Radagast the Brown, this
+ plain-seeming oak staff shields its bearer against the elements and helps
+ him fight off malicious beasts (such as the goblins' Warg-steeds). It
+ also grants exceptional insight into Nature magic, and can even cause
+ trees or healing herbs to spring forth at the bearer's command.
+
+The Mage Staff of Saruman
+ A white quarterstaff that faintly gleams a pale white, it once belonged to
+ one of the most powerful beings on Middle-Earth, Saruman the White.
+ Saruman fell into shadow, and the staff left him during his travels. As
+ you wield it, you become much more attuned to magic.
+
+The Quarterstaff of Thranduil
+ The carven oak staff of the King of the Woodland Realm, this weapon is a
+ fighter's best friend in a forest.
+
+The Mage Staff of Forochel
+ A shaft of pure, invincible crystal cut from the heart of one of the great
+ glaciers ringing the Ice-Bay of Forochel. While you hold it, your mind feels
+ as clear as the winter sky.
+
diff --git a/lib/mods/theme/file/book-9.txt b/lib/mods/theme/file/book-9.txt
new file mode 100644
index 00000000..878d4b74
--- /dev/null
+++ b/lib/mods/theme/file/book-9.txt
@@ -0,0 +1,99 @@
+ ------------------------
+ | Monstrous Compendium 1 |
+ | Humanoids |
+ ------------------------
+
+ *** Townsfolk (t) ***
+
+These are the monsters you will find in the various towns all across
+Middle-earth. Most of them are neutral to the player, though those who
+are not neutral are quite harmless, unless you take them on before you
+are strong enough. The townsfolk include [[[[[oAimless-looking merchants],
+[[[[[UPitiful-looking beggars], [[[[[ySinging, happy drunks], [[[[[uMangy-looking lepers],
+[[[[[GVillage idiots], [[[[[WBlubbering idiots], [[[[[RBoil-covered wretches], [[[[[gWoodsmen],
+[[[[[wSanctimonious-looking preachers], [[[[[vWeary-looking travellers],
+[[[[[DFilthy street urchins], [[[[[rMean-looking mercenaries],
+[[[[[bAgents of the black market], and [[[[[BBattle-scarred veterans].
+
+ *** Humans (p) ***
+
+These are the various humans inhabiting Middle-earth, from all trades
+and professions, of varying degrees of experience. The novices and
+apprentices are just what their titles imply: new to the craft and thus
+easier to deal with than more advanced masters. Depending on the
+player's race, some of these may be neutral or even coaligned. The
+trades include [[[[[brogues], [[[[[uwarriors], [[[[[rmages], [[[[[omystics], [[[[[Rsorcerers], [[[[[Wrangers],
+[[[[[Gdruids], [[[[[wpaladins], [[[[[ymindcrafters], and [[[[[gpriests].
+
+These also include various subraces of humans from different parts of
+Middle-earth, including the moderately dangerous [[[[[Ueasterlings], [[[[[rVariags],
+[[[[[UCorsairs of Umbar], [[[[[uHaradrim], [[[[[sWainriders], and [[[[[gDunlendings], the very
+dangerous [[[[[DBlack Numenoreans] and [[[[[DOathbreakers], as well as the friendly
+(yet deadly when roused) [[[[[BWavelords].
+
+
+ *** Elves and Halflings (h) ***
+
+The Halflings are a shy race, so there are not that many of them - only
+the [[[[[sScruffy-looking hobbits] and [[[[[UHalfling slingers]. Very stealthy and
+good shots, Halflings. They make excellent burglars.
+
+The [[[[[BMermaids] are an enigma, some argue that they are simply drowned
+Elven maidens, others say they're half-human, half-fish. Whatever they
+are, they are quite dangerous to the unwary adventurer. Another odd
+race are the [[[[[yMind flayers], whose mind powers are legendary and ability
+to deprive others of their sanity unmatched.
+
+The majority of Elven monsters an adventurer will encounter in the
+dungeons will be Dark Elves, all good at a particular profession, and
+much better at these professions than their human counterparts. There
+are simple [[[[[DDark elves] who live by their wits and a bit of magic, and
+then there are [[[[[vDark elven warlocks], [[[[[RDark elven sorcerers], [[[[[GDark elven]
+[[[[[Gdruids], [[[[[gDark elven priests], [[[[[uDark elven warriors], and [[[[[rDark elven]
+[[[[[rmages], all commanded by [[[[[DDark elven lords].
+
+Not all Elves you meet will be hostile and expert at the Dark arts,
+however, among them the [[[[[bAquatic elven warriors], [[[[[WElven archers],
+[[[[[wHigh-elven rangers], and [[[[[oAquatic elven mages].
+
+ *** Dwarves (k) ***
+
+A hardy and stout race, the Dwarves make formidable opponents to any
+adventurer who encounters them. They, too, practice a variety of trades,
+though their spectrum is not as wide-ranging as that of humans or elves.
+The [[[[[DDark dwarven lords] rule over the [[[[[gDark dwarven priests], [[[[[uDark dwarven]
+[[[[[uwarriors], and [[[[[wDark dwarven smiths].
+
+The Dwarves do not trust magic, but a subrace of them - the Petty-dwarves
+- do practice it, you will see both plain [[[[[sPetty-dwarves] and [[[[[RPetty-dwarf]
+[[[[[Rmages].
+
+Some adventurers who know the correct incantation will be able to summon
+[[[[[Udwarven warriors] to their aid.
+
+ *** Gnomes, leprawns, and their kin (l) ***
+
+The gnomes are a less-well-known race on Middle-earth; they are related
+to the Petty-dwarves, but they are not nearly as stout as Dwarves. The
+gnomes are quite cunning and smart, but not very strong. Their [[[[[sgnome lords]
+command the [[[[[ugnome warriors], [[[[[bgnome rogues], [[[[[rgnome priests], [[[[[Rgnome mages],
+[[[[[wgnome paladins], and [[[[[ognome mystics].
+
+A race closely related to gnomes are the leprawns - they are even smaller
+than gnomes, and much weaker. However, leprawns breed very quickly and an
+unwary adventurer might be overrun if he is not careful! The [[[[[vmalicious]
+[[[[[vleprawns] are a nuisance, the [[[[[Wwizard leprawns] are a dangerous nuisance,
+and one is not advised to underestimate the [[[[[Ddeath leprawns].
+
+There also exist [[[[[Gcheerful leprawns] and [[[[[Uadventurer gnomes], who have broken
+with the traditions of their races, and might agree to help other adventurers.
+
+A strange race from the depths are the [[[[[glizard men] with their [[[[[rlizard kings] -
+they are quite strong and command powerful magic. These creatures prefer to
+live in swamps and shallow water areas, however, so you will not encounter
+them in the dungeons often.
+
+
+
+
+
diff --git a/lib/mods/theme/file/bravado.txt b/lib/mods/theme/file/bravado.txt
new file mode 100644
index 00000000..13dec95a
--- /dev/null
+++ b/lib/mods/theme/file/bravado.txt
@@ -0,0 +1,105 @@
+103
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+cackles evilly.
+cackles diabolically.
+says: 'Surrender, miserable flea!'
+says: 'You shall not pass!'
+says: 'Let's see if you are worthy!'
+laughs devilishly.
+says: 'Flee while you can, gnat!'
+says: 'You are about to die, worm!'
+says: 'Read your prayers!'
+hisses: 'Die!'
+says: 'You don't have a chance!'
+says: 'Fear my wrath, fool!'
+says: 'Feel my fury!'
+stares at you darkly.
+gives you a contemptuous glance.
+says: 'Prepare to meet your destiny!'
+says: 'Perish, mortal!'
+says: 'Your puny efforts make me laugh!'
+says: 'Hell hath no fury like mine!'
+says: 'You should have fled while you had the chance.'
+screams: 'Die by my hand!'
+says: 'Your last wish?'
+says: 'Your death shall be a slow, painful one.'
+says: 'Your head shall be my next trophy.'
+screams: 'You are DOOMED!'
+grins sadistically.
+says: 'This dungeon shall be your TOMB!'
+laughs fiendishly.
+says: 'Your fate is sealed, worm.'
+says: 'Resistance is useless.'
+says: 'Hell shall soon claim your remains.'
+says: 'Thou shalt repent of thy cunning.'
+says: 'Aye, you will make fine eating, when you have hung a bit.'
+says: 'Surrender or die!'
+says: 'Savor thy breath, it be thine last.'
+says: 'Prepare do die!'
+says: 'You shall be bruised and battered to pieces when I'm through!'
+says: 'And ever so my foes shall fall!'
+says: 'Begone now ere my arrows fly!'
+says: 'Hammer and tongs! Knocker and gongs!'
+whispers nasty things.
+says: 'I shall flatten you!'
+says: 'I could spare you, but why?'
+says: 'I'll slaughter you slowly...'
+says: 'Nothing can save you now!'
+eyes your money pouch covetously.
+says: 'I bet I can shoot better than you...'
+says: 'I hope you enjoy pain!'
+says: 'Give me your best blow!'
+spouts torrents of obscenities.
+says: 'A time to die, fool!'
+bellows frighteningly!
+says: 'You will never leave this dungeon alive!'
+says: 'You'll leave this dungeon only in a wooden box!'
+attempts to read a Scroll of Curse Weapon at you!
+snickers: 'Now, I strike a blow for *our* side!'
+says: 'I love the smell of fresh blood.'
+says: 'I shall torture you slowly.'
+chuckles evilly.
+says: 'Victim is your name and you shall fall.'
+says: 'Stepping out? You'll feel our hell on your back!'
+says: 'Now I will waste my hate on you.'
+says: 'I will prepare something particularly uncomfortable for you.'
+says: 'I shall smite thee with extreme prejudice!'
+says: 'Verily, it is too late for thee.'
+says: 'You'll die as you lived, in a flash of the blade.'
+brags: 'My power is beyond compare!'
+says: 'I just want to see your blood, I just want to stand and stare.'
+says: 'I've been looking so long for you; you won't get away from my grasp.'
+says: 'A mere mortal dares challenge my might?'
+says: 'Too bad you are unlucky. But even that would not help you now.'
+sings: 'Swish, smack! Whip crack!'
+says: 'Think of it this way: you are fated to die here. DIE!'
+says: 'There is no escape and that's for sure.'
+says: 'This is the end; I won't take anymore.'
+says: 'Say goodbye to the world you live in.'
+says: 'Your weapon is no match for mine!'
+brags: 'I'm a friend of the Boss's, I am.'
+says: 'I can't help but laugh at your pathetic attempts.'
+lets out a truly awful cry of rage!
+says: 'My innocent victims are slaughtered with wrath and despise!'
+says: 'I have found you, and there is no place to run.'
+laughs at your wild swings.
+says: 'And damn'd be him that first cries: Hold, enough!'
+says: 'I can smell your blood!'
+says: 'Has your folly led to this?'
+wonders aloud how many experience points you're worth.
+says: 'Pride yourself on this, that you were slain by a champion.'
+thunders: 'May Eru have mercy on your soul, for I will have none.'
+screams for your blood!
+sighs: 'They send a poorer grade of adventurers down each year than the last.'
+says: 'Your life-blood will baptise my blade!'
+shouts: 'You are already dead!'
+snickers: 'You and what army could harm me?'
+says: 'You're almost not worth killing... almost!'
+leaps towards you with death in its eye.
+sings: 'Clash, crash! Crush, smash!'
+says: 'Another adventurer? I just got through picking my teeth with the last.'
+says: 'Your two ears will decorate my belt.'
+says: 'Consider yourself warned.'
+says: 'I don't want to hurt you, I only want to kill you.'
+says: 'I am fated never to die by the hand of a mortal. Just give up.'
+screams: 'I'm out to destroy and I will cut you down!'
diff --git a/lib/mods/theme/file/chainswd.txt b/lib/mods/theme/file/chainswd.txt
new file mode 100644
index 00000000..4755391c
--- /dev/null
+++ b/lib/mods/theme/file/chainswd.txt
@@ -0,0 +1,8 @@
+6
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+KILL, KILL, KILL!
+The Chainsword roars noisily!
+VROOM! VROOM!
+Kill, kill, kill, kill, kill, kill!
+Blood, blood, blood!
+Bloodbath!
diff --git a/lib/mods/theme/file/dam_huge.txt b/lib/mods/theme/file/dam_huge.txt
new file mode 100644
index 00000000..62f2ba60
--- /dev/null
+++ b/lib/mods/theme/file/dam_huge.txt
@@ -0,0 +1,9 @@
+7
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+You nearly decapitate %s!
+You impale %s on your weapon.
+Your weapon almost slices %s in half!
+%^s's head caves in!
+You broke %s's spine!
+Your weapon slices into %s's heart!
+You smashed %s's ribcage!
diff --git a/lib/mods/theme/file/dam_lots.txt b/lib/mods/theme/file/dam_lots.txt
new file mode 100644
index 00000000..1784d67c
--- /dev/null
+++ b/lib/mods/theme/file/dam_lots.txt
@@ -0,0 +1,21 @@
+18
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+You stab %s in the stomach.
+You cut off %s's hand.
+You chop down on %s's shins.
+You gave %s a deep gash.
+You gave %s a gigantic bruise.
+You cut off %s's arm!
+You cut off %s's leg!
+You stab %s in the heart.
+You slash at %s face.
+You throw %s down at the ground.
+You attempt to strangle %s.
+You grab %s's head and twist it.
+You knocked out several of %s's teeth!
+You broke some of %s's ribs!
+%^s spins around dizzily after your blow.
+%^s sputters at your tight, choking hold!
+%^s grunts under the force of your blows.
+%^s screams shrilly in fear.
+
diff --git a/lib/mods/theme/file/dam_med.txt b/lib/mods/theme/file/dam_med.txt
new file mode 100644
index 00000000..fc1db066
--- /dev/null
+++ b/lib/mods/theme/file/dam_med.txt
@@ -0,0 +1,25 @@
+23
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+You kick %s in the belly!
+You head-butt %s.
+You push %s over.
+You broke %s's finger!
+You broke %s's toe!
+You kick %s in the shins.
+You stab %s in the arm.
+You stab %s in the leg.
+You hit %s over the head.
+You knee %s in the groin!
+You aim a high kick at %s's head.
+You stab %s in the ribs.
+You chop at %s's neck.
+You put a tight choke-hold on %s.
+You attempt to topple %s over.
+You punch %s.
+You attempt to poke %s in the eye!
+You twist %s's leg.
+You twist %s's arm.
+You bend %s's fingers.
+You punch %s in the kidneys!
+You smash %s with your elbow.
+You smash %s with your knee.
diff --git a/lib/mods/theme/file/dam_none.txt b/lib/mods/theme/file/dam_none.txt
new file mode 100644
index 00000000..a6c20248
--- /dev/null
+++ b/lib/mods/theme/file/dam_none.txt
@@ -0,0 +1,24 @@
+22
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+You scratch %s.
+You give %s a nasty bruise.
+You stub %s's toe.
+You jab %s in the ribs.
+You almost poked your eye out while fighting %s!
+You made %s's nose bleed.
+You almost slipped while fighting %s.
+%^s doesn't even flinch!
+You accidentally hurt yourself while fighting %s.
+You slap %s.
+%^s slips and falls.
+%^s laughs at your wild swings.
+You pull at %s's hair.
+You punch %s in the nose.
+You pull at %s's ear.
+%^s growls at you.
+%^s is very, very annoyed!
+You scream an insult at %s.
+%^s makes a nasty face.
+You scowl at %s.
+%^s gnashes his teeth.
+%^s lets out a gurgling laugh.
diff --git a/lib/mods/theme/file/dam_xxx.txt b/lib/mods/theme/file/dam_xxx.txt
new file mode 100644
index 00000000..afceffe1
--- /dev/null
+++ b/lib/mods/theme/file/dam_xxx.txt
@@ -0,0 +1,11 @@
+9
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+%^s disintegrates into a fine mist!
+%^s splatters all over the floor.
+%^s explodes into tiny chunks.
+%^s's bones are crushed at the force of your blow!
+You almost squash %s into a pancake!
+Your weapons neatly slice %s into many little pieces.
+You cleave %s in half.
+%^s's head flies off in a wide trajectory.
+%^s is driven several feet into the ground under your blow!
diff --git a/lib/mods/theme/file/dead.txt b/lib/mods/theme/file/dead.txt
new file mode 100644
index 00000000..f32dae4d
--- /dev/null
+++ b/lib/mods/theme/file/dead.txt
@@ -0,0 +1,24 @@
+ #s_____#w #D,#w-#Wv#s___#w
+ #s_d&#y*#D'"#w #W/#w #D`#w|
+ #D,#W/#s?#D'#w | |#D'#w
+ #s?#D'#w|#D'#w | #D.,#W~#w-#D'""'#w |#D.#w
+ #D,#w| #sT#w --#y+#w-- #D,#W~#D'#w #D.,#W~#s:#w| #D`#W~\#w
+ | #sL#w | #D,#Wv#s_#D.#w #W/#D'#w #D,#W/#D"#w | #sT#D`#W\#D.`#W\#D.#w
+ |#D.#w |#W\#w | #D""'#w #s?#w--#Wv#D,#s?#w |#D'#w #s?#D,#w #W\#D.#w
+ #W\#w #D`#W\#D.#w #sT#w #D`#W~#w-#W\#s_]#w |
+ #D`#W\#D.#w #D"#W^~v#D.#w | #D"#W^#w-#W~v#w
+ #D`#W\#s_#w #sT#D.#w #D"#W^~v#w #D.#s__#D.#w #W/#w
+ #D``#w-#W~#w--| | |#D,#w #D"#s:#w| #D.#s___#D.#w #D.#w|
+ #D`#W\#w #s?#W\#w #W/#w #W/#w #D"#s:&#w #D,#w-#Wv#s_#W/#w
+ #D`#W\#D.#w #D`#W\#w| |#D'#w #D.,#W~#D'#w #D.#W/#D'#w
+ #D`#W~\#D.#w #D`#W^#D'"#w #D,#W~#D'#w
+ #D.#w| #s__#Wv#w-#W~#D''#w
+ #W/#w #W/#D'#w
+ #D,#w| #D.#w|
+ #W/#w #sJ#w
+ |#D'#w |
+---------------------------------------------#W/#w #W/#s:#w-------------------------
+ |#D'#w #D,#w|
+ |#D'#w #D'#w
+ #D`#w
+
diff --git a/lib/mods/theme/file/death.txt b/lib/mods/theme/file/death.txt
new file mode 100644
index 00000000..f033fa56
--- /dev/null
+++ b/lib/mods/theme/file/death.txt
@@ -0,0 +1,351 @@
+349
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+Tangado a chadad!
+AAAAAAAAARRRRRRRRRRRRRRGGGGGGGGGGGGGHHHHHHHHHHHHHHH!!!!!!!!!!!!
+AAAARRRGGGHHH!!!
+Somehow, I have a bad feeling about this...
+Strangely, all of a sudden I don't feel so good.
+You can see armored women on winged horses coming for you.
+Oh well, you can't always win.
+I'm too young to die!
+I'll be back!
+O, untimely death!
+Slave, thou hast slain me!
+Prepare to fire!
+Who knocked?
+Hello again, poor Yorick.
+Ouch.
+Et tu, Brute! Then fall, Caesar!
+O! I die, Horatio...
+I told you to be careful with that sword...
+This guy's a little crazy...
+Ok, ok, I get it.
+YASD
+Who turned off the light..?
+Join the army, see the world, they said...
+This one's for the YASD hall of fame.
+Rats!
+Shall this fellow live?
+Help, ho!
+What ho! Help!
+What hast thou done?
+I'll be revenged on the whole pack of you!
+You will *pay* for this!
+They say blood will have blood...
+Violence is no solution!
+Yes?
+#&%#&#%*#*&%!!!!!
+I must away, ere break of day...
+No time to make a testament?
+Ugh!
+Aargh!
+Aaagghhh!
+I'm melting!
+Oof..
+Oh!
+Did somebody knock?
+I hear the tramp of doom.
+To fly would be folly.
+The wind came down from mountains cold.
+Cut the bridges! To arms! To arms!
+Eeek!
+Aah!
+I hate it when that happens.
+One direct hit can ruin your whole day.
+Oh no!
+Not me!
+Ouch.
+Oh no, not again.
+Another one bites the dust.
+Goodbye.
+Help me!
+Farewell, cruel world.
+O! wandering folk, the summons heed!
+I go now to the halls of waiting.
+This is the End, my only friend.
+It's all over.
+This is a bitter adventure, if it must end so.
+Why does everything happen to me?
+I'm going down.
+I leave now all gold and silver, and go where it is of no worth.
+But sad or merry, I must leave it now. Farewell!
+His armour is shivered, his splendour is humbled.
+Roads go ever ever on.
+Yet feet that wandering have gone, turn at last to home afar.
+I should've listened to my mother...
+Presumed dead.
+What was that noise?
+For blood ye shall render blood.
+It's just one of those days...
+I see a bright light...
+The Shadow does not hold sway yet.
+I let you hit me!
+...and in the Darkness bind them.
+I didn't want to live anyway.
+-<sob>-
+One Ring to rule them all, One Ring to find them...
+Was that as close as I think it was?
+Monsters rejoice: the hero has been defeated.
+It wasn't just a job it was an adventure!
+I didn't like violence anyway!
+I thought you liked me?
+Such senseless violence! I don't understand it.
+Leithio i philinn!
+Somehow I don't feel like killing anymore.
+Help me! I am undone!
+Fire the arrows!
+This fell sergeant, Death, is strict in his arrest...
+The rest is silence.
+Guh!
+Sedho, hodo.
+You've run out of life.
+Thou art slain.
+Finish him!
+Trust me, I know what I'm doing...
+Die, mortal!
+Kill men i' the dark! What be these bloody thieves?
+Ho! Murder! Murder!
+O! I am spoil'd, undone by villains!
+O murderous slave! O villain!
+O, falsely, falsely murder'd!
+A guiltless death I die.
+AAAAAAAAAAAAAAAAAAAAAAAAHHHHHHH!
+Trust me.
+Be still, lie still.
+There-is-no life in-the-cold, in-the-dark.
+Look, behind you!!!
+Here - in-the-void only death.
+I have kept no hope for myself.
+I don't believe this!
+Oops.
+I Aear can ven na mar.
+Can't you take a joke?
+Well, I didn't much like this character, anyway...
+Oops, sorry... didn't mean to disturb you.
+I never get to have any fun!
+Stop!
+The Sea calls us home.
+Don't worry. I've got a plan.
+It didn't look so tough.
+Run away!
+Aiya Earendil Elenion Ancalima!
+AGAIN!?!?!
+I don't like this dungeon...
+Maybe this wasn't such a good idea.
+My God will protect me.
+You wouldn't dare!
+Hail Earendil brightest of the Stars!
+Farewell sweet earth and northern sky.
+And I've *never* done you any harm.
+I don't understand. It should be dead by now.
+I'm heir to the crown. They wouldn't dare!
+Mourn not overmuch! Mighty was the fallen.
+When winter comes without a spring that I shall ever see.
+Cover me.
+Watch this.
+O! Rowan dead, upon your head your hair is dry and grey.
+I will not yield.
+...but like a man he died.
+If you cut me down, I will only become more powerful.
+Well, at least I tried...?
+What could possibly have gone wrong?
+You die...
+Out of doubt, out of dark, to the day's rising.
+Surrender? Never!
+I'm sure reinforcements will get here on time. They promised.
+Hope he rekindled, and in hope ended.
+I have a very bad feeling about this.
+Over death, over dread, over doom lifted.
+I feel I could cast 'Speak with Dead' and talk to myself.
+Oh, that's just a light wound.
+Out of loss, out of life, unto long glory.
+I thought you were on MY side...
+Next time, try talking!
+Now for wrath, now for ruin and a red nightfall!
+Death in the morning and at day's ending...
+For into darkness fell his star...
+Where'd everybody go?
+Caveyard! Paveyard!
+What do you mean 'aaargllhhhh'? Hey man, I've paid for this.
+Ay! Ay! Ay!
+Ohe! Ohe! Ohe!
+Et tu, Caesar! Then fall, Brute!
+Even the best laid plans...
+Hey, not too rough!
+The Random Number Generator hates me!
+So when I die, the first thing I will see in heaven is a score list?
+Can't we talk this over?
+Wait! Spare me and I'll make you rich! Money is not a problem!
+I hate you!
+By the kind gods, 'twas most ignobly done!
+Thy nuncle was dead as a lump o' lead.
+A bump o' the boot on the seat.
+I'm the hero of this story! I CAN'T die!
+I thought heroes were supposed to win!
+I stood upon the bridge alone.
+You've fallen and can't get up!
+Dark is the path appointed for thee.
+Sure don't look good...
+Thy heart shall then rest in the forest no more.
+Hey - I've got lawyers.
+Thanks, I needed that.
+The Winter comes, the bare and leafless Day.
+Where now the horse and the rider?
+Fatality!
+Brutality!
+Who shall gather the smoke of the dead wood burning?
+For our days are ending and our years failing.
+I saw him walk in empty lands, until he passed away.
+All is lost. Monks, monks, monks!
+All my possessions for a moment of time!
+His cloven shield, his broken sword, they to the water brought.
+It is death, my boy: they have deceived me.
+Everyone dances with the Grim Reaper.
+His limbs they laid to rest.
+I will not say the Day is done, nor bid the Stars farewell.
+I am innocent, innocent, innocent!
+Watch where you're pointing with that sword! You nearly...
+The shadow lies upon my tomb...
+My cup runneth over...
+Of course I know what I am doing.
+It looked harmless.
+I have drained my cup to the bitter dregs.
+Si man i yulma nin enquantuva?
+Look! I'm flying!
+Namarie!
+I'll be back... as soon as I can.
+Fell deeds awake: fire and slaughter!
+Cold be hand and heart and bone...
+Yes! Yes! YES! YES! YY... AAARRRGGGHH!
+...cold be sleep under stone.
+Never more to wake on stony bed...
+Been nice knowing you.
+But I just got a little prick!
+Till the Sun fails and the Moon is dead.
+Hey guys, where are you?
+Hey look... ARCHERS!
+I can't probably miss...
+I don't care. I have a Scroll of Raise Dead.
+I don't care. I have a Ring of Regeneration.
+I have this dungeon at home, I know where everything is!
+This HAS to be an illusion. I attempt to disbelieve it.
+I thought you could be trusted.
+Never try to sneak in a plate mail.
+I'll never surrender.
+I'll use the Cheat Death option...
+I'm invincible!
+I'm death incarnate! Nothing can harm me!
+Hey, it was only a joke, all right?
+Hey, don't talk to me like that!
+In the black wind the stars shall die...
+Out into the barren lands.
+Where is my spellbook of Hand of Doom?
+Let me handle this.
+No problem. That's easy.
+But I have double resist!
+So what?
+Tell me this is an illusion... please!
+I hate the Random Number Generator.
+Oh. I didn't know it could resist that.
+Trust me.
+CHARGE!
+What do you mean, how many hit points do I have?
+What do you mean, my GOI expired?
+Yeah, I knew it was dangerous, but I was thinking about the experience points.
+I knew I should have played with stupid monsters on.
+I knew I shouldn't have let monsters learn from their mistakes.
+I'm not afraid of death. I just don't want to be there when it happens.
+I have such sweet thoughts.
+I pray you all pray for me.
+I shall hear in heaven.
+Is not this dying with courage and true greatness?
+I must sleep now.
+OK, turning that option on was a bad idea.
+It is finished.
+That unworthy hand! That unworthy hand!
+I am dying.
+Oh, dear.
+I will not kneel. Strike!
+I have led a happy life.
+Dying, dying.
+I feel the flowers growing over me.
+Now it is come.
+Let me die to the sound of sweet music.
+I will now enter the Halls of Mandos.
+Ungrateful traitors!
+We perish, we disappear, but the march of time goes on forever.
+Youth, I forgive thee.
+Treason! Treason!
+Coward! Why did you not protect me?
+I am absolutely undone.
+It is well. I die hard, but am not afraid to go.
+Do let me die in peace.
+Nothing is real but pain now.
+Violent use brings violent plans.
+Ha, ha, wrong again.
+Bodies fill the fields I see, the slaughter never ends.
+Life planned out before my birth, nothing could I say.
+Blood will follow blood, dying time is here.
+Never happy endings on these dark sets.
+This was supposed to be easy.
+I don't get it.
+But I read the manual!
+I was born for dying.
+The higher you walk, the farther you fall.
+Where's your crown, King Nothing?
+*sigh*
+My descendants will avenge me.
+I should have listened to my ancestors.
+I should have read the help files.
+There's a time to live, and a time to die, when it's time to meet the maker.
+One ill turn deserves another.
+Only the good die young, all the evil seem to live forever.
+That's not what the Wand of Death was supposed to do.
+And in my last hour, I'm a slave to the power of death.
+Now I am cold, but a ghost lives in my veins.
+*whimper*
+No, this really isn't happening.
+You'll take my life but I'll take yours too.
+We won't live to fight another day.
+As I lay forgotten and alone, without fear I draw my parting groan.
+Somebody please tell me that I'm dreaming!
+Can't it be there's been some sort of error?
+Is it really the end, not some crazy dream?
+Life down there is just a strange illusion.
+Your body tries to leave your soul.
+I'm so tired of living, I might as well end today.
+Life, life! Death, death! How curious it is!
+*bang*
+Flames? Not yet, I think.
+This can't be real.
+Someone call the Shiriff!
+And now the dreams end.
+Awake! Awake! Fear, Fire, Foes! Awake!
+Death greets me warm, now I will just say goodbye.
+What is this? I've been stricken by fate!
+This can't be happening to me!
+I didn't know it was a Scroll of Aggravate Monster!
+You have been dying since the day you were born.
+No point asking who's to blame.
+But for all his power he couldn't foresee his own demise.
+My creator will lay my soul to rest.
+Was that worth dying for?
+Can you say you are proud of what you've done?
+But there are some things which cannot be excused.
+Why is it some of us are here just so that we'll die?
+The shortest straw, pulled for you.
+There's got to be just more to it that this or tell me why do we exist?
+I can't believe that really my time has come.
+'New blood joins this earth...'
+But my Saving Throw is Good!
+I really only like writing poetry.
+What is Time, friend or foe?
+Time waits for none.
+Why didn't I start a Necromancer?
+Flash before my eyes: now it's time to die.
+Gaaaah! This is most frustrating.
+I hate summoners.
+I'm not dead yet. I still have five hit points.
+To sleep, perchance to dream.
+I rolled a 20. How could that be a miss?
+This thing all things devours.
diff --git a/lib/mods/theme/file/elvish.txt b/lib/mods/theme/file/elvish.txt
new file mode 100644
index 00000000..a00b5a22
--- /dev/null
+++ b/lib/mods/theme/file/elvish.txt
@@ -0,0 +1,218 @@
+216
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+adan
+ael
+in
+agl
+ar
+aina
+alda
+al
+qua
+am
+arth
+amon
+anca
+an
+dune
+anga
+anna
+ann
+on
+ar
+ien
+atar
+band
+bar
+ad
+bel
+eg
+brag
+ol
+breth
+il
+brith
+cal
+en
+gal
+en
+cam
+car
+ak
+cel
+eb
+cor
+on
+cu
+cui
+vie
+cul
+curu
+dae
+dag
+or
+del
+din
+dol
+dor
+draug
+du
+duin
+dur
+ear
+ech
+or
+edh
+el
+eith
+elen
+er
+ereg
+es
+gal
+fal
+as
+far
+oth
+faug
+fea
+fin
+for
+men
+fuin
+gaer
+gaur
+gil
+gir
+ith
+glin
+gol
+odh
+gond
+gor
+groth
+grod
+gul
+gurth
+gwaith
+gwath
+wath
+had
+hod
+haudh
+heru
+him
+hini
+hith
+hoth
+hyar
+men
+ia
+iant
+iath
+iaur
+ilm
+iluve
+kal
+gal
+kano
+kel
+kemen
+khel
+ek
+khil
+kir
+lad
+laure
+lhach
+lin
+lith
+lok
+lom
+lome
+londe
+los
+loth
+luin
+maeg
+mal
+man
+mel
+men
+menel
+mer
+eth
+min
+as
+mir
+mith
+mor
+moth
+nan
+nar
+naug
+dil
+dur
+nel
+dor
+nen
+nim
+orn
+orod
+os
+pal
+an
+pel
+quen
+quet
+ram
+ran
+rant
+ras
+rauko
+ril
+rim
+ring
+ris
+roch
+rom
+rond
+ros
+ruin
+ruth
+sarn
+ser
+eg
+sil
+sir
+sul
+tal
+dal
+tal
+ath
+tar
+tath
+ar
+taur
+tel
+thal
+thang
+thar
+thaur
+thin
+thol
+thon
+thor
+on
+til
+tin
+tir
+tol
+tum
+tur
+uial
+ur
+val
+wen
+wing
+yave
diff --git a/lib/mods/theme/file/error.txt b/lib/mods/theme/file/error.txt
new file mode 100644
index 00000000..5829ffbc
--- /dev/null
+++ b/lib/mods/theme/file/error.txt
@@ -0,0 +1,67 @@
+65
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+What game do you think you are playing anyway?
+Aivan sairas kaveri kun tuollaista aikoo puuhata!
+Insufficient data for further analysis.
+Non sequitur. Your facts are uncoordinated.
+Type '?' or '\' for help.
+Invalid command.
+What?
+WHAT?!
+You must be out of your mind!
+You're killing me.
+Are you sure?
+Are you sure you know what you are doing?
+Aww, come on!
+That makes no sense.
+I beg your pardon.
+Degreelessness mode on.
+Degreelessness mode off.
+Syntax error.
+That doesn't compute.
+I don't understand you.
+???
+Sure. Piece of cake.
+Error.
+You can't do that!
+Help!
+Come again?
+Sorry?
+Sorry, I'm not sure I understand you.
+What's your point?
+Unknown command.
+Command not found.
+An unexpected error has occurred because an error of type 42 occurred.
+Somehow, you think that would never work.
+Welcome to level 42.
+Don't be ridiculous!
+lfae aierty agnxzcg?
+Soyha, azho bouate!
+I don't fully understand you.
+Why would anybody want to do THAT?
+Yes, yes, now tell me about your childhood.
+Satisfied?
+Something is wrong here.
+There's something wrong with YOU.
+You leap up 9' and perform a miraculous 5xSpiral in the air.
+Aw, shaddap!
+Shut up, smartass!
+I see little point in doing that.
+Oh, really?
+Very funny.
+You've got to be kidding!
+I'm not amused.
+I must have misheard you.
+Nothing happens.
+Where did you learn THAT command?
+When all else fails, read the instructions.
+Why not read the instructions first?
+Cut it out!
+Nothing interesting happens.
+Just how exactly am I supposed to do THAT?
+That's morally wrong and I won't do it.
+I'm not gonna take this abuse.
+AAAAAAAAAAAAAHHHHHHHHHHHHHHHRRRRRRRRRRRGGGGGGGGGGG!
+No more, if you value your character's life!
+I don't have any options, oh my!
+Disk error. (a)bort, (r)etry, (f)ail?
diff --git a/lib/mods/theme/file/mondeath.txt b/lib/mods/theme/file/mondeath.txt
new file mode 100644
index 00000000..e1dc7967
--- /dev/null
+++ b/lib/mods/theme/file/mondeath.txt
@@ -0,0 +1,334 @@
+332
+****** BUFFER LINE *********************************** DO NOT REMOVE *******
+'I must away, ere break of day...'
+'AAAAAAAAARRRRRRRRRRRRRRRRGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHH!!!!!!!!!!!'
+'AAAARRRGGGHHH!!!'
+'Somehow, I have a bad feeling about this...'
+'Strangely, all of a sudden I don't feel so good.'
+'I can see armored women on winged horses coming for me.'
+'Oh well, you can't always win.'
+'I'm too young to die!'
+'I'll be back!'
+'O, untimely death!'
+'Slave, thou hast slain me!'
+'I hear the tramp of doom.'
+'Who knocked?'
+'What's a burrahobbit?'
+'Ouch.'
+'Et tu, Brute! Then fall, Caesar!'
+'To fly would be folly.'
+'I told you to be careful with that sword...'
+'The wind came down from mountains cold.'
+'Cut the bridges! To arms! To arms!'
+'O! wandering folk, the summons heed!'
+'Who turned off the light..?'
+'I go now to the halls of waiting.'
+'I leave now all gold and silver, and go where it is of no worth.'
+'Rats!'
+'Shall this fellow live?'
+'Help, ho!'
+'What ho! Help!'
+'What hast thou done?'
+'I'll be revenged on the whole pack of you!'
+'You will *pay* for this!'
+'They say blood will have blood...'
+'Violence is no solution!'
+'Yes?'
+'#&%#&#%*#*&%!!!!!'
+'This is a bitter adventure, if it must end so.'
+'No time to make a testament?'
+'Ugh!'
+'Aargh!'
+'Aaagghhh!'
+'I'm melting!'
+'Oof..'
+'Oh!'
+'Did somebody knock?'
+'But sad or merry, I must leave it now. Farewell!'
+'His armour is shivered, his splendour is humbled.'
+'Roads go ever ever on.'
+'Yet feet that wandering have gone, turn at last to home afar.'
+'Eeek!'
+'Aah!'
+'I hate it when that happens.'
+'One direct hit can ruin your whole day.'
+'Oh no!'
+'Not me!'
+'Presumed dead.'
+'Oh no, not again.'
+'Another one bites the dust.'
+'Goodbye.'
+'Help me!'
+'Farewell, cruel world.'
+'Blackheart! I have done thy bidding.'
+'For blood ye shall render blood.'
+'This is the End, my only friend.'
+'It's all over.'
+'The Shadow does not hold sway yet.'
+'Why does everything happen to me?'
+'I'm going down.'
+'...and in the Darkness bind them.'
+'One Ring to rule them all, One Ring to find them...'
+'Hail Sauron, Lord of the Ring, Lord of the Earth!'
+'Leithio i philinn!'
+'Fire the arrows!'
+'Sedho, hodo.'
+'Be still, lie still.'
+'What was that noise?'
+'There-is-no life in-the-cold, in-the-dark.'
+'It's just one of those days...'
+'I see a bright light...'
+'Here - in-the-void only death.'
+'I let you hit me!'
+'I have kept no hope for myself.'
+'I didn't want to live anyway.'
+'-<sob>-'
+'I Aear can ven na mar.'
+'Was that as close as I think it was?'
+'The monsters rejoice: the hero has been defeated.'
+'It wasn't just a job it was an adventure!'
+'I didn't like violence anyway!'
+'I thought you liked me?'
+'Such senseless violence! I don't understand it.'
+'The Sea calls us home.'
+'Somehow I don't feel like killing anymore.'
+'Help me! I am undone!'
+'Farewell sweet earth and northern sky.'
+'This fell sergeant, Death, is strict in his arrest...'
+'The rest is silence.'
+'Guh!'
+'Mourn not overmuch! Mighty was the fallen.'
+'Trust me, I know what I'm doing...'
+'Kill men i' the dark! What be these bloody thieves?'
+'Ho! Murder! Murder!'
+'O! I am spoil'd, undone by villains!'
+'O murderous slave! O villain!'
+'O, falsely, falsely murder'd!'
+'A guiltless death I die.'
+'AAAAAAAAAAAAAAAAAAAAAAAAHHHHHHH!'
+'Trust me.'
+'When winter comes without a spring that I shall ever see.'
+'Out of doubt, out of dark, to the day's rising.'
+'Look, behind you!!!'
+'Hope he rekindled, and in hope ended.'
+'Over death, over dread, over doom lifted.'
+'I don't believe this!'
+'Oops.'
+'Can't you take a joke?'
+'Out of loss, out of life, unto long glory.'
+'Oops, sorry... didn't mean to disturb you.'
+'I never get to have any fun!'
+'Stop!'
+'Now for wrath, now for ruin and a red nightfall!'
+'Don't worry. I've got a plan.'
+'It didn't look so tough.'
+'Run away!'
+'Death in the morning and at day's ending...'
+'AGAIN!?!?!'
+'I don't like this dungeon...'
+'Maybe this wasn't such a good idea.'
+'My God will protect me.'
+'You wouldn't dare!'
+'For into darkness fell his star...'
+'Caveyard! Paveyard!'
+'And I've *never* done you any harm.'
+'I don't understand. It should be dead by now.'
+'I'm heir to the crown. They wouldn't dare!'
+'Hey! Where's my stomach? My hands?'
+'Ha! That's the oldest trick in the book.'
+'Cover me.'
+'Watch this.'
+'And damn'd be him that first cries: Hold, enough!'
+'I will not yield.'
+'...but like a man he died.'
+'If you cut me down, I will only become more powerful.'
+'Well, at least I tried...?'
+'What could possibly have gone wrong?'
+'Thy nuncle was dead as a lump o' lead.'
+'Surrender? Never!'
+'I'm sure reinforcements will get here on time. They promised.'
+'A bump o' the boot on the seat.'
+'I have a very bad feeling about this.'
+'I stood upon the bridge alone.'
+'I feel I could cast Speak with Dead and talk to myself.'
+'Oh, that's just a light wound.'
+'Dark is the path appointed for thee.'
+'I thought you were on MY side...'
+'Thy heart shall then rest in the forest no more.'
+'The Winter comes, the bare and leafless Day.'
+'Where now the horse and the rider?'
+'Uhh... oh-oh...'
+'Gee, where'd everybody go?'
+'Who shall gather the smoke of the dead wood burning?'
+'Ay! Ay! Ay!'
+'Ohe! Ohe! Ohe!'
+'Et tu, Caesar! Then fall, Brute!'
+'Even the best laid plans...'
+'For our days are ending and our years failing.'
+'The Random Number Generator hates me!'
+'So when I die, the first thing I will see in heaven is a score list?'
+'Can't we talk this thing over?'
+'Wait! Spare me and I'll make you rich! Money is not a problem!'
+'I hate you!'
+'By the kind gods, 'twas most ignobly done!'
+'I saw him walk in empty lands, until he passed away.'
+'His cloven shield, his broken sword, they to the water brought.'
+'I'm the hero of this story! I CAN'T die!'
+'His limbs they laid to rest.'
+'I've fallen and I can't get up!'
+'I'll be back for my revenge.'
+'Sure don't look good...'
+'I will not say the Day is done, nor bid the Stars farewell.'
+'I'll be back...'
+'The shadow lies upon my tomb...'
+'Thanks, I needed that.'
+'My cup runneth over...'
+'I have drained my cup to the bitter dregs.'
+'Oh, basely done! I had hoped for better of thee!'
+'I am death incarnate! NOTHING can harm me!'
+'Si man i yulma nin enquantuva?'
+'Namarie!'
+'All is lost. Monks, monks, monks!'
+'All my possessions for a moment of time!'
+'Fell deeds awake: fire and slaughter!'
+'Cold be hand and heart and bone...'
+'Everyone dances with the Grim Reaper.'
+'...cold be sleep under stone.'
+'Never more to wake on stony bed...'
+'I am innocent, innocent, innocent!'
+'Watch where you're pointing with that sword! You nearly...'
+'Till the Sun fails and the Moon is dead.'
+'In the black wind the stars shall die...'
+'Of course I know what I am doing.'
+'It looked harmless.'
+'Out into the barren lands.'
+'Where is my spellbook of Hand of Doom?'
+'Look! I'm flying!'
+'But I have double resist!'
+'I'll be back... as soon as I can.'
+'Oh. I didn't know it could resist that'
+'This was supposed to be easy.'
+'Yes! Yes! YES! YES! YY... AAARRRGGGHH!'
+'I don't get it.'
+'But I read the manual!'
+'Been nice knowing you.'
+'But I just got a little prick!'
+'*sigh*'
+'Hey guys, where are you?'
+'Hey look... ARCHERS!'
+'I can't probably miss...'
+'I don't care. I have a Scroll of Raise Dead.'
+'I don't care. I have a Ring of Regeneration.'
+'I have this dungeon at home, I know where everything is!'
+'This HAS to be an illusion. I attempt to disbelieve it.'
+'I thought you could be trusted.'
+'Never try to sneak in a plate mail.'
+'I'll never surrender.'
+'I'll use the Cheat Death option...'
+'I'm invincible!'
+'Hey, it was only a joke, all right?'
+'Hey, don't talk to me like that!'
+'*bang*'
+'You have robbed my revenge of sweetness.'
+'I'll see your descendants later!'
+'Let me handle this.'
+'No problem. That's easy.'
+'*whimper*'
+'So what?'
+'Tell me this is an illusion... please!'
+'I hate the Random Number Generator.'
+'Oh, great.'
+'Trust me.'
+'CHARGE!'
+'What do you mean, how many hit points do I have?'
+'What do you mean, my GOI expired?'
+'One ill turn deserves another.'
+'But, Sharkey!'
+'But I'm famous!'
+'Awake! Awake! Fear, Fire, Foes! Awake!'
+'Idiots! I am surrounded by incompetent idiots!'
+'I have such sweet thoughts'
+'I pray you all pray for me.'
+'Is not this dying with courage and true greatness?'
+'I must sleep now.'
+'I really only like writing poetry.'
+'That unworthy hand! That unworthy hand!'
+'I am dying.'
+'I like happy things. I'm really calm and peaceful.'
+'I will not kneel. Strike!'
+'I have led a happy life.'
+'Dying, dying.'
+'I feel the flowers growing over me.'
+'Now it is come.'
+'Let me die to the sound of sweet music.'
+'I will now enter the Halls of Mandos.'
+'Ungrateful traitors!'
+'We perish, we disappear, but the march of time goes on forever.'
+'Youth, I forgive thee.'
+'Treason! Treason!'
+'Cowards! Why did you not protect me?'
+'I am absolutely undone.'
+'It is well. I die hard, but am not afraid to go.'
+'Do let me die in peace.'
+'Nothing is real but pain now.'
+'Violent use brings violent plans.'
+'Won't you look at all the pretty flowers?'
+'Bodies fill the fields I see, the slaughter never ends.'
+'Life planned out before my birth, nothing could I say.'
+'Blood will follow blood, dying time is here.'
+'Never happy endings on these dark sets.'
+'Gaaaah! This is most frustrating.'
+'What treachery is this?'
+'Greetings, Death, I'm yours to take away.'
+'I was born for dying.'
+'The higher you walk, the farther you fall.'
+'Down here, we all float.'
+'New blood joins this earth...'
+'You labeled me, I'll label you, so I dub thee unforgiven.'
+'See you in the Void!'
+'There's a time to live, and a time to die, when it's time to meet the maker.'
+'Isn't it strange, as soon as you're born you're dying?'
+'Only the good die young, all the evil seem to live forever.'
+'No, no, no. It's not fair.'
+'And in my last hour, I'm a slave to the power of death.'
+'Now I am cold, but a ghost lives in my veins.'
+'This didn't just happen.'
+'You hit me for HOW MUCH damage?'
+'You'll take my life but I'll take yours too.'
+'We won't live to fight another day.'
+'As I lay forgotten and alone, without fear I draw my parting groan.'
+'Somebody please tell me that I'm dreaming!'
+'Can't it be there's been some sort of error?'
+'You cheated!'
+'Life down there is just a strange illusion.'
+'My life suffocates, planting seeds of hate.'
+'I'm not dead yet. I still have five hit points'
+'My body tries to leave my soul.'
+'I'm so tired of living, I might as well end today.'
+'Life, life! Death, death! How curious it is!'
+'Oh well, it's back to square one in HMa.'
+'Flames? Not yet, I think.'
+'Great. Now I can finish my memoirs.'
+'And now the dreams end.'
+'Sharkey made me do it.'
+'Death greets me warm, now I will just say goodbye.'
+'What is this? I've been stricken by fate!'
+'This can't be happening to me!'
+'Flash before my eyes: now it's time to die.'
+'You have been dying since the day you were born.'
+'No point asking who's to blame.'
+'But for all my power I couldn't foresee my own demise.'
+'My creator will lay my soul to rest.'
+'Was that worth dying for?'
+'Can you say you are proud of what you've done?'
+'But there are some things which cannot be excused.'
+'Why is it some of us are here just so that we'll die?'
+'The shortest straw, pulled for me.'
+'There's got to be just more to it that this or tell me why do we exist?'
+'I can't believe that really my time has come.'
+'This is just gruesome.'
+'When the dream dies, the nightmare begins.'
+'This thing all things devours.'
+'This can't be real.'
+'No, this really isn't happening.'
+'I believe my kingdom will come'
diff --git a/lib/mods/theme/file/monfear.txt b/lib/mods/theme/file/monfear.txt
new file mode 100644
index 00000000..fbff8538
--- /dev/null
+++ b/lib/mods/theme/file/monfear.txt
@@ -0,0 +1,63 @@
+61
+*********** BUFFER LINE ********************** DO NOT REMOVE *****************
+says: 'I am too young to die.'
+says: 'Ok, ok!'
+screams: 'Help, ho!'
+screams: 'What ho! Help!'
+says: 'You will pay for this!'
+says: 'Violence is no solution!'
+says: 'I thought you liked me.'
+says: 'Such senseless violence! I don't understand it!'
+screams: 'Ho! Murder! Murder!'
+says: 'Look, behind you!'
+screams: 'Run away!'
+screams: 'Run to the hills! Run for your lives!'
+says: 'Wait! Spare me and I'll make you rich! Money isn't a problem!'
+says: 'I'll be back...'
+begs for you to spare its life.
+says: 'All my possession for a moment of time!'
+says: 'Hey, it was only a joke, all right?'
+says: 'Stop!'
+grovels at your feet.
+says: 'Money? Sure, take it all back!'
+screams: 'Cowards! Why did you not protect me?'
+sobs: 'I didn't MEAN it...'
+begs: 'Spare me and I'll get you Ringil! Really!'
+whimpers and grovels.
+screams: 'Keep that lunatic away from me!'
+shouts: 'Drop that weapon, now!'
+says: 'Fool! You don't know what you're doing!'
+screams for help!
+begs for mercy.
+sobs.
+screams: 'Help! The maniac's murdering me!'
+sobs: 'All right! I apologise! I really, really do!'
+says: 'Wait! Let's make a deal!'
+says: 'Just can't stop this surmounting terror!'
+says: 'If there is a God, then why has he let me die?'
+cringes and whimpers.
+says: 'No hope, no life, just pain and fear.'
+says: 'I am a fugitive, hunted down like game.'
+says: 'You'll live to regret this blasphemous offence!'
+says: 'All my life's blood is slowly draining away...'
+asks: 'Should we be fighting at all?'
+asks: 'What are we fighting for?'
+asks you: 'Can you say you are proud of what you've done?'
+says: 'Every minute I get weaker...'
+says: 'All my life I've run away...'
+says: 'All that I see, absolute horror!'
+says: 'I have fallen prey to failure.'
+says: 'Just leave me alone!'
+says: 'Please, save me!'
+says: 'You've won a battle, but I'll win the war!'
+says: 'You've won this round, next time it's *my* turn!'
+says: 'Another time, another battlefield, *my* victory.'
+says: 'I've got to keep running.'
+says: 'It's all so futile!'
+says: 'Cowards live to fight another day.'
+says: 'Life it seems will fade away, drifting further every day.'
+says: 'Emptiness is filling me, to the point of agony.'
+says: 'Cannot stand this hell I feel!'
+cries: 'Someone help me, oh please God help me!'
+prays fervently to any Gods that are listening.
+cries: 'Spare me!'
diff --git a/lib/mods/theme/file/monspeak.txt b/lib/mods/theme/file/monspeak.txt
new file mode 100644
index 00000000..221326be
--- /dev/null
+++ b/lib/mods/theme/file/monspeak.txt
@@ -0,0 +1,517 @@
+# This is the file for allowing uniques to speak their "own" lines.
+# Deleting this file will have no real effect on the game. Modifying it may
+# cause STRANGE unique lines to come up if the format's wrong, but shouldn't
+# crash anything. The format goes like so:
+#
+# N:45:whoever this is
+# 3
+# says bravado line 1
+# says bravado line 2
+# says bravado line 3
+# 2
+# says fear line 1
+# says fear line 2
+#
+# The number after the N: is the "monster index number" obtained from
+# r_info.txt. The text field after that number isn't actually used--it's
+# just there to help humans edit the file. The numbers on lines by
+# themselves say the number of "bravado" and "fear" lines. Getting these
+# numbers wrong won't crash anything, but will produce strange lines.
+#
+# Two or more monsters can share lines; just put their N: lines in a
+# contiguous block.
+#
+# To stop a certain monster from having unique lines, put a # in front of
+# its N: line.
+#
+# Have fun with this! --Matt G
+
+N:63:Smeagol
+27
+snickers.
+grovels.
+picks his nose.
+pines for his precious.
+searches his pockets.
+eats some slimy creatures.
+mutters: 'My preciouss, where iss my preciouss?'
+shouts: 'No Master Hobbitsisisisis!'
+cries: 'The ring was ours for agesisisisis!'
+says: 'Smeagol sneaking! ME! Shneeeakingsisis!'
+screams: 'Nassty Hobbitsisisisis...'
+says: 'Come on, quickly, follow Smeagol!'
+coughs: 'Gollum! Gollum!'
+says: 'Every way is guarded, silly foolsis!'
+says: 'Nassty Bagginsis, stole my precious.'
+says: 'She will kill them, oh yes she will preciouss.'
+says: 'Does it guess easy? It must have a competition with us, preciouss!'
+hisses: 'What has it got in its pocketses?'
+whimpers: 'We've lost it, we have.'
+says: 'No food, no rest; Smeagol a SNEAK!'
+says: 'What a dainty little dish you will be for her.'
+says: 'Hobbitses always SOOOO polite.'
+screams: 'Stop, Thief!'
+says: 'Makeses him drop his weapon precious.'
+grovels: 'He has only four fingers on the black hand.'
+growls: 'Not nice Hobbits, not sensible!'
+says: 'If you findesis it, give it us back.'
+3
+says, 'Don't hurt us, mastersisis.'
+says, 'Poor Smeagol, poor Smeagol.'
+says, 'No AH! Don't hurtsis us.'
+
+N:102:Lurtz, Uruk Captain of the White Hand
+N:140:Lagduf, the Snaga
+N:170:Radbug, the Goblin
+N:186:Grishnakh, the Hill Orc
+N:215:Golfimbul, the Hill Orc Chief
+N:260:Ufthak of Cirith Ungol
+N:314:Shagrat, the Orc Captain
+N:315:Gorbag, the Orc Captain
+N:330:Bolg, Son of Azog
+N:350:Ugluk, the Uruk
+N:356:Lugdush, the Uruk
+N:370:Muzgash, the Snaga
+N:373:Azog, King of the Uruk-Hai
+N:399:Mauhur, the Uruk
+17
+fingers his blade and grins evilly.
+says, 'I'll bet your innards would taste real sweet...'
+says, 'I love the smell of fresh blood.'
+wonders aloud how many experience points you're worth.
+sings, 'Clap! Snap! the black crack!'
+sings, 'Grip, grab! Pinch, nab!'
+sings, 'And down down to Goblin-town you go, my lad!'
+sings, 'Clash, crash! Crush, smash!'
+sings, 'Hammer and tongs! Knocker and gongs!'
+sings, 'Pound, pound, far underground!'
+sings, 'Ho, ho! my lad!'
+sings ' Swish, smack! Whip crack!'
+sings 'Batter and beat! Yammer and bleat!'
+sings, 'Work, work! Nor dare to shirk,'
+sings, 'While Goblins quaff, and Goblins laugh,'
+sings, 'Round and round far underground...'
+sings, 'Below, my lad!'
+6
+screams, 'Hey, orcs have rights too!'
+says, 'You're just prejudiced against orc-kind, aren't you?'
+begs, 'Spare me and I'll get you Ringil! Really!'
+says, 'Next time, I'm bringing more Uruks with me!'
+says, 'Don't hate me because I'm ugly!'
+whimpers and grovels.
+
+N:137:Grima Wormtongue, Agent of Saruman
+3
+says, 'Lathspell I name you, Ill-news; and Ill-news is an ill guest they say.'
+says, 'Forbid his staff!'
+yells, 'You lie!'
+3
+screams, 'Let me go, let me go!'
+says, 'My messages are useless now!'
+hisses, 'You told me to; you made me do it!'
+
+N:412:Lotho Sackville-Baggins, Betrayer of the Shire
+N:374:Bill Ferny
+N:437:Harry Goatleaf, Gatekeeper of Bree
+5
+whines and snickers.
+whispers nasty things.
+says, 'I'll slaughter you slowly...'
+giggles as he fingers his knife.
+says, 'Now, you shall taste my wrath!'
+3
+begs you to spare his miserable life.
+whines, 'This is not my fault!'
+screams, 'Help! Help!'
+
+N:138:Robin Hood, the Outlaw
+5
+eyes your money pouch covetously.
+says, 'You look like Nottingham's man to me!'
+says, 'I bet I can shoot better than you...'
+says, 'Give till it hurts!'
+says, 'Do not force me to put an arrow in your skull...'
+3
+begs you to spare his life.
+says, 'But I'm a GOOD guy, really!'
+says, 'Money? Sure, take it all back!'
+
+N:254:Maedhros the Tall
+N:263:Maglor the Mighty Singer
+N:268:Celegorm the Fair
+N:274:Caranthir the Dark
+N:276:Curufin the Crafty
+N:318:Amrod, Son of Feanor
+N:319:Amras, Son of Feanor
+8
+says, 'I swore an oath which none shall break.'
+says, 'I sword an oath which none should take.'
+says, 'I swore by the name of even Iluvatar.'
+says, 'I called the Everlasting Dark upon me if I kept it not.'
+says, 'I named Manwe my witness.'
+says, 'I named Varda, and hallowed Taniquetil, my witnesses.'
+says, 'I will pursue with vengeance and hatred.'
+says, 'None shall keep or hold a Silmaril from me.'
+3
+says, 'I accept my fate.'
+says, 'This must be payment for the Kinslaying.'
+says, 'The blood of my kin burns my hands.'
+
+N:169:Brodda, the Easterling
+N:291:Ulfast, Son of Ulfang
+N:413:Ulwarth, Son of Ulfang
+N:392:Sangahyando of Umbar
+N:380:Angamaite of Umbar
+N:573:Lorgan, Chief of the Easterlings
+N:987:Uldor the Accursed
+N:990:Ulfang the Black
+11
+fingers his blade and grins evilly.
+snickers, 'Now, I strike a blow for *our* side!'
+calls your mother nasty names.
+belches and spits.
+scratches his armpits.
+says, 'I love the smell of fresh blood.'
+says, 'Yeeha! Another idiot to slaughter!'
+wonders aloud how many experience points you're worth.
+says, 'My brain's on fire with the feeling to kill!'
+says, 'I shall torture you slowly.'
+says, 'I shall have my way with your women!'
+3
+whimpers, 'No, I will really fight on your side!'
+says, 'Morgoth made me do it.'
+says, 'Please don't kill me!'
+
+#This next may be unnecessarily evil... :-]
+N:393:It
+4
+says, 'Nyah, nyah, betcha can't find me!'
+magically summons mighty undead opponents!
+casts a spell and cackles evilly.
+magically summons special opponents!
+2
+howls, 'I'll be back!'
+whimpers, 'They said this invisibility thing was fool-proof!'
+
+N:441:Tom Bombadil
+8
+sings, 'Hey dol! merry dol! ring a dong dillo!'
+sings, 'Old Tom Bombadil water-lilies bringing...'
+sings, 'Goldberry, Goldberry, merry yellow berry-o!'
+sings, 'Hey! Come derry dol! Can you hear me singing?'
+says, 'Eat earth! Dig deep! Drink water! Go to sleep!'
+says, 'Bombadil is talking!'
+sings, 'Hey! Come derry dol! Hop along, my hearties!'
+sings, 'Old Tom Bombadil is a merry fellow!'
+0
+
+#N:467:Beorn, the Shape-Changer
+6
+says, 'They don't look dangerous!'
+laughs a great rolling laugh.
+says, 'O ho, so you've had trouble with THEM, have you?'
+says, 'I don't need your service, thank you.'
+asks, 'Where are they? Killed, eaten, gone home?'
+admonishes, 'I would have given them more than fireworks!'
+0
+
+N:489:Varda, Lady of the Stars
+N:490:Vaire, the Weaver
+N:492:Irmo of Lorien
+N:497:Este, the Gentle
+N:498:Nienna, the Sorrowful
+N:506:Nessa the Lithe
+N:511:Orome, the Huntsman of the Valar
+N:515:Vana, the Ever-young
+56
+gazes southwards.
+reveals: The Helcaraxe is in the north-west.
+gazes northwards.
+reveals: Don't bring any glassware to the Helcaraxe.
+gazes eastwards.
+reveals: The Wastelands of the North are guarded by the Hunter.
+gazes westwards.
+reveals: The Withered Heath is in the Grey Mountains.
+sings softly.
+reveals: Utumno has not been destroyed completely.
+whispers something.
+reveals: The Blue Wizards are trapped in Utumno.
+weeps quietly.
+reveals: Utumno is in the north-east.
+looks at you sadly.
+reveals: There is an artifact that will let you identify items.
+turns away from you.
+reveals: There is a powerful artifact guarded in Near Harad.
+says, 'Don't you have a quest to complete, child?'
+reveals: The Castle of Dol Amroth is in the south.
+gazes southwards.
+reveals: A strange creature guards the Maze in the south.
+gazes northwards.
+reveals: Cirith Ungol is poisonous.
+gazes eastwards.
+reveals: There is a passage to The Lonely Isle in the southwest.
+gazes westwards.
+reveals: Saruman waits for you beneath Isengard.
+sings softly.
+reveals: To get to Khazad-Dum, you must pass through Moria.
+whispers something.
+reveals: There is a snowy passage through the Misty Mountains.
+weeps quietly.
+reveals: The Witch-Realm of Angmar will poison and disenchant.
+looks at you sadly.
+reveals: There is a great treasure in the Blue Mountains.
+turns away from you.
+reveals: You must bring a Map and a Key to Smaug's lair in Erebor.
+says, 'Don't you have a quest to complete, child?'
+reveals: Beware of the Deep Marshes.
+gazes southwards.
+reveals: Level 95 of Angband is a special level.
+gazes northwards.
+reveals: Level 85 of Angband is a special level.
+gazes eastwards.
+reveals: Level 70 of Angband is a special level.
+gazes westwards.
+reveals: Level 21 of the Orc Caves is a special level.
+sings softly.
+reveals: Level 35 of Moria is a special level.
+whispers something.
+reveals: The last level of Mount Doom never changes.
+weeps quietly.
+reveals: Mirkwood forest will lead you to the Heart of the World.
+looks at you sadly.
+reveals: There is a small water cave in Moria.
+0
+
+N:493:Bert the Stone Troll
+N:494:Bill the Stone Troll
+N:495:Tom the Stone Troll
+7
+asks, 'What are yer?'
+asks, 'What's a burrahobbit got to do with my pockets?'
+muses, 'You wouldn't make above a mouthful.'
+taunts, 'You're a fat fool!'
+says, 'You're a booby.'
+says, 'That'll teach yer!'
+says, 'I won't take that from you!'
+0
+
+N:505:Groo the Wanderer
+0
+1
+says: 'A fray! A fray!'
+
+N:523:N:523:Ingeborg, the Runemistress
+6
+says: 'Hey, I just had a neat idea!'
+says: 'Ringil? Never heard of it where I come from!'
+scribbles busily on a stack of parchment.
+mutters something in an unknown tongue.
+cuddles something warm and fuzzy.
+offers you a hug.
+3
+shrieks: 'Oh my gods, I'm doomed!'
+protests: 'Awww, I just wanted to hug you...'
+protests: 'Hey, it's only a game--please don't hurt me!'
+
+N:531:Lindal Lossehelin
+N:552:Erianyth, the Sorceress
+N:557:Karrazix the Brave
+N:564:Sir Physt
+N:572:Slappy, Abbess of Pain
+5
+asks, 'Hey, you got a Cloak of Air I can borrow?'
+states matter-of-factly, 'You're not as tough as I am.'
+asks, 'Are you going to DiTL this one?'
+brags, 'My CON is higher than yours.'
+gloats, 'I got Boots of Speed from that stupid princess.'
+2
+screams, 'See you on the t-o-m-e.net forums!'
+screams, 'ToME rules!'
+
+N:535:Zizzo, Last of the Yeeks
+N:569:Nick LeYeek, Second Last of the Yeeks
+N:595:Orfax, son of Boldor
+N:596:Boldor, King of the Yeeks
+5
+wonders aloud about your sexual orientation.
+spouts torrents of obscenities.
+shouts, 'YEEK! YEEK! YEEK!'
+wonders aloud how many experience points you're worth.
+says, 'I'll teach you to respect yeeks!'
+2
+sobs, 'I didn't MEAN it...'
+whimpers and moans.
+
+N:660:Eol, the Dark Elf
+5
+says, 'I acknowledge not your law.'
+says, 'I care nothing for your secrets.'
+says, 'I came not to spy on you but to claim my own.'
+screams, 'My son you shall not withhold from me!'
+screams, 'You shall not hold what is mine!'
+1
+'Here you may yet die the same death as I.'
+
+N:697:Smaug the Golden
+12
+says, 'Well, thief! I smell you and I feel your air. I hear your breath.'
+says, 'Come along! Help yourself, there is plenty and to spare.'
+says, 'You have nice manners for a thief and a liar.'
+wonders: 'Who are you and where do you come from, may I ask?'
+says, 'Lucky numbers don't often come off.'
+says, 'Some nasty scheme of those Lake-men, or I'm a lizard.'
+brags, 'I kill where I wish and none dare resist.'
+brags, 'I laid low the warriors of old whose like is not in the world today.'
+brags, 'Now I am old and strong, strong, strong!'
+brags, 'My armour is like tenfold shields, my teeth are swords, my claws spears.'
+brags, 'The shock of my tail is a thunderbolt, my wings a hurricane!'
+brags, 'I am armoured above and below with iron scales and hard gems.'
+2
+wails, 'No, no, no! Not the Black Arrow!'
+admits defeat.
+
+N:714:Quickbeam, the Ent
+2
+says, 'I like birds, even when they chatter.'
+shouts, 'Ra-hoom-rah!'
+0
+
+N:715:Glaurung, Father of the Dragons
+5
+calls you a thankless fosterling.
+taunts, 'Captain foolhardy!'
+calls you The Usurper of Nargothrond!
+says, 'If thou wilt be slain, I will slay thee gladly.'
+lectures, 'They lie who say we do not honour the valour of foes.'
+1
+lets out a bloodcurdling scream.
+
+N:771:Saruman of Many Colours
+3
+says, 'One ill turn deserves another.'
+brags, 'Whoever strikes me shall be accursed.'
+admonishes, 'Meddle not in policies which you do not understand.'
+3
+says, 'Spare me your pity. I would hate you even more for it.'
+croaks, 'Do not expect me to wish you health and long life.'
+lets out a shrill shriek
+
+N:850:Carcharoth, the Jaws of Thirst
+N:840:Draugluin, Sire of All Werewolves
+7
+barks and bellows frighteningly!
+says, 'Oh good, another chew toy!'
+says, 'Yummy! I was getting tired of chicken...'
+lets out an earsplitting howl.
+drools all over the dungeon.
+says, 'Bad adventurer! No more living for you!'
+snarls and howls.
+1
+cringes and whimpers.
+
+N:818:The Mouth of Sauron
+6
+asks, 'Anyone with authority to treat with me? Not thou at least!'
+says, 'This time thou hast stuck out thy nose too far.'
+says, 'Thou shalt see what comes to him who defy Sauron the Great.'
+says, 'Take swift counsel with what little wit is left to you.'
+says, 'And now thou shalt endure the slow torment of years!'
+says, 'Do not bandy words in your insolence with the Mouth of Sauron!'
+1
+screams, 'This CAN'T be happening!'
+shouts, 'Kill me if you want, the Boss will get you!'
+
+N:804:Vecna, the Emperor Lich
+N:844:Feagwath the Undead Sorceror
+N:856:Gothmog, the High Captain of Balrogs
+N:860:Sauron, the Sorcerer
+8
+brags, 'My power is beyond compare!'
+snorts, 'A mere mortal dares challenge my might?'
+says, 'Not another one! I just finished chewing on the last!'
+wonders aloud how many experience points you're worth.
+says, 'Hell shall claim your remains!'
+yawns at your pathetic efforts to kill him.
+says, 'Minions, slaughter this fool!'
+says, 'Set thine house in order, for thou shalt die...'
+2
+screams, 'This CAN'T be happening!'
+shouts, 'Kill me if you want, the Boss will get you!'
+
+N:853:Huan, Wolfhound of the Valar
+1
+asks, 'Have you seen Carcharoth? I seek him.'
+0
+
+N:861:Dark God, the Mighty Coder of Hell
+6
+says 'Hullo'.
+emits a low 'hmmmm'.
+screams 'I came from the Hell for YOU!'.
+laughs out loudly.
+mutters something about bugs.
+asks you about the new version.
+1
+screams 'ToME rules!'.
+
+N:928:Mathilde, the Science Student
+3
+waves.
+wishes you luck.
+skips along happily.
+1
+is surrounded by the purple aura of the RNG. Touch at your peril.
+
+N:934:Fangorn the Treebeard
+5
+says: 'The night stretches out on the Isengard!'
+says: 'Trolls are strong, Ents are STRONGER!'
+says: 'Hoom, hm, ah well.'
+says: 'Saruman will now stop using his axes on the trees...'
+says: 'I will crush all those burarum ... those orcs!'
+says: 'I am totally of the side of nobody since nobody is totally of my side...'
+0
+
+N:954:The Witch-King of Angmar
+2
+says, 'Do you not know Death when you see it?'
+says, 'Thou fool. No living man may hinder me!'
+0
+
+N:969:Princess
+4
+cries.
+screams, 'Help me!'.
+whines, 'I need your help, great hero!'.
+implores you to help her.
+1
+screams 'I didn't REALISE I was STANDING on the stairs, OKAY???'.
+
+N:1010:The Insane Player
+4
+screams, 'There can be only one!'
+makes a chattering noise with his teeth.
+screams, 'Morgoth is MY quarry! GO AWAY!!!'
+scrapes some slime off the wall and eats it, repeating 'grow mold!'
+2
+whimpers, 'You sure looked harmless.'
+sobs uncontrollably.
+
+N:1036:Sanctimonious-looking preacher
+5
+screams 'And the streets shall flow with the blood of the non-believers!'
+says: 'Eru is the One. There is no mistaking it, nor arguing with it.'
+says: 'I have never killed, but I have read many obituaries with pleasure.'
+hisses, 'Repent, evil-doer! Ere it is too late.'
+yells, 'And He will execute vengeance in anger and fury upon the heathen!'
+3
+says: 'Okay, I admit it. Religion is basically guilt, with different holidays.'
+whispers, 'Walk with those seeking Truth. Run from those who think they've found it.'
+says, 'The light of Valinor is with me.'
+
+N:1039:Improv, the mighty MoLD
+2
+screams 'Your code is ugly!'
+mutters something about bugs.
+1
+screams 'ToME rules!'. \ No newline at end of file
diff --git a/lib/mods/theme/file/news.txt b/lib/mods/theme/file/news.txt
new file mode 100644
index 00000000..67691fb4
--- /dev/null
+++ b/lib/mods/theme/file/news.txt
@@ -0,0 +1,23 @@
+#G #W ~ ~~~ ~~~ ( #G
+#G ======/ ===== #W ~~ ) ~~ ) #G === === ===
+#G / // / __ \ #W )~ #r,.#W~ ( (#G // || \\ //
+#G // | | | | #W _#r,-"####`-^ #W ) #G || || || ||==:
+#G || | | | | #W ,#D###########r`W='#D###W`.#W () #G || || || ||
+#G \\_// \ -- / #W ,#D#######################D###W:#r,=. #G || || || \\===
+#G \_/ ===== #W /.#D###W,".#D#####W,".#D###########r"#W##\
+#W ,-. _,-= /"._ ,-. #w ," #W `:' `:#D#####W[JW] ,. #G #R "Theme"
+#W," `," `=._ `" -#w; #G The #W\#D#####W;"' V \#W __,-. ,-=.
+#W / " `-. #w / #GTroubles of #W `" `-.#W__,-""._," "--," >-=-
+#W ,-"`. #w _' #G Middle Earth#w "._ #W` _/
+ _," #w"=.".
+ _," #ohttp://www.t-o-m-e.net #w`._,=-._ _,-.
+ _._ ,"._," #w"-." \,-.
+-" `-" #w`-
+ ToME maintained by darkgod Module by furiosity
+ #Bdarkgod@t-o-m-e.net #Bfuriosity@gmail.com
+#y One Ring to rule them all,
+#y One Ring to find them,
+#y One Ring to bring them all,
+#y And in the Darkness bind them
+#y In the Land of Mordor, where the Shadows lie.
+#B [J.R.R. Tolkien] \ No newline at end of file
diff --git a/lib/mods/theme/file/news2.txt b/lib/mods/theme/file/news2.txt
new file mode 100644
index 00000000..67691fb4
--- /dev/null
+++ b/lib/mods/theme/file/news2.txt
@@ -0,0 +1,23 @@
+#G #W ~ ~~~ ~~~ ( #G
+#G ======/ ===== #W ~~ ) ~~ ) #G === === ===
+#G / // / __ \ #W )~ #r,.#W~ ( (#G // || \\ //
+#G // | | | | #W _#r,-"####`-^ #W ) #G || || || ||==:
+#G || | | | | #W ,#D###########r`W='#D###W`.#W () #G || || || ||
+#G \\_// \ -- / #W ,#D#######################D###W:#r,=. #G || || || \\===
+#G \_/ ===== #W /.#D###W,".#D#####W,".#D###########r"#W##\
+#W ,-. _,-= /"._ ,-. #w ," #W `:' `:#D#####W[JW] ,. #G #R "Theme"
+#W," `," `=._ `" -#w; #G The #W\#D#####W;"' V \#W __,-. ,-=.
+#W / " `-. #w / #GTroubles of #W `" `-.#W__,-""._," "--," >-=-
+#W ,-"`. #w _' #G Middle Earth#w "._ #W` _/
+ _," #w"=.".
+ _," #ohttp://www.t-o-m-e.net #w`._,=-._ _,-.
+ _._ ,"._," #w"-." \,-.
+-" `-" #w`-
+ ToME maintained by darkgod Module by furiosity
+ #Bdarkgod@t-o-m-e.net #Bfuriosity@gmail.com
+#y One Ring to rule them all,
+#y One Ring to find them,
+#y One Ring to bring them all,
+#y And in the Darkness bind them
+#y In the Land of Mordor, where the Shadows lie.
+#B [J.R.R. Tolkien] \ No newline at end of file
diff --git a/lib/mods/theme/file/rart_f.txt b/lib/mods/theme/file/rart_f.txt
new file mode 100644
index 00000000..50a55b93
--- /dev/null
+++ b/lib/mods/theme/file/rart_f.txt
@@ -0,0 +1,86 @@
+85
+The Bag of Tricks
+Pandora's Box
+The Deck of Wild Magic
+The Box of Horrors
+The Thirteenth Eye of Sauron
+Saruman's Unfinished Works
+The Gem of Fire
+The Gem of Ice
+The Gem of Venom
+The Gem of Knowledge
+The Gem of Rage
+The Gem of Hate
+The Gem of Wisdom
+The Gem of Ghosts
+The Boulder of Entmoot
+The Voodoo Doll of Ghan-buri-ghan
+The Mirror of Alternate Dimensions
+The Ebon Cube of Darkness
+The Diamond Prism of Light
+The Gem of Chaos
+The Pentagram of Lore
+The Fourteenth Eye of Sauron
+The Space-Time Continuum
+The Shard of Pottery that is Not Junk
+Curunir's Alteration Manual
+Gandalf's Tome of Unconventional Warfare
+The Tome of Collected Strange Magic
+The Pendulum of Immortality
+The Black Candle of Ered Mithrin
+Smeagol's Lost Toy
+The Staff of the Ithryn Luin
+The Tome of Chaos
+The Dagger ``Thanc''
+The Tome of Elven Household Magic
+a Piece of the Mage Staff of Olorin
+a Parchment titled ``Magic for the Layman''
+The Shopping Bag of Gaffer Gamgee
+The Bag of Magic Toys
+The Skull of Ancient Wisdom
+The Box of Wizardry
+The Potion of Winning
+Radagast's Summoning Manual
+The Gem of Time
+The Lost Works of Melian
+The Crystal Ball of Godly Sights
+The Box of Many Wonders
+Carcharoth's Favourite Toy
+The Hat of Radagast
+The Bottomless Bottle
+a Parchment titled ``How to Win the Game''
+The Wand Construction Kit
+The Clay Tablets of Antiquity
+The Blood of Death
+Darkgod's Voodoo Doll of the Player
+The Skeleton of Nob
+The Magical Honey Jar
+a Parchment titled ``Concerning Hobbits''
+a Parchment titled ``On Beren and Luthien''
+The Fifteenth Eye of Sauron
+The Sixteenth Eye of Sauron
+The Seventeenth Eye of Sauron
+The Crystal Ball of The Witch-King of Angmar
+a Parchment titled ``Secrets of the Gnomish Wizards''
+The Medallion of Good Will
+The Immortal Skull of Telepathy
+The Ultimate Slime Mold
+Saruman's Big Book of Brutality
+The Shopping List of Barliman
+a Parchment titled ''There And Back Again''
+The Portable Soldier
+The Torch of Isengard
+One Rune to Rule them All
+a Parchment titled ''Famous Last Words''
+The Fire of Orthanc
+Radagast's Compendium of Strange Behaviour
+The Antique Acorn of Watchfulness
+The Horn of Ages
+Gandalf's Portable Pandemonium
+The Perfect Symbiote
+Curunir's Book of Impossible Occurences
+a Parchment titled ''Of the Kinslaying Wars''
+The Altruistic Assassin
+The Pipe of Buckland
+The True Totem of an Ostrich
+The Collapsible Crutch
diff --git a/lib/mods/theme/file/rart_s.txt b/lib/mods/theme/file/rart_s.txt
new file mode 100644
index 00000000..cc84631f
--- /dev/null
+++ b/lib/mods/theme/file/rart_s.txt
@@ -0,0 +1,87 @@
+85
+a Bag
+a Shiny, Black Box
+a Deck of Cards
+a Rusty, Slimy Box
+an Eyeball
+a Red Tome
+a Red Gem
+a Blue Gem
+a Green Gem
+a White Gem
+an Orange Gem
+a Black Gem
+a Gray Gem
+a Translucent Gem
+a Boulder
+a Voodoo Doll
+a Mirror
+a Black Cube
+a Prism
+a Violet Gem
+a Pentagram
+a Glass Eyeball
+something weird
+a Shard of Pottery
+a Green Tome
+a Black Tome
+a White Tome
+a Pendulum
+a Black Candle
+a Tiny Doll
+a Black Staff
+a Violet Tome
+a Shiny Dagger
+a Gray Tome
+a Broken Stick
+a Parchment
+a Big Bag
+a Small Bag
+a Broken Skull
+a Blue Box
+a Gray Bottle
+an Orange Tome
+a Shiny Gem
+an Ancient Gray Tome
+a Crystal Ball
+a Golden Box
+a Broken Bone
+a Soft Leather Hat
+a Broken Bottle
+an Arcane Parchment
+many Small Wooden Sticks
+some Clay Tablets
+a Smoky Vial
+a Doll
+a Human Skeleton
+a Clay Jar
+an Arcane Parchment
+a Strange Parchment
+a Large Eye
+a Small Eye
+a Decayed Eye
+a Large Crystal Ball
+a Mud-Stained Parchment
+a Medallion
+a Jewel-Encrusted Skull
+a Slimy Mold
+a Battered Book
+a Small Note
+an Old Parchment
+a Small Figurine
+a Torch
+a Rune
+a Singed Parchment
+a Sphere
+a Red Book
+an Acorn
+a Strange Horn
+a Music-Box
+a Blue Mold
+a Torn Book
+a Greasy Parchment
+a Blackened Figurine
+a Pipe
+an Avian Figurine
+a Crutch
+
diff --git a/lib/mods/theme/file/readme! b/lib/mods/theme/file/readme!
new file mode 100644
index 00000000..90b6bbf2
--- /dev/null
+++ b/lib/mods/theme/file/readme!
@@ -0,0 +1,36 @@
+Most files in this directory are use by the get_rnd_line function for various
+purposes in the game. They can be edited and customised by the user with any
+ascii text editor. If you add / remove lines you should modify the index (the
+first line) accordingly. If you set an invalid index or remove the buffer line
+weird messages and other things can appear, and you can crash the game. Please
+see sample.txt before you try modifying the files.
+The a_*.txt and w_*.txt are used when the game generates a random artifact.
+However, instead of picking a name from the appropriate file, the game may
+form a new name from syllables[].
+
+The files in this directory:
+
+A_CURSED TXT Possible names for randomly generated cursed armour artifacts
+A_HIGH TXT Possible names for randomly generated 'powerful' armour artifacts
+A_LOW TXT Possible names for randomly generated 'weak' armour artifacts
+A_MED TXT Possible names for randomly generated 'medium' armour artifacts
+BRAVADO TXT Possible lines for speaking uniques
+CHAINSWD TXT Possible noise for the Chainsword
+CRIME TXT Possible crimes that speaking uniques may have committed
+DEAD TXT The tombstone picture (the death screen)
+DEATH TXT Possible 'last words' when the player dies
+ELVISH TXT Syllables for the names of random artifacts
+ERROR TXT Possible random error messages (instead of "Type ? for help")
+MONDEATH TXT Possible 'last words' for speaking uniques
+MONFEAR TXT Possible lines for scared speaking uniques
+NEWS TXT The game intro screen
+README! You are reading this file right now
+RUMORS TXT Possible rumours (for scrolls or rumour and shopkeepers)
+SAMPLE TXT A sample file for the random line selecting function
+SILLY TXT Silly monster names for hallucination
+SMEAGOL TXT Smeagol lines
+SMEAGOLR TXT Smeagol fleeing
+W_CURSED TXT Possible names for randomly generated cursed weapon artifacts
+W_HIGH TXT Possible names for randomly generated 'powerful' weapon artifacts
+W_LOW TXT Possible names for randomly generated 'weak' weapon artifacts
+W_MED TXT Possible names for randomly generated 'medium' weapon artifacts
diff --git a/lib/mods/theme/file/rumors.txt b/lib/mods/theme/file/rumors.txt
new file mode 100644
index 00000000..2790cafd
--- /dev/null
+++ b/lib/mods/theme/file/rumors.txt
@@ -0,0 +1,201 @@
+199
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+They say that you can't trust rumors.
+You have no more Black Potions of Death.
+Losto Caradhras, sedho, hodo, nuitho i 'ruith!
+Ando Eldarinwa a lasta quettanya, Fenda Casarinwa!
+Andelu i ven.
+Le aphadar aen.
+Nai tiruvantel ar varyuvantel i Valar tielyanna nu vilya.
+Throw a Potion of Blindness at a monster and it cannot cast any spells!
+Gu kibum kelkum-ishi, burzum-ishi. Akha - gum-ishi ashi gurum.
+Not satisfied with the artifacts you find? Then create your own!
+They say that Sauron has forged an all-powerful Ring.
+A good item will not corrode.
+They say that Nibelungs live in dark caves.
+Some weapons that slay dragons can be very deadly against them...
+Finding the Phial of Galadriel at Level 1 is nothing to be proud of.
+There are Black Market stores hidden deep in the dungeon.
+What a pity, you cannot read it!
+You will encounter a dark, tall stranger...
+A Mithril mail will not rust.
+An Galvorn mail cannot be destroyed by the elements.
+A Rusty Chain Mail cannot rust any further.
+Nedin dagor hen ú-'erir ortheri. Natha daged dhaer!
+A Eruchin, u-dano i faelas a hyn an uben tanatha le faelas!
+Tangado a chadad!
+A Wand of Death is useless against monsters that are tougher than you.
+A Wand of Death is of little use against foes that are dead already.
+Try taking off your armor before fighting a Gelatinous Cube!
+They say that only one sword can score *CRITICAL* hits.
+This rumor is not true.
+If you can fall like a feather, you need not care about gravity.
+They say that you should rejoice if you find a scroll labeled ""!
+You don't always have to kill everything you meet!
+If you can't beat it, leave it alone!
+An umber hulk can be a confusing sight.
+There *is* a good use for Potions of Detonations, Ruination and Death...
+Watch your step!
+It's a bad idea to throw away a Longsword (4d5).
+It's a bad idea to wield a Longsword (4d5).
+It's useless to bash monsters with bows - but there's one notable exception...
+Actually, Slime Mold Juice is not completely useless.
+Faeg i-varv din na lanc a nu ranc!
+Ever tried inscribing your armor {erodeproof}?
+Using a Morningstar in the evening has no effect.
+Why are you wasting time reading fortunes?
+There is a horrible, ghastly fate awaiting you... at 2700'!
+You can get the Longsword 'Ringil' by doing the following:
+You can protect yourself from Great Wyrms of Power by doing the following:
+Togo hon dad! Dago hon!
+Za dashu snaku Zigur, Durbgu nazgshu, Durbgu dashshu!
+Forth Eorlingas!
+Try inscribing the name of the first monster killed by it in the weapon!
+I Aear can ven na mar.
+Aiya Earendil Elenion Ancalima!
+There's something bad about what you are carrying in your backpack...
+Thieves are more likely to appear if you are carrying a lot of money.
+Brand's sword, Werewindle, probably knows more than just one trick.
+They say that Scrolls of *Curse Weapon* can create powerful cursed artifacts.
+They say that the Chainsword makes monsters mad with its awful noise!
+They say that Ringil shines so brightly that it makes monsters angry.
+Orcs are mortally afraid of weapons that can slay them.
+There is a way to turn a Ring of Speed (-20) into a Ring of Speed (+20).
+There is no way to turn a Ring of Speed (-20) into a Ring of Speed (+20).
+FRODO LIVES!!!
+A Elbereth! Gilthoniel!
+Hail Earendil brightest of the Stars!
+You feel the Longsword (t) you are carrying in your backpack is special...
+If you start seeing red monsters, you have probably gained infravision.
+They say that the dungeon is deeper than the Abyss.
+When all else fails, read the instructions.
+No poison is immediately deadly.
+I have seen a Ring of Speed (+50) in the Black Market!
+Telepathy works like a two-way door.
+Elvish waybread might negate the effects of poison.
+Once uncursed, Calris will become a deadly weapon.
+Havo dad and pass the damn Lembas.
+You feel your luck is turning...
+If you thought Death swords were bad, wait until you meet Killer katanas!
+Overeating can be bad for your health if there are others nearby.
+Cave dwellers are accustomed to darkness and rarely enjoy bright light.
+A creature made of stone can be slain by a spell that turns stone to mud.
+It is often a good idea to throw items that you don't want to eat or drink.
+The faster you run the more food you will burn.
+Invisible monsters will often expose themselves if you drop items around you.
+They say that the key to killing tougher monsters is called "hit&run".
+The Sea calls us home.
+Wearing an Amulet of Doom will take you into the Dungeons of Doom.
+You can often wrest one last charge from an empty wand if you try hard enough.
+Wands may recharge themselves if you leave them on the floor long enough.
+There is more than one way to deal with a locked door.
+Afraid of your valuables getting stolen? Carry more junk!
+Their armour is weak at the neck... and beneath the arm.
+If you hear something smash into splinters, you had better watch out.
+They say that you had better leave Greater hell-beasts alone.
+Selling unidentified potions to shopkeepers might be safer than quaffing them.
+Always look out for trapdoors on "special" feeling levels!
+There is a way to max out your stats with Potions of Charisma & Nexus.
+Unique opponents will recover their health faster than other creatures.
+Prepare to fire!
+Show them no mercy, for you shall receive none.
+Iorhael, lasto beth nin, tolo dan nan galad!
+A Potion of Detonations is also known as nitroglycerin.
+They cannot win this fight. They are all going to die!
+There is a trap on this level!
+A weapon of Undead Slaying has all you need to kill a ghost.
+A weapon of Dragon Slaying may give you resistance to a dragon's breath attack.
+There-is-no life in-the-cold, in-the-dark. Here - in-the-void only death.
+All that is shall come to an end - a dark day dawns for the gods.
+The One Ring is powerful, but will eventually destroy its owner.
+May your blood-stained horn fall upon the enemy-heads!
+May the Valar protect you on your path under the sky.
+Wands of Heal Monster are useful! Hint: ball spell, @....moo(o)ooo
+Guaranteed heal self - scenario: o'@, type c4c4c4c4
+If it can't see you, it can't hurt you!
+If it can't see you, you might still be able to hurt it...
+Nadath na i moe cerich.
+No animal is interested in sex if it is mortally scared.
+There is much yet you have to do.
+You are being followed.
+There is a plenty of Longswords around 1000'.
+The Road is very dangerous.
+Sleep Caradhras, be still, lie still, hold your wrath!
+The Shadow does not hold sway yet.
+There are often stairways in graveyards: bad people are carried to hell...
+Only a god of Thunder could ride a lightning bolt!
+The world is changed; I can feel it in the water...
+I can feel it in the earth, I can smell it in the air.
+They say the Valar have returned to walk upon Middle-earth.
+Weapons of Flame will light your way.
+Nauthannen i ned ol reniannen.
+Gandalf was here.
+They say that the gods get angry if you pray too much.
+For any remedy there is a misery.
+Poison will kill you slowly.
+Didn't you forget to pay?
+Death is just life's way of telling you you've been fired.
+They say that nobody can defeat his own ghost.
+A greedy genocide can be a fatal mistake, especially if you are low on hits.
+Ignore the previous rumour.
+There are scrolls that can be read only by mages.
+Some undead opponents will come back if defeated, more powerful than before!
+The answer is 42.
+I thought I had strayed into a dream.
+One level further down somebody is getting killed, right now.
+Gate of Elves listen to my word, Threshold of Dwarves!
+Bashing a creature may sometimes stun it.
+Nin o Chithaeglir lasto beth daer; rimmo nin Bruinen dan in Ulaer!
+One Ring to rule them all, One Ring to find them.
+One Ring to bring them all and in the darkness bind them.
+Three Rings for the Elven-kings under the sky...
+Never carry a Potion of Detonations if there is a fire trap nearby!
+Laugh to scorn the power of man, for none of woman born shall harm thee!
+All hail thee that shalt be king hereafter!
+You are fated to never die by the hand of a mortal being.
+The Hru hits you. The Hru hits you. The Hru hits you. The Hru hits you.
+-more-
+Appearance is only the frosting, not the cake!
+A feeling of Death flows through your body.
+Violence is no solution.
+Boots of Speed (+50) are no myth!
+You will need to Restore the Constitution if the Anarchists strike.
+Drain you of your sanity: Face the Thing That Should Not Be!
+Since by curse it came to me, accursed be this Ring!
+Each shall itch to possess the Ring, but none in it shall find pleasure!
+I know whatever was; whatever is, whatever shall be.
+You are fated to find something special on Level 99.
+Pudpadnoy Tooboothokoot is possessed by a demon known only as "It".
+They say that the One Ring has a very special curse.
+They say that alcohol is bad for your health.
+What if you DON'T give a name to the artifact you create..?
+They say that ancient battlefields are often haunted.
+Beware of pits that fill the whole level!
+Liar! I have not the gold!
+They say that the true name of wall monsters is 177.
+Never mind the Phial of Galadriel - the Phial of the Gods is better.
+A Ring of Speed? Phooey! Try looking for a Ring of *Speed*!
+Noro lim, Asfaloth, noro lim!
+If you hear heavy steps - watch out!
+A visit to the Zoo is educational: you meet many strange animals.
+What happens if you wear a Ring of Extra Ring Fingers (-2) {cursed}?
+I amar prestar aen, han mathon ne nen han mathon ne chae a han noston ned 'wilith.
+If I cancel tomorrow the undead will thank me today.
+Hellfire will burn your soul...
+You are fated to die on level 1.
+Why doesn't Detect Monsters show invisible monsters? 'Cos you can't see 'em!
+You are fated to find the Long Sword 'Ringil' on level 5.
+There's slime all over the walls.
+*** LOW HITPOINT WARNING! ***
+You cruelly stab the helpless, sleeping Software bug!
+Tangado haid! Leithio i philinn!
+It looked harmless.
+Spirit, hatch that painted spirit of the lamb sparrow.
+Gone insane from the pain that sure they know: for who the flange sound?
+'Ere, 'oo are you?
+Not to be never, never not to see, so as to dub the thee unforgiven.
+A Morphic Oil of Abomination will turn you into Morgoth himself.
+A Morphic Oil of Abomination will kill you.
+You are fated to win this game.
+The eternal death of eons of the foreigner of the lie can die not absolutely.
+They say that the dark mists of Morgoth can both bestow and remove the curse.
diff --git a/lib/mods/theme/file/sample.txt b/lib/mods/theme/file/sample.txt
new file mode 100644
index 00000000..5ff826f7
--- /dev/null
+++ b/lib/mods/theme/file/sample.txt
@@ -0,0 +1,5 @@
+3
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+line # 1
+line # 2
+line # 3
diff --git a/lib/mods/theme/file/sfail.txt b/lib/mods/theme/file/sfail.txt
new file mode 100644
index 00000000..ca4d9cb5
--- /dev/null
+++ b/lib/mods/theme/file/sfail.txt
@@ -0,0 +1,34 @@
+32
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+rose petals
+dirty straw
+rusty metal cutlery
+small, furry animals
+assorted toy jewelry
+visions of merry, dancing gnomes
+old and dusty accounting records
+moldy crusts of bread
+grass
+wet mud
+smelly bilge water
+clean linens
+scrap metal
+rotting wood
+leaves
+small insects
+rainwater
+flowers
+perfumed water
+overcooked sausage
+twigs
+pine needles
+hard leather
+small bones
+feathers
+crumbling manuscripts
+fresh air
+stale, smelly air
+dust
+clay
+earth
+wood shavings
diff --git a/lib/mods/theme/file/silly.txt b/lib/mods/theme/file/silly.txt
new file mode 100644
index 00000000..c5eca172
--- /dev/null
+++ b/lib/mods/theme/file/silly.txt
@@ -0,0 +1,301 @@
+299
+******************BUFFER LINE -- DO NOT REMOVE!*****************************
+Borg
+little Morgoth
+Sauron
+Ur-Vile
+Wizard of Yendor
+Smurf
+Moose
+Osama bin Laden
+Space Invader
+Agent
+Morpheus
+Hydralisk
+Infested Terran
+Asha'man
+Aes Sedai
+little lamb
+IRA Terrorist
+Nazi
+Klingon
+Tea-kettle
+Vorlon
+Giant flea
+Killer penguin
+Tractor trailer
+Giant were-penguin
+Zergling
+Dark Templar
+Dragon Reborn
+George Bush
+Saddam Hussein
+Death Orb
+Hru
+Greater Titan
+Lesser Titan
+Deodorant
+Minion of DarkGod, the Mighty Coder of Hell
+Mouth of Sauron
+Devil
+Anti-Christ
+Dark Avenger
+Evil Computer
+Evil Genius
+Satan
+Sea Folk Windfinder
+Fire Hydrant
+Multi-hued elephant
+Martian
+Seanchan
+Eminem
+Madonna
+Dementor
+Insurance salesman
+Moldoux, the Defenceless Mold
+Great Wyrm of Power
+Great Wyrm of Balance
+Typewriter
+Great Wyrm of Law
+Great Crystal Drake
+Munchkin
+Mad Scientist
+Great Wyrm of Chaos
+Great Bile Wyrm
+Great Hell Wyrm
+Great Wyrm of Nothing
+Great Wyrm of Toxic Waste
+Batman
+Damane
+Incredible Hulk
+Amazing Spider-Man
+Man in Black
+Matrix agent
+Secret agent
+Spy
+Harry Potter
+Vacuum cleaner
+Lawnmower
+Star-Spawn of Cthulhu
+Killer Banana
+Fear Mold
+Oracle
+Trinity
+Undead beholder
+Beholder Hive-mother
+Gauth
+Dumbledore
+Voldemort
+Maia
+Vala
+Elf
+Human
+Gnome
+Half-Troll
+Pope
+Skywalker cronie
+Jedi knight
+Dark Jedi
+Sith Lord
+Vulcan
+Existentialist philosopher
+Midichlorian
+Scientologist
+Jehovah's witness
+Skinhead
+Feanorian
+Umbarite
+Druj
+Yogi
+Karateka
+President
+King
+Prime Minister
+Trashman
+Teacher
+Cheshire Cat
+Mad Hatter
+March Hare
+Voodoo doll
+Rag doll
+Scarecrow
+Stormcrow
+Stone idol
+Hacker
+Samurai
+Dragkhar
+Phantom of the Opera
+Stone Dog
+Warrior of the Dawn
+Maiden of the Spear
+t-o-m-e.net forum poster
+Chimpanzee
+Messenger of Eru
+Grohlm
+G. I. Joe
+Aiel Wise One
+Alley cat
+Keanuholic
+Battlemage
+Saboteur
+Shadowkiller
+Cyborg
+Lemming
+Green Goblin
+Robocop
+Alien
+Lurker
+Iron Fist
+Trapper
+Amulet of Yendor
+Xeroc
+Catwoman
+Christian
+Muslim
+Extremist
+Forsaken
+Carnivore
+Xenu
+King of Arnor
+False prophet
+Emperor
+Rider of Rohan
+Draco Malfoy
+Cheeky bastard
+Ghost of Frodo Baggins
+Red Rose Knight
+Unholy cow
+Demonic Quylthulg
+Draconic Quylthulg
+Rotting Quylthulg
+Greater Demonic Quylthulg
+Lizard King
+Greater Draconic Quylthulg
+Greater Rotting Quylthulg
+Wookie
+Pit Fiend
+Muad' Dib
+Ent
+Huorn
+Werepotato
+Nycadaemon
+Alien queen
+Greater Balrog
+Lesser Balrog
+Doppleganger
+Evil dead
+Death incarnate
+Greater Kraken
+Death mold
+Rhinoceros
+Leviathan
+Software Bug
+Blob
+Cyberdemon
+Body snatcher
+Ghost of your past
+Biology professor
+Frankenstein
+Brain that would not die
+Breather
+Neekerbreeker
+Creature from the Black Lagoon
+Loch Ness monster
+Creeping death
+Creeping unknown
+Caligula
+Man of Haleth
+Budweiser frog
+Bride of Frankenstein
+Terminator
+T-800
+Purple space chicken
+Simpsons character
+UN weapons inspector
+Green giant
+Noldorin mercenary
+Squint-eyed rogue
+Egomaniac
+Russian mafia
+Godfather
+UFO
+Superman
+Hound of the Baskervilles
+Evil wizard
+Streetcar
+Karaoke machine
+Arch-vile
+Pain elemental
+Lesser kraken
+Murk dweller
+Killer tomato
+Chaos beastman
+Random Number Generator
+RNG
+Yakuza
+Wolverine
+Hunchback of Notre Dame
+Lovecraftian nightmare
+Shakespeare's imitator
+Morlock
+King Kong
+Protoss probe
+Shai'tan
+Baba Yaga
+Saucepan
+Ethereal dragon
+Pseudo-dragon
+Floating brain of Hitler
+Marshmallow Man
+High-elven ranger
+Swamp Thing
+Thing
+Teenage Frankenstein
+Teenage Werewolf
+Cellular automaton
+Strawman
+Logic gate
+Xenophobe
+Unspeakable horror
+Unknown terror
+Spirit of Roger Wilco
+Long sword 'Ringil'
+E.T.
+Zoolander
+Intel(R) Pentium processor
+Pac-Man
+Gangster
+Waterboy
+Long sword 'Mormegil'
+Wizard of Oz
+Battlecruiser
+Ultralisk
+Believer
+Heretic
+Loser
+Moron
+Libido
+Super-ego
+Imbecile
+Nebuchadnezzar
+Tomb raider
+Zelda
+Super Mario
+Hammer of Thor
+Wrath of the gods
+Betrayer of Turin
+Traitor of Gondolin
+Balrog
+Lesser Maia
+Greater Maia
+Cheerleader
+Model T-1000 Terminator
+Terminatrix
+Dragonlance
+Ancient multi-hued dragon
+Hillside strangler
+Texas chainsaw
+Pampers commercial
+Marilith
+White Balrog
+Bus driver
diff --git a/lib/mods/theme/file/smeagol.txt b/lib/mods/theme/file/smeagol.txt
new file mode 100644
index 00000000..22cb7038
--- /dev/null
+++ b/lib/mods/theme/file/smeagol.txt
@@ -0,0 +1,29 @@
+27
+******** BUFFER LINE *******************
+sniggers.
+grovels.
+picks his nose.
+pines for his precious.
+searches his pockets.
+eats some slimy creatures.
+mutters: 'My preciouss, where iss my preciouss?'
+shouts: 'No Master Hobbitsisisisis!'
+cries: 'The ring was ours for agesisisisis!'
+says: 'Smeagol sneaking! ME! Shneeeakingsisis!'
+screams: 'Nassty Hobbitsisisisis...'
+says: 'Come on, quickly, follow Smeagol!'
+coughs: 'Gollum! Gollum!'
+says: 'Every way is guarded, silly foolsis!'
+says: 'Nassty Bagginsis, stole my precious.'
+says: 'She will kill them, oh yes she will preciouss.'
+says: 'Does it guess easy? It must have a competition with us, preciouss!'
+hisses: 'What has it got in its pocketses?'
+whimpers: 'We've lost it, we have.'
+says: 'No food, no rest; Smeagol a SNEAK!'
+says: 'What a dainty little dish you will be for her.'
+says: 'Hobbitses always SOOOO polite.'
+screams: 'Stop, Thief!'
+says: 'Makeses him drop his weapon precious.'
+grovels: 'He has only four fingers on the black hand.'
+growls: 'Not nice Hobbits, not sensible!'
+says: 'If you findesis it, give it us back.'
diff --git a/lib/mods/theme/file/smeagolr.txt b/lib/mods/theme/file/smeagolr.txt
new file mode 100644
index 00000000..cc13c96f
--- /dev/null
+++ b/lib/mods/theme/file/smeagolr.txt
@@ -0,0 +1,5 @@
+3
+******** BUFFER LINE **************
+says: 'Don't hurt us, mastersisis.'
+says: 'Poor Smeagol, poor Smeagol.'
+says: 'No AH! Don't hurtsis us.'
diff --git a/lib/mods/theme/file/speakpet.txt b/lib/mods/theme/file/speakpet.txt
new file mode 100644
index 00000000..c6707e45
--- /dev/null
+++ b/lib/mods/theme/file/speakpet.txt
@@ -0,0 +1,53 @@
+51
+******** BUFFER LINE *********************************** DO NOT REMOVE *******
+admonishes: 'You need not be frightened like a rabbit.'
+says: 'Nice boots.'
+says: 'Isn't it dark down here?'
+says: 'I think I saw something move...'
+says: 'I really think I saw something move this time...'
+says: 'Phew, what's that smell?'
+says: 'There's slime all over the walls.'
+wonders: 'What is all this uproar in the forest tonight?'
+says: 'Hullo! You came pretty quick - where were you hiding?'
+says: 'Havo dad, and pass the damn Lembas.'
+says: 'Go on, go on! I will do the stinging!'
+says: 'The Eagles! The Eagles! The Eagles are coming!'
+says: 'If ever you are passing my way, do not wait to knock.'
+wonders aloud: 'Have I read about you in the ToME forums?'
+sings: 'Merry is May-time, and merry our meeting.'
+says: 'Hey, where did you find that thing?'
+muses: 'By the light of the Trees of Valinor, what IS that thing?'
+yells: 'After Morgoth to the ends of the earth!'
+says: 'Oops. I have slime mold on my wisp of vapor.'
+says: 'Show them no mercy, for you shall receive none.'
+says: 'I love troll. Eat once, stay full for a week.'
+says: 'Your sword sure is shiny.'
+says: 'Hey! WATCH IT! You almost hit me.'
+says: 'Their armour is weak at the neck... and beneath the arm.'
+says: 'Keep that demon blade away from me.'
+lectures: 'Gil-galad was an Elven king.'
+lectures: 'Earendil was a mariner that tarried in Arvernien.'
+says: 'The One Ring. That sure is a silly name...'
+says: 'Meddle not in the affairs of Wizards.'
+says: 'If Lokkak asks, I am not here.'
+sings: 'Together we will take the road beneath the bitter rain.'
+admonishes: 'What is with all this Dwarvish racket?'
+says: 'This is one for the Day in the Life archives!'
+recites: 'Seven stars and seven stones, and one white tree.'
+recites: 'All that is gold does not glitter.'
+says: 'Very fancy. Bet you cannot do it again.'
+says: '10AU says I can behead that snaga!'
+recites: 'Not all those who wander are lost.'
+sings: 'With a ping and a pong the fiddle-strings broke!'
+says: 'Were you looking for these?'
+sings: '...the cow jumped over the Moon'
+sings: 'Now let the fun begin! Let us sing together!'
+says: 'Kill, kill, kill. Let us play chess.'
+hums a song peppered with derry-dols and merry-dols.
+says: 'ToME just switched to an HMO.'
+says: 'Do you like my outfit?'
+says: 'Your shoelaces are untied.'
+asks: 'What did you go near them for?'
+says: 'You should post about that on the ToME forums.'
+says: 'A wand of rockets. Yeah, that's the ticket.'
+says: 'Where did everybody go?'
diff --git a/lib/mods/theme/file/timefun.txt b/lib/mods/theme/file/timefun.txt
new file mode 100644
index 00000000..ca3f642f
--- /dev/null
+++ b/lib/mods/theme/file/timefun.txt
@@ -0,0 +1,92 @@
+S:0000
+E:0059
+D:It's the witching hour!
+
+S:0100
+E:0259
+D:There may be Vampires around!
+
+S:0200
+E:0459
+D:Only ToME players are up now!
+
+S:0100
+E:0459
+D:It's really *very* late!
+
+S:0500
+E:0558
+D:Aren't you sleepy yet?
+
+S:0559
+E:0559
+D:It doesn't matter what you found!
+
+S:0600
+E:0759
+D:The sun is up. Time to have fun!
+
+S:0601
+E:0800
+D:Are you having fun yet?
+
+S:0800
+E:0905
+D:@$#$@$!%@$#%$@&$^#%@$!^#&#*
+
+S:0800
+E:1059
+D:You feel there is something special about this level.
+
+S:1100
+E:1159
+D:You see a maze of twisty passages, all alike.
+
+S:1155
+E:1200
+D:Are you having fun yet?
+
+S:1159
+E:1200
+D:This fortune is broken!
+
+S:1200
+E:1205
+D:This fortune is still broken!
+
+S:1200
+E:1359
+D:Uh oh, now you've done it!
+
+S:1400
+E:1729
+D:What did you do with the Phial?
+
+S:1730
+E:1744
+D:You need your chocolate vitamin!
+
+S:1745
+E:1759
+D:Tornado Warning!
+
+S:1759
+E:1800
+D:Night is coming. Danger! Danger!
+
+S:1700
+E:1859
+D:Take a Vampire out for dinner!
+
+S:2100
+E:2159
+D:Warp Factor Nine. Now!
+
+S:2200
+E:2359
+D:PARTY!
+
+S:2359
+E:2359
+D:It's almost the witching hour!
+
diff --git a/lib/mods/theme/file/timenorm.txt b/lib/mods/theme/file/timenorm.txt
new file mode 100644
index 00000000..611da496
--- /dev/null
+++ b/lib/mods/theme/file/timenorm.txt
@@ -0,0 +1,83 @@
+S:0000
+E:0000
+D:It is midnight.
+
+S:0001
+E:0200
+D:It is deep night.
+
+S:0300
+E:0400
+D:It is early morning, but still dark.
+
+S:0500
+E:0544
+D:It will be day soon.
+
+S:0545
+E:0559
+D:The sun is rising.
+
+S:0600
+E:0614
+D:The sun has risen.
+
+S:0615
+E:0659
+D:Morning has broken.
+
+S:0700
+E:0859
+D:It is early morning.
+
+S:0900
+E:0959
+D:It is midmorning.
+
+S:1000
+E:1154
+D:It is late morning.
+
+S:1155
+E:1159
+D:It is almost noon.
+
+S:1200
+E:1200
+D:It is noon.
+
+S:1201
+E:1459
+D:It is early afternoon.
+
+S:1500
+E:1559
+D:It is midafternoon.
+
+S:1600
+E:1659
+D:It is late afternoon.
+
+S:1700
+E:1729
+D:It will be night soon.
+
+S:1730
+E:1759
+D:The sun is setting.
+
+S:1800
+E:1859
+D:The night has begun.
+
+S:1900
+E:2059
+D:It is early night.
+
+S:2100
+E:2358
+D:It is late night.
+
+S:2359
+E:2358
+D:It is almost midnight.
diff --git a/lib/mods/theme/help/ability.txt b/lib/mods/theme/help/ability.txt
new file mode 100644
index 00000000..175d6745
--- /dev/null
+++ b/lib/mods/theme/help/ability.txt
@@ -0,0 +1,115 @@
+|||||oy
+~~~~~01|Abilities
+#####R=== ToME Abilities ===
+As well as spending your skill points on *****skills.txt*0[skills], you can also choose
+to spend them on abilities.
+Abilities are bought once, and then have a permanent effect. You cannot
+continue adding skill points into them, (which you can with *****skills.txt*0[skills]) as there
+would be no way that these abilities can improve. They are a "one-off
+purchase".
+As a consequence of this, they are often quite powerful abilities and can
+cost quite a few skill points to buy.
+Most abilities have a prerequisite skill or stat level which you must reach
+before being able to buy.
+
+For instance, you can invest in the *****ability.txt*03[Tree walking] ability. This will allow
+you to pass through dense undergrowth. In order to purchase this skill you must
+first have your *****skills.txt*34[Nature] skill at 20 or greater, and then it will cost you 7
+skill points to buy. This means you have to "save up" enough skill points in
+order to be able to afford this ability.
+
+You can access the Ability screen by pressing 'N' (in the original keyset, or
+'\N' in the roguelike keyset). Scroll up and down the abilities and then
+navigate right to buy selected ability.
+
+Adapt your character with skills and abilities in order to make it unique,
+playable, and maybe even powerful enough to win the game!
+
+Here follows a list of all the available abilities:
+
+*****ability.txt*02[Spread blows] *****ability.txt*03[Tree walking]
+*****ability.txt*04[Perfect casting] *****ability.txt*05[Extra Max Blow(1)]
+*****ability.txt*06[Extra Max Blow(2)] *****ability.txt*07[Ammo creation]
+*****ability.txt*08[Touch of death] *****ability.txt*09[Artifact Creation]
+*****ability.txt*10[Far reaching attack] *****ability.txt*11[Trapping]
+*****ability.txt*12[Undead Form]
+
+~~~~~02|Abilities|Spread blows
+[[[[[BSpread blows]
+If a monster dies to your attack but you still have blows left
+you won't lose the full turn, allowing you to attack some other
+monster in the same turn.
+#####UPrereq: Weaponmastery skill@30, Dex@17
+#####rCost: 5
+Warriors (of all types) gain this ability for free at character level 25.
+~~~~~03|Abilities|Tree walking
+[[[[[BTree walking]
+Allows you to walk in dense forest.
+#####UPrereq: Nature skill@20
+#####rCost: 7
+Ents and Wood Elves are born with this ability.
+~~~~~04|Abilities|Perfect casting
+[[[[[BPerfect casting]
+Allows you to reach 0% failure rate on spells.
+#####UPrereq: Magic skill@35
+#####rCost: 6
+Priests and Mages (of all types) are born with this ability.
+~~~~~05|Abilities|Extra Max Blow 1
+[[[[[BExtra Max Blow(1)]
+Increases your max possible blows number by 1.
+#####UPrereq: Combat skill@10
+#####rCost: 7
+Warriors (of all types) and Paladins are born with this ability.
+Rogues (of all types) gain this ability for free at character level 10.
+~~~~~06|Abilities|Extra Max Blow 2
+[[[[[BExtra Max Blow(2)]
+Increases your max possible blows number by 1 (Cumulative with
+Extra Max Blow(1)).
+#####UPrereq: Combat skill@20, Extra Max Blow(1)
+#####rCost: 7
+Warriors (of all types) are born with this ability.
+~~~~~07|Abilities|Ammo creation
+[[[[[BAmmo creation]
+Allows you to create shots, arrows and bolts from various materials.
+You can always make shots.
+At Archery level 10 you can start making arrows.
+At Archery level 20 you can start making bolts.
+#####UPrereq: Archery skill@10
+#####rCost: 8
+Archers (of all types) gain this ability for free at character level 2.
+~~~~~08|Abilities|Touch of death
+[[[[[BTouch of death]
+Your melee blows can insta-kill, but you only receive 1/3 of the experience
+for that kill.
+You must activate this from your 'm' menu.
+#####UPrereq: Necromancy skill@50, Combat skill@40, DEX@30, STR@30
+#####rCost: 15
+~~~~~09|Abilities|Artifact Creation
+[[[[[BArtifact Creation]
+In combination with a high alchemy skill this ability will let you
+design your very own artifacts.
+Prereq: Alchemy@40, INT@35, WIS@35
+#####rCost: 70
+~~~~~10|Abilities|Far reaching attack
+[[[[[BFar reaching attack]
+You can attack an enemy one square far using a long polearm.
+At high levels of Polearm-mastery skill, you can even hit two enemies at once.
+#####UPrereq: Combat@15, Polearm-mastery@15
+#####rCost: 10
+~~~~~11|Abilities|Trapping
+[[[[[BTrapping]
+Enables you to set traps which harm monsters.
+#####UPrereq: Disarming@15
+#####rCost: 10
+Rogues are born with this ability.
+~~~~~12|Abilities|Undead Form
+[[[[[BUndead Form]
+With this ability your character receives a small amount of Death Points (DP)
+when they 'die'. Every normal (+0 speed) turn, one DP
+is lost; you can regain it like you would do with Hit Points.
+If you manage to kill enough monsters before your DP goes below 0, your
+character is brought back to life.
+#####UPrereq: Necromancy@30, INT@25
+#####rCost: 15
+Necromancers gain this ability for free at character level 25.
+
diff --git a/lib/mods/theme/help/advanced.hlp b/lib/mods/theme/help/advanced.hlp
new file mode 100644
index 00000000..3f6fe4bd
--- /dev/null
+++ b/lib/mods/theme/help/advanced.hlp
@@ -0,0 +1,15 @@
+|||||oy
+#####RWelcome to the ToME Advanced Help System.
+#####R=============================================
+
+Please choose one of the following help files:
+
+ *****/aoption.txt*0[(a) Options]
+ *****/bmacrofaq.txt*0[(b) Macros]
+ *****/cautomat.txt*0[(c) Automatizer help]
+ (d) Lua scripting help - coming soon
+ *****/edebug.txt*0[(e) Debug commands]
+ *****/fversion.txt*0[(f) Version information] A history of ToME's roots
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
+
diff --git a/lib/mods/theme/help/attack.txt b/lib/mods/theme/help/attack.txt
new file mode 100644
index 00000000..c72e9725
--- /dev/null
+++ b/lib/mods/theme/help/attack.txt
@@ -0,0 +1,148 @@
+|||||oy
+~~~~~01|Attacking Monsters
+~~~~~02|Monsters|Attacking
+#####R=== Attacking and Being Attacked ===
+
+{{{{{<p>}Attacking is simple in ToME; attempting to move over a creature
+attacks it. It is also possible to attack from a distance by firing a missile
+or by magical means (wand, rod, spell, etc). Creatures attack in the same way.
+This means that if you do not wish to melee with a creature, it is wise to keep
+distant from it. This strategy is not perfect -- some monsters, such as
+dragons, have a way to attack from a distance.
+
+Some creatures, such as Ghosts, have the ability to pass through walls.
+To attack creatures (that you can see) who are currently in a wall,
+attempt to move over it (even if you cannot pass through walls, the
+attack will still happen). Monsters will take less damage from attacks
+while they are in walls. Also, if you cannot see the monster (e.g. if you
+are blind, or it is invisible and you do not have see invisible), this
+will not work: you'll have to try to tunnel. Most spells and magic devices
+cannot target monsters in walls. In situations like this, it is usually wise to
+lure the monster out of the wall before attacking it.
+
+Melee attacks are handled as such:
+#####G To-hit:
+ Your strength grants a bonus or penalty to-hit
+ Your class might grant a bonus or penalty to-hit
+ Your skill with specific kinds of weapons gives a bonus
+ to-hit (e.g.: Swordmastery gives a to-hit bonus
+ when using swords)
+ Enchantments on your weapon grant a bonus or penalty to-hit
+ Certain rings (accuracy, slaying) may also grants a bonus
+ or penalty to-hit
+ Your Tactic setting may give bonuses o penalties to-hit
+ (to change it, press 'C' and then 't' or 'T')
+ Other temporary effects (berserk, etc) might affect your
+ chance to hit
+ The armor rating of the monster you're attacking makes a
+ big difference
+
+#####G Blows:
+ Your strength and dexterity affect how many blows you get
+ Your class and level might affect how many blows you get
+ The weight of the weapon very likely will affect how many
+ blows you get
+ Certain skills (e.g. Swordmastery) may affect how many blows
+ you get with particular weapons
+ Enchantments on your weapon might also affect how many
+ blows you get (this is rare)
+ Certain very rare rings (of attacks) may also affect how
+ many blows you get
+
+#####G Damage:
+ The base damage of your weapon is rolled
+ Strength grants a bonus or penalty
+ Your class might grant a bonus or penalty
+ Combat and Weaponmastery skills increase your melee damage
+ Ranged masteries increase the damage multiplier of slings,
+ bows, crossbows or boomerangs(see below)
+ Enchantments on your weapon might also grant a bonus or
+ penalty
+ Your Tactic setting may give bonuses o penalties to damage
+ (to change it, press 'C' and then 't'or'T')
+ Temporary effects also might grant a bonus or penalty
+
+So, each blow you are entitled to is checked for a hit. If this is the case,
+the damage is then applied to the monster. Note that unless you have some
+barehanded combat training or are possessing a monster, melee without a weapon
+will result in a single blow that does base damage of 1d1. This might, however,
+be useful in attacking certain rare monsters that destroy weapons.
+
+Combat with a bow/sling is similar, except ammo is used (which will eventually
+run out, requiring replacement). Bows don't have a base damage rating (ammo
+does), instead having a damage multiplier. Bows can, however, be enchanted,
+and enchantment on bows and arrows is cumulative (meaning that well-enchanted
+bows and arrows can be one of the more effective weapons in the game. They
+do, however, tend to be very expensive, as non-artifact arrows frequently break
+after being fired).
+Using ammo without the appropriate bow generally has poor results.
+~~~~~03|Armor
+#####R=== Armor ===
+
+As the armor class of a monster greatly affects how hard it is for it
+to be hit, your armor class affects how hard it is for it to hit you.
+A high armor rating will make it much easier to survive deep in the dungeon.
+For a warrior style class (Unbelievers, Fighters, Archers, etc), it is
+generally wise to wear as much and as powerful armor as possible (subject
+to weight limitations, of course). Spellcasting classes, however, have
+limits on how much armor they can wear before it disrupts their motion
+and makes it hard for them to cast spells properly. For many of these classes,
+gloves are especially bad for spellcasting. Monks and Rogues skilled
+at dodging will often find heavy armor cumbersome, too.
+Armor has a base rating and an enchantment rating. The base rating is constant
+for the type of armor (e.g. paper armor always has a base rating of 4), and
+the enchantment depends on the item. There are also ways to further enchant
+armor you have. Certain very powerful enchantments grant resistances to
+specific forms of magical attacks.
+~~~~~04|Attacking Monsters|Resistances
+~~~~~05|Armor|Resistances
+#####R=== Resistances and typed attacks===
+Many kinds of monsters, traps, and other effects do damage that has a type.
+Types can have side effects in addition to the raw damage they deal. Certain
+enchanted items can grant resistances, reducing the raw damage and possibly
+reducing or eliminating the side effects. Some monsters also have resistances,
+so watching the messages when attacking a monster can often reveal that a
+particular attack is ineffective.
+~~~~~06|Attacking Monsters|Damage Effect type (Fire/cold/nether etc)
+~~~~~09|Damage Effects
+#####GLow attacks
+ Fire - Destroys weapons, armor, scrolls, and staves. Reduces strength.
+ Cold - Shatters potions.
+ Elec - Reduces dexterity.
+ Acid - Reduces bonuses on equipped armor, reduces charisma
+
+#####GMiddle attacks
+ Poison - Player becomes poisoned
+ Light - Blinds player, perma-lights area
+ Dark - Blinds player, darkens area
+ Confusion - Confuses player
+
+#####GHigh attacks
+ Nether - Drains experience
+ Nexus - Scrambles statistics, teleports player randomly
+ Disenchantment - Reduces bonuses on equipped items
+ Chaos - Confuses, drains life, causes hallucination, and more
+ Sound - Shatters potions
+ Shards - Cuts player
+
+#####GUnresistable attacks
+ Water - Stuns player
+ Ice - Stuns player, shatters potions
+ Plasma - Stuns player, otherwise same as fire attacks
+ Force - Pushes player a few squares back
+ Inertia - Slows player
+ Gravity - Slows and teleports player a few squares
+ Disintegration - Destroys items on ground, destroys walls
+ Mana - Destroys items on ground
+~~~~~07|Monsters|Monster Memory
+#####R=== Monster Memory ===
+
+The thousands of different creatures in ToME have many different
+characteristics, including spells, resistances, health, attacks, and speed.
+The information you have learned about each monster from your encounters
+with them is recorded in the monster memory (accessed with '/' or by 'l'ooking
+at a monster). It is possible to eventually learn all the characteristics
+of any given monster by interacting with them enough, but this is not always
+desirable (hanging around great hell wyrms, for example, can be hazardous
+to one's health). Certain spells may help you learn faster, as well as
+research centres in town.
diff --git a/lib/mods/theme/help/automat.txt b/lib/mods/theme/help/automat.txt
new file mode 100644
index 00000000..bf6478f8
--- /dev/null
+++ b/lib/mods/theme/help/automat.txt
@@ -0,0 +1,504 @@
+|||||oy
+~~~~~01|Automatizer
+~~~~~02|Auto pick-up
+~~~~~03|Auto destroy
+~~~~~04|Autosquelch
+#####R /----------------------------------------\
+#####R < The Automatizer >
+#####R \----------------------------------------/
+
+#####GWhat is the Automatizer?
+The automatizer is an advanced auto-pickup or auto-squelch (auto-destroyer). At
+a basic level, it will allow you to automatically destroy things that you have
+no use for once you walk over them, providing that you have identified one of
+them with your current character.
+
+#####GIs that it?
+Well no. The automatizer is far more flexible than that. The old-fashioned auto
+squelch allowed you to destroy things dependent on how they pseudo-id'd - you
+could auto-destroy all {cursed} swords for instance.
+This is fine to start with, but once you get deep in the dungeon, and have a lot
+of money and a decent weapon, you'll be interested in destroying {average} and
+{good} items too right? Well the automatizer allows you to define destruction of
+things providing you are of a certain level.
+
+#####GSounds quite cool, but wha...
+STOP RIGHT THERE! I haven't finished yet! Let's look at some other examples.
+Most of the time, scrolls of darkness are pretty useless. Unless you are a
+vampire, or an alchemist, right? So you might think it was no good to add
+auto-destroy of scrolls of darkness to the automatizer. But you'd be wrong, for
+you can add rules that are dependent on certain conditions, like that you are
+of a certain race, or class.
+
+#####GHey this is sounding good. What if it destroys my artifacts?
+It can't. Artifacts can never be destroyed, by the automatizer. However, watch
+out for items that are VERY cool but not artifacts... you wouldn't want to go
+destroying boots of speed would you? Fortunately there are provisions for this
+too, you could set a rule that destroyed all excellent boots (providing you were
+past character level 45 say), but not if they were boots of speed.
+
+#####GWoah! This sounds amazing!
+Yes it is, isn't it.
+
+#####GSo how do I use it?
+Well the very simplest way is as follows. When you hit 'k' (^D in the roguelike
+keyset) to destroy an item, you'll see that one option is "$ new automatizer
+rule(OFF)". If you want to destroy all future items like that that you find,
+then hit the $ key. You'll see that (OFF) changes to (ON). Now pick the item you
+want to destroy. Let's say it is a Potion of Salt Water. You would now, as
+normal, see a message "You destroy a Potion of Salt Water". Following this you
+get a prompt, "Destroy all of the same [T]ype, [F]amily, or [N]ame, also use
+[S]tatus (no)?". Let's take the easy one first and hit 'n' to go with name.
+You'll now see a message, "Rule added, please go to the automatizer screen
+(press = then T) to save the modified ruleset". Let's do that then, shall we. If
+this is the first time you have used the automatizer with this savefile, you'll
+be asked to enable it as you hit T. Confirm that you would like to enable it,
+otherwise it won't work.
+
+#####GWhat's the point in having it disabled then?
+Well let's say you spotted something that you weren't sure how it would be
+affected by your rules, but didn't want to destroy it; you could just disable
+the automatizer for a moment and check it over before deciding what to do with
+it and switching the automatizer back on.
+
+#####GHmmm, ok. So I've enabled the automatizer, now what?
+Well, you'll see a screen like this:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|GsGaGlGtG GwGaGtGeGrB B B w B|G<GrGuGlGeB BnBaBmBew=w"ysyaylyty ywyaytyeyrw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G<GnGaGmGeG>wpwowtwiwownw wowfw wswawlwtw wwwawtwewrg<g/gngagmgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+
+(snipped for brevity).
+
+The automatizer rules are written in XML, so if you're familiar with that format
+you shouldn't find things too difficult. It's also similar in format to HTML, as
+you may notice from the way that there are opening tags (<name>) and closing
+tags (</name>), and that everything between those tags is affected by that
+rule.
+
+#####GXML? HTML? What is this? Isn't ToME enough acronyms to be going on with?
+OK, so you don't know anything about mark-up languages, it's no problem. Let's
+take a look at the automatizer screen bit by bit, starting with the instructions
+bottom right.
+
+up/down to scroll. Well as you move the up/down cursor keys or number keys, a
+different rule name is highlighted in the left hand window, and that rule is
+displayed in the right hand window.
+tab to switch to the rule window. Does what it says on the tin: switches to the
+rule window (the right hand pane) to allow editing of existing rules.
+u/d to move rules. Pressing 'u' or 'd' will move the rule up or down the order
+displayed in the left hand window. Purely for cosmetic reasons.
+new rule. Adds the beginning of a new rule.
+rename rule. This is handy, as every rule added from the destroy prompt (as
+explained above) is automatically named 'destroy', which gets a bit confusing
+when you have 50 or so rules... renaming your rules will make them much easier
+to edit later.
+save rules. Saves all existing rules to a filename you designate (default is
+automat.atm). Don't forget to do this after adding new rules/before exiting the
+game.
+k to disable the automatizer. Disables the automatizer, preserving the rules you
+have made.
+
+#####GYeah yeah, so what about the rule window on the right hand side itself?
+OK, here we go. This is the real juicy stuff.
+
+Anything inside pointy brackets (greater than and less than signs) is called a
+tag. You'll notice that each tag opens with a word, and then that same word
+appears in another tag later on, preceded by a slash. These are referred to as
+opening tags (like <name> ) and closing tags (like </name> ). Everything within
+a set of closing and opening tags is affected by those tags. This will make more
+sense as we continue. Tags and the things they enclose are like "mini-rules"
+which will together make up one rule. I call these mini-rules, clauses.
+
+the first line:
+<rule name="destroy" type="destroy">
+Each rule starts with the tag <rule>, and this contains the rule name, and the
+rule type. The rule name is how it is identified in the left hand window, and
+need not be unique. The rule type will be either "destroy" (destroys items when
+conditions stated below are met) or "pickup" (picks up item when conditions are
+met) or "nothing" (neither picks up, nor destroys item when conditions are met)
+
+The second line:
+ <name>Potion of Salt Water</name>
+This tells us that for the rule to be carried out, the name of the item must be
+"Potion of Salt Water"
+
+The third line:
+</rule>
+This tells us the rule is ended.
+
+In total then, the rule named "destroy" checks to see if the name of every item
+is Potion of Salt water, and if it is, it destroys it.
+
+Nice and simple huh?
+
+#####GYes Yes, very simple. It doesn't look very advanced at the moment.
+Well, we've barely scratched the surface.
+Let's take a look at those other options we got at the destroy prompt. Let's say
+I was at a stage in the game where I wanted to be able to switch on an auto-
+destroy for all swords that pseudo-id'd as {average}. So let's say I have a
+dagger in my backpack, and I want to create an auto-destroy rule for that and
+all subsequent swords... This is what I'd do:
+Hit 'k' to destroy items and hit '$' to turn on automatizer rules. Then I'd
+select the dagger and confirm the destruction. Hit 's' to switch the status
+toggle. This toggle will include (when ON) how the dagger pseudo-ids, and
+finally hit 'f' to add a rule saying destroy by family. What you'll see in the
+automatizer screen now is this:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|GdGeGsGtGrGoGyB B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ydyeysytyryoyyw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wdwewswtwrwowyB B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+#####GOK, well I can see the pseudo-id status is there, what's that tval thing? And
+#####Gwhere does it say swords?
+Well actually the tval thing is where it says swords! This is what is added by
+the 'destroy by family' option.
+
+It's probably worth explaining a bit here about the internal structure of ToME
+code. Don't worry it's not too scary. In ToME, all objects are divided into
+types: swords, axes, hafted-weapons, scrolls, rings etc. Every type is further
+divided into sub-types. Eg swords are divided into daggers, broad swords, two-
+handed swords and so on. Scrolls are divided into their specific actions;
+scrolls of light, scrolls of satisfy hunger etc. Each type has a number assigned
+to it, that never changes, and so does each sub-type. In this way we can
+identify an exact object using just two values: it's type, or tvalue (tval) and
+it's sub-type, or svalue (sval). You see where we're going with this?
+Now daggers have a tval of 23 and an sval of 4. So you can see that we've said
+in the rule that all things with a tval of 23 and a status of average can be
+destroyed.
+
+#####GAh, right. I see. And what's with the <and> tags?
+Well, everything in those tags must be true for the rule to carry out. If we had
+the <tval>23</tval> and the <status>average</average> lines without the <and>
+tags, it would not be clear whether we wanted just one of those clauses to be
+true for the rule to be carried out, or both of them.
+
+#####GErr...
+In other words, without the <and> tags it might look like we wanted to destroy
+a) EVERYTHING that pseudo id'd as average, and
+b) EVERY sword, regardless of how it pseudo-id'd!
+
+#####GRight. What if I did want a rule that was more general, and had either/or
+options in it?
+Then there are tags to do that - the <or> </or> tags. If ANY of the clauses
+return as true within or tags, then the rule is carried out. Substitute <or>
+tags for the <and> tags in our sword example above, and the rule will operate in
+the rather unhelpful way I explained above (all {average} things destroyed, and
+all swords destroyed, regardless of how they pseudo-id). So essentially, if your
+rule has more than one clause, you will need to include either <and> tags or
+<or> tags, or in some cases both.
+
+#####GOK and so what does the [T]ype option do?
+It merely adds the sval, thus narrowing down the parameters for the auto-
+destroy. For instance if I'd chosen to destroy by type rather than family in the
+last example, we'd have ended up with this:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|GdGeGsGtGrGoGyB B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ydyeysytyryoyyw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wdwewswtwrwowyB B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GsGvGaGlB BmBiBnw=w"y4w"B BmBaBxw=w"y4w"G>g<g/gsgvgaglg>B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+You can see in this example that we have nested <and> tags. Evaluating the tags
+from the ones nested deepest first we can see that if an object has a tval of 23
+and an sval between the values of 4 and 4 (i.e. if it is 4) then the rule will
+check against the next part, which is to see if the object identifies {average}.
+If it does, then all the clauses have been met and rule is carried out. In
+short, it destroys all average daggers, rather than all average swords. Strictly
+speaking the nested <and> tags aren't needed, but they do no harm, and are added
+automatically when destroying by [T]ype.
+
+#####GThis is all well and good but the numbers are going to get rather confusing
+#####Garen't they? Be much easier if I could just write 'swords' or 'daggers'.
+Well, you can. Kind of. Instead of using the admittedly rather obtuse numbers,
+you can use the name of that tvalue rather than the number it represents. So
+instead of <tval>23</tval> you could write <tval>TV_SWORD</tval>.
+
+#####GAh that would be better. But where can I find out what all the names, and
+#####Gnumbers of tvalues are?
+Well I've written a *****defines.txt*0[file] which lists tvalues and one which lists svalues for you
+to check on, and you may want to check the objects entry in k_info.txt in your
+lib/edit directory. If you look at the entry for dagger you'll see:
+
+N:43:& Dagger~
+G:|:W
+I:23:4:0
+W:0:0:12:10
+A:0/1:5/1:10/1:20/1
+P:0:1d4:0:0:0
+<snip>
+The only line we're interested in is the one that starts I (for Index). The
+first number is the tval, and the second is the sval.
+Of course you could always rename your rule to make things clearer.
+
+#####GOK so you mentioned something about setting rules up that happen only if a
+#####Gplayer is a certain level?
+Yeah, good point. Well, let's develop our destroy average swords rule for the
+moment. Let's say we always wanted to destroy average swords by the time we got
+to character level 20. They don't earn enough gold to make it worth carrying
+back to town, and we'll have a better weapon by then anyway. So here we are in
+the automatizer screen, with the destroy sword rule displaying in the right hand
+window. If we hit tab, the right window becomes active and the rules at the
+bottom change:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|gdgegsgtgrgogyB B B B B B w B|v<vrvuvlveB BnBaBmBew=w"ydyeysytyryoyyw"B BtByBpBew=w"ydyeysytyryoyyw"v>B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wdwewswtwrwowyB B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|v<v/vrvuvlvev>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW/BlBeBfBtW/BrBiBgBhBtW WtWoW WnWaWvWiWtWaWgWeW WrWuWlWeW,W B9W/B3W/B7W/B1W WtWoW WsWcWrWoWlWlw w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BtBaBbW WfWoWrW WsWwWiWtWcWhW,W BaWdWdW WcWlWaWuWsWeW,W BdWeWlWeWtWeW WcWlWaWuWsWeW/WrWuWlWew w w w w w w w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+You can see the <rule> tags have changed to purple, indicating they are the
+active ones, that all key presses will act upon. Let's just quickly scoot
+through these new commands:
+up/down/left/right to navigate rule: These will change which clause is active,
+enabling you to delete that clause, or add further clauses inside that one if it
+so allows it.
+9/3/7/1 to scroll: scrolls the whole screen which can become useful if you have
+a particularly long rule or one with lots of nested clauses.
+tab for switch: will make the left-hand window active again.
+add clause: adds a new clause within the active one, providing the active clause
+is either a <and>, <or> or <not> tag.
+delete clause/rule: deletes the active clause, and any clauses nested within
+that one. Therefore if the <rule> tags are active, the whole rule will be
+deleted. Beware!
+
+So if we now hit our right arrow we see that the <and> tags are active. We can
+now add a new clause here. Let's do so by pressing 'a'. You'll now see a list of
+different types of clauses you can add, which you simply scroll through using up
+and down keys, and select by hitting enter. A brief description of the selected
+clause is shown in the right hand window. Scroll down to the 'level' rule type
+and hit enter. You'll be asked to enter a player level. Let's go for 20. You'll
+then be asked for a maximum level, put 50, as we want the rule to be true from
+level 20 and upwards. You'll now see our rule displays as:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|gdgegsgtgrgogyB B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ydyeysytyryoyyw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wdwewswtwrwowyB B B B B B w B|v v v v v<vavnvdv>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y2y0w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|v v v v v<v/vavnvdv>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW/BlBeBfBtW/BrBiBgBhBtW WtWoW WnWaWvWiWtWaWgWeW WrWuWlWeW,W B9W/B3W/B7W/B1W WtWoW WsWcWrWoWlWlw w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BtBaBbW WfWoWrW WsWwWiWtWcWhW,W BaWdWdW WcWlWaWuWsWeW,W BdWeWlWeWtWeW WcWlWaWuWsWeW/WrWuWlWew w w w w w w w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+So there we go. A rule which will destroy all {average} swords once the player
+is past character level 20.
+
+#####GHmmm I've tried this, it doesn't destroy cursed swords though...
+Nope. You haven't told it to. If you want a scaling rule, which always destroys
+cursed swords and then destroys average swords at character level 20, then {good}
+swords at character level 35, have a look at this, rather more complicated rule.
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|wswhwiwewlwdB B B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ysywyoyrydysw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wbwowwB B B B B B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|whwrwdw wawrwmwowuwrB B B w B|G G G G G G G G G<GtGvGaGlG>w2w3g<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wawxwewsB B B B B B B B B w B|G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|whwewlwmwsB B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswowfwtw wawrwmB B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y0w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B B w B|
+&&&&&B|wbwowlwtwsB B B B B B B B w B|G G G G G G G G G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wbwowowtwsB B B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wvwewrwyw wbwawdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wgwlwowvwewsB B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wbwawdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wpwowlwewawrwmwsB B B B B w B|g g g g g g g g g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wcwlwowawkB B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|GsGwGoGrGdGsB B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|whwawfwtwewdwsB B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y1y5w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|wawrwrwowwwsB B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswhwowtB B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wbwowowmwewrwawnwgB B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wtwowrwcwhB B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y2y5w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|wrwowdw wtwiwpwsB B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wgwowowdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wpwowtwiwownwsB B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wrwiwnwgwsB B B B B B B B w B|g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wwwawnwdwsB B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wmwuwswhwrwowowmwsB B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswcwrwowlwlwsB B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wawmwuwlwewtwsB B B B B B w B|w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w B|
+&&&&&B|wpwawrwcwhwmwewnwtwsB B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|wswhwawpwew wpwowtB B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|wswtwawvwewsw w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+#####GWoah! What the heck is that?!
+OK ok slow down a minute. Look at it carefully and a clause at a time. It's not
+difficult. Let's take it from the top. It's a destroying rule called swords. It
+opens with some <and> tags. The object must be a sword (tval 23). Now we have an
+OR tag, so we know that there are going to be some options:
+option 1: the player is between level 0 and level 50, and the sword pseudo id's
+as either cursed or worthless.
+option 2: the player is above character level 15, and the sword pseudo id's as
+average.
+option 3: the player is above character level 25, and the sword pseudo id's as
+good.
+If any of these options are true, the rule is carried out. This rule could
+easily be copied for other weapons or pieces of armour, substituting only the
+tval, and perhaps the name.
+
+#####GHmmm ok. looks good. I might want to change those character level values
+#####Gthough. they look a bit low...
+Well yeah, that's up to your playing style I guess... If you want to edit
+clauses directly rather than delete and re-add them, you might want to edit the
+automat.atm file directly. Just open it in your text editor (it's located in
+your lib/user directory or in ~/.tome on multiuser systems) and you'll see the
+format is identical to how it is displayed in the automatizer file. Just watch
+your spellings, and keep a back-up of the original to replace if things go
+wrong. Don't mess about in there if you feel unsure of what you're doing though.
+
+#####GSo what about those examples you gave up above? Like destroying scrolls of
+#####Gdarkness unless you are a vampire or an alchemist?
+OK, let's add this rule from scratch rather than from the destroy item prompt.
+In the automatizer screen, hit 'n' for new rule. It asks for a name and a type
+of rule (destroy/pickup/nothing). I called my rule "? of darkness", and it's a
+destroy rule. It is worthwhile thinking at this point how the rule is going to
+be structured; for very complicated rules pen and paper may help. We're going to
+need to define the object (either by name, or by tval and sval) then we're going
+to say unless the player race modifier is vampire, or the player class is
+alchemist. So we are obviously going to have more than one clause, and the
+clauses are going to have to BOTH be true for the rule to take effect so the
+first clause we add is an <and> one. So hit 'a' for add clause and enter to
+select the <and> clause. Lets now hit our right arrow, so the <and> tags are
+active, and add a new rule. We can now select the <name> tags. At this point
+we're prompted for the name. Now it's not case-sensitive, but you do need to
+spell it correctly!
+With the <and> tags still highlighted we now want to add our "unless vampire or
+alchemist" clause. Seeing as this is an "unless" type clause, we start with a
+<not> tag. So again, 'a'dd a new clause, and select <not>.
+Now make the <not> tag active by moving right and down with the cursor keys. We
+want "EITHER vampire or alchemist" so we include <or> tags, again by moving
+across to make the <not> tags active and 'a'dding a new <or> clause. Then select
+the <or> tags and 'a'dd a new <subrace> clause. Enter 'vampire'.
+So the last part is to add alchemist. Now this might at first glance seem to be
+a simple case of 'a'dding a new clause of the <class> type, within the <or>
+tags, and there is certainly nothing 'wrong' with doing this. At present there
+is no way for non-alchemists to get the alchemy skill, but it is sometimes best
+to 'future-proof' against such possibilities. That's what we're going to do
+here.
+So rather than add a <class> clause, we're going to add a <skill> clause.
+With the <or> tags active, 'a'dd a new <skill> clause. You're first asked for a
+minimum skill level. Well, we can't use any skill unless we have 1.00 whole
+skill points in it or more, so we can put 1 in here. We're then asked for a
+maximum skill level, so we'll put in 50 here. The skill name must be spelled
+correctly (as it appears on the skill screen) so we put 'Alchemy' here. Your
+complete rule now appears as follows:
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|G?G GdGaGrGkGnGeGsGsB B B w B|G<GrGuGlGeB BnBaBmBew=w"y?y ydyayrykynyeysysw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswwwowrwdwsB B B B B B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswawlwtw wwwawtwewrB B B w B|G G G G G G G G G<GnGaGmGeG>wSwcwrwowlwlw wowfw wdwawrwkwnwewswsg<g/gngagmgeg>B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G<GnGoGtG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGuGbGrGaGcGeG>wvwawmwpwiwrweg<g/gsgugbgrgagcgeg>B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGkGiGlGlB BmBiBnw=w"y1w"B BmBaBxw=w"y5y0w"G>wAwlwcwhwewmwyg<g/gsgkgiglglg>B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g<g/gngogtg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+You'll notice I've also renamed the rules to make things a bit more legible.
+
+#####GOK I'm getting there now, what about the boots of speed thing you talked about?
+Heh. Take a look at this, and see if you can work out what it's doing first
+before I talk you through it
+
+&&&&&B/B-B-B-B-BRBuBlBeBsB-B-B-B-B-B/B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B\
+&&&&&B|GbGoGoGtGsB B B B B B B B w B|G<GrGuGlGeB BnBaBmBew=w"ybyoyoytysw"B BtByBpBew=w"ydyeysytyryoyyw"G>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|w?w wdwawrwkwnwewswsB B B w B|G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswwwowrwdwsB B B B B B B w B|G G G G G G G G G<GtGvGaGlG>wTwVw_wBwOwOwTwSg<g/gtgvgaglg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wswawlwtw wwwawtwewrB B B w B|G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|wfwowowdB B B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y0w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GoGrG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wvwewrwyw wbwawdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wbwawdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y2y0w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wawvwewrwawgweg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y3y5w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wgwowowdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G<GaGnGdG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GlGeGvGeGlB BmBiBnw=w"y4y5w"B BmBaBxw=w"y5y0w"G>g<g/glgegvgeglg>B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGuGsG>wvwewrwyw wgwowowdg<g/gsgtgagtgugsg>B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GsGtGaGtGeG>wiwdwewnwtwiwfwiwewdg<g/gsgtgagtgeg>B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G<GnGoGtG>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|G G G G G G G G G G G G G G G G G G G G G<GcGoGnGtGaGiGnG>wswpwewewdg<g/gcgogngtgagigng>B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g g g g g<g/gngogtg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g g g g g<g/gogrg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g g g g g<g/gagngdg>B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B w B|
+&&&&&B|B B B B B B B B B B B B B w B|g<g/grguglgeg>w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w B|
+&&&&&B|B B B B B B B B B B B B B w B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/
+&&&&&B|B B B B B B B B B B B B B w B|w BuBpW/BdBoBwBnW WtWoW WsWcWrWoWlWlW,W BtBaBbW WtWoW WsWwWiWtWcWhW WtWoW WtWhWeW WrWuWlWeW WwWiWnWdWoWww w w w w w w w w w w w w
+&&&&&B|w w w w w w w w w w w w w w B|w BuW/BdW WtWoW WmWoWvWeW WrWuWlWeWsW,W BnWeWwW WrWuWlWeW,W BrWeWnWaWmWeW WrWuWlWeW,W BsWaWvWeW WrWuWlWeWsw w w w w w w w w w w w
+&&&&&B\B-B-B-B-B-B-B-B-B-B-B-B-B-B-B/w RkW WtWoW rdrirsrarbrlreW WtWhWeW WaWuWtWoWmWaWtWiWzWeWrw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+The majority of this is fairly similar to the swords rule; it destroys {average}
+boots at character level 20, {good} ones at character level 35 and cursed ones
+always. The addition is at the bottom. It adds clauses which will destroy
+excellent items providing that they have been identified and that the name does
+not contain the word "speed". The <state>identified</state> bit is important
+here, as it would destroy the boots on pseudo-id otherwise, before it even saw
+the full name of the boots.
+
+#####GThis is fantastic! Where can I get more help?
+email me: fearoffours@t-o-m-e.net
diff --git a/lib/mods/theme/help/birth.txt b/lib/mods/theme/help/birth.txt
new file mode 100644
index 00000000..9e7da8dd
--- /dev/null
+++ b/lib/mods/theme/help/birth.txt
@@ -0,0 +1,659 @@
+|||||oy
+~~~~~84|Birth
+~~~~~11|Character
+#####R /----------------------------------------\
+#####R < Creating a Character >
+#####R \----------------------------------------/
+
+ *****birth.txt*01[Creating a Character] *****birth.txt*02[Character Characteristics]
+ *****birth.txt*03[Races] *****birth.txt*04[Race Modifiers]
+ *****birth.txt*05[Classes] *****birth.txt*83[Gods]
+ *****birth.txt*06[Stats] *****birth.txt*07[Abilities]
+ *****birth.txt*08[Combinations of Race and Class] *****birth.txt*09[Stat bonus tables]
+
+~~~~~01|Character|Creating a Character
+~~~~~12|Creating a Character
+#####R=== Creating a Character ===
+
+ToME is a roleplaying game, in which you, the player, control a
+character in the various dungeons and places of Arda. Perhaps the most
+important thing you control is the birth of your character, in which you
+choose or allow to be chosen various attributes that will affect the future
+life of your character.
+
+Character creation, or birth, is controlled through a variety of choices
+as to constraints on the type of character you wish to play, followed by
+a series of random calculations to generate ("roll up") a random character
+matching the appropriate constraints.
+
+Once your character has been generated, you will be given the choice to
+generate a new character obeying the same constraints, and once you have
+generated more than one character, you can switch back and forth between
+the two most recent characters, until you are presented with a personality
+that you feel comfortable with.
+
+You may start the entire process over at any time.
+
+Once you have accepted a character you will asked to provide a name for the
+character. In general, the actual choice of a name is not important, but do
+keep in mind that it may have some effect on the game itself. For example,
+on some machines, the character name determines the filename that will be
+used to save the character to disk. On others, the character name specifies
+special "pref" files. And the character name is used on the high score list.
+
+~~~~~02|Character|Characteristics
+~~~~~13|Character|Stats 1
+~~~~~14|Stats|Display
+~~~~~37|Display
+~~~~~82|Stats
+#####R=== Character Characteristics ===
+
+Each character has four primary attributes -- gender, race, race modifier and
+class -- that are chosen before the character is generated, and all but gender
+stay fixed for the entire life of that character. These attributes have many
+effects, which will be mentioned as they come up. Keep in mind that in the
+current version of ToME, your choice of race may restrict your choice
+of class.
+
+Each character has a few secondary attributes -- height, weight, social class,
+and background history -- which are randomly determined, but which are affected
+by the gender and race of the character. In general, these attributes are only
+used to provide "flavor" to the character, to assist in the role playing, but
+they do have a few minor effects on the game. For example, background history
+affects social class, which affects the amount of money the character will
+start with.
+
+Each character also has six primary "stats": strength (STR), intelligence
+(INT), wisdom (WIS), dexterity (DEX), constitution (CON), and charisma(CHR).
+These stats will increase automatically every 5 levels, until the limit for
+each statistic has been reached or until you reach level 50 (whichever
+comes first.) Note that this automatic gain is given to
+a character only once, so if you restart a character from an old savefile,
+he will be considered a descendant of the original character and will not start
+gaining stats every 5 levels until he reaches the point where the original
+character died.
+
+By default, primary statistics are represented in a linear way rather than a
+percentile way. You can change to percentile via the game option sequence '=',
+'5' (ToME options), arrow down to 'stats are represented in a linear way', and
+type 'n' for no. Don't forget to save your options when you are done.
+
+These stats modify the abilities of the character in a variety of ways. Every
+stat has a numerical value, ranging from a minimum of 3, up to a normal maximum
+of 18, and even higher, into the "percentile" range, represented as "18/01"
+through "18/100". Actually, every stat can be raised even above 18/100 by
+magical means, up to a pure maximum of 18/220, which is represented as
+"18/***". Traditionally, a percentile stat such as "18/50" has been though of
+as representing a value part way between 18 and 19, and this is one way to
+think of them. However, often, the best way to view the "bonus" values after
+the "18/" is as "tenth" points, since it often takes the same magic to raise a
+stat from, say, 4 to 5, or 16 to 17, as it does from, say, 18/40 to 18/50. The
+important thing to remember is that almost all internal calculations "ignore"
+the final digit of any "bonus", so that, for example, "18/40" and "18/49"
+generally have the same effects. During character generation, each stat is
+rolled out as a number from 8 to 17, with a normal (bell-curve) distribution,
+and is then immediately modified based on the race and class of the character.
+
+Each character also has several primary "skills" -- disarming, magic devices,
+saving throws, stealth, searching ability, searching frequency, fighting skill,
+and shooting skill -- which are derived from the character's race, class, level,
+stats, and current equipment. These skills have rather obvious effects, but
+will be described more completely below.
+
+Each character may have one or more "intrinsic racial skills", based on
+the race of the character. These may include special resistances, abilities
+such as infravision, or even activatable powers such as food creation.
+~~~~~16|Gold
+~~~~~81|Abbreviations
+~~~~~17|Abbreviations|AU
+~~~~~18|Money
+Money in ToME is referred to in gold pieces, also frequently abbreviated as AU
+(the chemical symbol for gold).
+
+Each character starts with some gold, which can be used to buy items from the
+shops in town. Additionally, gold can be obtained by several means:
+
+ * selling items you have, or find, to the shops
+ * taking it from dead monsters
+ * finding it lying around on the floor in the dungeon
+ * digging it out of the walls in certain dungeons
+
+Each character starts out with some gold. The amount you start with is based on
+social class (higher is better), charisma (higher is better), and some other
+stats (less powerful characters start with more gold).
+~~~~~85|Inventory - starting info
+Inventory is what you are carrying and/or wearing at the moment. All items you
+carry/wear have a certain weight. If the weight is very heavy for your
+strength, it can slow you down, and that is not a good thing for your
+character's continuing health. When your character is first created, all items
+you are granted upon creation will be in your inventory. Sometimes starting
+inventory includes something other than a weapon or armor (for example, a light
+source, scroll, potion, or food.)
+~~~~~86|Weapons - starting info
+Some characters start with a weapon. If yours does, you will need to 'w'ield it
+in order to gain its attack capabilities.
+~~~~~23|Character|Armor Class
+~~~~~19|Armor|Armor Class
+~~~~~20|Abbreviations|AC
+#####R === Armour Class ===
+Each character has an armor class, representing how well the character can
+avoid damage. The armor class is affected by dexterity, the equipment, and
+sometimes the race. The higher the AC, the better.
+
+The numbers following a piece of armor's name indicate how good it is. A Metal
+Cap [3,+0] is not as good as an Iron Helm [5,+0], AC-wise, since the 5 is a
+bigger number than the 3. On the other hand, an Iron Helm is heavier than a
+Metal Cap, and that may make a difference to you.
+
+The plusses following the first number (e.g. the +0) indicate a magical bonus.
+If the plus number is more than zero, it should be added on to the base
+number. E.g. a Metal Cap [3,+3] has a higher AC than an Iron Helm [5,+0].
+
+Some characters start with armor. If yours does, you need will need to 'w'ield
+it in order to gain its protection.
+~~~~~21|Abbreviations|HP
+~~~~~22|Character|Hit Points
+Each character has hit points (HP), representing how much damage the character
+can sustain before death. Hit points are derived from your race, class,
+level, and constitution, and can be temporarily boosted by magical means.
+Hit points may be regained by resting, or by a variety of magical means.
+~~~~~24|Abbreviations|SN
+~~~~~25|Character|Sanity Points
+Each character has sanity points (SN), representing how much mental damage the
+character can sustain before death. Sanity points are derived from your wisdom
+and character level. Sanity points may only be regained by magical means and
+won't be regained by resting.
+~~~~~26|Abbreviations|SP
+~~~~~27|Magic|Mana
+~~~~~28|Character|Mana
+Each character has a certain amount of mana. The amount of mana represents how
+many spells of a certain difficulty a character can cast. When a spell is
+cast, you lose amount of mana corresponding to the 'cost' of the spell.
+
+When all mana is gone, or the cost of a given spell is greater than the amount
+of mana you have left, you may attempt to cast a spell; beware, as there are
+consequences to such a rash act.
+
+Spell points may be regained by resting. They can also be restored by a few
+magical means.
+
+Your spell points are derived from your Magic skill, player level and the
+greatest of INT and WIS.
+
+Your total spell points are additionally affected by:
+
+ * your character's race modifier
+ * character class
+
+Your total spell points may be affected by:
+
+ * your encumbrance
+ * what you wear
+
+~~~~~29|Abbreviations|Pt
+~~~~~30|Gods|Piety
+~~~~~31|Character|Piety
+Finally, characters that have chosen to follow a *****gods.txt*0[God] will have piety points
+(Pt). These points represent the character's standing with their God, a
+standing which may rise or fall over time. A character may spend piety points
+to cast a spell granted by his/her God. Spent piety points can be regained in
+different fashions, depending on which God is involved -- each is pleased or
+displeased by assorted actions. Pleasing your God gains you piety, while
+displeasing your god will lose you piety.
+
+In addition to forming the basis for God-granted spells, accumulated piety
+points may also confer various benefits or penalties upon your character,
+depending on the God involved. For example, followers of Eru who have
+accmulated lots of piety points gain a WIS bonus. The actual rules are
+quite specific to each God.
+~~~~~03|Races
+#####R=== Races ===
+
+There are lots different races that you can choose from in ToME. Some
+races are restricted as to what profession they may be, and each race has
+its own adjustments to a character's stats and abilities. Most races also
+have intrinsic abilities, which can be accessed via the "U" command (original
+keyset, or "O" in the roguelike keyset).
+
+ *****r_beorn.txt*0[Beorning] *****r_hafelf.txt*0[Half-Elf] *****r_orc.txt*0[Orc]
+ *****r_drkelf.txt*0[Dark Elf] *****r_hafogr.txt*0[Half-Ogre] *****r_pettyd.txt*0[Petty-Dwarf]
+ *****r_dragon.txt*0[Dragon] *****r_hielf.txt*0[High-Elf] *****r_rohank.txt*0[Rohan Knight]
+ *****r_dunad.txt*0[Dunadan] *****r_hobbit.txt*0[Hobbit] *****r_eagle.txt*0[Eagle]
+ *****r_dwarf.txt*0[Dwarf] *****r_human.txt*0[Human] *****r_troll.txt*0[Troll]
+ *****r_elf.txt*0[Elf] *****r_druadan.txt*0[Druadan] *****r_wodelf.txt*0[Wood Elf]
+ *****r_ent.txt*0[Ent] *****r_maia.txt*0[Maia] *****r_yeek.txt*0[Yeek]
+ *****r_gnome.txt*0[Gnome] *****r_demon.txt*0[Demon]
+~~~~~04|Race Modifiers
+#####R=== Race Modifiers ===
+There are many different race modifiers from which you can choose in ToME.
+Some are restricted as to what race they can be used with, and each one has
+its own adjustments to a character's stats and abilities. Most also have
+intrinsic abilities. If you are not asked for a race modifier, it is because
+your race only supports the classical form.
+
+ *****rm_class.txt*0[Classical] *****rm_barb.txt*0[Barbarian]
+ *****rm_herm.txt*0[Hermit] *****rm_lsoul.txt*0[Lost Soul]
+ *****rm_skel.txt*0[Skeleton] *****rm_spec.txt*0[Spectre]
+ *****rm_zomb.txt*0[Zombie] *****rm_vamp.txt*0[Vampire]
+
+Dragon subraces:
+
+ *****rm_red.txt*0[Red] *****rm_blue.txt*0[Blue]
+ *****rm_black.txt*0[Black] *****rm_white.txt*0[White]
+ *****rm_green.txt*0[Green] *****rm_ether.txt*0[Ethereal]
+
+Demon subraces:
+
+ *****rm_narrog.txt*0[Narrog] *****rm_drarog.txt*0[Draugrog]
+ *****rm_aewrog.txt*0[Aewrog] *****rm_lygrog.txt*0[Lygrog]
+ *****rm_hurog.txt*0[Hurog] *****rm_limrog.txt*0[Limrog]
+ *****rm_sarnrog.txt*0[Sarnrog] *****rm_rawrog.txt*0[Rawrog]
+ *****rm_cabrog.txt*0[Caborrog] *****rm_adanrog.txt*0[Adanrog]
+
+~~~~~05|Classes
+#####R=== Classes ===
+
+Once a race has been chosen, you will need to pick a class. Some classes will
+not be available to certain races, for instance, a Troll cannot become a
+Paladin. For the first few adventures it is suggested that you run a warrior
+or rogue. Spell casting generally requires a more experienced player that is
+familiar with survival techniques.
+
+ *****c_archer.txt*0[Archer] *****c_mimic.txt*0[Mimic] *****c_rogue.txt*0[Rogue]
+ *****c_ascet.txt*0[Ascetic] *****c_mindcr.txt*0[Mindcrafter] *****c_runecr.txt*0[Runecrafter]
+ *****c_assass.txt*0[Assassin] *****c_monk.txt*0[Monk] *****c_sorcer.txt*0[Sorceror]
+ *****c_axemas.txt*0[Axemaster] *****c_necro.txt*0[Necromancer] *****c_stonewr.txt*0[Stonewright]
+ *****c_bard.txt*0[Bard] *****c_palad.txt*0[Paladin] *****c_swordm.txt*0[Swordmaster]
+ *****c_clairv.txt*0[Clairvoyant] *****c_peacemag.txt*0[Peace-mage] *****c_symbia.txt*0[Symbiant]
+ *****c_pr_drk.txt*0[Dark-Priest] *****c_polear.txt*0[Polearmmaster] *****c_thaum.txt*0[Thaumaturgist]
+ *****c_demono.txt*0[Demonologist] *****c_posses.txt*0[Possessor] *****c_trapper.txt*0[Trapper]
+ *****c_druid.txt*0[Druid] *****c_pr_eru.txt*0[Priest(Eru)] *****c_unbel.txt*0[Unbeliever]
+ *****c_geoman.txt*0[Geomancer] *****c_pr_mand.txt*0[Priest(Mandos)] *****c_wainrid.txt*0[Wainrider]
+ *****c_hafted.txt*0[Haftedmaster] *****c_pr_man.txt*0[Priest(Manwe)] *****c_warper.txt*0[Warper]
+ *****c_lorema.txt*0[Loremaster] *****c_pr_ulmo.txt*0[Priest(Ulmo)] *****c_warmage.txt*0[War-mage]
+ *****c_mage.txt*0[Mage] *****c_pr_varda.txt*0[Priest(Varda)] *****c_warrio.txt*0[Warrior]
+ *****c_mercen.txt*0[Mercenary] *****c_ranger.txt*0[Ranger]
+
+#####R=== Gods ===
+
+Once a class has been chosen you may be given the option to choose a god. Some
+classes (notably most Priests) will be given a God to worship automatically.
+Some classes are not necessarily suited to following a God, and Gods are not
+recommended for new players. You can also choose your mind about who (if
+anyone) to worship during the game by finding an *****tome_faq.txt*04[altar] of that God.
+
+Read *****gods.txt*0[gods.txt] for a little more information about Gods.
+
+ *****g_eru.txt*0[Eru Iluvatar] *****g_tulkas.txt*0[Tulkas]
+ *****g_manwe.txt*0[Manwe Sulimo] *****g_aule.txt*0[Aule]
+ *****g_varda.txt*0[Varda Elentari] *****g_ulmo.txt*0[Ulmo]
+ *****g_yavann.txt*0[Yavanna Kementari] *****g_mandos.txt*0[Mandos]
+ *****g_melkor.txt*0[Melkor Bauglir]
+
+~~~~~39|Character|Stats 2
+~~~~~06|Stats|Individual explanations
+#####R=== Stats ===
+~~~~~32|Stats|Strength
+~~~~~34|Strength
+#####G Strength (STR)
+ Strength is important in fighting with weapons and in melee
+ combat. A high strength can improve your chances of hitting
+ as well as the amount of damage done with each hit. Char-
+ acters with low strengths may receive penalties. Strength
+ is also useful in tunnelling and in carrying heavy items.
+~~~~~33|Stats|Intelligence
+~~~~~35|Intelligence
+#####G Intelligence (INT)
+ Intelligence affects the spellcasting abilities of mage-like
+ spell schools (whether these spells are learned directly through
+ their associated skills, or indirectly through the Prayer
+ skill), as well as some of the special abilities of various
+ classes (e.g. Symbiants). Intelligence will affect the number
+ of spell points you receive. A high intelligence may also
+ improve your chances of successfully casting a spell. You cannot
+ learn spells if your intelligence is 7 or lower. A good
+ intelligence can also help with using magic devices, picking
+ locks, and disarming traps.
+~~~~~36|Stats|Wisdom
+~~~~~38|Wisdom
+#####G Wisdom (WIS)
+ The primary function of wisdom is to determine the ability
+ of a priest or paladin to use prayers (God-granted spells), just
+ like intelligence affects mage spells. Again, high wisdom will
+ increase the number of spell points you have (even though
+ prayers use piety points), and will improve the chance that a
+ prayer will be successful. A good wisdom can also help to
+ improve your chances of resisting magical spells cast
+ upon you by monsters.
+~~~~~40|Stats|Dexterity
+~~~~~41|Dexterity
+#####G Dexterity (DEX)
+ Dexterity is a combination of agility and quickness. A high
+ dexterity may allow your character to get multiple blows with
+ lighter weapons, thus greatly increasing your kill power, and
+ will increase your chances of hitting with any weapon and
+ dodging blows from enemies. Dexterity is also useful in
+ picking locks, disarming traps, and protecting yourself from
+ some of the thieves that inhabit the dungeons. The unscrupulous
+ adventurer may also find dexterity effective in obtaining items
+ from stores without rendering payment.
+~~~~~42|Stats|Constitution
+~~~~~43|Constitution
+#####G Constitution (CON)
+ Constitution is a character's ability to resist damage to his
+ body, and to recover from damage received. Therefore a
+ character with a high constitution will receive more hit
+ points and also recover them faster while resting.
+~~~~~44|Stats|Charisma
+~~~~~45|Charisma
+#####G Charisma (CHR)
+ Charisma represents a character's personality and physical
+ appearance. A character with a high charisma will receive
+ better prices from store owners, whereas a character with a
+ very low charisma may be robbed blind. A high charisma will
+ also mean more starting money for the character.
+~~~~~07
+~~~~~46|Character|Abilities
+#####R=== Abilities ===
+
+ Characters possess some different abilities which can help them
+ to survive. The starting abilities of a character are based upon
+ race and class. Abilities may be adjusted by high or low stats,
+ and increase with the corresponding *****skills.txt*0[skill] level.
+~~~~~48|Attacking monsters|Fighting ability
+#####G Fighting
+ Fighting is the ability to hit and do damage with weapons or
+ fists. Normally a character gets a single blow from any
+ weapon, but if his dexterity and strength are high enough,
+ he may receive more blows per round with lighter weapons.
+ Strength and dexterity both modify the ability to hit an
+ opponent. This skill increases with the *****skills.txt*02[Weaponmastery] skill
+ and its sub-skills.
+~~~~~50|Attacking monsters|Shooting
+#####G Shooting Ability (Bows/Throw)
+ Using ranged missile weapons (and throwing objects) is
+ included in this skill. Different stats apply to different
+ weapons, but this ability may modify the distance an object
+ is thrown/fired, the amount of damage done, and the ability
+ to hit a creature. This skill increases with the *****skills.txt*08[Archery] skill
+ and its sub-skills.
+~~~~~52|Saving throw
+#####G Saving Throw
+ A Saving Throw is the ability of a character to resist the
+ effects of a spell cast on him by another person/creature.
+ This does not include spells cast on the player by his own
+ stupidity, such as quaffing a nasty potion. This ability
+ increases with the *****skills.txt*38[Spirituality] skill,
+ A high wisdom also increases this ability.
+~~~~~54|Stealth
+#####G Stealth
+ The ability to move silently about is very useful. Charac-
+ ters with good stealth can usually surprise their opponents,
+ gaining the first blow. Also, creatures may fail to notice
+ a stealthy character entirely, allowing a player to avoid
+ certain fights. This skill is based upon race, class and the
+ *****skills.txt*15[Stealth] skill.
+~~~~~56|Disarming traps
+#####G Disarming
+ Disarming is the ability to remove traps (safely), and
+ includes picking locks on traps and doors. A successful
+ disarming will gain the character some experience. A trap
+ must be found before it can be disarmed. Dexterity and
+ intelligence both modify the ability to disarm, and this
+ ability increases with the *****skills.txt*16[Disarming] skill.
+~~~~~58|Magical Devices
+#####G Magic Device
+ Using a magical device such as a wand or staff requires
+ experience and knowledge. Spell users such as magi and
+ priests are therefore much better at using a magical device
+ than say a warrior. This skill is modified by intelligence,
+ and increases with the *****skills.txt*54[Magic-Device] skill.
+~~~~~60|Searching
+~~~~~61|Searching|Searching Frequency - Perception
+~~~~~62|Perception
+#####G Searching Frequency (Perception)
+ Perception is the ability to notice something without
+ actively seeking it out. This skill is based upon race,
+ class and the *****skills.txt*14[Sneakiness] skill.
+~~~~~63|Searching|Searching Ability
+#####G Searching Ability (Searching)
+ To search is to actively look for secret doors, floor traps,
+ and traps on chests. Rogues are the best at searching, but
+ magi, rangers, and priests are also good at it. This skill
+ is based upon race, class and the *****skills.txt*14[Sneakiness] skill.
+~~~~~66|Infra-vision
+#####G Infra-vision
+ Infra-vision is the ability to see heat sources. Since most
+ of the dungeon is cool or cold, infra-vision will not allow
+ the player to see walls and objects. Infra-vision will allow
+ a character to see any warm-blooded creatures up to a cer-
+ tain distance. This ability works equally well with or with
+ out a light source. The majority of ToME's creatures are
+ cold-blooded, and will not be detected unless lit up by a
+ light source. Most non-human races have innate infra-vision
+ ability. Humans can gain infra-vision only through magic
+ enhancement.
+
+~~~~~08|Character|Race and Class Combinations
+~~~~~67|Races|Combinations with class
+~~~~~68|Classes|Combinations with Race
+~~~~~69|Tables
+~~~~~70|Tables|Combinations of Race and Class
+#####R=== Combinations of Race and Class ===
+
+These are the classes that are recommended for different races. You can
+still select a race that is not in the chart, but these combinations are
+either rather poor (like a zombie mage), a concept so silly that they
+are not recommended, or an incredibly unfair combination of race and class.
+If you pick a combination that is not on the chart, don't complain if things
+don't turn out as you expected them to.
+
+#####B Warrior Archer Rogue Mage Priest Loremaster
+#####B
+Beorning Yes No Yes No No Yes
+Dark Elf Yes Yes Yes Yes Yes No
+Dragon No No No Yes Yes Yes
+Dunadan Yes Yes Yes Yes Yes Yes
+Dwarf Yes No No No Yes No
+Elf Yes Yes No Yes Yes Yes
+Ent Yes No No No Yes Yes
+Gnome Yes No Yes Yes No No
+Half-Elf Yes Yes Yes Yes Yes Yes
+Half-Ogre Yes No No No Yes No
+High-Elf Yes Yes No Yes Yes Yes
+Hobbit Yes Yes Yes Yes No Yes
+Human Yes Yes Yes Yes Yes Yes
+Druadan Yes Yes Yes No No Yes
+Maia Yes Yes Yes Yes Yes Yes
+Orc Yes Yes Yes No Yes No
+Petty Dwarf Yes No Yes No No No
+RohanKnight Yes No No No Yes No
+Eagle No No No Yes Yes Yes
+Troll Yes No No No No No
+Wood Elf Yes Yes No Yes Yes Yes
+Yeek Yes Yes Yes Yes Yes Yes
+Easterling Yes Yes No No No No
+Demon Yes Yes Yes Yes Yes Yes
+
+~~~~~09|Character|Stat Bonus Table
+~~~~~71|Stats|Bonus table
+~~~~~72|Tables|Stat bonuses
+#####R=== Stat Bonus Tables ===
+
+Stat, hit dice, and experience points per level modifications due to race
+are listed in the following table.
+~~~~~75|Races|Stat Bonuses
+#####GRaces:
+#####B STR INT WIS DEX CON CHR Hit Dice Rqd Exp/level
+ Beorning +4 -2 -2 -1 +3 -5 12 +50%
+ Dark Elf -1 +3 +2 +2 -2 +1 9 +50%
+ Dragon +3 +2 +2 -2 +2 -5 9 +150%
+ Dunadan +1 +2 +2 +2 +3 +2 10 +80%
+ Dwarf +2 -2 +2 -2 +2 -3 11 +25%
+ Elf -1 +2 +2 +1 -2 +2 8 +20%
+ Ent +10 -3 +2 -5 +11 -3 14 +110%
+ Gnome -1 +2 0 +2 +1 -2 8 +35%
+ Half-Elf 0 +1 +1 +1 -1 +1 9 +10%
+ Half-Ogre +3 -1 -1 -1 +3 -3 12 +30%
+ High-Elf +1 +3 +2 +3 +1 +5 10 +100%
+ Hobbit -2 +2 +1 +3 +2 +1 7 +10%
+ Human 0 0 0 0 0 0 10 +0%
+ Druadan -2 -3 +2 +3 +2 -2 9 +15%
+ Maia 0 0 0 0 0 0 10 +0%
+ Petty Dwarf +1 -1 +2 0 +2 -4 11 +35%
+ Orc +2 -1 0 +1 +1 -4 10 +10%
+ RohanKnight +4 -2 +3 +1 +4 +2 10 +120%
+ Eagle +6 +2 +1 -2 +3 +6 12 +200%
+ Troll +4 -4 -2 -4 +3 -6 12 +37%
+ Wood Elf +2 +2 -3 +5 0 +1 7 +30%
+ Yeek -5 -5 -5 -5 -5 -5 6 -75%
+ Easterling +2 -2 -2 -2 +2 -1 10 +40%
+ Demon 0 0 0 0 0 -1 10 +70%
+~~~~~76|Race Modifiers|Stat Bonuses
+#####GRace Modifiers:
+#####B STR INT WIS DEX CON CHR Hit Dice Rqd Exp/level
+ Classical 0 0 0 0 0 0 +0 +0%
+ Barbarian +2 -3 -2 +1 +1 -3 +1 +25%
+ Hermit -3 +1 +1 -3 -3 +1 -3 +20%
+ Lost Soul 0 0 0 0 0 0 +0 +0%
+ Skeleton 0 -2 -2 0 +1 -4 +0 +45%
+ Spectre -5 +1 +1 +2 -3 -6 -4 +80%
+ Vampire +3 +2 -3 -2 +1 -4 +1 +100%
+ Zombie +2 -6 -6 +1 +4 -5 +3 +45%
+
+
+#####R Dragons:
+ Red +3 0 0 0 0 0 +0 +0%
+ Black 0 0 0 0 0 +3 +0 +0%
+ Green 0 0 0 0 +3 0 +0 +0%
+ Blue 0 0 0 +3 0 0 +0 +0%
+ White 0 +3 0 0 0 0 +0 +0%
+ Ethereal 0 0 +3 0 0 0 +0 +0%
+
+#####R Demons:
+ (Narrog) -1 +1 +1 +1 -1 -2 +1 +20%
+ (Aewrog) -2 0 0 0 +3 0 +1 +0%
+ (Hurog) 0 0 0 0 0 -1 +0 -10%
+ (Sarnrog) +2 -1 -2 -2 +2 -1 +2 +20%
+ (Caborrog) -1 +2 +1 0 0 -3 +2 +10%
+ (Draugrog) +1 +1 +1 +1 +1 -1 +0 -20%
+ (Lygrog) -3 +5 +5 +5 -1 -6 +2 +40%
+ (Limrog) -2 +1 +1 +3 -1 -1 +1 +50%
+ (Rawrog) +2 +1 +1 -1 +2 +1 +2 +30%
+ (Adanrog) +1 +1 +1 +1 +1 +1 +3 +50%
+
+~~~~~77|Classes|Stat Bonuses
+#####GClasses:
+#####B STR INT WIS DEX CON CHR
+ Axemaster +5 -2 -2 +2 +2 -1
+ Demonologist +5 -2 -2 +2 +2 -1
+ Haftedmaster +5 -2 -2 +2 +2 -1
+ Polearmmaster +5 -2 -2 +2 +2 -1
+ Swordmaster +5 -2 -2 +2 +2 -1
+ Unbeliever +5 -2 -2 +2 +2 -1
+ Warrior +5 -2 -2 +2 +2 -1
+ Wainrider +5 -2 -2 +2 +2 -1
+
+ Clairvoyant -5 +3 0 +1 -2 +1
+ Geomancer -5 +3 0 +1 -2 +1
+ Mage -5 +3 0 +1 -2 +1
+ Necromancer -5 +3 0 +1 -2 +1
+ Runecrafter -5 +3 0 +1 -2 +1
+ Sorceror -5 +3 0 +1 -2 +1
+ Thaumaturgist -5 +3 0 +1 -2 +1
+ Warper -5 +3 0 +1 -2 +1
+
+ Archer +2 +1 0 +2 +1 +1
+ Ranger +2 +2 0 +2 +1 +1
+ Sniper +2 +2 0 +2 +1 +1
+
+ Assassin +2 +1 -2 +3 +1 -1
+ Rogue +2 +1 -2 +3 +1 -1
+ Mercenary +2 +1 -2 +3 +1 -1
+
+ Ascetic +1 -2 +1 +1 0 +1
+ Bard +1 -2 +1 +1 0 +1
+ Loremaster +1 -2 +1 +1 0 +1
+ Mimic +1 -2 +1 +1 0 +1
+ Monk +1 -2 +1 +1 0 +1
+ Possessor +1 -2 +1 +1 0 +1
+ Summoner +1 -2 +1 +1 0 +1
+ Symbiant +1 -2 +1 +1 0 +1
+
+ Dark-Priest -1 -3 +3 -1 0 +2
+ Druid -1 -3 +3 -1 0 +2
+ Mindcrafter -1 -3 +3 -1 0 +2
+ Paladin -1 -3 +3 -1 0 +2
+ Priest(Eru) -1 -3 +3 -1 0 +2
+ Priest(Mandos)-1 -3 +3 -1 0 +2
+ Priest(Manwe) -1 -3 +3 -1 0 +2
+ Priest(Ulmo) -1 -3 +3 -1 0 +2
+ Priest(Varda) -1 -3 +3 -1 0 +2
+ Stonewright -1 -3 +3 -1 0 +2
+
+ Trapper 0 +2 +2 +2 0 +4
+ Peace-mage 0 +2 +2 +2 0 +4
+
+
+~~~~~10|Character|Ability tables
+~~~~~74|Tables|Ability Tables
+#####R=== Ability Tables ===
+
+~~~~~78|Races|Ability table
+#####GRaces:
+#####B Dsrm Dvce Save Stlh Srch Prcp HtH Misl Infra
+ Beorning -6 -8 -6 -2 -1 +5 +25 +5 30 feet
+ Dark Elf +5 +15 +20 +3 +8 +12 -5 +10 50 feet
+ Dragon +5 +5 +5 -10 +5 +5 +5 -20 50 feet
+ Dunadan +4 +5 +5 +2 +3 +13 +15 +10 None
+ Dwarf +2 +9 +10 -1 +7 +10 +15 +0 50 feet
+ Elf +5 +6 +6 +2 +8 +12 -5 +15 30 feet
+ Ent +5 +5 +20 -6 +5 +4 +15 +5 50 feet
+ Gnome +10 +12 +12 +3 +6 +13 -8 +12 40 feet
+ Half-Elf +2 +3 +3 +1 +6 +11 -1 +5 20 feet
+ Half-Ogre -3 -5 -5 -2 -1 +5 +20 +0 30 feet
+ High-Elf +4 +20 +20 +4 +3 +14 +10 +25 40 feet
+ Hobbit +15 +18 +18 +5 +12 +15 -10 +20 40 feet
+ Human +0 +0 +0 +0 +0 +10 +0 +0 None
+ Druadan +5 +0 +0 +5 +15 +15 +0 +5 30 feet
+ Maia +0 +0 +0 +0 +0 +10 +0 +0 None
+ Orc -3 -3 -3 -1 +0 +7 +12 -5 30 feet
+ Petty Dwarf +3 +5 +10 +1 +5 +10 +9 +0 50 feet
+ RohanKnight +10 +5 +5 -8 +1 +1 +5 +5 None
+ Eagle +6 0 +10 -16 +30 +10 + 0 +0 50 feet
+ Troll -5 -8 -8 -2 -1 +5 +20 -10 30 feet
+ Wood Elf +5 +6 +6 +5 +8 +12 -5 +40 40 feet
+ Yeek -5 -5 -10 +0 -5 +0 -10 -10 20 feet
+ Easterling +0 -5 -1 +0 +0 +10 +5 +5 None
+ Demon +0 +0 +0 +0 +0 +0 +0 +0 30 feet
+~~~~~79|Race Modifiers|Ability table
+#####GRace Modifiers:
+#####B Dsrm Dvce Save Stlh Srch Prcp HtH Misl Infra
+ Classical +0 +0 +0 +0 +0 +0 +0 +0 +0 feet
+ Barbarian -2 -10 +2 -2 +0 +1 +12 +5 +0 feet
+ Hermit +5 +10 +5 +3 +4 +10 -5 -5 +10 feet
+ Lost Soul +0 +0 +0 +0 +0 +0 +0 +0 +0 feet
+ Skeleton -5 -5 +5 -1 -1 +8 +8 +0 +10 feet
+ Spectre +2 +8 +7 +2 +2 +7 -5 -2 +30 feet
+ Vampire +0 +0 +0 +0 +0 +0 +0 +0 +0 feet
+ Zombie -2 -2 +5 -1 -1 +2 +5 +0 +10 feet
+
+#####R Dragons:
+ Red +0 +0 +0 -2 +2 +0 +5 +0 +10 feet
+ Black +2 +0 +1 +0 +0 +0 +0 +0 +0 feet
+ Green +0 +0 +2 +0 +0 +0 +0 +0 +0 feet
+ Blue +3 +0 +2 +1 +0 +0 +0 +0 +10 feet
+ White +0 +2 +0 +0 +0 +0 +0 +0 +0 feet
+ Ethereal +0 +0 +1 +5 +2 +2 +0 +0 +30 feet
+
+#####R Demons:
+ (Narrog) +2 +0 +1 +2 +2 +20 +0 +0 +10 feet
+ (Aewrog) +0 +0 +1 -2 +0 +10 +0 +0 +10 feet
+ (Hurog) +2 +0 +2 +0 +5 +30 +0 +0 +20 feet
+ (Sarnrog) -1 +0 +0 -8 -2 -10 +5 +0 +0 feet
+ (Caborrog) +0 +0 +1 -10 +2 +10 +0 +0 +0 feet
+ (Draugrog) +2 +0 +2 -20 +5 +30 +0 +0 +20 feet
+ (Lygrog) +5 +5 +5 +10 +5 +50 +0 +0 +30 feet
+ (Limrog) +2 +2 +2 +2 +2 +30 +0 +0 +20 feet
+ (Rawrog) +0 +0 +4 -3 +0 +10 +10 +10 +0 feet
+ (Adanrog) +1 +1 +1 +1 +1 +20 +15 +10 +20 feet \ No newline at end of file
diff --git a/lib/mods/theme/help/c_alchem.txt b/lib/mods/theme/help/c_alchem.txt
new file mode 100644
index 00000000..2f7cd58c
--- /dev/null
+++ b/lib/mods/theme/help/c_alchem.txt
@@ -0,0 +1,135 @@
+|||||oy
+~~~~~01|Alchemist
+~~~~~02|Classes|Alchemist
+#####R=== Alchemists ===
+
+#####GDescription
+Alchemists are the only class that can harness the abilities of the
+essences found in the dungeon. They can add these essences to staves,
+rings, wands, rods, and sometimes weapons and armour to create new items
+or recharge old ones. They can also extract essences from magical items
+they find. Using these abilities, Alchemists can get very good items at
+low levels. The trouble is getting them to survive later on.
+
+Alchemists are extremely proficient with all kinds of magical devices,
+and have made a fine art of extracting, storing, and using these
+objects' magical energies. Because they neither fight well nor cast
+powerful spells, Alchemists rely on their craftsmanship to cope with
+the dangers of the dungeons. They will quickly learn to create damage-
+dealing wands, rods, and staffs, forge powerful weapons and armour,
+make highly useful objects of other kinds, and eventually, at great cost
+to other knowledge, they can learn the perilous art of artifact creation
+itself.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +0%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.700]
+ Weaponmastery 0.700 [0.700]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 3.000 [0.900]
+ Magic-Device 1.000 [1.250]
+ Geomancy
+ Fire 0.000 [0.100]
+ Water 0.000 [0.100]
+ Air 0.000 [0.100]
+ Earth 0.000 [0.100]
+ Meta 0.000 [0.500]
+ Conveyance 0.000 [0.100]
+ Divination 0.000 [0.500]
+ Temporal 0.000 [0.100]
+ Mind 0.000 [0.100]
+ Nature 0.000 [0.100]
+ Necromancy 0.000 [0.100]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.100]
+ Alchemy 1.000 [0.800]
+Spirituality 1.000 [0.800]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*An Alchemist cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+An Alchemist begins the game with:
+ a Dagger
+ six Essences of Explosion
+ an Empty Bottle
+ a Set of Leather Gloves
+~~~~~03|Alchemist|Alchemy powers explained
+~~~~~05|Skills|Alchemy - Alchemy powers
+#####GAlchemy
+[[[[[BThe alchemical techniques are accessed using the 'm' key.]
+Alchemists may then 'E'xtract essences or add 'P'owers. The Alchemist [[[[[vmust]
+be wearing GLOVES to use their alchemy powers.
+
+An Alchemist is also capable of [[[[[Bcreating their own artifacts], but
+this is a time-consuming, and costly, activity. To do so, he must first
+learn the ability *****ability.txt*09[Artifact Creation], which costs a whopping 70 skill points
+to learn, and requires some high pre-requisites. Once he has done so,
+he needs to imbue an ego item with a number of essences of magic (equal
+to their skill level) and then wield the item. While using the item,
+it will gain experience (which reduces the amount of exp the wearer
+gains during this time). When the Alchemist feels that the item is
+powerful enough, he can finalise the artifact by "buying" powers using
+the experience the artifact has collected. He will also require exotic
+ingredients to add the abilities.
+
+Most (but not all) potions, scrolls, wands, staffs, rods, rings, and
+amulets contain usable magical energies. An Alchemist taps that
+energy, using the technique "'E'xtract essences" to create one or more
+essences of a type appropriate to the original object.
+
+The drained object itself is now called "of nothing". Unlike any
+other kind of object, it can have new magics added to it.
+
+An Alchemist can add power to such items by using essences he made or
+found. He does this with the technique "'P'ower". He can then select
+the object he wishes to enchant, and the kind of object he wishes to
+create. Only object types for which he knows the recipe will be displayed,
+and ones for which essences are lacking will be displayed in red. Objects
+whose level exceeds his own are sometimes difficult to create, though
+he can always add gold to improve the chances of his success.
+
+[[[[[BA few pointers:]
+ -Recipes are (usually) logical. Acid essences don't make Dragon
+ Weapons. And you can always look at the recipes you know with
+ the "recipe 'B'ook" command.
+ -Not all objects or ego-item types can be made using alchemy.
+ -Alchemy is mostly reversible. Most items that you can
+ 'E'xtract from, you can later re-create, if you learn about
+ them when extracting from them. You won't always get enough
+ essences from destroying an item to recreate it, though the
+ chance of doing so will get higher as you increase in skill.
+ -*Identifying* an object that you can destroy will always teach
+ you how to create it (if creating it is possible).
+ -Since you can't create abilities in artifacts that you aren't
+ aware of, make sure to *identify* all the artifacts you can.
+ -You can't *identify* things you buy in shops, so you'll have
+ to extract from them and take your chances.
+
+[[[[[BSome Recipes:]
+Any Alchemist worth his salt knows lots of recipes. By extracting from
+items in the dungeon, he learns to create more and more items. You can
+see the recipes you know using the "recipe 'B'ook" command. The Alchemist
+starts off knowing some basic recipes, and gains more recipes as time
+goes on.
+
+More details can be found in the *****essences.txt*0[Essences SPOILER]).
+
diff --git a/lib/mods/theme/help/c_archer.txt b/lib/mods/theme/help/c_archer.txt
new file mode 100644
index 00000000..a115e6f2
--- /dev/null
+++ b/lib/mods/theme/help/c_archer.txt
@@ -0,0 +1,68 @@
+~~~~~01|Archer
+~~~~~02|Classes|Archer
+#####R=== Archers ===
+
+#####GDescription
+Archers are to bows what warriors are to melee. They are the best class
+around with any bow/crossbow/sling/boomerang.
+
+Needing a lot of ammo, they will learn early how to make it from junk found
+in the dungeons. They also gain, at skill level 20, the unique ability to make
+their arrows/bolts/shots pierce through monsters!
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom +0
+Dexterity +2
+Constitution +1
+Charisma +1
+Hit Die +d4
+Spell Points +0%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.500]
+ Archery 1.000 [0.850]
+ Sling-mastery 0.000 [0.500]
+ Bow-mastery 0.000 [0.500]
+ Crossbow-mastery 0.000 [0.500]
+ Boomerang-mastery 0.000 [0.500]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 0.000 [0.200]
+ Magic-Device 1.000 [1.100]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Ammo creation 2
+
+#####GStarting Equipment
+An Archer begins the game with:
+ a Short Bow
+ a Sling
+ some ammo
+~~~~~03|Creating Ammo
+#####GCreating Ammo
+Archers automatically gain the *****ability.txt*07[Ammo Creation] ability when they reach character
+level 2. (Other classes can purchase this ability when they have enough skill
+points.) This ability is accessed via the 'm' command. The first type of
+ammo you can make is sling ammo (pebbles or shots); as you increase in skill
+you'll be able to make other arrows (bow ammo) or bolts (crossbow ammo).
+
+Shots (or other sling ammo) are created from rubble piles found in the dungeons
+and other places. To make shots, stand next to a rubble pile, activate the
+ammo creation ability from the 'm' menu, select 's'hots, then specify the
+direction to the rubble pile, which will be consumed during the ammo creation.
+Arrows or bolts are made from "junk" items ('~' symbol, such as shards of
+pottery) that you can find in the dungeons and other places. To make arrows or
+bolts, assuming you have sufficient Archery skill, you must have the junk item
+in your inventory or on the ground at your feet. Specify the junk item after
+selecting 'a'rrows or 'b'olts from the ammo creation menu, and it will be
+consumed and replaced with a stack of ammo.
diff --git a/lib/mods/theme/help/c_ascet.txt b/lib/mods/theme/help/c_ascet.txt
new file mode 100644
index 00000000..cc2a2ab4
--- /dev/null
+++ b/lib/mods/theme/help/c_ascet.txt
@@ -0,0 +1,46 @@
+~~~~~01|Ascetic
+~~~~~02|Classes|Ascetic
+#####R=== Ascetics ===
+
+#####GDescription
+An Ascetic is a monk who has forsaken all worldly
+things, including deity worship and magic. Ascetics
+must survive by their fists and their natural
+ability to resist magic. Despite not worshipping any
+gods, Ascetics are highly spiritual, and can achieve
+excellent saving throws in addition to their magic-
+repelling abilities.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Bonus Blows 0
+Hit Die +d8
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.900]
+ Archery 1.000 [0.700]
+ Barehand-combat 1.000 [0.900]
+ Antimagic 1.000 [1.000]
+Sneakiness 1.000 [0.700]
+ Stealth 1.000 [1.000]
+ Disarming 1.000 [0.900]
+ Dodging 0.000 [1.000]
+Spirituality 1.000 [0.700]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 1.000 [0.700]
+
+#####GStarting Equipment
+An ascetic begins the game with:
+ a potion of healing
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(1) 5 \ No newline at end of file
diff --git a/lib/mods/theme/help/c_assass.txt b/lib/mods/theme/help/c_assass.txt
new file mode 100644
index 00000000..4269e3e8
--- /dev/null
+++ b/lib/mods/theme/help/c_assass.txt
@@ -0,0 +1,58 @@
+~~~~~01|Assassin
+~~~~~02|Classes|Assassin
+#####R=== Assassins ===
+#####GDescription
+Assassins are similar to Rogues, but have trained their combat abilities more
+extensively by neglecting the study of magic. They also tend to be more stealthy
+and careful in their dungeon exploration, but aren't so good at stealing,
+trapping and disarming as their more "peaceful" counterparts.
+
+Assassins have access to the schools of *****m_convey.txt*0[Conveyance], *****m_divin.txt*0[Divination] and *****m_tempo.txt*0[Temporal] magic.
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom -2
+Dexterity +3
+Constitution +1
+Charisma -1
+Hit Die +d6
+Spell Points +0%
+Exp Penalty 25%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.800]
+ Sword-mastery 1.000 [0.600]
+ Critical-hits 2.000 [0.800]
+ Archery
+ Boomerang-mastery 1.000 [0.300]
+Sneakiness 1.000 [2.000]
+ Stealth 1.000 [2.000]
+ Disarming 1.000 [1.000]
+ Backstab 1.000 [2.000]
+ Stealing 1.000 [0.200]
+ Dodging 1.000 [2.000]
+Magic 1.000 [0.200]
+ Magic-Device 1.000 [0.750]
+ Conveyance 0.000 [0.100]
+ Divination 0.000 [0.100]
+ Temporal 0.000 [0.200]
+Spirituality 1.000 [0.700]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*An Assassin cannot learn the Archery skill, but it is shown in his skill
+screen because Boomerang-mastery is a sub-skill of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 10
+
+#####GStarting Equipment
+An Assassin begins the game with:
+ a Dagger
+
+
+
diff --git a/lib/mods/theme/help/c_axemas.txt b/lib/mods/theme/help/c_axemas.txt
new file mode 100644
index 00000000..cdd6ba88
--- /dev/null
+++ b/lib/mods/theme/help/c_axemas.txt
@@ -0,0 +1,51 @@
+~~~~~01|Axemaster
+~~~~~02|Classes|Axemaster
+#####R=== Axemasters ===
+
+#####GDescription
+The Axemaster is a Warrior who specialises in axes.
+The training is so intense and specific that Axemasters gain huge bonuses
+when fighting with their chosen weapon, dependent on their Axe-mastery skill.
+In most other respects they perform about as well as a generic Warrior.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.900]
+ Weaponmastery 1.000 [0.950]
+ Sword-mastery 0.000 [0.300]
+ Axe-mastery 1.000 [0.700]
+ Hafted-mastery 0.000 [0.300]
+ Polearm-mastery 0.000 [0.300]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+An Axemaster begins the game with:
+ a Ring of Fear Resistance
+ a Chain Mail
+ a Hatchet
diff --git a/lib/mods/theme/help/c_bard.txt b/lib/mods/theme/help/c_bard.txt
new file mode 100644
index 00000000..23ba42ca
--- /dev/null
+++ b/lib/mods/theme/help/c_bard.txt
@@ -0,0 +1,69 @@
+|||||oy
+~~~~~01|Bard
+~~~~~02|Classes|Bard
+#####R=== Bards ===
+
+#####GDescription
+Bards are traditional musicians. Their magical attacks are sound-based, and
+last as long as the Bard has mana. If the Bard runs out of mana, he/she stops
+singing. There is also a low-level "spell" that will cease the song.
+
+While any class can use musical instruments, only Bards can tap the
+power of voice to aid themselves and hinder, dismay, and kill their
+foes.
+
+#####GMagic Usage
+
+Songs are continuous, and the song consumes mana every turn in order to
+maintain itself. The song will continue, once played, until either the 'Stop
+Singing' song is sung, or the player's mana runs out.
+
+Each song has a magic school level associated with, just as any other magic
+spell does. Each song also has a Roman numeral (e.g. I, II, III, IV, V)
+following its name. These numerals correspond to 1, 2, 3, 4, 5. The higher the
+numeral, the more music skill the Bard must have to play that song.
+
+Each musical instrument has a value between 1 and 4 assigned to it, as well.
+The higher the number, the better the craftmanship. A Bard can only play
+higher level songs with a more powerful instrument. You would be able to cast
+"Stop Singing (I)" and "Song of the Sun (I)" with a a Harp (+1). A Harp (+2)
+would allow you to sing those songs, as well as "Flow of Life (II)".
+
+For information on song effects see the *****m_music.txt*0[Music Songs] file.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Barehand-combat 1.000 [0.600]
+Sneakiness 1.000 [0.700]
+ Stealth 1.000 [0.700]
+ Disarming 1.000 [0.600]
+Magic 1.000 [0.600]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.800]
+ Prayer 0.000 [0.500]
+ Music 1.000 [0.800]
+Monster-lore 1.000 [1.100]
+ Summoning 0.000 [0.400]
+ Corpse-preservation 1.000 [0.700]
+ Symbiosis 0.000 [0.400]
+ Mimicry 0.000 [0.400]
+
+#####GStarting Equipment
+A Bard begins the game with:
+ a Harp (+1)
+ a Short Sword
+ a Robe
+ a Potion of Healing
diff --git a/lib/mods/theme/help/c_clairv.txt b/lib/mods/theme/help/c_clairv.txt
new file mode 100644
index 00000000..7d537486
--- /dev/null
+++ b/lib/mods/theme/help/c_clairv.txt
@@ -0,0 +1,47 @@
+~~~~~01|Clairvoyant
+~~~~~02|Classes|Clairvoyant
+#####R=== Clairvoyants ===
+
+#####GDescription
+Clairvoyants are masters of the mind, they are
+especially proficient at Mindcraft, Divination,
+and the Mind school of magic. They sacrifice
+breadth of ability for additional favour with
+their deity, so it makes sense to pick a deity
+to worship when playing a clairvoyant character.
+It is not, however, a requirement.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Bonus Blows 0
+Hit Die +d0
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.300]
+ Weaponmastery 0.700 [0.500]
+Sneakiness 1.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.200]
+ Spell-power 0.000 [0.600]
+ Divination 1.000 [1.000]
+ Mind 1.000 [1.000]
+Spirituality 1.000 [1.000]
+ Prayer 0.000 [1.000]
+ Mindcraft 1.000 [0.700]
+Monster-lore 0.000 [0.500]
+
+#####GStarting Equipment
+A clairvoyant begins the game with:
+ A book of Beginner Cantrips
+ A quarterstaff
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1 \ No newline at end of file
diff --git a/lib/mods/theme/help/c_demono.txt b/lib/mods/theme/help/c_demono.txt
new file mode 100644
index 00000000..98b0bc9b
--- /dev/null
+++ b/lib/mods/theme/help/c_demono.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Demonologist
+~~~~~02|Classes|Demonologist
+#####R=== Demonologists ===
+
+#####GDescription
+Masters of the Demons, members of this class can gain tremendous power
+over demonkind, either for good or for evil ends.
+
+Their spells are contained in specific blades, shields and helms (actually
+shaped in the form of horns) which when wielded allow the Demonologist to
+cast spells unique to her class; each piece of equipment holds 3 spells.
+
+See the information on the *****m_demono.txt*0[Demonology] school of magic for more details.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.750]
+ Weaponmastery 1.000 [0.750]
+ Sword-mastery 0.000 [0.600]
+ Archery 2.000 [0.400]
+Sneakiness 2.000 [1.800]
+ Stealth 0.000 [0.400]
+ Disarming 2.000 [1.800]
+Magic 2.000 [0.700]
+ Magic-Device 1.000 [1.150]
+ Demonology 1.000 [1.000]
+Spirituality 2.000 [0.700]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+A Demonologist begins the game with:
+ a Ring of Fear Resistance
+ a Demonblade
+ a Chain Mail
+
diff --git a/lib/mods/theme/help/c_druid.txt b/lib/mods/theme/help/c_druid.txt
new file mode 100644
index 00000000..0b0493e2
--- /dev/null
+++ b/lib/mods/theme/help/c_druid.txt
@@ -0,0 +1,55 @@
+|||||oy
+~~~~~01|Druid
+~~~~~02|Classes|Druid
+~~~~~03|Yavanna|Druid
+#####R=== Druids ===
+
+#####GDescription
+When Melkor first dug up Utumno and Angband, rivers were polluted and gave
+birth to dark clouds of stinging insects; animals changed into dark, horrible
+horned things and the forests themselves screamed in horror at their corruption.
+
+*****g_yavann.txt*0[Yavanna] heard this scream and gave to some of the children of Eru the strength
+to defend Nature; at first Ents were chosen, but later on other races were
+allowed to tread the path of the Druid.
+
+The embodiment of life itself, a Druid is a true force of nature and nothing
+can prevent him from completing his final quest: returning Angband to the
+grassy sunlit plain it once was.
+
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.750]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.600]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 1.000 [1.200]
+ Summoning 1.000 [0.700]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Druid begins the game with:
+ a Spellbook of Charm Animal
+ a Mace
diff --git a/lib/mods/theme/help/c_geoman.txt b/lib/mods/theme/help/c_geoman.txt
new file mode 100644
index 00000000..47855875
--- /dev/null
+++ b/lib/mods/theme/help/c_geoman.txt
@@ -0,0 +1,59 @@
+|||||oy
+~~~~~01|Geomancer
+~~~~~02|Classes|Geomancer
+#####R=== Geomancers ===
+
+#####GDescription
+Geomancers harness the power of the elements earth, air, fire and water.
+The level of their *****skills.txt*60[Geomancy] skill gives them access to their own
+*****m_geoman.txt*0[school of Geomancy], but the levels of the Fire, Water, Air, and Earth
+skills will have an effect on the outcome of each spell.
+
+Geomancers need the aid of a Mage Staff in order to use their powers.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.200]
+ Weaponmastery 0.700 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 1.000 [0.700]
+ Geomancy 1.000 [0.700]
+ Fire 1.000 [1.050]
+ Water 1.000 [1.050]
+ Air 1.000 [1.050]
+ Earth 1.000 [1.050]
+ Meta 0.000 [0.700]
+ Conveyance 0.000 [0.700]
+ Divination 0.000 [0.700]
+ Temporal 0.000 [0.700]
+ Mind 0.000 [0.700]
+ Nature 0.000 [0.700]
+ Necromancy 0.000 [0.700]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Geomancer begins the game with:
+ a Spellbook of Geyser
+ a Mage Staff
diff --git a/lib/mods/theme/help/c_hafted.txt b/lib/mods/theme/help/c_hafted.txt
new file mode 100644
index 00000000..7e8a3f89
--- /dev/null
+++ b/lib/mods/theme/help/c_hafted.txt
@@ -0,0 +1,54 @@
+~~~~~01|Haftedmaster
+~~~~~02|Classes|Haftedmaster
+#####R=== Haftedmasters ===
+
+#####GDescription
+The Haftedmaster is a Warrior who specialises in blunt weapons.
+
+The training is so intense and specific that Haftedmasters gain huge bonuses
+when fighting with their chosen weapon, dependent on their *****skills.txt*06[Hafted-mastery] skill.
+
+In most other respects they perform about as well as a generic Warrior.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.900]
+ Weaponmastery 1.000 [0.950]
+ Sword-mastery 0.000 [0.300]
+ Axe-mastery 0.000 [0.300]
+ Hafted-mastery 1.000 [0.700]
+ Stunning-blows 0.000 [0.500]
+ Polearm-mastery 0.000 [0.300]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+An Haftedmaster begins the game with:
+ a Ring of Fear Resistance
+ a Chain Mail
+ a Flail
diff --git a/lib/mods/theme/help/c_lorema.txt b/lib/mods/theme/help/c_lorema.txt
new file mode 100644
index 00000000..35c2093b
--- /dev/null
+++ b/lib/mods/theme/help/c_lorema.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Loremaster
+~~~~~02|Classes|Loremaster
+#####R=== Loremasters ===
+
+#####GDescription
+Loremasters are students of the creatures of Arda.
+
+To protect themselves during their observations, they usually learn how to
+pass unobserved, but should their attempt fail they have decent saving throws
+and almost always learn some kind of combat style, but the exact preference
+varies from Loremaster to Loremaster.
+
+As a result of their studies, they become familiar with a broad range of
+skills, ranging from *****skills.txt*45[Possession] and *****m_symbio.txt*0[Symbiosis] to *****skills.txt*43[Summoning] and *****skills.txt*47[Mimicry].
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Archery 1.000 [0.700]
+ Barehand-combat 1.000 [0.700]
+Sneakiness 1.000 [0.700]
+ Stealth 1.000 [0.700]
+ Disarming 1.000 [0.700]
+Magic 0.000 [0.600]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.700]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Summoning 0.000 [0.500]
+ Corpse-preservation 1.000 [0.700]
+ Possession 0.000 [0.500]
+ Symbiosis 0.000 [0.500]
+ Mimicry 0.000 [0.500]
+
+#####GStarting Equipment
+A Loremaster begins the game with:
+ a Sling
+ a Hard Leather Armour
+ a Quarterstaff
+ some Rounded Pebbles
diff --git a/lib/mods/theme/help/c_mage.txt b/lib/mods/theme/help/c_mage.txt
new file mode 100644
index 00000000..949d3bcc
--- /dev/null
+++ b/lib/mods/theme/help/c_mage.txt
@@ -0,0 +1,67 @@
+|||||oy
+~~~~~01|Mage
+~~~~~02|Classes|Mage
+#####R=== Mages ===
+
+#####GDescription
+A Mage must live by his wits. He cannot hope to simply hack his way
+through the dungeon, and so must therefore use his magic to defeat,
+deceive, confuse, and escape. A Mage is not really complete without an
+assortment of magical devices to use in addition to his spells. He can
+master the higher level magical devices easily and has good saving throws.
+
+There is no reason a Mage cannot become a good fighter, but spells are
+his true realm. For more information on magic schools and spell effects see
+the *****magic.txt*01[Magic help file].
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.500]
+ Weaponmastery 0.700 [0.500]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.200]
+ Spell-power 0.000 [0.600]
+ Sorcery 0.000 [0.200]
+ Mana 1.000 [0.900]
+ Geomancy
+ Fire 0.000 [0.900]
+ Water 0.000 [0.900]
+ Air 0.000 [0.900]
+ Earth 0.000 [0.900]
+ Meta 0.000 [0.900]
+ Conveyance 0.000 [0.900]
+ Divination 0.000 [0.900]
+ Temporal 0.000 [0.900]
+ Mind 0.000 [0.900]
+ Nature 0.000 [0.900]
+ Necromancy 0.000 [0.700]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Mage cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Mage begins the game with:
+ a Book of Beginner Cantrips
+ a Dagger
diff --git a/lib/mods/theme/help/c_mercen.txt b/lib/mods/theme/help/c_mercen.txt
new file mode 100644
index 00000000..75129d56
--- /dev/null
+++ b/lib/mods/theme/help/c_mercen.txt
@@ -0,0 +1,49 @@
+~~~~~01|Mercenary
+~~~~~02|Classes|Mercenary
+#####R=== Mercenaries ===
+
+#####GDescription
+Mercenaries are daring swashbucklers, masters of the blade. They
+do not have the magical abilities Rogues have, but they are just
+as stealthy and much deadlier with a light sword. They do gain
+some magical mastery over time, but only in the Temporal school.
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom -2
+Dexterity +3
+Constitution +1
+Charisma -1
+Bonus Blows 0
+Hit Die +d6
+Exp Penalty 25%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.700]
+ Weaponmastery 1.000 [0.900]
+ Sword-mastery 1.000 [0.700]
+ Critical-hits 1.000 [0.700]
+Sneakiness 1.000 [2.000]
+ Stealth 1.000 [1.500]
+ Disarming 1.000 [2.000]
+ Backstab 1.000 [1.000]
+ Stealing 1.000 [2.000]
+ Dodging 1.000 [2.000]
+Magic 1.000 [0.700]
+ Magic-Device 1.000 [1.550]
+ Temporal 0.000 [1.000]
+Spirituality 1.000 [0.700]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GStarting Equipment
+A mercenary begins the game with:
+ a rapier
+ a cloak
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra-Max-Blow(1) 10
+Extra-Max-Blow(1) 15 \ No newline at end of file
diff --git a/lib/mods/theme/help/c_merch.txt b/lib/mods/theme/help/c_merch.txt
new file mode 100644
index 00000000..31fb60dd
--- /dev/null
+++ b/lib/mods/theme/help/c_merch.txt
@@ -0,0 +1,29 @@
+#####R=== Merchants ===
+
+#####GDescription
+A Merchant is neither a warrior nor a spellcaster. They still have some great
+advantages, they can use chests to warp items into other items, they can
+indentify items, they soon learn to detect all objects in the area, and
+at higher level they can see all monsters carrying objects. They will also
+get the power to appraise items and to turn them into gold. A merchant will
+naturraly get better prices in shops and get access to the merchant guild
+services, loan and item request.
+
+#####GPrimary Stats
+Charisma
+Intelligence (Ability stat)
+
+#####GMagic Usage
+Merchants can use portable holes to carry more stuff than other classes but
+at the cost of an increased weight. To do that they must wear a portable hole
+and use it with 'm'.
+They also can use their merchants abilities and midas touch in the 'U' menu.
+
+#####GStarting Equipment
+A merchant begins the game with:
+ A portable hole
+ A small steel chest containing gold and items
+ A long sword
+ A wand of tame monsters
+
+
diff --git a/lib/mods/theme/help/c_mimic.txt b/lib/mods/theme/help/c_mimic.txt
new file mode 100644
index 00000000..b9378a03
--- /dev/null
+++ b/lib/mods/theme/help/c_mimic.txt
@@ -0,0 +1,53 @@
+~~~~~01|Mimic
+~~~~~02|Classes|Mimic
+#####R=== Mimics ===
+
+#####GDescription
+Mimics possess the ability to transform into various creatures using
+special cloaks. While transformed, they lose their intrinsic abilities,
+and gain those of the creature they have transformed into.
+
+At higher skill levels, Mimics gain additional Mimicry powers which help them
+to further blend in with their surroundings or modify themselves.
+
+See more on *****m_mimic.txt*0[Mimicry powers].
+
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.800]
+ Archery 1.000 [0.700]
+ Barehand-combat 1.000 [0.600]
+Sneakiness 1.000 [0.800]
+ Stealth 1.000 [0.800]
+ Disarming 1.000 [0.700]
+Magic 1.000 [0.700]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.500]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 1.000 [0.900]
+ Possession 0.000 [0.100]
+ Mimicry 1.000 [0.800]
+
+#####GStarting Equipment
+A Mimic begins the game with:
+ a Mouse Fur
+ a Potion of Healing
+ a Dagger
+
+
+
diff --git a/lib/mods/theme/help/c_mindcr.txt b/lib/mods/theme/help/c_mindcr.txt
new file mode 100644
index 00000000..c4ed2747
--- /dev/null
+++ b/lib/mods/theme/help/c_mindcr.txt
@@ -0,0 +1,57 @@
+|||||oy
+~~~~~01|Mindcrafter
+~~~~~02|Classes|Mindcrafter
+#####R=== Mindcrafters ===
+
+#####GDescription
+The Mindcrafter is a priest who uses the powers of mind instead of magic.
+These abilities vary from simple extrasensory perception to mental domination of
+others. Since these powers are developed by the practice of certain
+disciplines, a Mindcrafter requires no spellbooks to use them.
+The Mindcrafter uses the Mindcraft skill to determine how well she can
+perform these psychic "spells", and available powers are simply determined by
+the skill level. In combat a Mindcrafter is roughly the equivalent of a
+priest.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+Sneakiness 1.000 [1.100]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.150]
+ Spell-power 0.000 [0.600]
+ Necromancy 0.000 [0.400]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [0.900]
+ Mindcraft 1.000 [0.900]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GMindcraft Powers
+Although the powers of a Mindcrafter may seem like magic, this is not
+-- strictly speaking -- the case. They are mental powers, independent
+of the ordinary sources of magic. Consequently, Mindcrafters are not
+interested in 'magic' and learn no spells. These mental powers can be
+accessed through the "m" command, and you can find a full list of their
+powers in the *****m_mindcr.txt*0[Mindcraft powers] document.
+
+#####GStarting Equipment
+A Mindcrafter begins the game with:
+ a Mace
diff --git a/lib/mods/theme/help/c_monk.txt b/lib/mods/theme/help/c_monk.txt
new file mode 100644
index 00000000..87730f18
--- /dev/null
+++ b/lib/mods/theme/help/c_monk.txt
@@ -0,0 +1,87 @@
+|||||oy
+~~~~~01|Monk
+~~~~~02|Classes|Monk
+#####R=== Monks ===
+
+#####GDescription
+The Monk character class is very different from all other classes.
+Although they can use weapons and armour just like any other class,
+their training in martial arts makes them much more powerful with no
+armour nor weapons.
+
+As the Monk's skill level rises, new and more powerful forms of attack become
+available. It is also rumoured that the monastic training makes experienced
+monks faster than any other character class!
+
+A Monk might need to wear some kind of armour to gain the resistances necessary
+for survival at higher levels, but if that armour is too heavy, it will
+severely disturb his/her martial arts maneuvers.
+
+If skill points are invested in *****skills.txt*20[Dodging], a Monk's defensive capabilities
+(blocking and dodging) will also increase. However, if armour is being worn,
+dodging is much less effective. Fortunately, a Monk can increase his/her
+ability to fight while still wearing armor by increasing his/her
+*****skills.txt*13[Barehanded-combat] skill.
+
+Monks also have access to the schools of *****m_meta.txt*0[Meta],
+*****m_tempo.txt*0[Temporal] and *****m_mind.txt*0[Mind] magic.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 0.000 [0.900]
+ Weaponmastery 0.000 [0.300]
+ Archery 0.000 [0.400]
+ Barehand-combat 1.000 [0.900]
+Sneakiness 1.000 [0.900]
+ Stealth 1.000 [0.900]
+ Disarming 1.000 [0.900]
+ Dodging 0.000 [0.700]
+Magic 0.000 [0.600]
+ Magic-Device 1.000 [1.000]
+ Meta 0.000 [0.500]
+ Temporal 0.000 [0.500]
+ Mind 0.000 [0.500]
+Spirituality 1.000 [0.900]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 1.000 [0.500]
+ Possession 0.000 [0.100]
+
+#####GStarting Equipment
+A Monk begins the game with:
+ a Potion of Healing
+ a Soft Leather Armour
+~~~~~03|Monk|Monk attacks
+~~~~~04|Tables|Monk attacks
+#####GMonk Attacks
+#####BAttack Name Min.lvl Damage Stun Notes
+-----------------------------------------------------------------------------
+Punch 1 1d4 -
+Kick 2 1d6 -
+Strike 3 1d7 -
+Knee 5 2d3 * Painful to males; likely to stun them
+Elbow 7 1d8 -
+Butt 9 2d5 -
+Ankle Kick 11 3d4 - May slow down the opponent
+Uppercut 13 4d4 6
+Double-kick 16 5d4 8
+Cat's Claw 20 5d5 -
+Jump Kick 25 5d6 10
+Eagle's Claw 29 6d6 -
+Circle Kick 33 6d8 10
+Iron Fist 37 8d8 10
+Flying Kick 41 8d10 12
+Dragon Fist 45 10d10 16
+Crushing Blow 48 10d12 18
diff --git a/lib/mods/theme/help/c_necro.txt b/lib/mods/theme/help/c_necro.txt
new file mode 100644
index 00000000..f3a5ad2c
--- /dev/null
+++ b/lib/mods/theme/help/c_necro.txt
@@ -0,0 +1,80 @@
+|||||oy
+~~~~~01|Necromancer
+~~~~~02|Classes|Necromancer
+#####R=== Necromancers ===
+
+#####GDescription
+As a Priest devotes his life to his chosen deity, so Necromancers
+devote their lives to the study of death. Familiar with all of the
+forms of unbeing, they are able to manipulate spirit and flesh for
+great effect.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.400]
+ Weaponmastery 0.700 [0.600]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.200]
+ Spell-power 0.000 [0.600]
+ Mana 0.000 [0.600]
+ Geomancy
+ Fire 0.000 [0.800]
+ Water 0.000 [0.700]
+ Air 0.000 [0.700]
+ Earth 0.000 [0.800]
+ Meta 0.000 [0.700]
+ Conveyance 0.000 [0.700]
+ Divination 0.000 [0.700]
+ Temporal 0.000 [0.800]
+ Mind 0.000 [0.900]
+ Nature 0.000 [0.500]
+ Necromancy 1.000 [1.000]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 5.000 [0.900]
+
+*A Necromancer cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+Undead Form 25
+
+#####GStarting Equipment
+A Necromancer begins the game with:
+ a Book of Beginner Cantrips
+ a Dagger
+
+#####GNecromancy
+*****m_necrom.txt*0[Necromancy powers] [[[[[Bare accessed using the 'm' key.]
+Even from the start of his career, an inexperienced Necromancer
+can channel forces from the underworld to assault the mind of
+living creatures, therefore terrifying them. With little effort he
+can also learn the art of reanimating a dead corpse, turning it into
+an undead slave. It is only at a later point in his career that this
+foul mage learns to manipulate his life force as well, gaining the
+ability to absorb hit points from both living and dead opponents.
+The greatest Necromancers even gain the ability to survive their own
+death: when they should be killed, they instead turn into a ghostly
+being; they then receive a set number of Death Points, which are in
+all respects similar to hit points except that they go automatically
+down each turn. If the Necromancer manages to kill a certain number
+of creatures before his Death Points reach 0 he is returned to life;
+otherwise his will dissipates and he finally achieves true death.
diff --git a/lib/mods/theme/help/c_pacif.txt b/lib/mods/theme/help/c_pacif.txt
new file mode 100644
index 00000000..7ec7e7d1
--- /dev/null
+++ b/lib/mods/theme/help/c_pacif.txt
@@ -0,0 +1,10 @@
+~~~~~01|Pacifist
+~~~~~02|Classes|Pacifist
+#####R=== Pacifists ===
+
+#####GDescription
+A Pacifist is someone who prefers not to use violence to
+achieve their ends. There are two types of Pacifists:
+
+*****c_peacemag.txt*0[Peace-mage]
+*****c_trapper.txt*0[Trapper] \ No newline at end of file
diff --git a/lib/mods/theme/help/c_palad.txt b/lib/mods/theme/help/c_palad.txt
new file mode 100644
index 00000000..b4cc650b
--- /dev/null
+++ b/lib/mods/theme/help/c_palad.txt
@@ -0,0 +1,49 @@
+|||||oy
+~~~~~01|Paladin
+~~~~~02|Classes|Paladin
+~~~~~03|Tulkas|Paladin
+#####R=== Paladins ===
+
+#####GDescription
+A Paladin is a warrior-priest at the service of *****g_tulkas.txt*0[Tulkas]. As such, his duty
+is to be ever vigilant against the forces of evil and even seek and destroy
+those monsters which are evil to the core, especially the foulest
+spawns of hell. Luckily, his quest is eased by the blessing bestowed
+by Tulkas himself.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.800]
+ Weaponmastery 1.000 [0.800]
+ Barehand-combat 0.000 [0.900]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.600]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.400]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+Extra Max Blow(1) 1
+
+#####GStarting Equipment
+A Paladin begins the game with:
+ a Spellbook of Divine Aim
+ a Two-Handed Sword
diff --git a/lib/mods/theme/help/c_peacemag.txt b/lib/mods/theme/help/c_peacemag.txt
new file mode 100644
index 00000000..f75664f3
--- /dev/null
+++ b/lib/mods/theme/help/c_peacemag.txt
@@ -0,0 +1,46 @@
+~~~~~01|Peace-mage
+~~~~~02|Classes|Peace-mage
+#####R=== Peace-mages ===
+
+#####GDescription
+A Pacifist is someone who prefers not to use violence to
+achieve their ends. The peace-mages choose to use defensive
+spells and rely on symbiosis to protect themselves. They
+may also use spells provided by their deities.
+
+#####GStarting Stat Modifiers
+Strength 0
+Intelligence +2
+Wisdom +2
+Dexterity +2
+Constitution 0
+Charisma +4
+Bonus Blows 0
+Hit Die 0
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Sneakiness 0.000 [0.600]
+ Stealth 0.000 [0.600]
+ Disarming 1.000 [0.600]
+ Dodging 1.000 [0.700]
+Magic 1.000 [0.600]
+ Spell-power 0.000 [0.500]
+ Meta 0.000 [0.700]
+ Conveyance 1.000 [0.700]
+ Divination 0.000 [0.700]
+ Temporal 0.000 [0.700]
+ Nature 1.000 [1.000]
+Spirituality 0.000 [0.700]
+ Prayer 0.000 [0.500]
+Monster-lore 1.000 [0.900]
+ Symbiosis 1.000 [0.600]
+
+#####GStarting Equipment
+A peace-mage begins the game with:
+ a scroll of summon never-moving pet
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 15 \ No newline at end of file
diff --git a/lib/mods/theme/help/c_polear.txt b/lib/mods/theme/help/c_polear.txt
new file mode 100644
index 00000000..8ea2f04a
--- /dev/null
+++ b/lib/mods/theme/help/c_polear.txt
@@ -0,0 +1,52 @@
+~~~~~01|Polearmmaster
+~~~~~02|Classes|Polearmmaster
+#####R=== Polearmmasters ===
+
+#####GDescription
+The Polearmmaster is a Warrior who specialises in polearms.
+
+The training is so intense and specific that Polearmmasters gain huge bonuses
+when fighting with their chosen weapon, dependent on their Polearm-mastery
+skill. In most other respects they perform about as well as a generic Warrior.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.900]
+ Weaponmastery 1.000 [0.950]
+ Sword-mastery 0.000 [0.300]
+ Axe-mastery 0.000 [0.300]
+ Hafted-mastery 0.000 [0.300]
+ Polearm-mastery 1.000 [0.700]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+A Polearmmaster begins the game with:
+ a Ring of Fear Resistance
+ a Chain Mail
+ a Pike
diff --git a/lib/mods/theme/help/c_posses.txt b/lib/mods/theme/help/c_posses.txt
new file mode 100644
index 00000000..2d67a883
--- /dev/null
+++ b/lib/mods/theme/help/c_posses.txt
@@ -0,0 +1,70 @@
+~~~~~01|Possessor
+~~~~~02|Classes|Possessor
+#####R=== Possessors ===
+
+#####GDescription
+Possessors are unusual; they aren't good fighters, and they can't cast
+magic. Their special ability is that of being able to leave their
+bodies and inhabit corpses. While "in" a corpse, the Possessor gains
+the abilities of the monster, and their hit points and the monster's
+are averaged. (Most monsters have no, or very few, spell points.) While
+in the incorporeal form between bodies, they have only one hitpoint.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution +0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.600]
+ Weaponmastery 1.000 [0.600]
+ Archery 1.000 [0.400]
+Sneakiness 1.000 [0.700]
+ Stealth 1.000 [0.700]
+ Disarming 1.000 [0.500]
+Magic 0.000 [0.600]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.500]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 1.000 [0.900]
+ Possession 1.000 [0.800]
+
+#####GStarting Equipment
+A Possessor begins the game with:
+ a Potion of Healing
+ a Short Sword
+ a Hard Leather Armour
+
+~~~~~03|Possessor|Possessor powers
+~~~~~04|Skills|Possession - Possessor powers
+#####GPossession
+The strange art of reanimating the corpse of a monster and making
+it one's own can be of extreme benefit to those skilled in it. The body
+the player possesses can grant powerful abilities, such as increased
+speed, summoning, healing, breathing, and various resistances, and often
+gives the player a large number of hit points. Possessing uniques is
+especially neat.
+
+Possessors leave their own body by using the 'm' command, and choosing
+"[I]incarnating powers". Lacking a life force to sustain it, a corpse may rot
+immediately when a Possessor leaves it, but a high Possession skill score
+may prevent this from happening. They then become a very vulnerable ghostly
+being which travels to where another corpse is lying on the floor, and
+possesses it by again using the 'm' command. Once possessed, many
+monster corpses allow the player to perform various special actions
+(such as blinking or summoning) by using the option "Use your [R]ace
+powers".
+
+All corpses alter the player's melee attacks. When they incarnate in a
+monster that allows the use of a weapon, monster blows are ignored
+[[[[[Btotally]. When they incarnate in a monster that doesn't allow use of a
+weapon (dragons for example) they use the monster blows [[[[[Band only them]!
diff --git a/lib/mods/theme/help/c_pr_drk.txt b/lib/mods/theme/help/c_pr_drk.txt
new file mode 100644
index 00000000..fa99f89f
--- /dev/null
+++ b/lib/mods/theme/help/c_pr_drk.txt
@@ -0,0 +1,57 @@
+|||||oy
+~~~~~01|Dark Priest
+~~~~~02|Classes|Dark Priest
+~~~~~03|Melkor|Dark Priests
+#####R=== Melkor's Priests ===
+
+#####GDescription
+All gods have priests; but those serving *****g_melkor.txt*0[Melkor], the dark enemy, are not
+like their good counterparts. While usually it takes devotion and awe to be
+inspired into serving a deity, Melkor's followers revere him because of the
+power he gives them. Some of them may even be so ambitious as to aspire to
+take his place upon the black throne of Angband. This he knows very well, but
+as long as he can use those puny mortals to inspire fear into the followers of
+the Valar and to bring destruction to Arda, he doesn't mind; he even lends power
+to the ones more bent on destruction, while sapping their minds to reduce them
+to unthinking slaves.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.800]
+**Udun 0.000 [0.400]
+ Necromancy 0.000 [0.800]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.400]
+Monster-lore 0.000 [0.500]
+ Corpse-preservation 1.000 [1.000]
+
+**Actually, every character has this level of proficiency with the *****m_udun.txt*0[Udun] school,
+provided they are worshipping Melkor
+
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Priest serving Melkor begins the game with:
+ a Spellbook of Curse
+ a Mace
diff --git a/lib/mods/theme/help/c_pr_eru.txt b/lib/mods/theme/help/c_pr_eru.txt
new file mode 100644
index 00000000..ff5a0126
--- /dev/null
+++ b/lib/mods/theme/help/c_pr_eru.txt
@@ -0,0 +1,55 @@
+|||||oy
+~~~~~01|Priest - Eru
+~~~~~02|Classes|Priest - Eru
+~~~~~03|Eru|Priest - Eru
+#####R=== Eru's Priests ===
+
+#####GDescription
+*****g_eru.txt*0[Eru] is the father of the Valar: he created the world and all its inhabitants. He is the wisest being ever and even if he foresaw Morgoth's
+evil, his role was that of the creator; as such, he chose not to destroy
+anything on Arda.
+
+His priests are therefore expected to avoid all forms of bloodshed (so they
+can only use blunt weapons without penalty); however, Eru knows that sometimes
+destruction is unavoidable and marks a blade with his rune; his priests call
+them Blessed and use them without feeling guilty, for they know that divine
+wisdom will guide every swing of those weapons.
+
+Still, a priest serving Eru will find that his true strength lies in knowledge
+and in the use of the force of Mana to avoid close contact with evil beings,
+rather than in blind assault of Morgoth's hordes.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.700]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Priest serving Eru begins the game with:
+ a Spellbook of See the Music
+ a Mace
diff --git a/lib/mods/theme/help/c_pr_man.txt b/lib/mods/theme/help/c_pr_man.txt
new file mode 100644
index 00000000..3f83e8af
--- /dev/null
+++ b/lib/mods/theme/help/c_pr_man.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Priest - Manwe
+~~~~~02|Classes|Priest - Manwe
+~~~~~03|Manwe|Priest - Manwe
+#####R=== Manwe's Priests ===
+
+#####GDescription
+As the forces of darkness arose, *****g_manwe.txt*0[Manwe], lord of air, realised that urgent
+action was needed to save Arda from the incoming darkness. So he started
+gathering followers from the ranks of men and elves and he instructed them to
+do battle against the forces of Udun.
+
+His priests must be quick and strike before the situation becomes
+critical, always keeping a direct line of prayer with their patron deity.
+
+Manwe doesn't tolerate laziness, but He also does not appreciate mindless
+killing; only a few measure up to his standards, but those are granted access
+to a whole series of divine powers which will help them in their enduring
+efforts.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Hit Die +d2
+Spell Points +0%
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.750]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.600]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Priest serving Manwe begins the game with:
+ a Spellbook of Manwe's Blessing
+ a Mace
diff --git a/lib/mods/theme/help/c_pr_mand.txt b/lib/mods/theme/help/c_pr_mand.txt
new file mode 100644
index 00000000..df98e911
--- /dev/null
+++ b/lib/mods/theme/help/c_pr_mand.txt
@@ -0,0 +1,49 @@
+|||||oy
+~~~~~01|Priest - Mandos
+~~~~~02|Classes|Priest - Mandos
+~~~~~03|Mandos|Priest - Mandos
+#####R=== Priests of Mandos ===
+
+#####GDescription
+*****g_mandos.txt*0[Mandos] is the Doomsman of the Valar, Lord of
+the House of the Dead and he recalls the souls of the fallen ones.
+A Master of Spirit, he knows all that is going to happen, except
+that which lies in the will of Eru himself. Manwe calls upon Mandos
+to pass judgment upon the Ainur and Eru's children alike. The priests
+of Mandos fight righteously to rid the world of evil.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Bonus Blows 0
+Hit Die +d2
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Hafted-mastery 0.000 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.800]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect-casting 1
+
+#####GStarting Equipment
+A priest serving Varda begins the game with:
+ A spellbook of Tears of Luthien
+ A mace \ No newline at end of file
diff --git a/lib/mods/theme/help/c_pr_ulmo.txt b/lib/mods/theme/help/c_pr_ulmo.txt
new file mode 100644
index 00000000..6f82b368
--- /dev/null
+++ b/lib/mods/theme/help/c_pr_ulmo.txt
@@ -0,0 +1,50 @@
+|||||oy
+~~~~~01|Priest - Ulmo
+~~~~~02|Classes|Priest - Ulmo
+~~~~~03|Ulmo|Priest - Ulmo
+#####R=== Ulmo's Priests ===
+
+#####GDescription
+*****g_ulmo.txt*0[Ulmo] is the Lord of the Waters, second in power only
+to Manwe, and the most wrathful of the Valar after Tulkas Astaldo. He
+made a great contribution to the War of Wrath when he led Tuor to Gondolin,
+and he is ever watchful for the contrivances of Melkor Bauglir. His
+preferred weapon type is the polearm, and his priests learn to become
+very proficient with it. A priest of Ulmo is like unto living
+water, channelled through Ulmo's magic.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Bonus Blows 0
+Hit Die +d2
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Polearm-mastery 0.000 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.800]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect-casting 1
+
+#####GStarting Equipment
+A priest serving Ulmo begins the game with:
+ A spellbook of Song of Belegaer
+ A trident \ No newline at end of file
diff --git a/lib/mods/theme/help/c_pr_varda.txt b/lib/mods/theme/help/c_pr_varda.txt
new file mode 100644
index 00000000..f6473df4
--- /dev/null
+++ b/lib/mods/theme/help/c_pr_varda.txt
@@ -0,0 +1,50 @@
+|||||oy
+~~~~~01|Priest - Varda
+~~~~~02|Classes|Priest - Varda
+~~~~~03|Varda|Priest - Varda
+#####R=== Varda's Priests ===
+
+#####GDescription
+*****g_varda.txt*0[Varda] is called Elentari, which means The Queen
+of the Stars. She set the stars in the sky, for which the Eldar of
+Middle-earth revered her, calling her by the name of Elbereth. Her
+priests battle the darkness with light, and also have access to the
+Mana and Meta schools of magic by the grace of Varda. Varda prefers
+it if her servants do not get too close to the Shadow, and thus she
+grants a bonus in Archery to her priests.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Bonus Blows 0
+Hit Die +d2
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Archery 0.000 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.800]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect-casting 1
+
+#####GStarting Equipment
+A priest serving Varda begins the game with:
+ A spellbook of Light of Valinor
+ A mace \ No newline at end of file
diff --git a/lib/mods/theme/help/c_priest.txt b/lib/mods/theme/help/c_priest.txt
new file mode 100644
index 00000000..1eb7bcbb
--- /dev/null
+++ b/lib/mods/theme/help/c_priest.txt
@@ -0,0 +1,17 @@
+|||||oy
+~~~~~01|Priests
+#####R=== Priests ===
+
+#####GDescription
+There are 10 separate classes of Priest:
+
+*****c_pr_eru.txt*0[Priest(Eru)]
+*****c_pr_man.txt*0[Priest(Manwe)]
+*****c_pr_ulmo.txt*0[Priest(Ulmo)]
+*****c_pr_mand.txt*0[Priest(Mandos)]
+*****c_pr_varda.txt*0[Priest(Varda)]
+*****c_druid.txt*0[Druid]
+*****c_palad.txt*0[Paladin]
+*****c_stonewr.txt*0[Stonewright]
+*****c_pr_drk.txt*0[Dark-Priest]
+*****c_mindcr.txt*0[Mindcrafter]
diff --git a/lib/mods/theme/help/c_ranger.txt b/lib/mods/theme/help/c_ranger.txt
new file mode 100644
index 00000000..81af7715
--- /dev/null
+++ b/lib/mods/theme/help/c_ranger.txt
@@ -0,0 +1,56 @@
+|||||oy
+~~~~~01|Ranger
+~~~~~02|Classes|Ranger
+#####R=== Rangers ===
+
+#####GDescription
+Rangers are warrior-mages, devoted to nature. They are good fighters
+and quite effective with bows; their magic often allows them to avoid
+the worst of situations, but they have only a mild chance of resisting
+magical effects and are not terribly stealthy. They can, however,
+learn the ability to summon aid using totems.
+
+They have access to the schools of *****m_divin.txt*0[Divination] and *****m_nature.txt*0[Nature] magic.
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom +0
+Dexterity +2
+Constitution +1
+Charisma +1
+Hit Die +d4
+Spell Points +0%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.700]
+ Archery 1.000 [0.750]
+ Sling-mastery 0.000 [0.300]
+ Bow-mastery 0.000 [0.300]
+ Crossbow-mastery 0.000 [0.300]
+ Boomerang-mastery 0.000 [0.300]
+Sneakiness 1.000 [0.950]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [1.600]
+Magic 1.000 [0.700]
+ Magic-Device 1.000 [1.100]
+ Divination 0.000 [0.500]
+ Nature 0.000 [0.500]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.900]
+ Summoning 0.000 [0.300]
+
+
+#####GInnate Abilities:
+#####BAbility Character level
+Ammo creation 2
+
+#####GStarting Equipment
+A Ranger begins the game with:
+ a Short Sword
+ a Short Bow
+ some Arrows
diff --git a/lib/mods/theme/help/c_rogue.txt b/lib/mods/theme/help/c_rogue.txt
new file mode 100644
index 00000000..b42df3d5
--- /dev/null
+++ b/lib/mods/theme/help/c_rogue.txt
@@ -0,0 +1,62 @@
+|||||oy
+~~~~~01|Rogue
+~~~~~02|Classes|Rogue
+#####R== Rogues ===
+
+#####GDescription
+A rogue is a jack of all trades, but the master of none. With the notable
+exception of Archery and Monster-related skills, Rogues are capable of adapting
+to almost any situation. Their strong point lies in stealth and careful
+planning: Where a Warrior would simply hack away (and risk being hacked up
+himself) or a Mage would Manathrust, a Rogue would awaken a monster with a
+dagger in the back, or would wait for the creature to be killed by the line of
+traps she had previously laid between her and her opponent.
+
+Rogues have access to the schools of *****m_convey.txt*0[Conveyance], *****m_divin.txt*0[Divination] and *****m_tempo.txt*0[Temporal] magic.
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom -2
+Dexterity +3
+Constitution +1
+Charisma -1
+Hit Die +d6
+Spell Points +0%
+Exp Penalty 25%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Sword-mastery 1.000 [0.300]
+ Critical-hits 1.000 [0.500]
+Sneakiness 1.000 [2.000]
+ Stealth 1.000 [1.500]
+ Disarming 1.000 [2.000]
+ Backstab 1.000 [1.000]
+ Stealing 1.000 [2.000]
+ Dodging 1.000 [2.000]
+Magic 1.000 [0.700]
+ Magic-Device 1.000 [1.550]
+ Conveyance 0.000 [0.500]
+ Divination 0.000 [0.500]
+ Temporal 0.000 [0.500]
+Spirituality 1.000 [0.700]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Trapping 1
+Extra Max Blow(1) 10
+
+#####GStarting Equipment
+A Rogue begins the game with:
+ a Dagger
+ a Catapult Trap Set
+ some Iron Shots
+
+
+
+
diff --git a/lib/mods/theme/help/c_runecr.txt b/lib/mods/theme/help/c_runecr.txt
new file mode 100644
index 00000000..8388eff9
--- /dev/null
+++ b/lib/mods/theme/help/c_runecr.txt
@@ -0,0 +1,110 @@
+~~~~~01|Runecrafter
+~~~~~02|Classes|Runecrafter
+#####R=== Runecrafters ===
+
+#####GDescription
+Instead of using spellbooks like the other spellcasters they instead
+use mystic runes. To cast a spell they select a primary rune of the
+elements (fire, cold, etc.) and they also choose a set of secondary runes,
+which shape the effect of the first one. The secondary runes include
+Self, Arrow, Ray, ... and Armageddon. After that they chose the amount
+of mana to use and the spell is cast! But the more secondary runes they
+chose the more mana is used to cast the spell. They also are bad
+fighters, but if they concentrate all their mana in one spell
+(especially with a mage staff of mana) they could kill nearly anything.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.200]
+ Weaponmastery 0.700 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 2.000 [0.950]
+ Magic-Device 1.000 [1.200]
+ Spell-power 0.000 [0.600]
+ Mana 1.000 [0.600]
+ Geomancy
+ Fire 0.000 [0.700]
+ Water 0.000 [0.700]
+ Air 0.000 [0.700]
+ Earth 0.000 [0.700]
+ Meta 0.000 [0.700]
+ Conveyance 0.000 [0.700]
+ Divination 0.000 [0.700]
+ Temporal 0.000 [0.700]
+ Mind 0.000 [0.700]
+ Nature 0.000 [0.700]
+ Necromancy 0.000 [0.700]
+ Runecraft 1.000 [1.000]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Runecrafter cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+~~~~~03|Runecrafter|Runecrafter powers
+~~~~~04|Skills|Runecrafting - Runecrafter powers
+#####GRune Magic
+Runecrafters combine runes using the 'm' command. They first select a
+rune that controls magic type, then apply one or more runes to fine-tune
+effects, (pressing ESC when done), and then input the amount of mana
+they wish to expend on the spell.
+
+Runecrafters can cast the spells from their runes in several ways:
+1. On-the-fly by combining runes when they need them.
+2. Memorise rune combinations for quick use when needed (and they don't
+ need to be able to see then!), and then later cast from memory.
+3. Carving them into a Runestone, then using the Runestone later (takes
+ less mana, but they have to be able to see).
+
+[[[[[BSpell Types:]
+(Some kinds are not listed, and are left for the reader to discover...)
+ Knowledge: Identify all objects in affected grids, Self-knowledge
+ if Self rune is used.
+ Life: Heals monsters in affected grids, heals player if Self rune
+ is used.
+ Fire, Cold, Lightning, Acid: Casts magics of that element.
+ Elements: Irresistible damage.
+ Mind: A mind blast that badly effects intelligent monsters.
+ Temporary ESP if Self rune is used.
+ Gravity: A gravity spell that both does damage and whisks affected
+ creatures around.
+
+[[[[[BSpell Effects] (all are listed):
+ Self: Effects the caster. This rune can be used with any other;
+ if used alone, only the caster's grid is affected.
+ Arrow: Spell will include a bolt effect. This allows aiming.
+ Ray: Spell will include a beam effect. This allows aiming.
+ Increases difficulty slightly.
+ Sphere: Spell will end with a circular explosion. Increases
+ difficulty a bit. Can be used alone, or with Self, Arrow, or
+ Ray.
+ Power Surge: Not currently recommended for use. Increases
+ difficulty a lot.
+ Armageddon: Hurls down meteors of the magical type in the vicinity
+ of the caster. Increases difficulty noticeably, but can do a
+ great deal of damage.
+
+#####GStarting Equipment
+A Runecrafter begins the game with:
+ a Rune [Fire]
+ a Rune [Arrow]
+ a Dagger
+
diff --git a/lib/mods/theme/help/c_sniper.txt b/lib/mods/theme/help/c_sniper.txt
new file mode 100644
index 00000000..008202d8
--- /dev/null
+++ b/lib/mods/theme/help/c_sniper.txt
@@ -0,0 +1,50 @@
+~~~~~01|Sniper
+~~~~~02|Classes|Sniper
+#####R=== Snipers ===
+
+#####GDescription
+Snipers are stealthy archers who kill from a safe
+distance and aren't very good at hand-to-hand combat.
+They have some ability in the Conveyance school of
+magic, which can let them disappear quickly if the
+need should arise.
+
+#####GStarting Stat Modifiers
+Strength +2
+Intelligence +1
+Wisdom +0
+Dexterity +2
+Constitution +1
+Charisma +1
+Bonus Blows 0
+Hit Die +d4
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.500]
+ Weaponmastery 1.000 [0.500]
+ Archery 1.000 [0.750]
+ Sling-mastery 0.000 [0.300]
+ Bow-mastery 0.000 [0.300]
+ Crossbow-mastery 0.000 [0.300]
+ Boomerang-mastery 0.000 [0.300]
+Sneakiness 2.000 [1.000]
+ Stealth 1.000 [0.700]
+ Disarming 1.000 [1.000]
+ Backstab 1.000 [0.700]
+Magic 1.000 [0.600]
+ Magic-Device 1.000 [1.100]
+ Conveyance 1.000 [0.500]
+Spirituality 0.000 [0.500]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GStarting Equipment
+A sniper begins the game with:
+ a short bow
+ some ammo
+
+#####GInnate Abilities:
+#####BAbility Character level
+Ammo creation 2 \ No newline at end of file
diff --git a/lib/mods/theme/help/c_sorcer.txt b/lib/mods/theme/help/c_sorcer.txt
new file mode 100644
index 00000000..8a33184f
--- /dev/null
+++ b/lib/mods/theme/help/c_sorcer.txt
@@ -0,0 +1,68 @@
+|||||oy
+~~~~~01|Sorceror
+~~~~~02|Classes|Sorceror
+#####R=== Sorcerors ===
+
+#####GDescription
+Sorcerors are to magic what Unbelievers are to melee. They are the all-
+around best magicians, being able to cast spells from any school using
+only a single skill. They cannot comfortably use any weapon but a Mage Staff, and even with a Mage Staff, they will be unable to achieve anything remotely resembling battle effectiveness.
+
+The energies used for learning Sorcery also sap the life force of a
+Sorceror, penalising them with the loss of a percentage of their hit
+points equal to their Sorcery skill score and penalising their combat
+ability even more strongly.
+
+For more information on magic schools and spell effects see the
+*****magic.txt*01[Magic help file].
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [1.000]
+ Magic-Device 1.000 [1.000]
+ Spell-power 0.000 [0.600]
+ Sorcery 1.000 [0.700]
+ Mana 0.000 [0.900]
+ Geomancy
+ Fire 0.000 [1.000]
+ Water 0.000 [1.000]
+ Air 0.000 [1.000]
+ Earth 0.000 [1.000]
+ Meta 0.000 [1.000]
+ Conveyance 0.000 [1.000]
+ Divination 0.000 [1.000]
+ Temporal 0.000 [1.000]
+ Mind 0.000 [1.000]
+ Nature 0.000 [1.000]
+ Necromancy 0.000 [1.000]
+ Runecraft 0.000 [0.900]
+ Thaumaturgy 0.000 [0.900]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Sorceror cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Sorceror begins the game with:
+ a Book of Beginner Cantrips
+ a Robe
+
diff --git a/lib/mods/theme/help/c_stonewr.txt b/lib/mods/theme/help/c_stonewr.txt
new file mode 100644
index 00000000..7de1c0ef
--- /dev/null
+++ b/lib/mods/theme/help/c_stonewr.txt
@@ -0,0 +1,50 @@
+|||||oy
+~~~~~01|Stonewright
+~~~~~02|Classes|Stonewright
+~~~~~03|Aule|Stonewright
+#####R=== Aule's Priests ===
+
+#####GDescription
+*****g_aule.txt*0[Aule] the Smith is concerned with the substance of
+Arda; rock and metal. His priests serve him best by forging better
+weapons to use in the fight against the Dark, and his most beloved
+weapon is the axe, which his followers will find much easier to use
+than other types of weapons. Aule's realms are earth and fire, and
+his priests have access to these realms by the grace of their Vala.
+
+#####GStarting Stat Modifiers
+Strength -1
+Intelligence -3
+Wisdom +3
+Dexterity -1
+Constitution +0
+Charisma +2
+Bonus Blows 0
+Hit Die +d2
+Exp Penalty 20%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.700]
+ Weaponmastery 1.000 [0.700]
+ Axe-mastery 0.000 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 0.000 [0.900]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.800]
+Spirituality 1.000 [1.000]
+ Prayer 1.000 [1.500]
+ Mindcraft 0.000 [0.600]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect-casting 1
+Extra Max Blow(1) 10
+
+#####GStarting Equipment
+A priest serving Aule begins the game with:
+ A spellbook of Firebrand
+ A light war axe \ No newline at end of file
diff --git a/lib/mods/theme/help/c_summon.txt b/lib/mods/theme/help/c_summon.txt
new file mode 100644
index 00000000..a3eca1de
--- /dev/null
+++ b/lib/mods/theme/help/c_summon.txt
@@ -0,0 +1,80 @@
+~~~~~01|Summoners
+~~~~~02|Classes|Summoners
+#####R=== Summoners ===
+
+#####GDescription
+A Summoner is, with one exception, a fairly weak class. While he starts
+out a decent enough fighter, his fighting skill doesn't improve that much,
+he doesn't cast magic and has little in the way of survival skills. However,
+this weakness doesn't trouble him much, because he can summon creatures to
+do his bidding and still gain experience from their kills.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution 0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.600]
+ Weaponmastery 1.000 [0.600]
+ Archery 1.000 [0.400]
+Sneakiness 1.000 [0.700]
+ Stealth 1.000 [0.700]
+ Disarming 1.000 [0.500]
+Magic 1.000 [0.800]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.500]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 16.000 [1.200]
+ Summoning 1.000 [0.700]
+ Corpse-preservation 1.000 [1.000]
+
+#####GStarting Equipment
+A Summoner starts the game with:
+ A Potion of Healing
+ A Short Sword
+ A Suit of Hard Leather Armour
+~~~~~03|Summoners|Summoning
+~~~~~04|Skills|Summoning - Summoning powers
+#####GSummoning
+[[[[[BThe summoner's powers of invocation are accessed using the 'm' key.]
+In order to invoke a monster, a summoner must possess a related totem.
+
+There are two kinds of summoning, decided by the totem used:
+
+[[[[[BPartial Summoning]
+Partial summoning creates a simulacrum of the monster, with little will
+of its own. The Summoner must maintain the simulacrum using mana; when
+he runs out, or stops paying the mana, the simulacrum vanishes.
+
+[[[[[BTrue Summoning]
+True summoning is quite different in effect from Partial Summoning, but the
+two are closely related in usage. A True Totem conjures a full copy of the
+creature in question; the process tends to make the monster a loyal ally to
+the summoner, but this loyalty is not guaranteed, nor is the survival of the
+totem used in the summoning.
+
+[[[[[BTotem Creation]
+In order to summon any creature, the Summoner needs a totem. Totems cannot be
+found; they must be created through a special process which involves taking
+the corpse of a creature (the summoner need not have been involved in the
+death of the creature in question), and extracting certain essences from it.
+
+The summoner can create a totem using the 'm' command, and unless one is
+working on a unique's corpse, must choose whether the resulting totem is a
+Partial or True Totem.
+
+[[[[[BImportant Note]
+Uniques are very willful creatures by definition, and thus have three special
+rules about their summoning:
+1. No partial totem can be made from a unique's corpse.
+2. The totem in question is always destroyed.
+3. The unique is twice as likely to be disloyal.
diff --git a/lib/mods/theme/help/c_swordm.txt b/lib/mods/theme/help/c_swordm.txt
new file mode 100644
index 00000000..a3b5ed05
--- /dev/null
+++ b/lib/mods/theme/help/c_swordm.txt
@@ -0,0 +1,52 @@
+~~~~~01|Swordmasters
+~~~~~02|Classes|Swordmasters
+#####R=== Swordmasters ===
+
+#####GDescription
+The Swordmaster is a Warrior who specialises in swords.
+
+The training is so intense and specific that Swordmasters gain huge bonuses
+when fighting with their chosen weapon, dependent on their Sword-mastery skill.
+In most other respects they perform about as well as a generic Warrior.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.900]
+ Weaponmastery 1.000 [0.950]
+ Sword-mastery 1.000 [0.700]
+ Axe-mastery 0.000 [0.300]
+ Hafted-mastery 0.000 [0.300]
+ Polearm-mastery 0.000 [0.300]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread-blows 25
+
+#####GStarting Equipment
+A Swordmaster begins the game with:
+ a Ring of Fear Resistance
+ a Chain Mail
+ a Broad Sword
diff --git a/lib/mods/theme/help/c_symbia.txt b/lib/mods/theme/help/c_symbia.txt
new file mode 100644
index 00000000..9bbd92fd
--- /dev/null
+++ b/lib/mods/theme/help/c_symbia.txt
@@ -0,0 +1,68 @@
+|||||oy
+~~~~~01|Symbiant
+~~~~~02|Classes|Symbiant
+#####R=== Symbiants ===
+
+#####GDescription
+Symbiants live in harmony with all of the monsters that do not move:
+the Mushrooms, Molds, Floating Eyes, and such. They can hypnotise these
+creatures and then form a symbiotic relationship. Using other symbiotic
+powers, they can even use the magical abilities of their pets.
+
+Once hypnotised, the monster is placed onto the body, or "worn" in order to
+initiate the symbiotic relationship.
+
+#####GStarting Stat Modifiers
+Strength +1
+Intelligence -2
+Wisdom +1
+Dexterity +1
+Constitution 0
+Charisma +1
+Hit Die +d8
+Spell Points +0%
+Exp Penalty 40%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.800]
+ Weaponmastery 1.000 [0.800]
+ Archery 1.000 [0.700]
+ Barehand-combat 1.000 [0.600]
+Sneakiness 1.000 [0.800]
+ Stealth 1.000 [0.800]
+ Disarming 1.000 [0.700]
+Magic 1.000 [0.700]
+ Magic-Device 1.000 [1.000]
+Spirituality 1.000 [0.500]
+ Prayer 0.000 [0.500]
+ Music 0.000 [0.300]
+Monster-lore 1.000 [1.100]
+ Corpse-preservation 1.000 [0.900]
+ Possession 0.000 [0.100]
+ Symbiosis 1.000 [0.800]
+
+#####GStarting Equipment
+A Symbiant begins the game with:
+ a Dagger
+ a Scroll of Summon Never-Moving Pet
+
+
+#####GSymbiosis
+Symbiants rely on the partnerships they form, hypnotising creatures
+and then "wearing" them: "I get by with a little help from my friends".
+Depending on the monster, this does nothing except protect the player
+slightly (the worn monster takes some of the damage the player would
+otherwise) or grant some very powerful attacks and summons.
+Their "spells" are used by the 'm' command; as their Symbiosis skill
+increases, they automatically gain more powers.
+For more detail about the specific powers, look here: *****m_symbio.txt*0[Symbiosis]
+~~~~~03|Symbiant|Naming your symbiote
+#####GNaming your symbiote
+For those sentimental Symbiants who like to name your symbiotes, you
+can use the Inscribe command '{'. Inscribe your hypnotized symbiote
+with "#named Fido" (or whatever name you choose, but don't forget the
+leading '#'), and it will be listed in your equipment as "a Red Mold
+named Fido", and the game will refer to your symbiote by name ("Fido
+is healed", for instance, rather than "Your Red mold is healed").
+
diff --git a/lib/mods/theme/help/c_thaum.txt b/lib/mods/theme/help/c_thaum.txt
new file mode 100644
index 00000000..653e84fa
--- /dev/null
+++ b/lib/mods/theme/help/c_thaum.txt
@@ -0,0 +1,84 @@
+~~~~~01|Thaumaturgist
+~~~~~02|Classes|Thaumaturgy
+#####R=== Thaumaturgists ===
+
+#####GDescription
+A Thaumaturgist is a Mage that prefers chaos to order. As such, they tend to
+learn random spells, and since attacking something creates more chaos than
+anything else, every spell they learn is an attack spell. They have no need
+for spell-books, as they harness the spells from within themselves. However,
+they also have no ability to improve the power of a particular spell - once
+learnt it will remain at the same strength for ever. Likewise, they also have
+no ability to control what they learn, and some of their spells will cause
+them damage (like darkness spells blinding them if they do not resist
+darkness).
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.200]
+ Weaponmastery 0.700 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 3.000 [0.950]
+ Magic-Device 1.000 [1.050]
+ Spell-power 0.000 [0.600]
+ Mana 0.000 [0.600]
+ Geomancy
+ Fire 0.000 [0.700]
+ Water 0.000 [0.700]
+ Air 0.000 [0.700]
+ Earth 0.000 [0.700]
+ Meta 0.000 [0.700]
+ Conveyance 0.000 [0.700]
+ Divination 0.000 [0.700]
+ Temporal 0.000 [0.700]
+ Mind 0.000 [0.700]
+ Nature 0.000 [0.700]
+ Necromancy 0.000 [0.700]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 1.000 [1.000]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Thaumaturgist cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Thaumaturgist begins the game with:
+ a Book of Beginner Cantrips
+ a Dagger
+
+
+#####GThaumaturgy
+Thaumaturgists can wreak an amazing amount of destruction, and they don't
+even need spellbooks to do it. As they gain skill they memorise new,
+randomly generated attack spells. Note that they possess no guaranteed
+utility or alteration magics, and can never alter themselves.
+[[[[[BThaumaturgists just kill.]
+
+They use their magics through the 'm' key. They then select a general
+group of spells, followed by a specific spell. Thaumaturgists can learn
+more about a specific spell by browsing it; this is very useful for
+choosing the perfect spell for the occasion.
+
+Thaumaturgy spells can take the form of a bolt, a beam, a ball (either
+centred on the caster or targetable), an area (multiple balls in the
+vicinity of the caster), or a spell that affects all monsters in line of sight.
+
+You can find a little more information here: *****m_thaum.txt*0[Thaumaturgy].
diff --git a/lib/mods/theme/help/c_trapper.txt b/lib/mods/theme/help/c_trapper.txt
new file mode 100644
index 00000000..eb0badbe
--- /dev/null
+++ b/lib/mods/theme/help/c_trapper.txt
@@ -0,0 +1,46 @@
+~~~~~01|Trapper
+~~~~~02|Classes|Trapper
+#####R=== Trappers ===
+
+#####GDescription
+A Pacifist is someone who prefers not to use violence to
+achieve their ends. The trappers are not averse, however,
+to destroying monsters via traps and using corpses they
+find to create totems in order to summon aid. They
+may also use spells provided by their deities.
+
+#####GStarting Stat Modifiers
+Strength 0
+Intelligence +2
+Wisdom +2
+Dexterity +2
+Constitution 0
+Charisma +4
+Bonus Blows 0
+Hit Die 0
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Sneakiness 0.000 [0.600]
+ Stealth 0.000 [0.600]
+ Disarming 1.000 [0.600]
+ Dodging 1.000 [0.700]
+Magic 1.000 [0.600]
+ Spell-power 0.000 [0.500]
+ Nature 1.000 [1.000]
+Spirituality 0.000 [0.700]
+ Prayer 0.000 [0.500]
+Monster-lore 1.000 [0.900]
+ Summoning 1.000 [0.600]
+
+#####GStarting Equipment
+A trapper begins the game with:
+ a catapult trap set
+ some iron shots
+
+#####GInnate Abilities:
+#####BAbility Character level
+Trapping 1
+Ammo creation 10
+Perfect casting 15 \ No newline at end of file
diff --git a/lib/mods/theme/help/c_unbel.txt b/lib/mods/theme/help/c_unbel.txt
new file mode 100644
index 00000000..feec5723
--- /dev/null
+++ b/lib/mods/theme/help/c_unbel.txt
@@ -0,0 +1,65 @@
+~~~~~01|Unbeliever
+~~~~~02|Classes|Unbeliever
+#####R=== Unbelievers ===
+
+#####GDescription
+The full opposite of Sorcerors, Unbelievers so strongly despise magic
+that not only do they refuse to use magic spells, they refuse all
+training in the use of magic items, which leaves them almost totally
+incompetent when trying to use a magic item.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.800]
+ Weaponmastery 1.000 [0.850]
+ Sword-mastery 0.000 [0.400]
+ Axe-mastery 0.000 [0.400]
+ Hafted-mastery 0.000 [0.400]
+ Polearm-mastery 0.000 [0.400]
+ Archery 1.000 [0.600]
+ Antimagic 1.000 [0.650]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+An Unbeliever begins the game with:
+ a Ring of Fear Resistance
+ a Dark Sword
+ a Chain Mail
+
+~~~~~03|Unbelievers|Antimagic
+~~~~~04|Antimagic
+~~~~~05|Skills|Antimagic powers
+#####GAntimagic
+Thought carries power. And since Unbelievers think that magic doesn't
+exist, they can suppress its manifestation around them.
+Their magic-inhibiting ability and the area of effect around them are
+determined by the skill level in Antimagic. If they wield a Dark Sword,
+the strength and radius of the magic disrupting field are increased further,
+with best results if the blade is unenchanted.
+
+High levels of proficiency in Antimagic allow them also to stabilise the
+space-time continuum, so preventing teleportation, to sense the magical
+emanations coming from traps and to destroy these around them.
+These abilities are accessed using the 'm' key.
+
+
diff --git a/lib/mods/theme/help/c_wainrid.txt b/lib/mods/theme/help/c_wainrid.txt
new file mode 100644
index 00000000..cf3c3d69
--- /dev/null
+++ b/lib/mods/theme/help/c_wainrid.txt
@@ -0,0 +1,49 @@
+~~~~~01|Wainrider
+~~~~~02|Classes|Wainrider
+#####R=== Wainriders ===
+
+#####GDescription
+Proud warriors riding majestic chariots. They are most effective
+with short, thrusting blades. They are highly spiritual, but their
+deity must be Melkor Bauglir, they do not have a choice when they
+embark upon their adventure. They are better skilled in magic than
+other warrior classes, although their magical ability is limited to
+the Udun school.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Bonus Blows 3
+Hit Die +d9
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.800]
+ Weaponmastery 1.000 [0.850]
+ Sword-mastery 0.000 [0.700]
+ Critical-hits 0.000 [0.500]
+ Archery 1.000 [0.600]
+Sneakiness 1.000 [0.900]
+ Disarming 1.000 [0.900]
+Magic 2.000 [0.800]
+ Magic-Device 1.000 [1.150]
+ Udun 0.000 [0.400]
+Spirituality 1.000 [0.900]
+ Prayer 1.000 [0.700]
+Monster-lore 0.000 [0.500]
+
+#####GStarting Equipment
+A Wainrider begins the game with:
+ a spellbook of Curse
+ a potion of Corruption
+ a Shadow Blade
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1 \ No newline at end of file
diff --git a/lib/mods/theme/help/c_warper.txt b/lib/mods/theme/help/c_warper.txt
new file mode 100644
index 00000000..55d16be5
--- /dev/null
+++ b/lib/mods/theme/help/c_warper.txt
@@ -0,0 +1,60 @@
+|||||oy
+~~~~~01|Warper
+~~~~~02|Classes|Warper
+#####R=== Warpers ===
+
+#####GDescription
+A Warper is a type of mage that prefers to deal in magic that alters the
+fabric of space and time. They specialise in the schools of *****m_convey.txt*0[Conveyance],
+*****m_divin.txt*0[Divination] and *****m_tempo.txt*0[Temporal] magic.
+
+#####GStarting Stat Modifiers
+Strength -5
+Intelligence +3
+Wisdom +0
+Dexterity +1
+Constitution -2
+Charisma +1
+Hit Die +d0
+Spell Points +50%
+Exp Penalty 30%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 1.000 [0.200]
+ Weaponmastery 0.700 [0.400]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+Magic 1.000 [0.900]
+ Magic-Device 1.000 [1.050]
+ Spell-power 1.000 [0.700]
+ Mana 1.000 [0.700]
+ Geomancy
+ Fire 0.000 [0.800]
+ Water 0.000 [0.800]
+ Air 0.000 [0.800]
+ Earth 0.000 [0.800]
+ Meta 0.000 [0.800]
+ Conveyance 0.000 [1.200]
+ Divination 0.000 [1.200]
+ Temporal 0.000 [1.200]
+ Mind 0.000 [0.700]
+ Nature 0.000 [0.800]
+ Necromancy 0.000 [0.700]
+ Runecraft 0.000 [0.700]
+ Thaumaturgy 0.000 [0.700]
+Spirituality 1.000 [0.550]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+*A Warper cannot learn the Geomancy skill, but it is shown in his skill
+screen because the elemental schools are sub-skills of it.
+
+#####GInnate Abilities:
+#####BAbility Character level
+Perfect casting 1
+
+#####GStarting Equipment
+A Warper begins the game with:
+ a Book of Beginner Cantrips
+ a Dagger
diff --git a/lib/mods/theme/help/c_warrio.txt b/lib/mods/theme/help/c_warrio.txt
new file mode 100644
index 00000000..942b34bb
--- /dev/null
+++ b/lib/mods/theme/help/c_warrio.txt
@@ -0,0 +1,54 @@
+~~~~~01|Warrior
+~~~~~02|Classes|Warrior
+#####R=== Warriors ===
+
+#####GDescription
+A Warrior is a hack-and-slash character, who solves most of his problems
+by cutting them to pieces, but will occasionally fall back on the help
+of a magical device or a bow.
+
+A Warrior learns no magic, and can even suppress it like an Unbeliever through
+the Antimagic skill.
+
+#####GStarting Stat Modifiers
+Strength +5
+Intelligence -2
+Wisdom -2
+Dexterity +2
+Constitution +2
+Charisma -1
+Hit Die +d9
+Spell Points +0%
+Exp Penalty 0%
+
+#####GStarting Skills:
+#####BSkill Start Level Skill Point Gains
+Combat 2.000 [0.800]
+ Weaponmastery 1.000 [0.850]
+ Sword-mastery 0.000 [0.400]
+ Axe-mastery 0.000 [0.400]
+ Hafted-mastery 0.000 [0.400]
+ Polearm-mastery 0.000 [0.400]
+ Archery 1.000 [0.600]
+ Antimagic 0.000 [0.550]
+Sneakiness 1.000 [0.900]
+ Stealth 0.000 [0.400]
+ Disarming 1.000 [0.900]
+Magic 1.000 [0.300]
+ Magic-Device 1.000 [1.150]
+Spirituality 1.000 [0.400]
+ Prayer 0.000 [0.500]
+Monster-lore 0.000 [0.500]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Extra Max Blow(1) 1
+Extra Max Blow(2) 1
+Spread blows 25
+
+#####GStarting Equipment
+A Warrior begins the game with:
+ a Ring of Fear Resistance
+ a Broad Sword
+ a Chain Mail
+
diff --git a/lib/mods/theme/help/command.txt b/lib/mods/theme/help/command.txt
new file mode 100644
index 00000000..6616c252
--- /dev/null
+++ b/lib/mods/theme/help/command.txt
@@ -0,0 +1,1251 @@
+|||||oy
+~~~~~99|Commands
+#####R=== List of Commands ===
+
+
+ Angband commands are entered as an "underlying command" (a single key)
+plus a variety of optional or required arguments. You may choose how the
+"keyboard keys" are mapped to the "underlying commands" by choosing one of
+two standard "keysets", the "original" keyset or the "roguelike" keyset.
+
+ The original keyset is very similar to the "underlying" command set,
+with a few additions (such as the ability to use the numeric "directions" to
+"walk" or the "5" key to "stay still"). The roguelike keyset provides similar
+additions, and also allows the use of the h/j/k/l/y/u/b/n keys to "walk" (or,
+in combination with the shift or control keys, to run or tunnel), which thus
+requires a variety of key mappings to allow access to the underlying commands
+used for walking/running/tunneling. In particular, the "roguelike" keyset
+includes many more "capital" and "control" keys, as shown below.
+
+ Note that any keys that are not required for access to the underlying
+command set may be used by the user as "command macro" triggers (see below).
+You may always specify any "underlying command" directly by pressing backslash
+("\") plus the "underlying command" key. This is normally only used in "macro"
+definitions. [[[[[BYou may often enter "control-keys" as a caret ("^") plus the key]
+(so "^" + "p" often yields "^P").
+
+ Some commands allow an optional "repeat count", which allows you to tell
+the game that you wish to do the command multiple times, unless you press a
+key or are otherwise disturbed. To enter a "repeat count", type '0', followed
+by the numerical count, followed by the command. You must type "space" before
+entering certain commands. Skipping the numerical count yields a count of 99.
+An option allows certain commands (open, disarm, tunnel, etc) to auto-repeat.
+
+ Some commands will prompt for extra information, such as a direction, an
+inventory or equipment item, a spell, a textual inscription, the symbol of a
+monster race, a sub-command, a verification, an amount of time, a quantity,
+a file name, or various other things. Normally you can hit return to choose
+the "default" response, or escape to cancel the command entirely.
+
+ Some commands will prompt for a spell or an inventory item. Pressing
+space (or '*') will give you a list of choices. Pressing "-" (minus) selects
+the item on the floor. Pressing a lowercase letter selects the given item.
+Pressing a capital letter selects the given item after verification. Pressing
+a numeric digit '#' selects the first item (if any) whose inscription contains
+"@#" or "@x#", where "x" is the current "underlying command". You may only
+specify items which are "legal" for the command. Whenever an item inscription
+contains "!*" or "!x" (with "x" as above) you must verify its selection.
+
+ In ToME, there are items which occasionally teleport you away, asking
+for permission first. The recurring "Teleport (y/n)?" can be annoying, and
+this behavior can be eliminated by inscribing the object which causes the
+teleportation with "." (or any inscription containing the character ".").
+With this inscription, the object will no longer teleport you around nor
+keep asking you. If you want to restore the teleport ability to the object,
+just remove the "." from its inscription. Note that cursed items which
+teleport you are unaffected by the inscription.
+
+ Some commands will prompt for a direction. You may enter a "compass"
+direction using any of the "direction keys" shown below. Sometimes, you may
+specify that you wish to use the current "target", by pressing "t" or "5", or
+that you wish to select a new target, by pressing "*" (see "Target" below).
+~~~~~95
+#####G Original Keyset Directions Roguelike Keyset Directions
+
+ 7 8 9 y k u
+ 4 6 h l
+ 1 2 3 b j n
+
+ Each of the standard keysets provides some short-cuts over the "underlying
+commands". For example, both keysets allow you to "walk" by simply pressing
+an "original" direction key (or a "roguelike" direction key if you are using
+the roguelike keyset), instead of using the "walk" command plus a direction.
+[[[[[BThe roguelike keyset allows you to "run" or "tunnel" by simply holding the]
+[[[[[Bshift or control modifier key down while pressing a "roguelike" direction key,]
+[[[[[Binstead of using the "run" or "tunnel" command plus a direction.] Both keysets
+allow the use of the "5" key to "stand still", which is most convenient when
+using the original keyset.
+
+ Note that on many systems, it is possible to define "macros" (or "command
+macros") to various keys, or key combinations, so that it is often possible to
+make macros which, for example, allow the use of the shift or control modifier
+keys, plus a numeric keypad key, to specify the "run" or "tunnel" command, with
+the given direction, regardless of any keymap definitions, by using the fact
+that you can always, for example, use "\" + "." + "6", to specify "run east".
+~~~~~100|Commands|Original keyset
+#####R=== Original Keyset Command Summary (4.2.x) ===
+
+ *****command.txt*1[a Aim a wand] *****command.txt*2[A Activate an artifact]
+ *****command.txt*3[b Browse a book] *****command.txt*4[B Bash a door]
+ *****command.txt*5[c Close a door] *****command.txt*6[C Character description]
+ *****command.txt*7[d Drop an item] *****command.txt*8[D Disarm a trap]
+ *****command.txt*9[e Equipment list] *****command.txt*10[E Eat some food]
+ *****command.txt*11[f Fire (shoot) an item] *****command.txt*12[F Fuel your lantern/torch]
+ *****command.txt*13[g Stay still (flip pickup)] *****command.txt*14[G Gain new skills]
+ *****command.txt*15[h Hack up a corpse] *****command.txt*16[H Drink from a fountain]
+ *****command.txt*17[i Inventory list] *****command.txt*18[I Inspect (closely examine) an item]
+ *****command.txt*19[j Jam a door] J (unused)
+ *****command.txt*20[k Destroy an item] *****command.txt*21[K Cure meat]
+ *****command.txt*22[l Look around] *****command.txt*23[L Look around dungeon by sector]
+ *****command.txt*24[m Cast a spell / use mental power] *****command.txt*25[M Full dungeon map]
+ *****command.txt*85[n Repeat last command] *****command.txt*91[N Abilities Screen]
+ *****command.txt*26[o Open a door or chest] *****command.txt*27[O Sacrifice at an altar]
+ *****command.txt*28[p Pray to your god (if any)] *****command.txt*29[P Pet commands]
+ *****command.txt*30[q Quaff a potion] *****command.txt*31[Q Quit (commit suicide)]
+ *****command.txt*32[r Read a scroll] *****command.txt*33[R Rest for a period]
+ *****command.txt*34[s Search for traps/doors] *****command.txt*35[S Toggle search mode]
+ *****command.txt*36[t Take off equipment] *****command.txt*37[T Dig a tunnel]
+ *****command.txt*38[u Use a staff] *****command.txt*39[U Use bonus power (if any)]
+ *****command.txt*40[v Throw an item] *****command.txt*41[V Version Info]
+ *****command.txt*42[w Wear/wield equipment] W (unused)
+ *****command.txt*43[x Engrave the floor] X (unused)
+ *****command.txt*44[y Give item to monster] *****command.txt*96[Y Chat with a monster]
+ *****command.txt*45[z Zap a rod] *****command.txt*46[Z Steal]
+ *****command.txt*47[! Interact with system] *****debug.txt*101[^A (special - debug command)]
+ *****command.txt*49[@ Interact with macros] ^B (unused)
+ *****command.txt*89[# Begin extended command] ^C (special - break)
+ *****command.txt*97[$ Record macros] ^D (unused)
+ *****command.txt*51[% Interact with visuals] *****command.txt*52[^E Toggle choice window]
+ ^ (special - control key) *****command.txt*53[^F Repeat level feeling]
+ *****command.txt*54[& Interact with colors] ^G (unused)
+ *****command.txt*55[* Target monster or location] ^H (unused)
+ ( (unused) ^I (special - tab)
+ ) (unused) ^J (special - linefeed)
+ *****command.txt*58[{ Inscribe an object] ^K (unused)
+ *****command.txt*59[} Uninscribe an object] ^L (unused)
+ [ (unused) ^M (special - return)
+ ] (unused) ^N (unused)
+ *****command.txt*60[- Walk (flip pickup)] ^O (unused)
+ *****command.txt*61[_ Re-Enter store] *****command.txt*62[^P Show previous messages]
+ *****command.txt*63[+ Alter grid] *****command.txt*64[^Q Quit to next midi song]
+ *****command.txt*65[= Set options] *****command.txt*66[^R Redraw the screen]
+ *****command.txt*67[; Walk (with pickup)] *****command.txt*68[^S Save and don't quit]
+ *****command.txt*69[: Take notes] *****command.txt*70[^T Time of the day]
+ ' (unused) ^U (unused)
+ *****command.txt*71[" Enter a user pref command] ^V (unused)
+ *****command.txt*72[, Stay still (with pickup)] ^W (special - wizard mode)
+ *****command.txt*74[< Go up staircase] *****command.txt*75[^X Save and quit]
+ *****command.txt*76[. Run] ^Y (unused)
+ *****command.txt*77[> Go down staircase] ^Z (special - borg command)
+ *****command.txt*79[\ (special - bypass keymap)] *****command.txt*80[| Do cmovies]
+ *****command.txt*81[` (special - escape)] *****command.txt*82[~ Display current knowledge]
+ *****command.txt*83[/ Identify symbol] *****command.txt*84[? Help]
+ *****command.txt*98[^\] Take an html screenshot]
+
+
+~~~~~101|Commands|Roguelike keyset
+#####R=== Roguelike Keyset Command Summary (4.2.x) ===
+
+ *****command.txt*45[a Zap a rod (Activate)] *****command.txt*2[A Activate an artifact]
+ *****command.txt*95[b (walk - south west)] *****command.txt*95[B (run - south west)]
+ *****command.txt*5[c Close a door] *****command.txt*6[C Character description]
+ *****command.txt*7[d Drop an item] *****command.txt*8[D Disarm a trap or chest]
+ *****command.txt*9[e Equipment list] *****command.txt*10[E Eat some food]
+ *****command.txt*4[f Bash a door (force)] *****command.txt*12[F Fuel your lantern/torch]
+ *****command.txt*13[g Stay still (flip pickup)] *****command.txt*14[G Gain new skills]
+ *****command.txt*95[h (walk - west)] *****command.txt*95[H (run - west)]
+ *****command.txt*17[i Inventory list] *****command.txt*18[I Observe an item]
+ *****command.txt*95[j (walk - south)] *****command.txt*95[J (run - south)]
+ *****command.txt*95[k (walk - north)] *****command.txt*95[K (run - north)]
+ *****command.txt*95[l (walk - east)] *****command.txt*95[L (run - east)]
+ *****command.txt*24[m Spell casting / mental power] *****command.txt*25[M Full dungeon map]
+ *****command.txt*95[n (walk - south east)] *****command.txt*95[N (run - south east)]
+ *****command.txt*26[o Open a door or chest] *****command.txt*39[O Use bonus power (if any)]
+ *****command.txt*28[p Pray to your god (if any)] *****command.txt*3[P Browse a book]
+ *****command.txt*30[q Quaff a potion] *****command.txt*31[Q Quit (commit suicide)]
+ *****command.txt*32[r Read a scroll] *****command.txt*33[R Rest for a period]
+ *****command.txt*34[s Search for traps/doors] *****command.txt*97[S Record macros]
+ *****command.txt*11[t Fire an item] *****command.txt*36[T Take off equipment]
+ *****command.txt*95[u (walk - north east)] *****command.txt*95[U (run - north east)]
+ *****command.txt*40[v Throw an item] *****command.txt*16[V Drink from a fountain]
+ *****command.txt*42[w Wear/wield equipment] *****command.txt*23[W Locate player on map (Where)]
+ *****command.txt*22[x Look around] *****command.txt*29[X Pet commands]
+ *****command.txt*95[y (walk - north west)] *****command.txt*95[Y (run - north west)]
+ *****command.txt*1[z Aim a wand (Zap)] *****command.txt*38[Z Use a staff (Zap)]
+ *****command.txt*47[! Interact with system] ^A (special - debug command)
+ *****command.txt*49[@ Interact with macros] *****command.txt*95[^B (tunnel - south west)]
+ *****command.txt*35[# Toggle search mode] ^C (special - break)
+ *****command.txt*15[$ Hack up a corpse] *****command.txt*20[^D Destroy item]
+ *****command.txt*51[% Interact with visuals] *****command.txt*52[^E Toggle choice window]
+ ^ (special - control key) *****command.txt*53[^F Repeat level feeling]
+ *****command.txt*54[& Interact with colors] *****command.txt*27[^G Sacrifice at an altar]
+ *****command.txt*55[* Target monster or location] *****command.txt*95[^H (tunnel - west)]
+ *****command.txt*96[( Chat] ^I (special - tab)
+ *****command.txt*89[) Begin extended command] *****command.txt*95[^J (tunnel - south)]
+ *****command.txt*58[{ Inscribe an object] *****command.txt*95[^K (tunnel - north)]
+ *****command.txt*59[} Uninscribe an object] *****command.txt*95[^L (tunnel - east)]
+ [*****command.txt*46[ Steal] *****command.txt*95[^M (tunnel - south)]
+ ]*****command.txt*43[ Engrave the floor] *****command.txt*95[^N (tunnel - south east)]
+ *****command.txt*60[- Walk (flip pickup)] *****command.txt*21[^O Cure meat]
+ *****command.txt*61[_ Enter store] *****command.txt*62[^P Show previous messages]
+ *****command.txt*63[+ Alter grid] *****command.txt*64[^Q Quit to next midi song]
+ *****command.txt*65[= Set options] *****command.txt*66[^R Redraw the screen]
+ *****command.txt*67[; Walk (with pickup)] *****command.txt*68[^S Save and don't quit]
+ *****command.txt*69[: Take notes] *****command.txt*37[^T Dig a Tunnel]
+ *****command.txt*44[' Give object to monster] *****command.txt*95[^U (tunnel - north east)]
+ *****command.txt*71[" Enter a user pref command] ^V (unused)
+ *****command.txt*76[, Run] ^W (special - wizard mode)
+ *****command.txt*74[< Go up staircase] *****command.txt*75[^X Save and quit]
+ *****command.txt*72[. Stay still (with pickup)] *****command.txt*95[^Y (tunnel - north west)]
+ *****command.txt*77[> Go down staircase] ^Z (special - borg command)
+ *****command.txt*79[\ (special - bypass keymap)] *****command.txt*80[| Do cmovies]
+ *****command.txt*81[` (special - escape)] *****command.txt*82[~ Display current knowledge]
+ *****command.txt*83[/ Identify symbol] *****command.txt*84[? Help]
+
+~~~~~102|Commands|Special keys
+#####R=== Special Keys ===
+
+ Certain special keys may be intercepted by the operating system or
+the host machine, causing unexpected results. In general, these special keys
+are control keys, and often, you can disable their special effects.
+
+ If you are playing on a UNIX or similar system, then Ctrl-C will
+interrupt ToME. The second and third interrupt will induce a warning
+bell, and the fourth will induce both a warning bell and a special message,
+since the fifth will quit the game, after killing your character. Also,
+Ctrl-Z will suspend the game, and return you to the original command shell,
+until you resume the game with the "fg" command. There is now a compilation
+option to force the game to prevent the "double ctrl-z escape death trick".
+The Ctrl-\ and Ctrl-D and Ctrl-S keys should not be intercepted.
+
+ It is often possible to specify "control-keys" without actually
+pressing the control key, by typing a caret ("^") followed by the key.
+This is useful for specifying control-key commands which might be caught
+by the operating system as explained above.
+~~~~~79
+ Pressing [[[[[Gbackslash ("\\")] before a command will bypass all keymaps,
+and the next keypress will be interpreted as an "underlying command" key,
+unless it is a caret ("^"), in which case the keypress after that will be
+turned into a control-key and interpreted as a command in the underlying
+ToME keyset. The backslash key is useful for creating macro actions
+which are not affected by any keymap definitions that may be in force, for
+example, the sequence "\" + "." + "6" will always mean "run east", even if
+the "." key has been mapped to a different underlying command.
+
+ The "0" and "^" and "\" keys all have special meaning when entered
+at the command prompt, and there is no "useful" way to specify any of them
+as an "underlying command", which is okay, since they would have no effect.
+~~~~~81
+ For many input requests or queries, the [[[[[Gspecial character ESCAPE]
+will abort the command. The "[y/n]" prompts may be answered with "y" or
+"n", or escape. The "-more-" message prompts may be cleared (after reading
+the displayed message) by pressing ESCAPE, SPACE, RETURN, LINEFEED, or by
+any keypress, if the "quick_messages" option is turned on.
+~~~~~103|Commands|Command counts
+~~~~~104|Commands|Repeating a command
+#####R=== Command Counts ===
+
+ Some commands can be executed a fixed number of times by preceding
+them with a count. Counted commands will execute until the count expires,
+until you type any character, or until something significant happens, such
+as being attacked. Thus, a counted command doesn't work to attack another
+creature. While the command is being repeated, the number of times left
+to be repeated will flash by on the line at the bottom of the screen.
+
+ [[[[[BTo give a count to a command, type 0, the repeat count, and then]
+[[[[[Bthe command.] If you want to give a movement command and you are using the
+original command set (where the movement commands are digits), press space
+after the count and you will be prompted for the command.
+
+ Counted commands are very useful for searching or tunneling, as
+they automatically terminate on success, or if you are attacked. You may
+also terminate any counted command (or resting or running), by typing any
+character. This character is ignored, but it is safest to use a SPACE or
+ESCAPE which are always ignored as commands in case you type the command
+just after the count expires.
+
+ You can tell ToME to automatically use a repeat count of 99
+with commands you normally want to repeat (open, disarm, tunnel, bash,
+alter, etc) by setting the "always_repeat" option.
+
+
+#####R=== Selection of Objects ===
+
+ Many commands will also prompt for a particular object to be used.
+For example, the command to read a scroll will ask you which of the
+scrolls that you are carrying that you wish to read. In such cases, the
+selection is made by typing a letter of the alphabet. The prompt will
+indicate the possible letters, and will also allow you to type the key
+"*", which causes all of the available options to be described. The list
+of choices will also be shown in the Choice window, if you are using a
+windows environment and windows are turned on. Often you will be able to
+press "/" to select an object from your equipment instead of your
+inventory. Pressing space once will have the same effect as "*", and
+the second time will cancel the command and run the "i" or "e" command.
+
+ [[[[[BThe particular object may be selected by an upper case or a lower]
+[[[[[Bcase letter. If lower case is used, the selection takes place]
+[[[[[Bimmediately. If upper case is used, then the particular option is]
+[[[[[Bdescribed, and you are given the option of confirming or retracting that]
+[[[[[Bchoice.] Upper case selection is thus safer, but requires an extra key
+stroke. Also see the "!*" and "!x" inscriptions, below.
+
+ For many commands, [[[[[Byou can also use "-" to select an object on the]
+[[[[[Bfloor where you are standing.] This lets you read scrolls or quaff
+potions, for example, off the dungeon floor without picking them up.
+~~~~~90
+ If you enter a number between 0 and 9, the first item engraved
+with "@#" where "#" is the number you entered will be selected. For example,
+if you have a shovel engraved with "@0" and you type "w" (for wield) and
+then 0, you will wield the shovel. This is very useful for macros (see
+below), since you can use this to select an object regardless of its
+location in your pack. Multiple numbers can be engraved on the same object; for
+example, if a sword is engraved with @1@0, then either "w1" or "w0" will
+wield it. Normally, you inscribe "@1@0" on your primary weapon, and
+"@2@0" on your secondary weapon. [[[[[BNote that an inscription containing]
+[[[[[B"@x#" will act like "@#" but only when the current "ToME command"]
+[[[[[Bis "x".] Thus you can put "@z4" on a rod and "@u4" on a staff, and then
+use both "z4" and "u4" as desired.
+
+ Note that any object containing "!x" in its inscription, where
+"x" is the current "ToME command" (or containing "!*" ever) will induce
+"verification" whenever that object is "selected". Thus, inscribing, say,
+"!f!k!d" on an object will greatly reduce the odds of you "losing" it by
+accident, and [[[[[Binscribing "!*" on an object] will allow you to be very paranoid
+about the object. Note that "selling" and "dropping" both use the "d" command.
+
+~~~~~105|Pref files
+#####R=== User Pref Files ===
+
+ ToME allows you to change various aspects of the game to suit
+your tastes. You may define keymaps (changing the way ToME maps your
+keypresses to underlying commands), create macros (allowing you to map a
+single keypress to a series of keypresses), modify the visuals (allowing
+you to change the appearance of monsters, objects, or terrain features),
+change the colors (allowing you to make a given color brighter, darker,
+or even completely different), or set options (turning them off or on).
+
+ ToME stores your preferences in files called "user pref files",
+which contain comments and "user pref commands", which are simple strings
+describing one aspect of the system about which the user has a preference.
+There are many ways to load a user pref file, and in fact, some of these
+files are automatically loaded for you by the game. All of the files are
+kept in the "lib/user/" directory, though you may have to use one of the
+command line arguments to redirect this directory, especially on multiuser
+systems. You may also enter single user pref commands directly, using the
+special "Enter a user pref command" command, activated by "double quote".
+You may have to use the "redraw" command (^R) after changing certain of
+the aspects of the game, to allow ToME to adapt to your changes.
+
+ When the game starts up, after you have loaded an old character,
+or created a new character, some user pref files are loaded automatically.
+First, the "pref.prf" file is loaded. This file contains some user pref
+commands which will work on all platforms. Then one of "font-xxx.prf"
+(for normal usage) or "graf-xxx.prf" (for bitmap usage) is loaded. These
+files contain attr/char changes to allow the monsters, objects, and/or
+terrain features to look "better" on your system. Then the "pref-xxx.prf"
+file is loaded. This file contains pre-defined system specific stuff
+(macros, color definitions, etc). Then, the "user-xxx.prf" file is loaded.
+This file contains user-defined system specific stuff. The "user-xxx.prf"
+file is used as the "default" user pref file in many places. The "xxx" is
+the "system suffix" for your system, taken from the "main-xxx.c" file which
+was used to generate your executable. Finally, the "Race.prf", "Class.prf",
+and "Name.prf" files are loaded, where "Race", "Class", and "Name" are
+replaced by the actual race, class, and name of the current character.
+
+ Several commands allow you to both load existing user pref files,
+create new user pref files, append information to existing user pref files,
+and/or interact with various of the user preferences in a more intuitive
+way than the user pref commands allow. The commands include "Interact with
+macros" (@), "Interact with visuals" (%), and "Interact with colors" (&),
+described below.
+~~~~~106|Pref files|Macros
+#####G--- User Pref Files (Macros) ---
+
+ The "Interact with macros" command allows you to define or remove
+"macros", which are mappings from a single logical keypress to a sequence
+of keypresses, allowing you to use special keys on the keyboard, such as
+function keys or keypad keys, possibly in conjunction with modifier keys,
+to "automate" repetitive multi-keypress commands that you use a lot.
+
+ Since macros represent keypress sequences, and not all keypresses
+have a printable representation, macro triggers and actions must often be
+"encoded" into a human readable form. This is done using several types
+of encoding, including "\xHH" for character number HH in hexidecimal, "\e"
+for the "escape" code, "\n" for the "newline" code, "\r" for the "return"
+code, "\s" for the "space" code, "\\" for backslash, "\^" for caret, and
+"^X" for the code for any "control" key "ctrl-X". Note that the "action"
+of a macro will not be checked against other macro triggers (unless the
+macro action contains a "control-backslash"), so you cannot make infinite
+loops. You may specify extremely long macros, but you are limited in
+length by the underlying input mechanisms, which in general limit you
+to about 1024 keys in both triggers and actions.
+
+ The special "\" command (which must be encoded in macros as "\\")
+is very useful in macros, since it bypasses all keymaps and allows the next
+keystroke to be considered a command in the underlying ToME command set.
+For example, a macro which maps Shift-KP6 to "\" + "." + "6" will induce
+the "run east" behavior, regardless of what keyset the user has chosen, and
+regardless of what keymaps have been defined.
+
+ Macros can be specified in user pref files as a pair of lines, one
+of the form "A:<str>", which defines the encoded macro action, and one of
+the form "P:<str>", which defines the encoded macro trigger.
+
+ A [[[[[Bcommon example of a macro] to cast the first spell in your first spell
+book at the nearest monster would be: \e\e\em1a*t where \e is an escape (to make
+sure you are not still within another command), m1 selects the spell book that
+is inscribed ({) with @m1, a selects the first spell in that book, and *t targets
+the nearest monster.
+
+ More detailed information about specific macros can be found in
+*****macrofaq.txt*0[macrofaq.txt], originally written by Jim Lyon (jplyon@attglobal.net),
+modified for ToME with Jim's permission by Dawnmist
+(angband@dawnmist.8m.com).
+~~~~~107|Pref files|Keymaps
+#####G--- User Pref Files (Keymaps) ---
+
+ The "Interact with macros" command also allows you to define
+"keymaps", which are vaguely related to macros. A keymap maps a single
+keypress to a series of keypresses, which bypass both other keymaps and
+any macros. ToME uses keymaps to map the original and the roguelike
+keysets to the underlying command set, and allows the user to modify or
+add keymaps of their own. Note that all keymap actions must be specified
+using underlying commands, not keypresses from the original or roguelike
+keysets. The original keyset is almost identical to the underlying keyset,
+except that "numbers" are mapped to ";" plus a direction, "5" is mapped to
+",", and a few control-keys are mapped to various things. See "command.txt"
+for the full set of underlying commands. Some uses for keymaps include the
+ability to "disable" a command by mapping it to "\x00",
+
+ Keymaps can be specified in user pref files as line of the form
+"M:<T> <key> <str>", where <T> is the keyset (0/1 for original/roguelike),
+<key> is the encoded trigger key, and <str> is the encoded keymap action.
+~~~~~108|Pref files|Visuals
+#####G--- User Pref Files (Visuals) ---
+
+ You can use the "Interact with visuals" command to change various
+visual information, currently including the choice of what attr/char values
+are used to represent various monsters, objects, or terrain features. Note
+that in combination appropriate support in "main-xxx.c", and with the use of
+the "use_graphics" flag, you may be able to specify that "graphic bitmaps"
+should be used instead of normal "colored characters" for various things.
+
+ When interactively modifying the attr/char values for monsters,
+objects, or terrain features, pressing "n" or "N" will change which entry
+you are changing, pressing "a" or "A" will rotate through the available
+attr values, and pressing "c" or "C" will rotate though the available char
+values. Note that attr/char values with the "high bit" set may induce the
+display of special "graphic" pictures if the "use_graphics" flag is set,
+and your system supports the "use_graphics" flag.
+
+ Note that this command can be abused in various ways, and if you
+must do so, remember that you are only cheating yourself.
+
+ Keymaps can be specified in user pref files as line of the form
+"R:<N>:<A>/<C>" or "K:<N>:<A>/<C>" or "F:<N>:<A>/<C>" or "U:<N>:<A>/<C>".
+~~~~~109|Pref files|Colors
+#####G--- User Pref Files (Colors) ---
+
+ The "Interact with colors" command allows you to change the actual
+internal values used to display various colors. This command may or may
+not have any effect on your machine. Advanced machines may allow you to
+change the actual RGB values used to represent each of the 16 colors used
+by ToME, and perhaps even allow you to define new colors which are not
+currently used by ToME.
+
+ Colors can be specified in user pref files as line of the form
+"V:<N>:<V>:<R>:<G>:<B>".
+~~~~~110|Pref files|Options
+#####G--- User Pref Files (Options) ---
+
+ The "Interact with options" command allows you to turn options
+on or off. You may turn options off or on using the user pref commands
+of the form "X:<option>" or "Y:<option>" respectively.
+
+~~~~~111|Commands|Command descriptions
+#####R=== Command Descriptions ===
+
+ The following command descriptions are listed as the command name
+plus the "underlying command" key. This is followed by the command name
+and "roguelike" keyset key, if different from the underlying command key.
+Then comes a brief description of the command, including information about
+alternative methods of specifying the command in each keyset, when needed.
+Several commands (tunnel, disarm, bash, open) are repeated 99 times if the
+"always_repeat" option is set and no repeat count is given. Some commands
+use the "repeat count" to automatically repeat the command several times,
+while others use the "repeat count" as an "argument", for example, commands
+which need a "quantity" will use the "repeat count" instead of asking for
+a quantity, allowing the use of "0d" for "drop all". Commands which ask
+for a quantity will convert any "letters" into the maximal legal value.
+~~~~~112|Commands|Inventory
+#####R--- Inventory Commands ---
+~~~~~17
+[[[[[GInventory list (i)]
+ Displays a list of objects being carried but not equipped. You
+ can carry up to 23 different items, not counting those in your
+ equipment. Often, many identical objects can be "stacked" into
+ a "pile" which will count as a single item. This is always
+ true of things like potions, scrolls, and food, but you may have
+ to set options to allow wands, staves, and other such objects to
+ stack. Each object has a weight, and if you carry more objects
+ than your strength permits, you will begin to slow down.
+~~~~~9
+[[[[[GEquipment list (e)]
+ Use this command to display a list of the objects currently being
+ used by your character. The number and type of available slots for
+ equipment may vary. A human for example has 15 slots for equipment,
+ each corresponding to a different location on the body, and each of
+ which may contain only a single object at a time, and each of which
+ may only contain objects of the proper "type".
+ If the option "show_labels" is set, the slots are labelled as follows:
+ Wielding (weapon), Shooting (missile launcher or instruments),
+ On finger (ring), Around neck (amulet), Light source (light source),
+ On body (armor), About body (cloak), On arm (shield), On head (helmet),
+ On hands (gloves), On feet (boots), Carrying (symbiote), Quiver (ammo),
+ Using (tool). You must be using an object to receive any of its special
+ powers.
+~~~~~7
+[[[[[GDrop an item (d)]
+ This command drops an item from your inventory or equipment onto the
+ dungeon floor. If the place you are standing on already has objects
+ in it, ToME will attempt to drop the item onto an adjacent space.
+ A floor spot can hold more than one object, but there is still the
+ possibility that if the floor is too full and you attempt to drop
+ something, it may disappear and be destroyed. If the selected pile
+ contains multiple items, you may specify a quantity.
+~~~~~20
+[[[[[GDestroy an item (k) or Destroy an item (^D)]
+ This destroys an item in your inventory or on the dungeon floor.
+ If the selected pile contains multiple objects, you may specify
+ a quantity. You must always verify this command, unless the item
+ is cursed or worthless and the option "auto_destroy" is set.
+~~~~~42
+[[[[[GWear/Wield equipment (w)]
+ To wear or wield an object in your inventory, use this command.
+ Since only one object can be in each slot at a time, if you wear
+ or wield an item into a slot which is already occupied, the old
+ item will be first be taken off, and may in fact be dropped if
+ there is no room for it in your inventory.
+~~~~~36
+[[[[[GTake off equipment (t) or Take off equipment (T)]
+ Use this command to take off a piece of equipment and return it
+ to your inventory. Occasionally, you will run into a cursed item
+ which cannot be removed. These items normally penalise you in some
+ way and cannot be taken off until the curse is removed. If there
+ is no room in your inventory for the item, your pack will overflow
+ and you will drop the item after taking it off.
+~~~~~113|Commands|Movement
+#####R--- Movement Commands ---
+~~~~~67
+[[[[[GWalk (with pickup) (;)]
+ Moves one step in the given direction. The square you are moving
+ into must not be blocked by walls or doors. You will pick up any
+ items in the destination grid if the "always_pickup" option is set,
+ or if the "query_pickup" option is set and you respond correctly.
+ This command can take a count and requires a direction. You may
+ also use the "original" direction keys (both keysets) or the
+ "roguelike" direction keys (roguelike keyset) to walk in a
+ direction.
+~~~~~60
+[[[[[GWalk (flip pickup) (-)]
+ This is just like normal move, except that the "Pick things up"
+ option is inverted. In other words, if you normally pick up
+ anything you encounter (the default), you will not pick things up
+ when using this command. If you normally do not pick things up,
+ you will when using this command. This command can take a count
+ and requires a direction.
+~~~~~76
+[[[[[GRun (.) or Run (,)]
+ This command will move in the given direction, following any bends
+ in the corridor, until you either have to make a "choice" between
+ two directions or you are disturbed. You can configure what will
+ disturb you by setting the disturbance options. Run requires a
+ direction. You may also use shift plus the "roguelike" direction
+ keys (roguelike keyset), or shift plus the "original" direction keys
+ on the keypad (both keysets, some machines) to run in a direction.
+~~~~~74
+[[[[[GGo up staircase (<)]
+ Climbs up an up staircase you are standing on. There is always at
+ least one staircase going up on every level (this doesn't mean it's
+ easy to find) except for the surface, where '<' will bring up the
+ wilderness map. Going up a staircase will take you to a new dungeon
+ level unless you are at the first level of the dungeon, in which case
+ you will return to the surface. Note that whenever you leave a dungeon
+ level, you will never find it again, unless the level contains a dungeon
+ town. This means that for all intents and purposes, any objects on that
+ level are destroyed. This includes unknown artifacts unless the "Create
+ characters in preserve mode" option was set when your character was
+ created, in which case the artifacts may show up again later.
+~~~~~77
+[[[[[GGo down staircase (>)]
+ Descends a down staircase you are standing on. There are always
+ at least two staircases going down on each level, except for the
+ last level of a dungeon, and some "quest" levels, which have none until
+ the quest monsters are killed. Going down a staircase will take you
+ to a new dungeon level. See "Go Up Staircase" for more info.
+
+ This command is also used to enter Void Jumpgates, and to zoom in from
+ the wilderness map.
+~~~~~114|Commands|Resting
+#####R--- Resting Commands ---
+~~~~~72
+[[[[[GStay still (with pickup) (,) or Stay still (with pickup) (.)]
+ Stays in the same square for one move. If you normally pick up
+ objects you encounter, you will pick up whatever you are standing
+ on. This command can take a count. You may also use the "5" key
+ (both keysets).
+~~~~~13
+[[[[[GStay still (flip pickup) (g)]
+ Stays in the same square for one move. If you normally pick up
+ objects you encounter, you will not pick up whatever you are
+ standing on. If you normally do not pick up objects, you will
+ pick up what you are standing on. This command is normally only
+ used when the "always_pickup" option is false. This command can
+ take a count.
+~~~~~33
+[[[[[GRest (R)]
+ Resting is better for you than repeatedly staying still, and can
+ be told to automatically stop after a certain amount of time, or
+ when various conditions are met. In any case, you always wake up
+ when anything disturbing happens, or when you press any key. To
+ rest, enter the Rest command, followed by the number of turns you
+ want to rest, or "*" to rest until your hit points and mana are
+ restored, or "&" to rest until you are fully "healed". This command
+ can take a count, which is used for the number of turns to rest.
+~~~~~61
+[[[[[GEnter store (_)]
+ When standing on the door of a store, this command allows the character
+ to enter the store again.
+~~~~~115|Commands|Searching
+#####R--- Searching Commands ---
+~~~~~34
+[[[[[GSearch (s)]
+ This command can be used to locate hidden traps and secret doors
+ in the spaces adjacent to the player. More than a single turn of
+ searching will be required in most cases. You should always
+ search a chest before trying to open it, since they are generally
+ trapped. This command can take a count, which is useful if you
+ are fairly sure of finding something eventually, since the command
+ stops as soon as anything is found. This command can take a count.
+~~~~~35
+[[[[[GToggle search mode (S) or Toggle search mode (#)]
+ This command will take you into and out of search mode. When
+ first pressed, the message "Searching" will appear at the bottom
+ of the screen. You are now taking two turns for each command, one
+ for the command and one turn to search. This means that you are
+ taking twice the time to move around the dungeon, and therefore
+ twice the food. Search mode will automatically turn off if you
+ are disturbed. You may also turn off search mode by entering the
+ Search Mode command again.
+~~~~~116|Commands|Alteration commands
+~~~~~117|Commands|Terrain interaction
+#####R--- Alter Commands ---
+~~~~~37
+[[[[[GTunnel (T) or Tunnel (^T)]
+ Tunnelling or mining is a very useful art. There are many kinds of
+ rock, with varying hardness, including permanent rock (permanent),
+ granite (very hard), quartz veins (hard), magma veins (soft), and
+ rubble (very soft). Quartz and Magma veins may be displayed in a
+ special way, and may sometimes contain treasure, in which case they
+ will be displayed in a different way. Rubble sometimes covers an
+ object. It is only possible to tunnel if you are wielding a digging
+ tool such as a shovel or a pick. Tunnelling ability increases with
+ strength and tool weight. This command can take a count, requires a
+ direction, and is affected by the "always_repeat" option.
+~~~~~26
+[[[[[GOpen a door or chest (o)]
+ To open an object such as a door or chest, you must use this
+ command. If the object is locked, you will attempt to pick the
+ lock based on your disarming ability. If you open a trapped chest
+ without disarming the traps first, the trap will be set off. Some
+ doors will be jammed shut and may have to be forced open. You may
+ need several tries to open a door or chest. Open can take a count,
+ requires a direction, and is affected by the "always_repeat" option.
+~~~~~5
+[[[[[GClose a door (c)]
+ Non-intelligent and some other creatures cannot open doors, so
+ shutting doors can be quite valuable. Broken doors cannot be closed.
+ Bashing a door open may break it. Close can take a count, requires a
+ direction, and is affected by the "always_repeat" option.
+~~~~~19
+[[[[[GJam a door (j) or Spike a door (S)]
+ Many monsters can simply open closed doors, and can eventually
+ get through a locked door. You may therefore occasionally want
+ to jam a door shut with iron spikes. Each spike used on the door
+ will make it harder to bash down the door, up to a certain limit.
+ Smaller monsters are less able to bash down doors. In order to
+ use this command, you must be carrying iron spikes. Jam or Spike
+ requires a direction.
+~~~~~4
+[[[[[GBash a door (B) or Force a door (f)]
+ This command allows you to bash down jammed doors. Your bashing
+ ability increases with strength. Bashing open a door can (briefly)
+ throw you off balance. Doors that are stuck, or which have been
+ jammed closed with spikes can only be opened by bashing, and all
+ closed doors can be bashed open if desired. Bashing a door open
+ may permanently break it so that it can never be closed. Bash or
+ Force can take a count, requires a direction, and is affected by
+ the "always_repeat" option.
+~~~~~8
+[[[[[GDisarm a trap or chest (D)]
+ You can attempt to disarm traps on the floor or on chests. If you
+ fail, there is a chance that you will blunder and set it off. You
+ can only disarm a trap after you have found it (usually with the
+ Search command). Disarm can take a count, requires a direction,
+ and is affected by the "always_repeat" option.
+~~~~~63
+[[[[[GAlter (+)]
+ This special command allows the use of a single keypress to select
+ any of the "obvious" commands above (attack, tunnel, bash, open,
+ disarm, close), and, by using macros or keymaps, to combine this
+ keypress with directions. In general, this allows the use of the
+ "control" key plus the appropriate "direction" key (including the
+ roguelike direction keys in roguelike mode) as a kind of generic
+ "alter the terrain feature of an adjacent grid" command. Alter
+ can take a count, requires a direction, and is affected by the
+ "always_repeat" option.
+~~~~~43
+[[[[[GEngrave the floor (x)]
+ The dungeon is full of magics, and as such pools of it collect on
+ the floor in places. With the "inscribe" command, it is possible
+ to create some spell effects by inscribing words you have read from
+ various parchments detailing the languages used within the dungeon.
+ Then, if there is enough mana collected on that square, walking over
+ the inscription will trigger the spell. Some spells can be triggered
+ only by the player, some only by monsters, and some are triggered by
+ both.
+~~~~~46
+[[[[[GSteal (Z)]
+ Allows the player to try to steal items from shops. Also allows
+ rogues to steal from monsters.
+~~~~~118|Commands|Spells and prayers
+#####R--- Spell and Prayer Commands ---
+~~~~~3
+[[[[[GBrowse a book (b) or Peruse a book (P)]
+ Only characters with some knowledge in the magic schools, such as
+ mages, priests, rogues, and rangers, can read magic spellbooks.
+ Warriors normally cannot read any books. When this command is used,
+ all of the spells or prayers contained in the selected book are
+ displayed, along with information such as their level, the amount of
+ mana or piety required to cast them, and whether or not you know the
+ spell or prayer.
+~~~~~14
+[[[[[GGain new skills (G)]
+ Use this command to access the skills menu and spend the skill points
+ you gain at each new character level to increase the range of things
+ your character is able to do.
+~~~~~91
+[[[[[GGain new abilities (N)]
+ Use this command to access the Abilities menu and spend the skill points
+ you gain at each new character level to increase the range of things
+ your character is able to do.
+~~~~~24
+[[[[[GCast a spell / Pray a prayer (m) / Use a mental power]
+ To cast a spell or prayer, you must have the skill level required in
+ that school of magic to be able access that spell, and a book that
+ contains that spell in your inventory (for most schools). Each spell
+ has a chance of failure which starts out fairly large but decreases
+ as you gain levels. If you don't have enough mana to cast a spell,
+ you will be told you do not have enough mana to cast it. Since in most
+ cases you must read the spell from a book, you cannot be blind or
+ confused while casting, and there must be some light present.
+
+ Some classes (for example, Thaumaturgists) have the ability to use
+ some magic without actually needing spell books of any sort. These
+ classes are able to access their magical powers through the use of
+ the 'm' command.
+~~~~~39
+[[[[[GUse bonus power (if any) (U) or (O)]
+ Some races and classes have special natural abilities. All of these
+ possible abilities are listed in an index under the U (or O) command.
+ These type of abilities can include the Vampire's bite, a DeathMold's
+ telekinesis, and a RohanKnight's light speed capabilities.
+~~~~~119|Commands|Object manipulation
+#####R--- Object Manipulation Commands ---
+~~~~~10
+[[[[[GEat some food (E)]
+ You must eat regularly to prevent starvation. As you grow hungry,
+ a message will appear at the bottom of the screen saying "Hungry".
+ If you go hungry long enough, you will become weak, then start
+ fainting, and eventually, you may will die of starvation. You
+ may use this command to eat food in your inventory. Note that
+ you can sometimes find food in the dungeon, or you can butcher
+ corpses of killed creatures to obtain raw meat, but it is not
+ always wise to eat strange food.
+~~~~~12
+[[[[[GFuel your lantern/torch (F)]
+ If you are using a torch and have more torches in your pack,
+ or you are using a lantern and have flasks of oil in your pack,
+ then your can "refuel" them with this command. Torches and Lanterns
+ are limited in their maximal fuel. In general, two flasks will fully
+ fuel a lantern and two torches will fully fuel a torch.
+~~~~~30
+[[[[[GQuaff a potion (q)]
+ Use this command to drink a potion. Potions affect the player in
+ various ways, but the effects are not always immediately obvious.
+~~~~~32
+[[[[[GRead a scroll (r)]
+ Use this command to read a scroll. Scroll spells usually have an
+ area effect, except for a few cases where they act on other objects.
+ Reading a scroll causes the parchment to disintegrate as the scroll
+ takes effect, unless you are an Alchemist. Most scrolls which prompt
+ for more information can be aborted (by pressing escape), which will
+ stop reading the scroll before it disintegrates.
+~~~~~58
+[[[[[GInscribe an object ({)]
+ This command inscribes a string on an object. The inscription is
+ displayed inside curly braces after the object description. The
+ inscription is limited to the particular object (or pile) and is
+ not automatically transferred to all similar objects. Under certain
+ circumstances, ToME will display "fake" inscriptions on certain
+ objects ("cursed", "broken", "tried", "empty", "NN% off") when
+ appropriate. These "fake" inscriptions are "covered up" by real
+ inscriptions, but will re-appear if the real inscription is removed.
+ In addition, ToME will occasionally place a "real" inscription on
+ an object for you, normally as the result of your character getting
+ a "feeling" about the item. All characters will get "feelings" about
+ weapons and armor after carrying them for a while. Warriors get the
+ most detailed feelings, and get them quicker than any other class.
+ An item labeled as "{empty}" was found to be out of charges, and an
+ item labeled as "{tried}" is a "flavoured" item which the character
+ has used, but whose effects are unknown. Certain inscriptions have
+ a meaning to the game, see "@#", "@x#", "!*", and "!x", in the section
+ on *****command.txt*90[inventory object selection.]
+~~~~~59
+[[[[[GUninscribe an object (})]
+ This command removes the inscription on an object. This command will
+ have no effect on "fake" inscriptions added by the game itself.
+~~~~~15
+[[[[[GHack up a corpse (h or $)]
+ Corpses can be cut up into smaller pieces of meat, allowing the user to
+ eat the meat, or cure it for later use.
+~~~~~21
+[[[[[GCure meat (K)]
+ Curing meat requires the use of a potion of salt water, and is used to
+ protect meat from hacked-up corpses from going bad.
+~~~~~16
+[[[[[GDrink from a fountain (H)]
+ All fountains in Arda are magical, and act like magical potions. The
+ game will ask you whether you want to quaff from a fountain or to fill
+ empty bottles. The only way to identify the type of fountain is to
+ fill your bottles from it and see what you get.
+~~~~~44
+[[[[[GGive item to monster (y)]
+ This command is used to give an item within your inventory to a monster
+ standing next to you. The monster may not accept the item you give it,
+ however.
+~~~~~96
+[[[[[GChat (Y)]
+ This command allows you to chat with someone. Be warned that most
+ monsters won't chat
+
+#####R--- Magical Object Commands ---
+~~~~~2
+[[[[[GActivate an artifact (A)]
+ You have heard rumours of special weapons and armour deep in the
+ Pits, items that can let you breath fire like a dragon or light
+ rooms with just a thought. Should you ever be lucky enough to
+ find such an item, this command will let you activate its special
+ ability. Special abilities can only be used if you are wearing or
+ wielding the item.
+ Note that there are also a few common objects that can be activated,
+ e.g. music instruments, monster eggs and spell-storing mage staves,
+ and that some artifacts, so-called "junkarts", can't be wielded, but
+ must be activated from the backpack.
+~~~~~1
+[[[[[GAim a wand (a) or Zap a wand (z)]
+ Wands must be aimed in a direction to be used. Wands are magical
+ devices, and therefore there is a chance you will not be able to
+ figure out how to use them if you aren't good with magical
+ devices. They will fire a shot that affects the first object or
+ creature encountered or fire a beam that affects anything in a
+ given direction, depending on the wand. An obstruction such as a
+ door or wall will generally stop the effects from traveling any
+ farther. This command requires a direction and can use a target.
+~~~~~38
+[[[[[GUse a staff (u) or Zap a staff (Z)]
+ This command will use a staff. A staff is normally very similar
+ to a scroll, in that they normally either have an area effect or
+ affect a specific object. Staves are magical devices, and there
+ is a chance you will not be able to figure out how to use them.
+~~~~~45
+[[[[[GZap a rod (z) or Activate a rod (a)]
+ Rods are extremely powerful magical items, which cannot be burnt
+ or shattered, and which can have either staff-like or wand-like
+ effects, but unlike staves and wands, they don't have charges.
+ Instead, they draw on the ambient magical energy to recharge
+ themselves, and therefore can only be activated once every few
+ turns. The recharging time varies depending on the type of rod.
+ This command may require a direction (depending on the type of
+ rod, and whether you are aware of its type) and can use a target.
+~~~~~120|Commands|Throwing and missile weapons
+#####R--- Throwing and Missile Weapons ---
+~~~~~11
+[[[[[GFire an item (f) or Fire an item (t)]
+ You may throw any object carried by your character. Depending on
+ the weight, it may travel across the room or drop down beside you.
+ Only one object from a pile will be thrown at a time. Note that
+ throwing an object will often cause it to break, so be careful!
+ If you throw something at a creature, your chances of hitting it
+ are determined by your pluses to hit, your ability at throwing,
+ and the object's pluses to hit. Once the creature is it, the
+ object may or may not do any damage to it. You've heard rumors
+ that some objects found in the dungeon can do huge amounts of
+ damage when thrown, but you're not sure which objects those
+ are.... Note that flasks of oil will do a fairly large chunk
+ of damage to a monster on impact, supposedly representing fire
+ damage, but it works against fire elementals too... If you are
+ wielding a missile launcher compatible with the object you are
+ throwing, then you automatically use the launcher to fire the
+ missile with much higher range, accuracy, and damage, then you
+ would get by just throwing the missile. Fire or Throw requires
+ a direction. Targeting mode (see the next command) can be invoked
+ with "*" at the "Direction?" prompt.
+~~~~~40
+[[[[[GThrow an item (v)]
+ You may throw any object carried by your character. The lighter
+ the object, the farther you can throw it. Only one object from a
+ stack may be thrown at a time. Throwing an object may break it.
+ If you throw something at a monster, your chances of hitting it
+ are determined by your pluses to hit, your ability at throwing,
+ and the object's pluses to hit. If the object hits the monster,
+ it may or may not do damage. Some objects, such as weapons, or
+ flasks of oil, can do a substantial amount of damage. This
+ command requires a direction, and can take a target.
+~~~~~55
+[[[[[GTargeting Mode (*)]
+ This will allow you to aim your spells and such at a specific
+ monster or grid, so that you can point directly towards that
+ monster or grid (even if this is not a "compass" direction) when
+ you are asked for a direction. You can set a target using this
+ command, or you can set a new target at the "Direction?" prompt when
+ appropriate. At the targeting prompt, you have many options. First
+ of all, targetting mode starts targetting nearby monsters which can
+ be reached by "projectable" spells and thrown objects. In this mode,
+ you can press "t" (or "5" or ".") to select the current monster,
+ space to advance to the next monster, "-" to back up to the previous
+ monster, direction keys to advance to a monster more or less in that
+ direction, "r" to "recall" the current monster, "q" to exit targetting
+ mode, and "p" (or "o") to stop targetting monsters and enter the mode
+ for targetting a location on the floor or in a wall. Note that if
+ there are no nearby monsters, you will automatically enter this mode.
+ Note that hitting "o" is just like "p", except that the location
+ cursor starts on the last examined monster instead of on the player.
+ In this mode, you use the "direction" keys to move around, and the
+ "q" key to quit, and the "t" (or "5" or ".") key to target the cursor
+ location. Note that targetting a location is slightly "dangerous",
+ as the target is maintained even if you are far away. To cancel an
+ old target, simply hit "*" and then ESCAPE (or "q"). Note that when
+ you cast a spell or throw an object at the target location, the path
+ chosen is the "optimal" path towards that location, which may or may
+ not be the path you want. Sometimes, by clever choice of a location
+ on the floor for your target, you may be able to convince a thrown
+ object or cast spell to squeeze through a hole or corridor that is
+ blocking direct access to a different grid. Launching a ball spell
+ or breath weapon at a location in the middle of a group of monsters
+ can often improve the effects of that attack, since ball attacks are
+ not stopped by interposed monsters if the ball is launched at a target.
+ This command takes no time.
+~~~~~121|Commands|Looking
+#####R--- Looking Commands ---
+~~~~~25
+[[[[[GFull screen map (M)]
+ This command will show a map of the entire dungeon, reduced by a
+ factor of nine, on the screen. Only the major dungeon features
+ will be visible because of the scale, so even some important
+ objects may not show up on the map. This is particularly useful
+ in locating where the stairs are relative to your current
+ position, or for identifying unexplored areas of the dungeon.
+ This command takes no time.
+~~~~~23
+[[[[[GLocate player on map (L) or Where is the player (W)]
+ This command lets you scroll your map around, looking at all sectors
+ of the current dungeon level, until you press escape, at which point
+ the map will be re-centred on the player if necessary. To scroll
+ the map around, simply press any of the "direction" keys. The top
+ line will display the sector location, and the offset from your
+ current sector. This command takes no time.
+~~~~~22
+[[[[[GLook around (l) or Examine things (x)]
+ This command is used to look around at nearby monsters (to determine
+ their type and health) and objects (to determine their type). It is
+ also used to find out what objects (if any) are under monsters, and
+ if a monster is currently inside a wall. This command takes no time.
+ When you are looking at something, you may hit space for more details,
+ or to advance to the next interesting monster or object, or minus ("-")
+ to go back to the previous monster or object, or a direction key to
+ advance to the nearest interesting monster or object (if any) in that
+ general direction, or "r" to recall information about the current
+ monster race, or "q" or escape to stop looking around. You always
+ start out looking at the "nearest" interesting monster or object.
+~~~~~18
+[[[[[GObserve an item (I)]
+ This command lets you observe a previously *identified* item.
+ This will tell you things about the special powers of the object.
+ Currently, it only makes sense for artifacts and ego-items.
+~~~~~122|Commands|Messages
+#####R--- Message Commands ---
+~~~~~53
+[[[[[GRepeat level feeling (^F)]
+ Repeats the feeling about the dungeon level that you got when you
+ first entered the level.
+~~~~~62
+[[[[[GView previous messages (^P)]
+ This command shows you all the recent messages. You can scroll
+ through them, or exit with ESCAPE. This command takes no time.
+~~~~~69
+[[[[[GTake notes (:)]
+ This command allows you to take notes, which will then appear in your
+ note file, if the birth-option "take_notes" was set (the default), or
+ in your message list (prefixed with "Note:"), if the option was not set.
+ The note file can be displayed through the "Display Current Knowledge"
+ command (~ or |). This command takes no time.
+~~~~~123|Commands|Game status
+#####R--- Game Status Commands ---
+~~~~~6
+[[[[[GCharacter Description (C)]
+ Brings up a full description of your character, including your
+ skill levels, your current and potential stats, and various other
+ information. From this screen, you can change your name or use
+ the file character description command to save your character
+ status to a file. That command saves additional information,
+ including your background, your inventory, and the contents of
+ your house.
+~~~~~82
+[[[[[GDisplay Current Knowledge (~ or |)]
+ The command opens a menu from which you can lookup information
+ collected so far. This includes known artifacts, unique monsters,
+ identified objects, killed creatures, recall depths, acquired
+ corruptions, current pets, current quests, current fates, known
+ traps, known dungeon towns and last but not least the note file.
+
+ Display known artifacts
+ This selection lists all of the artifacts that you have encountered.
+ Any artifact that appears in this list, which you cannot seem to
+ find, has been lost forever. The "preserve" mode will prevent
+ you from accidentally losing any artifacts, but will also prevent
+ you from ever getting a "special" level feeling.
+
+ Display known uniques
+ Brings up a list of known unique monsters, plus their current
+ status. Once killed, unique monsters never show up again, with a
+ few remarkable exceptions.
+
+ Display known objects
+ This list all 'flavoured' objects (such as rings, scrolls, wands,
+ potions, etc.) which you have identified.
+
+ Display kill count
+ This lists all killed creatures together with a total kill count.
+
+ Display recall depths
+ This lists all recall depths of entered dungeons as well as marks
+ the current recall dungeon with an asterisk.
+
+ Display corruptions
+ This lists all acquired corruptions with their beneficial and
+ detrimental effects.
+
+ Display current pets
+ Display current quests
+ Display current fates
+ Display known traps
+ Display known dungeon towns
+
+ Display notes
+ If the option "take_notes" is set shows you your notes file, where all
+ remarkable events are noted. You can add notes yourself by using the
+ "Take notes" command (:).
+
+~~~~~70
+[[[[[GTime of the day (^T)]
+ This command is used to give the current date and time within the game.
+ Extremely useful for characters such as Vampires to check whether
+ it is safe to leave the dungeon.
+~~~~~124|Commands|Saving and Exiting
+~~~~~125|Saving and Exiting
+#####R--- Saving and Exiting Commands ---
+~~~~~75
+[[[[[GSave and Quit (Ctrl-X)]
+ To save your game so that you can return to it later, use this
+ command. Save files will also be generated (hopefully) if the
+ game crashes due to a system error. After you die, you can use
+ your savefile to play again with the same options and such.
+~~~~~68
+[[[[[GSave (Ctrl-S)]
+ This command saves the game but doesn't exit ToME. Use this
+ frequently if you are paranoid about having the computer crash
+ while you are playing.
+~~~~~31
+[[[[[GQuit (commit suicide) (Q)]
+ Kills your character and exits ToME. You will be prompted to
+ make sure you really want to do this, and then asked to verify
+ that choice. Note that dead characters are dead forever.
+~~~~~126|Commands|Pref files
+~~~~~127|Pref files|Commands
+#####R--- User pref file commands ---
+~~~~~65
+[[[[[GInteract with options (=)]
+ Allow you to interact with options. Note that using the "cheat"
+ options may mark your savefile as unsuitable for the high score
+ list. You may change normal options using the "X" and "Y" user
+ pref commands. You must use the "redraw" command (^R) after
+ changing certain options.
+~~~~~49
+[[[[[GInteract with macros (@)]
+ Allow you to interact with macros. You may load or save macros
+ from user pref files, create macros of various types, or define
+ keymaps. You must define a "current action", shown at the bottom
+ of the screen, before you attempt to use any of the "create macro"
+ commands, which use that "current action" as their action. This
+ is a horrible interface, and will be fixed eventually.
+~~~~~51
+[[[[[GInteract with visuals (%)]
+ Allow you to interact with visuals. You may load or save visuals
+ from user pref files, or modify the attr/char mappings for the
+ monsters, objects, and terrain features. You must use the "redraw"
+ command (^R) to redraw the map after changing attr/char mappings.
+~~~~~54
+[[[[[GInteract with colors (&)]
+ Allow the user to interact with colors. This command only
+ works on some systems.
+~~~~~47
+[[[[[GInteract with the system (!)]
+ Allow the user to interact with the underlying visual system.
+ This command is currently unused.
+~~~~~71
+[[[[[GEnter a user pref command (")]
+ ToME stores your preferences in files called "user pref files",
+ which contain comments and "user pref commands", which are simple strings
+ describing one aspect of the system about which the user has a preference.
+ You may enter single user pref commands directly, using the special "Enter
+ a user pref command" command, activated by "double quote". You may have to
+ use the "redraw" command (^R) after changing certain of the aspects of the
+ game, to allow ToME to adapt to your changes.
+~~~~~128|Commands|Help
+#####R--- Help ---
+~~~~~84
+[[[[[GHelp (?)]
+ Brings up the ToME on-line help system. Note that the help
+ files are just text files in a particular format, and that other
+ help files may be available on the Net. In particular, there are
+ a variety of spoiler files which do not come with the standard
+ distribution. Check the place you got ToME from or ask on the
+ newsgroup rec.games.roguelike.angband about them.
+~~~~~83
+[[[[[GIdentify Symbol (/)]
+ Use this command to find out what a character stands for. For
+ instance, by pressing "/.", you can find out that the "." symbol
+ stands for a floor spot. When used with a symbol that represents
+ creatures, the this command will tell you only what class of
+ creature the symbol stands for, not give you specific information
+ about a creature you can see. To get that, use the Look command.
+
+ There are three special symbols you can use with the Identify
+ Symbol command to access specific parts of your monster memory.
+ Typing Ctrl-A when asked for a symbol will recall details about
+ all monsters, typing Ctrl-U will recall details about all unique
+ monsters, and typing Ctrl-N will recall details about all
+ non-unique monsters.
+
+ If the character stands for a creature, you are asked if you want
+ to recall details. If you answer yes, information about the
+ creatures you have encountered with that symbol is shown in the
+ Recall window if available, or on the screen if not. You can also
+ answer "k" to see the list sorted by number of kills, or "p" to
+ see the list sorted by dungeon level the monster is normally found
+ on. Pressing ESCAPE at any point will exit this command.
+~~~~~41
+[[[[[GGame Version (V)]
+ This command will tell you what version of ToME you are using.
+ For more information, see the "version.txt" help file.
+
+~~~~~129|Commands|Extras
+#####R--- Extra Commands ---
+~~~~~85
+[[[[[GRepeat last command (n)]
+ This will automatically repeat the last command you inputted.
+~~~~~27
+[[[[[GSacrifice at an altar (O)]
+ Altars are places dedicated to the worship of a particular God. To
+ start worshipping the God who owns the altar, you must first sacrifice
+ on their altar.
+
+ Be warned, not all Gods are equal in power, and once you have selected
+ a God to worship, it is almost impossible to change which God you worship.
+ When your God is happy with you, you will receive more benefits from them.
+ Your God's happiness will decrease over time, so you will need to accomplish
+ deeds that increase your standing. Note that there is no requirement
+ for most classes to worship any God. (See *****gods.txt*0[gods.txt] for more information)
+~~~~~28
+[[[[[GPray to your God (p)]
+ If you worship a God, you have the option of praying. The effects of
+ praying differ considerably depending on the god, ranging from the
+ battle frenzy of paladins to the self-healing powers of druids.
+ However, Gods do not like being disturbed, with negative effects on
+ your piety. See *****gods.txt*0[gods.txt] for more information.
+~~~~~29
+[[[[[GPet commands (P)]
+ From time to time, you may acquire a pet within the dungeon. Pets are able
+ (to a more or less limited extent) to follow some simple commands, like
+ follow me. These commands are all accessed through the menu under "Pet
+ Commands".
+~~~~~52
+[[[[[GToggle Choice Window (^E)]
+ Toggles the display in the choice window (if available) between
+ your inventory and your equipment. This command only applies if
+ you are running ToME under a windowing environment and the
+ choice window is available. This also redraws the choice window.
+~~~~~66
+[[[[[GRedraw Screen (^R)]
+ This command adapts to various changes in global options, and
+ redraws all of the windows. This command should be used after
+ changing various global properties (options, attr/char mappings,
+ color definitions, etc). When in doubt, use it.
+~~~~~56
+[[[[[GLoad screen dump (left-paren)]
+ This command loads a "snap-shot" of the current screen from the file
+ "dump.txt", and displays it on the screen.
+~~~~~57
+[[[[[GSave screen dump (right-paren)]
+ This command dumps a "snap-shot" of the current screen to the file
+ "dump.txt", including encoded color information.
+~~~~~64
+[[[[[GQuit to next midi song (^Q)]
+ In the DOS binary (and maybe Windows) of ToME, it is possible for
+ the game to play any midi song in the lib/xtra/music directory. This
+ command allows the player to force the game to finish the current song
+ and move on to another one (i.e. if you are tired of hearing the current
+ song, you can change it).
+~~~~~80
+[[[[[GDo cmovies (|)]
+ The cmovie command (press | key in both normal or roguelike set) allows
+ you to make a "movie" that you can send to people showing your movement
+ through a part of the dungeon (like clearing that GCV . . .)
+
+ It asks for a name (it will add the extension itself) and then if you wish
+ to play or record it.
+
+ The cmovie files (.cmv) are located in lib/cmov, note that they quickly
+ become huge and so you REALLY should compress them before sending to friends.
+~~~~~97
+[[[[[GRecord macros ($)]
+ This is an easier way to create macros. Activate it, press the key
+ sequence for your macro, reactivate it and it will create the macro
+ for you. Note than when possible using the @ key at item selection
+ is a good idea since it removes the need to inscribe items.
+~~~~~98
+[[[[[GTake html screenshot (^\])]
+ Creates an html screenshot of the current screen.
+~~~~~89
+[[[[[GBegin extended command (#)]
+ Begins an extended command. Type "help" or "?" at the prompt for a
+ list of these commands.
+
+--
+Original: Alexander Cutler and Andy Astrand
+Updated (2.7.6): Russ Allbery (rra@cs.stanford.edu)
+Updated (2.7.9): Ben Harrison (benh@phial.com)
+Updated PernAngband 5.x.x: Dawnmist (angband@dawnmist.8m.com)
+Updated for ToME 2.1
diff --git a/lib/mods/theme/help/corspoil.txt b/lib/mods/theme/help/corspoil.txt
new file mode 100644
index 00000000..baac4fae
--- /dev/null
+++ b/lib/mods/theme/help/corspoil.txt
@@ -0,0 +1,136 @@
+~~~~~01|Corruptions (Spoiler)
+~~~~~02|Spoilers|Corruptions
+#####R=== ToME Corruptions Spoiler ===
+
+Sometimes adventurers become exposed to the dark powers of Morgoth. If they
+are unable to resist these powers, they become corrupted. Corruptions can
+change their physical or mental abilities, some of which can be good, and
+some bad. Most corruptions will affect you permanently, although some only
+operate when they are activated (whether by player choice or as a random
+event). You can check which corruptions do you have in the knowledge screen
+6 (accessed through the '~' menu) or in a character dump.
+
+#####GGaining and (not) losing corruptions
+There are several ways that you can become corrupted.
+
+You can become corrupted by quaffing a Potion of Corruption or by drinking
+from a Fountain of Corruption. Also some strange items can be activated
+for corruption.
+
+Corruptions are permanent. Once you have one, you have it for life.
+
+[[[[[BBalrog Aura]
+ Surrounds you with a fiery aura
+ But it can burn scrolls when you read them
+[[[[[GGain message: A corrupted wall of flames surrounds you.]
+[[[[[RLose message: The wall of corrupted flames abandons you.]
+
+
+[[[[[BBalrog Wings]
+ Creates ugly, but working, wings allowing you to fly
+ But it reduces charisma by 4 and dexterity by 2
+[[[[[GGain message: Wings of shadow grow in your back.]
+[[[[[RLose message: The wings in your back fall apart.]
+
+
+[[[[[BBalrog Strength]
+ Provides 3 strength and 1 constitution
+ But it reduces charisma by 1 and dexterity by 3
+[[[[[GGain message: Your muscles get unnatural strength.]
+[[[[[RLose message: Your muscles get weaker again.]
+
+
+[[[[[BBalrog Form]
+ Allows you to turn into a Balrog at will
+ You need Balrog Aura, Balrog Wings and Balrog Strength to activate it
+[[[[[GGain message: You feel the might of a Balrog inside you.]
+[[[[[RLose message: The presence of the Balrog seems to abandon you.]
+It depends on:
+ Balrog Aura
+ Balrog Wings
+ Balrog Strength
+
+
+[[[[[BDemon Spirit]
+ Increases your intelligence by 1
+ But reduce your charisma by 2
+[[[[[GGain message: Your spirit opens to corrupted thoughts.]
+[[[[[RLose message: Your spirit closes again to the corrupted thoughts.]
+
+
+[[[[[BDemon Hide]
+ Increases your armour class by your level
+ Provides immunity to fire at level 40
+ But reduces speed by your level / 7
+[[[[[GGain message: Your skin grows into a thick hide.]
+[[[[[RLose message: Your skin returns to a natural state.]
+
+
+[[[[[BDemon Breath]
+ Provides fire breath
+ But gives a small chance to spoil potions when you quaff them
+[[[[[GGain message: Your breath becomes mephitic.]
+[[[[[RLose message: Your breath is once again normal.]
+
+
+[[[[[BDemon Realm]
+ Provides access to the demon school skill and the use of demonic equipment
+ You need Demon Spirit, Demon Hide and Demon Breath to activate it
+[[[[[GGain message: You feel more attuned to the demon realm.]
+[[[[[RLose message: You lose your attunement to the demon realm.]
+It depends on:
+ Demon Spirit
+ Demon Hide
+ Demon Breath
+
+
+[[[[[BRandom teleportation]
+ Randomly teleports you around
+[[[[[GGain message: Space seems to fizzle around you.]
+[[[[[RLose message: Space solidify again around you.]
+It is opposed to:
+ Anti-teleportation
+
+
+[[[[[BAnti-teleportation]
+ Prevents all teleportations, be it of you or monsters
+[[[[[GGain message: Space continuum freezes around you.]
+[[[[[RLose message: Space continuum can once more be altered around you.]
+It is opposed to:
+ Random teleportation
+
+
+[[[[[BTroll Blood]
+ Troll blood flows in your veins, granting increased regeneration
+ It also enables you to feel the presence of other troll beings
+ But it will make your presence more noticeable and aggravating
+[[[[[GGain message: Your blood thickens, you sense corruption in it.]
+[[[[[RLose message: Your blood returns to a normal state.]
+
+
+[[[[[BVampiric Teeth]
+ Your teeth allow you to drain blood to feed yourself
+ However your stomach now only accepts blood.
+[[[[[GGain message: You grow vampiric teeth!]
+It is not removable.
+
+
+[[[[[BVampiric Strength]
+ Your body seems somewhat dead
+ In this near-undead state it has improved strength, constitution and
+ intelligence, but also reduced dexterity, wisdom and charisma.
+[[[[[GGain message: Your body seems more dead than alive.]
+It is not removable.
+It depends on:
+ Vampiric Teeth
+
+
+[[[[[BVampire]
+ You are a Vampire. As such you resist cold, poison, darkness and nether.
+ Your life is sustained, but you cannot stand the light of the sun.
+[[[[[GGain message: You die to be reborn in a Vampire form.]
+It is not removable.
+It depends on:
+ Vampiric Strength
+
+
diff --git a/lib/mods/theme/help/debug.txt b/lib/mods/theme/help/debug.txt
new file mode 100644
index 00000000..56d57098
--- /dev/null
+++ b/lib/mods/theme/help/debug.txt
@@ -0,0 +1,278 @@
+|||||oy
+~~~~~99|Debug
+#####R=== Debug Commands ===
+
+
+Debug commands are entered as an "underlying command" (a single key)
+plus a variety of optional or required arguments.
+
+The debug commands are used for debugging and experimenting. The game
+will not be scored if you use debug commands.
+
+~~~~~100|Debug|Command List
+#####R=== Command List Summary ===
+
+ *****debug.txt*1[a Autorestore] *****debug.txt*2[A Show all stats]
+ *****debug.txt*3[b Teleport to target] *****debug.txt*4[B HP to zero]
+ *****debug.txt*5[c Create object] *****debug.txt*6[C Create artifact]
+ *****debug.txt*7[d Detect all] *****debug.txt*8[D Teleport to the wilderness]
+ *****debug.txt*9[e Edit character attributes] *****debug.txt*10[E Change grid's mana]
+ *****debug.txt*11[f *IDENTIFY*] *****debug.txt*12[F Features]
+ *****debug.txt*13[g Create good item] G (unused)
+ *****debug.txt*15[h Change life rating] *****debug.txt*16[H Hostile monster creation]
+ *****debug.txt*17[i Identify] I (unused)
+ *****debug.txt*19[j Jump to other level] J (unused)
+ *****debug.txt*21[k Check attributes] K (unused)
+ *****debug.txt*23[l Learn about objects] L (unused)
+ *****debug.txt*25[m Magic Mapping] *****debug.txt*26[M Gain corruption]
+ *****debug.txt*27[n Summon named monster] *****debug.txt*28[N Summon _friendly_ named monster]
+ *****debug.txt*29[o Edit object attributes] O (unused)
+ *****debug.txt*31[p Phase door] *****debug.txt*32[P Panic save]
+ *****debug.txt*33[q Get a quest] Q (unused)
+ *****debug.txt*35[r Gain reward] *****debug.txt*36[R Create a trap]
+ *****debug.txt*37[s Summon monster] *****debug.txt*38[S Change the feature of the map]
+ *****debug.txt*39[t Teleport] *****debug.txt*40[T Teleport to a town]
+ *****debug.txt*41[u Complete map] *****debug.txt*42[U Become undead]
+ *****debug.txt*43[v Random artifact/ego item] V (unused)
+ *****debug.txt*45[w Wizard light the level] *****debug.txt*46[W Wish]
+ *****debug.txt*47[x XP boost] X (unused)
+ y (unused) Y (unused)
+ *****debug.txt*51[z Zap monsters] Z (unused)
+ ! (unused) ^A (unused)
+ *****debug.txt*55[@ Increment monster level] ^B (unused)
+ # (unused) ^C (unused)
+ $ (unused) ^D (unused)
+ % (unused) ^E (unused)
+ ^ (unused) ^F (unused)
+ & (unused) ^G (unused)
+ *****debug.txt*61[* Lose special powers] ^H (unused)
+ ( (unused) ^I (unused)
+ ) (unused) ^J (unused)
+ { (unused) ^K (unused)
+ } (unused) ^L (unused)
+ [ (unused) ^M (unused)
+ ] (unused) ^N (unused)
+ *****debug.txt*67[- Create object] ^O (unused)
+ *****debug.txt*69[_ The path to the god dark] ^P (unused)
+ *****debug.txt*71[+ Gain a fate] ^Q (unused)
+ *****debug.txt*73[= Align monster] ^R (unused)
+ ; (unused) ^S (unused)
+ : (unused) ^T (unused)
+ ' (unused) ^U (unused)
+ *****debug.txt*75[" Create spoiler] ^V (unused)
+ , (unused) ^W (unused)
+ < (unused) ^X (unused)
+ . (unused) ^Y (unused)
+ *****debug.txt*81[> Lua script] ^Z (unused)
+ \ (unused) | (unused)
+ ` (unused) ~ (unused)
+ *****debug.txt*91[/ Summon monster] *****debug.txt*92[? Help]
+ ^\ (unused)
+
+~~~~~111|Debug|Command descriptions
+#####R=== Command Descriptions ===
+
+ The following command descriptions are listed as the command name
+plus the "underlying command" key. Then comes a brief description of the
+command. Some commands use the "repeat count" to automatically repeat the
+command several times, while others use the "repeat count" as an "argument",
+for example, commands which need a "quantity" will use the "repeat count"
+instead of asking for a quantity, allowing the use of "0d" for "drop all".
+Commands which ask for a quantity will convert any "letters" into the
+maximal legal value.
+~~~~~112|Debug|General
+#####R--- General Commands ---
+~~~~~1
+[[[[[GAutorestore (a)]
+ Restores all your stats. This includes HP, SP, hunger, lost levels, etc.
+~~~~~2
+[[[[[GShow all stats (A)]
+ This brings up the Character status menu, where you can view
+ all the stats about your character.
+~~~~~3
+[[[[[GTeleport to target (b)]
+ You first need to have a monster targeted, then you can use
+ this command to teleport next to the monster.
+~~~~~4
+[[[[[GHP to zero (B)]
+ Bring your health down to zero.
+~~~~~5
+[[[[[GCreate object (c)]
+ Allows you to select and create a new object where you stand.
+ This brings up a menu where you can choose what type of object
+ you want created.
+~~~~~6
+[[[[[GCreate artifact (C)]
+ Allows you to select and create a new artifact where you stand.
+ Use the "Command count", aka 0, to specify a number from
+ a_info.txt to put it on the ground where you are standing.
+ For example : 03^AC will create the Arkenstone of Thrane (+3)
+~~~~~7
+[[[[[GDetect all (d)]
+ Sense ways out/monsters/objects/traps.
+~~~~~8
+[[[[[GTeleport to the wilderness (D)]
+ From a dungeon this will teleport you to the wilderness level
+ and if used in the wilderness it acts like teleport.
+~~~~~9
+[[[[[GEdit character attributes (e)]
+ Edit character attributes including Str, Int, Dex, experience, gold, luck, etc.
+~~~~~10
+[[[[[GChange grid's mana (E)]
+ Alter how much mana a grid has.
+ Use the "Command count", aka 0, to specify the amount of mana
+ that you want.
+~~~~~11
+[[[[[G*IDENTIFY* (f)]
+ Like a Scroll of *Identify*.
+~~~~~12
+[[[[[GFeatures (F)]
+ Use the "Command count", aka 0, to specify a number from
+ f_info.txt to put a feature on the ground where you are
+ standing.
+~~~~~13
+[[[[[GCreate good item (g)]
+ Create a random good item where you stand.
+~~~~~15
+[[[[[GChange life rating (h)]
+ Change your life rating.
+~~~~~16
+[[[[[GHostile monster creation (H)]
+ Summons a Pack of Creatures of the same kind. Will only work
+ if MONSTER_HORDES has been defined at compile time.
+~~~~~17
+[[[[[GIdentify (i)]
+ Like a Scroll of Identify.
+~~~~~19
+[[[[[GJump to other level (j)]
+ Jump to other dungeon level. This does not work in the
+ wilderness as it is treated as all one level.
+~~~~~21
+[[[[[GCheck attributes (k)]
+ Displays your characters attributes.
+~~~~~23
+[[[[[GLearn about objects (l)]
+ Make you know about all objects. Not sure how this works.
+~~~~~25
+[[[[[GMagic Mapping (m)]
+ Like a Scroll of Magic mapping.
+~~~~~26
+[[[[[GGain corruption (M)]
+ Allows your character to gain a corruption.
+~~~~~27
+[[[[[GSummon named monster (n)]
+ Summon a monster that will appear next to you.
+ Use the "Command count", aka 0, to specify a number from
+ r_info.txt to summon a monster.
+~~~~~28
+[[[[[GSummon _friendly_ named monster (N)]
+ The same as n but the creature will be your pet. Try this
+ with number 861, Darkgod is now your pet.
+~~~~~29
+[[[[[GEdit object attributes (o)]
+ Allows you to alter the attributes of any object that you
+ have in your backpack.
+~~~~~31
+[[[[[GPhase door (p)]
+ Like a Scroll of Phase Door.
+~~~~~32
+[[[[[GPanic save (P)]
+ Save and quit the game, which is the same as doing a ^X.
+~~~~~33
+[[[[[GGet a quest (q)]
+ Get a quest.
+ Use the "Command count", aka 0, to specify a number from
+ 1 to 25, as defined in defines.h ( the QUEST_XXX items ).
+ For example : 04^Aq will get you the thieves quest.
+~~~~~35
+[[[[[GGain reward (r)]
+ Some high being grants you a reward.
+~~~~~36
+[[[[[GCreate a trap (R)]
+ Use the "Command count", aka 0, to specify a number from
+ tr_info.txt to put a trap on the ground where you are
+ standing.
+~~~~~37
+[[[[[GSummon monster (s)]
+ Summon a random monster, next to where you stand.
+~~~~~38
+[[[[[GChange the feature of the map (S)]
+ This allows you to change the "special" field of the current
+ grid. This special field is used to store things like quest
+ ids, dungeon entries, and so on, not to be used unless
+ one knows what it's doing.
+~~~~~39
+[[[[[GTeleport (t)]
+ Like a Scroll of Teleport.
+~~~~~40
+[[[[[GTeleport to a town (T)]
+ Teleports you to a specific town.
+ Use the "Command count", aka 0, to specify a number from
+ wf_info.txt for where you want to go.
+ standing.
+ For example : 02^AT will teleport you to Gondolin
+~~~~~41
+[[[[[GComplete map (u)]
+ Displays the complete map of the dungeon.
+~~~~~42
+[[[[[GBecome undead (U)]
+ This is supposed to make you undead (as in the Necromantic power).
+~~~~~43
+[[[[[GRandom artifact/ego item (v)]
+ Create a random artifact/ego item where you stand.
+~~~~~45
+[[[[[GWizard light the level (w)]
+ Looks like the same as u.
+~~~~~46
+[[[[[GWish (W)]
+ Makes all your wishes come true.
+
+ Read the *****wishing.txt*0[wishing spoiler] to see how these work.
+~~~~~47
+[[[[[GXP boost (x)]
+ Use the "Command count", aka 0, to specify the increment,
+ if you do not specify a parameter it doubles your XP,
+ otherwise it increments by the specified amount.
+~~~~~51
+[[[[[GZap monsters (z)]
+ All monsters in sight range vanish like Mass Genocide, only with no
+ HP price.
+~~~~~55
+[[[[[GIncrement monster level (@)]
+ Level up a monster.
+~~~~~61
+[[[[[GLose special powers (*)]
+ Returns your powers to a normal level.
+~~~~~67
+[[[[[GCreate object (-)]
+ Allows you to create a new object where you stand. You must
+ specify an object number from k_info.txt.
+~~~~~69
+[[[[[GThe path to the god dark (_)]
+ Do not use this as it is used by DarkGod as a test for Lua
+ and will CRASH the game. You have been warned.
+~~~~~71
+[[[[[GGain a fate (+)]
+ Unearth more of your prophecy.
+~~~~~73
+[[[[[GAlign monster (=)]
+ Use the "Command count", aka 0, to specify one of the following
+ alignment types:
+ 0 monster becomes enemy
+ 1 monster becomes neutral
+ 2 monster becomes friendly
+ 3 monster becomes pet
+ 4 monster becomes companion
+ You then point at an enemy and press space.
+~~~~~75
+[[[[[GCreate spoiler (")]
+ Brings up a menu that allows you to create a spoiler file.
+~~~~~81
+[[[[[GLua script (>)]
+ Allows you to run a Lua script.
+~~~~~91
+[[[[[GSummon monster (/)]
+ Summons a random monster next to you.
+~~~~~91
+[[[[[GHelp (?)]
+ Displays the main help file.
diff --git a/lib/mods/theme/help/def.aux b/lib/mods/theme/help/def.aux
new file mode 100644
index 00000000..983e9683
--- /dev/null
+++ b/lib/mods/theme/help/def.aux
@@ -0,0 +1,3 @@
+file_ext="html"
+link_prefix=""
+link_suffix=""
diff --git a/lib/mods/theme/help/defines.txt b/lib/mods/theme/help/defines.txt
new file mode 100644
index 00000000..ac997501
--- /dev/null
+++ b/lib/mods/theme/help/defines.txt
@@ -0,0 +1,639 @@
+|||||oy
+~~~~~81|Defines
+~~~~~85|Defines|Tvals
+~~~~~82|Automatizer|Defines
+~~~~~83|Tvals
+#####R /----------------------------------------\
+#####R < Tvals and svals >
+#####R \----------------------------------------/
+
+Some objects don't have svals as such. Spellbooks, wands, and staves for
+instance don't have svalues as they are defined in lua.
+
+TV_SKELETON 1 /* Skeletons ('s') */
+TV_BOTTLE 2 /* Empty bottles ('!') */
+*****defines.txt*04[TV_BATERIE] 4 /* For the Alchemists */
+TV_SPIKE 5 /* Spikes ('~') */
+TV_MSTAFF 6 /* Mage Staffs */
+TV_CHEST 7 /* Chests ('~') */
+TV_PARCHMENT 8 /* Parchments from Kamband */
+*****defines.txt*09[TV_CORPSE] 9 /* Monster corpses */
+TV_EGG 10 /* Monster Eggs */
+TV_JUNK 11 /* Sticks, Pottery, etc ('~') */
+*****defines.txt*12[TV_TOOL] 12 /* Tools */
+*****defines.txt*14[TV_INSTRUMENT] 14 /* Musical instruments */
+*****defines.txt*15[TV_BOOMERANG] 15 /* Boomerangs */
+*****defines.txt*16[TV_SHOT] 16 /* Ammo for slings */
+*****defines.txt*16[TV_ARROW] 17 /* Ammo for bows */
+*****defines.txt*16[TV_BOLT] 18 /* Ammo for x-bows */
+*****defines.txt*19[TV_BOW] 19 /* Slings/Bows/Xbows */
+*****defines.txt*20[TV_DIGGING] 20 /* Shovels/Picks */
+*****defines.txt*21[TV_HAFTED] 21 /* Priest Weapons */
+*****defines.txt*22[TV_POLEARM] 22 /* Pikes/Glaives/Spears/etc. */
+*****defines.txt*23[TV_SWORD] 23 /* Edged Weapons */
+*****defines.txt*24[TV_AXE] 24 /* Axes/Cleavers */
+*****defines.txt*30[TV_BOOTS] 30 /* Boots */
+*****defines.txt*31[TV_GLOVES] 31 /* Gloves */
+*****defines.txt*32[TV_HELM] 32 /* Helms */
+*****defines.txt*32[TV_CROWN] 33 /* Crowns */
+*****defines.txt*34[TV_SHIELD] 34 /* Shields */
+*****defines.txt*35[TV_CLOAK] 35 /* Cloaks */
+*****defines.txt*36[TV_SOFT_ARMOR] 36 /* Soft Armor */
+*****defines.txt*37[TV_HARD_ARMOR] 37 /* Hard Armor */
+*****defines.txt*38[TV_DRAG_ARMOR] 38 /* Dragon Scale Mail */
+*****defines.txt*39[TV_LITE] 39 /* Lites (including Specials) */
+*****defines.txt*40[TV_AMULET] 40 /* Amulets (including Specials) */
+*****defines.txt*45[TV_RING] 45 /* Rings (including Specials) */
+*****defines.txt*46[TV_TRAPKIT] 46 /* Trapkits */
+TV_TOTEM 54 /* Summoner totems */
+*****defines.txt*55[TV_STAFF] 55 /* Staffs */
+*****defines.txt*65[TV_WAND] 65 /* Wands */
+*****defines.txt*66[TV_ROD] 66 /* Rod tips */
+*****defines.txt*67[TV_ROD_MAIN] 67 /* Rod body's */
+*****defines.txt*70[TV_SCROLL] 70 /* Scrolls */
+*****defines.txt*71[TV_POTION] 71 /* potions */
+*****defines.txt*72[TV_POTION2] 72 /* Second set of potion */
+TV_FLASK 77 /* Flasks of oil */
+*****defines.txt*80[TV_FOOD] 80 /* Food, including mushrooms */
+TV_HYPNOS 99 /* To wield monsters !:) */
+TV_GOLD 100 /* Gold can only be picked up by players */
+TV_RANDART 102 /* Random Artifacts */
+TV_RUNE1 104 /* Base runes */
+TV_RUNE2 105 /* Modifier runes */
+TV_BOOK 111 /* spell books */
+*****defines.txt*115[TV_DAEMON_BOOK] 115 /* Demon blades, shields and horns */
+~~~~~84|Defines|Svals
+~~~~~12|Svals
+/* The "sval" codes for TV_TOOL */
+ SV_TOOL_CLIMB 0
+ SV_PORTABLE_HOLE 1
+~~~~~16
+/* The "sval" codes for TV_SHOT/TV_ARROW/TV_BOLT */
+ SV_AMMO_LIGHT 0 /* pebbles */
+ SV_AMMO_NORMAL 1 /* shots, arrows, bolts */
+ SV_AMMO_HEAVY 2 /* seeker arrows and bolts, mithril shots */
+~~~~~14
+/* The "sval" codes for TV_INSTRUMENT */
+ SV_FLUTE 1
+ SV_BANJO 2
+ SV_LUTE 3
+ SV_MANDOLIN 4
+ SV_DRUM 5
+ SV_HARP 6
+ SV_HORN 7
+~~~~~46
+/* The "sval" codes for TV_TRAPKIT */
+ SV_TRAPKIT_SLING 1
+ SV_TRAPKIT_BOW 2
+ SV_TRAPKIT_XBOW 3
+ SV_TRAPKIT_POTION 4
+ SV_TRAPKIT_SCROLL 5
+ SV_TRAPKIT_DEVICE 6
+~~~~~15
+/* The "sval" codes for TV_BOOMERANG */
+ SV_BOOM_S_WOOD 1 /* 1d4 */
+ SV_BOOM_WOOD 2 /* 1d9 */
+ SV_BOOM_S_METAL 3 /* 1d8 */
+ SV_BOOM_METAL 4 /* 2d4 */
+~~~~~19
+/* The "sval" codes for TV_BOW (note information in "sval") */
+ SV_SLING 2 /* (x2) */
+ SV_SHORT_BOW 12 /* (x2) */
+ SV_LONG_BOW 13 /* (x3) */
+ SV_LIGHT_XBOW 23 /* (x3) */
+ SV_HEAVY_XBOW 24 /* (x4) */
+~~~~~20
+/* The "sval" codes for TV_DIGGING */
+ SV_SHOVEL 1
+ SV_GNOMISH_SHOVEL 2
+ SV_DWARVEN_SHOVEL 3
+ SV_PICK 4
+ SV_ORCISH_PICK 5
+ SV_DWARVEN_PICK 6
+ SV_MATTOCK 7
+~~~~~21
+/* The "sval" values for TV_HAFTED */
+ SV_CLUB 1 /* 1d4 */
+ SV_WHIP 2 /* 1d6 */
+ SV_QUARTERSTAFF 3 /* 1d9 */
+ SV_NUNCHAKU 4 /* 2d3 */
+ SV_MACE 5 /* 2d4 */
+ SV_BALL_AND_CHAIN 6 /* 2d4 */
+ SV_WAR_HAMMER 8 /* 3d3 */
+ SV_LUCERN_HAMMER 10 /* 2d5 */
+ SV_THREE_PIECE_ROD 11 /* 3d3 */
+ SV_MORNING_STAR 12 /* 2d6 */
+ SV_FLAIL 13 /* 2d6 */
+ SV_LEAD_FILLED_MACE 15 /* 3d4 */
+ SV_TWO_HANDED_FLAIL 18 /* 3d6 */
+ SV_GREAT_HAMMER 19 /* 4d6 */
+ SV_MACE_OF_DISRUPTION 20 /* 5d8 */
+ SV_GROND 50 /* 3d4 */
+~~~~~24
+/* The "sval" values for TV_AXE */
+ SV_HATCHET 1 /* 1d5 */
+ SV_CLEAVER 2 /* 2d4 */
+ SV_LIGHT_WAR_AXE 8 /* 2d5 */
+ SV_BEAKED_AXE 10 /* 2d6 */
+ SV_BROAD_AXE 11 /* 2d6 */
+ SV_BATTLE_AXE 22 /* 2d8 */
+ SV_GREAT_AXE 25 /* 4d4 */
+ SV_LOCHABER_AXE 28 /* 3d8 */
+ SV_SLAUGHTER_AXE 30 /* 5d7 */
+~~~~~22
+/* The "sval" values for TV_POLEARM */
+ SV_SPEAR 2 /* 1d6 */
+ SV_SICKLE 3 /* 2d3 */
+ SV_AWL_PIKE 4 /* 1d8 */
+ SV_TRIDENT 5 /* 1d9 */
+ SV_FAUCHARD 6 /* 1d10 */
+ SV_BROAD_SPEAR 7 /* 1d9 */
+ SV_PIKE 8 /* 2d5 */
+ SV_GLAIVE 13 /* 2d6 */
+ SV_HALBERD 15 /* 3d4 */
+ SV_GUISARME 16 /* 2d5 */
+ SV_SCYTHE 17 /* 5d3 */
+ SV_LANCE 20 /* 2d8 */
+ SV_TRIFURCATE_SPEAR 26 /* 2d9 */
+ SV_HEAVY_LANCE 29 /* 4d8 */
+ SV_SCYTHE_OF_SLICING 30 /* 8d4 */
+~~~~~23
+/* The "sval" codes for TV_SWORD */
+ SV_BROKEN_DAGGER 1 /* 1d1 */
+ SV_BROKEN_SWORD 2 /* 1d2 */
+ SV_DAGGER 4 /* 1d4 */
+ SV_MAIN_GAUCHE 5 /* 1d5 */
+ SV_RAPIER 7 /* 1d6 */
+ SV_SMALL_SWORD 8 /* 1d6 */
+ SV_BASILLARD 9 /* 1d8 */
+ SV_SHORT_SWORD 10 /* 1d7 */
+ SV_SABRE 11 /* 1d7 */
+ SV_CUTLASS 12 /* 1d7 */
+ SV_KHOPESH 14 /* 2d4 */
+ SV_TULWAR 15 /* 2d4 */
+ SV_BROAD_SWORD 16 /* 2d5 */
+ SV_LONG_SWORD 17 /* 2d5 */
+ SV_SCIMITAR 18 /* 2d5 */
+ SV_KATANA 20 /* 3d4 */
+ SV_BASTARD_SWORD 21 /* 3d4 */
+ SV_GREAT_SCIMITAR 22 /* 4d5 */
+ SV_CLAYMORE 23 /* 2d8 */
+ SV_ESPADON 24 /* 2d9 */
+ SV_TWO_HANDED_SWORD 25 /* 3d6 */
+ SV_FLAMBERGE 26 /* 3d7 */
+ SV_EXECUTIONERS_SWORD 28 /* 4d5 */
+ SV_ZWEIHANDER 29 /* 4d6 */
+ SV_BLADE_OF_CHAOS 30 /* 6d5 */
+ SV_SHADOW_BLADE 31 /* 4d4 */
+ SV_BLUESTEEL_BLADE 32 /* 3d9 */
+ SV_DARK_SWORD 33 /* 3d7 */
+~~~~~34
+/* The "sval" codes for TV_SHIELD */
+ SV_SMALL_LEATHER_SHIELD 2
+ SV_SMALL_METAL_SHIELD 3
+ SV_LARGE_LEATHER_SHIELD 4
+ SV_LARGE_METAL_SHIELD 5
+ SV_DRAGON_SHIELD 6
+ SV_SHIELD_OF_DEFLECTION 10
+~~~~~32
+/* The "sval" codes for TV_HELM */
+ SV_HARD_LEATHER_CAP 2
+ SV_METAL_CAP 3
+ SV_IRON_HELM 5
+ SV_STEEL_HELM 6
+ SV_DRAGON_HELM 7
+ SV_IRON_CROWN 10
+ SV_GOLDEN_CROWN 11
+ SV_JEWELED_CROWN 12
+ SV_MORGOTH 50
+~~~~~30
+/* The "sval" codes for TV_BOOTS */
+ SV_PAIR_OF_SOFT_LEATHER_BOOTS 2
+ SV_PAIR_OF_HARD_LEATHER_BOOTS 3
+ SV_PAIR_OF_METAL_SHOD_BOOTS 6
+~~~~~35
+/* The "sval" codes for TV_CLOAK */
+ SV_CLOAK 1
+ SV_ELVEN_CLOAK 2
+ SV_FUR_CLOAK 3
+ SV_SHADOW_CLOAK 6
+~~~~~31
+/* The "sval" codes for TV_GLOVES */
+ SV_SET_OF_LEATHER_GLOVES 1
+ SV_SET_OF_GAUNTLETS 2
+ SV_SET_OF_CESTI 5
+~~~~~36
+/* The "sval" codes for TV_SOFT_ARMOR */
+ SV_FILTHY_RAG 1
+ SV_ROBE 2
+ SV_PAPER_ARMOR 3 /* 4 */
+ SV_SOFT_LEATHER_ARMOR 4
+ SV_SOFT_STUDDED_LEATHER 5
+ SV_HARD_LEATHER_ARMOR 6
+ SV_HARD_STUDDED_LEATHER 7
+ SV_RHINO_HIDE_ARMOR 8
+ SV_CORD_ARMOR 9 /* 6 */
+ SV_PADDED_ARMOR 10 /* 4 */
+ SV_LEATHER_SCALE_MAIL 11
+ SV_LEATHER_JACK 12
+ SV_STONE_AND_HIDE_ARMOR 15 /* 15 */
+ SV_THUNDERLORD_SUIT 16
+~~~~~37
+/* The "sval" codes for TV_HARD_ARMOR */
+ SV_RUSTY_CHAIN_MAIL 1 /* 14- */
+ SV_RING_MAIL 2 /* 12 */
+ SV_METAL_SCALE_MAIL 3 /* 13 */
+ SV_CHAIN_MAIL 4 /* 14 */
+ SV_DOUBLE_RING_MAIL 5 /* 15 */
+ SV_AUGMENTED_CHAIN_MAIL 6 /* 16 */
+ SV_DOUBLE_CHAIN_MAIL 7 /* 16 */
+ SV_BAR_CHAIN_MAIL 8 /* 18 */
+ SV_METAL_BRIGANDINE_ARMOUR 9 /* 19 */
+ SV_SPLINT_MAIL 10 /* 19 */
+ SV_PARTIAL_PLATE_ARMOUR 12 /* 22 */
+ SV_METAL_LAMELLAR_ARMOUR 13 /* 23 */
+ SV_FULL_PLATE_ARMOUR 15 /* 25 */
+ SV_RIBBED_PLATE_ARMOUR 18 /* 28 */
+ SV_MITHRIL_CHAIN_MAIL 20 /* 28+ */
+ SV_MITHRIL_PLATE_MAIL 25 /* 35+ */
+ SV_ADAMANTITE_PLATE_MAIL 30 /* 40+ */
+~~~~~38
+/* The "sval" codes for TV_DRAG_ARMOR */
+ SV_DRAGON_BLACK 1
+ SV_DRAGON_BLUE 2
+ SV_DRAGON_WHITE 3
+ SV_DRAGON_RED 4
+ SV_DRAGON_GREEN 5
+ SV_DRAGON_MULTIHUED 6
+ SV_DRAGON_SHINING 10
+ SV_DRAGON_LAW 12
+ SV_DRAGON_BRONZE 14
+ SV_DRAGON_GOLD 16
+ SV_DRAGON_CHAOS 18
+ SV_DRAGON_BALANCE 20
+ SV_DRAGON_POWER 30
+~~~~~39
+/* The sval codes for TV_LITE */
+ SV_LITE_TORCH 0
+ SV_LITE_LANTERN 1
+ SV_LITE_TORCH_EVER 2
+ SV_LITE_DWARVEN 3
+ SV_LITE_FEANORIAN 4
+ SV_LITE_GALADRIEL 100
+ SV_LITE_ELENDIL 101
+ SV_LITE_THRAIN 102
+ SV_LITE_UNDEATH 103
+ SV_LITE_PALANTIR 104
+ SV_ANCHOR_SPACETIME 105
+ SV_STONE_LORE 106
+~~~~~40
+/* The "sval" codes for TV_AMULET */
+ SV_AMULET_DOOM 0
+ SV_AMULET_TELEPORT 1
+ SV_AMULET_ADORNMENT 2
+ SV_AMULET_SLOW_DIGEST 3
+ SV_AMULET_RESIST_ACID 4
+ SV_AMULET_SEARCHING 5
+ SV_AMULET_BRILLANCE 6
+ SV_AMULET_CHARISMA 7
+ SV_AMULET_THE_MAGI 8
+ SV_AMULET_REFLECTION 9
+ SV_AMULET_CARLAMMAS 10
+ SV_AMULET_INGWE 11
+ SV_AMULET_DWARVES 12
+ SV_AMULET_NO_MAGIC 13
+ SV_AMULET_NO_TELE 14
+ SV_AMULET_RESISTANCE 15
+ SV_AMULET_NOTHING 16
+ SV_AMULET_SERPENT 17
+ SV_AMULET_TORIS_MEJISTOS 18
+ SV_AMULET_ELESSAR 19
+ SV_AMULET_EVENSTAR 20
+ SV_AMULET_SUSTENANCE 21
+ SV_AMULET_TELEPATHY 22
+ SV_AMULET_TRICKERY 23
+ SV_AMULET_WEAPONMASTERY 24
+ SV_AMULET_DEVOTION 25
+ SV_AMULET_INFRA 26
+ SV_AMULET_SPELL 27
+ SV_AMULET_WISDOM 28
+ SV_AMULET_RESIST_ELEC 29
+ SV_AMULET_REGEN 30
+~~~~~45
+/* The sval codes for TV_RING */
+ SV_RING_WOE 0
+ SV_RING_AGGRAVATION 1
+ SV_RING_WEAKNESS 2
+ SV_RING_STUPIDITY 3
+ SV_RING_TELEPORTATION 4
+ SV_RING_SPECIAL 5
+ SV_RING_SLOW_DIGESTION 6
+ SV_RING_FEATHER_FALL 7
+ SV_RING_RESIST_FIRE 8
+ SV_RING_RESIST_COLD 9
+ SV_RING_SUSTAIN_STR 10
+ SV_RING_SUSTAIN_INT 11
+ SV_RING_SUSTAIN_WIS 12
+ SV_RING_SUSTAIN_CON 13
+ SV_RING_SUSTAIN_DEX 14
+ SV_RING_SUSTAIN_CHR 15
+ SV_RING_PROTECTION 16
+ SV_RING_ACID 17
+ SV_RING_FLAMES 18
+ SV_RING_ICE 19
+ SV_RING_RESIST_POIS 20
+ SV_RING_FREE_ACTION 21
+ SV_RING_SEE_INVIS 22
+ SV_RING_SEARCHING 23
+ SV_RING_STR 24
+ SV_RING_INT 25
+ SV_RING_DEX 26
+ SV_RING_CON 27
+ SV_RING_ACCURACY 28
+ SV_RING_DAMAGE 29
+ SV_RING_SLAYING 30
+ SV_RING_SPEED 31
+ SV_RING_BARAHIR 32
+ SV_RING_TULKAS 33
+ SV_RING_NARYA 34
+ SV_RING_NENYA 35
+ SV_RING_VILYA 36
+ SV_RING_POWER 37
+ SV_RING_RES_FEAR 38
+ SV_RING_RES_LD 39
+ SV_RING_RES_NETHER 40
+ SV_RING_RES_NEXUS 41
+ SV_RING_RES_SOUND 42
+ SV_RING_RES_CONFUSION 43
+ SV_RING_RES_SHARDS 44
+ SV_RING_RES_DISENCHANT 45
+ SV_RING_RES_CHAOS 46
+ SV_RING_RES_BLINDNESS 47
+ SV_RING_LORDLY 48
+ SV_RING_ATTACKS 49
+ SV_RING_NOTHING 50
+ SV_RING_PRECONITION 51
+ SV_RING_FLAR 52
+ SV_RING_INVIS 53
+ SV_RING_FLYING 54
+ SV_RING_WRAITH 55
+ SV_RING_ELEC 56
+ SV_RING_DURIN 57
+ SV_RING_SPELL 58
+ SV_RING_CRIT 59
+~~~~~55
+/* The "sval" codes for TV_STAFF */
+ SV_STAFF_SCHOOL 1
+ SV_STAFF_NOTHING 2
+~~~~~65
+/* The "sval" codes for TV_WAND */
+ SV_WAND_SCHOOL 1
+ SV_WAND_NOTHING 2
+~~~~~66
+/* The "sval" codes for TV_ROD(Rod Tips) */
+ SV_ROD_NOTHING 0
+ SV_ROD_DETECT_DOOR 1
+ SV_ROD_IDENTIFY 2
+ SV_ROD_RECALL 3
+ SV_ROD_ILLUMINATION 4
+ SV_ROD_MAPPING 5
+ SV_ROD_DETECTION 6
+ SV_ROD_PROBING 7
+ SV_ROD_CURING 8
+ SV_ROD_HEALING 9
+ SV_ROD_RESTORATION 10
+ SV_ROD_SPEED 11
+ SV_ROD_TELEPORT_AWAY 13
+ SV_ROD_DISARMING 14
+ SV_ROD_LITE 15
+ SV_ROD_SLEEP_MONSTER 16
+ SV_ROD_SLOW_MONSTER 17
+ SV_ROD_DRAIN_LIFE 18
+ SV_ROD_POLYMORPH 19
+ SV_ROD_ACID_BOLT 20
+ SV_ROD_ELEC_BOLT 21
+ SV_ROD_FIRE_BOLT 22
+ SV_ROD_COLD_BOLT 23
+ SV_ROD_ACID_BALL 24
+ SV_ROD_ELEC_BALL 25
+ SV_ROD_FIRE_BALL 26
+ SV_ROD_COLD_BALL 27
+ SV_ROD_HAVOC 28
+ SV_ROD_DETECT_TRAP 29
+ SV_ROD_HOME 30
+~~~~~67
+/* The "sval" codes for TV_ROD_MAIN(Rods) */
+ SV_ROD_WOODEN 10
+ SV_ROD_COPPER 20
+ SV_ROD_IRON 50
+ SV_ROD_ALUMINIUM 75
+ SV_ROD_SILVER 100
+ SV_ROD_GOLDEN 125
+ SV_ROD_MITHRIL 160
+ SV_ROD_ADMANTITE 200
+~~~~~70
+/* The "sval" codes for TV_SCROLL */
+ SV_SCROLL_DARKNESS 0
+ SV_SCROLL_AGGRAVATE_MONSTER 1
+ SV_SCROLL_CURSE_ARMOR 2
+ SV_SCROLL_CURSE_WEAPON 3
+ SV_SCROLL_SUMMON_MONSTER 4
+ SV_SCROLL_SUMMON_UNDEAD 5
+ SV_SCROLL_SUMMON_MINE 6
+ SV_SCROLL_TRAP_CREATION 7
+ SV_SCROLL_PHASE_DOOR 8
+ SV_SCROLL_TELEPORT 9
+ SV_SCROLL_TELEPORT_LEVEL 10
+ SV_SCROLL_WORD_OF_RECALL 11
+ SV_SCROLL_IDENTIFY 12
+ SV_SCROLL_STAR_IDENTIFY 13
+ SV_SCROLL_REMOVE_CURSE 14
+ SV_SCROLL_STAR_REMOVE_CURSE 15
+ SV_SCROLL_ENCHANT_ARMOR 16
+ SV_SCROLL_ENCHANT_WEAPON_TO_HIT 17
+ SV_SCROLL_ENCHANT_WEAPON_TO_DAM 18
+ SV_SCROLL_ENCHANT_WEAPON_PVAL 19
+ SV_SCROLL_STAR_ENCHANT_ARMOR 20
+ SV_SCROLL_STAR_ENCHANT_WEAPON 21
+ SV_SCROLL_RECHARGING 22
+ SV_SCROLL_RESET_RECALL 23
+ SV_SCROLL_LIGHT 24
+ SV_SCROLL_MAPPING 25
+ SV_SCROLL_DETECT_GOLD 26
+ SV_SCROLL_DETECT_ITEM 27
+ SV_SCROLL_DETECT_TRAP 28
+ SV_SCROLL_DETECT_DOOR 29
+ SV_SCROLL_DETECT_INVIS 30
+ SV_SCROLL_DIVINATION 31
+ SV_SCROLL_SATISFY_HUNGER 32
+ SV_SCROLL_BLESSING 33
+ SV_SCROLL_HOLY_CHANT 34
+ SV_SCROLL_HOLY_PRAYER 35
+ SV_SCROLL_MONSTER_CONFUSION 36
+ SV_SCROLL_PROTECTION_FROM_EVIL 37
+ SV_SCROLL_RUNE_OF_PROTECTION 38
+ SV_SCROLL_TRAP_DOOR_DESTRUCTION 39
+ SV_SCROLL_DEINCARNATION 40
+ SV_SCROLL_STAR_DESTRUCTION 41
+ SV_SCROLL_DISPEL_UNDEAD 42
+ SV_SCROLL_MASS_RESURECTION 43
+ SV_SCROLL_GENOCIDE 44
+ SV_SCROLL_MASS_GENOCIDE 45
+ SV_SCROLL_ACQUIREMENT 46
+ SV_SCROLL_STAR_ACQUIREMENT 47
+ SV_SCROLL_FIRE 48
+ SV_SCROLL_ICE 49
+ SV_SCROLL_CHAOS 50
+ SV_SCROLL_RUMOR 51
+ SV_SCROLL_ARTIFACT 52
+ SV_SCROLL_NOTHING 53
+ SV_SCROLL_SPELL 54
+~~~~~71
+/* The "sval" codes for TV_POTION */
+ SV_POTION_WATER 0
+ SV_POTION_APPLE_JUICE 1
+ SV_POTION_SLIME_MOLD 2
+ SV_POTION_BLOOD 3
+ SV_POTION_SLOWNESS 4
+ SV_POTION_SALT_WATER 5
+ SV_POTION_POISON 6
+ SV_POTION_BLINDNESS 7
+ SV_POTION_INVIS 8
+ SV_POTION_CONFUSION 9
+ SV_POTION_MUTATION 10
+ SV_POTION_SLEEP 11
+ SV_POTION_LEARNING 12
+ SV_POTION_LOSE_MEMORIES 13
+ SV_POTION_RUINATION 15
+ SV_POTION_DEC_STR 16
+ SV_POTION_DEC_INT 17
+ SV_POTION_DEC_WIS 18
+ SV_POTION_DEC_DEX 19
+ SV_POTION_DEC_CON 20
+ SV_POTION_DEC_CHR 21
+ SV_POTION_DETONATIONS 22
+ SV_POTION_DEATH 23
+ SV_POTION_INFRAVISION 24
+ SV_POTION_DETECT_INVIS 25
+ SV_POTION_SLOW_POISON 26
+ SV_POTION_CURE_POISON 27
+ SV_POTION_BOLDNESS 28
+ SV_POTION_SPEED 29
+ SV_POTION_RESIST_HEAT 30
+ SV_POTION_RESIST_COLD 31
+ SV_POTION_HEROISM 32
+ SV_POTION_BESERK_STRENGTH 33
+ SV_POTION_CURE_LIGHT 34
+ SV_POTION_CURE_SERIOUS 35
+ SV_POTION_CURE_CRITICAL 36
+ SV_POTION_HEALING 37
+ SV_POTION_STAR_HEALING 38
+ SV_POTION_LIFE 39
+ SV_POTION_RESTORE_MANA 40
+ SV_POTION_RESTORE_EXP 41
+ SV_POTION_RES_STR 42
+ SV_POTION_RES_INT 43
+ SV_POTION_RES_WIS 44
+ SV_POTION_RES_DEX 45
+ SV_POTION_RES_CON 46
+ SV_POTION_RES_CHR 47
+ SV_POTION_INC_STR 48
+ SV_POTION_INC_INT 49
+ SV_POTION_INC_WIS 50
+ SV_POTION_INC_DEX 51
+ SV_POTION_INC_CON 52
+ SV_POTION_INC_CHR 53
+ SV_POTION_AUGMENTATION 55
+ SV_POTION_ENLIGHTENMENT 56
+ SV_POTION_STAR_ENLIGHTENMENT 57
+ SV_POTION_SELF_KNOWLEDGE 58
+ SV_POTION_EXPERIENCE 59
+ SV_POTION_RESISTANCE 60
+ SV_POTION_CURING 61
+ SV_POTION_INVULNERABILITY 62
+ SV_POTION_NEW_LIFE 63
+~~~~~72
+/* The "sval" codes for TV_POTION2 */
+ SV_POTION2_MIMIC_ABOMINATION 1
+ SV_POTION2_MIMIC_WOLF 2
+ SV_POTION2_MIMIC_APE 3
+ SV_POTION2_MIMIC_GOAT 4
+ SV_POTION2_MIMIC_INSECT 5
+ SV_POTION2_MIMIC_SPARROW 6
+ SV_POTION2_MIMIC_STATUE 7
+ SV_POTION2_MIMIC_VAMPIRE 8
+ SV_POTION2_MIMIC_SPIDER 9
+ SV_POTION2_MIMIC_MANA_BALL 10
+ SV_POTION2_MIMIC_FIRE_CLOUD 11
+ SV_POTION2_MIMIC_COLD_CLOUD 12
+ SV_POTION2_MIMIC_CHAOS_CLOUD 13
+ SV_POTION2_CURE_LIGHT_SANITY 14
+ SV_POTION2_CURE_SERIOUS_SANITY 15
+ SV_POTION2_CURE_CRITICAL_SANITY 16
+ SV_POTION2_CURE_SANITY 17
+ SV_POTION2_CURE_WATER 18
+~~~~~80
+/* The "sval" codes for TV_FOOD */
+ SV_FOOD_POISON 0
+ SV_FOOD_BLINDNESS 1
+ SV_FOOD_PARANOIA 2
+ SV_FOOD_CONFUSION 3
+ SV_FOOD_HALLUCINATION 4
+ SV_FOOD_PARALYSIS 5
+ SV_FOOD_WEAKNESS 6
+ SV_FOOD_SICKNESS 7
+ SV_FOOD_STUPIDITY 8
+ SV_FOOD_NAIVETY 9
+ SV_FOOD_UNHEALTH 10
+ SV_FOOD_DISEASE 11
+ SV_FOOD_CURE_POISON 12
+ SV_FOOD_CURE_BLINDNESS 13
+ SV_FOOD_CURE_PARANOIA 14
+ SV_FOOD_CURE_CONFUSION 15
+ SV_FOOD_CURE_SERIOUS 16
+ SV_FOOD_RESTORE_STR 17
+ SV_FOOD_RESTORE_CON 18
+ SV_FOOD_RESTORING 19
+ SV_FOOD_BISCUIT 32
+ SV_FOOD_JERKY 33
+ SV_FOOD_RATION 35
+ SV_FOOD_SLIME_MOLD 36
+ SV_FOOD_WAYBREAD 37
+ SV_FOOD_PINT_OF_ALE 38
+ SV_FOOD_PINT_OF_WINE 39
+ SV_FOOD_ATHELAS 40
+ SV_FOOD_GREAT_HEALTH 41
+ SV_FOOD_FORTUNE_COOKIE 42
+~~~~~04
+/* The "sval" codes for TV_BATERIE */
+ SV_BATERIE_POISON 1
+ SV_BATERIE_EXPLOSION 2
+ SV_BATERIE_TELEPORT 3
+ SV_BATERIE_COLD 4
+ SV_BATERIE_FIRE 5
+ SV_BATERIE_ACID 6
+ SV_BATERIE_LIFE 7
+ SV_BATERIE_CONFUSION 8
+ SV_BATERIE_LITE 9
+ SV_BATERIE_CHAOS 10
+ SV_BATERIE_TIME 11
+ SV_BATERIE_MAGIC 12
+ SV_BATERIE_XTRA_LIFE 13
+ SV_BATERIE_DARKNESS 14
+ SV_BATERIE_KNOWLEDGE 15
+ SV_BATERIE_FORCE 16
+ SV_BATERIE_LIGHTNING 17
+ SV_BATERIE_MANA 18
+ MAX_BATERIE_SVAL 18
+~~~~~09
+/* The "sval" codes for TV_CORPSE */
+ SV_CORPSE_CORPSE 1
+ SV_CORPSE_SKELETON 2
+ SV_CORPSE_HEAD 3
+ SV_CORPSE_SKULL 4
+ SV_CORPSE_MEAT 5
+~~~~~115
+/* The "sval" codes for TV_DAEMON_BOOK */
+ SV_DEMONBLADE 55
+ SV_DEMONSHIELD 56
+ SV_DEMONHORN 57
diff --git a/lib/mods/theme/help/dungeon.txt b/lib/mods/theme/help/dungeon.txt
new file mode 100644
index 00000000..21c9651e
--- /dev/null
+++ b/lib/mods/theme/help/dungeon.txt
@@ -0,0 +1,703 @@
+|||||oy
+~~~~~02|Dungeons
+#####R /----------------------------------------\
+#####R < The Dungeons and Places of Middle-earth >
+#####R \----------------------------------------/
+
+ *****dungeon.txt*04[Symbols On Your Map] *****dungeon.txt*07[The Town and Buildings]
+ *****dungeon.txt*01[The Wilderness] *****dungeon.txt*06[In the Dungeon]
+ *****dungeon.txt*08[Objects] *****dungeon.txt*13[Mining]
+ *****dungeon.txt*12[Doors, Rooms, Staircases etc.] *****dungeon.txt*18[Pets]
+ *****dungeon.txt*14[Winning] *****dungeon.txt*15[Dying]
+ *****dungeon.txt*16[Where to get more help]
+
+After you have *****birth.txt*0[created your character], you will begin your ToME
+adventure. Symbols appearing on your screen will represent the world's
+walls, floor, objects, features, and creatures lurking about. In order
+to direct your character through his adventure, you will enter single
+character commands (see "*****command.txt*0[command.txt]").
+
+~~~~~03|Symbols
+~~~~~04|Identifying features
+#####R=== Symbols On Your Map ===
+
+Symbols on your map can be broken down into three categories: Features of
+the world such as walls, floor, doors, and traps; Objects which can be
+picked up such as treasure, weapons, magical devices, etc; and creatures
+which may or may not move about the dungeon, but are mostly harmful to your
+character's well being.
+
+Some symbols are used to represent more than one type of entity, and some
+symbols are used to represent entities in more than one category. The "@"
+symbol (by default) is used to represent the character.
+
+It will not be necessary to remember all of the symbols and their meanings.
+The "slash" command ("/") will identify any character appearing on your map
+(see "*****command.txt*0[command.txt]").
+
+Note that you can use a *****command.txt*105["user pref file"] to change any of these symbols to
+something you are more comfortable with.
+
+
+#####G Features that do not block line of sight
+
+ . A floor space 1 Entrance to General Store
+ . A trap (hidden) 2 Entrance to Armoury
+ ^ A trap (known) 3 Entrance to Weapon Smith
+ [[[[[y;] A glyph of warding 4 Entrance to Temple
+ [[[[[U'] An open door 5 Entrance to Alchemy Shop
+ [[[[[U'] A broken door 6 Entrance to Magic Shop
+ < A staircase up 7 Entrance to the Black Market
+ [[[[[y<] A quest exit 8 Entrance to your Home
+ [[[[[r<] A quest up level 9 Entrance to Bookstore
+ [[[[[U<] A shaft up [[[[[r>] A quest down level
+ > A staircase down [[[[[U>] A shaft down
+ [[[[[y>] A quest entrance [[[[[v>] Dungeon entrance
+ _ A fountain [[[[[D_] An empty fountain
+ * Straight road start/exit [[[[[B*] Section of the Straight Road
+ [[[[[b*] Section of the Straight Road [[[[[W*] Section of the Straight Road
+ [[[[[D*] Corrupted straight road [[[[[R*] An explosive rune
+ [[[[[B~] Stream of water (shallow) [[[[[b~] Stream of water (deep)
+ [[[[[u~] Tainted stream (water) [[[[[s#] Underground tunnel
+ [[[[[U#] Pool of lava (shallow) [[[[[r#] Pool of lava (deep)
+ [[[[[D#] Dark pit [[[[[u.] Dirt
+ [[[[[g.] Patch of Grass [[[[[W.] Ice
+ [[[[[y.] Sand [[[[[D.] Ash
+ [[[[[u.] Mud [[[[[v.] Nether mist
+ [[[[[r.] Floor [[[[[D0] Altar of Darkness
+ [[[[[R0] Altar of Force [[[[[B0] Altar of Winds
+ [[[[[W0] Altar of Being [[[[[v+] Void Jumpgate
+ [[[[[v;] Monster trap [[[[[B.] Glass wall
+ [[[[[w#] Illusion wall [[[[[g;] Grass with flowers
+ [[[[[w.] Cobblestone road [[[[[g#] Small tree
+ [[[[[w*] Town (in wilderness) [[[[[U^] Underground tunnel
+ [[[[[y+] A web
+
+#####G Features that block line of sight
+
+ [[[[[w#] A secret door # A wall
+ [[[[[U+] A closed door % A mineral vein
+ [[[[[U+] A locked door [[[[[o*] A mineral vein + treasure
+ [[[[[U+] A jammed door [[[[[w:] A pile of rubble
+ [[[[[D#] A dead tree [[[[[W#] Ice wall
+ [[[[[G#] A tree [[[[[y#] Sand wall
+ [[[[[U^] A mountain chain [[[[[W^] High mountain chain
+
+
+#####G Objects
+
+ ! A potion (or flask) / A pole-arm
+ ? A scroll, book, map, parchment / Music instrument
+ ? A rune, runestone | An edged weapon
+ , A mushroom (or food) \ A hafted weapon or digger
+ - A wand, rod or rod tip } A sling, bow, or x-bow
+ _ A staff { A shot, arrow, bolt, boomerang
+ = A ring ( Soft armour/cloak
+ " An amulet [ Hard armour
+ $ Gold or gems ] Misc. armour
+ ~ Lites, Tools, Chests, etc ) A shield
+ ~ Junk, Sticks, Skeletons, etc ` Trapping kit, climbing set
+ ~ Stone, random artifact o Egg
+ * An essence & (unused)
+
+~~~~~05|Monsters
+#####G Monsters
+
+ $ Creeping Coins , Mushroom Patch
+ a Giant Ant A Maia/Vala
+ b Giant Bat B Bird
+ c Cattle C Canine
+ d Dragon D Ancient Dragon
+ e Floating Eye E Elemental
+ f Feline F Dragon Fly
+ g Golem G Ghost
+ h Humanoids H Hybrid
+ i Mewlip I Insect
+ j Jelly J Snake
+ k Dwarf K Killer Beetle
+ l Giant Louse L Lich
+ m Mold M Multi-Headed Hydra
+ n Naga N (unused)
+ o Orc O Ogre
+ p Human P Giant Human(oid)
+ q Quadruped Q Quylthulg
+ r Rodent R Reptile/Amphibian
+ s Skeleton S Spider/Scorpion/Tick
+ t Townsperson T Troll
+ u Minor demon U Major demon
+ v Vortex V Vampire
+ w Worm or Worm Mass W Wight/Wraith
+ x (unused) X Xorn/Xaren
+ y Yeek Y Strange Humanoid
+ z Zombie/Mummy Z Zephyr Hound
+
+
+~~~~~07|Town
+#####R=== The Town Level ===
+
+The town level is where you will begin your adventure. The town consists of
+several buildings (most with an entrance), some townspeople, and a main wall
+which surrounds the town (with gates in it). Outside the gates may be found
+unclaimed lands and wilderness, where beasts still run wild. The first time
+you are in town it will be daytime (unless you are an undead character), but
+note that the sun will rise and set (rather instantly) as time passes.
+
+There are a few different towns around the world map, and your starting town
+will eventually become too small for you (if you survive the dangers of the
+dungeon). Other towns will have some different facilities, and you can find
+your way to other towns by reading the "Adventurer's Guide to Middle-earth"
+parchment with which *every* character begins the game.
+
+
+#####R=== Townspeople ===
+
+The town contains many different kinds of people. There are the street
+urchins, young children who will mob an adventurer for money, and seem to
+come out of the woodwork when excited. Blubbering idiots are a constant
+annoyance, but not harmful. Public drunks wander about the town singing,
+and are of no threat to anyone. Sneaky rogues who work for the black
+market are always greedily eyeing your backpack for potential new
+'purchases'... And finally, what town would be complete without a
+swarm of half drunk warriors, who take offense or become annoyed just for
+the fun of it.
+
+Most of the townspeople should be avoided by the largest possible distance
+when you wander from store to store. Fights will break out, though, so be
+prepared. Since your character grew up in this world of intrigue, no
+experience is awarded for killing the town inhabitants, though you may
+acquire treasure.
+
+~~~~~21|Buildings
+#####R=== Town Buildings ===
+
+Your character will begin his adventure with some basic supplies, and some
+extra gold with which to purchase more supplies at the town stores.
+
+You may enter any open store and barter with the owner for items you can
+afford. When bartering, you enter prices you will pay (or accept) for some
+object. You can either enter the absolute amount, or precede a number with
+a plus or minus sign to give a positive or negative increment on your
+previous offer. But be warned that the owners can easily be insulted, and
+may even throw you out for a while if you insult them too often. [[[[[BTo enter]
+[[[[[Ba store, simply move onto the entrance, which is represented by a number]
+[[[[[Bfrom 1 to 9.]
+
+If you consistently bargain well in a store, that is, you reach the final
+offer much more often than not, then the store owner will eventually
+recognise that you are a superb haggler, and will go directly to the final
+offer instead of haggling with you. Items which cost less than 10 gold
+pieces do not count, as haggling well with these items is usually either
+very easy or almost impossible. The more expensive the item is, the less
+likely the store owner is to assume that you are a good haggler. Note that
+you may disable haggling with a software option, though this will inflict a
+10% "sales tax" on all purchases for which the store owner would have
+required you to haggle.
+
+Once inside a store, you will see the name and race of the store owner, the
+name of the store, the maximum amount of cash that the store owner will pay
+for any one item, and the store inventory, listed along with tentative
+prices, which will become "fixed" (at the "final offer") should you ever
+manage to haggle a store owner down to his final offer.
+
+You will also see an (incomplete) list of available commands. Note that
+many of the commands which work in the dungeon work in the stores as well,
+but some do not, especially those which involve "using" objects.
+
+Stores do not always have everything in stock. As the game progresses, they
+may get new items, so check back from time to time. Also, if you sell them
+an item, it may get sold to a customer while you are adventuring, so don't
+always expect to be able to get back everything you have sold. If you have
+a lot of spare gold, you can purchase every item in a store, which will
+induce the store owner to bring out new stock, and perhaps even retire. If
+you are low on funds (and morals), you may attempt to steal an item from
+the store, but beware -- if you are caught, the store owner will not let you
+back in for a very long time.
+
+Store owners will not buy harmful or useless items. If an object is
+unidentified, they will pay you some base price for it. Once they have
+bought it they will immediately identify the object. If it is a good object,
+they will add it to their inventory. If it was a bad bargain, they simply
+throw the item away. In any case, you may receive some knowledge of the
+item in case another is encountered.
+
+#####GThe General Store ("1")
+ The General Store sells foods, drinks, some clothing, torches, lamps,
+ oil, shovels, picks, and spikes. All of these items and some others
+ can be sold back to the General store for money.
+
+#####GThe Armoury ("2")
+ The Armoury is where the town's armour is fashioned. All sorts of
+ protective gear may be bought and sold here.
+
+#####GThe Weaponsmith's Shop ("3")
+ The Weaponsmith's Shop is where the town's weapons are fashioned. Hand
+ and missile weapons may be purchased and sold here, along with arrows,
+ bolts, and shots.
+
+#####GThe Temple ("4")
+ The Temple deals in healing and restoration potions, as well as bless
+ scrolls, word of recall scrolls, some approved priestly weapons, and
+ priest spell books.
+
+#####GThe Alchemy shop ("5")
+ The Alchemy Shop deals in all types of potions and scrolls.
+
+#####GThe Magic User's Shop ("6")
+ The Magic User's Shop deals in all sorts of rings, wands, amulets, and
+ staves, as well as spell books.
+
+#####GThe Black Market ("7")
+ The Black Market will sell and buy anything at extortionate prices.
+ However it occasionally has VERY good items in it. The shopkeepers are
+ not known for their tolerance...
+
+#####GYour Home ("8")
+ This is your house where you can store objects that you cannot carry
+ on your travels, or will need at a later date.
+
+#####GThe Bookstore ("9")
+ The Bookstore deals in all sorts of magical books. You can purchase
+ and sell spellbooks for spellcasters and priests here.
+
+
+#####ROther Buildings
+In addition to the basic stores, there are some special buildings that can be
+found in some towns. These Buildings (represented by +'s) include:
+
+#####GMayor's Office/Castle
+ The home office for the town. Adventurers looking for work besides
+ exploring the dungeon should hunt in here.
+
+#####GPet Shop
+ Great place to purchase eggs and get pets.
+
+#####GThe Soothsayer
+ To discover what *****/afatespoi.txt*0[fates ("a")] lie in store for you.
+
+#####GThe Prancing Pony
+ Wine, dine, rest and relax!
+
+#####GThe Nest
+ Thunderlords are masters of teleportation, and will consent to bear you
+ to your chosen dungeon destination for a fee.
+
+#####GBeastmaster Shanty
+ For those who enjoy trophy hunting, and to research that strange animal
+ you saw during your adventures.
+
+#####GFighters Hall
+ The place to reforge weapons and armour.
+
+#####GRangers Guild
+ The place to reforge distance weapons and their ammunition.
+
+#####GLibrary
+ For information of all kinds.
+
+#####GGambling House
+ Read the *****/bgambling.txt*0[rules ("b")] before paying. The games are
+ not rigged, just naturally difficult.
+
+#####GTower of Magery/Wizards Spire
+ The wizards will identify your items or recharge your magical items for
+ a fee.
+
+#####GInner temple/Priests Circle
+ A place of healing.
+
+#####GPaladin guild
+ Some healing and enchantments available.
+
+
+~~~~~1|Wilderness
+#####R=== The Wilderness and the Wilderness Map ===
+
+Between the towns, the hand of civilisation has not tamed the lands, and
+wild creatures run rampant. This is another place that is worth exploring.
+Hidden within the wilderness are several interesting locations, with the
+four main ones for any adventurer - Barrow Downs, Mirkwood, Mordor and
+Angband each being located at or near one of the main towns of Middle-
+earth. These locations should be explored consecutively, as each one
+increases in difficulty from the point where the previous dungeon finished.
+A new character should not try to go at Mordor or Angband as their first
+dungeon (well, not if you wish to survive your first step, anyway)!
+
+As well as these (and other) locations, the wilderness can be a good place
+to go when you are seeking a change from the scenery of the dungeons, or just
+a bit of fast experience.
+
+Be warned - some creatures found in the wilderness can be quite dangerous,
+and travel through the wilderness can be time-consuming. If you are wishing
+to simply move to another town, there is an overview map (called the
+"Wilderness Map") that can be travelled through by going up "<" from the
+town level. While travelling through this map, your character is still having
+to actually walk through each square of the normal view, but you only see the
+end result of them moving from one 4x4 panel to the next. As such, food
+consumption will appear to be much higher in the Wilderness View than it is
+normally, and it is recommended that you travel prepared. It is also possible
+for the wild creatures within the wilderness to ambush you when travelling,
+which will force you out of the Wilderness Map so that you can safely get
+yourself out of trouble, before continuing on your way.
+
+All of the special locations can be seen as downstairs (">") on the
+Wilderness Map and towns as "*"s. This makes it *much* easier to find your
+way from one interesting place to another.
+
+The "Adventurer's Guide to Middle-earth" (a parchment with which *every*
+character begins the game) contains details about the towns and some of
+the dungeons, including rough directions on how to get there.
+
+~~~~~06|Dungeons|In the dungeon
+#####R=== Within The Dungeon ===
+
+Once your character is adequately supplied with food, light, armor, and
+weapons, he is ready to enter Barrow Downs. Move on top of the ">" symbol
+and use the "Down" command (">").
+
+Your character will enter a maze of interconnecting staircases and finally
+arrive somewhere on the first level of the dungeon. Each level of the
+dungeon is fifty feet high (thus dungeon level "Lev 1" is often called
+"50 ft"), and is divided into rectangular regions several times
+larger than the screen. Once you leave a level by a
+staircase, you will never again find your way back to that region of that
+level, but there are an infinite number of other regions at that same "depth"
+that you can explore later. So be careful that you have found all the
+treasure before you leave a level, or you may never find it again! The
+monsters, of course, can use the stairs, and you may eventually encounter
+them again.
+
+In the dungeon, there are many things to find, but your character must
+survive many horrible and challenging encounters to find the treasure lying
+about and take it safely back to the town to sell.
+
+~~~~~23|Light
+There are two sources for light once inside the dungeon: permanent light
+which has been magically placed within rooms, and a light source carried by
+the player (or some of the monsters). If neither is present, the character
+will be unable to see. This will affect searching, picking locks, disarming
+traps, reading scrolls, casting spells, browsing books, etc. So be very
+careful not to run out of light!
+
+A character must wield a torch or lamp in order to supply his own light. A
+torch or lamp burns fuel as it is used, and once it is out of fuel, it stops
+supplying light. You will be warned as the light approaches this point. You
+may use the "Fuel" command ("F") to refuel your lantern (with flasks of oil)
+or your torch (with other torches), so it is a good idea to carry extra
+torches or flasks of oil, as appropriate. There are rumours of objects of
+exceptional power which glow with their own never-ending light.
+
+~~~~~08|Objects
+#####R=== Objects Found In The Dungeon ===
+
+The mines are full of objects just waiting to be picked up and used. How
+did they get there? Well, the main source for useful items are all the
+foolish adventurers (like you?) that proceeded into the dungeon before you.
+They get killed, and the helpful creatures scatter the various treasures
+throughout the dungeon. Most cursed items are placed there by the joyful evil
+sorcerers, who enjoy a good joke when it gets you killed.
+
+You pick up objects by moving on top of them. You can carry up to 23
+different items in your backpack while wearing and wielding up to 12 others.
+Although you are limited to 23 different items, each item may actually be a
+"pile" of up to 99 similar items. If you somehow manage to stuff 24 items
+into your pack, for example, by removing an item from your head while your
+pack is full, then your pack will "overflow" and the most recently added
+item will fall out and onto the ground. You will be warned about any command
+that seems likely to induce this behaviour.
+
+You are, in addition, limited in the total amount of weight that you can
+carry. As you approach this value, you become slower, making it easier for
+monsters to chase you. Note that there is no upper bound on how much you can
+carry, if you do not mind being slow. Your weight limit is determined by your
+strength.
+
+Objects do not block the line of sight, but may stack on top of one another,
+with the one on top hiding others beneath it.
+
+ Q: I'm standing on a pile of items. How do I see what's in the pile
+ without picking it all up, moving it, or destroying it all?
+ A: 1. Stand on the pile in question
+ 2. Type shift + i (examine)
+ 3. Type - (examine items on floor)
+ 4. Type * (expand list of items on floor)
+ 5. (as needed) Type letter associated with item to look at it more
+ closely.
+
+Objects may also obscure stairs, Ways and void jumpgates.
+
+ Q: I'm standing on a pile of items. Is there a command to see if
+ there is a stair beneath the pile?
+ A: Stairs, void jumpgates and Ways that obscured by clutter still
+ function.
+ You are advised to take a good hard look at your surroundings before
+ creating lots of dungeon clutter. You can see if there is a stair
+ beneath the pile with either of these methods:
+ 1. Pick up, move, or eliminate the pile.
+ 2. Press l (look), then select the square you wish to inquire about.
+ Press <enter>; it will scroll through everything on the ground,
+ and eventually it ends with "It is in a Void Jumpgate", or
+ whatever.
+
+
+Many objects found within the dungeon have special commands for their use.
+Wands must be Aimed, staves must be Used, scrolls must be Read, and potions
+must be Quaffed. You may, in general, not only use items in your pack, but
+also items on the ground, if you are standing on top of them. For a detailed
+list of the commands to use objects, see *****command.txt*0[command.txt].
+
+Chests are complex objects, containing traps, locks, and possibly treasure
+or other objects inside them once they are opened. Many of the commands that
+apply to traps or doors also apply to chests and, like traps and doors, these
+commands do not work if you are carrying the chest.
+
+One item in particular will be discussed here. [[[[[BThe scroll of "Word of]
+[[[[[BRecall"] can be found within the dungeon, or bought at the temple in
+town. It acts in two manners, depending upon your current location. If read
+within the dungeon, it will teleport you back to town. If read in town, it
+will teleport you back down to the deepest level of the dungeon to which your
+character has previously journeyed. This makes the scroll very useful for
+getting back to the deeper levels of the dungeon. Once the scroll has been
+read it takes a while for the spell to act, so don't expect it to save you
+in a crisis. Reading a second scroll before the first has had a chance to
+take effect will cancel both scrolls. Since an accidental dive to a new depth
+(via a trapdoor, for example), may result in the Word of Recall dungeon depth
+being 'broken', so to speak (meaning that the next Word of Recall in town
+will take you back deeper than you would like to), there is a feature in
+ToME which allows you to read a scroll of Word of Recall on a different
+level and 'reset' the recall depth to that level (instead of the deepest
+level). Some dungeons cannot be recalled into, though you can still recall
+out.
+
+You may "inscribe" any object with a textual inscription of your choice.
+These inscriptions are not limited in length, though you may not be able to
+see the whole inscription on the item. The game applies special meaning to
+inscriptions containing any text of the form "@#" or "@x#" or "!x" or "!*",
+see "*****command.txt*0[command.txt]" and "*****macrofaq.txt*0[macrofaq.txt]".
+
+The game provides some "fake" inscriptions to help you keep track of your
+possessions. Wands and staves which are known to be empty will be inscribed
+with "empty". Objects which have been tried at least once but haven't been
+identified yet will be inscribed with "tried". Cursed objects are inscribed
+with "cursed". Broken objects may be inscribed with "broken". Also, any
+item which was purchased at a discount, implying that it is slightly
+"sub-standard", will be inscribed with the appropriate "discount", such as
+"25% off". Note that these inscriptions are fake, and cannot be removed,
+though they can be covered up by a real inscription if you so desire. Try
+"_" as a nice short one.
+
+Also, occasionally you will notice that something in your inventory or
+equipment list seems to be magical. High level characters are much more
+likely to notice this than beginning characters. When you do notice this,
+the item in question will be inscribed with "good" or "cursed" as is
+relevant. You can increase your ability to notice magical effects of armour
+and weapons by increasing the *****skills.txt*01[Combat] skill. You can increase your ability
+to sense particularly well enchanted magical items (potions, scrolls. wands
+etc) by increasing your *****skills.txt*21[Magic] skill. If you increase these
+high enough, you will gain a special method of "sensing" your
+inventory/equipment items, which tells you not only whether an item is "good"
+or "cursed", but also if it is "average", "special", "excellent", "terrible" or
+"worthless".
+
+~~~~~21|Objects|Colour of inventory slot letter
+The colour of the letter that identifies each item in your backpack can tell
+you something about their magical status. Grey indicates the item has not been
+identified yet. After identification, the colour changes to one of the
+following: white, indicating it is normal; blue indicates it is an ego-item
+(pseudo-id's as {excellent}); yellow indicates it is an artifact {special};
+green shows it is an artifact which is part of a set.
+
+It is rumoured that rings of power and extra rare spell books may be found
+deeper in the dungeon....
+
+And lastly, a final warning: not all objects are what they seem. The line
+between tasty food and annoying mushroom is a fine one, and sometimes a
+potion will reach out and bite you...
+~~~~~09|Objects|Cursed Objects
+~~~~~10|Cursed Objects
+#####R=== Cursed Objects ===
+
+Some objects, mainly armour and weapons, have had curses laid upon them.
+These horrible objects will look like any other normal item, but will
+detract from your character's stats or abilities if worn. They will also
+be impossible to remove until the curse is removed. In fact some are
+so badly cursed that even this will not work, and more potent methods are
+needed.
+
+If you wear or wield a cursed item, you will immediately feel something
+wrong. The item will also be inscribed "cursed".
+
+Shopkeepers will refuse to buy any known cursed item.
+~~~~~13|Mining
+~~~~~11|Dungeons|Mining
+#####R=== Digging and Mining ===
+
+It is possible for you to be trapped within the dungeon. You will not be able
+to dig your way out without a digging tool (shovel, pick, or other means of
+digging). It is absolutely essential to always carry some kind of digging tool,
+even when you are not planning on tunnelling for treasure. Do not leave the
+town level of Bree without a digger!
+
+Picks and shovels have a digging ability expressed as "(+<num>)", e.g. (+2).
+The higher the number, the better the digging ability of the tool. Diggers are
+effective against rubble, trees, and many walls. Rubble and veins may hide
+treasure; trees do not.
+
+You dig in something with the tunnel (shift + t) command. Thorough digging
+removes one ASCII square (i.e. tile) of what is being dug. This may require
+multiple attempts depending on how good your digger is (and how high your
+strength is). Once the square is removed, you will be informed if you found
+anything there. If another diggable square exists beyond the area you just dug,
+you can begin the process again.
+
+Some dungeons contain rich strikes which may be found only by mining it out of
+the walls. Quartz veins are the richest, yielding the most metals and gems, but
+magma veins may also hide hoards within them. When digging rock, granite is
+much harder to dig through than quartz or magma veins, so it is much faster to
+follow a vein exactly and dig around the granite. There is also a game option
+for highlighting magma and quartz within the walls, which makes this easier.
+
+If the character has a scroll, staff, or spell of treasure location, she can
+immediately locate all strikes of treasure within a vein shown on the screen.
+This makes mining much easier and more profitable.
+~~~~~12|Dungeons|Doors, Passages, Rooms and Staircases
+#####R=== Staircases, Ways, Void jumpgates, Secret Doors, Passages, and Rooms ===
+
+Staircases are the manner in which you get deeper or climb out of the
+dungeon. The symbols for the up and down staircases are the same as the
+commands to use them. A "<" represents an up staircase and a ">" represents
+a down staircase. You must move your character over the staircase before
+you can use it. You use it by typing the same character as the staircase
+itself (either "<" or ">".)
+
+In flat environments such as forests, Ways replace staircases. On the map, Ways
+are identical to staircases and behave the same way.
+
+Yellow down stairs and Ways are quest entrances (although not every quest
+is reached by such means).
+
+Shafts are also represented by "<" or ">", but are brown. They work similarly
+to stairs and Ways, but if you use one, you might traverse more than one
+dungeon level all in one go as a result.
+
+Stairs, impenetrable walls, and shop entrances like titanium walls, and the
+doors into shops, cannot be destroyed by any means (although their location can
+occasionally change under the right circumstances).
+~~~~~23|Void jumpgates
+A void jumpgate appears on your map as a violet "+". Jumpgates always occur in
+pairs. To activate a jumpgate, stand on it and type ">". You will instantly
+appear on top of its paired jumpgate, which will be somewhere else on the same
+dungeon level.
+
+Many secret doors are used within the dungeon to confuse and demoralise
+adventurers foolish enough to enter. But with some luck, and lots of
+concentration, you can find these secret doors. Secret doors will sometimes
+hide rooms or corridors, or even entire sections of that level of the
+dungeon. Sometimes they simply hide small empty closets or even dead ends.
+Secret doors always look like granite walls, just like traps always look
+like normal floors.
+
+Creatures in the dungeon will generally know and use these secret doors, and
+can sometimes be counted on to leave them open behind them when they pass
+through.
+
+For historical reasons, secret doors are never locked.
+
+~~~~~18|Pets
+~~~~~19|Companions
+~~~~~20|Monsters|Pets
+#####R=== Pets and Companions ===
+You may, in the course of a game, acquire friendly monsters who will help you
+defeat enemies. There are several different types of these, you can determine
+which your monster is by 'l'ooking at it.
+[[[[[vneutral] This monster will not help you by attacking other monsters, but nor
+ will it attack you.
+[[[[[vco-aligned] This monster will attack other enemy monsters, but you will not
+ gain any experience for its kills.
+[[[[[vpet] This monster will kill things for you. The amount of experience you gain
+ from its kills is determined by the level of your *****skills.txt*42[Monster-lore] skill.
+ This monster will gain levels and experience of its own, but cannot travel
+ between dungeon levels.
+[[[[[vcompanion] This type of monster will not only take experience and level up like
+ pets, but will also follow you from one dungeon level to the next. If
+ you successfully complete an adventurer quest for a lost sword and let
+ him join you, he will become a companion. Once again the amount of
+ experience you gain from a companion's kill depends upon your
+ Monster-lore skill.
+
+Your Monster-lore skill also determines the maximum number of pets and
+companions you can have at any one time.
+
+Pets, companions and co-aligned creatures cannot deliver killing blows to
+uniques or quest monsters. You must do this yourself!
+
+You can give commands to pets and companions to make them more useful, using
+the "P" command. The list of available commands is as follows:
+[[[[[vdismiss companions] Dismisses your companions. They can be difficult to get rid
+ of any other way.
+[[[[[vdismiss pets] Dismisses pets. You will be given the opportunity to dismiss all
+ current pets, or if you answer no to that first question, to
+ dismiss specific pets.
+[[[[[vcall pets] Calls your pets (and companions) to you.
+[[[[[vfollow me] Asks your pets (and companions) to follow you. They do have a mind of
+ their own, and may not be able to travel as fast as you can.
+[[[[[vseek and destroy] Selecting this will cause your pets and companions to wander
+ further from you, looking for enemies to kill.
+[[[[[vallow/disallow open doors] Selecting this toggles whether your pets and
+ companions can open doors.
+[[[[[vallow/disallow pickup items] Selecting this toggles whether your pets and
+ companions can pick up items. Disallowing it will
+ cause the monster to drop any items he is carrying on
+ the floor.
+[[[[[vgive target to a friend] Selecting this will cause one of your pets or
+ companions to attack your current target.
+[[[[[vgive target to all friends] Causes all pets or companions to attack your
+ current target.
+[[[[[vfriend forget target] All your friends will follow their normal attack
+ patterns, neglecting any targets you have given them.
+
+~~~~~14|Objectives
+#####R=== Game Objectives ===
+
+In ToME you will be required to complete a certain number of quests. Your
+first quest is to discover the true nature of the evil lurking in the Tower of
+Dol Guldur near Mirkwood.
+
+Each quest may lead on to others, and most quests can be postponed until when
+you feel ready to tackle them. Simply explore other dungeons until you feel you
+have gained enough experience to tackle your next task. Other quests are
+optional and can be used for further experience.
+
+Once you have finished your final quest, when you are ready to retire, simply
+"commit suicide" ("^Q") to have your character entered into the high score list
+as a winner. Note that until you retire, you can still be killed, so you may
+want to retire before wandering into a hoard of nasties....
+
+You may also like to make a character sheet of your winning character (by
+going through the "C"haracter screen and choosing "f"ile), and post in the
+rec.games.roguelike.angband newsgroup with a text copy of the dump pasted
+into the post. Include details about anything major that happened to your
+character - did they find a ring of speed (+10) on dungeon level 2? Or had
+they reached dungeon level 60 before finding their first artifact? Did you
+have a really scary moment that stands out from the rest of the game? And how
+*did* you actually win the game, anyway?
+
+~~~~~15|Dying
+~~~~~17|Loading old characters
+#####R=== Upon Death and Dying ===
+
+If your character falls below 0 hit points, he has died and cannot be
+restored (for most classes, anyway). A tombstone showing information about
+your character will be displayed. You are also permitted to get a record of
+your character, and all your equipment (identified) either on the screen or
+in a file.
+
+Your character will leave behind a reduced save file, which contains only
+the monster memory and your option choices. It may be restored, in which
+case the new character is generated exactly as if the file was not there,
+but the new player will find his monster memory containing all the experience
+of past incarnations.
+
+In this way, death in ToME is permanent. You cannot simply 'reload at the last
+save' as in most other contemporary games. Death is permanent, just as it is
+in real life.
+
diff --git a/lib/mods/theme/help/dunspoil.txt b/lib/mods/theme/help/dunspoil.txt
new file mode 100644
index 00000000..2da6d6b7
--- /dev/null
+++ b/lib/mods/theme/help/dunspoil.txt
@@ -0,0 +1,173 @@
+|||||oy
+~~~~~01|Dungeons|Spoilers
+~~~~~02|Spoilers|Dungeons
+#####R=== ToME's DUNGEONS ===
+
+There are numerous dungeons within Middle-earth, but not all
+of them are required to be ventured into. The original Angband
+dungeon has been split into 4 parts, each found near or at a
+different town. Travel between towns is usually easiest by
+using the wilderness overview map ("<" from the town level),
+but remember to take lots of food with you!
+
+#####GThe Basic Dungeons
+#####G------------------
+
+#####G1. Barrow-Downs
+Found near the outskirts of Bree (the starting town), this
+dungeon is where you should begin your adventure. It
+contains the main Dungeon levels 1 (50') to 10 (500'),
+after which it becomes necessary for the character to seek
+out a new dungeon in order to be able to descend further in
+their quest to kill Morgoth.
+
+#####G2. Mirkwood
+The Mirkwood forest contains levels 11 (550') to 33 (1650'),
+and can be found to the north-east of Lothlorien.
+
+#####G3. Mordor
+The Land of Mordor is a hot, cavernous region, containing
+levels 34 (1700') to 66 (3300') of the dungeon. Located to
+the East of Minas Anor, it is a place filled with danger,
+and only a wary adventurer will make it through to the other
+end of this dungeon.
+
+#####G4. Angband
+Only the most successful of adventurers usually make it this
+far. The Dungeon Angband contains both Sauron and Morgoth,
+who will gladly wipe out any who dare to oppose them! This
+dungeon covers levels 67 (3350') to 127 (6350'), but Sauron
+waits for you at level 99, and Morgoth at level 100. This
+dungeon can be found near Gondolin.
+
+
+#####GAdditional ToME Dungeons
+#####G------------------------
+
+In addition to the basic 4 dungeons, there are numerous other
+dungeons scattered around the world for an adventurer to explore
+while preparing for the final fight. Many of the dungeons have a
+guardian at the bottom of them, and a few have unique levels
+somewhere within them (like an orc town) with guaranteed artifacts
+and nasties within them. Other than the unique levels, all of the
+dungeons can be exited and re-entered at your leisure.
+
+Be warned though that some dungeons are partly toxic to the
+adventurer, and will damage you BY THEMSELVES just by you walking
+within them!
+
+#####GOrc Cave
+A dark tunnel leading to an Orc Cave, guarded at its base by Azog,
+King of the Uruk-Hai. Also somewhere within this dungeon is the
+hidden special level called Deathwatch.
+Equivalent to dungeon levels 10 to 22.
+
+#####GThe Old Forest
+A Forest is a haven for many animals, both of the good variety, and
+the bad. This forest is no exception. In the past, unsuccessful
+attempts have been made to cultivate this land, and it is possible
+that some of the towns may remain. It is also rumoured that Old Man
+Willow has made his home here, and is the source of the Forest's
+resistance to cultivation.
+Equivalent to dungeon levels 13 to 25.
+
+#####GHelcaraxe
+The Grinding Ice of Helcaraxe is a bitterly cold series of caverns,
+and guarded by the White Balrog.
+Equivalent to dungeon levels 20 to 40.
+
+#####GThe Sandworm lair
+A deep sandhole where most worms originated, it is guarded at its
+base by the Sandworm Queen.
+Equivalent to dungeon levels 22 to 30.
+
+#####GThe Heart of the Earth
+A dark passage leading into the heart of the world, the Heart of
+the Earth is the source of all the earth's changes. Some claim it
+to be the home of Golgarach, the Living Rock, who assists in the
+creation of new, ever-changing landforms.
+Equivalent to dungeon levels 25 to 36.
+
+#####GMaze
+A strange Maze where it becomes very difficult to remember where you
+have been, it is guarded at the bottom by The Minotaur of the Labyrinth.
+Equivalent to dungeon levels 25 to 37.
+
+#####GCirith Ungol
+The dungeon Cirith Ungol is full of poisonous fumes rising from the
+ground, and the land here looks diseased. Shelob is said to lurk
+within these depths.
+Equivalent to dungeon levels 25 to 50.
+
+#####GThe Land Of Rhun
+The Land Of Rhun is located on a large plain, and has been taken over
+by Ulfang the Black, Morgoth's first Easterling follower.
+Equivalent to dungeon levels 26 to 40.
+
+#####GThe Mines of Moria
+A stone door leads down to the depths of the Moria. Once the home of
+the dwarves, the mines have been taken over by creeping evil things, and
+unlucky adventurers may well stumble upon their training grounds. In
+the depths lurks Durin's Bane, the Balrog of Moria, and return from
+these depths can be difficult....
+Equivalent to dungeon levels 30 to 50.
+
+#####GThe Small Water Cave
+A small water cave filled with salt water, which rusts and damages an
+adventurer's equipment. This cave is not very deep, and is guarded by
+The Watcher in the Water.
+Equivalent to dungeon levels 32 to 34.
+
+#####GSubmerged Ruins
+The lost land of Numenor lies submerged here. The salt water causes
+everything to rust. These ruins are guarded by Ar-Pharazon the
+Golden.
+Equivalent to dungeon levels 35 to 50.
+
+#####GIllusory Castle
+The Illusory Castle is a very strange and confusing place for an
+adventurer to visit, and is rumoured to contain many strange
+monsters. Deep within the castle can be found The Glass Golem.
+Equivalent to dungeon levels 35 to 52.
+
+#####GPaths of the Dead
+A dark underground graveyard, this place looks extremely dangerous.
+It is claimed that the dead have all arisen in these depths, and are
+lead by Feagwath, the Undead Sorcerer.
+Equivalent to dungeon levels 40 to 70.
+
+#####GThe Sacred Land Of Mountains
+The Sacred Land Of Mountains is located in a large mountain range,
+with the remains of many old towns. Considered a perfect place to hide
+for one who could fly, it is rumoured that Trone the rebel Thunderlord
+fled into the ruins here.
+Equivalent to dungeon levels 45 to 70.
+
+#####GThe Tower of Dol Guldur
+The tower of of Dol Guldur is the last known residence of one known only
+as "the Necromancer". It is rumoured to be filled with his conjurations,
+although none have made it out of the Tower alive to confirm or deny this
+rumour.
+Equivalent to dungeon levels 57 to 70.
+
+#####GErebor, the Lonely Mountain
+A big, dark and frightening tunnel leading to the depth of the Lonely
+Mountain, this large cave is the ancestral home of the Dragons.
+Glaurung, Father of the Dragons has long made his home here.
+Equivalent to dungeon levels 60 to 72.
+
+#####GMount Doom
+A steaming cave in the centre of Mount Doom, this place is *hot*.
+It is said that Sauron forged the One Ring here and that it's the only place
+where it could be destroyed.
+Equivalent to dungeon levels 85 to 99.
+
+#####GNether Realm
+The Nether Realm is accessible only through a magic portal. Also
+known as Hell, this land is lethal to any who are unprepared for the
+ravages of Nether, and is guarded by Tik'srvzllat.
+#####BEquivalent to dungeon levels 666 to 696!!!!!
+
+
+ Created by Dawnmist for PernAngband 5.x.x
+ Updated for ToME 2.1.x
diff --git a/lib/mods/theme/help/essences.txt b/lib/mods/theme/help/essences.txt
new file mode 100644
index 00000000..f329fa80
--- /dev/null
+++ b/lib/mods/theme/help/essences.txt
@@ -0,0 +1,219 @@
+|||||oy
+~~~~~01|Spoilers|Essences
+~~~~~02|Alchemist|Essence Spoiler
+#####REssence Spoiler for ToME 2.2.0
+#####R------------------------------
+
+Essences are the tools of the trade for Alchemists, and unfortunately are
+useless for any other class. Alchemists use essences to create magical
+items for them to use.
+
+They can be either found on the floor while exploring the dungeon, or
+extracted from other magical items the alchemist finds during his
+adventures.
+
+To create an artifact, the alchemist will first have to have learnt the
+Artifact Creation ability. This ability costs 70 skill points (yes, 70,
+it's a very powerful ability!). And you need an alchemy skill of at least
+40, plus INT and WIS at 35 (thats 18/170 in non-linear form).
+To create the artifact, the alchemist will have to sacrifice 10 hit points,
+and an amount of magic essence similar to his skill in alchemy. The
+alchemist then allows the artifact to gain experience, and when it has
+enough, uses that experience to add abilities to the artifact. The
+alchemist can allow the artifact to continue to gain experience, thus
+keeping open the option to add more abilities later. This requires a
+similar amount of magic essence, but does not require the sacrifice of
+more hit points.
+
+Note that the experience you gain is divided among the artifacts that you
+have as well as going to yourself, so you will gain levels more slowly when
+empowering artifacts. Also, the artifact only gets 60% of the experience.
+So killing a creature worth 20xp would gain 10 for you, and 6 for the
+artifact.
+
+You can also modify existing artifacts when you attain skill level 50. Also
+at skill level 50 you will gain the ability to make temporary artifacts,
+which don't require the complex empowerments that regular items require,
+but also vanish after awhile.
+
+You cannot give an artifact an ability unless you have *Identified* an
+artifact which has that ability.
+
+For every four levels gained in the alchemy skill, the alchemist learns
+about objects of level (skill level)/4, starting by learning about level 1
+objects at skill level 0. (actually 1, but who's counting?)
+
+At skill level 5 you gain the ability to make ego items - but watch it!
+Your base failure rate will be 90%, and won't be 0% until you reach skill
+level 50. Adding gold will increase the chances of success in direct
+proportion to the value of the item you are trying to create. Note that
+this results in automatic success when the item you are trying to create
+happens to pick up a curse in the process.
+
+At skill level 5 you also gain knowledge of some basic ego item recipes.
+These are: Acidic, Shocking, Fiery, Frozen, Venomous, and Chaotic weapons,
+Resist Fire armour, and light sources of Fearlessness.
+
+At skill level 10 you will gain knowledge of digging ego items, if you have
+selected the option "always generate very unusual rooms" (ironman_rooms).
+
+At skill level 15 you can create ego wands, staves, rings, etc.
+
+At skill level 25 you gain the ability to empower double ego items.
+
+At skill level 50 you gain the ability to create temporary artifacts, which
+don't require any exotic ingredients beyond a single corpse of any type.
+
+Between skill levels 25 and 50, you will steadily gain the ability to set
+more and more flags.
+
+To finalise an artifact, you "P"ower it, and select the powers you want.
+Powers are divided into the following six categories:
+*****essences.txt*03[Stats, Sustains, Luck, Speed, Vision, etc.]
+*****essences.txt*04[Misc. (Auras, Light, See Invisibility, etc.)]
+*****essences.txt*05[Weapon Brands]
+*****essences.txt*06[Resistances and Immunities]
+*****essences.txt*07[ESP and Curses]
+*****essences.txt*08[Artifact Activations]
+
+~~~~~03
+#####GStats, Sustains, Luck, Speed, Vision, etc.
+lvl xp Power
+40 5000 Add to Strength Ring of Strength
+43 5000 Add to Intelligence Ring of Intelligence
+46 5000 Add to Wisdom Amulet of Wisdom
+46 5000 Add to Dexterity Ring of Dexterity
+42 5000 Add to Constitution Ring of Constitution
+30 5000 Add to Charisma Amulet of Adornment
+32 1000 Sustain Strength Ring of Sustain Strength
+34 1000 Sustain Intelligence Ring of Sustain Intelligence
+28 1000 Sustain Wisdom Ring of Sustain Wisdom
+36 1000 Sustain Dexterity Ring of Sustain Dexterity
+36 1000 Sustain Constitution Ring of Sustain Constitution
+25 1000 Sustain Charisma Ring of Sustain Charisma
+40 50000 Speed Ring of Speed
+38 150000 Extra Attacks Ring of Extra Attacks
+32 5000 Stealthy Left Insole from a Used Soft Boot
+29 2000 Adds to Searching Filthy Rag
+ 6 1000 Helps Infravision Brass Lantern
+30 1000 Lucky Rabbit's Left Forefoot
+25 30000 Aids in digging Pick
+40 50000 Multiplies Life Troll's Heart
+
+~~~~~04
+#####GMisc. (Auras, Light, See Invisibility, etc.)
+lvl xp Power
+20 15000 Invisibility Potion of Invisibility
+20 4000 See Invisible Potion of Invisibility
+20 30000 Free Action Iron Spike
+38 90000 Reflection Large Metal Shield
+20 30000 Aura of Fire Lungs from an Ancient Red Dragon
+25 30000 Aura of Lightning Lungs from an Ancient Blue Dragon
+ 8 1000 Light Everburning Torch
+20 10000 Bright Light Dwarven Lantern
+40 100000 Sunlight Feanorian Lamp
+40 200000 Flight Suit of Dragon Armour (any colour)
+50 10000000 Automatically IDs Morgoth's Testicles
+29 2000 Anti-Teleportation Teleport Inhibiting Amulet
+34 2000 Anti-Magic Magic Inhibiting Amulet
+50 100000 Wraith Form Potion of Invulnerability
+15 1000 Levitation Potion of Berserk Strength
+20 10000 Slow Digestion Lembas Wafer
+32 20000 Regenerate Mushroom of Unhealth
+12 20000 Teleport Mushroom of Confusion
+
+~~~~~05
+#####GWeapon Brands
+lvl xp Power
+30 20000 Extra Critical Hits Whip
+30 30000 Wounds Monsters Blade of Chaos
+26 6000 Vampiric Rod Tip of Drain Life
+16 2000 Slay Animal Dead Animal's Body
+25 2000 Slay Evil Evil Dead Thing's Remains
+30 2000 Slay Undead Remains of Undead Monster
+40 1500 Slay Demon Demon's Corpse
+10 700 Slay Orc Dead Orc
+16 700 Slay Troll Dead Troll
+25 900 Slay Giant Dead Giant
+33 2000 Slay Dragon Dead Dragon (any size will do)
+41 5000 *Slay* Dragon Mature Multi-Hued Dragon's Remains
+41 90000 *Slay* Undead Dead Summoner of Greater Undead
+41 90000 *Slay* Demon Lesser Balrog's Corpse
+36 20000 Vorpal
+40 90000 Earthquakes
+ 3 2000 Poison Brand
+12 2000 Acid Brand
+10 2000 Lightning Brand
+ 6 2000 Fire Brand
+ 8 2000 Frost Brand
+30 3000 Extra Might (Bows Only)
+35 3000 Extra Shots (Bows Only)
+
+~~~~~06
+#####GResistances and Immunities
+lvl xp Power
+49 500000 Immune to Acid Ancient Black Dragon's Foreskin
+50 500000 Immune to Lightning Ancient Blue Dragon's Foreskin
+49 500000 Immune to Fire Ancient Red Dragon's Foreskin
+50 500000 Immune to Cold Ancient White Dragon's Foreskin
+30 30000 Hold Life Amulet of the Magi
+12 10000 Resist Acid Ring of Acid
+15 10000 Resist Lightning Ring of Lightning
+13 10000 Resist Fire Potion of Resist Heat
+14 10000 Resist Cold Potion of Resist Cold
+25 30000 Resist Poison Potion of Cure Poison
+26 10000 Resist Fear Ring of Fear Resistance
+31 60000 Resist Light Ring of Light and Darkness Resistance
+31 60000 Resist Darkness Ring of Light and Darkness Resistance
+30 30000 Resist Blindness Ring of Blindness Resistance
+30 30000 Resist Confusion Ring of Confusion Resistance
+30 60000 Resist Sound Ring of Sound Resistance
+30 60000 Resist Shards Ring of Shard Resistance
+30 60000 Resist Nether Ring of Nether Resistance
+30 60000 Resist Nexus Ring of Nexus Resistance
+30 60000 Resist Chaos Ring of Chaos Resistance
+30 60000 Resist Disenchantment Ring of Disenchantment Resistance
+
+~~~~~07
+#####GESP and Curses
+lvl xp Power
+50 -100000 Temporary Item Corpse, any corpse
+10 -2000 Self-Cursing Filthy Rag
+45 -10000 Causes the Black Breath Sprig of Athelas
+40 -5000 Ancient Curse Scroll of *Remove Curse*
+40 -5000 Drains your Experience
+30 -5000 Aggravates Monsters
+30 -500 Curse Scroll of Remove Curse
+50 -5000 Permanently Cursed
+35 -2000 Can't be Dropped
+45 -5000 Drains your Hit Points
+20 -50000 Wielder Can't Move
+40 20000 Telepathy Formerly Floating Eye
+25 3000 Sense Orcs
+25 3000 Sense Trolls
+25 5000 Sense Dragons
+25 5000 Sense Giants
+25 5000 Sense Demons
+25 5000 Sense Undead
+25 5000 Sense Evil
+25 5000 Sense Animals
+25 5000 Sense Thunderlords
+25 5000 Sense Good
+25 5000 Sense Nonliving
+25 5000 Sense Unique Monsters
+25 2000 Sense Spiders
+
+~~~~~08
+#####GArtifact Activations
+lvl xp Power
+40 40000 Sunlight Brass Lantern
+20 4000 Magic Missile (1)
+30 300000 Magic Missile (2)
+40 400000 Ball of Missiles
+30 300000 Bolt of Lightning
+30 300000 Ball of Lightning
+35 350000 Ball of Lightning(2)
+40 400000 Ball of Lightning(3)
+40 400000 Ball of Lightning(4)
+45 450000 Breath Lightning
+50 40000 Fire a Rocket
diff --git a/lib/mods/theme/help/experien.hlp b/lib/mods/theme/help/experien.hlp
new file mode 100644
index 00000000..5e0bb9eb
--- /dev/null
+++ b/lib/mods/theme/help/experien.hlp
@@ -0,0 +1,28 @@
+|||||oy
+~~~~~01|Experience
+#####RGaining experience
+#####R==============================================
+
+The principle way for your character to gain experience (XP) is to kill
+monsters. There are a few other ways too, like lockpicking, but these only
+give small rewards.
+
+Once your character has gained enough experience to go up a level, then she
+will be given skill points to spend as you see fit. These points can be
+spent on either
+
+ *****/askills.txt*0[(a) Skills] which improve more for each point you put into them,
+or
+ *****/bability.txt*0[(b) Abilities] which are one-off purchases and grant your character new,
+ non-improvable powers
+
+Certain monsters can "drain" your experience, and thus your level. Although you
+do not lose the skill points you've already gained, you also will not gain
+further points until you reach a character level you have not already
+achieved. Luckily, you can restore drained experience through magical means,
+or by simply regaining the experience all over again.
+
+ *****/ynewbie.hlp*0[(y) New player help menu]
+ *****/zhelp.hlp*0[(z) Main menu]
+
+
diff --git a/lib/mods/theme/help/explore.hlp b/lib/mods/theme/help/explore.hlp
new file mode 100644
index 00000000..0c302ab8
--- /dev/null
+++ b/lib/mods/theme/help/explore.hlp
@@ -0,0 +1,16 @@
+|||||oy
+~~~~~01|Help|Exploring menu
+~~~~~02|Exploring menu
+#####RWelcome to the ToME Help System.
+#####R==============================================
+
+Please choose one of the following online help files:
+
+ *****/acommand.txt*0[(a) Available commands] How to control your character
+ *****/battack.txt*0[(b) Attacking monsters] How to attack, elemental attacks and resistances etc
+ *****/cdungeon.txt*0[(c) Exploring the dungeons] Symbols on your map, mining, pets, objects + more
+
+ *****/ynewbie.hlp*0[(y) New player help menu]
+ *****/zhelp.hlp*0[(z) Main menu]
+
+ \ No newline at end of file
diff --git a/lib/mods/theme/help/fatespoi.txt b/lib/mods/theme/help/fatespoi.txt
new file mode 100644
index 00000000..2815129e
--- /dev/null
+++ b/lib/mods/theme/help/fatespoi.txt
@@ -0,0 +1,28 @@
+|||||oy
+~~~~~01|Spoilers|Fates
+~~~~~02|Fates (spoiler)
+#####R Fate Spoiler
+#####R Accurate for PernAngband 5.x.x
+#####R by Dustin Ragan
+
+Numerous spirits inhabit the land of Arda, from the murderous barrow wights to
+the enigmatic Tom Bombadil. These spirits usually are bound to a specific
+geographic region, but there are exceptions to this rule. Sometimes one of
+these spirits will take interest in an adventurer. This can either be very,
+very good or very, very bad. These spirits will "rig" reality to ensure that
+something happens--or doesn't happen.
+
+In order to attract the attention of a spirit, the adventurer must be somewhat
+experienced, having attained at least the 11th level of experience. Every 10
+game turns, which corresponds to 1 normal speed player turn, there is a
+1 in 50,000 chance of gaining a fate. When this fate is chosen, there is a
+7/18 chance of being fated to find a specific mundane item on a specific
+dungeon level. A more belligerent spirit will, 7/18 of the time, summon a
+malicious monster to do battle on a specific dungeon level. There is a 1/9
+chance to be destined to find an artifact on a given level. There is also
+a 1/18 chance that you will meet your demise on a given level. Finally, there
+is a 1/18 chance of becoming invulnerable to attacks from mortals.
+
+Whenever a level is being chosen for a fate, it is always chosen within 20
+levels of your current recall depth. Items, monsters, and artifacts are all
+generated up to 10 levels out of depth for your current recall depth.
diff --git a/lib/mods/theme/help/foot.aux b/lib/mods/theme/help/foot.aux
new file mode 100644
index 00000000..47328799
--- /dev/null
+++ b/lib/mods/theme/help/foot.aux
@@ -0,0 +1,4 @@
+</TT></PRE>
+</FONT>
+</body>
+</html>
diff --git a/lib/mods/theme/help/g_aule.txt b/lib/mods/theme/help/g_aule.txt
new file mode 100644
index 00000000..89399179
--- /dev/null
+++ b/lib/mods/theme/help/g_aule.txt
@@ -0,0 +1,61 @@
+|||||oy
+~~~~~01|Gods|Aule
+~~~~~02|Aule
+#####R === Aule the Smith ===
+
+Aule the Smith is the inventor and smith of the Valar.
+His most faithful followers are those of the class *****c_stonewr.txt*0[Stonewright].
+
+#####GThe benefits of worshipping Aule the Smith
+1. As you increase your piety, Aule will grant you a boost to your accuracy
+ and damage to a maximum of +5.
+2. As your piety increases, he will grant you resistance to fire.
+3. If you are praying to him at the time, there is a chance that he will
+ cast Stone Skin on you.
+4. Aule likes Dwarves, Petty-dwarves, Gnomes, and Dark Elves.
+4. Your piety will increase slightly more if you are wielding an axe or a hammer.
+
+#####GThe disadvantages of worshipping Aule the Smith
+1. He doesn't like it if you kill dwarves of any kind.
+2. Your piety will decrease over time unless you are a Dwarf, Petty-dwarf,
+ Gnome, or Dark-Elf.
+3. He will completely abandon you if you wear The One Ring.
+~~~~~~03|Aule|Prayers
+#####GAule's Magic
+Worshipping Aule the Smith gives the adventurer access to a set of special
+spells that come directly from the hands of Aule. These spells use your piety
+to cast rather than your spellpoints, and the level of spells that Aule will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for his help without offending him!
+
+There is a special book - called the "The Earth Tome of Aule" which
+contains instructions for the procedure for each of the prayers Eru will
+grant. There are four prayers all told, which are:
+1. [[[[[BFirebrand] (Level 1)
+ Imbues your melee weapon with fire to deal more damage.
+ At level 15 it spreads over a 1 radius zone around your target.
+ At level 30 it deals holy fire damage.
+2. [[[[[BEnchant Weapon] (Level 10)
+ Tries to enchant a weapon to-hit.
+ At level 5 it also enchants to-dam.
+ At level 45 it enhances the special powers of magical weapons.
+ The might of the enchantment increases with level.
+3. [[[[[BEnchant Armour] (Level 15)
+ Tries to enchant a piece of armour.
+ At level 20 it also enchants to-hit and to-dam.
+ At level 40 it enhances the special powers of magical armour
+ The might of the enchantment increases with level.
+4. [[[[[BChild of Aule] (Level 20)
+ Summons a levelled Dwarven warrior to help you battle the forces
+ of Morgoth.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Aule will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+
+ *****m_earth.txt*0[Earth School] at 1/3 the Prayer skill level.
+ *****m_fire.txt*0[Fire School] at 3/5 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/mods/theme/help/g_eru.txt b/lib/mods/theme/help/g_eru.txt
new file mode 100644
index 00000000..113875b3
--- /dev/null
+++ b/lib/mods/theme/help/g_eru.txt
@@ -0,0 +1,65 @@
+|||||oy
+~~~~~01|Gods|Eru
+~~~~~02|Eru
+#####R === Eru Iluvatar ===
+
+Eru Iluvatar is the father of the Valar. His most faithful followers are those
+of the class *****c_pr_eru.txt*0[Priest(Eru)].
+
+#####GThe benefits of Worshipping Eru Iluvatar
+1. As you increase your piety, Eru will grant you a boost to your wisdom.
+ Eventually he will also start increasing your ability to handle magical
+ power, resulting in a boost to your spellpoints.
+2. If you are praying to him at the time, there is a chance that he will
+ deflect some blows from evil monsters (that increases with your level of
+ piety).
+3. If you are praying to him at the time, there is a chance that he will
+ resurrect you from the dead (provided you are very pious!).
+4. Your piety automatically increases over time if you are:
+ a) Not praying, and
+ b) Actively doing something (i.e. not resting or in the Wilderness map).
+
+#####GThe disadvantages of Worshipping Eru Iluvatar
+1. He doesn't like it if you destroy blessed weapons.
+2. You can only wield blunt or blessed weapons without penalty.
+3. He doesn't like it if you kill monsters that are aligned with good.
+4. He will completely abandon you if you wear The One Ring.
+~~~~~~03|Eru|Prayers
+#####GEru Iluvatar's Magic
+Worshipping Eru Iluvatar gives the adventurer access to a set of special
+spells that come directly from the hands of Eru. These spells use your piety
+to cast rather than your spellpoints, and the level of spells that Eru will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for his help without offending him!
+
+There is a special book called the "Holy Tome of Eru Iluvatar" which
+contains instructions for the procedure for each of the prayers Eru will
+grant. There are four prayers all told, which are:
+1. [[[[[BSee the Music] (Level 1)
+ Allows you to 'see' the Great Music from which the world originates,
+ allowing you to see unseen things, and can be cast while blind.
+ At spell level 10 it allows you to see your surroundings.
+ At spell level 20 it allows you to cure blindness.
+ At spell level 30 it allows you to fully see all the level.
+2. [[[[[BListen to the Music] (Level 7)
+ Allows you to listen to the Great Music from which the world originates,
+ allowing you to understand the meaning of things.
+ At spell level 14 it allows you to identify all your pack.
+ At spell level 30 it allows you to identify all items on the level.
+3. [[[[[BKnow the Music] (Level 30)
+ Allows you to understand the Great Music from which the world originates,
+ allowing you to know the full abilities of things.
+ At spell level 10 it allows you to *identify* all your pack.
+4. [[[[[BLay of Protection] (Level 35)
+ Creates a circle of safety around you.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Eru will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+ *****m_mana.txt*0[Mana School] at 1/2 the Prayer skill level.
+ *****m_divin.txt*0[Divination School] at 2/3 the Prayer skill level.
+ *****m_mind.txt*0[Mind School] at 1/3 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/mods/theme/help/g_mandos.txt b/lib/mods/theme/help/g_mandos.txt
new file mode 100644
index 00000000..5e21553c
--- /dev/null
+++ b/lib/mods/theme/help/g_mandos.txt
@@ -0,0 +1,56 @@
+|||||oy
+~~~~~01|Gods|Mandos
+~~~~~02|Mandos
+#####R === Mandos ===
+
+Mandos is the Doomsman of the Valar, rarely seen but much revered. His most faithful
+followers are those of the class *****c_pr_mand.txt*0[Priest(Mandos)].
+
+#####GThe benefits of worshipping Mandos
+1. His followers are granted resistance to nether forces.
+2. If your piety is sufficiently high, and you are praying to him, Mandos will prevent
+ the space-time continuum from being disrupted around you.
+3. If you are very pious and praying, Mandos will grant you immunity to nether.
+4. He likes it if you kill vampires.
+5. He adores it if you kill vampire elves.
+6. Your piety will slowly increase over time if you are not praying.
+7. Mandos likes High Elves and Lost Souls.
+
+#####GThe disadvantages of worshipping Mandos
+1. Mandos doesn't like Vampires and Demons.
+2. He hates being disturbed, so praying will make you lose piety very quickly.
+3. He hates it if you kill living elves of any kind.
+4. He *hates* it if you kill elves who are friendly to you.
+5. He absolutely detests it if you kill friendly spirits.
+6. He will completely abandon you if you wear The One Ring.
+~~~~~~03|Mandos|Prayers
+#####GMandos' Magic
+Worshipping Mandos gives the adventurer access to a set of special spells that come
+directly from the hands of Mandos. These spells use your piety to cast rather than
+your spellpoints, and the level of spells that Mandos will permit you to use is
+determined by your Prayer skill - how skillful you are in asking for his help
+without offending him!
+
+There is a special book - called the "Holy Tome of Mandos" which
+contains instructions for the procedure for each of the prayers Mandos will
+grant. There are four prayers all told, which are:
+1. [[[[[BTears of Luthien] (Level 5)
+ Calls upon the spirit of Luthien to ask Mandos for healing and succour.
+2. [[[[[BFeanturi] (Level 10)
+ Channels the power of Mandos to cure fear and confusion.
+ At level 20 it restores lost INT and WIS
+ At level 30 it cures hallucinations and restores a percentage of lost sanity.
+3. [[[[[BTale of Doom] (Level 25)
+ Allows you to predict the future for a short time.
+4. [[[[[BCall to the Halls] (Level 30)
+ Summons a leveled spirit from the Halls of Mandos to fight for you.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Mandos will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+ *****m_divin.txt*0[Divination School] at 1/3 the Prayer skill level.
+ *****m_tempo.txt*0[Temporal School] at 1/4 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/mods/theme/help/g_manwe.txt b/lib/mods/theme/help/g_manwe.txt
new file mode 100644
index 00000000..4bbc85fd
--- /dev/null
+++ b/lib/mods/theme/help/g_manwe.txt
@@ -0,0 +1,62 @@
+|||||oy
+~~~~~01|Gods|Manwe
+~~~~~02|Manwe
+#####R === Manwe Sulimo ===
+
+Manwe is the strongest of the Valar, next to Morgoth. His most faithful
+followers are those of the class *****c_pr_man.txt*0[Priest(Manwe)].
+
+#####GThe benefits of Worshipping Manwe Sulimo
+1. As you increase your piety, Manwe will grant boosts to your speed (up to
+ a maximum boost of +7 speed).
+2. If you are praying, Manwe likes it when you kill monsters that are aligned
+ with evil.
+3. As your piety increases, Manwe will grant you the following abilities (in
+ order):
+ a) Levitation
+ b) Free Action (while praying)
+ c) Flying (while praying)
+4. Manwe likes elves.
+
+#####GThe disadvantages of Worshipping Manwe Sulimo
+1. Your piety slowly decreases with time, whether you are praying or not.
+2. He doesn't like it if you kill monsters that are aligned with good.
+3. He will completely abandon you if you wear The One Ring.
+~~~~~03|Manwe|Prayers
+#####GManwe Sulimo's Magic
+Worshipping Manwe Sulimo gives the adventurer access to a set of special
+spells that come directly from the hands of Manwe. These spells use your piety
+to cast rather than your spellpoints, and the level of spells that Manwe will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for his help without offending him!
+
+There is a special book called the "Holy Tome of Manwe Sulimo" which
+contains instructions for the procedure for each of the prayers Manwe will
+grant. There are four prayers all told, which are:
+1. [[[[[BManwe's Blessing] (Level 1)
+ Manwe's Blessing removes your fears, blesses you and surrounds you with holy
+ light.
+ At spell level 10 it also grants heroism.
+ At spell level 20 it also grants super heroism.
+ At spell level 30 it also grants holy luck and life protection.
+2. [[[[[BWind Shield] (Level 10)
+ It surrounds you with a shield of wind that deflects blows from evil
+ monsters.
+ At level 10 it increases your armour rating.
+ At level 20 it retaliates against monsters that melee you.
+3. [[[[[BManwe's Call] (Level 20)
+ Manwe's Call summons a Great Eagle to help you battle the forces of
+ Morgoth.
+4. [[[[[BAvatar] (Level 35)
+ It turns you into a full grown Maia.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Manwe will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+ *****m_air.txt*0[Air School] at 2/3 the Prayer skill level.
+ *****m_convey.txt*0[Conveyance School] at 1/2 the Prayer skill level.
+ *****m_meta.txt*0[Meta School] at 1/3 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/mods/theme/help/g_melkor.txt b/lib/mods/theme/help/g_melkor.txt
new file mode 100644
index 00000000..d6033e72
--- /dev/null
+++ b/lib/mods/theme/help/g_melkor.txt
@@ -0,0 +1,65 @@
+|||||oy
+~~~~~01|Melkor
+~~~~~02|Gods|Melkor
+#####R === Melkor Bauglir ===
+
+Melkor Bauglir is Morgoth, the Dark Enemy. He once was the most powerful
+of the Valar. His most faithful followers are those of the class *****c_pr_drk.txt*0[Dark Priest].
+
+#####GThe benefits of Worshipping Melkor Bauglir
+ 1. As you increase your piety, Melkor will grant boosts to your strength,
+ constitution and charisma and will decrease intelligence and wisdom.
+ 2. As a follower of Melkor you are resistant to fire.
+ 3. If you are praying, Melkor may make you invisible and immune to fire.
+ 4. If you are praying, Melkor may cast Curse on your foes when you melee them.
+ 5. If you are praying, Melkor likes it when you kill monsters.
+ 6. If you are praying, Melkor *likes* it when you kill monsters that are
+ aligned with good.
+ 7. Melkor likes it if you quaff Potions of Corruption.
+ 8. Melkor likes the sacrifice of corpses and books at his altars.
+ 9. Melkor likes the permanent sacrifice of your own health at his altars.
+10. Melkor hates elves.
+11. Melkor grants access to the *****m_udun.txt*0[Udun] school of magic.
+121. Melkor can summon undead and demons to help you when your life goes down.
+
+#####GThe disadvantages of Worshipping Melkor Bauglir
+1. Your piety decreases with time.
+2. Your piety decreases with time even more if you are praying.
+3. He will completely abandon you if you destroy The One Ring.
+~~~~~03|Melkor|Prayers
+#####GMelkor Bauglir's Magic
+Worshipping Melkor Bauglir gives the adventurer access to a set of special
+spells that come directly from the hands of Melkor. These spells use your piety
+to cast rather than your spellpoints, and the level of spells that Melkor will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for his help without offending him!
+
+There is a special book called the "Corrupted Tome of Melkor" which
+contains instructions for the procedure for each of the prayers Melkor will
+grant. There are three prayers all told, which are:
+1. [[[[[BCurse] (Level 1)
+ It curses a monster, reducing its melee power
+ At level 5 it can be auto-casted (with no piety cost) while fighting
+ if your piety is over 5000.
+ At level 15 it also reduces armor
+ At level 25 it also reduces speed
+ At level 35 it also reduces max life (but it is never fatal)
+2. [[[[[BCorpse Explosion] (Level 10)
+ It makes corpses in an area around you explode for a percent of their hit
+ points as damage
+3. [[[[[BMind Steal] (Level 20)
+ It allows your spirit to temporarily leave your own body, which will
+ be vulnerable, to control one of your enemies body
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Melkor will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. This school is as follows:
+ *****m_mind.txt*0[Mind School] at 1/3 the Prayer skill level.
+
+Melkor also grants all of his followers access to the *****m_udun.txt*0[Udun] school of magic,
+but only powerful mages are able to cast all of its spells.
+
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/mods/theme/help/g_tulkas.txt b/lib/mods/theme/help/g_tulkas.txt
new file mode 100644
index 00000000..2c05292a
--- /dev/null
+++ b/lib/mods/theme/help/g_tulkas.txt
@@ -0,0 +1,45 @@
+|||||oy
+~~~~~01|Tulkas
+~~~~~02|Gods|Tulkas
+#####R === Tulkas ===
+
+Another of the Valar. His most faithful followers are *****c_palad.txt*0[Paladins].
+
+#####GThe benefits of Worshipping Tulkas
+1. As you increase your piety, Tulkas will grant boosts to your constitution
+ and your strength (up to a maximum of +3 each).
+2. He likes it when you kill monsters that are aligned with evil.
+3. He loves it when you kill evil monsters while praying.
+4. He *adores* it when you kill demons while praying.
+5. If you are praying, Tulkas may increase the damage you do in melee combat.
+
+#####GThe disadvantages of Worshipping Tulkas
+1. When you are praying, your piety slowly decreases with time.
+2. He will completely abandon you if you wear The One Ring.
+~~~~~03|Tulkas|Prayers
+#####GTulkas's Magic
+Worshipping Tulkas gives the adventurer access to a set of special spells
+that come directly from the hands of Tulkas. These spells use your piety to
+cast rather than your spellpoints, and the level of spells that Tulkas will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for his help without offending him!
+
+There is a special book called the "War Tome of Tulkas" which contains
+instructions for the procedure for each of the prayers Tulkas will grant.
+There are three prayers all told, which are:
+1. [[[[[BDivine Aim] (Level 1)
+ It makes you more accurate in combat.
+ At spell level 20 all your blows are critical hits.
+2. [[[[[BWhirlwind] (Level 10)
+ It allows you to spin around and hit all monsters nearby.
+3. [[[[[BWave of Power] (Level 20)
+ It allows you to project a number of melee blows across a distance.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Tulkas will also assist with your ability to
+use some magic from one of the "standard" schools, in relation to how skilled
+you are at Prayer. This school is as follows:
+ *****m_earth.txt*0[Earth School] at 4/5 the Prayer skill level.
+The spells from this school are all cast using your normal spellpoints.
diff --git a/lib/mods/theme/help/g_ulmo.txt b/lib/mods/theme/help/g_ulmo.txt
new file mode 100644
index 00000000..59c3d6e9
--- /dev/null
+++ b/lib/mods/theme/help/g_ulmo.txt
@@ -0,0 +1,58 @@
+|||||oy
+~~~~~01|Gods|Ulmo
+~~~~~02|Ulmo
+#####R === Ulmo ===
+
+Ulmo is the Lord of Waters, he controls all the lakes, rivers, seas, and oceans
+on Arda. His most faithful followers are those of the class *****c_pr_ulmo.txt*0[Priest(Ulmo)].
+
+#####GThe benefits of worshipping Ulmo
+1. Ulmo's followers can breathe underwater.
+2. If your piety is sufficiently high and you are praying, Ulmo will grant
+ you resistance to poison.
+3. If you are very pious and praying, Ulmo will grant you the ability
+ to breathe without air.
+4. Ulmo likes it if you wield or carry tridents.
+5. If you are not praying, your piety will increase automatically over time.
+6. Ulmo likes the Edain, Dunedain, Druedain, and Rohirrim.
+
+#####GThe disadvantages of worshipping Ulmo
+1. He doesn't like it if you kill aquatic creatures.
+2. He hates it if you kill good, friendly, or unique aquatic creatures.
+3. He doesn't like it if you use magic involving any kind of fire.
+4. Ulmo hates Easterlings, Orcs, and Demons.
+5. He will completely abandon you if you wear The One Ring.
+~~~~~~03|Ulmo|Prayers
+#####GUlmo's Magic
+Worshipping Ulmo gives the adventurer access to a set of special spells that come
+directly from the hands of Ulmo. These spells use your piety to cast rather than
+your spellpoints, and the level of spells that Ulmo will permit you to use is
+determined by your Prayer skill - how skillful you are in asking for his help
+without offending him!
+
+There is a special book - called the "Water Tome of Ulmo" which
+contains instructions for the procedure for each of the prayers Ulmo will
+grant. There are four prayers all told, which are:
+1. [[[[[BSong of Belegaer] (Level 1)
+ Channels the power of the Great Sea into your fingertips.
+ Sometimes it can blast through its first target.
+2. [[[[[BDraught of Ulmonan] (Level 15)
+ Fills you with a draught with powerful curing effects, prepared by Ulmo himself.
+ At spell level 1 it cures blindness, poison, cuts and stunning
+ At spell level 10 it restores drained STR, DEX and CON
+ At spell level 20 it removes parasites and unwanted mimicry
+3. [[[[[BCall of the Ulumuri] (Level 20)
+ Summons a leveled water spirit or elemental to fight for you.
+4. [[[[[BWrath of Ulmo] (Level 30)
+ Conjures up a sea storm.
+ At spell level 30 it turns into a more forceful storm.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to his specific magic, Ulmo will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+ *****m_water.txt*0[Water School] at 3/5 the Prayer skill level.
+ *****m_nature.txt*0[Nature School] at 1/2 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints. \ No newline at end of file
diff --git a/lib/mods/theme/help/g_varda.txt b/lib/mods/theme/help/g_varda.txt
new file mode 100644
index 00000000..a5d28475
--- /dev/null
+++ b/lib/mods/theme/help/g_varda.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Gods|Varda
+~~~~~02|Varda
+#####R === Varda Elentari ===
+
+Varda Elentari is the greatest Queen of the Valar. Her most faithful followers
+are those of the class *****c_pr_varda.txt*0[Priest(Varda)].
+
+#####GThe benefits of worshipping Varda Elentari
+1. She grants her followers permanent light of radius 1.
+2. As you increase your piety, Varda will grant you resistance to light
+ while praying.
+3. Your piety will increase while you are in lit areas.
+4. Varda loves when you use spells involving light.
+
+#####GThe disadvantages of worshipping Varda Elentari
+1. Your piety will decrease while you are in dark places.
+2. Varda dislikes evil races (Orcs, Trolls, Dragons, and Demons).
+3. Your piety will slowly decrease while praying.
+4. She will completely abandon you if you wear The One Ring.
+~~~~~~03|Varda|Prayers
+#####GVarda Elentari's Magic
+Worshipping Varda Elentari gives the adventurer access to a set of special
+spells that come directly from the hands of Varda. These spells use your piety
+to cast rather than your spellpoints, and the level of spells that Varda will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for her help without offending her!
+
+There is a special book - called the "Shining Tome of Varda" which
+contains instructions for the procedure for each of the prayers Varda will
+grant. There are four prayers all told, which are:
+1. [[[[[BLight of Valinor] (Level 1)
+ Lights up a room.
+ At spell level 3 it starts damaging monsters.
+ At spell level 15 it starts creating a more powerful kind of light.
+2. [[[[[BCall of Almaren] (Level 10)
+ Banishes evil beings.
+ At spell level 20 it dispels evil beings.
+3. [[[[[BEvenstar] (Level 30)
+ Maps and lights the whole level.
+ At spell level 40 it maps and lights the whole level, in addition to
+ letting you know yourself better and identifying your whole pack.
+4. [[[[[BStar Kindler] (Level 35)
+ Does multiple bursts of light damage. The power increases with level.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to her specific magic, Varda will also assist with your ability to
+use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+ *****m_mana.txt*0[Mana School] at 1/4 the Prayer skill level.
+ *****m_meta.txt*0[Meta School] at 1/3 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/mods/theme/help/g_yavann.txt b/lib/mods/theme/help/g_yavann.txt
new file mode 100644
index 00000000..6e6937ca
--- /dev/null
+++ b/lib/mods/theme/help/g_yavann.txt
@@ -0,0 +1,62 @@
+|||||oy
+~~~~~01|Yavanna
+~~~~~02|Gods|Yavanna
+#####R === Yavanna Kementari===
+
+Yavanna, the Giver of Fruits, created all plants and animals and awakened the
+Ents to protect the forests of Arda. Kementari, Queen of the Earth, is her
+surname. Her most faithful followers are the *****c_druid.txt*0[Druids].
+
+#####GThe benefits of Worshipping Yavanna
+1. As you increase your piety, Yavanna will grant you the ability to pass
+ trees while praying.
+2. She makes you regenerate faster while praying on grass.
+3. She likes it when you kill nonliving creatures, undead or demons.
+4. She likes it if you charm animals (except evil ones).
+5. Yavanna likes Ents.
+
+#####GThe disadvantages of Worshipping Yavanna
+1. Your piety slowly decreases with time, whether you are praying or not.
+2. She doesn't like it if you kill monsters while praying.
+3. She hates it if you kill animals while praying.
+4. She hates it if you hurt your animal pets.
+5. She hates it if you burn or destroy trees with magic or allow monsters to
+ do so.
+6. She will completely abandon you if you wear The One Ring.
+~~~~~03|Yavanna|Prayers
+#####GYavanna's Magic
+Worshipping Yavanna gives the adventurer access to a set of special spells
+that come directly from the hands of Yavanna. These spells use your piety to
+cast rather than your spellpoints, and the level of spells that Yavanna will
+permit you to use is determined by your Prayer skill - how skillful you are
+in asking for her help without offending her!
+
+There is a special book called the "Forest Tome of Yavanna" which contains
+instructions for the procedure for each of the prayers Yavanna will grant.
+There are five prayers all told, which are:
+1. [[[[[BCharm Animal] (Level 1)
+ Tries to tame animals in a zone around your target.
+2. [[[[[BGrow Grass] (Level 10)
+ Creates a floor of grass around you. While on grass and praying,
+ a worshipper of Yavanna will know a greater regeneration rate.
+3. [[[[[BTree Roots] (Level 15)
+ Creates roots deep in the floor from your feet, making you more stable and
+ able to do better attacks, but preventing any movement (even teleportation).
+ It also makes you recover from stunning almost immediately.
+4. [[[[[BWater Bite] (Level 20)
+ Imbues your melee weapon with a natural stream of water.
+ At level 25, it spreads over a 1 radius zone around your target.
+5. [[[[[BUproot] (Level 35)
+ Awakes a tree to help you battle the forces of Morgoth.
+
+Each of these spells can be increased in level both by improving your Prayer
+skill, and by improving your Spell-power skill.
+
+In addition to her specific magic, Yavanna will also assist with your ability
+to use some magic from the "standard" schools, in relation to how skilled you
+are at Prayer. These schools are as follows:
+ *****m_earth.txt*0[Earth School] at 1/2 the Prayer skill level.
+ *****m_nature.txt*0[Nature School] at 1/2 the Prayer skill level.
+ *****m_water.txt*0[Water School] at 1/2 the Prayer skill level.
+ *****m_tempo.txt*0[Temporal School] at 1/6 the Prayer skill level.
+The spells from these schools are all cast using your normal spellpoints.
diff --git a/lib/mods/theme/help/gambling.txt b/lib/mods/theme/help/gambling.txt
new file mode 100644
index 00000000..62352600
--- /dev/null
+++ b/lib/mods/theme/help/gambling.txt
@@ -0,0 +1,29 @@
+|||||oy
+~~~~~01|Gambling
+#####R=== Gambling Rules ===
+
+#####GBetween :
+ Three 12-sided dice rolled; 2 black, 1 red. The red
+ die must be between both black to win. If the red die
+ matches a black die, you lose. Pays 3 to 1
+#####GCraps:
+ Two 6-sided dice are rolled. On first roll, a 7 or 11
+ wins. A 2, 3 or 12 loses. Otherwise roll until the first
+ roll is matched (win) or a 7 is rolled (loss). Pays 2 to 1
+#####GWheel:
+ Pick a number from 0-9. If the number shows on wheel
+ after it stops spinning, you win. Pays 10 to 1
+
+#####GSlots:
+ Three dice rolled. Matches win gold.
+ Numbers are:
+ 1=Lemon, 2=Orange, 3=Sword, 4=Shield, 5=Plum, 6=Cherry
+ Payoffs are as follows:
+ Cherry Cherry Lemon 2-1 Cherry Cherry Orange 3-1
+ Cherry Cherry Sword 4-1 Cherry Cherry Shield 5-1
+ Cherry Cherry Plum 6-1
+ Lemon Lemon Lemon 4-1 Orange Orange Orange 16-1
+ Sword Sword Sword 6-1 Shield Shield Shield 25-1
+ Plum Plum Plum 9-1 Cherry Cherry Cherry 36-1
+
+
diff --git a/lib/mods/theme/help/general.txt b/lib/mods/theme/help/general.txt
new file mode 100644
index 00000000..17dc187c
--- /dev/null
+++ b/lib/mods/theme/help/general.txt
@@ -0,0 +1,39 @@
+|||||oy
+~~~~~01|Help
+#####R=== Using the Online Help ===
+
+This help system has been designed to be read whilst in-game. Printing it off
+will make it look clumsy and a little difficult to read.
+
+Any text in orange/yellow colour is likely to be a hyperlink, and pressing
+<enter> while the link is active (yellow) will take you to the relevant page.
+Navigate between viewable links by using the left-right keys. Some links also
+have bracketed letters included in the links. Pressing these letters on your
+keyboard will activate the link even if it is orange.
+
+The help files total over 850 kb, so there is a lot of information. They have
+been designed to be browsed, but you may be looking for specific information,
+in which case you should try looking at the alphabetical *****index.txt*0[index].
+
+Here are all the relevant keypresses for navigating the help system.
+
+#####GKey | Action
+-------------------------------------------------------------------
+Escape | Leave the Online Help
+Backspace | Return to previous Help File
+Space | Advance 1 page (screen)
+2, down arrow | Advance 1 line
+8, up arrow | Back up 1 line
+- | Back up 1 page (screen)
+6, right arrow | Advance 1 link
+4, left arrow | Back up 1 link
+Return | Activate the selected link
+# | Go to a specific line (defaults to line 0)
+% | Go to a specific help file (defaults to help.hlp)
+= | Highlight lines containing a string (e.g. "word")
+/ | Search for a string (e.g. "word")
+-------------------------------------------------------------------
+
+There are other sources for help playing ToME. Try http://forum.t-o-m-e.net
+and http://wiki.t-o-m-e.net . We also have an IRC channel #tome on the
+worldirc and freenode networks (they are linked) which is fairly low traffic.
diff --git a/lib/mods/theme/help/gods.txt b/lib/mods/theme/help/gods.txt
new file mode 100644
index 00000000..60427e7e
--- /dev/null
+++ b/lib/mods/theme/help/gods.txt
@@ -0,0 +1,42 @@
+|||||oy
+~~~~~01|Gods
+#####RThe Guide to the Gods.
+
+#####G1. Introduction
+ Everybody likes to have a little helping hand now and then. What
+could be better than having a god on your side? But it's not quite that easy.
+The gods won't help just any mortal who calls for help. You have to give them
+a little something too.
+
+#####G2. How Do I Get in on This?
+ When you start a character, you get a choice of whether or not you
+wish to begin worshipping a God (unless you're something like a priest - they
+*must* start with a God to worship). If you do choose to be a follower of one
+of the Gods, you will gain certain abilities provided you do not do things
+that displease them. The measure of how happy your God is with you is your
+Piety - the Pt stat is your measure of Piety. Different actions will allow you
+to gain or lose Piety over time. You can change your mind about whom (if
+anyone) to worship during the game by finding an *****tome_faq.txt*04[altar] of that God.
+
+#####G3. What about spells?
+God-granted spells are also known as prayers, and are cast using Piety instead
+of Mana. God-spells can be increased in level by improving either your Prayer
+or Spell-power skill. The chance of successfully invoking a prayer depends
+on the Prayer skill and your wisdom.
+
+Each God also grants access to standard magical spell schools; which school(s)
+vary depending on the Gods' individual preferences. Spells from these schools
+are cast using Mana, not Piety; and success depends on your intelligence, not
+your wisdom.
+
+#####G4. So, Who Are These Gods?
+ In Theme, there are nine Gods you may choose to worship, being:
+1. *****g_eru.txt*0[Eru Iluvatar] - the father of the Valar.
+2. *****g_manwe.txt*0[Manwe Sulimo] - the greatest of the Valar, watching from atop Taniquetil.
+3. *****g_ulmo.txt*0[Ulmo] - the second mightiest of the Valar, lord of all waters on Arda.
+4 *****g_varda.txt*0[Varda Elentari] - Manwe's spouse, the most beloved by the Elves.
+5. *****g_yavann.txt*0[Yavanna Kementari] - the Earth Queen who created plants and animals.
+6. *****g_aule.txt*0[Aule the Smith] - the builder and inventor of the Valar.
+7. *****g_tulkas.txt*0[Tulkas] - another of the Valar, Tulkas values strength and courage.
+8. *****g_mandos.txt*0[Mandos] - the Doomsman of the Valar, wise and powerful.
+9. *****g_melkor.txt*0[Melkor Bauglir] - the Dark Enemy himself, once the most powerful of the Valar.
diff --git a/lib/mods/theme/help/head.aux b/lib/mods/theme/help/head.aux
new file mode 100644
index 00000000..92e979d3
--- /dev/null
+++ b/lib/mods/theme/help/head.aux
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>T.o.M.E. Documentation</title>
+ <meta name="description" content="ToME and TomeNET homepage. ToME is a roguelike dungeon exploration game, based on Angband.">
+ <meta name="keywords" content="angband, tome, tomenet, library, angband, official, roguelike">
+</head>
+<body bgcolor="#000000" text="#FFFFFF" link="#CC0000" alink="#FF9900" vlink="#FFCC66">
+<FONT text="#CCCCCC">
+<PRE><TT>
diff --git a/lib/mods/theme/help/help.hlp b/lib/mods/theme/help/help.hlp
new file mode 100644
index 00000000..7c4b431f
--- /dev/null
+++ b/lib/mods/theme/help/help.hlp
@@ -0,0 +1,33 @@
+|||||oy
+~~~~~01|Help|Main Menu
+~~~~~02|Main Menu
+#####RWelcome to the ToME Online Help System.
+#####R==============================================
+
+Please choose one of the following online help files:
+
+ *****/ageneral.txt*0[(a) About this help system]
+ *****/bnewbie.hlp*0[(b) Help for new players] Skills, magic, races, classes + more
+ *****/cadvanced.hlp*0[(c) Help for more experienced players] Options, Macros, Automatizer etc
+ *****/dtome_faq.txt*0[(d) ToME FAQ] Common questions
+
+ *****/sspoiler.hlp*0[(s) Spoiler menu] Dungeons, fates, luck, corruptions and stuff
+
+
+ *****/xindex.txt*0[(x) Alphabetical index] Trouble finding something? Try here
+
+#####GBasic keys:
+Space | Advance 1 page (screen)
+2, down arrow | Advance 1 line
+8, up arrow | Back up 1 line
+- | Back up 1 page (screen)
+6, right arrow | Advance 1 link
+4, left arrow | Back up 1 link
+Return | Activate the selected link
+Escape | Leave the Online Help
+Backspace, ? | Return to previous Help File
+# | Go to a specific line (defaults to line 0)
+% | Go to a specific help file (defaults to help.hlp)
+= | Highlight lines containing a string (e.g. "word")
+/ | Search for a string (e.g. "word")
+
diff --git a/lib/mods/theme/help/index.txt b/lib/mods/theme/help/index.txt
new file mode 100644
index 00000000..c89a70b3
--- /dev/null
+++ b/lib/mods/theme/help/index.txt
@@ -0,0 +1,636 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Help Index >
+#####R \----------------------------------------/
+
+This is the index of everything in the T.o.M.E. documentation.
+
+#####BHit a letter key to jump to the entries for that letter.
+
+Some entries in the index link to the same place as other entries. This is
+intentional, so that the information you want is easy to find.
+
+Don't forget you can browse the help from the *****help.hlp*02[Main menu].
+
+#####sSpotted a problem with the help files, or some content thats missing?
+#####sContact fearoffours@t-o-m-e.net .
+
+~~~~~65
+*****/Aindex.txt*65[A]
+ *****birth.txt*81[Abbreviations]
+ *****birth.txt*20[AC]
+ *****birth.txt*17[AU]
+ *****tome_faq.txt*25[FF]
+ *****birth.txt*21[HP]
+ *****birth.txt*29[Pt]
+ *****birth.txt*24[SN]
+ *****birth.txt*26[SP]
+ *****ability.txt*01[Abilities]
+ *****ability.txt*07[Ammo creation]
+ *****ability.txt*05[Extra Max Blow 1]
+ *****ability.txt*06[Extra Max Blow 2]
+ *****ability.txt*10[Far reaching attack]
+ *****ability.txt*04[Perfect casting]
+ *****ability.txt*02[Spread blows]
+ *****ability.txt*08[Touch of death]
+ *****ability.txt*11[Trapping]
+ *****ability.txt*03[Tree walking]
+ *****ability.txt*12[Undead Form]
+ *****m_air.txt*02[Air Magic]
+ *****tome_faq.txt*03[Altars]
+ *****tome_faq.txt*37[Anti-magic Amulets and the Anti-magic shell]
+ *****c_unbel.txt*04[Antimagic]
+ *****c_archer.txt*01[Archer]
+ *****attack.txt*03[Armor]
+ *****birth.txt*19[Armor Class]
+ *****attack.txt*05[Resistances]
+ *****tome_faq.txt*18[Artifacts that activate but I cannot wear or wield]
+ *****c_ascet.txt*02[Ascetic]
+ *****c_assass.txt*01[Assassin]
+ *****attack.txt*01[Attacking Monsters]
+ *****attack.txt*06[Damage Effect type ]
+ *****attack.txt*04[Resistances]
+ *****birth.txt*48[Fighting ability]
+ *****birth.txt*50[Shooting]
+ *****g_aule.txt*02[Aule]
+ *****automat.txt*03[Auto destroy]
+ *****automat.txt*02[Auto pick-up]
+ *****automat.txt*01[Automatizer]
+ *****defines.txt*82[Defines]
+ *****automat.txt*04[Autosquelch]
+ *****c_axemas.txt*01[Axemaster]
+~~~~~66
+*****/Bindex.txt*66[B]
+ *****rm_barb.txt*01[Barbarian]
+ *****c_bard.txt*01[Bard]
+ *****tome_faq.txt*36[Beginner strategy]
+ *****r_beorn.txt*01[Beorning]
+ *****birth.txt*84[Birth]
+ *****dungeon.txt*21[Buildings]
+~~~~~67
+*****/Cindex.txt*67[C]
+ *****birth.txt*11[Character]
+ *****birth.txt*46[Abilities]
+ *****birth.txt*10[Ability tables]
+ *****birth.txt*23[Armor Class]
+ *****birth.txt*02[Characteristics]
+ *****birth.txt*01[Creating a Character]
+ *****birth.txt*22[Hit Points]
+ *****birth.txt*28[Mana]
+ *****birth.txt*31[Piety]
+ *****birth.txt*08[Race and Class Combinations]
+ *****birth.txt*25[Sanity Points]
+ *****birth.txt*09[Stat Bonus Table]
+ *****birth.txt*13[Stats 1]
+ *****birth.txt*39[Stats 2]
+ *****tome_faq.txt*34[Character choice is too confusing]
+ *****birth.txt*45[Charisma]
+ *****birth.txt*05[Classes]
+ *****c_archer.txt*02[Archer]
+ *****c_ascet.txt*02[Ascetic]
+ *****c_assass.txt*02[Assassin]
+ *****c_axemas.txt*02[Axemaster]
+ *****c_bard.txt*02[Bard]
+ *****c_clairv.txt*02[Clairvoyant]
+ *****birth.txt*68[Combinations with Race]
+ *****c_pr_drk.txt*02[Dark Priest]
+ *****c_demono.txt*02[Demonologist]
+ *****c_druid.txt*02[Druid]
+ *****c_geoman.txt*02[Geomancer]
+ *****c_hafted.txt*02[Haftedmaster]
+ *****c_lorema.txt*02[Loremaster]
+ *****c_mage.txt*02[Mage]
+ *****c_mercen.txt*02[Mercenary]
+ *****c_mimic.txt*02[Mimic]
+ *****c_mindcr.txt*02[Mindcrafter]
+ *****c_monk.txt*02[Monk]
+ *****c_necro.txt*02[Necromancer]
+ *****c_pacif.txt*02[Pacifist]
+ *****c_palad.txt*02[Paladin]
+ *****c_peacemag.txt*02[Peace-mage]
+ *****c_polear.txt*02[Polearmmaster]
+ *****c_posses.txt*02[Possessor]
+ *****c_pr_eru.txt*02[Priest - Eru]
+ *****c_pr_mand.txt*02[Priest - Mandos]
+ *****c_pr_man.txt*02[Priest - Manwe]
+ *****c_pr_ulmo.txt*02[Priest - Ulmo]
+ *****c_pr_varda.txt*02[Priest - Varda]
+ *****c_ranger.txt*02[Ranger]
+ *****c_rogue.txt*02[Rogue]
+ *****c_runecr.txt*02[Runecrafter]
+ *****c_sorcer.txt*02[Sorceror]
+ *****c_sniper.txt*02[Sniper]
+ *****birth.txt*77[Stat Bonuses]
+ *****c_stonewr.txt*02[Stonewright]
+ *****c_summon.txt*02[Summoners]
+ *****c_swordm.txt*02[Swordmasters]
+ *****c_symbia.txt*02[Symbiant]
+ *****c_trapper.txt*02[Trapper]
+ *****c_thaum.txt*02[Thaumaturgist]
+ *****c_unbel.txt*02[Unbeliever]
+ *****c_wainrid.txt*02[Wainrider]
+ *****c_warper.txt*02[Warper]
+ *****c_warrio.txt*02[Warrior]
+ *****rm_class.txt*01[Classical]
+ *****command.txt*99[Commands]
+ *****command.txt*116[Alteration commands]
+ *****command.txt*103[Command counts]
+ *****command.txt*111[Command descriptions ]
+ *****command.txt*129[Extras]
+ *****command.txt*123[Game status]
+ *****command.txt*128[Help]
+ *****command.txt*112[Inventory]
+ *****command.txt*121[Looking ]
+ *****command.txt*122[Messages]
+ *****command.txt*113[Movement]
+ *****command.txt*119[Object manipulation]
+ *****command.txt*100[Original keyset]
+ *****command.txt*126[Pref files]
+ *****command.txt*104[Repeating a command]
+ *****command.txt*114[Resting]
+ *****command.txt*101[Roguelike keyset]
+ *****command.txt*124[Saving and Exiting]
+ *****command.txt*115[Searching]
+ *****command.txt*102[Special keys]
+ *****command.txt*118[Spells and prayers]
+ *****command.txt*117[Terrain interaction]
+ *****command.txt*120[Throwing and missile weapons]
+ *****dungeon.txt*19[Companions]
+ *****birth.txt*43[Constitution]
+ *****m_convey.txt*02[Conveyance Magic]
+ *****corspoil.txt*01[Corruptions ]
+ *****c_clairv.txt*02[Clairvoyant]
+ *****c_archer.txt*03[Creating Ammo]
+ *****birth.txt*12[Creating a Character]
+ *****dungeon.txt*10[Cursed Objects]
+~~~~~68
+*****/Dindex.txt*68[D]
+ *****attack.txt*09[Damage Effects]
+ *****r_drkelf.txt*01[Dark Elf]
+ *****c_pr_drk.txt*01[Dark Priest]
+ *****tome_faq.txt*29[Dark grey things are difficult to see]
+ *****debug.txt*99[Debug]
+ *****debug.txt*100[Command List]
+ *****debug.txt*111[Command descriptions ]
+ *****debug.txt*112[General]
+ *****defines.txt*81[Defines]
+ *****defines.txt*84[Svals]
+ *****defines.txt*85[Tvals]
+ *****r_demon.txt*01[Demon]
+ *****rm_adanrog.txt*01[Adanrog]
+ *****rm_aewrog.txt*01[Aewrog]
+ *****rm_cabrog.txt*01[Caborrog]
+ *****rm_drarog.txt*01[Draugrog]
+ *****rm_hurog.txt*01[Hurog]
+ *****rm_limrog.txt*01[Limrog]
+ *****rm_lygrog.txt*01[Lygrog]
+ *****rm_narrog.txt*01[Narrog]
+ *****rm_rawrog.txt*01[Rawrog]
+ *****rm_sarnrog.txt*01[Sarnrog]
+ *****c_demono.txt*01[Demonologist]
+ *****m_demono.txt*02[Demonology Magic]
+ *****version.txt*01[Development history]
+ *****birth.txt*41[Dexterity]
+ *****birth.txt*56[Disarming traps]
+ *****birth.txt*37[Display]
+ *****m_divin.txt*02[Divination Magic]
+ *****r_dragon.txt*01[Dragon]
+ *****rm_black.txt*01[Black]
+ *****rm_blue.txt*01[Blue]
+ *****rm_ether.txt*01[Ethereal]
+ *****rm_green.txt*01[Green]
+ *****rm_red.txt*01[Red]
+ *****rm_white.txt*01[White]
+ *****r_druadan.txt*01[Druadan]
+ *****c_druid.txt*01[Druid]
+ *****r_dunad.txt*01[Dunedain]
+ *****dungeon.txt*02[Dungeons]
+ *****dungeon.txt*12[Doors]
+ *****dungeon.txt*06[In the dungeon]
+ *****dungeon.txt*11[Mining]
+ *****dunspoil.txt*01[Spoilers]
+ *****r_dwarf.txt*01[Dwarf]
+ *****dungeon.txt*15[Dying]
+~~~~~69
+*****/Eindex.txt*69[E]
+ *****r_eagle.txt*01[Eagle]
+ *****m_earth.txt*02[Earth Magic]
+ *****r_easterl.txt*01[Easterling]
+ *****r_elf.txt*01[Elf]
+ *****r_ent.txt*01[Ent]
+ *****spoil_faq.txt*24[Erebor spoiler]
+ *****g_eru.txt*02[Eru]
+ *****g_eru.txt*03[Prayers]
+ *****c_pr_eru.txt*03[Priest - Eru]
+ *****experien.hlp*01[Experience]
+ *****explore.hlp*02[Exploring menu]
+~~~~~70
+*****/Findex.txt*70[F]
+ *****tome_faq.txt*02[FAQ - Spoiler free]
+ *****spoil_faq.txt*02[FAQ - contains spoilers]
+ *****tome_faq.txt*13[Prophets]
+ *****fatespoi.txt*02[Fates ]
+ *****m_fire.txt*02[Fire Magic]
+ *****inscrip.txt*01[Floor Inscriptions ]
+ *****tome_faq.txt*28[Floor tiles displaying incorrectly]
+ *****tome_faq.txt*05[Fountains]
+ *****tome_faq.txt*24[Fumblefingers quests]
+~~~~~71
+*****/Gindex.txt*71[G]
+ *****gambling.txt*01[Gambling]
+ *****tome_faq.txt*30[Game ]
+ *****c_geoman.txt*01[Geomancer]
+ *****m_geoman.txt*02[Geomancy spells]
+ *****r_gnome.txt*01[Gnome]
+ *****gods.txt*01[Gods]
+ *****tome_faq.txt*04[Altars]
+ *****g_aule.txt*01[Aule]
+ *****g_eru.txt*01[Eru]
+ *****g_mandos.txt*01[Mandos]
+ *****g_manwe.txt*01[Manwe]
+ *****g_melkor.txt*01[Melkor]
+ *****birth.txt*30[Piety]
+ *****tome_faq.txt*23[Quest - Spoilers]
+ *****g_tulkas.txt*01[Tulkas]
+ *****g_ulmo.txt*01[Ulmo]
+ *****g_varda.txt*01[Varda]
+ *****g_yavann.txt*01[Yavanna]
+ *****birth.txt*16[Gold]
+~~~~~72
+*****/Hindex.txt*72[H]
+ *****c_hafted.txt*01[Haftedmaster]
+ *****r_hafelf.txt*01[Half-Elf]
+ *****r_hafogr.txt*01[Half-Ogre]
+ *****general.txt*01[Help]
+ *****explore.hlp*01[Exploring menu]
+ *****tome_faq.txt*01[FAQ - Spoiler free]
+ *****magic.hlp*02[Magic]
+ *****help.hlp*01[Main Menu]
+ *****newbie.hlp*01[New players]
+ *****spoil_faq.txt*01[Spoiled FAQ]
+ *****rm_herm.txt*01[Hermit]
+ *****r_hielf.txt*01[High-Elf]
+ *****r_hobbit.txt*01[Hobbit]
+ *****tome_faq.txt*12[Homes]
+ *****r_human.txt*01[Human]
+~~~~~73
+*****/Iindex.txt*73[I]
+ *****tome_faq.txt*35[I STILL keep dying]
+ *****tome_faq.txt*31[I keep dying]
+ *****dungeon.txt*04[Identifying features]
+ *****birth.txt*66[Infra-vision]
+ *****birth.txt*35[Intelligence]
+ *****birth.txt*85[Inventory - starting info]
+ *****tome_faq.txt*32[Invisible character]
+~~~~~75
+*****/Kindex.txt*75[K]
+ *****macrofaq.txt*44[Keymaps]
+ *****macrofaq.txt*46[Macro recorder]
+
+~~~~~76
+*****/Lindex.txt*76[L]
+ *****dungeon.txt*23[Light]
+ *****dungeon.txt*17[Loading old characters]
+ *****c_lorema.txt*01[Loremaster]
+ *****rm_lsoul.txt*01[Lost Soul]
+ *****luckspoi.txt*01[Luck ]
+~~~~~77
+*****/Mindex.txt*77[M]
+ *****macrofaq.txt*43[Macros]
+ *****macrofaq.txt*45[Macro recorder]
+ *****c_mage.txt*01[Mage]
+ *****magic.txt*03[Magic]
+ *****m_air.txt*01[Air School]
+ *****m_convey.txt*01[Conveyance School]
+ *****m_demono.txt*01[Demonology School]
+ *****m_divin.txt*01[Divination School]
+ *****m_earth.txt*01[Earth School]
+ *****m_fire.txt*01[Fire School]
+ *****m_geoman.txt*01[Geomancy]
+ *****magic.hlp*01[Index]
+ *****birth.txt*27[Mana]
+ *****m_mana.txt*01[Mana School]
+ *****m_meta.txt*01[Meta School]
+ *****m_mimic.txt*01[Mimicry]
+ *****m_mind.txt*01[Mind School]
+ *****m_mindcr.txt*01[Mindcraft]
+ *****m_music.txt*01[Music]
+ *****m_nature.txt*01[Nature School]
+ *****m_necrom.txt*01[Necromancy]
+ *****magic.txt*01[Schools]
+ *****m_symbio.txt*01[Symbiosis]
+ *****m_tempo.txt*01[Temporal School]
+ *****m_thaum.txt*01[Thaumaturgy]
+ *****m_udun.txt*01[Udun School]
+ *****magic.txt*04[Wands and Staves]
+ *****m_water.txt*01[Water School]
+ *****birth.txt*58[Magical Devices]
+ *****r_maia.txt*01[Maia]
+ *****help.hlp*02[Main Menu]
+ *****m_mana.txt*02[Mana Magic]
+ *****g_mandos.txt*02[Mandos]
+ *****g_manwe.txt*02[Manwe]
+ *****g_manwe.txt*03[Prayers]
+ *****c_pr_man.txt*03[Priest - Manwe]
+ *****tome_faq.txt*14[Mathilde]
+ *****g_melkor.txt*01[Melkor]
+ *****c_pr_drk.txt*03[Dark Priests]
+ *****g_melkor.txt*03[Prayers]
+ *****c_mercen.txt*02[Mercenary]
+ *****m_meta.txt*02[Meta Magic]
+ *****c_mimic.txt*01[Mimic]
+ *****m_mimic.txt*02[Mimicry powers]
+ *****m_mind.txt*02[Mind Magic]
+ *****c_mindcr.txt*01[Mindcrafter]
+ *****m_mindcr.txt*02[Mindcraft powers]
+ *****dungeon.txt*13[Mining]
+ *****birth.txt*18[Money]
+ *****c_monk.txt*01[Monk]
+ *****c_monk.txt*03[Monk attacks]
+ *****dungeon.txt*05[Monsters]
+ *****attack.txt*02[Attacking]
+ *****attack.txt*07[Monster Memory]
+ *****dungeon.txt*20[Pets]
+ *****tome_faq.txt*08[They are talking to me]
+ *****m_music.txt*02[Music]
+~~~~~78
+*****/Nindex.txt*78[N]
+ *****m_nature.txt*02[Nature Magic]
+ *****c_necro.txt*01[Necromancer]
+ *****m_necrom.txt*02[Necromancy Magic]
+~~~~~79
+*****/Oindex.txt*79[O]
+ *****dungeon.txt*14[Objectives]
+ *****dungeon.txt*08[Objects]
+ *****dungeon.txt*21[Colour of inventory slot letter]
+ *****dungeon.txt*09[Cursed Objects]
+ *****tome_faq.txt*33[Piles]
+ *****option.txt*05[Options]
+ *****option.txt*16[Automatizer]
+ *****option.txt*15[Autosave]
+ *****option.txt*13[Base Delay Factor]
+ *****option.txt*18[Cheating]
+ *****option.txt*09[Disturbance]
+ *****option.txt*19[Dump]
+ *****option.txt*11[Efficiency]
+ *****option.txt*10[Game-play]
+ *****option.txt*14[Hitpoint Warning]
+ *****option.txt*07[Ingame]
+ *****option.txt*08[Interface]
+ *****option.txt*06[Startup]
+ *****option.txt*12[ToME Options]
+ *****option.txt*17[Window Flags]
+ *****r_orc.txt*01[Orc]
+~~~~~80
+*****/Pindex.txt*80[P]
+ *****c_pacif.txt*02[Pacifist]
+ *****c_palad.txt*01[Paladin]
+ *****c_peacemag.txt*02[Peace-mage]
+ *****birth.txt*62[Perception]
+ *****dungeon.txt*18[Pets]
+ *****r_pettyd.txt*01[Petty Dwarf]
+ *****c_polear.txt*01[Polearmmaster]
+ *****c_posses.txt*01[Possessor]
+ *****c_posses.txt*03[Possessor powers ]
+ *****command.txt*105[Pref files]
+ *****command.txt*109[Colors]
+ *****command.txt*127[Commands]
+ *****command.txt*107[Keymaps]
+ *****command.txt*106[Macros]
+ *****command.txt*110[Options]
+ *****command.txt*108[Visuals]
+ *****c_pr_eru.txt*01[Priest - Eru]
+ *****c_pr_mandos.txt*0[Priest(Mandos)]
+ *****c_pr_man.txt*01[Priest - Manwe]
+ *****c_pr_ulmo.txt*0[Priest(Ulmo)]
+ *****c_pr_varda.txt*0[Priest(Varda)]
+ *****c_priest.txt*01[Priests]
+~~~~~82
+*****/Rindex.txt*82[R]
+ *****birth.txt*04[Race Modifiers]
+ *****birth.txt*79[Ability table]
+ *****rm_barb.txt*02[Barbarian]
+ *****rm_class.txt*02[Classical]
+ *****rm_herm.txt*02[Hermit]
+ *****rm_lsoul.txt*02[Lost Soul]
+ *****rm_skel.txt*02[Skeleton]
+ *****rm_spec.txt*02[Spectre]
+ *****birth.txt*76[Stat Bonuses]
+ *****rm_vamp.txt*02[Vampire]
+ *****rm_zomb.txt*02[Zombie]
+ *****birth.txt*03[Races]
+ *****birth.txt*78[Ability table]
+ *****r_beorn.txt*02[Beorning]
+ *****birth.txt*67[Combinations with class]
+ *****r_drkelf.txt*02[Dark Elf]
+ *****r_demon.txt*02[Demon]
+ *****r_dragon.txt*02[Dragon]
+ *****r_dunad.txt*02[Dunadan]
+ *****r_dwarf.txt*02[Dwarf]
+ *****r_eagle.txt*02[Eagle]
+ *****r_easterl.txt*02[Easterling]
+ *****r_elf.txt*02[Elf]
+ *****r_ent.txt*02[Ent]
+ *****r_gnome.txt*02[Gnome]
+ *****r_hafelf.txt*02[Half-Elf]
+ *****r_hafogr.txt*02[Half-Ogre]
+ *****r_hielf.txt*02[High-Elf]
+ *****r_hobbit.txt*02[Hobbit]
+ *****r_human.txt*02[Human]
+ *****r_druadan.txt*02[Druadan]
+ *****r_maia.txt*02[Maia]
+ *****r_orc.txt*02[Orc]
+ *****r_pettyd.txt*02[Petty Dwarf]
+ *****r_rohank.txt*02[RohanKnight]
+ *****birth.txt*75[Stat Bonuses]
+ *****r_troll.txt*02[Troll]
+ *****r_wodelf.txt*02[Wood Elf]
+ *****r_yeek.txt*02[Yeek]
+ *****tome_faq.txt*26[Random quests are not working]
+ *****tome_faq.txt*36[Random quests strategy]
+ *****c_ranger.txt*01[Ranger]
+ *****c_rogue.txt*01[Rogue]
+ *****r_rohank.txt*01[RohanKnight]
+ *****c_runecr.txt*01[Runecrafter]
+ *****c_runecr.txt*03[Runecrafter powers]
+ *****tome_faq.txt*11[Runes]
+~~~~~83
+*****/Sindex.txt*83[S]
+ *****command.txt*125[Saving and Exiting]
+ *****birth.txt*52[Saving throw]
+ *****birth.txt*60[Searching]
+ *****birth.txt*63[Searching Ability]
+ *****birth.txt*61[Searching Frequency - Perception]
+ *****spoil_faq.txt*23[Secret Valley]
+ *****tome_faq.txt*09[Sentient weapons]
+ *****rm_skel.txt*01[Skeleton]
+ *****skills.txt*55[Skills]
+ *****skills.txt*27[Air]
+ *****m_air.txt*03[Air - Spell Info]
+ *****skills.txt*50[Antimagic]
+ *****c_unbel.txt*05[Antimagic powers]
+ *****skills.txt*08[Archery]
+ *****skills.txt*05[Axe-mastery]
+ *****skills.txt*18[Backstab]
+ *****skills.txt*13[Barehand-combat]
+ *****skills.txt*61[Bearform-combat]
+ *****skills.txt*12[Boomerang-mastery]
+ *****skills.txt*58[Boulder-throwing]
+ *****skills.txt*10[Bow-mastery]
+ *****skills.txt*01[Combat]
+ *****skills.txt*30[Conveyance]
+ *****m_convey.txt*03[Conveyance - Spell Info]
+ *****skills.txt*44[Corpse-preservation]
+ *****skills.txt*04[Critical-Hits]
+ *****skills.txt*11[Crossbow-mastery]
+ *****skills.txt*52[Demonology]
+ *****m_demono.txt*03[Demonology - Spell Info]
+ *****skills.txt*16[Disarming]
+ *****skills.txt*31[Divination]
+ *****m_divin.txt*03[Divination - Spell Info]
+ *****skills.txt*20[Dodging]
+ *****skills.txt*28[Earth]
+ *****m_earth.txt*03[Earth - Spell Info]
+ *****skills.txt*25[Fire]
+ *****m_fire.txt*03[Fire - Spell Info]
+ *****skills.txt*60[Geomancy]
+ *****m_geoman.txt*03[Geomancy - Spell Info]
+ *****skills.txt*06[Hafted-mastery]
+ *****skills.txt*57[List of skills]
+ *****skills.txt*21[Magic]
+ *****skills.txt*54[Magic-device]
+ *****skills.txt*24[Mana]
+ *****m_mana.txt*03[Mana - Spell Info]
+ *****skills.txt*29[Meta]
+ *****m_meta.txt*03[Meta - Spell Info]
+ *****skills.txt*47[Mimicry]
+ *****m_mimic.txt*03[Mimicry - mimicry powers]
+ *****skills.txt*33[Mind]
+ *****m_mind.txt*03[Mind - Spell Info]
+ *****skills.txt*41[Mindcraft]
+ *****m_mindcr.txt*03[Mindcraft - Spell Info]
+ *****skills.txt*42[Monster-lore]
+ *****skills.txt*59[Music]
+ *****m_music.txt*03[Music - Song Info]
+ *****skills.txt*34[Nature]
+ *****m_nature.txt*03[Nature - Spell Info]
+ *****skills.txt*35[Necromancy]
+ *****m_necrom.txt*03[Necromancy - Spell Info]
+ *****skills.txt*07[Polearm-mastery]
+ *****skills.txt*45[Possession]
+ *****c_posses.txt*04[Possession - Possessor powers ]
+ *****skills.txt*39[Prayer]
+ *****skills.txt*36[Runecraft]
+ *****c_runecr.txt*04[Runecrafting - Runecrafter powers]
+ *****skills.txt*56[Screen]
+ *****skills.txt*09[Sling-mastery]
+ *****skills.txt*14[Sneakiness]
+ *****skills.txt*23[Sorcery]
+ *****skills.txt*22[Spell-power]
+ *****skills.txt*38[Spirituality]
+ *****skills.txt*19[Stealing]
+ *****skills.txt*15[Stealth]
+ *****skills.txt*53[Stunning-blows]
+ *****skills.txt*43[Summoning]
+ *****c_summon.txt*04[Summoning - Summoning powers]
+ *****skills.txt*03[Sword-mastery]
+ *****skills.txt*46[Symbiosis]
+ *****m_symbio.txt*03[Symbiosis - Symbiotic Powers]
+ *****skills.txt*32[Temporal]
+ *****m_tempo.txt*03[Temporal - Spell Info]
+ *****skills.txt*37[Thaumaturgy]
+ *****m_thaum.txt*03[Thaumaturgy - Spell Info]
+ *****skills.txt*48[Udun]
+ *****m_udun.txt*03[Udun - Spell Info]
+ *****skills.txt*26[Water]
+ *****m_water.txt*03[Water - Spell Info]
+ *****skills.txt*02[Weaponmastery]
+ *****c_sniper.txt*02[Sniper]
+ *****c_sorcer.txt*01[Sorceror]
+ *****rm_spec.txt*01[Spectre]
+ *****spoiler.hlp*01[Spoilers]
+ *****corspoil.txt*02[Corruptions]
+ *****dunspoil.txt*02[Dungeons]
+ *****fatespoi.txt*01[Fates]
+ *****inscrip.txt*02[Floor Inscriptions]
+ *****spoil_faq.txt*20[God Quest - directions]
+ *****spoil_faq.txt*22[God Quest - how many]
+ *****spoil_faq.txt*21[God Quest - relic]
+ *****spoil_faq.txt*07[Lothlorien Poisoned water quest]
+ *****luckspoi.txt*02[Luck]
+ *****wishing.txt*01[Wishing]
+ *****birth.txt*82[Stats]
+ *****birth.txt*71[Bonus table]
+ *****birth.txt*44[Charisma]
+ *****birth.txt*42[Constitution]
+ *****birth.txt*40[Dexterity]
+ *****birth.txt*14[Display]
+ *****birth.txt*06[Individual explanations]
+ *****birth.txt*33[Intelligence]
+ *****birth.txt*32[Strength]
+ *****birth.txt*36[Wisdom]
+ *****magic.txt*05[Staves]
+ *****birth.txt*54[Stealth]
+ *****c_stonewr.txt*0[Stonewright]
+ *****tome_faq.txt*17[Strange items]
+ *****birth.txt*34[Strength]
+ *****c_summon.txt*01[Summoners]
+ *****c_summon.txt*03[Summoning]
+ *****defines.txt*12[Svals]
+ *****c_swordm.txt*01[Swordmasters]
+ *****c_symbia.txt*01[Symbiant]
+ *****c_symbia.txt*03[Naming your symbiote]
+ *****m_symbio.txt*02[Symbiosis Magic]
+ *****dungeon.txt*03[Symbols]
+~~~~~84
+*****/Tindex.txt*84[T]
+ *****birth.txt*69[Tables]
+ *****birth.txt*74[Ability Tables]
+ *****birth.txt*70[Combinations of Race and Class]
+ *****c_monk.txt*04[Monk attacks]
+ *****birth.txt*72[Stat bonuses]
+ *****m_tempo.txt*02[Temporal Magic]
+ *****m_thaum.txt*02[Thaumaturgical Magic]
+ *****c_thaum.txt*01[Thaumaturgist]
+ *****whattome.txt*01[ToME - a General Description]
+ *****dungeon.txt*07[Town]
+ *****c_trapper.txt*02[Trapper]
+ *****r_troll.txt*01[Troll]
+ *****g_tulkas.txt*01[Tulkas]
+ *****c_palad.txt*03[Paladin]
+ *****g_tulkas.txt*03[Prayers]
+ *****defines.txt*83[Tvals]
+~~~~~85
+*****/Uindex.txt*85[U]
+ *****m_udun.txt*02[Udun Magic]
+ *****g_ulmo.txt*02[Ulmo]
+ *****c_unbel.txt*01[Unbeliever]
+ *****c_unbel.txt*03[Antimagic]
+~~~~~86
+*****/Vindex.txt*86[V]
+ *****rm_vamp.txt*01[Vampire]
+ *****g_varda.txt*02[Varda]
+ *****tome_faq.txt*16[Void jumpgates]
+ *****dungeon.txt*23[Void jumpgates]
+~~~~~87
+*****/Windex.txt*87[W]
+ *****magic.txt*02[Wands]
+ *****c_wainrid.txt*02[Wainrider]
+ *****c_warper.txt*01[Warper]
+ *****c_warrio.txt*01[Warrior]
+ *****m_water.txt*02[Water Magic]
+ *****birth.txt*86[Weapons - starting info]
+ *****tome_faq.txt*27[Weird display]
+ *****dungeon.txt*1[Wilderness]
+ *****birth.txt*38[Wisdom]
+ *****r_wodelf.txt*01[Wood Elf]
+ *****tome_faq.txt*15[Wrists hurting]
+~~~~~89
+*****/Yindex.txt*89[Y]
+ *****g_yavann.txt*01[Yavanna]
+ *****c_druid.txt*03[Druid]
+ *****g_yavann.txt*03[Prayers]
+ *****r_yeek.txt*01[Yeek]
+~~~~~90
+*****/Zindex.txt*90[Z]
+ *****rm_zomb.txt*01[Zombie]
diff --git a/lib/mods/theme/help/inscrip.txt b/lib/mods/theme/help/inscrip.txt
new file mode 100644
index 00000000..517c81c2
--- /dev/null
+++ b/lib/mods/theme/help/inscrip.txt
@@ -0,0 +1,65 @@
+~~~~~01|Floor Inscriptions (spoiler)
+~~~~~02|Spoilers|Floor Inscriptions
+#####R=== Floor Inscriptions ===
+
+It is possible to inscribe words on the floor in ToME. If you happen
+to be lucky and inscribe a spell formula from another language, the inscription
+will use the floor's mana to cast that spell when either you walk over it, a
+monster walks over it, or both walk over it. Not all inscriptions are triggered
+by monsters, and not all can be triggered by the player.
+
+In order to write an inscription in another language, you must first have found
+and read a parchment with some of that language's words upon it. So, just
+copying the inscriptions here won't work unless you have read the words on a
+parchment first ;-).
+
+#####GLight up the Room
+Inscription: 'ure nimir' (sun shine)
+Parchment: Numenorean for Beginners (I)
+Triggered by: Player, Monster.
+Grid Mana Needed: 30
+Effect: Lights up the current room
+
+#####GDarkness in Room
+Inscription: 'lomi gimli' (night stars)
+Parchment: Numenorean for Beginners (II)
+Triggered by: Player, Monster.
+Grid Mana Needed: 10
+Effect: Casts the room into darkness
+
+#####GStorm
+Inscription: 'dulgi bawiba' (black winds)
+Parchment: Advanced Lessons of Numenorean
+Triggered by: Player, Monster.
+Grid Mana Needed: 40
+Effect: Electrical Ball of energy released around the inscription
+
+#####GProtection
+Inscription: 'pedo mellon a minno' (say friend and enter)
+Parchment: Advanced Lessons of Sindarin
+Triggered by: Monster.
+Grid Mana Needed: 8
+Effect: Prevents a monster from stepping on the affected square
+
+#####GDwarven summoning
+Inscription: 'Baruk Khazad! Khazad aimenu!' (Axes of the Dwarves, the Dwarves
+ are upon you!)
+Parchment: Khuzdul - The Hidden Tongue of the Dwarves
+Triggered by: Player.
+Grid Mana Needed: 100
+Effect: Generates friendly Dwarven Warriors to help your cause
+
+#####GOpen Chasm
+Inscription: 'dunna hrassa' (black precipice)
+Parchment: Nandorin for Dummies
+Triggered by: Monster.
+Grid Mana Needed: 50
+Effect: Creates a bottomless hole in the floor that monsters (and potentially
+ objects) fall down
+
+#####GBlast of Black Fire
+Inscription: 'burz ghash ronk' (black fire pool)
+Parchment: Advanced Lessons of Orcish
+Triggered by: Player, Monster.
+Grid Mana Needed: 60
+Effect: Releases a ball of Hellfire around the inscription
diff --git a/lib/mods/theme/help/lua.hlp b/lib/mods/theme/help/lua.hlp
new file mode 100644
index 00000000..ba61676a
--- /dev/null
+++ b/lib/mods/theme/help/lua.hlp
@@ -0,0 +1,34 @@
+|||||oy
+~~~~~01|Help|Lua scripting for ToME
+#####R Welcome to the ToME Lua Help System.
+#####R=============================================
+
+Please choose one of the following help files:
+
+ *****/alua_intr.txt*0[(a) An Introduction to scripting]
+ *****/blua_pow.txt*0[(b) Adding a racial power (the 'U' menu)]
+ *****/clua_skil.txt*0[(c) Adding new skills (the 'm' menu)]
+ *****/dlua_ques.txt*0[(d) Adding a quest]
+
+
+ *****/elua_mon.txt*0[(e) Useful functions in monster.pkg]
+ *****/flua_play.txt*0[(f) Useful functions in player.pkg]
+ *****/glua_spel.txt*0[(g) Useful functions in spell.pkg]
+ *****/hlua_util.txt*0[(h) Useful functions in util.pkg]
+
+ *****/ilua_gf.txt*0[(g) A list of GF_FOO flags]
+
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/mods/theme/help/lua_gf.txt b/lib/mods/theme/help/lua_gf.txt
new file mode 100644
index 00000000..000f4af5
--- /dev/null
+++ b/lib/mods/theme/help/lua_gf.txt
@@ -0,0 +1,45 @@
+|||||oy
+#####R /--------------------------\
+#####R< A partial list of GF_FLAGS >
+#####R \--------------------------/
+
+GF_ARROW: arrows
+GF_MISSILE: magic missiles
+GF_MANA: mana
+GF_LITE_WEAK: light
+GF_DARK_WEAK: dark
+GF_WATER: water
+GF_PLASMA: plasma
+GF_METEOR: meteors
+GF_ICE: ice
+GF_GRAVITY: gravity
+GF_INERTIA: inertia
+GF_FORCE: force
+GF_TIME: pure time
+GF_ACID: acid
+GF_ELEC: lightning
+GF_FIRE: flames
+GF_COLD: cold
+GF_POIS: poison
+GF_LITE: pure light
+GF_DARK: pure dark
+GF_CONFUSION: confusion
+GF_SOUND: sound
+GF_SHARDS: shards
+GF_NEXUS: nexus
+GF_NETHER: nether
+GF_CHAOS: chaos
+GF_DISENCHANT: disenchantment
+GF_KILL_WALL: wall destruction
+GF_KILL_DOOR: door destruction
+GF_KILL_TRAP: trap destruction
+GF_STONE_WALL: wall creation
+GF_MAKE_DOOR: door creation
+GF_MAKE_TRAP: trap creation
+GF_DESTRUCTION: destruction
+
+Back to the *****lua.hlp*0[lua help index] .
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
+
+
diff --git a/lib/mods/theme/help/lua_intr.txt b/lib/mods/theme/help/lua_intr.txt
new file mode 100644
index 00000000..ccb87067
--- /dev/null
+++ b/lib/mods/theme/help/lua_intr.txt
@@ -0,0 +1,133 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Scripting for ToME with lua >
+#####R \----------------------------------------/
+
+So, you want to patch ToME eh? Maybe you've had a look at how the edit files
+work, maybe even added your own race/class, but want to go further and add
+new racial (U) or magic (m) powers. Well these help files will show a little
+bit of how to do that.
+
+I am not a master at this kind of thing. I wrote a small script, with much
+help from DarkGod, and he subsequently asked me to write these help files. I
+was looking forward to when the lua help files came out so that I could look
+at them myself. Little did I know I'd be asked to write them. Therefore I
+apologise for any inaccuracies or errors that you find, and if you care to let
+me know of any improvements which could be made (especially if you're an
+experienced programmer/scripter), I'd love to know. Email me at
+[[[[[gfearoffours@moppy.co.uk].
+
+#####R=== The example scripts ===
+
+These help files take the form of a tutorial, adding a line at a time to a
+script, and explaining important concepts along the way. To see it all in
+action, I strongly suggest that you download my example script pack from
+[[[[[Ghttp://www.moppy.co.uk/angband.htm]. As well as including all the
+scripts covered in these help files, they also include the addition of my
+"hina" race which has a Lua scripted racial power which you might like to look
+at. There's also a quest which I will be including documentation for as a
+tutorial soon. Plus there's all the other lua scripts in the lib\scpt
+directory to look at. Most of what you see in these files has been learned from
+those files anyway!
+
+The source code is invaluable as well. There's a searchable and browsable
+version of the latest ToME source code available online at
+[[[[[Ghttp://www.t-o-m-e.net/cvs.php]. Use it!
+
+If you don't want to download and install the example scripts, then just
+follow the tutorials with a text editor open! But I'll say it again, it's a lot
+easier if you download and install the example scripts.
+
+This file goes on to explain the concepts of scripting, programming,
+variables and functions. If you're familiar with these concepts, you might
+as well take a look at how to add a power to the U menu in the
+*****lua_pow.txt*0[Scripting a racial power] file.
+
+
+#####R=== Defining some basic stuff ===
+
+Computers don't do anything that they're not told to do. When we script, or
+program, we must assume they know nothing. We have to tell them each little
+bit of information from the ground up.
+
+A program, or a script (we'll talk about exact differences later) is like a
+set of instructions. Let's imagine that people responded to programs, and
+that we had a program called "Housework". Its series of instructions might
+look something like this:
+
+#####BDo the Washing up.
+#####BClean the kitchen.
+#####BDust the shelves.
+#####BHoover the lounge.
+
+Each step above could be called a function, as they are all actions that
+need to be carried out. Now to you and me, we'd understand that program just
+fine, but if someone didn't know HOW to wash, or what hoovering was, they'd
+soon run into problems. For those people we'd need to define each function
+clearly. Thus "do the washing up" might be -
+
+#####BRun hot water into bowl.
+#####BAdd washing up liquid.
+#####BPut dirty plates into bowl
+#####BScrub plates till clean
+#####BPlace clean plates on rack to dry,
+
+There's still plenty of problems here though. We've not said to turn the tap
+off, or what the bowl is, or to wash any dirty cutlery, mugs, saucepans, etc.,
+etc. Whilst this might seem fairly obvious to a person, this is how we need
+to think when writing programs for computers.
+
+Lets look now at some of the terms we're going to be using, in the rest of
+these help files, and what they mean...
+
+#####R=== Variables and Constants ===
+A variable is a way to store information in a computer. Just as you store
+things in your own memory, you can store things in the computer's memory. And
+just as things change in your memory, so things can change in the computer's
+memory. This factor of change is why they're called "variables" and not
+"statics".
+
+For instance, you may have a friend's email address committed to memory, but
+things change over time, they get a new ISP or domain, and so their email
+address changes. You commit this new address to memory, and eventually
+forget the old one. The thing you have stored in your memory is the same
+(your friend's address) but the value (property) of what you have stored has
+changed (from friend@old-address.com to friend@new-address.com).
+
+Variables are the building blocks out of which you will create your patch.
+
+A variable which will *never* change its value is called a constant.
+
+#####R===Functions===
+
+A function is a series of steps or statements, grouped together and given
+one name. When you want to carry out those steps, you simply ask the
+computer to carry out that function. To go back to our original example,
+rather than saying, "I'd like you to run some hot water into a bowl, add the
+washing up liquid, put the dirty plates into it, and then scrub them till
+they're clean", we just say "do the washing up".
+
+This is where we come to the difference between scripting and programming.
+With scripting we can use the functions and variables that exist in the
+ToME code. Maintainers like DarkGod have already made sure that the
+computer knows how to "do the washing up", including turning the tap off and
+what the bowl is. All we need to do in our script is say "do the washing
+up". Or to look at it in a more relevant way, the game has been coded so
+that when a magic missile is fired, a bolt or beam spell with a black line
+of asterisks will be drawn in the direction indicated by the player, the
+mana of that spell will be used up, the monster will take the appropriate
+amount of damage, and so on. All we need to do in our script is say "fire a
+magic missile".
+
+As you script, you will still be designing your own functions, and
+variables, but the hardest parts have been done for you!
+
+Not every function and global variable in the source-code has been exported to
+use in your scripting. But the ones that have are easily identifiable by
+looking in any source files with the extension .pkg . Chris Hadgis has written
+some excellent documentation which outline the use of the most important
+functions in some of these files. They outline the functions from the
+
+OK, the first tutorial proper is on *****lua_pow.txt*0[adding a racial power] .
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
diff --git a/lib/mods/theme/help/lua_mon.txt b/lib/mods/theme/help/lua_mon.txt
new file mode 100644
index 00000000..9bb363c0
--- /dev/null
+++ b/lib/mods/theme/help/lua_mon.txt
@@ -0,0 +1,535 @@
+|||||oy
+
+#####R /----------------------------------------\
+#####R < monster.pkg functions helper file >
+#####R \----------------------------------------/
+
+
+----------------------------------------------------------------------
+
+#####R=== race_info_idx ===
+
+#####GDeclaration
+ extern monster_race* race_info_idx(int r_idx, int ego);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Return a (monster_race*) with the combinations of the monster
+ * properties and the ego type
+ */
+
+#####GDescription
+Get monster info and ego info for monster with monster index "r_idx"
+and monster ego "ego". The ego information is applied to the monster
+information and the new monster information is returned.
+
+For example, race_info_idx(141,7) will create a brown yeek (monster)
+shaman (ego).
+
+#####GParameters
+> "r_idx" is an entry from the "r_info.txt" file. Beware: there is no
+ range checking.
+> "ego" is an entry from the "re_info.txt". Beware: there is no range
+ checking.
+
+----------------------------------------------------------------------
+
+#####R=== delete_monster_idx ===
+
+#####GDeclaration
+ extern void delete_monster_idx(int i);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Delete a monster by index.
+ *
+ * When a monster is deleted, all of its objects are deleted.
+ */
+
+#####GDescription
+Delete monster "i" from the monster array.
+
+#####GParameters
+> "i" is the index for the monster list (m_list[]). Beware: there is
+ no range checking.
+
+----------------------------------------------------------------------
+
+#####R=== m_pop ===
+
+#####GDeclaration
+ extern s16b m_pop(void);
+
+#####GFile
+ monsters2.c
+
+#####GComment
+/*
+ * Acquires and returns the index of a "free" monster.
+ *
+ * This routine should almost never fail, but it *can* happen.
+ */
+
+#####GDescription
+Get an empty slot in the monster list (m_list[]). If there are no
+empty slots, a slot will be reclaimed from a "dead" monster. If all
+slots are full, 0 is returned, which means the function has failed
+("Too many monsters!").
+
+----------------------------------------------------------------------
+
+#####R=== get_mon_num_prep ===
+
+#####GDeclaration
+ extern errr get_mon_num_prep(void);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Apply a "monster restriction function" to the "monster allocation table"
+ */
+
+#####GDescription
+There are no parameters, but there are some other variables which will
+need to be set. They are get_mon_num_hook and get_mon_num2_hook. They
+are pointers to functions.
+
+For example, get_mon_num_hook = monster_volcano means when
+get_mon_num_hook is called (*get_mon_num_hook)(index), the actual
+function called is monster_volcano(index). This particular function
+returns TRUE if the monster indicated by "index" has the
+RF8_WILD_VOLCANO flag set.
+
+It is a good idea to store the old value of get_mon_num_hook before
+setting a new one, and restoring it when your function is finished.
+
+Following is a list of functions which can be assigned to
+get_mon_num_hook:
+
+create_molds_hook
+create_townpeople_hook
+mon_hook_bounty
+monster_dungeon
+monster_grass
+monster_mountain
+monster_ocean
+monster_quest
+monster_shore
+monster_town
+monster_volcano
+monster_waste
+monster_wood
+mutate_monster_okay
+place_monster_okay
+summon_specific_okay
+vault_aux_animal
+vault_aux_chapel
+vault_aux_clone
+vault_aux_demon
+vault_aux_dragon
+vault_aux_giant
+vault_aux_jelly
+vault_aux_kennel
+vault_aux_orc
+vault_aux_symbol
+vault_aux_treasure
+vault_aux_troll
+vault_aux_undead
+
+Or you can write your own. The function must take an integer (index)
+as a parameter and return boolean (TRUE if the monster is selected,
+or FALSE if it is not).
+
+----------------------------------------------------------------------
+
+#####R=== get_mon_num ===
+
+#####GDeclaration
+ extern s16b get_mon_num(int level);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Choose a monster race that seems "appropriate" to the given level
+ *
+ * This function uses the "prob2" field of the "monster allocation table",
+ * and various local information, to calculate the "prob3" field of the
+ * same table, which is then used to choose an "appropriate" monster, in
+ * a relatively efficient manner.
+ *
+ * Note that "town" monsters will *only* be created in the town, and
+ * "normal" monsters will *never* be created in the town, unless the
+ * "level" is "modified", for example, by polymorph or summoning.
+ *
+ * There is a small chance (1/50) of "boosting" the given depth by
+ * a small amount (up to four levels), except in the town.
+ *
+ * It is (slightly) more likely to acquire a monster of the given level
+ * than one of a lower level. This is done by choosing several monsters
+ * appropriate to the given level and keeping the "hardest" one.
+ *
+ * Note that if no monsters are "appropriate", then this function will
+ * fail, and return zero, but this should *almost* never happen.
+ */
+
+Description:
+For the given level "level", return the index of an appropriate
+monster race.
+
+#####GParameters
+> "level" is a dungeon level
+
+----------------------------------------------------------------------
+
+#####R=== monster_desc ===
+
+#####GDeclaration
+ extern void monster_desc(char *desc, monster_type *m_ptr,
+ int mode);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Build a string describing a monster in some way.
+ *
+ * We can correctly describe monsters based on their visibility.
+ * We can force all monsters to be treated as visible or invisible.
+ * We can build nominatives, objectives, possessives, or reflexives.
+ * We can selectively pronominalize hidden, visible, or all monsters.
+ * We can use definite or indefinite descriptions for hidden monsters.
+ * We can use definite or indefinite descriptions for visible monsters.
+ *
+ * Pronominalization involves the gender whenever possible and allowed,
+ * so that by cleverly requesting pronominalization / visibility, you
+ * can get messages like "You hit someone. She screams in agony!".
+ *
+ * Reflexives are acquired by requesting Objective plus Possessive.
+ *
+ * If no m_ptr arg is given (?), the monster is assumed to be hidden,
+ * unless the "Assume Visible" mode is requested.
+ *
+ * If no r_ptr arg is given, it is extracted from m_ptr and r_info
+ * If neither m_ptr nor r_ptr is given, the monster is assumed to
+ * be neuter, singular, and hidden (unless "Assume Visible" is set),
+ * in which case you may be in trouble... :-)
+ *
+ * I am assuming that no monster name is more than 70 characters long,
+ * so that "char desc[80];" is sufficiently large for any result.
+ *
+ * Mode Flags:
+ * 0x01 --> Objective (or Reflexive)
+ * 0x02 --> Possessive (or Reflexive)
+ * 0x04 --> Use indefinites for hidden monsters ("something")
+ * 0x08 --> Use indefinites for visible monsters ("a kobold")
+ * 0x10 --> Pronominalize hidden monsters
+ * 0x20 --> Pronominalize visible monsters
+ * 0x40 --> Assume the monster is hidden
+ * 0x80 --> Assume the monster is visible
+ *
+ * Useful Modes:
+ * 0x00 --> Full nominative name ("the kobold") or "it"
+ * 0x04 --> Full nominative name ("the kobold") or "something"
+ * 0x80 --> Genocide resistance name ("the kobold")
+ * 0x88 --> Killing name ("a kobold")
+ * 0x22 --> Possessive, genderized if visible ("his") or "its"
+ * 0x23 --> Reflexive, genderized if visible ("himself") or "itself"
+ */
+
+#####GDescription
+Return a monster description "desc" for monster "monster_type" using
+flag "mode". The modes are described above.
+
+#####GParameters
+> "desc" is the returned description.
+> "monster type" is the monster (monster pointer).
+> "mode" is one of the modes described in the comments.
+
+----------------------------------------------------------------------
+
+#####R=== monster_race_desc ===
+
+#####GDeclaration
+ extern void monster_race_desc(char *desc, int r_idx,
+ int ego);
+
+#####GFile
+ monster2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the monster description "desc" for monster with monster index
+"r_idx" and monster ego "ego". The monster description is made up of
+the ego name (if any) and monster name, or the unique name.
+
+#####GParameters
+> "desc" is the returned description.
+> "r_idx" is an entry from the "r_info.txt" file. Beware: there is no
+ range checking.
+> "ego" is an entry from the "re_info.txt". Beware: there is no range
+ checking.
+
+----------------------------------------------------------------------
+
+#####R=== place_monster_aux ===
+
+#####GDeclaration
+ extern bool place_monster_aux(int y, int x, int r_idx,
+ bool slp, bool grp, int status);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Attempt to place a monster of the given race at the given location
+ *
+ * Note that certain monsters are now marked as requiring "friends".
+ * These monsters, if successfully placed, and if the "grp" parameter
+ * is TRUE, will be surrounded by a "group" of identical monsters.
+ *
+ * Note that certain monsters are now marked as requiring an "escort",
+ * which is a collection of monsters with similar "race" but lower
+ * level.
+ *
+ * Some monsters induce a fake "group" flag on their escorts.
+ *
+ * Note the "bizarre" use of non-recursion to prevent annoying output
+ * when running a code profiler.
+ *
+ * Note the use of the new "monster allocation table" code to restrict
+ * the "get_mon_num()" function to "legal" escort types.
+ */
+
+#####GDescription
+Attempt to place a monster at grid "y", "x". The monster has monster
+index "m_idx". The monster may be asleep ("slp"). The monster may be
+surrounded by a group of identical monsters ("grp"). The monster has
+a status of "status" (see below). The function returns TRUE if the
+monster is placed successfully, otherwise FALSE.
+
+#####GParameters
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "r_idx" is an entry from the "r_info.txt" file. Beware: there is no
+ range checking.
+> "slp" is TRUE if the monster is asleep, otherwise FALSE.
+> "grp" is TRUE if the monster is surrounded by a group, otherwise
+ FALSE.
+> "status" is the status of the monster
+ *****fields.txt*0[status]
+
+----------------------------------------------------------------------
+
+#####R=== place_monster ===
+
+#####GDeclaration
+ extern bool place_monster(int y, int x, bool slp,
+ bool grp);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Hack -- attempt to place a monster at the given location
+ *
+ * Attempt to find a monster appropriate to the "monster_level"
+ */
+
+#####GDescription
+Attempt to place a monster at grid "y", "x". The monster may be asleep
+("slp"). The monster may be surrounded by a group of identical
+monsters ("grp"). The monster is of the appropriate monster level. The
+function returns TRUE if the monster is placed successfully, otherwise
+FALSE.
+
+#####GParameters
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "slp" is TRUE if the monster is asleep, otherwise FALSE.
+> "grp" is TRUE if the monster is surrounded by a group, otherwise
+ FALSE.
+
+----------------------------------------------------------------------
+
+#####R=== place_monster_one ===
+
+#####GDeclaration
+ extern s16b place_monster_one(int y, int x, int r_idx,
+ int ego, bool slp, int status);
+
+#####GFile
+ monster2.c
+
+#####GComment
+/*
+ * Attempt to place a monster of the given race at the given location.
+ *
+ * To give the player a sporting chance, any monster that appears in
+ * line-of-sight and is extremely dangerous can be marked as
+ * "FORCE_SLEEP", which will cause them to be placed with low energy,
+ * which often (but not always) lets the player move before they do.
+ *
+ * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters.
+ *
+ * XXX XXX XXX Use special "here" and "dead" flags for unique monsters,
+ * remove old "cur_num" and "max_num" fields.
+ *
+ * XXX XXX XXX Actually, do something similar for artifacts, to simplify
+ * the "preserve" mode, and to make the "what artifacts" flag more useful.
+ *
+ * This is the only function which may place a monster in the dungeon,
+ * except for the savefile loading code.
+ */
+
+#####GDescription
+Attempt to place a monster at grid "y", "x". The monster has monster
+index "m_idx". The monster may be asleep ("slp"). The monster may have
+an ego type ("ego"). The monster has a status of "status" (see below).
+The function returns TRUE if the monster is placed successfully,
+otherwise FALSE.
+
+#####GParameters
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "r_idx" is an entry from the "r_info.txt" file. Beware: there is no
+ range checking.
+> "slp" is TRUE if the monster is asleep, otherwise FALSE.
+> "ego" is an entry from the "re_info.txt". Beware: there is no range
+ checking.
+> "status" is the status of the monster
+ *****fields.txt*0[status]
+
+----------------------------------------------------------------------
+
+#####R=== is_friend ===
+
+#####GDeclaration
+ extern int is_friend(monster_type *m_ptr);
+
+#####GFile
+ monster3.c
+
+#####GComment
+/*
+ * Is the monster in friendly state(pet, friend, ..)
+ * -1 = enemy, 0 = neutral, 1 = friend
+ */
+
+#####GDescription
+Return a value to indicate the status of monster "m_ptr".
+ *****fields.txt*0[status]
+
+#####GParameters
+> "m_ptr" is a pointer to a monster.
+
+----------------------------------------------------------------------
+
+#####R=== is_enemy ===
+
+#####GDeclaration
+ extern bool is_enemy(monster_type *m_ptr,
+ monster_type *t_ptr);
+
+#####GFile
+ monster3.c
+
+#####GComment
+/* Should they attack each others */
+
+#####GDescription
+Return TRUE if monster "m_ptr" should attack monster "t_ptr". If
+"m_ptr" is stupid and "r_ptr" is a different type of monster then the
+function will return TRUE. If "m_ptr" is not neutral and "r_ptr" is a
+breeder, and "r_ptr" is a different type of monster then the function
+will return TRUE (and vice versa). If both monsters are not neutral
+and one is friendly and the other isn't then the function will return
+TRUE. Otherwise the function returns FALSE.
+
+#####GParameters
+> "m_ptr" is a pointer to a monster.
+> "t_ptr" is a pointer to a monster (target).
+
+----------------------------------------------------------------------
+
+#####R=== change_side ===
+
+#####GDeclaration
+ extern bool change_side(monster_type *m_ptr);
+
+#####GFile
+ monster3.c
+
+#####GComment
+(none)
+
+#####GDescription
+Change the status of monster "m_ptr" from friendly to unfriendly and
+vice versa. Friends and pets become enemies. Neutral Ms become
+neutral Ps and vice versa. Companions are unaffected. The
+function returns TRUE if the status changed, otherwise FALSE.
+
+#####GParameters
+> "m_ptr" is a pointer to a monster.
+
+----------------------------------------------------------------------
+
+#####R=== find_position ===
+
+#####GDeclaration
+ extern void find_position(int y, int x, int *yy = 0,
+ int *xx = 0);
+
+#####GFile
+ lua_bind.c
+
+#####GComment
+(none)
+
+#####GDescription
+Find a new grid "yy", "xx" within 6 grids of target grid "y", "x".
+The new grid must be within line-of-sight of the target grid. A
+maximum of 5000 attempts is made.
+
+#####GParameters
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "yy" is the y co-ordinate of the new grid.
+> "xx" is the x co-ordinate of the new grid.
+
+----------------------------------------------------------------------
+
+#####R=== can_create_companion ===
+
+#####GDeclaration
+ extern bool can_create_companion();
+
+#####GFile
+ monster3.c
+
+#####GComment
+/* Returns if a new companion is allowed */
+
+#####GDescription
+Return TRUE if a companion can be created, otherwise FALSE.
+
+----------------------------------------------------------------------
+
+Back to the *****lua.hlp*0[lua help index] .
+
+
+ [[[[[gThis file by Chris Hadgis]
diff --git a/lib/mods/theme/help/lua_play.txt b/lib/mods/theme/help/lua_play.txt
new file mode 100644
index 00000000..6ab64ddb
--- /dev/null
+++ b/lib/mods/theme/help/lua_play.txt
@@ -0,0 +1,1225 @@
+|||||oy
+
+#####R /----------------------------------------\
+#####R < player.pkg functions helper file >
+#####R \----------------------------------------/
+
+----------------------------------------------------------------------
+
+#####RFunction: set_parasite
+
+#####GDeclaration: bool set_parasite(int v, int r);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->parasite" and "p_ptr->parasite_r_idx"
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until parasite with monster index "r" is created. The
+player gets the message "You feel something growing in you" if "v"
+is > 0. Otherwise the player gets the message "Your body convulse
+and spawn <monster name>" if the monster is created (80% chance) or
+"The hideous thing growing in you seems to die" if the monster dies.
+
+#####GParameters:
+>v is the time until the parasite gestates (must be between 0 and
+ 10000).
+>r is the monster index of parasite to be created.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_disrupt_shield
+
+#####GDeclaration: bool set_disrupt_shield(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->disrupt_shield"
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until shield of invulnerability expires. The player gets
+the message "You feel invulnerable" if "v" is > 0. Otherwise the
+player gets the message "You are more vulnerable".
+
+#####GParameters:
+>v is the time until the shield expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_prob_travel
+
+#####GDeclaration: bool set_prob_travel(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->prob_travel"
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until random teleportation expires. The player gets
+the message "You feel instable" if "v" is > 0. Otherwise the
+player gets the message "You are more stable".
+
+#####GParameters:
+>v is the time until random teleportation expires (must be between 0
+ and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_deadly
+
+#####GDeclaration: bool set_tim_deadly(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_deadly"
+*/
+
+#####GDescription:
+Set time "v" until deadly accuracy expires. The player gets the
+message "You feel extremely accurate" if "v" is > 0. Otherwise the
+player gets the message "You are suddenly much less accurate".
+
+#####GParameters:
+>v is the time until deadly accuracy expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_res_time
+
+#####GDeclaration: bool set_tim_res_time(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_res_time"
+*/
+
+#####GDescription:
+Set time "v" until space-time distortions expire. The player gets the
+message "You are now protected against the space-time distortions" if
+"v" is > 0. Otherwise the player gets the message "You are no longer
+protected against the space-time distortions".
+
+#####GParameters:
+>v is the time until space-time distortions expire (must be between
+ 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_reflect
+
+#####GDeclaration: bool set_tim_reflect(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_reflect"
+*/
+
+#####GDescription:
+Set time "v" until reflection expire. The player gets the message
+"You start reflecting the world around you" if "v" is > 0. Otherwise
+the player gets the message "You stop reflecting".
+
+#####GParameters:
+>v is the time until reflection expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_meditation
+
+#####GDeclaration: bool set_meditation(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->meditation"
+*/
+
+#####GDescription:
+Set time "v" until meditation expire. The player gets the message
+"You start meditating on yourself" if "v" is > 0. Otherwise the
+player gets the message "You stop your self meditation".
+
+#####GParameters:
+>v is the time until meditation expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_strike
+
+#####GDeclaration: bool set_strike(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->strike"
+*/
+
+#####GDescription:
+Set time "v" until accurate strikes expire. The player gets the
+message "You feel very accurate" if "v" is > 0. Otherwise the player
+gets the message "You are no longer very accurate".
+
+#####GParameters:
+>v is the time until accurate strikes expire (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_walk_water
+
+#####GDeclaration: bool set_walk_water(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->walk_water", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until walking on water expires. The player gets the
+message "You feel strangely insubmersible" if "v" is > 0. Otherwise
+the player gets the message "You are no longer insubmersible".
+
+#####GParameters:
+>v is the time until walking on water expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_ffall
+
+#####GDeclaration: bool set_tim_ffall(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_ffall"
+*/
+
+#####GDescription:
+Set time "v" until feather-fall expires. The player gets the message
+"You feel very light" if "v" is > 0. Otherwise the player gets the
+message "You are suddenly heavier".
+
+#####GParameters:
+>v is the time until feather-fall expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_fire_aura
+
+#####GDeclaration: bool set_tim_fire_aura(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_fire_aura"
+*/
+
+#####GDescription:
+Set time "v" until fiery aura expires. The player gets the message
+"You are enveloped in flames" if "v" is > 0. Otherwise the player
+gets the message "You are no longer enveloped in flames".
+
+#####GParameters:
+>v is the time until fiery aura expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_holy
+
+#####GDeclaration: bool set_holy(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->holy", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until holiness expires. The player gets the message
+"You feel a holy aura around you" if "v" is > 0. Otherwise the
+player gets the message "The holy aura vanishes".
+
+#####GParameters:
+>v is the time until holiness expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_grace
+
+#####GDeclaration: void set_grace(s32b v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->grace", notice observable changes
+*/
+
+#####GDescription:
+Set grace to value "v". Don't allow grace to fall below -30000 or
+rise above 30000.
+
+#####GParameters:
+>v is the value of grace.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_mimic
+
+#####GDeclaration: bool set_mimic(int v, int p);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_mimic", and "p_ptr->mimic_form",
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until morph into monster with monster index "p" expires.
+The player gets the message "You feel your body change" if "v" is > 0.
+Otherwise the player gets the message "You are no longer transformed".
+
+#####GParameters:
+>v is the time until transformation expires (must be between 0 and
+ 10000).
+>p is the monster index of the monster the player wants to mimic.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_no_breeders
+
+#####GDeclaration: bool set_no_breeders(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "no_breeds"
+*/
+
+#####GDescription:
+Set time "v" until breeders can breed again. The player gets the
+message "You feel an anti-sexual aura" if "v" is > 0. Otherwise the
+player gets the message "You no longer feel an anti-sexual aura".
+Okay...
+
+#####GParameters:
+>v is the time until breeders can breed again (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_invis
+
+#####GDeclaration: bool set_invis(int v,int p);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_invis", and "p_ptr->tim_inv_pow",
+* notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until invisibility expires. The player gets the message
+"You feel your body fade away" if "v" is > 0. Otherwise the player
+gets the message "You are no longer invisible".
+
+#####GParameters:
+>v is the time until invisibility expires (must be between 0 and
+ 10000).
+>p is the power of timed invisibility.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_lite
+
+#####GDeclaration: bool set_lite(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_lite", notice observable changes
+*
+* Note the use of "PU_VIEW", which is needed to
+* memorise any terrain features which suddenly become "visible".
+* Note that blindness is currently the only thing which can affect
+* "player_can_see_bold()".
+*/
+
+#####GDescription:
+Set time "v" until brightness expires. The player gets the message
+"You suddenly seem brighter" if "v" is > 0. Otherwise the player
+gets the message "You are no longer bright".
+
+#####GParameters:
+>v is the time until brightness expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_blind
+
+#####GDeclaration: bool set_blind(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->blind", notice observable changes
+*
+* Note the use of "PU_UN_VIEW", which is needed to memorise any terrain
+* features which suddenly become "visible".
+* Note that blindness is currently the only thing which can affect
+* "player_can_see_bold()".
+*/
+
+#####GDescription:
+Set time "v" until blindness expires. The player gets the message "You
+are blind" if "v" is > 0. Otherwise the player gets the message "You
+can see again".
+
+#####GParameters:
+>v is the time until blindness expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_confused
+
+#####GDeclaration: bool set_confused(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->confused", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until confusion expires. The player gets the message "You
+are confused" if "v" is > 0. Otherwise the player gets the message
+"You feel less confused now".
+
+#####GParameters:
+>v is the time until confusion expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_poisoned
+
+#####GDeclaration: bool set_poisoned(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->poisoned", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until poison expires. The player gets the message "You
+are poisoned" if "v" is > 0. Otherwise the player gets the message
+"You are no longer poisoned".
+
+#####GParameters:
+>v is the time until poison expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_afraid
+
+#####GDeclaration: bool set_afraid(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->afraid", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until fear expires. The player gets the message "You are
+terrified" if "v" is > 0. Otherwise the player gets the message "You
+feel bolder now".
+
+#####GParameters:
+>v is the time until fear expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_paralyzed
+
+#####GDeclaration: bool set_paralyzed(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->paralyzed", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until paralysis expires. The player gets the message "You
+are paralyzed" if "v" is > 0. Otherwise the player gets the message
+"You can move again".
+
+#####GParameters:
+>v is the time until paralysis expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_image
+
+#####GDeclaration: bool set_image(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->image", notice observable changes
+*
+* Note that we must redraw the map when hallucination changes.
+*/
+
+#####GDescription:
+Set time "v" until hallucination expires. The player gets the message
+"Oh, wow! Everything looks so cosmic now" if "v" is > 0. Otherwise
+the player gets the message "You can see clearly again".
+
+#####GParameters:
+>v is the time until hallucination expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_fast
+
+#####GDeclaration: bool set_fast(int v, int p);
+
+#####GFile: xtra2.c
+
+#####GComment:
+(none)
+
+#####GDescription:
+Set time "v" until speed of speed factor "p" expires. The player gets
+the message "You feel yourself moving faster" if "v" is > 0. Otherwise
+the player gets the message "You feel yourself slow down".
+
+#####GParameters:
+>v is the time until speed expires (must be between 0 and 10000).
+>p is the speed factor.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_light_speed
+
+#####GDeclaration: bool set_light_speed(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->lightspeed", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until light-speed expires. The player gets the message
+"You feel as if time has stopped" if "v" is > 0. Otherwise the player
+gets the message "You feel time returning to its normal rate".
+
+#####GParameters:
+>v is the time until light-speed expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_slow
+
+#####GDeclaration: bool set_slow(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->slow", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until slowness expires. The player gets the message "You
+feel yourself moving slower" if "v" is > 0. Otherwise the player gets
+the message "You feel yourself speed up".
+
+#####GParameters:
+>v is the time until slowness expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_shield
+
+#####GDeclaration: bool set_shield(int v, int p, s16b o, s16b d1, s16b d2);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->shield", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until stone-shield expires. The player gets the message
+"Your skin turns to stone" if "v" is > 0. Otherwise the player gets
+the message "Your skin returns to normal". Stone-shield has spell
+power "p", spell option "o", and power options "d1" and "d2".
+
+#####GParameters:
+>v is the time until stone-shield expires (must be between 0 and
+ 10000).
+>p is the power of the stone-shield spell.
+>o is the option of the stone-shield spell.
+>d1 is the power for option 1 of the stone-shield spell.
+>d2 is the power for option 2 of the stone-shield spell.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_blessed
+
+#####GDeclaration: bool set_blessed(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->blessed", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until blessing expires. The player gets the message "You
+feel righteous" if "v" is > 0. Otherwise the player gets the message
+"The prayer has expired".
+
+#####GParameters:
+>v is the time until blessing expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_hero
+
+#####GDeclaration: bool set_hero(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->hero", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until heroism expires. The player gets the message "You
+feel like a hero" if "v" is > 0. Otherwise the player gets the
+message "The heroism wears off".
+
+#####GParameters:
+>v is the time until heroism expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_shero
+
+#####GDeclaration: bool set_shero(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->shero", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until berserk expires. The player gets the message "You
+feel like a killing machine" if "v" is > 0. Otherwise the player gets
+the message "You feel less Berserk".
+
+#####GParameters:
+>v is the time until berserk expires (must be between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_protevil
+
+#####GDeclaration: bool set_protevil(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->protevil", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until protection from evil expires. The player gets the
+message "You feel safe from evil" if "v" is > 0. Otherwise the player
+gets the message "You no longer feel safe from evil".
+
+#####GParameters:
+>v is the time until protection from evil expires (must be between 0
+ and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_protgood
+
+#####GDeclaration: bool set_protgood(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->protgood", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until protection from good expires. The player gets the
+message "You feel safe from good" if "v" is > 0. Otherwise the player
+gets the message "You no longer feel safe from good".
+
+#####GParameters:
+>v is the time until protection from evil expires (must be between 0
+ and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_protundead
+
+#####GDeclaration: bool set_protundead(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->protundead", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until protection from undead expires. The player gets the
+message "You feel safe from undead" if "v" is > 0. Otherwise the
+player gets the message "You no longer feel safe from undead".
+
+#####GParameters:
+>v is the time until protection from undead expires (must be between
+ 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_invuln
+
+#####GDeclaration: bool set_invuln(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->invuln", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until invulnerability expires. The player gets the
+message "Invulnerability" if "v" is > 0. Otherwise the player gets
+the message "The invulnerability wears off".
+
+#####GParameters:
+>v is the time until invulnerability expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_invis
+
+#####GDeclaration: bool set_tim_invis(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_invis", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until see invisible expires. The player gets the message
+"Your eyes feel very sensitive" if "v" is > 0. Otherwise the player
+gets the message "Your eyes feel less sensitive".
+
+#####GParameters:
+>v is the time until see invisible expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_tim_infra
+
+#####GDeclaration: bool set_tim_infra(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_infra", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until infravision expires. The player gets the message
+"Your eyes begin to tingle" if "v" is > 0. Otherwise the player gets
+the message "Your eyes stop tingling".
+
+#####GParameters:
+>v is the time until infravision expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_mental_barrier
+
+#####GDeclaration: bool set_mental_barrier(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->tim_mental_barrier", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until mental barrier expires. The player gets the message
+"Your mind grows stronger" if "v" is > 0. Otherwise the player gets
+the message "Your mind is no longer especially strong".
+
+#####GParameters:
+>v is the time until mental barrier expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_acid
+
+#####GDeclaration: bool set_oppose_acid(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+
+#####GDescription:
+Set time "v" until feather-fall expires. The player gets the message
+"You feel very light" if "v" is > 0. Otherwise the player gets the
+message "You are suddenly heavier".
+
+#####GParameters:
+>v is the time until feather-fall expires (must be between 0 and
+ 10000).
+>v is the time until feather-fall expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_elec
+
+#####GDeclaration: bool set_oppose_elec(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_elec", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until electricity resistance expires. The player gets
+the message "You feel resistant to electricity" if "v" is > 0.
+Otherwise the player gets the message "You feel less resistant to
+electricity".
+
+#####GParameters:
+>v is the time until electricity resistance expires (must be between
+ 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_fire
+
+#####GDeclaration: bool set_oppose_fire(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_fire", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until fire resistance expires. The player gets the
+message "You feel resistant to fire" if "v" is > 0. Otherwise the
+player gets the message "You feel less resistant to fire".
+
+#####GParameters:
+>v is the time until fire resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_cold
+
+#####GDeclaration: bool set_oppose_cold(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_cold", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until cold resistance expires. The player gets the
+message "You feel resistant to cold" if "v" is > 0. Otherwise the
+player gets the message "You feel less resistant to cold".
+
+#####GParameters:
+>v is the time until cold resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_pois
+
+#####GDeclaration: bool set_oppose_pois(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_pois", notice observable changes
+*/
+
+#####GDescription:
+Set time "v" until poison resistance expires. The player gets the
+message "You feel resistant to poison" if "v" is > 0. Otherwise the
+player gets the message "You feel less resistant to poison".
+
+#####GParameters:
+>v is the time until poison resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_ld
+
+#####GDeclaration: bool set_oppose_ld(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_ld"
+*/
+
+#####GDescription:
+Set time "v" until light and dark resistance expires. The player gets
+the message "You feel protected against the light's fluctuation" if
+"v" is > 0. Otherwise the player gets the message "You are no longer
+protected against the light's fluctuation".
+
+#####GParameters:
+>v is the time until light and dark resistance expires (must be
+ between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_cc
+
+#####GDeclaration: bool set_oppose_cc(int v);
+
+#####GFile: xtra2.c
+/*
+* Set "p_ptr->oppose_cc"
+*/
+
+#####GComment:
+
+#####GDescription:
+Set time "v" until chaos resistance expires. The player gets the
+message "You feel protected against raw chaos" if "v" is > 0.
+Otherwise the player gets the message "You are no longer protected
+against chaos".
+
+#####GParameters:
+>v is the time until chaos resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_ss
+
+#####GDeclaration: bool set_oppose_ss(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_ss"
+*/
+
+#####GDescription:
+Set time "v" until sound and shard resistance expires. The player gets
+the message "You feel protected against the ravages of sound and
+shards" if "v" is > 0. Otherwise the player gets the message "You are
+no longer protected against the ravages of sound and shards".
+
+#####GParameters:
+>v is the time until sound and shard resistance expires (must be
+ between 0 and 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_oppose_nex
+
+#####GDeclaration: bool set_oppose_nex(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->oppose_nex"
+*/
+
+#####GDescription:
+Set time "v" until nexus resistance expires. The player gets the
+message "You feel protected against the strange forces of nexus" if
+"v" is > 0. Otherwise the player gets the message "You are no longer
+protected against the strange forces of nexus".
+
+#####GParameters:
+>v is the time until nexus resistance expires (must be between 0 and
+ 10000).
+
+----------------------------------------------------------------------
+
+#####RFunction: set_stun
+
+#####GDeclaration: bool set_stun(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->stun", notice observable changes
+*
+* Note the special code to only notice "range" changes.
+*/
+
+#####GDescription:
+Set stun level "v". If the player race can't be stunned then the level
+is forced to 0. A value > 100 means the player is knocked out. A value
+>50 is a heavy stun. A value > 0 is a stun. If the stun level has
+increased, a message is printed. There is a small chance of stun level
+in 1000, or a 1 in 16 chance of a vicious blow which decreases
+intelligence and/or wisdom for a while.
+
+#####GParameters:
+>v is the stun level.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_cut
+
+#####GDeclaration: bool set_cut(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->cut", notice observable changes
+*
+* Note the special code to only notice "range" changes.
+*/
+
+#####GDescription:
+Set cut level "v". If the player race can't be cut then the time is
+forced to 0. A value > 1000 is a mortal wound. A value > 200 is a deep
+gash. A value > 100 is a severe cut. A value > 50 is a nasty cut. A
+value > 25 is a bad cut. A value > 10 is a light cut. A value > 0 is a
+graze. If the cut level has increased, a message is printed. There is
+a small chance of stun level in 1000, or a 1 in 16 chance of scarring
+which decreases charisma for a while.
+
+#####GParameters:
+>v is the cut level.
+
+----------------------------------------------------------------------
+
+#####RFunction: set_food
+
+#####GDeclaration: bool set_food(int v);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Set "p_ptr->food", notice observable changes
+*
+* The "p_ptr->food" variable can get as large as 20000, allowing the
+* addition of the most "filling" item, Elvish Waybread, which adds
+* 7500 food units, without overflowing the 32767 maximum limit.
+*
+* Perhaps we should disturb the player with various messages,
+* especially messages about hunger status changes. XXX XXX XXX
+*
+* Digestion of food is handled in "dungeon.c", in which, normally,
+* the player digests about 20 food units per 100 game turns, more
+* when "fast", more when "regenerating", less with "slow digestion",
+* but when the player is "gorged", he digests 100 food units per 10
+* game turns, or a full 1000 food units per 100 game turns.
+*
+* Note that the player's speed is reduced by 10 units while gorged,
+* so if the player eats a single food ration (5000 food units) when
+* full (15000 food units), he will be gorged for (5000/100)*10 = 500
+* game turns, or 500/(100/5) = 25 player turns (if nothing else is
+* affecting the player speed).
+*/
+
+#####GDescription:
+Set hunger level "v". A value < 500 is fainting. A value < 1000 is
+weak. A value < 2000 is weak. A value < 10000 is full. A value
+< 15000 is bloated. A value < 20000 is gorged. If one of these
+levels is crossed a message is printed.
+
+#####GParameters:
+>v is the hunger level (must be between 0 and 20000).
+
+----------------------------------------------------------------------
+
+#####RFunction: check_experience
+
+#####GDeclaration: void check_experience(void);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Advance experience levels and print experience
+*/
+
+#####GDescription:
+Check if player experience level has changed. If a player has achieved
+a level for the first time, give reward or corruption (1 chance in 3)
+if they apply, and increase skill points.
+
+----------------------------------------------------------------------
+
+#####RFunction: check_experience_obj
+
+#####GDeclaration: void check_experience_obj(object_type *o_ptr);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Advance experience levels and print experience
+*/
+
+#####GDescription:
+Check if object "o_ptr" experience level has changed. If an object has
+achieved a level for the first time, apply gains.
+
+#####GParameters:
+>o_ptr is the pointer to the object gaining experience.
+
+----------------------------------------------------------------------
+
+#####RFunction: gain_exp
+
+#####GDeclaration: void gain_exp(s32b amount);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Gain experience (share it to objects if needed)
+*/
+
+#####GDescription:
+Gain "amount" of experience. Count the number of objects which will
+gain experience. The objects share equally 2/3 of "amount". Give
+corruption if it applies. Gain experience. If experience is less
+than maximum, then increase maximum experience by 20% of "amount".
+Check for level change and print experience (check_experience).
+
+#####GParameters:
+>amount is the amount of experience to share.
+
+----------------------------------------------------------------------
+
+#####RFunction: lose_exp
+
+#####GDeclaration: void lose_exp(s32b amount);
+
+#####GFile: xtra2.c
+
+#####GComment:
+/*
+* Lose experience
+*/
+
+#####GDescription:
+Decrease experience by "amount". Experience can not fall below zero.
+Check for level change and print experience (check_experience).
+
+#####GParameters:
+>amount is the amount of experience to lose.
+
+----------------------------------------------------------------------
+
+
+Back to the *****lua.hlp*0[lua help index] .
+
+
+ [[[[[gThis file by Chris Hadgis]
+
+
diff --git a/lib/mods/theme/help/lua_pow.txt b/lib/mods/theme/help/lua_pow.txt
new file mode 100644
index 00000000..c221a664
--- /dev/null
+++ b/lib/mods/theme/help/lua_pow.txt
@@ -0,0 +1,266 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Adding new racial powers >
+#####R \----------------------------------------/
+
+#####R=== Introduction ===
+
+You *must* download and install my lua example files from
+[[[[[Ghttp://www.moppy.co.uk/angband.htm]. And also you should read the
+*****lua_intr.txt*0[scripting introduction] file if you haven't already done
+so.
+
+The (commented) accompanying script file for this tutorial is
+lib\scpt\pheonix.lua. Open it in your text editor!
+
+#####R=== The Racial Power ===
+
+Let's start with something simple. Let's say you wanted your new race (let's
+call it "Pheonix") to be able to cast fire balls as their racial power.
+
+#####R=== Starting off ===
+
+If you have a look at pheonix.lua you'll note the first lines are comments.
+I'll talk a bit more about comments later, but it's worth pointing out that any
+lines of text preceded by a double hyphen ([[[[[B--]) will be ignored by the
+scripting engine, and are therefore comments.
+After the comments, the first 10 lines of code are as follows:
+
+#####BPHEONIX_POWER = add_power
+#####B{
+#####B ["name"] = "Fire Breath",
+#####B ["desc"] = "You are able to cast fireballs",
+#####B ["desc_get"] = "Your beak glows red",
+#####B ["desc_lose"] = "Your beak goes cold again",
+#####B ["level"] = 10,
+#####B ["cost"] = 11,
+#####B ["stat"] = A_INT,
+#####B ["fail"] = 14,
+
+So, [[[[[BPHEONIX_POWER = add_power] is registering our power. We're giving it
+a name (PHEONIX_POWER) and saying that it is defined by calling the special
+function [[[[[Badd_power]. This special function is only used to define lua-
+scripted
+powers, and has attributes which are identified by their inclusion in square
+brackets.
+Note the following:
+- Lua is case sensitive. The name of our power is a constant, will never change
+so that's been named with capitals. variables and functions are named all in
+lower case. Technically speaking, Lua does not support constants, but we can
+emulate them by variables in this way. They don't have to be capitalised, but
+if you capitalise all your constants, it makes things easier to read, and
+you'll be following normal programming protocol.
+- There are no spaces in the name of the power. Use an underscore for spaces
+if you need to improve legibility.
+
+[[[[[B"name" = "Fire Breath",] This is the name of the power as it is
+displayed in the
+U menu, and as you will define it in p_info.txt (more about that later).
+
+[[[[[B"desc" = "You are able to cast fireballs",] This is what would
+appear in the
+information display list if you drank a potion of self knowledge or
+similar.
+
+[[[[[B"desc_get" = "Your beak glows red",] This is the information displayed
+when you
+gain this power.
+
+[[[[[B"desc_lose" = "Your beak goes cold again",] This is the information
+displayed when
+you lose this power. Eg After a mutation/corruption.
+
+[[[[[B"level" = 10,] Character level which must be gained in order to use
+power,
+
+[[[[[B"cost" = 11,] Amount of mana to cast this power.
+
+[[[[[B"stat" = A_INT,] stat which will define whether it works or not,
+
+[[[[[B"fail" = 14,] how high that stat must be.
+
+So our Pheonix will be able to cast PHEONIX_POWER from clvl 10, at a cost of
+11 mana, providing that the player's intelligence is 14 and upwards.
+
+#####R=== The function ===
+
+The next section is a lot longer, so we'll look at it line by line. I'll
+strip the comments for the purpose of this helpfile.
+
+#####B["power"] = function()
+#####B local ret, dir, damage
+#####B ret, dir = get_aim_dir();
+#####B if (ret == FALSE) then
+#####B return
+#####B end
+#####B damage = player.lev*3
+#####B msg_print("You breathe fire.")
+#####B fire_ball(GF_FIRE, dir, damage, 3)
+#####Bend,
+
+The [[[[[B"power"] bit is what actually happens when the player accesses this
+power
+from their 'U' menu. Every function must start with the word [[[[[Bfunction].
+Normally, we'd also declare its name at this point, but as this is contained
+within the [[[[[Badd_power] function, we just use the word [[[[[Bfunction] The
+empty
+brackets after this denote that no arguments are passed to the function.
+Lets look at the next line.
+
+#####B local ret, dir, damage
+
+The [[[[[Blocal] bit is saying that we're going to declare some local
+variables. That
+is, that there will be three variables used in this function , that apply
+exclusively to this function, and to no others. Global variables are
+variables that apply to the whole script, in multiple functions. The three
+variables will be called [[[[[Bret] (return), [[[[[Bdir] (direction), and
+[[[[[Bdamage]. They will be used to determine the direction the ball
+will fire in, and how much damage it will do. We'll see them in use when we add
+the third line:
+
+#####B ret, dir = get_aim_dir();
+
+here we're saying that the variables will take their value from the result
+of a function. The program performs the function [[[[[Bget_aim_dir] which
+essentially asks the player to choose a direction or pick a target.
+[[[[[Bget_aim_dir]
+assigns the value [[[[[Bret] to either TRUE (if the player correctly selected a
+direction) or FALSE (if the player failed to do so (maybe they changed their
+mind, or hit the wrong key!)). The value [[[[[Bdir] is the direction which was
+selected (or the path to the target if a target was selected). OK so let's add
+the next line:
+
+#####B if (ret == FALSE) then return end
+
+This introduces another fundamental scripting concept - [[[[[Bif] statements.
+They work just as you would expect them too. You say "if a certain condition is
+met, then do the following things."
+So in this function we're saying, "if the value of [[[[[Bret] is FALSE then
+[[[[[Breturn]."
+As I mentioned above, [[[[[Bret] is false if the player aborted (either
+deliberately or accidentally) the spell casting whilst choosing a direction
+for the spell. The double equals sign are used to mean "is equal to" as a
+single equals sign is used for defining variables remember? A single equals
+sign is more of a "let x be equal to y" thing.
+[[[[[Breturn] means stop the current function. And [[[[[Bend] signifies the
+close of the [[[[[Bif]
+statement. Every [[[[[Bif] statement must begin with an [[[[[Bif] and finish
+with an [[[[[Bend].
+So, what our [[[[[Bif] statement is saying is; "if the player failed to specify
+a direction or target for the spell, stop the function here."
+If the player has correctly specified a direction/target, the function
+continues to the next line:
+
+#####B damage = player.lev*3
+
+Here we're saying that the variable [[[[[Bdamage] has a value equal to the
+players current character level, multiplied by 3.
+
+#####B msg_print("You breathe fire.")
+
+Fairly easy to see what this does - displays the message "You breathe fire."
+I could have put anything there obviously, like [[[[[Bmsg_print("You open]
+[[[[[Byour mouth and everyone falls over with the smell of hot curry")] or
+some other such rubbish. But note that the message is enclosed within double
+quotes. The quotes aren't displayed in the message on screen, but signify the
+start and end of the message.
+
+#####B fire_ball(GF_FIRE, dir, damage, 3)
+
+This is the line that casts the spell. it says execute the function
+[[[[[Bfire_ball]. Now, this doesn't mean a fireball, it means fire a ball.
+There's an important distinction there! All it knows it is doing is firing a
+ball, it doesn't know what kind of ball, or where, or how big, or how much
+damage.
+The [[[[[BGF_FIRE,] bit is what tell us it is a fire ball. If it was
+[[[[[BGF_COLD,]
+ we'd have a cold ball, or [[[[[BGF_CHAOS,] it would be a chaos ball and
+so on and so on. A full list of those types can be found in *****lua_gf.txt*0[lua_gf.txt].
+[[[[[B dir,] is the direction, from the [[[[[Bget_aim_dir()] bit.
+[[[[[B damage,] is the damage. As we've already said, this will be clvl*3.
+[[[[[B 3)] is the radius.
+and finally...
+
+#####B end,
+#####B}
+
+[[[[[Bend,] tells it the function has ended. Every function must finish with
+[[[[[Bend].
+You should have spotted that after the end of each attribute is a comma. Make
+sure you include this, and don't forget the braces at the very very end to
+close the [[[[[Badd_power] function.
+
+#####R=== Finishing the LUA file ===
+
+Save this as a text file 'pheonix.lua' Put it into the lib\scrpt directory
+of ToME, and open the init.lua file which you'll find in the same
+directory.
+
+Add the following line and resave the init.lua file.
+
+#####Btome_dofile("pheonix.lua")
+
+This ensures that ToME loads your file on start-up. Because you've installed
+the example scripts, this has all been done for you.
+
+#####R=== A quick word about comments ===
+
+One of the reasons Angband has so many variants is because the source code is
+clearly commented. Almost every line of code has an accompanying comment,
+explaining what that line does. It's good practice to add comments to any code
+or script you write. It's helpful to others who are learning, anyone who takes
+over your project, and also to yourself when you come back in a month's time
+and can't remember what you did! So comment your code clearly, and well!
+
+You can also add multi line comments which should be enclosed by [[[[[B--[[]
+and
+#####B]]
+
+#####R=== Tying it all together ===
+
+You'll now need to link this 'U' power to the pheonix race via the
+p_info.txt file. Simply add a line within the class definition file that has
+the format [[[[[BR:Z:<name>]the name of the power as it appears in the
+[[[[[B"name"]
+section we did right at the beginning, remember? Seeing as there is no pheonix
+race, I've gone ahead and made one up as a demonstration. If you've downloaded
+and installed the example files from [[[[[Ghttp://www.moppy.co.uk/angband.htm/]
+then
+you'll notice you already have the pheonix race available. Printed below is
+the p_info.txt entry for it.
+
+
+#####BR:N:23:Pheonix
+#####BR:D:Born from flame, these powerful bird like creatures gain fire related
+#####BR:D:abilities as they grow.
+#####BR:S:1:0:2:1:-3:2:-5
+#####BR:K:-8:15:20:-10:5:-1:-5:-5
+#####BR:P:8:130:5:210
+#####BR:M:255:70:2:1:20:5:2:1:18:3
+#####BR:E:1:1:1:2:1:1
+#####BR:C:Warrior | Mage | Priest | Rogue | Ranger | Paladin | Blade |
+#####BR:C:Warlock | Chaos-Warrior | Monk | Mindcrafter | High-Mage |
+#####BR:C:BeastMaster | Alchemist | Power-Mage | Runecrafter |
+#####BR:C:Sorceror | Archer | Illusionist | Druid | Necromancer | Black-Knight
+|
+#####BR:C:Daemonologist | Weaponmaster | Summoner |
+#####BR:Z:Fire Ball
+#####BR:R:1:0
+#####BR:F:RES_FIRE | FEATHER |
+
+Note the [[[[[BR:Z:] line.
+
+If all is well, you should be able to start ToME now and breathe fire! Once
+you get to lvl 10 anyhow. Don't forget, this is the kind of thing wizard mode
+was invented for! Ctrl-A and confirm at the prompt, and then 'e' will allow
+you to alter stats, including experience. Approx 1000 exp should do to get you
+to clvl 10.
+
+Ready for more? How about adding a new *****lua_skil.txt*0[skill] ?
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
+
+
+
+
diff --git a/lib/mods/theme/help/lua_ques.txt b/lib/mods/theme/help/lua_ques.txt
new file mode 100644
index 00000000..1d4b9c65
--- /dev/null
+++ b/lib/mods/theme/help/lua_ques.txt
@@ -0,0 +1,299 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Adding a new quest >
+#####R \----------------------------------------/
+
+#####R=== Introduction ===
+
+Adding a quest involves a bit more work, and there is, in some ways, rather
+more potential for things to go wrong! But it's a great way of showing just
+WHAT can be done with lua scripting. It proves just how much a lua patch can
+change the overall feel of the game. And it will give you a much better idea of
+how lua interfaces with the game source. You should have read the
+*****lua_intr.txt*0[scripting introduction], *****lua_pow.txt*0[racial power tutorial]
+and *****lua_skil.txt*0[adding new skills tutorial] before going much
+further. All of the above files contain some fairly fundamental information
+which you will find necessary for full understanding of this file.
+
+The script we're looking at is going to create a quest entrance in the middle
+of Bree. Entering the quest you see a little girl who has had her necklace
+stolen. Your job is to travel down a corridor, killing some monsters on the
+way, pick up the amulet and return it to the girl. Once done, she'll reveal the
+stairs back to Bree, and give you a (randomly generated) ring. If you feel the
+monsters are too hard, the only thing to do is talk to the little girl who will
+reveal the stairs again, failing the quest for you, and also block off the
+entrance to the amulet so that you can't cheat and make off with the amulet!
+
+#####R=== Getting started ===
+
+Open amulet.lua (you have downloaded the example scripts from
+[[[[[Ghttp://www.moppy.co.uk/angband.htm], haven't you?). The first thing you
+should see is that yet again we're calling a function that takes its arguments
+from a table, making it easy to read what's going on in the script.
+
+This time our function is add_quest and we have the following keys and values:
+
+#####B["global"] = "AMULET_QUEST",
+#####B["name"] = "Hannahs lost amulet",
+#####B["desc"] = {
+#####B "Retrieve an amulet for Hannah Cooke. It's guarded!"
+#####B },
+#####B["level"] = 5,
+#####B["hooks"] = {
+
+[[[[[B"global" = ] is a constant that we set when we refer to this quest in
+various places...
+[[[[[B"name" = ] Obviously a long name for the quest. This will appear in the
+quest screen (Ctrl-Q) and we may use in some map files too.
+[[[[[B"desc" = ] This is a long description for the quest. Again this is what
+will appear in the quest screen, and each line should be not more than 80
+characters.
+[[[[[B"level" = ] This is a rough indicator of how hard the quest is, and again,
+appears in the quest screen
+[[[[[B"hooks" = ] This is the real 'meat' of the quest. Like the [[[[[B"spell_list"] key
+in the [[[[[Badd_magic] function, this is another sub-table.
+
+To understand fully the structure of the "hooks" key it's worth taking a bit of
+a detour at this point and discussing how the scripting interface works in
+general.
+
+#####R=== How the scripts work (ish) ===
+
+Essentially there's a list of events that happen in the game. As each of these
+events happen they run a check to see if there's any functions that they need
+to run at that event. When we ran the add_mkey part of adding a new skill
+power, we essentially said "when the 'm' key is pressed in the game, perform
+the [[[[[Bexecute_magic(constructor_powers)] function". Likewise we did a similar
+thing with adding the racial power, only we hooked onto the pressing of the
+'U' key.
+
+All of this was partly hidden because of the way that the [[[[[Badd_magic] and
+[[[[[Badd_power] functions work. But here in the [[[[[Badd_quest] function it's a bit more
+specific. We are going to specify what events we're going to hook onto, and
+what functions we want to trigger at that event.
+
+A full list of hooks can be found in the source-file util.pkg.
+
+#####R=== The hooks ===
+
+#####B[HOOK_BIRTH_OBJECTS] = function()
+#####B quest(AMULET_QUEST).status = QUEST_STATUS_TAKEN
+#####Bend,
+
+So here we are with our first hook. We've declared that we're adding it to the
+birth of your character. That is, the function will be called when you create
+your character. And what we're doing here is automatically declaring the quest
+as being taken, like the Dol Guldur quest is. Each quest has 7 different
+statuses:
+
+[[[[[BQUEST_STATUS_IGNORED -1 ] This is unused, but the quest is
+ignored (will not be taken and has not been taken).
+[[[[[BQUEST_STATUS_UNTAKEN 0 ] The quest has not been accepted yet
+[[[[[BQUEST_STATUS_TAKEN 1 ] You have accepted the quest
+[[[[[BQUEST_STATUS_COMPLETED 2 ] You have completed the quest
+successfully but not been rewarded for it
+[[[[[BQUEST_STATUS_REWARDED 3 ] You've completed and rewarded the quest
+[[[[[BQUEST_STATUS_FAILED 4 ] You've failed the quest
+[[[[[BQUEST_STATUS_FINISHED 5 ] The quest is completely finished
+successfully.
+[[[[[BQUEST_STATUS_FAILED_DONE 6 ] The quest is completely finished
+unsuccessfully.
+
+You see that we've used the constant we defined in the "global" section is
+passed as an argument to [[[[[Bquest.status].
+
+Next hook then:
+
+#####B[HOOK_GEN_QUEST] = function()
+#####B if (player.inside_quest ~= AMULET_QUEST) then
+#####B return FALSE
+#####B else
+#####B load_map("amulet.map", 2, 2)
+#####B return TRUE
+#####B end
+#####Bend,
+
+Ok, we're hooking onto the generation of the quest here. This is specifically
+triggered in this instance by going down the quest entrance stairs in Bree.
+Once you've gone down the stairs, you are technically inside the quest, which
+means we can say if the person is not inside the amulet quest, then ignore this
+function, otherwise load the file 'amulet.map' at co-ordinates x=2 y=2. You'll
+find the amulet.map file in the edit directory, make sure you check it out. The
+syntax for map files is fairly simple, though I might get round to writing a
+tutorial on them some day! In the mean time holler for me at the usual email
+address if you're unsure.
+
+#####B[HOOK_FEELING] = function()
+#####B if (player.inside_quest ~= AMULET_QUEST) then
+#####B return FALSE
+#####B else
+#####B cmsg_print(TERM_L_BLUE, "Hannah speaks to you:")
+#####B cmsg_print(TERM_YELLOW, "'Some nasty monsters stole my
+#####B favourite necklace.'")
+#####B cmsg_print(TERM_YELLOW, "'It's hidden at the back of that
+#####B corridor! Please fetch it for me'")
+#####B return TRUE
+#####B end
+#####Bend,
+
+We're moving into some rather more obvious territory here, and getting into the
+meat of the quest. The [[[[[BHOOK_FEELING] is triggered at the point when the level
+feeling appears. It's important that this is run only if the player is inside
+the amulet quest, as otherwise it will trigger EVERY time a level feeling
+occurs, when you go down a level in the barrow-downs, whenever! Returning TRUE
+will replace the level feeling with what's above, returning FALSE will still
+perform the function but will amend the normal level feeling - so here if we'd
+returned false we'd still get our custom messages, but they'd follow with
+'looks like a typical quest level'. Of course returning false may cause you
+other problems (see end of this file!) depending on what else you have in your
+function.
+
+#####B[HOOK_GIVE] = function(m_idx, item)
+
+#####B m_ptr = monster(m_idx)
+#####B o_ptr = get_object(item)
+
+#####B if (m_ptr.r_idx == test_monster_name("Hannah Cooke, a little girl"))
+#####B and (o_ptr.tval == TV_AMULET) and (o_ptr.sval == 2) then
+
+#####B cmsg_print(TERM_YELLOW, "'Thank-you!'")
+
+#####B inven_item_increase(item, -1)
+#####B inven_item_optimize(item)
+
+#####B quest(AMULET_QUEST).status = QUEST_STATUS_COMPLETED
+
+#####B cave_set_feat(7, 6, 6)
+
+#####B cmsg_print(TERM_YELLOW, "'Here, take this pretty ring I found
+#####B as a token of gratitude!'")
+#####B random_type = randint(57)
+#####B reward = create_object(TV_RING, random_type)
+#####B drop_near(reward, -1, py, px)
+#####B quest(AMULET_QUEST).status = QUEST_STATUS_REWARDED
+#####B return TRUE
+#####B else
+#####B return FALSE
+#####B end
+#####Bend,
+
+This is a fairly long function, but don't be intimidated. It's not really
+difficult to understand. As you can see we're hooking into the giving of an
+object to a monster (the 'y' key). Because of this, the function takes two
+arguments - [[[[[Bm_idx] (the monster that you're giving to) and [[[[[Bitem] (the item that
+you're giving).
+
+We then make it possible to work with the monster and item variables by
+referencing them to two functions which identify them from the edit files:
+[[[[[Bmonster()] and [[[[[Bget_object()]. This enables us to now say, 'if the name of the
+monster is "Hannah Cooke, a little girl" and the type of item is an amulet and
+that amulet is an amulet of adornment, then carry out the following commands'.
+
+We then say call the function [[[[[Binven_item_increase()] which places an object in
+the inventory. It takes two arguments, the first being what object to put in
+the inventory and the second being how many of that type of objects to put in
+the inventory. You can see that by placing -1 as the second argument it fairly
+obviously subtracts that item from the inventory. The [[[[[Binven_item_optimize()]
+function checks that there are no empty inventory slots, and if there are,
+erases them.
+
+The quest is then completed, and the stairs are revealed using the
+[[[[[Bcave_set_feat()] function. This function takes three arguments, the first is the
+x co-ordinate of the cave square you wish to change (counted from top left) the
+second is the y co-ordinate, and the third is the index number of the feature
+you wish the square to become as defined in f_info.txt.
+
+We then set about rewarding the player. As you can see we call [[[[[Bcreate_object()]
+which takes two variables: the first is the type of object (these are all
+listed in object.pkg) and the second is the sub-type of that object. I searched
+k_info.txt to see how many different types of ring there were (57) and used a
+randomly selected number with a maximum value of 57 as that specific sub-type.
+
+We then drop the object (although it's been created, it has only been created
+in the game's memory, it's nowhere that the player can interact with it until
+we drop it). The [[[[[Bdrop_near()] function takes 3 variables, the first being the
+object that you wish to drop, the second being the chance that it disappears
+(like an arrow, or mimicked creature) on drop. If you set it to -1, it won't
+ever disappear. The last two are the co-ordinates at which the object will be
+dropped. py and px are the global variables defined by where the player is
+standing, so in this case it will drop under the player. You could do
+[[[[[Binven_item_increase(reward, 1)] if you wanted, but I wanted to show a variety of
+ways of handling objects.
+
+OK, let's take a look at the next hook:
+
+#####B[HOOK_CHAT] = function(m_idx)
+#####B m_ptr = monster(m_idx)
+#####B if (m_ptr.r_idx == test_monster_name("Hannah Cooke, a little girl")) then
+#####B if (quest(AMULET_QUEST).status == QUEST_STATUS_REWARDED) then
+#####B cmsg_print(TERM_YELLOW, "'Bye!'")
+#####B else
+#####B cmsg_print(TERM_YELLOW, "'Are the monsters too tough?
+#####B Do you want to leave?'")
+#####B if (get_check("Really leave and fail the quest?") ==
+#####B FALSE)
+#####B then
+#####B cmsg_print(TERM_YELLOW, "'Go and get my
+#####B amulet then!'")
+#####B else
+#####B cmsg_print(TERM_YELLOW, "'Awww. Never
+#####B mind. It was only a bit of rabbits foot'")
+#####B quest(AMULET_QUEST).status =
+#####B QUEST_STATUS_FAILED
+#####B cave_set_feat(7, 6, 6)
+#####B cave_set_feat(12, 5, 60)
+#####B end
+#####B end
+#####B return TRUE
+#####B end
+#####B return FALSE
+#####Bend,
+
+This only looks complicated because of the nested 'if' statements. It's easy to
+lose your way when doing this kind of thing, always make sure you close all the
+statements and put the returns in the right place. [[[[[BHOOK_CHAT] functions have one
+argument - the monster you are chatting to. As you can see, we perform a check
+to make sure it's the right monster and then away we go.... If the player wants
+to leave the quest without completion they talk to Hannah, who gives them a
+chance to change their mind! If the player asks to leave the entrance to the
+corridor is blocked off (the second cave_set_feat()) so that the user can't
+then go and get the amulet. Gumband or Zangband players may at this point think
+they've lost out on the rabbits foot of burglary! (they haven't though as it
+doesn't exist in ToME).
+
+#####B[HOOK_CHAR_DUMP] = function()
+#####B if (quest(AMULET_QUEST).status == QUEST_STATUS_FAILED) then
+#####B print_hook("\n You chickened out of rescuing a necklace and
+#####B made a little girl sad. ")
+#####B elseif (quest(AMULET_QUEST).status == QUEST_STATUS_COMPLETED) or
+#####B (quest(AMULET_QUEST).status == QUEST_STATUS_REWARDED) or
+#####B (quest(AMULET_QUEST).status == QUEST_STATUS_FINISHED) then
+#####B print_hook("\n You rescued little Hannah Cooke's necklace from
+#####B the nasty monsters ")
+#####B end
+#####B return FALSE
+#####Bend,
+
+This quite simply and obviously prints an appropriate line in the character
+dump based on the status of the quest. The [[[[[B\n] bit ensures the text goes on a
+new line, so make sure you include it! Also you should return FALSE as
+returning TRUE will stop executing all the other character dump lines (and you
+may get other quests not having their lines printed).
+
+=== A word about returning TRUE and FALSE ===
+
+As I mentioned above, you need to be careful what you return when dealing with
+HOOKS as you can mess up the game a bit. Bear in mind that if you add a
+function to [[[[[BHOOK_GEN_QUEST], every time a quest is generated, that function will
+run. If you return TRUE, then no further functions attached to that hook will
+run. If you return FALSE, it continues processing functions on that hook.
+
+That is pretty much it. Do take a look at the other included scripts that I
+haven't gone into any detail about in the files, as you'll pick up some useful
+techniques there too. Especially worthy of note is the hina.lua file which uses
+hooks outside of the quest structure and also global variables and variables in
+a table. If you have any questions, let me know at the email addy below.
+
+Back to the *****lua.hlp*0[lua help index] .
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
diff --git a/lib/mods/theme/help/lua_skil.txt b/lib/mods/theme/help/lua_skil.txt
new file mode 100644
index 00000000..87385e5d
--- /dev/null
+++ b/lib/mods/theme/help/lua_skil.txt
@@ -0,0 +1,342 @@
+|||||oy
+#####R /----------------------------------------\
+#####R < Adding new skill-based powers >
+#####R \----------------------------------------/
+
+#####R=== Introduction ===
+
+This is very much in the same vein as adding a racial/extra power, but has to
+be tied into skills, and we're defining more than one spell at once. You should
+have read the *****lua_intr.txt*0[scripting introduction] and
+*****lua_pow.txt*0[racial power tutorial] before going much further. Both of the above files
+contain some fairly fundamental information which you will find necessary for
+full understanding of this file.
+
+#####R=== Getting started ===
+
+Open construc.lua (you have downloaded the example scripts from
+[[[[[Ghttp://www.moppy.co.uk/angband.htm], haven't you?). The idea behind this
+script is that it adds a skill which affects you ability to build/knock down
+stuff. It treats the equivalent of stone-to-mud and trap-door destruction
+spells as if they were "building skills". It also adds quite a few high-level
+'spells' which do funky things like carving out corridors and chambers in a
+single turn, and building doors and stuff. Just think of it as if the person
+who has plenty of skills in this area would be a builder-type with lots of
+strength and constitution...
+
+In order to add these powers we're going to edit the s_info.txt file which
+lives in the edit folder, and add a new skill, underneath the 'misc' tree,
+called construction. The powers will then be accessed through the 'm' menu, in
+a similar way to mindcraft or alchemy skills or such. (That is, no books are
+needed to cast them, as we're treating them as a craft that has been learnt,
+rather than spells.) Our fist line of the script file reads:
+
+#####BSKILL_CONSTRUCT = 57
+
+This merely links the skill index that we'll be defining in s_info.txt to this
+file. We'll come back to this at the end of the tutorial.
+
+#####Bconstructor_powers = add_magic
+
+In a similar way to the [[[[[Badd_power] function we called when we added the
+Phoenix racial ability, this line calls a special function which we use to
+define new skills. It follows a very specific, but easy to understand form. It
+starts with a brace, which indicates the add_magic function will be storing
+these values in a table. Don't worry about this too much, but understand that a
+table starts and ends with braces [[[[[B{] and [[[[[B}] respectively. Each key
+(or field name) takes the format [[[[[B"key" = value,] (the comma is
+important!).
+
+#####B ["fail"] = function()
+#####B msg_print("You decide now is a good time for a cuppa")
+#####B end,
+#####B ["stat"] = A_STR,
+#####B ["get_level"] = function()
+#####B return get_skill_scale(SKILL_CONSTRUCT, 50)
+#####B end,
+#####B ["spell_list"] =
+
+[[[[[B"fail"] is a function that is called whenever you ##fail to cast the
+spells##. Here it does nothing spectacular.
+[[[[[B"stat"] defines the stat used to cast the spells. Here it is strength.
+Any other stat can be used, prefix it with [[[[[BA_].
+[[[[[B"get_level"] is used to determine the level of the spell. It's associated
+with spells that increase in power the more points that are invested in the
+associated skill. I know that's not terribly clear, I'll come back to it in a
+moment.
+[[[[[B"spell_list"] is just that, a list of all the spells.
+Each of these four properties within the table must end with a comma. If a
+function is defined in the property itself then we add the comma after the
+closing [[[[[Bend]. Again compare with construct.lua to see it. Any line NOT
+ending with a comma will cause a lua error on startup, probably of the type
+[[[[[V'}' expected to close '{' at line <whatever>.]
+
+#####R=== The spell list ===
+
+Each spell, within the [[[[[B"spell_list"] key has its own set of properties
+that we need to define from a sub-table so we open another set of braces to
+start the spell list, and then a third set of braces to start the first spell.
+So with all this, our first spell looks like:
+
+#####B ["spell_list"] =
+#####B {
+#####B {
+#####B ["name"] =
+#####B ["desc"] =
+#####B ["mana"] =
+#####B ["level"] =
+#####B ["fail"] =
+#####B ["spell"] =
+#####B ["info"] =
+#####B },
+
+[[[[[B"name"] is, as you would expect, the name of the spell, as you want it to
+appear in the spell list when choosing a spell. The maximum number of
+characters for this is 29.
+[[[[[B"desc"] is the description received when you hit the capital letter of
+that spell in the menu. (i.e., press 'a' to cast the first spell, but press 'A'
+to receive info about the first spell.
+[[[[[B"mana"] is the amount of mana required to cast the spell.
+[[[[[B"level"] is the level required to use that spell (that's level of the (in
+this case construction) skill, not character level!).
+[[[[[B"fail"] is base fail rate.
+[[[[[B"spell"] is the function that is executed when the spell is cast. Note
+that it MUST take the form [[[[[Bfunction() blah end] even if you're calling
+a C function directly. If you have a look at the end of the file, you'll see
+the "rebuild dungeon" spell which is identical to the "alter_reality" spell.
+However, rather than reading [[[[[B"spell" = alter_reality()], it reads:
+
+#####B["spell"] = function()
+#####B alter_reality()
+#####Bend,
+
+which appears to be a long way round to do the same thing, but this is how it
+must be done.
+
+In a similar way, the [[[[[B"info"] key must begin with a [[[[[Bfunction()]
+and return the value of what is to be displayed alongside the spell name,
+level and mana in the spell list. The maximum number of characters that can be
+displayed here is dependent on the width of the user's screen, but try to keep
+it under 12 if you can, as this will fit in a standard 80x24 terminal screen.
+The first character will need to be a space otherwise you'll have the info line
+squashed right up against the fail rate and it will look odd. If you wish to
+have this part blank in the spell list, you still need to return a value, so
+just a single space will do : [[[[[Breturn " "]
+
+All of these keys are repeated for each spell, with each spell in its own
+table (therefore, it's own set of braces). Again, check the lua file for
+clarification.
+
+When entering the spells in the "spell_list", you must take care to specify
+them in the order which they are gained, otherwise they display incorrectly in
+the spell list.
+
+You should by now be experienced enough to understand most of what's going on
+in the actual spell functions (especially if you dig around in the source a
+bit, and check out Chris Hadgis' excellent *****lua_spel.txt*0[spell.pkg] helper
+files. I'm not going to go through the whole file line by line, as this is
+something you should do yourself, figuring out what's going on. I'm going to
+examine a few of the things we haven't covered before though, so pay attention.
+
+#####R=== The get_level() function ===
+
+Probably one of the most important functions that you see reappearing in the
+file is the [[[[[Bget_level()] function. All this does is return the numerical
+value of the power that is given as the first argument. So [[[[[Bget_level]
+[[[[[B(constructor_power)] will return the current level of the constructor power.
+Given that the level of this is taken directly from the construction skill, (we
+defined that in the [[[[[B"get_level"] key, by saying [[[[[Bget_skill_scale]
+[[[[[B(SKILL_CONSTRUCT, 50)] ) it will return the value of your construction skill.
+[[[[[Bconstructor_power] is the name of the whole power, we named it thus on
+the second line of the script!
+
+[[[[[Bget_level] takes the following arguments: [[[[[Bget_level(power, max, ]
+[[[[[Bmin)]. The power is obviously which power we're taking the value from, and the
+max and min allow you to define boundaries for the spell. For instance the
+current maximum value that [[[[[Bget_level(constructor_power)] can return is
+50, as that is the maximum number of skill points you can have in that skill.
+If you were using this as the basis for the damage of a low-level bolt spell,
+you might decide that having a damage of 50 would be too much (unlikely, but
+still possible). You could therefore define a maximum value of 20 so that when
+the value of the construction skill was over 50, the maximum value for
+damage of that spell would be 20. To achieve this you'd have:
+[[[[[Bget_level(constructor_power, 20)]. In a similar way, you can force the
+minimum value of the spell to be higher than the actual construction skill
+level, with a [[[[[Bget_level(constructor_power, 50, 15)]. This would be useful
+say for spells that you wanted to be available when the construction skill
+level reaches 10, but for whom you wanted a (for example) base damage of 15
+right from the word go. These re-scale values rather than capping them!
+
+You can leave out the minimum value as I have done above. You can also leave
+the maximum value out (it will default to 50). If you want to specify a minimum
+value though, you MUST specify a maximum value as well.
+
+As you have hopefully been able to tell, the [[[[[Bget_level()] function
+enables us to have spells that increase in usefulness as you gain levels. Let's
+take the "Dismantle" spell. The function in the [[[[[B"spell"] key is as
+follows:
+
+#####Bfunction()
+#####B local ret, dir, dam
+
+#####B if (get_level(constructor_powers, 50) >= 11) then
+#####B ret, dir = get_aim_dir();
+#####B if (ret == FALSE) then return end
+#####B fire_beam(GF_KILL_TRAP, dir, 1)
+#####B else
+#####B fire_ball(GF_KILL_TRAP, 0, 1, 1)
+#####B end
+#####Bend,
+
+The [[[[[Bif] statement is obviously what really interests us here. You'll
+notice that this has the amendment of an [[[[[Belse] clause, which the [[[[[Bif]
+statement we used in the previous tutorial did not. As you would expect, if the
+condition on the first line of this statement is met, then the instructions
+immediately below it are carried out. If the condition is not met, then the
+statements that follow the [[[[[Belse] are executed.
+
+Coming back to the [[[[[Bget_level] function, we learnt from above, that the
+[[[[[Bget_level] part of this function translates as, "if the value of the
+construction_power level (which happens to be identical to the construction
+skill level) is greater than or equal to 11, cast a beam of trap disarming in
+the specified direction. (The first part of this is all straightforward,
+getting a direction, and cancelling correctly if the player presses 'ESC'.)
+Otherwise, cast a ball of trap disarming with a radius of one, centred on the
+player."
+
+In the same way, as you look at the construc.lua file, you will see that
+[[[[[Bget_level()] is used many times in this way, to increase the power of
+detection spells, to change bolt spells to ball spells, to keep a constantly
+increasing damage going, and so on.
+
+#####R=== Elseif's and things ===
+
+If you want to provide more than one alternative condition, in an
+[[[[[Bif-then-else] statement, you can use [[[[[Belseif]s which do what you
+might expect. Take a look at the first spell, "Survey area", for an example of
+this:
+
+#####Bif (get_level(constructor_powers, 50) >= 28) then
+#####B wiz_lite()
+#####Belseif (get_level(constructor_powers, 50) >= 15) then
+#####B map_area()
+#####B detect_traps(DEFAULT_RADIUS)
+#####Belseif (get_level(constructor_powers, 50) >= 5) then
+#####B detect_traps(DEFAULT_RADIUS)
+#####B detect_stairs(DEFAULT_RADIUS)
+#####B detect_doors(DEFAULT_RADIUS)
+#####Belse
+#####B detect_stairs(DEFAULT_RADIUS)
+#####B detect_doors(DEFAULT_RADIUS)
+#####Bend
+
+If the level of constructor powers is greater or equal to 28, then the function
+[[[[[Bwiz_lite()] is performed, and no other part of the if statement is
+executed. [[[[[Bwiz_lite()] is just the enlightenment spell. If it is less than
+28, the next condition is examined: that if the level of constructor powers is
+greater than or equal to 15, then [[[[[Bmap_area()](Magic mapping) and detect
+traps are called. If the level of constructor power is less than 15, it moves
+onto the next condition, which says that if the level of constructor power is
+greater than 5, then detect stairs, traps and doors. If none of these
+conditions are met,(that is, if the level of construction skill is less than 5)
+then we just detect doors and stairs.
+
+You'll note that each of the detection spells includes a DEFAULT_RADIUS
+constant. You could change this to a numerical value, or a variable defined
+somewhere else in your script. eg [[[[[Bdetect_traps(2)] would detect traps
+with a radius of 2 centred on the player.
+
+#####R=== Registering the skill type ===
+
+This is what we do at the end of the file, and is what ties the powers we've
+defined to the action of pressing the 'm' key in game. Once more we're calling
+a special function [[[[[Badd_mkey()] which takes its arguments for a table.
+There are only two keys in this table though which keeps things simple.
+
+#####Badd_mkey
+#####B{
+#####B ["mkey"] = MKEY_CONSTRUCT_POWERS,
+#####B ["fct"] = function()
+#####B execute_magic(constructor_powers)
+#####B energy_use = energy_use + 100;
+#####B end
+#####B}
+
+[[[[[B"mkey"] must be a UNIQUE value > 1000 . Here I've defined it as a
+constant, [[[[[BMKEY_CONSTRUCT_POWERS], which has the value 1004. This value
+we'll call again in the s_info.txt file.
+[[[[[B"fct"] is the function that's called when the user presses the key in the
+'m' menu. So here, it calls the [[[[[Bexecute_magic] function which actually
+displays a list of powers for the user to choose from. The argument it takes is
+the powers it will use (alchemy, mindcraft, etc., or in this case constructor),
+and then the [[[[[Benergy_use] line tells the game to take one game turn to do
+the action.
+
+#####R=== Adding the skill in s_info.txt ===
+
+Take a look in the s_info.txt file, under the Misc section. You'll see,
+
+#####BN:57:Construction
+#####BD:Ability to use constructor powers
+#####BD:Construction powers use strength
+#####BA:1004:Build or knock down stuff
+#####BI:1000
+
+The first line is the index of the skill; again this must be unique. The second
+property is the name of the skill. The [[[[[BD] lines are the lines displayed
+when the skill is highlighted in the skill screen.
+The first entry on the [[[[[BA] line is the value of the [[[[[B"mkey"] we
+defined in the [[[[[Badd_mkey] function in our script. The second entry is the
+display for selecting the construction power in the 'm' menu.
+The [[[[[BI] line is currently unused, but add a 1000 there anyway. That's what
+all the others have so when it's introduced, at least it will affect your
+powers identically to how it affects all the other powers.
+
+If you scroll to the very bottom of the file now, you'll see I've placed the
+skill at the bottom of the Misc branch of the skills tree. I then made a new
+class, constructor, which you can see in p_info.txt.
+
+That is all that is NEEDED when writing a script to add a skill - defining an
+mkey using add_mkey, and defining any powers that are called in the
+[[[[[B"fct"] (generally using [[[[[Badd_magic] ).
+
+And I've added the line
+
+#####Btome_dofile("construc.lua")
+
+in init.lua so the script is loaded on start-up!
+
+Below I'm going to talk in depth about a few other functions that you may find
+useful in your scripting.
+
+#####R=== fire_bolt() and fire_beam() ===
+
+In the last help file we looked at the routine for firing a ball -
+[[[[[Bfire_ball()]. Here's a quick note about beams and bolts...
+[[[[[Bfire_beam()] and [[[[[Bfire_bolt()] take 2 arguments:
+[[[[[B(type, direction, damage)]. So in the dismantle spell we have the
+direction passed from [[[[[Bget_aim_dir()] (the function that asks the player
+for a direction), the type of damage is [[[[[BGF_KILL_TRAP], which as you might
+expect disarms traps. And the damage is only 1 because it's not going to hurt
+monsters, just dismantle traps.
+
+#####R=== set_oppose_elec() ===
+
+OK here's another thing. Wander on down to the sparky_skills spell. After the
+appropriate bolt/ball is fired, we have the line:
+
+#####Bif player.oppose_elec == 0 then
+#####B set_oppose_elec(randint(10) + 20 + get_level(constructor_powers, 20)*3)
+#####Bend
+
+This is the bit that grants temporary resist electricity. We've called the
+function [[[[[Bset_oppose_elec(turns)], which sets the player's resist
+electricity to "on" for the time specified in the argument "turns". We're only
+calling this if the player is not already granted temporary resist electricity,
+and we've linked the number of turns it is active to the level of the
+construction skill. I've limited the maximum value of get_level to 20 in this
+instance. A similar idea can be used for temporarily granting levitation,
+extended infravision, protection against evil, resist fire, stuns, cuts and so
+on and so on. Have a look in player.pkg in the source for a full list....
+
+ [[[[[gThis file by fearoffours (fearoffours@moppy.co.uk)]
diff --git a/lib/mods/theme/help/lua_spel.txt b/lib/mods/theme/help/lua_spel.txt
new file mode 100644
index 00000000..aa4a532b
--- /dev/null
+++ b/lib/mods/theme/help/lua_spel.txt
@@ -0,0 +1,2150 @@
+|||||oy
+
+#####R /----------------------------------------\
+#####R < spell.pkg functions helper file >
+#####R \----------------------------------------/
+
+----------------------------------------------------------------------
+
+#####R=== teleport_player_directed ===
+
+#####GDeclaration
+ extern void teleport_player_directed(int rad, int dir);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport player, using a distance and a direction as a rough guide.
+ *
+ * This function is not at all obsessive about correctness.
+ * This function allows teleporting into vaults (!)
+ */
+
+#####GDescription
+Teleport a player up to "rad" grids away roughly in "dir" direction.
+
+#####GParameters
+> "rad" must not exceed 200. The distance teleported is a minimum of a
+ quarter of "rad".
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+
+----------------------------------------------------------------------
+
+#####R=== teleport_away ===
+
+#####GDeclaration
+ extern void teleport_away(int m_idx, int dis);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport a monster, normally up to "dis" grids away.
+ *
+ * Attempt to move the monster at least "dis/2" grids away.
+ *
+ * But allow variation to prevent infinite loops.
+ */
+
+#####GDescription
+Teleport monster indicated by "m_idx" up to "dis" grids away.
+
+#####GParameters
+> "m_idx" is the index of the monster in m_list[].
+> "dis" must not exceed 200. The distance teleported is a minimum of a
+ quarter of "dis".
+
+----------------------------------------------------------------------
+
+#####R=== teleport_player ===
+
+#####GDeclaration
+ extern void teleport_player(int dis);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport the player to a location up to "dis" grids away.
+ *
+ * If no such spaces are readily available, the distance may increase.
+ * Try very hard to move the player at least a quarter that distance.
+ */
+
+#####GDescription
+Teleport player up to "dis" grids away.
+
+#####GParameters
+> "dis" must not exceed 200. The distance teleported is a minimum of a
+ quarter of "dis".
+
+----------------------------------------------------------------------
+
+#####R=== teleport_player_to ===
+
+#####GDeclaration
+ extern void teleport_player_to(int ny, int nx);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport player to a grid near the given location
+ *
+ * This function is slightly obsessive about correctness.
+ * This function allows teleporting into vaults (!)
+ */
+
+#####GDescription
+Teleport player to a grid near the given location ("ny", "nx"). If
+the location is empty, the player goes there, otherwise they go to
+a grid as close as possible to the location.
+
+#####GParameters
+> "ny" is the y co-ordinate of the location.
+> "nx" is the x co-ordinate of the location.
+
+----------------------------------------------------------------------
+
+#####R=== teleport_monster_to ===
+
+#####GDeclaration
+ extern void teleport_monster_to(int m_idx, int ny,
+ int nx);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport a monster to a grid near the given location
+ *
+ * This function is slightly obsessive about correctness.
+ */
+
+#####GDescription
+Teleport monster indicated by "m_idx" to a grid near the given
+location ("ny", "nx"). If the location is empty, the monster goes
+there, otherwise they go to a grid as close as possible to the
+location.
+
+#####GParameters
+> "m_idx" is the index of the monster in m_list[].
+> "ny" is the y co-ordinate of the location.
+> "nx" is the x co-ordinate of the location.
+
+----------------------------------------------------------------------
+
+#####R=== teleport_player_level ===
+
+#####GDeclaration
+ extern void teleport_player_level(void);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Teleport the player one level up or down (random when legal)
+ */
+
+#####GDescription
+Teleport the player one level up or down at random.
+
+----------------------------------------------------------------------
+
+#####R=== recall_player ===
+
+#####GDeclaration
+ extern void recall_player(void);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Recall the player to town or dungeon
+ */
+
+#####GDescription
+Recall the player to town (if in dungeon) or dungeon (if in town).
+
+----------------------------------------------------------------------
+
+#####R=== take_hit ===
+
+#####GDeclaration
+ extern void take_hit(int damage, cptr kb_str);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Decreases players hit points and sets death flag if necessary
+ *
+ * XXX XXX XXX Invulnerability needs to be changed into a "shield"
+ *
+ * XXX XXX XXX Hack -- this function allows the user to save (or quit)
+ * the game when he dies, since the "You die." message is shown before
+ * setting the player to "dead".
+ */
+
+#####GDescription
+Reduce the player's current hit points by "damage" points. If the
+player dies, "kb_str" is used to record what the player was killed by
+(see high-score table).
+
+#####GParameters
+> "damage" is the amount of damage.
+> "kb_str" is a string describing what killed the player.
+
+----------------------------------------------------------------------
+
+#####R=== take_sanity_hit ===
+
+#####GDeclaration
+ extern void take_sanity_hit(int damage, cptr hit_from);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/* Decrease player's sanity. This is a copy of the function above. */
+
+#####GDescription
+Reduce the player's current sanity points by "damage" points. If the
+player dies, "hit_from" is used to record what the player was killed
+by (see high-score table).
+
+#####GParameters
+> "damage" is the amount of damage.
+> "hit_from" is a string describing what killed the player.
+
+----------------------------------------------------------------------
+
+#####R=== project ===
+
+#####GDeclaration
+ extern bool project(int who, int rad, int y, int x,
+ int dam, int typ, int flg);
+
+#####GFile
+ spells1.c
+
+#####GComment
+/*
+ * Generic "beam"/"bolt"/"ball" projection routine.
+ *
+ * Input:
+ * who: Index of "source" monster (negative for "player")
+ * jk -- -2 for traps, only used with project_jump
+ * rad: Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
+ * y,x: Target location (or location to travel "towards")
+ * dam: Base damage roll to apply to affected monsters (or player)
+ * typ: Type of damage to apply to monsters (and objects)
+ * flg: Extra bit flags (see PROJECT_xxxx in "defines.h")
+ *
+ * Return:
+ * TRUE if any "effects" of the projection were observed, else FALSE
+ *
+ * Allows a monster (or player) to project a beam/bolt/ball of a given kind
+ * towards a given location (optionally passing over the heads of interposing
+ * monsters), and have it do a given amount of damage to the monsters (and
+ * optionally objects) within the given radius of the final location.
+ *
+ * A "bolt" travels from source to target and affects only the target grid.
+ * A "beam" travels from source to target, affecting all grids passed through.
+ * A "ball" travels from source to the target, exploding at the target, and
+ * affecting everything within the given radius of the target location.
+ *
+ * Traditionally, a "bolt" does not affect anything on the ground, and does
+ * not pass over the heads of interposing monsters, much like a traditional
+ * missile, and will "stop" abruptly at the "target" even if no monster is
+ * positioned there, while a "ball", on the other hand, passes over the heads
+ * of monsters between the source and target, and affects everything except
+ * the source monster which lies within the final radius, while a "beam"
+ * affects every monster between the source and target, except for the casting
+ * monster (or player), and rarely affects things on the ground.
+ *
+ * Two special flags allow us to use this function in special ways, the
+ * "PROJECT_HIDE" flag allows us to perform "invisible" projections, while
+ * the "PROJECT_JUMP" flag allows us to affect a specific grid, without
+ * actually projecting from the source monster (or player).
+ *
+ * The player will only get "experience" for monsters killed by himself
+ * Unique monsters can only be destroyed by attacks from the player
+ *
+ * Only 256 grids can be affected per projection, limiting the effective
+ * "radius" of standard ball attacks to nine units (diameter nineteen).
+ *
+ * One can project in a given "direction" by combining PROJECT_THRU with small
+ * offsets to the initial location (see "line_spell()"), or by calculating
+ * "virtual targets" far away from the player.
+ *
+ * One can also use PROJECT_THRU to send a beam/bolt along an angled path,
+ * continuing until it actually hits something (useful for "stone to mud").
+ *
+ * Bolts and Beams explode INSIDE walls, so that they can destroy doors.
+ *
+ * Balls must explode BEFORE hitting walls, or they would affect monsters
+ * on both sides of a wall. Some bug reports indicate that this is still
+ * happening in 2.7.8 for Windows, though it appears to be impossible.
+ *
+ * We "pre-calculate" the blast area only in part for efficiency.
+ * More importantly, this lets us do "explosions" from the "inside" out.
+ * This results in a more logical distribution of "blast" treasure.
+ * It also produces a better (in my opinion) animation of the explosion.
+ * It could be (but is not) used to have the treasure dropped by monsters
+ * in the middle of the explosion fall "outwards", and then be damaged by
+ * the blast as it spreads outwards towards the treasure drop location.
+ *
+ * Walls and doors are included in the blast area, so that they can be
+ * "burned" or "melted" in later versions.
+ *
+ * This algorithm is intended to maximise simplicity, not necessarily
+ * efficiency, since this function is not a bottleneck in the code.
+ *
+ * We apply the blast effect from ground zero outwards, in several passes,
+ * first affecting features, then objects, then monsters, then the player.
+ * This allows walls to be removed before checking the object or monster
+ * in the wall, and protects objects which are dropped by monsters killed
+ * in the blast, and allows the player to see all affects before he is
+ * killed or teleported away. The semantics of this method are open to
+ * various interpretations, but they seem to work well in practice.
+ *
+ * We process the blast area from ground-zero outwards to allow for better
+ * distribution of treasure dropped by monsters, and because it provides a
+ * pleasing visual effect at low cost.
+ *
+ * Note that the damage done by "ball" explosions decreases with distance.
+ * This decrease is rapid, grids at radius "dist" take "1/dist" damage.
+ *
+ * Notice the "napalm" effect of "beam" weapons. First they "project" to
+ * the target, and then the damage "flows" along this beam of destruction.
+ * The damage at every grid is the same as at the "centre" of a "ball"
+ * explosion, since the "beam" grids are treated as if they ARE at the
+ * centre of a "ball" explosion.
+ *
+ * Currently, specifying "beam" plus "ball" means that locations which are
+ * covered by the initial "beam", and also covered by the final "ball", except
+ * for the final grid (the epicentre of the ball), will be "hit twice", once
+ * by the initial beam, and once by the exploding ball. For the grid right
+ * next to the epicentre, this results in 150% damage being done. The centre
+ * does not have this problem, for the same reason the final grid in a "beam"
+ * plus "bolt" does not -- it is explicitly removed. Simply removing "beam"
+ * grids which are covered by the "ball" will NOT work, as then they will
+ * receive LESS damage than they should. Do not combine "beam" with "ball".
+ *
+ * The array "gy[],gx[]" with current size "grids" is used to hold the
+ * collected locations of all grids in the "blast area" plus "beam path".
+ *
+ * Note the rather complex usage of the "gm[]" array. First, gm[0] is always
+ * zero. Second, for N>1, gm[N] is always the index (in gy[],gx[]) of the
+ * first blast grid (see above) with radius "N" from the blast centre. Note
+ * that only the first gm[1] grids in the blast area thus take full damage.
+ * Also, note that gm[rad+1] is always equal to "grids", which is the total
+ * number of blast grids.
+ *
+ * Note that once the projection is complete, (y2,x2) holds the final location
+ * of bolts/beams, and the "epicentre" of balls.
+ *
+ * Note also that "rad" specifies the "inclusive" radius of projection blast,
+ * so that a "rad" of "one" actually covers 5 or 9 grids, depending on the
+ * implementation of the "distance" function. Also, a bolt can be properly
+ * viewed as a "ball" with a "rad" of "zero".
+ *
+ * Note that if no "target" is reached before the beam/bolt/ball travels the
+ * maximum distance allowed (MAX_RANGE), no "blast" will be induced. This
+ * may be relevant even for bolts, since they have a "1x1" mini-blast.
+ *
+ * Note that for consistency, we "pretend" that the bolt actually takes "time"
+ * to move from point A to point B, even if the player cannot see part of the
+ * projection path. Note that in general, the player will *always* see part
+ * of the path, since it either starts at the player or ends on the player.
+ *
+ * Hack -- we assume that every "projection" is "self-illuminating".
+ *
+ * Hack -- when only a single monster is affected, we automatically track
+ * (and recall) that monster, unless "PROJECT_JUMP" is used.
+ *
+ * Note that all projections now "explode" at their final destination, even
+ * if they were being projected at a more distant destination. This means
+ * that "ball" spells will *always* explode.
+ *
+ * Note that we must call "handle_stuff()" after affecting terrain features
+ * in the blast radius, in case the "illumination" of the grid was changed,
+ * and "update_view()" and "update_monsters()" need to be called.
+ */
+
+#####GDescription
+Generate a beam/bolt/ball starting from "who" with a radius of "rad"
+at target grid "y,x" for "damage" points of "typ" damage. The beam/
+bolt/ball can have various properties as denoted by "flg".
+
+#####GParameters
+> "who" is > 0 (index of monster in m_list[]), < 0 and
+ not -100 or -101 (player), -100 or -101 (trap).
+> "rad" is 0 for a beam/bolt and 1-9 for a ball.
+> "y" is the y co-ordinate of the target grid.
+> "x" is the x co-ordinate of the target grid.
+> "dam" is the number of points of damage.
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "flg" is the projection effect
+ *****fields.txt*0[PROJECT_fields]
+
+----------------------------------------------------------------------
+
+#####R=== corrupt_player ===
+
+#####GDeclaration
+ extern void corrupt_player(void);
+
+#####GFile
+ spells1.c
+
+#####GComment
+(none)
+
+#####GDescription
+Swap two of the players stats at random.
+
+----------------------------------------------------------------------
+
+#####R=== grow_trees ===
+
+#####GDeclaration
+ extern void grow_trees(int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Grow trees
+ */
+
+#####GDescription
+Grow up to (("rad" x "rad") + 11) trees around the player.
+
+#####GParameters
+> "rad" is the radius of the area where trees may grow.
+
+----------------------------------------------------------------------
+
+#####R=== hp_player ===
+
+#####GDeclaration
+ extern bool hp_player(int num);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Increase players hit points, notice effects
+ */
+
+#####GDescription
+Add "num" points to the player's current hit points. The total can
+not exceed the maximum.
+
+#####GParameters
+> "num" is the number of points to add.
+
+----------------------------------------------------------------------
+
+#####R=== heal_insanity ===
+
+#####GDeclaration
+ extern bool heal_insanity(int val);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/* Heal insanity. */
+
+#####GDescription
+Add "val" points to the player's current sanity points. The total can
+not exceed the maximum.
+
+#####GParameters
+> "val" is the number of points to add.
+
+----------------------------------------------------------------------
+
+#####R=== warding_glyph ===
+
+#####GDeclaration
+ extern void warding_glyph(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Leave a "glyph of warding" which prevents monster movement
+ */
+
+#####GDescription
+Place a glyph at the player's location. The location must be bare.
+
+----------------------------------------------------------------------
+
+#####R=== explosive_rune ===
+
+#####GDeclaration
+ extern void explosive_rune(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Place a minor glyph (explosive rune) at the player's location. The
+location must be bare.
+
+----------------------------------------------------------------------
+
+#####R=== do_dec_stat ===
+
+#####GDeclaration
+ extern bool do_dec_stat(int stat, int mode);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Lose a "point"
+ */
+
+#####GDescription
+Attempt to reduce the player's "stat" statistic by a point.
+
+#####GParameters
+> "stat" is the statistic
+ *****fields.txt*0[A_fields]
+> "mode" is the type of decrease: temporary, normal, or permanent
+ *****fields.txt*0[STAT_DEC_fields]
+
+----------------------------------------------------------------------
+
+#####R=== do_res_stat ===
+
+#####GDeclaration
+ extern bool do_res_stat(int stat);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Restore lost "points" in a stat
+ */
+
+#####GDescription
+Restore the player's "stat" statistic.
+
+#####GParameters
+> "stat" is the statistic
+ *****fields.txt*0[A_fields]
+
+----------------------------------------------------------------------
+
+#####R=== do_inc_stat ===
+
+#####GDeclaration
+ extern bool do_inc_stat(int stat);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Gain a "point" in a stat
+ */
+
+#####GDescription
+Increase the player's "stat" statistic by a point.
+
+#####GParameters
+> "stat" is the statistic
+ *****fields.txt*0[A_fields]
+
+----------------------------------------------------------------------
+
+#####R=== identify_pack ===
+
+#####GDeclaration
+ extern void identify_pack(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Identify everything being carried.
+ * Done by a potion of "self knowledge".
+ */
+
+#####GDescription
+Identify all items in the inventory.
+
+----------------------------------------------------------------------
+
+#####R=== remove_curse ===
+
+#####GDeclaration
+ extern bool remove_curse(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Remove most curses
+ */
+
+#####GDescription
+Remove all curses except for heavy curses.
+
+----------------------------------------------------------------------
+
+#####R=== remove_all_curse ===
+
+#####GDeclaration
+ extern bool remove_all_curse(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Remove all curses
+ */
+
+#####GDescription
+Remove all curses including heavy curses.
+
+----------------------------------------------------------------------
+
+#####R=== restore_level ===
+
+#####GDeclaration
+ extern bool restore_level(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Restores any drained experience
+ */
+
+#####GDescription
+Restore all drained experience points (if any).
+
+----------------------------------------------------------------------
+
+#####R=== self_knowledge ===
+
+#####GDeclaration
+ extern void self_knowledge(FILE *fff);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * self-knowledge... idea from nethack. Useful for determining powers and
+ * resistances of items. It saves the screen, clears it, then starts listing
+ * attributes, a screenful at a time. (There are a LOT of attributes to
+ * list. It will probably take 2 or 3 screens for a powerful character whose
+ * using several artifacts...) -CFT
+ *
+ * It is now a lot more efficient. -BEN-
+ *
+ * See also "identify_fully()".
+ *
+ * XXX XXX XXX Use the "show_file()" method, perhaps.
+ */
+
+#####GDescription
+Show all attributes including racial powers, mutations, and equipment
+effects.
+
+#####GParameters
+> "*ffff" points to a file (write info to file) or is NULL (write info
+ to screen).
+
+----------------------------------------------------------------------
+
+#####R=== lose_all_info ===
+
+#####GDeclaration
+ extern bool lose_all_info(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Forget everything
+ */
+
+#####GDescription
+Forget about objects and the map.
+
+----------------------------------------------------------------------
+
+#####R=== detect_traps ===
+
+#####GDeclaration
+ extern bool detect_traps(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all traps on current panel
+ */
+
+#####GDescription
+Detect all traps on current panel.
+
+----------------------------------------------------------------------
+
+#####R=== detect_doors ===
+
+#####GDeclaration
+ extern bool detect_doors(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all doors on current panel
+ */
+
+#####GDescription
+Detect all doors on current panel.
+
+----------------------------------------------------------------------
+
+#####R=== detect_stairs ===
+
+#####GDeclaration
+ extern bool detect_stairs(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all stairs on current panel
+ */
+
+#####GDescription
+Detect all stairs on current panel.
+
+----------------------------------------------------------------------
+
+#####R=== detect_treasure ===
+
+#####GDeclaration
+ extern bool detect_treasure(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect any treasure on the current panel
+ */
+
+#####GDescription
+Detect any treasure on the current panel.
+
+----------------------------------------------------------------------
+
+Field: hack_no_detect_message
+Value: FALSE
+
+----------------------------------------------------------------------
+
+#####R=== detect_objects_gold ===
+
+#####GDeclaration
+ extern bool detect_objects_gold(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "gold" objects on the current panel
+ */
+
+#####GDescription
+Detect all objects with the TV_GOLD flag.
+
+----------------------------------------------------------------------
+
+#####R=== detect_objects_normal ===
+
+#####GDeclaration
+ extern bool detect_objects_normal(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "normal" objects on the current panel
+ */
+
+#####GDescription
+Detect all objects without the TV_GOLD flag.
+
+----------------------------------------------------------------------
+
+#####R=== detect_objects_magic ===
+
+#####GDeclaration
+ extern bool detect_objects_magic(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "magic" objects on the current panel.
+ *
+ * This will light up all spaces with "magic" items, including artifacts,
+ * ego-items, potions, scrolls, books, rods, wands, staves, amulets, rings,
+ * and "enchanted" items of the "good" variety.
+ *
+ * It can probably be argued that this function is now too powerful.
+ */
+
+#####GDescription
+Detect all "magic" objects which are artefacts, ego items, or have one
+of the following flags - TV_AMULET, TV_RING, TV_BATERIE, TV_STAFF,
+TV_WAND, TV_ROD, TV_ROD_MAIN, TV_SCROLL, TV_POTION, TV_POTION2,
+TV_VALARIN_BOOK, TV_MAGERY_BOOK, TV_SHADOW_BOOK, TV_CHAOS_BOOK,
+TV_SPIRIT_BOOK, TV_NETHER_BOOK, TV_DAEMON_BOOK, TV_CRUSADE_BOOK,
+TV_SIGALDRY_BOOK, TV_SYMBIOTIC_BOOK, TV_MUSIC_BOOK.
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_normal ===
+
+#####GDeclaration
+ extern bool detect_monsters_normal(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "normal" monsters on the current panel
+ */
+
+#####GDescription
+Detect all non-invisible monsters (without RF2_INVISIBLE).
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_invis ===
+
+#####GDeclaration
+ extern bool detect_monsters_invis(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "invisible" monsters on current panel
+ */
+
+#####GDescription
+Detect all invisible monsters (with RF2_INVISIBLE).
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_evil ===
+
+#####GDeclaration
+ extern bool detect_monsters_evil(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "evil" monsters on current panel
+ */
+
+#####GDescription
+Detect all evil monsters (with RF3_EVIL).
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_good ===
+
+#####GDeclaration
+ extern bool detect_monsters_good(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/* Detect good monsters */
+
+#####GDescription
+Detect all good monsters (with RF3_GOOD).
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_xxx ===
+
+#####GDeclaration
+ extern bool detect_monsters_xxx(u32b match_flag);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * A "generic" detect monsters routine, tagged to flags3
+ */
+
+#####GDescription
+Detect all monsters with "match_flag" flag.
+
+#####GParameters
+> "match_flag" can be any RF3_ flag (see defines.h) but only
+ RF3_DEMON, RF3_UNDEAD, RF3_GOOD work.
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_string ===
+
+#####GDeclaration
+ extern bool detect_monsters_string(cptr);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all (string) monsters on current panel
+ */
+
+#####GDescription
+Detect all monsters whose default monster character matches a
+character pointed to by "cptr".
+
+#####GParameters
+> "cptr" is a pointer to a single character, eg 'Z' for hounds. For
+ available characters, see the "symbol" field of the graphics (G)
+ line of r_info.txt.
+
+----------------------------------------------------------------------
+
+#####R=== detect_monsters_nonliving ===
+
+#####GDeclaration
+ extern bool detect_monsters_nonliving(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect all "nonliving", "undead" or "demonic" monsters on current panel
+ */
+
+#####GDescription
+Detect all non-living monsters (with RF3_NONLIVING, RF3_UNDEAD, or
+RF3_DEMON).
+
+----------------------------------------------------------------------
+
+#####R=== detect_all ===
+
+#####GDeclaration
+ extern bool detect_all(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Detect everything
+ */
+
+#####GDescription
+Detects traps, doors, stairs, treasure, gold objects, normal objects,
+invisible monsters, normal (visible) monsters.
+
+----------------------------------------------------------------------
+
+#####R=== stair_creation ===
+
+#####GDeclaration
+ extern void stair_creation(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Create stairs at the player location
+ */
+
+#####GDescription
+Create stairs at the player location. This is not allowed if the grid
+is not empty, the player is not in a dungeon, the player is on a
+special level, the player is in an arena or quest. If the player is
+in the town or wilderness the stairs will go down. If the player is
+on a quest level or at the bottom of a dungeon, the stairs will go up.
+Otherwise there is an even chance the stairs will go up or down.
+
+----------------------------------------------------------------------
+
+#####R=== wall_stone ===
+
+#####GDeclaration
+ extern bool wall_stone(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Create a stone wall on the player's grid. This function uses the
+project() function to create the stone wall. Apparently zero can be
+used as the "who" parameter for the player. See details for the
+project() function elsewhere in this document.
+
+----------------------------------------------------------------------
+
+#####R=== create_artifact ===
+
+#####GDeclaration
+ extern bool create_artifact(object_type *o_ptr,
+ bool a_scroll, bool get_name);
+
+#####GFile
+ randart.c
+
+#####GComment
+(none)
+
+#####GDescription
+Create an artifact from object "*optr".
+
+#####GParameters
+> "*optr* is a pointer to an object
+> "a_scroll" is true if the artifact is created by reading a scroll
+> "get_name" is true if the artifact is to be named by the player (if
+ a_scroll is true) or created randomly (a_scroll is false), or false
+ if an inscription is used.
+
+----------------------------------------------------------------------
+
+#####R=== ident_spell ===
+
+#####GDeclaration
+ extern bool ident_spell(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Identify an object in the inventory (or on the floor)
+ * This routine does *not* automatically combine objects.
+ * Returns TRUE if something was identified, else FALSE.
+ */
+
+#####GDescription
+Identify an object in the inventory (or on the floor).
+
+----------------------------------------------------------------------
+
+#####R=== identify_fully ===
+
+#####GDeclaration
+ extern bool identify_fully(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Fully "identify" an object in the inventory -BEN-
+ * This routine returns TRUE if an item was identified.
+ */
+
+#####GDescription
+Fully "identify" an object in the inventory (or on the floor).
+
+----------------------------------------------------------------------
+
+#####R=== recharge ===
+
+#####GDeclaration
+ extern bool recharge(int num);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Recharge a wand/staff/rod from the pack or on the floor.
+ * This function has been rewritten in Oangband. -LM-
+ *
+ * Mage -- Recharge I --> recharge(90)
+ * Mage -- Recharge II --> recharge(150)
+ * Mage -- Recharge III --> recharge(220)
+ *
+ * Priest or Necromancer -- Recharge --> recharge(140)
+ *
+ * Scroll of recharging --> recharge(130)
+ * Scroll of *recharging* --> recharge(200)
+ *
+ * It is harder to recharge high level, and highly charged wands,
+ * staffs, and rods. The more wands in a stack, the more easily and
+ * strongly they recharge. Staffs, however, each get fewer charges if
+ * stacked.
+ *
+ * XXX XXX XXX Beware of "sliding index errors".
+ */
+
+#####GDescription
+Recharge an object in the inventory (or on the floor) with "num"
+power.
+
+#####GParameters
+> "num" is the power used in recharging. It is compared to the
+ object's level to determine whether the item is recharged
+ successfully or destroyed. If it is recharged, it also determines
+ how many charges are added, or how much recharge time is reduced.
+
+----------------------------------------------------------------------
+
+#####R=== aggravate_monsters ===
+
+#####GDeclaration
+ extern void aggravate_monsters(int who);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Wake up all monsters, and speed up "los" monsters.
+ */
+
+#####GDescription
+Aggravate monsters, originating from "who".
+
+#####GParameters
+> "who" is the index of monster in m_list[] (1 if it is the player)
+ which triggers the aggravation;
+
+----------------------------------------------------------------------
+
+#####R=== genocide ===
+
+#####GDeclaration
+ extern bool genocide(bool player_cast);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Genocide a monster race.
+
+#####GParameters
+> "player_cast" is true if the player cast the spell so the player can
+ take damage.
+
+----------------------------------------------------------------------
+
+#####R=== mass_genocide ===
+
+#####GDeclaration
+ extern bool mass_genocide(bool player_cast);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Delete all nearby (non-unique) monsters
+ */
+
+#####GDescription
+Delete all nearby (non-unique) monsters.
+
+#####GParameters
+> "player_cast" is true if the player cast the spell so the player can
+ take damage.
+
+----------------------------------------------------------------------
+
+#####R=== probing ===
+
+#####GDeclaration
+ extern bool probing(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Probe nearby monsters
+ */
+
+#####GDescription
+Probe all nearby monsters.
+
+----------------------------------------------------------------------
+
+#####R=== banish_evil ===
+
+#####GDeclaration
+ extern bool banish_evil(int dist);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Banish evil monsters
+ */
+
+#####GDescription
+Banish nearby evil monsters doing "dist" points of GF_AWAY_EVIL
+damage.
+
+#####GParameters
+> "dist" is the amount of damage done to each monster.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_evil ===
+
+#####GDeclaration
+ extern bool dispel_evil(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel evil monsters
+ */
+
+#####GDescription
+Dispel nearby evil monsters doing "dam" points of GF_DISP_EVIL
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_good ===
+
+#####GDeclaration
+ extern bool dispel_good(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel good monsters
+ */
+
+#####GDescription
+Dispel nearby good monsters doing "dam" points of GF_DISP_GOOD
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_undead ===
+
+#####GDeclaration
+ extern bool dispel_undead(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel undead monsters
+ */
+
+#####GDescription
+Dispel nearby undead monsters doing "dam" points of GF_DISP_UNDEAD
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_monsters ===
+
+#####GDeclaration
+ extern bool dispel_monsters(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel all monsters
+ */
+
+#####GDescription
+Dispel all nearby monsters doing "dam" points of GF_DISP_ALL
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_living ===
+
+#####GDeclaration
+ extern bool dispel_living(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel 'living' monsters
+ */
+
+#####GDescription
+Dispel nearby living monsters doing "dam" points of GF_DISP_LIVING
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== dispel_demons ===
+
+#####GDeclaration
+ extern bool dispel_demons(int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Dispel demons
+ */
+
+#####GDescription
+Dispel nearby demon monsters doing "dam" points of GF_DISP_DEMON
+damage.
+
+#####GParameters
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== turn_undead ===
+
+#####GDeclaration
+ extern bool turn_undead(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Turn undead
+ */
+
+#####GDescription
+Turn nearby undead monsters doing a point of GF_TURN_UNDEAD damage for
+each player level.
+
+----------------------------------------------------------------------
+
+#####R=== wipe ===
+
+#####GDeclaration
+ extern void wipe(int y1, int x1, int r);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Wipe -- Empties a part of the dungeon
+ */
+
+#####GDescription
+Delete monsters and objects from an area of the dungeon centred at
+grid "y1,x1" for a radius "r". This does not work on special levels or
+quests. The player may be blinded. The player forgets the affected
+area and it becomes dark. All grids become floor.
+
+#####GParameters
+> "y1" is the y-coordinate of the wipe's origin.
+> "x1" is the x-coordinate of the wipe's origin.
+> "r" is the radius of the wipe.
+
+----------------------------------------------------------------------
+
+#####R=== destroy_area ===
+
+#####GDeclaration
+ extern void destroy_area(int y1, int x1, int r,
+ bool full);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * The spell of destruction
+ *
+ * This spell "deletes" monsters (instead of "killing" them).
+ *
+ * Later we may use one function for both "destruction" and
+ * "earthquake" by using the "full" to select "destruction".
+ */
+
+#####GDescription
+Delete monsters and objects from an area of the dungeon centred at
+grid "y1,x1" for a radius "r". This does not work on special levels or
+quests. The epicentre is NOT affected. The player may be blinded. The
+player forgets the affected area and it becomes dark. The grids can
+become granite, quartz, magma, or floor.
+
+#####GParameters
+> "y1" is the y-coordinate of the destruction's origin.
+> "x1" is the x-coordinate of the destruction's origin.
+> "r" is the radius of the destruction.
+> "full" is currently unused.
+
+----------------------------------------------------------------------
+
+#####R=== earthquake ===
+
+#####GDeclaration
+ extern void earthquake(int cy, int cx, int r);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Induce an "earthquake" of the given radius at the given location.
+ *
+ * This will turn some walls into floors and some floors into walls.
+ *
+ * The player will take damage and "jump" into a safe grid if possible,
+ * otherwise, he will "tunnel" through the rubble instantaneously.
+ *
+ * Monsters will take damage, and "jump" into a safe grid if possible,
+ * otherwise they will be "buried" in the rubble, disappearing from
+ * the level in the same way that they do when genocided.
+ *
+ * Note that thus the player and monsters (except eaters of walls and
+ * passers through walls) will never occupy the same grid as a wall.
+ * Note that as of now (2.7.8) no monster may occupy a "wall" grid, even
+ * for a single turn, unless that monster can pass_walls or kill_walls.
+ * This has allowed massive simplification of the "monster" code.
+ */
+
+#####GDescription
+Create an earthquake centred on grid "cy,cx" with a radius of "r".
+This does not work on quest levels. The epicentre is NOT affected.
+Only about 15% of the grids are affected. The player takes 300 points
+of damage if they can't be moved to a safe grid, otherwise damage is
+from 10 to 40 points. The player forgets the affected area and it
+becomes dark. The grids can become granite, quartz, magma, or floor.
+
+#####GParameters
+Parameters:
+> "cy" is the y-coordinate of the earthquake origin.
+> "cx" is the x-coordinate of the earthquake origin.
+> "r" is the radius of the earthquake.
+
+----------------------------------------------------------------------
+
+#####R=== map_area ===
+
+#####GDeclaration
+ extern void map_area(void);
+
+#####GFile
+ cave.c
+
+#####GComment
+/*
+ * Hack -- map the current panel (plus some) ala "magic mapping"
+ */
+
+#####GDescription
+Map the current panel plus up to 10 grids up and down, and up to 20
+grids left and right.
+
+----------------------------------------------------------------------
+
+#####R=== wiz_lite ===
+
+#####GDeclaration
+ extern void wiz_lite(void);
+
+#####GFile
+ cave.c
+
+#####GComment
+/*
+ * Light up the dungeon using "clairvoyance"
+ *
+ * This function "illuminates" every grid in the dungeon, memorises all
+ * "objects", memorises all grids as with magic mapping, and, under the
+ * standard option settings (view_perma_grids but not view_torch_grids)
+ * memorises all floor grids too.
+ *
+ * Note that if "view_perma_grids" is not set, we do not memorise floor
+ * grids, since this would defeat the purpose of "view_perma_grids", not
+ * that anyone seems to play without this option.
+ *
+ * Note that if "view_torch_grids" is set, we do not memorise floor grids,
+ * since this would prevent the use of "view_torch_grids" as a method to
+ * keep track of what grids have been observed directly.
+ */
+
+#####GDescription
+Light up the entire dungeon and show all monsters and objects.
+
+----------------------------------------------------------------------
+
+#####R=== wiz_lite_extra ===
+
+#####GDeclaration
+ extern void wiz_lite_extra(void);
+
+#####GFile
+ cave.c
+
+#####GComment
+(none)
+
+#####GDescription
+Light up the entire dungeon and show all monsters and objects. All
+squares are lit and remembered.
+
+----------------------------------------------------------------------
+
+#####R=== wiz_dark ===
+
+#####GDeclaration
+ extern void wiz_dark(void);
+
+#####GFile
+ cave.c
+
+#####GComment
+/*
+ * Forget the dungeon map (ala "Thinking of Maud...").
+ */
+
+#####GDescription
+Forget all grids and objects. All grids become dark.
+
+----------------------------------------------------------------------
+
+#####R=== lite_room ===
+
+#####GDeclaration
+ extern void lite_room(int y1, int x1);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Illuminate any room containing the given location.
+ */
+
+#####GDescription
+Light up the room (if any) of grid "y1,x1".
+
+#####GParameters
+> "y1" is the y-coordinate of the grid.
+> "x1" is the x-coordinate of the grid.
+
+----------------------------------------------------------------------
+
+#####R=== unlite_room ===
+
+#####GDeclaration
+ extern void unlite_room(int y1, int x1);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Darken all rooms containing the given location
+ */
+
+#####GDescription
+Darken all rooms (if any) of grid "y1,x1".
+
+#####GParameters
+> "y1" is the y-coordinate of the grid.
+> "x1" is the x-coordinate of the grid.
+
+----------------------------------------------------------------------
+
+#####R=== lite_area ===
+
+#####GDeclaration
+ extern bool lite_area(int dam, int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Hack -- call light around the player
+ * Affect all monsters in the projection radius
+ */
+
+#####GDescription
+Light up the room (if any) of the player's grid. Monsters take "dam"
+points of GF_LITE_WEAK damage if they are within "r" grids of the
+player.
+
+#####GParameters
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage.
+
+----------------------------------------------------------------------
+
+#####R=== unlite_area ===
+
+#####GDeclaration
+ extern bool unlite_area(int dam, int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Hack -- call darkness around the player
+ * Affect all monsters in the projection radius
+ */
+
+#####GDescription
+Darken the room (if any) of the player's grid. Monsters take "dam"
+points of GF_DARK_WEAK damage if they are within "r" grids of the
+player.
+
+#####GParameters
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_ball_beam ===
+
+#####GDeclaration
+ extern bool fire_ball_beam(int typ, int dir, int dam,
+ int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a ball-beamed spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+
+#####GDescription
+Cast a ball-beamed spell of type "typ" in direction "dir" for damage
+"dam" points with a radius of "rad" grids.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage (must be <= 16).
+
+----------------------------------------------------------------------
+
+#####R=== fire_ball ===
+
+#####GDeclaration
+ extern bool fire_ball(int typ, int dir, int dam, int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a ball spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+
+#####GDescription
+Cast a ball spell of type "typ" in direction "dir" for "dam" points of
+damage. The ball has a radius of "rad" grids.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage (must be <= 16).
+
+----------------------------------------------------------------------
+
+#####R=== fire_bolt ===
+
+#####GDeclaration
+ extern bool fire_bolt(int typ, int dir, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a bolt spell
+ * Stop if we hit a monster, as a "bolt"
+ * Affect monsters (not grids or objects)
+ */
+
+#####GDescription
+Cast a bolt spell of type "typ" in direction "dir" for "dam" points of
+damage.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_beam ===
+
+#####GDeclaration
+ extern bool fire_beam(int typ, int dir, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a beam spell
+ * Pass through monsters, as a "beam"
+ * Affect monsters (not grids or objects)
+ */
+
+#####GDescription
+Cast a beam spell of type "typ" in direction "dir" for "dam" points of
+damage.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_druid_ball ===
+
+#####GDeclaration
+ extern bool fire_druid_ball(int typ, int dir, int dam,
+ int rad);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a druidic ball spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+
+#####GDescription
+Cast a ball spell of type "typ" in direction "dir" for "dam" points of
+damage. The ball has a radius of "rad" grids. The spell follows a mana
+path.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+> "rad" is the radius of the effect of the damage (must be <= 16).
+
+----------------------------------------------------------------------
+
+#####R=== fire_druid_bolt ===
+
+#####GDeclaration
+ extern bool fire_druid_bolt(int typ, int dir, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a druidic bolt spell
+ * Stop if we hit a monster, as a "bolt"
+ * Affect monsters (not grids or objects)
+ */
+
+#####GDescription
+Cast a bolt spell of type "typ" in direction "dir" for "dam" points of
+damage. The spell follows a mana path.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_druid_beam ===
+
+#####GDeclaration
+ extern bool fire_druid_beam(int typ, int dir, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a druidistic beam spell
+ * Pass through monsters, as a "beam"
+ * Affect monsters (not grids or objects)
+ */
+
+#####GDescription
+Cast a beam spell of type "typ" in direction "dir" for "dam" points of
+damage. The spell follows a mana path.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== fire_bolt_or_beam ===
+
+#####GDeclaration
+ extern bool fire_bolt_or_beam(int prob, int typ, int dir,
+ int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Cast a bolt spell, or rarely, a beam spell
+ */
+
+#####GDescription
+Cast a beam (chance of "prob" in 100) or bolt spell of type "typ" in
+direction "dir" for "dam" points of damage.
+
+#####GParameters
+> "prob" is the number of times out of 100 that the bolt will actually
+ be a beam. Obviously this value should range from 1 to 99 (0 will
+ always give a beam, 100 or higher will always give a beam. There are
+ separate functions for these cases).
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+#####R=== alchemy ===
+
+#####GDeclaration
+ extern bool alchemy(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/* Turns an object into gold, gain some of its value in a shop */
+
+#####GDescription
+The player selects an object (and quantity if it applies) from the
+inventory or the floor and attempts to turn it into gold. If the
+price of the item is < 0 then the player gains nothing (fool's gold),
+otherwise the player gets a third of the price in gold. Artifacts are
+not affected.
+
+----------------------------------------------------------------------
+
+#####R=== alter_reality ===
+
+#####GDeclaration
+ extern void alter_reality(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+The player leaves the level immediately.
+
+----------------------------------------------------------------------
+
+#####R=== teleport_swap ===
+
+#####GDeclaration
+ extern void teleport_swap(int dir);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Player swaps places with target in direction "dir". The target must be
+a monster. It will not work if the space-time continuum can not be
+disrupted or if the monster resists teleportation.
+
+----------------------------------------------------------------------
+
+#####R=== project_meteor ===
+
+#####GDeclaration
+ extern void project_meteor(int radius, int typ, int dam,
+ u32b flg);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Apply a "project()" a la meteor shower
+ */
+
+#####GDescription
+Generate between "rad" and "rad" x 2 ball spells of type "typ" for
+"dam" points of damage. The ball can have various properties as
+denoted by "flg".
+
+#####GParameters
+> "rad" is the minimum number of balls created. "rad" + randint("rad")
+ balls are created. Each ball has a radius of 2 grids. Each target
+ grid is within 5 grids of the player.
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dam" is the number of points of damage.
+> "flg" is the projection effect
+ *****fields.txt*0[PROJECT_fields]
+
+----------------------------------------------------------------------
+
+#####R=== passwall ===
+
+#####GDeclaration
+ extern bool passwall(int dir, bool safe);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Send the player shooting through walls in the given direction until
+ * they reach a non-wall space, or a monster, or a permanent wall.
+ */
+
+#####GDescription
+Move the player through walls in direction "dir". if "safe" then the
+player can not end up in a wall - if they do, the wall is replaced by
+a floor. This does not work in the wilderness, on quest levels, or if
+teleport is not allowed. Stopping on monsters or inside vaults is not
+allowed.
+
+#####GParameters
+> "dir" must be from 0 to 9. It can not be 5.
+ *****fields.txt*0[direction]
+> "safe" must be true if the player is not to be trapped in a wall
+ when the movement is finished.
+
+----------------------------------------------------------------------
+
+#####R=== project_hook ===
+
+#####GDeclaration
+ extern bool project_hook(int typ, int dir, int dam,
+ int flg);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Hack -- apply a "projection()" in a direction (or at the target)
+ */
+
+#####GDescription
+Generate a beam/bolt of type "typ" in direction "dir" (or at a target)
+for "dam" points of damage. The beam/bolt can have various properties
+as denoted by "flg".
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dir" must be from 0 to 9. 5 means use the current target.
+ *****fields.txt*0[direction]
+> "dam" is the number of points of damage.
+> "flg" is the projection effect
+ *****fields.txt*0[PROJECT_fields]
+
+----------------------------------------------------------------------
+
+#####R=== reset_recall ===
+
+#####GDeclaration
+ extern bool reset_recall(void);
+
+#####GFile
+ spells2.c
+
+#####GComment
+(none)
+
+#####GDescription
+Ask the player for a dungeon and appropriate level within the dungeon.
+The player can not specify a dungeon they have not gone to yet. If the
+player chooses levels 99 or 100, the level is set to 98.
+
+----------------------------------------------------------------------
+
+#####R=== get_aim_dir ===
+
+#####GDeclaration
+ extern bool get_aim_dir(int *dp = 0);
+
+#####GFile
+ xtra2.c
+
+#####GComment
+/*
+ * Get an "aiming direction" from the user.
+ *
+ * The "dir" is loaded with 1,2,3,4,6,7,8,9 for "actual direction", and
+ * "0" for "current target", and "-1" for "entry aborted".
+ *
+ * Note that "Force Target", if set, will pre-empt user interaction,
+ * if there is a usable target already set.
+ *
+ * Note that confusion over-rides any (explicit?) user choice.
+ */
+
+#####GDescription
+Get an aiming direction from the user and store it in "dp". A target
+can be selected. If the player is confused, the direction will be
+random.
+
+#####GParameters
+> "dp" = player direction.
+
+----------------------------------------------------------------------
+
+#####R=== project_hack ===
+
+#####GDeclaration
+ extern bool project_hack(int typ, int dam);
+
+#####GFile
+ spells2.c
+
+#####GComment
+/*
+ * Apply a "project()" directly to all viewable monsters
+ *
+ * Note that affected monsters are NOT auto-tracked by this usage.
+ */
+
+#####GDescription
+Generate beam/bolt spells of type "typ" for "dam" points of damage to
+all viewable monsters in line of site.
+
+#####GParameters
+> "typ" is the type of damage
+ *****fields.txt*0[GF_fields]
+> "dam" is the number of points of damage.
+
+----------------------------------------------------------------------
+
+
+Back to the *****lua.hlp*0[lua help index] .
+
+ [[[[[gThis file by Chris Hadgis]
diff --git a/lib/mods/theme/help/lua_util.txt b/lib/mods/theme/help/lua_util.txt
new file mode 100644
index 00000000..8886a2b4
--- /dev/null
+++ b/lib/mods/theme/help/lua_util.txt
@@ -0,0 +1,898 @@
+|||||oy
+
+#####R /----------------------------------------\
+#####R < util.pkg functions helper file >
+#####R \----------------------------------------/
+
+----------------------------------------------------------------------
+
+#####R=== bst ===
+
+#####GDeclaration
+ s32b bst(s32b what, s32b t);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Break scalar time
+ */
+
+#####GDescription
+Return the minute, hour, day, or year for turn "t". One turn takes 7.5
+seconds.
+
+#####GParameters
+> "what" is the unit to be returned and must be one of
+ MINUTE (number of turns per minute, which is 8)
+ HOUR (number of turns per hour, which is 480)
+ DAY (number of turns per day, which is 11,520)
+ YEAR (number of turns per year, which is 4,204,800)
+> "t" is the number of turns.
+
+----------------------------------------------------------------------
+
+#####R=== path_build ===
+
+#####GDeclaration
+ errr path_build(char *buf, int max, cptr path, cptr file);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Create a new path by appending a file (or directory) to a path
+*
+* This requires no special processing on simple machines, except
+* for verifying the size of the filename, but note the ability to
+* bypass the given "path" with certain special file-names.
+*
+* Note that the "file" may actually be a "sub-path", including
+* a path and a file.
+*
+* Note that this function yields a path which must be "parsed"
+* using the "parse" function above.
+*/
+
+#####GDescription
+Append file "file" to path "path" and return the result in "buf". The
+length of "buf" is a maximum of "max" characters. If "file" starts
+with '~' then return "file". If "file" starts with the path separator
+and the path separator is not blank then return "file". If there is no
+path then return "file". Otherwise return "path" + path separator +
+"file". The path separator is defined in "H-config.h".
+
+#####GParameters
+> "buf" contains the new path.
+> "max" is the maximum number of characters allowed in "buf".
+> "path" is the original path.
+> "file" is the original file.
+
+----------------------------------------------------------------------
+
+#####R=== move_cursor ===
+
+#####GDeclaration
+ void move_cursor(int row, int col);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Move the cursor
+*/
+
+#####GDescription
+Move the cursor to row "row" and column "col".
+
+#####GParameters
+> "row" is the row the cursor is to be moved to.
+> "col" is the column the cursor is to be moved to.
+
+----------------------------------------------------------------------
+
+#####R=== inkey ===
+
+#####GDeclaration
+ char inkey(void);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Get a keypress from the user.
+*
+* This function recognises a few "global parameters". These are variables
+* which, if set to TRUE before calling this function, will have an effect
+* on this function, and which are always reset to FALSE by this function
+* before this function returns. Thus they function just like normal
+* parameters, except that most calls to this function can ignore them.
+*
+* If "inkey_xtra" is TRUE, then all pending keypresses will be flushed,
+* and any macro processing in progress will be aborted. This flag is
+* set by the "flush()" function, which does not actually flush anything
+* itself, but rather, triggers delayed input flushing via "inkey_xtra".
+*
+* If "inkey_scan" is TRUE, then we will immediately return "zero" if no
+* keypress is available, instead of waiting for a keypress.
+*
+* If "inkey_base" is TRUE, then all macro processing will be bypassed.
+* If "inkey_base" and "inkey_scan" are both TRUE, then this function will
+* not return immediately, but will wait for a keypress for as long as the
+* normal macro matching code would, allowing the direct entry of macro
+* triggers. The "inkey_base" flag is extremely dangerous!
+*
+* If "inkey_flag" is TRUE, then we will assume that we are waiting for a
+* normal command, and we will only show the cursor if "hilite_player" is
+* TRUE (or if the player is in a store), instead of always showing the
+* cursor. The various "main-xxx.c" files should avoid saving the game
+* in response to a "menu item" request unless "inkey_flag" is TRUE, to
+* prevent savefile corruption.
+*
+* If we are waiting for a keypress, and no keypress is ready, then we will
+* refresh (once) the window which was active when this function was called.
+*
+* Note that "back-quote" is automatically converted into "escape" for
+* convenience on machines with no "escape" key. This is done after the
+* macro matching, so the user can still make a macro for "backquote".
+*
+* Note the special handling of "ascii 30" (ctrl-caret, aka ctrl-shift-six)
+* and "ascii 31" (ctrl-underscore, aka ctrl-shift-minus), which are used to
+* provide support for simple keyboard "macros". These keys are so strange
+* that their loss as normal keys will probably be noticed by nobody. The
+* "ascii 30" key is used to indicate the "end" of a macro action, which
+* allows recursive macros to be avoided. The "ascii 31" key is used by
+* some of the "main-xxx.c" files to introduce macro trigger sequences.
+*
+* Hack -- we use "ascii 29" (ctrl-right-bracket) as a special "magic" key,
+* which can be used to give a variety of "sub-commands" which can be used
+* any time. These sub-commands could include commands to take a picture of
+* the current screen, to start/stop recording a macro action, etc.
+*
+* If "angband_term[0]" is not active, we will make it active during this
+* function, so that the various "main-xxx.c" files can assume that input
+* is only requested (via "Term_inkey()") when "angband_term[0]" is active.
+*
+* Mega-Hack -- This function is used as the entry point for clearing the
+* "signal_count" variable, and of the "character_saved" variable.
+*
+* Hack -- Note the use of "inkey_next" to allow "keymaps" to be processed.
+*
+* Mega-Hack -- Note the use of "inkey_hack" to allow the "Borg" to steal
+* control of the keyboard from the user.
+*/
+
+#####GDescription
+Get a keypress from the user.
+
+----------------------------------------------------------------------
+
+#####R=== cmsg_print ===
+
+#####GDeclaration
+ void cmsg_print(byte color, cptr msg);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Output a message to the top line of the screen.
+*
+* Break long messages into multiple pieces (40-72 chars).
+*
+* Allow multiple short messages to "share" the top line.
+*
+* Prompt the user to make sure he has a chance to read them.
+*
+* These messages are memorised for later reference (see above).
+*
+* We could do "Term_fresh()" to provide "flicker" if needed.
+*
+* The global "msg_flag" variable can be cleared to tell us to
+* "erase" any "pending" messages still on the screen.
+*
+* XXX XXX XXX Note that we must be very careful about using the
+* "msg_print()" functions without explicitly calling the special
+* "msg_print(NULL)" function, since this may result in the loss
+* of information if the screen is cleared, or if anything is
+* displayed on the top line.
+*
+* XXX XXX XXX Note that "msg_print(NULL)" will clear the top line
+* even if no messages are pending. This is probably a hack.
+*/
+
+#####GDescription
+In color "color", output message "msg" to the top line of the screen.
+If the message is blank or has more than 1000 characters, nothing is
+printed. Long messages are split after the 40th character and before
+the 72nd character.
+
+#####GParameters
+> "color" is the color of the message.
+ *****fields.txt*0[colors]
+> "msg" is the message.
+
+----------------------------------------------------------------------
+
+#####R=== msg_print ===
+
+#####GDeclaration
+ void msg_print(cptr msg);
+
+#####GFile
+ util.c
+
+#####GComment
+/* Hack -- for compatibility and easy sake */
+
+#####GDescription
+Print message "msg" in white (see cmsg_print() above).
+
+#####GParameters
+> "msg" is the message.
+
+----------------------------------------------------------------------
+
+#####R=== screen_save ===
+
+#####GDeclaration
+ void screen_save(void);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Save the screen, and increase the "icky" depth.
+ *
+ * This function must match exactly one call to "screen_load()".
+ */
+
+#####GDescription
+Save a screen shot.
+
+----------------------------------------------------------------------
+
+#####R=== screen_load ===
+
+#####GDeclaration
+ void screen_load(void);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Load the screen, and decrease the "icky" depth.
+ *
+ * This function must match exactly one call to "screen_save()".
+ */
+
+#####GDescription
+Load a previously saved screen shot.
+
+----------------------------------------------------------------------
+
+#####R=== c_put_str ===
+
+#####GDeclaration
+ void c_put_str(byte attr, cptr str, int row, int col);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Display a string on the screen using an attribute.
+*
+* At the given location, using the given attribute, if allowed,
+* add the given string. Do not clear the line.
+*/
+
+#####GDescription
+Put string "str" at row "row" and column "col" with attribute "attr".
+
+#####GParameters
+> "attr" is the color of the message.
+ *****fields.txt*0[colors]
+> "msg" is the message.
+> "row" is the row the message is to be printed at.
+> "col" is the column the message is to be printed at.
+
+----------------------------------------------------------------------
+
+#####R=== c_prt ===
+
+#####GDeclaration
+ void c_prt(byte attr, cptr str, int row, int col);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Display a string on the screen using an attribute, and clear
+* to the end of the line.
+*/
+
+#####GDescription
+Clear row "row" from column "col". Put string "str" at "row", "col"
+with attribute "attr".
+
+#####GParameters
+> "attr" is the color of the message.
+ *****fields.txt*0[colors]
+> "msg" is the message.
+> "row" is the row the message is to be printed at.
+> "col" is the column the message is to be printed at.
+
+----------------------------------------------------------------------
+
+#####R=== clear_from ===
+
+#####GDeclaration
+ void clear_from(int row);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Clear part of the screen
+*/
+
+#####GDescription
+Clear the screen from row "row" onwards.
+
+#####GParameters
+> "row" is the first row of the screen to be cleared.
+
+----------------------------------------------------------------------
+
+#####R=== askfor_aux ===
+
+#####GDeclaration
+ bool askfor_aux(char *buf, int len);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Get some input at the cursor location.
+* Assume the buffer is initialized to a default string.
+* Note that this string is often "empty" (see below).
+* The default buffer is displayed in yellow until cleared.
+* Pressing RETURN right away accepts the default entry.
+* Normal chars clear the default and append the char.
+* Backspace clears the default or deletes the final char.
+* ESCAPE clears the buffer and the window and returns FALSE.
+* RETURN accepts the current buffer contents and returns TRUE.
+*/
+
+#####GDescription
+Get string "buf" from the screen. "buf" is to be no more than "len"
+bytes. The string starts at the current cursor position. The length
+can not exceed the number of bytes from the cursor to the end of the
+line. Accept user input until the escape or return key is pressed.
+
+#####GParameters
+> "buf" is the string returned from the screen.
+> "len" is the length of the string. If it is <1 it is forced to 1.
+
+----------------------------------------------------------------------
+
+#####R=== get_string ===
+
+#####GDeclaration
+ bool get_string(cptr prompt, char *buf, int len);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Get a string from the user
+*
+* The "prompt" should take the form "Prompt: "
+*
+* Note that the initial contents of the string is used as
+* the default response, so be sure to "clear" it if needed.
+*
+* We clear the input, and return FALSE, on "ESCAPE".
+*/
+
+#####GDescription
+Print prompt "prompt" at the top-left corner of the screen and return
+response "buf" which will have a maximum length "length". If ESCAPE
+is entered, the function returns FALSE, otherwise it returns TRUE.
+
+#####GParameters
+> "prompt" is the prompt for input.
+> "buf" is the returned response.
+> "len" is the maximum length of the string.
+
+----------------------------------------------------------------------
+
+#####R=== get_check ===
+
+#####GDeclaration
+ bool get_check(cptr prompt);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Verify something with the user
+*
+* The "prompt" should take the form "Query? "
+*
+* Note that "[y/n]" is appended to the prompt.
+*/
+
+#####GDescription
+Ask the user question "prompt" which requires a yes/no answer. The
+prompt appears in the top-left corner of the screen. A response of
+'Y' (either case) returns TRUE. A response of 'N' (either case) or
+ESCAPE returns FALSE.
+
+#####GParameters
+> "prompt" is the question asked. It has a maximum length of 70
+ characters.
+
+----------------------------------------------------------------------
+
+#####R=== get_com_lua ===
+
+#####GDeclaration
+ bool get_com_lua @ get_com(cptr promtp, int *com);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Prompts for a keypress
+*
+* The "prompt" should take the form "Command: "
+*
+* Returns TRUE unless the character is "Escape"
+*/
+
+#####GDescription
+Ask the user for command "prompt" and return the key press "com". A
+response of ESCAPE returns FALSE. All other responses return TRUE.
+
+#####GParameters
+> "prompt" is the prompt for the key press.
+> "com" is the returned key press.
+
+----------------------------------------------------------------------
+
+#####R=== get_quantity ===
+
+#####GDeclaration
+ s32b get_quantity(cptr prompt, s32b max);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+* Request a "quantity" from the user
+*
+* Hack -- allow "command_arg" to specify a quantity
+*/
+
+#####GDescription
+Ask the user for quantity "prompt" of maximum value "max" and return
+a quantity. If the user quantity is higher than the maximum then the
+maximum is returned. If the response is a letter then the maximum is
+returned. If the user quantity is negative then zero is returned.
+
+#####GParameters
+> "prompt" is the prompt for a quantity.
+> "max" is the maximum value allowed.
+
+----------------------------------------------------------------------
+
+#####R=== test_monster_name ===
+
+#####GDeclaration
+ int test_monster_name(cptr name);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Given monster name as string, return the index in r_info array. Name
+ * must exactly match (look out for commas and the like!), or else 0 is
+ * returned. Case doesn't matter. -GSN-
+ */
+
+#####GDescription
+Return the monster index for monster with name "name". If no match is
+found then zero is returned.
+
+#####GParameters
+> "name" is the monster name.
+
+----------------------------------------------------------------------
+
+#####R=== test_item_name ===
+
+#####GDeclaration
+ int test_item_name(cptr name);
+
+#####GFile
+ util.c
+
+#####GComment
+/*
+ * Given item name as string, return the index in k_info array. Name
+ * must exactly match (look out for commas and the like!), or else 0 is
+ * returned. Case doesn't matter. -DG-
+ */
+
+#####GDescription
+Return the item index for item with name "name". If no match is found
+then zero is returned.
+
+#####GParameters
+> "name" is the item name.
+
+----------------------------------------------------------------------
+
+#####R=== luck ===
+
+#####GDeclaration
+ int luck(int min, int max);
+
+#####GFile
+ xtra1.c
+
+#####GComment
+/*
+ * Return a luck number between a certain range
+ */
+
+#####GDescription
+Return a number for luck between minimum "min" and maximum "max". The
+value begins with the player's current luck. The value is forced to
+be between -30 and +30. 30 is added to give a value between 0 and 60.
+The value is multiplied by the range (maximum - minimum) and divided
+by 60. The value is increased by the minimum. The value is returned.
+
+For example, if the player's current luck is 15, the minimum is -10,
+and the maximum is 10 (range 20), then the value returned is
+(45 * 20) / 60 which is 900 / 60 which is 15 + the minimum -10 gives
+a returned value of 5.
+
+#####GParameters
+> "min" is the minimum luck.
+> "max" is the maximum luck. Beware: this should be greater than the
+ minimum but it is not checked!
+
+----------------------------------------------------------------------
+
+#####R=== get_player_race_name ===
+
+#####GDeclaration
+ cptr get_player_race_name(int pr, int ps);
+
+#####GFile
+ util.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the name for player race "pr" and player sub-race "ps".
+
+#####GParameters
+> "pr" is the index for player race.
+> "ps" is the index for player sub-race.
+
+----------------------------------------------------------------------
+
+#####R=== quit ===
+
+#####GDeclaration
+ void quit(cptr str);
+
+#####GFile
+ z-util.c
+
+#####GComment
+/*
+ * Exit (ala "exit()"). If 'str' is NULL, do "exit(0)".
+ * If 'str' begins with "+" or "-", do "exit(atoi(str))".
+ * Otherwise, plog() 'str' and exit with an error code of -1.
+ * But always use 'quit_aux', if set, before anything else.
+ */
+
+#####GDescription
+Quit the game. If "str" is a string then write the string to the
+error file or screen. If "str" is a number then exit with the
+number as the exit code.
+
+#####GParameters
+> "str" is an error message or exit code.
+
+----------------------------------------------------------------------
+
+#####R=== dump_hooks ===
+
+#####GDeclaration
+ void dump_hooks();
+
+#####GFile
+ plots.c
+
+#####GComment
+(none)
+
+#####GDescription
+Print the name and type (C or Lua) of hooks in the hook list.
+
+----------------------------------------------------------------------
+
+#####R=== add_hook_script ===
+
+#####GDeclaration
+ void add_hook_script(int h_idx, char *script, cptr name);
+
+#####GFile
+ plots.c
+
+#####GComment
+(none)
+
+#####GDescription
+To hook list with index "h_idx", add a script with script file
+"script" and name "name" as a Lua hook if a hook with that name
+does not already exist.
+
+#####GParameters
+> "h_idx" is the index of the hook list in the array of hook lists.
+> "script" is the name of the script file.
+> "name" is the name of the hook to be added.
+
+----------------------------------------------------------------------
+
+#####R=== del_hook_name ===
+
+#####GDeclaration
+ void del_hook_name(int h_idx, cptr name);
+
+#####GFile
+ plots.c
+
+#####GComment
+(none)
+
+#####GDescription
+Search hook list with index "h_idx" and remove the hook with name
+"name".
+
+#####GParameters
+> "h_idx" is the index of the hook list in the array of hook lists.
+> "name" is the name of the hook to be removed.
+
+----------------------------------------------------------------------
+
+#####R=== pern_dofile ===
+
+#####GDeclaration
+ bool pern_dofile(char *file);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Parse the Lua script file "file".
+
+#####GParameters
+> "file" is the Lua script file to be parsed.
+
+----------------------------------------------------------------------
+
+#####R=== intMod ===
+
+#####GDeclaration
+ s32b intMod(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of operation "a" mod "b" (a % b).
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intAnd ===
+
+#####GDeclaration
+ s32b intAnd(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" AND "b" (a & b).
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intOr ===
+
+#####GDeclaration
+ s32b intOr(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" OR "b" (a | b).
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intXor ===
+
+#####GDeclaration
+ s32b intXor(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" XOR "b" (a ^ b).
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intShiftl ===
+
+#####GDeclaration
+ s32b intShiftl(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" << "b".
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intShiftr ===
+
+#####GDeclaration
+ s32b intShiftr(s32b a, s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation "a" >> "b".
+
+#####GParameters
+> "a" is a number.
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== intBitNot ===
+
+#####GDeclaration
+ s32b intBitNot(s32b b);
+
+#####GFile
+ script.c
+
+#####GComment
+(none)
+
+#####GDescription
+Return the result of bitwise operation NOT "b" (~ b).
+
+#####GParameters
+> "b" is a number.
+
+----------------------------------------------------------------------
+
+#####R=== register_savefile ===
+
+#####GDeclaration
+ void register_savefile(int num);
+
+#####GFile
+ loadsave.c
+
+#####GComment
+/*
+ * Add num slots to the savefile
+ */
+
+#####GDescription
+Add "num" slots to the save file.
+
+#####GParameters
+> "num" is the number of slots to add to the savefile. If num is <0
+ then "num" is forced to zero.
+
+----------------------------------------------------------------------
+
+#####R=== save_number_key ===
+
+#####GDeclaration
+ void save_number_key(char *key, s32b val);
+
+#####GFile
+ util.c
+
+#####GComment
+(none)
+
+#####GDescription
+Save the length of key "key", the key itself, and the value "val" as
+bytes in the savefile.
+
+#####GParameters
+> "key" is the key string for the value.
+> "val" is the value to be saved.
+
+----------------------------------------------------------------------
+
+
+
+Back to the *****lua.hlp*0[lua help index] .
+
+
+ [[[[[gThis file by Chris Hadgis]
+
diff --git a/lib/mods/theme/help/luckspoi.txt b/lib/mods/theme/help/luckspoi.txt
new file mode 100644
index 00000000..4b4007c2
--- /dev/null
+++ b/lib/mods/theme/help/luckspoi.txt
@@ -0,0 +1,129 @@
+|||||oy
+~~~~~01|Luck (spoiler)
+~~~~~02|Spoilers|Luck
+#####RLuck
+
+"You've got to ask yourself one question: do I feel lucky? Well do ya
+punk?"
+ --Clint Eastwood (Dirty Harry)
+
+#####G1. Starting luck
+Most races start with no luck points. Those that start with luck are listed
+below from most luck to least luck.
+
+Hobbit (+5);
+Maia (+4);
+Gnome, Dunadan (+2);
+Beorning (+1);
+Half-Ogre, Dark Elf, Ent (-2);
+Orc (-3);
+Troll (-4);
+Petty Dwarf, Yeek (-5).
+
+Most subraces start with no luck points. Those that start with luck are listed
+below from most luck to least luck.
+
+Barbarian (+1);
+Spectre, Skeleton (-3);
+Zombie (-4).
+
+So, a Hobbit starts with 5 luck points, a Beorning Barbarian starts with 2 luck
+points, while a Yeek Zombie starts with -9 luck points.
+
+#####G2. Descriptions
+Drinking a potion of self-knowledge will tell you how lucky or unlucky your
+character is.
+
+DESCRIPTION VALUE
+incredibly unlucky less than -27
+extremely unlucky less than -18
+very unlucky less than -9
+unlucky less than 0
+normal luck 0
+lucky more than 0
+very lucky more than 9
+extremely lucky more than 18
+incredibly lucky more than 27
+
+Luck < -30 is treated as -30 and luck > 30 is treated as +30.
+
+#####G3. Items affecting luck
+Elven cloaks give a bonus to luck.
+
+All Morgul items have -10 luck.
+Weapons of Telchar give a bonus to luck.
+Weapons of the Glamhoth are unlucky.
+Lucky amulets give a bonus to luck.
+Unlucky amulets are, well, unlucky.
+
+Artifacts can affect your luck. Beware: not all artifacts give you good luck.
+Listed below are the artifacts which affect your luck.
+
+The Phial of Galadriel (+4)
+The Arkenstone of Thrain (+3)
+The Ring of Power 'Narya' (+1)
+The Ring of Power 'Nenya' (+2)
+The Ring of Power 'Vilya' (+3)
+The Metal Cap of Thengel (+3)
+The Shadow Cloak of Luthien (+2)
+The Set of Cesti of Fingolfin (+4)
+The Broken Dagger 'Angrist' (+5)
+The Long Sword 'Anduril' (+4)
+The Long Sword of Dernhelm (+5)
+The Long Bow of Bard (+2)
+The Mage Staff of Manwe (+12)
+The Golden Harp of Thorin (+2)
+The Harp of Maglor (+3)
+The Drum of the Sky (+2)
+The Harp of Daeron (+1)
+The Long Sword of Tulkas (+10)
+The Robe of Great Luck (+60)
+The Heavy Crossbow of Orome (+5)
+The Iron Helm of Knowledge (-6)
+The Shield of Deflection of Gil-galad (+5)
+The Set of Gauntlets of Eol (+3)
+The Demonblade of Gothmog (-20)
+The Elven Cloak of Peregrin Took (+3)
+The Ring 'Fuin' (+15)
+The Blue Stone 'Coimir' (+2)
+The Elven Cloak of Mellyrn (+4)
+The Set of Cesti 'Skycleaver' (+1)
+The Robe of Belegaer (+5)
+The Harp of Tom Bombadil (+4)
+The Horn 'Valaroma' (+4)
+The Sceptre of Numenor (-3)
+The Rod of Annuminas (+4)
+The Lucerne Hammer of the Eruchin (+10)
+The Trident of Ulmo (+10)
+The Broad Axe of Aule (+10)
+The Rapier of Vaire (+10)
+The Long Bow of Irmo (+5)
+The Sling of Nessa (+5)
+The Boomerang of Varda (+5)
+The Ring of Power of the Blacklocks (+3)
+
+#####G4. What does it affect.
+It affects your chance to-hit in ranged combat and melee combat.
+
+It affects your chance of critical hits in ranged combat and melee combat.
+
+It affects your chance of being missed by a monster attack. This effectively
+changes armour class by -13 (incredibly unlucky) to +13 (incredibly lucky).
+
+It affects the rarity of special objects, artifacts, and ego items.
+
+It affects the number of wishes on a staff of wishing.
+
+It affects the base level for applying magic to an item.
+
+It affects the chance of an item being good or great.
+
+It affects the chance of creating a special object.
+
+It prevents the death fate if you are lucky.
+
+It affects the number of skill points you receive when quaffing the Potion of
+Learning.
+
+
+ Written for ToME 2.0 by Chris Hadgis
diff --git a/lib/mods/theme/help/m_air.txt b/lib/mods/theme/help/m_air.txt
new file mode 100644
index 00000000..ee9fa8d0
--- /dev/null
+++ b/lib/mods/theme/help/m_air.txt
@@ -0,0 +1,42 @@
+|||||oy
+~~~~~01|Magic|Air School
+~~~~~02|Air Magic
+~~~~~03|Skills|Air - Spell Info
+#####R === ToME Magic - Air School ===
+
+The air school of magic contains spells where the element of air is used
+to create the final spell effect. There are rumours of a "Tome of the Blowing
+Wind" which contains all the air school spells within its bindings.
+
+Worshipping the God Manwe Sulimo also gives the ability to cast spells from
+the air school at a level of 2/3 of your prayer level. E.g. if the skill
+"Spirituality: Prayer" is at level 12, you can cast up to level 8 air school
+spells.
+
+#####BAir Spells
+There are six spells available for the air school. These spells are:
+1. [[[[[BNoxious Cloud] (school level 3)
+ Creates a cloud of poison.
+ The cloud will persist for some turns, damaging all monsters passing by.
+ At spell level 30 it turns into a thick gas attacking all living beings.
+2. [[[[[BPoison Blood] (school level 12)
+ Grants resist poison.
+ At spell level 15 it provides poison branding to the wielded weapon.
+3. [[[[[BInvisibility] (school level 16)
+ Grants invisibility.
+4. [[[[[BSterilize] (school level 20)
+ Prevents explosive breeding for a while.
+5. [[[[[BWings of Winds] (dual school level 22)
+ Grants the power of levitation.
+ At spell level 16 it grants the power of controlled flight.
+#####v Your Air and Conveyance skills must have reached a combined average level
+#####v of 22 in order to cast this spell.
+6. [[[[[BThunderstorm] (dual school level 25)
+ Charges up the air around you with electricity.
+ Each turn it will throw a bolt of thunder at a random monster in sight.
+ This thunder does 3 types of damage:
+ one third of lightning
+ one third of sound
+ and one third of light.
+#####v Your Air and Nature skills must have reached a combined average level
+#####v of 25 in order to cast this spell.
diff --git a/lib/mods/theme/help/m_convey.txt b/lib/mods/theme/help/m_convey.txt
new file mode 100644
index 00000000..91ed8556
--- /dev/null
+++ b/lib/mods/theme/help/m_convey.txt
@@ -0,0 +1,71 @@
+|||||oy
+~~~~~01|Magic|Conveyance School
+~~~~~02|Conveyance Magic
+~~~~~03|Skills|Conveyance - Spell Info
+#####R === ToME Magic - Conveyance School ===
+
+The conveyance school of magic contains spells where the forces of space are
+manipulated by the spell. There are rumours of a "Tome of of Translocation"
+which contains all the conveyance school spells within its bindings.
+
+Worshipping the God Manwe Sulimo also gives the ability to cast spells from
+the conveyance school at a level of 1/2 of your prayer level. E.g. if the
+skill "Spirituality: Prayer" is at level 10, you can cast up to level 5
+conveyance school spells.
+
+#####sConveyance Spells
+There are six spells available for the conveyance school. These Spells are:
+1. [[[[[sPhase Door] (school level 1)
+ Teleports you on a small scale range.
+ At spell level 30 it creates void jumpgates.
+2. [[[[[sDisarm] (school level 3)
+ Destroys doors and disarms traps in adjacent tiles.
+ At spell level 10 it unlocks doors and disarms traps.
+3. [[[[[sTeleportation] (school level 10)
+ Teleports you around the level.
+ The casting time decreases with level.
+4. [[[[[sTeleport Away] (school level 23)
+ Teleports a line of monsters away.
+ At spell level 10 it turns into a ball.
+ At spell level 20 it teleports all monsters in sight.
+5. [[[[[sRecall] (school level 30)
+ Cast on yourself, it will recall you to the surface/dungeon.
+ Cast at a monster, it will make you swap positions with the monster.
+ Cast at an object, it will fetch the object to you (note that you must have
+ an empty space under your feet for the object to fall onto).
+6. [[[[[sProbability Travel] (school level 35)
+ Renders you unstable. When you hit a wall you travel through it and
+ instantly appear on the other side of it. You can also float up and down
+ at will.
+
+#####GAir spells that can be cast with Conveyance skill
+
+1. [[[[[BWings of Winds] (dual school level 22)
+ Grants the power of levitation.
+ At spell level 16 it grants the power of controlled flight.
+#####v Your Air and Conveyance skills must have reached a combined average level
+#####v of 22 in order to cast this spell.
+
+#####GTemporal spells that can be cast with Conveyance skill
+
+1. [[[[[sBanishment] (dual school level 30)
+ Disrupts the space/time continuum in your area and teleports all monsters
+ away.
+ At spell level 15 it also may lock them in a time bubble for some turns.
+#####v Your Temporal and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+
+#####GMeta spells that can be cast with Conveyance skill
+
+1. [[[[[sTracker] (dual school level 30)
+ Tracks down the last teleportation that happened on the level and teleports
+ you to it.
+#####v Your Meta and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+
+#####GUdun spells that can be cast with Conveyance skill
+
+1. [[[[[DWraithform] (dual school level 30)
+ Turns you temporarily into an immaterial being.
+#####v Your Udun and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
diff --git a/lib/mods/theme/help/m_demono.txt b/lib/mods/theme/help/m_demono.txt
new file mode 100644
index 00000000..cb32d360
--- /dev/null
+++ b/lib/mods/theme/help/m_demono.txt
@@ -0,0 +1,44 @@
+|||||oy
+~~~~~01|Magic|Demonology School
+~~~~~02|Demonology Magic
+~~~~~03|Skills|Demonology - Spell Info
+#####R === ToME Magic - Demonology ===
+
+Available only to Demonologists, or those sufficiently corrupted with
+demon-like powers, this school contains spells where demonic energies
+are used to create mainly devastating effects.
+
+#####oDemonic equipment
+Unlike other magic schools, the spells of a Demonologist are not written
+in spell books, but are contained within items of demonic origin known as
+Demonblades, Demonshields, and Demonhorns (helms), which when wielded allow
+the Demonologist to cast spells; each piece of equipment holds three spells.
+
+#####oDemonblade spells
+1. [[[[[oDemon Blade] (school level 1)
+ Imbues your blade with fire to deal more damage.
+ At level 30 it deals hell fire damage.
+ At level 45 it spreads over a 1 radius zone around your target.
+2. [[[[[oDemon Madness] (school level 10)
+ Fire 2 balls in opposite directions of randomly chaos, confusion or charm.
+3. [[[[[oDemon Field] (school level 20)
+ Fires a lingering cloud of deadly nexus over a radius of 7.
+
+#####oDemonshield spells
+1. [[[[[oDoom Shield] (school level 1)
+ Raises a mirror of pain around you, doing very high damage to your foes
+ that dare hit you, but greatly reduces your armour class.
+2. [[[[[oDemon Cloak] (school level 20)
+ Raises a mirror that can reflect bolts and arrows for a time.
+3. [[[[[oUnholy Word] (school level 25)
+ Kills a pet to heal you. There is a chance that the pet won't die but will
+ turn against you. This chance will decrease with higher spell levels.
+
+#####oDemonhorn spells
+1. [[[[[oSummon Demon] (school level 5)
+ Summons a leveled demon to your side.
+ At level 35 it summons a high demon.
+2. [[[[[oDischarge Minion] (school level 10)
+ The targeted pet will explode in a burst of gravity.
+3. [[[[[oControl Demon] (school level 25)
+ Attempts to control a demon.
diff --git a/lib/mods/theme/help/m_divin.txt b/lib/mods/theme/help/m_divin.txt
new file mode 100644
index 00000000..df92c11b
--- /dev/null
+++ b/lib/mods/theme/help/m_divin.txt
@@ -0,0 +1,38 @@
+|||||oy
+~~~~~01|Magic|Divination School
+~~~~~02|Divination Magic
+~~~~~03|Skills|Divination - Spell Info
+#####R === ToME Magic - Divination School ===
+
+The divination school of magic contains spells where magic is used to
+psychically gain information about things. There are rumours of a "Tome of
+Knowledge" which contains all the divination school spells within its bindings.
+
+Worshipping Eru Iluvatar or Mandos also gives the ability to cast spells from
+the divination school at a level of 2/3 and 1/3, respectively, of your prayer
+level. E.g. if the skill "Spirituality: Prayer" is at level 12, a worshipper
+of Eru can cast up to level 8 divination school spells, whereas a worshipper
+of Mandos can cast up to level 4 divination school spells.
+
+#####sDivination Spells
+There are six spells available for the divination school. These Spells are:
+1. [[[[[sSense Monsters] (school level 1)
+ Detects all monsters near you.
+ At spell level 30 it allows you to sense monster minds for a while.
+2. [[[[[sSense Hidden] (school level 5)
+ Detects the traps in a certain radius around you.
+ At spell level 15 it allows you to sense invisible monsters for a while.
+3. [[[[[sIdentify] (school level 8)
+ Asks for an object and identifies it.
+ At spell level 17 it identifies all objects in the inventory.
+ At spell level 27 it identifies all objects in the inventory and in a
+ radius on the floor, as well as probing monsters in that radius.
+4. [[[[[sReveal Ways] (school level 9)
+ Detects the doors/stairs/ways in a certain radius around you.
+5. [[[[[sVision] (school level 15)
+ Detects the layout of the surrounding area.
+ At spell level 25 it maps and lights the whole level.
+6. [[[[[sGreater Identify] (school level 35)
+ Asks for an object and fully identifies it, providing the full list of
+ powers (as with a scroll of *Identify*).
+ Cast at yourself, it will reveal your powers (Self Knowledge).
diff --git a/lib/mods/theme/help/m_earth.txt b/lib/mods/theme/help/m_earth.txt
new file mode 100644
index 00000000..2f2bd9c2
--- /dev/null
+++ b/lib/mods/theme/help/m_earth.txt
@@ -0,0 +1,35 @@
+|||||oy
+~~~~~01|Magic|Earth School
+~~~~~02|Earth Magic
+~~~~~03|Skills|Earth - Spell Info
+#####R === ToME Magic - Earth School ===
+
+The earth school of magic contains spells where the element of earth is used
+to create the final spell effect. There are rumours of a "Tome of the
+Impenetrable Earth" which contains all the earth school spells within its
+bindings.
+
+Worshipping Tulkas, Yavanna Kementari or Aule also gives the ability to cast
+spells from the earth school, at a level of 4/5, 1/2, or 1/3, respectively,
+of your prayer level. E.g. if the skill "Spirituality: Prayer" is at level
+10, a worshipper of Tulkas can cast up to level 8 earth school spells,
+whereas a worshipper of Yavanna can cast up to level 5 earth school spells
+and a worshipper of Aule can cast up to level 3 earth school spells.
+
+#####uEarth Spells
+There are five spells available for the earth school. These Spells are:
+1. [[[[[uStone Skin] (school level 1)
+ Creates a shield of earth around you to protect you.
+ At spell level 25 it starts dealing damage to attackers.
+2. [[[[[uDig] (school level 12)
+ Digs a hole in a wall much faster than any shovels.
+3. [[[[[uStone Prison] (school level 25)
+ Creates a prison of walls around you.
+ At spell level 10 it allows you to target a monster.
+4. [[[[[uShake] (school level 27)
+ Creates a localised earthquake.
+ At spell level 10 it can be targeted at any location.
+5. [[[[[uStrike] (school level 30)
+ Creates a micro-ball of force that will push monsters backwards.
+ If the monster is caught near a wall, it'll be crushed against it.
+ At spell level 12 it turns into a ball of radius 1.
diff --git a/lib/mods/theme/help/m_fire.txt b/lib/mods/theme/help/m_fire.txt
new file mode 100644
index 00000000..826a1d9a
--- /dev/null
+++ b/lib/mods/theme/help/m_fire.txt
@@ -0,0 +1,53 @@
+|||||oy
+~~~~~01|Magic|Fire School
+~~~~~02|Fire Magic
+~~~~~03|Skills|Fire - Spell Info
+#####R === ToME Magic - Fire School ===
+
+The fire school of magic contains spells where the element of fire is used
+to create the final spell effect. There are rumours of a "Tome of the Eternal
+Flame" which contains all the fire school spells within its bindings.
+
+Worshipping Aule also gives the ability to cast spells from the fire school
+at a level of 3/5 of your prayer level. E.g. if the skill "Spirituality:
+Prayer" is at level 15, you can cast up to level 9 fire school spells.
+
+#####RFire Spells
+There are five spells available for the fire school. These spells are:
+1. [[[[[RGlobe of Light] (school level 1)
+ Creates a globe of pure light.
+ At spell level 3 it starts damaging monsters.
+ At spell level 15 it starts creating a more powerful kind of light.
+2. [[[[[RFire Golem] (dual school level 7)
+ Creates a fiery golem and controls it.
+ During the control the available keylist is:
+ Movement keys: move the golem (depending on its speed it can move more
+ than one square).
+ , : pickup all items on the floor
+ d : drop all carried items
+ i : list all carried items
+ m : end the possession/use golem powers
+ Most of the other keys are disabled; you cannot interact with your
+ real body while controlling the golem.
+ But to cast the spell you will need a lantern or a wooden torch to create
+ the golem.
+#####v Your Fire and Mind skills must have reached a combined average level
+#####v of 7 in order to cast this spell.
+3. [[[[[RFireflash] (school level 10)
+ Conjures a ball of fire to burn your foes to ashes.
+ At spell level 20 it turns into a ball of holy fire.
+4. [[[[[RFirewall] (school level 15)
+ Creates a fiery wall to incinerate monsters stupid enough to attack you.
+ At spell level 6 it turns into a wall of hell fire.
+5. [[[[[RFiery Shield] (school level 20)
+ Creates a shield of fierce flames around you.
+ At spell level 8 it turns into a greater kind of flame that cannot be
+ resisted by your foes.
+
+
+#####GUdun spells that can be cast with Fire skill
+
+1. [[[[[DFlame of Udun] (dual school level 35)
+ Turns you temporarily into a powerful Balrog.
+#####v Your Fire and Udun skills must have reached a combined average level
+#####v of 35 in order to cast this spell.
diff --git a/lib/mods/theme/help/m_geoman.txt b/lib/mods/theme/help/m_geoman.txt
new file mode 100644
index 00000000..97c1ac1a
--- /dev/null
+++ b/lib/mods/theme/help/m_geoman.txt
@@ -0,0 +1,75 @@
+|||||oy
+~~~~~01|Magic|Geomancy
+~~~~~02|Geomancer|Geomancy spells
+~~~~~03|Skills|Geomancy - Spell Info
+#####R === ToME Magic - Geomancy ===
+Geomancy harnesses the power of nature to awesome effect. Therefore neither
+books nor light are necessary, and as the geomancers's skill increases, so do
+his powers over the elements of nature.
+
+Because Geomancy relies so heavily on the environment, you will need
+sufficient knowledge of the elemental skills (Earth, Air, Fire and Water) in
+order to cast some of the spells, and the exact effects of a spell often
+depend upon your levels in the elemental skills and your current surroundings.
+
+The powers are accessed using the 'm' key and then selecting 'Use Geomancy';
+they are cast with spell points, like normal spells, which can be increased
+as usual through the *****skills.txt*21[Magic] skill.
+
+1. [[[[[RCall] [[[[[GThe] [[[[[BElements] (Level 1) Cost:2
+ Randomly creates various elements around you.
+ The chance for each type of element is controlled by your level in the
+ corresponding skill.
+ At level 17 it can be targeted.
+
+2. [[[[[UChannel] [[[[[GElements] (Level 3) Cost:3
+ Draws on the caster's immediate environs to form an attack or other effect.
+ Grass/Flower heals.
+ Water creates water bolt attacks.
+ Ice creates ice bolt attacks.
+ Sand creates a wall of burning sand around you, but the wall is thick and
+ blinds you.
+ Lava creates fire bolt attacks.
+ Deep lava creates fire ball attacks.
+ Chasm creates darkness bolt attacks.
+ At Earth level 18, darkness becomes nether.
+ At Water level 8, water attacks become beams with a striking effect.
+ At Water level 12, ice attacks become balls of ice shards.
+ At Water level 18, water attacks push monsters back.
+ At Fire level 15, fire becomes hellfire.
+
+3. [[[[[RElemental] [[[[[BWave] (Level 15) Cost:15
+ Draws on an adjacent special square to project a slow-moving wave of that
+ element in that direction.
+ Abyss squares cannot be channeled into a wave.
+
+4. [[[[[UElemental] [[[[[RMinion] (Level 20) Cost:40
+ Summons a minion from a nearby element.
+ Walls can summon Earth elmentals, Xorns and Xarens.
+ Dark Pits can summon Air elementals, Ancient blue dragons, Great Storm Wyrms
+ and Sky Drakes.
+ Sandwalls and lava can summon Fire elementals and Ancient red dragons.
+ Icewalls and water can summon Water elementals, Water trolls and Water
+ demons.
+
+5. [[[[[GVaporize] (Level 4) Cost:3
+ Draws upon your immediate environs to form a cloud of damaging vapors.
+#####v You must have reached at least level 4 in the Air skill to cast this
+#####v spell.
+
+6. [[[[[UGeolysis] (Level 7) Cost:15
+ Burrows deeply and slightly at random into a wall, leaving behind tailings
+ of various different sorts of walls in the passage.
+#####v You must have reached at least level 7 in the Earth skill to cast this
+#####v spell.
+
+7. [[[[[BDripping Tread] (Level 10) Cost:15
+ Causes you to leave random elemental forms behind as you walk.
+#####v You must have reached at least level 10 in the Water skill to cast this
+#####v spell.
+
+8. [[[[[UGrow Barrier] (Level 12) Cost:30
+ Creates impassable terrain (walls, trees, etc.) around you.
+ At air level 20 it can be projected around another area.
+#####v You must have reached at least level 12 in the Earth skill to cast this
+#####v spell.
diff --git a/lib/mods/theme/help/m_mana.txt b/lib/mods/theme/help/m_mana.txt
new file mode 100644
index 00000000..23d8e680
--- /dev/null
+++ b/lib/mods/theme/help/m_mana.txt
@@ -0,0 +1,40 @@
+|||||oy
+~~~~~01|Magic|Mana School
+~~~~~02|Mana Magic
+~~~~~03|Skills|Mana - Spell Info
+#####R === ToME Magic - Mana School ===
+
+The mana school of magic contains spells where the raw force of magic is used
+to create the final spell effect. There are rumours of a "Tome of Magical
+Energy" which contains all the mana school spells within its bindings.
+
+Worshipping Eru Iluvatar or Varda Elentari also gives the ability to cast spells
+from the mana school at a level of 1/2 or 1/4, respectively, of your prayer level.
+E.g. if the skill "Spirituality: Prayer" is at level 10, Eru worshippers can cast
+up to level 5 mana school spells whereas Varda worshippers can cast up to level 3
+mana school spells.
+
+#####sMana Spells
+There are four spells available for the mana school. These spells are:
+1. [[[[[sManathrust] (school level 1)
+ Conjures up mana into a powerful bolt.
+ The damage is irresistible and will increase with spell level.
+2. [[[[[sRemove Curses] (school level 10)
+ Removes curses of worn objects.
+ At spell level 20, removes heavy curses.
+3. [[[[[sElemental Shield] (school level 20)
+ Provides resistance to the four basic elements.
+4. [[[[[sDisruption Shield] (school level 45)
+ Uses mana instead of hitpoints to take damage.
+ At spell level 5 switches to Globe of Invulnerability.
+ The spell breaks as soon as a melee, shooting, throwing or magical skill
+ action is attempted, and lasts only a short time otherwise.
+
+
+#####GUdun spells that can be cast with Mana skill
+
+1. [[[[[DDrain] (dual school level 1)
+ Drains the mana contained in wands, staves and rods to increase yours.
+#####v Your Mana and Udun skills must have reached a combined average level
+#####v of 1 in order to cast this spell.
+
diff --git a/lib/mods/theme/help/m_meta.txt b/lib/mods/theme/help/m_meta.txt
new file mode 100644
index 00000000..7bf1471b
--- /dev/null
+++ b/lib/mods/theme/help/m_meta.txt
@@ -0,0 +1,75 @@
+|||||oy
+~~~~~01|Magic|Meta School
+~~~~~02|Meta Magic
+~~~~~03|Skills|Meta - Spell Info
+#####R === ToME Magic - Meta School ===
+
+The meta school of magic contains spells where the raw forces of magic are
+manipulated by the spell. There are rumours of a "Tome of Meta Spells" which
+contains all the meta school spells within its bindings.
+
+Worshipping Manwe Sulimo or Varda Elentari also gives the ability to cast
+spells from the meta school at a level of 1/3 of your prayer level. E.g. if
+the skill "Spirituality: Prayer" is at level 15, Manwe and Varda worshippers
+alike can cast up to level 5 meta school spells.
+
+#####sMeta Spells
+There are five spells available for the meta school. These spells are:
+1. [[[[[sRecharge] (school level 5)
+ Taps the ambient mana to recharge an object's power (charges or mana).
+2. [[[[[sDisperse Magic] (school level 15)
+ Dispels a lot of magic that can affect you, be it good or bad:
+ Spell Level 1: blindness and light.
+ Spell Level 5: confusion and hallucination.
+ Spell Level 10: speed (either bad or good) and light speed.
+ Spell Level 15: stunning, meditation and cuts.
+ Spell Level 20: heroism, super heroism, blessing, shields, fear, parasites
+ and mimicry.
+3. [[[[[sSpellbinder] (school level 20)
+ Stores spells in a trigger.
+ When the condition is met all spells fire off at the same time. This spell
+ takes a long time to cast so you are advised to prepare it in a safe area.
+ Also it will use the mana for the Spellbinder and the mana for the selected
+ spells.
+4. [[[[[sTracker] (dual school level 30)
+ Tracks down the last teleportation that happened on the level and teleports
+ you to it.
+#####v Your Meta and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+5. [[[[[sInertia Control] (school level 37)
+ Changes the energy flow of a spell to be continuously recasted at a given
+ interval. The inertia-controlled spell reduces your maximum mana by four
+ times its cost.
+
+#####R=== List of Controllable Spells ===
+ Armor of Fear
+ Banishment
+ Disperse Magic
+ Disruption Shield
+ Elemental Shield
+ Ent's Potion
+ Essence of Speed
+ Fiery Shield
+ Flame of Udun
+ Globe of Light
+ Grow Trees
+ Ice Storm
+ Invisibility
+ Phase Door
+ Poison Blood
+ Probability Travel
+ Recovery
+ Regeneration
+ Remove Curses
+ Reveal Ways
+ Sense Hidden
+ Sense Monsters
+ Shake
+ Stone Skin
+ Teleportation
+ Thunderstorm
+ Tidal Wave
+ Vapor
+ Vision
+ Wings of Winds
+ Wraithform
diff --git a/lib/mods/theme/help/m_mimic.txt b/lib/mods/theme/help/m_mimic.txt
new file mode 100644
index 00000000..79d39521
--- /dev/null
+++ b/lib/mods/theme/help/m_mimic.txt
@@ -0,0 +1,33 @@
+|||||oy
+~~~~~01|Magic|Mimicry
+~~~~~02|Mimic|Mimicry powers
+~~~~~03|Skills|Mimicry - mimicry powers
+#####R === ToME Magic - Mimicry ===
+Mimics can alter their form using special cloaks called cloaks of mimicry.
+Even though this ability can give them access to increased stats, regeneration,
+speed and resistances, there is always the risk of the shape-change going
+horribly wrong, turning the character into an abomination for some time.
+Also, you should keep in mind that any racial power or stat modifier is
+overridden during the shape-shift.
+
+As your mimicry skill increases, your character is less likely to spoil
+the transformation attempt and may even gain other powers, such as making
+his colouration match his surroundings (becoming in all respects invisible)
+or even stranger abilities... rumours abound about Tarka the Chameleon and
+her two pairs of boots of speed.
+
+The powers are accessed using the 'm' key and then selecting 'Use Mimicry';
+they are cast with spell points, like normal spells, which can be increased
+as usual through the *****skills.txt*21[Magic] skill.
+
+1. [[[[[sMimic] (Level 1) Cost:2
+ Allows you to mimic the creature whose cloak you are wearing for a time.
+2. [[[[[sInvisibility] (Level 10) Cost:6
+ Turns you invisible for a time.
+3. [[[[[sLegs Mimicry] (Level 25) Cost:20
+ Gives you an additional set of legs for a time.
+4. [[[[[sWall Mimicry] (Level 30) Cost:40
+ Allows you to move within walls, and [[[[[Bonly] walls, for a time.
+[[[[[v Be careful you don't get stuck in a wall when it runs out.]
+5. [[[[[sArms Mimicry] (Level 35) Cost:100
+ Gives you an additional set of arms for a time.
diff --git a/lib/mods/theme/help/m_mind.txt b/lib/mods/theme/help/m_mind.txt
new file mode 100644
index 00000000..b6c1196f
--- /dev/null
+++ b/lib/mods/theme/help/m_mind.txt
@@ -0,0 +1,49 @@
+|||||oy
+~~~~~01|Magic|Mind School
+~~~~~02|Mind Magic
+~~~~~03|Skills|Mind - Spell Info
+#####R === ToME Magic - Mind School ===
+
+The mind school of magic contains spells which alter the mind. There are
+rumours of a "Tome of the Mind" which contains all the mind school spells
+within its bindings.
+
+Worshipping the God Eru Iluvatar or the God Melkor Bauglir also gives the
+ability to cast spells from the mind school at a level of 1/3 of your prayer
+level. E.g. if the skill "Spirituality: Prayer" is at level 12, you can cast
+up to level 4 mind school spells.
+
+#####sMind Spells
+There are four spells available for the mind school. These spells are:
+1. [[[[[sCharm] (school level 1)
+ Tries to manipulate the mind of a monster to make it friendly.
+ At spell level 15 it turns into a ball.
+ At spell level 35 it affects all monsters in sight.
+2. [[[[[sConfuse] (school level 5)
+ Tries to manipulate the mind of a monster to confuse it.
+ At spell level 15 it turns into a ball.
+ At spell level 35 it affects all monsters in sight.
+3. [[[[[sArmor of Fear] (school level 10)
+ Creates a shield of pure fear around you. Any monster attempting to hit
+ you must save or flee.
+4. [[[[[sStun] (school level 15)
+ Tries to manipulate the mind of a monster to stun it.
+ At spell level 20 it turns into a ball.
+
+#####GFire spells that can be cast with Mind skill
+
+1. [[[[[RFire Golem] (school level 7)
+ Creates a fiery golem and controls it.
+ During the control the available keylist is:
+ Movement keys: move the golem (depending on its speed it can move more
+ than one square).
+ , : pickup all items on the floor
+ d : drop all carried items
+ i : list all carried items
+ m : end the possession/use golem powers
+ Most of the other keys are disabled; you cannot interact with your
+ real body while controlling the golem.
+ But to cast the spell you will need a lantern or a wooden torch to create
+ the golem.
+#####v Your Fire and Mind skills must have reached a combined average level
+#####v of 7 in order to cast this spell.
diff --git a/lib/mods/theme/help/m_mindcr.txt b/lib/mods/theme/help/m_mindcr.txt
new file mode 100644
index 00000000..4f420656
--- /dev/null
+++ b/lib/mods/theme/help/m_mindcr.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Magic|Mindcraft
+~~~~~02|Mindcrafter|Mindcraft powers
+~~~~~03|Skills|Mindcraft - Spell Info
+#####R === ToME Magic - Mindcraft ===
+Mindcrafting uses the power of the mind to cast its spells. Therefore neither
+books nor light are necessary, and as the mindcrafter's skill increases, so do
+the powers of his mind.
+
+The powers are accessed using the 'm' key and then selecting 'Use Mindcraft';
+they are cast with spell points, like normal spells, which can be increased
+as usual through the *****skills.txt*21[Magic] skill.
+
+1. [[[[[sPrecognition] (Level 1) Cost:1
+ Detects monster minds around you.
+ At level 5 it also detects traps.
+ At level 15 it also allows you to see invisible monsters for a time.
+ At level 20 it maps out the surrounding area.
+ At level 25 it gives you ESP for a time.
+ At level 30 it also detects objects and treasure.
+ At level 45 it fully shows the entire level.
+2. [[[[[sNeural blast] (Level 2) Cost:1
+ Fires a bolt or beam, to stun and damage monsters.
+3. [[[[[sMinor Displacement] (Level 3) Cost:2
+ Teleports you a short distance.
+ At level 25 it grants the ability to create void jumpgates.
+4. [[[[[sMajor Displacement] (Level 7) Cost:6
+ Teleports you a good distance.
+ At level 30 it also banishes the monsters around you.
+5. [[[[[sDomination] (Level 9) Cost:7
+ Attempts to dominate the minds of your foes, scaring them.
+ At level 30 it attempts to charm monsters.
+6. [[[[[sPulverise] (Level 11) Cost:7
+ Fires pure sound at your opponents, crushing their bodies.
+7. [[[[[sCharacter Armour] (Level 13) Cost:12
+ Raises a physical shield around your body.
+ At level 15 it also grants resistance to acid.
+ At level 20 it also grants resistance to fire.
+ At level 25 it also grants resistance to cold.
+ At level 30 it also grants resistance to electricity.
+ At level 35 it also grants resistance to poison.
+8. [[[[[sPsychometry] (Level 15) Cost:12
+ Senses the quality of an item.
+ At level 40 it identifies an item.
+9. [[[[[sMindwave] (Level 18) Cost:10
+ Blasts the minds of monsters close to you.
+ At level 25 it affect all monsters in line of sight.
+10.[[[[[sAdrenaline Channeling] (Level 23) Cost:15
+ Heals you, hastes you and cures you.
+11.[[[[[sPsychic Drain] (Level 25) Cost:10
+ Drains the life of your foes into your mana reserves.
+12.[[[[[sTelekinesis] (Level 28) Cost:20
+ Projects a wave of pure telekinetic force from your body, damaging and maybe
+ banishing monsters.
diff --git a/lib/mods/theme/help/m_music.txt b/lib/mods/theme/help/m_music.txt
new file mode 100644
index 00000000..0f84f08f
--- /dev/null
+++ b/lib/mods/theme/help/m_music.txt
@@ -0,0 +1,77 @@
+|||||oy
+~~~~~01|Magic|Music
+~~~~~02|Music
+~~~~~03|Skills|Music - Song Info
+#####R === ToME Spells - Music ===
+
+Musical songs can have powerful effects for those who have the ability to
+play instruments, chiefly *****c_bard.txt*0[Bards].
+
+In order to continue playing a song, mana is consumed each turn, until
+either the 'Stop Singing' song is sung, or the player's mana runs out.
+
+Each song, as well as having a school level like any other magic spell, also
+has a roman numeral following its name. The higher this number, the greater the
+craftmanship of the instrument required to play it.
+
+Each musical instrument has a value assigned to it as well, between 1 and 4. The
+higher the number, the better the craftmanship; hence it will be possible
+for the bard to play higher level songs only with more powerful instruments.
+E.g. a Harp(+1) will allow you to cast "Stop Singing(I)" and "Song of the
+Sun(I)". A Harp(+2) would allow you to sing those songs, as well as "Flow of
+Life(II)".
+
+There are 3 different types of instruments: Harps, Drums and Horns. Each type
+of instrument contains a different family of musical songs:
+
+
+#####vMusical Songs
+
+#####GAll Instruments
+1. [[[[[vStop Singing(I)] (school level 1)
+ Stops the current song, if any.
+
+#####GDrums
+1. [[[[[vHolding Pattern(I)] (school level 1)
+ Slows down all monsters listening the song.
+ Consumes mana each turn.
+2. [[[[[vIllusion Pattern(II)] (school level 5)
+ Tries to confuse all monsters listening the song.
+ Consumes mana each turn.
+3. [[[[[vStun Pattern(IV)] (school level 10)
+ Stuns all monsters listening to the song.
+ Consumes mana each turn.
+
+#####GHarps
+1. [[[[[vSong of the Sun(I)] (School level 1)
+ Provides light as long as you sing.
+ Consumes mana each turn.
+2. [[[[[vFlow of Life(II)] (School level 5)
+ Heals you as long as you sing.
+ Consumes mana each turn.
+3. [[[[[vHeroic Ballad(II)] (School level 10)
+ Increases melee accuracy.
+ At level 10 it increases it even more and reduces armour a bit.
+ At level 20 it increases it still more.
+ At level 25 it grants protection against chaos and confusion.
+ Consumes mana each turn.
+4. [[[[[vHobbit Melodies(III)] (School level 20)
+ Greatly increases your reflexes allowing you to block more melee blows.
+ At level 15 it also makes you faster.
+ Consumes mana each turn.
+5. [[[[[vClairaudience(IV)] (School level 25)
+ Allows you to sense monster minds as long as you sing.
+ At level 10 it identifies all objects in a radius on the floor,
+ as well as probing monsters in that radius.
+ Consumes mana each turn.
+
+#####GHorns
+1. [[[[[vBlow(I)] (School level 4)
+ Produces a powerful, blowing sound all around you.
+2. [[[[[vGush of Wind (II)] (School level 14)
+ Produces a outgoing gush of wind that sends monsters away.
+3. [[[[[vHorns of Ylmir(III)] (School level 20)
+ Produces an earth-shaking sound.
+4. [[[[[vAmbarkanta(IV)] (School level 25)
+ Produces a reality-shaking sound that transports you to a nearly
+ identical reality.
diff --git a/lib/mods/theme/help/m_nature.txt b/lib/mods/theme/help/m_nature.txt
new file mode 100644
index 00000000..e57c5704
--- /dev/null
+++ b/lib/mods/theme/help/m_nature.txt
@@ -0,0 +1,54 @@
+|||||oy
+~~~~~01|Magic|Nature School
+~~~~~02|Nature Magic
+~~~~~03|Skills|Nature - Spell Info
+#####R === ToME Magic - Nature School ===
+
+The nature school of magic contains spells that interact with nature. There
+are rumours of a "Tome of the Tree" which contains all the nature school
+spells within its bindings.
+
+Worshipping Yavanna Kementari or Ulmo also gives the ability to cast spells
+from the nature school at a level of 1/2 of your prayer level. E.g. if the skill
+"Spirituality: Prayer" is at level 10, Yavanna and Ulmo worshippers alike can
+cast up to level 5 nature school spells.
+
+#####GNature Spells
+There are five spells available for the nature school. These spells are:
+1. [[[[[GGrow Trees] (dual school level 6)
+ Makes trees grow extremely quickly around you.
+#####v Your Nature and Temporal skills must have reached a combined average level
+#####v of 6 in order to cast this spell.
+2. [[[[[GHealing] (school level 10)
+ Heals a portion of your hitpoints.
+3. [[[[[GRecovery] (school level 15)
+ Reduces the length of time that you are poisoned.
+ At spell level 5 it cures poison and cuts.
+ At spell level 10 it restores drained stats.
+ At spell level 15 it restores lost experience.
+4. [[[[[GRegeneration] (school level 20)
+ Increases your body's regeneration rate.
+5. [[[[[GSummon Animal] (school level 25)
+ Summons a leveled animal to your aid.
+6. [[[[[GGrow Athelas] (school level 30)
+ Cures the Black Breath
+
+#####GAir spells that can be cast with Nature skill
+
+1. [[[[[BThunderstorm] (dual school level 25)
+ Charges up the air around you with electricity.
+ Each turn it will throw a bolt of thunder at a random monster in sight.
+ This thunder does 3 types of damage:
+ one third of lightning
+ one third of sound
+ and one third of light.
+#####v Your Nature and Air skills must have reached a combined average level
+#####v of 25 in order to cast this spell.
+
+#####GUdun spells that can be cast with Nature skill
+
+1. [[[[[DGenocide] (dual school level 25)
+ Genocides all monsters of a specified race on the level.
+ At level 10 it can genocide all monsters near you.
+#####v Your Nature and Udun skills must have reached a combined average level
+#####v of 25 in order to cast this spell.
diff --git a/lib/mods/theme/help/m_necrom.txt b/lib/mods/theme/help/m_necrom.txt
new file mode 100644
index 00000000..8de4fd37
--- /dev/null
+++ b/lib/mods/theme/help/m_necrom.txt
@@ -0,0 +1,35 @@
+|||||oy
+~~~~~01|Magic|Necromancy
+~~~~~02|Necromancy Magic
+~~~~~03|Skills|Necromancy - Spell Info
+#####R === ToME Magic - Necromancy ===
+The art of Necromancy is the foul practice of manipulating the life
+force of creatures.
+
+Necromancy powers are accessed using the 'm' key and then selecting
+'Use Necromancy'; they are cast with Spell Points, like normal spells,
+and do not need light to be performed.
+
+1. [[[[[DHorrify] (Level 1) Cost:2
+ Calls upon the dark forces and opens a channel into the mind of a
+ monster, stunning and scaring it.
+ At level 21 it affects all monsters in a beam.
+ At level 36 it affects all monsters in a ball.
+ At level 46 it affects all monsters in sight.
+2. [[[[[DRaise Dead] (Level 5) Cost:6
+ This power makes corpses in a small radius around the caster rise as
+ undead ego monsters at the service of the caster. The loyalty of those
+ monsters is not guaranteed, though. It also heals all monsters within the
+ same radius.
+3. [[[[[DNecromantic Teeth] (Level 12) Cost:20
+ This conjures up a temporary vampiric weapon.
+4. [[[[[DAbsorb Soul] (Level 20) Cost:10
+ This heals you by a substantial amount every time you kill a monster within
+ its duration. It is especially useful when your character is in
+ *****ability.txt*12[Undead Form].
+5. [[[[[DVampirism] (Level 30) Cost:15
+ Drains part of the life-force from a nearby monster and gives it to you.
+6. [[[[[DDeath] (Level 35) Cost:100
+ Yes, the name is not nice. Neither are the effects: the target dies
+ immediately, but so does your character (note that death is not such a great
+ annoyance for necromancers).
diff --git a/lib/mods/theme/help/m_symbio.txt b/lib/mods/theme/help/m_symbio.txt
new file mode 100644
index 00000000..b7e04632
--- /dev/null
+++ b/lib/mods/theme/help/m_symbio.txt
@@ -0,0 +1,50 @@
+|||||oy
+~~~~~01|Magic|Symbiosis
+~~~~~02|Symbiosis Magic
+~~~~~03|Skills|Symbiosis - Symbiotic Powers
+#####R === ToME Magic - Symbiosis ===
+
+Symbiosis is the art of joining body, fate and sometimes even mind with
+creatures not capable of moving on their own.
+
+While a humble student of the Craft of Slime (as it's sometimes called)
+has very few options apart from asking the symbiote to help him in combat,
+master practitioners have access to an incredible array of tricks.
+
+Once hypnotised, the monster is placed onto the body, or "worn", in order to
+initiate the symbiotic relationship.
+
+#####uSymbiotic Powers
+There are nine powers a symbiant can develop. They are:
+1. [[[[[uHypnotize] (level 1) Cost:1
+ The very basis of symbiosis itself, this asks a monster to lower its
+ natural defences so that it can be safely "worn".
+2. [[[[[uRelease] (level 1) Cost:1
+ Sometimes even life-long friends part. This power allows you to revert
+ a monster on the floor to its primal state, even though the shock of waking
+ up will lower it to 0 HP.
+3. [[[[[uCharm never-moving] (level 3) Cost:2
+ A symbiant soon learns to communicate with molds and slimes.
+ This power allows him to gain the "friendship" of such a creature.
+4. [[[[[uLife share] (level 5) Cost:5
+ The cells of the symbiant and the symbiote intermingle, spreading damage
+ evenly among the two organisms.
+5. [[[[[uUse minor powers] (level 10) Cost:10
+ Allows you to tap into minor magic abilities provided by your symbiote
+ such as Blink or Slow.
+6. [[[[[uHeal symbiote] (level 15) Cost:14
+ Consciously altering the metabolism of your symbiote, you can urge its
+ bodily structure to repair itself almost instantaneously.
+7. [[[[[uUse major powers] (level 25) Cost:30
+ Highly intelligent slimes such as Quylthulgs may be more than willing to
+ employ their summoning or teleporting powers on your behalf; this power
+ can also call upon the abilities normally invoked by "Use minor powers"
+ (but this would be a waste of mana).
+8. [[[[[uSummon never-moving pet] (level 30) Cost:35
+ By releasing certain chemicals in the air, a symbiant can attract the
+ attention of slimes and mold; the better specimens are found in deeper
+ dungeons, of course.
+9. [[[[[uForce symbiosis] (level 40) Cost:60
+ An expert symbiant has such control over the cells of primitive
+ life-forms that he can temporarily "charm" part of them, thus forcing
+ their powers to manifest at his own advantage.
diff --git a/lib/mods/theme/help/m_tempo.txt b/lib/mods/theme/help/m_tempo.txt
new file mode 100644
index 00000000..64340ee5
--- /dev/null
+++ b/lib/mods/theme/help/m_tempo.txt
@@ -0,0 +1,42 @@
+|||||oy
+~~~~~01|Magic|Temporal School
+~~~~~02|Temporal Magic
+~~~~~03|Skills|Temporal - Spell Info
+#####R === ToME Magic - Temporal School ===
+
+The temporal school of magic contains spells where magic is used to meddle
+in the relationship between time and space. There are rumours of a "Tome of
+the Time" which contains all the temporal school spells within its bindings.
+
+Worshipping Yavanna Kementari or Mandos also gives the ability to cast spells
+from the temporal school at a level of 1/6 or 1/4, respectively, of your prayer
+level. E.g. if the skill "Spirituality: Prayer" is at level 12, a worshipper
+of Yavanna can cast up to level 2 temporal school spells, whereas a worshipper
+of Mandos can cast up to level 3 temporal school spells.
+
+
+#####sTemporal Spells
+There are four spells available for the temporal school. These Spells are:
+1. [[[[[sMagelock] (school level 1)
+ Magically locks a door.
+ At spell level 30 it creates a glyph of warding.
+ At spell level 40 the glyph can be placed anywhere in the field of vision.
+2. [[[[[sSlow Monster] (school level 10)
+ Magically slows down the passing of time around a monster.
+ At level 20 it affects a zone.
+3. [[[[[sEssence of Speed] (school level 15)
+ Magically decreases the passing of time around you, allowing you to move
+ and act more quickly with respect to the rest of the universe.
+4. [[[[[sBanishment] (school level 30)
+ Disrupts the space/time continuum in your area and teleports all monsters
+ away.
+ At spell level 15 it also may lock them in a time bubble for some turns.
+#####v Your Temporal and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+
+#####GNature spells that can be cast with Temporal skill
+
+1. [[[[[GGrow Trees] (dual school level 6)
+ Makes trees grow extremely quickly around you.
+#####v Your Nature and Temporal skills must have reached a combined average level
+#####v of 6 in order to cast this spell.
diff --git a/lib/mods/theme/help/m_thaum.txt b/lib/mods/theme/help/m_thaum.txt
new file mode 100644
index 00000000..253d52be
--- /dev/null
+++ b/lib/mods/theme/help/m_thaum.txt
@@ -0,0 +1,31 @@
+|||||oy
+~~~~~01|Magic|Thaumaturgy
+~~~~~02|Thaumaturgical Magic
+~~~~~03|Skills|Thaumaturgy - Spell Info
+#####R === ToME Magic - Thaumaturgy ===
+
+Thaumaturgy is a different type of magic where the spells learnt are not
+restricted to one school, nor are they read out of spellbooks. Each time an
+adventurer increases her thaumaturgy skill, she gains access to a few
+[[[[[Rrandom] attack spells, each one automatically "learnt" at a specific
+casting level. Since she doesn't need spellbooks, she does not end up with
+inventory slots being filled up so quickly by the necessary items for safe
+exploration of the dungeon, and can therefore collect more loot.
+
+The downside of this is that she has no ability to choose what spells she
+learns, and no ability to improve the power of a learnt spell. So, a bolt
+spell with damage 1d5 will remain at 1d5 damage for the whole game. And the
+spells learnt are *all* attack spells of some sort (remembering that things
+like light and stone-to-mud can damage some monsters) - so no teleporting, no
+identify, no healing spells are learnt. At most, some wall creation may be
+employed.
+
+Thaumaturgist use their magic through the 'm' key. They then select a general
+group of spells, followed by a specific spell.
+
+Thaumaturgy spells can take the form of:
+- a bolt, targeted at a single location;
+- a beam, which hits all monsters in a line;
+- a ball (either centred on the caster or targetable);
+- an meteor strike (multiple balls in the vicinity of the caster);
+- a spell that affects all monsters in line of sight.
diff --git a/lib/mods/theme/help/m_udun.txt b/lib/mods/theme/help/m_udun.txt
new file mode 100644
index 00000000..a903d9f9
--- /dev/null
+++ b/lib/mods/theme/help/m_udun.txt
@@ -0,0 +1,35 @@
+|||||oy
+~~~~~01|Magic|Udun School
+~~~~~02|Udun Magic
+~~~~~03|Skills|Udun - Spell Info
+#####R === ToME Magic - Udun School ===
+
+The Udun school of magic contains spells where the corrupted forces of Melkor
+Bauglir are used to create the final spell effect. There are rumours of an
+"Unholy Tome of the Hellflame" which contains all the Udun school spells within
+its bindings.
+
+The Udun school is available only to worshippers of *****g_melkor.txt*0[Melkor Bauglir]. They will also
+need some proficiency in the magic schools of Mana, Nature, Conveyance, and Fire
+(or alternatively Sorcery) to cast the Udun spells. On the other hand, the spell
+power of Udun spells is greatly increased by the level of the caster.
+
+#####DUdun Spells
+There are four spells available for the Udun school. These spells are:
+1. [[[[[DDrain] (dual school level 1)
+ Drains the mana contained in wands, staves and rods to increase yours.
+#####v Your Udun and Mana skills must have reached a combined average level
+#####v of 1 in order to cast this spell.
+2. [[[[[DGenocide] (dual school level 25)
+ Genocides all monsters of a specified race on the level.
+ At level 10 it can genocide all monsters near you.
+#####v Your Udun and Nature skills must have reached a combined average level
+#####v of 25 in order to cast this spell.
+3. [[[[[DWraithform] (dual school level 30)
+ Turns you temporarily into an immaterial being.
+#####v Your Udun and Conveyance skills must have reached a combined average level
+#####v of 30 in order to cast this spell.
+4. [[[[[DFlame of Udun] (dual school level 35)
+ Turns you temporarily into a powerful Balrog.
+#####v Your Udun and Fire skills must have reached a combined average level
+#####v of 35 in order to cast this spell.
diff --git a/lib/mods/theme/help/m_water.txt b/lib/mods/theme/help/m_water.txt
new file mode 100644
index 00000000..2eb4cc5a
--- /dev/null
+++ b/lib/mods/theme/help/m_water.txt
@@ -0,0 +1,34 @@
+|||||oy
+~~~~~01|Magic|Water School
+~~~~~02|Water Magic
+~~~~~03|Skills|Water - Spell Info
+#####R === ToME Magic - Water School ===
+
+The water school of magic contains spells where the element of water is
+used to create the final spell effect. There are rumours of a "Tome of the
+Everrunning Wave" which contains all the water school spells within its
+bindings.
+
+Worshipping Yavanna Kementari or Ulmo also gives the ability to cast spells
+from the water school at a level of 1/2 or 3/5, respectively, of your prayer
+level. E.g. if the skill "Spirituality: Prayer" is at level 10, a Yavanna
+worshipper can cast up to level 5 water school spells, whereas an Ulmo
+worshipper can cast up to level 6 water school spells.
+
+#####bWater Spells
+There are four spells available for the water school. These Spells are:
+1. [[[[[bGeyser] (school level 1)
+ Shoots a geyser of water from your fingertips.
+ Sometimes it can blast through its first target.
+2. [[[[[bVapor] (school level 2)
+ Fills the air with toxic moisture to wash away annoying creatures.
+3. [[[[[bEnt's Potion] (school level 6)
+ Fills up your stomach (i.e. satisfy hunger).
+ At spell level 5 it emboldens your heart (boldness).
+ At level 12 it make you heroic.
+4. [[[[[bTidal Wave] (school level 16)
+ Summons a monstrous tidal wave that will expand and crush monsters under
+ its mighty waves.
+5. [[[[[bIce Storm] (school level 22)
+ Engulfs you in a storm of roaring cold that strikes your foes.
+ At spell level 10 it turns into shards of ice.
diff --git a/lib/mods/theme/help/macrofaq.txt b/lib/mods/theme/help/macrofaq.txt
new file mode 100644
index 00000000..97fad944
--- /dev/null
+++ b/lib/mods/theme/help/macrofaq.txt
@@ -0,0 +1,2360 @@
+|||||oy
+~~~~~43|Macros
+~~~~~44|Keymaps
+#####R======================================================================
+#####B ToME Macro FAQ
+
+ Original Angband Macro FAQ by Jim Lyon
+ (jplyon@attglobal.net)
+ 09-Dec-2000
+ Compiled from usenet postings to r.g.r.a
+ and Angband source & documentation
+
+#####B Edited by Dawnmist (angband@dawnmist.8m.com)
+#####B for PernAngband 5.x.x on 03-Aug-2001
+#####B with permission from Jim Lyon
+~~~~~30
+#####R======================================================================
+#####R1. Introduction
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G1.1 About this FAQ
+#####G----------------------------------------------------------------------
+
+This FAQ is mean to be a companion to the standard ToME help files
+for using inscriptions, macros, and keymaps. The ToME help files
+which also describe them are listed in the "References" section.
+
+This documentation is for ToME, version 4.2.x.
+
+#####B==================================
+#####B SPOILER ALERT
+#####B==================================
+
+This document gives some information on how the game does or doesn't
+work that might be considered spoiling.
+(Most players advanced enough to use macros probably won't notice.)
+
+#####G----------------------------------------------------------------------
+#####G1.2 Table of contents
+#####G----------------------------------------------------------------------
+
+ *****macrofaq.txt*30[1. Introduction]
+ *****macrofaq.txt*5[2. Quick start tutorial]
+ *****macrofaq.txt*32[3. Overview]
+ *****macrofaq.txt*33[4. Common macros and techniques]
+ *****macrofaq.txt*34[5. Common questions]
+ *****macrofaq.txt*35[6. Common problems]
+ *****macrofaq.txt*36[7. Inscriptions added by the game]
+ *****macrofaq.txt*37[8. Keys and commands]
+ *****macrofaq.txt*38[9. Pref files]
+*****macrofaq.txt*39[10. Macro editing commands]
+*****macrofaq.txt*20[11. Advanced macro techniques]
+*****macrofaq.txt*41[12. Problems]
+*****macrofaq.txt*42[13. Miscellaneous]
+
+#####G----------------------------------------------------------------------
+#####G1.3 Notation
+#####G----------------------------------------------------------------------
+
+#####BSingle Quotes (')
+These are generally used to delimit a single character to be typed in.
+These shouldn't by typed in themselves.
+
+#####BDouble Quotes (")
+These are generally used to delimit a sequence of characters to be
+typed in. These shouldn't by typed in themselves.
+
+#####BParentheses ( )
+These are generally used for single-key Angband commands.
+
+#####BBraces { }
+These are used to enclose inscriptions. These aren't typed in as part
+of inscribing an item. They are added by the interface.
+
+#####G= Special Keys =
+#####G-----------------------------------
+The following abbreviations are used in this document. These keys may
+be named differently or missing on some keyboards. Some keys may be
+duplicated. These abbreviations shouldn't be typed in literally. For
+example, when F1 is encountered in a string of keys to press it means
+to press the F1 function key, not 'F','1', unless otherwise stated.
+Additional special keys may be listed later.
+
+Alt Alt
+Ctrl Control
+Del Delete
+Esc Escape
+Enter Enter / Return
+F1 Function key F1, ...
+Shift Shift
+
+#####G= System abbreviations =
+#####G-----------------------------------
+Each system that ToME compiles on has a semi-standard 3-letter
+abbreviation. These are commonly referred to in the source and docs
+using "xxx" as a "wildcard" standing for any one of them. In this
+document "***" is used instead because there are actual generic files
+not associated with any specific system that use "xxx". Sometimes this
+refers to a feature instead of a specific system: "xxx" is used for a
+generic / default file, and "new" is used for Adam Bolt's tiles.
+
+~~~~~5
+#####R======================================================================
+#####R2. Quick Start Tutorial
+#####R======================================================================
+
+This section is designed to get you quickly using the most common
+keymaps and macros. Later sections explain the techniques used in more
+detail. These examples may not be the "best" ones to use in real play.
+
+#####G----------------------------------------------------------------------
+#####G2.0 Definitions
+#####G----------------------------------------------------------------------
+
+First, you should know some fundamental terms:
+
+Actions are sequences of keypresses that the game can recognise. They
+can't be recorded by the game, but must be input manually.
+
+Macros and keymaps map a keypress to an action. They can be used to
+customise the keyboard, reduce typing, and speed up game play. Macros
+must be used when the trigger key doesn't have a system-independent
+representation. Keymap actions can only contain underlying commands.
+[[[[[BMost customisation should be done with keymaps instead of macros when]
+[[[[[Bthere is a choice.]
+
+Inscriptions are "markings" which you can put on any game item. One
+use is to label items in a way that doesn't depend on inventory
+position. Another allows verifying the selection of an item. Under the
+right conditions they can save your life.
+
+#####G----------------------------------------------------------------------
+#####G2.1 Swap weapons
+#####G----------------------------------------------------------------------
+
+First inscribe your main weapon:
+(Press the following keys in sequence)
+
+1) { Inscribe an object
+2) * Show inventory list
+3) / Switch to equipment list
+4) a Main weapon slot
+5) @w0 Wield when object 0 is chosen
+6) (Hit Enter)
+
+Now inscribe the second weapon:
+
+1) { Inscribe an object
+2) * Show inventory list
+3) (Choose letter of second weapon)
+4) @w0 Wield when object 0 is chosen
+5) (Hit Enter)
+
+Finally, ToME (unlike standard 'Vanilla' Angband) does
+not have an automatic trigger key to swap items, so it must be
+created. Select a key that is not being used for any other commands
+('X' in the normal keyset is free - see *****command.txt*0[command.txt]), and create
+the following keymap:
+
+1) @ Interact with macros
+2) 8 Create a keymap
+3) X The trigger key for the keymap
+4) w0 Wield object 0
+5) (Hit Enter)
+6) (Hit Esc to exit the editor)
+
+Now to swap weapons, just press the trigger key 'X' which is bound to
+the default keymap "w0". You may also press "w0" directly to swap.
+~~~~~45|Macros|Macro recorder
+~~~~~46|Keymaps|Macro recorder
+#####G----------------------------------------------------------------------
+#####G2.2 Using the macro-recorder
+#####G----------------------------------------------------------------------
+
+You may find all the key-presses involved in ToME a long and time-consuming way
+to play the game. There are ways to speed up repeated commands by assigning
+them to a trigger key which can help. These are called macros or keymaps.
+
+The most obvious use for these in ToME is for mage-types, especially sorcerors,
+who rely on their spells for just about everything. Typing mbaa*t in order to
+fire a Manathrust is fine if you only have to do it once or twice, but can
+quickly get annoying when you're doing it every move. Far easier to assign that
+sequence of keypresses to a single trigger key which you can then press as many
+times as you need. (Until your SP run out of course!)
+
+The easiest way to assign a macro is to use the macro-recorder. Start this by
+hitting the '$' key. You'll then receive a message telling you that the macro
+recorder has now started and you will need to press the '$' key a second time
+to stop the recorder. Preparation is all important here. It is best to be in a
+situation where you really NEED to cast the spell before recording the macro,
+so you use all the correct casting techniques and the game behaves as it would
+in a real (combat) situation (if the spell is to be generally cast in combat).
+
+So assuming we're going to create a macro for manathrust. We've walked into a
+room and there's a nasty small kobold. What do we do?
+
+1) $ Start macro recorder
+2) *t target monster (or player if no monster in Line of sight)
+3) m open skills menu
+4) @ enters verbose mode
+5) Cast a Spell selects skill to use - CASE SENSITIVE
+6) @ enters verbose mode
+7) Manathrust casts spell from any book/spell container - CASE SENSITIVE
+8) $ end macro recorder
+9) y confirms macro keystrokes[[[[[B*]
+10) (choose trigger key)
+11) @ opens macro saving/loading screen
+12) 2 appends macros to a file
+13) (choose a name for the file, e.g. sorceror.prf)
+14) (Hit Enter)
+15) (Hit Esc to exit the editor)
+
+This will search for the spell in all your books and equipment. If it is found,
+in either a book or a wielded item that contains a spell, then the spell is
+cast at the targetted monster.
+
+This technique can be used for all the other skills as well (Use Mindcraft,
+Forge Ammo) etc.
+
+[[[[[B*]If you answer no the recorder continues recording keypresses. If
+you know you have made a mistake, you need to answer yes, and then not
+save the macro!
+
+~~~~~12
+#####G----------------------------------------------------------------------
+#####G2.3 Prevent unwanted use of an item
+#####G----------------------------------------------------------------------
+
+#####BPrevent "losing" an item by "accident":
+
+1) { Inscribe an object
+2) * Show inventory list
+3) (Choose an item)
+4) !d!k!v
+ !d - don't drop (d)
+ !k - don't destroy (k)
+ !v - don't throw (v)
+5) (Hit Enter)
+
+This prevents dropping, destroying, or throwing the item. You will be
+asked if you really want to do so. This is one of the most common
+inscriptions used, and one of the most useful.
+
+#####BPrevent "using" an item at all:
+
+1) { Inscribe an object
+2) * Show inventory list
+3) (Choose an item)
+4) !* Don't do anything with this item without verifying
+5) (Hit Enter)
+
+This inscription is commonly used on Scrolls of Word of Recall...
+~~~~~8
+#####G----------------------------------------------------------------------
+#####G2.4 Saving these macros and keymaps for reuse
+#####G----------------------------------------------------------------------
+
+Save the macros and keymaps for reuse by the current character:
+
+1) @ Interact with macros
+2) 2 Append macros to a file
+ (optionally enter a filename: e.g. dump.prf or dump.txt)
+ (Hit Enter to save the file with the filename shown)
+3) 6 Append keymaps to a file
+ (Hit Enter to save the file with the filename shown)
+4) (Hit Esc to exit the editor)
+
+This pref file will be automatically loaded any time a character with
+a name, race, or class matching the filename is loaded.
+
+The "Append macros/keymaps to a file" commands will append ALL current
+macros/keymaps to the given file. They will not overwrite the file.
+
+You should edit the file to remove macros that weren't added by you,
+to reduce clutter and prevent errors. Unfortunately the best way to do
+this is still "by hand". Open up the pref file in a text editor and
+remove the duplicate macros and keymaps added. These will be added
+after the headers "# Automatic macro dump" and "# Automatic keymap
+dump". The ones you added will be the very last ones in the list. The
+others are the entire set of keymaps and macros from all other prefs
+loaded. (This step isn't necessary, but is very helpful.)
+
+~~~~~32
+#####R======================================================================
+#####R3. Overview
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G3.1 Inscriptions
+#####G----------------------------------------------------------------------
+
+Inscriptions are "markings" which you can inscribe on any game item.
+
+One common use is recording where you got one of your favorite items.
+Example: The Broad Sword 'Glamdring' (2d5) (+10,+15) {icky thing, 50'!}
+
+Another is to note important resists or activations on an item to make
+figuring out resist combinations easier.
+Example: The Nice Shiny Armor (-3) [35,+25] {resDk,resDis,A:Geno}
+
+Inscriptions can "number" an item so that you don't have to know where
+it is in your inventory.
+Example: inscribing your scrolls {@r1} lets you use '1' at the prompt
+for which scroll to read, instead of having to use the inventory letter,
+which can change unnoticed.
+
+Number inscriptions work together with macros to allow reproducible
+labeling of items independent of inventory position.
+
+Note that the game produces "fake" inscriptions, which look like real
+inscriptions, but are really just displayed the same way (e.g. "cursed").
+
+Finally, if you are in symbiosis with another creature, you can name it by
+inscribing it with "#named SomeName" (the word "#named" must be entered
+literally at the start of the inscription). This will tell the game that
+your symbiotic partner should be referred to by its name, rather than simply
+"Your white jelly". This has no effect on game play other than the aesthetic.
+
+#####G----------------------------------------------------------------------
+#####G3.2 Macros
+#####G----------------------------------------------------------------------
+
+Macros are mappings from a single "logical" keypress to a sequence of
+keypresses, allowing you to use special keys on the keyboard, such as
+function keys or keypad keys, possibly in conjunction with modifier
+keys, to "automate" repetitive multi-key commands that you use a lot.
+
+[[[[[BFor keys which don't have a system-independent representation, such as]
+[[[[[Bfunction keys, this is the only way to change their behavior.]
+
+#####G----------------------------------------------------------------------
+#####G3.3 Keymaps
+#####G----------------------------------------------------------------------
+
+Keymaps are vaguely related to macros. A keymap maps a single keypress
+to a series of keypresses, which bypass both other keymaps and any
+macros. Angband uses keymaps to map the original and the roguelike
+keysets to the underlying command set, and allows the user to modify or
+add keymaps of their own. All keymap actions must be specified using
+underlying commands. Keymaps and macros aren't expanded. The original
+keyset is almost identical to the underlying keyset, except that
+"numbers" are mapped to ";" plus a direction, "5" is mapped to ",",
+and a few control-keys are mapped to various things. See *****command.txt*0[command.txt]
+for the full set of underlying commands. Keymaps also allow the
+"disabling" of a command by mapping it to "\x00".
+
+#####G----------------------------------------------------------------------
+#####G3.4 Pref files
+#####G----------------------------------------------------------------------
+
+Preference files save commands such as macros and keymaps which are
+used to customise the game. They are used to implement the "original"
+and "roguelike" keysets. They provide default appearances for items.
+
+They also implement the default behaviors which make Angband look and
+play the same (for the most part) on different systems.
+
+Pref files can be saved with the name of a player name, class, and
+race, and anytime a player with a matching characteristic is loaded,
+the appropriate pref file is loaded. This makes some customisations
+transparent and automatic.
+
+Pref files let you do some things that could otherwise only reasonably
+be done by changing the info files or source, such as changing the
+appearance of a given terrain feature, or the symbol used for the
+player.
+
+Pref files let you set up and save your favorite game options, and
+have them available for new characters without having to redo them.
+
+~~~~~33
+#####R======================================================================
+#####R4. Common macros and techniques
+#####R======================================================================
+~~~~~13
+#####G----------------------------------------------------------------------
+#####G4.1 Clearing the command buffer
+#####G----------------------------------------------------------------------
+
+[[[[[v++++++++++ This is one of the most important techniques! ++++++++++]
+
+Almost all action strings should begin with a sequence to clear the
+buffer of existing commands and messages. These sequences are often
+omitted in usenet postings and in this FAQ because they clutter the
+description, but they should almost always be used.
+
+If an unfinished command is still waiting for input when you press the
+trigger key of a macro or keymap, the characters of its action string
+will be taken as input for the command. The command will ignore keys
+it doesn't know how to handle until it finds one that it does. This
+often leads to something completely unexpected, with embarrassing
+results such as your death, or losing a really nifty item.
+
+If there are still messages waiting, the first characters in the
+action will instead just clear the waiting messages. How this happens
+depends on whether the *****option.txt*1[option (quick_messages)] is set. Then the action
+will start executing in the middle of its action string, with equally
+dangerous results as in the above case. Note that some messages caused
+by a command are quite rare, and others could be produced by a game
+state change like becoming hungry that has nothing to do with the command.
+
+These types of problems are more common when using an action such as
+auto-firing where a trigger key is repeatedly pressed.
+
+[[[[[B"\e\e\e"]
+Multiple escapes are used to clear the command buffer. Escape cancels
+any command/input still being processed, and also clears a [single]
+message whether/not the (quick_messages) option is set. This string
+should be used to begin all action strings. It is also wise to put it
+between actions in multi-action macros. Note that this technique can
+also be dangerous, hiding warnings or important information.
+Example: an action like "*tf1" would be changed to "\e\e\e*tf1".
+
+There are a few situations in which you do not want to use escapes.
+For example, after the spell Detect Monsters, an escape will clear the
+detection. Or if the action is part of a multi-part action or is meant
+to wait for user input such as the firing action "f1" which will wait
+for targeting information.
+
+[[[[[B"\s\s\s"]
+Spaces are useful for clearing messages, but won't cancel a command
+that is waiting for an item choice. Sometimes it is useful to split
+an action into two parts and bind them to two separate trigger keys.
+Prefixing spaces before the 2nd action will discard any remaining
+messages without canceling unfinished commands from the 1st one. Some
+players create a macro consisting of a large number of spaces to be
+used to clear a flood of messages.
+
+See sections:
+- *****macrofaq.txt*1["Messages and Questions"] for how to deal with them.
+- *****macrofaq.txt*2["My macro outputs "e - Floating Eye"..."] for an example of a common
+ mistake using escape sequences.
+- *****macrofaq.txt*3["My macro drops/takes off my main weapon!"] for an example of the
+ kind of thing that can go wrong when you fail to use them.
+- *****macrofaq.txt*4["What just killed me?"] for an example of skipping over messages
+ *too* fast.
+
+#####G----------------------------------------------------------------------
+#####G4.2 Swap weapons
+#####G----------------------------------------------------------------------
+
+If you followed the *****macrofaq.txt*5[Quick-Start Tutorial] in Section 2.1, the 'X' key has
+the keymapping "w0", which will wield the first item inscribed as "@0"
+or "@w0". This will swap between 2 weapons which are both inscribed with
+{@0} or {@w0}. If there is more than one item in the inventory inscribed
+as 0, it will use the first one.
+
+This will also work for other wieldable items. For example, if you
+have a helm which gives telepathy, which can be a real pain when you
+need to rest, it can be used to swap it with another helm.
+
+Inscribing weapons with {@w1@w0}, {@w2@w0} allows directly wielding a
+specific one. If you don't want that ability, you can just inscribe
+both with {@w0}. These can also be inscribed as just {@1@0} and {@2@0}
+if you don't inscribe any other items with numbers, although this is
+not recommended.
+
+
+#####G----------------------------------------------------------------------
+#####G4.3 Resting
+#####G----------------------------------------------------------------------
+
+#####B= Rest as needed =
+"R&\r"
+R - rest
+& - until 100% healthy
+\r - return.
+
+Note that this isn't particularly dangerous, because the game will
+break out of the resting command if you are disturbed by hunger,
+sensing a monster, ...
+
+#####B= Rest for a specific duration =
+"R100\r"
+R - rest
+100 - turn count
+\r - return
+
+This version is useful if you are already healed up. For fighter
+pseudo-id, for example. Also useful for recovering a fixed amount of
+mana before/after a spell, waiting for a Recall spell to kick in,...
+
+Note that this is one of the few times when you can directly enter the
+count after the command. Usually you need to enter the count before
+the command, using the (0) count command.
+
+#####B= Maximum Rest =
+"R9999\r"
+
+The maximum number of turns you can use as an argument. This can be
+useful when waiting for shop inventory to change, etc. Be sure to take
+off any non-permanent light source, and have plenty of food when you
+rest for long periods of time.
+
+#####G----------------------------------------------------------------------
+#####G4.4 Activate the phial
+#####G----------------------------------------------------------------------
+
+"Am\s\s"
+A - Activate
+m - light source (the phial).
+\s - skip message
+\s - skip message
+
+"Am\s\sR50\r"
+Activate the phial and rest for 50 turns.
+
+This can be bound to 'F' key since you won't need to refuel lanterns
+much after you have the phial :).
+
+#####G----------------------------------------------------------------------
+#####G4.5 Kill item(s) on floor
+#####G----------------------------------------------------------------------
+
+The need to destroy large numbers of items arises as one reaches
+deeper levels of the dungeon. The auto-squelch feature only partially
+reduces the need for this. The behavior of these actions is affected
+by the option (quick_messages), and the possible presence of a pile of
+items on the floor.
+
+*****option.txt*1[(quick_messages)] allows any key to cancel a message.
+
+In ToME, multiple items on the floor are displayed in a list.
+This allows the player to select an item from the floor by entering an
+item index when there is a pile (more than one item). This generally
+complicates writing these macros.
+
+Note that space '\s' is used to clear messages in the action strings,
+but one could use escape '\e' just as well.
+
+Note: you cannot destroy artifacts, so these macros are safer and more
+useful than they might first appear. The (k) Destroy item command will
+fail when trying to destroy an artifact, leaving any following
+characters in the action string, which may be interpreted differently
+than anticipated.
+
+[[[[[B"k-yy"]
+k - Kill item
+- - Select item from floor
+y - "yes" to query "Really destroy a <item>?"
+y - skip the "you destroy the <item>" message.
+
+This version only works when (quick_messages) option is on. Here the
+last 'y' key gets rid of the last message, since any key will. This
+won't work for piles. The 'y' will be ignored as an invalid item choice.
+
+[[[[[B"k-y\s"]
+k - Kill item
+- - Select item from floor
+y - "yes" to query "Really destroy a <item>?"
+\s - skip the "you destroy the <item>" message.
+
+This version works as above, but also when (quick_messages) is off.
+
+[[[[[B"0k-y\s"]
+0 - enter count (causes to skip prompt for how many to destroy)
+k - Kill item
+- - Select item from floor
+\s - skip the "you destroy the <item>" message.
+
+Destroy a single item on floor below you. Doesn't prompt for a count.
+This won't work for piles, which will prompt you for the item. Works
+correctly when (quick_messages) is off, because there is no prompt
+for how many to destroy.
+
+[[[[[B"0k-ay\e"]
+0 - enter count (causes to skip prompt for how many to destroy)
+k - Kill item
+- - Select item from floor
+a - either item 'a', or ignored
+\e - escape (ignored), or cancel message
+
+Destroy a single item on floor below you. Doesn't ask to confirm.
+[[[[[vWARNING:] This action can destroy the first item in your inventory if
+there aren't any items on the floor below you!
+
+The leading '0' causes a prompt for a count to be skipped. If there is
+a pile, the 'a' key will select the top item in the pile. If not, the
+'a' will aim a wand, the following 'y' will be ignored, and the final
+escape will cancel the aiming.
+
+[[[[[B"0k-yay\e"]
+0 - enter count (causes to skip prompt for how many to destroy)
+k - Kill item
+- - Select item from floor
+y - "yes" to query "Really destroy a <item>?", or ignored.
+a - top item (a) in a pile, or activate wand.
+y - "yes" to query "Really destroy a <item>?" (for piles).
+\e - skip the "you destroy the <item>" message.
+
+The above action will work in most cases. This version works correctly
+for piles. If there is a pile, the 'y' is ignored and the 'a' selects
+the top item. If there isn't a pile, then the 'y' will correctly answer
+the yes/no question "Really destroy a <item>?", and the following "ay"
+will aim a rod, and then ignore the 'y' key press, and the final escape
+will cancel the aiming. Works correctly when (quick_messages) is off.
+When (quick_messages) is on, and there is no pile, the 'a' will cancel
+the message, and the following 'y' will be passed through as an
+unimplemented command, and the space will cancel the error message.
+
+Backslashes "\\" may be required to keep the 'y's from being
+interpreted as keymaps in case 'y' has been assigned one.
+
+#####G----------------------------------------------------------------------
+#####G4.6 Fire missile at nearest target
+#####G----------------------------------------------------------------------
+
+Each of these needs "\e\e\e\e" afterwards to cancel up to 4 possible
+messages. The first message will always occur. Note that adding too
+many escapes can cause you to miss the messages in which the monster
+fights back.
+- "You have NN <ammo> left. -more-"
+- "The <ammo> hits the <monster>. -more-"
+- "It was a <adj> hit! The monster ... -more-"
+- "The <monster> dies/grunts with pain/..."
+
+[[[[[B"f*t"]
+f - fire ammo from quiver slot
+* - target
+t - select first target
+
+Note that targeting is affected by the option (*****option.txt*4[use_old_target]). If
+this action is used with the (use_old_target) option set, the "f"
+part will fire the missile before the targeting part "*t" is reached.
+See section *****macrofaq.txt*6["My auto-firing macro shoots the wrong target!"].
+
+[[[[[B"*tf"]
+*t - select first target
+f - fire ammo from quiver slot
+
+If (use_old_target) is on, this works correctly, by selecting the
+target before firing. If the option is off, it will still prompt you
+to select a target, even though you just selected one.
+
+[[[[[B"*tf*t"]
+*t - select first target
+f - fire ammo from quiver slot
+*t - select first target
+
+This works correctly for (use_old_target) either on/off. If the option
+is on, this works by selecting the target before firing. If the option
+is off, the first target selection will be ignored, and firing will
+wait on the second target selection.
+
+Note that if there are no valid targets, "*t" will select the player's
+current position. Also, it is fairly easy to make safe assumptions
+about the (use_old_target) option, since a player doesn't tend to
+change back and forth. It is generally easier to make one set of
+actions that work for (use_old_target) on, and another for it off.
+
+Note also that the swapping weapon macro can be very useful for swapping
+the type of ammo in the quiver slot when you have two different sets of
+ammo you use - your standard "fire at everyone normal" ammo (usually
+not enchanted), and your big damage "Uniques and nasty monster"
+enchanted ammo.
+
+#####G----------------------------------------------------------------------
+#####G4.7 Preventing actions
+#####G----------------------------------------------------------------------
+
+#####B= Prevent selling =
+{!d}
+Prevent selling - use on main weapon, artifacts.
+
+#####B= Prevent going up/down =
+{^<}
+Verify before going up stairs.
+{^>}
+Inscribe boots to make confirm before going down stairs.
+This can also be useful on Charisma boosting items that you wear
+around town but don't want to take into the dungeon.
+{^>^r^z^m^p}
+Prevent leaving town with this item. Need to catch stairs, scrolls and
+rods of Recall, and Mage and Priest Word of Recall spells.
+
+#####G----------------------------------------------------------------------
+#####G4.8 Warrior macros and inscriptions
+#####G----------------------------------------------------------------------
+
+#####B= Identify with list =
+Inscribe Identify scrolls {@r0}.
+Then action "r0*" will cast Identify and bring up the inventory list.
+
+#####B= Identify floor =
+"r0-" will Identify without showing the inventory.
+
+#####G----------------------------------------------------------------------
+#####G4.9 Verification techniques
+#####G----------------------------------------------------------------------
+
+#####B= Verify All =
+{!*}
+verify any attempt to use this item. Useful for some things such as
+Scrolls/rods of Recall that you don't want to lose or use by accident.
+
+#####B= Verify drop, destroy, throw =
+{!d!k!v}
+don't drop, destroy, or throw this item. Prevents dropping your
+favorite weapon,... This is one of the most useful inscriptions, as it
+prevents the kind of typing accidents that can get you killed.
+
+#####B= Verify selling =
+{!d}
+Prevents selling as well as dropping.
+
+#####B= Multiple verification =
+These inscriptions can be repeated. So {!*!*} will make you confirm
+twice for any action using that item.
+
+#####G----------------------------------------------------------------------
+#####G4.10 Canceling targeting
+#####G----------------------------------------------------------------------
+
+[[[[[B"*\e\s"]
+* - start targeting
+\e - cancel targeting.
+\s - skip message "Target Aborted."
+
+OR
+
+[[[[[B"*q\r"]
+* - start targeting
+q - cancels targeting.
+\r - skip message "Target Aborted."
+
+This is useful before casting Stone to Mud, or a ball spell. For ball
+spells you usually want to target the middle of a pack, or sometimes
+to "miss" the creature in order to get the ball to detonate on a
+nearby wall.
+
+Using a targeted action after this will cause the user to be prompted
+for a target.
+
+Canceling targeting is made necessary by the existence of the option
+(use_last_target), which causes an action which requires a target to
+use the last target without prompting. See section
+*****macrofaq.txt*6["My auto-firing macro shoots the wrong target!"] for more on this.
+~~~~~15
+#####G----------------------------------------------------------------------
+#####G4.11 Automatically loading pref files
+#####G----------------------------------------------------------------------
+
+Angband automatically loads pref files when a character is loaded or
+born. Among the last ones loaded are: "<$RACE>.prf", "<$CLASS>.prf",
+and "<$PLAYER>.prf", in that order. These are the best ones to use to
+customise the game for individuals. The order is important because
+pref files which load later will overwrite options and macros/keymaps
+from previous ones.
+
+Here <$RACE> is the name of the character's race, <$CLASS> is the name
+of its class, and <$PLAYER> is the character's name. Both <$RACE> and
+<$CLASS> have a fixed number of choices. These are listed for ToME
+in section *****macrofaq.txt*7["Pref file loading order"].
+
+Your character's name is the one that appears during game play in the
+upper left hand corner of the screen. If it isn't visible there, you
+can use the (C) Character description command. Note that this name may
+be different than the filename of the character's save file.
+
+Filenames for the save and pref files are built from a "base name",
+which is the player name with all non-alphanumeric characters changed
+to underscores (_). On Windows and DOS systems the base name will also
+be truncated to 8 characters. This could lead to different characters
+having the same (default) pref files.
+Example: "Grog the Elder" and "Grog the Younger" would both try to
+load the same pref file "Grog_the.prf".
+
+In recent versions of ToME "<$PLAYER>.prf" is the default filename
+when saving your macros and keymaps from the (@) Interact with macros
+screen. Just hit Enter to accept that name.
+
+On some systems you may encounter problems automatically loading this
+file if your name is more than 8 characters, or if it contains spaces
+or special characters.
+
+See section *****macrofaq.txt*8["Saving these macros and keymaps for reuse"] for how to
+save your character's preferences.
+
+See section *****macrofaq.txt*7["Pref file loading order"] for the full list of pref files
+loaded and their order.
+
+Note: for pref files to load automatically they must end in the file
+extension "prf", which is the default when saving pref files. But it
+is possible to save and load pref files with any or no file extension,
+from the macros and visuals editor screens.
+
+#####G----------------------------------------------------------------------
+#####G4.12 Multiple macros bound to one trigger key
+#####G----------------------------------------------------------------------
+
+Angband supports using modifier keys on trigger keys. One thing this
+lets you do is easily choose between variants of an action. Another is
+to minimise the amount of moving your hands have to do, speeding up
+play and reducing stress on your wrists.
+
+[[[[[BYou can bind multiple versions of the same macro to the same trigger]
+[[[[[Bkey, using Alt, Control, Shift in different combinations] to choose
+among the different versions.
+Example: use <Alt> for targeted, and <Shift> for non-targeted.
+
+Another use is to heavily use modifiers on numeric keypad keys. The
+standard version already comes with Shift-<digit> bound to running in
+that direction. But by using various combinations of modifier keys, it
+is possibly to play with the right hand almost always on the numeric
+keypad, and the left on the modifier keys.
+
+#####G----------------------------------------------------------------------
+#####G4.13 Multi-part actions
+#####G----------------------------------------------------------------------
+
+Better to only do this when spells have ~0% failure.
+Be careful of the order of commands. Commands that leave useful info
+on the screen shouldn't be followed by ones that will clear it.
+Be careful of commands that set or clear targets.
+Use "\e\e\e\e" in-between commands to be safe.
+
+#####G----------------------------------------------------------------------
+#####G4.14 Easy running
+#####G----------------------------------------------------------------------
+
+Bind Shift+<keypad dir> to running for each of the directions.
+For example, running "North":
+
+1) @ Interact with macros
+2) 4 Create a macro
+3) Shift+8 (Trigger key for the macro)
+4) \\. Run
+ 8 "North"
+5) (Hit Enter)
+6) (Hit Esc to exit the editor)
+
+Macros for the other directions are added similarly. Remember that the
+original and roguelike keysets differ, but using the backslashes makes
+sure that the "underlying" keyset gets used:
+ 7 8 9
+ 4 6
+ 1 2 3
+
+These macros are already in the "pref-***.prf" files that ship with
+the standard Angband distribution for some systems, but not all.
+Systems "mac", "win", "x11" have them. If you aren't sure if you have
+them, just try moving in any direction with the shift key down.
+
+[[[[[BThese do have to be macros instead of keymaps], because they rely on
+keypad keys having different scan codes than the top-row number keys.
+
+There are also default macros for Ctrl+<dir> which applies the command
+(+) Alter to that direction.
+
+#####G----------------------------------------------------------------------
+#####G4.15 Farming techniques
+#####G----------------------------------------------------------------------
+
+#####v+++ NOTE: This is considered scumming! (cheating) +++
+
+Farming is the practice of automatically "harvesting" large numbers of
+weaker monsters for their experience value. This is usually done to
+advance a lower level character. There are apparently several methods
+that the "old timers" used to use. I don't know that farming is that
+popular any more. Even then it was sort of a lark.
+
+Apparently a golf ball is just the right size and weight for many
+keyboards to hold a key down and get it to auto repeat. Then you walk
+away, and the next morning you have gained several levels. Ballpoint
+pen caps are also supposed to be good at wedging a key down.
+
+Using a farming macro for long periods of time like this requires a
+way of getting food, so it really needs to be employed by a magic user
+who can create their own food.
+
+Use turn counts with attack (move) commands to move around the room,
+mowing down creatures as you move. Periodically rest enough to
+regenerate to full mana. This may not be necessary if it takes long
+enough to kill the monsters as you move.
+
+This requires an effective macro and a room full of breeders which
+can't attack for enough damage to kill you. Farming for short periods
+of time with a fighter class is quite feasible. The limitation for
+fighters is food. The limitation for spell casters is probably hit
+points. You may also need to insert action sequences for healing if
+the farmed monsters are capable of significantly damaging you.
+
+Note that red and green worm masses can knock down the doors of the
+room you're in. Blues can destroy potions and flasks, so you will need
+to stash your potions outside somewhere before farming.
+~~~~~10
+#####G----------------------------------------------------------------------
+#####G4.16 Macros can contain their own trigger key
+#####G----------------------------------------------------------------------
+
+It is permissible to make a macro or keymap which contains its own key
+in its action. It won't cause recursion, but there are a few wrinkles.
+
+Example: you can bind "*tf1" to the 'f' key, to cause it to auto-fire
+at the nearest target. You can still use the 'f' key for Fire in other
+macros or keymaps.
+
+If you bound 'f' as a keymap you will need to use "\\f" for Fire when
+it is used in a macro action string. You don't need to do anything
+special to use it in a keymap in its usual sense. Keymap and macro
+expansion isn't done inside keymap action strings.
+
+If you bound 'f' as a macro, the problem will be in entering the new
+macro or keymap in the editor. When you try to press an 'f' key for
+the action, it will expand to "*tf1", even when you don't want it to.
+You will first have to remove the macro bound to 'f', then add the
+macro or keymap that uses 'f' in its action, and then reenter the 'f'
+macro. You can also create the macro in a pref file and load it using
+the "Load pref file" command in the (@) Interact with macros screen.
+
+#####G----------------------------------------------------------------------
+#####G4.17 Changing the player's color and character (ASCII text display)
+#####G----------------------------------------------------------------------
+
+#####B= Using the Visuals Editor =
+1) % Interact with visuals.
+2) 6 Change monster attr/chars
+3) a (repeatedly) cycle thru colors (A moves backwards)
+4) c (repeatedly) cycle thru characters (C moves backwards)
+5) Esc accept changes
+6) Esc exit the editor
+
+#####B= Using the Enter User Pref command =
+1) " Enter user pref line
+2) "R:0:<attr>:<char>"
+ The user pref line.
+ <attr> - the attr (color) specified as an integer index.
+ <char> - the (ASCII) character specified as an integer.
+3) (Hit Enter)
+
+You can't directly use the Angband attr letters to specify colors, but
+must instead use their index. Eg 4 is Red. These indexes can be found
+from within the game using the (&) Interact with colors command. That
+editor also allows you to change the colors used by the game.
+
+The <char> integer is generally the index of an (ASCII) character.
+Non-ASCII characters may be available on some systems. Available
+characters can found using the (%) Interact with visuals command.
+
+These integers can be specified in decimal, hexadecimal, or octal
+notation. Decimal is the default, hexadecimal numbers are prefixed
+with "0x", and octal numbers are prefixed with 0 (zero). Example: the
+standard character for the player is '@'. This may be entered as "64",
+"0x40", or "0100". Yellow may be entered as "11", "0x0B", or "013".
+
+This pref line can be added to any pref file to save the change for
+future reuse. Changes made using the internal colors editor screen can
+be dumped from that screen. Note that colors and characters saved in
+pref dumps are in hexadecimal.
+
+After making a change, you must move the character or otherwise cause
+a screen redraw for the change to be visible.
+
+If you make a mistake, you can use the (0) command in the editor to
+reset the visuals to their original colors and characters.
+
+#####B= Changing Using the Monster Info file =
+#####B----------------------------------------
+
+This may also be done by changing the entry for the player in the info
+file "r_info.txt". The player data starts with line "N:0:Player". In
+the following line G:<c>:<a> the character <c> is entered directly,
+and the attr (color) is specified by letter. See the section "Message
+color lines" for the list of standard colors. In many versions you
+will have to delete the file "lib\data\r_info.raw" and restart the
+game for this change to take effect. Note that that char/attr pair is
+entered in the opposite order as for an R: user pref line.
+
+#####B= Options which Change Player appearance =
+#####B------------------------------------------
+
+These are accessible through the (=) Set options command.
+
+*****option.txt*2[(hilite_player)] -- causes the player's symbol to be drawn with the
+"cursor" on it. It will be drawn with the same color as the character.
+
+*****option.txt*3[(player_symbols)] -- for graphics mode only, and only works when option
+(use_graphics) is also on. This apparently varies the player graphic
+and its color based on class, race, and sex.
+
+#####G----------------------------------------------------------------------
+#####G4.18 Recharging a rod using a Recharge Item spell
+#####G----------------------------------------------------------------------
+
+(You can also recharge staffs and wands with this technique.)
+
+Inscribe the rod with {@m<d>}, where <d> is any decimal digit not
+already used as a label.
+
+The trick is that we want to use a digit to label the rod so we can
+refer to it using its label instead of its inventory letter, but we
+have usually used up many of the digits for spell books. If we were to
+label the rod with {@m1} and the first spellbook was also labeled with
+{@m1}, then the spellbook will sort first in the inventory so it will
+be found first when looking for item '1' to use with the (m) command.
+So that would try to recharge the spellbook, which will fail. Angband
+doesn't restrict itself to "appropriate" items when looking for a
+labeled item. It simply finds the first one whose command letter and
+digit match.
+
+You can't get around this by omitting the letter 'm', or using 'z'
+instead. Using no command letter means it will still match. And if you
+use a command letter it has to be 'm', because that is the built-in
+trigger for the current command.
+
+Note that the digits used with different command triggers can be
+different, so inscribing {@z1@m0} is perfectly legal. Use digit 1
+when zapping the rod, and 0 when referring to it during the casting
+of a [mage] spell.
+
+You can also use this technique with scrolls. In that case you need to
+use the inscription {@r<d>} since the item is being referred to while
+processing the (r) Read scroll command.
+
+#####G----------------------------------------------------------------------
+#####G4.19 Disabling a built-in command
+#####G----------------------------------------------------------------------
+
+At times it may be useful to disable an underlying Angband command.
+For example, a dangerous key may be too easy to press by accident.
+The macro editor commands for removing macros and keymaps can't be
+used in this situation. [[[[[BInstead bind the trigger key to the action]
+[[[[[Bstring "\x00"]. This special 'command' takes no "energy" and won't
+generate an error message. It truly does "nothing". This will work for
+both macros and keymaps. If possible you should use a keymap instead
+of a macro to disable the key. A keymap will catch occurrences of the
+key both in macros and by typing, and will still allow you to use the
+key when it isn't being interpreted as a command.
+
+If you use the "Query a macro/keymap" on a trigger key bound to this
+action, it will report having found it, but no action string will be
+printed.
+
+Another technique is to use the action "\e\e\e". This is used in some
+of the standard pref files.
+
+[[[[[BIf you need to use the built-in command again you can use the '\' key]
+[[[[[Bat any prompt to bypass its macro/keymap.]
+
+#####G----------------------------------------------------------------------
+#####G4.20 "Naming" an item (patch)
+#####G----------------------------------------------------------------------
+
+#####B= 'Fake artifact' name =
+# "Name" an item
+This isn't an actual command in the interface, but a flag character
+that alters the way an item description is generated. This isn't part
+of standard Angband. It's added by Tom Morton's 'fake artifact' patch.
+
+Example: inscription {#Thumper} will cause a Club (+8,+8) to display
+as Club 'Thumper' (+8,+8) in your inventory and messages.
+
+~~~~~34
+#####R======================================================================
+#####R5. Common Questions
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G5.1 Why can't I add a keymap for a function key?
+#####G----------------------------------------------------------------------
+
+Because keymaps can only be created for keys with system-independent
+representations. This leaves out function keys, and several other
+special keys. The "Create a keymap" command will continue waiting for
+a keypress until you press a valid keymap trigger. You can, however,
+create a macro for a function key.
+
+#####G----------------------------------------------------------------------
+#####G5.2 How can I automatically inscribe items when I pick them up?
+#####G----------------------------------------------------------------------
+
+You need to turn on the "Merge inscriptions when stacking" option.
+If you are already carrying the same item with an inscription, a new
+one will be added to the stack. Note that this WON'T merge discounts.
+Although discounts display like inscriptions, they are different.
+
+1) = Options
+2) 1 User interface options
+3) "Merge inscriptions when stacking" (stack_force_notes)
+ move down to this line and change to "yes".
+
+#####G----------------------------------------------------------------------
+#####G5.3 Can I use macros inside other macros?
+#####G----------------------------------------------------------------------
+
+No. Macros don't expand macro triggers they contain in their actions,
+in order to avoid recursion and other problems. However, keymap
+substitution is done, so you can use keymaps to alter the behavior of
+macros. This keymap expansion can be bypassed by preceding a trigger
+with "\\" in the action.
+
+Keymaps don't expand macro or keymap triggers in their actions.
+
+Also see section *****macrofaq.txt*9["Can I create an infinite loop using a macro?"].
+
+#####G----------------------------------------------------------------------
+#####G5.4 How do I find out what the standard commands are?
+#####G----------------------------------------------------------------------
+
+1) ? Angband help
+2) 6 *****command.txt*0[Command Descriptions (command.txt)]
+
+Space - moves you down by a page
+Minus - moves up by a page
+2 - moves down by a line
+8 - moves you up by a line
+
+Note that the original and roguelike command sets differ, and both are
+different from the "underlying" command set.
+
+#####G----------------------------------------------------------------------
+#####G5.5 How can I tell if a key has a keymap/macro?
+#####G----------------------------------------------------------------------
+
+#####B= Query Macro/Keymap =
+
+In ToME this is easy:
+1) @ Interact with macros
+2) 3 Query a macro
+OR 7 Query a keymap
+3) (Press the trigger key to test)
+4) Esc (Exit macro editor when done)
+
+It will report "Found no macro" or "Found a macro" at the top of the
+screen. The action it is bound to will be displayed at the bottom of
+the screen, under the "Current action..." line. You must test for both
+macros and keymaps, and keymaps will only show for the current "mode",
+i.e. original/roguelike.
+
+#####B= Notes =
+
+Note: on some machines, there are duplicate keys such as left and right
+Shift keys. These will generally produce different key codes and can
+have different macros and keymaps.
+
+Note: just because a key doesn't have a macro doesn't mean there isn't
+a command that uses that key.
+
+#####G----------------------------------------------------------------------
+#####G5.6 How can I tell if a key has a built-in command bound to it?
+#####G----------------------------------------------------------------------
+
+Er ... try pressing the key. If there is a command bound to that key
+it should usually generate a message of some kind. If there isn't one,
+it may respond: "Type '?' for help.". Some keys may not generate any
+message at all. Function keys are a good example.
+
+In ToME, the game will also generate "silly" error messages
+which may not look like error messages at first. After a few repeated
+key presses it uses the standard "Type '?' for help." message.
+
+Failing that, look in *****command.txt*0["command.txt"], which lists all
+commands, and is up-to-date. There is no specific method for checking if
+a key has a command bound to it from within the game.
+
+#####G----------------------------------------------------------------------
+#####G5.7 Can I inscribe multiple items with the same number?
+#####G----------------------------------------------------------------------
+
+You can, but it can cause problems if you aren't careful. Use the
+command letter in the inscriptions to minimise problems. For example,
+it is safe to inscribe both rods with {@z1} and a spell book with
+{@m1} because the command letter allows distinguishing the two.
+
+When the game looks for an item to use with a command, it tries the
+first one it finds that matches. If the command fails on that item, it
+doesn't continue looking. The search for a matching item also doesn't
+know how to only check the right kind of item, so if you have a Spellbook
+inscribed {@1} and scrolls inscribed {@1} or {@r1}, when you read a
+scroll it will find the spellbook first, even though it doesn't make
+sense to read it, and the command will fail.
+
+#####G----------------------------------------------------------------------
+#####G5.8 How do I convert a macro to a keymap?
+#####G----------------------------------------------------------------------
+
+You can simply remove it and re-add it "by hand", but for more complex
+actions there are faster, safer ways.
+
+#####B= Directly modifying the pref file =
+
+A macro with the following form in the pref file:
+ A:<action string>
+ P:<trigger>\r
+Should be converted to the keymap form:
+ A:<action string>
+ C:0:<trigger>
+The "\r" needs to be removed, and the 0 (zero) means standard keyset.
+Use 1 for roguelike keyset. To make a keymap for both keysets:
+ A:<action string>
+ C:0:<trigger>
+ C:1:<trigger>
+
+#####G= Using the "Interact with Macros" editor =
+
+1) @ Interact with Macros
+2) 3 Query a macro
+ <k> The trigger key for the macro
+ (its action string will now become the current action)
+3) 5 Remove a macro
+ <k> The trigger key for the macro
+4) 8 Create a keymap
+ <k> The trigger key for the keymap
+5) (Hit Enter to accept the current action)
+ (Hit Esc to clear the message "Added a keymap")
+
+This technique can also be used to move or copy actions between macros
+or keymaps of the same kind. [[[[[BAnd old macro MUST be removed from a key]
+[[[[[Bbefore it can be used as the trigger key for a keymap], otherwise the
+macro action will expand when you press the trigger key in the editor.
+Converting a keymap to a macro doesn't require removing the keymap
+first.
+
+Note that not all macros can be converted to keymaps. Keymaps don't do
+macro or keymap expansion on their action strings, so macros that rely
+on this will no longer work. Also, keymaps can only be bound to a
+trigger key with a printable internal representation. For example, a
+function key can't be a trigger for a keymap.
+~~~~~9
+#####G----------------------------------------------------------------------
+#####G5.9 Can I create an infinite loop using a macro?
+#####G----------------------------------------------------------------------
+
+No. Well, okay, you can, but only if you work *really* hard at it and
+abuse bugs in the macro handling code. This isn't something that will
+happen by accident just by using the trigger key inside its action.
+
+You also can't create recursion. So don't worry about this. See the
+section *****macrofaq.txt*10["Macros can contain their own trigger key"] for more info.
+~~~~~4
+#####G----------------------------------------------------------------------
+#####G5.10 What just killed me?
+#####G----------------------------------------------------------------------
+
+When you are using lots of escapes and spaces in your macros to skip
+over messages, you can miss important things happening. One of these
+is dying. Usually when something goes wrong, you can just use the (^P)
+Previous Messages command to see what happened. But if you died the
+escapes can take you past the tombstone screen, your last chance to
+examine the previous messages list. This also happens without macros.
+
+To examine your recall, load the savefile and start a new character.
+You will then be able to use the message recall command to see the
+last messages of that character's previous incarnation.
+
+~~~~~35
+#####R======================================================================
+#####R6. Common Problems
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G6.1 My macro works all the time when I press its key!
+#####G----------------------------------------------------------------------
+
+Macros *do* work all the time. Every time you press a key, macro
+expansion is done on it, and then keymap expansion. So if you use 'y'
+as a trigger key for a macro, and then you try and answer a yes/no
+prompt with 'y', instead you will get the macro's action string.
+
+The answer to this is to change your macro to a keymap. These can be
+bound to keys which have a system-independent representation in the
+game, which includes all keys that you would use when interacting with
+the game interface.
+
+If you don't want to change it to a keymap, try changing the trigger
+key to a "special" key, such as a function key.
+~~~~~6
+#####G----------------------------------------------------------------------
+#####G6.2 My auto-firing macro shoots the wrong target!
+#####G----------------------------------------------------------------------
+
+Your macro is probably firing at the previous target. This will happen
+if the option (*****option.txt*4[use_old_target]) is set. Then a macro will like "f1*t"
+or "m1a*t" will execute as:
+
+f Fire
+1 Ammo inscribed 1
+ (it will now fire at the last [wrong] target)
+* Choose a [new] target
+t Accept first target
+
+If there are no valid targets, the (t) targeting command will centre
+on your position. If you move, the target will still be your old
+square. The first time you use the "f1*t" macro it will fire at that
+square, even if there is now a valid target (monster) nearby.
+
+One fix is to turn off the (use_old_taret) option, since the action
+doesn't require it. This is done with the (=) Set Options command.
+
+Another is to change the action to choose the target before it fires.
+Example: "*tf1".
+
+[[[[[BNote:] just because you can "see" a monster doesn't mean you can target
+it. The code used for vision (line of sight) and firing (projection)
+is slightly different. So when shooting near corners or pillars it may
+happen that you can "see" a monster but not target it. If your action
+kills messages at the end, you could keep hitting your auto-fire macro
+and the only thing happening would be a large pile of missiles quietly
+accumulating underneath you.
+
+#####G----------------------------------------------------------------------
+#####G6.3 I used to have items inscribed, and now they aren't!
+#####G----------------------------------------------------------------------
+
+The game only knows about inscriptions that you are carrying. There is
+no way to "store" them independently of a character's save file. So if
+you lose all of an item that was inscribed, picking up another of that
+kind won't automatically inscribe it.
+
+Normal inscriptions aren't affected by your player's "memory".
+
+Note that some items, when fully identified, could have their
+descriptions grow so long that no inscription will show. In that case
+you can use the (I) Identify command. It will display the full
+description, even if nothing special is known about that item.
+
+#####G----------------------------------------------------------------------
+#####G6.4 I changed some macros in a pref file and nothing happened!
+#####G----------------------------------------------------------------------
+
+Settings loaded in later pref files will overwrite earlier ones. So if
+you add macros for the same trigger key to files "<$CLASS>.prf" and
+"<$PLAYER>.prf", the second one will get used because its file loads
+later. This affects macros, keymaps, actions, attrs/colors, and other
+info. See section *****macrofaq.txt*11["Pref lines summary"] for all the types of settings
+that can be loaded. Also see section *****macrofaq.txt*7["Pref file loading order"].
+
+#####G----------------------------------------------------------------------
+#####G6.5 It moves me when I try to use my bow/rod/wand!
+#####G----------------------------------------------------------------------
+
+Example: you type "f1" and it moves you in direction 1 (South West).
+What is happening is that the 'f' key isn't being handled correctly.
+It may be remapped to a bogus command, or one which doesn't take an
+argument. So the 'f' command is skipped/dealt with, and the '1' key is
+then treated as a direction. You can examine what is going on with the
+'f' key using the (@) Interact with macros screen to check for any
+macros or keymaps bound to that key. Use the appropriate "Remove ..."
+command to restore the built-in Angband command.
+~~~~~3
+#####G----------------------------------------------------------------------
+#####G6.6 My macro drops/takes off my main weapon!
+#####G----------------------------------------------------------------------
+
+This is probably caused by an auto-fire macro like "*tm1a" for magic
+missile. If you hold down the trigger key to repeatedly use it, and
+some game event (possibly caused by the macro) creates a message, then
+the action will be interpreted as:
+* (cancel message)
+t Take off item
+m (ignored as invalid)
+1 (ignored as invalid)
+a Item a (main weapon)
+
+If there is room in your inventory, it will be put there. If not, your
+inventory will overflow and it will be dropped on the ground. If this
+happens during combat this is a very good way to die. This is just
+another good reason to have {!d!k!v} on your main weapon. See the
+section *****macrofaq.txt*12["Prevent unwanted use of an item"].
+
+This can be fixed by using the escape sequence "\e\e\e" before and
+after the action string to cancel any pending messages or commands.
+See the section *****macrofaq.txt*13["Clearing the command buffer"].
+~~~~~2
+#####G----------------------------------------------------------------------
+#####G6.7 My macro outputs "e - Floating Eye" on the message line!
+#####G----------------------------------------------------------------------
+
+It is wise to add an escape sequence "\e\e\e" to the beginning and end
+of all macros for which this doesn't destroy useful information. See
+section *****macrofaq.txt*13["Clearing the command buffer"] for more information on this.
+
+But many players play on flavors of unix, which uses '/' as the path
+separator for files, and automatically type a forward slash when they
+mean to type a backslash. So many actions in macros/keymaps in usenet
+posts have the wrong type of slash. Angband "gurus" are perhaps more
+vulnerable to this than novices.
+
+The game sees this as:
+/ Identify a character
+e Character to be identified
+And outputs "e - Floating Eye" on the message line.
+
+If this sequence gets expanded when you are trying to select an item,
+it will lead to different behaviors.
+Example:
+/ Switch between inventory and equipment
+e Select item e.
+Or:
+/ Switch between inventory and equipment
+e (ignored because invalid) Select item e.
+/ Switch between inventory and equipment
+e Select item e.
+
+~~~~~36
+#####R======================================================================
+#####R7. Inscriptions added by the game
+#####R======================================================================
+
+Some inscriptions are added by the game itself. These can overwrite
+your inscriptions. There are also "fake" and "special" inscriptions,
+which "look" like real inscriptions to the player.
+
+#####G----------------------------------------------------------------------
+#####G7.1 Fake inscriptions
+#####G----------------------------------------------------------------------
+
+These "fake" inscriptions are "covered up" by real inscriptions, but
+will reappear if the real inscription is removed.
+
+"fake" inscriptions are unaffected by the uninscribe command (}).
+
+{cursed} - cursed item
+{empty} - item out of charges
+{tried} - a "flavored" item which the character
+ has used, but whose effects are unknown.
+{N% off} - item bought on sale
+{quest} - this item is a quest item. It may need to be taken to someone.
+
+#####G----------------------------------------------------------------------
+#####G7.2 Auto-inscriptions
+#####G----------------------------------------------------------------------
+
+These added when your character gets a "feeling" about an item.
+In ToME these are "special" inscriptions, like "fake" inscriptions
+above, which don't overwrite user inscriptions. They just hide user
+inscriptions, which are still there.
+
+{terrible} - cursed or broken artifact
+{broken} - broken item
+{cursed} - cursed item
+{uncursed} - previously cursed item
+{average}
+{good} - good (magical) item
+{excellent} - ego item
+{special} - unique item
+{on sale} - displayed only in the store
+
+~~~~~37
+#####R======================================================================
+#####R8. Keys and commands
+#####R======================================================================
+
+This section gives short descriptions of keys and commands used in
+actions and trigger key representations. They are only listed in this
+section if they aren't fully described elsewhere in this FAQ. Not all
+of these keys are actually for "commands". See the normal Angband help
+for a fuller description of these commands. The commands and keysets
+are documented in *****command.txt*0["command.txt"].
+
+#####G----------------------------------------------------------------------
+#####G8.1 Keysets
+#####G----------------------------------------------------------------------
+
+ToME supports two "keysets", which are fully customisable sets of
+keymaps. The "original" command set is close to the built-in commands,
+with some additions for ease of use such as number keys moving you in
+that direction. The "roguelike" command set allows easy movement on a
+keyboard without a numeric keypad. As a consequence its letter keys
+are almost completely "full". These used to be hard-coded by the game,
+but are now fully customisable. The default keymaps are in "pref.prf".
+
+#####G----------------------------------------------------------------------
+#####G8.2 Item selection
+#####G----------------------------------------------------------------------
+
+(*) - gives list of choices
+(-) - selects item on the floor
+(/) - toggles between the inventory and equipment lists.
+
+(space) - shows list of choices. Pressing (space) again hides the list.
+(lower) - selects the inventory item with that letter.
+(upper) - selects the inventory item with that letter, and requires
+ confirmation.
+(digit) - selects first item inscribed with "@#" or "@x#" where 'x' is
+ the command, and '#' is the digit. Only legal items are allowed.
+
+#####G----------------------------------------------------------------------
+#####G8.3 Directions and Movement
+#####G----------------------------------------------------------------------
+
+Original keyset directions
+7 8 9
+4 5 6
+1 2 3
+
+Roguelike keyset directions
+y k u
+h 5 l
+b j n
+
+#####B= Underlying command keys =
+
+;<dir> - walk (with pickup)
++<dir> - alter
+.<dir> - run
+
+Digits AREN'T built-in movement commands in ToME. They are actually
+keymaps found in the standard pref file "pref.prf". The digits are
+direction arguments to the (;) Walk command.
+
+#####G----------------------------------------------------------------------
+#####G8.4 Escape sequences
+#####G----------------------------------------------------------------------
+
+Many [non-printable] characters have a standard printable encoding
+which uses an "escape" character to change the meaning of the
+following character. The backslash character is used as in the C
+language for many keys. The caret '^' is used for control keys.
+
+#####B= Escape sequences =
+\b backspace
+\e escape
+\n newline
+\r return
+\s space
+\t tab
+\xNN hex ASCII char
+\\ (literal) backslash
+\^ (literal) caret
+
+#####B= Backslash =
+In a macro, "\\" followed by a character uses the "underlying" command
+for that character without translation. This is useful in macros to
+avoid keymaps changing the behavior of the macro. In particular this
+can be used to make macros which work for both original and roguelike
+keysets. Keymaps don't have this problem.
+
+#####B= Newline and Return =
+These two characters can be used interchangeably.
+
+#####B= ASCII chars =
+Any ASCII character can be encoded in this way. So many keys will have
+more than one representation. For example, [Enter] can be "\r", "^M",
+and "\x09". The backslash representations are case sensitive, so "\t"
+is [Tab], but "\T" will just be interpreted as "T". The hexadecimal
+number must be exactly 2 digits.
+
+#####B= Escape and Space =
+See section *****macrofaq.txt*13["Clearing the command buffer"] for their main uses.
+
+#####G----------------------------------------------------------------------
+#####G8.5 Repeats and Counts
+#####G----------------------------------------------------------------------
+
+#####B= Auto repeat =
+Some commands will automatically repeat. These are:
+(T) Tunnel
+(B) Bash
+(D) Disarm
+(o) Open
+(c) Close
+(+) Alter
+
+#####B= Number keys =
+
+0 - starts a repeat count. Some commands take a repeat count argument.
+They can be entered as "0<count><cmmd>". If the command is movement,
+it can (must) be preceded by space(s) to separate the direction
+(command) number from the count number.
+~~~~~1
+#####G----------------------------------------------------------------------
+#####G8.6 Messages and Questions
+#####G----------------------------------------------------------------------
+
+#####B= Yes/No queries =
+Yes/No questions can be answered with 'y', 'n', or Esc. These are not
+case sensitive. Only 'y' or 'Y' will respond Yes. 'n', 'N', and Esc
+are No. If the option (quick_messages) is on, any other keypress is
+also No. When the option is off, it will keep waiting for a valid key.
+
+#####B= "-more-" message prompts =
+These may be cleared by Esc(\e), Space(\s), Enter(\r), or Newline(\n).
+If the (quick_messages) option is on, they can be cleared by any key.
+
+#####G----------------------------------------------------------------------
+#####G8.7 Special keys
+#####G----------------------------------------------------------------------
+
+#####B= Function keys =
+Function keys are free for reassignment, but only as macros. [[[[[BFunction]
+[[[[[Bkeys can be modified by Alt, Ctrl, Shift like other keys.]
+
+#####B= Alt keys =
+Alt-modified keys are generally free for reassignment as either macros
+or keymaps.
+
+#####B= Control keys =
+Control keys can be entered in as "^x" where 'x' is the key. Note
+that the case of 'x' is unimportant. This also allows typing control
+keys which would be intercepted by the operating system, such as ^C.
+You must type the caret '^' and the following key separately. Note
+that some have special meanings, such as ^M for Return, and ^H for
+backspace. Some also have special Operating System meanings, such as
+"^Z" in un*x, and "^C" in DOS. Control keys can be trigger keys for
+both macros and keymaps.
+
+#####B= Interrupting the game =
+(^C) This will kill your character and quit the game, after verifying.
+
+#####G----------------------------------------------------------------------
+#####G8.8 Keys used in inscriptions
+#####G----------------------------------------------------------------------
+
+#####B= Confirm command =
+^ Confirm the following command.
+This isn't an actual command, but a character with a special meaning
+inside command strings. {^*} will confirm all actions for the item.
+
+#####B{=g}
+This inscription will cause an item of the same kind to be picked up
+from the floor without prompting.
+
+~~~~~38
+#####R======================================================================
+#####R9. Pref files
+#####R======================================================================
+
+All pref files are loaded from and saved to folder "\lib\user". The
+folder "\lib\pref" is unused at this time! The location and name of
+this folder can be configured.
+
+Warning: the directory "\lib\pref" is unused by the game. Pref files
+moved there will never get used (unless the user has redirected the
+folder locations).
+
+Integers can be in hex "0x10", decimal "16", or octal "020" formats.
+These are converted using the C library fn strtol(), and are case
+insensitive.
+
+Decimal numbers start with '1'-'9'.
+Octal numbers must start with '0' (zero).
+Hex numbers start with '0x' or '0X'.
+
+#####G----------------------------------------------------------------------
+#####G9.1 Standard Pref files
+#####G----------------------------------------------------------------------
+
+Below "***" stands for the 3-letter system abbreviations, such as
+"acn", "mac", "win", "x11", ...
+
+"font.prf"
+Includes "font-***.prf" files.
+This file defines special attr/char mappings for "text" mode.
+
+"graf.prf"
+Includes "graf-***.prf" files.
+This file defines special attr/char mappings for "graphics" mode.
+
+"pref.prf"
+Includes "pref-***.prf" files.
+This file defines "default" actions of various kinds. This includes
+mapping the original and roguelike keysets to the underlying keyset.
+
+"user.prf"
+Includes "user-***.prf" files.
+This file defines "override" actions of various kinds. It includes the
+pref files based on system, race, and class.
+
+"xtra-***.prf"
+This file defines special attr/char mappings for "graphics" mode.
+Currently this just maps the player icon based on race and class.
+"new" refers to Adam Bolt's tiles.
+
+[[[[[vWarning:] you shouldn't edit the base pref files without a good reason,
+and understanding what you are doing. Breaking these files can make
+your game unusable. They are, however, the place to make changes that
+should affect all users.
+~~~~~7
+#####G----------------------------------------------------------------------
+#####G9.2 Pref file loading order
+#####G----------------------------------------------------------------------
+
+This loading order follows from the order of includes in "pref.prf".
+Files which are "hard-coded" in the source are preceded with an index.
+The rest are included by the other files. Files which come later will
+overwrite settings from earlier files.
+
+(1) "pref.prf"
+ "message.prf"
+ "pref-***.prf"
+
+(2) "graf.prf"
+ "font-xxx.prf"
+ "graf-***.prf"
+
+(3) "font.prf"
+ "font-xxx.prf"
+ "font-***.prf"
+
+(4) "user.prf"
+ "user-***.prf"
+ "<$RACE>.prf"
+ "<$CLASS>.prf"
+
+(5) "<$PLAYER>.prf"
+
+(6) ".angband.prf"
+
+
+= $RACE =
+Can be one of any of the races in ToME.
+
+= $CLASS =
+Can be one of any of the classes in ToME.
+
+= $PLAYER =
+The name of the current player being loaded or born. See section
+*****macrofaq.txt*15["Automatically loading pref files"] for more information.
+
+#####B= Specific pref files =
+#####B-----------------------------------
+
+"user-mac.prf"
+This is the only user pref file with example macros that ships with
+ToME. A good set of examples.
+
+"pref-win.prf"
+This is the same as (missing) "pref-dos.prf" and "pref-ibm.prf".
+
+"colours.prf"
+Amiga only. Contains Amiga palette.
+
+".angband.prf"
+Only on multi-user systems. This doesn't ship with the source. This
+file must be located in the directory contained in environ variable
+"HOME".
+~~~~~11
+#####G----------------------------------------------------------------------
+#####G9.3 Pref lines summary
+#####G----------------------------------------------------------------------
+
+Comment lines start with a '#' and extend to end of line.
+
+Note: integer values can be specified as decimal, as hexadecimal by
+preceding with an "x", or as octal by using a leading "0" (zero).
+
+E:<tv>:<a> - attr/char values for inventory objects by index
+F:<num>:<a>:<c> - attr/char values for features by index
+K:<num>:<a>:<c> - attr/char values for objects by index
+R:<num>:<a>:<c> - attr/char values for monsters by index
+S:<num>:<a>:<c> - attr/char values for special things by index
+
+A:<str> - action line
+ An action line should be followed by a keymap trigger "C:" line
+ or a macro trigger "P:" line. There can be intervening comments
+ and lines. The same action will be [re]used by all keymap and
+ command lines which follow it until there is another action line.
+P:<str> - macro line
+ <str> a macro encoding of a keypress. (system dependent)
+C:<mode>:<str> - keymap line
+ <mode> 0 = "original, 1 = "roguelike".
+ <str> logical keypress, including backslash codes such as "\e" and
+ control codes such as "^K". (system independent)
+ Note that there are 2 independent sets of keymaps now. Changing a
+ keymap in one doesn't affect the other.
+
+V:<num>:<kv>:<rv>:<gv>:<bv> - specify visual information
+ <num> is the color index (0-255, only 0-15 used)
+ <kv> black (?) value -- unused
+ <rv> red value (0-255)
+ <gv> green value (0-255)
+ <bv> blue value (0-255)
+W:<win>:<flag>:<value> - turn a window flag on/off.
+ <win> window number (1-7)
+ <flag> (0-31)
+ <value> 0 = off, 1 = on
+
+X:<str> - turn option off
+Y:<str> - turn option on
+ <str> the name of an option in option_text[].
+ These are the names displayed in the options screen (=).
+
+?: - conditional expression
+%: - include another pref file
+
+#####G----------------------------------------------------------------------
+#####G9.4 Option lines "X:" and "Y:"
+#####G----------------------------------------------------------------------
+
+Options and their descriptions are listed in help file *****option.txt*0["option.txt"].
+These options are set within the game using the (=) Options command,
+and the option names are the ones displayed within parentheses in the
+options screen.
+
+#####B= Common options =
+rogue_like_commands
+use_old_target
+always_pickup
+depth_in_feet
+alert_hitpoint
+auto_haggle
+auto_scum
+
+#####G----------------------------------------------------------------------
+#####G9.5 Conditional expression lines "?:"
+#####G----------------------------------------------------------------------
+
+expressions are lisp-like prefix notation.
+names (class, race, ...) aren't placed in quotes.
+AND - logical AND
+IOR - inclusive OR
+EQU - (string) equals
+NOT - logical negation
+LEQ - (string) less than or equal to
+GEQ - (string) greater than or equal to
+[,] - group expressions
+$CLASS - current class
+$GRAF - 3-letter graphics abbr in "graf-***.prf" (old, new)
+$PLAYER - current player name
+$RACE - current race
+$SYS - 3-letter system abbr in "pref-***.prf" (ami, mac, win,...)
+
+0 - false
+1 - true (can't just be non-zero)
+
+If the conditional expression is false all pref file commands
+encountered until the next conditional pref line are skipped.
+
+This isn't an actual command. It only works in pref files.
+
+The variables $CLASS, $GRAF, $PLAYER, $RACE, $PLAYER, $SYS and the
+string values they take on are case sensitive. The values also can't
+contain spaces. These constraints on the values hold when they are
+used in a pref file, but might not when used as pref filenames.
+
+This can be "turned back on" using the pref line "?:1", which is
+generally the last line in a file which contains conditional macros,
+to make sure that any files loaded after it don't get ignored as well.
+
+#####G----------------------------------------------------------------------
+#####G9.6 Macro trigger lines "P:"
+#####G----------------------------------------------------------------------
+
+All "special" keys are translated by "main-***.c" into encoded "macro
+triggers". These macro triggers have the encoded form "^_MMMxSS\r",
+where the "modifier" flags are stored in "MMM", and the two digit
+hexadecimal scan code of the keypress is stored in "SS". See source
+file "main-ibm.c" and others for more info. Note that because these
+scan codes are system-dependent, macro trigger encodings are as well.
+Keymaps are used for system independent mapping of triggers to actions.
+
+#####BModifier flags
+
+A - Alt
+C - Control
+S - Shift
+O - Option key (Mac)
+
+#####BIBM Scan codes
+
+x47 - keypad 7
+x48 - keypad 8
+x49 - keypad 9
+x4A - keypad -
+x4B - keypad 4
+x4C - keypad 5
+x4D - keypad 6
+x4E - keypad +
+x4F - keypad 1
+x50 - keypad 2
+x51 - keypad 3
+x52 - keypad Ins / .
+x53 - keypad Del / Enter
+x45 - Pause
+
+Others can be found using the "Query a macro" feature.
+
+Note that scan codes can't be assumed to be "in order", even for keys
+like function keys which "logically" should be!
+
+Note that you can't always just add a modifier to a known scan code
+because that combination might not be recognised by the hardware or
+the translation code in "main-***.c".
+
+Example: a Windows system will recognise function key F1, Shift-F1,
+and Ctrl-F1, but not Ctrl-Shift-F1. Similarly Pause and Alt-Pause are
+recognised, but not Ctrl-Pause, and Shift-Pause gives the same
+encoding as Pause alone.
+
+#####G----------------------------------------------------------------------
+#####G9.7 Saving to a pref file
+#####G----------------------------------------------------------------------
+
+Commands "Append macros to file" and "Append keymaps to file" don't
+erase the previous macros or keymaps. Instead they are appended. Note
+that this can produce *large* files after a while. Newer versions
+append to "<$PLAYER>.prf" by default, whereas older versions appended
+to "user.prf". The appended sections are preceded by headers of the
+form "Automatic macro/keymap dump". Using a distinctive comment line
+such as ###... after your entries can make editing the appended ones
+easier.
+
+[[[[[BNote: macros and keymaps aren't saved in the character file, so they]
+[[[[[Bmust be saved separately. All macros and keymaps entered by the user]
+[[[[[Bare lost when Angband terminates.]
+
+Note: keeping macros in the <$PLAYER>.prf files allows several users
+to share the same installation without interfering with each other.
+You can easily reuse or share preferences by moving them into a pref
+file "<my-name>.prf" and using the pref line "%:<my-name>.prf" to
+include them in "user.prf" for single user installations, or
+<$PLAYER>.prf for multi-user installations.
+
+#####G----------------------------------------------------------------------
+#####G9.8 Editing pref files
+#####G----------------------------------------------------------------------
+
+This is still most easily done in a text editor.
+
+~~~~~39
+#####R======================================================================
+#####R10. Macro editing commands
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G10.1 (") Enter a User Pref Command
+#####G----------------------------------------------------------------------
+
+This allows entering a single pref line.
+Example: "X:auto_scum" turns auto-scum off.
+
+Example "A:<str>" sets the current action string. If you open the
+"Interact with macros" screen this action will be the default used.
+Then using the (") command again with "P:<key>" will create a macro
+for the action <str> previously entered.
+
+Not all pref commands can be used here, or are meaningful.
+The "pseudo" pref commands (?), (%) cannot be used here.
+
+See section *****macrofaq.txt*20["Advanced macro techniques"] for ways to [ab]use this.
+
+#####G----------------------------------------------------------------------
+#####G10.2 (@) Interact with macros
+#####G----------------------------------------------------------------------
+
+#####B= Vanilla command set = (2.8.3 - 2.9.1)
+#####B-----------------------------------
+Load a user pref file
+Append macros to a file
+Query a macro action
+Create a macro
+Remove a macro
+Append keymaps to a file
+Query a keymap
+Create a keymap
+Remove a keymap
+Enter a new action
+
+#####B= Load a user pref file =
+#####B-----------------------------------
+Loads a user pref file from "lib\user". Defaults to the name of the
+current character. Macros/keymaps loaded will replace existing ones.
+
+#####B= Append macros to a file =
+#####B-----------------------------------
+Macros are dumped in macro list order. Newer ones are at the end.
+Macros are *appended* to the file. The old one isn't overwritten. This
+prevents you from accidentally wiping out your old pref file. However,
+the file can grow very long without your noticing it. Placing a line
+of ###'s at the end of your macros can help sort out what is what.
+Macros are labeled with comment "# Macro 'NNN' ". These numbers are the
+internal macro list numbers, and have no relation to key scan codes.
+The filename must end in ".prf". It will save correctly without this
+extension, or with a different one, but if you save as "<$NAME>"
+instead of "<$NAME>.prf", it won't be automatically loaded when you
+load the character with that name.
+
+#####B= Query a macro =
+#####B-----------------------------------
+Press the trigger key to test at the prompt.
+This will show "Found a macro" on the message line if it found one,
+and the line "Trigger: <trigger>". This will show "Found no macro"
+on the message line if it didn't find a macro. Some keys such as
+function keys won't be recognised by the prompt. It will wait until
+you hit a key it recognises.
+
+This command doesn't alter any settings. It will return to the main
+menu after you hit any key it recognises.
+
+#####B= Create a macro =
+#####B-----------------------------------
+After choosing this command, press the trigger key for the macro.
+The internal form will be shown after the "Trigger: " prompt.
+Note that some keys may not be recognised for remapping, such as the
+new Windows keys, as well as modifier keys such as Alt, Control, Shift
+pressed by themselves. In this case it will continue to wait for a
+valid trigger key.
+
+The current action (if any) will be shown *below* the "Trigger: "
+prompt line. On the prompt line ("Action: ") will be shown the last
+macro sequence entered. This is the action in the "action buffer".
+This isn't necessarily the macro sequence currently bound to this key.
+This is the action that will be bound to the current trigger key if
+you hit Enter.
+
+You may type in an action string to replace the one after the prompt.
+Hit Enter when you are finished.
+
+For ToME you can quit the command assignment by hitting
+Esc. The new action entered won't be assigned, and the previous one
+will remain unaltered.
+
+#####B= Remove a macro =
+#####B-----------------------------------
+Removes the macro from the trigger key by creating an identity macro
+on that key for itself. So the macro isn't completely removed, just
+overwritten. The new identity macro will be saved when the macros are
+appended to a file. This is different from the "Remove a keymap"
+command, which completely removes the keymap.
+
+#####B----------------------------------------------------------------------
+The following "keymap" commands only apply to the current "mode"
+(original/roguelike). Keymaps for the other mode will be unaffected.
+Because keymaps can only be bound to trigger keys which have a system
+independent representation, some key presses won't be recognised by
+these editing commands. They will instead wait until you press a valid
+trigger key.
+#####B----------------------------------------------------------------------
+
+#####B= Append keymaps to a file =
+#####B-----------------------------------
+Works just like "Append macros to a file". These are appended after a
+header comment "# Automatic keymap dump".
+
+#####B= Query a keymap =
+#####B-----------------------------------
+Works just like "Query a macro". This will show "Found a keymap" on
+the message line if it found one, and will display "Keypress: <map>".
+This will show "Found no keymap" on the message line if it didn't
+find a keymap. This command doesn't alter any settings. It will return
+to the main menu after you hit any key it recognises.
+
+#####B= Create a keymap =
+#####B-----------------------------------
+Works just like the "Create a macro" command. Keymaps can only be
+assigned to keys which have a system independent representation. Note
+that creating a keymap will cause the behavior of any macro whose
+action string contains that key to change.
+
+#####B= Remove a keymap =
+#####B-----------------------------------
+Removes the keymap completely from the trigger key. If the key had a
+built-in command it can now be used again. Note that removing a keymap
+will cause the behavior of any macro whose action string contained
+that key to change. This behaves differently from the "Remove a macro"
+command, which creates an identity macro.
+
+If the original "command" was itself a keymap, removing a user-entered
+keymap won't restore it. Example: the key (n) is bound to the built-in
+command "Repeat last action" in file "pref.prf" via a keymap. If you
+add a keymap for (n) and then remove it, the "Repeat last command"
+functionality won't be restored. You will have to add it back by hand,
+or reload a pref file that contains that stored keymap. [[[[[BIn particular]
+[[[[[Balmost all roguelike commands are now implemented as keymaps.]
+
+#####B= Enter a new action =
+#####B-----------------------------------
+Allows entering a new action. Actions are entered into a static buffer
+which is shared by both macros and keymaps. The action string entered
+will become the default action for creating a keymap or action, and
+will only change when a keymap or macro is created with a different
+action string, or when one is queried. Note that the same action can
+be bound to multiple trigger keys by hitting Enter when using the
+commands to create a keymap/macro.
+
+~~~~~20
+#####R======================================================================
+#####R11. Advanced Macro Techniques
+#####R======================================================================
+
+This section outlines advanced techniques not really required for game
+play. But macros become addictive after a while ...
+
+Action strings in this section are enclosed in braces {} because many
+use a double quote (") inside the action string. These are not
+inscriptions.
+
+#####G----------------------------------------------------------------------
+#####G11.1 Set current action using (@) command in an action
+#####G----------------------------------------------------------------------
+
+{"@0<str>\r\e}
+@ - Interact with macros
+0 - Enter a new action
+<str>- (action string)
+\r - Enter the action
+\e - Exit the macro editor
+
+This will work when bound to a macro.
+
+#####G----------------------------------------------------------------------
+#####G11.2 Set current action using (") command in an action
+#####G----------------------------------------------------------------------
+
+{"A:<action>\r} - sets the current action.
+" - Enter pref line
+A: - Action line
+<str>- (action string)
+\r - Enter the action
+
+This works in either a macro or keymap.
+
+#####G----------------------------------------------------------------------
+#####G11.3 Create a new keymap using (") command in an action
+#####G----------------------------------------------------------------------
+
+{"A:<act>\r"C:0:<key>\r}
+Here <act> can't contain an '\r' or '\e'.
+
+Example {"A:z0\r"C:0:J\r} binds action "z0" to (standard) keymap 'J'.
+
+#####G----------------------------------------------------------------------
+#####G11.4 Create a new macro using (") command in an action
+#####G----------------------------------------------------------------------
+
+{"A:<act>\r"P:<key>\r}
+Here <act> can't contain an '\r' or '\e'.
+Here <key> is a standard key. (not a "special" one like F1, \b, or ^A)
+
+Example
+{"A:<action1>\r"P:j\r} binds action <action1> to trigger 'j'.
+{"A:<action2>\r"P:j\r} binds action <action2> to trigger 'j'.
+If we bind these 2 macros to different trigger keys, the action that
+is on key (j) can be swapped back and forth.
+
+#####G----------------------------------------------------------------------
+#####G11.5 Turning an option on/off in an action
+#####G----------------------------------------------------------------------
+
+Turn an option on:
+{"Y:<option_name>\r}
+
+Turn an option of:
+{"Y:<option_name>\r}
+
+Example: Turn (quick_messages) on, do an action, and turn it back off:
+{"Y:quick_messages\r<action>"X:quick_messages\r}
+
+This will work in either a macro or keymap. <option_name> is the name
+of the option as it appears in the option editor accessed through the
+(=) command. These are also listed in the help file *****option.txt*0["option.txt"]. Note
+that option names contain underscores instead of spaces.
+
+#####G----------------------------------------------------------------------
+#####G11.6 Inscribe/Uninscribe an item in an action
+#####G----------------------------------------------------------------------
+
+(These action strings are enclosed in double quotes)
+
+Inscribe an item:
+"{<item>\s<inscr>\r"
+
+Uninscribe an item:
+"}<item>\r"
+
+<item> must be the inventory letter of the item, possibly preceded by
+a '/' to switch to the equipment list. You can't use digit labels for
+items with inscriptions that contain the command triggers '{' or '}',
+but you can use "@<digit>".
+
+This will work in either a macro or keymap.
+
+~~~~~41
+#####R======================================================================
+#####R12. Problems
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G12.1 Keys to avoid remapping
+#####G----------------------------------------------------------------------
+
+These don't really *need* to be avoided, but all carry dangers of one
+kind or another. You should think through potential problems before
+deciding to use them. You have been warned.
+
+#####B= Navigation keys =
+Enter, Esc, Backspace, ...
+These aren't a good choice unless you *really* need them. If you do it
+is far better to use keymaps. If you bind a macro to the Enter key,
+you will lose the ability to enter line-based commands like Inscribe.
+
+#####B= Commands generated internally =
+(_) Enter store
+This command is generated internally by the game when the player moves
+onto the door of a store. In some versions, if this key has a keymap
+bound to it, that will fire when you try to enter a store.
+
+#####B= Keys with important Operating System meanings =
+^Z (un*x) Suspends the game and returns to the command shell. This
+ is an operating system command, not an Angband command.
+ Command "fg" returns to Angband.
+^\, ^D, ^S
+ These are keys that shouldn't be bound to macros or have their
+ behavior altered.
+
+#####B= Keys with dangerous ToME meanings =
+(Q) Quit (commit suicide), (k) destroy item, (^A) Enter Debug mode...
+Using these as triggers is dangerous in case, for some reason, you
+wind up in a situation where the macro hasn't loaded or is disabled.
+You also don't want to get into a habit of typing these too fast.
+
+#####B= Selection keys =
+(e) Equipment, (i) Inventory, (-) Floor item, (/) Switch inventory
+lists. You should avoid binding these as macro triggers, to prevent
+making inventory and choice management next to impossible. But even as
+keymaps they hold some dangers.
+Example: you bind keymap on '-' to destroy item on the floor. Now if
+you try to do an action on a floor item, and it fails (such as using
+rod to identify), then the '-' can be taken from the input stream and
+used as a keymap, which would destroy the item you tried to identify.
+
+#####B= Response keys =
+(y) yes, (n) no, (Esc) cancel, (Space) skip message,...
+Binding macros to these is a [[[[[vVery Bad Idea.] Macro expansion will then
+be done when you answer a question like "Are you sure you want to quit
+the game without saving?". The expanded macro action string will be
+used as the input, and may not lead to the answer you were trying for.
+Keymaps don't have this problem. As a rule you should never use a
+macro instead of a keymap unless necessary.
+
+#####G----------------------------------------------------------------------
+#####G12.2 Num lock
+#####G----------------------------------------------------------------------
+
+Whether/not NumLock is on can make a difference for some macros.
+For example, if NumLock is on under X11 the 'X' macro won't work.
+
+#####G----------------------------------------------------------------------
+#####G12.3 Recovering
+#####G----------------------------------------------------------------------
+
+Restarting ToME clears all macros entered during the last session.
+
+You can use "Load a pref file" in the "Interact with macros" screen to
+reload a good set of prefs, overwriting bad ones being used. This will
+not "erase" a macro/keymap which doesn't have a corresponding saved
+one in the pref file. So if you add a macro/keymap to a trigger key
+which didn't have anything bound to it, reloading the pref file won't
+restore the key to its original state.
+
+If you still have problems, restore or edit any modified *.prf files
+that might be loaded.
+
+Try saving your macros, and examine them to see what went wrong.
+
+[[[[[BYou can use the backspace '\' key at the command prompt to use the]
+[[[[[Boriginal "underlying" command bound to that key. For example, if you]
+[[[[[Bbound the key '@' to a macro, you wouldn't be able to enter the macro]
+[[[[[Beditor to rebind it to itself.] Pressing '\' first, then '@' causes the
+command handler to use the built-in command, which allows you to enter
+the command editor. Note: when you use the backspace inside an action
+string, you have to double it as "\\". Do not use just a single back-
+slash, or it will be ignored, and possibly alter the meaning of the
+character that follows it.
+
+You can remove a macro/keymap from an essential key (such as the Esc
+key). Use the (@) "Interact with macros" command to access the remove
+commands.
+
+#####G----------------------------------------------------------------------
+#####G12.4 Unrecognised keys
+#####G----------------------------------------------------------------------
+
+#####B= Un*x =
+
+Function keys may not be recognised on some Un*x systems.
+
+#####B= PC/Dos/Windows =
+Doesn't recognise the WINDOWS key (start menu) or the APPLICATION key
+(context menu).
+
+On some systems, doesn't recognise modifier keys (Alt, Ctrl, Shift) on
+keypad keys when NumLock is on.
+
+See special_key_list[] in "main-win.c" for list of "special" keys that
+are recognised.
+
+#####G----------------------------------------------------------------------
+#####G12.5 Nonexistent commands
+#####G----------------------------------------------------------------------
+
+Macros and keymaps can only be bound to keypresses. The game state
+changing isn't a keypress, so you can't trigger an action when you
+become hungry, blind, confused, slowed, pseudo-id an item, pick up an
+item, gain a level, have a rod recharge, or any other event that isn't
+directly triggered by a keypress.
+
+"Attacking" also isn't a command, but you can use commands (+) Alter
+grid, (;) Walk, and (.) Run.
+
+So you don't really _attack_ Morgoth, you just _alter_ him. First he's
+alive, then he's not. :)
+
+#####G----------------------------------------------------------------------
+#####G12.6 File permissions
+#####G----------------------------------------------------------------------
+
+If you lack write permission to the pref file currently loaded by the
+game, try saving to a file with a new name. The macros can be copied
+over "by hand" later.
+
+~~~~~42
+#####R======================================================================
+#####R13. Miscellaneous
+#####R======================================================================
+
+#####G----------------------------------------------------------------------
+#####G13.1 References
+#####G----------------------------------------------------------------------
+
+*****command.txt*0["COMMAND.TXT"]
+- lists standard and roguelike keys and commands. full descriptions.
+- long description of command behavior.
+- intro to macros and user pref files.
+
+*****dungeon.txt*8["DUNGEON.TXT"]
+- look under "Objects Found in the Dungeon".
+
+*****option.txt*0["OPTION.TXT"]
+- list of options and their descriptions.
+
+"INSCRIPTIONS.HTML"
+- short intro by Julian Lighton. Available from
+"http://www.fragment.com/~jl8e/angband/inscriptions.html".
+
+#####G----------------------------------------------------------------------
+#####G13.2 Contributors
+#####G----------------------------------------------------------------------
+
+This FAQ was largely compiled from newsgroup postings to "r.g.r.a".
+So thanks to the generous contributors to the newsgroup! Email
+addresses have been removed to foil spam-bots.
+
+Ben Harrison -- maintainer: Angband 2.7.1 - 2.8.5, =Ben= in source.
+Robert Ruehlman -- maintainer: Angband 2.9.0 - present.
+DarkGod -- maintainer: PernAngband 2.9.9a - present
+
+Scott Bigham, DamonShawX, Jonathan Ellis, George W. Harris, Roger
+Hoyle, Graham S. Johnson, Chris Kern, Matthias Kurzke, Steve Lamb,
+Julian Lighton, Art Mruczek, Daniel Nash, Timo Pietilä, Jack Wise,
+Greg Wooledge, and others.
+
+#####G----------------------------------------------------------------------
+#####G13.3 Legalese
+#####G----------------------------------------------------------------------
+
+Copyright 2000 Jim Lyon and others. Redistribution of unaltered copies
+of this document is permitted without restriction. Distribution of
+altered copies is permitted without restriction as long as the
+alteration does not significantly alter the content. (For example,
+translation and conversion to another format is permitted.)
+Distribution of all other altered copies is permitted as long as credit
+for previous authors is maintained, the contact information is
+replaced with that of the alterer, and redistribution is not further
+restricted.
+
+Edited for PernAngband V5.x.x by Dawnmist with permission from Jim Lyon
+August 2001. All comments to angband@dawnmist.8m.com
diff --git a/lib/mods/theme/help/magic.hlp b/lib/mods/theme/help/magic.hlp
new file mode 100644
index 00000000..382451c3
--- /dev/null
+++ b/lib/mods/theme/help/magic.hlp
@@ -0,0 +1,41 @@
+|||||oy
+~~~~~01|Magic|Index
+~~~~~02|Help|Magic
+#####RWelcome to the ToME Magic Help System.
+#####R=============================================
+
+Please choose one of the following help files:
+
+General Info
+
+ *****/amagic.txt*0[(a) The ToME magic system]
+ *****/bmagic.txt*02[(b) Wands and Staves]
+
+Magic schools
+
+ *****/cm_air.txt*0[(c) The Air School]
+ *****/dm_convey.txt*0[(d) The Conveyance School]
+ *****/em_demono.txt*0[(e) The Demonology School]
+ *****/fm_divin.txt*0[(f) The Divination School]
+ *****/gm_earth.txt*0[(g) The Earth School]
+ *****/hm_fire.txt*0[(h) The Fire School]
+ *****/im_geoman.txt*0[(i) The Geomancy School]
+ *****/jm_mana.txt*0[(j) The Mana School]
+ *****/km_meta.txt*0[(k) The Meta School]
+ *****/lm_mind.txt*0[(l) The Mind School]
+ *****/mm_nature.txt*0[(m) The Nature School]
+ *****/nm_necrom.txt*0[(n) The Necromancy School]
+ *****/om_tempo.txt*0[(o) The Temporal School]
+ *****/pm_udun.txt*0[(p) The Udun School]
+ *****/qm_water.txt*0[(q) The Water School]
+
+Other powers accessed by the 'm' menu
+
+ *****/rm_mimic.txt*0[(r) Mimicry Powers]
+ *****/sm_mindcr.txt*0[(s) Mindcrafting Powers]
+ *****/tm_music.txt*0[(t) Musical Songs]
+ *****/um_symbio.txt*0[(u) Symbiotic Powers]
+ *****/vm_thaum.txt*0[(v) Thaumaturgical Spells]
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
+ \ No newline at end of file
diff --git a/lib/mods/theme/help/magic.txt b/lib/mods/theme/help/magic.txt
new file mode 100644
index 00000000..93486f0b
--- /dev/null
+++ b/lib/mods/theme/help/magic.txt
@@ -0,0 +1,143 @@
+|||||oy
+~~~~~03|Magic
+#####R === ToME Magic system ===
+
+*****magic.txt*02[Wands and Staves]
+
+For the basics of how to use skills, please see *****skills.txt*0[Using Skills].
+
+In ToME you have a basic *****skills.txt*21[Magic] skill. This skill is one of the most
+important ones for a spellcaster, since it is responsible for how much mana you
+have. You can never have too much of it. If you like magical devices, the
+Magical Device skill is also important, since it controls the Magical
+Device ability of your character. This ability again dictates the fail rates
+of use of wands/rods/staffs and activation of random-artifacts/artifacts, and
+it will also increase the power of these items.
+~~~~~01|Magic|Schools
+ToME uses skills to define the various schools of magic. There are 11 primary
+schools:
+ *****m_mana.txt*0[Mana] *****m_fire.txt*0[Fire] *****m_water.txt*0[Water]
+ *****m_air.txt*0[Air] *****m_earth.txt*0[Earth] *****m_meta.txt*0[Meta]
+ *****m_convey.txt*0[Conveyance] *****m_divin.txt*0[Divination] *****m_tempo.txt*0[Temporal]
+ *****m_mind.txt*0[Mind] *****m_nature.txt*0[Nature]
+
+Other magical skills, generally being used primarily by characters of a
+specific class, are:
+ *****m_demono.txt*0[Demonology] *****m_necrom.txt*0[Necromancy] *****skills.txt*36[Runecraft]
+ *****m_thaum.txt*0[Thaumaturgy] *****skills.txt*49[Alchemy] *****m_geoman.txt*0[Geomancy]
+
+The *****m_demono.txt*0[Demonology] skill is primarily used by *****c_demono.txt*0[Demonologists] for their special
+spells, whereas the *****m_necrom.txt*0[Necromancy] skill is used by *****c_necro.txt*0[Necromancers] for their own set
+of special spells.
+The same goes for *****skills.txt*36[Runecraft], which is used by *****c_runecr.txt*0[Runecrafters] to allow use of more
+difficult runes or rune-combinations. *****m_thaum.txt*0[Thaumaturgy] gives you randomly chosen
+attack spells, and as such each game with it will be different. *****c_geoman.txt*0[Geomancers]
+harness the powers of the elements using *****m_geoman.txt*0[Geomancy]. Lastly we have
+*****skills.txt*49[Alchemy], which is used by *****c_alchem.txt*0[Alchemists].
+
+In addition to the schools of magic, you can get access to special sets of
+spells if you worship a God. There are currently four good Gods,
+*****g_eru.txt*0[Eru Iluvatar], *****g_manwe.txt*0[Manwe Sulimo], *****g_yavann.txt*0[Yavanna Kementari] and *****g_tulkas.txt*0[Tulkas]. There is also an evil
+god, *****g_melkor.txt*0[Melkor]. Each of them gives you access to different types of spells.
+
+*****c_pr_drk.txt*0[Worshippers of Melkor] also have access to the special *****m_udun.txt*0[Udun] school of magic,
+whereas other *****c_priest.txt*0[Priests] and *****c_mindcr.txt*0[Mindcrafters] can use *****m_mindcr.txt*0[Mindcrafting Powers].
+
+*****c_symbia.txt*0[Symbiants] have access to their own special brand of *****m_symbio.txt*0[magic powers], and *****c_bard.txt*0[Bards] have
+access to *****m_music.txt*0[Songs], which affect creatures in ways that can appear to be magical.
+
+The 11 different primary schools give you access to different spells of
+variable usefulness. The way they work is that adding skill points to a
+specific school will enable you to get higher level spells for that specific
+school. By level requirements for a specific spell you could actually say skill
+requirement, since they correlate exactly. Let's take a simple example:
+If you have the *****m_mana.txt*0[Mana] school skill at level 24.000, it means you can use any
+spell in the mana school up to and including those requiring level 24. [[[[[BThere are]
+[[[[[Balso some spells requiring a certain skill level in two schools, and there is a]
+[[[[[Bpossibility of spells requiring three or more. For this kind of spells the ]
+[[[[[Bspell level is determined by taking an average of the necessary skills. ]
+When calculating spell level for spells which require more than one school,
+sorcery (or god-granted access) can be used in place of the primary schools in
+the normal way. Once the average has been calculated, any bonus from the
+spell-power skill can also be applied as normal. If one of the schools required
+is the Udun school, then the appropriate bonus from character level will be
+applied. Lastly, if you look at a spell, and the spell level reads -2 or some
+other negative value while it's also grayed out, that means you need to
+increase the corresponding school's skill level by 3, since only 2 will have
+it end up on spell level 0, where it still is unusable. If it reads n/a, you
+currently have no skill points in that school.
+
+Another thing that should be explained about the skills and schools of magic
+right now, is that the skill doesn't stop being useful only for gaining spells.
+The higher the skill level, the higher the spell level will be, and the more
+powerful your spells will be. For instance, say you have the *****m_mana.txt*0[Mana] skill at
+level 24. Now, the Manathrust spell is one of the spells for that school
+that only requires skill level 1, but since you've got skill at level 24, the
+power of the spell is increased as well. For comparison, a level 1
+Manathrust costs 1 mana and does 4d2 damage, while at level 24 it costs 12
+mana and does a whopping 27d10 damage.
+
+The *****skills.txt*23[Sorcery] skill is a nice skill, since it gives you
+access to all the 11 primary schools of magic, just as if you'd spent an equal
+amount of skill points in all the skills. It's available to any mage character,
+but only a *****c_sorcer.txt*0[Sorceror] will be able to be proficient in it. Also, having this
+skill at level 1 will give you a hitpoint-penalty of 1%, all the way up to
+skill level 50, with a hitpoint-penalty of 50%. There are also ToHit and ToDam
+penalties for sorcery, so don't choose sorcery if you plan to do much fighting.
+
+There is also the *****skills.txt*22[Spell Power] skill. This skill is rather nice, since it
+will augment the power of spells you already know. The distinction between this
+and the others, is that it will not grant you new spells, but instead increases
+the levels of spells. At level 50 it grants 20 extra spell levels. [[[[[BThis skill ]
+[[[[[Bonly affects the 11 primary schools] (Mana, Earth, Air, Fire, Water, Meta,
+Mind, Temporal, Conveyance, Divination and Nature) as well as Geomancy and the
+spells granted by the Gods.
+
+There is also the Magic-Device skill which affects your ability to use wands,
+staves, rods and to activate special objects. It also affects the spell-levels
+of the staff and wand spells, as explained below.
+~~~~~02|Wands
+~~~~~04|Magic|Wands and Staves
+~~~~~05|Staves
+#####GWands and Staves
+
+Wands and staves (sticks) operate in a similar fashion, and in fact most of
+them use the same spells with the same effects. When you pick up a stick, you'll
+see it has two numbers in the format [x|y] in addition to the number of charges
+it holds. By increasing your magic-device skill you can increase the level (and
+hence the power) of the spell in that stick. The x value are skill level
+bonuses which the staff itself holds, and these are added onto your existing
+magic-device skill for the purpose of using the staff. The y value is the
+maximum possible skill level for that stick. Things are balanced by the use of a
+"minimum magic-device skill level required to raise spell level". Here's an
+example:
+A Staff of Sense Hidden [1|10]. Your magic device skill is at 6. If you were to
+identify the staff and then 'I'nspect it, you would see the following
+information:
+
+&&&&&w wSwpwewlwlw wdwewswcwrwiwbwtwiwownw:w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wDwewtwewcwtwsw wtwhwew wtwrwawpwsw wiwnw waw wcwewrwtwawiwnw wrwawdwiwuwsw wawrwowuwnwdw wywowuw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wAwtw wlwewvwewlw w1w5w wiwtw wawlwlwowwwsw wywowuw wtwow wswewnwswew wiwnwvwiwswiwbwlwew wfwowrw waw wwwhwiwlwew w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wSwpwewlwlw wlwewvwewlw:w B3w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wMwiwnwiwmwuwnw wMwawgwiwcw wDwewvwiwcwew wlwewvwewlw wtwow wiwnwcwrwewawswew wswpwewlwlw wlwewvwewlw:w B5w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wSwpwewlwlw wfwawiwlw:w g2g3w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&w wSwpwewlwlw wiwnwfwow:w yryaydy y1y3w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+
+The Spell level is the level at which the spell will actually be cast.
+Spell fail is the spell fail percentage. The spell info may contain the radius
+of effect, amount of damage, or duration the spell might last.
+The Minimum Magic Device level to increase your spell level is just that. If
+your magic device skill was less than this level, then the staff would be
+casting the spell at level one. Our magic device skill is 6. Therefore we are
+casting at level 2 (at skill level 5, we should be casting the spell at level
+1). Then we add the bonus from the staff of 1, which gives us our spell level
+of 3. If our magic device in this example had been 14, this would have given us
+a spell level of 1 + (14 - 5 + 1) = 11. This is calculated from the formula:
+spell level = staff bonus + (magic device - minimum magic device + 1)).
+However given that the maximum spell level with this staff is 10, you'll be
+casting with a spell level of 10.
+As you get deeper into the dungeons, you will find sticks with higher bonuses
+and maximum spell levels.
+
+ Written by: vrak AKA Per-Arne Holtmon Akoe
+ Wands and Staves section added by fearoffours
diff --git a/lib/mods/theme/help/newbie.hlp b/lib/mods/theme/help/newbie.hlp
new file mode 100644
index 00000000..2dda8dbc
--- /dev/null
+++ b/lib/mods/theme/help/newbie.hlp
@@ -0,0 +1,16 @@
+|||||oy
+~~~~~01|Help|New players
+#####RWelcome to the ToME New Players Help System.
+#####R=============================================
+
+Please choose one of the following help files:
+
+ *****/awhattome.txt*0[(a) What is ToME?]
+ *****/bbirth.txt*0[(b) Creating a character] Race, class, gods, stats + more
+ *****/cexplore.hlp*0[(c) Exploring the town and dungeon] Dungeons, commands, features
+ *****/dexperien.hlp*0[(d) Gaining experience] Skills and abilities
+ *****/emagic.hlp*0[(e) Using magic and magical items] Magic schools, the 'm' menu, wands etc
+ *****/fTANG.txt*0[(f) The ToME newbie guide]
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
+
diff --git a/lib/mods/theme/help/option.txt b/lib/mods/theme/help/option.txt
new file mode 100644
index 00000000..34a2fe6b
--- /dev/null
+++ b/lib/mods/theme/help/option.txt
@@ -0,0 +1,697 @@
+|||||oy
+~~~~~05|Options
+#####R=== Options and Effects (ToME 2.1.x) ===
+
+Most of the options are accessible through the '=' command, which provides
+an interface to the various sets of options available to the player.
+
+In the descriptions below, each option is listed as the textual summary
+which is shown on the options screen, plus the internal name of the
+option in brackets, followed by a textual description of the option.
+
+Note that the internal name of the option can be used in user pref files
+to force the option to a given setting; see *****command.txt*105["command.txt"] for more info.
+
+Various concepts are mentioned in the descriptions below, including "disturb"
+(cancel any running, resting, or repeated commands, which are in progress),
+"flush" (forget any keypresses waiting in the keypress queue, including any
+macros in progress), and "fresh" (dump any pending output to the screen).
+
+~~~~~06|Options|Startup
+#####R=== Birth/Startup Options ===
+
+The birth or startup options are only able to be changed during character
+creation, and can be accessed by typing '=' during the creation process. They
+can also be viewed from the option menu while playing, but not changed then.
+
+#####GMaximise stats [maximize]
+ Maximise causes the race and class stat bonuses to be applied like
+ equipment bonuses. This usually makes the character harder at the
+ beginning of the game, but easier later on, since the stats are no longer
+ limited to a "natural" value of 28 (18/100).
+
+#####GPreserve artifacts [preserve]
+ Preserve artifacts cancels all level feelings of the "special" variety,
+ but allows missed artifacts to be "saved" by wandering monsters and
+ found again at a later time. This only works for non-identified artifacts.
+
+#####GSpecify 'minimal' stats [autoroll]
+ Uses the standard autoroller for character creation. This allows the player
+ to specify a set of minimum values for the stats, and the game will keep
+ rerolling until it achieves them (or 1 million rolls, whichever comes
+ first). Be warned, however, that there is a maximum total power permitted
+ for a starting character. Setting one stat to near maximum is easily
+ achievable; 2 is reasonable; but 3 would require the remaining 3 stats to
+ be near their minimum values.
+
+#####GGenerate character using a point system [point_based]
+ Allows the player to distribute a certain number of points among her stats.
+ It results in the player being able to get one or two really high stats, at
+ the expense of other not-so-important stats; or to have a well-rounded
+ character who is above average (but not great) in all stats. Unused points
+ convert into starting gold for the player.
+
+#####GAlways generate very unusual rooms [ironman_rooms]
+ Tries to place a special room or vault on every dungeon level. Very fun,
+ but extremely deadly - imagine that Greater Checkerboard Vault with Lokkak
+ on dungeon level 1!
+
+#####GAllow notes to be written to a file [take_notes]
+ Allows any player-written notes (with the "|" command) to be written to
+ a file and kept (instead of being put in the message list).
+
+#####GAutomatically note important events [auto_notes]
+ Used in conjunction with the take_notes option, this option makes a note
+ each time you gain a level, kill a unique, find an artifact, etc.
+
+#####GFast autoroller (NOT on multiuser systems) [fast_autoroller]
+ The normal autoroller has a built-in delay that helps prevent it from
+ overloading a system. This option reduces that delay, allowing characters
+ to be rolled in a much shorter time, but should not be used on multiuser
+ systems.
+
+#####GAllow use of some 'joke' monsters [joke_monsters]
+ Allows monsters flagged as being some of DarkGod's jokes to be generated.
+
+#####GAlways make small levels [always_small_level]
+ Overrides the in-game option of small_levels, generating smaller levels
+ whenever possible.
+
+#####GYou can receive fates, good or bad [fate_option]
+ Allows the player to turn off ToME's *****fatespoi.txt*0[fates] for that character.
+
+~~~~~07|Options|Ingame
+#####RIN GAME OPTIONS
+#####R===============
+
+These options are available from within the game, and can be toggled on and
+off at will during the course of the game.
+
+~~~~~08|Options|Interface
+#####R=== Option Set 1 -- User Interface ===
+
+#####GRogue-like commands [rogue_like_commands]
+ Selects the "roguelike" command set (see *****command.txt*0["command.txt"] for info).
+~~~~~1
+#####GActivate quick messages [quick_messages]
+ Allows the use of any keypress as a response to the "-more-" prompt
+ (useful for monster farming). Allows most keys to mean "no" to any
+ "[y/n]" prompt.
+
+#####GPrompt for various information [other_query_flag]
+ No longer used.
+
+#####GPrompt before picking things up [carry_query_flag]
+ Forces the game to ask you for confirmation when you do something that
+ would normally cause an item to be picked up.
+~~~~~4
+#####GUse old target by default [use_old_target]
+ Forces all commands which normally ask for a direction to use the
+ current target if there is one. If the current target is a monster, it
+ becomes unset when that monster dies. Use of this option can be dangerous
+ if you target locations on the ground, unless you clear them when done.
+
+#####GPick things up by default [always_pickup]
+ Tells the game that walking onto an item should attempt to pick it up.
+ Otherwise, you must use the "g" command, or the "-" command while walking.
+ Combined with "carry_query_flag" (Prompt before picking things up), allows
+ you to selectively pick up all items which you step on.
+
+#####GPrompt before picking up heavy objects [prompt_pickup_heavy]
+ Generates a prompt whenever the character tries to pick up an item that
+ would slow him down.
+
+#####GRepeat obvious commands [always_repeat]
+ Tells the game that when you attempt to open a door or chest, bash
+ a door, tunnel through walls, or disarm traps or chests, that you
+ wish to repeat the command 99 times (see *****command.txt*0["command.txt"]).
+
+#####GShow dungeon level in feet [depth_in_feet]
+ Display the dungeon depth in "feet" instead of as a level number (one
+ level is equivalent to 50'). This also affects the monster memory display.
+
+#####GMerge inscriptions when stacking [stack_force_notes]
+ Force otherwise identical objects to merge, even if one has an empty
+ inscription and the other does not. The resulting stack keeps the
+ non-empty inscription.
+
+#####GMerge discounts when stacking [stack_force_costs]
+ Force otherwise identical objects to merge, even if they have different
+ discounts. The resulting stack keeps the largest discount. This option
+ may cause you to lose "value", but will give you optimal pack usage.
+
+#####GShow labels in object lists [show_labels]
+ Display the "labels" for objects in the equipment list, and in any
+ special window which is displaying the equipment. These labels
+ indicate what the player is using the object for, such as "wielding"
+ or "wearing" (in a given location). After you have played for a while,
+ this information is no longer useful, and can be annoying.
+ Note that in ToME this option no longer controls the "plain
+ flavoured object descriptions": a separate option for them has been added
+ under "ToME Options".
+
+#####GShow weights in object lists [show_weights]
+ Display the weight of objects in the inventory and equipment lists,
+ and in stores, and in any special window which is displaying any of
+ these lists.
+
+#####GShow graphics in inventory list [show_inven_graph]
+ Display the graphics of objects in the inventory list, and in any special
+ window which is displaying the inventory list.
+
+#####GShow graphics in equipment list [show_equip_graph]
+ Display the graphics of objects in the equipment list, and in any special
+ window which is displaying the equipment list.
+
+#####GShow graphics in stores [show_store_graph]
+ Display the graphics of objects in the store list.
+
+#####GShow choices in certain sub-windows [show_choices]
+ Indicate legal choices in special windows which display lists.
+
+#####GShow details in certain sub-windows [show_details]
+ Indicate extra details in special windows, currently used to activate
+ the display of death counts and monster descriptions when recalling
+ details about a monster.
+
+#####GAudible bell (on errors, etc) [ring_bell]
+ Attempt to make a "bell" noise when various errors occur.
+
+~~~~~09|Options|Disturbance
+#####R=== Option Set 2 -- Disturbance ===
+
+#####GRun past stairs [find_ignore_stairs]
+ Ignore stairs when running.
+
+#####GRun through open doors [find_ignore_doors]
+ Ignore open doors when running.
+
+#####GRun past known corners [find_cut]
+ Cut sharply around known corners when running. This will result in
+ faster running, but may cause you to run into a lurking monster.
+
+#####GRun into potential corners [find_examine]
+ Fully explore potential corners in hallways. This is strongly
+ recommended if your light source has a small radius (e.g. a torch).
+
+#####GDisturb whenever any monster moves [disturb_move]
+ Disturb the player when any monster moves, appears, or disappears.
+ This includes monsters which are only visible due to telepathy, so
+ you should probably turn this option off if you want to "rest" near
+ such monsters.
+
+#####GDisturb whenever viewable monster moves [disturb_near]
+ Disturb the player when any viewable monster moves, whenever any
+ monster becomes viewable for the first time, and also whenever any
+ viewable monster becomes no longer viewable. This option ignores
+ the existence of telepathy for the purpose of determining whether
+ a monster is viewable. See also the "view_reduce_view" option.
+
+#####GDisturb whenever map panel changes [disturb_panel]
+ This option causes you to be disturbed (stop running) when the screen
+ scrolls, as it does when you get close to the edge of the visible screen.
+
+#####GDisturb whenever leaving trap-detected area [disturb_detect]
+ This option causes you to be disturbed whenever you are leaving
+ a trap-detected area. This option is strongly recommended.
+
+#####GDisturb whenever player state changes [disturb_state]
+ This option causes you to be disturbed whenever the player state
+ changes, including changes in hunger, resistance, confusion, etc.
+
+#####GDisturb whenever boring things happen [disturb_minor]
+ This option causes you to be disturbed by various boring things,
+ including monsters bashing down doors, inventory feelings, and
+ beginning to run out of light-source fuel.
+
+#####GDisturb whenever random things happen [disturb_other]
+ In ToME, uncursed teleporting items may teleport you around sometimes,
+ asking for your confirmation (and possibly disturbing your rest). If you
+ unset this option, they will stop asking you and teleporting you randomly.
+ Cursed items will neither ask for confirmation nor stop teleporting you
+ even if this option is unset. (You may also inscribe an item with {.}
+ to suppress its random-teleportation power, unless it is cursed.)
+
+#####GAlert user to critical hitpoints [alert_hitpoint]
+ Produce a "bell" noise, and flushes all pending input, when your hitpoints
+ reach the warning point chosen elsewhere, preventing stupid deaths.
+
+#####GAlert user to various failures [alert_failure]
+ Produce a "bell" noise, and flushes all pending input, when various
+ failures occur, as described above.
+
+#####GGet last words when the character dies [last_words]
+ Display a random line from the "death.txt" file when your character
+ dies. If this option is not selected, the "You die." message is displayed
+ instead.
+
+#####GAllow shopkeepers and uniques to speak [speak_unique]
+ If this option is in use, shopkeepers may sometimes whisper rumours to
+ you. Also certain monsters start boasting as they attack you, and when
+ they die, they say their "last words".
+
+#####GNo query to destroy known worthless items [auto_destroy]
+ It can sometimes be annoying that the Destroy command asks for confirmation
+ when you are attempting to destroy a Broken sword {cursed}. If this option
+ is set, no confirmation will be asked if you attempt to destroy an object
+ which you know to be worthless. Of course, cursed artifacts cannot be
+ destroyed even if this option is set.
+
+#####GConfirm to wear/wield known cursed items [confirm_wear]
+ Some players may occasionally, due to a typing mistake, find themselves
+ wearing an item which they knew was cursed. If this option is set, you
+ should be safe from such typing mistakes: you will be prompted if you
+ attempt to wear or wield an item if your character knows it is cursed.
+
+#####GPrompt before exiting a dungeon level [confirm_stairs]
+ Some players (such as myself) often accidentally press the '<' key
+ and exit a Special feeling level. If this option is set, the program
+ asks for confirmation before you go up or down the stairs. Others may
+ find the prompt annoying; they should of course not set this option. :-)
+
+#####GDisturb when visible pets move [disturb_pets]
+ The player may wish that some of the disturbance options do not apply
+ to pets: for example, it can be annoying if your rest is always disturbed
+ by a pet dog who pops in every now and then. By default, pets do not
+ disturb you even if full monster disturbance options are set. If you
+ want your pets to disturb you like normal monsters, set this option.
+
+#####GAutomatically open doors [easy_open]
+ Opens (and unlocks) doors by walking into them. Also, if you are adjacent
+ to only one known door, using the "o"pen command will not prompt you for
+ a direction.
+
+#####GAutomatically disarm traps [easy_disarm]
+ Attempts to disarm traps by walking into/over them. Also, if you are
+ adjacent to only one known trap, using the "D"isarm command will not
+ prompt you for a direction. If your disarming ability is particularly
+ low, you should probably not enable this option, because you will often
+ fail to disarm the traps, and sometimes trigger them.
+
+#####GAutomatically tunnel walls [easy_tunnel]
+ Automatically tunnels into walls by walking into them.
+
+~~~~~10|Options|Game-play
+#####R=== Option Set 3 -- Game-play ===
+
+#####GAuto-haggle in stores [auto_haggle]
+ Disable haggling in stores, resulting in a ten percent sales tax
+ on items which you would have otherwise been forced to haggle for.
+ When this option is on, all prices listed in stores will be the
+ actual price that you pay for an item, as opposed to the price
+ that the shop-keeper will suggest.
+
+#####GAuto-scum for good levels [auto_scum]
+ This is a hack but allows you to force the generation of "good" levels
+ in the dungeon. This option may be extremely slow on some machines,
+ especially deep in the dungeon. The minimum "goodness" of the level
+ is based on the dungeon level, so the deeper you go, the better the
+ level will be.
+
+#####GAllow weapons and armor to stack [stack_allow_items]
+ Allow identical weapons and armor to be combined into a stack. This
+ also allows unidentified, but identical, ammo to be combined, which
+ may result in the auto-identification of some of the ammo, but which
+ makes it a lot easier to actually use unidentified ammo.
+
+#####GAllow wands/staffs/rods to stack [stack_allow_wands]
+ Allow identical wands/staffs/rods to be combined into a stack. This
+ may force the items to be unstacked to use them, which may result
+ in overflow of the pack. Also, the entire stack can be recharged
+ (and possibly destroyed) at the same time.
+
+#####GExpand the power of the look command [expand_look]
+ Expand the "l"ook command to allow the user to look at grids which
+ are not actually in view of the player, allowing the examination of
+ objects/monsters which have only been detected by spells, or sensed
+ via telepathy.
+
+#####GExpand the power of the list commands [expand_list]
+ Expand the "listing" commands so that they wrap at the edges of
+ the appropriate list. This allows the "l"ook and "t"arget commands
+ to cycle through all appropriate grids forever, and the "identify
+ symbol" to browse through all of the monsters of a given type.
+
+#####GMap remembers all perma-lit grids [view_perma_grids]
+ Memorise all perma-lit floor grids which are seen by the player.
+ This option allows you to keep track of which explored floor grids
+ were perma-lit, but does not distinguish between dark floor grids,
+ unexplored floor grids, and unknown grids. Turning off this option
+ allows the player to always know which lit floor grids are in line
+ of sight, but this is better accomplished by the "view_bright_lite"
+ option. Note that any non-floor grids which is seen by the player
+ are always memorised, and any object which is seen by the player is
+ memorised independently from the memorisation of the grid itself.
+
+#####GMap remembers all torch-lit grids [view_torch_grids]
+ Memorise all (torch-lit) floor grids which are seen by the player.
+ This option not only allows you to keep track of which floor grids
+ have been explored, but also which ones are dark, because the use
+ of this option activates a special color scheme for the display of
+ floor grids, in which dark grids are drawn in dark grey, lit grids
+ are drawn in white, and (if the "view_bright_lite" option is set)
+ lit grids which are also in line of sight are drawn in orange. Note
+ that grids which are currently torch-lit are considered to be "lit",
+ and are thus drawn in white, unless the "view_yellow_lite" option is
+ set, in which case they are drawn in yellow.
+
+#####GAllow some monsters to carry light [monster_lite]
+ This option allows some monsters to carry light sources around with them,
+ lighting up the space around them. It can also allow you to see when some
+ monsters are heading your way before they reach the bend in the corridor
+ where you are hiding in ambush....
+
+#####GGenerate dungeons with aligned rooms [dungeon_align]
+ Force all rooms to be aligned with the "panel" divisions. This results
+ in a much prettier dungeon, but may result in fewer greater vaults.
+
+#####GGenerate dungeons with connected stairs [dungeon_stair]
+ Always generate a staircase back to the level whence you came, if you used
+ a staircase to get to the level. This is more "realistic", and safer,
+ but less of a challenge for some people.
+
+#####GMonsters chase current location (v.slow) [flow_by_sound]
+ Allow monsters to make paths to the player when they are nearby. This
+ option is extremely slow, but can produce viciously smart monsters.
+~~~~~3
+#####GUse special symbols for the player char [player_symbols]
+ If this option has been compiled in, it allows you to display your
+ character using race / class / sex dependent colours and graphical
+ symbols. Note that the support for this option may not have been
+ compiled in on all platforms.
+
+#####GPlain object descriptions [plain_descriptions]
+ In ToME, this option disables "full" names for identified flavoured
+ objects; in other words, if this option is not in use, an identified
+ Potion of Speed could be listed (for example) as a Blue Potion of Speed.
+ If you prefer simpler, less verbose descriptions, set this option.
+
+#####GMonsters learn from their mistakes [smart_learn]
+ Allow monsters to learn what spell attacks you are resistant to,
+ and to use this information to choose the best attacks.
+
+#####GMonsters exploit players weaknesses [smart_cheat]
+ Allow monsters to know what spell attacks you are resistant to, without
+ first having to observe such an attack upon you, and to use this
+ information to choose the best attacks.
+
+#####GMonsters behave stupidly [stupid_monsters]
+ ToME incorporates Keldon Jones' improved monster Artificial
+ Intelligence patch. While this patch most certainly makes monsters
+ behave more realistically, they will also be more deadly with the
+ improved AI. If you are a sissy, set this option to get the old,
+ really stupid monster AI.
+ Note that the new AI is a bit processing power expensive. If you have
+ an old computer (386sx) and ToME is running too slowly, you could
+ try turning stupid_monsters on. Or dumpster-dive for a Pentium so you can
+ run ToME. :-)
+
+#####GAllow unusually small dungeon levels [small_levels]
+ This option enables the creation of levels of varying sizes. Levels
+ that are as small as one "screen" (80x24) are possible, and they can be
+ quite dangerous, especially for a low level character, because they have
+ as many monsters and traps as their full-sized counterparts.
+ Note that this option has the side effect of enabling / disabling
+ 'destroyed' levels (they are enabled if small levels are).
+
+#####GAllow empty 'arena' levels [empty_levels]
+ Normal dungeon levels consist mostly of rock. If this option is in
+ use, levels which have empty floor instead of solid rock may also
+ be created (somewhat reminiscent of Nethack's "big-room" levels).
+ These levels can be extremely deadly, especially with breathing
+ monsters (since there are few obstructions to shield you). Arena levels
+ may have vaults, nests and pits in them like normal levels. Some
+ arena levels are dark when they are created, but most are lit.
+
+~~~~~11|Options|Efficiency
+#####R=== Option Set 4 -- Efficiency ===
+
+#####GReduce lite-radius when running [view_reduce_lite]
+ Reduce the radius of the player's light to that of a torch (radius 1)
+ when the player is running, which makes running more efficient (CPU-wise),
+ but is extremely annoying. Certain older versions of Angband used
+ this behavior always, so "purists" should turn it on.
+
+#####GReduce view-radius in town [view_reduce_view]
+ No longer in use.
+
+#####GAvoid checking for user abort [avoid_abort]
+ Avoid checking to see if the user has pressed a key during resting
+ or running or repeated commands. This not only makes the game much
+ more efficient (on many systems), but also allows the use of certain
+ obscure macro sequences, such as turning this option on, resting until
+ done, turning this option off, and casting a spell. Note that the use
+ of this option may be dangerous on certain "graphic" machines. Resting
+ for long periods of time with this option set is dangerous since the
+ resting may not stop until the user takes damage from starvation.
+
+#####GAvoid processing special colors [avoid_other]
+ Avoid processing the "multi-hued" or "clear" attributes of monsters.
+ This will cause all multi-hued monsters to appear violet and all
+ clear monsters to appear white, and will cause trappers and lurkers to
+ be visible on some machines, but it may greatly increase efficiency
+ especially when telepathy is active. Certain systems may choose to set
+ this option if they are unable to support the special color processing,
+ but if they handle graphics "correctly", by using attr/char pairs with
+ the "high bits" set, then not only will the game correctly avoid using
+ any "dangerous" color processing, but it will allow such processing to
+ occur when it is not dangerous. So if you are using graphics, and you
+ use a normal attr/char for the floor grids, then you can use the
+ "special lighting effects" for floors.
+
+#####GFlush input on various failures [flush_failure]
+ This option forces the game to flush all pending input whenever various
+ "failures" occur, such as failure to cast a spell, failure to use a wand,
+ etc. This is very useful if you use macros which include "directional"
+ components with commands that can fail, since it will prevent you from
+ walking towards monsters when your spells fail.
+
+#####GFlush input whenever disturbed [flush_disturb]
+ This option forces the game to flush all pending input whenever the
+ character is "disturbed". This is useful if you use macros which take
+ time, since it will prevent you from continuing your macro while being
+ attacked by a monster.
+
+#####GFlush input before every command [flush_command]
+ This option forces the game to flush all pending input before every
+ command. This option is silly, unless you are very paranoid.
+
+#####GFlush output before every command [fresh_before]
+ This option forces the game to flush all output before every command.
+ This will give you maximal information, but may slow down the game
+ somewhat. Note that this option is only useful when using macros,
+ resting, running, or repeating commands, since the output is always
+ flushed when the game is waiting for a keypress from the user.
+
+#####GFlush output after every command [fresh_after]
+ This option forces the game to flush all output after not only every
+ player command, but also after every round of processing monsters and
+ objects, which will give you maximal information, but may slow down
+ the game a lot, especially on slower machines; and on faster machines
+ you normally do not have a chance to see the results anyway.
+
+#####GFlush output after every message [fresh_message]
+ This option forces the game to flush all output after every message
+ displayed by the game. This will give you maximal information, but
+ may slow down the game somewhat.
+~~~~~2
+#####GHilite the player with the cursor [hilite_player]
+ Place the visible cursor on the player. This looks fine on some Unix
+ machines, but horrible on most graphics machines. Note that only some
+ machines are able to *not* show the cursor, but on those machines, hiding
+ the cursor often speeds up the game and looks better.
+
+#####GUse special colors for torch-lit grids [view_yellow_lite]
+ This option causes special colors to be used for "torch-lit" grids in
+ certain situations (see "view_granite_lite" and "view_special_lite").
+ Turning this option off will slightly improve game speed.
+
+#####GUse special colors for 'viewable' grids [view_bright_lite]
+ This option causes special colors to be used for non "viewable" grids
+ in certain situations (see "view_granite_lite" and "view_special_lite").
+ When this option is set, floor grids which are normally drawn in white
+ but which are not currently viewable by the player are instead drawn
+ in dark grey. This makes the viewable grids appear brighter than the
+ others, allowing the player to easily determine which floor grids are
+ in line of sight. Turning this option off will probably increase the
+ speed of the game.
+
+#####GUse special colors for wall grids (slow) [view_granite_lite]
+ This option activates a special color scheme for all wall grids which
+ are normally drawn in white (as walls and rubble normally are). When
+ the player is blind, we use dark grey, else if the grid is torch-lit,
+ we use yellow (or white, depending on the "view_yellow_lite" option),
+ else if the "view_bright_lite" option is set, and the grid is not in line
+ of sight, or the grid is dark, or the grid is only "partially" lit, then
+ we use grey, otherwise we use the normal white. Turning this option
+ off will probably increase the speed of the game.
+
+#####GUse special colors for floor grids (slow) [view_special_lite]
+ This option activates a special color scheme for all floor grids which
+ are normally drawn in white (as they normally are). When the player is
+ blind, we use dark grey, else if the grid is torch-lit, we use yellow
+ (or white, depending on the "view_yellow_lite" option), else if the grid
+ is dark, we use dark grey, else if the "view_bright_lite" option is
+ set, and the grid is not in line of sight, we use grey, otherwise we
+ use the normal white. Turning this option off will probably increase
+ the speed of the game.
+
+#####GCentre the view on the player (very slow) [center_player]
+ Keeps the player's character in the centre of the screen, and moves the
+ dungeon around the player. Can be useful to prevent off-screen breaths.
+
+~~~~~12|Options|ToME Options
+#####R=== ToME Options ===
+
+Features which are unique to ToME are collected in this menu.
+
+#####GIngame contextual help [ingame_help]
+ Setting this option allows the game to trigger a help message the first
+ time you come across an item or some other trigger. This is very useful
+ for new players. More experienced players may wish to switch this option
+ off.
+
+#####GShow the experience needed for the next level [exp_need]
+ Setting this option alters the display of experience on the left of
+ the main screen to the experience needed to reach the next character level,
+ instead of the character's current total experience.
+
+#####GUse the old(Z) coloring scheme(reload the game) [old_colors]
+ Setting this option toggles the ASCII game colour display from the
+ standard Angband monster colours to the Zangband-based monster colours.
+ Since this alters the display and monster memory display, you need to
+ reload the game when you alter this setting before it will display the
+ new colours.
+
+#####GAutomatically clear '-more-' prompts [auto_more]
+ Setting this option automatically clears any messages from the top
+ of the window. Be warned that this could be dangerous, as you don't
+ actually get to see the messages unless you use ^P.
+
+#####GPlayer char represent his/her health [player_char_health]
+ Setting this option only affects the game when playing without tiles.
+ As the player becomes injured, his icon changes to a figure representing
+ the percentage of health remaining; for example if he is down to 68% of
+ his maximum hitpoints, his character will be a '6' instead of an '@'.
+ The character used only starts changing once the player has lost at
+ least 30% of his maximum hitpoints.
+
+#####GStats are represented in a linear way [linear_stats]
+ Setting this option alters the display of character stats. The default
+ is 3 to 40 (linear), but the older 3 to 18/220 (Moria/Angband style) is
+ retained for players who prefer it.
+
+#####GIn option windows, just omit the select char [inventory_no_move]
+ If this option is set, the equipment/inventory windows don't move items
+ around when a prompt asks for an item.
+
+
+#####R=== Stacking Options ===
+
+In ToME items are allowed to stack on floors and monsters are allowed to
+maintain inventories. These features are enabled by default, and aren't
+accessible through the option menu, but can still be disabled through
+user pref files (see *****command.txt*105["command.txt"]).
+
+#####GAllow objects to stack on the floor [testing_stack]
+ Allows a cave grid to hold more than one object (or one kind of
+ object).
+
+#####GAllow monsters to carry objects [testing_carry]
+ If this option is set, monsters which "pick up" objects will drop
+ the objects they were carrying when you kill them. Note that monsters
+ which "crush" objects are not affected by this option.
+
+~~~~~13|Options|Base Delay Factor
+#####R=== Base Delay Factor ===
+
+The "delay_factor" value, if non-zero, is used to slow down the game, which is
+useful to allow you to observe the temporal effects of bolt, beam, and ball
+attacks. The actual delay is equal to "delay_factor" cubed, in milliseconds.
+Frequently used factors are 2 or 3.
+
+~~~~~14|Options|Hitpoint Warning
+#####R=== Hitpoint Warning ===
+
+The "hitpoint_warn" value, if non-zero, is the percentage of maximal hitpoints
+at which the player is warned that he may die. It is also used as the cut-off
+for using red to display hitpoints, mana and sanity. It is entered as a value
+between 0 and 9 (0% and 90%).
+
+~~~~~15|Options|Autosave
+#####R=== Autosave Options ===
+
+Ideally, the game should be so stable that these options are not needed
+at all. However, even if the game were 100% reliable (which, to be frank, it
+probably is not), the user might forget to save, and his hardware could fail
+him. For all of these reasons, you may want to use these options:
+
+#####GAutosave when entering new levels [autosave_l]
+ If this option is set, the program will attempt to save your
+ character every time before creating a new dungeon level. Useful
+ if you experience any game or computer crashes (or your dog enjoys
+ kicking your power cords out of the wall like mine does!).
+
+#####GTimed autosave [autosave_t]
+ If this option is set, the program will attempt to save your
+ character every n game turns, where n is the "frequency". To set
+ frequency, press n: it will increase the frequency to the next
+ category, these being every 50, 100, 250, 500, 1000, 2500, 5000,
+ 10000 or 25000 turns. (After 25000, pressing n again will cycle back
+ to 0.) Note that the frequency must be higher than 0 and the
+ "Timed autosave" set to "yes" for timed autosaves to take place.
+
+~~~~~16|Options|Automatizer
+#####R=== The Automatizer ===
+
+Allows you to set options for the game to automatically destroy or pick up
+objects when you identify them, for example skeletons, essences, cursed
+daggers, etc. Useful for reducing the clutter in the dungeon, and reducing the
+amount of loot to have to sort through. This *****automat.txt*0[Tutorial] may help you.
+
+~~~~~17|Options|Window Flags
+#####R=== Window Flags ===
+
+Selects what kind of information is displayed in which window, on platforms
+which use multiple windows.
+
+You can select a window to be able to toggle between 2 different
+sets of information (e.g. Basic Character stats and monster recall)
+by pressing the "y" key over the second display option.
+
+~~~~~18|Options|Cheating
+#####R=== Cheating Options ===
+
+#####GPeek into object creation [cheat_peek]
+ Cheaters never win. But they can peek at object creation.
+
+#####GPeek into monster creation [cheat_hear]
+ Cheaters never win. But they can peek at monster creation.
+
+#####GPeek into dungeon creation [cheat_room]
+ Cheaters never win. But they can peek at room creation.
+
+#####GPeek into something else [cheat_xtra]
+ Cheaters never win. But they can see debugging messages.
+
+#####GKnow complete monster info [cheat_know]
+ Cheaters never win. But they can know all about monsters.
+
+#####GAllow player to avoid death [cheat_live]
+ Cheaters never win. But they can cheat death.
+
+~~~~~19|Options|Dump/Load Options
+#####R=== Dump Options ===
+
+Allows the player to save the options to a file (defaults to charname.prf)
+so that they can be reloaded into other character files.
+
+
+#####R=== Load Options ===
+
+Allows you to load a preference file saved through the "Dump Options"
+command in another character file, hence saving all the initial time of having
+to reset all the options every time you wish to play.
+
+
++++ Ben +++ (Updated by Dark God and Dawnmist et al. for ToME)
diff --git a/lib/mods/theme/help/r_beorn.txt b/lib/mods/theme/help/r_beorn.txt
new file mode 100644
index 00000000..b000403f
--- /dev/null
+++ b/lib/mods/theme/help/r_beorn.txt
@@ -0,0 +1,33 @@
+~~~~~01|Beorning
+~~~~~02|Races|Beorning
+#####R=== Beornings ===
+
+#####GDescription
+Beornings are the descendants of Beorn, a powerful shapeshifter who
+dwells near Mirkwood. They have all inherited his shapeshifting abilities
+and can turn into powerful bears at will.
+
+#####GStat Modifiers
+Strength +4
+Intelligence -2
+Wisdom -2
+Dexterity -1
+Constitution +3
+Charisma -5
+Hit Dice Sides 12
+Exp Penalty +50%
+
+#####GSkill Bonuses (supplementary to existing skills)
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 2.500 [0.000]
+ Archery 0.500 [0.000]
+ Bearform-combat 1.000 [1.000]
+Sneakiness -0.100 [0.000]
+ Stealth -2.000 [0.000]
+ Disarming -0.600 [0.000]
+Magic
+ Magic-Device -0.800 [0.000]
+Spirituality -3.000 [0.000]
diff --git a/lib/mods/theme/help/r_demon.txt b/lib/mods/theme/help/r_demon.txt
new file mode 100644
index 00000000..7d54d187
--- /dev/null
+++ b/lib/mods/theme/help/r_demon.txt
@@ -0,0 +1,31 @@
+~~~~~01|Demon
+~~~~~02|Races|Demon
+#####R=== Demons ===
+
+#####GDescription
+Demons are minor servants of the Dark. They are natural creatures
+that have been corrupted and twisted by Melkor to serve his ends.
+All demons have an intrinsic understanding of the forces of Dark,
+they resist darkness and fear, and have a firm hold on their life
+forces. Most of a demon's ability depends on their subrace, of
+which there are ten. As a corrupted race, demons will gain and
+lose corruptions randomly as they gain experience.
+
+#####GStat Modifiers
+Strength 0
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution 0
+Charisma -1
+Hit Dice Sides 10
+Exp Penalty +70%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Sneakiness 0.000 [0.000]
+ Stealth 0.000 [0.000]
+ Disarming +0.500 [0.000]
+Magic
+ Magic-Device +0.050 [0.000]
+Spirituality -5.000 [0.000] \ No newline at end of file
diff --git a/lib/mods/theme/help/r_dragon.txt b/lib/mods/theme/help/r_dragon.txt
new file mode 100644
index 00000000..097d6462
--- /dev/null
+++ b/lib/mods/theme/help/r_dragon.txt
@@ -0,0 +1,33 @@
+~~~~~01|Dragons
+~~~~~02|Races|Dragons
+#####R=== Dragons ===
+
+#####GDescription
+Dragons are majestic creatures of power traditionally aligned with
+the forces of evil. However, some may choose to become adventurers.
+They may not wield any weapons, bows, or play musical instruments.
+However, they are able to fly from birth, and gain resistances to
+some of the elements (depending on their subrace). Dragons have to
+choose a subrace specific to their race. Dragons make very good
+Mages, but they cannot become Geomancers, because they are unable
+to wield mage staves. As winged beings, Dragons may not wear cloaks.
+
+#####GStat Modifiers
+Strength +3
+Intelligence +2
+Wisdom +2
+Dexterity -2
+Constitution +2
+Charisma -5
+Hit Dice Sides 9
+Exp Penalty +150%
+
+#####GRacial Skills
+Combat 0.000 [0.000]
+ Barehand-combat 0.000 [0.400]
+Sneakiness 0.000 [0.000]
+ Stealth -10.000 [0.000]
+ Disarming 1.000 [0.000]
+Magic 0.000 [0.000]
+ Magic-Device 0.500 [0.000]
+Spirituality -4.000 [0.000] \ No newline at end of file
diff --git a/lib/mods/theme/help/r_drkelf.txt b/lib/mods/theme/help/r_drkelf.txt
new file mode 100644
index 00000000..3f0758e5
--- /dev/null
+++ b/lib/mods/theme/help/r_drkelf.txt
@@ -0,0 +1,33 @@
+~~~~~01|Dark Elf
+~~~~~02|Races|Dark Elf
+#####R=== Dark Elves ===
+
+#####GDescription
+Another dark, cave-dwelling race, likewise unhampered by darkness attacks,
+the Dark Elves have a long tradition and knowledge of magic. With their
+intelligence and wisdom they can become superb mages or priests, and they
+have an inherent magic missile attack available to them at a low level. With
+their keen sight, they also learn to see invisible things as their relatives
+the High-Elves do, but at a higher level.
+
+#####GStat Modifiers
+Strength -1
+Intelligence +3
+Wisdom +2
+Dexterity +2
+Constitution -2
+Charisma +1
+Hit Dice Sides 9
+Exp Penalty +50%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.500 [0.000]
+ Archery 1.000 [0.000]
+Sneakiness 0.800 [0.000]
+ Stealth 3.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic 0.000 [0.200]
+ Magic-Device 1.500 [0.000]
+Spirituality 10.000 [0.000]
diff --git a/lib/mods/theme/help/r_druadan.txt b/lib/mods/theme/help/r_druadan.txt
new file mode 100644
index 00000000..bf063956
--- /dev/null
+++ b/lib/mods/theme/help/r_druadan.txt
@@ -0,0 +1,32 @@
+~~~~~01|Druedain
+~~~~~02|Races|Druadan
+#####R=== Druedain ===
+
+#####GDescription
+An ancient branch of the race of Men, they are somewhat weaker, but wiser
+and better at disguise. They can learn to throw poisoned darts (of which
+they carry an unlimited supply). They are also inherently resistant to
+poison, and can become adequate fighters.
+
+#####GStat Modifiers
+Strength -2
+Intelligence -3
+Wisdom 2
+Dexterity 3
+Constitution -2
+Charisma -2
+Hit Dice Sides 9
+Exp Penalty +15%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat 0.000 [0.000]
+ Weaponmastery 1.000 [0.000]
+ Archery 0.800 [0.000]
+ Boomerang-mastery 0.000 [0.250]
+Sneakiness 0.100 [0.000]
+ Stealth 1.000 [0.000]
+ Disarming -0.200 [0.000]
+Magic 0.000 [0.000]
+ Magic-Device -0.300 [0.000]
+Spirituality -1.000 [0.000] \ No newline at end of file
diff --git a/lib/mods/theme/help/r_dunad.txt b/lib/mods/theme/help/r_dunad.txt
new file mode 100644
index 00000000..79b85049
--- /dev/null
+++ b/lib/mods/theme/help/r_dunad.txt
@@ -0,0 +1,32 @@
+~~~~~01|Dunedain
+~~~~~02|Races|Dunedain
+#####R=== Dunedain ===
+
+#####GDescription
+Dunedain are a race of hardy men from the West. This elder race surpasses
+human abilities in every field, especially constitution. However, being
+men of the world, very little is new to them, and levels are very hard for
+them to gain. They can play all classes. Their constitution cannot be
+reduced and they regain hit points quickly.
+
+#####GStat Modifiers
+Strength +1
+Intelligence +2
+Wisdom +2
+Dexterity +2
+Constitution +3
+Charisma +2
+Hit Dice Sides 10
+Exp Penalty +80%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.500 [0.000]
+ Archery 1.000 [0.000]
+Sneakiness 0.800 [0.000]
+ Stealth 2.000 [0.000]
+ Disarming 0.400 [0.000]
+Magic
+ Magic-Device 0.500 [0.000]
+Spirituality 2.500 [0.000]
diff --git a/lib/mods/theme/help/r_dwarf.txt b/lib/mods/theme/help/r_dwarf.txt
new file mode 100644
index 00000000..6c5a9b80
--- /dev/null
+++ b/lib/mods/theme/help/r_dwarf.txt
@@ -0,0 +1,39 @@
+~~~~~01|Dwarf
+~~~~~02|Races|Dwarf
+#####R=== Dwarves ===
+
+#####GDescription
+Dwarves are the headstrong miners and fighters of legend. Since dungeons
+are the natural home of a dwarf, they are excellent choices for a warrior
+or priest. Dwarves tend to be stronger and tougher but less agile and
+intelligent than humans. Because they are so headstrong and are somewhat
+wise, they resist spells which are cast on them. Dwarves also have very
+good infra-vision because they live underground. They do have one big
+drawback, though: dwarves are loud-mouthed and proud, singing in boisterous
+voices, arguing with themselves for no good reason, and screaming out
+challenges at nearby foes. In other words, dwarves have miserable
+stealth. They can never be blinded, and they can also open secret tunnels
+through rock.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -2
+Wisdom +2
+Dexterity -2
+Constitution +2
+Charisma -3
+Hit Dice Sides 11
+Exp Penalty +25%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.500 [0.000]
+ Axe-mastery 0.000 [0.200]
+ Archery 0.500 [0.000]
+Sneakiness 0.700 [0.000]
+ Stealth -1.000 [0.000]
+ Disarming 0.200 [0.000]
+Magic
+ Magic-Device 0.900 [0.000]
+Spirituality 5.000 [0.000]
diff --git a/lib/mods/theme/help/r_eagle.txt b/lib/mods/theme/help/r_eagle.txt
new file mode 100644
index 00000000..cd59aaaf
--- /dev/null
+++ b/lib/mods/theme/help/r_eagle.txt
@@ -0,0 +1,32 @@
+~~~~~01|Eagle
+~~~~~02|Races|Eagle
+#####R=== Eagles ===
+
+#####GDescription
+"The Eagles are coming! The Eagles are coming!" Ever has this cry signified
+the Great Eagles of Manwe coming to a battlefield or a dire emergency to aid
+the forces of good. Majestic magical birds ever faithful to Manwe Sulimo,
+though they may choose to worship other Valar during their time on Arda. They
+have been given many gifts by Manwe, not the least important of which is the
+ability to resist the elements as they mature. They cannot wield weapons,
+bows, or play musical instruments, however. The Eagles' greatest enemies are
+the dragons, and they learn to detect the presence of dragons fairly early.
+As winged creatures, Eagles may not wear cloaks.
+
+#####GStat Modifiers
+Strength +6
+Intelligence +2
+Wisdom +1
+Dexterity -2
+Constitution +3
+Charisma +6
+Hit Dice Sides 12
+Exp Penalty +200%
+
+#####GRacial Skills
+Combat 0.000 [0.000]
+ Barehand-combat 1.000 [0.300]
+Sneakiness 3.000 [0.000]
+ Stealth -16.000 [0.000]
+ Disarming 6.000 [0.000]
+Spirituality 5.000 [0.000] \ No newline at end of file
diff --git a/lib/mods/theme/help/r_easterl.txt b/lib/mods/theme/help/r_easterl.txt
new file mode 100644
index 00000000..2370d260
--- /dev/null
+++ b/lib/mods/theme/help/r_easterl.txt
@@ -0,0 +1,34 @@
+~~~~~01|Easterling
+~~~~~02|Races|Easterling
+#####R=== Easterlings ===
+
+#####GDescription
+From the time of the Dagor Bragollach, the Easterlings have stood as
+the treacherous race of men. Swarthy and stout, these humans cannot
+be stunned, get a penchant for landing on their feet, and are not
+confused easily, once they have gained some experience. They are equally
+good at all kinds of weapons, being trained in combat from an early age.
+They do not trust magic, however, and have little skill in it.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -2
+Wisdom -2
+Dexterity -2
+Constitution +2
+Charisma -1
+Hit Dice Sides 10
+Exp Penalty +40%
+
+#####GSkill bonuses (supplementary to existing skills)
+Combat 1.000 [0.100]
+ Weaponmastery 0.500 [0.100]
+ Sword-mastery 0.000 [0.100]
+ Axe-mastery 0.000 [0.100]
+ Hafted-mastery 0.000 [0.100]
+ Polearm-mastery 0.000 [0.100]
+ Archery 2.000 [0.200]
+Sneakiness 1.000 [0.300]
+ Stealth 1.000 [0.200]
+ Disarming 1.000 [0.200]
+Spirituality 2.500 [0.300] \ No newline at end of file
diff --git a/lib/mods/theme/help/r_elf.txt b/lib/mods/theme/help/r_elf.txt
new file mode 100644
index 00000000..6b4ceb3b
--- /dev/null
+++ b/lib/mods/theme/help/r_elf.txt
@@ -0,0 +1,32 @@
+~~~~~01|Elf
+~~~~~02|Races|Elf
+#####R=== Elves ===
+
+#####GDescription
+Elves are better magicians than humans, but not as good at fighting. They
+tend to be smarter and faster than either humans or half-elves and also
+have better wisdom. Elves are better at searching, disarming, perception,
+stealth, bows, and magic, but they are not as good at hand weapons.
+They resist light effects intrinsically.
+
+#####GStat Modifiers
+Strength -1
+Intelligence +2
+Wisdom +2
+Dexterity +1
+Constitution -2
+Charisma +2
+Hit Dice Sides 8
+Exp Penalty +20%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -5.000 [0.000]
+ Archery 1.500 [0.000]
+Sneakiness 0.800 [0.000]
+ Stealth 2.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic
+ Magic-Device 0.600 [0.000]
+Spirituality 3.000 [0.000]
diff --git a/lib/mods/theme/help/r_ent.txt b/lib/mods/theme/help/r_ent.txt
new file mode 100644
index 00000000..1b3e047e
--- /dev/null
+++ b/lib/mods/theme/help/r_ent.txt
@@ -0,0 +1,39 @@
+~~~~~01|Ent
+~~~~~02|Races|Ent
+#####R=== Ents ===
+
+#####GDescription
+The Ents are a powerful race dating back to the beginning of the world and
+are the eldest of all animals or plants that inhabit Arda. Spirits of the land,
+they were summoned to guard the forests of Middle-earth. Being much like
+trees they are very slow but strong, and very susceptible to fire. They cannot
+be poisoned, however, and their bark is very tough. As the Shepherds of the Trees,
+they have the innate ability to cause trees to rise about them for protection.
+
+#####GStat Modifiers
+Strength +10
+Intelligence -3
+Wisdom +2
+Dexterity -5
+Constitution +11
+Charisma -3
+Hit Dice Sides 14
+Exp Penalty +110%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.300 [0.000]
+ Archery -0.200 [0.000]
+ Barehand-combat 0.000 [0.200]
+ Boulder-throwing 0.000 [0.600]
+Sneakiness 0.500 [0.000]
+ Stealth -6.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic
+ Magic-Device 0.500 [0.000]
+Spirituality 10.000 [0.000]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Tree-walking 1
diff --git a/lib/mods/theme/help/r_gnome.txt b/lib/mods/theme/help/r_gnome.txt
new file mode 100644
index 00000000..8272e8a5
--- /dev/null
+++ b/lib/mods/theme/help/r_gnome.txt
@@ -0,0 +1,36 @@
+~~~~~01|Gnome
+~~~~~02|Races|Gnome
+#####R=== Gnomes ===
+
+#####GDescription
+Gnomes are smaller than dwarves but larger than halflings. Like the hobbits,
+they live in the earth in burrow-like homes. Gnomes make excellent magi,
+and have very good saving throws. They are good at searching, disarming,
+perception, and stealth. They have lower strength than humans and they are
+not very good at fighting with hand weapons, but have developed a fondness
+for the crossbow. Gnomes have fair infra-vision, so they can detect
+warm-blooded creatures at a distance. Gnomes are intrinsically protected
+against paralysis and some slowing effects. At higher levels, gnomes learn
+to teleport at will.
+
+#####GStat Modifiers
+Strength -1
+Intelligence +2
+Wisdom 0
+Dexterity +2
+Constitution +1
+Charisma -2
+Hit Dice Sides 8
+Exp Penalty +35%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.800 [0.000]
+ Archery 1.200 [0.000]
+Sneakiness 0.600 [0.000]
+ Stealth 3.000 [0.000]
+ Disarming 1.000 [0.000]
+Magic
+ Magic-Device 1.200 [0.000]
+Spirituality 6.000 [0.000]
diff --git a/lib/mods/theme/help/r_hafelf.txt b/lib/mods/theme/help/r_hafelf.txt
new file mode 100644
index 00000000..ea748440
--- /dev/null
+++ b/lib/mods/theme/help/r_hafelf.txt
@@ -0,0 +1,31 @@
+~~~~~01|Half-Elf
+~~~~~02|Races|Half-Elf
+#####R=== Half-Elves ===
+
+#####GDescription
+Half-elves tend to be smarter and more agile than humans, but not as tough.
+Half-elves are slightly better at searching, disarming, saving throws,
+stealth, bows, and magic, but they are not as good at hand weapons. Half-
+elves may choose any class and do not receive any intrinsic abilities.
+
+#####GStat Modifiers
+Strength 0
+Intelligence +1
+Wisdom +1
+Dexterity +1
+Constitution -1
+Charisma +1
+Hit Dice Sides 9
+Exp Penalty +10%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -1.000 [0.000]
+ Archery 0.500 [0.000]
+Sneakiness 0.600 [0.000]
+ Stealth 1.000 [0.000]
+ Disarming 0.200 [0.000]
+Magic
+ Magic-Device 0.300 [0.000]
+Spirituality 1.500 [0.000]
diff --git a/lib/mods/theme/help/r_hafogr.txt b/lib/mods/theme/help/r_hafogr.txt
new file mode 100644
index 00000000..2a173e98
--- /dev/null
+++ b/lib/mods/theme/help/r_hafogr.txt
@@ -0,0 +1,31 @@
+~~~~~01|Half-Ogre
+~~~~~02|Races|Half-Ogre
+#####R=== Half-Ogres ===
+
+#####GDescription
+Half-Ogres are a crossbreed between a human and an ogre. They are big, bad, and
+stupid. For warriors, they have all the necessary attributes, and they can even
+become priests: after all, they are related to Ogre Magi, from whom they have
+learned the skill of setting trapped runes once their level is high enough. Like
+orcs, they resist darkness, and like trolls, they have their strength sustained.
+
+#####GStat Modifiers
+Strength +3
+Intelligence -1
+Wisdom -1
+Dexterity -1
+Constitution +3
+Charisma -3
+Hit Dice Sides 12
+Exp Penalty +30%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 2.000 [0.000]
+Sneakiness -0.100 [0.000]
+ Stealth -2.000 [0.000]
+ Disarming -0.300 [0.000]
+Magic
+ Magic-Device -0.500 [0.000]
+Spirituality -2.500 [0.000]
diff --git a/lib/mods/theme/help/r_hielf.txt b/lib/mods/theme/help/r_hielf.txt
new file mode 100644
index 00000000..3317a67b
--- /dev/null
+++ b/lib/mods/theme/help/r_hielf.txt
@@ -0,0 +1,34 @@
+~~~~~01|High-Elf
+~~~~~02|Races|High-Elf
+#####R=== High-Elves ===
+
+#####GDescription
+High-elves are a race of immortal beings dating from the beginning of
+time. They are masters of all skills, and are strong and intelligent.
+They can play all classes except rogues, and very well at that.
+High-elves begin their lives able to see the unseen, and resist light
+effects just like regular elves. However, there are few things that
+they have not seen already, and experience is very hard for them to
+gain.
+
+#####GStat Modifiers
+Strength +1
+Intelligence +3
+Wisdom +2
+Dexterity +3
+Constitution +1
+Charisma +5
+Hit Dice Sides 10
+Exp Penalty +100%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.000 [0.000]
+ Archery 2.500 [0.000]
+Sneakiness 0.300 [0.000]
+ Stealth 4.000 [0.000]
+ Disarming 0.400 [0.000]
+Magic
+ Magic-Device 2.000 [0.000]
+Spirituality 10.000 [0.000]
diff --git a/lib/mods/theme/help/r_hobbit.txt b/lib/mods/theme/help/r_hobbit.txt
new file mode 100644
index 00000000..d9fafb08
--- /dev/null
+++ b/lib/mods/theme/help/r_hobbit.txt
@@ -0,0 +1,39 @@
+~~~~~01|Hobbit
+~~~~~02|Races|Hobbit
+#####R=== Hobbits ===
+
+#####GDescription
+Hobbits, or Halflings, are very good at ranged combat (especially with slings),
+throwing, and have good saving throws. They also are very good at searching,
+disarming, perception and stealth; so they make excellent rogues, but prefer
+to be called burglars. They are much weaker than humans, and no good at melee
+fighting. Halflings have fair infra-vision, so they can detect warm creatures
+at a distance. Hobbits have their dexterity sustained and in time they learn
+to cook a delicious meal from available ingredients. Their sturdy constitutions
+also allow them to resist the insidious poison of the ring-wraiths. They do not
+wear shoes, as their feet grow naturally thick, leathery soles which make shoes
+a chore to put on and take off.
+
+#####GStat Modifiers
+Strength -2
+Intelligence +2
+Wisdom +1
+Dexterity +3
+Constitution +2
+Charisma +1
+Hit Dice Sides 7
+Exp Penalty +10%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -1.000 [0.000]
+ Archery 2.000 [0.000]
+ Sling-Mastery 0.000 [0.300]
+Sneakiness 1.200 [0.000]
+ Stealth 5.000 [0.000]
+ Disarming 1.500 [0.000]
+Magic
+ Magic-Device 1.800 [0.000]
+Spirituality 9.000 [0.000]
+
diff --git a/lib/mods/theme/help/r_human.txt b/lib/mods/theme/help/r_human.txt
new file mode 100644
index 00000000..57606764
--- /dev/null
+++ b/lib/mods/theme/help/r_human.txt
@@ -0,0 +1,23 @@
+~~~~~01|Human
+~~~~~02|Races|Human
+#####R=== Humans ===
+
+#####GDescription
+Humans act as a baseline race -- all other races are compared to them.
+Humans can choose any class and are average at everything. Humans tend to
+go up levels faster than most other races because of their shorter life
+spans. No racial adjustments or intrinsics occur to characters choosing
+the human race.
+
+#####GStat Modifiers
+Strength 0
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution 0
+Charisma 0
+Hit Dice Sides 10
+Exp Penalty 0%
+
+#####GRacial Skill Modifiers:
+None. Humans are the baseline race.
diff --git a/lib/mods/theme/help/r_maia.txt b/lib/mods/theme/help/r_maia.txt
new file mode 100644
index 00000000..d4a6c635
--- /dev/null
+++ b/lib/mods/theme/help/r_maia.txt
@@ -0,0 +1,20 @@
+~~~~~01|Maia
+~~~~~02|Races|Maia
+#####R=== Maia ===
+
+#####GDescription
+An old race, dating from before the creation of Arda, the Maiar were created by
+Eru to help the Valar in their task. However, they can not worship a God, nor
+is experience easy to remember for them. When they do finally manage to remember
+their encounters, they will find that their abilities will increase as they gain
+in knowledge.
+
+#####GStat Modifiers
+Strength 0
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution 0
+Charisma 0
+Hit Dice Sides 10
+Exp Penalty +0%
diff --git a/lib/mods/theme/help/r_orc.txt b/lib/mods/theme/help/r_orc.txt
new file mode 100644
index 00000000..c4bcf691
--- /dev/null
+++ b/lib/mods/theme/help/r_orc.txt
@@ -0,0 +1,35 @@
+~~~~~01|Orc
+~~~~~02|Races|Orc
+#####R=== Orcs ===
+
+#####GDescription
+Orcs make excellent warriors and decent priests, but are terrible at magic.
+They are as bad as dwarves at stealth, and horrible at searching, disarming,
+and perception. Orcs are quite ugly, and tend to pay more for goods in town.
+Orcs do make good warriors and rogues, for the simple reason that Orcs tend
+to have great constitutions and lots of hit points. Because of their
+preference for living underground rather than on the surface, orcs resist
+darkness attacks. Upon reaching experience level 3, an orc learns to dispel
+any fear that may be upon him.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -1
+Wisdom 0
+Dexterity +1
+Constitution +1
+Charisma -4
+Hit Dice Sides 10
+Exp Penalty +10%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.200 [0.000]
+ Archery -0.500 [0.000]
+Sneakiness
+ Stealth -1.000 [0.000]
+ Disarming -0.300 [0.000]
+Magic
+ Magic-Device -0.300 [0.000]
+Spirituality -1.000 [0.000]
diff --git a/lib/mods/theme/help/r_pettyd.txt b/lib/mods/theme/help/r_pettyd.txt
new file mode 100644
index 00000000..c8b8eba3
--- /dev/null
+++ b/lib/mods/theme/help/r_pettyd.txt
@@ -0,0 +1,30 @@
+~~~~~01|Petty Dwarf
+~~~~~02|Races|Petty Dwarf
+#####R=== Petty Dwarves ===
+
+#####GDescription
+A hated and persecuted race of nocturnal dwarves, these cave-dwellers are not
+bothered much by darkness. Their natural inclination to magically augmented
+items has made them immune to effects which could drain away magical
+enchantments, and, like ordinary dwarves, they can examine the dungeon to
+discover traps and secret doors. They are quite proficient as priests,
+warriors or rogues.
+
+#####GStat Modifiers
+Strength +1
+Intelligence -1
+Wisdom +2
+Dexterity 0
+Constitution +2
+Charisma -4
+Hit Dice Sides 11
+Exp Penalty +35%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Sneakiness 0.500 [0.000]
+ Stealth 1.000 [0.000]
+ Disarming 0.300 [0.000]
+Magic
+ Magic-Device 0.500 [0.000]
+Spirituality 5.000 [0.000]
diff --git a/lib/mods/theme/help/r_rohank.txt b/lib/mods/theme/help/r_rohank.txt
new file mode 100644
index 00000000..03391d4b
--- /dev/null
+++ b/lib/mods/theme/help/r_rohank.txt
@@ -0,0 +1,33 @@
+~~~~~01|RohanKnight
+~~~~~02|Races|RohanKnight
+#####R=== RohanKnights ===
+
+#####GDescription
+Knights of the Riddermark, these warriors are mounted upon swift steeds.
+Thus they receive a bonus to speed from the beginning and gain in speed
+as they become more experienced in riding. Wise through their prolonged
+contact with the Dunedain, their wrath may be seen in auras of war that
+drive their foes to confusion, and in a ray of light when jumping at light
+speed.
+
+#####GStat Modifiers
+Strength +4
+Intelligence -2
+Wisdom +3
+Dexterity +1
+Constitution +4
+Charisma +2
+Hit Dice Sides 10
+Exp Penalty +120%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 0.100 [0.200]
+ Archery 0.500 [0.000]
+Sneakiness 0.100 [0.000]
+ Stealth -8.000 [0.000]
+ Disarming 1.000 [0.000]
+Magic
+ Magic-Device 0.500 [0.000]
+Spirituality 2.500 [0.000]
diff --git a/lib/mods/theme/help/r_troll.txt b/lib/mods/theme/help/r_troll.txt
new file mode 100644
index 00000000..f35e5aa6
--- /dev/null
+++ b/lib/mods/theme/help/r_troll.txt
@@ -0,0 +1,34 @@
+~~~~~01|Troll
+~~~~~02|Races|Troll
+#####R=== Trolls ===
+
+#####GDescription
+Trolls are incredibly strong, and have more hit points than most other
+character races, so they make great warriors, and marginal priests. They
+are also very stupid and clumsy. They are bad at searching, disarming,
+perception, and stealth. They are so ugly that an orc grimaces in their
+presence. They also happen to be fun to play.... Trolls always have
+their strength sustained. At higher levels, trolls learn to enter a
+berserk fury, and regenerate from their wounds automatically.
+
+#####GStat Modifiers
+Strength +4
+Intelligence -4
+Wisdom -2
+Dexterity -4
+Constitution +3
+Charisma -6
+Hit Dice Sides 12
+Exp Penalty +37%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 2.000 [0.000]
+ Archery -1.000 [0.000]
+Sneakiness -0.100 [0.000]
+ Stealth -2.000 [0.000]
+ Disarming -0.500 [0.000]
+Magic
+ Magic-Device -0.800 [0.000]
+Spirituality -4.000 [0.000]
diff --git a/lib/mods/theme/help/r_wodelf.txt b/lib/mods/theme/help/r_wodelf.txt
new file mode 100644
index 00000000..1cb4bb55
--- /dev/null
+++ b/lib/mods/theme/help/r_wodelf.txt
@@ -0,0 +1,37 @@
+~~~~~01|Wood Elf
+~~~~~02|Races|Wood Elf
+#####R=== Wood Elves ===
+
+#####GDescription
+The first love of Wood Elves is hunting. As such, their skill with the bow
+is unparalleled. They train tirelessly with their bows, to the point of
+neglecting even melee skills. They resist light as with other elves, and
+do extra damage with a ranged weapon. They are almost custom made for the
+archer class, but also make interesting warriors. Even Wood Elf Mages
+are feasible, using the bow to attack and saving their magic for defence.
+They are more dangerous but less wise than High-Elves.
+
+#####GStat Modifiers
+Strength +2
+Intelligence +2
+Wisdom -3
+Dexterity +5
+Constitution 0
+Charisma +1
+Hit Dice Sides 7
+Exp Penalty +30%
+
+#####GRacial Skills
+Combat 0.000 [0.000]
+ Archery 4.000 [0.000]
+ Weaponmastery 1.000 [0.200]
+Sneakiness 0.800 [0.000]
+ Stealth 5.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic 0.000 [0.000]
+ Magic-Device 0.600 [0.000]
+Spirituality 3.000 [0.000]
+
+#####GInnate Abilities:
+#####BAbility Character level
+Tree-walking 1
diff --git a/lib/mods/theme/help/r_yeek.txt b/lib/mods/theme/help/r_yeek.txt
new file mode 100644
index 00000000..bdc7dcc5
--- /dev/null
+++ b/lib/mods/theme/help/r_yeek.txt
@@ -0,0 +1,30 @@
+~~~~~01|Yeek
+~~~~~02|Races|Yeek
+#####R=== Yeeks ===
+
+#####GDescription
+Yeeks are the least powerful of all the races. They suffer disadvantages
+in nearly all skills and attributes but to compensate they learn (and thus
+gain levels) extremely quickly.
+
+#####GStat Modifiers
+Strength -5
+Intelligence -5
+Wisdom -5
+Dexterity -5
+Constitution -5
+Charisma -5
+Hit Dice Sides 6
+Exp Penalty -75%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.500 [0.000]
+ Archery -0.500 [0.000]
+Sneakiness -0.500 [0.000]
+ Stealth -5.000 [0.000]
+ Disarming -0.500 [0.000]
+Magic
+ Magic-Device -0.500 [0.000]
+Spirituality -2.500 [0.000]
diff --git a/lib/mods/theme/help/rm_adanrog.txt b/lib/mods/theme/help/rm_adanrog.txt
new file mode 100644
index 00000000..5e4a46b9
--- /dev/null
+++ b/lib/mods/theme/help/rm_adanrog.txt
@@ -0,0 +1,31 @@
+~~~~~01|Adanrog
+~~~~~02|Race Modifiers|Adanrog
+#####R=== Adanroeg (Man-demons) ===
+
+#####GDescription
+The greatest of all the lesser demons, these are humanoid
+figures wreathed in living flame. Their most obvious
+advantage is that they are completely immune to fire from
+birth, because they are born in fire and all carry a small
+part of the Flame of Udun inside them. They are equally
+good at magic and combat. With time, they learn to channel
+the forces of darkness to temporarily assume Balrog form.
+
+#####GStat Modifiers
+Strength +1
+Intelligence +1
+Wisdom +1
+Dexterity +1
+Constitution +1
+Charisma +1
+Hit Dice +3 sides
+Exp Penalty +50%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Combat 0.000 [0.300]
+Magic 0.000 [0.300]
+
+#####GStarting Equipment
+An Adanrog character begins the game with:
+ Some rations
+ Some torches \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_aewrog.txt b/lib/mods/theme/help/rm_aewrog.txt
new file mode 100644
index 00000000..28d8013f
--- /dev/null
+++ b/lib/mods/theme/help/rm_aewrog.txt
@@ -0,0 +1,35 @@
+~~~~~01|Aewrog
+~~~~~02|Race Modifiers|Aewrog
+#####R=== Aewroeg (Bird Demons) ===
+
+#####GDescription
+The Aewroeg are birds corrupted by Morgoth into foul
+birdlike beings with dazzling wings. They are somewhat
+physically weak, but expert at befuddling enemies so
+that they believe they'd never seen anything so fair.
+They can fly, and their charisma is naturally sustained.
+With experience, they learn to resist fire and to
+prevent holding magics. They also have an innate ability
+to flap their wings to create mesmerising illusions.
+Good magic users, they are particularly skilled at the
+Mind school.
+
+#####GStat Modifiers
+Strength -2
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution 0
+Charisma +3
+Hit Dice +1 sides
+Exp Penalty +0%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Magic 0.000 [0.200]
+Mind 1.000 [0.300]
+
+#####GStarting Equipment
+An Aewrog character begins the game with:
+ Some rations
+ Some torches
+ A spellbook of Charm \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_barb.txt b/lib/mods/theme/help/rm_barb.txt
new file mode 100644
index 00000000..57d793ff
--- /dev/null
+++ b/lib/mods/theme/help/rm_barb.txt
@@ -0,0 +1,38 @@
+~~~~~01|Barbarian
+~~~~~02|Race Modifiers|Barbarian
+#####R=== Barbarian Race ===
+
+#####GDescription
+Barbarians are hardy members of their race. They are fierce in combat, and
+their wrath is feared throughout the world. Combat is their life: they learn
+to feel no fear. Barbarians are, however, suspicious of magic, which makes
+magic devices fairly hard for them to use, and also makes it impossible for
+them to play Mages.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -3
+Wisdom -2
+Dexterity +1
+Constitution +1
+Charisma -3
+Hit Dice +1 side
+Spell Points -50%
+Exp Penalty +25%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 1.200 [0.000]
+ Archery 0.500 [0.000]
+Sneakiness
+ Stealth -2.000 [0.000]
+ Disarming -0.200 [0.000]
+Magic
+ Magic-Device -1.000 [0.000]
+Spirituality 0.200 [0.000]
+
+#####GStarting Equipment
+A barbarian character begins the game with:
+ Some rations
+ Some torches
diff --git a/lib/mods/theme/help/rm_black.txt b/lib/mods/theme/help/rm_black.txt
new file mode 100644
index 00000000..1570389c
--- /dev/null
+++ b/lib/mods/theme/help/rm_black.txt
@@ -0,0 +1,31 @@
+~~~~~01|Black
+~~~~~02|Race Modifiers|Black
+#####R=== Black Dragons ===
+
+#####GDescription
+These dragons are utterly in command of the element of acid. They
+resist acid very well and learn to become impervious to it with
+experience. Their glistening coats are so beautiful that those who
+look upon them cannot help but marvel at their majesty. The more
+experience they gain, the more charismatic they become. They have
+an innate ability to spit acid collected at the bottom of their
+stomach, and they have access to the Water school of magic.
+
+#####GStat Modifiers
+Strength 0
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution 0
+Charisma +3
+Hit Dice +0 sides
+Exp Penalty +0%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Water 1.000 [0.600]
+
+#####GStarting Equipment
+A Black dragon character begins the game with:
+ Some rations
+ Some torches
+ A spellbook of Geyser \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_blue.txt b/lib/mods/theme/help/rm_blue.txt
new file mode 100644
index 00000000..d6d0bbeb
--- /dev/null
+++ b/lib/mods/theme/help/rm_blue.txt
@@ -0,0 +1,31 @@
+~~~~~01|Blue
+~~~~~02|Race Modifiers|Blue
+#####R=== Blue Dragons ===
+
+#####GDescription
+These dragons are utterly in command of the element of Earth.
+As such, they have an innate resistance to electricity, which
+with time becomes full immunity, as they can use the power of
+the Earth to neutralize electrical discharges. They have access
+to the Earth school of magic and can conjure up showers of
+blazing sparks to dazzle their opponents. They are especially
+agile and lithe, and their dexterity will increase with experience.
+
+#####GStat Modifiers
+Strength 0
+Intelligence 0
+Wisdom 0
+Dexterity +3
+Constitution 0
+Charisma 0
+Hit Dice +0 sides
+Exp Penalty +0%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Earth 1.000 [0.600]
+
+#####GStarting Equipment
+A Blue dragon character begins the game with:
+ Some rations
+ Some torches
+ A spellbook of Stone Skin
diff --git a/lib/mods/theme/help/rm_cabrog.txt b/lib/mods/theme/help/rm_cabrog.txt
new file mode 100644
index 00000000..eee1dada
--- /dev/null
+++ b/lib/mods/theme/help/rm_cabrog.txt
@@ -0,0 +1,35 @@
+~~~~~01|Caborrog
+~~~~~02|Race Modifiers|Caborrog
+#####R=== Caborroeg (Frog Demons) ===
+
+#####GDescription
+These demons are frogs that have been corrupted by Melkor.
+Small humanoids with quick, darting eyes and a penchant
+for emitting loud croaks. As such, they are not very
+strong or stealthy - however, they are quite fast and
+smart. With experience, they learn to develop a special
+protective layer around themselves and do not even need
+to wear armour. Expert magic users, their intelligence
+increases with experience, and they have access to the
+Conveyance and Temporal schools of magic.
+
+#####GStat Modifiers
+Strength -1
+Intelligence +2
+Wisdom +1
+Dexterity 0
+Constitution 0
+Charisma -3
+Hit Dice +2 sides
+Exp Penalty +10%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Dodging 1.000 [0.400]
+Magic 0.000 [0.200]
+Conveyance 0.000 [0.300]
+Temporal 0.000 [0.300]
+
+#####GStarting Equipment
+A Caborrog character begins the game with:
+ Some rations
+ Some torches \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_class.txt b/lib/mods/theme/help/rm_class.txt
new file mode 100644
index 00000000..81f72d87
--- /dev/null
+++ b/lib/mods/theme/help/rm_class.txt
@@ -0,0 +1,14 @@
+~~~~~01|Classical
+~~~~~02|Race Modifiers|Classical
+#####R=== Classical Race ===
+
+#####GDescription
+This is the normal, classical character of your chosen race.
+
+#####GStat Modifiers
+No changes to stats.
+
+#####GStarting Equipment
+A classical character begins the game with:
+ Some rations
+ Some torches
diff --git a/lib/mods/theme/help/rm_drarog.txt b/lib/mods/theme/help/rm_drarog.txt
new file mode 100644
index 00000000..7794f2cd
--- /dev/null
+++ b/lib/mods/theme/help/rm_drarog.txt
@@ -0,0 +1,34 @@
+~~~~~01|Draugrog
+~~~~~02|Race Modifiers|Draugrog
+#####R=== Draugroeg (Wolf Demons) ===
+
+#####GDescription
+Humanoids with long, snoutlike faces and shaggy fur around
+the ears. They learn more quickly and have more magical
+powes than their Hurog cousins. They have a tendency to
+snarl, however, which makes them quite unstealthy. They too
+learn to detect living and non-living beings around them as
+they gain experience, but they can also learn to detect the
+presence of powerful objects and beings before they even get
+near them. Good with magic, they have the ability to harness
+the power of their mind.
+
+#####GStat Modifiers
+Strength +1
+Intelligence +1
+Wisdom +1
+Dexterity +1
+Constitution +1
+Charisma -1
+Hit Dice +0 sides
+Exp Penalty -20%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Magic 0.000 [0.200]
+Spirituality 0.000 [0.200]
+Mindcraft 1.000 [0.500]
+
+#####GStarting Equipment
+A Draugrog character begins the game with:
+ Some rations
+ Some torches \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_ether.txt b/lib/mods/theme/help/rm_ether.txt
new file mode 100644
index 00000000..ee49f002
--- /dev/null
+++ b/lib/mods/theme/help/rm_ether.txt
@@ -0,0 +1,32 @@
+~~~~~01|Ethereal
+~~~~~02|Race Modifiers|Ethereal
+#####R=== Ethereal Dragons ===
+
+#####GDescription
+These dragons are powerful undead creatures, able to both fly and
+pass through solid objects with ease. Because of their previous
+experiences, they are much wiser than other dragons, and being
+undead, they know very well how to keep hold of their life force.
+As undead, they have access to the realm of chaos in the nether
+world, and can learn to breathe chaos at their enemies. Their
+wisdom increases with time, granting them access to the complex
+Meta school of magic.
+
+#####GStat Modifiers
+Strength 0
+Intelligence 0
+Wisdom +3
+Dexterity 0
+Constitution 0
+Charisma 0
+Hit Dice +0 sides
+Exp Penalty +0%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Meta 1.000 [0.600]
+
+#####GStarting Equipment
+An Ethereal dragon character begins the game with:
+ Some rations
+ Some torches
+ A spellbook of Recharge
diff --git a/lib/mods/theme/help/rm_green.txt b/lib/mods/theme/help/rm_green.txt
new file mode 100644
index 00000000..0e07d6aa
--- /dev/null
+++ b/lib/mods/theme/help/rm_green.txt
@@ -0,0 +1,30 @@
+~~~~~01|Green
+~~~~~02|Race Modifiers|Green
+#####R=== Green Dragons ===
+
+#####GDescription
+Sickly greenish vapours rise from the scales and skin of these
+dragons. They have utter mastery of environmental poisons and
+air, and so are much healthier than other dragons, and do not
+succumb to constitution-draining attacks. They have ability to
+instantly forge poison darts from the upper layer of their scales,
+and they have access to the Air school of magic.
+
+#####GStat Modifiers
+Strength 0
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution +3
+Charisma 0
+Hit Dice +0 sides
+Exp Penalty +0%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Air 1.000 [0.600]
+
+#####GStarting Equipment
+A Green dragon character begins the game with:
+ Some rations
+ Some torches
+ A spellbook of Noxious Cloud
diff --git a/lib/mods/theme/help/rm_herm.txt b/lib/mods/theme/help/rm_herm.txt
new file mode 100644
index 00000000..4787b8ae
--- /dev/null
+++ b/lib/mods/theme/help/rm_herm.txt
@@ -0,0 +1,36 @@
+~~~~~01|Hermit
+~~~~~02|Race Modifiers|Hermit
+#####R=== Hermit Race ===
+
+#####GDescription
+Hermits live retired from the world. Spending long hours studying, they
+weaken their physical side while they strengthen their spiritual powers.
+Thus they get higher mana reserves but are much worse at physical combat.
+
+#####GStat Modifiers
+Strength -3
+Intelligence +1
+Wisdom +1
+Dexterity -3
+Constitution -3
+Charisma +1
+Hit Dice -3 sides
+Spell Points +20%
+Exp Penalty +20%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.500 [0.000]
+ Archery -0.500 [0.000]
+Sneakiness 0.400 [0.000]
+ Stealth 3.000 [0.000]
+ Disarming 0.500 [0.000]
+Magic
+ Magic-Device 1.000 [0.000]
+Spirituality 0.500 [0.000]
+
+#####GStarting Equipment
+A hermit begins the game with:
+ Some rations
+ Some torches
diff --git a/lib/mods/theme/help/rm_hurog.txt b/lib/mods/theme/help/rm_hurog.txt
new file mode 100644
index 00000000..10b6b922
--- /dev/null
+++ b/lib/mods/theme/help/rm_hurog.txt
@@ -0,0 +1,27 @@
+~~~~~01|Hurog
+~~~~~02|Race Modifiers|Hurog
+#####R=== Huroeg (Dog Demons) ===
+
+#####GDescription
+The Huroeg are dogs that have been corrupted by Melkor -
+Humanoid creatures with doglike snouts and elongated ears.
+One of the lowest form of demons, they have an uncanny
+sense of smell which increase with experience, so that
+these creatures learn to detect every living thing around
+them. They are very good at detecting treasure, and will
+become expert at searching for hidden passageways and traps.
+
+#####GStat Modifiers
+Strength -1
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution -1
+Charisma 0
+Hit Dice +0 sides
+Exp Penalty -10%
+
+#####GStarting Equipment
+A Hurog character begins the game with:
+ Some rations
+ Some torches \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_limrog.txt b/lib/mods/theme/help/rm_limrog.txt
new file mode 100644
index 00000000..bf43a87b
--- /dev/null
+++ b/lib/mods/theme/help/rm_limrog.txt
@@ -0,0 +1,33 @@
+~~~~~01|Limrog
+~~~~~02|Race Modifiers|Limrog
+#####R=== Limroeg (Fish Demons) ===
+
+#####GDescription
+Humanoid creatures with gill slits at the necks. They can
+survive underwater for extended periods of time, and with
+sufficient experience, they'll learn to breathe without any
+air at all. Somewhat weak and sickly, they are highly agile
+and masters of the Conveyance, Temporal, and Meta schools of
+magic. They also have several special abilities that enable
+them to disappear and reappear at will.
+
+#####GStat Modifiers
+Strength -2
+Intelligence +1
+Wisdom +1
+Dexterity +3
+Constitution -1
+Charisma -1
+Hit Dice +1 sides
+Exp Penalty +50%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Magic 0.000 [0.200]
+Conveyance 0.000 [0.500]
+Temporal 0.000 [0.500]
+Meta 0.000 [0.500]
+
+#####GStarting Equipment
+A Limrog character begins the game with:
+ Some rations
+ Some torches \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_lsoul.txt b/lib/mods/theme/help/rm_lsoul.txt
new file mode 100644
index 00000000..2f5e6e2c
--- /dev/null
+++ b/lib/mods/theme/help/rm_lsoul.txt
@@ -0,0 +1,26 @@
+~~~~~01|Lost Soul
+~~~~~02|Race Modifiers|Lost Soul
+#####R=== LostSoul ===
+
+#####GDescription
+
+#####RThis is a difficult modifier. Your character will almost always die quickly.
+#####RIt's probably best only to play it after you have some experience with normal
+#####Rcharacters.
+
+There are haunting whispers of souls that have come back from the Halls of
+Waiting, for purposes unknown. These are called Lost Souls, for it is presumed
+that their real body died off long ago, leaving only a soul to wander forever...
+or until killed again.
+Lost Souls start at level 98 of the Halls of Waiting. Very few ever make it out
+again. Those that do can continue as a fairly normal character, but with the
+advantage of any treasure and experience gained.
+
+#####GStat Modifiers
+No changes to stats.
+
+#####GStarting Equipment
+A Lost Soul starts the game with:
+ Some torches.
+ Over thirty scrolls of Identify.
+ Over twenty scrolls of Satisfy Hunger.
diff --git a/lib/mods/theme/help/rm_lygrog.txt b/lib/mods/theme/help/rm_lygrog.txt
new file mode 100644
index 00000000..80b6fa45
--- /dev/null
+++ b/lib/mods/theme/help/rm_lygrog.txt
@@ -0,0 +1,27 @@
+~~~~~01|Lygrog
+~~~~~02|Race Modifiers|Lygrog
+#####R=== Lygroeg (Snake Demons) ===
+
+#####GDescription
+These slithering snakelike demons lack many physical
+advantages of their humanoid cousins, but they have
+access to lost and forgotten realms of magic that
+enable them to overcome their physical handicaps, if
+they can survive long enough to reap the benefits of
+their experience, that is. As highly magical creatures,
+they are no good at anything else.
+
+#####GStat Modifiers
+Strength -3
+Intelligence +5
+Wisdom +5
+Dexterity +5
+Constitution -1
+Charisma -6
+Hit Dice +2 sides
+Exp Penalty +40%
+
+#####GStarting Equipment
+A Lygrog character begins the game with:
+ Some rations
+ Some torches \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_narrog.txt b/lib/mods/theme/help/rm_narrog.txt
new file mode 100644
index 00000000..2f0ed5f9
--- /dev/null
+++ b/lib/mods/theme/help/rm_narrog.txt
@@ -0,0 +1,34 @@
+~~~~~01|Narrog
+~~~~~02|Race Modifiers|Narrog
+#####R=== Narroeg (Rat Demons) ===
+
+#####GDescription
+These ratlike demons have fangs that drip with venom.
+Their quick, scurrying feet enable them to gain speed
+as they gain experience. They learn to use the winglike
+appendages on their slick, black backs in order to fly.
+They are somewhat weak and sickly (though resistant to
+poison), but sly, cunning and agile. Good with magic,
+they can forge poison darts to throw at their opponents,
+and can become masters of disguise and disappearance.
+
+#####GStat Modifiers
+Strength -1
+Intelligence +1
+Wisdom +1
+Dexterity +1
+Constitution -1
+Charisma -2
+Hit Dice +1 sides
+Exp Penalty +20%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Stealth 1.000 [0.500]
+Magic 0.000 [0.200]
+Conveyance 1.000 [0.300]
+
+#####GStarting Equipment
+A Narrog character begins the game with:
+ Some rations
+ Some torches
+ A spellbook of Phase Door \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_rawrog.txt b/lib/mods/theme/help/rm_rawrog.txt
new file mode 100644
index 00000000..830a8dc3
--- /dev/null
+++ b/lib/mods/theme/help/rm_rawrog.txt
@@ -0,0 +1,30 @@
+~~~~~01|Rawrog
+~~~~~02|Race Modifiers|Rawrog
+#####R=== Rawroeg (Lion Demons) ===
+
+#####GDescription
+Tall humanoids with glorious red-gold hair and decidedly
+catlike faces, the Rawroeg are corrupted lions. Strong,
+healthy, intelligent and wise, they fear very little and
+can emit roars that instill fear into the very souls of
+their enemies. They learn to resist the elements fairly
+well as they gain experience. They make good warriors.
+
+#####GStat Modifiers
+Strength +2
+Intelligence +1
+Wisdom +1
+Dexterity -1
+Constitution +2
+Charisma +1
+Hit Dice +2 sides
+Exp Penalty +30%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Combat 0.000 [0.100]
+Weaponmastery 0.000 [0.100]
+
+#####GStarting Equipment
+A Rawrog character begins the game with:
+ Some rations
+ Some torches \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_red.txt b/lib/mods/theme/help/rm_red.txt
new file mode 100644
index 00000000..ac2ef2fc
--- /dev/null
+++ b/lib/mods/theme/help/rm_red.txt
@@ -0,0 +1,30 @@
+~~~~~01|Red
+~~~~~02|Race Modifiers|Red
+#####R=== Red Dragons ===
+
+#####GDescription
+These dragons are utterly in command of the element of fire.
+Not only are they surrounded by a fiery blaze, but they learn
+to withstand the effects of fire entirely as they become more
+experienced. They are also able to draw upon their master
+element to become even stronger as they mature. They can
+breathe fire and they have access to the Fire school of magic.
+
+#####GStat Modifiers
+Strength +3
+Intelligence 0
+Wisdom 0
+Dexterity 0
+Constitution 0
+Charisma 0
+Hit Dice +0 sides
+Exp Penalty +0%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Fire 1.000 [0.600]
+
+#####GStarting Equipment
+A Red dragon character begins the game with:
+ Some rations
+ Some torches
+ A spellbook of Globe of Light
diff --git a/lib/mods/theme/help/rm_sarnrog.txt b/lib/mods/theme/help/rm_sarnrog.txt
new file mode 100644
index 00000000..4b34f0c0
--- /dev/null
+++ b/lib/mods/theme/help/rm_sarnrog.txt
@@ -0,0 +1,30 @@
+~~~~~01|Sarnrog
+~~~~~02|Race Modifiers|Sarnrog
+#####R=== Sarnroeg (Stone Demons ===
+
+#####GDescription
+Medium-sized winged humanoids that look like they are
+made of stone - they are Druedain that have been corrupted
+by Melkor. Though clumsy and dumb, they are strong and stout.
+They learn to resist the basic elements quite well, and they
+can sustain themselves by eating stones and rocks. They have
+the ability to throw boulders at their enemies, and are good
+at digging tunnels.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -1
+Wisdom -2
+Dexterity -2
+Constitution +2
+Charisma -1
+Hit Dice +2 sides
+Exp Penalty +20%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Boulder-throwing 1.000 [0.500]
+
+#####GStarting Equipment
+A Sarnrog character begins the game with:
+ Some rations
+ Some torches \ No newline at end of file
diff --git a/lib/mods/theme/help/rm_skel.txt b/lib/mods/theme/help/rm_skel.txt
new file mode 100644
index 00000000..aff6408d
--- /dev/null
+++ b/lib/mods/theme/help/rm_skel.txt
@@ -0,0 +1,40 @@
+~~~~~01|Skeleton
+~~~~~02|Race Modifiers|Skeleton
+#####R=== Skeletal Race ===
+
+#####GDescription
+As undead beings, skeletons need to worry very little about poison or
+attacks that can drain life. They do not really use eyes for perceiving
+things, and are thus not fooled by invisibility. Their bones are resistant
+to sharp shrapnels (not much to cut there), and they will quickly become
+resistant to cold. It is very hard for skeletons to eat food or drink potions.
+Although the magical effects of these will affect the skeleton even without
+entering the skeleton's (non-existent) belly, the potion / food itself will
+fall through the skeleton's jaws, giving no nutritional benefit.
+
+#####GStat Modifiers
+Strength 0
+Intelligence -2
+Wisdom -2
+Dexterity 0
+Constitution +1
+Charisma -4
+Hit Dice +0 sides
+Spell Points -30%
+Exp Penalty +45%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 0.800 [0.000]
+Sneakiness -0.100 [0.000]
+ Stealth -1.000 [0.000]
+ Disarming -0.500 [0.000]
+Magic
+ Magic-Device -0.500 [0.000]
+Spirituality 0.500 [0.000]
+
+#####GStarting Equipment
+A skeletal character begins the game with:
+ Some scrolls of satisfy hunger
+ Some torches
diff --git a/lib/mods/theme/help/rm_spec.txt b/lib/mods/theme/help/rm_spec.txt
new file mode 100644
index 00000000..01802465
--- /dev/null
+++ b/lib/mods/theme/help/rm_spec.txt
@@ -0,0 +1,44 @@
+~~~~~01|Spectre
+~~~~~02|Race Modifiers|Spectre
+#####R=== Spectral Race ===
+
+#####GDescription
+
+Another powerful undead creature, the spectre is a ghastly apparition,
+surrounded by an unearthly glow. They exist only partially on our
+plane of existence: half-corporeal, they can pass through walls, though
+this requires a sacrifice of some of their life-force. As a result
+they cannot rest whilst passing through a wall.
+
+As undead, they have a firm hold on their life force, can see invisible, and
+resist poison and cold. They also resist nether. Spectres make superb
+spellcasters, but their physical form is very weak. Like Zombies,
+Spectres gain almost no nutrition from ordinary food.
+
+#####GStat Modifiers
+Strength -5
+Intelligence +4
+Wisdom +4
+Dexterity +2
+Constitution -3
+Charisma -6
+Hit Dice -3 sides
+Spell Points +5%
+Exp Penalty +80%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery -0.500 [0.000]
+ Archery -0.200 [0.000]
+Sneakiness 0.200 [0.000]
+ Stealth 2.000 [0.000]
+ Disarming 0.200 [0.000]
+Magic
+ Magic-Device 0.800 [0.000]
+Spirituality 0.700 [0.000]
+
+#####GStarting Equipment
+A spectral character begins the game with:
+ Some scrolls of satisfy hunger
+ Some torches
diff --git a/lib/mods/theme/help/rm_vamp.txt b/lib/mods/theme/help/rm_vamp.txt
new file mode 100644
index 00000000..22ae6514
--- /dev/null
+++ b/lib/mods/theme/help/rm_vamp.txt
@@ -0,0 +1,32 @@
+~~~~~01|Vampire
+~~~~~02|Race Modifiers|Vampire
+#####R=== Vampire ===
+
+#####GDescription
+One of the mightier undead creatures, the vampire is an awe-inspiring
+sight. Yet this mighty creature has a serious weakness: the bright rays of
+sun are its bane, and it will need to flee the surface to the deep
+recesses of the earth until the sun finally sets. Darkness, on the other
+hand, only makes the vampire stronger. Being undead, the vampire has a firm
+hold on its life force, and resists nether attacks. The vampire also
+resists cold and poison based attacks. It is, however, susceptible to its
+perpetual hunger for fresh blood, which can only be satiated by sucking
+the blood from a nearby monster, which is the vampire's special power.
+
+It should be noted that the vampires are so sensitive to daylight that even
+certain artifact light items which are filled with daylight will hurt them
+if they try to wield the items. Fortunately, the vampires do not really
+need these items, since they radiate an aura of 'dark light' of their own.
+Light resistance will, in any case, protect the vampire from the adverse
+effects of sunlight.
+
+#####GStat Modifiers
+Strength +3
+Intelligence +2
+Wisdom -3
+Dexterity -2
+Constitution +1
+Charisma -4
+Hit Dice +1 side
+Spell Points +0%
+Exp penalty +100%
diff --git a/lib/mods/theme/help/rm_white.txt b/lib/mods/theme/help/rm_white.txt
new file mode 100644
index 00000000..00f31694
--- /dev/null
+++ b/lib/mods/theme/help/rm_white.txt
@@ -0,0 +1,32 @@
+~~~~~01|White
+~~~~~02|Race Modifiers|White
+#####R=== White Dragons ===
+
+#####GDescription
+White dragons are extremely intelligent and calculating,
+always able to keep a cool head. They can breathe cold
+and freeze time and space long enough to divine what the
+future and present have in store, and to find out the
+abilities of objects. Their intelligence will increase as
+they gain experience. Naturally resistant to cold, they
+will learn to withstand its effects entirely with time.
+They are especially susceptible to fire attacks, however.
+
+#####GStat Modifiers
+Strength 0
+Intelligence +3
+Wisdom 0
+Dexterity 0
+Constitution 0
+Charisma 0
+Hit Dice +0 sides
+Exp Penalty +0%
+
+#####GSkill Bonuses (supplementary to existing skills)
+Divination 1.000 [0.600]
+
+#####GStarting Equipment
+A White dragon character begins the game with:
+ Some rations
+ Some torches
+ A spellbook of Sense Monsters
diff --git a/lib/mods/theme/help/rm_zomb.txt b/lib/mods/theme/help/rm_zomb.txt
new file mode 100644
index 00000000..be89162b
--- /dev/null
+++ b/lib/mods/theme/help/rm_zomb.txt
@@ -0,0 +1,39 @@
+~~~~~01|Zombie
+~~~~~02|Race Modifiers|Zombie
+#####R=== Zombie Race ===
+
+#####GDescription
+Much like Skeletons, zombies too are undead horrors: they are resistant to
+life-draining attacks, they become resistant to cold-based attacks (actually
+earlier than skeletons), resist poison and can see invisible, while being still
+vulnerable to cuts (unlike skeletons). They also gain very little nutrition from
+the food of mortals. However, zombies are, as the name implies, practically
+mindless.
+
+#####GStat Modifiers
+Strength +2
+Intelligence -6
+Wisdom -6
+Dexterity +1
+Constitution +4
+Charisma -5
+Hit Dice +3 sides
+Spell Points -30%
+Exp Penalty +45%
+
+#####GRacial Skill Modifiers:
+#####BSkill Start Mod Skill Point Gains Mod
+Combat
+ Weaponmastery 0.500 [0.000]
+Sneakiness -0.100 [0.000]
+ Stealth -1.000 [0.000]
+ Disarming -0.200 [0.000]
+Magic
+ Magic-Device -0.200 [0.000]
+Spirituality 0.500 [0.000]
+
+#####GStarting Equipment
+A zombie character begins the game with:
+ Some scrolls of satisfy hunger
+ Some torches
+
diff --git a/lib/mods/theme/help/skills.txt b/lib/mods/theme/help/skills.txt
new file mode 100644
index 00000000..c4a02c06
--- /dev/null
+++ b/lib/mods/theme/help/skills.txt
@@ -0,0 +1,539 @@
+|||||oy
+~~~~~55|Skills
+#####R=== ToME Skills System ===
+One of the big differences between standard "Vanilla" Angband and ToME is the
+implementation of a skill system where the player can choose what skills she
+will improve as her character progresses. As such, many abilities such as
+spell casting, fighting and trap disarming *do not* increase automatically -
+the player must choose to use skill points to improve those abilities. This
+gives the player the chance to tailor a character to suit their playing style
+with a lot more flexibility than has existed with a fixed progression system
+in the past. However, not all types of characters are able to gain skills to
+the same degree; while a fighter can learn some magic, he's unlikely to become
+as good at it as a mage can. So the number of skill points required to raise
+a skill to the next level varies according to the starting "type" of character.
+
+You can also spend skill points in "one-off purchase" *****ability.txt*0[Abilities].
+~~~~~56|Skills|Screen
+#####GThe Skills Menu
+Each time you gain a level of experience, you receive 6 skill points to spread
+around as you wish. To use these skill points, you need to access the skills
+menu ("G" for both keysets). This opens up a long list of abilities that can
+be improved. The menu may look something like this:
+
+&&&&&w w w w w w w w w w w w w w w w w w w w w w w w w w w w wTwowMwEw wSwkwiwlwlwsw wSwcwrwewewnw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&BEBnBtBeBrW WtWoW WdWeWvWeWlWoWpW WaW WbWrWaWnWcWhW,W BuBpW/BdBoBwBnW WtWoW WmWoWvWeW,W BrBiBgBhBtW/BlBeBfBtW WtWoW WmWoWdWiWfWyW,W B?W WfWoWrW WhWeWlWpw w w w
+&&&&&BSBkBiBlBlB BpBoBiBnBtBsB BlBeBfBtB:B B6w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&yGyeynyeyryayly yaybyiylyiytyyy ytyoy yfyiygyhyty yaynydy ytyoy ypysyeyuydyoy-yiydy yayrymyoyrysy yaynydy ywyeyaypyoynysy.w w w w w w w w w w w w w w w w w w w
+&&&&&yIyty yaylysyoy yaylylyoywysy ytyoy yuysyey yhyeyayvyiyeyry yayrymyoyuyrysy ywyiytyhyoyuyty ypyeynyaylytyiyeysw w w w w w w w w w w w w w w w w w w w w w w w w
+&&&&&G[G-G]GCGoGmGbGaGtw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w G0G2G.G0G0G0G G[G0G.G8G0G0G]w w w w w w
+&&&&&w w w w w w-w wWwewawpwownwmwawswtwewrwyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w8w5w0w]w w w w w w
+&&&&&w w w w w w w w o o.o oSowooorodo-omoaosotoeoroyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o4o0o0o]w w w w w w
+&&&&&w w w w w w w w o o.o oAoxoeo-omoaosotoeoroyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o4o0o0o]w w w w w w
+&&&&&w w w w w w w w o o.o oHoaofotoeodo-omoaosotoeoroyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o4o0o0o]w w w w w w
+&&&&&w w w w w w w w o o.o oPoooloeoaoromo-omoaosotoeoroyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o4o0o0o]w w w w w w
+&&&&&w w w w w w.w wAwrwcwhwewrwyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w6w0w0w]w w w w w w
+&&&&&w w w w o o.o oAonotoiomoaogoiocw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o5o5o0o]w w w w w w
+&&&&&w w+w wSwnwewawkwiwnwewswsw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w9w0w0w]w w w w w w
+&&&&&w w+w wMwawgwiwcw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w3w0w0w]w w w w w w
+&&&&&w w-w wSwpwiwrwiwtwuwawlwiwtwyw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0w1w.w0w0w0w w[w0w.w4w0w0w]w w w w w w
+&&&&&w w w w o o.o oPoroaoyoeorw w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o5o0o0o]w w w w w w
+&&&&&o o.o oMooonosotoeoro-oloooroew w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w o0o0o.o0o0o0o o[o0o.o5o0o0o]w w w w w w
+
+Now, looking at this screen, there are several things to be aware of. The
+first line lets you know if you have any available skill points to spend, and
+how many there are. Following that are 2 description lines for the currently
+selected skill - in this case they are describing the "Combat" skill. When
+looking at the list of skills, there are a few different colours used - the
+light green coloured skill (which also has its starting character in square
+brackets []) is the currently selected one - Combat in the example above.
+Skills that you cannot learn are omitted from the list. Skills that you are
+capable of learning, but as yet have not, are coloured in orange, while skills
+of which you have some knowledge are shown in white.
+
+At the end of each skill is a pair of numbers. The first represents your
+current level of knowledge in the skill, and the second how much an advance
+in this knowledge investing one skill point in this skill would produce. So,
+in the above example, if the player invested one skill point in their Combat
+skill, the skill would increase from 02.000 to 02.800.
+
+In addition, investing in some skills may raise your knowledge in others.
+This improvement is based on the modifier in the related class (the one which
+gets the free points). For example, a skill point put into Weaponmastery
+raises Combat by 0.5 skill points. This is actually multiplied by the skill
+modifier that your character has in the Combat skill. For example, a
+Swordmaster investing a skill point into Weaponmastery would have his Combat
+skill raised by 0.5 * [0.900] while a Runecrafter would have his Combat
+skill raised by 0.5 * [0.200].
+
+As well as this, skills are grouped together in similar types. Looking under
+the Combat skill, there are subtypes of Weaponmastery, Archery and Antimagic.
+An increase of one of these subskills may also increase the main skill by a
+small amount. You can tell which skills have subskills by the + (or -) in front
+of their name. The + indicates that there are more skills within this category.
+To open a skill category up, move the cursor up/down until the skill category
+is green, then hit the "Enter" key. Likewise, the - indicates that the category
+is already opened, and selecting this and hitting the "Enter" key will close it
+up again. Skills which don't have usable subskills start with a ".".
+
+To spend points on a skill (including skill categories), use the left/right
+arrow (right arrow or "6" adds one skill point, left arrow or "4" removes
+one). Spending points on a sub-skill will also marginally improve the parent
+skill (or skill category). When you've finished spending skill points (and any
+unspent points *will* be saved), hit the "Esc" key to finish. This will give
+a confirmation prompt to check that you really do want to spend your points as
+you've assigned them. Saying 'y' saves the changes and allows you to use or
+apply your new skills :).
+
+All skills have a maximum level of 50, and as long as you can learn a skill,
+and have enough skill points to pump into it, it is theoretically possible to
+get it to level 50 no matter what your race, class or how you learned it.
+
+Each skill affects your character differently. It may be worth getting one or
+more of your characters skills to 50, but it may not be worth investing [[[[[Bany]
+skill points in some other skills. As general and personal advice, which may
+not work for you, I'd say concentrate on a few skills, and leave the others
+empty. Just because you [[[[[Bcan] learn a skill, it doesn't mean you have to.
+It often pays to have a plan ("I'm going to make this assassin the
+stealthiest, most able-dodging, backstabber around. I'm not going to bother
+with trapping or thieving ability") which you can stick to for the whole game.
+~~~~~57|Skills|List of skills
+#####GThe Skills Themselves
+So you want to know what each of the skills do so that you can decide how to
+spend you're hard-earned points, huh? Well, each skill affects different
+abilities, and not all of them are intuitive - but they don't take all that
+long to learn :).
+If you don't find this informative enough, and would like more detailed spoilers
+on what each skill does, try [[[[[ghttp://www.killerbunnies.org/angband/skill-220.html]
+for some third party help!
+The skills are:
+
+ *****skills.txt*27[Air] *****skills.txt*49[Alchemy] *****skills.txt*50[Antimagic] *****skills.txt*08[Archery]
+ *****skills.txt*05[Axe-mastery] *****skills.txt*18[Backstab] *****skills.txt*13[Barehand-combat] *****skills.txt*61[Bearform-combat]
+ *****skills.txt*12[Boomerang-mastery] *****skills.txt*58[Boulder-throwing] *****skills.txt*10[Bow-mastery] *****skills.txt*01[Combat]
+ *****skills.txt*30[Conveyance] *****skills.txt*44[Corpse-preservation]*****skills.txt*04[Critical-hits] *****skills.txt*11[Crossbow-mastery]
+ *****skills.txt*52[Demonology] *****skills.txt*16[Disarming] *****skills.txt*31[Divination] *****skills.txt*20[Dodging]
+ *****skills.txt*28[Earth] *****skills.txt*25[Fire] *****skills.txt*60[Geomancy] *****skills.txt*06[Hafted-mastery]
+ *****skills.txt*21[Magic] *****skills.txt*54[Magic-device] *****skills.txt*24[Mana] *****skills.txt*29[Meta]
+ *****skills.txt*47[Mimicry] *****skills.txt*33[Mind] *****skills.txt*41[Mindcraft] *****skills.txt*42[Monster-lore]
+ *****skills.txt*59[Music] *****skills.txt*34[Nature] *****skills.txt*35[Necromancy] *****skills.txt*07[Polearm-mastery]
+ *****skills.txt*45[Possession] *****skills.txt*39[Prayer] *****skills.txt*36[Runecraft] *****skills.txt*09[Sling-mastery]
+ *****skills.txt*14[Sneakiness] *****skills.txt*22[Spell-power] *****skills.txt*38[Spirituality] *****skills.txt*23[Sorcery]
+ *****skills.txt*19[Stealing] *****skills.txt*15[Stealth] *****skills.txt*53[Stunning-blows] *****skills.txt*43[Summoning]
+ *****skills.txt*03[Sword-mastery] *****skills.txt*46[Symbiosis] *****skills.txt*32[Temporal] *****skills.txt*37[Thaumaturgy]
+ *****skills.txt*48[Udun] *****skills.txt*26[Water] *****skills.txt*02[Weaponmastery]
+
+
+~~~~~01|Skills|Combat
+[[[[[BCombat]
+The combat skill is used to determine the maximum combined weight of armour
+you can wear before you become encumbered by it. It also affects your general
+fighting ability, although not to as great an extent as Weaponmastery, and
+determines the speed and strength of pseudo-id of weapons and armour.
+
+Investing in the combat skill? You might be interested in the
+*****ability.txt*05[Extra Max Blow(1)] and *****ability.txt*06[(2)] abilities.
+
+Sub-skills of Combat are Weaponmastery, Archery, Barehand-combat,
+Boulder-throwing and Anti-magic.
+~~~~~02|Skills|Weaponmastery
+[[[[[BWeaponmastery]
+This skill is a sub-skill of the Combat skill. It affects your general
+ability to use melee weapons of all sorts. Spending 1 skill point on
+Weaponmastery adds 0.5 bonus skill points to Combat.
+
+Investing in the weaponmastery skill? You might be interested in the
+*****ability.txt*02[Spread Blows] ability.
+
+Sub-skills of Weaponmastery are Sword-mastery, Axe-mastery, Hafted-mastery
+and Polearm-mastery.
+~~~~~03|Skills|Sword-mastery
+[[[[[BSword-mastery]
+This skill is a sub-skill of the Weaponmastery skill. It affects your ability
+to use bladed weapons (e.g. daggers, swords). Spending 1 skill point on your
+Sword-mastery skill adds 0.25 bonus skill points to your Weaponmastery skill
+and adds 0.07 bonus skill points to your Combat skill.
+
+Critical-hits is a sub-skill of Sword-mastery.
+~~~~~04|Skills|Critical-Hits
+[[[[[BCritical-hits]
+This skill is a sub-skill of the Sword-mastery skill. It affects your ability
+to deal critical hits to monsters using a bladed weapon that weighs less than 5
+pounds. Spending one skill point on your Critical-hits skill also increases
+your Sword-mastery skill by 0.05 skill points.
+~~~~~05|Skills|Axe-mastery
+[[[[[BAxe-mastery]
+This skill is a sub-skill of the Weaponmastery skill. It affects your ability
+to use axes. Spending 1 skill point on your Axe-mastery skill adds 0.25 bonus
+skill points to your Weaponmastery skill and adds 0.07 bonus skill points to
+your Combat skill.
+~~~~~06|Skills|Hafted-mastery
+[[[[[BHafted-mastery]
+This skill is a sub-skill of the Weaponmastery skill. It affects your ability
+to use hafted weapons (e.g. whips & maces). Spending 1 skill point on your
+Hafted-mastery skill adds 0.25 bonus skill points to your Weaponmastery skill
+and adds 0.07 bonus skill points to your Combat skill.
+
+Stunning-blows is a sub-skill of Hafted-mastery.
+~~~~~53|Skills|Stunning-blows
+[[[[[BStunning-blows]
+This skill is a sub-skill of the Hafted-mastery skill. It affects your ability
+to stun opponents when doing critical hits with a hafted weapon that weighs
+more than 5 lbs. Spending one skill point on your Stunning-blows skill also
+increases your Hafted-mastery skill by 0.05 skill points.
+~~~~~07|Skills|Polearm-mastery
+[[[[[BPolearm-mastery]
+This skill is a sub-skill of the Weaponmastery skill. It affects your ability
+to use polearms (e.g. pikes & halberds). Spending 1 skill point on your
+Polearm-mastery skill adds 0.25 bonus skill points to your Weaponmastery skill
+and adds 0.07 bonus skill points to your Combat skill.
+
+Investing in the Polearm-mastery skill? You might be interested in the
+*****ability.txt*10[Far reaching attack] ability.
+~~~~~08|Skills|Archery
+[[[[[BArchery]
+This skill is a sub-skill of the Combat skill. It affects your general
+ability to use ranged weapons of all sorts. Spending one skill point on your
+Archery skill adds 0.5 bonus skill points to your Combat skill.
+
+Investing in the Archery skill? You might be interested in the
+*****ability.txt*07[Ammo creation] ability.
+
+Sub-skills of Archery include Sling-mastery, Bow-mastery, Crossbow-mastery
+and Boomerang-mastery.
+~~~~~09|Skills|Sling-mastery
+[[[[[BSling-mastery]
+This skill is a sub-skill of the Archery skill. It affects your ability to
+use Slings. Spending 1 skill point on your Sling-mastery skill adds 0.25
+bonus skill points to your Archery skill and 0.07 bonus skill points to your
+Combat skill.
+~~~~~10|Skills|Bow-mastery
+[[[[[BBow-mastery]
+This skill is a sub-skill of the Archery skill. It affects your ability to
+use both Long and Short Bows. Spending 1 skill point on your Bow-mastery
+skill adds 0.25 bonus skill points to your Archery skill and 0.07 bonus skill
+points to your Combat skill.
+~~~~~11|Skills|Crossbow-mastery
+[[[[[BCrossbow-mastery]
+This skill is a sub-skill of the Archery skill. It affects your ability
+to use both Heavy and Light Crossbows. Spending 1 skill point on your
+Crossbow-mastery skill adds 0.25 bonus skill points to your Archery skill
+and 0.07 bonus skill points to your Combat skill.
+~~~~~12|Skills|Boomerang-mastery
+[[[[[BBoomerang-mastery]
+This skill is a sub-skill of the Archery skill. It affects your ability to
+use all boomerangs. Spending 1 skill point on your Boomerang-mastery skill
+adds 0.25 bonus skill points to your Archery skill and 0.07 bonus skill
+points to your Combat skill.
+~~~~~13|Skills|Barehand-combat
+[[[[[BBarehand-combat]
+This skill is a sub-skill of the Combat skill. It affects your general ability
+to fight using martial arts. In order to utilise it, you must be capable of
+using a weapon in the first place, but choose not to. Spending 1 skill point
+on your Barehand-combat skill adds 0.5 bonus skill points to your Combat skill.
+Barehand-combat fighters develop stronger and faster attacks, and also gain
+speed bonuses, as they advance in skill. However, they cannot use this skill
+whilst wearing heavy armour.
+~~~~~61|Skills|Bearform-combat
+[[[[[BBearform-combat]
+This skill is a sub-skill of the Combat skill. It affects your ability to fight
+while in the form of a bear. In order to utilise it, you must be in bearform.
+*****r_beorn.txt*0[Beornings] are the adventurers most likely to use this form of skill.
+~~~~~58|Skills|Boulder-throwing
+[[[[[BBoulder-throwing]
+This skill is a sub-skill of the Combat skill. It affects your ability to
+throw boulders and make them from granite walls. Spending 1 skill point on
+your Boulder-throwing skill adds 0.4 bonus skill points to your Combat skill.
+~~~~~50|Skills|Antimagic
+[[[[[BAntimagic]
+This skill is a sub-skill of the Combat skill. It generates a field around
+the character within which magic cannot work. As such, it can be very useful
+to prevent monsters from casting offensive spells against you or from
+teleporting away from you just before you kill them - but it will also prevent
+you from casting spells, or teleporting away when they've almost killed you!
+It also inhibits your ability to do magic, affecting *all* the magic and
+spirituality sub-skills.
+
+This skill does not affect your ability to use scrolls and potions, but other
+items that require [Self]Magic-Device are affected. At higher levels you gain
+the ability to detect traps and disrupt all teleportation.
+~~~~~14|Skills|Sneakiness
+[[[[[BSneakiness]
+The sneakiness skill affects your searching and perception abilities.
+
+Sub-skills of Sneakiness include Stealth, Disarming, Trapping, Backstab,
+Stealing and Dodging.
+~~~~~15|Skills|Stealth
+[[[[[BStealth]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to move around the dungeon quietly so that you are not noticed by its
+inhabitants. Spending 1 skill point on your Stealth skill adds 0.15 bonus
+skill points to your Sneakiness skill.
+~~~~~16|Skills|Disarming
+[[[[[BDisarming]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to safely disarm any traps you find. Spending 1 skill point on your Disarming
+skill adds 0.1 bonus skill points to your Sneakiness skill.
+
+Investing in the Disarming skill? You might be interested in the *****ability.txt*11[Trapping]
+ability.
+~~~~~18|Skills|Backstab
+[[[[[BBackstab]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to sneak up on monsters and do extra damage to them before they wake up.
+It also affects monsters who have turned to flee from you. Spending 1 skill
+point on your Backstab skill adds 0.05 bonus skill points to your Sneakiness
+skill.
+~~~~~19|Skills|Stealing
+[[[[[BStealing]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to steal items from monsters and shops. Be careful when stealing from shops;
+if you're caught, the shopkeeper will close his doors to you and not open
+them again. I have heard that shop keepers do not stay in one shop forever
+though. Spending 1 skill point on your Stealing skill adds 0.15 bonus skill
+points to your Sneakiness skill.
+~~~~~20|Skills|Dodging
+[[[[[BDodging]
+This skill is a sub-skill of the Sneakiness skill. It affects your ability
+to dodge out of the way of monster blows and bolts. The less armour you wear
+and the less you carry, the greater your chance of dodging a blow. Rings and
+amulets do not affect your chance to dodge, but full armour will almost render
+the effect of the skill obsolete. Spending 1 skill point on your Dodging skill
+adds 0.1 bonus skill points to your Sneakiness skill.
+~~~~~21|Skills|Magic
+[[[[[BMagic]
+The Magic skill affects your general use of magic items, the amount of mana
+you can handle, and in general your ability to do magic. It can also affect
+the strength of wands and staffs.
+
+Investing in the Magic skill? You might be interested in the *****ability.txt*04[Perfect Casting]
+ability.
+
+Sub-skills include: Magic-device, Spell-power, Sorcery, Mana, Fire, Water, Air,
+Earth, Meta, Conveyance, Divination, Temporal, Mind, Nature, Udun, Demonology,
+Necromancy, Runecraft, Thaumaturgy, and Alchemy.
+~~~~~54|Skills|Magic-device
+[[[[[BMagic-device]
+This skill is a sub-skill of the Magic skill. It eases the use of magical
+devices, such as wands, staves, and rods, and boosts the casting level of spells
+stored in a wand or a staff. *****magic.txt*02[More on this]. It also helps pseudo-id of magic
+objects. Spending 1 skill point on your Magic-device skill adds 0.07 bonus skill
+points to your Magic skill.
+~~~~~22|Skills|Spell-power
+[[[[[BSpell-power]
+This skill is a sub-skill of the Magic skill. It boosts the casting level of
+most spells you are capable of casting. For example, if you have level one in
+the mana school, you could cast "Manathrust". For every 2.5 skill levels of
+Spell-power, Manathrust becomes more powerful, adding +1 casting level to the
+spell. Note that this is not exactly the same as certain magic items which
+boost spell power. Spending 1 skill point on your Spell-power skill adds 0.2
+bonus skill points to your Magic skill.
+
+[[[[[BThis skill only affects the 11 primary schools] (Mana, Earth, Air, Fire,
+Water, Meta, Mind, Temporal, Conveyance, Divination and Nature), as well as
+Geomancy and the spells granted by the Gods.
+~~~~~23|Skills|Sorcery
+[[[[[BSorcery]
+This skill is a sub-skill of the Magic skill. It allows you to access any
+spell in the 11 schools up to the sorcery skill level. For example, if you
+have a sorcery skill of 1, you could cast "Manathrust", which is a level 1
+mana school spell; and "Phase Door", which is a level 1 conveyance school
+spell. Spending 1 skill point on your Sorcery skill adds 0.2 bonus skill
+points to your Magic skill.
+
+[[[[[BThis skill only affects the 11 primary schools] (Mana, Earth, Air, Fire,
+Water, Meta, Mind, Temporal, Conveyance, Divination and Nature).
+
+However, handling that much magic is hazardous to your health, and as such
+reduces both your hit points and your fighting ability. Any ability in sorcery
+affects your Weaponmastery, Archery, Barehand-combat and gives a negative
+percentage modifier to your total hit points, equal to the level of your
+sorcery skill (i.e. if sorcery is 12.500, hit points get modified by -12.5%).
+~~~~~24|Skills|Mana
+[[[[[BMana]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_mana.txt*0[mana] school, and as it increases so does the casting level of
+spells already attained in the school. For example, if you have level 1 in
+the mana school, you could cast "Manathrust" at a casting level of 1. For
+every skill level you add to Mana, Manathrust will become more powerful,
+adding 1 casting level to the spell. Spending 1 skill point on your Mana
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~60|Skills|Geomancy
+[[[[[BGeomancy]
+This skill is a subskill of the Magic skill. It gives access to spells
+within the *****m_geoman.txt*0[Geomancy] school, and as it increases so does the casting level of
+spells already attained in the school. Most spells from this school rely
+on the Fire, Water, Air and Earth skills as well. Spending 1 skill point
+on your Geomancy skill adds 0.45 bonus skill points to your Fire, Water,
+Air and Earth skills.
+~~~~~25|Skills|Fire
+[[[[[BFire]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_fire.txt*0[fire] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Fire
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~26|Skills|Water
+[[[[[BWater]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_water.txt*0[water] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Water
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~27|Skills|Air
+[[[[[BAir]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_air.txt*0[air] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Air
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~28|Skills|Earth
+[[[[[BEarth]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_earth.txt*0[earth] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Earth
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~29|Skills|Meta
+[[[[[BMeta]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_meta.txt*0[meta] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Meta
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~30|Skills|Conveyance
+[[[[[BConveyance]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_convey.txt*0[conveyance] school, and as it increases so does the casting level
+of spells already attained in the school. Spending 1 skill point on your
+Conveyance skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~31|Skills|Divination
+[[[[[BDivination]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_divin.txt*0[divination] school, and as it increases so does the casting level
+of spells already attained in the school. Spending 1 skill point on your
+Divination skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~32|Skills|Temporal
+[[[[[BTemporal]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_tempo.txt*0[temporal] school, and as it increases so does the casting level
+of spells already attained in the school. Spending 1 skill point on your
+Temporal skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~33|Skills|Mind
+[[[[[BMind]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_mind.txt*0[mind] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Mind
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~34|Skills|Nature
+[[[[[BNature]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_nature.txt*0[nature] school, and as it increases so does the casting level of
+spells already attained in the school. Spending 1 skill point on your Nature
+skill adds 0.1 bonus skill points to your Magic skill.
+
+Investing in the Nature skill? You might be interested in the *****ability.txt*03[Tree Walking]
+ability.
+~~~~~48|Skills|Udun
+[[[[[BUdun]
+This skill is a sub-skill of the Magic skill. It gives access to spells
+within the *****m_udun.txt*0[Udun] school, and is available only to worshippers of Melkor.
+As it increases so does the casting level of spells already attained in the
+school. Spending 1 skill point on your Udun skill adds 0.1 bonus skill
+points to your Magic skill.
+~~~~~52|Skills|Demonology
+[[[[[BDemonology]
+This skill is a sub-skill of the Magic skill. *****m_demono.txt*0[Demonology] gives access to spells
+contained within special Demon-blades, -shields and -horns (helms), and as it
+increases so does the casting level of spells already attained in the school.
+This skill is available only to Demonologists, or those sufficiently
+corrupted with demon-like powers. Spending 1 skill point on your Demonology
+skill adds 0.1 bonus skill points to your Magic skill.
+~~~~~35|Skills|Necromancy
+[[[[[BNecromancy]
+This skill is a sub-skill of the Magic skill. It grants access to *****m_necrom.txt*0[necromancy]
+spells. This is the base skill of the Necromancer class. Spending 1 skill
+point on your Necromancy skill adds 0.04 bonus skill points to your Magic skill.
+
+Investing in the Necromancy skill? You might be interested in the
+*****ability.txt*08[Touch of Death] and *****ability.txt*12[Undead Form] abilities.
+~~~~~36|Skills|Runecraft
+[[[[[BRunecraft]
+This skill is a sub-skill of the Magic skill. This is the base skill of the
+Runecrafter class. Spending 1 skill point on your Runecraft skill adds 0.12
+bonus skill points to your Magic skill.
+~~~~~37|Skills|Thaumaturgy
+[[[[[BThaumaturgy]
+This skill is a sub-skill of the Magic skill. Each level of *****m_thaum.txt*0[thaumaturgy] gives
+a few random attack spells that can be cast without the use of spell books of
+any sort. However, once learned these spells do not gain in levels as the
+thaumaturgy skill or the spell-power skills are increased. Spending 1 skill
+point on your Thaumaturgy skill adds 0.06 bonus skill points to your Magic
+skill.
+~~~~~49|Skills|Alchemy
+[[[[[BAlchemy]
+The Alchemy skill affects your ability to extract and use essences to create
+magical items.
+
+Investing in the Alchemy skill? You might be interested in the *****ability.txt*09[Artifact Creation]
+ability.
+~~~~~38|Skills|Spirituality
+[[[[[BSpirituality]
+The spirituality skill influences things which have a "helping hand" from the
+Gods, like your saving throw, and the general spirituality skills.
+
+Sub-skills of Spirituality are Prayer, Mindcraft and Music.
+~~~~~39|Skills|Prayer
+[[[[[BPrayer]
+This skill is a sub-skill of the Spirituality skill. It affects what level of
+your *****gods.txt*0[God's] special magic you can access (and what levels of the additional
+schools that each God also provides). Spending 1 skill point on your Prayer
+skill adds 0.1 bonus skill points to your Spirituality skill and 0.1 bonus
+skill points to your Magic skill.
+~~~~~41|Skills|Mindcraft
+[[[[[BMindcraft]
+This skill is a sub-skill of the Spirituality skill. It affects what level of
+*****m_mindcr.txt*0[Mindcrafter powers] you can access, which is done without books and is
+available under the "m" menu. Spending 1 skill point on your Mindcraft skill
+adds 0.1 bonus skill points to your Spirituality skill and 0.1 bonus skill
+points to your Magic skill.
+~~~~~59|Skills|Music
+[[[[[BMusic]
+This skill is a sub-skill of the Spirituality skill. It affects what level of
+*****m_music.txt*0[Musical songs] you can access through instruments. This power
+is available under the "m" menu. Spending 1 skill point on your Music skill
+adds 0.1 bonus skill points to your Spirituality skill and 0.1 bonus skill
+points to your Magic skill.
+~~~~~42|Skills|Monster-lore
+[[[[[BMonster-lore]
+The monster-lore skill affects your general ability at the monster related
+skills. It determines how much experience you will gain if your *****dungeon.txt*18[pets] kill a
+monster, and how many companions you can have. At skill level 12, it allows
+you to turn a pet into a loyal companion.
+
+Sub-skills of Monster-lore are Summoning, Corpse-preservation, Possession,
+Symbiosis, and Mimicry.
+~~~~~43|Skills|Summoning
+[[[[[BSummoning]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to create "totems" and use them to summon monsters to your aid. Spending 1
+skill point on your Summoning skill adds 0.1 bonus skill points to your
+Monster-lore skill.
+~~~~~44|Skills|Corpse-preservation
+[[[[[BCorpse-preservation]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to kill monsters without destroying their bodies, so the corpses will be
+available to use. Spending 1 skill point on your Corpse-preservation skill
+adds 0.1 bonus skill points to your Monster-lore skill.
+~~~~~45|Skills|Possession
+[[[[[BPossession]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to possess a dead monster's corpse. Spending 1 skill point on your Possession
+skill adds 0.1 bonus skill points to your Monster-lore skill.
+~~~~~46|Skills|Symbiosis
+[[[[[BSymbiosis]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to go into symbiosis with monsters that cannot move, and to cast *****m_symbio.txt*0[Symbiotic]
+spells. Spending 1 skill point on your Symbiosis skill adds 0.1 bonus skill
+points to your Monster-lore skill.
+~~~~~47|Skills|Mimicry
+[[[[[BMimicry]
+This skill is a sub-skill of the Monster-lore skill. It affects your ability
+to use cloaks of mimicry to change form and to cast *****m_mimic.txt*0[Mimicry spells].
+Spending 1 skill point on your Mimicry skill adds 0.1 bonus skill points to
+your Monster-lore skill.
diff --git a/lib/mods/theme/help/spoil_faq.txt b/lib/mods/theme/help/spoil_faq.txt
new file mode 100644
index 00000000..fd3a0f42
--- /dev/null
+++ b/lib/mods/theme/help/spoil_faq.txt
@@ -0,0 +1,63 @@
+|||||oy
+~~~~~01|Help|Spoiled FAQ
+~~~~~02|FAQ - contains spoilers
+#####R ToME Spoiler FAQ
+#####R Updated for version 2.3.x
+
+#####G------------------------------------------------------------------------------
+
+This page contains significant spoilers. Don't browse it unless you want some
+parts of the game ruined, but don't expect the spoilers to spoil you completely!
+
+~~~~~07|Spoilers|Lothlorien Poisoned water quest
+#####G------------------------------------------------------------------------------
+#####GQ: I'm trying to find the Poisoned water quest at Lothlorien, but cannot
+#####G find the quest entrance!
+
+A: This quest is located in the wilderness. To the west of Lothlorien are 4
+water squares in an upside down L shape. One of these squares will contain the
+quest. (Viewed from the Wilderness map). There is no yellow > sign, so don't
+bother looking for one.
+~~~~~20|Spoilers|God Quest - directions
+~~~~~23|Gods|Quest - Spoilers
+#####G------------------------------------------------------------------------------
+#####GQ: I've been given directions to a temple by my God but can't find the
+#####G temple anywhere!
+
+A: It [[[[[BIS] there. However, your god's idea of compass directions that are
+not directly on the 4 main axes are probably slightly less acurate than your
+idea. In other words, if your god says it is South-East, s/he means it is
+somewhere in the quadrant that is between the south and east axes.
+~~~~~21|Spoilers|God Quest - relic
+#####G------------------------------------------------------------------------------
+#####GQ: Where is the relic by god was talking about? I've looked in the lost
+#####G temple and can't find it anywhere!
+
+A: It [[[[[BIS] there. However, when your god told you to look for it VERY
+carefully, s/he meant it. Regardless of your game settings, the relic will only
+be created once in the temple, at a random place. If you have searched the
+whole temple once over, and not located it, then you have missed it, and it is
+lost forever. Each temple has 5 dungeon levels, and the relic might be on
+any of these 5 levels.
+~~~~~22|Spoilers|God Quest - how many?
+#####G------------------------------------------------------------------------------
+#####GQ: Apparently my god has lost another piece of a relic and wants me to go
+#####G find it again. How many of these are there?
+
+A: You can receive up to seven god quests, with the final piece yielding an
+extra reward. However you will only receive extra quests if you have
+sucessfully completed all the previous ones.
+~~~~~23|Spoilers|Secret Valley
+#####G------------------------------------------------------------------------------
+#####GQ: What's this Secret Valley place in the northern part of the wilderness?
+
+This is a stay-over from regular ToME, where that valley is the location of
+Gondolin. In Theme, Gondolin is elsewhere, and the Secret Valley is simply a
+cosmetic change to avoid confusion.
+
+~~~~~24|Spoilers|Erebor
+#####G------------------------------------------------------------------------------
+#####GQ: Why can't I get past the first level of Erebor?
+
+Think back to "The Hobbit". What did Bilbo and his friends use to enter the Lonely
+Mountain? Locating the town of Dale and asking the mayor might prove profitable...
diff --git a/lib/mods/theme/help/spoiler.hlp b/lib/mods/theme/help/spoiler.hlp
new file mode 100644
index 00000000..bc229852
--- /dev/null
+++ b/lib/mods/theme/help/spoiler.hlp
@@ -0,0 +1,18 @@
+|||||oy
+~~~~~01|Spoilers
+#####RWelcome to the Angband Online Spoiler System.
+#####R=============================================
+
+Please choose one of the following online spoiler files:
+
+ *****/acorspoil.txt*0[(a) Corruptions]
+ *****/bdunspoil.txt*0[(b) Dungeons]
+ *****/cessences.txt*0[(c) Essence Spoiler]
+ *****/dinscrip.txt*0[(d) Floor Inscriptions]
+ *****/eluckspoi.txt*0[(e) Luck]
+ *****/ffatespoi.txt*0[(f) Fates]
+ *****/gwishing.txt*0[(g) Wishing]
+ *****/hspoil_faq.txt*0[(h) Spoiled FAQ]
+
+
+ *****/zhelp.hlp*0[(z) Main Help menu]
diff --git a/lib/mods/theme/help/tome_faq.txt b/lib/mods/theme/help/tome_faq.txt
new file mode 100644
index 00000000..756ce639
--- /dev/null
+++ b/lib/mods/theme/help/tome_faq.txt
@@ -0,0 +1,381 @@
+|||||oy
+~~~~~01|Help|FAQ - Spoiler free
+~~~~~02|FAQ - Spoiler free
+#####R ToME FAQ
+#####R Updated for version 2.3.x
+
+#####G------------------------------------------------------------------------------
+
+#####R=== Differences Between ToME and Vanilla Angband ===
+
+The first main difference a new player to ToME will need to be aware of is
+that it has implemented a skills based system. Instead of the adventurer
+automatically improving in his abilities as he becomes more experienced,
+he gets 6 skill points to spend on his skills, allowing the player to
+customise what type of character she will play. See the *****skills.txt*0[skills] help file
+for details.
+
+A second major difference is that the main dungeon from Angband has been split
+into 4 "dungeons", each of which covers a different portion of the Angband
+dungeon's levels. Each of these 4 dungeons is located either in or near one of
+the four main towns so that the character can keep stocked up on supplies. As
+the adventurer advances in ability, he will need to travel overland to the next
+town/dungeon, which is most easily carried out using the wilderness map ("<"
+from town level). As well as these main places, there are a number of
+additional dungeons which the character may or may not choose to enter, which
+can have guardians, contain specific artifacts, or just be used as an
+alternative place to enjoy gaining experience. Note that not all of the places
+are actually "dungeons" - some are caves, forests, etc.
+
+ToME also offers the player the ability to undertake a series of quests.
+Random quests can be specified during start-up, and involve rescuing a princess
+from a group of monsters within the dungeon, or recovering a lost sword from
+(you guessed it...) a group of monsters. If you do not wish to play with
+random quests, simply specify "0" when asked how many you want during character
+generation. Other "fixed" quests are also available from the towns (whether
+random quests are enabled or not), usually given by the town leaders upon the
+request of the adventurer. It is not required for any adventurer to undertake
+the fixed quests, but they can result in some nice rewards.
+
+The third main difference between Vanilla Angband and ToME is the difference
+in character classes and races, as well as a very different magic system.
+See the help files on *****birth.txt*0[Creating a character] and the *****magic.txt*0[magic] system.
+Class abilities (generally referred to as skills) are generally accessed
+through the 'm' command. Most racial abilities, or corruptions, are accessed
+through the "U" command.
+
+To balance the expansion in things like player abilities and customisation, the
+list of both monsters and items has also been expanded. Be warned that items
+which were by default safe in Vanilla are not necessarily safe in ToME (a
+certain early artifact comes to mind here...), and picking on defenceless
+creatures is frowned upon....
+
+Happy adventuring!
+~~~~~03|Altars
+~~~~~04|Gods|Altars
+#####G------------------------------------------------------------------------------
+#####GQ: How do I use the altars (the 'O's) I see in the dungeon?
+
+A: ToME introduces a new system of gods.
+
+You can find altars only in Lothlorien and in the dungeon.
+The ones on the surface are dedicated to the good Valar (Eru, Manwe, Tulkas and
+Yavanna), while altars found in the dungeons are "sacred" for Melkor.
+You can use altars to convert yourself to the service of a specific Vala by
+using the "O" command while standing on them. Beware, this works only if you
+don't already have a God, and as a new convert, your God won't like you that
+much. Melkor also uses his altars as a mean of collecting sacrifices from his
+devotees; this function is likewise accomplished by the "O" command.
+
+Read *****gods.txt*0[gods.txt] for more information about Gods.
+~~~~~05|Fountains
+#####G------------------------------------------------------------------------------
+#####GQ: How do I use the fountains (the '_'s) I see in the dungeon?
+
+A: Fountains in ToME act like potions, but can only be identified by
+drinking from them. Each one can hold between 3 and 12 doses of the potion.
+Quaffing from a fountain can be done by using the 'H' command (in the standard
+keyset) and answering 'Q' at the prompt.
+
+You can also fill empty bottles at a fountain (enabling you to identify the
+potion and hence the type of fountain) by using the 'H' command and answering
+'F' at the prompt. The game will then ask you to choose bottles and how many
+bottles you want to fill. You can find empty bottles on the dungeon and
+drinking pints of fine ale/wine will give you emtpy bottles; if you are
+trained in Alchemy, you can reuse bottles after quaffing potions as well.
+
+#####G------------------------------------------------------------------------------
+#####GQ: I got killed by a Great Wyrm of Power at 50'!!! What happened?
+
+A: You killed a defenceless creature. I told you that it was frowned upon!
+~~~~~18|Artifacts that activate but I cannot wear or wield
+~~~~~17|Strange items
+#####G------------------------------------------------------------------------------
+#####GQ: I've found some strange items like a Red Tome, a Voodoo Doll, ...
+#####G What can I do with them?
+
+A: You've found an unusual artifact that cannot be wielded, but always
+has a sometimes-useful activation. It will not be listed in the known
+artifact list and its activation is chosen randomly. It would probably be
+wise for this kind of artifact be *identified* before use, as the
+activation can be something very nasty....
+
+To activate it, use the normal Activation command, but when prompted for which
+item to activate change to the backpack instead of wielded equipment.
+~~~~~10|Essences
+~~~~~11|Runes
+#####G------------------------------------------------------------------------------
+#####GQ: I keep coming across "essences" and "runes". What are they?
+
+Essences are the *****c_alchem.txt*0[Alchemist's] friend, and you can only use them if you
+have access to the *****skills.txt*49[Alchemy] skill.
+Runes are used to cast and store spells of varying types. *****c_runecr.txt*0[Runecrafters] are the
+class who are most proficient at using these. You can only use them if you
+have access to the *****skills.txt*36[Runecrafting] skill.
+~~~~~12|Homes
+#####G------------------------------------------------------------------------------
+#####GQ: Where can I store all my equipment? Theere's not enough room in my
+#####Ginventory? And what happened to the thieves quest in Bree?
+
+Nor is there supposed to be enough room in your backpack. It's not
+bottomless you know! If you go talk to the Mayor in Bree, he might let you know
+about a slight problem that there's been in town. If you can clear up the
+problem, you may find yourself with somewhere extra to keep your stuff. I've
+heard tell that there are similiar problems in other towns in Middle-Earth.
+~~~~~13|Fates|Prophets
+#####G------------------------------------------------------------------------------
+#####GQ: I spent 500 gp at the Prophet but she said nothing. Is that a bug ?
+
+A: No. Nor is it because Prophets are swindlers. She said nothing
+because you have no fate at this moment. You gain fates while playing, and
+will be warned by a message such as "You feel your fate has changed". A fate
+can be useless like finding a broken skull at level 30, deadly like dying at
+level 56, or really useful like never dying by the hand of a mortal.
+~~~~~14|Mathilde
+#####G------------------------------------------------------------------------------
+#####GQ: Who is Mathilde, the Science Student whom I see every so often in the
+#####G town?
+
+A: Most of the time she laughs and giggles. She has no loot on her, and
+she's never done you any harm. So leave her be - even if she should
+happen to shout "Drop dead, creep!"
+~~~~~15|Wrists hurting
+#####G------------------------------------------------------------------------------
+#####GQ: My wrists hurt a lot when playing the game. Should I take precautions?
+
+A: Yes, you should. Repetitive strain on wrists (which results from a badly
+placed keyboard, for example) can lead to serious injury of the wrist ligaments
+called Carpal Tunnel Syndrome. If you feel your wrists are strained, here is
+an exercise posted by Jason Maskell in rec.games.roguelike.angband which might
+help:
+
+Hold your arms out horizontally, make a fist, and then point the fist towards
+the floor, as much as you can. This will stretch one side's tendons. Hold for
+5 seconds. Then make a flat hand and hold it level with your arm, hold for 5
+seconds. Now splay your fingers and attempt to make your hand point toward the
+ceiling (this one is hard, so don't push it too much). You should feel your
+tendons stretching. Repeat this a few times. Take frequent breaks and do this
+if it starts to hurt a little bit. I was sliding very fast towards CTS and this
+corrected it.
+~~~~~16|Void jumpgates
+#####G------------------------------------------------------------------------------
+#####GQ: When I stand on void jumpgates I'm never teleported away, what's wrong?
+
+A: Void jumpgates are not automatic. You must press '>' while standing
+on one to activate it.
+
+#####G------------------------------------------------------------------------------
+#####GQ: When it panic saves it reloads an old savefile !!
+
+A: Now the panic saves use a different file to save, savefile.pnc.
+This file will be loaded first, if present, when the game is started.
+If it loads successfully, save the game immediately. Otherwise, delete
+the panic save, and your old (non-panic) savefile should be safe.
+
+~~~~~08|Monsters|They are talking to me!
+#####G------------------------------------------------------------------------------
+#####GQ: Farmer Maggot / Melinda Proudfoot keep shouting at me, and I cannot
+#####G kill them.
+
+A: Both these people need to talk to you about something. Have a chat with them
+(check the file *****command.txt*96[command.txt] for how to chat).
+~~~~~09|Sentient weapons
+#####G------------------------------------------------------------------------------
+#####GQ: I have found a sentient weapon, it says it has access to the realms
+#####G of Earth and Fire. How do I use these realms?
+
+A: You don't actually 'use' them as such. If a weapon is sentient it means it
+gains experience itself as it delivers killing blows. As it levels up it has
+the chance to gain pluses to hit and to damage, and also powers from any of the
+available 'realms'. For instance, the realm of fire gives the chance to gain
+resistance to fire, or fire branding on your weapon. The realm of earth has a
+chance to confer extra attacks or the power of causing earthquakes and so on.
+~~~~~24|Fumblefingers quests
+~~~~~25|Abbreviations|FF
+#####G------------------------------------------------------------------------------
+#####GQ: What or who is Fumblefingers? How do I get his quests?
+
+A: FF is short for Fumblefingers, the name that some players give to the
+adventurer who keeps having his sword stolen by monsters and asking you to
+find it for him. So named because he often seems to lose it to molds and
+other creatures you wouldn't expect to be able to pickpocket! During birth
+you'll be asked to specify a number of random quests you would like to
+attempt to complete. Some of these quests will take the form of princess
+quests, others will be fumble-finger quests. If you complete the task he
+sets you sucessfully, he'll offer to join you as a companion. If you do not
+want him to join you, he'll offer to teach you some new skills. Quite handy.
+~~~~~26|Random quests are not working.
+#####G------------------------------------------------------------------------------
+#####GQ: Where has the option gone to set the number of random quests?
+#####G Why aren't there any after the Barrow-downs?
+
+A: Turning on either of the options "Allow permanent dungeon levels" or "Always
+create special rooms" will disable random quests. Random quests can only be
+found in the four main dungeons (Barrowdowns, Mirkwood, Mordor and Angband).
+~~~~~27|Weird display
+~~~~~28|Floor tiles displaying incorrectly
+#####G------------------------------------------------------------------------------
+#####GQ: How do I get the dots to show up on floor tiles in Windows XP? I've tried
+#####G changing the tile character to the brighter dot. Toggling 'Bizarre Display'
+#####G mode helped with the trailing @@@@@@@@@@@@@@@@@ problem. Any suggestions? I
+#####G gave up a long time ago and play with graphics tiles now, but I'd like to be
+#####G able to fix this.
+
+A: In the file ./lib/pref/font_win.prf, either remove or comment out with # the
+lines that end in /0x1F, e.g.
+# open floor
+# F:1:0x01/0x1F
+Another possibility is to manually change the symbols used with the '%'
+command, but the previous solution is faster.
+~~~~~29|Dark grey things are difficult to see
+#####G------------------------------------------------------------------------------
+#####GQ: Many things are written in a dark grey color which is next to impossible to
+#####G read against a black background. Also, some monsters appear in dark grey and
+#####G are easy to miss! What can I do to fix this?
+
+A: Fix the gamma control of your display. If your display software does not
+include such a tool, access the 'Interact with Colors' screen in ToME via
+shift+7, type '4', and modify the gamma correction there.
+~~~~~30|Game 'balance'
+#####G------------------------------------------------------------------------------
+#####GQ: Why don't you make X class less powerful or Y class more powerful?
+
+A: In ToME the player determines how hard the game is. Classes, races, and
+subraces are neither meant nor desired to be equal in game difficulty. So no,
+we won't make Axemasters more powerful just to "balance them out", nor will we
+make Sorcerors weaker.
+~~~~~31|I keep dying!
+#####G------------------------------------------------------------------------------
+#####GQ: Why do I always start in a terribly difficult, very deep dungeon instead of
+#####G a town? Is the game really this hard?
+
+A: You have chosen a "Lost soul" character subrace. That's where Lost souls
+start. They tend to die very quickly, so don't choose them if you're new to
+ToME.
+~~~~~32|Invisible character
+#####G------------------------------------------------------------------------------
+#####GQ: My character is invisible. That's great, but how do I know where she is if
+#####G I can't see her?!
+
+A: You could seek for a way to see invisible things.
+You could also go to game options:
+ 1. Type = (game options)
+ 2. Type 4 (efficiency options)
+ 3. Arrow down to 'hilite the player with the cursor'
+ 4. Type y to toggle the option to 'yes'
+~~~~~33|Objects|Piles
+#####G------------------------------------------------------------------------------
+#####GQ: I'm standing on a pile of items. How do I see what's in the pile without
+#####G picking it all up, moving it, or destroying it all?
+A:
+ 1. Stand on the pile in question
+ 2. Type shift + I (inspect)
+ 3. Type - (examine items on floor)
+ 4. Type * (expand list of items on floor)
+ 5. (as needed) Type letter associated with item to look at it more closely.
+
+#####G------------------------------------------------------------------------------
+#####GQ: If I'm standing on a pile of items. Is there a command to see if there is a
+#####G stairway or jumpgate beneath the pile?
+
+A: Stairs/jumpgates obscured by clutter do still function. You are advised to
+take a good hard look at your surroundings before creating lots of dungeon
+clutter.
+ 1. You can pick up, move, or eliminate the pile.
+ 2. Press l (look), then select the square you wish to inquire about. Press
+<enter>; it will scroll through everything on the ground, and eventually it
+ends with "It is in a Void Jumpgate", or whatever.
+~~~~~34|Character choice is too confusing
+~~~~~36|Beginner strategy
+#####G------------------------------------------------------------------------------
+#####GQ: What is a good starting character?
+
+A: Make sure to read the parchment you start the game with!
+
+If you're new to ToME, understand that your characters are going to die a lot.
+Be prepared for that. In fact, take advantage of it by using the various
+characters you run to experiment and learn the game's various facets.
+
+Try a warrior. A Dunadan Swordmaster is an excellent combination of race and
+class.
+
+Try a priest. A Rohan Knight Paladin gives you some magic to go with strong
+combat, but your terrible stealth will give you a tougher time in some respects.
+
+Try an archer. A Wood-elf Archer will have fewer hitpoints than you're used to,
+but lets you use excellent ranged combat instead. Also note how your higher
+stealth wakes up fewer monsters, letting you fight them more on your own terms.
+
+Try a mage. A Dark-elf Mage lets you keep using weapons, while getting a taste
+of the various magic schools. You have even fewer hitpoints, though, so beware.
+
+Try another mage. A Hobbit Sorceror is a fun character, but the hitpoint
+penalties make you need to be very careful. You get high-powered magic, though,
+to more than make up for it.
+
+I would just add that for those who get frustrated in the early levels and want
+to run a more powerful character that I think the three easiest combinations
+are probably the Zombie Rohan Knight Unbeliever, the Thunderlord (or Vampire
+Half-Ogre) Sorceror, and the High-Elf (or Deathmold if you can figure it out)
+Possessor. Also, you might want to try a priest of Eru or Tulkas. Most of these
+have low stealth, but should be pretty easy to play up to around level 30, and
+they offer an attractive range of experiences for the new player.
+~~~~~35|I STILL keep dying!
+#####G------------------------------------------------------------------------------
+#####GQ: I'm getting killed a lot. Can you recommend some starting options to
+#####G make my chances a little better?
+
+A: Realize that getting killed a lot is to be expected. Having said that, try
+this. At character creation:
+ 1. Turn off "always generate very unusual rooms".
+ 2. Turn off joke monsters.
+ 3. Turn off "always make small levels".
+ 4. Regarding the number of random quests: See the Q/A below.
+ 5. Do not choose a Lost Soul character.
+
+Later, set these options:
+ 1. Turn on "expand the power of the look command".
+ 2. Turn on "allow some monsters to carry light".
+ 3. Turn on "map remembers all perma-lit grids".
+ 4. Turn on "map remembers all torch-lit grids".
+ 5. Turn off "monsters learn from their mistakes".
+ 6. Turn off "monsters exploit player weaknesses".
+ 7. Turn on "monsters behave stupidly".
+ 8. Turn off "allow unusually small dungeon levels".
+ 9. Turn off "allow empty 'arena' levels".
+
+~~~~~36|Random quests strategy
+#####G------------------------------------------------------------------------------
+#####GQ: How many random quests should I choose?
+
+A: One big question a beginner is faced with is: How many (random) optional
+quests to choose?
+
+I think this is another area where the beginner should mix it up. The early
+items from princesses are a great benefit to beginners, but coming to rely on
+those can be a problem when it comes time to enter deep dungeons and the real
+nasty quests begin.
+
+Also high counts, especially 98 quests, can be very frustrating for a beginner
+when it puts an especially difficult quest on dungeon level 1 or 2.
+
+~~~~~37|Anti-magic Amulets and the Anti-magic shell
+#####G------------------------------------------------------------------------------
+#####GQ: Are Amulets of Anti-magic and the Anti-magic skill related?
+
+A: No. The Anti-magic shell of the Amulet of Anti-magic has nothing to do with
+the Anti-magic field given off by the skill and Dark Swords.
+
+~~~~~38|Beornings and Bearform-combat
+#####G------------------------------------------------------------------------------
+#####GQ: My Beorning character doesn't have Bearform-combat! Why?
+
+A: You cannot put points into Bearform-combat unless you are transformed
+into a bear. Use the racial power ('U' in the original keyset, 'O' in
+roguelike) to transform first.
+
+#####G------------------------------------------------------------------------------
+#####GQ: The game is so slow...
+
+A: Yeah :(
+Try disabling the various options marked as (slow)
diff --git a/lib/mods/theme/help/version.txt b/lib/mods/theme/help/version.txt
new file mode 100644
index 00000000..501be7f6
--- /dev/null
+++ b/lib/mods/theme/help/version.txt
@@ -0,0 +1,354 @@
+|||||oy
+~~~~~01|Development history
+*****version.txt*01[The origins of ToME]
+*****version.txt*02[Zangband History and Information]
+*****version.txt*03[Brief Version History (of standard Angband)]
+*****version.txt*04[A Posting from the Original Author (of Moria)]
+*****version.txt*05[Previous Versions (outdated)]
+
+
+#####R====== ToME Brief History =======
+
+When Zangband came to its 2.2.0 version I (DarkGod) was an Angband winner and
+I had been a C programmer for a long time, so I decided to take the sources
+and to try to code my own variant. At this time I was reading the Pern
+novels from Anne McCaffrey and I found them *VERY* good, so I decided to
+include some elements of them into my variant from which it takes the name,
+PernAngband.
+
+One hard thing to decide was on which Angband to base it. Although I didn't
+like Zangband because of the Zelazny universe, which I found to be not very
+Tolkienish, I chose it because of all the good things it had (especially
+the race powers that I wasn't able to code at the time). So I removed
+much of the Zelazny stuff and replaced it with Tolkien and Pernish stuff.
+And so the history of PernAngband began with the version 2.9.9a.
+
+Now, in PernAngband 5.x.x, PernAngband is a thriving Angband variant
+with plenty of unique features.
+
+Then came some legal problems with Anne McCaffrey estate and ubisoft and
+I had to remove the Pern stuff, so the game got renamed to ToME,
+the Troubles of Middle Earth.
+~~~~~02
+#####R=== Zangband History and Information ===
+
+The seeds of Zangband lie in an obsolete and long ago vanished PC variant
+(somewhat misleadingly) dubbed Angband--. The variant was written by a
+hopeless Angband addict (previously Moria veteran and winner) who got
+bored with the standard monsters and wanted to introduce some new
+monsters. Angband-- was based on the PC Angband 1.31 sources, and
+it was set in Roger Zelazny's 'Amber' universe.
+
+Later this individual got a better computer and learned to code, and
+produced the PC Zangband, and most Angband-- monsters survived into
+PC Zangband 1.0. PC Zangband 1.0 was the first PC Angband to introduce
+(simple, font-based) graphics, which were also used in the graphical
+PC Angband 1.40.
+
+Yet this individual was still not cured of his addiction... his almost
+as strong addiction to the Civilization style fantasy strategy game
+'Master of Magic' inspired him to write a new magic system. The current
+version of Zangband (2.*) incorporates this magic system, as well as
+the best features from Angband-- and PC Zangband 1.0. It is based on
+the Angband 2.8.1 sources (by Ben Harrison), and is therefore portable
+to other systems (unlike the earlier versions which were for DOS-PC's
+only).
+
+Incidentally, this person (me, Topi Ylinen) also thought that the
+standard Angband monsters were too easy, which led him to introduce
+such monsters as Death swords, Cyberdemons and Great Wyrms of Power...
+
+Special thanks -- The current version of Zangband might not have come into
+existence without the significant help from these excellent Angband
+programmers:
+
+ Ben Harrison, for obvious reasons.
+
+ Greg Wooledge, who pointed out a bug in the dos compiler,
+ which was preventing my progress with the first 2.* version
+ of Zangband and for various patches.
+
+ Julian Lighton, who must have sent me more ideas, patches, and
+ bug reports than all the others together.
+
+ Robert Ruehlmann, whose nice new main-dos.c enables SVGA
+ graphics and even windows in MS-DOS.
+
+ Paul Sexton, who is responsible for about 50% of the new code
+ in 2.1.0.
+
+ Heino Vander Sanden, who created the quest-code and
+ Dean Anderson, whose patch showed me the quickest way to
+ implement the quests.
+
+ Adam Bolt, who created the new ZAngband tiles.
+
+ Scott Bigham, for the S-Lang patch.
+
+ Jeff Duprey for the new mutations.
+
+ Leigh Silas Hanrihan for the new items.
+
+ Benny S. Hofmann, Aram Harrow, Greg Harvey, Keldon Jones,
+ Graham Murray, Remco Gerlich, Tim Baker and many others
+ for bugreports, patches, bugfixes, and ideas.
+
+
+ZAngband 2.1.0c was Topi's last version, he has got a job and
+doesn't have enough time anymore to continue work on ZAngband.
+He asked for a new maintainer and I was the one to take over the task.
+May I introduce myself, my name is Robert Ruehlmann, I'm the creator
+of the graphical Angband versions for DOS and webmaster of
+"Thangorodrim - The Angband Page" ("http://www.thangorodrim.net").
+~~~~~03
+#####R=== Brief Version History (of standard Angband) ===
+
+First came "VMS Moria", by Robert Alan Koeneke (1985).
+
+Then came "Umoria" (Unix Moria), by James E. Wilson (1989).
+
+In 1990, Alex Cutler and Andy Astrand, with the help of other students
+at the University of Warwick, created Angband 1.0, based on the existing
+code for Umoria 5.2.1. They wanted to expand the game, keeping or even
+strengthening the grounding in Tolkien lore, while adding more monsters
+and items, including unique monsters and artifact items, plus activation,
+pseudo-sensing, level feelings, and special dungeon rooms.
+
+Over time, Sean Marsh, Geoff Hill, Charles Teague, and others, worked on
+the source, releasing a copy known as "Angband 2.4.frog_knows" at some
+point, which ran only on Unix systems, but which was ported by various
+people to various other systems.
+
+Then Charles Swiger (cs4w+@andrew.cmu.edu) attempted to clean up the mess,
+resulting in several versions, starting sometime around November, 1993, with
+Angband 2.5.1 (more or less) and leading up to Angband 2.6.2 in late 1994.
+Several people ported (the primarily Unix/NeXT centered) Angband 2.6.1 to
+other platforms, including Keith Randall, who made a Macintosh port that
+added support for color usage. Some of the changes during this period were
+based on suggestions from the "net", PC Angband 1.40, UMoria 5.5, and some
+of the Angband "variations", such as FAngband.
+
+Finally, I (Ben Harrison) took over in late 1994 when Charles Swiger left.
+Initially my intention was simply to clean up what had become, after ten
+years, a rather unholy mess, but the deeper I delved into the code, the
+more it became apparent that drastic changes were needed, so, starting
+with MacAngband 2.6.1, I began a more or less total rewrite, resulting,
+eventually, in Angband 2.7.0, released around January first, 1995.
+
+Angband 2.7.0 was a very clean (but very buggy) rewrite that, among other
+things, allowed extremely simple porting to multiple platforms, starting
+with Unix and Macintosh, and by the time most of the bugs were cleaned up,
+in Angband 2.7.2, including X11, and various IBM machines. Angband 2.7.4
+was released to the "ftp.cis.ksu.edu" site, and quickly gained acceptance,
+perhaps helped by the OS2 and Windows and Amiga and Linux ports. Angband
+2.7.5 and 2.7.6 added important capabilities such as macros and user pref
+files, and continued to clean up the source. Angband 2.7.8 was designed
+to supply another "stable" version that we can all give to our friends,
+with new "help files" and "spoiler files" for the "online help", plus a
+variety of minor tweaks and some new features. Angband 2.7.9 optimized
+a few things, and tweaked a few other things, and cleaned up a few other
+things, and introduced a few minor semantic changes.
+
+It is very hard to pin down, along the way from 2.6.2 to 2.7.0, and thence
+to 2.7.8, exactly what was added exactly when. Most of these steps involved
+so many changes as to make "diff files" not very useful, since often the diff
+files were as long as the code itself. Most of the changes, with the notable
+exception of the creation of the new "main-xxx.c" files for the various new
+platforms, and a few other exceptions generally noted in the source, were
+written by myself, either spontaneously, or, more commonly, as the result of
+a suggestion or comment by an Angband player. So if you have any problems
+with anything that you do not recognize from older versions, you can blame
+them on me. And if you like the new features and such, you can send me a
+brief little "thank you" email (to benh@phial.com) or something...
+
+The Official Angband Home Page ("http://www.phial.com/")
+was created along with Angband 2.7.9 to serve as an up to date description
+of any bugs found in various versions, and to list all of the people whose
+email addresses I kept having to look up.
+
+~~~~~04
+#####R=== A Posting from the Original Author ===
+
+From: koeneke@ionet.net (Robert Alan Koeneke)
+Newsgroups: rec.games.roguelike.angband,rec.games.roguelike.moria
+Subject: Early history of Moria
+Date: Wed, 21 Feb 1996 04:20:51 GMT
+
+I had some email show up asking about the origin of Moria, and its
+relation to Rogue. So I thought I would just post some text on the
+early days of Moria.
+
+First of all, yes, I really am the Robert Koeneke who wrote the first
+Moria. I had a lot of mail accussing me of pulling their leg and
+such. I just recently connected to Internet (yes, I work for a
+company in the dark ages where Internet is concerned) and
+was real surprised to find Moria in the news groups... Angband was an
+even bigger surprise, since I have never seen it. I probably spoke to
+its originator though... I have given permission to lots of people
+through the years to enhance, modify, or whatever as long as they
+freely distributed the results. I have always been a proponent of
+sharing games, not selling them.
+
+Anyway...
+
+Around 1980 or 81 I was enrolled in engineering courses at the
+University of Oklahoma. The engineering lab ran on a PDP 1170 under
+an early version of UNIX. I was always good at computers, so it was
+natural for me to get to know the system administrators. They invited
+me one night to stay and play some games, an early startrek game, The
+Colossal Cave Adventure (later just 'Adventure'), and late one night,
+a new dungeon game called 'Rogue'.
+
+So yes, I was exposed to Rogue before Moria was even a gleam in my
+eye. In fact, Rogue was directly responsible for millions of hours of
+play time wasted on Moria and its descendents...
+
+Soon after playing Rogue (and man, was I HOOKED), I got a job in a
+different department as a student assistant in computers. I worked on
+one of the early VAX 11/780's running VMS, and no games were available
+for it at that time. The engineering lab got a real geek of an
+administrator who thought the only purpose of a computer was WORK!
+Imagine... Soooo, no more games, and no more rogue!
+
+This was intolerable! So I decided to write my own rogue game, Moria
+Beta 1.0. I had three languages available on my VMS system. Fortran
+IV, PASCAL V1.?, and BASIC. Since most of the game was string
+manipulation, I wrote the first attempt at Moria in VMS BASIC, and it
+looked a LOT like Rogue, at least what I could remember of it. Then I
+began getting ideas of how to improve it, how it should work
+differently, and I pretty much didn't touch it for about a year.
+
+Around 1983, two things happened that caused Moria to be born in its
+recognizable form. I was engaged to be married, and the only cure for
+THAT is to work so hard you can't think about it; and I was enrolled
+for fall to take an operating systems class in PASCAL.
+
+So, I investigated the new version of VMS PASCAL and found out it had
+a new feature. Variable length strings! Wow...
+
+That summer I finished Moria 1.0 in VMS PASCAL. I learned more about
+data structures, optimization, and just plain programming that summer
+then in all of my years in school. I soon drew a crowd of devoted
+Moria players... All at OU.
+
+I asked Jimmey Todd, a good friend of mine, to write a better
+character generator for the game, and so the skills and history were
+born. Jimmey helped out on many of the functions in the game as well.
+This would have been about Moria 2.0
+
+In the following two years, I listened a lot to my players and kept
+making enhancements to the game to fix problems, to challenge them,
+and to keep them going. If anyone managed to win, I immediately found
+out how, and 'enhanced' the game to make it harder. I once vowed it
+was 'unbeatable', and a week later a friend of mine beat it! His
+character, 'Iggy', was placed into the game as 'The Evil Iggy', and
+immortalized... And of course, I went in and plugged up the trick he
+used to win...
+
+Around 1985 I started sending out source to other universities. Just
+before a OU / Texas football clash, I was asked to send a copy to the
+Univeristy of Texas... I couldn't resist... I modified it so that
+the begger on the town level was 'An OU football fan' and they moved
+at maximum rate. They also multiplied at maximum rate... So the
+first step you took and woke one up, it crossed the floor increasing
+to hundreds of them and pounded you into oblivion... I soon received
+a call and provided instructions on how to 'de-enhance' the game!
+
+Around 1986 - 87 I released Moria 4.7, my last official release. I
+was working on a Moria 5.0 when I left OU to go to work for American
+Airlines (and yes, I still work there). Moria 5.0 was a complete
+rewrite, and contained many neat enhancements, features, you name it.
+It had water, streams, lakes, pools, with water monsters. It had
+'mysterious orbs' which could be carried like torches for light but
+also gave off magical aura's (like protection from fire, or aggrivate
+monster...). It had new weapons and treasures... I left it with the
+student assistants at OU to be finished, but I guess it soon died on
+the vine. As far as I know, that source was lost...
+
+I gave permission to anyone who asked to work on the game. Several
+people asked if they could convert it to 'C', and I said fine as long
+as a complete credit history was maintained, and that it could NEVER
+be sold, only given. So I guess one or more of them succeeded in
+their efforts to rewrite it in 'C'.
+
+I have since received thousands of letters from all over the world
+from players telling about their exploits, and from administrators
+cursing the day I was born... I received mail from behind the iron
+curtain (while it was still standing) talking about the game on VAX's
+(which supposedly couldn't be there due to export laws). I used to
+have a map with pins for every letter I received, but I gave up on
+that!
+
+I am very happy to learn my creation keeps on going... I plan to
+download it and Angband and play them... Maybe something has been
+added that will surprise me! That would be nice... I never got to
+play Moria and be surprised...
+
+Robert Alan Koeneke
+koeneke@ionet.net
+
+~~~~~05
+#####R=== Previous Versions (outdated) ===
+
+
+ VMS Moria Version 4.8
+Version 0.1 : 03/25/83
+Version 1.0 : 05/01/84
+Version 2.0 : 07/10/84
+Version 3.0 : 11/20/84
+Version 4.0 : 01/20/85
+
+Modules :
+ V1.0 Dungeon Generator - RAK
+ Character Generator - RAK & JWT
+ Moria Module - RAK
+ Miscellaneous - RAK & JWT
+ V2.0 Town Level & Misc - RAK
+ V3.0 Internal Help & Misc - RAK
+ V4.0 Source Release Version - RAK
+
+Robert Alan Koeneke Jimmey Wayne Todd Jr.
+Student/University of Oklahoma Student/University of Oklahoma
+
+
+ Umoria Version 5.2 (formerly UNIX Moria)
+Version 4.83 : 5/14/87
+Version 4.85 : 10/26/87
+Version 4.87 : 5/27/88
+Version 5.0 : 11/2/89
+Version 5.2 : 5/9/90
+
+James E. Wilson, U.C. Berkeley
+ wilson@ernie.Berkeley.EDU
+ ...!ucbvax!ucbernie!wilson
+
+Other contributors:
+D. G. Kneller - MS-DOS Moria port
+Christopher J. Stuart - recall, options, inventory, and running code
+Curtis McCauley - Macintosh Moria port
+Stephen A. Jacobs - Atari ST Moria port
+William Setzer - object naming code
+David J. Grabiner - numerous bug reports, and consistency checking
+Dan Bernstein - UNIX hangup signal fix, many bug fixes
+and many others...
+
+
+
+
+Copyright (c) 1989 James E. Wilson, Robert A. Keoneke
+ This software may be copied and distributed for educational, research, and
+ not for profit purposes provided that this copyright and statement are
+ included in all such copies.
+
+Umoria Version 5.2, patch level 1
+
+Angband Version 2.0 Alex Cutler, Andy Astrand, Sean Marsh, Geoff Hill,
+ Charles Teague.
+
+Angband Version 2.4 : 5/09/93
+
+Angband Version 2.5 : 12/05/93 Charles Swiger.
+
+Angband Version 2.6 : 9/04/94
+
+Angband Version 2.7 : 1/1/95 Ben Harrison
diff --git a/lib/mods/theme/help/whattome.txt b/lib/mods/theme/help/whattome.txt
new file mode 100644
index 00000000..43ebb2e1
--- /dev/null
+++ b/lib/mods/theme/help/whattome.txt
@@ -0,0 +1,30 @@
+|||||oy
+~~~~~01|ToME - a General Description
+#####R /----------------------------------------\
+#####R < What is ToME? >
+#####R \----------------------------------------/
+
+Tales of Middle Earth (ToME) is a fantasy adventure game, based on the works
+of Tolkien. Focusing on game-play rather than fancy graphics that get boring
+after a week, ToME will keep you playing for years.
+
+Explore dozens of different dungeons including hundreds of randomly generated
+levels filled with multitudes of different items and treasures. Fight off
+hundreds of monsters and uniques from the stories in a complex fighting system.
+Gain experience and learn skills; choose from the dozens of races and classes
+available to the player; cast spells from simple teleportation spells to
+advanced spells that can wipe out a whole army at once. It's the only game where
+you can burn spell books by trudging in lava (unless you have gained immunity
+from some armour), dry up rivers to cast mighty spells, strike at orcs with
+blades attuned to slay them specifically, summon armies from a simple totem,
+and even enter a symbiotic relationship with a mold!
+
+Explore dungeons, gain power, and save Middle-earth!
+
+The player will begin his adventure on the town level where he may acquire
+supplies, weapons, armour, and magical devices by bartering with various shop
+owners. After preparing for his adventure, the player can descend into the
+dungeon near Bree where fantastic adventures await his coming!
+
+Make sure you read the parchment you are given when you start the game, and
+read the in-game documentation.
diff --git a/lib/mods/theme/help/wishing.txt b/lib/mods/theme/help/wishing.txt
new file mode 100644
index 00000000..d16f5ae9
--- /dev/null
+++ b/lib/mods/theme/help/wishing.txt
@@ -0,0 +1,24 @@
+~~~~~01|Spoilers|Wishing
+#####R=== Wishes ===
+
+Some items in ToME will grant the user the ability to "wish" for an
+object that they are interested in. As such, these are generally very rare
+and very powerful objects.
+
+#####GRules for Wishes
+Due to the powerful nature of wishes, there are some rules that govern
+what is able to be wished for. These rules are as follows:
+1. You cannot wish for a wish, or any other item which would grant more
+ wishes.
+2. A wish will always generate *one* object. So, never put a number, "a"
+ or "an" in front of the object you are wishing for.
+3. It is not possible to wish for the magical +'s to the object (i.e. you
+ cannot wish for "gloves of slaying (+10,+10)", but you can wish for
+ "gloves of slaying").
+4. You cannot wish for artifacts, but you *can* wish for excellent (ego)
+ items.
+5. You can wish for monsters and ego monsters (e.g. "cave orc", "rogue cave
+ orc").
+6. You cannot wish for unique monsters.
+7. You can wish the monster to have a specific flag - a pet, or a foe.
+ Possible flags include: enemy, neutral, friendly, pet, companion.
diff --git a/lib/mods/theme/module.lua b/lib/mods/theme/module.lua
new file mode 100644
index 00000000..cc0b6f08
--- /dev/null
+++ b/lib/mods/theme/module.lua
@@ -0,0 +1,48 @@
+add_module
+{
+ ["name"] = "Theme",
+ ["version"] = { 1, 2, 0 },
+ ["author"] = { "furiosity", "furiosity@gmail.com" },
+ ["desc"] = {
+ "A module that goes back to Tolkien roots, though by no means canonical.",
+ "A new wilderness map, new monsters, objects, artifacts, uniques, ego items,",
+ "terrain features, gods, races, subraces, and classes. Have fun. :-)",
+ },
+
+ ["rand_quest"] = TRUE,
+ ["C_quest"] = TRUE,
+
+ ["base_dungeon"] = 4,
+ ["death_dungeon"] = 28,
+
+ ["astral_dungeon"] = 8,
+ ["astral_wild_x"] = 45,
+ ["astral_wild_y"] = 19,
+
+ ["random_artifact_weapon_chance"] = 30,
+ ["random_artifact_armor_chance"] = 30,
+ ["random_artifact_jewelry_chance"] = 30,
+
+ ["max_plev"] = 50,
+ ["max_skill_overage"] = 5,
+
+ ["mod_savefiles"]=
+ {
+ "Theme",
+ },
+ ["layout"] =
+ {
+ ["apex"] = "theme",
+ ["core"] = "theme",
+ ["data"] = "theme",
+ ["dngn"] = "theme",
+ ["edit"] = "theme",
+ ["file"] = "theme",
+ ["help"] = "theme",
+ ["note"] = "theme",
+ ["save"] = "theme",
+ ["scpt"] = "theme",
+ ["user"] = "theme",
+ ["pref"] = "theme",
+ },
+} \ No newline at end of file
diff --git a/lib/mods/theme/note/delete.me b/lib/mods/theme/note/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/mods/theme/note/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/mods/theme/permission.txt b/lib/mods/theme/permission.txt
new file mode 100644
index 00000000..bb850954
--- /dev/null
+++ b/lib/mods/theme/permission.txt
@@ -0,0 +1,3 @@
+Permission hereby granted to use any and all parts of the Theme module in other modules, games, fan fiction, whatever, as long as it's nonprofit. Please give credit where credit is due and don't simply take my work and use it as though it was always yours. Adding something of mine to an *_info file? Include a comment that credits Theme.
+
+furiosity \ No newline at end of file
diff --git a/lib/mods/theme/pref/422color.prf b/lib/mods/theme/pref/422color.prf
new file mode 100644
index 00000000..309c36b0
--- /dev/null
+++ b/lib/mods/theme/pref/422color.prf
@@ -0,0 +1,909 @@
+# Agent of the black market
+R:14:0x08:0x74
+
+# Mean-looking mercenary
+R:17:0x0c:0x74
+
+# Battle-scarred veteran
+R:18:0x04:0x74
+
+# Small kobold
+R:29:0x0d:0x6b
+
+# Kobold
+R:30:0x05:0x6b
+
+# Floating eye
+R:32:0x06:0x65
+
+# Fruit bat
+R:37:0x0a:0x62
+
+# Blubbering icky thing
+R:41:0x05:0x69
+
+# Metallic green centipede
+R:42:0x0d:0x63
+
+# Novice warrior
+R:43:0x0f:0x70
+
+# Novice rogue
+R:44:0x08:0x70
+
+# Novice priest
+R:45:0x0e:0x70
+
+# Novice mage
+R:46:0x0c:0x70
+
+# Smeagol
+R:63:0x07:0x68
+
+# Metallic blue centipede
+R:67:0x0e:0x63
+
+# Metallic red centipede
+R:77:0x0c:0x63
+
+# Novice ranger
+R:83:0x05:0x70
+
+# Snotling
+R:87:0x0d:0x6f
+
+# Skeleton kobold
+R:91:0x01:0x73
+
+# Novice mage
+R:93:0x0c:0x70
+
+# Giant leech
+R:95:0x0a:0x77
+
+# Large kobold
+R:102:0x01:0x6b
+
+# Novice priest
+R:109:0x0e:0x70
+
+# Novice warrior
+R:110:0x0f:0x70
+
+# Novice rogue
+R:116:0x08:0x70
+
+# Snaga
+R:118:0x0d:0x6f
+
+# Giant pink frog
+R:121:0x0c:0x52
+
+# Cave orc
+R:126:0x0f:0x6f
+
+# Manes
+R:128:0x0c:0x75
+
+# Red naga
+R:130:0x0c:0x6e
+
+# Red jelly
+R:131:0x0c:0x6a
+
+# Green icky thing
+R:132:0x0d:0x69
+
+# Lost soul
+R:133:0x07:0x47
+
+# Mughash, the Kobold Lord
+R:135:0x06:0x6b
+
+# Skeleton orc
+R:136:0x01:0x73
+
+# Wormtongue, Agent of Saruman
+R:137:0x08:0x70
+
+# Nurgling
+R:139:0x0f:0x75
+
+# Lagduf, the Snaga
+R:140:0x07:0x6f
+
+# Novice ranger
+R:142:0x05:0x70
+
+# Giant salamander
+R:143:0x04:0x52
+
+# Lemure
+R:148:0x03:0x75
+
+# Hill orc
+R:149:0x02:0x6f
+
+# Bandit
+R:150:0x08:0x70
+
+# Orc shaman
+R:162:0x06:0x6f
+
+# Baby blue dragon
+R:163:0x0e:0x64
+
+# Baby white dragon
+R:164:0x09:0x64
+
+# Baby green dragon
+R:165:0x0d:0x64
+
+# Baby red dragon
+R:167:0x0c:0x64
+
+# Giant red ant
+R:168:0x0c:0x61
+
+# Brodda, the Easterling
+R:169:0x03:0x70
+
+# Giant spider
+R:175:0x02:0x53
+
+# Dark elven mage
+R:178:0x0a:0x68
+
+# Kamikaze yeek
+R:179:0x07:0x79
+
+# Dark elven warrior
+R:182:0x08:0x68
+
+# Sand-dweller
+R:183:0x0f:0x75
+
+# Clear mushroom patch
+R:184:0x01:0x2c
+
+# Grishnakh, the Hill Orc
+R:186:0x07:0x6f
+
+# Hairy mold
+R:190:0x0f:0x6d
+
+# Grizzly bear
+R:191:0x07:0x71
+
+# Pseudo dragon
+R:193:0x0a:0x64
+
+# Giant fruit fly
+R:197:0x0f:0x49
+
+# Golfimbul, the Hill Orc Chief
+R:215:0x07:0x6f
+
+# Swordsman
+R:216:0x0f:0x70
+
+# Priest
+R:225:0x0e:0x70
+
+# Dark elven priest
+R:226:0x06:0x68
+
+# Skeleton human
+R:228:0x01:0x73
+
+# Moaning spirit
+R:231:0x0f:0x47
+
+# Stegocentipede
+R:232:0x06:0x63
+
+# Spotted jelly
+R:233:0x02:0x6a
+
+# Illusionist
+R:240:0x0a:0x70
+
+# Druid
+R:241:0x05:0x70
+
+# Ochre jelly
+R:245:0x0b:0x6a
+
+# Vlasta
+R:249:0x06:0x52
+
+# Snaga sapper
+R:251:0x0d:0x6f
+
+# Flesh golem
+R:256:0x03:0x67
+
+# Dark naga
+R:265:0x08:0x6e
+
+# Giant tarantula
+R:275:0x0d:0x53
+
+# Giant clear centipede
+R:276:0x01:0x63
+
+# Mirkwood spider
+R:277:0x07:0x53
+
+# Umber hulk
+R:283:0x07:0x58
+
+# Orc captain
+R:285:0x05:0x6f
+
+# Gelatinous cube
+R:286:0x0e:0x6a
+
+# Lizard man
+R:290:0x0c:0x68
+
+# Ulfast, Son of Ulfang
+R:291:0x03:0x70
+
+# Quasit
+R:294:0x09:0x75
+
+# Imp
+R:296:0x04:0x75
+
+# Forest troll
+R:297:0x0d:0x54
+
+# Giant red scorpion
+R:304:0x0c:0x53
+
+# Earth spirit
+R:305:0x0f:0x45
+
+# Fire spirit
+R:306:0x0c:0x45
+
+# Cold hound
+R:308:0x09:0x5a
+
+# Energy hound
+R:309:0x0b:0x5a
+
+# Uruk
+R:313:0x01:0x6f
+
+# Shagrat, the Orc Captain
+R:314:0x07:0x6f
+
+# Gorbag, the Orc Captain
+R:315:0x07:0x6f
+
+# Stone giant
+R:321:0x02:0x50
+
+# Giant black dragon fly
+R:322:0x08:0x46
+
+# Stone golem
+R:323:0x02:0x67
+
+# Ghast
+R:327:0x0f:0x7a
+
+# Bolg, Son of Azog
+R:330:0x0c:0x6f
+
+# Lizard king
+R:332:0x0c:0x68
+
+# Wyvern
+R:334:0x0d:0x64
+
+# Air hound
+R:338:0x0e:0x5a
+
+# Quylthulg
+R:342:0x09:0x51
+
+# Dark elven lord
+R:348:0x08:0x68
+
+# Cloud giant
+R:349:0x0e:0x50
+
+# Ugluk, the Uruk
+R:350:0x07:0x6f
+
+# Blue dragon bat
+R:351:0x0e:0x62
+
+# Water vortex
+R:355:0x06:0x76
+
+# Cold vortex
+R:358:0x09:0x76
+
+# Energy vortex
+R:359:0x0b:0x76
+
+# Mummified orc
+R:362:0x07:0x7a
+
+# Serpent man
+R:364:0x05:0x4a
+
+# Killer stag beetle
+R:366:0x02:0x4b
+
+# Iron golem
+R:367:0x09:0x67
+
+# Azog, King of the Uruk-Hai
+R:373:0x04:0x6f
+
+# Master rogue
+R:376:0x08:0x70
+
+# Angamaite of Umbar
+R:380:0x07:0x70
+
+# Forest wight
+R:381:0x0d:0x57
+
+# 4-headed hydra
+R:387:0x0f:0x4d
+
+# Mummified human
+R:390:0x0f:0x7a
+
+# Sangahyando of Umbar
+R:392:0x03:0x70
+
+# Banshee
+R:394:0x09:0x47
+
+# Pukelman
+R:398:0x07:0x67
+
+# Disenchanter beast
+R:399:0x01:0x71
+
+# Stone troll
+R:401:0x08:0x54
+
+# Troll priest
+R:403:0x06:0x54
+
+# Khufu, the Mummified King
+R:409:0x07:0x7a
+
+# Beast of Nurgle
+R:422:0x03:0x71
+
+# Creeping adamantite coins
+R:423:0x0a:0x24
+
+# Algroth
+R:424:0x02:0x54
+
+# Flamer of Tzeentch
+R:425:0x0c:0x2c
+
+# Vibration hound
+R:428:0x0f:0x5a
+
+# Ogre mage
+R:430:0x03:0x4f
+
+# Lokkak, the Ogre Chieftain
+R:431:0x05:0x4f
+
+# Colbran
+R:435:0x06:0x67
+
+# Spirit naga
+R:436:0x0e:0x6e
+
+# Corpser
+R:437:0x05:0x2c
+
+# Black knight
+R:442:0x08:0x70
+
+# Clairvoyant
+R:445:0x0e:0x70
+
+# Basilisk
+R:453:0x08:0x52
+
+# Aklash
+R:463:0x09:0x54
+
+# Skeleton troll
+R:465:0x01:0x73
+
+# Shadow drake
+R:471:0x08:0x64
+
+# Manticore
+R:472:0x03:0x48
+
+# Killer slicer beetle
+R:474:0x03:0x4b
+
+# Gug
+R:476:0x08:0x50
+
+# Death watch beetle
+R:478:0x0e:0x4b
+
+# Doombat
+R:484:0x06:0x62
+
+# Ninja
+R:485:0x08:0x70
+
+# Storm giant
+R:487:0x06:0x50
+
+# Bokrug
+R:489:0x05:0x52
+
+# Half-troll
+R:491:0x03:0x54
+
+# Bert the Stone Troll
+R:493:0x09:0x54
+
+# Bill the Stone Troll
+R:494:0x09:0x54
+
+# Tom the Stone Troll
+R:495:0x09:0x54
+
+# Barrow wight
+R:499:0x09:0x57
+
+# Law drake
+R:502:0x09:0x64
+
+# Balance drake
+R:503:0x02:0x64
+
+# Groo, the Wanderer
+R:505:0x03:0x70
+
+# Spectre
+R:508:0x0d:0x47
+
+# Cherub
+R:511:0x09:0x41
+
+# Master thief
+R:516:0x08:0x70
+
+# Lich
+R:518:0x01:0x4c
+
+# Master vampire
+R:520:0x02:0x56
+
+# Oriental vampire
+R:521:0x05:0x56
+
+# Greater mummy
+R:522:0x09:0x7a
+
+# Eog golem
+R:530:0x08:0x67
+
+# Dagashi
+R:532:0x0b:0x70
+
+# Smoke elemental
+R:537:0x08:0x45
+
+# Olog
+R:538:0x05:0x54
+
+# Gravity hound
+R:540:0x02:0x5a
+
+# Acidic cytoplasm
+R:541:0x0d:0x6a
+
+# Ooze elemental
+R:545:0x0f:0x45
+
+# Young black dragon
+R:546:0x08:0x64
+
+# Xorn
+R:550:0x03:0x58
+
+# Colossus
+R:558:0x0b:0x67
+
+# Bodak
+R:566:0x08:0x75
+
+# Lorgan, Chief of the Easterlings
+R:573:0x0c:0x70
+
+# Chaos spawn
+R:574:0x07:0x65
+
+# Crypt thing
+R:577:0x0e:0x4c
+
+# Will o' the wisp
+R:582:0x0b:0x45
+
+# Crystal drake
+R:591:0x0e:0x64
+
+# Mature black dragon
+R:592:0x08:0x64
+
+# Draebor, the Imp
+R:595:0x05:0x75
+
+# Mother Hydra
+R:596:0x05:0x75
+
+# Death knight
+R:597:0x02:0x70
+
+# Time vortex
+R:599:0x0d:0x76
+
+# Shimmering vortex
+R:600:0x0a:0x76
+
+# Beholder
+R:603:0x05:0x65
+
+# Emperor wight
+R:604:0x0b:0x57
+
+# Vargo, Tyrant of Fire
+R:606:0x0c:0x45
+
+# Nether wraith
+R:612:0x0c:0x57
+
+# Waldern, King of Water
+R:615:0x02:0x45
+
+# Ettin
+R:621:0x0b:0x54
+
+# Night mare
+R:622:0x0a:0x71
+
+# Ancient black dragon
+R:624:0x08:0x44
+
+# Shadowfax, steed of Gandalf
+R:629:0x09:0x71
+
+# Spirit troll
+R:630:0x0a:0x47
+
+# War troll
+R:631:0x05:0x54
+
+# Rotting quylthulg
+R:633:0x0f:0x51
+
+# 9-headed hydra
+R:635:0x03:0x4d
+
+# Enchantress
+R:636:0x0b:0x70
+
+# Sorcerer
+R:638:0x03:0x70
+
+# Xaren
+R:639:0x0b:0x58
+
+# Medusa, the Gorgon
+R:642:0x03:0x6e
+
+# Death drake
+R:643:0x07:0x44
+
+# Great crystal drake
+R:646:0x0e:0x44
+
+# Wyrd sister
+R:647:0x0b:0x70
+
+# Death quasit
+R:649:0x01:0x75
+
+# Fallen angel
+R:652:0x08:0x41
+
+# Judge Fire
+R:654:0x04:0x73
+
+# Master lich
+R:658:0x09:0x4c
+
+# Eol, the Dark Elf
+R:660:0x02:0x68
+
+# Undead beholder
+R:664:0x02:0x65
+
+# Dark young of Shub-Niggurath
+R:677:0x08:0x55
+
+# Dreadmaster
+R:690:0x03:0x47
+
+# Scatha the Worm
+R:692:0x01:0x44
+
+# Zoth-Ommog
+R:695:0x07:0x52
+
+# Grand master thief
+R:696:0x0e:0x70
+
+# Leprechaun fanatic
+R:700:0x08:0x68
+
+# Dracolich
+R:701:0x0e:0x44
+
+# Greater titan
+R:702:0x0a:0x50
+
+# Dracolisk
+R:703:0x04:0x44
+
+# Itangast the Fire Drake
+R:710:0x04:0x44
+
+# Glaurung, Father of the Dragons
+R:715:0x04:0x44
+
+# Behemoth
+R:716:0x05:0x48
+
+# Garm, Guardian of Hel
+R:717:0x07:0x43
+
+# Maulotaur
+R:723:0x07:0x48
+
+# Nether hound
+R:724:0x08:0x5a
+
+# Time hound
+R:725:0x0d:0x5a
+
+# Demonic quylthulg
+R:727:0x0c:0x51
+
+# Ulik the Troll
+R:729:0x03:0x54
+
+# Baphomet the Minotaur Lord
+R:730:0x08:0x48
+
+# Hell knight
+R:731:0x02:0x70
+
+# Old Sorcerer
+R:738:0x0a:0x70
+
+# Keeper of Secrets
+R:746:0x0a:0x48
+
+# Hand druj
+R:748:0x08:0x73
+
+# Eye druj
+R:749:0x08:0x73
+
+# Skull druj
+R:750:0x08:0x73
+
+# Aether vortex
+R:752:0x0e:0x76
+
+# Draconic quylthulg
+R:759:0x0d:0x51
+
+# Fundin Bluecloak
+R:762:0x0d:0x68
+
+# Gabriel, the Messenger
+R:769:0x0a:0x41
+
+# Artsi, the Champion of Chaos
+R:770:0x0d:0x68
+
+# The Cat Lord
+R:777:0x04:0x66
+
+# Vlad Dracula, Prince of Darkness
+R:780:0x06:0x56
+
+# Great Wyrm of Law
+R:784:0x09:0x44
+
+# Great Wyrm of Balance
+R:785:0x02:0x44
+
+# Glaaki
+R:788:0x05:0x7e
+
+# Greater draconic quylthulg
+R:801:0x05:0x51
+
+# Greater rotting quylthulg
+R:802:0x07:0x51
+
+# Omarax the Eye Tyrant
+R:805:0x0b:0x65
+
+# Greater Balrog
+R:807:0x0c:0x55
+
+# Aether hound
+R:811:0x0e:0x5a
+
+# Yig, Father of Serpents
+R:814:0x05:0x4a
+
+# Hela, Queen of the Dead
+R:817:0x05:0x70
+
+# Master quylthulg
+R:821:0x06:0x51
+
+# Qlzqqlzuup, the Lord of Flesh
+R:822:0x0e:0x51
+
+# F'lar, rider of the Bronze Mnementh
+R:824:0x08:0x44
+
+# Cyaegha
+R:826:0x08:0x65
+
+# Pazuzu, Lord of Air
+R:827:0x01:0x55
+
+# Cantoras, the Skeletal Lord
+R:830:0x0e:0x73
+
+# Godzilla
+R:832:0x05:0x52
+
+# Loki, the Trickster
+R:835:0x05:0x50
+
+# Lungorthin, the Balrog of White Fire
+R:839:0x01:0x55
+
+# Draugluin, Sire of All Werewolves
+R:840:0x07:0x43
+
+# Vecna, the Emperor Lich
+R:844:0x0b:0x4c
+
+# Great Wyrm of Power
+R:847:0x0b:0x44
+
+# Nodens, Lord of the Great Abyss
+R:849:0x01:0x50
+
+# Jormungand the Midgard Serpent
+R:854:0x05:0x4a
+
+# The Destroyer
+R:855:0x09:0x67
+
+# Gothmog, the High Captain of Balrogs
+R:856:0x0c:0x55
+
+# Sauron, the Sorcerer
+R:860:0x03:0x70
+
+# Human Warrior
+R:863:0x01:0x70
+
+# Elven archer
+R:864:0x0d:0x68
+
+# Death
+R:875:0x02:0x47
+
+# Famine
+R:876:0x02:0x47
+
+# Pestilence
+R:877:0x02:0x47
+
+# War
+R:878:0x02:0x47
+
+# Giant piranha
+R:884:0x0d:0x7e
+
+# Octopus
+R:891:0x02:0x7e
+
+# Giant octopus
+R:892:0x0a:0x7e
+
+# Drowned soul
+R:895:0x02:0x47
+
+# Devilfish
+R:920:0x0a:0x7e
+
+# Undead devilfish
+R:921:0x0a:0x7e
+
+# Gandalf the Grey
+R:935:0x0a:0x70
+
+# Brown Firelizard
+R:942:0x0f:0x64
+
+# Bronze Firelizard
+R:943:0x01:0x64
+
+# Elder aranea
+R:964:0x04:0x53
+
+# Bullroarer the Hobbit
+R:985:0x06:0x68
+
+# Hezrou
+R:992:0x0a:0x55
+
+# Glabrezu
+R:993:0x03:0x55
+
+# Lesser Balrog
+R:996:0x0c:0x55
+
+# The Rat King
+R:1006:0x07:0x72
+
+# Vort the Kobold Queen
+R:1007:0x06:0x6b
+
+# Fire Phantom
+R:1009:0x0c:0x47
+
+# Bone golem
+R:1013:0x08:0x67
+
+# Snake of Yig
+R:1014:0x04:0x4a
+
+# Cultist
+R:1017:0x0e:0x70
+
+# Cult leader
+R:1018:0x06:0x70
+
+# Green dragon worm
+R:1025:0x05:0x77
+
+# Red dragon worm
+R:1027:0x04:0x77
+
diff --git a/lib/mods/theme/pref/colors.prf b/lib/mods/theme/pref/colors.prf
new file mode 100644
index 00000000..fa4d3f05
--- /dev/null
+++ b/lib/mods/theme/pref/colors.prf
@@ -0,0 +1,53 @@
+
+
+# Color redefinitions
+
+# Color 'White'
+V:1:0x07:0xFF:0xFF:0xFF
+
+# Color 'Slate'
+V:2:0x03:0x8C:0x8C:0x8C
+
+# Color 'Orange'
+V:3:0x0C:0xFF:0x77:0x00
+
+# Color 'Red'
+V:4:0x04:0xC9:0x00:0x00
+
+# Color 'Green'
+V:5:0x02:0x00:0x86:0x45
+
+# Color 'Blue'
+V:6:0x01:0x00:0x00:0xE3
+
+# Color 'Umber'
+V:7:0x06:0x8E:0x45:0x00
+
+# Color 'Light Dark'
+V:8:0x08:0x50:0x50:0x50
+
+# Color 'Light Slate'
+V:9:0x0B:0xD1:0xD1:0xD1
+
+# Color 'Violet'
+V:10:0x05:0xC0:0x00:0xAF
+
+# Color 'Yellow'
+V:11:0x0E:0xFF:0xFF:0x00
+
+# Color 'Light Red'
+V:12:0x0D:0xFF:0x00:0x68
+
+# Color 'Light Green'
+V:13:0x0A:0x00:0xFF:0x00
+
+# Color 'Light Blue'
+V:14:0x09:0x51:0xDD:0xFF
+
+# Color 'Light Umber'
+V:15:0x06:0xD7:0x8E:0x45
+
+
+
+
+
diff --git a/lib/mods/theme/pref/font-ami.prf b/lib/mods/theme/pref/font-ami.prf
new file mode 100644
index 00000000..1c06dbb3
--- /dev/null
+++ b/lib/mods/theme/pref/font-ami.prf
@@ -0,0 +1,28 @@
+# File: font-ami.prf
+
+#
+# This file contains text remapping data
+# currently used in the Amiga version.
+#
+# Lars Haugseth <larshau@ifi.uio.no>
+#
+
+
+# Color palette - Text
+V:0:0x01:0x00:0x00:0x00
+V:1:0x01:0xFF:0xFF:0xFF
+V:2:0x01:0xC7:0xC7:0xC7
+V:3:0x01:0xFF:0x92:0x00
+V:4:0x01:0xFF:0x00:0x00
+V:5:0x01:0x00:0xCD:0x00
+V:6:0x01:0x00:0x00:0xFE
+V:7:0x01:0xC8:0x64:0x00
+V:8:0x01:0x8A:0x8A:0x8A
+V:9:0x01:0xE0:0xE0:0xE0
+V:10:0x01:0xA5:0x00:0xFF
+V:11:0x01:0xFF:0xFD:0x00
+V:12:0x01:0xFF:0x00:0xBC
+V:13:0x01:0x00:0xFF:0x00
+V:14:0x01:0x00:0xC8:0xFF
+V:15:0x01:0xFF:0xCC:0x80
+
diff --git a/lib/mods/theme/pref/font-dos.prf b/lib/mods/theme/pref/font-dos.prf
new file mode 100644
index 00000000..9cf1866f
--- /dev/null
+++ b/lib/mods/theme/pref/font-dos.prf
@@ -0,0 +1,8 @@
+# File: font-dos.prf
+
+#
+# This file is used by Angband (when it was compiled using "main-dos.c")
+# to specify simple attr/char remappings using a standard font, allowing
+# the use of special pseudo-graphic pictures for walls and such.
+#
+
diff --git a/lib/mods/theme/pref/font-ibm.prf b/lib/mods/theme/pref/font-ibm.prf
new file mode 100644
index 00000000..91ca81bb
--- /dev/null
+++ b/lib/mods/theme/pref/font-ibm.prf
@@ -0,0 +1,365 @@
+# File: font-ibm.prf
+
+#
+# This file is used by Angband (when it was compiled using "main-ibm.c")
+# to specify simple attr/char remappings using a standard font, allowing
+# the use of the IBM's built in pseudo-graphic pictures for walls and such.
+#
+
+
+##### Feature attr/char definitions #####
+
+# open floor
+F:1:0x01/0xF9
+
+# fountain
+F:2:0x01/0xF4
+
+# fountain
+F:15:0x08/0xF4
+
+# web
+F:16:0x0B/0xB2
+
+# secret door
+F:48:0x01/0xB1
+
+# magma vein
+F:50:0x02/0xB0
+
+# quartz vein
+F:51:0x01/0xB0
+
+# magma vein
+F:52:0x02/0xB0
+
+# quartz vein
+F:53:0x01/0xB0
+
+# magma vein with treasure
+F:54:0x03/0xB0
+
+# quartz vein with treasure
+F:55:0x03/0xB0
+
+# granite wall
+F:56:0x01/0xB1
+
+# granite wall
+F:57:0x01/0xB1
+
+# granite wall
+F:58:0x01/0xB1
+
+# granite wall
+F:59:0x01/0xB1
+
+# permanent wall
+F:60:0x01/0xB1
+
+# permanent wall
+F:61:0x01/0xB1
+
+# permanent wall
+F:62:0x01/0xB1
+
+# permanent wall
+F:63:0x01/0xB1
+
+# Straight Road startpoint
+F:65:0x01/0xB2
+
+# section of the Straight Road
+F:66:0x0E/0xB2
+
+# section of the Straight Road
+F:67:0x06/0xB2
+
+# section of the Straight Road
+F:68:0x0E/0xB2
+
+# section of the Straight Road
+F:69:0x06/0xB2
+
+# section of the Straight Road
+F:70:0x09/0xB2
+
+# section of the Straight Road (discharged)
+F:71:0x09/0xB2
+
+# Straight Road exit
+F:72:0x01/0xB2
+
+# corrupted section of the Straight Road
+F:73:0x08/0xB2
+
+# permanent wall
+F:75:0x01/0xB1
+
+# permanent wall
+F:76:0x01/0xB1
+
+# permanent wall
+F:77:0x01/0xB1
+
+# permanent wall
+F:78:0x01/0xB1
+
+# stream of shallow water
+F:84:0x0E/0xF7
+
+# pool of deep lava
+F:85:0x0C/0xF7
+
+# stream of shallow lava
+F:86:0x04/0xF7
+
+# dark pit
+F:87:0x08/0xDB
+
+# dirt
+F:88:0x0F/0xF9
+
+# patch of grass
+F:89:0x0D/0xF9
+
+# ice
+F:90:0x09/0xDB
+
+# sand
+F:91:0x0B/0xF9
+
+# dead tree
+F:92:0x08/0x9D
+
+# ash
+F:93:0x02/0xF9
+
+# mud
+F:94:0x07/0xF9
+
+# ice wall
+F:95:0x09/0xB1
+
+# tree
+F:96:0x0D/0x9D
+
+# sandwall
+F:98:0x0B/0xB1
+
+# sandwall
+F:99:0x0B/0xB1
+
+# sandwall with treasure
+F:100:0x03/0xB1
+
+# nether mist
+F:102:0x0A/0xB2
+
+# Void Jumpgate
+F:160:0x0A/0xEF
+
+# Altar of Being
+F:161:0x09/0xD2
+
+# Altar of Winds
+F:162:0x0E/0xD2
+
+# Altar of Force
+F:163:0x0C/0xD2
+
+# Altar of Darkness
+F:164:0x08/0xD2
+
+# floor
+F:172:0x01/0xF9
+
+# Underground Tunnel
+F:173:0x02/0xB0
+
+# stream of tainted water
+F:174:0x07/0xF7
+
+# Void Jumpgate
+F:176:0x0A/0xEF
+
+# lava wall
+F:177:0x0C/0xB1
+
+# Great Fire
+F:178:0x0A/0xF7
+
+# field
+F:181:0x05/0xF9
+
+# Ekkaia, the Encircling Sea
+F:182:0x06/0xF7
+
+# pool of deep water
+F:187:0x06/0xF7
+
+# glass wall
+F:188:0x0E/0xDB
+
+# illusion wall
+F:189:0x01/0xB1
+
+# Grass roof
+F:190:0x0B/0xB1
+
+# grass roof top
+F:191:0x0B/0xB1
+
+# grass roof chimney
+F:192:0x0B/0xB1
+
+# brick roof
+F:193:0x04/0xB1
+
+# brick roof top
+F:194:0x04/0xB1
+
+# brick roof chimney
+F:195:0x04/0xB1
+
+# window
+F:196:0x01/0x4F
+
+# small window
+F:197:0x01/0x6F
+
+# rain barrel
+F:198:0x01/0xB1
+
+# cobblestone road
+F:200:0x01/0xF9
+
+# cobblestone with outlet
+F:201:0x01/0xF9
+
+# small tree
+F:202:0x05/0x9D
+
+# Underground Tunnel
+F:204:0x0F/0xB0
+
+# a blazing fire
+F:205:0x0B/0xF7
+
+# rocky ground
+F:207:0x02/0xF9
+
+# cloud-like vapour
+F:208:0x09/0xB2
+
+# condensing water
+F:209:0x0E/0xF7
+
+# dense mist
+F:210:0x01/0xB2
+
+# hail-stone wall
+F:211:0x09/0xB1
+
+# dark pit
+F:248:0x04:0x27
+
+##### Monster attr/char definitions #####
+
+# Space monster
+R:144:0x00/0xF9
+
+# Old Man Willow
+R:206:0x02/0x9D
+
+# Lurker
+R:247:0x01/0xF9
+
+# Tangleweed
+R:248:0x05/0x9D
+
+# Poison ivy
+R:266:0x05/0x9D
+
+# Giant Venus Flytrap
+R:317:0x05/0x9D
+
+# Stunwall
+R:326:0x09/0xB1
+
+# Huorn
+R:329:0x05/0x9D
+
+# Landmine
+R:333:0x01/0xF9
+
+# Livingstone
+R:336:0x09/0xB1
+
+# Vampiric mist
+R:365:0x08/0xB2
+
+# It
+R:393:0x09/0xF9
+
+# Xiclotlan
+R:396:0x08/0x9D
+
+# Roper
+R:426:0x08/0xB1
+
+# Lesser wall monster
+R:448:0x09/0xB1
+
+# Chaos tile
+R:458:0x0A/0xF9
+
+# Mist giant
+R:552:0x0E/0xB2
+
+# Trapper
+R:565:0x01/0xF9
+
+# Time bomb
+R:567:0x01/0xF9
+
+# Weird fume
+R:625:0x0A/0xB2
+
+# Colour out of space
+R:678:0x0A/0xF9
+
+# Ent
+R:708:0x0D/0x9D
+
+# Quickbeam, the Ent
+R:714:0x0D/0x9D
+
+# Greater wall monster
+R:718:0x09/0xB1
+
+# Ahtu, Avatar of Nyarlathotep
+R:761:0x08/0xB1
+
+# Null, the Living Void
+R:803:0x00/0xF9
+
+# Rocket mine
+R:870:0x0C/0xF9
+
+# Bouncing mine
+R:871:0x0E/0xF9
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0x0D/0x9D
+
+# The Glass Golem
+R:1033:0x09/0xB1
+
+# Golgarach, the Living Rock
+R:1035:0x09/0xB1
+
+# Spirit
+R:1053:0x09/0xF9
+
+
diff --git a/lib/mods/theme/pref/font-mac.new b/lib/mods/theme/pref/font-mac.new
new file mode 100644
index 00000000..8b7f937c
--- /dev/null
+++ b/lib/mods/theme/pref/font-mac.new
@@ -0,0 +1,110 @@
+# File: font-mac.prf
+
+#
+# This file is used by Angband (when it was compiled using "main-mac.c")
+# to specify simple attr/char remappings using a standard font, allowing
+# the use of the Macintosh's special characters for some things.
+#
+
+
+##### Feature attr/char definitions #####
+
+# fountain
+F:2:0x01/0xBA
+
+# fountain
+F:15:0x08/0xBA
+
+# stream of shallow water
+F:84:0x0E/0xC5
+
+# pool of deep lava
+F:85:0x0C/0xC5
+
+# stream of shallow lava
+F:86:0x04/0xC5
+
+# dead tree
+F:92:0x08/0xB4
+
+# tree
+F:96:0x0D/0xB4
+
+# mountain chain
+F:97:0x0F/0xC6
+
+# high mountain chain
+F:101:0x09/0xC6
+
+# Void Jumpgate
+F:160:0x0A/0xBD
+
+# Altar of Being
+F:161:0x09/0xB9
+
+# Altar of Winds
+F:162:0x0E/0xB9
+
+# Altar of Force
+F:163:0x0C/0xB9
+
+# Altar of Darkness
+F:164:0x08/0xB9
+
+# stream of tainted water
+F:174:0x07/0xC5
+
+# Void Jumpgate
+F:176:0x0A/0xBD
+
+# Great Fire
+F:178:0x0A/0xC5
+
+# Ekkaia, the Encircling Sea
+F:182:0x06/0xC5
+
+# pool of deep water
+F:187:0x06/0xC5
+
+# small tree
+F:202:0x05/0xB4
+
+# a blazing fire
+F:205:0x0B/0xC5
+
+# condensing water
+F:209:0x0E/0xC5
+
+# dark pit
+F:248:0x04:0x27
+
+##### Monster attr/char definitions #####
+
+# Old Man Willow
+R:206:0x02/0xB4
+
+# Tangleweed
+R:248:0x05/0xB4
+
+# Poison ivy
+R:266:0x05/0xB4
+
+# Giant Venus Flytrap
+R:317:0x05/0xB4
+
+# Huorn
+R:329:0x05/0xB4
+
+# Xiclotlan
+R:396:0x08/0xB4
+
+# Ent
+R:708:0x0D/0xB4
+
+# Quickbeam, the Ent
+R:714:0x0D/0xB4
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0x0D/0xB4
+
+
diff --git a/lib/mods/theme/pref/font-mac.prf b/lib/mods/theme/pref/font-mac.prf
new file mode 100644
index 00000000..d15c2e47
--- /dev/null
+++ b/lib/mods/theme/pref/font-mac.prf
@@ -0,0 +1,18 @@
+# File: font.prf
+
+#
+# This file defines special attr/char mappings for use in "text" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+## OPTION: Display "veins" (white "%") as "normal walls" (white "#")
+## This replaces the old method of setting "notice_seams" to false,
+## which no longer works as of Angband 2.7.9, for various reasons.
+#
+#F:50:1/35
+#F:51:1/35
+#F:52:1/35
+#F:53:1/35
+
diff --git a/lib/mods/theme/pref/font-win.prf b/lib/mods/theme/pref/font-win.prf
new file mode 100644
index 00000000..6c54e7e5
--- /dev/null
+++ b/lib/mods/theme/pref/font-win.prf
@@ -0,0 +1,304 @@
+# File: font-win.prf
+
+#
+# This file is used by Angband (when it was compiled using "main-win.c")
+# to specify simple attr/char remappings using a standard font, allowing
+# the use of special pseudo-graphic pictures for walls and such.
+#
+# Note that this file is extremely similar to the file "font-ibm.prf",
+# but it uses different codes, since it uses the special pseudo-graphic
+# symbols defined in the "lib/xtra/font/*.FON" files, and there is only
+# one special wall type, so we have to use special "colors".
+#
+
+
+##### Feature attr/char definitions #####
+
+# open floor
+F:1:0x01/0x1F
+
+# web
+F:16:0x0B/0x7F
+
+# secret door
+F:48:0x01/0x7F
+
+# magma vein
+F:50:0x02/0x7F
+
+# quartz vein
+F:51:0x09/0x7F
+
+# magma vein
+F:52:0x02/0x7F
+
+# quartz vein
+F:53:0x09/0x7F
+
+# granite wall
+F:56:0x01/0x7F
+
+# granite wall
+F:57:0x01/0x7F
+
+# granite wall
+F:58:0x01/0x7F
+
+# granite wall
+F:59:0x01/0x7F
+
+# permanent wall
+F:60:0x01/0x7F
+
+# permanent wall
+F:61:0x01/0x7F
+
+# permanent wall
+F:62:0x01/0x7F
+
+# permanent wall
+F:63:0x01/0x7F
+
+# permanent wall
+F:75:0x01/0x7F
+
+# permanent wall
+F:76:0x01/0x7F
+
+# permanent wall
+F:77:0x01/0x7F
+
+# permanent wall
+F:78:0x01/0x7F
+
+# pool of deep lava
+F:85:0x0C/0x1F
+
+# stream of shallow lava
+F:86:0x04/0x1F
+
+# dark pit
+F:87:0x08/0x7F
+
+# dirt
+F:88:0x0F/0x1F
+
+# patch of grass
+F:89:0x0D/0x1F
+
+# ice
+F:90:0x09/0x1F
+
+# sand
+F:91:0x0B/0x1F
+
+# dead tree
+F:92:0x08/0x7F
+
+# ash
+F:93:0x02/0x1F
+
+# mud
+F:94:0x07/0x1F
+
+# ice wall
+F:95:0x09/0x7F
+
+# tree
+F:96:0x0D/0x7F
+
+# sandwall
+F:98:0x0B/0x7F
+
+# sandwall
+F:99:0x0B/0x7F
+
+# sandwall with treasure
+F:100:0x03/0x7F
+
+# nether mist
+F:102:0x0A/0x7F
+
+# glass wall
+F:103:0x0E/0x1F
+
+# Underground Tunnel
+F:173:0x02/0x7F
+
+# lava wall
+F:177:0x0C/0x7F
+
+# Great Fire
+F:178:0x0A/0x7F
+
+# field
+F:181:0x05/0x1F
+
+# glass wall
+F:188:0x0E/0x1F
+
+# illusion wall
+F:189:0x01/0x7F
+
+# Grass roof
+F:190:0x0B/0x7F
+
+# grass roof top
+F:191:0x0B/0x7F
+
+# grass roof chimney
+F:192:0x0B/0x7F
+
+# brick roof
+F:193:0x04/0x7F
+
+# brick roof top
+F:194:0x04/0x7F
+
+# brick roof chimney
+F:195:0x04/0x7F
+
+# rain barrel
+F:198:0x01/0x7F
+
+# cobblestone road
+F:200:0x01/0x1F
+
+# cobblestone with outlet
+F:201:0x01/0x1F
+
+# small tree
+F:202:0x05/0x7F
+
+# Underground Tunnel
+F:204:0x0F/0x7F
+
+# a blazing fire
+F:205:0x0B/0x7F
+
+# rocky ground
+F:207:0x02/0x1F
+
+# cloud-like vapour
+F:208:0x09/0x1F
+
+# dense mist
+F:210:0x01/0x7F
+
+# hail-stone wall
+F:211:0x09/0x7F
+
+# copper pillar
+F:244:0x07/0x7F
+
+# ethereal wall
+F:245:0x01/0x1F
+
+# glacial wall
+F:246:0x0E/0x7F
+
+# battlement
+F:247:0x01/0x7F
+
+# dark pit
+F:248:0x04:0x27
+
+##### Monster attr/char definitions #####
+
+# Space monster
+R:144:0x00/0x1F
+
+# Old Man Willow
+R:206:0x02/0x7F
+
+# Lurker
+R:247:0x01/0x1F
+
+# Tangleweed
+R:248:0x05/0x7F
+
+# Poison ivy
+R:266:0x05/0x7F
+
+# Giant Venus Flytrap
+R:317:0x05/0x7F
+
+# Stunwall
+R:326:0x09/0x7F
+
+# Huorn
+R:329:0x05/0x7F
+
+# Landmine
+R:333:0x01/0x1F
+
+# Livingstone
+R:336:0x09/0x7F
+
+# Vampiric mist
+R:365:0x08/0x7F
+
+# It
+R:393:0x09/0x1F
+
+# Xiclotlan
+R:396:0x08/0x7F
+
+# Roper
+R:426:0x08/0x7F
+
+# Lesser wall monster
+R:448:0x09/0x7F
+
+# Chaos tile
+R:458:0x0A/0x1F
+
+# Mist giant
+R:552:0x0E/0x7F
+
+# Trapper
+R:565:0x01/0x1F
+
+# Time bomb
+R:567:0x01/0x1F
+
+# Weird fume
+R:625:0x0A/0x7F
+
+# Colour out of space
+R:678:0x0A/0x1F
+
+# Ent
+R:708:0x0D/0x7F
+
+# Quickbeam, the Ent
+R:714:0x0D/0x7F
+
+# Greater wall monster
+R:718:0x09/0x7F
+
+# Ahtu, Avatar of Nyarlathotep
+R:761:0x08/0x7F
+
+# Null, the Living Void
+R:803:0x00/0x1F
+
+# Rocket mine
+R:870:0x0C/0x1F
+
+# Bouncing mine
+R:871:0x0E/0x1F
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0x0D/0x7F
+
+# The Glass Golem
+R:1033:0x09/0x7F
+
+# Golgarach, the Living Rock
+R:1035:0x09/0x7F
+
+# Spirit
+R:1053:0x09/0x1F
+
+
diff --git a/lib/mods/theme/pref/font-x11.prf b/lib/mods/theme/pref/font-x11.prf
new file mode 100644
index 00000000..57828a56
--- /dev/null
+++ b/lib/mods/theme/pref/font-x11.prf
@@ -0,0 +1,22 @@
+# File: font-x11.prf
+
+
+# Color palette - Text
+
+V:0:0x01:0x00:0x00:0x00
+V:1:0x01:0xFF:0xFF:0xFF
+V:2:0x01:0xC7:0xC7:0xC7
+V:3:0x01:0xFF:0x92:0x00
+V:4:0x01:0xC0:0x00:0x00
+V:5:0x01:0x00:0xC0:0x00
+V:6:0x01:0x00:0x00:0xFE
+V:7:0x01:0xC8:0x64:0x00
+V:8:0x01:0x8A:0x8A:0x8A
+V:9:0x01:0xE0:0xE0:0xE0
+V:10:0x01:0xA5:0x00:0xFF
+V:11:0x01:0xFF:0xFD:0x00
+V:12:0x01:0xFF:0x40:0x40
+V:13:0x01:0x00:0xFF:0x00
+V:14:0x01:0x00:0xC8:0xFF
+V:15:0x01:0xFF:0xCC:0x80
+
diff --git a/lib/mods/theme/pref/font-xxx.prf b/lib/mods/theme/pref/font-xxx.prf
new file mode 100644
index 00000000..298a8643
--- /dev/null
+++ b/lib/mods/theme/pref/font-xxx.prf
@@ -0,0 +1,472 @@
+# File: font-xxx.prf
+
+#
+# This file defines special attr/char mappings for use in "text" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+##### Special attr/char values #####
+
+
+## # Unused (@)
+## S:0x00:0x00/0x40
+## S:0x01:0x01/0x40
+## S:0x02:0x02/0x40
+## S:0x03:0x03/0x40
+## S:0x04:0x04/0x40
+## S:0x05:0x05/0x40
+## S:0x06:0x06/0x40
+## S:0x07:0x07/0x40
+## S:0x08:0x08/0x40
+## S:0x09:0x09/0x40
+## S:0x0A:0x0A/0x40
+## S:0x0B:0x0B/0x40
+## S:0x0C:0x0C/0x40
+## S:0x0D:0x0D/0x40
+## S:0x0E:0x0E/0x40
+## S:0x0F:0x0F/0x40
+
+## # Unused (@)
+## S:0x10:0x00/0x40
+## S:0x11:0x01/0x40
+## S:0x12:0x02/0x40
+## S:0x13:0x03/0x40
+## S:0x14:0x04/0x40
+## S:0x15:0x05/0x40
+## S:0x16:0x06/0x40
+## S:0x17:0x07/0x40
+## S:0x18:0x08/0x40
+## S:0x19:0x09/0x40
+## S:0x1A:0x0A/0x40
+## S:0x1B:0x0B/0x40
+## S:0x1C:0x0C/0x40
+## S:0x1D:0x0D/0x40
+## S:0x1E:0x0E/0x40
+## S:0x1F:0x0F/0x40
+
+## # Unused (@)
+## S:0x20:0x00/0x40
+## S:0x21:0x01/0x40
+## S:0x22:0x02/0x40
+## S:0x23:0x03/0x40
+## S:0x24:0x04/0x40
+## S:0x25:0x05/0x40
+## S:0x26:0x06/0x40
+## S:0x27:0x07/0x40
+## S:0x28:0x08/0x40
+## S:0x29:0x09/0x40
+## S:0x2A:0x0A/0x40
+## S:0x2B:0x0B/0x40
+## S:0x2C:0x0C/0x40
+## S:0x2D:0x0D/0x40
+## S:0x2E:0x0E/0x40
+## S:0x2F:0x0F/0x40
+
+# Spells (*)
+S:0x30:0x00/0x2A
+S:0x31:0x01/0x2A
+S:0x32:0x02/0x2A
+S:0x33:0x03/0x2A
+S:0x34:0x04/0x2A
+S:0x35:0x05/0x2A
+S:0x36:0x06/0x2A
+S:0x37:0x07/0x2A
+S:0x38:0x08/0x2A
+S:0x39:0x09/0x2A
+S:0x3A:0x0A/0x2A
+S:0x3B:0x0B/0x2A
+S:0x3C:0x0C/0x2A
+S:0x3D:0x0D/0x2A
+S:0x3E:0x0E/0x2A
+S:0x3F:0x0F/0x2A
+
+# Spells (|)
+S:0x40:0x00/0x7C
+S:0x41:0x01/0x7C
+S:0x42:0x02/0x7C
+S:0x43:0x03/0x7C
+S:0x44:0x04/0x7C
+S:0x45:0x05/0x7C
+S:0x46:0x06/0x7C
+S:0x47:0x07/0x7C
+S:0x48:0x08/0x7C
+S:0x49:0x09/0x7C
+S:0x4A:0x0A/0x7C
+S:0x4B:0x0B/0x7C
+S:0x4C:0x0C/0x7C
+S:0x4D:0x0D/0x7C
+S:0x4E:0x0E/0x7C
+S:0x4F:0x0F/0x7C
+
+# Spells (-)
+S:0x50:0x00/0x2D
+S:0x51:0x01/0x2D
+S:0x52:0x02/0x2D
+S:0x53:0x03/0x2D
+S:0x54:0x04/0x2D
+S:0x55:0x05/0x2D
+S:0x56:0x06/0x2D
+S:0x57:0x07/0x2D
+S:0x58:0x08/0x2D
+S:0x59:0x09/0x2D
+S:0x5A:0x0A/0x2D
+S:0x5B:0x0B/0x2D
+S:0x5C:0x0C/0x2D
+S:0x5D:0x0D/0x2D
+S:0x5E:0x0E/0x2D
+S:0x5F:0x0F/0x2D
+
+# Spells (/)
+S:0x60:0x00/0x2F
+S:0x61:0x01/0x2F
+S:0x62:0x02/0x2F
+S:0x63:0x03/0x2F
+S:0x64:0x04/0x2F
+S:0x65:0x05/0x2F
+S:0x66:0x06/0x2F
+S:0x67:0x07/0x2F
+S:0x68:0x08/0x2F
+S:0x69:0x09/0x2F
+S:0x6A:0x0A/0x2F
+S:0x6B:0x0B/0x2F
+S:0x6C:0x0C/0x2F
+S:0x6D:0x0D/0x2F
+S:0x6E:0x0E/0x2F
+S:0x6F:0x0F/0x2F
+
+# Spells (\)
+S:0x70:0x00/0x5C
+S:0x71:0x01/0x5C
+S:0x72:0x02/0x5C
+S:0x73:0x03/0x5C
+S:0x74:0x04/0x5C
+S:0x75:0x05/0x5C
+S:0x76:0x06/0x5C
+S:0x77:0x07/0x5C
+S:0x78:0x08/0x5C
+S:0x79:0x09/0x5C
+S:0x7A:0x0A/0x5C
+S:0x7B:0x0B/0x5C
+S:0x7C:0x0C/0x5C
+S:0x7D:0x0D/0x5C
+S:0x7E:0x0E/0x5C
+S:0x7F:0x0F/0x5C
+
+# Amulets (")
+S:0x80:0x00/0x22
+S:0x81:0x01/0x22
+S:0x82:0x02/0x22
+S:0x83:0x03/0x22
+S:0x84:0x04/0x22
+S:0x85:0x05/0x22
+S:0x86:0x06/0x22
+S:0x87:0x07/0x22
+S:0x88:0x08/0x22
+S:0x89:0x09/0x22
+S:0x8A:0x0A/0x22
+S:0x8B:0x0B/0x22
+S:0x8C:0x0C/0x22
+S:0x8D:0x0D/0x22
+S:0x8E:0x0E/0x22
+S:0x8F:0x0F/0x22
+
+# Rings (=)
+S:0x90:0x00/0x3D
+S:0x91:0x01/0x3D
+S:0x92:0x02/0x3D
+S:0x93:0x03/0x3D
+S:0x94:0x04/0x3D
+S:0x95:0x05/0x3D
+S:0x96:0x06/0x3D
+S:0x97:0x07/0x3D
+S:0x98:0x08/0x3D
+S:0x99:0x09/0x3D
+S:0x9A:0x0A/0x3D
+S:0x9B:0x0B/0x3D
+S:0x9C:0x0C/0x3D
+S:0x9D:0x0D/0x3D
+S:0x9E:0x0E/0x3D
+S:0x9F:0x0F/0x3D
+
+# Staffs (_)
+S:0xA0:0x00/0x5F
+S:0xA1:0x01/0x5F
+S:0xA2:0x02/0x5F
+S:0xA3:0x03/0x5F
+S:0xA4:0x04/0x5F
+S:0xA5:0x05/0x5F
+S:0xA6:0x06/0x5F
+S:0xA7:0x07/0x5F
+S:0xA8:0x08/0x5F
+S:0xA9:0x09/0x5F
+S:0xAA:0x0A/0x5F
+S:0xAB:0x0B/0x5F
+S:0xAC:0x0C/0x5F
+S:0xAD:0x0D/0x5F
+S:0xAE:0x0E/0x5F
+S:0xAF:0x0F/0x5F
+
+# Wands (-)
+S:0xB0:0x00/0x2D
+S:0xB1:0x01/0x2D
+S:0xB2:0x02/0x2D
+S:0xB3:0x03/0x2D
+S:0xB4:0x04/0x2D
+S:0xB5:0x05/0x2D
+S:0xB6:0x06/0x2D
+S:0xB7:0x07/0x2D
+S:0xB8:0x08/0x2D
+S:0xB9:0x09/0x2D
+S:0xBA:0x0A/0x2D
+S:0xBB:0x0B/0x2D
+S:0xBC:0x0C/0x2D
+S:0xBD:0x0D/0x2D
+S:0xBE:0x0E/0x2D
+S:0xBF:0x0F/0x2D
+
+# Rods (-)
+S:0xC0:0x00/0x2D
+S:0xC1:0x01/0x2D
+S:0xC2:0x02/0x2D
+S:0xC3:0x03/0x2D
+S:0xC4:0x04/0x2D
+S:0xC5:0x05/0x2D
+S:0xC6:0x06/0x2D
+S:0xC7:0x07/0x2D
+S:0xC8:0x08/0x2D
+S:0xC9:0x09/0x2D
+S:0xCA:0x0A/0x2D
+S:0xCB:0x0B/0x2D
+S:0xCC:0x0C/0x2D
+S:0xCD:0x0D/0x2D
+S:0xCE:0x0E/0x2D
+S:0xCF:0x0F/0x2D
+
+# Scrolls (?)
+S:0xD0:0x00/0x3F
+S:0xD1:0x01/0x3F
+S:0xD2:0x02/0x3F
+S:0xD3:0x03/0x3F
+S:0xD4:0x04/0x3F
+S:0xD5:0x05/0x3F
+S:0xD6:0x06/0x3F
+S:0xD7:0x07/0x3F
+S:0xD8:0x08/0x3F
+S:0xD9:0x09/0x3F
+S:0xDA:0x0A/0x3F
+S:0xDB:0x0B/0x3F
+S:0xDC:0x0C/0x3F
+S:0xDD:0x0D/0x3F
+S:0xDE:0x0E/0x3F
+S:0xDF:0x0F/0x3F
+
+# Potions (!)
+S:0xE0:0x00/0x21
+S:0xE1:0x01/0x21
+S:0xE2:0x02/0x21
+S:0xE3:0x03/0x21
+S:0xE4:0x04/0x21
+S:0xE5:0x05/0x21
+S:0xE6:0x06/0x21
+S:0xE7:0x07/0x21
+S:0xE8:0x08/0x21
+S:0xE9:0x09/0x21
+S:0xEA:0x0A/0x21
+S:0xEB:0x0B/0x21
+S:0xEC:0x0C/0x21
+S:0xED:0x0D/0x21
+S:0xEE:0x0E/0x21
+S:0xEF:0x0F/0x21
+
+# Food (,)
+S:0xF0:0x00/0x2C
+S:0xF1:0x01/0x2C
+S:0xF2:0x02/0x2C
+S:0xF3:0x03/0x2C
+S:0xF4:0x04/0x2C
+S:0xF5:0x05/0x2C
+S:0xF6:0x06/0x2C
+S:0xF7:0x07/0x2C
+S:0xF8:0x08/0x2C
+S:0xF9:0x09/0x2C
+S:0xFA:0x0A/0x2C
+S:0xFB:0x0B/0x2C
+S:0xFC:0x0C/0x2C
+S:0xFD:0x0D/0x2C
+S:0xFE:0x0E/0x2C
+S:0xFF:0x0F/0x2C
+
+
+
+##### Default inventory object colors #####
+
+
+# SKELETON
+E:1:0x01
+
+# BOTTLE
+E:2:0x01
+
+# FIRESTONE
+E:3:0x01
+
+# SPIKE
+E:5:0x02
+
+# CHEST
+E:7:0x02
+
+# JUNK
+E:11:0x01
+
+# BOOMERANG
+E:15:0x07
+
+# SHOT
+E:16:0x0F
+
+# ARROW
+E:17:0x0F
+
+# BOLT
+E:18:0x0F
+
+# BOW
+E:19:0x07
+
+# DIGGING
+E:20:0x02
+
+# HAFTED
+E:21:0x01
+
+# POLEARM
+E:22:0x01
+
+# SWORD
+E:23:0x01
+
+# AXE
+E:24:0x01
+
+# BOOTS
+E:30:0x0F
+
+# GLOVES
+E:31:0x0F
+
+# HELM
+E:32:0x0F
+
+# CROWN
+E:33:0x0F
+
+# SHIELD
+E:34:0x0F
+
+# CLOAK
+E:35:0x0F
+
+# SOFT_ARMOR
+E:36:0x02
+
+# HARD_ARMOR
+E:37:0x02
+
+# DRAG_ARMOR
+E:38:0x02
+
+# LITE
+E:39:0x0B
+
+# AMULET
+E:40:0x03
+
+# RING
+E:45:0x04
+
+# STAFF
+E:55:0x0F
+
+# WAND
+E:65:0x05
+
+# ROD
+E:66:0x0A
+
+# ROD TIP
+E:67:0x0A
+
+# SCROLL
+E:70:0x01
+
+# POTION
+E:71:0x0E
+
+# POTION2
+E:72:0x0E
+
+# FLASK
+E:77:0x0B
+
+# FOOD
+E:80:0x0F
+
+# BOOK
+E:111:0x0E
+
+# SYMBIOTIC_BOOK
+E:112:0x05
+
+# MUSIC_BOOK
+E:113:0x02
+
+# DRUID_BOOK
+E:114:0x0D
+
+# DAEMON BOOK
+E:115:0x03
+
+# POWER BATERIES
+E:4:0x0D
+
+# MAGE STAFFS
+E:6:0x0E
+
+# PARCHEMENT
+E:8:0x03
+
+# CORPSE
+E:9:0x0F
+
+# HYPNOS
+E:99:0x0F
+
+# RANDOM ARTIFACT
+E:102:0x0D
+
+# MUSICAL INSTRUMENT
+E:14:0x0A
+
+# EGG
+E:10:0x03
+
+# BASE RUNE
+E:104:0x0A
+
+# SECONDARY RUNE
+E:105:0x03
+
+# GOLD
+E:100:0x0B
+
+# TOOL
+E:12:0x0A
+
+# TRAPPING KIT
+E:46:0x08
+
+# TOTEM
+E:54:0x08
diff --git a/lib/mods/theme/pref/font.prf b/lib/mods/theme/pref/font.prf
new file mode 100644
index 00000000..505964bd
--- /dev/null
+++ b/lib/mods/theme/pref/font.prf
@@ -0,0 +1,60 @@
+# File: font.prf
+
+#
+# This file defines special attr/char mappings for use in "text" mode
+#
+# This file includes, if appropriate, various "sub-files"
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+## #
+## # OPTION: Display "veins" (white "%") as "normal walls" (white "#").
+## #
+## F:50:0x01/0x23
+## F:51:0x01/0x23
+## F:52:0x01/0x23
+## F:53:0x01/0x23
+
+
+##### Standard font file #####
+
+%:font-xxx.prf
+
+
+##### System Specific Subfiles #####
+
+?:[IOR [EQU $SYS xaw] [EQU $SYS x11] [EQU $SYS gtk]]
+%:font-x11.prf
+
+?:[EQU $SYS glu]
+%:font-glu.prf
+
+?:[EQU $SYS gcu]
+%:font-gcu.prf
+
+?:[EQU $SYS ami]
+%:font-ami.prf
+
+?:[EQU $SYS mac]
+%:font-mac.prf
+
+?:[EQU $SYS win]
+%:font-win.prf
+
+?:[EQU $SYS dos]
+%:font-dos.prf
+
+?:[EQU $SYS ibm]
+%:font-ibm.prf
+
+?:[EQU $SYS emx]
+%:font-emx.prf
+
+?:[EQU $SYS acn]
+%:font-acn.prf
+
+?:1
+
+
diff --git a/lib/mods/theme/pref/graf-ami.prf b/lib/mods/theme/pref/graf-ami.prf
new file mode 100644
index 00000000..d9b1b356
--- /dev/null
+++ b/lib/mods/theme/pref/graf-ami.prf
@@ -0,0 +1,64 @@
+# File: graf-ami.prf
+
+#
+# This file contains color definitions and
+# graphics remapping for the Amiga version.
+#
+# Lars Haugseth <larshau@ifi.uio.no>
+#
+
+
+# Color palette - Graphics
+V:0:0x01:0x00:0x00:0x00
+V:1:0x01:0xF0:0xE0:0xD0
+V:2:0x01:0x80:0x80:0x80
+V:3:0x01:0x50:0x50:0x50
+V:4:0x01:0xE0:0xB0:0x00
+V:5:0x01:0xC0:0xA0:0x70
+V:6:0x01:0x80:0x60:0x40
+V:7:0x01:0x40:0x30:0x20
+V:8:0x01:0x00:0xA0:0xF0
+V:9:0x01:0x00:0x00:0xF0
+V:10:0x01:0x00:0x00:0x70
+V:11:0x01:0xF0:0x00:0x00
+V:12:0x01:0x80:0x00:0x00
+V:13:0x01:0x90:0x00:0xB0
+V:14:0x01:0x00:0x60:0x10
+V:15:0x01:0x60:0xF0:0x40
+
+
+# Color palette - Text
+V:16:0x01:0x00:0x00:0x00
+V:17:0x01:0xFF:0xFF:0xFF
+V:18:0x01:0xC7:0xC7:0xC7
+V:19:0x01:0xFF:0x92:0x00
+V:20:0x01:0xFF:0x00:0x00
+V:21:0x01:0x00:0xCD:0x00
+V:22:0x01:0x00:0x00:0xFE
+V:23:0x01:0xC8:0x64:0x00
+V:24:0x01:0x8A:0x8A:0x8A
+V:25:0x01:0xE0:0xE0:0xE0
+V:26:0x01:0xA5:0x00:0xFF
+V:27:0x01:0xFF:0xFD:0x00
+V:28:0x01:0xFF:0x00:0xBC
+V:29:0x01:0x00:0xFF:0x00
+V:30:0x01:0x00:0xC8:0xFF
+V:31:0x01:0xFF:0xCC:0x80
+
+
+# Standard file
+%:graf-xxx.prf
+
+
+### Feature attr/char definitions
+
+# nothing
+F:0:0x01/0x20
+
+# open floor
+F:1:0x81/0x8E
+
+# invis trap
+F:2:0x81/0x8E
+
+
diff --git a/lib/mods/theme/pref/graf-dos.prf b/lib/mods/theme/pref/graf-dos.prf
new file mode 100644
index 00000000..41f38c76
--- /dev/null
+++ b/lib/mods/theme/pref/graf-dos.prf
@@ -0,0 +1,15 @@
+# File: graf-win.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
diff --git a/lib/mods/theme/pref/graf-ibm.prf b/lib/mods/theme/pref/graf-ibm.prf
new file mode 100644
index 00000000..eee54a13
--- /dev/null
+++ b/lib/mods/theme/pref/graf-ibm.prf
@@ -0,0 +1,6237 @@
+# File: graf-ibm.prf
+
+# This file defines special attr/char mappings for use in the pseudo
+# graphics mode using character generator font redefinitions. It can
+# also be used with X11/XAW/GTK ports by generating a bdf (then pcf)
+# file from lib/xtra/angband.fnt. How to do so is beyond the scope of
+# this file.
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+##### Special attr/char values #####
+
+## # Unused
+## S:0x00:0x00/0x40
+## S:0x01:0x01/0x40
+## S:0x02:0x02/0x40
+## S:0x03:0x03/0x40
+## S:0x04:0x04/0x40
+## S:0x05:0x05/0x40
+## S:0x06:0x06/0x40
+## S:0x07:0x07/0x40
+## S:0x08:0x08/0x40
+## S:0x09:0x09/0x40
+## S:0x0A:0x0A/0x40
+## S:0x0B:0x0B/0x40
+## S:0x0C:0x0C/0x40
+## S:0x0D:0x0D/0x40
+## S:0x0E:0x0E/0x40
+## S:0x0F:0x0F/0x40
+
+## # Unused
+## S:0x10:0x00/0x40
+## S:0x11:0x01/0x40
+## S:0x12:0x02/0x40
+## S:0x13:0x03/0x40
+## S:0x14:0x04/0x40
+## S:0x15:0x05/0x40
+## S:0x16:0x06/0x40
+## S:0x17:0x07/0x40
+## S:0x18:0x08/0x40
+## S:0x19:0x09/0x40
+## S:0x1A:0x0A/0x40
+## S:0x1B:0x0B/0x40
+## S:0x1C:0x0C/0x40
+## S:0x1D:0x0D/0x40
+## S:0x1E:0x0E/0x40
+## S:0x1F:0x0F/0x40
+
+## # Unused
+## S:0x20:0x00/0x40
+## S:0x21:0x01/0x40
+## S:0x22:0x02/0x40
+## S:0x23:0x03/0x40
+## S:0x24:0x04/0x40
+## S:0x25:0x05/0x40
+## S:0x26:0x06/0x40
+## S:0x27:0x07/0x40
+## S:0x28:0x08/0x40
+## S:0x29:0x09/0x40
+## S:0x2A:0x0A/0x40
+## S:0x2B:0x0B/0x40
+## S:0x2C:0x0C/0x40
+## S:0x2D:0x0D/0x40
+## S:0x2E:0x0E/0x40
+## S:0x2F:0x0F/0x40
+
+# Spells (*)
+S:0x30:0x00/0x2A
+S:0x31:0x01/0x2A
+S:0x32:0x02/0x2A
+S:0x33:0x03/0x2A
+S:0x34:0x04/0x2A
+S:0x35:0x05/0x2A
+S:0x36:0x06/0x2A
+S:0x37:0x07/0x2A
+S:0x38:0x08/0x2A
+S:0x39:0x09/0x2A
+S:0x3A:0x0A/0x2A
+S:0x3B:0x0B/0x2A
+S:0x3C:0x0C/0x2A
+S:0x3D:0x0D/0x2A
+S:0x3E:0x0E/0x2A
+S:0x3F:0x0F/0x2A
+
+# Spells (|)
+S:0x40:0x00/0x7C
+S:0x41:0x01/0x7C
+S:0x42:0x02/0x7C
+S:0x43:0x03/0x7C
+S:0x44:0x04/0x7C
+S:0x45:0x05/0x7C
+S:0x46:0x06/0x7C
+S:0x47:0x07/0x7C
+S:0x48:0x08/0x7C
+S:0x49:0x09/0x7C
+S:0x4A:0x0A/0x7C
+S:0x4B:0x0B/0x7C
+S:0x4C:0x0C/0x7C
+S:0x4D:0x0D/0x7C
+S:0x4E:0x0E/0x7C
+S:0x4F:0x0F/0x7C
+
+# Spells (-)
+S:0x50:0x00/0x2D
+S:0x51:0x01/0x2D
+S:0x52:0x02/0x2D
+S:0x53:0x03/0x2D
+S:0x54:0x04/0x2D
+S:0x55:0x05/0x2D
+S:0x56:0x06/0x2D
+S:0x57:0x07/0x2D
+S:0x58:0x08/0x2D
+S:0x59:0x09/0x2D
+S:0x5A:0x0A/0x2D
+S:0x5B:0x0B/0x2D
+S:0x5C:0x0C/0x2D
+S:0x5D:0x0D/0x2D
+S:0x5E:0x0E/0x2D
+S:0x5F:0x0F/0x2D
+
+# Spells (/)
+S:0x60:0x00/0x2F
+S:0x61:0x01/0x2F
+S:0x62:0x02/0x2F
+S:0x63:0x03/0x2F
+S:0x64:0x04/0x2F
+S:0x65:0x05/0x2F
+S:0x66:0x06/0x2F
+S:0x67:0x07/0x2F
+S:0x68:0x08/0x2F
+S:0x69:0x09/0x2F
+S:0x6A:0x0A/0x2F
+S:0x6B:0x0B/0x2F
+S:0x6C:0x0C/0x2F
+S:0x6D:0x0D/0x2F
+S:0x6E:0x0E/0x2F
+S:0x6F:0x0F/0x2F
+
+# Spells (\)
+S:0x70:0x00/0x5C
+S:0x71:0x01/0x5C
+S:0x72:0x02/0x5C
+S:0x73:0x03/0x5C
+S:0x74:0x04/0x5C
+S:0x75:0x05/0x5C
+S:0x76:0x06/0x5C
+S:0x77:0x07/0x5C
+S:0x78:0x08/0x5C
+S:0x79:0x09/0x5C
+S:0x7A:0x0A/0x5C
+S:0x7B:0x0B/0x5C
+S:0x7C:0x0C/0x5C
+S:0x7D:0x0D/0x5C
+S:0x7E:0x0E/0x5C
+S:0x7F:0x0F/0x5C
+
+# Amulets
+S:0x80:0x00/0xE7
+S:0x81:0x01/0xE7
+S:0x82:0x02/0xE7
+S:0x83:0x03/0xE7
+S:0x84:0x04/0xE7
+S:0x85:0x05/0xE7
+S:0x86:0x06/0xE7
+S:0x87:0x07/0xE7
+S:0x88:0x08/0xE7
+S:0x89:0x09/0xE7
+S:0x8A:0x0A/0xE7
+S:0x8B:0x0B/0xE7
+S:0x8C:0x0C/0xE7
+S:0x8D:0x0D/0xE7
+S:0x8E:0x0E/0xE7
+S:0x8F:0x0F/0xE7
+
+# Rings
+S:0x90:0x00/0xE8
+S:0x91:0x01/0xE8
+S:0x92:0x02/0xE8
+S:0x93:0x03/0xE8
+S:0x94:0x04/0xE8
+S:0x95:0x05/0xE8
+S:0x96:0x06/0xE8
+S:0x97:0x07/0xE8
+S:0x98:0x08/0xE8
+S:0x99:0x09/0xE8
+S:0x9A:0x0A/0xE8
+S:0x9B:0x0B/0xE8
+S:0x9C:0x0C/0xE8
+S:0x9D:0x0D/0xE8
+S:0x9E:0x0E/0xE8
+S:0x9F:0x0F/0xE8
+
+# Staffs
+S:0xA0:0x00/0xE9
+S:0xA1:0x01/0xE9
+S:0xA2:0x02/0xE9
+S:0xA3:0x03/0xE9
+S:0xA4:0x04/0xE9
+S:0xA5:0x05/0xE9
+S:0xA6:0x06/0xE9
+S:0xA7:0x07/0xE9
+S:0xA8:0x08/0xE9
+S:0xA9:0x09/0xE9
+S:0xAA:0x0A/0xE9
+S:0xAB:0x0B/0xE9
+S:0xAC:0x0C/0xE9
+S:0xAD:0x0D/0xE9
+S:0xAE:0x0E/0xE9
+S:0xAF:0x0F/0xE9
+
+# Wands
+S:0xB0:0x00/0xEA
+S:0xB1:0x01/0xEA
+S:0xB2:0x02/0xEA
+S:0xB3:0x03/0xEA
+S:0xB4:0x04/0xEA
+S:0xB5:0x05/0xEA
+S:0xB6:0x06/0xEA
+S:0xB7:0x07/0xEA
+S:0xB8:0x08/0xEA
+S:0xB9:0x09/0xEA
+S:0xBA:0x0A/0xEA
+S:0xBB:0x0B/0xEA
+S:0xBC:0x0C/0xEA
+S:0xBD:0x0D/0xEA
+S:0xBE:0x0E/0xEA
+S:0xBF:0x0F/0xEA
+
+# Rods
+S:0xC0:0x00/0xEB
+S:0xC1:0x01/0xEB
+S:0xC2:0x02/0xEB
+S:0xC3:0x03/0xEB
+S:0xC4:0x04/0xEB
+S:0xC5:0x05/0xEB
+S:0xC6:0x06/0xEB
+S:0xC7:0x07/0xEB
+S:0xC8:0x08/0xEB
+S:0xC9:0x09/0xEB
+S:0xCA:0x0A/0xEB
+S:0xCB:0x0B/0xEB
+S:0xCC:0x0C/0xEB
+S:0xCD:0x0D/0xEB
+S:0xCE:0x0E/0xEB
+S:0xCF:0x0F/0xEB
+
+# Scrolls
+S:0xD0:0x00/0xEC
+S:0xD1:0x01/0xEC
+S:0xD2:0x02/0xEC
+S:0xD3:0x03/0xEC
+S:0xD4:0x04/0xEC
+S:0xD5:0x05/0xEC
+S:0xD6:0x06/0xEC
+S:0xD7:0x07/0xEC
+S:0xD8:0x08/0xEC
+S:0xD9:0x09/0xEC
+S:0xDA:0x0A/0xEC
+S:0xDB:0x0B/0xEC
+S:0xDC:0x0C/0xEC
+S:0xDD:0x0D/0xEC
+S:0xDE:0x0E/0xEC
+S:0xDF:0x0F/0xEC
+
+# Potions
+S:0xE0:0x00/0xED
+S:0xE1:0x01/0xED
+S:0xE2:0x02/0xED
+S:0xE3:0x03/0xED
+S:0xE4:0x04/0xED
+S:0xE5:0x05/0xED
+S:0xE6:0x06/0xED
+S:0xE7:0x07/0xED
+S:0xE8:0x08/0xED
+S:0xE9:0x09/0xED
+S:0xEA:0x0A/0xED
+S:0xEB:0x0B/0xED
+S:0xEC:0x0C/0xED
+S:0xED:0x0D/0xED
+S:0xEE:0x0E/0xED
+S:0xEF:0x0F/0xED
+
+# Food
+S:0xF0:0x00/0xEE
+S:0xF1:0x01/0xEE
+S:0xF2:0x02/0xEE
+S:0xF3:0x03/0xEE
+S:0xF4:0x04/0xEE
+S:0xF5:0x05/0xEE
+S:0xF6:0x06/0xEE
+S:0xF7:0x07/0xEE
+S:0xF8:0x08/0xEE
+S:0xF9:0x09/0xEE
+S:0xFA:0x0A/0xEE
+S:0xFB:0x0B/0xEE
+S:0xFC:0x0C/0xEE
+S:0xFD:0x0D/0xEE
+S:0xFE:0x0E/0xEE
+S:0xFF:0x0F/0xEE
+
+
+##### Feature attr/char definitions #####
+
+# nothing
+# F:0:0x01/0x20
+
+# open floor
+F:1:0x01/0xB5
+
+# fountain
+F:2:0x0E/0xC8
+
+# glyph of warding
+F:3:0x0B/0xC6
+
+# open door
+F:4:0x0F/0xB9
+
+# broken door
+F:5:0x0F/0xBA
+
+# up staircase
+F:6:0x01/0xB6
+
+# down staircase
+F:7:0x01/0xB7
+
+# quest entrance
+F:8:0x0B/0xB7
+
+# quest exit
+F:9:0x0B/0xB6
+
+# quest down level
+F:10:0x04/0xB7
+
+# quest up level
+F:11:0x04/0xB6
+
+# town exit
+F:12:0x05/0xB7
+
+# shaft down
+F:13:0x0F/0xB7
+
+# shaft up
+F:14:0x0F/0xB6
+
+# fountain
+F:15:0x08/0xC8
+
+# web
+F:16:0x0B/0xCA
+
+# trap
+F:17:0x01/0xC7
+
+# door
+F:32:0x0F/0xB8
+
+# locked door
+F:33:0x0F/0xB8
+
+# locked door
+F:34:0x0F/0xB8
+
+# locked door
+F:35:0x0F/0xB8
+
+# locked door
+F:36:0x0F/0xB8
+
+# locked door
+F:37:0x0F/0xB8
+
+# locked door
+F:38:0x0F/0xB8
+
+# locked door
+F:39:0x0F/0xB8
+
+# jammed door
+F:40:0x0F/0xB8
+
+# jammed door
+F:41:0x0F/0xB8
+
+# jammed door
+F:42:0x0F/0xB8
+
+# jammed door
+F:43:0x0F/0xB8
+
+# jammed door
+F:44:0x0F/0xB8
+
+# jammed door
+F:45:0x0F/0xB8
+
+# jammed door
+F:46:0x0F/0xB8
+
+# jammed door
+F:47:0x0F/0xB8
+
+# secret door
+F:48:0x02/0xBC
+
+# pile of rubble
+F:49:0x02/0xBB
+
+# magma vein
+F:50:0x01/0xBC
+
+# quartz vein
+F:51:0x09/0xBC
+
+# magma vein
+F:52:0x01/0xBC
+
+# quartz vein
+F:53:0x09/0xBC
+
+# magma vein with treasure
+F:54:0x03/0xBC
+
+# quartz vein with treasure
+F:55:0x03/0xBC
+
+# granite wall
+F:56:0x02/0xBC
+
+# granite wall
+F:57:0x02/0xBC
+
+# granite wall
+F:58:0x02/0xBC
+
+# granite wall
+F:59:0x02/0xBC
+
+# permanent wall
+F:60:0x02/0xBC
+
+# permanent wall
+F:61:0x02/0xBC
+
+# permanent wall
+F:62:0x02/0xBC
+
+# permanent wall
+F:63:0x02/0xBC
+
+# explosive rune
+F:64:0x0C/0xC6
+
+# Straight Road startpoint
+F:65:0x01/0xCA
+
+# section of the Straight Road
+F:66:0x0E/0xCA
+
+# section of the Straight Road
+F:67:0x06/0xCA
+
+# section of the Straight Road
+F:68:0x0E/0xCA
+
+# section of the Straight Road
+F:69:0x06/0xCA
+
+# section of the Straight Road
+F:70:0x09/0xCA
+
+# section of the Straight Road (discharged)
+F:71:0x09/0xCA
+
+# Straight Road exit
+F:72:0x01/0xCA
+
+# corrupted section of the Straight Road
+F:73:0x08/0xCA
+
+# Building
+F:74:0x0F/0xC5
+
+# permanent wall
+F:75:0x02/0xBC
+
+# permanent wall
+F:76:0x02/0xBC
+
+# permanent wall
+F:77:0x02/0xBC
+
+# permanent wall
+F:78:0x02/0xBC
+
+# stream of shallow water
+F:84:0x0E/0xCB
+
+# pool of deep lava
+F:85:0x04/0xCB
+
+# stream of shallow lava
+F:86:0x0C/0xCB
+
+# dark pit
+F:87:0x08/0xD0
+
+# dirt
+F:88:0x07/0xB5
+
+# patch of grass
+F:89:0x0D/0xC9
+
+# ice
+F:90:0x01/0xD0
+
+# sand
+F:91:0x0F/0xB5
+
+# dead tree
+F:92:0x08/0xCC
+
+# ash
+F:93:0x02/0xB5
+
+# mud
+F:94:0x07/0xB5
+
+# ice wall
+F:95:0x01/0xCF
+
+# tree
+F:96:0x05/0xCC
+
+# mountain chain
+F:97:0x02/0xCE
+
+# sandwall
+F:98:0x0F/0xCF
+
+# sandwall
+F:99:0x0F/0xCF
+
+# sandwall with treasure
+F:100:0x03/0xCF
+
+# high mountain chain
+F:101:0x01/0xCE
+
+# nether mist
+F:102:0x0A/0xCA
+
+# Void Jumpgate
+F:160:0x0A/0xB9
+
+# Altar of Being
+F:161:0x09/0xD1
+
+# Altar of Winds
+F:162:0x0E/0xD1
+
+# Altar of Force
+F:163:0x0C/0xD1
+
+# Altar of Darkness
+F:164:0x08/0xD1
+
+# Altar of Nature
+# F:165:0x05/0x30
+
+# floor
+F:172:0x01/0xB5
+
+# Underground Tunnel
+F:173:0x02/0xB9
+
+# stream of tainted water
+F:174:0x0A/0xCB
+
+# monster trap
+F:175:0x0A/0xC6
+
+# Void Jumpgate
+F:176:0x0A/0xB9
+
+# lava wall
+F:177:0x0C/0xBC
+
+# Great Fire
+F:178:0x0C/0xCB
+
+# path to the next area
+F:179:0x01/0xB7
+
+# path to the previous area
+F:180:0x01/0xB6
+
+# field
+F:181:0x05/0xB5
+
+# Ekkaia, the Encircling Sea
+F:182:0x06/0xCB
+
+# pool of deep water
+F:187:0x06/0xCB
+
+# glass wall
+F:188:0x0E/0xD0
+
+# illusion wall
+F:189:0x02/0xBC
+
+# Grass roof
+F:190:0x0F/0xCA
+
+# grass roof top
+F:191:0x0F/0xCA
+
+# grass roof chimney
+F:192:0x0F/0xCA
+
+# brick roof
+F:193:0x04/0xCF
+
+# brick roof top
+F:194:0x04/0xCF
+
+# brick roof chimney
+F:195:0x04/0xCF
+
+# window
+F:196:0x01/0x4F
+
+# small window
+F:197:0x01/0x6F
+
+# rain barrel
+F:198:0x02/0xBC
+
+# grass with flowers
+F:199:0x04/0xC9
+
+# cobblestone road
+F:200:0x02/0xB5
+
+# cobblestone with outlet
+F:201:0x02/0xB5
+
+# small tree
+F:202:0x0D/0xCD
+
+# town
+F:203:0x01/0xC5
+
+# Underground Tunnel
+F:204:0x02/0xB9
+
+# a blazing fire
+F:205:0x0C/0xCB
+
+# pile of rubble
+F:206:0x02/0xBB
+
+# rocky ground
+F:207:0x02/0xB5
+
+# cloud-like vapour
+F:208:0x09/0xCA
+
+# condensing water
+F:209:0x0E/0xCB
+
+# dense mist
+F:210:0x01/0xCA
+
+# hail-stone wall
+F:211:0x09/0xBC
+
+
+##### Building attr/char definitions #####
+
+# General Store
+B:0:0x0F/0xBD
+
+# Armoury
+B:1:0x02/0xBE
+
+# Weaponsmith
+B:2:0x01/0xBF
+
+# Temple
+B:3:0x05/0xC0
+
+# Alchemy shop
+B:4:0x06/0xC1
+
+# Magic shop
+B:5:0x04/0xC4
+
+# Black Market
+B:6:0x08/0xC3
+
+# Home
+B:7:0x0B/0xB8
+
+# Book Store
+B:8:0x03/0xC2
+
+# Pet Shop
+B:9:0x06/0xB8
+
+# Mayor's Office
+B:10:0x03/0xB8
+
+# Inn
+B:11:0x01/0xB8
+
+# The Soothsayer
+B:12:0x0E/0xB8
+
+# Library
+B:13:0x0F/0xC2
+
+# Castle
+B:14:0x03/0xB8
+
+# Casino
+B:15:0x02/0xB8
+
+# Beastmaster Shanty
+B:16:0x05/0xB8
+
+# Fighters Hall
+B:17:0x02/0xB8
+
+# Tower of Magery
+B:18:0x06/0xB8
+
+# Inner Temple
+B:19:0x0D/0xC0
+
+# Paladins Guild
+B:20:0x05/0xB8
+
+# Rangers Guild
+B:21:0x07/0xB8
+
+# Thunderlords' Nest
+B:22:0x0F/0xB8
+
+# The Mirror
+B:23:0x0F/0xB8
+
+# Seat of Ruling
+B:24:0x0F/0xCC
+
+# Wizards Spire
+B:25:0x0F/0xB8
+
+# Priests Circle
+B:26:0x03/0xB8
+
+# Tower of the King
+B:27:0x0F/0xB8
+
+# Library
+B:28:0x0F/0xC2
+
+# The White Tree
+B:29:0x01/0xCC
+
+# Craftsmaster
+B:30:0x02/0xB8
+
+# Earth-Dome (Nature)
+B:31:0x0F/0xB8
+
+# Minstrels Haven
+B:32:0x0F/0xB8
+
+# Star-Dome
+B:33:0x0F/0xB8
+
+# Valarin Temple
+B:34:0x0F/0xC0
+
+# Sea-Dome
+B:35:0x0F/0xB8
+
+# The Golden Flower
+B:36:0x0F/0xB8
+
+# The Fountain
+B:37:0x0F/0xC8
+
+# Axe Smith
+B:38:0x01/0xBF
+
+# Hafted Smith
+B:39:0x01/0xBF
+
+# Polearm Smith
+B:40:0x01/0xBF
+
+# Sword Smith
+B:41:0x01/0xBF
+
+# Rare Jewelry Shop
+B:42:0x0A/0xC4
+
+# Jewelry Shop
+B:43:0x0B/0xC4
+
+# Footwear Shop
+B:44:0x04/0xBE
+
+# Rare Footwear Shop
+B:45:0x04/0xBE
+
+# Library
+B:46:0x0B/0xC2
+
+# Forbidden Library
+B:47:0x0A/0xC2
+
+# Expensive Black Market
+B:48:0x0A/0xC3
+
+# Common Shop
+B:49:0x0F/0xBD
+
+# Dragon Hunter
+B:50:0x0A/0xBE
+
+# Speed Ring Market
+B:51:0x0D/0xC4
+
+# Scribe
+B:52:0x0E/0xC1
+
+# Potion Store
+B:53:0x0E/0xC1
+
+# Recaller
+B:54:0x06/0xB8
+
+# Master Archer
+B:55:0x05/0xBF
+
+# Merchants Guild
+B:56:0x05/0xB8
+
+# The Mathom-house
+B:57:0x05/0xB8
+
+# The Prancing Pony
+B:58:0x01/0xB8
+
+# Mining Supply store
+B:59:0x02/0xB8
+
+
+##### Object attr/char definitions #####
+
+# something
+# K:0:0x01/0x26
+
+# Blindness
+K:1:0x00/0xEE
+
+# Paranoia
+K:2:0x00/0xEE
+
+# Confusion
+K:3:0x00/0xEE
+
+# Hallucination
+K:4:0x00/0xEE
+
+# Cure Poison
+K:5:0x00/0xEE
+
+# Cure Blindness
+K:6:0x00/0xEE
+
+# Cure Paranoia
+K:7:0x00/0xEE
+
+# Cure Confusion
+K:8:0x00/0xEE
+
+# Weakness
+K:9:0x00/0xEE
+
+# Unhealth
+K:10:0x00/0xEE
+
+# Restore Constitution
+K:11:0x00/0xEE
+
+# Restoring
+K:12:0x00/0xEE
+
+# Stupidity
+K:13:0x00/0xEE
+
+# Naivety
+K:14:0x00/0xEE
+
+# Poison
+K:15:0x00/0xEE
+
+# Sickness
+K:16:0x00/0xEE
+
+# Paralysis
+K:17:0x00/0xEE
+
+# Restore Strength
+K:18:0x00/0xEE
+
+# Disease
+K:19:0x00/0xEE
+
+# Cure Serious Wounds
+K:20:0x00/0xEE
+
+# & Ration~ of Food
+K:21:0x0F/0xF2
+
+# & Hard Biscuit~
+K:22:0x0F/0xF2
+
+# & Strip~ of Venison
+K:23:0x07/0xF2
+
+# & Slime Mold~
+K:24:0x05/0xF2
+
+# & Lembas~
+K:25:0x0E/0xF2
+
+# & Pint~ of Fine Ale
+K:26:0x0B/0xED
+
+# & Pint~ of Fine Wine
+K:27:0x04/0xED
+
+# & Mattock~
+K:28:0x08/0xD9
+
+# & Blue Stone~
+K:29:0x0E/0xE7
+
+# & Broken Dagger~
+K:30:0x08/0xDC
+
+# & Bastard Sword~
+K:31:0x09/0xDC
+
+# & Scimitar~
+K:32:0x09/0xDC
+
+# & Tulwar~
+K:33:0x09/0xDC
+
+# & Broad Sword~
+K:34:0x09/0xDC
+
+# & Short Sword~
+K:35:0x09/0xDC
+
+# & Blade~ of Chaos
+K:36:0x0A/0xDC
+
+# & Two-Handed Sword~
+K:37:0x09/0xDC
+
+# & Main Gauche~
+K:38:0x09/0xDC
+
+# & Cutlass~
+K:39:0x09/0xDC
+
+# & Executioner's Sword~
+K:40:0x04/0xDC
+
+# & Katana~
+K:41:0x09/0xDC
+
+# & Long Sword~
+K:42:0x09/0xDC
+
+# & Dagger~
+K:43:0x09/0xDC
+
+# & Rapier~
+K:44:0x09/0xDC
+
+# & Sabre~
+K:45:0x09/0xDC
+
+# & Small Sword~
+K:46:0x09/0xDC
+
+# & Broken Sword~
+K:47:0x08/0xDC
+
+# & Ball-and-Chain~
+K:48:0x08/0xDA
+
+# & Whip~
+K:49:0x08/0xDA
+
+# & Flail~
+K:50:0x08/0xDA
+
+# & Two-Handed Flail~
+K:51:0x0B/0xDA
+
+# & Morning Star~
+K:52:0x08/0xDA
+
+# & Mace~
+K:53:0x08/0xDA
+
+# & Quarterstaff~
+K:54:0x0F/0xDA
+
+# & War Hammer~
+K:55:0x08/0xDA
+
+# & Lead-Filled Mace~
+K:56:0x08/0xDA
+
+# & Mace~ of Disruption
+K:57:0x0A/0xDA
+
+# & Lucerne Hammer~
+K:58:0x0E/0xDA
+
+# & Beaked Axe~
+K:59:0x02/0xDB
+
+# & Glaive~
+K:60:0x02/0xDB
+
+# & Halberd~
+K:61:0x02/0xDB
+
+# & Awl-Pike~
+K:62:0x02/0xDB
+
+# & Pike~
+K:63:0x02/0xDB
+
+# & Spear~
+K:64:0x02/0xDB
+
+# & Trident~
+K:65:0x0B/0xDB
+
+# & Lance~
+K:66:0x02/0xDB
+
+# & Great Axe~
+K:67:0x02/0xDB
+
+# & Battle Axe~
+K:68:0x02/0xDB
+
+# & Lochaber Axe~
+K:69:0x08/0xDB
+
+# & Broad Axe~
+K:70:0x02/0xDB
+
+# & Scythe~
+K:71:0x02/0xDB
+
+# & Scythe~ of Slicing
+K:72:0x04/0xDB
+
+# & Short Bow~
+K:73:0x0F/0xD8
+
+# & Long Bow~
+K:74:0x0F/0xD8
+
+# & Light Crossbow~
+K:75:0x02/0xD8
+
+# & Heavy Crossbow~
+K:76:0x02/0xD8
+
+# & Sling~
+K:77:0x07/0xD8
+
+# & Arrow~
+K:78:0x0F/0xD7
+
+# & Seeker Arrow~
+K:79:0x0D/0xD7
+
+# & Bolt~
+K:80:0x02/0xD7
+
+# & Seeker Bolt~
+K:81:0x0E/0xD7
+
+# & Rounded Pebble~
+K:82:0x02/0xD6
+
+# & Iron Shot~
+K:83:0x02/0xD6
+
+# & Shovel~
+K:84:0x02/0xD9
+
+# & Gnomish Shovel~
+K:85:0x0D/0xD9
+
+# & Dwarven Shovel~
+K:86:0x0E/0xD9
+
+# & Pick~
+K:87:0x02/0xD9
+
+# & Orcish Pick~
+K:88:0x05/0xD9
+
+# & Dwarven Pick~
+K:89:0x06/0xD9
+
+# & Elven Cloak~
+K:90:0x0D/0xE2
+
+# & Pair~ of Soft Leather Boots
+K:91:0x0F/0xDD
+
+# & Pair~ of Hard Leather Boots
+K:92:0x0F/0xDD
+
+# & Pair~ of Metal Shod Boots
+K:93:0x02/0xDD
+
+# & Hard Leather Cap~
+K:94:0x07/0xDF
+
+# & Metal Cap~
+K:95:0x02/0xDF
+
+# & Iron Helm~
+K:96:0x02/0xDF
+
+# & Steel Helm~
+K:97:0x09/0xDF
+
+# & Iron Crown~
+K:98:0x02/0xE0
+
+# & Golden Crown~
+K:99:0x0B/0xE0
+
+# & Jewel Encrusted Crown~
+K:100:0x0A/0xE0
+
+# & Robe~
+K:101:0x06/0xE3
+
+# & Filthy Rag~
+K:102:0x08/0xE3
+
+# Soft Leather Armour~
+K:103:0x0F/0xE3
+
+# Soft Studded Leather~
+K:104:0x0F/0xE3
+
+# Hard Leather Armour~
+K:105:0x0F/0xE3
+
+# Hard Studded Leather~
+K:106:0x0F/0xE3
+
+# Leather Scale Mail~
+K:107:0x0F/0xE3
+
+# Metal Scale Mail~
+K:108:0x02/0xE4
+
+# Chain Mail~
+K:109:0x02/0xE4
+
+# Rusty Chain Mail~
+K:110:0x04/0xE4
+
+# Augmented Chain Mail~
+K:111:0x02/0xE4
+
+# Bar Chain Mail~
+K:112:0x02/0xE4
+
+# Metal Brigandine Armour~
+K:113:0x02/0xE4
+
+# Partial Plate Armour~
+K:114:0x09/0xE4
+
+# Metal Lamellar Armour~
+K:115:0x09/0xE4
+
+# Full Plate Armour~
+K:116:0x09/0xE4
+
+# Ribbed Plate Armour~
+K:117:0x09/0xE4
+
+# Adamantite Plate Mail~
+K:118:0x0D/0xE4
+
+# Mithril Plate Mail~
+K:119:0x0E/0xE4
+
+# Mithril Chain Mail~
+K:120:0x0E/0xE4
+
+# Double Chain Mail~
+K:121:0x02/0xE4
+
+# & Shield~ of Deflection
+K:122:0x0E/0xE1
+
+# & Cloak~
+K:123:0x05/0xE2
+
+# & Shadow Cloak~
+K:124:0x08/0xE2
+
+# & Set~ of Leather Gloves
+K:125:0x0F/0xDE
+
+# & Set~ of Gauntlets
+K:126:0x0F/0xDE
+
+# & Set~ of Cesti
+K:127:0x09/0xDE
+
+# & Small Leather Shield~
+K:128:0x0F/0xE1
+
+# & Large Leather Shield~
+K:129:0x0F/0xE1
+
+# & Small Metal Shield~
+K:130:0x02/0xE1
+
+# & Large Metal Shield~
+K:131:0x02/0xE1
+
+# Strength
+K:132:0x00/0xE8
+
+# Dexterity
+K:133:0x00/0xE8
+
+# Constitution
+K:134:0x00/0xE8
+
+# Intelligence
+K:135:0x00/0xE8
+
+# Speed
+K:136:0x00/0xE8
+
+# Searching
+K:137:0x00/0xE8
+
+# Teleportation
+K:138:0x00/0xE8
+
+# Slow Digestion
+K:139:0x00/0xE8
+
+# Fire Resistance
+K:140:0x00/0xE8
+
+# Cold Resistance
+K:141:0x00/0xE8
+
+# Levitation
+K:142:0x00/0xE8
+
+# Poison Resistance
+K:143:0x00/0xE8
+
+# Free Action
+K:144:0x00/0xE8
+
+# Weakness
+K:145:0x00/0xE8
+
+# Flames
+K:146:0x00/0xE8
+
+# Acid
+K:147:0x00/0xE8
+
+# Ice
+K:148:0x00/0xE8
+
+# Woe
+K:149:0x00/0xE8
+
+# Stupidity
+K:150:0x00/0xE8
+
+# Damage
+K:151:0x00/0xE8
+
+# Accuracy
+K:152:0x00/0xE8
+
+# Protection
+K:153:0x00/0xE8
+
+# Aggravate Monster
+K:154:0x00/0xE8
+
+# See Invisible
+K:155:0x00/0xE8
+
+# Sustain Strength
+K:156:0x00/0xE8
+
+# Sustain Intelligence
+K:157:0x00/0xE8
+
+# Sustain Wisdom
+K:158:0x00/0xE8
+
+# Sustain Constitution
+K:159:0x00/0xE8
+
+# Sustain Dexterity
+K:160:0x00/0xE8
+
+# Sustain Charisma
+K:161:0x00/0xE8
+
+# Slaying
+K:162:0x00/0xE8
+
+# Brilliance
+K:163:0x00/0xE7
+
+# Charisma
+K:164:0x00/0xE7
+
+# Searching
+K:165:0x00/0xE7
+
+# Teleportation
+K:166:0x00/0xE7
+
+# Slow Digestion
+K:167:0x00/0xE7
+
+# Acid Resistance
+K:168:0x00/0xE7
+
+# Adornment
+K:169:0x00/0xE7
+
+# Double Ring Mail~
+K:170:0x02/0xE4
+
+# the Magi
+K:171:0x00/0xE7
+
+# Doom
+K:172:0x00/0xE7
+
+# Enchant Weapon To-Hit
+K:173:0x00/0xEC
+
+# Enchant Weapon To-Dam
+K:174:0x00/0xEC
+
+# Enchant Armor
+K:175:0x00/0xEC
+
+# Identify
+K:176:0x00/0xEC
+
+# *Identify*
+K:177:0x00/0xEC
+
+# Rumour
+K:178:0x00/0xEC
+
+# Chaos
+K:179:0x00/0xEC
+
+# Remove Curse
+K:180:0x00/0xEC
+
+# Light
+K:181:0x00/0xEC
+
+# Fire
+K:182:0x00/0xEC
+
+# Ice
+K:183:0x00/0xEC
+
+# Summon Monster
+K:184:0x00/0xEC
+
+# Phase Door
+K:185:0x00/0xEC
+
+# Teleportation
+K:186:0x00/0xEC
+
+# Teleport Level
+K:187:0x00/0xEC
+
+# Monster Confusion
+K:188:0x00/0xEC
+
+# Magic Mapping
+K:189:0x00/0xEC
+
+# Rune of Protection
+K:190:0x00/0xEC
+
+# *Remove Curse*
+K:191:0x00/0xEC
+
+# Treasure Detection
+K:192:0x00/0xEC
+
+# Object Detection
+K:193:0x00/0xEC
+
+# Trap Detection
+K:194:0x00/0xEC
+
+# & Sheaf Arrow~
+K:195:0x03/0xD7
+
+# & Mithril Shot~
+K:196:0x0E/0xD6
+
+# Door/Stair Location
+K:197:0x00/0xEC
+
+# Acquirement
+K:198:0x00/0xEC
+
+# *Acquirement*
+K:199:0x00/0xEC
+
+# Mass Genocide
+K:200:0x00/0xEC
+
+# Detect Invisible
+K:201:0x00/0xEC
+
+# Aggravate Monster
+K:202:0x00/0xEC
+
+# Trap Creation
+K:203:0x00/0xEC
+
+# Trap/Door Destruction
+K:204:0x00/0xEC
+
+# Artifact Creation
+K:205:0x00/0xEC
+
+# Recharging
+K:206:0x00/0xEC
+
+# Genocide
+K:207:0x00/0xEC
+
+# Darkness
+K:208:0x00/0xEC
+
+# Protection from Evil
+K:209:0x00/0xEC
+
+# Satisfy Hunger
+K:210:0x00/0xEC
+
+# Dispel Undead
+K:211:0x00/0xEC
+
+# *Enchant Weapon*
+K:212:0x00/0xEC
+
+# Curse Weapon
+K:213:0x00/0xEC
+
+# *Enchant Armor*
+K:214:0x00/0xEC
+
+# Curse Armor
+K:215:0x00/0xEC
+
+# Summon Undead
+K:216:0x00/0xEC
+
+# Blessing
+K:217:0x00/0xEC
+
+# Holy Chant
+K:218:0x00/0xEC
+
+# Holy Prayer
+K:219:0x00/0xEC
+
+# Word of Recall
+K:220:0x00/0xEC
+
+# *Destruction*
+K:221:0x00/0xEC
+
+# Slime Mold Juice
+K:222:0x00/0xED
+
+# Apple Juice
+K:223:0x00/0xED
+
+# Water
+K:224:0x00/0xED
+
+# Strength
+K:225:0x00/0xED
+
+# Weakness
+K:226:0x00/0xED
+
+# Restore Strength
+K:227:0x00/0xED
+
+# Intelligence
+K:228:0x00/0xED
+
+# Stupidity
+K:229:0x00/0xED
+
+# Restore Intelligence
+K:230:0x00/0xED
+
+# Wisdom
+K:231:0x00/0xED
+
+# Naivety
+K:232:0x00/0xED
+
+# Restore Wisdom
+K:233:0x00/0xED
+
+# Charisma
+K:234:0x00/0xED
+
+# Ugliness
+K:235:0x00/0xED
+
+# Restore Charisma
+K:236:0x00/0xED
+
+# Curing
+K:237:0x00/0xED
+
+# Invulnerability
+K:238:0x00/0xED
+
+# New Life
+K:239:0x00/0xED
+
+# Cure Serious Wounds
+K:240:0x00/0xED
+
+# Cure Critical Wounds
+K:241:0x00/0xED
+
+# Healing
+K:242:0x00/0xED
+
+# Constitution
+K:243:0x00/0xED
+
+# Experience
+K:244:0x00/0xED
+
+# Sleep
+K:245:0x00/0xED
+
+# Blindness
+K:246:0x00/0xED
+
+# Booze
+K:247:0x00/0xED
+
+# Poison
+K:248:0x00/0xED
+
+# Speed
+K:249:0x00/0xED
+
+# Slowness
+K:250:0x00/0xED
+
+# Dexterity
+K:251:0x00/0xED
+
+# Restore Dexterity
+K:252:0x00/0xED
+
+# Restore Constitution
+K:253:0x00/0xED
+
+# Lose Memories
+K:254:0x00/0xED
+
+# Salt Water
+K:255:0x00/0xED
+
+# Enlightenment
+K:256:0x00/0xED
+
+# Heroism
+K:257:0x00/0xED
+
+# Berserk Strength
+K:258:0x00/0xED
+
+# Boldness
+K:259:0x00/0xED
+
+# Restore Life Levels
+K:260:0x00/0xED
+
+# Resist Heat
+K:261:0x00/0xED
+
+# Resist Cold
+K:262:0x00/0xED
+
+# Detect Invisible
+K:263:0x00/0xED
+
+# Slow Poison
+K:264:0x00/0xED
+
+# Neutralise Poison
+K:265:0x00/0xED
+
+# Restore Mana
+K:266:0x00/0xED
+
+# Infra-vision
+K:267:0x00/0xED
+
+# Resistance
+K:268:0x00/0xED
+
+# Spell
+K:269:0x00/0xEA
+
+# Manathrust
+K:270:0x00/0xEA
+
+# Fireflash
+K:271:0x00/0xEA
+
+# Firewall
+K:272:0x00/0xEA
+
+# Tidal Wave
+K:273:0x00/0xEA
+
+# Ice Storm
+K:274:0x00/0xEA
+
+# Noxious Cloud
+K:275:0x00/0xEA
+
+# Poison Blood
+K:276:0x00/0xEA
+
+# Thunderstorm
+K:277:0x00/0xEA
+
+# Dig
+K:278:0x00/0xEA
+
+# Stone Prison
+K:279:0x00/0xEA
+
+# Strike
+K:280:0x00/0xEA
+
+# Teleport Away
+K:281:0x00/0xEA
+
+# Summon Animal
+K:282:0x00/0xEA
+
+# Magelock
+K:283:0x00/0xEA
+
+# Slow Monster
+K:284:0x00/0xEA
+
+# Essence of Speed
+K:285:0x00/0xEA
+
+# Banishment
+K:286:0x00/0xEA
+
+# Disperse Magic
+K:287:0x00/0xEA
+
+# Charm
+K:288:0x00/0xEA
+
+# Confuse
+K:289:0x00/0xEA
+
+# Demon Blade
+K:290:0x00/0xEA
+
+# Heal Monster
+K:291:0x00/0xEA
+
+# Haste Monster
+K:292:0x00/0xEA
+
+# & Flight Arrow~
+K:293:0x0B/0xD7
+
+# Spell
+K:300:0x00/0xE9
+
+# Nothing
+K:301:0x00/0xE9
+
+# Globe of Light
+K:302:0x00/0xE9
+
+# Fiery Shield
+K:303:0x00/0xE9
+
+# Remove Curses
+K:304:0x00/0xE9
+
+# Wings of Winds
+K:305:0x00/0xE9
+
+# Shake
+K:306:0x00/0xE9
+
+# Disarm
+K:307:0x00/0xE9
+
+# Teleportation
+K:308:0x00/0xE9
+
+# Probability Travel
+K:309:0x00/0xE9
+
+# Recovery
+K:310:0x00/0xE9
+
+# Healing
+K:311:0x00/0xE9
+
+# Vision
+K:312:0x00/0xE9
+
+# Identify
+K:313:0x00/0xE9
+
+# Sense Hidden
+K:314:0x00/0xE9
+
+# Reveal Ways
+K:315:0x00/0xE9
+
+# Sense Monsters
+K:316:0x00/0xE9
+
+# Genocide
+K:317:0x00/0xE9
+
+# Summon
+K:318:0x00/0xE9
+
+# Wish
+K:320:0x00/0xE9
+
+# Mana
+K:321:0x00/0xE9
+
+# & Tome~ of Magical Energy
+K:330:0x0E/0xEF
+
+# & Tome~ of the Eternal Flame
+K:331:0x0C/0xEF
+
+# & Tome~ of the Blowing Wind
+K:332:0x06/0xEF
+
+# & Tome~ of the Impenetrable Earth
+K:333:0x0F/0xEF
+
+# & Tome~ of the Everrunning Wave
+K:334:0x0E/0xEF
+
+# & Tome~ of Translocation
+K:335:0x0E/0xEF
+
+# & Tome~ of the Tree
+K:336:0x0D/0xEF
+
+# & Tome~ of Knowledge
+K:337:0x08/0xEF
+
+# & Small wooden chest~
+K:338:0x02/0xD5
+
+# & Large wooden chest~
+K:339:0x02/0xD5
+
+# & Small iron chest~
+K:340:0x02/0xD5
+
+# & Large iron chest~
+K:341:0x02/0xD5
+
+# & Small steel chest~
+K:342:0x02/0xD5
+
+# & Large steel chest~
+K:343:0x02/0xD5
+
+# & Ruined chest~
+K:344:0x02/0xD5
+
+# & Iron Spike~
+K:345:0x09/0xD4
+
+# & Wooden Torch~
+K:346:0x07/0xF1
+
+# & Brass Lantern~
+K:347:0x0F/0xE6
+
+# & Flask~ of oil
+K:348:0x0B/0xED
+
+# & Empty Bottle~
+K:349:0x01/0xED
+
+# Havoc
+K:350:0x00/0xEB
+
+# Door/Stair Location
+K:351:0x00/0xEB
+
+# Trap Location
+K:352:0x00/0xEB
+
+# Probing
+K:353:0x00/0xEB
+
+# Recall
+K:354:0x00/0xEB
+
+# Illumination
+K:355:0x00/0xEB
+
+# Light
+K:356:0x00/0xEB
+
+# Lightning Bolts
+K:357:0x00/0xEB
+
+# Frost Bolts
+K:358:0x00/0xEB
+
+# Fire Bolts
+K:359:0x00/0xEB
+
+# Polymorph
+K:360:0x00/0xEB
+
+# Slow Monster
+K:361:0x00/0xEB
+
+# Sleep Monster
+K:362:0x00/0xEB
+
+# Drain Life
+K:363:0x00/0xEB
+
+# Teleport Other
+K:364:0x00/0xEB
+
+# Disarming
+K:365:0x00/0xEB
+
+# Lightning Balls
+K:366:0x00/0xEB
+
+# Cold Balls
+K:367:0x00/0xEB
+
+# Fire Balls
+K:368:0x00/0xEB
+
+# Acid Balls
+K:369:0x00/0xEB
+
+# Acid Bolts
+K:370:0x00/0xEB
+
+# Enlightenment
+K:371:0x00/0xEB
+
+# Perception
+K:372:0x00/0xEB
+
+# Curing
+K:373:0x00/0xEB
+
+# Healing
+K:374:0x00/0xEB
+
+# Detection
+K:375:0x00/0xEB
+
+# Restoration
+K:376:0x00/0xEB
+
+# Speed
+K:377:0x00/0xEB
+
+# Spell
+K:378:0x00/0xE8
+
+# Spell
+K:379:0x00/0xE7
+
+# & Broken Skull~
+K:391:0x01/0xD3
+
+# & Broken Bone~
+K:392:0x01/0xD3
+
+# & Canine Skeleton~
+K:393:0x01/0xD3
+
+# & Rodent Skeleton~
+K:394:0x01/0xD3
+
+# & Human Skeleton~
+K:395:0x01/0xD3
+
+# & Dwarf Skeleton~
+K:396:0x01/0xD3
+
+# & Elf Skeleton~
+K:397:0x01/0xD3
+
+# & Gnome Skeleton~
+K:398:0x01/0xD3
+
+# & Great Hammer~
+K:399:0x08/0xDA
+
+# Black Dragon Scale Mail~
+K:400:0x02/0xE5
+
+# Blue Dragon Scale Mail~
+K:401:0x06/0xE5
+
+# White Dragon Scale Mail~
+K:402:0x01/0xE5
+
+# Red Dragon Scale Mail~
+K:403:0x04/0xE5
+
+# Green Dragon Scale Mail~
+K:404:0x05/0xE5
+
+# Multi-Hued Dragon Scale Mail~
+K:405:0x0A/0xE5
+
+# Pseudo Dragon Scale Mail~
+K:406:0x0A/0xE5
+
+# Law Dragon Scale Mail~
+K:407:0x0E/0xE5
+
+# Bronze Dragon Scale Mail~
+K:408:0x0F/0xE5
+
+# Gold Dragon Scale Mail~
+K:409:0x0B/0xE5
+
+# Chaos Dragon Scale Mail~
+K:410:0x0A/0xE5
+
+# Balance Dragon Scale Mail~
+K:411:0x0A/0xE5
+
+# Power Dragon Scale Mail~
+K:412:0x0A/0xE5
+
+# & Dragon Helm~
+K:413:0x0D/0xDF
+
+# & Dragon Shield~
+K:414:0x0D/0xE1
+
+# Death
+K:415:0x00/0xED
+
+# Ruination
+K:416:0x00/0xED
+
+# Detonations
+K:417:0x00/0xED
+
+# Augmentation
+K:418:0x00/0xED
+
+# *Healing*
+K:419:0x00/0xED
+
+# Life
+K:420:0x00/0xED
+
+# Self Knowledge
+K:421:0x00/0xED
+
+# *Enlightenment*
+K:422:0x00/0xED
+
+# Fear Resistance
+K:425:0x00/0xE8
+
+# Light and Darkness Resistance
+K:426:0x00/0xE8
+
+# Nether Resistance
+K:427:0x00/0xE8
+
+# Nexus Resistance
+K:428:0x00/0xE8
+
+# Sound Resistance
+K:429:0x00/0xE8
+
+# Confusion Resistance
+K:430:0x00/0xE8
+
+# Shard Resistance
+K:431:0x00/0xE8
+
+# Disenchantment Resistance
+K:432:0x00/0xE8
+
+# Chaos Resistance
+K:433:0x00/0xE8
+
+# Blindness Resistance
+K:434:0x00/0xE8
+
+# Lordly Protection
+K:435:0x00/0xE8
+
+# Extra Attacks
+K:436:0x00/0xE8
+
+# Cure Light Wounds
+K:437:0x00/0xED
+
+# Clumsiness
+K:438:0x00/0xED
+
+# Sickliness
+K:439:0x00/0xED
+
+# Map of Bree
+K:440:0x02/0xEC
+
+# Map of Gondolin
+K:441:0x02/0xEC
+
+# Map of Lothlorien
+K:442:0x02/0xEC
+
+# Map of Minas Anor
+K:443:0x02/0xEC
+
+# & Silver Arrow~
+K:465:0x09/0xD7
+
+# & Silver Bolt~
+K:466:0x01/0xD7
+
+# Lightning Resistance
+K:467:0x00/0xE7
+
+# Wisdom
+K:468:0x00/0xE7
+
+# Regeneration
+K:469:0x00/0xE7
+
+# Infravision
+K:470:0x00/0xE7
+
+# Devotion
+K:471:0x00/0xE7
+
+# Weaponmastery
+K:472:0x00/0xE7
+
+# Trickery
+K:473:0x00/0xE7
+
+# Telepathy
+K:474:0x00/0xE7
+
+# Sustenance
+K:475:0x00/0xE7
+
+# & Palantir~
+K:476:0x0B/0xF0
+
+# & Elfstone~
+K:477:0x05/0xE7
+
+# & Jewel~
+K:478:0x01/0xE7
+
+# & Ring~
+K:479:0x00/0xE8
+
+# copper
+K:480:0x07/0xF3
+
+# copper
+K:481:0x07/0xF3
+
+# copper
+K:482:0x07/0xF3
+
+# silver
+K:483:0x02/0xF3
+
+# silver
+K:484:0x02/0xF3
+
+# silver
+K:485:0x02/0xF3
+
+# garnets
+K:486:0x04/0xF4
+
+# garnets
+K:487:0x04/0xF4
+
+# gold
+K:488:0x0B/0xF3
+
+# gold
+K:489:0x0B/0xF3
+
+# gold
+K:490:0x0B/0xF3
+
+# opals
+K:491:0x09/0xF4
+
+# sapphires
+K:492:0x06/0xF4
+
+# rubies
+K:493:0x04/0xF4
+
+# diamonds
+K:494:0x01/0xF4
+
+# emeralds
+K:495:0x05/0xF4
+
+# mithril
+K:496:0x0E/0xF3
+
+# adamantite
+K:497:0x0D/0xF3
+
+# & Mighty Hammer~
+K:498:0x08/0xDA
+
+# & Massive Iron Crown~
+K:499:0x08/0xE0
+
+# & Phial~
+K:500:0x0B/0xF0
+
+# & Star~
+K:501:0x0E/0xF0
+
+# & Arkenstone~
+K:502:0x0C/0xF0
+
+# & Amulet~
+K:503:0x00/0xE7
+
+# & Amulet~
+K:504:0x00/0xE7
+
+# & Necklace~
+K:505:0x00/0xE7
+
+# & Ring~
+K:506:0x00/0xE8
+
+# & Ring~
+K:507:0x00/0xE8
+
+# & Ring~
+K:508:0x00/0xE8
+
+# & Ring~
+K:509:0x00/0xE8
+
+# & Ring~
+K:510:0x00/0xE8
+
+# & Ring~
+K:511:0x0B/0xE8
+
+# Reflection
+K:520:0x00/0xE7
+
+# Anti-Magic
+K:521:0x00/0xE7
+
+# Anti-Teleportation
+K:522:0x00/0xE7
+
+# Resistance
+K:523:0x00/0xE7
+
+# & Zweihander~
+K:524:0x01/0xDC
+
+# & Dwarven Lantern~
+K:525:0x06/0xE6
+
+# Splint Mail~
+K:526:0x08/0xE4
+
+# & Everburning Torch~
+K:527:0x0C/0xF1
+
+# & Trifurcate Spear~
+K:528:0x03/0xDB
+
+# & Three Piece Rod~
+K:529:0x07/0xDA
+
+# & Feanorian Lamp~
+K:530:0x0E/0xE6
+
+# & Fur Cloak~
+K:531:0x09/0xE2
+
+# Water Curing
+K:532:0x00/0xED
+
+# & Hatchet~
+K:533:0x02/0xDB
+
+# Rhino Hide Armour~
+K:535:0x02/0xE3
+
+# Leather Jacket~
+K:536:0x0F/0xE3
+
+# & Sickle~
+K:537:0x02/0xDB
+
+# & Club~
+K:542:0x07/0xDA
+
+# & Broad Spear~
+K:543:0x01/0xDB
+
+# & Khopesh~
+K:544:0x09/0xDC
+
+# & Flamberge~
+K:545:0x09/0xDC
+
+# & Claymore~
+K:546:0x09/0xDC
+
+# & Espadon~
+K:547:0x09/0xDC
+
+# & Great Scimitar~
+K:548:0x09/0xDC
+
+# Arrow
+K:549:0x04/0xF8
+
+# Bolt
+K:550:0x03/0xF8
+
+# & Fauchard~
+K:551:0x02/0xDB
+
+# & Guisarme~
+K:552:0x02/0xDB
+
+# & Heavy Lance~
+K:553:0x02/0xDB
+
+# & Basillard~
+K:554:0x01/0xDC
+
+# Catapult
+K:555:0x0C/0xF8
+
+# Ring Mail~
+K:556:0x02/0xE4
+
+# Cord Armour~
+K:557:0x0B/0xE3
+
+# Paper Armour~
+K:558:0x01/0xE3
+
+# Padded Armour~
+K:559:0x0B/0xE3
+
+# Fumes
+K:560:0x0D/0xF8
+
+# Stone and Hide Armour~
+K:561:0x0F/0xE3
+
+# Magic
+K:562:0x05/0xF8
+
+# Device
+K:563:0x0A/0xF8
+
+# Nothing
+K:564:0x00/0xEC
+
+# Poison
+K:565:0x0D/0xF6
+
+# Nothing
+K:566:0x00/0xEA
+
+# Nothing
+K:567:0x00/0xE8
+
+# Nothing
+K:568:0x00/0xE9
+
+# Nothing
+K:569:0x00/0xEB
+
+# Explosion
+K:570:0x0D/0xF6
+
+# Teleport
+K:571:0x0D/0xF6
+
+# Nothing
+K:572:0x00/0xE7
+
+# & Blood~ of Life
+K:573:0x00/0xED
+
+# Cold
+K:574:0x0D/0xF6
+
+# Fire
+K:575:0x0D/0xF6
+
+# Acid
+K:576:0x0D/0xF6
+
+# & Mage Staff~
+K:577:0x0E/0xE9
+
+# Lightning
+K:578:0x00/0xE8
+
+# Life
+K:579:0x0D/0xF6
+
+# Confusion
+K:580:0x0D/0xF6
+
+# Light
+K:581:0x0D/0xF6
+
+# & Ring~
+K:582:0x0B/0xE8
+
+# Invisibility
+K:583:0x00/0xED
+
+# Chaos
+K:584:0x0D/0xF6
+
+# Corruption
+K:585:0x00/0xED
+
+# Invisibility
+K:586:0x00/0xE8
+
+# Time
+K:587:0x0D/0xF6
+
+# Deep Thoughts
+K:588:0x03/0xEC
+
+# More Deep Thoughts
+K:589:0x03/0xEC
+
+# Compendium of Deep Thoughts
+K:590:0x03/0xEC
+
+# Artifact Lore Vol. I
+K:591:0x03/0xEC
+
+# Artifact Lore Vol. II
+K:592:0x03/0xEC
+
+# Artifact Lore Vol. III
+K:593:0x03/0xEC
+
+# Monstrous Compendium 1
+K:594:0x03/0xEC
+
+# Monstrous Compendium 2
+K:595:0x03/0xEC
+
+# Monstrous Compendium 3
+K:596:0x03/0xEC
+
+# Monstrous Compendium 4
+K:597:0x03/0xEC
+
+# Monstrous Compendium 5
+K:598:0x03/0xEC
+
+# Monstrous Compendium 6
+K:599:0x03/0xEC
+
+# Monstrous Compendium 7
+K:600:0x03/0xEC
+
+# Monstrous Compendium 8
+K:601:0x03/0xEC
+
+# Monstrous Compendium 9
+K:602:0x03/0xEC
+
+# Monstrous Compendium 10
+K:603:0x03/0xEC
+
+# Monstrous Compendium 11
+K:604:0x03/0xEC
+
+# Abomination
+K:605:0x00/0xED
+
+# Shape of Wolf
+K:606:0x00/0xED
+
+# Shape of Ape
+K:607:0x00/0xED
+
+# Shape of Goat
+K:608:0x00/0xED
+
+# Shape of Insect
+K:609:0x00/0xED
+
+# Shape of Sparrow
+K:610:0x00/0xED
+
+# Shape of Ent
+K:611:0x00/0xED
+
+# Shape of Vampire
+K:612:0x00/0xED
+
+# Shape of Spider
+K:613:0x00/0xED
+
+# Shape of Mana ball
+K:614:0x00/0xED
+
+# Shape of Fire cloud
+K:615:0x00/0xED
+
+# Shape of Cold cloud
+K:616:0x00/0xED
+
+# Shape of Chaos cloud
+K:617:0x00/0xED
+
+# [Wolf]
+K:618:0x0B/0xE2
+
+# [Ape]
+K:619:0x0B/0xE2
+
+# [Goat]
+K:620:0x0B/0xE2
+
+# [Insect]
+K:621:0x0B/0xE2
+
+# [Sparrow]
+K:622:0x0B/0xE2
+
+# [Ent]
+K:623:0x0B/0xE2
+
+# [Vampire]
+K:624:0x0B/0xE2
+
+# [Spider]
+K:625:0x0B/0xE2
+
+# [Mana ball]
+K:626:0x0B/0xE2
+
+# [Fire cloud]
+K:627:0x0B/0xE2
+
+# [Cold cloud]
+K:628:0x0B/0xE2
+
+# [Chaos Cloud]
+K:629:0x0B/0xE2
+
+# [Ghost]
+K:630:0x0B/0xE2
+
+# [Kobold]
+K:631:0x0B/0xE2
+
+# [Dragon]
+K:632:0x0B/0xE2
+
+# [Demon]
+K:633:0x0B/0xE2
+
+# [Hound]
+K:634:0x0B/0xE2
+
+# [Quylthulg]
+K:635:0x0B/0xE2
+
+# [Maia]
+K:636:0x0B/0xE2
+
+# [Serpent]
+K:637:0x0B/0xE2
+
+# [Giant]
+K:638:0x0B/0xE2
+
+# [Vala]
+K:639:0x0B/0xE2
+
+# Magic
+K:640:0x0D/0xF6
+
+# corpse
+K:641:0x0F/0xD2
+
+# skeleton
+K:642:0x0F/0xD2
+
+# head
+K:643:0x0F/0xD2
+
+# skull
+K:644:0x0F/0xD2
+
+# raw meat
+K:645:0x0F/0xD2
+
+# & Thunderlord Coat~
+K:646:0x0B/0xE3
+
+# & Stone~
+K:647:0x05/0xF0
+
+# & Small Wooden Boomerang~
+K:648:0x0B/0xD8
+
+# & Wooden Boomerang~
+K:649:0x0B/0xD8
+
+# & Small Metal Boomerang~
+K:650:0x0B/0xD8
+
+# & metal Boomerang~
+K:651:0x0B/0xD8
+
+# & Anchor~
+K:652:0x0A/0xF0
+
+# & ~
+K:653:0x0B/0xD2
+
+# Summon Never-Moving Pet
+K:654:0x00/0xEC
+
+# Cure Light Insanity
+K:657:0x00/0xED
+
+# Cure Serious Insanity
+K:658:0x00/0xED
+
+# Cure Critical Insanity
+K:659:0x00/0xED
+
+# Cure Insanity
+K:660:0x00/0xED
+
+# & Phial~
+K:661:0x0B/0xF0
+
+# Random Artifact
+K:662:0x03/0xD3
+
+# Craftmanship
+K:663:0x00/0xEC
+
+# The One Ring
+K:664:0x02/0xEC
+
+# & Book~ of the Lays of the Heroes
+K:665:0x0B/0xEF
+
+# & Book~ of Sound Patterns
+K:666:0x0B/0xEF
+
+# & Flute~
+K:669:0x09/0xF7
+
+# & Drum~
+K:670:0x09/0xF7
+
+# & Harp~
+K:671:0x09/0xF7
+
+# & Banjo~
+K:672:0x09/0xF7
+
+# & Lute~
+K:673:0x09/0xF7
+
+# & Mandolin~
+K:674:0x09/0xF7
+
+# & Palantir~
+K:675:0x0B/0xF0
+
+# Egg
+K:676:0x09/0xD6
+
+# Reset Recall
+K:677:0x00/0xEC
+
+# Divination
+K:678:0x00/0xEC
+
+# Self
+K:679:0x06/0xF5
+
+# Ray
+K:680:0x06/0xF5
+
+# Sphere
+K:681:0x06/0xF5
+
+# Knowledge
+K:682:0x06/0xF5
+
+# Life
+K:683:0x08/0xF5
+
+# Fire
+K:684:0x04/0xF5
+
+# Cold
+K:685:0x06/0xF5
+
+# Lightning
+K:686:0x09/0xF5
+
+# Acid
+K:687:0x0E/0xF5
+
+# Element
+K:688:0x05/0xF5
+
+# Chaos
+K:689:0x0A/0xF5
+
+# Mind
+K:690:0x08/0xF5
+
+# Holding
+K:691:0x0E/0xF5
+
+# Arrow
+K:692:0x06/0xF5
+
+# Power Surge
+K:693:0x06/0xF5
+
+# Armageddon
+K:694:0x06/0xF5
+
+# Gravity
+K:695:0x0D/0xF5
+
+# Extra Life
+K:696:0x0D/0xF6
+
+# Undeath
+K:697:0x0D/0xF5
+
+# Protection
+K:698:0x0D/0xF5
+
+# & Horn~
+K:699:0x09/0xF7
+
+# & Ring~ of Precognition
+K:700:0x00/0xE8
+
+# & Sprig~ of Athelas
+K:701:0x05/0xF2
+
+# & Old Scroll~ of Deincarnation
+K:720:0x00/0xEC
+
+# & Dark Sword~
+K:721:0x08/0xDC
+
+# Numenorean for Beginners (I)
+K:722:0x02/0xEC
+
+# Numenorean for Beginners (II)
+K:723:0x02/0xEC
+
+# Advanced lessons of Numenorean
+K:724:0x02/0xEC
+
+# Advanced lessons of Sindarin
+K:725:0x02/0xEC
+
+# & Shard~ of Pottery
+K:726:0x04/0xD3
+
+# & Broken Stick~
+K:727:0x04/0xD3
+
+# & Book~ of Beginner Cantrips
+K:738:0x01/0xEF
+
+# & Book~ of Teleportation
+K:739:0x01/0xEF
+
+# & Book~ of Recall
+K:740:0x01/0xEF
+
+# & Book~ of Summoning
+K:741:0x01/0xEF
+
+# & Book~ of Fireflash
+K:742:0x01/0xEF
+
+# & Potion~ of Learning
+K:743:0x00/0xED
+
+# Spell
+K:749:0x00/0xEC
+
+# Khuzdul - The Hidden Tongue of the Dwarves
+K:751:0x02/0xEC
+
+# Nandorin for Dummies
+K:752:0x02/0xEC
+
+# Advanced Lessons of Orcish
+K:753:0x02/0xEC
+
+# Flying
+K:755:0x00/0xE8
+
+# & Tome~ of the Time
+K:756:0x06/0xEF
+
+# & Spellbook~ of #
+K:757:0x01/0xEF
+
+# & Tome~ of Meta Spells
+K:758:0x0A/0xEF
+
+# & Tome~ of the Mind
+K:759:0x0E/0xEF
+
+# & Holy Tome~ of Eru Iluvatar
+K:760:0x0D/0xEF
+
+# & Holy Tome~ of Manwe Sulimo
+K:761:0x0E/0xEF
+
+# & War Tome~ of Tulkas
+K:762:0x0C/0xEF
+
+# & Unholy Tome~ of the Hellflame
+K:763:0x0A/0xEF
+
+# & Corrupted Tome~ of Melkor
+K:764:0x08/0xEF
+
+# & Forest Tome~ of Yavanna
+K:768:0x0D/0xEF
+
+# & Ring~
+K:770:0x00/0xE8
+
+# [Earth]
+K:771:0x0C/0xEF
+
+# [Fire]
+K:772:0x0C/0xEF
+
+# [Air]
+K:773:0x04/0xEF
+
+# [Water]
+K:774:0x04/0xEF
+
+# [Mana]
+K:775:0x04/0xEF
+
+# Home Summoning
+K:776:0x00/0xEB
+
+# & Shadow Blade~
+K:777:0x08/0xDC
+
+# & Bluesteel Blade~
+K:778:0x06/0xDC
+
+# the Serpents
+K:779:0x0D/0xE7
+
+# Darkness
+K:780:0x0D/0xF6
+
+# Knowledge
+K:781:0x0D/0xF6
+
+# Force
+K:782:0x0D/0xF6
+
+# Lightning
+K:783:0x0D/0xF6
+
+# Mana
+K:784:0x0D/0xF6
+
+# Ring~ of Power
+K:785:0x00/0xE8
+
+# Climbing Set~
+K:786:0x0E/0xF8
+
+# Adventurer's Guide to Middle-earth
+K:787:0x03/0xEC
+
+# & Demonblade~
+K:788:0x0C/0xEF
+
+# & Demonshield~
+K:789:0x0C/0xEF
+
+# & Demonhorn~
+K:790:0x0C/0xEF
+
+# & Wooden Rod~ of#
+K:793:0x07/0xEB
+
+# & Copper Rod~ of#
+K:794:0x02/0xEB
+
+# & Iron Rod~ of#
+K:795:0x08/0xEB
+
+# & Moonstone Rod~ of#
+K:796:0x0F/0xEB
+
+# & Silver Rod~ of#
+K:797:0x02/0xEB
+
+# & Golden Rod~ of#
+K:798:0x0B/0xEB
+
+# & Mithril Rod~ of#
+K:799:0x0E/0xEB
+
+# & Adamantite Rod~ of#
+K:800:0x0A/0xEB
+
+# & Greater Ration~ of Health
+K:801:0x05/0xF2
+
+# & Crumpled Scroll~ of Mass Resurrection
+K:802:0x00/0xEC
+
+# & Cleaver~
+K:803:0x02/0xDB
+
+# & Light War Axe~
+K:804:0x02/0xDB
+
+# & Slaughter Axe~
+K:805:0x0D/0xDB
+
+# & Runestone~
+K:806:0x0A/0xF5
+
+# & Fortune cookie~
+K:807:0x0F/0xF2
+
+# Portable hole
+K:808:0x0E/0xF8
+
+# Critical Hits
+K:809:0x00/0xE8
+
+# & Wand~ of Digging of Thrain
+K:810:0x00/0xEA
+
+# & Gnarled Staff~ of Holy Fire of Mithrandir
+K:811:0x00/0xE9
+
+# Partial Totem
+K:812:0x0A/0xF8
+
+# True Totem
+K:813:0x0A/0xF8
+
+# & Piece~ of the Relic of Eru
+K:814:0x0A/0xD3
+
+# & Piece~ of the Relic of Manwe
+K:815:0x0A/0xD3
+
+# & Piece~ of the Relic of Tulkas
+K:816:0x0A/0xD3
+
+# & Piece~ of the Relic of Melkor
+K:817:0x0A/0xD3
+
+# & Piece~ of the Relic of Yavanna
+K:818:0x0A/0xD3
+
+
+##### Monster attr/char definitions #####
+
+# Player
+R:0:0x01/0x80
+
+# Filthy street urchin
+R:1:0x08/0xAE
+
+# Scrawny cat
+R:2:0x0F/0xA0
+
+# Sparrow
+R:3:0x0F/0x82
+
+# Chaffinch
+R:4:0x04/0x82
+
+# Wild rabbit
+R:5:0x0F/0xAC
+
+# Woodsman
+R:6:0x05/0xAE
+
+# Scruffy little dog
+R:7:0x0F/0x83
+
+# Farmer Maggot
+R:8:0x01/0xA2
+
+# Blubbering idiot
+R:9:0x09/0xAE
+
+# Boil-covered wretch
+R:10:0x05/0xAE
+
+# Village idiot
+R:11:0x0D/0xAE
+
+# Pitiful-looking beggar
+R:12:0x0F/0xAE
+
+# Mangy-looking leper
+R:13:0x07/0xAE
+
+# Agent of the black market
+R:14:0x06/0xAE
+
+# Singing, happy drunk
+R:15:0x0B/0xAE
+
+# Aimless-looking merchant
+R:16:0x03/0xAE
+
+# Mean-looking mercenary
+R:17:0x04/0xAE
+
+# Battle-scarred veteran
+R:18:0x0E/0xAE
+
+# Martti Ihrasaari
+R:19:0x01/0x90
+
+# Grey mold
+R:20:0x02/0xA7
+
+# Large white snake
+R:21:0x01/0x8A
+
+# Grey mushroom patch
+R:22:0x02/0xEE
+
+# Newt
+R:23:0x0B/0x92
+
+# Giant white centipede
+R:24:0x01/0x9D
+
+# White icky thing
+R:25:0x01/0xA3
+
+# Clear icky thing
+R:26:0x0E/0xA3
+
+# Giant white mouse
+R:27:0x01/0xAC
+
+# Large brown snake
+R:28:0x07/0x8A
+
+# Small kobold
+R:29:0x0B/0xA5
+
+# Kobold
+R:30:0x0D/0xA5
+
+# White worm mass
+R:31:0x01/0xB1
+
+# Floating eye
+R:32:0x03/0x9F
+
+# Rock lizard
+R:33:0x0F/0x92
+
+# Grid bug
+R:34:0x0A/0x89
+
+# Jackal
+R:35:0x0F/0x83
+
+# Soldier ant
+R:36:0x07/0x9B
+
+# Fruit bat
+R:37:0x03/0x9C
+
+# Insect swarm
+R:38:0x07/0x89
+
+# The Greater hell-beast
+R:39:0x02/0x95
+
+# Shrieker mushroom patch
+R:40:0x0C/0xEE
+
+# Blubbering icky thing
+R:41:0x09/0xA3
+
+# Metallic green centipede
+R:42:0x05/0x9D
+
+# Novice warrior
+R:43:0x07/0xAA
+
+# Novice rogue
+R:44:0x06/0xAA
+
+# Novice priest
+R:45:0x05/0xAA
+
+# Novice mage
+R:46:0x04/0xAA
+
+# Yellow mushroom patch
+R:47:0x0B/0xEE
+
+# White jelly
+R:48:0x01/0xA4
+
+# Giant black ant
+R:49:0x08/0x9B
+
+# Salamander
+R:50:0x03/0x92
+
+# White harpy
+R:51:0x01/0x88
+
+# Blue yeek
+R:52:0x06/0xB3
+
+# Grip, Farmer Maggot's dog
+R:53:0x01/0x83
+
+# Wolf, Farmer Maggot's dog
+R:54:0x01/0x83
+
+# Fang, Farmer Maggot's dog
+R:55:0x01/0x83
+
+# Giant green frog
+R:56:0x05/0x92
+
+# Freesia
+R:57:0x07/0xA0
+
+# Green worm mass
+R:58:0x05/0xB1
+
+# Large yellow snake
+R:59:0x0B/0x8A
+
+# Cave spider
+R:60:0x08/0x93
+
+# Crow
+R:61:0x02/0x82
+
+# Wild cat
+R:62:0x0F/0xA0
+
+# Smeagol
+R:63:0x0E/0xA2
+
+# Green ooze
+R:64:0x05/0xA4
+
+# Poltergeist
+R:65:0x02/0x87
+
+# Yellow jelly
+R:66:0x0B/0xA4
+
+# Metallic blue centipede
+R:67:0x06/0x9D
+
+# Raven
+R:68:0x08/0x82
+
+# Giant white louse
+R:69:0x01/0x89
+
+# Giant yellow centipede
+R:70:0x0B/0x9D
+
+# Black naga
+R:71:0x08/0xA8
+
+# Spotted mushroom patch
+R:72:0x03/0xEE
+
+# Silver jelly
+R:73:0x09/0xA4
+
+# Scruffy-looking hobbit
+R:74:0x02/0xA2
+
+# Giant white ant
+R:75:0x01/0x9B
+
+# Yellow mold
+R:76:0x0B/0xA7
+
+# Metallic red centipede
+R:77:0x04/0x9D
+
+# Yellow worm mass
+R:78:0x0B/0xB1
+
+# Clear worm mass
+R:79:0x0E/0xB1
+
+# Radiation eye
+R:80:0x0C/0x9F
+
+# Yellow light
+R:81:0x0B/0xF0
+
+# Cave lizard
+R:82:0x07/0x92
+
+# Novice ranger
+R:83:0x09/0xAA
+
+# Blue jelly
+R:84:0x06/0xA4
+
+# Creeping copper coins
+R:85:0x07/0xF3
+
+# Giant white rat
+R:86:0x09/0xAC
+
+# Snotling
+R:87:0x0F/0xA9
+
+# Swordfish
+R:88:0x09/0x7E
+
+# Blue worm mass
+R:89:0x06/0xB1
+
+# Large grey snake
+R:90:0x02/0x8A
+
+# Skeleton kobold
+R:91:0x09/0xAD
+
+# Ewok
+R:92:0x0D/0xA2
+
+# Novice mage
+R:93:0x04/0xAA
+
+# Green naga
+R:94:0x05/0xA8
+
+# Giant leech
+R:95:0x07/0xB1
+
+# Barracuda
+R:96:0x0D/0x7E
+
+# Novice paladin
+R:97:0x01/0xAA
+
+# Zog
+R:98:0x06/0xA2
+
+# Blue ooze
+R:99:0x06/0xA4
+
+# Green glutton ghost
+R:100:0x05/0x87
+
+# Green jelly
+R:101:0x05/0xA4
+
+# Large kobold
+R:102:0x06/0xA5
+
+# Grey icky thing
+R:103:0x02/0xA3
+
+# Disenchanter eye
+R:104:0x0A/0x9F
+
+# Red worm mass
+R:105:0x04/0xB1
+
+# Copperhead snake
+R:106:0x03/0x8A
+
+# Death sword
+R:107:0x09/0xDC
+
+# Purple mushroom patch
+R:108:0x0A/0xEE
+
+# Novice priest
+R:109:0x05/0xAA
+
+# Novice warrior
+R:110:0x07/0xAA
+
+# Nibelung
+R:111:0x08/0xA2
+
+# The disembodied hand that strangled people
+R:112:0x05/0xB4
+
+# Brown mold
+R:113:0x07/0xA7
+
+# Giant brown bat
+R:114:0x07/0x9C
+
+# Rat-thing
+R:115:0x0C/0xAC
+
+# Novice rogue
+R:116:0x06/0xAA
+
+# Creeping silver coins
+R:117:0x02/0xF3
+
+# Snaga
+R:118:0x0F/0xA9
+
+# Rattlesnake
+R:119:0x04/0x8A
+
+# Giant slug
+R:120:0x0F/0xB1
+
+# Giant pink frog
+R:121:0x04/0x92
+
+# Dark elf
+R:122:0x08/0xA2
+
+# Zombified kobold
+R:123:0x02/0xB4
+
+# Crypt creep
+R:124:0x08/0xAD
+
+# Rotting corpse
+R:125:0x0C/0xB4
+
+# Cave orc
+R:126:0x0D/0xA9
+
+# Wood spider
+R:127:0x0F/0x93
+
+# Manes
+R:128:0x04/0xAF
+
+# Bloodshot eye
+R:129:0x04/0x9F
+
+# Red naga
+R:130:0x04/0xA8
+
+# Red jelly
+R:131:0x04/0xA4
+
+# Green icky thing
+R:132:0x05/0xA3
+
+# Lost soul
+R:133:0x09/0x87
+
+# Night lizard
+R:134:0x06/0x92
+
+# Mughash, the Kobold Lord
+R:135:0x0A/0xA5
+
+# Skeleton orc
+R:136:0x09/0xAD
+
+# Wormtongue, Agent of Saruman
+R:137:0x0E/0xAA
+
+# Robin Hood, the Outlaw
+R:138:0x0D/0xAA
+
+# Nurgling
+R:139:0x03/0xAF
+
+# Lagduf, the Snaga
+R:140:0x0B/0xA9
+
+# Brown yeek
+R:141:0x07/0xB3
+
+# Novice ranger
+R:142:0x09/0xAA
+
+# Giant salamander
+R:143:0x0C/0x92
+
+# Space monster
+R:144:0x00/0xB5
+
+# Carnivorous flying monkey
+R:145:0x0C/0x88
+
+# Green mold
+R:146:0x05/0xA7
+
+# Novice paladin
+R:147:0x01/0xAA
+
+# Lemure
+R:148:0x0F/0xAF
+
+# Hill orc
+R:149:0x07/0xA9
+
+# Bandit
+R:150:0x06/0xAA
+
+# Hunting hawk
+R:151:0x07/0x82
+
+# Phantom warrior
+R:152:0x0E/0x87
+
+# Gremlin
+R:153:0x07/0xAF
+
+# Yeti
+R:154:0x01/0x99
+
+# Bloodshot icky thing
+R:155:0x04/0xA3
+
+# Giant grey rat
+R:156:0x02/0xAC
+
+# Black harpy
+R:157:0x08/0x88
+
+# Skaven
+R:158:0x0D/0xAC
+
+# The wounded bear
+R:159:0x04/0xAB
+
+# Cave bear
+R:160:0x07/0xAB
+
+# Rock mole
+R:161:0x02/0xAC
+
+# Mindcrafter
+R:162:0x0B/0xAA
+
+# Baby blue dragon
+R:163:0x06/0x9E
+
+# Baby white dragon
+R:164:0x01/0x9E
+
+# Baby green dragon
+R:165:0x05/0x9E
+
+# Baby black dragon
+R:166:0x02/0x9E
+
+# Baby red dragon
+R:167:0x04/0x9E
+
+# Giant red ant
+R:168:0x04/0x9B
+
+# Brodda, the Easterling
+R:169:0x0F/0xAA
+
+# Bloodfang, the Wolf
+R:170:0x0C/0x83
+
+# King cobra
+R:171:0x05/0x8A
+
+# Eagle
+R:172:0x07/0x82
+
+# War bear
+R:173:0x07/0xAB
+
+# Killer bee
+R:174:0x0B/0x89
+
+# Giant spider
+R:175:0x0A/0x93
+
+# Giant white tick
+R:176:0x01/0x93
+
+# The Borshin
+R:177:0x01/0xA1
+
+# Dark elven mage
+R:178:0x04/0xA2
+
+# Kamikaze yeek
+R:179:0x04/0xB3
+
+# Orfax, Son of Boldor
+R:180:0x0E/0xB3
+
+# Servant of Glaaki
+R:181:0x0D/0xB4
+
+# Dark elven warrior
+R:182:0x07/0xA2
+
+# Sand-dweller
+R:183:0x0B/0xAF
+
+# Clear mushroom patch
+R:184:0x0E/0xEE
+
+# Quiver slot
+R:185:0x0F/0xEE
+
+# Grishnakh, the Hill Orc
+R:186:0x0B/0xA9
+
+# Giant tan bat
+R:187:0x0F/0x9C
+
+# Owlbear
+R:188:0x03/0x88
+
+# Blue horror
+R:189:0x0E/0xAF
+
+# Hairy mold
+R:190:0x03/0xA7
+
+# Grizzly bear
+R:191:0x0F/0xAB
+
+# Disenchanter mold
+R:192:0x0A/0xA7
+
+# Pseudo dragon
+R:193:0x03/0x9E
+
+# Tengu
+R:194:0x06/0xAF
+
+# Creeping gold coins
+R:195:0x0B/0xF3
+
+# Wolf
+R:196:0x07/0x83
+
+# Giant fruit fly
+R:197:0x0D/0x89
+
+# Panther
+R:198:0x08/0xA0
+
+# Brigand
+R:199:0x06/0xAA
+
+# Hobbes the Tiger
+R:200:0x0B/0xA0
+
+# Shadow Creature of Fiona
+R:201:0x02/0xA2
+
+# Undead mass
+R:202:0x07/0xA4
+
+# Chaos shapechanger
+R:203:0x0A/0x88
+
+# Baby multi-hued dragon
+R:204:0x0A/0x9E
+
+# Vorpal bunny
+R:205:0x01/0xAC
+
+# Old Man Willow
+R:206:0x02/0xCC
+
+# Hippocampus
+R:207:0x0E/0x88
+
+# Zombified orc
+R:208:0x02/0xB4
+
+# Hippogriff
+R:209:0x0F/0x88
+
+# Black mamba
+R:210:0x08/0x8A
+
+# White wolf
+R:211:0x01/0x83
+
+# Grape jelly
+R:212:0x0A/0xA4
+
+# Nether worm mass
+R:213:0x08/0xB1
+
+# Abyss worm mass
+R:214:0x08/0xB1
+
+# Golfimbul, the Hill Orc Chief
+R:215:0x0B/0xA9
+
+# Swordsman
+R:216:0x07/0xAA
+
+# Skaven shaman
+R:217:0x05/0xAC
+
+# Baby bronze dragon
+R:218:0x0F/0x9E
+
+# Baby gold dragon
+R:219:0x0B/0x9E
+
+# Evil eye
+R:220:0x08/0x9F
+
+# Mine-dog
+R:221:0x07/0x83
+
+# Hellcat
+R:222:0x0C/0xA0
+
+# Moon beast
+R:223:0x09/0xAB
+
+# Master yeek
+R:224:0x05/0xB3
+
+# Priest
+R:225:0x05/0xAA
+
+# Dark elven priest
+R:226:0x05/0xA2
+
+# Air spirit
+R:227:0x0E/0x85
+
+# Skeleton human
+R:228:0x09/0xAD
+
+# Zombified human
+R:229:0x02/0xB4
+
+# Tiger
+R:230:0x03/0xA0
+
+# Moaning spirit
+R:231:0x07/0x87
+
+# Stegocentipede
+R:232:0x07/0x9D
+
+# Spotted jelly
+R:233:0x03/0xA4
+
+# Drider
+R:234:0x06/0x93
+
+# Mongbat
+R:235:0x0F/0x9C
+
+# Killer brown beetle
+R:236:0x07/0x8B
+
+# Boldor, King of the Yeeks
+R:237:0x0A/0xB3
+
+# Ogre
+R:238:0x0F/0x8F
+
+# Creeping mithril coins
+R:239:0x0E/0xF3
+
+# Illusionist
+R:240:0x0C/0xAA
+
+# Druid
+R:241:0x0D/0xAA
+
+# Pink horror
+R:242:0x0C/0xAF
+
+# Cloaker
+R:243:0x05/0xE2
+
+# Black orc
+R:244:0x08/0xA9
+
+# Ochre jelly
+R:245:0x0F/0xA4
+
+# Software bug
+R:246:0x04/0x89
+
+# Lurker
+R:247:0x01/0xB5
+
+# Tangleweed
+R:248:0x05/0xCC
+
+# Vlasta
+R:249:0x0E/0x92
+
+# Giant white dragon fly
+R:250:0x01/0x86
+
+# Snaga sapper
+R:251:0x0F/0xA9
+
+# Blue icky thing
+R:252:0x06/0xA3
+
+# Gibbering mouther
+R:253:0x03/0xA4
+
+# Wolfhound of Flora
+R:254:0x02/0x83
+
+# Hill giant
+R:255:0x0F/0x90
+
+# Flesh golem
+R:256:0x0C/0xA1
+
+# Warg
+R:257:0x08/0x83
+
+# Cheerful leprechaun
+R:258:0x0D/0xA2
+
+# Giant flea
+R:259:0x02/0x89
+
+# Ufthak of Cirith Ungol
+R:260:0x05/0xA9
+
+# Clay golem
+R:261:0x0F/0xA1
+
+# Black ogre
+R:262:0x08/0x8F
+
+# Dweller on the threshold
+R:263:0x02/0x99
+
+# Half-orc
+R:264:0x02/0xA9
+
+# Dark naga
+R:265:0x02/0xA8
+
+# Poison ivy
+R:266:0x05/0xCC
+
+# Magic mushroom patch
+R:267:0x0E/0xEE
+
+# Plaguebearer of Nurgle
+R:268:0x03/0xB4
+
+# Guardian naga
+R:269:0x0B/0xA8
+
+# Wererat
+R:270:0x08/0xAC
+
+# Light hound
+R:271:0x03/0x9A
+
+# Dark hound
+R:272:0x08/0x9A
+
+# Flying skull
+R:273:0x02/0xAD
+
+# Mi-Go
+R:274:0x0C/0x89
+
+# Giant tarantula
+R:275:0x03/0x93
+
+# Giant clear centipede
+R:276:0x0E/0x9D
+
+# Mirkwood spider
+R:277:0x0D/0x93
+
+# Frost giant
+R:278:0x01/0x90
+
+# Griffon
+R:279:0x07/0x88
+
+# Homunculus
+R:280:0x0B/0xAF
+
+# Gnome mage
+R:281:0x0C/0xA2
+
+# Clear hound
+R:282:0x0E/0x9A
+
+# Umber hulk
+R:283:0x0F/0x98
+
+# Rust monster
+R:284:0x03/0xAB
+
+# Ogrillon
+R:285:0x09/0x8F
+
+# Gelatinous cube
+R:286:0x0D/0xA4
+
+# Giant green dragon fly
+R:287:0x0D/0x86
+
+# Fire giant
+R:288:0x04/0x90
+
+# Hummerhorn
+R:289:0x0B/0x89
+
+# Lizard man
+R:290:0x0D/0xA2
+
+# Ulfast, Son of Ulfang
+R:291:0x0F/0xAA
+
+# Crebain
+R:292:0x08/0x82
+
+# Berserker
+R:293:0x07/0xAA
+
+# Quasit
+R:294:0x03/0xAF
+
+# Sphinx
+R:295:0x03/0x88
+
+# Imp
+R:296:0x05/0xAF
+
+# Forest troll
+R:297:0x05/0x94
+
+# Freezing sphere
+R:298:0x01/0xF0
+
+# Jumping fireball
+R:299:0x04/0xF0
+
+# Ball lightning
+R:300:0x0E/0xF0
+
+# 2-headed hydra
+R:301:0x07/0x8D
+
+# Swamp thing
+R:302:0x05/0x88
+
+# Water spirit
+R:303:0x06/0x85
+
+# Giant red scorpion
+R:304:0x04/0x93
+
+# Earth spirit
+R:305:0x07/0x85
+
+# Fire spirit
+R:306:0x04/0x85
+
+# Fire hound
+R:307:0x04/0x9A
+
+# Cold hound
+R:308:0x01/0x9A
+
+# Energy hound
+R:309:0x06/0x9A
+
+# Lesser Mimic
+R:310:0x0B/0xA7
+
+# Door mimic
+R:311:0x0F/0xB8
+
+# Blink dog
+R:312:0x0E/0x83
+
+# Uruk
+R:313:0x0E/0xA9
+
+# Shagrat, the Orc Captain
+R:314:0x05/0xA9
+
+# Gorbag, the Orc Captain
+R:315:0x05/0xA9
+
+# Shambling mound
+R:316:0x05/0xEE
+
+# Giant Venus Flytrap
+R:317:0x05/0xCC
+
+# Chaos beastman
+R:318:0x07/0x88
+
+# Daemonette of Slaanesh
+R:319:0x0C/0xAF
+
+# Giant bronze dragon fly
+R:320:0x0F/0x86
+
+# Stone giant
+R:321:0x09/0x90
+
+# Giant black dragon fly
+R:322:0x02/0x86
+
+# Stone golem
+R:323:0x09/0xA1
+
+# Red mold
+R:324:0x04/0xA7
+
+# Giant gold dragon fly
+R:325:0x0B/0x86
+
+# Stunwall
+R:326:0x09/0xBC
+
+# Ghast
+R:327:0x07/0xB4
+
+# Neekerbreeker
+R:328:0x08/0x89
+
+# Huorn
+R:329:0x05/0xCC
+
+# Bolg, Son of Azog
+R:330:0x0A/0xA9
+
+# Phase spider
+R:331:0x0E/0x93
+
+# Lizard king
+R:332:0x05/0xA2
+
+# Landmine
+R:333:0x01/0xB5
+
+# Wyvern
+R:334:0x05/0x9E
+
+# Great eagle
+R:335:0x07/0x82
+
+# Livingstone
+R:336:0x09/0xBC
+
+# Earth hound
+R:337:0x07/0x9A
+
+# Air hound
+R:338:0x05/0x9A
+
+# Sabre-tooth tiger
+R:339:0x0B/0xA0
+
+# Acid hound
+R:340:0x02/0x9A
+
+# Chimaera
+R:341:0x04/0x88
+
+# Quylthulg
+R:342:0x0B/0x91
+
+# Sasquatch
+R:343:0x09/0x99
+
+# Weir
+R:344:0x09/0x83
+
+# Ranger
+R:345:0x09/0xAA
+
+# Paladin
+R:346:0x01/0xAA
+
+# Werewolf
+R:347:0x08/0x83
+
+# Dark elven lord
+R:348:0x02/0xA2
+
+# Cloud giant
+R:349:0x06/0x90
+
+# Ugluk, the Uruk
+R:350:0x0A/0xA9
+
+# Blue dragon bat
+R:351:0x06/0x9C
+
+# Mimic
+R:352:0x0B/0xA7
+
+# Ultimate Mimic
+R:353:0x0B/0xA7
+
+# Fire vortex
+R:354:0x04/0xB0
+
+# Acid vortex
+R:355:0x02/0xB0
+
+# Lugdush, the Uruk
+R:356:0x0A/0xA9
+
+# Arch-vile
+R:357:0x09/0xAF
+
+# Cold vortex
+R:358:0x01/0xB0
+
+# Energy vortex
+R:359:0x06/0xB0
+
+# Globefish
+R:360:0x01/0x7E
+
+# Giant firefly
+R:361:0x04/0x89
+
+# Mummified orc
+R:362:0x01/0xB4
+
+# Wolf chieftain
+R:363:0x08/0x83
+
+# Serpent man
+R:364:0x0D/0x8A
+
+# Vampiric mist
+R:365:0x08/0xCA
+
+# Killer stag beetle
+R:366:0x05/0x8B
+
+# Iron golem
+R:367:0x02/0xA1
+
+# Auto-roller
+R:368:0x02/0xA1
+
+# Giant yellow scorpion
+R:369:0x0B/0x93
+
+# Jade monk
+R:370:0x0D/0xAA
+
+# Black ooze
+R:371:0x08/0xA4
+
+# Hardened warrior
+R:372:0x07/0xAA
+
+# Azog, King of the Uruk-Hai
+R:373:0x0A/0xA9
+
+# Fleshhound of Khorne
+R:374:0x0C/0x83
+
+# Dark elven warlock
+R:375:0x0A/0xA2
+
+# Master rogue
+R:376:0x06/0xAA
+
+# Red dragon bat
+R:377:0x04/0x9C
+
+# Killer white beetle
+R:378:0x01/0x8B
+
+# Ice skeleton
+R:379:0x01/0xAD
+
+# Angamaite of Umbar
+R:380:0x0F/0xAA
+
+# Forest wight
+R:381:0x05/0x97
+
+# Khim, Son of Mim
+R:382:0x03/0xA2
+
+# Ibun, Son of Mim
+R:383:0x03/0xA2
+
+# Meneldor the Swift
+R:384:0x07/0x82
+
+# Phantom beast
+R:385:0x0E/0x87
+
+# Giant silver ant
+R:386:0x09/0x9B
+
+# 4-headed hydra
+R:387:0x0B/0x8D
+
+# Lesser hell-beast
+R:388:0x02/0x95
+
+# Tyrannosaur
+R:389:0x05/0x92
+
+# Mummified human
+R:390:0x01/0xB4
+
+# Vampire bat
+R:391:0x08/0x9C
+
+# Sangahyando of Umbar
+R:392:0x0F/0xAA
+
+# It
+R:393:0x09/0xB5
+
+# Banshee
+R:394:0x06/0x87
+
+# Carrion crawler
+R:395:0x03/0x9D
+
+# Xiclotlan
+R:396:0x08/0xCC
+
+# Silent watcher
+R:397:0x02/0xA1
+
+# Pukelman
+R:398:0x08/0xA1
+
+# Disenchanter beast
+R:399:0x0A/0xAB
+
+# Dark elven druid
+R:400:0x0D/0xA2
+
+# Stone troll
+R:401:0x09/0x94
+
+# Black
+R:402:0x00/0xA4
+
+# Hill troll
+R:403:0x02/0x94
+
+# Wereworm
+R:404:0x07/0xB1
+
+# Killer red beetle
+R:405:0x04/0x8B
+
+# Disenchanter bat
+R:406:0x0A/0x9C
+
+# Gnoph-Keh
+R:407:0x02/0xAB
+
+# Giant grey ant
+R:408:0x02/0x9B
+
+# Khufu, the Mummified King
+R:409:0x0A/0xB4
+
+# Gwaihir the Windlord
+R:410:0x07/0x82
+
+# Giant fire tick
+R:411:0x0C/0x93
+
+# Displacer beast
+R:412:0x06/0xA0
+
+# Ulwarth, Son of Ulfang
+R:413:0x0F/0xAA
+
+# Werebear
+R:414:0x08/0xAB
+
+# Cave ogre
+R:415:0x07/0x8F
+
+# White wraith
+R:416:0x01/0x97
+
+# Angel
+R:417:0x03/0x81
+
+# Ghoul
+R:418:0x0F/0xB4
+
+# Mim, Betrayer of Turin
+R:419:0x03/0xA2
+
+# Hellblade
+R:420:0x0A/0xDC
+
+# Killer fire beetle
+R:421:0x0C/0x8B
+
+# Beast of Nurgle
+R:422:0x0B/0xAB
+
+# Creeping adamantite coins
+R:423:0x0D/0xF3
+
+# Algroth
+R:424:0x03/0x94
+
+# Flamer of Tzeentch
+R:425:0x04/0xEE
+
+# Roper
+R:426:0x08/0xBC
+
+# Headless
+R:427:0x07/0x88
+
+# Vibration hound
+R:428:0x0B/0x9A
+
+# Nexus hound
+R:429:0x0A/0x9A
+
+# Half-ogre
+R:430:0x03/0x8F
+
+# Lokkak, the Ogre Chieftain
+R:431:0x0A/0x8F
+
+# Vampire
+R:432:0x09/0x96
+
+# Gorgimaera
+R:433:0x03/0x88
+
+# Shantak
+R:434:0x08/0x88
+
+# Colbran
+R:435:0x0B/0xA1
+
+# Spirit naga
+R:436:0x01/0xA8
+
+# Corpser
+R:437:0x08/0xEE
+
+# Fiend of Slaanesh
+R:438:0x0C/0x93
+
+# Stairway to Hell
+R:439:0x09/0xB7
+
+# 5-headed hydra
+R:440:0x05/0x8D
+
+# Barney the Dinosaur
+R:441:0x0A/0x92
+
+# Black knight
+R:442:0x02/0xAA
+
+# Seahorse
+R:443:0x03/0x7E
+
+# Cyclops
+R:444:0x07/0x90
+
+# Clairvoyant
+R:445:0x0B/0xAA
+
+# Purple worm
+R:446:0x0A/0xB1
+
+# Catoblepas
+R:447:0x05/0xAB
+
+# Lesser wall monster
+R:448:0x09/0xBC
+
+# Mage
+R:449:0x04/0xAA
+
+# Mind flayer
+R:450:0x0A/0xA2
+
+# The Ultimate Dungeon Cleaner
+R:451:0x08/0xA1
+
+# Deep one
+R:452:0x05/0xAF
+
+# Basilisk
+R:453:0x02/0x92
+
+# Ice troll
+R:454:0x01/0x94
+
+# Dhole
+R:455:0x02/0xB1
+
+# Archangel
+R:456:0x0E/0x81
+
+# Greater Mimic
+R:457:0x0B/0xA7
+
+# Chaos tile
+R:458:0x0A/0xB5
+
+# Young blue dragon
+R:459:0x06/0x9E
+
+# Young white dragon
+R:460:0x01/0x9E
+
+# Young green dragon
+R:461:0x05/0x9E
+
+# Young bronze dragon
+R:462:0x0F/0x9E
+
+# Aklash
+R:463:0x0C/0x94
+
+# Mithril golem
+R:464:0x0E/0xA1
+
+# Skeleton troll
+R:465:0x09/0xAD
+
+# Skeletal tyrannosaur
+R:466:0x01/0x92
+
+# Beorn, the Shape-Changer
+R:467:0x08/0xAB
+
+# Thorondor, Lord of Eagles
+R:468:0x07/0x82
+
+# Giant blue ant
+R:469:0x06/0x9B
+
+# Grave wight
+R:470:0x06/0x97
+
+# Shadow drake
+R:471:0x0D/0x9E
+
+# Manticore
+R:472:0x0B/0x88
+
+# Giant army ant
+R:473:0x03/0x9B
+
+# Killer slicer beetle
+R:474:0x0B/0x8B
+
+# Gorgon
+R:475:0x06/0x88
+
+# Gug
+R:476:0x0D/0x90
+
+# Ghost
+R:477:0x01/0x87
+
+# Death watch beetle
+R:478:0x08/0x8B
+
+# Mountain ogre
+R:479:0x02/0x8F
+
+# Nexus quylthulg
+R:480:0x0A/0x91
+
+# Shelob, Spider of Darkness
+R:481:0x08/0x93
+
+# Giant squid
+R:482:0x05/0x7E
+
+# Ghoulking
+R:483:0x08/0xB4
+
+# Doombat
+R:484:0x0C/0x9C
+
+# Ninja
+R:485:0x07/0xAA
+
+# Memory moss
+R:486:0x06/0xEE
+
+# Storm giant
+R:487:0x0E/0x90
+
+# Spectator
+R:488:0x0E/0x9F
+
+# Bokrug
+R:489:0x0A/0x92
+
+# Biclops
+R:490:0x07/0x90
+
+# Half-troll
+R:491:0x0F/0x94
+
+# Ivory monk
+R:492:0x01/0xAA
+
+# Bert the Stone Troll
+R:493:0x09/0x94
+
+# Bill the Stone Troll
+R:494:0x09/0x94
+
+# Tom the Stone Troll
+R:495:0x09/0x94
+
+# Cave troll
+R:496:0x07/0x94
+
+# Anti-paladin
+R:497:0x08/0xAA
+
+# Chaos master
+R:498:0x0A/0xAA
+
+# Barrow wight
+R:499:0x0A/0x97
+
+# Skeleton ettin
+R:500:0x09/0xAD
+
+# Chaos drake
+R:501:0x0A/0x9E
+
+# Law drake
+R:502:0x0E/0x9E
+
+# Balance drake
+R:503:0x0A/0x9E
+
+# Ethereal drake
+R:504:0x03/0x9E
+
+# Groo, the Wanderer
+R:505:0x0F/0xAA
+
+# Fasolt the Giant
+R:506:0x07/0x90
+
+# Shade
+R:507:0x08/0x87
+
+# Spectre
+R:508:0x0F/0x87
+
+# Water troll
+R:509:0x0E/0x94
+
+# Fire elemental
+R:510:0x04/0x85
+
+# Cherub
+R:511:0x0D/0x81
+
+# Water elemental
+R:512:0x06/0x85
+
+# Multi-hued hound
+R:513:0x0A/0x9A
+
+# Invisible stalker
+R:514:0x0B/0x85
+
+# Carrion crawler
+R:515:0x03/0x9D
+
+# Master thief
+R:516:0x06/0xAA
+
+# The Watcher in the Water
+R:517:0x0A/0x7E
+
+# Lich
+R:518:0x03/0x8C
+
+# Gas spore
+R:519:0x05/0x9F
+
+# Master vampire
+R:520:0x05/0x96
+
+# Oriental vampire
+R:521:0x02/0x96
+
+# Greater mummy
+R:522:0x0B/0xB4
+
+# Bloodletter of Khorne
+R:523:0x04/0x95
+
+# Giant grey scorpion
+R:524:0x02/0x93
+
+# Earth elemental
+R:525:0x07/0x85
+
+# Air elemental
+R:526:0x0E/0x85
+
+# Shimmering mold
+R:527:0x06/0xA7
+
+# Gargoyle
+R:528:0x02/0xAF
+
+# Malicious leprechaun
+R:529:0x0A/0xA2
+
+# Eog golem
+R:530:0x07/0xA1
+
+# Little Boy
+R:531:0x08/0xD6
+
+# Dagashi
+R:532:0x07/0xAA
+
+# Headless ghost
+R:533:0x07/0x87
+
+# Dread
+R:534:0x03/0x87
+
+# Leng spider
+R:535:0x0A/0x93
+
+# Gauth
+R:536:0x02/0x9F
+
+# Smoke elemental
+R:537:0x0C/0x85
+
+# Olog
+R:538:0x0B/0x94
+
+# Halfling slinger
+R:539:0x0F/0xA2
+
+# Gravity hound
+R:540:0x09/0x9A
+
+# Acidic cytoplasm
+R:541:0x02/0xA4
+
+# Inertia hound
+R:542:0x09/0x9A
+
+# Impact hound
+R:543:0x07/0x9A
+
+# Shardstorm
+R:544:0x07/0xB0
+
+# Ooze elemental
+R:545:0x05/0x85
+
+# Young black dragon
+R:546:0x02/0x9E
+
+# Mumak
+R:547:0x02/0xAB
+
+# Giant fire ant
+R:548:0x0C/0x9B
+
+# Mature white dragon
+R:549:0x01/0x9E
+
+# Xorn
+R:550:0x07/0x98
+
+# Rogrog the Black Troll
+R:551:0x08/0x94
+
+# Mist giant
+R:552:0x0E/0xCA
+
+# Phantom
+R:553:0x0A/0x87
+
+# Grey wraith
+R:554:0x02/0x97
+
+# Revenant
+R:555:0x07/0x97
+
+# Young multi-hued dragon
+R:556:0x0A/0x9E
+
+# Raal's Tome of Destruction
+R:557:0x04/0xEF
+
+# Colossus
+R:558:0x0D/0xA1
+
+# Young gold dragon
+R:559:0x0B/0x9E
+
+# Mature blue dragon
+R:560:0x06/0x9E
+
+# Mature green dragon
+R:561:0x05/0x9E
+
+# Mature bronze dragon
+R:562:0x0F/0x9E
+
+# Young red dragon
+R:563:0x04/0x9E
+
+# Nightblade
+R:564:0x08/0xA2
+
+# Trapper
+R:565:0x01/0xB5
+
+# Bodak
+R:566:0x04/0xAF
+
+# Time bomb
+R:567:0x01/0xB5
+
+# Mezzodaemon
+R:568:0x03/0xAF
+
+# Elder thing
+R:569:0x0D/0xAF
+
+# Ice elemental
+R:570:0x01/0x85
+
+# Necromancer
+R:571:0x0C/0xAA
+
+# The Greater hell magic mushroom were-quylthulg
+R:572:0x02/0x91
+
+# Lorgan, Chief of the Easterlings
+R:573:0x0A/0xAA
+
+# Chaos spawn
+R:574:0x02/0x9F
+
+# Mummified troll
+R:575:0x01/0xB4
+
+# Storm of Unmagic
+R:576:0x0A/0xB0
+
+# Crypt thing
+R:577:0x0D/0x8C
+
+# Chaos butterfly
+R:578:0x0D/0x89
+
+# Time elemental
+R:579:0x0D/0x85
+
+# Flying polyp
+R:580:0x0C/0x7E
+
+# The Queen Ant
+R:581:0x0A/0x9B
+
+# Will o' the wisp
+R:582:0x09/0x85
+
+# Shan
+R:583:0x0E/0x89
+
+# Magma elemental
+R:584:0x03/0x85
+
+# Black pudding
+R:585:0x08/0xA4
+
+# Killer iridescent beetle
+R:586:0x0A/0x8B
+
+# Nexus vortex
+R:587:0x0A/0xB0
+
+# Plasma vortex
+R:588:0x0C/0xB0
+
+# Mature red dragon
+R:589:0x04/0x9E
+
+# Mature gold dragon
+R:590:0x0B/0x9E
+
+# Crystal drake
+R:591:0x07/0x9E
+
+# Mature black dragon
+R:592:0x02/0x9E
+
+# Mature multi-hued dragon
+R:593:0x0A/0x9E
+
+# Sky whale
+R:594:0x0D/0x7E
+
+# Draebor, the Imp
+R:595:0x0A/0xAF
+
+# Mother Hydra
+R:596:0x0A/0xAF
+
+# Death knight
+R:597:0x08/0xAA
+
+# Castamir the Usurper
+R:598:0x0C/0xAA
+
+# Time vortex
+R:599:0x0E/0xB0
+
+# Shimmering vortex
+R:600:0x03/0xB0
+
+# Ancient blue dragon
+R:601:0x06/0x84
+
+# Ancient bronze dragon
+R:602:0x0F/0x84
+
+# Beholder
+R:603:0x0F/0x9F
+
+# Emperor wight
+R:604:0x04/0x97
+
+# Seraph
+R:605:0x04/0x81
+
+# Vargo, Tyrant of Fire
+R:606:0x04/0x85
+
+# Black wraith
+R:607:0x08/0x97
+
+# Nightgaunt
+R:608:0x08/0x95
+
+# Baron of hell
+R:609:0x0F/0x95
+
+# Scylla
+R:610:0x0E/0x8D
+
+# Monastic lich
+R:611:0x07/0x8C
+
+# Nether wraith
+R:612:0x0D/0x97
+
+# Hellhound
+R:613:0x04/0x83
+
+# 7-headed hydra
+R:614:0x0D/0x8D
+
+# Waldern, King of Water
+R:615:0x06/0x85
+
+# Kavlax the Many-Headed
+R:616:0x0A/0x9E
+
+# Ancient white dragon
+R:617:0x01/0x84
+
+# Ancient green dragon
+R:618:0x05/0x84
+
+# Chthonian
+R:619:0x08/0xB1
+
+# Eldrak
+R:620:0x04/0x94
+
+# Ettin
+R:621:0x06/0x94
+
+# Night mare
+R:622:0x0D/0xAB
+
+# Vampire lord
+R:623:0x06/0x96
+
+# Ancient black dragon
+R:624:0x02/0x84
+
+# Weird fume
+R:625:0x0A/0xCA
+
+# Spawn of Ubbo-Sathla
+R:626:0x0A/0xA4
+
+# Fat Man
+R:627:0x08/0xD6
+
+# Malekith the Accursed
+R:628:0x0A/0xA2
+
+# Shadowfax, steed of Gandalf
+R:629:0x0A/0xAB
+
+# Spirit troll
+R:630:0x0D/0x87
+
+# War troll
+R:631:0x06/0x94
+
+# Disenchanter worm mass
+R:632:0x0A/0xB1
+
+# Rotting quylthulg
+R:633:0x07/0x91
+
+# Lesser titan
+R:634:0x0B/0x90
+
+# 9-headed hydra
+R:635:0x04/0x8D
+
+# Enchantress
+R:636:0x0C/0xAA
+
+# Ranger chieftain
+R:637:0x09/0xAA
+
+# Sorcerer
+R:638:0x0C/0xAA
+
+# Xaren
+R:639:0x02/0x98
+
+# Giant roc
+R:640:0x07/0x82
+
+# Minotaur
+R:641:0x0F/0x88
+
+# Medusa, the Gorgon
+R:642:0x0A/0xA8
+
+# Death drake
+R:643:0x0D/0x84
+
+# Ancient red dragon
+R:644:0x04/0x84
+
+# Ancient gold dragon
+R:645:0x0B/0x84
+
+# Great crystal drake
+R:646:0x0F/0x84
+
+# Wyrd sister
+R:647:0x0A/0xAA
+
+# Vrock
+R:648:0x02/0x95
+
+# Death quasit
+R:649:0x08/0xAF
+
+# Giganto, the Gargantuan
+R:650:0x02/0x7E
+
+# Strygalldwir
+R:651:0x09/0x95
+
+# Fallen angel
+R:652:0x02/0x81
+
+# Giant headless
+R:653:0x07/0x88
+
+# Judge Fire
+R:654:0x0C/0xAD
+
+# Ubbo-Sathla, the Unbegotten Source
+R:655:0x09/0xA4
+
+# Judge Mortis
+R:656:0x0D/0xB4
+
+# Dark elven sorcerer
+R:657:0x0C/0xA2
+
+# Master lich
+R:658:0x04/0x8C
+
+# Byakhee
+R:659:0x08/0x95
+
+# Eol, the Dark Elf
+R:660:0x08/0xA2
+
+# Archon
+R:661:0x0B/0x81
+
+# Formless spawn of Tsathoggua
+R:662:0x08/0x95
+
+# Hunting horror
+R:663:0x08/0x95
+
+# Undead beholder
+R:664:0x07/0x9F
+
+# Shadow
+R:665:0x08/0x87
+
+# Iron lich
+R:666:0x02/0x8C
+
+# Dread
+R:667:0x03/0x87
+
+# Greater basilisk
+R:668:0x08/0x92
+
+# Charybdis
+R:669:0x04/0x7E
+
+# Jack of Shadows
+R:670:0x02/0xAA
+
+# Zephyr Lord
+R:671:0x0A/0x97
+
+# Juggernaut of Khorne
+R:672:0x08/0xA1
+
+# Mumak
+R:673:0x02/0xAB
+
+# Judge Fear
+R:674:0x08/0x97
+
+# Ancient multi-hued dragon
+R:675:0x0A/0x84
+
+# Ethereal dragon
+R:676:0x03/0x84
+
+# Dark young of Shub-Niggurath
+R:677:0x05/0x95
+
+# Colour out of space
+R:678:0x0A/0xB5
+
+# Quaker, Master of Earth
+R:679:0x07/0x85
+
+# Death leprechaun
+R:680:0x08/0xA2
+
+# Chaugnar Faugn, Horror from the Hills
+R:681:0x08/0xAB
+
+# Lloigor
+R:682:0x0E/0xB0
+
+# Utgard-Loke
+R:683:0x0A/0x90
+
+# Quachil Uttaus, Treader of the Dust
+R:684:0x08/0xB4
+
+# Shoggoth
+R:685:0x08/0xA4
+
+# Judge Death
+R:686:0x08/0x97
+
+# Ariel, Queen of Air
+R:687:0x0E/0x85
+
+# 11-headed hydra
+R:688:0x0C/0x8D
+
+# Patriarch
+R:689:0x0D/0xAA
+
+# Dreadmaster
+R:690:0x0B/0x87
+
+# Drolem
+R:691:0x05/0xA1
+
+# Scatha the Worm
+R:692:0x09/0x84
+
+# Warrior of the Dawn
+R:693:0x0C/0xAA
+
+# Lesser black reaver
+R:694:0x08/0x8C
+
+# Zoth-Ommog
+R:695:0x0A/0x92
+
+# Grand master thief
+R:696:0x06/0xAA
+
+# Smaug the Golden
+R:697:0x0C/0x84
+
+# The Stormbringer
+R:698:0x08/0xDC
+
+# Knight Templar
+R:699:0x01/0xAA
+
+# Leprechaun fanatic
+R:700:0x04/0xA2
+
+# Dracolich
+R:701:0x0D/0x84
+
+# Greater titan
+R:702:0x03/0x90
+
+# Dracolisk
+R:703:0x0C/0x84
+
+# Winged Horror
+R:704:0x08/0x82
+
+# Spectral tyrannosaur
+R:705:0x0D/0x92
+
+# Yibb-Tstll, the Patient One
+R:706:0x08/0x90
+
+# Ghatanothoa
+R:707:0x08/0xB0
+
+# Ent
+R:708:0x0D/0xCC
+
+# Hru
+R:709:0x02/0x90
+
+# Itangast the Fire Drake
+R:710:0x0C/0x84
+
+# Death mold
+R:711:0x08/0xA7
+
+# Fafner the Dragon
+R:712:0x0D/0x84
+
+# Charon, Boatman of the Styx
+R:713:0x0E/0x97
+
+# Quickbeam, the Ent
+R:714:0x0D/0xCC
+
+# Glaurung, Father of the Dragons
+R:715:0x0C/0x84
+
+# Behemoth
+R:716:0x0E/0x88
+
+# Garm, Guardian of Hel
+R:717:0x06/0x83
+
+# Greater wall monster
+R:718:0x09/0xBC
+
+# Nycadaemon
+R:719:0x03/0x95
+
+# Barbazu
+R:720:0x0D/0x95
+
+# Goat of Mendes
+R:721:0x08/0xAB
+
+# Nightwing
+R:722:0x08/0x97
+
+# Maulotaur
+R:723:0x02/0x88
+
+# Nether hound
+R:724:0x0D/0x9A
+
+# Time hound
+R:725:0x0E/0x9A
+
+# Plasma hound
+R:726:0x0C/0x9A
+
+# Demonic quylthulg
+R:727:0x04/0x91
+
+# Great Storm Wyrm
+R:728:0x06/0x84
+
+# Ulik the Troll
+R:729:0x0A/0x94
+
+# Baphomet the Minotaur Lord
+R:730:0x0A/0x88
+
+# Hell knight
+R:731:0x08/0xAA
+
+# Bull Gates
+R:732:0x08/0xAA
+
+# Santa Claus
+R:733:0x04/0xA2
+
+# Eihort, the Thing in the Labyrinth
+R:734:0x0C/0xA4
+
+# The King in Yellow
+R:735:0x0B/0x8C
+
+# Great unclean one
+R:736:0x05/0x95
+
+# Lord of Chaos
+R:737:0x0A/0xAA
+
+# Old Sorcerer
+R:738:0x0C/0xAA
+
+# Ethereal hound
+R:739:0x0D/0x9A
+
+# Lesser kraken
+R:740:0x0D/0x7E
+
+# Great Ice Wyrm
+R:741:0x01/0x84
+
+# Demilich
+R:742:0x0F/0x8C
+
+# The Phoenix
+R:743:0x04/0x82
+
+# Nightcrawler
+R:744:0x08/0x97
+
+# Lord of Change
+R:745:0x0A/0x95
+
+# Keeper of Secrets
+R:746:0x0D/0x88
+
+# Shudde M'ell
+R:747:0x02/0xB1
+
+# Hand druj
+R:748:0x0B/0xAD
+
+# Eye druj
+R:749:0x04/0xAD
+
+# Skull druj
+R:750:0x03/0xAD
+
+# Chaos vortex
+R:751:0x0A/0xB0
+
+# Aether vortex
+R:752:0x0A/0xB0
+
+# Nidhogg, the Hel-Drake
+R:753:0x08/0x84
+
+# The Lernaean Hydra
+R:754:0x0A/0x8D
+
+# Thuringwethil, the Vampire Messenger
+R:755:0x0A/0x96
+
+# Great Hell Wyrm
+R:756:0x04/0x84
+
+# Hastur the Unspeakable
+R:757:0x06/0x88
+
+# Bloodthirster
+R:758:0x04/0x95
+
+# Draconic quylthulg
+R:759:0x05/0x91
+
+# Nyogtha, the Thing that Should not Be
+R:760:0x08/0xA4
+
+# Ahtu, Avatar of Nyarlathotep
+R:761:0x08/0xBC
+
+# Fundin Bluecloak
+R:762:0x0E/0xA2
+
+# Bile Demon
+R:763:0x0C/0x95
+
+# Uriel, Angel of Fire
+R:764:0x0C/0x81
+
+# Azriel, Angel of Death
+R:765:0x08/0x81
+
+# Ancalagon the Black
+R:766:0x08/0x84
+
+# Daoloth, the Render of the Veils
+R:767:0x02/0x95
+
+# Nightwalker
+R:768:0x08/0x97
+
+# Gabriel, the Messenger
+R:769:0x01/0x81
+
+# Artsi, the Champion of Chaos
+R:770:0x0A/0xA2
+
+# Saruman of Many Colours
+R:771:0x0A/0xAA
+
+# Harowen the Black Hand
+R:772:0x0E/0xAA
+
+# Osyluth
+R:773:0x09/0x95
+
+# Dreadlord
+R:774:0x04/0x87
+
+# Greater kraken
+R:775:0x0D/0x7E
+
+# Archlich
+R:776:0x0E/0x8C
+
+# The Cat Lord
+R:777:0x0A/0xA0
+
+# Jabberwock
+R:778:0x0A/0x88
+
+# Chaos hound
+R:779:0x0A/0x9A
+
+# Vlad Dracula, Prince of Darkness
+R:780:0x08/0x96
+
+# Beholder hive-mother
+R:781:0x0B/0x9F
+
+# Leviathan
+R:782:0x0A/0x7E
+
+# Great Wyrm of Chaos
+R:783:0x0A/0x84
+
+# Great Wyrm of Law
+R:784:0x0E/0x84
+
+# Great Wyrm of Balance
+R:785:0x0A/0x84
+
+# Shambler
+R:786:0x09/0x85
+
+# Gelugon
+R:787:0x01/0x95
+
+# Glaaki
+R:788:0x0A/0x7E
+
+# Trone, the Rebel Thunderlord
+R:789:0x08/0x82
+
+# Great Wyrm of Many Colours
+R:790:0x0A/0x84
+
+# Marda, rider of gold Laronth
+R:791:0x0B/0x82
+
+# Tselakus, the Dreadlord
+R:792:0x0C/0x87
+
+# Sky Drake
+R:793:0x0E/0x84
+
+# Eilinel the Entrapped
+R:794:0x08/0xAA
+
+# Horned Reaper
+R:795:0x0E/0x95
+
+# The Norsa
+R:796:0x0E/0x88
+
+# Rhan-Tegoth
+R:797:0x06/0x93
+
+# Black reaver
+R:798:0x08/0x8C
+
+# Master mindcrafter
+R:799:0x0B/0xAA
+
+# Greater demonic quylthulg
+R:800:0x0C/0x91
+
+# Greater draconic quylthulg
+R:801:0x0D/0x91
+
+# Greater rotting quylthulg
+R:802:0x0F/0x91
+
+# Null, the Living Void
+R:803:0x00/0xB5
+
+# Feagwath, the Undead Sorcerer
+R:804:0x0B/0x8C
+
+# Omarax the Eye Tyrant
+R:805:0x0A/0x9F
+
+# Tsathoggua, the Sleeper of N'kai
+R:806:0x08/0x92
+
+# Greater Balrog
+R:807:0x0A/0x95
+
+# Ungoliant, the Unlight
+R:808:0x08/0x93
+
+# Atlach-Nacha, the Spider God
+R:809:0x08/0x93
+
+# Y'golonac
+R:810:0x0C/0x88
+
+# Aether hound
+R:811:0x0A/0x9A
+
+# Pit Fiend
+R:812:0x03/0x95
+
+# The Serpent of Chaos
+R:813:0x0A/0x8A
+
+# Yig, Father of Serpents
+R:814:0x06/0x8A
+
+# Unmaker
+R:815:0x0A/0x85
+
+# Cyberdemon
+R:816:0x07/0x95
+
+# Hela, Queen of the Dead
+R:817:0x0D/0xAA
+
+# The Mouth of Sauron
+R:818:0x0A/0xAA
+
+# The Necromancer of Dol Guldur
+R:819:0x0A/0xAA
+
+# Lisa, rider of gold Romth
+R:820:0x0B/0x82
+
+# Master quylthulg
+R:821:0x0E/0x91
+
+# Qlzqqlzuup, the Lord of Flesh
+R:822:0x0A/0x91
+
+# Cthugha, the Living Flame
+R:823:0x0C/0x85
+
+# Flare, rider of bronze Moonth
+R:824:0x0F/0x82
+
+# Maeglin, the Traitor of Gondolin
+R:825:0x08/0xA2
+
+# Cyaegha
+R:826:0x0D/0x9F
+
+# Pazuzu, Lord of Air
+R:827:0x06/0x95
+
+# Ithaqua the Windwalker
+R:828:0x0E/0x99
+
+# Greater Hellhound
+R:829:0x04/0x83
+
+# Cantoras, the Skeletal Lord
+R:830:0x0A/0xAD
+
+# Mephistopheles, Lord of Hell
+R:831:0x04/0x95
+
+# Godzilla
+R:832:0x0A/0x92
+
+# Abhoth, Source of Uncleanness
+R:833:0x0D/0xA4
+
+# Ymir, the Ice Giant
+R:834:0x01/0x90
+
+# Loki, the Trickster
+R:835:0x08/0x90
+
+# Star-spawn of Cthulhu
+R:836:0x0D/0x95
+
+# Surtur, the Fire Giant
+R:837:0x04/0x90
+
+# The Tarrasque
+R:838:0x0A/0x92
+
+# Lungorthin, the Balrog of White Fire
+R:839:0x0A/0x95
+
+# Draugluin, Sire of All Werewolves
+R:840:0x0A/0x83
+
+# Shuma-Gorath
+R:841:0x0D/0x9F
+
+# Tulzscha, the Green Flame
+R:842:0x0D/0x85
+
+# Oremorj, the Cyberdemon Lord
+R:843:0x07/0x95
+
+# Vecna, the Emperor Lich
+R:844:0x0A/0x8C
+
+# Yog-Sothoth, the All-in-One
+R:845:0x0A/0xA4
+
+# Fenris Wolf
+R:846:0x08/0x83
+
+# Great Wyrm of Power
+R:847:0x0A/0x84
+
+# Shub-Niggurath, Black Goat of the Woods
+R:848:0x08/0x95
+
+# Nodens, Lord of the Great Abyss
+R:849:0x09/0x90
+
+# Carcharoth, the Jaws of Thirst
+R:850:0x08/0x83
+
+# Nyarlathotep, the Crawling Chaos
+R:851:0x04/0x95
+
+# Azathoth, the Daemon Sultan
+R:852:0x0E/0x85
+
+# Huan, Wolfhound of the Valar
+R:853:0x09/0x83
+
+# Jormungand the Midgard Serpent
+R:854:0x0A/0x8A
+
+# The Destroyer
+R:855:0x0A/0xA1
+
+# Gothmog, the High Captain of Balrogs
+R:856:0x0A/0x95
+
+# Great Cthulhu
+R:857:0x05/0x95
+
+# Sarko, rider of gold Foronth
+R:858:0x0B/0x82
+
+# The Unicorn of Order
+R:859:0x01/0xAB
+
+# Sauron, the Sorcerer
+R:860:0x0A/0xAA
+
+# DarkGod, the Mighty Coder of Hell
+R:861:0x0E/0x90
+
+# Morgoth, Lord of Darkness
+R:862:0x08/0x90
+
+# Human Warrior
+R:863:0x07/0xAA
+
+# Elven archer
+R:864:0x09/0xA2
+
+# Dwarven warrior
+R:865:0x0F/0xA2
+
+# Elite uruk
+R:866:0x01/0xA9
+
+# The Philosophy Teacher
+R:867:0x04/0xAA
+
+# The Variant Maintainer
+R:868:0x0E/0xAA
+
+# Random Number Generator
+R:869:0x06/0x89
+
+# Rocket mine
+R:870:0x0C/0xB5
+
+# Bouncing mine
+R:871:0x0E/0xB5
+
+# Durin's Bane
+R:872:0x0A/0x95
+
+# The Icky Queen
+R:873:0x0A/0xA3
+
+# Rot jelly
+R:874:0x07/0xA4
+
+# Death
+R:875:0x08/0x87
+
+# Famine
+R:876:0x0F/0x87
+
+# Pestilence
+R:877:0x0D/0x87
+
+# War
+R:878:0x04/0x87
+
+# Pike
+R:879:0x02/0x7E
+
+# Electric eel
+R:880:0x0E/0x8A
+
+# Giant crayfish
+R:881:0x0C/0x7E
+
+# Mermaid
+R:882:0x0D/0xA2
+
+# Box jellyfish
+R:883:0x0E/0x7E
+
+# Giant piranha
+R:884:0x05/0x7E
+
+# Piranha
+R:885:0x05/0x7E
+
+# Bullywug
+R:886:0x05/0xA2
+
+# Bullywug warrior
+R:887:0x05/0xA2
+
+# Bullywug shaman
+R:888:0x05/0xA2
+
+# Whale
+R:889:0x0D/0x7E
+
+# Sand mite
+R:890:0x0E/0x7E
+
+# Octopus
+R:891:0x05/0x7E
+
+# Giant octopus
+R:892:0x05/0x7E
+
+# Eye of the deep
+R:893:0x06/0x9F
+
+# Murk dweller
+R:894:0x02/0x93
+
+# Drowned soul
+R:895:0x0E/0x87
+
+# Tiger shark
+R:896:0x05/0x7E
+
+# Hammerhead shark
+R:897:0x05/0x7E
+
+# Great white shark
+R:898:0x01/0x7E
+
+# Aquatic golem
+R:899:0x06/0xA1
+
+# Aquatic kobold
+R:900:0x0E/0xA5
+
+# White shark
+R:901:0x09/0x7E
+
+# Scrag
+R:902:0x0E/0x94
+
+# Jaws
+R:903:0x01/0x7E
+
+# Aquatic elf
+R:904:0x06/0xA2
+
+# Aquatic elven warrior
+R:905:0x06/0xA2
+
+# Aquatic elven shaman
+R:906:0x06/0xA2
+
+# Stargazer
+R:907:0x0B/0x7E
+
+# Elder stargazer
+R:908:0x0B/0x7E
+
+# Flounder
+R:909:0x02/0x7E
+
+# Giant turtle
+R:910:0x0D/0x92
+
+# Baby dragon turtle
+R:911:0x09/0x9E
+
+# Young dragon turtle
+R:912:0x09/0x9E
+
+# Mature dragon turtle
+R:913:0x09/0x9E
+
+# Ancient dragon turtle
+R:914:0x09/0x84
+
+# Fastitocalon
+R:915:0x05/0x84
+
+# Undead stargazer
+R:916:0x0B/0x7E
+
+# Killer whale
+R:917:0x01/0x7E
+
+# Merrow
+R:918:0x0E/0x8F
+
+# Water naga
+R:919:0x0E/0xA8
+
+# Devilfish
+R:920:0x02/0x7E
+
+# Undead devilfish
+R:921:0x08/0x7E
+
+# Moby Dick, the White Whale
+R:922:0x01/0x7E
+
+# Aquatic hound
+R:923:0x0E/0x9A
+
+# Water demon
+R:924:0x0E/0x95
+
+# Ixitxachitl
+R:925:0x02/0x7E
+
+# Ixitxachitl priest
+R:926:0x02/0x7E
+
+# Vampiric ixitxachitl
+R:927:0x08/0x7E
+
+# Mathilde, the Science Student
+R:928:0x0B/0xA2
+
+# Child spirit
+R:929:0x09/0x87
+
+# Young spirit
+R:930:0x09/0x87
+
+# Mature spirit
+R:931:0x09/0x87
+
+# Experienced spirit
+R:932:0x09/0x87
+
+# Wise spirit
+R:933:0x09/0x87
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0x0D/0xCC
+
+# Gandalf the Grey
+R:935:0x02/0xAA
+
+# Nar, the Dwarf
+R:936:0x0B/0xA2
+
+# Novice mindcrafter
+R:937:0x0B/0xAA
+
+# Great Swamp Wyrm
+R:938:0x05/0x84
+
+# Great Bile Wyrm
+R:939:0x02/0x84
+
+# Blue Firebird
+R:940:0x0E/0x82
+
+# Green Firebird
+R:941:0x0D/0x82
+
+# Brown Firebird
+R:942:0x07/0x82
+
+# Bronze Firebird
+R:943:0x0F/0x82
+
+# Gold Firebird
+R:944:0x0B/0x82
+
+# High-elven ranger
+R:945:0x0D/0xA2
+
+# Uvatha the Horseman
+R:946:0x08/0x97
+
+# Adunaphel the Quiet
+R:947:0x08/0x97
+
+# Akhorahil the Blind
+R:948:0x08/0x97
+
+# Ren the Unclean
+R:949:0x08/0x97
+
+# Ji Indur Dawndeath
+R:950:0x08/0x97
+
+# Dwar, Dog Lord of Waw
+R:951:0x08/0x97
+
+# Hoarmurath of Dir
+R:952:0x08/0x97
+
+# Khamul, the Black Easterling
+R:953:0x08/0x97
+
+# The Witch-King of Angmar
+R:954:0x08/0x97
+
+# Green Thunderlord
+R:955:0x05/0x82
+
+# Blue Thunderlord
+R:956:0x06/0x82
+
+# Brown Thunderlord
+R:957:0x07/0x82
+
+# Bronze Thunderlord
+R:958:0x0F/0x82
+
+# Gold Thunderlord
+R:959:0x0B/0x82
+
+# Blood Sprout
+R:960:0x05/0xEE
+
+# Gorlim, Betrayer of Barahir
+R:961:0x02/0xAA
+
+# The Blubbering idiot, agent of black market, Simon the weak
+R:962:0x09/0xAE
+
+# Aranea
+R:963:0x04/0x93
+
+# Elder aranea
+R:964:0x0A/0x93
+
+# Giant brown tick
+R:965:0x07/0x93
+
+# Wavelord
+R:966:0x06/0xAA
+
+# Novice possessor (soul)
+R:967:0x08/0x87
+
+# Bat of Gorgoroth
+R:968:0x05/0x9C
+
+# The Princess
+R:969:0x0B/0xAA
+
+# Merton Proudfoot, the lost hobbit
+R:970:0x0A/0xA2
+
+# The Wight-King of the Barrow-downs
+R:971:0x0A/0x97
+
+# Adventurer
+R:972:0x0F/0x80
+
+# Experienced possessor (soul)
+R:973:0x08/0x87
+
+# Old possessor (soul)
+R:974:0x08/0x87
+
+# Death orb
+R:975:0x08/0x85
+
+# Bronze dragon worm
+R:976:0x0F/0xB1
+
+# Gold dragon worm
+R:977:0x0B/0xB1
+
+# Moldoux, the Defenceless Mold
+R:978:0x0A/0xA7
+
+# The Physics Teacher
+R:979:0x01/0xAA
+
+# Ar-Pharazon the Golden
+R:980:0x0B/0xAA
+
+# Doppelganger
+R:981:0x01/0x80
+
+# Marylene, Heartbreakeress of the Netherworld
+R:982:0x09/0x90
+
+# The Greater Lag Monster
+R:983:0x0A/0x95
+
+# Hrungnir, the Stone Giant
+R:984:0x09/0x90
+
+# Bullroarer the Hobbit
+R:985:0x0F/0xA2
+
+# 3-headed hydra
+R:986:0x03/0x8D
+
+# Uldor the Accursed
+R:987:0x0F/0xAA
+
+# Mystic
+R:988:0x03/0xAA
+
+# Elder vampire
+R:989:0x04/0x96
+
+# Ulfang the Black
+R:990:0x0F/0xAA
+
+# Demonologist
+R:991:0x0C/0xAA
+
+# Hezrou
+R:992:0x05/0x95
+
+# Glabrezu
+R:993:0x0F/0x95
+
+# Nalfeshnee
+R:994:0x04/0x95
+
+# Marilith
+R:995:0x0B/0x95
+
+# Lesser Balrog
+R:996:0x0A/0x95
+
+# Master mystic
+R:997:0x03/0xAA
+
+# Grand master mystic
+R:998:0x03/0xAA
+
+# Erinyes
+R:999:0x07/0x95
+
+# Novice mindcrafter
+R:1000:0x0B/0xAA
+
+# Polyphemus, the Blind Cyclops
+R:1001:0x05/0x90
+
+# Great Wyrm of Perplexity
+R:1002:0x0F/0x84
+
+# Hound of Tindalos
+R:1003:0x02/0x9A
+
+# Great Wyrm of Thunder
+R:1004:0x0B/0x84
+
+# Silver mouse
+R:1005:0x09/0xAC
+
+# The Rat King
+R:1006:0x0A/0xAC
+
+# Vort the Kobold Queen
+R:1007:0x0A/0xA5
+
+# Giant black louse
+R:1008:0x08/0x89
+
+# Fire Phantom
+R:1009:0x04/0x87
+
+# The Insane Player
+R:1010:0x0A/0xAA
+
+# Glaryssa, Succubus Queen
+R:1011:0x09/0x95
+
+# Vermicious Knid
+R:1012:0x02/0xA4
+
+# Bone golem
+R:1013:0x01/0xA1
+
+# Snake of Yig
+R:1014:0x06/0x8A
+
+# Bronze golem
+R:1015:0x03/0xA1
+
+# Dimensional shambler
+R:1016:0x0E/0xA2
+
+# Cultist
+R:1017:0x0D/0xAA
+
+# Cult leader
+R:1018:0x0D/0xAA
+
+# Servitor of the outer gods
+R:1019:0x0B/0x88
+
+# Avatar of Nyarlathotep
+R:1020:0x0C/0xAA
+
+# Thiazi, the Storm Giant
+R:1021:0x0E/0x90
+
+# Hypnos, Lord of Sleep
+R:1022:0x0D/0xAA
+
+# Blue dragon worm
+R:1023:0x0E/0xB1
+
+# White dragon worm
+R:1024:0x09/0xB1
+
+# Green dragon worm
+R:1025:0x0D/0xB1
+
+# Black dragon worm
+R:1026:0x02/0xB1
+
+# Red dragon worm
+R:1027:0x0C/0xB1
+
+# Multi-hued dragon worm
+R:1028:0x0A/0xB1
+
+# The Minotaur of the Labyrinth
+R:1029:0x02/0x88
+
+# The Sandworm Queen
+R:1030:0x0A/0xB1
+
+# Sandworm
+R:1031:0x0B/0xB1
+
+# Tik'srvzllat
+R:1032:0x0A/0x87
+
+# The Glass Golem
+R:1033:0x09/0xBC
+
+# The White Balrog
+R:1034:0x09/0x95
+
+# Golgarach, the Living Rock
+R:1035:0x09/0xBC
+
+# Atlas, the Titan
+R:1036:0x02/0x90
+
+# Kronos, Lord of the Titans
+R:1037:0x0A/0x90
+
+# Water hound
+R:1038:0x04/0x9A
+
+# Improv, the mighty MoLD
+R:1039:0x0A/0xA7
+
+# Emperor Mimic
+R:1040:0x0B/0xA7
+
+# Melinda Proudfoot
+R:1041:0x0A/0xA2
+
+# Thrain, the King Under the Mountain
+R:1042:0x0E/0xA2
+
+# Fire golem
+R:1043:0x04/0xA1
+
+# Melkor, Lord of Darkness
+R:1044:0x0A/0x87
+
+# Spirit
+R:1045:0x0A/0x87
+
+# Spirit
+R:1046:0x0E/0x87
+
+# Spirit
+R:1047:0x0E/0x87
+
+# Spirit
+R:1048:0x0A/0x87
+
+# Spirit
+R:1049:0x0F/0x87
+
+# Spirit
+R:1050:0x0A/0x87
+
+# Spirit
+R:1051:0x05/0x87
+
+# Spirit
+R:1052:0x0A/0x87
+
+# Spirit
+R:1053:0x09/0xB5
+
+# Spirit
+R:1054:0x05/0x87
+
+# Spirit
+R:1055:0x09/0x87
+
+# Spirit
+R:1056:0x00/0x87
+
+# Spirit
+R:1057:0x07/0x87
+
+# Spirit
+R:1058:0x04/0x87
+
+# Spirit
+R:1059:0x0D/0x87
+
+# Spirit
+R:1060:0x09/0x87
+
+# Spirit
+R:1061:0x02/0x87
+
+# Spirit
+R:1062:0x06/0x87
+
+# Spirit
+R:1063:0x04/0x87
+
+# Spirit
+R:1064:0x01/0x87
+
+# Spirit
+R:1065:0x02/0x87
+
+# Spirit
+R:1066:0x06/0x87
+
+# Spirit
+R:1067:0x0A/0x87
+
+# Spirit
+R:1068:0x00/0x87
+
+# Spirit
+R:1069:0x09/0x87
+
+# Spirit
+R:1070:0x0A/0x87
+
+# Spirit
+R:1071:0x0D/0x87
+
+# Spirit
+R:1072:0x0B/0x87
+
+# Spirit
+R:1073:0x08/0x87
+
+# Spirit
+R:1074:0x03/0x87
+
+# Spirit
+R:1075:0x0A/0x87
+
+
diff --git a/lib/mods/theme/pref/graf-iso.prf b/lib/mods/theme/pref/graf-iso.prf
new file mode 100644
index 00000000..eaf26901
--- /dev/null
+++ b/lib/mods/theme/pref/graf-iso.prf
@@ -0,0 +1,5963 @@
+# File: graf-iso.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+# with the isometric view.
+#
+# By Hansjoerg Malthaner < hansjoerg.malthaner@gmx.de >
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+# Scrolls (?)
+S:0xD0:0x80/0xBF
+S:0xD1:0x80/0xBF
+S:0xD2:0x80/0xBF
+S:0xD3:0x80/0xBF
+S:0xD4:0x80/0xBF
+S:0xD5:0x80/0xBF
+S:0xD6:0x80/0xBF
+S:0xD7:0x80/0xBF
+S:0xD8:0x80/0xBF
+S:0xD9:0x80/0xBF
+S:0xDA:0x80/0xBF
+S:0xDB:0x80/0xBF
+S:0xDC:0x80/0xBF
+S:0xDD:0x80/0xBF
+S:0xDE:0x80/0xBF
+S:0xDF:0x80/0xBF
+
+# Potions (!)
+S:0xE0:0x81/0x68
+S:0xE1:0x81/0x69
+S:0xE2:0x81/0x6A
+S:0xE3:0x81/0x6B
+S:0xE4:0x81/0x6C
+S:0xE5:0x81/0x6D
+S:0xE6:0x81/0x6E
+S:0xE7:0x81/0x6F
+S:0xE8:0x81/0x68
+S:0xE9:0x81/0x69
+S:0xEA:0x81/0x6A
+S:0xEB:0x81/0x6B
+S:0xEC:0x81/0x6C
+S:0xED:0x81/0x6D
+S:0xEE:0x81/0x6E
+S:0xEF:0x81/0x6F
+
+
+# Food (,)
+S:0xF0:0x90/0x92
+S:0xF1:0x90/0x92
+S:0xF2:0x90/0x92
+S:0xF3:0x90/0x92
+S:0xF4:0x90/0x92
+S:0xF5:0x90/0x92
+S:0xF6:0x90/0x92
+S:0xF7:0x90/0x92
+S:0xF8:0x90/0x92
+S:0xF9:0x90/0x92
+S:0xFA:0x90/0x92
+S:0xFB:0x90/0x92
+S:0xFC:0x90/0x92
+S:0xFD:0x90/0x92
+S:0xFE:0x90/0x92
+S:0xFF:0x90/0x92
+
+
+# Spells (*)
+S:48:0x82/0x60
+S:49:0x82/0x61
+S:50:0x82/0x62
+S:51:0x82/0x63
+S:52:0x82/0x64
+S:53:0x82/0x65
+S:54:0x82/0x66
+S:55:0x82/0x67
+S:56:0x82/0x60
+S:57:0x82/0x61
+S:58:0x82/0x62
+S:59:0x82/0x63
+S:60:0x82/0x64
+S:61:0x82/0x65
+S:62:0x82/0x66
+S:63:0x82/0x67
+
+# Spells (|)
+S:64:0x82/0x40
+S:65:0x82/0x44
+S:66:0x82/0x48
+S:67:0x82/0x4C
+S:68:0x82/0x50
+S:69:0x82/0x54
+S:70:0x82/0x58
+S:71:0x82/0x5C
+S:72:0x82/0x40
+S:73:0x82/0x44
+S:74:0x82/0x48
+S:75:0x82/0x4C
+S:76:0x82/0x50
+S:77:0x82/0x54
+S:78:0x82/0x58
+S:79:0x82/0x5C
+
+# Spells (-)
+S:80:0x82/0x41
+S:81:0x82/0x45
+S:82:0x82/0x49
+S:83:0x82/0x4D
+S:84:0x82/0x51
+S:85:0x82/0x55
+S:86:0x82/0x59
+S:87:0x82/0x5D
+S:88:0x82/0x41
+S:89:0x82/0x45
+S:90:0x82/0x49
+S:91:0x82/0x4D
+S:92:0x82/0x51
+S:93:0x82/0x55
+S:94:0x82/0x59
+S:95:0x82/0x5D
+
+# Spells (/)
+S:96:0x82/0x42
+S:97:0x82/0x46
+S:98:0x82/0x4A
+S:99:0x82/0x4E
+S:100:0x82/0x52
+S:101:0x82/0x56
+S:102:0x82/0x5A
+S:103:0x82/0x5D
+S:104:0x82/0x42
+S:105:0x82/0x46
+S:106:0x82/0x4A
+S:107:0x82/0x4D
+S:108:0x82/0x52
+S:109:0x82/0x56
+S:110:0x82/0x5A
+S:111:0x82/0x5D
+
+# Spells (\)
+S:112:0x82/0x43
+S:113:0x82/0x47
+S:114:0x82/0x4B
+S:115:0x82/0x4F
+S:116:0x82/0x53
+S:117:0x82/0x57
+S:118:0x82/0x5B
+S:119:0x82/0x5F
+S:120:0x82/0x43
+S:121:0x82/0x47
+S:122:0x82/0x4B
+S:123:0x82/0x4F
+S:124:0x82/0x53
+S:125:0x82/0x57
+S:126:0x82/0x5B
+S:127:0x82/0x5F
+
+
+# Feature attr/char definitions
+
+# nothing
+F:0:0x80:0xA0
+
+# open floor
+F:1:0x82:0xBC
+
+# fountain
+F:2:0x81:0x8D
+
+# glyph of warding
+F:3:0x80:0xBB
+
+# open door
+F:4:0x80:0xA7
+
+# broken door
+F:5:0x80:0xA7
+
+# up staircase
+F:6:0x80:0xBC
+
+# down staircase
+F:7:0x80:0xBE
+
+# quest entrance
+F:8:0x80:0xBE
+
+# quest exit
+F:9:0x80:0xBC
+
+# quest down level
+F:10:0x80:0xBE
+
+# quest up level
+F:11:0x80:0xBC
+
+# town exit
+F:12:0x80:0xBE
+
+# shaft down
+F:13:0x80:0xBE
+
+# shaft up
+F:14:0x80:0xBC
+
+# fountain
+F:15:0x81:0x8D
+
+# door
+F:32:0x80:0xAB
+
+# locked door
+F:33:0x80:0xAB
+
+# locked door
+F:34:0x80:0xAB
+
+# locked door
+F:35:0x80:0xAB
+
+# locked door
+F:36:0x80:0xAB
+
+# locked door
+F:37:0x80:0xAB
+
+# locked door
+F:38:0x80:0xAB
+
+# locked door
+F:39:0x80:0xAB
+
+# jammed door
+F:40:0x80:0xAB
+
+# jammed door
+F:41:0x80:0xAB
+
+# jammed door
+F:42:0x80:0xAB
+
+# jammed door
+F:43:0x80:0xAB
+
+# jammed door
+F:44:0x80:0xAB
+
+# jammed door
+F:45:0x80:0xAB
+
+# jammed door
+F:46:0x80:0xAB
+
+# jammed door
+F:47:0x80:0xAB
+
+# secret door
+F:48:0x80:0xA3
+
+# pile of rubble
+F:49:0x80:0xBA
+
+# magma vein
+F:50:0x80:0xA5
+
+# quartz vein
+F:51:0x81:0xF3
+
+# magma vein
+F:52:0x81:0xF3
+
+# quartz vein
+F:53:0x81:0xF3
+
+# magma vein with treasure
+F:54:0x80:0xAA
+
+# quartz vein with treasure
+F:55:0x80:0xAA
+
+# granite wall
+F:56:0x81:0xF0
+
+# granite wall
+F:57:0x81:0xF0
+
+# granite wall
+F:58:0x81:0xF0
+
+# granite wall
+F:59:0x81:0xF0
+
+# permanent wall
+F:60:0x81:0xF3
+
+# permanent wall
+F:61:0x81:0xF3
+
+# permanent wall
+F:62:0x81:0xF3
+
+# permanent wall
+F:63:0x81:0xF3
+
+# explosive rune
+F:64:0x80:0xAA
+
+# Straight Road startpoint
+F:65:0x80:0xAA
+
+# section of the Straight Road
+F:66:0x80:0xAA
+
+# section of the Straight Road
+F:67:0x80:0xAA
+
+# section of the Straight Road
+F:68:0x80:0xAA
+
+# section of the Straight Road
+F:69:0x80:0xAA
+
+# section of the Straight Road
+F:70:0x80:0xAA
+
+# section of the Straight Road (discharged)
+F:71:0x80:0xAA
+
+# Straight Road exit
+F:72:0x80:0xAA
+
+# corrupted section of the Straight Road
+F:73:0x80:0xAA
+
+# General Store
+B:0:0x80:0xB0
+
+# Armoury
+B:1:0x80:0xB1
+
+# Weapon Smiths
+B:2:0x80:0xB2
+
+# Temple
+B:3:0x80:0xB3
+
+# Alchemy Shop
+B:4:0x80:0xB4
+
+# Magic Shop
+B:5:0x80:0xB5
+
+# Black Market
+B:6:0x80:0xB6
+
+# Home
+B:7:0x80:0xB7
+
+# Bookstore
+B:8:0x80:0xB8
+
+# Pet shop
+B:9:0x80:0xAB
+
+# Mayors office
+B:10:0x80:0xAB
+
+# Inn
+B:11:0x80:0xAB
+
+# The Soothsayer
+B:12:0x80:0xAB
+
+# The library
+B:13:0x80:0xAB
+
+B:14:0x80:0xAB
+B:15:0x80:0xAB
+B:16:0x80:0xAB
+B:17:0x80:0xAB
+B:18:0x80:0xAB
+B:19:0x80:0xAB
+B:20:0x80:0xAB
+B:21:0x80:0xAB
+B:22:0x80:0xAB
+B:23:0x80:0xAB
+B:24:0x80:0xAB
+B:25:0x80:0xAB
+B:26:0x80:0xAB
+B:27:0x80:0xAB
+B:28:0x80:0xAB
+B:29:0x80:0xAB
+B:30:0x80:0xAB
+B:31:0x80:0xAB
+B:32:0x80:0xAB
+B:33:0x80:0xAB
+B:34:0x80:0xAB
+B:35:0x80:0xAB
+B:36:0x80:0xAB
+B:37:0x80:0xAB
+
+# Building
+F:74:0x80:0xB1
+
+# permanent wall
+F:75:0x80:0xA3
+
+# permanent wall
+F:76:0x80:0xA3
+
+# permanent wall
+F:77:0x80:0xA3
+
+# permanent wall
+F:78:0x80:0xA3
+
+# Deep water
+F:83:0xCB:0x81
+
+# stream of shallow water
+F:84:0x82:0xEB
+
+# pool of deep lava
+F:85:0x80:0xA3
+
+# stream of shallow lava
+F:86:0x80:0xA3
+
+# dark pit
+F:87:0x83:0x8B
+
+# dirt
+F:88:0x82:0xF3
+
+# patch of grass
+F:89:0x82:0xE8
+
+# ice
+F:90:0x80:0xAE
+
+# sand
+F:91:0x80:0xAE
+
+# dead tree
+F:92:0x80:0xA3
+
+# ash
+F:93:0x80:0xAE
+
+# mud
+F:94:0x80:0xAE
+
+# ice wall
+F:95:0x80:0x80
+
+# tree
+F:96:0x83:0x88
+
+# mountain chain
+F:97:0x81:0x9D
+
+# sandwall
+F:98:0x80:0xA3
+
+# sandwall
+F:99:0x80:0xA5
+
+# sandwall with treasure
+F:100:0x80:0xAA
+
+# high mountain chain
+F:101:0x80:0xDE
+
+# nether mist
+F:102:0x80:0x80
+
+# molten glass wall
+F:103:0x80:0xAE
+
+# Between gate
+F:160:0x81:0x8C
+
+# Altar of Forests
+F:161:0x81:0x94
+
+# Altar of Water
+F:162:0x81:0x94
+
+# Altar of Earth
+F:163:0x81:0x94
+
+# Altar of Darkness
+F:164:0x81:0x94
+
+# Altar of Moon
+F:165:0x81:0x94
+
+# Altar of Sun
+F:166:0x81:0x94
+
+# Altar of Rage
+F:167:0x81:0x94
+
+# Altar of Winds
+F:168:0x81:0x94
+
+# Altar of Stars
+F:169:0x81:0x94
+
+# Altar of Being
+F:170:0x81:0x94
+
+# Altar of Randomness
+F:171:0x81:0x94
+
+# pool of deep water
+F:187:0x82:0xF0
+
+# glass wall
+F:188:0x80:0xAE
+
+# illusion wall
+F:189:0x80:0xA3
+
+# Grass roof
+F:190:0x82:0xF6
+
+# grass roof top
+F:191:0x82:0xFE
+
+# grass roof chimney
+F:192:0x82:0xF7
+
+# brick roof
+F:193:0x82:0xEE
+
+# brick roof top
+F:194:0x82:0xEF
+
+# brick roof chimney
+F:195:0x80:0xA3
+
+# window
+F:196:0x80:0xA3
+
+# small window
+F:197:0x80:0xA3
+
+# rain barrel
+F:198:0x80:0xA3
+
+# grass with flowers
+F:199:0x82:0xF8
+
+# cobblestone road
+F:200:0x83:0x83
+
+# cobblestone with outlet
+F:201:0x80:0xAE
+
+# small tree
+F:202:0x80:0xA3
+
+# town
+F:203:0x80:0xAA
+
+
+
+
+
+
+
+# Object attr/char definitions
+
+# something
+K:0:0x80:0xA6
+
+# Blindness
+K:1:0x80:0xAC
+
+# Paranoia
+K:2:0x80:0xAC
+
+# Confusion
+K:3:0x80:0xAC
+
+# Hallucination
+K:4:0x80:0xAC
+
+# Cure Poison
+K:5:0x80:0xAC
+
+# Cure Blindness
+K:6:0x80:0xAC
+
+# Cure Paranoia
+K:7:0x80:0xAC
+
+# Cure Confusion
+K:8:0x80:0xAC
+
+# Weakness
+K:9:0x80:0xAC
+
+# Unhealth
+K:10:0x80:0xAC
+
+# Restore Constitution
+K:11:0x80:0xAC
+
+# Restoring
+K:12:0x80:0xAC
+
+# Stupidity
+K:13:0x80:0xAC
+
+# Naivety
+K:14:0x80:0xAC
+
+# Poison
+K:15:0x80:0xAC
+
+# Sickness
+K:16:0x80:0xAC
+
+# Paralysis
+K:17:0x80:0xAC
+
+# Restore Strength
+K:18:0x80:0xAC
+
+# Disease
+K:19:0x80:0xAC
+
+# Cure Serious Wounds
+K:20:0x80:0xAC
+
+# & Ration~ of Food
+K:21:0x80:0xAC
+
+# & Hard Biscuit~
+K:22:0x80:0xAC
+
+# & Strip~ of Venison
+K:23:0x80:0xAC
+
+# & Slime Mold~
+K:24:0x80:0xAC
+
+# & Piece~ of Elvish Waybread
+K:25:0x80:0xAC
+
+# & Pint~ of Fine Ale
+K:26:0x80:0xAC
+
+# & Pint~ of Fine Wine
+K:27:0x80:0xAC
+
+# & Mattock~
+K:28:0x80:0xDC
+
+# & No-dachi~
+K:29:0x80:0xFC
+
+# & Broken Dagger~
+K:30:0x80:0xFC
+
+# & Bastard Sword~
+K:31:0x80:0xFC
+
+# & Scimitar~
+K:32:0x80:0xFC
+
+# & Tulwar~
+K:33:0x80:0xFC
+
+# & Broad Sword~
+K:34:0x80:0xFC
+
+# & Short Sword~
+K:35:0x80:0xFC
+
+# & Blade~ of Chaos
+K:36:0x80:0xFC
+
+# & Two-Handed Sword~
+K:37:0x80:0xFC
+
+# & Main Gauche~
+K:38:0x80:0xFC
+
+# & Cutlass~
+K:39:0x80:0xFC
+
+# & Executioner's Sword~
+K:40:0x80:0xFC
+
+# & Katana~
+K:41:0x80:0xFC
+
+# & Long Sword~
+K:42:0x80:0xFC
+
+# & Dagger~
+K:43:0x80:0xFC
+
+# & Rapier~
+K:44:0x80:0xFC
+
+# & Sabre~
+K:45:0x80:0xFC
+
+# & Small Sword~
+K:46:0x80:0xFC
+
+# & Broken Sword~
+K:47:0x80:0xFC
+
+# & Ball-and-Chain~
+K:48:0x80:0xDC
+
+# & Whip~
+K:49:0x80:0xDC
+
+# & Flail~
+K:50:0x80:0xDC
+
+# & Two-Handed Flail~
+K:51:0x80:0xDC
+
+# & Morning Star~
+K:52:0x80:0xDC
+
+# & Mace~
+K:53:0x80:0xDC
+
+# & Quarterstaff~
+K:54:0x80:0xDC
+
+# & War Hammer~
+K:55:0x80:0xDC
+
+# & Lead-Filled Mace~
+K:56:0x80:0xDC
+
+# & Mace~ of Disruption
+K:57:0x80:0xDC
+
+# & Lucerne Hammer~
+K:58:0x80:0xDC
+
+# & Beaked Axe~
+K:59:0x80:0xAF
+
+# & Glaive~
+K:60:0x80:0xAF
+
+# & Halberd~
+K:61:0x80:0xAF
+
+# & Awl-Pike~
+K:62:0x80:0xAF
+
+# & Pike~
+K:63:0x80:0xAF
+
+# & Spear~
+K:64:0x80:0xAF
+
+# & Trident~
+K:65:0x80:0xAF
+
+# & Lance~
+K:66:0x80:0xAF
+
+# & Great Axe~
+K:67:0x80:0xAF
+
+# & Battle Axe~
+K:68:0x80:0xAF
+
+# & Lochaber Axe~
+K:69:0x80:0xAF
+
+# & Broad Axe~
+K:70:0x80:0xAF
+
+# & Scythe~
+K:71:0x80:0xAF
+
+# & Scythe~ of Slicing
+K:72:0x80:0xAF
+
+# & Short Bow~
+K:73:0x80:0xFD
+
+# & Long Bow~
+K:74:0x80:0xFD
+
+# & Light Crossbow~
+K:75:0x80:0xFD
+
+# & Heavy Crossbow~
+K:76:0x80:0xFD
+
+# & Sling~
+K:77:0x80:0xFD
+
+# & Arrow~
+K:78:0x80:0xFB
+
+# & Seeker Arrow~
+K:79:0x80:0xFB
+
+# & Bolt~
+K:80:0x80:0xFB
+
+# & Seeker Bolt~
+K:81:0x80:0xFB
+
+# & Rounded Pebble~
+K:82:0x81:0x93
+
+# & Iron Shot~
+K:83:0x80:0xFB
+
+# & Shovel~
+K:84:0x80:0xDC
+
+# & Gnomish Shovel~
+K:85:0x80:0xDC
+
+# & Dwarven Shovel~
+K:86:0x80:0xDC
+
+# & Pick~
+K:87:0x80:0xDC
+
+# & Orcish Pick~
+K:88:0x80:0xDC
+
+# & Dwarven Pick~
+K:89:0x80:0xDC
+
+# & Elven Cloak~
+K:90:0x80:0xA8
+
+# & Pair~ of Soft Leather Boots
+K:91:0x80:0xDD
+
+# & Pair~ of Hard Leather Boots
+K:92:0x80:0xDD
+
+# & Pair~ of Metal Shod Boots
+K:93:0x80:0xDD
+
+# & Hard Leather Cap~
+K:94:0x80:0xDD
+
+# & Metal Cap~
+K:95:0x80:0xDD
+
+# & Iron Helm~
+K:96:0x80:0xDD
+
+# & Steel Helm~
+K:97:0x80:0xDD
+
+# & Iron Crown~
+K:98:0x80:0xDD
+
+# & Golden Crown~
+K:99:0x80:0xDD
+
+# & Jewel Encrusted Crown~
+K:100:0x80:0xDD
+
+# & Robe~
+K:101:0x80:0xA8
+
+# & Filthy Rag~
+K:102:0x80:0xA8
+
+# Soft Leather Armour~
+K:103:0x80:0xA8
+
+# Soft Studded Leather~
+K:104:0x80:0xA8
+
+# Hard Leather Armour~
+K:105:0x80:0xA8
+
+# Hard Studded Leather~
+K:106:0x80:0xA8
+
+# Leather Scale Mail~
+K:107:0x80:0xA8
+
+# Metal Scale Mail~
+K:108:0x80:0xDB
+
+# Chain Mail~
+K:109:0x80:0xDB
+
+# Rusty Chain Mail~
+K:110:0x80:0xDB
+
+# Augmented Chain Mail~
+K:111:0x80:0xDB
+
+# Bar Chain Mail~
+K:112:0x80:0xDB
+
+# Metal Brigandine Armour~
+K:113:0x80:0xDB
+
+# Partial Plate Armour~
+K:114:0x80:0xDB
+
+# Metal Lamellar Armour~
+K:115:0x80:0xDB
+
+# Full Plate Armour~
+K:116:0x80:0xDB
+
+# Ribbed Plate Armour~
+K:117:0x80:0xDB
+
+# Adamantite Plate Mail~
+K:118:0x80:0xDB
+
+# Mithril Plate Mail~
+K:119:0x80:0xDB
+
+# Mithril Chain Mail~
+K:120:0x80:0xDB
+
+# Double Chain Mail~
+K:121:0x80:0xDB
+
+# & Shield~ of Deflection
+K:122:0x80:0xDB
+
+# & Cloak~
+K:123:0x80:0xA8
+
+# & Shadow Cloak~
+K:124:0x80:0xA8
+
+# & Set~ of Leather Gloves
+K:125:0x80:0xDD
+
+# & Set~ of Gauntlets
+K:126:0x80:0xDD
+
+# & Set~ of Cesti
+K:127:0x80:0xDD
+
+# & Small Leather Shield~
+K:128:0x80:0xA9
+
+# & Large Leather Shield~
+K:129:0x80:0xA9
+
+# & Small Metal Shield~
+K:130:0x80:0xA9
+
+# & Large Metal Shield~
+K:131:0x80:0xA9
+
+# Strength
+K:132:0x80:0xBD
+
+# Dexterity
+K:133:0x80:0xBD
+
+# Constitution
+K:134:0x80:0xBD
+
+# Intelligence
+K:135:0x80:0xBD
+
+# Speed
+K:136:0x80:0xBD
+
+# Searching
+K:137:0x80:0xBD
+
+# Teleportation
+K:138:0x80:0xBD
+
+# Slow Digestion
+K:139:0x80:0xBD
+
+# Resist Fire
+K:140:0x80:0xBD
+
+# Resist Cold
+K:141:0x80:0xBD
+
+# Levitation
+K:142:0x80:0xBD
+
+# Poison Resistance
+K:143:0x80:0xBD
+
+# Free Action
+K:144:0x80:0xBD
+
+# Weakness
+K:145:0x80:0xBD
+
+# Flames
+K:146:0x80:0xBD
+
+# Acid
+K:147:0x80:0xBD
+
+# Ice
+K:148:0x80:0xBD
+
+# Woe
+K:149:0x80:0xBD
+
+# Stupidity
+K:150:0x80:0xBD
+
+# Damage
+K:151:0x80:0xBD
+
+# Accuracy
+K:152:0x80:0xBD
+
+# Protection
+K:153:0x80:0xBD
+
+# Aggravate Monster
+K:154:0x80:0xBD
+
+# See Invisible
+K:155:0x80:0xBD
+
+# Sustain Strength
+K:156:0x80:0xBD
+
+# Sustain Intelligence
+K:157:0x80:0xBD
+
+# Sustain Wisdom
+K:158:0x80:0xBD
+
+# Sustain Constitution
+K:159:0x80:0xBD
+
+# Sustain Dexterity
+K:160:0x80:0xBD
+
+# Sustain Charisma
+K:161:0x80:0xBD
+
+# Slaying
+K:162:0x80:0xBD
+
+# Brilliance
+K:163:0x80:0xA2
+
+# Charisma
+K:164:0x80:0xA2
+
+# Searching
+K:165:0x80:0xA2
+
+# Teleportation
+K:166:0x80:0xA2
+
+# Slow Digestion
+K:167:0x80:0xA2
+
+# Resist Acid
+K:168:0x80:0xA2
+
+# Adornment
+K:169:0x80:0xA2
+
+# Double Ring Mail~
+K:170:0x80:0xDB
+
+# the Magi
+K:171:0x80:0xA2
+
+# DOOM
+K:172:0x80:0xA2
+
+# Enchant Weapon To-Hit
+K:173:0x80:0xBF
+
+# Enchant Weapon To-Dam
+K:174:0x80:0xBF
+
+# Enchant Armor
+K:175:0x80:0xBF
+
+# Identify
+K:176:0x80:0xBF
+
+# *Identify*
+K:177:0x80:0xBF
+
+# Rumour
+K:178:0x80:0xBF
+
+# Chaos
+K:179:0x80:0xBF
+
+# Remove Curse
+K:180:0x80:0xBF
+
+# Light
+K:181:0x80:0xBF
+
+# Fire
+K:182:0x80:0xBF
+
+# Ice
+K:183:0x80:0xBF
+
+# Summon Monster
+K:184:0x80:0xBF
+
+# Phase Door
+K:185:0x80:0xBF
+
+# Teleportation
+K:186:0x80:0xBF
+
+# Teleport Level
+K:187:0x80:0xBF
+
+# Monster Confusion
+K:188:0x80:0xBF
+
+# Magic Mapping
+K:189:0x80:0xBF
+
+# Rune of Protection
+K:190:0x80:0xBF
+
+# *Remove Curse*
+K:191:0x80:0xBF
+
+# Treasure Detection
+K:192:0x80:0xBF
+
+# Object Detection
+K:193:0x80:0xBF
+
+# Trap Detection
+K:194:0x80:0xBF
+
+# & Sheaf Arrow~
+K:195:0x80:0xFB
+
+# & Mithril Shot~
+K:196:0x80:0xFB
+
+# Door/Stair Location
+K:197:0x80:0xBF
+
+# Acquirement
+K:198:0x80:0xBF
+
+# *Acquirement*
+K:199:0x80:0xBF
+
+# Mass Genocide
+K:200:0x80:0xBF
+
+# Detect Invisible
+K:201:0x80:0xBF
+
+# Aggravate Monster
+K:202:0x80:0xBF
+
+# Trap Creation
+K:203:0x80:0xBF
+
+# Trap/Door Destruction
+K:204:0x80:0xBF
+
+# Artifact Creation
+K:205:0x80:0xBF
+
+# Recharging
+K:206:0x80:0xBF
+
+# Genocide
+K:207:0x80:0xBF
+
+# Darkness
+K:208:0x80:0xBF
+
+# Protection from Evil
+K:209:0x80:0xBF
+
+# Satisfy Hunger
+K:210:0x80:0xBF
+
+# Dispel Undead
+K:211:0x80:0xBF
+
+# *Enchant Weapon*
+K:212:0x80:0xBF
+
+# Curse Weapon
+K:213:0x80:0xBF
+
+# *Enchant Armor*
+K:214:0x80:0xBF
+
+# Curse Armor
+K:215:0x80:0xBF
+
+# Summon Undead
+K:216:0x80:0xBF
+
+# Blessing
+K:217:0x80:0xBF
+
+# Holy Chant
+K:218:0x80:0xBF
+
+# Holy Prayer
+K:219:0x80:0xBF
+
+# Word of Recall
+K:220:0x80:0xBF
+
+# *Destruction*
+K:221:0x80:0xBF
+
+# Slime Mold Juice
+K:222:0x80:0xA1
+
+# Apple Juice
+K:223:0x80:0xA1
+
+# Water
+K:224:0x80:0xA1
+
+# Strength
+K:225:0x80:0xA1
+
+# Weakness
+K:226:0x80:0xA1
+
+# Restore Strength
+K:227:0x80:0xA1
+
+# Intelligence
+K:228:0x80:0xA1
+
+# Stupidity
+K:229:0x80:0xA1
+
+# Restore Intelligence
+K:230:0x80:0xA1
+
+# Wisdom
+K:231:0x80:0xA1
+
+# Naivety
+K:232:0x80:0xA1
+
+# Restore Wisdom
+K:233:0x80:0xA1
+
+# Charisma
+K:234:0x80:0xA1
+
+# Ugliness
+K:235:0x80:0xA1
+
+# Restore Charisma
+K:236:0x80:0xA1
+
+# Curing
+K:237:0x80:0xA1
+
+# Invulnerability
+K:238:0x80:0xA1
+
+# New Life
+K:239:0x80:0xA1
+
+# Cure Serious Wounds
+K:240:0x80:0xA1
+
+# Cure Critical Wounds
+K:241:0x80:0xA1
+
+# Healing
+K:242:0x80:0xA1
+
+# Constitution
+K:243:0x80:0xA1
+
+# Experience
+K:244:0x80:0xA1
+
+# Sleep
+K:245:0x80:0xA1
+
+# Blindness
+K:246:0x80:0xA1
+
+# Booze
+K:247:0x80:0xA1
+
+# Poison
+K:248:0x80:0xA1
+
+# Speed
+K:249:0x80:0xA1
+
+# Slowness
+K:250:0x80:0xA1
+
+# Dexterity
+K:251:0x80:0xA1
+
+# Restore Dexterity
+K:252:0x80:0xA1
+
+# Restore Constitution
+K:253:0x80:0xA1
+
+# Lose Memories
+K:254:0x80:0xA1
+
+# Salt Water
+K:255:0x80:0xA1
+
+# Enlightenment
+K:256:0x80:0xA1
+
+# Heroism
+K:257:0x80:0xA1
+
+# Berserk Strength
+K:258:0x80:0xA1
+
+# Boldness
+K:259:0x80:0xA1
+
+# Restore Life Levels
+K:260:0x80:0xA1
+
+# Resist Heat
+K:261:0x80:0xA1
+
+# Resist Cold
+K:262:0x80:0xA1
+
+# Detect Invisible
+K:263:0x80:0xA1
+
+# Slow Poison
+K:264:0x80:0xA1
+
+# Neutralise Poison
+K:265:0x80:0xA1
+
+# Restore Mana
+K:266:0x80:0xA1
+
+# Infra-vision
+K:267:0x80:0xA1
+
+# Resistance
+K:268:0x80:0xA1
+
+# Light
+K:269:0x80:0xAD
+
+# Tame Monster
+K:270:0x80:0xAD
+
+# Frost Bolts
+K:271:0x80:0xAD
+
+# Fire Bolts
+K:272:0x80:0xAD
+
+# Stone to Mud
+K:273:0x80:0xAD
+
+# Polymorph
+K:274:0x80:0xAD
+
+# Heal Monster
+K:275:0x80:0xAD
+
+# Haste Monster
+K:276:0x80:0xAD
+
+# Slow Monster
+K:277:0x80:0xAD
+
+# Confuse Monster
+K:278:0x80:0xAD
+
+# Sleep Monster
+K:279:0x80:0xAD
+
+# Drain Life
+K:280:0x80:0xAD
+
+# Trap/Door Destruction
+K:281:0x80:0xAD
+
+# Magic Missile
+K:282:0x80:0xAD
+
+# Clone Monster
+K:283:0x80:0xAD
+
+# Scare Monster
+K:284:0x80:0xAD
+
+# Teleport Other
+K:285:0x80:0xAD
+
+# Disarming
+K:286:0x80:0xAD
+
+# Lightning Balls
+K:287:0x80:0xAD
+
+# Cold Balls
+K:288:0x80:0xAD
+
+# Fire Balls
+K:289:0x80:0xAD
+
+# Stinking Cloud
+K:290:0x80:0xAD
+
+# Acid Balls
+K:291:0x80:0xAD
+
+# Wonder
+K:292:0x80:0xAD
+
+# & Flight Arrow~
+K:293:0x80:0xFB
+
+# Acid Bolts
+K:294:0x80:0xAD
+
+# Dragon's Flame
+K:295:0x80:0xAD
+
+# Dragon's Frost
+K:296:0x80:0xAD
+
+# Dragon's Breath
+K:297:0x80:0xAD
+
+# Annihilation
+K:298:0x80:0xAD
+
+# Rockets
+K:299:0x80:0xAD
+
+# Trap Location
+K:300:0x80:0xDF
+
+# Treasure Location
+K:301:0x80:0xDF
+
+# Object Location
+K:302:0x80:0xDF
+
+# Teleportation
+K:303:0x80:0xDF
+
+# Earthquakes
+K:304:0x80:0xDF
+
+# Summoning
+K:305:0x80:0xDF
+
+# Light
+K:306:0x80:0xDF
+
+# *Destruction*
+K:307:0x80:0xDF
+
+# Starlight
+K:308:0x80:0xDF
+
+# Haste Monsters
+K:309:0x80:0xDF
+
+# Slow Monsters
+K:310:0x80:0xDF
+
+# Sleep Monsters
+K:311:0x80:0xDF
+
+# Cure Light Wounds
+K:312:0x80:0xDF
+
+# Detect Invisible
+K:313:0x80:0xDF
+
+# Speed
+K:314:0x80:0xDF
+
+# Slowness
+K:315:0x80:0xDF
+
+# Door/Stair Location
+K:316:0x80:0xDF
+
+# Remove Curse
+K:317:0x80:0xDF
+
+# Detect Evil
+K:318:0x80:0xDF
+
+# Curing
+K:319:0x80:0xDF
+
+# Dispel Evil
+K:320:0x80:0xDF
+
+# Probing
+K:321:0x80:0xDF
+
+# Darkness
+K:322:0x80:0xDF
+
+# Genocide
+K:323:0x80:0xDF
+
+# Power
+K:324:0x80:0xDF
+
+# the Magi
+K:325:0x80:0xDF
+
+# Perception
+K:326:0x80:0xDF
+
+# Holiness
+K:327:0x80:0xDF
+
+# Enlightenment
+K:328:0x80:0xDF
+
+# Healing
+K:329:0x80:0xDF
+
+# [Call of the West]
+K:330:0x80:0xBF
+
+# [Light of Valinor]
+K:331:0x80:0xBF
+
+# [Divine Mastery]
+K:332:0x80:0xBF
+
+# [Words of Power]
+K:333:0x80:0xBF
+
+# [Apprentice Handbook]
+K:334:0x80:0xBF
+
+# [Mystical Words]
+K:335:0x80:0xBF
+
+# [Arcane Chants]
+K:336:0x80:0xBF
+
+# [Locus of Force]
+K:337:0x80:0xBF
+
+# & Small wooden chest~
+K:338:0x80:0xFE
+
+# & Large wooden chest~
+K:339:0x80:0xFE
+
+# & Small iron chest~
+K:340:0x80:0xFE
+
+# & Large iron chest~
+K:341:0x80:0xFE
+
+# & Small steel chest~
+K:342:0x80:0xFE
+
+# & Large steel chest~
+K:343:0x80:0xFE
+
+# & Ruined chest~
+K:344:0x80:0xFE
+
+# & Iron Spike~
+K:345:0x81:0x91
+
+# & Wooden Torch~
+K:346:0x80:0xFE
+
+# & Brass Lantern~
+K:347:0x80:0xFE
+
+# & Flask~ of oil
+K:348:0x80:0xA1
+
+# & Empty Bottle~
+K:349:0x80:0xA1
+
+# Havoc
+K:350:0x80:0xAD
+
+# Door/Stair Location
+K:351:0x80:0xAD
+
+# Trap Location
+K:352:0x80:0xAD
+
+# Probing
+K:353:0x80:0xAD
+
+# Recall
+K:354:0x80:0xAD
+
+# Illumination
+K:355:0x80:0xAD
+
+# Light
+K:356:0x80:0xAD
+
+# Lightning Bolts
+K:357:0x80:0xAD
+
+# Frost Bolts
+K:358:0x80:0xAD
+
+# Fire Bolts
+K:359:0x80:0xAD
+
+# Polymorph
+K:360:0x80:0xAD
+
+# Slow Monster
+K:361:0x80:0xAD
+
+# Sleep Monster
+K:362:0x80:0xAD
+
+# Drain Life
+K:363:0x80:0xAD
+
+# Teleport Other
+K:364:0x80:0xAD
+
+# Disarming
+K:365:0x80:0xAD
+
+# Lightning Balls
+K:366:0x80:0xAD
+
+# Cold Balls
+K:367:0x80:0xAD
+
+# Fire Balls
+K:368:0x80:0xAD
+
+# Acid Balls
+K:369:0x80:0xAD
+
+# Acid Bolts
+K:370:0x80:0xAD
+
+# Enlightenment
+K:371:0x80:0xAD
+
+# Perception
+K:372:0x80:0xAD
+
+# Curing
+K:373:0x80:0xAD
+
+# Healing
+K:374:0x80:0xAD
+
+# Detection
+K:375:0x80:0xAD
+
+# Restoration
+K:376:0x80:0xAD
+
+# Speed
+K:377:0x80:0xAD
+
+# [Inner Void]
+K:378:0x80:0xBF
+
+# [Lurkings of the Night]
+K:379:0x80:0xBF
+
+# [Beings of Darkness]
+K:380:0x80:0xBF
+
+# [Material Shadow]
+K:381:0x80:0xBF
+
+# [Sign of Chaos]
+K:383:0x80:0xBF
+
+# [Chaos Mastery]
+K:384:0x80:0xBF
+
+# [Chaos Channels]
+K:385:0x80:0xBF
+
+# [Armageddon Tome]
+K:386:0x80:0xBF
+
+# [Nether Openings]
+K:387:0x80:0xBF
+
+# [Unholy Blessings]
+K:388:0x80:0xBF
+
+# & Firestone~
+K:389:0x80:0xFE
+
+# & Small Firestone~
+K:390:0x80:0xFE
+
+# & Broken Skull~
+K:391:0x80:0xFE
+
+# & Broken Bone~
+K:392:0x80:0xFE
+
+# & Canine Skeleton~
+K:393:0x80:0xFE
+
+# & Rodent Skeleton~
+K:394:0x80:0xFE
+
+# & Human Skeleton~
+K:395:0x80:0xFE
+
+# & Dwarf Skeleton~
+K:396:0x80:0xFE
+
+# & Elf Skeleton~
+K:397:0x80:0xFE
+
+# & Gnome Skeleton~
+K:398:0x80:0xFE
+
+# & Great Hammer~
+K:399:0x80:0xDC
+
+# Black Dragon Scale Mail~
+K:400:0x80:0xDB
+
+# Blue Dragon Scale Mail~
+K:401:0x80:0xDB
+
+# White Dragon Scale Mail~
+K:402:0x80:0xDB
+
+# Red Dragon Scale Mail~
+K:403:0x80:0xDB
+
+# Green Dragon Scale Mail~
+K:404:0x80:0xDB
+
+# Multi-Hued Dragon Scale Mail~
+K:405:0x80:0xDB
+
+# Pseudo Dragon Scale Mail~
+K:406:0x80:0xDB
+
+# Law Dragon Scale Mail~
+K:407:0x80:0xDB
+
+# Bronze Dragon Scale Mail~
+K:408:0x80:0xDB
+
+# Gold Dragon Scale Mail~
+K:409:0x80:0xDB
+
+# Chaos Dragon Scale Mail~
+K:410:0x80:0xDB
+
+# Balance Dragon Scale Mail~
+K:411:0x80:0xDB
+
+# Power Dragon Scale Mail~
+K:412:0x80:0xDB
+
+# & Dragon Helm~
+K:413:0x80:0xDD
+
+# & Dragon Shield~
+K:414:0x80:0xDB
+
+# Death
+K:415:0x80:0xA1
+
+# Ruination
+K:416:0x80:0xA1
+
+# Detonations
+K:417:0x80:0xA1
+
+# Augmentation
+K:418:0x80:0xA1
+
+# *Healing*
+K:419:0x80:0xA1
+
+# Life
+K:420:0x80:0xA1
+
+# Self Knowledge
+K:421:0x80:0xA1
+
+# *Enlightenment*
+K:422:0x80:0xA1
+
+# [Necromantic Incantations]
+K:423:0x80:0xBF
+
+# [Curses of Angmar]
+K:424:0x80:0xBF
+
+# Fear Resistance
+K:425:0x80:0xBD
+
+# Light and Darkness Resistance
+K:426:0x80:0xBD
+
+# Nether Resistance
+K:427:0x80:0xBD
+
+# Nexus Resistance
+K:428:0x80:0xBD
+
+# Sound Resistance
+K:429:0x80:0xBD
+
+# Confusion Resistance
+K:430:0x80:0xBD
+
+# Shard Resistance
+K:431:0x80:0xBD
+
+# Disenchantment Resistance
+K:432:0x80:0xBD
+
+# Chaos Resistance
+K:433:0x80:0xBD
+
+# Blindness Resistance
+K:434:0x80:0xBD
+
+# Lordly Protection
+K:435:0x80:0xBD
+
+# Extra Attacks
+K:436:0x80:0xBD
+
+# Cure Light Wounds
+K:437:0x80:0xA1
+
+# Clumsiness
+K:438:0x80:0xA1
+
+# Sickliness
+K:439:0x80:0xA1
+
+# Map of Bree
+K:440:0x80:0xBF
+
+# Map of Gondolin
+K:441:0x80:0xBF
+
+# Map of LothLorien
+K:442:0x80:0xBF
+
+# Map of Minas Anor
+K:443:0x80:0xBF
+
+# copper
+K:480:0x81:0xCA
+
+# copper
+K:481:0x81:0xC9
+
+# copper
+K:482:0x81:0xC8
+
+# silver
+K:483:0x80:0xA4
+
+# silver
+K:484:0x80:0xA4
+
+# silver
+K:485:0x80:0xA4
+
+# garnets
+K:486:0x80:0xA4
+
+# garnets
+K:487:0x80:0xA4
+
+# gold
+K:488:0x80:0xA4
+
+# gold
+K:489:0x80:0xA4
+
+# gold
+K:490:0x80:0xA4
+
+# opals
+K:491:0x80:0xA4
+
+# sapphires
+K:492:0x80:0xA4
+
+# rubies
+K:493:0x80:0xA4
+
+# diamonds
+K:494:0x80:0xA4
+
+# emeralds
+K:495:0x80:0xA4
+
+# mithril
+K:496:0x80:0xA4
+
+# adamantite
+K:497:0x80:0xA4
+
+# & Mighty Hammer~
+K:498:0x80:0xDC
+
+# & Massive Iron Crown~
+K:499:0x80:0xDD
+
+# & Phial~
+K:500:0x80:0xFE
+
+# & Star~
+K:501:0x80:0xFE
+
+# & Arkenstone~
+K:502:0x80:0xFE
+
+# & Amulet~
+K:503:0x80:0xA2
+
+# & Amulet~
+K:504:0x80:0xA2
+
+# & Necklace~
+K:505:0x80:0xA2
+
+# & Ring~
+K:506:0x80:0xBD
+
+# & Ring~
+K:507:0x80:0xBD
+
+# & Ring~
+K:508:0x80:0xBD
+
+# & Ring~
+K:509:0x80:0xBD
+
+# & Ring~
+K:510:0x80:0xBD
+
+# & Ring~
+K:511:0x80:0xBD
+
+# [Rites of Initiation]
+K:512:0x80:0xBF
+
+# [Ways of War]
+K:513:0x80:0xBF
+
+# [Divine Retribution]
+K:514:0x80:0xBF
+
+# [Essence of Fury]
+K:515:0x80:0xBF
+
+# [Novice Crafts]
+K:516:0x80:0xBF
+
+# [Arcane Channels]
+K:517:0x80:0xBF
+
+# [Sigils of Wizardry]
+K:518:0x80:0xBF
+
+# [Mana Focus]
+K:519:0x80:0xBF
+
+# Reflection
+K:520:0x80:0xA2
+
+# Anti-Magic
+K:521:0x80:0xA2
+
+# Anti-Teleportation
+K:522:0x80:0xA2
+
+# Resistance
+K:523:0x80:0xA2
+
+# & Zweihander~
+K:524:0x80:0xFC
+
+# & Tanto~
+K:525:0x80:0xFC
+
+# Splint Mail~
+K:526:0x80:0xDB
+
+# Do-maru~
+K:527:0x80:0xDB
+
+# & Trifurcate Spear~
+K:528:0x80:0xAF
+
+# & Three Piece Rod~
+K:529:0x80:0xDC
+
+# O-yoroi~
+K:530:0x80:0xDB
+
+# & Fur Cloak~
+K:531:0x80:0xA8
+
+# & Lajatang~
+K:532:0x80:0xAF
+
+# & Hatchet~
+K:533:0x80:0xAF
+
+# Rhino Hide Armour~
+K:535:0x80:0xA8
+
+# Leather Jacket~
+K:536:0x80:0xA8
+
+# & Sickle~
+K:537:0x80:0xAF
+
+# & Tetsubo~
+K:538:0x80:0xDC
+
+# & Nunchaku~
+K:539:0x80:0xDC
+
+# & Bo Staff~
+K:540:0x80:0xDC
+
+# & Jo Staff~
+K:541:0x80:0xDC
+
+# & Club~
+K:542:0x80:0xDC
+
+# & Broad Spear~
+K:543:0x80:0xAF
+
+# & Khopesh~
+K:544:0x80:0xFC
+
+# & Flamberge~
+K:545:0x80:0xFC
+
+# & Claymore~
+K:546:0x80:0xFC
+
+# & Espadon~
+K:547:0x80:0xFC
+
+# & Great Scimitar~
+K:548:0x80:0xFC
+
+# & Wakizashi~
+K:549:0x80:0xFC
+
+# & Naginata~
+K:550:0x80:0xAF
+
+# & Fauchard~
+K:551:0x80:0xAF
+
+# & Guisarme~
+K:552:0x80:0xAF
+
+# & Heavy Lance~
+K:553:0x80:0xAF
+
+# & Basillard~
+K:554:0x80:0xFC
+
+# & Ninjato~
+K:555:0x80:0xFC
+
+# Ring Mail~
+K:556:0x80:0xDB
+
+# Cord Armour~
+K:557:0x80:0xA8
+
+# Paper Armour~
+K:558:0x80:0xA8
+
+# Padded Armour~
+K:559:0x80:0xA8
+
+# & Kabuto~
+K:560:0x80:0xDD
+
+# Stone and Hide Armour~
+K:561:0x80:0xA8
+
+# & Jingasa~
+K:562:0x80:0xDD
+
+# Haramakido~
+K:563:0x80:0xDB
+
+# Nothing
+K:564:0x80:0xBF
+
+# Poison
+K:565:0x80:0xAA
+
+# Nothing
+K:566:0x80:0xAD
+
+# Nothing
+K:567:0x80:0xAD
+
+# Nothing
+K:568:0x80:0xAD
+
+# Nothing
+K:569:0x80:0xAD
+
+# Explosion
+K:570:0x80:0xAA
+
+# Teleport
+K:571:0x80:0xAA
+
+# Nothing
+K:572:0x80:0xAD
+
+# the Blood of Life
+K:573:0x80:0xA1
+
+# Cold
+K:574:0x80:0xAA
+
+# Fire
+K:575:0x80:0xAA
+
+# Acid
+K:576:0x80:0xAA
+
+# & Mage Staff~
+K:577:0x80:0xDC
+
+# Life
+K:579:0x80:0xAA
+
+# Confusion
+K:580:0x80:0xAA
+
+# Light
+K:581:0x80:0xAA
+
+# & Ring~
+K:582:0x80:0xBD
+
+# Invisibility
+K:583:0x80:0xA1
+
+# Chaos
+K:584:0x80:0xAA
+
+# Mutation
+K:585:0x80:0xA1
+
+# Invisibility
+K:586:0x80:0xBD
+
+# Time
+K:587:0x80:0xAA
+
+# Deep Thoughts
+K:588:0x80:0xBF
+
+# More Deep Thoughts
+K:589:0x80:0xBF
+
+# Compendium of Deep Thoughts
+K:590:0x80:0xBF
+
+# Artifact Lore Vol. I
+K:591:0x80:0xBF
+
+# Artifact Lore Vol. II
+K:592:0x80:0xBF
+
+# Artifact Lore Vol. III
+K:593:0x80:0xBF
+
+# Monstrous Compendium 1
+K:594:0x80:0xBF
+
+# Monstrous Compendium 2
+K:595:0x80:0xBF
+
+# Monstrous Compendium 3
+K:596:0x80:0xBF
+
+# Monstrous Compendium 4
+K:597:0x80:0xBF
+
+# Monstrous Compendium 5
+K:598:0x80:0xBF
+
+# Monstrous Compendium 6
+K:599:0x80:0xBF
+
+# Monstrous Compendium 7
+K:600:0x80:0xBF
+
+# Monstrous Compendium 8
+K:601:0x80:0xBF
+
+# Monstrous Compendium 9
+K:602:0x80:0xBF
+
+# Monstrous Compendium 10
+K:603:0x80:0xBF
+
+# Monstrous Compendium 11
+K:604:0x80:0xBF
+
+# Abomination
+K:605:0x80:0xA1
+
+# Shape of Wolf
+K:606:0x80:0xA1
+
+# Shape of Ape
+K:607:0x80:0xA1
+
+# Shape of Goat
+K:608:0x80:0xA1
+
+# Shape of Insect
+K:609:0x80:0xA1
+
+# Shape of Sparrow
+K:610:0x80:0xA1
+
+# Shape of Ent
+K:611:0x80:0xA1
+
+# Shape of Vampire
+K:612:0x80:0xA1
+
+# Shape of Spider
+K:613:0x80:0xA1
+
+# Shape of Mana ball
+K:614:0x80:0xA1
+
+# Shape of Fire cloud
+K:615:0x80:0xA1
+
+# Shape of Cold cloud
+K:616:0x80:0xA1
+
+# Shape of Chaos cloud
+K:617:0x80:0xA1
+
+# [Wolf]
+K:618:0x80:0xBF
+
+# [Ape]
+K:619:0x80:0xBF
+
+# [Goat]
+K:620:0x80:0xBF
+
+# [Insect]
+K:621:0x80:0xBF
+
+# [Sparrow]
+K:622:0x80:0xBF
+
+# [Ent]
+K:623:0x80:0xBF
+
+# [Vampire]
+K:624:0x80:0xBF
+
+# [Spider]
+K:625:0x80:0xBF
+
+# [Mana ball]
+K:626:0x80:0xBF
+
+# [Fire cloud]
+K:627:0x80:0xBF
+
+# [Cold cloud]
+K:628:0x80:0xBF
+
+# [Chaos Cloud]
+K:629:0x80:0xBF
+
+# [Ghost]
+K:630:0x80:0xBF
+
+# [Kobold]
+K:631:0x80:0xBF
+
+# [Dragon]
+K:632:0x80:0xBF
+
+# [Demon]
+K:633:0x80:0xBF
+
+# [Hound]
+K:634:0x80:0xBF
+
+# [Quylthulg]
+K:635:0x80:0xBF
+
+# [Maia]
+K:636:0x80:0xBF
+
+# [Serpent]
+K:637:0x80:0xBF
+
+# [Giant]
+K:638:0x80:0xBF
+
+# [Vala]
+K:639:0x80:0xBF
+
+# Magic
+K:640:0x80:0xAA
+
+# corpse
+K:641:0x80:0xFE
+
+# skeleton
+K:642:0x80:0xFE
+
+# head
+K:643:0x80:0xFE
+
+# skull
+K:644:0x80:0xFE
+
+# raw meat
+K:645:0x80:0xFE
+
+# & Dragonrider Coat~
+K:646:0x80:0xA8
+
+# & Stone~
+K:647:0x80:0xFE
+
+# & small wooden Boomerang~
+K:648:0x80:0xFB
+
+# & wooden Boomerang~
+K:649:0x80:0xFB
+
+# & small metal Boomerang~
+K:650:0x80:0xFB
+
+# & metal Boomerang~
+K:651:0x80:0xFB
+
+# & Anchor~
+K:652:0x80:0xFE
+
+# & ~
+K:653:0x80:0xFE
+
+# Summon never-moving pet
+K:654:0x80:0xBF
+
+# [Life in symbiosis]
+K:655:0x80:0xBF
+
+# [Perfect Symbiosis]
+K:656:0x80:0xBF
+
+# Cure Light Insanity
+K:657:0x80:0xA1
+
+# Cure Serious Insanity
+K:658:0x80:0xA1
+
+# Cure Critical Insanity
+K:659:0x80:0xA1
+
+# Cure Insanity
+K:660:0x80:0xA1
+
+# & Phial~
+K:661:0x80:0xFE
+
+# Random Artifact
+K:662:0x80:0xFE
+
+# Craftmanship
+K:663:0x80:0xBF
+
+# The One Ring
+K:664:0x80:0xBF
+
+# [Apprentice Handbook]
+K:665:0x80:0xBF
+
+# [Minstrel's Music]
+K:666:0x80:0xBF
+
+# [Harps of Rivendell]
+K:667:0x80:0xBF
+
+# [Lays of Beleriand]
+K:668:0x80:0xBF
+
+# & Flute~
+K:669:0x80:0xAF
+
+# & Drum~
+K:670:0x80:0xAF
+
+# & Harp~
+K:671:0x80:0xAF
+
+# & Banjo~
+K:672:0x80:0xAF
+
+# & Lute~
+K:673:0x80:0xAF
+
+# & Mandolin~
+K:674:0x80:0xAF
+
+# & Palantir~
+K:675:0x80:0xA1
+
+# Egg
+K:676:0x80:0xEF
+
+# Reset Recall
+K:677:0x80:0xBF
+
+# Divination
+K:678:0x80:0xBF
+
+# Self
+K:679:0x80:0xBF
+
+# Ray
+K:680:0x80:0xBF
+
+# Sphere
+K:681:0x80:0xBF
+
+# Knowledge
+K:682:0x80:0xBF
+
+# Life
+K:683:0x80:0xBF
+
+# Fire
+K:684:0x80:0xBF
+
+# Cold
+K:685:0x80:0xBF
+
+# Lightning
+K:686:0x80:0xBF
+
+# Acid
+K:687:0x80:0xBF
+
+# Element
+K:688:0x80:0xBF
+
+# Chaos
+K:689:0x80:0xBF
+
+# Mind
+K:690:0x80:0xBF
+
+# Holding
+K:691:0x80:0xBF
+
+# Arrow
+K:692:0x80:0xBF
+
+# Power Surge
+K:693:0x80:0xBF
+
+# Armageddon
+K:694:0x80:0xBF
+
+# Gravity
+K:695:0x80:0xBF
+
+# Extra Life
+K:696:0x80:0xAA
+
+# Anti-Death
+K:697:0x80:0xBF
+
+# Protection
+K:698:0x80:0xBF
+
+# & Horn~
+K:699:0x80:0xAF
+
+# Precognition
+K:700:0x80:0xBD
+
+# & Sprig~ of Athelas
+K:701:0x80:0xAC
+
+# [Magic for Beginners]
+K:702:0x80:0xBF
+
+# [Conjurings and Tricks]
+K:703:0x80:0xBF
+
+# [Incantations and Illusions]
+K:704:0x80:0xBF
+
+# [Sorcery and Evocations]
+K:705:0x80:0xBF
+
+# [Beginners Handbook]
+K:706:0x80:0xBF
+
+# [Words of Wisdom]
+K:707:0x80:0xBF
+
+# [Chants and Blessings]
+K:708:0x80:0xBF
+
+# [Exorcism and Dispelling]
+K:709:0x80:0xBF
+
+# [Resistance of Scarabtarices]
+K:710:0x80:0xBF
+
+# [Mordenkainen's Escapes]
+K:711:0x80:0xBF
+
+# [Kelek's Grimoire of Power]
+K:712:0x80:0xBF
+
+# [Tenser's Transformations]
+K:713:0x80:0xBF
+
+# [Raal's Tome of Destruction]
+K:714:0x80:0xBF
+
+# [Ethereal Openings]
+K:715:0x80:0xBF
+
+# [Godly Insights]
+K:716:0x80:0xBF
+
+# [Purifications and Healing]
+K:717:0x80:0xBF
+
+# [Holy Infusions]
+K:718:0x80:0xBF
+
+# [Wrath of God]
+K:719:0x80:0xBF
+
+# Deincarnation
+K:720:0x80:0xBF
+
+# Numenorean for beginners
+K:722:0x80:0xBF
+
+# Numenorean for beginners
+K:723:0x80:0xBF
+
+# Advanced lessons of Numenorean
+K:724:0x80:0xBF
+
+# Advanced lessons of Sindarin
+K:725:0x80:0xBF
+
+# & Shard~ of Pottery
+K:726:0x80:0xFE
+
+# & Broken Stick~
+K:727:0x80:0xFE
+
+# Wall Creation
+K:728:0x80:0xAD
+
+# [Illusions for Beginners]
+K:729:0x80:0xBF
+
+# [Tricks and Visions]
+K:730:0x80:0xBF
+
+# [Phantasms and Illusions]
+K:731:0x80:0xBF
+
+# [Shadows and Prisms]
+K:732:0x80:0xBF
+
+# [Serten's Immunities]
+K:733:0x80:0xBF
+
+# [Knowledge of Kenault]
+K:734:0x80:0xBF
+
+# [Otiluke's Spheres]
+K:735:0x80:0xBF
+
+# [Boccob's Book of Shadows]
+K:736:0x80:0xBF
+
+# [Bigby's Handbook]
+K:737:0x80:0xBF
+
+# [Hunt of Orome]
+K:738:0x80:0xBF
+
+# [Holy Sanctifications]
+K:739:0x80:0xBF
+
+# [Secrets of the Feanturi]
+K:740:0x80:0xBF
+
+# [War of Wrath]
+K:741:0x80:0xBF
+
+# [Gifts of Iluvatar]
+K:742:0x80:0xBF
+
+# Learning
+K:743:0x80:0xA1
+
+# [Eye of Sauron]
+K:744:0x80:0xBF
+
+# [Flame of Udun]
+K:745:0x80:0xBF
+
+# [Corruptions of Melkor]
+K:746:0x80:0xBF
+
+# [Crescent of Morgul]
+K:747:0x80:0xBF
+
+# [Morgoth's Ring]
+K:748:0x80:0xBF
+
+# Spell
+K:749:0x80:0xBF
+
+# Wishing
+K:750:0x80:0xDF
+
+# Khuzdul - The hidden tonge of the Dwarves
+K:751:0x80:0xBF
+
+# Nandorin for the dumbs
+K:752:0x80:0xBF
+
+# Advanced lessons of Orkish
+K:753:0x80:0xBF
+
+# Flying
+K:755:0x80:0xBD
+
+# [Powerful Sigils]
+K:756:0x80:0xBF
+
+# [Disruptive Forces]
+K:758:0x80:0xBF
+
+# [Forces of the Mind]
+K:759:0x80:0xBF
+
+# [Power of Ancient Sorcerors]
+K:760:0x80:0xBF
+
+# [Tricks of the Wild]
+K:761:0x80:0xBF
+
+# [Mastering the Rituals]
+K:762:0x80:0xBF
+
+# [Rites of Power]
+K:763:0x80:0xBF
+
+# [Tribal Power]
+K:764:0x80:0xBF
+
+# [Aiding Shades]
+K:765:0x80:0xBF
+
+# [Morgoth's Space-Time Warpings]
+K:766:0x80:0xBF
+
+# [Murazor Tome of Conjuring & Dispeling]
+K:767:0x80:0xBF
+
+# [Channeling the Void]
+K:768:0x80:0xBF
+
+# [Sauron's Forgotten Tome]
+K:769:0x80:0xBF
+
+# Wraith Form
+K:770:0x80:0xBD
+
+# [Earth]
+K:771:0x80:0xBF
+
+# [Fire]
+K:772:0x80:0xBF
+
+# [Air]
+K:773:0x80:0xBF
+
+# [Water]
+K:774:0x80:0xBF
+
+# [Mana]
+K:775:0x80:0xBF
+
+# Home Summoning
+K:776:0x80:0xAD
+
+# & Shadow Blade~
+K:777:0x80:0xFC
+
+# & Bluesteel Blade~
+K:778:0x80:0xFC
+
+# the Serpents
+K:779:0x80:0xA2
+
+# Darkness
+K:780:0x80:0xAA
+
+# Knowledge
+K:781:0x80:0xAA
+
+# Force
+K:782:0x80:0xAA
+
+# Lightning
+K:783:0x80:0xAA
+
+# Mana
+K:784:0x80:0xAA
+
+# Power
+K:785:0x80:0xBD
+
+# Climbing Set
+K:786:0x80:0xE0
+
+# Adventurer's Guide to Middle-earth
+K:787:0x80:0xBF
+
+# [Dark Incantations]
+K:788:0x80:0xBF
+
+# [Immortal Rituals]
+K:789:0x80:0xBF
+
+# [Minions of Azathoth]
+K:790:0x80:0xBF
+
+# [Demonthoughts]
+K:791:0x80:0xBF
+
+# [Hellfire Tome]
+K:792:0x80:0xBF
+
+# & Wooden Rod~ of#
+K:793:0x80:0xAD
+
+# & Copper Rod~ of#
+K:794:0x80:0xAD
+
+# & Iron Rod~ of#
+K:795:0x80:0xAD
+
+# & Aluminium Rod~ of#
+K:796:0x80:0xAD
+
+# & Silver Rod~ of#
+K:797:0x80:0xAD
+
+# & Golden Rod~ of#
+K:798:0x80:0xAD
+
+# & Mithril Rod~ of#
+K:799:0x80:0xAD
+
+# & Adamantite Rod~ of#
+K:800:0x80:0xAD
+
+
+
+
+
+
+
+# Monster attr/char definitions
+
+# Player
+R:0:0x80:0xC0
+
+# Filthy street urchin
+R:1:0x80:0xF4
+
+# Scrawny cat
+R:2:0x80:0xE6
+
+# Sparrow
+R:3:0x80:0xC2
+
+# Chaffinch
+R:4:0x80:0xC2
+
+# Wild rabbit
+R:5:0x80:0xF2
+
+# Woodsman
+R:6:0x80:0xF0
+
+# Scruffy little dog
+R:7:0x80:0xC3
+
+# Farmer Maggot
+R:8:0x81:0xBB
+
+# Blubbering idiot
+R:9:0x80:0xF4
+
+# Boil-covered wretch
+R:10:0x80:0xF4
+
+# Village idiot
+R:11:0x80:0xF4
+
+# Pitiful looking beggar
+R:12:0x80:0xF4
+
+# Mangy looking leper
+R:13:0x80:0xF4
+
+# Agent of black market
+R:14:0x81:0xB8
+
+# Singing, happy drunk
+R:15:0x81:0xB9
+
+# Aimless looking merchant
+R:16:0x81:0xBA
+
+# Mean looking mercenary
+R:17:0x80:0xF4
+
+# Battle scarred veteran
+R:18:0x81:0xC3
+
+# Martti Ihrasaari
+R:19:0x80:0xD0
+
+# Grey mold
+R:20:0x81:0x32
+
+# Large white snake
+R:21:0x81:0xA0
+
+# Grey mushroom patch
+R:22:0x80:0xAC
+
+# Newt
+R:23:0x80:0xD2
+
+# Giant white centipede
+R:24:0x80:0xE3
+
+# White icky thing
+R:25:0x80:0xE9
+
+# Clear icky thing
+R:26:0x80:0xE9
+
+# Giant white mouse
+R:27:0x80:0xF2
+
+# Large brown snake
+R:28:0x81:0xA1
+
+# Small kobold
+R:29:0x80:0xEB
+
+# Kobold
+R:30:0x80:0xEB
+
+# White worm mass
+R:31:0x80:0xF7
+
+# Floating eye
+R:32:0x80:0xE5
+
+# Rock lizard
+R:33:0x80:0xD2
+
+# Grid bug
+R:34:0x81:0xA9
+
+# Jackal
+R:35:0x81:0xB1
+
+# Soldier ant
+R:36:0x81:0xAA
+
+# Fruit bat
+R:37:0x80:0xE2
+
+# Insect swarm
+R:38:0x81:0xA8
+
+# Greater hell-beast
+R:39:0x80:0xD5
+
+# Shrieker mushroom patch
+R:40:0x80:0xAC
+
+# Blubbering icky thing
+R:41:0x80:0xE9
+
+# Metallic green centipede
+R:42:0x80:0xE3
+
+# Novice warrior
+R:43:0x81:0xC2
+
+# Novice rogue
+R:44:0x80:0xF0
+
+# Novice priest
+R:45:0x80:0xF0
+
+# Novice mage
+R:46:0x80:0xF0
+
+# Yellow mushroom patch
+R:47:0x80:0xAC
+
+# White jelly
+R:48:0x80:0xEA
+
+# Giant black ant
+R:49:0x80:0xE1
+
+# Salamander
+R:50:0x80:0xD2
+
+# White harpy
+R:51:0x80:0xC8
+
+# Blue yeek
+R:52:0x80:0xF9
+
+# Grip, Farmer Maggot's dog
+R:53:0x80:0xC3
+
+# Wolf, Farmer Maggot's dog
+R:54:0x80:0xC3
+
+# Fang, Farmer Maggot's dog
+R:55:0x80:0xC3
+
+# Giant green frog
+R:56:0x80:0xD2
+
+# Freesia
+R:57:0x80:0xE6
+
+# Green worm mass
+R:58:0x80:0xF7
+
+# Large yellow snake
+R:59:0x80:0xCA
+
+# Cave spider
+R:60:0x80:0xD3
+
+# Crow
+R:61:0x80:0xC2
+
+# Wild cat
+R:62:0x80:0xE6
+
+# Smeagol
+R:63:0x80:0xE8
+
+# Green ooze
+R:64:0x80:0xEA
+
+# Poltergeist
+R:65:0x80:0xC7
+
+# Yellow jelly
+R:66:0x80:0xEA
+
+# Metallic blue centipede
+R:67:0x80:0xE3
+
+# Raven
+R:68:0x80:0xC2
+
+# Giant white louse
+R:69:0x80:0xEC
+
+# Piranha
+R:70:0x80:0xFE
+
+# Black naga
+R:71:0x80:0xEE
+
+# Spotted mushroom patch
+R:72:0x80:0xAC
+
+# Silver jelly
+R:73:0x80:0xEA
+
+# Scruffy looking hobbit
+R:74:0x80:0xE8
+
+# Giant white ant
+R:75:0x80:0xE1
+
+# Yellow mold
+R:76:0x80:0xED
+
+# Metallic red centipede
+R:77:0x80:0xE3
+
+# Yellow worm mass
+R:78:0x80:0xF7
+
+# Clear worm mass
+R:79:0x80:0xF7
+
+# Radiation eye
+R:80:0x80:0xE5
+
+# Yellow light
+R:81:0x80:0xAA
+
+# Cave lizard
+R:82:0x80:0xD2
+
+# Novice ranger
+R:83:0x80:0xF0
+
+# Blue jelly
+R:84:0x80:0xEA
+
+# Creeping copper coins
+R:85:0x80:0xA4
+
+# Giant white rat
+R:86:0x80:0xF2
+
+# Snotling
+R:87:0x80:0xEF
+
+# Swordfish
+R:88:0x80:0xFE
+
+# Blue worm mass
+R:89:0x80:0xF7
+
+# Large grey snake
+R:90:0x80:0xCA
+
+# Skeleton kobold
+R:91:0x80:0xF3
+
+# Ewok
+R:92:0x80:0xE8
+
+# Novice mage
+R:93:0x80:0xF0
+
+# Green naga
+R:94:0x80:0xEE
+
+# Giant leech
+R:95:0x80:0xF7
+
+# Barracuda
+R:96:0x80:0xFE
+
+# Novice paladin
+R:97:0x80:0xF0
+
+# Zog
+R:98:0x80:0xE8
+
+# Blue ooze
+R:99:0x80:0xEA
+
+# Green glutton ghost
+R:100:0x80:0xC7
+
+# Green jelly
+R:101:0x80:0xEA
+
+# Large kobold
+R:102:0x80:0xEB
+
+# Grey icky thing
+R:103:0x80:0xE9
+
+# Disenchanter eye
+R:104:0x80:0xE5
+
+# Red worm mass
+R:105:0x80:0xF7
+
+# Copperhead snake
+R:106:0x80:0xCA
+
+# Death sword
+R:107:0x80:0xFC
+
+# Purple mushroom patch
+R:108:0x80:0xAC
+
+# Novice priest
+R:109:0x80:0xF0
+
+# Novice warrior
+R:110:0x80:0xF0
+
+# Nibelung
+R:111:0x80:0xE8
+
+# Disembodied hand that strangled people
+R:112:0x80:0xFA
+
+# Brown mold
+R:113:0x80:0xED
+
+# Giant brown bat
+R:114:0x80:0xE2
+
+# Rat-thing
+R:115:0x80:0xF2
+
+# Novice archer
+R:116:0x81:0xC1
+
+# Creeping silver coins
+R:117:0x80:0xA4
+
+# Snaga
+R:118:0x80:0xEF
+
+# Rattlesnake
+R:119:0x80:0xCA
+
+# Giant slug
+R:120:0x80:0xF7
+
+# Giant pink frog
+R:121:0x80:0xD2
+
+# Dark elf
+R:122:0x80:0xE8
+
+# Zombified kobold
+R:123:0x80:0xFA
+
+# Crypt Creep
+R:124:0x80:0xF3
+
+# Rotting corpse
+R:125:0x80:0xFA
+
+# Cave orc
+R:126:0x81:0xBC
+
+# Wood spider
+R:127:0x80:0xD3
+
+# Manes
+R:128:0x80:0xF5
+
+# Bloodshot eye
+R:129:0x80:0xE5
+
+# Red naga
+R:130:0x80:0xEE
+
+# Red jelly
+R:131:0x80:0xEA
+
+# Green icky thing
+R:132:0x80:0xE9
+
+# Lost soul
+R:133:0x80:0xC7
+
+# Night lizard
+R:134:0x80:0xD2
+
+# Mughash the Kobold Lord
+R:135:0x80:0xEB
+
+# Skeleton orc
+R:136:0x80:0xF3
+
+# Wormtongue, Agent of Saruman
+R:137:0x80:0xF0
+
+# Robin Hood, the Outlaw
+R:138:0x80:0xF0
+
+# Nurgling
+R:139:0x80:0xF5
+
+# Lagduf, the Snaga
+R:140:0x80:0xEF
+
+# Brown yeek
+R:141:0x80:0xF9
+
+# Novice ranger
+R:142:0x80:0xF0
+
+# Giant salamander
+R:143:0x80:0xD2
+
+# Space monster
+R:144:0x80:0xAE
+
+# Carnivorous flying monkey
+R:145:0x80:0xC8
+
+# Green mold
+R:146:0x80:0xED
+
+# Novice paladin
+R:147:0x80:0xF0
+
+# Lemure
+R:148:0x80:0xF5
+
+# Hill orc
+R:149:0x80:0xEF
+
+# Bandit
+R:150:0x80:0xF0
+
+# Hunting hawk
+R:151:0x80:0xC2
+
+# Phantom warrior
+R:152:0x80:0xC7
+
+# Gremlin
+R:153:0x80:0xF5
+
+# Yeti
+R:154:0x80:0xD9
+
+# Bloodshot icky thing
+R:155:0x80:0xE9
+
+# Giant grey rat
+R:156:0x80:0xF2
+
+# Black harpy
+R:157:0x80:0xC8
+
+# Skaven
+R:158:0x80:0xF2
+
+# The wounded bear
+R:159:0x80:0xF1
+
+# Portuguese man-o-war
+R:160:0x80:0xEA
+
+# Rock mole
+R:161:0x80:0xF2
+
+# Orc shaman
+R:162:0x80:0xEF
+
+# Baby blue dragon
+R:163:0x80:0xE4
+
+# Baby white dragon
+R:164:0x80:0xE4
+
+# Baby green dragon
+R:165:0x80:0xE4
+
+# Baby black dragon
+R:166:0x80:0xE4
+
+# Baby red dragon
+R:167:0x80:0xE4
+
+# Giant red ant
+R:168:0x80:0xE1
+
+# Brodda, the Easterling
+R:169:0x80:0xF0
+
+# Bloodfang the Wolf
+R:170:0x80:0xC3
+
+# King cobra
+R:171:0x80:0xCA
+
+# Eagle
+R:172:0x80:0xC2
+
+# War bear
+R:173:0x80:0xF1
+
+# Killer bee
+R:174:0x80:0xC9
+
+# Giant spider
+R:175:0x80:0xD3
+
+# Giant white tick
+R:176:0x80:0xD3
+
+# The Borshin
+R:177:0x80:0xE7
+
+# Dark elven mage
+R:178:0x80:0xE8
+
+# Kamikaze yeek
+R:179:0x80:0xF9
+
+# Orfax, Son of Boldor
+R:180:0x80:0xF9
+
+# Servant of Glaaki
+R:181:0x80:0xFA
+
+# Dark elven warrior
+R:182:0x81:0xBF
+
+# Sand-dweller
+R:183:0x80:0xF5
+
+# Clear mushroom patch
+R:184:0x80:0xAC
+
+# Quiver slot
+R:185:0x80:0xAC
+
+# Grishnakh, the Hill Orc
+R:186:0x80:0xEF
+
+# Giant piranha
+R:187:0x80:0xFE
+
+# Owlbear
+R:188:0x80:0xC8
+
+# Blue horror
+R:189:0x80:0xF5
+
+# Hairy mold
+R:190:0x80:0xED
+
+# Grizzly bear
+R:191:0x80:0xF1
+
+# Disenchanter mold
+R:192:0x80:0xED
+
+# Pseudo dragon
+R:193:0x80:0xE4
+
+# Tengu
+R:194:0x80:0xF5
+
+# Creeping gold coins
+R:195:0x80:0xA4
+
+# Wolf
+R:196:0x80:0xC3
+
+# Giant fruit fly
+R:197:0x80:0xC9
+
+# Panther
+R:198:0x80:0xE6
+
+# Brigand
+R:199:0x80:0xF0
+
+# Hobbes the Tiger
+R:200:0x80:0xE6
+
+# Shadow Creature of Fiona
+R:201:0x80:0xE8
+
+# Undead mass
+R:202:0x80:0xEA
+
+# Chaos shapechanger
+R:203:0x80:0xC8
+
+# Baby multi-hued dragon
+R:204:0x80:0xE4
+
+# Vorpal bunny
+R:205:0x80:0xF2
+
+# Old Man Willow
+R:206:0x80:0xA3
+
+# Hippocampus
+R:207:0x80:0xC8
+
+# Zombified orc
+R:208:0x80:0xFA
+
+# Hippogriff
+R:209:0x80:0xC8
+
+# Black mamba
+R:210:0x80:0xCA
+
+# White wolf
+R:211:0x80:0xC3
+
+# Grape jelly
+R:212:0x80:0xEA
+
+# Nether worm mass
+R:213:0x80:0xF7
+
+# Abyss worm mass
+R:214:0x80:0xF7
+
+# Golfimbul, the Hill Orc Chief
+R:215:0x80:0xEF
+
+# Swordsman
+R:216:0x80:0xF0
+
+# Skaven shaman
+R:217:0x80:0xF2
+
+# Gazer
+R:218:0x80:0xE5
+
+# Knight archer
+R:219:0x80:0xF0
+
+# Ixitxachitl
+R:220:0x80:0xFE
+
+# Mine-dog
+R:221:0x80:0xC3
+
+# Hellcat
+R:222:0x80:0xE6
+
+# Moon beast
+R:223:0x80:0xF1
+
+# Master yeek
+R:224:0x80:0xF9
+
+# Priest
+R:225:0x80:0xF0
+
+# Dark elven priest
+R:226:0x80:0xE8
+
+# Air spirit
+R:227:0x80:0xC5
+
+# Skeleton human
+R:228:0x80:0xF3
+
+# Zombified human
+R:229:0x80:0xFA
+
+# Tiger
+R:230:0x80:0xE6
+
+# Moaning spirit
+R:231:0x80:0xC7
+
+# Stegocentipede
+R:232:0x80:0xE3
+
+# Spotted jelly
+R:233:0x80:0xEA
+
+# Drider
+R:234:0x80:0xD3
+
+# Mongbat
+R:235:0x80:0xE2
+
+# Killer brown beetle
+R:236:0x80:0xCB
+
+# Boldor, King of the Yeeks
+R:237:0x80:0xF9
+
+# Ogre
+R:238:0x81:0xBD
+
+# Creeping mithril coins
+R:239:0x80:0xA4
+
+# Illusionist
+R:240:0x80:0xF0
+
+# Druid
+R:241:0x80:0xF0
+
+# Pink horror
+R:242:0x80:0xF5
+
+# Cloaker
+R:243:0x80:0xA8
+
+# Black orc
+R:244:0x80:0xEF
+
+# Ochre jelly
+R:245:0x80:0xEA
+
+# Software bug
+R:246:0x80:0xC9
+
+# Lurker
+R:247:0x80:0xAE
+
+# Nixie
+R:248:0x80:0xE8
+
+# Vlasta
+R:249:0x80:0xD2
+
+# Giant white dragon fly
+R:250:0x80:0xC6
+
+# Snaga sapper
+R:251:0x80:0xEF
+
+# Blue icky thing
+R:252:0x80:0xE9
+
+# Gibbering mouther
+R:253:0x80:0xEA
+
+# Irish wolfhound of Flora
+R:254:0x80:0xC3
+
+# Hill giant
+R:255:0x80:0xD0
+
+# Flesh golem
+R:256:0x80:0xE7
+
+# Warg
+R:257:0x80:0xC3
+
+# Cheerful leprechaun
+R:258:0x80:0xE8
+
+# Giant black flea
+R:259:0x80:0xC9
+
+# Ufthak of Cirith Ungol
+R:260:0x80:0xEF
+
+# Clay golem
+R:261:0x80:0xE7
+
+# Black ogre
+R:262:0x80:0xCF
+
+# Dweller on the threshold
+R:263:0x80:0xD9
+
+# Half-orc
+R:264:0x80:0xEF
+
+# Dark naga
+R:265:0x80:0xEE
+
+# Giant octopus
+R:266:0x80:0xFE
+
+# Magic mushroom patch
+R:267:0x80:0xAC
+
+# Plaguebearer of Nurgle
+R:268:0x80:0xFA
+
+# Guardian naga
+R:269:0x80:0xEE
+
+# Wererat
+R:270:0x80:0xF2
+
+# Light hound
+R:271:0x80:0xDA
+
+# Shadow hound
+R:272:0x80:0xDA
+
+# Flying skull
+R:273:0x80:0xF3
+
+# Mi-Go
+R:274:0x80:0xC9
+
+# Giant tarantula
+R:275:0x80:0xD3
+
+# Giant clear centipede
+R:276:0x80:0xE3
+
+# Mirkwood spider
+R:277:0x80:0xD3
+
+# Frost giant
+R:278:0x80:0xD0
+
+# Griffon
+R:279:0x80:0xC8
+
+# Homonculous
+R:280:0x80:0xF5
+
+# Gnome mage
+R:281:0x80:0xE8
+
+# Clear hound
+R:282:0x80:0xDA
+
+# Umber hulk
+R:283:0x80:0xD8
+
+# Rust monster
+R:284:0x80:0xF1
+
+# Orc captain
+R:285:0x80:0xEF
+
+# Gelatinous cube
+R:286:0x80:0xEA
+
+# Giant green dragon fly
+R:287:0x80:0xC6
+
+# Fire giant
+R:288:0x80:0xD0
+
+# Hummerhorn
+R:289:0x80:0xC9
+
+# Lizardman
+R:290:0x80:0xE8
+
+# Ulfast, Son of Ulfang
+R:291:0x80:0xF0
+
+# Hammerhead
+R:292:0x80:0xFE
+
+# Berserker
+R:293:0x80:0xF0
+
+# Quasit
+R:294:0x80:0xF5
+
+# Sphinx
+R:295:0x80:0xC8
+
+# Imp
+R:296:0x80:0xF5
+
+# Forest troll
+R:297:0x80:0xD4
+
+# Freezing sphere
+R:298:0x80:0xAA
+
+# Jumping fireball
+R:299:0x80:0xAA
+
+# Ball lightning
+R:300:0x80:0xAA
+
+# 2-headed hydra
+R:301:0x80:0xCD
+
+# Swamp thing
+R:302:0x80:0xC8
+
+# Water spirit
+R:303:0x80:0xC5
+
+# Giant red scorpion
+R:304:0x80:0xD3
+
+# Earth spirit
+R:305:0x80:0xC5
+
+# Fire spirit
+R:306:0x80:0xC5
+
+# Fire hound
+R:307:0x80:0xDA
+
+# Cold hound
+R:308:0x80:0xDA
+
+# Energy hound
+R:309:0x80:0xDA
+
+# Potion mimic
+R:310:0x80:0xA1
+
+# Door mimic
+R:311:0x80:0xAB
+
+# Blink dog
+R:312:0x80:0xC3
+
+# Uruk
+R:313:0x80:0xEF
+
+# Shagrat, the Orc Captain
+R:314:0x80:0xEF
+
+# Gorbag, the Orc Captain
+R:315:0x80:0xEF
+
+# Shambling mound
+R:316:0x80:0xAC
+
+# White shark
+R:317:0x80:0xFE
+
+# Chaos beastman
+R:318:0x80:0xC8
+
+# Daemonette of Slaanesh
+R:319:0x80:0xF5
+
+# Giant bronze dragon fly
+R:320:0x80:0xC6
+
+# Stone giant
+R:321:0x80:0xD0
+
+# Giant black dragon fly
+R:322:0x80:0xC6
+
+# Stone golem
+R:323:0x80:0xE7
+
+# Red mold
+R:324:0x80:0xED
+
+# Giant gold dragon fly
+R:325:0x80:0xC6
+
+# Stunwall
+R:326:0x80:0xA3
+
+# Ghast
+R:327:0x80:0xFA
+
+# Ixitxachitl priest
+R:328:0x80:0xFE
+
+# Huorn
+R:329:0x80:0xA3
+
+# Bolg, Son of Azog
+R:330:0x80:0xEF
+
+# Phase spider
+R:331:0x80:0xD3
+
+# Lizard king
+R:332:0x80:0xE8
+
+# Landmine
+R:333:0x80:0xAE
+
+# Wyvern
+R:334:0x80:0xE4
+
+# Great eagle
+R:335:0x80:0xC2
+
+# Livingstone
+R:336:0x80:0xA3
+
+# Earth hound
+R:337:0x80:0xDA
+
+# Air hound
+R:338:0x80:0xDA
+
+# Sabre-tooth tiger
+R:339:0x80:0xE6
+
+# Water hound
+R:340:0x80:0xDA
+
+# Chimera
+R:341:0x80:0xC8
+
+# Quylthulg
+R:342:0x80:0xD1
+
+# Sasquatch
+R:343:0x80:0xD9
+
+# Weir
+R:344:0x80:0xC3
+
+# Whale
+R:345:0x80:0xFE
+
+# Electric eel
+R:346:0x80:0xCA
+
+# Werewolf
+R:347:0x80:0xC3
+
+# Dark elven lord
+R:348:0x80:0xE8
+
+# Cloud giant
+R:349:0x80:0xD0
+
+# Ugluk, the Uruk
+R:350:0x80:0xEF
+
+# Blue dragon bat
+R:351:0x80:0xE2
+
+# Scroll mimic
+R:352:0x80:0xBF
+
+# Chest mimic
+R:353:0x80:0xFE
+
+# Fire vortex
+R:354:0x80:0xF6
+
+# Water vortex
+R:355:0x80:0xF6
+
+# Lugdush, the Uruk
+R:356:0x80:0xEF
+
+# Arch-vile
+R:357:0x80:0xF5
+
+# Cold vortex
+R:358:0x80:0xF6
+
+# Energy vortex
+R:359:0x80:0xF6
+
+# Globefish
+R:360:0x80:0xFE
+
+# Carrion
+R:361:0x80:0xC2
+
+# Mummified orc
+R:362:0x80:0xFA
+
+# Killer whale
+R:363:0x80:0xFE
+
+# Serpent man
+R:364:0x80:0xCA
+
+# Vampiric mist
+R:365:0x80:0xA3
+
+# Killer stag beetle
+R:366:0x80:0xCB
+
+# Iron golem
+R:367:0x80:0xE7
+
+# Auto-roller
+R:368:0x80:0xE7
+
+# Giant yellow scorpion
+R:369:0x80:0xD3
+
+# Jade monk
+R:370:0x80:0xF0
+
+# Black ooze
+R:371:0x80:0xEA
+
+# Hardened warrior
+R:372:0x80:0xF0
+
+# Azog, King of the Uruk-Hai
+R:373:0x80:0xEF
+
+# Fleshhound of Khorne
+R:374:0x80:0xC3
+
+# Dark elven warlock
+R:375:0x80:0xE8
+
+# Master rogue
+R:376:0x80:0xF0
+
+# Red dragon bat
+R:377:0x80:0xE2
+
+# Killer white beetle
+R:378:0x80:0xCB
+
+# Ice skeleton
+R:379:0x80:0xF3
+
+# Angamaite of Umbar
+R:380:0x80:0xF0
+
+# Forest wight
+R:381:0x80:0xD7
+
+# Mime, the Nibelung
+R:382:0x80:0xE8
+
+# Ibun, Son of Mim
+R:383:0x80:0xE8
+
+# Meneldor the Swift
+R:384:0x80:0xC2
+
+# Phantom beast
+R:385:0x80:0xC7
+
+# Great white shark
+R:386:0x80:0xFE
+
+# 4-headed hydra
+R:387:0x80:0xCD
+
+# Lesser hell-beast
+R:388:0x80:0xD5
+
+# Tyrannosaur
+R:389:0x80:0xD2
+
+# Mummified human
+R:390:0x80:0xFA
+
+# Vampire bat
+R:391:0x80:0xE2
+
+# Sangahyando of Umbar
+R:392:0x80:0xF0
+
+# It
+R:393:0x80:0xAE
+
+# Banshee
+R:394:0x80:0xC7
+
+# Carrion crawler
+R:395:0x80:0xE3
+
+# Xiclotlan
+R:396:0x80:0xA3
+
+# Silent watcher
+R:397:0x80:0xE7
+
+# Pukelman
+R:398:0x80:0xE7
+
+# Disenchanter beast
+R:399:0x80:0xF1
+
+# Dark elven druid
+R:400:0x80:0xE8
+
+# Stone troll
+R:401:0x80:0xD4
+
+# Black
+R:402:0x80:0xEA
+
+# Troll priest
+R:403:0x80:0xD4
+
+# Wereworm
+R:404:0x80:0xF7
+
+# Killer crimson beetle
+R:405:0x80:0xCB
+
+# Vampiric ixitxachitl
+R:406:0x80:0xFE
+
+# Gnoph-Keh
+R:407:0x80:0xF1
+
+# Giant grey ant
+R:408:0x80:0xE1
+
+# Khufu the Mummified King
+R:409:0x80:0xFA
+
+# Gwaihir the Windlord
+R:410:0x80:0xC2
+
+# Giant red tick
+R:411:0x80:0xD3
+
+# Displacer beast
+R:412:0x80:0xE6
+
+# Ulwarth, Son of Ulfang
+R:413:0x80:0xF0
+
+# Agent of Saruman
+R:414:0x80:0xF0
+
+# Cave ogre
+R:415:0x80:0xCF
+
+# White wraith
+R:416:0x80:0xD7
+
+# Monadic Deva
+R:417:0x80:0xC1
+
+# Ghoul
+R:418:0x80:0xFA
+
+# Mim, Betrayer of Turin
+R:419:0x80:0xE8
+
+# Hellblade
+R:420:0x80:0xFC
+
+# Killer red beetle
+R:421:0x80:0xCB
+
+# Beast of Nurgle
+R:422:0x80:0xF1
+
+# Creeping adamantite coins
+R:423:0x80:0xA4
+
+# Algroth
+R:424:0x80:0xD4
+
+# Flamer of Tzeentch
+R:425:0x80:0xAC
+
+# Roper
+R:426:0x80:0xA3
+
+# Headless
+R:427:0x80:0xC8
+
+# Vibration hound
+R:428:0x80:0xDA
+
+# Nexus hound
+R:429:0x80:0xDA
+
+# Ogre mage
+R:430:0x80:0xCF
+
+# Lokkak, the Ogre Chieftain
+R:431:0x80:0xCF
+
+# Vampire
+R:432:0x80:0xD6
+
+# Gorgimera
+R:433:0x80:0xC8
+
+# Shantak
+R:434:0x80:0xC2
+
+# Colbran
+R:435:0x80:0xE7
+
+# Spirit naga
+R:436:0x80:0xEE
+
+# Corpser
+R:437:0x80:0xAC
+
+# Fiend of Slaanesh
+R:438:0x80:0xD3
+
+# Stairway to hell
+R:439:0x80:0xBE
+
+# 5-headed hydra
+R:440:0x80:0xCD
+
+# Barney the Dinosaur
+R:441:0x80:0xD2
+
+# Black knight
+R:442:0x80:0xF0
+
+# Seahorse
+R:443:0x80:0xFE
+
+# Cyclops
+R:444:0x80:0xD0
+
+# Clairvoyant
+R:445:0x80:0xF0
+
+# Giant purple worm
+R:446:0x80:0xF7
+
+# Catoblepas
+R:447:0x80:0xF1
+
+# Lesser wall monster
+R:448:0x80:0xA3
+
+# Mage
+R:449:0x80:0xF0
+
+# Mind flayer
+R:450:0x80:0xE8
+
+# The Ultimate Dungeon Cleaner
+R:451:0x80:0xE7
+
+# Deep one
+R:452:0x80:0xF5
+
+# Basilisk
+R:453:0x80:0xD2
+
+# Ice troll
+R:454:0x80:0xD4
+
+# Dhole
+R:455:0x80:0xF7
+
+# Movanic Deva
+R:456:0x80:0xC1
+
+# Ring mimic
+R:457:0x80:0xBD
+
+# Chaos tile
+R:458:0x80:0xAE
+
+# Young blue dragon
+R:459:0x80:0xE4
+
+# Young white dragon
+R:460:0x80:0xE4
+
+# Young green dragon
+R:461:0x80:0xE4
+
+# Young bronze dragon
+R:462:0x80:0xE4
+
+# Aklash
+R:463:0x80:0xD4
+
+# Mithril golem
+R:464:0x80:0xE7
+
+# Skeleton troll
+R:465:0x80:0xF3
+
+# Skeletal tyrannosaur
+R:466:0x80:0xD2
+
+# Jaws
+R:467:0x80:0xFE
+
+# Thorondor
+R:468:0x80:0xC2
+
+# Giant blue ant
+R:469:0x80:0xE1
+
+# Grave wight
+R:470:0x80:0xD7
+
+# Shadow drake
+R:471:0x80:0xE4
+
+# Manticore
+R:472:0x80:0xC8
+
+# Giant army ant
+R:473:0x80:0xE1
+
+# Killer slicer beetle
+R:474:0x80:0xCB
+
+# Gorgon
+R:475:0x80:0xC8
+
+# Gug
+R:476:0x80:0xC7
+
+# Ghost
+R:477:0x80:0xC7
+
+# Death watch beetle
+R:478:0x80:0xCB
+
+# Ogre shaman
+R:479:0x80:0xCF
+
+# Nexus quylthulg
+R:480:0x80:0xD1
+
+# Shelob, Spider of Darkness
+R:481:0x80:0xD3
+
+# Giant squid
+R:482:0x80:0xFE
+
+# Ghoulking
+R:483:0x80:0xFA
+
+# Doombat
+R:484:0x80:0xE2
+
+# Ninja
+R:485:0x80:0xF0
+
+# Memory moss
+R:486:0x80:0xAC
+
+# Storm giant
+R:487:0x80:0xD0
+
+# Spectator
+R:488:0x80:0xE5
+
+# Bokrug
+R:489:0x80:0xD2
+
+# Biclops
+R:490:0x80:0xD0
+
+# Half-troll
+R:491:0x80:0xD4
+
+# Ivory monk
+R:492:0x80:0xF0
+
+# Bert the Stone Troll
+R:493:0x80:0xD4
+
+# Bill the Stone Troll
+R:494:0x80:0xD4
+
+# Tom the Stone Troll
+R:495:0x80:0xD4
+
+# Cave troll
+R:496:0x80:0xD4
+
+# Anti-paladin
+R:497:0x80:0xF0
+
+# Chaos master
+R:498:0x80:0xF0
+
+# Barrow wight
+R:499:0x80:0xD7
+
+# Giant skeleton troll
+R:500:0x80:0xF3
+
+# Chaos drake
+R:501:0x80:0xE4
+
+# Law drake
+R:502:0x80:0xE4
+
+# Balance drake
+R:503:0x80:0xE4
+
+# Ethereal drake
+R:504:0x80:0xE4
+
+# Groo the Wanderer
+R:505:0x80:0xD4
+
+# Fasolt the Giant
+R:506:0x80:0xD0
+
+# Shade
+R:507:0x80:0xC7
+
+# Spectre
+R:508:0x80:0xC7
+
+# Water troll
+R:509:0x80:0xD4
+
+# Fire elemental
+R:510:0x80:0xC5
+
+# Cherub
+R:511:0x80:0xC1
+
+# Water elemental
+R:512:0x80:0xC5
+
+# Multi-hued hound
+R:513:0x80:0xDA
+
+# Night stalker
+R:514:0x80:0xC5
+
+# Carrion crawler
+R:515:0x80:0xE3
+
+# Master thief
+R:516:0x80:0xF0
+
+# Waldern, King of Water
+R:517:0x80:0xC5
+
+# Lich
+R:518:0x80:0xCC
+
+# Gas spore
+R:519:0x80:0xE5
+
+# Master vampire
+R:520:0x80:0xD6
+
+# Oriental vampire
+R:521:0x80:0xD6
+
+# Greater mummy
+R:522:0x80:0xFA
+
+# Bloodletter of Khorne
+R:523:0x80:0xD5
+
+# Giant grey scorpion
+R:524:0x80:0xD3
+
+# Earth elemental
+R:525:0x80:0xC5
+
+# Air elemental
+R:526:0x80:0xC5
+
+# Doom drake
+R:527:0x80:0xE4
+
+# Gargoyle
+R:528:0x80:0xF5
+
+# Malicious leprechaun
+R:529:0x80:0xE8
+
+# Eog golem
+R:530:0x80:0xE7
+
+# Little Boy
+R:531:0x80:0xFB
+
+# Dagashi
+R:532:0x80:0xF0
+
+# Headless ghost
+R:533:0x80:0xC7
+
+# Dread
+R:534:0x80:0xC7
+
+# Leng spider
+R:535:0x80:0xD3
+
+# Star vampire
+R:536:0x80:0xD6
+
+# Smoke elemental
+R:537:0x80:0xC5
+
+# Olog
+R:538:0x80:0xD4
+
+# Halfling slinger
+R:539:0x80:0xE8
+
+# Gravity hound
+R:540:0x80:0xDA
+
+# Acidic cytoplasm
+R:541:0x80:0xEA
+
+# Inertia hound
+R:542:0x80:0xDA
+
+# Impact hound
+R:543:0x80:0xDA
+
+# Sea troll
+R:544:0x80:0xD4
+
+# Ooze elemental
+R:545:0x80:0xC5
+
+# Young black dragon
+R:546:0x80:0xE4
+
+# Mumak
+R:547:0x80:0xF1
+
+# Giant red ant
+R:548:0x80:0xE1
+
+# Mature white dragon
+R:549:0x80:0xE4
+
+# Xorn
+R:550:0x80:0xD8
+
+# Rogrog the Black Troll
+R:551:0x80:0xD4
+
+# Mist giant
+R:552:0x80:0xA3
+
+# Phantom
+R:553:0x80:0xC7
+
+# Grey wraith
+R:554:0x80:0xD7
+
+# Revenant
+R:555:0x80:0xD7
+
+# Young multi-hued dragon
+R:556:0x80:0xE4
+
+# Raal's Tome of Destruction
+R:557:0x80:0xBF
+
+# Colossus
+R:558:0x80:0xE7
+
+# Young gold dragon
+R:559:0x80:0xE4
+
+# Mature blue dragon
+R:560:0x80:0xE4
+
+# Mature green dragon
+R:561:0x80:0xE4
+
+# Mature bronze dragon
+R:562:0x80:0xE4
+
+# Young red dragon
+R:563:0x80:0xE4
+
+# Nightblade
+R:564:0x80:0xE8
+
+# Trapper
+R:565:0x80:0xAE
+
+# Bodak
+R:566:0x80:0xF5
+
+# Time bomb
+R:567:0x80:0xAE
+
+# Mezzodaemon
+R:568:0x80:0xF5
+
+# Elder thing
+R:569:0x80:0xF5
+
+# Ice elemental
+R:570:0x80:0xC5
+
+# Necromancer
+R:571:0x81:0xBE
+
+# The Greater hell magic mushroom were-quylthulg
+R:572:0x80:0xD1
+
+# Lorgan, Chief of the Easterlings
+R:573:0x80:0xF0
+
+# Chaos spawn
+R:574:0x80:0xE5
+
+# Mummified troll
+R:575:0x80:0xFA
+
+# Fire angel
+R:576:0x80:0xE4
+
+# Crypt thing
+R:577:0x80:0xCC
+
+# Chaos butterfly
+R:578:0x80:0xC9
+
+# Time elemental
+R:579:0x80:0xC5
+
+# Flying polyp
+R:580:0x80:0xFE
+
+# The Queen Ant
+R:581:0x80:0xE1
+
+# Will o' the wisp
+R:582:0x80:0xC5
+
+# Shan
+R:583:0x80:0xC9
+
+# Magma elemental
+R:584:0x80:0xC5
+
+# Black pudding
+R:585:0x80:0xEA
+
+# Killer iridescent beetle
+R:586:0x80:0xCB
+
+# Nexus vortex
+R:587:0x80:0xF6
+
+# Plasma vortex
+R:588:0x80:0xF6
+
+# Mature red dragon
+R:589:0x80:0xE4
+
+# Mature gold dragon
+R:590:0x80:0xE4
+
+# Crystal drake
+R:591:0x80:0xE4
+
+# Mature black dragon
+R:592:0x80:0xE4
+
+# Mature multi-hued dragon
+R:593:0x80:0xE4
+
+# Sky whale
+R:594:0x80:0xFE
+
+# Draebor, the Imp
+R:595:0x80:0xF5
+
+# Mother Hydra
+R:596:0x80:0xF5
+
+# Death knight
+R:597:0x80:0xF0
+
+# Castamir the Usurper
+R:598:0x80:0xF0
+
+# Time vortex
+R:599:0x80:0xF6
+
+# Shimmering vortex
+R:600:0x80:0xF6
+
+# Ancient blue dragon
+R:601:0x80:0xC4
+
+# Ancient bronze dragon
+R:602:0x80:0xC4
+
+# Beholder
+R:603:0x80:0xE5
+
+# Emperor wight
+R:604:0x80:0xD7
+
+# Planetar
+R:605:0x80:0xC1
+
+# Vargo, Tyrant of Fire
+R:606:0x80:0xC5
+
+# Black wraith
+R:607:0x80:0xD7
+
+# Nightgaunt
+R:608:0x80:0xD5
+
+# Baron of hell
+R:609:0x80:0xD5
+
+# Medusa
+R:610:0x80:0xCD
+
+# Monastic lich
+R:611:0x80:0xCC
+
+# Nether wraith
+R:612:0x80:0xD7
+
+# Fire vampire
+R:613:0x80:0xD6
+
+# 7-headed hydra
+R:614:0x80:0xCD
+
+# Moire, Queen of Rebma
+R:615:0x80:0xC5
+
+# Kavlax the Many-Headed
+R:616:0x80:0xE4
+
+# Ancient white dragon
+R:617:0x80:0xC4
+
+# Ancient green dragon
+R:618:0x80:0xC4
+
+# Chthonian
+R:619:0x80:0xF7
+
+# Eldrak
+R:620:0x80:0xD4
+
+# Ettin
+R:621:0x80:0xD4
+
+# Night mare
+R:622:0x80:0xF1
+
+# Vampire lord
+R:623:0x80:0xD6
+
+# Ancient black dragon
+R:624:0x80:0xC4
+
+# Weird fume
+R:625:0x80:0xA3
+
+# Spawn of Ubbo-Sathla
+R:626:0x80:0xEA
+
+# Fat Man
+R:627:0x80:0xFB
+
+# Malekith the Accursed
+R:628:0x80:0xE8
+
+# Shadowfax, steed of Gandalf
+R:629:0x80:0xF1
+
+# Spirit troll
+R:630:0x80:0xD4
+
+# War troll
+R:631:0x80:0xD4
+
+# Disenchanter worm mass
+R:632:0x80:0xF7
+
+# Rotting quylthulg
+R:633:0x80:0xD1
+
+# Lesser titan
+R:634:0x80:0xD0
+
+# 9-headed hydra
+R:635:0x80:0xCD
+
+# Enchantress
+R:636:0x80:0xF0
+
+# Archpriest
+R:637:0x80:0xF0
+
+# Sorcerer
+R:638:0x80:0xF0
+
+# Xaren
+R:639:0x80:0xD8
+
+# Giant roc
+R:640:0x80:0xC2
+
+# Minotaur
+R:641:0x80:0xC8
+
+# Jasra, Brand's Mistress
+R:642:0x80:0xEE
+
+# Death drake
+R:643:0x80:0xC4
+
+# Ancient red dragon
+R:644:0x80:0xC4
+
+# Ancient gold dragon
+R:645:0x80:0xC4
+
+# Great crystal drake
+R:646:0x80:0xC4
+
+# Wyrd sister
+R:647:0x80:0xF0
+
+# Clubber demon
+R:648:0x80:0xD5
+
+# Death quasit
+R:649:0x80:0xF5
+
+# Giganto the Gargantuan
+R:650:0x80:0xFE
+
+# Strygalldwir
+R:651:0x80:0xD5
+
+# Fallen angel
+R:652:0x80:0xC1
+
+# Giant headless
+R:653:0x80:0xC8
+
+# Judge Fire
+R:654:0x80:0xF3
+
+# Ubbo-Sathla, the Unbegotten Source
+R:655:0x80:0xEA
+
+# Judge Mortis
+R:656:0x80:0xFA
+
+# Dark elven sorceror
+R:657:0x80:0xE8
+
+# Master lich
+R:658:0x80:0xCC
+
+# Byakhee
+R:659:0x80:0xD5
+
+# Eol the Dark Elf
+R:660:0x80:0xE8
+
+# Archon
+R:661:0x80:0xC1
+
+# Formless spawn of Tsathoggua
+R:662:0x80:0xD5
+
+# Hunting horror
+R:663:0x80:0xD5
+
+# Undead beholder
+R:664:0x80:0xE5
+
+# Shadow demon
+R:665:0x80:0xC7
+
+# Iron lich
+R:666:0x80:0xCC
+
+# Dread
+R:667:0x80:0xC7
+
+# Greater basilisk
+R:668:0x80:0xD2
+
+# Charybdis
+R:669:0x80:0xFE
+
+# Jack of Shadows
+R:670:0x80:0xF0
+
+# Zephyr Lord
+R:671:0x80:0xD7
+
+# Juggernaut of Khorne
+R:672:0x80:0xE7
+
+# Great Mumak
+R:673:0x80:0xF1
+
+# Judge Fear
+R:674:0x80:0xD7
+
+# Ancient multi-hued dragon
+R:675:0x80:0xC4
+
+# Ethereal dragon
+R:676:0x80:0xC4
+
+# Dark young of Shub-Niggurath
+R:677:0x80:0xA3
+
+# Colour out of space
+R:678:0x80:0xAE
+
+# Quaker, Master of Earth
+R:679:0x80:0xC5
+
+# Death leprechaun
+R:680:0x80:0xE8
+
+# Chaugnar Faugn, Horror from the Hills
+R:681:0x80:0xF1
+
+# Lloigor
+R:682:0x80:0xF6
+
+# Utgard-Loke
+R:683:0x80:0xD0
+
+# Quachil Uttaus, Treader of the Dust
+R:684:0x80:0xFA
+
+# Shoggoth
+R:685:0x80:0xEA
+
+# Judge Death
+R:686:0x80:0xD7
+
+# Ariel, Queen of Air
+R:687:0x80:0xC5
+
+# 11-headed hydra
+R:688:0x80:0xCD
+
+# High priest
+R:689:0x80:0xF0
+
+# Dreadmaster
+R:690:0x80:0xC7
+
+# Drolem
+R:691:0x80:0xE7
+
+# Scatha the Worm
+R:692:0x80:0xC4
+
+# Warrior of the Dawn
+R:693:0x80:0xF0
+
+# Lesser black reaver
+R:694:0x80:0xCC
+
+# Zoth-Ommog
+R:695:0x80:0xD2
+
+# Grand master thief
+R:696:0x80:0xF0
+
+# Smaug the Golden
+R:697:0x80:0xC4
+
+# The Stormbringer
+R:698:0x80:0xFC
+
+# Ultra-elite paladin
+R:699:0x80:0xF0
+
+# Leprechaun fanatic
+R:700:0x80:0xE8
+
+# Dracolich
+R:701:0x80:0xC4
+
+# Greater titan
+R:702:0x80:0xD0
+
+# Dracolisk
+R:703:0x80:0xC4
+
+# Fastitocalon
+R:704:0x80:0xC4
+
+# Spectral tyrannosaur
+R:705:0x80:0xD2
+
+# Yibb-Tstll the Patient One
+R:706:0x80:0xD0
+
+# Ghatanothoa
+R:707:0x80:0xC8
+
+# Ent
+R:708:0x80:0xA3
+
+# Hru
+R:709:0x80:0xD0
+
+# Itangast the Fire Drake
+R:710:0x80:0xC4
+
+# Death mold
+R:711:0x80:0xED
+
+# Fafner the Dragon
+R:712:0x80:0xC4
+
+# Charon the Boatsman
+R:713:0x80:0xD7
+
+# Quickbeam
+R:714:0x80:0xA3
+
+# Glaurung, Father of the Dragons
+R:715:0x80:0xC4
+
+# Behemoth
+R:716:0x80:0xC8
+
+# Garm, Guardian of Hel
+R:717:0x80:0xC3
+
+# Greater wall monster
+R:718:0x80:0xA3
+
+# Nycadaemon
+R:719:0x80:0xD5
+
+# Balrog
+R:720:0x80:0xD5
+
+# Goat of Mendes
+R:721:0x80:0xF1
+
+# Nightwing
+R:722:0x80:0xD7
+
+# Maulotaur
+R:723:0x80:0xC8
+
+# Nether hound
+R:724:0x80:0xDA
+
+# Time hound
+R:725:0x80:0xDA
+
+# Plasma hound
+R:726:0x80:0xDA
+
+# Demonic quylthulg
+R:727:0x80:0xD1
+
+# Great storm wyrm
+R:728:0x80:0xC4
+
+# Ulik the Troll
+R:729:0x80:0xD4
+
+# Baphomet the Minotaur Lord
+R:730:0x80:0xC8
+
+# Hell knight
+R:731:0x80:0xF0
+
+# Bull Gates
+R:732:0x80:0xF0
+
+# Santa Claus
+R:733:0x80:0xE8
+
+# Eihort, the Thing in the Labyrinth
+R:734:0x80:0xEA
+
+# The King in Yellow
+R:735:0x80:0xCC
+
+# Great unclean one
+R:736:0x80:0xD5
+
+# Lord of Chaos
+R:737:0x80:0xF0
+
+# Old Sorcerer
+R:738:0x80:0xF0
+
+# Hound of Tindalos
+R:739:0x80:0xDA
+
+# Lesser kraken
+R:740:0x80:0xFE
+
+# Great ice wyrm
+R:741:0x80:0xC4
+
+# Demilich
+R:742:0x80:0xCC
+
+# The Phoenix
+R:743:0x80:0xC2
+
+# Nightcrawler
+R:744:0x80:0xD7
+
+# Lord of Change
+R:745:0x80:0xC2
+
+# Keeper of Secrets
+R:746:0x80:0xC8
+
+# Shudde M'ell
+R:747:0x80:0xF7
+
+# Hand druj
+R:748:0x80:0xF3
+
+# Eye druj
+R:749:0x80:0xF3
+
+# Skull druj
+R:750:0x80:0xF3
+
+# Chaos vortex
+R:751:0x80:0xF6
+
+# Aether vortex
+R:752:0x80:0xF6
+
+# Nidhogg the Hel-Drake
+R:753:0x80:0xC4
+
+# The Lernean Hydra
+R:754:0x80:0xCD
+
+# Thuringwethil
+R:755:0x80:0xD6
+
+# Great hell wyrm
+R:756:0x80:0xC4
+
+# Hastur the Unspeakable
+R:757:0x80:0xC8
+
+# Bloodthirster
+R:758:0x80:0xD5
+
+# Draconic quylthulg
+R:759:0x80:0xD1
+
+# Nyogtha, the Thing that Should not Be
+R:760:0x80:0xEA
+
+# Ahtu, Avatar of Nyarlathotep
+R:761:0x80:0xA3
+
+# Fundin Bluecloak
+R:762:0x80:0xE8
+
+# The Philosophy Teacher
+R:763:0x80:0xF0
+
+# Uriel, Angel of Fire
+R:764:0x80:0xC1
+
+# Azriel, Angel of Death
+R:765:0x80:0xC1
+
+# Ancalagon the Black
+R:766:0x80:0xC4
+
+# Daoloth, the Render of the Veils
+R:767:0x80:0xD5
+
+# Nightwalker
+R:768:0x80:0xD7
+
+# Gabriel, the Messenger
+R:769:0x80:0xC1
+
+# Artsi the Champion of Chaos
+R:770:0x80:0xE8
+
+# Saruman of Many Colours
+R:771:0x80:0xF0
+
+# Harowen the Black Hand
+R:772:0x80:0xF0
+
+# The Physics Teacher
+R:773:0x80:0xF0
+
+# Shadowlord
+R:774:0x80:0xC7
+
+# Greater kraken
+R:775:0x80:0xFE
+
+# Archlich
+R:776:0x80:0xCC
+
+# The Cat Lord
+R:777:0x80:0xE6
+
+# Chaos beetle
+R:778:0x80:0xCB
+
+# Chaos hound
+R:779:0x80:0xDA
+
+# Vlad Dracula, Prince of Darkness
+R:780:0x80:0xD6
+
+# Ultimate beholder
+R:781:0x80:0xE5
+
+# Leviathan
+R:782:0x80:0xC4
+
+# Great Wyrm of Chaos
+R:783:0x80:0xC4
+
+# Great Wyrm of Law
+R:784:0x80:0xC4
+
+# Great Wyrm of Balance
+R:785:0x80:0xC4
+
+# Shambler
+R:786:0x80:0xC5
+
+# Hypnos, Lord of Sleep
+R:787:0x80:0xD0
+
+# Glaaki
+R:788:0x80:0xFE
+
+# T'ron, the rebel DragonRider
+R:789:0x80:0xC4
+
+# Great Wyrm of Many Colours
+R:790:0x80:0xC4
+
+# Mardra, rider of the Gold Loranth
+R:791:0x80:0xC4
+
+# Tselakus, the Dreadlord
+R:792:0x80:0xC7
+
+# Sky Drake
+R:793:0x80:0xC4
+
+# Eilinel the Entrapped
+R:794:0x80:0xF0
+
+# Tiamat, Celestial Dragon of Evil
+R:795:0x80:0xC4
+
+# The Norsa
+R:796:0x80:0xC8
+
+# Rhan-Tegoth
+R:797:0x80:0xD3
+
+# Black reaver
+R:798:0x80:0xCC
+
+# Troll High Priest
+R:799:0x80:0xD4
+
+# Master quylthulg
+R:800:0x80:0xD1
+
+# Greater draconic quylthulg
+R:801:0x80:0xD1
+
+# Greater rotting quylthulg
+R:802:0x80:0xD1
+
+# Null the Living Void
+R:803:0x80:0xAE
+
+# Vecna, the Emperor Lich
+R:804:0x80:0xCC
+
+# Omarax the Eye Tyrant
+R:805:0x80:0xE5
+
+# Tsathoggua, the Sleeper of N'kai
+R:806:0x80:0xF2
+
+# Greater Balrog
+R:807:0x80:0xD5
+
+# Ungoliant, the Unlight
+R:808:0x80:0xD3
+
+# Atlach-Nacha, the Spider God
+R:809:0x80:0xD3
+
+# Y'golonac
+R:810:0x80:0xC8
+
+# Aether hound
+R:811:0x80:0xDA
+
+# Warp demon
+R:812:0x80:0xD5
+
+# Serpent of Chaos
+R:813:0x80:0xCA
+
+# Yig, Father of Serpents
+R:814:0x80:0xD2
+
+# Unmaker
+R:815:0x80:0xC5
+
+# Cyberdemon
+R:816:0x80:0xD5
+
+# Hela, Queen of the Dead
+R:817:0x80:0xF0
+
+# The Mouth of Sauron
+R:818:0x80:0xF0
+
+# Klingsor, Evil Master of Magic
+R:819:0x80:0xF0
+
+# Lessa, rider of the Gold Ramoth
+R:820:0x80:0xC4
+
+# The Emperor Quylthulg
+R:821:0x80:0xD1
+
+# Qlzqqlzuup, the Lord of Flesh
+R:822:0x80:0xD1
+
+# Cthugha, the Living Flame
+R:823:0x80:0xC5
+
+# F'lar, rider of the Bronze Mnementh
+R:824:0x80:0xC4
+
+# Maeglin, Betrayer of Gondolin
+R:825:0x80:0xE8
+
+# Cyaegha
+R:826:0x80:0xE5
+
+# Pazuzu, Lord of Air
+R:827:0x80:0xC2
+
+# Ithaqua the Windwalker
+R:828:0x80:0xD9
+
+# Hell hound
+R:829:0x80:0xC3
+
+# Cantoras, the Skeletal Lord
+R:830:0x80:0xF3
+
+# Mephistopheles, Lord of Hell
+R:831:0x80:0xD5
+
+# Godzilla
+R:832:0x80:0xD2
+
+# Abhoth, Source of Uncleanness
+R:833:0x80:0xCA
+
+# Ymir the Ice Giant
+R:834:0x80:0xD0
+
+# Loki the Trickster
+R:835:0x80:0xD0
+
+# Star-spawn of Cthulhu
+R:836:0x80:0xD5
+
+# Surtur the Giant Fire Demon
+R:837:0x80:0xD0
+
+# The Tarrasque
+R:838:0x80:0xD2
+
+# Lungorthin, the Balrog of White Fire
+R:839:0x80:0xD5
+
+# Draugluin, Sire of All Werewolves
+R:840:0x80:0xC3
+
+# Shuma-Gorath
+R:841:0x80:0xE5
+
+# Tulzscha, the Green Flame
+R:842:0x80:0xC5
+
+# Oremorj the Cyberdemon Lord
+R:843:0x80:0xD5
+
+# Feagwath the Undead Sorceror
+R:844:0x80:0xCC
+
+# Yog-Sothoth, the All-in-One
+R:845:0x80:0xEA
+
+# Fenris Wolf
+R:846:0x80:0xC3
+
+# Great Wyrm of Power
+R:847:0x80:0xC4
+
+# Shub-Niggurath, Black Goat of the Woods
+R:848:0x80:0xD5
+
+# Nodens, Lord of the Great Abyss
+R:849:0x80:0xD0
+
+# Carcharoth, the Jaws of Thirst
+R:850:0x80:0xC3
+
+# Nyarlathotep, the Crawling Chaos
+R:851:0x80:0xD5
+
+# Azathoth, the Daemon Sultan
+R:852:0x80:0xC5
+
+# Cerberus, Guardian of Hades
+R:853:0x80:0xC3
+
+# Jormungand the Midgard Serpent
+R:854:0x80:0xCA
+
+# The Destroyer
+R:855:0x80:0xE7
+
+# Gothmog, the High Captain of Balrogs
+R:856:0x80:0xD5
+
+# Great Cthulhu
+R:857:0x80:0xD5
+
+# Sorka, rider of the Gold Faranth
+R:858:0x80:0xC4
+
+# The Unicorn of Order
+R:859:0x80:0xF1
+
+# Sauron, the Sorcerer
+R:860:0x80:0xF0
+
+# Dark God, the Mighty Coder of Hell
+R:861:0x80:0xD0
+
+# Morgoth, Lord of Darkness
+R:862:0x80:0xD0
+
+# Human Warrior
+R:863:0x81:0xB7
+
+# Elven Archer
+R:864:0x81:0xC0
+
+# Dwarven Warrior
+R:865:0x80:0xE8
+
+# Mountain Orc
+R:866:0x80:0xEF
+
+# The Philosophy Teacher
+R:867:0x80:0xD0
+
+# The Variant Maintainer
+R:868:0x80:0xF0
+
+# Random Number Generator
+R:869:0x80:0xC9
+
+# Rocket mine
+R:870:0x80:0xAE
+
+# Bouncing mine
+R:871:0x80:0xAE
+
+# Muar, the Balrog
+R:872:0x80:0xD5
+
+# The Icky Queen
+R:873:0x80:0xE9
+
+# Ratmold
+R:874:0x80:0xED
+
+# Death
+R:875:0x80:0xC7
+
+# Famine
+R:876:0x80:0xC7
+
+# Pestilence
+R:877:0x80:0xC7
+
+# War
+R:878:0x80:0xC7
+
+# Pike
+R:879:0x80:0xFE
+
+# Electric eel
+R:880:0x80:0xFE
+
+# Giant crayfish
+R:881:0x80:0xFE
+
+# Mermaid
+R:882:0x80:0xE8
+
+# Merman
+R:883:0x80:0xE8
+
+# Big Pirahna
+R:884:0x80:0xFE
+
+# Lizard man
+R:885:0x80:0xE8
+
+# Frogman
+R:886:0x80:0xE8
+
+# Frogman warrior
+R:887:0x80:0xE8
+
+# Frogman shaman
+R:888:0x80:0xE8
+
+# Small medusa
+R:889:0x80:0xD1
+
+# Sand mite
+R:890:0x80:0xFE
+
+# Octopus
+R:891:0x80:0xD1
+
+# Kraken
+R:892:0x80:0xD1
+
+# Aquatic beholder
+R:893:0x80:0xE5
+
+# Murk dweller
+R:894:0x80:0xD3
+
+# Drowned soul
+R:895:0x80:0xC7
+
+# Tiger shark
+R:896:0x80:0xFE
+
+# Hammerhead shark
+R:897:0x80:0xFE
+
+# Great white shark
+R:898:0x80:0xFE
+
+# Aquatic golem
+R:899:0x80:0xE7
+
+# Aquatic kobold
+R:900:0x80:0xEB
+
+# Elder kraken
+R:901:0x80:0xD1
+
+# Aquatic troll
+R:902:0x80:0xD4
+
+# Elder aquatic beholder
+R:903:0x80:0xE5
+
+# Abysmal elf
+R:904:0x80:0xE8
+
+# Abysmal elven warrior
+R:905:0x80:0xE8
+
+# Abysmal elven shaman
+R:906:0x80:0xE8
+
+# Stargazer
+R:907:0x80:0xFE
+
+# Elder stargazer
+R:908:0x80:0xFE
+
+# Flounder
+R:909:0x80:0xFE
+
+# Giant turtle
+R:910:0x80:0xD2
+
+# Baby abysmal dragon
+R:911:0x80:0xE4
+
+# Young abysmal dragon
+R:912:0x80:0xE4
+
+# Mature abysmal dragon
+R:913:0x80:0xE4
+
+# Ancient abysmal dragon
+R:914:0x80:0xC4
+
+# Dragon turtle
+R:915:0x80:0xD2
+
+# Undead stargazer
+R:916:0x80:0xFE
+
+# Killer whale
+R:917:0x80:0xFE
+
+# Undead killer whale
+R:918:0x80:0xC7
+
+# Aquatic naga
+R:919:0x80:0xEE
+
+# Devilfish
+R:920:0x80:0xFE
+
+# Undead devilfish
+R:921:0x80:0xFE
+
+# Devilfish beholder
+R:922:0x80:0xE5
+
+# Aquatic hound
+R:923:0x80:0xDA
+
+# Aquatic demon
+R:924:0x80:0xD5
+
+# Aquatic demonlord
+R:925:0x80:0xD5
+
+# Manta ray
+R:926:0x80:0xFE
+
+# Undead manta ray
+R:927:0x80:0xFE
+
+# Mathilde, the Science Student
+R:928:0x80:0xE8
+
+# Child spirit
+R:929:0x80:0xC7
+
+# Young spirit
+R:930:0x80:0xC7
+
+# Mature spirit
+R:931:0x80:0xC7
+
+# Experienced spirit
+R:932:0x80:0xC7
+
+# Wise spirit
+R:933:0x80:0xC7
+
+# Fangorn the Treebeard
+R:934:0x80:0xA3
+
+# Gandalf the Grey
+R:935:0x80:0xF0
+
+# Nar, the Dwarf
+R:936:0x80:0xE8
+
+# Black troll
+R:937:0x80:0xD4
+
+# Troll Clan Chief
+R:938:0x80:0xD4
+
+# Troll King
+R:939:0x80:0xD4
+
+# Blue Firelizard
+R:940:0x80:0xE4
+
+# Green Firelizard
+R:941:0x80:0xE4
+
+# Brown Firelizard
+R:942:0x80:0xE4
+
+# Bronze Firelizard
+R:943:0x80:0xE4
+
+# Gold Firelizard
+R:944:0x80:0xE4
+
+# High-elven ranger
+R:945:0x80:0xE8
+
+# Uvatha the Horseman
+R:946:0x80:0xD7
+
+# Adunaphel the Quiet
+R:947:0x80:0xD7
+
+# Akhorahil the Blind
+R:948:0x80:0xD7
+
+# Ren the Unclean
+R:949:0x80:0xD7
+
+# Ji Indur Dawndeath
+R:950:0x80:0xD7
+
+# Dwar, Dog Lord of Waw
+R:951:0x80:0xD7
+
+# Hoarmurath of Dir
+R:952:0x80:0xD7
+
+# Khamul the Easterling
+R:953:0x80:0xD7
+
+# Murazor, the Witch-King of Angmar
+R:954:0x80:0xD7
+
+# Green DragonRider
+R:955:0x80:0xC4
+
+# Blue DragonRider
+R:956:0x80:0xC4
+
+# Brown DragonRider
+R:957:0x80:0xC4
+
+# Bronze DragonRider
+R:958:0x80:0xC4
+
+# Gold DragonRider
+R:959:0x80:0xC4
+
+# Thread
+R:960:0x80:0xED
+
+# Gorlim, Betrayer of Barahir
+R:961:0x80:0xF0
+
+# The Blubbering idiot, agent of black market, Simon the weak
+R:962:0x80:0xF4
+
+# Aranea
+R:963:0x80:0xD3
+
+# Elder aranea
+R:964:0x80:0xD3
+
+# Greater Aranea
+R:965:0x80:0xD3
+
+# Dolphiner
+R:966:0x80:0xF0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:967:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:968:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:969:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:970:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:971:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:972:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:973:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:974:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:975:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:976:0x80:0xC0
+
+# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+R:977:0x80:0xC0
+
+# Moldoux, the Defenceless Mold
+R:978:0x80:0xED
+
+# Ben Harrison
+R:979:0x80:0xF0
+
+# Ar-Pharazon the Golden
+R:980:0x80:0xF0
+
+# Doppleganger
+R:981:0x80:0xC0
+
+# Marylene, Heartbreakeress of the Netherworld
+R:982:0x80:0xD0
+
+# The Greater Lag Monster
+R:983:0x80:0xD5
+
+# Khim, Son of Mim
+R:984:0x80:0xE8
+
+# Bullroarer the Hobbit
+R:985:0x80:0xE8
+
+# 3-headed hydra
+R:986:0x80:0xCD
+
+# Uldor the Accursed
+R:987:0x80:0xF0
+
+# Mystic
+R:988:0x80:0xF0
+
+# Invisible stalker
+R:989:0x80:0xC5
+
+# Ulfang the Black
+R:990:0x80:0xF0
+
+# Demonologist
+R:991:0x80:0xF0
+
+# Hezrou
+R:992:0x80:0xD5
+
+# Glabrezu
+R:993:0x80:0xD5
+
+# Nalfeshnee
+R:994:0x80:0xD5
+
+# Marilith
+R:995:0x80:0xD5
+
+# Lesser Balrog
+R:996:0x80:0xD5
+
+# Master mystic
+R:997:0x80:0xF0
+
+# Grand master mystic
+R:998:0x80:0xF0
+
+# Erinyes
+R:999:0x80:0xD5
+
+# Medusa, the Gorgon
+R:1000:0x80:0xEE
+
+# Vrock
+R:1001:0x80:0xD5
+
+# Solar
+R:1002:0x80:0xC1
+
+# Ethereal hound
+R:1003:0x80:0xDA
+
+# Dreadlord
+R:1004:0x80:0xC7
+
+# Redweed
+R:1005:0x81:0xB0
+
+# The Rat King
+R:1006:0x80:0xF2
+
+# Vort the Kobold Queen
+R:1007:0x80:0xEB
+
+# Giant cockroach
+R:1008:0x80:0xC9
+
+# Fire Phantom
+R:1009:0x80:0xC7
+
+# The Insane Player
+R:1010:0x80:0xF0
+
+# Glaryssa, Succubus Queen
+R:1011:0x80:0xD5
+
+# Vermicious Knid
+R:1012:0x80:0xCF
+
+# Bone golem
+R:1013:0x80:0xE7
+
+# Snake of Yig
+R:1014:0x80:0xCA
+
+# Wild Man
+R:1015:0x80:0xE8
+
+# Dimensional shambler
+R:1016:0x80:0xE8
+
+# Cultist
+R:1017:0x80:0xF0
+
+# Cult leader
+R:1018:0x80:0xF0
+
+# Servitor of the outer gods
+R:1019:0x80:0xD5
+
+# Avatar of Nyarlathotep
+R:1020:0x80:0xF0
+
+# Fthagghua, Lord of the fire vampires
+R:1021:0x80:0xD5
+
+# Hypnos
+R:1022:0x80:0xF0
+
+# Blue Dragon Worm
+R:1023:0x80:0xF7
+
+# White Dragon Worm
+R:1024:0x80:0xF7
+
+# Red Dragon Worm
+R:1025:0x80:0xF7
+
+# Black Dragon Worm
+R:1026:0x80:0xF7
+
+# Green Dragon Worm
+R:1027:0x80:0xF7
+
+# Multi-hued Dragon Worm
+R:1028:0x80:0xF7
+
+# The Baby Minotaur
+R:1029:0x80:0xC8
+
+# The Sandworm Queen
+R:1030:0x80:0xF7
+
+# Sandworm
+R:1031:0x80:0xF7
+
+# Nobody, the Undefined Ghost
+R:1032:0x80:0xC7
+
+
+
+
+
diff --git a/lib/mods/theme/pref/graf-mac.prf b/lib/mods/theme/pref/graf-mac.prf
new file mode 100644
index 00000000..7bb84141
--- /dev/null
+++ b/lib/mods/theme/pref/graf-mac.prf
@@ -0,0 +1,15 @@
+# File: graf-mac.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
diff --git a/lib/mods/theme/pref/graf-new.prf b/lib/mods/theme/pref/graf-new.prf
new file mode 100644
index 00000000..2fb1b215
--- /dev/null
+++ b/lib/mods/theme/pref/graf-new.prf
@@ -0,0 +1,6934 @@
+# PRF file generated by Andreas Koch`s Tile Assigner
+# at 03.12.02 , 17:18:08 by Ja with version 1.7c
+
+# 2460 items
+# 2312 probably mapped correctly
+# 147 imported but not yet defined
+# 1 defined to value(s) lower than 0x80
+# Old header :
+# File: graf-new.prf
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+# with Adam Bolt's 16x16 tiles.
+#
+# By Robert Ruehlmann < rr9@angband.org >
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+# General Store
+B:0:0x82/0x87
+
+# Armoury
+B:1:0x82/0x88
+
+# Weaponsmith
+B:2:0x82/0x89
+
+# Temple
+B:3:0x82/0x8A
+
+# Alchemy shop
+B:4:0x82/0x8B
+
+# Magic shop
+B:5:0x82/0x8C
+
+# Black Market
+B:6:0x82/0x8D
+
+# Home
+B:7:0x82/0x8E
+
+# Book Store
+B:8:0x82/0x8F
+
+# Pet Shop
+B:9:0x82/0x90
+
+# Mayor's Office
+B:10:0x86/0xA0
+
+# Inn
+B:11:0x86/0xA1
+
+# The Soothsayer
+B:12:0x86/0xA2
+
+# Library
+B:13:0x86/0xA3
+
+# Castle
+B:14:0x86/0xA4
+
+# Casino
+B:15:0x86/0xA5
+
+# Beastmaster Shanty
+B:16:0x86/0xA6
+
+# Fighters Hall
+B:17:0x86/0xA7
+
+# Tower of Magery
+B:18:0x86/0xA8
+
+# Inner Temple
+B:19:0x86/0xA9
+
+# Paladins Guild
+B:20:0x86/0xAA
+
+# Rangers Guild
+B:21:0x86/0xAB
+
+# Thunderlords' Hide
+B:22:0x86/0xAC
+
+# The Mirror
+B:23:0x86/0xAD
+
+# Seat of Ruling
+B:24:0x86/0xAE
+
+# Wizards Spire
+B:25:0x86/0xAF
+
+# Priests Circle
+B:26:0x86/0xB0
+
+# Tower of the King
+B:27:0x86/0xB1
+
+# Library
+B:28:0x86/0xA3
+
+# The White Tree
+B:29:0x86/0xB2
+
+# Craftsmaster
+B:30:0x86/0xB3
+
+# Earth-Dome (Nature)
+B:31:0x86/0xB4
+
+# Minstrels Haven
+B:32:0x86/0xB5
+
+# Star-Dome
+B:33:0x86/0xB6
+
+# Valarin Temple
+B:34:0x86/0xB7
+
+# Sea-Dome
+B:35:0x86/0xB8
+
+# The Golden Flower
+B:36:0x86/0xB9
+
+# The Fountain
+B:37:0x86/0xBA
+
+# Axe Smith
+B:38:0x86/0xBB
+
+# Hafted Smith
+B:39:0x86/0xBC
+
+# Polearm Smith
+B:40:0x86/0xBD
+
+# Sword Smith
+B:41:0x86/0xBE
+
+# Rare Jewelry Shop
+B:42:0x86/0xBF
+
+# Jewelry Shop
+B:43:0x87/0xA0
+
+# Footwear Shop
+B:44:0x87/0xA1
+
+# Rare Footwear Shop
+B:45:0x87/0xA2
+
+# Library
+B:46:0x86/0xA3
+
+# Forbidden Library
+B:47:0x87/0xA3
+
+# Expensive Black Market
+B:48:0x87/0xA4
+
+# Common Shop
+B:49:0x87/0xA5
+
+# Dragon Hunter
+B:50:0x87/0xA6
+
+# Speed Ring Market
+B:51:0x87/0xA7
+
+# Scribe
+B:52:0x87/0xA8
+
+# Potion Store
+B:53:0x87/0xA9
+
+# Recaller
+B:54:0x87/0xAA
+
+# Master Archer
+B:55:0x87/0xAB
+
+# Merchants Guild
+B:56:0x87/0xAC
+
+# The Mathom-house
+B:57:0x87/0xAD
+
+# The Prancing Pony
+B:58:0x86/0xA1
+
+# Mining Supply store
+B:59:0x86/0xB3
+
+# Library quest in Minas Anor
+B:60:0x86/0xA3
+
+# Hunting Supply Store
+B:61:0x87/0xAB
+
+# Runic Magic Shop
+B:62:0x82/0x8C
+
+# Construction Supply Store
+B:63:0x86/0xB3
+
+# Music Store
+B:64:0x86/0xB5
+
+# Magic Rod Market
+B:65:0x82/0x8C
+
+# Map store
+B:66:0x86/0xA3
+
+# Farm
+B:67:0x87/0xA5
+
+#Pelargir inn - The Grey Swan
+B:68:0x86/0xA1
+
+#Caras Galadhon inn - The Garden
+B:69:0x86/0xA1
+
+#Khazad Dum inn - The Mithril Lode
+B:70:0x86/0xA1
+
+#Dale inn - The Builder Barracks
+B:71:0x86/0xA1
+
+#Edoras inn - The Horse and Ox
+B:72:0x86/0xA1
+
+#Esgaroth inn - The Dancing Dragon
+B:73:0x86/0xA1
+
+#Hobbiton inn - The Green Dragon
+B:74:0x86/0xA1
+
+#Osgiliath inn - The Twinkling Star
+B:75:0x86/0xA1
+
+#The House of Beorn
+B:76:0x86/0xA0
+
+#Bard's Hut
+B:77:0x86/0xA0
+
+#The Ranger Conclave
+B:78:0x86/0xA0
+
+#Imladris
+B:79:0x86/0xA0
+
+#The Hornburg
+B:80:0x86/0xA0
+
+#Thranduil's Hall
+B:81:0x86/0xA0
+
+#Meduseld
+B:82:0x86/0xA0
+
+#The Master's House
+B:83:0x86/0xA0
+
+#Bag End
+B:84:0x86/0xA0
+
+#The Castle of Stars
+B:85:0x86/0xA0
+
+#The Prince's Tower
+B:86:0x86/0xA0
+
+#The Seat of Durin
+B:87:0x86/0xA0
+
+### The forge in Imladris
+B:88:0x86/0xB3
+
+# nothing
+F:0:0x80/0x80
+
+# open floor
+F:1:0x80/0x81
+
+# fountain
+F:2:0xC3/0x9A
+
+# glyph of warding
+F:3:0x8D/0x95
+
+# open door
+F:4:0x82/0x84
+
+# broken door
+F:5:0x82/0x85
+
+# up staircase
+F:6:0x80/0x96
+
+# down staircase
+F:7:0x80/0x99
+
+# quest entrance
+F:8:0x80/0x9A
+
+# quest exit
+F:9:0x80/0x97
+
+# quest down level
+F:10:0x80/0x9B
+
+# quest up level
+F:11:0x80/0x98
+
+# town exit
+F:12:0x82/0x84
+
+# shaft down
+F:13:0xC3/0x84
+
+# shaft up
+F:14:0xC3/0x85
+
+# fountain
+F:15:0xC3/0x99
+
+# web
+F:16:0x81/0x8C
+
+# trap
+F:17:0x81/0x89
+
+# visible trap -- spiked pit
+F:18:0x81/0x89
+
+# visible trap -- poison pit
+F:19:0x81/0x89
+
+# visible trap -- rune -- summon
+F:20:0x81/0x8F
+
+# visible trap -- rune -- teleport
+F:21:0x81/0x92
+
+# visible trap -- spot -- fire
+F:22:0x81/0x86
+
+# visible trap -- spot -- acid
+F:23:0x81/0x86
+
+# visible trap -- dart -- slow
+F:24:0x81/0x80
+
+# visible trap -- dart -- lose str
+F:25:0x81/0x80
+
+# visible trap -- dart -- lose dex
+F:26:0x81/0x80
+
+# visible trap -- dart -- lose con
+F:27:0x81/0x80
+
+# visible trap -- gas -- blind
+F:28:0x81/0x83
+
+# visible trap -- gas -- confuse
+F:29:0x81/0x83
+
+# visible trap -- gas -- poison
+F:30:0x81/0x83
+
+# visible trap -- gas -- sleep
+F:31:0x81/0x83
+
+# door
+F:32:0x82/0x83
+
+# locked door
+F:33:0x82/0x83
+F:34:0x82/0x83
+F:35:0x82/0x83
+F:36:0x82/0x83
+F:37:0x82/0x83
+F:38:0x82/0x86
+F:39:0x82/0x86
+
+# jammed door
+F:40:0x82/0x83
+F:41:0x82/0x83
+F:42:0x82/0x83
+F:43:0x82/0x83
+F:44:0x82/0x83
+F:45:0x82/0x86
+F:46:0x82/0x86
+F:47:0x82/0x86
+
+# secret door
+F:48:0x80/0x84
+
+# pile of rubble
+F:49:0x80/0x9C
+
+# magma vein
+F:50:0x80/0x8D
+
+# quartz vein
+F:51:0x80/0x87
+
+# magma vein
+F:52:0x80/0x90
+
+# quartz vein
+F:53:0x80/0x87
+
+# magma vein with treasure
+F:54:0x80/0x90
+
+# quartz vein with treasure
+F:55:0x80/0x8A
+
+# granite wall
+F:56:0x80/0x84
+F:57:0x80/0x84
+F:58:0x80/0x84
+F:59:0x80/0x84
+
+# permanent wall
+F:60:0x80/0x93
+F:61:0x80/0x93
+F:62:0x80/0x93
+F:63:0x80/0x93
+
+# explosive rune
+F:64:0x8D/0x9E
+
+# Straight Road startpoint
+F:65:0x81/0x95
+
+# section of the Straight Road
+F:66:0x81/0x95
+F:67:0x81/0x95
+F:68:0x81/0x95
+F:69:0x81/0x95
+F:70:0x81/0x95
+
+# section of the Straight Road (discharged)
+F:71:0x81/0x98
+
+# Straight Road exit
+F:72:0x81/0x9B
+
+# corrupted section of the Straight Road
+F:73:0x81/0x9E
+
+# Building
+F:74:0x82/0x93
+
+# permanent wall
+F:75:0x82/0x93
+F:76:0x82/0x94
+F:77:0x82/0x95
+F:78:0x82/0x96
+
+#Elanor
+F:79:0xC6:0xA0
+
+#Fumellar
+F:80:0xC6:0xA1
+
+#Anemones
+F:81:0xC6:0xA2
+
+#Niphredil
+F:82:0xC6:0xA3
+
+#Iris
+F:83:0xC6:0xA4
+
+# stream of shallow water
+F:84:0xB4/0x97
+
+# pool of deep lava
+F:85:0x83/0x8D
+
+# stream of shallow lava
+F:86:0xB4/0x9A
+
+# dark pit
+F:87:0x80/0x80
+
+# dirt
+F:88:0xB4/0x91
+
+# patch of grass
+F:89:0xB4/0x94
+
+# ice
+F:90:0xC3/0x83
+
+# sand
+F:91:0xC3/0x88
+
+# dead tree
+F:92:0xC3/0x98
+
+# ash
+F:93:0xC3/0x97
+
+# mud
+F:94:0xC3/0x96
+
+# ice wall
+F:95:0xC5/0x92
+
+# tree
+F:96:0x82/0x9A
+
+# mountain chain
+F:97:0x8D/0x98
+
+# sandwall
+F:98:0xC3/0x86
+F:99:0xC3/0x86
+
+# sandwall with treasure
+F:100:0xC3/0x87
+
+# high mountain chain
+F:101:0xC3/0x9E
+
+# nether mist
+F:102:0xC3/0x9F
+
+# molten glass wall
+F:103:0xC0/0x9F
+
+# Void Jumpgate
+F:160:0x91/0x84
+
+# Altar of Being
+F:161:0xC1/0x8E
+
+# Altar of Winds
+F:162:0xB5/0x8A
+
+# Altar of Force
+F:163:0xB5/0x86
+
+# Altar of Darkness
+F:164:0xB5/0x86
+
+# Altar of Nature
+F:165:0xB5/0x91
+
+# Altar of Sun
+F:166:0xB5/0x8F
+
+# Altar of Rage
+F:167:0xB5/0x8C
+
+# Altar of Winds
+F:168:0xB5/0x92
+
+# Altar of Stars
+F:169:0xC1/0x8F
+
+# Altar of Being
+F:170:0xB5/0x8D
+
+# Altar of Randomness
+F:171:0xB5/0x88
+
+# floor
+F:172:0x80/0x81
+
+# Underground Tunnel
+F:173:0x80/0x82
+
+# stream of tainted water
+F:174:0xAF/0x8E
+
+# monster trap
+F:175:0x81/0x9C
+
+# Void Jumpgate
+F:176:0xAF/0x8C
+
+# lava wall
+F:177:0xC6/0x8C
+
+# Great Fire
+F:178:0xC6/0x8A
+
+# path to the next area
+F:179:0x88/0xA1
+
+# path to the previous area
+F:180:0x88/0xA0
+
+# field
+F:181:0x88/0xA2
+
+# Ekkaia, the Encircling Sea
+F:182:0x88/0xA3
+
+# Altar of Energy
+F:183:0xB5/0x9A
+
+# Altar of Matter
+F:184:0xB5/0x9B
+
+# Altar of Being
+F:185:0xB5/0x9C
+
+# Altar of Unbeing
+F:186:0xB5/0x9D
+
+# pool of deep water
+F:187:0x83/0x80
+
+# glass wall
+F:188:0xC0/0x9F
+
+# illusion wall
+F:189:0x80/0x84
+
+# Grass roof
+F:190:0xC2/0x80
+
+# grass roof top
+F:191:0xC2/0x81
+
+# grass roof chimney
+F:192:0xC2/0x82
+
+# brick roof
+F:193:0xC3/0x80
+
+# brick roof top
+F:194:0xC3/0x81
+
+# brick roof chimney
+F:195:0xC3/0x82
+
+# window
+F:196:0xC2/0x83
+
+# small window
+F:197:0xC2/0x84
+
+# rain barrel
+F:198:0xC2/0x85
+
+# grass with flowers
+F:199:0xC2/0x86
+
+# cobblestone road
+F:200:0xC2/0x87
+
+# cobblestone with outlet
+F:201:0xC2/0x88
+
+# small tree
+F:202:0x82/0x9D
+
+# town
+F:203:0xC3/0x95
+
+# Underground Tunnel
+F:204:0x80/0x82
+
+# a blazing fire
+F:205:0xC6/0x8A
+
+# pile of rubble
+F:206:0xC6/0x8B
+
+# rocky ground
+F:207:0x8D/0xA0
+
+# cloud-like vapour
+F:208:0x8D/0xA1
+
+# condensing water
+F:209:0x8D/0xA2
+
+# dense mist
+F:210:0x8D/0xA3
+
+# hail-stone wall
+F:211:0x8D/0xA4
+
+# dead small tree
+F:212:0xC6:0xA5
+
+# low hill
+F:213:0xC6:0xA6
+
+# dark mountain chain
+F:214:0xC6:0xA7
+
+# blue mountain chain
+F:215:0xC6:0xA8
+
+# grey mountain chain
+F:216:0xC6:0xA9
+
+# part of Mount Doom
+F:217:0xC6:0xAA
+
+# snow-capped peak
+F:218:0xC3:0x9E
+
+# fir tree
+F:219:0xC6:0xAB
+
+# section of a flet
+F:220:0xC6:0xAC
+
+# light post
+F:221:0xC6:0xAD
+
+# water lily
+F:222:0xC6:0xAE
+
+# part of the Dead Marshes
+F:223:0xC6:0xAF
+
+# Black Gate
+F:224:0xC6:0xB0
+
+# river
+F:225:0xC6:0xB1
+
+# swamp pool
+F:226:0xC6:0xB2
+
+# stream of the Anduin river
+F:227:0xC6:0xB3
+
+# road sign that says 'Hurry to Gondolin!'
+F:228:0xC6:0xB4
+
+# beehive
+F:229:0xC6:0xB5
+
+# dirt road
+F:230:0xC6:0xB6
+
+# wide gate
+F:231:0xC6:0xB7
+
+# open gate
+F:232:0xC6:0xB8
+
+# wooden board
+F:233:0xC6:0xB9
+
+# wooden board
+F:234:0xC6:0xBA
+
+# wooden board
+F:235:0xC6:0xBB
+
+# wooden board
+F:236:0xC6:0xBC
+
+# white tree
+F:237:0xC6:0xBD
+
+# swift waterfall
+F:238:0xC6:0xBE
+
+# slippery rock ledge
+F:239:0xC5:0xA0
+
+# stable
+F:240:0xC5:0xA1
+
+# wooden plank
+F:241:0xC5:0xA2
+
+# fosse pit
+F:242:0xC5:0xA3
+
+# Mallorn
+F:243:0xC5:0xA4
+
+# copper pillar
+F:244:0xC5:0xBC
+
+# ethereal wall
+F:245:0x80/0x81
+
+# glacial wall
+F:246:0xC5/0x92
+
+# battlement
+F:247:0xC5:0xBD
+
+# dark pit
+F:248:0x82/0x84
+
+# Skeleton
+G:M:1:0xC6/0x91
+
+# Zombie
+G:M:2:0xC6/0x92
+
+# Lich
+G:M:3:0xC6/0x93
+
+# Spectral
+G:M:4:0xC6/0x94
+
+# Captain
+G:M:5:0xC6/0x95
+
+# Chieftain
+G:M:6:0xC6/0x96
+
+# Shaman
+G:M:7:0xC6/0x97
+
+# Priest
+G:M:8:0xC6/0x98
+
+# Mage
+G:M:9:0xC6/0x99
+
+# Archer
+G:M:10:0xC6/0x9A
+
+# Rogue
+G:M:11:0xC6/0x9B
+
+# Inertia Ball Trap
+G:T:95:0x82/0xBF
+
+# something
+K:0:0x01:0x20
+
+# Blindness
+K:1:0x85:0x94
+
+# Fear
+K:2:0x85:0x94
+
+# Confusion
+K:3:0x85:0x94
+
+# Hallucination
+K:4:0x85:0x94
+
+# Cure Poison
+K:5:0x85:0x94
+
+# Cure Blindness
+K:6:0x85:0x94
+
+# Cure Fear
+K:7:0xC6:0x83
+
+# Cure Confusion
+K:8:0x85:0x94
+
+# Weakness
+K:9:0x85:0x94
+
+# Unhealth
+K:10:0x85:0x94
+
+# Restore Constitution
+K:11:0x85:0x94
+
+# Restoring
+K:12:0x85:0x94
+
+# Stupidity
+K:13:0x85:0x94
+
+# Naivety
+K:14:0x85:0x94
+
+# Poison
+K:15:0x85:0x94
+
+# Sickness
+K:16:0x85:0x94
+
+# Paralysis
+K:17:0x85:0x94
+
+# Restore Strength
+K:18:0x85:0x94
+
+# Disease
+K:19:0x85:0x94
+
+# Cure Serious Wounds
+K:20:0x85:0x94
+
+# & Ration~ of Cram
+K:21:0x8E:0x84
+
+# & Round Seed-Cake~
+K:22:0x8E:0x82
+
+# & Strip~ of Venison
+K:23:0x8E:0x83
+
+# & Slime Mold~
+K:24:0x8E:0x85
+
+# & Lembas~
+K:25:0x8E:0x86
+
+# & Pint~ of Fine Ale
+K:26:0x8E:0x80
+
+# & Pint~ of Old Winyards
+K:27:0x8E:0x80
+
+# & Mattock~
+K:28:0xB6:0x8C
+
+# & Blue Stone~
+K:29:0xC5:0x93
+
+# & Broken Dagger~
+K:30:0x8A:0x8D
+
+# & Bastard Sword~
+K:31:0x8A:0x8E
+
+# & Scimitar~
+K:32:0x8A:0x97
+
+# & Tulwar~
+K:33:0x8A:0x95
+
+# & Broad Sword~
+K:34:0x8A:0x98
+
+# & Short Sword~
+K:35:0x8A:0x94
+
+# & Blade~ of Chaos
+K:36:0x8A:0x9E
+
+# & Two-Handed Sword~
+K:37:0x8A:0x9C
+
+# & Main Gauche~
+K:38:0x8A:0x90
+
+# & Cutlass~
+K:39:0x8A:0x96
+
+# & Executioner's Sword~
+K:40:0x8A:0x9D
+
+# & Katana~
+K:41:0x8A:0x9B
+
+# & Long Sword~
+K:42:0x8A:0x99
+
+# & Dagger~
+K:43:0x8A:0x8F
+
+# & Rapier~
+K:44:0x8A:0x91
+
+# & Sabre~
+K:45:0x8A:0x93
+
+# & Small Sword~
+K:46:0x8A:0x92
+
+# & Broken Sword~
+K:47:0x8A:0x8E
+
+# & Ball-and-Chain~
+K:48:0x8B:0x86
+
+# & Whip~
+K:49:0x8A:0x9F
+
+# & Flail~
+K:50:0x8B:0x83
+
+# & Two-Handed Flail~
+K:51:0x8B:0x87
+
+# & Morning Star~
+K:52:0x8B:0x84
+
+# & Mace~
+K:53:0x8B:0x81
+
+# & Quarterstaff~
+K:54:0x8B:0x82
+
+# & War Hammer~
+K:55:0x8B:0x80
+
+# & Lead-Filled Mace~
+K:56:0x8B:0x85
+
+# & Mace~ of Disruption
+K:57:0x8B:0x88
+
+# & Lucerne Hammer~
+K:58:0x8B:0x8D
+
+# & Beaked Axe~
+K:59:0x8B:0x90
+
+# & Glaive~
+K:60:0x8B:0x92
+
+# & Halberd~
+K:61:0x8B:0x93
+
+# & Awl-Pike~
+K:62:0x8B:0x8B
+
+# & Pike~
+K:63:0x8B:0x8F
+
+# & Spear~
+K:64:0x8B:0x89
+
+# & Trident~
+K:65:0x8B:0x8A
+
+# & Lance~
+K:66:0x8B:0x8C
+
+# & Great Axe~
+K:67:0x8B:0x95
+
+# & Battle Axe~
+K:68:0x8B:0x8E
+
+# & Lochaber Axe~
+K:69:0x8B:0x94
+
+# & Broad Axe~
+K:70:0x8B:0x91
+
+# & Scythe~
+K:71:0x8B:0x96
+
+# & Scythe~ of Slicing
+K:72:0x8B:0x97
+
+# & Short Bow~
+K:73:0x8B:0x98
+
+# & Long Bow~
+K:74:0x8B:0x99
+
+# & Light Crossbow~
+K:75:0x8B:0x9A
+
+# & Heavy Crossbow~
+K:76:0x8B:0x9B
+
+# & Sling~
+K:77:0x8B:0x9C
+
+# & Arrow~
+K:78:0x8C:0x80
+
+# & Seeker Arrow~
+K:79:0x8C:0x81
+
+# & Bolt~
+K:80:0x8C:0x82
+
+# & Seeker Bolt~
+K:81:0x8C:0x83
+
+# & Rounded Pebble~
+K:82:0x8C:0x84
+
+# & Iron Shot~
+K:83:0x8C:0x85
+
+# & Shovel~
+K:84:0x8E:0x8F
+
+# & Gnomish Shovel~
+K:85:0x8E:0x90
+
+# & Dwarven Shovel~
+K:86:0x8E:0x91
+
+# & Pick~
+K:87:0x8E:0x8C
+
+# & Orcish Pick~
+K:88:0x8E:0x8D
+
+# & Dwarven Pick~
+K:89:0x8E:0x91
+
+# & Elven Cloak~
+K:90:0x89:0x8A
+
+# & Pair~ of Soft Leather Boots
+K:91:0x88:0x8E
+
+# & Pair~ of Hard Leather Boots
+K:92:0x88:0x8F
+
+# & Pair~ of Metal Shod Boots
+K:93:0x88:0x90
+
+# & Hard Leather Cap~
+K:94:0x87:0x98
+
+# & Metal Cap~
+K:95:0x87:0x99
+
+# & Iron Helm~
+K:96:0x87:0x9A
+
+# & Steel Helm~
+K:97:0x87:0x9B
+
+# & Iron Crown~
+K:98:0x87:0x9C
+
+# & Golden Crown~
+K:99:0x87:0x9D
+
+# & Jewel-Encrusted Crown~
+K:100:0x87:0x9E
+
+# & Robe~
+K:101:0x89:0x8C
+
+# & Filthy Rag~
+K:102:0x89:0x8B
+
+# Soft Leather Armour~
+K:103:0x89:0x8D
+
+# Soft Studded Leather~
+K:104:0x89:0x8E
+
+# Hard Leather Armour~
+K:105:0x89:0x8F
+
+# Hard Studded Leather~
+K:106:0x89:0x90
+
+# Leather Scale Mail~
+K:107:0x89:0x91
+
+# Metal Scale Mail~
+K:108:0x89:0x92
+
+# Chain Mail~
+K:109:0x89:0x94
+
+# Rusty Chain Mail~
+K:110:0x89:0x93
+
+# Augmented Chain Mail~
+K:111:0x89:0x96
+
+# Bar Chain Mail~
+K:112:0x89:0x97
+
+# Metal Brigandine Armour~
+K:113:0x89:0x98
+
+# Partial Plate Armour~
+K:114:0x89:0x99
+
+# Metal Lamellar Armour~
+K:115:0x89:0x9A
+
+# Full Plate Armour~
+K:116:0x89:0x9B
+
+# Ribbed Plate Armour~
+K:117:0x89:0x9C
+
+# Galvorn Plate Mail~
+K:118:0x89:0x9F
+
+# Mithril Plate Mail~
+K:119:0x89:0x9E
+
+# Mithril Chain Mail~
+K:120:0x89:0x9D
+
+# Double Chain Mail~
+K:121:0x89:0x95
+
+# & Shield~ of Deflection
+K:122:0x88:0x98
+
+# & Cloak~
+K:123:0x89:0x88
+
+# & Shadow Cloak~
+K:124:0x89:0x89
+
+# & Set~ of Leather Gloves
+K:125:0x88:0x91
+
+# & Set~ of Gauntlets
+K:126:0x88:0x92
+
+# & Set~ of Cesti
+K:127:0x88:0x93
+
+# & Small Leather Shield~
+K:128:0x88:0x94
+
+# & Large Leather Shield~
+K:129:0x88:0x95
+
+# & Small Metal Shield~
+K:130:0x88:0x96
+
+# & Large Metal Shield~
+K:131:0x88:0x97
+
+# Strength
+K:132:0x84:0x81
+
+# Dexterity
+K:133:0x84:0x83
+
+# Constitution
+K:134:0x84:0x83
+
+# Intelligence
+K:135:0x84:0x83
+
+# Speed
+K:136:0x84:0x83
+
+# Searching
+K:137:0x84:0x83
+
+# Teleportation
+K:138:0x84:0x83
+
+# Slow Digestion
+K:139:0x84:0x83
+
+# Fire Resistance
+K:140:0x84:0x83
+
+# Cold Resistance
+K:141:0x84:0x83
+
+# Levitation
+K:142:0x84:0x83
+
+# Poison Resistance
+K:143:0x84:0x83
+
+# Free Action
+K:144:0x84:0x83
+
+# Weakness
+K:145:0x84:0x83
+
+# Flames
+K:146:0x84:0x83
+
+# Acid
+K:147:0x84:0x83
+
+# Ice
+K:148:0x84:0x83
+
+# Woe
+K:149:0x84:0x83
+
+# Stupidity
+K:150:0x84:0x83
+
+# Damage
+K:151:0x84:0x83
+
+# Accuracy
+K:152:0x84:0x83
+
+# Protection
+K:153:0x84:0x83
+
+# Aggravate Monster
+K:154:0x84:0x83
+
+# See Invisible
+K:155:0x84:0x83
+
+# Sustain Strength
+K:156:0x84:0x83
+
+# Sustain Intelligence
+K:157:0x84:0x83
+
+# Sustain Wisdom
+K:158:0x84:0x83
+
+# Sustain Constitution
+K:159:0x84:0x83
+
+# Sustain Dexterity
+K:160:0x84:0x83
+
+# Sustain Charisma
+K:161:0x84:0x83
+
+# Slaying
+K:162:0x84:0x83
+
+# Brilliance
+K:163:0x87:0x83
+
+# Charisma
+K:164:0x87:0x83
+
+# Searching
+K:165:0x87:0x83
+
+# Teleportation
+K:166:0x87:0x83
+
+# Slow Digestion
+K:167:0x87:0x83
+
+# Acid Resistance
+K:168:0x87:0x83
+
+# Protection from Evil
+K:169:0x87:0x83
+
+# Double Ring Mail~
+K:170:0x89:0x9B
+
+# the Magi
+K:171:0x87:0x83
+
+# Doom
+K:172:0x87:0x83
+
+# Enchant Weapon To-Hit
+K:173:0x83:0x9C
+
+# Enchant Weapon To-Dam
+K:174:0x83:0x9C
+
+# Enchant Armor
+K:175:0x83:0x9C
+
+# Identify
+K:176:0x83:0x9C
+
+# *Identify*
+K:177:0x83:0x9C
+
+# Rumour
+K:178:0x83:0x9C
+
+# Chaos
+K:179:0x83:0x9C
+
+# Remove Curse
+K:180:0x83:0x9C
+
+# Light
+K:181:0x83:0x9C
+
+# Fire
+K:182:0x83:0x9C
+
+# Ice
+K:183:0x83:0x9C
+
+# Summon Monsters
+K:184:0x83:0x9C
+
+# Phase Door
+K:185:0x83:0x9C
+
+# Teleportation
+K:186:0x83:0x9C
+
+# Teleport Level
+K:187:0x83:0x9C
+
+# Monster Confusion
+K:188:0x83:0x9C
+
+# Magic Mapping
+K:189:0x83:0x9C
+
+# Rune of Protection
+K:190:0x83:0x9C
+
+# *Remove Curse*
+K:191:0x83:0x9C
+
+# Treasure Detection
+K:192:0x83:0x9C
+
+# Object Detection
+K:193:0x83:0x9C
+
+# Trap Detection
+K:194:0x83:0x9C
+
+# & Sheaf Arrow~
+K:195:0x8C:0x81
+
+# & Mithril Shot~
+K:196:0x8C:0x85
+
+# Door/Stair Location
+K:197:0x83:0x9C
+
+# Acquirement
+K:198:0x83:0x9C
+
+# *Acquirement*
+K:199:0x83:0x9C
+
+# Mass Genocide
+K:200:0x83:0x9C
+
+# Detect Invisible
+K:201:0x83:0x9C
+
+# Aggravation
+K:202:0x83:0x9C
+
+# Trap Creation
+K:203:0x83:0x9C
+
+# Trap/Door Destruction
+K:204:0x83:0x9C
+
+# Artifact Creation
+K:205:0x83:0x9C
+
+# Recharging
+K:206:0x83:0x9C
+
+# Genocide
+K:207:0x83:0x9C
+
+# Darkness
+K:208:0x83:0x9C
+
+# Protection from Evil
+K:209:0x83:0x9C
+
+# Satisfy Hunger
+K:210:0x83:0x9C
+
+# Dispel Undead
+K:211:0x83:0x9C
+
+# *Enchant Weapon*
+K:212:0x83:0x9C
+
+# Curse Weapon
+K:213:0x83:0x9C
+
+# *Enchant Armour*
+K:214:0x83:0x9C
+
+# Curse Armour
+K:215:0x83:0x9C
+
+# Summon Undead
+K:216:0x83:0x9C
+
+# Blessing
+K:217:0x83:0x9C
+
+# Holy Chant
+K:218:0x83:0x9C
+
+# Holy Prayer
+K:219:0x83:0x9C
+
+# Word of Recall
+K:220:0x83:0x9C
+
+# *Destruction*
+K:221:0x83:0x9C
+
+# Slime Mold Juice
+K:222:0x85:0x85
+
+# Apple Juice
+K:223:0x85:0x85
+
+# Water
+K:224:0x85:0x85
+
+# Strength
+K:225:0x85:0x85
+
+# Weakness
+K:226:0x85:0x85
+
+# Restore Strength
+K:227:0x85:0x85
+
+# Intelligence
+K:228:0x85:0x85
+
+# Stupidity
+K:229:0x85:0x85
+
+# Restore Intelligence
+K:230:0x85:0x85
+
+# Wisdom
+K:231:0x85:0x85
+
+# Naivety
+K:232:0x85:0x85
+
+# Restore Wisdom
+K:233:0x85:0x85
+
+# Charisma
+K:234:0x85:0x85
+
+# Ugliness
+K:235:0x85:0x85
+
+# Restore Charisma
+K:236:0x85:0x85
+
+# Curing
+K:237:0x85:0x85
+
+# Invulnerability
+K:238:0x85:0x85
+
+# New Life
+K:239:0x85:0x85
+
+# Cure Serious Wounds
+K:240:0x85:0x85
+
+# Cure Critical Wounds
+K:241:0x85:0x85
+
+# Healing
+K:242:0x85:0x85
+
+# Constitution
+K:243:0x85:0x85
+
+# Experience
+K:244:0x85:0x85
+
+# Sleep
+K:245:0x85:0x85
+
+# Blindness
+K:246:0x85:0x85
+
+# Booze
+K:247:0x85:0x85
+
+# Poison
+K:248:0x85:0x85
+
+# Speed
+K:249:0x85:0x85
+
+# Slowness
+K:250:0x85:0x85
+
+# Dexterity
+K:251:0x85:0x85
+
+# Restore Dexterity
+K:252:0x85:0x85
+
+# Restore Constitution
+K:253:0x85:0x85
+
+# Lose Memories
+K:254:0x85:0x85
+
+# Salt Water
+K:255:0x85:0x85
+
+# Enlightenment
+K:256:0x85:0x85
+
+# Heroism
+K:257:0x85:0x85
+
+# Berserk Strength
+K:258:0x85:0x85
+
+# Boldness
+K:259:0x85:0x85
+
+# Restore Life Levels
+K:260:0x85:0x85
+
+# Resist Heat
+K:261:0x85:0x85
+
+# Resist Cold
+K:262:0x85:0x85
+
+# Detect Invisible
+K:263:0x85:0x85
+
+# Slow Poison
+K:264:0x85:0x85
+
+# Neutralise Poison
+K:265:0x85:0x85
+
+# Restore Mana
+K:266:0x85:0x85
+
+# Infra-vision
+K:267:0x85:0x85
+
+# Resistance
+K:268:0x85:0x85
+
+# Spell
+K:269:0x86:0x93
+
+# Manathrust
+K:270:0x86:0x93
+
+# Fireflash
+K:271:0x86:0x93
+
+# Firewall
+K:272:0x86:0x93
+
+# Tidal Wave
+K:273:0x86:0x93
+
+# Ice Storm
+K:274:0x86:0x93
+
+# Noxious Cloud
+K:275:0x86:0x93
+
+# Poison Blood
+K:276:0x86:0x93
+
+# Thunderstorm
+K:277:0x86:0x93
+
+# Dig
+K:278:0x86:0x93
+
+# Stone Prison
+K:279:0x86:0x93
+
+# Strike
+K:280:0x86:0x93
+
+# Teleport Away
+K:281:0x86:0x93
+
+# Summon Animal
+K:282:0x86:0x93
+
+# Magelock
+K:283:0x86:0x93
+
+# Slow Monster
+K:284:0x86:0x93
+
+# Essence of Speed
+K:285:0x86:0x93
+
+# Banishment
+K:286:0x86:0x93
+
+# Disperse Magic
+K:287:0x86:0x93
+
+# Charm
+K:288:0x86:0x93
+
+# Confuse
+K:289:0x86:0x93
+
+# Demon Blade
+K:290:0x86:0x93
+
+# Heal Monster
+K:291:0x86:0x93
+
+# Haste Monster
+K:292:0x86:0x93
+
+# & Flight Arrow~
+K:293:0x8C:0x81
+
+# & Boulder~
+K:295:0xC6:0x9F
+
+# & Flame~ Imperishable
+K:296:0xBE:0x9F
+
+# & Necromantic Teeth~
+K:297:0xC5:0xA5
+
+# & Golden Horn~ of the Eagles
+K:298:0x86:0x93
+
+# Spell
+K:300:0x87:0x92
+
+# Nothing
+K:301:0x87:0x92
+
+# Globe of Light
+K:302:0x87:0x92
+
+# Fiery Shield
+K:303:0x87:0x92
+
+# Remove Curses
+K:304:0x87:0x92
+
+# Wings of Winds
+K:305:0x87:0x92
+
+# Shake
+K:306:0x87:0x92
+
+# Disarm
+K:307:0x87:0x92
+
+# Teleportation
+K:308:0x87:0x92
+
+# Probability Travel
+K:309:0x87:0x92
+
+# Recovery
+K:310:0x87:0x92
+
+# Healing
+K:311:0x87:0x92
+
+# Vision
+K:312:0x87:0x92
+
+# Identify
+K:313:0x87:0x92
+
+# Sense Hidden
+K:314:0x87:0x92
+
+# Reveal Ways
+K:315:0x87:0x92
+
+# Sense Monsters
+K:316:0x87:0x92
+
+# Genocide
+K:317:0x87:0x92
+
+# Summon
+K:318:0x87:0x92
+
+# Sterilization
+K:319:0x87:0x92
+
+# Wish
+K:320:0x87:0x92
+
+# Mana
+K:321:0x87:0x92
+
+# & Tome~ of Magical Energy
+K:330:0x90:0xA0
+
+# & Tome~ of the Eternal Flame
+K:331:0x90:0xA1
+
+# & Tome~ of the Blowing Wind
+K:332:0x90:0xA2
+
+# & Tome~ of the Impenetrable Earth
+K:333:0x90:0xA3
+
+# & Tome~ of the Everrunning Wave
+K:334:0x90:0xA4
+
+# & Tome~ of Translocation
+K:335:0x90:0xA5
+
+# & Tome~ of the Tree
+K:336:0x90:0xA6
+
+# & Tome~ of Knowledge
+K:337:0x90:0xA7
+
+# & Small wooden chest~
+K:338:0x84:0x99
+
+# & Large wooden chest~
+K:339:0x84:0x9A
+
+# & Small iron chest~
+K:340:0x84:0x9B
+
+# & Large iron chest~
+K:341:0x84:0x9C
+
+# & Small steel chest~
+K:342:0x84:0x9D
+
+# & Large steel chest~
+K:343:0x84:0x9E
+
+# & Ruined chest~
+K:344:0x84:0x9F
+
+# & Iron Spike~
+K:345:0x8E:0x89
+
+# & Wooden Torch~
+K:346:0x8E:0x8B
+
+# & Brass Lantern~
+K:347:0x8E:0x8A
+
+# & Flask~ of oil
+K:348:0x8E:0x88
+
+# & Empty Bottle~
+K:349:0x8E:0x87
+
+# Havoc
+K:350:0x86:0x83
+
+# Door/Stair Location
+K:351:0x86:0x83
+
+# Trap Location
+K:352:0x86:0x83
+
+# Probing
+K:353:0x86:0x83
+
+# Recall
+K:354:0x86:0x83
+
+# Illumination
+K:355:0x86:0x83
+
+# Light
+K:356:0x86:0x83
+
+# Lightning Bolts
+K:357:0x86:0x83
+
+# Frost Bolts
+K:358:0x86:0x83
+
+# Fire Bolts
+K:359:0x86:0x83
+
+# Polymorph
+K:360:0x86:0x83
+
+# Slow Monster
+K:361:0x86:0x83
+
+# Sleep Monster
+K:362:0x86:0x83
+
+# Drain Life
+K:363:0x86:0x83
+
+# Teleport Other
+K:364:0x86:0x83
+
+# Disarming
+K:365:0x86:0x83
+
+# Lightning Balls
+K:366:0x86:0x83
+
+# Cold Balls
+K:367:0x86:0x83
+
+# Fire Balls
+K:368:0x86:0x83
+
+# Acid Balls
+K:369:0x86:0x83
+
+# Acid Bolts
+K:370:0x86:0x83
+
+# Enlightenment
+K:371:0x86:0x83
+
+# Perception
+K:372:0x86:0x83
+
+# Curing
+K:373:0x86:0x83
+
+# Healing
+K:374:0x86:0x83
+
+# Detection
+K:375:0x86:0x83
+
+# Restoration
+K:376:0x86:0x83
+
+# Speed
+K:377:0x86:0x83
+
+# Spell
+K:378:0x84:0x83
+
+# Spell
+K:379:0x87:0x80
+
+# & Broken Skull~
+K:391:0x8E:0x94
+
+# & Broken Bone~
+K:392:0x8E:0x95
+
+# & Canine Skeleton~
+K:393:0x8E:0x9A
+
+# & Rodent Skeleton~
+K:394:0x8E:0x9B
+
+# & Human Skeleton~
+K:395:0x8E:0x96
+
+# & Dwarf Skeleton~
+K:396:0x8E:0x98
+
+# & Elf Skeleton~
+K:397:0x8E:0x97
+
+# & Gnome Skeleton~
+K:398:0x8E:0x99
+
+# & Great Hammer~
+K:399:0xB6:0x8A
+
+# Black Dragon Scale Mail~
+K:400:0x8A:0x82
+
+# Blue Dragon Scale Mail~
+K:401:0x8A:0x80
+
+# White Dragon Scale Mail~
+K:402:0x8A:0x81
+
+# Red Dragon Scale Mail~
+K:403:0x8A:0x83
+
+# Green Dragon Scale Mail~
+K:404:0x8A:0x84
+
+# Multi-Hued Dragon Scale Mail~
+K:405:0x8A:0x8B
+
+# Pseudo Dragon Scale Mail~
+K:406:0x8A:0x87
+
+# Law Dragon Scale Mail~
+K:407:0x8A:0x89
+
+# Bronze Dragon Scale Mail~
+K:408:0x8A:0x85
+
+# Gold Dragon Scale Mail~
+K:409:0x8A:0x86
+
+# Chaos Dragon Scale Mail~
+K:410:0x8A:0x88
+
+# Balance Dragon Scale Mail~
+K:411:0x8A:0x8A
+
+# Power Dragon Scale Mail~
+K:412:0x8A:0x8C
+
+# & Dragon Helm~
+K:413:0x88:0x82
+
+# & Dragon Shield~
+K:414:0x88:0x9C
+
+# Death
+K:415:0x85:0x85
+
+# Ruination
+K:416:0x85:0x85
+
+# Detonations
+K:417:0x85:0x85
+
+# Augmentation
+K:418:0x85:0x85
+
+# *Healing*
+K:419:0x85:0x85
+
+# Life
+K:420:0x85:0x85
+
+# Self Knowledge
+K:421:0x85:0x85
+
+# *Enlightenment*
+K:422:0x85:0x85
+
+# Fear Resistance
+K:425:0x84:0x83
+
+# Light and Darkness Resistance
+K:426:0x84:0x83
+
+# Nether Resistance
+K:427:0x84:0x83
+
+# Nexus Resistance
+K:428:0x84:0x83
+
+# Sound Resistance
+K:429:0x84:0x83
+
+# Confusion Resistance
+K:430:0x84:0x83
+
+# Shard Resistance
+K:431:0x84:0x83
+
+# Disenchantment Resistance
+K:432:0x84:0x83
+
+# Chaos Resistance
+K:433:0x84:0x83
+
+# Blindness Resistance
+K:434:0x84:0x83
+
+# Lordly Protection
+K:435:0x84:0x83
+
+# Extra Attacks
+K:436:0x84:0x83
+
+# Cure Light Wounds
+K:437:0x85:0x85
+
+# Clumsiness
+K:438:0x85:0x85
+
+# Sickliness
+K:439:0x85:0x85
+
+# Map of Bree
+K:440:0xC4:0x80
+
+# Map of Gondolin
+K:441:0xC4:0x80
+
+# Map of Lothlorien
+K:442:0xC4:0x80
+
+# Map of Minas Anor
+K:443:0xC4:0x80
+
+# & Silver Arrow~
+K:465:0xC6:0x81
+
+# & Silver Bolt~
+K:466:0xC6:0x82
+
+# Lightning Resistance
+K:467:0x87:0x80
+
+# Wisdom
+K:468:0x87:0x80
+
+# Regeneration
+K:469:0x87:0x80
+
+# Infravision
+K:470:0x87:0x80
+
+# Devotion
+K:471:0x87:0x80
+
+# Weaponmastery
+K:472:0x87:0x80
+
+# Trickery
+K:473:0x87:0x80
+
+# Telepathy
+K:474:0x87:0x80
+
+# Sustenance
+K:475:0x87:0x80
+
+# & Palantir~
+K:476:0xC6:0x87
+
+# & Elfstone~
+K:477:0xC6:0x83
+
+# & Jewel~
+K:478:0xC6:0x84
+
+# & Ring~
+K:479:0xC6:0x85
+
+# copper
+K:480:0x83:0x91
+
+# copper
+K:481:0x83:0x91
+
+# copper
+K:482:0x83:0x91
+
+# silver
+K:483:0x83:0x92
+
+# silver
+K:484:0x83:0x92
+
+# silver
+K:485:0x83:0x92
+
+# garnets
+K:486:0x83:0x96
+
+# garnets
+K:487:0x83:0x96
+
+# gold
+K:488:0x83:0x93
+
+# gold
+K:489:0x83:0x93
+
+# gold
+K:490:0x83:0x93
+
+# opals
+K:491:0x83:0x97
+
+# sapphires
+K:492:0x83:0x98
+
+# rubies
+K:493:0x83:0x99
+
+# diamonds
+K:494:0x83:0x9A
+
+# emeralds
+K:495:0x83:0x9B
+
+# mithril
+K:496:0x83:0x94
+
+# adamantite
+K:497:0x83:0x95
+
+# & Mighty Hammer~
+K:498:0xB6:0x8A
+
+# & Massive Iron Crown~
+K:499:0x87:0x9C
+
+# & Phial~
+K:500:0x8E:0x9D
+
+# & Star~
+K:501:0x8E:0x9E
+
+# & Arkenstone~
+K:502:0x8E:0x9F
+
+# & Amulet~
+K:503:0x84:0x96
+
+# & Amulet~
+K:504:0x84:0x97
+
+# & Necklace~
+K:505:0x84:0x98
+
+# & Ring~
+K:506:0x84:0x8F
+
+# & Ring~
+K:507:0x84:0x83
+
+# & Ring~
+K:508:0x84:0x92
+
+# & Ring~
+K:509:0x84:0x93
+
+# & Ring~
+K:510:0x84:0x94
+
+# & Ring~
+K:511:0x84:0x95
+
+# Reflection
+K:520:0x87:0x83
+
+# Anti-Magic
+K:521:0x87:0x83
+
+# Anti-Teleportation
+K:522:0x87:0x83
+
+# Resistance
+K:523:0x87:0x83
+
+# & Zweihander~
+K:524:0xB6:0x8C
+
+# & Dwarven Lantern~
+K:525:0xC5:0x94
+
+# Splint Mail~
+K:526:0x89:0x9C
+
+# & Everburning Torch~
+K:527:0xC5:0x95
+
+# & Trifurcate Spear~
+K:528:0xB6:0x85
+
+# & Three-Piece Rod~
+K:529:0xB6:0x80
+
+# & Feanorian Lamp~
+K:530:0xC5:0x96
+
+# & Fur Cloak~
+K:531:0x89:0x89
+
+# Water Curing
+K:532:0x85:0x85
+
+# & Hatchet~
+K:533:0xB6:0x8F
+
+# Mumak Hide Armour~
+K:535:0x89:0x98
+
+# & Leather Jerkin~
+K:536:0x89:0x8F
+
+# & Sickle~
+K:537:0xB6:0x90
+
+# & Club~
+K:542:0xB6:0x92
+
+# & Broad Spear~
+K:543:0xB6:0x84
+
+# & Khopesh~
+K:544:0xB6:0x94
+
+# & Flamberge~
+K:545:0xB6:0x83
+
+# & Claymore~
+K:546:0xB6:0x8D
+
+# & Espadon~
+K:547:0xB6:0x8E
+
+# & Great Scimitar~
+K:548:0xB6:0x8B
+
+# Arrow
+K:549:0x8E:0xA0
+
+# Bolt
+K:550:0x8E:0xA1
+
+# & Fauchard~
+K:551:0xB6:0x95
+
+# & Guisarme~
+K:552:0xB6:0x96
+
+# & Heavy Lance~
+K:553:0xB6:0x82
+
+# & Bardiche~
+K:554:0xB6:0x99
+
+# Catapult
+K:555:0x8E:0xA2
+
+# Ring Mail~
+K:556:0x89:0x9C
+
+# Cord Armour~
+K:557:0x89:0x90
+
+# Paper Armour~
+K:558:0x8A:0x81
+
+# Padded Armour~
+K:559:0x89:0x91
+
+# Fumes
+K:560:0x8E:0xA3
+
+# Golden Ring Mail~
+K:561:0xC5:0xB4
+
+# Magic
+K:562:0x8E:0xA4
+
+# Device
+K:563:0x8E:0xA5
+
+# Nothing
+K:569:0x86:0x83
+
+# & Blood~ of Life
+K:573:0x85:0x85
+
+# & Mage Staff~
+K:577:0xB8:0x80
+
+# Lightning
+K:578:0x84:0x80
+
+# & Ring~
+K:582:0x84:0x85
+
+# Invisibility
+K:583:0x85:0x85
+
+# Corruption
+K:585:0x85:0x85
+
+# Invisibility
+K:586:0x84:0x80
+
+# Deep Thoughts
+K:588:0x83:0x9C
+
+# More Deep Thoughts
+K:589:0x83:0x9D
+
+# Compendium of Deep Thoughts
+K:590:0x83:0x9E
+
+# Artifact Lore Vol. I
+K:591:0x83:0x9C
+
+# Artifact Lore Vol. II
+K:592:0x83:0x9D
+
+# Artifact Lore Vol. III
+K:593:0x83:0x9F
+
+# Monstrous Compendium 1
+K:594:0x83:0x9F
+
+# Monstrous Compendium 2
+K:595:0x83:0x9E
+
+# Monstrous Compendium 3
+K:596:0x83:0x9D
+
+# Monstrous Compendium 4
+K:597:0x83:0x9C
+
+# Monstrous Compendium 5
+K:598:0x83:0x9F
+
+# Monstrous Compendium 6
+K:599:0x83:0x9E
+
+# Monstrous Compendium 7
+K:600:0x83:0x9D
+
+# Monstrous Compendium 8
+K:601:0x83:0x9C
+
+# Monstrous Compendium 9
+K:602:0x83:0x9D
+
+# Monstrous Compendium 10
+K:603:0x83:0x9E
+
+# Monstrous Compendium 11
+K:604:0x83:0x9F
+
+# & Morphic Oil~ of #
+K:605:0x85:0x85
+
+# Artifact Lore Vol. IV
+K:607:0x83:0x9C
+
+# Artifact Lore Vol. V
+K:608:0x83:0x9D
+
+# Artifact Lore Vol. VI
+K:609:0x83:0x9E
+
+# Artifact Lore Vol. VII
+K:610:0x83:0x9F
+
+# Artifact Lore Vol. VIII
+K:611:0x83:0x9C
+
+# Artifact Lore Vol. IX
+K:612:0x83:0x9D
+
+# Artifact Lore Vol. X
+K:613:0x83:0x9E
+
+# Artifact Lore Vol. XI
+K:614:0x83:0x9F
+
+# Artifact Lore Vol. IX
+K:615:0x83:0x9C
+
+# Artifact Lore Vol. X
+K:616:0x83:0x9D
+
+# Artifact Lore Vol. XI
+K:617:0x83:0x9E
+
+# & #~
+K:618:0x8F:0xA0
+
+# corpse
+K:641:0xB8:0x81
+
+# skeleton
+K:642:0x8E:0x96
+
+# head
+K:643:0x8E:0x94
+
+# skull
+K:644:0x8E:0x94
+
+# raw meat
+K:645:0x8E:0x83
+
+# & Great Eagle Down Coat~
+K:646:0x8A:0x86
+
+# & Key~
+K:647:0x8E:0x9C
+
+# & Small Wooden Boomerang~
+K:648:0xB8:0x82
+
+# & Wooden Boomerang~
+K:649:0xB8:0x83
+
+# & Small Metal Boomerang~
+K:650:0xB8:0x84
+
+# & Metal Boomerang~
+K:651:0xB8:0x85
+
+# & Anchor~
+K:652:0x8D:0x9E
+
+# & ~
+K:653:0xC5:0xB5
+
+# Summon Never-Moving Pet
+K:654:0x83:0x9D
+
+# Cure Light Insanity
+K:657:0x85:0x85
+
+# Cure Serious Insanity
+K:658:0x85:0x85
+
+# Cure Critical Insanity
+K:659:0x85:0x85
+
+# Cure Insanity
+K:660:0x85:0x85
+
+# & Phial~
+K:661:0x8E:0x9D
+
+# Junkart
+K:662:0xC5:0xB6
+
+# Craftsmanship
+K:663:0x83:0x9F
+
+# The One Ring
+K:664:0x83:0x9E
+
+# & Horn~
+K:669:0xB8:0x88
+
+# & Drum~
+K:670:0xB8:0x89
+
+# & Harp~
+K:671:0xB8:0x8A
+
+# & Palantir~
+K:675:0x8D:0x9F
+
+# Egg
+K:676:0xB7:0x8D
+
+# Reset Recall
+K:677:0x83:0x9D
+
+# Divination
+K:678:0x83:0x9D
+
+# Self
+K:679:0xB7:0x8E
+
+# Ray
+K:680:0xB7:0x8F
+
+# Sphere
+K:681:0xB7:0x90
+
+# Knowledge
+K:682:0xB7:0x94
+
+# Life
+K:683:0xB7:0x95
+
+# Fire
+K:684:0xB7:0x96
+
+# Cold
+K:685:0xB7:0x97
+
+# Lightning
+K:686:0xB7:0x98
+
+# Acid
+K:687:0xB7:0x99
+
+# Element
+K:688:0xB7:0x9A
+
+# Chaos
+K:689:0xB7:0x9B
+
+# Mind
+K:690:0xB7:0x9C
+
+# Holding
+K:691:0xB7:0x9D
+
+# Arrow
+K:692:0xB7:0x91
+
+# Power Surge
+K:693:0xB7:0x92
+
+# Armageddon
+K:694:0xB7:0x93
+
+# Gravity
+K:695:0xB7:0x9E
+
+# Undeath
+K:697:0xB6:0x9B
+
+# Protection
+K:698:0xB6:0x9C
+
+# & Ring~ of Precognition
+K:700:0x84:0x83
+
+# & Sprig~ of Athelas
+K:701:0xB8:0x8E
+
+# & Old Scroll~ of Deincarnation
+K:720:0x83:0x9F
+
+# & Dark Sword~
+K:721:0xC4:0x81
+
+# Numenorean for Beginners (I)
+K:722:0x83:0x9D
+
+# Numenorean for Beginners (II)
+K:723:0x83:0x9D
+
+# Advanced Lessons of Numenorean
+K:724:0x83:0x9D
+
+# Advanced Lessons of Sindarin
+K:725:0x83:0x9D
+
+# & Shard~ of Pottery
+K:726:0x8E:0x92
+
+# & Broken Stick~
+K:727:0x8E:0x93
+
+# & Book~ of Beginner Cantrips
+K:738:0x90:0xA0
+
+# & Book~ of Teleportation
+K:739:0x90:0xA5
+
+# & Book~ of Summoning
+K:741:0x90:0xA7
+
+# & Potion~ of Learning
+K:743:0xC1:0x82
+
+# Khuzdul - The Hidden Tongue of the Dwarves
+K:751:0x83:0x9D
+
+# Nandorin for Dummies
+K:752:0x83:0x9D
+
+# Advanced Lessons of Orcish
+K:753:0x83:0x9D
+
+# Flying
+K:755:0x84:0x88
+
+# & Tome~ of the Time
+K:756:0x90:0xA5
+
+# & Spellbook~ of #
+K:757:0x91:0xA4
+
+# & Tome~ of Meta Spells
+K:758:0x90:0xA0
+
+# & Tome~ of the Mind
+K:759:0x90:0xA7
+
+# & Holy Tome~ of Eru Iluvatar
+K:760:0x90:0xA7
+
+# & Holy Tome~ of Manwe Sulimo
+K:761:0x90:0xA2
+
+# & War Tome~ of Tulkas
+K:762:0x90:0xA5
+
+# & Unholy Tome~ of the Hellflame
+K:763:0x90:0xA1
+
+# & Corrupted Tome~ of Melkor
+K:764:0x90:0xA1
+
+# & Earth Tome~ of Aule
+K:765:0x90:0xA3
+
+# & Shining Tome~ of Varda
+K:766:0x90:0xA2
+
+# & Water Tome~ of Ulmo
+K:767:0x90:0xA4
+
+# & Forest Tome~ of Yavanna
+K:768:0x90:0xA6
+
+# Tome of#
+K:769:0x90:0xA3
+
+# & Ring~
+K:770:0x84:0x84
+
+# & Holy Tome~ of Mandos
+K:771:0x90:0xA0
+
+# & Great Rod Tip~ of Home Summoning
+K:776:0x86:0x83
+
+# & Shadow Blade~
+K:777:0xC1:0x91
+
+# & Bluesteel Blade~
+K:778:0xC1:0x92
+
+# the Serpents
+K:779:0xC4:0x88
+
+# Ring~ of Power
+K:785:0xC4:0x8E
+
+# Climbing Set~
+K:786:0xC1:0x93
+
+# Adventurer's Guide to Middle-earth
+K:787:0x83:0x9E
+
+# & Demonblade~
+K:788:0x90:0xA8
+
+# & Demonshield~
+K:789:0x90:0xA9
+
+# & Demonhorn~
+K:790:0x90:0xAA
+
+# & Wooden Rod~ of#
+K:793:0xC1:0x95
+
+# & Copper Rod~ of#
+K:794:0xC1:0x96
+
+# & Iron Rod~ of#
+K:795:0xC1:0x97
+
+# & Moonstone Rod~ of#
+K:796:0xC1:0x98
+
+# & Silver Rod~ of#
+K:797:0xC1:0x99
+
+# & Golden Rod~ of#
+K:798:0xC1:0x9B
+
+# & Mithril Rod~ of#
+K:799:0xC1:0x9C
+
+# & Tilkal Rod~ of#
+K:800:0xC1:0x9D
+
+# & Greater Ration~ of Health
+K:801:0xC4:0x87
+
+# & Crumpled Scroll~ of Mass Resurrection
+K:802:0x83:0x9E
+
+# & Cleaver~
+K:803:0xC4:0x82
+
+# & Light War Axe~
+K:804:0xC4:0x83
+
+# & Slaughter Axe~
+K:805:0xC4:0x84
+
+# & Runestone~
+K:806:0xC4:0x85
+
+# & Fortune cookie~
+K:807:0xC6:0x86
+
+# Critical Hits
+K:809:0x84:0x83
+
+# & Wand~ of Digging of Thrain
+K:810:0x86:0x93
+
+# & Gnarled Staff~ of Holy Fire of Mithrandir
+K:811:0x87:0x92
+
+# Partial Totem
+K:812:0xC6:0x9D
+
+# True Totem
+K:813:0xC6:0x9E
+
+# & Piece~ of the Relic of Eru
+K:814:0x8C:0xA2
+
+# & Piece~ of the Relic of Manwe
+K:815:0x8C:0xA3
+
+# & Piece~ of the Relic of Tulkas
+K:816:0x8C:0xA4
+
+# & Piece~ of the Relic of Melkor
+K:817:0x8C:0xA5
+
+# & Piece~ of the Relic of Yavanna
+K:818:0x8C:0xA6
+
+# & Ring~
+K:819:0x84:0x83
+
+# & Ring~
+K:820:0x84:0x83
+
+# & Ring~
+K:821:0x84:0x83
+
+# & Ring~
+K:822:0x84:0x83
+
+# & Ring~
+K:823:0x84:0x83
+
+# & Ring~
+K:824:0x84:0x83
+
+# & Piece~ of the Relic of Aule
+K:825:0x8C:0xA7
+
+# & Piece~ of the Relic of Varda
+K:826:0x8C:0xA8
+
+# & Piece~ of the Relic of Ulmo
+K:827:0x8C:0xA9
+
+# & Piece~ of the Relic of Mandos
+K:828:0x8C:0xAA
+
+# THEME
+
+# & Pinch~ of Longbottom Leaf
+K:831:0xC5:0xAA
+
+# & Ear~ of Corn
+K:832:0xC6:0xBF
+
+# & Tater~
+K:833:0xC5:0xA6
+
+# & Strawberry~
+K:834:0x93:0xA4
+
+# & Turnip~
+K:835:0xC5:0xA7
+
+# & Jar~ of Honey
+K:836:0xC5:0xA8
+
+# & Jug~ of Milk
+K:837:0xC5:0xA9
+
+# of War
+K:838:0x87:0x80
+
+# of Life
+K:839:0x87:0x80
+
+# Wizardry
+K:840:0x84:0x83
+
+# Vitality
+K:841:0x84:0x83
+
+# Clear Thought
+K:842:0x84:0x83
+
+# Clumsiness
+K:843:0x84:0x83
+
+# Sickliness
+K:844:0x84:0x83
+
+# Fortune
+K:845:0x84:0x83
+
+# Sterilise
+K:846:0x83:0x9C
+
+# Map of Middle-earth
+K:847:0xC4:0x80
+
+# Map of Edoras
+K:848:0xC4:0x80
+
+# Map of Esgaroth
+K:849:0xC4:0x80
+
+# Map of Hobbiton
+K:850:0xC4:0x80
+
+# Map of Osgiliath
+K:851:0xC4:0x80
+
+# Map of Pelargir
+K:852:0xC4:0x80
+
+# Map of Beorn's domain
+K:853:0xC4:0x80
+
+# Map of Dale
+K:854:0xC4:0x80
+
+# Map of Henneth Annun
+K:855:0xC4:0x80
+
+# Map of Helm's Deep
+K:856:0xC4:0x80
+
+# Map of Thranduil's realm
+K:857:0xC4:0x80
+
+# Map of Imladris
+K:858:0xC4:0x80
+
+# & Bearded Axe~
+K:859:0xC5:0xAD
+
+# & Double Axe~
+K:860:0xC5:0xAE
+
+# & Crusader Axe~
+K:861:0xC5:0xAF
+
+# & Reaper Axe~
+K:862:0xC5:0xB0
+
+# & Mithril Helm~
+K:863:0xC5:0xB8
+
+# & Set~ of Mithril Gauntlets
+K:864:0xC5:0xB9
+
+# & Small Mithril Shield~
+K:865:0xC5:0xBA
+
+# & Large Mithril Shield~
+K:866:0xC5:0xBB
+
+# & Map~
+K:867:0xC4:0x80
+
+# & Key~
+K:868:0x93:0xA7
+
+# & Cup~
+K:869:0xC5:0xAB
+
+# & Red Arrow~
+K:870:0xAE:0x87
+
+# & Sceptre~
+K:871:0x86:0x94
+
+# & Rod~
+K:872:0x86:0x93
+
+# & Necklace~
+K:873:0x87:0x8C
+
+# & Amulet~
+K:874:0x87:0x80
+
+# & Black Banner~
+K:875:0xC5:0xAC
+
+# & Pearl~
+K:876:0xC5:0xB1
+
+# & Silmaril~
+K:877:0xC5:0xB2
+
+# & Silmaril~
+K:878:0xC5:0xB3
+
+# & Golden Harp~
+K:879:0xC5:0xB7
+
+# Player
+R:0:0x8E/0x80
+
+# Filthy street urchin
+R:1:0xAA:0x80
+
+# Scrawny cat
+R:2:0xA7:0x82
+
+# Sparrow
+R:3:0xB4:0x9E
+
+# Chaffinch
+R:4:0xB4:0x9E
+
+# Wild rabbit
+R:5:0xB4:0x9F
+
+# Woodsman
+R:6:0xAA:0x91
+
+# Scruffy little dog
+R:7:0x9D:0x9A
+
+# Farmer Maggot
+R:8:0xAA:0x81
+
+# Blubbering idiot
+R:9:0xAA:0x82
+
+# Boil-covered wretch
+R:10:0xAA:0x83
+
+# Village idiot
+R:11:0xAA:0x84
+
+# Pitiful-looking beggar
+R:12:0xAA:0x85
+
+# Mangy-looking leper
+R:13:0xAA:0x86
+
+# Agent of the black market
+R:14:0xAA:0x87
+
+# Singing, happy drunk
+R:15:0xAA:0x88
+
+# Aimless-looking merchant
+R:16:0xAA:0x89
+
+# Mean-looking mercenary
+R:17:0xAA:0x8A
+
+# Battle-scarred veteran
+R:18:0xAA:0x8B
+
+# The Squint-eyed Southerner
+R:19:0xB0:0x80
+
+# Grey mold
+R:20:0xA8:0x9F
+
+# Large white snake
+R:21:0xA2:0x85
+
+# Grey mushroom patch
+R:22:0xB0:0x81
+
+# Newt
+R:23:0xB0:0x82
+
+# Ox
+R:24:0xC0:0xAE
+
+# Kine of Araw
+R:25:0xC0:0xAF
+
+# Sheep
+R:26:0xC0:0xB0
+
+# Giant white mouse
+R:27:0xAC:0x85
+
+# Large brown snake
+R:28:0xA2:0x84
+
+# Meara
+R:29:0xC0:0xB1
+
+# Horse
+R:30:0xC0:0xB2
+
+# White worm mass
+R:31:0xAC:0x9D
+
+# Floating eye
+R:32:0xA6:0x9B
+
+# Rock lizard
+R:33:0xA2:0x86
+
+# The Boar of Everholt
+R:34:0xC0:0xB3
+
+# Jackal
+R:35:0x9D:0x9B
+
+# Soldier ant
+R:36:0xA5:0x87
+
+# Fruit bat
+R:37:0xA5:0x8F
+
+# Insect swarm
+R:38:0xB5:0x9E
+
+# Boar
+R:39:0xC0:0xB4
+
+# Shrieker mushroom patch
+R:40:0x9D:0x86
+
+# Cow
+R:41:0xC0:0xB5
+
+# Novice warrior
+R:43:0xAA:0x8C
+
+# Novice rogue
+R:44:0xAA:0x8D
+
+# Novice priest
+R:45:0xAA:0x8E
+
+# Novice mage
+R:46:0xAA:0x8F
+
+# Yellow mushroom patch
+R:47:0x9D:0x87
+
+# White jelly
+R:48:0xA8:0x8A
+
+# Giant black ant
+R:49:0xA5:0x88
+
+# Salamander
+R:50:0xA2:0x88
+
+# White harpy
+R:51:0xA0:0x88
+
+# Deer
+R:52:0xC0:0xB6
+
+# Grip, Farmer Maggot's dog
+R:53:0x9D:0x9C
+
+# Wolf, Farmer Maggot's dog
+R:54:0x9D:0x9D
+
+# Fang, Farmer Maggot's dog
+R:55:0x9D:0x9D
+
+# Giant green frog
+R:56:0xA2:0x87
+
+# Lion
+R:57:0xC0:0xB7
+
+# Green worm mass
+R:58:0xAC:0x9E
+
+# Large yellow snake
+R:59:0xA2:0x89
+
+# Cave spider
+R:60:0xA2:0x9D
+
+# Crow
+R:61:0xB5:0x9F
+
+# Wild cat
+R:62:0xA7:0x83
+
+# Smeagol
+R:63:0xAA:0x90
+
+# Green ooze
+R:64:0xA8:0x8B
+
+# Poltergeist
+R:65:0x9F:0x99
+
+# Yellow jelly
+R:66:0xA8:0x8D
+
+# Squirrel
+R:67:0xC0:0xB8
+
+# Raven
+R:68:0xB5:0x9F
+
+# White midge
+R:69:0xA8:0x9D
+
+# Squirrel of Mirkwood
+R:70:0xC0:0xB9
+
+# Black naga
+R:71:0xA9:0x88
+
+# Spotted mushroom patch
+R:72:0x9D:0x88
+
+# Silver jelly
+R:73:0xA8:0x8C
+
+# Scruffy-looking hobbit
+R:74:0xA7:0x93
+
+# Giant white ant
+R:75:0xA5:0x89
+
+# Yellow mold
+R:76:0xA9:0x80
+
+# Ape
+R:77:0xC0:0xBA
+
+# Yellow worm mass
+R:78:0xAC:0x9F
+
+# Clear worm mass
+R:79:0xAD:0x80
+
+# Radiation eye
+R:80:0xA6:0x9C
+
+# Yellow light
+R:81:0xB8:0x93
+
+# Cave lizard
+R:82:0xA2:0x8A
+
+# Novice ranger
+R:83:0xAA:0x91
+
+# Blue jelly
+R:84:0xA8:0x8E
+
+# Creeping copper coins
+R:85:0x9D:0x80
+
+# Giant white rat
+R:86:0xAC:0x86
+
+# Snotling
+R:87:0xB9:0x89
+
+# Swordfish
+R:88:0xB6:0x9E
+
+# Blue worm mass
+R:89:0xAD:0x81
+
+# Large grey snake
+R:90:0xA2:0x8B
+
+# Corsair of Umbar
+R:91:0xC0:0xBB
+
+# Dunlending
+R:92:0xC0:0xBC
+
+# Apprentice mage
+R:93:0xAA:0x8F
+
+# Green naga
+R:94:0xA9:0x89
+
+# Giant leech
+R:95:0xB8:0x94
+
+# Barracuda
+R:96:0xB6:0x9F
+
+# Novice paladin
+R:97:0xAA:0x92
+
+# Man of Harad
+R:98:0xC0:0xBD
+
+# Blue ooze
+R:99:0xA8:0x8F
+
+# Green glutton ghost
+R:100:0x9F:0x9A
+
+# Green jelly
+R:101:0xA8:0x90
+
+# Lurtz, Uruk Captain of the White Hand
+R:102:0xA8:0x9B
+
+# Munchkin
+R:103:0xA8:0x86
+
+# Disenchanter eye
+R:104:0xA6:0x9D
+
+# Red worm mass
+R:105:0xAD:0x82
+
+# Copperhead snake
+R:106:0xA2:0x8C
+
+# Death sword
+R:107:0xB0:0x87
+
+# Purple mushroom patch
+R:108:0x9D:0x89
+
+# Apprentice priest
+R:109:0xAA:0x8E
+
+# Apprentice warrior
+R:110:0xAA:0x8C
+
+# Petty-dwarf
+R:111:0xB0:0x88
+
+# Petty-dwarf mage
+R:112:0xC0:0xBE
+
+# Brown mold
+R:113:0xA9:0x81
+
+# Giant brown bat
+R:114:0xA5:0x90
+
+# Butterfly
+R:115:0xC4:0xB3
+
+# Apprentice rogue
+R:116:0xAA:0x87
+
+# Creeping silver coins
+R:117:0x9D:0x81
+
+# Snaga
+R:118:0xA9:0x8E
+
+# Rattlesnake
+R:119:0xA2:0x8D
+
+# Giant slug
+R:120:0xB8:0x94
+
+# Giant pink frog
+R:121:0xB8:0x95
+
+# Dark elf
+R:122:0x92:0x94
+
+# Moth
+R:123:0xC4:0xB4
+
+# Crypt creep
+R:124:0xB0:0x8A
+
+# Rotting corpse
+R:125:0xB0:0x8B
+
+# Cave orc
+R:126:0xA9:0x8F
+
+# Wood spider
+R:127:0xA2:0x9E
+
+# Hurog
+R:128:0xA0:0x91
+
+# Bloodshot eye
+R:129:0xA6:0x9E
+
+# Red naga
+R:130:0xA9:0x8A
+
+# Red jelly
+R:131:0xA8:0x91
+
+# Nightingale
+R:132:0xC4:0xAD
+
+# Lost soul
+R:133:0x9F:0x9B
+
+# Night lizard
+R:134:0xA2:0x8F
+
+# Gorcrow
+R:135:0xC4:0xB1
+
+# Skeleton orc
+R:136:0xAC:0x8A
+
+# Grima the Wormtongue, Agent of Saruman
+R:137:0xAA:0x98
+
+# Robin Hood, the Outlaw
+R:138:0xB0:0x8C
+
+# Gull
+R:139:0xC4:0xAE
+
+# Lagduf, the Snaga
+R:140:0xA9:0x90
+
+# Kirinki
+R:141:0xC4:0xAF
+
+# Apprentice ranger
+R:142:0xAA:0x91
+
+# Giant salamander
+R:143:0xA2:0x90
+
+# Space monster
+R:144:0xB0:0x8D
+
+# Swan
+R:145:0xC0:0xBF
+
+# Green mold
+R:146:0xA9:0x82
+
+# Apprentice paladin
+R:147:0xAA:0x92
+
+# Caborrog
+R:148:0xA0:0x92
+
+# Hill orc
+R:149:0xA9:0x91
+
+# Bandit
+R:150:0xAA:0x9B
+
+# Hunting hawk
+R:151:0xB0:0x8E
+
+# Phantom warrior
+R:152:0xB0:0x8F
+
+# Thrush
+R:153:0xC4:0xB0
+
+# Yeti
+R:154:0xA4:0x91
+
+# Fox
+R:155:0xC4:0xAC
+
+# Giant grey rat
+R:156:0xAC:0x87
+
+# Black harpy
+R:157:0xA0:0x89
+
+# Fly of Mordor
+R:158:0xC4:0xB5
+
+# Limlug
+R:159:0xBF:0xA0
+
+# Cave bear
+R:160:0xC4:0x8F
+
+# Rock mole
+R:161:0xBA:0x82
+
+# Mindcrafter
+R:162:0xAA:0x93
+
+# Hatchling blue dragon
+R:163:0xA5:0x9D
+
+# Hatchling white dragon
+R:164:0xA5:0x9E
+
+# Hatchling green dragon
+R:165:0xA5:0x9F
+
+# Hatchling black dragon
+R:166:0xA6:0x80
+
+# Hatchling red dragon
+R:167:0xA6:0x81
+
+# Giant red ant
+R:168:0xA5:0x8D
+
+# Brodda, the Easterling
+R:169:0xAA:0x9C
+
+# Radbug, the Goblin
+R:170:0xBF:0xA1
+
+# King cobra
+R:171:0xA2:0x91
+
+# Eagle
+R:172:0xB4:0x9E
+
+# War bear
+R:173:0xB0:0x91
+
+# Killer bee
+R:174:0xB0:0x92
+
+# Giant spider
+R:175:0xA2:0x9F
+
+# Giant white tick
+R:176:0xA8:0x9D
+
+# The Lucky Hobbit
+R:177:0xBF:0xA2
+
+# Dark elven mage
+R:178:0xA7:0x96
+
+# Dark dwarven warrior
+R:179:0xBF:0xA3
+
+# Dark dwarven smith
+R:180:0xBF:0xA4
+
+# Dark dwarven lord
+R:181:0xBF:0xA5
+
+# Dark dwarven priest
+R:182:0xBF:0xA6
+
+# Dark elven warrior
+R:183:0xBF:0xA6
+
+# Clear mushroom patch
+R:184:0xB8:0x96
+
+# Quiver slot
+R:185:0xB0:0x93
+
+# Grishnakh, the Hill Orc
+R:186:0xA9:0x93
+
+# Giant tan bat
+R:187:0xC4:0x90
+
+# Owlbear
+R:188:0xBA:0x87
+
+# Clear mewlip
+R:189:0xBF:0xA7
+
+# Hairy mold
+R:190:0xA9:0x83
+
+# Grizzly bear
+R:191:0xBA:0x88
+
+# Disenchanter mold
+R:192:0xA9:0x84
+
+# Pseudo-dragon
+R:193:0xA6:0x82
+
+# Limrog
+R:194:0xA0:0x93
+
+# Creeping gold coins
+R:195:0x9D:0x82
+
+# Wolf
+R:196:0x9D:0x9E
+
+# Giant fruit fly
+R:197:0x9F:0x91
+
+# Panther
+R:198:0xA7:0x84
+
+# Brigand
+R:199:0xB0:0x94
+
+# Gray mewlip
+R:200:0xBF:0xA8
+
+# Orange mewlip
+R:201:0xBF:0xA9
+
+# Undead mass
+R:202:0xB0:0x97
+
+# Bloodshot mewlip
+R:203:0xBF:0xAA
+
+# Hatchling multi-hued dragon
+R:204:0xA6:0x83
+
+# Green mewlip
+R:205:0xBF:0xAB
+
+# Old Man Willow
+R:206:0xBA:0x89
+
+# Blue mewlip
+R:207:0xBF:0xAC
+
+# Zombified orc
+R:208:0xAC:0x8C
+
+# Hippogryph
+R:209:0xA0:0x8A
+
+# Black mamba
+R:210:0xA2:0x92
+
+# White wolf
+R:211:0x9D:0x9F
+
+# Grape jelly
+R:212:0xA8:0x92
+
+# Nether worm mass
+R:213:0xAD:0x83
+
+# Brown mewlip
+R:214:0xBF:0xAD
+
+# Golfimbul, the Hill Orc Chief
+R:215:0xA9:0x94
+
+# Swordsman
+R:216:0x97:0x81
+
+# Stone mewlip
+R:217:0xBF:0xAE
+
+# Hatchling bronze dragon
+R:218:0xA6:0x82
+
+# Hatchling gold dragon
+R:219:0xA6:0x82
+
+# Evil eye
+R:220:0xC4:0x91
+
+# Yellow mewlip
+R:221:0xBF:0xAF
+
+# Pink mewlip
+R:222:0xBF:0xB0
+
+# Tree mewlip
+R:223:0xBF:0xB1
+
+# Air mewlip
+R:224:0xBF:0xB2
+
+# Priest
+R:225:0xAA:0x9E
+
+# Dark elven priest
+R:226:0xA7:0x99
+
+# Air spirit
+R:227:0x9E:0x9F
+
+# Skeleton human
+R:228:0xAC:0x8B
+
+# Zombified human
+R:229:0xAD:0x8E
+
+# Tiger
+R:230:0xA7:0x85
+
+# Moaning spirit
+R:231:0x9F:0x9C
+
+# Plague mewlip
+R:232:0xBF:0xB3
+
+# Spotted jelly
+R:233:0xA8:0x93
+
+# Drider
+R:234:0xA3:0x80
+
+# Mongbat
+R:235:0xB0:0x9C
+
+# Killer brown beetle
+R:236:0xA0:0x9B
+
+# Death mewlip
+R:237:0xBF:0xB4
+
+# Ogre
+R:238:0xA1:0x8B
+
+# Creeping mithril coins
+R:239:0x9D:0x83
+
+# Illusionist
+R:240:0xAB:0x80
+
+# Druid
+R:241:0xAB:0x81
+
+# Fuinur, Lord of the Haradrim
+R:242:0xBF:0xB5
+
+# Cloaker
+R:243:0x89:0x88
+
+# Black orc
+R:244:0xA9:0x95
+
+# Ochre jelly
+R:245:0xA8:0x94
+
+# Software bug
+R:246:0xB0:0x9D
+
+# Lurker
+R:247:0x80:0x81
+
+# Tangleweed
+R:248:0xC4:0x92
+
+# Glorfindel of Rivendell
+R:249:0xBF:0xB6
+
+# Giant white dragonfly
+R:250:0x9F:0x93
+
+# Snaga sapper
+R:251:0xB9:0x8C
+
+# Finrod Felagund
+R:252:0xBF:0xB7
+
+# Gibbering mouther
+R:253:0xB0:0x9E
+
+# Maedhros the Tall
+R:254:0xBF:0xB8
+
+# Hill giant
+R:255:0xA1:0x91
+
+# Flesh golem
+R:256:0xA7:0x89
+
+# Warg
+R:257:0x9E:0x80
+
+# Cheerful leprawn
+R:258:0xB1:0x80
+
+# Giant flea
+R:259:0x9F:0x92
+
+# Ufthak of Cirith Ungol
+R:260:0xBA:0x8C
+
+# Clay golem
+R:261:0xB8:0x9D
+
+# Black ogre
+R:262:0xA1:0x8C
+
+# Maglor the Mighty Singer
+R:263:0xBF:0xB9
+
+# Half-orc
+R:264:0xBA:0x8D
+
+# Dark naga
+R:265:0xB8:0x9E
+
+# Poison ivy
+R:266:0xC4:0x93
+
+# Magic mushroom patch
+R:267:0x9D:0x8B
+
+# Celegorm the Fair
+R:268:0xBF:0xBA
+
+# Guardian naga
+R:269:0xA9:0x8B
+
+# Wererat
+R:270:0xBA:0x8E
+
+# Light hound
+R:271:0xA4:0x93
+
+# Dark hound
+R:272:0xA4:0x94
+
+# Flying skull
+R:273:0xB1:0x81
+
+# Caranthir the Dark
+R:274:0xBF:0xBB
+
+# Giant tarantula
+R:275:0xA3:0x81
+
+# Curufin the Crafty
+R:276:0xBF:0xBC
+
+# Mirkwood spider
+R:277:0xA3:0x82
+
+# Frost giant
+R:278:0xA1:0x92
+
+# Griffon
+R:279:0xA0:0x8B
+
+# Aewrog
+R:280:0xA0:0x94
+
+# Gnome mage
+R:281:0xA7:0x98
+
+# Clear hound
+R:282:0xA4:0x95
+
+# Umber hulk
+R:283:0xA3:0x99
+
+# Rust monster
+R:284:0xB9:0x8F
+
+# Ogrillon
+R:285:0xA9:0x98
+
+# Gelatinous cube
+R:286:0xA8:0x95
+
+# Giant green dragonfly
+R:287:0x9F:0x94
+
+# Fire giant
+R:288:0xA1:0x93
+
+# Hummerhorn
+R:289:0xBA:0x8F
+
+# Lizard man
+R:290:0xB9:0x90
+
+# Ulfast, Son of Ulfang
+R:291:0xAB:0x82
+
+# Crebain
+R:292:0xC4:0x94
+
+# Berserker
+R:293:0xA9:0x97
+
+# Draugrog
+R:294:0xA0:0x95
+
+# Sphinx
+R:295:0xB9:0x91
+
+# Narrog
+R:296:0xA0:0x96
+
+# Forest troll
+R:297:0xA3:0x89
+
+# Freezing sphere
+R:298:0xBA:0x91
+
+# Jumping fireball
+R:299:0xB9:0x92
+
+# Ball lightning
+R:300:0xBA:0x92
+
+# 2-headed hydra
+R:301:0xA2:0x93
+
+# Swamp thing
+R:302:0xB9:0x93
+
+# Water spirit
+R:303:0x9F:0x80
+
+# Giant red scorpion
+R:304:0xA3:0x83
+
+# Earth spirit
+R:305:0x9F:0x81
+
+# Fire spirit
+R:306:0x9F:0x82
+
+# Fire hound
+R:307:0xA4:0x96
+
+# Cold hound
+R:308:0xA4:0x97
+
+# Energy hound
+R:309:0xA4:0x98
+
+# Lesser mimic
+R:310:0x9D:0x8E
+
+# Door mimic
+R:311:0x82:0x83
+
+# Blink dog
+R:312:0x9E:0x81
+
+# Uruk
+R:313:0xA9:0x99
+
+# Shagrat, the Orc Captain
+R:314:0xA9:0x9A
+
+# Gorbag, the Orc Captain
+R:315:0xA9:0x9B
+
+# Shambling mound
+R:316:0x9D:0x8C
+
+# Venus Flytrap
+R:317:0xC4:0x95
+
+# Amrod, Son of Feanor
+R:318:0xBF:0xBD
+
+# Amras, Son of Feanor
+R:319:0xBF:0xBD
+
+# Giant bronze dragonfly
+R:320:0x9F:0x98
+
+# Stone giant
+R:321:0xA1:0x94
+
+# Giant black dragonfly
+R:322:0x9F:0x96
+
+# Stone golem
+R:323:0xA7:0x8B
+
+# Red mold
+R:324:0xA9:0x85
+
+# Giant gold dragonfly
+R:325:0x9F:0x97
+
+# Telchar the Smith
+R:326:0xBF:0xBE
+
+# Ghast
+R:327:0xBA:0x95
+
+# Neekerbreeker
+R:328:0xC4:0x96
+
+# Huorn
+R:329:0xBA:0x96
+
+# Bolg, Son of Azog
+R:330:0xA9:0x9C
+
+# Phase spider
+R:331:0xA3:0x84
+
+# Lizard king
+R:332:0xB9:0x97
+
+# Landmine
+R:333:0xBA:0x97
+
+# Roac, son of Carc
+R:334:0xC4:0xB2
+
+# Great eagle
+R:335:0xB9:0x98
+
+# Livingstone
+R:336:0xB1:0x84
+
+# Earth hound
+R:337:0xA4:0x99
+
+# Air hound
+R:338:0xA4:0x9A
+
+# Sabre-tooth tiger
+R:339:0xA7:0x86
+
+# Acid hound
+R:340:0xA4:0x9B
+
+# Chimaera
+R:341:0xA0:0x8C
+
+# Quylthulg
+R:342:0xA1:0x9A
+
+# Sasquatch
+R:343:0xA4:0x92
+
+# Carc of Ravenhill
+R:344:0xC4:0xB2
+
+# Ranger
+R:345:0xAA:0x97
+
+# Paladin
+R:346:0xAB:0x92
+
+# Werewolf
+R:347:0xBA:0x99
+
+# Dark elven lord
+R:348:0xA7:0x9C
+
+# Cloud giant
+R:349:0xA1:0x96
+
+# Ugluk, the Uruk
+R:350:0xA9:0x9D
+
+# Blue dragon bat
+R:351:0xA5:0x91
+
+# Mimic
+R:352:0x83:0x9D
+
+# Ultimate mimic
+R:353:0x84:0x9E
+
+# Fire vortex
+R:354:0xAC:0x94
+
+# Acid vortex
+R:355:0xAC:0x95
+
+# Lugdush, the Uruk
+R:356:0xB9:0x9A
+
+# Alatar, the Blue Wizard
+R:357:0xBF:0xBF
+
+# Cold vortex
+R:358:0xAC:0x96
+
+# Energy vortex
+R:359:0xAC:0x97
+
+# Globefish
+R:360:0xB9:0x9B
+
+# Giant firefly
+R:361:0x9F:0x95
+
+# Mummified orc
+R:362:0xA1:0x88
+
+# Wolf chieftain
+R:363:0xC4:0x97
+
+# Pallando, the Blue Wizard
+R:364:0xBF:0xBF
+
+# Vampiric mist
+R:365:0xB9:0x9D
+
+# Killer stag beetle
+R:366:0xA0:0x9D
+
+# Iron golem
+R:367:0xA7:0x8C
+
+# Auto-roller
+R:368:0xB1:0x86
+
+# Giant yellow scorpion
+R:369:0xA3:0x85
+
+# Muzgash, the Snaga
+R:370:0xBE:0xA0
+
+# Black ooze
+R:371:0xA8:0x96
+
+# Hardened warrior
+R:372:0xAB:0x83
+
+# Azog, King of the Uruk-Hai
+R:373:0xA9:0x9F
+
+# Bill Ferny
+R:374:0xBE:0xA1
+
+# Dark elven warlock
+R:375:0xB1:0x87
+
+# Master rogue
+R:376:0xAB:0x84
+
+# Red dragon bat
+R:377:0xA5:0x92
+
+# Killer white beetle
+R:378:0xBA:0x9E
+
+# Ice skeleton
+R:379:0xB9:0x9F
+
+# Angamaite of Umbar
+R:380:0xBB:0x80
+
+# Forest wight
+R:381:0xB1:0x88
+
+# Khim, Son of Mim
+R:382:0xB1:0x89
+
+# Ibun, Son of Mim
+R:383:0xB1:0x8A
+
+# Meneldor the Swift
+R:384:0xBB:0x81
+
+# Phantom beast
+R:385:0xB1:0x8B
+
+# Giant silver ant
+R:386:0xA0:0x9C
+
+# 4-headed hydra
+R:387:0xA2:0x95
+
+# Beruthiel, Queen of Cats
+R:388:0xBE:0xA2
+
+# The Hunter
+R:389:0xB1:0x8C
+
+# Mummified human
+R:390:0xA1:0x89
+
+# Vampire bat
+R:391:0xA5:0x93
+
+# Sangahyando of Umbar
+R:392:0xAB:0x85
+
+# It
+R:393:0xB1:0x8D
+
+# Banshee
+R:394:0x9F:0x9D
+
+# Herumor, Lord of the Haradrim
+R:395:0xBE:0xA3
+
+# Fimbrethil
+R:396:0xBB:0x84
+
+# Silent watcher
+R:397:0xB1:0x8E
+
+# Pukelman
+R:398:0xA7:0x8D
+
+# Mauhur, the Uruk
+R:399:0xBE:0xA4
+
+# Dark elven druid
+R:400:0xA7:0x9F
+
+# Stone troll
+R:401:0xA3:0x8A
+
+# Prince Imrahil the Proud
+R:402:0xBE:0xA5
+
+# Hill troll
+R:403:0xA3:0x8B
+
+# Wereworm
+R:404:0xAD:0x84
+
+# Killer red beetle
+R:405:0xA0:0x9F
+
+# Disenchanter bat
+R:406:0xC4:0x98
+
+# Umuiyan, Doorkeeper of Tevildo
+R:407:0xBE:0xA6
+
+# Giant grey ant
+R:408:0xA5:0x8C
+
+# Oikeroi, Bodyguard of Tevildo
+R:409:0xBE:0xA7
+
+# Gwaihir the Windlord
+R:410:0xBB:0x81
+
+# Giant fire tick
+R:411:0xBB:0x87
+
+# Lotho Sackville-Baggins, Betrayer of the Shire
+R:412:0xBE:0xA8
+
+# Ulwarth, Son of Ulfang
+R:413:0xAA:0x99
+
+# Werebear
+R:414:0xC4:0x8F
+
+# Cave ogre
+R:415:0xA1:0x8D
+
+# White wraith
+R:416:0xA3:0x9F
+
+# Thranduil, King of the Wood Elves
+R:417:0xBE:0xA9
+
+# Ghoul
+R:418:0xB4:0x8F
+
+# Mim, Betrayer of Turin
+R:419:0xB1:0x90
+
+# Hellblade
+R:420:0xB1:0x91
+
+# Killer fire beetle
+R:421:0xA1:0x80
+
+# Denethor, Steward of Gondor
+R:422:0xBE:0xAA
+
+# Creeping adamantite coins
+R:423:0x9D:0x84
+
+# Algroth
+R:424:0xA3:0x8C
+
+# Boromir, Son of Denethor
+R:425:0xBE:0xAB
+
+# Roper
+R:426:0xB9:0x80
+
+# Headless
+R:427:0xB1:0x92
+
+# Vibration hound
+R:428:0xA4:0x9C
+
+# Nexus hound
+R:429:0xA4:0x9D
+
+# Half-ogre
+R:430:0xA1:0x8E
+
+# Lokkak, the Ogre Chieftain
+R:431:0xA1:0x90
+
+# Vampire
+R:432:0xA3:0x9A
+
+# Gorgimaera
+R:433:0xA0:0x8D
+
+# Faramir, Son of Denethor
+R:434:0xBE:0xAC
+
+# Colbran
+R:435:0xA7:0x8E
+
+# Spirit naga
+R:436:0xA9:0x8C
+
+# Harry Goatleaf, Gatekeeper of Bree
+R:437:0xBE:0xAD
+
+# The Watcher of Cirith Ungol
+R:438:0xB1:0x8E
+
+# Stairway to Hell
+R:439:0xB1:0x94
+
+# 5-headed hydra
+R:440:0xA2:0x96
+
+# Tom Bombadil
+R:441:0xBE:0xAE
+
+# Wainrider
+R:442:0xAB:0x88
+
+# Seahorse
+R:443:0xBB:0x89
+
+# Cyclops
+R:444:0xBB:0x8A
+
+# Clairvoyant
+R:445:0xAB:0x86
+
+# Purple worm
+R:446:0xB9:0x82
+
+# Catoblepas
+R:447:0xAC:0x81
+
+# Lesser wall monster
+R:448:0xB1:0x96
+
+# Mage
+R:449:0xAB:0x8A
+
+# Mind flayer
+R:450:0xAB:0x8B
+
+# The Ultimate Dungeon Cleaner
+R:451:0xB1:0x97
+
+# The Mewlip Queen
+R:452:0xBE:0xAF
+
+# Basilisk
+R:453:0xA2:0x97
+
+# Snow-troll
+R:454:0xA3:0x8D
+
+# Fluithuin the Ogress, Consort of Morgoth
+R:455:0xBE:0xB0
+
+# Ulbandi the Ogress, Consort of Morgoth
+R:456:0xBE:0xB1
+
+# Naugladur, Lord of Nogrod
+R:457:0xBE:0xB2
+
+# Greater mimic
+R:458:0xB1:0x9A
+
+# Young blue dragon
+R:459:0xA6:0x84
+
+# Young white dragon
+R:460:0xA6:0x85
+
+# Young green dragon
+R:461:0xA6:0x86
+
+# Young bronze dragon
+R:462:0xA6:0x87
+
+# Androg the Outlaw
+R:463:0xBE:0xB3
+
+# Mithril golem
+R:464:0xA7:0x8F
+
+# Skeleton troll
+R:465:0xAC:0x8D
+
+# Amlach, son of Imlach
+R:466:0xBE:0xB4
+
+# Beorn, the Shape-Changer
+R:467:0xC4:0x99
+
+# Thorondor, Lord of Eagles
+R:468:0xBB:0x81
+
+# Giant blue ant
+R:469:0xA5:0x8B
+
+# Grave wight
+R:470:0xAD:0x9C
+
+# Shadow drake
+R:471:0xA6:0x88
+
+# Manticore
+R:472:0xA0:0x8E
+
+# Giant army ant
+R:473:0xAE:0x81
+
+# Killer slicer beetle
+R:474:0xA1:0x81
+
+# Gorgon
+R:475:0xBB:0x8D
+
+# Radagast the Brown
+R:476:0xBE:0xB5
+
+# Ghost
+R:477:0x9F:0x9E
+
+# Death watch beetle
+R:478:0xA1:0x82
+
+# Mountain ogre
+R:479:0xA1:0x8F
+
+# Nexus quylthulg
+R:480:0xA1:0x9B
+
+# Shelob, Spider of Darkness
+R:481:0xA3:0x86
+
+# Giant squid
+R:482:0xB9:0x83
+
+# Ghoulking
+R:483:0xAD:0x8C
+
+# Doombat
+R:484:0xB9:0x84
+
+# Easterling
+R:485:0xAB:0x8C
+
+# Memory moss
+R:486:0xA9:0x86
+
+# Storm giant
+R:487:0xA1:0x95
+
+# Spectator
+R:488:0xB1:0x9B
+
+# Bjorn the Warper
+R:489:0xC4:0x99
+
+# Vaire, the Weaver
+R:490:0xBE:0xB6
+
+# Half-troll
+R:491:0xA9:0x9E
+
+# Irmo of Lorien
+R:492:0xBE:0xB7
+
+# Bert the Stone Troll
+R:493:0xA3:0x90
+
+# Bill the Stone Troll
+R:494:0xA3:0x91
+
+# Tom the Stone Troll
+R:495:0xA3:0x92
+
+# Cave troll
+R:496:0xA3:0x8E
+
+# Este, the Gentle
+R:497:0xBE:0xB8
+
+# Barrow wight
+R:499:0xA4:0x81
+
+# Skeleton ettin
+R:500:0xC4:0x9A
+
+# Chaos drake
+R:501:0xA6:0x89
+
+# Law drake
+R:502:0xA6:0x8A
+
+# Balance drake
+R:503:0xA6:0x8B
+
+# Ethereal drake
+R:504:0xA6:0x8C
+
+# Groo, the Wanderer
+R:505:0xB1:0x9E
+
+# Nessa the Lithe
+R:506:0xBE:0xB9
+
+# Shade
+R:507:0xA4:0x89
+
+# Spectre
+R:508:0xA0:0x80
+
+# Water troll
+R:509:0xA3:0x93
+
+# Fire elemental
+R:510:0x9F:0x83
+
+# Water elemental
+R:512:0x9F:0x84
+
+# Multi-hued hound
+R:513:0xB2:0x81
+
+# Invisible stalker
+R:514:0x9F:0x85
+
+# Vana, the Ever-young
+R:515:0xBE:0xBA
+
+# Master thief
+R:516:0xAB:0x8E
+
+# The Watcher in the Water
+R:517:0xAF:0x95
+
+# Lich
+R:518:0xA1:0x83
+
+# Gas spore
+R:519:0xB2:0x8E
+
+# Master vampire
+R:520:0xA3:0x9B
+
+# Oriental vampire
+R:521:0xB2:0x83
+
+# Greater mummy
+R:522:0xA1:0x8A
+
+# Ingeborg, the Runemistress
+R:523:0xBE:0xBB
+
+# Giant grey scorpion
+R:524:0xA3:0x87
+
+# Earth elemental
+R:525:0x9F:0x86
+
+# Air elemental
+R:526:0x9F:0x87
+
+# Shimmering mold
+R:527:0xAF:0x81
+
+# Sarnrog
+R:528:0xBB:0x91
+
+# Malicious leprawn
+R:529:0xB2:0x85
+
+# Eog golem
+R:530:0xA7:0x90
+
+# Lindal Lossehelin
+R:531:0xBE:0xBC
+
+# Variag
+R:532:0x04:0x70
+
+# Headless ghost
+R:533:0xBB:0x92
+
+# Dread
+R:534:0xB9:0x87
+
+# Zizzo, Last of the Yeeks
+R:535:0xC3:0xAF
+
+# Gauth
+R:536:0xC4:0x9B
+
+# Smoke elemental
+R:537:0x9F:0x90
+
+# Olog
+R:538:0xA3:0x94
+
+# Halfling slinger
+R:539:0xB2:0x86
+
+# Gravity hound
+R:540:0xA4:0x9E
+
+# Acidic cytoplasm
+R:541:0xA8:0x97
+
+# Inertia hound
+R:542:0xA4:0x9F
+
+# Impact hound
+R:543:0xA5:0x80
+
+# Shardstorm
+R:544:0xC4:0x9C
+
+# Ooze elemental
+R:545:0x9F:0x88
+
+# Young black dragon
+R:546:0xA6:0x8D
+
+# Mumak
+R:547:0xAC:0x84
+
+# Giant fire ant
+R:548:0xA5:0x8A
+
+# Cold-drake
+R:549:0xA6:0x8E
+
+# Xorn
+R:550:0xA4:0x8F
+
+# Rogrog the Black Troll
+R:551:0xA3:0x8F
+
+# Erianyth, the Sorceress
+R:552:0xA7:0x91
+
+# Phantom
+R:553:0xB2:0x87
+
+# Grey wraith
+R:554:0xA4:0x82
+
+# Revenant
+R:555:0xA4:0x88
+
+# Young multi-hued dragon
+R:556:0xA6:0x8F
+
+# Karrazix the Brave
+R:557:0x9E:0x89
+
+# Colossus
+R:558:0xB2:0x89
+
+# Young gold dragon
+R:559:0xA6:0x90
+
+# Blue drake
+R:560:0xA6:0x91
+
+# Green drake
+R:561:0xA6:0x92
+
+# Bronze drake
+R:562:0xA6:0x93
+
+# Young red dragon
+R:563:0xA6:0x94
+
+# Sir Physt
+R:564:0x0B:0x56
+
+# Trapper
+R:565:0xAD:0x9F
+
+# Adanrog
+R:566:0xA0:0x98
+
+# Time bomb
+R:567:0xBB:0x96
+
+# Rawrog
+R:568:0xAD:0x90
+
+# Nick LeYeek, Second Last of the Yeeks
+R:569:0xC3:0xB0
+
+# Ice elemental
+R:570:0x9F:0x8A
+
+# Necromancer
+R:571:0xB2:0x8C
+
+# Slappy, Abbess of Pain
+R:572:0xBE:0xBD
+
+# Lorgan, Chief of the Easterlings
+R:573:0xB2:0x8D
+
+# Snow tiger
+R:574:0xC2:0xB0
+
+# Mummified troll
+R:575:0xBB:0x97
+
+# Storm of Unmagic
+R:576:0xC4:0x9D
+
+# Crypt thing
+R:577:0xA4:0x80
+
+# Chaos butterfly
+R:578:0xBB:0x98
+
+# Time elemental
+R:579:0xB2:0x8F
+
+# Blue yeek
+R:580:0xAD:0x87
+
+# The Queen Ant
+R:581:0xA5:0x8E
+
+# Will o' the wisp
+R:582:0x9F:0x8B
+
+# Brown yeek
+R:583:0xAD:0x88
+
+# Magma elemental
+R:584:0x9F:0x8C
+
+# Black pudding
+R:585:0xA8:0x98
+
+# Killer iridescent beetle
+R:586:0xB4:0x90
+
+# Nexus vortex
+R:587:0xAE:0x80
+
+# Plasma vortex
+R:588:0xAC:0x98
+
+# Fire-drake
+R:589:0xA6:0x95
+
+# Golden drake
+R:590:0xA6:0x96
+
+# Crystal drake
+R:591:0xA6:0x97
+
+# Black drake
+R:592:0xA6:0x98
+
+# Multi-hued drake
+R:593:0xA6:0x99
+
+# Master yeek
+R:594:0xAD:0x8A
+
+# Orfax, son of Boldor
+R:595:0xAD:0x89
+
+# Boldor, King of the Yeeks
+R:596:0xAD:0x8B
+
+# Black Numenorean
+R:597:0xAB:0x94
+
+# Castamir the Usurper
+R:598:0xB2:0x90
+
+# Time vortex
+R:599:0xAC:0x99
+
+# Shimmering vortex
+R:600:0xAC:0x9A
+
+# Ancient blue dragon
+R:601:0x9E:0x88
+
+# Ancient bronze dragon
+R:602:0x9E:0x89
+
+# Beholder
+R:603:0xA6:0x9F
+
+# Emperor wight
+R:604:0xA4:0x83
+
+# Giant tree ant
+R:605:0xC4:0xB7
+
+# Vargo, Tyrant of Fire
+R:606:0x9F:0x8D
+
+# Black wraith
+R:607:0xA4:0x84
+
+# Giant yellow ant
+R:608:0xC4:0xB8
+
+# Giant green ant
+R:609:0xC4:0xB9
+
+# Aquatic ant
+R:610:0xC4:0xBA
+
+# Monastic lich
+R:611:0xA1:0x87
+
+# Nether wraith
+R:612:0xA4:0x85
+
+# Hellhound
+R:613:0xAD:0x96
+
+# 7-headed hydra
+R:614:0xA2:0x99
+
+# Waldern, King of Water
+R:615:0x9F:0x8E
+
+# Termite
+R:616:0xC4:0xB6
+
+# Ancient white dragon
+R:617:0x9E:0x8A
+
+# Ancient green dragon
+R:618:0x9E:0x8B
+
+# Giant snow bat
+R:619:0xC4:0xBB
+
+# Eldrak
+R:620:0xA3:0x97
+
+# Ettin
+R:621:0xA3:0x96
+
+# Night mare
+R:622:0xAC:0x83
+
+# Vampire lord
+R:623:0xA3:0x9C
+
+# Ancient black dragon
+R:624:0x9E:0x8C
+
+# Weird fume
+R:625:0xAF:0x80
+
+# Giant grey bat
+R:626:0xC4:0xBC
+
+# Giant silver bat
+R:627:0xC4:0xBD
+
+# Giant yellow bat
+R:628:0xC4:0xBE
+
+# Shadowfax, steed of Gandalf
+R:629:0xBB:0x9E
+
+# Spirit troll
+R:630:0xA3:0x98
+
+# War troll
+R:631:0xB2:0x94
+
+# Disenchanter worm mass
+R:632:0xAD:0x86
+
+# Rotting quylthulg
+R:633:0xA1:0x9C
+
+# Lesser titan
+R:634:0xA1:0x97
+
+# 9-headed hydra
+R:635:0xA2:0x99
+
+# Enchantress
+R:636:0xAB:0x96
+
+# Ranger chieftain
+R:637:0xAB:0x97
+
+# Sorcerer
+R:638:0xAB:0x98
+
+# Xaren
+R:639:0xA4:0x90
+
+# Giant green bat
+R:640:0xC4:0xBF
+
+# Death vortex
+R:641:0xC3:0xA5
+
+# Gas vortex
+R:642:0xC3:0xA6
+
+# Death drake
+R:643:0x9E:0x8D
+
+# Ancient red dragon
+R:644:0x9E:0x8E
+
+# Ancient gold dragon
+R:645:0x9E:0x8F
+
+# Great crystal drake
+R:646:0x9E:0x90
+
+# Mana vortex
+R:647:0xC3:0xA7
+
+# Helcungol
+R:648:0xB2:0x95
+
+# Lygrog
+R:649:0xA0:0x99
+
+# Slow vortex
+R:650:0xC3:0xA8
+
+# Nether vortex
+R:651:0xC3:0xA9
+
+# Puzzling vortex
+R:652:0xC3:0xAA
+
+# Dark yeek
+R:653:0xC3:0xAB
+
+# Judge Fire
+R:654:0xAB:0x93
+
+# White yeek
+R:655:0xC3:0xAC
+
+# Judge Mortis
+R:656:0xBC:0x82
+
+# Dark elven sorcerer
+R:657:0xA8:0x81
+
+# Master lich
+R:658:0xA1:0x84
+
+# Gray yeek
+R:659:0xC3:0xAD
+
+# Eol, the Dark Elf
+R:660:0xB2:0x99
+
+# Yellow yeek
+R:661:0xC3:0xAE
+
+# Adventurer yeek
+R:662:0xAD:0x88
+
+# Dark mushroom patch
+R:663:0xC3:0xA1
+
+# Undead beholder
+R:664:0xA7:0x80
+
+# Shadow
+R:665:0xA0:0x81
+
+# Iron lich
+R:666:0xB2:0x9C
+
+# Dread
+R:667:0xB9:0x87
+
+# Greater basilisk
+R:668:0xBC:0x83
+
+# White mushroom patch
+R:669:0xC3:0xA0
+
+# Brown mushroom patch
+R:670:0xC3:0xA2
+
+# Silver mushroom patch
+R:671:0xC3:0xA3
+
+# Green mushroom patch
+R:672:0xC3:0xA4
+
+# Mumak
+R:673:0xAC:0x82
+
+# Judge Fear
+R:674:0xA7:0x88
+
+# Ancient multi-hued dragon
+R:675:0x9E:0x91
+
+# Ethereal dragon
+R:676:0x9E:0x92
+
+# Dark elemental
+R:677:0xC3:0xB1
+
+# Slow elemental
+R:678:0xC3:0xB2
+
+# Quaker, Master of Earth
+R:679:0x9F:0x8F
+
+# Death leprawn
+R:680:0xA7:0x9E
+
+# Chaos elemental
+R:681:0xC3:0xB4
+
+# Confusion elemental
+R:682:0xC3:0xB3
+
+# Large blue snake
+R:683:0xC2:0xA8
+
+# Large silver snake
+R:684:0xC2:0xA9
+
+# Large purple snake
+R:685:0xC2:0xAA
+
+# Judge Death
+R:686:0xBC:0x99
+
+# Ariel, Queen of Air
+R:687:0x9F:0x91
+
+# 11-headed hydra
+R:688:0xA2:0x9A
+
+# Patriarch
+R:689:0xAB:0x9A
+
+# Dreadmaster
+R:690:0xA0:0x85
+
+# Drolem
+R:691:0xA7:0x92
+
+# Scatha the Worm
+R:692:0xAD:0x9B
+
+# Warrior of the Dawn
+R:693:0xB2:0x9E
+
+# Lesser black reaver
+R:694:0xA4:0x87
+
+# Large red snake
+R:695:0xC2:0xAB
+
+# Grand master thief
+R:696:0xC2:0x8A
+
+# Smaug the Golden
+R:697:0x9E:0x93
+
+# The Stormbringer
+R:698:0xB3:0x80
+
+# Knight Templar
+R:699:0xB3:0x81
+
+# Large eel
+R:700:0xC2:0xAC
+
+# Dracolich
+R:701:0x9E:0x95
+
+# Greater titan
+R:702:0xA1:0x98
+
+# Dracolisk
+R:703:0x9E:0x94
+
+# Winged Horror
+R:704:0xC4:0x9E
+
+# Killer gray beetle
+R:705:0xC2:0xA1
+
+# Killer orange beetle
+R:706:0xC2:0xA2
+
+# Killer blue beetle
+R:707:0xC2:0xA3
+
+# Ent
+R:708:0xBC:0x86
+
+# Rock giant
+R:709:0xBC:0x9D
+
+# Itangast the Fire Drake
+R:710:0x9E:0x96
+
+# Death mold
+R:711:0xA9:0x87
+
+# Killer silver beetle
+R:712:0xC2:0xA4
+
+# Killer green beetle
+R:713:0xC2:0xA5
+
+# Quickbeam, the Ent
+R:714:0xBC:0x9F
+
+# Glaurung, Father of the Dragons
+R:715:0xAD:0x9A
+
+# Behemoth
+R:716:0xBD:0x80
+
+# Killer aquatic beetle
+R:717:0xC2:0xA6
+
+# Greater wall monster
+R:718:0xB3:0x84
+
+# Menelrog
+R:719:0xAD:0x91
+
+# Mornungol
+R:720:0xAD:0x95
+
+# Killer tree beetle
+R:721:0xC2:0xA7
+
+# Nightwing
+R:722:0xAD:0x9D
+
+# 6-headed hydra
+R:723:0xC3:0xB9
+
+# Nether hound
+R:724:0xA5:0x81
+
+# Time hound
+R:725:0xA5:0x82
+
+# Plasma hound
+R:726:0xA5:0x83
+
+# Demonic quylthulg
+R:727:0xA1:0x9D
+
+# Great Storm Worm
+R:728:0x9E:0x97
+
+# Ulik the Troll
+R:729:0xBD:0x81
+
+# 8-headed hydra
+R:730:0xC3:0xBA
+
+# Oathbreaker
+R:731:0xBD:0x82
+
+# 10-headed hydra
+R:732:0xC3:0xBB
+
+# 12-headed hydra
+R:733:0xC3:0xBC
+
+# 13-headed hydra
+R:734:0xC3:0xBD
+
+# 14-headed hydra
+R:735:0xC3:0xBE
+
+# 15-headed hydra
+R:736:0xC3:0xBF
+
+# Killer hydra
+R:737:0xC2:0xA0
+
+# Old Sorcerer
+R:738:0x9C:0x8A
+
+# Ethereal hound
+R:739:0xB3:0x8A
+
+# Lesser kraken
+R:740:0xBD:0x83
+
+# Great Ice Worm
+R:741:0x9E:0x98
+
+# Demilich
+R:742:0xA4:0x8A
+
+# The Phoenix
+R:743:0x9D:0x98
+
+# Nightcrawler
+R:744:0xA4:0x8C
+
+# Forest ogre
+R:745:0xC3:0xB8
+
+# Rebel ogre
+R:746:0xA1:0x8B
+
+# Rebel giant
+R:747:0xA1:0x91
+
+# Hand druj
+R:748:0xAC:0x8E
+
+# Eye druj
+R:749:0xAC:0x8F
+
+# Skull druj
+R:750:0xAC:0x90
+
+# Chaos vortex
+R:751:0xAC:0x9B
+
+# Aether vortex
+R:752:0xAC:0x9C
+
+# Spider quylthulg
+R:753:0xC3:0xB5
+
+# Canine quylthulg
+R:754:0xC3:0xB6
+
+# Thuringwethil, the Vampire Messenger
+R:755:0xA3:0x9D
+
+# Great Worm of Fire
+R:756:0x9E:0x99
+
+# Aquatic quylthulg
+R:757:0xC3:0xB7
+
+# Adventurer quylthulg
+R:758:0xA1:0x9A
+
+# Draconic quylthulg
+R:759:0xA1:0x9E
+
+# White hulk
+R:760:0xC4:0xA0
+
+# Death hulk
+R:761:0xC4:0xA1
+
+# Fundin Bluecloak
+R:762:0xBE:0x91
+
+# Black Balrog
+R:763:0xC0:0xA9
+
+# Orange hulk
+R:764:0xC4:0xA2
+
+# Fire hulk
+R:765:0xC4:0xA3
+
+# Ancalagon the Black
+R:766:0x9E:0x9A
+
+# Forest hulk
+R:767:0xC4:0xA4
+
+# Nightwalker
+R:768:0xBD:0x85
+
+# Night hulk
+R:769:0xC4:0xA5
+
+# Silver hulk
+R:770:0xC4:0xA6
+
+# Saruman of Many Colours
+R:771:0xAB:0x9E
+
+# Harowen the Black Hand
+R:772:0xBE:0x94
+
+# Blue Balrog
+R:773:0xC0:0xAB
+
+# Dreadlord
+R:774:0xA0:0x86
+
+# Greater kraken
+R:775:0xBD:0x86
+
+# Archlich
+R:776:0xA4:0x8D
+
+# Tevildo, Prince of Cats
+R:777:0xB3:0x8F
+
+# Jabberwock
+R:778:0xC5:0x82
+
+# Chaos hound
+R:779:0xA5:0x85
+
+# Chaos hulk
+R:780:0xC4:0xA7
+
+# Beholder hive-mother
+R:781:0xBE:0x96
+
+# Leviathan
+R:782:0xBD:0x87
+
+# Great Worm of Chaos
+R:783:0x9E:0x9B
+
+# Great Worm of Law
+R:784:0x9E:0x9C
+
+# Great Worm of Balance
+R:785:0x9E:0x9D
+
+# Yellow hulk
+R:786:0xC4:0xA8
+
+# White Balrog
+R:787:0xC0:0xAA
+
+# Red hulk
+R:788:0xC4:0xA9
+
+# Trone, the Rebel Thunderlord
+R:789:0x08:0x42
+
+# Great Worm of Many Colours
+R:790:0xB3:0x93
+
+# Marda, rider of gold Laronth
+R:791:0xB3:0x94
+
+# Tselakus, the Dreadlord
+R:792:0xA0:0x87
+
+# Sky Drake
+R:793:0xB3:0x95
+
+# Eilinel the Entrapped
+R:794:0xA0:0x83
+
+# Dagorrog
+R:795:0xC5:0x84
+
+# Green hulk
+R:796:0xC4:0xAA
+
+# Blue hulk
+R:797:0xC4:0xAB
+
+# Black reaver
+R:798:0xA1:0x85
+
+# Master mindcrafter
+R:799:0xAB:0x9F
+
+# Greater demonic quylthulg
+R:800:0xA1:0x9F
+
+# Greater draconic quylthulg
+R:801:0xA2:0x80
+
+# Greater rotting quylthulg
+R:802:0xA2:0x81
+
+# Invisible Horror
+R:803:0xBC:0x88
+
+# Feagwath, the Undead Sorcerer
+R:804:0xA1:0x86
+
+# Silver wraith
+R:805:0xA3:0x9F
+
+# Adventurer wraith
+R:806:0xA4:0x81
+
+# Balrog Captain
+R:807:0xC0:0xAC
+
+# Ungoliant, the Unlight
+R:808:0xA3:0x88
+
+# Vampire orc
+R:809:0xC0:0xA0
+
+# Vampire yeek
+R:810:0xC0:0xA1
+
+# Aether hound
+R:811:0xA5:0x86
+
+# Greater Balrog
+R:812:0xC0:0xAD
+
+# Vampire ogre
+R:813:0xC0:0xA2
+
+# Vampire troll
+R:814:0xC0:0xA3
+
+# Vampire dwarf
+R:815:0xC0:0xA4
+
+# Vampire elf
+R:816:0xC0:0xA5
+
+# Vampire gnome
+R:817:0xC0:0xA6
+
+# The Mouth of Sauron
+R:818:0xBE:0x9E
+
+# The Necromancer of Dol Guldur
+R:819:0xB3:0x9E
+
+# Lisa, rider of gold Romth
+R:820:0xB3:0x9F
+
+# Master quylthulg
+R:821:0xA2:0x82
+
+# Qlzqqlzuup, the Lord of Flesh
+R:822:0xA2:0x83
+
+# Vampire adventurer
+R:823:0xA3:0x9A
+
+# Flare, rider of bronze Moonth
+R:824:0xB4:0x80
+
+# Maeglin, the Traitor of Gondolin
+R:825:0xA4:0x8E
+
+# Snow-frog
+R:826:0xC1:0xBE
+
+# Swamp lizard
+R:827:0xC1:0xBD
+
+# Giant silver frog
+R:828:0xC1:0xBE
+
+# Greater Hellhound
+R:829:0x9E:0x83
+
+# Cantoras, the Skeletal Lord
+R:830:0xAC:0x91
+
+# Blue lizard
+R:831:0xC1:0xBF
+
+# Death dragonfly
+R:832:0xC1:0xB3
+
+# Giant swamp dragonfly
+R:833:0xC1:0xB4
+
+# Giant red dragonfly
+R:834:0xC1:0xB5
+
+# Giant forest dragonfly
+R:835:0xC1:0xB6
+
+# Giant blue dragonfly
+R:836:0xC1:0xB7
+
+# Giant brown dragonfly
+R:837:0xC1:0xB8
+
+# The Tarrasque
+R:838:0xBC:0x93
+
+# Lungorthin, the Balrog of White Fire
+R:839:0xBF:0x86
+
+# Draugluin, Sire of All Werewolves
+R:840:0xBF:0x87
+
+# Giant silver dragonfly
+R:841:0xC1:0xB9
+
+# Giant violet dragonfly
+R:842:0xC1:0xBA
+
+# Giant pink dragonfly
+R:843:0xC1:0xBB
+
+# Vecna, the Emperor Lich
+R:844:0xB4:0x85
+
+# Aquatic dragonfly
+R:845:0xC1:0xBC
+
+# Giant red mouse
+R:846:0xC1:0xB0
+
+# Great Wyrm of Power
+R:847:0xB4:0x87
+
+# Giant blue mouse
+R:848:0xC1:0xB1
+
+# Giant yellow mouse
+R:849:0xC1:0xB2
+
+# Carcharoth, the Jaws of Thirst
+R:850:0x9E:0x86
+
+# Giant pink rat
+R:851:0xC1:0xAE
+
+# Giant tree rat
+R:852:0xC1:0xAF
+
+# Huan, Wolfhound of the Valar
+R:853:0x9E:0x87
+
+# Polar bear
+R:854:0xC1:0xA8
+
+# Blue bear
+R:855:0xC1:0xA9
+
+# Gothmog, the High Captain of Balrogs
+R:856:0xAD:0x98
+
+# Old bear
+R:857:0xC1:0xAA
+
+# Sarko, rider of gold Foronth
+R:858:0xB4:0x8C
+
+# Teddy bear
+R:859:0xC1:0xAB
+
+# Sauron, the Sorcerer
+R:860:0xAC:0x80
+
+# DarkGod, the Mighty Coder of Hell
+R:861:0xC0:0x9D
+
+# Morgoth, Lord of Darkness
+R:862:0xB4:0x8E
+
+# Human Warrior
+R:863:0xB5:0x80
+
+# Elven archer
+R:864:0xB5:0x81
+
+# Dwarven warrior
+R:865:0xB5:0x82
+
+# Elite uruk
+R:866:0xB5:0x83
+
+# Fire bear
+R:867:0xC1:0xAC
+
+# The Variant Maintainer
+R:868:0xBC:0x8B
+
+# Random Number Generator
+R:869:0xBC:0x8A
+
+# Rocket mine
+R:870:0xBD:0x88
+
+# Bouncing mine
+R:871:0xBD:0x89
+
+# Durin's Bane
+R:872:0xBF:0x89
+
+# Aquatic bear
+R:873:0xC1:0xAD
+
+# Rot jelly
+R:874:0xBD:0x8A
+
+# Death
+R:875:0xBD:0x8B
+
+# Famine
+R:876:0xBD:0x8D
+
+# Pestilence
+R:877:0xBD:0x8C
+
+# War
+R:878:0xBD:0x8E
+
+# Pike
+R:879:0xBD:0x8F
+
+# Electric eel
+R:880:0xBD:0x90
+
+# Giant crayfish
+R:881:0xBD:0x91
+
+# Mermaid
+R:882:0xBD:0x92
+
+# Box jellyfish
+R:883:0xBA:0x81
+
+# Giant piranha
+R:884:0xB6:0x9D
+
+# Piranha
+R:885:0xB6:0x9D
+
+# Swamp naga
+R:886:0xC1:0xA2
+
+# Ocean naga
+R:887:0xC1:0xA3
+
+# Snail
+R:888:0xBE:0xBE
+
+# Whale
+R:889:0xBA:0x98
+
+# Sand mite
+R:890:0xBD:0x98
+
+# Octopus
+R:891:0xBD:0x99
+
+# Giant octopus
+R:892:0xBD:0x9A
+
+# Eye of the deep
+R:893:0xBD:0x9B
+
+# Murk dweller
+R:894:0xBF:0x8B
+
+# Drowned soul
+R:895:0xBF:0x8C
+
+# Tiger shark
+R:896:0xBF:0x8D
+
+# Hammerhead shark
+R:897:0xBA:0x90
+
+# Great white shark
+R:898:0xBB:0x82
+
+# Aquatic golem
+R:899:0xBF:0x8E
+
+# Brown naga
+R:900:0xC1:0xA4
+
+# White shark
+R:901:0xBB:0x82
+
+# Scrag
+R:902:0xBF:0x91
+
+# Jaws
+R:903:0xBB:0x8C
+
+# Silver naga
+R:904:0xC1:0xA5
+
+# Aquatic elven warrior
+R:905:0xBF:0x94
+
+# Aquatic elven mage
+R:906:0xBF:0x95
+
+# Stargazer
+R:907:0xBF:0x96
+
+# Elder stargazer
+R:908:0xBF:0x97
+
+# Flounder
+R:909:0xBF:0x98
+
+# Giant turtle
+R:910:0xBF:0x99
+
+# Hatchling dragon turtle
+R:911:0xBF:0x9A
+
+# Young dragon turtle
+R:912:0xBF:0x9B
+
+# Mature dragon turtle
+R:913:0xBF:0x9C
+
+# Ancient dragon turtle
+R:914:0xBF:0x9D
+
+# Fastitocalon
+R:915:0xBF:0x9E
+
+# Undead stargazer
+R:916:0xBF:0x9F
+
+# Killer whale
+R:917:0xB9:0x9C
+
+# Merrow
+R:918:0xC5:0x85
+
+# Water naga
+R:919:0xC0:0x81
+
+# Night naga
+R:920:0xC1:0xA6
+
+# Tree naga
+R:921:0xC1:0xA7
+
+# Moby Dick, the White Whale
+R:922:0xC0:0x80
+
+# Aquatic hound
+R:923:0xC0:0x85
+
+# Gaurrog
+R:924:0xC0:0x86
+
+# Adventurer naga
+R:925:0xA9:0x88
+
+# White mold
+R:926:0xC2:0xBD
+
+# Silver mold
+R:927:0xC2:0xBE
+
+# Mathilde
+R:928:0xBD:0x9C
+
+# Child spirit
+R:929:0xBD:0x9D
+
+# Young spirit
+R:930:0xBD:0x9E
+
+# Mature spirit
+R:931:0xBD:0x9F
+
+# Experienced spirit
+R:932:0xBE:0x80
+
+# Wise spirit
+R:933:0xBE:0x81
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0xC0:0x8A
+
+# Gandalf the Grey
+R:935:0xC0:0x8B
+
+# Nar, the Dwarf
+R:936:0xC0:0x8C
+
+# Apprentice mindcrafter
+R:937:0xAA:0x9A
+
+# Great Swamp Worm
+R:938:0xC5:0x86
+
+# Great Bile Worm
+R:939:0xC5:0x87
+
+# Blue Firebird
+R:940:0xBE:0x82
+
+# Green Firebird
+R:941:0xBE:0x83
+
+# Brown Firebird
+R:942:0xBE:0x84
+
+# Bronze Firebird
+R:943:0xBE:0x85
+
+# Gold Firebird
+R:944:0xBE:0x86
+
+# High-elven ranger
+R:945:0xBE:0x87
+
+# Uvatha the Horseman
+R:946:0xC0:0x90
+
+# Adunaphel the Quiet
+R:947:0xC0:0x91
+
+# Akhorahil the Blind
+R:948:0xC0:0x92
+
+# Ren the Unclean
+R:949:0xC0:0x93
+
+# Ji Indur Dawndeath
+R:950:0xC0:0x94
+
+# Dwar, Dog Lord of Waw
+R:951:0xC0:0x95
+
+# Hoarmurath of Dir
+R:952:0xC0:0x96
+
+# Khamul, the Black Easterling
+R:953:0xC0:0x97
+
+# The Witch-King of Angmar
+R:954:0xC0:0x98
+
+# Green Thunderlord
+R:955:0xB3:0x96
+
+# Blue Thunderlord
+R:956:0xB3:0x8E
+
+# Brown Thunderlord
+R:957:0xB3:0x98
+
+# Bronze Thunderlord
+R:958:0xB3:0x98
+
+# Gold Thunderlord
+R:959:0xB3:0x94
+
+# Blood Sprout
+R:960:0xBE:0x88
+
+# Gorlim the Unhappy
+R:961:0xC0:0x99
+
+# Pink mold
+R:962:0xC2:0xBF
+
+# Aranea
+R:963:0xC1:0x9A
+
+# Elder aranea
+R:964:0xC0:0x9A
+
+# Giant brown tick
+R:965:0xC5:0x88
+
+# Wavelord
+R:966:0xC0:0x9C
+
+# Novice possessor (soul)
+R:967:0xC4:0x86
+
+# Bat of Gorgoroth
+R:968:0xC5:0x97
+
+# The Princess
+R:969:0xC5:0x98
+
+# Merton Proudfoot, the lost hobbit
+R:970:0xC5:0x99
+
+# The Wight-King of the Barrow-downs
+R:971:0xA4:0x81
+
+# Adventurer
+R:972:0xC5:0x9B
+
+# Experienced possessor (soul)
+R:973:0xC5:0x9C
+
+# Old possessor (soul)
+R:974:0xC5:0x9D
+
+# Tree mold
+R:975:0xC1:0xA0
+
+# Bronze dragon worm
+R:976:0xC6:0x80
+
+# Gold dragon worm
+R:977:0xC5:0x9F
+
+# Defenceless Mold
+R:978:0xBC:0x89
+
+# Blue mold
+R:979:0xC1:0xA1
+
+# Ar-Pharazon the Golden
+R:980:0xC0:0x9E
+
+# Doppleganger
+R:981:0x97:0x8C
+
+# Marylene, Heartbreakeress of the Netherworld
+R:982:0xC1:0x8D
+
+# Adventurer mold
+R:983:0xA9:0x81
+
+# Gnome paladin
+R:984:0xC2:0xB7
+
+# Bandobras Took
+R:985:0xA7:0x9B
+
+# 3-headed hydra
+R:986:0xA2:0x94
+
+# Uldor the Accursed
+R:987:0xAB:0x95
+
+# Mystic
+R:988:0xAB:0x9B
+
+# Elder vampire
+R:989:0xA1:0x99
+
+# Ulfang the Black
+R:990:0xAA:0x96
+
+# Demonologist
+R:991:0xA8:0x82
+
+# Ungorrog
+R:992:0xA2:0x9C
+
+# Faunungol
+R:993:0xA2:0x8E
+
+# Naurungol
+R:994:0xC2:0x8E
+
+# Sererrog
+R:995:0xC2:0x8F
+
+# Red Balrog
+R:996:0xC0:0xA8
+
+# Master mystic
+R:997:0xAA:0x94
+
+# Grand master mystic
+R:998:0xAB:0x9D
+
+# Morgulrog
+R:999:0xA0:0x84
+
+# Novice mindcrafter
+R:1000:0xAA:0x9A
+
+# Gnome lord
+R:1001:0xC2:0xB8
+
+# Great Worm of Perplexity
+R:1002:0xC2:0x92
+
+# Gnome mystic
+R:1003:0xC2:0xBA
+
+# Great Worm of Thunder
+R:1004:0xC5:0x8A
+
+# Silver mouse
+R:1005:0xC5:0x8B
+
+# The Rat King
+R:1006:0xC2:0x96
+
+# Gnome priest
+R:1007:0xC2:0xB9
+
+# Black midge
+R:1008:0xC2:0x98
+
+# Fire Phantom
+R:1009:0xC2:0x99
+
+# The Insane Player
+R:1010:0x92:0x81
+
+# Gnome rogue
+R:1011:0xC2:0xBB
+
+# Vermicious Knid
+R:1012:0xC2:0x9B
+
+# Bone golem
+R:1013:0xC2:0x9C
+
+# Gnome warrior
+R:1014:0xC2:0xBC
+
+# Bronze golem
+R:1015:0xC5:0x8C
+
+# Wizard leprawn
+R:1016:0xC2:0xB5
+
+# Kender
+R:1017:0xC2:0xB6
+
+# Adventurer gnome
+R:1018:0xC2:0xBC
+
+# Tree cat
+R:1019:0xC2:0xB1
+
+# Night cat
+R:1020:0xC2:0xB2
+
+# Leopard
+R:1021:0xC2:0xB3
+
+# Cheshire cat
+R:1022:0xC2:0xB4
+
+# Blue dragon worm
+R:1023:0xC3:0x8E
+
+# White dragon worm
+R:1024:0xC3:0x8F
+
+# Green dragon worm
+R:1025:0xC3:0x92
+
+# Black dragon worm
+R:1026:0xC3:0x91
+
+# Red dragon worm
+R:1027:0xC3:0x90
+
+# Multi-hued dragon worm
+R:1028:0xC3:0x93
+
+# The Minotaur of the Labyrinth
+R:1029:0xC3:0x94
+
+# The Sandworm Queen
+R:1030:0xC3:0x9B
+
+# Sandworm
+R:1031:0xC3:0x9C
+
+# Tik'srvzllat
+R:1032:0xC3:0x9D
+
+# The Glass Golem
+R:1033:0xC5:0x8E
+
+# Elenwe the Lost
+R:1034:0xBE:0xBF
+
+# Golgarach, the Living Rock
+R:1035:0x80:0x84
+
+# Sanctimonious-looking preacher
+R:1036:0xC2:0xAD
+
+# Weary-looking traveller
+R:1037:0xC2:0xAE
+
+# Water hound
+R:1038:0xC6:0x88
+
+# Improv, the mighty MoLD
+R:1039:0xC6:0x8E
+
+# Emperor mimic
+R:1040:0xC6:0x9C
+
+# Melinda Proudfoot
+R:1041:0x88:0xAA
+
+# Thrain, the King Under the Mountain
+R:1042:0x88:0xAB
+
+# Fire golem
+R:1043:0x8C:0xA0
+
+# Melkor, Lord of Darkness
+R:1044:0x8C:0xA1
+
+# Spirit
+R:1045:0x92:0x9F
+
+# Spirit
+R:1046:0x92:0xA0
+
+# Spirit
+R:1047:0x92:0xA1
+
+# Spirit
+R:1048:0x92:0xA2
+
+# Spirit
+R:1049:0x92:0xA3
+
+# Spirit
+R:1050:0x92:0xA4
+
+# Spirit
+R:1051:0x92:0xA5
+
+# Spirit
+R:1052:0x92:0xA6
+
+# Spirit
+R:1053:0x92:0xA7
+
+# Spirit
+R:1054:0x92:0xA8
+
+# Spirit
+R:1055:0x92:0xA9
+
+# Spirit
+R:1056:0x92:0xAA
+
+# Spirit
+R:1057:0x92:0xA3
+
+# Spirit
+R:1058:0x92:0xAB
+
+# Spirit
+R:1059:0x92:0xAC
+
+# Spirit
+R:1060:0x92:0xAD
+
+# Spirit
+R:1061:0x92:0xAE
+
+# Spirit
+R:1062:0x92:0xAF
+
+# Spirit
+R:1063:0x92:0xB0
+
+# Spirit
+R:1064:0x92:0xB1
+
+# Spirit
+R:1065:0x92:0xB2
+
+# Spirit
+R:1066:0x92:0xB3
+
+# Spirit
+R:1067:0x92:0xB4
+
+# Spirit
+R:1068:0x92:0xB5
+
+# Spirit
+R:1069:0x92:0xB6
+
+# Spirit
+R:1070:0x92:0xB7
+
+# Spirit
+R:1071:0x92:0xB8
+
+# Spirit
+R:1072:0x92:0xB9
+
+# Spirit
+R:1073:0x92:0xBA
+
+# Spirit
+R:1074:0x92:0xBB
+
+# Spirit
+R:1075:0x92:0xBC
+
+# Neil, the Sorceror
+R:1076:0x0A:0x68
+
+# Swamp wight
+R:1077:0xC0:0xA7
+
+# Knight of the Swan
+R:1078:0xC2:0xAF
+
+# Spells (*)
+S:48:0x91/0x88
+S:49:0x91/0x89
+S:50:0x91/0x8A
+S:51:0x91/0x8B
+S:52:0x91/0x8C
+S:53:0x91/0x8D
+S:54:0x91/0x8E
+S:55:0x91/0x8F
+S:56:0x91/0x90
+S:57:0x91/0x91
+S:58:0x91/0x92
+S:59:0x91/0x93
+S:60:0x91/0x94
+S:61:0x91/0x95
+S:62:0x91/0x96
+S:63:0x91/0x97
+
+# Spells (|)
+S:64:0x8F/0x80
+S:65:0x8F/0x84
+S:66:0x8F/0x88
+S:67:0x8F/0x8C
+S:68:0x8F/0x90
+S:69:0x8F/0x94
+S:70:0x8F/0x98
+S:71:0x8F/0x9C
+S:72:0x90/0x80
+S:73:0x90/0x84
+S:74:0x90/0x88
+S:75:0x90/0x8C
+S:76:0x90/0x90
+S:77:0x90/0x94
+S:78:0x90/0x98
+S:79:0x90/0x9C
+
+# Spells (-)
+S:80:0x8F/0x81
+S:81:0x8F/0x85
+S:82:0x8F/0x89
+S:83:0x8F/0x8D
+S:84:0x8F/0x91
+S:85:0x8F/0x95
+S:86:0x8F/0x99
+S:87:0x8F/0x9D
+S:88:0x90/0x81
+S:89:0x90/0x85
+S:90:0x90/0x89
+S:91:0x90/0x8D
+S:92:0x90/0x91
+S:93:0x90/0x95
+S:94:0x90/0x99
+S:95:0x90/0x9D
+
+# Spells (/)
+S:96:0x8F/0x82
+S:97:0x8F/0x86
+S:98:0x8F/0x8A
+S:99:0x8F/0x8E
+S:100:0x8F/0x92
+S:101:0x8F/0x96
+S:102:0x8F/0x9A
+S:103:0x8F/0x9E
+S:104:0x90/0x82
+S:105:0x90/0x86
+S:106:0x90/0x8A
+S:107:0x90/0x8E
+S:108:0x90/0x92
+S:109:0x90/0x96
+S:110:0x90/0x9A
+S:111:0x90/0x9E
+
+# Spells (\)
+S:112:0x8F/0x83
+S:113:0x8F/0x87
+S:114:0x8F/0x8B
+S:115:0x8F/0x8F
+S:116:0x8F/0x93
+S:117:0x8F/0x97
+S:118:0x8F/0x9B
+S:119:0x8F/0x9F
+S:120:0x90/0x83
+S:121:0x90/0x87
+S:122:0x90/0x8B
+S:123:0x90/0x8F
+S:124:0x90/0x93
+S:125:0x90/0x97
+S:126:0x90/0x9B
+S:127:0x90/0x9F
+
+# Amulets (")
+S:128:0x87/0x87
+S:129:0x87/0x80
+S:130:0x87/0x88
+S:131:0x87/0x82
+S:132:0x87/0x83
+S:133:0x87/0x84
+S:134:0x87/0x85
+S:135:0x87/0x86
+S:136:0x87/0x81
+S:137:0x87/0x81
+S:138:0x87/0x89
+S:139:0x87/0x8A
+S:140:0x87/0x8B
+S:141:0x87/0x8C
+S:142:0x87/0x8D
+S:143:0x87/0x8E
+
+# Rings (=)
+S:144:0x84/0x87
+S:145:0x84/0x80
+S:146:0x84/0x88
+S:147:0x84/0x82
+S:148:0x84/0x83
+S:149:0x84/0x84
+S:150:0x84/0x85
+S:151:0x84/0x86
+S:152:0x84/0x81
+S:153:0x84/0x81
+S:154:0x84/0x89
+S:155:0x84/0x8A
+S:156:0x84/0x8B
+S:157:0x84/0x8C
+S:158:0x84/0x8D
+S:159:0x84/0x8E
+
+# Staffs (_)
+S:160:0x87/0x96
+S:161:0x87/0x95
+S:162:0x87/0x95
+S:163:0x87/0x92
+S:164:0x87/0x92
+S:165:0x87/0x93
+S:166:0x87/0x95
+S:167:0x87/0x90
+S:168:0x87/0x95
+S:169:0x87/0x95
+S:170:0x87/0x92
+S:171:0x87/0x94
+S:172:0x87/0x92
+S:173:0x87/0x93
+S:174:0x87/0x96
+S:175:0x87/0x90
+
+# Wands (-)
+S:176:0x86/0x97
+S:177:0x86/0x90
+S:178:0x86/0x98
+S:179:0x86/0x92
+S:180:0x86/0x93
+S:181:0x86/0x94
+S:182:0x86/0x95
+S:183:0x86/0x96
+S:184:0x86/0x91
+S:185:0x86/0x91
+S:186:0x86/0x99
+S:187:0x86/0x9A
+S:188:0x86/0x9B
+S:189:0x86/0x9C
+S:190:0x86/0x9D
+S:191:0x86/0x9E
+
+# Rods (-)
+S:192:0x86/0x87
+S:193:0x86/0x80
+S:194:0x86/0x88
+S:195:0x86/0x82
+S:196:0x86/0x83
+S:197:0x86/0x84
+S:198:0x86/0x85
+S:199:0x86/0x86
+S:200:0x86/0x81
+S:201:0x86/0x81
+S:202:0x86/0x89
+S:203:0x86/0x8A
+S:204:0x86/0x8B
+S:205:0x86/0x8C
+S:206:0x86/0x8D
+S:207:0x86/0x8E
+
+# Scrolls (?)
+S:208:0x83/0x9C
+S:209:0x83/0x9D
+S:210:0x83/0x9E
+S:211:0x83/0x9F
+S:212:0x83/0x9C
+S:213:0x83/0x9D
+S:214:0x83/0x9E
+S:215:0x83/0x9F
+S:216:0x83/0x9C
+S:217:0x83/0x9D
+S:218:0x83/0x9E
+S:219:0x83/0x9F
+S:220:0x83/0x9C
+S:221:0x83/0x9D
+S:222:0x83/0x9E
+S:223:0x83/0x9F
+
+# Potions (!)
+S:224:0x85/0x87
+S:225:0x85/0x80
+S:226:0x85/0x88
+S:227:0x85/0x82
+S:228:0x85/0x83
+S:229:0x85/0x84
+S:230:0x85/0x85
+S:231:0x85/0x86
+S:232:0x85/0x81
+S:233:0x85/0x81
+S:234:0x85/0x89
+S:235:0x85/0x8A
+S:236:0x85/0x8B
+S:237:0x85/0x8C
+S:238:0x85/0x8D
+S:239:0x85/0x8E
+
+# Food (,)
+S:240:0x85/0x97
+S:241:0x85/0x90
+S:242:0x85/0x98
+S:243:0x85/0x92
+S:244:0x85/0x93
+S:245:0x85/0x94
+S:246:0x85/0x95
+S:247:0x85/0x96
+S:248:0x85/0x91
+S:249:0x85/0x91
+S:250:0x85/0x99
+S:251:0x85/0x9A
+S:252:0x85/0x9B
+S:253:0x85/0x9C
+S:254:0x85/0x9D
+S:255:0x85/0x9E
+
+# Elven
+G:M:12:0x91/0xA1
+
+# Dwarven
+G:M:13:0x91/0xA0
+
+# Spirit
+R:1045:0x92/0x9F
+R:1046:0x92/0xA0
+R:1047:0x92/0xA1
+R:1048:0x92/0xA2
+R:1049:0x92/0xA3
+R:1050:0x92/0xA4
+R:1051:0x92/0xA5
+R:1052:0x92/0xA6
+R:1053:0x92/0xA7
+R:1054:0x92/0xA8
+R:1055:0x92/0xA9
+R:1056:0x92/0xAA
+R:1057:0x92/0xA3
+R:1058:0x92/0xAB
+R:1059:0x92/0xAC
+R:1060:0x92/0xAD
+R:1061:0x92/0xAE
+R:1062:0x92/0xAF
+R:1063:0x92/0xB0
+R:1064:0x92/0xB1
+R:1065:0x92/0xB2
+R:1066:0x92/0xB3
+R:1067:0x92/0xB4
+R:1068:0x92/0xB5
+R:1069:0x92/0xB6
+R:1070:0x92/0xB7
+R:1071:0x92/0xB8
+R:1072:0x92/0xB9
+R:1073:0x92/0xBA
+R:1074:0x92/0xBB
+R:1075:0x92/0xBC
+
+# & Spellbook~ of #
+K:757:0x91/0xA4
+
+# Weakness Trap
+#G:T:1:0xFF/0xFF
+#G:T:2:0xFF/0xFF
+#G:T:3:0xFF/0xFF
+
+# Intelligence Trap
+#G:T:4:0xFF/0xFF
+#G:T:5:0xFF/0xFF
+#G:T:6:0xFF/0xFF
+
+# Wisdom Trap
+#G:T:7:0xFF/0xFF
+#G:T:8:0xFF/0xFF
+#G:T:9:0xFF/0xFF
+
+# Fumbling Fingers Trap
+#G:T:10:0xFF/0xFF
+#G:T:11:0xFF/0xFF
+#G:T:12:0xFF/0xFF
+
+# Wasting Trap
+#G:T:13:0xFF/0xFF
+#G:T:14:0xFF/0xFF
+#G:T:15:0xFF/0xFF
+
+# Beauty Trap
+#G:T:16:0xFF/0xFF
+#G:T:17:0xFF/0xFF
+#G:T:18:0xFF/0xFF
+
+# Trap of Curse Weapon
+#G:T:20:0xFF/0xFF
+
+# Trap of Curse Armor
+#G:T:21:0xFF/0xFF
+
+# Earthquake Trap
+#G:T:22:0xFF/0xFF
+
+# Poison Needle Trap
+#G:T:23:0xFF/0xFF
+
+# Summon Monster Trap
+#G:T:24:0xFF/0xFF
+
+# Summon Undead Trap
+#G:T:25:0xFF/0xFF
+
+# Summon Greater Undead Trap
+#G:T:26:0xFF/0xFF
+
+# Teleport Trap
+#G:T:27:0xFF/0xFF
+
+# Paralyzing Trap
+#G:T:28:0xFF/0xFF
+
+# Explosive Device
+#G:T:29:0xFF/0xFF
+
+# Teleport Item Trap
+#G:T:30:0xFF/0xFF
+
+# Lose Memory Trap
+#G:T:31:0xFF/0xFF
+
+# Bitter Regret Trap
+#G:T:32:0xFF/0xFF
+
+# Bowel Cramps Trap
+#G:T:33:0xFF/0xFF
+
+# Blindness
+#G:T:34:0xFF/0xFF
+
+# Aggravation Trap
+#G:T:35:0xFF/0xFF
+
+# Multiplication Trap
+#G:T:36:0xFF/0xFF
+
+# Steal Item Trap
+#G:T:37:0xFF/0xFF
+
+# Summon Fast Quylthulgs Trap
+#G:T:38:0xFF/0xFF
+
+# Trap of Sinking
+#G:T:39:0xFF/0xFF
+
+# Trap of Mana Drain
+#G:T:40:0xFF/0xFF
+
+# Trap of Missing Money
+#G:T:41:0xFF/0xFF
+
+# Trap of No Return
+#G:T:42:0xFF/0xFF
+
+# Trap of Silent Switching
+#G:T:43:0xFF/0xFF
+
+# Trap of Walls
+#G:T:44:0xFF/0xFF
+
+# Trap of Calling Out
+#G:T:45:0xFF/0xFF
+
+# Trap of Sliding
+#G:T:46:0xFF/0xFF
+
+# Trap of Charges Drain
+#G:T:47:0xFF/0xFF
+
+# Trap of Stair Movement
+#G:T:48:0xFF/0xFF
+
+# Trap of New Trap
+#G:T:49:0xFF/0xFF
+
+# Trap of Scatter Items
+#G:T:50:0xFF/0xFF
+
+# Trap of Decay
+#G:T:51:0xFF/0xFF
+
+# Trap of Wasting Wands
+#G:T:52:0xFF/0xFF
+
+# Trap of Filling
+#G:T:53:0xFF/0xFF
+
+# Trap of Drain Speed
+#G:T:54:0xFF/0xFF
+
+# Lightning Bolt Trap
+#G:T:60:0xFF/0xFF
+
+# Poison Bolt Trap
+#G:T:61:0xFF/0xFF
+
+# Acid Bolt Trap
+#G:T:62:0xFF/0xFF
+
+# Cold Bolt Trap
+#G:T:63:0xFF/0xFF
+
+# Fire Bolt Trap
+#G:T:64:0xFF/0xFF
+
+# Plasma Bolt Trap
+#G:T:65:0xFF/0xFF
+
+# Water Bolt Trap
+#G:T:66:0xFF/0xFF
+
+# Lite Bolt Trap
+#G:T:67:0xFF/0xFF
+
+# Dark Bolt Trap
+#G:T:68:0xFF/0xFF
+
+# Shards Bolt Trap
+#G:T:69:0xFF/0xFF
+
+# Sound Bolt Trap
+#G:T:70:0xFF/0xFF
+
+# Confusion Bolt Trap
+#G:T:71:0xFF/0xFF
+
+# Force Bolt Trap
+#G:T:72:0xFF/0xFF
+
+# Inertia Bolt Trap
+#G:T:73:0xFF/0xFF
+
+# Mana Bolt Trap
+#G:T:74:0xFF/0xFF
+
+# Ice Bolt Trap
+#G:T:75:0xFF/0xFF
+
+# Chaos Bolt Trap
+#G:T:76:0xFF/0xFF
+
+# Nether Bolt Trap
+#G:T:77:0xFF/0xFF
+
+# Disenchantment Bolt Trap
+#G:T:78:0xFF/0xFF
+
+# Nexus Bolt Trap
+#G:T:79:0xFF/0xFF
+
+# Time Bolt Trap
+#G:T:80:0xFF/0xFF
+
+# Gravity Bolt Trap
+#G:T:81:0xFF/0xFF
+
+# Lightning Ball Trap
+#G:T:82:0xFF/0xFF
+
+# Poison Ball Trap
+#G:T:83:0xFF/0xFF
+
+# Acid Ball Trap
+#G:T:84:0xFF/0xFF
+
+# Cold Ball Trap
+#G:T:85:0xFF/0xFF
+
+# Fire Ball Trap
+#G:T:86:0xFF/0xFF
+
+# Plasma Ball Trap
+#G:T:87:0xFF/0xFF
+
+# Water Ball Trap
+#G:T:88:0xFF/0xFF
+
+# Light Ball Trap
+#G:T:89:0xFF/0xFF
+
+# Darkness Ball Trap
+#G:T:90:0xFF/0xFF
+
+# Shards Ball Trap
+#G:T:91:0xFF/0xFF
+
+# Sound Ball Trap
+#G:T:92:0xFF/0xFF
+
+# Confusion Ball Trap
+#G:T:93:0xFF/0xFF
+
+# Force Ball Trap
+#G:T:94:0xFF/0xFF
+
+# Mana Ball Trap
+#G:T:96:0xFF/0xFF
+
+# Ice Ball Trap
+#G:T:97:0xFF/0xFF
+
+# Chaos Ball Trap
+#G:T:98:0xFF/0xFF
+
+# Nether Ball Trap
+#G:T:99:0xFF/0xFF
+
+# Disenchantment Ball Trap
+#G:T:100:0xFF/0xFF
+
+# Nexus Ball Trap
+#G:T:101:0xFF/0xFF
+
+# Time Ball Trap
+#G:T:102:0xFF/0xFF
+
+# Gravity Ball Trap
+#G:T:103:0xFF/0xFF
+
+# Arrow Trap
+#G:T:110:0xFF/0xFF
+
+# Bolt Trap
+#G:T:111:0xFF/0xFF
+
+# Seeker Arrow Trap
+#G:T:112:0xFF/0xFF
+
+# Seeker Bolt Trap
+#G:T:113:0xFF/0xFF
+
+# Poison Arrow Trap
+#G:T:114:0xFF/0xFF
+
+# Poison Bolt Trap
+#G:T:115:0xFF/0xFF
+
+# Poison Seeker Arrow Trap
+#G:T:116:0xFF/0xFF
+
+# Poison Seeker Bolt Trap
+#G:T:117:0xFF/0xFF
+
+# Broken Dagger Trap
+#G:T:118:0xFF/0xFF
+
+# Dagger Trap
+#G:T:119:0xFF/0xFF
+
+# Poison Broken Dagger Trap
+#G:T:120:0xFF/0xFF
+
+# Poison Dagger Trap
+#G:T:121:0xFF/0xFF
+
+# Arrows Trap
+#G:T:122:0xFF/0xFF
+
+# Bolts Trap
+#G:T:123:0xFF/0xFF
+
+# Seeker Arrow Trap
+#G:T:124:0xFF/0xFF
+
+# Seeker Bolt Trap
+#G:T:125:0xFF/0xFF
+
+# Poison Arrows Trap
+#G:T:126:0xFF/0xFF
+
+# Poison Bolt Trap
+#G:T:127:0xFF/0xFF
+
+# Poison Seeker Arrows Trap
+#G:T:128:0xFF/0xFF
+
+# Poison Seeker Bolts Trap
+#G:T:129:0xFF/0xFF
+
+# Broken Daggers Trap
+#G:T:130:0xFF/0xFF
+
+# Dagger Trap
+#G:T:131:0xFF/0xFF
+
+# Poison Broken Daggers Trap
+#G:T:132:0xFF/0xFF
+
+# Poison Daggers Trap
+#G:T:133:0xFF/0xFF
+
+# Trap of Drop Item
+#G:T:140:0xFF/0xFF
+
+# Trap of Drop Items
+#G:T:141:0xFF/0xFF
+
+# Trap of Drop Everything
+#G:T:142:0xFF/0xFF
+
+# Trap of Femininity
+#G:T:150:0xFF/0xFF
+
+# Trap of Masculinity
+#G:T:151:0xFF/0xFF
+
+# Trap of Neutrality
+#G:T:152:0xFF/0xFF
+
+# Trap of Aging
+#G:T:153:0xFF/0xFF
+
+# Trap of Growing
+#G:T:154:0xFF/0xFF
+
+# Trap of Shrinking
+#G:T:155:0xFF/0xFF
+
+# Trap of Tanker Drain
+#G:T:157:0xFF/0xFF
+
+# Trap of Divine Anger
+#G:T:158:0xFF/0xFF
+
+# Trap of Divine Wrath
+#G:T:159:0xFF/0xFF
+
+# Hallucination Trap
+#G:T:160:0xFF/0xFF
+
+# Greater Magic Missile Trap
+#G:T:161:0xFF/0xFF
+
+# Foulness Trap
+#G:T:162:0xFF/0xFF
+
+# Trap of Holy Fire
+#G:T:164:0xFF/0xFF
+
+# Trap of Hell Fire
+#G:T:165:0xFF/0xFF
+
+# Psi Bolt Trap
+#G:T:166:0xFF/0xFF
+
+# Psi Drain Trap
+#G:T:167:0xFF/0xFF
+
+# Plasma Ball Trap
+#G:T:168:0xFF/0xFF
+
+# Psi Ball Trap
+#G:T:169:0xFF/0xFF
+
+# Acquirement Trap
+#G:T:170:0xFF/0xFF
+
+# Greater Lightning Bolt Trap
+#G:T:171:0xFF/0xFF
+
+# Greater Poison Bolt Trap
+#G:T:172:0xFF/0xFF
+
+# Greater Acid Bolt Trap
+#G:T:173:0xFF/0xFF
+
+# Greater Cold Bolt Trap
+#G:T:174:0xFF/0xFF
+
+# Greater Fire Bolt Trap
+#G:T:175:0xFF/0xFF
+# non-defines encountered :
+# Load the special player pictures
+%:xtra-new.prf
diff --git a/lib/mods/theme/pref/graf-sdl.prf b/lib/mods/theme/pref/graf-sdl.prf
new file mode 100644
index 00000000..818f876a
--- /dev/null
+++ b/lib/mods/theme/pref/graf-sdl.prf
@@ -0,0 +1,37 @@
+# File: graf-x11.prf
+
+
+# Font stuff
+%:font-x11.prf
+
+
+# Color palette - Graphics
+
+#V:16:0x01:0x00:0x00:0x00
+#V:17:0x01:0xF0:0xE0:0xD0
+#V:18:0x01:0x80:0x80:0x80
+#V:19:0x01:0x50:0x50:0x50
+#V:20:0x01:0xE0:0xB0:0x00
+#V:21:0x01:0xC0:0xA0:0x70
+#V:22:0x01:0x80:0x60:0x40
+#V:23:0x01:0x50:0x3C:0x28
+#V:24:0x01:0x00:0xA0:0xF0
+#V:25:0x01:0x00:0x00:0xF0
+#V:26:0x01:0x00:0x00:0x70
+#V:27:0x01:0xF0:0x00:0x00
+#V:28:0x01:0x80:0x00:0x00
+#V:29:0x01:0x90:0x00:0xB0
+#V:30:0x01:0x00:0x60:0x10
+#V:31:0x01:0x60:0xF0:0x40
+
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
+
+?:1
+
diff --git a/lib/mods/theme/pref/graf-win.prf b/lib/mods/theme/pref/graf-win.prf
new file mode 100644
index 00000000..f59edb35
--- /dev/null
+++ b/lib/mods/theme/pref/graf-win.prf
@@ -0,0 +1,16 @@
+# File: graf-win.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
diff --git a/lib/mods/theme/pref/graf-x11.prf b/lib/mods/theme/pref/graf-x11.prf
new file mode 100644
index 00000000..818f876a
--- /dev/null
+++ b/lib/mods/theme/pref/graf-x11.prf
@@ -0,0 +1,37 @@
+# File: graf-x11.prf
+
+
+# Font stuff
+%:font-x11.prf
+
+
+# Color palette - Graphics
+
+#V:16:0x01:0x00:0x00:0x00
+#V:17:0x01:0xF0:0xE0:0xD0
+#V:18:0x01:0x80:0x80:0x80
+#V:19:0x01:0x50:0x50:0x50
+#V:20:0x01:0xE0:0xB0:0x00
+#V:21:0x01:0xC0:0xA0:0x70
+#V:22:0x01:0x80:0x60:0x40
+#V:23:0x01:0x50:0x3C:0x28
+#V:24:0x01:0x00:0xA0:0xF0
+#V:25:0x01:0x00:0x00:0xF0
+#V:26:0x01:0x00:0x00:0x70
+#V:27:0x01:0xF0:0x00:0x00
+#V:28:0x01:0x80:0x00:0x00
+#V:29:0x01:0x90:0x00:0xB0
+#V:30:0x01:0x00:0x60:0x10
+#V:31:0x01:0x60:0xF0:0x40
+
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
+
+?:1
+
diff --git a/lib/mods/theme/pref/graf-xxx.prf b/lib/mods/theme/pref/graf-xxx.prf
new file mode 100644
index 00000000..8be9d6da
--- /dev/null
+++ b/lib/mods/theme/pref/graf-xxx.prf
@@ -0,0 +1,3267 @@
+# PRF file generated by Andreas Koch`s Tile Assigner
+# at 12:19:29 AM
+
+# 2185 items
+# 2185 probably mapped correctly
+# 0 imported but not yet defined
+# 0 defined to value(s) lower than 0x80
+# Old header :
+### Special attr:char values ###
+# # Unused (@)
+# S:0x00:0x00:0x40
+# S:0x01:0x01:0x40
+# S:0x02:0x02:0x40
+# S:0x03:0x03:0x40
+# S:0x04:0x04:0x40
+# S:0x05:0x05:0x40
+# S:0x06:0x06:0x40
+# S:0x07:0x07:0x40
+# S:0x08:0x08:0x40
+# S:0x09:0x09:0x40
+# S:0x0A:0x0A:0x40
+# S:0x0B:0x0B:0x40
+# S:0x0C:0x0C:0x40
+# S:0x0D:0x0D:0x40
+# S:0x0E:0x0E:0x40
+# S:0x0F:0x0F:0x40
+# # Unused (@)
+# S:0x10:0x00:0x40
+# S:0x11:0x01:0x40
+# S:0x12:0x02:0x40
+# S:0x13:0x03:0x40
+# S:0x14:0x04:0x40
+# S:0x15:0x05:0x40
+# S:0x16:0x06:0x40
+# S:0x17:0x07:0x40
+# S:0x18:0x08:0x40
+# S:0x19:0x09:0x40
+# S:0x1A:0x0A:0x40
+# S:0x1B:0x0B:0x40
+# S:0x1C:0x0C:0x40
+# S:0x1D:0x0D:0x40
+# S:0x1E:0x0E:0x40
+# S:0x1F:0x0F:0x40
+# # Unused (@)
+# S:0x20:0x00:0x40
+# S:0x21:0x01:0x40
+# S:0x22:0x02:0x40
+# S:0x23:0x03:0x40
+# S:0x24:0x04:0x40
+# S:0x25:0x05:0x40
+# S:0x26:0x06:0x40
+# S:0x27:0x07:0x40
+# S:0x28:0x08:0x40
+# S:0x29:0x09:0x40
+# S:0x2A:0x0A:0x40
+# S:0x2B:0x0B:0x40
+# S:0x2C:0x0C:0x40
+# S:0x2D:0x0D:0x40
+# S:0x2E:0x0E:0x40
+# S:0x2F:0x0F:0x40
+
+# General Store
+B:0:0x81/0x91
+
+# Armoury
+B:1:0x81/0x92
+
+# Weapon Smiths
+B:2:0x81/0x93
+
+# Temple
+B:3:0x81/0x94
+
+# Alchemy Shop
+B:4:0x81/0x95
+
+# Magic Shop
+B:5:0x81/0x96
+
+# Black Market
+B:6:0x81/0x97
+
+# Home
+B:7:0x81/0x98
+
+# Bookstore
+B:8:0x82/0x93
+
+# Pet Shop
+B:9:0xCB/0x96
+
+# Mayor's Office
+B:10:0xCB/0x92
+
+# Inn
+B:11:0xCB/0x95
+
+# The Soothsayer
+B:12:0xD4/0x85
+
+# Library
+B:13:0xD4/0x89
+
+# Castle
+B:14:0xCB/0x92
+
+# Casino
+B:15:0xD5/0x81
+
+# Beastmaster Shanty
+B:16:0xD3/0x8B
+
+# Fighters Hall
+B:17:0xD3/0x8C
+
+# Tower of Magery
+B:18:0xD4/0x8B
+
+# Inner Temple
+B:19:0xD4/0x9D
+
+# Paladins Guild
+B:20:0xCB/0x8F
+
+# Rangers Guild
+B:21:0xD3/0x83
+
+# Weyr
+B:22:0xCB/0x93
+
+# The Mirror
+B:23:0xD4/0x89
+
+# Seat of Ruling
+B:24:0xCB/0x92
+
+# Wizards Spire
+B:25:0xD4/0x8A
+
+# Priests Circle
+B:26:0xD4/0x92
+
+# Tower of the King
+B:27:0xCB/0x92
+
+# Library
+B:28:0xD4/0x89
+
+# The White Tree
+B:29:0xCB/0x95
+
+# Craftsmaster
+B:30:0xCB/0x97
+
+# Earth-Dome (Nature)
+B:31:0xCB/0x9A
+
+# Minstrels Haven
+B:32:0xD3/0x9F
+
+# Star-Dome
+B:33:0xD4/0x8C
+
+# Valarin Temple
+B:34:0xD4/0x90
+
+# Sea-Dome
+B:35:0xD4/0x91
+
+# The Golden Flower
+B:36:0xD3/0x83
+
+# The Fountain
+B:37:0xD4/0x9D
+
+# Axe Smith
+B:38:0xCC/0x96
+
+# Hafted Smith
+B:39:0xCC/0x97
+
+# Polearm Smith
+B:40:0xCC/0x98
+
+# Sword Smith
+B:41:0xCC/0x80
+
+# Rare Jewelry Shop
+B:42:0xD3/0x96
+
+# Jewelry Shop
+B:43:0xD3/0x93
+
+# Footwear Shop
+B:44:0xD3/0x9D
+
+# Rare Footwear Shop
+B:45:0xD3/0x9E
+
+# Library
+B:46:0xD3/0x9C
+
+# Forbidden Library
+B:47:0xD4/0x8F
+
+# Expensive Black Market
+B:48:0xD4/0x95
+
+# Common Shop
+B:49:0xD4/0x93
+
+# Dragon Hunter
+B:50:0xCC/0x89
+
+# Speed Ring Market
+B:51:0xD3/0x97
+
+# Scribe
+B:52:0xD4/0x86
+
+# Potion Store
+B:53:0xD4/0x80
+
+# Recaller
+B:54:0xD4/0x88
+
+# Master Archer
+B:55:0xD3/0x85
+
+# Merchants Guild
+B:56:0xD4/0x9B
+
+# The Mathom-house
+B:57:0xCB/0x9B
+
+# The Prancing Pony
+B:58:0xCB/0x95
+
+# Mining Supply store
+B:59:0xCB/0x97
+
+# Library quest in Minas Anor
+B:60:0xD3/0x9C
+
+# Hunting Supply Store
+B:61:0xD3/0x85
+
+# Runic Magic Shop
+B:62:0x81/0x96
+
+# Construction Supply Store
+B:63:0xCB/0x97
+
+# Music Store
+B:64:0xD3/0x9F
+
+# Magic Rod Market
+B:65:0x81/0x96
+
+# Map store
+B:66:0xD3/0x9C
+
+# Farm
+B:67:0xD4/0x93
+
+#Pelargir inn - The Grey Swan
+B:68:0xCB/0x95
+
+#Caras Galadhon inn - The Garden
+B:69:0xCB/0x95
+
+#Khazad Dum inn - The Mithril Lode
+B:70:0xCB/0x95
+
+#Dale inn - The Builder Barracks
+B:71:0xCB/0x95
+
+#Edoras inn - The Horse and Ox
+B:72:0xCB/0x95
+
+#Esgaroth inn - The Dancing Dragon
+B:73:0xCB/0x95
+
+#Hobbiton inn - The Green Dragon
+B:74:0xCB/0x95
+
+#Osgiliath inn - The Twinkling Star
+B:75:0xCB/0x95
+
+#The House of Beorn
+B:76:0xCB/0x92
+
+#Bard's Hut
+B:77:0xCB/0x92
+
+#The Ranger Conclave
+B:78:0xCB/0x92
+
+#Imladris
+B:79:0xCB/0x92
+
+#The Hornburg
+B:80:0xCB/0x92
+
+#Thranduil's Hall
+B:81:0xCB/0x92
+
+#Meduseld
+B:82:0xCB/0x92
+
+#The Master's House
+B:83:0xCB/0x92
+
+#Bag End
+B:84:0xCB/0x92
+
+#The Castle of Stars
+B:85:0xCB/0x92
+
+#The Prince's Tower
+B:86:0xCB/0x92
+
+#The Seat of Durin
+B:87:0xCB/0x92
+
+### The forge in Imladris
+B:88:0xCB/0x97
+
+# nothing
+F:0:0x81/0x80
+
+# open floor
+F:1:0x80/0x80
+
+# fountain - wet
+F:2:0xD1/0x83
+
+# glyph of warding
+F:3:0xA2/0x88
+
+# open door
+F:4:0x81/0x87
+
+# broken door
+F:5:0x81/0x87
+
+# up staircase
+F:6:0x81/0x9C
+
+# down staircase
+F:7:0x81/0x9E
+
+# quest entrance
+F:8:0x82/0x8E
+
+# quest exit
+F:9:0x82/0x8B
+
+# quest down level
+F:10:0x82/0x8F
+
+# quest up level
+F:11:0x82/0x8C
+
+# town exit
+F:12:0x82/0x91
+
+# shaft down
+F:13:0x82/0x90
+
+# shaft up
+F:14:0x82/0x8D
+
+# fountain
+F:15:0xD1/0x82
+
+# web
+F:16:0x82/0x92
+
+# Open pit
+F:17:0xA2/0x96
+
+# Spiked Pit
+F:18:0xA2/0x96
+
+# Poison Pit
+F:19:0xA2/0x96
+
+# Summon Rune
+F:20:0x8A/0x9C
+
+# Teleport Rune
+F:21:0x8A/0x9C
+
+# Fire spot
+F:22:0x8A/0x9B
+
+# Acid spot
+F:23:0x8A/0x9B
+
+# Slow dart trap
+F:24:0x82/0x9E
+
+# Lose str dart
+F:25:0xA2/0x89
+
+# Lose dex dart
+F:26:0xA2/0x8D
+
+# Lose con dart
+F:27:0xA2/0x92
+
+# gas trap - blind
+F:28:0xA2/0x8E
+
+# gas trap - confuse
+F:29:0xA2/0x8F
+
+# gas trap - poison
+F:30:0xA2/0x90
+
+# gas trap - sleep
+F:31:0xA2/0x91
+
+# door
+F:32:0x81/0x8B
+
+# locked door
+F:33:0x81/0x8B
+F:34:0x81/0x8B
+F:35:0x81/0x8B
+F:36:0x81/0x8B
+F:37:0x81/0x8B
+F:38:0x81/0x8B
+F:39:0x81/0x8B
+
+# jammed door
+F:40:0x81/0x8B
+F:41:0x81/0x8B
+F:42:0x81/0x8B
+F:43:0x81/0x8B
+F:44:0x81/0x8B
+F:45:0x81/0x8B
+F:46:0x81/0x8B
+F:47:0x81/0x8B
+
+# secret door
+F:48:0x80/0x82
+
+# pile of rubble
+F:49:0x81/0x9A
+
+# magma vein
+F:50:0x81/0x83
+
+# quartz vein
+F:51:0x80/0x83
+
+# magma vein
+F:52:0x81/0x83
+
+# quartz vein
+F:53:0x80/0x83
+
+# magma vein with treasure
+F:54:0x80/0x84
+
+# quartz vein with treasure
+F:55:0x80/0x84
+
+# granite wall
+F:56:0x80/0x82
+F:57:0x80/0x82
+F:58:0x80/0x82
+F:59:0x80/0x82
+
+# permanent wall
+F:60:0x80/0x95
+F:61:0x80/0x95
+F:62:0x80/0x95
+F:63:0x80/0x95
+
+# explosive rune
+F:64:0xA2/0x87
+
+# Straight Road startpoint
+F:65:0xA3/0x9D
+
+# section of the Straight Road
+F:66:0xA3/0x97
+F:67:0xA3/0x9C
+F:68:0xA3/0x9B
+F:69:0xA3/0x9A
+F:70:0xA3/0x98
+
+# section of the Straight Road (discharged)
+F:71:0xA3/0x98
+
+# Straight Road exit
+F:72:0xA3/0x9D
+
+# corrupted section of the Straight Road
+F:73:0xA3/0x99
+
+# Building
+F:74:0x81/0x91
+
+# permanent wall
+F:75:0x80/0x95
+F:76:0x80/0x95
+F:77:0x80/0x95
+F:78:0x80/0x95
+
+# grass with Elanor flowers
+F:79:0x82:0x95
+
+# grass with Fumella flowers
+F:80:0x82:0x96
+
+# grass with anemones
+F:81:0x82:0x97
+
+# grass with Niphredil flowers
+F:82:0x82:0x98
+
+# grass with irises
+F:83:0x82:0x99
+
+# stream of shallow water
+F:84:0xD2/0x81
+
+# pool of deep lava
+F:85:0xCB/0x89
+
+# stream of shallow lava
+F:86:0xCB/0x88
+
+# dark pit
+F:87:0x81/0x80
+
+# dirt
+F:88:0xCB/0x84
+
+# patch of grass
+F:89:0xD0/0x8E
+
+# ice
+F:90:0xCF/0x81
+
+# sand
+F:91:0xCF/0x8E
+
+# dead tree
+F:92:0xCF/0x85
+
+# ash
+F:93:0xCF/0x95
+
+# mud
+F:94:0xCF/0x8D
+
+# ice wall
+F:95:0xD0/0x88
+
+# tree
+F:96:0xCB/0x86
+
+# mountain chain
+F:97:0xCB/0x87
+
+# sandwall
+F:98:0xD0/0x87
+F:99:0xD0/0x87
+
+# sandwall with treasure
+F:100:0xD0/0x8A
+
+# high mountain chain
+F:101:0xCB/0x87
+
+# nether mist
+F:102:0xC5/0x8C
+
+# molten glass wall
+F:103:0xD0/0x89
+
+# Between gate
+F:160:0x8A/0x9D
+
+# Altar of Forests
+F:161:0xD1/0x85
+
+# Altar of Water
+F:162:0xD1/0x86
+
+# Altar of Earth
+F:163:0xD1/0x8E
+
+# Altar of Darkness
+F:164:0xD1/0x88
+
+# Altar of Moon
+F:165:0xD1/0x89
+
+# Altar of Sun
+F:166:0xD1/0x8C
+
+# Altar of Rage
+F:167:0xD1/0x8A
+
+# Altar of Winds
+F:168:0xD1/0x8B
+
+# Altar of Stars
+F:169:0xD1/0x8D
+
+# Altar of Being
+F:170:0xD1/0x87
+
+# Altar of Randomness
+F:171:0xD1/0x8F
+
+# floor
+F:172:0x80/0x80
+
+# Underground Tunnel
+F:173:0xCF/0x97
+
+# stream of tainted water
+F:174:0xD2/0x82
+
+# monster trap
+F:175:0x82/0x94
+
+# Between gate
+F:176:0x8A/0x9D
+
+# lava wall
+F:177:0xD0/0x86
+
+# Great Fire
+F:178:0xD1/0x90
+
+# Path to next area
+F:179:0xCF/0x9C
+
+# Path to previous area
+F:180:0xCF/0x9B
+
+# field
+F:181:0xCF/0x8A
+
+# Ekkaia, the Encircling Sea
+F:182:0xD2/0x84
+
+# pool of deep water
+F:187:0xD2/0x80
+
+# glass wall
+F:188:0xD0/0x89
+
+# illusion wall
+F:189:0xD0/0x8C
+
+# Grass roof
+F:190:0xD0/0x8F
+
+# grass roof top
+F:191:0xD0/0x8F
+
+# grass roof chimney
+F:192:0xD0/0x8F
+
+# brick roof
+F:193:0xD0/0x90
+
+# brick roof top
+F:194:0xD0/0x90
+
+# brick roof chimney
+F:195:0xD0/0x90
+
+# window
+F:196:0xD0/0x91
+
+# small window
+F:197:0xD0/0x92
+
+# rain barrel
+F:198:0xD0/0x93
+
+# grass with flowers
+F:199:0xD0/0x8D
+
+# cobblestone road
+F:200:0x82/0x8A
+
+# cobblestone with outlet
+F:201:0x82/0x8A
+
+# small tree
+F:202:0xD0/0x8B
+
+# town
+F:203:0xD0/0x94
+
+# Underground Tunnel
+F:204:0xD0/0x95
+
+# a blazing fire
+F:205:0xD1/0x84
+
+# pile of rubble
+F:206:0x81/0x9A
+
+# rocky ground
+F:207:0x82:0x9A
+
+# cloud-like vapour
+F:208:0x82:0x9B
+
+# condensing water
+F:209:0x82:0x9C
+
+# dense mist
+F:210:0x82:0x9D
+
+# hail-stone wall
+F:211:0x83:0x80
+
+# dead small tree
+F:212:0x83:0x83
+
+# low hill
+F:213:0x83:0x84
+
+# dark mountain chain
+F:214:0x83:0x85
+
+# blue mountain chain
+F:215:0x83:0x86
+
+# grey mountain chain
+F:216:0x83:0x87
+
+# part of Mount Doom
+F:217:0x83:0x88
+
+# snow-capped peak
+F:218:0x83:0x89
+
+# fir tree
+F:219:0x83:0x8A
+
+# section of a flet
+F:220:0x83:0x8B
+
+# light post
+F:221:0x83:0x8C
+
+# water lily
+F:222:0x83:0x8D
+
+# part of the Dead Marshes
+F:223:0x83:0x8E
+
+# Black Gate
+F:224:0x83:0x8F
+
+# river
+F:225:0x83:0x90
+
+# swamp pool
+F:226:0x83:0x91
+
+# stream of the Anduin river
+F:227:0x83:0x92
+
+# road sign that says 'Hurry to Gondolin!'
+F:228:0x83:0x93
+
+# beehive
+F:229:0x83:0x94
+
+# dirt road
+F:230:0x83:0x95
+
+# wide gate
+F:231:0x83:0x96
+
+# open gate
+F:232:0x83:0x97
+
+# wooden board
+F:233:0x83:0x98
+
+# wooden board
+F:234:0x83:0x99
+
+# wooden board
+F:235:0x83:0x9A
+
+# wooden board
+F:236:0x83:0x9B
+
+# white tree
+F:237:0x83:0x9C
+
+# swift waterfall
+F:238:0x83:0x9D
+
+# slippery rock ledge
+F:239:0x82:0x9A
+
+# stable
+F:240:0x83:0x9E
+
+# wooden plank
+F:241:0x83:0x9F
+
+# fosse pit
+F:242:0x82:0x9F
+
+# Mallorn
+F:243:0x81:0x9F
+
+# copper pillar
+F:244:0x86:0x93
+
+# ethereal wall
+F:245:0x80:0x80
+
+# glacial wall
+F:246:0xD0:0x88
+
+# battlement
+F:247:0x86:0x98
+
+# door of Orthanc
+F:248:0x04:0x27
+
+# something
+K:0:0x80:0x80
+
+# Blindness
+K:1:0xBA:0x81
+
+# Fear
+K:2:0xBA:0x81
+
+# Confusion
+K:3:0xBA:0x81
+
+# Hallucination
+K:4:0xBA:0x81
+
+# Cure Poison
+K:5:0xBA:0x81
+
+# Cure Blindness
+K:6:0xBA:0x81
+
+# Cure Fear
+K:7:0xBA:0x81
+
+# Cure Confusion
+K:8:0xBA:0x81
+
+# Weakness
+K:9:0xBA:0x81
+
+# Unhealth
+K:10:0xBA:0x81
+
+# Restore Constitution
+K:11:0xBA:0x81
+
+# Restoring
+K:12:0xBA:0x81
+
+# Stupidity
+K:13:0xBA:0x81
+
+# Naivety
+K:14:0xBA:0x81
+
+# Poison
+K:15:0xBA:0x81
+
+# Sickness
+K:16:0xBA:0x81
+
+# Paralysis
+K:17:0xBA:0x81
+
+# Restore Strength
+K:18:0xBA:0x81
+
+# Disease
+K:19:0xBA:0x81
+
+# Cure Serious Wounds
+K:20:0xBA:0x81
+
+# & Ration~ of Cram
+K:21:0x8B:0x82
+
+# & Round Seed-Cake~
+K:22:0x8B:0x82
+
+# & Strip~ of Venison
+K:23:0x8B:0x82
+
+# & Slime Mold~
+K:24:0x8A:0x9F
+
+# & Lembas~
+K:25:0x8B:0x80
+
+# & Pint~ of Fine Ale
+K:26:0x8A:0x95
+
+# & Pint~ of Old Winyards
+K:27:0x8A:0x96
+
+# & Mattock~
+K:28:0xCD:0x80
+
+# & Blue Stone~
+K:29:0xB6:0x89
+
+# & Broken Dagger~
+K:30:0x89:0x83
+
+# & Bastard Sword~
+K:31:0x89:0x85
+
+# & Scimitar~
+K:32:0x89:0x85
+
+# & Tulwar~
+K:33:0x89:0x84
+
+# & Broad Sword~
+K:34:0x89:0x85
+
+# & Short Sword~
+K:35:0x89:0x84
+
+# & Blade~ of Chaos
+K:36:0x89:0x87
+
+# & Two-Handed Sword~
+K:37:0x89:0x85
+
+# & Main Gauche~
+K:38:0x89:0x83
+
+# & Cutlass~
+K:39:0x89:0x84
+
+# & Executioner's Sword~
+K:40:0x89:0x86
+
+# & Katana~
+K:41:0x89:0x85
+
+# & Long Sword~
+K:42:0x89:0x85
+
+# & Dagger~
+K:43:0x89:0x83
+
+# & Rapier~
+K:44:0x89:0x84
+
+# & Sabre~
+K:45:0x89:0x84
+
+# & Small Sword~
+K:46:0x89:0x84
+
+# & Broken Sword~
+K:47:0x89:0x83
+
+# & Ball-and-Chain~
+K:48:0x89:0x88
+
+# & Whip~
+K:49:0x89:0x89
+
+# & Flail~
+K:50:0x89:0x8B
+
+# & Two-Handed Flail~
+K:51:0x89:0x8B
+
+# & Morning Star~
+K:52:0x89:0x8B
+
+# & Mace~
+K:53:0x89:0x8C
+
+# & Quarterstaff~
+K:54:0x89:0x8E
+
+# & War Hammer~
+K:55:0x89:0x8F
+
+# & Lead-Filled Mace~
+K:56:0x89:0x8C
+
+# & Mace~ of Disruption
+K:57:0x89:0x8D
+
+# & Lucerne Hammer~
+K:58:0x89:0x90
+
+# & Beaked Axe~
+K:59:0x89:0x90
+
+# & Glaive~
+K:60:0x89:0x90
+
+# & Halberd~
+K:61:0x89:0x90
+
+# & Awl-Pike~
+K:62:0x89:0x91
+
+# & Pike~
+K:63:0x89:0x91
+
+# & Spear~
+K:64:0x89:0x91
+
+# & Trident~
+K:65:0x89:0x92
+
+# & Lance~
+K:66:0x89:0x93
+
+# & Great Axe~
+K:67:0x89:0x90
+
+# & Battle Axe~
+K:68:0x89:0x90
+
+# & Lochaber Axe~
+K:69:0x89:0x90
+
+# & Broad Axe~
+K:70:0x89:0x90
+
+# & Scythe~
+K:71:0x89:0x94
+
+# & Scythe~ of Slicing
+K:72:0x89:0x94
+
+# & Short Bow~
+K:73:0x89:0x95
+
+# & Long Bow~
+K:74:0x89:0x96
+
+# & Light Crossbow~
+K:75:0x89:0x97
+
+# & Heavy Crossbow~
+K:76:0x89:0x98
+
+# & Sling~
+K:77:0x89:0x99
+
+# & Arrow~
+K:78:0x89:0x9A
+
+# & Seeker Arrow~
+K:79:0x89:0x9B
+
+# & Bolt~
+K:80:0x89:0x9C
+
+# & Seeker Bolt~
+K:81:0x89:0x9D
+
+# & Rounded Pebble~
+K:82:0x89:0x9E
+
+# & Iron Shot~
+K:83:0x89:0x9F
+
+# & Shovel~
+K:84:0x8A:0x98
+
+# & Gnomish Shovel~
+K:85:0x8B:0x8F
+
+# & Dwarven Shovel~
+K:86:0x8B:0x90
+
+# & Pick~
+K:87:0x8A:0x97
+
+# & Orcish Pick~
+K:88:0x8B:0x8D
+
+# & Dwarven Pick~
+K:89:0x8B:0x8E
+
+# & Elven Cloak~
+K:90:0x88:0x81
+
+# & Pair~ of Soft Leather Boots
+K:91:0x88:0x89
+
+# & Pair~ of Hard Leather Boots
+K:92:0x88:0x8A
+
+# & Pair~ of Metal Shod Boots
+K:93:0x88:0x8B
+
+# & Hard Leather Cap~
+K:94:0x88:0x82
+
+# & Metal Cap~
+K:95:0x88:0x83
+
+# & Iron Helm~
+K:96:0x88:0x84
+
+# & Steel Helm~
+K:97:0x88:0x85
+
+# & Iron Crown~
+K:98:0x88:0x86
+
+# & Golden Crown~
+K:99:0x88:0x87
+
+# & Jewel-Encrusted Crown~
+K:100:0x88:0x88
+
+# & Robe~
+K:101:0x88:0x95
+
+# & Filthy Rag~
+K:102:0x88:0x94
+
+# Soft Leather Armour~
+K:103:0x88:0x96
+
+# Soft Studded Leather~
+K:104:0x88:0x96
+
+# Hard Leather Armour~
+K:105:0x88:0x97
+
+# Hard Studded Leather~
+K:106:0x88:0x97
+
+# Leather Scale Mail~
+K:107:0x88:0x98
+
+# Metal Scale Mail~
+K:108:0x88:0x98
+
+# Chain Mail~
+K:109:0x88:0x99
+
+# Rusty Chain Mail~
+K:110:0x88:0x9A
+
+# Augmented Chain Mail~
+K:111:0x88:0x99
+
+# Bar Chain Mail~
+K:112:0x88:0x99
+
+# Metal Brigandine Armour~
+K:113:0x88:0x99
+
+# Partial Plate Armour~
+K:114:0x88:0x9B
+
+# Metal Lamellar Armour~
+K:115:0x88:0x9B
+
+# Full Plate Armour~
+K:116:0xCD:0x82
+
+# Ribbed Plate Armour~
+K:117:0x88:0x9B
+
+# Galvorn Plate Mail~
+K:118:0xA3:0x96
+
+# Mithril Plate Mail~
+K:119:0x85:0x96
+
+# Mithril Chain Mail~
+K:120:0x85:0x96
+
+# Double Chain Mail~
+K:121:0x88:0x99
+
+# & Shield~ of Deflection
+K:122:0x88:0x93
+
+# & Cloak~
+K:123:0x88:0x80
+
+# & Shadow Cloak~
+K:124:0x88:0x81
+
+# & Set~ of Leather Gloves
+K:125:0x88:0x8C
+
+# & Set~ of Gauntlets
+K:126:0x88:0x8D
+
+# & Set~ of Cesti
+K:127:0x88:0x8E
+
+# & Small Leather Shield~
+K:128:0x88:0x8F
+
+# & Large Leather Shield~
+K:129:0x88:0x90
+
+# & Small Metal Shield~
+K:130:0x88:0x91
+
+# & Large Metal Shield~
+K:131:0x88:0x92
+
+# Strength
+K:132:0xB5:0x81
+
+# Dexterity
+K:133:0xB5:0x81
+
+# Constitution
+K:134:0xB5:0x81
+
+# Intelligence
+K:135:0xB5:0x81
+
+# Speed
+K:136:0xB5:0x83
+
+# Searching
+K:137:0xB5:0x80
+
+# Teleportation
+K:138:0xB5:0x80
+
+# Slow Digestion
+K:139:0xB5:0x80
+
+# Fire Resistance
+K:140:0xB5:0x80
+
+# Cold Resistance
+K:141:0xB5:0x80
+
+# Levitation
+K:142:0xB5:0x80
+
+# Poison Resistance
+K:143:0xB5:0x82
+
+# Free Action
+K:144:0xB5:0x80
+
+# Weakness
+K:145:0xB5:0x80
+
+# Flames
+K:146:0xB5:0x82
+
+# Acid
+K:147:0xB5:0x82
+
+# Ice
+K:148:0xB5:0x82
+
+# Woe
+K:149:0xB5:0x82
+
+# Stupidity
+K:150:0xB5:0x80
+
+# Damage
+K:151:0xB5:0x81
+
+# Accuracy
+K:152:0xB5:0x81
+
+# Protection
+K:153:0xB5:0x80
+
+# Aggravate Monster
+K:154:0xB5:0x80
+
+# See Invisible
+K:155:0xB5:0x81
+
+# Sustain Strength
+K:156:0xB5:0x81
+
+# Sustain Intelligence
+K:157:0xB5:0x81
+
+# Sustain Wisdom
+K:158:0xB5:0x81
+
+# Sustain Constitution
+K:159:0xB5:0x81
+
+# Sustain Dexterity
+K:160:0xB5:0x81
+
+# Sustain Charisma
+K:161:0xB5:0x81
+
+# Slaying
+K:162:0xB5:0x81
+
+# Brilliance
+K:163:0xB6:0x9F
+
+# Charisma
+K:164:0xB6:0x9F
+
+# Searching
+K:165:0xB6:0x9E
+
+# Teleportation
+K:166:0xB6:0x9E
+
+# Slow Digestion
+K:167:0xB6:0x9E
+
+# Acid Resistance
+K:168:0xB6:0x9E
+
+# Protection from Evil
+K:169:0xB6:0x9E
+
+# Double Ring Mail~
+K:170:0xCD:0x83
+
+# the Magi
+K:171:0xB6:0x80
+
+# Doom
+K:172:0xB6:0x80
+
+# Enchant Weapon To-Hit
+K:173:0x86:0x80
+
+# Enchant Weapon To-Dam
+K:174:0x86:0x80
+
+# Enchant Armor
+K:175:0x86:0x80
+
+# Identify
+K:176:0x86:0x80
+
+# *Identify*
+K:177:0x86:0x82
+
+# Rumour
+K:178:0x86:0x80
+
+# Chaos
+K:179:0x86:0x80
+
+# Remove Curse
+K:180:0x86:0x80
+
+# Light
+K:181:0x86:0x80
+
+# Fire
+K:182:0x86:0x80
+
+# Ice
+K:183:0x86:0x80
+
+# Summon Monsters
+K:184:0x86:0x80
+
+# Phase Door
+K:185:0x86:0x80
+
+# Teleportation
+K:186:0x86:0x80
+
+# Teleport Level
+K:187:0x86:0x80
+
+# Monster Confusion
+K:188:0x86:0x80
+
+# Magic Mapping
+K:189:0x86:0x80
+
+# Rune of Protection
+K:190:0x86:0x82
+
+# *Remove Curse*
+K:191:0x86:0x82
+
+# Treasure Detection
+K:192:0x86:0x80
+
+# Object Detection
+K:193:0x86:0x80
+
+# Trap Detection
+K:194:0x86:0x80
+
+# & Sheaf Arrow~
+K:195:0xCD:0x84
+
+# & Mithril Shot~
+K:196:0xCD:0x85
+
+# Door/Stair Location
+K:197:0x86:0x80
+
+# Acquirement
+K:198:0x86:0x80
+
+# *Acquirement*
+K:199:0x86:0x82
+
+# Mass Genocide
+K:200:0x86:0x82
+
+# Detect Invisible
+K:201:0x86:0x80
+
+# Aggravation
+K:202:0x86:0x80
+
+# Trap Creation
+K:203:0x86:0x80
+
+# Trap/Door Destruction
+K:204:0x86:0x80
+
+# Artifact Creation
+K:205:0x86:0x82
+
+# Recharging
+K:206:0x86:0x81
+
+# Genocide
+K:207:0x86:0x81
+
+# Darkness
+K:208:0x86:0x80
+
+# Protection from Evil
+K:209:0x86:0x81
+
+# Satisfy Hunger
+K:210:0x86:0x80
+
+# Dispel Undead
+K:211:0x86:0x81
+
+# *Enchant Weapon*
+K:212:0x86:0x82
+
+# Curse Weapon
+K:213:0x86:0x82
+
+# *Enchant Armour*
+K:214:0x86:0x82
+
+# Curse Armour
+K:215:0x86:0x82
+
+# Summon Undead
+K:216:0x86:0x80
+
+# Blessing
+K:217:0x86:0x80
+
+# Holy Chant
+K:218:0x86:0x80
+
+# Holy Prayer
+K:219:0x86:0x81
+
+# Word of Recall
+K:220:0x86:0x80
+
+# *Destruction*
+K:221:0x86:0x82
+
+# Slime Mold Juice
+K:222:0xBC:0x85
+
+# Apple Juice
+K:223:0xBC:0x85
+
+# Water
+K:224:0xBC:0x85
+
+# Strength
+K:225:0xBC:0x86
+
+# Weakness
+K:226:0xBC:0x85
+
+# Restore Strength
+K:227:0xBC:0x86
+
+# Intelligence
+K:228:0xBC:0x86
+
+# Stupidity
+K:229:0xBC:0x85
+
+# Restore Intelligence
+K:230:0xBC:0x86
+
+# Wisdom
+K:231:0xBC:0x86
+
+# Naivety
+K:232:0xBC:0x85
+
+# Restore Wisdom
+K:233:0xBC:0x86
+
+# Charisma
+K:234:0xBC:0x86
+
+# Ugliness
+K:235:0xBC:0x86
+
+# Restore Charisma
+K:236:0xBC:0x86
+
+# Curing
+K:237:0xBC:0x86
+
+# Invulnerability
+K:238:0xBC:0x86
+
+# New Life
+K:239:0xBC:0x86
+
+# Cure Serious Wounds
+K:240:0xBC:0x85
+
+# Cure Critical Wounds
+K:241:0xBC:0x85
+
+# Healing
+K:242:0xBC:0x85
+
+# Constitution
+K:243:0xBC:0x86
+
+# Experience
+K:244:0xBC:0x87
+
+# Sleep
+K:245:0xBC:0x85
+
+# Blindness
+K:246:0xBC:0x85
+
+# Booze
+K:247:0xBC:0x85
+
+# Poison
+K:248:0xBC:0x85
+
+# Speed
+K:249:0xBC:0x85
+
+# Slowness
+K:250:0xBC:0x85
+
+# Dexterity
+K:251:0xBC:0x86
+
+# Restore Dexterity
+K:252:0xBC:0x86
+
+# Restore Constitution
+K:253:0xBC:0x86
+
+# Lose Memories
+K:254:0xBC:0x85
+
+# Salt Water
+K:255:0xBC:0x85
+
+# Enlightenment
+K:256:0xBC:0x85
+
+# Heroism
+K:257:0xBC:0x85
+
+# Berserk Strength
+K:258:0xBC:0x85
+
+# Boldness
+K:259:0xBC:0x85
+
+# Restore Life Levels
+K:260:0xBC:0x87
+
+# Resist Heat
+K:261:0xBC:0x85
+
+# Resist Cold
+K:262:0xBC:0x85
+
+# Detect Invisible
+K:263:0xBC:0x85
+
+# Slow Poison
+K:264:0xBC:0x85
+
+# Neutralise Poison
+K:265:0xBC:0x85
+
+# Restore Mana
+K:266:0xBC:0x86
+
+# Infra-vision
+K:267:0xBC:0x85
+
+# Resistance
+K:268:0xBC:0x85
+
+# Spell
+K:269:0xB7:0x8F
+
+# Manathrust
+K:270:0xB7:0x8F
+
+# Fireflash
+K:271:0xB7:0x8F
+
+# Firewall
+K:272:0xB7:0x90
+
+# Tidal Wave
+K:273:0xB7:0x8F
+
+# Ice Storm
+K:274:0xB7:0x8F
+
+# Noxious Cloud
+K:275:0xB7:0x8F
+
+# Poison Blood
+K:276:0xB7:0x8F
+
+# Thunderstorm
+K:277:0xB7:0x8F
+
+# Dig
+K:278:0xB7:0x8F
+
+# Stone Prison
+K:279:0xB7:0x8F
+
+# Strike
+K:280:0xB7:0x91
+
+# Teleport Away
+K:281:0xB7:0x8F
+
+# Summon Animal
+K:282:0xB7:0x8F
+
+# Magelock
+K:283:0xB7:0x90
+
+# Slow Monster
+K:284:0xB7:0x90
+
+# Essence of Speed
+K:285:0xB7:0x8F
+
+# Banishment
+K:286:0xB7:0x8F
+
+# Disperse Magic
+K:287:0xB7:0x90
+
+# Charm
+K:288:0xB7:0x90
+
+# Confuse
+K:289:0xB7:0x91
+
+# Demon Blade
+K:290:0xB7:0x8F
+
+# Heal Monster
+K:291:0xB7:0x91
+
+# Haste Monster
+K:292:0xB7:0x8F
+
+# & Flight Arrow~
+K:293:0xCD:0x86
+
+# & Boulder~
+K:295:0x85:0x97
+
+# & Flame~ Imperishable
+K:296:0x85:0x98
+
+# & Necromantic Teeth~
+K:297:0x85:0x99
+
+# & Golden Horn~ of the Eagles
+K:298:0xB7:0x91
+
+# Spell
+K:300:0xB9:0x99
+
+# Nothing
+K:301:0xB9:0x99
+
+# Globe of Light
+K:302:0xB9:0x99
+
+# Fiery Shield
+K:303:0xB9:0x99
+
+# Remove Curses
+K:304:0xB9:0x9A
+
+# Wings of Winds
+K:305:0xB9:0x99
+
+# Shake
+K:306:0xB9:0x99
+
+# Disarm
+K:307:0xB9:0x9B
+
+# Teleportation
+K:308:0xB9:0x99
+
+# Probability Travel
+K:309:0xB9:0x99
+
+# Recovery
+K:310:0xB9:0x99
+
+# Healing
+K:311:0xB9:0x99
+
+# Vision
+K:312:0xB9:0x99
+
+# Identify
+K:313:0xB9:0x99
+
+# Sense Hidden
+K:314:0xB9:0x9A
+
+# Reveal Ways
+K:315:0xB9:0x99
+
+# Sense Monsters
+K:316:0xB9:0x99
+
+# Genocide
+K:317:0xB9:0x9A
+
+# Summon
+K:318:0xB9:0x99
+
+# Sterilization
+K:319:0xB9:0x9A
+
+# Wish
+K:320:0xB9:0x9B
+
+# Mana
+K:321:0xB9:0x9A
+
+# & Tome~ of Magical Energy
+K:330:0xA3:0x8A
+
+# & Tome~ of the Eternal Flame
+K:331:0xA3:0x8A
+
+# & Tome~ of the Blowing Wind
+K:332:0xA3:0x8A
+
+# & Tome~ of the Impenetrable Earth
+K:333:0xA3:0x8A
+
+# & Tome~ of the Everrunning Wave
+K:334:0xA3:0x8C
+
+# & Tome~ of Translocation
+K:335:0xA3:0x8C
+
+# & Tome~ of the Tree
+K:336:0xA3:0x8C
+
+# & Tome~ of Knowledge
+K:337:0xA3:0x8C
+
+# & Small wooden chest~
+K:338:0x80:0x96
+
+# & Large wooden chest~
+K:339:0x80:0x97
+
+# & Small iron chest~
+K:340:0x80:0x98
+
+# & Large iron chest~
+K:341:0x80:0x99
+
+# & Small steel chest~
+K:342:0x80:0x9A
+
+# & Large steel chest~
+K:343:0x80:0x9B
+
+# & Ruined chest~
+K:344:0x80:0x9C
+
+# & Iron Spike~
+K:345:0x8B:0x84
+
+# & Wooden Torch~
+K:346:0x8B:0x86
+
+# & Brass Lantern~
+K:347:0x8B:0x85
+
+# & Flask~ of oil
+K:348:0xBC:0x90
+
+# & Empty Bottle~
+K:349:0x8A:0x99
+
+# Havoc
+K:350:0xB8:0x94
+
+# Door/Stair Location
+K:351:0xB8:0x94
+
+# Trap Location
+K:352:0xB8:0x94
+
+# Probing
+K:353:0xB8:0x97
+
+# Recall
+K:354:0xB8:0x96
+
+# Illumination
+K:355:0xB8:0x95
+
+# Light
+K:356:0xB8:0x94
+
+# Lightning Bolts
+K:357:0xB8:0x94
+
+# Frost Bolts
+K:358:0xB8:0x95
+
+# Fire Bolts
+K:359:0xB8:0x95
+
+# Polymorph
+K:360:0xB8:0x95
+
+# Slow Monster
+K:361:0xB8:0x95
+
+# Sleep Monster
+K:362:0xB8:0x95
+
+# Drain Life
+K:363:0xB8:0x97
+
+# Teleport Other
+K:364:0xB8:0x96
+
+# Disarming
+K:365:0xB8:0x95
+
+# Lightning Balls
+K:366:0xB8:0x96
+
+# Cold Balls
+K:367:0xB8:0x96
+
+# Fire Balls
+K:368:0xB8:0x97
+
+# Acid Balls
+K:369:0xB8:0x97
+
+# Acid Bolts
+K:370:0xB8:0x95
+
+# Enlightenment
+K:371:0xB8:0x97
+
+# Perception
+K:372:0xB8:0x96
+
+# Curing
+K:373:0xB8:0x97
+
+# Healing
+K:374:0xB8:0x97
+
+# Detection
+K:375:0xB8:0x95
+
+# Restoration
+K:376:0xB8:0x97
+
+# Speed
+K:377:0xB8:0x97
+
+# Spell
+K:378:0xA3:0x8E
+
+# Spell
+K:379:0x86:0x9E
+
+# & Broken Skull~
+K:391:0x8B:0x8A
+
+# & Broken Bone~
+K:392:0x8B:0x8B
+
+# & Canine Skeleton~
+K:393:0x8B:0x87
+
+# & Rodent Skeleton~
+K:394:0x8B:0x87
+
+# & Human Skeleton~
+K:395:0x8B:0x87
+
+# & Dwarf Skeleton~
+K:396:0x8B:0x87
+
+# & Elf Skeleton~
+K:397:0x8B:0x87
+
+# & Gnome Skeleton~
+K:398:0x8B:0x87
+
+# & Great Hammer~
+K:399:0xCD:0x87
+
+# Black Dragon Scale Mail~
+K:400:0x88:0x9F
+
+# Blue Dragon Scale Mail~
+K:401:0x88:0x9D
+
+# White Dragon Scale Mail~
+K:402:0x88:0x9E
+
+# Red Dragon Scale Mail~
+K:403:0x89:0x81
+
+# Green Dragon Scale Mail~
+K:404:0x89:0x80
+
+# Multi-Hued Dragon Scale Mail~
+K:405:0x89:0x82
+
+# Pseudo Dragon Scale Mail~
+K:406:0xBB:0x9C
+
+# Law Dragon Scale Mail~
+K:407:0x88:0x9F
+
+# Bronze Dragon Scale Mail~
+K:408:0x88:0x96
+
+# Gold Dragon Scale Mail~
+K:409:0x88:0x9C
+
+# Chaos Dragon Scale Mail~
+K:410:0x89:0x80
+
+# Balance Dragon Scale Mail~
+K:411:0x88:0x99
+
+# Power Dragon Scale Mail~
+K:412:0xA2:0x9E
+
+# & Dragon Helm~
+K:413:0xA2:0x9D
+
+# & Dragon Shield~
+K:414:0xA2:0x9C
+
+# Death
+K:415:0xBC:0x88
+
+# Ruination
+K:416:0xBC:0x87
+
+# Detonations
+K:417:0xBC:0x87
+
+# Augmentation
+K:418:0xBC:0x87
+
+# *Healing*
+K:419:0xBC:0x87
+
+# Life
+K:420:0xBC:0x88
+
+# Self Knowledge
+K:421:0xBC:0x87
+
+# *Enlightenment*
+K:422:0xBC:0x88
+
+# Fear Resistance
+K:425:0xB5:0x81
+
+# Light and Darkness Resistance
+K:426:0xB5:0x81
+
+# Nether Resistance
+K:427:0xB5:0x81
+
+# Nexus Resistance
+K:428:0xB5:0x81
+
+# Sound Resistance
+K:429:0xB5:0x81
+
+# Confusion Resistance
+K:430:0xB5:0x81
+
+# Shard Resistance
+K:431:0xB5:0x81
+
+# Disenchantment Resistance
+K:432:0xB5:0x81
+
+# Chaos Resistance
+K:433:0xB5:0x81
+
+# Blindness Resistance
+K:434:0xB5:0x81
+
+# Lordly Protection
+K:435:0xB5:0x81
+
+# Extra Attacks
+K:436:0xB5:0x81
+
+# Cure Light Wounds
+K:437:0xBC:0x85
+
+# Clumsiness
+K:438:0xBC:0x85
+
+# Sickliness
+K:439:0xBC:0x85
+
+# Map of Bree
+K:440:0xD8:0x81
+
+# Map of Gondolin
+K:441:0xD8:0x81
+
+# Map of Lothlorien
+K:442:0xD8:0x81
+
+# Map of Minas Anor
+K:443:0xD8:0x81
+
+# & Silver Arrow~
+K:465:0xCE:0x91
+
+# & Silver Bolt~
+K:466:0xCE:0x92
+
+# Lightning Resistance
+K:467:0x87:0x80
+
+# Wisdom
+K:468:0x87:0x80
+
+# Regeneration
+K:469:0x87:0x80
+
+# Infravision
+K:470:0x87:0x80
+
+# Devotion
+K:471:0x87:0x80
+
+# Weaponmastery
+K:472:0x87:0x80
+
+# Trickery
+K:473:0x87:0x80
+
+# Telepathy
+K:474:0x87:0x80
+
+# Sustenance
+K:475:0x87:0x80
+
+# & Palantir~
+K:476:0xD8:0x8F
+
+# & Elfstone~
+K:477:0xB6:0x8F
+
+# & Jewel~
+K:478:0xB6:0x90
+
+# & Ring~
+K:479:0xB5:0x8E
+
+# copper
+K:480:0x80:0x8B
+
+# copper
+K:481:0x80:0x8B
+
+# copper
+K:482:0x80:0x8B
+
+# silver
+K:483:0x80:0x8C
+
+# silver
+K:484:0x80:0x8C
+
+# silver
+K:485:0x80:0x8C
+
+# garnets
+K:486:0x80:0x8F
+
+# garnets
+K:487:0x80:0x8F
+
+# gold
+K:488:0x80:0x8D
+
+# gold
+K:489:0x80:0x8D
+
+# gold
+K:490:0x80:0x8D
+
+# opals
+K:491:0x80:0x90
+
+# sapphires
+K:492:0x80:0x91
+
+# rubies
+K:493:0x80:0x92
+
+# diamonds
+K:494:0x80:0x93
+
+# emeralds
+K:495:0x80:0x94
+
+# mithril
+K:496:0x80:0x8E
+
+# adamantite
+K:497:0xA3:0x95
+
+# & Mighty Hammer~
+K:498:0x87:0x9A
+
+# & Massive Iron Crown~
+K:499:0x87:0x9B
+
+# & Phial~
+K:500:0x87:0x9D
+
+# & Star~
+K:501:0x87:0x9E
+
+# & Arkenstone~
+K:502:0x87:0x9F
+
+# & Amulet~
+K:503:0xB6:0x82
+
+# & Amulet~
+K:504:0xB6:0x83
+
+# & Necklace~
+K:505:0xB6:0x84
+
+# & Ring~
+K:506:0xB5:0x83
+
+# & Ring~
+K:507:0xB5:0x83
+
+# & Ring~
+K:508:0xB5:0x84
+
+# & Ring~
+K:509:0xB5:0x85
+
+# & Ring~
+K:510:0xB5:0x86
+
+# & Ring~
+K:511:0xB5:0x87
+
+# Reflection
+K:520:0xB6:0x80
+
+# Anti-Magic
+K:521:0xB6:0x80
+
+# Anti-Teleportation
+K:522:0xB6:0x80
+
+# Resistance
+K:523:0xB6:0x80
+
+# & Zweihander~
+K:524:0xCD:0x88
+
+# & Dwarven Lantern~
+K:525:0xD8:0x86
+
+# Splint Mail~
+K:526:0xCD:0x8A
+
+# & Everburning Torch~
+K:527:0xD8:0x87
+
+# & Trifurcate Spear~
+K:528:0xCD:0x96
+
+# & Three-Piece Rod~
+K:529:0xCD:0x8C
+
+# & Feanorian Lamp~
+K:530:0xD8:0x85
+
+# & Fur Cloak~
+K:531:0xCD:0x8E
+
+# Water Curing
+K:532:0xBC:0x84
+
+# & Hatchet~
+K:533:0xCD:0x90
+
+# Mumak Hide Armour~
+K:535:0xCD:0x91
+
+# & Leather Jerkin~
+K:536:0xCD:0x92
+
+# & Sickle~
+K:537:0xCD:0x93
+
+# & Club~
+K:542:0xCD:0x99
+
+# & Broad Spear~
+K:543:0xCD:0x9A
+
+# & Khopesh~
+K:544:0xCD:0x9B
+
+# & Flamberge~
+K:545:0xCD:0x9C
+
+# & Claymore~
+K:546:0xCD:0x9D
+
+# & Espadon~
+K:547:0xCD:0x9E
+
+# & Great Scimitar~
+K:548:0xCD:0x9F
+
+# Arrow
+K:549:0xD7:0x84
+
+# Bolt
+K:550:0xD7:0x83
+
+# & Fauchard~
+K:551:0xCE:0x82
+
+# & Guisarme~
+K:552:0xCE:0x83
+
+# & Heavy Lance~
+K:553:0xCE:0x84
+
+# & Bardiche~
+K:554:0xCE:0x85
+
+# Catapult
+K:555:0xD7:0x82
+
+# Ring Mail~
+K:556:0xCE:0x87
+
+# Cord Armour~
+K:557:0xCE:0x88
+
+# Paper Armour~
+K:558:0xCE:0x89
+
+# Padded Armour~
+K:559:0xCE:0x8A
+
+# Fumes
+K:560:0xD7:0x80
+
+# Golden Ring Mail~
+K:561:0x87:0x98
+
+# Magic
+K:562:0xD7:0x81
+
+# Device
+K:563:0xD7:0x85
+
+# Nothing
+K:569:0xB8:0x95
+
+# & Blood~ of Life
+K:573:0x87:0x88
+
+# & Mage Staff~
+K:577:0xCE:0x97
+
+# Lightning
+K:578:0xB5:0x81
+
+# & Ring~
+K:582:0xB5:0x8F
+
+# Invisibility
+K:583:0xB8:0x85
+
+# Corruption
+K:585:0xB8:0x85
+
+# Invisibility
+K:586:0xB5:0x81
+
+# Deep Thoughts
+K:588:0xD8:0x80
+
+# More Deep Thoughts
+K:589:0xD8:0x80
+
+# Compendium of Deep Thoughts
+K:590:0xD8:0x80
+
+# Artifact Lore Vol. I
+K:591:0xD8:0x80
+
+# Artifact Lore Vol. II
+K:592:0xD8:0x80
+
+# Artifact Lore Vol. III
+K:593:0xD8:0x80
+
+# Monstrous Compendium 1
+K:594:0xD8:0x80
+
+# Monstrous Compendium 2
+K:595:0xD8:0x80
+
+# Monstrous Compendium 3
+K:596:0xD8:0x80
+
+# Monstrous Compendium 4
+K:597:0xD8:0x80
+
+# Monstrous Compendium 5
+K:598:0xD8:0x80
+
+# Monstrous Compendium 6
+K:599:0xD8:0x80
+
+# Monstrous Compendium 7
+K:600:0xD8:0x80
+
+# Monstrous Compendium 8
+K:601:0xD8:0x80
+
+# Monstrous Compendium 9
+K:602:0xD8:0x80
+
+# Monstrous Compendium 10
+K:603:0xD8:0x80
+
+# Monstrous Compendium 11
+K:604:0xD8:0x80
+
+# & Morphic Oil~ of #
+K:605:0xBC:0x85
+
+# Artifact Lore Vol. IV
+K:607:0xD8:0x80
+
+# Artifact Lore Vol. V
+K:608:0xD8:0x80
+
+# Artifact Lore Vol. VI
+K:609:0xD8:0x80
+
+# Artifact Lore Vol. VII
+K:610:0xD8:0x80
+
+# Artifact Lore Vol. VIII
+K:611:0xD8:0x80
+
+# Artifact Lore Vol. IX
+K:612:0xD8:0x80
+
+# Artifact Lore Vol. X
+K:613:0xD8:0x80
+
+# Artifact Lore Vol. XI
+K:614:0xD8:0x80
+
+# Artifact Lore Vol. IX
+K:615:0xD8:0x80
+
+# Artifact Lore Vol. X
+K:616:0xD8:0x80
+
+# Artifact Lore Vol. XI
+K:617:0xD8:0x80
+
+# & #~
+K:618:0xCE:0x93
+
+# corpse
+K:641:0xB4:0x90
+
+# skeleton
+K:642:0xB4:0x8B
+
+# head
+K:643:0xB4:0x8E
+
+# skull
+K:644:0xB4:0x8F
+
+# raw meat
+K:645:0xB4:0x8C
+
+# & Great Eagle Down Coat~
+K:646:0xCE:0x98
+
+# & Key~
+K:647:0xD8:0x90
+
+# & Small Wooden Boomerang~
+K:648:0xCE:0x99
+
+# & Wooden Boomerang~
+K:649:0xCE:0x9A
+
+# & Small Metal Boomerang~
+K:650:0xCE:0x9B
+
+# & Metal Boomerang~
+K:651:0xCE:0x9C
+
+# & Anchor~
+K:652:0xD8:0x91
+
+# & ~
+K:653:0x87:0x99
+
+# Summon Never-Moving Pet
+K:654:0x86:0x80
+
+# Cure Light Insanity
+K:657:0xBC:0x85
+
+# Cure Serious Insanity
+K:658:0xBC:0x85
+
+# Cure Critical Insanity
+K:659:0xBC:0x85
+
+# Cure Insanity
+K:660:0xBC:0x85
+
+# & Phial~
+K:661:0x87:0x9D
+
+# Junkart
+K:662:0x87:0x9C
+
+# Craftsmanship
+K:663:0x86:0x82
+
+# The One Ring
+K:664:0xD8:0x81
+
+# & Horn~
+K:669:0xD8:0x88
+
+# & Drum~
+K:670:0xD8:0x89
+
+# & Harp~
+K:671:0xD8:0x8A
+
+# & Palantir~
+K:675:0xD8:0x8F
+
+# Egg
+K:676:0xD8:0x84
+
+# Reset Recall
+K:677:0x86:0x81
+
+# Divination
+K:678:0x86:0x81
+
+# Self
+K:679:0xDA:0x80
+
+# Ray
+K:680:0xDA:0x80
+
+# Sphere
+K:681:0xDA:0x80
+
+# Knowledge
+K:682:0xDA:0x80
+
+# Life
+K:683:0xDA:0x84
+
+# Fire
+K:684:0xDA:0x81
+
+# Cold
+K:685:0xDA:0x80
+
+# Lightning
+K:686:0xDA:0x85
+
+# Acid
+K:687:0xDA:0x88
+
+# Element
+K:688:0xDA:0x89
+
+# Chaos
+K:689:0xDA:0x83
+
+# Mind
+K:690:0xDA:0x84
+
+# Holding
+K:691:0xDA:0x84
+
+# Arrow
+K:692:0xDA:0x80
+
+# Power Surge
+K:693:0xDA:0x80
+
+# Armageddon
+K:694:0xDA:0x80
+
+# Gravity
+K:695:0xDA:0x82
+
+# Undeath
+K:697:0xDA:0x82
+
+# Protection
+K:698:0xDA:0x82
+
+# & Ring~ of Precognition
+K:700:0xB5:0x8E
+
+# & Sprig~ of Athelas
+K:701:0xCE:0x96
+
+# & Old Scroll~ of Deincarnation
+K:720:0x86:0x82
+
+# & Dark Sword~
+K:721:0xCE:0x9D
+
+# Numenorean for Beginners (I)
+K:722:0xD8:0x81
+
+# Numenorean for Beginners (II)
+K:723:0xD8:0x81
+
+# Advanced Lessons of Numenorean
+K:724:0xD8:0x81
+
+# Advanced Lessons of Sindarin
+K:725:0xD8:0x81
+
+# & Shard~ of Pottery
+K:726:0x8B:0x88
+
+# & Broken Stick~
+K:727:0x8B:0x89
+
+# & Book~ of Beginner Cantrips
+K:738:0xA3:0x8B
+
+# & Book~ of Teleportation
+K:739:0xA3:0x8B
+
+# & Book~ of Summoning
+K:741:0xA3:0x8B
+
+# & Potion~ of Learning
+K:743:0x87:0x86
+
+# Khuzdul - The Hidden Tongue of the Dwarves
+K:751:0xD8:0x81
+
+# Nandorin for Dummies
+K:752:0xD8:0x81
+
+# Advanced Lessons of Orcish
+K:753:0xD8:0x81
+
+# Flying
+K:755:0xB5:0x80
+
+# & Tome~ of the Time
+K:756:0xA3:0x8D
+
+# & Spellbook~ of #
+K:757:0xA3:0x8A
+
+# & Tome~ of Meta Spells
+K:758:0xA3:0x8D
+
+# & Tome~ of the Mind
+K:759:0xA3:0x8D
+
+# & Holy Tome~ of Eru Iluvatar
+K:760:0xA3:0x8B
+
+# & Holy Tome~ of Manwe Sulimo
+K:761:0xA3:0x8C
+
+# & War Tome~ of Tulkas
+K:762:0xA3:0x90
+
+# & Unholy Tome~ of the Hellflame
+K:763:0xA3:0x91
+
+# & Corrupted Tome~ of Melkor
+K:764:0xA3:0x91
+
+# & Earth Tome~ of Aule
+K:765:0xA3:0x92
+
+# & Shining Tome~ of Varda
+K:766:0xA3:0x8B
+
+# & Water Tome~ of Ulmo
+K:767:0xA3:0x8D
+
+# & Forest Tome~ of Yavanna
+K:768:0xA3:0x8F
+
+# Tome of#
+K:769:0xA3:0x8F
+
+# & Ring~
+K:770:0xB5:0x8E
+
+# & Holy Tome~ of Mandos
+K:771:0xA3:0x8A
+
+# & Great Rod Tip~ of Home Summoning
+K:776:0xB8:0x84
+
+# & Shadow Blade~
+K:777:0xCD:0x9C
+
+# & Bluesteel Blade~
+K:778:0xCE:0x9E
+
+# the Serpents
+K:779:0xB6:0x9F
+
+# Ring~ of Power
+K:785:0xB5:0x85
+
+# Climbing Set~
+K:786:0xD8:0x92
+
+# Adventurer's Guide to Middle-earth
+K:787:0xD8:0x80
+
+# & Demonblade~
+K:788:0xCE:0x94
+
+# & Demonshield~
+K:789:0xCE:0x94
+
+# & Demonhorn~
+K:790:0xCE:0x95
+
+# & Wooden Rod~ of#
+K:793:0xDB:0x80
+
+# & Copper Rod~ of#
+K:794:0xDB:0x81
+
+# & Iron Rod~ of#
+K:795:0xDB:0x82
+
+# & Moonstone Rod~ of#
+K:796:0xDB:0x83
+
+# & Silver Rod~ of#
+K:797:0xDB:0x84
+
+# & Golden Rod~ of#
+K:798:0xDB:0x85
+
+# & Mithril Rod~ of#
+K:799:0xDB:0x86
+
+# & Tilkal Rod~ of#
+K:800:0xDB:0x87
+
+# & Greater Ration~ of Health
+K:801:0x8A:0x9E
+
+# & Crumpled Scroll~ of Mass Resurrection
+K:802:0x86:0x82
+
+# & Cleaver~
+K:803:0xD8:0x93
+
+# & Light War Axe~
+K:804:0xD8:0x94
+
+# & Slaughter Axe~
+K:805:0xD8:0x95
+
+# & Runestone~
+K:806:0xDA:0x83
+
+# & Fortune cookie~
+K:807:0x8A:0x93
+
+# Critical Hits
+K:809:0xB5:0x82
+
+# & Wand~ of Digging of Thrain
+K:810:0xB8:0x97
+
+# & Gnarled Staff~ of Holy Fire of Mithrandir
+K:811:0xCE:0x9F
+
+# Partial Totem
+K:812:0xB4:0x82
+
+# True Totem
+K:813:0xB4:0x85
+
+# & Piece~ of the Relic of Eru
+K:814:0x8B:0x91
+
+# & Piece~ of the Relic of Manwe
+K:815:0x8B:0x92
+
+# & Piece~ of the Relic of Tulkas
+K:816:0x8B:0x93
+
+# & Piece~ of the Relic of Melkor
+K:817:0x8B:0x94
+
+# & Piece~ of the Relic of Yavanna
+K:818:0x8B:0x95
+
+# & Ring~
+K:819:0xB5:0x82
+
+# & Ring~
+K:820:0xB5:0x82
+
+# & Ring~
+K:821:0xB5:0x82
+
+# & Ring~
+K:822:0xB5:0x82
+
+# & Ring~
+K:823:0xB5:0x82
+
+# & Ring~
+K:824:0xB5:0x82
+
+# & Piece~ of the Relic of Aule
+K:825:0x8B:0x96
+
+# & Piece~ of the Relic of Varda
+K:826:0x8B:0x97
+
+# & Piece~ of the Relic of Ulmo
+K:827:0x8B:0x98
+
+# & Piece~ of the Relic of Mandos
+K:828:0x8B:0x99
+
+# & Pinch~ of Longbottom Leaf
+K:831:0x87:0x8C
+
+# & Ear~ of Corn
+K:832:0x85:0x9A
+
+# & Tater~
+K:833:0x85:0x9B
+
+# & Strawberry~
+K:834:0x85:0x9C
+
+# & Turnip~
+K:835:0x85:0x9D
+
+# & Jar~ of Honey
+K:836:0x85:0x9E
+
+# & Jug~ of Milk
+K:837:0x85:0x9F
+
+# of War
+K:838:0xB9:0x9A
+
+# of Life
+K:839:0xB9:0x9C
+
+# Wizardry
+K:840:0x82:0x81
+
+# Vitality
+K:841:0x82:0x81
+
+# Clear Thought
+K:842:0x00:0x3D
+
+# Clumsiness
+K:843:0x82:0x81
+
+# Sickliness
+K:844:0x82:0x81
+
+# Fortune
+K:845:0x82:0x7F
+
+# Sterilise
+K:846:0xA3:0x92
+
+# Map of Middle-earth
+K:847:0xA3:0x92
+
+# Map of Edoras
+K:848:0xD8:0x81
+
+# Map of Esgaroth
+K:849:0xD8:0x81
+
+# Map of Hobbiton
+K:850:0xD8:0x81
+
+# Map of Osgiliath
+K:851:0xD8:0x81
+
+# Map of Pelargir
+K:852:0xD8:0x81
+
+# Map of Beorn's domain
+K:853:0xD8:0x81
+
+# Map of Dale
+K:854:0xD8:0x81
+
+# Map of Henneth Annun
+K:855:0xD8:0x81
+
+# Map of Helm's Deep
+K:856:0xD8:0x81
+
+# Map of Thranduil's realm
+K:857:0xD8:0x81
+
+# Map of Imladris
+K:858:0xD8:0x81
+
+# & Bearded Axe~
+K:859:0x87:0x90
+
+# & Double Axe~
+K:860:0x87:0x91
+
+# & Crusader Axe~
+K:861:0x87:0x92
+
+# & Reaper Axe~
+K:862:0x87:0x93
+
+# & Mithril Helm~
+K:863:0x8B:0x9A
+
+# & Set~ of Mithril Gauntlets
+K:864:0x8B:0x9B
+
+# & Small Mithril Shield~
+K:865:0x8B:0x9C
+
+# & Large Mithril Shield~
+K:866:0x8B:0x9D
+
+# & Map~
+K:867:0xA3:0x92
+
+# & Key~
+K:868:0x87:0x8D
+
+# & Cup~
+K:869:0x87:0x8E
+
+# & Red Arrow~
+K:870:0x87:0x8F
+
+# & Sceptre~
+K:871:0x86:0x91
+
+# & Rod~
+K:872:0x86:0x90
+
+# & Necklace~
+K:873:0x86:0x9F
+
+# & Amulet~
+K:874:0x86:0x9E
+
+# & Black Banner~
+K:875:0x87:0x94
+
+# & Pearl~
+K:876:0x87:0x95
+
+# & Silmaril~
+K:877:0x87:0x96
+
+# & Silmaril~
+K:878:0x87:0x97
+
+# & Golden Harp~
+K:879:0xD9:0x8A
+
+# Player
+R:0:0x8C/0x81
+
+# Spells (*)
+S:0x30:0x85/0x93
+S:0x31:0x85/0x92
+S:0x32:0x85/0x92
+S:0x33:0x85/0x8D
+S:0x34:0x85/0x8C
+S:0x35:0x85/0x8F
+S:0x36:0x85/0x90
+S:0x37:0x85/0x95
+S:0x38:0x85/0x93
+S:0x39:0x85/0x92
+S:0x3A:0x85/0x91
+S:0x3B:0x85/0x8E
+S:0x3C:0x85/0x8D
+S:0x3D:0x85/0x8F
+S:0x3E:0x85/0x90
+S:0x3F:0x85/0x95
+
+# Spells (|)
+S:0x40:0x84/0x9C
+S:0x41:0x84/0x98
+S:0x42:0x84/0x98
+S:0x43:0x85/0x88
+S:0x44:0x84/0x80
+S:0x45:0x84/0x8C
+S:0x46:0x84/0x90
+S:0x47:0x85/0x84
+S:0x48:0x84/0x9C
+S:0x49:0x84/0x98
+S:0x4A:0x84/0x94
+S:0x4B:0x84/0x88
+S:0x4C:0x85/0x88
+S:0x4D:0x84/0x8C
+S:0x4E:0x84/0x90
+S:0x4F:0x85/0x84
+
+# Spells (-)
+S:0x50:0x84/0x9D
+S:0x51:0x84/0x99
+S:0x52:0x84/0x99
+S:0x53:0x85/0x89
+S:0x54:0x84/0x81
+S:0x55:0x84/0x8D
+S:0x56:0x84/0x91
+S:0x57:0x85/0x85
+S:0x58:0x84/0x9D
+S:0x59:0x84/0x99
+S:0x5A:0x84/0x95
+S:0x5B:0x84/0x89
+S:0x5C:0x85/0x89
+S:0x5D:0x84/0x8D
+S:0x5E:0x84/0x91
+S:0x5F:0x85/0x85
+
+# Spells (:)
+S:0x60:0x84/0x9E
+S:0x61:0x84/0x9A
+S:0x62:0x84/0x9A
+S:0x63:0x85/0x8A
+S:0x64:0x84/0x82
+S:0x65:0x84/0x8E
+S:0x66:0x84/0x92
+S:0x67:0x85/0x86
+S:0x68:0x84/0x9E
+S:0x69:0x84/0x9A
+S:0x6A:0x84/0x96
+S:0x6B:0x84/0x8A
+S:0x6C:0x85/0x8A
+S:0x6D:0x84/0x8E
+S:0x6E:0x84/0x92
+S:0x6F:0x85/0x86
+
+# Spells (\)
+S:0x70:0x84/0x9F
+S:0x71:0x84/0x9B
+S:0x72:0x84/0x9B
+S:0x73:0x85/0x8B
+S:0x74:0x84/0x83
+S:0x75:0x84/0x8F
+S:0x76:0x84/0x93
+S:0x77:0x85/0x87
+S:0x78:0x84/0x9F
+S:0x79:0x84/0x9B
+S:0x7A:0x84/0x97
+S:0x7B:0x84/0x8B
+S:0x7C:0x85/0x8B
+S:0x7D:0x84/0x8F
+S:0x7E:0x84/0x93
+S:0x7F:0x85/0x87
+
+# Amulets (")
+S:0x80:0xB6/0x87
+S:0x81:0xB6/0x88
+S:0x82:0xB6/0x85
+S:0x83:0xB6/0x86
+S:0x84:0xB6/0x81
+S:0x85:0xB6/0x82
+S:0x86:0xB6/0x83
+S:0x87:0xB6/0x84
+S:0x88:0xB6/0x87
+S:0x89:0xB6/0x88
+S:0x8A:0xB6/0x8E
+S:0x8B:0xB6/0x86
+S:0x8C:0xB6/0x81
+S:0x8D:0xB6/0x82
+S:0x8E:0xB6/0x8B
+S:0x8F:0xB6/0x8C
+
+# Rings (=)
+S:0x90:0xB5/0x8B
+S:0x91:0xB5/0x8C
+S:0x92:0xB5/0x89
+S:0x93:0xB5/0x8A
+S:0x94:0xB5/0x81
+S:0x95:0xB5/0x82
+S:0x96:0xB5/0x83
+S:0x97:0xB5/0x88
+S:0x98:0xB5/0x8B
+S:0x99:0xB5/0x8C
+S:0x9A:0xB5/0x80
+S:0x9B:0xB5/0x8A
+S:0x9C:0xB5/0x81
+S:0x9D:0xB5/0x82
+S:0x9E:0xB5/0x83
+S:0x9F:0xB5/0x88
+
+# Staffs (_)
+S:0xA0:0xB9/0x84
+S:0xA1:0xB9/0x85
+S:0xA2:0xB9/0x85
+S:0xA3:0xB9/0x81
+S:0xA4:0xB9/0x81
+S:0xA5:0xB9/0x82
+S:0xA6:0xB9/0x80
+S:0xA7:0xB9/0x87
+S:0xA8:0xB9/0x84
+S:0xA9:0xB9/0x85
+S:0xAA:0xB9/0x83
+S:0xAB:0xB9/0x87
+S:0xAC:0xB9/0x81
+S:0xAD:0xB9/0x82
+S:0xAE:0xB9/0x80
+S:0xAF:0xB9/0x87
+
+# Wands (-)
+S:0xB0:0xB7/0x84
+S:0xB1:0xB7/0x85
+S:0xB2:0xB7/0x85
+S:0xB3:0xB7/0x86
+S:0xB4:0xB7/0x81
+S:0xB5:0xB7/0x82
+S:0xB6:0xB7/0x80
+S:0xB7:0xB7/0x87
+S:0xB8:0xB7/0x84
+S:0xB9:0xB7/0x85
+S:0xBA:0xB7/0x83
+S:0xBB:0xB7/0x86
+S:0xBC:0xB7/0x81
+S:0xBD:0xB7/0x82
+S:0xBE:0xB7/0x80
+S:0xBF:0xB7/0x87
+
+# Rods (-)
+S:0xC0:0xB8/0x84
+S:0xC1:0xB8/0x85
+S:0xC2:0xB8/0x85
+S:0xC3:0xB8/0x86
+S:0xC4:0xB8/0x81
+S:0xC5:0xB8/0x82
+S:0xC6:0xB8/0x80
+S:0xC7:0xB8/0x87
+S:0xC8:0xB8/0x84
+S:0xC9:0xB8/0x85
+S:0xCA:0xB8/0x83
+S:0xCB:0xB8/0x86
+S:0xCC:0xB8/0x81
+S:0xCD:0xB8/0x82
+S:0xCE:0xB8/0x80
+S:0xCF:0xB8/0x87
+
+# Scrolls (?)
+S:0xD0:0x86/0x82
+S:0xD1:0x86/0x82
+S:0xD2:0x86/0x82
+S:0xD3:0x86/0x82
+S:0xD4:0x86/0x82
+S:0xD5:0x86/0x82
+S:0xD6:0x86/0x82
+S:0xD7:0x86/0x82
+S:0xD8:0x86/0x82
+S:0xD9:0x86/0x82
+S:0xDA:0x86/0x82
+S:0xDB:0x86/0x82
+S:0xDC:0x86/0x82
+S:0xDD:0x86/0x82
+S:0xDE:0x86/0x82
+S:0xDF:0x86/0x82
+
+# Potions (!)
+S:0xE0:0xBC/0x84
+S:0xE1:0xBC/0x83
+S:0xE2:0xBC/0x8A
+S:0xE3:0xBC/0x8B
+S:0xE4:0xBC/0x87
+S:0xE5:0xBC/0x86
+S:0xE6:0xBC/0x85
+S:0xE7:0xBC/0x89
+S:0xE8:0xBC/0x84
+S:0xE9:0xBC/0x83
+S:0xEA:0xBC/0x8E
+S:0xEB:0xBC/0x88
+S:0xEC:0xBC/0x8B
+S:0xED:0xBC/0x8C
+S:0xEE:0xBC/0x8D
+S:0xEF:0xBC/0x89
+
+# Food (,)
+S:0xF0:0xBA/0x84
+S:0xF1:0xBA/0x85
+S:0xF2:0xBA/0x85
+S:0xF3:0xBA/0x86
+S:0xF4:0xBA/0x81
+S:0xF5:0xBA/0x82
+S:0xF6:0xBA/0x80
+S:0xF7:0xBA/0x87
+S:0xF8:0xBA/0x84
+S:0xF9:0xBA/0x85
+S:0xFA:0xBA/0x83
+S:0xFB:0xBA/0x86
+S:0xFC:0xBA/0x81
+S:0xFD:0xBA/0x82
+S:0xFE:0xBA/0x80
+S:0xFF:0xBA/0x87
+
+# Unknown Amulet
+U:40:0xB6/0x81
+
+# Unknown Ring
+U:45:0xB5/0x81
+
+# Unknown Staff
+U:55:0xB9/0x81
+
+# Unknown Wand
+U:65:0xB7/0x81
+
+# Unknown Rod
+U:66:0xB8/0x81
+
+# Unknown Scroll
+U:70:0x86/0x82
+
+# Unknown Potion
+U:75:0xBC/0x85
+
+# Unknown Food
+U:80:0x8B/0x81
+# non-defines encountered :
+# Load the Trap image definitions
+%:trap-xxx.prf
diff --git a/lib/mods/theme/pref/graf.prf b/lib/mods/theme/pref/graf.prf
new file mode 100644
index 00000000..a82ce364
--- /dev/null
+++ b/lib/mods/theme/pref/graf.prf
@@ -0,0 +1,51 @@
+# File: graf.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# This file includes, if appropriate, various "sub-files"
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+##### Standard font file #####
+
+%:font-xxx.prf
+
+
+##### System Specific Subfiles #####
+
+?:[IOR [EQU $SYS xaw] [EQU $SYS x11] [EQU $SYS gtk]]
+%:graf-x11.prf
+
+?:[EQU $SYS gcu]
+%:graf-gcu.prf
+
+?:[EQU $SYS ami]
+%:graf-ami.prf
+
+?:[EQU $SYS mac]
+%:graf-mac.prf
+
+?:[EQU $SYS dos]
+%:graf-dos.prf
+
+?:[EQU $SYS win]
+%:graf-win.prf
+
+?:[EQU $SYS ibm]
+%:graf-ibm.prf
+
+?:[EQU $SYS emx]
+%:graf-emx.prf
+
+?:[EQU $SYS acn]
+%:graf-acn.prf
+
+?:[EQU $SYS sdl]
+%:graf-sdl.prf
+
+?:1
+
+
diff --git a/lib/mods/theme/pref/pref-acn.prf b/lib/mods/theme/pref/pref-acn.prf
new file mode 100644
index 00000000..ae95fe26
--- /dev/null
+++ b/lib/mods/theme/pref/pref-acn.prf
@@ -0,0 +1,24 @@
+# File: pref-acn.prf
+
+# This is a minimal "pref" file for RISC OS
+
+
+# Map cursor keys onto keypad
+
+A:4
+P:^_18C\r
+
+A:6
+P:^_18D\r
+
+A:2
+P:^_18E\r
+
+A:8
+P:^_18F\r
+
+
+# Map F3 to ^S (to be a bit RISC OS-ey)
+
+A:^S
+P:^_183\r
diff --git a/lib/mods/theme/pref/pref-ami.prf b/lib/mods/theme/pref/pref-ami.prf
new file mode 100644
index 00000000..08a1c310
--- /dev/null
+++ b/lib/mods/theme/pref/pref-ami.prf
@@ -0,0 +1,7 @@
+# File: pref-ami.prf
+
+#
+# This file contains various default macros for use with
+# the executable built from "main-ami.c".
+#
+
diff --git a/lib/mods/theme/pref/pref-emx.prf b/lib/mods/theme/pref/pref-emx.prf
new file mode 100644
index 00000000..555c0dbc
--- /dev/null
+++ b/lib/mods/theme/pref/pref-emx.prf
@@ -0,0 +1,19 @@
+# File: pref-emx.prf
+
+#
+# Include "pref-ibm.prf" to get the default macros.
+#
+# Note that, while most key-to-trigger mappings are the same as DOS/Win,
+# some few odd keys will be different or not available at all.
+#
+# Examples: Ctrl-Escape, Alt-PrintScreen
+#
+# What's NOT working: color palette redefinitions.
+#
+
+%:pref-win.prf
+
+
+# shift-5 - rest
+A:R\r
+P:^_Sx4C\r
diff --git a/lib/mods/theme/pref/pref-gcu.prf b/lib/mods/theme/pref/pref-gcu.prf
new file mode 100644
index 00000000..cbc80ada
--- /dev/null
+++ b/lib/mods/theme/pref/pref-gcu.prf
@@ -0,0 +1,70 @@
+# File: pref-gcu.prf
+
+#
+# This file may be included by "pref.prf", when using "main-gcu.prf".
+#
+# It contains macro definitions to allow the VT100 cursor keys to be
+# recognized by Angband. This will also make the "escape" key take a
+# few seconds to recognize, so you may want to use the "`" key instead.
+#
+
+
+### VT100 Keypad ###
+
+
+# Special keypad keys (delete, insert)
+
+A:.
+P:\e[3~
+
+A:0
+P:\e[2~
+
+
+# Numerical keypad keys (map to appropriate number)
+
+A:1
+P:\e[4~
+P:\e[F
+
+A:2
+P:\e[B
+
+A:3
+P:\e[6~
+
+A:4
+P:\e[D
+
+A:5
+P:\e[G
+
+A:6
+P:\e[C
+
+A:7
+P:\e[1~
+P:\e[H
+
+A:8
+P:\e[A
+
+A:9
+P:\e[5~
+
+
+# Basic function keys (F1 - F4)
+
+A:\e
+P:\eOP
+
+A:\e
+P:\eOQ
+
+A:\e
+P:\eOR
+
+A:\e
+P:\eOS
+
+
diff --git a/lib/mods/theme/pref/pref-mac.prf b/lib/mods/theme/pref/pref-mac.prf
new file mode 100644
index 00000000..88e5618e
--- /dev/null
+++ b/lib/mods/theme/pref/pref-mac.prf
@@ -0,0 +1,243 @@
+# File: pref-mac.prf
+
+#
+# This file is included by "pref.prf" when "main-mac.c" is used.
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+#
+# Macro Trigger configuration
+#
+# T:<trigger template>:<modifiers>:<modifier name1>:<modifier name2>:....
+# '&' in <trigger template> specifies location of modifier character.
+# '#' in <trigger template> specifies location of key code.
+#
+# If <trigger template> is null string, all trigger difinition will be cleared.
+
+T:&#:CSOX:control-:shift-:option-:command-
+
+# T:<trigger name>:<keycode>:<keycode with shiftkey>
+# '\' in <trigger name> is escape character.
+
+T:KP_Decimal:1
+T:KP_Multiply:3
+T:KP_Add:5
+T:KP_Clear:7
+T:KP_Divide:11
+T:KP_Enter:12
+T:KP_Subtract:14
+T:KP_Equal:17
+T:KP_0:18
+T:KP_1:19
+T:KP_2:20
+T:KP_3:21
+T:KP_4:22
+T:KP_5:23
+T:KP_6:24
+T:KP_7:25
+T:KP_8:27
+T:KP_9:28
+T:F5:32
+T:F6:33
+T:F7:34
+T:F3:35
+T:F8:36
+T:F10:37
+T:F11:39
+T:F13:41
+T:F14:43
+T:F9:45
+T:F12:47
+T:F15:49
+T:Help:50
+T:Home:51
+T:Page_Up:52
+T:Delete:53
+T:F4:54
+T:End:55
+T:F2:56
+T:Page_Down:57
+T:F1:58
+T:Left:59
+T:Right:60
+T:Down:61
+T:Up:62
+
+##### Simple Macros #####
+
+
+#
+# Keypad -- (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:/
+P:^_K/\r
+
+A:*
+P:^_K*\r
+
+A:7
+P:^_K7\r
+
+A:8
+P:^_K8\r
+
+A:9
+P:^_K9\r
+
+A:-
+P:^_K-\r
+
+A:4
+P:^_K4\r
+
+A:5
+P:^_K5\r
+
+A:6
+P:^_K6\r
+
+A:+
+P:^_K+\r
+
+A:1
+P:^_K1\r
+
+A:2
+P:^_K2\r
+
+A:3
+P:^_K3\r
+
+A:0
+P:^_K0\r
+
+A:.
+P:^_K.\r
+
+
+#
+# Shift-Keypad -- Directed running
+#
+
+A:\e\e\\.1
+P:^_S19\r
+
+A:\e\e\\.2
+P:^_S20\r
+
+A:\e\e\\.3
+P:^_S21\r
+
+A:\e\e\\.4
+P:^_S22\r
+
+A:\e\e\\.5
+P:^_S23\r
+
+A:\e\e\\.6
+P:^_S24\r
+
+A:\e\e\\.7
+P:^_S25\r
+
+A:\e\e\\.8
+P:^_S27\r
+
+A:\e\e\\.9
+P:^_S28\r
+
+
+#
+# Control-Keypad -- Directed tunneling
+#
+
+A:\e\e\\+1
+P:^_C19\r
+
+A:\e\e\\+2
+P:^_C20\r
+
+A:\e\e\\+3
+P:^_C21\r
+
+A:\e\e\\+4
+P:^_C22\r
+
+A:\e\e\\+5
+P:^_C23\r
+
+A:\e\e\\+6
+P:^_C24\r
+
+A:\e\e\\+7
+P:^_C25\r
+
+A:\e\e\\+8
+P:^_C27\r
+
+A:\e\e\\+9
+P:^_C28\r
+
+
+
+#
+# Option-Control-Keypad -- wield {@0} and tunnel
+#
+
+A:\e\ew0\s\s\\+1
+P:^_CO19\r
+
+A:\e\ew0\s\s\\+2
+P:^_CO20\r
+
+A:\e\ew0\s\s\\+3
+P:^_CO21\r
+
+A:\e\ew0\s\s\\+4
+P:^_CO22\r
+
+A:\e\ew0\s\s\\+5
+P:^_CO23\r
+
+A:\e\ew0\s\s\\+6
+P:^_CO24\r
+
+A:\e\ew0\s\s\\+7
+P:^_CO25\r
+
+A:\e\ew0\s\s\\+8
+P:^_CO27\r
+
+A:\e\ew0\s\s\\+9
+P:^_CO28\r
+
+
+#
+# Option-Control-Keypad-Zero -- wield {@0}
+#
+
+A:\e\ew0\s
+P:^_CO18\r
+
+
+
+#
+# Hack -- Arrow-Keys
+#
+
+A:4
+P:^_59\r
+
+A:6
+P:^_60\r
+
+A:2
+P:^_61\r
+
+A:8
+P:^_62\r
+
+
diff --git a/lib/mods/theme/pref/pref-sdl.prf b/lib/mods/theme/pref/pref-sdl.prf
new file mode 100644
index 00000000..3bc0f030
--- /dev/null
+++ b/lib/mods/theme/pref/pref-sdl.prf
@@ -0,0 +1,144 @@
+# File: pref-sdl.prf
+
+# This file implements macros for extended keyboard commands (characters not
+# within the 128 character ASCII set).
+# Basically, if you have to hold down control or alt or it's an arrow key,
+# it will be handled here. This means that we can let SDL worry about figuring
+# out what key is which; all it needs to do is give us the name and we'll map
+# it here.
+#
+# Note the use of "\e\e\e\e" (four escapes) to allow the macros to work
+# even if the game is not yet ready for a command.
+#
+# Note the use of "\\." (for "run") and "\\+" (for "alter"), to make sure
+# that the macros will work regardless of the "keymap" being used.
+#
+
+# Basic Arrow Movement
+
+A:8
+P:\[up]
+
+A:6
+P:\[right]
+
+A:4
+P:\[left]
+
+A:2
+P:\[down]
+
+# Basic Arrows with Shift Down
+
+A:\e\e\e\e\\.8
+P:\[shift-up]
+
+A:\e\e\e\e\\.6
+P:\[shift-right]
+
+A:\e\e\e\e\\.4
+P:\[shift-left]
+
+A:\e\e\e\e\\.2
+P:\[shift-down]
+
+# Basic Arrows with Control Down
+
+A:\e\e\e\e\\+8
+P:\[ctrl-up]
+
+A:\e\e\e\e\\+6
+P:\[ctrl-right]
+
+A:\e\e\e\e\\+4
+P:\[ctrl-left]
+
+A:\e\e\e\e\\+2
+P:\[ctrl-down]
+
+# Keypad
+
+A:1
+P:\[[1]]
+
+A:2
+P:\[[2]]
+
+A:3
+P:\[[3]]
+
+A:4
+P:\[[4]]
+
+A:5
+P:\[[5]]
+
+A:6
+P:\[[6]]
+
+A:7
+P:\[[7]]
+
+A:8
+P:\[[8]]
+
+A:9
+P:\[[9]]
+
+# Keypad With Shift
+
+A:\e\e\e\e\\.1
+P:\[shift-[1]]
+
+A:\e\e\e\e\\.2
+P:\[shift-[2]]
+
+A:\e\e\e\e\\.3
+P:\[shift-[3]]
+
+A:\e\e\e\e\\.4
+P:\[shift-[4]]
+
+A:\e\e\e\e\\.5
+P:\[shift-[5]]
+
+A:\e\e\e\e\\.6
+P:\[shift-[6]]
+
+A:\e\e\e\e\\.7
+P:\[shift-[7]]
+
+A:\e\e\e\e\\.8
+P:\[shift-[8]]
+
+A:\e\e\e\e\\.9
+P:\[shift-[9]]
+
+# Keypad With Control
+
+A:\e\e\e\e\\+1
+P:\[ctrl-[1]]
+
+A:\e\e\e\e\\+2
+P:\[ctrl-[2]]
+
+A:\e\e\e\e\\+3
+P:\[ctrl-[3]]
+
+A:\e\e\e\e\\+4
+P:\[ctrl-[4]]
+
+A:\e\e\e\e\\+5
+P:\[ctrl-[5]]
+
+A:\e\e\e\e\\+6
+P:\[ctrl-[6]]
+
+A:\e\e\e\e\\+7
+P:\[ctrl-[7]]
+
+A:\e\e\e\e\\+8
+P:\[ctrl-[8]]
+
+A:\e\e\e\e\\+9
+P:\[ctrl-[9]]
diff --git a/lib/mods/theme/pref/pref-win.prf b/lib/mods/theme/pref/pref-win.prf
new file mode 100644
index 00000000..7b1501f1
--- /dev/null
+++ b/lib/mods/theme/pref/pref-win.prf
@@ -0,0 +1,534 @@
+# File: pref-ibm.prf
+
+#
+# This file is used by Angband (when it was compiled using "main-ibm.c"
+# or "main-dos.c" or "main-win.c") to specify various "user preferences",
+# including "macros".
+#
+# This file defines some basic macros, which allow the use of the "keypad",
+# alone, and with the shift and/or control modifier keys. All "special"
+# keys are translated by "main-ibm.c" (or "main-win.c") into special "macro
+# triggers" of the encoded form "^_MMMxSS\r", where the "modifier" flags are
+# stored in "MMM", and the two digit hexidecimal scan code of the keypress is
+# stored in "SS".
+#
+# The "main-ibm.prf" and "main-dos.prf" files may not be able to recognize
+# the "/" and "*" keys on the keypad, because it mistakenly classifies the
+# "0x35" and "0x37" codes as the keycodes of "normal" keys.
+#
+# The "main-win.prf" file should not be using the final "control + keypad"
+# section in this file, it was created for "main-ibm.c" and "main-dos.c".
+#
+# The "main-win.prf" file may actually send the "ascii" equivalent of some
+# keypad keys after the keypad key itself, especially if "numlock" is down,
+# which may cause problems. Or it may not, it is hard to tell. This is bad.
+#
+# See "main-ibm.c" and "main-dos.c" and "main-win.c" for more info.
+#
+
+#
+# Macro Trigger configuration
+#
+# T:<trigger template>:<modifiers>:<modifier name1>:<modifier name2>:....
+# '&' in <trigger template> specifies location of modifier character.
+# '#' in <trigger template> specifies location of key code.
+#
+# If <trigger template> is null string, all trigger difinition will be cleared.
+
+T:&x#:CSA:control-:shift-:alt-
+
+# T:<trigger name>:<keycode>:<keycode with shiftkey>
+# '\' in <trigger name> is escape character.
+
+# These keycodes are actually direct keyboard scan code taken from the 'dinput.h'.
+
+?:[EQU $KEYBOARD JAPAN]
+# For Japanese keyboard.
+T:-:0C
+T:^:0D
+T:@:1A
+T:[:1B
+T:;:27
+T:\::28
+T:]:2B
+T:,:33
+T:.:34
+T:\/:35
+T:_:73
+?:1
+
+?:[EQU $KEYBOARD 0]
+# For US keyboard.
+T:-:0C
+T:=:0D
+T:[:1A
+T:]:1B
+T:;:27
+T:\':28
+T:`:29
+T:\\:2B
+T:,:33
+T:.:34
+T:\/:35
+?:1
+
+############
+# Common keycodes (except NEC PC-98x1)
+
+?:[NOT [EQU $KEYBOARD NEC98]]
+T:1:02
+T:2:03
+T:3:04
+T:4:05
+T:5:06
+T:6:07
+T:7:08
+T:8:09
+T:9:0A
+T:0:0B
+T:Backspace:0E
+T:Q:10
+T:W:11
+T:E:12
+T:R:13
+T:T:14
+T:Y:15
+T:U:16
+T:I:17
+T:O:18
+T:P:19
+T:Enter:1C
+T:A:1E
+T:S:1F
+T:D:20
+T:F:21
+T:G:22
+T:H:23
+T:J:24
+T:K:25
+T:L:26
+T:Zenkaku_Hankaku:29
+T:Z:2C
+T:X:2D
+T:C:2E
+T:V:2F
+T:B:30
+T:N:31
+T:M:32
+T:KP_Multiply:37
+T:CapsLock:3A
+T:F1:3B
+T:F2:3C
+T:F3:3D
+T:F4:3E
+T:F5:3F
+T:F6:40
+T:F7:41
+T:F8:42
+T:F9:43
+T:F10:44
+T:Numlock:45
+T:Scroll:46
+#T:KP_7:47
+T:Home:47
+#T:KP_8:48
+T:Up:48
+#T:KP_9:49
+T:Page_Up:49
+T:KP_Subtract:4A
+#T:KP_4:4B
+T:Left:4B
+T:KP_5:4C
+#T:KP_6:4D
+T:Right:4D
+T:KP_Add:4E
+#T:KP_1:4F
+T:End:4F
+#T:KP_2:50
+T:Down:50
+#T:KP_3:51
+T:Page_Down:51
+#T:KP_0:52
+T:Insert:52
+#T:KP_Decimal:53
+T:Delete:53
+T:Oem_102:56
+T:F11:57
+T:F12:58
+T:Menu:5D
+T:F13:64
+T:F14:65
+T:F15:66
+T:Hiragana_Katakana:70
+T:Abnt_C1:73
+T:Henkan:79
+T:Muhenkan:7B
+T:Yen:7D
+T:Abnt_C2:7E
+T:KP_equals:8D
+T:Prevtrack:90
+T:Kanji:94
+T:Stop:95
+T:Ax:96
+T:Unlabeled:97
+T:Nexttrack:99
+T:KP_Enter:9C
+T:Mute:A0
+T:Calculator:A1
+T:Playpause:A2
+T:Mediastop:A4
+T:Volumedown:AE
+T:Volumeup:B0
+T:Webhome:B2
+T:KP_Comma:B3
+T:KP_Divide:B5
+T:Sys_Req:B7
+T:Pause:C5
+#T:Home:C7
+#T:Up:C8
+#T:Prior:C9
+#T:Left:CB
+#T:Right:CD
+#T:End:CF
+#T:Down:D0
+#T:Next:D1
+#T:Insert:D2
+#T:Delete:D3
+T:Lwin:DB
+T:Rwin:DC
+T:Apps:DD
+T:Power:DE
+T:Sleep:DF
+T:Wake:E3
+T:Websearch:E5
+T:Webfavorites:E6
+T:Webrefresh:E7
+T:Webstop:E8
+T:Webforward:E9
+T:Webback:EA
+T:Mycomputer:EB
+T:Mail:EC
+T:Mediaselect:ED
+?:1
+
+
+######################
+# For NEC PC-98x1
+
+?:[EQU $KEYBOARD NEC98]
+T:1:01
+T:2:02
+T:3:03
+T:4:04
+T:5:05
+T:6:06
+T:7:07
+T:8:08
+T:9:09
+T:0:0A
+T:-:0B
+T:^:0C
+T:Yen:0D
+T:Backspace:0E
+T:Q:10
+T:W:11
+T:E:12
+T:R:13
+T:T:14
+T:Y:15
+T:U:16
+T:I:17
+T:O:18
+T:P:19
+T:@:1a
+T:[:1b
+T:Enter:1C
+T:A:1D
+T:S:1E
+T:D:1F
+T:F:20
+T:G:21
+T:H:22
+T:J:23
+T:K:24
+T:L:25
+T:;:26
+T:\::27
+T:[:28
+T:Z:29
+T:X:2A
+T:C:2B
+T:V:2C
+T:B:2D
+T:N:2E
+T:M:2F
+T:,:30
+T:.:31
+T:\/:32
+T:_:33
+T:Henkan:35
+T:Page_Down:36
+T:Page_Up:37
+T:Insert:38
+T:Delete:39
+T:Up:3A
+T:Left:3B
+T:Right:3C
+T:Down:3D
+T:Home:3E
+T:End:3F
+T:KP_Subtract:40
+T:KP_Divide:41
+T:KP_7:42
+T:KP_8:43
+T:KP_9:44
+T:KP_Multiply:45
+T:KP_4:46
+T:KP_5:47
+T:KP_6:48
+T:KP_Add:49
+T:KP_1:4A
+T:KP_2:4B
+T:KP_3:4C
+T:KP_Equal:4D
+T:KP_0:4E
+T:KP_Comma:4F
+T:KP_Decimal:50
+T:Muhenkan:51
+T:F11:52
+T:F12:53
+T:F13:54
+T:F14:55
+T:F15:56
+T:Pause:60
+T:F1:62
+T:F2:63
+T:F3:64
+T:F4:65
+T:F5:66
+T:F6:67
+T:F7:68
+T:F8:69
+T:F9:6A
+T:F10:6B
+T:CapsLock:71
+T:Hiragana_Katakana:72
+T:Menu:79
+
+?:[NOT [EQU $KEYBOARD NEC98]]
+
+
+#
+# Hack -- Some foreign keyboards have a special key on the keyboard, which
+# is used to generate the "<", ">", and "|" keys (alone, shifted, alt-ed).
+#
+
+A:<
+P:^_x56\r
+
+A:>
+P:^_Sx56\r
+
+A:|
+P:^_Ax56\r
+
+
+#
+# Keypad (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:/
+P:^_x35\r
+
+A:*
+P:^_x37\r
+
+A:7
+P:^_x47\r
+
+A:8
+P:^_x48\r
+
+A:9
+P:^_x49\r
+
+A:-
+P:^_x4A\r
+
+A:4
+P:^_x4B\r
+
+A:5
+P:^_x4C\r
+
+A:6
+P:^_x4D\r
+
+A:+
+P:^_x4E\r
+
+A:1
+P:^_x4F\r
+
+A:2
+P:^_x50\r
+
+A:3
+P:^_x51\r
+
+A:0
+P:^_x52\r
+
+A:.
+P:^_x53\r
+
+
+#
+# Shift + Keypad (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:\e\e\e
+P:^_Sx35\r
+
+A:\e\e\e
+P:^_Sx37\r
+
+A:\e\e\\.7
+P:^_Sx47\r
+
+A:\e\e\\.8
+P:^_Sx48\r
+
+A:\e\e\\.9
+P:^_Sx49\r
+
+A:\e\e\e
+P:^_Sx4A\r
+
+A:\e\e\\.4
+P:^_Sx4B\r
+
+A:\e\e\\.5
+P:^_Sx4C\r
+
+A:\e\e\\.6
+P:^_Sx4D\r
+
+A:\e\e\e
+P:^_Sx4E\r
+
+A:\e\e\\.1
+P:^_Sx4F\r
+
+A:\e\e\\.2
+P:^_Sx50\r
+
+A:\e\e\\.3
+P:^_Sx51\r
+
+A:\e\e\e
+P:^_Sx52\r
+
+A:\e\e\e
+P:^_Sx53\r
+
+
+#
+# Control + Keypad (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:\e\e\e
+P:^_Cx35\r
+
+A:\e\e\e
+P:^_Cx37\r
+
+A:\e\e\\+7
+P:^_Cx47\r
+
+A:\e\e\\+8
+P:^_Cx48\r
+
+A:\e\e\\+9
+P:^_Cx49\r
+
+A:\e\e\e
+P:^_Cx4A\r
+
+A:\e\e\\+4
+P:^_Cx4B\r
+
+A:\e\e\\+5
+P:^_Cx4C\r
+
+A:\e\e\\+6
+P:^_Cx4D\r
+
+A:\e\e\e
+P:^_Cx4E\r
+
+A:\e\e\\+1
+P:^_Cx4F\r
+
+A:\e\e\\+2
+P:^_Cx50\r
+
+A:\e\e\\+3
+P:^_Cx51\r
+
+A:\e\e\e
+P:^_Cx52\r
+
+A:\e\e\e
+P:^_Cx53\r
+
+
+#
+# Control + Keypad (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:\e\e\e
+P:^_Cx95\r
+
+A:\e\e\e
+P:^_Cx96\r
+
+A:\e\e\\+7
+P:^_Cx77\r
+
+A:\e\e\\+8
+P:^_Cx8D\r
+
+A:\e\e\\+9
+P:^_Cx84\r
+
+A:\e\e\e
+P:^_Cx8E\r
+
+A:\e\e\\+4
+P:^_Cx73\r
+
+A:\e\e\\+5
+P:^_Cx8F\r
+
+A:\e\e\\+6
+P:^_Cx74\r
+
+A:\e\e\e
+P:^_Cx90\r
+
+A:\e\e\\+1
+P:^_Cx75\r
+
+A:\e\e\\+2
+P:^_Cx91\r
+
+A:\e\e\\+3
+P:^_Cx76\r
+
+A:\e\e\e
+P:^_Cx92\r
+
+A:\e\e\e
+P:^_Cx93\r
+
diff --git a/lib/mods/theme/pref/pref-x11.prf b/lib/mods/theme/pref/pref-x11.prf
new file mode 100644
index 00000000..f4df9376
--- /dev/null
+++ b/lib/mods/theme/pref/pref-x11.prf
@@ -0,0 +1,413 @@
+# File: pref-x11.prf
+
+#
+# This file provides some macros for use with versions of Angband compiled
+# using the "main-x11.c" (or "main-xaw.c") file.
+#
+# Note the use of "\e\e\e\e" (four escapes) to allow the macros to work
+# even if the game is not yet ready for a command.
+#
+# Note the use of "\\." (for "run") and "\\+" (for "alter"), to make sure
+# that the macros will work regardless of the "keymap" being used.
+#
+
+#
+# Macro Trigger configuration
+#
+# T:<trigger template>:<modifiers>:<modifier name1>:<modifier name2>:....
+# '&' in <trigger template> specifies location of modifier character.
+# '#' in <trigger template> specifies location of key code.
+#
+# If <trigger template> is null string, all trigger difinition will be cleared.
+
+T:&_#:NSOM:control-:shift-:alt-:mod2-
+
+# T:<trigger name>:<keycode>:<keycode with shiftkey>
+# '\' in <trigger name> is escape character.
+
+T:Clear:FF0B
+T:Pause:FF13
+T:Scroll_Lock:FF14
+T:Sys_Req:FF15
+T:Escape:FF1B
+T:Delete:FFFF
+T:Multi_Key:FF20
+T:Codeinput:FF37
+T:SingleCandidate:FF3C
+T:MultipleCandidate:FF3D
+T:PreviousCandidate:FF3E
+T:Kanji:FF21
+T:Muhenkan:FF22
+T:Henkan:FF23
+T:Henkan_Mode:FF23
+T:Romaji:FF24
+T:Hiragana:FF25
+T:Katakana:FF26
+T:Hiragana_Katakana:FF27
+T:Zenkaku:FF28
+T:Hankaku:FF29
+T:Zenkaku_Hankaku:FF2A
+T:Touroku:FF2B
+T:Massyo:FF2C
+T:Kana_Lock:FF2D
+T:Kana_Shift:FF2E
+T:Eisu_Shift:FF2F
+T:Eisu_Toggle:FF30
+T:Kanji_Bangou:FF37
+T:Zen_Koho:FF3D
+T:Mae_Koho:FF3E
+T:Home:FF50
+T:Left:FF51
+T:Up:FF52
+T:Right:FF53
+T:Down:FF54
+T:Page_Up:FF55
+T:Page_Down:FF56
+T:End:FF57
+T:Begin:FF58
+T:Select:FF60
+T:Print:FF61
+T:Execute:FF62
+T:Insert:FF63
+T:Undo:FF65
+T:Redo:FF66
+T:Menu:FF67
+T:Find:FF68
+T:Cancel:FF69
+T:Help:FF6A
+T:Break:FF6B
+T:Mode_Switch:FF7E
+T:Num_Lock:FF7F
+T:KP_Space:FF80
+T:KP_Tab:FF89
+T:KP_Enter:FF8D
+T:KP_F1:FF91
+T:KP_F2:FF92
+T:KP_F3:FF93
+T:KP_F4:FF94
+T:KP_Home:FF95
+T:KP_Left:FF96
+T:KP_Up:FF97
+T:KP_Right:FF98
+T:KP_Down:FF99
+T:KP_Page_Up:FF9A
+T:KP_Page_Down:FF9B
+T:KP_End:FF9C
+T:KP_Begin:FF9D
+T:KP_Insert:FF9E
+T:KP_Delete:FF9F
+T:KP_Equal:FFBD
+T:KP_Multiply:FFAA
+T:KP_Add:FFAB
+T:KP_Comma:FFAC
+T:KP_Subtract:FFAD
+T:KP_Decimal:FFAE
+T:KP_Divide:FFAF
+T:KP_0:FFB0
+T:KP_1:FFB1
+T:KP_2:FFB2
+T:KP_3:FFB3
+T:KP_4:FFB4
+T:KP_5:FFB5
+T:KP_6:FFB6
+T:KP_7:FFB7
+T:KP_8:FFB8
+T:KP_9:FFB9
+T:F1:FFBE
+T:F2:FFBF
+T:F3:FFC0
+T:F4:FFC1
+T:F5:FFC2
+T:F6:FFC3
+T:F7:FFC4
+T:F8:FFC5
+T:F9:FFC6
+T:F10:FFC7
+T:F11:FFC8
+T:F12:FFC9
+T:F13:FFCA
+T:F14:FFCB
+T:F15:FFCC
+T:F16:FFCD
+T:F17:FFCE
+T:F18:FFCF
+T:F19:FFD0
+T:F20:FFD1
+T:F21:FFD2
+T:F22:FFD3
+T:F23:FFD4
+T:F24:FFD5
+T:F25:FFD6
+T:F26:FFD7
+T:F27:FFD8
+T:F28:FFD9
+T:F29:FFDA
+T:F30:FFDB
+T:F31:FFDC
+T:F32:FFDD
+T:F33:FFDE
+T:F34:FFDF
+T:F35:FFE0
+
+T:\::3A:2A
+T:*:3A:2A
+T:;:3B:2B
+T:+:3B:2B
+T:,:2C:3C
+T:<:2C:3C
+T:-:2D:3D
+T:=:2D:3D
+T:.:2E:3E
+T:>:2E:3E
+T:\/:2F:3F
+T:?:2F:3F
+T:0:30:7E
+T:~:30:7E
+T:1:31:21
+T:!:31:21
+T:2:32:22
+T:":32:22
+T:3:33:23
+T:#:33:23
+T:4:34:24
+T:$:34:24
+T:5:35:25
+T:%:35:25
+T:6:36:26
+T:&:36:26
+T:7:37:27
+T:\':37:27
+T:8:38:28
+T:(:38:28
+T:9:39:29
+T:):39:29
+T:@:40:60
+T:`:40:60
+T:A:61:41
+T:B:62:42
+T:C:63:43
+T:D:64:44
+T:E:65:45
+T:F:66:46
+T:G:67:47
+T:H:68:48
+T:I:69:49
+T:J:6A:4A
+T:K:6B:4B
+T:L:6C:4C
+T:M:6D:4D
+T:N:6E:4E
+T:O:6F:4F
+T:P:70:50
+T:Q:71:51
+T:R:72:52
+T:S:73:53
+T:T:74:54
+T:U:75:55
+T:V:76:56
+T:W:77:57
+T:X:78:58
+T:Y:79:59
+T:Z:7A:5A
+T:[:5B:7B
+T:{:5B:7B
+T:\\:5C:5F
+T:_:5C:5F
+T:]:5D:7D
+T:}:5D:7D
+T:^:5E:7E
+T:~:5E:7E
+T:|:A5:7C
+
+
+# Keypad (0-9)
+
+A:0
+P:^__FFB0\r
+P:^__FF63\r
+P:^__????\r
+P:^__FF9E\r
+
+A:1
+P:^__FFB1\r
+P:^__FF57\r
+P:^__FFDE\r
+P:^__FF9C\r
+
+A:2
+P:^__FFB2\r
+P:^__FF54\r
+P:^__FFDF\r
+P:^__FF99\r
+
+A:3
+P:^__FFB3\r
+P:^__FF56\r
+P:^__FFE0\r
+P:^__FF9B\r
+
+A:4
+P:^__FFB4\r
+P:^__FF51\r
+P:^__FFDB\r
+P:^__FF96\r
+
+A:5
+P:^__FFB5\r
+P:^__FF80\r
+P:^__FFDC\r
+P:^__FF9D\r
+
+A:6
+P:^__FFB6\r
+P:^__FF53\r
+P:^__FFDD\r
+P:^__FF98\r
+
+A:7
+P:^__FFB7\r
+P:^__FF50\r
+P:^__FFD8\r
+P:^__FF95\r
+
+A:8
+P:^__FFB8\r
+P:^__FF52\r
+P:^__FFD9\r
+P:^__FF97\r
+
+A:9
+P:^__FFB9\r
+P:^__FF55\r
+P:^__FFDA\r
+P:^__FF9A\r
+
+
+# Shift-Keypad (0-9)
+
+A:\e\e\e\e\\.0
+P:^_S_FFB0\r
+P:^_S_FF63\r
+P:^_S_????\r
+P:^_S_FF9E\r
+
+A:\e\e\e\e\\.1
+P:^_S_FFB1\r
+P:^_S_FF57\r
+P:^_S_FFDE\r
+P:^_S_FF9C\r
+
+A:\e\e\e\e\\.2
+P:^_S_FFB2\r
+P:^_S_FF54\r
+P:^_S_FFDF\r
+P:^_S_FF99\r
+
+A:\e\e\e\e\\.3
+P:^_S_FFB3\r
+P:^_S_FF56\r
+P:^_S_FFE0\r
+P:^_S_FF9B\r
+
+A:\e\e\e\e\\.4
+P:^_S_FFB4\r
+P:^_S_FF51\r
+P:^_S_FFDB\r
+P:^_S_FF96\r
+
+A:\e\e\e\e\\.5
+P:^_S_FFB5\r
+P:^_S_FF80\r
+P:^_S_FFDC\r
+P:^_S_????\r
+
+A:\e\e\e\e\\.6
+P:^_S_FFB6\r
+P:^_S_FF53\r
+P:^_S_FFDD\r
+P:^_S_FF98\r
+
+A:\e\e\e\e\\.7
+P:^_S_FFB7\r
+P:^_S_FF50\r
+P:^_S_FFD8\r
+P:^_S_FF95\r
+
+A:\e\e\e\e\\.8
+P:^_S_FFB8\r
+P:^_S_FF52\r
+P:^_S_FFD9\r
+P:^_S_FF97\r
+
+A:\e\e\e\e\\.9
+P:^_S_FFB9\r
+P:^_S_FF55\r
+P:^_S_FFDA\r
+P:^_S_FF9A\r
+
+
+# Control-Keypad (0-9)
+
+A:\e\e\e\e\\+0
+P:^_N_FFB0\r
+P:^_N_FF63\r
+P:^_N_????\r
+P:^_N_FF9E\r
+
+A:\e\e\e\e\\+1
+P:^_N_FFB1\r
+P:^_N_FF57\r
+P:^_N_FFDE\r
+P:^_N_FF9C\r
+
+A:\e\e\e\e\\+2
+P:^_N_FFB2\r
+P:^_N_FF54\r
+P:^_N_FFDF\r
+P:^_N_FF99\r
+
+A:\e\e\e\e\\+3
+P:^_N_FFB3\r
+P:^_N_FF56\r
+P:^_N_FFE0\r
+P:^_N_FF9B\r
+
+A:\e\e\e\e\\+4
+P:^_N_FFB4\r
+P:^_N_FF51\r
+P:^_N_FFDB\r
+P:^_N_FF96\r
+
+A:\e\e\e\e\\+5
+P:^_N_FFB5\r
+P:^_N_FF80\r
+P:^_N_FFDC\r
+P:^_N_????\r
+
+A:\e\e\e\e\\+6
+P:^_N_FFB6\r
+P:^_N_FF53\r
+P:^_N_FFDD\r
+P:^_N_FF98\r
+
+A:\e\e\e\e\\+7
+P:^_N_FFB7\r
+P:^_N_FF50\r
+P:^_N_FFD8\r
+P:^_N_FF95\r
+
+A:\e\e\e\e\\+8
+P:^_N_FFB8\r
+P:^_N_FF52\r
+P:^_N_FFD9\r
+P:^_N_FF97\r
+
+A:\e\e\e\e\\+9
+P:^_N_FFB9\r
+P:^_N_FF55\r
+P:^_N_FFDA\r
+P:^_N_FF9A\r
+
+
+
+
diff --git a/lib/mods/theme/pref/pref.prf b/lib/mods/theme/pref/pref.prf
new file mode 100644
index 00000000..a6bfdbe1
--- /dev/null
+++ b/lib/mods/theme/pref/pref.prf
@@ -0,0 +1,311 @@
+# File: pref.prf
+
+#
+# This file defines "default" actions of various kinds
+#
+# This file includes, if appropriate, various "sub-files"
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+# Note that the "X" key is mapped in both keysets to the key sequence
+# "w0", which will "swap weapons" as long as both weapons contain the
+# inscription "@0". For example, inscribe your main weapon as "@1@0"
+# and your digger (or secondary weapon) as "@2@0".
+#
+
+
+##### Force certain options #####
+
+## # Option -- Default to original commands
+## X:rogue_like_commands
+
+## # Option -- Default to roguelike commands
+## Y:rogue_like_commands
+
+
+##### Original Keyset Mappings #####
+
+# Stay still
+A:,
+C:0:5
+
+# Movement
+A:;1
+C:0:1
+A:;2
+C:0:2
+A:;3
+C:0:3
+A:;4
+C:0:4
+A:;6
+C:0:6
+A:;7
+C:0:7
+A:;8
+C:0:8
+A:;9
+C:0:9
+
+# Hack -- Return
+A:\r
+C:0:^J
+
+# Hack -- Commit suicide
+A:Q
+C:0:^K
+
+# Hack -- Commit suicide
+A:Q
+C:0:^C
+
+
+##### Roguelike Keyset Mappings #####
+
+# Run
+A:.
+C:1:,
+
+# Stay still
+A:,
+C:1:.
+
+# Stay still
+A:,
+C:1:5
+
+# Movement
+A:;1
+C:1:1
+A:;2
+C:1:2
+A:;3
+C:1:3
+A:;4
+C:1:4
+A:;6
+C:1:6
+A:;7
+C:1:7
+A:;8
+C:1:8
+A:;9
+C:1:9
+
+# Movement (rogue keys)
+A:;1
+C:1:b
+A:;2
+C:1:j
+A:;3
+C:1:n
+A:;4
+C:1:h
+A:;6
+C:1:l
+A:;7
+C:1:y
+A:;8
+C:1:k
+A:;9
+C:1:u
+
+# Running (shift + rogue keys)
+A:.1
+C:1:B
+A:.2
+C:1:J
+A:.3
+C:1:N
+A:.4
+C:1:H
+A:.6
+C:1:L
+A:.7
+C:1:Y
+A:.8
+C:1:K
+A:.9
+C:1:U
+
+# Altering (control + rogue keys)
+A:+1
+C:1:^B
+A:+2
+C:1:^J
+A:+3
+C:1:^N
+A:+4
+C:1:^H
+A:+6
+C:1:^L
+A:+7
+C:1:^Y
+A:+8
+C:1:^K
+A:+9
+C:1:^U
+
+# Allow use of the "tunnel" command
+A:T
+C:1:^T
+
+# Allow use of the "destroy" command
+A:k
+C:1:^D
+
+# Locate player on map
+A:L
+C:1:W
+
+# Browse a book (Peruse)
+A:b
+C:1:P
+
+# Toggle search mode
+A:S
+C:1:#
+
+# Use a staff (Zap)
+A:u
+C:1:Z
+
+# Take off equipment
+A:t
+C:1:T
+
+# Fire an item
+A:f
+C:1:t
+
+# Bash a door (Force)
+A:B
+C:1:f
+
+# Look around (examine)
+A:l
+C:1:x
+
+# Aim a wand (Zap)
+A:a
+C:1:z
+
+# Zap a rod (Activate)
+A:z
+C:1:a
+
+# Hack -- Commit suicide
+A:Q
+C:1:^C
+
+# Hack - race/mutation power activation
+A:U
+C:1:O
+
+# Sacrifice at an altar
+A:O
+C:1:^g
+
+# Hack up a corpse
+A:h
+C:1:$
+
+# Cure meat
+A:K
+C:1:^O
+
+# Pet commands
+A:P
+C:1:X
+
+# Engrave
+A:x
+C:1:]
+
+# Steal
+A:Z
+C:1:[
+
+# Drink from a fountain
+A:H
+C:1:V
+
+# Give item
+A:y
+C:1:'
+
+# Chat
+A:Y
+C:1:(
+
+# Command line
+A:#
+C:1:)
+
+# Record command
+A:$
+C:1:S
+
+
+### Extended macros ###
+
+# Note that : and ' can only be included in triggers if they are
+# within quotes (i.e. as ':' or ''').
+
+L:-8192:help:Show this help
+L:-8192:?
+L:-8192:'''
+L:-8191:irc_on:Connect to IRC
+L:-8191:C
+L:-8190:irc_say:Speak on IRC
+L:-8190:@
+L:-8190:':'
+L:-8189:irc_off:Disconnect from IRC
+L:-8188:time:Get the current game time
+L:-8188:T
+L:-8187:skills:Check skills
+L:-8187:S
+L:-8186:html-dump:Save an html screenshot
+L:-8186:D
+L:-8184:quest:Show quest list
+L:-8184:Q
+L:-8183:blunder:Walk without disarming
+L:-8183:B
+L:-8182:ability:Check abilities
+L:-8182:A
+L:y:give:Give an object to a monster
+L:Y:chat:Talk to a monster
+L:j:jam:Jam a door
+
+##### System Specific Subfiles #####
+
+?:[IOR [EQU $SYS xaw] [EQU $SYS x11] [EQU $SYS gtk2]]
+%:pref-x11.prf
+
+?:[EQU $SYS gcu]
+%:pref-gcu.prf
+
+?:[EQU $SYS ami]
+%:pref-ami.prf
+
+?:[EQU $SYS mac]
+%:pref-mac.prf
+
+?:[IOR [EQU $SYS win] [EQU $SYS dos] [EQU $SYS ibm]]
+%:pref-win.prf
+
+?:[EQU $SYS emx]
+%:pref-emx.prf
+
+?:[EQU $SYS acn]
+%:pref-acn.prf
+
+?:[EQU $SYS sdl]
+%:pref-sdl.prf
+
+?:[EQU $SYS pgu]
+%:pref-pgu.prf
+
+?:1
+
+
diff --git a/lib/mods/theme/pref/trap-xxx.prf b/lib/mods/theme/pref/trap-xxx.prf
new file mode 100644
index 00000000..f4d699a0
--- /dev/null
+++ b/lib/mods/theme/pref/trap-xxx.prf
@@ -0,0 +1,428 @@
+# Prf file for use with the 8x8 tiles to define
+# trap image locations. Separated out from main
+# graphics definitions due to the G:T:num:y:x
+# instead of T:num:y:x (major problems if this
+# file is opened in the TileAssigner)
+
+# Weakness Traps
+G:T:1:0x82:0x9E
+G:T:2:0x82:0x9E
+G:T:3:0x82:0x9E
+
+# Intelligence Traps
+G:T:4:0x82:0x9E
+G:T:5:0x82:0x9E
+G:T:6:0x82:0x9E
+
+# Wisdom Traps
+G:T:7:0x82:0x9E
+G:T:8:0x82:0x9E
+G:T:9:0x82:0x9E
+
+# Fumbling Fingers Traps
+G:T:10:0x82:0x9E
+G:T:11:0x82:0x9E
+G:T:12:0x82:0x9E
+
+# Wasting Traps
+G:T:13:0x82:0x9E
+G:T:14:0x82:0x9E
+G:T:15:0x82:0x9E
+
+# Beauty Traps
+G:T:16:0x82:0x9E
+G:T:17:0x82:0x9E
+G:T:18:0x82:0x9E
+
+# Trap of Curse Weapon
+G:T:20:0xA2:0x92
+
+# Trap of Curse Armor
+G:T:21:0xA2:0x92
+
+# Earthquake Trap
+G:T:22:0xA2:0x87
+
+# Poison Needle Trap
+G:T:23:0xA2:0x8B
+
+# Summon Monster Trap
+G:T:24:0xA2:0x89
+
+# Summon Undead Trap
+G:T:25:0xA2:0x89
+
+# Summon Greater Undead Trap
+G:T:26:0xA2:0x89
+
+# Teleport Trap
+G:T:27:0x8A:0x9C
+
+# Paralyzing Trap
+G:T:28:0xA2:0x8B
+
+# Explosive Device
+G:T:29:0xA2:0x8B
+
+# Teleport Item Trap
+G:T:30:0x8A:0x9C
+
+# Lose Memory Trap
+G:T:31:0xA2:0x8B
+
+# Bitter Regret Trap
+G:T:32:0xA2:0x8B
+
+# Bowel Cramps Trap
+G:T:33:0xA2:0x8B
+
+# Blindness/Confusion Trap
+G:T:34:0xA2:0x8B
+
+# Aggravation Trap
+G:T:35:0xA2:0x87
+
+# Multiplication Trap
+G:T:36:0xA2:0x87
+
+# Steal Item Trap
+G:T:37:0xA2:0x92
+
+# Summon Fast Quylthulgs Trap
+G:T:38:0xA2:0x89
+
+# Trap of Sinking
+G:T:39:0x8A:0x9C
+
+# Trap of Mana Drain
+G:T:40:0xA2:0x8B
+
+# Trap of Missing Money
+G:T:41:0xA2:0x92
+
+# Trap of No Return
+G:T:42:0xA2:0x92
+
+# Trap of Silent Switching
+G:T:43:0xA2:0x92
+
+# Trap of Walls
+G:T:44:0xA2:0x87
+
+# Trap of Calling Out
+G:T:45:0xA2:0x89
+
+# Trap of Sliding
+G:T:46:0xA2:0x8B
+
+# Trap of Charges Drain
+G:T:47:0xA2:0x92
+
+# Trap of Stair Movement
+G:T:48:0xA2:0x87
+
+# Trap of New Trap
+G:T:49:0xA2:0x87
+
+# Trap of Scatter Items
+G:T:50:0x8A:0x9C
+
+# Trap of Decay
+G:T:51:0xA2:0x8B
+
+# Trap of Wasting Wands
+G:T:52:0xA2:0x92
+
+# Trap of Filling
+G:T:53:0xA2:0x87
+
+# Trap of Drain Speed
+G:T:54:0xA2:0x92
+
+# Lightning Bolt Trap
+G:T:60:0xA2:0x8C
+
+# Poison Bolt Trap
+G:T:61:0xA2:0x8C
+
+# Acid Bolt Trap
+G:T:62:0xA2:0x8C
+
+# Cold Bolt Trap
+G:T:63:0xA2:0x8C
+
+# Fire Bolt Trap
+G:T:64:0xA2:0x8C
+
+# Plasma Bolt Trap
+G:T:65:0xA2:0x8C
+
+# Water Bolt Trap
+G:T:66:0xA2:0x8C
+
+# Lite Bolt Trap
+G:T:67:0xA2:0x8C
+
+# Dark Bolt Trap
+G:T:68:0xA2:0x8C
+
+# Shards Bolt Trap
+G:T:69:0xA2:0x8C
+
+# Sound Bolt Trap
+G:T:70:0xA2:0x8C
+
+# Confusion Bolt Trap
+G:T:71:0xA2:0x8C
+
+# Force Bolt Trap
+G:T:72:0xA2:0x8C
+
+# Inertia Bolt Trap
+G:T:73:0xA2:0x8C
+
+# Mana Bolt Trap
+G:T:74:0xA2:0x8C
+
+# Ice Bolt Trap
+G:T:75:0xA2:0x8C
+
+# Chaos Bolt Trap
+G:T:76:0xA2:0x8C
+
+# Nether Bolt Trap
+G:T:77:0xA2:0x8C
+
+# Disenchantment Bolt Trap
+G:T:78:0xA2:0x8C
+
+# Nexus Bolt Trap
+G:T:79:0xA2:0x8C
+
+# Time Bolt Trap
+G:T:80:0xA2:0x8C
+
+# Gravity Bolt Trap
+G:T:81:0xA2:0x8C
+
+# Lightning Ball Trap
+G:T:82:0xA2:0x8D
+
+# Poison Ball Trap
+G:T:83:0xA2:0x8D
+
+# Acid Ball Trap
+G:T:84:0xA2:0x8D
+
+# Cold Ball Trap
+G:T:85:0xA2:0x8D
+
+# Fire Ball Trap
+G:T:86:0xA2:0x8D
+
+# Plasma Ball Trap
+G:T:87:0xA2:0x8D
+
+# Water Ball Trap
+G:T:88:0xA2:0x8D
+
+# Light Ball Trap
+G:T:89:0xA2:0x8D
+
+# Darkness Ball Trap
+G:T:90:0xA2:0x8D
+
+# Shards Ball Trap
+G:T:91:0xA2:0x8D
+
+# Sound Ball Trap
+G:T:92:0xA2:0x8D
+
+# Confusion Ball Trap
+G:T:93:0xA2:0x8D
+
+# Force Ball Trap
+G:T:94:0xA2:0x8D
+
+# Inertia Ball Trap
+G:T:95:0xA2:0x8D
+
+# Mana Ball Trap
+G:T:96:0xA2:0x8D
+
+# Ice Ball Trap
+G:T:97:0xA2:0x8D
+
+# Chaos Ball Trap
+G:T:98:0xA2:0x8D
+
+# Nether Ball Trap
+G:T:99:0xA2:0x8D
+
+# Disenchantment Ball Trap
+G:T:100:0xA2:0x8D
+
+# Nexus Ball Trap
+G:T:101:0xA2:0x8D
+
+# Time Ball Trap
+G:T:102:0xA2:0x8D
+
+# Gravity Ball Trap
+G:T:103:0xA2:0x8D
+
+# Arrow Trap
+G:T:110:0xA2:0x8E
+
+# Bolt Trap
+G:T:111:0xA2:0x8E
+
+# Seeker Arrow Trap
+G:T:112:0xA2:0x8E
+
+# Seeker Bolt Trap
+G:T:113:0xA2:0x8E
+
+# Poison Arrow Trap
+G:T:114:0xA2:0x8E
+
+# Poison Bolt Trap
+G:T:115:0xA2:0x8E
+
+# Poison Seeker Arrow Trap
+G:T:116:0xA2:0x8E
+
+# Poison Seeker Bolt Trap
+G:T:117:0xA2:0x8E
+
+# Broken Dagger Trap
+G:T:118:0xA2:0x8E
+
+# Dagger Trap
+G:T:119:0xA2:0x8E
+
+# Poison Broken Dagger Trap
+G:T:120:0xA2:0x8E
+
+# Poison Dagger Trap
+G:T:121:0xA2:0x8E
+
+# Arrows Trap
+G:T:122:0xA2:0x8E
+
+# Bolts Trap
+G:T:123:0xA2:0x8E
+
+# Seeker Arrow Trap
+G:T:124:0xA2:0x8E
+
+# Seeker Bolt Trap
+G:T:125:0xA2:0x8E
+
+# Poison Arrows Trap
+G:T:126:0xA2:0x8E
+
+# Poison Bolt Trap
+G:T:127:0xA2:0x8E
+
+# Poison Seeker Arrows Trap
+G:T:128:0xA2:0x8E
+
+# Poison Seeker Bolts Trap
+G:T:129:0xA2:0x8E
+
+# Broken Daggers Trap
+G:T:130:0xA2:0x8E
+
+# Dagger Trap
+G:T:131:0xA2:0x8E
+
+# Poison Broken Daggers Trap
+G:T:132:0xA2:0x8E
+
+# Poison Daggers Trap
+G:T:133:0xA2:0x8E
+
+# Trap of Drop Item
+G:T:140:0xA2:0x92
+
+# Trap of Drop Items
+G:T:141:0xA2:0x92
+
+# Trap of Drop Everything
+G:T:142:0xA2:0x92
+
+# Trap of Femininity
+G:T:150:0xA2:0x8B
+
+# Trap of Masculinity
+G:T:151:0xA2:0x8B
+
+# Trap of Neutrality
+G:T:152:0xA2:0x8B
+
+# Trap of Aging
+G:T:153:0xA2:0x8B
+
+# Trap of Growing
+G:T:154:0xA2:0x8B
+
+# Trap of Shrinking
+G:T:155:0xA2:0x8B
+
+# Trap of Tanker Drain
+G:T:157:0xA2:0x8B
+
+# Trap of Divine Anger
+G:T:158:0xA2:0x88
+
+# Trap of Divine Wrath
+G:T:159:0xA2:0x88
+
+# Hallucination Trap
+G:T:160:0xA2:0x8B
+
+# Greater Magic Missile Trap
+G:T:161:0xA2:0x8C
+
+# Foulness Trap
+G:T:162:0xA2:0x8C
+
+# Trap of Death Ray
+G:T:163:0xA2:0x8C
+
+# Trap of Holy Fire
+G:T:164:0xA2:0x8C
+
+# Trap of Hell Fire
+G:T:165:0xA2:0x8C
+
+# Psi Bolt Trap
+G:T:166:0xA2:0x8C
+
+# Psi Drain Trap
+G:T:167:0xA2:0x8B
+
+# Plasma (Nuke) Ball Trap
+G:T:168:0xA2:0x8D
+
+# Psi Ball Trap
+G:T:169:0xA2:0x8D
+
+# Aquirement Trap
+G:T:170:0xA2:0x89
+
+# Greater Lightning Bolt Trap
+G:T:171:0xA2:0x8C
+
+# Greater Poison Bolt Trap
+G:T:172:0xA2:0x8C
+
+# Greater Acid Bolt Trap
+G:T:173:0xA2:0x8C
+
+# Greater Cold Bolt Trap
+G:T:174:0xA2:0x8C
+
+# Greater Fire Bolt Trap
+G:T:175:0xA2:0x8C \ No newline at end of file
diff --git a/lib/mods/theme/pref/user.prf b/lib/mods/theme/pref/user.prf
new file mode 100644
index 00000000..9e10b2ac
--- /dev/null
+++ b/lib/mods/theme/pref/user.prf
@@ -0,0 +1,50 @@
+# File: user.prf
+
+#
+# This file defines "override" actions of various kinds
+#
+# This file includes, if appropriate, various "sub-files"
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+## Option -- Force the use of original commands
+#X:rogue_like_commands
+
+## Option -- Force the use of roguelike commands
+#Y:rogue_like_commands
+
+
+##### System Specific Subfiles #####
+
+?:[IOR [EQU $SYS xaw] [EQU $SYS x11]]
+%:user-x11.prf
+
+?:[EQU $SYS gcu]
+%:user-gcu.prf
+
+?:[EQU $SYS ami]
+%:user-ami.prf
+
+?:[EQU $SYS mac]
+%:user-mac.prf
+
+?:[EQU $SYS dos]
+%:user-dos.prf
+
+?:[EQU $SYS ibm]
+%:user-ibm.prf
+
+?:[EQU $SYS win]
+%:user-win.prf
+
+?:[EQU $SYS emx]
+%:user-emx.prf
+
+?:[EQU $SYS acn]
+%:user-acn.prf
+
+?:1
+
+
diff --git a/lib/mods/theme/pref/xtra-gcu.prf b/lib/mods/theme/pref/xtra-gcu.prf
new file mode 100644
index 00000000..7097658e
--- /dev/null
+++ b/lib/mods/theme/pref/xtra-gcu.prf
@@ -0,0 +1,34 @@
+# File: xtra-gcu.prf
+
+# Rename this file to "pref-gcu.prf" to allow the VT100 cursor keys
+# to be recognized by Angband. This will also make the "escape" key
+# take a few seconds to recognize, so you may want to use the "`" key
+# instead, or make a macro from escape+escape to escape.
+
+### VT100 Keypad ###
+
+# Special keypad keys (delete, insert)
+A:.
+P:\e[3~
+A:0
+P:\e[2~
+
+# Numerical keypad keys (map to appropriate number)
+A:1
+P:\e[4~
+A:2
+P:\e[B
+A:3
+P:\e[6~
+A:4
+P:\e[D
+A:5
+P:\e[G
+A:6
+P:\e[C
+A:7
+P:\e[1~
+A:8
+P:\e[A
+A:9
+P:\e[5~
diff --git a/lib/mods/theme/pref/xtra-new.prf b/lib/mods/theme/pref/xtra-new.prf
new file mode 100644
index 00000000..214796cf
--- /dev/null
+++ b/lib/mods/theme/pref/xtra-new.prf
@@ -0,0 +1,63 @@
+# File: xtra-new.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# Edited for use with Adam Bolt's new graphics by Robert Ruehlmann < rr9@angband.org >
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+##### AK 20011216 Default pictures for all races that
+# are not handled below, without caring for class
+
+
+?:[EQU $RACE Human]
+R:0:0x89/0xA0
+?:[EQU $RACE Half-Elf]
+R:0:0x89/0xA1
+?:[EQU $RACE Elf]
+R:0:0x89/0xA2
+?:[EQU $RACE Hobbit]
+R:0:0x89/0xA3
+?:[EQU $RACE Gnome]
+R:0:0x89/0xA4
+?:[EQU $RACE Dwarf]
+R:0:0x89/0xA5
+?:[EQU $RACE Orc]
+R:0:0x89/0xA6
+?:[EQU $RACE Troll]
+R:0:0x89/0xA7
+?:[EQU $RACE Dunadan]
+R:0:0x89/0xA8
+?:[EQU $RACE High-Elf]
+R:0:0x89/0xA9
+?:[EQU $RACE Half-Ogre]
+R:0:0x89/0xAA
+?:[EQU $RACE Beorning]
+R:0:0x89/0xAB
+?:[EQU $RACE Druadan]
+R:0:0x89/0xAC
+?:[EQU $RACE Petty-Dwarf]
+R:0:0x89/0xAD
+?:[EQU $RACE Dark-Elf]
+R:0:0x89/0xAE
+?:[EQU $RACE Ent]
+R:0:0x89/0xAF
+?:[EQU $RACE RohanKnight]
+R:0:0x89/0xB0
+?:[EQU $RACE Eagle]
+R:0:0x89/0xB1
+?:[EQU $RACE Dragon]
+R:0:0x89/0xB2
+?:[EQU $RACE Yeek]
+R:0:0x89/0xB3
+?:[EQU $RACE Wood-Elf]
+R:0:0x89/0xB4
+?:[EQU $RACE Maia]
+R:0:0x89/0xB5
+?:[EQU $RACE Easterling]
+R:0:0x89/0xB6
+?:[EQU $RACE Demon]
+R:0:0x89/0xB7 \ No newline at end of file
diff --git a/lib/mods/theme/pref/xtra-xxx.prf b/lib/mods/theme/pref/xtra-xxx.prf
new file mode 100644
index 00000000..0c6186de
--- /dev/null
+++ b/lib/mods/theme/pref/xtra-xxx.prf
@@ -0,0 +1,137 @@
+# File: xtra-xxx.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+##### Remap the player icon #####
+
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Human] ]
+R:0:0x8C/0x80
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Elf] ]
+R:0:0x8C/0x81
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Elf] ]
+R:0:0x8C/0x82
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Hobbit] ]
+R:0:0x8C/0x83
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Gnome] ]
+R:0:0x8C/0x84
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Dwarf] ]
+R:0:0x8C/0x85
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Orc] ]
+R:0:0x8C/0x86
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Troll] ]
+R:0:0x8C/0x87
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Dunadan] ]
+R:0:0x8C/0x88
+?:[AND [EQU $CLASS Warrior] [EQU $RACE High-Elf] ]
+R:0:0x8C/0x89
+
+?:[AND [EQU $CLASS Mage] [EQU $RACE Human] ]
+R:0:0x8C/0x8A
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Elf] ]
+R:0:0x8C/0x8B
+?:[AND [EQU $CLASS Mage] [EQU $RACE Elf] ]
+R:0:0x8C/0x8C
+?:[AND [EQU $CLASS Mage] [EQU $RACE Hobbit] ]
+R:0:0x8C/0x8D
+?:[AND [EQU $CLASS Mage] [EQU $RACE Gnome] ]
+R:0:0x8C/0x8E
+?:[AND [EQU $CLASS Mage] [EQU $RACE Dwarf] ]
+R:0:0x8C/0x8F
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Orc] ]
+R:0:0x8C/0x90
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Troll] ]
+R:0:0x8C/0x91
+?:[AND [EQU $CLASS Mage] [EQU $RACE Dunadan] ]
+R:0:0x8C/0x92
+?:[AND [EQU $CLASS Mage] [EQU $RACE High-Elf] ]
+R:0:0x8C/0x93
+
+?:[AND [EQU $CLASS Priest] [EQU $RACE Human] ]
+R:0:0x8C/0x94
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Elf] ]
+R:0:0x8C/0x95
+?:[AND [EQU $CLASS Priest] [EQU $RACE Elf] ]
+R:0:0x8C/0x96
+?:[AND [EQU $CLASS Priest] [EQU $RACE Hobbit] ]
+R:0:0x8C/0x97
+?:[AND [EQU $CLASS Priest] [EQU $RACE Gnome] ]
+R:0:0x8C/0x98
+?:[AND [EQU $CLASS Priest] [EQU $RACE Dwarf] ]
+R:0:0x8C/0x99
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Orc] ]
+R:0:0x8C/0x9A
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Troll] ]
+R:0:0x8C/0x9B
+?:[AND [EQU $CLASS Priest] [EQU $RACE Dunadan] ]
+R:0:0x8C/0x9C
+?:[AND [EQU $CLASS Priest] [EQU $RACE High-Elf] ]
+R:0:0x8C/0x9D
+
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Human] ]
+R:0:0x8C/0x9E
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Elf] ]
+R:0:0x8C/0x9F
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Elf] ]
+R:0:0x8D/0x80
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Hobbit] ]
+R:0:0x8D/0x81
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Gnome] ]
+R:0:0x8D/0x82
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Dwarf] ]
+R:0:0x8D/0x83
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Orc] ]
+R:0:0x8D/0x84
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Troll] ]
+R:0:0x8D/0x85
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Dunadan] ]
+R:0:0x8D/0x86
+?:[AND [EQU $CLASS Rogue] [EQU $RACE High-Elf] ]
+R:0:0x8D/0x87
+
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Human] ]
+R:0:0x8D/0x88
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Elf] ]
+R:0:0x8D/0x89
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Elf] ]
+R:0:0x8D/0x8A
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Hobbit] ]
+R:0:0x8D/0x8B
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Gnome] ]
+R:0:0x8D/0x8C
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Dwarf] ]
+R:0:0x8D/0x8D
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Orc] ]
+R:0:0x8D/0x8E
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Troll] ]
+R:0:0x8D/0x8F
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Dunadan] ]
+R:0:0x8D/0x90
+?:[AND [EQU $CLASS Ranger] [EQU $RACE High-Elf] ]
+R:0:0x8D/0x91
+
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Human] ]
+R:0:0x8D/0x92
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Elf] ]
+R:0:0x8D/0x93
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Elf] ]
+R:0:0x8D/0x94
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Hobbit] ]
+R:0:0x8D/0x95
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Gnome] ]
+R:0:0x8D/0x96
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Dwarf] ]
+R:0:0x8D/0x97
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Orc] ]
+R:0:0x8D/0x98
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Troll] ]
+R:0:0x8D/0x99
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Dunadan] ]
+R:0:0x8D/0x9A
+?:[AND [EQU $CLASS Paladin] [EQU $RACE High-Elf] ]
+R:0:0x8D/0x9B
+
diff --git a/lib/mods/theme/save/delete.me b/lib/mods/theme/save/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/mods/theme/save/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/mods/theme/scpt/bounty.lua b/lib/mods/theme/scpt/bounty.lua
new file mode 100644
index 00000000..94c15598
--- /dev/null
+++ b/lib/mods/theme/scpt/bounty.lua
@@ -0,0 +1,90 @@
+-- The bounty quest! bring back corpses to increase your monster lore skill
+
+add_quest
+{
+ ["global"] = "BOUNTY_QUEST",
+ ["name"] = "Bounty quest",
+ ["desc"] = function()
+ if quest(BOUNTY_QUEST).status == QUEST_STATUS_TAKEN then
+ print_hook("#####yBounty quest!\n")
+ print_hook("You must bring back "..monster_race_desc(bounty_quest_monster, 0).." corpse to the beastmaster.\n")
+ print_hook("\n")
+ end
+ end,
+ ["level"] = -1,
+ ["data"] = {
+ ["bounty_quest_monster"] = 0,
+ },
+ ["hooks"] = {
+ -- Start the game without the quest, need to request it
+ [HOOK_BIRTH_OBJECTS] = function()
+ quest(BOUNTY_QUEST).status = QUEST_STATUS_UNTAKEN
+ end,
+ },
+}
+
+add_building_action
+{
+ -- Index is used in ba_info.txt to set the actions
+ ["index"] = 54,
+ ["action"] = function()
+ if quest(BOUNTY_QUEST).status == QUEST_STATUS_UNTAKEN then
+ quest(BOUNTY_QUEST).status = QUEST_STATUS_TAKEN
+ bounty_quest_monster = get_new_bounty_monster(3 + ((player.lev * 3) / 2))
+
+ msg_print("You must bring me back "..monster_race_desc(bounty_quest_monster, 0).." corpse.")
+ else
+ msg_print("You still must bring me back "..monster_race_desc(bounty_quest_monster, 0).." corpse.")
+ end
+ end
+}
+
+add_building_action
+{
+ -- Index is used in ba_info.txt to set the actions
+ ["index"] = 55,
+ ["action"] = function()
+ if quest(BOUNTY_QUEST).status == QUEST_STATUS_TAKEN then
+ local ret, item
+
+ -- Ask for an item
+ ret, item = get_item("What corpse to return?",
+ "You have no corpse to return.",
+ bor(USE_INVEN),
+ function (obj)
+ if (obj.tval == TV_CORPSE) and (obj.pval2 == bounty_quest_monster) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+
+ -- Ok we got the corpse!
+ if ret == TRUE then
+ -- Take the corpse from the inventory
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+
+ msg_print("Ah well done adventurer!")
+ msg_print("As a reward I will teach you a bit of monster lore.")
+
+ if skill(SKILL_LORE).mod == 0 then
+ skill(SKILL_LORE).mod = 900
+ skill(SKILL_LORE).dev = TRUE
+ end
+ skill(SKILL_LORE).value = skill(SKILL_LORE).value + skill(SKILL_LORE).mod
+ if skill(SKILL_PRESERVATION).mod == 0 then
+ skill(SKILL_PRESERVATION).value = 800
+ skill(SKILL_PRESERVATION).mod = 800
+ skill(SKILL_PRESERVATION).dev = TRUE
+ msg_print("I see you don't know the corpse preservation skill, I shall teach you it too.")
+ end
+
+ quest(BOUNTY_QUEST).status = QUEST_STATUS_UNTAKEN
+ bounty_quest_monster = 0
+ end
+ else
+ msg_print("You do not have any bounty quest yet.")
+ end
+ end
+}
diff --git a/lib/mods/theme/scpt/corrupt.lua b/lib/mods/theme/scpt/corrupt.lua
new file mode 100644
index 00000000..f402add3
--- /dev/null
+++ b/lib/mods/theme/scpt/corrupt.lua
@@ -0,0 +1,1089 @@
+-- Definition of the corruptions
+-- Theme adds the restriction T-Plus has for Maiar: they may only gain the Balrog corruptions.
+
+-- The Balrog corruptions
+CORRUPT_BALROG_AURA = add_corruption
+{
+ ["color"] = TERM_ORANGE,
+ ["name"] = "Balrog Aura",
+ ["get_text"] = "A corrupted wall of flames surrounds you.",
+ ["lose_text"] = "The wall of corrupted flames abandons you.",
+ ["desc"] =
+ {
+ " Surrounds you with a fiery aura",
+ " But it can burn scrolls when you read them"
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SH_FIRE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_LITE1)
+ end,
+ [HOOK_READ] = function(obj)
+ if magik(5) == TRUE then
+ msg_print("Your demon aura burns the scroll before you read it!")
+ return TRUE, TRUE, FALSE
+ else
+ return FALSE
+ end
+ end,
+ },
+}
+
+CORRUPT_BALROG_WINGS = add_corruption
+{
+ ["color"] = TERM_ORANGE,
+ ["name"] = "Balrog Wings",
+ ["get_text"] = "Wings of shadow grow in your back.",
+ ["lose_text"] = "The wings in your back fall apart.",
+ ["desc"] =
+ {
+ " Creates ugly, but working, wings allowing you to fly",
+ " But it reduces charisma by 4 and dexterity by 2"
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.xtra_f4 = bor(player.xtra_f4, TR4_FLY)
+ player.modify_stat(A_CHR, -4)
+ player.modify_stat(A_DEX, -2)
+ end,
+ },
+}
+
+CORRUPT_BALROG_STRENGTH = add_corruption
+{
+ ["color"] = TERM_ORANGE,
+ ["name"] = "Balrog Strength",
+ ["get_text"] = "Your muscles get unnatural strength.",
+ ["lose_text"] = "Your muscles get weaker again.",
+ ["desc"] =
+ {
+ " Provides 3 strength and 1 constitution",
+ " But it reduces charisma by 1 and dexterity by 3"
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.modify_stat(A_STR, 3)
+ player.modify_stat(A_CON, 1)
+ player.modify_stat(A_DEX, -3)
+ player.modify_stat(A_CHR, -1)
+ end,
+ },
+}
+
+CORRUPT_BALROG_FORM = add_corruption
+{
+ ["color"] = TERM_YELLOW,
+ ["name"] = "Balrog Form",
+ ["get_text"] = "You feel the might of a Balrog inside you.",
+ ["lose_text"] = "The presence of the Balrog seems to abandon you.",
+ ["desc"] =
+ {
+ " Allows you to turn into a Balrog at will",
+ " You need Balrog Wings, Balrog Aura and Balrog Strength to activate it"
+ },
+ ["depends"] =
+ {
+ [CORRUPT_BALROG_AURA] = TRUE,
+ [CORRUPT_BALROG_WINGS] = TRUE,
+ [CORRUPT_BALROG_STRENGTH] = TRUE
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_BALROG)
+ end,
+ },
+}
+
+
+-- The Demon corruptions
+CORRUPT_DEMON_SPIRIT = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Demon Spirit",
+ ["get_text"] = "Your spirit opens to corrupted thoughts.",
+ ["lose_text"] = "Your spirit closes again to the corrupted thoughts.",
+ ["desc"] =
+ {
+ " Increases your intelligence by 1",
+ " But reduce your charisma by 2",
+ },
+["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.modify_stat(A_INT, 1)
+ player.modify_stat(A_CHR, -2)
+ end,
+ },
+}
+
+CORRUPT_DEMON_HIDE = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Demon Hide",
+ ["get_text"] = "Your skin grows into a thick hide.",
+ ["lose_text"] = "Your skin returns to a natural state.",
+ ["desc"] =
+ {
+ " Increases your armour class by your level",
+ " Provides immunity to fire at level 40",
+ " But reduces speed by your level / 7",
+ },
+["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.to_a = player.to_a + player.lev
+ player.dis_to_a = player.dis_to_a + player.lev
+ player.pspeed = player.pspeed - (player.lev / 7)
+ if player.lev >= 40 then player.xtra_f2 = bor(player.xtra_f2, TR2_IM_FIRE) end
+ end,
+ },
+}
+
+CORRUPT_DEMON_BREATH = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Demon Breath",
+ ["get_text"] = "Your breath becomes mephitic.",
+ ["lose_text"] = "Your breath is once again normal.",
+ ["desc"] =
+ {
+ " Provides fire breath",
+ " But gives a small chance to spoil potions when you quaff them",
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_BR_FIRE)
+ end,
+ [HOOK_QUAFF] = function(obj)
+ if magik(9) == TRUE then
+ msg_print("Your demon breath spoils the potion!")
+ return TRUE, FALSE
+ else
+ return FALSE
+ end
+ end,
+ },
+}
+
+CORRUPT_DEMON_REALM = add_corruption
+{
+ ["color"] = TERM_L_RED,
+ ["name"] = "Demon Realm",
+ ["get_text"] = "You feel more attuned to the demon realm.",
+ ["lose_text"] = "You lose your attunement to the demon realm.",
+ ["desc"] =
+ {
+ " Provides access to the demon school skill and the use of demonic equipment",
+ " You need Demon Spirit, Demon Hide and Demon Breath to activate it"
+ },
+ ["depends"] =
+ {
+ [CORRUPT_DEMON_SPIRIT] = TRUE,
+ [CORRUPT_DEMON_HIDE] = TRUE,
+ [CORRUPT_DEMON_BREATH] = TRUE
+ },
+["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ -- 1500 may seem a lot, but people are rather unlikely to get the corruption very soon
+ -- due to the dependencies
+ if s_info[SKILL_DAEMON + 1].mod == 0 then s_info[SKILL_DAEMON + 1].mod = 1500 end
+ s_info[SKILL_DAEMON + 1].hidden = FALSE;
+ end,
+ },
+}
+
+
+-- Teleportation corruptions
+
+-- Random teleportation will ask for confirmation 70% of the time
+-- But 30% of the time it will teleport, without asking
+CORRUPT_RANDOM_TELEPORT = add_corruption
+{
+ ["color"] = TERM_GREEN,
+ ["name"] = "Random teleportation",
+ ["get_text"] = "Space seems to fizzle around you.",
+ ["lose_text"] = "Space solidify again around you.",
+ ["desc"] =
+ {
+ " Randomly teleports you around",
+ },
+["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ -- No oppose field, it will be automatically set when we declare the anti-telep corruption to oppose us
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.xtra_f3 = bor(player.xtra_f3, TR3_TELEPORT)
+ end,
+ [HOOK_PROCESS_WORLD] = function()
+ if rand_int(300) == 1 then
+ if magik(70) == TRUE then
+ if get_check("Teleport?") == TRUE then
+ teleport_player(50)
+ end
+ else
+ disturb(0, 0)
+ msg_print("Your corruption takes over you, you teleport!")
+ teleport_player(50)
+ end
+ end
+ end,
+ },
+}
+
+-- Anti-teleportation corruption, can be stopped with this power
+CORRUPT_ANTI_TELEPORT = add_corruption
+{
+ ["color"] = TERM_GREEN,
+ ["name"] = "Anti-teleportation",
+ ["get_text"] = "Space continuum freezes around you.",
+ ["lose_text"] = "Space continuum can once more be altered around you.",
+ ["desc"] =
+ {
+ " Prevents all teleportations, be it of you or monsters",
+ },
+ ["oppose"] =
+ {
+ [CORRUPT_RANDOM_TELEPORT] = TRUE
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_BIRTH_OBJECTS] = function()
+ player.corrupt_anti_teleport_stopped = FALSE
+ end,
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(POWER_COR_SPACE_TIME)
+ end,
+ [HOOK_CALC_BONUS] = function()
+ if player.corrupt_anti_teleport_stopped == FALSE then
+ player.resist_continuum = TRUE
+ end
+ end,
+ [HOOK_PROCESS_WORLD] = function()
+ if player.corrupt_anti_teleport_stopped == TRUE then
+ local amt = player.msp + player.csp
+ amt = amt / 100
+ if (amt < 1) then amt = 1 end
+ increase_mana(-amt)
+ if player.csp == 0 then
+ player.corrupt_anti_teleport_stopped = FALSE
+ msg_print("You stop controlling your corruption.")
+ player.update = bor(player.update, PU_BONUS)
+ end
+ end
+ end,
+ },
+}
+
+
+-- Troll blood
+CORRUPT_TROLL_BLOOD = add_corruption
+{
+ ["color"] = TERM_GREEN,
+ ["name"] = "Troll Blood",
+ ["get_text"] = "Your blood thickens, you sense corruption in it.",
+ ["lose_text"] = "Your blood returns to a normal state.",
+ ["desc"] =
+ {
+ " Troll blood flows in your veins, granting increased regeneration",
+ " It also enables you to feel the presence of other troll beings",
+ " But it will make your presence more noticeable and aggravating",
+ },
+ ["can_gain"] = function()
+ -- Ok trolls should not get this one. never.
+ local str = get_race_name()
+ if (str == "Maia") or (str == "Troll") then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN, TR3_AGGRAVATE)
+ player.xtra_esp = bor(player.xtra_esp, ESP_TROLL)
+ end,
+ },
+}
+
+-- The vampire corruption set
+CORRUPT_VAMPIRE_TEETH = add_corruption
+{
+ ["group"] = "Vampire",
+ ["removable"] = FALSE,
+ ["color"] = TERM_L_DARK,
+ ["name"] = "Vampiric Teeth",
+ ["get_text"] = "You grow vampiric teeth!",
+ ["lose_text"] = "BUG! this should not happen",
+ ["desc"] =
+ {
+ " Your teeth allow you to drain blood to feed yourself",
+ " However your stomach now only accepts blood.",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["allow"] = function()
+ if test_race_flags(1, PR1_NO_SUBRACE_CHANGE) == FALSE then return not nil else return nil end
+ end,
+ ["gain"] = function()
+ switch_subrace(SUBRACE_SAVE, TRUE);
+
+ subrace_add_power(subrace(SUBRACE_SAVE), PWR_VAMPIRISM)
+ subrace(SUBRACE_SAVE).flags1 = bor(subrace(SUBRACE_SAVE).flags1, PR1_VAMPIRE, PR1_UNDEAD, PR1_NO_SUBRACE_CHANGE)
+ end,
+ ["hooks"] =
+ {
+ },
+}
+CORRUPT_VAMPIRE_STRENGTH = add_corruption
+{
+ ["group"] = "Vampire",
+ ["removable"] = FALSE,
+ ["color"] = TERM_L_DARK,
+ ["name"] = "Vampiric Strength",
+ ["get_text"] = "Your body seems more dead than alive.",
+ ["lose_text"] = "BUG! this should not happen",
+ ["desc"] =
+ {
+ " Your body seems somewhat dead",
+ " In this near undead state it has improved strength, constitution and intelligence",
+ " But reduced dexterity, wisdom and charisma.",
+ },
+ ["depends"] =
+ {
+ [CORRUPT_VAMPIRE_TEETH] = TRUE,
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["gain"] = function()
+ -- Apply the bonuses/penalities
+ subrace(SUBRACE_SAVE).r_mhp = subrace(SUBRACE_SAVE).r_mhp + 1
+ subrace(SUBRACE_SAVE).r_exp = subrace(SUBRACE_SAVE).r_exp + 100
+
+ subrace(SUBRACE_SAVE).r_adj[A_STR + 1] = subrace(SUBRACE_SAVE).r_adj[A_STR + 1] + 3
+ subrace(SUBRACE_SAVE).r_adj[A_INT + 1] = subrace(SUBRACE_SAVE).r_adj[A_INT + 1] + 2
+ subrace(SUBRACE_SAVE).r_adj[A_WIS + 1] = subrace(SUBRACE_SAVE).r_adj[A_WIS + 1] - 3
+ subrace(SUBRACE_SAVE).r_adj[A_DEX + 1] = subrace(SUBRACE_SAVE).r_adj[A_DEX + 1] - 2
+ subrace(SUBRACE_SAVE).r_adj[A_CON + 1] = subrace(SUBRACE_SAVE).r_adj[A_CON + 1] + 1
+ subrace(SUBRACE_SAVE).r_adj[A_CHR + 1] = subrace(SUBRACE_SAVE).r_adj[A_CHR + 1] - 4
+
+ -- be reborn!
+ do_rebirth()
+ cmsg_print(TERM_L_DARK, "You feel death slipping inside.")
+ end,
+ ["hooks"] =
+ {
+ },
+}
+CORRUPT_VAMPIRE_VAMPIRE = add_corruption
+{
+ ["group"] = "Vampire",
+ ["removable"] = FALSE,
+ ["color"] = TERM_L_DARK,
+ ["name"] = "Vampire",
+ ["get_text"] = "You die to be reborn in a Vampire form.",
+ ["lose_text"] = "BUG! this should not happen",
+ ["desc"] =
+ {
+ " You are a Vampire. As such you resist cold, poison, darkness and nether.",
+ " Your life is sustained, but you cannot stand the light of the sun."
+ },
+ ["depends"] =
+ {
+ [CORRUPT_VAMPIRE_STRENGTH] = TRUE,
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["gain"] = function()
+ -- Be a Vampire and be proud of it
+ local title = get_subrace_title(SUBRACE_SAVE)
+ if title == " " or title == "Vampire" then
+ title = "Vampire"
+ subrace(SUBRACE_SAVE).place = FALSE
+ else
+ title = "Vampire "..title
+ end
+ set_subrace_title(SUBRACE_SAVE, title)
+
+ -- Bonus/and .. not bonus :)
+ subrace(SUBRACE_SAVE).flags1 = bor(subrace(SUBRACE_SAVE).flags1, PR1_HURT_LITE)
+ subrace(SUBRACE_SAVE).oflags2[2] = bor(subrace(SUBRACE_SAVE).oflags2[2], TR2_RES_POIS, TR2_RES_NETHER, TR2_RES_COLD, TR2_RES_DARK, TR2_HOLD_LIFE)
+ subrace(SUBRACE_SAVE).oflags3[2] = bor(subrace(SUBRACE_SAVE).oflags3[2], TR3_LITE1)
+ end,
+ ["hooks"] =
+ {
+ },
+}
+
+-- The old activable corruptions / mutations
+
+MUT1_SPIT_ACID = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Ancalagon's Breath",
+ ["get_text"] = "You gain the ability to spit acid.",
+ ["lose_text"] = "You lose the ability to spit acid.",
+ ["desc"] =
+ {
+ " Fires an acid ball.",
+ " Damage=level Radius 1+(level/30)",
+ " Level=9, Cost=9, Stat=DEX, Difficulty=15",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_SPIT_ACID)
+ end,
+ },
+}
+
+MUT1_BR_FIRE = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Smaug's Breath",
+ ["get_text"] = "You gain the ability to breathe fire.",
+ ["lose_text"] = "You lose the ability to breathe fire.",
+ ["desc"] =
+ {
+ " Fires a fire ball.",
+ " Damage=2*level Radius 1+(level/20)",
+ " Level=20, Cost=10, Stat=CON, Difficulty=18",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_BR_FIRE)
+ end,
+ },
+}
+
+MUT1_HYPN_GAZE = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Glaurung's Gaze",
+ ["get_text"] = "Your eyes look mesmerizing...",
+ ["lose_text"] = "Your eyes look uninteresting.",
+ ["desc"] =
+ {
+ " Tries to make a monster your pet.",
+ " Power=level",
+ " Level=12, Cost=12, Stat=CHR, Difficulty=18",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_HYPN_GAZE)
+ end,
+ },
+}
+
+MUT1_TELEKINES = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Saruman's Power",
+ ["get_text"] = "You gain the ability to move objects telekinetically.",
+ ["lose_text"] = "You lose the ability to move objects telekinetically.",
+ ["desc"] =
+ {
+ " Move an object in line of sight to you.",
+ " Max weight equal to (level) pounds",
+ " Level=9, Cost=9, Stat=WIS, Difficulty=14",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_TELEKINES)
+ end,
+ },
+}
+
+MUT1_VTELEPORT = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Teleport",
+ ["get_text"] = "You gain the power of teleportation at will.",
+ ["lose_text"] = "You lose the power of teleportation at will.",
+ ["desc"] =
+ {
+ " Teleports the player at will.",
+ " Distance 10+4*level squares",
+ " Level=7, Cost=7, Stat=WIS, Difficulty=15",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_VTELEPORT)
+ end,
+ },
+}
+
+MUT1_MIND_BLST = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Glaurung's Spell",
+ ["get_text"] = "You gain the power of Mind Blast.",
+ ["lose_text"] = "You lose the power of Mind Blast.",
+ ["desc"] =
+ {
+ " Fires a mind blasting bolt (psi damage).",
+ " Psi Damage (3+(level-1)/5)d3",
+ " Level=5, Cost=3, Stat=WIS, Difficulty=15",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_MIND_BLST)
+ end,
+ },
+}
+
+MUT1_VAMPIRISM = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Vampiric Drain",
+ ["get_text"] = "You become vampiric.",
+ ["lose_text"] = "You are no longer vampiric.",
+ ["desc"] =
+ {
+ " You can drain life from a foe like a vampire.",
+ " Drains (level+1d(level))*(level/10) hitpoints,",
+ " heals you and satiates you. Doesn't work on all monsters",
+ " Level=4, Cost=5, Stat=CON, Difficulty=9",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_VAMPIRISM)
+ end,
+ },
+}
+
+MUT1_SMELL_MET = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Carcharoth's Nose",
+ ["get_text"] = "You smell a metallic odour.",
+ ["lose_text"] = "You no longer smell a metallic odour.",
+ ["desc"] =
+ {
+ " You can detect nearby precious metal (treasure).",
+ " Radius 25",
+ " Level=3, Cost=2, Stat=INT, Difficulty=12",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_SMELL_MET)
+ end,
+ },
+}
+
+MUT1_SMELL_MON = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Huan's Nose",
+ ["get_text"] = "You smell filthy monsters.",
+ ["lose_text"] = "You no longer smell filthy monsters.",
+ ["desc"] =
+ {
+ " You can detect nearby monsters.",
+ " Radius 25",
+ " Level=5, Cost=4, Stat=INT, Difficulty=15",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_SMELL_MON)
+ end,
+ },
+}
+
+MUT1_BLINK = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Blink",
+ ["get_text"] = "You gain the power of minor teleportation.",
+ ["lose_text"] = "You lose the power of minor teleportation.",
+ ["desc"] =
+ {
+ " You can teleport yourself short distances (10 squares).",
+ " Level=3, Cost=3, Stat=WIS, Difficulty=12",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_BLINK)
+ end,
+ },
+}
+
+MUT1_EAT_ROCK = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Eat Rock",
+ ["get_text"] = "The walls look delicious.",
+ ["lose_text"] = "The walls look unappetizing.",
+ ["desc"] =
+ {
+ " You can consume solid rock with food benefit,",
+ " leaving an empty space behind.",
+ " Level=8, Cost=12, Stat=CON, Difficulty=18",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_EAT_ROCK)
+ end,
+ },
+}
+
+MUT1_SWAP_POS = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Swap Position",
+ ["get_text"] = "You feel like walking a mile in someone else's shoes.",
+ ["lose_text"] = "You feel like staying in your own shoes.",
+ ["desc"] =
+ {
+ " You can switch locations with another being,",
+ " unless it resists teleportation.",
+ " Level=15, Cost=12, Stat=DEX, Difficulty=16",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_SWAP_POS)
+ end,
+ },
+}
+
+MUT1_SHRIEK = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Shriek",
+ ["get_text"] = "Your vocal cords get much tougher.",
+ ["lose_text"] = "Your vocal cords get much weaker.",
+ ["desc"] =
+ {
+ " Fires a sound ball and aggravates monsters.",
+ " Damage=level*4, Radius=8, centered on player",
+ " Level=4, Cost=4, Stat=CON, Difficulty=6",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_SHRIEK)
+ end,
+ },
+}
+
+MUT1_ILLUMINE = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Illuminate",
+ ["get_text"] = "You can light up rooms with your presence.",
+ ["lose_text"] = "You can no longer light up rooms with your presence.",
+ ["desc"] =
+ {
+ " You can emit bright light that illuminates an area.",
+ " Damage=2d(level/2) Radius=(level/10)+1",
+ " Level=3, Cost=2, Stat=INT, Difficulty=10",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_ILLUMINE)
+ end,
+ },
+}
+
+MUT1_DET_CURSE = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Detect Curses",
+ ["get_text"] = "You can feel evil magics.",
+ ["lose_text"] = "You can no longer feel evil magics.",
+ ["desc"] =
+ {
+ " You can feel the danger of evil magic.",
+ " It detects cursed items in the inventory",
+ " Level=7, Cost=14, Stat=WIS, Difficulty=14",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_DET_CURSE)
+ end,
+ },
+}
+
+MUT1_BERSERK = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Berserk",
+ ["get_text"] = "You feel a controlled rage.",
+ ["lose_text"] = "You no longer feel a controlled rage.",
+ ["desc"] =
+ {
+ " You can drive yourself into a berserk frenzy.",
+ " It grants super-heroism. Duration=10+1d(level)",
+ " Level=8, Cost=8, Stat=STR, Difficulty=14",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_BERSERK)
+ end,
+ },
+}
+
+
+MUT1_MIDAS_TCH = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Midas touch",
+ ["get_text"] = "You gain the Midas touch.",
+ ["lose_text"] = "You lose the Midas touch.",
+ ["desc"] =
+ {
+ " You can turn ordinary items to gold.",
+ " Turns a non-artifact object into 1/3 its value in gold",
+ " Level=10, Cost=5, Stat=INT, Difficulty=12",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_MIDAS_TCH)
+ end,
+ },
+}
+
+MUT1_GROW_MOLD = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Grow Mold",
+ ["get_text"] = "You feel a sudden affinity for mold.",
+ ["lose_text"] = "You feel a sudden dislike for mold.",
+ ["desc"] =
+ {
+ " You can cause mold to grow near you.",
+ " Summons up to 8 molds around the player",
+ " Level=1, Cost=6, Stat=CON, Difficulty=14",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_GROW_MOLD)
+ end,
+ },
+}
+
+MUT1_RESIST = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Resist Elements",
+ ["get_text"] = "You feel like you can protect yourself.",
+ ["lose_text"] = "You feel like you might be vulnerable.",
+ ["desc"] =
+ {
+ " You can harden yourself to the ravages of the elements.",
+ " Level-dependent chance of gaining resistances to the four ",
+ " elements and poison. Duration=20 + d20",
+ " Level=10, Cost=12, Stat=CON, Difficulty=12",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_RESIST)
+ end,
+ },
+}
+
+MUT1_EARTHQUAKE = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Earthquake",
+ ["get_text"] = "You gain the ability to wreck the dungeon.",
+ ["lose_text"] = "You lose the ability to wreck the dungeon.",
+ ["desc"] =
+ {
+ " You can bring down the dungeon around your ears.",
+ " Radius=10, center on the player",
+ " Level=12, Cost=12, Stat=STR, Difficulty=16",
+ },
+ ["can_gain"] = function()
+ -- Maiar can't get this one!
+ local str = get_race_name()
+ if str == "Maia" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_EARTHQUAKE)
+ end,
+ },
+}
+--[[
+CORRUPT_ = add_corruption
+{
+ ["color"] = TERM_GREEN,
+ ["name"] = "",
+ ["get_text"] = "",
+ ["lose_text"] = "",
+ ["desc"] =
+ {
+ " ",
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ end,
+ },
+}
+]]
diff --git a/lib/mods/theme/scpt/drunk.lua b/lib/mods/theme/scpt/drunk.lua
new file mode 100644
index 00000000..7d90af8d
--- /dev/null
+++ b/lib/mods/theme/scpt/drunk.lua
@@ -0,0 +1,21 @@
+-- silly function that allows a drunk to take a bottle of wine/ale from the player
+
+function drunk_takes_wine(m_idx, item)
+
+ m_ptr = monster(m_idx)
+ o_ptr = get_object(item)
+
+ if (m_ptr.r_idx == test_monster_name("Singing, happy drunk"))
+ and (o_ptr.tval == TV_FOOD) and ((o_ptr.sval == 38) or (o_ptr.sval == 39)) then
+
+ cmsg_print(TERM_YELLOW, "'Hic!'")
+
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+add_hook_script(HOOK_GIVE, "drunk_takes_wine", "drunk_takes_wine")
diff --git a/lib/mods/theme/scpt/fireprof.lua b/lib/mods/theme/scpt/fireprof.lua
new file mode 100644
index 00000000..8691b821
--- /dev/null
+++ b/lib/mods/theme/scpt/fireprof.lua
@@ -0,0 +1,415 @@
+-- The Old Mages/Fireproofing quest: Bring back a rune from a fiery cave and get some books/scrolls/staves fireproofed in return
+
+fireproof_quest = {}
+
+
+-- change this constant (and the FOO_POINTS ones) to adjust the no of items fire-proofed as a reward
+fireproof_quest.TOTAL_ITEM_POINTS = 24
+
+-- These constants are how many 'points' each type of item will take up. So currently, you can fireproof 3 books, 4 staves or 12 scrolls.
+fireproof_quest.BOOK_POINTS = 4
+fireproof_quest.STAFF_POINTS = 3
+fireproof_quest.SCROLL_POINTS = 1
+
+add_quest
+{
+ ["global"] = "FIREPROOF_QUEST",
+ ["name"] = "Old Mages quest",
+ ["desc"] = function()
+ local num_books, num_staff, num_scroll
+
+ num_books = fireproof_quest.item_points_remaining / fireproof_quest.BOOK_POINTS
+ num_staff = fireproof_quest.item_points_remaining / fireproof_quest.STAFF_POINTS
+ num_scroll = fireproof_quest.item_points_remaining / fireproof_quest.SCROLL_POINTS
+
+ -- Quest taken
+ if (quest(FIREPROOF_QUEST).status == QUEST_STATUS_TAKEN) then
+ print_hook("#####yAn Old Mages Quest!\n")
+ print_hook("Retrieve the strange rune for the old mage in Lothlorien.\n")
+ print_hook("\n")
+ -- essence retrieved, not taken to mage
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_COMPLETED) then
+ print_hook("#####yAn Old Mages Quest!\n")
+ print_hook("You have retrieved the rune for the old mage in Lothlorien. Perhaps you \n")
+ print_hook("should see about a reward.\n")
+ print_hook("\n")
+ -- essence returned, not all books fireproofed
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_FINISHED) and (fireproof_quest.item_points_remaining > 0) then
+ print_hook("#####yAn Old Mages Quest!\n")
+ print_hook("You have retrieved the rune for the old mage in Lothlorien. He will still \n")
+ print_hook("fireproof "..num_books.." book(s) or "..num_staff.." staff/staves or "..num_scroll.." scroll(s) for you.\n")
+ print_hook("\n")
+ end
+ end,
+ ["level"] = 20,
+ ["data"] = {
+ -- store some variables
+ ["fireproof_quest.item_points_remaining"] = fireproof_quest.TOTAL_ITEM_POINTS,
+ ["fireproof_quest.essence"] = 0,
+ },
+ ["hooks"] = {
+ -- Start the game without the quest, need to request it
+ [HOOK_BIRTH_OBJECTS] = function()
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_UNTAKEN
+
+ -- reset some variables on birth
+ fireproof_quest.item_points_remaining = fireproof_quest.TOTAL_ITEM_POINTS
+ fireproof_quest.essence = 0
+ end,
+ [HOOK_GEN_QUEST] = function()
+ local essence, y, x, traps, tries, trap_y, trap_x, grid
+
+ -- Only if player doing this quest
+ if (player.inside_quest ~= FIREPROOF_QUEST) then
+ return FALSE
+ else
+ -- load the map
+ load_map("fireprof.map", 2, 2)
+
+ -- no teleport
+ level_flags2 = DF2_NO_TELEPORT
+
+ -- determine type of rune
+ fireproof_quest.essence = randint(5)
+
+ -- create essence
+ essence = create_object(TV_RUNE2, fireproof_quest.essence)
+
+ -- mark rune
+ essence.pval2 = fireproof_quest.essence
+ essence.note = quark_add("quest")
+
+ -- roll for co-ordinates in top half of map
+ y = randint(3) + 2
+ x = randint(45) + 2
+
+ -- drop it
+ drop_near(essence, -1, y, x)
+
+ -- how many traps to generate
+ traps = rand_range(10, 30)
+
+ -- generate the traps
+ while (traps > 0) do
+
+ -- initialise tries variable
+ tries = 0
+
+ -- make sure it's a safe place
+ while (tries == 0) do
+
+ -- get grid coordinates
+ trap_y = randint(19) + 2
+ trap_x = randint(45) + 2
+ grid = cave(trap_y, trap_x)
+
+ -- are the coordinates on a stair, or a wall?
+ if (cave_is(grid, FF1_PERMANENT) ~= 0) or (cave_is(grid, FF1_FLOOR) == 0) then
+
+ -- try again
+ tries = 0
+ else
+ -- not a stair, then stop this 'while'
+ tries = 1
+ end
+ end
+
+ -- randomise level of trap
+ trap_level = rand_range(20, 40)
+
+ -- put the trap there
+ place_trap(trap_y, trap_x, trap_level)
+
+ -- that's one less trap to place
+ traps = traps - 1
+ end
+ return TRUE
+ end
+ end,
+ [HOOK_STAIR] = function()
+ local ret
+
+ -- only ask this if player about to go up stairs of quest and hasn't retrieved rune
+ if (player.inside_quest ~= FIREPROOF_QUEST) or
+ (quest(FIREPROOF_QUEST).status == QUEST_STATUS_COMPLETED) then
+ return FALSE
+ else
+ if cave(player.py, player.px).feat ~= FEAT_LESS then return end
+
+ -- flush all pending input
+ flush()
+
+ -- confirm
+ ret = get_check("Really abandon the quest?")
+
+ -- if yes, then
+ if (ret == TRUE) then
+
+ -- fail the quest
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_FAILED
+ return FALSE
+ else
+ -- if no, they stay in the quest
+ return TRUE
+ end
+ end
+ end,
+ [HOOK_GET] = function(o_ptr)
+
+ -- if they're in the quest and haven't picked up the rune already, continue
+ if (player.inside_quest ~= FIREPROOF_QUEST) or
+ (quest(FIREPROOF_QUEST).status == QUEST_STATUS_COMPLETED) then
+ return FALSE
+ else
+
+ -- check that it's the real rune and not another one generated via the random object placing in fireproof.map
+ if (o_ptr.pval2 == fireproof_quest.essence) then
+
+ -- ok mark the quest 'completed'
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_COMPLETED
+ msg_print(TERM_YELLOW, "Fine! Looks like you've found it.")
+ end
+ end
+ end,
+
+ },
+}
+
+-- add the bit that determines what happens when the request 'q'uest bit is done in the wizard spire
+add_building_action
+{
+ -- Index is used in ba_info.txt to set the actions
+ ["index"] = 56,
+ ["action"] = function()
+
+ local num_books, num_staff, num_scroll
+
+ num_books = fireproof_quest.item_points_remaining / fireproof_quest.BOOK_POINTS
+ num_staff = fireproof_quest.item_points_remaining / fireproof_quest.STAFF_POINTS
+ num_scroll = fireproof_quest.item_points_remaining / fireproof_quest.SCROLL_POINTS
+
+ -- the quest hasn;t been requested already, right?
+ if quest(FIREPROOF_QUEST).status == QUEST_STATUS_UNTAKEN then
+
+ -- quest has been taken now
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_TAKEN
+ fireproof_quest.item_points_remaining = fireproof_quest.TOTAL_ITEM_POINTS
+
+ -- issue instructions
+ msg_print("I need a very special rune for a spell I am working on. I am too old to ")
+ msg_print("fetch it myself. Please bring it back to me. You can find it north of here.")
+ msg_print("Be careful with it, it's fragile and might be destroyed easily.")
+
+ return TRUE, FALSE, TRUE
+ -- if quest completed (rune was retrieved)
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_COMPLETED) then
+
+ -- ask for rune
+ ret, item = get_item("Which rune?",
+ "You have no runes to return",
+ bor(USE_INVEN),
+ function (obj)
+
+ -- check it's the 'marked' rune
+ if (obj.tval == TV_RUNE2) and (obj.sval == fireproof_quest.essence) and (obj.pval2 == fireproof_quest.essence) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+
+ -- didn't get the rune?
+ if (ret == FALSE) then
+ return TRUE
+
+ -- got the rune!
+ else
+
+ -- take rune
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+ msg_print("Great! Let me fireproof some of your items in thanks. I can do "..num_books.." books, ")
+ msg_print(num_staff.." staves, or "..num_scroll.." scrolls.")
+
+ -- how many items to proof?
+ local items = fireproof_quest.item_points_remaining
+
+ -- repeat till up to 3 (value defined as TOTAL_ITEM_POINTS constant) books fireproofed
+ while items > 0 do
+ ret = fireproof()
+
+ -- don't loop the fireproof if there's nothing to fireproof
+ if ret == FALSE then
+ break
+ end
+
+ -- subtract item points
+ items = fireproof_quest.item_points_remaining
+ end
+
+ -- have they all been done?
+ if (fireproof_quest.item_points_remaining == 0) then
+ -- mark quest to make sure no more quests are given
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_REWARDED
+ else
+ -- mark in preparation of anymore books to fireproof
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_FINISHED
+ end
+
+
+ end
+
+ -- if the player asks for a quest when they already have it, but haven't failed it, give them some extra instructions
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_TAKEN) then
+ msg_print("The rune is in a cave just behind the shop.")
+
+ -- ok not all books have been fireproofed... lets do the rest
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_FINISHED) then
+
+ -- how many books still to proof?
+ local items = fireproof_quest.item_points_remaining
+
+ -- repeat as necessary
+ while items > 0 do
+ ret = fireproof()
+
+ -- don't loop the fireproof if there's nothing to fireproof
+ if ret == FALSE then
+ break
+ else
+ -- have they all been done?
+ if (fireproof_quest.item_points_remaining == 0) then quest(FIREPROOF_QUEST).status = QUEST_STATUS_REWARDED end
+ end
+
+ -- subtract item points
+ items = fireproof_quest.item_points_remaining
+ end
+
+ -- quest failed or completed, then give no more quests
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_FAILED) or (quest(FIREPROOF_QUEST).status == QUEST_STATUS_REWARDED) then
+ msg_print("I have no more quests for you")
+ end
+ return TRUE
+ end,
+}
+
+-- the routine that checks for a book and actually fireproofs it
+function fireproof()
+
+ local ret, item, obj2, stack, obj3, carry_it
+
+ ret, item = get_item("Which item shall I fireproof?",
+ "You have no more items I can fireproof, come back when you have some.",
+ bor(USE_INVEN),
+ function (obj)
+
+ -- get some flags
+ local f1, f2, f3, f4, f5, esp = object_flags(obj)
+
+ -- is it a book/staff/scroll, is it already fireproof?
+ if ((obj.tval == TV_BOOK) or (obj.tval == TV_SCROLL) or (obj.tval == TV_STAFF)) and (band(f3, TR3_IGNORE_FIRE) == 0) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+
+ -- get the object type from the number
+ obj2 = get_object(item)
+
+ -- check we have enough points (if we 'got' an item)
+ if (ret == TRUE) then
+ ret2, stack = enough_points(obj2)
+ end
+
+ -- did either routine fail?
+ if (ret == FALSE) or (ret2 == FALSE) then
+ return FALSE
+ else
+
+ -- are we part of the items from a stack?
+ if (obj2.number ~= stack) then
+
+ -- make a new object to handle
+ object_copy(obj_forge, obj2)
+
+ -- give it the right number of items
+ obj_forge.number = stack
+
+ -- adjust for number of items in pack not to be fireproofed
+ obj2.number = obj2.number - stack
+ obj3 = obj_forge
+
+ -- we'll need to add this to the inventory after fireproofing
+ carry_it = TRUE
+ else
+
+ -- use the whole stack
+ obj3 = obj2
+
+ -- we'll be dealing this while it's still in the inventory
+ carry_it = FALSE
+ end
+
+ -- make it fireproof
+ obj3.name2 = 149
+
+ -- apply it, making sure the pvals don't change with apply_magic (it would change the type of book!)
+ local oldpval = obj3.pval
+ local oldpval2 = obj3.pval2
+ local oldpval3 = obj3.pval3
+ apply_magic(obj3, -1, FALSE, FALSE, FALSE)
+ obj3.pval = oldpval
+ obj3.pval2 = oldpval2
+ obj3.pval3 = oldpval3
+
+ -- put it in the inventory if it's only part of a stack
+ if (carry_it == TRUE) then
+ inven_carry(obj3, TRUE)
+ end
+
+ -- id and notice it
+ set_known(obj3)
+ set_aware(obj3)
+
+ return TRUE
+ end
+end
+
+-- This function makes sure the player has enough 'points' left to fireproof stuff.
+function enough_points(obj)
+ local item_value, stack
+
+ -- are the items in a stack?
+ if (obj.number > 1) then
+
+ -- how many to fireproof?
+ stack = get_quantity("How many would you like fireproofed?", obj.number)
+ else
+ stack = 1
+ end
+
+ -- check for item type and multiply number in the stack by the amount of points per item of that type
+ if (obj.tval == TV_BOOK) then
+ item_value = fireproof_quest.BOOK_POINTS * stack
+ elseif (obj.tval == TV_STAFF) then
+ item_value = fireproof_quest.STAFF_POINTS * stack
+ elseif (obj.tval == TV_SCROLL) then
+ item_value = fireproof_quest.SCROLL_POINTS * stack
+ end
+
+ -- do we have enough points?
+ if (item_value > fireproof_quest.item_points_remaining) then
+ msg_print("I do not have enough fireproofing material for that.")
+ return FALSE
+ else
+ -- if so then subtract those points before we do the fireproofing
+ fireproof_quest.item_points_remaining = fireproof_quest.item_points_remaining - item_value
+ end
+
+ -- Used all the points? the quest is completely rewarded.
+ if fireproof_quest.item_points_remaining == 0 then quest(FIREPROOF_QUEST).status = QUEST_STATUS_REWARDED end
+
+ return TRUE, stack
+end
+
diff --git a/lib/mods/theme/scpt/god.lua b/lib/mods/theme/scpt/god.lua
new file mode 100644
index 00000000..7567178c
--- /dev/null
+++ b/lib/mods/theme/scpt/god.lua
@@ -0,0 +1,812 @@
+-- The god quest: find randomly placed relic in a randomly placed dungeon!
+
+-- set some global variables (stored in the save file via the ["data"] key)
+god_quest = {}
+
+-- increase this number to make god quests more common, to a max value of 100
+god_quest.CHANCE_OF_GOD_QUEST = 21
+
+-- increase this number to make more quests
+god_quest.MAX_NUM_GOD_QUESTS = 7
+
+-- d_idx of the god_quest (Lost Temple) dungeon
+god_quest.DUNGEON_GOD = 30
+
+add_quest
+{
+ ["global"] = "GOD_QUEST",
+ ["name"] = "God quest",
+ ["desc"] = function()
+
+ if quest(GOD_QUEST).status == QUEST_STATUS_TAKEN then
+
+ -- get the direction that the dungeon lies from lothlorien/angband
+ local home, home_axis, home_distance, home2, home2_axis, home2_distance = get_god_quest_axes()
+
+ print_hook("#####yGod quest "..god_quest.quests_given.."!\n")
+ print_hook("Thou art to find the lost temple of thy God and\n");
+ print_hook("to retrieve the lost part of the relic for thy God! \n")
+ if home_axis ~= "close" then
+ print_hook("The temple lies "..home_distance.." to the "..home_axis.." of "..home..", \n")
+ else
+ print_hook("The temple lies very close to "..home..", \n")
+ end
+ if home2_axis ~= "close" then
+ print_hook( "and "..home2_distance.." to the "..home2_axis.." of "..home2..", I can feel it.' \n")
+ else
+ print_hook("and very close to "..home2..", I can feel it.' \n")
+ end
+ print_hook("\n")
+ end
+ end,
+ ["level"] = -1,
+ ["data"] = {
+ ["god_quest.relic_num"] = 1,
+ ["god_quest.quests_given"] = 0,
+ ["god_quest.relics_found"] = 0,
+ ["god_quest.dun_mindepth"] = 1,
+ ["god_quest.dun_maxdepth"] = 4,
+ ["god_quest.dun_minplev"] = 0,
+ ["god_quest.relic_gen_tries"] = 0,
+ ["god_quest.relic_generated"] = FALSE,
+ ["god_quest.dung_x"] = 1,
+ ["god_quest.dung_y"] = 1,
+ ["god_quest.player_x"] = 0,
+ ["god_quest.player_y"] = 0,
+ },
+ ["hooks"] = {
+ -- Start the game without the quest, given it by chance
+ [HOOK_BIRTH_OBJECTS] = function()
+ quest(GOD_QUEST).status = QUEST_STATUS_UNTAKEN
+
+ -- initialise save-file stored variables when new character is created
+ god_quest.relic_num = 1
+ god_quest.quests_given = 0
+ god_quest.relics_found = 0
+ god_quest.dun_mindepth = 1
+ god_quest.dun_maxdepth = 4
+ god_quest.dun_minplev = 0
+ god_quest.relic_gen_tries = 0
+ god_quest.relic_generated = FALSE
+ end,
+ [HOOK_PLAYER_LEVEL] = function(gained)
+ local home_axis, home
+
+ if gained > 0 then
+ -- roll for chance of quest
+ local give_god_quest = magik(god_quest.CHANCE_OF_GOD_QUEST)
+
+ -- check player is worshipping a god, not already on a god quest.
+ if (player.astral ~= FALSE) or (player.pgod <= 0)
+ or (quest(GOD_QUEST).status == QUEST_STATUS_TAKEN) or (quest(GOD_QUEST).status == QUEST_STATUS_FAILED)
+ or (god_quest.quests_given >= god_quest.MAX_NUM_GOD_QUESTS) or (give_god_quest == FALSE)
+ or ((current_dungeon_idx == god_quest.DUNGEON_GOD) and (dun_level > 0)) or (player.lev <= god_quest.dun_minplev) then
+ -- Don't let a player get quests with trickery
+ if player.lev > god_quest.dun_minplev then
+ god_quest.dun_minplev = player.lev
+ end
+ return
+ else
+ -- each god has different characteristics, so the quests are differnet depending on your god
+ if player.pgod == GOD_ERU then
+ god_quest.relic_num = 7
+ elseif player.pgod == GOD_MANWE then
+ god_quest.relic_num = 8
+ elseif player.pgod == GOD_TULKAS then
+ god_quest.relic_num = 9
+ elseif player.pgod == GOD_MELKOR then
+ god_quest.relic_num = 10
+ elseif player.pgod == GOD_YAVANNA then
+ god_quest.relic_num = 11
+ elseif player.pgod == GOD_AULE then
+ god_quest.relic_num = 16
+ elseif player.pgod == GOD_VARDA then
+ god_quest.relic_num = 17
+ elseif player.pgod == GOD_ULMO then
+ god_quest.relic_num = 18
+ elseif player.pgod == GOD_MANDOS then
+ god_quest.relic_num = 19
+ end
+
+ -- This var will need resetting
+ god_quest.relic_generated = FALSE
+ quest(GOD_QUEST).status = QUEST_STATUS_TAKEN
+ god_quest.quests_given = god_quest.quests_given + 1
+
+ -- actually place the dungeon in a random place
+ place_rand_dung()
+
+ -- store the variables of the coords where the player was given the quest
+ god_quest.player_y, god_quest.player_x = player.get_wild_coord()
+
+ -- establish direction of player and 'home' from dungeon
+ local home, home_axis, home_distance, home2, home2_axis, home2_distance = get_god_quest_axes()
+
+ -- God issues instructions
+ cmsg_print(TERM_L_BLUE, "The voice of "..deity(player.pgod).name.." booms in your head:")
+
+ cmsg_print(TERM_YELLOW, "'I have a task for thee.")
+ cmsg_print(TERM_YELLOW, "Centuries ago an ancient relic of mine was broken apart.")
+ cmsg_print(TERM_YELLOW, "The pieces of it have been lost in fallen temples.")
+ cmsg_print(TERM_YELLOW, "Thou art to find my lost temple and retrieve a piece of the relic.")
+ cmsg_print(TERM_YELLOW, "When thy task is done, thou art to lift it in the air and call upon my name.")
+ cmsg_print(TERM_YELLOW, "I shall then come to reclaim what is mine!")
+ if home_axis ~= "close" then
+ cmsg_print(TERM_YELLOW, "The temple lies "..home_distance.." to the "..home_axis.." of "..home..", ")
+ else
+ cmsg_print(TERM_YELLOW, "The temple lies very close to "..home..",")
+ end
+
+ if home2_axis ~= "close" then
+ cmsg_print(TERM_YELLOW, "and "..home2_distance.." to the "..home2_axis.." of "..home2..", I can feel it.'")
+ else
+ cmsg_print(TERM_YELLOW, "and very close to "..home2..", I can feel it.'")
+ end
+
+ -- Prepare depth of dungeon. If this was generated in set_god_dungeon_attributes(),
+ -- then we'd have trouble if someone levelled up in the dungeon!
+ god_quest.dun_mindepth = player.lev*2/3
+ god_quest.dun_maxdepth = god_quest.dun_mindepth + 4
+ end
+ end
+ end,
+ [HOOK_LEVEL_END_GEN] = function()
+ local chance
+
+ -- Check for dungeon
+ if (current_dungeon_idx ~= god_quest.DUNGEON_GOD) or (quest(GOD_QUEST).status == QUEST_STATUS_UNTAKEN) then
+ return
+ -- if the relic has been created at this point, then it was created on the *PREVIOUS* call of HOOK_LEVEL_END_GEN, and
+ -- therefore the player has caused another level generation in the temple and hence failed the quest.
+ elseif (god_quest.relic_generated == TRUE) and quest(GOD_QUEST).status ~= QUEST_STATUS_FAILED then
+
+ -- fail the quest, don't give another one, don't give this message again
+ quest(GOD_QUEST).status = QUEST_STATUS_FAILED
+ -- God issues instructions
+ cmsg_print(TERM_L_BLUE, "The voice of "..deity(player.pgod).name.." booms in your head:")
+
+ cmsg_print(TERM_YELLOW, "'Thou art a fool!")
+ cmsg_print(TERM_YELLOW, "I told thee to look carefully for the relic. It appears thou hast missed the")
+ cmsg_print(TERM_YELLOW, "opportunity to claim it in my name, as I sense that those monsters who ")
+ cmsg_print(TERM_YELLOW, "have overrun my temple have destroyed it themselves.")
+ cmsg_print(TERM_YELLOW, "I shall not ask thee to do such a thing again, as thou hast failed me in this")
+ cmsg_print(TERM_YELLOW, "simple task!'")
+ else
+ -- Force relic generation on 5th attempt if others have been unsuccessful.
+ if (god_quest.relic_gen_tries == 4) and (god_quest.relic_generated == FALSE) then
+ generate_relic()
+ else
+ -- 1/5 chance of generation
+ chance = randint(5)
+ if (chance == 5) then
+ generate_relic()
+ else
+ god_quest.relic_gen_tries = god_quest.relic_gen_tries + 1
+ end
+ end
+ end
+ end,
+ [HOOK_ENTER_DUNGEON] = function(d_idx)
+ -- call the function to set the dungeon variables (dependant on pgod) the first time we enter the dungeon
+ if d_idx ~= god_quest.DUNGEON_GOD then
+ return
+ else
+ set_god_dungeon_attributes()
+ end
+ end,
+ [HOOK_GEN_LEVEL_BEGIN] = function()
+ -- call the function to set the dungeon variables (dependant on pgod) when we WoR back into the dungeon
+ if current_dungeon_idx ~= god_quest.DUNGEON_GOD then
+ return
+ else
+ set_god_dungeon_attributes()
+ end
+ end,
+ [HOOK_STAIR] = function()
+ -- call the function to set the dungeon variables (dependant on pgod) every time we go down a level
+ if current_dungeon_idx ~= god_quest.DUNGEON_GOD then
+ return
+ else
+ set_god_dungeon_attributes()
+ end
+ end,
+ [HOOK_GET] = function(o_ptr, item)
+ -- Is it the relic, and check to make sure the relic hasn't already been identified
+ if (quest(GOD_QUEST).status == QUEST_STATUS_TAKEN) and (o_ptr.tval == TV_JUNK) and (o_ptr.sval == god_quest.relic_num)
+ and (o_ptr.pval ~= TRUE) and (god_quest.relics_found < god_quest.quests_given) then
+
+ -- more God talky-talky
+ cmsg_print(TERM_L_BLUE, deity(player.pgod).name.." speaks to you:")
+
+ -- Is it the last piece of the relic?
+ if (god_quest.quests_given == god_quest.MAX_NUM_GOD_QUESTS) then
+ cmsg_print(TERM_YELLOW, "'At last! Thou hast found all of the relic pieces.")
+
+ -- reward player by increasing prayer skill
+ cmsg_print(TERM_YELLOW, "Thou hast done exceptionally well! I shall increase thy prayer skill even more!'")
+ skill(SKILL_PRAY).value = skill(SKILL_PRAY).value + (10 * (skill(SKILL_PRAY).mod))
+
+ -- Take the relic piece
+ floor_item_increase(item, -1)
+ floor_item_optimize(item)
+ else
+ cmsg_print(TERM_YELLOW, "'Well done! Thou hast found part of the relic.")
+ cmsg_print(TERM_YELLOW, "I shall surely ask thee to find more of it later!")
+ cmsg_print(TERM_YELLOW, "I will take it from thee for now'")
+
+ -- Take the relic piece
+ floor_item_increase(item, -1)
+ floor_item_optimize(item)
+
+ -- reward player by increasing prayer skill
+ cmsg_print(TERM_YELLOW, "'As a reward, I shall teach thee how to pray better'")
+ skill(SKILL_PRAY).value = skill(SKILL_PRAY).value + (5 * (skill(SKILL_PRAY).mod))
+ end
+
+ -- relic piece has been identified
+ o_ptr.pval = TRUE
+ god_quest.relics_found = god_quest.relics_found + 1
+
+ -- Make sure quests can be given again if neccesary
+ quest(GOD_QUEST).status = QUEST_STATUS_UNTAKEN
+ return TRUE
+ end
+ end,
+ [HOOK_CHAR_DUMP] = function()
+
+ if (god_quest.quests_given > 0) then
+
+ local relics = god_quest.relics_found
+ local append_text = ""
+ if (god_quest.relics_found == god_quest.MAX_NUM_GOD_QUESTS) then
+ relics = "all"
+ append_text = " and pleased your god"
+ else
+ if (god_quest.relics_found == 0) then
+ relics = "none"
+ end
+ if (quest(GOD_QUEST).status == QUEST_STATUS_FAILED) then
+ append_text = " and failed in your quest"
+ end
+ end
+
+ print_hook("\n You found "..(relics).." of the relic pieces"..(append_text)..".")
+
+ end
+ end,
+ },
+}
+
+-- this function places the lost temple at a randomly determined place.
+function place_rand_dung()
+ local tries, grid
+
+ -- erase old dungeon
+ if (god_quest.quests_given > 0) then
+ place_dungeon(god_quest.dung_y, god_quest.dung_x)
+
+ -- erase old recall level
+ max_dlv[god_quest.DUNGEON_GOD + 1] = 0
+ end
+
+ -- initialise tries variable
+ tries = 1000
+
+ while tries > 0 do
+
+ tries = tries - 1
+ -- get grid coordinates, within a range which prevents dungeon being generated at the very edge of the wilderness (would crash the game).
+ god_quest.dung_x = rand_range(1, max_wild_x-2)
+ god_quest.dung_y = rand_range(1, max_wild_y-2)
+
+ -- Is there a town/dungeon/potentially impassable feature there, ?
+ if (wild_map(god_quest.dung_y, god_quest.dung_x).entrance ~= 0)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).entrance ~= 0)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_EDGE)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_DEEP_WATER)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_TREES)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_SHALLOW_LAVA)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_DEEP_LAVA)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_MOUNTAIN) then
+ -- try again
+ else
+ --neither player, nor wall, then stop this 'while'
+ break
+ end
+ end
+
+ -- Uhuh BAD ! lets use the default location up bree
+ if tries == 0 then
+ god_quest.dung_x = 32
+ god_quest.dung_y = 19
+ end
+
+ -- create god dungeon in that place
+ place_dungeon(god_quest.dung_y, god_quest.dung_x, god_quest.DUNGEON_GOD)
+
+end
+
+-- this function generates the relic at a randomly determined place in the temple.
+function generate_relic()
+ local tries, grid, x, y, relic
+
+ -- initialise tries variable
+ tries = 1000
+
+ while (tries > 0) do
+
+ tries = tries - 1
+ -- get grid coordinates from current height/width, minus one to prevent relic being generated in outside wall. (would crash the game)
+ y = randint(cur_hgt-1)
+ x = randint(cur_wid-1)
+ grid = cave(y, x)
+
+ -- are the coordinates on a floor, not on a permanent feature (eg stairs), and not on a trap ?
+ if (cave_is(grid, FF1_FLOOR) == TRUE) and (cave_is(grid, FF1_PERMANENT) == FALSE) and (grid.t_idx == 0) then break end
+
+ end
+
+ -- create relic
+ relic = create_object(TV_JUNK, god_quest.relic_num)
+
+ -- inscribe it to prevent automatizer 'accidents'
+ relic.note = quark_add("quest")
+
+ -- If no safe co-ords were found, put it in the players backpack
+ if tries == 0 then
+
+ -- explain it
+ msg_print(TERM_L_BLUE, "You luckily stumble across the relic on the stairs!")
+
+ if (inven_carry_okay(relic)) then
+ inven_carry(relic, FALSE)
+ else
+ -- no place found, drop it on the stairs
+ drop_near(relic, -1, player.py, player.px)
+ end
+
+ else
+ -- drop it
+ drop_near(relic, -1, y, x)
+ end
+
+ -- Only generate once!
+ god_quest.relic_generated = TRUE
+
+ -- Reset some variables
+ god_quest.relic_gen_tries = 0
+
+end
+
+
+
+
+function set_god_dungeon_attributes()
+
+ -- dungeon properties altered according to which god player is worshipping,
+ if player.pgod == GOD_ERU then
+
+ -- The Eru temple is based on Meneltarma.
+ -- W: Not too many monsters (they'll be tough though, with big levels)
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 14
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 200
+
+ -- L: Dirt and grass. More dirt at bottom, more grass at top. rocky ground would be nice
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 88
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 89
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 70
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 30
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[2] = 10
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[2] = 90
+
+ -- A: Outer wall mountain chain. other walls granite
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 97
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 57
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 97
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 2
+
+ -- O: "At Meneltarma no weapon or tool had ever been borne" (but invaders would have left a small number)
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 45
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 5
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 45
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 5
+
+ -- F: A large pillar, with stairs created at edges. (You can't climb a rock through the middle, can you?)
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_BIG, DF1_NO_DOORS, DF1_CIRCULAR_ROOMS, DF1_EMPTY, DF1_TOWER, DF1_FLAT, DF1_ADJUST_LEVEL_2)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = bor(DF2_ADJUST_LEVEL_1_2, DF2_NO_SHAFT, DF2_ADJUST_LEVEL_PLAYER)
+
+ -- R:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 50
+
+ -- M: We want evil or flying characters
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags3 = RF3_EVIL
+
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[2].percent = 50
+
+ -- M: We want evil or flying characters
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mflags7 = RF7_CAN_FLY
+
+
+ elseif player.pgod == GOD_MANWE then
+
+ -- Manwe's lost temple is high in the clouds
+ -- W: Has average number of monsters.
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 18
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 160
+
+
+ -- L: floor will be 'cloud-like vapour' and pools of 'condensing water'
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 208
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 209
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 85
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 15
+
+ -- A: Outer wall is 'hail stone wall', inner wall 'dense fog'. FIlled at max smoothing, like islands.
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 211
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 210
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 211
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 4
+
+ -- O: Can't imagine Manwe having much treasure. Little need for tools in a cloud temple. lots of magical stuff though...
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 15
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 25
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 55
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 5
+
+ -- F: It's open, goes up like a tower, give it a few interesting rooms, make the monsters hard(ish).
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_NO_DOORS, DF1_TOWER, DF1_CAVERN, DF1_ADJUST_LEVEL_2)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = bor(DF2_NO_SHAFT, DF2_ADJUST_LEVEL_PLAYER)
+
+ -- R:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[2].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[3].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[3].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[4].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[4].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[5].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[5].percent = 20
+
+ -- M: We want air(poison-type) or flying characters. Orcs too. They would have ransacked his elf-loving temple :)
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags2 = RF2_INVISIBLE
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mflags3 = bor(RF3_ORC, RF3_IM_POIS)
+ dungeon(god_quest.DUNGEON_GOD).rules[3].mflags4 = bor(RF4_BR_POIS, RF4_BR_GRAV)
+ dungeon(god_quest.DUNGEON_GOD).rules[4].mflags5 = RF5_BA_POIS
+ dungeon(god_quest.DUNGEON_GOD).rules[5].mflags7 = RF7_CAN_FLY
+
+
+ elseif player.pgod == GOD_TULKAS then
+
+ -- Tulkas dungeon is quite normal, possibly a bit boring to be honest. Maybe I should add something radical to it.
+ -- 'The house of Tulkas in the midmost of Valmar was a house of mirth and revelry. It sprang into the air with many storeys,
+ -- and had a tower of bronze and pillars of copper in a wide arcade'
+ -- W: but with lots of monsters
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 20
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 120
+
+ -- L: floor is normal
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 1
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 100
+
+ -- A: Granite walls
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 56
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 58
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 57
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 0
+
+ -- O: Loads of combat drops
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 10
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 70
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 5
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 15
+
+ -- F: fairly standard
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_NO_DESTROY, DF1_ADJUST_LEVEL_2)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = DF2_ADJUST_LEVEL_PLAYER
+
+ -- R:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 100
+
+ -- M: plenty demons please
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags3 = bor(RF3_DEMON, RF3_EVIL)
+
+
+ elseif player.pgod == GOD_MELKOR then
+
+ -- Melkors dungeon will be dark, fiery and stuff
+ -- Many many monsters! (but prob ADJUST_LEVEL_1_2)
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 24
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 80
+
+
+ -- L: floor is dirt/mud/nether
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 88
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 94
+ dungeon(god_quest.DUNGEON_GOD).floor3 = 102
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 45
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 45
+ dungeon(god_quest.DUNGEON_GOD).floor_percent3[1] = 10
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[2] = 35
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[2] = 35
+ dungeon(god_quest.DUNGEON_GOD).floor_percent3[2] = 30
+
+ -- A: Granite walls to fill but glass walls for room perimeters (you can see the nasty monsters coming)
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 188
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 188
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 57
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 1
+
+ -- O: Even drops
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 25
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 25
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 25
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 25
+
+ -- F: Small, lava rivers, nasty monsters hehehehehe
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_SMALL, DF1_LAVA_RIVERS, DF1_ADJUST_LEVEL_1)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = bor(DF2_ADJUST_LEVEL_1_2, DF2_ADJUST_LEVEL_PLAYER)
+
+ -- R: No restrictions on monsters here
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 0
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 80
+
+ -- R: Apart from making sure we have some GOOD ones
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[2].percent = 20
+
+ -- M:
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mflags3 = RF3_GOOD
+
+ elseif player.pgod == GOD_YAVANNA then
+
+ -- Yavannas dungeon will be very natural, tress and stuff.
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 22
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 100
+
+ -- L: floor is grass/flowers, plus dirt so not always regenerating quick!
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 89
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 199
+ dungeon(god_quest.DUNGEON_GOD).floor3 = 88
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 40
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 15
+ dungeon(god_quest.DUNGEON_GOD).floor_percent3[1] = 45
+
+ -- A: Tree walls to fill, small trees for inner walls
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 96
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 202
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 96
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 1
+
+ -- O: nt much combat.. tools where ransackers have tried to chop trees down.
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 20
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 10
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 30
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 40
+
+ -- F: Natural looking
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_NO_DOORS, DF1_WATER_RIVERS, DF1_NO_DESTROY, DF1_ADJUST_LEVEL_1, DF1_NO_RECALL)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = bor(DF2_ADJUST_LEVEL_1_2, DF2_NO_SHAFT, DF2_NO_GENO, DF2_ADJUST_LEVEL_PLAYER)
+
+ -- R: Demons, Undead, non-living
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 100
+
+ -- M:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags3 = bor(RF3_DEMON, RF3_UNDEAD, RF3_NONLIVING)
+
+ elseif player.pgod == GOD_AULE then
+
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 24
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 80
+
+ -- L: floor is dirt/mud/shallow water
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 88
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 94
+ dungeon(god_quest.DUNGEON_GOD).floor3 = 84
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 45
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 45
+ dungeon(god_quest.DUNGEON_GOD).floor_percent3[1] = 10
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[2] = 35
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[2] = 35
+ dungeon(god_quest.DUNGEON_GOD).floor_percent3[2] = 30
+
+ -- A: Grey mountains, inner walls are low hills
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 216
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 216
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 213
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 1
+
+ -- O: Weapons and tools only
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 0
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 50
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 0
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 50
+
+ -- F: Small, no destroyed levels, min monster level = dungeon level
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_SMALL, DF1_NO_DESTROY, DF1_ADJUST_LEVEL_1, DF1_NO_STREAMERS)
+
+ -- R: No restrictions on monsters here
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 0
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 80
+
+ elseif player.pgod == GOD_VARDA then
+
+ -- Varda lives with Manwe, so high in the clouds
+ -- W: Has average number of monsters.
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 18
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 160
+
+
+ -- L: floor will be grass and flowers
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 89
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 82
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 85
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 15
+
+ -- A: Outer wall is 'hail stone wall', inner wall 'dense fog'. Filled at max smoothing, like islands.
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 211
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 210
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 211
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 4
+
+ -- O: Varda likes magical items and tools, not much treasure or weapons
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 15
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 5
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 55
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 25
+
+ -- F: It's open, goes up like a tower, give it a few interesting rooms, make the monsters hard(ish).
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_NO_DOORS, DF1_TOWER, DF1_CAVERN, DF1_ADJUST_LEVEL_1)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = bor(DF2_NO_SHAFT, DF2_ADJUST_LEVEL_PLAYER)
+
+ -- R:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[2].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[3].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[3].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[4].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[4].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[5].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[5].percent = 20
+
+ -- M: We want air(poison-type) or flying characters. Orcs too.
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags2 = RF2_INVISIBLE
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mflags3 = bor(RF3_ORC, RF3_IM_POIS)
+ dungeon(god_quest.DUNGEON_GOD).rules[3].mflags4 = bor(RF4_BR_POIS, RF4_BR_GRAV)
+ dungeon(god_quest.DUNGEON_GOD).rules[4].mflags5 = RF5_BA_POIS
+ dungeon(god_quest.DUNGEON_GOD).rules[5].mflags7 = RF7_CAN_FLY
+
+
+ elseif player.pgod == GOD_ULMO then
+
+ -- Mandos dungeon is basically Tulkas, except with undead.
+ -- W: but with lots of monsters
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 20
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 120
+
+ -- L: floor is dirt
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 88
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 100
+
+ -- A: Cheat: walls are water.
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 187
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 238
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 84
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 0
+
+ -- O: Lots of treasure, not much else.
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 90
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 0
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 5
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 5
+
+ -- F: fairly standard
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_NO_DESTROY, DF1_ADJUST_LEVEL_2)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = DF2_ADJUST_LEVEL_PLAYER
+
+ -- R:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 35
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[2].percent = 30
+ dungeon(god_quest.DUNGEON_GOD).rules[3].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[3].percent = 30
+
+ -- M: Aquatic creatures only.
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags3 = RF7_CAN_FLY
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mflags3 = RF7_AQUATIC
+ dungeon(god_quest.DUNGEON_GOD).rules[3].mflags3 = RF3_RES_WATE
+
+ elseif player.pgod == GOD_MANDOS then
+
+ -- Mandos dungeon is basically Tulkas, except with undead.
+ -- W: but with lots of monsters
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 20
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 120
+
+ -- L: floor is normal
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 1
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 100
+
+ -- A: Granite walls
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 56
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 58
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 57
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 0
+
+ -- O: Loads of combat drops
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 10
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 70
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 5
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 15
+
+ -- F: fairly standard
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_NO_DESTROY, DF1_ADJUST_LEVEL_2)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = DF2_ADJUST_LEVEL_PLAYER
+
+ -- R:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 100
+
+ -- M: vampires!
+ dungeon(god_quest.DUNGEON_GOD).rules[1].r_char = "V"
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags3 = bor(RF3_UNDEAD, RF3_EVIL)
+
+ end
+
+ -- W: All dungeons are 5 levels deep, and created at 2/3 of the player clvl when the quest is given
+ dungeon(god_quest.DUNGEON_GOD).mindepth = god_quest.dun_mindepth
+ dungeon(god_quest.DUNGEON_GOD).maxdepth = god_quest.dun_maxdepth
+ dungeon(god_quest.DUNGEON_GOD).minplev = god_quest.dun_minplev
+
+end
+
+-- Calling this function returns the direction the dungeon is in from the players position at the time
+-- the quest was given, and also the direction from angband (if the player is worshipping Melkor) or lothlorien.
+function get_god_quest_axes()
+ local home, home_y_coord, home_x_coord, home_axis, home2, home2_y_coord, home2_x_coord, home2_axis, mydistance
+
+ -- different values for different gods...
+ if player.pgod ~= GOD_MELKOR then
+
+ -- one of the valar, "home" is lothlorien, home2 is Minas Arnor
+ home = "Bree"
+ home_y_coord = 21
+ home_x_coord = 35
+ home2 = "Minas Anor"
+ home2_y_coord = 56
+ home2_x_coord = 60
+ else
+ -- Melkor, "home" is angband, home2 is Barad-dur
+ home = "the Pits of Angband"
+ home_y_coord = 7
+ home_x_coord = 11
+ home2 = "the Land of Mordor"
+ home2_y_coord = 49
+ home2_x_coord = 70
+ end
+
+ home_axis = compass(home_y_coord, home_x_coord, god_quest.dung_y, god_quest.dung_x)
+ home2_axis = compass(home2_y_coord, home2_x_coord, god_quest.dung_y, god_quest.dung_x)
+
+ home_distance = approximate_distance(home_y_coord, home_x_coord, god_quest.dung_y, god_quest.dung_x)
+ home2_distance = approximate_distance(home2_y_coord, home2_x_coord, god_quest.dung_y, god_quest.dung_x)
+
+ return home, home_axis, home_distance, home2, home2_axis, home2_distance
+end
diff --git a/lib/mods/theme/scpt/gods.lua b/lib/mods/theme/scpt/gods.lua
new file mode 100644
index 00000000..014a4423
--- /dev/null
+++ b/lib/mods/theme/scpt/gods.lua
@@ -0,0 +1,26 @@
+add_hooks
+{
+ [HOOK_FOLLOW_GOD] = function(god, action)
+ if action == "ask" then
+ if not (god == GOD_MELKOR) then
+ local i = INVEN_WIELD
+ while i < INVEN_TOTAL do
+ -- 13 is ART_POWER
+ if player.inventory(i).name1 == 13 then
+ msg_print("The One Ring has corrupted you, and you are rejected.")
+ return TRUE
+ end
+ i = i + 1
+ end
+ end
+ end
+ return FALSE
+ end,
+ [HOOK_RECALC_SKILLS] = function()
+ if not (player.pgod == GOD_NONE) and (get_skill(SKILL_ANTIMAGIC) > 0) then
+ msg_print("You no longer believe.")
+ abandon_god(GOD_ALL)
+ end
+ return FALSE
+ end,
+}
diff --git a/lib/mods/theme/scpt/gods_new.lua b/lib/mods/theme/scpt/gods_new.lua
new file mode 100644
index 00000000..8153d453
--- /dev/null
+++ b/lib/mods/theme/scpt/gods_new.lua
@@ -0,0 +1,454 @@
+-- This file contains all the new gods
+
+add_loadsave("GRACE_DELAY",0)
+
+function aule_stone_skin()
+local type
+ if player.grace >= 10000 then
+ type = SHIELD_COUNTER
+ else
+ type = 0
+ end
+
+ set_shield(randint(10) + 10 + (player.grace / 100), 10 + (player.grace / 100), type, 2 + (player.grace / 200), 3 + (player.grace / 400))
+end
+
+GOD_AULE = add_god
+{
+ ["name"] = "Aule the Smith",
+ ["desc"] =
+ {
+ "Aule is a smith, and the creator of the Dwarves."
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ if (player.pgod == GOD_AULE) and (player.grace > 0) then
+ -- Resist fire, not shown on the character screen (?)
+ if (player.grace > 5000) then
+ player.resist_fire = TRUE
+ end
+
+ local bonus = player.grace / 5000
+ if bonus > 5 then
+ bonus = 5
+ end
+ player.to_h = player.to_h + bonus
+ player.dis_to_h = player.dis_to_h + bonus
+ player.to_d = player.to_d + bonus
+ player.dis_to_d = player.dis_to_d + bonus
+
+ end
+ end,
+ [HOOK_PROCESS_WORLD] = function()
+ if (player.pgod == GOD_AULE) then
+ GRACE_DELAY = GRACE_DELAY + 1
+ if GRACE_DELAY >= 15 then
+ -- Aule likes Dwarves and Dark Elves (Eol's influence here)
+ if
+ (get_race_name() ~= "Dwarf") and
+ (get_race_name() ~= "Petty-dwarf") and
+ (get_race_name() ~= "Gnome") and
+ (get_race_name() ~= "Dark-Elf") then
+ set_grace(player.grace - 1)
+ end
+
+ -- Search inventory for axe or hammer - Gain 1 point of grace for each hammer or axe
+ for i = 0, INVEN_TOTAL - 1 do
+ if ((player.inventory(i).tval) == TV_AXE) then
+ set_grace(player.grace + 1)
+ end
+ if ((player.inventory(i).tval) == TV_HAFTED) then
+ if (((player.inventory(i).sval) == SV_WAR_HAMMER) or ((player.inventory(i).sval) == SV_LUCERN_HAMMER) or ((player.inventory(i).sval) == SV_GREAT_HAMMER)) then
+ set_grace(player.grace + 1)
+ end
+ end
+ end
+
+ if (player.praying == TRUE) then
+ set_grace(player.grace - 2)
+
+ -- Chance of casting Stoneskin if praying
+ local chance
+ if (player.grace >= 50000) then
+ chance = 50000
+ else
+ chance = 50000 - player.grace
+ end
+
+ if (randint(100000) <= 100000 / chance) then
+ aule_stone_skin()
+ msg_print("Aule casts Stone Skin on you.")
+ end
+
+ end
+ GRACE_DELAY = 0
+ end
+
+ end
+ end,
+ [HOOK_SACRIFICE_GOD] = function()
+ if (player.pgod == GOD_AULE) then
+ local ret, item, obj, value
+ ret, item = get_item(
+ "Sacrifice which item? ",
+ "You have nothing to sacrifice.",
+ USE_INVEN,
+ function(obj)
+ -- perhaps restrict this only to metal armour and weapons
+ if (obj.found == OBJ_FOUND_SELFMADE) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+
+ -- Item selected
+ if ret == TRUE then
+ -- Increase piety by the value of the item / 10
+ -- object_value is not available in Lua, therefore I used the
+ -- cost of the base item, without magical boni
+ obj = get_object(item)
+ -- value = object_value(obj)/10
+ value = k_info[obj.k_idx + 1].cost/10
+
+ set_grace(player.grace + value)
+
+ -- remove the object
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+ end
+ end
+ end,
+ [HOOK_MONSTER_DEATH] = function(m_idx)
+ if (player.pgod == GOD_AULE) then
+ m_ptr = monster(m_idx)
+ if
+ (m_ptr.r_idx == test_monster_name("Petty-dwarf")) or
+ (m_ptr.r_idx == test_monster_name("Petty-dwarf mage")) or
+ (m_ptr.r_idx == test_monster_name("Dark dwarven warrior")) or
+ (m_ptr.r_idx == test_monster_name("Dark dwarven smith")) or
+ (m_ptr.r_idx == test_monster_name("Dark dwarven lord")) or
+ (m_ptr.r_idx == test_monster_name("Dark dwarven priest")) or
+ (m_ptr.r_idx == test_monster_name("Dwarven warrior")) then
+ -- Aule dislikes you killing dwarves
+ set_grace(player.grace - 20)
+ end
+ if
+ (m_ptr.r_idx == test_monster_name("Nar, the Dwarf")) or
+ (m_ptr.r_idx == test_monster_name("Naugladur, Lord of Nogrod")) or
+ (m_ptr.r_idx == test_monster_name("Telchar the Smith")) or
+ (m_ptr.r_idx == test_monster_name("Fundin Bluecloak")) or
+ (m_ptr.r_idx == test_monster_name("Khim, Son of Mim")) or
+ (m_ptr.r_idx == test_monster_name("Ibun, Son of Mim")) or
+ (m_ptr.r_idx == test_monster_name("Mim, Betrayer of Turin")) then
+ -- These uniques earn a bigger penalty
+ set_grace(player.grace - 500)
+ end
+ end
+ end,
+ }
+}
+
+GOD_VARDA = add_god
+{
+ ["name"] = "Varda Elentari",
+ ["desc"] =
+ {
+ "The Queen of the Stars. In light is her power and joy."
+ },
+ ["hooks"] =
+ {
+ [HOOK_PROCESS_WORLD] = function()
+ if (player.pgod == GOD_VARDA) then
+ GRACE_DELAY = GRACE_DELAY + 1
+
+ -- piety increase if in light
+ if (GRACE_DELAY >= 15) then
+ if band(cave(player.py, player.px).info, CAVE_GLOW) ~= 0 then
+ set_grace(player.grace + 2)
+ end
+ if (
+ (get_race_name() == "Orc") or
+ (get_race_name() == "Troll") or
+ (get_race_name() == "Dragon") or
+ (get_race_name() == "Demon")) then
+ -- Varda hates evils
+ set_grace(player.grace - 2)
+ else
+ set_grace(player.grace - 1)
+ end
+
+ if (player.praying == TRUE) then
+ set_grace(player.grace - 1)
+ end
+ GRACE_DELAY = 0
+ end
+ end
+ end,
+ [HOOK_CALC_LITE] = function()
+ if (player.pgod == GOD_VARDA) then
+ -- increase lite radius
+ player.cur_lite = player.cur_lite + 1
+ end
+ end,
+ [HOOK_GF_EXEC] = function (target, who, type, dam, r, y, x, m_ptr)
+ if (player.pgod == GOD_VARDA) then
+ if ((type == GF_LITE) or (type == GF_LITE_WEAK)) then
+ -- Raise piety for using lite
+ set_grace(player.grace + 1)
+ end
+ end
+ end,
+ },
+}
+
+GOD_ULMO = add_god
+{
+ ["name"] = "Ulmo",
+ ["desc"] =
+ {
+ "Ulmo is called Lord of Waters, he rules all that is water on Arda."
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ if (player.pgod == GOD_ULMO) then
+ player.water_breath = TRUE
+ end
+ if (player.pgod == GOD_ULMO) and (player.grace > 0) then
+ local bonus = player.grace / 5000
+ if bonus > 5 then
+ bonus = 5
+ end
+
+ if ((player.grace > 1000) and (player.praying == TRUE)) then
+ player.resist_pois = TRUE
+ end
+ if ((player.grace > 15000) and (player.praying == TRUE)) then
+ player.magic_breath = TRUE
+ end
+ end
+ end,
+
+ [HOOK_MONSTER_DEATH] = function(m_idx)
+ if (player.pgod == GOD_ULMO) then
+ m_ptr = monster(m_idx)
+ if
+ (m_ptr.r_idx == test_monster_name("Swordfish")) or
+ (m_ptr.r_idx == test_monster_name("Barracuda")) or
+ (m_ptr.r_idx == test_monster_name("Globefish")) or
+ (m_ptr.r_idx == test_monster_name("Aquatic bear")) or
+ (m_ptr.r_idx == test_monster_name("Pike")) or
+ (m_ptr.r_idx == test_monster_name("Electric eel")) or
+ (m_ptr.r_idx == test_monster_name("Giant crayfish")) or
+ (m_ptr.r_idx == test_monster_name("Mermaid")) or
+ (m_ptr.r_idx == test_monster_name("Leviathan")) or
+ (m_ptr.r_idx == test_monster_name("Box jellyfish")) or
+ (m_ptr.r_idx == test_monster_name("Giant piranha")) or
+ (m_ptr.r_idx == test_monster_name("Piranha")) or
+ (m_ptr.r_idx == test_monster_name("Ocean naga")) or
+ (m_ptr.r_idx == test_monster_name("Whale")) or
+ (m_ptr.r_idx == test_monster_name("Octopus")) or
+ (m_ptr.r_idx == test_monster_name("Giant octopus")) or
+ (m_ptr.r_idx == test_monster_name("Drowned soul")) or
+ (m_ptr.r_idx == test_monster_name("Tiger shark")) or
+ (m_ptr.r_idx == test_monster_name("Hammerhead shark")) or
+ (m_ptr.r_idx == test_monster_name("Great white shark")) or
+ (m_ptr.r_idx == test_monster_name("White shark")) or
+ (m_ptr.r_idx == test_monster_name("Stargazer")) or
+ (m_ptr.r_idx == test_monster_name("Flounder")) or
+ (m_ptr.r_idx == test_monster_name("Giant turtle")) or
+ (m_ptr.r_idx == test_monster_name("Killer whale")) or
+ (m_ptr.r_idx == test_monster_name("Water naga")) or
+ (m_ptr.r_idx == test_monster_name("Behemoth")) then
+ -- He doesn't like it if you kill these monsters
+ set_grace(player.grace - 20)
+ end
+ if
+ (m_ptr.r_idx == test_monster_name("Seahorse")) or
+ (m_ptr.r_idx == test_monster_name("Aquatic elven warrior")) or
+ (m_ptr.r_idx == test_monster_name("Aquatic elven mage")) or
+ (m_ptr.r_idx == test_monster_name("Wavelord")) or
+ (m_ptr.r_idx == test_monster_name("The Watcher in the Water")) then
+ -- These monsters earn higher penalties
+ set_grace(player.grace - 500)
+ end
+ end
+ end,
+ [HOOK_GF_EXEC] = function (target, who, type, dam, r, y, x, m_ptr)
+ if (player.pgod == GOD_ULMO) then
+ if ((type == GF_FIRE) or (type == GF_HELL_FIRE) or (type == GF_HOLY_FIRE) or (type == GF_LAVA_FLOW) or (type == GF_METEOR) or (type == GF_NUKE) or (type == GF_PLASMA)) then
+ -- Reduce piety for using any kind of fire magic
+ set_grace(player.grace - 5)
+ end
+ end
+ end,
+ [HOOK_PROCESS_WORLD] = function()
+ if (player.pgod == GOD_ULMO) then
+ GRACE_DELAY = GRACE_DELAY + 1
+ if GRACE_DELAY >= 15 then
+ -- Ulmo likes the Edain (except Easterlings)
+ if
+ (get_race_name() == "Human") or
+ (get_race_name() == "Dunadan") or
+ (get_race_name() == "Druadan") or
+ (get_race_name() == "RohanKnight") then
+ set_grace(player.grace + 1)
+
+ elseif (
+ (get_race_name() == "Easterling") or
+ (get_race_name() == "Demon") or
+ (get_race_name() == "Orc")) then
+ -- hated races
+ set_grace(player.grace - 2)
+ else
+ set_grace(player.grace + 1)
+ end
+
+ if (player.praying == TRUE) then
+ set_grace(player.grace - 1)
+ end
+ -- Search inventory for axe or hammer - Gain 1 point of grace for each hammer or axe
+ for i = 0, INVEN_TOTAL - 1 do
+ if ((player.inventory(i).tval) == TV_POLEARM) then
+ if ((player.inventory(i).sval) == SV_TRIDENT) then
+ set_grace(player.grace + 1)
+ end
+ end
+ end
+
+ GRACE_DELAY = 0
+ end
+
+ end
+ end,
+ },
+}
+
+GOD_MANDOS = add_god
+{
+ ["name"] = "Mandos",
+ ["desc"] =
+ {
+ "The Doomsman of the Valar and keeper of the slain."
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ if (player.pgod == GOD_MANDOS) then
+ player.resist_neth = TRUE
+ end
+ if (player.pgod == GOD_MANDOS) and (player.grace > 0) then
+ local bonus = player.grace / 5000
+ if bonus > 5 then
+ bonus = 5
+ end
+
+ if ((player.grace > 10000) and (player.praying == TRUE)) then
+ player.resist_continuum = TRUE
+ end
+
+ if ((player.grace > 20000) and (player.praying == TRUE)) then
+ player.immune_neth = TRUE
+ end
+ end
+ end,
+ [HOOK_PROCESS_WORLD] = function()
+ if (player.pgod == GOD_MANDOS) then
+ GRACE_DELAY = GRACE_DELAY + 1
+ if GRACE_DELAY >= 15 then
+ -- He loves astral beings
+ if (get_subrace_name() == "LostSoul") then
+ set_grace(player.grace + 1)
+ end
+
+ -- He likes High Elves only, though, as races
+ if (get_race_name() ~= "High-Elf") then
+ set_grace(player.grace - 1)
+ end
+ end
+ -- piety increase if (condition)
+ if (GRACE_DELAY >= 15) then
+ if (
+ (get_subrace_name() == "Vampire") or
+ (get_race_name() == "Demon")) then
+ -- hated races
+ set_grace(player.grace - 10)
+ else
+ set_grace(player.grace + 2)
+ end
+ -- he really doesn't like to be disturbed
+ if (player.praying == TRUE) then
+ set_grace(player.grace - 5)
+ end
+ GRACE_DELAY = 0
+ end
+
+ end
+ end,
+ [HOOK_MONSTER_DEATH] = function(m_idx)
+ if (player.pgod == GOD_MANDOS) then
+ m_ptr = monster(m_idx)
+ if
+ (m_ptr.r_idx == test_monster_name("Vampire")) or
+ (m_ptr.r_idx == test_monster_name("Master vampire")) or
+ (m_ptr.r_idx == test_monster_name("Oriental vampire")) or
+ (m_ptr.r_idx == test_monster_name("Vampire lord")) or
+ (m_ptr.r_idx == test_monster_name("Vampire orc")) or
+ (m_ptr.r_idx == test_monster_name("Vampire yeek")) or
+ (m_ptr.r_idx == test_monster_name("Vampire ogre")) or
+ (m_ptr.r_idx == test_monster_name("Vampire troll")) or
+ (m_ptr.r_idx == test_monster_name("Vampire dwarf")) or
+ (m_ptr.r_idx == test_monster_name("Vampire gnome")) or
+ (m_ptr.r_idx == test_monster_name("Elder vampire")) then
+ -- He really likes it if you kill Vampires (but not the adventurer kind :P)
+ set_grace(player.grace + 50)
+ end
+
+ if
+ (m_ptr.r_idx == test_monster_name("Vampire elf")) or
+ (m_ptr.r_idx == test_monster_name("Thuringwethil, the Vampire Messenger")) then
+ -- He *loves* it if you kill vampire Elves
+ -- He will also thank you extra kindly if you kill Thuringwethil
+ set_grace(player.grace + 200)
+ end
+
+ if
+ (m_ptr.r_idx == test_monster_name("Dark elf")) or
+ (m_ptr.r_idx == test_monster_name("Dark elven druid")) or
+ (m_ptr.r_idx == test_monster_name("Eol, the Dark Elf")) or
+ (m_ptr.r_idx == test_monster_name("Maeglin, the Traitor of Gondolin")) or
+ (m_ptr.r_idx == test_monster_name("Dark elven mage")) or
+ (m_ptr.r_idx == test_monster_name("Dark elven warrior")) or
+ (m_ptr.r_idx == test_monster_name("Dark elven priest")) or
+ (m_ptr.r_idx == test_monster_name("Dark elven lord")) or
+ (m_ptr.r_idx == test_monster_name("Dark elven warlock")) or
+ (m_ptr.r_idx == test_monster_name("Dark elven sorcerer")) then
+ -- He doesn't like it if you kill normal Elves (means more work for him :P)
+ set_grace(player.grace - 20)
+ end
+ if
+ (m_ptr.r_idx == test_monster_name("Glorfindel of Rivendell")) or
+ (m_ptr.r_idx == test_monster_name("Finrod Felagund")) or
+ (m_ptr.r_idx == test_monster_name("Thranduil, King of the Wood Elves")) or
+ (m_ptr.r_idx == test_monster_name("Aquatic elven warrior")) or
+ (m_ptr.r_idx == test_monster_name("Aquatic elven mage")) or
+ (m_ptr.r_idx == test_monster_name("High-elven ranger")) or
+ (m_ptr.r_idx == test_monster_name("Elven archer")) then
+ -- He hates it if you kill coaligned Elves
+ set_grace(player.grace - 200)
+ end
+ if
+ (m_ptr.r_idx == test_monster_name("Child spirit")) or
+ (m_ptr.r_idx == test_monster_name("Young spirit")) or
+ (m_ptr.r_idx == test_monster_name("Mature spirit")) or
+ (m_ptr.r_idx == test_monster_name("Experienced spirit")) or
+ (m_ptr.r_idx == test_monster_name("Wise spirit")) then
+ -- He *hates* it if you kill the coaligned Spirits
+ set_grace(player.grace - 1000)
+ end
+ end
+ end
+ }
+}
diff --git a/lib/mods/theme/scpt/gondolin.lua b/lib/mods/theme/scpt/gondolin.lua
new file mode 100644
index 00000000..c85d8f53
--- /dev/null
+++ b/lib/mods/theme/scpt/gondolin.lua
@@ -0,0 +1,63 @@
+-- This script makes the void jumpgates between Minas Anor and Gondolin appear in Gondolin rather than in a weird wilderness spot
+-- as well as making the Save Gondolin quest take the player straight to Gondolin instead of the Secret Valley.
+-- Many thanks to TheFalcon for the code.
+
+function minas_gate()
+ if (quest(16).status == QUEST_STATUS_FINISHED) and (player.wilderness_y == 56) and (player.wilderness_x == 60) and (player.wild_mode == FALSE) then
+ cave(35,10).feat = 159
+ end
+end
+
+add_hook_script(HOOK_QUEST_FINISH, "minas_gate", "minas_gate")
+add_hook_script(HOOK_WILD_GEN, "minas_gate", "minas_gate")
+
+function minas_jump(direction)
+ if (quest(16).status == QUEST_STATUS_FINISHED) and (player.wilderness_y == 56) and (player.wilderness_x == 60) and (player.wild_mode == FALSE) then
+ if (player.px == 10) and (player.py == 35) then
+ if (direction == "down") then
+ player.wilderness_x = 3
+ player.wilderness_y = 11
+ player.wild_mode = FALSE
+ player.px = 119
+ player.py = 25
+ player.oldpx = player.px
+ player.oldpy = player.py
+ dun_level = 0
+ player.leaving = TRUE
+ return TRUE
+ end
+ end
+ end
+end
+
+add_hook_script(HOOK_STAIR, "minas_jump", "minas_jump")
+
+add_loadsave("tolan_count", 0)
+
+function tolan_travel()
+ if (quest(15).status == QUEST_STATUS_TAKEN) and (tolan_count == 0) then
+ player.wilderness_x = 3
+ player.wilderness_y = 11
+ player.wild_mode = FALSE
+ player.px = 117
+ player.py = 25
+ player.oldpx = player.px
+ player.oldpy = player.py
+ dun_level = 0
+ player.leaving = TRUE
+ tolan_count = 1
+ return TRUE
+ end
+end
+
+add_hook_script(HOOK_END_TURN, "tolan_travel", "tolan_travel")
+
+add_hooks
+{
+ [HOOK_BIRTH] = function()
+ if tolan_count >=1
+ then tolan_count = 0
+ else
+ end
+ end
+} \ No newline at end of file
diff --git a/lib/mods/theme/scpt/help.lua b/lib/mods/theme/scpt/help.lua
new file mode 100644
index 00000000..4e244df6
--- /dev/null
+++ b/lib/mods/theme/scpt/help.lua
@@ -0,0 +1,445 @@
+-- Ingame contextual help
+
+-------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+-----------------------Here comes the definition of help-----------------------
+-------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if cave(y, x).feat == FEAT_BETWEEN then return TRUE end end,
+ ["desc"] =
+ {
+ "Void Jumpgates can be entered by pressing the > key. They will transport",
+ "you to another jumpgate, but beware of the cold damage that might kill you.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if cave(y, x).feat == FEAT_FOUNTAIN then return TRUE end end,
+ ["desc"] =
+ {
+ "Fountains are always magical. You can quaff from them by pressing H.",
+ "Beware that unlike potions they cannot be identified.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if cave(y, x).o_idx ~= 0 then return TRUE end end,
+ ["desc"] =
+ {
+ "So you found your first item! Nice, eh? Now when you stumble across",
+ "objects, you can pick them up by pressing g, and if you are wondering",
+ "what they do, press I (then *, then the letter for the item) to get",
+ "some basic information. You may also want to identify them with scrolls,",
+ "staves, rods or spells.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if (cave(y, x).feat >= FEAT_ALTAR_HEAD) and (cave(y, x).feat <= FEAT_ALTAR_TAIL) then return TRUE end end,
+ ["desc"] =
+ {
+ "Altars are the way to reach the Valar, powers of the world,",
+ "usualy called Gods. You can press O to become a follower.",
+ "Beware that once you follow a god, you are not allowed to change.",
+ "For an exact description of what gods do and want, read the documentation."
+ }
+}
+
+-- Beware this one, if Bree is moved from 21, 34 (y, x) on the wilderness map it will break
+ingame_help
+{
+ ["hook"] = HOOK_END_TURN,
+ ["event"] = function(y, x)
+ if ((player.wilderness_x ~= 34) or (player.wilderness_y ~= 21) and (player.astral == FALSE)) then return TRUE end
+ end,
+ ["desc"] =
+ {
+ "Ahh wilderness travel... The overview mode will allow you to travel",
+ "fast, but that comes to the cost of GREATLY increased food consumption.",
+ "So you should bring lots of food and really watch your hunger status.",
+ "To enter the overview mode, press < while in the wilderness.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_PLAYER_LEVEL,
+ ["event"] = function(y, x) if player.lev > 1 then return TRUE end end,
+ ["desc"] =
+ {
+ "Ok, so you now gained a level, and you have skill points to spend.",
+ "To do so simply press G to learn skills. Reading the documentation",
+ "about skills and abilities is also strongly recommended.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if cave(y, x).feat == FEAT_MORE then return TRUE end end,
+ ["desc"] =
+ {
+ "Ah, this is a stair, or a way into something. Press > to enter it.",
+ "But be ready to fight what lies within, for it might not be too friendly.",
+ }
+}
+
+ingame_help
+{
+ ["callback"] = "monster_chat",
+ ["desc"] =
+ {
+ "Somebody is speaking to you it seems. You can talk back with the Y key.",
+ "This can lead to quests. You can also give items to 'monsters' with the y key.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_END_TURN,
+ ["event"] = function(y, x) return TRUE end,
+ ["desc"] =
+ {
+ "Welcome to Theme! I am the spirit of knowledge and my task is to help you",
+ "to get used to how to play. I have prepared a #vparchment#y for you to #vread#y.",
+ "Press r, then space then select it. You can also check the documentation",
+ "by pressing ? at (nearly) any time.",
+ "The first place you can explore is Barrow-downs. Go to the west of town",
+ "and you should see a #v>#y there.",
+ "If you miss any of this you can press ctrl+p to see your message log.",
+ "Now I must reveal your task here. You are on a quest to investigate",
+ "the dreadful tower of Dol Guldur in the Mirkwood forest to see what evil",
+ "lurks there, but beware, you are not yet ready.",
+ "If you do not want me to bother you any more with tips, press = then go",
+ "into the ToME options and deactivate the ingame_help option.",
+ "You can see your quest log by pressing ctrl+q. Now go to your destiny!",
+ }
+}
+
+ingame_help
+{
+ ["no_test"] = TRUE,
+ ["callback"] = "select_context",
+ ["fct"] = function(typ, name)
+ -- list of files for classes, { filename, anchor }
+ local t =
+ {
+ ["race"] =
+ {
+ ["Beorning"] = { "r_beorn.txt", 0 },
+ ["Dragon"] = { "r_dragon.txt", 0 },
+ ["Dark-Elf"] = { "r_drkelf.txt", 0 },
+ ["Dunadan"] = { "r_dunad.txt", 0 },
+ ["Dwarf"] = { "r_dwarf.txt", 0 },
+ ["Elf"] = { "r_elf.txt", 0 },
+ ["Ent"] = { "r_ent.txt", 0 },
+ ["Gnome"] = { "r_gnome.txt", 0 },
+ ["Half-Elf"] = { "r_hafelf.txt", 0 },
+ ["Half-Ogre"] = { "r_hafogr.txt", 0 },
+ ["High-Elf"] = { "r_hielf.txt", 0 },
+ ["Hobbit"] = { "r_hobbit.txt", 0 },
+ ["Human"] = { "r_human.txt", 0 },
+ ["Druadan"] = { "r_druadan.txt", 0 },
+ ["Maia"] = { "r_maia.txt", 0 },
+ ["Orc"] = { "r_orc.txt", 0 },
+ ["Petty-Dwarf"] = { "r_pettyd.txt", 0 },
+ ["RohanKnight"] = { "r_rohank.txt", 0 },
+ ["Eagle"] = { "r_eagle.txt", 0 },
+ ["Troll"] = { "r_troll.txt", 0 },
+ ["Wood-Elf"] = { "r_wodelf.txt", 0 },
+ ["Yeek"] = { "r_yeek.txt", 0 },
+ ["Easterling"] = { "r_easterl.txt", 0 },
+ ["Demon"] = { "r_demon.txt", 0},
+ },
+ ["subrace"] =
+ {
+ ["Barbarian"] = { "rm_barb.txt", 0 },
+ ["Classical"] = { "rm_class.txt", 0 },
+ ["Corrupted"] = { "rm_corru.txt", 0 },
+ ["Hermit"] = { "rm_herm.txt", 0 },
+ ["LostSoul"] = { "rm_lsoul.txt", 0 },
+ ["Skeleton"] = { "rm_skel.txt", 0 },
+ ["Spectre"] = { "rm_spec.txt", 0 },
+ ["Vampire"] = { "rm_vamp.txt", 0 },
+ ["Zombie"] = { "rm_zomb.txt", 0 },
+ ["Red"] = {"rm_red.txt", 0 },
+ ["Black"] = {"rm_black.txt", 0 },
+ ["Green"] = {"rm_green.txt", 0 },
+ ["Blue"] = {"rm_blue.txt", 0 },
+ ["White"] = {"rm_white.txt", 0 },
+ ["Ethereal"] = {"rm_ether.txt", 0 },
+ ["(Narrog)"] = {"rm_narrog.txt", 0 },
+ ["(Aewrog)"] = {"rm_aewrog.txt", 0 },
+ ["(Hurog)"] = {"rm_hurog.txt", 0 },
+ ["(Sarnrog)"] = {"rm_sarnrog.txt", 0 },
+ ["(Caborrog)"] = {"rm_cabrog.txt", 0 },
+ ["(Draugrog)"] = {"rm_drarog.txt", 0 },
+ ["(Lygrog)"] = {"rm_lygrog.txt", 0 },
+ ["(Limrog)"] = {"rm_limrog.txt", 0 },
+ ["(Rawrog)"] = {"rm_rawrog.txt", 0 },
+ ["(Adanrog)"] = {"rm_adanrog.txt", 0 },
+ },
+ ["class"] =
+ {
+ ["Archer"] = { "c_archer.txt", 0 },
+ ["Ascetic"] = { "c_ascet.txt", 0 },
+ ["Assassin"] = { "c_assass.txt", 0 },
+ ["Axemaster"] = { "c_axemas.txt", 0 },
+ ["Bard"] = { "c_bard.txt", 0 },
+ ["Clairvoyant"] = {"c_clairv.txt", 0},
+ ["Dark-Priest"] = { "c_pr_drk.txt", 0 },
+ ["Demonologist"] = { "c_demono.txt", 0 },
+ ["Druid"] = { "c_druid.txt", 0 },
+ ["Geomancer"] = { "c_geoman.txt", 0 },
+ ["Haftedmaster"] = { "c_hafted.txt", 0 },
+ ["Loremaster"] = { "c_lorema.txt", 0 },
+ ["Mage"] = { "c_mage.txt", 0 },
+ ["Mercenary"] = { "c_mercen.txt", 0 },
+ ["Mimic"] = { "c_mimic.txt", 0 },
+ ["Mindcrafter"] = { "c_mindcr.txt", 0 },
+ ["Monk"] = { "c_monk.txt", 0 },
+ ["Necromancer"] = { "c_necro.txt", 0 },
+ ["Pacifist"] = { "c_pacif.txt", 0 },
+ ["Paladin"] = { "c_palad.txt", 0 },
+ ["Peace-mage"] = { "c_peacemag.txt", 0 },
+ ["Polearmmaster"] = { "c_polear.txt", 0 },
+ ["Possessor"] = { "c_posses.txt", 0 },
+ ["Priest"] = { "c_priest.txt", 0 },
+ ["Priest(Eru)"] = { "c_pr_eru.txt", 0 },
+ ["Priest(Mandos)"] = { "c_pr_mand.txt", 0 },
+ ["Priest(Manwe)"] = { "c_pr_man.txt", 0 },
+ ["Priest(Ulmo)"] = { "c_pr_ulmo.txt", 0 },
+ ["Priest(Varda)"] = { "c_pr_varda.txt", 0 },
+ ["Ranger"] = { "c_ranger.txt", 0 },
+ ["Rogue"] = { "c_rogue.txt", 0 },
+ ["Runecrafter"] = { "c_runecr.txt", 0 },
+ ["Sniper"] = {"c_sniper.txt", 0 },
+ ["Sorceror"] = { "c_sorcer.txt", 0 },
+ ["Stonewright"] = { "c_stonewr.txt", 0 },
+ ["Summoner"] = { "c_summon.txt", 0 },
+ ["Swordmaster"] = { "c_swordm.txt", 0 },
+ ["Symbiant"] = { "c_symbia.txt", 0 },
+ ["Thaumaturgist"] = { "c_thaum.txt", 0 },
+ ["Trapper"] = { "c_trapper.txt", 0 },
+ ["Unbeliever"] = { "c_unbel.txt", 0 },
+ ["Wainrider"] = { "c_wainrid.txt", 0 },
+ ["War-mage"] = { "c_warmage.txt", 0 },
+ ["Warper"] = { "c_warper.txt", 0 },
+ ["Warrior"] = { "c_warrio.txt", 0 },
+ },
+ ["god"] =
+ {
+ ["Aule the Smith"] = { "g_aule.txt", 0 },
+ ["Eru Iluvatar"] = { "g_eru.txt", 0 },
+ ["Mandos"] = { "g_mandos.txt", 0 },
+ ["Manwe Sulimo"] = { "g_manwe.txt", 0 },
+ ["Melkor Bauglir"] = { "g_melkor.txt", 0 },
+ ["Tulkas"] = { "g_tulkas.txt", 0 },
+ ["Ulmo"] = { "g_ulmo.txt", 0 },
+ ["Varda Elentari"] = { "g_varda.txt", 0 },
+ ["Yavanna Kementari"] = { "g_yavann.txt", 0 },
+ },
+ ["skill"] =
+ {
+ ["Air"] = { "skills.txt", 27 },
+ ["Alchemy"] = { "skills.txt", 49 },
+ ["Antimagic"] = { "skills.txt", 50 },
+ ["Archery"] = { "skills.txt", 08 },
+ ["Axe-mastery"] = { "skills.txt", 05 },
+ ["Backstab"] = { "skills.txt", 18 },
+ ["Barehand-combat"] = { "skills.txt", 13 },
+ ["Boomerang-mastery"] = { "skills.txt", 12 },
+ ["Boulder-throwing"] = { "skills.txt", 58 },
+ ["Bow-mastery"] = { "skills.txt", 10 },
+ ["Combat"] = { "skills.txt", 01 },
+ ["Conveyance"] = { "skills.txt", 30 },
+ ["Corpse-preservation"] = { "skills.txt", 44 },
+ ["Critical-hits"] = { "skills.txt", 04 },
+ ["Crossbow-mastery"] = { "skills.txt", 11 },
+ ["Demonology"] = { "skills.txt", 52 },
+ ["Disarming"] = { "skills.txt", 16 },
+ ["Divination"] = { "skills.txt", 31 },
+ ["Dodging"] = { "skills.txt", 20 },
+ ["Druidistic"] = { "skills.txt", 40 },
+ ["Earth"] = { "skills.txt", 28 },
+ ["Fire"] = { "skills.txt", 25 },
+ ["Geomancy"] = { "skills.txt", 60 },
+ ["Hafted-mastery"] = { "skills.txt", 06 },
+ ["Magic"] = { "skills.txt", 21 },
+ ["Magic-Device"] = { "skills.txt", 54 },
+ ["Mana"] = { "skills.txt", 24 },
+ ["Meta"] = { "skills.txt", 29 },
+ ["Mimicry"] = { "skills.txt", 47 },
+ ["Mind"] = { "skills.txt", 33 },
+ ["Mindcraft"] = { "skills.txt", 41 },
+ ["Monster-lore"] = { "skills.txt", 42 },
+ ["Music"] = { "skills.txt", 59 },
+ ["Nature"] = { "skills.txt", 34 },
+ ["Necromancy"] = { "skills.txt", 35 },
+ ["Polearm-mastery"] = { "skills.txt", 07 },
+ ["Possession"] = { "skills.txt", 45 },
+ ["Prayer"] = { "skills.txt", 39 },
+ ["Runecraft"] = { "skills.txt", 36 },
+ ["Sling-mastery"] = { "skills.txt", 09 },
+ ["Sneakiness"] = { "skills.txt", 14 },
+ ["Spell-power"] = { "skills.txt", 22 },
+ ["Spirituality"] = { "skills.txt", 38 },
+ ["Sorcery"] = { "skills.txt", 23 },
+ ["Stealing"] = { "skills.txt", 19 },
+ ["Stealth"] = { "skills.txt", 15 },
+ ["Stunning-blows"] = { "skills.txt", 53 },
+ ["Summoning"] = { "skills.txt", 43 },
+ ["Sword-mastery"] = { "skills.txt", 03 },
+ ["Symbiosis"] = { "skills.txt", 46 },
+ ["Temporal"] = { "skills.txt", 32 },
+ ["Thaumaturgy"] = { "skills.txt", 37 },
+ ["Udun"] = { "skills.txt", 48 },
+ ["Weaponmastery"] = { "skills.txt", 02 },
+ ["Water"] = { "skills.txt", 26 },
+ },
+ ["ability"] =
+ {
+ ["Spread blows"] = { "ability.txt", 02 },
+ ["Tree walking"] = { "ability.txt", 03 },
+ ["Perfect casting"] = { "ability.txt", 04 },
+ ["Extra Max Blow(1)"] = { "ability.txt", 05 },
+ ["Extra Max Blow(2)"] = { "ability.txt", 06 },
+ ["Ammo creation"] = { "ability.txt", 07 },
+ ["Touch of death"] = { "ability.txt", 08 },
+ ["Artifact Creation"] = { "ability.txt", 09 },
+ ["Far reaching attack"] = { "ability.txt", 10 },
+ ["Trapping"] = { "ability.txt", 11 },
+ ["Undead Form"] = { "ability.txt", 12 },
+ },
+ }
+
+ if t[typ][name] then ingame_help_doc(t[typ][name][1], t[typ][name][2])
+ else ingame_help_doc("help.hlp", 0)
+ end
+ end,
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_IDENTIFY,
+ ["event"] = function(i, mode)
+ if mode == "full" then
+ local obj = get_object(i)
+ local f1, f2, f3, f4, f5, esp = object_flags(obj)
+ if band(f5, TR5_SPELL_CONTAIN) ~= 0 then return TRUE end
+ end
+ end,
+ ["desc"] =
+ {
+ "Ah, an item that can contain a spell. To use it you must have some levels of",
+ "Magic skill and then you get the option to copy a spell when pressing m.",
+ "Then just select which spell to copy and to which object. Note that doing so",
+ "is permanent; the spell cannot be removed or changed later.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_BATERIE then return TRUE end end,
+ ["desc"] =
+ {
+ "Ah, an essence! Those magical containers stores energies. They are used",
+ "with the Alchemy skill to create or modify the powers of items.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_RUNE1 or obj.tval == TV_RUNE2 then return TRUE end end,
+ ["desc"] =
+ {
+ "Ah, a rune! Runes are used with the Runecraft skill to allow you to",
+ "create spells on your own.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_ROD_MAIN then return TRUE end end,
+ ["desc"] =
+ {
+ "This is a rod. You will need to attach a rod tip to it before you",
+ "can use it. This main part of the rod may give the rod bonuses",
+ "like quicker charging time, or a larger capacity for charges.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_ROD then return TRUE end end,
+ ["desc"] =
+ {
+ "You've found a rod-tip! You will need to attach it to a rod base",
+ "before you can use it. Once it has been attatched (use the 'z' key)",
+ "you cannot unattach it! The rod tip will determine the effect of",
+ "the rod. To use your rod, 'z'ap it once it has been assembled.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_TRAPKIT then return TRUE end end,
+ ["desc"] =
+ {
+ "Ooooh, a trapping kit. If you have ability in the trapping skill,",
+ "you can lay this trap (via the 'm' key) to harm unsuspecting foes.",
+ "You'll generally need either some ammo or magic device depending",
+ "on the exact type of trap kit.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_RECALC_SKILLS,
+ ["event"] = function() if game.started and (get_melee_skills() > 1) then return TRUE end end,
+ ["desc"] =
+ {
+ "Ah, you now possess more than one melee type. To switch between them press m",
+ "and select the switch melee type option.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_WAND or obj.tval == TV_STAFF then return TRUE end end,
+ ["desc"] =
+ {
+ "You've found a magical device, either a staff or a wand. Each staff",
+ "contains a spell, often from one of the primary magic schools. There",
+ "is a lot of information you can find about this object if you identify",
+ "it and 'I'nspect it. Check the help file on Magic for more about these.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_PLAYER_LEVEL,
+ ["event"] = function(y, x) if player.lev >= 20 then return TRUE end end,
+ ["desc"] =
+ {
+ "I see you are now at least level 20. Nice! If you want to gloat about your",
+ "character you could press 'C' then 'f' to make a character dump and post it to",
+ "http://angband.oook.cz/ where it will end up in the ladder.",
+ }
+}
diff --git a/lib/mods/theme/scpt/init.lua b/lib/mods/theme/scpt/init.lua
new file mode 100644
index 00000000..958d8f7d
--- /dev/null
+++ b/lib/mods/theme/scpt/init.lua
@@ -0,0 +1,56 @@
+--
+-- This file is loaded at the initialisation of ToME
+--
+
+-- Load the class specific stuff
+tome_dofile("player.lua")
+
+-- Load the ingame contextual help
+tome_dofile("help.lua")
+
+-- let the store specific stuff happen!
+tome_dofile("stores.lua")
+
+-- Add various 'U' powers
+tome_dofile("powers.lua")
+
+-- Add the mimic shapes
+tome_dofile("mimic.lua")
+
+-- Add the corruptions
+tome_dofile("corrupt.lua")
+
+-- Add the mkey activations
+tome_dofile("mkeys.lua")
+
+-- Add god stuff
+tome_dofile("gods.lua")
+tome_dofile("gods_new.lua")
+
+-- Add the schools of magic
+tome_dofile("spells.lua")
+
+-- Add some quests
+tome_dofile("bounty.lua")
+tome_dofile("god.lua")
+tome_dofile("fireprof.lua")
+tome_dofile("library.lua")
+
+-- Add joke stuff
+tome_dofile("drunk.lua")
+tome_dofile("joke.lua")
+
+-- Some tests, if the file is not present, this is fine
+tome_dofile_anywhere(ANGBAND_DIR_SCPT, "dg_test.lua", FALSE)
+
+-- A nice custom intro :)
+tome_dofile("intro.lua")
+
+-- Add monster interaction
+tome_dofile("monsters.lua")
+
+-- Add miscellaneous stuff
+tome_dofile("misc.lua")
+
+-- Add map-related quest fix
+tome_dofile("gondolin.lua") \ No newline at end of file
diff --git a/lib/mods/theme/scpt/intro.lua b/lib/mods/theme/scpt/intro.lua
new file mode 100644
index 00000000..3cdce225
--- /dev/null
+++ b/lib/mods/theme/scpt/intro.lua
@@ -0,0 +1,43 @@
+function tome_intro()
+ screen_save()
+ Term_clear()
+
+ if (TRUE == drop_text_left(TERM_L_BLUE, "Three Rings for the Elven-kings under the sky,", 10, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_BLUE, "Seven for the Dwarf-lords in their halls of stone,", 11, -1)) then screen_load() return end
+ if (TRUE == drop_text_left(TERM_L_BLUE, "Nine for Mortal Men doomed to die,", 12, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_BLUE, "One for the Dark Lord on his dark throne", 13, -1)) then screen_load() return end
+ if (TRUE == drop_text_left(TERM_L_BLUE, "In the land of Mordor, where the Shadows lie.", 14, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_BLUE, "One Ring to rule them all, One Ring to find them,", 15, -1)) then screen_load() return end
+ if (TRUE == drop_text_left(TERM_L_BLUE, "One Ring to bring them all and in the darkness bind them", 16, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_BLUE, "In the land of Mordor, where the Shadows lie.", 17, -1)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_GREEN, "--J.R.R. Tolkien", 18, 0)) then screen_load() return end
+ if (TRUE == drop_text_left(TERM_WHITE, "[Press any key to continue]", 23, -1)) then screen_load() return end
+
+ Term_putch(0, 0, TERM_DARK, 32)
+ inkey_scan = FALSE
+ inkey()
+
+ Term_clear()
+
+ if (TRUE == drop_text_left(TERM_L_BLUE, "furiosity", 8, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_WHITE, "in collaboration with", 9, -1)) then screen_load() return end
+ if (TRUE == drop_text_left(TERM_L_GREEN, "DarkGod and all the ToME contributors,", 10, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_GREEN, "module creators, t-o-m-e.net forum posters,", 11, -1)) then screen_load() return end
+ if (TRUE == drop_text_left(TERM_WHITE, "and", 12, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_GREEN, "by the grace of the Valar", 13, -1)) then screen_load() return end
+
+ if (TRUE == drop_text_left(TERM_WHITE, "present", 15, 1)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_YELLOW, "Theme (a module for ToME)", 16, 0)) then screen_load() return end
+
+ if (TRUE == drop_text_left(TERM_WHITE, "[Press any key to continue]", 23, -1)) then screen_load() return end
+ Term_putch(0, 0, TERM_DARK, 32)
+
+ inkey_scan = FALSE
+
+ inkey()
+
+ screen_load()
+ return
+end
+
+add_hook_script(HOOK_INIT, "tome_intro", "lua_intro_init")
diff --git a/lib/mods/theme/scpt/joke.lua b/lib/mods/theme/scpt/joke.lua
new file mode 100644
index 00000000..2d87b651
--- /dev/null
+++ b/lib/mods/theme/scpt/joke.lua
@@ -0,0 +1,31 @@
+-- Place a monster in a good spot
+function gen_joke_place_monster(r_idx)
+ local try = 1000
+ local x
+ local y
+ while try > 0 do
+ x = randint(cur_hgt - 4) + 2
+ y = randint(cur_wid - 4) + 2
+ if not (0 == place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_ENEMY)) then
+ return
+ end
+ try = try - 1
+ end
+end
+
+-- Check if a special joke monster can be generated here
+function gen_joke_monsters()
+ if joke_monsters == FALSE then
+ return
+ end
+
+ -- Neil
+ if (current_dungeon_idx == 20) and (dun_level == 72) then
+ neil = test_monster_name("Neil, the Sorceror")
+ m_allow_special[neil + 1] = TRUE
+ gen_joke_place_monster(neil)
+ m_allow_special[neil + 1] = FALSE
+ end
+end
+
+add_hook_script(HOOK_LEVEL_END_GEN, "gen_joke_monsters", "gen_joke_monsters")
diff --git a/lib/mods/theme/scpt/library.lua b/lib/mods/theme/scpt/library.lua
new file mode 100644
index 00000000..a16d37ef
--- /dev/null
+++ b/lib/mods/theme/scpt/library.lua
@@ -0,0 +1,439 @@
+-- Library quest in Minas Anor
+
+-- Partially based on Fireproofing quest
+
+library_quest = {}
+
+-- Map helper
+library_quest.place_random = function(minY, minX, maxY, maxX, monster)
+ y = randint(maxY - minY + 1) + minY
+ x = randint(maxX - minX + 1) + minX
+ return place_monster_one(y, x, monster, 0, TRUE, MSTATUS_ENEMY)
+end
+
+-- Book creation helpers
+library_quest.bookable_spells =
+{
+ MANATHRUST, DELCURSES,
+ GLOBELIGHT, FIREGOLEM, FIREFLASH, FIREWALL,
+ GEYSER, VAPOR, ENTPOTION,
+ NOXIOUSCLOUD, POISONBLOOD,
+ STONESKIN, DIG,
+ RECHARGE, DISPERSEMAGIC,
+ BLINK, DISARM, TELEPORT,
+ SENSEMONSTERS, SENSEHIDDEN, REVEALWAYS, IDENTIFY, VISION,
+ MAGELOCK, SLOWMONSTER, ESSENCESPEED,
+ CHARM, CONFUSE, ARMOROFFEAR, STUN,
+ GROWTREE, HEALING, RECOVERY,
+ ERU_SEE, ERU_LISTEN,
+ MANWE_BLESS, MANWE_SHIELD,
+ YAVANNA_CHARM_ANIMAL, YAVANNA_GROW_GRASS, YAVANNA_TREE_ROOTS,
+ TULKAS_AIM, TULKAS_SPIN,
+ MELKOR_CURSE, MELKOR_CORPSE_EXPLOSION, DRAIN,
+ AULE_FIREBRAND, AULE_CHILD,
+ VARDA_LIGHT_VALINOR, VARDA_EVENSTAR,
+ ULMO_BELEGAER, ULMO_WRATH,
+ MANDOS_TEARS_LUTHIEN, MANDOS_TALE_DOOM
+}
+
+library_quest.get_term_size = function()
+ local width = 0
+ local height = 0
+ ret, width, height = Term_get_size(width, height)
+ return width, height
+end
+
+library_quest.book_slots_left = function()
+ if school_book[61][1] == -1 then
+ return 3
+ elseif school_book[61][2] == -1 then
+ return 2
+ elseif school_book[61][3] == -1 then
+ return 1
+ else
+ return 0
+ end
+end
+
+library_quest.book_contains_spell = function(spell)
+ if school_book[61][1] == spell then
+ return TRUE
+ elseif school_book[61][2] == spell then
+ return TRUE
+ elseif school_book[61][3] == spell then
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+library_quest.add_spell = function(spell)
+ if school_book[61][1] == -1 then
+ school_book[61][1] = spell
+ return TRUE
+ elseif school_book[61][2] == -1 then
+ school_book[61][2] = spell
+ return TRUE
+ elseif school_book[61][3] == -1 then
+ school_book[61][3] = spell
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+library_quest.remove_spell = function(spell)
+ if school_book[61][1] == spell then
+ school_book[61][1] = school_book[61][2]
+ school_book[61][2] = school_book[61][3]
+ school_book[61][3] = -1
+ return TRUE
+ elseif school_book[61][2] == spell then
+ school_book[61][2] = school_book[61][3]
+ school_book[61][3] = -1
+ return TRUE
+ elseif school_book[61][3] == spell then
+ school_book[61][3] = -1
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+-- Print a spell (taken from s_aux)
+function library_quest.print_spell(color, y, spl)
+ local x, index, sch, size, s
+
+ x = 0
+ size = 0
+ book = 255
+ obj = nil
+
+ -- Hack if the book is 255 it is a random book
+ if book == 255 then
+ school_book[book] = {spl}
+ end
+
+ -- Parse all spells
+ for index, s in school_book[book] do
+ local lvl, na = get_level_school(s, 50, -50)
+ local xx, sch_str
+
+ sch_str = spell_school_name(s)
+
+ if s == spl then
+ if na then
+ c_prt(color, format("%-20s%-16s %3s %4s %3d%s %s", spell(s).name, sch_str, na, get_mana(s), spell_chance(s), "%", __spell_info[s]()), y, x)
+ else
+ c_prt(color, format("%-20s%-16s %3d %4s %3d%s %s", spell(s).name, sch_str, lvl, get_mana(s), spell_chance(s), "%", __spell_info[s]()), y, x)
+ end
+ y = y + 1
+ size = size + 1
+ end
+ end
+ return y
+end
+
+-- spell selection routines inspired by skills.c
+library_quest.print_spells = function(first, current)
+ Term_clear()
+ width, height = library_quest.get_term_size()
+ slots = library_quest.book_slots_left()
+
+ c_prt(TERM_WHITE, "Book Creation Screen", 0, 0);
+ c_prt(TERM_WHITE, "Up/Down to move, Right/Left to modify, I to describe, Esc to Save/Cancel", 1, 0);
+
+ if slots == 0 then
+ c_prt(TERM_L_RED, "The book can hold no more spells.", 2, 0);
+ elseif slots == 1 then
+ c_prt(TERM_L_BLUE, "The book can hold 1 more spell.", 2, 0);
+ else
+ c_prt(TERM_L_BLUE, "The book can hold "..slots.." more spells.", 2, 0);
+ end
+
+ row = 3;
+ for index, spell in library_quest.bookable_spells do
+ if index >= first then
+ if index == current then
+ color = TERM_GREEN
+ elseif library_quest.book_contains_spell(spell) == TRUE then
+ color = TERM_WHITE
+ else
+ color = TERM_ORANGE
+ end
+ library_quest.print_spell(color, row, spell)
+
+ if row == height - 1 then
+ return
+ end
+ row = row + 1
+ end
+ end
+end
+
+library_quest.fill_book = function()
+ -- Always start with a cleared book
+ school_book[61] = {-1, -1, -1}
+
+ screen_save()
+ width, height = library_quest.get_term_size()
+ -- room for legend
+ margin = 3
+
+ first = 1
+ current = 1
+ done = FALSE
+
+ while done == FALSE do
+ library_quest.print_spells(first, current)
+
+ inkey_scan = FALSE
+ inkey_base = TRUE
+ char = inkey()
+ dir = get_keymap_dir(char)
+ if char == ESCAPE then
+ if library_quest.book_slots_left() == 0 then
+ flush()
+ done = get_check("Really create the book?")
+ else
+ done = TRUE
+ end
+ elseif char == strbyte('\r') then
+ -- TODO: make tree of schools
+ elseif char == strbyte('n') then
+ current = current + height
+ elseif char == strbyte('p') then
+ current = current - height
+ elseif char == strbyte('I') then
+ print_spell_desc(library_quest.bookable_spells[current], 0)
+ inkey()
+ elseif dir == 2 then
+ current = current + 1
+ elseif dir == 8 then
+ current = current - 1
+ elseif dir == 6 then
+ if library_quest.book_contains_spell(library_quest.bookable_spells[current]) == FALSE then
+ library_quest.add_spell(library_quest.bookable_spells[current])
+ end
+ elseif dir == 4 then
+ library_quest.remove_spell(library_quest.bookable_spells[current])
+ end
+ total = getn(library_quest.bookable_spells)
+ if current > total then
+ current = total
+ elseif current < 1 then
+ current = 1
+ end
+
+ if current > (first + height - margin - 1) then
+ first = current - height + margin + 1
+ elseif first > current then
+ first = current
+ end
+ end
+
+ screen_load()
+end
+
+-- Quest data and hooks
+add_quest
+{
+ ["global"] = "LIBRARY_QUEST",
+ ["name"] = "Library quest",
+ ["desc"] = function()
+ -- Quest taken
+ if (quest(LIBRARY_QUEST).status == QUEST_STATUS_TAKEN) then
+ print_hook("#####yAn Old Mages Quest! (Danger Level: 35)\n")
+ print_hook("Make the library safe for the old mage in Minas Anor.\n")
+ print_hook("\n")
+ -- Quest done, book not gotten yet
+ elseif (quest(LIBRARY_QUEST).status == QUEST_STATUS_COMPLETED) then
+ print_hook("#####yAn Old Mages Quest!\n")
+ print_hook("You have made the library safe for the old mage in Minas Anor.\n")
+ print_hook("Perhaps you should see about a reward.\n")
+ print_hook("\n")
+ end
+ end,
+ ["level"] = 35,
+ ["data"] =
+ {
+ ["school_book[61][1]"] = -1,
+ ["school_book[61][2]"] = -1,
+ ["school_book[61][3]"] = -1
+ },
+ ["hooks"] =
+ {
+ -- Start the game without the quest, need to request it
+ [HOOK_BIRTH_OBJECTS] = function()
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_UNTAKEN
+ school_book[61] = {-1, -1, -1}
+ end,
+
+ [HOOK_GEN_QUEST] = function()
+ -- Only if player doing this quest
+ if (player.inside_quest ~= LIBRARY_QUEST) then
+ return FALSE
+ end
+
+ load_map("library.map", 2, 2)
+ level_flags2 = DF2_NO_GENO
+
+ -- generate the Liches 518
+ liches = damroll(4, 2) -- plus one on the map
+ while(liches > 0) do
+ if 0 < library_quest.place_random(4, 4, 14, 37, 518) then
+ liches = liches - 1
+ end
+ end
+
+ -- generate the Monastic liches 611
+ liches = damroll(1, 2)
+ while(liches > 0) do
+ if 0 < library_quest.place_random(14, 34, 37, 67, 611) then
+ liches = liches - 1
+ end
+ end
+
+ -- generate more Monastic liches 611
+ liches = damroll(1, 2) - 1
+ while(liches > 0) do
+ if 0 < library_quest.place_random(4, 34, 14, 67, 611) then
+ liches = liches - 1
+ end
+ end
+
+ -- generate even more Monastic liches 611
+ liches = damroll(1, 2) - 1
+ while(liches > 0) do
+ if 0 < library_quest.place_random(14, 4, 37, 34, 611) then
+ liches = liches - 1
+ end
+ end
+
+ -- Flesh golem 256
+ golems = 2
+ while(golems > 0) do
+ if 0 < library_quest.place_random(10, 10, 37, 67, 256) then
+ golems = golems - 1
+ end
+ end
+
+ -- Clay golem 261
+ golems = 2
+ while(golems > 0) do
+ if 0 < library_quest.place_random(10, 10, 37, 67, 261) then
+ golems = golems - 1
+ end
+ end
+
+ -- Iron golem 367
+ golems = 2
+ while(golems > 0) do
+ if 0 < library_quest.place_random(10, 10, 37, 67, 367) then
+ golems = golems - 1
+ end
+ end
+
+ -- Mithril Golem 464
+ golems = 1
+ while(golems > 0) do
+ if 0 < library_quest.place_random(10, 10, 37, 67, 464) then
+ golems = golems - 1
+ end
+ end
+
+ -- one Master lich is on the map
+
+ return TRUE
+ end,
+ [HOOK_STAIR] = function()
+ local ret
+
+ -- only ask this if player about to go up stairs of quest and hasn't won yet
+ if (player.inside_quest ~= LIBRARY_QUEST) or (quest(LIBRARY_QUEST).status == QUEST_STATUS_COMPLETED) then
+ return FALSE
+ end
+
+ if cave(player.py, player.px).feat ~= FEAT_LESS then return end
+
+ -- flush all pending input
+ flush()
+
+ -- confirm
+ ret = get_check("Really abandon the quest?")
+
+ -- if yes, then
+ if ret == TRUE then
+ -- fail the quest
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_FAILED
+ return FALSE
+ else
+ -- if no, they stay in the quest
+ return TRUE
+ end
+ end,
+ [HOOK_MONSTER_DEATH] = function()
+ -- if they're in the quest and haven't won, continue
+ if (player.inside_quest ~= LIBRARY_QUEST) or (quest(LIBRARY_QUEST).status == QUEST_STATUS_COMPLETED) then
+ return FALSE
+ end
+
+ i = 1
+ count = -1
+ while i <= m_max do
+ local monster = m_list[i]
+ if (monster.r_idx > 0) and (monster.status <= MSTATUS_ENEMY) then
+ count = count + 1
+ end
+ i = i + 1
+ end
+
+ if count == 0 then
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_COMPLETED
+ msg_print(TERM_YELLOW, "The library is safe now.")
+ end
+ end,
+ },
+}
+
+-- Library store action
+add_building_action
+{
+ ["index"] = 61,
+ ["action"] = function()
+ -- the quest hasn't been requested already, right?
+ if quest(LIBRARY_QUEST).status == QUEST_STATUS_UNTAKEN then
+ -- quest has been taken now
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_TAKEN
+
+ -- issue instructions
+ msg_print("I need get some stock from my main library, but it is infested with monsters!")
+ msg_print("Please use the side entrance and vanquish the intruders for me.")
+
+ return TRUE, FALSE, TRUE
+ -- if quest completed
+ elseif (quest(LIBRARY_QUEST).status == QUEST_STATUS_COMPLETED) then
+ msg_print("Thank you! Let me make a special book for you.")
+ msg_print("Tell me three spells and I will write them in the book.")
+ library_quest.fill_book()
+ if library_quest.book_slots_left() == 0 then
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_REWARDED
+ book = create_object(TV_BOOK, 61)
+ book.art_name = quark_add(player_name())
+ book.found = OBJ_FOUND_REWARD
+ set_aware(book)
+ set_known(book)
+ inven_carry(book, FALSE)
+ end
+
+ -- if the player asks for a quest when they already have it, but haven't failed it, give them some extra instructions
+ elseif (quest(LIBRARY_QUEST).status == QUEST_STATUS_TAKEN) then
+ msg_print("Please use the side entrance and vanquish the intruders for me.")
+
+ -- quest failed or completed, then give no more quests
+ elseif (quest(LIBRARY_QUEST).status == QUEST_STATUS_FAILED) or (quest(LIBRARY_QUEST).status == QUEST_STATUS_REWARDED) then
+ msg_print("I have no more quests for you.")
+ end
+ return TRUE
+ end,
+}
diff --git a/lib/mods/theme/scpt/mimic.lua b/lib/mods/theme/scpt/mimic.lua
new file mode 100644
index 00000000..f38f70f7
--- /dev/null
+++ b/lib/mods/theme/scpt/mimic.lua
@@ -0,0 +1,419 @@
+-- Define the various possible mimic shapes
+
+-- Nature shapes
+add_mimic_shape
+{
+ ["name"] = "Mouse",
+ ["obj_name"] = "Mouse Fur",
+ ["desc"] = "Mice are small, fast and very stealthy",
+ ["realm"] = "nature",
+ ["level"] = 1,
+ ["rarity"] = 10,
+ ["duration"] = {20, 40},
+ ["calc"] = function ()
+ -- Mice run!
+ player.pspeed = player.pspeed + 5 + (player.mimic_level / 7)
+
+ -- They can crtawl under your armor to hit you ;)
+ player.to_h = player.to_h + 10 + (player.mimic_level / 5)
+ player.dis_to_h = player.dis_to_h + 10 + (player.mimic_level / 5)
+
+ -- But they are not very powerfull
+ player.to_d = player.to_d / 5
+ player.dis_to_d = player.dis_to_d / 5
+
+ -- But they are stealthy
+ player.skill_stl = player.skill_stl + 10 + (player.mimic_level / 5)
+
+ -- Stat mods
+ player.modify_stat(A_STR, -5)
+ player.modify_stat(A_DEX, 3)
+ player.modify_stat(A_CON, 1)
+
+ end,
+ ["power"] = function()
+ if player.mimic_level >= 30 then
+ player.add_power(POWER_INVISIBILITY)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Eagle",
+ ["obj_name"] = "Feathered Cloak",
+ ["desc"] = "Eagles are master of the air, good hunters with excellent vision.",
+ ["realm"] = "nature",
+ ["level"] = 10,
+ ["rarity"] = 30,
+ ["duration"] = {10, 50},
+ ["calc"] = function ()
+ player.ffall = TRUE
+ player.pspeed = player.pspeed + 2 + (player.mimic_level / 6)
+
+ player.modify_stat(A_STR, -3)
+ player.modify_stat(A_DEX, 2 + (player.mimic_level / 15))
+ player.modify_stat(A_CON, 4 + (player.mimic_level / 20))
+ player.modify_stat(A_INT, -1)
+ player.modify_stat(A_WIS, 1)
+ player.modify_stat(A_CHR, -1)
+
+ if player.mimic_level >= 20 then
+ player.xtra_f4 = bor(player.xtra_f4, TR4_FLY)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SEE_INVIS)
+ end
+ if player.mimic_level >= 25 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_ELEC)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SH_ELEC)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Wolf",
+ ["obj_name"] = "Wolf Pelt",
+ ["desc"] = "Wolves are masters of movement, strong and have excellent eyesight.",
+ ["realm"] = "nature",
+ ["level"] = 20,
+ ["rarity"] = 40,
+ ["duration"] = {10, 50},
+ ["calc"] = function ()
+ player.modify_stat(A_STR, 2 + (player.mimic_level / 20))
+ player.modify_stat(A_DEX, 3 + (player.mimic_level / 20))
+ player.modify_stat(A_INT, -3)
+ player.modify_stat(A_CHR, -2)
+
+ player.pspeed = player.pspeed + 10 + (player.mimic_level / 5)
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_FEAR)
+
+ if player.mimic_level >= 10 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_COLD)
+ end
+ if player.mimic_level >= 15 then
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SEE_INVIS)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_DARK)
+ end
+ if player.mimic_level >= 35 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CONF)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Spider",
+ ["obj_name"] = "Spider Web",
+ ["desc"] = "Spiders are clever and become good climbers.",
+ ["realm"] = "nature",
+ ["level"] = 25,
+ ["rarity"] = 50,
+ ["duration"] = {10, 50},
+ ["calc"] = function ()
+ player.modify_stat(A_STR, -4)
+ player.modify_stat(A_DEX, 1 + (player.mimic_level / 8))
+ player.modify_stat(A_INT, 1 + (player.mimic_level / 5))
+ player.modify_stat(A_WIS, 1 + (player.mimic_level / 5))
+ player.modify_stat(A_CON, -5)
+ player.modify_stat(A_CHR, -10)
+
+ player.pspeed = player.pspeed + 5
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_FEAR)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_DARK)
+
+ if player.mimic_level >= 40 then
+ player.xtra_f4 = bor(player.xtra_f4, TR4_CLIMB)
+ end
+
+ end,
+ ["power"] = function()
+ if player.mimic_level >= 25 then
+ player.add_power(POWER_WEB)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Elder Ent",
+ ["obj_name"] = "Entish Bark",
+ ["desc"] = "Ents are powerful tree-like beings dating from the dawn of time.",
+ ["realm"] = "nature",
+ ["level"] = 40,
+ ["rarity"] = 60,
+ ["duration"] = {10, 30},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.pspeed = player.pspeed - 5 - (player.mimic_level / 10)
+
+ player.to_a = player.to_a + 10 + player.mimic_level
+ player.dis_to_a = player.dis_to_a + 10 + player.mimic_level
+
+ player.modify_stat(A_STR, player.mimic_level / 5)
+ player.modify_stat(A_INT, - (player.mimic_level / 7))
+ player.modify_stat(A_WIS, - (player.mimic_level / 7))
+ player.modify_stat(A_DEX, -4)
+ player.modify_stat(A_CON, player.mimic_level / 5)
+ player.modify_stat(A_CHR, -7)
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_COLD)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SEE_INVIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_SENS_FIRE)
+ end,
+ ["power"] = function ()
+ player.add_power(PWR_GROW_TREE)
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Vapour",
+ ["obj_name"] = "Cloak of Mist",
+ ["desc"] = "A sentient cloud, darting around",
+ ["realm"] = "nature",
+ ["level"] = 15,
+ ["rarity"] = 10,
+ ["duration"] = {10, 40},
+ ["calc"] = function ()
+
+ player.pspeed = player.pspeed + 5
+
+ --Try to hit a cloud!
+ player.to_a = player.to_a + 40 + player.mimic_level
+ player.dis_to_a = player.dis_to_a + 40 + player.mimic_level
+
+ --Try to hit WITH a cloud!
+ player.to_h = player.to_h - 40
+ player.dis_to_h = player.dis_to_h -40
+
+ -- Stat mods
+ player.modify_stat(A_STR, -4)
+ player.modify_stat(A_DEX, 5)
+ player.modify_stat(A_CON, -4)
+ player.modify_stat(A_CHR, -10)
+
+ -- But they are stealthy
+ player.skill_stl = player.skill_stl + 10 + (player.mimic_level / 5)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_SHARDS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_COLD)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SEE_INVIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_SENS_FIRE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_FEATHER)
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Serpent",
+ ["obj_name"] = "Snakeskin Cloak",
+ ["desc"] = "Serpents are fast, lethal predators.",
+ ["realm"] = "nature",
+ ["level"] = 30,
+ ["rarity"] = 25,
+ ["duration"] = {15, 20},
+ ["calc"] = function ()
+ player.pspeed = player.pspeed + 10 + (player.mimic_level / 6)
+ player.to_a = player.to_a + 3 + (player.mimic_level / 8)
+ player.dis_to_a = player.dis_to_a + 3 + (player.mimic_level / 8)
+
+ player.modify_stat(A_STR, player.mimic_level / 8)
+ player.modify_stat(A_INT, -6)
+ player.modify_stat(A_WIS, -6)
+ player.modify_stat(A_DEX, -4)
+ player.modify_stat(A_CON, player.mimic_level / 7)
+ player.modify_stat(A_CHR, -6)
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ if player.mimic_level >= 25 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Mumak",
+ ["obj_name"] = "Mumak Hide",
+ ["desc"] = "A giant, elaphantine form.",
+ ["realm"] = "nature",
+ ["level"] = 40,
+ ["rarity"] = 40,
+ ["duration"] = {15, 20},
+ ["calc"] = function ()
+ player.pspeed = player.pspeed - 5 - (player.mimic_level / 10)
+ player.to_a = player.to_a + 10 + (player.mimic_level / 6)
+ player.dis_to_a = player.dis_to_a + 10 + (player.mimic_level / 6)
+ player.to_d = player.to_d + 5 + ((player.mimic_level * 2) / 3)
+ player.dis_to_d = player.dis_to_d + 5 + ((player.mimic_level * 2) / 3)
+
+ player.modify_stat(A_STR, player.mimic_level / 4)
+ player.modify_stat(A_INT, -8)
+ player.modify_stat(A_WIS, -4)
+ player.modify_stat(A_DEX, -5)
+ player.modify_stat(A_CON, player.mimic_level / 3)
+ player.modify_stat(A_CHR, -10)
+
+ if player.mimic_level >= 10 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_FEAR)
+ end
+ if player.mimic_level >= 25 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CONF)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ end
+ if player.mimic_level >= 35 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_NEXUS)
+ end
+ end,
+}
+
+--------- Extra shapes -----------
+
+-- For Beornings
+add_mimic_shape
+{
+ ["name"] = "Bear",
+ ["desc"] = "A fierce, terrible bear.",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {50, 200},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.pspeed = player.pspeed - 5 + (player.mimic_level / 5)
+
+ player.to_a = player.to_a + 5 + ((player.mimic_level * 2) / 3)
+ player.dis_to_a = player.dis_to_a + 5 + ((player.mimic_level * 2) / 3)
+
+ player.modify_stat(A_STR, player.mimic_level / 11)
+ player.modify_stat(A_INT, player.mimic_level / 11)
+ player.modify_stat(A_WIS, player.mimic_level / 11)
+ player.modify_stat(A_DEX, -1)
+ player.modify_stat(A_CON, player.mimic_level / 11)
+ player.modify_stat(A_CHR, -10)
+
+ if player.mimic_level >= 10 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ end
+ if player.mimic_level >= 20 then
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CONF)
+ end
+ if player.mimic_level >= 35 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_NEXUS)
+ end
+
+ -- activate the skill
+ skill(SKILL_BEAR).hidden = FALSE
+ end,
+}
+
+-- For balrog corruptions
+add_mimic_shape
+{
+ ["name"] = "Balrog",
+ ["desc"] = "A corrupted maia.",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {30, 70},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.modify_stat(A_STR, 5 + player.mimic_level / 5)
+ player.modify_stat(A_INT, player.mimic_level / 10)
+ player.modify_stat(A_WIS, - ( 5 + player.mimic_level / 10))
+ player.modify_stat(A_DEX, player.mimic_level / 10)
+ player.modify_stat(A_CON, 5 + player.mimic_level / 5)
+ player.modify_stat(A_CHR, - ( 5 + player.mimic_level / 10))
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_ACID)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_FIRE)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_ELEC)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_DARK)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CHAOS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_HOLD_LIFE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_FEATHER)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SH_FIRE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_LITE1)
+ return 1
+ end,
+}
+
+-- For avatar spell
+add_mimic_shape
+{
+ ["name"] = "Maia",
+ ["desc"] = "A near god-like being.",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {30, 70},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.modify_stat(A_STR, 5 + player.mimic_level / 5)
+ player.modify_stat(A_INT, 5 + player.mimic_level / 5)
+ player.modify_stat(A_WIS, 5 + player.mimic_level / 5)
+ player.modify_stat(A_DEX, 5 + player.mimic_level / 5)
+ player.modify_stat(A_CON, 5 + player.mimic_level / 5)
+ player.modify_stat(A_CHR, 5 + player.mimic_level / 5)
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_FIRE)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_ELEC)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_ACID)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_COLD)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_LITE)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_DARK)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CHAOS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_HOLD_LIFE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_FEATHER)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ return 2
+ end,
+}
+
+-- For Geomancy
+add_mimic_shape
+{
+ ["name"] = "Fire Elem.",
+ ["desc"] = "A towering column of flames",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {10, 10},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.modify_stat(A_STR, 5 + (player.mimic_level / 5))
+ player.modify_stat(A_DEX, 5 + (player.mimic_level / 5))
+ player.modify_stat(A_WIS, -5 - (player.mimic_level / 5))
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_FIRE)
+ -- was immune to poison in the 3.0.0 version
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SH_FIRE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_LITE1)
+ return 0
+ end,
+}
diff --git a/lib/mods/theme/scpt/misc.lua b/lib/mods/theme/scpt/misc.lua
new file mode 100644
index 00000000..acb45f3c
--- /dev/null
+++ b/lib/mods/theme/scpt/misc.lua
@@ -0,0 +1,213 @@
+-- New scrolls
+function sterilize_scroll(tval, sval)
+ if tval == 70 and sval == 54 then
+ msg_print("A neutralising wave radiates from you!")
+ set_no_breeders(randint(100) + 100)
+ return TRUE
+ end
+end
+
+add_hook_script(HOOK_READ, "sterilize_scroll", "sterilize_scroll")
+
+-- Neil's automagic statgain script
+
+player.last_rewarded_level = 1
+add_loadsave("player.last_rewarded_level", 1)
+
+add_hooks
+ {
+ [HOOK_PLAYER_LEVEL] = function()
+ while player.last_rewarded_level * 5 <= player.lev do
+ do_inc_stat(A_STR)
+ do_inc_stat(A_INT)
+ do_inc_stat(A_WIS)
+ do_inc_stat(A_DEX)
+ do_inc_stat(A_CON)
+ do_inc_stat(A_CHR)
+ player.last_rewarded_level = player.last_rewarded_level + 1
+ end
+ end,
+ }
+
+add_hooks
+{
+ [HOOK_BIRTH_OBJECTS] = function()
+ if player.last_rewarded_level >= 1
+ then player.last_rewarded_level = 1
+ else
+ end
+ end
+}
+
+-- silly function that allows a drunk to take a bottle of wine/ale from the player
+
+function drunk_takes_wine(m_idx, item)
+
+ m_ptr = monster(m_idx)
+ o_ptr = get_object(item)
+
+ if (m_ptr.r_idx == test_monster_name("Singing, happy drunk"))
+ and (o_ptr.tval == TV_FOOD) and ((o_ptr.sval == 38) or (o_ptr.sval == 39)) then
+
+ cmsg_print(TERM_YELLOW, "'Hic!'")
+
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+
+-- HackSmurf: the drunk may drop an empty bottle
+ bottle = create_object(TV_BOTTLE,1)
+ drop_near(bottle, 50, player.py, player.px)
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+add_hook_script(HOOK_GIVE, "drunk_takes_wine", "drunk_takes_wine")
+
+-- winged races are allowed soft armor only, no cloaks (from T-Plus)
+function __hook_wings_wear(obj)
+ local str = get_race_name()
+ local type = obj.tval
+ if (str == "Dragon" or str == "Eagle") and (type == 35 or type == 37 or type == 38) then
+ return TRUE, -1
+ end
+end
+
+add_hook_script(HOOK_WIELD_SLOT, "__hook_wings_wear", "__hook_wings_wear")
+
+-- A not-too-scummy way of generating junk for ammo
+function food_vessel(object)
+ if ((object.tval == 80) and (object.sval == 43)) or
+ ((object.tval == 80) and (object.sval == 44)) then
+ local obj = create_object(TV_JUNK, 3)
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ return FALSE
+ end
+end
+
+add_hook_script(HOOK_EAT, "food_vessel", "food_vessel")
+
+-- Longbottom Leaf *is* a great stress reliever:
+function longbottom_leaf(object)
+ if (object.tval == 80) and (object.sval == 45) then
+ msg_print("What a stress reliever!")
+ heal_insanity(1000)
+ return FALSE
+ end
+end
+add_hook_script(HOOK_EAT, "longbottom_leaf", "longbottom_leaf")
+
+-- Hobbits like food
+function hobbit_food(m_idx, item)
+
+ m_ptr = monster(m_idx)
+ o_ptr = get_object(item)
+
+ if (m_ptr.r_idx == test_monster_name("Scruffy-looking hobbit"))
+ and (o_ptr.tval == TV_FOOD) then
+ cmsg_print(TERM_YELLOW, "'Yum!'")
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+add_hook_script(HOOK_GIVE, "hobbit_food", "hobbit_food")
+
+-- Smeagol likes rings
+function smeagol_ring(m_idx, item)
+
+ m_ptr = monster(m_idx)
+ o_ptr = get_object(item)
+
+ if (m_ptr.r_idx == test_monster_name("Smeagol"))
+ and (o_ptr.tval == TV_RING) then
+
+ cmsg_print(TERM_YELLOW, "'MY... PRECIOUSSSSS!!!'")
+
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+add_hook_script(HOOK_GIVE, "smeagol_ring", "smeagol_ring")
+
+-- functions to check for Map and Key of Thror before proceeding in Erebor
+-- Thank you, Massimiliano Marangio :-)
+add_hooks
+{
+ [HOOK_STAIR] = function(direction)
+ if ((current_dungeon_idx == 20) and (dun_level == 60) and (direction == "down")) then
+ local i
+ local mapkey = 0
+ for i = 0, INVEN_TOTAL - 1 do
+ if ((player.inventory(i).name1 == 209) or (player.inventory(i).name1 == 210)) then
+ mapkey = mapkey + 1
+ end
+ end
+
+ if (mapkey == 2) then
+ msg_print("The moon-letters on the map show you the keyhole! You use the key to enter.")
+ return FALSE
+ else
+ msg_print("You have found a door, but you cannot find a way to enter. Ask in Dale, perhaps?")
+ return TRUE
+ end
+ end
+ return FALSE
+ end,
+}
+
+-- function to make the Dale mayor tell you about how to get to Erebor 61
+add_building_action
+{
+ ["index"] = 66,
+ ["action"] = function()
+ msg_print("You will need Thorin's Key and Thrain's Map to get anywhere in Erebor. One may be found in the Barrow-Downs. The other, in Mirkwood.")
+ end
+}
+
+-- function to make Melkor like it if a player quaffs potions of corruption
+function melkor_potion_corruption(object)
+ if (player.pgod == GOD_MELKOR) then
+ if (object.tval == TV_POTION) and (object.sval == SV_POTION_MUTATION) then
+ msg_print("Your quaffing of this potion pleases Melkor!")
+ set_grace(player.grace + 2)
+ return FALSE
+ end
+ end
+end
+add_hook_script(HOOK_QUAFF, "melkor_potion_corruption", "melkor_potion_corruption")
+
+-- function to check for Key of Orthanc before proceeding to the final level in Isengard
+add_hooks
+{
+ [HOOK_STAIR] = function(direction)
+ if ((current_dungeon_idx == 36) and (dun_level == 39) and (direction == "down")) then
+ local i
+ local orthkey = 0
+ for i = 0, INVEN_TOTAL - 1 do
+ if (player.inventory(i).name1 == 15) then
+ orthkey = orthkey + 1
+ end
+ end
+
+ if (orthkey == 1) then
+ msg_print("#BYou have the key to the tower of Orthanc! You may proceed.#w")
+ return FALSE
+ else
+ msg_print("#yYou may not enter Orthanc without the key to the gates!#w Rumours say the key was lost in the Mines of Moria...")
+ return TRUE
+ end
+ end
+ return FALSE
+ end,
+} \ No newline at end of file
diff --git a/lib/mods/theme/scpt/mkeys.lua b/lib/mods/theme/scpt/mkeys.lua
new file mode 100644
index 00000000..07105c64
--- /dev/null
+++ b/lib/mods/theme/scpt/mkeys.lua
@@ -0,0 +1,95 @@
+-- Mkeys for skills & abilities
+
+GF_INSTA_DEATH = add_spell_type
+{
+ ["color"] = { TERM_DARK, 0 },
+ ["angry"] = function() return TRUE, TRUE end,
+ ["monster"] = function(who, dam, rad, y, x, monst)
+ local race = race_info_idx(monst.r_idx, monst.ego)
+ if magik(5) == FALSE or band(race.flags1, RF1_UNIQUE) ~= FALSE or band(race.flags3, RF3_UNDEAD) ~= FALSE or band(race.flags3, RF3_NONLIVING) ~= FALSE then
+ return TRUE, FALSE
+ else
+ -- Reduce the exp gained this way
+ monst.level = monst.level / 3
+ return TRUE, FALSE, 32535, 0, 0, 0, 0, 0, 0, 0, " faints.", " is sucked out of life."
+ end
+ end,
+}
+
+-- Death touch ability
+add_mkey
+{
+ ["mkey"] = 100,
+ ["fct"] = function()
+ if player.csp > 40 then
+ increase_mana(-40)
+ set_project(randint(30) + 10, GF_INSTA_DEATH, 1, 0, bor(PROJECT_STOP, PROJECT_KILL))
+ energy_use = 100
+ else
+ msg_print("You need at least 40 mana.")
+ end
+ end,
+}
+
+
+-- Geomancy skill
+add_mkey
+{
+ ["mkey"] = 101,
+ ["fct"] = function()
+ local s
+
+ -- No magic
+ if (player.antimagic > 0) then
+ msg_print("Your anti-magic field disrupts any magic attempts.")
+ return
+ end
+
+ local obj = get_object(INVEN_WIELD)
+ if (obj.k_idx <= 0) or (obj.tval ~= TV_MSTAFF) then
+ msg_print('You must wield a magestaff to use Geomancy.')
+ return
+ end
+
+ s = get_school_spell("cast", "is_ok_spell", 62);
+
+ -- Actualy cast the choice
+ if (s ~= -1) then
+ cast_school_spell(s, spell(s))
+ end
+ end,
+}
+
+-- Far reaching attack of polearms
+add_mkey
+{
+ ["mkey"] = 102,
+ ["fct"] = function()
+ local weapon = get_object(INVEN_WIELD);
+ if weapon.tval == TV_POLEARM then
+ else
+ msg_print("You will need a long polearm for this!")
+ return
+ end
+
+ ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+
+ local dy, dx = explode_dir(dir)
+ dy = dy * 2
+ dx = dx * 2
+ targety = player.py + dy
+ targetx = player.px + dx
+
+ local max_blows = get_skill_scale(SKILL_POLEARM, player.num_blow / 2)
+ if max_blows == 0 then max_blows = 1 end
+
+ if get_skill(SKILL_POLEARM) >= 40 then
+ energy_use = energy_use + 200
+ return project(0, 0, targety, targetx, max_blows, GF_ATTACK, bor(PROJECT_BEAM, PROJECT_KILL))
+ else
+ energy_use = energy_use + 200
+ return project(0, 0, targety, targetx, max_blows, GF_ATTACK, bor(PROJECT_BEAM, PROJECT_STOP, PROJECT_KILL))
+ end
+ end,
+}
diff --git a/lib/mods/theme/scpt/monsters.lua b/lib/mods/theme/scpt/monsters.lua
new file mode 100644
index 00000000..ad3a5628
--- /dev/null
+++ b/lib/mods/theme/scpt/monsters.lua
@@ -0,0 +1,182 @@
+-- This file holds various things that govern monster behaviour with respect to the player
+
+-- Enables player to push past any monster who is >= MSTATUS_NEUTRAL.
+-- Written by BauMog for the Intets Hevn module; permission granted to use in the Theme module
+
+-- Adapted from defines.h
+function cave_floor_bold(y, x)
+ local c_ptr = cave(y, x);
+ if(cave_is(c_ptr, FF1_FLOOR) == TRUE) and (c_ptr.feat ~= FEAT_MON_TRAP) then
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+-- Adapted from cmd1.c
+function __hook_push_past(y, x)
+ local c_ptr = cave(y, x);
+
+ if(c_ptr.m_idx > 0) then
+ m_ptr = monster(c_ptr.m_idx);
+ if(m_ptr.status >= MSTATUS_NEUTRAL) then
+ if(cave_floor_bold(y, x) == TRUE) or (m_ptr.flags2 == RF2_PASS_WALL) then
+ msg_print(format("You push past %s.", monster_desc(m_ptr, 0)));
+ m_ptr.fy = player.py;
+ m_ptr.fx = player.px;
+ cave(player.py, player.px).m_idx = c_ptr.m_idx;
+ c_ptr.m_idx = 0;
+ else
+ msg_print(format("%s is in your way!", monster_desc(m_ptr, 0)));
+ energy_use = 0;
+ end
+ end
+ end
+
+end
+
+add_hook_script(HOOK_MOVE, "__hook_push_past", "__hook_push_past");
+
+-- Monster vs. Player Race alignment script
+-- From T-Plus by Ingeborg S. Norden
+
+monst_al = {}
+
+function monst_al_add(status, mrs, prs)
+for i,v in mrs do
+-- added end
+if not monst_al[v] then monst_al[v] = {} end
+for j, w in prs do
+monst_al[v][w] = status
+end
+end
+end
+
+function monst_al_get(mr,pr)
+ if monst_al[mr] then return monst_al[mr][pr]
+ else return end
+end
+
+-- Maia aggravation for evil beings (provided that no demonic corruptions are present)
+-- Based on parts of angel.lua from T-Plus by Ingeborg S. Norden
+
+-- cast dispel evil with 0 damage every 10 turns
+
+TIMER_AGGRAVATE_EVIL = new_timer
+{
+ ["enabled"] = FALSE,
+ ["delay"] = 10,
+ ["callback"] = function()
+ dispel_evil(0)
+ end,
+}
+
+add_hooks{
+[HOOK_GAME_START] = function()
+
+ if ((get_race_name() == "Maia") and
+ (player.corruption(CORRUPT_BALROG_AURA) ~= TRUE) and
+ (player.corruption(CORRUPT_BALROG_WINGS) ~= TRUE) and
+ (player.corruption(CORRUPT_BALROG_STRENGTH) ~= TRUE) and
+ (player.corruption(CORRUPT_BALROG_FORM) ~= TRUE)) then
+ -- "Proper" Maiar aggravate evil beings
+ TIMER_AGGRAVATE_EVIL.enabled = TRUE
+ -- Good beings (except swans, GWoPs, Wyrm Spirits, and some joke uniques) are coaligned with Maiar
+
+ monst_al_add(MSTATUS_FRIEND, {25, 29, 45, 97, 109, 147, 225, 335, 346, 443, 581, 629, 699, 853, 984, 1007, 1017}, {21})
+
+ -- Non-evil humanoids are neutral to Humans, Dunedain, Druedain, Rohirrim
+ elseif ((get_race_name() == "Human") or
+ (get_race_name() == "Dunadan") or
+ (get_race_name() == "Druadan") or
+ (get_race_name() == "RohanKnight")) then
+ monst_al_add(MSTATUS_NEUTRAL, {43, 45, 46, 83, 93, 97, 109, 110, 142, 147, 216, 225, 293, 345, 346, 693, 699, 937, 988, 997, 998, 1000},{0, 8, 12, 16})
+
+ -- Non-evil sentient (and non-animal) creatures are neutral to Hobbits, Elves, Wood-Elves
+ elseif ((get_race_name() == "Hobbit") or
+ (get_race_name() == "Elf") or
+ (get_race_name() == "Wood-Elf")) then
+ monst_al_add(MSTATUS_NEUTRAL, {43, 45, 46, 83, 93, 97, 109, 110, 142, 147, 216, 225, 293, 345, 346, 693, 699, 937, 988, 997, 998, 1000, 74, 103, 882, 1017},{2, 3, 20})
+
+ -- Gnome monsters are neutral to Gnomes
+ elseif get_race_name() == "Gnome" then
+ monst_al_add(MSTATUS_NEUTRAL, {103, 281, 680, 984, 1001, 1003, 1007, 1011, 1014, 1016},{4})
+
+ -- Dwarven monsters are neutral to Petty-dwarves and Dwarves
+ elseif ((get_race_name() == "Dwarf") or
+ (get_race_name() == "Petty-Dwarf")) then
+ monst_al_add(MSTATUS_NEUTRAL, {111, 112, 179, 180, 181, 182},{5, 13})
+
+ -- If an Orc character worships Melkor, lower-level Orcs are neutral (not Uruk-hai, however)
+ elseif ((get_race_name() == "Orc") and
+ (player.pgod == GOD_MELKOR)) then
+ monst_al_add(MSTATUS_FRIEND, {87, 118, 126, 149, 244, 251, 264},{6})
+
+ -- If a Troll character worships Melkor, Trolls are neutral (not Eldraks, Ettins, and War trolls, though)
+ elseif ((get_race_name() == "Troll") and
+ (player.pgod == GOD_MELKOR)) then
+ monst_al_add(MSTATUS_NEUTRAL, {297, 401, 403, 424, 454, 491, 496, 509, 538},{7})
+
+ -- Ogres are neutral to Half-Ogres
+ elseif get_race_name() == "Half-Ogre" then
+ monst_al_add(MSTATUS_NEUTRAL, {262, 285, 415, 430, 479, 745, 918},{10})
+
+ -- Bears are neutral to Beornings, except werebears.
+ elseif get_race_name() == "Beorning" then
+ monst_al_add(MSTATUS_NEUTRAL, {160, 173, 191, 854, 855, 867, 873},{11})
+
+ -- Dark elven monsters are coaligned with Dark Elves
+ elseif get_race_name() == "Dark-Elf" then
+ monst_al_add(MSTATUS_FRIEND, {122, 178, 183, 226, 348, 375, 400, 657},{14})
+
+ -- Plants are coaligned with Ents
+ elseif get_race_name() == "Ent" then
+ monst_al_add(MSTATUS_FRIEND, {248, 266, 317, 329, 396},{15})
+
+ -- And since the above is largely useless except out in the wild...
+ -- If an Ent worships Yavanna, lower-level animals are coaligned
+ -- should make the early game a bit easier for Ents.
+ elseif ((get_race_name() == "Ent") and
+ (player.pgod == GOD_YAVANNA)) then
+ monst_al_add(MSTATUS_FRIEND, {21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 35, 36, 37, 38, 39, 41, 49, 50, 52, 56, 57, 58, 59, 60, 61, 62, 69, 70, 75, 77, 78, 79, 86, 88, 89, 90, 95, 96, 105, 106, 114, 119, 120, 121, 123, 127, 134, 141, 143, 151, 154, 155, 156, 160, 161, 168, 171, 173, 174, 175, 176, 187, 191, 196, 197, 198, 210, 211, 213, 230, 236, 250, 259},{15})
+
+ -- All non-evil non-neutral birds are coaligned with Eagles
+ elseif get_race_name() == "Eagle" then
+ monst_al_add(MSTATUS_FRIEND, {61, 141, 151, 279},{17})
+
+ -- Hatchling dragons are coaligned with Dragons
+ elseif get_race_name() == "Dragon" then
+ monst_al_add(MSTATUS_FRIEND, {163, 164, 165, 166, 167, 204, 218, 219, 911},{18})
+
+ -- Yeeks are neutral to Yeeks
+ elseif get_race_name() == "Yeek" then
+ monst_al_add(MSTATUS_NEUTRAL, {580, 583, 594, 653, 655, 659, 661},{19})
+
+ -- Oathbreakers are coaligned if player is wielding Anduril
+ -- It's dirty, but it works, and it doesn't bother checking demons and the races who can't wield weapons.
+ elseif get_object(INVEN_WIELD).name1 == 83 then
+ monst_al_add(MSTATUS_FRIEND, {731},{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23})
+ end
+end,
+
+[HOOK_LEVEL_END_GEN] = function()
+
+for i=0,m_max-1 do
+ local monst = monster(i)
+ local s = monst_al_get(monst.r_idx, player.prace)
+ if s then monst.status = s end
+end
+
+end,
+
+[HOOK_NEW_MONSTER] = function()
+
+for i=0,m_max-1 do
+ local monst = monster(i)
+ local s = monst_al_get(monst.r_idx, player.prace)
+ if s then monst.status = s end
+end
+
+end,
+
+} \ No newline at end of file
diff --git a/lib/mods/theme/scpt/player.lua b/lib/mods/theme/scpt/player.lua
new file mode 100644
index 00000000..fd11ed9d
--- /dev/null
+++ b/lib/mods/theme/scpt/player.lua
@@ -0,0 +1,196 @@
+------------------------------------------------------------------------------
+----------------------- Hook to create birth objects -------------------------
+------------------------------------------------------------------------------
+function __birth_hook_objects()
+
+ -- Grace delay for adding piety
+ GRACE_DELAY = 0
+
+ -- Provide a book of Geyser to Geomancers
+ if get_class_name() == "Geomancer" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Geyser")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Provide a book of prayer to priests
+ if get_class_name() == "Priest(Eru)" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("See the Music")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Priest(Manwe)" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Manwe's Blessing")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Druid" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Charm Animal")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Dark-Priest" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Curse")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Paladin" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Divine Aim")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Stonewright" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Firebrand")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Priest(Varda)" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Light of Valinor")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Priest(Ulmo)" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Song of Belegaer")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Priest(Mandos)" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Tears of Luthien")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ if get_class_name() == "Mimic" then
+ local obj = create_object(TV_CLOAK, 100);
+ obj.pval2 = resolve_mimic_name("Mouse")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the undeads, as undeads with the corruptions
+ if get_subrace_name() == "Vampire" then
+ player.corruption(CORRUPT_VAMPIRE_TEETH, TRUE)
+ player.corruption(CORRUPT_VAMPIRE_STRENGTH, TRUE)
+ player.corruption(CORRUPT_VAMPIRE_VAMPIRE, TRUE)
+ end
+
+ -- Start the Red (Fire) dragons with a book of Light (Theme)
+ if get_subrace_name() == "Red" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Globe of Light")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the Black (Water) dragons with a book of Geyser (Theme)
+ if get_subrace_name() == "Black" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Geyser")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the Green (Air) dragons with a book of Noxious Cloud (Theme)
+ if get_subrace_name() == "Green" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Noxious Cloud")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the Blue (Earth) dragons with a book of Stone Skin (Theme)
+ if get_subrace_name() == "Blue" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Stone Skin")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the White dragons with a book of Sense Monsters (Theme)
+ if get_subrace_name() == "White" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Sense Monsters")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the Ethereal dragons with a book of Recharge (Theme)
+ if get_subrace_name() == "Ethereal" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Recharge")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the Aewroeg with a book of Charm (Theme)
+ if get_subrace_name() == "(Aewrog)" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Charm")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the Narroeg with a book of blink (Theme)
+ if get_subrace_name() == "(Narrog)" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Phase Door")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the Peace-mages with a book of blink (Theme)
+ if get_class_name() == "Peace-mage" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Phase Door")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the Wainriders with a book of Curse (Theme)
+ if get_class_name() == "Wainrider" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Curse")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Provide everyone with a scroll of WoR (Theme)
+ local obj = create_object(TV_SCROLL, SV_SCROLL_WORD_OF_RECALL);
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ identify_pack_fully()
+end
+
+-- Register in the hook list
+add_hook_script(HOOK_BIRTH_OBJECTS, "__birth_hook_objects", "__birth_hook_objects")
diff --git a/lib/mods/theme/scpt/powers.lua b/lib/mods/theme/scpt/powers.lua
new file mode 100644
index 00000000..ff4c62c5
--- /dev/null
+++ b/lib/mods/theme/scpt/powers.lua
@@ -0,0 +1,61 @@
+-- Various 'U' powers
+
+-- Invisibility power, for the mouse mimic shape
+POWER_INVISIBILITY = add_power
+{
+ ["name"] = "invisibility",
+ ["desc"] = "You are able melt into the shadows to become invisible.",
+ ["desc_get"] = "You suddenly become able to melt into the shadows.",
+ ["desc_lose"] = "You lose your shadow-melting ability.",
+ ["level"] = 30,
+ ["cost"] = 10,
+ ["stat"] = A_DEX,
+ ["fail"] = 20,
+ ["power"] = function()
+ set_invis(20 + randint(30), 30)
+ end,
+}
+
+-- Web power, for the spider mimic shape
+POWER_WEB = add_power
+{
+ ["name"] = "web",
+ ["desc"] = "You are able throw a thick and very resistant spider web.",
+ ["desc_get"] = "You suddenly become able to weave webs.",
+ ["desc_lose"] = "You lose your web-weaving capability.",
+ ["level"] = 25,
+ ["cost"] = 30,
+ ["stat"] = A_DEX,
+ ["fail"] = 20,
+ ["power"] = function()
+ -- Warning, beware of f_info changes .. I hate to do that ..
+ grow_things(16, 1 + (player.lev / 10))
+ end,
+}
+
+-- Activating/stopping space-continuum
+-- When stopped it will induce constant mana loss
+player.corrupt_anti_teleport_stopped = FALSE
+add_loadsave("player.corrupt_anti_teleport_stopped", FALSE)
+POWER_COR_SPACE_TIME = add_power
+{
+ ["name"] = "control space/time continuum",
+ ["desc"] = "You are able to control the space/time continuum.",
+ ["desc_get"] = "You become able to control the space/time continuum.",
+ ["desc_lose"] = "You are no more able to control the space/time continuum.",
+ ["level"] = 1,
+ ["cost"] = 10,
+ ["stat"] = A_WIS,
+ ["fail"] = 10,
+ ["power"] = function()
+ if player.corrupt_anti_teleport_stopped == TRUE then
+ player.corrupt_anti_teleport_stopped = FALSE
+ msg_print("You stop controlling your corruption.")
+ player.update = bor(player.update, PU_BONUS)
+ else
+ player.corrupt_anti_teleport_stopped = TRUE
+ msg_print("You start controlling your corruption, teleportation works once more.")
+ player.update = bor(player.update, PU_BONUS)
+ end
+ end,
+}
diff --git a/lib/mods/theme/scpt/s_air.lua b/lib/mods/theme/scpt/s_air.lua
new file mode 100644
index 00000000..afd1f584
--- /dev/null
+++ b/lib/mods/theme/scpt/s_air.lua
@@ -0,0 +1,193 @@
+-- handle the air school
+
+NOXIOUSCLOUD = add_spell
+{
+ ["name"] = "Noxious Cloud",
+ ["school"] = {SCHOOL_AIR},
+ ["level"] = 3,
+ ["mana"] = 3,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 7 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 15,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir, type
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ if get_level(NOXIOUSCLOUD, 50) >= 30 then type = GF_UNBREATH
+ else type = GF_POIS end
+ fire_cloud(type, dir, 7 + get_level(NOXIOUSCLOUD, 150), 3, 5 + get_level(NOXIOUSCLOUD, 40))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(7 + get_level(NOXIOUSCLOUD, 150)).." rad 3 dur "..(5 + get_level(NOXIOUSCLOUD, 40))
+ end,
+ ["desc"] = {
+ "Creates a cloud of poison",
+ "The cloud will persist for some turns, damaging all monsters passing by",
+ "At spell level 30 it turns into a thick gas attacking all living beings"
+ }
+}
+
+AIRWINGS = add_spell
+{
+ ["name"] = "Wings of Winds",
+ ["school"] = {SCHOOL_AIR, SCHOOL_CONVEYANCE},
+ ["level"] = 22,
+ ["mana"] = 30,
+ ["mana_max"] = 40,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 27,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ if get_level(AIRWINGS, 50) >= 16 then
+ if player.tim_fly == 0 then return set_tim_fly(randint(10) + 5 + get_level(AIRWINGS, 25)) end
+ else
+ if player.tim_ffall == 0 then return set_tim_ffall(randint(10) + 5 + get_level(AIRWINGS, 25)) end
+ end
+ return FALSE
+ end,
+ ["info"] = function()
+ return "dur "..(5 + get_level(AIRWINGS, 25)).."+d10"
+ end,
+ ["desc"] = {
+ "Grants the power of levitation",
+ "At level 16 it grants the power of controlled flight"
+ }
+}
+
+INVISIBILITY = add_spell
+{
+ ["name"] = "Invisibility",
+ ["school"] = {SCHOOL_AIR},
+ ["level"] = 16,
+ ["mana"] = 10,
+ ["mana_max"] = 20,
+ ["fail"] = 50,
+ ["inertia"] = { 1, 30 },
+ ["spell"] = function()
+ if player.tim_invisible == 0 then return set_invis(randint(20) + 15 + get_level(INVISIBILITY, 50), 20 + get_level(INVISIBILITY, 50)) end
+ end,
+ ["info"] = function()
+ return "dur "..(15 + get_level(INVISIBILITY, 50)).."+d20 power "..(20 + get_level(INVISIBILITY, 50))
+ end,
+ ["desc"] = {
+ "Grants invisibility"
+ }
+}
+
+POISONBLOOD = add_spell
+{
+ ["name"] = "Poison Blood",
+ ["school"] = {SCHOOL_AIR},
+ ["level"] = 12,
+ ["mana"] = 10,
+ ["mana_max"] = 20,
+ ["fail"] = 30,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 15 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 45,
+ ["base_level"] = { 1, 25 },
+ ["max_level"] = { 35, 50 },
+ },
+ },
+ ["inertia"] = { 1, 35 },
+ ["spell"] = function()
+ local obvious = nil
+ if player.oppose_pois == 0 then obvious = set_oppose_pois(randint(30) + 25 + get_level(POISONBLOOD, 25)) end
+ if (player.tim_poison == 0) and (get_level(POISONBLOOD, 50) >= 15) then obvious = is_obvious(set_poison(randint(30) + 25 + get_level(POISONBLOOD, 25)), obvious) end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(25 + get_level(POISONBLOOD, 25)).."+d30"
+ end,
+ ["desc"] = {
+ "Grants resist poison",
+ "At level 15 it provides poison branding to wielded weapon"
+ }
+}
+
+THUNDERSTORM = add_spell
+{
+ ["name"] = "Thunderstorm",
+ ["school"] = {SCHOOL_AIR, SCHOOL_NATURE},
+ ["level"] = 25,
+ ["mana"] = 40,
+ ["mana_max"] = 60,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 85,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["inertia"] = { 2, 15 },
+ ["spell"] = function()
+ if player.tim_thunder == 0 then return set_tim_thunder(randint(10) + 10 + get_level(THUNDERSTORM, 25), 5 + get_level(THUNDERSTORM, 10), 10 + get_level(THUNDERSTORM, 25)) end
+ return FALSE
+ end,
+ ["info"] = function()
+ return "dam "..(5 + get_level(THUNDERSTORM, 10)).."d"..(10 + get_level(THUNDERSTORM, 25)).." dur "..(10 + get_level(THUNDERSTORM, 25)).."+d10"
+ end,
+ ["desc"] = {
+ "Charges up the air around you with electricity",
+ "Each turn it will throw a thunder bolt at a random monster in sight",
+ "The thunder does 3 types of damage, one third of lightning",
+ "one third of sound and one third of light"
+ }
+}
+
+STERILIZE = add_spell
+{
+ ["name"] = "Sterilize",
+ ["school"] = {SCHOOL_AIR},
+ ["level"] = 20,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 50,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 20,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ set_no_breeders((30) + 20 + get_level(STERILIZE, 70))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dur "..(20 + get_level(STERILIZE, 70)).."+d30"
+ end,
+ ["desc"] = {
+ "Prevents explosive breeding for a while."
+ }
+}
diff --git a/lib/mods/theme/scpt/s_aule.lua b/lib/mods/theme/scpt/s_aule.lua
new file mode 100644
index 00000000..d3ca4733
--- /dev/null
+++ b/lib/mods/theme/scpt/s_aule.lua
@@ -0,0 +1,222 @@
+-- Spells for Aule school
+
+BOOK_AULE = 63
+
+AULE_FIREBRAND = add_spell
+{
+ ["name"] = "Firebrand",
+ ["school"] = {SCHOOL_AULE},
+ ["level"] = 1,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 20,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local type, rad
+ local level = get_level(AULE_FIREBRAND)
+ type = GF_FIRE
+
+ if (get_level(AULE_FIREBRAND) > 30) then
+ type = GF_HOLY_FIRE
+ end
+
+ rad = 0
+ if (level >= 15) then
+ rad = 1
+ end
+ return set_project(level + randint(20),
+ type, 4 + level, rad,
+ bor(PROJECT_STOP, PROJECT_KILL))
+ end,
+ ["info"] = function()
+ local level = get_level(AULE_FIREBRAND)
+ return "dur "..(level).."+d20 dam "..(4 + level).."/blow"
+ end,
+ ["desc"] = {
+ "Imbues your melee weapon with fire to deal more damage",
+ "At level 15 it spreads over a 1 radius zone around your target",
+ "At level 30 it deals holy fire damage"
+ }
+}
+
+AULE_ENCHANT_WEAPON = add_spell
+{
+ ["name"] = "Enchant Weapon",
+ ["school"] = {SCHOOL_AULE},
+ ["level"] = 10,
+ ["mana"] = 100,
+ ["mana_max"] = 200,
+ ["fail"] = 20,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local level = get_level(AULE_ENCHANT_WEAPON)
+ local num_h, num_d, num_p
+
+ local ret, item, obj
+
+ num_h = 1 + randint(level/12)
+ num_d = 0
+ num_p = 0
+ if (level >= 5) then
+ num_d = 1 + randint(level/12)
+ end
+ if (level >= 45) then
+ num_p = 1
+ end
+ --return enchant_spell(num_h, num_d, 0, num_p)
+
+ ret, item = get_item("Which object do you want to enchant?",
+ "You have no objects to enchant.",
+ bor(USE_INVEN),
+ function (obj)
+ if obj.name1 > 0 then return FALSE end
+ if (obj.tval == TV_MSTAFF) then
+ return TRUE
+ elseif (obj.tval == TV_BOW) then
+ return TRUE
+ elseif (obj.tval == TV_HAFTED) then
+ return TRUE
+ elseif (obj.tval == TV_POLEARM) then
+ return TRUE
+ elseif (obj.tval == TV_SWORD) then
+ return TRUE
+ elseif (obj.tval == TV_AXE) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+ if ret == FALSE then return FALSE end
+
+ obj = get_object(item)
+
+ obj.to_h = obj.to_h + num_h
+ obj.to_d = obj.to_d + num_h
+ obj.pval = obj.pval + num_p
+
+ return TRUE
+
+ end,
+ ["info"] = function()
+ return "tries "..(1 + get_level(AULE_ENCHANT_WEAPON)/12)
+ end,
+ ["desc"] = {
+ "Tries to enchant a weapon to-hit",
+ "At level 5 it also enchants to-dam",
+ "At level 45 it enhances the special powers of magical weapons",
+ "The might of the enchantment increases with the level"
+ }
+}
+
+AULE_ENCHANT_ARMOUR = add_spell {
+ ["name"] = "Enchant Armour",
+ ["school"] = {SCHOOL_AULE},
+ ["level"] = 15,
+ ["mana"] = 100,
+ ["mana_max"] = 200,
+ ["fail"] = 20,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local level = get_level(AULE_ENCHANT_ARMOUR)
+ local num_h, num_d, num_a, num_p
+ local ret, item, obj
+
+ num_a = 1 + randint(level/10)
+ num_h = 0
+ num_d = 0
+ num_p = 0
+ if (level >= 20) then
+ num_h = 1
+ num_d = 1
+ end
+ if (level >= 40) then
+ num_p = 1
+ end
+ --return enchant_spell(num_h, num_d, num_a, num_p)
+
+ ret, item = get_item("Which object do you want to enchant?",
+ "You have no objects to enchant.",
+ bor(USE_INVEN),
+ function (obj)
+ if obj.name1 > 0 then return FALSE end
+ if (obj.tval == TV_BOOTS) then
+ return TRUE
+ elseif (obj.tval == TV_GLOVES) then
+ return TRUE
+ elseif (obj.tval == TV_HELM) then
+ return TRUE
+ elseif (obj.tval == TV_CROWN) then
+ return TRUE
+ elseif (obj.tval == TV_SHIELD) then
+ return TRUE
+ elseif (obj.tval == TV_CLOAK) then
+ return TRUE
+ elseif (obj.tval == TV_SOFT_ARMOR) then
+ return TRUE
+ elseif (obj.tval == TV_HARD_ARMOR) then
+ return TRUE
+ elseif (obj.tval == TV_DRAG_ARMOR) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+ if ret == FALSE then return FALSE end
+
+ obj = get_object(item)
+
+ obj.to_h = obj.to_h + num_h
+ obj.to_d = obj.to_d + num_h
+ obj.pval = obj.pval + num_p
+ obj.to_a = obj.to_a + num_h
+
+ return TRUE
+
+ end,
+ ["info"] = function()
+ return "tries "..(1 + get_level(AULE_ENCHANT_ARMOUR)/10)
+ end,
+ ["desc"] = {
+ "Tries to enchant a piece of armour",
+ "At level 20 it also enchants to-hit and to-dam",
+ "At level 40 it enhances the special powers of magical armour",
+ "The might of the enchantment increases with the level"
+ }
+}
+
+AULE_CHILD = add_spell
+{
+ ["name"] = "Child of Aule",
+ ["school"] = {SCHOOL_AULE},
+ ["level"] = 20,
+ ["mana"] = 200,
+ ["mana_max"] = 500,
+ ["fail"] = 40,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local y, x, m_idx
+
+ y, x = find_position(player.py, player.px)
+ m_idx = place_monster_one(y, x, test_monster_name("Dwarven warrior"), 0, FALSE, MSTATUS_FRIEND)
+
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 20 + get_level(AULE_CHILD, 70, 0))
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return "level "..(20 + get_level(AULE_CHILD, 70))
+ end,
+ ["desc"] = {
+ "Summons a levelled Dwarven warrior to help you battle the forces",
+ "of Morgoth"
+ }
+} \ No newline at end of file
diff --git a/lib/mods/theme/scpt/s_convey.lua b/lib/mods/theme/scpt/s_convey.lua
new file mode 100644
index 00000000..1105a850
--- /dev/null
+++ b/lib/mods/theme/scpt/s_convey.lua
@@ -0,0 +1,226 @@
+-- handle the conveyance school
+
+BLINK = add_spell
+{
+ ["name"] = "Phase Door",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 3,
+ ["fail"] = 10,
+ ["inertia"] = { 1, 5 },
+ ["spell"] = function()
+ if get_level(BLINK, 50) >= 30 then
+ local oy, ox = player.py, player.px
+
+ teleport_player(10 + get_level(BLINK, 8))
+ create_between_gate(0, oy, ox)
+ return TRUE
+ else
+ teleport_player(10 + get_level(BLINK, 8))
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return "distance "..(10 + get_level(BLINK, 8))
+ end,
+ ["desc"] = {
+ "Teleports you on a small scale range",
+ "At level 30 it creates void jumpgates",
+ }
+}
+
+DISARM = add_spell
+{
+ ["name"] = "Disarm",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 3,
+ ["mana"] = 2,
+ ["mana_max"] = 4,
+ ["fail"] = 15,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 15 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 4,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 10, 50 },
+ },
+ },
+ ["spell"] = function()
+ local obvious
+ obvious = destroy_doors_touch()
+ if get_level(DISARM, 50) >= 10 then obvious = is_obvious(destroy_traps_touch(), obvious) end
+ return obvious
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Destroys doors and disarms traps",
+ "At level 10 it unlocks doors and disarms traps",
+ }
+}
+
+TELEPORT = add_spell
+{
+ ["name"] = "Teleportation",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 10,
+ ["mana"] = 8,
+ ["mana_max"] = 14,
+ ["fail"] = 30,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 7 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 50,
+ ["base_level"] = { 1, 20 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ player.energy = player.energy - (25 - get_level(TELEPORT, 50))
+ teleport_player(100 + get_level(TELEPORT, 100))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "distance "..(100 + get_level(TELEPORT, 100))
+ end,
+ ["desc"] = {
+ "Teleports you around the level. The casting time decreases with level",
+ }
+}
+
+TELEAWAY = add_spell
+{
+ ["name"] = "Teleport Away",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 23,
+ ["mana"] = 15,
+ ["mana_max"] = 40,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 75,
+ ["base_level"] = { 1, 20 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir
+
+ if get_level(TELEAWAY, 50) >= 20 then
+ return project_los(GF_AWAY_ALL, 100)
+ elseif get_level(TELEAWAY, 50) >= 10 then
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_AWAY_ALL, dir, 100, 3 + get_level(TELEAWAY, 4))
+ else
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return teleport_monster(dir)
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Teleports a line of monsters away",
+ "At level 10 it turns into a ball",
+ "At level 20 it teleports all monsters in sight"
+ }
+}
+
+RECALL = add_spell
+{
+ ["name"] = "Recall",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 30,
+ ["mana"] = 25,
+ ["mana_max"] = 25,
+ ["fail"] = 60,
+ ["spell"] = function()
+ local ret, x, y, c_ptr
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ c_ptr = cave(y, x)
+ if (y == player.py) and (x == player.px) then
+ local d = 21 - get_level(RECALL, 15)
+ if d < 0 then
+ d = 0
+ end
+ local f = 15 - get_level(RECALL, 10)
+ if f < 1 then
+ f = 1
+ end
+ recall_player(d, f)
+ return TRUE
+ elseif c_ptr.m_idx > 0 then
+ swap_position(y, x)
+ return TRUE
+ elseif c_ptr.o_idx > 0 then
+ set_target(y, x)
+ if get_level(RECALL, 50) >= 15 then
+ fetch(5, 10 + get_level(RECALL, 150), FALSE)
+ else
+ fetch(5, 10 + get_level(RECALL, 150), TRUE)
+ end
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ local d = 21 - get_level(RECALL, 15)
+ if d < 0 then
+ d = 0
+ end
+ local f = 15 - get_level(RECALL, 10)
+ if f < 1 then
+ f = 1
+ end
+ return "dur "..f.."+d"..d.." weight "..(1 + get_level(RECALL, 15)).."lb"
+ end,
+ ["desc"] = {
+ "Cast on yourself it will recall you to the surface/dungeon.",
+ "Cast at a monster you will swap positions with the monster.",
+ "Cast at an object it will fetch the object to you."
+ }
+}
+
+PROBABILITY_TRAVEL = add_spell
+{
+ ["name"] = "Probability Travel",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 35,
+ ["mana"] = 30,
+ ["mana_max"] = 50,
+ ["fail"] = 90,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 2 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 97,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 8, 25 },
+ },
+ },
+ ["inertia"] = { 6, 40 },
+ ["spell"] = function()
+ return set_prob_travel(randint(20) + get_level(PROBABILITY_TRAVEL, 60))
+ end,
+ ["info"] = function()
+ return "dur "..get_level(PROBABILITY_TRAVEL, 60).."+d20"
+ end,
+ ["desc"] = {
+ "Renders you immaterial, when you hit a wall you travel through it and",
+ "instantly appear on the other side of it. You can also float up and down",
+ "at will"
+ }
+}
diff --git a/lib/mods/theme/scpt/s_demon.lua b/lib/mods/theme/scpt/s_demon.lua
new file mode 100644
index 00000000..ada97310
--- /dev/null
+++ b/lib/mods/theme/scpt/s_demon.lua
@@ -0,0 +1,337 @@
+-- handle the demonology school
+
+-- Demonblade
+DEMON_BLADE = add_spell
+{
+ ["name"] = "Demon Blade",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 1,
+ ["mana"] = 4,
+ ["mana_max"] = 44,
+ ["fail"] = 10,
+ ["random"] = 0,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 7 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 75,
+ ["base_level"] = { 1, 17 },
+ ["max_level"] = { 20, 40 },
+ },
+ },
+ ["spell"] = function()
+ local type, rad
+
+ type = GF_FIRE
+ if get_level(DEMON_BLADE) >= 30 then type = GF_HELL_FIRE end
+
+ rad = 0
+ if get_level(DEMON_BLADE) >= 45 then rad = 1 end
+
+ return set_project(randint(20) + get_level(DEMON_BLADE, 80),
+ type,
+ 4 + get_level(DEMON_BLADE, 40),
+ rad,
+ bor(PROJECT_STOP, PROJECT_KILL))
+ end,
+ ["info"] = function()
+ return "dur "..(get_level(DEMON_BLADE, 80)).."+d20 dam "..(4 + get_level(DEMON_BLADE, 40)).."/blow"
+ end,
+ ["desc"] = {
+ "Imbues your blade with fire to deal more damage",
+ "At level 30 it deals hellfire damage",
+ "At level 45 it spreads over a 1 radius zone around your target",
+ }
+}
+
+DEMON_MADNESS = add_spell
+{
+ ["name"] = "Demon Madness",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 10,
+ ["mana"] = 5,
+ ["mana_max"] = 20,
+ ["fail"] = 25,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir, type, y1, x1, y2, x2
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ type = GF_CHAOS
+ if magik(33) == TRUE then type = GF_CONFUSION end
+ if magik(33) == TRUE then type = GF_CHARM end
+
+ -- Calc the coordinates of arrival
+ y1, x1 = get_target(dir)
+ y2 = player.py - (y1 - player.py)
+ x2 = player.px - (x1 - player.px)
+
+ local obvious = nil
+ obvious = project(0, 1 + get_level(DEMON_MADNESS, 4, 0),
+ y1, x1,
+ 20 + get_level(DEMON_MADNESS, 200),
+ type, bor(PROJECT_STOP, PROJECT_GRID, PROJECT_ITEM, PROJECT_KILL))
+ obvious = is_obvious(project(0, 1 + get_level(DEMON_MADNESS, 4, 0),
+ y2, x2,
+ 20 + get_level(DEMON_MADNESS, 200),
+ type, bor(PROJECT_STOP, PROJECT_GRID, PROJECT_ITEM, PROJECT_KILL)), obvious)
+ return obvious
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(DEMON_MADNESS, 200)).." rad "..(1 + get_level(DEMON_MADNESS, 4, 0))
+ end,
+ ["desc"] = {
+ "Fire 2 balls in opposite directions of randomly chaos, confusion or charm",
+ }
+}
+
+DEMON_FIELD = add_spell
+{
+ ["name"] = "Demon Field",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 20,
+ ["mana"] = 20,
+ ["mana_max"] = 60,
+ ["fail"] = 60,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_cloud(GF_NEXUS, dir, 20 + get_level(DEMON_FIELD, 70), 7, 30 + get_level(DEMON_FIELD, 100))
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(DEMON_FIELD, 70)).." dur "..(30 + get_level(DEMON_FIELD, 100))
+ end,
+ ["desc"] = {
+ "Fires a cloud of deadly nexus over a radius of 7",
+ }
+}
+
+-- Demonshield
+
+DOOM_SHIELD = add_spell
+{
+ ["name"] = "Doom Shield",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 1,
+ ["mana"] = 2,
+ ["mana_max"] = 30,
+ ["fail"] = 10,
+ ["random"] = 0,
+ ["spell"] = function()
+ return set_shield(randint(10) + 20 + get_level(DOOM_SHIELD, 100), -300 + get_level(DOOM_SHIELD, 100), SHIELD_COUNTER, 1 + get_level(DOOM_SHIELD, 14), 10 + get_level(DOOM_SHIELD, 15))
+ end,
+ ["info"] = function()
+ return "dur "..(20 + get_level(DOOM_SHIELD, 100)).."+d10 dam "..(1 + get_level(DOOM_SHIELD, 14)).."d"..(10 + get_level(DOOM_SHIELD, 15))
+ end,
+ ["desc"] = {
+ "Raises a mirror of pain around you, doing very high damage to your foes",
+ "that dare hit you, but greatly reduces your armour class",
+ }
+}
+
+UNHOLY_WORD = add_spell
+{
+ ["name"] = "Unholy Word",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 25,
+ ["mana"] = 15,
+ ["mana_max"] = 45,
+ ["fail"] = 55,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, x, y, c_ptr
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ c_ptr = cave(y, x)
+
+ -- ok that is a monster
+ if c_ptr.m_idx > 0 then
+ local m_ptr = monster(c_ptr.m_idx)
+ if m_ptr.status ~= MSTATUS_PET then
+ msg_print("You can only target a pet.")
+ return
+ end
+
+ -- Oups he is angry now
+ if magik(30 - get_level(UNHOLY_WORD, 25, 0)) == TRUE then
+ local m_name = monster_desc(m_ptr, 0).." turns against you."
+ msg_print(strupper(strsub(m_name, 0, 1))..strsub(m_name, 2))
+ else
+ local m_name = monster_desc(m_ptr, 0)
+ msg_print("You consume "..m_name..".")
+
+ local heal = (m_ptr.hp * 100) / m_ptr.maxhp
+ heal = ((30 + get_level(UNHOLY_WORD, 50, 0)) * heal) / 100
+
+ hp_player(heal)
+
+ delete_monster_idx(c_ptr.m_idx)
+ end
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return "heal mhp% of "..(30 + get_level(UNHOLY_WORD, 50, 0)).."%"
+ end,
+ ["desc"] = {
+ "Kills a pet to heal you",
+ "There is a chance that the pet won't die but will turn against you",
+ "it will decrease with higher level",
+ }
+}
+
+DEMON_CLOAK = add_spell
+{
+ ["name"] = "Demon Cloak",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 20,
+ ["mana"] = 10,
+ ["mana_max"] = 40,
+ ["fail"] = 70,
+ ["random"] = 0,
+ ["spell"] = function()
+ return set_tim_reflect(randint(5) + 5 + get_level(DEMON_CLOAK, 15, 0))
+ end,
+ ["info"] = function()
+ return "dur "..(5 + get_level(DEMON_CLOAK, 15, 0)).."+d5"
+ end,
+ ["desc"] = {
+ "Raises a mirror that can reflect bolts and arrows for a time",
+ }
+}
+
+
+-- Demonhorn
+DEMON_SUMMON = add_spell
+{
+ ["name"] = "Summon Demon",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 5,
+ ["mana"] = 10,
+ ["mana_max"] = 50,
+ ["fail"] = 30,
+ ["random"] = 0,
+ ["spell"] = function()
+ local type = SUMMON_DEMON
+ local level = dun_level
+ local minlevel = 4
+ if level < minlevel then level=minlevel end
+ summon_specific_level = 5 + get_level(DEMON_SUMMON, 100)
+ if get_level(DEMON_SUMMON) >= 35 then type = SUMMON_HI_DEMON end
+ if summon_monster(player.py, player.px, level, TRUE, type) == TRUE then
+ return TRUE
+ else
+ msg_print("Something blocks your summoning!")
+ return FALSE
+ end
+ end,
+ ["info"] = function()
+ return "level "..(5 + get_level(DEMON_SUMMON, 100))
+ end,
+ ["desc"] = {
+ "Summons a leveled demon to your side",
+ "At level 35 it summons a high demon",
+ }
+}
+
+DISCHARGE_MINION = add_spell
+{
+ ["name"] = "Discharge Minion",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 10,
+ ["mana"] = 20,
+ ["mana_max"] = 50,
+ ["fail"] = 30,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, x, y, c_ptr
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ c_ptr = cave(y, x)
+
+ -- ok that is a monster
+ if c_ptr.m_idx > 0 then
+ local m_ptr = monster(c_ptr.m_idx)
+ if m_ptr.status ~= MSTATUS_PET then
+ msg_print("You can only target a pet.")
+ return
+ end
+
+ local dam = m_ptr.hp
+ delete_monster_idx(c_ptr.m_idx)
+ dam = (dam * (20 + get_level(DISCHARGE_MINION, 60, 0))) / 100
+ if dam > 100 + get_level(DISCHARGE_MINION, 500, 0) then
+ dam = 100 + get_level(DISCHARGE_MINION, 500, 0)
+ end
+
+ -- We use project instead of fire_ball because we must tell it exactly where to land
+ return project(0, 2,
+ y, x,
+ dam,
+ GF_GRAVITY, bor(PROJECT_STOP, PROJECT_GRID, PROJECT_ITEM, PROJECT_KILL))
+ end
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(DISCHARGE_MINION, 60, 0)).."% max "..(100 + get_level(DISCHARGE_MINION, 500, 0))
+ end,
+ ["desc"] = {
+ "The targeted pet will explode in a burst of gravity",
+ }
+}
+
+CONTROL_DEMON = add_spell
+{
+ ["name"] = "Control Demon",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 25,
+ ["mana"] = 30,
+ ["mana_max"] = 70,
+ ["fail"] = 55,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ return fire_ball(GF_CONTROL_DEMON, dir, 50 + get_level(CONTROL_DEMON, 250), 0)
+ end,
+ ["info"] = function()
+ return "power "..(50 + get_level(CONTROL_DEMON, 250))
+ end,
+ ["desc"] = {
+ "Attempts to control a demon",
+ }
+}
+
+-- ok we need to have different wield slots
+add_hooks
+{
+ [HOOK_WIELD_SLOT] = function (obj, ideal)
+ if (obj.tval == TV_DAEMON_BOOK) then
+ local slot
+ if (obj.sval == SV_DEMONBLADE) then
+ if(ideal == TRUE) then
+ slot = INVEN_WIELD
+ else
+ slot = get_slot(INVEN_WIELD)
+ end
+ elseif (obj.sval == SV_DEMONSHIELD) then
+ if(ideal == TRUE) then
+ slot = INVEN_ARM
+ else
+ slot = get_slot(INVEN_ARM)
+ end
+ elseif (obj.sval == SV_DEMONHORN) then
+ if(ideal == TRUE) then
+ slot = INVEN_HEAD
+ else
+ slot = get_slot(INVEN_HEAD)
+ end
+ end
+ return TRUE, slot
+ end
+ end,
+}
diff --git a/lib/mods/theme/scpt/s_divin.lua b/lib/mods/theme/scpt/s_divin.lua
new file mode 100644
index 00000000..60b0275f
--- /dev/null
+++ b/lib/mods/theme/scpt/s_divin.lua
@@ -0,0 +1,230 @@
+-- Handles thhe divination school
+
+
+STARIDENTIFY = add_spell
+{
+ ["name"] = "Greater Identify",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 35,
+ ["mana"] = 30,
+ ["mana_max"] = 30,
+ ["fail"] = 80,
+ ["spell"] = function()
+ if get_check("Cast on yourself?") == TRUE then
+ self_knowledge()
+ else
+ identify_fully()
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Asks for an object and fully identify it, providing the full list of powers",
+ "Cast at yourself it will reveal your powers"
+ }
+}
+
+IDENTIFY = add_spell
+{
+ ["name"] = "Identify",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 8,
+ ["mana"] = 10,
+ ["mana_max"] = 50,
+ ["fail"] = 40,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 10 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 45,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 15, 40 },
+ },
+ },
+ ["spell"] = function()
+ if get_level(IDENTIFY, 50) >= 27 then
+ local obvious
+ obvious = identify_pack()
+ obvious = is_obvious(fire_ball(GF_IDENTIFY, 0, 1, get_level(IDENTIFY, 3)), obvious)
+ if obvious == TRUE then
+ player.notice = bor(player.notice, PN_COMBINE, PN_REORDER)
+ end
+ return obvious
+ elseif get_level(IDENTIFY, 50) >= 17 then
+ local obvious
+ obvious = identify_pack()
+ obvious = is_obvious(fire_ball(GF_IDENTIFY, 0, 1, 0), obvious)
+ if obvious == TRUE then
+ player.notice = bor(player.notice, PN_COMBINE, PN_REORDER)
+ end
+ return obvious
+ else
+ if ident_spell() == TRUE then return TRUE else return end
+ end
+ end,
+ ["info"] = function()
+ if get_level(IDENTIFY, 50) >= 27 then
+ return "rad "..(get_level(IDENTIFY, 3))
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Asks for an object and identifies it",
+ "At level 17 it identifies all objects in the inventory",
+ "At level 27 it identifies all objects in the inventory and in a",
+ "radius on the floor, as well as probing monsters in that radius"
+ }
+}
+
+VISION = add_spell
+{
+ ["name"] = "Vision",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 15,
+ ["mana"] = 7,
+ ["mana_max"] = 55,
+ ["fail"] = 45,
+ ["stick"] =
+ {
+ ["charge"] = { 4, 6 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 60,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 10, 30 },
+ },
+ },
+ ["inertia"] = { 2, 200 },
+ ["spell"] = function()
+ if get_level(VISION, 50) >= 25 then
+ wiz_lite_extra()
+ else
+ map_area()
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Detects the layout of the surrounding area",
+ "At level 25 it maps and lights the whole level",
+ }
+}
+
+SENSEHIDDEN = add_spell
+{
+ ["name"] = "Sense Hidden",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 5,
+ ["mana"] = 2,
+ ["mana_max"] = 10,
+ ["fail"] = 25,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 15 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 20,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 10, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ local obvious = nil
+ obvious = detect_traps(15 + get_level(SENSEHIDDEN, 40, 0))
+ if get_level(SENSEHIDDEN, 50) >= 15 then
+ obvious = is_obvious(set_tim_invis(10 + randint(20) + get_level(SENSEHIDDEN, 40)), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ if get_level(SENSEHIDDEN, 50) >= 15 then
+ return "rad "..(15 + get_level(SENSEHIDDEN, 40)).." dur "..(10 + get_level(SENSEHIDDEN, 40)).."+d20"
+ else
+ return "rad "..(15 + get_level(SENSEHIDDEN, 40))
+ end
+ end,
+ ["desc"] = {
+ "Detects the traps in a certain radius around you",
+ "At level 15 it allows you to sense invisible for a while"
+ }
+}
+
+REVEALWAYS = add_spell
+{
+ ["name"] = "Reveal Ways",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 9,
+ ["mana"] = 3,
+ ["mana_max"] = 15,
+ ["fail"] = 20,
+ ["stick"] =
+ {
+ ["charge"] = { 6, 6 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 35,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ local obvious
+ obvious = detect_doors(10 + get_level(REVEALWAYS, 40, 0))
+ obvious = is_obvious(detect_stairs(10 + get_level(REVEALWAYS, 40, 0)), obvious)
+ return obvious
+ end,
+ ["info"] = function()
+ return "rad "..(10 + get_level(REVEALWAYS, 40))
+ end,
+ ["desc"] = {
+ "Detects the doors/stairs/ways in a certain radius around you",
+ }
+}
+
+SENSEMONSTERS = add_spell
+{
+ ["name"] = "Sense Monsters",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 20,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 10 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 37,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 15, 40 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ local obvious
+ obvious = detect_monsters_normal(10 + get_level(SENSEMONSTERS, 40, 0))
+ if get_level(SENSEMONSTERS, 50) >= 30 then
+ obvious = is_obvious(set_tim_esp(10 + randint(10) + get_level(SENSEMONSTERS, 20)), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ if get_level(SENSEMONSTERS, 50) >= 30 then
+ return "rad "..(10 + get_level(SENSEMONSTERS, 40)).." dur "..(10 + get_level(SENSEMONSTERS, 20)).."+d10"
+ else
+ return "rad "..(10 + get_level(SENSEMONSTERS, 40))
+ end
+ end,
+ ["desc"] = {
+ "Detects all monsters near you",
+ "At level 30 it allows you to sense monster minds for a while"
+ }
+}
diff --git a/lib/mods/theme/scpt/s_earth.lua b/lib/mods/theme/scpt/s_earth.lua
new file mode 100644
index 00000000..23aa001c
--- /dev/null
+++ b/lib/mods/theme/scpt/s_earth.lua
@@ -0,0 +1,184 @@
+-- The earth school
+
+STONESKIN = add_spell
+{
+ ["name"] = "Stone Skin",
+ ["school"] = SCHOOL_EARTH,
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 50,
+ ["fail"] = 10,
+ ["inertia"] = { 2, 50 },
+ ["spell"] = function()
+ local type
+ if get_level(STONESKIN, 50) >= 25 then
+ type = SHIELD_COUNTER
+ else
+ type = 0
+ end
+ return set_shield(randint(10) + 10 + get_level(STONESKIN, 100), 10 + get_level(STONESKIN, 50), type, 2 + get_level(STONESKIN, 5), 3 + get_level(STONESKIN, 5))
+ end,
+ ["info"] = function()
+ if get_level(STONESKIN, 50) >= 25 then
+ return "dam "..(2 + get_level(STONESKIN, 5)).."d"..(3 + get_level(STONESKIN, 5)).." dur "..(10 + get_level(STONESKIN, 100)).."+d10 AC "..(10 + get_level(STONESKIN, 50))
+ else
+ return "dur "..(10 + get_level(STONESKIN, 100)).."+d10 AC "..(10 + get_level(STONESKIN, 50))
+ end
+ end,
+ ["desc"] = {
+ "Creates a shield of earth around you to protect you",
+ "At level 25 it starts dealing damage to attackers"
+ }
+}
+
+DIG = add_spell
+{
+ ["name"] = "Dig",
+ ["school"] = SCHOOL_EARTH,
+ ["level"] = 12,
+ ["mana"] = 14,
+ ["mana_max"] = 14,
+ ["fail"] = 20,
+ ["stick"] =
+ {
+ ["charge"] = { 15, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 25,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return wall_to_mud(dir)
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Digs a hole in a wall much faster than any shovels",
+ }
+}
+
+STONEPRISON = add_spell
+{
+ ["name"] = "Stone Prison",
+ ["school"] = SCHOOL_EARTH,
+ ["level"] = 25,
+ ["mana"] = 30,
+ ["mana_max"] = 50,
+ ["fail"] = 65,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 3 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 57,
+ ["base_level"] = { 1, 3 },
+ ["max_level"] = { 5, 20 },
+ },
+ },
+ ["spell"] = function()
+ local ret, x, y
+ if get_level(STONEPRISON, 50) >= 10 then
+ ret, x, y = tgt_pt()
+ else
+ y = player.py
+ x = player.px
+ end
+ wall_stone(y, x)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Creates a prison of walls around you",
+ "At level 10 it allows you to target a monster"
+ }
+}
+
+STRIKE = add_spell
+{
+ ["name"] = "Strike",
+ ["school"] = {SCHOOL_EARTH},
+ ["level"] = 30,
+ ["mana"] = 30,
+ ["mana_max"] = 50,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 6 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 635,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 10, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir, rad
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ if get_level(STRIKE, 50) >= 12 then
+ return fire_ball(GF_FORCE, dir, 50 + get_level(STRIKE, 50), 1)
+ else
+ return fire_ball(GF_FORCE, dir, 50 + get_level(STRIKE, 50), 0)
+ end
+ end,
+ ["info"] = function()
+ if get_level(STRIKE, 50) >= 12 then
+ return "dam "..(50 + get_level(STRIKE, 50)).." rad 1"
+ else
+ return "dam "..(50 + get_level(STRIKE, 50))
+ end
+ end,
+ ["desc"] = {
+ "Creates a micro-ball of force that will push monsters backwards",
+ "If the monster is caught near a wall, it'll be crushed against it",
+ "At level 12 it turns into a ball of radius 1"
+ }
+}
+
+SHAKE = add_spell
+{
+ ["name"] = "Shake",
+ ["school"] = {SCHOOL_EARTH},
+ ["level"] = 27,
+ ["mana"] = 25,
+ ["mana_max"] = 30,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 10 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 75,
+ ["base_level"] = { 1, 3 },
+ ["max_level"] = { 9, 20 },
+ },
+ },
+ ["inertia"] = { 2, 50 },
+ ["spell"] = function()
+ local ret, x, y
+ if get_level(SHAKE, 50) >= 10 then
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ else
+ x = player.px
+ y = player.py
+ end
+ earthquake(y, x, 4 + get_level(SHAKE, 10));
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(4 + get_level(SHAKE, 10))
+ end,
+ ["desc"] = {
+ "Creates a localised earthquake",
+ "At level 10 it can be targeted at any location"
+ }
+}
diff --git a/lib/mods/theme/scpt/s_eru.lua b/lib/mods/theme/scpt/s_eru.lua
new file mode 100644
index 00000000..c0cb0aaf
--- /dev/null
+++ b/lib/mods/theme/scpt/s_eru.lua
@@ -0,0 +1,130 @@
+-- Handle Eru Iluvatar magic school
+
+ERU_SEE = add_spell
+{
+ ["name"] = "See the Music",
+ ["school"] = {SCHOOL_ERU},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 50,
+ ["fail"] = 20,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local obvious
+ obvious = set_tim_invis(randint(20) + 10 + get_level(ERU_SEE, 100))
+ if get_level(ERU_SEE) >= 30 then
+ wiz_lite_extra()
+ obvious = TRUE
+ elseif get_level(ERU_SEE) >= 10 then
+ map_area()
+ obvious = TRUE
+ end
+ if get_level(ERU_SEE) >= 20 then
+ obvious = is_obvious(set_blind(0), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(ERU_SEE, 100)).."+d20"
+ end,
+ ["desc"] = {
+ "Allows you to 'see' the Great Music from which the world",
+ "originates, allowing you to see unseen things",
+ "At level 10 it allows you to see your surroundings",
+ "At level 20 it allows you to cure blindness",
+ "At level 30 it allows you to fully see all the level"
+ }
+}
+
+ERU_LISTEN = add_spell
+{
+ ["name"] = "Listen to the Music",
+ ["school"] = {SCHOOL_ERU},
+ ["level"] = 7,
+ ["mana"] = 15,
+ ["mana_max"] = 200,
+ ["fail"] = 25,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ if get_level(ERU_LISTEN) >= 30 then
+ ident_all()
+ identify_pack()
+ return TRUE
+ elseif get_level(ERU_LISTEN) >= 14 then
+ identify_pack()
+ return TRUE
+ else
+ return ident_spell()
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Allows you to listen to the Great Music from which the world",
+ "originates, allowing you to understand the meaning of things",
+ "At level 14 it allows you to identify all your pack",
+ "At level 30 it allows you to identify all items on the level",
+ }
+}
+
+ERU_UNDERSTAND = add_spell
+{
+ ["name"] = "Know the Music",
+ ["school"] = {SCHOOL_ERU},
+ ["level"] = 30,
+ ["mana"] = 200,
+ ["mana_max"] = 600,
+ ["fail"] = 50,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ if get_level(ERU_UNDERSTAND) >= 10 then
+ identify_pack_fully()
+ return TRUE
+ else
+ return identify_fully()
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Allows you to understand the Great Music from which the world",
+ "originates, allowing you to know the full abilities of things",
+ "At level 10 it allows you to *identify* all your pack",
+ }
+}
+
+ERU_PROT = add_spell
+{
+ ["name"] = "Lay of Protection",
+ ["school"] = {SCHOOL_ERU},
+ ["level"] = 35,
+ ["mana"] = 400,
+ ["mana_max"] = 400,
+ ["fail"] = 80,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return fire_ball(GF_MAKE_GLYPH, 0, 1, 1 + get_level(ERU_PROT, 2, 0))
+ end,
+ ["info"] = function()
+ return "rad "..(1 + get_level(ERU_PROT, 2, 0))
+ end,
+ ["desc"] = {
+ "Creates a circle of safety around you",
+ }
+}
diff --git a/lib/mods/theme/scpt/s_fire.lua b/lib/mods/theme/scpt/s_fire.lua
new file mode 100644
index 00000000..dbbf7604
--- /dev/null
+++ b/lib/mods/theme/scpt/s_fire.lua
@@ -0,0 +1,227 @@
+-- handle the fire school
+
+GLOBELIGHT = add_spell
+{
+ ["name"] = "Globe of Light",
+ ["school"] = {SCHOOL_FIRE},
+ ["level"] = 1,
+ ["mana"] = 2,
+ ["mana_max"] = 15,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 7,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 10, 45 },
+ },
+ },
+ ["inertia"] = { 1, 40 },
+ ["spell"] = function()
+ local obvious
+ if get_level(GLOBELIGHT, 50) >= 3 then
+ obvious = lite_area(10, 4)
+ else
+ lite_room(player.py, player.px)
+ obvious = TRUE
+ end
+ if get_level(GLOBELIGHT, 50) >= 15 then
+ obvious = is_obvious(fire_ball(GF_LITE, 0, 10 + get_level(GLOBELIGHT, 100), 5 + get_level(GLOBELIGHT, 6)), obvious)
+ player.update = bor(player.update, PU_VIEW)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ if get_level(GLOBELIGHT, 50) >= 15 then
+ return "dam "..(10 + get_level(GLOBELIGHT, 100)).." rad "..(5 + get_level(GLOBELIGHT, 6))
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Creates a globe of pure light",
+ "At level 3 it starts damaging monsters",
+ "At level 15 it starts creating a more powerful kind of light",
+ }
+}
+
+FIREFLASH = add_spell
+{
+ ["name"] = "Fireflash",
+ ["school"] = {SCHOOL_FIRE},
+ ["level"] = 10,
+ ["mana"] = 5,
+ ["mana_max"] = 70,
+ ["fail"] = 35,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 35,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 15, 35 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir, type
+ if (get_level(FIREFLASH, 50) >= 20) then
+ type = GF_HOLY_FIRE
+ else
+ type = GF_FIRE
+ end
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(type, dir, 20 + get_level(FIREFLASH, 500), 2 + get_level(FIREFLASH, 5))
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(FIREFLASH, 500)).." rad "..(2 + get_level(FIREFLASH, 5))
+ end,
+ ["desc"] = {
+ "Conjures a ball of fire to burn your foes to ashes",
+ "At level 20 it turns into a ball of holy fire"
+ }
+}
+
+FIERYAURA = add_spell
+{
+ ["name"] = "Fiery Shield",
+ ["school"] = {SCHOOL_FIRE},
+ ["level"] = 20,
+ ["mana"] = 20,
+ ["mana_max"] = 60,
+ ["fail"] = 50,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 50,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 5, 40 },
+ },
+ },
+ ["inertia"] = { 2, 15 },
+ ["spell"] = function()
+ local type
+ if (get_level(FIERYAURA, 50) >= 8) then
+ type = SHIELD_GREAT_FIRE
+ else
+ type = SHIELD_FIRE
+ end
+ return set_shield(randint(20) + 10 + get_level(FIERYAURA, 70), 10, type, 5 + get_level(FIERYAURA, 10), 5 + get_level(FIERYAURA, 7))
+ end,
+ ["info"] = function()
+ return "dam "..(5 + get_level(FIERYAURA, 15)).."d"..(5 + get_level(FIERYAURA, 7)).." dur "..(10 + get_level(FIERYAURA, 70)).."+d20"
+ end,
+ ["desc"] = {
+ "Creates a shield of fierce flames around you",
+ "At level 8 it turns into a greater kind of flame that can not be resisted"
+ }
+}
+
+FIREWALL = add_spell
+{
+ ["name"] = "Firewall",
+ ["school"] = {SCHOOL_FIRE},
+ ["level"] = 15,
+ ["mana"] = 25,
+ ["mana_max"] = 100,
+ ["fail"] = 40,
+ ["stick"] =
+ {
+ ["charge"] = { 4, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 55,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 5, 40 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir, type
+ if (get_level(FIREWALL, 50) >= 6) then
+ type = GF_HELL_FIRE
+ else
+ type = GF_FIRE
+ end
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ fire_wall(type, dir, 40 + get_level(FIREWALL, 150), 10 + get_level(FIREWALL, 14))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(40 + get_level(FIREWALL, 150)).." dur "..(10 + get_level(FIREWALL, 14))
+ end,
+ ["desc"] = {
+ "Creates a fiery wall to incinerate monsters stupid enough to attack you",
+ "At level 6 it turns into a wall of hell fire"
+ }
+}
+
+FIREGOLEM = add_spell
+{
+ ["name"] = "Fire Golem",
+ ["school"] = {SCHOOL_FIRE, SCHOOL_MIND},
+ ["level"] = 7,
+ ["mana"] = 16,
+ ["mana_max"] = 70,
+ ["fail"] = 40,
+ ["spell"] = function()
+ local m_idx, y, x, ret, item
+
+ -- Can we reconnect ?
+ if do_control_reconnect() == TRUE then
+ msg_print("Control re-established.")
+ return
+ end
+
+ ret, item = get_item("Which light source do you want to use to create the golem?",
+ "You have no light source for the golem",
+ bor(USE_INVEN, USE_EQUIP),
+ function (obj)
+ if (obj.tval == TV_LITE) and ((obj.sval == SV_LITE_TORCH) or (obj.sval == SV_LITE_LANTERN)) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+ if ret == FALSE then return TRUE end
+ inven_item_increase(item, -1)
+ inven_item_describe(item)
+ inven_item_optimize(item)
+
+ -- Summon it
+ m_allow_special[1043 + 1] = TRUE
+ y, x = find_position(player.py, player.px)
+ m_idx = place_monster_one(y, x, 1043, 0, FALSE, MSTATUS_FRIEND)
+ m_allow_special[1043 + 1] = FALSE
+
+ -- level it
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 7 + get_level(FIREGOLEM, 70))
+ player.control = m_idx
+ monster(m_idx).mflag = bor(monster(m_idx).mflag, MFLAG_CONTROL)
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return "golem level "..(7 + get_level(FIREGOLEM, 70))
+ end,
+ ["desc"] = {
+ "Creates a fiery golem and controls it",
+ "During the control the available keylist is:",
+ "Movement keys: movement of the golem(depending on its speed",
+ " it can move more than one square)",
+ ", : pickup all items on the floor",
+ "d : drop all carried items",
+ "i : list all carried items",
+ "m : end the possession/use golem powers",
+ "Most of the other keys are disabled, you cannot interact with your",
+ "real body while controlling the golem",
+ "But to cast the spell you will need a lantern or a wooden torch to",
+ "Create the golem from"
+ }
+}
diff --git a/lib/mods/theme/scpt/s_geom.lua b/lib/mods/theme/scpt/s_geom.lua
new file mode 100644
index 00000000..b9730318
--- /dev/null
+++ b/lib/mods/theme/scpt/s_geom.lua
@@ -0,0 +1,656 @@
+-- Geomancy school
+
+function geomancy_random_wall(y, x)
+ local c_ptr = cave(y, x)
+
+ -- Do not destroy permanent things
+ if cave_is(c_ptr, FF1_PERMANENT) ~= FALSE then return end
+
+ local feat = nil
+ local table =
+ {
+ [1] = { SKILL_FIRE, FEAT_SANDWALL, 1},
+
+ [2] = { SKILL_WATER, FEAT_TREES, 1},
+ [3] = { SKILL_WATER, FEAT_ICE_WALL, 12},
+
+ [4] = { SKILL_EARTH, FEAT_WALL_EXTRA, 1},
+ }
+
+ while feat == nil do
+ local t = table[randint(getn(table))]
+
+ -- Do we meet the requirements ?
+ -- And then select the features based on skill proportions
+ if get_skill(t[1]) >= t[3] and magik(get_skill_scale(t[1], 100)) == TRUE then
+ feat = t[2]
+ end
+ end
+
+ cave_set_feat(y, x, feat)
+end
+
+
+GF_ELEMENTAL_WALL = add_spell_type
+{
+ ["color"] = { TERM_GREEN, 0 },
+ ["angry"] = function() return TRUE, FALSE end,
+ ["grid"] = function(who, dam, rad, y, x)
+ if player.py ~= y or player.px ~= x then
+ geomancy_random_wall(y, x)
+ end
+ end,
+}
+
+function geomancy_random_floor(y, x, kill_wall)
+ local c_ptr = cave(y, x)
+
+ -- Do not destroy permanent things
+ if cave_is(c_ptr, FF1_PERMANENT) ~= FALSE then return end
+ if not kill_wall then
+ if cave_is(c_ptr, FF1_FLOOR) ~= TRUE then return end
+ end
+
+ local feat = nil
+ local table =
+ {
+ [1] = { SKILL_FIRE, FEAT_SAND, 1},
+ [2] = { SKILL_FIRE, FEAT_SHAL_LAVA, 8},
+ [3] = { SKILL_FIRE, FEAT_DEEP_LAVA, 18},
+
+ [4] = { SKILL_WATER, FEAT_SHAL_WATER, 1},
+ [5] = { SKILL_WATER, FEAT_DEEP_WATER, 8},
+ [6] = { SKILL_WATER, FEAT_ICE, 18},
+
+ [7] = { SKILL_EARTH, FEAT_GRASS, 1},
+ [8] = { SKILL_EARTH, FEAT_FLOWER, 8},
+ [9] = { SKILL_EARTH, FEAT_DARK_PIT, 18},
+ }
+
+ while feat == nil do
+ local t = table[randint(getn(table))]
+
+ -- Do we meet the requirements ?
+ -- And then select the features based on skill proportions
+ if get_skill(t[1]) >= t[3] and magik(get_skill_scale(t[1], 100)) == TRUE then
+ feat = t[2]
+ end
+ end
+
+ cave_set_feat(y, x, feat)
+end
+
+
+GF_ELEMENTAL_GROWTH = add_spell_type
+{
+ ["color"] = { TERM_GREEN, 0 },
+ ["angry"] = function() return TRUE, FALSE end,
+ ["grid"] = function(who, dam, rad, y, x)
+ geomancy_random_floor(y, x)
+ end,
+}
+
+CALL_THE_ELEMENTS = add_spell
+{
+ ["name"] = "Call the Elements",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 1,
+ ["mana"] = 2,
+ ["mana_max"] = 20,
+ ["fail"] = 10,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir = 0, 0
+
+ if get_level(CALL_THE_ELEMENTS) >= 17 then
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ end
+
+ fire_ball(GF_ELEMENTAL_GROWTH, dir, 1, 1 + get_level(CALL_THE_ELEMENTS, 5, 0))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(1 + get_level(CALL_THE_ELEMENTS, 5, 0))
+ end,
+ ["desc"] = {
+ "Randomly creates various elements around you",
+ "Each type of element chance is controlled by your level",
+ "in the corresponding skill",
+ "At level 17 it can be targeted",
+ }
+}
+
+-- Seperate function because an other spell needs it
+function channel_the_elements(y, x, level, silent)
+ local t =
+ {
+ -- Earth stuff
+ [FEAT_GRASS] = function()
+ hp_player(player.mhp * (5 + get_skill_scale(SKILL_EARTH, 20)) / 100)
+ end,
+ [FEAT_FLOWER] = function()
+ hp_player(player.mhp * (5 + get_skill_scale(SKILL_EARTH, 30)) / 100)
+ end,
+ [FEAT_DARK_PIT] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ local type = GF_DARK
+ if get_skill(SKILL_EARTH) >= 18 then type = GF_NETHER end
+ fire_bolt(type, dir, damroll(10, get_skill(SKILL_EARTH)))
+ end,
+
+ -- Water stuff
+ [FEAT_SHAL_WATER] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ local type = GF_WATER
+ if get_skill(SKILL_WATER) >= 18 then type = GF_WAVE end
+
+ if get_skill(SKILL_WATER) >= 8 then
+ fire_beam(type, dir, damroll(3, get_skill(SKILL_WATER)))
+ else
+ fire_bolt(type, dir, damroll(3, get_skill(SKILL_WATER)))
+ end
+ end,
+ [FEAT_DEEP_WATER] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ local type = GF_WATER
+ if get_skill(SKILL_WATER) >= 18 then type = GF_WAVE end
+
+ if get_skill(SKILL_WATER) >= 8 then
+ fire_beam(type, dir, damroll(5, get_skill(SKILL_WATER)))
+ else
+ fire_bolt(type, dir, damroll(5, get_skill(SKILL_WATER)))
+ end
+ end,
+ [FEAT_ICE] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if get_skill(SKILL_WATER) >= 12 then
+ fire_ball(GF_ICE, dir, get_skill_scale(SKILL_WATER, 340), 3)
+ else
+ fire_bolt(GF_ICE, dir, damroll(3, get_skill(SKILL_WATER)))
+ end
+ end,
+
+ -- Fire stuff
+ [FEAT_SAND] = function()
+ local type
+ if (get_level(FIERYAURA, 50) >= 8) then
+ type = SHIELD_GREAT_FIRE
+ else
+ type = SHIELD_FIRE
+ end
+ local dur = randint(20) + %level + get_skill(SKILL_AIR)
+ set_shield(dur, 0, type, 5 + get_skill_scale(SKILL_FIRE, 20), 5 + get_skill_scale(SKILL_FIRE, 14))
+ set_blind(dur)
+ end,
+ [FEAT_SHAL_LAVA] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if get_skill(SKILL_FIRE) >= 15 then
+ fire_bolt(GF_HELL_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15))
+ else
+ fire_bolt(GF_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15))
+ end
+ end,
+ [FEAT_DEEP_LAVA] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if get_skill(SKILL_FIRE) >= 15 then
+ fire_ball(GF_HELL_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15), 3)
+ else
+ fire_ball(GF_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15), 3)
+ end
+ end,
+ }
+
+ if t[cave(y, x).feat] then
+ t[cave(y, x).feat]()
+
+ if magik(100 - level) == TRUE then
+ if cave(y, x).feat == FEAT_FLOWER then
+ cave_set_feat(y, x, FEAT_GRASS)
+ else
+ cave_set_feat(y, x, FEAT_FLOOR)
+ end
+ msg_print("The area is drained.")
+ end
+ elseif not silent then
+ msg_print("You cannot channel this area.")
+ end
+end
+
+CHANNEL_ELEMENTS = add_spell
+{
+ ["name"] = "Channel Elements",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 3,
+ ["mana"] = 3,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ ["spell"] = function()
+ channel_the_elements(player.py, player.px, get_level(CHANNEL_ELEMENTS), nil)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Draws on the caster's immediate environs to form an attack or other effect.",
+ "Grass/Flower heals.",
+ "Water creates water bolt attacks.",
+ "Ice creates ice bolt attacks.",
+ "Sand creates a wall of thick, blinding, burning sand around you.",
+ "Lava creates fire bolt attacks.",
+ "Deep lava creates fire ball attacks.",
+ "Chasm creates darkness bolt attacks.",
+ "At Earth level 18, darkness becomes nether.",
+ "At Water level 8, water attacks become beams with a striking effect.",
+ "At Water level 12, ice attacks become balls of ice shards.",
+ "At Water level 18, water attacks push monsters back.",
+ "At Fire level 15, fire become hellfire.",
+ }
+}
+
+ELEMENTAL_WAVE = add_spell
+{
+ ["name"] = "Elemental Wave",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 15,
+ ["mana"] = 15,
+ ["mana_max"] = 50,
+ ["fail"] = 20,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+
+ local y, x = explode_dir(dir)
+ y = y + player.py
+ x = x + player.px
+
+ local t =
+ {
+ -- Earth stuff
+ [FEAT_GRASS] = { GF_POIS, GF_POIS, 10 + get_skill_scale(SKILL_EARTH, 200) },
+ [FEAT_FLOWER] = { GF_POIS, GF_POIS, 10 + get_skill_scale(SKILL_EARTH, 300) },
+ -- cannot turn chasm into a wave
+
+ -- Water stuff
+ [FEAT_SHAL_WATER] = { GF_WATER, GF_WATER, 10 + get_skill_scale(SKILL_WATER, 200) },
+ [FEAT_DEEP_WATER] = { GF_WATER, GF_WATER, 10 + get_skill_scale(SKILL_WATER, 300) },
+ [FEAT_ICE] = { GF_ICE, GF_ICE, 10 + get_skill_scale(SKILL_WATER, 200) },
+
+ -- Fire stuff
+ [FEAT_SAND] = { GF_LITE, GF_LITE, 10 + get_skill_scale(SKILL_FIRE, 400) },
+ [FEAT_SHAL_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 10 + get_skill_scale(SKILL_FIRE, 200) },
+ [FEAT_DEEP_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 10 + get_skill_scale(SKILL_FIRE, 300) },
+ }
+
+
+ local effect = t[cave(y, x).feat]
+ if not effect then
+ msg_print("You cannot channel this area.")
+ else
+ local typ = effect[1]
+ if get_level(ELEMENTAL_WAVE) >= 20 then typ = effect[2] end
+
+ cave_set_feat(y, x, FEAT_FLOOR)
+
+ fire_wave(typ, 0, effect[3], 0, 6 + get_level(ELEMENTAL_WAVE, 20), EFF_WAVE + EFF_LAST + getglobal("EFF_DIR"..dir))
+ end
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Draws on an adjacent special square to project a slow-moving",
+ "wave of that element in that direction",
+ "Abyss squares cannot be channeled into a wave.",
+ }
+}
+
+VAPORIZE = add_spell
+{
+ ["name"] = "Vaporize",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 4,
+ ["mana"] = 3,
+ ["mana_max"] = 30,
+ ["fail"] = 15,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ -- Must have at least 4 Air
+ ["random"] = 0,
+ ["depend"] = function()
+ if get_skill(SKILL_AIR) >= 4 then return TRUE end
+ end,
+ ["spell"] = function()
+ local t =
+ {
+ -- Earth stuff
+ [FEAT_GRASS] = { GF_POIS, GF_POIS, 5 + get_skill_scale(SKILL_EARTH, 100) },
+ [FEAT_FLOWER] = { GF_POIS, GF_POIS, 5 + get_skill_scale(SKILL_EARTH, 150) },
+ [FEAT_DARK_PIT] = { GF_DARK, GF_DARK, 5 + get_skill_scale(SKILL_EARTH, 200) },
+
+ -- Water stuff
+ [FEAT_SHAL_WATER] = { GF_WATER, GF_WATER, 5 + get_skill_scale(SKILL_WATER, 100) },
+ [FEAT_DEEP_WATER] = { GF_WATER, GF_WATER, 5 + get_skill_scale(SKILL_WATER, 150) },
+ [FEAT_ICE] = { GF_ICE, GF_ICE, 5 + get_skill_scale(SKILL_WATER, 100) },
+
+ -- Fire stuff
+ [FEAT_SAND] = { GF_LITE, GF_LITE, 5 + get_skill_scale(SKILL_FIRE, 200) },
+ [FEAT_SHAL_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 5 + get_skill_scale(SKILL_FIRE, 100) },
+ [FEAT_DEEP_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 5 + get_skill_scale(SKILL_FIRE, 150) },
+ }
+
+ local effect = t[cave(player.py, player.px).feat]
+ if not effect then
+ msg_print("You cannot channel this area.")
+ else
+ local typ = effect[1]
+ if get_level(VAPORIZE) >= 20 then typ = effect[2] end
+
+ cave_set_feat(player.py, player.px, FEAT_FLOOR)
+
+ fire_cloud(typ, 0, effect[3], 1 + get_level(VAPORIZE, 4), 10 + get_level(VAPORIZE, 20))
+ end
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(1 + get_level(VAPORIZE, 4)).." dur "..(10 + get_level(VAPORIZE, 20))
+ end,
+ ["desc"] = {
+ "Draws upon your immediate environs to form a cloud of damaging vapors",
+ }
+}
+
+geomancy_can_tunnel =
+{
+ [FEAT_WALL_EXTRA] = TRUE,
+ [FEAT_WALL_OUTER] = TRUE,
+ [FEAT_WALL_INNER] = TRUE,
+ [FEAT_WALL_SOLID] = TRUE,
+
+ [FEAT_MAGMA] = TRUE,
+ [FEAT_QUARTZ] = TRUE,
+ [FEAT_MAGMA_H] = TRUE,
+ [FEAT_QUARTZ_H] = TRUE,
+ [FEAT_MAGMA_K] = TRUE,
+ [FEAT_QUARTZ_K] = TRUE,
+
+ [FEAT_TREES] = TRUE,
+ [FEAT_DEAD_TREE] = TRUE,
+
+ [FEAT_SANDWALL] = TRUE,
+ [FEAT_SANDWALL_H] = TRUE,
+ [FEAT_SANDWALL_K] = TRUE,
+
+ [FEAT_ICE_WALL] = TRUE,
+}
+
+-- Dig & sprew
+function geomancy_dig(oy, ox, dir, length)
+ local dy, dx = explode_dir(dir)
+ local y = dy + oy
+ local x = dx + ox
+
+ for i = 1, length do
+ local c_ptr = cave(y, x)
+ local ox = x - dx
+ local oy = y - dy
+
+ -- stop at the end of tunnelable things
+ if not geomancy_can_tunnel[c_ptr.feat] then break end
+
+ if geomancy_can_tunnel[cave(y - 1, x - 1).feat] then geomancy_random_wall(y - 1, x - 1) end
+ if geomancy_can_tunnel[cave(y - 1, x).feat] then geomancy_random_wall(y - 1, x) end
+ if geomancy_can_tunnel[cave(y - 1, x + 1).feat] then geomancy_random_wall(y - 1, x + 1) end
+
+ if geomancy_can_tunnel[cave(y, x - 1).feat] then geomancy_random_wall(y, x - 1) end
+ if geomancy_can_tunnel[cave(y, x + 1).feat] then geomancy_random_wall(y, x + 1) end
+
+ if geomancy_can_tunnel[cave(y + 1, x - 1).feat] then geomancy_random_wall(y + 1, x - 1) end
+ if geomancy_can_tunnel[cave(y + 1, x).feat] then geomancy_random_wall(y + 1, x) end
+ if geomancy_can_tunnel[cave(y + 1, x + 1).feat] then geomancy_random_wall(y + 1, x + 1) end
+
+ y = y + dy
+ x = x + dx
+ end
+
+ y = y - dy
+ x = x - dx
+ while (y ~= oy) or (x ~= ox) do
+ geomancy_random_floor(y, x, TRUE)
+
+ -- Should we branch ?
+ if magik(20) == TRUE then
+ local rot = 1
+ if magik(50) == TRUE then rot = -1 end
+ geomancy_dig(y, x, rotate_dir(dir, rot), length / 3)
+ end
+
+ y = y - dy
+ x = x - dx
+ end
+end
+
+GEOLYSIS = add_spell
+{
+ ["name"] = "Geolysis",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 7,
+ ["mana"] = 15,
+ ["mana_max"] = 40,
+ ["fail"] = 15,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ -- Must have at least 7 Earth
+ ["depend"] = function()
+ if get_skill(SKILL_EARTH) >= 7 then return TRUE end
+ end,
+ ["spell"] = function()
+ local ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+
+ msg_print("Elements recombine before you, laying down an open path.")
+ geomancy_dig(player.py, player.px, dir, 5 + get_level(GEOLYSIS, 12))
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return "length "..(5 + get_level(GEOLYSIS, 12))
+ end,
+ ["desc"] = {
+ "Burrows deeply and slightly at random into a wall,",
+ "leaving behind tailings of various different sorts of walls in the passage.",
+ }
+}
+
+player.dripping_tread = 0
+add_loadsave("player.dripping_tread", 0)
+add_hooks
+{
+ [HOOK_MOVED] = function(oy, ox)
+ if player.dripping_tread > 0 then
+ geomancy_random_floor(oy, ox)
+ player.dripping_tread = player.dripping_tread - 1
+ if player.dripping_tread == 0 then
+ msg_print("You stop dripping raw elemental energies.")
+ end
+ end
+ end
+}
+DRIPPING_TREAD = add_spell
+{
+ ["name"] = "Dripping Tread",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 10,
+ ["mana"] = 15,
+ ["mana_max"] = 25,
+ ["fail"] = 15,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ -- Must have at least 10 Water
+ ["depend"] = function()
+ if get_skill(SKILL_WATER) >= 10 then return TRUE end
+ end,
+ ["spell"] = function()
+ if player.dripping_tread == 0 then
+ player.dripping_tread = randint(15) + 10 + get_level(DRIPPING_TREAD)
+ msg_print("You start dripping raw elemental energies.")
+ else
+ player.dripping_tread = 0
+ msg_print("You stop dripping raw elemental energies.")
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(DRIPPING_TREAD)).."+d15 movs"
+ end,
+ ["desc"] = {
+ "Causes you to leave random elemental forms behind as you walk",
+ }
+}
+
+GROW_BARRIER = add_spell
+{
+ ["name"] = "Grow Barrier",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 12,
+ ["mana"] = 30,
+ ["mana_max"] = 40,
+ ["fail"] = 15,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ -- Must have at least 12 Earth
+ ["depend"] = function()
+ if get_skill(SKILL_EARTH) >= 12 then return TRUE end
+ end,
+ ["spell"] = function()
+ local ret, dir = 0, 0
+
+ if get_level(GROW_BARRIER) >= 20 then
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ end
+
+ fire_ball(GF_ELEMENTAL_WALL, dir, 1, 1)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Creates impassable terrain (walls, trees, etc.) around you.",
+ "At level 20 it can be projected around another area.",
+ }
+}
+
+ELEMENTAL_MINION = add_spell
+{
+ ["name"] = "Elemental Minion",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 20,
+ ["mana"] = 40,
+ ["mana_max"] = 80,
+ ["fail"] = 25,
+ -- Unnafected by blindness
+ ["random"] = 0,
+ -- Must have at least 12 Earth
+ ["spell"] = function()
+ local ret, dir = 0, 0
+
+ ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+
+ local t =
+ {
+ [FEAT_WALL_EXTRA] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_WALL_OUTER] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_WALL_INNER] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_WALL_SOLID] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_MAGMA] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_QUARTZ] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_MAGMA_H] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_QUARTZ_H] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_MAGMA_K] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_QUARTZ_K] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+
+ [FEAT_DARK_PIT] = { SKILL_AIR, { "Air elemental", "Ancient blue dragon", "Great Storm Wyrm", "Sky Drake" } },
+
+ [FEAT_SANDWALL] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+ [FEAT_SANDWALL_H] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+ [FEAT_SANDWALL_K] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+ [FEAT_SHAL_LAVA] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+ [FEAT_DEEP_LAVA] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+
+ [FEAT_ICE_WALL] = { SKILL_WATER, { "Water elemental", "Water troll", "Water demon" } },
+ [FEAT_SHAL_WATER] = { SKILL_WATER, { "Water elemental", "Water troll", "Water demon" } },
+ [FEAT_DEEP_WATER] = { SKILL_WATER, { "Water elemental", "Water troll", "Water demon" } },
+ }
+
+ local y, x = explode_dir(dir)
+ y = y + player.py
+ x = x + player.px
+
+ local effect = t[cave(y, x).feat]
+ if not effect then
+ msg_print("You cannot summon from this area.")
+ else
+ local skill = effect[1]
+ local types = effect[2]
+
+ local max = get_skill_scale(skill, getn(types))
+ if max == 0 then max = 1 end
+
+ local r_idx = test_monster_name(types[rand_range(1, max)])
+
+ -- Summon it
+ local my, mx = find_position(y, x)
+ local m_idx = place_monster_one(my, mx, r_idx, 0, FALSE, MSTATUS_FRIEND)
+
+ -- level it
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 10 + get_level(ELEMENTAL_MINION, 120))
+ end
+
+ cave_set_feat(y, x, FEAT_FLOOR)
+ end
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return "min level "..(10 + get_level(ELEMENTAL_MINION, 120))
+ end,
+ ["desc"] = {
+ "Summons a minion from a nearby element.",
+ "Walls can summon Earth elmentals, Xorns and Xarens",
+ "Dark Pits can summon Air elementals, Ancient blue dragons, Great Storm Wyrms",
+ "and Sky Drakes",
+ "Sandwalls and lava can summon Fire elementals and Ancient red dragons",
+ "Icewall, and water can summon Water elementals, Water trolls and Water demons",
+ }
+}
diff --git a/lib/mods/theme/scpt/s_mana.lua b/lib/mods/theme/scpt/s_mana.lua
new file mode 100644
index 00000000..736b06b0
--- /dev/null
+++ b/lib/mods/theme/scpt/s_mana.lua
@@ -0,0 +1,132 @@
+-- The mana school
+
+function get_manathrust_dam()
+ return 3 + get_level(MANATHRUST, 50), 1 + get_level(MANATHRUST, 20)
+end
+
+MANATHRUST = add_spell
+{
+ ["name"] = "Manathrust",
+ ["school"] = SCHOOL_MANA,
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 25,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 10 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 5,
+ ["base_level"] = { 1, 20 },
+ ["max_level"] = { 15, 33 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt(GF_MANA, dir, damroll(get_manathrust_dam()))
+ end,
+ ["info"] = function()
+ local x, y
+
+ x, y = get_manathrust_dam()
+ return "dam "..x.."d"..y
+ end,
+ ["desc"] = {
+ "Conjures up mana into a powerful bolt",
+ "The damage is irresistible and will increase with level"
+ }
+}
+
+DELCURSES = add_spell
+{
+ ["name"] = "Remove Curses",
+ ["school"] = SCHOOL_MANA,
+ ["level"] = 10,
+ ["mana"] = 20,
+ ["mana_max"] = 40,
+ ["fail"] = 30,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 8 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 70,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 15, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ local done
+
+ if get_level(DELCURSES, 50) >= 20 then done = remove_all_curse()
+ else done = remove_curse() end
+ if done == TRUE then msg_print("The curse is broken!") end
+ return done
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Remove curses of worn objects",
+ "At level 20 switches to *remove curses*"
+ }
+}
+
+RESISTS = add_spell
+{
+ ["name"] = "Elemental Shield",
+ ["school"] = SCHOOL_MANA,
+ ["level"] = 20,
+ ["mana"] = 17,
+ ["mana_max"] = 20,
+ ["fail"] = 40,
+ ["inertia"] = { 2, 25 },
+ ["spell"] = function()
+ local obvious
+ if player.oppose_fire == 0 then obvious = set_oppose_fire(randint(10) + 15 + get_level(RESISTS, 50)) end
+ if player.oppose_cold == 0 then obvious = is_obvious(set_oppose_cold(randint(10) + 15 + get_level(RESISTS, 50)), obvious) end
+ if player.oppose_elec == 0 then obvious = is_obvious(set_oppose_elec(randint(10) + 15 + get_level(RESISTS, 50)), obvious) end
+ if player.oppose_acid == 0 then obvious = is_obvious(set_oppose_acid(randint(10) + 15 + get_level(RESISTS, 50)), obvious) end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(15 + get_level(RESISTS, 50)).."+d10"
+ end,
+ ["desc"] = {
+ "Provide resistances to the four basic elements",
+ }
+}
+
+MANASHIELD = add_spell
+{
+ ["name"] = "Disruption Shield",
+ ["school"] = SCHOOL_MANA,
+ ["level"] = 45,
+ ["mana"] = 50,
+ ["mana_max"] = 50,
+ ["fail"] = 90,
+ ["inertia"] = { 9, 10},
+ ["spell"] = function()
+ if get_level(MANASHIELD, 50) >= 5 then
+ if (player.invuln == 0) then
+ return set_invuln(randint(5) + 3 + get_level(MANASHIELD, 10))
+ end
+ else
+ if (player.disrupt_shield == 0) then return set_disrupt_shield(randint(5) + 3 + get_level(MANASHIELD, 10)) end
+ end
+ end,
+ ["info"] = function()
+ return "dur "..(3 + get_level(MANASHIELD, 10)).."+d5"
+ end,
+ ["desc"] = {
+ "Uses mana instead of hp to take damage",
+ "At level 5 switches to Globe of Invulnerability.",
+ "The spell breaks as soon as a melee, shooting, throwing or magical",
+ "skill action is attempted, and lasts only a short time."
+ }
+}
diff --git a/lib/mods/theme/scpt/s_mandos.lua b/lib/mods/theme/scpt/s_mandos.lua
new file mode 100644
index 00000000..cc7e346a
--- /dev/null
+++ b/lib/mods/theme/scpt/s_mandos.lua
@@ -0,0 +1,186 @@
+-- Spells for the school of Mandos
+
+BOOK_MANDOS = 66
+
+-- precognition timer for high-level spell [from T-Plus by Ingeborg S. Norden]
+
+add_loadsave("tim_precognition",0)
+
+function set_precognition(v)
+ local notice = FALSE
+ if (v < 0) then v = 0 end
+ if (v > 10000) then v = 10000 end
+
+ -- Check if the state will change
+ if (v > 0) and (tim_precognition == 0) then
+ msg_print("You feel able to predict the future.")
+ notice = TRUE
+ elseif (v == 0) and (tim_precognition > 0) then
+ msg_print("You feel less able to predict the future.")
+ notice = TRUE
+ end
+
+ -- set the new value
+ tim_precognition = v
+
+ if (notice == TRUE) then
+ player.update = bor(player.update, PU_BONUS)
+ disturb(0,0)
+ end
+ return notice
+end
+
+-- related hooks
+
+add_hooks{
+ [HOOK_CALC_BONUS] = function()
+ if (tim_precognition > 0) then
+ --player.precognition = TRUE
+ apply_flags(0, 0, 0, TR4_PRECOGNITION, 0, 0, 0, 0, 0, 0, 0)
+ end
+ end,
+
+ [HOOK_PROCESS_WORLD] = function()
+ if (tim_precognition > 0) then
+ set_precognition(tim_precognition - 1)
+ end
+ end,
+}
+
+-- "Tears of Luthien" based on Holy Word from T-Plus
+MANDOS_TEARS_LUTHIEN = add_spell
+{
+ ["name"] = "Tears of Luthien",
+ ["school"] = {SCHOOL_MANDOS},
+ ["level"] = 5,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 25,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local level = get_level(MANDOS_TEARS_LUTHIEN, 30)
+ local obvious = hp_player(10 * level)
+ obvious = is_obvious (set_stun(0), obvious)
+ obvious = is_obvious (set_cut(0), obvious)
+ obvious = is_obvious (set_afraid(0), obvious)
+ return obvious
+ end,
+ ["info"] = function()
+ local level = get_level(MANDOS_TEARS_LUTHIEN, 30)
+ return "heals "..(10 * level)
+ end,
+ ["desc"] = {
+ "Calls upon the spirit of Luthien to ask Mandos for healing and succour."
+ }
+}
+
+-- "Spirit of the Feanturi" based on Restore Mind from T-Plus
+MANDOS_SPIRIT_FEANTURI = add_spell {
+ ["name"] = "Feanturi",
+ ["school"] = {SCHOOL_MANDOS},
+ ["level"] = 10,
+ ["mana"] = 40,
+ ["mana_max"] = 200,
+ ["fail"] = 50,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local level = get_level(MANDOS_SPIRIT_FEANTURI, 50)
+ local obvious
+ obvious = set_afraid(0)
+ obvious = is_obvious(set_confused(0), obvious)
+
+ if level >= 20 then
+ obvious = is_obvious(do_res_stat(A_WIS, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_INT, TRUE), obvious)
+ end
+
+ if level >= 30 then
+ obvious = is_obvious(set_image(0), obvious)
+ obvious = is_obvious(heal_insanity(player.msane * level / 100), obvious)
+ end
+
+ return obvious
+ end,
+
+ ["info"] = function()
+ local level = get_level(MANDOS_SPIRIT_FEANTURI, 50)
+ if level >= 20 then
+ return "heals "..level.."%"
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Channels the power of Mandos to cure fear and confusion.",
+ "At level 20 it restores lost INT and WIS",
+ "At level 30 it cures hallucinations and restores a percentage of lost sanity"
+ }
+}
+
+-- "Tale of Doom" based on Foretell from T-Plus
+MANDOS_TALE_DOOM = add_spell
+{
+ ["name"] = "Tale of Doom",
+ ["school"] = {SCHOOL_MANDOS},
+ ["level"] = 25,
+ ["mana"] = 60,
+ ["mana_max"] = 300,
+ ["stat"] = A_WIS,
+ ["fail"] = 75,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return set_precognition(5 + get_level(MANDOS_TALE_DOOM,10))
+ end,
+ ["info"] = function()
+ return "dur "..(5 + get_level(MANDOS_TALE_DOOM,10))
+ end,
+ ["desc"] = {
+ "Allows you to predict the future for a short time."
+ }
+}
+
+-- "Call to the Halls" based on Call Blessed Soul from T-Plus
+MANDOS_CALL_HALLS= add_spell
+
+{
+ ["name"] = "Call to the Halls",
+ ["school"] = {SCHOOL_MANDOS},
+ ["level"] = 30,
+ ["mana"] = 80,
+ ["mana_max"] = 400,
+ ["fail"] = 95,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local y, x, m_idx
+ local summons =
+ {
+ test_monster_name("Experienced spirit"),
+ test_monster_name("Wise spirit"),
+ }
+ y, x = find_position(player.py, player.px)
+ m_idx = place_monster_one(y, x, summons[rand_range(1, 2)], 0, FALSE, MSTATUS_FRIEND)
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 20 + get_level(MANDOS_CALL_HALLS, 70, 0))
+ return TRUE
+ end
+ end,
+
+ ["info"] = function()
+ return "level "..(get_level(MANDOS_CALL_HALLS, 70))
+ end,
+ ["desc"] = {
+ "Summons a leveled spirit from the Halls of Mandos",
+ "to fight for you."
+
+ }
+} \ No newline at end of file
diff --git a/lib/mods/theme/scpt/s_manwe.lua b/lib/mods/theme/scpt/s_manwe.lua
new file mode 100644
index 00000000..6f0f9661
--- /dev/null
+++ b/lib/mods/theme/scpt/s_manwe.lua
@@ -0,0 +1,144 @@
+-- Handle Manwe Sulimo magic school
+
+MANWE_SHIELD = add_spell
+{
+ ["name"] = "Wind Shield",
+ ["school"] = {SCHOOL_MANWE},
+ ["level"] = 10,
+ ["mana"] = 100,
+ ["mana_max"] = 500,
+ ["fail"] = 30,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local dur = get_level(MANWE_SHIELD, 50) + 10 + randint(20)
+ local obvious
+
+ obvious = set_protevil(dur)
+ if get_level(MANWE_SHIELD) >= 10 then
+ local type
+
+ type = 0
+ if get_level(MANWE_SHIELD) >= 20 then
+ type = SHIELD_COUNTER
+ end
+ obvious = is_obvious(set_shield(dur, get_level(MANWE_SHIELD, 30), type, 1 + get_level(MANWE_SHIELD, 2), 1 + get_level(MANWE_SHIELD, 6)), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ local desc = "dur "..(get_level(MANWE_SHIELD, 50) + 10).."+d20"
+
+ if get_level(MANWE_SHIELD) >= 10 then
+ desc = desc.." AC "..(get_level(MANWE_SHIELD, 30))
+ end
+ if get_level(MANWE_SHIELD) >= 20 then
+ desc = desc.." dam "..(1 + get_level(MANWE_SHIELD, 2)).."d"..(1 + get_level(MANWE_SHIELD, 6))
+ end
+ return desc
+ end,
+ ["desc"] = {
+ "It surrounds you with a shield of wind that deflects blows from evil monsters",
+ "At level 10 it increases your armour rating",
+ "At level 20 it retaliates against monsters that melee you",
+ }
+}
+
+MANWE_AVATAR = add_spell
+{
+ ["name"] = "Avatar",
+ ["school"] = {SCHOOL_MANWE},
+ ["level"] = 35,
+ ["mana"] = 1000,
+ ["mana_max"] = 1000,
+ ["fail"] = 80,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return set_mimic(get_level(MANWE_AVATAR, 20) + randint(10), resolve_mimic_name("Maia"), player.lev)
+ end,
+ ["info"] = function()
+ return "dur "..(get_level(MANWE_AVATAR, 20)).."+d10"
+ end,
+ ["desc"] = {
+ "It turns you into a full grown Maia",
+ }
+}
+
+MANWE_BLESS = add_spell
+{
+ ["name"] = "Manwe's Blessing",
+ ["school"] = {SCHOOL_MANWE},
+ ["level"] = 1,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 20,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local dur = get_level(MANWE_BLESS, 70) + 30 + randint(40)
+ local obvious
+
+ obvious = set_blessed(dur)
+ obvious = is_obvious(set_afraid(0), obvious)
+ obvious = is_obvious(set_lite(0), obvious)
+ if get_level(MANWE_BLESS) >= 10 then
+ obvious = is_obvious(set_hero(dur), obvious)
+ end
+ if get_level(MANWE_BLESS) >= 20 then
+ obvious = is_obvious(set_shero(dur), obvious)
+ end
+ if get_level(MANWE_BLESS) >= 30 then
+ obvious = is_obvious(set_holy(dur), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(get_level(MANWE_BLESS, 70) + 30).."+d40"
+ end,
+ ["desc"] = {
+ "Manwe's Blessing removes your fears, blesses you and surrounds you with",
+ "holy light",
+ "At level 10 it also grants heroism",
+ "At level 20 it also grants super heroism",
+ "At level 30 it also grants holy luck and life protection",
+ }
+}
+
+MANWE_CALL = add_spell
+{
+ ["name"] = "Manwe's Call",
+ ["school"] = {SCHOOL_MANWE},
+ ["level"] = 20,
+ ["mana"] = 200,
+ ["mana_max"] = 500,
+ ["fail"] = 40,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local y, x, m_idx
+
+ y, x = find_position(player.py, player.px)
+ m_idx = place_monster_one(y, x, test_monster_name("Great eagle"), 0, FALSE, MSTATUS_FRIEND)
+
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 20 + get_level(MANWE_CALL, 70, 0))
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return "level "..(get_level(MANWE_CALL, 70) + 20)
+ end,
+ ["desc"] = {
+ "Manwe's Call summons a Great Eagle to help you battle the forces",
+ "of Morgoth"
+ }
+}
diff --git a/lib/mods/theme/scpt/s_melkor.lua b/lib/mods/theme/scpt/s_melkor.lua
new file mode 100644
index 00000000..b2c693dd
--- /dev/null
+++ b/lib/mods/theme/scpt/s_melkor.lua
@@ -0,0 +1,154 @@
+-- handle the melkor school
+
+-- Not included in the spell code directly because I need to call it from somewhere else too
+function do_melkor_curse(who)
+ local m_ptr = monster(who)
+
+ if get_level(MELKOR_CURSE) >= 35 then
+ local r_ptr = race_info_idx(m_ptr.r_idx, m_ptr.ego)
+
+ m_ptr.maxhp = m_ptr.maxhp - r_ptr.hside;
+ if m_ptr.maxhp < 1 then m_ptr.maxhp = 1 end
+ if m_ptr.hp > m_ptr.maxhp then m_ptr.hp = m_ptr.maxhp end
+ player.redraw = bor(player.redraw, PR_HEALTH)
+ end
+ if get_level(MELKOR_CURSE) >= 25 then
+ m_ptr.speed = m_ptr.speed - get_level(MELKOR_CURSE, 7)
+ m_ptr.mspeed = m_ptr.mspeed - get_level(MELKOR_CURSE, 7)
+
+ if m_ptr.speed < 70 then m_ptr.speed = 70 end
+ if m_ptr.mspeed < 70 then m_ptr.mspeed = 70 end
+ end
+ if get_level(MELKOR_CURSE) >= 15 then
+ m_ptr.ac = m_ptr.ac - get_level(MELKOR_CURSE, 50)
+
+ if m_ptr.ac < -70 then m_ptr.ac = -70 end
+ end
+
+ local i, pow
+ i = 1
+ pow = get_level(MELKOR_CURSE, 2)
+ while (i <= 4) do
+ if m_ptr.blow[i].d_dice > 0 then
+ if m_ptr.blow[i].d_dice < pow then
+ pow = m_ptr.blow[i].d_dice
+ end
+ if m_ptr.blow[i].d_side < pow then
+ pow = m_ptr.blow[i].d_side
+ end
+ m_ptr.blow[i].d_dice = m_ptr.blow[i].d_dice - pow
+ end
+ i = i + 1
+ end
+
+ local m_name = monster_desc(m_ptr, 0).." looks weaker."
+ msg_print(strupper(strsub(m_name, 0, 1))..strsub(m_name, 2))
+
+ -- wake it
+ m_ptr.csleep = 0;
+end
+
+MELKOR_CURSE = add_spell
+{
+ ["name"] = "Curse",
+ ["school"] = {SCHOOL_MELKOR},
+ ["level"] = 1,
+ ["mana"] = 50,
+ ["mana_max"] = 300,
+ ["fail"] = 20,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if target_who == -1 then
+ msg_print("You must target a monster.")
+ else
+ do_melkor_curse(target_who)
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "It curses a monster, reducing its melee power",
+ "At level 5 it can be auto-casted (with no piety cost) while fighting",
+ "At level 15 it also reduces armor",
+ "At level 25 it also reduces speed",
+ "At level 35 it also reduces max life (but it is never fatal)",
+ }
+}
+
+MELKOR_CORPSE_EXPLOSION = add_spell
+{
+ ["name"] = "Corpse Explosion",
+ ["school"] = {SCHOOL_MELKOR},
+ ["level"] = 10,
+ ["mana"] = 100,
+ ["mana_max"] = 500,
+ ["fail"] = 45,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return fire_ball(GF_CORPSE_EXPL, 0, 20 + get_level(MELKOR_CORPSE_EXPLOSION, 70), 2 + get_level(MELKOR_CORPSE_EXPLOSION, 5))
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(MELKOR_CORPSE_EXPLOSION, 70)).."%"
+ end,
+ ["desc"] = {
+ "It makes corpses in an area around you explode for a percent of their",
+ "hit points as damage",
+ }
+}
+
+MELKOR_MIND_STEAL = add_spell
+{
+ ["name"] = "Mind Steal",
+ ["school"] = {SCHOOL_MELKOR},
+ ["level"] = 20,
+ ["mana"] = 1000,
+ ["mana_max"] = 3000,
+ ["fail"] = 90,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if target_who == -1 then
+ msg_print("You must target a monster.")
+ else
+ local chance, m_ptr, r_ptr
+
+ m_ptr = monster(target_who)
+ r_ptr = race_info_idx(m_ptr.r_idx, m_ptr.ego)
+ chance = get_level(MELKOR_MIND_STEAL)
+ if (randint(m_ptr.level) < chance) and (band(r_ptr.flags1, RF1_UNIQUE) == 0) then
+ player.control = target_who
+ m_ptr.mflag = bor(m_ptr.mflag, MFLAG_CONTROL)
+
+ local m_name = monster_desc(m_ptr, 0).." falls under your control."
+ msg_print(strupper(strsub(m_name, 0, 1))..strsub(m_name, 2))
+ else
+ local m_name = monster_desc(m_ptr, 0).." resists."
+ msg_print(strupper(strsub(m_name, 0, 1))..strsub(m_name, 2))
+ end
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return "chance 1d(mlvl)<"..(get_level(MELKOR_MIND_STEAL))
+ end,
+ ["desc"] = {
+ "It allows your spirit to temporarily leave your own body, which will",
+ "be vulnerable, to control one of your enemies body."
+ }
+}
diff --git a/lib/mods/theme/scpt/s_meta.lua b/lib/mods/theme/scpt/s_meta.lua
new file mode 100644
index 00000000..eab691d8
--- /dev/null
+++ b/lib/mods/theme/scpt/s_meta.lua
@@ -0,0 +1,287 @@
+-- handle the meta school
+
+RECHARGE = add_spell
+{
+ ["name"] = "Recharge",
+ ["school"] = {SCHOOL_META},
+ ["level"] = 5,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 20,
+ ["spell"] = function()
+ return recharge(60 + get_level(RECHARGE, 140))
+ end,
+ ["info"] = function()
+ return "power "..(60 + get_level(RECHARGE, 140))
+ end,
+ ["desc"] = {
+ "Taps on the ambient mana to recharge an object's power (charges or mana)",
+ }
+}
+
+function get_spellbinder_max()
+ local i
+
+ i = get_level(SPELLBINDER, 4)
+ if i > 4 then i = 4 end
+ return i
+end
+--'
+SPELLBINDER = add_spell
+{
+ ["name"] = "Spellbinder",
+ ["school"] = {SCHOOL_META},
+ ["level"] = 20,
+ ["mana"] = 100,
+ ["mana_max"] = 300,
+ ["fail"] = 85,
+ ["spell"] = function()
+ local i, ret, c
+
+ if player.spellbinder_num ~= 0 then
+ local t =
+ {
+ [SPELLBINDER_HP75] = "75% HP",
+ [SPELLBINDER_HP50] = "50% HP",
+ [SPELLBINDER_HP25] = "25% HP",
+ }
+ msg_print("The spellbinder is already active.")
+ msg_print("It will trigger at "..t[player.spellbinder_trigger]..".")
+ msg_print("With the spells: ")
+ for i = 1, player.spellbinder_num do
+ msg_print(spell(player.spellbinder[i]).name)
+ end
+ return TRUE
+ end
+
+ ret, c = get_com("Trigger at [a]75% hp [b]50% hp [c]25% hp?", strbyte("a"))
+ if ret == FALSE then return TRUE end
+
+ if c == strbyte("a") then
+ player.spellbinder_trigger = SPELLBINDER_HP75
+ elseif c == strbyte("b") then
+ player.spellbinder_trigger = SPELLBINDER_HP50
+ elseif c == strbyte("c") then
+ player.spellbinder_trigger = SPELLBINDER_HP25
+ else
+ return
+ end
+ player.spellbinder_num = get_spellbinder_max()
+ i = player.spellbinder_num
+ while i > 0 do
+ local s
+
+ s = get_school_spell("bind", "is_ok_spell", 0)
+ if s == -1 then
+ player.spellbinder_trigger = 0
+ player.spellbinder_num = 0
+ return TRUE
+ else
+ if spell(s).skill_level > 7 + get_level(SPELLBINDER, 35) then
+ msg_print("You are only allowed spells with a base level of "..(7 + get_level(SPELLBINDER, 35))..".");
+ return TRUE
+ end
+ end
+ player.spellbinder[i] = s
+ i = i - 1
+ end
+ player.energy = player.energy - 3100;
+ msg_print("Spellbinder ready.")
+ return TRUE
+ end,
+ ["info"] = function()
+ return "number "..(get_spellbinder_max()).." max level "..(7 + get_level(SPELLBINDER, 35))
+ end,
+ ["desc"] = {
+ "Stores spells in a trigger.",
+ "When the condition is met all spells fire off at the same time",
+ "This spell takes a long time to cast so you are advised to prepare it",
+ "in a safe area.",
+ "Also it will use the mana for the Spellbinder and the mana for the",
+ "selected spells"
+ }
+}
+
+DISPERSEMAGIC = add_spell
+{
+ ["name"] = "Disperse Magic",
+ ["school"] = {SCHOOL_META},
+ ["level"] = 15,
+ ["mana"] = 30,
+ ["mana_max"] = 60,
+ ["fail"] = 40,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ -- Unnafected by confusion
+ ["confusion"] = FALSE,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 25,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 5, 40 },
+ },
+ },
+ ["inertia"] = { 1, 5 },
+ ["spell"] = function()
+ local obvious
+ obvious = set_blind(0)
+ obvious = is_obvious(set_lite(0), obvious)
+ if get_level(DISPERSEMAGIC, 50) >= 5 then
+ obvious = is_obvious(set_confused(0), obvious)
+ obvious = is_obvious(set_image(0), obvious)
+ end
+ if get_level(DISPERSEMAGIC, 50) >= 10 then
+ obvious = is_obvious(set_slow(0), obvious)
+ obvious = is_obvious(set_fast(0, 0), obvious)
+ obvious = is_obvious(set_light_speed(0), obvious)
+ end
+ if get_level(DISPERSEMAGIC, 50) >= 15 then
+ obvious = is_obvious(set_stun(0), obvious)
+ obvious = is_obvious(set_meditation(0), obvious)
+ obvious = is_obvious(set_cut(0), obvious)
+ end
+ if get_level(DISPERSEMAGIC, 50) >= 20 then
+ obvious = is_obvious(set_hero(0), obvious)
+ obvious = is_obvious(set_shero(0), obvious)
+ obvious = is_obvious(set_blessed(0), obvious)
+ obvious = is_obvious(set_shield(0, 0, 0, 0, 0), obvious)
+ obvious = is_obvious(set_afraid(0), obvious)
+ obvious = is_obvious(set_parasite(0, 0), obvious)
+ obvious = is_obvious(set_mimic(0, 0, 0), obvious)
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Dispels a lot of magic that can affect you, be it good or bad",
+ "Level 1: blindness and light",
+ "Level 5: confusion and hallucination",
+ "Level 10: speed (both bad or good) and light speed",
+ "Level 15: stunning, meditation, cuts",
+ "Level 20: hero, super hero, bless, shields, afraid, parasites, mimicry",
+ }
+}
+
+TRACKER = add_spell
+{
+ ["name"] = "Tracker",
+ ["school"] = {SCHOOL_META, SCHOOL_CONVEYANCE},
+ ["level"] = 30,
+ ["mana"] = 50,
+ ["mana_max"] = 50,
+ ["fail"] = 95,
+ ["spell"] = function()
+ if last_teleportation_y == -1 then
+ msg_print("There has not been any teleporatation here.")
+ return TRUE
+ end
+ teleport_player_to(last_teleportation_y, last_teleportation_x)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Tracks down the last teleportation that happened on the level and teleports",
+ "you to it",
+ }
+}
+
+-- Saves the values of the timer
+save_timer("TIMER_INERTIA_CONTROL")
+add_loadsave("player.inertia_controlled_spell", -1)
+player.inertia_controlled_spell = -1
+
+-- Automatically cast the inertia controlled spells
+TIMER_INERTIA_CONTROL = new_timer
+{
+ ["enabled"] = FALSE,
+ ["delay"] = 10,
+ ["callback"] = function()
+ -- Don't cast a controlled spell in wilderness mode
+ if player.antimagic then
+ msg_print("Your anti-magic field disrupts any magic attempts.")
+ elseif player.anti_magic then
+ msg_print("Your anti-magic shell disrupts any magic attempts.")
+ elseif (player.inertia_controlled_spell ~= -1) and (player.wild_mode == FALSE) then
+ __spell_spell[player.inertia_controlled_spell]()
+ end
+ end,
+}
+
+stop_inertia_controlled_spell = function()
+ player.inertia_controlled_spell = -1
+ TIMER_INERTIA_CONTROL.enabled = FALSE
+ player.update = bor(player.update, PU_MANA)
+ return TRUE
+end
+
+add_hooks
+{
+ -- Reduce the mana by four times the cost of the spell
+ [HOOK_CALC_MANA] = function(msp)
+ if player.inertia_controlled_spell ~= -1 then
+ msp = msp - (get_mana(player.inertia_controlled_spell) * 4)
+ if msp < 0 then msp = 0 end
+ return TRUE, msp
+ end
+ end,
+
+ -- Stop a previous spell at birth
+ [HOOK_BIRTH_OBJECTS] = function()
+ stop_inertia_controlled_spell()
+ end,
+}
+
+INERTIA_CONTROL = add_spell
+{
+ ["name"] = "Inertia Control",
+ ["school"] = {SCHOOL_META},
+ ["level"] = 37,
+ ["mana"] = 300,
+ ["mana_max"] = 700,
+ ["fail"] = 95,
+ ["spell"] = function()
+ if player.inertia_controlled_spell ~= -1 then
+ msg_print("You cancel your inertia flow control.")
+ return stop_inertia_controlled_spell()
+ end
+
+ local s = get_school_spell("control", "is_ok_spell", 0)
+ if s == -1 then
+ return stop_inertia_controlled_spell()
+ end
+
+ local inertia = __tmp_spells[s].inertia
+
+ if inertia == nil then
+ msg_print("This spell inertia flow can not be controlled.")
+ return stop_inertia_controlled_spell()
+ end
+ if inertia[1] > get_level(INERTIA_CONTROL, 10) then
+ msg_print("This spell inertia flow("..inertia[1]..") is too strong to be controlled by your current spell.")
+ return stop_inertia_controlled_spell()
+ end
+
+ player.inertia_controlled_spell = s
+ TIMER_INERTIA_CONTROL.enabled = TRUE
+ TIMER_INERTIA_CONTROL.delay = inertia[2]
+ TIMER_INERTIA_CONTROL.countdown = TIMER_INERTIA_CONTROL.delay
+ player.update = bor(player.update, PU_MANA)
+ msg_print("Inertia flow controlling spell "..spell(s).name..".")
+ return TRUE
+ end,
+ ["info"] = function()
+ return "level "..get_level(INERTIA_CONTROL, 10)
+ end,
+ ["desc"] = {
+ "Changes the energy flow of a spell to be continuously recasted",
+ "at a given interval. The inertia controlled spell reduces your",
+ "maximum mana by four times its cost.",
+ }
+}
diff --git a/lib/mods/theme/scpt/s_mind.lua b/lib/mods/theme/scpt/s_mind.lua
new file mode 100644
index 00000000..d1b25e9e
--- /dev/null
+++ b/lib/mods/theme/scpt/s_mind.lua
@@ -0,0 +1,132 @@
+-- handle the mind school
+
+CHARM = add_spell
+{
+ ["name"] = "Charm",
+ ["school"] = {SCHOOL_MIND},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 20,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 35,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 20, 40 },
+ },
+ },
+ ["spell"] = function()
+ if get_level(CHARM, 50) >= 35 then
+ return project_los(GF_CHARM, 10 + get_level(CHARM, 150))
+ elseif get_level(CHARM, 50) >= 15 then
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_CHARM, dir, 10 + get_level(CHARM, 150), 3)
+ else
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt(GF_CHARM, dir, 10 + get_level(CHARM, 150))
+ end
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(CHARM, 150))
+ end,
+ ["desc"] = {
+ "Tries to manipulate the mind of a monster to make it friendly",
+ "At level 15 it turns into a ball",
+ "At level 35 it affects all monsters in sight"
+ }
+}
+
+CONFUSE = add_spell
+{
+ ["name"] = "Confuse",
+ ["school"] = {SCHOOL_MIND},
+ ["level"] = 5,
+ ["mana"] = 5,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 4 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 45,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 20, 40 },
+ },
+ },
+ ["spell"] = function()
+ if get_level(CONFUSE, 50) >= 35 then
+ return project_los(GF_OLD_CONF, 10 + get_level(CONFUSE, 150))
+ elseif get_level(CONFUSE, 50) >= 15 then
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_OLD_CONF, dir, 10 + get_level(CONFUSE, 150), 3)
+ else
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt(GF_OLD_CONF, dir, 10 + get_level(CONFUSE, 150))
+ end
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(CONFUSE, 150))
+ end,
+ ["desc"] = {
+ "Tries to manipulate the mind of a monster to confuse it",
+ "At level 15 it turns into a ball",
+ "At level 35 it affects all monsters in sight"
+ }
+}
+
+ARMOROFFEAR = add_spell
+{
+ ["name"] = "Armor of Fear",
+ ["school"] = SCHOOL_MIND,
+ ["level"] = 10,
+ ["mana"] = 10,
+ ["mana_max"] = 50,
+ ["fail"] = 35,
+ ["inertia"] = { 2, 20 },
+ ["spell"] = function()
+ return set_shield(randint(10) + 10 + get_level(ARMOROFFEAR, 100), 10, SHIELD_FEAR, 1 + get_level(ARMOROFFEAR, 7), 5 + get_level(ARMOROFFEAR, 20))
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(ARMOROFFEAR, 100)).." power "..(1 + get_level(ARMOROFFEAR, 7)).."d"..(5 + get_level(ARMOROFFEAR, 20))
+ end,
+ ["desc"] = {
+ "Creates a shield of pure fear around you. Any monster attempting to hit you",
+ "must save or flee",
+ }
+}
+
+STUN = add_spell
+{
+ ["name"] = "Stun",
+ ["school"] = {SCHOOL_MIND},
+ ["level"] = 15,
+ ["mana"] = 10,
+ ["mana_max"] = 90,
+ ["fail"] = 45,
+ ["spell"] = function()
+ if get_level(STUN, 50) >= 20 then
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_STUN, dir, 10 + get_level(STUN, 150), 3)
+ else
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt(GF_STUN, dir, 10 + get_level(STUN, 150))
+ end
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(STUN, 150))
+ end,
+ ["desc"] = {
+ "Tries to manipulate the mind of a monster to stun it",
+ "At level 20 it turns into a ball",
+ }
+}
diff --git a/lib/mods/theme/scpt/s_music.lua b/lib/mods/theme/scpt/s_music.lua
new file mode 100644
index 00000000..9da6393a
--- /dev/null
+++ b/lib/mods/theme/scpt/s_music.lua
@@ -0,0 +1,443 @@
+-- handle the music school
+-- *ALL* lasting spell must return the mana cost in the lasting function
+
+MUSIC_STOP = add_spell
+{
+ ["name"] = "Stop singing(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = -400,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["blind"] = FALSE,
+ ["spell"] = function()
+ player.start_lasting_spell(0)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Stops the current song, if any."
+ }
+}
+
+--- Drums
+MUSIC_HOLD = add_spell
+{
+ ["name"] = "Holding Pattern(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 10,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["blind"] = FALSE,
+ ["lasting"] = function()
+ project_los(GF_OLD_SLOW, 10 + get_level(MUSIC_HOLD, 100))
+ return get_mana(MUSIC_HOLD)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_HOLD)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(MUSIC_HOLD, 100))
+ end,
+ ["desc"] = {
+ "Slows down all monsters listening the song.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_CONF = add_spell
+{
+ ["name"] = "Illusion Pattern(II)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 5,
+ ["mana"] = 2,
+ ["mana_max"] = 15,
+ ["fail"] = 30,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 2,
+ ["blind"] = FALSE,
+ ["lasting"] = function()
+ project_los(GF_OLD_CONF, 10 + get_level(MUSIC_CONF, 100))
+ return get_mana(MUSIC_CONF)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_CONF)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(MUSIC_CONF, 100))
+ end,
+ ["desc"] = {
+ "Tries to confuse all monsters listening the song.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_STUN = add_spell
+{
+ ["name"] = "Stun Pattern(IV)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 10,
+ ["mana"] = 3,
+ ["mana_max"] = 25,
+ ["fail"] = 45,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 4,
+ ["blind"] = FALSE,
+ ["lasting"] = function()
+ project_los(GF_STUN, 10 + get_level(MUSIC_STUN, 90))
+ return get_mana(MUSIC_STUN)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_STUN)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(MUSIC_STUN, 90))
+ end,
+ ["desc"] = {
+ "Stuns all monsters listening the song.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+--- Harps
+MUSIC_LITE = add_spell
+{
+ ["name"] = "Song of the Sun(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 1,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["blind"] = FALSE,
+ ["pval"] = 1,
+ ["lasting"] = function()
+ set_lite(5)
+ return 1
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_LITE)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Provides light as long as you sing.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_HEAL = add_spell
+{
+ ["name"] = "Flow of Life(II)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 7,
+ ["mana"] = 5,
+ ["mana_max"] = 30,
+ ["fail"] = 35,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 2,
+ ["lasting"] = function()
+ hp_player(7 + get_level(MUSIC_HEAL, 100))
+ return get_mana(MUSIC_HEAL)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_HEAL)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "heal "..(7 + get_level(MUSIC_HEAL, 100)).."/turn"
+ end,
+ ["desc"] = {
+ "Heals you as long as you sing.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_HERO = add_spell
+{
+ ["name"] = "Heroic Ballad(II)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 10,
+ ["mana"] = 4,
+ ["mana_max"] = 14,
+ ["fail"] = 45,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 2,
+ ["lasting"] = function()
+ set_hero(5)
+ if get_level(MUSIC_HERO) >= 10 then
+ set_shero(5)
+ end
+ if get_level(MUSIC_HERO) >= 20 then
+ set_strike(5)
+ end
+ if get_level(MUSIC_HERO) >= 25 then
+ set_oppose_cc(5)
+ end
+ return get_mana(MUSIC_HERO)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_HERO)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Increases melee accuracy",
+ "At level 10 it increases it even more and reduces armour a bit",
+ "At level 20 it increases it again",
+ "At level 25 it grants protection against chaos and confusion",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_TIME = add_spell
+{
+ ["name"] = "Hobbit Melodies(III)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 20,
+ ["mana"] = 10,
+ ["mana_max"] = 30,
+ ["fail"] = 70,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 3,
+ ["lasting"] = function()
+ set_shield(5, 10 + get_level(MUSIC_TIME, 50), 0, 0, 0)
+ if get_level(MUSIC_TIME) >= 15 then
+ set_fast(5, 7 + get_level(MUSIC_TIME, 10))
+ end
+ return get_mana(MUSIC_TIME)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_TIME)
+ return TRUE
+ end,
+ ["info"] = function()
+ if get_level(MUSIC_TIME) >= 15 then
+ return "AC "..(10 + get_level(MUSIC_TIME, 50)).." speed "..(7 + get_level(MUSIC_TIME, 10))
+ else
+ return "AC "..(10 + get_level(MUSIC_TIME, 50))
+ end
+ end,
+ ["desc"] = {
+ "Greatly increases your reflexes allowing you to block more melee blows.",
+ "At level 15 it also makes you faster.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_MIND = add_spell
+{
+ ["name"] = "Clairaudience(IV)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 25,
+ ["mana"] = 15,
+ ["mana_max"] = 30,
+ ["fail"] = 75,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 4,
+ ["lasting"] = function()
+ set_tim_esp(5)
+ if get_level(MUSIC_MIND) >= 10 then
+ fire_ball(GF_IDENTIFY, 0, 1, 1 + get_level(MUSIC_MIND, 3, 0))
+ end
+ return get_mana(MUSIC_MIND)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_MIND)
+ return TRUE
+ end,
+ ["info"] = function()
+ if get_level(MUSIC_MIND) >= 10 then
+ return "rad "..(1 + get_level(MUSIC_MIND, 3, 0))
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Allows you to sense monster minds as long as you sing.",
+ "At level 10 it identifies all objects in a radius on the floor,",
+ "as well as probing monsters in that radius.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+--- Horns
+
+MUSIC_BLOW = add_spell
+{
+ ["name"] = "Blow(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 4,
+ ["mana"] = 3,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["spell"] = function()
+ fire_ball(GF_SOUND,
+ 0,
+ damroll(2 + get_level(MUSIC_BLOW, 10, 0), 4 + get_level(MUSIC_BLOW, 40, 0)),
+ 1 + get_level(MUSIC_BLOW, 12, 0)
+ )
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(2 + get_level(MUSIC_BLOW, 10, 0)).."d"..(4 + get_level(MUSIC_BLOW, 40, 0)).." rad "..(1 + get_level(MUSIC_BLOW, 12, 0))
+ end,
+ ["desc"] = {
+ "Produces a powerful, blowing, sound all around you.",
+ }
+}
+
+MUSIC_WIND = add_spell
+{
+ ["name"] = "Gush of Wind(II)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 14,
+ ["mana"] = 15,
+ ["mana_max"] = 45,
+ ["fail"] = 30,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 2,
+ ["spell"] = function()
+ fire_ball(GF_AWAY_ALL,
+ 0,
+ 10 + get_level(MUSIC_BLOW, 40, 0),
+ 1 + get_level(MUSIC_BLOW, 12, 0)
+ )
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dist "..(10 + get_level(MUSIC_BLOW, 40, 0)).." rad "..(1 + get_level(MUSIC_BLOW, 12, 0))
+ end,
+ ["desc"] = {
+ "Produces a outgoing gush of wind that sends monsters away.",
+ }
+}
+
+MUSIC_YLMIR = add_spell
+{
+ ["name"] = "Horns of Ylmir(III)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 20,
+ ["mana"] = 25,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 3,
+ ["spell"] = function()
+ earthquake(player.py, player.px, 2 + get_level(SHAKE, 10))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(2 + get_level(SHAKE, 10))
+ end,
+ ["desc"] = {
+ "Produces an earth shaking sound.",
+ }
+}
+
+MUSIC_AMBARKANTA = add_spell
+{
+ ["name"] = "Ambarkanta(IV)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 25,
+ ["mana"] = 70,
+ ["mana_max"] = 70,
+ ["fail"] = 60,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 4,
+ ["spell"] = function()
+ alter_reality()
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Produces a reality shaking sound that transports you to a nearly",
+ "identical reality.",
+ }
+}
+
+
+--[[
+MUSIC_ = add_spell
+{
+ ["name"] = "(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["lasting"] = function()
+ return get_mana(MUSIC_)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+or
+
+MUSIC_ = add_spell
+{
+ ["name"] = "(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["spell"] = function()
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "",
+ }
+}
+]]
diff --git a/lib/mods/theme/scpt/s_nature.lua b/lib/mods/theme/scpt/s_nature.lua
new file mode 100644
index 00000000..3d44c569
--- /dev/null
+++ b/lib/mods/theme/scpt/s_nature.lua
@@ -0,0 +1,184 @@
+-- handle the nature school
+
+GROWTREE = add_spell
+{
+ ["name"] = "Grow Trees",
+ ["school"] = {SCHOOL_NATURE, SCHOOL_TEMPORAL},
+ ["level"] = 6,
+ ["mana"] = 6,
+ ["mana_max"] = 30,
+ ["fail"] = 35,
+ ["inertia"] = { 5, 50 },
+ ["spell"] = function()
+ grow_trees(2 + get_level(GROWTREE, 7))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(2 + get_level(GROWTREE, 7))
+ end,
+ ["desc"] = {
+ "Makes trees grow extremely quickly around you",
+ }
+}
+
+HEALING = add_spell
+{
+ ["name"] = "Healing",
+ ["school"] = {SCHOOL_NATURE},
+ ["level"] = 10,
+ ["mana"] = 15,
+ ["mana_max"] = 50,
+ ["fail"] = 45,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 3 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 90,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 20, 40 },
+ },
+ },
+ ["spell"] = function()
+ return hp_player(player.mhp * (15 + get_level(HEALING, 35)) / 100)
+ end,
+ ["info"] = function()
+ return "heal "..(15 + get_level(HEALING, 35)).."% = "..(player.mhp * (15 + get_level(HEALING, 35)) / 100).."hp"
+ end,
+ ["desc"] = {
+ "Heals a percent of hitpoints",
+ }
+}
+
+RECOVERY = add_spell
+{
+ ["name"] = "Recovery",
+ ["school"] = {SCHOOL_NATURE},
+ ["level"] = 15,
+ ["mana"] = 10,
+ ["mana_max"] = 25,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 10 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 50,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 10, 30 },
+ },
+ },
+ ["inertia"] = { 2, 100 },
+ ["spell"] = function()
+ local obvious
+ obvious = set_poisoned(player.poisoned / 2)
+ if get_level(RECOVERY, 50) >= 5 then
+ obvious = is_obvious(set_poisoned(0), obvious)
+ obvious = is_obvious(set_cut(0), obvious)
+ end
+ if get_level(RECOVERY, 50) >= 10 then
+ obvious = is_obvious(do_res_stat(A_STR, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_CON, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_DEX, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_WIS, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_INT, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_CHR, TRUE), obvious)
+ end
+ if get_level(RECOVERY, 50) >= 15 then
+ obvious = is_obvious(restore_level(), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Reduces the length of time that you are poisoned",
+ "At level 5 it cures poison and cuts",
+ "At level 10 it restores drained stats",
+ "At level 15 it restores lost experience"
+ }
+}
+
+REGENERATION = add_spell
+{
+ ["name"] = "Regeneration",
+ ["school"] = {SCHOOL_NATURE},
+ ["level"] = 20,
+ ["mana"] = 30,
+ ["mana_max"] = 55,
+ ["fail"] = 70,
+ ["inertia"] = { 4, 40 },
+ ["spell"] = function()
+ if player.tim_regen == 0 then return set_tim_regen(randint(10) + 5 + get_level(REGENERATION, 50), 300 + get_level(REGENERATION, 700)) end
+ end,
+ ["info"] = function()
+ return "dur "..(5 + get_level(REGENERATION, 50)).."+d10 power "..(300 + get_level(REGENERATION, 700))
+ end,
+ ["desc"] = {
+ "Increases your body's regeneration rate",
+ }
+}
+
+
+SUMMONANNIMAL = add_spell
+{
+ ["name"] = "Summon Animal",
+ ["school"] = {SCHOOL_NATURE},
+ ["level"] = 25,
+ ["mana"] = 25,
+ ["mana_max"] = 50,
+ ["fail"] = 90,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 3 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 85,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 15, 45 },
+ },
+ },
+ ["spell"] = function()
+ summon_specific_level = 25 + get_level(SUMMONANNIMAL, 50)
+ return summon_monster(player.py, player.px, dun_level, TRUE, SUMMON_ANIMAL)
+ end,
+ ["info"] = function()
+ return "level "..(25 + get_level(SUMMONANNIMAL, 50))
+ end,
+ ["desc"] = {
+ "Summons a leveled animal to your aid",
+ }
+}
+
+-- From T-Plus
+GROW_ATHELAS = add_spell {
+ ["name"] = "Grow Athelas",
+ ["school"] = {SCHOOL_NATURE},
+ ["level"] = 30,
+ ["mana"] = 60,
+ ["mana_max"] = 100,
+ ["fail"] = 95,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 3 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 85,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 15, 45 },
+ },
+ },
+ ["spell"] = function()
+ if (player.black_breath == TRUE) then
+ msg_print("The hold of the Black Breath on you is broken!")
+ player.black_breath = FALSE
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Cures the Black Breath",
+ }
+}
diff --git a/lib/mods/theme/scpt/s_stick.lua b/lib/mods/theme/scpt/s_stick.lua
new file mode 100644
index 00000000..9bbd641a
--- /dev/null
+++ b/lib/mods/theme/scpt/s_stick.lua
@@ -0,0 +1,494 @@
+-- Spells that are stick or artifacts/... only
+
+DEVICE_HEAL_MONSTER = add_spell
+{
+ ["name"] = "Heal Monster",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 3,
+ ["mana"] = 5,
+ ["mana_max"] = 20,
+ ["fail"] = 15,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 10 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 17,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ return fire_ball(GF_OLD_HEAL, dir, 20 + get_level(DEVICE_HEAL_MONSTER, 380), 0)
+ end,
+ ["info"] = function()
+ return "heal "..(20 + get_level(DEVICE_HEAL_MONSTER, 380))
+ end,
+ ["desc"] = {
+ "Heals a monster",
+ }
+}
+
+DEVICE_SPEED_MONSTER = add_spell
+{
+ ["name"] = "Haste Monster",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 10,
+ ["mana"] = 10,
+ ["mana_max"] = 10,
+ ["fail"] = 30,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 7,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ return fire_ball(GF_OLD_SPEED, dir, 1, 0)
+ end,
+ ["info"] = function()
+ return "speed +10"
+ end,
+ ["desc"] = {
+ "Haste a monster",
+ }
+}
+
+DEVICE_WISH = add_spell
+{
+ ["name"] = "Wish",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 50,
+ ["mana"] = 400,
+ ["mana_max"] = 400,
+ ["fail"] = 99,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 2 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 98,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1 },
+ },
+ },
+ ["spell"] = function()
+ make_wish()
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "This grants you a wish, beware of what you ask for!",
+ }
+}
+
+DEVICE_SUMMON = add_spell
+{
+ ["name"] = "Summon",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 5,
+ ["mana"] = 5,
+ ["mana_max"] = 25,
+ ["fail"] = 20,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 20 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 13,
+ ["base_level"] = { 1, 40 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["spell"] = function()
+ local i, obvious
+ obvious = nil
+ for i = 1, 4 + get_level(DEVICE_SUMMON, 30) do
+ obvious = is_obvious(summon_specific(player.py, player.px, dun_level, 0), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Summons hostile monsters near you",
+ }
+}
+
+DEVICE_MANA = add_spell
+{
+ ["name"] = "Mana",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 30,
+ ["mana"] = 1,
+ ["mana_max"] = 1,
+ ["fail"] = 80,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 3 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 78,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 20, 35 },
+ },
+ },
+ ["spell"] = function()
+ increase_mana((player.msp * (20 + get_level(DEVICE_MANA, 50))) / 100)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "restore "..(20 + get_level(DEVICE_MANA, 50)).."%"
+ end,
+ ["desc"] = {
+ "Restores a part(or all) of your mana",
+ }
+}
+
+DEVICE_NOTHING = add_spell
+{
+ ["name"] = "Nothing",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 0,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 0, 0 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 3,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1 },
+ },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 3,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1},
+ },
+ },
+ ["spell"] = function()
+ return FALSE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "It does nothing.",
+ }
+}
+
+DEVICE_MAGGOT = add_spell
+{
+ ["name"] = "Artifact Maggot",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 7,
+ ["mana_max"] = 7,
+ ["fail"] = 20,
+ ["random"] = -1,
+ ["activate"] = { 10, 50 },
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_TURN_ALL, dir, 40, 2)
+ end,
+ ["info"] = function()
+ return "power 40 rad 2"
+ end,
+ ["desc"] = {
+ "terrify",
+ }
+}
+
+DEVICE_HOLY_FIRE = add_spell
+{
+ ["name"] = "Holy Fire of Mithrandir",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 30,
+ ["mana"] = 50,
+ ["mana_max"] = 150,
+ ["fail"] = 75,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 5 },
+ [TV_STAFF] =
+ {
+ -- Rarity higher than 100 to be sure to not have it generated randomly
+ ["rarity"] = 999,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 35, 35 },
+ },
+ },
+ ["spell"] = function()
+ return project_los(GF_HOLY_FIRE, 50 + get_level(DEVICE_HOLY_FIRE, 300))
+ end,
+ ["info"] = function()
+ return "dam "..(50 + get_level(DEVICE_HOLY_FIRE, 250))
+ end,
+ ["desc"] = {
+ "The Holy Fire created by this staff will deeply(double damage) burn",
+ "all that is evil.",
+ }
+}
+
+-- Ok the Eternal Flame, to craete one of the 4 ultimate arts
+-- needed to enter the last level of the Void
+DEVICE_ETERNAL_FLAME = add_spell
+{
+ ["name"] = "Artifact Eternal Flame",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 0,
+ ["random"] = -1,
+ ["activate"] = { 0, 0 },
+ ["spell"] = function(flame_item)
+ local ret, item, obj
+
+ ret, item = get_item("Which object do you want to imbue?",
+ "You have no objects to imbue.",
+ bor(USE_INVEN),
+ function (obj)
+ if obj.name1 > 0 or obj.name2 > 0 then return FALSE end
+ if (obj.tval == TV_SWORD) and (obj.sval == SV_LONG_SWORD) then
+ return TRUE
+ elseif (obj.tval == TV_MSTAFF) and (obj.sval == SV_MSTAFF) then
+ return TRUE
+ elseif (obj.tval == TV_BOW) and (obj.sval == SV_HEAVY_XBOW) then
+ return TRUE
+ elseif (obj.tval == TV_DRAG_ARMOR) and (obj.sval == SV_DRAGON_POWER) then
+ return TRUE
+ elseif (obj.tval == TV_HAFTED) and (obj.sval == SV_LUCERN_HAMMER) then
+ return TRUE
+ elseif (obj.tval == TV_POLEARM) and (obj.sval == SV_TRIDENT) then
+ return TRUE
+ elseif (obj.tval == TV_AXE) and (obj.sval == SV_BATTLE_AXE) then
+ return TRUE
+ elseif (obj.tval == TV_BOW) and (obj.sval == SV_LONG_BOW) then
+ return TRUE
+ elseif (obj.tval == TV_BOOMERANG) and (obj.sval == SV_BOOM_METAL) then
+ return TRUE
+ elseif (obj.tval == TV_BOW) and (obj.sval == SV_SLING) then
+ return TRUE
+ elseif (obj.tval == TV_SWORD) and (obj.sval == SV_RAPIER) then
+ return TRUE
+ elseif (obj.tval == TV_AMULET) and (obj.sval == SV_AMULET_SPELL) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+ if ret == FALSE then return FALSE end
+
+ obj = get_object(item)
+
+ if (obj.tval == TV_SWORD) and (obj.sval == SV_LONG_SWORD) then
+ obj.name1 = 147
+ elseif (obj.tval == TV_MSTAFF) and (obj.sval == SV_MSTAFF) then
+ obj.name1 = 127
+ elseif (obj.tval == TV_BOW) and (obj.sval == SV_HEAVY_XBOW) then
+ obj.name1 = 152
+ elseif (obj.tval == TV_DRAG_ARMOR) and (obj.sval == SV_DRAGON_POWER) then
+ obj.name1 = 17
+ elseif (obj.tval == TV_HAFTED) and (obj.sval == SV_LUCERN_HAMMER) then
+ obj.name1 = 241
+ elseif (obj.tval == TV_POLEARM) and (obj.sval == SV_TRIDENT) then
+ obj.name1 = 242
+ elseif (obj.tval == TV_AXE) and (obj.sval == SV_BROAD_AXE) then
+ obj.name1 = 243
+ elseif (obj.tval == TV_BOW) and (obj.sval == SV_LONG_BOW) then
+ obj.name1 = 245
+ elseif (obj.tval == TV_BOOMERANG) and (obj.sval == SV_BOOM_METAL) then
+ obj.name1 = 247
+ elseif (obj.tval == TV_BOW) and (obj.sval == SV_SLING) then
+ obj.name1 = 246
+ elseif (obj.tval == TV_SWORD) and (obj.sval == SV_RAPIER) then
+ obj.name1 = 244
+ elseif (obj.tval == TV_AMULET) and (obj.sval == SV_AMULET_SPELL) then
+ obj.name1 = 248
+ end
+ apply_magic(obj, -1, TRUE, TRUE, TRUE)
+
+ obj.found = OBJ_FOUND_SELFMADE
+
+ inven_item_increase(flame_item, -1)
+ inven_item_describe(flame_item)
+ inven_item_optimize(flame_item)
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Imbuing an object with the eternal fire",
+ }
+}
+
+DEVICE_THUNDERLORDS = add_spell
+{
+ ["name"] = "Artifact Thunderlords",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 1,
+ ["fail"] = 20,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 5 },
+ [TV_STAFF] =
+ {
+ -- Rarity higher than 100 to be sure to not have it generated randomly
+ ["rarity"] = 999,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1 },
+ },
+ },
+ ["spell"] = function()
+ if dun_level > 0 then
+ msg_print("As you blow the horn, an Eagle of Manwe appears overhead.")
+ recall_player(0, 1)
+ else
+ msg_print("You cannot use it there.")
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "An Eagle of Manwe will appear to transport you quickly to the town.",
+ }
+}
+
+-- Two new spells from T-Plus by Ingeborg S. Norden, for artifact activations:
+
+DEVICE_RADAGAST = add_spell
+{
+ ["name"] = "Artifact Radagast",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 10,
+ ["random"] = -1,
+ ["activate"] = 15000,
+ ["spell"] = function()
+ msg_print(TERM_GREEN, "The staff's power cleanses you completely!")
+ remove_all_curse()
+ do_res_stat(A_STR, TRUE)
+ do_res_stat(A_CON, TRUE)
+ do_res_stat(A_DEX, TRUE)
+ do_res_stat(A_WIS, TRUE)
+ do_res_stat(A_INT, TRUE)
+ do_res_stat(A_CHR, TRUE)
+ restore_level()
+ clean_corruptions()
+ hp_player(5000)
+ heal_insanity(5000)
+ set_poisoned(0)
+ set_blind(0)
+ set_confused(0)
+ set_image(0)
+ set_stun(0)
+ set_cut(0)
+ set_parasite(0, 0)
+
+ if (player.black_breath) == TRUE then
+ msg_print("The hold of the Black Breath on you is broken!")
+ end
+ player.black_breath = FALSE
+
+ player.update = bor(player.update, PU_BONUS)
+ player.window = bor(player.window, PW_PLAYER)
+
+ return TRUE
+ end,
+
+ ["info"] = function()
+ return ""
+ end,
+
+ ["desc"] = {
+ "purity and health",
+ }
+}
+
+DEVICE_VALAROMA = add_spell
+{
+ ["name"] = "Artifact Valaroma",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 25,
+ ["random"] = -1,
+ ["activate"] = 250,
+ ["spell"] = function()
+ local power = 5 * player.lev
+ banish_evil(power)
+ return FALSE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "banish evil (level x5)",
+ }
+}
+--[[ Template
+DEVICE_ = add_spell
+{
+ ["name"] = "",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 2,
+ ["mana_max"] = 15,
+ ["fail"] = 10,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 7,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["spell"] = function()
+ return FALSE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "",
+ }
+}
+]]
diff --git a/lib/mods/theme/scpt/s_tempo.lua b/lib/mods/theme/scpt/s_tempo.lua
new file mode 100644
index 00000000..d3d2fbb5
--- /dev/null
+++ b/lib/mods/theme/scpt/s_tempo.lua
@@ -0,0 +1,162 @@
+-- Handles thhe temporal school
+
+
+MAGELOCK = add_spell
+{
+ ["name"] = "Magelock",
+ ["school"] = {SCHOOL_TEMPORAL},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 35,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 30,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 15, 45 },
+ },
+ },
+ ["spell"] = function()
+ if get_level(MAGELOCK, 50) >= 30 then
+ local ret, x, y, c_ptr
+
+ if get_level(MAGELOCK, 50) >= 40 then
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ if cave_is(cave(y, x), FF1_FLOOR) == FALSE or cave_is(cave(y, x), FF1_PERMANENT) == TRUE or los(player.py, player.px, y, x) == FALSE then
+ msg_print("You cannot place it there.")
+ return TRUE
+ end
+ else
+ y = player.py
+ x = player.px
+ end
+ cave_set_feat(y, x, 3)
+ return TRUE
+ else
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return wizard_lock(dir)
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Magically locks a door",
+ "At level 30 it creates a glyph of warding",
+ "At level 40 the glyph can be placed anywhere in the field of vision"
+ }
+}
+
+SLOWMONSTER = add_spell
+{
+ ["name"] = "Slow Monster",
+ ["school"] = {SCHOOL_TEMPORAL},
+ ["level"] = 10,
+ ["mana"] = 10,
+ ["mana_max"] = 15,
+ ["fail"] = 35,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 23,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ if get_level(SLOWMONSTER, 50) >= 20 then
+ return fire_ball(GF_OLD_SLOW, dir, 40 + get_level(SLOWMONSTER, 160), 1)
+ else
+ return fire_bolt(GF_OLD_SLOW, dir, 40 + get_level(SLOWMONSTER, 160))
+ end
+ end,
+ ["info"] = function()
+ if get_level(SLOWMONSTER, 50) >= 20 then
+ return "power "..(40 + get_level(SLOWMONSTER, 160)).." rad 1"
+ else
+ return "power "..(40 + get_level(SLOWMONSTER, 160))
+ end
+ end,
+ ["desc"] = {
+ "Magically slows down the passing of time around a monster",
+ "At level 20 it affects a zone"
+ }
+}
+
+ESSENCESPEED = add_spell
+{
+ ["name"] = "Essence of Speed",
+ ["school"] = {SCHOOL_TEMPORAL},
+ ["level"] = 15,
+ ["mana"] = 20,
+ ["mana_max"] = 40,
+ ["fail"] = 50,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 3 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 80,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 10, 39 },
+ },
+ },
+ ["inertia"] = { 5, 20 },
+ ["spell"] = function()
+ if player.fast == 0 then return set_fast(10 + randint(10) + get_level(ESSENCESPEED, 50), 5 + get_level(ESSENCESPEED, 20)) end
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(ESSENCESPEED, 50)).."+d10 speed "..(5 + get_level(ESSENCESPEED, 20))
+ end,
+ ["desc"] = {
+ "Magically decreases the passing of time around you, making you move faster with",
+ "respect to the rest of the universe."
+ }
+}
+
+BANISHMENT = add_spell
+{
+ ["name"] = "Banishment",
+ ["school"] = {SCHOOL_TEMPORAL, SCHOOL_CONVEYANCE},
+ ["level"] = 30,
+ ["mana"] = 30,
+ ["mana_max"] = 40,
+ ["fail"] = 95,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 3 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 98,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 10, 36 },
+ },
+ },
+ ["inertia"] = { 5, 50 },
+ ["spell"] = function()
+ local obvious
+ obvious = project_los(GF_AWAY_ALL, 40 + get_level(BANISHMENT, 160))
+ if get_level(BANISHMENT, 50) >= 15 then
+ obvious = is_obvious(project_los(GF_STASIS, 20 + get_level(BANISHMENT, 120)), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return "power "..(40 + get_level(BANISHMENT, 160))
+ end,
+ ["desc"] = {
+ "Disrupts the space/time continuum in your area and teleports all monsters away.",
+ "At level 15 it may also lock them in a time bubble for a while."
+ }
+}
diff --git a/lib/mods/theme/scpt/s_tulkas.lua b/lib/mods/theme/scpt/s_tulkas.lua
new file mode 100644
index 00000000..4afa8082
--- /dev/null
+++ b/lib/mods/theme/scpt/s_tulkas.lua
@@ -0,0 +1,81 @@
+-- Handle Tulkas magic school
+
+TULKAS_AIM = add_spell
+{
+ ["name"] = "Divine Aim",
+ ["school"] = {SCHOOL_TULKAS},
+ ["level"] = 1,
+ ["mana"] = 30,
+ ["mana_max"] = 500,
+ ["fail"] = 20,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local dur = get_level(TULKAS_AIM, 50) + randint(10)
+ local obvious
+
+ obvious = set_strike(dur)
+ if get_level(TULKAS_AIM) >= 20 then
+ obvious = is_obvious(set_tim_deadly(dur), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(get_level(TULKAS_AIM, 50)).."+d10"
+ end,
+ ["desc"] = {
+ "It makes you more accurate in combat",
+ "At level 20 all your blows are critical hits",
+ }
+}
+
+TULKAS_WAVE = add_spell
+{
+ ["name"] = "Wave of Power",
+ ["school"] = {SCHOOL_TULKAS},
+ ["level"] = 20,
+ ["mana"] = 200,
+ ["mana_max"] = 200,
+ ["fail"] = 75,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ return fire_bolt(GF_ATTACK, dir, get_level(TULKAS_WAVE, player.num_blow))
+ end,
+ ["info"] = function()
+ return "blows "..(get_level(TULKAS_WAVE, player.num_blow))
+ end,
+ ["desc"] = {
+ "It allows you to project a number of melee blows across a distance",
+ }
+}
+
+TULKAS_SPIN = add_spell
+{
+ ["name"] = "Whirlwind",
+ ["school"] = {SCHOOL_TULKAS},
+ ["level"] = 10,
+ ["mana"] = 100,
+ ["mana_max"] = 100,
+ ["fail"] = 45,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return fire_ball(GF_ATTACK, 0, 1, 1)
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "It allows you to spin around and hit all monsters nearby",
+ }
+}
diff --git a/lib/mods/theme/scpt/s_udun.lua b/lib/mods/theme/scpt/s_udun.lua
new file mode 100644
index 00000000..c4266239
--- /dev/null
+++ b/lib/mods/theme/scpt/s_udun.lua
@@ -0,0 +1,180 @@
+-- handle the udun school
+
+DRAIN = add_spell
+{
+ ["name"] = "Drain",
+ ["school"] = {SCHOOL_UDUN, SCHOOL_MANA},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 20,
+ ["spell"] = function()
+ local ret, item, obj, o_name, add
+
+ -- Ask for an item
+ ret, item = get_item("What item to drain?", "You have nothing you can drain", USE_INVEN,
+ function (obj)
+ if (obj.tval == TV_WAND) or (obj.tval == TV_ROD_MAIN) or (obj.tval == TV_STAFF) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+
+ if ret == TRUE then
+ -- get the item
+ obj = get_object(item)
+
+ add = 0
+ if (obj.tval == TV_STAFF) or (obj.tval == TV_WAND) then
+ local kind = get_kind(obj)
+
+ add = kind.level * obj.pval * obj.number
+
+ -- Destroy it!
+ inven_item_increase(item, -99)
+ inven_item_describe(item)
+ inven_item_optimize(item)
+ end
+ if obj.tval == TV_ROD_MAIN then
+ add = obj.timeout
+ obj.timeout = 0;
+
+ --Combine / Reorder the pack (later)
+ player.notice = bor(player.notice, PN_COMBINE, PN_REORDER)
+ player.window = bor(player.window, PW_INVEN, PW_EQUIP, PW_PLAYER)
+ end
+ increase_mana(add)
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Drains the mana contained in wands, staves and rods to increase yours",
+ }
+}
+
+GENOCIDE = add_spell
+{
+ ["name"] = "Genocide",
+ ["school"] = {SCHOOL_UDUN, SCHOOL_NATURE},
+ ["level"] = 25,
+ ["mana"] = 50,
+ ["mana_max"] = 50,
+ ["fail"] = 90,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 2 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 85,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 5, 15 },
+ },
+ },
+ ["spell"] = function()
+ local type
+
+ type = 0
+ if get_level(GENOCIDE) >= 10 then type = 1 end
+ if type == 0 then
+ genocide(TRUE)
+ return TRUE
+ else
+ if get_check("Genocide all monsters near you? ") == TRUE then
+ mass_genocide(TRUE)
+ else
+ genocide(TRUE)
+ end
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Genocides all monsters of a race on the level",
+ "At level 10 it can genocide all monsters near you"
+ }
+}
+
+WRAITHFORM = add_spell
+{
+ ["name"] = "Wraithform",
+ ["school"] = {SCHOOL_UDUN, SCHOOL_CONVEYANCE},
+ ["level"] = 30,
+ ["mana"] = 20,
+ ["mana_max"] = 40,
+ ["fail"] = 95,
+ ["inertia"] = { 4, 30 },
+ ["spell"] = function()
+ return set_shadow(randint(30) + 20 + get_level(WRAITHFORM, 40))
+ end,
+ ["info"] = function()
+ return "dur "..(20 + get_level(WRAITHFORM, 40)).."+d30"
+ end,
+ ["desc"] = {
+ "Turns you into an immaterial being",
+ }
+}
+
+FLAMEOFUDUN = add_spell
+{
+ ["name"] = "Flame of Udun",
+ ["school"] = {SCHOOL_UDUN, SCHOOL_FIRE},
+ ["level"] = 35,
+ ["mana"] = 70,
+ ["mana_max"] = 100,
+ ["fail"] = 95,
+ ["inertia"] = { 7, 15 },
+ ["spell"] = function()
+ return set_mimic(randint(15) + 5 + get_level(FLAMEOFUDUN, 30), resolve_mimic_name("Balrog"), get_level(FLAMEOFUDUN))
+ end,
+ ["info"] = function()
+ return "dur "..(5 + get_level(FLAMEOFUDUN, 30)).."+d15"
+ end,
+ ["desc"] = {
+ "Turns you into a powerful Balrog",
+ }
+}
+
+
+-- Return the number of Udun/Melkor spells in a given book
+function udun_in_book(sval, pval)
+ local i, y, index, sch, s
+
+ i = 0
+
+ -- Hack if the book is 255 it is a random book
+ if sval == 255 then
+ school_book[sval] = {pval}
+ end
+ -- Parse all spells
+ for index, s in school_book[sval] do
+ for index, sch in __spell_school[s] do
+ if sch == SCHOOL_UDUN then i = i + 1 end
+ if sch == SCHOOL_MELKOR then i = i + 1 end
+ end
+ end
+ return i
+end
+
+-- Return the total level of spells
+function levels_in_book(sval, pval)
+ local i, y, index, sch, s
+
+ i = 0
+
+ -- Hack if the book is 255 it is a random book
+ if sval == 255 then
+ school_book[sval] = {pval}
+ end
+
+ -- Parse all spells
+ for index, s in school_book[sval] do
+ i = i + __tmp_spells[s].level
+ end
+ return i
+end
diff --git a/lib/mods/theme/scpt/s_ulmo.lua b/lib/mods/theme/scpt/s_ulmo.lua
new file mode 100644
index 00000000..a2c24b29
--- /dev/null
+++ b/lib/mods/theme/scpt/s_ulmo.lua
@@ -0,0 +1,147 @@
+-- Spells for Ulmo's school
+
+BOOK_ULMO = 65
+
+-- "Song of Belegaer" copied from Geyser
+ULMO_BELEGAER = add_spell
+{
+ ["name"] = "Song of Belegaer",
+ ["school"] = SCHOOL_ULMO,
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 100,
+ ["fail"] = 25,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt_or_beam(2 * get_level(ULMO_BELEGAER, 85), GF_WATER, dir, damroll(get_geyser_damage()))
+ end,
+ ["info"] = function()
+ local n, d
+ n, d = get_geyser_damage()
+ return "dam "..n.."d"..d
+ end,
+ ["desc"] =
+ {
+ "Channels the power of the Great Sea into your fingertips.",
+ "Sometimes it can blast through its first target."
+ },
+}
+
+-- "Draught of Ulmonan" copied with tweaks from T-Plus Nature spell "Restore Body"
+ULMO_DRAUGHT_ULMONAN = add_spell
+{
+ ["name"] = "Draught of Ulmonan",
+ ["school"] = {SCHOOL_ULMO},
+ ["level"] = 15,
+ ["mana"] = 25,
+ ["mana_max"] = 200,
+ ["fail"] = 50,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local level = get_level(ULMO_DRAUGHT_ULMONAN, 50)
+ local obvious = hp_player(5 * level)
+ obvious = is_obvious(set_poisoned(0), obvious)
+ obvious = is_obvious(set_cut(0), obvious)
+ obvious = is_obvious(set_stun(0), obvious)
+ obvious = is_obvious(set_blind(0), obvious)
+ if level >= 10 then
+ obvious = is_obvious(do_res_stat(A_STR, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_CON, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_DEX, TRUE), obvious)
+ end
+ if level >= 20 then
+ obvious = is_obvious(set_parasite(0, 0), obvious)
+ obvious = is_obvious(set_mimic(0, 0, 0), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ local level = get_level(ULMO_DRAUGHT_ULMONAN, 50)
+ return "cure "..(5 * level)
+ end,
+ ["desc"] = {
+ "Fills you with a draught with powerful curing effects,",
+ "prepared by Ulmo himself.",
+ "Level 1: blindness, poison, cuts and stunning",
+ "Level 10: drained STR, DEX and CON",
+ "Level 20: parasites and mimicry",
+ },
+}
+
+-- "Call of the Ulumuri" based on Call Blessed Soul from T-Plus
+ULMO_CALL_ULUMURI = add_spell
+
+{
+ ["name"] = "Call of the Ulumuri",
+ ["school"] = {SCHOOL_ULMO},
+ ["level"] = 20,
+ ["mana"] = 50,
+ ["mana_max"] = 300,
+ ["fail"] = 75,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local y, x, m_idx
+ local summons =
+ {
+ test_monster_name("Water spirit"),
+ test_monster_name("Water elemental"),
+ }
+ y, x = find_position(player.py, player.px)
+ m_idx = place_monster_one(y, x, summons[rand_range(1, 2)], 0, FALSE, MSTATUS_FRIEND)
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 30 + get_level(ULMO_CALL_ULUMURI, 70, 0))
+ return TRUE
+ end
+ end,
+
+ ["info"] = function()
+ return "level "..(get_level(ULMO_CALL_ULUMURI, 70))
+ end,
+ ["desc"] = {
+ "Summons a leveled water spirit or elemental",
+ "to fight for you",
+
+ },
+}
+
+-- "Wrath of Ulmo" based on Firewall
+ULMO_WRATH = add_spell
+{
+ ["name"] = "Wrath of Ulmo",
+ ["school"] = {SCHOOL_ULMO},
+ ["level"] = 30,
+ ["mana"] = 100,
+ ["mana_max"] = 400,
+ ["fail"] = 95,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir, type
+ if (get_level(ULMO_WRATH, 50) >= 30) then
+ type = GF_WAVE
+ else
+ type = GF_WATER
+ end
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ fire_wall(type, dir, 40 + get_level(ULMO_WRATH, 150), 10 + get_level(ULMO_WRATH, 14))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(40 + get_level(ULMO_WRATH, 150)).." dur "..(10 + get_level(ULMO_WRATH, 14))
+ end,
+ ["desc"] = {
+ "Conjures up a sea storm.",
+ "At level 30 it turns into a more forceful storm."
+ }
+} \ No newline at end of file
diff --git a/lib/mods/theme/scpt/s_varda.lua b/lib/mods/theme/scpt/s_varda.lua
new file mode 100644
index 00000000..f4f46a83
--- /dev/null
+++ b/lib/mods/theme/scpt/s_varda.lua
@@ -0,0 +1,140 @@
+-- Spells for Varda school (From Annals of Ea module)
+
+BOOK_VARDA = 64
+
+-- Holy light spell copied from Globe of Light
+VARDA_LIGHT_VALINOR = add_spell
+{
+ ["name"] = "Light of Valinor",
+ ["school"] = {SCHOOL_VARDA},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 100,
+ ["fail"] = 20,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local obvious
+ if get_level(VARDA_LIGHT_VALINOR, 50) >= 3 then
+ obvious = lite_area(10, 4)
+ else
+ lite_room(player.py, player.px)
+ obvious = TRUE
+ end
+ if get_level(VARDA_LIGHT_VALINOR, 50) >= 15 then
+ obvious = is_obvious(fire_ball(GF_LITE, 0, 10 + get_level(VARDA_LIGHT_VALINOR, 100), 5 + get_level(GLOBELIGHT, 6)), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ if get_level(VARDA_LIGHT_VALINOR, 50) >= 15 then
+ return "dam "..(10 + get_level(VARDA_LIGHT_VALINOR, 100)).." rad "..(5 + get_level(VARDA_LIGHT_VALINOR, 6))
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Lights a room",
+ "At level 3 it starts damaging monsters",
+ "At level 15 it starts creating a more powerful kind of light",
+ }
+}
+
+VARDA_CALL_ALMAREN = add_spell
+{
+ ["name"] = "Call of Almaren",
+ ["school"] = {SCHOOL_VARDA},
+ ["level"] = 10,
+ ["mana"] = 5,
+ ["mana_max"] = 150,
+ ["fail"] = 20,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local power = 5 * player.lev
+ if (get_level(VARDA_CALL_ALMAREN) >= 20) then
+ dispel_evil(power)
+ else
+ banish_evil(power)
+ end
+ return FALSE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Banishes evil beings",
+ "At level 20 it dispels evil beings",
+ }
+}
+
+VARDA_EVENSTAR = add_spell
+{
+ ["name"] = "Evenstar",
+ ["school"] = {SCHOOL_VARDA},
+ ["level"] = 20,
+ ["mana"] = 20,
+ ["mana_max"] = 200,
+ ["fail"] = 20,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ if (get_level(VARDA_EVENSTAR) >= 40) then
+ -- Enlightenment
+ wiz_lite_extra()
+ -- Identify
+ identify_pack()
+ -- Self knowledge
+ self_knowledge()
+ else
+ wiz_lite_extra()
+ end
+ return FALSE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Maps and lights the whole level.",
+ "At level 40 it maps and lights the whole level,",
+ "in addition to letting you know yourself better",
+ "and identifying your whole pack.",
+ }
+}
+
+VARDA_STARKINDLER = add_spell
+{
+ ["name"] = "Star Kindler",
+ ["school"] = {SCHOOL_VARDA},
+ ["level"] = 30,
+ ["mana"] = 50,
+ ["mana_max"] = 250,
+ ["fail"] = 20,
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local power = player.lev / 5
+ local ret, dir
+
+ ret, dir = get_aim_dir()
+
+ if ret == FALSE then return end
+ for i = 1, power do
+ fire_ball(GF_LITE, dir, 20 + get_level(VARDA_STARKINDLER, 100), 10)
+ end
+
+ return FALSE
+ end,
+ ["info"] = function()
+ local power = player.lev / 5
+ return "dam "..(20 + get_level(VARDA_STARKINDLER, 100)).." rad 10"
+ end,
+ ["desc"] = {
+ "Does multiple bursts of light damage.",
+ "The damage increases with level.",
+ }
+} \ No newline at end of file
diff --git a/lib/mods/theme/scpt/s_water.lua b/lib/mods/theme/scpt/s_water.lua
new file mode 100644
index 00000000..739b066b
--- /dev/null
+++ b/lib/mods/theme/scpt/s_water.lua
@@ -0,0 +1,154 @@
+-- handle the water school
+
+TIDALWAVE = add_spell
+{
+ ["name"] = "Tidal Wave",
+ ["school"] = {SCHOOL_WATER},
+ ["level"] = 16,
+ ["mana"] = 16,
+ ["mana_max"] = 40,
+ ["fail"] = 65,
+ ["stick"] =
+ {
+ ["charge"] = { 6, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 54,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["inertia"] = { 4, 100 },
+ ["spell"] = function()
+ fire_wave(GF_WAVE, 0, 40 + get_level(TIDALWAVE, 200), 0, 6 + get_level(TIDALWAVE, 10), EFF_WAVE)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(40 + get_level(TIDALWAVE, 200)).." rad "..(6 + get_level(TIDALWAVE, 10))
+ end,
+ ["desc"] = {
+ "Summons a monstrous tidal wave that will expand and crush the",
+ "monsters under its mighty waves."
+ }
+}
+
+ICESTORM = add_spell
+{
+ ["name"] = "Ice Storm",
+ ["school"] = {SCHOOL_WATER},
+ ["level"] = 22,
+ ["mana"] = 30,
+ ["mana_max"] = 60,
+ ["fail"] = 80,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 7 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 65,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 25, 45 },
+ },
+ },
+ ["inertia"] = { 3, 40 },
+ ["spell"] = function()
+ local type
+
+ if get_level(ICESTORM, 50) >= 10 then type = GF_ICE
+ else type = GF_COLD end
+ fire_wave(type, 0, 80 + get_level(ICESTORM, 200), 1 + get_level(ICESTORM, 3, 0), 20 + get_level(ICESTORM, 70), EFF_STORM)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(80 + get_level(ICESTORM, 200)).." rad "..(1 + get_level(ICESTORM, 3, 0)).." dur "..(20 + get_level(ICESTORM, 70))
+ end,
+ ["desc"] = {
+ "Engulfs you in a storm of roaring cold that strikes your foes.",
+ "At level 10 it turns into shards of ice."
+ }
+}
+
+ENTPOTION = add_spell
+{
+ ["name"] = "Ent's Potion",
+ ["school"] = {SCHOOL_WATER},
+ ["level"] = 6,
+ ["mana"] = 7,
+ ["mana_max"] = 15,
+ ["fail"] = 35,
+ ["inertia"] = { 1, 30 },
+ ["spell"] = function()
+ set_food(PY_FOOD_MAX - 1)
+ msg_print("The Ent's Potion fills your stomach.")
+ if get_level(ENTPOTION, 50) >= 5 then
+ set_afraid(0)
+ end
+ if get_level(ENTPOTION, 50) >= 12 then
+ set_hero(player.hero + randint(25) + 25 + get_level(ENTPOTION, 40))
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ if get_level(ENTPOTION, 50) >= 12 then
+ return "dur "..(25 + get_level(ENTPOTION, 40)).."+d25"
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Fills up your stomach.",
+ "At level 5 it boldens your heart.",
+ "At level 12 it makes you heroic."
+ }
+}
+
+VAPOR = add_spell
+{
+ ["name"] = "Vapor",
+ ["school"] = {SCHOOL_WATER},
+ ["level"] = 2,
+ ["mana"] = 2,
+ ["mana_max"] = 12,
+ ["fail"] = 20,
+ ["inertia"] = { 1, 30 },
+ ["spell"] = function()
+ fire_cloud(GF_WATER, 0, 3 + get_level(VAPOR, 20), 3 + get_level(VAPOR, 9, 0), 5)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(3 + get_level(VAPOR, 20)).." rad "..(3 + get_level(VAPOR, 9, 0)).." dur 5"
+ end,
+ ["desc"] = {
+ "Fills the air with toxic moisture to eradicate annoying critters."
+ }
+}
+
+function get_geyser_damage()
+ return get_level(GEYSER, 10), 3 + get_level(GEYSER, 35)
+end
+
+GEYSER = add_spell
+{
+ ["name"] = "Geyser",
+ ["school"] = SCHOOL_WATER,
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 35,
+ ["fail"] = 5,
+ ["spell"] = function()
+ local ret, dir
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt_or_beam(2 * get_level(GEYSER, 85), GF_WATER, dir, damroll(get_geyser_damage()))
+ end,
+ ["info"] = function()
+ local n, d
+ n, d = get_geyser_damage()
+ return "dam "..n.."d"..d
+ end,
+ ["desc"] =
+ {
+ "Shoots a geyser of water from your fingertips.",
+ "Sometimes it can blast through its first target."
+ },
+}
diff --git a/lib/mods/theme/scpt/s_yavann.lua b/lib/mods/theme/scpt/s_yavann.lua
new file mode 100644
index 00000000..2f594e85
--- /dev/null
+++ b/lib/mods/theme/scpt/s_yavann.lua
@@ -0,0 +1,157 @@
+-- Handle Yavanna kementari magic school
+
+YAVANNA_CHARM_ANIMAL = add_spell
+{
+ ["name"] = "Charm Animal",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 1,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 30,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ return fire_ball(GF_CONTROL_ANIMAL, dir, 10 + get_level(YAVANNA_CHARM_ANIMAL, 170), get_level(YAVANNA_CHARM_ANIMAL, 2))
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(YAVANNA_CHARM_ANIMAL, 170)).." rad "..(get_level(YAVANNA_CHARM_ANIMAL, 2))
+ end,
+ ["desc"] = {
+ "It tries to tame an animal",
+ }
+}
+
+YAVANNA_GROW_GRASS = add_spell
+{
+ ["name"] = "Grow Grass",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 10,
+ ["mana"] = 70,
+ ["mana_max"] = 150,
+ ["fail"] = 65,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ grow_grass(get_level(YAVANNA_GROW_GRASS, 4))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(get_level(YAVANNA_GROW_GRASS, 4))
+ end,
+ ["desc"] = {
+ "Create a floor of grass around you. While on grass and praying",
+ "a worshipper of Yavanna will know a greater regeneration rate"
+ }
+}
+
+YAVANNA_TREE_ROOTS = add_spell
+{
+ ["name"] = "Tree Roots",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 15,
+ ["mana"] = 50,
+ ["mana_max"] = 1000,
+ ["fail"] = 70,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return set_roots(10 + get_level(YAVANNA_TREE_ROOTS, 30), 10 + get_level(YAVANNA_TREE_ROOTS, 60), 10 + get_level(YAVANNA_TREE_ROOTS, 20))
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(YAVANNA_TREE_ROOTS, 30)).." AC "..(10 + get_level(YAVANNA_TREE_ROOTS, 60)).." dam "..(10 + get_level(YAVANNA_TREE_ROOTS, 20))
+ end,
+ ["desc"] = {
+ "Creates roots deep in the floor from your feet, making you more stable and able",
+ "to make stronger attacks, but prevents any movement (even teleportation).",
+ "It also makes you recover from stunning almost immediately."
+ }
+}
+
+YAVANNA_WATER_BITE = add_spell
+{
+ ["name"] = "Water Bite",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 20,
+ ["mana"] = 150,
+ ["mana_max"] = 300,
+ ["fail"] = 90,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local rad
+
+ rad = 0
+ if get_level(YAVANNA_WATER_BITE) >= 25 then rad = 1 end
+
+ return set_project(randint(30) + 30 + get_level(YAVANNA_WATER_BITE, 150),
+ GF_WATER,
+ 10 + get_level(YAVANNA_WATER_BITE),
+ rad,
+ bor(PROJECT_STOP, PROJECT_KILL))
+ end,
+ ["info"] = function()
+ return "dur "..(30 + get_level(YAVANNA_WATER_BITE, 150)).."+d30 dam "..(10 + get_level(YAVANNA_WATER_BITE)).."/blow"
+ end,
+ ["desc"] = {
+ "Imbues your melee weapon with a natural stream of water",
+ "At level 25, it spreads over a 1 radius zone around your target"
+ }
+}
+
+YAVANNA_UPROOT = add_spell
+{
+ ["name"] = "Uproot",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 35,
+ ["mana"] = 250,
+ ["mana_max"] = 350,
+ ["fail"] = 95,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local m_idx, x, y, c_ptr, ret, dir
+
+ ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+ y, x = explode_dir(dir)
+ y, x = y + player.py, x + player.px
+ c_ptr = cave(y, x)
+
+ if c_ptr.feat == FEAT_TREES then
+ cave_set_feat(y, x, FEAT_GRASS);
+
+ -- Summon it
+ y, x = find_position(y, x)
+ m_idx = place_monster_one(y, x, test_monster_name("Ent"), 0, FALSE, MSTATUS_FRIEND)
+
+ -- level it
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 30 + get_level(YAVANNA_UPROOT, 70))
+ end
+
+ msg_print("The tree awakes!");
+ else
+ msg_print("There is no tree there.")
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return "lev "..(30 + get_level(YAVANNA_UPROOT, 70))
+ end,
+ ["desc"] = {
+ "Awakes a tree to help you battle the forces of Morgoth",
+ }
+}
diff --git a/lib/mods/theme/scpt/spells.lua b/lib/mods/theme/scpt/spells.lua
new file mode 100644
index 00000000..838240a3
--- /dev/null
+++ b/lib/mods/theme/scpt/spells.lua
@@ -0,0 +1,627 @@
+--
+-- This file takes care of the schools of magic
+--
+
+-- Create the schools
+SCHOOL_MANA = add_school
+{
+ ["name"] = "Mana",
+ ["skill"] = SKILL_MANA,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Varda provides the Mana school at 1/4 the prayer skill
+ [GOD_VARDA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 4,
+ },
+ -- Eru Iluvatar provides the Mana school at half the prayer skill
+ [GOD_ERU] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_MANA] = function(msp)
+ if get_skill(SKILL_MANA) >= 35 then
+ msp = msp + (msp * ((get_skill(SKILL_MANA) - 34)) / 100)
+ return TRUE, msp
+ end
+ end
+ },
+}
+SCHOOL_FIRE = add_school
+{
+ ["name"] = "Fire",
+ ["skill"] = SKILL_FIRE,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ if get_skill(SKILL_FIRE) >= 35 then
+ end
+ end,
+ [HOOK_CALC_POWERS] = function()
+ if get_skill(SKILL_FIRE) >= 50 then
+-- player.add_power(PWR_FIRE_SHAPE)
+ end
+ end,
+ },
+ ["gods"] =
+ {
+ -- Aule provides the Fire school at 3/5 the prayer skill
+ [GOD_AULE] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 3,
+ ["div"] = 5,
+ },
+ },
+}
+SCHOOL_AIR = add_school
+{
+ ["name"] = "Air",
+ ["skill"] = SKILL_AIR,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ if get_skill(SKILL_AIR) >= 50 then
+ player.magical_breath = TRUE
+ end
+ end,
+ [HOOK_CALC_POWERS] = function()
+ if get_skill(SKILL_AIR) >= 50 then
+-- player.add_powe(PWR_AIR_SHAPE)
+ end
+ end,
+ },
+ ["gods"] =
+ {
+ -- Manwe Sulimo provides the Air school at 2/3 the prayer skill
+ [GOD_MANWE] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 2,
+ ["div"] = 3,
+ },
+ },
+}
+SCHOOL_WATER = add_school
+{
+ ["name"] = "Water",
+ ["skill"] = SKILL_WATER,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ if get_skill(SKILL_WATER) >= 30 then
+ player.water_breath = TRUE
+ end
+ end,
+ [HOOK_CALC_POWERS] = function()
+ if get_skill(SKILL_WATER) >= 50 then
+-- player.add_powe(PWR_WATER_SHAPE)
+ end
+ end,
+ },
+ ["gods"] =
+ {
+ -- Yavanna Kementari provides the Water school at 1/2 the prayer skill
+ [GOD_YAVANNA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ -- Ulmo provides the Water school at 3/5 the prayer skill
+ [GOD_ULMO] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 3,
+ ["div"] = 5,
+ },
+ },
+}
+SCHOOL_EARTH = add_school
+{
+ ["name"] = "Earth",
+ ["skill"] = SKILL_EARTH,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ if get_skill(SKILL_EARTH) >= 50 then
+-- player.add_powe(PWR_EARTH_SHAPE)
+ end
+ end,
+ },
+ ["gods"] =
+ {
+ -- Tulkas provides the Earth school at 4/5 the prayer skill
+ [GOD_TULKAS] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 4,
+ ["div"] = 5,
+ },
+ -- Yavanna Kementari provides the Earth school at 1/2 the prayer skill
+ [GOD_YAVANNA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+
+ -- Aule provides the Earth school at 1/3 the prayer skill
+ [GOD_AULE] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 3,
+ },
+ },
+}
+SCHOOL_CONVEYANCE = add_school
+{
+ ["name"] = "Conveyance",
+ ["skill"] = SKILL_CONVEYANCE,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Manwe Sulimo provides the Conveyance school at 1/2 the prayer skill
+ [GOD_MANWE] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ },
+}
+SCHOOL_GEOMANCY = add_school
+{
+ ["name"] = "Geomancy",
+ ["skill"] = SKILL_GEOMANCY,
+ ["spell_power"] = TRUE,
+ -- Require to wield a Mage Staff, as the spells requries the caster to stomp the floor with it
+ ["depend"] = function()
+ -- Require at least one point in each school
+ if get_skill(SKILL_FIRE) == 0 then return end
+ if get_skill(SKILL_AIR) == 0 then return end
+ if get_skill(SKILL_EARTH) == 0 then return end
+ if get_skill(SKILL_WATER) == 0 then return end
+
+ local obj = get_object(INVEN_WIELD)
+ if (obj.k_idx > 0) and (obj.tval == TV_MSTAFF) then return TRUE end
+ end,
+}
+SCHOOL_DIVINATION = add_school
+{
+ ["name"] = "Divination",
+ ["skill"] = SKILL_DIVINATION,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Eru Iluvatar provides the Divination school at 2/3 the prayer skill
+ [GOD_ERU] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 2,
+ ["div"] = 3,
+ },
+ -- Mandos the Divination school at 1/3 the prayer skill
+ [GOD_MANDOS] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 3,
+ },
+ },
+}
+SCHOOL_TEMPORAL = add_school
+{
+ ["name"] = "Temporal",
+ ["skill"] = SKILL_TEMPORAL,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Yavanna Kementari provides the Temporal school at 1/6 the prayer skill
+ [GOD_YAVANNA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 6,
+ },
+ -- Mandos provides the Temporal school at 1/4 the prayer skill
+ [GOD_MANDOS] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 4,
+ },
+ },
+}
+SCHOOL_NATURE = add_school
+{
+ ["name"] = "Nature",
+ ["skill"] = SKILL_NATURE,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Yavanna Kementari provides the Nature school at 1/2 the prayer skill
+ [GOD_YAVANNA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ -- Ulmo provides the Nature school at 1/2 the prayer skill
+ [GOD_ULMO] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ },
+}
+SCHOOL_META = add_school
+{
+ ["name"] = "Meta",
+ ["skill"] = SKILL_META,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Manwe Sulimo provides the Meta school at 1/3 the prayer skill
+ [GOD_MANWE] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 3,
+ },
+ -- Varda provides the Meta school at 1/2 the prayer skill
+ [GOD_VARDA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ },
+}
+SCHOOL_MIND = add_school
+{
+ ["name"] = "Mind",
+ ["skill"] = SKILL_MIND,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Eru Iluvatar provides the Mind school at 1/3 the prayer skill
+ [GOD_ERU] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 3,
+ },
+ -- Melkor Bauglir provides the Mind school at 1/3 the prayer skill
+ [GOD_MELKOR] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 3,
+ },
+ },
+}
+SCHOOL_UDUN = add_school
+{
+ ["name"] = "Udun",
+ ["skill"] = SKILL_UDUN,
+ ["bonus_level"] = function()
+ return ((player.lev * 2) / 3)
+ end,
+}
+SCHOOL_DEMON = add_school
+{
+ ["name"] = "Demon",
+ ["skill"] = SKILL_DAEMON,
+ ["no_random"] = TRUE,
+}
+
+-- The God specific schools, all tied to the prayer skill
+SCHOOL_ERU = add_school
+{
+ ["name"] = "Eru Iluvatar",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_ERU,
+}
+SCHOOL_MANWE = add_school
+{
+ ["name"] = "Manwe Sulimo",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_MANWE,
+}
+SCHOOL_TULKAS = add_school
+{
+ ["name"] = "Tulkas",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_TULKAS,
+}
+SCHOOL_MELKOR = add_school
+{
+ ["name"] = "Melkor Bauglir",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_MELKOR,
+}
+SCHOOL_YAVANNA = add_school
+{
+ ["name"] = "Yavanna Kementari",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_YAVANNA,
+}
+
+-- New schools
+SCHOOL_AULE = add_school
+{
+ ["name"] = "Aule the Smith",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_AULE,
+}
+SCHOOL_VARDA = add_school
+{
+ ["name"] = "Varda Elentari",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_VARDA,
+}
+
+SCHOOL_ULMO = add_school
+{
+ ["name"] = "Ulmo",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_ULMO,
+}
+
+SCHOOL_MANDOS = add_school
+{
+ ["name"] = "Mandos",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_MANDOS,
+}
+
+-- Not a real school, rather a palcehodler for stick only spells
+SCHOOL_DEVICE = add_school
+{
+ ["name"] = "Device",
+ ["skill"] = SKILL_DEVICE,
+}
+
+-- Music "spells"
+SCHOOL_MUSIC = add_school
+{
+ ["name"] = "Music",
+ ["skill"] = SKILL_MUSIC,
+}
+
+-- Put some spells
+tome_dofile("s_fire.lua")
+tome_dofile("s_mana.lua")
+tome_dofile("s_water.lua")
+tome_dofile("s_air.lua")
+tome_dofile("s_earth.lua")
+tome_dofile("s_convey.lua")
+tome_dofile("s_nature.lua")
+tome_dofile("s_divin.lua")
+tome_dofile("s_tempo.lua")
+tome_dofile("s_meta.lua")
+tome_dofile("s_mind.lua")
+tome_dofile("s_udun.lua")
+tome_dofile("s_geom.lua")
+
+-- God's specific spells
+tome_dofile("s_eru.lua")
+tome_dofile("s_manwe.lua")
+tome_dofile("s_tulkas.lua")
+tome_dofile("s_melkor.lua")
+tome_dofile("s_yavann.lua")
+
+-- New gods' spells
+tome_dofile("s_aule.lua")
+tome_dofile("s_varda.lua")
+tome_dofile("s_ulmo.lua")
+tome_dofile("s_mandos.lua")
+
+-- Specific schools
+tome_dofile("s_demon.lua")
+
+-- Device spells
+tome_dofile("s_stick.lua")
+
+-- Musics
+tome_dofile("s_music.lua")
+
+-- List of spellbooks
+
+-- Create the crystal of mana
+school_book[0] = {
+ MANATHRUST, DELCURSES, RESISTS, MANASHIELD,
+}
+
+-- The book of the eternal flame
+school_book[1] = {
+ GLOBELIGHT, FIREGOLEM, FIREFLASH, FIREWALL, FIERYAURA,
+}
+
+-- The book of the blowing winds
+school_book[2] = {
+ NOXIOUSCLOUD, POISONBLOOD, INVISIBILITY, STERILIZE, AIRWINGS, THUNDERSTORM,
+}
+
+-- The book of the impenetrable earth
+school_book[3] = {
+ STONESKIN, DIG, STONEPRISON, SHAKE, STRIKE,
+}
+
+-- The book of the unstopable wave
+school_book[4] = {
+ GEYSER, VAPOR, ENTPOTION, TIDALWAVE, ICESTORM
+}
+
+-- Create the book of translocation
+school_book[5] = {
+ BLINK, DISARM, TELEPORT, TELEAWAY, RECALL, PROBABILITY_TRAVEL,
+}
+
+-- Create the book of the tree
+school_book[6] = {
+ GROWTREE, HEALING, RECOVERY, REGENERATION, SUMMONANNIMAL, GROW_ATHELAS,
+}
+
+-- Create the book of Knowledge
+school_book[7] = {
+ SENSEMONSTERS, SENSEHIDDEN, REVEALWAYS, IDENTIFY, VISION, STARIDENTIFY,
+}
+
+-- Create the book of the Time
+school_book[8] = {
+ MAGELOCK, SLOWMONSTER, ESSENCESPEED, BANISHMENT,
+}
+
+-- Create the book of meta spells
+school_book[9] = {
+ RECHARGE, DISPERSEMAGIC, SPELLBINDER, TRACKER, INERTIA_CONTROL,
+}
+
+-- Create the book of the mind
+school_book[10] = {
+ CHARM, CONFUSE, ARMOROFFEAR, STUN,
+}
+
+-- Create the book of hellflame
+school_book[11] = {
+ DRAIN, GENOCIDE, WRAITHFORM, FLAMEOFUDUN,
+}
+
+-- Create the book of eru
+school_book[20] = {
+ ERU_SEE, ERU_LISTEN, ERU_UNDERSTAND, ERU_PROT,
+}
+
+-- Create the book of manwe
+school_book[21] = {
+ MANWE_BLESS, MANWE_SHIELD, MANWE_CALL, MANWE_AVATAR,
+}
+
+-- Create the book of tulkas
+school_book[22] = {
+ TULKAS_AIM, TULKAS_SPIN, TULKAS_WAVE,
+}
+
+-- Create the book of melkor
+school_book[23] = {
+ MELKOR_CURSE, MELKOR_CORPSE_EXPLOSION, MELKOR_MIND_STEAL,
+}
+
+-- Create the book of yavanna
+school_book[24] = {
+ YAVANNA_CHARM_ANIMAL, YAVANNA_GROW_GRASS, YAVANNA_TREE_ROOTS, YAVANNA_WATER_BITE, YAVANNA_UPROOT,
+}
+
+-- Create the book of beginner's cantrip
+school_book[50] = {
+ MANATHRUST, GLOBELIGHT, ENTPOTION, BLINK, SENSEMONSTERS, SENSEHIDDEN,
+}
+
+-- Create the book of teleporatation
+school_book[51] = {
+ BLINK, TELEPORT, TELEAWAY
+}
+
+-- Create the book of summoning
+school_book[52] = {
+ FIREGOLEM, SUMMONANNIMAL
+}
+
+
+-- Create the Armageddon Demonblade
+school_book[55] = {
+ DEMON_BLADE, DEMON_MADNESS, DEMON_FIELD,
+}
+
+-- Create the Shield Demonblade
+school_book[56] = {
+ DOOM_SHIELD, DEMON_CLOAK, UNHOLY_WORD,
+}
+
+-- Create the Control Demonblade
+school_book[57] = {
+ DEMON_SUMMON, DISCHARGE_MINION, CONTROL_DEMON,
+}
+
+-- Create the Drums
+school_book[58] = {
+ MUSIC_STOP, MUSIC_HOLD, MUSIC_CONF, MUSIC_STUN,
+}
+
+-- Create the Harps
+school_book[59] = {
+ MUSIC_STOP, MUSIC_LITE, MUSIC_HERO, MUSIC_HEAL, MUSIC_TIME, MUSIC_MIND,
+}
+
+-- Create the Horns
+school_book[60] = {
+ MUSIC_STOP, MUSIC_BLOW, MUSIC_WIND, MUSIC_YLMIR, MUSIC_AMBARKANTA,
+}
+
+-- Book of the Player, filled in by the Library Quest
+school_book[61] = { }
+
+-- Geomancy spells, not a real book
+school_book[62] = {
+ CALL_THE_ELEMENTS, CHANNEL_ELEMENTS, ELEMENTAL_WAVE, VAPORIZE, GEOLYSIS, DRIPPING_TREAD, GROW_BARRIER, ELEMENTAL_MINION
+}
+
+-- Aule book [63]
+school_book[BOOK_AULE] =
+{
+ AULE_FIREBRAND, AULE_ENCHANT_WEAPON, AULE_ENCHANT_ARMOUR, AULE_CHILD,
+}
+
+-- Varda book [64]
+school_book[BOOK_VARDA] =
+{
+ VARDA_LIGHT_VALINOR, VARDA_CALL_ALMAREN, VARDA_EVENSTAR, VARDA_STARKINDLER,
+}
+
+-- Ulmo book [65]
+school_book[BOOK_ULMO] =
+{
+ ULMO_BELEGAER, ULMO_DRAUGHT_ULMONAN, ULMO_CALL_ULUMURI, ULMO_WRATH,
+}
+
+-- Mandos book [66]
+school_book[BOOK_MANDOS] =
+{
+ MANDOS_TEARS_LUTHIEN, MANDOS_SPIRIT_FEANTURI, MANDOS_TALE_DOOM, MANDOS_CALL_HALLS
+} \ No newline at end of file
diff --git a/lib/mods/theme/scpt/stores.lua b/lib/mods/theme/scpt/stores.lua
new file mode 100644
index 00000000..4902c4d0
--- /dev/null
+++ b/lib/mods/theme/scpt/stores.lua
@@ -0,0 +1,161 @@
+-- Whats shops can buy what
+store_buy_list
+{
+ ["General Store"] =
+ {
+ TV_CORPSE,
+ TV_FOOD,
+ TV_LITE,
+ TV_FLASK,
+ TV_SPIKE,
+ TV_SHOT,
+ TV_ARROW,
+ TV_BOLT,
+ TV_DIGGING,
+ TV_CLOAK,
+ TV_BOTTLE,
+ },
+ ["Armoury"] =
+ {
+ TV_BOOTS,
+ TV_GLOVES,
+ TV_CROWN,
+ TV_HELM,
+ TV_SHIELD,
+ TV_CLOAK,
+ TV_SOFT_ARMOR,
+ TV_HARD_ARMOR,
+ TV_DRAG_ARMOR,
+ },
+ ["Weaponsmith"] =
+ {
+ TV_SHOT,
+ TV_BOLT,
+ TV_ARROW,
+ TV_BOOMERANG,
+ TV_BOW,
+ TV_DIGGING,
+ TV_HAFTED,
+ TV_POLEARM,
+ TV_SWORD,
+ TV_AXE,
+ TV_MSTAFF,
+ },
+ -- We use a function because we want to restrict to blessed weapons and god spells
+ ["Temple"] = function (obj)
+ if obj.tval == TV_DRUID_BOOK then return TRUE
+ elseif obj.tval == TV_BOOK and obj.sval == 255 and (can_spell_random(obj.pval) == SKILL_SPIRITUALITY) then return TRUE
+ elseif obj.tval == TV_SCROLL then return TRUE
+ elseif obj.tval == TV_POTION2 then return TRUE
+ elseif obj.tval == TV_POTION then return TRUE
+ elseif obj.tval == TV_HAFTED then return TRUE
+ elseif obj.tval == TV_POLEARM and is_blessed(obj) == TRUE then return TRUE
+ elseif obj.tval == TV_SWORD and is_blessed(obj) == TRUE then return TRUE
+ elseif obj.tval == TV_AXE and is_blessed(obj) == TRUE then return TRUE
+ elseif obj.tval == TV_BOOMERANG and is_blessed(obj) == TRUE then return TRUE
+ end
+ end,
+ ["Alchemy shop"] =
+ {
+ TV_SCROLL,
+ TV_POTION2,
+ TV_POTION,
+ TV_BATERIE,
+ TV_BOTTLE,
+ },
+ -- We use a function because we dont want god spells
+ ["Magic shop"] = function (obj)
+ local buy =
+ {
+ [TV_SYMBIOTIC_BOOK] = TRUE,
+ [TV_AMULET] = TRUE,
+ [TV_RING] = TRUE,
+ [TV_STAFF] = TRUE,
+ [TV_WAND] = TRUE,
+ [TV_ROD] = TRUE,
+ [TV_ROD_MAIN] = TRUE,
+ [TV_SCROLL] = TRUE,
+ [TV_POTION2] = TRUE,
+ [TV_POTION] = TRUE,
+ [TV_MSTAFF] = TRUE,
+ [TV_RANDART] = TRUE,
+ }
+
+ if obj.tval == TV_BOOK and obj.sval == 255 and (can_spell_random(obj.pval) == SKILL_MAGIC) then return TRUE
+ elseif obj.tval == TV_BOOK and obj.sval ~= 255 then return TRUE
+ elseif buy[obj.tval] == TRUE then return TRUE
+ end
+ end,
+ -- Black markets wants ALL!
+ ["Black Market"] = function (obj)
+ return TRUE
+ end,
+ ["Book Store"] =
+ {
+ TV_BOOK,
+ TV_SYMBIOTIC_BOOK,
+ TV_MUSIC_BOOK,
+ TV_DAEMON_BOOK,
+ TV_DRUID_BOOK,
+ },
+ ["Pet Shop"] =
+ {
+ TV_EGG,
+ },
+-- Theme stores
+
+ ["Hunting Supply Store"] =
+ {
+ TV_TRAPKIT,
+ TV_BOOMERANG,
+ TV_SHOT,
+ TV_BOLT,
+ TV_ARROW,
+ TV_BOW,
+ TV_POTION2,
+ },
+
+ ["Runic Magic Shop"] =
+ {
+ TV_RUNE1,
+ TV_RUNE2,
+ },
+
+ ["Construction Supply Store"] =
+ {
+ TV_LITE,
+ TV_DIGGING,
+ },
+
+ ["Music Store"] =
+ {
+ TV_INSTRUMENT,
+ },
+}
+
+-- Take care to have Magic shop/Temple have specific spells only
+add_hooks
+{
+ [HOOK_STORE_STOCK] = function (index, name, level)
+ if name == "Magic shop" then
+ -- Books
+ if magik(20) == TRUE then
+ object_prep(obj_forge, lookup_kind(TV_BOOK, 255))
+ local spell = get_random_spell(SKILL_MAGIC, 20)
+ if spell > -1 then
+ obj_forge.pval = spell
+ return TRUE, obj_forge
+ end
+ end
+ elseif name == "Temple" then
+ if magik(20) == TRUE then
+ object_prep(obj_forge, lookup_kind(TV_BOOK, 255))
+ local spell = get_random_spell(SKILL_SPIRITUALITY, 20)
+ if spell > -1 then
+ obj_forge.pval = spell
+ return TRUE, obj_forge
+ end
+ end
+ end
+ end,
+}
diff --git a/lib/mods/theme/theme.txt b/lib/mods/theme/theme.txt
new file mode 100644
index 00000000..f85ba157
--- /dev/null
+++ b/lib/mods/theme/theme.txt
@@ -0,0 +1,313 @@
+Chronological list of changes made in Theme module.
+
+Detailed list: http://www.zionmainframe.ca/tome/theme/changes.html
+Known bugs: http://www.zionmainframe.ca/tome/theme/bugs.html
+Credits: http://www.zionmainframe.ca/tome/theme/credits.html
+
+Theme 0.0.1 AKA "The Beginning"
+
+ - 20 new terrain features
+ - removed Alchemy [the class, the skill, and the Artifact Creation ability]
+ - removed DeathMolds [replaced with Dragons from Annals of Ea]
+ - Morgoth's corrupted races may no longer play as Lost Souls
+ - changed the intro screen and wording
+ - removed access to the Lost Hobbit quest (NEVER_GENE to both Proudfoots)
+
+Theme 0.0.2 AKA "Object Mayhem"
+
+ - removed all items relating to alchemy and portable hole
+ - changed many descriptions and item names
+ - fountainized more potions
+ - Greater Ration of Health and the Potion of Learning are no longer artifacts, but more rare.
+ - rings and amulets are all indestructible now
+ - amulets of Devotion are blessed
+ - Adamantite rods are now Tilkal rods and more rare
+ - Espadons must be wielded two-handed
+ - the Bardiche replaces the Basillard
+ - Adamantite armour is now Galvorn
+ - Paper Armour makes wearer sensitive to fire; Fur cloaks grant cold resistance.
+ - Rhino Hide Armour became Mumak Hide Armour
+ - Golden Ring Mail replaces Stone and Hide Armour
+ - adjusted leather jacket, renamed to leather jerkin
+
+Theme 0.0.3 AKA "Wordsmith"
+
+ - new rumours
+ - revamped list of silly monster names
+ - junkarts got a total facelift
+ - monster speech made more thematic all across the board
+ - more thematic last words (both monsters and player)
+
+Theme 0.0.4 AKA "Monstervore"
+(veteran *banders beware: many, many changes to monsters. Read the detailed list, the starting parchment, or take extra time to look around. 'Monstervore' is about right for the version name, in fact.)
+
+ - more neutral monsters all across the board
+ - Zangband and CthAngband monsters are gone, joke monsters greatly revamped.
+ - Angels, icky things, centipedes, and kobolds are gone.
+ - many colour changes to reduce confusion, different monsters should be easier to, uh, differentiate
+ - gnomes, leprechauns, and lizard men are now using the 'l' symbol instead of 'h'
+ - dwarves use the 'k' symbol instead of 'h'
+ - wainriders, black numenoreans, and oathbreakers are in, knights of all kinds are out.
+ - none of the 'cold' variety dragons have flight
+ - mature non-aquatic dragons have been renamed to drakes
+ - great wyrms are now great worms
+ - baby dragons are hatchling dragons
+ - Smaug no longer erroneously described as an 'uruloki' - uruloki can't fly.
+ - Nazgul are all represented by the letter N now (too many dark gray Ws as it is)
+ - renamed some uniques to be more in-theme
+ - Huan and Shadowfax are now neutral
+ - brought back aquatic elven warriors (friend), aquatic elven mages (friend), Headless, and mermaids from Z.
+ - completely new set of demons (major and minor) all in-theme, replacing the old D&D demons.
+ - the White Balrog renamed and re-described to avoid confusion due to the above.
+ - minotaurs, maulotaurs, and hippocampi are gone. The unique Maze guardian stays.
+
+Theme 0.0.5 AKA "Artifactual"
+
+ - removed joke artifacts, many ammo artifacts, the phial of undeath, and toris mejistos
+ - changed many artifact names
+ - broadened some descriptions
+ - Gurthang renamed to Angalachel (detailed explanation in changelog.txt)
+ - The sword formerly known as Vorpal Blade is sentient
+ - Sting is a short sword, not small sword
+ - Anduril now resists being shattered by Morgul beings.
+ - Angrist is a broken dagger and gives a luck bonus.
+ - Theoden King had a sword, not an axe. That axe is now of Dain Ironfoot.
+
+Theme 0.0.6 AKA "Brave New World"
+
+ - wilderness map corrected a lot to fit the Middle-Earth map, dungeon locations have changed considerably.
+ - some places on the map have names now, so you can wander through Rivendell, the Brown Lands, Udun, etc.
+ - three words: the Dead Marshes. Avoid 'em.
+ - some dungeons renamed; many new terrain features.
+ - in general, the wilderness is a lot more dangerous to travel (thanks to BlackSmurf for the inspiration).
+ - Angband levels 101-127 separated out into Utumno.
+ - 7 new dungeons, all with a final guardian and guaranteed artifact or randart.
+ - random towns in Cirith Ungol, Blue Mountains, Dol Amroth, Near Harad.
+ - Gondolin map tweaked a bit to suit new location.
+ - Lothlorien has been renamed to Caras Galadhon.
+
+Theme 0.0.7 AKA "The Forge"
+
+ - 16 new item types, some from T-Plus, some as suggested in the forum, others my own - mostly for 'game flavour' [no pun intended :-)]
+ - 37 new ego-types, many from T-Plus and Annals of Ea
+ - 35 new artifacts, many from T-Plus, some from Annals of Ea, some implemented based on forum suggestions
+ - 6 new item sets, one of my own, one from T-Plus, others as suggested in the forum
+ - over 200 new monsters:
+ - centipedes replaced by 9 types of cattle and one unique (Boar of Everholt)
+ - icky things replaced by mewlips (undead things of hobbit-lore), 14 types
+ - 59 new uniques (8 are unkillable, wilderness-only Valar, 8 are joke monsters)
+
+Theme 0.0.8 AKA "Gone to Town"
+
+ - numerous bug fixes, refer to changelog.txt for details
+ - 4 new artifacts, 4 new sets, 3 new ego types, some item and monster tweaks
+ - 14 new terrain features for town use
+ - 12 new towns, of these 7 are not visible on the wilderness map (all have parchments)
+ - Caras Galadhon map redone completely, Gondolin map tweaked to suit new location
+ - 'Rest for the night' option available for free in player home and some thematic locations
+ - 8 new store types
+ - rewritten store owner list
+
+Theme 0.0.9 AKA "Out, Out, Damned Spot!"
+
+ - a bugfix release on the heels of ToME 2.2.7; see changelog.txt for details
+ - Player can now push past neutral monsters, thanks to a lua script written by BauMog
+ - Bjorn (a joke unique based on a DiTLer) replaces Varda
+ - Player can get free dinner at some thematic locations where player race is liked
+ - Increased quality of rods at the magic rod market
+ - The Valar have an equal number of non-spoiler lines now.
+ - Renumbered the planned releases (see below)
+ - From now on bugfix releases will always come separately.
+
+Theme 0.1.0 AKA "A Farewell to Kobolds"
+
+ - several bugfixes, see changelog.txt for details
+ - only in-theme races can now be Lost Souls: Eldar and Maiar. I put half-elves among them too, as there's conflicting information on whether half-elves made it to the Halls of Mandos or not.
+ - thematised Maiar, Ents, Hobbits, Dwarves, and Wood Elves.
+ - 4 new races: Druedain (replace Kobolds), Easterlings, Roeg (minor demons), Eagles (replace Thunderlords)
+ - 6 dragon subraces
+ - 10 demon subraces
+ - Beefed up Rangers and removed ability to worship anyone but Melkor from Demonologists and Necromancers.
+ - 7 new subclasses
+
+Theme 0.1.1 AKA "Sleeping Awake"
+
+ - several bugfixes, see changelog.txt for details
+ - some tweaks to the Clairvoyants, Ascetics, and Mercenaries
+ - a new joke monster, and more monspeak.txt lines
+ - 3 new ego types
+ - some preliminary changes to lua scripts, mostly stuff from the ToME Script library and T-Plus
+
+Theme 0.1.2 AKA "Friends and Neighbours"
+
+ - a player/monster race alignment scheme based on the T-Plus code for Angel alignments
+
+Theme 0.1.3 AKA "Odds and Ends"
+
+ - tweaks to various info files
+ - added 6 Dwarven Rings of Power
+
+Theme 0.1.4 AKA "Milk and Bones"
+
+ - two lua scriptlets for players who like Ammo creation but don't like scumming for junk
+ - two lua scriptlets for some thematic fun
+
+Theme 0.5.0 AKA "Eternity of Stars"
+
+ - removed weapons belonging to the Valar from a_info (changed names)
+ - renamed existing Eternity items
+ - added 8 new Ultimate items for the Void-divers
+
+Theme 1.0.0 AKA "Shiny and New"
+
+ - Four new Valar: Varda, Aule, Ulmo, Mandos. All with their own magic schools, priest classes, and quest temples.
+ - Fully documented all the changes so far for the ingame help.
+ - Some monster and item tweaks.
+ - Numerous tweaks to the new races and classes.
+ - The Pacifists are now a class alongside warriors, mages, and priests - there are two subclasses.
+
+Theme 1.0.1. AKA "Khazad aimenu!"
+
+ - Fixed some God-related issues
+ - Some miscellaneous cosmetic fixes
+ - Updated automatiser file to work regardless of object flavour display
+ - 4 new axe types from T-Plus
+ - New ego magestaff
+
+Theme 1.0.2. AKA "Order of the Swan"
+
+ - Fixed the Elemental Mastery ego-type
+ - God quest fixes
+ - 3 new ego types, 2 new artifacts, and 1 new item set
+ - Fog on the Barrow-Downs is back, toned down.
+ - New monster: Knight of the Swan (white 'p')
+ - Mithril armour adapted from T-Plus
+
+Theme 1.0.3 AKA "Old and New"
+
+ - New special level in Erebor
+ - New amulet ego-type
+ - Axed the Rustproof and of Valour ego-types
+ - Tweaked Ranger class further
+ - (2.3.0 CVS) Axed several out-of-theme artifacts to make room for new ones from ToME3
+ - (2.3.0 CVS) War-mage class (T-Plus) is useless with the new Mage class, removed
+
+Theme 1.0.4 AKA "Jocos Et Dii Amant"
+
+ - Ulmo now dislikes the player using fire magic and Orc players (Thanks to LogrusMage)
+ - Fixed the monster flag problem which caused lua errors in Ulmo's temple dungeon
+ - Commented out Nienna and Orome in r_info
+
+Theme 1.0.5 AKA "As You Like It"
+
+ - New tiles for terrain and objects
+ - Pref file for 16x16 tileset uses ASCII characters for the *missing* monsters
+ - Pref file for 8x8 tileset uses ASCII characters for *all* monsters.
+
+Theme 1.0.6 AKA "Flame of Udun"
+
+ - Fixed a bug that prevented Ulmo from working properly
+ - Re-added the Maia restrictions for corruptions
+ - Added some new corruptions (from MM's script)
+
+Theme 1.0.7 AKA "All Shall Wait"
+
+ - Monster tiles and pref files done
+ - Renamed *thanc daggers
+ - Renamed Halls of Mandos and lifted the elves-only restrictions.
+ - Thror's map is now actually a map
+ - More corruptions from MM's script
+ - Added NO_TARGET to monsters that start out neutral
+
+Theme 1.0.8 AKA "To The Keep!"
+
+ - Several small bugfixes
+ - Some documentation updates
+ - Fixed Aule's spells to prevent insane pval increases
+ - (2.3.0 CVS) Several documentation tweaks
+ - (2.3.0 CVS) misc.lua was not called from init.lua
+
+Theme 1.0.9 AKA "Through the Darkness"
+
+ - Several small bugfixes
+ - Several documentation and in-game parchment updates
+ - Pippin's dagger (former *thanc) is now part of another set, too
+ - Graphics package updated, plus .gif files as in 2.3.0
+ - (2.3.0 CVS) Removed museums from all towns but three
+
+Theme 1.1.0 AKA "Forever There"
+
+ - Minor piety-gain tweaks to Ulmo and Melkor
+ - Took away 'normal' magic schools from Thaumaturgists
+ - Mages got .400 in Disarming
+ - Trolls got a bonus to hafted-mastery
+
+Theme 1.1.1 AKA "I Amar Prestar Aen"
+
+ - New special level by Burb Lulls
+ - Some item, monster, artifact, class, and ego tweaks
+ - Fireproofing quest is now for a rune, not potion
+ - Tweaked the Tears of Luthien spell
+
+Theme 1.1.2 AKA "Serpensortia"
+
+ - minor bugfixes/tweaks: items, races, classes
+ - (2.3.0 CVS) fixed the new jewelry crashing bug
+ - (2.3.0 CVS) removed several types of old rings and amulets
+
+Theme 1.1.3 AKA "Phoenix Song"
+
+ - Updated all files from the 2.3.0 (CVS) version to 2.3.1
+ - Removed Peregrin's dagger from the Peregrin's Gear set.
+ - Aule followers should be able to sacrifice self-made items now.
+ - The coordinates for Melkor's god quests have been fixed.
+ - Added more text to the Erebor map and key to make sure player keeps them.
+
+Theme 1.1.4 AKA "Release the River"
+
+ - Updated all files from the 2.3.1 version to 2.3.3
+ - Fixed bugs with maps, sets, jumpgates and quests.
+ - Updated a number of help files on gods and magic.
+ - Retired two ego types and reworked some others.
+ - Retired the Polymorph corruption.
+ - Replaced Carlammas with a new artifact and added a new ring ego type.
+
+Theme 1.1.5 AKA "Angles and Corners"
+
+ - Some feature flag tweaks.
+ - Orc Cave now leads out on the other side of the Misty Mountains.
+ - Two new special levels to accomodate Erebor quest items; new special final level in Isengard.
+ - Eagles' nest in Khazad-dum.
+
+Theme 1.1.6 AKA "Curses to This Mirage"
+
+ - Some monster flag tweaks.
+ - Neutral monsters forced into wilderness.
+ - Fixed player-related bugs with stat gain and starting equipment.
+
+Theme 1.1.7 AKA "Poor Madeleine"
+
+ - Some item tweaks.
+ - Removed several miscellaneous food items.
+ - 5 new item types.
+
+Theme 1.1.8 AKA "Little White Candle"
+
+ - Numerous ego item tweaks.
+ - Renamed several ego types to be more in-theme.
+ - Removed Rings of the Elements to avoid redundancy.
+ - 3 new ego types.
+
+Theme 1.1.9 AKA "Kit Bag Full of Marbles"
+
+ - Several randart tweaks.
+ - FF now offers three additional skills.
+ - Non-elves can no longer be LostSouls.
+ - Flight at birth now means mountain climbing at clvl50
+
+Theme 1.2.0 AKA "Twining Light"
+
+ - Several artifact tweaks.
+ - Removed the dwarven rings of power.
+ - 3 new artifacts.
+ - 1 new item set. \ No newline at end of file
diff --git a/lib/mods/theme/user/all.prf b/lib/mods/theme/user/all.prf
new file mode 100644
index 00000000..4e9dead3
--- /dev/null
+++ b/lib/mods/theme/user/all.prf
@@ -0,0 +1,520 @@
+
+
+# Automatic option dump
+
+# Option 'Rogue-like commands'
+X:rogue_like_commands
+
+# Option 'Activate quick messages'
+Y:quick_messages
+
+# Option 'Prompt for various information'
+X:other_query_flag
+
+# Option 'Prompt before picking things up'
+X:carry_query_flag
+
+# Option 'Use old target by default'
+X:use_old_target
+
+# Option 'Pick things up by default'
+X:always_pickup
+
+# Option 'Prompt before picking up heavy objects'
+Y:prompt_pickup_heavy
+
+# Option 'Repeat obvious commands'
+Y:always_repeat
+
+# Option 'Show dungeon level in feet'
+X:depth_in_feet
+
+# Option 'Merge inscriptions when stacking'
+Y:stack_force_notes
+
+# Option 'Merge discounts when stacking'
+Y:stack_force_costs
+
+# Option 'Show labels in object listings'
+Y:show_labels
+
+# Option 'Show weights in object listings'
+Y:show_weights
+
+# Option 'Show graphics in inventory list'
+Y:show_inven_graph
+
+# Option 'Show graphics in equipment list'
+Y:show_equip_graph
+
+# Option 'Show graphics in stores'
+Y:show_store_graph
+
+# Option 'Show choices in certain sub-windows'
+Y:show_choices
+
+# Option 'Show details in certain sub-windows'
+Y:show_details
+
+# Option 'Audible bell (on errors, etc)'
+X:ring_bell
+
+# Option 'Use color if possible (slow)'
+Y:use_color
+
+# Option 'Run past stairs'
+Y:find_ignore_stairs
+
+# Option 'Run through open doors'
+Y:find_ignore_doors
+
+# Option 'Run past known corners'
+Y:find_cut
+
+# Option 'Run into potential corners'
+Y:find_examine
+
+# Option 'Disturb whenever any monster moves'
+X:disturb_move
+
+# Option 'Disturb whenever viewable monster moves'
+Y:disturb_near
+
+# Option 'Disturb whenever map panel changes'
+Y:disturb_panel
+
+# Option 'Disturb whenever leaving trap-detected area'
+Y:disturb_detect
+
+# Option 'Disturb whenever player state changes'
+Y:disturb_state
+
+# Option 'Disturb whenever boring things happen'
+X:disturb_minor
+
+# Option 'Disturb whenever random things happen'
+X:disturb_other
+
+# Option 'Alert user to critical hitpoints'
+Y:alert_hitpoint
+
+# Option 'Alert user to various failures'
+Y:alert_failure
+
+# Option 'Get last words when the character dies'
+Y:last_words
+
+# Option 'Allow shopkeepers and uniques to speak'
+Y:speak_unique
+
+# Option 'No query to destroy known worthless items'
+Y:auto_destroy
+
+# Option 'Confirm to wear/wield known cursed items'
+Y:confirm_wear
+
+# Option 'Prompt before exiting a dungeon level'
+X:confirm_stairs
+
+# Option 'Disturb when visible pets move'
+X:disturb_pets
+
+# Option 'Automatically open doors'
+Y:easy_open
+
+# Option 'Automatically disarm traps'
+Y:easy_disarm
+
+# Option 'Automatically tunnel walls'
+Y:easy_tunnel
+
+# Option 'Auto-haggle in stores'
+Y:auto_haggle
+
+# Option 'Auto-scum for good levels'
+Y:auto_scum
+
+# Option 'Allow weapons and armour to stack'
+Y:stack_allow_items
+
+# Option 'Allow wands/staffs/rods to stack'
+Y:stack_allow_wands
+
+# Option 'Expand the power of the look command'
+Y:expand_look
+
+# Option 'Expand the power of the list commands'
+Y:expand_list
+
+# Option 'Map remembers all perma-lit grids'
+Y:view_perma_grids
+
+# Option 'Map remembers all torch-lit grids'
+Y:view_torch_grids
+
+# Option 'Allow some monsters to carry light'
+Y:monster_lite
+
+# Option 'Generate dungeons with aligned rooms'
+Y:dungeon_align
+
+# Option 'Generate dungeons with connected stairs'
+Y:dungeon_stair
+
+# Option 'Monsters chase current location (v.slow)'
+X:flow_by_sound
+
+# Option 'Use special symbols for the player char'
+X:player_symbols
+
+# Option 'Plain object descriptions'
+Y:plain_descriptions
+
+# Option 'Monsters learn from their mistakes'
+X:smart_learn
+
+# Option 'Monsters exploit players weaknesses'
+X:smart_cheat
+
+# Option 'Monsters behave stupidly'
+X:stupid_monsters
+
+# Option 'Allow unusually small dungeon levels'
+Y:small_levels
+
+# Option 'Allow empty 'arena' levels'
+Y:empty_levels
+
+# Option 'Reduce lite-radius when running'
+X:view_reduce_lite
+
+# Option 'Reduce view-radius in town'
+X:view_reduce_view
+
+# Option 'Avoid checking for user abort'
+X:avoid_abort
+
+# Option 'Avoid extra shimmering (fast)'
+Y:avoid_shimmer
+
+# Option 'Avoid processing special colors (fast)'
+X:avoid_other
+
+# Option 'Flush input on various failures'
+Y:flush_failure
+
+# Option 'Flush input whenever disturbed'
+X:flush_disturb
+
+# Option 'Flush input before every command'
+X:flush_command
+
+# Option 'Flush output before every command'
+Y:fresh_before
+
+# Option 'Flush output after every command'
+X:fresh_after
+
+# Option 'Flush output after every message'
+X:fresh_message
+
+# Option 'Compress messages in savefiles'
+Y:compress_savefile
+
+# Option 'Hilite the player with the cursor'
+X:hilite_player
+
+# Option 'Use special colors for torch-lit grids'
+X:view_yellow_lite
+
+# Option 'Use special colors for 'viewable' grids'
+X:view_bright_lite
+
+# Option 'Use special colors for wall grids (slow)'
+X:view_granite_lite
+
+# Option 'Use special colors for floor grids (slow)'
+X:view_special_lite
+
+# Option 'Center the view on the player (very slow)'
+X:center_player
+
+# Option 'Ingame contextual help'
+X:ingame_help
+
+# Option 'Show the experience needed for next level'
+X:exp_need
+
+# Option 'Use the old(Z) coloring scheme(reload the game)'
+X:old_colors
+
+# Option 'Automatically clear '-more-' prompts'
+X:auto_more
+
+# Option 'Player char represent his/her health'
+Y:player_char_health
+
+# Option 'Stats are represented in a linear way'
+Y:linear_stats
+
+# Option 'In option windows, just omit the select char'
+X:inventory_no_move
+
+# Option 'Allow objects to stack on floor'
+Y:testing_stack
+
+# Option 'Allow monsters to carry objects'
+Y:testing_carry
+
+# Window 'Mirror', Flag 'Display inven/equip'
+W:1:0:0
+
+# Window 'Mirror', Flag 'Display equip/inven'
+W:1:1:0
+
+# Window 'Mirror', Flag 'Display character'
+W:1:3:0
+
+# Window 'Mirror', Flag 'Show visible monsters'
+W:1:4:0
+
+# Window 'Mirror', Flag 'Display IRC messages'
+W:1:5:0
+
+# Window 'Mirror', Flag 'Display messages'
+W:1:6:0
+
+# Window 'Mirror', Flag 'Display overhead view'
+W:1:7:0
+
+# Window 'Mirror', Flag 'Display monster recall'
+W:1:8:0
+
+# Window 'Mirror', Flag 'Display object recall'
+W:1:9:0
+
+# Window 'Mirror', Flag 'Display snap-shot'
+W:1:11:0
+
+# Window 'Mirror', Flag 'Display borg messages'
+W:1:14:0
+
+# Window 'Mirror', Flag 'Display borg status'
+W:1:15:0
+
+# Window 'Recall', Flag 'Display inven/equip'
+W:2:0:0
+
+# Window 'Recall', Flag 'Display equip/inven'
+W:2:1:0
+
+# Window 'Recall', Flag 'Display character'
+W:2:3:0
+
+# Window 'Recall', Flag 'Show visible monsters'
+W:2:4:0
+
+# Window 'Recall', Flag 'Display IRC messages'
+W:2:5:0
+
+# Window 'Recall', Flag 'Display messages'
+W:2:6:0
+
+# Window 'Recall', Flag 'Display overhead view'
+W:2:7:0
+
+# Window 'Recall', Flag 'Display monster recall'
+W:2:8:0
+
+# Window 'Recall', Flag 'Display object recall'
+W:2:9:0
+
+# Window 'Recall', Flag 'Display snap-shot'
+W:2:11:0
+
+# Window 'Recall', Flag 'Display borg messages'
+W:2:14:0
+
+# Window 'Recall', Flag 'Display borg status'
+W:2:15:0
+
+# Window 'Choice', Flag 'Display inven/equip'
+W:3:0:0
+
+# Window 'Choice', Flag 'Display equip/inven'
+W:3:1:0
+
+# Window 'Choice', Flag 'Display character'
+W:3:3:0
+
+# Window 'Choice', Flag 'Show visible monsters'
+W:3:4:0
+
+# Window 'Choice', Flag 'Display IRC messages'
+W:3:5:0
+
+# Window 'Choice', Flag 'Display messages'
+W:3:6:0
+
+# Window 'Choice', Flag 'Display overhead view'
+W:3:7:0
+
+# Window 'Choice', Flag 'Display monster recall'
+W:3:8:0
+
+# Window 'Choice', Flag 'Display object recall'
+W:3:9:0
+
+# Window 'Choice', Flag 'Display snap-shot'
+W:3:11:0
+
+# Window 'Choice', Flag 'Display borg messages'
+W:3:14:0
+
+# Window 'Choice', Flag 'Display borg status'
+W:3:15:0
+
+# Window 'Term-4', Flag 'Display inven/equip'
+W:4:0:0
+
+# Window 'Term-4', Flag 'Display equip/inven'
+W:4:1:0
+
+# Window 'Term-4', Flag 'Display character'
+W:4:3:0
+
+# Window 'Term-4', Flag 'Show visible monsters'
+W:4:4:0
+
+# Window 'Term-4', Flag 'Display IRC messages'
+W:4:5:0
+
+# Window 'Term-4', Flag 'Display messages'
+W:4:6:0
+
+# Window 'Term-4', Flag 'Display overhead view'
+W:4:7:0
+
+# Window 'Term-4', Flag 'Display monster recall'
+W:4:8:0
+
+# Window 'Term-4', Flag 'Display object recall'
+W:4:9:0
+
+# Window 'Term-4', Flag 'Display snap-shot'
+W:4:11:0
+
+# Window 'Term-4', Flag 'Display borg messages'
+W:4:14:0
+
+# Window 'Term-4', Flag 'Display borg status'
+W:4:15:0
+
+# Window 'Term-5', Flag 'Display inven/equip'
+W:5:0:0
+
+# Window 'Term-5', Flag 'Display equip/inven'
+W:5:1:0
+
+# Window 'Term-5', Flag 'Display character'
+W:5:3:0
+
+# Window 'Term-5', Flag 'Show visible monsters'
+W:5:4:0
+
+# Window 'Term-5', Flag 'Display IRC messages'
+W:5:5:0
+
+# Window 'Term-5', Flag 'Display messages'
+W:5:6:0
+
+# Window 'Term-5', Flag 'Display overhead view'
+W:5:7:0
+
+# Window 'Term-5', Flag 'Display monster recall'
+W:5:8:0
+
+# Window 'Term-5', Flag 'Display object recall'
+W:5:9:0
+
+# Window 'Term-5', Flag 'Display snap-shot'
+W:5:11:0
+
+# Window 'Term-5', Flag 'Display borg messages'
+W:5:14:0
+
+# Window 'Term-5', Flag 'Display borg status'
+W:5:15:0
+
+# Window 'Term-6', Flag 'Display inven/equip'
+W:6:0:0
+
+# Window 'Term-6', Flag 'Display equip/inven'
+W:6:1:0
+
+# Window 'Term-6', Flag 'Display character'
+W:6:3:0
+
+# Window 'Term-6', Flag 'Show visible monsters'
+W:6:4:0
+
+# Window 'Term-6', Flag 'Display IRC messages'
+W:6:5:0
+
+# Window 'Term-6', Flag 'Display messages'
+W:6:6:0
+
+# Window 'Term-6', Flag 'Display overhead view'
+W:6:7:0
+
+# Window 'Term-6', Flag 'Display monster recall'
+W:6:8:0
+
+# Window 'Term-6', Flag 'Display object recall'
+W:6:9:0
+
+# Window 'Term-6', Flag 'Display snap-shot'
+W:6:11:0
+
+# Window 'Term-6', Flag 'Display borg messages'
+W:6:14:0
+
+# Window 'Term-6', Flag 'Display borg status'
+W:6:15:0
+
+# Window 'Term-7', Flag 'Display inven/equip'
+W:7:0:0
+
+# Window 'Term-7', Flag 'Display equip/inven'
+W:7:1:0
+
+# Window 'Term-7', Flag 'Display character'
+W:7:3:0
+
+# Window 'Term-7', Flag 'Show visible monsters'
+W:7:4:0
+
+# Window 'Term-7', Flag 'Display IRC messages'
+W:7:5:0
+
+# Window 'Term-7', Flag 'Display messages'
+W:7:6:0
+
+# Window 'Term-7', Flag 'Display overhead view'
+W:7:7:0
+
+# Window 'Term-7', Flag 'Display monster recall'
+W:7:8:0
+
+# Window 'Term-7', Flag 'Display object recall'
+W:7:9:0
+
+# Window 'Term-7', Flag 'Display snap-shot'
+W:7:11:0
+
+# Window 'Term-7', Flag 'Display borg messages'
+W:7:14:0
+
+# Window 'Term-7', Flag 'Display borg status'
+W:7:15:0
+
diff --git a/lib/mods/theme/user/automat.atm b/lib/mods/theme/user/automat.atm
new file mode 100644
index 00000000..03e31974
--- /dev/null
+++ b/lib/mods/theme/user/automat.atm
@@ -0,0 +1,667 @@
+-- This automatiser file was created by Feanor for the Annals of Ea module.
+clean_ruleset()
+add_ruleset
+[[
+<rule name="emptychest" type="destroy" module="Theme">
+ <and>
+ <and>
+ <tval>7</tval>
+ </and>
+ <status>empty</status>
+ </and>
+</rule>
+<rule name="junkmushrooms" type="destroy" module="Theme">
+ <and>
+ <tval>80</tval>
+ <sval min="0" max="11"></sval>
+ </and>
+</rule>
+<rule name="junkjewelry" type="destroy" module="Theme">
+ <and>
+ <or>
+ <and>
+ <tval>40</tval>
+ <sval min="0" max="0"></sval>
+ </and>
+ <and>
+ <tval>45</tval>
+ <sval min="0" max="4"></sval>
+ </and>
+ <and>
+ <tval>40</tval>
+ <status>bad</status>
+ </and>
+ <and>
+ <tval>45</tval>
+ <status>bad</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="junkpotions" type="destroy" module="Theme">
+ <and>
+ <not>
+ <ability>Trapping</ability>
+ </not>
+ <or>
+ <and>
+ <tval>71</tval>
+ <sval min="4" max="7"></sval>
+ </and>
+ <and>
+ <tval>71</tval>
+ <sval min="9" max="11"></sval>
+ </and>
+ <and>
+ <tval>71</tval>
+ <sval min="13" max="13">13</sval>
+ </and>
+ <and>
+ <tval>71</tval>
+ <sval min="15" max="21"></sval>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="junkwands" type="destroy" module="Theme">
+ <and>
+ <tval>65</tval>
+ <sval min="24" max="25"></sval>
+ </and>
+</rule>
+<rule name="junkscrolls" type="destroy" module="Theme">
+ <and>
+ <not>
+ <ability>Trapping</ability>
+ </not>
+ <or>
+ <and>
+ <tval>70</tval>
+ <sval min="0" max="0"></sval>
+ <not>
+ <subrace>Vampire</subrace>
+ </not>
+ </and>
+ <and>
+ <tval>70</tval>
+ <sval min="1" max="5"></sval>
+ </and>
+ <and>
+ <tval>70</tval>
+ <sval min="7" max="7"></sval>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="brokendagger" type="destroy" module="Theme">
+ <and>
+ <name>Broken Dagger</name>
+ <or>
+ <status>average</status>
+ <status>bad</status>
+ <status>very bad</status>
+ </or>
+ </and>
+</rule>
+<rule name="magestaffs" type="destroy" module="Theme">
+ <and>
+ <tval>6</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="instruments" type="destroy" module="Theme">
+ <and>
+ <tval>14</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="boomerangs" type="destroy" module="Theme">
+ <and>
+ <tval>15</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="shots" type="destroy" module="Theme">
+ <and>
+ <tval>16</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="35" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="45" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="arrows" type="destroy" module="Theme">
+ <and>
+ <tval>17</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="35" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="45" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="bolts" type="destroy" module="Theme">
+ <and>
+ <tval>18</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="35" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="45" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="missile" type="destroy" module="Theme">
+ <and>
+ <tval>19</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="diggers" type="destroy" module="Theme">
+ <and>
+ <tval>20</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="hafted" type="destroy" module="Theme">
+ <and>
+ <tval>21</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="polearm" type="destroy" module="Theme">
+ <and>
+ <tval>22</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="swords" type="destroy" module="Theme">
+ <and>
+ <tval>23</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="axes" type="destroy" module="Theme">
+ <and>
+ <tval>24</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="boots" type="destroy" module="Theme">
+ <and>
+ <tval>30</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="gloves" type="destroy" module="Theme">
+ <and>
+ <tval>31</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="helms" type="destroy" module="Theme">
+ <and>
+ <tval>32</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="crowns" type="destroy" module="Theme">
+ <and>
+ <tval>33</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="shields" type="destroy" module="Theme">
+ <and>
+ <tval>34</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="cloaks" type="destroy" module="Theme">
+ <and>
+ <tval>35</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="softarmour" type="destroy" module="Theme">
+ <and>
+ <tval>36</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="hardarmour" type="destroy" module="Theme">
+ <and>
+ <tval>37</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="dragonarmour" type="destroy" module="Theme">
+ <and>
+ <tval>38</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="45" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="daemonbooks" type="destroy" module="Theme">
+ <and>
+ <and>
+ <tval>115</tval>
+ <sval min="55" max="57"></sval>
+ </and>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="trapkits" type="destroy" module="Theme">
+ <and>
+ <tval>46</tval>
+ <or>
+ <status>bad</status>
+ <status>very bad</status>
+ </or>
+ </and>
+</rule>
+<rule name="classitems" type="destroy" module="Theme">
+ <or>
+ <and>
+ <tval>9</tval>
+ <and>
+ <not>
+ <skill min="1" max="50">Corpse-preservation</skill>
+ </not>
+ <not>
+ <skill min="1" max="50">Possession</skill>
+ </not>
+ <not>
+ <skill min="1" max="50">Summoning</skill>
+ </not>
+ </and>
+ </and>
+ <and>
+ <or>
+ <tval>104</tval>
+ <tval>105</tval>
+ </or>
+ <not>
+ <skill min="1" max="50">Runecraft</skill>
+ </not>
+ </and>
+ <and>
+ <tval>46</tval>
+ <not>
+ <ability>Trapping</ability>
+ </not>
+ <or>
+ <status>average</status>
+ <status>good</status>
+ </or>
+ </and>
+ <and>
+ <and>
+ <not>
+ <class>Archer</class>
+ </not>
+ <not>
+ <class>Ranger</class>
+ </not>
+ <not>
+ <class>Sniper</class>
+ </not>
+ </and>
+ <tval>11</tval>
+ </and>
+ <and>
+ <and>
+ <not>
+ <class>Archer</class>
+ </not>
+ <not>
+ <class>Ranger</class>
+ </not>
+ <not>
+ <class>Sniper</class>
+ </not>
+ </and>
+ <tval>1</tval>
+ </and>
+ </or>
+</rule>
+]]
diff --git a/lib/mods/theme/user/fierce.atm b/lib/mods/theme/user/fierce.atm
new file mode 100644
index 00000000..c49f7de3
--- /dev/null
+++ b/lib/mods/theme/user/fierce.atm
@@ -0,0 +1,761 @@
+clean_ruleset()
+add_ruleset
+[[
+<rule name="oilflask" type="destroy" module="Theme">
+ <name>flask of oil</name>
+</rule>
+<rule name="emptychest" type="destroy" module="Theme">
+ <and>
+ <and>
+ <tval>7</tval>
+ </and>
+ <status>empty</status>
+ </and>
+</rule>
+<rule name="junkmushrooms" type="destroy" module="Theme">
+ <and>
+ <tval>80</tval>
+ <sval min="0" max="11"></sval>
+ </and>
+</rule>
+<rule name="junkjewelry" type="destroy" module="Theme">
+ <and>
+ <or>
+ <and>
+ <tval>40</tval>
+ <sval min="0" max="0"></sval>
+ </and>
+ <and>
+ <tval>45</tval>
+ <sval min="0" max="4"></sval>
+ </and>
+ <and>
+ <tval>40</tval>
+ <status>bad</status>
+ </and>
+ <and>
+ <tval>45</tval>
+ <status>bad</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="junkpotions" type="destroy" module="Theme">
+ <and>
+ <not>
+ <ability>Trapping</ability>
+ </not>
+ <or>
+ <and>
+ <tval>71</tval>
+ <sval min="4" max="7"></sval>
+ </and>
+ <and>
+ <tval>71</tval>
+ <sval min="9" max="11"></sval>
+ </and>
+ <and>
+ <tval>71</tval>
+ <sval min="13" max="13">13</sval>
+ </and>
+ <and>
+ <tval>71</tval>
+ <sval min="15" max="21"></sval>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="junkwands" type="destroy" module="Theme">
+ <and>
+ <tval>65</tval>
+ <sval min="24" max="25"></sval>
+ </and>
+</rule>
+<rule name="junkscrolls" type="destroy" module="Theme">
+ <and>
+ <not>
+ <ability>Trapping</ability>
+ </not>
+ <or>
+ <and>
+ <tval>70</tval>
+ <sval min="0" max="0"></sval>
+ <not>
+ <subrace>Vampire</subrace>
+ </not>
+ </and>
+ <and>
+ <tval>70</tval>
+ <sval min="1" max="5"></sval>
+ </and>
+ <and>
+ <tval>70</tval>
+ <sval min="7" max="7"></sval>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="brokendagger" type="destroy" module="Theme">
+ <and>
+ <name>Broken Dagger</name>
+ <or>
+ <status>average</status>
+ <status>bad</status>
+ <status>very bad</status>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="magestaffs" type="destroy" module="Theme">
+ <and>
+ <tval>6</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="instruments" type="destroy" module="Theme">
+ <and>
+ <tval>14</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="boomerangs" type="destroy" module="Theme">
+ <and>
+ <tval>15</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="shots" type="destroy" module="Theme">
+ <and>
+ <tval>16</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="35" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="arrows" type="destroy" module="Theme">
+ <and>
+ <tval>17</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="35" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="bolts" type="destroy" module="Theme">
+ <and>
+ <tval>18</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="35" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="missile" type="destroy" module="Theme">
+ <and>
+ <tval>19</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="diggers" type="destroy" module="Theme">
+ <and>
+ <tval>20</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="hafted" type="destroy" module="Theme">
+ <and>
+ <tval>21</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="polearm" type="destroy" module="Theme">
+ <and>
+ <tval>22</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="swords" type="destroy" module="Theme">
+ <and>
+ <tval>23</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="axes" type="destroy" module="Theme">
+ <and>
+ <tval>24</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="boots" type="destroy" module="Theme">
+ <and>
+ <tval>30</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="gloves" type="destroy" module="Theme">
+ <and>
+ <tval>31</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="helms" type="destroy" module="Theme">
+ <and>
+ <tval>32</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="crowns" type="destroy" module="Theme">
+ <and>
+ <tval>33</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="shields" type="destroy" module="Theme">
+ <and>
+ <tval>34</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="cloaks" type="destroy" module="Theme">
+ <and>
+ <tval>35</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="softarmour" type="destroy" module="Theme">
+ <and>
+ <tval>36</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="hardarmour" type="destroy" module="Theme">
+ <and>
+ <tval>37</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="dragonarmour" type="destroy" module="Theme">
+ <and>
+ <tval>38</tval>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="40" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="45" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="49" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="daemonbooks" type="destroy" module="Theme">
+ <and>
+ <and>
+ <tval>115</tval>
+ <sval min="55" max="57"></sval>
+ </and>
+ <or>
+ <and>
+ <level min="0" max="50"></level>
+ <or>
+ <status>very bad</status>
+ <status>bad</status>
+ </or>
+ </and>
+ <and>
+ <level min="15" max="50"></level>
+ <status>average</status>
+ </and>
+ <and>
+ <level min="25" max="50"></level>
+ <status>good</status>
+ </and>
+ <and>
+ <level min="49" max="50"></level>
+ <status>very good</status>
+ </and>
+ </or>
+ </and>
+</rule>
+<rule name="trapkits" type="destroy" module="Theme">
+ <and>
+ <tval>46</tval>
+ <or>
+ <status>bad</status>
+ <status>very bad</status>
+ </or>
+ </and>
+</rule>
+<rule name="classitems" type="destroy" module="Theme">
+ <or>
+ <and>
+ <tval>9</tval>
+ <and>
+ <not>
+ <skill min="1" max="50">Corpse-preservation</skill>
+ </not>
+ <not>
+ <skill min="1" max="50">Possession</skill>
+ </not>
+ <not>
+ <skill min="1" max="50">Summoning</skill>
+ </not>
+ </and>
+ </and>
+ <and>
+ <or>
+ <tval>104</tval>
+ <tval>105</tval>
+ </or>
+ <not>
+ <skill min="1" max="50">Runecraft</skill>
+ </not>
+ </and>
+ <and>
+ <tval>46</tval>
+ <not>
+ <ability>Trapping</ability>
+ </not>
+ <or>
+ <status>average</status>
+ <status>good</status>
+ </or>
+ </and>
+ <and>
+ <and>
+ <not>
+ <class>Archer</class>
+ </not>
+ <not>
+ <class>Ranger</class>
+ </not>
+ <not>
+ <class>Sniper</class>
+ </not>
+ </and>
+ <tval>11</tval>
+ </and>
+ <and>
+ <and>
+ <not>
+ <class>Archer</class>
+ </not>
+ <not>
+ <class>Ranger</class>
+ </not>
+ <not>
+ <class>Sniper</class>
+ </not>
+ </and>
+ <tval>1</tval>
+ </and>
+ </or>
+</rule>
+]]
diff --git a/lib/module.lua b/lib/module.lua
new file mode 100644
index 00000000..e3214205
--- /dev/null
+++ b/lib/module.lua
@@ -0,0 +1,36 @@
+add_module
+{
+ ["name"] = "ToME",
+ ["version"] = { 2, 3, 11 },
+ ["author"] = { "DarkGod", "darkgod@t-o-m-e.net" },
+ ["desc"] = {
+ "The Tales of Middle-earth, the standard and official game.",
+ "You are set on a quest to investigate the old tower of Dol Guldur.",
+ "But who knows what will happen...",
+ },
+
+ ["rand_quest"] = TRUE,
+ ["C_quest"] = TRUE,
+
+ ["base_dungeon"] = 4,
+ ["death_dungeon"] = 28,
+
+ ["astral_dungeon"] = 8,
+ ["astral_wild_x"] = 45,
+ ["astral_wild_y"] = 19,
+
+ ["random_artifact_weapon_chance"] = 30,
+ ["random_artifact_armor_chance"] = 20,
+ ["random_artifact_jewelry_chance"] = 20,
+
+ ["max_plev"] = 50,
+ ["max_skill_overage"] = 4,
+ ["skill_per_level"] = function()
+ return 6
+ end,
+
+ ["mod_savefiles"]=
+ {
+ "ToME",
+ },
+}
diff --git a/lib/note/delete.me b/lib/note/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/note/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/patch/.cvsignore b/lib/patch/.cvsignore
new file mode 100644
index 00000000..d287cd3e
--- /dev/null
+++ b/lib/patch/.cvsignore
@@ -0,0 +1 @@
+debug
diff --git a/lib/patch/delete.me b/lib/patch/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/patch/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/pref/422color.prf b/lib/pref/422color.prf
new file mode 100644
index 00000000..309c36b0
--- /dev/null
+++ b/lib/pref/422color.prf
@@ -0,0 +1,909 @@
+# Agent of the black market
+R:14:0x08:0x74
+
+# Mean-looking mercenary
+R:17:0x0c:0x74
+
+# Battle-scarred veteran
+R:18:0x04:0x74
+
+# Small kobold
+R:29:0x0d:0x6b
+
+# Kobold
+R:30:0x05:0x6b
+
+# Floating eye
+R:32:0x06:0x65
+
+# Fruit bat
+R:37:0x0a:0x62
+
+# Blubbering icky thing
+R:41:0x05:0x69
+
+# Metallic green centipede
+R:42:0x0d:0x63
+
+# Novice warrior
+R:43:0x0f:0x70
+
+# Novice rogue
+R:44:0x08:0x70
+
+# Novice priest
+R:45:0x0e:0x70
+
+# Novice mage
+R:46:0x0c:0x70
+
+# Smeagol
+R:63:0x07:0x68
+
+# Metallic blue centipede
+R:67:0x0e:0x63
+
+# Metallic red centipede
+R:77:0x0c:0x63
+
+# Novice ranger
+R:83:0x05:0x70
+
+# Snotling
+R:87:0x0d:0x6f
+
+# Skeleton kobold
+R:91:0x01:0x73
+
+# Novice mage
+R:93:0x0c:0x70
+
+# Giant leech
+R:95:0x0a:0x77
+
+# Large kobold
+R:102:0x01:0x6b
+
+# Novice priest
+R:109:0x0e:0x70
+
+# Novice warrior
+R:110:0x0f:0x70
+
+# Novice rogue
+R:116:0x08:0x70
+
+# Snaga
+R:118:0x0d:0x6f
+
+# Giant pink frog
+R:121:0x0c:0x52
+
+# Cave orc
+R:126:0x0f:0x6f
+
+# Manes
+R:128:0x0c:0x75
+
+# Red naga
+R:130:0x0c:0x6e
+
+# Red jelly
+R:131:0x0c:0x6a
+
+# Green icky thing
+R:132:0x0d:0x69
+
+# Lost soul
+R:133:0x07:0x47
+
+# Mughash, the Kobold Lord
+R:135:0x06:0x6b
+
+# Skeleton orc
+R:136:0x01:0x73
+
+# Wormtongue, Agent of Saruman
+R:137:0x08:0x70
+
+# Nurgling
+R:139:0x0f:0x75
+
+# Lagduf, the Snaga
+R:140:0x07:0x6f
+
+# Novice ranger
+R:142:0x05:0x70
+
+# Giant salamander
+R:143:0x04:0x52
+
+# Lemure
+R:148:0x03:0x75
+
+# Hill orc
+R:149:0x02:0x6f
+
+# Bandit
+R:150:0x08:0x70
+
+# Orc shaman
+R:162:0x06:0x6f
+
+# Baby blue dragon
+R:163:0x0e:0x64
+
+# Baby white dragon
+R:164:0x09:0x64
+
+# Baby green dragon
+R:165:0x0d:0x64
+
+# Baby red dragon
+R:167:0x0c:0x64
+
+# Giant red ant
+R:168:0x0c:0x61
+
+# Brodda, the Easterling
+R:169:0x03:0x70
+
+# Giant spider
+R:175:0x02:0x53
+
+# Dark elven mage
+R:178:0x0a:0x68
+
+# Kamikaze yeek
+R:179:0x07:0x79
+
+# Dark elven warrior
+R:182:0x08:0x68
+
+# Sand-dweller
+R:183:0x0f:0x75
+
+# Clear mushroom patch
+R:184:0x01:0x2c
+
+# Grishnakh, the Hill Orc
+R:186:0x07:0x6f
+
+# Hairy mold
+R:190:0x0f:0x6d
+
+# Grizzly bear
+R:191:0x07:0x71
+
+# Pseudo dragon
+R:193:0x0a:0x64
+
+# Giant fruit fly
+R:197:0x0f:0x49
+
+# Golfimbul, the Hill Orc Chief
+R:215:0x07:0x6f
+
+# Swordsman
+R:216:0x0f:0x70
+
+# Priest
+R:225:0x0e:0x70
+
+# Dark elven priest
+R:226:0x06:0x68
+
+# Skeleton human
+R:228:0x01:0x73
+
+# Moaning spirit
+R:231:0x0f:0x47
+
+# Stegocentipede
+R:232:0x06:0x63
+
+# Spotted jelly
+R:233:0x02:0x6a
+
+# Illusionist
+R:240:0x0a:0x70
+
+# Druid
+R:241:0x05:0x70
+
+# Ochre jelly
+R:245:0x0b:0x6a
+
+# Vlasta
+R:249:0x06:0x52
+
+# Snaga sapper
+R:251:0x0d:0x6f
+
+# Flesh golem
+R:256:0x03:0x67
+
+# Dark naga
+R:265:0x08:0x6e
+
+# Giant tarantula
+R:275:0x0d:0x53
+
+# Giant clear centipede
+R:276:0x01:0x63
+
+# Mirkwood spider
+R:277:0x07:0x53
+
+# Umber hulk
+R:283:0x07:0x58
+
+# Orc captain
+R:285:0x05:0x6f
+
+# Gelatinous cube
+R:286:0x0e:0x6a
+
+# Lizard man
+R:290:0x0c:0x68
+
+# Ulfast, Son of Ulfang
+R:291:0x03:0x70
+
+# Quasit
+R:294:0x09:0x75
+
+# Imp
+R:296:0x04:0x75
+
+# Forest troll
+R:297:0x0d:0x54
+
+# Giant red scorpion
+R:304:0x0c:0x53
+
+# Earth spirit
+R:305:0x0f:0x45
+
+# Fire spirit
+R:306:0x0c:0x45
+
+# Cold hound
+R:308:0x09:0x5a
+
+# Energy hound
+R:309:0x0b:0x5a
+
+# Uruk
+R:313:0x01:0x6f
+
+# Shagrat, the Orc Captain
+R:314:0x07:0x6f
+
+# Gorbag, the Orc Captain
+R:315:0x07:0x6f
+
+# Stone giant
+R:321:0x02:0x50
+
+# Giant black dragon fly
+R:322:0x08:0x46
+
+# Stone golem
+R:323:0x02:0x67
+
+# Ghast
+R:327:0x0f:0x7a
+
+# Bolg, Son of Azog
+R:330:0x0c:0x6f
+
+# Lizard king
+R:332:0x0c:0x68
+
+# Wyvern
+R:334:0x0d:0x64
+
+# Air hound
+R:338:0x0e:0x5a
+
+# Quylthulg
+R:342:0x09:0x51
+
+# Dark elven lord
+R:348:0x08:0x68
+
+# Cloud giant
+R:349:0x0e:0x50
+
+# Ugluk, the Uruk
+R:350:0x07:0x6f
+
+# Blue dragon bat
+R:351:0x0e:0x62
+
+# Water vortex
+R:355:0x06:0x76
+
+# Cold vortex
+R:358:0x09:0x76
+
+# Energy vortex
+R:359:0x0b:0x76
+
+# Mummified orc
+R:362:0x07:0x7a
+
+# Serpent man
+R:364:0x05:0x4a
+
+# Killer stag beetle
+R:366:0x02:0x4b
+
+# Iron golem
+R:367:0x09:0x67
+
+# Azog, King of the Uruk-Hai
+R:373:0x04:0x6f
+
+# Master rogue
+R:376:0x08:0x70
+
+# Angamaite of Umbar
+R:380:0x07:0x70
+
+# Forest wight
+R:381:0x0d:0x57
+
+# 4-headed hydra
+R:387:0x0f:0x4d
+
+# Mummified human
+R:390:0x0f:0x7a
+
+# Sangahyando of Umbar
+R:392:0x03:0x70
+
+# Banshee
+R:394:0x09:0x47
+
+# Pukelman
+R:398:0x07:0x67
+
+# Disenchanter beast
+R:399:0x01:0x71
+
+# Stone troll
+R:401:0x08:0x54
+
+# Troll priest
+R:403:0x06:0x54
+
+# Khufu, the Mummified King
+R:409:0x07:0x7a
+
+# Beast of Nurgle
+R:422:0x03:0x71
+
+# Creeping adamantite coins
+R:423:0x0a:0x24
+
+# Algroth
+R:424:0x02:0x54
+
+# Flamer of Tzeentch
+R:425:0x0c:0x2c
+
+# Vibration hound
+R:428:0x0f:0x5a
+
+# Ogre mage
+R:430:0x03:0x4f
+
+# Lokkak, the Ogre Chieftain
+R:431:0x05:0x4f
+
+# Colbran
+R:435:0x06:0x67
+
+# Spirit naga
+R:436:0x0e:0x6e
+
+# Corpser
+R:437:0x05:0x2c
+
+# Black knight
+R:442:0x08:0x70
+
+# Clairvoyant
+R:445:0x0e:0x70
+
+# Basilisk
+R:453:0x08:0x52
+
+# Aklash
+R:463:0x09:0x54
+
+# Skeleton troll
+R:465:0x01:0x73
+
+# Shadow drake
+R:471:0x08:0x64
+
+# Manticore
+R:472:0x03:0x48
+
+# Killer slicer beetle
+R:474:0x03:0x4b
+
+# Gug
+R:476:0x08:0x50
+
+# Death watch beetle
+R:478:0x0e:0x4b
+
+# Doombat
+R:484:0x06:0x62
+
+# Ninja
+R:485:0x08:0x70
+
+# Storm giant
+R:487:0x06:0x50
+
+# Bokrug
+R:489:0x05:0x52
+
+# Half-troll
+R:491:0x03:0x54
+
+# Bert the Stone Troll
+R:493:0x09:0x54
+
+# Bill the Stone Troll
+R:494:0x09:0x54
+
+# Tom the Stone Troll
+R:495:0x09:0x54
+
+# Barrow wight
+R:499:0x09:0x57
+
+# Law drake
+R:502:0x09:0x64
+
+# Balance drake
+R:503:0x02:0x64
+
+# Groo, the Wanderer
+R:505:0x03:0x70
+
+# Spectre
+R:508:0x0d:0x47
+
+# Cherub
+R:511:0x09:0x41
+
+# Master thief
+R:516:0x08:0x70
+
+# Lich
+R:518:0x01:0x4c
+
+# Master vampire
+R:520:0x02:0x56
+
+# Oriental vampire
+R:521:0x05:0x56
+
+# Greater mummy
+R:522:0x09:0x7a
+
+# Eog golem
+R:530:0x08:0x67
+
+# Dagashi
+R:532:0x0b:0x70
+
+# Smoke elemental
+R:537:0x08:0x45
+
+# Olog
+R:538:0x05:0x54
+
+# Gravity hound
+R:540:0x02:0x5a
+
+# Acidic cytoplasm
+R:541:0x0d:0x6a
+
+# Ooze elemental
+R:545:0x0f:0x45
+
+# Young black dragon
+R:546:0x08:0x64
+
+# Xorn
+R:550:0x03:0x58
+
+# Colossus
+R:558:0x0b:0x67
+
+# Bodak
+R:566:0x08:0x75
+
+# Lorgan, Chief of the Easterlings
+R:573:0x0c:0x70
+
+# Chaos spawn
+R:574:0x07:0x65
+
+# Crypt thing
+R:577:0x0e:0x4c
+
+# Will o' the wisp
+R:582:0x0b:0x45
+
+# Crystal drake
+R:591:0x0e:0x64
+
+# Mature black dragon
+R:592:0x08:0x64
+
+# Draebor, the Imp
+R:595:0x05:0x75
+
+# Mother Hydra
+R:596:0x05:0x75
+
+# Death knight
+R:597:0x02:0x70
+
+# Time vortex
+R:599:0x0d:0x76
+
+# Shimmering vortex
+R:600:0x0a:0x76
+
+# Beholder
+R:603:0x05:0x65
+
+# Emperor wight
+R:604:0x0b:0x57
+
+# Vargo, Tyrant of Fire
+R:606:0x0c:0x45
+
+# Nether wraith
+R:612:0x0c:0x57
+
+# Waldern, King of Water
+R:615:0x02:0x45
+
+# Ettin
+R:621:0x0b:0x54
+
+# Night mare
+R:622:0x0a:0x71
+
+# Ancient black dragon
+R:624:0x08:0x44
+
+# Shadowfax, steed of Gandalf
+R:629:0x09:0x71
+
+# Spirit troll
+R:630:0x0a:0x47
+
+# War troll
+R:631:0x05:0x54
+
+# Rotting quylthulg
+R:633:0x0f:0x51
+
+# 9-headed hydra
+R:635:0x03:0x4d
+
+# Enchantress
+R:636:0x0b:0x70
+
+# Sorcerer
+R:638:0x03:0x70
+
+# Xaren
+R:639:0x0b:0x58
+
+# Medusa, the Gorgon
+R:642:0x03:0x6e
+
+# Death drake
+R:643:0x07:0x44
+
+# Great crystal drake
+R:646:0x0e:0x44
+
+# Wyrd sister
+R:647:0x0b:0x70
+
+# Death quasit
+R:649:0x01:0x75
+
+# Fallen angel
+R:652:0x08:0x41
+
+# Judge Fire
+R:654:0x04:0x73
+
+# Master lich
+R:658:0x09:0x4c
+
+# Eol, the Dark Elf
+R:660:0x02:0x68
+
+# Undead beholder
+R:664:0x02:0x65
+
+# Dark young of Shub-Niggurath
+R:677:0x08:0x55
+
+# Dreadmaster
+R:690:0x03:0x47
+
+# Scatha the Worm
+R:692:0x01:0x44
+
+# Zoth-Ommog
+R:695:0x07:0x52
+
+# Grand master thief
+R:696:0x0e:0x70
+
+# Leprechaun fanatic
+R:700:0x08:0x68
+
+# Dracolich
+R:701:0x0e:0x44
+
+# Greater titan
+R:702:0x0a:0x50
+
+# Dracolisk
+R:703:0x04:0x44
+
+# Itangast the Fire Drake
+R:710:0x04:0x44
+
+# Glaurung, Father of the Dragons
+R:715:0x04:0x44
+
+# Behemoth
+R:716:0x05:0x48
+
+# Garm, Guardian of Hel
+R:717:0x07:0x43
+
+# Maulotaur
+R:723:0x07:0x48
+
+# Nether hound
+R:724:0x08:0x5a
+
+# Time hound
+R:725:0x0d:0x5a
+
+# Demonic quylthulg
+R:727:0x0c:0x51
+
+# Ulik the Troll
+R:729:0x03:0x54
+
+# Baphomet the Minotaur Lord
+R:730:0x08:0x48
+
+# Hell knight
+R:731:0x02:0x70
+
+# Old Sorcerer
+R:738:0x0a:0x70
+
+# Keeper of Secrets
+R:746:0x0a:0x48
+
+# Hand druj
+R:748:0x08:0x73
+
+# Eye druj
+R:749:0x08:0x73
+
+# Skull druj
+R:750:0x08:0x73
+
+# Aether vortex
+R:752:0x0e:0x76
+
+# Draconic quylthulg
+R:759:0x0d:0x51
+
+# Fundin Bluecloak
+R:762:0x0d:0x68
+
+# Gabriel, the Messenger
+R:769:0x0a:0x41
+
+# Artsi, the Champion of Chaos
+R:770:0x0d:0x68
+
+# The Cat Lord
+R:777:0x04:0x66
+
+# Vlad Dracula, Prince of Darkness
+R:780:0x06:0x56
+
+# Great Wyrm of Law
+R:784:0x09:0x44
+
+# Great Wyrm of Balance
+R:785:0x02:0x44
+
+# Glaaki
+R:788:0x05:0x7e
+
+# Greater draconic quylthulg
+R:801:0x05:0x51
+
+# Greater rotting quylthulg
+R:802:0x07:0x51
+
+# Omarax the Eye Tyrant
+R:805:0x0b:0x65
+
+# Greater Balrog
+R:807:0x0c:0x55
+
+# Aether hound
+R:811:0x0e:0x5a
+
+# Yig, Father of Serpents
+R:814:0x05:0x4a
+
+# Hela, Queen of the Dead
+R:817:0x05:0x70
+
+# Master quylthulg
+R:821:0x06:0x51
+
+# Qlzqqlzuup, the Lord of Flesh
+R:822:0x0e:0x51
+
+# F'lar, rider of the Bronze Mnementh
+R:824:0x08:0x44
+
+# Cyaegha
+R:826:0x08:0x65
+
+# Pazuzu, Lord of Air
+R:827:0x01:0x55
+
+# Cantoras, the Skeletal Lord
+R:830:0x0e:0x73
+
+# Godzilla
+R:832:0x05:0x52
+
+# Loki, the Trickster
+R:835:0x05:0x50
+
+# Lungorthin, the Balrog of White Fire
+R:839:0x01:0x55
+
+# Draugluin, Sire of All Werewolves
+R:840:0x07:0x43
+
+# Vecna, the Emperor Lich
+R:844:0x0b:0x4c
+
+# Great Wyrm of Power
+R:847:0x0b:0x44
+
+# Nodens, Lord of the Great Abyss
+R:849:0x01:0x50
+
+# Jormungand the Midgard Serpent
+R:854:0x05:0x4a
+
+# The Destroyer
+R:855:0x09:0x67
+
+# Gothmog, the High Captain of Balrogs
+R:856:0x0c:0x55
+
+# Sauron, the Sorcerer
+R:860:0x03:0x70
+
+# Human Warrior
+R:863:0x01:0x70
+
+# Elven archer
+R:864:0x0d:0x68
+
+# Death
+R:875:0x02:0x47
+
+# Famine
+R:876:0x02:0x47
+
+# Pestilence
+R:877:0x02:0x47
+
+# War
+R:878:0x02:0x47
+
+# Giant piranha
+R:884:0x0d:0x7e
+
+# Octopus
+R:891:0x02:0x7e
+
+# Giant octopus
+R:892:0x0a:0x7e
+
+# Drowned soul
+R:895:0x02:0x47
+
+# Devilfish
+R:920:0x0a:0x7e
+
+# Undead devilfish
+R:921:0x0a:0x7e
+
+# Gandalf the Grey
+R:935:0x0a:0x70
+
+# Brown Firelizard
+R:942:0x0f:0x64
+
+# Bronze Firelizard
+R:943:0x01:0x64
+
+# Elder aranea
+R:964:0x04:0x53
+
+# Bullroarer the Hobbit
+R:985:0x06:0x68
+
+# Hezrou
+R:992:0x0a:0x55
+
+# Glabrezu
+R:993:0x03:0x55
+
+# Lesser Balrog
+R:996:0x0c:0x55
+
+# The Rat King
+R:1006:0x07:0x72
+
+# Vort the Kobold Queen
+R:1007:0x06:0x6b
+
+# Fire Phantom
+R:1009:0x0c:0x47
+
+# Bone golem
+R:1013:0x08:0x67
+
+# Snake of Yig
+R:1014:0x04:0x4a
+
+# Cultist
+R:1017:0x0e:0x70
+
+# Cult leader
+R:1018:0x06:0x70
+
+# Green dragon worm
+R:1025:0x05:0x77
+
+# Red dragon worm
+R:1027:0x04:0x77
+
diff --git a/lib/pref/colors.prf b/lib/pref/colors.prf
new file mode 100644
index 00000000..fa4d3f05
--- /dev/null
+++ b/lib/pref/colors.prf
@@ -0,0 +1,53 @@
+
+
+# Color redefinitions
+
+# Color 'White'
+V:1:0x07:0xFF:0xFF:0xFF
+
+# Color 'Slate'
+V:2:0x03:0x8C:0x8C:0x8C
+
+# Color 'Orange'
+V:3:0x0C:0xFF:0x77:0x00
+
+# Color 'Red'
+V:4:0x04:0xC9:0x00:0x00
+
+# Color 'Green'
+V:5:0x02:0x00:0x86:0x45
+
+# Color 'Blue'
+V:6:0x01:0x00:0x00:0xE3
+
+# Color 'Umber'
+V:7:0x06:0x8E:0x45:0x00
+
+# Color 'Light Dark'
+V:8:0x08:0x50:0x50:0x50
+
+# Color 'Light Slate'
+V:9:0x0B:0xD1:0xD1:0xD1
+
+# Color 'Violet'
+V:10:0x05:0xC0:0x00:0xAF
+
+# Color 'Yellow'
+V:11:0x0E:0xFF:0xFF:0x00
+
+# Color 'Light Red'
+V:12:0x0D:0xFF:0x00:0x68
+
+# Color 'Light Green'
+V:13:0x0A:0x00:0xFF:0x00
+
+# Color 'Light Blue'
+V:14:0x09:0x51:0xDD:0xFF
+
+# Color 'Light Umber'
+V:15:0x06:0xD7:0x8E:0x45
+
+
+
+
+
diff --git a/lib/pref/font-ami.prf b/lib/pref/font-ami.prf
new file mode 100644
index 00000000..1c06dbb3
--- /dev/null
+++ b/lib/pref/font-ami.prf
@@ -0,0 +1,28 @@
+# File: font-ami.prf
+
+#
+# This file contains text remapping data
+# currently used in the Amiga version.
+#
+# Lars Haugseth <larshau@ifi.uio.no>
+#
+
+
+# Color palette - Text
+V:0:0x01:0x00:0x00:0x00
+V:1:0x01:0xFF:0xFF:0xFF
+V:2:0x01:0xC7:0xC7:0xC7
+V:3:0x01:0xFF:0x92:0x00
+V:4:0x01:0xFF:0x00:0x00
+V:5:0x01:0x00:0xCD:0x00
+V:6:0x01:0x00:0x00:0xFE
+V:7:0x01:0xC8:0x64:0x00
+V:8:0x01:0x8A:0x8A:0x8A
+V:9:0x01:0xE0:0xE0:0xE0
+V:10:0x01:0xA5:0x00:0xFF
+V:11:0x01:0xFF:0xFD:0x00
+V:12:0x01:0xFF:0x00:0xBC
+V:13:0x01:0x00:0xFF:0x00
+V:14:0x01:0x00:0xC8:0xFF
+V:15:0x01:0xFF:0xCC:0x80
+
diff --git a/lib/pref/font-dos.prf b/lib/pref/font-dos.prf
new file mode 100644
index 00000000..9cf1866f
--- /dev/null
+++ b/lib/pref/font-dos.prf
@@ -0,0 +1,8 @@
+# File: font-dos.prf
+
+#
+# This file is used by Angband (when it was compiled using "main-dos.c")
+# to specify simple attr/char remappings using a standard font, allowing
+# the use of special pseudo-graphic pictures for walls and such.
+#
+
diff --git a/lib/pref/font-mac.new b/lib/pref/font-mac.new
new file mode 100644
index 00000000..0d6dd8e1
--- /dev/null
+++ b/lib/pref/font-mac.new
@@ -0,0 +1,108 @@
+# File: font-mac.prf
+
+#
+# This file is used by Angband (when it was compiled using "main-mac.c")
+# to specify simple attr/char remappings using a standard font, allowing
+# the use of the Macintosh's special characters for some things.
+#
+
+
+##### Feature attr/char definitions #####
+
+# fountain
+F:2:0x01/0xBA
+
+# fountain
+F:15:0x08/0xBA
+
+# stream of shallow water
+F:84:0x0E/0xC5
+
+# pool of deep lava
+F:85:0x0C/0xC5
+
+# stream of shallow lava
+F:86:0x04/0xC5
+
+# dead tree
+F:92:0x08/0xB4
+
+# tree
+F:96:0x0D/0xB4
+
+# mountain chain
+F:97:0x0F/0xC6
+
+# high mountain chain
+F:101:0x09/0xC6
+
+# Void Jumpgate
+F:160:0x0A/0xBD
+
+# Altar of Being
+F:161:0x09/0xB9
+
+# Altar of Winds
+F:162:0x0E/0xB9
+
+# Altar of Force
+F:163:0x0C/0xB9
+
+# Altar of Darkness
+F:164:0x08/0xB9
+
+# stream of tainted water
+F:174:0x07/0xC5
+
+# Void Jumpgate
+F:176:0x0A/0xBD
+
+# Great Fire
+F:178:0x0A/0xC5
+
+# Ekkaia, the Encircling Sea
+F:182:0x06/0xC5
+
+# pool of deep water
+F:187:0x06/0xC5
+
+# small tree
+F:202:0x05/0xB4
+
+# a blazing fire
+F:205:0x0B/0xC5
+
+# condensing water
+F:209:0x0E/0xC5
+
+
+##### Monster attr/char definitions #####
+
+# Old Man Willow
+R:206:0x02/0xB4
+
+# Tangleweed
+R:248:0x05/0xB4
+
+# Poison ivy
+R:266:0x05/0xB4
+
+# Giant Venus Flytrap
+R:317:0x05/0xB4
+
+# Huorn
+R:329:0x05/0xB4
+
+# Xiclotlan
+R:396:0x08/0xB4
+
+# Ent
+R:708:0x0D/0xB4
+
+# Quickbeam, the Ent
+R:714:0x0D/0xB4
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0x0D/0xB4
+
+
diff --git a/lib/pref/font-mac.prf b/lib/pref/font-mac.prf
new file mode 100644
index 00000000..d15c2e47
--- /dev/null
+++ b/lib/pref/font-mac.prf
@@ -0,0 +1,18 @@
+# File: font.prf
+
+#
+# This file defines special attr/char mappings for use in "text" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+## OPTION: Display "veins" (white "%") as "normal walls" (white "#")
+## This replaces the old method of setting "notice_seams" to false,
+## which no longer works as of Angband 2.7.9, for various reasons.
+#
+#F:50:1/35
+#F:51:1/35
+#F:52:1/35
+#F:53:1/35
+
diff --git a/lib/pref/font-win.prf b/lib/pref/font-win.prf
new file mode 100644
index 00000000..1754d0f5
--- /dev/null
+++ b/lib/pref/font-win.prf
@@ -0,0 +1,301 @@
+# File: font-win.prf
+
+#
+# This file is used by Angband (when it was compiled using "main-win.c")
+# to specify simple attr/char remappings using a standard font, allowing
+# the use of special pseudo-graphic pictures for walls and such.
+#
+# Note that this file is extremely similar to the file "font-ibm.prf",
+# but it uses different codes, since it uses the special pseudo-graphic
+# symbols defined in the "lib/xtra/font/*.FON" files, and there is only
+# one special wall type, so we have to use special "colors".
+#
+
+
+##### Feature attr/char definitions #####
+
+# open floor
+F:1:0x01/0x1F
+
+# web
+F:16:0x0B/0x7F
+
+# secret door
+F:48:0x01/0x7F
+
+# magma vein
+F:50:0x02/0x7F
+
+# quartz vein
+F:51:0x09/0x7F
+
+# magma vein
+F:52:0x02/0x7F
+
+# quartz vein
+F:53:0x09/0x7F
+
+# granite wall
+F:56:0x01/0x7F
+
+# granite wall
+F:57:0x01/0x7F
+
+# granite wall
+F:58:0x01/0x7F
+
+# granite wall
+F:59:0x01/0x7F
+
+# permanent wall
+F:60:0x01/0x7F
+
+# permanent wall
+F:61:0x01/0x7F
+
+# permanent wall
+F:62:0x01/0x7F
+
+# permanent wall
+F:63:0x01/0x7F
+
+# permanent wall
+F:75:0x01/0x7F
+
+# permanent wall
+F:76:0x01/0x7F
+
+# permanent wall
+F:77:0x01/0x7F
+
+# permanent wall
+F:78:0x01/0x7F
+
+# pool of deep lava
+F:85:0x0C/0x1F
+
+# stream of shallow lava
+F:86:0x04/0x1F
+
+# dark pit
+F:87:0x08/0x7F
+
+# dirt
+F:88:0x0F/0x1F
+
+# patch of grass
+F:89:0x0D/0x1F
+
+# ice
+F:90:0x09/0x1F
+
+# sand
+F:91:0x0B/0x1F
+
+# dead tree
+F:92:0x08/0x7F
+
+# ash
+F:93:0x02/0x1F
+
+# mud
+F:94:0x07/0x1F
+
+# ice wall
+F:95:0x09/0x7F
+
+# tree
+F:96:0x0D/0x7F
+
+# sandwall
+F:98:0x0B/0x7F
+
+# sandwall
+F:99:0x0B/0x7F
+
+# sandwall with treasure
+F:100:0x03/0x7F
+
+# nether mist
+F:102:0x0A/0x7F
+
+# glass wall
+F:103:0x0E/0x1F
+
+# Underground Tunnel
+F:173:0x02/0x7F
+
+# lava wall
+F:177:0x0C/0x7F
+
+# Great Fire
+F:178:0x0A/0x7F
+
+# field
+F:181:0x05/0x1F
+
+# glass wall
+F:188:0x0E/0x1F
+
+# illusion wall
+F:189:0x01/0x7F
+
+# Grass roof
+F:190:0x0B/0x7F
+
+# grass roof top
+F:191:0x0B/0x7F
+
+# grass roof chimney
+F:192:0x0B/0x7F
+
+# brick roof
+F:193:0x04/0x7F
+
+# brick roof top
+F:194:0x04/0x7F
+
+# brick roof chimney
+F:195:0x04/0x7F
+
+# rain barrel
+F:198:0x01/0x7F
+
+# cobblestone road
+F:200:0x01/0x1F
+
+# cobblestone with outlet
+F:201:0x01/0x1F
+
+# small tree
+F:202:0x05/0x7F
+
+# Underground Tunnel
+F:204:0x0F/0x7F
+
+# a blazing fire
+F:205:0x0B/0x7F
+
+# rocky ground
+F:207:0x02/0x1F
+
+# cloud-like vapour
+F:208:0x09/0x1F
+
+# dense mist
+F:210:0x01/0x7F
+
+# hail-stone wall
+F:211:0x09/0x7F
+
+# copper pillar
+F:213:0x07/0x7F
+
+# ethereal wall
+F:214:0x01/0x1F
+
+# glacial wall
+F:215:0x0E/0x7F
+
+# battlement
+F:216:0x01/0x7F
+
+##### Monster attr/char definitions #####
+
+# Space monster
+R:144:0x00/0x1F
+
+# Old Man Willow
+R:206:0x02/0x7F
+
+# Lurker
+R:247:0x01/0x1F
+
+# Tangleweed
+R:248:0x05/0x7F
+
+# Poison ivy
+R:266:0x05/0x7F
+
+# Giant Venus Flytrap
+R:317:0x05/0x7F
+
+# Stunwall
+R:326:0x09/0x7F
+
+# Huorn
+R:329:0x05/0x7F
+
+# Landmine
+R:333:0x01/0x1F
+
+# Livingstone
+R:336:0x09/0x7F
+
+# Vampiric mist
+R:365:0x08/0x7F
+
+# It
+R:393:0x09/0x1F
+
+# Xiclotlan
+R:396:0x08/0x7F
+
+# Roper
+R:426:0x08/0x7F
+
+# Lesser wall monster
+R:448:0x09/0x7F
+
+# Chaos tile
+R:458:0x0A/0x1F
+
+# Mist giant
+R:552:0x0E/0x7F
+
+# Trapper
+R:565:0x01/0x1F
+
+# Time bomb
+R:567:0x01/0x1F
+
+# Weird fume
+R:625:0x0A/0x7F
+
+# Colour out of space
+R:678:0x0A/0x1F
+
+# Ent
+R:708:0x0D/0x7F
+
+# Quickbeam, the Ent
+R:714:0x0D/0x7F
+
+# Greater wall monster
+R:718:0x09/0x7F
+
+# Ahtu, Avatar of Nyarlathotep
+R:761:0x08/0x7F
+
+# Null, the Living Void
+R:803:0x00/0x1F
+
+# Rocket mine
+R:870:0x0C/0x1F
+
+# Bouncing mine
+R:871:0x0E/0x1F
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0x0D/0x7F
+
+# The Glass Golem
+R:1033:0x09/0x7F
+
+# Golgarach, the Living Rock
+R:1035:0x09/0x7F
+
+# Spirit
+R:1053:0x09/0x1F
+
+
diff --git a/lib/pref/font-x11.prf b/lib/pref/font-x11.prf
new file mode 100644
index 00000000..57828a56
--- /dev/null
+++ b/lib/pref/font-x11.prf
@@ -0,0 +1,22 @@
+# File: font-x11.prf
+
+
+# Color palette - Text
+
+V:0:0x01:0x00:0x00:0x00
+V:1:0x01:0xFF:0xFF:0xFF
+V:2:0x01:0xC7:0xC7:0xC7
+V:3:0x01:0xFF:0x92:0x00
+V:4:0x01:0xC0:0x00:0x00
+V:5:0x01:0x00:0xC0:0x00
+V:6:0x01:0x00:0x00:0xFE
+V:7:0x01:0xC8:0x64:0x00
+V:8:0x01:0x8A:0x8A:0x8A
+V:9:0x01:0xE0:0xE0:0xE0
+V:10:0x01:0xA5:0x00:0xFF
+V:11:0x01:0xFF:0xFD:0x00
+V:12:0x01:0xFF:0x40:0x40
+V:13:0x01:0x00:0xFF:0x00
+V:14:0x01:0x00:0xC8:0xFF
+V:15:0x01:0xFF:0xCC:0x80
+
diff --git a/lib/pref/font-xxx.prf b/lib/pref/font-xxx.prf
new file mode 100644
index 00000000..298a8643
--- /dev/null
+++ b/lib/pref/font-xxx.prf
@@ -0,0 +1,472 @@
+# File: font-xxx.prf
+
+#
+# This file defines special attr/char mappings for use in "text" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+##### Special attr/char values #####
+
+
+## # Unused (@)
+## S:0x00:0x00/0x40
+## S:0x01:0x01/0x40
+## S:0x02:0x02/0x40
+## S:0x03:0x03/0x40
+## S:0x04:0x04/0x40
+## S:0x05:0x05/0x40
+## S:0x06:0x06/0x40
+## S:0x07:0x07/0x40
+## S:0x08:0x08/0x40
+## S:0x09:0x09/0x40
+## S:0x0A:0x0A/0x40
+## S:0x0B:0x0B/0x40
+## S:0x0C:0x0C/0x40
+## S:0x0D:0x0D/0x40
+## S:0x0E:0x0E/0x40
+## S:0x0F:0x0F/0x40
+
+## # Unused (@)
+## S:0x10:0x00/0x40
+## S:0x11:0x01/0x40
+## S:0x12:0x02/0x40
+## S:0x13:0x03/0x40
+## S:0x14:0x04/0x40
+## S:0x15:0x05/0x40
+## S:0x16:0x06/0x40
+## S:0x17:0x07/0x40
+## S:0x18:0x08/0x40
+## S:0x19:0x09/0x40
+## S:0x1A:0x0A/0x40
+## S:0x1B:0x0B/0x40
+## S:0x1C:0x0C/0x40
+## S:0x1D:0x0D/0x40
+## S:0x1E:0x0E/0x40
+## S:0x1F:0x0F/0x40
+
+## # Unused (@)
+## S:0x20:0x00/0x40
+## S:0x21:0x01/0x40
+## S:0x22:0x02/0x40
+## S:0x23:0x03/0x40
+## S:0x24:0x04/0x40
+## S:0x25:0x05/0x40
+## S:0x26:0x06/0x40
+## S:0x27:0x07/0x40
+## S:0x28:0x08/0x40
+## S:0x29:0x09/0x40
+## S:0x2A:0x0A/0x40
+## S:0x2B:0x0B/0x40
+## S:0x2C:0x0C/0x40
+## S:0x2D:0x0D/0x40
+## S:0x2E:0x0E/0x40
+## S:0x2F:0x0F/0x40
+
+# Spells (*)
+S:0x30:0x00/0x2A
+S:0x31:0x01/0x2A
+S:0x32:0x02/0x2A
+S:0x33:0x03/0x2A
+S:0x34:0x04/0x2A
+S:0x35:0x05/0x2A
+S:0x36:0x06/0x2A
+S:0x37:0x07/0x2A
+S:0x38:0x08/0x2A
+S:0x39:0x09/0x2A
+S:0x3A:0x0A/0x2A
+S:0x3B:0x0B/0x2A
+S:0x3C:0x0C/0x2A
+S:0x3D:0x0D/0x2A
+S:0x3E:0x0E/0x2A
+S:0x3F:0x0F/0x2A
+
+# Spells (|)
+S:0x40:0x00/0x7C
+S:0x41:0x01/0x7C
+S:0x42:0x02/0x7C
+S:0x43:0x03/0x7C
+S:0x44:0x04/0x7C
+S:0x45:0x05/0x7C
+S:0x46:0x06/0x7C
+S:0x47:0x07/0x7C
+S:0x48:0x08/0x7C
+S:0x49:0x09/0x7C
+S:0x4A:0x0A/0x7C
+S:0x4B:0x0B/0x7C
+S:0x4C:0x0C/0x7C
+S:0x4D:0x0D/0x7C
+S:0x4E:0x0E/0x7C
+S:0x4F:0x0F/0x7C
+
+# Spells (-)
+S:0x50:0x00/0x2D
+S:0x51:0x01/0x2D
+S:0x52:0x02/0x2D
+S:0x53:0x03/0x2D
+S:0x54:0x04/0x2D
+S:0x55:0x05/0x2D
+S:0x56:0x06/0x2D
+S:0x57:0x07/0x2D
+S:0x58:0x08/0x2D
+S:0x59:0x09/0x2D
+S:0x5A:0x0A/0x2D
+S:0x5B:0x0B/0x2D
+S:0x5C:0x0C/0x2D
+S:0x5D:0x0D/0x2D
+S:0x5E:0x0E/0x2D
+S:0x5F:0x0F/0x2D
+
+# Spells (/)
+S:0x60:0x00/0x2F
+S:0x61:0x01/0x2F
+S:0x62:0x02/0x2F
+S:0x63:0x03/0x2F
+S:0x64:0x04/0x2F
+S:0x65:0x05/0x2F
+S:0x66:0x06/0x2F
+S:0x67:0x07/0x2F
+S:0x68:0x08/0x2F
+S:0x69:0x09/0x2F
+S:0x6A:0x0A/0x2F
+S:0x6B:0x0B/0x2F
+S:0x6C:0x0C/0x2F
+S:0x6D:0x0D/0x2F
+S:0x6E:0x0E/0x2F
+S:0x6F:0x0F/0x2F
+
+# Spells (\)
+S:0x70:0x00/0x5C
+S:0x71:0x01/0x5C
+S:0x72:0x02/0x5C
+S:0x73:0x03/0x5C
+S:0x74:0x04/0x5C
+S:0x75:0x05/0x5C
+S:0x76:0x06/0x5C
+S:0x77:0x07/0x5C
+S:0x78:0x08/0x5C
+S:0x79:0x09/0x5C
+S:0x7A:0x0A/0x5C
+S:0x7B:0x0B/0x5C
+S:0x7C:0x0C/0x5C
+S:0x7D:0x0D/0x5C
+S:0x7E:0x0E/0x5C
+S:0x7F:0x0F/0x5C
+
+# Amulets (")
+S:0x80:0x00/0x22
+S:0x81:0x01/0x22
+S:0x82:0x02/0x22
+S:0x83:0x03/0x22
+S:0x84:0x04/0x22
+S:0x85:0x05/0x22
+S:0x86:0x06/0x22
+S:0x87:0x07/0x22
+S:0x88:0x08/0x22
+S:0x89:0x09/0x22
+S:0x8A:0x0A/0x22
+S:0x8B:0x0B/0x22
+S:0x8C:0x0C/0x22
+S:0x8D:0x0D/0x22
+S:0x8E:0x0E/0x22
+S:0x8F:0x0F/0x22
+
+# Rings (=)
+S:0x90:0x00/0x3D
+S:0x91:0x01/0x3D
+S:0x92:0x02/0x3D
+S:0x93:0x03/0x3D
+S:0x94:0x04/0x3D
+S:0x95:0x05/0x3D
+S:0x96:0x06/0x3D
+S:0x97:0x07/0x3D
+S:0x98:0x08/0x3D
+S:0x99:0x09/0x3D
+S:0x9A:0x0A/0x3D
+S:0x9B:0x0B/0x3D
+S:0x9C:0x0C/0x3D
+S:0x9D:0x0D/0x3D
+S:0x9E:0x0E/0x3D
+S:0x9F:0x0F/0x3D
+
+# Staffs (_)
+S:0xA0:0x00/0x5F
+S:0xA1:0x01/0x5F
+S:0xA2:0x02/0x5F
+S:0xA3:0x03/0x5F
+S:0xA4:0x04/0x5F
+S:0xA5:0x05/0x5F
+S:0xA6:0x06/0x5F
+S:0xA7:0x07/0x5F
+S:0xA8:0x08/0x5F
+S:0xA9:0x09/0x5F
+S:0xAA:0x0A/0x5F
+S:0xAB:0x0B/0x5F
+S:0xAC:0x0C/0x5F
+S:0xAD:0x0D/0x5F
+S:0xAE:0x0E/0x5F
+S:0xAF:0x0F/0x5F
+
+# Wands (-)
+S:0xB0:0x00/0x2D
+S:0xB1:0x01/0x2D
+S:0xB2:0x02/0x2D
+S:0xB3:0x03/0x2D
+S:0xB4:0x04/0x2D
+S:0xB5:0x05/0x2D
+S:0xB6:0x06/0x2D
+S:0xB7:0x07/0x2D
+S:0xB8:0x08/0x2D
+S:0xB9:0x09/0x2D
+S:0xBA:0x0A/0x2D
+S:0xBB:0x0B/0x2D
+S:0xBC:0x0C/0x2D
+S:0xBD:0x0D/0x2D
+S:0xBE:0x0E/0x2D
+S:0xBF:0x0F/0x2D
+
+# Rods (-)
+S:0xC0:0x00/0x2D
+S:0xC1:0x01/0x2D
+S:0xC2:0x02/0x2D
+S:0xC3:0x03/0x2D
+S:0xC4:0x04/0x2D
+S:0xC5:0x05/0x2D
+S:0xC6:0x06/0x2D
+S:0xC7:0x07/0x2D
+S:0xC8:0x08/0x2D
+S:0xC9:0x09/0x2D
+S:0xCA:0x0A/0x2D
+S:0xCB:0x0B/0x2D
+S:0xCC:0x0C/0x2D
+S:0xCD:0x0D/0x2D
+S:0xCE:0x0E/0x2D
+S:0xCF:0x0F/0x2D
+
+# Scrolls (?)
+S:0xD0:0x00/0x3F
+S:0xD1:0x01/0x3F
+S:0xD2:0x02/0x3F
+S:0xD3:0x03/0x3F
+S:0xD4:0x04/0x3F
+S:0xD5:0x05/0x3F
+S:0xD6:0x06/0x3F
+S:0xD7:0x07/0x3F
+S:0xD8:0x08/0x3F
+S:0xD9:0x09/0x3F
+S:0xDA:0x0A/0x3F
+S:0xDB:0x0B/0x3F
+S:0xDC:0x0C/0x3F
+S:0xDD:0x0D/0x3F
+S:0xDE:0x0E/0x3F
+S:0xDF:0x0F/0x3F
+
+# Potions (!)
+S:0xE0:0x00/0x21
+S:0xE1:0x01/0x21
+S:0xE2:0x02/0x21
+S:0xE3:0x03/0x21
+S:0xE4:0x04/0x21
+S:0xE5:0x05/0x21
+S:0xE6:0x06/0x21
+S:0xE7:0x07/0x21
+S:0xE8:0x08/0x21
+S:0xE9:0x09/0x21
+S:0xEA:0x0A/0x21
+S:0xEB:0x0B/0x21
+S:0xEC:0x0C/0x21
+S:0xED:0x0D/0x21
+S:0xEE:0x0E/0x21
+S:0xEF:0x0F/0x21
+
+# Food (,)
+S:0xF0:0x00/0x2C
+S:0xF1:0x01/0x2C
+S:0xF2:0x02/0x2C
+S:0xF3:0x03/0x2C
+S:0xF4:0x04/0x2C
+S:0xF5:0x05/0x2C
+S:0xF6:0x06/0x2C
+S:0xF7:0x07/0x2C
+S:0xF8:0x08/0x2C
+S:0xF9:0x09/0x2C
+S:0xFA:0x0A/0x2C
+S:0xFB:0x0B/0x2C
+S:0xFC:0x0C/0x2C
+S:0xFD:0x0D/0x2C
+S:0xFE:0x0E/0x2C
+S:0xFF:0x0F/0x2C
+
+
+
+##### Default inventory object colors #####
+
+
+# SKELETON
+E:1:0x01
+
+# BOTTLE
+E:2:0x01
+
+# FIRESTONE
+E:3:0x01
+
+# SPIKE
+E:5:0x02
+
+# CHEST
+E:7:0x02
+
+# JUNK
+E:11:0x01
+
+# BOOMERANG
+E:15:0x07
+
+# SHOT
+E:16:0x0F
+
+# ARROW
+E:17:0x0F
+
+# BOLT
+E:18:0x0F
+
+# BOW
+E:19:0x07
+
+# DIGGING
+E:20:0x02
+
+# HAFTED
+E:21:0x01
+
+# POLEARM
+E:22:0x01
+
+# SWORD
+E:23:0x01
+
+# AXE
+E:24:0x01
+
+# BOOTS
+E:30:0x0F
+
+# GLOVES
+E:31:0x0F
+
+# HELM
+E:32:0x0F
+
+# CROWN
+E:33:0x0F
+
+# SHIELD
+E:34:0x0F
+
+# CLOAK
+E:35:0x0F
+
+# SOFT_ARMOR
+E:36:0x02
+
+# HARD_ARMOR
+E:37:0x02
+
+# DRAG_ARMOR
+E:38:0x02
+
+# LITE
+E:39:0x0B
+
+# AMULET
+E:40:0x03
+
+# RING
+E:45:0x04
+
+# STAFF
+E:55:0x0F
+
+# WAND
+E:65:0x05
+
+# ROD
+E:66:0x0A
+
+# ROD TIP
+E:67:0x0A
+
+# SCROLL
+E:70:0x01
+
+# POTION
+E:71:0x0E
+
+# POTION2
+E:72:0x0E
+
+# FLASK
+E:77:0x0B
+
+# FOOD
+E:80:0x0F
+
+# BOOK
+E:111:0x0E
+
+# SYMBIOTIC_BOOK
+E:112:0x05
+
+# MUSIC_BOOK
+E:113:0x02
+
+# DRUID_BOOK
+E:114:0x0D
+
+# DAEMON BOOK
+E:115:0x03
+
+# POWER BATERIES
+E:4:0x0D
+
+# MAGE STAFFS
+E:6:0x0E
+
+# PARCHEMENT
+E:8:0x03
+
+# CORPSE
+E:9:0x0F
+
+# HYPNOS
+E:99:0x0F
+
+# RANDOM ARTIFACT
+E:102:0x0D
+
+# MUSICAL INSTRUMENT
+E:14:0x0A
+
+# EGG
+E:10:0x03
+
+# BASE RUNE
+E:104:0x0A
+
+# SECONDARY RUNE
+E:105:0x03
+
+# GOLD
+E:100:0x0B
+
+# TOOL
+E:12:0x0A
+
+# TRAPPING KIT
+E:46:0x08
+
+# TOTEM
+E:54:0x08
diff --git a/lib/pref/font.prf b/lib/pref/font.prf
new file mode 100644
index 00000000..505964bd
--- /dev/null
+++ b/lib/pref/font.prf
@@ -0,0 +1,60 @@
+# File: font.prf
+
+#
+# This file defines special attr/char mappings for use in "text" mode
+#
+# This file includes, if appropriate, various "sub-files"
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+## #
+## # OPTION: Display "veins" (white "%") as "normal walls" (white "#").
+## #
+## F:50:0x01/0x23
+## F:51:0x01/0x23
+## F:52:0x01/0x23
+## F:53:0x01/0x23
+
+
+##### Standard font file #####
+
+%:font-xxx.prf
+
+
+##### System Specific Subfiles #####
+
+?:[IOR [EQU $SYS xaw] [EQU $SYS x11] [EQU $SYS gtk]]
+%:font-x11.prf
+
+?:[EQU $SYS glu]
+%:font-glu.prf
+
+?:[EQU $SYS gcu]
+%:font-gcu.prf
+
+?:[EQU $SYS ami]
+%:font-ami.prf
+
+?:[EQU $SYS mac]
+%:font-mac.prf
+
+?:[EQU $SYS win]
+%:font-win.prf
+
+?:[EQU $SYS dos]
+%:font-dos.prf
+
+?:[EQU $SYS ibm]
+%:font-ibm.prf
+
+?:[EQU $SYS emx]
+%:font-emx.prf
+
+?:[EQU $SYS acn]
+%:font-acn.prf
+
+?:1
+
+
diff --git a/lib/pref/graf-ami.prf b/lib/pref/graf-ami.prf
new file mode 100644
index 00000000..d9b1b356
--- /dev/null
+++ b/lib/pref/graf-ami.prf
@@ -0,0 +1,64 @@
+# File: graf-ami.prf
+
+#
+# This file contains color definitions and
+# graphics remapping for the Amiga version.
+#
+# Lars Haugseth <larshau@ifi.uio.no>
+#
+
+
+# Color palette - Graphics
+V:0:0x01:0x00:0x00:0x00
+V:1:0x01:0xF0:0xE0:0xD0
+V:2:0x01:0x80:0x80:0x80
+V:3:0x01:0x50:0x50:0x50
+V:4:0x01:0xE0:0xB0:0x00
+V:5:0x01:0xC0:0xA0:0x70
+V:6:0x01:0x80:0x60:0x40
+V:7:0x01:0x40:0x30:0x20
+V:8:0x01:0x00:0xA0:0xF0
+V:9:0x01:0x00:0x00:0xF0
+V:10:0x01:0x00:0x00:0x70
+V:11:0x01:0xF0:0x00:0x00
+V:12:0x01:0x80:0x00:0x00
+V:13:0x01:0x90:0x00:0xB0
+V:14:0x01:0x00:0x60:0x10
+V:15:0x01:0x60:0xF0:0x40
+
+
+# Color palette - Text
+V:16:0x01:0x00:0x00:0x00
+V:17:0x01:0xFF:0xFF:0xFF
+V:18:0x01:0xC7:0xC7:0xC7
+V:19:0x01:0xFF:0x92:0x00
+V:20:0x01:0xFF:0x00:0x00
+V:21:0x01:0x00:0xCD:0x00
+V:22:0x01:0x00:0x00:0xFE
+V:23:0x01:0xC8:0x64:0x00
+V:24:0x01:0x8A:0x8A:0x8A
+V:25:0x01:0xE0:0xE0:0xE0
+V:26:0x01:0xA5:0x00:0xFF
+V:27:0x01:0xFF:0xFD:0x00
+V:28:0x01:0xFF:0x00:0xBC
+V:29:0x01:0x00:0xFF:0x00
+V:30:0x01:0x00:0xC8:0xFF
+V:31:0x01:0xFF:0xCC:0x80
+
+
+# Standard file
+%:graf-xxx.prf
+
+
+### Feature attr/char definitions
+
+# nothing
+F:0:0x01/0x20
+
+# open floor
+F:1:0x81/0x8E
+
+# invis trap
+F:2:0x81/0x8E
+
+
diff --git a/lib/pref/graf-dos.prf b/lib/pref/graf-dos.prf
new file mode 100644
index 00000000..41f38c76
--- /dev/null
+++ b/lib/pref/graf-dos.prf
@@ -0,0 +1,15 @@
+# File: graf-win.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
diff --git a/lib/pref/graf-iso.prf b/lib/pref/graf-iso.prf
new file mode 100644
index 00000000..05bc8621
--- /dev/null
+++ b/lib/pref/graf-iso.prf
@@ -0,0 +1,6878 @@
+%:trap-iso.prf
+
+# General Store
+B:0:0x80:0xB1
+
+# Armoury
+B:1:0x80:0xB2
+
+# Weapon Smiths
+B:2:0x80:0xB3
+
+# Temple
+B:3:0x80:0xB4
+
+# Alchemy Shop
+B:4:0x80:0xB5
+
+# Magic Shop
+B:5:0x80:0xB6
+
+# Black Market
+B:6:0x80:0xB7
+
+# Home
+B:7:0x80:0xB8
+
+# Bookstore
+B:8:0x80:0xB9
+
+# Pet shop
+B:9:0x80:0xAB
+
+# Mayors office
+B:10:0x80:0xAB
+
+# Inn
+B:11:0x80:0xB0
+
+# The Soothsayer
+B:12:0x80:0xAB
+
+# Library
+B:13:0x80:0xAB
+
+# Castle
+B:14:0x80:0xAB
+
+# Casino
+B:15:0x80:0xAB
+
+# Beastmaster Shanty
+B:16:0x80:0xAB
+
+# Fighters Hall
+B:17:0x80:0xAB
+
+# Tower of Magery
+B:18:0x80:0xAB
+
+# Inner Temple
+B:19:0x80:0xAB
+
+# Paladins Guild
+B:20:0x80:0xAB
+
+# Rangers Guild
+B:21:0x80:0xAB
+
+# Thunderlords' Hide
+B:22:0x80:0xAB
+
+# The Mirror
+B:23:0x80:0xAB
+
+# Seat of Ruling
+B:24:0x80:0xAB
+
+# Wizards Spire
+B:25:0x80:0xAB
+
+# Priests Circle
+B:26:0x80:0xAB
+
+# Tower of the King
+B:27:0x80:0xAB
+
+# Library
+B:28:0x80:0xAB
+
+# The White Tree
+B:29:0x80:0xAB
+
+# Craftsmaster
+B:30:0x80:0xAB
+
+# Earth-Dome (Nature)
+B:31:0x80:0xAB
+
+# Minstrels Haven
+B:32:0x80:0xAB
+
+# Star-Dome
+B:33:0x80:0xAB
+
+# Valarin Temple
+B:34:0x80:0xAB
+
+# Sea-Dome
+B:35:0x80:0xAB
+
+# The Golden Flower
+B:36:0x80:0xAB
+
+# The Fountain
+B:37:0x80:0xAB
+
+# Axe Smith
+B:38:0x80:0xAB
+
+# Hafted Smith
+B:39:0x80:0xAB
+
+# Polearm Smith
+B:40:0x80:0xAB
+
+# Sword Smith
+B:41:0x80:0xAB
+
+# Rare Jewelry Shop
+B:42:0x80:0xAB
+
+# Jewelry Shop
+B:43:0x80:0xAB
+
+# Footwear Shop
+B:44:0x80:0xAB
+
+# Rare Footwear Shop
+B:45:0x80:0xAB
+
+# Library
+B:46:0x80:0xAB
+
+# Forbidden Library
+B:47:0x80:0xAB
+
+# Expensive Black Market
+B:48:0x80:0xAB
+
+# Common Shop
+B:49:0x80:0xAB
+
+# Dragon Hunter
+B:50:0x80:0xAB
+
+# Speed Ring Market
+B:51:0x80:0xAB
+
+# Scribe
+B:52:0x80:0xAB
+
+# Potion Store
+B:53:0x80:0xAB
+
+# Recaller
+B:54:0x80:0xAB
+
+# Master Archer
+B:55:0x80:0xAB
+
+# Merchants Guild
+B:56:0x80:0xAB
+
+# The Mathom-house
+B:57:0x80:0xAB
+
+# The Prancing Pony
+B:58:0x80:0xAB
+
+# nothing
+F:0:0x80:0xA0
+
+# open floor
+F:1:0x82:0xBC
+
+# fountain
+F:2:0x81:0x8D
+
+# glyph of warding
+F:3:0x8A:0xE1
+
+# open door
+F:4:0x80:0xA7
+
+# broken door
+F:5:0x80:0xA7
+
+# up staircase
+F:6:0x80:0xBC
+
+# down staircase
+F:7:0x80:0xBE
+
+# quest entrance
+F:8:0x80:0xBE
+
+# quest exit
+F:9:0x80:0xBC
+
+# quest down level
+F:10:0x80:0xBE
+
+# quest up level
+F:11:0x80:0xBC
+
+# town exit
+F:12:0x80:0xBE
+
+# shaft down
+F:13:0x80:0xBE
+
+# shaft up
+F:14:0x80:0xBC
+
+# fountain
+F:15:0x81:0x8D
+
+# web
+F:15:0x81:0x8D
+
+# trap
+F:17:0x8A:0xF9
+
+# visible trap -- spiked pit
+F:18:0x8A:0xF9
+
+# visible trap -- poison pit
+F:19:0x8A:0xF8
+
+# visible trap -- rune -- summon
+F:20:0x8A:0xF8
+
+# visible trap -- rune -- teleport
+F:21:0x8A:0xF8
+
+# visible trap -- spot -- fire
+F:22:0x8A:0xFD
+
+# visible trap -- spot -- acid
+F:23:0x8A:0xFA
+
+# visible trap -- dart -- slow
+F:24:0x8A:0xF3
+
+# visible trap -- dart -- lose str
+F:25:0x8A:0xF3
+
+# visible trap -- dart -- lose dex
+F:26:0x8A:0xF3
+
+# visible trap -- dart -- lose con
+F:27:0x8A:0xF3
+
+# visible trap -- gas -- blind
+F:28:0x8A:0xF6
+
+# visible trap -- gas -- confuse
+F:29:0x8A:0xF6
+
+# visible trap -- gas -- poison
+F:30:0x8A:0xF6
+
+# visible trap -- gas -- sleep
+F:31:0x8A:0xF6
+
+# door
+F:32:0x80:0xAB
+
+# locked door
+F:33:0x80:0xAB
+
+# locked door
+F:34:0x80:0xAB
+
+# locked door
+F:35:0x80:0xAB
+
+# locked door
+F:36:0x80:0xAB
+
+# locked door
+F:37:0x80:0xAB
+
+# locked door
+F:38:0x80:0xAB
+
+# locked door
+F:39:0x80:0xAB
+
+# jammed door
+F:40:0x80:0xAB
+
+# jammed door
+F:41:0x80:0xAB
+
+# jammed door
+F:42:0x80:0xAB
+
+# jammed door
+F:43:0x80:0xAB
+
+# jammed door
+F:44:0x80:0xAB
+
+# jammed door
+F:45:0x80:0xAB
+
+# jammed door
+F:46:0x80:0xAB
+
+# jammed door
+F:47:0x80:0xAB
+
+# secret door
+F:48:0x80:0xA3
+
+# pile of rubble
+F:49:0x8A:0xEF
+
+# magma vein
+F:50:0x80:0xA5
+
+# quartz vein
+F:51:0x81:0xF3
+
+# magma vein
+F:52:0x81:0xF3
+
+# quartz vein
+F:53:0x81:0xF3
+
+# magma vein with treasure
+F:54:0x80:0xAA
+
+# quartz vein with treasure
+F:55:0x80:0xAA
+
+# granite wall
+F:56:0x81:0xF0
+
+# granite wall
+F:57:0x81:0xF0
+
+# granite wall
+F:58:0x81:0xF0
+
+# granite wall
+F:59:0x81:0xF0
+
+# permanent wall
+F:60:0x81:0xF3
+
+# permanent wall
+F:61:0x81:0xF3
+
+# permanent wall
+F:62:0x81:0xF3
+
+# permanent wall
+F:63:0x81:0xF3
+
+# explosive rune
+F:64:0x80:0xAA
+
+# Straight Road startpoint
+F:65:0x80:0xAA
+
+# section of the Straight Road
+F:66:0x80:0xAA
+
+# section of the Straight Road
+F:67:0x80:0xAA
+
+# section of the Straight Road
+F:68:0x80:0xAA
+
+# section of the Straight Road
+F:69:0x80:0xAA
+
+# section of the Straight Road
+F:70:0x80:0xAA
+
+# section of the Straight Road (discharged)
+F:71:0x80:0xAA
+
+# Straight Road exit
+F:72:0x80:0xAA
+
+# corrupted section of the Straight Road
+F:73:0x80:0xAA
+
+# Building
+F:74:0x80:0xB1
+
+# permanent wall
+F:75:0x81:0xF3
+
+# permanent wall
+F:76:0x81:0xF3
+
+# permanent wall
+F:77:0x81:0xF3
+
+# permanent wall
+F:78:0x81:0xF3
+
+# stream of shallow water
+F:84:0x82:0xEB
+
+# pool of deep lava
+F:85:0x82:0xAB
+
+# stream of shallow lava
+F:86:0x82:0xAB
+
+# dark pit
+F:87:0x83:0x8B
+
+# dirt
+F:88:0x82:0xF3
+
+# patch of grass
+F:89:0x82:0xE8
+
+# ice
+F:90:0x80:0xAE
+
+# sand
+F:91:0x80:0xAE
+
+# dead tree
+F:92:0x80:0xA3
+
+# ash
+F:93:0x80:0xAE
+
+# mud
+F:94:0x80:0xAE
+
+# ice wall
+F:95:0x80:0x80
+
+# tree
+F:96:0x83:0x88
+
+# mountain chain
+F:97:0x81:0x9D
+
+# sandwall
+F:98:0x80:0xA3
+
+# sandwall
+F:99:0x80:0xA5
+
+# sandwall with treasure
+F:100:0x80:0xAA
+
+# high mountain chain
+F:101:0x80:0xDE
+
+# nether mist
+F:102:0x80:0x80
+
+# molten glass wall
+F:103:0x80:0xAE
+
+# Void Jumpgate
+F:160:0x81:0x8C
+
+# Altar of Being
+F:161:0x81:0x94
+
+# Altar of Winds
+F:162:0x81:0x94
+
+# Altar of Force
+F:163:0x81:0x94
+
+# Altar of Darkness
+F:164:0x81:0x94
+
+# Altar of Nature
+F:165:0x81:0x94
+
+# Altar of Sun
+F:166:0x81:0x94
+
+# Altar of Rage
+F:167:0x81:0x94
+
+# Altar of Winds
+F:168:0x81:0x94
+
+# Altar of Stars
+F:169:0x81:0x94
+
+# Altar of Being
+F:170:0x81:0x94
+
+# Altar of Randomness
+F:171:0x81:0x94
+
+# floor
+F:172:0x80:0x81
+
+# Underground Tunnel
+F:173:0x80:0x82
+
+# stream of tainted water
+F:174:0x80:0x80
+
+# monster trap
+F:175:0x81:0x9C
+
+# Void Jumpgate
+F:176:0x80:0x80
+
+# lava wall
+F:177:0x80:0x80
+
+# Great Fire
+F:178:0x80:0x80
+
+# Path to next area
+F:179:0x80:0xBE
+
+# Path to previous area
+F:180:0x80:0xBC
+
+# field
+F:181:0x80:0x80
+
+# Ekkaia, the Encircling Sea
+F:182:0x80:0x80
+
+# Altar of Energy
+F:183:0x80:0x80
+
+# Altar of Matter
+F:184:0x80:0x80
+
+# Altar of Being
+F:185:0x80:0x80
+
+# Altar of Unbeing
+F:186:0x80:0x80
+
+# pool of deep water
+F:187:0x82:0xF0
+
+# glass wall
+F:188:0x80:0xAE
+
+# illusion wall
+F:189:0x80:0xA3
+
+# Grass roof
+F:190:0x82:0xF6
+
+# grass roof top
+F:191:0x82:0xF6
+
+# grass roof chimney
+F:192:0x82:0xF7
+
+# brick roof
+F:193:0x82:0xEE
+
+# brick roof top
+F:194:0x82:0xEE
+
+# brick roof chimney
+F:195:0x82:0xF7
+
+# window
+F:196:0x80:0xA3
+
+# small window
+F:197:0x80:0xA3
+
+# rain barrel
+F:198:0x80:0xA3
+
+# grass with flowers
+F:199:0x82:0xF8
+
+# cobblestone road
+F:200:0x83:0x83
+
+# cobblestone with outlet
+F:201:0x80:0xAE
+
+# small tree
+F:202:0x83:0x88
+
+# town
+F:203:0x80:0xAA
+
+# Underground Tunnel
+F:204:0x80:0x82
+
+# a blazing fire
+F:205:0x80:0x80
+
+# pile of rubble
+F:206:0x8A:0xEF
+
+# rocky ground
+F:207:0x80:0x80
+
+# cloud-like vapour
+F:208:0x80:0x80
+
+# condensing water
+F:209:0x80:0x80
+
+# dense mist
+F:210:0x80:0x80
+
+# hail-stone wall
+F:211:0x80:0x80
+
+# dead small tree
+F:212:0x80:0x80
+
+# something
+K:0:0x80:0x80
+
+# Blindness
+K:1:0x86:0x8C
+
+# Paranoia
+K:2:0x86:0x8C
+
+# Confusion
+K:3:0x86:0x8C
+
+# Hallucination
+K:4:0x86:0x8C
+
+# Cure Poison
+K:5:0x86:0x8C
+
+# Cure Blindness
+K:6:0x86:0x8C
+
+# Cure Paranoia
+K:7:0xA6:0xBB
+
+# Cure Confusion
+K:8:0x86:0x8C
+
+# Weakness
+K:9:0x86:0x8C
+
+# Unhealth
+K:10:0x86:0x8C
+
+# Restore Constitution
+K:11:0x86:0x8C
+
+# Restoring
+K:12:0x86:0x8C
+
+# Stupidity
+K:13:0x86:0x8C
+
+# Naivety
+K:14:0x86:0x8C
+
+# Poison
+K:15:0x86:0x8C
+
+# Sickness
+K:16:0x86:0x8C
+
+# Paralysis
+K:17:0x86:0x8C
+
+# Restore Strength
+K:18:0x86:0x8C
+
+# Disease
+K:19:0x86:0x8C
+
+# Cure Serious Wounds
+K:20:0x86:0x8C
+
+# & Ration~ of Food
+K:21:0x8A:0xBC
+
+# & Hard Biscuit~
+K:22:0x8A:0xBA
+
+# & Strip~ of Venison
+K:23:0x8A:0xBB
+
+# & Slime Mold~
+K:24:0x8A:0xBD
+
+# & Lembas~
+K:25:0x8A:0xBE
+
+# & Pint~ of Fine Ale
+K:26:0x8A:0xB8
+
+# & Pint~ of Fine Wine
+K:27:0x8A:0xB8
+
+# & Mattock~
+K:28:0x9E:0xC4
+
+# & Blue Stone~
+K:29:0xA6:0x8B
+
+# & Broken Dagger~
+K:30:0x88:0xC5
+
+# & Bastard Sword~
+K:31:0x88:0xC6
+
+# & Scimitar~
+K:32:0x88:0xCF
+
+# & Tulwar~
+K:33:0x88:0xCD
+
+# & Broad Sword~
+K:34:0x88:0xD0
+
+# & Short Sword~
+K:35:0x88:0xCC
+
+# & Blade~ of Chaos
+K:36:0x88:0xD6
+
+# & Two-Handed Sword~
+K:37:0x88:0xD4
+
+# & Main Gauche~
+K:38:0x88:0xC8
+
+# & Cutlass~
+K:39:0x88:0xCE
+
+# & Executioner's Sword~
+K:40:0x88:0xD5
+
+# & Katana~
+K:41:0x88:0xD3
+
+# & Long Sword~
+K:42:0x88:0xD1
+
+# & Dagger~
+K:43:0x88:0xC7
+
+# & Rapier~
+K:44:0x88:0xC9
+
+# & Sabre~
+K:45:0x88:0xCB
+
+# & Small Sword~
+K:46:0x88:0xCA
+
+# & Broken Sword~
+K:47:0x88:0xC6
+
+# & Ball-and-Chain~
+K:48:0x88:0xFE
+
+# & Whip~
+K:49:0x88:0xD7
+
+# & Flail~
+K:50:0x88:0xFB
+
+# & Two-Handed Flail~
+K:51:0x88:0xFF
+
+# & Morning Star~
+K:52:0x88:0xFC
+
+# & Mace~
+K:53:0x88:0xF9
+
+# & Quarterstaff~
+K:54:0x88:0xFA
+
+# & War Hammer~
+K:55:0x88:0xF8
+
+# & Lead-Filled Mace~
+K:56:0x88:0xFD
+
+# & Mace~ of Disruption
+K:57:0x89:0x80
+
+# & Lucerne Hammer~
+K:58:0x89:0x85
+
+# & Beaked Axe~
+K:59:0x89:0x88
+
+# & Glaive~
+K:60:0x89:0x8A
+
+# & Halberd~
+K:61:0x89:0x8B
+
+# & Awl-Pike~
+K:62:0x89:0x83
+
+# & Pike~
+K:63:0x89:0x87
+
+# & Spear~
+K:64:0x89:0x81
+
+# & Trident~
+K:65:0x89:0x82
+
+# & Lance~
+K:66:0x89:0x84
+
+# & Great Axe~
+K:67:0x89:0x8D
+
+# & Battle Axe~
+K:68:0x89:0x86
+
+# & Lochaber Axe~
+K:69:0x89:0x8C
+
+# & Broad Axe~
+K:70:0x89:0x89
+
+# & Scythe~
+K:71:0x89:0x8E
+
+# & Scythe~ of Slicing
+K:72:0x89:0x8F
+
+# & Short Bow~
+K:73:0x89:0x90
+
+# & Long Bow~
+K:74:0x89:0x91
+
+# & Light Crossbow~
+K:75:0x89:0x92
+
+# & Heavy Crossbow~
+K:76:0x89:0x93
+
+# & Sling~
+K:77:0x89:0x94
+
+# & Arrow~
+K:78:0x89:0xB8
+
+# & Seeker Arrow~
+K:79:0x89:0xB9
+
+# & Bolt~
+K:80:0x89:0xBA
+
+# & Seeker Bolt~
+K:81:0x89:0xBB
+
+# & Rounded Pebble~
+K:82:0x89:0xBC
+
+# & Iron Shot~
+K:83:0x89:0xBD
+
+# & Shovel~
+K:84:0x8A:0xC7
+
+# & Gnomish Shovel~
+K:85:0x8A:0xC8
+
+# & Dwarven Shovel~
+K:86:0x8A:0xC9
+
+# & Pick~
+K:87:0x8A:0xC4
+
+# & Orcish Pick~
+K:88:0x8A:0xC5
+
+# & Dwarven Pick~
+K:89:0x8A:0xC9
+
+# & Elven Cloak~
+K:90:0x88:0x81
+
+# & Pair~ of Soft Leather Boots
+K:91:0x87:0xC6
+
+# & Pair~ of Hard Leather Boots
+K:92:0x87:0xC7
+
+# & Pair~ of Metal Shod Boots
+K:93:0x87:0xC8
+
+# & Hard Leather Cap~
+K:94:0x87:0x90
+
+# & Metal Cap~
+K:95:0x87:0x91
+
+# & Iron Helm~
+K:96:0x87:0x92
+
+# & Steel Helm~
+K:97:0x87:0x93
+
+# & Iron Crown~
+K:98:0x87:0x94
+
+# & Golden Crown~
+K:99:0x87:0x95
+
+# & Jewel Encrusted Crown~
+K:100:0x87:0x96
+
+# & Robe~
+K:101:0x88:0x84
+
+# & Filthy Rag~
+K:102:0x88:0x83
+
+# Soft Leather Armour~
+K:103:0x88:0x85
+
+# Soft Studded Leather~
+K:104:0x88:0x86
+
+# Hard Leather Armour~
+K:105:0x88:0x87
+
+# Hard Studded Leather~
+K:106:0x88:0x88
+
+# Leather Scale Mail~
+K:107:0x88:0x89
+
+# Metal Scale Mail~
+K:108:0x88:0x8A
+
+# Chain Mail~
+K:109:0x88:0x8C
+
+# Rusty Chain Mail~
+K:110:0x88:0x8B
+
+# Augmented Chain Mail~
+K:111:0x88:0x8E
+
+# Bar Chain Mail~
+K:112:0x88:0x8F
+
+# Metal Brigandine Armour~
+K:113:0x88:0x90
+
+# Partial Plate Armour~
+K:114:0x88:0x91
+
+# Metal Lamellar Armour~
+K:115:0x88:0x92
+
+# Full Plate Armour~
+K:116:0x88:0x93
+
+# Ribbed Plate Armour~
+K:117:0x88:0x94
+
+# Adamantite Plate Mail~
+K:118:0x88:0x97
+
+# Mithril Plate Mail~
+K:119:0x88:0x96
+
+# Mithril Chain Mail~
+K:120:0x88:0x95
+
+# Double Chain Mail~
+K:121:0x88:0x8D
+
+# & Shield~ of Deflection
+K:122:0x87:0xD0
+
+# & Cloak~
+K:123:0x88:0x80
+
+# & Shadow Cloak~
+K:124:0x88:0x81
+
+# & Set~ of Leather Gloves
+K:125:0x87:0xC9
+
+# & Set~ of Gauntlets
+K:126:0x87:0xCA
+
+# & Set~ of Cesti
+K:127:0x87:0xCB
+
+# & Small Leather Shield~
+K:128:0x87:0xCC
+
+# & Large Leather Shield~
+K:129:0x87:0xCD
+
+# & Small Metal Shield~
+K:130:0x87:0xCE
+
+# & Large Metal Shield~
+K:131:0x87:0xCF
+
+# Strength
+K:132:0x85:0xB9
+
+# Dexterity
+K:133:0x85:0xBB
+
+# Constitution
+K:134:0x85:0xBB
+
+# Intelligence
+K:135:0x85:0xBB
+
+# Speed
+K:136:0x85:0xBB
+
+# Searching
+K:137:0x85:0xBB
+
+# Teleportation
+K:138:0x85:0xBB
+
+# Slow Digestion
+K:139:0x85:0xBB
+
+# Fire Resistance
+K:140:0x85:0xBB
+
+# Cold Resistance
+K:141:0x85:0xBB
+
+# Levitation
+K:142:0x85:0xBB
+
+# Poison Resistance
+K:143:0x85:0xBB
+
+# Free Action
+K:144:0x85:0xBB
+
+# Weakness
+K:145:0x85:0xBB
+
+# Flames
+K:146:0x85:0xBB
+
+# Acid
+K:147:0x85:0xBB
+
+# Ice
+K:148:0x85:0xBB
+
+# Woe
+K:149:0x85:0xBB
+
+# Stupidity
+K:150:0x85:0xBB
+
+# Damage
+K:151:0x85:0xBB
+
+# Accuracy
+K:152:0x85:0xBB
+
+# Protection
+K:153:0x85:0xBB
+
+# Aggravate Monster
+K:154:0x85:0xBB
+
+# See Invisible
+K:155:0x85:0xBB
+
+# Sustain Strength
+K:156:0x85:0xBB
+
+# Sustain Intelligence
+K:157:0x85:0xBB
+
+# Sustain Wisdom
+K:158:0x85:0xBB
+
+# Sustain Constitution
+K:159:0x85:0xBB
+
+# Sustain Dexterity
+K:160:0x85:0xBB
+
+# Sustain Charisma
+K:161:0x85:0xBB
+
+# Slaying
+K:162:0x85:0xBB
+
+# Brilliance
+K:163:0x86:0xFB
+
+# Charisma
+K:164:0x86:0xFB
+
+# Searching
+K:165:0x86:0xFB
+
+# Teleportation
+K:166:0x86:0xFB
+
+# Slow Digestion
+K:167:0x86:0xFB
+
+# Acid Resistance
+K:168:0x86:0xFB
+
+# Adornment
+K:169:0x86:0xFB
+
+# Double Ring Mail~
+K:170:0x88:0x93
+
+# the Magi
+K:171:0x86:0xFB
+
+# Doom
+K:172:0x86:0xFB
+
+# Enchant Weapon To-Hit
+K:173:0x85:0x94
+
+# Enchant Weapon To-Dam
+K:174:0x85:0x94
+
+# Enchant Armor
+K:175:0x85:0x94
+
+# Identify
+K:176:0x85:0x94
+
+# *Identify*
+K:177:0x85:0x94
+
+# Rumour
+K:178:0x85:0x94
+
+# Chaos
+K:179:0x85:0x94
+
+# Remove Curse
+K:180:0x85:0x94
+
+# Light
+K:181:0x85:0x94
+
+# Fire
+K:182:0x85:0x94
+
+# Ice
+K:183:0x85:0x94
+
+# Summon Monster
+K:184:0x85:0x94
+
+# Phase Door
+K:185:0x85:0x94
+
+# Teleportation
+K:186:0x85:0x94
+
+# Teleport Level
+K:187:0x85:0x94
+
+# Monster Confusion
+K:188:0x85:0x94
+
+# Magic Mapping
+K:189:0x85:0x94
+
+# Rune of Protection
+K:190:0x85:0x94
+
+# *Remove Curse*
+K:191:0x85:0x94
+
+# Treasure Detection
+K:192:0x85:0x94
+
+# Object Detection
+K:193:0x85:0x94
+
+# Trap Detection
+K:194:0x85:0x94
+
+# & Sheaf Arrow~
+K:195:0x89:0xB9
+
+# & Mithril Shot~
+K:196:0x89:0xBD
+
+# Door
+K:197:0x85:0x94
+
+# Acquirement
+K:198:0x85:0x94
+
+# *Acquirement*
+K:199:0x85:0x94
+
+# Mass Genocide
+K:200:0x85:0x94
+
+# Detect Invisible
+K:201:0x85:0x94
+
+# Aggravate Monster
+K:202:0x85:0x94
+
+# Trap Creation
+K:203:0x85:0x94
+
+# Trap
+K:204:0x85:0x94
+
+# Artifact Creation
+K:205:0x85:0x94
+
+# Recharging
+K:206:0x85:0x94
+
+# Genocide
+K:207:0x85:0x94
+
+# Darkness
+K:208:0x85:0x94
+
+# Protection from Evil
+K:209:0x85:0x94
+
+# Satisfy Hunger
+K:210:0x85:0x94
+
+# Dispel Undead
+K:211:0x85:0x94
+
+# *Enchant Weapon*
+K:212:0x85:0x94
+
+# Curse Weapon
+K:213:0x85:0x94
+
+# *Enchant Armor*
+K:214:0x85:0x94
+
+# Curse Armor
+K:215:0x85:0x94
+
+# Summon Undead
+K:216:0x85:0x94
+
+# Blessing
+K:217:0x85:0x94
+
+# Holy Chant
+K:218:0x85:0x94
+
+# Holy Prayer
+K:219:0x85:0x94
+
+# Word of Recall
+K:220:0x85:0x94
+
+# *Destruction*
+K:221:0x85:0x94
+
+# Slime Mold Juice
+K:222:0x85:0xFD
+
+# Apple Juice
+K:223:0x85:0xFD
+
+# Water
+K:224:0x85:0xFD
+
+# Strength
+K:225:0x85:0xFD
+
+# Weakness
+K:226:0x85:0xFD
+
+# Restore Strength
+K:227:0x85:0xFD
+
+# Intelligence
+K:228:0x85:0xFD
+
+# Stupidity
+K:229:0x85:0xFD
+
+# Restore Intelligence
+K:230:0x85:0xFD
+
+# Wisdom
+K:231:0x85:0xFD
+
+# Naivety
+K:232:0x85:0xFD
+
+# Restore Wisdom
+K:233:0x85:0xFD
+
+# Charisma
+K:234:0x85:0xFD
+
+# Ugliness
+K:235:0x85:0xFD
+
+# Restore Charisma
+K:236:0x85:0xFD
+
+# Curing
+K:237:0x85:0xFD
+
+# Invulnerability
+K:238:0x85:0xFD
+
+# New Life
+K:239:0x85:0xFD
+
+# Cure Serious Wounds
+K:240:0x85:0xFD
+
+# Cure Critical Wounds
+K:241:0x85:0xFD
+
+# Healing
+K:242:0x85:0xFD
+
+# Constitution
+K:243:0x85:0xFD
+
+# Experience
+K:244:0x85:0xFD
+
+# Sleep
+K:245:0x85:0xFD
+
+# Blindness
+K:246:0x85:0xFD
+
+# Booze
+K:247:0x85:0xFD
+
+# Poison
+K:248:0x85:0xFD
+
+# Speed
+K:249:0x85:0xFD
+
+# Slowness
+K:250:0x85:0xFD
+
+# Dexterity
+K:251:0x85:0xFD
+
+# Restore Dexterity
+K:252:0x85:0xFD
+
+# Restore Constitution
+K:253:0x85:0xFD
+
+# Lose Memories
+K:254:0x85:0xFD
+
+# Salt Water
+K:255:0x85:0xFD
+
+# Enlightenment
+K:256:0x85:0xFD
+
+# Heroism
+K:257:0x85:0xFD
+
+# Berserk Strength
+K:258:0x85:0xFD
+
+# Boldness
+K:259:0x85:0xFD
+
+# Restore Life Levels
+K:260:0x85:0xFD
+
+# Resist Heat
+K:261:0x85:0xFD
+
+# Resist Cold
+K:262:0x85:0xFD
+
+# Detect Invisible
+K:263:0x85:0xFD
+
+# Slow Poison
+K:264:0x85:0xFD
+
+# Neutralise Poison
+K:265:0x85:0xFD
+
+# Restore Mana
+K:266:0x85:0xFD
+
+# Infra-vision
+K:267:0x85:0xFD
+
+# Resistance
+K:268:0x85:0xFD
+
+# Spell
+K:269:0x86:0xCB
+
+# Manathrust
+K:270:0x86:0xCB
+
+# Fireflash
+K:271:0x86:0xCB
+
+# Firewall
+K:272:0x86:0xCB
+
+# Tidal Wave
+K:273:0x86:0xCB
+
+# Ice Storm
+K:274:0x86:0xCB
+
+# Noxious Cloud
+K:275:0x86:0xCB
+
+# Poison Blood
+K:276:0x86:0xCB
+
+# Thunderstorm
+K:277:0x86:0xCB
+
+# Dig
+K:278:0x86:0xCB
+
+# Stone Prison
+K:279:0x86:0xCB
+
+# Strike
+K:280:0x86:0xCB
+
+# Teleport Away
+K:281:0x86:0xCB
+
+# Summon Animal
+K:282:0x86:0xCB
+
+# Magelock
+K:283:0x86:0xCB
+
+# Slow Monster
+K:284:0x86:0xCB
+
+# Essence of Speed
+K:285:0x9F:0x84
+
+# Banishment
+K:286:0x86:0xCB
+
+# Disperse Magic
+K:287:0x86:0xCB
+
+# Charm
+K:288:0x86:0xCB
+
+# Confuse
+K:289:0x86:0xCB
+
+# Demon Blade
+K:290:0x86:0xCB
+
+# Heal Monster
+K:291:0x86:0xCB
+
+# Haste Monster
+K:292:0x86:0xCB
+
+# & Flight Arrow~
+K:293:0x89:0xB9
+
+# Acid Bolts
+K:294:0x86:0xCB
+
+# Dragon's Flame
+K:295:0x86:0xCB
+
+# Dragon's Frost
+K:296:0x86:0xCB
+
+# Dragon's Breath
+K:297:0x86:0xCB
+
+# Annihilation
+K:298:0x86:0xCB
+
+# Rockets
+K:299:0x86:0xCB
+
+# Spell
+K:300:0x87:0x8A
+
+# Nothing
+K:301:0x87:0x8A
+
+# Globe of Light
+K:302:0x87:0x8A
+
+# Fiery Shield
+K:303:0x87:0x8A
+
+# Remove Curses
+K:304:0x87:0x8A
+
+# Wings of Winds
+K:305:0x87:0x8A
+
+# Shake
+K:306:0x87:0x8A
+
+# Disarm
+K:307:0x87:0x8A
+
+# Teleportation
+K:308:0x87:0x8A
+
+# Probability Travel
+K:309:0x87:0x8A
+
+# Recovery
+K:310:0x87:0x8A
+
+# Healing
+K:311:0x87:0x8A
+
+# Vision
+K:312:0x87:0x8A
+
+# Identify
+K:313:0x87:0x8A
+
+# Sense Hidden
+K:314:0x87:0x8A
+
+# Reveal Ways
+K:315:0x87:0x8A
+
+# Sense Monsters
+K:316:0x87:0x8A
+
+# Genocide
+K:317:0x87:0x8A
+
+# Summon
+K:318:0x87:0x8A
+
+# Curing
+K:319:0x87:0x8A
+
+# Wish
+K:320:0x87:0x8A
+
+# Mana
+K:321:0x87:0x8A
+
+# Darkness
+K:322:0x87:0x8A
+
+# Genocide
+K:323:0x87:0x8A
+
+# Power
+K:324:0x87:0x8A
+
+# the Magi
+K:325:0x87:0x8A
+
+# Perception
+K:326:0x87:0x8A
+
+# Holiness
+K:327:0x87:0x8A
+
+# Enlightenment
+K:328:0x87:0x8A
+
+# Healing
+K:329:0x87:0x8A
+
+# & Tome~ of Magical Energy
+K:330:0x8B:0xD8
+
+# & Tome~ of the Eternal Flame
+K:331:0x8B:0xD9
+
+# & Tome~ of the Blowing Wind
+K:332:0x8B:0xDA
+
+# & Tome~ of the Impenetrable Earth
+K:333:0x8B:0xDB
+
+# & Tome~ of the Everrunning Wave
+K:334:0x8B:0xDC
+
+# & Tome~ of Translocation
+K:335:0x8B:0xDD
+
+# & Tome~ of the Tree
+K:336:0x8B:0xDE
+
+# & Tome~ of Knowledge
+K:337:0x8B:0xDF
+
+# & Small wooden chest~
+K:338:0x85:0xD1
+
+# & Large wooden chest~
+K:339:0x85:0xD2
+
+# & Small iron chest~
+K:340:0x85:0xD3
+
+# & Large iron chest~
+K:341:0x85:0xD4
+
+# & Small steel chest~
+K:342:0x85:0xD5
+
+# & Large steel chest~
+K:343:0x85:0xD6
+
+# & Ruined chest~
+K:344:0x85:0xD7
+
+# & Iron Spike~
+K:345:0x8A:0xC1
+
+# & Wooden Torch~
+K:346:0x8A:0xC3
+
+# & Brass Lantern~
+K:347:0x8A:0xC2
+
+# & Flask~ of oil
+K:348:0x8A:0xC0
+
+# & Empty Bottle~
+K:349:0x8A:0xBF
+
+# Havoc
+K:350:0x86:0xBB
+
+# Door
+K:351:0x86:0xBB
+
+# Trap Location
+K:352:0x86:0xBB
+
+# Probing
+K:353:0x86:0xBB
+
+# Recall
+K:354:0x86:0xBB
+
+# Illumination
+K:355:0x86:0xBB
+
+# Light
+K:356:0x86:0xBB
+
+# Lightning Bolts
+K:357:0x86:0xBB
+
+# Frost Bolts
+K:358:0x86:0xBB
+
+# Fire Bolts
+K:359:0x86:0xBB
+
+# Polymorph
+K:360:0x86:0xBB
+
+# Slow Monster
+K:361:0x86:0xBB
+
+# Sleep Monster
+K:362:0x86:0xBB
+
+# Drain Life
+K:363:0x86:0xBB
+
+# Teleport Other
+K:364:0x86:0xBB
+
+# Disarming
+K:365:0x86:0xBB
+
+# Lightning Balls
+K:366:0x86:0xBB
+
+# Cold Balls
+K:367:0x86:0xBB
+
+# Fire Balls
+K:368:0x86:0xBB
+
+# Acid Balls
+K:369:0x86:0xBB
+
+# Acid Bolts
+K:370:0x86:0xBB
+
+# Enlightenment
+K:371:0x86:0xBB
+
+# Perception
+K:372:0x86:0xBB
+
+# Curing
+K:373:0x86:0xBB
+
+# Healing
+K:374:0x86:0xBB
+
+# Detection
+K:375:0x86:0xBB
+
+# Restoration
+K:376:0x86:0xBB
+
+# Speed
+K:377:0x86:0xBB
+
+# Spell
+K:378:0xA3:0xFC
+
+# Spell
+K:379:0x89:0xF8
+
+# [Beings of Darkness]
+K:380:0x89:0xF9
+
+# [Material Shadow]
+K:381:0x89:0xFA
+
+# [Nature's Wrath]
+K:382:0x89:0xFB
+
+# [Sign of Chaos]
+K:383:0x89:0xD0
+
+# [Chaos Mastery]
+K:384:0x89:0xD1
+
+# [Chaos Channels]
+K:385:0x89:0xD2
+
+# [Armageddon Tome]
+K:386:0x89:0xD3
+
+# [Nether Openings]
+K:387:0x8A:0x80
+
+# [Unholy Blessings]
+K:388:0x8A:0x81
+
+# & Firestone~
+K:389:0x8A:0xCA
+
+# & Small Firestone~
+K:390:0x8A:0xCB
+
+# & Broken Skull~
+K:391:0x8A:0xCC
+
+# & Broken Bone~
+K:392:0x8A:0xCD
+
+# & Canine Skeleton~
+K:393:0x8A:0xD2
+
+# & Rodent Skeleton~
+K:394:0x8A:0xD3
+
+# & Human Skeleton~
+K:395:0x8A:0xCE
+
+# & Dwarf Skeleton~
+K:396:0x8A:0xD0
+
+# & Elf Skeleton~
+K:397:0x8A:0xCF
+
+# & Gnome Skeleton~
+K:398:0x8A:0xD1
+
+# & Great Hammer~
+K:399:0x9E:0xC2
+
+# Black Dragon Scale Mail~
+K:400:0x88:0xBA
+
+# Blue Dragon Scale Mail~
+K:401:0x88:0xB8
+
+# White Dragon Scale Mail~
+K:402:0x88:0xB9
+
+# Red Dragon Scale Mail~
+K:403:0x88:0xBB
+
+# Green Dragon Scale Mail~
+K:404:0x88:0xBC
+
+# Multi-Hued Dragon Scale Mail~
+K:405:0x88:0xC3
+
+# Pseudo Dragon Scale Mail~
+K:406:0x88:0xBF
+
+# Law Dragon Scale Mail~
+K:407:0x88:0xC1
+
+# Bronze Dragon Scale Mail~
+K:408:0x88:0xBD
+
+# Gold Dragon Scale Mail~
+K:409:0x88:0xBE
+
+# Chaos Dragon Scale Mail~
+K:410:0x88:0xC0
+
+# Balance Dragon Scale Mail~
+K:411:0x88:0xC2
+
+# Power Dragon Scale Mail~
+K:412:0x88:0xC4
+
+# & Dragon Helm~
+K:413:0x87:0xBA
+
+# & Dragon Shield~
+K:414:0x87:0xD4
+
+# Death
+K:415:0x85:0xFD
+
+# Ruination
+K:416:0x85:0xFD
+
+# Detonations
+K:417:0x85:0xFD
+
+# Augmentation
+K:418:0x85:0xFD
+
+# *Healing*
+K:419:0x85:0xFD
+
+# Life
+K:420:0x85:0xFD
+
+# Self Knowledge
+K:421:0x85:0xFD
+
+# *Enlightenment*
+K:422:0x85:0xFD
+
+# [Necromantic Incantations]
+K:423:0x8A:0x82
+
+# [Curses of Angmar]
+K:424:0x8A:0x83
+
+# Fear Resistance
+K:425:0x85:0xBB
+
+# Light and Darkness Resistance
+K:426:0x85:0xBB
+
+# Nether Resistance
+K:427:0x85:0xBB
+
+# Nexus Resistance
+K:428:0x85:0xBB
+
+# Sound Resistance
+K:429:0x85:0xBB
+
+# Confusion Resistance
+K:430:0x85:0xBB
+
+# Shard Resistance
+K:431:0x85:0xBB
+
+# Disenchantment Resistance
+K:432:0x85:0xBB
+
+# Chaos Resistance
+K:433:0x85:0xBB
+
+# Blindness Resistance
+K:434:0x85:0xBB
+
+# Lordly Protection
+K:435:0x85:0xBB
+
+# Extra Attacks
+K:436:0x85:0xBB
+
+# Cure Light Wounds
+K:437:0x85:0xFD
+
+# Clumsiness
+K:438:0x85:0xFD
+
+# Sickliness
+K:439:0x85:0xFD
+
+# Map of Bree
+K:440:0xA5:0xB8
+
+# Map of Gondolin
+K:441:0xA5:0xB8
+
+# Map of Lothlorien
+K:442:0xA5:0xB8
+
+# Map of Minas Anor
+K:443:0xA5:0xB8
+
+# & Silver Arrow~
+K:465:0xA6:0xB9
+
+# & Silver Bolt~
+K:466:0xA6:0xBA
+
+# Lightning Resistance
+K:467:0x86:0xF8
+
+# Wisdom
+K:468:0x86:0xF8
+
+# Regeneration
+K:469:0x86:0xF8
+
+# Infravision
+K:470:0x86:0xF8
+
+# Devotion
+K:471:0x86:0xF8
+
+# Weaponmastery
+K:472:0x86:0xF8
+
+# Trickery
+K:473:0x86:0xF8
+
+# Telepathy
+K:474:0x86:0xF8
+
+# Sustenance
+K:475:0x86:0xF8
+
+# & Palantir~
+K:476:0xA6:0xBF
+
+# & Elfstone~
+K:477:0xA6:0xBB
+
+# & Jewel~
+K:478:0xA6:0xBC
+
+# & Ring~
+K:479:0xA6:0xBD
+
+# copper
+K:480:0x85:0x89
+
+# copper
+K:481:0x85:0x89
+
+# copper
+K:482:0x85:0x89
+
+# silver
+K:483:0x85:0x8A
+
+# silver
+K:484:0x85:0x8A
+
+# silver
+K:485:0x85:0x8A
+
+# garnets
+K:486:0x85:0x8E
+
+# garnets
+K:487:0x85:0x8E
+
+# gold
+K:488:0x85:0x8B
+
+# gold
+K:489:0x85:0x8B
+
+# gold
+K:490:0x85:0x8B
+
+# opals
+K:491:0x85:0x8F
+
+# sapphires
+K:492:0x85:0x90
+
+# rubies
+K:493:0x85:0x91
+
+# diamonds
+K:494:0x85:0x92
+
+# emeralds
+K:495:0x85:0x93
+
+# mithril
+K:496:0x85:0x8C
+
+# adamantite
+K:497:0x85:0x8D
+
+# & Mighty Hammer~
+K:498:0x9E:0xC2
+
+# & Massive Iron Crown~
+K:499:0x87:0x94
+
+# & Phial~
+K:500:0x8A:0xD5
+
+# & Star~
+K:501:0x8A:0xD6
+
+# & Arkenstone~
+K:502:0x8A:0xD7
+
+# & Amulet~
+K:503:0x85:0xCE
+
+# & Amulet~
+K:504:0x85:0xCF
+
+# & Necklace~
+K:505:0x85:0xD0
+
+# & Ring~
+K:506:0x85:0xC7
+
+# & Ring~
+K:507:0x85:0xC8
+
+# & Ring~
+K:508:0x85:0xCA
+
+# & Ring~
+K:509:0x85:0xCB
+
+# & Ring~
+K:510:0x85:0xCC
+
+# & Ring~
+K:511:0x85:0xCD
+
+# [Rites of Initiation]
+K:512:0x8A:0x88
+
+# [Ways of War]
+K:513:0x8A:0x89
+
+# [Divine Retribution]
+K:514:0x8A:0x8A
+
+# [Essence of Fury]
+K:515:0x8A:0x8B
+
+# [Novice Crafts]
+K:516:0x8A:0x84
+
+# [Arcane Channels]
+K:517:0x8A:0x85
+
+# [Sigils of Wizardry]
+K:518:0x8A:0x86
+
+# [Mana Focus]
+K:519:0x8A:0x87
+
+# Reflection
+K:520:0x86:0xFB
+
+# Anti-Magic
+K:521:0x86:0xFB
+
+# Anti-Teleportation
+K:522:0x86:0xFB
+
+# Resistance
+K:523:0x86:0xFB
+
+# & Zweihander~
+K:524:0x9E:0xC4
+
+# & Dwarven Lantern~
+K:525:0xA6:0x8C
+
+# Splint Mail~
+K:526:0x88:0x94
+
+# & Everburning Torch~
+K:527:0xA6:0x8D
+
+# & Trifurcate Spear~
+K:528:0x9E:0xBD
+
+# & Three Piece Rod~
+K:529:0x9E:0xB8
+
+# & Feanorian Lamp~
+K:530:0xA6:0x8E
+
+# & Fur Cloak~
+K:531:0x88:0x81
+
+# Water Curing
+K:532:0x9E:0xBE
+
+# & Hatchet~
+K:533:0x9E:0xC7
+
+# Rhino Hide Armour~
+K:535:0x88:0x90
+
+# Leather Jacket~
+K:536:0x88:0x87
+
+# & Sickle~
+K:537:0x9E:0xC8
+
+# [Psychoportation]
+K:538:0x9E:0xBF
+
+# [Clairsentience]
+K:539:0x9E:0xC9
+
+# [Telekinesis]
+K:540:0x9E:0xCB
+
+# [Empathy]
+K:541:0x9E:0xCA
+
+# & Club~
+K:542:0x9E:0xCA
+
+# & Broad Spear~
+K:543:0x9E:0xBC
+
+# & Khopesh~
+K:544:0x9E:0xCC
+
+# & Flamberge~
+K:545:0x9E:0xBB
+
+# & Claymore~
+K:546:0x9E:0xC5
+
+# & Espadon~
+K:547:0x9E:0xC6
+
+# & Great Scimitar~
+K:548:0x9E:0xC3
+
+# Arrow
+K:549:0x8A:0xD8
+
+# Bolt
+K:550:0x8A:0xD9
+
+# & Fauchard~
+K:551:0x9E:0xCD
+
+# & Guisarme~
+K:552:0x9E:0xCE
+
+# & Heavy Lance~
+K:553:0x9E:0xBA
+
+# & Basillard~
+K:554:0x9E:0xD1
+
+# Catapult
+K:555:0x8A:0xDA
+
+# Ring Mail~
+K:556:0x88:0x94
+
+# Cord Armour~
+K:557:0x88:0x88
+
+# Paper Armour~
+K:558:0x88:0xB9
+
+# Padded Armour~
+K:559:0x88:0x89
+
+# Fumes
+K:560:0x8A:0xDB
+
+# Stone and Hide Armour~
+K:561:0x88:0x8F
+
+# Magic
+K:562:0x8A:0xDC
+
+# Device
+K:563:0x8A:0xDD
+
+# Nothing
+K:564:0xA6:0xD4
+
+# Poison
+K:565:0x9E:0xF8
+
+# Nothing
+K:566:0xA6:0xD4
+
+# Nothing
+K:567:0xA6:0xD4
+
+# Nothing
+K:568:0xA6:0xD4
+
+# Nothing
+K:569:0xA6:0xD4
+
+# Explosion
+K:570:0x9E:0xF9
+
+# Teleport
+K:571:0x9E:0xFA
+
+# Nothing
+K:572:0xA6:0xD4
+
+# & Blood~ of Life
+K:573:0x85:0xFD
+
+# Cold
+K:574:0x9E:0xFB
+
+# Fire
+K:575:0x9E:0xFC
+
+# Acid
+K:576:0x9E:0xFD
+
+# & Mage Staff~
+K:577:0x9F:0xB8
+
+# Lightning
+K:578:0x85:0xB8
+
+# Life
+K:579:0x9E:0xFE
+
+# Confusion
+K:580:0x9E:0xFF
+
+# Light
+K:581:0x9F:0x80
+
+# & Ring~
+K:582:0x85:0xBD
+
+# Invisibility
+K:583:0x85:0xFD
+
+# Chaos
+K:584:0x9F:0x81
+
+# Corruption
+K:585:0x85:0xFD
+
+# Invisibility
+K:586:0x85:0xFD
+
+# Time
+K:587:0x9F:0x82
+
+# Deep Thoughts
+K:588:0x85:0x94
+
+# More Deep Thoughts
+K:589:0x85:0x95
+
+# Compendium of Deep Thoughts
+K:590:0x85:0x96
+
+# Artifact Lore Vol. I
+K:591:0x85:0x94
+
+# Artifact Lore Vol. II
+K:592:0x85:0x95
+
+# Artifact Lore Vol. III
+K:593:0x85:0x97
+
+# Monstrous Compendium 1
+K:594:0x85:0x97
+
+# Monstrous Compendium 2
+K:595:0x85:0x96
+
+# Monstrous Compendium 3
+K:596:0x85:0x95
+
+# Monstrous Compendium 4
+K:597:0x85:0x94
+
+# Monstrous Compendium 5
+K:598:0x85:0x97
+
+# Monstrous Compendium 6
+K:599:0x85:0x96
+
+# Monstrous Compendium 7
+K:600:0x85:0x95
+
+# Monstrous Compendium 8
+K:601:0x85:0x94
+
+# Monstrous Compendium 9
+K:602:0x85:0x95
+
+# Monstrous Compendium 10
+K:603:0x85:0x96
+
+# Monstrous Compendium 11
+K:604:0x85:0x97
+
+# Abomination
+K:605:0x85:0xFD
+
+# Shape of Wolf
+K:606:0x85:0xFD
+
+# Shape of Ape
+K:607:0x85:0xFD
+
+# Shape of Goat
+K:608:0x85:0xFD
+
+# Shape of Insect
+K:609:0x85:0xFD
+
+# Shape of Sparrow
+K:610:0x85:0xFD
+
+# Shape of Ent
+K:611:0x85:0xFD
+
+# Shape of Vampire
+K:612:0x85:0xFD
+
+# Shape of Spider
+K:613:0x85:0xFD
+
+# Shape of Mana ball
+K:614:0x85:0xFD
+
+# Shape of Fire cloud
+K:615:0x85:0xFD
+
+# Shape of Cold cloud
+K:616:0x85:0xFD
+
+# Shape of Chaos cloud
+K:617:0x85:0xFD
+
+# [Wolf]
+K:618:0x8B:0x98
+
+# [Ape]
+K:619:0x8B:0x99
+
+# [Goat]
+K:620:0x8B:0x9A
+
+# [Insect]
+K:621:0x8B:0x9B
+
+# [Sparrow]
+K:622:0x8B:0x9C
+
+# [Ent]
+K:623:0x8B:0x9D
+
+# [Vampire]
+K:624:0x8B:0x9E
+
+# [Spider]
+K:625:0x8B:0x9F
+
+# [Mana ball]
+K:626:0x8B:0xA0
+
+# [Fire cloud]
+K:627:0x8B:0xA1
+
+# [Cold cloud]
+K:628:0x8B:0xA2
+
+# [Chaos Cloud]
+K:629:0x8B:0xA3
+
+# [Ghost]
+K:630:0x8B:0xA4
+
+# [Kobold]
+K:631:0x8B:0xA5
+
+# [Dragon]
+K:632:0x8B:0xA6
+
+# [Demon]
+K:633:0x8B:0xA7
+
+# [Hound]
+K:634:0x8B:0xA8
+
+# [Quylthulg]
+K:635:0x8B:0xA9
+
+# [Maia]
+K:636:0x8B:0xAA
+
+# [Serpent]
+K:637:0x8B:0xAB
+
+# [Giant]
+K:638:0x8B:0xAC
+
+# [Vala]
+K:639:0x8B:0xAD
+
+# Magic
+K:640:0x9F:0x83
+
+# corpse
+K:641:0x9F:0xB9
+
+# skeleton
+K:642:0x8A:0xCE
+
+# head
+K:643:0x8A:0xCC
+
+# skull
+K:644:0x8A:0xCC
+
+# raw meat
+K:645:0x8A:0xBB
+
+# & Thunderlord Coat~
+K:646:0x88:0xBE
+
+# & Stone~
+K:647:0x8A:0xD4
+
+# & small wooden Boomerang~
+K:648:0x9F:0xBA
+
+# & wooden Boomerang~
+K:649:0x9F:0xBB
+
+# & small metal Boomerang~
+K:650:0x9F:0xBC
+
+# & metal Boomerang~
+K:651:0x9F:0xBD
+
+# & Anchor~
+K:652:0x8A:0x96
+
+# & ~
+K:653:0xA6:0xD4
+
+# Summon never-moving pet
+K:654:0x85:0x95
+
+# [Life in symbiosis]
+K:655:0x9F:0xBE
+
+# [Perfect Symbiosis]
+K:656:0x9F:0xBE
+
+# Cure Light Insanity
+K:657:0x85:0xFD
+
+# Cure Serious Insanity
+K:658:0x85:0xFD
+
+# Cure Critical Insanity
+K:659:0x85:0xFD
+
+# Cure Insanity
+K:660:0x85:0xFD
+
+# & Phial~
+K:661:0x8A:0xD5
+
+# Random Artifact
+K:662:0xA6:0xD4
+
+# Craftmanship
+K:663:0x85:0x97
+
+# The One Ring
+K:664:0x85:0x96
+
+# & Book~ of the Lays of the Heroes
+K:665:0x9F:0xBF
+
+# & Book~ of Sound Patterns
+K:666:0x9F:0xBF
+
+# [Harps of Rivendell]
+K:667:0x9F:0xBF
+
+# [Lays of Beleriand]
+K:668:0x9F:0xBF
+
+# & Flute~
+K:669:0x9F:0xC0
+
+# & Drum~
+K:670:0x9F:0xC1
+
+# & Harp~
+K:671:0x9F:0xC2
+
+# & Banjo~
+K:672:0x9F:0xC4
+
+# & Lute~
+K:673:0x9F:0xC3
+
+# & Mandolin~
+K:674:0x9F:0xC3
+
+# & Palantir~
+K:675:0x8A:0x97
+
+# Egg
+K:676:0x9F:0x85
+
+# Reset Recall
+K:677:0x85:0x95
+
+# Divination
+K:678:0x85:0x95
+
+# Self
+K:679:0x9F:0x86
+
+# Ray
+K:680:0x9F:0x87
+
+# Sphere
+K:681:0x9F:0x88
+
+# Knowledge
+K:682:0x9F:0x8C
+
+# Life
+K:683:0x9F:0x8D
+
+# Fire
+K:684:0x9F:0x8E
+
+# Cold
+K:685:0x9F:0x8F
+
+# Lightning
+K:686:0x9F:0x90
+
+# Acid
+K:687:0x9F:0x91
+
+# Element
+K:688:0x9F:0x92
+
+# Chaos
+K:689:0x9F:0x93
+
+# Mind
+K:690:0x9F:0x94
+
+# Holding
+K:691:0x9F:0x95
+
+# Arrow
+K:692:0x9F:0x89
+
+# Power Surge
+K:693:0x9F:0x8A
+
+# Armageddon
+K:694:0x9F:0x8B
+
+# Gravity
+K:695:0x9F:0x96
+
+# Extra Life
+K:696:0x9F:0x97
+
+# Undeath
+K:697:0x9E:0xD3
+
+# Protection
+K:698:0x9E:0xD4
+
+# & Horn~
+K:699:0x9F:0xC5
+
+# & Ring~ of Precognition
+K:700:0x85:0xBB
+
+# & Sprig~ of Athelas
+K:701:0x9F:0xC6
+
+# [Magic for Beginners]
+K:702:0x9F:0xC7
+
+# [Conjurings and Tricks]
+K:703:0x9F:0xC7
+
+# [Incantations and Illusions]
+K:704:0x9F:0xC7
+
+# [Sorcery and Evocations]
+K:705:0x9F:0xC7
+
+# [Beginners Handbook]
+K:706:0x9F:0xC8
+
+# [Words of Wisdom]
+K:707:0x9F:0xC8
+
+# [Chants and Blessings]
+K:708:0x9F:0xC8
+
+# [Exorcism and Dispelling]
+K:709:0x9F:0xC8
+
+# [Resistance of Scarabtarices]
+K:710:0x9F:0xCA
+
+# [Mordenkainen's Escapes]
+K:711:0x9F:0xCA
+
+# [Kelek's Grimoire of Power]
+K:712:0x9F:0xCA
+
+# [Tenser's Transformations]
+K:713:0x9F:0xCA
+
+# [Raal's Tome of Destruction]
+K:714:0x9F:0xCA
+
+# [Ethereal Openings]
+K:715:0x9F:0xCA
+
+# [Godly Insights]
+K:716:0x9F:0xC9
+
+# [Purifications and Healing]
+K:717:0x9F:0xC9
+
+# [Holy Infusions]
+K:718:0x9F:0xC9
+
+# [Wrath of God]
+K:719:0x9F:0xC9
+
+# & Old Scroll~ of Deincarnation
+K:720:0x85:0x97
+
+# & Dark Sword~
+K:721:0xA5:0xB9
+
+# Numenorean for beginners (I)
+K:722:0xA3:0xF8
+
+# Numenorean for beginners (II)
+K:723:0xA3:0xF9
+
+# Advanced lessons of Numenorean
+K:724:0xA3:0xF8
+
+# Advanced lessons of Sindarin
+K:725:0xA3:0xF9
+
+# & Shard~ of Pottery
+K:726:0x8A:0xCA
+
+# & Broken Stick~
+K:727:0x8A:0xCB
+
+# Wall Creation
+K:728:0x85:0x97
+
+# [Illusions for Beginners]
+K:729:0xA3:0xFA
+
+# [Tricks and Visions]
+K:730:0xA3:0xFA
+
+# [Phantasms and Illusions]
+K:731:0xA3:0xFA
+
+# [Shadows and Prisms]
+K:732:0xA3:0xFA
+
+# [Serten's Immunities]
+K:733:0xA3:0xFB
+
+# [Knowledge of Kenault]
+K:734:0xA3:0xFB
+
+# [Otiluke's Spheres]
+K:735:0xA3:0xFA
+
+# [Boccob's Book of Shadows]
+K:736:0xA3:0xFC
+
+# [Bigby's Handbook]
+K:737:0xA3:0xFC
+
+# & Book~ of Beginner Cantrips
+K:738:0xA3:0xFD
+
+# & Book~ of Teleportation
+K:739:0xA3:0xFE
+
+# & Book~ of Recall
+K:740:0xA3:0xFF
+
+# & Book~ of Summoning
+K:741:0xA3:0xF8
+
+# & Book~ of Fireflash
+K:742:0xA3:0xF9
+
+# & Potion~ of Learning
+K:743:0xA3:0xFA
+
+# [Eye of Sauron]
+K:744:0xA3:0xFB
+
+# [Flame of Udun]
+K:745:0xA3:0xFC
+
+# [Corruptions of Melkor]
+K:746:0xA3:0xFD
+
+# [Crescent of Morgul]
+K:747:0xA3:0xFE
+
+# [Morgoth's Ring]
+K:748:0xA3:0xFF
+
+# Spell
+K:749:0x86:0xC8
+
+# Wishing
+K:750:0x86:0xC8
+
+# Khuzdul - The hidden tongue of the Dwarves
+K:751:0x85:0x95
+
+# Nandorin for dummies
+K:752:0xA3:0xF9
+
+# Advanced lessons of Orcish
+K:753:0xA3:0xFA
+
+# & Ancient Tome~
+K:754:0xA3:0xFE
+
+# Flying
+K:755:0x85:0xC0
+
+# & Tome~ of the Time
+K:756:0xA3:0xF8
+
+# & Spellbook~ of #
+K:757:0x8C:0x9C
+
+# & Tome~ of Meta Spells
+K:758:0xA3:0xF9
+
+# & Tome~ of the Mind
+K:759:0xA3:0xFA
+
+# & Holy Tome~ of Eru Iluvatar
+K:760:0xA3:0xFB
+
+# & Holy Tome~ of Manwe Sulimo
+K:761:0xA3:0xFC
+
+# & War Tome~ of Tulkas
+K:762:0xA3:0xFD
+
+# & Unholy Tome~ of the Hellflame
+K:763:0xA3:0xFE
+
+# & Corrupted Tome~ of Melkor
+K:764:0xA3:0xFF
+
+# [Aiding Shades]
+K:765:0xA3:0xF8
+
+# [Morgoth's Space-Time Warpings]
+K:766:0xA3:0xF9
+
+# [Murazor's Tome of Conjuring & Dispelling]
+K:767:0xA3:0xFA
+
+# & Forest Tome~ of Yavanna
+K:768:0xA3:0xFB
+
+# [Sauron's Forgotten Tome]
+K:769:0xA3:0xFF
+
+# & Ring~
+K:770:0x85:0xBC
+
+# [Earth]
+K:771:0xA4:0x80
+
+# [Fire]
+K:772:0xA4:0x81
+
+# [Air]
+K:773:0xA4:0x82
+
+# [Water]
+K:774:0xA4:0x83
+
+# [Mana]
+K:775:0xA4:0x84
+
+# Home Summoning
+K:776:0x85:0x97
+
+# & Shadow Blade~
+K:777:0xA4:0x89
+
+# & Bluesteel Blade~
+K:778:0xA4:0x8A
+
+# the Serpents
+K:779:0xA5:0xC0
+
+# Darkness
+K:780:0xA5:0xC1
+
+# Knowledge
+K:781:0xA5:0xC2
+
+# Force
+K:782:0xA5:0xC3
+
+# Lightning
+K:783:0xA5:0xC4
+
+# Mana
+K:784:0xA5:0xC5
+
+# Ring~ of Power
+K:785:0xA5:0xC6
+
+# Climbing Set~
+K:786:0xA4:0x8B
+
+# Adventurer's guide to Middle-earth
+K:787:0x85:0x96
+
+# & Demonblade~
+K:788:0x8B:0xE0
+
+# & Demonshield~
+K:789:0x8B:0xE1
+
+# & Demonhorn~
+K:790:0x8B:0xE2
+
+# [Demonthoughts]
+K:791:0xA3:0xFB
+
+# [Hellfire Tome]
+K:792:0xA4:0x8C
+
+# & Wooden Rod~ of#
+K:793:0xA4:0x8D
+
+# & Copper Rod~ of#
+K:794:0xA4:0x8E
+
+# & Iron Rod~ of#
+K:795:0xA4:0x8F
+
+# & Moonstone Rod~ of#
+K:796:0xA4:0x90
+
+# & Silver Rod~ of#
+K:797:0xA4:0x91
+
+# & Golden Rod~ of#
+K:798:0xA4:0x93
+
+# & Mithril Rod~ of#
+K:799:0xA4:0x94
+
+# & Adamantite Rod~ of#
+K:800:0xA4:0x95
+
+# & Greater Ration~ of Health
+K:801:0xA5:0xBF
+
+# & Crumpled Scroll~ of Mass Resurrection
+K:802:0x85:0x96
+
+# & Cleaver~
+K:803:0xA5:0xBA
+
+# & Light War Axe~
+K:804:0xA5:0xBB
+
+# & Slaughter Axe~
+K:805:0xA5:0xBC
+
+# & Runestone~
+K:806:0xA5:0xBD
+
+# & Fortune cookie~
+K:807:0xA6:0xBE
+
+# Portable hole
+K:808:0xA6:0xC1
+
+# Critical Hits
+K:809:0xA6:0xD4
+
+# & Wand~ of Digging of Thrain
+K:810:0xA6:0xD4
+
+# & Gnarled Staff~ of Holy Fire of Mithrandir
+K:811:0xA6:0xD4
+
+# Partial Totem
+K:812:0xA6:0xD5
+
+# True Totem
+K:813:0xA6:0xD6
+
+# & piece~ of a Relic of Eru
+K:814:0x89:0xDA
+
+# & piece~ of a Relic of Manwe
+K:815:0x89:0xDB
+
+# & piece~ of a Relic of Tulkas
+K:816:0x89:0xDC
+
+# & piece~ of a Relic of Melkor
+K:817:0x89:0xDD
+
+# & piece~ of a Relic of Yavanna
+K:818:0x89:0xDE
+
+# Player
+R:0:0x80:0xC0
+
+# Filthy street urchin
+R:1:0x98:0xB8
+
+# Scrawny cat
+R:2:0x96:0xFA
+
+# Sparrow
+R:3:0x9D:0xD6
+
+# Chaffinch
+R:4:0x9D:0xD6
+
+# Wild rabbit
+R:5:0x9D:0xD7
+
+# Woodsman
+R:6:0x98:0xC9
+
+# Scruffy little dog
+R:7:0x92:0x92
+
+# Farmer Maggot
+R:8:0x98:0xB9
+
+# Blubbering idiot
+R:9:0x98:0xBA
+
+# Boil-covered wretch
+R:10:0x98:0xBB
+
+# Village idiot
+R:11:0x98:0xBC
+
+# Pitiful-looking beggar
+R:12:0x98:0xBD
+
+# Mangy-looking leper
+R:13:0x98:0xBE
+
+# Agent of the black market
+R:14:0x98:0xBF
+
+# Singing, happy drunk
+R:15:0x98:0xC0
+
+# Aimless-looking merchant
+R:16:0x98:0xC1
+
+# Mean-looking mercenary
+R:17:0x98:0xC2
+
+# Battle-scarred veteran
+R:18:0x98:0xC3
+
+# Martti Ihrasaari
+R:19:0x9B:0xB8
+
+# Grey mold
+R:20:0x97:0xD7
+
+# Large white snake
+R:21:0x94:0xBD
+
+# Grey mushroom patch
+R:22:0x9B:0xB9
+
+# Newt
+R:23:0x9B:0xBA
+
+# Giant white centipede
+R:24:0x96:0x8D
+
+# White icky thing
+R:25:0x97:0xBB
+
+# Clear icky thing
+R:26:0x97:0xBC
+
+# Giant white mouse
+R:27:0x99:0xBD
+
+# Large brown snake
+R:28:0x94:0xBC
+
+# Small kobold
+R:29:0x97:0xD1
+
+# Kobold
+R:30:0x97:0xD2
+
+# White worm mass
+R:31:0x99:0xD5
+
+# Floating eye
+R:32:0x96:0xD3
+
+# Rock lizard
+R:33:0x94:0xBE
+
+# Grid bug
+R:34:0x9B:0xBC
+
+# Jackal
+R:35:0x92:0x93
+
+# Soldier ant
+R:36:0x95:0xFF
+
+# Fruit bat
+R:37:0x96:0x87
+
+# Insect swarm
+R:38:0x9E:0x96
+
+# The Greater hell-beast
+R:39:0x9B:0xBB
+
+# Shrieker mushroom patch
+R:40:0x91:0xFE
+
+# Blubbering icky thing
+R:41:0x97:0xBD
+
+# Metallic green centipede
+R:42:0x96:0x8E
+
+# Novice warrior
+R:43:0x98:0xC4
+
+# Novice rogue
+R:44:0x98:0xC5
+
+# Novice priest
+R:45:0x98:0xC6
+
+# Novice mage
+R:46:0x98:0xC7
+
+# Yellow mushroom patch
+R:47:0x91:0xFF
+
+# White jelly
+R:48:0x97:0xC2
+
+# Giant black ant
+R:49:0x96:0x80
+
+# Salamander
+R:50:0x94:0xC0
+
+# White harpy
+R:51:0x93:0xC0
+
+# Blue yeek
+R:52:0x99:0xFF
+
+# Grip, Farmer Maggot's dog
+R:53:0x92:0x94
+
+# Wolf, Farmer Maggot's dog
+R:54:0x92:0x95
+
+# Fang, Farmer Maggot's dog
+R:55:0x92:0x95
+
+# Giant green frog
+R:56:0x94:0xBF
+
+# Freesia
+R:57:0x9B:0xBD
+
+# Green worm mass
+R:58:0x99:0xD6
+
+# Large yellow snake
+R:59:0x94:0xC1
+
+# Cave spider
+R:60:0x94:0xD5
+
+# Crow
+R:61:0x9E:0x97
+
+# Wild cat
+R:62:0x96:0xFB
+
+# Smeagol
+R:63:0x98:0xC8
+
+# Green ooze
+R:64:0x97:0xC3
+
+# Poltergeist
+R:65:0x93:0x91
+
+# Yellow jelly
+R:66:0x97:0xC5
+
+# Metallic blue centipede
+R:67:0x96:0x8F
+
+# Raven
+R:68:0x9E:0x97
+
+# Giant white louse
+R:69:0x97:0xD5
+
+# Giant yellow centipede
+R:70:0x96:0x8C
+
+# Black naga
+R:71:0x98:0x80
+
+# Spotted mushroom patch
+R:72:0x92:0x80
+
+# Silver jelly
+R:73:0x97:0xC4
+
+# Scruffy-looking hobbit
+R:74:0x97:0x8B
+
+# Giant white ant
+R:75:0x96:0x81
+
+# Yellow mold
+R:76:0x97:0xF8
+
+# Metallic red centipede
+R:77:0x96:0x90
+
+# Yellow worm mass
+R:78:0x99:0xD7
+
+# Clear worm mass
+R:79:0x99:0xF8
+
+# Radiation eye
+R:80:0x96:0xD4
+
+# Yellow light
+R:81:0x9F:0xCB
+
+# Cave lizard
+R:82:0x94:0xC2
+
+# Novice ranger
+R:83:0x98:0xC9
+
+# Blue jelly
+R:84:0x97:0xC6
+
+# Creeping copper coins
+R:85:0x91:0xF8
+
+# Giant white rat
+R:86:0x99:0xBE
+
+# Snotling
+R:87:0xA0:0x81
+
+# Swordfish
+R:88:0x9E:0xD6
+
+# Blue worm mass
+R:89:0x99:0xF9
+
+# Large grey snake
+R:90:0x94:0xC3
+
+# Skeleton kobold
+R:91:0x99:0xC1
+
+# Ewok
+R:92:0x9B:0xBE
+
+# Novice mage
+R:93:0x98:0xC7
+
+# Green naga
+R:94:0x98:0x81
+
+# Giant leech
+R:95:0x9F:0xCC
+
+# Barracuda
+R:96:0x9E:0xD7
+
+# Novice paladin
+R:97:0x98:0xCA
+
+# Zog
+R:98:0x93:0xF8
+
+# Blue ooze
+R:99:0x97:0xC7
+
+# Green glutton ghost
+R:100:0x93:0x92
+
+# Green jelly
+R:101:0x97:0xC8
+
+# Large kobold
+R:102:0x97:0xD3
+
+# Grey icky thing
+R:103:0x97:0xBE
+
+# Disenchanter eye
+R:104:0x96:0xD5
+
+# Red worm mass
+R:105:0x99:0xFA
+
+# Copperhead snake
+R:106:0x94:0xC4
+
+# Death sword
+R:107:0x9B:0xBF
+
+# Purple mushroom patch
+R:108:0x92:0x81
+
+# Novice priest
+R:109:0x98:0xC6
+
+# Novice warrior
+R:110:0x98:0xC4
+
+# Nibelung
+R:111:0x9B:0xC0
+
+# The disembodied hand that strangled people
+R:112:0x9B:0xC1
+
+# Brown mold
+R:113:0x97:0xF9
+
+# Giant brown bat
+R:114:0x96:0x88
+
+# Rat-thing
+R:115:0x99:0xC0
+
+# Novice rogue
+R:116:0x98:0xBF
+
+# Creeping silver coins
+R:117:0x91:0xF9
+
+# Snaga
+R:118:0x98:0x86
+
+# Rattlesnake
+R:119:0x94:0xC5
+
+# Giant slug
+R:120:0x9F:0xCC
+
+# Giant pink frog
+R:121:0x9F:0xCD
+
+# Dark elf
+R:122:0x8C:0xCC
+
+# Zombified kobold
+R:123:0x99:0xC1
+
+# Crypt creep
+R:124:0x9B:0xC2
+
+# Rotting corpse
+R:125:0x9B:0xC3
+
+# Cave orc
+R:126:0x98:0x87
+
+# Wood spider
+R:127:0x94:0xD6
+
+# Manes
+R:128:0x93:0xC9
+
+# Bloodshot eye
+R:129:0x96:0xD6
+
+# Red naga
+R:130:0x98:0x82
+
+# Red jelly
+R:131:0x97:0xC9
+
+# Green icky thing
+R:132:0x97:0xBF
+
+# Lost soul
+R:133:0x93:0x93
+
+# Night lizard
+R:134:0x94:0xC7
+
+# Mughash, the Kobold Lord
+R:135:0x97:0xD4
+
+# Skeleton orc
+R:136:0x99:0xC2
+
+# Wormtongue, Agent of Saruman
+R:137:0x98:0xD0
+
+# Robin Hood, the Outlaw
+R:138:0x9B:0xC4
+
+# Nurgling
+R:139:0x9F:0xCF
+
+# Lagduf, the Snaga
+R:140:0x98:0x88
+
+# Brown yeek
+R:141:0x9A:0x80
+
+# Novice ranger
+R:142:0x98:0xC9
+
+# Giant salamander
+R:143:0x94:0xC8
+
+# Space monster
+R:144:0x9B:0xC5
+
+# Carnivorous flying monkey
+R:145:0x9F:0xD0
+
+# Green mold
+R:146:0x97:0xFA
+
+# Novice paladin
+R:147:0x98:0xCA
+
+# Lemure
+R:148:0x93:0xCA
+
+# Hill orc
+R:149:0x98:0x89
+
+# Bandit
+R:150:0x98:0xD3
+
+# Hunting hawk
+R:151:0x9B:0xC6
+
+# Phantom warrior
+R:152:0x9B:0xC7
+
+# Gremlin
+R:153:0x9B:0xC8
+
+# Yeti
+R:154:0x95:0xC9
+
+# Bloodshot icky thing
+R:155:0x97:0xC0
+
+# Giant grey rat
+R:156:0x99:0xBF
+
+# Black harpy
+R:157:0x93:0xC1
+
+# Skaven
+R:158:0x9F:0xD1
+
+# The wounded bear
+R:159:0xA0:0xB8
+
+# Cave bear
+R:160:0xA5:0xC7
+
+# Rock mole
+R:161:0xA0:0xBA
+
+# Mindcrafter
+R:162:0x98:0xCB
+
+# Baby blue dragon
+R:163:0x96:0x95
+
+# Baby white dragon
+R:164:0x96:0x96
+
+# Baby green dragon
+R:165:0x96:0x97
+
+# Baby black dragon
+R:166:0x96:0xB8
+
+# Baby red dragon
+R:167:0x96:0xB9
+
+# Giant red ant
+R:168:0x96:0x85
+
+# Brodda, the Easterling
+R:169:0x98:0xD4
+
+# Bloodfang, the Wolf
+R:170:0xA0:0xBB
+
+# King cobra
+R:171:0x94:0xC9
+
+# Eagle
+R:172:0x9D:0xD6
+
+# War bear
+R:173:0x9B:0xC9
+
+# Killer bee
+R:174:0x9B:0xCA
+
+# Giant spider
+R:175:0x94:0xD7
+
+# Giant white tick
+R:176:0x97:0xD5
+
+# The Borshin
+R:177:0xA0:0xBC
+
+# Dark elven mage
+R:178:0x97:0x8E
+
+# Kamikaze yeek
+R:179:0xA0:0xCC
+
+# Orfax, Son of Boldor
+R:180:0x9A:0x81
+
+# Servant of Glaaki
+R:181:0xA0:0xBD
+
+# Dark elven warrior
+R:182:0x97:0x8F
+
+# Sand-dweller
+R:183:0xA0:0xBE
+
+# Clear mushroom patch
+R:184:0x9F:0xCE
+
+# Quiver slot
+R:185:0x9B:0xCB
+
+# Grishnakh, the Hill Orc
+R:186:0x98:0x8B
+
+# Giant tan bat
+R:187:0xA5:0xC8
+
+# Owlbear
+R:188:0xA0:0xBF
+
+# Blue horror
+R:189:0x9F:0xD2
+
+# Hairy mold
+R:190:0x97:0xFB
+
+# Grizzly bear
+R:191:0xA0:0xC0
+
+# Disenchanter mold
+R:192:0x97:0xFC
+
+# Pseudo dragon
+R:193:0x96:0xBA
+
+# Tengu
+R:194:0x93:0xCB
+
+# Creeping gold coins
+R:195:0x91:0xFA
+
+# Wolf
+R:196:0x92:0x96
+
+# Giant fruit fly
+R:197:0x93:0x89
+
+# Panther
+R:198:0x96:0xFC
+
+# Brigand
+R:199:0x9B:0xCC
+
+# Hobbes the Tiger
+R:200:0x9B:0xCD
+
+# Shadow Creature of Fiona
+R:201:0x9B:0xCE
+
+# Undead mass
+R:202:0x9B:0xCF
+
+# Chaos shapechanger
+R:203:0x9B:0xD0
+
+# Baby multi-hued dragon
+R:204:0x96:0xBB
+
+# Vorpal bunny
+R:205:0x9D:0xD7
+
+# Old Man Willow
+R:206:0xA0:0xC1
+
+# Hippocampus
+R:207:0xA0:0xC2
+
+# Zombified orc
+R:208:0x99:0xC4
+
+# Hippogriff
+R:209:0x93:0xC2
+
+# Black mamba
+R:210:0x94:0xCA
+
+# White wolf
+R:211:0x92:0x97
+
+# Grape jelly
+R:212:0x97:0xCA
+
+# Nether worm mass
+R:213:0x99:0xFB
+
+# Abyss worm mass
+R:214:0x9B:0xD1
+
+# Golfimbul, the Hill Orc Chief
+R:215:0x98:0x8C
+
+# Swordsman
+R:216:0x8E:0xF9
+
+# Skaven shaman
+R:217:0x90:0xBC
+
+# Baby bronze dragon
+R:218:0x96:0xBA
+
+# Baby gold dragon
+R:219:0x96:0xBA
+
+# Evil eye
+R:220:0xA5:0xC9
+
+# Mine-dog
+R:221:0xA0:0x83
+
+# Hellcat
+R:222:0x9B:0xD2
+
+# Moon beast
+R:223:0x9B:0xD3
+
+# Master yeek
+R:224:0x9A:0x82
+
+# Priest
+R:225:0x98:0xD6
+
+# Dark elven priest
+R:226:0x97:0x91
+
+# Air spirit
+R:227:0x92:0xD7
+
+# Skeleton human
+R:228:0x99:0xC3
+
+# Zombified human
+R:229:0x9A:0x86
+
+# Tiger
+R:230:0x96:0xFD
+
+# Moaning spirit
+R:231:0x93:0x94
+
+# Stegocentipede
+R:232:0x96:0x91
+
+# Spotted jelly
+R:233:0x97:0xCB
+
+# Drider
+R:234:0x94:0xF8
+
+# Mongbat
+R:235:0x9B:0xD4
+
+# Killer brown beetle
+R:236:0x93:0xD3
+
+# Boldor, King of the Yeeks
+R:237:0x9A:0x83
+
+# Ogre
+R:238:0x94:0x83
+
+# Creeping mithril coins
+R:239:0x91:0xFB
+
+# Illusionist
+R:240:0x98:0xF8
+
+# Druid
+R:241:0x98:0xF9
+
+# Pink horror
+R:242:0x9F:0xD3
+
+# Cloaker
+R:243:0x88:0x80
+
+# Black orc
+R:244:0x98:0x8D
+
+# Ochre jelly
+R:245:0x97:0xCC
+
+# Software bug
+R:246:0x9B:0xD5
+
+# Lurker
+R:247:0x83:0xB9
+
+# Tangleweed
+R:248:0xA5:0xCA
+
+# Vlasta
+R:249:0x95:0xFC
+
+# Giant white dragon fly
+R:250:0x93:0x8B
+
+# Snaga sapper
+R:251:0xA0:0x84
+
+# Blue icky thing
+R:252:0x97:0xC1
+
+# Gibbering mouther
+R:253:0x9B:0xD6
+
+# Wolfhound of Flora
+R:254:0x9B:0xD7
+
+# Hill giant
+R:255:0x94:0x89
+
+# Flesh golem
+R:256:0x97:0x81
+
+# Warg
+R:257:0x92:0xB8
+
+# Cheerful leprechaun
+R:258:0x9B:0xF8
+
+# Giant flea
+R:259:0x93:0x8A
+
+# Ufthak of Cirith Ungol
+R:260:0xA0:0xC4
+
+# Clay golem
+R:261:0x9F:0xD5
+
+# Black ogre
+R:262:0x94:0x84
+
+# Dweller on the threshold
+R:263:0xA0:0x85
+
+# Half-orc
+R:264:0xA0:0xC5
+
+# Dark naga
+R:265:0x9F:0xD6
+
+# Poison ivy
+R:266:0xA5:0xCB
+
+# Magic mushroom patch
+R:267:0x92:0x83
+
+# Plaguebearer of Nurgle
+R:268:0x9A:0x85
+
+# Guardian naga
+R:269:0x98:0x83
+
+# Wererat
+R:270:0xA0:0xC6
+
+# Light hound
+R:271:0x95:0xCB
+
+# Dark hound
+R:272:0x95:0xCC
+
+# Flying skull
+R:273:0x9B:0xF9
+
+# Mi-Go
+R:274:0x9B:0xFA
+
+# Giant tarantula
+R:275:0x94:0xF9
+
+# Giant clear centipede
+R:276:0x96:0x92
+
+# Mirkwood spider
+R:277:0x94:0xFA
+
+# Frost giant
+R:278:0x94:0x8A
+
+# Griffon
+R:279:0x93:0xC3
+
+# Homunculus
+R:280:0x93:0xCC
+
+# Gnome mage
+R:281:0x97:0x90
+
+# Clear hound
+R:282:0x95:0xCD
+
+# Umber hulk
+R:283:0x95:0x91
+
+# Rust monster
+R:284:0xA0:0x87
+
+# Ogrillon
+R:285:0x98:0x90
+
+# Gelatinous cube
+R:286:0x97:0xCD
+
+# Giant green dragon fly
+R:287:0x93:0x8C
+
+# Fire giant
+R:288:0x94:0x8B
+
+# Hummerhorn
+R:289:0xA0:0xC7
+
+# Lizard man
+R:290:0xA0:0x88
+
+# Ulfast, Son of Ulfang
+R:291:0x98:0xFA
+
+# Crebain
+R:292:0xA5:0xCC
+
+# Berserker
+R:293:0x98:0x8F
+
+# Quasit
+R:294:0x93:0xCD
+
+# Sphinx
+R:295:0xA0:0x89
+
+# Imp
+R:296:0x93:0xCE
+
+# Forest troll
+R:297:0x95:0x81
+
+# Freezing sphere
+R:298:0xA0:0xC9
+
+# Jumping fireball
+R:299:0xA0:0x8A
+
+# Ball lightning
+R:300:0xA0:0xCA
+
+# 2-headed hydra
+R:301:0x94:0xCB
+
+# Swamp thing
+R:302:0xA0:0x8B
+
+# Water spirit
+R:303:0x92:0xF8
+
+# Giant red scorpion
+R:304:0x94:0xFB
+
+# Earth spirit
+R:305:0x92:0xF9
+
+# Fire spirit
+R:306:0x92:0xFA
+
+# Fire hound
+R:307:0x95:0xCE
+
+# Cold hound
+R:308:0x95:0xCF
+
+# Energy hound
+R:309:0x95:0xD0
+
+# Lesser Mimic
+R:310:0x92:0x86
+
+# Door mimic
+R:311:0x84:0xBB
+
+# Blink dog
+R:312:0x92:0xB9
+
+# Uruk
+R:313:0x98:0x91
+
+# Shagrat, the Orc Captain
+R:314:0x98:0x92
+
+# Gorbag, the Orc Captain
+R:315:0x98:0x93
+
+# Shambling mound
+R:316:0x92:0x84
+
+# Giant Venus Flytrap
+R:317:0xA5:0xCD
+
+# Chaos beastman
+R:318:0xA0:0x8D
+
+# Daemonette of Slaanesh
+R:319:0xA0:0x8C
+
+# Giant bronze dragon fly
+R:320:0x93:0x90
+
+# Stone giant
+R:321:0x94:0x8C
+
+# Giant black dragon fly
+R:322:0x93:0x8E
+
+# Stone golem
+R:323:0x97:0x83
+
+# Red mold
+R:324:0x97:0xFD
+
+# Giant gold dragon fly
+R:325:0x93:0x8F
+
+# Stunwall
+R:326:0x83:0xCB
+
+# Ghast
+R:327:0xA0:0xCD
+
+# Neekerbreeker
+R:328:0xA5:0xCE
+
+# Huorn
+R:329:0xA0:0xCE
+
+# Bolg, Son of Azog
+R:330:0x98:0x94
+
+# Phase spider
+R:331:0x94:0xFC
+
+# Lizard king
+R:332:0xA0:0x8F
+
+# Landmine
+R:333:0xA0:0xCF
+
+# Wyvern
+R:334:0x9B:0xFB
+
+# Great eagle
+R:335:0xA0:0x90
+
+# Livingstone
+R:336:0x9B:0xFC
+
+# Earth hound
+R:337:0x95:0xD1
+
+# Air hound
+R:338:0x95:0xD2
+
+# Sabre-tooth tiger
+R:339:0x96:0xFE
+
+# Acid hound
+R:340:0x95:0xD3
+
+# Chimaera
+R:341:0x93:0xC4
+
+# Quylthulg
+R:342:0x94:0x92
+
+# Sasquatch
+R:343:0x95:0xCA
+
+# Weir
+R:344:0x9B:0xFD
+
+# Ranger
+R:345:0x98:0xCF
+
+# Paladin
+R:346:0x99:0x8A
+
+# Werewolf
+R:347:0xA0:0xD1
+
+# Dark elven lord
+R:348:0x97:0x94
+
+# Cloud giant
+R:349:0x94:0x8E
+
+# Ugluk, the Uruk
+R:350:0x98:0x95
+
+# Blue dragon bat
+R:351:0x96:0x89
+
+# Mimic
+R:352:0x85:0x95
+
+# Ultimate Mimic
+R:353:0x85:0xD6
+
+# Fire vortex
+R:354:0x99:0xCC
+
+# Acid vortex
+R:355:0x99:0xCD
+
+# Lugdush, the Uruk
+R:356:0xA0:0x92
+
+# Arch-vile
+R:357:0xA0:0xD2
+
+# Cold vortex
+R:358:0x99:0xCE
+
+# Energy vortex
+R:359:0x99:0xCF
+
+# Globefish
+R:360:0xA0:0x93
+
+# Giant firefly
+R:361:0x93:0x8D
+
+# Mummified orc
+R:362:0x94:0x80
+
+# Wolf chieftain
+R:363:0xA5:0xCF
+
+# Serpent man
+R:364:0xA0:0xD4
+
+# Vampiric mist
+R:365:0xA0:0x95
+
+# Killer stag beetle
+R:366:0x93:0xD5
+
+# Iron golem
+R:367:0x97:0x84
+
+# Auto-roller
+R:368:0x9B:0xFE
+
+# Giant yellow scorpion
+R:369:0x94:0xFD
+
+# Jade monk
+R:370:0xA0:0xD5
+
+# Black ooze
+R:371:0x97:0xCE
+
+# Hardened warrior
+R:372:0x98:0xFB
+
+# Azog, King of the Uruk-Hai
+R:373:0x98:0x97
+
+# Fleshhound of Khorne
+R:374:0xA0:0x96
+
+# Dark elven warlock
+R:375:0x9B:0xFF
+
+# Master rogue
+R:376:0x98:0xFC
+
+# Red dragon bat
+R:377:0x96:0x8A
+
+# Killer white beetle
+R:378:0xA0:0xD6
+
+# Ice skeleton
+R:379:0xA0:0x97
+
+# Angamaite of Umbar
+R:380:0xA0:0xF8
+
+# Forest wight
+R:381:0x9C:0x80
+
+# Khim, Son of Mim
+R:382:0x9C:0x81
+
+# Ibun, Son of Mim
+R:383:0x9C:0x82
+
+# Meneldor the Swift
+R:384:0xA0:0xF9
+
+# Phantom beast
+R:385:0x9C:0x83
+
+# Giant silver ant
+R:386:0x93:0xD4
+
+# 4-headed hydra
+R:387:0x94:0xCD
+
+# Lesser hell-beast
+R:388:0xA0:0xFB
+
+# Tyrannosaur
+R:389:0x9C:0x84
+
+# Mummified human
+R:390:0x94:0x81
+
+# Vampire bat
+R:391:0x96:0x8B
+
+# Sangahyando of Umbar
+R:392:0x98:0xFD
+
+# It
+R:393:0x9C:0x85
+
+# Banshee
+R:394:0x93:0x95
+
+# Carrion crawler
+R:395:0x96:0x93
+
+# Xiclotlan
+R:396:0xA0:0xFC
+
+# Silent watcher
+R:397:0x9C:0x86
+
+# Pukelman
+R:398:0x97:0x85
+
+# Disenchanter beast
+R:399:0xA0:0xD7
+
+# Dark elven druid
+R:400:0x97:0x97
+
+# Stone troll
+R:401:0x95:0x82
+
+# Black
+R:402:0x9B:0xC5
+
+# Hill troll
+R:403:0x95:0x83
+
+# Wereworm
+R:404:0x99:0xFC
+
+# Killer red beetle
+R:405:0x93:0xD7
+
+# Disenchanter bat
+R:406:0xA5:0xD0
+
+# Gnoph-Keh
+R:407:0xA0:0xFE
+
+# Giant grey ant
+R:408:0x96:0x84
+
+# Khufu, the Mummified King
+R:409:0x9C:0x87
+
+# Gwaihir the Windlord
+R:410:0xA0:0xF9
+
+# Giant fire tick
+R:411:0xA0:0xFF
+
+# Displacer beast
+R:412:0x96:0xFF
+
+# Ulwarth, Son of Ulfang
+R:413:0x98:0xD1
+
+# Werebear
+R:414:0xA5:0xC7
+
+# Cave ogre
+R:415:0x94:0x85
+
+# White wraith
+R:416:0x95:0x97
+
+# Angel
+R:417:0x92:0x87
+
+# Ghoul
+R:418:0x9D:0xC7
+
+# Mim, Betrayer of Turin
+R:419:0x9C:0x88
+
+# Hellblade
+R:420:0x9C:0x89
+
+# Killer fire beetle
+R:421:0x93:0xF8
+
+# Beast of Nurgle
+R:422:0xA1:0x80
+
+# Creeping adamantite coins
+R:423:0x91:0xFC
+
+# Algroth
+R:424:0x95:0x84
+
+# Flamer of Tzeentch
+R:425:0x9F:0xD7
+
+# Roper
+R:426:0x9F:0xF8
+
+# Headless
+R:427:0x9C:0x8A
+
+# Vibration hound
+R:428:0x95:0xD4
+
+# Nexus hound
+R:429:0x95:0xD5
+
+# Half-ogre
+R:430:0x94:0x86
+
+# Lokkak, the Ogre Chieftain
+R:431:0x94:0x88
+
+# Vampire
+R:432:0x95:0x92
+
+# Gorgimaera
+R:433:0x93:0xC5
+
+# Shantak
+R:434:0x9C:0x8B
+
+# Colbran
+R:435:0x97:0x86
+
+# Spirit naga
+R:436:0x98:0x84
+
+# Corpser
+R:437:0x9F:0xF9
+
+# Fiend of Slaanesh
+R:438:0x94:0xCF
+
+# Stairway to Hell
+R:439:0x9C:0x8C
+
+# 5-headed hydra
+R:440:0x94:0xCE
+
+# Barney the Dinosaur
+R:441:0x9C:0x8D
+
+# Black knight
+R:442:0x99:0x80
+
+# Seahorse
+R:443:0xA1:0x81
+
+# Cyclops
+R:444:0xA1:0x82
+
+# Clairvoyant
+R:445:0x98:0xFE
+
+# Purple worm
+R:446:0x9F:0xFA
+
+# Catoblepas
+R:447:0x99:0xB9
+
+# Lesser wall monster
+R:448:0x9C:0x8E
+
+# Mage
+R:449:0x99:0x82
+
+# Mind flayer
+R:450:0x99:0x83
+
+# The Ultimate Dungeon Cleaner
+R:451:0x9C:0x8F
+
+# Deep one
+R:452:0x95:0xBE
+
+# Basilisk
+R:453:0x94:0xCF
+
+# Ice troll
+R:454:0x95:0x85
+
+# Dhole
+R:455:0x9C:0x91
+
+# Archangel
+R:456:0x92:0x88
+
+# Greater Mimic
+R:457:0x9A:0x96
+
+# Chaos tile
+R:458:0x9C:0x92
+
+# Young blue dragon
+R:459:0x96:0xBC
+
+# Young white dragon
+R:460:0x96:0xBD
+
+# Young green dragon
+R:461:0x96:0xBE
+
+# Young bronze dragon
+R:462:0x96:0xBF
+
+# Aklash
+R:463:0xA4:0x96
+
+# Mithril golem
+R:464:0x97:0x87
+
+# Skeleton troll
+R:465:0x99:0xC5
+
+# Skeletal tyrannosaur
+R:466:0xA1:0x83
+
+# Beorn, the Shape-Changer
+R:467:0xA5:0xD1
+
+# Thorondor, Lord of Eagles
+R:468:0xA0:0xF9
+
+# Giant blue ant
+R:469:0x96:0x83
+
+# Grave wight
+R:470:0x9A:0x94
+
+# Shadow drake
+R:471:0x96:0xC0
+
+# Manticore
+R:472:0x93:0xC6
+
+# Giant army ant
+R:473:0x9A:0xB9
+
+# Killer slicer beetle
+R:474:0x93:0xF9
+
+# Gorgon
+R:475:0xA1:0x85
+
+# Gug
+R:476:0xA1:0x86
+
+# Ghost
+R:477:0x93:0x96
+
+# Death watch beetle
+R:478:0x93:0xFA
+
+# Mountain ogre
+R:479:0x94:0x87
+
+# Nexus quylthulg
+R:480:0x94:0x93
+
+# Shelob, Spider of Darkness
+R:481:0x94:0xFE
+
+# Giant squid
+R:482:0x9F:0xFB
+
+# Ghoulking
+R:483:0x9A:0x84
+
+# Doombat
+R:484:0x9F:0xFC
+
+# Ninja
+R:485:0x99:0x84
+
+# Memory moss
+R:486:0x97:0xFE
+
+# Storm giant
+R:487:0x94:0x8D
+
+# Spectator
+R:488:0x9C:0x93
+
+# Bokrug
+R:489:0xA1:0x87
+
+# Biclops
+R:490:0xA1:0x88
+
+# Half-troll
+R:491:0x98:0x96
+
+# Ivory monk
+R:492:0x98:0xCB
+
+# Bert the Stone Troll
+R:493:0x95:0x88
+
+# Bill the Stone Troll
+R:494:0x95:0x89
+
+# Tom the Stone Troll
+R:495:0x95:0x8A
+
+# Cave troll
+R:496:0x95:0x86
+
+# Anti-paladin
+R:497:0x9C:0x94
+
+# Chaos master
+R:498:0x9C:0x95
+
+# Barrow wight
+R:499:0x95:0xB9
+
+# Skeleton ettin
+R:500:0xA5:0xD2
+
+# Chaos drake
+R:501:0x96:0xC1
+
+# Law drake
+R:502:0x96:0xC2
+
+# Balance drake
+R:503:0x96:0xC3
+
+# Ethereal drake
+R:504:0x96:0xC4
+
+# Groo, the Wanderer
+R:505:0x9C:0x96
+
+# Fasolt the Giant
+R:506:0x9C:0x97
+
+# Shade
+R:507:0x95:0xC1
+
+# Spectre
+R:508:0x93:0xB8
+
+# Water troll
+R:509:0x95:0x8B
+
+# Fire elemental
+R:510:0x92:0xFB
+
+# Cherub
+R:511:0x92:0x89
+
+# Water elemental
+R:512:0x92:0xFC
+
+# Multi-hued hound
+R:513:0x9C:0xB9
+
+# Invisible stalker
+R:514:0x92:0xFD
+
+# Carrion crawler
+R:515:0x96:0x94
+
+# Master thief
+R:516:0x99:0x86
+
+# The Watcher in the Water
+R:517:0x9B:0x8D
+
+# Lich
+R:518:0x93:0xFB
+
+# Gas spore
+R:519:0x9C:0xC6
+
+# Master vampire
+R:520:0x95:0x93
+
+# Oriental vampire
+R:521:0x9C:0xBB
+
+# Greater mummy
+R:522:0x94:0x82
+
+# Bloodletter of Khorne
+R:523:0x93:0xD0
+
+# Giant grey scorpion
+R:524:0x94:0xFF
+
+# Earth elemental
+R:525:0x92:0xFE
+
+# Air elemental
+R:526:0x92:0xFF
+
+# Shimmering mold
+R:527:0x9A:0xF9
+
+# Gargoyle
+R:528:0xA1:0x89
+
+# Malicious leprechaun
+R:529:0x9C:0xBD
+
+# Eog golem
+R:530:0x97:0x88
+
+# Little Boy
+R:531:0x9F:0xFD
+
+# Dagashi
+R:532:0x99:0x88
+
+# Headless ghost
+R:533:0xA1:0x8A
+
+# Dread
+R:534:0x9F:0xFF
+
+# Leng spider
+R:535:0xA1:0x8B
+
+# Gauth
+R:536:0xA5:0xD3
+
+# Smoke elemental
+R:537:0x93:0x88
+
+# Olog
+R:538:0x95:0x8C
+
+# Halfling slinger
+R:539:0x9C:0xBE
+
+# Gravity hound
+R:540:0x95:0xD6
+
+# Acidic cytoplasm
+R:541:0x97:0xCF
+
+# Inertia hound
+R:542:0x95:0xD7
+
+# Impact hound
+R:543:0x95:0xF8
+
+# Shardstorm
+R:544:0xA5:0xD4
+
+# Ooze elemental
+R:545:0x93:0x80
+
+# Young black dragon
+R:546:0x96:0xC5
+
+# Mumak
+R:547:0x99:0xBC
+
+# Giant fire ant
+R:548:0x96:0x82
+
+# Mature white dragon
+R:549:0x96:0xC6
+
+# Xorn
+R:550:0x95:0xC7
+
+# Rogrog the Black Troll
+R:551:0x95:0x87
+
+# Mist giant
+R:552:0x97:0x89
+
+# Phantom
+R:553:0x9C:0xBF
+
+# Grey wraith
+R:554:0x95:0xBA
+
+# Revenant
+R:555:0x95:0xC0
+
+# Young multi-hued dragon
+R:556:0x96:0xC7
+
+# Raal's Tome of Destruction
+R:557:0x9C:0xC0
+
+# Colossus
+R:558:0x9C:0xC1
+
+# Young gold dragon
+R:559:0x96:0xC8
+
+# Mature blue dragon
+R:560:0x96:0xC9
+
+# Mature green dragon
+R:561:0x96:0xCA
+
+# Mature bronze dragon
+R:562:0x96:0xCB
+
+# Young red dragon
+R:563:0x96:0xCC
+
+# Nightblade
+R:564:0x9C:0xC2
+
+# Trapper
+R:565:0x9A:0x97
+
+# Bodak
+R:566:0x93:0xD0
+
+# Time bomb
+R:567:0xA1:0x8E
+
+# Mezzodaemon
+R:568:0x9A:0x88
+
+# Elder thing
+R:569:0x9C:0xC3
+
+# Ice elemental
+R:570:0x93:0x82
+
+# Necromancer
+R:571:0x9C:0xC4
+
+# The Greater hell magic mushroom were-quylthulg
+R:572:0x9F:0xFE
+
+# Lorgan, Chief of the Easterlings
+R:573:0x9C:0xC5
+
+# Chaos spawn
+R:574:0x9C:0xC6
+
+# Mummified troll
+R:575:0xA1:0x8F
+
+# Storm of Unmagic
+R:576:0xA5:0xD5
+
+# Crypt thing
+R:577:0x95:0xB8
+
+# Chaos butterfly
+R:578:0x80:0x80
+
+# Time elemental
+R:579:0x9C:0xC7
+
+# Flying polyp
+R:580:0xA1:0x91
+
+# The Queen Ant
+R:581:0x96:0x86
+
+# Will o' the wisp
+R:582:0x93:0x83
+
+# Shan
+R:583:0xA1:0x92
+
+# Magma elemental
+R:584:0x93:0x84
+
+# Black pudding
+R:585:0x97:0xD0
+
+# Killer iridescent beetle
+R:586:0x9D:0xC8
+
+# Nexus vortex
+R:587:0x9A:0xB8
+
+# Plasma vortex
+R:588:0x99:0xD0
+
+# Mature red dragon
+R:589:0x96:0xCD
+
+# Mature gold dragon
+R:590:0x96:0xCE
+
+# Crystal drake
+R:591:0x96:0xCF
+
+# Mature black dragon
+R:592:0x96:0xD0
+
+# Mature multi-hued dragon
+R:593:0x96:0xD1
+
+# Sky whale
+R:594:0xA1:0x93
+
+# Draebor, the Imp
+R:595:0xA4:0x97
+
+# Mother Hydra
+R:596:0x94:0xD0
+
+# Death knight
+R:597:0x99:0x8C
+
+# Castamir the Usurper
+R:598:0x9C:0xC8
+
+# Time vortex
+R:599:0x99:0xD1
+
+# Shimmering vortex
+R:600:0x99:0xD2
+
+# Ancient blue dragon
+R:601:0x92:0xC0
+
+# Ancient bronze dragon
+R:602:0x92:0xC1
+
+# Beholder
+R:603:0x96:0xD7
+
+# Emperor wight
+R:604:0x95:0xBB
+
+# Seraph
+R:605:0x92:0x8A
+
+# Vargo, Tyrant of Fire
+R:606:0x93:0x85
+
+# Black wraith
+R:607:0x95:0xBC
+
+# Nightgaunt
+R:608:0x9C:0xC9
+
+# Baron of hell
+R:609:0x9C:0xCA
+
+# Scylla
+R:610:0xA1:0x94
+
+# Monastic lich
+R:611:0x93:0xFF
+
+# Nether wraith
+R:612:0x95:0xBD
+
+# Hellhound
+R:613:0x9A:0x8E
+
+# 7-headed hydra
+R:614:0x94:0xD1
+
+# Waldern, King of Water
+R:615:0x93:0x86
+
+# Kavlax the Many-Headed
+R:616:0x96:0xD2
+
+# Ancient white dragon
+R:617:0x92:0xC2
+
+# Ancient green dragon
+R:618:0x92:0xC3
+
+# Chthonian
+R:619:0x9C:0xCB
+
+# Eldrak
+R:620:0x95:0x8F
+
+# Ettin
+R:621:0x95:0x8E
+
+# Night mare
+R:622:0x99:0xBB
+
+# Vampire lord
+R:623:0x95:0x94
+
+# Ancient black dragon
+R:624:0x92:0xC4
+
+# Weird fume
+R:625:0x9A:0xF8
+
+# Spawn of Ubbo-Sathla
+R:626:0xA1:0x95
+
+# Fat Man
+R:627:0x9F:0xFD
+
+# Malekith the Accursed
+R:628:0x97:0x8D
+
+# Shadowfax, steed of Gandalf
+R:629:0xA1:0x96
+
+# Spirit troll
+R:630:0x95:0x90
+
+# War troll
+R:631:0x9C:0xCC
+
+# Disenchanter worm mass
+R:632:0x99:0xFE
+
+# Rotting quylthulg
+R:633:0x94:0x94
+
+# Lesser titan
+R:634:0x94:0x8F
+
+# 9-headed hydra
+R:635:0x94:0xD1
+
+# Enchantress
+R:636:0x99:0x8E
+
+# Ranger chieftain
+R:637:0x99:0x8F
+
+# Sorcerer
+R:638:0x99:0x90
+
+# Xaren
+R:639:0x95:0xC8
+
+# Giant roc
+R:640:0x92:0x8F
+
+# Minotaur
+R:641:0x93:0xC7
+
+# Medusa, the Gorgon
+R:642:0x98:0x85
+
+# Death drake
+R:643:0x92:0xC5
+
+# Ancient red dragon
+R:644:0x92:0xC6
+
+# Ancient gold dragon
+R:645:0x92:0xC7
+
+# Great crystal drake
+R:646:0x92:0xC8
+
+# Wyrd sister
+R:647:0x97:0x95
+
+# Vrock
+R:648:0x9C:0xCD
+
+# Death quasit
+R:649:0x93:0xD1
+
+# Giganto, the Gargantuan
+R:650:0xA1:0x97
+
+# Strygalldwir
+R:651:0x9C:0xCE
+
+# Fallen angel
+R:652:0x98:0xC6
+
+# Giant headless
+R:653:0xA1:0xB8
+
+# Judge Fire
+R:654:0x99:0x8B
+
+# Ubbo-Sathla, the Unbegotten Source
+R:655:0xA1:0xB9
+
+# Judge Mortis
+R:656:0xA1:0xBA
+
+# Dark elven sorcerer
+R:657:0x97:0xB9
+
+# Master lich
+R:658:0x93:0xFC
+
+# Byakhee
+R:659:0x9C:0xCF
+
+# Eol, the Dark Elf
+R:660:0x9C:0xD1
+
+# Archon
+R:661:0x92:0x8B
+
+# Formless spawn of Tsathoggua
+R:662:0x9C:0xD2
+
+# Hunting horror
+R:663:0x9C:0xD3
+
+# Undead beholder
+R:664:0x96:0xF8
+
+# Shadow
+R:665:0x93:0xB9
+
+# Iron lich
+R:666:0x9C:0xD4
+
+# Dread
+R:667:0x9F:0xFF
+
+# Greater basilisk
+R:668:0xA1:0xBB
+
+# Charybdis
+R:669:0xA1:0xBC
+
+# Jack of Shadows
+R:670:0x99:0x94
+
+# Zephyr Lord
+R:671:0x99:0x89
+
+# Juggernaut of Khorne
+R:672:0xA1:0xBD
+
+# Mumak
+R:673:0x99:0xBA
+
+# Judge Fear
+R:674:0x97:0x80
+
+# Ancient multi-hued dragon
+R:675:0x92:0xC9
+
+# Ethereal dragon
+R:676:0x92:0xCA
+
+# Dark young of Shub-Niggurath
+R:677:0x9C:0xD5
+
+# Colour out of space
+R:678:0x8C:0x91
+
+# Quaker, Master of Earth
+R:679:0x93:0x87
+
+# Death leprechaun
+R:680:0x97:0x96
+
+# Chaugnar Faugn, Horror from the Hills
+R:681:0xA1:0xCC
+
+# Lloigor
+R:682:0xA1:0xCD
+
+# Utgard-Loke
+R:683:0xA1:0xCE
+
+# Quachil Uttaus, Treader of the Dust
+R:684:0xA1:0xCF
+
+# Shoggoth
+R:685:0xA1:0xD0
+
+# Judge Death
+R:686:0xA1:0xD1
+
+# Ariel, Queen of Air
+R:687:0x93:0x89
+
+# 11-headed hydra
+R:688:0x94:0xD2
+
+# Patriarch
+R:689:0x99:0x92
+
+# Dreadmaster
+R:690:0x93:0xBD
+
+# Drolem
+R:691:0x97:0x8A
+
+# Scatha the Worm
+R:692:0x9A:0x93
+
+# Warrior of the Dawn
+R:693:0x9C:0xD6
+
+# Lesser black reaver
+R:694:0x95:0xBF
+
+# Zoth-Ommog
+R:695:0xA2:0xC1
+
+# Grand master thief
+R:696:0xA4:0xC2
+
+# Smaug the Golden
+R:697:0x92:0xCB
+
+# The Stormbringer
+R:698:0x9C:0xF8
+
+# Knight Templar
+R:699:0x9C:0xF9
+
+# Leprechaun fanatic
+R:700:0x97:0xB8
+
+# Dracolich
+R:701:0x92:0xCD
+
+# Greater titan
+R:702:0x94:0x90
+
+# Dracolisk
+R:703:0x92:0xCC
+
+# Winged Horror
+R:704:0xA5:0xD6
+
+# Spectral tyrannosaur
+R:705:0x9C:0xFA
+
+# Yibb-Tstll, the Patient One
+R:706:0xA1:0xD3
+
+# Ghatanothoa
+R:707:0xA1:0xD4
+
+# Ent
+R:708:0xA1:0xBE
+
+# Hru
+R:709:0xA1:0xD5
+
+# Itangast the Fire Drake
+R:710:0x92:0xCE
+
+# Death mold
+R:711:0x97:0xFF
+
+# Fafner the Dragon
+R:712:0x9C:0xFB
+
+# Charon, Boatman of the Styx
+R:713:0xA1:0xD6
+
+# Quickbeam, the Ent
+R:714:0xA1:0xD7
+
+# Glaurung, Father of the Dragons
+R:715:0x9A:0x92
+
+# Behemoth
+R:716:0xA1:0xF8
+
+# Garm, Guardian of Hel
+R:717:0x92:0xBC
+
+# Greater wall monster
+R:718:0x9C:0xFC
+
+# Nycadaemon
+R:719:0x9A:0x89
+
+# Barbazu
+R:720:0x9A:0x8D
+
+# Goat of Mendes
+R:721:0x9C:0xFD
+
+# Nightwing
+R:722:0x9A:0x95
+
+# Maulotaur
+R:723:0x9C:0xFE
+
+# Nether hound
+R:724:0x95:0xF9
+
+# Time hound
+R:725:0x95:0xFA
+
+# Plasma hound
+R:726:0x95:0xFB
+
+# Demonic quylthulg
+R:727:0x94:0x95
+
+# Great Storm Wyrm
+R:728:0x92:0xCF
+
+# Ulik the Troll
+R:729:0xA1:0xF9
+
+# Baphomet the Minotaur Lord
+R:730:0x93:0xC8
+
+# Hell knight
+R:731:0xA1:0xFA
+
+# Bull Gates
+R:732:0x9C:0xFF
+
+# Santa Claus
+R:733:0x9D:0x80
+
+# Eihort, the Thing in the Labyrinth
+R:734:0xA2:0xC2
+
+# The King in Yellow
+R:735:0xA2:0xC3
+
+# Great unclean one
+R:736:0xA2:0xC4
+
+# Lord of Chaos
+R:737:0x9D:0x81
+
+# Old Sorcerer
+R:738:0x91:0xC2
+
+# Ethereal hound
+R:739:0x9D:0x82
+
+# Lesser kraken
+R:740:0xA1:0xFB
+
+# Great Ice Wyrm
+R:741:0x92:0xD0
+
+# Demilich
+R:742:0x95:0xC2
+
+# The Phoenix
+R:743:0x92:0x90
+
+# Nightcrawler
+R:744:0x95:0xC4
+
+# Lord of Change
+R:745:0xA1:0xBF
+
+# Keeper of Secrets
+R:746:0xA2:0xC5
+
+# Shudde M'ell
+R:747:0xA2:0xC6
+
+# Hand druj
+R:748:0x99:0xC6
+
+# Eye druj
+R:749:0x99:0xC7
+
+# Skull druj
+R:750:0x99:0xC8
+
+# Chaos vortex
+R:751:0x99:0xD3
+
+# Aether vortex
+R:752:0x99:0xD4
+
+# Nidhogg, the Hel-Drake
+R:753:0xA2:0xC7
+
+# The Lernaean Hydra
+R:754:0x94:0xD3
+
+# Thuringwethil, the Vampire Messenger
+R:755:0x95:0x95
+
+# Great Hell Wyrm
+R:756:0x92:0xD1
+
+# Hastur the Unspeakable
+R:757:0x9D:0x83
+
+# Bloodthirster
+R:758:0xA1:0xFC
+
+# Draconic quylthulg
+R:759:0x94:0x96
+
+# Nyogtha, the Thing that Should not Be
+R:760:0x9D:0x84
+
+# Ahtu, Avatar of Nyarlathotep
+R:761:0xA2:0xC8
+
+# Fundin Bluecloak
+R:762:0xA2:0xC9
+
+# Bile Demon
+R:763:0xA5:0xF8
+
+# Uriel, Angel of Fire
+R:764:0x92:0x8C
+
+# Azriel, Angel of Death
+R:765:0x92:0x8D
+
+# Ancalagon the Black
+R:766:0x92:0xD2
+
+# Daoloth, the Render of the Veils
+R:767:0xA2:0xCA
+
+# Nightwalker
+R:768:0xA1:0xFD
+
+# Gabriel, the Messenger
+R:769:0x92:0x8E
+
+# Artsi, the Champion of Chaos
+R:770:0xA2:0xCB
+
+# Saruman of Many Colours
+R:771:0x99:0x96
+
+# Harowen the Black Hand
+R:772:0xA2:0xCC
+
+# Osyluth
+R:773:0xA5:0xF9
+
+# Dreadlord
+R:774:0x93:0xBE
+
+# Greater kraken
+R:775:0xA1:0xFE
+
+# Archlich
+R:776:0x95:0xC5
+
+# The Cat Lord
+R:777:0x9D:0x87
+
+# Jabberwock
+R:778:0xA5:0xFA
+
+# Chaos hound
+R:779:0x95:0xFD
+
+# Vlad Dracula, Prince of Darkness
+R:780:0xA2:0xCD
+
+# Beholder hive-mother
+R:781:0xA2:0xCE
+
+# Leviathan
+R:782:0xA1:0xFF
+
+# Great Wyrm of Chaos
+R:783:0x92:0xD3
+
+# Great Wyrm of Law
+R:784:0x92:0xD4
+
+# Great Wyrm of Balance
+R:785:0x92:0xD5
+
+# Shambler
+R:786:0x9D:0x89
+
+# Gelugon
+R:787:0xA5:0xFB
+
+# Glaaki
+R:788:0xA0:0x80
+
+# T'ron, the Rebel Dragonrider
+R:789:0x9D:0x8A
+
+# Great Wyrm of Many Colours
+R:790:0x9D:0x8B
+
+# Mardra, rider of the Gold Loranth
+R:791:0x9D:0x8C
+
+# Tselakus, the Dreadlord
+R:792:0x93:0xBF
+
+# Sky Drake
+R:793:0x9D:0x8D
+
+# Eilinel the Entrapped
+R:794:0x93:0xBB
+
+# Horned Reaper
+R:795:0xA5:0xFC
+
+# The Norsa
+R:796:0x9D:0x8F
+
+# Rhan-Tegoth
+R:797:0xA2:0xD1
+
+# Black reaver
+R:798:0x93:0xFD
+
+# Master mindcrafter
+R:799:0x99:0x97
+
+# Greater demonic quylthulg
+R:800:0x94:0x97
+
+# Greater draconic quylthulg
+R:801:0x94:0xB8
+
+# Greater rotting quylthulg
+R:802:0x94:0xB9
+
+# Null, the Living Void
+R:803:0xA1:0xC0
+
+# Feagwath, the Undead Sorcerer
+R:804:0x93:0xFE
+
+# Omarax the Eye Tyrant
+R:805:0x96:0xF9
+
+# Tsathoggua, the Sleeper of N'kai
+R:806:0xA2:0xD2
+
+# Greater Balrog
+R:807:0x9A:0x8B
+
+# Ungoliant, the Unlight
+R:808:0x95:0x80
+
+# Atlach-Nacha, the Spider God
+R:809:0x9D:0x92
+
+# Y'golonac
+R:810:0xA2:0xD3
+
+# Aether hound
+R:811:0x95:0xFE
+
+# Pit Fiend
+R:812:0x9A:0x8A
+
+# The Serpent of Chaos
+R:813:0x9D:0xC5
+
+# Yig, Father of Serpents
+R:814:0xA2:0xD4
+
+# Unmaker
+R:815:0x9D:0x94
+
+# Cyberdemon
+R:816:0x9D:0x95
+
+# Hela, Queen of the Dead
+R:817:0xA2:0xD5
+
+# The Mouth of Sauron
+R:818:0xA2:0xD6
+
+# The Necromancer of Dol Guldur
+R:819:0x9D:0x96
+
+# Lessa, rider of the Gold Ramoth
+R:820:0x9D:0x97
+
+# Master quylthulg
+R:821:0x94:0xBA
+
+# Qlzqqlzuup, the Lord of Flesh
+R:822:0x94:0xBB
+
+# Cthugha, the Living Flame
+R:823:0xA2:0xD7
+
+# F'lar, rider of the Bronze Mnementh
+R:824:0x9D:0xB8
+
+# Maeglin, the Traitor of Gondolin
+R:825:0x95:0xC6
+
+# Cyaegha
+R:826:0xA2:0xF8
+
+# Pazuzu, Lord of Air
+R:827:0xA2:0xF9
+
+# Ithaqua the Windwalker
+R:828:0x9D:0xB9
+
+# Greater Hellhound
+R:829:0x92:0xBB
+
+# Cantoras, the Skeletal Lord
+R:830:0x99:0xC9
+
+# Mephistopheles, Lord of Hell
+R:831:0x9D:0xBA
+
+# Godzilla
+R:832:0x9D:0xBB
+
+# Abhoth, Source of Uncleanness
+R:833:0xA2:0xFA
+
+# Ymir, the Ice Giant
+R:834:0xA2:0xFB
+
+# Loki, the Trickster
+R:835:0xA2:0xFC
+
+# Star-spawn of Cthulhu
+R:836:0x9D:0xBC
+
+# Surtur, the Fire Giant
+R:837:0xA2:0xFD
+
+# The Tarrasque
+R:838:0xA1:0xCB
+
+# Lungorthin, the Balrog of White Fire
+R:839:0xA2:0xFE
+
+# Draugluin, Sire of All Werewolves
+R:840:0xA2:0xFF
+
+# Shuma-Gorath
+R:841:0xA3:0x80
+
+# Tulzscha, the Green Flame
+R:842:0xA1:0xCA
+
+# Oremorj, the Cyberdemon Lord
+R:843:0xA1:0xC9
+
+# Vecna, the Emperor Lich
+R:844:0x9D:0xBD
+
+# Yog-Sothoth, the All-in-One
+R:845:0x9D:0xBE
+
+# Fenris Wolf
+R:846:0xA1:0xC8
+
+# Great Wyrm of Power
+R:847:0x9D:0xBF
+
+# Shub-Niggurath, Black Goat of the Woods
+R:848:0x9D:0xC0
+
+# Nodens, Lord of the Great Abyss
+R:849:0x99:0x85
+
+# Carcharoth, the Jaws of Thirst
+R:850:0x92:0xBE
+
+# Nyarlathotep, the Crawling Chaos
+R:851:0x9D:0xC1
+
+# Azathoth, the Daemon Sultan
+R:852:0x9D:0xC2
+
+# Huan, Wolfhound of the Valar
+R:853:0x92:0xBF
+
+# Jormungand the Midgard Serpent
+R:854:0xA1:0xC7
+
+# The Destroyer
+R:855:0xA1:0xC6
+
+# Gothmog, the High Captain of Balrogs
+R:856:0x9A:0x90
+
+# Great Cthulhu
+R:857:0x9D:0xC3
+
+# Sorka, rider of the Gold Faranth
+R:858:0x9D:0xC4
+
+# The Unicorn of Order
+R:859:0xA1:0xC5
+
+# Sauron, the Sorcerer
+R:860:0x99:0xB8
+
+# DarkGod, the Mighty Coder of Hell
+R:861:0xA3:0xD5
+
+# Morgoth, Lord of Darkness
+R:862:0x9D:0xC6
+
+# Human Warrior
+R:863:0x9D:0xF8
+
+# Elven archer
+R:864:0x9D:0xF9
+
+# Dwarven warrior
+R:865:0x9D:0xFA
+
+# Elite uruk
+R:866:0x9D:0xFB
+
+# The Philosophy Teacher
+R:867:0xA1:0xC4
+
+# The Variant Maintainer
+R:868:0xA1:0xC3
+
+# Random Number Generator
+R:869:0xA1:0xC2
+
+# Rocket mine
+R:870:0xA2:0x80
+
+# Bouncing mine
+R:871:0xA2:0x81
+
+# Durin's Bane
+R:872:0xA3:0x81
+
+# The Icky Queen
+R:873:0xA3:0x82
+
+# Rot jelly
+R:874:0xA2:0x82
+
+# Death
+R:875:0xA2:0x83
+
+# Famine
+R:876:0xA2:0x85
+
+# Pestilence
+R:877:0xA2:0x84
+
+# War
+R:878:0xA2:0x86
+
+# Pike
+R:879:0xA2:0x87
+
+# Electric eel
+R:880:0xA2:0x88
+
+# Giant crayfish
+R:881:0xA2:0x89
+
+# Mermaid
+R:882:0xA2:0x8A
+
+# Box jellyfish
+R:883:0xA0:0xB9
+
+# Giant piranha
+R:884:0x9E:0xD5
+
+# Piranha
+R:885:0x9E:0xD5
+
+# Bullywug
+R:886:0xA2:0x8C
+
+# Bullywug warrior
+R:887:0xA2:0x8D
+
+# Bullywug shaman
+R:888:0xA2:0x8E
+
+# Whale
+R:889:0xA0:0xD0
+
+# Sand mite
+R:890:0xA2:0x90
+
+# Octopus
+R:891:0xA2:0x91
+
+# Giant octopus
+R:892:0xA2:0x92
+
+# Eye of the deep
+R:893:0xA2:0x93
+
+# Murk dweller
+R:894:0xA3:0x83
+
+# Drowned soul
+R:895:0xA3:0x84
+
+# Tiger shark
+R:896:0xA3:0x85
+
+# Hammerhead shark
+R:897:0xA0:0xC8
+
+# Great white shark
+R:898:0xA0:0xFA
+
+# Aquatic golem
+R:899:0xA3:0x86
+
+# Aquatic kobold
+R:900:0xA3:0x87
+
+# White shark
+R:901:0xA0:0xFA
+
+# Scrag
+R:902:0xA3:0x89
+
+# Jaws
+R:903:0xA1:0x84
+
+# Aquatic elf
+R:904:0xA3:0x8B
+
+# Aquatic elven warrior
+R:905:0xA3:0x8C
+
+# Aquatic elven shaman
+R:906:0xA3:0x8D
+
+# Stargazer
+R:907:0xA3:0x8E
+
+# Elder stargazer
+R:908:0xA3:0x8F
+
+# Flounder
+R:909:0xA3:0x90
+
+# Giant turtle
+R:910:0xA3:0x91
+
+# Baby dragon turtle
+R:911:0xA3:0x92
+
+# Young dragon turtle
+R:912:0xA3:0x93
+
+# Mature dragon turtle
+R:913:0xA3:0x94
+
+# Ancient dragon turtle
+R:914:0xA3:0x95
+
+# Fastitocalon
+R:915:0xA3:0x96
+
+# Undead stargazer
+R:916:0xA3:0x97
+
+# Killer whale
+R:917:0xA0:0x94
+
+# Merrow
+R:918:0xA5:0xFD
+
+# Water naga
+R:919:0xA3:0xB9
+
+# Devilfish
+R:920:0xA3:0xBA
+
+# Undead devilfish
+R:921:0xA3:0xBB
+
+# Moby Dick, the White Whale
+R:922:0xA3:0xB8
+
+# Aquatic hound
+R:923:0xA3:0xBD
+
+# Water demon
+R:924:0xA3:0xBE
+
+# Ixitxachitl
+R:925:0x9F:0xD4
+
+# Ixitxachitl priest
+R:926:0xA3:0xC0
+
+# Vampiric ixitxachitl
+R:927:0xA3:0xC1
+
+# Mathilde, the Science Student
+R:928:0xA2:0x94
+
+# Child spirit
+R:929:0xA2:0x95
+
+# Young spirit
+R:930:0xA2:0x96
+
+# Mature spirit
+R:931:0xA2:0x97
+
+# Experienced spirit
+R:932:0xA2:0xB8
+
+# Wise spirit
+R:933:0xA2:0xB9
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0xA3:0xC2
+
+# Gandalf the Grey
+R:935:0xA3:0xC3
+
+# Nar, the Dwarf
+R:936:0xA3:0xC4
+
+# Novice mindcrafter
+R:937:0x98:0xD2
+
+# Great Swamp Wyrm
+R:938:0xA5:0xFE
+
+# Great Bile Wyrm
+R:939:0xA5:0xFF
+
+# Blue Firelizard
+R:940:0xA2:0xBA
+
+# Green Firelizard
+R:941:0xA2:0xBB
+
+# Brown Firelizard
+R:942:0xA2:0xBC
+
+# Bronze Firelizard
+R:943:0xA2:0xBD
+
+# Gold Firelizard
+R:944:0xA2:0xBE
+
+# High-elven ranger
+R:945:0xA2:0xBF
+
+# Uvatha the Horseman
+R:946:0xA3:0xC8
+
+# Adunaphel the Quiet
+R:947:0xA3:0xC9
+
+# Akhorahil the Blind
+R:948:0xA3:0xCA
+
+# Ren the Unclean
+R:949:0xA3:0xCB
+
+# Ji Indur Dawndeath
+R:950:0xA3:0xCC
+
+# Dwar, Dog Lord of Waw
+R:951:0xA3:0xCD
+
+# Hoarmurath of Dir
+R:952:0xA3:0xCE
+
+# Khamul, the Black Easterling
+R:953:0xA3:0xCF
+
+# The Witch-King of Angmar
+R:954:0xA3:0xD0
+
+# Green Dragonrider
+R:955:0x9D:0x8E
+
+# Blue Dragonrider
+R:956:0x9D:0x86
+
+# Brown Dragonrider
+R:957:0x9D:0x90
+
+# Bronze Dragonrider
+R:958:0x9D:0x90
+
+# Gold Dragonrider
+R:959:0x9D:0x8C
+
+# Thread
+R:960:0xA2:0xC0
+
+# Gorlim, Betrayer of Barahir
+R:961:0xA3:0xD1
+
+# The Blubbering idiot, agent of black market, Simon the weak
+R:962:0x98:0xBA
+
+# Aranea
+R:963:0xA4:0x92
+
+# Elder aranea
+R:964:0xA3:0xD2
+
+# Giant brown tick
+R:965:0xA6:0x80
+
+# Dolphiner
+R:966:0xA3:0xD4
+
+# Novice possessor (soul)
+R:967:0xA5:0xBE
+
+# Bat of Gorgoroth
+R:968:0xA6:0x8F
+
+# The Princess
+R:969:0xA6:0x90
+
+# Merton Proudfoot, the lost hobbit
+R:970:0xA6:0x91
+
+# The Wight-King of the Barrow-downs
+R:971:0xA6:0x92
+
+# Adventurer
+R:972:0xA6:0x93
+
+# Experienced possessor (soul)
+R:973:0xA6:0x94
+
+# Old possessor (soul)
+R:974:0xA6:0x95
+
+# Death orb
+R:975:0xA6:0x96
+
+# Bronze dragon worm
+R:976:0xA6:0xB8
+
+# Gold dragon worm
+R:977:0xA6:0x97
+
+# Moldoux, the Defenceless Mold
+R:978:0xA1:0xC1
+
+# The Physics Teacher
+R:979:0xA2:0xCF
+
+# Ar-Pharazon the Golden
+R:980:0xA3:0xD6
+
+# Doppelganger
+R:981:0x8F:0x84
+
+# Marylene, Heartbreakeress of the Netherworld
+R:982:0xA4:0x85
+
+# The Greater Lag Monster
+R:983:0xA4:0xC5
+
+# Hrungnir, the Stone Giant
+R:984:0x97:0x82
+
+# Bullroarer the Hobbit
+R:985:0x97:0x93
+
+# 3-headed hydra
+R:986:0x94:0xCC
+
+# Uldor the Accursed
+R:987:0x99:0x8D
+
+# Mystic
+R:988:0x99:0x93
+
+# Elder vampire
+R:989:0x94:0x91
+
+# Ulfang the Black
+R:990:0x98:0xCE
+
+# Demonologist
+R:991:0x97:0xBA
+
+# Hezrou
+R:992:0x94:0xD4
+
+# Glabrezu
+R:993:0x94:0xC6
+
+# Nalfeshnee
+R:994:0xA4:0xC6
+
+# Marilith
+R:995:0xA4:0xC7
+
+# Lesser Balrog
+R:996:0x9A:0x8D
+
+# Master mystic
+R:997:0x98:0xCC
+
+# Grand master mystic
+R:998:0x99:0x95
+
+# Erinyes
+R:999:0x93:0xBC
+
+# Novice mindcrafter
+R:1000:0x98:0xD2
+
+# Polyphemus, the Blind Cyclops
+R:1001:0xA6:0x81
+
+# Great Wyrm of Perplexity
+R:1002:0xA4:0xCA
+
+# Hound of Tindalos
+R:1003:0xA4:0xCB
+
+# Great Wyrm of Thunder
+R:1004:0xA6:0x82
+
+# Silver mouse
+R:1005:0xA6:0x83
+
+# The Rat King
+R:1006:0xA4:0xCE
+
+# Vort the Kobold Queen
+R:1007:0xA4:0xCF
+
+# Giant black louse
+R:1008:0xA4:0xD0
+
+# Fire Phantom
+R:1009:0xA4:0xD1
+
+# The Insane Player
+R:1010:0x8C:0xB9
+
+# Glaryssa, Succubus Queen
+R:1011:0xA4:0xD2
+
+# Vermicious Knid
+R:1012:0xA4:0xD3
+
+# Bone golem
+R:1013:0xA4:0xD4
+
+# Snake of Yig
+R:1014:0xA4:0xD5
+
+# Bronze golem
+R:1015:0xA6:0x84
+
+# Dimensional shambler
+R:1016:0xA4:0xD7
+
+# Cultist
+R:1017:0x8D:0xD1
+
+# Cult leader
+R:1018:0x90:0x8F
+
+# Servitor of the outer gods
+R:1019:0xA5:0x82
+
+# Avatar of Nyarlathotep
+R:1020:0xA5:0x83
+
+# Thiazi, the Storm Giant
+R:1021:0xA6:0x85
+
+# Hypnos, Lord of Sleep
+R:1022:0xA5:0x85
+
+# Blue dragon worm
+R:1023:0xA5:0x86
+
+# White dragon worm
+R:1024:0xA5:0x87
+
+# Green dragon worm
+R:1025:0xA5:0x8A
+
+# Black dragon worm
+R:1026:0xA5:0x89
+
+# Red dragon worm
+R:1027:0xA5:0x88
+
+# Multi-hued dragon worm
+R:1028:0xA5:0x8B
+
+# The Minotaur of the Labyrinth
+R:1029:0xA5:0x8C
+
+# The Sandworm Queen
+R:1030:0xA5:0x93
+
+# Sandworm
+R:1031:0xA5:0x94
+
+# Tik'srvzllat
+R:1032:0xA5:0x95
+
+# The Glass Golem
+R:1033:0xA6:0x86
+
+# The White Balrog
+R:1034:0xA6:0x87
+
+# Golgarach, the Living Rock
+R:1035:0x83:0xBC
+
+# Atlas, the Titan
+R:1036:0xA6:0x88
+
+# Kronos, Lord of the Titans
+R:1037:0xA6:0x89
+
+# Water hound
+R:1038:0xA6:0xC0
+
+# Improv, the mighty MoLD
+R:1039:0xA6:0xC6
+
+# Emperor Mimic
+R:1040:0xA6:0xD4
+
+# Melinda Proudfoot
+R:1041:0x87:0xE2
+
+# Thrain, the King Under the Mountain
+R:1042:0x87:0xE3
+
+# Fire golem
+R:1043:0x89:0xD8
+
+# Melkor, Lord of Darkness
+R:1044:0x89:0xD9
+
+# Spirit
+R:1045:0x8C:0xD7
+
+# Spirit
+R:1046:0x8C:0xD8
+
+# Spirit
+R:1047:0x8C:0xD9
+
+# Spirit
+R:1048:0x8C:0xDA
+
+# Spirit
+R:1049:0x8C:0xDB
+
+# Spirit
+R:1050:0x8C:0xDC
+
+# Spirit
+R:1051:0x8C:0xDD
+
+# Spirit
+R:1052:0x8C:0xDE
+
+# Spirit
+R:1053:0x8C:0xDF
+
+# Spirit
+R:1054:0x8C:0xE0
+
+# Spirit
+R:1055:0x8C:0xE1
+
+# Spirit
+R:1056:0x8C:0xE2
+
+# Spirit
+R:1057:0x8C:0xDB
+
+# Spirit
+R:1058:0x8C:0xE3
+
+# Spirit
+R:1059:0x8C:0xE4
+
+# Spirit
+R:1060:0x8C:0xE5
+
+# Spirit
+R:1061:0x8C:0xE6
+
+# Spirit
+R:1062:0x8C:0xE7
+
+# Spirit
+R:1063:0x8C:0xE8
+
+# Spirit
+R:1064:0x8C:0xE9
+
+# Spirit
+R:1065:0x8C:0xEA
+
+# Spirit
+R:1066:0x8C:0xEB
+
+# Spirit
+R:1067:0x8C:0xEC
+
+# Spirit
+R:1068:0x8C:0xED
+
+# Spirit
+R:1069:0x8C:0xEE
+
+# Spirit
+R:1070:0x8C:0xEF
+
+# Spirit
+R:1071:0x8C:0xF0
+
+# Spirit
+R:1072:0x8C:0xF1
+
+# Spirit
+R:1073:0x8C:0xF2
+
+# Spirit
+R:1074:0x8C:0xF3
+
+# Spirit
+R:1075:0x8C:0xF4
+
+# Spells (*)
+S:48:0x8C:0x80
+
+# Spells (*)
+S:49:0x8C:0x81
+
+# Spells (*)
+S:50:0x8C:0x82
+
+# Spells (*)
+S:51:0x8C:0x83
+
+# Spells (*)
+S:52:0x8C:0x84
+
+# Spells (*)
+S:53:0x8C:0x85
+
+# Spells (*)
+S:54:0x8C:0x86
+
+# Spells (*)
+S:55:0x8C:0x87
+
+# Spells (*)
+S:56:0x8C:0x88
+
+# Spells (*)
+S:57:0x8C:0x89
+
+# Spells (*)
+S:58:0x8C:0x8A
+
+# Spells (*)
+S:59:0x8C:0x8B
+
+# Spells (*)
+S:60:0x8C:0x8C
+
+# Spells (*)
+S:61:0x8C:0x8D
+
+# Spells (*)
+S:62:0x8C:0x8E
+
+# Spells (*)
+S:63:0x8C:0x8F
+
+# Spells (|)
+S:64:0x8A:0xF8
+
+# Spells (|)
+S:65:0x8A:0xFC
+
+# Spells (|)
+S:66:0x8B:0x80
+
+# Spells (|)
+S:67:0x8B:0x84
+
+# Spells (|)
+S:68:0x8B:0x88
+
+# Spells (|)
+S:69:0x8B:0x8C
+
+# Spells (|)
+S:70:0x8B:0x90
+
+# Spells (|)
+S:71:0x8B:0x94
+
+# Spells (|)
+S:72:0x8B:0xB8
+
+# Spells (|)
+S:73:0x8B:0xBC
+
+# Spells (|)
+S:74:0x8B:0xC0
+
+# Spells (|)
+S:75:0x8B:0xC4
+
+# Spells (|)
+S:76:0x8B:0xC8
+
+# Spells (|)
+S:77:0x8B:0xCC
+
+# Spells (|)
+S:78:0x8B:0xD0
+
+# Spells (|)
+S:79:0x8B:0xD4
+
+# Spells (-)
+S:80:0x8A:0xF9
+
+# Spells (-)
+S:81:0x8A:0xFD
+
+# Spells (-)
+S:82:0x8B:0x81
+
+# Spells (-)
+S:83:0x8B:0x85
+
+# Spells (-)
+S:84:0x8B:0x89
+
+# Spells (-)
+S:85:0x8B:0x8D
+
+# Spells (-)
+S:86:0x8B:0x91
+
+# Spells (-)
+S:87:0x8B:0x95
+
+# Spells (-)
+S:88:0x8B:0xB9
+
+# Spells (-)
+S:89:0x8B:0xBD
+
+# Spells (-)
+S:90:0x8B:0xC1
+
+# Spells (-)
+S:91:0x8B:0xC5
+
+# Spells (-)
+S:92:0x8B:0xC9
+
+# Spells (-)
+S:93:0x8B:0xCD
+
+# Spells (-)
+S:94:0x8B:0xD1
+
+# Spells (-)
+S:95:0x8B:0xD5
+
+# Spells (:)
+S:96:0x8A:0xFA
+
+# Spells (:)
+S:97:0x8A:0xFE
+
+# Spells (:)
+S:98:0x8B:0x82
+
+# Spells (:)
+S:99:0x8B:0x86
+
+# Spells (:)
+S:100:0x8B:0x8A
+
+# Spells (:)
+S:101:0x8B:0x8E
+
+# Spells (:)
+S:102:0x8B:0x92
+
+# Spells (:)
+S:103:0x8B:0x96
+
+# Spells (:)
+S:104:0x8B:0xBA
+
+# Spells (:)
+S:105:0x8B:0xBE
+
+# Spells (:)
+S:106:0x8B:0xC2
+
+# Spells (:)
+S:107:0x8B:0xC6
+
+# Spells (:)
+S:108:0x8B:0xCA
+
+# Spells (:)
+S:109:0x8B:0xCE
+
+# Spells (:)
+S:110:0x8B:0xD2
+
+# Spells (:)
+S:111:0x8B:0xD6
+
+# Spells (\)
+S:112:0x8A:0xFB
+
+# Spells (\)
+S:113:0x8A:0xFF
+
+# Spells (\)
+S:114:0x8B:0x83
+
+# Spells (\)
+S:115:0x8B:0x87
+
+# Spells (\)
+S:116:0x8B:0x8B
+
+# Spells (\)
+S:117:0x8B:0x8F
+
+# Spells (\)
+S:118:0x8B:0x93
+
+# Spells (\)
+S:119:0x8B:0x97
+
+# Spells (\)
+S:120:0x8B:0xBB
+
+# Spells (\)
+S:121:0x8B:0xBF
+
+# Spells (\)
+S:122:0x8B:0xC3
+
+# Spells (\)
+S:123:0x8B:0xC7
+
+# Spells (\)
+S:124:0x8B:0xCB
+
+# Spells (\)
+S:125:0x8B:0xCF
+
+# Spells (\)
+S:126:0x8B:0xD3
+
+# Spells (\)
+S:127:0x8B:0xD7
+
+# Amulets (
+S:128:0x86:0xFF
+
+# Amulets (
+S:129:0x86:0xF8
+
+# Amulets (
+S:130:0x87:0x80
+
+# Amulets (
+S:131:0x86:0xFA
+
+# Amulets (
+S:132:0x86:0xFB
+
+# Amulets (
+S:133:0x86:0xFC
+
+# Amulets (
+S:134:0x86:0xFD
+
+# Amulets (
+S:135:0x86:0xFE
+
+# Amulets (
+S:136:0x86:0xF9
+
+# Amulets (
+S:137:0x86:0xF9
+
+# Amulets (
+S:138:0x87:0x81
+
+# Amulets (
+S:139:0x87:0x82
+
+# Amulets (
+S:140:0x87:0x83
+
+# Amulets (
+S:141:0x87:0x84
+
+# Amulets (
+S:142:0x87:0x85
+
+# Amulets (
+S:143:0x87:0x86
+
+# Rings (=)
+S:144:0x85:0xBF
+
+# Rings (=)
+S:145:0x85:0xB8
+
+# Rings (=)
+S:146:0x85:0xC0
+
+# Rings (=)
+S:147:0x85:0xBA
+
+# Rings (=)
+S:148:0x85:0xBB
+
+# Rings (=)
+S:149:0x85:0xBC
+
+# Rings (=)
+S:150:0x85:0xBD
+
+# Rings (=)
+S:151:0x85:0xBE
+
+# Rings (=)
+S:152:0x85:0xB9
+
+# Rings (=)
+S:153:0x85:0xB9
+
+# Rings (=)
+S:154:0x85:0xC1
+
+# Rings (=)
+S:155:0x85:0xC2
+
+# Rings (=)
+S:156:0x85:0xC3
+
+# Rings (=)
+S:157:0x85:0xC4
+
+# Rings (=)
+S:158:0x85:0xC5
+
+# Rings (=)
+S:159:0x85:0xC6
+
+# Staffs (_)
+S:160:0x87:0x8E
+
+# Staffs (_)
+S:161:0x87:0x8D
+
+# Staffs (_)
+S:162:0x87:0x8D
+
+# Staffs (_)
+S:163:0x87:0x8A
+
+# Staffs (_)
+S:164:0x87:0x8A
+
+# Staffs (_)
+S:165:0x87:0x8B
+
+# Staffs (_)
+S:166:0x87:0x8D
+
+# Staffs (_)
+S:167:0x87:0x88
+
+# Staffs (_)
+S:168:0x87:0x8D
+
+# Staffs (_)
+S:169:0x87:0x8D
+
+# Staffs (_)
+S:170:0x87:0x8A
+
+# Staffs (_)
+S:171:0x87:0x8C
+
+# Staffs (_)
+S:172:0x87:0x8A
+
+# Staffs (_)
+S:173:0x87:0x8B
+
+# Staffs (_)
+S:174:0x87:0x8E
+
+# Staffs (_)
+S:175:0x87:0x88
+
+# Wands (-)
+S:176:0x86:0xCF
+
+# Wands (-)
+S:177:0x86:0xC8
+
+# Wands (-)
+S:178:0x86:0xD0
+
+# Wands (-)
+S:179:0x86:0xCA
+
+# Wands (-)
+S:180:0x86:0xCB
+
+# Wands (-)
+S:181:0x86:0xCC
+
+# Wands (-)
+S:182:0x86:0xCD
+
+# Wands (-)
+S:183:0x86:0xCE
+
+# Wands (-)
+S:184:0x86:0xC9
+
+# Wands (-)
+S:185:0x86:0xC9
+
+# Wands (-)
+S:186:0x86:0xD1
+
+# Wands (-)
+S:187:0x86:0xD2
+
+# Wands (-)
+S:188:0x86:0xD3
+
+# Wands (-)
+S:189:0x86:0xD4
+
+# Wands (-)
+S:190:0x86:0xD5
+
+# Wands (-)
+S:191:0x86:0xD6
+
+# Rods (-)
+S:192:0x86:0xBF
+
+# Rods (-)
+S:193:0x86:0xB8
+
+# Rods (-)
+S:194:0x86:0xC0
+
+# Rods (-)
+S:195:0x86:0xBA
+
+# Rods (-)
+S:196:0x86:0xBB
+
+# Rods (-)
+S:197:0x86:0xBC
+
+# Rods (-)
+S:198:0x86:0xBD
+
+# Rods (-)
+S:199:0x86:0xBE
+
+# Rods (-)
+S:200:0x86:0xB9
+
+# Rods (-)
+S:201:0x86:0xB9
+
+# Rods (-)
+S:202:0x86:0xC1
+
+# Rods (-)
+S:203:0x86:0xC2
+
+# Rods (-)
+S:204:0x86:0xC3
+
+# Rods (-)
+S:205:0x86:0xC4
+
+# Rods (-)
+S:206:0x86:0xC5
+
+# Rods (-)
+S:207:0x86:0xC6
+
+# Scrolls (?)
+S:208:0x85:0x94
+
+# Scrolls (?)
+S:209:0x85:0x95
+
+# Scrolls (?)
+S:210:0x85:0x96
+
+# Scrolls (?)
+S:211:0x85:0x97
+
+# Scrolls (?)
+S:212:0x85:0x94
+
+# Scrolls (?)
+S:213:0x85:0x95
+
+# Scrolls (?)
+S:214:0x85:0x96
+
+# Scrolls (?)
+S:215:0x85:0x97
+
+# Scrolls (?)
+S:216:0x85:0x94
+
+# Scrolls (?)
+S:217:0x85:0x95
+
+# Scrolls (?)
+S:218:0x85:0x96
+
+# Scrolls (?)
+S:219:0x85:0x97
+
+# Scrolls (?)
+S:220:0x85:0x94
+
+# Scrolls (?)
+S:221:0x85:0x95
+
+# Scrolls (?)
+S:222:0x85:0x96
+
+# Scrolls (?)
+S:223:0x85:0x97
+
+# Potions (!)
+S:224:0x85:0xFF
+
+# Potions (!)
+S:225:0x85:0xF8
+
+# Potions (!)
+S:226:0x86:0x80
+
+# Potions (!)
+S:227:0x85:0xFA
+
+# Potions (!)
+S:228:0x85:0xFB
+
+# Potions (!)
+S:229:0x85:0xFC
+
+# Potions (!)
+S:230:0x85:0xFD
+
+# Potions (!)
+S:231:0x85:0xFE
+
+# Potions (!)
+S:232:0x85:0xF9
+
+# Potions (!)
+S:233:0x85:0xF9
+
+# Potions (!)
+S:234:0x86:0x81
+
+# Potions (!)
+S:235:0x86:0x82
+
+# Potions (!)
+S:236:0x86:0x83
+
+# Potions (!)
+S:237:0x86:0x84
+
+# Potions (!)
+S:238:0x86:0x85
+
+# Potions (!)
+S:239:0x86:0x86
+
+# Food (,)
+S:240:0x86:0x8F
+
+# Food (,)
+S:241:0x86:0x88
+
+# Food (,)
+S:242:0x86:0x90
+
+# Food (,)
+S:243:0x86:0x8A
+
+# Food (,)
+S:244:0x86:0x8B
+
+# Food (,)
+S:245:0x86:0x8C
+
+# Food (,)
+S:246:0x86:0x8D
+
+# Food (,)
+S:247:0x86:0x8E
+
+# Food (,)
+S:248:0x86:0x89
+
+# Food (,)
+S:249:0x86:0x89
+
+# Food (,)
+S:250:0x86:0x91
+
+# Food (,)
+S:251:0x86:0x92
+
+# Food (,)
+S:252:0x86:0x93
+
+# Food (,)
+S:253:0x86:0x94
+
+# Food (,)
+S:254:0x86:0x95
+
+# Food (,)
+S:255:0x86:0x96
+
diff --git a/lib/pref/graf-mac.prf b/lib/pref/graf-mac.prf
new file mode 100644
index 00000000..7bb84141
--- /dev/null
+++ b/lib/pref/graf-mac.prf
@@ -0,0 +1,15 @@
+# File: graf-mac.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
diff --git a/lib/pref/graf-new.prf b/lib/pref/graf-new.prf
new file mode 100644
index 00000000..ca806ca7
--- /dev/null
+++ b/lib/pref/graf-new.prf
@@ -0,0 +1,6847 @@
+# PRF file generated by Andreas Koch`s Tile Assigner
+# 23/06/2004 Edited manually
+
+# 2460 items
+# 2312 probably mapped correctly
+# 147 imported but not yet defined
+# 1 defined to value(s) lower than 0x80
+# Old header :
+# File: graf-new.prf
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+# with Adam Bolt's 16x16 tiles.
+#
+# By Robert Ruehlmann < rr9@angband.org >
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+# General Store
+B:0:0x82/0x87
+
+# Armoury
+B:1:0x82/0x88
+
+# Weaponsmith
+B:2:0x82/0x89
+
+# Temple
+B:3:0x82/0x8A
+
+# Alchemy shop
+B:4:0x82/0x8B
+
+# Magic shop
+B:5:0x82/0x8C
+
+# Black Market
+B:6:0x82/0x8D
+
+# Home
+B:7:0x82/0x8E
+
+# Book Store
+B:8:0x82/0x8F
+
+# Pet Shop
+B:9:0x82/0x90
+
+# Mayor's Office
+B:10:0x86/0xA0
+
+# Inn
+B:11:0x86/0xA1
+
+# The Soothsayer
+B:12:0x86/0xA2
+
+# Library
+B:13:0x86/0xA3
+
+# Castle
+B:14:0x86/0xA4
+
+# Casino
+B:15:0x86/0xA5
+
+# Beastmaster Shanty
+B:16:0x86/0xA6
+
+# Fighters Hall
+B:17:0x86/0xA7
+
+# Tower of Magery
+B:18:0x86/0xA8
+
+# Inner Temple
+B:19:0x86/0xA9
+
+# Paladins Guild
+B:20:0x86/0xAA
+
+# Rangers Guild
+B:21:0x86/0xAB
+
+# Thunderlords' Hide
+B:22:0x86/0xAC
+
+# The Mirror
+B:23:0x86/0xAD
+
+# Seat of Ruling
+B:24:0x86/0xAE
+
+# Wizards Spire
+B:25:0x86/0xAF
+
+# Priests Circle
+B:26:0x86/0xB0
+
+# Tower of the King
+B:27:0x86/0xB1
+
+# Library
+B:28:0x86/0xA3
+
+# The White Tree
+B:29:0x86/0xB2
+
+# Craftsmaster
+B:30:0x86/0xB3
+
+# Earth-Dome (Nature)
+B:31:0x86/0xB4
+
+# Minstrels Haven
+B:32:0x86/0xB5
+
+# Star-Dome
+B:33:0x86/0xB6
+
+# Valarin Temple
+B:34:0x86/0xB7
+
+# Sea-Dome
+B:35:0x86/0xB8
+
+# The Golden Flower
+B:36:0x86/0xB9
+
+# The Fountain
+B:37:0x86/0xBA
+
+# Axe Smith
+B:38:0x86/0xBB
+
+# Hafted Smith
+B:39:0x86/0xBC
+
+# Polearm Smith
+B:40:0x86/0xBD
+
+# Sword Smith
+B:41:0x86/0xBE
+
+# Rare Jewelry Shop
+B:42:0x86/0xBF
+
+# Jewelry Shop
+B:43:0x87/0xA0
+
+# Footwear Shop
+B:44:0x87/0xA1
+
+# Rare Footwear Shop
+B:45:0x87/0xA2
+
+# Library
+B:46:0x86/0xA3
+
+# Forbidden Library
+B:47:0x87/0xA3
+
+# Expensive Black Market
+B:48:0x87/0xA4
+
+# Common Shop
+B:49:0x87/0xA5
+
+# Dragon Hunter
+B:50:0x87/0xA6
+
+# Speed Ring Market
+B:51:0x87/0xA7
+
+# Scribe
+B:52:0x87/0xA8
+
+# Potion Store
+B:53:0x87/0xA9
+
+# Recaller
+B:54:0x87/0xAA
+
+# Master Archer
+B:55:0x87/0xAB
+
+# Merchants Guild
+B:56:0x87/0xAC
+
+# The Mathom-house
+B:57:0x87/0xAD
+
+# The Prancing Pony
+B:58:0x86/0xA1
+
+# nothing
+F:0:0x80/0x80
+
+# open floor
+F:1:0x80/0x81
+
+# fountain
+F:2:0xC3/0x9A
+
+# glyph of warding
+F:3:0x8D/0x95
+
+# open door
+F:4:0x82/0x84
+
+# broken door
+F:5:0x82/0x85
+
+# up staircase
+F:6:0x80/0x96
+
+# down staircase
+F:7:0x80/0x99
+
+# quest entrance
+F:8:0x80/0x9A
+
+# quest exit
+F:9:0x80/0x97
+
+# quest down level
+F:10:0x80/0x9B
+
+# quest up level
+F:11:0x80/0x98
+
+# town exit
+F:12:0x82/0x84
+
+# shaft down
+F:13:0xC3/0x84
+
+# shaft up
+F:14:0xC3/0x85
+
+# fountain
+F:15:0xC3/0x99
+
+# web
+F:16:0x81/0x8C
+
+# trap
+F:17:0x81/0x89
+
+# visible trap -- spiked pit
+F:18:0x81/0x89
+
+# visible trap -- poison pit
+F:19:0x81/0x89
+
+# visible trap -- rune -- summon
+F:20:0x81/0x8F
+
+# visible trap -- rune -- teleport
+F:21:0x81/0x92
+
+# visible trap -- spot -- fire
+F:22:0x81/0x86
+
+# visible trap -- spot -- acid
+F:23:0x81/0x86
+
+# visible trap -- dart -- slow
+F:24:0x81/0x80
+
+# visible trap -- dart -- lose str
+F:25:0x81/0x80
+
+# visible trap -- dart -- lose dex
+F:26:0x81/0x80
+
+# visible trap -- dart -- lose con
+F:27:0x81/0x80
+
+# visible trap -- gas -- blind
+F:28:0x81/0x83
+
+# visible trap -- gas -- confuse
+F:29:0x81/0x83
+
+# visible trap -- gas -- poison
+F:30:0x81/0x83
+
+# visible trap -- gas -- sleep
+F:31:0x81/0x83
+
+# door
+F:32:0x82/0x83
+
+# locked door
+F:33:0x82/0x83
+F:34:0x82/0x83
+F:35:0x82/0x83
+F:36:0x82/0x83
+F:37:0x82/0x83
+F:38:0x82/0x86
+F:39:0x82/0x86
+
+# jammed door
+F:40:0x82/0x83
+F:41:0x82/0x83
+F:42:0x82/0x83
+F:43:0x82/0x83
+F:44:0x82/0x83
+F:45:0x82/0x86
+F:46:0x82/0x86
+F:47:0x82/0x86
+
+# secret door
+F:48:0x80/0x84
+
+# pile of rubble
+F:49:0x80/0x9C
+
+# magma vein
+F:50:0x80/0x8D
+
+# quartz vein
+F:51:0x80/0x87
+
+# magma vein
+F:52:0x80/0x90
+
+# quartz vein
+F:53:0x80/0x87
+
+# magma vein with treasure
+F:54:0x80/0x90
+
+# quartz vein with treasure
+F:55:0x80/0x8A
+
+# granite wall
+F:56:0x80/0x84
+F:57:0x80/0x84
+F:58:0x80/0x84
+F:59:0x80/0x84
+
+# permanent wall
+F:60:0x80/0x93
+F:61:0x80/0x93
+F:62:0x80/0x93
+F:63:0x80/0x93
+
+# explosive rune
+F:64:0x8D/0x9E
+
+# Straight Road startpoint
+F:65:0x81/0x95
+
+# section of the Straight Road
+F:66:0x81/0x95
+F:67:0x81/0x95
+F:68:0x81/0x95
+F:69:0x81/0x95
+F:70:0x81/0x95
+
+# section of the Straight Road (discharged)
+F:71:0x81/0x98
+
+# Straight Road exit
+F:72:0x81/0x9B
+
+# corrupted section of the Straight Road
+F:73:0x81/0x9E
+
+# Building
+F:74:0x82/0x93
+
+# permanent wall
+F:75:0x82/0x93
+F:76:0x82/0x94
+F:77:0x82/0x95
+F:78:0x82/0x96
+
+# stream of shallow water
+F:84:0xB4/0x97
+
+# pool of deep lava
+F:85:0x83/0x8D
+
+# stream of shallow lava
+F:86:0xB4/0x9A
+
+# dark pit
+F:87:0x80/0x80
+
+# dirt
+F:88:0xB4/0x91
+
+# patch of grass
+F:89:0xB4/0x94
+
+# ice
+F:90:0xC3/0x83
+
+# sand
+F:91:0xC3/0x88
+
+# dead tree
+F:92:0xC3/0x98
+
+# ash
+F:93:0xC3/0x97
+
+# mud
+F:94:0xC3/0x96
+
+# ice wall
+F:95:0xC5/0x92
+
+# tree
+F:96:0x82/0x9A
+
+# mountain chain
+F:97:0x8D/0x98
+
+# sandwall
+F:98:0xC3/0x86
+F:99:0xC3/0x86
+
+# sandwall with treasure
+F:100:0xC3/0x87
+
+# high mountain chain
+F:101:0xC3/0x9E
+
+# nether mist
+F:102:0xC3/0x9F
+
+# molten glass wall
+F:103:0xC0/0x9F
+
+# Void Jumpgate
+F:160:0x91/0x84
+
+# Altar of Being
+F:161:0xC1/0x8E
+
+# Altar of Winds
+F:162:0xB5/0x8A
+
+# Altar of Force
+F:163:0xB5/0x86
+
+# Altar of Darkness
+F:164:0xB5/0x86
+
+# Altar of Nature
+F:165:0xB5/0x91
+
+# Altar of Sun
+F:166:0xB5/0x8F
+
+# Altar of Rage
+F:167:0xB5/0x8C
+
+# Altar of Winds
+F:168:0xB5/0x92
+
+# Altar of Stars
+F:169:0xC1/0x8F
+
+# Altar of Being
+F:170:0xB5/0x8D
+
+# Altar of Randomness
+F:171:0xB5/0x88
+
+# floor
+F:172:0x80/0x81
+
+# Underground Tunnel
+F:173:0x80/0x82
+
+# stream of tainted water
+F:174:0xAF/0x8E
+
+# monster trap
+F:175:0x81/0x9C
+
+# Void Jumpgate
+F:176:0xAF/0x8C
+
+# lava wall
+F:177:0xC6/0x8C
+
+# Great Fire
+F:178:0xC6/0x8A
+
+# path to the next area
+F:179:0x88/0xA1
+
+# path to the previous area
+F:180:0x88/0xA0
+
+# field
+F:181:0x88/0xA2
+
+# Ekkaia, the Encircling Sea
+F:182:0x88/0xA3
+
+# Altar of Energy
+F:183:0xB5/0x9A
+
+# Altar of Matter
+F:184:0xB5/0x9B
+
+# Altar of Being
+F:185:0xB5/0x9C
+
+# Altar of Unbeing
+F:186:0xB5/0x9D
+
+# pool of deep water
+F:187:0x83/0x80
+
+# glass wall
+F:188:0xC0/0x9F
+
+# illusion wall
+F:189:0x80/0x84
+
+# Grass roof
+F:190:0xC2/0x80
+
+# grass roof top
+F:191:0xC2/0x81
+
+# grass roof chimney
+F:192:0xC2/0x82
+
+# brick roof
+F:193:0xC3/0x80
+
+# brick roof top
+F:194:0xC3/0x81
+
+# brick roof chimney
+F:195:0xC3/0x82
+
+# window
+F:196:0xC2/0x83
+
+# small window
+F:197:0xC2/0x84
+
+# rain barrel
+F:198:0xC2/0x85
+
+# grass with flowers
+F:199:0xC2/0x86
+
+# cobblestone road
+F:200:0xC2/0x87
+
+# cobblestone with outlet
+F:201:0xC2/0x88
+
+# small tree
+F:202:0x82/0x9D
+
+# town
+F:203:0xC3/0x95
+
+# Underground Tunnel
+F:204:0x80/0x82
+
+# a blazing fire
+F:205:0xC6/0x8A
+
+# pile of rubble
+F:206:0xC6/0x8B
+
+# ethereal wall
+F:214:0x80/0x81
+
+# glacial wall
+F:215:0xC5/0x92
+
+# Skeleton
+G:M:1:0xC6/0x91
+
+# Zombie
+G:M:2:0xC6/0x92
+
+# Lich
+G:M:3:0xC6/0x93
+
+# Spectral
+G:M:4:0xC6/0x94
+
+# Captain
+G:M:5:0xC6/0x95
+
+# Chieftain
+G:M:6:0xC6/0x96
+
+# Shaman
+G:M:7:0xC6/0x97
+
+# Priest
+G:M:8:0xC6/0x98
+
+# Mage
+G:M:9:0xC6/0x99
+
+# Archer
+G:M:10:0xC6/0x9A
+
+# Rogue
+G:M:11:0xC6/0x9B
+
+# Vampire
+G:P:1:0x88/0xA4
+
+# Spectre
+G:P:2:0x88/0xA5
+
+# Skeleton
+G:P:3:0xC6/0x91
+
+# Zombie
+G:P:4:0xC6/0x92
+
+# Barbarian
+G:P:5:0x88/0xA6
+
+# Hermit
+G:P:6:0x88/0xA7
+
+# Corrupted
+G:P:7:0x88/0xA8
+
+# LostSoul
+G:P:8:0x88/0xA9
+
+# something
+K:0:0x01/0x20
+
+# Blindness
+K:1:0x85/0x94
+
+# Paranoia
+K:2:0x85/0x94
+
+# Confusion
+K:3:0x85/0x94
+
+# Hallucination
+K:4:0x85/0x94
+
+# Cure Poison
+K:5:0x85/0x94
+
+# Cure Blindness
+K:6:0x85/0x94
+
+# Cure Paranoia
+K:7:0xC6/0x83
+
+# Cure Confusion
+K:8:0x85/0x94
+
+# Weakness
+K:9:0x85/0x94
+
+# Unhealth
+K:10:0x85/0x94
+
+# Restore Constitution
+K:11:0x85/0x94
+
+# Restoring
+K:12:0x85/0x94
+
+# Stupidity
+K:13:0x85/0x94
+
+# Naivety
+K:14:0x85/0x94
+
+# Poison
+K:15:0x85/0x94
+
+# Sickness
+K:16:0x85/0x94
+
+# Paralysis
+K:17:0x85/0x94
+
+# Restore Strength
+K:18:0x85/0x94
+
+# Disease
+K:19:0x85/0x94
+
+# Cure Serious Wounds
+K:20:0x85/0x94
+
+# & Ration~ of Food
+K:21:0x8E/0x84
+
+# & Hard Biscuit~
+K:22:0x8E/0x82
+
+# & Strip~ of Venison
+K:23:0x8E/0x83
+
+# & Slime Mold~
+K:24:0x8E/0x85
+
+# & Lembas~
+K:25:0x8E/0x86
+
+# & Pint~ of Fine Ale
+K:26:0x8E/0x80
+
+# & Pint~ of Fine Wine
+K:27:0x8E/0x80
+
+# & Mattock~
+K:28:0xB6/0x8C
+
+# & Blue Stone~
+K:29:0xC5/0x93
+
+# & Broken Dagger~
+K:30:0x8A/0x8D
+
+# & Bastard Sword~
+K:31:0x8A/0x8E
+
+# & Scimitar~
+K:32:0x8A/0x97
+
+# & Tulwar~
+K:33:0x8A/0x95
+
+# & Broad Sword~
+K:34:0x8A/0x98
+
+# & Short Sword~
+K:35:0x8A/0x94
+
+# & Blade~ of Chaos
+K:36:0x8A/0x9E
+
+# & Two-Handed Sword~
+K:37:0x8A/0x9C
+
+# & Main Gauche~
+K:38:0x8A/0x90
+
+# & Cutlass~
+K:39:0x8A/0x96
+
+# & Executioner's Sword~
+K:40:0x8A/0x9D
+
+# & Katana~
+K:41:0x8A/0x9B
+
+# & Long Sword~
+K:42:0x8A/0x99
+
+# & Dagger~
+K:43:0x8A/0x8F
+
+# & Rapier~
+K:44:0x8A/0x91
+
+# & Sabre~
+K:45:0x8A/0x93
+
+# & Small Sword~
+K:46:0x8A/0x92
+
+# & Broken Sword~
+K:47:0x8A/0x8E
+
+# & Ball-and-Chain~
+K:48:0x8B/0x86
+
+# & Whip~
+K:49:0x8A/0x9F
+
+# & Flail~
+K:50:0x8B/0x83
+
+# & Two-Handed Flail~
+K:51:0x8B/0x87
+
+# & Morning Star~
+K:52:0x8B/0x84
+
+# & Mace~
+K:53:0x8B/0x81
+
+# & Quarterstaff~
+K:54:0x8B/0x82
+
+# & War Hammer~
+K:55:0x8B/0x80
+
+# & Lead-Filled Mace~
+K:56:0x8B/0x85
+
+# & Mace~ of Disruption
+K:57:0x8B/0x88
+
+# & Lucerne Hammer~
+K:58:0x8B/0x8D
+
+# & Beaked Axe~
+K:59:0x8B/0x90
+
+# & Glaive~
+K:60:0x8B/0x92
+
+# & Halberd~
+K:61:0x8B/0x93
+
+# & Awl-Pike~
+K:62:0x8B/0x8B
+
+# & Pike~
+K:63:0x8B/0x8F
+
+# & Spear~
+K:64:0x8B/0x89
+
+# & Trident~
+K:65:0x8B/0x8A
+
+# & Lance~
+K:66:0x8B/0x8C
+
+# & Great Axe~
+K:67:0x8B/0x95
+
+# & Battle Axe~
+K:68:0x8B/0x8E
+
+# & Lochaber Axe~
+K:69:0x8B/0x94
+
+# & Broad Axe~
+K:70:0x8B/0x91
+
+# & Scythe~
+K:71:0x8B/0x96
+
+# & Scythe~ of Slicing
+K:72:0x8B/0x97
+
+# & Short Bow~
+K:73:0x8B/0x98
+
+# & Long Bow~
+K:74:0x8B/0x99
+
+# & Light Crossbow~
+K:75:0x8B/0x9A
+
+# & Heavy Crossbow~
+K:76:0x8B/0x9B
+
+# & Sling~
+K:77:0x8B/0x9C
+
+# & Arrow~
+K:78:0x8C/0x80
+
+# & Seeker Arrow~
+K:79:0x8C/0x81
+
+# & Bolt~
+K:80:0x8C/0x82
+
+# & Seeker Bolt~
+K:81:0x8C/0x83
+
+# & Rounded Pebble~
+K:82:0x8C/0x84
+
+# & Iron Shot~
+K:83:0x8C/0x85
+
+# & Shovel~
+K:84:0x8E/0x8F
+
+# & Gnomish Shovel~
+K:85:0x8E/0x90
+
+# & Dwarven Shovel~
+K:86:0x8E/0x91
+
+# & Pick~
+K:87:0x8E/0x8C
+
+# & Orcish Pick~
+K:88:0x8E/0x8D
+
+# & Dwarven Pick~
+K:89:0x8E/0x91
+
+# & Elven Cloak~
+K:90:0x89/0x89
+
+# & Pair~ of Soft Leather Boots
+K:91:0x88/0x8E
+
+# & Pair~ of Hard Leather Boots
+K:92:0x88/0x8F
+
+# & Pair~ of Metal Shod Boots
+K:93:0x88/0x90
+
+# & Hard Leather Cap~
+K:94:0x87/0x98
+
+# & Metal Cap~
+K:95:0x87/0x99
+
+# & Iron Helm~
+K:96:0x87/0x9A
+
+# & Steel Helm~
+K:97:0x87/0x9B
+
+# & Iron Crown~
+K:98:0x87/0x9C
+
+# & Golden Crown~
+K:99:0x87/0x9D
+
+# & Jewel Encrusted Crown~
+K:100:0x87/0x9E
+
+# & Robe~
+K:101:0x89/0x8C
+
+# & Filthy Rag~
+K:102:0x89/0x8B
+
+# Soft Leather Armour~
+K:103:0x89/0x8D
+
+# Soft Studded Leather~
+K:104:0x89/0x8E
+
+# Hard Leather Armour~
+K:105:0x89/0x8F
+
+# Hard Studded Leather~
+K:106:0x89/0x90
+
+# Leather Scale Mail~
+K:107:0x89/0x91
+
+# Metal Scale Mail~
+K:108:0x89/0x92
+
+# Chain Mail~
+K:109:0x89/0x94
+
+# Rusty Chain Mail~
+K:110:0x89/0x93
+
+# Augmented Chain Mail~
+K:111:0x89/0x96
+
+# Bar Chain Mail~
+K:112:0x89/0x97
+
+# Metal Brigandine Armour~
+K:113:0x89/0x98
+
+# Partial Plate Armour~
+K:114:0x89/0x99
+
+# Metal Lamellar Armour~
+K:115:0x89/0x9A
+
+# Full Plate Armour~
+K:116:0x89/0x9B
+
+# Ribbed Plate Armour~
+K:117:0x89/0x9C
+
+# Adamantite Plate Mail~
+K:118:0x89/0x9F
+
+# Mithril Plate Mail~
+K:119:0x89/0x9E
+
+# Mithril Chain Mail~
+K:120:0x89/0x9D
+
+# Double Chain Mail~
+K:121:0x89/0x95
+
+# & Shield~ of Deflection
+K:122:0x88/0x98
+
+# & Cloak~
+K:123:0x89/0x88
+
+# & Shadow Cloak~
+K:124:0x89/0x89
+
+# & Set~ of Leather Gloves
+K:125:0x88/0x91
+
+# & Set~ of Gauntlets
+K:126:0x88/0x92
+
+# & Set~ of Cesti
+K:127:0x88/0x93
+
+# & Small Leather Shield~
+K:128:0x88/0x94
+
+# & Large Leather Shield~
+K:129:0x88/0x95
+
+# & Small Metal Shield~
+K:130:0x88/0x96
+
+# & Large Metal Shield~
+K:131:0x88/0x97
+
+# Strength
+K:132:0x84/0x81
+
+# Dexterity
+K:133:0x84/0x83
+
+# Constitution
+K:134:0x84/0x83
+
+# Intelligence
+K:135:0x84/0x83
+
+# Speed
+K:136:0x84/0x83
+
+# Searching
+K:137:0x84/0x83
+
+# Teleportation
+K:138:0x84/0x83
+
+# Slow Digestion
+K:139:0x84/0x83
+
+# Fire Resistance
+K:140:0x84/0x83
+
+# Cold Resistance
+K:141:0x84/0x83
+
+# Levitation
+K:142:0x84/0x83
+
+# Poison Resistance
+K:143:0x84/0x83
+
+# Free Action
+K:144:0x84/0x83
+
+# Weakness
+K:145:0x84/0x83
+
+# Flames
+K:146:0x84/0x83
+
+# Acid
+K:147:0x84/0x83
+
+# Ice
+K:148:0x84/0x83
+
+# Woe
+K:149:0x84/0x83
+
+# Stupidity
+K:150:0x84/0x83
+
+# Damage
+K:151:0x84/0x83
+
+# Accuracy
+K:152:0x84/0x83
+
+# Protection
+K:153:0x84/0x83
+
+# Aggravate Monster
+K:154:0x84/0x83
+
+# See Invisible
+K:155:0x84/0x83
+
+# Sustain Strength
+K:156:0x84/0x83
+
+# Sustain Intelligence
+K:157:0x84/0x83
+
+# Sustain Wisdom
+K:158:0x84/0x83
+
+# Sustain Constitution
+K:159:0x84/0x83
+
+# Sustain Dexterity
+K:160:0x84/0x83
+
+# Sustain Charisma
+K:161:0x84/0x83
+
+# Slaying
+K:162:0x84/0x83
+
+# Brilliance
+K:163:0x87/0x83
+
+# Charisma
+K:164:0x87/0x83
+
+# Searching
+K:165:0x87/0x83
+
+# Teleportation
+K:166:0x87/0x83
+
+# Slow Digestion
+K:167:0x87/0x83
+
+# Acid Resistance
+K:168:0x87/0x83
+
+# Adornment
+K:169:0x87/0x83
+
+# Double Ring Mail~
+K:170:0x89/0x9B
+
+# the Magi
+K:171:0x87/0x83
+
+# Doom
+K:172:0x87/0x83
+
+# Enchant Weapon To-Hit
+K:173:0x83/0x9C
+
+# Enchant Weapon To-Dam
+K:174:0x83/0x9C
+
+# Enchant Armor
+K:175:0x83/0x9C
+
+# Identify
+K:176:0x83/0x9C
+
+# *Identify*
+K:177:0x83/0x9C
+
+# Rumour
+K:178:0x83/0x9C
+
+# Chaos
+K:179:0x83/0x9C
+
+# Remove Curse
+K:180:0x83/0x9C
+
+# Light
+K:181:0x83/0x9C
+
+# Fire
+K:182:0x83/0x9C
+
+# Ice
+K:183:0x83/0x9C
+
+# Summon Monster
+K:184:0x83/0x9C
+
+# Phase Door
+K:185:0x83/0x9C
+
+# Teleportation
+K:186:0x83/0x9C
+
+# Teleport Level
+K:187:0x83/0x9C
+
+# Monster Confusion
+K:188:0x83/0x9C
+
+# Magic Mapping
+K:189:0x83/0x9C
+
+# Rune of Protection
+K:190:0x83/0x9C
+
+# *Remove Curse*
+K:191:0x83/0x9C
+
+# Treasure Detection
+K:192:0x83/0x9C
+
+# Object Detection
+K:193:0x83/0x9C
+
+# Trap Detection
+K:194:0x83/0x9C
+
+# & Sheaf Arrow~
+K:195:0x8C/0x81
+
+# & Mithril Shot~
+K:196:0x8C/0x85
+
+# Door
+K:197:0x83/0x9C
+
+# Acquirement
+K:198:0x83/0x9C
+
+# *Acquirement*
+K:199:0x83/0x9C
+
+# Mass Genocide
+K:200:0x83/0x9C
+
+# Detect Invisible
+K:201:0x83/0x9C
+
+# Aggravate Monster
+K:202:0x83/0x9C
+
+# Trap Creation
+K:203:0x83/0x9C
+
+# Trap
+K:204:0x83/0x9C
+
+# Artifact Creation
+K:205:0x83/0x9C
+
+# Recharging
+K:206:0x83/0x9C
+
+# Genocide
+K:207:0x83/0x9C
+
+# Darkness
+K:208:0x83/0x9C
+
+# Protection from Evil
+K:209:0x83/0x9C
+
+# Satisfy Hunger
+K:210:0x83/0x9C
+
+# Dispel Undead
+K:211:0x83/0x9C
+
+# *Enchant Weapon*
+K:212:0x83/0x9C
+
+# Curse Weapon
+K:213:0x83/0x9C
+
+# *Enchant Armor*
+K:214:0x83/0x9C
+
+# Curse Armor
+K:215:0x83/0x9C
+
+# Summon Undead
+K:216:0x83/0x9C
+
+# Blessing
+K:217:0x83/0x9C
+
+# Holy Chant
+K:218:0x83/0x9C
+
+# Holy Prayer
+K:219:0x83/0x9C
+
+# Word of Recall
+K:220:0x83/0x9C
+
+# *Destruction*
+K:221:0x83/0x9C
+
+# Slime Mold Juice
+K:222:0x85/0x85
+
+# Apple Juice
+K:223:0x85/0x85
+
+# Water
+K:224:0x85/0x85
+
+# Strength
+K:225:0x85/0x85
+
+# Weakness
+K:226:0x85/0x85
+
+# Restore Strength
+K:227:0x85/0x85
+
+# Intelligence
+K:228:0x85/0x85
+
+# Stupidity
+K:229:0x85/0x85
+
+# Restore Intelligence
+K:230:0x85/0x85
+
+# Wisdom
+K:231:0x85/0x85
+
+# Naivety
+K:232:0x85/0x85
+
+# Restore Wisdom
+K:233:0x85/0x85
+
+# Charisma
+K:234:0x85/0x85
+
+# Ugliness
+K:235:0x85/0x85
+
+# Restore Charisma
+K:236:0x85/0x85
+
+# Curing
+K:237:0x85/0x85
+
+# Invulnerability
+K:238:0x85/0x85
+
+# New Life
+K:239:0x85/0x85
+
+# Cure Serious Wounds
+K:240:0x85/0x85
+
+# Cure Critical Wounds
+K:241:0x85/0x85
+
+# Healing
+K:242:0x85/0x85
+
+# Constitution
+K:243:0x85/0x85
+
+# Experience
+K:244:0x85/0x85
+
+# Sleep
+K:245:0x85/0x85
+
+# Blindness
+K:246:0x85/0x85
+
+# Booze
+K:247:0x85/0x85
+
+# Poison
+K:248:0x85/0x85
+
+# Speed
+K:249:0x85/0x85
+
+# Slowness
+K:250:0x85/0x85
+
+# Dexterity
+K:251:0x85/0x85
+
+# Restore Dexterity
+K:252:0x85/0x85
+
+# Restore Constitution
+K:253:0x85/0x85
+
+# Lose Memories
+K:254:0x85/0x85
+
+# Salt Water
+K:255:0x85/0x85
+
+# Enlightenment
+K:256:0x85/0x85
+
+# Heroism
+K:257:0x85/0x85
+
+# Berserk Strength
+K:258:0x85/0x85
+
+# Boldness
+K:259:0x85/0x85
+
+# Restore Life Levels
+K:260:0x85/0x85
+
+# Resist Heat
+K:261:0x85/0x85
+
+# Resist Cold
+K:262:0x85/0x85
+
+# Detect Invisible
+K:263:0x85/0x85
+
+# Slow Poison
+K:264:0x85/0x85
+
+# Neutralise Poison
+K:265:0x85/0x85
+
+# Restore Mana
+K:266:0x85/0x85
+
+# Infra-vision
+K:267:0x85/0x85
+
+# Resistance
+K:268:0x85/0x85
+
+# Spell
+K:269:0x86/0x93
+
+# Manathrust
+K:270:0x86/0x93
+
+# Fireflash
+K:271:0x86/0x93
+
+# Firewall
+K:272:0x86/0x93
+
+# Tidal Wave
+K:273:0x86/0x93
+
+# Ice Storm
+K:274:0x86/0x93
+
+# Noxious Cloud
+K:275:0x86/0x93
+
+# Poison Blood
+K:276:0x86/0x93
+
+# Thunderstorm
+K:277:0x86/0x93
+
+# Dig
+K:278:0x86/0x93
+
+# Stone Prison
+K:279:0x86/0x93
+
+# Strike
+K:280:0x86/0x93
+
+# Teleport Away
+K:281:0x86/0x93
+
+# Summon Animal
+K:282:0x86/0x93
+
+# Magelock
+K:283:0x86/0x93
+
+# Slow Monster
+K:284:0x86/0x93
+
+# Essence of Speed
+K:285:0xB7/0x8C
+
+# Banishment
+K:286:0x86/0x93
+
+# Disperse Magic
+K:287:0x86/0x93
+
+# Charm
+K:288:0x86/0x93
+
+# Confuse
+K:289:0x86/0x93
+
+# Demon Blade
+K:290:0x86/0x93
+
+# Heal Monster
+K:291:0x86/0x93
+
+# Haste Monster
+K:292:0x86/0x93
+
+# & Flight Arrow~
+K:293:0x8C/0x81
+
+# Acid Bolts
+K:294:0x86/0x93
+
+# Dragon's Flame
+K:295:0x86/0x93
+
+# Dragon's Frost
+K:296:0x86/0x93
+
+# Dragon's Breath
+K:297:0x86/0x93
+
+# Annihilation
+K:298:0x86/0x93
+
+# Rockets
+K:299:0x86/0x93
+
+# Spell
+K:300:0x87/0x92
+
+# Nothing
+K:301:0x87/0x92
+
+# Globe of Light
+K:302:0x87/0x92
+
+# Fiery Shield
+K:303:0x87/0x92
+
+# Remove Curses
+K:304:0x87/0x92
+
+# Wings of Winds
+K:305:0x87/0x92
+
+# Shake
+K:306:0x87/0x92
+
+# Disarm
+K:307:0x87/0x92
+
+# Teleportation
+K:308:0x87/0x92
+
+# Probability Travel
+K:309:0x87/0x92
+
+# Recovery
+K:310:0x87/0x92
+
+# Healing
+K:311:0x87/0x92
+
+# Vision
+K:312:0x87/0x92
+
+# Identify
+K:313:0x87/0x92
+
+# Sense Hidden
+K:314:0x87/0x92
+
+# Reveal Ways
+K:315:0x87/0x92
+
+# Sense Monsters
+K:316:0x87/0x92
+
+# Genocide
+K:317:0x87/0x92
+
+# Summon
+K:318:0x87/0x92
+
+# Curing
+K:319:0x87/0x92
+
+# Wish
+K:320:0x87/0x92
+
+# Mana
+K:321:0x87/0x92
+
+# Darkness
+K:322:0x87/0x92
+
+# Genocide
+K:323:0x87/0x92
+
+# Power
+K:324:0x87/0x92
+
+# the Magi
+K:325:0x87/0x92
+
+# Perception
+K:326:0x87/0x92
+
+# Holiness
+K:327:0x87/0x92
+
+# Enlightenment
+K:328:0x87/0x92
+
+# Healing
+K:329:0x87/0x92
+
+# & Tome~ of Magical Energy
+K:330:0x90/0xA0
+
+# & Tome~ of the Eternal Flame
+K:331:0x90/0xA1
+
+# & Tome~ of the Blowing Wind
+K:332:0x90/0xA2
+
+# & Tome~ of the Impenetrable Earth
+K:333:0x90/0xA3
+
+# & Tome~ of the Everrunning Wave
+K:334:0x90/0xA4
+
+# & Tome~ of Translocation
+K:335:0x90/0xA5
+
+# & Tome~ of the Tree
+K:336:0x90/0xA6
+
+# & Tome~ of Knowledge
+K:337:0x90/0xA7
+
+# & Small wooden chest~
+K:338:0x84/0x99
+
+# & Large wooden chest~
+K:339:0x84/0x9A
+
+# & Small iron chest~
+K:340:0x84/0x9B
+
+# & Large iron chest~
+K:341:0x84/0x9C
+
+# & Small steel chest~
+K:342:0x84/0x9D
+
+# & Large steel chest~
+K:343:0x84/0x9E
+
+# & Ruined chest~
+K:344:0x84/0x9F
+
+# & Iron Spike~
+K:345:0x8E/0x89
+
+# & Wooden Torch~
+K:346:0x8E/0x8B
+
+# & Brass Lantern~
+K:347:0x8E/0x8A
+
+# & Flask~ of oil
+K:348:0x8E/0x88
+
+# & Empty Bottle~
+K:349:0x8E/0x87
+
+# Havoc
+K:350:0x86/0x83
+
+# Door
+K:351:0x86/0x83
+
+# Trap Location
+K:352:0x86/0x83
+
+# Probing
+K:353:0x86/0x83
+
+# Recall
+K:354:0x86/0x83
+
+# Illumination
+K:355:0x86/0x83
+
+# Light
+K:356:0x86/0x83
+
+# Lightning Bolts
+K:357:0x86/0x83
+
+# Frost Bolts
+K:358:0x86/0x83
+
+# Fire Bolts
+K:359:0x86/0x83
+
+# Polymorph
+K:360:0x86/0x83
+
+# Slow Monster
+K:361:0x86/0x83
+
+# Sleep Monster
+K:362:0x86/0x83
+
+# Drain Life
+K:363:0x86/0x83
+
+# Teleport Other
+K:364:0x86/0x83
+
+# Disarming
+K:365:0x86/0x83
+
+# Lightning Balls
+K:366:0x86/0x83
+
+# Cold Balls
+K:367:0x86/0x83
+
+# Fire Balls
+K:368:0x86/0x83
+
+# Acid Balls
+K:369:0x86/0x83
+
+# Acid Bolts
+K:370:0x86/0x83
+
+# Enlightenment
+K:371:0x86/0x83
+
+# Perception
+K:372:0x86/0x83
+
+# Curing
+K:373:0x86/0x83
+
+# Healing
+K:374:0x86/0x83
+
+# Detection
+K:375:0x86/0x83
+
+# Restoration
+K:376:0x86/0x83
+
+# Speed
+K:377:0x86/0x83
+
+# Spell
+K:378:0xC1/0x84
+K:379:0x8D/0x80
+
+# [Beings of Darkness]
+K:380:0x8D/0x81
+
+# [Material Shadow]
+K:381:0x8D/0x82
+
+# [Nature's Wrath]
+K:382:0x8D/0x83
+
+# [Sign of Chaos]
+K:383:0x8C/0x98
+
+# [Chaos Mastery]
+K:384:0x8C/0x99
+
+# [Chaos Channels]
+K:385:0x8C/0x9A
+
+# [Armageddon Tome]
+K:386:0x8C/0x9B
+
+# [Nether Openings]
+K:387:0x8D/0x88
+
+# [Unholy Blessings]
+K:388:0x8D/0x89
+
+# & Firestone~
+K:389:0x8E/0x92
+
+# & Small Firestone~
+K:390:0x8E/0x93
+
+# & Broken Skull~
+K:391:0x8E/0x94
+
+# & Broken Bone~
+K:392:0x8E/0x95
+
+# & Canine Skeleton~
+K:393:0x8E/0x9A
+
+# & Rodent Skeleton~
+K:394:0x8E/0x9B
+
+# & Human Skeleton~
+K:395:0x8E/0x96
+
+# & Dwarf Skeleton~
+K:396:0x8E/0x98
+
+# & Elf Skeleton~
+K:397:0x8E/0x97
+
+# & Gnome Skeleton~
+K:398:0x8E/0x99
+
+# & Great Hammer~
+K:399:0xB6/0x8A
+
+# Black Dragon Scale Mail~
+K:400:0x8A/0x82
+
+# Blue Dragon Scale Mail~
+K:401:0x8A/0x80
+
+# White Dragon Scale Mail~
+K:402:0x8A/0x81
+
+# Red Dragon Scale Mail~
+K:403:0x8A/0x83
+
+# Green Dragon Scale Mail~
+K:404:0x8A/0x84
+
+# Multi-Hued Dragon Scale Mail~
+K:405:0x8A/0x8B
+
+# Pseudo Dragon Scale Mail~
+K:406:0x8A/0x87
+
+# Law Dragon Scale Mail~
+K:407:0x8A/0x89
+
+# Bronze Dragon Scale Mail~
+K:408:0x8A/0x85
+
+# Gold Dragon Scale Mail~
+K:409:0x8A/0x86
+
+# Chaos Dragon Scale Mail~
+K:410:0x8A/0x88
+
+# Balance Dragon Scale Mail~
+K:411:0x8A/0x8A
+
+# Power Dragon Scale Mail~
+K:412:0x8A/0x8C
+
+# & Dragon Helm~
+K:413:0x88/0x82
+
+# & Dragon Shield~
+K:414:0x88/0x9C
+
+# Death
+K:415:0x85/0x85
+
+# Ruination
+K:416:0x85/0x85
+
+# Detonations
+K:417:0x85/0x85
+
+# Augmentation
+K:418:0x85/0x85
+
+# *Healing*
+K:419:0x85/0x85
+
+# Life
+K:420:0x85/0x85
+
+# Self Knowledge
+K:421:0x85/0x85
+
+# *Enlightenment*
+K:422:0x85/0x85
+
+# [Necromantic Incantations]
+K:423:0x8D/0x8A
+
+# [Curses of Angmar]
+K:424:0x8D/0x8B
+
+# Fear Resistance
+K:425:0x84/0x83
+
+# Light and Darkness Resistance
+K:426:0x84/0x83
+
+# Nether Resistance
+K:427:0x84/0x83
+
+# Nexus Resistance
+K:428:0x84/0x83
+
+# Sound Resistance
+K:429:0x84/0x83
+
+# Confusion Resistance
+K:430:0x84/0x83
+
+# Shard Resistance
+K:431:0x84/0x83
+
+# Disenchantment Resistance
+K:432:0x84/0x83
+
+# Chaos Resistance
+K:433:0x84/0x83
+
+# Blindness Resistance
+K:434:0x84/0x83
+
+# Lordly Protection
+K:435:0x84/0x83
+
+# Extra Attacks
+K:436:0x84/0x83
+
+# Cure Light Wounds
+K:437:0x85/0x85
+
+# Clumsiness
+K:438:0x85/0x85
+
+# Sickliness
+K:439:0x85/0x85
+
+# Map of Bree
+K:440:0xC4/0x80
+
+# Map of Gondolin
+K:441:0xC4/0x80
+
+# Map of Lothlorien
+K:442:0xC4/0x80
+
+# Map of Minas Anor
+K:443:0xC4/0x80
+
+# & Silver Arrow~
+K:465:0xC6/0x81
+
+# & Silver Bolt~
+K:466:0xC6/0x82
+
+# Lightning Resistance
+K:467:0x87/0x80
+
+# Wisdom
+K:468:0x87/0x80
+
+# Regeneration
+K:469:0x87/0x80
+
+# Infravision
+K:470:0x87/0x80
+
+# Devotion
+K:471:0x87/0x80
+
+# Weaponmastery
+K:472:0x87/0x80
+
+# Trickery
+K:473:0x87/0x80
+
+# Telepathy
+K:474:0x87/0x80
+
+# Sustenance
+K:475:0x87/0x80
+
+# & Palantir~
+K:476:0xC6/0x87
+
+# & Elfstone~
+K:477:0xC6/0x83
+
+# & Jewel~
+K:478:0xC6/0x84
+
+# & Ring~
+K:479:0xC6/0x85
+
+# copper
+K:480:0x83/0x91
+K:481:0x83/0x91
+K:482:0x83/0x91
+
+# silver
+K:483:0x83/0x92
+K:484:0x83/0x92
+K:485:0x83/0x92
+
+# garnets
+K:486:0x83/0x96
+K:487:0x83/0x96
+
+# gold
+K:488:0x83/0x93
+K:489:0x83/0x93
+K:490:0x83/0x93
+
+# opals
+K:491:0x83/0x97
+
+# sapphires
+K:492:0x83/0x98
+
+# rubies
+K:493:0x83/0x99
+
+# diamonds
+K:494:0x83/0x9A
+
+# emeralds
+K:495:0x83/0x9B
+
+# mithril
+K:496:0x83/0x94
+
+# adamantite
+K:497:0x83/0x95
+
+# & Mighty Hammer~
+K:498:0xB6/0x8A
+
+# & Massive Iron Crown~
+K:499:0x87/0x9C
+
+# & Phial~
+K:500:0x8E/0x9D
+
+# & Star~
+K:501:0x8E/0x9E
+
+# & Arkenstone~
+K:502:0x8E/0x9F
+
+# & Amulet~
+K:503:0x84/0x96
+K:504:0x84/0x97
+
+# & Necklace~
+K:505:0x84/0x98
+
+# & Ring~
+K:506:0x84/0x8F
+K:507:0x84/0x90
+K:508:0x84/0x92
+K:509:0x84/0x93
+K:510:0x84/0x94
+K:511:0x84/0x95
+
+# [Rites of Initiation]
+K:512:0x8D/0x90
+
+# [Ways of War]
+K:513:0x8D/0x91
+
+# [Divine Retribution]
+K:514:0x8D/0x92
+
+# [Essence of Fury]
+K:515:0x8D/0x93
+
+# [Novice Crafts]
+K:516:0x8D/0x8C
+
+# [Arcane Channels]
+K:517:0x8D/0x8D
+
+# [Sigils of Wizardry]
+K:518:0x8D/0x8E
+
+# [Mana Focus]
+K:519:0x8D/0x8F
+
+# Reflection
+K:520:0x87/0x83
+
+# Anti-Magic
+K:521:0x87/0x83
+
+# Anti-Teleportation
+K:522:0x87/0x83
+
+# Resistance
+K:523:0x87/0x83
+
+# & Zweihander~
+K:524:0xB6/0x8C
+
+# & Dwarven Lantern~
+K:525:0xC5/0x94
+
+# Splint Mail~
+K:526:0x89/0x9C
+
+# & Everburning Torch~
+K:527:0xC5/0x95
+
+# & Trifurcate Spear~
+K:528:0xB6/0x85
+
+# & Three Piece Rod~
+K:529:0xB6/0x80
+
+# & Feanorian Lamp~
+K:530:0xC5/0x96
+
+# & Fur Cloak~
+K:531:0x89/0x89
+
+# Water Curing
+K:532:0xB6/0x86
+
+# & Hatchet~
+K:533:0xB6/0x8F
+
+# Rhino Hide Armour~
+K:535:0x89/0x98
+
+# Leather Jacket~
+K:536:0x89/0x8F
+
+# & Sickle~
+K:537:0xB6/0x90
+
+# [Psychoportation]
+K:538:0xB6/0x87
+
+# [Clairsentience]
+K:539:0xB6/0x91
+
+# [Telekinesis]
+K:540:0xB6/0x93
+
+# [Empathy]
+K:541:0xB6/0x92
+
+# & Club~
+K:542:0xB6/0x92
+
+# & Broad Spear~
+K:543:0xB6/0x84
+
+# & Khopesh~
+K:544:0xB6/0x94
+
+# & Flamberge~
+K:545:0xB6/0x83
+
+# & Claymore~
+K:546:0xB6/0x8D
+
+# & Espadon~
+K:547:0xB6/0x8E
+
+# & Great Scimitar~
+K:548:0xB6/0x8B
+
+# Arrow
+K:549:0x8E/0xA0
+
+# Bolt
+K:550:0x8E/0xA1
+
+# & Fauchard~
+K:551:0xB6/0x95
+
+# & Guisarme~
+K:552:0xB6/0x96
+
+# & Heavy Lance~
+K:553:0xB6/0x82
+
+# & Basillard~
+K:554:0xB6/0x99
+
+# Catapult
+K:555:0x8E/0xA2
+
+# Ring Mail~
+K:556:0x89/0x9C
+
+# Cord Armour~
+K:557:0x89/0x90
+
+# Paper Armour~
+K:558:0x8A/0x81
+
+# Padded Armour~
+K:559:0x89/0x91
+
+# Fumes
+K:560:0x8E/0xA3
+
+# Stone and Hide Armour~
+K:561:0x89/0x97
+
+# Magic
+K:562:0x8E/0xA4
+
+# Device
+K:563:0x8E/0xA5
+
+# Nothing
+K:564:0xC6/0x9C
+
+# Poison
+K:565:0xB7/0x80
+
+# Nothing
+K:566:0xC6/0x9C
+K:567:0xC6/0x9C
+K:568:0xC6/0x9C
+K:569:0xC6/0x9C
+
+# Explosion
+K:570:0xB7/0x81
+
+# Teleport
+K:571:0xB7/0x82
+
+# Nothing
+K:572:0xC6/0x9C
+
+# & Blood~ of Life
+K:573:0x85/0x85
+
+# Cold
+K:574:0xB7/0x83
+
+# Fire
+K:575:0xB7/0x84
+
+# Acid
+K:576:0xB7/0x85
+
+# & Mage Staff~
+K:577:0xB8/0x80
+
+# Lightning
+K:578:0x84/0x80
+
+# Life
+K:579:0xB7/0x86
+
+# Confusion
+K:580:0xB7/0x87
+
+# Light
+K:581:0xB7/0x88
+
+# & Ring~
+K:582:0x84/0x85
+
+# Invisibility
+K:583:0x85/0x85
+
+# Chaos
+K:584:0xB7/0x89
+
+# Corruption
+K:585:0x85/0x85
+
+# Invisibility
+K:586:0x85/0x85
+
+# Time
+K:587:0xB7/0x8A
+
+# Deep Thoughts
+K:588:0x83/0x9C
+
+# More Deep Thoughts
+K:589:0x83/0x9D
+
+# Compendium of Deep Thoughts
+K:590:0x83/0x9E
+
+# Artifact Lore Vol. I
+K:591:0x83/0x9C
+
+# Artifact Lore Vol. II
+K:592:0x83/0x9D
+
+# Artifact Lore Vol. III
+K:593:0x83/0x9F
+
+# Monstrous Compendium 1
+K:594:0x83/0x9F
+
+# Monstrous Compendium 2
+K:595:0x83/0x9E
+
+# Monstrous Compendium 3
+K:596:0x83/0x9D
+
+# Monstrous Compendium 4
+K:597:0x83/0x9C
+
+# Monstrous Compendium 5
+K:598:0x83/0x9F
+
+# Monstrous Compendium 6
+K:599:0x83/0x9E
+
+# Monstrous Compendium 7
+K:600:0x83/0x9D
+
+# Monstrous Compendium 8
+K:601:0x83/0x9C
+
+# Monstrous Compendium 9
+K:602:0x83/0x9D
+
+# Monstrous Compendium 10
+K:603:0x83/0x9E
+
+# Monstrous Compendium 11
+K:604:0x83/0x9F
+
+# Abomination
+K:605:0x85/0x85
+
+# Shape of Wolf
+K:606:0x85/0x85
+
+# Shape of Ape
+K:607:0x85/0x85
+
+# Shape of Goat
+K:608:0x85/0x85
+
+# Shape of Insect
+K:609:0x85/0x85
+
+# Shape of Sparrow
+K:610:0x85/0x85
+
+# Shape of Ent
+K:611:0x85/0x85
+
+# Shape of Vampire
+K:612:0x85/0x85
+
+# Shape of Spider
+K:613:0x85/0x85
+
+# Shape of Mana ball
+K:614:0x85/0x85
+
+# Shape of Fire cloud
+K:615:0x85/0x85
+
+# Shape of Cold cloud
+K:616:0x85/0x85
+
+# Shape of Chaos cloud
+K:617:0x85/0x85
+
+# [Wolf]
+K:618:0x8F/0xA0
+
+# [Ape]
+K:619:0x8F/0xA1
+
+# [Goat]
+K:620:0x8F/0xA2
+
+# [Insect]
+K:621:0x8F/0xA3
+
+# [Sparrow]
+K:622:0x8F/0xA4
+
+# [Ent]
+K:623:0x8F/0xA5
+
+# [Vampire]
+K:624:0x8F/0xA6
+
+# [Spider]
+K:625:0x8F/0xA7
+
+# [Mana ball]
+K:626:0x8F/0xA8
+
+# [Fire cloud]
+K:627:0x8F/0xA9
+
+# [Cold cloud]
+K:628:0x8F/0xAA
+
+# [Chaos Cloud]
+K:629:0x8F/0xAB
+
+# [Ghost]
+K:630:0x8F/0xAC
+
+# [Kobold]
+K:631:0x8F/0xAD
+
+# [Dragon]
+K:632:0x8F/0xAE
+
+# [Demon]
+K:633:0x8F/0xAF
+
+# [Hound]
+K:634:0x8F/0xB0
+
+# [Quylthulg]
+K:635:0x8F/0xB1
+
+# [Maia]
+K:636:0x8F/0xB2
+
+# [Serpent]
+K:637:0x8F/0xB3
+
+# [Giant]
+K:638:0x8F/0xB4
+
+# [Vala]
+K:639:0x8F/0xB5
+
+# Magic
+K:640:0xB7/0x8B
+
+# corpse
+K:641:0xB8/0x81
+
+# skeleton
+K:642:0x8E/0x96
+
+# head
+K:643:0x8E/0x94
+
+# skull
+K:644:0x8E/0x94
+
+# raw meat
+K:645:0x8E/0x83
+
+# & Thunderlord Coat~
+K:646:0x8A/0x86
+
+# & Stone~
+K:647:0x8E/0x9C
+
+# & small wooden Boomerang~
+K:648:0xB8/0x82
+
+# & wooden Boomerang~
+K:649:0xB8/0x83
+
+# & small metal Boomerang~
+K:650:0xB8/0x84
+
+# & metal Boomerang~
+K:651:0xB8/0x85
+
+# & Anchor~
+K:652:0x8D/0x9E
+
+# & ~
+K:653:0xC6/0x9C
+
+# Summon never-moving pet
+K:654:0x83/0x9D
+
+# [Life in symbiosis]
+K:655:0xB8/0x86
+
+# [Perfect Symbiosis]
+K:656:0xB8/0x86
+
+# Cure Light Insanity
+K:657:0x85/0x85
+
+# Cure Serious Insanity
+K:658:0x85/0x85
+
+# Cure Critical Insanity
+K:659:0x85/0x85
+
+# Cure Insanity
+K:660:0x85/0x85
+
+# & Phial~
+K:661:0x8E/0x9D
+
+# Random Artifact
+K:662:0xC6/0x9C
+
+# Craftmanship
+K:663:0x83/0x9F
+
+# The One Ring
+K:664:0x83/0x9E
+
+# & Book~ of the Lays of the Heroes
+K:665:0xB8/0x87
+
+# & Book~ of Sound Patterns
+K:666:0xB8/0x87
+
+# [Harps of Rivendell]
+K:667:0xB8/0x87
+
+# [Lays of Beleriand]
+K:668:0xB8/0x87
+
+# & Flute~
+K:669:0xB8/0x88
+
+# & Drum~
+K:670:0xB8/0x89
+
+# & Harp~
+K:671:0xB8/0x8A
+
+# & Banjo~
+K:672:0xB8/0x8C
+
+# & Lute~
+K:673:0xB8/0x8B
+
+# & Mandolin~
+K:674:0xB8/0x8B
+
+# & Palantir~
+K:675:0x8D/0x9F
+
+# Egg
+K:676:0xB7/0x8D
+
+# Reset Recall
+K:677:0x83/0x9D
+
+# Divination
+K:678:0x83/0x9D
+
+# Self
+K:679:0xB7/0x8E
+
+# Ray
+K:680:0xB7/0x8F
+
+# Sphere
+K:681:0xB7/0x90
+
+# Knowledge
+K:682:0xB7/0x94
+
+# Life
+K:683:0xB7/0x95
+
+# Fire
+K:684:0xB7/0x96
+
+# Cold
+K:685:0xB7/0x97
+
+# Lightning
+K:686:0xB7/0x98
+
+# Acid
+K:687:0xB7/0x99
+
+# Element
+K:688:0xB7/0x9A
+
+# Chaos
+K:689:0xB7/0x9B
+
+# Mind
+K:690:0xB7/0x9C
+
+# Holding
+K:691:0xB7/0x9D
+
+# Arrow
+K:692:0xB7/0x91
+
+# Power Surge
+K:693:0xB7/0x92
+
+# Armageddon
+K:694:0xB7/0x93
+
+# Gravity
+K:695:0xB7/0x9E
+
+# Extra Life
+K:696:0xB7/0x9F
+
+# Undeath
+K:697:0xB6/0x9B
+
+# Protection
+K:698:0xB6/0x9C
+
+# & Horn~
+K:699:0xB8/0x8D
+
+# & Ring~ of Precognition
+K:700:0x84/0x83
+
+# & Sprig~ of Athelas
+K:701:0xB8/0x8E
+
+# [Magic for Beginners]
+K:702:0xB8/0x8F
+
+# [Conjurings and Tricks]
+K:703:0xB8/0x8F
+
+# [Incantations and Illusions]
+K:704:0xB8/0x8F
+
+# [Sorcery and Evocations]
+K:705:0xB8/0x8F
+
+# [Beginners Handbook]
+K:706:0xB8/0x90
+
+# [Words of Wisdom]
+K:707:0xB8/0x90
+
+# [Chants and Blessings]
+K:708:0xB8/0x90
+
+# [Exorcism and Dispelling]
+K:709:0xB8/0x90
+
+# [Resistance of Scarabtarices]
+K:710:0xB8/0x92
+
+# [Mordenkainen's Escapes]
+K:711:0xB8/0x92
+
+# [Kelek's Grimoire of Power]
+K:712:0xB8/0x92
+
+# [Tenser's Transformations]
+K:713:0xB8/0x92
+
+# [Raal's Tome of Destruction]
+K:714:0xB8/0x92
+
+# [Ethereal Openings]
+K:715:0xB8/0x92
+
+# [Godly Insights]
+K:716:0xB8/0x91
+
+# [Purifications and Healing]
+K:717:0xB8/0x91
+
+# [Holy Infusions]
+K:718:0xB8/0x91
+
+# [Wrath of God]
+K:719:0xB8/0x91
+
+# & Old Scroll~ of Deincarnation
+K:720:0x83/0x9F
+
+# & Dark Sword~
+K:721:0xC4/0x81
+
+# Numenorean for beginners (I)
+K:722:0xC1/0x80
+
+# Numenorean for beginners (II)
+K:723:0xC1/0x81
+
+# Advanced lessons of Numenorean
+K:724:0xC1/0x80
+
+# Advanced lessons of Sindarin
+K:725:0xC1/0x81
+
+# & Shard~ of Pottery
+K:726:0x8E/0x92
+
+# & Broken Stick~
+K:727:0x8E/0x93
+
+# Wall Creation
+K:728:0x83/0x9F
+
+# [Illusions for Beginners]
+K:729:0xC1/0x82
+
+# [Tricks and Visions]
+K:730:0xC1/0x82
+
+# [Phantasms and Illusions]
+K:731:0xC1/0x82
+
+# [Shadows and Prisms]
+K:732:0xC1/0x82
+
+# [Serten's Immunities]
+K:733:0xC1/0x83
+
+# [Knowledge of Kenault]
+K:734:0xC1/0x83
+
+# [Otiluke's Spheres]
+K:735:0xC1/0x82
+
+# [Boccob's Book of Shadows]
+K:736:0xC1/0x84
+
+# [Bigby's Handbook]
+K:737:0xC1/0x84
+
+# & Book~ of Beginner Cantrips
+K:738:0xC1/0x85
+
+# & Book~ of Teleportation
+K:739:0xC1/0x86
+
+# & Book~ of Recall
+K:740:0xC1/0x87
+
+# & Book~ of Summoning
+K:741:0xC1/0x80
+
+# & Book~ of Fireflash
+K:742:0xC1/0x81
+
+# & Potion~ of Learning
+K:743:0xC1/0x82
+
+# [Eye of Sauron]
+K:744:0xC1/0x83
+
+# [Flame of Udun]
+K:745:0xC1/0x84
+
+# [Corruptions of Melkor]
+K:746:0xC1/0x85
+
+# [Crescent of Morgul]
+K:747:0xC1/0x86
+
+# [Morgoth's Ring]
+K:748:0xC1/0x87
+
+# Spell
+K:749:0x86/0x90
+
+# Wishing
+K:750:0x86/0x90
+
+# Khuzdul - The hidden tongue of the Dwarves
+K:751:0x83/0x9D
+
+# Nandorin for dummies
+K:752:0xC1/0x81
+
+# Advanced lessons of Orcish
+K:753:0xC1/0x82
+
+# & Ancient Tome~
+K:754:0xC1/0x86
+
+# Flying
+K:755:0x84/0x88
+
+# & Tome~ of the Time
+K:756:0xC1/0x80
+
+# & Tome~ of Meta Spells
+K:758:0xC1/0x81
+
+# & Tome~ of the Mind
+K:759:0xC1/0x82
+
+# & Holy Tome~ of Eru Iluvatar
+K:760:0xC1/0x83
+
+# & Holy Tome~ of Manwe Sulimo
+K:761:0xC1/0x84
+
+# & War Tome~ of Tulkas
+K:762:0xC1/0x85
+
+# & Unholy Tome~ of the Hellflame
+K:763:0xC1/0x86
+
+# & Corrupted Tome~ of Melkor
+K:764:0xC1/0x87
+
+# [Aiding Shades]
+K:765:0xC1/0x80
+
+# [Morgoth's Space-Time Warpings]
+K:766:0xC1/0x81
+
+# [Murazor's Tome of Conjuring & Dispelling]
+K:767:0xC1/0x82
+
+# & Forest Tome~ of Yavanna
+K:768:0xC1/0x83
+
+# [Sauron's Forgotten Tome]
+K:769:0xC1/0x87
+
+# & Ring~
+K:770:0x84/0x84
+
+# [Earth]
+K:771:0xC1/0x88
+
+# [Fire]
+K:772:0xC1/0x89
+
+# [Air]
+K:773:0xC1/0x8A
+
+# [Water]
+K:774:0xC1/0x8B
+
+# [Mana]
+K:775:0xC1/0x8C
+
+# Home Summoning
+K:776:0x83/0x9F
+
+# & Shadow Blade~
+K:777:0xC1/0x91
+
+# & Bluesteel Blade~
+K:778:0xC1/0x92
+
+# the Serpents
+K:779:0xC4/0x88
+
+# Darkness
+K:780:0xC4/0x89
+
+# Knowledge
+K:781:0xC4/0x8A
+
+# Force
+K:782:0xC4/0x8B
+
+# Lightning
+K:783:0xC4/0x8C
+
+# Mana
+K:784:0xC4/0x8D
+
+# Ring~ of Power
+K:785:0xC4/0x8E
+
+# Climbing Set~
+K:786:0xC1/0x93
+
+# Adventurer's guide to Middle-earth
+K:787:0x83/0x9E
+
+# & Demonblade~
+K:788:0x90/0xA8
+
+# & Demonshield~
+K:789:0x90/0xA9
+
+# & Demonhorn~
+K:790:0x90/0xAA
+
+# [Demonthoughts]
+K:791:0xC1/0x83
+
+# [Hellfire Tome]
+K:792:0xC1/0x94
+
+# & Wooden Rod~ of#
+K:793:0xC1/0x95
+
+# & Copper Rod~ of#
+K:794:0xC1/0x96
+
+# & Iron Rod~ of#
+K:795:0xC1/0x97
+
+# & Moonstone Rod~ of#
+K:796:0xC1/0x98
+
+# & Silver Rod~ of#
+K:797:0xC1/0x99
+
+# & Golden Rod~ of#
+K:798:0xC1/0x9B
+
+# & Mithril Rod~ of#
+K:799:0xC1/0x9C
+
+# & Adamantite Rod~ of#
+K:800:0xC1/0x9D
+
+# & Greater Ration~ of Health
+K:801:0xC4/0x87
+
+# & Crumpled Scroll~ of Mass Resurrection
+K:802:0x83/0x9E
+
+# & Cleaver~
+K:803:0xC4/0x82
+
+# & Light War Axe~
+K:804:0xC4/0x83
+
+# & Slaughter Axe~
+K:805:0xC4/0x84
+
+# & Runestone~
+K:806:0xC4/0x85
+
+# & Fortune cookie~
+K:807:0xC6/0x86
+
+# Portable hole
+K:808:0xC6/0x89
+
+# Critical Hits
+K:809:0xC6/0x9C
+
+# & Wand~ of Digging of Thrain
+K:810:0xC6/0x9C
+
+# & Gnarled Staff~ of Holy Fire of Mithrandir
+K:811:0xC6/0x9C
+
+# Partial Totem
+K:812:0xC6/0x9D
+
+# True Totem
+K:813:0xC6/0x9E
+
+# Player
+R:0:0x8E/0x80
+
+# Filthy street urchin
+R:1:0xAA/0x80
+
+# Scrawny cat
+R:2:0xA7/0x82
+
+# Sparrow
+R:3:0xB4/0x9E
+
+# Chaffinch
+R:4:0xB4/0x9E
+
+# Wild rabbit
+R:5:0xB4/0x9F
+
+# Woodsman
+R:6:0xAA/0x91
+
+# Scruffy little dog
+R:7:0x9D/0x9A
+
+# Farmer Maggot
+R:8:0xAA/0x81
+
+# Blubbering idiot
+R:9:0xAA/0x82
+
+# Boil-covered wretch
+R:10:0xAA/0x83
+
+# Village idiot
+R:11:0xAA/0x84
+
+# Pitiful-looking beggar
+R:12:0xAA/0x85
+
+# Mangy-looking leper
+R:13:0xAA/0x86
+
+# Agent of the black market
+R:14:0xAA/0x87
+
+# Singing, happy drunk
+R:15:0xAA/0x88
+
+# Aimless-looking merchant
+R:16:0xAA/0x89
+
+# Mean-looking mercenary
+R:17:0xAA/0x8A
+
+# Battle-scarred veteran
+R:18:0xAA/0x8B
+
+# Martti Ihrasaari
+R:19:0xB0/0x80
+
+# Grey mold
+R:20:0xA8/0x9F
+
+# Large white snake
+R:21:0xA2/0x85
+
+# Grey mushroom patch
+R:22:0xB0/0x81
+
+# Newt
+R:23:0xB0/0x82
+
+# Giant white centipede
+R:24:0xA5/0x95
+
+# White icky thing
+R:25:0xA8/0x83
+
+# Clear icky thing
+R:26:0xA8/0x84
+
+# Giant white mouse
+R:27:0xAC/0x85
+
+# Large brown snake
+R:28:0xA2/0x84
+
+# Small kobold
+R:29:0xA8/0x99
+
+# Kobold
+R:30:0xA8/0x9A
+
+# White worm mass
+R:31:0xAC/0x9D
+
+# Floating eye
+R:32:0xA6/0x9B
+
+# Rock lizard
+R:33:0xA2/0x86
+
+# Grid bug
+R:34:0xB0/0x84
+
+# Jackal
+R:35:0x9D/0x9B
+
+# Soldier ant
+R:36:0xA5/0x87
+
+# Fruit bat
+R:37:0xA5/0x8F
+
+# Insect swarm
+R:38:0xB5/0x9E
+
+# The Greater hell-beast
+R:39:0xB0/0x83
+
+# Shrieker mushroom patch
+R:40:0x9D/0x86
+
+# Blubbering icky thing
+R:41:0xA8/0x85
+
+# Metallic green centipede
+R:42:0xA5/0x96
+
+# Novice warrior
+R:43:0xAA/0x8C
+
+# Novice rogue
+R:44:0xAA/0x8D
+
+# Novice priest
+R:45:0xAA/0x8E
+
+# Novice mage
+R:46:0xAA/0x8F
+
+# Yellow mushroom patch
+R:47:0x9D/0x87
+
+# White jelly
+R:48:0xA8/0x8A
+
+# Giant black ant
+R:49:0xA5/0x88
+
+# Salamander
+R:50:0xA2/0x88
+
+# White harpy
+R:51:0xA0/0x88
+
+# Blue yeek
+R:52:0xAD/0x87
+
+# Grip, Farmer Maggot's dog
+R:53:0x9D/0x9C
+
+# Wolf, Farmer Maggot's dog
+R:54:0x9D/0x9D
+
+# Fang, Farmer Maggot's dog
+R:55:0x9D/0x9D
+
+# Giant green frog
+R:56:0xA2/0x87
+
+# Freesia
+R:57:0xB0/0x85
+
+# Green worm mass
+R:58:0xAC/0x9E
+
+# Large yellow snake
+R:59:0xA2/0x89
+
+# Cave spider
+R:60:0xA2/0x9D
+
+# Crow
+R:61:0xB5/0x9F
+
+# Wild cat
+R:62:0xA7/0x83
+
+# Smeagol
+R:63:0xAA/0x90
+
+# Green ooze
+R:64:0xA8/0x8B
+
+# Poltergeist
+R:65:0x9F/0x99
+
+# Yellow jelly
+R:66:0xA8/0x8D
+
+# Metallic blue centipede
+R:67:0xA5/0x97
+
+# Raven
+R:68:0xB5/0x9F
+
+# Giant white louse
+R:69:0xA8/0x9D
+
+# Giant yellow centipede
+R:70:0xA5/0x94
+
+# Black naga
+R:71:0xA9/0x88
+
+# Spotted mushroom patch
+R:72:0x9D/0x88
+
+# Silver jelly
+R:73:0xA8/0x8C
+
+# Scruffy-looking hobbit
+R:74:0xA7/0x93
+
+# Giant white ant
+R:75:0xA5/0x89
+
+# Yellow mold
+R:76:0xA9/0x80
+
+# Metallic red centipede
+R:77:0xA5/0x98
+
+# Yellow worm mass
+R:78:0xAC/0x9F
+
+# Clear worm mass
+R:79:0xAD/0x80
+
+# Radiation eye
+R:80:0xA6/0x9C
+
+# Yellow light
+R:81:0xB8/0x93
+
+# Cave lizard
+R:82:0xA2/0x8A
+
+# Novice ranger
+R:83:0xAA/0x91
+
+# Blue jelly
+R:84:0xA8/0x8E
+
+# Creeping copper coins
+R:85:0x9D/0x80
+
+# Giant white rat
+R:86:0xAC/0x86
+
+# Snotling
+R:87:0xB9/0x89
+
+# Swordfish
+R:88:0xB6/0x9E
+
+# Blue worm mass
+R:89:0xAD/0x81
+
+# Large grey snake
+R:90:0xA2/0x8B
+
+# Skeleton kobold
+R:91:0xAC/0x89
+
+# Ewok
+R:92:0xB0/0x86
+
+# Novice mage
+R:93:0xAA/0x8F
+
+# Green naga
+R:94:0xA9/0x89
+
+# Giant leech
+R:95:0xB8/0x94
+
+# Barracuda
+R:96:0xB6/0x9F
+
+# Novice paladin
+R:97:0xAA/0x92
+
+# Zog
+R:98:0xA1/0x80
+
+# Blue ooze
+R:99:0xA8/0x8F
+
+# Green glutton ghost
+R:100:0x9F/0x9A
+
+# Green jelly
+R:101:0xA8/0x90
+
+# Large kobold
+R:102:0xA8/0x9B
+
+# Grey icky thing
+R:103:0xA8/0x86
+
+# Disenchanter eye
+R:104:0xA6/0x9D
+
+# Red worm mass
+R:105:0xAD/0x82
+
+# Copperhead snake
+R:106:0xA2/0x8C
+
+# Death sword
+R:107:0xB0/0x87
+
+# Purple mushroom patch
+R:108:0x9D/0x89
+
+# Novice priest
+R:109:0xAA/0x8E
+
+# Novice warrior
+R:110:0xAA/0x8C
+
+# Nibelung
+R:111:0xB0/0x88
+
+# The disembodied hand that strangled people
+R:112:0xB0/0x89
+
+# Brown mold
+R:113:0xA9/0x81
+
+# Giant brown bat
+R:114:0xA5/0x90
+
+# Rat-thing
+R:115:0xAC/0x88
+
+# Novice rogue
+R:116:0xAA/0x87
+
+# Creeping silver coins
+R:117:0x9D/0x81
+
+# Snaga
+R:118:0xA9/0x8E
+
+# Rattlesnake
+R:119:0xA2/0x8D
+
+# Giant slug
+R:120:0xB8/0x94
+
+# Giant pink frog
+R:121:0xB8/0x95
+
+# Dark elf
+R:122:0x92/0x94
+
+# Zombified kobold
+R:123:0xAC/0x89
+
+# Crypt creep
+R:124:0xB0/0x8A
+
+# Rotting corpse
+R:125:0xB0/0x8B
+
+# Cave orc
+R:126:0xA9/0x8F
+
+# Wood spider
+R:127:0xA2/0x9E
+
+# Manes
+R:128:0xA0/0x91
+
+# Bloodshot eye
+R:129:0xA6/0x9E
+
+# Red naga
+R:130:0xA9/0x8A
+
+# Red jelly
+R:131:0xA8/0x91
+
+# Green icky thing
+R:132:0xA8/0x87
+
+# Lost soul
+R:133:0x9F/0x9B
+
+# Night lizard
+R:134:0xA2/0x8F
+
+# Mughash, the Kobold Lord
+R:135:0xA8/0x9C
+
+# Skeleton orc
+R:136:0xAC/0x8A
+
+# Wormtongue, Agent of Saruman
+R:137:0xAA/0x98
+
+# Robin Hood, the Outlaw
+R:138:0xB0/0x8C
+
+# Nurgling
+R:139:0xB8/0x97
+
+# Lagduf, the Snaga
+R:140:0xA9/0x90
+
+# Brown yeek
+R:141:0xAD/0x88
+
+# Novice ranger
+R:142:0xAA/0x91
+
+# Giant salamander
+R:143:0xA2/0x90
+
+# Space monster
+R:144:0xB0/0x8D
+
+# Carnivorous flying monkey
+R:145:0xB8/0x98
+
+# Green mold
+R:146:0xA9/0x82
+
+# Novice paladin
+R:147:0xAA/0x92
+
+# Lemure
+R:148:0xA0/0x92
+
+# Hill orc
+R:149:0xA9/0x91
+
+# Bandit
+R:150:0xAA/0x9B
+
+# Hunting hawk
+R:151:0xB0/0x8E
+
+# Phantom warrior
+R:152:0xB0/0x8F
+
+# Gremlin
+R:153:0xB0/0x90
+
+# Yeti
+R:154:0xA4/0x91
+
+# Bloodshot icky thing
+R:155:0xA8/0x88
+
+# Giant grey rat
+R:156:0xAC/0x87
+
+# Black harpy
+R:157:0xA0/0x89
+
+# Skaven
+R:158:0xB8/0x99
+
+# The wounded bear
+R:159:0xBA/0x80
+
+# Cave bear
+R:160:0xC4/0x8F
+
+# Rock mole
+R:161:0xBA/0x82
+
+# Mindcrafter
+R:162:0xAA/0x93
+
+# Baby blue dragon
+R:163:0xA5/0x9D
+
+# Baby white dragon
+R:164:0xA5/0x9E
+
+# Baby green dragon
+R:165:0xA5/0x9F
+
+# Baby black dragon
+R:166:0xA6/0x80
+
+# Baby red dragon
+R:167:0xA6/0x81
+
+# Giant red ant
+R:168:0xA5/0x8D
+
+# Brodda, the Easterling
+R:169:0xAA/0x9C
+
+# Bloodfang, the Wolf
+R:170:0xBA/0x83
+
+# King cobra
+R:171:0xA2/0x91
+
+# Eagle
+R:172:0xB4/0x9E
+
+# War bear
+R:173:0xB0/0x91
+
+# Killer bee
+R:174:0xB0/0x92
+
+# Giant spider
+R:175:0xA2/0x9F
+
+# Giant white tick
+R:176:0xA8/0x9D
+
+# The Borshin
+R:177:0xBA/0x84
+
+# Dark elven mage
+R:178:0xA7/0x96
+
+# Kamikaze yeek
+R:179:0xBA/0x94
+
+# Orfax, Son of Boldor
+R:180:0xAD/0x89
+
+# Servant of Glaaki
+R:181:0xBA/0x85
+
+# Dark elven warrior
+R:182:0xA7/0x97
+
+# Sand-dweller
+R:183:0xBA/0x86
+
+# Clear mushroom patch
+R:184:0xB8/0x96
+
+# Quiver slot
+R:185:0xB0/0x93
+
+# Grishnakh, the Hill Orc
+R:186:0xA9/0x93
+
+# Giant tan bat
+R:187:0xC4/0x90
+
+# Owlbear
+R:188:0xBA/0x87
+
+# Blue horror
+R:189:0xB8/0x9A
+
+# Hairy mold
+R:190:0xA9/0x83
+
+# Grizzly bear
+R:191:0xBA/0x88
+
+# Disenchanter mold
+R:192:0xA9/0x84
+
+# Pseudo dragon
+R:193:0xA6/0x82
+
+# Tengu
+R:194:0xA0/0x93
+
+# Creeping gold coins
+R:195:0x9D/0x82
+
+# Wolf
+R:196:0x9D/0x9E
+
+# Giant fruit fly
+R:197:0x9F/0x91
+
+# Panther
+R:198:0xA7/0x84
+
+# Brigand
+R:199:0xB0/0x94
+
+# Hobbes the Tiger
+R:200:0xB0/0x95
+
+# Shadow Creature of Fiona
+R:201:0xB0/0x96
+
+# Undead mass
+R:202:0xB0/0x97
+
+# Chaos shapechanger
+R:203:0xB0/0x98
+
+# Baby multi-hued dragon
+R:204:0xA6/0x83
+
+# Vorpal bunny
+R:205:0xB4/0x9F
+
+# Old Man Willow
+R:206:0xBA/0x89
+
+# Hippocampus
+R:207:0xBA/0x8A
+
+# Zombified orc
+R:208:0xAC/0x8C
+
+# Hippogriff
+R:209:0xA0/0x8A
+
+# Black mamba
+R:210:0xA2/0x92
+
+# White wolf
+R:211:0x9D/0x9F
+
+# Grape jelly
+R:212:0xA8/0x92
+
+# Nether worm mass
+R:213:0xAD/0x83
+
+# Abyss worm mass
+R:214:0xB0/0x99
+
+# Golfimbul, the Hill Orc Chief
+R:215:0xA9/0x94
+
+# Swordsman
+R:216:0x97/0x81
+
+# Skaven shaman
+R:217:0x9A/0x84
+
+# Baby bronze dragon
+R:218:0xA6/0x82
+
+# Baby gold dragon
+R:219:0xA6/0x82
+
+# Evil eye
+R:220:0xC4/0x91
+
+# Mine-dog
+R:221:0xB9/0x8B
+
+# Hellcat
+R:222:0xB0/0x9A
+
+# Moon beast
+R:223:0xB0/0x9B
+
+# Master yeek
+R:224:0xAD/0x8A
+
+# Priest
+R:225:0xAA/0x9E
+
+# Dark elven priest
+R:226:0xA7/0x99
+
+# Air spirit
+R:227:0x9E/0x9F
+
+# Skeleton human
+R:228:0xAC/0x8B
+
+# Zombified human
+R:229:0xAD/0x8E
+
+# Tiger
+R:230:0xA7/0x85
+
+# Moaning spirit
+R:231:0x9F/0x9C
+
+# Stegocentipede
+R:232:0xA5/0x99
+
+# Spotted jelly
+R:233:0xA8/0x93
+
+# Drider
+R:234:0xA3/0x80
+
+# Mongbat
+R:235:0xB0/0x9C
+
+# Killer brown beetle
+R:236:0xA0/0x9B
+
+# Boldor, King of the Yeeks
+R:237:0xAD/0x8B
+
+# Ogre
+R:238:0xA1/0x8B
+
+# Creeping mithril coins
+R:239:0x9D/0x83
+
+# Illusionist
+R:240:0xAB/0x80
+
+# Druid
+R:241:0xAB/0x81
+
+# Pink horror
+R:242:0xB8/0x9B
+
+# Cloaker
+R:243:0x89/0x88
+
+# Black orc
+R:244:0xA9/0x95
+
+# Ochre jelly
+R:245:0xA8/0x94
+
+# Software bug
+R:246:0xB0/0x9D
+
+# Lurker
+R:247:0x80/0x81
+
+# Tangleweed
+R:248:0xC4/0x92
+
+# Vlasta
+R:249:0xA5/0x84
+
+# Giant white dragon fly
+R:250:0x9F/0x93
+
+# Snaga sapper
+R:251:0xB9/0x8C
+
+# Blue icky thing
+R:252:0xA8/0x89
+
+# Gibbering mouther
+R:253:0xB0/0x9E
+
+# Wolfhound of Flora
+R:254:0xB0/0x9F
+
+# Hill giant
+R:255:0xA1/0x91
+
+# Flesh golem
+R:256:0xA7/0x89
+
+# Warg
+R:257:0x9E/0x80
+
+# Cheerful leprechaun
+R:258:0xB1/0x80
+
+# Giant flea
+R:259:0x9F/0x92
+
+# Ufthak of Cirith Ungol
+R:260:0xBA/0x8C
+
+# Clay golem
+R:261:0xB8/0x9D
+
+# Black ogre
+R:262:0xA1/0x8C
+
+# Dweller on the threshold
+R:263:0xB9/0x8D
+
+# Half-orc
+R:264:0xBA/0x8D
+
+# Dark naga
+R:265:0xB8/0x9E
+
+# Poison ivy
+R:266:0xC4/0x93
+
+# Magic mushroom patch
+R:267:0x9D/0x8B
+
+# Plaguebearer of Nurgle
+R:268:0xAD/0x8D
+
+# Guardian naga
+R:269:0xA9/0x8B
+
+# Wererat
+R:270:0xBA/0x8E
+
+# Light hound
+R:271:0xA4/0x93
+
+# Dark hound
+R:272:0xA4/0x94
+
+# Flying skull
+R:273:0xB1/0x81
+
+# Mi-Go
+R:274:0xB1/0x82
+
+# Giant tarantula
+R:275:0xA3/0x81
+
+# Giant clear centipede
+R:276:0xA5/0x9A
+
+# Mirkwood spider
+R:277:0xA3/0x82
+
+# Frost giant
+R:278:0xA1/0x92
+
+# Griffon
+R:279:0xA0/0x8B
+
+# Homunculus
+R:280:0xA0/0x94
+
+# Gnome mage
+R:281:0xA7/0x98
+
+# Clear hound
+R:282:0xA4/0x95
+
+# Umber hulk
+R:283:0xA3/0x99
+
+# Rust monster
+R:284:0xB9/0x8F
+
+# Ogrillon
+R:285:0xA9/0x98
+
+# Gelatinous cube
+R:286:0xA8/0x95
+
+# Giant green dragon fly
+R:287:0x9F/0x94
+
+# Fire giant
+R:288:0xA1/0x93
+
+# Hummerhorn
+R:289:0xBA/0x8F
+
+# Lizard man
+R:290:0xB9/0x90
+
+# Ulfast, Son of Ulfang
+R:291:0xAB/0x82
+
+# Crebain
+R:292:0xC4/0x94
+
+# Berserker
+R:293:0xA9/0x97
+
+# Quasit
+R:294:0xA0/0x95
+
+# Sphinx
+R:295:0xB9/0x91
+
+# Imp
+R:296:0xA0/0x96
+
+# Forest troll
+R:297:0xA3/0x89
+
+# Freezing sphere
+R:298:0xBA/0x91
+
+# Jumping fireball
+R:299:0xB9/0x92
+
+# Ball lightning
+R:300:0xBA/0x92
+
+# 2-headed hydra
+R:301:0xA2/0x93
+
+# Swamp thing
+R:302:0xB9/0x93
+
+# Water spirit
+R:303:0x9F/0x80
+
+# Giant red scorpion
+R:304:0xA3/0x83
+
+# Earth spirit
+R:305:0x9F/0x81
+
+# Fire spirit
+R:306:0x9F/0x82
+
+# Fire hound
+R:307:0xA4/0x96
+
+# Cold hound
+R:308:0xA4/0x97
+
+# Energy hound
+R:309:0xA4/0x98
+
+# Lesser Mimic
+R:310:0x9D/0x8E
+
+# Door mimic
+R:311:0x82/0x83
+
+# Blink dog
+R:312:0x9E/0x81
+
+# Uruk
+R:313:0xA9/0x99
+
+# Shagrat, the Orc Captain
+R:314:0xA9/0x9A
+
+# Gorbag, the Orc Captain
+R:315:0xA9/0x9B
+
+# Shambling mound
+R:316:0x9D/0x8C
+
+# Giant Venus Flytrap
+R:317:0xC4/0x95
+
+# Chaos beastman
+R:318:0xB9/0x95
+
+# Daemonette of Slaanesh
+R:319:0xB9/0x94
+
+# Giant bronze dragon fly
+R:320:0x9F/0x98
+
+# Stone giant
+R:321:0xA1/0x94
+
+# Giant black dragon fly
+R:322:0x9F/0x96
+
+# Stone golem
+R:323:0xA7/0x8B
+
+# Red mold
+R:324:0xA9/0x85
+
+# Giant gold dragon fly
+R:325:0x9F/0x97
+
+# Stunwall
+R:326:0x80/0x93
+
+# Ghast
+R:327:0xBA/0x95
+
+# Neekerbreeker
+R:328:0xC4/0x96
+
+# Huorn
+R:329:0xBA/0x96
+
+# Bolg, Son of Azog
+R:330:0xA9/0x9C
+
+# Phase spider
+R:331:0xA3/0x84
+
+# Lizard king
+R:332:0xB9/0x97
+
+# Landmine
+R:333:0xBA/0x97
+
+# Wyvern
+R:334:0xB1/0x83
+
+# Great eagle
+R:335:0xB9/0x98
+
+# Livingstone
+R:336:0xB1/0x84
+
+# Earth hound
+R:337:0xA4/0x99
+
+# Air hound
+R:338:0xA4/0x9A
+
+# Sabre-tooth tiger
+R:339:0xA7/0x86
+
+# Acid hound
+R:340:0xA4/0x9B
+
+# Chimaera
+R:341:0xA0/0x8C
+
+# Quylthulg
+R:342:0xA1/0x9A
+
+# Sasquatch
+R:343:0xA4/0x92
+
+# Weir
+R:344:0xB1/0x85
+
+# Ranger
+R:345:0xAA/0x97
+
+# Paladin
+R:346:0xAB/0x92
+
+# Werewolf
+R:347:0xBA/0x99
+
+# Dark elven lord
+R:348:0xA7/0x9C
+
+# Cloud giant
+R:349:0xA1/0x96
+
+# Ugluk, the Uruk
+R:350:0xA9/0x9D
+
+# Blue dragon bat
+R:351:0xA5/0x91
+
+# Mimic
+R:352:0x83/0x9D
+
+# Ultimate Mimic
+R:353:0x84/0x9E
+
+# Fire vortex
+R:354:0xAC/0x94
+
+# Acid vortex
+R:355:0xAC/0x95
+
+# Lugdush, the Uruk
+R:356:0xB9/0x9A
+
+# Arch-vile
+R:357:0xBA/0x9A
+
+# Cold vortex
+R:358:0xAC/0x96
+
+# Energy vortex
+R:359:0xAC/0x97
+
+# Globefish
+R:360:0xB9/0x9B
+
+# Giant firefly
+R:361:0x9F/0x95
+
+# Mummified orc
+R:362:0xA1/0x88
+
+# Wolf chieftain
+R:363:0xC4/0x97
+
+# Serpent man
+R:364:0xBA/0x9C
+
+# Vampiric mist
+R:365:0xB9/0x9D
+
+# Killer stag beetle
+R:366:0xA0/0x9D
+
+# Iron golem
+R:367:0xA7/0x8C
+
+# Auto-roller
+R:368:0xB1/0x86
+
+# Giant yellow scorpion
+R:369:0xA3/0x85
+
+# Jade monk
+R:370:0xBA/0x9D
+
+# Black ooze
+R:371:0xA8/0x96
+
+# Hardened warrior
+R:372:0xAB/0x83
+
+# Azog, King of the Uruk-Hai
+R:373:0xA9/0x9F
+
+# Fleshhound of Khorne
+R:374:0xB9/0x9E
+
+# Dark elven warlock
+R:375:0xB1/0x87
+
+# Master rogue
+R:376:0xAB/0x84
+
+# Red dragon bat
+R:377:0xA5/0x92
+
+# Killer white beetle
+R:378:0xBA/0x9E
+
+# Ice skeleton
+R:379:0xB9/0x9F
+
+# Angamaite of Umbar
+R:380:0xBB/0x80
+
+# Forest wight
+R:381:0xB1/0x88
+
+# Khim, Son of Mim
+R:382:0xB1/0x89
+
+# Ibun, Son of Mim
+R:383:0xB1/0x8A
+
+# Meneldor the Swift
+R:384:0xBB/0x81
+
+# Phantom beast
+R:385:0xB1/0x8B
+
+# Giant silver ant
+R:386:0xA0/0x9C
+
+# 4-headed hydra
+R:387:0xA2/0x95
+
+# Lesser hell-beast
+R:388:0xBB/0x83
+
+# Tyrannosaur
+R:389:0xB1/0x8C
+
+# Mummified human
+R:390:0xA1/0x89
+
+# Vampire bat
+R:391:0xA5/0x93
+
+# Sangahyando of Umbar
+R:392:0xAB/0x85
+
+# It
+R:393:0xB1/0x8D
+
+# Banshee
+R:394:0x9F/0x9D
+
+# Carrion crawler
+R:395:0xA5/0x9B
+
+# Xiclotlan
+R:396:0xBB/0x84
+
+# Silent watcher
+R:397:0xB1/0x8E
+
+# Pukelman
+R:398:0xA7/0x8D
+
+# Disenchanter beast
+R:399:0xBA/0x9F
+
+# Dark elven druid
+R:400:0xA7/0x9F
+
+# Stone troll
+R:401:0xA3/0x8A
+
+# Black
+R:402:0xB0/0x8D
+
+# Hill troll
+R:403:0xA3/0x8B
+
+# Wereworm
+R:404:0xAD/0x84
+
+# Killer red beetle
+R:405:0xA0/0x9F
+
+# Disenchanter bat
+R:406:0xC4/0x98
+
+# Gnoph-Keh
+R:407:0xBB/0x86
+
+# Giant grey ant
+R:408:0xA5/0x8C
+
+# Khufu, the Mummified King
+R:409:0xB1/0x8F
+
+# Gwaihir the Windlord
+R:410:0xBB/0x81
+
+# Giant fire tick
+R:411:0xBB/0x87
+
+# Displacer beast
+R:412:0xA7/0x87
+
+# Ulwarth, Son of Ulfang
+R:413:0xAA/0x99
+
+# Werebear
+R:414:0xC4/0x8F
+
+# Cave ogre
+R:415:0xA1/0x8D
+
+# White wraith
+R:416:0xA3/0x9F
+
+# Angel
+R:417:0x9D/0x8F
+
+# Ghoul
+R:418:0xB4/0x8F
+
+# Mim, Betrayer of Turin
+R:419:0xB1/0x90
+
+# Hellblade
+R:420:0xB1/0x91
+
+# Killer fire beetle
+R:421:0xA1/0x80
+
+# Beast of Nurgle
+R:422:0xBB/0x88
+
+# Creeping adamantite coins
+R:423:0x9D/0x84
+
+# Algroth
+R:424:0xA3/0x8C
+
+# Flamer of Tzeentch
+R:425:0xB8/0x9F
+
+# Roper
+R:426:0xB9/0x80
+
+# Headless
+R:427:0xB1/0x92
+
+# Vibration hound
+R:428:0xA4/0x9C
+
+# Nexus hound
+R:429:0xA4/0x9D
+
+# Half-ogre
+R:430:0xA1/0x8E
+
+# Lokkak, the Ogre Chieftain
+R:431:0xA1/0x90
+
+# Vampire
+R:432:0xA3/0x9A
+
+# Gorgimaera
+R:433:0xA0/0x8D
+
+# Shantak
+R:434:0xB1/0x93
+
+# Colbran
+R:435:0xA7/0x8E
+
+# Spirit naga
+R:436:0xA9/0x8C
+
+# Corpser
+R:437:0xB9/0x81
+
+# Fiend of Slaanesh
+R:438:0xA2/0x97
+
+# Stairway to Hell
+R:439:0xB1/0x94
+
+# 5-headed hydra
+R:440:0xA2/0x96
+
+# Barney the Dinosaur
+R:441:0xB1/0x95
+
+# Black knight
+R:442:0xAB/0x88
+
+# Seahorse
+R:443:0xBB/0x89
+
+# Cyclops
+R:444:0xBB/0x8A
+
+# Clairvoyant
+R:445:0xAB/0x86
+
+# Purple worm
+R:446:0xB9/0x82
+
+# Catoblepas
+R:447:0xAC/0x81
+
+# Lesser wall monster
+R:448:0xB1/0x96
+
+# Mage
+R:449:0xAB/0x8A
+
+# Mind flayer
+R:450:0xAB/0x8B
+
+# The Ultimate Dungeon Cleaner
+R:451:0xB1/0x97
+
+# Deep one
+R:452:0xA4/0x86
+
+# Basilisk
+R:453:0xA2/0x97
+
+# Ice troll
+R:454:0xA3/0x8D
+
+# Dhole
+R:455:0xB1/0x99
+
+# Archangel
+R:456:0x9D/0x90
+
+# Greater Mimic
+R:457:0xAD/0x9E
+
+# Chaos tile
+R:458:0xB1/0x9A
+
+# Young blue dragon
+R:459:0xA6/0x84
+
+# Young white dragon
+R:460:0xA6/0x85
+
+# Young green dragon
+R:461:0xA6/0x86
+
+# Young bronze dragon
+R:462:0xA6/0x87
+
+# Aklash
+R:463:0xC1/0x9E
+
+# Mithril golem
+R:464:0xA7/0x8F
+
+# Skeleton troll
+R:465:0xAC/0x8D
+
+# Skeletal tyrannosaur
+R:466:0xBB/0x8B
+
+# Beorn, the Shape-Changer
+R:467:0xC4/0x99
+
+# Thorondor, Lord of Eagles
+R:468:0xBB/0x81
+
+# Giant blue ant
+R:469:0xA5/0x8B
+
+# Grave wight
+R:470:0xAD/0x9C
+
+# Shadow drake
+R:471:0xA6/0x88
+
+# Manticore
+R:472:0xA0/0x8E
+
+# Giant army ant
+R:473:0xAE/0x81
+
+# Killer slicer beetle
+R:474:0xA1/0x81
+
+# Gorgon
+R:475:0xBB/0x8D
+
+# Gug
+R:476:0xBB/0x8E
+
+# Ghost
+R:477:0x9F/0x9E
+
+# Death watch beetle
+R:478:0xA1/0x82
+
+# Mountain ogre
+R:479:0xA1/0x8F
+
+# Nexus quylthulg
+R:480:0xA1/0x9B
+
+# Shelob, Spider of Darkness
+R:481:0xA3/0x86
+
+# Giant squid
+R:482:0xB9/0x83
+
+# Ghoulking
+R:483:0xAD/0x8C
+
+# Doombat
+R:484:0xB9/0x84
+
+# Ninja
+R:485:0xAB/0x8C
+
+# Memory moss
+R:486:0xA9/0x86
+
+# Storm giant
+R:487:0xA1/0x95
+
+# Spectator
+R:488:0xB1/0x9B
+
+# Bokrug
+R:489:0xBB/0x8F
+
+# Biclops
+R:490:0xBB/0x90
+
+# Half-troll
+R:491:0xA9/0x9E
+
+# Ivory monk
+R:492:0xAA/0x93
+
+# Bert the Stone Troll
+R:493:0xA3/0x90
+
+# Bill the Stone Troll
+R:494:0xA3/0x91
+
+# Tom the Stone Troll
+R:495:0xA3/0x92
+
+# Cave troll
+R:496:0xA3/0x8E
+
+# Anti-paladin
+R:497:0xB1/0x9C
+
+# Chaos master
+R:498:0xB1/0x9D
+
+# Barrow wight
+R:499:0xA4/0x81
+
+# Skeleton ettin
+R:500:0xC4/0x9A
+
+# Chaos drake
+R:501:0xA6/0x89
+
+# Law drake
+R:502:0xA6/0x8A
+
+# Balance drake
+R:503:0xA6/0x8B
+
+# Ethereal drake
+R:504:0xA6/0x8C
+
+# Groo, the Wanderer
+R:505:0xB1/0x9E
+
+# Fasolt the Giant
+R:506:0xB1/0x9F
+
+# Shade
+R:507:0xA4/0x89
+
+# Spectre
+R:508:0xA0/0x80
+
+# Water troll
+R:509:0xA3/0x93
+
+# Fire elemental
+R:510:0x9F/0x83
+
+# Cherub
+R:511:0x9D/0x91
+
+# Water elemental
+R:512:0x9F/0x84
+
+# Multi-hued hound
+R:513:0xB2/0x81
+
+# Invisible stalker
+R:514:0x9F/0x85
+
+# Carrion crawler
+R:515:0xA5/0x9C
+
+# Master thief
+R:516:0xAB/0x8E
+
+# The Watcher in the Water
+R:517:0xAF/0x95
+
+# Lich
+R:518:0xA1/0x83
+
+# Gas spore
+R:519:0xB2/0x8E
+
+# Master vampire
+R:520:0xA3/0x9B
+
+# Oriental vampire
+R:521:0xB2/0x83
+
+# Greater mummy
+R:522:0xA1/0x8A
+
+# Bloodletter of Khorne
+R:523:0xA0/0x98
+
+# Giant grey scorpion
+R:524:0xA3/0x87
+
+# Earth elemental
+R:525:0x9F/0x86
+
+# Air elemental
+R:526:0x9F/0x87
+
+# Shimmering mold
+R:527:0xAF/0x81
+
+# Gargoyle
+R:528:0xBB/0x91
+
+# Malicious leprechaun
+R:529:0xB2/0x85
+
+# Eog golem
+R:530:0xA7/0x90
+
+# Little Boy
+R:531:0xB9/0x85
+
+# Dagashi
+R:532:0xAB/0x90
+
+# Headless ghost
+R:533:0xBB/0x92
+
+# Dread
+R:534:0xB9/0x87
+
+# Leng spider
+R:535:0xBB/0x93
+
+# Gauth
+R:536:0xC4/0x9B
+
+# Smoke elemental
+R:537:0x9F/0x90
+
+# Olog
+R:538:0xA3/0x94
+
+# Halfling slinger
+R:539:0xB2/0x86
+
+# Gravity hound
+R:540:0xA4/0x9E
+
+# Acidic cytoplasm
+R:541:0xA8/0x97
+
+# Inertia hound
+R:542:0xA4/0x9F
+
+# Impact hound
+R:543:0xA5/0x80
+
+# Shardstorm
+R:544:0xC4/0x9C
+
+# Ooze elemental
+R:545:0x9F/0x88
+
+# Young black dragon
+R:546:0xA6/0x8D
+
+# Mumak
+R:547:0xAC/0x84
+
+# Giant fire ant
+R:548:0xA5/0x8A
+
+# Mature white dragon
+R:549:0xA6/0x8E
+
+# Xorn
+R:550:0xA4/0x8F
+
+# Rogrog the Black Troll
+R:551:0xA3/0x8F
+
+# Mist giant
+R:552:0xA7/0x91
+
+# Phantom
+R:553:0xB2/0x87
+
+# Grey wraith
+R:554:0xA4/0x82
+
+# Revenant
+R:555:0xA4/0x88
+
+# Young multi-hued dragon
+R:556:0xA6/0x8F
+
+# Raal's Tome of Destruction
+R:557:0xB2/0x88
+
+# Colossus
+R:558:0xB2/0x89
+
+# Young gold dragon
+R:559:0xA6/0x90
+
+# Mature blue dragon
+R:560:0xA6/0x91
+
+# Mature green dragon
+R:561:0xA6/0x92
+
+# Mature bronze dragon
+R:562:0xA6/0x93
+
+# Young red dragon
+R:563:0xA6/0x94
+
+# Nightblade
+R:564:0xB2/0x8A
+
+# Trapper
+R:565:0xAD/0x9F
+
+# Bodak
+R:566:0xA0/0x98
+
+# Time bomb
+R:567:0xBB/0x96
+
+# Mezzodaemon
+R:568:0xAD/0x90
+
+# Elder thing
+R:569:0xB2/0x8B
+
+# Ice elemental
+R:570:0x9F/0x8A
+
+# Necromancer
+R:571:0xB2/0x8C
+
+# The Greater hell magic mushroom were-quylthulg
+R:572:0xB9/0x86
+
+# Lorgan, Chief of the Easterlings
+R:573:0xB2/0x8D
+
+# Chaos spawn
+R:574:0xB2/0x8E
+
+# Mummified troll
+R:575:0xBB/0x97
+
+# Storm of Unmagic
+R:576:0xC4/0x9D
+
+# Crypt thing
+R:577:0xA4/0x80
+
+# Chaos butterfly
+R:578:0xBB/0x98
+
+# Time elemental
+R:579:0xB2/0x8F
+
+# Flying polyp
+R:580:0xBB/0x99
+
+# The Queen Ant
+R:581:0xA5/0x8E
+
+# Will o' the wisp
+R:582:0x9F/0x8B
+
+# Shan
+R:583:0xBB/0x9A
+
+# Magma elemental
+R:584:0x9F/0x8C
+
+# Black pudding
+R:585:0xA8/0x98
+
+# Killer iridescent beetle
+R:586:0xB4/0x90
+
+# Nexus vortex
+R:587:0xAE/0x80
+
+# Plasma vortex
+R:588:0xAC/0x98
+
+# Mature red dragon
+R:589:0xA6/0x95
+
+# Mature gold dragon
+R:590:0xA6/0x96
+
+# Crystal drake
+R:591:0xA6/0x97
+
+# Mature black dragon
+R:592:0xA6/0x98
+
+# Mature multi-hued dragon
+R:593:0xA6/0x99
+
+# Sky whale
+R:594:0xBB/0x9B
+
+# Draebor, the Imp
+R:595:0xC1/0x9F
+
+# Mother Hydra
+R:596:0xA2/0x98
+
+# Death knight
+R:597:0xAB/0x94
+
+# Castamir the Usurper
+R:598:0xB2/0x90
+
+# Time vortex
+R:599:0xAC/0x99
+
+# Shimmering vortex
+R:600:0xAC/0x9A
+
+# Ancient blue dragon
+R:601:0x9E/0x88
+
+# Ancient bronze dragon
+R:602:0x9E/0x89
+
+# Beholder
+R:603:0xA6/0x9F
+
+# Emperor wight
+R:604:0xA4/0x83
+
+# Seraph
+R:605:0x9D/0x92
+
+# Vargo, Tyrant of Fire
+R:606:0x9F/0x8D
+
+# Black wraith
+R:607:0xA4/0x84
+
+# Nightgaunt
+R:608:0xB2/0x91
+
+# Baron of hell
+R:609:0xB2/0x92
+
+# Scylla
+R:610:0xBB/0x9C
+
+# Monastic lich
+R:611:0xA1/0x87
+
+# Nether wraith
+R:612:0xA4/0x85
+
+# Hellhound
+R:613:0xAD/0x96
+
+# 7-headed hydra
+R:614:0xA2/0x99
+
+# Waldern, King of Water
+R:615:0x9F/0x8E
+
+# Kavlax the Many-Headed
+R:616:0xA6/0x9A
+
+# Ancient white dragon
+R:617:0x9E/0x8A
+
+# Ancient green dragon
+R:618:0x9E/0x8B
+
+# Chthonian
+R:619:0xB2/0x93
+
+# Eldrak
+R:620:0xA3/0x97
+
+# Ettin
+R:621:0xA3/0x96
+
+# Night mare
+R:622:0xAC/0x83
+
+# Vampire lord
+R:623:0xA3/0x9C
+
+# Ancient black dragon
+R:624:0x9E/0x8C
+
+# Weird fume
+R:625:0xAF/0x80
+
+# Spawn of Ubbo-Sathla
+R:626:0xBB/0x9D
+
+# Fat Man
+R:627:0xB9/0x85
+
+# Malekith the Accursed
+R:628:0xA7/0x95
+
+# Shadowfax, steed of Gandalf
+R:629:0xBB/0x9E
+
+# Spirit troll
+R:630:0xA3/0x98
+
+# War troll
+R:631:0xB2/0x94
+
+# Disenchanter worm mass
+R:632:0xAD/0x86
+
+# Rotting quylthulg
+R:633:0xA1/0x9C
+
+# Lesser titan
+R:634:0xA1/0x97
+
+# 9-headed hydra
+R:635:0xA2/0x99
+
+# Enchantress
+R:636:0xAB/0x96
+
+# Ranger chieftain
+R:637:0xAB/0x97
+
+# Sorcerer
+R:638:0xAB/0x98
+
+# Xaren
+R:639:0xA4/0x90
+
+# Giant roc
+R:640:0x9D/0x97
+
+# Minotaur
+R:641:0xA0/0x8F
+
+# Medusa, the Gorgon
+R:642:0xA9/0x8D
+
+# Death drake
+R:643:0x9E/0x8D
+
+# Ancient red dragon
+R:644:0x9E/0x8E
+
+# Ancient gold dragon
+R:645:0x9E/0x8F
+
+# Great crystal drake
+R:646:0x9E/0x90
+
+# Wyrd sister
+R:647:0xA7/0x9D
+
+# Vrock
+R:648:0xB2/0x95
+
+# Death quasit
+R:649:0xA0/0x99
+
+# Giganto, the Gargantuan
+R:650:0xBB/0x9F
+
+# Strygalldwir
+R:651:0xB2/0x96
+
+# Fallen angel
+R:652:0xAA/0x8E
+
+# Giant headless
+R:653:0xBC/0x80
+
+# Judge Fire
+R:654:0xAB/0x93
+
+# Ubbo-Sathla, the Unbegotten Source
+R:655:0xBC/0x81
+
+# Judge Mortis
+R:656:0xBC/0x82
+
+# Dark elven sorcerer
+R:657:0xA8/0x81
+
+# Master lich
+R:658:0xA1/0x84
+
+# Byakhee
+R:659:0xB2/0x97
+
+# Eol, the Dark Elf
+R:660:0xB2/0x99
+
+# Archon
+R:661:0x9D/0x93
+
+# Formless spawn of Tsathoggua
+R:662:0xB2/0x9A
+
+# Hunting horror
+R:663:0xB2/0x9B
+
+# Undead beholder
+R:664:0xA7/0x80
+
+# Shadow
+R:665:0xA0/0x81
+
+# Iron lich
+R:666:0xB2/0x9C
+
+# Dread
+R:667:0xB9/0x87
+
+# Greater basilisk
+R:668:0xBC/0x83
+
+# Charybdis
+R:669:0xBC/0x84
+
+# Jack of Shadows
+R:670:0xAB/0x9C
+
+# Zephyr Lord
+R:671:0xAB/0x91
+
+# Juggernaut of Khorne
+R:672:0xBC/0x85
+
+# Mumak
+R:673:0xAC/0x82
+
+# Judge Fear
+R:674:0xA7/0x88
+
+# Ancient multi-hued dragon
+R:675:0x9E/0x91
+
+# Ethereal dragon
+R:676:0x9E/0x92
+
+# Dark young of Shub-Niggurath
+R:677:0xB2/0x9D
+
+# Colour out of space
+R:678:0x91/0x99
+
+# Quaker, Master of Earth
+R:679:0x9F/0x8F
+
+# Death leprechaun
+R:680:0xA7/0x9E
+
+# Chaugnar Faugn, Horror from the Hills
+R:681:0xBC/0x94
+
+# Lloigor
+R:682:0xBC/0x95
+
+# Utgard-Loke
+R:683:0xBC/0x96
+
+# Quachil Uttaus, Treader of the Dust
+R:684:0xBC/0x97
+
+# Shoggoth
+R:685:0xBC/0x98
+
+# Judge Death
+R:686:0xBC/0x99
+
+# Ariel, Queen of Air
+R:687:0x9F/0x91
+
+# 11-headed hydra
+R:688:0xA2/0x9A
+
+# Patriarch
+R:689:0xAB/0x9A
+
+# Dreadmaster
+R:690:0xA0/0x85
+
+# Drolem
+R:691:0xA7/0x92
+
+# Scatha the Worm
+R:692:0xAD/0x9B
+
+# Warrior of the Dawn
+R:693:0xB2/0x9E
+
+# Lesser black reaver
+R:694:0xA4/0x87
+
+# Zoth-Ommog
+R:695:0xBE/0x89
+
+# Grand master thief
+R:696:0xC2/0x8A
+
+# Smaug the Golden
+R:697:0x9E/0x93
+
+# The Stormbringer
+R:698:0xB3/0x80
+
+# Knight Templar
+R:699:0xB3/0x81
+
+# Leprechaun fanatic
+R:700:0xA8/0x80
+
+# Dracolich
+R:701:0x9E/0x95
+
+# Greater titan
+R:702:0xA1/0x98
+
+# Dracolisk
+R:703:0x9E/0x94
+
+# Winged Horror
+R:704:0xC4/0x9E
+
+# Spectral tyrannosaur
+R:705:0xB3/0x82
+
+# Yibb-Tstll, the Patient One
+R:706:0xBC/0x9B
+
+# Ghatanothoa
+R:707:0xBC/0x9C
+
+# Ent
+R:708:0xBC/0x86
+
+# Hru
+R:709:0xBC/0x9D
+
+# Itangast the Fire Drake
+R:710:0x9E/0x96
+
+# Death mold
+R:711:0xA9/0x87
+
+# Fafner the Dragon
+R:712:0xB3/0x83
+
+# Charon, Boatman of the Styx
+R:713:0xBC/0x9E
+
+# Quickbeam, the Ent
+R:714:0xBC/0x9F
+
+# Glaurung, Father of the Dragons
+R:715:0xAD/0x9A
+
+# Behemoth
+R:716:0xBD/0x80
+
+# Garm, Guardian of Hel
+R:717:0x9E/0x84
+
+# Greater wall monster
+R:718:0xB3/0x84
+
+# Nycadaemon
+R:719:0xAD/0x91
+
+# Barbazu
+R:720:0xAD/0x95
+
+# Goat of Mendes
+R:721:0xB3/0x85
+
+# Nightwing
+R:722:0xAD/0x9D
+
+# Maulotaur
+R:723:0xB3/0x86
+
+# Nether hound
+R:724:0xA5/0x81
+
+# Time hound
+R:725:0xA5/0x82
+
+# Plasma hound
+R:726:0xA5/0x83
+
+# Demonic quylthulg
+R:727:0xA1/0x9D
+
+# Great Storm Wyrm
+R:728:0x9E/0x97
+
+# Ulik the Troll
+R:729:0xBD/0x81
+
+# Baphomet the Minotaur Lord
+R:730:0xA0/0x90
+
+# Hell knight
+R:731:0xBD/0x82
+
+# Bull Gates
+R:732:0xB3/0x87
+
+# Santa Claus
+R:733:0xB3/0x88
+
+# Eihort, the Thing in the Labyrinth
+R:734:0xBE/0x8A
+
+# The King in Yellow
+R:735:0xBE/0x8B
+
+# Great unclean one
+R:736:0xBE/0x8C
+
+# Lord of Chaos
+R:737:0xB3/0x89
+
+# Old Sorcerer
+R:738:0x9C/0x8A
+
+# Ethereal hound
+R:739:0xB3/0x8A
+
+# Lesser kraken
+R:740:0xBD/0x83
+
+# Great Ice Wyrm
+R:741:0x9E/0x98
+
+# Demilich
+R:742:0xA4/0x8A
+
+# The Phoenix
+R:743:0x9D/0x98
+
+# Nightcrawler
+R:744:0xA4/0x8C
+
+# Lord of Change
+R:745:0xBC/0x87
+
+# Keeper of Secrets
+R:746:0xBE/0x8D
+
+# Shudde M'ell
+R:747:0xBE/0x8E
+
+# Hand druj
+R:748:0xAC/0x8E
+
+# Eye druj
+R:749:0xAC/0x8F
+
+# Skull druj
+R:750:0xAC/0x90
+
+# Chaos vortex
+R:751:0xAC/0x9B
+
+# Aether vortex
+R:752:0xAC/0x9C
+
+# Nidhogg, the Hel-Drake
+R:753:0xBE/0x8F
+
+# The Lernaean Hydra
+R:754:0xA2/0x9B
+
+# Thuringwethil, the Vampire Messenger
+R:755:0xA3/0x9D
+
+# Great Hell Wyrm
+R:756:0x9E/0x99
+
+# Hastur the Unspeakable
+R:757:0xB3/0x8B
+
+# Bloodthirster
+R:758:0xBD/0x84
+
+# Draconic quylthulg
+R:759:0xA1/0x9E
+
+# Nyogtha, the Thing that Should not Be
+R:760:0xB3/0x8C
+
+# Ahtu, Avatar of Nyarlathotep
+R:761:0xBE/0x90
+
+# Fundin Bluecloak
+R:762:0xBE/0x91
+
+# Bile Demon
+R:763:0xC5/0x80
+
+# Uriel, Angel of Fire
+R:764:0x9D/0x94
+
+# Azriel, Angel of Death
+R:765:0x9D/0x95
+
+# Ancalagon the Black
+R:766:0x9E/0x9A
+
+# Daoloth, the Render of the Veils
+R:767:0xBE/0x92
+
+# Nightwalker
+R:768:0xBD/0x85
+
+# Gabriel, the Messenger
+R:769:0x9D/0x96
+
+# Artsi, the Champion of Chaos
+R:770:0xBE/0x93
+
+# Saruman of Many Colours
+R:771:0xAB/0x9E
+
+# Harowen the Black Hand
+R:772:0xBE/0x94
+
+# Osyluth
+R:773:0xC5/0x81
+
+# Dreadlord
+R:774:0xA0/0x86
+
+# Greater kraken
+R:775:0xBD/0x86
+
+# Archlich
+R:776:0xA4/0x8D
+
+# The Cat Lord
+R:777:0xB3/0x8F
+
+# Jabberwock
+R:778:0xC5/0x82
+
+# Chaos hound
+R:779:0xA5/0x85
+
+# Vlad Dracula, Prince of Darkness
+R:780:0xBE/0x95
+
+# Beholder hive-mother
+R:781:0xBE/0x96
+
+# Leviathan
+R:782:0xBD/0x87
+
+# Great Wyrm of Chaos
+R:783:0x9E/0x9B
+
+# Great Wyrm of Law
+R:784:0x9E/0x9C
+
+# Great Wyrm of Balance
+R:785:0x9E/0x9D
+
+# Shambler
+R:786:0xB3/0x91
+
+# Gelugon
+R:787:0xC5/0x83
+
+# Glaaki
+R:788:0xB9/0x88
+
+# T'ron, the Rebel Dragonrider
+R:789:0xB3/0x92
+
+# Great Wyrm of Many Colours
+R:790:0xB3/0x93
+
+# Mardra, rider of the Gold Loranth
+R:791:0xB3/0x94
+
+# Tselakus, the Dreadlord
+R:792:0xA0/0x87
+
+# Sky Drake
+R:793:0xB3/0x95
+
+# Eilinel the Entrapped
+R:794:0xA0/0x83
+
+# Horned Reaper
+R:795:0xC5/0x84
+
+# The Norsa
+R:796:0xB3/0x97
+
+# Rhan-Tegoth
+R:797:0xBE/0x99
+
+# Black reaver
+R:798:0xA1/0x85
+
+# Master mindcrafter
+R:799:0xAB/0x9F
+
+# Greater demonic quylthulg
+R:800:0xA1/0x9F
+
+# Greater draconic quylthulg
+R:801:0xA2/0x80
+
+# Greater rotting quylthulg
+R:802:0xA2/0x81
+
+# Null, the Living Void
+R:803:0xBC/0x88
+
+# Feagwath, the Undead Sorcerer
+R:804:0xA1/0x86
+
+# Omarax the Eye Tyrant
+R:805:0xA7/0x81
+
+# Tsathoggua, the Sleeper of N'kai
+R:806:0xBE/0x9A
+
+# Greater Balrog
+R:807:0xAD/0x93
+
+# Ungoliant, the Unlight
+R:808:0xA3/0x88
+
+# Atlach-Nacha, the Spider God
+R:809:0xB3/0x9A
+
+# Y'golonac
+R:810:0xBE/0x9B
+
+# Aether hound
+R:811:0xA5/0x86
+
+# Pit Fiend
+R:812:0xAD/0x92
+
+# The Serpent of Chaos
+R:813:0xB4/0x8D
+
+# Yig, Father of Serpents
+R:814:0xBE/0x9C
+
+# Unmaker
+R:815:0xB3/0x9C
+
+# Cyberdemon
+R:816:0xB3/0x9D
+
+# Hela, Queen of the Dead
+R:817:0xBE/0x9D
+
+# The Mouth of Sauron
+R:818:0xBE/0x9E
+
+# The Necromancer of Dol Guldur
+R:819:0xB3/0x9E
+
+# Lessa, rider of the Gold Ramoth
+R:820:0xB3/0x9F
+
+# Master quylthulg
+R:821:0xA2/0x82
+
+# Qlzqqlzuup, the Lord of Flesh
+R:822:0xA2/0x83
+
+# Cthugha, the Living Flame
+R:823:0xBE/0x9F
+
+# F'lar, rider of the Bronze Mnementh
+R:824:0xB4/0x80
+
+# Maeglin, the Traitor of Gondolin
+R:825:0xA4/0x8E
+
+# Cyaegha
+R:826:0xBF/0x80
+
+# Pazuzu, Lord of Air
+R:827:0xBF/0x81
+
+# Ithaqua the Windwalker
+R:828:0xB4/0x81
+
+# Greater Hellhound
+R:829:0x9E/0x83
+
+# Cantoras, the Skeletal Lord
+R:830:0xAC/0x91
+
+# Mephistopheles, Lord of Hell
+R:831:0xB4/0x82
+
+# Godzilla
+R:832:0xB4/0x83
+
+# Abhoth, Source of Uncleanness
+R:833:0xBF/0x82
+
+# Ymir, the Ice Giant
+R:834:0xBF/0x83
+
+# Loki, the Trickster
+R:835:0xBF/0x84
+
+# Star-spawn of Cthulhu
+R:836:0xB4/0x84
+
+# Surtur, the Fire Giant
+R:837:0xBF/0x85
+
+# The Tarrasque
+R:838:0xBC/0x93
+
+# Lungorthin, the Balrog of White Fire
+R:839:0xBF/0x86
+
+# Draugluin, Sire of All Werewolves
+R:840:0xBF/0x87
+
+# Shuma-Gorath
+R:841:0xBF/0x88
+
+# Tulzscha, the Green Flame
+R:842:0xBC/0x92
+
+# Oremorj, the Cyberdemon Lord
+R:843:0xBC/0x91
+
+# Vecna, the Emperor Lich
+R:844:0xB4/0x85
+
+# Yog-Sothoth, the All-in-One
+R:845:0xB4/0x86
+
+# Fenris Wolf
+R:846:0xBC/0x90
+
+# Great Wyrm of Power
+R:847:0xB4/0x87
+
+# Shub-Niggurath, Black Goat of the Woods
+R:848:0xB4/0x88
+
+# Nodens, Lord of the Great Abyss
+R:849:0xAB/0x8D
+
+# Carcharoth, the Jaws of Thirst
+R:850:0x9E/0x86
+
+# Nyarlathotep, the Crawling Chaos
+R:851:0xB4/0x89
+
+# Azathoth, the Daemon Sultan
+R:852:0xB4/0x8A
+
+# Huan, Wolfhound of the Valar
+R:853:0x9E/0x87
+
+# Jormungand the Midgard Serpent
+R:854:0xBC/0x8F
+
+# The Destroyer
+R:855:0xBC/0x8E
+
+# Gothmog, the High Captain of Balrogs
+R:856:0xAD/0x98
+
+# Great Cthulhu
+R:857:0xB4/0x8B
+
+# Sorka, rider of the Gold Faranth
+R:858:0xB4/0x8C
+
+# The Unicorn of Order
+R:859:0xBC/0x8D
+
+# Sauron, the Sorcerer
+R:860:0xAC/0x80
+
+# DarkGod, the Mighty Coder of Hell
+R:861:0xC0/0x9D
+
+# Morgoth, Lord of Darkness
+R:862:0xB4/0x8E
+
+# Human Warrior
+R:863:0xB5/0x80
+
+# Elven archer
+R:864:0xB5/0x81
+
+# Dwarven warrior
+R:865:0xB5/0x82
+
+# Elite uruk
+R:866:0xB5/0x83
+
+# The Philosophy Teacher
+R:867:0xBC/0x8C
+
+# The Variant Maintainer
+R:868:0xBC/0x8B
+
+# Random Number Generator
+R:869:0xBC/0x8A
+
+# Rocket mine
+R:870:0xBD/0x88
+
+# Bouncing mine
+R:871:0xBD/0x89
+
+# Durin's Bane
+R:872:0xBF/0x89
+
+# The Icky Queen
+R:873:0xBF/0x8A
+
+# Rot jelly
+R:874:0xBD/0x8A
+
+# Death
+R:875:0xBD/0x8B
+
+# Famine
+R:876:0xBD/0x8D
+
+# Pestilence
+R:877:0xBD/0x8C
+
+# War
+R:878:0xBD/0x8E
+
+# Pike
+R:879:0xBD/0x8F
+
+# Electric eel
+R:880:0xBD/0x90
+
+# Giant crayfish
+R:881:0xBD/0x91
+
+# Mermaid
+R:882:0xBD/0x92
+
+# Box jellyfish
+R:883:0xBA/0x81
+
+# Giant piranha
+R:884:0xB6/0x9D
+
+# Piranha
+R:885:0xB6/0x9D
+
+# Bullywug
+R:886:0xBD/0x94
+
+# Bullywug warrior
+R:887:0xBD/0x95
+
+# Bullywug shaman
+R:888:0xBD/0x96
+
+# Whale
+R:889:0xBA/0x98
+
+# Sand mite
+R:890:0xBD/0x98
+
+# Octopus
+R:891:0xBD/0x99
+
+# Giant octopus
+R:892:0xBD/0x9A
+
+# Eye of the deep
+R:893:0xBD/0x9B
+
+# Murk dweller
+R:894:0xBF/0x8B
+
+# Drowned soul
+R:895:0xBF/0x8C
+
+# Tiger shark
+R:896:0xBF/0x8D
+
+# Hammerhead shark
+R:897:0xBA/0x90
+
+# Great white shark
+R:898:0xBB/0x82
+
+# Aquatic golem
+R:899:0xBF/0x8E
+
+# Aquatic kobold
+R:900:0xBF/0x8F
+
+# White shark
+R:901:0xBB/0x82
+
+# Scrag
+R:902:0xBF/0x91
+
+# Jaws
+R:903:0xBB/0x8C
+
+# Aquatic elf
+R:904:0xBF/0x93
+
+# Aquatic elven warrior
+R:905:0xBF/0x94
+
+# Aquatic elven shaman
+R:906:0xBF/0x95
+
+# Stargazer
+R:907:0xBF/0x96
+
+# Elder stargazer
+R:908:0xBF/0x97
+
+# Flounder
+R:909:0xBF/0x98
+
+# Giant turtle
+R:910:0xBF/0x99
+
+# Baby dragon turtle
+R:911:0xBF/0x9A
+
+# Young dragon turtle
+R:912:0xBF/0x9B
+
+# Mature dragon turtle
+R:913:0xBF/0x9C
+
+# Ancient dragon turtle
+R:914:0xBF/0x9D
+
+# Fastitocalon
+R:915:0xBF/0x9E
+
+# Undead stargazer
+R:916:0xBF/0x9F
+
+# Killer whale
+R:917:0xB9/0x9C
+
+# Merrow
+R:918:0xC5/0x85
+
+# Water naga
+R:919:0xC0/0x81
+
+# Devilfish
+R:920:0xC0/0x82
+
+# Undead devilfish
+R:921:0xC0/0x83
+
+# Moby Dick, the White Whale
+R:922:0xC0/0x80
+
+# Aquatic hound
+R:923:0xC0/0x85
+
+# Water demon
+R:924:0xC0/0x86
+
+# Ixitxachitl
+R:925:0xB8/0x9C
+
+# Ixitxachitl priest
+R:926:0xC0/0x88
+
+# Vampiric ixitxachitl
+R:927:0xC0/0x89
+
+# Mathilde, the Science Student
+R:928:0xBD/0x9C
+
+# Child spirit
+R:929:0xBD/0x9D
+
+# Young spirit
+R:930:0xBD/0x9E
+
+# Mature spirit
+R:931:0xBD/0x9F
+
+# Experienced spirit
+R:932:0xBE/0x80
+
+# Wise spirit
+R:933:0xBE/0x81
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0xC0/0x8A
+
+# Gandalf the Grey
+R:935:0xC0/0x8B
+
+# Nar, the Dwarf
+R:936:0xC0/0x8C
+
+# Novice mindcrafter
+R:937:0xAA/0x9A
+
+# Great Swamp Wyrm
+R:938:0xC5/0x86
+
+# Great Bile Wyrm
+R:939:0xC5/0x87
+
+# Blue Firelizard
+R:940:0xBE/0x82
+
+# Green Firelizard
+R:941:0xBE/0x83
+
+# Brown Firelizard
+R:942:0xBE/0x84
+
+# Bronze Firelizard
+R:943:0xBE/0x85
+
+# Gold Firelizard
+R:944:0xBE/0x86
+
+# High-elven ranger
+R:945:0xBE/0x87
+
+# Uvatha the Horseman
+R:946:0xC0/0x90
+
+# Adunaphel the Quiet
+R:947:0xC0/0x91
+
+# Akhorahil the Blind
+R:948:0xC0/0x92
+
+# Ren the Unclean
+R:949:0xC0/0x93
+
+# Ji Indur Dawndeath
+R:950:0xC0/0x94
+
+# Dwar, Dog Lord of Waw
+R:951:0xC0/0x95
+
+# Hoarmurath of Dir
+R:952:0xC0/0x96
+
+# Khamul, the Black Easterling
+R:953:0xC0/0x97
+
+# The Witch-King of Angmar
+R:954:0xC0/0x98
+
+# Green Dragonrider
+R:955:0xB3/0x96
+
+# Blue Dragonrider
+R:956:0xB3/0x8E
+
+# Brown Dragonrider
+R:957:0xB3/0x98
+
+# Bronze Dragonrider
+R:958:0xB3/0x98
+
+# Gold Dragonrider
+R:959:0xB3/0x94
+
+# Thread
+R:960:0xBE/0x88
+
+# Gorlim, Betrayer of Barahir
+R:961:0xC0/0x99
+
+# The Blubbering idiot, agent of black market, Simon the weak
+R:962:0xAA/0x82
+
+# Aranea
+R:963:0xC1/0x9A
+
+# Elder aranea
+R:964:0xC0/0x9A
+
+# Giant brown tick
+R:965:0xC5/0x88
+
+# Dolphiner
+R:966:0xC0/0x9C
+
+# Novice possessor (soul)
+R:967:0xC4/0x86
+
+# Bat of Gorgoroth
+R:968:0xC5/0x97
+
+# The Princess
+R:969:0xC5/0x98
+
+# Merton Proudfoot, the lost hobbit
+R:970:0xC5/0x99
+
+# The Wight-King of the Barrow-downs
+R:971:0xC5/0x9A
+
+# Adventurer
+R:972:0xC5/0x9B
+
+# Experienced possessor (soul)
+R:973:0xC5/0x9C
+
+# Old possessor (soul)
+R:974:0xC5/0x9D
+
+# Death orb
+R:975:0xC5/0x9E
+
+# Bronze dragon worm
+R:976:0xC6/0x80
+
+# Gold dragon worm
+R:977:0xC5/0x9F
+
+# Moldoux, the Defenceless Mold
+R:978:0xBC/0x89
+
+# The Physics Teacher
+R:979:0xBE/0x97
+
+# Ar-Pharazon the Golden
+R:980:0xC0/0x9E
+
+# Doppelganger
+R:981:0x97/0x8C
+
+# Marylene, Heartbreakeress of the Netherworld
+R:982:0xC1/0x8D
+
+# The Greater Lag Monster
+R:983:0xC2/0x8D
+
+# Hrungnir, the Stone Giant
+R:984:0xA7/0x8A
+
+# Bullroarer the Hobbit
+R:985:0xA7/0x9B
+
+# 3-headed hydra
+R:986:0xA2/0x94
+
+# Uldor the Accursed
+R:987:0xAB/0x95
+
+# Mystic
+R:988:0xAB/0x9B
+
+# Elder vampire
+R:989:0xA1/0x99
+
+# Ulfang the Black
+R:990:0xAA/0x96
+
+# Demonologist
+R:991:0xA8/0x82
+
+# Hezrou
+R:992:0xA2/0x9C
+
+# Glabrezu
+R:993:0xA2/0x8E
+
+# Nalfeshnee
+R:994:0xC2/0x8E
+
+# Marilith
+R:995:0xC2/0x8F
+
+# Lesser Balrog
+R:996:0xAD/0x95
+
+# Master mystic
+R:997:0xAA/0x94
+
+# Grand master mystic
+R:998:0xAB/0x9D
+
+# Erinyes
+R:999:0xA0/0x84
+
+# Novice mindcrafter
+R:1000:0xAA/0x9A
+
+# Polyphemus, the Blind Cyclops
+R:1001:0xC5/0x89
+
+# Great Wyrm of Perplexity
+R:1002:0xC2/0x92
+
+# Hound of Tindalos
+R:1003:0xC2/0x93
+
+# Great Wyrm of Thunder
+R:1004:0xC5/0x8A
+
+# Silver mouse
+R:1005:0xC5/0x8B
+
+# The Rat King
+R:1006:0xC2/0x96
+
+# Vort the Kobold Queen
+R:1007:0xC2/0x97
+
+# Giant black louse
+R:1008:0xC2/0x98
+
+# Fire Phantom
+R:1009:0xC2/0x99
+
+# The Insane Player
+R:1010:0x92/0x81
+
+# Glaryssa, Succubus Queen
+R:1011:0xC2/0x9A
+
+# Vermicious Knid
+R:1012:0xC2/0x9B
+
+# Bone golem
+R:1013:0xC2/0x9C
+
+# Snake of Yig
+R:1014:0xC2/0x9D
+
+# Bronze golem
+R:1015:0xC5/0x8C
+
+# Dimensional shambler
+R:1016:0xC2/0x9F
+
+# Cultist
+R:1017:0x94/0x99
+
+# Cult leader
+R:1018:0x99/0x97
+
+# Servitor of the outer gods
+R:1019:0xC3/0x8A
+
+# Avatar of Nyarlathotep
+R:1020:0xC3/0x8B
+
+# Thiazi, the Storm Giant
+R:1021:0xC5/0x8D
+
+# Hypnos, Lord of Sleep
+R:1022:0xC3/0x8D
+
+# Blue dragon worm
+R:1023:0xC3/0x8E
+
+# White dragon worm
+R:1024:0xC3/0x8F
+
+# Green dragon worm
+R:1025:0xC3/0x92
+
+# Black dragon worm
+R:1026:0xC3/0x91
+
+# Red dragon worm
+R:1027:0xC3/0x90
+
+# Multi-hued dragon worm
+R:1028:0xC3/0x93
+
+# The Minotaur of the Labyrinth
+R:1029:0xC3/0x94
+
+# The Sandworm Queen
+R:1030:0xC3/0x9B
+
+# Sandworm
+R:1031:0xC3/0x9C
+
+# Tik'srvzllat
+R:1032:0xC3/0x9D
+
+# The Glass Golem
+R:1033:0xC5/0x8E
+
+# The White Balrog
+R:1034:0xC5/0x8F
+
+# Golgarach, the Living Rock
+R:1035:0x80/0x84
+
+# Atlas, the Titan
+R:1036:0xC5/0x90
+
+# Kronos, Lord of the Titans
+R:1037:0xC5/0x91
+
+# Water hound
+R:1038:0xC6/0x88
+
+# Improv, the mighty MoLD
+R:1039:0xC6/0x8E
+
+# Emperor Mimic
+R:1040:0xC6/0x9C
+
+# Melinda Proudfoot
+R:1041:0x88/0xAA
+
+# Thrain, the King Under the Mountain
+R:1042:0x88/0xAB
+
+# Spells (*)
+S:48:0x91/0x88
+S:49:0x91/0x89
+S:50:0x91/0x8A
+S:51:0x91/0x8B
+S:52:0x91/0x8C
+S:53:0x91/0x8D
+S:54:0x91/0x8E
+S:55:0x91/0x8F
+S:56:0x91/0x90
+S:57:0x91/0x91
+S:58:0x91/0x92
+S:59:0x91/0x93
+S:60:0x91/0x94
+S:61:0x91/0x95
+S:62:0x91/0x96
+S:63:0x91/0x97
+
+# Spells (|)
+S:64:0x8F/0x80
+S:65:0x8F/0x84
+S:66:0x8F/0x88
+S:67:0x8F/0x8C
+S:68:0x8F/0x90
+S:69:0x8F/0x94
+S:70:0x8F/0x98
+S:71:0x8F/0x9C
+S:72:0x90/0x80
+S:73:0x90/0x84
+S:74:0x90/0x88
+S:75:0x90/0x8C
+S:76:0x90/0x90
+S:77:0x90/0x94
+S:78:0x90/0x98
+S:79:0x90/0x9C
+
+# Spells (-)
+S:80:0x8F/0x81
+S:81:0x8F/0x85
+S:82:0x8F/0x89
+S:83:0x8F/0x8D
+S:84:0x8F/0x91
+S:85:0x8F/0x95
+S:86:0x8F/0x99
+S:87:0x8F/0x9D
+S:88:0x90/0x81
+S:89:0x90/0x85
+S:90:0x90/0x89
+S:91:0x90/0x8D
+S:92:0x90/0x91
+S:93:0x90/0x95
+S:94:0x90/0x99
+S:95:0x90/0x9D
+
+# Spells (/)
+S:96:0x8F/0x82
+S:97:0x8F/0x86
+S:98:0x8F/0x8A
+S:99:0x8F/0x8E
+S:100:0x8F/0x92
+S:101:0x8F/0x96
+S:102:0x8F/0x9A
+S:103:0x8F/0x9E
+S:104:0x90/0x82
+S:105:0x90/0x86
+S:106:0x90/0x8A
+S:107:0x90/0x8E
+S:108:0x90/0x92
+S:109:0x90/0x96
+S:110:0x90/0x9A
+S:111:0x90/0x9E
+
+# Spells (\)
+S:112:0x8F/0x83
+S:113:0x8F/0x87
+S:114:0x8F/0x8B
+S:115:0x8F/0x8F
+S:116:0x8F/0x93
+S:117:0x8F/0x97
+S:118:0x8F/0x9B
+S:119:0x8F/0x9F
+S:120:0x90/0x83
+S:121:0x90/0x87
+S:122:0x90/0x8B
+S:123:0x90/0x8F
+S:124:0x90/0x93
+S:125:0x90/0x97
+S:126:0x90/0x9B
+S:127:0x90/0x9F
+
+# Amulets (")
+S:128:0x87/0x87
+S:129:0x87/0x80
+S:130:0x87/0x88
+S:131:0x87/0x82
+S:132:0x87/0x83
+S:133:0x87/0x84
+S:134:0x87/0x85
+S:135:0x87/0x86
+S:136:0x87/0x81
+S:137:0x87/0x81
+S:138:0x87/0x89
+S:139:0x87/0x8A
+S:140:0x87/0x8B
+S:141:0x87/0x8C
+S:142:0x87/0x8D
+S:143:0x87/0x8E
+
+# Rings (=)
+S:144:0x84/0x87
+S:145:0x84/0x80
+S:146:0x84/0x88
+S:147:0x84/0x82
+S:148:0x84/0x83
+S:149:0x84/0x84
+S:150:0x84/0x85
+S:151:0x84/0x86
+S:152:0x84/0x81
+S:153:0x84/0x81
+S:154:0x84/0x89
+S:155:0x84/0x8A
+S:156:0x84/0x8B
+S:157:0x84/0x8C
+S:158:0x84/0x8D
+S:159:0x84/0x8E
+
+# Staffs (_)
+S:160:0x87/0x96
+S:161:0x87/0x95
+S:162:0x87/0x95
+S:163:0x87/0x92
+S:164:0x87/0x92
+S:165:0x87/0x93
+S:166:0x87/0x95
+S:167:0x87/0x90
+S:168:0x87/0x95
+S:169:0x87/0x95
+S:170:0x87/0x92
+S:171:0x87/0x94
+S:172:0x87/0x92
+S:173:0x87/0x93
+S:174:0x87/0x96
+S:175:0x87/0x90
+
+# Wands (-)
+S:176:0x86/0x97
+S:177:0x86/0x90
+S:178:0x86/0x98
+S:179:0x86/0x92
+S:180:0x86/0x93
+S:181:0x86/0x94
+S:182:0x86/0x95
+S:183:0x86/0x96
+S:184:0x86/0x91
+S:185:0x86/0x91
+S:186:0x86/0x99
+S:187:0x86/0x9A
+S:188:0x86/0x9B
+S:189:0x86/0x9C
+S:190:0x86/0x9D
+S:191:0x86/0x9E
+
+# Rods (-)
+S:192:0x86/0x87
+S:193:0x86/0x80
+S:194:0x86/0x88
+S:195:0x86/0x82
+S:196:0x86/0x83
+S:197:0x86/0x84
+S:198:0x86/0x85
+S:199:0x86/0x86
+S:200:0x86/0x81
+S:201:0x86/0x81
+S:202:0x86/0x89
+S:203:0x86/0x8A
+S:204:0x86/0x8B
+S:205:0x86/0x8C
+S:206:0x86/0x8D
+S:207:0x86/0x8E
+
+# Scrolls (?)
+S:208:0x83/0x9C
+S:209:0x83/0x9D
+S:210:0x83/0x9E
+S:211:0x83/0x9F
+S:212:0x83/0x9C
+S:213:0x83/0x9D
+S:214:0x83/0x9E
+S:215:0x83/0x9F
+S:216:0x83/0x9C
+S:217:0x83/0x9D
+S:218:0x83/0x9E
+S:219:0x83/0x9F
+S:220:0x83/0x9C
+S:221:0x83/0x9D
+S:222:0x83/0x9E
+S:223:0x83/0x9F
+
+# Potions (!)
+S:224:0x85/0x87
+S:225:0x85/0x80
+S:226:0x85/0x88
+S:227:0x85/0x82
+S:228:0x85/0x83
+S:229:0x85/0x84
+S:230:0x85/0x85
+S:231:0x85/0x86
+S:232:0x85/0x81
+S:233:0x85/0x81
+S:234:0x85/0x89
+S:235:0x85/0x8A
+S:236:0x85/0x8B
+S:237:0x85/0x8C
+S:238:0x85/0x8D
+S:239:0x85/0x8E
+
+# Food (,)
+S:240:0x85/0x97
+S:241:0x85/0x90
+S:242:0x85/0x98
+S:243:0x85/0x92
+S:244:0x85/0x93
+S:245:0x85/0x94
+S:246:0x85/0x95
+S:247:0x85/0x96
+S:248:0x85/0x91
+S:249:0x85/0x91
+S:250:0x85/0x99
+S:251:0x85/0x9A
+S:252:0x85/0x9B
+S:253:0x85/0x9C
+S:254:0x85/0x9D
+S:255:0x85/0x9E
+
+# Fire golem
+R:1043:0x8C/0xA0
+
+# Melkor, Lord of Darkness
+R:1044:0x8C/0xA1
+
+# & piece~ of a Relic of Eru
+K:814:0x8C/0xA2
+
+# & piece~ of a Relic of Manwe
+K:815:0x8C/0xA3
+
+# & piece~ of a Relic of Tulkas
+K:816:0x8C/0xA4
+
+# & piece~ of a Relic of Melkor
+K:817:0x8C/0xA5
+
+# rocky ground
+F:207:0x8D/0xA0
+
+# cloud-like vapour
+F:208:0x8D/0xA1
+
+# condensing water
+F:209:0x8D/0xA2
+
+# dense mist
+F:210:0x8D/0xA3
+
+# hail-stone wall
+F:211:0x8D/0xA4
+
+# Mining Supply store
+B:59:0x87/0xAE
+
+# & piece~ of a Relic of Yavanna
+K:818:0x8C/0xA6
+
+# Elven
+G:M:12:0x91/0xA1
+
+# Dwarven
+G:M:13:0x91/0xA0
+
+# Spirit
+R:1045:0x92/0x9F
+R:1046:0x92/0xA0
+R:1047:0x92/0xA1
+R:1048:0x92/0xA2
+R:1049:0x92/0xA3
+R:1050:0x92/0xA4
+R:1051:0x92/0xA5
+R:1052:0x92/0xA6
+R:1053:0x92/0xA7
+R:1054:0x92/0xA8
+R:1055:0x92/0xA9
+R:1056:0x92/0xAA
+R:1057:0x92/0xA3
+R:1058:0x92/0xAB
+R:1059:0x92/0xAC
+R:1060:0x92/0xAD
+R:1061:0x92/0xAE
+R:1062:0x92/0xAF
+R:1063:0x92/0xB0
+R:1064:0x92/0xB1
+R:1065:0x92/0xB2
+R:1066:0x92/0xB3
+R:1067:0x92/0xB4
+R:1068:0x92/0xB5
+R:1069:0x92/0xB6
+R:1070:0x92/0xB7
+R:1071:0x92/0xB8
+R:1072:0x92/0xB9
+R:1073:0x92/0xBA
+R:1074:0x92/0xBB
+R:1075:0x92/0xBC
+
+# & Spellbook~ of #
+K:757:0x91/0xA4
+
+# Weakness Trap
+#G:T:1:0xFF/0xFF
+#G:T:2:0xFF/0xFF
+#G:T:3:0xFF/0xFF
+
+# Intelligence Trap
+#G:T:4:0xFF/0xFF
+#G:T:5:0xFF/0xFF
+#G:T:6:0xFF/0xFF
+
+# Wisdom Trap
+#G:T:7:0xFF/0xFF
+#G:T:8:0xFF/0xFF
+#G:T:9:0xFF/0xFF
+
+# Fumbling Fingers Trap
+#G:T:10:0xFF/0xFF
+#G:T:11:0xFF/0xFF
+#G:T:12:0xFF/0xFF
+
+# Wasting Trap
+#G:T:13:0xFF/0xFF
+#G:T:14:0xFF/0xFF
+#G:T:15:0xFF/0xFF
+
+# Beauty Trap
+#G:T:16:0xFF/0xFF
+#G:T:17:0xFF/0xFF
+#G:T:18:0xFF/0xFF
+
+# Trap of Curse Weapon
+#G:T:20:0xFF/0xFF
+
+# Trap of Curse Armor
+#G:T:21:0xFF/0xFF
+
+# Earthquake Trap
+#G:T:22:0xFF/0xFF
+
+# Poison Needle Trap
+#G:T:23:0xFF/0xFF
+
+# Summon Monster Trap
+#G:T:24:0xFF/0xFF
+
+# Summon Undead Trap
+#G:T:25:0xFF/0xFF
+
+# Summon Greater Undead Trap
+#G:T:26:0xFF/0xFF
+
+# Teleport Trap
+#G:T:27:0xFF/0xFF
+
+# Paralyzing Trap
+#G:T:28:0xFF/0xFF
+
+# Explosive Device
+#G:T:29:0xFF/0xFF
+
+# Teleport Item Trap
+#G:T:30:0xFF/0xFF
+
+# Lose Memory Trap
+#G:T:31:0xFF/0xFF
+
+# Bitter Regret Trap
+#G:T:32:0xFF/0xFF
+
+# Bowel Cramps Trap
+#G:T:33:0xFF/0xFF
+
+# Blindness
+#G:T:34:0xFF/0xFF
+
+# Aggravation Trap
+#G:T:35:0xFF/0xFF
+
+# Multiplication Trap
+#G:T:36:0xFF/0xFF
+
+# Steal Item Trap
+#G:T:37:0xFF/0xFF
+
+# Summon Fast Quylthulgs Trap
+#G:T:38:0xFF/0xFF
+
+# Trap of Sinking
+#G:T:39:0xFF/0xFF
+
+# Trap of Mana Drain
+#G:T:40:0xFF/0xFF
+
+# Trap of Missing Money
+#G:T:41:0xFF/0xFF
+
+# Trap of No Return
+#G:T:42:0xFF/0xFF
+
+# Trap of Silent Switching
+#G:T:43:0xFF/0xFF
+
+# Trap of Walls
+#G:T:44:0xFF/0xFF
+
+# Trap of Calling Out
+#G:T:45:0xFF/0xFF
+
+# Trap of Sliding
+#G:T:46:0xFF/0xFF
+
+# Trap of Charges Drain
+#G:T:47:0xFF/0xFF
+
+# Trap of Stair Movement
+#G:T:48:0xFF/0xFF
+
+# Trap of New Trap
+#G:T:49:0xFF/0xFF
+
+# Trap of Scatter Items
+#G:T:50:0xFF/0xFF
+
+# Trap of Decay
+#G:T:51:0xFF/0xFF
+
+# Trap of Wasting Wands
+#G:T:52:0xFF/0xFF
+
+# Trap of Filling
+#G:T:53:0xFF/0xFF
+
+# Trap of Drain Speed
+#G:T:54:0xFF/0xFF
+
+# Lightning Bolt Trap
+#G:T:60:0xFF/0xFF
+
+# Poison Bolt Trap
+#G:T:61:0xFF/0xFF
+
+# Acid Bolt Trap
+#G:T:62:0xFF/0xFF
+
+# Cold Bolt Trap
+#G:T:63:0xFF/0xFF
+
+# Fire Bolt Trap
+#G:T:64:0xFF/0xFF
+
+# Plasma Bolt Trap
+#G:T:65:0xFF/0xFF
+
+# Water Bolt Trap
+#G:T:66:0xFF/0xFF
+
+# Lite Bolt Trap
+#G:T:67:0xFF/0xFF
+
+# Dark Bolt Trap
+#G:T:68:0xFF/0xFF
+
+# Shards Bolt Trap
+#G:T:69:0xFF/0xFF
+
+# Sound Bolt Trap
+#G:T:70:0xFF/0xFF
+
+# Confusion Bolt Trap
+#G:T:71:0xFF/0xFF
+
+# Force Bolt Trap
+#G:T:72:0xFF/0xFF
+
+# Inertia Bolt Trap
+#G:T:73:0xFF/0xFF
+
+# Mana Bolt Trap
+#G:T:74:0xFF/0xFF
+
+# Ice Bolt Trap
+#G:T:75:0xFF/0xFF
+
+# Chaos Bolt Trap
+#G:T:76:0xFF/0xFF
+
+# Nether Bolt Trap
+#G:T:77:0xFF/0xFF
+
+# Disenchantment Bolt Trap
+#G:T:78:0xFF/0xFF
+
+# Nexus Bolt Trap
+#G:T:79:0xFF/0xFF
+
+# Time Bolt Trap
+#G:T:80:0xFF/0xFF
+
+# Gravity Bolt Trap
+#G:T:81:0xFF/0xFF
+
+# Lightning Ball Trap
+#G:T:82:0xFF/0xFF
+
+# Poison Ball Trap
+#G:T:83:0xFF/0xFF
+
+# Acid Ball Trap
+#G:T:84:0xFF/0xFF
+
+# Cold Ball Trap
+#G:T:85:0xFF/0xFF
+
+# Fire Ball Trap
+#G:T:86:0xFF/0xFF
+
+# Plasma Ball Trap
+#G:T:87:0xFF/0xFF
+
+# Water Ball Trap
+#G:T:88:0xFF/0xFF
+
+# Light Ball Trap
+#G:T:89:0xFF/0xFF
+
+# Darkness Ball Trap
+#G:T:90:0xFF/0xFF
+
+# Shards Ball Trap
+#G:T:91:0xFF/0xFF
+
+# Sound Ball Trap
+#G:T:92:0xFF/0xFF
+
+# Confusion Ball Trap
+#G:T:93:0xFF/0xFF
+
+# Force Ball Trap
+#G:T:94:0xFF/0xFF
+
+# Inertia Ball Trap
+#G:T:95:0x82/0xBF
+
+# Mana Ball Trap
+#G:T:96:0xFF/0xFF
+
+# Ice Ball Trap
+#G:T:97:0xFF/0xFF
+
+# Chaos Ball Trap
+#G:T:98:0xFF/0xFF
+
+# Nether Ball Trap
+#G:T:99:0xFF/0xFF
+
+# Disenchantment Ball Trap
+#G:T:100:0xFF/0xFF
+
+# Nexus Ball Trap
+#G:T:101:0xFF/0xFF
+
+# Time Ball Trap
+#G:T:102:0xFF/0xFF
+
+# Gravity Ball Trap
+#G:T:103:0xFF/0xFF
+
+# Arrow Trap
+#G:T:110:0xFF/0xFF
+
+# Bolt Trap
+#G:T:111:0xFF/0xFF
+
+# Seeker Arrow Trap
+#G:T:112:0xFF/0xFF
+
+# Seeker Bolt Trap
+#G:T:113:0xFF/0xFF
+
+# Poison Arrow Trap
+#G:T:114:0xFF/0xFF
+
+# Poison Bolt Trap
+#G:T:115:0xFF/0xFF
+
+# Poison Seeker Arrow Trap
+#G:T:116:0xFF/0xFF
+
+# Poison Seeker Bolt Trap
+#G:T:117:0xFF/0xFF
+
+# Broken Dagger Trap
+#G:T:118:0xFF/0xFF
+
+# Dagger Trap
+#G:T:119:0xFF/0xFF
+
+# Poison Broken Dagger Trap
+#G:T:120:0xFF/0xFF
+
+# Poison Dagger Trap
+#G:T:121:0xFF/0xFF
+
+# Arrows Trap
+#G:T:122:0xFF/0xFF
+
+# Bolts Trap
+#G:T:123:0xFF/0xFF
+
+# Seeker Arrow Trap
+#G:T:124:0xFF/0xFF
+
+# Seeker Bolt Trap
+#G:T:125:0xFF/0xFF
+
+# Poison Arrows Trap
+#G:T:126:0xFF/0xFF
+
+# Poison Bolt Trap
+#G:T:127:0xFF/0xFF
+
+# Poison Seeker Arrows Trap
+#G:T:128:0xFF/0xFF
+
+# Poison Seeker Bolts Trap
+#G:T:129:0xFF/0xFF
+
+# Broken Daggers Trap
+#G:T:130:0xFF/0xFF
+
+# Dagger Trap
+#G:T:131:0xFF/0xFF
+
+# Poison Broken Daggers Trap
+#G:T:132:0xFF/0xFF
+
+# Poison Daggers Trap
+#G:T:133:0xFF/0xFF
+
+# Trap of Drop Item
+#G:T:140:0xFF/0xFF
+
+# Trap of Drop Items
+#G:T:141:0xFF/0xFF
+
+# Trap of Drop Everything
+#G:T:142:0xFF/0xFF
+
+# Trap of Femininity
+#G:T:150:0xFF/0xFF
+
+# Trap of Masculinity
+#G:T:151:0xFF/0xFF
+
+# Trap of Neutrality
+#G:T:152:0xFF/0xFF
+
+# Trap of Aging
+#G:T:153:0xFF/0xFF
+
+# Trap of Growing
+#G:T:154:0xFF/0xFF
+
+# Trap of Shrinking
+#G:T:155:0xFF/0xFF
+
+# Trap of Tanker Drain
+#G:T:157:0xFF/0xFF
+
+# Trap of Divine Anger
+#G:T:158:0xFF/0xFF
+
+# Trap of Divine Wrath
+#G:T:159:0xFF/0xFF
+
+# Hallucination Trap
+#G:T:160:0xFF/0xFF
+
+# Greater Magic Missile Trap
+#G:T:161:0xFF/0xFF
+
+# Foulness Trap
+#G:T:162:0xFF/0xFF
+
+# Trap of Holy Fire
+#G:T:164:0xFF/0xFF
+
+# Trap of Hell Fire
+#G:T:165:0xFF/0xFF
+
+# Psi Bolt Trap
+#G:T:166:0xFF/0xFF
+
+# Psi Drain Trap
+#G:T:167:0xFF/0xFF
+
+# Plasma Ball Trap
+#G:T:168:0xFF/0xFF
+
+# Psi Ball Trap
+#G:T:169:0xFF/0xFF
+
+# Acquirement Trap
+#G:T:170:0xFF/0xFF
+
+# Greater Lightning Bolt Trap
+#G:T:171:0xFF/0xFF
+
+# Greater Poison Bolt Trap
+#G:T:172:0xFF/0xFF
+
+# Greater Acid Bolt Trap
+#G:T:173:0xFF/0xFF
+
+# Greater Cold Bolt Trap
+#G:T:174:0xFF/0xFF
+
+# Greater Fire Bolt Trap
+#G:T:175:0xFF/0xFF
+# non-defines encountered :
+# Load the special player pictures
+%:xtra-new.prf
diff --git a/lib/pref/graf-sdl.prf b/lib/pref/graf-sdl.prf
new file mode 100644
index 00000000..818f876a
--- /dev/null
+++ b/lib/pref/graf-sdl.prf
@@ -0,0 +1,37 @@
+# File: graf-x11.prf
+
+
+# Font stuff
+%:font-x11.prf
+
+
+# Color palette - Graphics
+
+#V:16:0x01:0x00:0x00:0x00
+#V:17:0x01:0xF0:0xE0:0xD0
+#V:18:0x01:0x80:0x80:0x80
+#V:19:0x01:0x50:0x50:0x50
+#V:20:0x01:0xE0:0xB0:0x00
+#V:21:0x01:0xC0:0xA0:0x70
+#V:22:0x01:0x80:0x60:0x40
+#V:23:0x01:0x50:0x3C:0x28
+#V:24:0x01:0x00:0xA0:0xF0
+#V:25:0x01:0x00:0x00:0xF0
+#V:26:0x01:0x00:0x00:0x70
+#V:27:0x01:0xF0:0x00:0x00
+#V:28:0x01:0x80:0x00:0x00
+#V:29:0x01:0x90:0x00:0xB0
+#V:30:0x01:0x00:0x60:0x10
+#V:31:0x01:0x60:0xF0:0x40
+
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
+
+?:1
+
diff --git a/lib/pref/graf-win.prf b/lib/pref/graf-win.prf
new file mode 100644
index 00000000..f59edb35
--- /dev/null
+++ b/lib/pref/graf-win.prf
@@ -0,0 +1,16 @@
+# File: graf-win.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
diff --git a/lib/pref/graf-x11.prf b/lib/pref/graf-x11.prf
new file mode 100644
index 00000000..818f876a
--- /dev/null
+++ b/lib/pref/graf-x11.prf
@@ -0,0 +1,37 @@
+# File: graf-x11.prf
+
+
+# Font stuff
+%:font-x11.prf
+
+
+# Color palette - Graphics
+
+#V:16:0x01:0x00:0x00:0x00
+#V:17:0x01:0xF0:0xE0:0xD0
+#V:18:0x01:0x80:0x80:0x80
+#V:19:0x01:0x50:0x50:0x50
+#V:20:0x01:0xE0:0xB0:0x00
+#V:21:0x01:0xC0:0xA0:0x70
+#V:22:0x01:0x80:0x60:0x40
+#V:23:0x01:0x50:0x3C:0x28
+#V:24:0x01:0x00:0xA0:0xF0
+#V:25:0x01:0x00:0x00:0xF0
+#V:26:0x01:0x00:0x00:0x70
+#V:27:0x01:0xF0:0x00:0x00
+#V:28:0x01:0x80:0x00:0x00
+#V:29:0x01:0x90:0x00:0xB0
+#V:30:0x01:0x00:0x60:0x10
+#V:31:0x01:0x60:0xF0:0x40
+
+
+# Standard file
+?:[EQU $GRAF old]
+%:graf-xxx.prf
+
+# New tiles
+?:[EQU $GRAF new]
+%:graf-new.prf
+
+?:1
+
diff --git a/lib/pref/graf-xxx.prf b/lib/pref/graf-xxx.prf
new file mode 100644
index 00000000..bea696d9
--- /dev/null
+++ b/lib/pref/graf-xxx.prf
@@ -0,0 +1,6348 @@
+# PRF file generated by Andreas Koch`s Tile Assigner
+# 23/06/2004 : Edited manually
+
+# 2185 items
+# 2185 probably mapped correctly
+# 0 imported but not yet defined
+# 0 defined to value(s) lower than 0x80
+# Old header :
+### Special attr:char values ###
+# # Unused (@)
+# S:0x00:0x00:0x40
+# S:0x01:0x01:0x40
+# S:0x02:0x02:0x40
+# S:0x03:0x03:0x40
+# S:0x04:0x04:0x40
+# S:0x05:0x05:0x40
+# S:0x06:0x06:0x40
+# S:0x07:0x07:0x40
+# S:0x08:0x08:0x40
+# S:0x09:0x09:0x40
+# S:0x0A:0x0A:0x40
+# S:0x0B:0x0B:0x40
+# S:0x0C:0x0C:0x40
+# S:0x0D:0x0D:0x40
+# S:0x0E:0x0E:0x40
+# S:0x0F:0x0F:0x40
+# # Unused (@)
+# S:0x10:0x00:0x40
+# S:0x11:0x01:0x40
+# S:0x12:0x02:0x40
+# S:0x13:0x03:0x40
+# S:0x14:0x04:0x40
+# S:0x15:0x05:0x40
+# S:0x16:0x06:0x40
+# S:0x17:0x07:0x40
+# S:0x18:0x08:0x40
+# S:0x19:0x09:0x40
+# S:0x1A:0x0A:0x40
+# S:0x1B:0x0B:0x40
+# S:0x1C:0x0C:0x40
+# S:0x1D:0x0D:0x40
+# S:0x1E:0x0E:0x40
+# S:0x1F:0x0F:0x40
+# # Unused (@)
+# S:0x20:0x00:0x40
+# S:0x21:0x01:0x40
+# S:0x22:0x02:0x40
+# S:0x23:0x03:0x40
+# S:0x24:0x04:0x40
+# S:0x25:0x05:0x40
+# S:0x26:0x06:0x40
+# S:0x27:0x07:0x40
+# S:0x28:0x08:0x40
+# S:0x29:0x09:0x40
+# S:0x2A:0x0A:0x40
+# S:0x2B:0x0B:0x40
+# S:0x2C:0x0C:0x40
+# S:0x2D:0x0D:0x40
+# S:0x2E:0x0E:0x40
+# S:0x2F:0x0F:0x40
+
+# General Store
+B:0:0x81/0x91
+
+# Armoury
+B:1:0x81/0x92
+
+# Weapon Smiths
+B:2:0x81/0x93
+
+# Temple
+B:3:0x81/0x94
+
+# Alchemy Shop
+B:4:0x81/0x95
+
+# Magic Shop
+B:5:0x81/0x96
+
+# Black Market
+B:6:0x81/0x97
+
+# Home
+B:7:0x81/0x98
+
+# Bookstore
+B:8:0x82/0x93
+
+# Pet Shop
+B:9:0xCB/0x96
+
+# Mayor's Office
+B:10:0xCB/0x92
+
+# Inn
+B:11:0xCB/0x95
+
+# The Soothsayer
+B:12:0xD4/0x85
+
+# Library
+B:13:0xD4/0x89
+
+# Castle
+B:14:0xCB/0x92
+
+# Casino
+B:15:0xD5/0x81
+
+# Beastmaster Shanty
+B:16:0xD3/0x8B
+
+# Fighters Hall
+B:17:0xD3/0x8C
+
+# Tower of Magery
+B:18:0xD4/0x8B
+
+# Inner Temple
+B:19:0xD4/0x9D
+
+# Paladins Guild
+B:20:0xCB/0x8F
+
+# Rangers Guild
+B:21:0xD3/0x83
+
+# Weyr
+B:22:0xCB/0x93
+
+# The Mirror
+B:23:0xD4/0x89
+
+# Seat of Ruling
+B:24:0xCB/0x92
+
+# Wizards Spire
+B:25:0xD4/0x8A
+
+# Priests Circle
+B:26:0xD4/0x92
+
+# Tower of the King
+B:27:0xCB/0x92
+
+# Library
+B:28:0xD4/0x89
+
+# The White Tree
+B:29:0xCB/0x95
+
+# Craftsmaster
+B:30:0xCB/0x97
+
+# Earth-Dome (Nature)
+B:31:0xCB/0x9A
+
+# Minstrels Haven
+B:32:0xD3/0x9F
+
+# Star-Dome
+B:33:0xD4/0x8C
+
+# Valarin Temple
+B:34:0xD4/0x90
+
+# Sea-Dome
+B:35:0xD4/0x91
+
+# The Golden Flower
+B:36:0xD3/0x83
+
+# The Fountain
+B:37:0xD4/0x9D
+
+# Axe Smith
+B:38:0xCC/0x96
+
+# Hafted Smith
+B:39:0xCC/0x97
+
+# Polearm Smith
+B:40:0xCC/0x98
+
+# Sword Smith
+B:41:0xCC/0x80
+
+# Rare Jewelry Shop
+B:42:0xD3/0x96
+
+# Jewelry Shop
+B:43:0xD3/0x93
+
+# Footwear Shop
+B:44:0xD3/0x9D
+
+# Rare Footwear Shop
+B:45:0xD3/0x9E
+
+# Library
+B:46:0xD3/0x9C
+
+# Forbidden Library
+B:47:0xD4/0x8F
+
+# Expensive Black Market
+B:48:0xD4/0x95
+
+# Common Shop
+B:49:0xD4/0x93
+
+# Dragon Hunter
+B:50:0xCC/0x89
+
+# Speed Ring Market
+B:51:0xD3/0x97
+
+# Scribe
+B:52:0xD4/0x86
+
+# Potion Store
+B:53:0xD4/0x80
+
+# Recaller
+B:54:0xD4/0x88
+
+# Master Archer
+B:55:0xD3/0x85
+
+# Merchants Guild
+B:56:0xD4/0x9B
+
+# The Mathom-house
+B:57:0xCB/0x9B
+
+# The Prancing Pony
+B:58:0xCB/0x95
+
+# nothing
+F:0:0x81/0x80
+
+# open floor
+F:1:0x80/0x80
+
+# fountain - wet
+F:2:0xD1/0x83
+
+# glyph of warding
+F:3:0xA2/0x88
+
+# open door
+F:4:0x81/0x87
+
+# broken door
+F:5:0x81/0x87
+
+# up staircase
+F:6:0x81/0x9C
+
+# down staircase
+F:7:0x81/0x9E
+
+# quest entrance
+F:8:0x82/0x8E
+
+# quest exit
+F:9:0x82/0x8B
+
+# quest down level
+F:10:0x82/0x8F
+
+# quest up level
+F:11:0x82/0x8C
+
+# town exit
+F:12:0x82/0x91
+
+# shaft down
+F:13:0x82/0x90
+
+# shaft up
+F:14:0x82/0x8D
+
+# fountain
+F:15:0xD1/0x82
+
+# web
+F:16:0x82/0x92
+
+# Open pit
+F:17:0xA2/0x96
+
+# Spiked Pit
+F:18:0xA2/0x96
+
+# Poison Pit
+F:19:0xA2/0x96
+
+# Summon Rune
+F:20:0x8A/0x9C
+
+# Teleport Rune
+F:21:0x8A/0x9C
+
+# Fire spot
+F:22:0x8A/0x9B
+
+# Acid spot
+F:23:0x8A/0x9B
+
+# Slow dart trap
+F:24:0x82/0x9E
+
+# Lose str dart
+F:25:0xA2/0x89
+
+# Lose dex dart
+F:26:0xA2/0x8D
+
+# Lose con dart
+F:27:0xA2/0x92
+
+# gas trap - blind
+F:28:0xA2/0x8E
+
+# gas trap - confuse
+F:29:0xA2/0x8F
+
+# gas trap - poison
+F:30:0xA2/0x90
+
+# gas trap - sleep
+F:31:0xA2/0x91
+
+# door
+F:32:0x81/0x8B
+
+# locked door
+F:33:0x81/0x8B
+F:34:0x81/0x8B
+F:35:0x81/0x8B
+F:36:0x81/0x8B
+F:37:0x81/0x8B
+F:38:0x81/0x8B
+F:39:0x81/0x8B
+
+# jammed door
+F:40:0x81/0x8B
+F:41:0x81/0x8B
+F:42:0x81/0x8B
+F:43:0x81/0x8B
+F:44:0x81/0x8B
+F:45:0x81/0x8B
+F:46:0x81/0x8B
+F:47:0x81/0x8B
+
+# secret door
+F:48:0x80/0x82
+
+# pile of rubble
+F:49:0x81/0x9A
+
+# magma vein
+F:50:0x81/0x83
+
+# quartz vein
+F:51:0x80/0x83
+
+# magma vein
+F:52:0x81/0x83
+
+# quartz vein
+F:53:0x80/0x83
+
+# magma vein with treasure
+F:54:0x80/0x84
+
+# quartz vein with treasure
+F:55:0x80/0x84
+
+# granite wall
+F:56:0x80/0x82
+F:57:0x80/0x82
+F:58:0x80/0x82
+F:59:0x80/0x82
+
+# permanent wall
+F:60:0x80/0x95
+F:61:0x80/0x95
+F:62:0x80/0x95
+F:63:0x80/0x95
+
+# explosive rune
+F:64:0xA2/0x87
+
+# Straight Road startpoint
+F:65:0xA3/0x9D
+
+# section of the Straight Road
+F:66:0xA3/0x97
+F:67:0xA3/0x9C
+F:68:0xA3/0x9B
+F:69:0xA3/0x9A
+F:70:0xA3/0x98
+
+# section of the Straight Road (discharged)
+F:71:0xA3/0x98
+
+# Straight Road exit
+F:72:0xA3/0x9D
+
+# corrupted section of the Straight Road
+F:73:0xA3/0x99
+
+# Building
+F:74:0x81/0x91
+
+# permanent wall
+F:75:0x80/0x95
+F:76:0x80/0x95
+F:77:0x80/0x95
+F:78:0x80/0x95
+
+# Deep water
+F:83:0xD2/0x83
+
+# stream of shallow water
+F:84:0xD2/0x81
+
+# pool of deep lava
+F:85:0xCB/0x89
+
+# stream of shallow lava
+F:86:0xCB/0x88
+
+# dark pit
+F:87:0x81/0x80
+
+# dirt
+F:88:0xCB/0x84
+
+# patch of grass
+F:89:0xD0/0x8E
+
+# ice
+F:90:0xCF/0x81
+
+# sand
+F:91:0xCF/0x8E
+
+# dead tree
+F:92:0xCF/0x85
+
+# ash
+F:93:0xCF/0x95
+
+# mud
+F:94:0xCF/0x8D
+
+# ice wall
+F:95:0xD0/0x88
+
+# tree
+F:96:0xCB/0x86
+
+# mountain chain
+F:97:0xCB/0x87
+
+# sandwall
+F:98:0xD0/0x87
+F:99:0xD0/0x87
+
+# sandwall with treasure
+F:100:0xD0/0x8A
+
+# high mountain chain
+F:101:0xCB/0x87
+
+# nether mist
+F:102:0xC5/0x8C
+
+# molten glass wall
+F:103:0xD0/0x89
+
+# Between gate
+F:160:0x8A/0x9D
+
+# Altar of Forests
+F:161:0xD1/0x85
+
+# Altar of Water
+F:162:0xD1/0x86
+
+# Altar of Earth
+F:163:0xD1/0x8E
+
+# Altar of Darkness
+F:164:0xD1/0x88
+
+# Altar of Moon
+F:165:0xD1/0x89
+
+# Altar of Sun
+F:166:0xD1/0x8C
+
+# Altar of Rage
+F:167:0xD1/0x8A
+
+# Altar of Winds
+F:168:0xD1/0x8B
+
+# Altar of Stars
+F:169:0xD1/0x8D
+
+# Altar of Being
+F:170:0xD1/0x87
+
+# Altar of Randomness
+F:171:0xD1/0x8F
+
+# floor
+F:172:0x80/0x80
+
+# Underground Tunnel
+F:173:0xCF/0x97
+
+# stream of tainted water
+F:174:0xD2/0x82
+
+# monster trap
+F:175:0x82/0x94
+
+# Between gate
+F:176:0x8A/0x9D
+
+# lava wall
+F:177:0xD0/0x86
+
+# Great Fire
+F:178:0xD1/0x90
+
+# Path to next area
+F:179:0xCF/0x9C
+
+# Path to previous area
+F:180:0xCF/0x9B
+
+# field
+F:181:0xCF/0x8A
+
+# Ekkaia, the Encircling Sea
+F:182:0xD2/0x84
+
+# pool of deep water
+F:187:0xD2/0x80
+
+# glass wall
+F:188:0xD0/0x89
+
+# illusion wall
+F:189:0xD0/0x8C
+
+# Grass roof
+F:190:0xD0/0x8F
+
+# grass roof top
+F:191:0xD0/0x8F
+
+# grass roof chimney
+F:192:0xD0/0x8F
+
+# brick roof
+F:193:0xD0/0x90
+
+# brick roof top
+F:194:0xD0/0x90
+
+# brick roof chimney
+F:195:0xD0/0x90
+
+# window
+F:196:0xD0/0x91
+
+# small window
+F:197:0xD0/0x92
+
+# rain barrel
+F:198:0xD0/0x93
+
+# grass with flowers
+F:199:0xD0/0x8D
+
+# cobblestone road
+F:200:0x82/0x8A
+
+# cobblestone with outlet
+F:201:0x82/0x8A
+
+# small tree
+F:202:0xD0/0x8B
+
+# town
+F:203:0xD0/0x94
+
+# Underground Tunnel
+F:204:0xD0/0x95
+
+# a blazing fire
+F:205:0xD1/0x84
+
+# pile of rubble
+F:206:0x81/0x9A
+
+# ethereal wall
+F:214:0x80/0x80
+
+# glacial wall
+F:215:0xD0/0x88
+
+# something
+K:0:0x80/0x80
+
+# Blindness
+K:1:0xBA/0x81
+
+# Paranoia
+K:2:0xBA/0x81
+
+# Confusion
+K:3:0xBA/0x81
+
+# Hallucination
+K:4:0xBA/0x81
+
+# Cure Poison
+K:5:0xBA/0x81
+
+# Cure Blindness
+K:6:0xBA/0x81
+
+# Cure Paranoia
+K:7:0xBA/0x81
+
+# Cure Confusion
+K:8:0xBA/0x81
+
+# Weakness
+K:9:0xBA/0x81
+
+# Unhealth
+K:10:0xBA/0x81
+
+# Restore Constitution
+K:11:0xBA/0x81
+
+# Restoring
+K:12:0xBA/0x81
+
+# Stupidity
+K:13:0xBA/0x81
+
+# Naivety
+K:14:0xBA/0x81
+
+# Poison
+K:15:0xBA/0x81
+
+# Sickness
+K:16:0xBA/0x81
+
+# Paralysis
+K:17:0xBA/0x81
+
+# Restore Strength
+K:18:0xBA/0x81
+
+# Disease
+K:19:0xBA/0x81
+
+# Cure Serious Wounds
+K:20:0xBA/0x81
+
+# & Ration~ of Food
+K:21:0x8B/0x82
+
+# & Hard Biscuit~
+K:22:0x8B/0x82
+
+# & Strip~ of Venison
+K:23:0x8B/0x82
+
+# & Slime Mold~
+K:24:0x8A/0x9F
+
+# & Piece~ of Elvish Waybread
+K:25:0x8B/0x80
+
+# & Pint~ of Fine Ale
+K:26:0x8A/0x95
+
+# & Pint~ of Fine Wine
+K:27:0x8A/0x96
+
+# & Mattock~
+K:28:0xCD/0x80
+
+# The Blue Stone 'Toris Mejistos'
+K:29:0xB6/0x89
+
+# & Broken Dagger~
+K:30:0x89/0x83
+
+# & Bastard Sword~
+K:31:0x89/0x85
+
+# & Scimitar~
+K:32:0x89/0x85
+
+# & Tulwar~
+K:33:0x89/0x84
+
+# & Broad Sword~
+K:34:0x89/0x85
+
+# & Short Sword~
+K:35:0x89/0x84
+
+# & Blade~ of Chaos
+K:36:0x89/0x87
+
+# & Two-Handed Sword~
+K:37:0x89/0x85
+
+# & Main Gauche~
+K:38:0x89/0x83
+
+# & Cutlass~
+K:39:0x89/0x84
+
+# & Executioner's Sword~
+K:40:0x89/0x86
+
+# & Katana~
+K:41:0x89/0x85
+
+# & Long Sword~
+K:42:0x89/0x85
+
+# & Dagger~
+K:43:0x89/0x83
+
+# & Rapier~
+K:44:0x89/0x84
+
+# & Sabre~
+K:45:0x89/0x84
+
+# & Small Sword~
+K:46:0x89/0x84
+
+# & Broken Sword~
+K:47:0x89/0x83
+
+# & Ball-and-Chain~
+K:48:0x89/0x88
+
+# & Whip~
+K:49:0x89/0x89
+
+# & Flail~
+K:50:0x89/0x8B
+
+# & Two-Handed Flail~
+K:51:0x89/0x8B
+
+# & Morning Star~
+K:52:0x89/0x8B
+
+# & Mace~
+K:53:0x89/0x8C
+
+# & Quarterstaff~
+K:54:0x89/0x8E
+
+# & War Hammer~
+K:55:0x89/0x8F
+
+# & Lead-Filled Mace~
+K:56:0x89/0x8C
+
+# & Mace~ of Disruption
+K:57:0x89/0x8D
+
+# & Lucerne Hammer~
+K:58:0x89/0x90
+
+# & Beaked Axe~
+K:59:0x89/0x90
+
+# & Glaive~
+K:60:0x89/0x90
+
+# & Halberd~
+K:61:0x89/0x90
+
+# & Awl-Pike~
+K:62:0x89/0x91
+
+# & Pike~
+K:63:0x89/0x91
+
+# & Spear~
+K:64:0x89/0x91
+
+# & Trident~
+K:65:0x89/0x92
+
+# & Lance~
+K:66:0x89/0x93
+
+# & Great Axe~
+K:67:0x89/0x90
+
+# & Battle Axe~
+K:68:0x89/0x90
+
+# & Lochaber Axe~
+K:69:0x89/0x90
+
+# & Broad Axe~
+K:70:0x89/0x90
+
+# & Scythe~
+K:71:0x89/0x94
+
+# & Scythe~ of Slicing
+K:72:0x89/0x94
+
+# & Short Bow~
+K:73:0x89/0x95
+
+# & Long Bow~
+K:74:0x89/0x96
+
+# & Light Crossbow~
+K:75:0x89/0x97
+
+# & Heavy Crossbow~
+K:76:0x89/0x98
+
+# & Sling~
+K:77:0x89/0x99
+
+# & Arrow~
+K:78:0x89/0x9A
+
+# & Seeker Arrow~
+K:79:0x89/0x9B
+
+# & Bolt~
+K:80:0x89/0x9C
+
+# & Seeker Bolt~
+K:81:0x89/0x9D
+
+# & Rounded Pebble~
+K:82:0x89/0x9E
+
+# & Iron Shot~
+K:83:0x89/0x9F
+
+# & Shovel~
+K:84:0x8A/0x98
+
+# & Gnomish Shovel~
+K:85:0x8B/0x8F
+
+# & Dwarven Shovel~
+K:86:0x8B/0x90
+
+# & Pick~
+K:87:0x8A/0x97
+
+# & Orcish Pick~
+K:88:0x8B/0x8D
+
+# & Dwarven Pick~
+K:89:0x8B/0x8E
+
+# & Elven Cloak~
+K:90:0x88/0x81
+
+# & Pair~ of Soft Leather Boots
+K:91:0x88/0x89
+
+# & Pair~ of Hard Leather Boots
+K:92:0x88/0x8A
+
+# & Pair~ of Metal Shod Boots
+K:93:0x88/0x8B
+
+# & Hard Leather Cap~
+K:94:0x88/0x82
+
+# & Metal Cap~
+K:95:0x88/0x83
+
+# & Iron Helm~
+K:96:0x88/0x84
+
+# & Steel Helm~
+K:97:0x88/0x85
+
+# & Iron Crown~
+K:98:0x88/0x86
+
+# & Golden Crown~
+K:99:0x88/0x87
+
+# & Jewel Encrusted Crown~
+K:100:0x88/0x88
+
+# & Robe~
+K:101:0x88/0x95
+
+# & Filthy Rag~
+K:102:0x88/0x94
+
+# Soft Leather Armour~
+K:103:0x88/0x96
+
+# Soft Studded Leather~
+K:104:0x88/0x96
+
+# Hard Leather Armour~
+K:105:0x88/0x97
+
+# Hard Studded Leather~
+K:106:0x88/0x97
+
+# Leather Scale Mail~
+K:107:0x88/0x98
+
+# Metal Scale Mail~
+K:108:0x88/0x98
+
+# Chain Mail~
+K:109:0x88/0x99
+
+# Rusty Chain Mail~
+K:110:0x88/0x9A
+
+# Augmented Chain Mail~
+K:111:0x88/0x99
+
+# Bar Chain Mail~
+K:112:0x88/0x99
+
+# Metal Brigandine Armour~
+K:113:0x88/0x99
+
+# Partial Plate Armour~
+K:114:0x88/0x9B
+
+# Metal Lamellar Armour~
+K:115:0x88/0x9B
+
+# Full Plate Armour~
+K:116:0xCD/0x82
+
+# Ribbed Plate Armour~
+K:117:0x88/0x9B
+
+# Adamantite Plate Mail~
+K:118:0xA3/0x96
+
+# Mithril Plate Mail~
+K:119:0x88/0x9C
+
+# Mithril Chain Mail~
+K:120:0x88/0x9C
+
+# Double Chain Mail~
+K:121:0x88/0x99
+
+# & Shield~ of Deflection
+K:122:0x88/0x93
+
+# & Cloak~
+K:123:0x88/0x80
+
+# & Shadow Cloak~
+K:124:0x88/0x81
+
+# & Set~ of Leather Gloves
+K:125:0x88/0x8C
+
+# & Set~ of Gauntlets
+K:126:0x88/0x8D
+
+# & Set~ of Cesti
+K:127:0x88/0x8E
+
+# & Small Leather Shield~
+K:128:0x88/0x8F
+
+# & Large Leather Shield~
+K:129:0x88/0x90
+
+# & Small Metal Shield~
+K:130:0x88/0x91
+
+# & Large Metal Shield~
+K:131:0x88/0x92
+
+# Strength
+K:132:0xB5/0x81
+
+# Dexterity
+K:133:0xB5/0x81
+
+# Constitution
+K:134:0xB5/0x81
+
+# Intelligence
+K:135:0xB5/0x81
+
+# Speed
+K:136:0xB5/0x83
+
+# Searching
+K:137:0xB5/0x80
+
+# Teleportation
+K:138:0xB5/0x80
+
+# Slow Digestion
+K:139:0xB5/0x80
+
+# Fire Resistance
+K:140:0xB5/0x80
+
+# Cold Resistance
+K:141:0xB5/0x80
+
+# Levitation
+K:142:0xB5/0x80
+
+# Poison Resistance
+K:143:0xB5/0x82
+
+# Free Action
+K:144:0xB5/0x80
+
+# Weakness
+K:145:0xB5/0x80
+
+# Flames
+K:146:0xB5/0x82
+
+# Acid
+K:147:0xB5/0x82
+
+# Ice
+K:148:0xB5/0x82
+
+# Woe
+K:149:0xB5/0x82
+
+# Stupidity
+K:150:0xB5/0x80
+
+# Damage
+K:151:0xB5/0x81
+
+# Accuracy
+K:152:0xB5/0x81
+
+# Protection
+K:153:0xB5/0x80
+
+# Aggravate Monster
+K:154:0xB5/0x80
+
+# See Invisible
+K:155:0xB5/0x81
+
+# Sustain Strength
+K:156:0xB5/0x81
+
+# Sustain Intelligence
+K:157:0xB5/0x81
+
+# Sustain Wisdom
+K:158:0xB5/0x81
+
+# Sustain Constitution
+K:159:0xB5/0x81
+
+# Sustain Dexterity
+K:160:0xB5/0x81
+
+# Sustain Charisma
+K:161:0xB5/0x81
+
+# Slaying
+K:162:0xB5/0x81
+
+# Brilliance
+K:163:0xB6/0x9F
+
+# Charisma
+K:164:0xB6/0x9F
+
+# Searching
+K:165:0xB6/0x9E
+
+# Teleportation
+K:166:0xB6/0x9E
+
+# Slow Digestion
+K:167:0xB6/0x9E
+
+# Acid Resistance
+K:168:0xB6/0x9E
+
+# Adornment
+K:169:0xB6/0x9E
+
+# Double Ring Mail~
+K:170:0xCD/0x83
+
+# the Magi
+K:171:0xB6/0x80
+
+# Doom
+K:172:0xB6/0x80
+
+# Enchant Weapon To-Hit
+K:173:0x86/0x80
+
+# Enchant Weapon To-Dam
+K:174:0x86/0x80
+
+# Enchant Armor
+K:175:0x86/0x80
+
+# Identify
+K:176:0x86/0x80
+
+# *Identify*
+K:177:0x86/0x82
+
+# Rumour
+K:178:0x86/0x80
+
+# Chaos
+K:179:0x86/0x80
+
+# Remove Curse
+K:180:0x86/0x80
+
+# Light
+K:181:0x86/0x80
+
+# Fire
+K:182:0x86/0x80
+
+# Ice
+K:183:0x86/0x80
+
+# Summon Monster
+K:184:0x86/0x80
+
+# Phase Door
+K:185:0x86/0x80
+
+# Teleportation
+K:186:0x86/0x80
+
+# Teleport Level
+K:187:0x86/0x80
+
+# Monster Confusion
+K:188:0x86/0x80
+
+# Magic Mapping
+K:189:0x86/0x80
+
+# Rune of Protection
+K:190:0x86/0x82
+
+# *Remove Curse*
+K:191:0x86/0x82
+
+# Treasure Detection
+K:192:0x86/0x80
+
+# Object Detection
+K:193:0x86/0x80
+
+# Trap Detection
+K:194:0x86/0x80
+
+# & Sheaf Arrow~
+K:195:0xCD/0x84
+
+# & Mithril Shot~
+K:196:0xCD/0x85
+
+# Door
+K:197:0x86/0x80
+
+# Acquirement
+K:198:0x86/0x80
+
+# *Acquirement*
+K:199:0x86/0x82
+
+# Mass Genocide
+K:200:0x86/0x82
+
+# Detect Invisible
+K:201:0x86/0x80
+
+# Aggravate Monster
+K:202:0x86/0x80
+
+# Trap Creation
+K:203:0x86/0x80
+
+# Trap
+K:204:0x86/0x80
+
+# Artifact Creation
+K:205:0x86/0x82
+
+# Recharging
+K:206:0x86/0x81
+
+# Genocide
+K:207:0x86/0x81
+
+# Darkness
+K:208:0x86/0x80
+
+# Protection from Evil
+K:209:0x86/0x81
+
+# Satisfy Hunger
+K:210:0x86/0x80
+
+# Dispel Undead
+K:211:0x86/0x81
+
+# *Enchant Weapon*
+K:212:0x86/0x82
+
+# Curse Weapon
+K:213:0x86/0x82
+
+# *Enchant Armor*
+K:214:0x86/0x82
+
+# Curse Armor
+K:215:0x86/0x82
+
+# Summon Undead
+K:216:0x86/0x80
+
+# Blessing
+K:217:0x86/0x80
+
+# Holy Chant
+K:218:0x86/0x80
+
+# Holy Prayer
+K:219:0x86/0x81
+
+# Word of Recall
+K:220:0x86/0x80
+
+# *Destruction*
+K:221:0x86/0x82
+
+# Slime Mold Juice
+K:222:0xBC/0x85
+
+# Apple Juice
+K:223:0xBC/0x85
+
+# Water
+K:224:0xBC/0x85
+
+# Strength
+K:225:0xBC/0x86
+
+# Weakness
+K:226:0xBC/0x85
+
+# Restore Strength
+K:227:0xBC/0x86
+
+# Intelligence
+K:228:0xBC/0x86
+
+# Stupidity
+K:229:0xBC/0x85
+
+# Restore Intelligence
+K:230:0xBC/0x86
+
+# Wisdom
+K:231:0xBC/0x86
+
+# Naivety
+K:232:0xBC/0x85
+
+# Restore Wisdom
+K:233:0xBC/0x86
+
+# Charisma
+K:234:0xBC/0x86
+
+# Ugliness
+K:235:0xBC/0x86
+
+# Restore Charisma
+K:236:0xBC/0x86
+
+# Curing
+K:237:0xBC/0x86
+
+# Invulnerability
+K:238:0xBC/0x86
+
+# New Life
+K:239:0xBC/0x86
+
+# Cure Serious Wounds
+K:240:0xBC/0x85
+
+# Cure Critical Wounds
+K:241:0xBC/0x85
+
+# Healing
+K:242:0xBC/0x85
+
+# Constitution
+K:243:0xBC/0x86
+
+# Experience
+K:244:0xBC/0x87
+
+# Sleep
+K:245:0xBC/0x85
+
+# Blindness
+K:246:0xBC/0x85
+
+# Booze
+K:247:0xBC/0x85
+
+# Poison
+K:248:0xBC/0x85
+
+# Speed
+K:249:0xBC/0x85
+
+# Slowness
+K:250:0xBC/0x85
+
+# Dexterity
+K:251:0xBC/0x86
+
+# Restore Dexterity
+K:252:0xBC/0x86
+
+# Restore Constitution
+K:253:0xBC/0x86
+
+# Lose Memories
+K:254:0xBC/0x85
+
+# Salt Water
+K:255:0xBC/0x85
+
+# Enlightenment
+K:256:0xBC/0x85
+
+# Heroism
+K:257:0xBC/0x85
+
+# Berserk Strength
+K:258:0xBC/0x85
+
+# Boldness
+K:259:0xBC/0x85
+
+# Restore Life Levels
+K:260:0xBC/0x87
+
+# Resist Heat
+K:261:0xBC/0x85
+
+# Resist Cold
+K:262:0xBC/0x85
+
+# Detect Invisible
+K:263:0xBC/0x85
+
+# Slow Poison
+K:264:0xBC/0x85
+
+# Neutralise Poison
+K:265:0xBC/0x85
+
+# Restore Mana
+K:266:0xBC/0x86
+
+# Infra-vision
+K:267:0xBC/0x85
+
+# Resistance
+K:268:0xBC/0x85
+
+# Light
+K:269:0xB7/0x8F
+
+# Tame Monster
+K:270:0xB7/0x8F
+
+# Frost Bolts
+K:271:0xB7/0x8F
+
+# Fire Bolts
+K:272:0xB7/0x90
+
+# Stone to Mud
+K:273:0xB7/0x8F
+
+# Polymorph
+K:274:0xB7/0x8F
+
+# Heal Monster
+K:275:0xB7/0x8F
+
+# Haste Monster
+K:276:0xB7/0x8F
+
+# Slow Monster
+K:277:0xB7/0x8F
+
+# Confuse Monster
+K:278:0xB7/0x8F
+
+# Sleep Monster
+K:279:0xB7/0x8F
+
+# Drain Life
+K:280:0xB7/0x91
+
+# Trap
+K:281:0xB7/0x8F
+
+# Magic Missile
+K:282:0xB7/0x8F
+
+# Clone Monster
+K:283:0xB7/0x90
+
+# Scare Monster
+K:284:0xB7/0x90
+
+# Teleport Other
+K:285:0xB7/0x8F
+
+# Disarming
+K:286:0xB7/0x8F
+
+# Lightning Balls
+K:287:0xB7/0x90
+
+# Cold Balls
+K:288:0xB7/0x90
+
+# Fire Balls
+K:289:0xB7/0x91
+
+# Stinking Cloud
+K:290:0xB7/0x8F
+
+# Acid Balls
+K:291:0xB7/0x91
+
+# Wonder
+K:292:0xB7/0x8F
+
+# & Flight Arrow~
+K:293:0xCD/0x86
+
+# Acid Bolts
+K:294:0xB7/0x90
+
+# Dragon's Flame
+K:295:0xB7/0x91
+
+# Dragon's Frost
+K:296:0xB7/0x91
+
+# Dragon's Breath
+K:297:0xB7/0x91
+
+# Annihilation
+K:298:0xB7/0x91
+
+# Rockets
+K:299:0xB7/0x91
+
+# Trap Location
+K:300:0xB9/0x99
+
+# Treasure Location
+K:301:0xB9/0x99
+
+# Object Location
+K:302:0xB9/0x99
+
+# Teleportation
+K:303:0xB9/0x99
+
+# Earthquakes
+K:304:0xB9/0x9A
+
+# Summoning
+K:305:0xB9/0x99
+
+# Light
+K:306:0xB9/0x99
+
+# *Destruction*
+K:307:0xB9/0x9B
+
+# Starlight
+K:308:0xB9/0x99
+
+# Haste Monsters
+K:309:0xB9/0x99
+
+# Slow Monsters
+K:310:0xB9/0x99
+
+# Sleep Monsters
+K:311:0xB9/0x99
+
+# Cure Light Wounds
+K:312:0xB9/0x99
+
+# Detect Invisible
+K:313:0xB9/0x99
+
+# Speed
+K:314:0xB9/0x9A
+
+# Slowness
+K:315:0xB9/0x99
+
+# Door
+K:316:0xB9/0x99
+
+# Remove Curse
+K:317:0xB9/0x9A
+
+# Detect Evil
+K:318:0xB9/0x99
+
+# Curing
+K:319:0xB9/0x9A
+
+# Dispel Evil
+K:320:0xB9/0x9B
+
+# Probing
+K:321:0xB9/0x9A
+
+# Darkness
+K:322:0xB9/0x99
+
+# Genocide
+K:323:0xB9/0x9B
+
+# Power
+K:324:0xB9/0x9C
+
+# the Magi
+K:325:0xB9/0x9C
+
+# Perception
+K:326:0xB9/0x99
+
+# Holiness
+K:327:0xB9/0x9C
+
+# Enlightenment
+K:328:0xB9/0x9A
+
+# Healing
+K:329:0xB9/0x9C
+
+# [Call of the West]
+K:330:0xA3/0x8A
+
+# [Light of Valinor]
+K:331:0xA3/0x8A
+
+# [Divine Mastery]
+K:332:0xA3/0x8A
+
+# [Words of Power]
+K:333:0xA3/0x8A
+
+# [Apprentice Handbook]
+K:334:0xA3/0x8C
+
+# [Mystical Words]
+K:335:0xA3/0x8C
+
+# [Arcane Chants]
+K:336:0xA3/0x8C
+
+# [Locus of Force]
+K:337:0xA3/0x8C
+
+# & Small wooden chest~
+K:338:0x80/0x96
+
+# & Large wooden chest~
+K:339:0x80/0x97
+
+# & Small iron chest~
+K:340:0x80/0x98
+
+# & Large iron chest~
+K:341:0x80/0x99
+
+# & Small steel chest~
+K:342:0x80/0x9A
+
+# & Large steel chest~
+K:343:0x80/0x9B
+
+# & Ruined chest~
+K:344:0x80/0x9C
+
+# & Iron Spike~
+K:345:0x8B/0x84
+
+# & Wooden Torch~
+K:346:0x8B/0x86
+
+# & Brass Lantern~
+K:347:0x8B/0x85
+
+# & Flask~ of oil
+K:348:0xBC/0x90
+
+# & Empty Bottle~
+K:349:0x8A/0x99
+
+# Havoc
+K:350:0xB8/0x94
+
+# Door
+K:351:0xB8/0x94
+
+# Trap Location
+K:352:0xB8/0x94
+
+# Probing
+K:353:0xB8/0x97
+
+# Recall
+K:354:0xB8/0x96
+
+# Illumination
+K:355:0xB8/0x95
+
+# Light
+K:356:0xB8/0x94
+
+# Lightning Bolts
+K:357:0xB8/0x94
+
+# Frost Bolts
+K:358:0xB8/0x95
+
+# Fire Bolts
+K:359:0xB8/0x95
+
+# Polymorph
+K:360:0xB8/0x95
+
+# Slow Monster
+K:361:0xB8/0x95
+
+# Sleep Monster
+K:362:0xB8/0x95
+
+# Drain Life
+K:363:0xB8/0x97
+
+# Teleport Other
+K:364:0xB8/0x96
+
+# Disarming
+K:365:0xB8/0x95
+
+# Lightning Balls
+K:366:0xB8/0x96
+
+# Cold Balls
+K:367:0xB8/0x96
+
+# Fire Balls
+K:368:0xB8/0x97
+
+# Acid Balls
+K:369:0xB8/0x97
+
+# Acid Bolts
+K:370:0xB8/0x95
+
+# Enlightenment
+K:371:0xB8/0x97
+
+# Perception
+K:372:0xB8/0x96
+
+# Curing
+K:373:0xB8/0x97
+
+# Healing
+K:374:0xB8/0x97
+
+# Detection
+K:375:0xB8/0x95
+
+# Restoration
+K:376:0xB8/0x97
+
+# Speed
+K:377:0xB8/0x97
+
+# [Inner Void]
+K:378:0xA3/0x8E
+
+# [Lurkings of the Night]
+K:379:0xA3/0x8E
+
+# [Beings of Darkness]
+K:380:0xA3/0x8E
+
+# [Material Shadow]
+K:381:0xA3/0x8E
+
+# [Sign of Chaos]
+K:383:0xA3/0x90
+
+# [Chaos Mastery]
+K:384:0xA3/0x90
+
+# [Chaos Channels]
+K:385:0xA3/0x91
+
+# [Armageddon Tome]
+K:386:0xA3/0x91
+
+# [Nether Openings]
+K:387:0xA3/0x92
+
+# [Unholy Blessings]
+K:388:0xA3/0x92
+
+# & Firestone~
+K:389:0x8B/0x88
+
+# & Small Firestone~
+K:390:0x8B/0x89
+
+# & Broken Skull~
+K:391:0x8B/0x8A
+
+# & Broken Bone~
+K:392:0x8B/0x8B
+
+# & Canine Skeleton~
+K:393:0x8B/0x87
+
+# & Rodent Skeleton~
+K:394:0x8B/0x87
+
+# & Human Skeleton~
+K:395:0x8B/0x87
+
+# & Dwarf Skeleton~
+K:396:0x8B/0x87
+
+# & Elf Skeleton~
+K:397:0x8B/0x87
+
+# & Gnome Skeleton~
+K:398:0x8B/0x87
+
+# & Great Hammer~
+K:399:0xCD/0x87
+
+# Black Dragon Scale Mail~
+K:400:0x88/0x9F
+
+# Blue Dragon Scale Mail~
+K:401:0x88/0x9D
+
+# White Dragon Scale Mail~
+K:402:0x88/0x9E
+
+# Red Dragon Scale Mail~
+K:403:0x89/0x81
+
+# Green Dragon Scale Mail~
+K:404:0x89/0x80
+
+# Multi-Hued Dragon Scale Mail~
+K:405:0x89/0x82
+
+# Pseudo Dragon Scale Mail~
+K:406:0xBB/0x9C
+
+# Law Dragon Scale Mail~
+K:407:0x88/0x9F
+
+# Bronze Dragon Scale Mail~
+K:408:0x88/0x96
+
+# Gold Dragon Scale Mail~
+K:409:0x88/0x9C
+
+# Chaos Dragon Scale Mail~
+K:410:0x89/0x80
+
+# Balance Dragon Scale Mail~
+K:411:0x88/0x99
+
+# Power Dragon Scale Mail~
+K:412:0xA2/0x9E
+
+# & Dragon Helm~
+K:413:0xA2/0x9D
+
+# & Dragon Shield~
+K:414:0xA2/0x9C
+
+# Death
+K:415:0xBC/0x88
+
+# Ruination
+K:416:0xBC/0x87
+
+# Detonations
+K:417:0xBC/0x87
+
+# Augmentation
+K:418:0xBC/0x87
+
+# *Healing*
+K:419:0xBC/0x87
+
+# Life
+K:420:0xBC/0x88
+
+# Self Knowledge
+K:421:0xBC/0x87
+
+# *Enlightenment*
+K:422:0xBC/0x88
+
+# [Necromantic Incantations]
+K:423:0xA3/0x92
+
+# [Curses of Angmar]
+K:424:0xA3/0x92
+
+# Fear Resistance
+K:425:0xB5/0x81
+
+# Light and Darkness Resistance
+K:426:0xB5/0x81
+
+# Nether Resistance
+K:427:0xB5/0x81
+
+# Nexus Resistance
+K:428:0xB5/0x81
+
+# Sound Resistance
+K:429:0xB5/0x81
+
+# Confusion Resistance
+K:430:0xB5/0x81
+
+# Shard Resistance
+K:431:0xB5/0x81
+
+# Disenchantment Resistance
+K:432:0xB5/0x81
+
+# Chaos Resistance
+K:433:0xB5/0x81
+
+# Blindness Resistance
+K:434:0xB5/0x81
+
+# Lordly Protection
+K:435:0xB5/0x81
+
+# Extra Attacks
+K:436:0xB5/0x81
+
+# Cure Light Wounds
+K:437:0xBC/0x85
+
+# Clumsiness
+K:438:0xBC/0x85
+
+# Sickliness
+K:439:0xBC/0x85
+
+# Map of Bree
+K:440:0xD8/0x81
+
+# Map of Gondolin
+K:441:0xD8/0x81
+
+# Map of Lothlorien
+K:442:0xD8/0x81
+
+# Map of Minas Anor
+K:443:0xD8/0x81
+
+# & Silver Arrow~
+K:465:0xCE/0x91
+
+# & Silver Bolt~
+K:466:0xCE/0x92
+
+# Lightning Resistance
+K:467:0x87/0x80
+
+# Wisdom
+K:468:0x87/0x80
+
+# Regeneration
+K:469:0x87/0x80
+
+# Infravision
+K:470:0x87/0x80
+
+# Devotion
+K:471:0x87/0x80
+
+# Weaponmastery
+K:472:0x87/0x80
+
+# Trickery
+K:473:0x87/0x80
+
+# ESP
+K:474:0x87/0x80
+
+# Sustenance
+K:475:0x87/0x80
+
+# Palantir
+K:476:0xD8/0x8F
+
+# Elfstone 'Elessar'
+K:477:0xB6/0x8F
+
+# Jewel 'Evenstar'
+K:478:0xB6/0x90
+
+# Ring of Durin
+K:479:0xB5/0x8E
+
+# copper
+K:480:0x80/0x8B
+K:481:0x80/0x8B
+K:482:0x80/0x8B
+
+# silver
+K:483:0x80/0x8C
+K:484:0x80/0x8C
+K:485:0x80/0x8C
+
+# garnets
+K:486:0x80/0x8F
+K:487:0x80/0x8F
+
+# gold
+K:488:0x80/0x8D
+K:489:0x80/0x8D
+K:490:0x80/0x8D
+
+# opals
+K:491:0x80/0x90
+
+# sapphires
+K:492:0x80/0x91
+
+# rubies
+K:493:0x80/0x92
+
+# diamonds
+K:494:0x80/0x93
+
+# emeralds
+K:495:0x80/0x94
+
+# mithril
+K:496:0x80/0x8E
+
+# adamantite
+K:497:0xA3/0x95
+
+# & Mighty Hammer~
+K:498:0x87/0x9A
+
+# & Massive Iron Crown~
+K:499:0x87/0x9B
+
+# & Phial~
+K:500:0x87/0x9D
+
+# & Star~
+K:501:0x87/0x9E
+
+# & Arkenstone~
+K:502:0x87/0x9F
+
+# & Amulet~
+K:503:0xB6/0x82
+K:504:0xB6/0x83
+
+# & Necklace~
+K:505:0xB6/0x84
+
+# & Ring~
+K:506:0xB5/0x83
+K:507:0xB5/0x83
+K:508:0xB5/0x84
+K:509:0xB5/0x85
+K:510:0xB5/0x86
+K:511:0xB5/0x87
+
+# [Rites of Initiation]
+K:512:0xBC/0x91
+
+# [Ways of War]
+K:513:0xBC/0x91
+
+# [Divine Retribution]
+K:514:0xBC/0x92
+
+# [Essence of Fury]
+K:515:0xBC/0x92
+
+# [Novice Crafts]
+K:516:0xBC/0x95
+
+# [Arcane Channels]
+K:517:0xBC/0x95
+
+# [Sigils of Wizardry]
+K:518:0xBC/0x95
+
+# [Mana Focus]
+K:519:0xBC/0x95
+
+# Reflection
+K:520:0xB6/0x80
+
+# Anti-Magic
+K:521:0xB6/0x80
+
+# Anti-Teleportation
+K:522:0xB6/0x80
+
+# Resistance
+K:523:0xB6/0x80
+
+# & Zweihander~
+K:524:0xCD/0x88
+
+# & Dwarven Lantern~
+K:525:0xD8/0x86
+
+# Splint Mail~
+K:526:0xCD/0x8A
+
+# & Everburning Torch~
+K:527:0xD8/0x87
+
+# & Trifurcate Spear~
+K:528:0xCD/0x96
+
+# & Three Piece Rod~
+K:529:0xCD/0x8C
+
+# & Feanorian Lamp~
+K:530:0xD8/0x85
+
+# & Fur Cloak~
+K:531:0xCD/0x8E
+
+# Potion: Water Curing
+K:532:0xBC/0x84
+
+# & Hatchet~
+K:533:0xCD/0x90
+
+# Rhino Hide Armour~
+K:535:0xCD/0x91
+
+# Leather Jacket~
+K:536:0xCD/0x92
+
+# & Sickle~
+K:537:0xCD/0x93
+
+# [Psychoportation]
+K:538:0xA3/0x88
+
+# [Clairsentience]
+K:539:0xA3/0x88
+
+# [Telekinesis]
+K:540:0xA3/0x89
+
+# [Empathy]
+K:541:0xA3/0x89
+
+# & Club~
+K:542:0xCD/0x99
+
+# & Broad Spear~
+K:543:0xCD/0x9A
+
+# & Khopesh~
+K:544:0xCD/0x9B
+
+# & Flamberge~
+K:545:0xCD/0x9C
+
+# & Claymore~
+K:546:0xCD/0x9D
+
+# & Espadon~
+K:547:0xCD/0x9E
+
+# & Great Scimitar~
+K:548:0xCD/0x9F
+
+# Trapping Kit: Arrow
+K:549:0xD7/0x84
+
+# Trapping Kit: Bolt
+K:550:0xD7/0x83
+
+# & Fauchard~
+K:551:0xCE/0x82
+
+# & Guisarme~
+K:552:0xCE/0x83
+
+# & Heavy Lance~
+K:553:0xCE/0x84
+
+# & Basillard~
+K:554:0xCE/0x85
+
+# Trapping Kit: Catapult
+K:555:0xD7/0x82
+
+# Ring Mail~
+K:556:0xCE/0x87
+
+# Cord Armour~
+K:557:0xCE/0x88
+
+# Paper Armour~
+K:558:0xCE/0x89
+
+# Padded Armour~
+K:559:0xCE/0x8A
+
+# Trap Kit: Fumes
+K:560:0xD7/0x80
+
+# Stone and Hide Armour~
+K:561:0xCE/0x8C
+
+# Trap Kit: Magic
+K:562:0xD7/0x81
+
+# Trap Kit: Device
+K:563:0xD7/0x85
+
+# Scroll: Nothing
+K:564:0x86/0x80
+
+# Poison
+K:565:0xD9/0x82
+
+# Wand: Nothing
+K:566:0xB7/0x90
+
+# Ring: Nothing
+K:567:0xB5/0x80
+
+# Staff: Nothing
+K:568:0xB8/0x96
+
+# Rod Tip: Nothing
+K:569:0xB8/0x95
+
+# Explosion
+K:570:0xD9/0x82
+
+# Teleport
+K:571:0xD9/0x82
+
+# Amulet: Nothing
+K:572:0x87/0x80
+
+# & Blood~ of Life
+K:573:0x87/0x88
+
+# Cold
+K:574:0xD9/0x82
+
+# Fire
+K:575:0xD9/0x82
+
+# Acid
+K:576:0xD9/0x82
+
+# Mage Staff
+K:577:0xCE/0x97
+
+# Lightning
+K:578:0xB5/0x81
+
+# Life
+K:579:0xD9/0x82
+
+# Confusion
+K:580:0xD9/0x82
+
+# Light
+K:581:0xD9/0x82
+
+# Ring of F'Lar
+K:582:0xB5/0x8F
+
+# Invisibility
+K:583:0xB8/0x85
+
+# Chaos
+K:584:0xD9/0x82
+
+# Corruption
+K:585:0xB8/0x85
+
+# Invisibility
+K:586:0xB5/0x81
+
+# Time
+K:587:0xD9/0x82
+
+# Deep Thoughts
+K:588:0xD8/0x80
+
+# More Deep Thoughts
+K:589:0xD8/0x80
+
+# Compendium of Deep Thoughts
+K:590:0xD8/0x80
+
+# Artifact Lore Vol. I
+K:591:0xD8/0x80
+
+# Artifact Lore Vol. II
+K:592:0xD8/0x80
+
+# Artifact Lore Vol. III
+K:593:0xD8/0x80
+
+# Monstrous Compendium 1
+K:594:0xD8/0x80
+
+# Monstrous Compendium 2
+K:595:0xD8/0x80
+
+# Monstrous Compendium 3
+K:596:0xD8/0x80
+
+# Monstrous Compendium 4
+K:597:0xD8/0x80
+
+# Monstrous Compendium 5
+K:598:0xD8/0x80
+
+# Monstrous Compendium 6
+K:599:0xD8/0x80
+
+# Monstrous Compendium 7
+K:600:0xD8/0x80
+
+# Monstrous Compendium 8
+K:601:0xD8/0x80
+
+# Monstrous Compendium 9
+K:602:0xD8/0x80
+
+# Monstrous Compendium 10
+K:603:0xD8/0x80
+
+# Monstrous Compendium 11
+K:604:0xD8/0x80
+
+# Abomination
+K:605:0xBC/0x85
+
+# Shape of Wolf
+K:606:0xBC/0x85
+
+# Shape of Ape
+K:607:0xBC/0x85
+
+# Shape of Goat
+K:608:0xBC/0x85
+
+# Shape of Insect
+K:609:0xBC/0x85
+
+# Shape of Sparrow
+K:610:0xBC/0x85
+
+# Shape of Ent
+K:611:0xBC/0x85
+
+# Shape of Vampire
+K:612:0xBC/0x85
+
+# Shape of Spider
+K:613:0xBC/0x85
+
+# Shape of Mana ball
+K:614:0xBC/0x85
+
+# Shape of Fire cloud
+K:615:0xBC/0x85
+
+# Shape of Cold cloud
+K:616:0xBC/0x85
+
+# Shape of Chaos cloud
+K:617:0xBC/0x85
+
+# [Wolf]
+K:618:0xCE/0x93
+
+# [Ape]
+K:619:0xCE/0x93
+
+# [Goat]
+K:620:0xCE/0x93
+
+# [Insect]
+K:621:0xCE/0x93
+
+# [Sparrow]
+K:622:0xCE/0x93
+
+# [Ent]
+K:623:0xCE/0x93
+
+# [Vampire]
+K:624:0xCE/0x93
+
+# [Spider]
+K:625:0xCE/0x93
+
+# [Mana ball]
+K:626:0xCE/0x93
+
+# [Fire cloud]
+K:627:0xCE/0x93
+
+# [Cold cloud]
+K:628:0xCE/0x93
+
+# [Chaos Cloud]
+K:629:0xCE/0x93
+
+# [Ghost]
+K:630:0xCE/0x93
+
+# [Kobold]
+K:631:0xCE/0x93
+
+# [Dragon]
+K:632:0xCE/0x93
+
+# [Demon]
+K:633:0xCE/0x93
+
+# [Hound]
+K:634:0xCE/0x93
+
+# [Quylthulg]
+K:635:0xCE/0x93
+
+# [Maia]
+K:636:0xCE/0x93
+
+# [Serpent]
+K:637:0xCE/0x93
+
+# [Giant]
+K:638:0xCE/0x93
+
+# [Vala]
+K:639:0xCE/0x93
+
+# Magic
+K:640:0xD9/0x82
+
+# corpse
+K:641:0xB4/0x90
+
+# skeleton
+K:642:0xB4/0x8B
+
+# head
+K:643:0xB4/0x8E
+
+# skull
+K:644:0xB4/0x8F
+
+# raw meat
+K:645:0xB4/0x8C
+
+# Dragonrider Coat
+K:646:0xCE/0x98
+
+# Stone of Lore
+K:647:0xD8/0x90
+
+# small wooden boomerang
+K:648:0xCE/0x99
+
+# large wooden boomerang
+K:649:0xCE/0x9A
+
+# small metal boomerang
+K:650:0xCE/0x9B
+
+# large metal boomerang
+K:651:0xCE/0x9C
+
+# The Space-Time Anchor
+K:652:0xD8/0x91
+
+# Summon never-moving pet
+K:654:0x86/0x80
+
+# [Life in symbiosis]
+K:655:0xA3/0x84
+
+# [Perfect Symbiosis]
+K:656:0xA3/0x85
+
+# Cure Light Insanity
+K:657:0xBC/0x85
+
+# Cure Serious Insanity
+K:658:0xBC/0x85
+
+# Cure Critical Insanity
+K:659:0xBC/0x85
+
+# Cure Insanity
+K:660:0xBC/0x85
+
+# & Phial~
+K:661:0x87/0x9D
+
+# Craftmanship
+K:663:0x86/0x82
+
+# The One Ring
+K:664:0xD8/0x81
+
+# [Apprentice Handbook]
+K:665:0xA3/0x81
+
+# [Minstrel's Music]
+K:666:0xA3/0x81
+
+# [Harps of Rivendell]
+K:667:0x8A/0x90
+
+# [Lays of Beleriand]
+K:668:0x8A/0x90
+
+# & Flute~
+K:669:0xD8/0x88
+
+# & Drum~
+K:670:0xD8/0x89
+
+# & Harp~
+K:671:0xD8/0x8A
+
+# & Banjo~
+K:672:0xD8/0x8B
+
+# & Lute~
+K:673:0xD8/0x8C
+
+# & Mandolin~
+K:674:0xD8/0x8D
+
+# Palantir of Orthanc
+K:675:0xD8/0x8F
+
+# Egg
+K:676:0xD8/0x84
+
+# Reset Recall
+K:677:0x86/0x81
+
+# Divination
+K:678:0x86/0x81
+
+# Rune: Self
+K:679:0xDA/0x80
+
+# Rune: Ray
+K:680:0xDA/0x80
+
+# Rune: Sphere
+K:681:0xDA/0x80
+
+# Rune: Knowledge
+K:682:0xDA/0x80
+
+# Rune: Life
+K:683:0xDA/0x84
+
+# Rune: Fire
+K:684:0xDA/0x81
+
+# Rune: Cold
+K:685:0xDA/0x80
+
+# Rune: Lightning
+K:686:0xDA/0x85
+
+# Rune: Acid
+K:687:0xDA/0x88
+
+# Rune: Element
+K:688:0xDA/0x89
+
+# Rune: Chaos
+K:689:0xDA/0x83
+
+# Rune: Mind
+K:690:0xDA/0x84
+
+# Rune: Holding
+K:691:0xDA/0x84
+
+# Rune: Arrow
+K:692:0xDA/0x80
+
+# Rune: Power Surge
+K:693:0xDA/0x80
+
+# Rune: Armageddon
+K:694:0xDA/0x80
+
+# Rune: Gravity
+K:695:0xDA/0x82
+
+# Essence: Extra Life
+K:696:0xD9/0x82
+
+# Rune: Undeath
+K:697:0xDA/0x82
+
+# Rune: Protection
+K:698:0xDA/0x82
+
+# Horn
+K:699:0xD8/0x8E
+
+# The Ring of Precognition
+K:700:0xB5/0x8E
+
+# Sprig of Athelas
+K:701:0xCE/0x96
+
+# [Magic for Beginners]
+K:702:0x8A/0x80
+
+# [Conjurings and Tricks]
+K:703:0x8A/0x80
+
+# [Incantations and Illusions]
+K:704:0x8A/0x80
+
+# [Sorcery and Evocations]
+K:705:0x8A/0x80
+
+# [Beginners Handbook]
+K:706:0x8A/0x89
+
+# [Words of Wisdom]
+K:707:0x8A/0x89
+
+# [Chants and Blessings]
+K:708:0x8A/0x89
+
+# [Exorcism and Dispelling]
+K:709:0x8A/0x89
+
+# [Resistance of Scarabtarices]
+K:710:0x8A/0x88
+
+# [Mordenkainen's Escapes]
+K:711:0x8A/0x88
+
+# [Kelek's Grimoire of Power]
+K:712:0x8A/0x88
+
+# [Tenser's Transformations]
+K:713:0x8A/0x88
+
+# [Raal's Tome of Destruction]
+K:714:0x8A/0x88
+
+# [Ethereal Openings]
+K:715:0x8A/0x85
+
+# [Godly Insights]
+K:716:0x8A/0x85
+
+# [Purifications and Healing]
+K:717:0x8A/0x85
+
+# [Holy Infusions]
+K:718:0x8A/0x85
+
+# [Wrath of God]
+K:719:0x8A/0x85
+
+# & Old Scroll~ of Deincarnation
+K:720:0x85/0x80
+
+# Dark Sword
+K:721:0xCE/0x9D
+
+# Numenorean for beginners (I)
+K:722:0xD8/0x81
+
+# Numenorean for beginners (II)
+K:723:0xD8/0x81
+
+# Advanced lessons of Numenorean
+K:724:0xD8/0x81
+
+# Advanced lessons of Sindarin
+K:725:0xD8/0x81
+
+# & Shard~ of Pottery
+K:726:0x8B/0x88
+
+# & Broken Stick~
+K:727:0x8B/0x89
+
+# Wall Creation
+K:728:0xB5/0x80
+
+# [Illusions for Beginners]
+K:729:0xA3/0x86
+
+# [Tricks and Visions]
+K:730:0xA3/0x86
+
+# [Phantasms and Illusions]
+K:731:0xA3/0x86
+
+# [Shadows and Prisms]
+K:732:0xA3/0x86
+
+# [Serten's Immunities]
+K:733:0xA3/0x87
+
+# [Knowledge of Kenault]
+K:734:0xA3/0x87
+
+# [Otiluke's Spheres]
+K:735:0xA3/0x87
+
+# [Boccob's Book of Shadows]
+K:736:0xA3/0x87
+
+# [Bigby's Handbook]
+K:737:0xA3/0x87
+
+# [Hunt of Orome]
+K:738:0xA3/0x8B
+
+# [Holy Sanctifications]
+K:739:0xA3/0x8B
+
+# [Secrets of the Feanturi]
+K:740:0xA3/0x8B
+
+# [War of Wrath]
+K:741:0xA3/0x8B
+
+# [Gifts of Iluvatar]
+K:742:0xA3/0x8B
+
+# & Potion~ of Learning
+K:743:0x87/0x86
+
+# [Eye of Sauron]
+K:744:0xA3/0x93
+
+# [Flame of Udun]
+K:745:0xA3/0x93
+
+# [Corruptions of Melkor]
+K:746:0xA3/0x93
+
+# [Crescent of Morgul]
+K:747:0xA3/0x93
+
+# [Morgoth's Ring]
+K:748:0xA3/0x93
+
+# Scroll: Spell
+K:749:0x86/0x82
+
+# Staff: Wishing
+K:750:0xB9/0x9B
+
+# Khuzdul - The hidden tongue of the Dwarves
+K:751:0xD8/0x81
+
+# Nandorin for dummies
+K:752:0xD8/0x81
+
+# Advanced lessons of Orcish
+K:753:0xD8/0x81
+
+# Ring: Flying
+K:755:0xB5/0x80
+
+# [Powerful Sigils]
+K:756:0xA3/0x8D
+
+# [Disruptive Forces]
+K:758:0xA3/0x8D
+
+# [Forces of the Mind]
+K:759:0xA3/0x8D
+
+# [Power of Ancient Sorcerors]
+K:760:0xA3/0x8D
+
+# [Tricks of the Wild]
+K:761:0xBC/0x93
+
+# [Mastering the Rituals]
+K:762:0xBC/0x93
+
+# [Rites of Power]
+K:763:0xBC/0x94
+
+# [Tribal Power]
+K:764:0xBC/0x94
+
+# [Aiding Shades]
+K:765:0xA3/0x8F
+
+# [Morgoth's Space-Time Warpings]
+K:766:0xA3/0x8F
+
+# [Murazor's Tome of Conjuring & Dispelling]
+K:767:0xA3/0x8F
+
+# [Channeling the Void]
+K:768:0xA3/0x8F
+
+# [Sauron's Forgotten Tome]
+K:769:0xA3/0x8F
+
+# Ring of Phasing
+K:770:0xB5/0x8E
+
+# [Earth]
+K:771:0xD8/0x82
+
+# [Fire]
+K:772:0xD8/0x82
+
+# [Air]
+K:773:0xD8/0x83
+
+# [Water]
+K:774:0xD8/0x83
+
+# [Mana]
+K:775:0xD8/0x83
+
+# Rod Tip: Home Summoning
+K:776:0xB8/0x84
+
+# Shadow Blade
+K:777:0xCD/0x9C
+
+# Bluesteel Blade
+K:778:0xCE/0x9E
+
+# Amulet: of the Serpents
+K:779:0xB6/0x9F
+
+# Darkness
+K:780:0xD9/0x82
+
+# Knowledge
+K:781:0xD9/0x82
+
+# Force
+K:782:0xD9/0x82
+
+# Lightning
+K:783:0xD9/0x82
+
+# Mana
+K:784:0xD9/0x82
+
+# Nazgul Ring
+K:785:0xB5/0x85
+
+# Climbing Set
+K:786:0xD8/0x92
+
+# Adventurer's guide to Middle-earth
+K:787:0xD8/0x80
+
+# [Dark Incantations]
+K:788:0xCE/0x94
+
+# [Immortal Rituals]
+K:789:0xCE/0x94
+
+# [Minions of Azathoth]
+K:790:0xCE/0x95
+
+# [Demonthoughts]
+K:791:0xCE/0x95
+
+# [Hellfire Tome]
+K:792:0xCE/0x95
+
+# Rod: Wooden
+K:793:0xDB/0x80
+
+# Rod: Copper
+K:794:0xDB/0x81
+
+# Rod: Iron
+K:795:0xDB/0x82
+
+# Rod: Aluminium
+K:796:0xDB/0x83
+
+# Rod: Silver
+K:797:0xDB/0x84
+
+# Rod: Golden
+K:798:0xDB/0x85
+
+# Rod: Mithril
+K:799:0xDB/0x86
+
+# Rod: Adamantite
+K:800:0xDB/0x87
+
+# Greater Ration of Health
+K:801:0x8A/0x9E
+
+# Scroll of Mass Ressurrection
+K:802:0x86/0x82
+
+# Cleaver
+K:803:0xD8/0x93
+
+# Light War Axe
+K:804:0xD8/0x94
+
+# Slaughter Axe
+K:805:0xD8/0x95
+
+# Runestone
+K:806:0xDA/0x83
+
+# Fortune Cookie
+K:807:0x8A/0x93
+
+# Portable Hole
+K:808:0xD8/0x96
+
+# Ring: Critical Hits
+K:809:0xB5/0x82
+
+# Wand of Digging of Thrain
+K:810:0xB8/0x97
+
+# Gnarled Staff of Holy Fire of Mithrandir
+K:811:0xCE/0x9F
+
+# Partial Totem
+K:812:0xB4/0x82
+
+# True Totem
+K:813:0xB4/0x85
+
+# Player
+R:0:0x8C/0x81
+
+# Filthy street urchin
+R:1:0x9B/0x8A
+
+# Scrawny cat
+R:2:0x98/0x8B
+
+# Sparrow
+R:3:0xBD/0x87
+
+# Chaffinch
+R:4:0xBD/0x86
+
+# Wild rabbit
+R:5:0xBF/0x85
+
+# Woodsman
+R:6:0xBD/0x88
+
+# Scruffy little dog
+R:7:0x8E/0x9D
+
+# Farmer Maggot
+R:8:0x9B/0x8B
+
+# Blubbering idiot
+R:9:0x9B/0x8C
+
+# Boil-covered wretch
+R:10:0x9B/0x8D
+
+# Village idiot
+R:11:0x9B/0x8E
+
+# Pitiful-looking beggar
+R:12:0xBB/0x82
+
+# Mangy-looking leper
+R:13:0x9B/0x90
+
+# Agent of the black market
+R:14:0xA2/0x94
+
+# Singing, happy drunk
+R:15:0x9B/0x92
+
+# Aimless-looking merchant
+R:16:0x9B/0x93
+
+# Mean-looking mercenary
+R:17:0x9B/0x94
+
+# Battle-scarred veteran
+R:18:0x9B/0x95
+
+# Martti Ihrasaari
+R:19:0xA1/0x8D
+
+# Grey mold
+R:20:0x9A/0x88
+
+# Large white snake
+R:21:0x93/0x8A
+
+# Grey mushroom patch
+R:22:0x8E/0x85
+
+# Newt
+R:23:0xA0/0x86
+
+# Giant white centipede
+R:24:0x96/0x9E
+
+# White icky thing
+R:25:0x99/0x8C
+
+# Clear icky thing
+R:26:0x99/0x8D
+
+# Giant white mouse
+R:27:0x9D/0x8F
+
+# Large brown snake
+R:28:0x93/0x92
+
+# Small kobold
+R:29:0x9A/0x82
+
+# Kobold
+R:30:0x9A/0x83
+
+# White worm mass
+R:31:0x9E/0x88
+
+# Floating eye
+R:32:0x98/0x84
+
+# Rock lizard
+R:33:0x93/0x8B
+
+# Grid bug
+R:34:0xA2/0x9B
+
+# Jackal
+R:35:0x8E/0x9E
+
+# Soldier ant
+R:36:0x96/0x8F
+
+# Fruit bat
+R:37:0x96/0x98
+
+# Insect swarm
+R:38:0xBD/0x89
+
+# The Greater hell-beast
+R:39:0xA2/0x82
+
+# Shrieker mushroom patch
+R:40:0x8E/0x86
+
+# Blubbering icky thing
+R:41:0x99/0x8E
+
+# Metallic green centipede
+R:42:0x96/0x9F
+
+# Novice warrior
+R:43:0x9B/0x96
+
+# Novice rogue
+R:44:0x9B/0x97
+
+# Novice priest
+R:45:0x9B/0x98
+
+# Novice mage
+R:46:0x9B/0x99
+
+# Yellow mushroom patch
+R:47:0x8E/0x87
+
+# White jelly
+R:48:0x99/0x93
+
+# Giant black ant
+R:49:0x96/0x90
+
+# Salamander
+R:50:0x93/0x8D
+
+# White harpy
+R:51:0x91/0x8C
+
+# Blue yeek
+R:52:0x9E/0x92
+
+# Grip, Farmer Maggot's dog
+R:53:0x8E/0x9F
+
+# Wolf, Farmer Maggot's dog
+R:54:0xBD/0x8A
+
+# Fang, Farmer Maggot's dog
+R:55:0x8F/0x80
+
+# Giant green frog
+R:56:0x93/0x8C
+
+# Freesia
+R:57:0xBC/0x98
+
+# Green worm mass
+R:58:0x9E/0x89
+
+# Large yellow snake
+R:59:0x93/0x91
+
+# Cave spider
+R:60:0x94/0x82
+
+# Crow
+R:61:0xBD/0x8B
+
+# Wild cat
+R:62:0x98/0x8C
+
+# Smeagol
+R:63:0x9B/0x9A
+
+# Green ooze
+R:64:0x99/0x94
+
+# Poltergeist
+R:65:0x90/0x9D
+
+# Yellow jelly
+R:66:0x99/0x96
+
+# Metallic blue centipede
+R:67:0x97/0x80
+
+# Raven
+R:68:0xBD/0x8C
+
+# Giant white louse
+R:69:0x9A/0x86
+
+# Giant yellow centipede
+R:70:0x96/0x9D
+
+# Black naga
+R:71:0x9A/0x91
+
+# Spotted mushroom patch
+R:72:0x8E/0x88
+
+# Silver jelly
+R:73:0x99/0x95
+
+# Scruffy-looking hobbit
+R:74:0x98/0x9C
+
+# Giant white ant
+R:75:0x96/0x91
+
+# Yellow mold
+R:76:0x9A/0x89
+
+# Metallic red centipede
+R:77:0x97/0x81
+
+# Yellow worm mass
+R:78:0x9E/0x8A
+
+# Clear worm mass
+R:79:0x9E/0x8B
+
+# Radiation eye
+R:80:0x98/0x85
+
+# Yellow light
+R:81:0xBD/0x92
+
+# Cave lizard
+R:82:0x93/0x8F
+
+# Novice ranger
+R:83:0x9B/0x9B
+
+# Blue jelly
+R:84:0x99/0x97
+
+# Creeping copper coins
+R:85:0x8E/0x80
+
+# Giant white rat
+R:86:0x9D/0x90
+
+# Snotling
+R:87:0xBD/0x8D
+
+# Swordfish
+R:88:0xBE/0x81
+
+# Blue worm mass
+R:89:0x9E/0x8C
+
+# Large grey snake
+R:90:0x93/0x90
+
+# Skeleton kobold
+R:91:0x9D/0x93
+
+# Ewok
+R:92:0xBB/0x90
+
+# Novice mage
+R:93:0x9B/0x9D
+
+# Green naga
+R:94:0x9A/0x92
+
+# Giant leech
+R:95:0xBD/0x8E
+
+# Barracuda
+R:96:0xBE/0x82
+
+# Novice paladin
+R:97:0x9B/0x9C
+
+# Zog
+R:98:0xBD/0x8F
+
+# Blue ooze
+R:99:0x99/0x98
+
+# Green glutton ghost
+R:100:0x90/0x9E
+
+# Green jelly
+R:101:0x99/0x99
+
+# Large kobold
+R:102:0x9A/0x84
+
+# Grey icky thing
+R:103:0x99/0x8F
+
+# Disenchanter eye
+R:104:0x98/0x86
+
+# Red worm mass
+R:105:0x9E/0x8D
+
+# Copperhead snake
+R:106:0x93/0x91
+
+# Death sword
+R:107:0x89/0x85
+
+# Purple mushroom patch
+R:108:0x8E/0x89
+
+# Novice priest
+R:109:0x9B/0x9E
+
+# Novice warrior
+R:110:0x9B/0x9F
+
+# Nibelung
+R:111:0xBB/0x8E
+
+# The disembodied hand that strangled people
+R:112:0x9F/0x87
+
+# Brown mold
+R:113:0x9A/0x8A
+
+# Giant brown bat
+R:114:0x96/0x99
+
+# Rat-thing
+R:115:0xBD/0x90
+
+# Novice rogue
+R:116:0x9C/0x81
+
+# Creeping silver coins
+R:117:0x8E/0x81
+
+# Snaga
+R:118:0x9A/0x97
+
+# Rattlesnake
+R:119:0x93/0x92
+
+# Giant slug
+R:120:0xBD/0x93
+
+# Giant pink frog
+R:121:0x93/0x93
+
+# Dark elf
+R:122:0x98/0x9E
+
+# Zombified kobold
+R:123:0x9E/0x97
+
+# Crypt creep
+R:124:0x9F/0x93
+
+# Rotting corpse
+R:125:0xBB/0x8B
+
+# Cave orc
+R:126:0x9A/0x98
+
+# Wood spider
+R:127:0x94/0x83
+
+# Manes
+R:128:0x91/0x96
+
+# Bloodshot eye
+R:129:0x98/0x87
+
+# Red naga
+R:130:0x9A/0x93
+
+# Red jelly
+R:131:0x99/0x9A
+
+# Green icky thing
+R:132:0x99/0x90
+
+# Lost soul
+R:133:0x90/0x9F
+
+# Night lizard
+R:134:0x93/0x94
+
+# Mughash, the Kobold Lord
+R:135:0x9A/0x85
+
+# Skeleton orc
+R:136:0x9D/0x94
+
+# Wormtongue, Agent of Saruman
+R:137:0xBC/0x9A
+
+# Robin Hood, the Outlaw
+R:138:0xBB/0x88
+
+# Nurgling
+R:139:0xBD/0x94
+
+# Lagduf, the Snaga
+R:140:0x9A/0x99
+
+# Brown yeek
+R:141:0x9E/0x93
+
+# Novice ranger
+R:142:0x9B/0x9B
+
+# Giant salamander
+R:143:0x93/0x95
+
+# Space monster
+R:144:0x8A/0x9B
+
+# Carnivorous flying monkey
+R:145:0xBD/0x95
+
+# Green mold
+R:146:0x9A/0x8B
+
+# Novice paladin
+R:147:0x9B/0x9C
+
+# Lemure
+R:148:0x91/0x97
+
+# Hill orc
+R:149:0x9A/0x9A
+
+# Bandit
+R:150:0x9C/0x85
+
+# Hunting hawk
+R:151:0x96/0x99
+
+# Phantom warrior
+R:152:0xA0/0x83
+
+# Gremlin
+R:153:0xA1/0x86
+
+# Yeti
+R:154:0x95/0x99
+
+# Bloodshot icky thing
+R:155:0x99/0x91
+
+# Giant grey rat
+R:156:0x9D/0x91
+
+# Black harpy
+R:157:0x91/0x8D
+
+# Skaven
+R:158:0xBD/0x96
+
+# The wounded bear
+R:159:0xBD/0x98
+
+# Cave bear
+R:160:0xB0/0x82
+
+# Rock mole
+R:161:0xBD/0x99
+
+# Mindcrafter
+R:162:0xB0/0x85
+
+# Baby blue dragon
+R:163:0x97/0x86
+
+# Baby white dragon
+R:164:0x97/0x87
+
+# Baby green dragon
+R:165:0x97/0x88
+
+# Baby black dragon
+R:166:0x97/0x89
+
+# Baby red dragon
+R:167:0x97/0x8A
+
+# Giant red ant
+R:168:0x96/0x96
+
+# Brodda, the Easterling
+R:169:0x9C/0x86
+
+# Bloodfang, the Wolf
+R:170:0xBD/0x9A
+
+# King cobra
+R:171:0x93/0x96
+
+# Eagle
+R:172:0xBD/0x9B
+
+# War bear
+R:173:0x9F/0x9D
+
+# Killer bee
+R:174:0xA0/0x88
+
+# Giant spider
+R:175:0x94/0x87
+
+# Giant white tick
+R:176:0x9D/0x9C
+
+# The Borshin
+R:177:0xBD/0x9C
+
+# Dark elven mage
+R:178:0x98/0x9F
+
+# Kamikaze yeek
+R:179:0xBD/0x9D
+
+# Orfax, Son of Boldor
+R:180:0x9E/0x94
+
+# Servant of Glaaki
+R:181:0xBD/0x9E
+
+# Dark elven warrior
+R:182:0x99/0x80
+
+# Sand-dweller
+R:183:0xBF/0x80
+
+# Clear mushroom patch
+R:184:0x8E/0x8A
+
+# Quiver slot
+R:185:0x89/0x9A
+
+# Grishnakh, the Hill Orc
+R:186:0x9A/0x9C
+
+# Giant tan bat
+R:187:0x96/0x99
+
+# Owlbear
+R:188:0xBF/0x81
+
+# Blue horror
+R:189:0xBF/0x82
+
+# Hairy mold
+R:190:0x9A/0x8C
+
+# Grizzly bear
+R:191:0xBF/0x83
+
+# Disenchanter mold
+R:192:0x9A/0x8D
+
+# Pseudo dragon
+R:193:0xBB/0x9B
+
+# Tengu
+R:194:0x91/0x98
+
+# Creeping gold coins
+R:195:0x8E/0x82
+
+# Wolf
+R:196:0x8F/0x81
+
+# Giant fruit fly
+R:197:0x90/0x95
+
+# Panther
+R:198:0x98/0x8D
+
+# Brigand
+R:199:0x9C/0x87
+
+# Hobbes the Tiger
+R:200:0x98/0x8E
+
+# Shadow Creature of Fiona
+R:201:0xBB/0x8F
+
+# Undead mass
+R:202:0xA0/0x89
+
+# Chaos shapechanger
+R:203:0xA0/0x8E
+
+# Baby multi-hued dragon
+R:204:0x97/0x8C
+
+# Vorpal bunny
+R:205:0xBF/0x84
+
+# Old Man Willow
+R:206:0xBF/0x86
+
+# Hippocampus
+R:207:0xBE/0x85
+
+# Zombified orc
+R:208:0x9E/0x98
+
+# Hippogriff
+R:209:0x91/0x8E
+
+# Black mamba
+R:210:0x93/0x97
+
+# White wolf
+R:211:0x8F/0x82
+
+# Grape jelly
+R:212:0x99/0x9B
+
+# Nether worm mass
+R:213:0x9E/0x8E
+
+# Abyss worm mass
+R:214:0xA0/0x8C
+
+# Golfimbul, the Hill Orc Chief
+R:215:0x9A/0x9D
+
+# Swordsman
+R:216:0x9C/0x89
+
+# Skaven shaman
+R:217:0xBD/0x97
+
+# Baby bronze dragon
+R:218:0xB0/0x89
+
+# Baby gold dragon
+R:219:0xB0/0x8A
+
+# Evil eye
+R:220:0xB0/0x8B
+
+# Mine-dog
+R:221:0xBF/0x88
+
+# Hellcat
+R:222:0xBC/0x97
+
+# Moon beast
+R:223:0xBB/0x9E
+
+# Master yeek
+R:224:0x9E/0x95
+
+# Priest
+R:225:0x9C/0x88
+
+# Dark elven priest
+R:226:0x99/0x82
+
+# Air spirit
+R:227:0x90/0x83
+
+# Skeleton human
+R:228:0x9D/0x95
+
+# Zombified human
+R:229:0x9E/0x99
+
+# Tiger
+R:230:0x98/0x8E
+
+# Moaning spirit
+R:231:0x91/0x80
+
+# Stegocentipede
+R:232:0x97/0x82
+
+# Spotted jelly
+R:233:0x99/0x9C
+
+# Drider
+R:234:0x94/0x85
+
+# Mongbat
+R:235:0xC4/0x80
+
+# Killer brown beetle
+R:236:0x92/0x80
+
+# Boldor, King of the Yeeks
+R:237:0x9E/0x96
+
+# Ogre
+R:238:0x92/0x90
+
+# Creeping mithril coins
+R:239:0x8E/0x83
+
+# Illusionist
+R:240:0x9C/0x8A
+
+# Druid
+R:241:0x9C/0x8B
+
+# Pink horror
+R:242:0xBF/0x89
+
+# Cloaker
+R:243:0xBF/0x8A
+
+# Black orc
+R:244:0x9A/0x9E
+
+# Ochre jelly
+R:245:0x99/0x9D
+
+# Software bug
+R:246:0xA0/0x92
+
+# Lurker
+R:247:0x80/0x80
+
+# Tangleweed
+R:248:0xBE/0x9E
+
+# Vlasta
+R:249:0xBF/0x8C
+
+# Giant white dragon fly
+R:250:0x90/0x97
+
+# Snaga sapper
+R:251:0xBF/0x8D
+
+# Blue icky thing
+R:252:0x99/0x92
+
+# Gibbering mouther
+R:253:0xA0/0x8A
+
+# Wolfhound of Flora
+R:254:0xA0/0x91
+
+# Hill giant
+R:255:0x92/0x96
+
+# Flesh golem
+R:256:0x98/0x92
+
+# Warg
+R:257:0x8F/0x83
+
+# Cheerful leprechaun
+R:258:0xA0/0x93
+
+# Giant flea
+R:259:0x90/0x96
+
+# Ufthak of Cirith Ungol
+R:260:0x9A/0x9F
+
+# Clay golem
+R:261:0x98/0x93
+
+# Black ogre
+R:262:0x92/0x91
+
+# Dweller on the threshold
+R:263:0xC4/0x83
+
+# Half-orc
+R:264:0x9B/0x80
+
+# Dark naga
+R:265:0xBF/0x8E
+
+# Poison ivy
+R:266:0xBE/0x9C
+
+# Magic mushroom patch
+R:267:0x8E/0x8B
+
+# Plaguebearer of Nurgle
+R:268:0xBF/0x8F
+
+# Guardian naga
+R:269:0x9A/0x94
+
+# Wererat
+R:270:0x9D/0x92
+
+# Light hound
+R:271:0x95/0x9B
+
+# Dark hound
+R:272:0x95/0x9C
+
+# Flying skull
+R:273:0xA0/0x95
+
+# Mi-Go
+R:274:0x9F/0x9F
+
+# Giant tarantula
+R:275:0x94/0x86
+
+# Giant clear centipede
+R:276:0x97/0x83
+
+# Mirkwood spider
+R:277:0x94/0x84
+
+# Frost giant
+R:278:0x92/0x97
+
+# Griffon
+R:279:0x91/0x8F
+
+# Homunculus
+R:280:0x91/0x99
+
+# Gnome mage
+R:281:0x99/0x83
+
+# Clear hound
+R:282:0x95/0x9D
+
+# Umber hulk
+R:283:0x94/0x9E
+
+# Rust monster
+R:284:0xBF/0x90
+
+# Ogrillon
+R:285:0xB0/0x8C
+
+# Gelatinous cube
+R:286:0x99/0x9E
+
+# Giant green dragon fly
+R:287:0x90/0x98
+
+# Fire giant
+R:288:0x92/0x98
+
+# Hummerhorn
+R:289:0x90/0x99
+
+# Lizard man
+R:290:0xBF/0x91
+
+# Ulfast, Son of Ulfang
+R:291:0x9C/0x8C
+
+# Crebain
+R:292:0xC4/0x94
+
+# Berserker
+R:293:0xBF/0x92
+
+# Quasit
+R:294:0x91/0x9A
+
+# Sphinx
+R:295:0xBF/0x93
+
+# Imp
+R:296:0x91/0x9B
+
+# Forest troll
+R:297:0x94/0x8E
+
+# Freezing sphere
+R:298:0xBF/0x94
+
+# Jumping fireball
+R:299:0xBF/0x95
+
+# Ball lightning
+R:300:0xBF/0x96
+
+# 2-headed hydra
+R:301:0x93/0x98
+
+# Swamp thing
+R:302:0xBF/0x97
+
+# Water spirit
+R:303:0x90/0x84
+
+# Giant red scorpion
+R:304:0x94/0x8C
+
+# Earth spirit
+R:305:0x90/0x85
+
+# Fire spirit
+R:306:0x90/0x86
+
+# Fire hound
+R:307:0x95/0x9E
+
+# Cold hound
+R:308:0x95/0x9F
+
+# Energy hound
+R:309:0x96/0x80
+
+# Lesser Mimic
+R:310:0x8E/0x8F
+
+# Door mimic
+R:311:0xBF/0x98
+
+# Blink dog
+R:312:0x8F/0x84
+
+# Uruk
+R:313:0x9B/0x82
+
+# Shagrat, the Orc Captain
+R:314:0x9B/0x83
+
+# Gorbag, the Orc Captain
+R:315:0x9B/0x84
+
+# Shambling mound
+R:316:0x8E/0x8C
+
+# Giant Venus Flytrap
+R:317:0xBE/0x9D
+
+# Chaos beastman
+R:318:0xBF/0x99
+
+# Daemonette of Slaanesh
+R:319:0xBF/0x9A
+
+# Giant bronze dragon fly
+R:320:0x90/0x9C
+
+# Stone giant
+R:321:0x92/0x99
+
+# Giant black dragon fly
+R:322:0x90/0x9A
+
+# Stone golem
+R:323:0x98/0x94
+
+# Red mold
+R:324:0x9A/0x8E
+
+# Giant gold dragon fly
+R:325:0x90/0x9B
+
+# Stunwall
+R:326:0xBF/0x9B
+
+# Ghast
+R:327:0xBF/0x9C
+
+# Neekerbreeker
+R:328:0xBE/0x86
+
+# Huorn
+R:329:0xBF/0x9D
+
+# Bolg, Son of Azog
+R:330:0x9B/0x85
+
+# Phase spider
+R:331:0x94/0x89
+
+# Lizard king
+R:332:0xBF/0x9E
+
+# Landmine
+R:333:0xBF/0x9F
+
+# Wyvern
+R:334:0xA0/0x97
+
+# Great eagle
+R:335:0xC0/0x80
+
+# Livingstone
+R:336:0x80/0x82
+
+# Earth hound
+R:337:0x96/0x81
+
+# Air hound
+R:338:0x96/0x82
+
+# Sabre-tooth tiger
+R:339:0x98/0x8F
+
+# Acid hound
+R:340:0x96/0x83
+
+# Chimaera
+R:341:0x91/0x90
+
+# Quylthulg
+R:342:0x92/0x9F
+
+# Sasquatch
+R:343:0x95/0x9A
+
+# Weir
+R:344:0xA0/0x96
+
+# Ranger
+R:345:0x9C/0x83
+
+# Paladin
+R:346:0x8D/0x9C
+
+# Werewolf
+R:347:0x8F/0x85
+
+# Dark elven lord
+R:348:0x99/0x85
+
+# Cloud giant
+R:349:0x92/0x9A
+
+# Ugluk, the Uruk
+R:350:0x9B/0x86
+
+# Blue dragon bat
+R:351:0x96/0x9A
+
+# Mimic
+R:352:0x86/0x82
+
+# Ultimate Mimic
+R:353:0xC0/0x83
+
+# Fire vortex
+R:354:0x9D/0x9E
+
+# Acid vortex
+R:355:0x9D/0x9F
+
+# Lugdush, the Uruk
+R:356:0x9B/0x87
+
+# Arch-vile
+R:357:0xC0/0x84
+
+# Cold vortex
+R:358:0x9E/0x80
+
+# Energy vortex
+R:359:0x9E/0x81
+
+# Globefish
+R:360:0xBE/0x8D
+
+# Giant firefly
+R:361:0xB0/0x8D
+
+# Mummified orc
+R:362:0x92/0x8D
+
+# Wolf chieftain
+R:363:0xBE/0x8E
+
+# Serpent man
+R:364:0xC0/0x85
+
+# Vampiric mist
+R:365:0xC0/0x86
+
+# Killer stag beetle
+R:366:0x92/0x81
+
+# Iron golem
+R:367:0x98/0x95
+
+# Auto-roller
+R:368:0xA0/0x98
+
+# Giant yellow scorpion
+R:369:0x94/0x8A
+
+# Jade monk
+R:370:0xC0/0x87
+
+# Black ooze
+R:371:0x99/0x9F
+
+# Hardened warrior
+R:372:0x9C/0x8D
+
+# Azog, King of the Uruk-Hai
+R:373:0x9B/0x88
+
+# Fleshhound of Khorne
+R:374:0xC0/0x89
+
+# Dark elven warlock
+R:375:0xA0/0x81
+
+# Master rogue
+R:376:0x9C/0x8E
+
+# Red dragon bat
+R:377:0x96/0x9B
+
+# Killer white beetle
+R:378:0x96/0x91
+
+# Ice skeleton
+R:379:0xC0/0x8A
+
+# Angamaite of Umbar
+R:380:0x9C/0x90
+
+# Forest wight
+R:381:0x95/0x83
+
+# Khim, Son of Mim
+R:382:0x99/0x87
+
+# Ibun, Son of Mim
+R:383:0x99/0x86
+
+# Meneldor the Swift
+R:384:0xC0/0x8B
+
+# Phantom beast
+R:385:0xA0/0x84
+
+# Giant silver ant
+R:386:0xB0/0x87
+
+# 4-headed hydra
+R:387:0x93/0x9A
+
+# Lesser hell-beast
+R:388:0xC0/0x8C
+
+# Tyrannosaur
+R:389:0x9F/0x94
+
+# Mummified human
+R:390:0x92/0x8E
+
+# Vampire bat
+R:391:0x96/0x9C
+
+# Sangahyando of Umbar
+R:392:0x9C/0x8F
+
+# It
+R:393:0x80/0x80
+
+# Banshee
+R:394:0x91/0x81
+
+# Carrion crawler
+R:395:0x97/0x84
+
+# Xiclotlan
+R:396:0xC0/0x8D
+
+# Silent watcher
+R:397:0xA0/0x9A
+
+# Pukelman
+R:398:0x98/0x96
+
+# Disenchanter beast
+R:399:0xC0/0x8E
+
+# Dark elven druid
+R:400:0x99/0x88
+
+# Stone troll
+R:401:0x94/0x9A
+
+# Black
+R:402:0xC0/0x8F
+
+# Hill troll
+R:403:0xB0/0x8F
+
+# Wereworm
+R:404:0x9E/0x8F
+
+# Killer red beetle
+R:405:0x92/0x83
+
+# Disenchanter bat
+R:406:0xB0/0x9B
+
+# Gnoph-Keh
+R:407:0xC0/0x90
+
+# Giant grey ant
+R:408:0x96/0x95
+
+# Khufu, the Mummified King
+R:409:0xA0/0x9C
+
+# Gwaihir the Windlord
+R:410:0xC0/0x91
+
+# Giant fire tick
+R:411:0x9D/0x9D
+
+# Displacer beast
+R:412:0x98/0x90
+
+# Ulwarth, Son of Ulfang
+R:413:0x9C/0x91
+
+# Werebear
+R:414:0xB1/0x96
+
+# Cave ogre
+R:415:0x92/0x92
+
+# White wraith
+R:416:0x95/0x84
+
+# Angel
+R:417:0x8E/0x92
+
+# Ghoul
+R:418:0xBB/0x8C
+
+# Mim, Betrayer of Turin
+R:419:0x99/0x89
+
+# Hellblade
+R:420:0x89/0x87
+
+# Killer fire beetle
+R:421:0x92/0x84
+
+# Beast of Nurgle
+R:422:0xC0/0x92
+
+# Creeping adamantite coins
+R:423:0x8E/0x84
+
+# Algroth
+R:424:0x94/0x91
+
+# Flamer of Tzeentch
+R:425:0xC0/0x93
+
+# Roper
+R:426:0xC0/0x94
+
+# Headless
+R:427:0x9F/0x86
+
+# Vibration hound
+R:428:0x96/0x84
+
+# Nexus hound
+R:429:0x96/0x8A
+
+# Half-ogre
+R:430:0xB0/0x9E
+
+# Lokkak, the Ogre Chieftain
+R:431:0xA1/0x80
+
+# Vampire
+R:432:0x94/0x9F
+
+# Gorgimaera
+R:433:0x91/0x91
+
+# Shantak
+R:434:0xA0/0x9D
+
+# Colbran
+R:435:0x98/0x97
+
+# Spirit naga
+R:436:0x9A/0x95
+
+# Corpser
+R:437:0xC0/0x95
+
+# Fiend of Slaanesh
+R:438:0xC0/0x96
+
+# Stairway to Hell
+R:439:0x81/0x9E
+
+# 5-headed hydra
+R:440:0x93/0x9B
+
+# Barney the Dinosaur
+R:441:0x9F/0x96
+
+# Black knight
+R:442:0x9C/0x92
+
+# Seahorse
+R:443:0xBE/0x91
+
+# Cyclops
+R:444:0xC0/0x97
+
+# Clairvoyant
+R:445:0xC0/0x98
+
+# Purple worm
+R:446:0x9E/0x90
+
+# Catoblepas
+R:447:0x9D/0x8B
+
+# Lesser wall monster
+R:448:0x80/0x82
+
+# Mage
+R:449:0x9C/0x94
+
+# Mind flayer
+R:450:0x9C/0x95
+
+# The Ultimate Dungeon Cleaner
+R:451:0xA0/0x99
+
+# Deep one
+R:452:0xC0/0x99
+
+# Basilisk
+R:453:0xBB/0x9F
+
+# Ice troll
+R:454:0x94/0x92
+
+# Dhole
+R:455:0xA1/0x82
+
+# Archangel
+R:456:0x8E/0x93
+
+# Greater Mimic
+R:457:0x82/0x81
+
+# Chaos tile
+R:458:0xA2/0x86
+
+# Young blue dragon
+R:459:0x97/0x8D
+
+# Young white dragon
+R:460:0x97/0x8E
+
+# Young green dragon
+R:461:0x97/0x8F
+
+# Young bronze dragon
+R:462:0x97/0x90
+
+# Aklash
+R:463:0xC0/0x9A
+
+# Mithril golem
+R:464:0x98/0x98
+
+# Skeleton troll
+R:465:0x9D/0x96
+
+# Skeletal tyrannosaur
+R:466:0xC0/0x9B
+
+# Beorn, the Shape-Changer
+R:467:0xA1/0x92
+
+# Thorondor, Lord of Eagles
+R:468:0xC0/0x9C
+
+# Giant blue ant
+R:469:0x96/0x94
+
+# Grave wight
+R:470:0x95/0x85
+
+# Shadow drake
+R:471:0x97/0x91
+
+# Manticore
+R:472:0x91/0x92
+
+# Giant army ant
+R:473:0x96/0x95
+
+# Killer slicer beetle
+R:474:0x92/0x85
+
+# Gorgon
+R:475:0xC0/0x9D
+
+# Gug
+R:476:0xC0/0x9E
+
+# Ghost
+R:477:0x91/0x82
+
+# Death watch beetle
+R:478:0x92/0x86
+
+# Mountain ogre
+R:479:0x92/0x95
+
+# Nexus quylthulg
+R:480:0x93/0x80
+
+# Shelob, Spider of Darkness
+R:481:0x94/0x8B
+
+# Giant squid
+R:482:0xBE/0x87
+
+# Ghoulking
+R:483:0xC0/0x9F
+
+# Doombat
+R:484:0xC1/0x80
+
+# Ninja
+R:485:0x9C/0x96
+
+# Memory moss
+R:486:0x9A/0x8F
+
+# Storm giant
+R:487:0x92/0x9B
+
+# Spectator
+R:488:0xA0/0x85
+
+# Bokrug
+R:489:0xC1/0x81
+
+# Biclops
+R:490:0xC1/0x82
+
+# Half-troll
+R:491:0x94/0x94
+
+# Ivory monk
+R:492:0xC0/0x88
+
+# Bert the Stone Troll
+R:493:0x94/0x95
+
+# Bill the Stone Troll
+R:494:0x94/0x96
+
+# Tom the Stone Troll
+R:495:0x94/0x97
+
+# Cave troll
+R:496:0x94/0x93
+
+# Anti-paladin
+R:497:0xA1/0x84
+
+# Chaos master
+R:498:0xBB/0x84
+
+# Barrow wight
+R:499:0x95/0x86
+
+# Skeleton ettin
+R:500:0x9D/0x97
+
+# Chaos drake
+R:501:0xBB/0x9A
+
+# Law drake
+R:502:0x97/0x93
+
+# Balance drake
+R:503:0x97/0x94
+
+# Ethereal drake
+R:504:0x97/0x95
+
+# Groo, the Wanderer
+R:505:0xA1/0x81
+
+# Fasolt the Giant
+R:506:0xBB/0x83
+
+# Shade
+R:507:0x91/0x83
+
+# Spectre
+R:508:0xA2/0x85
+
+# Water troll
+R:509:0x94/0x98
+
+# Fire elemental
+R:510:0x90/0x87
+
+# Cherub
+R:511:0x8E/0x94
+
+# Water elemental
+R:512:0x90/0x88
+
+# Multi-hued hound
+R:513:0xA2/0x83
+
+# Invisible stalker
+R:514:0x90/0x89
+
+# Carrion crawler
+R:515:0x97/0x85
+
+# Master thief
+R:516:0x9C/0x98
+
+# The Watcher in the Water
+R:517:0xBB/0x87
+
+# Lich
+R:518:0x92/0x88
+
+# Gas spore
+R:519:0xC1/0x83
+
+# Master vampire
+R:520:0x95/0x80
+
+# Oriental vampire
+R:521:0xA1/0x88
+
+# Greater mummy
+R:522:0xC1/0x84
+
+# Bloodletter of Khorne
+R:523:0xC1/0x85
+
+# Giant grey scorpion
+R:524:0xBB/0x9D
+
+# Earth elemental
+R:525:0x90/0x8A
+
+# Air elemental
+R:526:0x90/0x8B
+
+# Shimmering mold
+R:527:0xA2/0x93
+
+# Gargoyle
+R:528:0xC1/0x86
+
+# Malicious leprechaun
+R:529:0xA0/0x94
+
+# Eog golem
+R:530:0x98/0x99
+
+# Little Boy
+R:531:0xC0/0x81
+
+# Dagashi
+R:532:0x9C/0x9A
+
+# Headless ghost
+R:533:0xC1/0x87
+
+# Dread
+R:534:0x91/0x85
+
+# Gauth
+R:536:0xC5/0x8D
+
+# Leng spider
+R:535:0xC1/0x88
+
+# Smoke elemental
+R:537:0x90/0x8D
+
+# Olog
+R:538:0x94/0x99
+
+# Halfling slinger
+R:539:0xBB/0x91
+
+# Gravity hound
+R:540:0x96/0x86
+
+# Acidic cytoplasm
+R:541:0x9A/0x80
+
+# Inertia hound
+R:542:0x96/0x87
+
+# Impact hound
+R:543:0x96/0x88
+
+# Shardstorm
+R:544:0xB0/0x9F
+
+# Ooze elemental
+R:545:0x90/0x8C
+
+# Young black dragon
+R:546:0x97/0x96
+
+# Mumak
+R:547:0x9D/0x8C
+
+# Giant fire ant
+R:548:0x96/0x96
+
+# Mature white dragon
+R:549:0x97/0x97
+
+# Xorn
+R:550:0x95/0x97
+
+# Rogrog the Black Troll
+R:551:0x94/0x9A
+
+# Mist giant
+R:552:0xC1/0x8A
+
+# Phantom
+R:553:0x91/0x87
+
+# Grey wraith
+R:554:0x95/0x87
+
+# Revenant
+R:555:0xC1/0x8B
+
+# Young multi-hued dragon
+R:556:0x97/0x98
+
+# Raal's Tome of Destruction
+R:557:0xA3/0x91
+
+# Colossus
+R:558:0xA0/0x80
+
+# Young gold dragon
+R:559:0x97/0x99
+
+# Mature blue dragon
+R:560:0x97/0x9A
+
+# Mature green dragon
+R:561:0x97/0x9B
+
+# Mature bronze dragon
+R:562:0x97/0x9C
+
+# Young red dragon
+R:563:0x97/0x9D
+
+# Nightblade
+R:564:0xBB/0x92
+
+# Trapper
+R:565:0x8E/0x8E
+
+# Bodak
+R:566:0x91/0x9D
+
+# Time bomb
+R:567:0xC1/0x8C
+
+# Mezzodaemon
+R:568:0xC1/0x8D
+
+# Elder thing
+R:569:0x9F/0x9E
+
+# Ice elemental
+R:570:0x90/0x8E
+
+# Necromancer
+R:571:0x9C/0x9B
+
+# The Greater hell magic mushroom were-quylthulg
+R:572:0xB1/0x97
+
+# Lorgan, Chief of the Easterlings
+R:573:0x9C/0x9C
+
+# Chaos spawn
+R:574:0x9F/0x85
+
+# Mummified troll
+R:575:0x92/0x8F
+
+# Storm of Unmagic
+R:576:0xB1/0x98
+
+# Crypt thing
+R:577:0xC1/0x90
+
+# Chaos butterfly
+R:578:0xC1/0x92
+
+# Time elemental
+R:579:0xA2/0x84
+
+# Flying polyp
+R:580:0xC1/0x93
+
+# The Queen Ant
+R:581:0x96/0x97
+
+# Will o' the wisp
+R:582:0x90/0x8F
+
+# Shan
+R:583:0xC1/0x94
+
+# Magma elemental
+R:584:0x90/0x90
+
+# Black pudding
+R:585:0x9A/0x81
+
+# Killer iridescent beetle
+R:586:0xA3/0x94
+
+# Nexus vortex
+R:587:0xA1/0x9D
+
+# Plasma vortex
+R:588:0x9E/0x83
+
+# Mature red dragon
+R:589:0x97/0x9E
+
+# Mature gold dragon
+R:590:0x97/0x9F
+
+# Crystal drake
+R:591:0xBB/0x99
+
+# Mature black dragon
+R:592:0x98/0x81
+
+# Mature multi-hued dragon
+R:593:0x98/0x82
+
+# Sky whale
+R:594:0xC1/0x95
+
+# Draebor, the Imp
+R:595:0x91/0x9C
+
+# Mother Hydra
+R:596:0xC1/0x97
+
+# Death knight
+R:597:0x9C/0x9E
+
+# Castamir the Usurper
+R:598:0x9C/0x9F
+
+# Time vortex
+R:599:0x9E/0x82
+
+# Shimmering vortex
+R:600:0x9E/0x85
+
+# Ancient blue dragon
+R:601:0x8F/0x8B
+
+# Ancient bronze dragon
+R:602:0x8F/0x8C
+
+# Beholder
+R:603:0x98/0x88
+
+# Emperor wight
+R:604:0x95/0x88
+
+# Seraph
+R:605:0x8E/0x95
+
+# Vargo, Tyrant of Fire
+R:606:0x90/0x91
+
+# Black wraith
+R:607:0x95/0x89
+
+# Nightgaunt
+R:608:0xA0/0x9E
+
+# Baron of hell
+R:609:0x9F/0x8F
+
+# Scylla
+R:610:0xC1/0x98
+
+# Monastic lich
+R:611:0xC1/0x91
+
+# Nether wraith
+R:612:0x95/0x8A
+
+# Hellhound
+R:613:0x8F/0x87
+
+# 7-headed hydra
+R:614:0x93/0x9D
+
+# Waldern, King of Water
+R:615:0x90/0x92
+
+# Kavlax the Many-Headed
+R:616:0x98/0x83
+
+# Ancient white dragon
+R:617:0x8F/0x8D
+
+# Ancient green dragon
+R:618:0x8F/0x8E
+
+# Chthonian
+R:619:0xA1/0x83
+
+# Eldrak
+R:620:0x94/0x9B
+
+# Ettin
+R:621:0x94/0x9C
+
+# Night mare
+R:622:0x9D/0x8D
+
+# Vampire lord
+R:623:0x95/0x81
+
+# Ancient black dragon
+R:624:0x8F/0x8F
+
+# Weird fume
+R:625:0xC1/0x9A
+
+# Spawn of Ubbo-Sathla
+R:626:0xC1/0x9B
+
+# Fat Man
+R:627:0xC0/0x82
+
+# Malekith the Accursed
+R:628:0xBD/0x91
+
+# Shadowfax, steed of Gandalf
+R:629:0xC1/0x9C
+
+# Spirit troll
+R:630:0xC4/0x84
+
+# War troll
+R:631:0xA1/0x8C
+
+# Disenchanter worm mass
+R:632:0x9E/0x91
+
+# Rotting quylthulg
+R:633:0x93/0x81
+
+# Lesser titan
+R:634:0x92/0x9C
+
+# 9-headed hydra
+R:635:0x93/0x9E
+
+# Enchantress
+R:636:0xBB/0x81
+
+# Ranger chieftain
+R:637:0xB1/0x99
+
+# Sorcerer
+R:638:0x9D/0x82
+
+# Xaren
+R:639:0x95/0x98
+
+# Giant roc
+R:640:0x8E/0x9A
+
+# Minotaur
+R:641:0x91/0x93
+
+# Medusa, the Gorgon
+R:642:0x9A/0x96
+
+# Death drake
+R:643:0xBB/0x98
+
+# Ancient red dragon
+R:644:0x8F/0x91
+
+# Ancient gold dragon
+R:645:0x8F/0x92
+
+# Great crystal drake
+R:646:0xBB/0x97
+
+# Wyrd sister
+R:647:0xC1/0x9D
+
+# Vrock
+R:648:0x9E/0x9D
+
+# Death quasit
+R:649:0x91/0x9E
+
+# Giganto, the Gargantuan
+R:650:0xBE/0x95
+
+# Strygalldwir
+R:651:0x8E/0x9C
+
+# Fallen angel
+R:652:0xC1/0x9E
+
+# Giant headless
+R:653:0xC1/0x9F
+
+# Judge Fire
+R:654:0xC2/0x80
+
+# Ubbo-Sathla, the Unbegotten Source
+R:655:0xC2/0x81
+
+# Judge Mortis
+R:656:0xC2/0x82
+
+# Dark elven sorcerer
+R:657:0x99/0x8A
+
+# Master lich
+R:658:0x92/0x89
+
+# Byakhee
+R:659:0xA0/0x9F
+
+# Eol, the Dark Elf
+R:660:0xB2/0x8A
+
+# Archon
+R:661:0x8E/0x96
+
+# Formless spawn of Tsathoggua
+R:662:0x9F/0x9C
+
+# Hunting horror
+R:663:0x9F/0x98
+
+# Undead beholder
+R:664:0x98/0x89
+
+# Shadow
+R:665:0x91/0x86
+
+# Iron lich
+R:666:0xA1/0x8B
+
+# Dread
+R:667:0x91/0x85
+
+# Greater basilisk
+R:668:0xC2/0x83
+
+# Charybdis
+R:669:0xBE/0x96
+
+# Jack of Shadows
+R:670:0xC2/0x84
+
+# Zephyr Lord
+R:671:0xC2/0x85
+
+# Juggernaut of Khorne
+R:672:0xC2/0x86
+
+# Mumak
+R:673:0x9D/0x8E
+
+# Judge Fear
+R:674:0xC2/0x87
+
+# Ancient multi-hued dragon
+R:675:0x8F/0x94
+
+# Ethereal dragon
+R:676:0x8F/0x95
+
+# Dark young of Shub-Niggurath
+R:677:0xA1/0x8F
+
+# Colour out of space
+R:678:0xC2/0x88
+
+# Quaker, Master of Earth
+R:679:0x90/0x93
+
+# Death leprechaun
+R:680:0xBD/0x82
+
+# Chaugnar Faugn, Horror from the Hills
+R:681:0xC2/0x89
+
+# Lloigor
+R:682:0xC2/0x8A
+
+# Utgard-Loke
+R:683:0xC2/0x8B
+
+# Quachil Uttaus, Treader of the Dust
+R:684:0xC2/0x8C
+
+# Shoggoth
+R:685:0xA1/0x8E
+
+# Judge Death
+R:686:0xC2/0x8D
+
+# Ariel, Queen of Air
+R:687:0x90/0x94
+
+# 11-headed hydra
+R:688:0x93/0x9F
+
+# Patriarch
+R:689:0x9D/0x84
+
+# Dreadmaster
+R:690:0x91/0x89
+
+# Drolem
+R:691:0x98/0x9B
+
+# Scatha the Worm
+R:692:0x8F/0x93
+
+# Warrior of the Dawn
+R:693:0xA1/0x8A
+
+# Lesser black reaver
+R:694:0xC2/0x8E
+
+# Zoth-Ommog
+R:695:0xC2/0x8F
+
+# Grand master thief
+R:696:0x9C/0x84
+
+# Smaug the Golden
+R:697:0xBB/0x96
+
+# The Stormbringer
+R:698:0xA0/0x9B
+
+# Knight Templar
+R:699:0xB1/0x9A
+
+# Leprechaun fanatic
+R:700:0xC2/0x90
+
+# Dracolich
+R:701:0x8F/0x98
+
+# Greater titan
+R:702:0x92/0x9D
+
+# Dracolisk
+R:703:0x8F/0x9E
+
+# Winged Horror
+R:704:0xC4/0x85
+
+# Spectral tyrannosaur
+R:705:0x9F/0x95
+
+# Yibb-Tstll, the Patient One
+R:706:0xC2/0x91
+
+# Ghatanothoa
+R:707:0xC2/0x92
+
+# Ent
+R:708:0xC2/0x93
+
+# Hru
+R:709:0xC2/0x94
+
+# Itangast the Fire Drake
+R:710:0x8F/0x99
+
+# Death mold
+R:711:0x9A/0x90
+
+# Fafner the Dragon
+R:712:0xA1/0x90
+
+# Charon, Boatman of the Styx
+R:713:0xB1/0x9B
+
+# Quickbeam, the Ent
+R:714:0xB1/0x9C
+
+# Glaurung, Father of the Dragons
+R:715:0x8F/0x99
+
+# Behemoth
+R:716:0xC2/0x97
+
+# Garm, Guardian of Hel
+R:717:0xC2/0x98
+
+# Greater wall monster
+R:718:0x80/0x82
+
+# Nycadaemon
+R:719:0xC2/0x99
+
+# Barbazu
+R:720:0xB2/0x9D
+
+# Goat of Mendes
+R:721:0x9F/0x8D
+
+# Nightwing
+R:722:0x95/0x91
+
+# Maulotaur
+R:723:0xA0/0x8B
+
+# Nether hound
+R:724:0x96/0x89
+
+# Time hound
+R:725:0x96/0x85
+
+# Plasma hound
+R:726:0x96/0x8B
+
+# Demonic quylthulg
+R:727:0x93/0x82
+
+# Great Storm Wyrm
+R:728:0x8F/0x9B
+
+# Ulik the Troll
+R:729:0xC2/0x9A
+
+# Baphomet the Minotaur Lord
+R:730:0x91/0x95
+
+# Hell knight
+R:731:0xC2/0x9B
+
+# Bull Gates
+R:732:0xBC/0x9B
+
+# Santa Claus
+R:733:0x9F/0x89
+
+# Eihort, the Thing in the Labyrinth
+R:734:0xC2/0x9C
+
+# The King in Yellow
+R:735:0xC2/0x9D
+
+# Great unclean one
+R:736:0xC2/0x9E
+
+# Lord of Chaos
+R:737:0xBB/0x85
+
+# Old Sorcerer
+R:738:0xB1/0x9E
+
+# Ethereal hound
+R:739:0x96/0x8C
+
+# Lesser kraken
+R:740:0xBE/0x98
+
+# Great Ice Wyrm
+R:741:0x8F/0x9C
+
+# Demilich
+R:742:0xC2/0x9F
+
+# The Phoenix
+R:743:0x8E/0x9B
+
+# Nightcrawler
+R:744:0x95/0x94
+
+# Lord of Change
+R:745:0xC3/0x80
+
+# Keeper of Secrets
+R:746:0xC3/0x81
+
+# Shudde M'ell
+R:747:0xC3/0x82
+
+# Hand druj
+R:748:0x9D/0x98
+
+# Eye druj
+R:749:0x9D/0x99
+
+# Skull druj
+R:750:0x9D/0x9A
+
+# Chaos vortex
+R:751:0xBB/0x93
+
+# Aether vortex
+R:752:0x9E/0x87
+
+# Nidhogg, the Hel-Drake
+R:753:0xC3/0x83
+
+# The Lernaean Hydra
+R:754:0x94/0x80
+
+# Thuringwethil, the Vampire Messenger
+R:755:0x95/0x82
+
+# Great Hell Wyrm
+R:756:0x8F/0x9D
+
+# Hastur the Unspeakable
+R:757:0x9F/0x8C
+
+# Bloodthirster
+R:758:0xC3/0x84
+
+# Draconic quylthulg
+R:759:0x93/0x83
+
+# Nyogtha, the Thing that Should not Be
+R:760:0xA1/0x91
+
+# Ahtu, Avatar of Nyarlathotep
+R:761:0xC3/0x85
+
+# Fundin Bluecloak
+R:762:0x99/0x8B
+
+# Bile Demon
+R:763:0xB1/0x9F
+
+# Uriel, Angel of Fire
+R:764:0x8E/0x97
+
+# Azriel, Angel of Death
+R:765:0x8E/0x98
+
+# Ancalagon the Black
+R:766:0x8F/0x90
+
+# Daoloth, the Render of the Veils
+R:767:0xC3/0x86
+
+# Nightwalker
+R:768:0x95/0x95
+
+# Gabriel, the Messenger
+R:769:0x8E/0x99
+
+# Artsi, the Champion of Chaos
+R:770:0xC3/0x87
+
+# Saruman of Many Colours
+R:771:0x9D/0x88
+
+# Harowen the Black Hand
+R:772:0x9D/0x86
+
+# Osyluth
+R:773:0xB2/0x8E
+
+# Dreadlord
+R:774:0x91/0x8A
+
+# Greater kraken
+R:775:0xBE/0x99
+
+# Archlich
+R:776:0xC3/0x89
+
+# The Cat Lord
+R:777:0x98/0x91
+
+# Jabberwock
+R:778:0x91/0x9F
+
+# Chaos hound
+R:779:0xBB/0x94
+
+# Vlad Dracula, Prince of Darkness
+R:780:0xC3/0x8B
+
+# Beholder hive-mother
+R:781:0xC3/0x8C
+
+# Leviathan
+R:782:0xBE/0x9A
+
+# Great Wyrm of Chaos
+R:783:0xBB/0x95
+
+# Great Wyrm of Law
+R:784:0x90/0x80
+
+# Great Wyrm of Balance
+R:785:0x90/0x81
+
+# Shambler
+R:786:0x9F/0x92
+
+# Gelugon
+R:787:0xB2/0x8B
+
+# Glaaki
+R:788:0xC3/0x8E
+
+# T'ron, the Rebel Dragonrider
+R:789:0xB2/0x88
+
+# Great Wyrm of Many Colours
+R:790:0xA2/0x95
+
+# Mardra, rider of the Gold Loranth
+R:791:0xB2/0x85
+
+# Tselakus, the Dreadlord
+R:792:0x91/0x8B
+
+# Sky Drake
+R:793:0xA2/0x80
+
+# Eilinel the Entrapped
+R:794:0xB2/0x80
+
+# Horned Reaper
+R:795:0xB2/0x81
+
+# The Norsa
+R:796:0xBB/0x80
+
+# Rhan-Tegoth
+R:797:0xC3/0x8F
+
+# Black reaver
+R:798:0x92/0x8A
+
+# Master mindcrafter
+R:799:0xB0/0x86
+
+# Greater demonic quylthulg
+R:800:0x93/0x87
+
+# Greater draconic quylthulg
+R:801:0x93/0x85
+
+# Greater rotting quylthulg
+R:802:0x93/0x86
+
+# Null, the Living Void
+R:803:0xC3/0x90
+
+# Feagwath, the Undead Sorcerer
+R:804:0x92/0x8C
+
+# Omarax the Eye Tyrant
+R:805:0x98/0x8A
+
+# Tsathoggua, the Sleeper of N'kai
+R:806:0xC3/0x91
+
+# Greater Balrog
+R:807:0xB2/0x9E
+
+# Ungoliant, the Unlight
+R:808:0x94/0x8D
+
+# Atlach-Nacha, the Spider God
+R:809:0x94/0x8D
+
+# Y'golonac
+R:810:0xC3/0x92
+
+# Aether hound
+R:811:0x96/0x8E
+
+# Pit Fiend
+R:812:0xB2/0x9F
+
+# The Serpent of Chaos
+R:813:0x9F/0x8E
+
+# Yig, Father of Serpents
+R:814:0xC3/0x94
+
+# Unmaker
+R:815:0xA1/0x9E
+
+# Cyberdemon
+R:816:0x9F/0x91
+
+# Hela, Queen of the Dead
+R:817:0xC3/0x95
+
+# The Mouth of Sauron
+R:818:0x9D/0x89
+
+# The Necromancer of Dol Guldur
+R:819:0xC5/0x8B
+
+# Lessa, rider of the Gold Ramoth
+R:820:0xB2/0x86
+
+# Master quylthulg
+R:821:0x93/0x84
+
+# Qlzqqlzuup, the Lord of Flesh
+R:822:0x93/0x88
+
+# Cthugha, the Living Flame
+R:823:0xC3/0x96
+
+# F'lar, rider of the Bronze Mnementh
+R:824:0xB2/0x87
+
+# Maeglin, the Traitor of Gondolin
+R:825:0xA1/0x9C
+
+# Cyaegha
+R:826:0xBD/0x81
+
+# Pazuzu, Lord of Air
+R:827:0x8E/0x9C
+
+# Ithaqua the Windwalker
+R:828:0xA0/0x82
+
+# Hellhound
+R:829:0x8F/0x87
+
+# Cantoras, the Skeletal Lord
+R:830:0x9D/0x9B
+
+# Mephistopheles, Lord of Hell
+R:831:0x9F/0x90
+
+# Godzilla
+R:832:0x9F/0x97
+
+# Abhoth, Source of Uncleanness
+R:833:0xC3/0x97
+
+# Ymir, the Ice Giant
+R:834:0xBD/0x84
+
+# Loki, the Trickster
+R:835:0xC3/0x98
+
+# Star-spawn of Cthulhu
+R:836:0x9F/0x8A
+
+# Surtur, the Fire Giant
+R:837:0xBD/0x85
+
+# The Tarrasque
+R:838:0x94/0x81
+
+# Lungorthin, the Balrog of White Fire
+R:839:0x9F/0x82
+
+# Draugluin, Sire of All Werewolves
+R:840:0x8F/0x88
+
+# Shuma-Gorath
+R:841:0xBD/0x80
+
+# Tulzscha, the Green Flame
+R:842:0xC3/0x99
+
+# Oremorj, the Cyberdemon Lord
+R:843:0xC3/0x9A
+
+# Vecna, the Emperor Lich
+R:844:0x92/0x8B
+
+# Yog-Sothoth, the All-in-One
+R:845:0x9F/0x8B
+
+# Fenris Wolf
+R:846:0xC3/0x9B
+
+# Great Wyrm of Power
+R:847:0xA2/0x81
+
+# Shub-Niggurath, Black Goat of the Woods
+R:848:0x9F/0x99
+
+# Nodens, Lord of the Great Abyss
+R:849:0xC3/0x9C
+
+# Carcharoth, the Jaws of Thirst
+R:850:0x8F/0x89
+
+# Nyarlathotep, the Crawling Chaos
+R:851:0x9F/0x9B
+
+# Azathoth, the Daemon Sultan
+R:852:0xC4/0x8C
+
+# Huan, Wolfhound of the Valar
+R:853:0xB2/0x83
+
+# Jormungand the Midgard Serpent
+R:854:0xBE/0x9B
+
+# The Destroyer
+R:855:0xBD/0x83
+
+# Gothmog, the High Captain of Balrogs
+R:856:0x9F/0x81
+
+# Great Cthulhu
+R:857:0x9F/0x84
+
+# Sorka, rider of the Gold Faranth
+R:858:0xB2/0x84
+
+# The Unicorn of Order
+R:859:0xC3/0x9D
+
+# Sauron, the Sorcerer
+R:860:0x9D/0x8A
+
+# DarkGod, the Mighty Coder of Hell
+R:861:0xA1/0x93
+
+# Morgoth, Lord of Darkness
+R:862:0x92/0x9E
+
+# Human Warrior
+R:863:0xB2/0x82
+
+# Elven archer
+R:864:0x9C/0x81
+
+# Dwarven warrior
+R:865:0xB2/0x89
+
+# Elite uruk
+R:866:0x9B/0x81
+
+# The Philosophy Teacher
+R:867:0xC4/0x82
+
+# The Variant Maintainer
+R:868:0xA1/0x99
+
+# Random Number Generator
+R:869:0xBD/0x9F
+
+# Rocket mine
+R:870:0xB2/0x8C
+
+# Bouncing mine
+R:871:0xB2/0x8D
+
+# The Balrog of Moria
+R:872:0xB2/0x8F
+
+# The Icky Queen
+R:873:0xB2/0x90
+
+# Rot jelly
+R:874:0xB1/0x91
+
+# Death
+R:875:0xB2/0x91
+
+# Famine
+R:876:0xB2/0x92
+
+# Pestilence
+R:877:0xB2/0x93
+
+# War
+R:878:0xB2/0x94
+
+# Pike
+R:879:0xB2/0x95
+
+# Electric eel
+R:880:0xBE/0x8C
+
+# Giant crayfish
+R:881:0xB2/0x96
+
+# Mermaid
+R:882:0xB1/0x9D
+
+# Box jellyfish
+R:883:0xBE/0x83
+
+# Giant piranha
+R:884:0xBE/0x84
+
+# Piranha
+R:885:0xBE/0x80
+
+# Bullywug
+R:886:0xB2/0x97
+
+# Bullywug warrior
+R:887:0xB2/0x98
+
+# Bullywug shaman
+R:888:0xB2/0x99
+
+# Whale
+R:889:0xBE/0x8B
+
+# Sand mite
+R:890:0xB0/0x9D
+
+# Octopus
+R:891:0xB2/0x9A
+
+# Giant octopus
+R:892:0xBE/0x93
+
+# Eye of the deep
+R:893:0xB2/0x9B
+
+# Murk dweller
+R:894:0xB2/0x9C
+
+# Drowned soul
+R:895:0xC5/0x8F
+
+# Tiger shark
+R:896:0xC5/0x8E
+
+# Hammerhead shark
+R:897:0xBE/0x88
+
+# Great white shark
+R:898:0xBE/0x8F
+
+# Aquatic golem
+R:899:0xC5/0x95
+
+# Aquatic kobold
+R:900:0xC5/0x96
+
+# White shark
+R:901:0xBE/0x89
+
+# Scrag
+R:902:0xC5/0x97
+
+# Jaws
+R:903:0xBE/0x92
+
+# Aquatic elf
+R:904:0xC5/0x98
+
+# Aquatic elven warrior
+R:905:0xC5/0x99
+
+# Aquatic elven shaman
+R:906:0xC5/0x9A
+
+# Stargazer
+R:907:0xC5/0x9E
+
+# Elder stargazer
+R:908:0xC5/0x9F
+
+# Flounder
+R:909:0xC6/0x81
+
+# Giant turtle
+R:910:0xC6/0x82
+
+# Baby dragon turtle
+R:911:0xC6/0x83
+
+# Young dragon turtle
+R:912:0xC6/0x84
+
+# Mature dragon turtle
+R:913:0xC6/0x85
+
+# Ancient dragon turtle
+R:914:0xC6/0x86
+
+# Fastitocalon
+R:915:0xBE/0x97
+
+# Undead stargazer
+R:916:0xC6/0x80
+
+# Killer whale
+R:917:0xBE/0x8E
+
+# Merrow
+R:918:0xC5/0x9D
+
+# Water naga
+R:919:0xC6/0x87
+
+# Devilfish
+R:920:0xC6/0x88
+
+# Undead devilfish
+R:921:0xC6/0x89
+
+# Moby Dick, the White Whale
+R:922:0xC5/0x9C
+
+# Aquatic hound
+R:923:0xC4/0x9E
+
+# Water demon
+R:924:0xC6/0x8B
+
+# Ixitxachitl
+R:925:0xBE/0x86
+
+# Ixitxachitl priest
+R:926:0xBE/0x8A
+
+# Vampiric ixitxachitl
+R:927:0xBE/0x90
+
+# Mathilde, the Science Student
+R:928:0x9D/0x80
+
+# Child spirit
+R:929:0xC5/0x90
+
+# Young spirit
+R:930:0xC5/0x91
+
+# Mature spirit
+R:931:0xC5/0x92
+
+# Experienced spirit
+R:932:0xC5/0x93
+
+# Wise spirit
+R:933:0xC5/0x94
+
+# Fangorn the Treebeard, Lord of the Ents
+R:934:0xC2/0x95
+
+# Gandalf the Grey
+R:935:0xC3/0x88
+
+# Nar, the Dwarf
+R:936:0x99/0x84
+
+# Novice mindcrafter
+R:937:0xB0/0x84
+
+# Great Swamp Wyrm
+R:938:0x8F/0x9A
+
+# Great Bile Wyrm
+R:939:0x8F/0x9F
+
+# Blue Firelizard
+R:940:0xB0/0x99
+
+# Green Firelizard
+R:941:0xB0/0x98
+
+# Brown Firelizard
+R:942:0xB0/0x97
+
+# Bronze Firelizard
+R:943:0xB0/0x96
+
+# Gold Firelizard
+R:944:0xB0/0x95
+
+# High-elven ranger
+R:945:0xC6/0x93
+
+# Uvatha the Horseman
+R:946:0x95/0x8B
+
+# Adunaphel the Quiet
+R:947:0x95/0x8C
+
+# Akhorahil the Blind
+R:948:0x95/0x8D
+
+# Ren the Unclean
+R:949:0x95/0x82
+
+# Ji Indur Dawndeath
+R:950:0x95/0x8F
+
+# Dwar, Dog Lord of Waw
+R:951:0x95/0x8F
+
+# Hoarmurath of Dir
+R:952:0x95/0x92
+
+# Khamul, the Black Easterling
+R:953:0x95/0x93
+
+# The Witch-King of Angmar
+R:954:0x95/0x96
+
+# Green Dragonrider
+R:955:0xB0/0x91
+
+# Blue Dragonrider
+R:956:0xB0/0x94
+
+# Brown Dragonrider
+R:957:0xB0/0x92
+
+# Bronze Dragonrider
+R:958:0xB0/0x93
+
+# Gold Dragonrider
+R:959:0xB0/0x90
+
+# Thread
+R:960:0xB0/0x9A
+
+# Gorlim, Betrayer of Barahir
+R:961:0x9D/0x83
+
+# The Blubbering idiot, agent of black market, Simon the weak
+R:962:0x9B/0x8F
+
+# Aranea
+R:963:0xB0/0x80
+
+# Elder aranea
+R:964:0xB0/0x81
+
+# Giant brown tick
+R:965:0xC5/0x9B
+
+# Dolphiner
+R:966:0xC6/0x98
+
+# Novice possessor (soul)
+R:967:0xC6/0x8E
+
+# Bat of Gorgoroth
+R:968:0xC6/0x94
+
+# The Princess
+R:969:0xA2/0x9F
+
+# Merton Proudfoot, the lost hobbit
+R:970:0xC6/0x9E
+
+# The Wight-King of the Barrow-downs
+R:971:0xC6/0x91
+
+# Adventurer
+R:972:0xA9/0x86
+
+# Experienced possessor (soul)
+R:973:0xC6/0x8F
+
+# Old possessor (soul)
+R:974:0xC6/0x90
+
+# Death orb
+R:975:0xC6/0x99
+
+# Bronze dragon worm
+R:976:0xB1/0x80
+
+# Gold dragon worm
+R:977:0xB1/0x81
+
+# Moldoux, the Defenceless Mold
+R:978:0xB1/0x8A
+
+# The Physics Teacher
+R:979:0xC6/0x9A
+
+# Ar-Pharazon the Golden
+R:980:0xA1/0x9B
+
+# Doppelganger
+R:981:0x8C/0x81
+
+# Marylene, Heartbreakeress of the Netherworld
+R:982:0xA3/0x9E
+
+# The Greater Lag Monster
+R:983:0xC6/0x96
+
+# Hrungnir, the Stone Giant
+R:984:0xB1/0x8B
+
+# Bullroarer the Hobbit
+R:985:0x98/0x9D
+
+# 3-headed hydra
+R:986:0x93/0x99
+
+# Uldor the Accursed
+R:987:0x9C/0x93
+
+# Mystic
+R:988:0x9C/0x97
+
+# Elder vampire
+R:989:0xA1/0x9F
+
+# Ulfang the Black
+R:990:0x9C/0x99
+
+# Demonologist
+R:991:0x9C/0x9D
+
+# Hezrou
+R:992:0x9E/0x9C
+
+# Glabrezu
+R:993:0x9E/0x9D
+
+# Nalfeshnee
+R:994:0x9E/0x9E
+
+# Marilith
+R:995:0x9E/0x9F
+
+# Lesser Balrog
+R:996:0x9F/0x80
+
+# Master mystic
+R:997:0x9D/0x85
+
+# Grand master mystic
+R:998:0x9D/0x87
+
+# Erinyes
+R:999:0x9E/0x9A
+
+# Novice mindcrafter
+R:1000:0xB0/0x84
+
+# Polyphemus, the Blind Cyclops
+R:1001:0xC6/0x92
+
+# Great Wyrm of Perplexity
+R:1002:0xB1/0x8C
+
+# Hound of Tindalos
+R:1003:0xB0/0x8E
+
+# Great Wyrm of Thunder
+R:1004:0xB1/0x8D
+
+# Silver mouse
+R:1005:0xB0/0x83
+
+# The Rat King
+R:1006:0xB1/0x8E
+
+# Vort the Kobold Queen
+R:1007:0xB0/0x88
+
+# Giant black louse
+R:1008:0x9A/0x87
+
+# Fire Phantom
+R:1009:0xB1/0x8F
+
+# The Insane Player
+R:1010:0xBC/0x99
+
+# Glaryssa, Succubus Queen
+R:1011:0xA3/0x9F
+
+# Vermicious Knid
+R:1012:0xB1/0x90
+
+# Bone golem
+R:1013:0xB1/0x92
+
+# Snake of Yig
+R:1014:0xC6/0x8A
+
+# Bronze golem
+R:1015:0xB1/0x93
+
+# Dimensional shambler
+R:1016:0xB0/0x9C
+
+# Cultist
+R:1017:0xC6/0x8C
+
+# Cult leader
+R:1018:0xC6/0x8D
+
+# Servitor of the outer gods
+R:1019:0xC6/0x95
+
+# Avatar of Nyarlathotep
+R:1020:0xC3/0x85
+
+# Thiazi, the Storm Giant
+R:1021:0xB1/0x94
+
+# Hypnos, Lord of Sleep
+R:1022:0xC3/0x8D
+
+# Blue dragon worm
+R:1023:0xB1/0x82
+
+# White dragon worm
+R:1024:0xB1/0x83
+
+# Green dragon worm
+R:1025:0xB1/0x84
+
+# Black dragon worm
+R:1026:0xB1/0x85
+
+# Red dragon worm
+R:1027:0xB1/0x86
+
+# Multi-hued dragon worm
+R:1028:0xB1/0x87
+
+# The Minotaur of the Labyrinth
+R:1029:0x91/0x95
+
+# The Sandworm Queen
+R:1030:0xB1/0x88
+
+# Sandworm
+R:1031:0xB1/0x89
+
+# Tik'srvzllat
+R:1032:0xC6/0x9B
+
+# The Glass Golem
+R:1033:0xB1/0x95
+
+# The White Balrog
+R:1034:0x9F/0x82
+
+# Golgarach, the Living Rock
+R:1035:0x80/0x95
+
+# Atlas, the Titan
+R:1036:0xC6/0x9C
+
+# Kronos, Lord of the Titans
+R:1037:0xC6/0x9D
+
+# Water hound
+R:1038:0x96/0x83
+
+# Improv, the mighty MoLD
+R:1039:0xB1/0x8A
+
+# Emperor Mimic
+R:1040:0xA3/0x8D
+
+# Melinda Proudfoot
+R:1041:0xC6/0x9F
+
+# Thrain, the King Under the Mountain
+R:1042:0xC6/0x97
+
+## Fire golem
+R:1043:0xBC/0x9C
+
+# Spells (*)
+S:0x30:0x85/0x93
+S:0x31:0x85/0x92
+S:0x32:0x85/0x92
+S:0x33:0x85/0x8D
+S:0x34:0x85/0x8C
+S:0x35:0x85/0x8F
+S:0x36:0x85/0x90
+S:0x37:0x85/0x95
+S:0x38:0x85/0x93
+S:0x39:0x85/0x92
+S:0x3A:0x85/0x91
+S:0x3B:0x85/0x8E
+S:0x3C:0x85/0x8D
+S:0x3D:0x85/0x8F
+S:0x3E:0x85/0x90
+S:0x3F:0x85/0x95
+
+# Spells (|)
+S:0x40:0x84/0x9C
+S:0x41:0x84/0x98
+S:0x42:0x84/0x98
+S:0x43:0x85/0x88
+S:0x44:0x84/0x80
+S:0x45:0x84/0x8C
+S:0x46:0x84/0x90
+S:0x47:0x85/0x84
+S:0x48:0x84/0x9C
+S:0x49:0x84/0x98
+S:0x4A:0x84/0x94
+S:0x4B:0x84/0x88
+S:0x4C:0x85/0x88
+S:0x4D:0x84/0x8C
+S:0x4E:0x84/0x90
+S:0x4F:0x85/0x84
+
+# Spells (-)
+S:0x50:0x84/0x9D
+S:0x51:0x84/0x99
+S:0x52:0x84/0x99
+S:0x53:0x85/0x89
+S:0x54:0x84/0x81
+S:0x55:0x84/0x8D
+S:0x56:0x84/0x91
+S:0x57:0x85/0x85
+S:0x58:0x84/0x9D
+S:0x59:0x84/0x99
+S:0x5A:0x84/0x95
+S:0x5B:0x84/0x89
+S:0x5C:0x85/0x89
+S:0x5D:0x84/0x8D
+S:0x5E:0x84/0x91
+S:0x5F:0x85/0x85
+
+# Spells (:)
+S:0x60:0x84/0x9E
+S:0x61:0x84/0x9A
+S:0x62:0x84/0x9A
+S:0x63:0x85/0x8A
+S:0x64:0x84/0x82
+S:0x65:0x84/0x8E
+S:0x66:0x84/0x92
+S:0x67:0x85/0x86
+S:0x68:0x84/0x9E
+S:0x69:0x84/0x9A
+S:0x6A:0x84/0x96
+S:0x6B:0x84/0x8A
+S:0x6C:0x85/0x8A
+S:0x6D:0x84/0x8E
+S:0x6E:0x84/0x92
+S:0x6F:0x85/0x86
+
+# Spells (\)
+S:0x70:0x84/0x9F
+S:0x71:0x84/0x9B
+S:0x72:0x84/0x9B
+S:0x73:0x85/0x8B
+S:0x74:0x84/0x83
+S:0x75:0x84/0x8F
+S:0x76:0x84/0x93
+S:0x77:0x85/0x87
+S:0x78:0x84/0x9F
+S:0x79:0x84/0x9B
+S:0x7A:0x84/0x97
+S:0x7B:0x84/0x8B
+S:0x7C:0x85/0x8B
+S:0x7D:0x84/0x8F
+S:0x7E:0x84/0x93
+S:0x7F:0x85/0x87
+
+# Amulets (")
+S:0x80:0xB6/0x87
+S:0x81:0xB6/0x88
+S:0x82:0xB6/0x85
+S:0x83:0xB6/0x86
+S:0x84:0xB6/0x81
+S:0x85:0xB6/0x82
+S:0x86:0xB6/0x83
+S:0x87:0xB6/0x84
+S:0x88:0xB6/0x87
+S:0x89:0xB6/0x88
+S:0x8A:0xB6/0x8E
+S:0x8B:0xB6/0x86
+S:0x8C:0xB6/0x81
+S:0x8D:0xB6/0x82
+S:0x8E:0xB6/0x8B
+S:0x8F:0xB6/0x8C
+
+# Rings (=)
+S:0x90:0xB5/0x8B
+S:0x91:0xB5/0x8C
+S:0x92:0xB5/0x89
+S:0x93:0xB5/0x8A
+S:0x94:0xB5/0x81
+S:0x95:0xB5/0x82
+S:0x96:0xB5/0x83
+S:0x97:0xB5/0x88
+S:0x98:0xB5/0x8B
+S:0x99:0xB5/0x8C
+S:0x9A:0xB5/0x80
+S:0x9B:0xB5/0x8A
+S:0x9C:0xB5/0x81
+S:0x9D:0xB5/0x82
+S:0x9E:0xB5/0x83
+S:0x9F:0xB5/0x88
+
+# Staffs (_)
+S:0xA0:0xB9/0x84
+S:0xA1:0xB9/0x85
+S:0xA2:0xB9/0x85
+S:0xA3:0xB9/0x81
+S:0xA4:0xB9/0x81
+S:0xA5:0xB9/0x82
+S:0xA6:0xB9/0x80
+S:0xA7:0xB9/0x87
+S:0xA8:0xB9/0x84
+S:0xA9:0xB9/0x85
+S:0xAA:0xB9/0x83
+S:0xAB:0xB9/0x87
+S:0xAC:0xB9/0x81
+S:0xAD:0xB9/0x82
+S:0xAE:0xB9/0x80
+S:0xAF:0xB9/0x87
+
+# Wands (-)
+S:0xB0:0xB7/0x84
+S:0xB1:0xB7/0x85
+S:0xB2:0xB7/0x85
+S:0xB3:0xB7/0x86
+S:0xB4:0xB7/0x81
+S:0xB5:0xB7/0x82
+S:0xB6:0xB7/0x80
+S:0xB7:0xB7/0x87
+S:0xB8:0xB7/0x84
+S:0xB9:0xB7/0x85
+S:0xBA:0xB7/0x83
+S:0xBB:0xB7/0x86
+S:0xBC:0xB7/0x81
+S:0xBD:0xB7/0x82
+S:0xBE:0xB7/0x80
+S:0xBF:0xB7/0x87
+
+# Rods (-)
+S:0xC0:0xB8/0x84
+S:0xC1:0xB8/0x85
+S:0xC2:0xB8/0x85
+S:0xC3:0xB8/0x86
+S:0xC4:0xB8/0x81
+S:0xC5:0xB8/0x82
+S:0xC6:0xB8/0x80
+S:0xC7:0xB8/0x87
+S:0xC8:0xB8/0x84
+S:0xC9:0xB8/0x85
+S:0xCA:0xB8/0x83
+S:0xCB:0xB8/0x86
+S:0xCC:0xB8/0x81
+S:0xCD:0xB8/0x82
+S:0xCE:0xB8/0x80
+S:0xCF:0xB8/0x87
+
+# Scrolls (?)
+S:0xD0:0x86/0x82
+S:0xD1:0x86/0x82
+S:0xD2:0x86/0x82
+S:0xD3:0x86/0x82
+S:0xD4:0x86/0x82
+S:0xD5:0x86/0x82
+S:0xD6:0x86/0x82
+S:0xD7:0x86/0x82
+S:0xD8:0x86/0x82
+S:0xD9:0x86/0x82
+S:0xDA:0x86/0x82
+S:0xDB:0x86/0x82
+S:0xDC:0x86/0x82
+S:0xDD:0x86/0x82
+S:0xDE:0x86/0x82
+S:0xDF:0x86/0x82
+
+# Potions (!)
+S:0xE0:0xBC/0x84
+S:0xE1:0xBC/0x83
+S:0xE2:0xBC/0x8A
+S:0xE3:0xBC/0x8B
+S:0xE4:0xBC/0x87
+S:0xE5:0xBC/0x86
+S:0xE6:0xBC/0x85
+S:0xE7:0xBC/0x89
+S:0xE8:0xBC/0x84
+S:0xE9:0xBC/0x83
+S:0xEA:0xBC/0x8E
+S:0xEB:0xBC/0x88
+S:0xEC:0xBC/0x8B
+S:0xED:0xBC/0x8C
+S:0xEE:0xBC/0x8D
+S:0xEF:0xBC/0x89
+
+# Food (,)
+S:0xF0:0xBA/0x84
+S:0xF1:0xBA/0x85
+S:0xF2:0xBA/0x85
+S:0xF3:0xBA/0x86
+S:0xF4:0xBA/0x81
+S:0xF5:0xBA/0x82
+S:0xF6:0xBA/0x80
+S:0xF7:0xBA/0x87
+S:0xF8:0xBA/0x84
+S:0xF9:0xBA/0x85
+S:0xFA:0xBA/0x83
+S:0xFB:0xBA/0x86
+S:0xFC:0xBA/0x81
+S:0xFD:0xBA/0x82
+S:0xFE:0xBA/0x80
+S:0xFF:0xBA/0x87
+
+# Unknown Amulet
+U:40:0xB6/0x81
+
+# Unknown Ring
+U:45:0xB5/0x81
+
+# Unknown Staff
+U:55:0xB9/0x81
+
+# Unknown Wand
+U:65:0xB7/0x81
+
+# Unknown Rod
+U:66:0xB8/0x81
+
+# Unknown Scroll
+U:70:0x86/0x82
+
+# Unknown Potion
+U:75:0xBC/0x85
+
+# Unknown Food
+U:80:0x8B/0x81
+# non-defines encountered :
+# Load the special player pictures
+%:xtra-xxx.prf
+# Load the Trap image definitions
+%:trap-xxx.prf
diff --git a/lib/pref/graf.prf b/lib/pref/graf.prf
new file mode 100644
index 00000000..a82ce364
--- /dev/null
+++ b/lib/pref/graf.prf
@@ -0,0 +1,51 @@
+# File: graf.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# This file includes, if appropriate, various "sub-files"
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+##### Standard font file #####
+
+%:font-xxx.prf
+
+
+##### System Specific Subfiles #####
+
+?:[IOR [EQU $SYS xaw] [EQU $SYS x11] [EQU $SYS gtk]]
+%:graf-x11.prf
+
+?:[EQU $SYS gcu]
+%:graf-gcu.prf
+
+?:[EQU $SYS ami]
+%:graf-ami.prf
+
+?:[EQU $SYS mac]
+%:graf-mac.prf
+
+?:[EQU $SYS dos]
+%:graf-dos.prf
+
+?:[EQU $SYS win]
+%:graf-win.prf
+
+?:[EQU $SYS ibm]
+%:graf-ibm.prf
+
+?:[EQU $SYS emx]
+%:graf-emx.prf
+
+?:[EQU $SYS acn]
+%:graf-acn.prf
+
+?:[EQU $SYS sdl]
+%:graf-sdl.prf
+
+?:1
+
+
diff --git a/lib/pref/pref-acn.prf b/lib/pref/pref-acn.prf
new file mode 100644
index 00000000..ae95fe26
--- /dev/null
+++ b/lib/pref/pref-acn.prf
@@ -0,0 +1,24 @@
+# File: pref-acn.prf
+
+# This is a minimal "pref" file for RISC OS
+
+
+# Map cursor keys onto keypad
+
+A:4
+P:^_18C\r
+
+A:6
+P:^_18D\r
+
+A:2
+P:^_18E\r
+
+A:8
+P:^_18F\r
+
+
+# Map F3 to ^S (to be a bit RISC OS-ey)
+
+A:^S
+P:^_183\r
diff --git a/lib/pref/pref-ami.prf b/lib/pref/pref-ami.prf
new file mode 100644
index 00000000..08a1c310
--- /dev/null
+++ b/lib/pref/pref-ami.prf
@@ -0,0 +1,7 @@
+# File: pref-ami.prf
+
+#
+# This file contains various default macros for use with
+# the executable built from "main-ami.c".
+#
+
diff --git a/lib/pref/pref-emx.prf b/lib/pref/pref-emx.prf
new file mode 100644
index 00000000..555c0dbc
--- /dev/null
+++ b/lib/pref/pref-emx.prf
@@ -0,0 +1,19 @@
+# File: pref-emx.prf
+
+#
+# Include "pref-ibm.prf" to get the default macros.
+#
+# Note that, while most key-to-trigger mappings are the same as DOS/Win,
+# some few odd keys will be different or not available at all.
+#
+# Examples: Ctrl-Escape, Alt-PrintScreen
+#
+# What's NOT working: color palette redefinitions.
+#
+
+%:pref-win.prf
+
+
+# shift-5 - rest
+A:R\r
+P:^_Sx4C\r
diff --git a/lib/pref/pref-gcu.prf b/lib/pref/pref-gcu.prf
new file mode 100644
index 00000000..cbc80ada
--- /dev/null
+++ b/lib/pref/pref-gcu.prf
@@ -0,0 +1,70 @@
+# File: pref-gcu.prf
+
+#
+# This file may be included by "pref.prf", when using "main-gcu.prf".
+#
+# It contains macro definitions to allow the VT100 cursor keys to be
+# recognized by Angband. This will also make the "escape" key take a
+# few seconds to recognize, so you may want to use the "`" key instead.
+#
+
+
+### VT100 Keypad ###
+
+
+# Special keypad keys (delete, insert)
+
+A:.
+P:\e[3~
+
+A:0
+P:\e[2~
+
+
+# Numerical keypad keys (map to appropriate number)
+
+A:1
+P:\e[4~
+P:\e[F
+
+A:2
+P:\e[B
+
+A:3
+P:\e[6~
+
+A:4
+P:\e[D
+
+A:5
+P:\e[G
+
+A:6
+P:\e[C
+
+A:7
+P:\e[1~
+P:\e[H
+
+A:8
+P:\e[A
+
+A:9
+P:\e[5~
+
+
+# Basic function keys (F1 - F4)
+
+A:\e
+P:\eOP
+
+A:\e
+P:\eOQ
+
+A:\e
+P:\eOR
+
+A:\e
+P:\eOS
+
+
diff --git a/lib/pref/pref-iso.prf b/lib/pref/pref-iso.prf
new file mode 100644
index 00000000..a6bad2e3
--- /dev/null
+++ b/lib/pref/pref-iso.prf
@@ -0,0 +1,118 @@
+# File: pref-sdl.prf
+
+#
+# This file provides some macros for use with versions of Angband compiled
+# using the "main-x11.c" (or "main-xaw.c") file.
+#
+# Note the use of "\e\e\e\e" (four escapes) to allow the macros to work
+# even if the game is not yet ready for a command.
+#
+# Note the use of "\\." (for "run") and "\\+" (for "alter"), to make sure
+# that the macros will work regardless of the "keymap" being used.
+#
+
+
+
+# Keypad (0-9)
+
+A:0
+P:^__100\r
+
+A:1
+P:^__101\r
+
+A:2
+P:^__112\r
+P:^__102\r
+
+A:3
+P:^__103\r
+
+A:4
+P:^__114\r
+P:^__104\r
+
+A:5
+P:^__105\r
+
+A:6
+P:^__113\r
+P:^__106\r
+
+A:7
+P:^__107\r
+
+A:8
+P:^__111\r
+P:^__108\r
+
+A:9
+P:^__109\r
+
+
+# Shift-Keypad (0-9)
+
+A:\e\e\e\e\\.0
+P:^_S_100\r
+
+A:\e\e\e\e\\.1
+P:^_S_101\r
+
+A:\e\e\e\e\\.2
+P:^_S_102\r
+
+A:\e\e\e\e\\.3
+P:^_S_103\r
+
+A:\e\e\e\e\\.4
+P:^_S_104\r
+
+A:\e\e\e\e\\.5
+P:^_S_105\r
+
+A:\e\e\e\e\\.6
+P:^_S_106\r
+
+A:\e\e\e\e\\.7
+P:^_S_107\r
+
+A:\e\e\e\e\\.8
+P:^_S_108\r
+
+A:\e\e\e\e\\.9
+P:^_S_109\r
+
+
+
+# Control-Keypad (0-9)
+
+A:\e\e\e\e\\+0
+P:^_N_100\r
+
+A:\e\e\e\e\\+1
+P:^_N_101\r
+
+A:\e\e\e\e\\+2
+P:^_N_102\r
+
+A:\e\e\e\e\\+3
+P:^_N_103\r
+
+A:\e\e\e\e\\+4
+P:^_N_104\r
+
+A:\e\e\e\e\\+5
+P:^_N_105\r
+
+A:\e\e\e\e\\+6
+P:^_N_106\r
+
+A:\e\e\e\e\\+7
+P:^_N_107\r
+
+A:\e\e\e\e\\+8
+P:^_N_108\r
+
+A:\e\e\e\e\\+9
+P:^_N_109\r
+
diff --git a/lib/pref/pref-mac.prf b/lib/pref/pref-mac.prf
new file mode 100644
index 00000000..88e5618e
--- /dev/null
+++ b/lib/pref/pref-mac.prf
@@ -0,0 +1,243 @@
+# File: pref-mac.prf
+
+#
+# This file is included by "pref.prf" when "main-mac.c" is used.
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+#
+# Macro Trigger configuration
+#
+# T:<trigger template>:<modifiers>:<modifier name1>:<modifier name2>:....
+# '&' in <trigger template> specifies location of modifier character.
+# '#' in <trigger template> specifies location of key code.
+#
+# If <trigger template> is null string, all trigger difinition will be cleared.
+
+T:&#:CSOX:control-:shift-:option-:command-
+
+# T:<trigger name>:<keycode>:<keycode with shiftkey>
+# '\' in <trigger name> is escape character.
+
+T:KP_Decimal:1
+T:KP_Multiply:3
+T:KP_Add:5
+T:KP_Clear:7
+T:KP_Divide:11
+T:KP_Enter:12
+T:KP_Subtract:14
+T:KP_Equal:17
+T:KP_0:18
+T:KP_1:19
+T:KP_2:20
+T:KP_3:21
+T:KP_4:22
+T:KP_5:23
+T:KP_6:24
+T:KP_7:25
+T:KP_8:27
+T:KP_9:28
+T:F5:32
+T:F6:33
+T:F7:34
+T:F3:35
+T:F8:36
+T:F10:37
+T:F11:39
+T:F13:41
+T:F14:43
+T:F9:45
+T:F12:47
+T:F15:49
+T:Help:50
+T:Home:51
+T:Page_Up:52
+T:Delete:53
+T:F4:54
+T:End:55
+T:F2:56
+T:Page_Down:57
+T:F1:58
+T:Left:59
+T:Right:60
+T:Down:61
+T:Up:62
+
+##### Simple Macros #####
+
+
+#
+# Keypad -- (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:/
+P:^_K/\r
+
+A:*
+P:^_K*\r
+
+A:7
+P:^_K7\r
+
+A:8
+P:^_K8\r
+
+A:9
+P:^_K9\r
+
+A:-
+P:^_K-\r
+
+A:4
+P:^_K4\r
+
+A:5
+P:^_K5\r
+
+A:6
+P:^_K6\r
+
+A:+
+P:^_K+\r
+
+A:1
+P:^_K1\r
+
+A:2
+P:^_K2\r
+
+A:3
+P:^_K3\r
+
+A:0
+P:^_K0\r
+
+A:.
+P:^_K.\r
+
+
+#
+# Shift-Keypad -- Directed running
+#
+
+A:\e\e\\.1
+P:^_S19\r
+
+A:\e\e\\.2
+P:^_S20\r
+
+A:\e\e\\.3
+P:^_S21\r
+
+A:\e\e\\.4
+P:^_S22\r
+
+A:\e\e\\.5
+P:^_S23\r
+
+A:\e\e\\.6
+P:^_S24\r
+
+A:\e\e\\.7
+P:^_S25\r
+
+A:\e\e\\.8
+P:^_S27\r
+
+A:\e\e\\.9
+P:^_S28\r
+
+
+#
+# Control-Keypad -- Directed tunneling
+#
+
+A:\e\e\\+1
+P:^_C19\r
+
+A:\e\e\\+2
+P:^_C20\r
+
+A:\e\e\\+3
+P:^_C21\r
+
+A:\e\e\\+4
+P:^_C22\r
+
+A:\e\e\\+5
+P:^_C23\r
+
+A:\e\e\\+6
+P:^_C24\r
+
+A:\e\e\\+7
+P:^_C25\r
+
+A:\e\e\\+8
+P:^_C27\r
+
+A:\e\e\\+9
+P:^_C28\r
+
+
+
+#
+# Option-Control-Keypad -- wield {@0} and tunnel
+#
+
+A:\e\ew0\s\s\\+1
+P:^_CO19\r
+
+A:\e\ew0\s\s\\+2
+P:^_CO20\r
+
+A:\e\ew0\s\s\\+3
+P:^_CO21\r
+
+A:\e\ew0\s\s\\+4
+P:^_CO22\r
+
+A:\e\ew0\s\s\\+5
+P:^_CO23\r
+
+A:\e\ew0\s\s\\+6
+P:^_CO24\r
+
+A:\e\ew0\s\s\\+7
+P:^_CO25\r
+
+A:\e\ew0\s\s\\+8
+P:^_CO27\r
+
+A:\e\ew0\s\s\\+9
+P:^_CO28\r
+
+
+#
+# Option-Control-Keypad-Zero -- wield {@0}
+#
+
+A:\e\ew0\s
+P:^_CO18\r
+
+
+
+#
+# Hack -- Arrow-Keys
+#
+
+A:4
+P:^_59\r
+
+A:6
+P:^_60\r
+
+A:2
+P:^_61\r
+
+A:8
+P:^_62\r
+
+
diff --git a/lib/pref/pref-sdl.prf b/lib/pref/pref-sdl.prf
new file mode 100644
index 00000000..3bc0f030
--- /dev/null
+++ b/lib/pref/pref-sdl.prf
@@ -0,0 +1,144 @@
+# File: pref-sdl.prf
+
+# This file implements macros for extended keyboard commands (characters not
+# within the 128 character ASCII set).
+# Basically, if you have to hold down control or alt or it's an arrow key,
+# it will be handled here. This means that we can let SDL worry about figuring
+# out what key is which; all it needs to do is give us the name and we'll map
+# it here.
+#
+# Note the use of "\e\e\e\e" (four escapes) to allow the macros to work
+# even if the game is not yet ready for a command.
+#
+# Note the use of "\\." (for "run") and "\\+" (for "alter"), to make sure
+# that the macros will work regardless of the "keymap" being used.
+#
+
+# Basic Arrow Movement
+
+A:8
+P:\[up]
+
+A:6
+P:\[right]
+
+A:4
+P:\[left]
+
+A:2
+P:\[down]
+
+# Basic Arrows with Shift Down
+
+A:\e\e\e\e\\.8
+P:\[shift-up]
+
+A:\e\e\e\e\\.6
+P:\[shift-right]
+
+A:\e\e\e\e\\.4
+P:\[shift-left]
+
+A:\e\e\e\e\\.2
+P:\[shift-down]
+
+# Basic Arrows with Control Down
+
+A:\e\e\e\e\\+8
+P:\[ctrl-up]
+
+A:\e\e\e\e\\+6
+P:\[ctrl-right]
+
+A:\e\e\e\e\\+4
+P:\[ctrl-left]
+
+A:\e\e\e\e\\+2
+P:\[ctrl-down]
+
+# Keypad
+
+A:1
+P:\[[1]]
+
+A:2
+P:\[[2]]
+
+A:3
+P:\[[3]]
+
+A:4
+P:\[[4]]
+
+A:5
+P:\[[5]]
+
+A:6
+P:\[[6]]
+
+A:7
+P:\[[7]]
+
+A:8
+P:\[[8]]
+
+A:9
+P:\[[9]]
+
+# Keypad With Shift
+
+A:\e\e\e\e\\.1
+P:\[shift-[1]]
+
+A:\e\e\e\e\\.2
+P:\[shift-[2]]
+
+A:\e\e\e\e\\.3
+P:\[shift-[3]]
+
+A:\e\e\e\e\\.4
+P:\[shift-[4]]
+
+A:\e\e\e\e\\.5
+P:\[shift-[5]]
+
+A:\e\e\e\e\\.6
+P:\[shift-[6]]
+
+A:\e\e\e\e\\.7
+P:\[shift-[7]]
+
+A:\e\e\e\e\\.8
+P:\[shift-[8]]
+
+A:\e\e\e\e\\.9
+P:\[shift-[9]]
+
+# Keypad With Control
+
+A:\e\e\e\e\\+1
+P:\[ctrl-[1]]
+
+A:\e\e\e\e\\+2
+P:\[ctrl-[2]]
+
+A:\e\e\e\e\\+3
+P:\[ctrl-[3]]
+
+A:\e\e\e\e\\+4
+P:\[ctrl-[4]]
+
+A:\e\e\e\e\\+5
+P:\[ctrl-[5]]
+
+A:\e\e\e\e\\+6
+P:\[ctrl-[6]]
+
+A:\e\e\e\e\\+7
+P:\[ctrl-[7]]
+
+A:\e\e\e\e\\+8
+P:\[ctrl-[8]]
+
+A:\e\e\e\e\\+9
+P:\[ctrl-[9]]
diff --git a/lib/pref/pref-win.prf b/lib/pref/pref-win.prf
new file mode 100644
index 00000000..7b1501f1
--- /dev/null
+++ b/lib/pref/pref-win.prf
@@ -0,0 +1,534 @@
+# File: pref-ibm.prf
+
+#
+# This file is used by Angband (when it was compiled using "main-ibm.c"
+# or "main-dos.c" or "main-win.c") to specify various "user preferences",
+# including "macros".
+#
+# This file defines some basic macros, which allow the use of the "keypad",
+# alone, and with the shift and/or control modifier keys. All "special"
+# keys are translated by "main-ibm.c" (or "main-win.c") into special "macro
+# triggers" of the encoded form "^_MMMxSS\r", where the "modifier" flags are
+# stored in "MMM", and the two digit hexidecimal scan code of the keypress is
+# stored in "SS".
+#
+# The "main-ibm.prf" and "main-dos.prf" files may not be able to recognize
+# the "/" and "*" keys on the keypad, because it mistakenly classifies the
+# "0x35" and "0x37" codes as the keycodes of "normal" keys.
+#
+# The "main-win.prf" file should not be using the final "control + keypad"
+# section in this file, it was created for "main-ibm.c" and "main-dos.c".
+#
+# The "main-win.prf" file may actually send the "ascii" equivalent of some
+# keypad keys after the keypad key itself, especially if "numlock" is down,
+# which may cause problems. Or it may not, it is hard to tell. This is bad.
+#
+# See "main-ibm.c" and "main-dos.c" and "main-win.c" for more info.
+#
+
+#
+# Macro Trigger configuration
+#
+# T:<trigger template>:<modifiers>:<modifier name1>:<modifier name2>:....
+# '&' in <trigger template> specifies location of modifier character.
+# '#' in <trigger template> specifies location of key code.
+#
+# If <trigger template> is null string, all trigger difinition will be cleared.
+
+T:&x#:CSA:control-:shift-:alt-
+
+# T:<trigger name>:<keycode>:<keycode with shiftkey>
+# '\' in <trigger name> is escape character.
+
+# These keycodes are actually direct keyboard scan code taken from the 'dinput.h'.
+
+?:[EQU $KEYBOARD JAPAN]
+# For Japanese keyboard.
+T:-:0C
+T:^:0D
+T:@:1A
+T:[:1B
+T:;:27
+T:\::28
+T:]:2B
+T:,:33
+T:.:34
+T:\/:35
+T:_:73
+?:1
+
+?:[EQU $KEYBOARD 0]
+# For US keyboard.
+T:-:0C
+T:=:0D
+T:[:1A
+T:]:1B
+T:;:27
+T:\':28
+T:`:29
+T:\\:2B
+T:,:33
+T:.:34
+T:\/:35
+?:1
+
+############
+# Common keycodes (except NEC PC-98x1)
+
+?:[NOT [EQU $KEYBOARD NEC98]]
+T:1:02
+T:2:03
+T:3:04
+T:4:05
+T:5:06
+T:6:07
+T:7:08
+T:8:09
+T:9:0A
+T:0:0B
+T:Backspace:0E
+T:Q:10
+T:W:11
+T:E:12
+T:R:13
+T:T:14
+T:Y:15
+T:U:16
+T:I:17
+T:O:18
+T:P:19
+T:Enter:1C
+T:A:1E
+T:S:1F
+T:D:20
+T:F:21
+T:G:22
+T:H:23
+T:J:24
+T:K:25
+T:L:26
+T:Zenkaku_Hankaku:29
+T:Z:2C
+T:X:2D
+T:C:2E
+T:V:2F
+T:B:30
+T:N:31
+T:M:32
+T:KP_Multiply:37
+T:CapsLock:3A
+T:F1:3B
+T:F2:3C
+T:F3:3D
+T:F4:3E
+T:F5:3F
+T:F6:40
+T:F7:41
+T:F8:42
+T:F9:43
+T:F10:44
+T:Numlock:45
+T:Scroll:46
+#T:KP_7:47
+T:Home:47
+#T:KP_8:48
+T:Up:48
+#T:KP_9:49
+T:Page_Up:49
+T:KP_Subtract:4A
+#T:KP_4:4B
+T:Left:4B
+T:KP_5:4C
+#T:KP_6:4D
+T:Right:4D
+T:KP_Add:4E
+#T:KP_1:4F
+T:End:4F
+#T:KP_2:50
+T:Down:50
+#T:KP_3:51
+T:Page_Down:51
+#T:KP_0:52
+T:Insert:52
+#T:KP_Decimal:53
+T:Delete:53
+T:Oem_102:56
+T:F11:57
+T:F12:58
+T:Menu:5D
+T:F13:64
+T:F14:65
+T:F15:66
+T:Hiragana_Katakana:70
+T:Abnt_C1:73
+T:Henkan:79
+T:Muhenkan:7B
+T:Yen:7D
+T:Abnt_C2:7E
+T:KP_equals:8D
+T:Prevtrack:90
+T:Kanji:94
+T:Stop:95
+T:Ax:96
+T:Unlabeled:97
+T:Nexttrack:99
+T:KP_Enter:9C
+T:Mute:A0
+T:Calculator:A1
+T:Playpause:A2
+T:Mediastop:A4
+T:Volumedown:AE
+T:Volumeup:B0
+T:Webhome:B2
+T:KP_Comma:B3
+T:KP_Divide:B5
+T:Sys_Req:B7
+T:Pause:C5
+#T:Home:C7
+#T:Up:C8
+#T:Prior:C9
+#T:Left:CB
+#T:Right:CD
+#T:End:CF
+#T:Down:D0
+#T:Next:D1
+#T:Insert:D2
+#T:Delete:D3
+T:Lwin:DB
+T:Rwin:DC
+T:Apps:DD
+T:Power:DE
+T:Sleep:DF
+T:Wake:E3
+T:Websearch:E5
+T:Webfavorites:E6
+T:Webrefresh:E7
+T:Webstop:E8
+T:Webforward:E9
+T:Webback:EA
+T:Mycomputer:EB
+T:Mail:EC
+T:Mediaselect:ED
+?:1
+
+
+######################
+# For NEC PC-98x1
+
+?:[EQU $KEYBOARD NEC98]
+T:1:01
+T:2:02
+T:3:03
+T:4:04
+T:5:05
+T:6:06
+T:7:07
+T:8:08
+T:9:09
+T:0:0A
+T:-:0B
+T:^:0C
+T:Yen:0D
+T:Backspace:0E
+T:Q:10
+T:W:11
+T:E:12
+T:R:13
+T:T:14
+T:Y:15
+T:U:16
+T:I:17
+T:O:18
+T:P:19
+T:@:1a
+T:[:1b
+T:Enter:1C
+T:A:1D
+T:S:1E
+T:D:1F
+T:F:20
+T:G:21
+T:H:22
+T:J:23
+T:K:24
+T:L:25
+T:;:26
+T:\::27
+T:[:28
+T:Z:29
+T:X:2A
+T:C:2B
+T:V:2C
+T:B:2D
+T:N:2E
+T:M:2F
+T:,:30
+T:.:31
+T:\/:32
+T:_:33
+T:Henkan:35
+T:Page_Down:36
+T:Page_Up:37
+T:Insert:38
+T:Delete:39
+T:Up:3A
+T:Left:3B
+T:Right:3C
+T:Down:3D
+T:Home:3E
+T:End:3F
+T:KP_Subtract:40
+T:KP_Divide:41
+T:KP_7:42
+T:KP_8:43
+T:KP_9:44
+T:KP_Multiply:45
+T:KP_4:46
+T:KP_5:47
+T:KP_6:48
+T:KP_Add:49
+T:KP_1:4A
+T:KP_2:4B
+T:KP_3:4C
+T:KP_Equal:4D
+T:KP_0:4E
+T:KP_Comma:4F
+T:KP_Decimal:50
+T:Muhenkan:51
+T:F11:52
+T:F12:53
+T:F13:54
+T:F14:55
+T:F15:56
+T:Pause:60
+T:F1:62
+T:F2:63
+T:F3:64
+T:F4:65
+T:F5:66
+T:F6:67
+T:F7:68
+T:F8:69
+T:F9:6A
+T:F10:6B
+T:CapsLock:71
+T:Hiragana_Katakana:72
+T:Menu:79
+
+?:[NOT [EQU $KEYBOARD NEC98]]
+
+
+#
+# Hack -- Some foreign keyboards have a special key on the keyboard, which
+# is used to generate the "<", ">", and "|" keys (alone, shifted, alt-ed).
+#
+
+A:<
+P:^_x56\r
+
+A:>
+P:^_Sx56\r
+
+A:|
+P:^_Ax56\r
+
+
+#
+# Keypad (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:/
+P:^_x35\r
+
+A:*
+P:^_x37\r
+
+A:7
+P:^_x47\r
+
+A:8
+P:^_x48\r
+
+A:9
+P:^_x49\r
+
+A:-
+P:^_x4A\r
+
+A:4
+P:^_x4B\r
+
+A:5
+P:^_x4C\r
+
+A:6
+P:^_x4D\r
+
+A:+
+P:^_x4E\r
+
+A:1
+P:^_x4F\r
+
+A:2
+P:^_x50\r
+
+A:3
+P:^_x51\r
+
+A:0
+P:^_x52\r
+
+A:.
+P:^_x53\r
+
+
+#
+# Shift + Keypad (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:\e\e\e
+P:^_Sx35\r
+
+A:\e\e\e
+P:^_Sx37\r
+
+A:\e\e\\.7
+P:^_Sx47\r
+
+A:\e\e\\.8
+P:^_Sx48\r
+
+A:\e\e\\.9
+P:^_Sx49\r
+
+A:\e\e\e
+P:^_Sx4A\r
+
+A:\e\e\\.4
+P:^_Sx4B\r
+
+A:\e\e\\.5
+P:^_Sx4C\r
+
+A:\e\e\\.6
+P:^_Sx4D\r
+
+A:\e\e\e
+P:^_Sx4E\r
+
+A:\e\e\\.1
+P:^_Sx4F\r
+
+A:\e\e\\.2
+P:^_Sx50\r
+
+A:\e\e\\.3
+P:^_Sx51\r
+
+A:\e\e\e
+P:^_Sx52\r
+
+A:\e\e\e
+P:^_Sx53\r
+
+
+#
+# Control + Keypad (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:\e\e\e
+P:^_Cx35\r
+
+A:\e\e\e
+P:^_Cx37\r
+
+A:\e\e\\+7
+P:^_Cx47\r
+
+A:\e\e\\+8
+P:^_Cx48\r
+
+A:\e\e\\+9
+P:^_Cx49\r
+
+A:\e\e\e
+P:^_Cx4A\r
+
+A:\e\e\\+4
+P:^_Cx4B\r
+
+A:\e\e\\+5
+P:^_Cx4C\r
+
+A:\e\e\\+6
+P:^_Cx4D\r
+
+A:\e\e\e
+P:^_Cx4E\r
+
+A:\e\e\\+1
+P:^_Cx4F\r
+
+A:\e\e\\+2
+P:^_Cx50\r
+
+A:\e\e\\+3
+P:^_Cx51\r
+
+A:\e\e\e
+P:^_Cx52\r
+
+A:\e\e\e
+P:^_Cx53\r
+
+
+#
+# Control + Keypad (/,*,7,8,9,-,4,5,6,+,1,2,3,0,.)
+#
+
+A:\e\e\e
+P:^_Cx95\r
+
+A:\e\e\e
+P:^_Cx96\r
+
+A:\e\e\\+7
+P:^_Cx77\r
+
+A:\e\e\\+8
+P:^_Cx8D\r
+
+A:\e\e\\+9
+P:^_Cx84\r
+
+A:\e\e\e
+P:^_Cx8E\r
+
+A:\e\e\\+4
+P:^_Cx73\r
+
+A:\e\e\\+5
+P:^_Cx8F\r
+
+A:\e\e\\+6
+P:^_Cx74\r
+
+A:\e\e\e
+P:^_Cx90\r
+
+A:\e\e\\+1
+P:^_Cx75\r
+
+A:\e\e\\+2
+P:^_Cx91\r
+
+A:\e\e\\+3
+P:^_Cx76\r
+
+A:\e\e\e
+P:^_Cx92\r
+
+A:\e\e\e
+P:^_Cx93\r
+
diff --git a/lib/pref/pref-x11.prf b/lib/pref/pref-x11.prf
new file mode 100644
index 00000000..f4df9376
--- /dev/null
+++ b/lib/pref/pref-x11.prf
@@ -0,0 +1,413 @@
+# File: pref-x11.prf
+
+#
+# This file provides some macros for use with versions of Angband compiled
+# using the "main-x11.c" (or "main-xaw.c") file.
+#
+# Note the use of "\e\e\e\e" (four escapes) to allow the macros to work
+# even if the game is not yet ready for a command.
+#
+# Note the use of "\\." (for "run") and "\\+" (for "alter"), to make sure
+# that the macros will work regardless of the "keymap" being used.
+#
+
+#
+# Macro Trigger configuration
+#
+# T:<trigger template>:<modifiers>:<modifier name1>:<modifier name2>:....
+# '&' in <trigger template> specifies location of modifier character.
+# '#' in <trigger template> specifies location of key code.
+#
+# If <trigger template> is null string, all trigger difinition will be cleared.
+
+T:&_#:NSOM:control-:shift-:alt-:mod2-
+
+# T:<trigger name>:<keycode>:<keycode with shiftkey>
+# '\' in <trigger name> is escape character.
+
+T:Clear:FF0B
+T:Pause:FF13
+T:Scroll_Lock:FF14
+T:Sys_Req:FF15
+T:Escape:FF1B
+T:Delete:FFFF
+T:Multi_Key:FF20
+T:Codeinput:FF37
+T:SingleCandidate:FF3C
+T:MultipleCandidate:FF3D
+T:PreviousCandidate:FF3E
+T:Kanji:FF21
+T:Muhenkan:FF22
+T:Henkan:FF23
+T:Henkan_Mode:FF23
+T:Romaji:FF24
+T:Hiragana:FF25
+T:Katakana:FF26
+T:Hiragana_Katakana:FF27
+T:Zenkaku:FF28
+T:Hankaku:FF29
+T:Zenkaku_Hankaku:FF2A
+T:Touroku:FF2B
+T:Massyo:FF2C
+T:Kana_Lock:FF2D
+T:Kana_Shift:FF2E
+T:Eisu_Shift:FF2F
+T:Eisu_Toggle:FF30
+T:Kanji_Bangou:FF37
+T:Zen_Koho:FF3D
+T:Mae_Koho:FF3E
+T:Home:FF50
+T:Left:FF51
+T:Up:FF52
+T:Right:FF53
+T:Down:FF54
+T:Page_Up:FF55
+T:Page_Down:FF56
+T:End:FF57
+T:Begin:FF58
+T:Select:FF60
+T:Print:FF61
+T:Execute:FF62
+T:Insert:FF63
+T:Undo:FF65
+T:Redo:FF66
+T:Menu:FF67
+T:Find:FF68
+T:Cancel:FF69
+T:Help:FF6A
+T:Break:FF6B
+T:Mode_Switch:FF7E
+T:Num_Lock:FF7F
+T:KP_Space:FF80
+T:KP_Tab:FF89
+T:KP_Enter:FF8D
+T:KP_F1:FF91
+T:KP_F2:FF92
+T:KP_F3:FF93
+T:KP_F4:FF94
+T:KP_Home:FF95
+T:KP_Left:FF96
+T:KP_Up:FF97
+T:KP_Right:FF98
+T:KP_Down:FF99
+T:KP_Page_Up:FF9A
+T:KP_Page_Down:FF9B
+T:KP_End:FF9C
+T:KP_Begin:FF9D
+T:KP_Insert:FF9E
+T:KP_Delete:FF9F
+T:KP_Equal:FFBD
+T:KP_Multiply:FFAA
+T:KP_Add:FFAB
+T:KP_Comma:FFAC
+T:KP_Subtract:FFAD
+T:KP_Decimal:FFAE
+T:KP_Divide:FFAF
+T:KP_0:FFB0
+T:KP_1:FFB1
+T:KP_2:FFB2
+T:KP_3:FFB3
+T:KP_4:FFB4
+T:KP_5:FFB5
+T:KP_6:FFB6
+T:KP_7:FFB7
+T:KP_8:FFB8
+T:KP_9:FFB9
+T:F1:FFBE
+T:F2:FFBF
+T:F3:FFC0
+T:F4:FFC1
+T:F5:FFC2
+T:F6:FFC3
+T:F7:FFC4
+T:F8:FFC5
+T:F9:FFC6
+T:F10:FFC7
+T:F11:FFC8
+T:F12:FFC9
+T:F13:FFCA
+T:F14:FFCB
+T:F15:FFCC
+T:F16:FFCD
+T:F17:FFCE
+T:F18:FFCF
+T:F19:FFD0
+T:F20:FFD1
+T:F21:FFD2
+T:F22:FFD3
+T:F23:FFD4
+T:F24:FFD5
+T:F25:FFD6
+T:F26:FFD7
+T:F27:FFD8
+T:F28:FFD9
+T:F29:FFDA
+T:F30:FFDB
+T:F31:FFDC
+T:F32:FFDD
+T:F33:FFDE
+T:F34:FFDF
+T:F35:FFE0
+
+T:\::3A:2A
+T:*:3A:2A
+T:;:3B:2B
+T:+:3B:2B
+T:,:2C:3C
+T:<:2C:3C
+T:-:2D:3D
+T:=:2D:3D
+T:.:2E:3E
+T:>:2E:3E
+T:\/:2F:3F
+T:?:2F:3F
+T:0:30:7E
+T:~:30:7E
+T:1:31:21
+T:!:31:21
+T:2:32:22
+T:":32:22
+T:3:33:23
+T:#:33:23
+T:4:34:24
+T:$:34:24
+T:5:35:25
+T:%:35:25
+T:6:36:26
+T:&:36:26
+T:7:37:27
+T:\':37:27
+T:8:38:28
+T:(:38:28
+T:9:39:29
+T:):39:29
+T:@:40:60
+T:`:40:60
+T:A:61:41
+T:B:62:42
+T:C:63:43
+T:D:64:44
+T:E:65:45
+T:F:66:46
+T:G:67:47
+T:H:68:48
+T:I:69:49
+T:J:6A:4A
+T:K:6B:4B
+T:L:6C:4C
+T:M:6D:4D
+T:N:6E:4E
+T:O:6F:4F
+T:P:70:50
+T:Q:71:51
+T:R:72:52
+T:S:73:53
+T:T:74:54
+T:U:75:55
+T:V:76:56
+T:W:77:57
+T:X:78:58
+T:Y:79:59
+T:Z:7A:5A
+T:[:5B:7B
+T:{:5B:7B
+T:\\:5C:5F
+T:_:5C:5F
+T:]:5D:7D
+T:}:5D:7D
+T:^:5E:7E
+T:~:5E:7E
+T:|:A5:7C
+
+
+# Keypad (0-9)
+
+A:0
+P:^__FFB0\r
+P:^__FF63\r
+P:^__????\r
+P:^__FF9E\r
+
+A:1
+P:^__FFB1\r
+P:^__FF57\r
+P:^__FFDE\r
+P:^__FF9C\r
+
+A:2
+P:^__FFB2\r
+P:^__FF54\r
+P:^__FFDF\r
+P:^__FF99\r
+
+A:3
+P:^__FFB3\r
+P:^__FF56\r
+P:^__FFE0\r
+P:^__FF9B\r
+
+A:4
+P:^__FFB4\r
+P:^__FF51\r
+P:^__FFDB\r
+P:^__FF96\r
+
+A:5
+P:^__FFB5\r
+P:^__FF80\r
+P:^__FFDC\r
+P:^__FF9D\r
+
+A:6
+P:^__FFB6\r
+P:^__FF53\r
+P:^__FFDD\r
+P:^__FF98\r
+
+A:7
+P:^__FFB7\r
+P:^__FF50\r
+P:^__FFD8\r
+P:^__FF95\r
+
+A:8
+P:^__FFB8\r
+P:^__FF52\r
+P:^__FFD9\r
+P:^__FF97\r
+
+A:9
+P:^__FFB9\r
+P:^__FF55\r
+P:^__FFDA\r
+P:^__FF9A\r
+
+
+# Shift-Keypad (0-9)
+
+A:\e\e\e\e\\.0
+P:^_S_FFB0\r
+P:^_S_FF63\r
+P:^_S_????\r
+P:^_S_FF9E\r
+
+A:\e\e\e\e\\.1
+P:^_S_FFB1\r
+P:^_S_FF57\r
+P:^_S_FFDE\r
+P:^_S_FF9C\r
+
+A:\e\e\e\e\\.2
+P:^_S_FFB2\r
+P:^_S_FF54\r
+P:^_S_FFDF\r
+P:^_S_FF99\r
+
+A:\e\e\e\e\\.3
+P:^_S_FFB3\r
+P:^_S_FF56\r
+P:^_S_FFE0\r
+P:^_S_FF9B\r
+
+A:\e\e\e\e\\.4
+P:^_S_FFB4\r
+P:^_S_FF51\r
+P:^_S_FFDB\r
+P:^_S_FF96\r
+
+A:\e\e\e\e\\.5
+P:^_S_FFB5\r
+P:^_S_FF80\r
+P:^_S_FFDC\r
+P:^_S_????\r
+
+A:\e\e\e\e\\.6
+P:^_S_FFB6\r
+P:^_S_FF53\r
+P:^_S_FFDD\r
+P:^_S_FF98\r
+
+A:\e\e\e\e\\.7
+P:^_S_FFB7\r
+P:^_S_FF50\r
+P:^_S_FFD8\r
+P:^_S_FF95\r
+
+A:\e\e\e\e\\.8
+P:^_S_FFB8\r
+P:^_S_FF52\r
+P:^_S_FFD9\r
+P:^_S_FF97\r
+
+A:\e\e\e\e\\.9
+P:^_S_FFB9\r
+P:^_S_FF55\r
+P:^_S_FFDA\r
+P:^_S_FF9A\r
+
+
+# Control-Keypad (0-9)
+
+A:\e\e\e\e\\+0
+P:^_N_FFB0\r
+P:^_N_FF63\r
+P:^_N_????\r
+P:^_N_FF9E\r
+
+A:\e\e\e\e\\+1
+P:^_N_FFB1\r
+P:^_N_FF57\r
+P:^_N_FFDE\r
+P:^_N_FF9C\r
+
+A:\e\e\e\e\\+2
+P:^_N_FFB2\r
+P:^_N_FF54\r
+P:^_N_FFDF\r
+P:^_N_FF99\r
+
+A:\e\e\e\e\\+3
+P:^_N_FFB3\r
+P:^_N_FF56\r
+P:^_N_FFE0\r
+P:^_N_FF9B\r
+
+A:\e\e\e\e\\+4
+P:^_N_FFB4\r
+P:^_N_FF51\r
+P:^_N_FFDB\r
+P:^_N_FF96\r
+
+A:\e\e\e\e\\+5
+P:^_N_FFB5\r
+P:^_N_FF80\r
+P:^_N_FFDC\r
+P:^_N_????\r
+
+A:\e\e\e\e\\+6
+P:^_N_FFB6\r
+P:^_N_FF53\r
+P:^_N_FFDD\r
+P:^_N_FF98\r
+
+A:\e\e\e\e\\+7
+P:^_N_FFB7\r
+P:^_N_FF50\r
+P:^_N_FFD8\r
+P:^_N_FF95\r
+
+A:\e\e\e\e\\+8
+P:^_N_FFB8\r
+P:^_N_FF52\r
+P:^_N_FFD9\r
+P:^_N_FF97\r
+
+A:\e\e\e\e\\+9
+P:^_N_FFB9\r
+P:^_N_FF55\r
+P:^_N_FFDA\r
+P:^_N_FF9A\r
+
+
+
+
diff --git a/lib/pref/pref.prf b/lib/pref/pref.prf
new file mode 100644
index 00000000..a6bfdbe1
--- /dev/null
+++ b/lib/pref/pref.prf
@@ -0,0 +1,311 @@
+# File: pref.prf
+
+#
+# This file defines "default" actions of various kinds
+#
+# This file includes, if appropriate, various "sub-files"
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+# Note that the "X" key is mapped in both keysets to the key sequence
+# "w0", which will "swap weapons" as long as both weapons contain the
+# inscription "@0". For example, inscribe your main weapon as "@1@0"
+# and your digger (or secondary weapon) as "@2@0".
+#
+
+
+##### Force certain options #####
+
+## # Option -- Default to original commands
+## X:rogue_like_commands
+
+## # Option -- Default to roguelike commands
+## Y:rogue_like_commands
+
+
+##### Original Keyset Mappings #####
+
+# Stay still
+A:,
+C:0:5
+
+# Movement
+A:;1
+C:0:1
+A:;2
+C:0:2
+A:;3
+C:0:3
+A:;4
+C:0:4
+A:;6
+C:0:6
+A:;7
+C:0:7
+A:;8
+C:0:8
+A:;9
+C:0:9
+
+# Hack -- Return
+A:\r
+C:0:^J
+
+# Hack -- Commit suicide
+A:Q
+C:0:^K
+
+# Hack -- Commit suicide
+A:Q
+C:0:^C
+
+
+##### Roguelike Keyset Mappings #####
+
+# Run
+A:.
+C:1:,
+
+# Stay still
+A:,
+C:1:.
+
+# Stay still
+A:,
+C:1:5
+
+# Movement
+A:;1
+C:1:1
+A:;2
+C:1:2
+A:;3
+C:1:3
+A:;4
+C:1:4
+A:;6
+C:1:6
+A:;7
+C:1:7
+A:;8
+C:1:8
+A:;9
+C:1:9
+
+# Movement (rogue keys)
+A:;1
+C:1:b
+A:;2
+C:1:j
+A:;3
+C:1:n
+A:;4
+C:1:h
+A:;6
+C:1:l
+A:;7
+C:1:y
+A:;8
+C:1:k
+A:;9
+C:1:u
+
+# Running (shift + rogue keys)
+A:.1
+C:1:B
+A:.2
+C:1:J
+A:.3
+C:1:N
+A:.4
+C:1:H
+A:.6
+C:1:L
+A:.7
+C:1:Y
+A:.8
+C:1:K
+A:.9
+C:1:U
+
+# Altering (control + rogue keys)
+A:+1
+C:1:^B
+A:+2
+C:1:^J
+A:+3
+C:1:^N
+A:+4
+C:1:^H
+A:+6
+C:1:^L
+A:+7
+C:1:^Y
+A:+8
+C:1:^K
+A:+9
+C:1:^U
+
+# Allow use of the "tunnel" command
+A:T
+C:1:^T
+
+# Allow use of the "destroy" command
+A:k
+C:1:^D
+
+# Locate player on map
+A:L
+C:1:W
+
+# Browse a book (Peruse)
+A:b
+C:1:P
+
+# Toggle search mode
+A:S
+C:1:#
+
+# Use a staff (Zap)
+A:u
+C:1:Z
+
+# Take off equipment
+A:t
+C:1:T
+
+# Fire an item
+A:f
+C:1:t
+
+# Bash a door (Force)
+A:B
+C:1:f
+
+# Look around (examine)
+A:l
+C:1:x
+
+# Aim a wand (Zap)
+A:a
+C:1:z
+
+# Zap a rod (Activate)
+A:z
+C:1:a
+
+# Hack -- Commit suicide
+A:Q
+C:1:^C
+
+# Hack - race/mutation power activation
+A:U
+C:1:O
+
+# Sacrifice at an altar
+A:O
+C:1:^g
+
+# Hack up a corpse
+A:h
+C:1:$
+
+# Cure meat
+A:K
+C:1:^O
+
+# Pet commands
+A:P
+C:1:X
+
+# Engrave
+A:x
+C:1:]
+
+# Steal
+A:Z
+C:1:[
+
+# Drink from a fountain
+A:H
+C:1:V
+
+# Give item
+A:y
+C:1:'
+
+# Chat
+A:Y
+C:1:(
+
+# Command line
+A:#
+C:1:)
+
+# Record command
+A:$
+C:1:S
+
+
+### Extended macros ###
+
+# Note that : and ' can only be included in triggers if they are
+# within quotes (i.e. as ':' or ''').
+
+L:-8192:help:Show this help
+L:-8192:?
+L:-8192:'''
+L:-8191:irc_on:Connect to IRC
+L:-8191:C
+L:-8190:irc_say:Speak on IRC
+L:-8190:@
+L:-8190:':'
+L:-8189:irc_off:Disconnect from IRC
+L:-8188:time:Get the current game time
+L:-8188:T
+L:-8187:skills:Check skills
+L:-8187:S
+L:-8186:html-dump:Save an html screenshot
+L:-8186:D
+L:-8184:quest:Show quest list
+L:-8184:Q
+L:-8183:blunder:Walk without disarming
+L:-8183:B
+L:-8182:ability:Check abilities
+L:-8182:A
+L:y:give:Give an object to a monster
+L:Y:chat:Talk to a monster
+L:j:jam:Jam a door
+
+##### System Specific Subfiles #####
+
+?:[IOR [EQU $SYS xaw] [EQU $SYS x11] [EQU $SYS gtk2]]
+%:pref-x11.prf
+
+?:[EQU $SYS gcu]
+%:pref-gcu.prf
+
+?:[EQU $SYS ami]
+%:pref-ami.prf
+
+?:[EQU $SYS mac]
+%:pref-mac.prf
+
+?:[IOR [EQU $SYS win] [EQU $SYS dos] [EQU $SYS ibm]]
+%:pref-win.prf
+
+?:[EQU $SYS emx]
+%:pref-emx.prf
+
+?:[EQU $SYS acn]
+%:pref-acn.prf
+
+?:[EQU $SYS sdl]
+%:pref-sdl.prf
+
+?:[EQU $SYS pgu]
+%:pref-pgu.prf
+
+?:1
+
+
diff --git a/lib/pref/trap-iso.prf b/lib/pref/trap-iso.prf
new file mode 100644
index 00000000..a2b77aec
--- /dev/null
+++ b/lib/pref/trap-iso.prf
@@ -0,0 +1,429 @@
+# Prf file for use with the 8x8 tiles to define
+# trap image locations. Separated out from main
+# graphics definitions due to the G:T:num:y:x
+# instead of T:num:y:x (major problems if this
+# file is opened in the TileAssigner)
+
+# Weakness Traps
+G:T:1:0x8A:0xF6
+G:T:2:0x8A:0xF6
+G:T:3:0x8A:0xF6
+
+# Intelligence Traps
+G:T:4:0x8A:0xF6
+G:T:5:0x8A:0xF6
+G:T:6:0x8A:0xF6
+
+# Wisdom Traps
+G:T:7:0x8A:0xF6
+G:T:8:0x8A:0xF6
+G:T:9:0x8A:0xF6
+
+# Fumbling Fingers Traps
+G:T:10:0x8A:0xF6
+G:T:11:0x8A:0xF6
+G:T:12:0x8A:0xF6
+
+# Wasting Traps
+G:T:13:0x8A:0xF6
+G:T:14:0x8A:0xF6
+G:T:15:0x8A:0xF6
+
+# Beauty Traps
+G:T:16:0x8A:0xF6
+G:T:17:0x8A:0xF6
+G:T:18:0x8A:0xF6
+
+# Trap of Curse Weapon
+G:T:20:0x8A:0xF7
+
+# Trap of Curse Armor
+G:T:21:0x8A:0xF7
+
+# Earthquake Trap
+G:T:22:0x8A:0xFC
+
+# Poison Needle Trap
+G:T:23:0x8A:0xF8
+
+# Summon Monster Trap
+G:T:24:0x8A:0xFA
+
+# Summon Undead Trap
+G:T:25:0x8A:0xFA
+
+# Summon Greater Undead Trap
+G:T:26:0x8A:0xFA
+
+# Teleport Trap
+G:T:27:0x8A:0xFA
+
+# Paralyzing Trap
+G:T:28:0x8A:0xF8
+
+# Explosive Device
+G:T:29:0x8A:0xF8
+
+# Teleport Item Trap
+G:T:30:0x8A:0xFA
+
+# Lose Memory Trap
+G:T:31:0x8A:0xF8
+
+# Bitter Regret Trap
+G:T:32:0x8A:0xF8
+
+# Bowel Cramps Trap
+G:T:33:0x8A:0xF8
+
+# Blindness/Confusion Trap
+G:T:34:0x8A:0xF8
+
+# Aggravation Trap
+G:T:35:0x8A:0xFC
+
+# Multiplication Trap
+G:T:36:0x8A:0xFC
+
+# Steal Item Trap
+G:T:37:0x8A:0xF7
+
+# Summon Fast Quylthulgs Trap
+G:T:38:0x8A:0xFA
+
+# Trap of Sinking
+G:T:39:0x8A:0xFA
+
+# Trap of Mana Drain
+G:T:40:0x8A:0xF8
+
+# Trap of Missing Money
+#G:T:41:0x8A:0xF7
+G:T:41:0x8A:0xF9
+
+# Trap of No Return
+G:T:42:0x8A:0xF7
+
+# Trap of Silent Switching
+G:T:43:0x8A:0xF7
+
+# Trap of Walls
+G:T:44:0x8A:0xFC
+
+# Trap of Calling Out
+G:T:45:0x8A:0xFA
+
+# Trap of Sliding
+G:T:46:0x8A:0xF8
+
+# Trap of Charges Drain
+G:T:47:0x8A:0xF7
+
+# Trap of Stair Movement
+G:T:48:0x8A:0xFC
+
+# Trap of New Trap
+G:T:49:0x8A:0xFC
+
+# Trap of Scatter Items
+G:T:50:0x8A:0xFA
+
+# Trap of Decay
+G:T:51:0x8A:0xF8
+
+# Trap of Wasting Wands
+G:T:52:0x8A:0xF7
+
+# Trap of Filling
+G:T:53:0x8A:0xFC
+
+# Trap of Drain Speed
+G:T:54:0x8A:0xF7
+
+# Lightning Bolt Trap
+G:T:60:0x8A:0xF9
+
+# Poison Bolt Trap
+G:T:61:0x8A:0xF9
+
+# Acid Bolt Trap
+G:T:62:0x8A:0xF9
+
+# Cold Bolt Trap
+G:T:63:0x8A:0xF9
+
+# Fire Bolt Trap
+G:T:64:0x8A:0xF9
+
+# Plasma Bolt Trap
+G:T:65:0x8A:0xF9
+
+# Water Bolt Trap
+G:T:66:0x8A:0xF9
+
+# Lite Bolt Trap
+G:T:67:0x8A:0xF9
+
+# Dark Bolt Trap
+G:T:68:0x8A:0xF9
+
+# Shards Bolt Trap
+G:T:69:0x8A:0xF9
+
+# Sound Bolt Trap
+G:T:70:0x8A:0xF9
+
+# Confusion Bolt Trap
+G:T:71:0x8A:0xF9
+
+# Force Bolt Trap
+G:T:72:0x8A:0xF9
+
+# Inertia Bolt Trap
+G:T:73:0x8A:0xF9
+
+# Mana Bolt Trap
+G:T:74:0x8A:0xF9
+
+# Ice Bolt Trap
+G:T:75:0x8A:0xF9
+
+# Chaos Bolt Trap
+G:T:76:0x8A:0xF9
+
+# Nether Bolt Trap
+G:T:77:0x8A:0xF9
+
+# Disenchantment Bolt Trap
+G:T:78:0x8A:0xF9
+
+# Nexus Bolt Trap
+G:T:79:0x8A:0xF9
+
+# Time Bolt Trap
+G:T:80:0x8A:0xF9
+
+# Gravity Bolt Trap
+G:T:81:0x8A:0xF9
+
+# Lightning Ball Trap
+G:T:82:0x8A:0xFA
+
+# Poison Ball Trap
+G:T:83:0x8A:0xFA
+
+# Acid Ball Trap
+G:T:84:0x8A:0xFA
+
+# Cold Ball Trap
+G:T:85:0x8A:0xFA
+
+# Fire Ball Trap
+G:T:86:0x8A:0xFA
+
+# Plasma Ball Trap
+G:T:87:0x8A:0xFA
+
+# Water Ball Trap
+G:T:88:0x8A:0xFA
+
+# Light Ball Trap
+G:T:89:0x8A:0xFA
+
+# Darkness Ball Trap
+G:T:90:0x8A:0xFA
+
+# Shards Ball Trap
+G:T:91:0x8A:0xFA
+
+# Sound Ball Trap
+G:T:92:0x8A:0xFA
+
+# Confusion Ball Trap
+G:T:93:0x8A:0xFA
+
+# Force Ball Trap
+G:T:94:0x8A:0xFA
+
+# Inertia Ball Trap
+G:T:95:0x8A:0xFA
+
+# Mana Ball Trap
+G:T:96:0x8A:0xFA
+
+# Ice Ball Trap
+G:T:97:0x8A:0xFA
+
+# Chaos Ball Trap
+G:T:98:0x8A:0xFA
+
+# Nether Ball Trap
+G:T:99:0x8A:0xFA
+
+# Disenchantment Ball Trap
+G:T:100:0x8A:0xFA
+
+# Nexus Ball Trap
+G:T:101:0x8A:0xFA
+
+# Time Ball Trap
+G:T:102:0x8A:0xFA
+
+# Gravity Ball Trap
+G:T:103:0x8A:0xFA
+
+# Arrow Trap
+G:T:110:0x8A:0xFC
+
+# Bolt Trap
+G:T:111:0x8A:0xFC
+
+# Seeker Arrow Trap
+G:T:112:0x8A:0xFC
+
+# Seeker Bolt Trap
+G:T:113:0x8A:0xFC
+
+# Poison Arrow Trap
+G:T:114:0x8A:0xFC
+
+# Poison Bolt Trap
+G:T:115:0x8A:0xFC
+
+# Poison Seeker Arrow Trap
+G:T:116:0x8A:0xFC
+
+# Poison Seeker Bolt Trap
+G:T:117:0x8A:0xFC
+
+# Broken Dagger Trap
+G:T:118:0x8A:0xFC
+
+# Dagger Trap
+G:T:119:0x8A:0xFC
+
+# Poison Broken Dagger Trap
+G:T:120:0x8A:0xFC
+
+# Poison Dagger Trap
+G:T:121:0x8A:0xFC
+
+# Arrows Trap
+G:T:122:0x8A:0xFC
+
+# Bolts Trap
+G:T:123:0x8A:0xFC
+
+# Seeker Arrow Trap
+G:T:124:0x8A:0xFC
+
+# Seeker Bolt Trap
+G:T:125:0x8A:0xFC
+
+# Poison Arrows Trap
+G:T:126:0x8A:0xFC
+
+# Poison Bolt Trap
+G:T:127:0x8A:0xFC
+
+# Poison Seeker Arrows Trap
+G:T:128:0x8A:0xFC
+
+# Poison Seeker Bolts Trap
+G:T:129:0x8A:0xFC
+
+# Broken Daggers Trap
+G:T:130:0x8A:0xFC
+
+# Dagger Trap
+G:T:131:0x8A:0xFC
+
+# Poison Broken Daggers Trap
+G:T:132:0x8A:0xFC
+
+# Poison Daggers Trap
+G:T:133:0x8A:0xFC
+
+# Trap of Drop Item
+G:T:140:0x8A:0xF7
+
+# Trap of Drop Items
+G:T:141:0x8A:0xF7
+
+# Trap of Drop Everything
+G:T:142:0x8A:0xF7
+
+# Trap of Femininity
+G:T:150:0x8A:0xF8
+
+# Trap of Masculinity
+G:T:151:0x8A:0xF8
+
+# Trap of Neutrality
+G:T:152:0x8A:0xF8
+
+# Trap of Aging
+G:T:153:0x8A:0xF8
+
+# Trap of Growing
+G:T:154:0x8A:0xF8
+
+# Trap of Shrinking
+G:T:155:0x8A:0xF8
+
+# Trap of Tanker Drain
+G:T:157:0x8A:0xF8
+
+# Trap of Divine Anger
+G:T:158:0x8A:0xFB
+
+# Trap of Divine Wrath
+G:T:159:0x8A:0xFB
+
+# Hallucination Trap
+G:T:160:0x8A:0xF8
+
+# Greater Magic Missile Trap
+G:T:161:0x8A:0xF9
+
+# Foulness Trap
+G:T:162:0x8A:0xF9
+
+# Trap of Death Ray
+G:T:163:0x8A:0xF9
+
+# Trap of Holy Fire
+G:T:164:0x8A:0xF9
+
+# Trap of Hell Fire
+G:T:165:0x8A:0xF9
+
+# Psi Bolt Trap
+G:T:166:0x8A:0xF9
+
+# Psi Drain Trap
+G:T:167:0x8A:0xF8
+
+# Plasma (Nuke) Ball Trap
+G:T:168:0x8A:0xFA
+
+# Psi Ball Trap
+G:T:169:0x8A:0xFA
+
+# Aquirement Trap
+G:T:170:0x8A:0xFA
+
+# Greater Lightning Bolt Trap
+G:T:171:0x8A:0xF9
+
+# Greater Poison Bolt Trap
+G:T:172:0x8A:0xF9
+
+# Greater Acid Bolt Trap
+G:T:173:0x8A:0xF9
+
+# Greater Cold Bolt Trap
+G:T:174:0x8A:0xF9
+
+# Greater Fire Bolt Trap
+G:T:175:0x8A:0xF9
diff --git a/lib/pref/trap-xxx.prf b/lib/pref/trap-xxx.prf
new file mode 100644
index 00000000..f4d699a0
--- /dev/null
+++ b/lib/pref/trap-xxx.prf
@@ -0,0 +1,428 @@
+# Prf file for use with the 8x8 tiles to define
+# trap image locations. Separated out from main
+# graphics definitions due to the G:T:num:y:x
+# instead of T:num:y:x (major problems if this
+# file is opened in the TileAssigner)
+
+# Weakness Traps
+G:T:1:0x82:0x9E
+G:T:2:0x82:0x9E
+G:T:3:0x82:0x9E
+
+# Intelligence Traps
+G:T:4:0x82:0x9E
+G:T:5:0x82:0x9E
+G:T:6:0x82:0x9E
+
+# Wisdom Traps
+G:T:7:0x82:0x9E
+G:T:8:0x82:0x9E
+G:T:9:0x82:0x9E
+
+# Fumbling Fingers Traps
+G:T:10:0x82:0x9E
+G:T:11:0x82:0x9E
+G:T:12:0x82:0x9E
+
+# Wasting Traps
+G:T:13:0x82:0x9E
+G:T:14:0x82:0x9E
+G:T:15:0x82:0x9E
+
+# Beauty Traps
+G:T:16:0x82:0x9E
+G:T:17:0x82:0x9E
+G:T:18:0x82:0x9E
+
+# Trap of Curse Weapon
+G:T:20:0xA2:0x92
+
+# Trap of Curse Armor
+G:T:21:0xA2:0x92
+
+# Earthquake Trap
+G:T:22:0xA2:0x87
+
+# Poison Needle Trap
+G:T:23:0xA2:0x8B
+
+# Summon Monster Trap
+G:T:24:0xA2:0x89
+
+# Summon Undead Trap
+G:T:25:0xA2:0x89
+
+# Summon Greater Undead Trap
+G:T:26:0xA2:0x89
+
+# Teleport Trap
+G:T:27:0x8A:0x9C
+
+# Paralyzing Trap
+G:T:28:0xA2:0x8B
+
+# Explosive Device
+G:T:29:0xA2:0x8B
+
+# Teleport Item Trap
+G:T:30:0x8A:0x9C
+
+# Lose Memory Trap
+G:T:31:0xA2:0x8B
+
+# Bitter Regret Trap
+G:T:32:0xA2:0x8B
+
+# Bowel Cramps Trap
+G:T:33:0xA2:0x8B
+
+# Blindness/Confusion Trap
+G:T:34:0xA2:0x8B
+
+# Aggravation Trap
+G:T:35:0xA2:0x87
+
+# Multiplication Trap
+G:T:36:0xA2:0x87
+
+# Steal Item Trap
+G:T:37:0xA2:0x92
+
+# Summon Fast Quylthulgs Trap
+G:T:38:0xA2:0x89
+
+# Trap of Sinking
+G:T:39:0x8A:0x9C
+
+# Trap of Mana Drain
+G:T:40:0xA2:0x8B
+
+# Trap of Missing Money
+G:T:41:0xA2:0x92
+
+# Trap of No Return
+G:T:42:0xA2:0x92
+
+# Trap of Silent Switching
+G:T:43:0xA2:0x92
+
+# Trap of Walls
+G:T:44:0xA2:0x87
+
+# Trap of Calling Out
+G:T:45:0xA2:0x89
+
+# Trap of Sliding
+G:T:46:0xA2:0x8B
+
+# Trap of Charges Drain
+G:T:47:0xA2:0x92
+
+# Trap of Stair Movement
+G:T:48:0xA2:0x87
+
+# Trap of New Trap
+G:T:49:0xA2:0x87
+
+# Trap of Scatter Items
+G:T:50:0x8A:0x9C
+
+# Trap of Decay
+G:T:51:0xA2:0x8B
+
+# Trap of Wasting Wands
+G:T:52:0xA2:0x92
+
+# Trap of Filling
+G:T:53:0xA2:0x87
+
+# Trap of Drain Speed
+G:T:54:0xA2:0x92
+
+# Lightning Bolt Trap
+G:T:60:0xA2:0x8C
+
+# Poison Bolt Trap
+G:T:61:0xA2:0x8C
+
+# Acid Bolt Trap
+G:T:62:0xA2:0x8C
+
+# Cold Bolt Trap
+G:T:63:0xA2:0x8C
+
+# Fire Bolt Trap
+G:T:64:0xA2:0x8C
+
+# Plasma Bolt Trap
+G:T:65:0xA2:0x8C
+
+# Water Bolt Trap
+G:T:66:0xA2:0x8C
+
+# Lite Bolt Trap
+G:T:67:0xA2:0x8C
+
+# Dark Bolt Trap
+G:T:68:0xA2:0x8C
+
+# Shards Bolt Trap
+G:T:69:0xA2:0x8C
+
+# Sound Bolt Trap
+G:T:70:0xA2:0x8C
+
+# Confusion Bolt Trap
+G:T:71:0xA2:0x8C
+
+# Force Bolt Trap
+G:T:72:0xA2:0x8C
+
+# Inertia Bolt Trap
+G:T:73:0xA2:0x8C
+
+# Mana Bolt Trap
+G:T:74:0xA2:0x8C
+
+# Ice Bolt Trap
+G:T:75:0xA2:0x8C
+
+# Chaos Bolt Trap
+G:T:76:0xA2:0x8C
+
+# Nether Bolt Trap
+G:T:77:0xA2:0x8C
+
+# Disenchantment Bolt Trap
+G:T:78:0xA2:0x8C
+
+# Nexus Bolt Trap
+G:T:79:0xA2:0x8C
+
+# Time Bolt Trap
+G:T:80:0xA2:0x8C
+
+# Gravity Bolt Trap
+G:T:81:0xA2:0x8C
+
+# Lightning Ball Trap
+G:T:82:0xA2:0x8D
+
+# Poison Ball Trap
+G:T:83:0xA2:0x8D
+
+# Acid Ball Trap
+G:T:84:0xA2:0x8D
+
+# Cold Ball Trap
+G:T:85:0xA2:0x8D
+
+# Fire Ball Trap
+G:T:86:0xA2:0x8D
+
+# Plasma Ball Trap
+G:T:87:0xA2:0x8D
+
+# Water Ball Trap
+G:T:88:0xA2:0x8D
+
+# Light Ball Trap
+G:T:89:0xA2:0x8D
+
+# Darkness Ball Trap
+G:T:90:0xA2:0x8D
+
+# Shards Ball Trap
+G:T:91:0xA2:0x8D
+
+# Sound Ball Trap
+G:T:92:0xA2:0x8D
+
+# Confusion Ball Trap
+G:T:93:0xA2:0x8D
+
+# Force Ball Trap
+G:T:94:0xA2:0x8D
+
+# Inertia Ball Trap
+G:T:95:0xA2:0x8D
+
+# Mana Ball Trap
+G:T:96:0xA2:0x8D
+
+# Ice Ball Trap
+G:T:97:0xA2:0x8D
+
+# Chaos Ball Trap
+G:T:98:0xA2:0x8D
+
+# Nether Ball Trap
+G:T:99:0xA2:0x8D
+
+# Disenchantment Ball Trap
+G:T:100:0xA2:0x8D
+
+# Nexus Ball Trap
+G:T:101:0xA2:0x8D
+
+# Time Ball Trap
+G:T:102:0xA2:0x8D
+
+# Gravity Ball Trap
+G:T:103:0xA2:0x8D
+
+# Arrow Trap
+G:T:110:0xA2:0x8E
+
+# Bolt Trap
+G:T:111:0xA2:0x8E
+
+# Seeker Arrow Trap
+G:T:112:0xA2:0x8E
+
+# Seeker Bolt Trap
+G:T:113:0xA2:0x8E
+
+# Poison Arrow Trap
+G:T:114:0xA2:0x8E
+
+# Poison Bolt Trap
+G:T:115:0xA2:0x8E
+
+# Poison Seeker Arrow Trap
+G:T:116:0xA2:0x8E
+
+# Poison Seeker Bolt Trap
+G:T:117:0xA2:0x8E
+
+# Broken Dagger Trap
+G:T:118:0xA2:0x8E
+
+# Dagger Trap
+G:T:119:0xA2:0x8E
+
+# Poison Broken Dagger Trap
+G:T:120:0xA2:0x8E
+
+# Poison Dagger Trap
+G:T:121:0xA2:0x8E
+
+# Arrows Trap
+G:T:122:0xA2:0x8E
+
+# Bolts Trap
+G:T:123:0xA2:0x8E
+
+# Seeker Arrow Trap
+G:T:124:0xA2:0x8E
+
+# Seeker Bolt Trap
+G:T:125:0xA2:0x8E
+
+# Poison Arrows Trap
+G:T:126:0xA2:0x8E
+
+# Poison Bolt Trap
+G:T:127:0xA2:0x8E
+
+# Poison Seeker Arrows Trap
+G:T:128:0xA2:0x8E
+
+# Poison Seeker Bolts Trap
+G:T:129:0xA2:0x8E
+
+# Broken Daggers Trap
+G:T:130:0xA2:0x8E
+
+# Dagger Trap
+G:T:131:0xA2:0x8E
+
+# Poison Broken Daggers Trap
+G:T:132:0xA2:0x8E
+
+# Poison Daggers Trap
+G:T:133:0xA2:0x8E
+
+# Trap of Drop Item
+G:T:140:0xA2:0x92
+
+# Trap of Drop Items
+G:T:141:0xA2:0x92
+
+# Trap of Drop Everything
+G:T:142:0xA2:0x92
+
+# Trap of Femininity
+G:T:150:0xA2:0x8B
+
+# Trap of Masculinity
+G:T:151:0xA2:0x8B
+
+# Trap of Neutrality
+G:T:152:0xA2:0x8B
+
+# Trap of Aging
+G:T:153:0xA2:0x8B
+
+# Trap of Growing
+G:T:154:0xA2:0x8B
+
+# Trap of Shrinking
+G:T:155:0xA2:0x8B
+
+# Trap of Tanker Drain
+G:T:157:0xA2:0x8B
+
+# Trap of Divine Anger
+G:T:158:0xA2:0x88
+
+# Trap of Divine Wrath
+G:T:159:0xA2:0x88
+
+# Hallucination Trap
+G:T:160:0xA2:0x8B
+
+# Greater Magic Missile Trap
+G:T:161:0xA2:0x8C
+
+# Foulness Trap
+G:T:162:0xA2:0x8C
+
+# Trap of Death Ray
+G:T:163:0xA2:0x8C
+
+# Trap of Holy Fire
+G:T:164:0xA2:0x8C
+
+# Trap of Hell Fire
+G:T:165:0xA2:0x8C
+
+# Psi Bolt Trap
+G:T:166:0xA2:0x8C
+
+# Psi Drain Trap
+G:T:167:0xA2:0x8B
+
+# Plasma (Nuke) Ball Trap
+G:T:168:0xA2:0x8D
+
+# Psi Ball Trap
+G:T:169:0xA2:0x8D
+
+# Aquirement Trap
+G:T:170:0xA2:0x89
+
+# Greater Lightning Bolt Trap
+G:T:171:0xA2:0x8C
+
+# Greater Poison Bolt Trap
+G:T:172:0xA2:0x8C
+
+# Greater Acid Bolt Trap
+G:T:173:0xA2:0x8C
+
+# Greater Cold Bolt Trap
+G:T:174:0xA2:0x8C
+
+# Greater Fire Bolt Trap
+G:T:175:0xA2:0x8C \ No newline at end of file
diff --git a/lib/pref/user.prf b/lib/pref/user.prf
new file mode 100644
index 00000000..9e10b2ac
--- /dev/null
+++ b/lib/pref/user.prf
@@ -0,0 +1,50 @@
+# File: user.prf
+
+#
+# This file defines "override" actions of various kinds
+#
+# This file includes, if appropriate, various "sub-files"
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+## Option -- Force the use of original commands
+#X:rogue_like_commands
+
+## Option -- Force the use of roguelike commands
+#Y:rogue_like_commands
+
+
+##### System Specific Subfiles #####
+
+?:[IOR [EQU $SYS xaw] [EQU $SYS x11]]
+%:user-x11.prf
+
+?:[EQU $SYS gcu]
+%:user-gcu.prf
+
+?:[EQU $SYS ami]
+%:user-ami.prf
+
+?:[EQU $SYS mac]
+%:user-mac.prf
+
+?:[EQU $SYS dos]
+%:user-dos.prf
+
+?:[EQU $SYS ibm]
+%:user-ibm.prf
+
+?:[EQU $SYS win]
+%:user-win.prf
+
+?:[EQU $SYS emx]
+%:user-emx.prf
+
+?:[EQU $SYS acn]
+%:user-acn.prf
+
+?:1
+
+
diff --git a/lib/pref/xtra-gcu.prf b/lib/pref/xtra-gcu.prf
new file mode 100644
index 00000000..7097658e
--- /dev/null
+++ b/lib/pref/xtra-gcu.prf
@@ -0,0 +1,34 @@
+# File: xtra-gcu.prf
+
+# Rename this file to "pref-gcu.prf" to allow the VT100 cursor keys
+# to be recognized by Angband. This will also make the "escape" key
+# take a few seconds to recognize, so you may want to use the "`" key
+# instead, or make a macro from escape+escape to escape.
+
+### VT100 Keypad ###
+
+# Special keypad keys (delete, insert)
+A:.
+P:\e[3~
+A:0
+P:\e[2~
+
+# Numerical keypad keys (map to appropriate number)
+A:1
+P:\e[4~
+A:2
+P:\e[B
+A:3
+P:\e[6~
+A:4
+P:\e[D
+A:5
+P:\e[G
+A:6
+P:\e[C
+A:7
+P:\e[1~
+A:8
+P:\e[A
+A:9
+P:\e[5~
diff --git a/lib/pref/xtra-new.prf b/lib/pref/xtra-new.prf
new file mode 100644
index 00000000..de82b976
--- /dev/null
+++ b/lib/pref/xtra-new.prf
@@ -0,0 +1,1128 @@
+# File: xtra-new.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# Edited for use with Adam Bolt's new graphics by Robert Ruehlmann < rr9@angband.org >
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+##### AK 20011216 Default pictures for all races that
+# are not handled below, without caring for class
+
+
+?:[EQU $RACE Human]
+R:0:0x89/0xA0
+?:[EQU $RACE Half-Elf]
+R:0:0x89/0xA1
+?:[EQU $RACE Elf]
+R:0:0x89/0xA2
+?:[EQU $RACE Hobbit]
+R:0:0x89/0xA3
+?:[EQU $RACE Gnome]
+R:0:0x89/0xA4
+?:[EQU $RACE Dwarf]
+R:0:0x89/0xA5
+?:[EQU $RACE Orc]
+R:0:0x89/0xA6
+?:[EQU $RACE Troll]
+R:0:0x89/0xA7
+?:[EQU $RACE Dunadan]
+R:0:0x89/0xA8
+?:[EQU $RACE High-Elf]
+R:0:0x89/0xA9
+?:[EQU $RACE Half-Ogre]
+R:0:0x89/0xAA
+?:[EQU $RACE Beorning]
+R:0:0x89/0xAB
+?:[EQU $RACE Kobold]
+R:0:0x89/0xAC
+?:[EQU $RACE Petty-Dwarf]
+R:0:0x89/0xAD
+?:[EQU $RACE Dark-Elf]
+R:0:0x89/0xAE
+?:[EQU $RACE Ent]
+R:0:0x89/0xAF
+?:[EQU $RACE RohanKnight]
+R:0:0x89/0xB0
+?:[EQU $RACE Thunderlord]
+R:0:0x89/0xB1
+?:[EQU $RACE DeathMold]
+R:0:0x89/0xB2
+?:[EQU $RACE Yeek]
+R:0:0x89/0xB3
+?:[EQU $RACE Wood-Elf]
+R:0:0x89/0xB4
+?:[EQU $RACE Maia]
+R:0:0x89/0xB5
+
+##### Remap the player icon #####
+
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Human] ]
+R:0:0x92/0x80
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Elf] ]
+R:0:0x92/0x81
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Elf] ]
+R:0:0x92/0x82
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Hobbit] ]
+R:0:0x92/0x83
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Gnome] ]
+R:0:0x92/0x84
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Dwarf] ]
+R:0:0x92/0x85
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Orc] ]
+R:0:0x92/0x86
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Troll] ]
+R:0:0x92/0x87
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Dunadan] ]
+R:0:0x92/0x88
+?:[AND [EQU $CLASS Warrior] [EQU $RACE High-Elf] ]
+R:0:0x92/0x89
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Dunadan] ]
+R:0:0x92/0x8A
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Barbarian] ]
+R:0:0x92/0x8B
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Ogre] ]
+R:0:0x92/0x8C
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Giant] ]
+R:0:0x92/0x8D
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Titan] ]
+R:0:0x92/0x8E
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Kobold] ]
+R:0:0x92/0x92
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Nibelung] ]
+R:0:0x92/0x93
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Dark Elf] ]
+R:0:0x92/0x94
+?:[AND [EQU $CLASS Warrior] [EQU $RACE RohanKnight] ]
+R:0:0x93/0x91
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Thunderlord] ]
+R:0:0x92/0x95
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Mindflayer] ]
+R:0:0x92/0x96
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Imp] ]
+R:0:0x92/0x97
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Ent] ]
+R:0:0x92/0x98
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Skeleton] ]
+R:0:0x92/0x99
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Zombie] ]
+R:0:0x92/0x9A
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Vampire] ]
+R:0:0x92/0x9B
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Spectre] ]
+R:0:0x92/0x9C
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Sprite] ]
+R:0:0x92/0x9D
+?:[AND [EQU $CLASS Warrior] [EQU $RACE DeathMold] ]
+R:0:0x92/0x9E
+
+?:[AND [EQU $CLASS Mage] [EQU $RACE Human] ]
+R:0:0x93/0x80
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Elf] ]
+R:0:0x93/0x81
+?:[AND [EQU $CLASS Mage] [EQU $RACE Elf] ]
+R:0:0x93/0x82
+?:[AND [EQU $CLASS Mage] [EQU $RACE Hobbit] ]
+R:0:0x93/0x83
+?:[AND [EQU $CLASS Mage] [EQU $RACE Gnome] ]
+R:0:0x93/0x84
+?:[AND [EQU $CLASS Mage] [EQU $RACE Dwarf] ]
+R:0:0x93/0x85
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Orc] ]
+R:0:0x93/0x86
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Troll] ]
+R:0:0x93/0x87
+?:[AND [EQU $CLASS Mage] [EQU $RACE Dunadan] ]
+R:0:0x93/0x88
+?:[AND [EQU $CLASS Mage] [EQU $RACE High-Elf] ]
+R:0:0x93/0x89
+?:[AND [EQU $CLASS Mage] [EQU $RACE Dunadan] ]
+R:0:0x93/0x8A
+?:[AND [EQU $CLASS Mage] [EQU $RACE Barbarian] ]
+R:0:0x93/0x8B
+?:[AND [EQU $CLASS Mage] [EQU $RACE Ogre] ]
+R:0:0x93/0x8C
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Giant] ]
+R:0:0x93/0x8D
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Titan] ]
+R:0:0x93/0x8E
+?:[AND [EQU $CLASS Mage] [EQU $RACE Cyclops] ]
+R:0:0x93/0x8F
+?:[AND [EQU $CLASS Mage] [EQU $RACE Yeek] ]
+R:0:0x93/0x90
+?:[AND [EQU $CLASS Mage] [EQU $RACE RohanKnight] ]
+R:0:0x93/0x91
+?:[AND [EQU $CLASS Mage] [EQU $RACE Kobold] ]
+R:0:0x93/0x92
+?:[AND [EQU $CLASS Mage] [EQU $RACE Nibelung] ]
+R:0:0x93/0x93
+?:[AND [EQU $CLASS Mage] [EQU $RACE Dark Elf] ]
+R:0:0x93/0x94
+?:[AND [EQU $CLASS Mage] [EQU $RACE Thunderlord] ]
+R:0:0x93/0x95
+?:[AND [EQU $CLASS Mage] [EQU $RACE Mindflayer] ]
+R:0:0x93/0x96
+?:[AND [EQU $CLASS Mage] [EQU $RACE Imp] ]
+R:0:0x93/0x97
+?:[AND [EQU $CLASS Mage] [EQU $RACE Ent] ]
+R:0:0x93/0x98
+?:[AND [EQU $CLASS Mage] [EQU $RACE Skeleton] ]
+R:0:0x93/0x99
+?:[AND [EQU $CLASS Mage] [EQU $RACE Zombie] ]
+R:0:0x93/0x9A
+?:[AND [EQU $CLASS Mage] [EQU $RACE Vampire] ]
+R:0:0x93/0x9B
+?:[AND [EQU $CLASS Mage] [EQU $RACE Spectre] ]
+R:0:0x93/0x9C
+?:[AND [EQU $CLASS Mage] [EQU $RACE Sprite] ]
+R:0:0x93/0x9D
+?:[AND [EQU $CLASS Mage] [EQU $RACE DeathMold] ]
+R:0:0x93/0x9E
+
+?:[AND [EQU $CLASS Priest] [EQU $RACE Human] ]
+R:0:0x94/0x80
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Elf] ]
+R:0:0x94/0x81
+?:[AND [EQU $CLASS Priest] [EQU $RACE Elf] ]
+R:0:0x94/0x82
+?:[AND [EQU $CLASS Priest] [EQU $RACE Hobbit] ]
+R:0:0x94/0x83
+?:[AND [EQU $CLASS Priest] [EQU $RACE Gnome] ]
+R:0:0x94/0x84
+?:[AND [EQU $CLASS Priest] [EQU $RACE Dwarf] ]
+R:0:0x94/0x85
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Orc] ]
+R:0:0x94/0x86
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Troll] ]
+R:0:0x94/0x87
+?:[AND [EQU $CLASS Priest] [EQU $RACE Dunadan] ]
+R:0:0x94/0x88
+?:[AND [EQU $CLASS Priest] [EQU $RACE High-Elf] ]
+R:0:0x94/0x89
+?:[AND [EQU $CLASS Priest] [EQU $RACE Dunadan] ]
+R:0:0x94/0x8A
+?:[AND [EQU $CLASS Priest] [EQU $RACE Barbarian] ]
+R:0:0x94/0x8B
+?:[AND [EQU $CLASS Priest] [EQU $RACE Ogre] ]
+R:0:0x94/0x8C
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Giant] ]
+R:0:0x94/0x8D
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Titan] ]
+R:0:0x94/0x8E
+?:[AND [EQU $CLASS Priest] [EQU $RACE Cyclops] ]
+R:0:0x94/0x8F
+?:[AND [EQU $CLASS Priest] [EQU $RACE Yeek] ]
+R:0:0x94/0x90
+?:[AND [EQU $CLASS Priest] [EQU $RACE RohanKnight] ]
+R:0:0x94/0x91
+?:[AND [EQU $CLASS Priest] [EQU $RACE Kobold] ]
+R:0:0x94/0x92
+?:[AND [EQU $CLASS Priest] [EQU $RACE Nibelung] ]
+R:0:0x94/0x93
+?:[AND [EQU $CLASS Priest] [EQU $RACE Dark Elf] ]
+R:0:0x94/0x94
+?:[AND [EQU $CLASS Priest] [EQU $RACE Thunderlord] ]
+R:0:0x94/0x95
+?:[AND [EQU $CLASS Priest] [EQU $RACE Mindflayer] ]
+R:0:0x94/0x96
+?:[AND [EQU $CLASS Priest] [EQU $RACE Imp] ]
+R:0:0x94/0x97
+?:[AND [EQU $CLASS Priest] [EQU $RACE Ent] ]
+R:0:0x94/0x98
+?:[AND [EQU $CLASS Priest] [EQU $RACE Skeleton] ]
+R:0:0x94/0x99
+?:[AND [EQU $CLASS Priest] [EQU $RACE Zombie] ]
+R:0:0x94/0x9A
+?:[AND [EQU $CLASS Priest] [EQU $RACE Vampire] ]
+R:0:0x94/0x9B
+?:[AND [EQU $CLASS Priest] [EQU $RACE Spectre] ]
+R:0:0x94/0x9C
+?:[AND [EQU $CLASS Priest] [EQU $RACE Sprite] ]
+R:0:0x94/0x9D
+?:[AND [EQU $CLASS Priest] [EQU $RACE DeathMold] ]
+R:0:0x94/0x9E
+
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Human] ]
+R:0:0x95/0x80
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Elf] ]
+R:0:0x95/0x81
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Elf] ]
+R:0:0x95/0x82
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Hobbit] ]
+R:0:0x95/0x83
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Gnome] ]
+R:0:0x95/0x84
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Dwarf] ]
+R:0:0x95/0x85
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Orc] ]
+R:0:0x95/0x86
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Troll] ]
+R:0:0x95/0x87
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Dunadan] ]
+R:0:0x95/0x88
+?:[AND [EQU $CLASS Rogue] [EQU $RACE High-Elf] ]
+R:0:0x95/0x89
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Dunadan] ]
+R:0:0x95/0x8A
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Barbarian] ]
+R:0:0x95/0x8B
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Ogre] ]
+R:0:0x95/0x8C
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Giant] ]
+R:0:0x95/0x8D
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Titan] ]
+R:0:0x95/0x8E
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Cyclops] ]
+R:0:0x95/0x8F
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Yeek] ]
+R:0:0x95/0x90
+?:[AND [EQU $CLASS Rogue] [EQU $RACE RohanKnight] ]
+R:0:0x95/0x91
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Kobold] ]
+R:0:0x95/0x92
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Nibelung] ]
+R:0:0x95/0x93
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Dark Elf] ]
+R:0:0x95/0x94
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Thunderlord] ]
+R:0:0x95/0x95
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Mindflayer] ]
+R:0:0x95/0x96
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Imp] ]
+R:0:0x95/0x97
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Ent] ]
+R:0:0x95/0x98
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Skeleton] ]
+R:0:0x95/0x99
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Zombie] ]
+R:0:0x95/0x9A
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Vampire] ]
+R:0:0x95/0x9B
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Spectre] ]
+R:0:0x95/0x9C
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Sprite] ]
+R:0:0x95/0x9D
+?:[AND [EQU $CLASS Rogue] [EQU $RACE DeathMold] ]
+R:0:0x95/0x9E
+
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Human] ]
+R:0:0x96/0x80
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Elf] ]
+R:0:0x96/0x81
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Elf] ]
+R:0:0x96/0x82
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Hobbit] ]
+R:0:0x96/0x83
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Gnome] ]
+R:0:0x96/0x84
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Dwarf] ]
+R:0:0x96/0x85
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Orc] ]
+R:0:0x96/0x86
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Troll] ]
+R:0:0x96/0x87
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Dunadan] ]
+R:0:0x96/0x88
+?:[AND [EQU $CLASS Ranger] [EQU $RACE High-Elf] ]
+R:0:0x96/0x89
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Dunadan] ]
+R:0:0x96/0x8A
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Barbarian] ]
+R:0:0x96/0x8B
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Ogre] ]
+R:0:0x96/0x8C
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Giant] ]
+R:0:0x96/0x8D
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Titan] ]
+R:0:0x96/0x8E
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Cyclops] ]
+R:0:0x96/0x8F
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Yeek] ]
+R:0:0x96/0x90
+?:[AND [EQU $CLASS Ranger] [EQU $RACE RohanKnight] ]
+R:0:0x96/0x91
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Kobold] ]
+R:0:0x96/0x92
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Nibelung] ]
+R:0:0x96/0x93
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Dark Elf] ]
+R:0:0x96/0x94
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Thunderlord] ]
+R:0:0x96/0x95
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Mindflayer] ]
+R:0:0x96/0x96
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Imp] ]
+R:0:0x96/0x97
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Ent] ]
+R:0:0x96/0x98
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Skeleton] ]
+R:0:0x96/0x99
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Zombie] ]
+R:0:0x96/0x9A
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Vampire] ]
+R:0:0x96/0x9B
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Spectre] ]
+R:0:0x96/0x9C
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Sprite] ]
+R:0:0x96/0x9D
+?:[AND [EQU $CLASS Ranger] [EQU $RACE DeathMold] ]
+R:0:0x96/0x9E
+
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Human] ]
+R:0:0x97/0x80
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Elf] ]
+R:0:0x97/0x81
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Elf] ]
+R:0:0x97/0x82
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Hobbit] ]
+R:0:0x97/0x83
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Gnome] ]
+R:0:0x97/0x84
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Dwarf] ]
+R:0:0x97/0x85
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Orc] ]
+R:0:0x97/0x86
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Troll] ]
+R:0:0x97/0x87
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Dunadan] ]
+R:0:0x97/0x88
+?:[AND [EQU $CLASS Paladin] [EQU $RACE High-Elf] ]
+R:0:0x97/0x89
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Dunadan] ]
+R:0:0x97/0x8A
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Barbarian] ]
+R:0:0x97/0x8B
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Ogre] ]
+R:0:0x97/0x8C
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Giant] ]
+R:0:0x97/0x8D
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Titan] ]
+R:0:0x97/0x8E
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Cyclops] ]
+R:0:0x97/0x8F
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Yeek] ]
+R:0:0x97/0x90
+?:[AND [EQU $CLASS Paladin] [EQU $RACE RohanKnight] ]
+R:0:0x97/0x91
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Kobold] ]
+R:0:0x97/0x92
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Nibelung] ]
+R:0:0x97/0x93
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Dark Elf] ]
+R:0:0x97/0x94
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Thunderlord] ]
+R:0:0x97/0x95
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Mindflayer] ]
+R:0:0x97/0x96
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Imp] ]
+R:0:0x97/0x97
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Ent] ]
+R:0:0x97/0x98
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Skeleton] ]
+R:0:0x97/0x99
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Zombie] ]
+R:0:0x97/0x9A
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Vampire] ]
+R:0:0x97/0x9B
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Spectre] ]
+R:0:0x97/0x9C
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Sprite] ]
+R:0:0x97/0x9D
+?:[AND [EQU $CLASS Paladin] [EQU $RACE DeathMold] ]
+R:0:0x97/0x9E
+
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Human] ]
+R:0:0x98/0x80
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Half-Elf] ]
+R:0:0x98/0x81
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Elf] ]
+R:0:0x98/0x82
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Hobbit] ]
+R:0:0x98/0x83
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Gnome] ]
+R:0:0x98/0x84
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Dwarf] ]
+R:0:0x98/0x85
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Half-Orc] ]
+R:0:0x98/0x86
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Half-Troll] ]
+R:0:0x98/0x87
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Dunadan] ]
+R:0:0x98/0x88
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE High-Elf] ]
+R:0:0x98/0x89
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Dunadan] ]
+R:0:0x98/0x8A
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Barbarian] ]
+R:0:0x98/0x8B
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Ogre] ]
+R:0:0x98/0x8C
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Half-Giant] ]
+R:0:0x98/0x8D
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Half-Titan] ]
+R:0:0x98/0x8E
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Cyclops] ]
+R:0:0x98/0x8F
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Yeek] ]
+R:0:0x98/0x90
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE RohanKnight] ]
+R:0:0x98/0x91
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Kobold] ]
+R:0:0x98/0x92
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Nibelung] ]
+R:0:0x98/0x93
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Dark Elf] ]
+R:0:0x98/0x94
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Thunderlord] ]
+R:0:0x98/0x95
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Mindflayer] ]
+R:0:0x98/0x96
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Imp] ]
+R:0:0x98/0x97
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Ent] ]
+R:0:0x98/0x98
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Skeleton] ]
+R:0:0x98/0x99
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Zombie] ]
+R:0:0x98/0x9A
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Vampire] ]
+R:0:0x98/0x9B
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Spectre] ]
+R:0:0x98/0x9C
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE Sprite] ]
+R:0:0x98/0x9D
+?:[AND [EQU $CLASS Warrior-Mage] [EQU $RACE DeathMold] ]
+R:0:0x98/0x9E
+
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Human] ]
+R:0:0x99/0x80
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Half-Elf] ]
+R:0:0x99/0x81
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Elf] ]
+R:0:0x99/0x82
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Hobbit] ]
+R:0:0x99/0x83
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Gnome] ]
+R:0:0x99/0x84
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Dwarf] ]
+R:0:0x99/0x85
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Half-Orc] ]
+R:0:0x99/0x86
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Half-Troll] ]
+R:0:0x99/0x87
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Dunadan] ]
+R:0:0x99/0x88
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE High-Elf] ]
+R:0:0x99/0x89
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Dunadan] ]
+R:0:0x99/0x8A
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Barbarian] ]
+R:0:0x99/0x8B
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Ogre] ]
+R:0:0x99/0x8C
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Half-Giant] ]
+R:0:0x99/0x8D
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Half-Titan] ]
+R:0:0x99/0x8E
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Cyclops] ]
+R:0:0x99/0x8F
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Yeek] ]
+R:0:0x99/0x90
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE RohanKnight] ]
+R:0:0x99/0x91
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Kobold] ]
+R:0:0x99/0x92
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Nibelung] ]
+R:0:0x99/0x93
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Dark Elf] ]
+R:0:0x99/0x94
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Thunderlord] ]
+R:0:0x99/0x95
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Mindflayer] ]
+R:0:0x99/0x96
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Imp] ]
+R:0:0x99/0x97
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Ent] ]
+R:0:0x99/0x98
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Skeleton] ]
+R:0:0x99/0x99
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Zombie] ]
+R:0:0x99/0x9A
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Vampire] ]
+R:0:0x99/0x9B
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Spectre] ]
+R:0:0x99/0x9C
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE Sprite] ]
+R:0:0x99/0x9D
+?:[AND [EQU $CLASS Chaos-Warrior] [EQU $RACE DeathMold] ]
+R:0:0x99/0x9E
+
+?:[AND [EQU $CLASS Monk] [EQU $RACE Human] ]
+R:0:0x9A/0x80
+?:[AND [EQU $CLASS Monk] [EQU $RACE Half-Elf] ]
+R:0:0x9A/0x81
+?:[AND [EQU $CLASS Monk] [EQU $RACE Elf] ]
+R:0:0x9A/0x82
+?:[AND [EQU $CLASS Monk] [EQU $RACE Hobbit] ]
+R:0:0x9A/0x83
+?:[AND [EQU $CLASS Monk] [EQU $RACE Gnome] ]
+R:0:0x9A/0x84
+?:[AND [EQU $CLASS Monk] [EQU $RACE Dwarf] ]
+R:0:0x9A/0x85
+?:[AND [EQU $CLASS Monk] [EQU $RACE Half-Orc] ]
+R:0:0x9A/0x86
+?:[AND [EQU $CLASS Monk] [EQU $RACE Half-Troll] ]
+R:0:0x9A/0x87
+?:[AND [EQU $CLASS Monk] [EQU $RACE Dunadan] ]
+R:0:0x9A/0x88
+?:[AND [EQU $CLASS Monk] [EQU $RACE High-Elf] ]
+R:0:0x9A/0x89
+?:[AND [EQU $CLASS Monk] [EQU $RACE Dunadan] ]
+R:0:0x9A/0x8A
+?:[AND [EQU $CLASS Monk] [EQU $RACE Barbarian] ]
+R:0:0x9A/0x8B
+?:[AND [EQU $CLASS Monk] [EQU $RACE Ogre] ]
+R:0:0x9A/0x8C
+?:[AND [EQU $CLASS Monk] [EQU $RACE Half-Giant] ]
+R:0:0x9A/0x8D
+?:[AND [EQU $CLASS Monk] [EQU $RACE Half-Titan] ]
+R:0:0x9A/0x8E
+?:[AND [EQU $CLASS Monk] [EQU $RACE Cyclops] ]
+R:0:0x9A/0x8F
+?:[AND [EQU $CLASS Monk] [EQU $RACE Yeek] ]
+R:0:0x9A/0x90
+?:[AND [EQU $CLASS Monk] [EQU $RACE RohanKnight] ]
+R:0:0x9A/0x91
+?:[AND [EQU $CLASS Monk] [EQU $RACE Kobold] ]
+R:0:0x9A/0x92
+?:[AND [EQU $CLASS Monk] [EQU $RACE Nibelung] ]
+R:0:0x9A/0x93
+?:[AND [EQU $CLASS Monk] [EQU $RACE Dark Elf] ]
+R:0:0x9A/0x94
+?:[AND [EQU $CLASS Monk] [EQU $RACE Thunderlord] ]
+R:0:0x9A/0x95
+?:[AND [EQU $CLASS Monk] [EQU $RACE Mindflayer] ]
+R:0:0x9A/0x96
+?:[AND [EQU $CLASS Monk] [EQU $RACE Imp] ]
+R:0:0x9A/0x97
+?:[AND [EQU $CLASS Monk] [EQU $RACE Ent] ]
+R:0:0x9A/0x98
+?:[AND [EQU $CLASS Monk] [EQU $RACE Skeleton] ]
+R:0:0x9A/0x99
+?:[AND [EQU $CLASS Monk] [EQU $RACE Zombie] ]
+R:0:0x9A/0x9A
+?:[AND [EQU $CLASS Monk] [EQU $RACE Vampire] ]
+R:0:0x9A/0x9B
+?:[AND [EQU $CLASS Monk] [EQU $RACE Spectre] ]
+R:0:0x9A/0x9C
+?:[AND [EQU $CLASS Monk] [EQU $RACE Sprite] ]
+R:0:0x9A/0x9D
+?:[AND [EQU $CLASS Monk] [EQU $RACE DeathMold] ]
+R:0:0x9A/0x9E
+
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Human] ]
+R:0:0x9B/0x80
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Half-Elf] ]
+R:0:0x9B/0x81
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Elf] ]
+R:0:0x9B/0x82
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Hobbit] ]
+R:0:0x9B/0x83
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Gnome] ]
+R:0:0x9B/0x84
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Dwarf] ]
+R:0:0x9B/0x85
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Half-Orc] ]
+R:0:0x9B/0x86
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Half-Troll] ]
+R:0:0x9B/0x87
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Dunadan] ]
+R:0:0x9B/0x88
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE High-Elf] ]
+R:0:0x9B/0x89
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Dunadan] ]
+R:0:0x9B/0x8A
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Barbarian] ]
+R:0:0x9B/0x8B
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Ogre] ]
+R:0:0x9B/0x8C
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Half-Giant] ]
+R:0:0x9B/0x8D
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Half-Titan] ]
+R:0:0x9B/0x8E
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Cyclops] ]
+R:0:0x9B/0x8F
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Yeek] ]
+R:0:0x9B/0x90
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE RohanKnight] ]
+R:0:0x9B/0x91
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Kobold] ]
+R:0:0x9B/0x92
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Nibelung] ]
+R:0:0x9B/0x93
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Dark Elf] ]
+R:0:0x9B/0x94
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Thunderlord] ]
+R:0:0x9B/0x95
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Mindflayer] ]
+R:0:0x9B/0x96
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Imp] ]
+R:0:0x9B/0x97
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Ent] ]
+R:0:0x9B/0x98
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Skeleton] ]
+R:0:0x9B/0x99
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Zombie] ]
+R:0:0x9B/0x9A
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Vampire] ]
+R:0:0x9B/0x9B
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Spectre] ]
+R:0:0x9B/0x9C
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE Sprite] ]
+R:0:0x9B/0x9D
+?:[AND [EQU $CLASS Mindcrafter] [EQU $RACE DeathMold] ]
+R:0:0x9B/0x9E
+
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Human] ]
+R:0:0x9C/0x80
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Half-Elf] ]
+R:0:0x9C/0x81
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Elf] ]
+R:0:0x9C/0x82
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Hobbit] ]
+R:0:0x9C/0x83
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Gnome] ]
+R:0:0x9C/0x84
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Dwarf] ]
+R:0:0x9C/0x85
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Half-Orc] ]
+R:0:0x9C/0x86
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Half-Troll] ]
+R:0:0x9C/0x87
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Dunadan] ]
+R:0:0x9C/0x88
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE High-Elf] ]
+R:0:0x9C/0x89
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Dunadan] ]
+R:0:0x9C/0x8A
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Barbarian] ]
+R:0:0x9C/0x8B
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Ogre] ]
+R:0:0x9C/0x8C
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Half-Giant] ]
+R:0:0x9C/0x8D
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Half-Titan] ]
+R:0:0x9C/0x8E
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Cyclops] ]
+R:0:0x9C/0x8F
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Yeek] ]
+R:0:0x9C/0x90
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE RohanKnight] ]
+R:0:0x9C/0x91
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Kobold] ]
+R:0:0x9C/0x92
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Nibelung] ]
+R:0:0x9C/0x93
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Dark Elf] ]
+R:0:0x9C/0x94
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Thunderlord] ]
+R:0:0x9C/0x95
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Mindflayer] ]
+R:0:0x9C/0x96
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Imp] ]
+R:0:0x9C/0x97
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Ent] ]
+R:0:0x9C/0x98
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Skeleton] ]
+R:0:0x9C/0x99
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Zombie] ]
+R:0:0x9C/0x9A
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Vampire] ]
+R:0:0x9C/0x9B
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Spectre] ]
+R:0:0x9C/0x9C
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE Sprite] ]
+R:0:0x9C/0x9D
+?:[AND [EQU $CLASS High-Mage] [EQU $RACE DeathMold] ]
+R:0:0x9C/0x9E
+
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Human] ]
+R:0:0x9C/0x80
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Elf] ]
+R:0:0x9C/0x81
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Elf] ]
+R:0:0x9C/0x82
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Hobbit] ]
+R:0:0x9C/0x83
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Gnome] ]
+R:0:0x9C/0x84
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Dwarf] ]
+R:0:0x9C/0x85
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Orc] ]
+R:0:0x9C/0x86
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Troll] ]
+R:0:0x9C/0x87
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Dunadan] ]
+R:0:0x9C/0x88
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE High-Elf] ]
+R:0:0x9C/0x89
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Dunadan] ]
+R:0:0x9C/0x8A
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Barbarian] ]
+R:0:0x9C/0x8B
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Ogre] ]
+R:0:0x9C/0x8C
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Giant] ]
+R:0:0x9C/0x8D
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Titan] ]
+R:0:0x9C/0x8E
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Cyclops] ]
+R:0:0x9C/0x8F
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Yeek] ]
+R:0:0x9C/0x90
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE RohanKnight] ]
+R:0:0x9C/0x91
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Kobold] ]
+R:0:0x9C/0x92
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Nibelung] ]
+R:0:0x9C/0x93
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Dark Elf] ]
+R:0:0x9C/0x94
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Thunderlord] ]
+R:0:0x9C/0x95
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Mindflayer] ]
+R:0:0x9C/0x96
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Imp] ]
+R:0:0x9C/0x97
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Ent] ]
+R:0:0x9C/0x98
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Skeleton] ]
+R:0:0x9C/0x99
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Zombie] ]
+R:0:0x9C/0x9A
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Vampire] ]
+R:0:0x9C/0x9B
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Spectre] ]
+R:0:0x9C/0x9C
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Sprite] ]
+R:0:0x9C/0x9D
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE DeathMold] ]
+R:0:0x9C/0x9E
+
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Human] ]
+R:0:0x96/0x80
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Half-Elf] ]
+R:0:0x96/0x81
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Elf] ]
+R:0:0x96/0x82
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Hobbit] ]
+R:0:0x96/0x83
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Gnome] ]
+R:0:0x96/0x84
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Dwarf] ]
+R:0:0x96/0x85
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Half-Orc] ]
+R:0:0x96/0x86
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Half-Troll] ]
+R:0:0x96/0x87
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Dunadan] ]
+R:0:0x96/0x88
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE High-Elf] ]
+R:0:0x96/0x89
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Dunadan] ]
+R:0:0x96/0x8A
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Barbarian] ]
+R:0:0x96/0x8B
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Ogre] ]
+R:0:0x96/0x8C
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Half-Giant] ]
+R:0:0x96/0x8D
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Half-Titan] ]
+R:0:0x96/0x8E
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Cyclops] ]
+R:0:0x96/0x8F
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Yeek] ]
+R:0:0x96/0x90
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE RohanKnight] ]
+R:0:0x96/0x91
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Kobold] ]
+R:0:0x96/0x92
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Nibelung] ]
+R:0:0x96/0x93
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Dark Elf] ]
+R:0:0x96/0x94
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Thunderlord] ]
+R:0:0x96/0x95
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Mindflayer] ]
+R:0:0x96/0x96
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Imp] ]
+R:0:0x96/0x97
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Ent] ]
+R:0:0x96/0x98
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Skeleton] ]
+R:0:0x96/0x99
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Zombie] ]
+R:0:0x96/0x9A
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Vampire] ]
+R:0:0x96/0x9B
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Spectre] ]
+R:0:0x96/0x9C
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE Sprite] ]
+R:0:0x96/0x9D
+?:[AND [EQU $CLASS BeastMaster] [EQU $RACE DeathMold] ]
+R:0:0x96/0x9E
+
+?:[EQU $CLASS Mimic]
+R:0:0x91/0x95
+
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Human] ]
+R:0:0x93/0x80
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Elf] ]
+R:0:0x93/0x81
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Elf] ]
+R:0:0x93/0x82
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Hobbit] ]
+R:0:0x93/0x83
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Gnome] ]
+R:0:0x93/0x84
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Dwarf] ]
+R:0:0x93/0x85
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Orc] ]
+R:0:0x93/0x86
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Troll] ]
+R:0:0x93/0x87
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Dunadan] ]
+R:0:0x93/0x88
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE High-Elf] ]
+R:0:0x93/0x89
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Dunadan] ]
+R:0:0x93/0x8A
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Barbarian] ]
+R:0:0x93/0x8B
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Ogre] ]
+R:0:0x93/0x8C
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Giant] ]
+R:0:0x93/0x8D
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Half-Titan] ]
+R:0:0x93/0x8E
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Cyclops] ]
+R:0:0x93/0x8F
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Yeek] ]
+R:0:0x93/0x90
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE RohanKnight] ]
+R:0:0x93/0x91
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Kobold] ]
+R:0:0x93/0x92
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Nibelung] ]
+R:0:0x93/0x93
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Dark Elf] ]
+R:0:0x93/0x94
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Thunderlord] ]
+R:0:0x93/0x95
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Mindflayer] ]
+R:0:0x93/0x96
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Imp] ]
+R:0:0x93/0x97
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Ent] ]
+R:0:0x93/0x98
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Skeleton] ]
+R:0:0x93/0x99
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Zombie] ]
+R:0:0x93/0x9A
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Vampire] ]
+R:0:0x93/0x9B
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Spectre] ]
+R:0:0x93/0x9C
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE Sprite] ]
+R:0:0x93/0x9D
+?:[AND [EQU $CLASS Alchemist] [EQU $RACE DeathMold] ]
+R:0:0x93/0x9E
+
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Human] ]
+R:0:0x93/0x80
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Half-Elf] ]
+R:0:0x93/0x81
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Elf] ]
+R:0:0x93/0x82
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Hobbit] ]
+R:0:0x93/0x83
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Gnome] ]
+R:0:0x93/0x84
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Dwarf] ]
+R:0:0x93/0x85
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Half-Orc] ]
+R:0:0x93/0x86
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Half-Troll] ]
+R:0:0x93/0x87
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Dunadan] ]
+R:0:0x93/0x88
+?:[AND [EQU $CLASS Wizard] [EQU $RACE High-Elf] ]
+R:0:0x93/0x89
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Dunadan] ]
+R:0:0x93/0x8A
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Barbarian] ]
+R:0:0x93/0x8B
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Ogre] ]
+R:0:0x93/0x8C
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Half-Giant] ]
+R:0:0x93/0x8D
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Half-Titan] ]
+R:0:0x93/0x8E
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Cyclops] ]
+R:0:0x93/0x8F
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Yeek] ]
+R:0:0x93/0x90
+?:[AND [EQU $CLASS Wizard] [EQU $RACE RohanKnight] ]
+R:0:0x93/0x91
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Kobold] ]
+R:0:0x93/0x92
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Nibelung] ]
+R:0:0x93/0x93
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Dark Elf] ]
+R:0:0x93/0x94
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Thunderlord] ]
+R:0:0x93/0x95
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Mindflayer] ]
+R:0:0x93/0x96
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Imp] ]
+R:0:0x93/0x97
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Ent] ]
+R:0:0x93/0x98
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Skeleton] ]
+R:0:0x93/0x99
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Zombie] ]
+R:0:0x93/0x9A
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Vampire] ]
+R:0:0x93/0x9B
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Spectre] ]
+R:0:0x93/0x9C
+?:[AND [EQU $CLASS Wizard] [EQU $RACE Sprite] ]
+R:0:0x93/0x9D
+?:[AND [EQU $CLASS Wizard] [EQU $RACE DeathMold] ]
+R:0:0x93/0x9E
+
+?:[AND [EQU $CLASS Prior] [EQU $RACE Human] ]
+R:0:0x94/0x80
+?:[AND [EQU $CLASS Prior] [EQU $RACE Half-Elf] ]
+R:0:0x94/0x81
+?:[AND [EQU $CLASS Prior] [EQU $RACE Elf] ]
+R:0:0x94/0x82
+?:[AND [EQU $CLASS Prior] [EQU $RACE Hobbit] ]
+R:0:0x94/0x83
+?:[AND [EQU $CLASS Prior] [EQU $RACE Gnome] ]
+R:0:0x94/0x84
+?:[AND [EQU $CLASS Prior] [EQU $RACE Dwarf] ]
+R:0:0x94/0x85
+?:[AND [EQU $CLASS Prior] [EQU $RACE Half-Orc] ]
+R:0:0x94/0x86
+?:[AND [EQU $CLASS Prior] [EQU $RACE Half-Troll] ]
+R:0:0x94/0x87
+?:[AND [EQU $CLASS Prior] [EQU $RACE Dunadan] ]
+R:0:0x94/0x88
+?:[AND [EQU $CLASS Prior] [EQU $RACE High-Elf] ]
+R:0:0x94/0x89
+?:[AND [EQU $CLASS Prior] [EQU $RACE Dunadan] ]
+R:0:0x94/0x8A
+?:[AND [EQU $CLASS Prior] [EQU $RACE Barbarian] ]
+R:0:0x94/0x8B
+?:[AND [EQU $CLASS Prior] [EQU $RACE Ogre] ]
+R:0:0x94/0x8C
+?:[AND [EQU $CLASS Prior] [EQU $RACE Half-Giant] ]
+R:0:0x94/0x8D
+?:[AND [EQU $CLASS Prior] [EQU $RACE Half-Titan] ]
+R:0:0x94/0x8E
+?:[AND [EQU $CLASS Prior] [EQU $RACE Cyclops] ]
+R:0:0x94/0x8F
+?:[AND [EQU $CLASS Prior] [EQU $RACE Yeek] ]
+R:0:0x94/0x90
+?:[AND [EQU $CLASS Prior] [EQU $RACE RohanKnight] ]
+R:0:0x94/0x91
+?:[AND [EQU $CLASS Prior] [EQU $RACE Kobold] ]
+R:0:0x94/0x92
+?:[AND [EQU $CLASS Prior] [EQU $RACE Nibelung] ]
+R:0:0x94/0x93
+?:[AND [EQU $CLASS Prior] [EQU $RACE Dark Elf] ]
+R:0:0x94/0x94
+?:[AND [EQU $CLASS Prior] [EQU $RACE Thunderlord] ]
+R:0:0x94/0x95
+?:[AND [EQU $CLASS Prior] [EQU $RACE Mindflayer] ]
+R:0:0x94/0x96
+?:[AND [EQU $CLASS Prior] [EQU $RACE Imp] ]
+R:0:0x94/0x97
+?:[AND [EQU $CLASS Prior] [EQU $RACE Ent] ]
+R:0:0x94/0x98
+?:[AND [EQU $CLASS Prior] [EQU $RACE Skeleton] ]
+R:0:0x94/0x99
+?:[AND [EQU $CLASS Prior] [EQU $RACE Zombie] ]
+R:0:0x94/0x9A
+?:[AND [EQU $CLASS Prior] [EQU $RACE Vampire] ]
+R:0:0x94/0x9B
+?:[AND [EQU $CLASS Prior] [EQU $RACE Spectre] ]
+R:0:0x94/0x9C
+?:[AND [EQU $CLASS Prior] [EQU $RACE Sprite] ]
+R:0:0x94/0x9D
+?:[AND [EQU $CLASS Prior] [EQU $RACE DeathMold] ]
+R:0:0x94/0x9E
+
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Human] ]
+R:0:0x92/0x80
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Half-Elf] ]
+R:0:0x92/0x81
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Elf] ]
+R:0:0x92/0x82
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Hobbit] ]
+R:0:0x92/0x83
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Gnome] ]
+R:0:0x92/0x84
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Dwarf] ]
+R:0:0x92/0x85
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Half-Orc] ]
+R:0:0x92/0x86
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Half-Troll] ]
+R:0:0x92/0x87
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Dunadan] ]
+R:0:0x92/0x88
+?:[AND [EQU $CLASS Possessor] [EQU $RACE High-Elf] ]
+R:0:0x92/0x89
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Dunadan] ]
+R:0:0x92/0x8A
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Barbarian] ]
+R:0:0x92/0x8B
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Ogre] ]
+R:0:0x92/0x8C
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Half-Giant] ]
+R:0:0x92/0x8D
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Half-Titan] ]
+R:0:0x92/0x8E
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Kobold] ]
+R:0:0x92/0x92
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Nibelung] ]
+R:0:0x92/0x93
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Dark Elf] ]
+R:0:0x92/0x94
+?:[AND [EQU $CLASS Possessor] [EQU $RACE RohanKnight] ]
+R:0:0x93/0x91
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Thunderlord] ]
+R:0:0x92/0x95
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Mindflayer] ]
+R:0:0x92/0x96
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Imp] ]
+R:0:0x92/0x97
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Ent] ]
+R:0:0x92/0x98
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Skeleton] ]
+R:0:0x92/0x99
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Zombie] ]
+R:0:0x92/0x9A
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Vampire] ]
+R:0:0x92/0x9B
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Spectre] ]
+R:0:0x92/0x9C
+?:[AND [EQU $CLASS Possessor] [EQU $RACE Sprite] ]
+R:0:0x92/0x9D
+?:[AND [EQU $CLASS Possessor] [EQU $RACE DeathMold] ]
+R:0:0x92/0x9E
+
diff --git a/lib/pref/xtra-xxx.prf b/lib/pref/xtra-xxx.prf
new file mode 100644
index 00000000..0c6186de
--- /dev/null
+++ b/lib/pref/xtra-xxx.prf
@@ -0,0 +1,137 @@
+# File: xtra-xxx.prf
+
+#
+# This file defines special attr/char mappings for use in "graphics" mode
+#
+# See "lib/help/command.txt" and "src/files.c" for more information.
+#
+
+
+##### Remap the player icon #####
+
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Human] ]
+R:0:0x8C/0x80
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Elf] ]
+R:0:0x8C/0x81
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Elf] ]
+R:0:0x8C/0x82
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Hobbit] ]
+R:0:0x8C/0x83
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Gnome] ]
+R:0:0x8C/0x84
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Dwarf] ]
+R:0:0x8C/0x85
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Orc] ]
+R:0:0x8C/0x86
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Half-Troll] ]
+R:0:0x8C/0x87
+?:[AND [EQU $CLASS Warrior] [EQU $RACE Dunadan] ]
+R:0:0x8C/0x88
+?:[AND [EQU $CLASS Warrior] [EQU $RACE High-Elf] ]
+R:0:0x8C/0x89
+
+?:[AND [EQU $CLASS Mage] [EQU $RACE Human] ]
+R:0:0x8C/0x8A
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Elf] ]
+R:0:0x8C/0x8B
+?:[AND [EQU $CLASS Mage] [EQU $RACE Elf] ]
+R:0:0x8C/0x8C
+?:[AND [EQU $CLASS Mage] [EQU $RACE Hobbit] ]
+R:0:0x8C/0x8D
+?:[AND [EQU $CLASS Mage] [EQU $RACE Gnome] ]
+R:0:0x8C/0x8E
+?:[AND [EQU $CLASS Mage] [EQU $RACE Dwarf] ]
+R:0:0x8C/0x8F
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Orc] ]
+R:0:0x8C/0x90
+?:[AND [EQU $CLASS Mage] [EQU $RACE Half-Troll] ]
+R:0:0x8C/0x91
+?:[AND [EQU $CLASS Mage] [EQU $RACE Dunadan] ]
+R:0:0x8C/0x92
+?:[AND [EQU $CLASS Mage] [EQU $RACE High-Elf] ]
+R:0:0x8C/0x93
+
+?:[AND [EQU $CLASS Priest] [EQU $RACE Human] ]
+R:0:0x8C/0x94
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Elf] ]
+R:0:0x8C/0x95
+?:[AND [EQU $CLASS Priest] [EQU $RACE Elf] ]
+R:0:0x8C/0x96
+?:[AND [EQU $CLASS Priest] [EQU $RACE Hobbit] ]
+R:0:0x8C/0x97
+?:[AND [EQU $CLASS Priest] [EQU $RACE Gnome] ]
+R:0:0x8C/0x98
+?:[AND [EQU $CLASS Priest] [EQU $RACE Dwarf] ]
+R:0:0x8C/0x99
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Orc] ]
+R:0:0x8C/0x9A
+?:[AND [EQU $CLASS Priest] [EQU $RACE Half-Troll] ]
+R:0:0x8C/0x9B
+?:[AND [EQU $CLASS Priest] [EQU $RACE Dunadan] ]
+R:0:0x8C/0x9C
+?:[AND [EQU $CLASS Priest] [EQU $RACE High-Elf] ]
+R:0:0x8C/0x9D
+
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Human] ]
+R:0:0x8C/0x9E
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Elf] ]
+R:0:0x8C/0x9F
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Elf] ]
+R:0:0x8D/0x80
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Hobbit] ]
+R:0:0x8D/0x81
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Gnome] ]
+R:0:0x8D/0x82
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Dwarf] ]
+R:0:0x8D/0x83
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Orc] ]
+R:0:0x8D/0x84
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Half-Troll] ]
+R:0:0x8D/0x85
+?:[AND [EQU $CLASS Rogue] [EQU $RACE Dunadan] ]
+R:0:0x8D/0x86
+?:[AND [EQU $CLASS Rogue] [EQU $RACE High-Elf] ]
+R:0:0x8D/0x87
+
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Human] ]
+R:0:0x8D/0x88
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Elf] ]
+R:0:0x8D/0x89
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Elf] ]
+R:0:0x8D/0x8A
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Hobbit] ]
+R:0:0x8D/0x8B
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Gnome] ]
+R:0:0x8D/0x8C
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Dwarf] ]
+R:0:0x8D/0x8D
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Orc] ]
+R:0:0x8D/0x8E
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Half-Troll] ]
+R:0:0x8D/0x8F
+?:[AND [EQU $CLASS Ranger] [EQU $RACE Dunadan] ]
+R:0:0x8D/0x90
+?:[AND [EQU $CLASS Ranger] [EQU $RACE High-Elf] ]
+R:0:0x8D/0x91
+
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Human] ]
+R:0:0x8D/0x92
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Elf] ]
+R:0:0x8D/0x93
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Elf] ]
+R:0:0x8D/0x94
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Hobbit] ]
+R:0:0x8D/0x95
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Gnome] ]
+R:0:0x8D/0x96
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Dwarf] ]
+R:0:0x8D/0x97
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Orc] ]
+R:0:0x8D/0x98
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Half-Troll] ]
+R:0:0x8D/0x99
+?:[AND [EQU $CLASS Paladin] [EQU $RACE Dunadan] ]
+R:0:0x8D/0x9A
+?:[AND [EQU $CLASS Paladin] [EQU $RACE High-Elf] ]
+R:0:0x8D/0x9B
+
diff --git a/lib/save/delete.me b/lib/save/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/save/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/scpt/.cvsignore b/lib/scpt/.cvsignore
new file mode 100644
index 00000000..908e5b42
--- /dev/null
+++ b/lib/scpt/.cvsignore
@@ -0,0 +1 @@
+debug.lua
diff --git a/lib/scpt/bounty.lua b/lib/scpt/bounty.lua
new file mode 100644
index 00000000..94c15598
--- /dev/null
+++ b/lib/scpt/bounty.lua
@@ -0,0 +1,90 @@
+-- The bounty quest! bring back corpses to increase your monster lore skill
+
+add_quest
+{
+ ["global"] = "BOUNTY_QUEST",
+ ["name"] = "Bounty quest",
+ ["desc"] = function()
+ if quest(BOUNTY_QUEST).status == QUEST_STATUS_TAKEN then
+ print_hook("#####yBounty quest!\n")
+ print_hook("You must bring back "..monster_race_desc(bounty_quest_monster, 0).." corpse to the beastmaster.\n")
+ print_hook("\n")
+ end
+ end,
+ ["level"] = -1,
+ ["data"] = {
+ ["bounty_quest_monster"] = 0,
+ },
+ ["hooks"] = {
+ -- Start the game without the quest, need to request it
+ [HOOK_BIRTH_OBJECTS] = function()
+ quest(BOUNTY_QUEST).status = QUEST_STATUS_UNTAKEN
+ end,
+ },
+}
+
+add_building_action
+{
+ -- Index is used in ba_info.txt to set the actions
+ ["index"] = 54,
+ ["action"] = function()
+ if quest(BOUNTY_QUEST).status == QUEST_STATUS_UNTAKEN then
+ quest(BOUNTY_QUEST).status = QUEST_STATUS_TAKEN
+ bounty_quest_monster = get_new_bounty_monster(3 + ((player.lev * 3) / 2))
+
+ msg_print("You must bring me back "..monster_race_desc(bounty_quest_monster, 0).." corpse.")
+ else
+ msg_print("You still must bring me back "..monster_race_desc(bounty_quest_monster, 0).." corpse.")
+ end
+ end
+}
+
+add_building_action
+{
+ -- Index is used in ba_info.txt to set the actions
+ ["index"] = 55,
+ ["action"] = function()
+ if quest(BOUNTY_QUEST).status == QUEST_STATUS_TAKEN then
+ local ret, item
+
+ -- Ask for an item
+ ret, item = get_item("What corpse to return?",
+ "You have no corpse to return.",
+ bor(USE_INVEN),
+ function (obj)
+ if (obj.tval == TV_CORPSE) and (obj.pval2 == bounty_quest_monster) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+
+ -- Ok we got the corpse!
+ if ret == TRUE then
+ -- Take the corpse from the inventory
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+
+ msg_print("Ah well done adventurer!")
+ msg_print("As a reward I will teach you a bit of monster lore.")
+
+ if skill(SKILL_LORE).mod == 0 then
+ skill(SKILL_LORE).mod = 900
+ skill(SKILL_LORE).dev = TRUE
+ end
+ skill(SKILL_LORE).value = skill(SKILL_LORE).value + skill(SKILL_LORE).mod
+ if skill(SKILL_PRESERVATION).mod == 0 then
+ skill(SKILL_PRESERVATION).value = 800
+ skill(SKILL_PRESERVATION).mod = 800
+ skill(SKILL_PRESERVATION).dev = TRUE
+ msg_print("I see you don't know the corpse preservation skill, I shall teach you it too.")
+ end
+
+ quest(BOUNTY_QUEST).status = QUEST_STATUS_UNTAKEN
+ bounty_quest_monster = 0
+ end
+ else
+ msg_print("You do not have any bounty quest yet.")
+ end
+ end
+}
diff --git a/lib/scpt/corrupt.lua b/lib/scpt/corrupt.lua
new file mode 100644
index 00000000..550f8bc0
--- /dev/null
+++ b/lib/scpt/corrupt.lua
@@ -0,0 +1,433 @@
+-- Definition of the corruptions
+
+-- The Balrog corruptions
+CORRUPT_BALROG_AURA = add_corruption
+{
+ ["color"] = TERM_ORANGE,
+ ["name"] = "Balrog Aura",
+ ["get_text"] = "A corrupted wall of flames surrounds you.",
+ ["lose_text"] = "The wall of corrupted flames abandons you.",
+ ["desc"] =
+ {
+ " Surrounds you with a fiery aura",
+ " But it can burn scrolls when you read them"
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SH_FIRE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_LITE1)
+ end,
+ [HOOK_READ] = function(obj)
+ if magik(5) == TRUE then
+ msg_print("Your demon aura burns the scroll before you read it!")
+ return TRUE, TRUE, FALSE
+ else
+ return FALSE
+ end
+ end,
+ },
+}
+
+CORRUPT_BALROG_WINGS = add_corruption
+{
+ ["color"] = TERM_ORANGE,
+ ["name"] = "Balrog Wings",
+ ["get_text"] = "Wings of shadow grow in your back.",
+ ["lose_text"] = "The wings in your back fall apart.",
+ ["desc"] =
+ {
+ " Creates ugly, but working, wings allowing you to fly",
+ " But it reduces charisma by 4 and dexterity by 2"
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.xtra_f4 = bor(player.xtra_f4, TR4_FLY)
+ player.modify_stat(A_CHR, -4)
+ player.modify_stat(A_DEX, -2)
+ end,
+ },
+}
+
+CORRUPT_BALROG_STRENGTH = add_corruption
+{
+ ["color"] = TERM_ORANGE,
+ ["name"] = "Balrog Strength",
+ ["get_text"] = "Your muscles get unnatural strength.",
+ ["lose_text"] = "Your muscles get weaker again.",
+ ["desc"] =
+ {
+ " Provides 3 strength and 1 constitution",
+ " But it reduces charisma by 1 and dexterity by 3"
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.modify_stat(A_STR, 3)
+ player.modify_stat(A_CON, 1)
+ player.modify_stat(A_DEX, -3)
+ player.modify_stat(A_CHR, -1)
+ end,
+ },
+}
+
+CORRUPT_BALROG_FORM = add_corruption
+{
+ ["color"] = TERM_YELLOW,
+ ["name"] = "Balrog Form",
+ ["get_text"] = "You feel the might of a Balrog inside you.",
+ ["lose_text"] = "The presence of the Balrog seems to abandon you.",
+ ["desc"] =
+ {
+ " Allows you to turn into a Balrog at will",
+ " You need Balrog Wings, Balrog Aura and Balrog Strength to activate it"
+ },
+ ["depends"] =
+ {
+ [CORRUPT_BALROG_AURA] = TRUE,
+ [CORRUPT_BALROG_WINGS] = TRUE,
+ [CORRUPT_BALROG_STRENGTH] = TRUE
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_BALROG)
+ end,
+ },
+}
+
+
+-- The Demon corruptions
+CORRUPT_DEMON_SPIRIT = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Demon Spirit",
+ ["get_text"] = "Your spirit opens to corrupted thoughts.",
+ ["lose_text"] = "Your spirit closes again to the corrupted thoughts.",
+ ["desc"] =
+ {
+ " Increases your intelligence by 1",
+ " But reduce your charisma by 2",
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.modify_stat(A_INT, 1)
+ player.modify_stat(A_CHR, -2)
+ end,
+ },
+}
+
+CORRUPT_DEMON_HIDE = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Demon Hide",
+ ["get_text"] = "Your skin grows into a thick hide.",
+ ["lose_text"] = "Your skin returns to a natural state.",
+ ["desc"] =
+ {
+ " Increases your armour class by your level",
+ " Provides immunity to fire at level 40",
+ " But reduces speed by your level / 7",
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.to_a = player.to_a + player.lev
+ player.dis_to_a = player.dis_to_a + player.lev
+ player.pspeed = player.pspeed - (player.lev / 7)
+ if player.lev >= 40 then player.xtra_f2 = bor(player.xtra_f2, TR2_IM_FIRE) end
+ end,
+ },
+}
+
+CORRUPT_DEMON_BREATH = add_corruption
+{
+ ["color"] = TERM_RED,
+ ["name"] = "Demon Breath",
+ ["get_text"] = "Your breath becomes mephitic.",
+ ["lose_text"] = "Your breath is once again normal.",
+ ["desc"] =
+ {
+ " Provides fire breath",
+ " But gives a small chance to spoil potions when you quaff them",
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(PWR_BR_FIRE)
+ end,
+ [HOOK_QUAFF] = function(obj)
+ if magik(9) == TRUE then
+ msg_print("Your demon breath spoils the potion!")
+ return TRUE, FALSE
+ else
+ return FALSE
+ end
+ end,
+ },
+}
+
+CORRUPT_DEMON_REALM = add_corruption
+{
+ ["color"] = TERM_L_RED,
+ ["name"] = "Demon Realm",
+ ["get_text"] = "You feel more attuned to the demon realm.",
+ ["lose_text"] = "You lose your attunement to the demon realm.",
+ ["desc"] =
+ {
+ " Provides access to the demon school skill and the use of demonic equipment",
+ " You need Demon Spirit, Demon Hide and Demon Breath to activate it"
+ },
+ ["depends"] =
+ {
+ [CORRUPT_DEMON_SPIRIT] = TRUE,
+ [CORRUPT_DEMON_HIDE] = TRUE,
+ [CORRUPT_DEMON_BREATH] = TRUE
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ -- 1500 may seem a lot, but people are rather unlikely to get the corruption very soon
+ -- due to the dependencies
+ if s_info[SKILL_DAEMON + 1].mod == 0 then s_info[SKILL_DAEMON + 1].mod = 1500 end
+ s_info[SKILL_DAEMON + 1].hidden = FALSE;
+ end,
+ },
+}
+
+
+-- Teleportation corruptions
+
+-- Random teleportation will ask for confirmation 70% of the time
+-- But 30% of the time it will teleport, without asking
+CORRUPT_RANDOM_TELEPORT = add_corruption
+{
+ ["color"] = TERM_GREEN,
+ ["name"] = "Random teleportation",
+ ["get_text"] = "Space seems to fizzle around you.",
+ ["lose_text"] = "Space solidify again around you.",
+ ["desc"] =
+ {
+ " Randomly teleports you around",
+ },
+ -- No oppose field, it will be automatically set when we declare the anti-telep corruption to oppose us
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.xtra_f3 = bor(player.xtra_f3, TR3_TELEPORT)
+ end,
+ [HOOK_PROCESS_WORLD] = function()
+ if rand_int(300) == 1 then
+ if magik(70) == TRUE then
+ if get_check("Teleport?") == TRUE then
+ teleport_player(50)
+ end
+ else
+ disturb(0, 0)
+ msg_print("Your corruption takes over you, you teleport!")
+ teleport_player(50)
+ end
+ end
+ end,
+ },
+}
+
+-- Anti-teleportation corruption, can be stopped with this power
+CORRUPT_ANTI_TELEPORT = add_corruption
+{
+ ["color"] = TERM_GREEN,
+ ["name"] = "Anti-teleportation",
+ ["get_text"] = "Space continuum freezes around you.",
+ ["lose_text"] = "Space continuum can once more be altered around you.",
+ ["desc"] =
+ {
+ " Prevents all teleportations, be it of you or monsters",
+ },
+ ["oppose"] =
+ {
+ [CORRUPT_RANDOM_TELEPORT] = TRUE
+ },
+ ["hooks"] =
+ {
+ [HOOK_BIRTH_OBJECTS] = function()
+ player.corrupt_anti_teleport_stopped = FALSE
+ end,
+ [HOOK_CALC_POWERS] = function()
+ player.add_power(POWER_COR_SPACE_TIME)
+ end,
+ [HOOK_CALC_BONUS] = function()
+ if player.corrupt_anti_teleport_stopped == FALSE then
+ player.resist_continuum = TRUE
+ end
+ end,
+ [HOOK_PROCESS_WORLD] = function()
+ if player.corrupt_anti_teleport_stopped == TRUE then
+ local amt = player.msp + player.csp
+ amt = amt / 100
+ if (amt < 1) then amt = 1 end
+ increase_mana(-amt)
+ if player.csp == 0 then
+ player.corrupt_anti_teleport_stopped = FALSE
+ msg_print("You stop controlling your corruption.")
+ player.update = bor(player.update, PU_BONUS)
+ end
+ end
+ end,
+ },
+}
+
+
+-- Troll blood
+CORRUPT_TROLL_BLOOD = add_corruption
+{
+ ["color"] = TERM_GREEN,
+ ["name"] = "Troll Blood",
+ ["get_text"] = "Your blood thickens, you sense corruption in it.",
+ ["lose_text"] = "Your blood returns to a normal state.",
+ ["desc"] =
+ {
+ " Troll blood flows in your veins, granting increased regeneration",
+ " It also enables you to feel the presence of other troll beings",
+ " But it will make your presence more noticeable and aggravating",
+ },
+ ["can_gain"] = function()
+ -- Ok trolls should not get this one. never.
+ if get_race_name() == "Troll" then
+ return nil
+ else
+ return not nil
+ end
+ end,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN, TR3_AGGRAVATE)
+ player.xtra_esp = bor(player.xtra_esp, ESP_TROLL)
+ end,
+ },
+}
+
+-- The vampire corruption set
+CORRUPT_VAMPIRE_TEETH = add_corruption
+{
+ ["group"] = "Vampire",
+ ["removable"] = FALSE,
+ ["color"] = TERM_L_DARK,
+ ["name"] = "Vampiric Teeth",
+ ["get_text"] = "You grow vampiric teeth!",
+ ["lose_text"] = "BUG! this should not happen",
+ ["desc"] =
+ {
+ " Your teeth allow you to drain blood to feed yourself",
+ " However your stomach now only accepts blood.",
+ },
+ ["allow"] = function()
+ if test_race_flags(1, PR1_NO_SUBRACE_CHANGE) == FALSE then return not nil else return nil end
+ end,
+ ["gain"] = function()
+ switch_subrace(SUBRACE_SAVE, TRUE);
+
+ subrace_add_power(subrace(SUBRACE_SAVE), PWR_VAMPIRISM)
+ subrace(SUBRACE_SAVE).flags1 = bor(subrace(SUBRACE_SAVE).flags1, PR1_VAMPIRE, PR1_UNDEAD, PR1_NO_SUBRACE_CHANGE)
+ end,
+ ["hooks"] =
+ {
+ },
+}
+CORRUPT_VAMPIRE_STRENGTH = add_corruption
+{
+ ["group"] = "Vampire",
+ ["removable"] = FALSE,
+ ["color"] = TERM_L_DARK,
+ ["name"] = "Vampiric Strength",
+ ["get_text"] = "Your body seems more dead than alive.",
+ ["lose_text"] = "BUG! this should not happen",
+ ["desc"] =
+ {
+ " Your body seems somewhat dead",
+ " In this near undead state it has improved strength, constitution and intelligence",
+ " But reduced dexterity, wisdom and charisma.",
+ },
+ ["depends"] =
+ {
+ [CORRUPT_VAMPIRE_TEETH] = TRUE,
+ },
+ ["gain"] = function()
+ -- Apply the bonuses/penalities
+ subrace(SUBRACE_SAVE).r_mhp = subrace(SUBRACE_SAVE).r_mhp + 1
+ subrace(SUBRACE_SAVE).r_exp = subrace(SUBRACE_SAVE).r_exp + 100
+
+ subrace(SUBRACE_SAVE).r_adj[A_STR + 1] = subrace(SUBRACE_SAVE).r_adj[A_STR + 1] + 3
+ subrace(SUBRACE_SAVE).r_adj[A_INT + 1] = subrace(SUBRACE_SAVE).r_adj[A_INT + 1] + 2
+ subrace(SUBRACE_SAVE).r_adj[A_WIS + 1] = subrace(SUBRACE_SAVE).r_adj[A_WIS + 1] - 3
+ subrace(SUBRACE_SAVE).r_adj[A_DEX + 1] = subrace(SUBRACE_SAVE).r_adj[A_DEX + 1] - 2
+ subrace(SUBRACE_SAVE).r_adj[A_CON + 1] = subrace(SUBRACE_SAVE).r_adj[A_CON + 1] + 1
+ subrace(SUBRACE_SAVE).r_adj[A_CHR + 1] = subrace(SUBRACE_SAVE).r_adj[A_CHR + 1] - 4
+
+ -- be reborn!
+ do_rebirth()
+ cmsg_print(TERM_L_DARK, "You feel death slipping inside.")
+ end,
+ ["hooks"] =
+ {
+ },
+}
+CORRUPT_VAMPIRE_VAMPIRE = add_corruption
+{
+ ["group"] = "Vampire",
+ ["removable"] = FALSE,
+ ["color"] = TERM_L_DARK,
+ ["name"] = "Vampire",
+ ["get_text"] = "You die to be reborn in a Vampire form.",
+ ["lose_text"] = "BUG! this should not happen",
+ ["desc"] =
+ {
+ " You are a Vampire. As such you resist cold, poison, darkness and nether.",
+ " Your life is sustained, but you cannot stand the light of the sun."
+ },
+ ["depends"] =
+ {
+ [CORRUPT_VAMPIRE_STRENGTH] = TRUE,
+ },
+ ["gain"] = function()
+ -- Be a Vampire and be proud of it
+ local title = get_subrace_title(SUBRACE_SAVE)
+ if title == " " or title == "Vampire" then
+ title = "Vampire"
+ subrace(SUBRACE_SAVE).place = FALSE
+ else
+ title = "Vampire "..title
+ end
+ set_subrace_title(SUBRACE_SAVE, title)
+
+ -- Bonus/and .. not bonus :)
+ subrace(SUBRACE_SAVE).flags1 = bor(subrace(SUBRACE_SAVE).flags1, PR1_HURT_LITE)
+ subrace(SUBRACE_SAVE).oflags2[2] = bor(subrace(SUBRACE_SAVE).oflags2[2], TR2_RES_POIS, TR2_RES_NETHER, TR2_RES_COLD, TR2_RES_DARK, TR2_HOLD_LIFE)
+ subrace(SUBRACE_SAVE).oflags3[2] = bor(subrace(SUBRACE_SAVE).oflags3[2], TR3_LITE1)
+ end,
+ ["hooks"] =
+ {
+ },
+}
+
+
+--[[
+CORRUPT_ = add_corruption
+{
+ ["color"] = TERM_GREEN,
+ ["name"] = "",
+ ["get_text"] = "",
+ ["lose_text"] = "",
+ ["desc"] =
+ {
+ " ",
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ end,
+ },
+}
+]]
diff --git a/lib/scpt/drunk.lua b/lib/scpt/drunk.lua
new file mode 100644
index 00000000..7d90af8d
--- /dev/null
+++ b/lib/scpt/drunk.lua
@@ -0,0 +1,21 @@
+-- silly function that allows a drunk to take a bottle of wine/ale from the player
+
+function drunk_takes_wine(m_idx, item)
+
+ m_ptr = monster(m_idx)
+ o_ptr = get_object(item)
+
+ if (m_ptr.r_idx == test_monster_name("Singing, happy drunk"))
+ and (o_ptr.tval == TV_FOOD) and ((o_ptr.sval == 38) or (o_ptr.sval == 39)) then
+
+ cmsg_print(TERM_YELLOW, "'Hic!'")
+
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+add_hook_script(HOOK_GIVE, "drunk_takes_wine", "drunk_takes_wine")
diff --git a/lib/scpt/fireprof.lua b/lib/scpt/fireprof.lua
new file mode 100644
index 00000000..0a3aad28
--- /dev/null
+++ b/lib/scpt/fireprof.lua
@@ -0,0 +1,415 @@
+-- The Old Mages/Fireproofing quest: Bring back an essence from a fiery cave and get some books/scrolls/staves fireproofed in return
+
+fireproof_quest = {}
+
+
+-- change this constant (and the FOO_POINTS ones) to adjust the no of items fire-proofed as a reward
+fireproof_quest.TOTAL_ITEM_POINTS = 12
+
+-- These constants are how many 'points' each type of item will take up. So currently, you can fireproof 3 books, 4 staves or 12 scrolls.
+fireproof_quest.BOOK_POINTS = 4
+fireproof_quest.STAFF_POINTS = 3
+fireproof_quest.SCROLL_POINTS = 1
+
+add_quest
+{
+ ["global"] = "FIREPROOF_QUEST",
+ ["name"] = "Old Mages quest",
+ ["desc"] = function()
+ local num_books, num_staff, num_scroll
+
+ num_books = fireproof_quest.item_points_remaining / fireproof_quest.BOOK_POINTS
+ num_staff = fireproof_quest.item_points_remaining / fireproof_quest.STAFF_POINTS
+ num_scroll = fireproof_quest.item_points_remaining / fireproof_quest.SCROLL_POINTS
+
+ -- Quest taken
+ if (quest(FIREPROOF_QUEST).status == QUEST_STATUS_TAKEN) then
+ print_hook("#####yAn Old Mages Quest!\n")
+ print_hook("Retrieve the strange essence for the old mage in Lothlorien.\n")
+ print_hook("\n")
+ -- essence retrieved, not taken to mage
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_COMPLETED) then
+ print_hook("#####yAn Old Mages Quest!\n")
+ print_hook("You have retrieved the essence for the old mage in Lothlorien. Perhaps you \n")
+ print_hook("should see about a reward.\n")
+ print_hook("\n")
+ -- essence returned, not all books fireproofed
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_FINISHED) and (fireproof_quest.item_points_remaining > 0) then
+ print_hook("#####yAn Old Mages Quest!\n")
+ print_hook("You have retrieved the essence for the old mage in Lothlorien. He will still \n")
+ print_hook("fireproof "..num_books.." book(s) or "..num_staff.." staff/staves or "..num_scroll.." scroll(s) for you.\n")
+ print_hook("\n")
+ end
+ end,
+ ["level"] = 20,
+ ["data"] = {
+ -- store some variables
+ ["fireproof_quest.item_points_remaining"] = fireproof_quest.TOTAL_ITEM_POINTS,
+ ["fireproof_quest.essence"] = 0,
+ },
+ ["hooks"] = {
+ -- Start the game without the quest, need to request it
+ [HOOK_BIRTH_OBJECTS] = function()
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_UNTAKEN
+
+ -- reset some variables on birth
+ fireproof_quest.item_points_remaining = fireproof_quest.TOTAL_ITEM_POINTS
+ fireproof_quest.essence = 0
+ end,
+ [HOOK_GEN_QUEST] = function()
+ local essence, y, x, traps, tries, trap_y, trap_x, grid
+
+ -- Only if player doing this quest
+ if (player.inside_quest ~= FIREPROOF_QUEST) then
+ return FALSE
+ else
+ -- load the map
+ load_map("fireprof.map", 2, 2)
+
+ -- no teleport
+ level_flags2 = DF2_NO_TELEPORT
+
+ -- determine type of essence
+ fireproof_quest.essence = randint(18)
+
+ -- create essence
+ essence = create_object(TV_BATERIE, fireproof_quest.essence)
+
+ -- mark essence
+ essence.pval2 = fireproof_quest.essence
+ essence.note = quark_add("quest")
+
+ -- roll for co-ordinates in top half of map
+ y = randint(3) + 2
+ x = randint(45) + 2
+
+ -- drop it
+ drop_near(essence, -1, y, x)
+
+ -- how many traps to generate
+ traps = rand_range(10, 30)
+
+ -- generate the traps
+ while (traps > 0) do
+
+ -- initialise tries variable
+ tries = 0
+
+ -- make sure it's a safe place
+ while (tries == 0) do
+
+ -- get grid coordinates
+ trap_y = randint(19) + 2
+ trap_x = randint(45) + 2
+ grid = cave(trap_y, trap_x)
+
+ -- are the coordinates on a stair, or a wall?
+ if (cave_is(grid, FF1_PERMANENT) ~= 0) or (cave_is(grid, FF1_FLOOR) == 0) then
+
+ -- try again
+ tries = 0
+ else
+ -- not a stair, then stop this 'while'
+ tries = 1
+ end
+ end
+
+ -- randomise level of trap
+ trap_level = rand_range(20, 40)
+
+ -- put the trap there
+ place_trap(trap_y, trap_x, trap_level)
+
+ -- that's one less trap to place
+ traps = traps - 1
+ end
+ return TRUE
+ end
+ end,
+ [HOOK_STAIR] = function()
+ local ret
+
+ -- only ask this if player about to go up stairs of quest and hasn;t retrieved essence
+ if (player.inside_quest ~= FIREPROOF_QUEST) or
+ (quest(FIREPROOF_QUEST).status == QUEST_STATUS_COMPLETED) then
+ return FALSE
+ else
+ if cave(player.py, player.px).feat ~= FEAT_LESS then return end
+
+ -- flush all pending input
+ flush()
+
+ -- confirm
+ ret = get_check("Really abandon the quest?")
+
+ -- if yes, then
+ if (ret == TRUE) then
+
+ -- fail the quest
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_FAILED
+ return FALSE
+ else
+ -- if no, they stay in the quest
+ return TRUE
+ end
+ end
+ end,
+ [HOOK_GET] = function(o_ptr)
+
+ -- if they're in the quest and haven't picked up the essence already, continue
+ if (player.inside_quest ~= FIREPROOF_QUEST) or
+ (quest(FIREPROOF_QUEST).status == QUEST_STATUS_COMPLETED) then
+ return FALSE
+ else
+
+ -- check that it's the real essence and not another one generated via the random object placing in fireproof.map
+ if (o_ptr.pval2 == fireproof_quest.essence) then
+
+ -- ok mark the quest 'completed'
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_COMPLETED
+ msg_print(TERM_YELLOW, "Fine! Looks like you've found it.")
+ end
+ end
+ end,
+
+ },
+}
+
+-- add the bit that determines what happens when the request 'q'uest bit is done in the wizard spire
+add_building_action
+{
+ -- Index is used in ba_info.txt to set the actions
+ ["index"] = 56,
+ ["action"] = function()
+
+ local num_books, num_staff, num_scroll
+
+ num_books = fireproof_quest.item_points_remaining / fireproof_quest.BOOK_POINTS
+ num_staff = fireproof_quest.item_points_remaining / fireproof_quest.STAFF_POINTS
+ num_scroll = fireproof_quest.item_points_remaining / fireproof_quest.SCROLL_POINTS
+
+ -- the quest hasn;t been requested already, right?
+ if quest(FIREPROOF_QUEST).status == QUEST_STATUS_UNTAKEN then
+
+ -- quest has been taken now
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_TAKEN
+ fireproof_quest.item_points_remaining = fireproof_quest.TOTAL_ITEM_POINTS
+
+ -- issue instructions
+ msg_print("I need a very special essence for a spell I am working on. I am too old to ")
+ msg_print("fetch it myself. Please bring it back to me. You can find it north of here.")
+ msg_print("Be careful with it, it's fragile and might be destroyed easily.")
+
+ return TRUE, FALSE, TRUE
+ -- if quest completed (essence was retrieved)
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_COMPLETED) then
+
+ -- ask for essence
+ ret, item = get_item("Which essence?",
+ "You have no essences to return",
+ bor(USE_INVEN),
+ function (obj)
+
+ -- check it's the 'marked' essence
+ if (obj.tval == TV_BATERIE) and (obj.sval == fireproof_quest.essence) and (obj.pval2 == fireproof_quest.essence) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+
+ -- didn't get the essence?
+ if (ret == FALSE) then
+ return TRUE
+
+ -- got the essence!
+ else
+
+ -- take essence
+ inven_item_increase(item, -1)
+ inven_item_optimize(item)
+ msg_print("Great! Let me fireproof some of your items in thanks. I can do "..num_books.." books, ")
+ msg_print(num_staff.." staves, or "..num_scroll.." scrolls.")
+
+ -- how many items to proof?
+ local items = fireproof_quest.item_points_remaining
+
+ -- repeat till up to 3 (value defined as TOTAL_ITEM_POINTS constant) books fireproofed
+ while items > 0 do
+ ret = fireproof()
+
+ -- don't loop the fireproof if there's nothing to fireproof
+ if ret == FALSE then
+ break
+ end
+
+ -- subtract item points
+ items = fireproof_quest.item_points_remaining
+ end
+
+ -- have they all been done?
+ if (fireproof_quest.item_points_remaining == 0) then
+ -- mark quest to make sure no more quests are given
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_REWARDED
+ else
+ -- mark in preparation of anymore books to fireproof
+ quest(FIREPROOF_QUEST).status = QUEST_STATUS_FINISHED
+ end
+
+
+ end
+
+ -- if the player asks for a quest when they already have it, but haven't failed it, give them some extra instructions
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_TAKEN) then
+ msg_print("The essence is in a cave just behind the shop.")
+
+ -- ok not all books have been fireproofed... lets do the rest
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_FINISHED) then
+
+ -- how many books still to proof?
+ local items = fireproof_quest.item_points_remaining
+
+ -- repeat as necessary
+ while items > 0 do
+ ret = fireproof()
+
+ -- don't loop the fireproof if there's nothing to fireproof
+ if ret == FALSE then
+ break
+ else
+ -- have they all been done?
+ if (fireproof_quest.item_points_remaining == 0) then quest(FIREPROOF_QUEST).status = QUEST_STATUS_REWARDED end
+ end
+
+ -- subtract item points
+ items = fireproof_quest.item_points_remaining
+ end
+
+ -- quest failed or completed, then give no more quests
+ elseif (quest(FIREPROOF_QUEST).status == QUEST_STATUS_FAILED) or (quest(FIREPROOF_QUEST).status == QUEST_STATUS_REWARDED) then
+ msg_print("I have no more quests for you")
+ end
+ return TRUE
+ end,
+}
+
+-- the routine that checks for a book and actually fireproofs it
+function fireproof()
+
+ local ret, item, obj2, stack, obj3, carry_it
+
+ ret, item = get_item("Which item shall I fireproof?",
+ "You have no more items I can fireproof, come back when you have some.",
+ bor(USE_INVEN),
+ function (obj)
+
+ -- get some flags
+ local f1, f2, f3, f4, f5, esp = object_flags(obj)
+
+ -- is it a book/staff/scroll, is it already fireproof?
+ if ((obj.tval == TV_BOOK) or (obj.tval == TV_SCROLL) or (obj.tval == TV_STAFF)) and (band(f3, TR3_IGNORE_FIRE) == 0) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+
+ -- get the object type from the number
+ obj2 = get_object(item)
+
+ -- check we have enough points (if we 'got' an item)
+ if (ret == TRUE) then
+ ret2, stack = enough_points(obj2)
+ end
+
+ -- did either routine fail?
+ if (ret == FALSE) or (ret2 == FALSE) then
+ return FALSE
+ else
+
+ -- are we part of the items from a stack?
+ if (obj2.number ~= stack) then
+
+ -- make a new object to handle
+ object_copy(obj_forge, obj2)
+
+ -- give it the right number of items
+ obj_forge.number = stack
+
+ -- adjust for number of items in pack not to be fireproofed
+ obj2.number = obj2.number - stack
+ obj3 = obj_forge
+
+ -- we'll need to add this to the inventory after fireproofing
+ carry_it = TRUE
+ else
+
+ -- use the whole stack
+ obj3 = obj2
+
+ -- we'll be dealing this while it's still in the inventory
+ carry_it = FALSE
+ end
+
+ -- make it fireproof
+ obj3.name2 = 149
+
+ -- apply it, making sure the pvals don't change with apply_magic (it would change the type of book!)
+ local oldpval = obj3.pval
+ local oldpval2 = obj3.pval2
+ local oldpval3 = obj3.pval3
+ apply_magic(obj3, -1, FALSE, FALSE, FALSE)
+ obj3.pval = oldpval
+ obj3.pval2 = oldpval2
+ obj3.pval3 = oldpval3
+
+ -- put it in the inventory if it's only part of a stack
+ if (carry_it == TRUE) then
+ inven_carry(obj3, TRUE)
+ end
+
+ -- id and notice it
+ set_known(obj3)
+ set_aware(obj3)
+
+ return TRUE
+ end
+end
+
+-- This function makes sure the player has enough 'points' left to fireproof stuff.
+function enough_points(obj)
+ local item_value, stack
+
+ -- are the items in a stack?
+ if (obj.number > 1) then
+
+ -- how many to fireproof?
+ stack = get_quantity("How many would you like fireproofed?", obj.number)
+ else
+ stack = 1
+ end
+
+ -- check for item type and multiply number in the stack by the amount of points per item of that type
+ if (obj.tval == TV_BOOK) then
+ item_value = fireproof_quest.BOOK_POINTS * stack
+ elseif (obj.tval == TV_STAFF) then
+ item_value = fireproof_quest.STAFF_POINTS * stack
+ elseif (obj.tval == TV_SCROLL) then
+ item_value = fireproof_quest.SCROLL_POINTS * stack
+ end
+
+ -- do we have enough points?
+ if (item_value > fireproof_quest.item_points_remaining) then
+ msg_print("I do not have enough fireproofing material for that.")
+ return FALSE
+ else
+ -- if so then subtract those points before we do the fireproofing
+ fireproof_quest.item_points_remaining = fireproof_quest.item_points_remaining - item_value
+ end
+
+ -- Used all the points? the quest is completely rewarded.
+ if fireproof_quest.item_points_remaining == 0 then quest(FIREPROOF_QUEST).status = QUEST_STATUS_REWARDED end
+
+ return TRUE, stack
+end
+
diff --git a/lib/scpt/god.lua b/lib/scpt/god.lua
new file mode 100644
index 00000000..3f32888b
--- /dev/null
+++ b/lib/scpt/god.lua
@@ -0,0 +1,640 @@
+-- The god quest: find randomly placed relic in a randomly placed dungeon!
+
+-- set some global variables (stored in the save file via the ["data"] key)
+god_quest = {}
+
+-- increase this number to make god quests more common, to a max value of 100
+god_quest.CHANCE_OF_GOD_QUEST = 21
+
+-- increase this number to make more quests
+god_quest.MAX_NUM_GOD_QUESTS = 5
+
+-- d_idx of the god_quest (Lost Temple) dungeon
+god_quest.DUNGEON_GOD = 30
+
+add_quest
+{
+ ["global"] = "GOD_QUEST",
+ ["name"] = "God quest",
+ ["desc"] = function()
+
+ if quest(GOD_QUEST).status == QUEST_STATUS_TAKEN then
+
+ -- get the direction that the dungeon lies from lothlorien/angband
+ local home, home_axis, home_distance, home2, home2_axis, home2_distance = get_god_quest_axes()
+
+ print_hook("#####yGod quest "..god_quest.quests_given.."!\n")
+ print_hook("Thou art to find the lost temple of thy God and\n");
+ print_hook("to retrieve the lost part of the relic for thy God! \n")
+ if home_axis ~= "close" then
+ print_hook("The temple lies "..home_distance.." to the "..home_axis.." of "..home..", \n")
+ else
+ print_hook("The temple lies very close to "..home..", \n")
+ end
+ if home2_axis ~= "close" then
+ print_hook( "and "..home2_distance.." to the "..home2_axis.." of "..home2..".\n")
+ else
+ print_hook("and very close to "..home2..".\n")
+ end
+ print_hook("\n")
+ end
+ end,
+ ["level"] = -1,
+ ["data"] = {
+ ["god_quest.relic_num"] = 1,
+ ["god_quest.quests_given"] = 0,
+ ["god_quest.relics_found"] = 0,
+ ["god_quest.dun_mindepth"] = 1,
+ ["god_quest.dun_maxdepth"] = 4,
+ ["god_quest.dun_minplev"] = 0,
+ ["god_quest.relic_gen_tries"] = 0,
+ ["god_quest.relic_generated"] = FALSE,
+ ["god_quest.dung_x"] = 1,
+ ["god_quest.dung_y"] = 1,
+ ["god_quest.player_x"] = 0,
+ ["god_quest.player_y"] = 0,
+ },
+ ["hooks"] = {
+ -- Start the game without the quest, given it by chance
+ [HOOK_BIRTH_OBJECTS] = function()
+ quest(GOD_QUEST).status = QUEST_STATUS_UNTAKEN
+
+ -- initialise save-file stored variables when new character is created
+ god_quest.relic_num = 1
+ god_quest.quests_given = 0
+ god_quest.relics_found = 0
+ god_quest.dun_mindepth = 1
+ god_quest.dun_maxdepth = 4
+ god_quest.dun_minplev = 0
+ god_quest.relic_gen_tries = 0
+ god_quest.relic_generated = FALSE
+ end,
+ [HOOK_PLAYER_LEVEL] = function(gained)
+ local home_axis, home
+
+ if gained > 0 then
+ -- roll for chance of quest
+ local give_god_quest = magik(god_quest.CHANCE_OF_GOD_QUEST)
+
+ -- check player is worshipping a god, not already on a god quest.
+ if (player.astral ~= FALSE) or (player.pgod <= 0)
+ or (quest(GOD_QUEST).status == QUEST_STATUS_TAKEN) or (quest(GOD_QUEST).status == QUEST_STATUS_FAILED)
+ or (god_quest.quests_given >= god_quest.MAX_NUM_GOD_QUESTS) or (give_god_quest == FALSE)
+ or ((current_dungeon_idx == god_quest.DUNGEON_GOD) and (dun_level > 0)) or (player.lev <= god_quest.dun_minplev) then
+ -- Don't let a player get quests with trickery
+ if player.lev > god_quest.dun_minplev then
+ god_quest.dun_minplev = player.lev
+ end
+ return
+ else
+ -- each god has different characteristics, so the quests are differnet depending on your god
+ if player.pgod == GOD_ERU then
+ god_quest.relic_num = 7
+ elseif player.pgod == GOD_MANWE then
+ god_quest.relic_num = 8
+ elseif player.pgod == GOD_TULKAS then
+ god_quest.relic_num = 9
+ elseif player.pgod == GOD_MELKOR then
+ god_quest.relic_num = 10
+ elseif player.pgod == GOD_YAVANNA then
+ god_quest.relic_num =11
+ end
+
+ -- This var will need resetting
+ god_quest.relic_generated = FALSE
+ quest(GOD_QUEST).status = QUEST_STATUS_TAKEN
+ god_quest.quests_given = god_quest.quests_given + 1
+
+ -- actually place the dungeon in a random place
+ place_rand_dung()
+
+ -- store the variables of the coords where the player was given the quest
+ god_quest.player_y, god_quest.player_x = player.get_wild_coord()
+
+ -- establish direction of player and 'home' from dungeon
+ local home, home_axis, home_distance, home2, home2_axis, home2_distance = get_god_quest_axes()
+
+ -- God issues instructions
+ cmsg_print(TERM_L_BLUE, "The voice of "..deity(player.pgod).name.." booms in your head:")
+
+ cmsg_print(TERM_YELLOW, "'I have a task for thee.")
+ cmsg_print(TERM_YELLOW, "Centuries ago an ancient relic of mine was broken apart.")
+ cmsg_print(TERM_YELLOW, "The pieces of it have been lost in fallen temples.")
+ cmsg_print(TERM_YELLOW, "Thou art to find my lost temple and retrieve a piece of the relic.")
+ cmsg_print(TERM_YELLOW, "When thy task is done, thou art to lift it in the air and call upon my name.")
+ cmsg_print(TERM_YELLOW, "I shall then come to reclaim what is mine!")
+ if home_axis ~= "close" then
+ cmsg_print(TERM_YELLOW, "The temple lies "..home_distance.." to the "..home_axis.." of "..home..", ")
+ else
+ cmsg_print(TERM_YELLOW, "The temple lies very close to "..home..",")
+ end
+
+ if home2_axis ~= "close" then
+ cmsg_print(TERM_YELLOW, "and "..home2_distance.." to the "..home2_axis.." of "..home2..", I can feel it.'")
+ else
+ cmsg_print(TERM_YELLOW, "and very close to "..home2..", I can feel it.'")
+ end
+
+ -- Prepare depth of dungeon. If this was generated in set_god_dungeon_attributes(),
+ -- then we'd have trouble if someone levelled up in the dungeon!
+ god_quest.dun_mindepth = player.lev*2/3
+ god_quest.dun_maxdepth = god_quest.dun_mindepth + 4
+ end
+ end
+ end,
+ [HOOK_LEVEL_END_GEN] = function()
+ local chance
+
+ -- Check for dungeon
+ if (current_dungeon_idx ~= god_quest.DUNGEON_GOD) or (quest(GOD_QUEST).status == QUEST_STATUS_UNTAKEN) then
+ return
+ -- if the relic has been created at this point, then it was created on the *PREVIOUS* call of HOOK_LEVEL_END_GEN, and
+ -- therefore the player has caused another level generation in the temple and hence failed the quest.
+ elseif (god_quest.relic_generated == TRUE) and quest(GOD_QUEST).status ~= QUEST_STATUS_FAILED then
+
+ -- fail the quest, don't give another one, don't give this message again
+ quest(GOD_QUEST).status = QUEST_STATUS_FAILED
+ -- God issues instructions
+ cmsg_print(TERM_L_BLUE, "The voice of "..deity(player.pgod).name.." booms in your head:")
+
+ cmsg_print(TERM_YELLOW, "'Thou art a fool!")
+ cmsg_print(TERM_YELLOW, "I told thee to look carefully for the relic. It appears thou hast missed the")
+ cmsg_print(TERM_YELLOW, "opportunity to claim it in my name, as I sense that those monsters who ")
+ cmsg_print(TERM_YELLOW, "have overrun my temple have destroyed it themselves.")
+ cmsg_print(TERM_YELLOW, "I shall not ask thee to do such a thing again, as thou hast failed me in this")
+ cmsg_print(TERM_YELLOW, "simple task!'")
+ else
+ -- Force relic generation on 5th attempt if others have been unsuccessful.
+ if (god_quest.relic_gen_tries == 4) and (god_quest.relic_generated == FALSE) then
+ generate_relic()
+ else
+ -- 1/5 chance of generation
+ chance = randint(5)
+ if (chance == 5) then
+ generate_relic()
+ else
+ god_quest.relic_gen_tries = god_quest.relic_gen_tries + 1
+ end
+ end
+ end
+ end,
+ [HOOK_ENTER_DUNGEON] = function(d_idx)
+ -- call the function to set the dungeon variables (dependant on pgod) the first time we enter the dungeon
+ if d_idx ~= god_quest.DUNGEON_GOD then
+ return
+ else
+ set_god_dungeon_attributes()
+ end
+ end,
+ [HOOK_GEN_LEVEL_BEGIN] = function()
+ -- call the function to set the dungeon variables (dependant on pgod) when we WoR back into the dungeon
+ if current_dungeon_idx ~= god_quest.DUNGEON_GOD then
+ return
+ else
+ set_god_dungeon_attributes()
+ end
+ end,
+ [HOOK_STAIR] = function()
+ -- call the function to set the dungeon variables (dependant on pgod) every time we go down a level
+ if current_dungeon_idx ~= god_quest.DUNGEON_GOD then
+ return
+ else
+ set_god_dungeon_attributes()
+ end
+ end,
+ [HOOK_GET] = function(o_ptr, item)
+ -- Is it the relic, and check to make sure the relic hasn't already been identified
+ if (quest(GOD_QUEST).status == QUEST_STATUS_TAKEN) and (o_ptr.tval == TV_JUNK) and (o_ptr.sval == god_quest.relic_num)
+ and (o_ptr.pval ~= TRUE) and (god_quest.relics_found < god_quest.quests_given) then
+
+ -- more God talky-talky
+ cmsg_print(TERM_L_BLUE, deity(player.pgod).name.." speaks to you:")
+
+ -- Is it the last piece of the relic?
+ if (god_quest.quests_given == god_quest.MAX_NUM_GOD_QUESTS) then
+ cmsg_print(TERM_YELLOW, "'At last! Thou hast found all of the relic pieces.")
+
+ -- reward player by increasing prayer skill
+ cmsg_print(TERM_YELLOW, "Thou hast done exceptionally well! I shall increase thy prayer skill even more!'")
+ skill(SKILL_PRAY).value = skill(SKILL_PRAY).value + (10 * (skill(SKILL_PRAY).mod))
+
+ -- Take the relic piece
+ floor_item_increase(item, -1)
+ floor_item_optimize(item)
+ else
+ cmsg_print(TERM_YELLOW, "'Well done! Thou hast found part of the relic.")
+ cmsg_print(TERM_YELLOW, "I shall surely ask thee to find more of it later!")
+ cmsg_print(TERM_YELLOW, "I will take it from thee for now'")
+
+ -- Take the relic piece
+ floor_item_increase(item, -1)
+ floor_item_optimize(item)
+
+ -- reward player by increasing prayer skill
+ cmsg_print(TERM_YELLOW, "'As a reward, I shall teach thee how to pray better'")
+ skill(SKILL_PRAY).value = skill(SKILL_PRAY).value + (5 * (skill(SKILL_PRAY).mod))
+ end
+
+ -- relic piece has been identified
+ o_ptr.pval = TRUE
+ god_quest.relics_found = god_quest.relics_found + 1
+
+ -- Make sure quests can be given again if neccesary
+ quest(GOD_QUEST).status = QUEST_STATUS_UNTAKEN
+ return TRUE
+ end
+ end,
+ [HOOK_CHAR_DUMP] = function()
+
+ if (god_quest.quests_given > 0) then
+
+ local relics = god_quest.relics_found
+ local append_text = ""
+ if (god_quest.relics_found == god_quest.MAX_NUM_GOD_QUESTS) then
+ relics = "all"
+ append_text = " and pleased your god"
+ else
+ if (god_quest.relics_found == 0) then
+ relics = "none"
+ end
+ if (quest(GOD_QUEST).status == QUEST_STATUS_FAILED) then
+ append_text = " and failed in your quest"
+ end
+ end
+
+ print_hook("\n You found "..(relics).." of the relic pieces"..(append_text)..".")
+
+ end
+ end,
+ },
+}
+
+-- this function places the lost temple at a randomly determined place.
+function place_rand_dung()
+ local tries, grid
+
+ -- erase old dungeon
+ if (god_quest.quests_given > 0) then
+ place_dungeon(god_quest.dung_y, god_quest.dung_x)
+
+ -- erase old recall level
+ max_dlv[god_quest.DUNGEON_GOD + 1] = 0
+ end
+
+ -- initialise tries variable
+ tries = 1000
+
+ while tries > 0 do
+
+ tries = tries - 1
+ -- get grid coordinates, within a range which prevents dungeon being generated at the very edge of the wilderness (would crash the game).
+ god_quest.dung_x = rand_range(1, max_wild_x-2)
+ god_quest.dung_y = rand_range(1, max_wild_y-2)
+
+ -- Is there a town/dungeon/potentially impassable feature there, ?
+ if (wild_map(god_quest.dung_y, god_quest.dung_x).entrance ~= 0)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).entrance ~= 0)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_EDGE)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_DEEP_WATER)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_TREES)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_SHALLOW_LAVA)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_DEEP_LAVA)
+ or (wild_feat(wild_map(god_quest.dung_y, god_quest.dung_x)).terrain_idx == TERRAIN_MOUNTAIN) then
+ -- try again
+ else
+ --neither player, nor wall, then stop this 'while'
+ break
+ end
+ end
+
+ -- Uhuh BAD ! lets use the default location up bree
+ if tries == 0 then
+ god_quest.dung_x = 32
+ god_quest.dung_y = 19
+ end
+
+ -- create god dungeon in that place
+ place_dungeon(god_quest.dung_y, god_quest.dung_x, god_quest.DUNGEON_GOD)
+
+end
+
+-- this function generates the relic at a randomly determined place in the temple.
+function generate_relic()
+ local tries, grid, x, y, relic
+
+ -- initialise tries variable
+ tries = 1000
+
+ while (tries > 0) do
+
+ tries = tries - 1
+ -- get grid coordinates from current height/width, minus one to prevent relic being generated in outside wall. (would crash the game)
+ y = randint(cur_hgt-1)
+ x = randint(cur_wid-1)
+ grid = cave(y, x)
+
+ -- are the coordinates on a floor, not on a permanent feature (eg stairs), and not on a trap ?
+ if (cave_is(grid, FF1_FLOOR) == TRUE) and (cave_is(grid, FF1_PERMANENT) == FALSE) and (grid.t_idx == 0) then break end
+
+ end
+
+ -- create relic
+ relic = create_object(TV_JUNK, god_quest.relic_num)
+
+ -- inscribe it to prevent automatizer 'accidents'
+ relic.note = quark_add("quest")
+
+ -- If no safe co-ords were found, put it in the players backpack
+ if tries == 0 then
+
+ -- explain it
+ msg_print(TERM_L_BLUE, "You luckily stumble across the relic on the stairs!")
+
+ if (inven_carry_okay(relic)) then
+ inven_carry(relic, FALSE)
+ else
+ -- no place found, drop it on the stairs
+ drop_near(relic, -1, player.py, player.px)
+ end
+
+ else
+ -- drop it
+ drop_near(relic, -1, y, x)
+ end
+
+ -- Only generate once!
+ god_quest.relic_generated = TRUE
+
+ -- Reset some variables
+ god_quest.relic_gen_tries = 0
+
+end
+
+
+
+
+function set_god_dungeon_attributes()
+
+ -- dungeon properties altered according to which god player is worshipping,
+ if player.pgod == GOD_ERU then
+
+ -- The Eru temple is based on Meneltarma.
+ -- W: Not too many monsters (they'll be tough though, with big levels)
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 14
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 200
+
+ -- L: Dirt and grass. More dirt at bottom, more grass at top. rocky ground would be nice
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 88
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 89
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 70
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 30
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[2] = 10
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[2] = 90
+
+ -- A: Outer wall mountain chain. other walls granite
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 97
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 57
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 97
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 2
+
+ -- O: "At Meneltarma no weapon or tool had ever been borne" (but invaders would have left a small number)
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 45
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 5
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 45
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 5
+
+ -- F: A large pillar, with stairs created at edges. (You can't climb a rock through the middle, can you?)
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_BIG, DF1_NO_DOORS, DF1_CIRCULAR_ROOMS, DF1_EMPTY, DF1_TOWER, DF1_FLAT, DF1_ADJUST_LEVEL_2)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = bor(DF2_ADJUST_LEVEL_1_2, DF2_NO_SHAFT, DF2_ADJUST_LEVEL_PLAYER)
+
+ -- R:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 50
+
+ -- M: We want evil or flying characters
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags3 = RF3_EVIL
+
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[2].percent = 50
+
+ -- M: We want evil or flying characters
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mflags7 = RF7_CAN_FLY
+
+
+ elseif player.pgod == GOD_MANWE then
+
+ -- Manwe's lost temple is high in the clouds
+ -- W: Has average number of monsters.
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 18
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 160
+
+
+ -- L: floor will be 'cloud-like vapour' and pools of 'condensing water'
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 208
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 209
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 85
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 15
+
+ -- A: Outer wall is 'hail stone wall', inner wall 'dense fog'. FIlled at max smoothing, like islands.
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 211
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 210
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 211
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 4
+
+ -- O: Can't imagine Manwe having much treasure. Little need for tools in a cloud temple. lots of magical stuff though...
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 15
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 25
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 55
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 5
+
+ -- F: It's open, goes up like a tower, give it a few interesting rooms, make the monsters hard(ish).
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_NO_DOORS, DF1_TOWER, DF1_CAVERN, DF1_ADJUST_LEVEL_2)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = bor(DF2_NO_SHAFT, DF2_ADJUST_LEVEL_PLAYER)
+
+ -- R:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[2].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[3].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[3].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[4].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[4].percent = 20
+ dungeon(god_quest.DUNGEON_GOD).rules[5].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[5].percent = 20
+
+ -- M: We want air(poison-type) or flying characters. Orcs too. They would have ransacked his elf-loving temple :)
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags2 = RF2_INVISIBLE
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mflags3 = bor(RF3_ORC, RF3_IM_POIS)
+ dungeon(god_quest.DUNGEON_GOD).rules[3].mflags4 = bor(RF4_BR_POIS, RF4_BR_GRAV)
+ dungeon(god_quest.DUNGEON_GOD).rules[4].mflags5 = RF5_BA_POIS
+ dungeon(god_quest.DUNGEON_GOD).rules[5].mflags7 = RF7_CAN_FLY
+
+
+ elseif player.pgod == GOD_TULKAS then
+
+ -- Tulkas dungeon is quite normal, possibly a bit boring to be honest. Maybe I should add something radical to it.
+ -- 'The house of Tulkas in the midmost of Valmar was a house of mirth and revelry. It sprang into the air with many storeys,
+ -- and had a tower of bronze and pillars of copper in a wide arcade'
+ -- W: but with lots of monsters
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 20
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 120
+
+ -- L: floor is normal
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 1
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 100
+
+ -- A: Granite walls
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 56
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 58
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 57
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 0
+
+ -- O: Loads of combat drops
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 10
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 70
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 5
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 15
+
+ -- F: fairly standard
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_NO_DESTROY, DF1_ADJUST_LEVEL_2)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = DF2_ADJUST_LEVEL_PLAYER
+
+ -- R:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 100
+
+ -- M: plenty demons please
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags3 = bor(RF3_DEMON, RF3_EVIL)
+
+
+ elseif player.pgod == GOD_MELKOR then
+
+ -- Melkors dungeon will be dark, fiery and stuff
+ -- Many many monsters! (but prob ADJUST_LEVEL_1_2)
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 24
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 80
+
+
+ -- L: floor is dirt/mud/nether
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 88
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 94
+ dungeon(god_quest.DUNGEON_GOD).floor3 = 102
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 45
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 45
+ dungeon(god_quest.DUNGEON_GOD).floor_percent3[1] = 10
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[2] = 35
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[2] = 35
+ dungeon(god_quest.DUNGEON_GOD).floor_percent3[2] = 30
+
+ -- A: Granite walls to fill but glass walls for room perimeters (you can see the nasty monsters coming)
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 188
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 188
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 57
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 1
+
+ -- O: Even drops
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 25
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 25
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 25
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 25
+
+ -- F: Small, lava rivers, nasty monsters hehehehehe
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_SMALL, DF1_LAVA_RIVERS, DF1_ADJUST_LEVEL_1)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = bor(DF2_ADJUST_LEVEL_1_2, DF2_ADJUST_LEVEL_PLAYER)
+
+ -- R: No restrictions on monsters here
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 0
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 80
+
+ -- R: Apart from making sure we have some GOOD ones
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[2].percent = 20
+
+ -- M:
+ dungeon(god_quest.DUNGEON_GOD).rules[2].mflags3 = RF3_GOOD
+
+ elseif player.pgod == GOD_YAVANNA then
+
+ -- Yavannas dungeon will be very natural, tress and stuff.
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_level = 22
+ dungeon(god_quest.DUNGEON_GOD).min_m_alloc_chance = 100
+
+ -- L: floor is grass/flowers, plus dirt so not always regenerating quick!
+ dungeon(god_quest.DUNGEON_GOD).floor1 = 89
+ dungeon(god_quest.DUNGEON_GOD).floor2 = 199
+ dungeon(god_quest.DUNGEON_GOD).floor3 = 88
+ dungeon(god_quest.DUNGEON_GOD).floor_percent1[1] = 40
+ dungeon(god_quest.DUNGEON_GOD).floor_percent2[1] = 15
+ dungeon(god_quest.DUNGEON_GOD).floor_percent3[1] = 45
+
+ -- A: Tree walls to fill, small trees for inner walls
+ dungeon(god_quest.DUNGEON_GOD).fill_type1 = 96
+ dungeon(god_quest.DUNGEON_GOD).fill_percent1[1] = 100
+ dungeon(god_quest.DUNGEON_GOD).outer_wall = 202
+ dungeon(god_quest.DUNGEON_GOD).inner_wall = 96
+ dungeon(god_quest.DUNGEON_GOD).fill_method = 1
+
+ -- O: nt much combat.. tools where ransackers have tried to chop trees down.
+ dungeon(god_quest.DUNGEON_GOD).objs.treasure = 20
+ dungeon(god_quest.DUNGEON_GOD).objs.combat = 10
+ dungeon(god_quest.DUNGEON_GOD).objs.magic = 30
+ dungeon(god_quest.DUNGEON_GOD).objs.tools = 40
+
+ -- F: Natural looking
+ dungeon(god_quest.DUNGEON_GOD).flags1 = bor(DF1_NO_DOORS, DF1_WATER_RIVERS, DF1_NO_DESTROY, DF1_ADJUST_LEVEL_1, DF1_NO_RECALL)
+ dungeon(god_quest.DUNGEON_GOD).flags2 = bor(DF2_ADJUST_LEVEL_1_2, DF2_NO_SHAFT, DF2_NO_GENO, DF2_ADJUST_LEVEL_PLAYER)
+
+ -- R: Demons, Undead, non-living
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mode = 3
+ dungeon(god_quest.DUNGEON_GOD).rules[1].percent = 100
+
+ -- M:
+ dungeon(god_quest.DUNGEON_GOD).rules[1].mflags3 = bor(RF3_DEMON, RF3_UNDEAD, RF3_NONLIVING)
+
+ end
+
+ -- W: All dungeons are 5 levels deep, and created at 2/3 of the player clvl when the quest is given
+ dungeon(god_quest.DUNGEON_GOD).mindepth = god_quest.dun_mindepth
+ dungeon(god_quest.DUNGEON_GOD).maxdepth = god_quest.dun_maxdepth
+ dungeon(god_quest.DUNGEON_GOD).minplev = god_quest.dun_minplev
+
+end
+
+-- Calling this function returns the direction the dungeon is in from the players position at the time
+-- the quest was given, and also the direction from angband (if the player is worshipping Melkor) or lothlorien.
+function get_god_quest_axes()
+ local home, home_y_coord, home_x_coord, home_axis, home2, home2_y_coord, home2_x_coord, home2_axis, mydistance
+
+ -- different values for different gods...
+ if player.pgod ~= GOD_MELKOR then
+
+ -- one of the valar, "home" is lothlorien, home2 is Minas Arnor
+ home = "Bree"
+ home_y_coord = 21
+ home_x_coord = 34
+ home2 = "Minas Anor"
+ home2_y_coord = 56
+ home2_x_coord = 60
+ else
+ -- Melkor, "home" is angband, home2 is Barad-dur
+ home = "the Pits of Angband"
+ home_y_coord = 7
+ home_x_coord = 34
+ home2 = "the Land of Mordor"
+ home2_y_coord = 58
+ home2_x_coord = 65
+ end
+
+ home_axis = compass(home_y_coord, home_x_coord, god_quest.dung_y, god_quest.dung_x)
+ home2_axis = compass(home2_y_coord, home2_x_coord, god_quest.dung_y, god_quest.dung_x)
+
+ home_distance = approximate_distance(home_y_coord, home_x_coord, god_quest.dung_y, god_quest.dung_x)
+ home2_distance = approximate_distance(home2_y_coord, home2_x_coord, god_quest.dung_y, god_quest.dung_x)
+
+ return home, home_axis, home_distance, home2, home2_axis, home2_distance
+end
diff --git a/lib/scpt/gods.lua b/lib/scpt/gods.lua
new file mode 100644
index 00000000..014a4423
--- /dev/null
+++ b/lib/scpt/gods.lua
@@ -0,0 +1,26 @@
+add_hooks
+{
+ [HOOK_FOLLOW_GOD] = function(god, action)
+ if action == "ask" then
+ if not (god == GOD_MELKOR) then
+ local i = INVEN_WIELD
+ while i < INVEN_TOTAL do
+ -- 13 is ART_POWER
+ if player.inventory(i).name1 == 13 then
+ msg_print("The One Ring has corrupted you, and you are rejected.")
+ return TRUE
+ end
+ i = i + 1
+ end
+ end
+ end
+ return FALSE
+ end,
+ [HOOK_RECALC_SKILLS] = function()
+ if not (player.pgod == GOD_NONE) and (get_skill(SKILL_ANTIMAGIC) > 0) then
+ msg_print("You no longer believe.")
+ abandon_god(GOD_ALL)
+ end
+ return FALSE
+ end,
+}
diff --git a/lib/scpt/help.lua b/lib/scpt/help.lua
new file mode 100644
index 00000000..5350fec8
--- /dev/null
+++ b/lib/scpt/help.lua
@@ -0,0 +1,411 @@
+-- Ingame contextual help
+
+-------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+-----------------------Here comes the definition of help-----------------------
+-------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if cave(y, x).feat == FEAT_BETWEEN then return TRUE end end,
+ ["desc"] =
+ {
+ "Void Jumpgates can be entered by pressing the > key. They will transport",
+ "you to another jumpgate, but beware of the cold damage that might kill you.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if cave(y, x).feat == FEAT_FOUNTAIN then return TRUE end end,
+ ["desc"] =
+ {
+ "Fountains are always magical. You can quaff from them by pressing H.",
+ "Beware that unlike potions they cannot be identified.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if cave(y, x).o_idx ~= 0 then return TRUE end end,
+ ["desc"] =
+ {
+ "So you found your first item! Nice, eh? Now when you stumble across",
+ "objects, you can pick them up by pressing g, and if you are wondering",
+ "what they do, press I (then *, then the letter for the item) to get",
+ "some basic information. You may also want to identify them with scrolls,",
+ "staves, rods or spells.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if (cave(y, x).feat >= FEAT_ALTAR_HEAD) and (cave(y, x).feat <= FEAT_ALTAR_TAIL) then return TRUE end end,
+ ["desc"] =
+ {
+ "Altars are the way to reach the Valar, powers of the world,",
+ "usualy called Gods. You can press O to become a follower.",
+ "Beware that once you follow a god, you are not allowed to change.",
+ "For an exact description of what gods do and want, read the documentation."
+ }
+}
+
+-- Beware this one, if Bree is moved from 21, 34 (y, x) on the wilderness map it will break
+ingame_help
+{
+ ["hook"] = HOOK_END_TURN,
+ ["event"] = function(y, x)
+ if ((player.wilderness_x ~= 34) or (player.wilderness_y ~= 21) and (player.astral == FALSE)) then return TRUE end
+ end,
+ ["desc"] =
+ {
+ "Ahh wilderness travel... The overview mode will allow you to travel",
+ "fast, but that comes to the cost of GREATLY increased food consumption.",
+ "So you should bring lots of food and really watch your hunger status.",
+ "To enter the overview mode, press < while in the wilderness.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_PLAYER_LEVEL,
+ ["event"] = function(y, x) if player.lev > 1 then return TRUE end end,
+ ["desc"] =
+ {
+ "Ok, so you now gained a level, and you have skill points to spend.",
+ "To do so simply press G to learn skills. Reading the documentation",
+ "about skills and abilities is also strongly recommended.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_MOVE,
+ ["event"] = function(y, x) if cave(y, x).feat == FEAT_MORE then return TRUE end end,
+ ["desc"] =
+ {
+ "Ah, this is a stair, or a way into something. Press > to enter it.",
+ "But be ready to fight what lies within, for it might not be too friendly.",
+ }
+}
+
+ingame_help
+{
+ ["callback"] = "monster_chat",
+ ["desc"] =
+ {
+ "Somebody is speaking to you it seems. You can talk back with the Y key.",
+ "This can lead to quests. You can also give items to 'monsters' with the y key.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_END_TURN,
+ ["event"] = function(y, x) return TRUE end,
+ ["desc"] =
+ {
+ "Welcome to ToME! I am the spirit of knowledge and my task is to help you",
+ "to get used to how to play. I have prepared a #vparchment#y for you to #vread#y.",
+ "Press r, then space then select it. You can also check the documentation",
+ "by pressing ? at (nearly) any time.",
+ "The first place you can explore is Barrow-downs. Go to the west of town",
+ "and you should see a #v>#y there.",
+ "If you miss any of this you can press ctrl+p to see your message log.",
+ "Now I must reveal your task here. You are on a quest to investigate",
+ "the dreadful tower of Dol Guldur in the Mirkwood forest to see what evil",
+ "lurks there, but beware, you are not yet ready.",
+ "If you do not want me to bother you any more with tips, press = then go",
+ "into the ToME options and deactivate the ingame_help option.",
+ "You can see your quest log by pressing ctrl+q. Now go to your destiny!",
+ }
+}
+
+ingame_help
+{
+ ["no_test"] = TRUE,
+ ["callback"] = "select_context",
+ ["fct"] = function(typ, name)
+ -- list of files for classes, { filename, anchor }
+ local t =
+ {
+ ["race"] =
+ {
+ ["Beorning"] = { "r_beorn.txt", 0 },
+ ["DeathMold"] = { "r_deathm.txt", 0 },
+ ["Dark-Elf"] = { "r_drkelf.txt", 0 },
+ ["Dunadan"] = { "r_dunad.txt", 0 },
+ ["Dwarf"] = { "r_dwarf.txt", 0 },
+ ["Elf"] = { "r_elf.txt", 0 },
+ ["Ent"] = { "r_ent.txt", 0 },
+ ["Gnome"] = { "r_gnome.txt", 0 },
+ ["Half-Elf"] = { "r_hafelf.txt", 0 },
+ ["Half-Ogre"] = { "r_hafogr.txt", 0 },
+ ["High-Elf"] = { "r_hielf.txt", 0 },
+ ["Hobbit"] = { "r_hobbit.txt", 0 },
+ ["Human"] = { "r_human.txt", 0 },
+ ["Kobold"] = { "r_kobold.txt", 0 },
+ ["Maia"] = { "r_maia.txt", 0 },
+ ["Orc"] = { "r_orc.txt", 0 },
+ ["Petty-Dwarf"] = { "r_pettyd.txt", 0 },
+ ["RohanKnight"] = { "r_rohank.txt", 0 },
+ ["Thunderlord"] = { "r_thlord.txt", 0 },
+ ["Troll"] = { "r_troll.txt", 0 },
+ ["Wood-Elf"] = { "r_wodelf.txt", 0 },
+ ["Yeek"] = { "r_yeek.txt", 0 },
+ },
+ ["subrace"] =
+ {
+ ["Barbarian"] = { "rm_barb.txt", 0 },
+ ["Classical"] = { "rm_class.txt", 0 },
+ ["Corrupted"] = { "rm_corru.txt", 0 },
+ ["Hermit"] = { "rm_herm.txt", 0 },
+ ["LostSoul"] = { "rm_lsoul.txt", 0 },
+ ["Skeleton"] = { "rm_skel.txt", 0 },
+ ["Spectre"] = { "rm_spec.txt", 0 },
+ ["Vampire"] = { "rm_vamp.txt", 0 },
+ ["Zombie"] = { "rm_zomb.txt", 0 },
+ },
+ ["class"] =
+ {
+ ["Alchemist"] = { "c_alchem.txt", 0 },
+ ["Archer"] = { "c_archer.txt", 0 },
+ ["Assassin"] = { "c_assass.txt", 0 },
+ ["Axemaster"] = { "c_axemas.txt", 0 },
+ ["Bard"] = { "c_bard.txt", 0 },
+ ["Dark-Priest"] = { "c_pr_drk.txt", 0 },
+ ["Demonologist"] = { "c_demono.txt", 0 },
+ ["Druid"] = { "c_druid.txt", 0 },
+ ["Geomancer"] = { "c_geoman.txt", 0 },
+ ["Haftedmaster"] = { "c_hafted.txt", 0 },
+ ["Loremaster"] = { "c_lorema.txt", 0 },
+ ["Mage"] = { "c_mage.txt", 0 },
+ ["Mimic"] = { "c_mimic.txt", 0 },
+ ["Mindcrafter"] = { "c_mindcr.txt", 0 },
+ ["Monk"] = { "c_monk.txt", 0 },
+ ["Necromancer"] = { "c_necro.txt", 0 },
+ ["Paladin"] = { "c_palad.txt", 0 },
+ ["Polearmmaster"] = { "c_polear.txt", 0 },
+ ["Possessor"] = { "c_posses.txt", 0 },
+ ["Priest"] = { "c_priest.txt", 0 },
+ ["Priest(Eru)"] = { "c_pr_eru.txt", 0 },
+ ["Priest(Manwe)"] = { "c_pr_man.txt", 0 },
+ ["Ranger"] = { "c_ranger.txt", 0 },
+ ["Rogue"] = { "c_rogue.txt", 0 },
+ ["Runecrafter"] = { "c_runecr.txt", 0 },
+ ["Sorceror"] = { "c_sorcer.txt", 0 },
+ ["Summoner"] = { "c_summon.txt", 0 },
+ ["Swordmaster"] = { "c_swordm.txt", 0 },
+ ["Symbiant"] = { "c_symbia.txt", 0 },
+ ["Thaumaturgist"] = { "c_thaum.txt", 0 },
+ ["Unbeliever"] = { "c_unbel.txt", 0 },
+ ["Warper"] = { "c_warper.txt", 0 },
+ ["Warrior"] = { "c_warrio.txt", 0 },
+ },
+ ["god"] =
+ {
+ ["Eru Iluvatar"] = { "g_eru.txt", 0 },
+ ["Manwe Sulimo"] = { "g_manwe.txt", 0 },
+ ["Tulkas"] = { "g_tulkas.txt", 0 },
+ ["Melkor Bauglir"] = { "g_melkor.txt", 0 },
+ ["Yavanna Kementari"] = { "g_yavann.txt", 0 },
+ },
+ ["skill"] =
+ {
+ ["Air"] = { "skills.txt", 27 },
+ ["Alchemy"] = { "skills.txt", 49 },
+ ["Antimagic"] = { "skills.txt", 50 },
+ ["Archery"] = { "skills.txt", 08 },
+ ["Axe-mastery"] = { "skills.txt", 05 },
+ ["Backstab"] = { "skills.txt", 18 },
+ ["Barehand-combat"] = { "skills.txt", 13 },
+ ["Boomerang-mastery"] = { "skills.txt", 12 },
+ ["Boulder-throwing"] = { "skills.txt", 58 },
+ ["Bow-mastery"] = { "skills.txt", 10 },
+ ["Combat"] = { "skills.txt", 01 },
+ ["Conveyance"] = { "skills.txt", 30 },
+ ["Corpse-preservation"] = { "skills.txt", 44 },
+ ["Critical-hits"] = { "skills.txt", 04 },
+ ["Crossbow-mastery"] = { "skills.txt", 11 },
+ ["Demonology"] = { "skills.txt", 52 },
+ ["Disarming"] = { "skills.txt", 16 },
+ ["Divination"] = { "skills.txt", 31 },
+ ["Dodging"] = { "skills.txt", 20 },
+ ["Druidistic"] = { "skills.txt", 40 },
+ ["Earth"] = { "skills.txt", 28 },
+ ["Fire"] = { "skills.txt", 25 },
+ ["Geomancy"] = { "skills.txt", 60 },
+ ["Hafted-mastery"] = { "skills.txt", 06 },
+ ["Magic"] = { "skills.txt", 21 },
+ ["Magic-Device"] = { "skills.txt", 54 },
+ ["Mana"] = { "skills.txt", 24 },
+ ["Meta"] = { "skills.txt", 29 },
+ ["Mimicry"] = { "skills.txt", 47 },
+ ["Mind"] = { "skills.txt", 33 },
+ ["Mindcraft"] = { "skills.txt", 41 },
+ ["Monster-lore"] = { "skills.txt", 42 },
+ ["Music"] = { "skills.txt", 59 },
+ ["Nature"] = { "skills.txt", 34 },
+ ["Necromancy"] = { "skills.txt", 35 },
+ ["Polearm-mastery"] = { "skills.txt", 07 },
+ ["Possession"] = { "skills.txt", 45 },
+ ["Prayer"] = { "skills.txt", 39 },
+ ["Runecraft"] = { "skills.txt", 36 },
+ ["Sling-mastery"] = { "skills.txt", 09 },
+ ["Sneakiness"] = { "skills.txt", 14 },
+ ["Spell-power"] = { "skills.txt", 22 },
+ ["Spirituality"] = { "skills.txt", 38 },
+ ["Sorcery"] = { "skills.txt", 23 },
+ ["Stealing"] = { "skills.txt", 19 },
+ ["Stealth"] = { "skills.txt", 15 },
+ ["Stunning-blows"] = { "skills.txt", 53 },
+ ["Summoning"] = { "skills.txt", 43 },
+ ["Sword-mastery"] = { "skills.txt", 03 },
+ ["Symbiosis"] = { "skills.txt", 46 },
+ ["Temporal"] = { "skills.txt", 32 },
+ ["Thaumaturgy"] = { "skills.txt", 37 },
+ ["Udun"] = { "skills.txt", 48 },
+ ["Weaponmastery"] = { "skills.txt", 02 },
+ ["Water"] = { "skills.txt", 26 },
+ },
+ ["ability"] =
+ {
+ ["Spread blows"] = { "ability.txt", 02 },
+ ["Tree walking"] = { "ability.txt", 03 },
+ ["Perfect casting"] = { "ability.txt", 04 },
+ ["Extra Max Blow(1)"] = { "ability.txt", 05 },
+ ["Extra Max Blow(2)"] = { "ability.txt", 06 },
+ ["Ammo creation"] = { "ability.txt", 07 },
+ ["Touch of death"] = { "ability.txt", 08 },
+ ["Artifact Creation"] = { "ability.txt", 09 },
+ ["Far reaching attack"] = { "ability.txt", 10 },
+ ["Trapping"] = { "ability.txt", 11 },
+ ["Undead Form"] = { "ability.txt", 12 },
+ },
+ }
+
+ if t[typ][name] then ingame_help_doc(t[typ][name][1], t[typ][name][2])
+ else ingame_help_doc("help.hlp", 0)
+ end
+ end,
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_IDENTIFY,
+ ["event"] = function(i, mode)
+ if mode == "full" then
+ local obj = get_object(i)
+ local f1, f2, f3, f4, f5, esp = object_flags(obj)
+ if band(f5, TR5_SPELL_CONTAIN) ~= 0 then return TRUE end
+ end
+ end,
+ ["desc"] =
+ {
+ "Ah, an item that can contain a spell. To use it you must have some levels of",
+ "Magic skill and then you get the option to copy a spell when pressing m.",
+ "Then just select which spell to copy and to which object. Note that doing so",
+ "is permanent; the spell cannot be removed or changed later.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_BATERIE then return TRUE end end,
+ ["desc"] =
+ {
+ "Ah, an essence! Those magical containers stores energies. They are used",
+ "with the Alchemy skill to create or modify the powers of items.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_RUNE1 or obj.tval == TV_RUNE2 then return TRUE end end,
+ ["desc"] =
+ {
+ "Ah, a rune! Runes are used with the Runecraft skill to allow you to",
+ "create spells on your own.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_ROD_MAIN then return TRUE end end,
+ ["desc"] =
+ {
+ "This is a rod. You will need to attach a rod tip to it before you",
+ "can use it. This main part of the rod may give the rod bonuses",
+ "like quicker charging time, or a larger capacity for charges.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_ROD then return TRUE end end,
+ ["desc"] =
+ {
+ "You've found a rod-tip! You will need to attach it to a rod base",
+ "before you can use it. Once it has been attatched (use the 'z' key)",
+ "you cannot unattach it! The rod tip will determine the effect of",
+ "the rod. To use your rod, 'z'ap it once it has been assembled.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_TRAPKIT then return TRUE end end,
+ ["desc"] =
+ {
+ "Ooooh, a trapping kit. If you have ability in the trapping skill,",
+ "you can lay this trap (via the 'm' key) to harm unsuspecting foes.",
+ "You'll generally need either some ammo or magic device depending",
+ "on the exact type of trap kit.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_RECALC_SKILLS,
+ ["event"] = function() if game.started and (get_melee_skills() > 1) then return TRUE end end,
+ ["desc"] =
+ {
+ "Ah, you now possess more than one melee type. To switch between them press m",
+ "and select the switch melee type option.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_GET,
+ ["event"] = function(obj, idx) if obj.tval == TV_WAND or obj.tval == TV_STAFF then return TRUE end end,
+ ["desc"] =
+ {
+ "You've found a magical device, either a staff or a wand. Each staff",
+ "contains a spell, often from one of the primary magic schools. There",
+ "is a lot of information you can find about this object if you identify",
+ "it and 'I'nspect it. Check the help file on Magic for more about these.",
+ }
+}
+
+ingame_help
+{
+ ["hook"] = HOOK_PLAYER_LEVEL,
+ ["event"] = function(y, x) if player.lev >= 20 then return TRUE end end,
+ ["desc"] =
+ {
+ "I see you are now at least level 20. Nice! If you want to gloat about your",
+ "character you could press 'C' then 'f' to make a character dump and post it to",
+ "http://angband.oook.cz/ where it will end up in the ladder.",
+ }
+}
diff --git a/lib/scpt/init.lua b/lib/scpt/init.lua
new file mode 100644
index 00000000..a6f3f8ab
--- /dev/null
+++ b/lib/scpt/init.lua
@@ -0,0 +1,46 @@
+--
+-- This file is loaded at the initialisation of ToME
+--
+
+-- Load the class specific stuff
+tome_dofile("player.lua")
+
+-- Load the ingame contextual help
+tome_dofile("help.lua")
+
+-- let the store specific stuff happen!
+tome_dofile("stores.lua")
+
+-- Add various 'U' powers
+tome_dofile("powers.lua")
+
+-- Add the mimic shapes
+tome_dofile("mimic.lua")
+
+-- Add the corruptions
+tome_dofile("corrupt.lua")
+
+-- Add the mkey activations
+tome_dofile("mkeys.lua")
+
+-- Add the schools of magic
+tome_dofile("spells.lua")
+
+-- Add god stuff
+tome_dofile("gods.lua")
+
+-- Add some quests
+tome_dofile("bounty.lua")
+tome_dofile("god.lua")
+tome_dofile("fireprof.lua")
+tome_dofile("library.lua")
+
+-- Add joke stuff
+tome_dofile("drunk.lua")
+tome_dofile("joke.lua")
+
+-- Some tests, if the file is not present, this is fine
+tome_dofile_anywhere(ANGBAND_DIR_SCPT, "dg_test.lua", FALSE)
+
+-- A nice custom intro :)
+tome_dofile("intro.lua")
diff --git a/lib/scpt/intro.lua b/lib/scpt/intro.lua
new file mode 100644
index 00000000..ef6041a5
--- /dev/null
+++ b/lib/scpt/intro.lua
@@ -0,0 +1,39 @@
+function tome_intro()
+ screen_save()
+ Term_clear()
+
+ if (TRUE == drop_text_left(TERM_L_BLUE, "Art thou an adventurer,", 10, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_BLUE, "One who passes through the waterfalls we call danger", 11, -1)) then screen_load() return end
+ if (TRUE == drop_text_left(TERM_L_BLUE, "to find the true nature of the legends beyond them?", 12, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_BLUE, "If this is so, then seeketh me.", 13, -1)) then screen_load() return end
+
+ if (TRUE == drop_text_left(TERM_WHITE, "[Press any key to continue]", 23, -1)) then screen_load() return end
+
+ Term_putch(0, 0, TERM_DARK, 32)
+ inkey_scan = FALSE
+ inkey()
+
+ Term_clear()
+
+ if (TRUE == drop_text_left(TERM_L_BLUE, "DarkGod", 8, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_WHITE, "in collaboration with", 9, -1)) then screen_load() return end
+ if (TRUE == drop_text_left(TERM_L_GREEN, "Eru Iluvatar,", 10, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_GREEN, "Manwe", 11, -1)) then screen_load() return end
+ if (TRUE == drop_text_left(TERM_WHITE, "and", 12, 0)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_L_GREEN, "All the T.o.M.E. contributors(see credits.txt)", 13, -1)) then screen_load() return end
+
+ if (TRUE == drop_text_left(TERM_WHITE, "present", 15, 1)) then screen_load() return end
+ if (TRUE == drop_text_right(TERM_YELLOW, "T.o.M.E.", 16, 0)) then screen_load() return end
+
+ if (TRUE == drop_text_left(TERM_WHITE, "[Press any key to continue]", 23, -1)) then screen_load() return end
+ Term_putch(0, 0, TERM_DARK, 32)
+
+ inkey_scan = FALSE
+
+ inkey()
+
+ screen_load()
+ return
+end
+
+add_hook_script(HOOK_INIT, "tome_intro", "lua_intro_init")
diff --git a/lib/scpt/joke.lua b/lib/scpt/joke.lua
new file mode 100644
index 00000000..2d87b651
--- /dev/null
+++ b/lib/scpt/joke.lua
@@ -0,0 +1,31 @@
+-- Place a monster in a good spot
+function gen_joke_place_monster(r_idx)
+ local try = 1000
+ local x
+ local y
+ while try > 0 do
+ x = randint(cur_hgt - 4) + 2
+ y = randint(cur_wid - 4) + 2
+ if not (0 == place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_ENEMY)) then
+ return
+ end
+ try = try - 1
+ end
+end
+
+-- Check if a special joke monster can be generated here
+function gen_joke_monsters()
+ if joke_monsters == FALSE then
+ return
+ end
+
+ -- Neil
+ if (current_dungeon_idx == 20) and (dun_level == 72) then
+ neil = test_monster_name("Neil, the Sorceror")
+ m_allow_special[neil + 1] = TRUE
+ gen_joke_place_monster(neil)
+ m_allow_special[neil + 1] = FALSE
+ end
+end
+
+add_hook_script(HOOK_LEVEL_END_GEN, "gen_joke_monsters", "gen_joke_monsters")
diff --git a/lib/scpt/library.lua b/lib/scpt/library.lua
new file mode 100644
index 00000000..1433e47f
--- /dev/null
+++ b/lib/scpt/library.lua
@@ -0,0 +1,436 @@
+-- Library quest in Minas Anor
+
+-- Partially based on Fireproofing quest
+
+library_quest = {}
+
+-- Map helper
+library_quest.place_random = function(minY, minX, maxY, maxX, monster)
+ y = randint(maxY - minY + 1) + minY
+ x = randint(maxX - minX + 1) + minX
+ return place_monster_one(y, x, monster, 0, TRUE, MSTATUS_ENEMY)
+end
+
+-- Book creation helpers
+library_quest.bookable_spells =
+{
+ MANATHRUST, DELCURSES,
+ GLOBELIGHT, FIREGOLEM, FIREFLASH, FIREWALL,
+ GEYSER, VAPOR, ENTPOTION,
+ NOXIOUSCLOUD, POISONBLOOD,
+ STONESKIN, DIG,
+ RECHARGE, DISPERSEMAGIC,
+ BLINK, DISARM, TELEPORT,
+ SENSEMONSTERS, SENSEHIDDEN, REVEALWAYS, IDENTIFY, VISION,
+ MAGELOCK, SLOWMONSTER, ESSENCESPEED,
+ CHARM, CONFUSE, ARMOROFFEAR, STUN,
+ GROWTREE, HEALING, RECOVERY,
+ ERU_SEE, ERU_LISTEN,
+ MANWE_BLESS, MANWE_SHIELD,
+ YAVANNA_CHARM_ANIMAL, YAVANNA_GROW_GRASS, YAVANNA_TREE_ROOTS,
+ TULKAS_AIM, TULKAS_SPIN,
+ MELKOR_CURSE, MELKOR_CORPSE_EXPLOSION,
+ DRAIN
+}
+
+library_quest.get_term_size = function()
+ local width = 0
+ local height = 0
+ ret, width, height = Term_get_size(width, height)
+ return width, height
+end
+
+library_quest.book_slots_left = function()
+ if school_book[61][1] == -1 then
+ return 3
+ elseif school_book[61][2] == -1 then
+ return 2
+ elseif school_book[61][3] == -1 then
+ return 1
+ else
+ return 0
+ end
+end
+
+library_quest.book_contains_spell = function(spell)
+ if school_book[61][1] == spell then
+ return TRUE
+ elseif school_book[61][2] == spell then
+ return TRUE
+ elseif school_book[61][3] == spell then
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+library_quest.add_spell = function(spell)
+ if school_book[61][1] == -1 then
+ school_book[61][1] = spell
+ return TRUE
+ elseif school_book[61][2] == -1 then
+ school_book[61][2] = spell
+ return TRUE
+ elseif school_book[61][3] == -1 then
+ school_book[61][3] = spell
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+library_quest.remove_spell = function(spell)
+ if school_book[61][1] == spell then
+ school_book[61][1] = school_book[61][2]
+ school_book[61][2] = school_book[61][3]
+ school_book[61][3] = -1
+ return TRUE
+ elseif school_book[61][2] == spell then
+ school_book[61][2] = school_book[61][3]
+ school_book[61][3] = -1
+ return TRUE
+ elseif school_book[61][3] == spell then
+ school_book[61][3] = -1
+ return TRUE
+ else
+ return FALSE
+ end
+end
+
+-- Print a spell (taken from s_aux)
+function library_quest.print_spell(color, y, spl)
+ local x, index, sch, size, s
+
+ x = 0
+ size = 0
+ book = 255
+ obj = nil
+
+ -- Hack if the book is 255 it is a random book
+ if book == 255 then
+ school_book[book] = {spl}
+ end
+
+ -- Parse all spells
+ for index, s in school_book[book] do
+ local lvl, na = get_level_school(s, 50, -50)
+ local xx, sch_str
+
+ sch_str = spell_school_name(s)
+
+ if s == spl then
+ if na then
+ c_prt(color, format("%-20s%-16s %3s %4s %3d%s %s", spell(s).name, sch_str, na, get_mana(s), spell_chance(s), "%", __spell_info[s]()), y, x)
+ else
+ c_prt(color, format("%-20s%-16s %3d %4s %3d%s %s", spell(s).name, sch_str, lvl, get_mana(s), spell_chance(s), "%", __spell_info[s]()), y, x)
+ end
+ y = y + 1
+ size = size + 1
+ end
+ end
+ return y
+end
+
+-- spell selection routines inspired by skills.c
+library_quest.print_spells = function(first, current)
+ Term_clear()
+ width, height = library_quest.get_term_size()
+ slots = library_quest.book_slots_left()
+
+ c_prt(TERM_WHITE, "Book Creation Screen", 0, 0);
+ c_prt(TERM_WHITE, "Up/Down to move, Right/Left to modify, I to describe, Esc to Save/Cancel", 1, 0);
+
+ if slots == 0 then
+ c_prt(TERM_L_RED, "The book can hold no more spells.", 2, 0);
+ elseif slots == 1 then
+ c_prt(TERM_L_BLUE, "The book can hold 1 more spell.", 2, 0);
+ else
+ c_prt(TERM_L_BLUE, "The book can hold "..slots.." more spells.", 2, 0);
+ end
+
+ row = 3;
+ for index, spell in library_quest.bookable_spells do
+ if index >= first then
+ if index == current then
+ color = TERM_GREEN
+ elseif library_quest.book_contains_spell(spell) == TRUE then
+ color = TERM_WHITE
+ else
+ color = TERM_ORANGE
+ end
+ library_quest.print_spell(color, row, spell)
+
+ if row == height - 1 then
+ return
+ end
+ row = row + 1
+ end
+ end
+end
+
+library_quest.fill_book = function()
+ -- Always start with a cleared book
+ school_book[61] = {-1, -1, -1}
+
+ screen_save()
+ width, height = library_quest.get_term_size()
+ -- room for legend
+ margin = 3
+
+ first = 1
+ current = 1
+ done = FALSE
+
+ while done == FALSE do
+ library_quest.print_spells(first, current)
+
+ inkey_scan = FALSE
+ inkey_base = TRUE
+ char = inkey()
+ dir = get_keymap_dir(char)
+ if char == ESCAPE then
+ if library_quest.book_slots_left() == 0 then
+ flush()
+ done = get_check("Really create the book?")
+ else
+ done = TRUE
+ end
+ elseif char == strbyte('\r') then
+ -- TODO: make tree of schools
+ elseif char == strbyte('n') then
+ current = current + height
+ elseif char == strbyte('p') then
+ current = current - height
+ elseif char == strbyte('I') then
+ print_spell_desc(library_quest.bookable_spells[current], 0)
+ inkey()
+ elseif dir == 2 then
+ current = current + 1
+ elseif dir == 8 then
+ current = current - 1
+ elseif dir == 6 then
+ if library_quest.book_contains_spell(library_quest.bookable_spells[current]) == FALSE then
+ library_quest.add_spell(library_quest.bookable_spells[current])
+ end
+ elseif dir == 4 then
+ library_quest.remove_spell(library_quest.bookable_spells[current])
+ end
+ total = getn(library_quest.bookable_spells)
+ if current > total then
+ current = total
+ elseif current < 1 then
+ current = 1
+ end
+
+ if current > (first + height - margin - 1) then
+ first = current - height + margin + 1
+ elseif first > current then
+ first = current
+ end
+ end
+
+ screen_load()
+end
+
+-- Quest data and hooks
+add_quest
+{
+ ["global"] = "LIBRARY_QUEST",
+ ["name"] = "Library quest",
+ ["desc"] = function()
+ -- Quest taken
+ if (quest(LIBRARY_QUEST).status == QUEST_STATUS_TAKEN) then
+ print_hook("#####yAn Old Mages Quest! (Danger Level: 35)\n")
+ print_hook("Make the library safe for the old mage in Minas Anor.\n")
+ print_hook("\n")
+ -- Quest done, book not gotten yet
+ elseif (quest(LIBRARY_QUEST).status == QUEST_STATUS_COMPLETED) then
+ print_hook("#####yAn Old Mages Quest!\n")
+ print_hook("You have made the library safe for the old mage in Minas Anor.\n")
+ print_hook("Perhaps you should see about a reward.\n")
+ print_hook("\n")
+ end
+ end,
+ ["level"] = 35,
+ ["data"] =
+ {
+ ["school_book[61][1]"] = -1,
+ ["school_book[61][2]"] = -1,
+ ["school_book[61][3]"] = -1
+ },
+ ["hooks"] =
+ {
+ -- Start the game without the quest, need to request it
+ [HOOK_BIRTH_OBJECTS] = function()
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_UNTAKEN
+ school_book[61] = {-1, -1, -1}
+ end,
+
+ [HOOK_GEN_QUEST] = function()
+ -- Only if player doing this quest
+ if (player.inside_quest ~= LIBRARY_QUEST) then
+ return FALSE
+ end
+
+ load_map("library.map", 2, 2)
+ level_flags2 = DF2_NO_GENO
+
+ -- generate the Liches 518
+ liches = damroll(4, 2) -- plus one on the map
+ while(liches > 0) do
+ if 0 < library_quest.place_random(4, 4, 14, 37, 518) then
+ liches = liches - 1
+ end
+ end
+
+ -- generate the Monastic liches 611
+ liches = damroll(1, 2)
+ while(liches > 0) do
+ if 0 < library_quest.place_random(14, 34, 37, 67, 611) then
+ liches = liches - 1
+ end
+ end
+
+ -- generate more Monastic liches 611
+ liches = damroll(1, 2) - 1
+ while(liches > 0) do
+ if 0 < library_quest.place_random(4, 34, 14, 67, 611) then
+ liches = liches - 1
+ end
+ end
+
+ -- generate even more Monastic liches 611
+ liches = damroll(1, 2) - 1
+ while(liches > 0) do
+ if 0 < library_quest.place_random(14, 4, 37, 34, 611) then
+ liches = liches - 1
+ end
+ end
+
+ -- Flesh golem 256
+ golems = 2
+ while(golems > 0) do
+ if 0 < library_quest.place_random(10, 10, 37, 67, 256) then
+ golems = golems - 1
+ end
+ end
+
+ -- Clay golem 261
+ golems = 2
+ while(golems > 0) do
+ if 0 < library_quest.place_random(10, 10, 37, 67, 261) then
+ golems = golems - 1
+ end
+ end
+
+ -- Iron golem 367
+ golems = 2
+ while(golems > 0) do
+ if 0 < library_quest.place_random(10, 10, 37, 67, 367) then
+ golems = golems - 1
+ end
+ end
+
+ -- Mithril Golem 464
+ golems = 1
+ while(golems > 0) do
+ if 0 < library_quest.place_random(10, 10, 37, 67, 464) then
+ golems = golems - 1
+ end
+ end
+
+ -- one Master lich is on the map
+
+ return TRUE
+ end,
+ [HOOK_STAIR] = function()
+ local ret
+
+ -- only ask this if player about to go up stairs of quest and hasn't won yet
+ if (player.inside_quest ~= LIBRARY_QUEST) or (quest(LIBRARY_QUEST).status == QUEST_STATUS_COMPLETED) then
+ return FALSE
+ end
+
+ if cave(player.py, player.px).feat ~= FEAT_LESS then return end
+
+ -- flush all pending input
+ flush()
+
+ -- confirm
+ ret = get_check("Really abandon the quest?")
+
+ -- if yes, then
+ if ret == TRUE then
+ -- fail the quest
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_FAILED
+ return FALSE
+ else
+ -- if no, they stay in the quest
+ return TRUE
+ end
+ end,
+ [HOOK_MONSTER_DEATH] = function()
+ -- if they're in the quest and haven't won, continue
+ if (player.inside_quest ~= LIBRARY_QUEST) or (quest(LIBRARY_QUEST).status == QUEST_STATUS_COMPLETED) then
+ return FALSE
+ end
+
+ i = 1
+ count = -1
+ while i <= m_max do
+ local monster = m_list[i]
+ if (monster.r_idx > 0) and (monster.status <= MSTATUS_ENEMY) then
+ count = count + 1
+ end
+ i = i + 1
+ end
+
+ if count == 0 then
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_COMPLETED
+ msg_print(TERM_YELLOW, "The library is safe now.")
+ end
+ end,
+ },
+}
+
+-- Library store action
+add_building_action
+{
+ ["index"] = 61,
+ ["action"] = function()
+ -- the quest hasn't been requested already, right?
+ if quest(LIBRARY_QUEST).status == QUEST_STATUS_UNTAKEN then
+ -- quest has been taken now
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_TAKEN
+
+ -- issue instructions
+ msg_print("I need get some stock from my main library, but it is infested with monsters!")
+ msg_print("Please use the side entrance and vanquish the intruders for me.")
+
+ return TRUE, FALSE, TRUE
+ -- if quest completed
+ elseif (quest(LIBRARY_QUEST).status == QUEST_STATUS_COMPLETED) then
+ msg_print("Thank you! Let me make a special book for you.")
+ msg_print("Tell me three spells and I will write them in the book.")
+ library_quest.fill_book()
+ if library_quest.book_slots_left() == 0 then
+ quest(LIBRARY_QUEST).status = QUEST_STATUS_REWARDED
+ book = create_object(TV_BOOK, 61)
+ book.art_name = quark_add(player_name())
+ book.found = OBJ_FOUND_REWARD
+ set_aware(book)
+ set_known(book)
+ inven_carry(book, FALSE)
+ end
+
+ -- if the player asks for a quest when they already have it, but haven't failed it, give them some extra instructions
+ elseif (quest(LIBRARY_QUEST).status == QUEST_STATUS_TAKEN) then
+ msg_print("Please use the side entrance and vanquish the intruders for me.")
+
+ -- quest failed or completed, then give no more quests
+ elseif (quest(LIBRARY_QUEST).status == QUEST_STATUS_FAILED) or (quest(LIBRARY_QUEST).status == QUEST_STATUS_REWARDED) then
+ msg_print("I have no more quests for you.")
+ end
+ return TRUE
+ end,
+}
diff --git a/lib/scpt/mimic.lua b/lib/scpt/mimic.lua
new file mode 100644
index 00000000..6529f35c
--- /dev/null
+++ b/lib/scpt/mimic.lua
@@ -0,0 +1,419 @@
+-- Define the various possible mimic shapes
+
+-- Nature shapes
+add_mimic_shape
+{
+ ["name"] = "Mouse",
+ ["obj_name"] = "Mouse Fur",
+ ["desc"] = "Mice are small, fast and very stealthy",
+ ["realm"] = "nature",
+ ["level"] = 1,
+ ["rarity"] = 10,
+ ["duration"] = {20, 40},
+ ["calc"] = function ()
+ -- Mice run!
+ player.pspeed = player.pspeed + 5 + (player.mimic_level / 7)
+
+ -- They can crtawl under your armor to hit you ;)
+ player.to_h = player.to_h + 10 + (player.mimic_level / 5)
+ player.dis_to_h = player.dis_to_h + 10 + (player.mimic_level / 5)
+
+ -- But they are not very powerfull
+ player.to_d = player.to_d / 5
+ player.dis_to_d = player.dis_to_d / 5
+
+ -- But they are stealthy
+ player.skill_stl = player.skill_stl + 10 + (player.mimic_level / 5)
+
+ -- Stat mods
+ player.modify_stat(A_STR, -5)
+ player.modify_stat(A_DEX, 3)
+ player.modify_stat(A_CON, 1)
+
+ end,
+ ["power"] = function()
+ if player.mimic_level >= 30 then
+ player.add_power(POWER_INVISIBILITY)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Eagle",
+ ["obj_name"] = "Feathers Cloak",
+ ["desc"] = "Eagles are master of the air, good hunters with excellent vision.",
+ ["realm"] = "nature",
+ ["level"] = 10,
+ ["rarity"] = 30,
+ ["duration"] = {10, 50},
+ ["calc"] = function ()
+ player.ffall = TRUE
+ player.pspeed = player.pspeed + 2 + (player.mimic_level / 6)
+
+ player.modify_stat(A_STR, -3)
+ player.modify_stat(A_DEX, 2 + (player.mimic_level / 15))
+ player.modify_stat(A_CON, 4 + (player.mimic_level / 20))
+ player.modify_stat(A_INT, -1)
+ player.modify_stat(A_WIS, 1)
+ player.modify_stat(A_CHR, -1)
+
+ if player.mimic_level >= 20 then
+ player.xtra_f4 = bor(player.xtra_f4, TR4_FLY)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SEE_INVIS)
+ end
+ if player.mimic_level >= 25 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_ELEC)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SH_ELEC)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Wolf",
+ ["obj_name"] = "Wolf Pelt",
+ ["desc"] = "Wolves are masters of movement, strong and have excellent eyesight.",
+ ["realm"] = "nature",
+ ["level"] = 20,
+ ["rarity"] = 40,
+ ["duration"] = {10, 50},
+ ["calc"] = function ()
+ player.modify_stat(A_STR, 2 + (player.mimic_level / 20))
+ player.modify_stat(A_DEX, 3 + (player.mimic_level / 20))
+ player.modify_stat(A_INT, -3)
+ player.modify_stat(A_CHR, -2)
+
+ player.pspeed = player.pspeed + 10 + (player.mimic_level / 5)
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_FEAR)
+
+ if player.mimic_level >= 10 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_COLD)
+ end
+ if player.mimic_level >= 15 then
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SEE_INVIS)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_DARK)
+ end
+ if player.mimic_level >= 35 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CONF)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Spider",
+ ["obj_name"] = "Spider Web",
+ ["desc"] = "Spiders are clever and become good climbers.",
+ ["realm"] = "nature",
+ ["level"] = 25,
+ ["rarity"] = 50,
+ ["duration"] = {10, 50},
+ ["calc"] = function ()
+ player.modify_stat(A_STR, -4)
+ player.modify_stat(A_DEX, 1 + (player.mimic_level / 8))
+ player.modify_stat(A_INT, 1 + (player.mimic_level / 5))
+ player.modify_stat(A_WIS, 1 + (player.mimic_level / 5))
+ player.modify_stat(A_CON, -5)
+ player.modify_stat(A_CHR, -10)
+
+ player.pspeed = player.pspeed + 5
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_FEAR)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_DARK)
+
+ if player.mimic_level >= 40 then
+ player.xtra_f4 = bor(player.xtra_f4, TR4_CLIMB)
+ end
+
+ end,
+ ["power"] = function()
+ if player.mimic_level >= 25 then
+ player.add_power(POWER_WEB)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Elder Ent",
+ ["obj_name"] = "Entish Bark",
+ ["desc"] = "Ents are powerful tree-like beings dating from the dawn of time.",
+ ["realm"] = "nature",
+ ["level"] = 40,
+ ["rarity"] = 60,
+ ["duration"] = {10, 30},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.pspeed = player.pspeed - 5 - (player.mimic_level / 10)
+
+ player.to_a = player.to_a + 10 + player.mimic_level
+ player.dis_to_a = player.dis_to_a + 10 + player.mimic_level
+
+ player.modify_stat(A_STR, player.mimic_level / 5)
+ player.modify_stat(A_INT, - (player.mimic_level / 7))
+ player.modify_stat(A_WIS, - (player.mimic_level / 7))
+ player.modify_stat(A_DEX, -4)
+ player.modify_stat(A_CON, player.mimic_level / 5)
+ player.modify_stat(A_CHR, -7)
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_COLD)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SEE_INVIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_SENS_FIRE)
+ end,
+ ["power"] = function ()
+ player.add_power(PWR_GROW_TREE)
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Vapour",
+ ["obj_name"] = "Cloak of Mist",
+ ["desc"] = "A sentient cloud, darting around",
+ ["realm"] = "nature",
+ ["level"] = 15,
+ ["rarity"] = 10,
+ ["duration"] = {10, 40},
+ ["calc"] = function ()
+
+ player.pspeed = player.pspeed + 5
+
+ --Try to hit a cloud!
+ player.to_a = player.to_a + 40 + player.mimic_level
+ player.dis_to_a = player.dis_to_a + 40 + player.mimic_level
+
+ --Try to hit WITH a cloud!
+ player.to_h = player.to_h - 40
+ player.dis_to_h = player.dis_to_h -40
+
+ -- Stat mods
+ player.modify_stat(A_STR, -4)
+ player.modify_stat(A_DEX, 5)
+ player.modify_stat(A_CON, -4)
+ player.modify_stat(A_CHR, -10)
+
+ -- But they are stealthy
+ player.skill_stl = player.skill_stl + 10 + (player.mimic_level / 5)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_SHARDS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_COLD)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SEE_INVIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_SENS_FIRE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_FEATHER)
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Serpent",
+ ["obj_name"] = "Snakeskin Cloak",
+ ["desc"] = "Serpents are fast, lethal predators.",
+ ["realm"] = "nature",
+ ["level"] = 30,
+ ["rarity"] = 25,
+ ["duration"] = {15, 20},
+ ["calc"] = function ()
+ player.pspeed = player.pspeed + 10 + (player.mimic_level / 6)
+ player.to_a = player.to_a + 3 + (player.mimic_level / 8)
+ player.dis_to_a = player.dis_to_a + 3 + (player.mimic_level / 8)
+
+ player.modify_stat(A_STR, player.mimic_level / 8)
+ player.modify_stat(A_INT, -6)
+ player.modify_stat(A_WIS, -6)
+ player.modify_stat(A_DEX, -4)
+ player.modify_stat(A_CON, player.mimic_level / 7)
+ player.modify_stat(A_CHR, -6)
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ if player.mimic_level >= 25 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ end
+ end,
+}
+
+add_mimic_shape
+{
+ ["name"] = "Mumak",
+ ["obj_name"] = "Mumak Hide",
+ ["desc"] = "A giant, elaphantine form.",
+ ["realm"] = "nature",
+ ["level"] = 40,
+ ["rarity"] = 40,
+ ["duration"] = {15, 20},
+ ["calc"] = function ()
+ player.pspeed = player.pspeed - 5 - (player.mimic_level / 10)
+ player.to_a = player.to_a + 10 + (player.mimic_level / 6)
+ player.dis_to_a = player.dis_to_a + 10 + (player.mimic_level / 6)
+ player.to_d = player.to_d + 5 + ((player.mimic_level * 2) / 3)
+ player.dis_to_d = player.dis_to_d + 5 + ((player.mimic_level * 2) / 3)
+
+ player.modify_stat(A_STR, player.mimic_level / 4)
+ player.modify_stat(A_INT, -8)
+ player.modify_stat(A_WIS, -4)
+ player.modify_stat(A_DEX, -5)
+ player.modify_stat(A_CON, player.mimic_level / 3)
+ player.modify_stat(A_CHR, -10)
+
+ if player.mimic_level >= 10 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_FEAR)
+ end
+ if player.mimic_level >= 25 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CONF)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ end
+ if player.mimic_level >= 35 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_NEXUS)
+ end
+ end,
+}
+
+--------- Extra shapes -----------
+
+-- For Beornings
+add_mimic_shape
+{
+ ["name"] = "Bear",
+ ["desc"] = "A fierce, terrible bear.",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {50, 200},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.pspeed = player.pspeed - 5 + (player.mimic_level / 5)
+
+ player.to_a = player.to_a + 5 + ((player.mimic_level * 2) / 3)
+ player.dis_to_a = player.dis_to_a + 5 + ((player.mimic_level * 2) / 3)
+
+ player.modify_stat(A_STR, player.mimic_level / 11)
+ player.modify_stat(A_INT, player.mimic_level / 11)
+ player.modify_stat(A_WIS, player.mimic_level / 11)
+ player.modify_stat(A_DEX, -1)
+ player.modify_stat(A_CON, player.mimic_level / 11)
+ player.modify_stat(A_CHR, -10)
+
+ if player.mimic_level >= 10 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_FREE_ACT)
+ end
+ if player.mimic_level >= 20 then
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ end
+ if player.mimic_level >= 30 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CONF)
+ end
+ if player.mimic_level >= 35 then
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_NEXUS)
+ end
+
+ -- activate the skill
+ skill(SKILL_BEAR).hidden = FALSE
+ end,
+}
+
+-- For balrog corruptions
+add_mimic_shape
+{
+ ["name"] = "Balrog",
+ ["desc"] = "A corrupted maia.",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {30, 70},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.modify_stat(A_STR, 5 + player.mimic_level / 5)
+ player.modify_stat(A_INT, player.mimic_level / 10)
+ player.modify_stat(A_WIS, - ( 5 + player.mimic_level / 10))
+ player.modify_stat(A_DEX, player.mimic_level / 10)
+ player.modify_stat(A_CON, 5 + player.mimic_level / 5)
+ player.modify_stat(A_CHR, - ( 5 + player.mimic_level / 10))
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_ACID)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_FIRE)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_ELEC)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_DARK)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CHAOS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_HOLD_LIFE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_FEATHER)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SH_FIRE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_LITE1)
+ return 1
+ end,
+}
+
+-- For avatar spell
+add_mimic_shape
+{
+ ["name"] = "Maia",
+ ["desc"] = "A near god-like being.",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {30, 70},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.modify_stat(A_STR, 5 + player.mimic_level / 5)
+ player.modify_stat(A_INT, 5 + player.mimic_level / 5)
+ player.modify_stat(A_WIS, 5 + player.mimic_level / 5)
+ player.modify_stat(A_DEX, 5 + player.mimic_level / 5)
+ player.modify_stat(A_CON, 5 + player.mimic_level / 5)
+ player.modify_stat(A_CHR, 5 + player.mimic_level / 5)
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_FIRE)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_ELEC)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_ACID)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_COLD)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_LITE)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_DARK)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_CHAOS)
+ player.xtra_f2 = bor(player.xtra_f2, TR2_HOLD_LIFE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_FEATHER)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_REGEN)
+ return 2
+ end,
+}
+
+-- For Geomancy
+add_mimic_shape
+{
+ ["name"] = "Fire Elem.",
+ ["desc"] = "A towering column of flames",
+ ["realm"] = nil,
+ ["level"] = 1,
+ ["rarity"] = 101,
+ ["duration"] = {10, 10},
+ ["limit"] = TRUE,
+ ["calc"] = function ()
+ player.modify_stat(A_STR, 5 + (player.mimic_level / 5))
+ player.modify_stat(A_DEX, 5 + (player.mimic_level / 5))
+ player.modify_stat(A_WIS, -5 - (player.mimic_level / 5))
+
+ player.xtra_f2 = bor(player.xtra_f2, TR2_IM_FIRE)
+ -- was immune to poison in the 3.0.0 version
+ player.xtra_f2 = bor(player.xtra_f2, TR2_RES_POIS)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_SH_FIRE)
+ player.xtra_f3 = bor(player.xtra_f3, TR3_LITE1)
+ return 0
+ end,
+}
diff --git a/lib/scpt/mkeys.lua b/lib/scpt/mkeys.lua
new file mode 100644
index 00000000..07105c64
--- /dev/null
+++ b/lib/scpt/mkeys.lua
@@ -0,0 +1,95 @@
+-- Mkeys for skills & abilities
+
+GF_INSTA_DEATH = add_spell_type
+{
+ ["color"] = { TERM_DARK, 0 },
+ ["angry"] = function() return TRUE, TRUE end,
+ ["monster"] = function(who, dam, rad, y, x, monst)
+ local race = race_info_idx(monst.r_idx, monst.ego)
+ if magik(5) == FALSE or band(race.flags1, RF1_UNIQUE) ~= FALSE or band(race.flags3, RF3_UNDEAD) ~= FALSE or band(race.flags3, RF3_NONLIVING) ~= FALSE then
+ return TRUE, FALSE
+ else
+ -- Reduce the exp gained this way
+ monst.level = monst.level / 3
+ return TRUE, FALSE, 32535, 0, 0, 0, 0, 0, 0, 0, " faints.", " is sucked out of life."
+ end
+ end,
+}
+
+-- Death touch ability
+add_mkey
+{
+ ["mkey"] = 100,
+ ["fct"] = function()
+ if player.csp > 40 then
+ increase_mana(-40)
+ set_project(randint(30) + 10, GF_INSTA_DEATH, 1, 0, bor(PROJECT_STOP, PROJECT_KILL))
+ energy_use = 100
+ else
+ msg_print("You need at least 40 mana.")
+ end
+ end,
+}
+
+
+-- Geomancy skill
+add_mkey
+{
+ ["mkey"] = 101,
+ ["fct"] = function()
+ local s
+
+ -- No magic
+ if (player.antimagic > 0) then
+ msg_print("Your anti-magic field disrupts any magic attempts.")
+ return
+ end
+
+ local obj = get_object(INVEN_WIELD)
+ if (obj.k_idx <= 0) or (obj.tval ~= TV_MSTAFF) then
+ msg_print('You must wield a magestaff to use Geomancy.')
+ return
+ end
+
+ s = get_school_spell("cast", "is_ok_spell", 62);
+
+ -- Actualy cast the choice
+ if (s ~= -1) then
+ cast_school_spell(s, spell(s))
+ end
+ end,
+}
+
+-- Far reaching attack of polearms
+add_mkey
+{
+ ["mkey"] = 102,
+ ["fct"] = function()
+ local weapon = get_object(INVEN_WIELD);
+ if weapon.tval == TV_POLEARM then
+ else
+ msg_print("You will need a long polearm for this!")
+ return
+ end
+
+ ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+
+ local dy, dx = explode_dir(dir)
+ dy = dy * 2
+ dx = dx * 2
+ targety = player.py + dy
+ targetx = player.px + dx
+
+ local max_blows = get_skill_scale(SKILL_POLEARM, player.num_blow / 2)
+ if max_blows == 0 then max_blows = 1 end
+
+ if get_skill(SKILL_POLEARM) >= 40 then
+ energy_use = energy_use + 200
+ return project(0, 0, targety, targetx, max_blows, GF_ATTACK, bor(PROJECT_BEAM, PROJECT_KILL))
+ else
+ energy_use = energy_use + 200
+ return project(0, 0, targety, targetx, max_blows, GF_ATTACK, bor(PROJECT_BEAM, PROJECT_STOP, PROJECT_KILL))
+ end
+ end,
+}
diff --git a/lib/scpt/player.lua b/lib/scpt/player.lua
new file mode 100644
index 00000000..2a617608
--- /dev/null
+++ b/lib/scpt/player.lua
@@ -0,0 +1,76 @@
+------------------------------------------------------------------------------
+----------------------- Hook to create birth objects -------------------------
+------------------------------------------------------------------------------
+function __birth_hook_objects()
+ -- Provide a book of blink to rangers
+ if get_class_name() == "Ranger" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Phase Door")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Provide a book of Geyser to Geomancers
+ if get_class_name() == "Geomancer" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Geyser")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Provide a book of prayer to priests
+ if get_class_name() == "Priest(Eru)" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("See the Music")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Priest(Manwe)" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Manwe's Blessing")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Druid" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Charm Animal")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Dark-Priest" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Curse")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Paladin" then
+ local obj = create_object(TV_BOOK, 255);
+ obj.pval = find_spell("Divine Aim")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+ if get_class_name() == "Mimic" then
+ local obj = create_object(TV_CLOAK, 100);
+ obj.pval2 = resolve_mimic_name("Mouse")
+ obj.ident = bor(obj.ident, IDENT_MENTAL, IDENT_KNOWN)
+ inven_carry(obj, FALSE)
+ end_object(obj)
+ end
+
+ -- Start the undeads, as undeads with the corruptions
+ if get_subrace_name() == "Vampire" then
+ player.corruption(CORRUPT_VAMPIRE_TEETH, TRUE)
+ player.corruption(CORRUPT_VAMPIRE_STRENGTH, TRUE)
+ player.corruption(CORRUPT_VAMPIRE_VAMPIRE, TRUE)
+ end
+end
+
+-- Register in the hook list
+add_hook_script(HOOK_BIRTH_OBJECTS, "__birth_hook_objects", "__birth_hook_objects")
diff --git a/lib/scpt/powers.lua b/lib/scpt/powers.lua
new file mode 100644
index 00000000..ff4c62c5
--- /dev/null
+++ b/lib/scpt/powers.lua
@@ -0,0 +1,61 @@
+-- Various 'U' powers
+
+-- Invisibility power, for the mouse mimic shape
+POWER_INVISIBILITY = add_power
+{
+ ["name"] = "invisibility",
+ ["desc"] = "You are able melt into the shadows to become invisible.",
+ ["desc_get"] = "You suddenly become able to melt into the shadows.",
+ ["desc_lose"] = "You lose your shadow-melting ability.",
+ ["level"] = 30,
+ ["cost"] = 10,
+ ["stat"] = A_DEX,
+ ["fail"] = 20,
+ ["power"] = function()
+ set_invis(20 + randint(30), 30)
+ end,
+}
+
+-- Web power, for the spider mimic shape
+POWER_WEB = add_power
+{
+ ["name"] = "web",
+ ["desc"] = "You are able throw a thick and very resistant spider web.",
+ ["desc_get"] = "You suddenly become able to weave webs.",
+ ["desc_lose"] = "You lose your web-weaving capability.",
+ ["level"] = 25,
+ ["cost"] = 30,
+ ["stat"] = A_DEX,
+ ["fail"] = 20,
+ ["power"] = function()
+ -- Warning, beware of f_info changes .. I hate to do that ..
+ grow_things(16, 1 + (player.lev / 10))
+ end,
+}
+
+-- Activating/stopping space-continuum
+-- When stopped it will induce constant mana loss
+player.corrupt_anti_teleport_stopped = FALSE
+add_loadsave("player.corrupt_anti_teleport_stopped", FALSE)
+POWER_COR_SPACE_TIME = add_power
+{
+ ["name"] = "control space/time continuum",
+ ["desc"] = "You are able to control the space/time continuum.",
+ ["desc_get"] = "You become able to control the space/time continuum.",
+ ["desc_lose"] = "You are no more able to control the space/time continuum.",
+ ["level"] = 1,
+ ["cost"] = 10,
+ ["stat"] = A_WIS,
+ ["fail"] = 10,
+ ["power"] = function()
+ if player.corrupt_anti_teleport_stopped == TRUE then
+ player.corrupt_anti_teleport_stopped = FALSE
+ msg_print("You stop controlling your corruption.")
+ player.update = bor(player.update, PU_BONUS)
+ else
+ player.corrupt_anti_teleport_stopped = TRUE
+ msg_print("You start controlling your corruption, teleportation works once more.")
+ player.update = bor(player.update, PU_BONUS)
+ end
+ end,
+}
diff --git a/lib/scpt/s_air.lua b/lib/scpt/s_air.lua
new file mode 100644
index 00000000..afd1f584
--- /dev/null
+++ b/lib/scpt/s_air.lua
@@ -0,0 +1,193 @@
+-- handle the air school
+
+NOXIOUSCLOUD = add_spell
+{
+ ["name"] = "Noxious Cloud",
+ ["school"] = {SCHOOL_AIR},
+ ["level"] = 3,
+ ["mana"] = 3,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 7 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 15,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir, type
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ if get_level(NOXIOUSCLOUD, 50) >= 30 then type = GF_UNBREATH
+ else type = GF_POIS end
+ fire_cloud(type, dir, 7 + get_level(NOXIOUSCLOUD, 150), 3, 5 + get_level(NOXIOUSCLOUD, 40))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(7 + get_level(NOXIOUSCLOUD, 150)).." rad 3 dur "..(5 + get_level(NOXIOUSCLOUD, 40))
+ end,
+ ["desc"] = {
+ "Creates a cloud of poison",
+ "The cloud will persist for some turns, damaging all monsters passing by",
+ "At spell level 30 it turns into a thick gas attacking all living beings"
+ }
+}
+
+AIRWINGS = add_spell
+{
+ ["name"] = "Wings of Winds",
+ ["school"] = {SCHOOL_AIR, SCHOOL_CONVEYANCE},
+ ["level"] = 22,
+ ["mana"] = 30,
+ ["mana_max"] = 40,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 27,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ if get_level(AIRWINGS, 50) >= 16 then
+ if player.tim_fly == 0 then return set_tim_fly(randint(10) + 5 + get_level(AIRWINGS, 25)) end
+ else
+ if player.tim_ffall == 0 then return set_tim_ffall(randint(10) + 5 + get_level(AIRWINGS, 25)) end
+ end
+ return FALSE
+ end,
+ ["info"] = function()
+ return "dur "..(5 + get_level(AIRWINGS, 25)).."+d10"
+ end,
+ ["desc"] = {
+ "Grants the power of levitation",
+ "At level 16 it grants the power of controlled flight"
+ }
+}
+
+INVISIBILITY = add_spell
+{
+ ["name"] = "Invisibility",
+ ["school"] = {SCHOOL_AIR},
+ ["level"] = 16,
+ ["mana"] = 10,
+ ["mana_max"] = 20,
+ ["fail"] = 50,
+ ["inertia"] = { 1, 30 },
+ ["spell"] = function()
+ if player.tim_invisible == 0 then return set_invis(randint(20) + 15 + get_level(INVISIBILITY, 50), 20 + get_level(INVISIBILITY, 50)) end
+ end,
+ ["info"] = function()
+ return "dur "..(15 + get_level(INVISIBILITY, 50)).."+d20 power "..(20 + get_level(INVISIBILITY, 50))
+ end,
+ ["desc"] = {
+ "Grants invisibility"
+ }
+}
+
+POISONBLOOD = add_spell
+{
+ ["name"] = "Poison Blood",
+ ["school"] = {SCHOOL_AIR},
+ ["level"] = 12,
+ ["mana"] = 10,
+ ["mana_max"] = 20,
+ ["fail"] = 30,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 15 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 45,
+ ["base_level"] = { 1, 25 },
+ ["max_level"] = { 35, 50 },
+ },
+ },
+ ["inertia"] = { 1, 35 },
+ ["spell"] = function()
+ local obvious = nil
+ if player.oppose_pois == 0 then obvious = set_oppose_pois(randint(30) + 25 + get_level(POISONBLOOD, 25)) end
+ if (player.tim_poison == 0) and (get_level(POISONBLOOD, 50) >= 15) then obvious = is_obvious(set_poison(randint(30) + 25 + get_level(POISONBLOOD, 25)), obvious) end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(25 + get_level(POISONBLOOD, 25)).."+d30"
+ end,
+ ["desc"] = {
+ "Grants resist poison",
+ "At level 15 it provides poison branding to wielded weapon"
+ }
+}
+
+THUNDERSTORM = add_spell
+{
+ ["name"] = "Thunderstorm",
+ ["school"] = {SCHOOL_AIR, SCHOOL_NATURE},
+ ["level"] = 25,
+ ["mana"] = 40,
+ ["mana_max"] = 60,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 85,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["inertia"] = { 2, 15 },
+ ["spell"] = function()
+ if player.tim_thunder == 0 then return set_tim_thunder(randint(10) + 10 + get_level(THUNDERSTORM, 25), 5 + get_level(THUNDERSTORM, 10), 10 + get_level(THUNDERSTORM, 25)) end
+ return FALSE
+ end,
+ ["info"] = function()
+ return "dam "..(5 + get_level(THUNDERSTORM, 10)).."d"..(10 + get_level(THUNDERSTORM, 25)).." dur "..(10 + get_level(THUNDERSTORM, 25)).."+d10"
+ end,
+ ["desc"] = {
+ "Charges up the air around you with electricity",
+ "Each turn it will throw a thunder bolt at a random monster in sight",
+ "The thunder does 3 types of damage, one third of lightning",
+ "one third of sound and one third of light"
+ }
+}
+
+STERILIZE = add_spell
+{
+ ["name"] = "Sterilize",
+ ["school"] = {SCHOOL_AIR},
+ ["level"] = 20,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 50,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 20,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ set_no_breeders((30) + 20 + get_level(STERILIZE, 70))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dur "..(20 + get_level(STERILIZE, 70)).."+d30"
+ end,
+ ["desc"] = {
+ "Prevents explosive breeding for a while."
+ }
+}
diff --git a/lib/scpt/s_convey.lua b/lib/scpt/s_convey.lua
new file mode 100644
index 00000000..e7856c43
--- /dev/null
+++ b/lib/scpt/s_convey.lua
@@ -0,0 +1,227 @@
+-- handle the conveyance school
+
+BLINK = add_spell
+{
+ ["name"] = "Phase Door",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 3,
+ ["fail"] = 10,
+ ["inertia"] = { 1, 5 },
+ ["spell"] = function()
+ if get_level(BLINK, 50) >= 30 then
+ local oy, ox = player.py, player.px
+
+ teleport_player(10 + get_level(BLINK, 8))
+ create_between_gate(0, oy, ox)
+ return TRUE
+ else
+ teleport_player(10 + get_level(BLINK, 8))
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return "distance "..(10 + get_level(BLINK, 8))
+ end,
+ ["desc"] = {
+ "Teleports you on a small scale range",
+ "At level 30 it creates void jumpgates",
+ }
+}
+
+DISARM = add_spell
+{
+ ["name"] = "Disarm",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 3,
+ ["mana"] = 2,
+ ["mana_max"] = 4,
+ ["fail"] = 15,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 15 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 4,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 10, 50 },
+ },
+ },
+ ["spell"] = function()
+ local obvious
+ obvious = destroy_doors_touch()
+ if get_level(DISARM, 50) >= 10 then obvious = is_obvious(destroy_traps_touch(), obvious) end
+ return obvious
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Destroys doors and traps",
+ "At level 10 it destroys doors and traps, then reveals and unlocks any secret",
+ "doors"
+ }
+}
+
+TELEPORT = add_spell
+{
+ ["name"] = "Teleportation",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 10,
+ ["mana"] = 8,
+ ["mana_max"] = 14,
+ ["fail"] = 30,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 7 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 50,
+ ["base_level"] = { 1, 20 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ player.energy = player.energy - (25 - get_level(TELEPORT, 50))
+ teleport_player(100 + get_level(TELEPORT, 100))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "distance "..(100 + get_level(TELEPORT, 100))
+ end,
+ ["desc"] = {
+ "Teleports you around the level. The casting time decreases with level",
+ }
+}
+
+TELEAWAY = add_spell
+{
+ ["name"] = "Teleport Away",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 23,
+ ["mana"] = 15,
+ ["mana_max"] = 40,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 75,
+ ["base_level"] = { 1, 20 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir
+
+ if get_level(TELEAWAY, 50) >= 20 then
+ return project_los(GF_AWAY_ALL, 100)
+ elseif get_level(TELEAWAY, 50) >= 10 then
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_AWAY_ALL, dir, 100, 3 + get_level(TELEAWAY, 4))
+ else
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return teleport_monster(dir)
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Teleports a line of monsters away",
+ "At level 10 it turns into a ball",
+ "At level 20 it teleports all monsters in sight"
+ }
+}
+
+RECALL = add_spell
+{
+ ["name"] = "Recall",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 30,
+ ["mana"] = 25,
+ ["mana_max"] = 25,
+ ["fail"] = 60,
+ ["spell"] = function()
+ local ret, x, y, c_ptr
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ c_ptr = cave(y, x)
+ if (y == player.py) and (x == player.px) then
+ local d = 21 - get_level(RECALL, 15)
+ if d < 0 then
+ d = 0
+ end
+ local f = 15 - get_level(RECALL, 10)
+ if f < 1 then
+ f = 1
+ end
+ recall_player(d, f)
+ return TRUE
+ elseif c_ptr.m_idx > 0 then
+ swap_position(y, x)
+ return TRUE
+ elseif c_ptr.o_idx > 0 then
+ set_target(y, x)
+ if get_level(RECALL, 50) >= 15 then
+ fetch(5, 10 + get_level(RECALL, 150), FALSE)
+ else
+ fetch(5, 10 + get_level(RECALL, 150), TRUE)
+ end
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ local d = 21 - get_level(RECALL, 15)
+ if d < 0 then
+ d = 0
+ end
+ local f = 15 - get_level(RECALL, 10)
+ if f < 1 then
+ f = 1
+ end
+ return "dur "..f.."+d"..d.." weight "..(1 + get_level(RECALL, 15)).."lb"
+ end,
+ ["desc"] = {
+ "Cast on yourself it will recall you to the surface/dungeon.",
+ "Cast at a monster you will swap positions with the monster.",
+ "Cast at an object it will fetch the object to you."
+ }
+}
+
+PROBABILITY_TRAVEL = add_spell
+{
+ ["name"] = "Probability Travel",
+ ["school"] = {SCHOOL_CONVEYANCE},
+ ["level"] = 35,
+ ["mana"] = 30,
+ ["mana_max"] = 50,
+ ["fail"] = 90,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 2 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 97,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 8, 25 },
+ },
+ },
+ ["inertia"] = { 6, 40 },
+ ["spell"] = function()
+ return set_prob_travel(randint(20) + get_level(PROBABILITY_TRAVEL, 60))
+ end,
+ ["info"] = function()
+ return "dur "..get_level(PROBABILITY_TRAVEL, 60).."+d20"
+ end,
+ ["desc"] = {
+ "Renders you immaterial, when you hit a wall you travel through it and",
+ "instantly appear on the other side of it. You can also float up and down",
+ "at will"
+ }
+}
diff --git a/lib/scpt/s_demon.lua b/lib/scpt/s_demon.lua
new file mode 100644
index 00000000..ada97310
--- /dev/null
+++ b/lib/scpt/s_demon.lua
@@ -0,0 +1,337 @@
+-- handle the demonology school
+
+-- Demonblade
+DEMON_BLADE = add_spell
+{
+ ["name"] = "Demon Blade",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 1,
+ ["mana"] = 4,
+ ["mana_max"] = 44,
+ ["fail"] = 10,
+ ["random"] = 0,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 7 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 75,
+ ["base_level"] = { 1, 17 },
+ ["max_level"] = { 20, 40 },
+ },
+ },
+ ["spell"] = function()
+ local type, rad
+
+ type = GF_FIRE
+ if get_level(DEMON_BLADE) >= 30 then type = GF_HELL_FIRE end
+
+ rad = 0
+ if get_level(DEMON_BLADE) >= 45 then rad = 1 end
+
+ return set_project(randint(20) + get_level(DEMON_BLADE, 80),
+ type,
+ 4 + get_level(DEMON_BLADE, 40),
+ rad,
+ bor(PROJECT_STOP, PROJECT_KILL))
+ end,
+ ["info"] = function()
+ return "dur "..(get_level(DEMON_BLADE, 80)).."+d20 dam "..(4 + get_level(DEMON_BLADE, 40)).."/blow"
+ end,
+ ["desc"] = {
+ "Imbues your blade with fire to deal more damage",
+ "At level 30 it deals hellfire damage",
+ "At level 45 it spreads over a 1 radius zone around your target",
+ }
+}
+
+DEMON_MADNESS = add_spell
+{
+ ["name"] = "Demon Madness",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 10,
+ ["mana"] = 5,
+ ["mana_max"] = 20,
+ ["fail"] = 25,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir, type, y1, x1, y2, x2
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ type = GF_CHAOS
+ if magik(33) == TRUE then type = GF_CONFUSION end
+ if magik(33) == TRUE then type = GF_CHARM end
+
+ -- Calc the coordinates of arrival
+ y1, x1 = get_target(dir)
+ y2 = player.py - (y1 - player.py)
+ x2 = player.px - (x1 - player.px)
+
+ local obvious = nil
+ obvious = project(0, 1 + get_level(DEMON_MADNESS, 4, 0),
+ y1, x1,
+ 20 + get_level(DEMON_MADNESS, 200),
+ type, bor(PROJECT_STOP, PROJECT_GRID, PROJECT_ITEM, PROJECT_KILL))
+ obvious = is_obvious(project(0, 1 + get_level(DEMON_MADNESS, 4, 0),
+ y2, x2,
+ 20 + get_level(DEMON_MADNESS, 200),
+ type, bor(PROJECT_STOP, PROJECT_GRID, PROJECT_ITEM, PROJECT_KILL)), obvious)
+ return obvious
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(DEMON_MADNESS, 200)).." rad "..(1 + get_level(DEMON_MADNESS, 4, 0))
+ end,
+ ["desc"] = {
+ "Fire 2 balls in opposite directions of randomly chaos, confusion or charm",
+ }
+}
+
+DEMON_FIELD = add_spell
+{
+ ["name"] = "Demon Field",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 20,
+ ["mana"] = 20,
+ ["mana_max"] = 60,
+ ["fail"] = 60,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_cloud(GF_NEXUS, dir, 20 + get_level(DEMON_FIELD, 70), 7, 30 + get_level(DEMON_FIELD, 100))
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(DEMON_FIELD, 70)).." dur "..(30 + get_level(DEMON_FIELD, 100))
+ end,
+ ["desc"] = {
+ "Fires a cloud of deadly nexus over a radius of 7",
+ }
+}
+
+-- Demonshield
+
+DOOM_SHIELD = add_spell
+{
+ ["name"] = "Doom Shield",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 1,
+ ["mana"] = 2,
+ ["mana_max"] = 30,
+ ["fail"] = 10,
+ ["random"] = 0,
+ ["spell"] = function()
+ return set_shield(randint(10) + 20 + get_level(DOOM_SHIELD, 100), -300 + get_level(DOOM_SHIELD, 100), SHIELD_COUNTER, 1 + get_level(DOOM_SHIELD, 14), 10 + get_level(DOOM_SHIELD, 15))
+ end,
+ ["info"] = function()
+ return "dur "..(20 + get_level(DOOM_SHIELD, 100)).."+d10 dam "..(1 + get_level(DOOM_SHIELD, 14)).."d"..(10 + get_level(DOOM_SHIELD, 15))
+ end,
+ ["desc"] = {
+ "Raises a mirror of pain around you, doing very high damage to your foes",
+ "that dare hit you, but greatly reduces your armour class",
+ }
+}
+
+UNHOLY_WORD = add_spell
+{
+ ["name"] = "Unholy Word",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 25,
+ ["mana"] = 15,
+ ["mana_max"] = 45,
+ ["fail"] = 55,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, x, y, c_ptr
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ c_ptr = cave(y, x)
+
+ -- ok that is a monster
+ if c_ptr.m_idx > 0 then
+ local m_ptr = monster(c_ptr.m_idx)
+ if m_ptr.status ~= MSTATUS_PET then
+ msg_print("You can only target a pet.")
+ return
+ end
+
+ -- Oups he is angry now
+ if magik(30 - get_level(UNHOLY_WORD, 25, 0)) == TRUE then
+ local m_name = monster_desc(m_ptr, 0).." turns against you."
+ msg_print(strupper(strsub(m_name, 0, 1))..strsub(m_name, 2))
+ else
+ local m_name = monster_desc(m_ptr, 0)
+ msg_print("You consume "..m_name..".")
+
+ local heal = (m_ptr.hp * 100) / m_ptr.maxhp
+ heal = ((30 + get_level(UNHOLY_WORD, 50, 0)) * heal) / 100
+
+ hp_player(heal)
+
+ delete_monster_idx(c_ptr.m_idx)
+ end
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return "heal mhp% of "..(30 + get_level(UNHOLY_WORD, 50, 0)).."%"
+ end,
+ ["desc"] = {
+ "Kills a pet to heal you",
+ "There is a chance that the pet won't die but will turn against you",
+ "it will decrease with higher level",
+ }
+}
+
+DEMON_CLOAK = add_spell
+{
+ ["name"] = "Demon Cloak",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 20,
+ ["mana"] = 10,
+ ["mana_max"] = 40,
+ ["fail"] = 70,
+ ["random"] = 0,
+ ["spell"] = function()
+ return set_tim_reflect(randint(5) + 5 + get_level(DEMON_CLOAK, 15, 0))
+ end,
+ ["info"] = function()
+ return "dur "..(5 + get_level(DEMON_CLOAK, 15, 0)).."+d5"
+ end,
+ ["desc"] = {
+ "Raises a mirror that can reflect bolts and arrows for a time",
+ }
+}
+
+
+-- Demonhorn
+DEMON_SUMMON = add_spell
+{
+ ["name"] = "Summon Demon",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 5,
+ ["mana"] = 10,
+ ["mana_max"] = 50,
+ ["fail"] = 30,
+ ["random"] = 0,
+ ["spell"] = function()
+ local type = SUMMON_DEMON
+ local level = dun_level
+ local minlevel = 4
+ if level < minlevel then level=minlevel end
+ summon_specific_level = 5 + get_level(DEMON_SUMMON, 100)
+ if get_level(DEMON_SUMMON) >= 35 then type = SUMMON_HI_DEMON end
+ if summon_monster(player.py, player.px, level, TRUE, type) == TRUE then
+ return TRUE
+ else
+ msg_print("Something blocks your summoning!")
+ return FALSE
+ end
+ end,
+ ["info"] = function()
+ return "level "..(5 + get_level(DEMON_SUMMON, 100))
+ end,
+ ["desc"] = {
+ "Summons a leveled demon to your side",
+ "At level 35 it summons a high demon",
+ }
+}
+
+DISCHARGE_MINION = add_spell
+{
+ ["name"] = "Discharge Minion",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 10,
+ ["mana"] = 20,
+ ["mana_max"] = 50,
+ ["fail"] = 30,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, x, y, c_ptr
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ c_ptr = cave(y, x)
+
+ -- ok that is a monster
+ if c_ptr.m_idx > 0 then
+ local m_ptr = monster(c_ptr.m_idx)
+ if m_ptr.status ~= MSTATUS_PET then
+ msg_print("You can only target a pet.")
+ return
+ end
+
+ local dam = m_ptr.hp
+ delete_monster_idx(c_ptr.m_idx)
+ dam = (dam * (20 + get_level(DISCHARGE_MINION, 60, 0))) / 100
+ if dam > 100 + get_level(DISCHARGE_MINION, 500, 0) then
+ dam = 100 + get_level(DISCHARGE_MINION, 500, 0)
+ end
+
+ -- We use project instead of fire_ball because we must tell it exactly where to land
+ return project(0, 2,
+ y, x,
+ dam,
+ GF_GRAVITY, bor(PROJECT_STOP, PROJECT_GRID, PROJECT_ITEM, PROJECT_KILL))
+ end
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(DISCHARGE_MINION, 60, 0)).."% max "..(100 + get_level(DISCHARGE_MINION, 500, 0))
+ end,
+ ["desc"] = {
+ "The targeted pet will explode in a burst of gravity",
+ }
+}
+
+CONTROL_DEMON = add_spell
+{
+ ["name"] = "Control Demon",
+ ["school"] = {SCHOOL_DEMON},
+ ["level"] = 25,
+ ["mana"] = 30,
+ ["mana_max"] = 70,
+ ["fail"] = 55,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ return fire_ball(GF_CONTROL_DEMON, dir, 50 + get_level(CONTROL_DEMON, 250), 0)
+ end,
+ ["info"] = function()
+ return "power "..(50 + get_level(CONTROL_DEMON, 250))
+ end,
+ ["desc"] = {
+ "Attempts to control a demon",
+ }
+}
+
+-- ok we need to have different wield slots
+add_hooks
+{
+ [HOOK_WIELD_SLOT] = function (obj, ideal)
+ if (obj.tval == TV_DAEMON_BOOK) then
+ local slot
+ if (obj.sval == SV_DEMONBLADE) then
+ if(ideal == TRUE) then
+ slot = INVEN_WIELD
+ else
+ slot = get_slot(INVEN_WIELD)
+ end
+ elseif (obj.sval == SV_DEMONSHIELD) then
+ if(ideal == TRUE) then
+ slot = INVEN_ARM
+ else
+ slot = get_slot(INVEN_ARM)
+ end
+ elseif (obj.sval == SV_DEMONHORN) then
+ if(ideal == TRUE) then
+ slot = INVEN_HEAD
+ else
+ slot = get_slot(INVEN_HEAD)
+ end
+ end
+ return TRUE, slot
+ end
+ end,
+}
diff --git a/lib/scpt/s_divin.lua b/lib/scpt/s_divin.lua
new file mode 100644
index 00000000..60b0275f
--- /dev/null
+++ b/lib/scpt/s_divin.lua
@@ -0,0 +1,230 @@
+-- Handles thhe divination school
+
+
+STARIDENTIFY = add_spell
+{
+ ["name"] = "Greater Identify",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 35,
+ ["mana"] = 30,
+ ["mana_max"] = 30,
+ ["fail"] = 80,
+ ["spell"] = function()
+ if get_check("Cast on yourself?") == TRUE then
+ self_knowledge()
+ else
+ identify_fully()
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Asks for an object and fully identify it, providing the full list of powers",
+ "Cast at yourself it will reveal your powers"
+ }
+}
+
+IDENTIFY = add_spell
+{
+ ["name"] = "Identify",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 8,
+ ["mana"] = 10,
+ ["mana_max"] = 50,
+ ["fail"] = 40,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 10 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 45,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 15, 40 },
+ },
+ },
+ ["spell"] = function()
+ if get_level(IDENTIFY, 50) >= 27 then
+ local obvious
+ obvious = identify_pack()
+ obvious = is_obvious(fire_ball(GF_IDENTIFY, 0, 1, get_level(IDENTIFY, 3)), obvious)
+ if obvious == TRUE then
+ player.notice = bor(player.notice, PN_COMBINE, PN_REORDER)
+ end
+ return obvious
+ elseif get_level(IDENTIFY, 50) >= 17 then
+ local obvious
+ obvious = identify_pack()
+ obvious = is_obvious(fire_ball(GF_IDENTIFY, 0, 1, 0), obvious)
+ if obvious == TRUE then
+ player.notice = bor(player.notice, PN_COMBINE, PN_REORDER)
+ end
+ return obvious
+ else
+ if ident_spell() == TRUE then return TRUE else return end
+ end
+ end,
+ ["info"] = function()
+ if get_level(IDENTIFY, 50) >= 27 then
+ return "rad "..(get_level(IDENTIFY, 3))
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Asks for an object and identifies it",
+ "At level 17 it identifies all objects in the inventory",
+ "At level 27 it identifies all objects in the inventory and in a",
+ "radius on the floor, as well as probing monsters in that radius"
+ }
+}
+
+VISION = add_spell
+{
+ ["name"] = "Vision",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 15,
+ ["mana"] = 7,
+ ["mana_max"] = 55,
+ ["fail"] = 45,
+ ["stick"] =
+ {
+ ["charge"] = { 4, 6 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 60,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 10, 30 },
+ },
+ },
+ ["inertia"] = { 2, 200 },
+ ["spell"] = function()
+ if get_level(VISION, 50) >= 25 then
+ wiz_lite_extra()
+ else
+ map_area()
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Detects the layout of the surrounding area",
+ "At level 25 it maps and lights the whole level",
+ }
+}
+
+SENSEHIDDEN = add_spell
+{
+ ["name"] = "Sense Hidden",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 5,
+ ["mana"] = 2,
+ ["mana_max"] = 10,
+ ["fail"] = 25,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 15 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 20,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 10, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ local obvious = nil
+ obvious = detect_traps(15 + get_level(SENSEHIDDEN, 40, 0))
+ if get_level(SENSEHIDDEN, 50) >= 15 then
+ obvious = is_obvious(set_tim_invis(10 + randint(20) + get_level(SENSEHIDDEN, 40)), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ if get_level(SENSEHIDDEN, 50) >= 15 then
+ return "rad "..(15 + get_level(SENSEHIDDEN, 40)).." dur "..(10 + get_level(SENSEHIDDEN, 40)).."+d20"
+ else
+ return "rad "..(15 + get_level(SENSEHIDDEN, 40))
+ end
+ end,
+ ["desc"] = {
+ "Detects the traps in a certain radius around you",
+ "At level 15 it allows you to sense invisible for a while"
+ }
+}
+
+REVEALWAYS = add_spell
+{
+ ["name"] = "Reveal Ways",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 9,
+ ["mana"] = 3,
+ ["mana_max"] = 15,
+ ["fail"] = 20,
+ ["stick"] =
+ {
+ ["charge"] = { 6, 6 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 35,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ local obvious
+ obvious = detect_doors(10 + get_level(REVEALWAYS, 40, 0))
+ obvious = is_obvious(detect_stairs(10 + get_level(REVEALWAYS, 40, 0)), obvious)
+ return obvious
+ end,
+ ["info"] = function()
+ return "rad "..(10 + get_level(REVEALWAYS, 40))
+ end,
+ ["desc"] = {
+ "Detects the doors/stairs/ways in a certain radius around you",
+ }
+}
+
+SENSEMONSTERS = add_spell
+{
+ ["name"] = "Sense Monsters",
+ ["school"] = {SCHOOL_DIVINATION},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 20,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 10 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 37,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 15, 40 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ local obvious
+ obvious = detect_monsters_normal(10 + get_level(SENSEMONSTERS, 40, 0))
+ if get_level(SENSEMONSTERS, 50) >= 30 then
+ obvious = is_obvious(set_tim_esp(10 + randint(10) + get_level(SENSEMONSTERS, 20)), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ if get_level(SENSEMONSTERS, 50) >= 30 then
+ return "rad "..(10 + get_level(SENSEMONSTERS, 40)).." dur "..(10 + get_level(SENSEMONSTERS, 20)).."+d10"
+ else
+ return "rad "..(10 + get_level(SENSEMONSTERS, 40))
+ end
+ end,
+ ["desc"] = {
+ "Detects all monsters near you",
+ "At level 30 it allows you to sense monster minds for a while"
+ }
+}
diff --git a/lib/scpt/s_earth.lua b/lib/scpt/s_earth.lua
new file mode 100644
index 00000000..23aa001c
--- /dev/null
+++ b/lib/scpt/s_earth.lua
@@ -0,0 +1,184 @@
+-- The earth school
+
+STONESKIN = add_spell
+{
+ ["name"] = "Stone Skin",
+ ["school"] = SCHOOL_EARTH,
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 50,
+ ["fail"] = 10,
+ ["inertia"] = { 2, 50 },
+ ["spell"] = function()
+ local type
+ if get_level(STONESKIN, 50) >= 25 then
+ type = SHIELD_COUNTER
+ else
+ type = 0
+ end
+ return set_shield(randint(10) + 10 + get_level(STONESKIN, 100), 10 + get_level(STONESKIN, 50), type, 2 + get_level(STONESKIN, 5), 3 + get_level(STONESKIN, 5))
+ end,
+ ["info"] = function()
+ if get_level(STONESKIN, 50) >= 25 then
+ return "dam "..(2 + get_level(STONESKIN, 5)).."d"..(3 + get_level(STONESKIN, 5)).." dur "..(10 + get_level(STONESKIN, 100)).."+d10 AC "..(10 + get_level(STONESKIN, 50))
+ else
+ return "dur "..(10 + get_level(STONESKIN, 100)).."+d10 AC "..(10 + get_level(STONESKIN, 50))
+ end
+ end,
+ ["desc"] = {
+ "Creates a shield of earth around you to protect you",
+ "At level 25 it starts dealing damage to attackers"
+ }
+}
+
+DIG = add_spell
+{
+ ["name"] = "Dig",
+ ["school"] = SCHOOL_EARTH,
+ ["level"] = 12,
+ ["mana"] = 14,
+ ["mana_max"] = 14,
+ ["fail"] = 20,
+ ["stick"] =
+ {
+ ["charge"] = { 15, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 25,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return wall_to_mud(dir)
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Digs a hole in a wall much faster than any shovels",
+ }
+}
+
+STONEPRISON = add_spell
+{
+ ["name"] = "Stone Prison",
+ ["school"] = SCHOOL_EARTH,
+ ["level"] = 25,
+ ["mana"] = 30,
+ ["mana_max"] = 50,
+ ["fail"] = 65,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 3 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 57,
+ ["base_level"] = { 1, 3 },
+ ["max_level"] = { 5, 20 },
+ },
+ },
+ ["spell"] = function()
+ local ret, x, y
+ if get_level(STONEPRISON, 50) >= 10 then
+ ret, x, y = tgt_pt()
+ else
+ y = player.py
+ x = player.px
+ end
+ wall_stone(y, x)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Creates a prison of walls around you",
+ "At level 10 it allows you to target a monster"
+ }
+}
+
+STRIKE = add_spell
+{
+ ["name"] = "Strike",
+ ["school"] = {SCHOOL_EARTH},
+ ["level"] = 30,
+ ["mana"] = 30,
+ ["mana_max"] = 50,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 6 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 635,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 10, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir, rad
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ if get_level(STRIKE, 50) >= 12 then
+ return fire_ball(GF_FORCE, dir, 50 + get_level(STRIKE, 50), 1)
+ else
+ return fire_ball(GF_FORCE, dir, 50 + get_level(STRIKE, 50), 0)
+ end
+ end,
+ ["info"] = function()
+ if get_level(STRIKE, 50) >= 12 then
+ return "dam "..(50 + get_level(STRIKE, 50)).." rad 1"
+ else
+ return "dam "..(50 + get_level(STRIKE, 50))
+ end
+ end,
+ ["desc"] = {
+ "Creates a micro-ball of force that will push monsters backwards",
+ "If the monster is caught near a wall, it'll be crushed against it",
+ "At level 12 it turns into a ball of radius 1"
+ }
+}
+
+SHAKE = add_spell
+{
+ ["name"] = "Shake",
+ ["school"] = {SCHOOL_EARTH},
+ ["level"] = 27,
+ ["mana"] = 25,
+ ["mana_max"] = 30,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 10 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 75,
+ ["base_level"] = { 1, 3 },
+ ["max_level"] = { 9, 20 },
+ },
+ },
+ ["inertia"] = { 2, 50 },
+ ["spell"] = function()
+ local ret, x, y
+ if get_level(SHAKE, 50) >= 10 then
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ else
+ x = player.px
+ y = player.py
+ end
+ earthquake(y, x, 4 + get_level(SHAKE, 10));
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(4 + get_level(SHAKE, 10))
+ end,
+ ["desc"] = {
+ "Creates a localised earthquake",
+ "At level 10 it can be targeted at any location"
+ }
+}
diff --git a/lib/scpt/s_eru.lua b/lib/scpt/s_eru.lua
new file mode 100644
index 00000000..c0cb0aaf
--- /dev/null
+++ b/lib/scpt/s_eru.lua
@@ -0,0 +1,130 @@
+-- Handle Eru Iluvatar magic school
+
+ERU_SEE = add_spell
+{
+ ["name"] = "See the Music",
+ ["school"] = {SCHOOL_ERU},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 50,
+ ["fail"] = 20,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local obvious
+ obvious = set_tim_invis(randint(20) + 10 + get_level(ERU_SEE, 100))
+ if get_level(ERU_SEE) >= 30 then
+ wiz_lite_extra()
+ obvious = TRUE
+ elseif get_level(ERU_SEE) >= 10 then
+ map_area()
+ obvious = TRUE
+ end
+ if get_level(ERU_SEE) >= 20 then
+ obvious = is_obvious(set_blind(0), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(ERU_SEE, 100)).."+d20"
+ end,
+ ["desc"] = {
+ "Allows you to 'see' the Great Music from which the world",
+ "originates, allowing you to see unseen things",
+ "At level 10 it allows you to see your surroundings",
+ "At level 20 it allows you to cure blindness",
+ "At level 30 it allows you to fully see all the level"
+ }
+}
+
+ERU_LISTEN = add_spell
+{
+ ["name"] = "Listen to the Music",
+ ["school"] = {SCHOOL_ERU},
+ ["level"] = 7,
+ ["mana"] = 15,
+ ["mana_max"] = 200,
+ ["fail"] = 25,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ if get_level(ERU_LISTEN) >= 30 then
+ ident_all()
+ identify_pack()
+ return TRUE
+ elseif get_level(ERU_LISTEN) >= 14 then
+ identify_pack()
+ return TRUE
+ else
+ return ident_spell()
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Allows you to listen to the Great Music from which the world",
+ "originates, allowing you to understand the meaning of things",
+ "At level 14 it allows you to identify all your pack",
+ "At level 30 it allows you to identify all items on the level",
+ }
+}
+
+ERU_UNDERSTAND = add_spell
+{
+ ["name"] = "Know the Music",
+ ["school"] = {SCHOOL_ERU},
+ ["level"] = 30,
+ ["mana"] = 200,
+ ["mana_max"] = 600,
+ ["fail"] = 50,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ if get_level(ERU_UNDERSTAND) >= 10 then
+ identify_pack_fully()
+ return TRUE
+ else
+ return identify_fully()
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Allows you to understand the Great Music from which the world",
+ "originates, allowing you to know the full abilities of things",
+ "At level 10 it allows you to *identify* all your pack",
+ }
+}
+
+ERU_PROT = add_spell
+{
+ ["name"] = "Lay of Protection",
+ ["school"] = {SCHOOL_ERU},
+ ["level"] = 35,
+ ["mana"] = 400,
+ ["mana_max"] = 400,
+ ["fail"] = 80,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return fire_ball(GF_MAKE_GLYPH, 0, 1, 1 + get_level(ERU_PROT, 2, 0))
+ end,
+ ["info"] = function()
+ return "rad "..(1 + get_level(ERU_PROT, 2, 0))
+ end,
+ ["desc"] = {
+ "Creates a circle of safety around you",
+ }
+}
diff --git a/lib/scpt/s_fire.lua b/lib/scpt/s_fire.lua
new file mode 100644
index 00000000..dbbf7604
--- /dev/null
+++ b/lib/scpt/s_fire.lua
@@ -0,0 +1,227 @@
+-- handle the fire school
+
+GLOBELIGHT = add_spell
+{
+ ["name"] = "Globe of Light",
+ ["school"] = {SCHOOL_FIRE},
+ ["level"] = 1,
+ ["mana"] = 2,
+ ["mana_max"] = 15,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 7,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 10, 45 },
+ },
+ },
+ ["inertia"] = { 1, 40 },
+ ["spell"] = function()
+ local obvious
+ if get_level(GLOBELIGHT, 50) >= 3 then
+ obvious = lite_area(10, 4)
+ else
+ lite_room(player.py, player.px)
+ obvious = TRUE
+ end
+ if get_level(GLOBELIGHT, 50) >= 15 then
+ obvious = is_obvious(fire_ball(GF_LITE, 0, 10 + get_level(GLOBELIGHT, 100), 5 + get_level(GLOBELIGHT, 6)), obvious)
+ player.update = bor(player.update, PU_VIEW)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ if get_level(GLOBELIGHT, 50) >= 15 then
+ return "dam "..(10 + get_level(GLOBELIGHT, 100)).." rad "..(5 + get_level(GLOBELIGHT, 6))
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Creates a globe of pure light",
+ "At level 3 it starts damaging monsters",
+ "At level 15 it starts creating a more powerful kind of light",
+ }
+}
+
+FIREFLASH = add_spell
+{
+ ["name"] = "Fireflash",
+ ["school"] = {SCHOOL_FIRE},
+ ["level"] = 10,
+ ["mana"] = 5,
+ ["mana_max"] = 70,
+ ["fail"] = 35,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 35,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 15, 35 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir, type
+ if (get_level(FIREFLASH, 50) >= 20) then
+ type = GF_HOLY_FIRE
+ else
+ type = GF_FIRE
+ end
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(type, dir, 20 + get_level(FIREFLASH, 500), 2 + get_level(FIREFLASH, 5))
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(FIREFLASH, 500)).." rad "..(2 + get_level(FIREFLASH, 5))
+ end,
+ ["desc"] = {
+ "Conjures a ball of fire to burn your foes to ashes",
+ "At level 20 it turns into a ball of holy fire"
+ }
+}
+
+FIERYAURA = add_spell
+{
+ ["name"] = "Fiery Shield",
+ ["school"] = {SCHOOL_FIRE},
+ ["level"] = 20,
+ ["mana"] = 20,
+ ["mana_max"] = 60,
+ ["fail"] = 50,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 50,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 5, 40 },
+ },
+ },
+ ["inertia"] = { 2, 15 },
+ ["spell"] = function()
+ local type
+ if (get_level(FIERYAURA, 50) >= 8) then
+ type = SHIELD_GREAT_FIRE
+ else
+ type = SHIELD_FIRE
+ end
+ return set_shield(randint(20) + 10 + get_level(FIERYAURA, 70), 10, type, 5 + get_level(FIERYAURA, 10), 5 + get_level(FIERYAURA, 7))
+ end,
+ ["info"] = function()
+ return "dam "..(5 + get_level(FIERYAURA, 15)).."d"..(5 + get_level(FIERYAURA, 7)).." dur "..(10 + get_level(FIERYAURA, 70)).."+d20"
+ end,
+ ["desc"] = {
+ "Creates a shield of fierce flames around you",
+ "At level 8 it turns into a greater kind of flame that can not be resisted"
+ }
+}
+
+FIREWALL = add_spell
+{
+ ["name"] = "Firewall",
+ ["school"] = {SCHOOL_FIRE},
+ ["level"] = 15,
+ ["mana"] = 25,
+ ["mana_max"] = 100,
+ ["fail"] = 40,
+ ["stick"] =
+ {
+ ["charge"] = { 4, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 55,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 5, 40 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir, type
+ if (get_level(FIREWALL, 50) >= 6) then
+ type = GF_HELL_FIRE
+ else
+ type = GF_FIRE
+ end
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ fire_wall(type, dir, 40 + get_level(FIREWALL, 150), 10 + get_level(FIREWALL, 14))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(40 + get_level(FIREWALL, 150)).." dur "..(10 + get_level(FIREWALL, 14))
+ end,
+ ["desc"] = {
+ "Creates a fiery wall to incinerate monsters stupid enough to attack you",
+ "At level 6 it turns into a wall of hell fire"
+ }
+}
+
+FIREGOLEM = add_spell
+{
+ ["name"] = "Fire Golem",
+ ["school"] = {SCHOOL_FIRE, SCHOOL_MIND},
+ ["level"] = 7,
+ ["mana"] = 16,
+ ["mana_max"] = 70,
+ ["fail"] = 40,
+ ["spell"] = function()
+ local m_idx, y, x, ret, item
+
+ -- Can we reconnect ?
+ if do_control_reconnect() == TRUE then
+ msg_print("Control re-established.")
+ return
+ end
+
+ ret, item = get_item("Which light source do you want to use to create the golem?",
+ "You have no light source for the golem",
+ bor(USE_INVEN, USE_EQUIP),
+ function (obj)
+ if (obj.tval == TV_LITE) and ((obj.sval == SV_LITE_TORCH) or (obj.sval == SV_LITE_LANTERN)) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+ if ret == FALSE then return TRUE end
+ inven_item_increase(item, -1)
+ inven_item_describe(item)
+ inven_item_optimize(item)
+
+ -- Summon it
+ m_allow_special[1043 + 1] = TRUE
+ y, x = find_position(player.py, player.px)
+ m_idx = place_monster_one(y, x, 1043, 0, FALSE, MSTATUS_FRIEND)
+ m_allow_special[1043 + 1] = FALSE
+
+ -- level it
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 7 + get_level(FIREGOLEM, 70))
+ player.control = m_idx
+ monster(m_idx).mflag = bor(monster(m_idx).mflag, MFLAG_CONTROL)
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return "golem level "..(7 + get_level(FIREGOLEM, 70))
+ end,
+ ["desc"] = {
+ "Creates a fiery golem and controls it",
+ "During the control the available keylist is:",
+ "Movement keys: movement of the golem(depending on its speed",
+ " it can move more than one square)",
+ ", : pickup all items on the floor",
+ "d : drop all carried items",
+ "i : list all carried items",
+ "m : end the possession/use golem powers",
+ "Most of the other keys are disabled, you cannot interact with your",
+ "real body while controlling the golem",
+ "But to cast the spell you will need a lantern or a wooden torch to",
+ "Create the golem from"
+ }
+}
diff --git a/lib/scpt/s_geom.lua b/lib/scpt/s_geom.lua
new file mode 100644
index 00000000..b9730318
--- /dev/null
+++ b/lib/scpt/s_geom.lua
@@ -0,0 +1,656 @@
+-- Geomancy school
+
+function geomancy_random_wall(y, x)
+ local c_ptr = cave(y, x)
+
+ -- Do not destroy permanent things
+ if cave_is(c_ptr, FF1_PERMANENT) ~= FALSE then return end
+
+ local feat = nil
+ local table =
+ {
+ [1] = { SKILL_FIRE, FEAT_SANDWALL, 1},
+
+ [2] = { SKILL_WATER, FEAT_TREES, 1},
+ [3] = { SKILL_WATER, FEAT_ICE_WALL, 12},
+
+ [4] = { SKILL_EARTH, FEAT_WALL_EXTRA, 1},
+ }
+
+ while feat == nil do
+ local t = table[randint(getn(table))]
+
+ -- Do we meet the requirements ?
+ -- And then select the features based on skill proportions
+ if get_skill(t[1]) >= t[3] and magik(get_skill_scale(t[1], 100)) == TRUE then
+ feat = t[2]
+ end
+ end
+
+ cave_set_feat(y, x, feat)
+end
+
+
+GF_ELEMENTAL_WALL = add_spell_type
+{
+ ["color"] = { TERM_GREEN, 0 },
+ ["angry"] = function() return TRUE, FALSE end,
+ ["grid"] = function(who, dam, rad, y, x)
+ if player.py ~= y or player.px ~= x then
+ geomancy_random_wall(y, x)
+ end
+ end,
+}
+
+function geomancy_random_floor(y, x, kill_wall)
+ local c_ptr = cave(y, x)
+
+ -- Do not destroy permanent things
+ if cave_is(c_ptr, FF1_PERMANENT) ~= FALSE then return end
+ if not kill_wall then
+ if cave_is(c_ptr, FF1_FLOOR) ~= TRUE then return end
+ end
+
+ local feat = nil
+ local table =
+ {
+ [1] = { SKILL_FIRE, FEAT_SAND, 1},
+ [2] = { SKILL_FIRE, FEAT_SHAL_LAVA, 8},
+ [3] = { SKILL_FIRE, FEAT_DEEP_LAVA, 18},
+
+ [4] = { SKILL_WATER, FEAT_SHAL_WATER, 1},
+ [5] = { SKILL_WATER, FEAT_DEEP_WATER, 8},
+ [6] = { SKILL_WATER, FEAT_ICE, 18},
+
+ [7] = { SKILL_EARTH, FEAT_GRASS, 1},
+ [8] = { SKILL_EARTH, FEAT_FLOWER, 8},
+ [9] = { SKILL_EARTH, FEAT_DARK_PIT, 18},
+ }
+
+ while feat == nil do
+ local t = table[randint(getn(table))]
+
+ -- Do we meet the requirements ?
+ -- And then select the features based on skill proportions
+ if get_skill(t[1]) >= t[3] and magik(get_skill_scale(t[1], 100)) == TRUE then
+ feat = t[2]
+ end
+ end
+
+ cave_set_feat(y, x, feat)
+end
+
+
+GF_ELEMENTAL_GROWTH = add_spell_type
+{
+ ["color"] = { TERM_GREEN, 0 },
+ ["angry"] = function() return TRUE, FALSE end,
+ ["grid"] = function(who, dam, rad, y, x)
+ geomancy_random_floor(y, x)
+ end,
+}
+
+CALL_THE_ELEMENTS = add_spell
+{
+ ["name"] = "Call the Elements",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 1,
+ ["mana"] = 2,
+ ["mana_max"] = 20,
+ ["fail"] = 10,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir = 0, 0
+
+ if get_level(CALL_THE_ELEMENTS) >= 17 then
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ end
+
+ fire_ball(GF_ELEMENTAL_GROWTH, dir, 1, 1 + get_level(CALL_THE_ELEMENTS, 5, 0))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(1 + get_level(CALL_THE_ELEMENTS, 5, 0))
+ end,
+ ["desc"] = {
+ "Randomly creates various elements around you",
+ "Each type of element chance is controlled by your level",
+ "in the corresponding skill",
+ "At level 17 it can be targeted",
+ }
+}
+
+-- Seperate function because an other spell needs it
+function channel_the_elements(y, x, level, silent)
+ local t =
+ {
+ -- Earth stuff
+ [FEAT_GRASS] = function()
+ hp_player(player.mhp * (5 + get_skill_scale(SKILL_EARTH, 20)) / 100)
+ end,
+ [FEAT_FLOWER] = function()
+ hp_player(player.mhp * (5 + get_skill_scale(SKILL_EARTH, 30)) / 100)
+ end,
+ [FEAT_DARK_PIT] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ local type = GF_DARK
+ if get_skill(SKILL_EARTH) >= 18 then type = GF_NETHER end
+ fire_bolt(type, dir, damroll(10, get_skill(SKILL_EARTH)))
+ end,
+
+ -- Water stuff
+ [FEAT_SHAL_WATER] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ local type = GF_WATER
+ if get_skill(SKILL_WATER) >= 18 then type = GF_WAVE end
+
+ if get_skill(SKILL_WATER) >= 8 then
+ fire_beam(type, dir, damroll(3, get_skill(SKILL_WATER)))
+ else
+ fire_bolt(type, dir, damroll(3, get_skill(SKILL_WATER)))
+ end
+ end,
+ [FEAT_DEEP_WATER] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ local type = GF_WATER
+ if get_skill(SKILL_WATER) >= 18 then type = GF_WAVE end
+
+ if get_skill(SKILL_WATER) >= 8 then
+ fire_beam(type, dir, damroll(5, get_skill(SKILL_WATER)))
+ else
+ fire_bolt(type, dir, damroll(5, get_skill(SKILL_WATER)))
+ end
+ end,
+ [FEAT_ICE] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if get_skill(SKILL_WATER) >= 12 then
+ fire_ball(GF_ICE, dir, get_skill_scale(SKILL_WATER, 340), 3)
+ else
+ fire_bolt(GF_ICE, dir, damroll(3, get_skill(SKILL_WATER)))
+ end
+ end,
+
+ -- Fire stuff
+ [FEAT_SAND] = function()
+ local type
+ if (get_level(FIERYAURA, 50) >= 8) then
+ type = SHIELD_GREAT_FIRE
+ else
+ type = SHIELD_FIRE
+ end
+ local dur = randint(20) + %level + get_skill(SKILL_AIR)
+ set_shield(dur, 0, type, 5 + get_skill_scale(SKILL_FIRE, 20), 5 + get_skill_scale(SKILL_FIRE, 14))
+ set_blind(dur)
+ end,
+ [FEAT_SHAL_LAVA] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if get_skill(SKILL_FIRE) >= 15 then
+ fire_bolt(GF_HELL_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15))
+ else
+ fire_bolt(GF_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15))
+ end
+ end,
+ [FEAT_DEEP_LAVA] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if get_skill(SKILL_FIRE) >= 15 then
+ fire_ball(GF_HELL_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15), 3)
+ else
+ fire_ball(GF_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15), 3)
+ end
+ end,
+ }
+
+ if t[cave(y, x).feat] then
+ t[cave(y, x).feat]()
+
+ if magik(100 - level) == TRUE then
+ if cave(y, x).feat == FEAT_FLOWER then
+ cave_set_feat(y, x, FEAT_GRASS)
+ else
+ cave_set_feat(y, x, FEAT_FLOOR)
+ end
+ msg_print("The area is drained.")
+ end
+ elseif not silent then
+ msg_print("You cannot channel this area.")
+ end
+end
+
+CHANNEL_ELEMENTS = add_spell
+{
+ ["name"] = "Channel Elements",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 3,
+ ["mana"] = 3,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ ["spell"] = function()
+ channel_the_elements(player.py, player.px, get_level(CHANNEL_ELEMENTS), nil)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Draws on the caster's immediate environs to form an attack or other effect.",
+ "Grass/Flower heals.",
+ "Water creates water bolt attacks.",
+ "Ice creates ice bolt attacks.",
+ "Sand creates a wall of thick, blinding, burning sand around you.",
+ "Lava creates fire bolt attacks.",
+ "Deep lava creates fire ball attacks.",
+ "Chasm creates darkness bolt attacks.",
+ "At Earth level 18, darkness becomes nether.",
+ "At Water level 8, water attacks become beams with a striking effect.",
+ "At Water level 12, ice attacks become balls of ice shards.",
+ "At Water level 18, water attacks push monsters back.",
+ "At Fire level 15, fire become hellfire.",
+ }
+}
+
+ELEMENTAL_WAVE = add_spell
+{
+ ["name"] = "Elemental Wave",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 15,
+ ["mana"] = 15,
+ ["mana_max"] = 50,
+ ["fail"] = 20,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ ["spell"] = function()
+ local ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+
+ local y, x = explode_dir(dir)
+ y = y + player.py
+ x = x + player.px
+
+ local t =
+ {
+ -- Earth stuff
+ [FEAT_GRASS] = { GF_POIS, GF_POIS, 10 + get_skill_scale(SKILL_EARTH, 200) },
+ [FEAT_FLOWER] = { GF_POIS, GF_POIS, 10 + get_skill_scale(SKILL_EARTH, 300) },
+ -- cannot turn chasm into a wave
+
+ -- Water stuff
+ [FEAT_SHAL_WATER] = { GF_WATER, GF_WATER, 10 + get_skill_scale(SKILL_WATER, 200) },
+ [FEAT_DEEP_WATER] = { GF_WATER, GF_WATER, 10 + get_skill_scale(SKILL_WATER, 300) },
+ [FEAT_ICE] = { GF_ICE, GF_ICE, 10 + get_skill_scale(SKILL_WATER, 200) },
+
+ -- Fire stuff
+ [FEAT_SAND] = { GF_LITE, GF_LITE, 10 + get_skill_scale(SKILL_FIRE, 400) },
+ [FEAT_SHAL_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 10 + get_skill_scale(SKILL_FIRE, 200) },
+ [FEAT_DEEP_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 10 + get_skill_scale(SKILL_FIRE, 300) },
+ }
+
+
+ local effect = t[cave(y, x).feat]
+ if not effect then
+ msg_print("You cannot channel this area.")
+ else
+ local typ = effect[1]
+ if get_level(ELEMENTAL_WAVE) >= 20 then typ = effect[2] end
+
+ cave_set_feat(y, x, FEAT_FLOOR)
+
+ fire_wave(typ, 0, effect[3], 0, 6 + get_level(ELEMENTAL_WAVE, 20), EFF_WAVE + EFF_LAST + getglobal("EFF_DIR"..dir))
+ end
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Draws on an adjacent special square to project a slow-moving",
+ "wave of that element in that direction",
+ "Abyss squares cannot be channeled into a wave.",
+ }
+}
+
+VAPORIZE = add_spell
+{
+ ["name"] = "Vaporize",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 4,
+ ["mana"] = 3,
+ ["mana_max"] = 30,
+ ["fail"] = 15,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ -- Must have at least 4 Air
+ ["random"] = 0,
+ ["depend"] = function()
+ if get_skill(SKILL_AIR) >= 4 then return TRUE end
+ end,
+ ["spell"] = function()
+ local t =
+ {
+ -- Earth stuff
+ [FEAT_GRASS] = { GF_POIS, GF_POIS, 5 + get_skill_scale(SKILL_EARTH, 100) },
+ [FEAT_FLOWER] = { GF_POIS, GF_POIS, 5 + get_skill_scale(SKILL_EARTH, 150) },
+ [FEAT_DARK_PIT] = { GF_DARK, GF_DARK, 5 + get_skill_scale(SKILL_EARTH, 200) },
+
+ -- Water stuff
+ [FEAT_SHAL_WATER] = { GF_WATER, GF_WATER, 5 + get_skill_scale(SKILL_WATER, 100) },
+ [FEAT_DEEP_WATER] = { GF_WATER, GF_WATER, 5 + get_skill_scale(SKILL_WATER, 150) },
+ [FEAT_ICE] = { GF_ICE, GF_ICE, 5 + get_skill_scale(SKILL_WATER, 100) },
+
+ -- Fire stuff
+ [FEAT_SAND] = { GF_LITE, GF_LITE, 5 + get_skill_scale(SKILL_FIRE, 200) },
+ [FEAT_SHAL_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 5 + get_skill_scale(SKILL_FIRE, 100) },
+ [FEAT_DEEP_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 5 + get_skill_scale(SKILL_FIRE, 150) },
+ }
+
+ local effect = t[cave(player.py, player.px).feat]
+ if not effect then
+ msg_print("You cannot channel this area.")
+ else
+ local typ = effect[1]
+ if get_level(VAPORIZE) >= 20 then typ = effect[2] end
+
+ cave_set_feat(player.py, player.px, FEAT_FLOOR)
+
+ fire_cloud(typ, 0, effect[3], 1 + get_level(VAPORIZE, 4), 10 + get_level(VAPORIZE, 20))
+ end
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(1 + get_level(VAPORIZE, 4)).." dur "..(10 + get_level(VAPORIZE, 20))
+ end,
+ ["desc"] = {
+ "Draws upon your immediate environs to form a cloud of damaging vapors",
+ }
+}
+
+geomancy_can_tunnel =
+{
+ [FEAT_WALL_EXTRA] = TRUE,
+ [FEAT_WALL_OUTER] = TRUE,
+ [FEAT_WALL_INNER] = TRUE,
+ [FEAT_WALL_SOLID] = TRUE,
+
+ [FEAT_MAGMA] = TRUE,
+ [FEAT_QUARTZ] = TRUE,
+ [FEAT_MAGMA_H] = TRUE,
+ [FEAT_QUARTZ_H] = TRUE,
+ [FEAT_MAGMA_K] = TRUE,
+ [FEAT_QUARTZ_K] = TRUE,
+
+ [FEAT_TREES] = TRUE,
+ [FEAT_DEAD_TREE] = TRUE,
+
+ [FEAT_SANDWALL] = TRUE,
+ [FEAT_SANDWALL_H] = TRUE,
+ [FEAT_SANDWALL_K] = TRUE,
+
+ [FEAT_ICE_WALL] = TRUE,
+}
+
+-- Dig & sprew
+function geomancy_dig(oy, ox, dir, length)
+ local dy, dx = explode_dir(dir)
+ local y = dy + oy
+ local x = dx + ox
+
+ for i = 1, length do
+ local c_ptr = cave(y, x)
+ local ox = x - dx
+ local oy = y - dy
+
+ -- stop at the end of tunnelable things
+ if not geomancy_can_tunnel[c_ptr.feat] then break end
+
+ if geomancy_can_tunnel[cave(y - 1, x - 1).feat] then geomancy_random_wall(y - 1, x - 1) end
+ if geomancy_can_tunnel[cave(y - 1, x).feat] then geomancy_random_wall(y - 1, x) end
+ if geomancy_can_tunnel[cave(y - 1, x + 1).feat] then geomancy_random_wall(y - 1, x + 1) end
+
+ if geomancy_can_tunnel[cave(y, x - 1).feat] then geomancy_random_wall(y, x - 1) end
+ if geomancy_can_tunnel[cave(y, x + 1).feat] then geomancy_random_wall(y, x + 1) end
+
+ if geomancy_can_tunnel[cave(y + 1, x - 1).feat] then geomancy_random_wall(y + 1, x - 1) end
+ if geomancy_can_tunnel[cave(y + 1, x).feat] then geomancy_random_wall(y + 1, x) end
+ if geomancy_can_tunnel[cave(y + 1, x + 1).feat] then geomancy_random_wall(y + 1, x + 1) end
+
+ y = y + dy
+ x = x + dx
+ end
+
+ y = y - dy
+ x = x - dx
+ while (y ~= oy) or (x ~= ox) do
+ geomancy_random_floor(y, x, TRUE)
+
+ -- Should we branch ?
+ if magik(20) == TRUE then
+ local rot = 1
+ if magik(50) == TRUE then rot = -1 end
+ geomancy_dig(y, x, rotate_dir(dir, rot), length / 3)
+ end
+
+ y = y - dy
+ x = x - dx
+ end
+end
+
+GEOLYSIS = add_spell
+{
+ ["name"] = "Geolysis",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 7,
+ ["mana"] = 15,
+ ["mana_max"] = 40,
+ ["fail"] = 15,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ -- Must have at least 7 Earth
+ ["depend"] = function()
+ if get_skill(SKILL_EARTH) >= 7 then return TRUE end
+ end,
+ ["spell"] = function()
+ local ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+
+ msg_print("Elements recombine before you, laying down an open path.")
+ geomancy_dig(player.py, player.px, dir, 5 + get_level(GEOLYSIS, 12))
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return "length "..(5 + get_level(GEOLYSIS, 12))
+ end,
+ ["desc"] = {
+ "Burrows deeply and slightly at random into a wall,",
+ "leaving behind tailings of various different sorts of walls in the passage.",
+ }
+}
+
+player.dripping_tread = 0
+add_loadsave("player.dripping_tread", 0)
+add_hooks
+{
+ [HOOK_MOVED] = function(oy, ox)
+ if player.dripping_tread > 0 then
+ geomancy_random_floor(oy, ox)
+ player.dripping_tread = player.dripping_tread - 1
+ if player.dripping_tread == 0 then
+ msg_print("You stop dripping raw elemental energies.")
+ end
+ end
+ end
+}
+DRIPPING_TREAD = add_spell
+{
+ ["name"] = "Dripping Tread",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 10,
+ ["mana"] = 15,
+ ["mana_max"] = 25,
+ ["fail"] = 15,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ -- Must have at least 10 Water
+ ["depend"] = function()
+ if get_skill(SKILL_WATER) >= 10 then return TRUE end
+ end,
+ ["spell"] = function()
+ if player.dripping_tread == 0 then
+ player.dripping_tread = randint(15) + 10 + get_level(DRIPPING_TREAD)
+ msg_print("You start dripping raw elemental energies.")
+ else
+ player.dripping_tread = 0
+ msg_print("You stop dripping raw elemental energies.")
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(DRIPPING_TREAD)).."+d15 movs"
+ end,
+ ["desc"] = {
+ "Causes you to leave random elemental forms behind as you walk",
+ }
+}
+
+GROW_BARRIER = add_spell
+{
+ ["name"] = "Grow Barrier",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 12,
+ ["mana"] = 30,
+ ["mana_max"] = 40,
+ ["fail"] = 15,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ ["random"] = 0,
+ -- Must have at least 12 Earth
+ ["depend"] = function()
+ if get_skill(SKILL_EARTH) >= 12 then return TRUE end
+ end,
+ ["spell"] = function()
+ local ret, dir = 0, 0
+
+ if get_level(GROW_BARRIER) >= 20 then
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ end
+
+ fire_ball(GF_ELEMENTAL_WALL, dir, 1, 1)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Creates impassable terrain (walls, trees, etc.) around you.",
+ "At level 20 it can be projected around another area.",
+ }
+}
+
+ELEMENTAL_MINION = add_spell
+{
+ ["name"] = "Elemental Minion",
+ ["school"] = {SCHOOL_GEOMANCY},
+ ["level"] = 20,
+ ["mana"] = 40,
+ ["mana_max"] = 80,
+ ["fail"] = 25,
+ -- Unnafected by blindness
+ ["random"] = 0,
+ -- Must have at least 12 Earth
+ ["spell"] = function()
+ local ret, dir = 0, 0
+
+ ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+
+ local t =
+ {
+ [FEAT_WALL_EXTRA] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_WALL_OUTER] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_WALL_INNER] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_WALL_SOLID] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_MAGMA] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_QUARTZ] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_MAGMA_H] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_QUARTZ_H] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_MAGMA_K] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+ [FEAT_QUARTZ_K] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } },
+
+ [FEAT_DARK_PIT] = { SKILL_AIR, { "Air elemental", "Ancient blue dragon", "Great Storm Wyrm", "Sky Drake" } },
+
+ [FEAT_SANDWALL] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+ [FEAT_SANDWALL_H] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+ [FEAT_SANDWALL_K] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+ [FEAT_SHAL_LAVA] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+ [FEAT_DEEP_LAVA] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } },
+
+ [FEAT_ICE_WALL] = { SKILL_WATER, { "Water elemental", "Water troll", "Water demon" } },
+ [FEAT_SHAL_WATER] = { SKILL_WATER, { "Water elemental", "Water troll", "Water demon" } },
+ [FEAT_DEEP_WATER] = { SKILL_WATER, { "Water elemental", "Water troll", "Water demon" } },
+ }
+
+ local y, x = explode_dir(dir)
+ y = y + player.py
+ x = x + player.px
+
+ local effect = t[cave(y, x).feat]
+ if not effect then
+ msg_print("You cannot summon from this area.")
+ else
+ local skill = effect[1]
+ local types = effect[2]
+
+ local max = get_skill_scale(skill, getn(types))
+ if max == 0 then max = 1 end
+
+ local r_idx = test_monster_name(types[rand_range(1, max)])
+
+ -- Summon it
+ local my, mx = find_position(y, x)
+ local m_idx = place_monster_one(my, mx, r_idx, 0, FALSE, MSTATUS_FRIEND)
+
+ -- level it
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 10 + get_level(ELEMENTAL_MINION, 120))
+ end
+
+ cave_set_feat(y, x, FEAT_FLOOR)
+ end
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return "min level "..(10 + get_level(ELEMENTAL_MINION, 120))
+ end,
+ ["desc"] = {
+ "Summons a minion from a nearby element.",
+ "Walls can summon Earth elmentals, Xorns and Xarens",
+ "Dark Pits can summon Air elementals, Ancient blue dragons, Great Storm Wyrms",
+ "and Sky Drakes",
+ "Sandwalls and lava can summon Fire elementals and Ancient red dragons",
+ "Icewall, and water can summon Water elementals, Water trolls and Water demons",
+ }
+}
diff --git a/lib/scpt/s_mana.lua b/lib/scpt/s_mana.lua
new file mode 100644
index 00000000..736b06b0
--- /dev/null
+++ b/lib/scpt/s_mana.lua
@@ -0,0 +1,132 @@
+-- The mana school
+
+function get_manathrust_dam()
+ return 3 + get_level(MANATHRUST, 50), 1 + get_level(MANATHRUST, 20)
+end
+
+MANATHRUST = add_spell
+{
+ ["name"] = "Manathrust",
+ ["school"] = SCHOOL_MANA,
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 25,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 10 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 5,
+ ["base_level"] = { 1, 20 },
+ ["max_level"] = { 15, 33 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt(GF_MANA, dir, damroll(get_manathrust_dam()))
+ end,
+ ["info"] = function()
+ local x, y
+
+ x, y = get_manathrust_dam()
+ return "dam "..x.."d"..y
+ end,
+ ["desc"] = {
+ "Conjures up mana into a powerful bolt",
+ "The damage is irresistible and will increase with level"
+ }
+}
+
+DELCURSES = add_spell
+{
+ ["name"] = "Remove Curses",
+ ["school"] = SCHOOL_MANA,
+ ["level"] = 10,
+ ["mana"] = 20,
+ ["mana_max"] = 40,
+ ["fail"] = 30,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 8 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 70,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 15, 50 },
+ },
+ },
+ ["inertia"] = { 1, 10 },
+ ["spell"] = function()
+ local done
+
+ if get_level(DELCURSES, 50) >= 20 then done = remove_all_curse()
+ else done = remove_curse() end
+ if done == TRUE then msg_print("The curse is broken!") end
+ return done
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Remove curses of worn objects",
+ "At level 20 switches to *remove curses*"
+ }
+}
+
+RESISTS = add_spell
+{
+ ["name"] = "Elemental Shield",
+ ["school"] = SCHOOL_MANA,
+ ["level"] = 20,
+ ["mana"] = 17,
+ ["mana_max"] = 20,
+ ["fail"] = 40,
+ ["inertia"] = { 2, 25 },
+ ["spell"] = function()
+ local obvious
+ if player.oppose_fire == 0 then obvious = set_oppose_fire(randint(10) + 15 + get_level(RESISTS, 50)) end
+ if player.oppose_cold == 0 then obvious = is_obvious(set_oppose_cold(randint(10) + 15 + get_level(RESISTS, 50)), obvious) end
+ if player.oppose_elec == 0 then obvious = is_obvious(set_oppose_elec(randint(10) + 15 + get_level(RESISTS, 50)), obvious) end
+ if player.oppose_acid == 0 then obvious = is_obvious(set_oppose_acid(randint(10) + 15 + get_level(RESISTS, 50)), obvious) end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(15 + get_level(RESISTS, 50)).."+d10"
+ end,
+ ["desc"] = {
+ "Provide resistances to the four basic elements",
+ }
+}
+
+MANASHIELD = add_spell
+{
+ ["name"] = "Disruption Shield",
+ ["school"] = SCHOOL_MANA,
+ ["level"] = 45,
+ ["mana"] = 50,
+ ["mana_max"] = 50,
+ ["fail"] = 90,
+ ["inertia"] = { 9, 10},
+ ["spell"] = function()
+ if get_level(MANASHIELD, 50) >= 5 then
+ if (player.invuln == 0) then
+ return set_invuln(randint(5) + 3 + get_level(MANASHIELD, 10))
+ end
+ else
+ if (player.disrupt_shield == 0) then return set_disrupt_shield(randint(5) + 3 + get_level(MANASHIELD, 10)) end
+ end
+ end,
+ ["info"] = function()
+ return "dur "..(3 + get_level(MANASHIELD, 10)).."+d5"
+ end,
+ ["desc"] = {
+ "Uses mana instead of hp to take damage",
+ "At level 5 switches to Globe of Invulnerability.",
+ "The spell breaks as soon as a melee, shooting, throwing or magical",
+ "skill action is attempted, and lasts only a short time."
+ }
+}
diff --git a/lib/scpt/s_manwe.lua b/lib/scpt/s_manwe.lua
new file mode 100644
index 00000000..6f0f9661
--- /dev/null
+++ b/lib/scpt/s_manwe.lua
@@ -0,0 +1,144 @@
+-- Handle Manwe Sulimo magic school
+
+MANWE_SHIELD = add_spell
+{
+ ["name"] = "Wind Shield",
+ ["school"] = {SCHOOL_MANWE},
+ ["level"] = 10,
+ ["mana"] = 100,
+ ["mana_max"] = 500,
+ ["fail"] = 30,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local dur = get_level(MANWE_SHIELD, 50) + 10 + randint(20)
+ local obvious
+
+ obvious = set_protevil(dur)
+ if get_level(MANWE_SHIELD) >= 10 then
+ local type
+
+ type = 0
+ if get_level(MANWE_SHIELD) >= 20 then
+ type = SHIELD_COUNTER
+ end
+ obvious = is_obvious(set_shield(dur, get_level(MANWE_SHIELD, 30), type, 1 + get_level(MANWE_SHIELD, 2), 1 + get_level(MANWE_SHIELD, 6)), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ local desc = "dur "..(get_level(MANWE_SHIELD, 50) + 10).."+d20"
+
+ if get_level(MANWE_SHIELD) >= 10 then
+ desc = desc.." AC "..(get_level(MANWE_SHIELD, 30))
+ end
+ if get_level(MANWE_SHIELD) >= 20 then
+ desc = desc.." dam "..(1 + get_level(MANWE_SHIELD, 2)).."d"..(1 + get_level(MANWE_SHIELD, 6))
+ end
+ return desc
+ end,
+ ["desc"] = {
+ "It surrounds you with a shield of wind that deflects blows from evil monsters",
+ "At level 10 it increases your armour rating",
+ "At level 20 it retaliates against monsters that melee you",
+ }
+}
+
+MANWE_AVATAR = add_spell
+{
+ ["name"] = "Avatar",
+ ["school"] = {SCHOOL_MANWE},
+ ["level"] = 35,
+ ["mana"] = 1000,
+ ["mana_max"] = 1000,
+ ["fail"] = 80,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return set_mimic(get_level(MANWE_AVATAR, 20) + randint(10), resolve_mimic_name("Maia"), player.lev)
+ end,
+ ["info"] = function()
+ return "dur "..(get_level(MANWE_AVATAR, 20)).."+d10"
+ end,
+ ["desc"] = {
+ "It turns you into a full grown Maia",
+ }
+}
+
+MANWE_BLESS = add_spell
+{
+ ["name"] = "Manwe's Blessing",
+ ["school"] = {SCHOOL_MANWE},
+ ["level"] = 1,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 20,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local dur = get_level(MANWE_BLESS, 70) + 30 + randint(40)
+ local obvious
+
+ obvious = set_blessed(dur)
+ obvious = is_obvious(set_afraid(0), obvious)
+ obvious = is_obvious(set_lite(0), obvious)
+ if get_level(MANWE_BLESS) >= 10 then
+ obvious = is_obvious(set_hero(dur), obvious)
+ end
+ if get_level(MANWE_BLESS) >= 20 then
+ obvious = is_obvious(set_shero(dur), obvious)
+ end
+ if get_level(MANWE_BLESS) >= 30 then
+ obvious = is_obvious(set_holy(dur), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(get_level(MANWE_BLESS, 70) + 30).."+d40"
+ end,
+ ["desc"] = {
+ "Manwe's Blessing removes your fears, blesses you and surrounds you with",
+ "holy light",
+ "At level 10 it also grants heroism",
+ "At level 20 it also grants super heroism",
+ "At level 30 it also grants holy luck and life protection",
+ }
+}
+
+MANWE_CALL = add_spell
+{
+ ["name"] = "Manwe's Call",
+ ["school"] = {SCHOOL_MANWE},
+ ["level"] = 20,
+ ["mana"] = 200,
+ ["mana_max"] = 500,
+ ["fail"] = 40,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local y, x, m_idx
+
+ y, x = find_position(player.py, player.px)
+ m_idx = place_monster_one(y, x, test_monster_name("Great eagle"), 0, FALSE, MSTATUS_FRIEND)
+
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 20 + get_level(MANWE_CALL, 70, 0))
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return "level "..(get_level(MANWE_CALL, 70) + 20)
+ end,
+ ["desc"] = {
+ "Manwe's Call summons a Great Eagle to help you battle the forces",
+ "of Morgoth"
+ }
+}
diff --git a/lib/scpt/s_melkor.lua b/lib/scpt/s_melkor.lua
new file mode 100644
index 00000000..b2c693dd
--- /dev/null
+++ b/lib/scpt/s_melkor.lua
@@ -0,0 +1,154 @@
+-- handle the melkor school
+
+-- Not included in the spell code directly because I need to call it from somewhere else too
+function do_melkor_curse(who)
+ local m_ptr = monster(who)
+
+ if get_level(MELKOR_CURSE) >= 35 then
+ local r_ptr = race_info_idx(m_ptr.r_idx, m_ptr.ego)
+
+ m_ptr.maxhp = m_ptr.maxhp - r_ptr.hside;
+ if m_ptr.maxhp < 1 then m_ptr.maxhp = 1 end
+ if m_ptr.hp > m_ptr.maxhp then m_ptr.hp = m_ptr.maxhp end
+ player.redraw = bor(player.redraw, PR_HEALTH)
+ end
+ if get_level(MELKOR_CURSE) >= 25 then
+ m_ptr.speed = m_ptr.speed - get_level(MELKOR_CURSE, 7)
+ m_ptr.mspeed = m_ptr.mspeed - get_level(MELKOR_CURSE, 7)
+
+ if m_ptr.speed < 70 then m_ptr.speed = 70 end
+ if m_ptr.mspeed < 70 then m_ptr.mspeed = 70 end
+ end
+ if get_level(MELKOR_CURSE) >= 15 then
+ m_ptr.ac = m_ptr.ac - get_level(MELKOR_CURSE, 50)
+
+ if m_ptr.ac < -70 then m_ptr.ac = -70 end
+ end
+
+ local i, pow
+ i = 1
+ pow = get_level(MELKOR_CURSE, 2)
+ while (i <= 4) do
+ if m_ptr.blow[i].d_dice > 0 then
+ if m_ptr.blow[i].d_dice < pow then
+ pow = m_ptr.blow[i].d_dice
+ end
+ if m_ptr.blow[i].d_side < pow then
+ pow = m_ptr.blow[i].d_side
+ end
+ m_ptr.blow[i].d_dice = m_ptr.blow[i].d_dice - pow
+ end
+ i = i + 1
+ end
+
+ local m_name = monster_desc(m_ptr, 0).." looks weaker."
+ msg_print(strupper(strsub(m_name, 0, 1))..strsub(m_name, 2))
+
+ -- wake it
+ m_ptr.csleep = 0;
+end
+
+MELKOR_CURSE = add_spell
+{
+ ["name"] = "Curse",
+ ["school"] = {SCHOOL_MELKOR},
+ ["level"] = 1,
+ ["mana"] = 50,
+ ["mana_max"] = 300,
+ ["fail"] = 20,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if target_who == -1 then
+ msg_print("You must target a monster.")
+ else
+ do_melkor_curse(target_who)
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "It curses a monster, reducing its melee power",
+ "At level 5 it can be auto-casted (with no piety cost) while fighting",
+ "At level 15 it also reduces armor",
+ "At level 25 it also reduces speed",
+ "At level 35 it also reduces max life (but it is never fatal)",
+ }
+}
+
+MELKOR_CORPSE_EXPLOSION = add_spell
+{
+ ["name"] = "Corpse Explosion",
+ ["school"] = {SCHOOL_MELKOR},
+ ["level"] = 10,
+ ["mana"] = 100,
+ ["mana_max"] = 500,
+ ["fail"] = 45,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return fire_ball(GF_CORPSE_EXPL, 0, 20 + get_level(MELKOR_CORPSE_EXPLOSION, 70), 2 + get_level(MELKOR_CORPSE_EXPLOSION, 5))
+ end,
+ ["info"] = function()
+ return "dam "..(20 + get_level(MELKOR_CORPSE_EXPLOSION, 70)).."%"
+ end,
+ ["desc"] = {
+ "It makes corpses in an area around you explode for a percent of their",
+ "hit points as damage",
+ }
+}
+
+MELKOR_MIND_STEAL = add_spell
+{
+ ["name"] = "Mind Steal",
+ ["school"] = {SCHOOL_MELKOR},
+ ["level"] = 20,
+ ["mana"] = 1000,
+ ["mana_max"] = 3000,
+ ["fail"] = 90,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ if target_who == -1 then
+ msg_print("You must target a monster.")
+ else
+ local chance, m_ptr, r_ptr
+
+ m_ptr = monster(target_who)
+ r_ptr = race_info_idx(m_ptr.r_idx, m_ptr.ego)
+ chance = get_level(MELKOR_MIND_STEAL)
+ if (randint(m_ptr.level) < chance) and (band(r_ptr.flags1, RF1_UNIQUE) == 0) then
+ player.control = target_who
+ m_ptr.mflag = bor(m_ptr.mflag, MFLAG_CONTROL)
+
+ local m_name = monster_desc(m_ptr, 0).." falls under your control."
+ msg_print(strupper(strsub(m_name, 0, 1))..strsub(m_name, 2))
+ else
+ local m_name = monster_desc(m_ptr, 0).." resists."
+ msg_print(strupper(strsub(m_name, 0, 1))..strsub(m_name, 2))
+ end
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return "chance 1d(mlvl)<"..(get_level(MELKOR_MIND_STEAL))
+ end,
+ ["desc"] = {
+ "It allows your spirit to temporarily leave your own body, which will",
+ "be vulnerable, to control one of your enemies body."
+ }
+}
diff --git a/lib/scpt/s_meta.lua b/lib/scpt/s_meta.lua
new file mode 100644
index 00000000..eab691d8
--- /dev/null
+++ b/lib/scpt/s_meta.lua
@@ -0,0 +1,287 @@
+-- handle the meta school
+
+RECHARGE = add_spell
+{
+ ["name"] = "Recharge",
+ ["school"] = {SCHOOL_META},
+ ["level"] = 5,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 20,
+ ["spell"] = function()
+ return recharge(60 + get_level(RECHARGE, 140))
+ end,
+ ["info"] = function()
+ return "power "..(60 + get_level(RECHARGE, 140))
+ end,
+ ["desc"] = {
+ "Taps on the ambient mana to recharge an object's power (charges or mana)",
+ }
+}
+
+function get_spellbinder_max()
+ local i
+
+ i = get_level(SPELLBINDER, 4)
+ if i > 4 then i = 4 end
+ return i
+end
+--'
+SPELLBINDER = add_spell
+{
+ ["name"] = "Spellbinder",
+ ["school"] = {SCHOOL_META},
+ ["level"] = 20,
+ ["mana"] = 100,
+ ["mana_max"] = 300,
+ ["fail"] = 85,
+ ["spell"] = function()
+ local i, ret, c
+
+ if player.spellbinder_num ~= 0 then
+ local t =
+ {
+ [SPELLBINDER_HP75] = "75% HP",
+ [SPELLBINDER_HP50] = "50% HP",
+ [SPELLBINDER_HP25] = "25% HP",
+ }
+ msg_print("The spellbinder is already active.")
+ msg_print("It will trigger at "..t[player.spellbinder_trigger]..".")
+ msg_print("With the spells: ")
+ for i = 1, player.spellbinder_num do
+ msg_print(spell(player.spellbinder[i]).name)
+ end
+ return TRUE
+ end
+
+ ret, c = get_com("Trigger at [a]75% hp [b]50% hp [c]25% hp?", strbyte("a"))
+ if ret == FALSE then return TRUE end
+
+ if c == strbyte("a") then
+ player.spellbinder_trigger = SPELLBINDER_HP75
+ elseif c == strbyte("b") then
+ player.spellbinder_trigger = SPELLBINDER_HP50
+ elseif c == strbyte("c") then
+ player.spellbinder_trigger = SPELLBINDER_HP25
+ else
+ return
+ end
+ player.spellbinder_num = get_spellbinder_max()
+ i = player.spellbinder_num
+ while i > 0 do
+ local s
+
+ s = get_school_spell("bind", "is_ok_spell", 0)
+ if s == -1 then
+ player.spellbinder_trigger = 0
+ player.spellbinder_num = 0
+ return TRUE
+ else
+ if spell(s).skill_level > 7 + get_level(SPELLBINDER, 35) then
+ msg_print("You are only allowed spells with a base level of "..(7 + get_level(SPELLBINDER, 35))..".");
+ return TRUE
+ end
+ end
+ player.spellbinder[i] = s
+ i = i - 1
+ end
+ player.energy = player.energy - 3100;
+ msg_print("Spellbinder ready.")
+ return TRUE
+ end,
+ ["info"] = function()
+ return "number "..(get_spellbinder_max()).." max level "..(7 + get_level(SPELLBINDER, 35))
+ end,
+ ["desc"] = {
+ "Stores spells in a trigger.",
+ "When the condition is met all spells fire off at the same time",
+ "This spell takes a long time to cast so you are advised to prepare it",
+ "in a safe area.",
+ "Also it will use the mana for the Spellbinder and the mana for the",
+ "selected spells"
+ }
+}
+
+DISPERSEMAGIC = add_spell
+{
+ ["name"] = "Disperse Magic",
+ ["school"] = {SCHOOL_META},
+ ["level"] = 15,
+ ["mana"] = 30,
+ ["mana_max"] = 60,
+ ["fail"] = 40,
+ -- Unnafected by blindness
+ ["blind"] = FALSE,
+ -- Unnafected by confusion
+ ["confusion"] = FALSE,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 25,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 5, 40 },
+ },
+ },
+ ["inertia"] = { 1, 5 },
+ ["spell"] = function()
+ local obvious
+ obvious = set_blind(0)
+ obvious = is_obvious(set_lite(0), obvious)
+ if get_level(DISPERSEMAGIC, 50) >= 5 then
+ obvious = is_obvious(set_confused(0), obvious)
+ obvious = is_obvious(set_image(0), obvious)
+ end
+ if get_level(DISPERSEMAGIC, 50) >= 10 then
+ obvious = is_obvious(set_slow(0), obvious)
+ obvious = is_obvious(set_fast(0, 0), obvious)
+ obvious = is_obvious(set_light_speed(0), obvious)
+ end
+ if get_level(DISPERSEMAGIC, 50) >= 15 then
+ obvious = is_obvious(set_stun(0), obvious)
+ obvious = is_obvious(set_meditation(0), obvious)
+ obvious = is_obvious(set_cut(0), obvious)
+ end
+ if get_level(DISPERSEMAGIC, 50) >= 20 then
+ obvious = is_obvious(set_hero(0), obvious)
+ obvious = is_obvious(set_shero(0), obvious)
+ obvious = is_obvious(set_blessed(0), obvious)
+ obvious = is_obvious(set_shield(0, 0, 0, 0, 0), obvious)
+ obvious = is_obvious(set_afraid(0), obvious)
+ obvious = is_obvious(set_parasite(0, 0), obvious)
+ obvious = is_obvious(set_mimic(0, 0, 0), obvious)
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Dispels a lot of magic that can affect you, be it good or bad",
+ "Level 1: blindness and light",
+ "Level 5: confusion and hallucination",
+ "Level 10: speed (both bad or good) and light speed",
+ "Level 15: stunning, meditation, cuts",
+ "Level 20: hero, super hero, bless, shields, afraid, parasites, mimicry",
+ }
+}
+
+TRACKER = add_spell
+{
+ ["name"] = "Tracker",
+ ["school"] = {SCHOOL_META, SCHOOL_CONVEYANCE},
+ ["level"] = 30,
+ ["mana"] = 50,
+ ["mana_max"] = 50,
+ ["fail"] = 95,
+ ["spell"] = function()
+ if last_teleportation_y == -1 then
+ msg_print("There has not been any teleporatation here.")
+ return TRUE
+ end
+ teleport_player_to(last_teleportation_y, last_teleportation_x)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Tracks down the last teleportation that happened on the level and teleports",
+ "you to it",
+ }
+}
+
+-- Saves the values of the timer
+save_timer("TIMER_INERTIA_CONTROL")
+add_loadsave("player.inertia_controlled_spell", -1)
+player.inertia_controlled_spell = -1
+
+-- Automatically cast the inertia controlled spells
+TIMER_INERTIA_CONTROL = new_timer
+{
+ ["enabled"] = FALSE,
+ ["delay"] = 10,
+ ["callback"] = function()
+ -- Don't cast a controlled spell in wilderness mode
+ if player.antimagic then
+ msg_print("Your anti-magic field disrupts any magic attempts.")
+ elseif player.anti_magic then
+ msg_print("Your anti-magic shell disrupts any magic attempts.")
+ elseif (player.inertia_controlled_spell ~= -1) and (player.wild_mode == FALSE) then
+ __spell_spell[player.inertia_controlled_spell]()
+ end
+ end,
+}
+
+stop_inertia_controlled_spell = function()
+ player.inertia_controlled_spell = -1
+ TIMER_INERTIA_CONTROL.enabled = FALSE
+ player.update = bor(player.update, PU_MANA)
+ return TRUE
+end
+
+add_hooks
+{
+ -- Reduce the mana by four times the cost of the spell
+ [HOOK_CALC_MANA] = function(msp)
+ if player.inertia_controlled_spell ~= -1 then
+ msp = msp - (get_mana(player.inertia_controlled_spell) * 4)
+ if msp < 0 then msp = 0 end
+ return TRUE, msp
+ end
+ end,
+
+ -- Stop a previous spell at birth
+ [HOOK_BIRTH_OBJECTS] = function()
+ stop_inertia_controlled_spell()
+ end,
+}
+
+INERTIA_CONTROL = add_spell
+{
+ ["name"] = "Inertia Control",
+ ["school"] = {SCHOOL_META},
+ ["level"] = 37,
+ ["mana"] = 300,
+ ["mana_max"] = 700,
+ ["fail"] = 95,
+ ["spell"] = function()
+ if player.inertia_controlled_spell ~= -1 then
+ msg_print("You cancel your inertia flow control.")
+ return stop_inertia_controlled_spell()
+ end
+
+ local s = get_school_spell("control", "is_ok_spell", 0)
+ if s == -1 then
+ return stop_inertia_controlled_spell()
+ end
+
+ local inertia = __tmp_spells[s].inertia
+
+ if inertia == nil then
+ msg_print("This spell inertia flow can not be controlled.")
+ return stop_inertia_controlled_spell()
+ end
+ if inertia[1] > get_level(INERTIA_CONTROL, 10) then
+ msg_print("This spell inertia flow("..inertia[1]..") is too strong to be controlled by your current spell.")
+ return stop_inertia_controlled_spell()
+ end
+
+ player.inertia_controlled_spell = s
+ TIMER_INERTIA_CONTROL.enabled = TRUE
+ TIMER_INERTIA_CONTROL.delay = inertia[2]
+ TIMER_INERTIA_CONTROL.countdown = TIMER_INERTIA_CONTROL.delay
+ player.update = bor(player.update, PU_MANA)
+ msg_print("Inertia flow controlling spell "..spell(s).name..".")
+ return TRUE
+ end,
+ ["info"] = function()
+ return "level "..get_level(INERTIA_CONTROL, 10)
+ end,
+ ["desc"] = {
+ "Changes the energy flow of a spell to be continuously recasted",
+ "at a given interval. The inertia controlled spell reduces your",
+ "maximum mana by four times its cost.",
+ }
+}
diff --git a/lib/scpt/s_mind.lua b/lib/scpt/s_mind.lua
new file mode 100644
index 00000000..d1b25e9e
--- /dev/null
+++ b/lib/scpt/s_mind.lua
@@ -0,0 +1,132 @@
+-- handle the mind school
+
+CHARM = add_spell
+{
+ ["name"] = "Charm",
+ ["school"] = {SCHOOL_MIND},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 20,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 35,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 20, 40 },
+ },
+ },
+ ["spell"] = function()
+ if get_level(CHARM, 50) >= 35 then
+ return project_los(GF_CHARM, 10 + get_level(CHARM, 150))
+ elseif get_level(CHARM, 50) >= 15 then
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_CHARM, dir, 10 + get_level(CHARM, 150), 3)
+ else
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt(GF_CHARM, dir, 10 + get_level(CHARM, 150))
+ end
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(CHARM, 150))
+ end,
+ ["desc"] = {
+ "Tries to manipulate the mind of a monster to make it friendly",
+ "At level 15 it turns into a ball",
+ "At level 35 it affects all monsters in sight"
+ }
+}
+
+CONFUSE = add_spell
+{
+ ["name"] = "Confuse",
+ ["school"] = {SCHOOL_MIND},
+ ["level"] = 5,
+ ["mana"] = 5,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 4 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 45,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 20, 40 },
+ },
+ },
+ ["spell"] = function()
+ if get_level(CONFUSE, 50) >= 35 then
+ return project_los(GF_OLD_CONF, 10 + get_level(CONFUSE, 150))
+ elseif get_level(CONFUSE, 50) >= 15 then
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_OLD_CONF, dir, 10 + get_level(CONFUSE, 150), 3)
+ else
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt(GF_OLD_CONF, dir, 10 + get_level(CONFUSE, 150))
+ end
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(CONFUSE, 150))
+ end,
+ ["desc"] = {
+ "Tries to manipulate the mind of a monster to confuse it",
+ "At level 15 it turns into a ball",
+ "At level 35 it affects all monsters in sight"
+ }
+}
+
+ARMOROFFEAR = add_spell
+{
+ ["name"] = "Armor of Fear",
+ ["school"] = SCHOOL_MIND,
+ ["level"] = 10,
+ ["mana"] = 10,
+ ["mana_max"] = 50,
+ ["fail"] = 35,
+ ["inertia"] = { 2, 20 },
+ ["spell"] = function()
+ return set_shield(randint(10) + 10 + get_level(ARMOROFFEAR, 100), 10, SHIELD_FEAR, 1 + get_level(ARMOROFFEAR, 7), 5 + get_level(ARMOROFFEAR, 20))
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(ARMOROFFEAR, 100)).." power "..(1 + get_level(ARMOROFFEAR, 7)).."d"..(5 + get_level(ARMOROFFEAR, 20))
+ end,
+ ["desc"] = {
+ "Creates a shield of pure fear around you. Any monster attempting to hit you",
+ "must save or flee",
+ }
+}
+
+STUN = add_spell
+{
+ ["name"] = "Stun",
+ ["school"] = {SCHOOL_MIND},
+ ["level"] = 15,
+ ["mana"] = 10,
+ ["mana_max"] = 90,
+ ["fail"] = 45,
+ ["spell"] = function()
+ if get_level(STUN, 50) >= 20 then
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_STUN, dir, 10 + get_level(STUN, 150), 3)
+ else
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt(GF_STUN, dir, 10 + get_level(STUN, 150))
+ end
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(STUN, 150))
+ end,
+ ["desc"] = {
+ "Tries to manipulate the mind of a monster to stun it",
+ "At level 20 it turns into a ball",
+ }
+}
diff --git a/lib/scpt/s_music.lua b/lib/scpt/s_music.lua
new file mode 100644
index 00000000..9da6393a
--- /dev/null
+++ b/lib/scpt/s_music.lua
@@ -0,0 +1,443 @@
+-- handle the music school
+-- *ALL* lasting spell must return the mana cost in the lasting function
+
+MUSIC_STOP = add_spell
+{
+ ["name"] = "Stop singing(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = -400,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["blind"] = FALSE,
+ ["spell"] = function()
+ player.start_lasting_spell(0)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Stops the current song, if any."
+ }
+}
+
+--- Drums
+MUSIC_HOLD = add_spell
+{
+ ["name"] = "Holding Pattern(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 10,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["blind"] = FALSE,
+ ["lasting"] = function()
+ project_los(GF_OLD_SLOW, 10 + get_level(MUSIC_HOLD, 100))
+ return get_mana(MUSIC_HOLD)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_HOLD)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(MUSIC_HOLD, 100))
+ end,
+ ["desc"] = {
+ "Slows down all monsters listening the song.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_CONF = add_spell
+{
+ ["name"] = "Illusion Pattern(II)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 5,
+ ["mana"] = 2,
+ ["mana_max"] = 15,
+ ["fail"] = 30,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 2,
+ ["blind"] = FALSE,
+ ["lasting"] = function()
+ project_los(GF_OLD_CONF, 10 + get_level(MUSIC_CONF, 100))
+ return get_mana(MUSIC_CONF)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_CONF)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(MUSIC_CONF, 100))
+ end,
+ ["desc"] = {
+ "Tries to confuse all monsters listening the song.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_STUN = add_spell
+{
+ ["name"] = "Stun Pattern(IV)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 10,
+ ["mana"] = 3,
+ ["mana_max"] = 25,
+ ["fail"] = 45,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 4,
+ ["blind"] = FALSE,
+ ["lasting"] = function()
+ project_los(GF_STUN, 10 + get_level(MUSIC_STUN, 90))
+ return get_mana(MUSIC_STUN)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_STUN)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(MUSIC_STUN, 90))
+ end,
+ ["desc"] = {
+ "Stuns all monsters listening the song.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+--- Harps
+MUSIC_LITE = add_spell
+{
+ ["name"] = "Song of the Sun(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 1,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["blind"] = FALSE,
+ ["pval"] = 1,
+ ["lasting"] = function()
+ set_lite(5)
+ return 1
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_LITE)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Provides light as long as you sing.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_HEAL = add_spell
+{
+ ["name"] = "Flow of Life(II)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 7,
+ ["mana"] = 5,
+ ["mana_max"] = 30,
+ ["fail"] = 35,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 2,
+ ["lasting"] = function()
+ hp_player(7 + get_level(MUSIC_HEAL, 100))
+ return get_mana(MUSIC_HEAL)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_HEAL)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "heal "..(7 + get_level(MUSIC_HEAL, 100)).."/turn"
+ end,
+ ["desc"] = {
+ "Heals you as long as you sing.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_HERO = add_spell
+{
+ ["name"] = "Heroic Ballad(II)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 10,
+ ["mana"] = 4,
+ ["mana_max"] = 14,
+ ["fail"] = 45,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 2,
+ ["lasting"] = function()
+ set_hero(5)
+ if get_level(MUSIC_HERO) >= 10 then
+ set_shero(5)
+ end
+ if get_level(MUSIC_HERO) >= 20 then
+ set_strike(5)
+ end
+ if get_level(MUSIC_HERO) >= 25 then
+ set_oppose_cc(5)
+ end
+ return get_mana(MUSIC_HERO)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_HERO)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Increases melee accuracy",
+ "At level 10 it increases it even more and reduces armour a bit",
+ "At level 20 it increases it again",
+ "At level 25 it grants protection against chaos and confusion",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_TIME = add_spell
+{
+ ["name"] = "Hobbit Melodies(III)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 20,
+ ["mana"] = 10,
+ ["mana_max"] = 30,
+ ["fail"] = 70,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 3,
+ ["lasting"] = function()
+ set_shield(5, 10 + get_level(MUSIC_TIME, 50), 0, 0, 0)
+ if get_level(MUSIC_TIME) >= 15 then
+ set_fast(5, 7 + get_level(MUSIC_TIME, 10))
+ end
+ return get_mana(MUSIC_TIME)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_TIME)
+ return TRUE
+ end,
+ ["info"] = function()
+ if get_level(MUSIC_TIME) >= 15 then
+ return "AC "..(10 + get_level(MUSIC_TIME, 50)).." speed "..(7 + get_level(MUSIC_TIME, 10))
+ else
+ return "AC "..(10 + get_level(MUSIC_TIME, 50))
+ end
+ end,
+ ["desc"] = {
+ "Greatly increases your reflexes allowing you to block more melee blows.",
+ "At level 15 it also makes you faster.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+MUSIC_MIND = add_spell
+{
+ ["name"] = "Clairaudience(IV)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 25,
+ ["mana"] = 15,
+ ["mana_max"] = 30,
+ ["fail"] = 75,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 4,
+ ["lasting"] = function()
+ set_tim_esp(5)
+ if get_level(MUSIC_MIND) >= 10 then
+ fire_ball(GF_IDENTIFY, 0, 1, 1 + get_level(MUSIC_MIND, 3, 0))
+ end
+ return get_mana(MUSIC_MIND)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_MIND)
+ return TRUE
+ end,
+ ["info"] = function()
+ if get_level(MUSIC_MIND) >= 10 then
+ return "rad "..(1 + get_level(MUSIC_MIND, 3, 0))
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Allows you to sense monster minds as long as you sing.",
+ "At level 10 it identifies all objects in a radius on the floor,",
+ "as well as probing monsters in that radius.",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+--- Horns
+
+MUSIC_BLOW = add_spell
+{
+ ["name"] = "Blow(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 4,
+ ["mana"] = 3,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["spell"] = function()
+ fire_ball(GF_SOUND,
+ 0,
+ damroll(2 + get_level(MUSIC_BLOW, 10, 0), 4 + get_level(MUSIC_BLOW, 40, 0)),
+ 1 + get_level(MUSIC_BLOW, 12, 0)
+ )
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(2 + get_level(MUSIC_BLOW, 10, 0)).."d"..(4 + get_level(MUSIC_BLOW, 40, 0)).." rad "..(1 + get_level(MUSIC_BLOW, 12, 0))
+ end,
+ ["desc"] = {
+ "Produces a powerful, blowing, sound all around you.",
+ }
+}
+
+MUSIC_WIND = add_spell
+{
+ ["name"] = "Gush of Wind(II)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 14,
+ ["mana"] = 15,
+ ["mana_max"] = 45,
+ ["fail"] = 30,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 2,
+ ["spell"] = function()
+ fire_ball(GF_AWAY_ALL,
+ 0,
+ 10 + get_level(MUSIC_BLOW, 40, 0),
+ 1 + get_level(MUSIC_BLOW, 12, 0)
+ )
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dist "..(10 + get_level(MUSIC_BLOW, 40, 0)).." rad "..(1 + get_level(MUSIC_BLOW, 12, 0))
+ end,
+ ["desc"] = {
+ "Produces a outgoing gush of wind that sends monsters away.",
+ }
+}
+
+MUSIC_YLMIR = add_spell
+{
+ ["name"] = "Horns of Ylmir(III)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 20,
+ ["mana"] = 25,
+ ["mana_max"] = 30,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 3,
+ ["spell"] = function()
+ earthquake(player.py, player.px, 2 + get_level(SHAKE, 10))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(2 + get_level(SHAKE, 10))
+ end,
+ ["desc"] = {
+ "Produces an earth shaking sound.",
+ }
+}
+
+MUSIC_AMBARKANTA = add_spell
+{
+ ["name"] = "Ambarkanta(IV)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 25,
+ ["mana"] = 70,
+ ["mana_max"] = 70,
+ ["fail"] = 60,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 4,
+ ["spell"] = function()
+ alter_reality()
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Produces a reality shaking sound that transports you to a nearly",
+ "identical reality.",
+ }
+}
+
+
+--[[
+MUSIC_ = add_spell
+{
+ ["name"] = "(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["lasting"] = function()
+ return get_mana(MUSIC_)
+ end,
+ ["spell"] = function()
+ player.start_lasting_spell(MUSIC_)
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "",
+ "Consumes the amount of mana each turn.",
+ }
+}
+
+or
+
+MUSIC_ = add_spell
+{
+ ["name"] = "(I)",
+ ["school"] = {SCHOOL_MUSIC},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 20,
+ ["stat"] = A_CHR,
+ ["random"] = SKILL_MUSIC,
+ ["pval"] = 1,
+ ["spell"] = function()
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "",
+ }
+}
+]]
diff --git a/lib/scpt/s_nature.lua b/lib/scpt/s_nature.lua
new file mode 100644
index 00000000..e71a89bf
--- /dev/null
+++ b/lib/scpt/s_nature.lua
@@ -0,0 +1,152 @@
+-- handle the nature school
+
+GROWTREE = add_spell
+{
+ ["name"] = "Grow Trees",
+ ["school"] = {SCHOOL_NATURE, SCHOOL_TEMPORAL},
+ ["level"] = 6,
+ ["mana"] = 6,
+ ["mana_max"] = 30,
+ ["fail"] = 35,
+ ["inertia"] = { 5, 50 },
+ ["spell"] = function()
+ grow_trees(2 + get_level(GROWTREE, 7))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(2 + get_level(GROWTREE, 7))
+ end,
+ ["desc"] = {
+ "Makes trees grow extremely quickly around you",
+ }
+}
+
+HEALING = add_spell
+{
+ ["name"] = "Healing",
+ ["school"] = {SCHOOL_NATURE},
+ ["level"] = 10,
+ ["mana"] = 15,
+ ["mana_max"] = 50,
+ ["fail"] = 45,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 3 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 90,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 20, 40 },
+ },
+ },
+ ["spell"] = function()
+ return hp_player(player.mhp * (15 + get_level(HEALING, 35)) / 100)
+ end,
+ ["info"] = function()
+ return "heal "..(15 + get_level(HEALING, 35)).."% = "..(player.mhp * (15 + get_level(HEALING, 35)) / 100).."hp"
+ end,
+ ["desc"] = {
+ "Heals a percent of hitpoints",
+ }
+}
+
+RECOVERY = add_spell
+{
+ ["name"] = "Recovery",
+ ["school"] = {SCHOOL_NATURE},
+ ["level"] = 15,
+ ["mana"] = 10,
+ ["mana_max"] = 25,
+ ["fail"] = 60,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 10 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 50,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 10, 30 },
+ },
+ },
+ ["inertia"] = { 2, 100 },
+ ["spell"] = function()
+ local obvious
+ obvious = set_poisoned(player.poisoned / 2)
+ if get_level(RECOVERY, 50) >= 5 then
+ obvious = is_obvious(set_poisoned(0), obvious)
+ obvious = is_obvious(set_cut(0), obvious)
+ end
+ if get_level(RECOVERY, 50) >= 10 then
+ obvious = is_obvious(do_res_stat(A_STR, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_CON, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_DEX, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_WIS, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_INT, TRUE), obvious)
+ obvious = is_obvious(do_res_stat(A_CHR, TRUE), obvious)
+ end
+ if get_level(RECOVERY, 50) >= 15 then
+ obvious = is_obvious(restore_level(), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Reduces the length of time that you are poisoned",
+ "At level 5 it cures poison and cuts",
+ "At level 10 it restores drained stats",
+ "At level 15 it restores lost experience"
+ }
+}
+
+REGENERATION = add_spell
+{
+ ["name"] = "Regeneration",
+ ["school"] = {SCHOOL_NATURE},
+ ["level"] = 20,
+ ["mana"] = 30,
+ ["mana_max"] = 55,
+ ["fail"] = 70,
+ ["inertia"] = { 4, 40 },
+ ["spell"] = function()
+ if player.tim_regen == 0 then return set_tim_regen(randint(10) + 5 + get_level(REGENERATION, 50), 300 + get_level(REGENERATION, 700)) end
+ end,
+ ["info"] = function()
+ return "dur "..(5 + get_level(REGENERATION, 50)).."+d10 power "..(300 + get_level(REGENERATION, 700))
+ end,
+ ["desc"] = {
+ "Increases your body's regeneration rate",
+ }
+}
+
+
+SUMMONANNIMAL = add_spell
+{
+ ["name"] = "Summon Animal",
+ ["school"] = {SCHOOL_NATURE},
+ ["level"] = 25,
+ ["mana"] = 25,
+ ["mana_max"] = 50,
+ ["fail"] = 90,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 3 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 85,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 15, 45 },
+ },
+ },
+ ["spell"] = function()
+ summon_specific_level = 25 + get_level(SUMMONANNIMAL, 50)
+ return summon_monster(player.py, player.px, dun_level, TRUE, SUMMON_ANIMAL)
+ end,
+ ["info"] = function()
+ return "level "..(25 + get_level(SUMMONANNIMAL, 50))
+ end,
+ ["desc"] = {
+ "Summons a leveled animal to your aid",
+ }
+}
diff --git a/lib/scpt/s_stick.lua b/lib/scpt/s_stick.lua
new file mode 100644
index 00000000..36647414
--- /dev/null
+++ b/lib/scpt/s_stick.lua
@@ -0,0 +1,444 @@
+-- Spells that are stick or artifacts/... only
+
+DEVICE_HEAL_MONSTER = add_spell
+{
+ ["name"] = "Heal Monster",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 3,
+ ["mana"] = 5,
+ ["mana_max"] = 20,
+ ["fail"] = 15,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 10 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 17,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ return fire_ball(GF_OLD_HEAL, dir, 20 + get_level(DEVICE_HEAL_MONSTER, 380), 0)
+ end,
+ ["info"] = function()
+ return "heal "..(20 + get_level(DEVICE_HEAL_MONSTER, 380))
+ end,
+ ["desc"] = {
+ "Heals a monster",
+ }
+}
+
+DEVICE_SPEED_MONSTER = add_spell
+{
+ ["name"] = "Haste Monster",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 10,
+ ["mana"] = 10,
+ ["mana_max"] = 10,
+ ["fail"] = 30,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 7,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ return fire_ball(GF_OLD_SPEED, dir, 1, 0)
+ end,
+ ["info"] = function()
+ return "speed +10"
+ end,
+ ["desc"] = {
+ "Haste a monster",
+ }
+}
+
+DEVICE_WISH = add_spell
+{
+ ["name"] = "Wish",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 50,
+ ["mana"] = 400,
+ ["mana_max"] = 400,
+ ["fail"] = 99,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 2 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 98,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1 },
+ },
+ },
+ ["spell"] = function()
+ make_wish()
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "This grants you a wish, beware of what you ask for!",
+ }
+}
+
+DEVICE_SUMMON = add_spell
+{
+ ["name"] = "Summon",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 5,
+ ["mana"] = 5,
+ ["mana_max"] = 25,
+ ["fail"] = 20,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 20 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 13,
+ ["base_level"] = { 1, 40 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["spell"] = function()
+ local i, obvious
+ obvious = nil
+ for i = 1, 4 + get_level(DEVICE_SUMMON, 30) do
+ obvious = is_obvious(summon_specific(player.py, player.px, dun_level, 0), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Summons hostile monsters near you",
+ }
+}
+
+DEVICE_MANA = add_spell
+{
+ ["name"] = "Mana",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 30,
+ ["mana"] = 1,
+ ["mana_max"] = 1,
+ ["fail"] = 80,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 3 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 78,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 20, 35 },
+ },
+ },
+ ["spell"] = function()
+ increase_mana((player.msp * (20 + get_level(DEVICE_MANA, 50))) / 100)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "restore "..(20 + get_level(DEVICE_MANA, 50)).."%"
+ end,
+ ["desc"] = {
+ "Restores a part(or all) of your mana",
+ }
+}
+
+DEVICE_NOTHING = add_spell
+{
+ ["name"] = "Nothing",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 0,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 0, 0 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 3,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1 },
+ },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 3,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1},
+ },
+ },
+ ["spell"] = function()
+ return FALSE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "It does nothing.",
+ }
+}
+
+DEVICE_LEBOHAUM = add_spell
+{
+ ["name"] = "Artifact Lebauhaum",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 0,
+ ["random"] = -1,
+ ["activate"] = 3,
+ ["spell"] = function()
+ msg_print("You hear a little song in your head in some unknown tongue:")
+ msg_print("'Avec le casque Lebohaum y a jamais d'anicroches, je parcours les dongeons,")
+ msg_print("j'en prend plein la caboche. Avec le casque Lebohaum, tout ces monstres a la")
+ msg_print("con, je leur met bien profond: c'est moi le maitre du dongeon!'")
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "sing a cheerful song",
+ }
+}
+
+DEVICE_MAGGOT = add_spell
+{
+ ["name"] = "Artifact Maggot",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 7,
+ ["mana_max"] = 7,
+ ["fail"] = 20,
+ ["random"] = -1,
+ ["activate"] = { 10, 50 },
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_ball(GF_TURN_ALL, dir, 40, 2)
+ end,
+ ["info"] = function()
+ return "power 40 rad 2"
+ end,
+ ["desc"] = {
+ "terrify",
+ }
+}
+
+DEVICE_HOLY_FIRE = add_spell
+{
+ ["name"] = "Holy Fire of Mithrandir",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 30,
+ ["mana"] = 50,
+ ["mana_max"] = 150,
+ ["fail"] = 75,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 5 },
+ [TV_STAFF] =
+ {
+ -- Rarity higher than 100 to be sure to not have it generated randomly
+ ["rarity"] = 999,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 35, 35 },
+ },
+ },
+ ["spell"] = function()
+ return project_los(GF_HOLY_FIRE, 50 + get_level(DEVICE_HOLY_FIRE, 300))
+ end,
+ ["info"] = function()
+ return "dam "..(50 + get_level(DEVICE_HOLY_FIRE, 250))
+ end,
+ ["desc"] = {
+ "The Holy Fire created by this staff will deeply(double damage) burn",
+ "all that is evil.",
+ }
+}
+
+-- Ok the Eternal Flame, to craete one of the 4 ultimate arts
+-- needed to enter the last level of the Void
+DEVICE_ETERNAL_FLAME = add_spell
+{
+ ["name"] = "Artifact Eternal Flame",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 0,
+ ["random"] = -1,
+ ["activate"] = { 0, 0 },
+ ["spell"] = function(flame_item)
+ local ret, item, obj
+
+ ret, item = get_item("Which object do you want to imbue?",
+ "You have no objects to imbue.",
+ bor(USE_INVEN),
+ function (obj)
+ if obj.name1 > 0 or obj.name2 > 0 then return FALSE end
+ if (obj.tval == TV_SWORD) and (obj.sval == SV_LONG_SWORD) then
+ return TRUE
+ elseif (obj.tval == TV_MSTAFF) and (obj.sval == SV_MSTAFF) then
+ return TRUE
+ elseif (obj.tval == TV_BOW) and (obj.sval == SV_HEAVY_XBOW) then
+ return TRUE
+ elseif (obj.tval == TV_DRAG_ARMOR) and (obj.sval == SV_DRAGON_POWER) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+ if ret == FALSE then return FALSE end
+
+ obj = get_object(item)
+
+ if (obj.tval == TV_SWORD) and (obj.sval == SV_LONG_SWORD) then
+ obj.name1 = 147
+ elseif (obj.tval == TV_MSTAFF) and (obj.sval == SV_MSTAFF) then
+ obj.name1 = 127
+ elseif (obj.tval == TV_BOW) and (obj.sval == SV_HEAVY_XBOW) then
+ obj.name1 = 152
+ elseif (obj.tval == TV_DRAG_ARMOR) and (obj.sval == SV_DRAGON_POWER) then
+ obj.name1 = 17
+ end
+ apply_magic(obj, -1, TRUE, TRUE, TRUE)
+
+ obj.found = OBJ_FOUND_SELFMADE
+
+ inven_item_increase(flame_item, -1)
+ inven_item_describe(flame_item)
+ inven_item_optimize(flame_item)
+
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Imbuing an object with the eternal fire",
+ }
+}
+
+-- And one more silly activation :)
+DEVICE_DURANDIL = add_spell
+{
+ ["name"] = "Artifact Durandil",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 0,
+ ["random"] = -1,
+ ["activate"] = 3,
+ ["spell"] = function()
+ msg_print("You hear a little song in your head in some unknown tongue:")
+ msg_print("'Les epees Durandils sont forgees dans les mines par des nains.")
+ msg_print("Avec ca c'est facile de tuer un troll avec une seule main. Pas besoin")
+ msg_print("de super entrainement nis de niveau 28. Quand tu sors l'instrument")
+ msg_print("c'est l'ennemi qui prend la fuite! Avec ton epee Durandil quand tu")
+ msg_print("parcours les chemins, tu massacre sans peine les brigands et les gobelins,")
+ msg_print("les rats geants, les ogres mutants, les zombies et les liches, tu les")
+ msg_print("decoupe en tranches comme si c'etait des parts de quiches.")
+ msg_print("Les epees Durandil! Les epees Durandil!")
+ msg_print("Quand tu la sort dans un dongeon au moins t'as pas l'air debile.")
+ msg_print("C'est l'arme des bourins qui savent etre subtils.")
+ msg_print("Ne partez pas a l'aventure sans votre epee Durandil!'")
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "sing a cheerful song",
+ }
+}
+
+DEVICE_THUNDERLORDS = add_spell
+{
+ ["name"] = "Artifact Thunderlords",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 1,
+ ["fail"] = 20,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 3 },
+ [TV_STAFF] =
+ {
+ -- Rarity higher than 100 to be sure to not have it generated randomly
+ ["rarity"] = 999,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 1, 1 },
+ },
+ },
+ ["spell"] = function()
+ if dun_level > 0 then
+ msg_print("As you blow the horn a thunderlord pops out of nowhere and grabs you.")
+ recall_player(0, 1)
+ else
+ msg_print("You cannot use it there.")
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "A thunderlord will appear to transport you quickly to the surface.",
+ }
+}
+
+--[[ Template
+DEVICE_ = add_spell
+{
+ ["name"] = "",
+ ["school"] = {SCHOOL_DEVICE},
+ ["level"] = 1,
+ ["mana"] = 2,
+ ["mana_max"] = 15,
+ ["fail"] = 10,
+ ["random"] = -1,
+ ["stick"] =
+ {
+ ["charge"] = { 10, 5 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 7,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 25, 50 },
+ },
+ },
+ ["spell"] = function()
+ return FALSE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "",
+ }
+}
+]]
diff --git a/lib/scpt/s_tempo.lua b/lib/scpt/s_tempo.lua
new file mode 100644
index 00000000..d3d2fbb5
--- /dev/null
+++ b/lib/scpt/s_tempo.lua
@@ -0,0 +1,162 @@
+-- Handles thhe temporal school
+
+
+MAGELOCK = add_spell
+{
+ ["name"] = "Magelock",
+ ["school"] = {SCHOOL_TEMPORAL},
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 35,
+ ["fail"] = 10,
+ ["stick"] =
+ {
+ ["charge"] = { 7, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 30,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 15, 45 },
+ },
+ },
+ ["spell"] = function()
+ if get_level(MAGELOCK, 50) >= 30 then
+ local ret, x, y, c_ptr
+
+ if get_level(MAGELOCK, 50) >= 40 then
+ ret, x, y = tgt_pt()
+ if ret == FALSE then return end
+ if cave_is(cave(y, x), FF1_FLOOR) == FALSE or cave_is(cave(y, x), FF1_PERMANENT) == TRUE or los(player.py, player.px, y, x) == FALSE then
+ msg_print("You cannot place it there.")
+ return TRUE
+ end
+ else
+ y = player.py
+ x = player.px
+ end
+ cave_set_feat(y, x, 3)
+ return TRUE
+ else
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return wizard_lock(dir)
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Magically locks a door",
+ "At level 30 it creates a glyph of warding",
+ "At level 40 the glyph can be placed anywhere in the field of vision"
+ }
+}
+
+SLOWMONSTER = add_spell
+{
+ ["name"] = "Slow Monster",
+ ["school"] = {SCHOOL_TEMPORAL},
+ ["level"] = 10,
+ ["mana"] = 10,
+ ["mana_max"] = 15,
+ ["fail"] = 35,
+ ["stick"] =
+ {
+ ["charge"] = { 5, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 23,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["spell"] = function()
+ local ret, dir
+
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ if get_level(SLOWMONSTER, 50) >= 20 then
+ return fire_ball(GF_OLD_SLOW, dir, 40 + get_level(SLOWMONSTER, 160), 1)
+ else
+ return fire_bolt(GF_OLD_SLOW, dir, 40 + get_level(SLOWMONSTER, 160))
+ end
+ end,
+ ["info"] = function()
+ if get_level(SLOWMONSTER, 50) >= 20 then
+ return "power "..(40 + get_level(SLOWMONSTER, 160)).." rad 1"
+ else
+ return "power "..(40 + get_level(SLOWMONSTER, 160))
+ end
+ end,
+ ["desc"] = {
+ "Magically slows down the passing of time around a monster",
+ "At level 20 it affects a zone"
+ }
+}
+
+ESSENCESPEED = add_spell
+{
+ ["name"] = "Essence of Speed",
+ ["school"] = {SCHOOL_TEMPORAL},
+ ["level"] = 15,
+ ["mana"] = 20,
+ ["mana_max"] = 40,
+ ["fail"] = 50,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 3 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 80,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 10, 39 },
+ },
+ },
+ ["inertia"] = { 5, 20 },
+ ["spell"] = function()
+ if player.fast == 0 then return set_fast(10 + randint(10) + get_level(ESSENCESPEED, 50), 5 + get_level(ESSENCESPEED, 20)) end
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(ESSENCESPEED, 50)).."+d10 speed "..(5 + get_level(ESSENCESPEED, 20))
+ end,
+ ["desc"] = {
+ "Magically decreases the passing of time around you, making you move faster with",
+ "respect to the rest of the universe."
+ }
+}
+
+BANISHMENT = add_spell
+{
+ ["name"] = "Banishment",
+ ["school"] = {SCHOOL_TEMPORAL, SCHOOL_CONVEYANCE},
+ ["level"] = 30,
+ ["mana"] = 30,
+ ["mana_max"] = 40,
+ ["fail"] = 95,
+ ["stick"] =
+ {
+ ["charge"] = { 1, 3 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 98,
+ ["base_level"] = { 1, 15 },
+ ["max_level"] = { 10, 36 },
+ },
+ },
+ ["inertia"] = { 5, 50 },
+ ["spell"] = function()
+ local obvious
+ obvious = project_los(GF_AWAY_ALL, 40 + get_level(BANISHMENT, 160))
+ if get_level(BANISHMENT, 50) >= 15 then
+ obvious = is_obvious(project_los(GF_STASIS, 20 + get_level(BANISHMENT, 120)), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return "power "..(40 + get_level(BANISHMENT, 160))
+ end,
+ ["desc"] = {
+ "Disrupts the space/time continuum in your area and teleports all monsters away.",
+ "At level 15 it may also lock them in a time bubble for a while."
+ }
+}
diff --git a/lib/scpt/s_tulkas.lua b/lib/scpt/s_tulkas.lua
new file mode 100644
index 00000000..4afa8082
--- /dev/null
+++ b/lib/scpt/s_tulkas.lua
@@ -0,0 +1,81 @@
+-- Handle Tulkas magic school
+
+TULKAS_AIM = add_spell
+{
+ ["name"] = "Divine Aim",
+ ["school"] = {SCHOOL_TULKAS},
+ ["level"] = 1,
+ ["mana"] = 30,
+ ["mana_max"] = 500,
+ ["fail"] = 20,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local dur = get_level(TULKAS_AIM, 50) + randint(10)
+ local obvious
+
+ obvious = set_strike(dur)
+ if get_level(TULKAS_AIM) >= 20 then
+ obvious = is_obvious(set_tim_deadly(dur), obvious)
+ end
+ return obvious
+ end,
+ ["info"] = function()
+ return "dur "..(get_level(TULKAS_AIM, 50)).."+d10"
+ end,
+ ["desc"] = {
+ "It makes you more accurate in combat",
+ "At level 20 all your blows are critical hits",
+ }
+}
+
+TULKAS_WAVE = add_spell
+{
+ ["name"] = "Wave of Power",
+ ["school"] = {SCHOOL_TULKAS},
+ ["level"] = 20,
+ ["mana"] = 200,
+ ["mana_max"] = 200,
+ ["fail"] = 75,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ return fire_bolt(GF_ATTACK, dir, get_level(TULKAS_WAVE, player.num_blow))
+ end,
+ ["info"] = function()
+ return "blows "..(get_level(TULKAS_WAVE, player.num_blow))
+ end,
+ ["desc"] = {
+ "It allows you to project a number of melee blows across a distance",
+ }
+}
+
+TULKAS_SPIN = add_spell
+{
+ ["name"] = "Whirlwind",
+ ["school"] = {SCHOOL_TULKAS},
+ ["level"] = 10,
+ ["mana"] = 100,
+ ["mana_max"] = 100,
+ ["fail"] = 45,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return fire_ball(GF_ATTACK, 0, 1, 1)
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "It allows you to spin around and hit all monsters nearby",
+ }
+}
diff --git a/lib/scpt/s_udun.lua b/lib/scpt/s_udun.lua
new file mode 100644
index 00000000..c4266239
--- /dev/null
+++ b/lib/scpt/s_udun.lua
@@ -0,0 +1,180 @@
+-- handle the udun school
+
+DRAIN = add_spell
+{
+ ["name"] = "Drain",
+ ["school"] = {SCHOOL_UDUN, SCHOOL_MANA},
+ ["level"] = 1,
+ ["mana"] = 0,
+ ["mana_max"] = 0,
+ ["fail"] = 20,
+ ["spell"] = function()
+ local ret, item, obj, o_name, add
+
+ -- Ask for an item
+ ret, item = get_item("What item to drain?", "You have nothing you can drain", USE_INVEN,
+ function (obj)
+ if (obj.tval == TV_WAND) or (obj.tval == TV_ROD_MAIN) or (obj.tval == TV_STAFF) then
+ return TRUE
+ end
+ return FALSE
+ end
+ )
+
+ if ret == TRUE then
+ -- get the item
+ obj = get_object(item)
+
+ add = 0
+ if (obj.tval == TV_STAFF) or (obj.tval == TV_WAND) then
+ local kind = get_kind(obj)
+
+ add = kind.level * obj.pval * obj.number
+
+ -- Destroy it!
+ inven_item_increase(item, -99)
+ inven_item_describe(item)
+ inven_item_optimize(item)
+ end
+ if obj.tval == TV_ROD_MAIN then
+ add = obj.timeout
+ obj.timeout = 0;
+
+ --Combine / Reorder the pack (later)
+ player.notice = bor(player.notice, PN_COMBINE, PN_REORDER)
+ player.window = bor(player.window, PW_INVEN, PW_EQUIP, PW_PLAYER)
+ end
+ increase_mana(add)
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Drains the mana contained in wands, staves and rods to increase yours",
+ }
+}
+
+GENOCIDE = add_spell
+{
+ ["name"] = "Genocide",
+ ["school"] = {SCHOOL_UDUN, SCHOOL_NATURE},
+ ["level"] = 25,
+ ["mana"] = 50,
+ ["mana_max"] = 50,
+ ["fail"] = 90,
+ ["stick"] =
+ {
+ ["charge"] = { 2, 2 },
+ [TV_STAFF] =
+ {
+ ["rarity"] = 85,
+ ["base_level"] = { 1, 1 },
+ ["max_level"] = { 5, 15 },
+ },
+ },
+ ["spell"] = function()
+ local type
+
+ type = 0
+ if get_level(GENOCIDE) >= 10 then type = 1 end
+ if type == 0 then
+ genocide(TRUE)
+ return TRUE
+ else
+ if get_check("Genocide all monsters near you? ") == TRUE then
+ mass_genocide(TRUE)
+ else
+ genocide(TRUE)
+ end
+ return TRUE
+ end
+ end,
+ ["info"] = function()
+ return ""
+ end,
+ ["desc"] = {
+ "Genocides all monsters of a race on the level",
+ "At level 10 it can genocide all monsters near you"
+ }
+}
+
+WRAITHFORM = add_spell
+{
+ ["name"] = "Wraithform",
+ ["school"] = {SCHOOL_UDUN, SCHOOL_CONVEYANCE},
+ ["level"] = 30,
+ ["mana"] = 20,
+ ["mana_max"] = 40,
+ ["fail"] = 95,
+ ["inertia"] = { 4, 30 },
+ ["spell"] = function()
+ return set_shadow(randint(30) + 20 + get_level(WRAITHFORM, 40))
+ end,
+ ["info"] = function()
+ return "dur "..(20 + get_level(WRAITHFORM, 40)).."+d30"
+ end,
+ ["desc"] = {
+ "Turns you into an immaterial being",
+ }
+}
+
+FLAMEOFUDUN = add_spell
+{
+ ["name"] = "Flame of Udun",
+ ["school"] = {SCHOOL_UDUN, SCHOOL_FIRE},
+ ["level"] = 35,
+ ["mana"] = 70,
+ ["mana_max"] = 100,
+ ["fail"] = 95,
+ ["inertia"] = { 7, 15 },
+ ["spell"] = function()
+ return set_mimic(randint(15) + 5 + get_level(FLAMEOFUDUN, 30), resolve_mimic_name("Balrog"), get_level(FLAMEOFUDUN))
+ end,
+ ["info"] = function()
+ return "dur "..(5 + get_level(FLAMEOFUDUN, 30)).."+d15"
+ end,
+ ["desc"] = {
+ "Turns you into a powerful Balrog",
+ }
+}
+
+
+-- Return the number of Udun/Melkor spells in a given book
+function udun_in_book(sval, pval)
+ local i, y, index, sch, s
+
+ i = 0
+
+ -- Hack if the book is 255 it is a random book
+ if sval == 255 then
+ school_book[sval] = {pval}
+ end
+ -- Parse all spells
+ for index, s in school_book[sval] do
+ for index, sch in __spell_school[s] do
+ if sch == SCHOOL_UDUN then i = i + 1 end
+ if sch == SCHOOL_MELKOR then i = i + 1 end
+ end
+ end
+ return i
+end
+
+-- Return the total level of spells
+function levels_in_book(sval, pval)
+ local i, y, index, sch, s
+
+ i = 0
+
+ -- Hack if the book is 255 it is a random book
+ if sval == 255 then
+ school_book[sval] = {pval}
+ end
+
+ -- Parse all spells
+ for index, s in school_book[sval] do
+ i = i + __tmp_spells[s].level
+ end
+ return i
+end
diff --git a/lib/scpt/s_water.lua b/lib/scpt/s_water.lua
new file mode 100644
index 00000000..739b066b
--- /dev/null
+++ b/lib/scpt/s_water.lua
@@ -0,0 +1,154 @@
+-- handle the water school
+
+TIDALWAVE = add_spell
+{
+ ["name"] = "Tidal Wave",
+ ["school"] = {SCHOOL_WATER},
+ ["level"] = 16,
+ ["mana"] = 16,
+ ["mana_max"] = 40,
+ ["fail"] = 65,
+ ["stick"] =
+ {
+ ["charge"] = { 6, 5 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 54,
+ ["base_level"] = { 1, 10 },
+ ["max_level"] = { 20, 50 },
+ },
+ },
+ ["inertia"] = { 4, 100 },
+ ["spell"] = function()
+ fire_wave(GF_WAVE, 0, 40 + get_level(TIDALWAVE, 200), 0, 6 + get_level(TIDALWAVE, 10), EFF_WAVE)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(40 + get_level(TIDALWAVE, 200)).." rad "..(6 + get_level(TIDALWAVE, 10))
+ end,
+ ["desc"] = {
+ "Summons a monstrous tidal wave that will expand and crush the",
+ "monsters under its mighty waves."
+ }
+}
+
+ICESTORM = add_spell
+{
+ ["name"] = "Ice Storm",
+ ["school"] = {SCHOOL_WATER},
+ ["level"] = 22,
+ ["mana"] = 30,
+ ["mana_max"] = 60,
+ ["fail"] = 80,
+ ["stick"] =
+ {
+ ["charge"] = { 3, 7 },
+ [TV_WAND] =
+ {
+ ["rarity"] = 65,
+ ["base_level"] = { 1, 5 },
+ ["max_level"] = { 25, 45 },
+ },
+ },
+ ["inertia"] = { 3, 40 },
+ ["spell"] = function()
+ local type
+
+ if get_level(ICESTORM, 50) >= 10 then type = GF_ICE
+ else type = GF_COLD end
+ fire_wave(type, 0, 80 + get_level(ICESTORM, 200), 1 + get_level(ICESTORM, 3, 0), 20 + get_level(ICESTORM, 70), EFF_STORM)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(80 + get_level(ICESTORM, 200)).." rad "..(1 + get_level(ICESTORM, 3, 0)).." dur "..(20 + get_level(ICESTORM, 70))
+ end,
+ ["desc"] = {
+ "Engulfs you in a storm of roaring cold that strikes your foes.",
+ "At level 10 it turns into shards of ice."
+ }
+}
+
+ENTPOTION = add_spell
+{
+ ["name"] = "Ent's Potion",
+ ["school"] = {SCHOOL_WATER},
+ ["level"] = 6,
+ ["mana"] = 7,
+ ["mana_max"] = 15,
+ ["fail"] = 35,
+ ["inertia"] = { 1, 30 },
+ ["spell"] = function()
+ set_food(PY_FOOD_MAX - 1)
+ msg_print("The Ent's Potion fills your stomach.")
+ if get_level(ENTPOTION, 50) >= 5 then
+ set_afraid(0)
+ end
+ if get_level(ENTPOTION, 50) >= 12 then
+ set_hero(player.hero + randint(25) + 25 + get_level(ENTPOTION, 40))
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ if get_level(ENTPOTION, 50) >= 12 then
+ return "dur "..(25 + get_level(ENTPOTION, 40)).."+d25"
+ else
+ return ""
+ end
+ end,
+ ["desc"] = {
+ "Fills up your stomach.",
+ "At level 5 it boldens your heart.",
+ "At level 12 it makes you heroic."
+ }
+}
+
+VAPOR = add_spell
+{
+ ["name"] = "Vapor",
+ ["school"] = {SCHOOL_WATER},
+ ["level"] = 2,
+ ["mana"] = 2,
+ ["mana_max"] = 12,
+ ["fail"] = 20,
+ ["inertia"] = { 1, 30 },
+ ["spell"] = function()
+ fire_cloud(GF_WATER, 0, 3 + get_level(VAPOR, 20), 3 + get_level(VAPOR, 9, 0), 5)
+ return TRUE
+ end,
+ ["info"] = function()
+ return "dam "..(3 + get_level(VAPOR, 20)).." rad "..(3 + get_level(VAPOR, 9, 0)).." dur 5"
+ end,
+ ["desc"] = {
+ "Fills the air with toxic moisture to eradicate annoying critters."
+ }
+}
+
+function get_geyser_damage()
+ return get_level(GEYSER, 10), 3 + get_level(GEYSER, 35)
+end
+
+GEYSER = add_spell
+{
+ ["name"] = "Geyser",
+ ["school"] = SCHOOL_WATER,
+ ["level"] = 1,
+ ["mana"] = 1,
+ ["mana_max"] = 35,
+ ["fail"] = 5,
+ ["spell"] = function()
+ local ret, dir
+ ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+ return fire_bolt_or_beam(2 * get_level(GEYSER, 85), GF_WATER, dir, damroll(get_geyser_damage()))
+ end,
+ ["info"] = function()
+ local n, d
+ n, d = get_geyser_damage()
+ return "dam "..n.."d"..d
+ end,
+ ["desc"] =
+ {
+ "Shoots a geyser of water from your fingertips.",
+ "Sometimes it can blast through its first target."
+ },
+}
diff --git a/lib/scpt/s_yavann.lua b/lib/scpt/s_yavann.lua
new file mode 100644
index 00000000..2f594e85
--- /dev/null
+++ b/lib/scpt/s_yavann.lua
@@ -0,0 +1,157 @@
+-- Handle Yavanna kementari magic school
+
+YAVANNA_CHARM_ANIMAL = add_spell
+{
+ ["name"] = "Charm Animal",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 1,
+ ["mana"] = 10,
+ ["mana_max"] = 100,
+ ["fail"] = 30,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local ret, dir = get_aim_dir()
+ if ret == FALSE then return end
+
+ return fire_ball(GF_CONTROL_ANIMAL, dir, 10 + get_level(YAVANNA_CHARM_ANIMAL, 170), get_level(YAVANNA_CHARM_ANIMAL, 2))
+ end,
+ ["info"] = function()
+ return "power "..(10 + get_level(YAVANNA_CHARM_ANIMAL, 170)).." rad "..(get_level(YAVANNA_CHARM_ANIMAL, 2))
+ end,
+ ["desc"] = {
+ "It tries to tame an animal",
+ }
+}
+
+YAVANNA_GROW_GRASS = add_spell
+{
+ ["name"] = "Grow Grass",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 10,
+ ["mana"] = 70,
+ ["mana_max"] = 150,
+ ["fail"] = 65,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ grow_grass(get_level(YAVANNA_GROW_GRASS, 4))
+ return TRUE
+ end,
+ ["info"] = function()
+ return "rad "..(get_level(YAVANNA_GROW_GRASS, 4))
+ end,
+ ["desc"] = {
+ "Create a floor of grass around you. While on grass and praying",
+ "a worshipper of Yavanna will know a greater regeneration rate"
+ }
+}
+
+YAVANNA_TREE_ROOTS = add_spell
+{
+ ["name"] = "Tree Roots",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 15,
+ ["mana"] = 50,
+ ["mana_max"] = 1000,
+ ["fail"] = 70,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ return set_roots(10 + get_level(YAVANNA_TREE_ROOTS, 30), 10 + get_level(YAVANNA_TREE_ROOTS, 60), 10 + get_level(YAVANNA_TREE_ROOTS, 20))
+ end,
+ ["info"] = function()
+ return "dur "..(10 + get_level(YAVANNA_TREE_ROOTS, 30)).." AC "..(10 + get_level(YAVANNA_TREE_ROOTS, 60)).." dam "..(10 + get_level(YAVANNA_TREE_ROOTS, 20))
+ end,
+ ["desc"] = {
+ "Creates roots deep in the floor from your feet, making you more stable and able",
+ "to make stronger attacks, but prevents any movement (even teleportation).",
+ "It also makes you recover from stunning almost immediately."
+ }
+}
+
+YAVANNA_WATER_BITE = add_spell
+{
+ ["name"] = "Water Bite",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 20,
+ ["mana"] = 150,
+ ["mana_max"] = 300,
+ ["fail"] = 90,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local rad
+
+ rad = 0
+ if get_level(YAVANNA_WATER_BITE) >= 25 then rad = 1 end
+
+ return set_project(randint(30) + 30 + get_level(YAVANNA_WATER_BITE, 150),
+ GF_WATER,
+ 10 + get_level(YAVANNA_WATER_BITE),
+ rad,
+ bor(PROJECT_STOP, PROJECT_KILL))
+ end,
+ ["info"] = function()
+ return "dur "..(30 + get_level(YAVANNA_WATER_BITE, 150)).."+d30 dam "..(10 + get_level(YAVANNA_WATER_BITE)).."/blow"
+ end,
+ ["desc"] = {
+ "Imbues your melee weapon with a natural stream of water",
+ "At level 25, it spreads over a 1 radius zone around your target"
+ }
+}
+
+YAVANNA_UPROOT = add_spell
+{
+ ["name"] = "Uproot",
+ ["school"] = {SCHOOL_YAVANNA},
+ ["level"] = 35,
+ ["mana"] = 250,
+ ["mana_max"] = 350,
+ ["fail"] = 95,
+ -- Uses piety to cast
+ ["piety"] = TRUE,
+ ["stat"] = A_WIS,
+ ["random"] = SKILL_SPIRITUALITY,
+ ["spell"] = function()
+ local m_idx, x, y, c_ptr, ret, dir
+
+ ret, dir = get_rep_dir()
+ if ret == FALSE then return end
+ y, x = explode_dir(dir)
+ y, x = y + player.py, x + player.px
+ c_ptr = cave(y, x)
+
+ if c_ptr.feat == FEAT_TREES then
+ cave_set_feat(y, x, FEAT_GRASS);
+
+ -- Summon it
+ y, x = find_position(y, x)
+ m_idx = place_monster_one(y, x, test_monster_name("Ent"), 0, FALSE, MSTATUS_FRIEND)
+
+ -- level it
+ if m_idx ~= 0 then
+ monster_set_level(m_idx, 30 + get_level(YAVANNA_UPROOT, 70))
+ end
+
+ msg_print("The tree awakes!");
+ else
+ msg_print("There is no tree there.")
+ end
+ return TRUE
+ end,
+ ["info"] = function()
+ return "lev "..(30 + get_level(YAVANNA_UPROOT, 70))
+ end,
+ ["desc"] = {
+ "Awakes a tree to help you battle the forces of Morgoth",
+ }
+}
diff --git a/lib/scpt/spells.lua b/lib/scpt/spells.lua
new file mode 100644
index 00000000..2f90c10b
--- /dev/null
+++ b/lib/scpt/spells.lua
@@ -0,0 +1,475 @@
+--
+-- This file takes care of the schools of magic
+--
+
+-- Create the schools
+SCHOOL_MANA = add_school
+{
+ ["name"] = "Mana",
+ ["skill"] = SKILL_MANA,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Eru Iluvatar provides the Mana school at half the prayer skill
+ [GOD_ERU] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ },
+ ["hooks"] =
+ {
+ [HOOK_CALC_MANA] = function(msp)
+ if get_skill(SKILL_MANA) >= 35 then
+ msp = msp + (msp * ((get_skill(SKILL_MANA) - 34)) / 100)
+ return TRUE, msp
+ end
+ end
+ },
+}
+SCHOOL_FIRE = add_school
+{
+ ["name"] = "Fire",
+ ["skill"] = SKILL_FIRE,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+}
+SCHOOL_AIR = add_school
+{
+ ["name"] = "Air",
+ ["skill"] = SKILL_AIR,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ if get_skill(SKILL_AIR) >= 50 then
+ player.magical_breath = TRUE
+ end
+ end,
+ },
+ ["gods"] =
+ {
+ -- Manwe Sulimo provides the Air school at 2/3 the prayer skill
+ [GOD_MANWE] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 2,
+ ["div"] = 3,
+ },
+ },
+}
+SCHOOL_WATER = add_school
+{
+ ["name"] = "Water",
+ ["skill"] = SKILL_WATER,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["hooks"] =
+ {
+ [HOOK_CALC_BONUS] = function()
+ if get_skill(SKILL_WATER) >= 30 then
+ player.water_breath = TRUE
+ end
+ end,
+ },
+ ["gods"] =
+ {
+ -- Yavanna Kementari provides the Water school at 1/2 the prayer skill
+ [GOD_YAVANNA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ },
+}
+SCHOOL_EARTH = add_school
+{
+ ["name"] = "Earth",
+ ["skill"] = SKILL_EARTH,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Tulkas provides the Earth school at 4/5 the prayer skill
+ [GOD_TULKAS] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 4,
+ ["div"] = 5,
+ },
+ -- Yavanna Kementari provides the Earth school at 1/2 the prayer skill
+ [GOD_YAVANNA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ },
+}
+SCHOOL_CONVEYANCE = add_school
+{
+ ["name"] = "Conveyance",
+ ["skill"] = SKILL_CONVEYANCE,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Manwe Sulimo provides the Conveyance school at 1/2 the prayer skill
+ [GOD_MANWE] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ },
+}
+SCHOOL_GEOMANCY = add_school
+{
+ ["name"] = "Geomancy",
+ ["skill"] = SKILL_GEOMANCY,
+ ["spell_power"] = TRUE,
+ -- Require to wield a Mage Staff, as the spells requries the caster to stomp the floor with it
+ ["depend"] = function()
+ -- Require at least one point in each school
+ if get_skill(SKILL_FIRE) == 0 then return end
+ if get_skill(SKILL_AIR) == 0 then return end
+ if get_skill(SKILL_EARTH) == 0 then return end
+ if get_skill(SKILL_WATER) == 0 then return end
+
+ local obj = get_object(INVEN_WIELD)
+ if (obj.k_idx > 0) and (obj.tval == TV_MSTAFF) then return TRUE end
+ end,
+}
+SCHOOL_DIVINATION = add_school
+{
+ ["name"] = "Divination",
+ ["skill"] = SKILL_DIVINATION,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Eru Iluvatar provides the Divination school at 2/3 the prayer skill
+ [GOD_ERU] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 2,
+ ["div"] = 3,
+ },
+ },
+}
+SCHOOL_TEMPORAL = add_school
+{
+ ["name"] = "Temporal",
+ ["skill"] = SKILL_TEMPORAL,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Yavanna Kementari provides the Temporal school at 1/6 the prayer skill
+ [GOD_YAVANNA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 6,
+ },
+ },
+}
+SCHOOL_NATURE = add_school
+{
+ ["name"] = "Nature",
+ ["skill"] = SKILL_NATURE,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Yavanna Kementari provides the Nature school at 1/2 the prayer skill
+ [GOD_YAVANNA] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 2,
+ },
+ },
+}
+SCHOOL_META = add_school
+{
+ ["name"] = "Meta",
+ ["skill"] = SKILL_META,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Manwe Sulimo provides the Meta school at 1/3 the prayer skill
+ [GOD_MANWE] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 3,
+ },
+ },
+}
+SCHOOL_MIND = add_school
+{
+ ["name"] = "Mind",
+ ["skill"] = SKILL_MIND,
+ ["spell_power"] = TRUE,
+ ["sorcery"] = TRUE,
+ ["gods"] =
+ {
+ -- Eru Iluvatar provides the Mind school at 1/3 the prayer skill
+ [GOD_ERU] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 3,
+ },
+ -- Melkor Bauglir provides the Mind school at 1/3 the prayer skill
+ [GOD_MELKOR] =
+ {
+ ["skill"] = SKILL_PRAY,
+ ["mul"] = 1,
+ ["div"] = 3,
+ },
+ },
+}
+SCHOOL_UDUN = add_school
+{
+ ["name"] = "Udun",
+ ["skill"] = SKILL_UDUN,
+ ["bonus_level"] = function()
+ return ((player.lev * 2) / 3)
+ end,
+}
+SCHOOL_DEMON = add_school
+{
+ ["name"] = "Demon",
+ ["skill"] = SKILL_DAEMON,
+ ["no_random"] = TRUE,
+}
+
+-- The God specific schools, all tied to the prayer skill
+SCHOOL_ERU = add_school
+{
+ ["name"] = "Eru Iluvatar",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_ERU,
+}
+SCHOOL_MANWE = add_school
+{
+ ["name"] = "Manwe Sulimo",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_MANWE,
+}
+SCHOOL_TULKAS = add_school
+{
+ ["name"] = "Tulkas",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_TULKAS,
+}
+SCHOOL_MELKOR = add_school
+{
+ ["name"] = "Melkor Bauglir",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_MELKOR,
+}
+SCHOOL_YAVANNA = add_school
+{
+ ["name"] = "Yavanna Kementari",
+ ["skill"] = SKILL_PRAY,
+ ["spell_power"] = TRUE,
+ ["god"] = GOD_YAVANNA,
+}
+
+-- Not a real school, rather a palcehodler for stick only spells
+SCHOOL_DEVICE = add_school
+{
+ ["name"] = "Device",
+ ["skill"] = SKILL_DEVICE,
+}
+
+-- Music "spells"
+SCHOOL_MUSIC = add_school
+{
+ ["name"] = "Music",
+ ["skill"] = SKILL_MUSIC,
+}
+
+-- Put some spells
+tome_dofile("s_fire.lua")
+tome_dofile("s_mana.lua")
+tome_dofile("s_water.lua")
+tome_dofile("s_air.lua")
+tome_dofile("s_earth.lua")
+tome_dofile("s_convey.lua")
+tome_dofile("s_nature.lua")
+tome_dofile("s_divin.lua")
+tome_dofile("s_tempo.lua")
+tome_dofile("s_meta.lua")
+tome_dofile("s_mind.lua")
+tome_dofile("s_udun.lua")
+tome_dofile("s_geom.lua")
+
+-- God's specific spells
+tome_dofile("s_eru.lua")
+tome_dofile("s_manwe.lua")
+tome_dofile("s_tulkas.lua")
+tome_dofile("s_melkor.lua")
+tome_dofile("s_yavann.lua")
+
+-- Specific schools
+tome_dofile("s_demon.lua")
+
+-- Device spells
+tome_dofile("s_stick.lua")
+
+-- Musics
+tome_dofile("s_music.lua")
+
+-- List of spellbooks
+
+-- Create the crystal of mana
+school_book[0] = {
+ MANATHRUST, DELCURSES, RESISTS, MANASHIELD,
+}
+
+-- The book of the eternal flame
+school_book[1] = {
+ GLOBELIGHT, FIREGOLEM, FIREFLASH, FIREWALL, FIERYAURA,
+}
+
+-- The book of the blowing winds
+school_book[2] = {
+ NOXIOUSCLOUD, POISONBLOOD, INVISIBILITY, STERILIZE, AIRWINGS, THUNDERSTORM,
+}
+
+-- The book of the impenetrable earth
+school_book[3] = {
+ STONESKIN, DIG, STONEPRISON, SHAKE, STRIKE,
+}
+
+-- The book of the unstopable wave
+school_book[4] = {
+ GEYSER, VAPOR, ENTPOTION, TIDALWAVE, ICESTORM
+}
+
+-- Create the book of translocation
+school_book[5] = {
+ BLINK, DISARM, TELEPORT, TELEAWAY, RECALL, PROBABILITY_TRAVEL,
+}
+
+-- Create the book of the tree
+school_book[6] = {
+ GROWTREE, HEALING, RECOVERY, REGENERATION, SUMMONANNIMAL,
+}
+
+-- Create the book of Knowledge
+school_book[7] = {
+ SENSEMONSTERS, SENSEHIDDEN, REVEALWAYS, IDENTIFY, VISION, STARIDENTIFY,
+}
+
+-- Create the book of the Time
+school_book[8] = {
+ MAGELOCK, SLOWMONSTER, ESSENCESPEED, BANISHMENT,
+}
+
+-- Create the book of meta spells
+school_book[9] = {
+ RECHARGE, DISPERSEMAGIC, SPELLBINDER, TRACKER, INERTIA_CONTROL,
+}
+
+-- Create the book of the mind
+school_book[10] = {
+ CHARM, CONFUSE, ARMOROFFEAR, STUN,
+}
+
+-- Create the book of hellflame
+school_book[11] = {
+ DRAIN, GENOCIDE, WRAITHFORM, FLAMEOFUDUN,
+}
+
+-- Create the book of eru
+school_book[20] = {
+ ERU_SEE, ERU_LISTEN, ERU_UNDERSTAND, ERU_PROT,
+}
+
+-- Create the book of manwe
+school_book[21] = {
+ MANWE_BLESS, MANWE_SHIELD, MANWE_CALL, MANWE_AVATAR,
+}
+
+-- Create the book of tulkas
+school_book[22] = {
+ TULKAS_AIM, TULKAS_SPIN, TULKAS_WAVE,
+}
+
+-- Create the book of melkor
+school_book[23] = {
+ MELKOR_CURSE, MELKOR_CORPSE_EXPLOSION, MELKOR_MIND_STEAL,
+}
+
+-- Create the book of yavanna
+school_book[24] = {
+ YAVANNA_CHARM_ANIMAL, YAVANNA_GROW_GRASS, YAVANNA_TREE_ROOTS, YAVANNA_WATER_BITE, YAVANNA_UPROOT,
+}
+
+-- Create the book of beginner's cantrip
+school_book[50] = {
+ MANATHRUST, GLOBELIGHT, ENTPOTION, BLINK, SENSEMONSTERS, SENSEHIDDEN,
+}
+
+-- Create the book of teleporatation
+school_book[51] = {
+ BLINK, TELEPORT, TELEAWAY
+}
+
+-- Create the book of summoning
+school_book[52] = {
+ FIREGOLEM, SUMMONANNIMAL
+}
+
+
+-- Create the Armageddon Demonblade
+school_book[55] = {
+ DEMON_BLADE, DEMON_MADNESS, DEMON_FIELD,
+}
+
+-- Create the Shield Demonblade
+school_book[56] = {
+ DOOM_SHIELD, DEMON_CLOAK, UNHOLY_WORD,
+}
+
+-- Create the Control Demonblade
+school_book[57] = {
+ DEMON_SUMMON, DISCHARGE_MINION, CONTROL_DEMON,
+}
+
+-- Create the Drums
+school_book[58] = {
+ MUSIC_STOP, MUSIC_HOLD, MUSIC_CONF, MUSIC_STUN,
+}
+
+-- Create the Harps
+school_book[59] = {
+ MUSIC_STOP, MUSIC_LITE, MUSIC_HERO, MUSIC_HEAL, MUSIC_TIME, MUSIC_MIND,
+}
+
+-- Create the Horns
+school_book[60] = {
+ MUSIC_STOP, MUSIC_BLOW, MUSIC_WIND, MUSIC_YLMIR, MUSIC_AMBARKANTA,
+}
+
+-- Book of the Player, filled in by the Library Quest
+school_book[61] = { }
+
+-- Geomancy spells, not a real book
+school_book[62] = {
+ CALL_THE_ELEMENTS, CHANNEL_ELEMENTS, ELEMENTAL_WAVE, VAPORIZE, GEOLYSIS, DRIPPING_TREAD, GROW_BARRIER, ELEMENTAL_MINION
+}
diff --git a/lib/scpt/stores.lua b/lib/scpt/stores.lua
new file mode 100644
index 00000000..03d29e6e
--- /dev/null
+++ b/lib/scpt/stores.lua
@@ -0,0 +1,132 @@
+-- Whats shops can buy what
+store_buy_list
+{
+ ["General Store"] =
+ {
+ TV_CORPSE,
+ TV_FOOD,
+ TV_LITE,
+ TV_FLASK,
+ TV_SPIKE,
+ TV_SHOT,
+ TV_ARROW,
+ TV_BOLT,
+ TV_DIGGING,
+ TV_CLOAK,
+ TV_BOTTLE,
+ },
+ ["Armoury"] =
+ {
+ TV_BOOTS,
+ TV_GLOVES,
+ TV_CROWN,
+ TV_HELM,
+ TV_SHIELD,
+ TV_CLOAK,
+ TV_SOFT_ARMOR,
+ TV_HARD_ARMOR,
+ TV_DRAG_ARMOR,
+ },
+ ["Weaponsmith"] =
+ {
+ TV_SHOT,
+ TV_BOLT,
+ TV_ARROW,
+ TV_BOOMERANG,
+ TV_BOW,
+ TV_DIGGING,
+ TV_HAFTED,
+ TV_POLEARM,
+ TV_SWORD,
+ TV_AXE,
+ TV_MSTAFF,
+ },
+ -- We use a function because we want to restrict to blessed weapons and god spells
+ ["Temple"] = function (obj)
+ if obj.tval == TV_DRUID_BOOK then return TRUE
+ elseif obj.tval == TV_BOOK and obj.sval == 255 and (can_spell_random(obj.pval) == SKILL_SPIRITUALITY) then return TRUE
+ elseif obj.tval == TV_SCROLL then return TRUE
+ elseif obj.tval == TV_POTION2 then return TRUE
+ elseif obj.tval == TV_POTION then return TRUE
+ elseif obj.tval == TV_HAFTED then return TRUE
+ elseif obj.tval == TV_POLEARM and is_blessed(obj) == TRUE then return TRUE
+ elseif obj.tval == TV_SWORD and is_blessed(obj) == TRUE then return TRUE
+ elseif obj.tval == TV_AXE and is_blessed(obj) == TRUE then return TRUE
+ elseif obj.tval == TV_BOOMERANG and is_blessed(obj) == TRUE then return TRUE
+ end
+ end,
+ ["Alchemy shop"] =
+ {
+ TV_SCROLL,
+ TV_POTION2,
+ TV_POTION,
+ TV_BATERIE,
+ TV_BOTTLE,
+ },
+ -- We use a function because we dont want god spells
+ ["Magic shop"] = function (obj)
+ local buy =
+ {
+ [TV_SYMBIOTIC_BOOK] = TRUE,
+ [TV_AMULET] = TRUE,
+ [TV_RING] = TRUE,
+ [TV_STAFF] = TRUE,
+ [TV_WAND] = TRUE,
+ [TV_ROD] = TRUE,
+ [TV_ROD_MAIN] = TRUE,
+ [TV_SCROLL] = TRUE,
+ [TV_POTION2] = TRUE,
+ [TV_POTION] = TRUE,
+ [TV_MSTAFF] = TRUE,
+ [TV_RANDART] = TRUE,
+ }
+
+ if obj.tval == TV_BOOK and obj.sval == 255 and (can_spell_random(obj.pval) == SKILL_MAGIC) then return TRUE
+ elseif obj.tval == TV_BOOK and obj.sval ~= 255 then return TRUE
+ elseif buy[obj.tval] == TRUE then return TRUE
+ end
+ end,
+ -- Black markets wants ALL!
+ ["Black Market"] = function (obj)
+ return TRUE
+ end,
+ ["Book Store"] =
+ {
+ TV_BOOK,
+ TV_SYMBIOTIC_BOOK,
+ TV_MUSIC_BOOK,
+ TV_DAEMON_BOOK,
+ TV_DRUID_BOOK,
+ },
+ ["Pet Shop"] =
+ {
+ TV_EGG,
+ },
+}
+
+-- Take care to have Magic shop/Temple have specific spells only
+add_hooks
+{
+ [HOOK_STORE_STOCK] = function (index, name, level)
+ if name == "Magic shop" then
+ -- Books
+ if magik(20) == TRUE then
+ object_prep(obj_forge, lookup_kind(TV_BOOK, 255))
+ local spell = get_random_spell(SKILL_MAGIC, 20)
+ if spell > -1 then
+ obj_forge.pval = spell
+ return TRUE, obj_forge
+ end
+ end
+ elseif name == "Temple" then
+ if magik(20) == TRUE then
+ object_prep(obj_forge, lookup_kind(TV_BOOK, 255))
+ local spell = get_random_spell(SKILL_SPIRITUALITY, 20)
+ if spell > -1 then
+ obj_forge.pval = spell
+ return TRUE, obj_forge
+ end
+ end
+ end
+ end,
+}
diff --git a/lib/user/automat.atm b/lib/user/automat.atm
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/lib/user/automat.atm
diff --git a/lib/user/delete.me b/lib/user/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/user/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/xtra/ang16.bdf b/lib/xtra/ang16.bdf
new file mode 100644
index 00000000..f59a2eca
--- /dev/null
+++ b/lib/xtra/ang16.bdf
@@ -0,0 +1,5017 @@
+STARTFONT 2.1
+FONT -Angband-Fixed-Medium-R-Normal--16-120-100-100-C-80-Misc-Fontspecific
+SIZE 16 100 100
+FONTBOUNDINGBOX 8 16 0 -2
+STARTPROPERTIES 18
+FONTNAME_REGISTRY ""
+FOUNDRY "Angband"
+FAMILY_NAME "Fixed"
+WEIGHT_NAME "Medium"
+SLANT "R"
+SETWIDTH_NAME "Normal"
+ADD_STYLE_NAME ""
+PIXEL_SIZE 16
+POINT_SIZE 120
+RESOLUTION_X 100
+RESOLUTION_Y 100
+SPACING "C"
+AVERAGE_WIDTH 80
+CHARSET_REGISTRY "Misc"
+CHARSET_ENCODING "Fontspecific"
+DEFAULT_CHAR 32
+FONT_DESCENT 2
+FONT_ASCENT 14
+ENDPROPERTIES
+CHARS 217
+STARTCHAR C20
+ENCODING 32
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C21
+ENCODING 33
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+30
+30
+30
+30
+30
+30
+00
+00
+30
+30
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C22
+ENCODING 34
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+66
+42
+24
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C23
+ENCODING 35
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+6c
+6c
+6c
+fe
+6c
+6c
+6c
+fe
+6c
+6c
+6c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C24
+ENCODING 36
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+10
+7c
+d2
+d0
+f0
+7c
+3e
+1e
+16
+96
+7c
+10
+00
+00
+00
+ENDCHAR
+STARTCHAR C25
+ENCODING 37
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+62
+66
+0e
+1c
+38
+70
+e0
+cc
+8c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C26
+ENCODING 38
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+30
+68
+58
+38
+70
+f2
+d4
+c8
+d4
+76
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C27
+ENCODING 39
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+18
+08
+10
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C28
+ENCODING 40
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+08
+10
+30
+30
+30
+30
+30
+30
+30
+10
+08
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C29
+ENCODING 41
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+10
+08
+0c
+0c
+0c
+0c
+0c
+0c
+0c
+08
+10
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C2A
+ENCODING 42
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+d6
+fe
+7c
+ee
+7c
+fe
+d6
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C2B
+ENCODING 43
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+18
+18
+18
+7e
+18
+18
+18
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C2C
+ENCODING 44
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+38
+38
+10
+20
+00
+00
+ENDCHAR
+STARTCHAR C2D
+ENCODING 45
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+7e
+00
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C2E
+ENCODING 46
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+18
+18
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C2F
+ENCODING 47
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+02
+06
+0e
+1c
+38
+70
+e0
+c0
+80
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C30
+ENCODING 48
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+1c
+26
+66
+66
+6e
+76
+66
+66
+64
+38
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C31
+ENCODING 49
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+18
+38
+78
+18
+18
+18
+18
+18
+18
+7e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C32
+ENCODING 50
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+46
+66
+06
+0c
+18
+30
+62
+7e
+7e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C33
+ENCODING 51
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+66
+66
+06
+3c
+06
+06
+66
+66
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C34
+ENCODING 52
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+02
+06
+0e
+16
+26
+46
+ff
+06
+06
+0f
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C35
+ENCODING 53
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7e
+7e
+40
+5c
+66
+46
+06
+66
+46
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C36
+ENCODING 54
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+1c
+26
+66
+60
+7c
+66
+66
+66
+66
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C37
+ENCODING 55
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7e
+7e
+42
+06
+0c
+18
+30
+30
+30
+30
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C38
+ENCODING 56
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+66
+62
+74
+3c
+2e
+46
+46
+66
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C39
+ENCODING 57
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+66
+66
+66
+66
+3e
+06
+66
+64
+38
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C3A
+ENCODING 58
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+18
+00
+00
+18
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C3B
+ENCODING 59
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+30
+30
+00
+00
+00
+38
+18
+10
+20
+00
+00
+ENDCHAR
+STARTCHAR C3C
+ENCODING 60
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+04
+0c
+18
+30
+60
+30
+18
+0c
+04
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C3D
+ENCODING 61
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+7e
+00
+00
+7e
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C3E
+ENCODING 62
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+20
+30
+18
+0c
+06
+0c
+18
+30
+20
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C3F
+ENCODING 63
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7c
+c6
+86
+06
+0c
+18
+30
+00
+30
+30
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C40
+ENCODING 64
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+46
+9a
+b6
+ba
+b6
+9c
+80
+c2
+7c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C41
+ENCODING 65
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+06
+0e
+0e
+16
+16
+26
+3e
+46
+46
+ef
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C42
+ENCODING 66
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fc
+66
+62
+66
+7c
+66
+62
+62
+66
+fc
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C43
+ENCODING 67
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3e
+46
+c2
+c0
+c0
+c0
+c0
+c2
+e6
+7c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C44
+ENCODING 68
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fc
+6e
+66
+66
+66
+66
+66
+66
+64
+f8
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C45
+ENCODING 69
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fe
+62
+60
+64
+7c
+64
+60
+60
+62
+fe
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C46
+ENCODING 70
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fe
+62
+60
+64
+7c
+64
+60
+60
+60
+f0
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C47
+ENCODING 71
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+66
+c2
+c0
+ce
+c6
+c6
+c6
+e4
+78
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C48
+ENCODING 72
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e7
+66
+66
+66
+7e
+66
+66
+66
+66
+e7
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C49
+ENCODING 73
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+18
+18
+18
+18
+18
+18
+18
+18
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C4A
+ENCODING 74
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+18
+18
+18
+18
+18
+18
+18
+18
+18
+d8
+70
+00
+00
+ENDCHAR
+STARTCHAR C4B
+ENCODING 75
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e7
+62
+62
+64
+68
+7c
+6e
+66
+66
+e7
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C4C
+ENCODING 76
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+f0
+60
+60
+60
+60
+60
+60
+60
+62
+fe
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C4D
+ENCODING 77
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e7
+66
+76
+7e
+7e
+56
+46
+46
+46
+ef
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C4E
+ENCODING 78
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e7
+62
+72
+72
+5a
+5a
+4e
+4e
+46
+e6
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C4F
+ENCODING 79
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+4e
+c6
+c6
+c6
+c6
+c6
+c6
+e4
+78
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C50
+ENCODING 80
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fc
+66
+66
+66
+64
+78
+60
+60
+60
+f0
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C51
+ENCODING 81
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+4e
+c6
+c6
+c6
+c6
+d6
+d6
+f4
+78
+0e
+00
+00
+00
+ENDCHAR
+STARTCHAR C52
+ENCODING 82
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fc
+66
+66
+66
+6c
+78
+64
+66
+66
+e7
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C53
+ENCODING 83
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7a
+c6
+c2
+e0
+70
+1c
+0e
+86
+ce
+bc
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C54
+ENCODING 84
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+ff
+db
+99
+18
+18
+18
+18
+18
+18
+7e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C55
+ENCODING 85
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e3
+62
+62
+62
+62
+62
+62
+62
+72
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C56
+ENCODING 86
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e3
+62
+64
+64
+68
+68
+70
+70
+60
+60
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C57
+ENCODING 87
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e3
+62
+62
+6a
+6a
+7e
+7e
+7e
+6c
+68
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C58
+ENCODING 88
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+f7
+62
+62
+74
+38
+1c
+2e
+46
+46
+ef
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C59
+ENCODING 89
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e3
+62
+74
+34
+38
+18
+18
+18
+18
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C5A
+ENCODING 90
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fe
+86
+0e
+1c
+38
+70
+e0
+c0
+c2
+fe
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C5B
+ENCODING 91
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+30
+30
+30
+30
+30
+30
+30
+30
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C5C
+ENCODING 92
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+80
+c0
+e0
+70
+38
+1c
+0e
+06
+02
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C5D
+ENCODING 93
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+0c
+0c
+0c
+0c
+0c
+0c
+0c
+0c
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C5E
+ENCODING 94
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+10
+38
+6c
+c6
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C5F
+ENCODING 95
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+7e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C60
+ENCODING 96
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+10
+20
+30
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C61
+ENCODING 97
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+78
+8c
+1c
+6c
+ce
+dc
+68
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C62
+ENCODING 98
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+20
+60
+e0
+60
+6c
+76
+66
+66
+66
+64
+58
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C63
+ENCODING 99
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+1c
+26
+60
+60
+62
+64
+38
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C64
+ENCODING 100
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+04
+0c
+1c
+0c
+3c
+4c
+cc
+cc
+cc
+dc
+6e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C65
+ENCODING 101
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+1c
+22
+64
+78
+72
+64
+38
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C66
+ENCODING 102
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+06
+0f
+16
+30
+7c
+30
+30
+30
+30
+30
+78
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C67
+ENCODING 103
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+06
+3a
+4c
+64
+38
+7c
+8e
+66
+62
+3c
+00
+00
+ENDCHAR
+STARTCHAR C68
+ENCODING 104
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+20
+60
+e0
+60
+6c
+76
+66
+66
+66
+66
+e7
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C69
+ENCODING 105
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+0c
+00
+00
+04
+0c
+1c
+0c
+0c
+0c
+1e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C6A
+ENCODING 106
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+0c
+00
+00
+04
+0c
+1c
+0c
+0c
+0c
+0c
+68
+70
+00
+00
+ENDCHAR
+STARTCHAR C6B
+ENCODING 107
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+20
+60
+e0
+60
+6e
+64
+68
+70
+78
+6c
+ee
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C6C
+ENCODING 108
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+08
+18
+38
+18
+18
+18
+18
+18
+18
+18
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C6D
+ENCODING 109
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+2a
+7f
+eb
+6b
+6b
+6b
+eb
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C6E
+ENCODING 110
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+2c
+76
+e6
+66
+66
+66
+e7
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C6F
+ENCODING 111
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+1c
+26
+66
+66
+66
+64
+38
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C70
+ENCODING 112
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+2c
+76
+e6
+66
+64
+78
+60
+60
+f0
+00
+00
+ENDCHAR
+STARTCHAR C71
+ENCODING 113
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+34
+4c
+cc
+cc
+cc
+7c
+0c
+0c
+1e
+00
+00
+ENDCHAR
+STARTCHAR C72
+ENCODING 114
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+06
+4f
+f6
+60
+60
+60
+60
+f0
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C73
+ENCODING 115
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+1e
+32
+38
+1c
+0e
+26
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C74
+ENCODING 116
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+10
+30
+7e
+30
+30
+30
+32
+34
+18
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C75
+ENCODING 117
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+ee
+66
+66
+66
+67
+6e
+34
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C76
+ENCODING 118
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+e6
+64
+68
+68
+70
+70
+60
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C77
+ENCODING 119
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+e3
+62
+6a
+6e
+7e
+6c
+48
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C78
+ENCODING 120
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+ee
+64
+38
+38
+38
+4c
+ee
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C79
+ENCODING 121
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+f3
+62
+36
+3c
+1c
+08
+10
+70
+60
+00
+00
+ENDCHAR
+STARTCHAR C7A
+ENCODING 122
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+7e
+46
+0c
+18
+30
+62
+7e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C7B
+ENCODING 123
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+0e
+18
+18
+18
+18
+70
+18
+18
+18
+18
+0e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C7C
+ENCODING 124
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+30
+30
+30
+30
+00
+30
+30
+30
+30
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C7D
+ENCODING 125
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+70
+18
+18
+18
+18
+0e
+18
+18
+18
+18
+70
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C7E
+ENCODING 126
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+32
+7e
+4c
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C7F
+ENCODING 127
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+10
+38
+6c
+c6
+82
+fe
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C80
+ENCODING 128
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7c
+c6
+c6
+de
+de
+de
+dc
+c0
+7e
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C81
+ENCODING 129
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+38
+6c
+c6
+c6
+c6
+fe
+c6
+c6
+c6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C82
+ENCODING 130
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fc
+66
+66
+66
+7c
+66
+66
+66
+fc
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C83
+ENCODING 131
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+66
+c0
+c0
+c0
+c0
+c0
+66
+3c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C84
+ENCODING 132
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+f8
+6c
+66
+66
+66
+66
+66
+6c
+f8
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C85
+ENCODING 133
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fe
+66
+60
+60
+7c
+60
+60
+66
+fe
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C86
+ENCODING 134
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fe
+66
+60
+60
+7c
+60
+60
+60
+f0
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C87
+ENCODING 135
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7c
+c6
+c6
+c0
+c0
+ce
+c6
+c6
+7c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C88
+ENCODING 136
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+c6
+c6
+c6
+c6
+fe
+c6
+c6
+c6
+c6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C89
+ENCODING 137
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+18
+18
+18
+18
+18
+18
+18
+3c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C8A
+ENCODING 138
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3c
+18
+18
+18
+18
+18
+d8
+d8
+70
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C8B
+ENCODING 139
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+c6
+cc
+d8
+f0
+f0
+d8
+cc
+c6
+c6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C8C
+ENCODING 140
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+f0
+60
+60
+60
+60
+60
+62
+66
+fe
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C8D
+ENCODING 141
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+c6
+c6
+ee
+fe
+d6
+d6
+d6
+c6
+c6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C8E
+ENCODING 142
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+c6
+c6
+e6
+e6
+f6
+de
+ce
+ce
+c6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C8F
+ENCODING 143
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7c
+c6
+c6
+c6
+c6
+c6
+c6
+c6
+7c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C90
+ENCODING 144
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fc
+66
+66
+66
+7c
+60
+60
+60
+f0
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C91
+ENCODING 145
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7c
+c6
+c6
+c6
+c6
+c6
+c6
+d6
+7c
+06
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C92
+ENCODING 146
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fc
+66
+66
+66
+7c
+78
+6c
+66
+e6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C93
+ENCODING 147
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7c
+c6
+c0
+60
+38
+0c
+06
+c6
+7c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C94
+ENCODING 148
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7e
+5a
+18
+18
+18
+18
+18
+18
+3c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C95
+ENCODING 149
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+c6
+c6
+c6
+c6
+c6
+c6
+c6
+c6
+7c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C96
+ENCODING 150
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+c6
+c6
+c6
+c6
+c6
+c6
+6c
+38
+10
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C97
+ENCODING 151
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+c6
+c6
+d6
+d6
+d6
+fe
+ee
+c6
+c6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C98
+ENCODING 152
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+c6
+c6
+6c
+38
+38
+38
+6c
+c6
+c6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C99
+ENCODING 153
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+66
+66
+66
+66
+3c
+18
+18
+18
+3c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C9A
+ENCODING 154
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+fe
+c6
+8c
+18
+30
+60
+c2
+c6
+fe
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C9B
+ENCODING 155
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+78
+0c
+7c
+cc
+dc
+76
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C9C
+ENCODING 156
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e0
+60
+60
+7c
+66
+66
+66
+66
+fc
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C9D
+ENCODING 157
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+7c
+c6
+c0
+c0
+c6
+7c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C9E
+ENCODING 158
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+1c
+0c
+0c
+7c
+cc
+cc
+cc
+cc
+7e
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C9F
+ENCODING 159
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+7c
+c6
+fe
+c0
+c6
+7c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CA0
+ENCODING 160
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+1c
+36
+30
+30
+fc
+30
+30
+30
+78
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CA1
+ENCODING 161
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+76
+ce
+c6
+c6
+7e
+06
+c6
+7c
+00
+00
+00
+ENDCHAR
+STARTCHAR CA2
+ENCODING 162
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e0
+60
+60
+6c
+76
+66
+66
+66
+e6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CA3
+ENCODING 163
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+18
+18
+00
+38
+18
+18
+18
+18
+3c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CA4
+ENCODING 164
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+0c
+0c
+00
+1c
+0c
+0c
+0c
+0c
+cc
+cc
+78
+00
+00
+00
+ENDCHAR
+STARTCHAR CA5
+ENCODING 165
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+e0
+60
+60
+66
+6c
+78
+6c
+66
+e6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CA6
+ENCODING 166
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+38
+18
+18
+18
+18
+18
+18
+18
+3c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CA7
+ENCODING 167
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+6c
+fe
+d6
+d6
+c6
+c6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CA8
+ENCODING 168
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+dc
+66
+66
+66
+66
+66
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CA9
+ENCODING 169
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+7c
+c6
+c6
+c6
+c6
+7c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CAA
+ENCODING 170
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+dc
+66
+66
+66
+7c
+60
+60
+f0
+00
+00
+00
+ENDCHAR
+STARTCHAR CAB
+ENCODING 171
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+76
+cc
+cc
+cc
+7c
+0c
+0c
+1e
+00
+00
+00
+ENDCHAR
+STARTCHAR CAC
+ENCODING 172
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+dc
+66
+60
+60
+60
+f0
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CAD
+ENCODING 173
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+7c
+c6
+70
+1c
+c6
+7c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CAE
+ENCODING 174
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+30
+30
+30
+fc
+30
+30
+30
+36
+1c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CAF
+ENCODING 175
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+cc
+cc
+cc
+cc
+cc
+76
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CB0
+ENCODING 176
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+c6
+c6
+c6
+6c
+38
+10
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CB1
+ENCODING 177
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+c6
+c6
+d6
+d6
+fe
+6c
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CB2
+ENCODING 178
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+c6
+6c
+38
+38
+6c
+c6
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CB3
+ENCODING 179
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+c6
+c6
+c6
+ce
+76
+06
+c6
+7c
+00
+00
+00
+ENDCHAR
+STARTCHAR CB4
+ENCODING 180
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+fe
+8c
+18
+30
+62
+fe
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CB5
+ENCODING 181
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+88
+00
+00
+00
+22
+00
+00
+00
+88
+00
+00
+00
+22
+00
+00
+00
+ENDCHAR
+STARTCHAR CB6
+ENCODING 182
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+ff
+42
+42
+7e
+42
+42
+7e
+42
+42
+7e
+42
+42
+7e
+42
+42
+ENDCHAR
+STARTCHAR CB7
+ENCODING 183
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+42
+42
+7e
+42
+42
+7e
+42
+42
+7e
+42
+42
+7e
+42
+42
+ff
+ff
+ENDCHAR
+STARTCHAR CB8
+ENCODING 184
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+ff
+95
+d5
+95
+d5
+95
+d5
+95
+d5
+95
+d5
+95
+d5
+ff
+ff
+ENDCHAR
+STARTCHAR CB9
+ENCODING 185
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+c3
+81
+81
+81
+81
+81
+81
+81
+81
+81
+81
+81
+81
+81
+81
+ENDCHAR
+STARTCHAR CBA
+ENCODING 186
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+7e
+52
+52
+52
+50
+02
+12
+00
+82
+82
+92
+92
+f6
+fe
+ff
+ENDCHAR
+STARTCHAR CBB
+ENCODING 187
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+1c
+2e
+53
+ff
+00
+00
+ENDCHAR
+STARTCHAR CBC
+ENCODING 188
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+20
+20
+20
+ff
+02
+02
+02
+ff
+20
+20
+20
+ff
+02
+02
+02
+ENDCHAR
+STARTCHAR CBD
+ENCODING 189
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+81
+81
+81
+9d
+bd
+ad
+ad
+ad
+b9
+81
+81
+42
+24
+18
+00
+ENDCHAR
+STARTCHAR CBE
+ENCODING 190
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+81
+81
+81
+81
+bd
+bd
+bd
+bd
+99
+81
+81
+42
+24
+18
+00
+ENDCHAR
+STARTCHAR CBF
+ENCODING 191
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+81
+95
+9d
+bd
+95
+91
+91
+91
+91
+91
+81
+42
+24
+18
+00
+ENDCHAR
+STARTCHAR CC0
+ENCODING 192
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+e7
+db
+db
+e7
+81
+81
+e7
+e7
+e7
+e7
+e7
+7e
+3c
+18
+00
+ENDCHAR
+STARTCHAR CC1
+ENCODING 193
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+e7
+c3
+e7
+e7
+e7
+c3
+a1
+81
+81
+c3
+e7
+7e
+3c
+18
+00
+ENDCHAR
+STARTCHAR CC2
+ENCODING 194
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+87
+83
+b5
+85
+85
+85
+85
+85
+85
+dd
+e1
+7e
+3c
+18
+00
+ENDCHAR
+STARTCHAR CC3
+ENCODING 195
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+81
+b9
+a9
+b9
+91
+91
+91
+95
+9d
+95
+81
+42
+24
+18
+00
+ENDCHAR
+STARTCHAR CC4
+ENCODING 196
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+ff
+ef
+bb
+ef
+c7
+ef
+c7
+bb
+bb
+bb
+c7
+7e
+3c
+18
+00
+ENDCHAR
+STARTCHAR CC5
+ENCODING 197
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+18
+3c
+7e
+ff
+7e
+66
+66
+66
+66
+66
+66
+66
+ff
+00
+00
+ENDCHAR
+STARTCHAR CC6
+ENCODING 198
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+04
+08
+00
+7e
+90
+20
+40
+80
+84
+82
+82
+42
+3c
+00
+00
+ENDCHAR
+STARTCHAR CC7
+ENCODING 199
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+7e
+ff
+7e
+00
+00
+00
+ENDCHAR
+STARTCHAR CC8
+ENCODING 200
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+6c
+92
+10
+10
+10
+10
+54
+92
+7c
+00
+00
+00
+ENDCHAR
+STARTCHAR CC9
+ENCODING 201
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+c0
+c0
+00
+00
+0c
+0c
+00
+00
+c0
+c0
+00
+00
+0c
+0c
+00
+00
+ENDCHAR
+STARTCHAR CCA
+ENCODING 202
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+55
+aa
+55
+aa
+55
+aa
+55
+aa
+55
+aa
+55
+aa
+55
+aa
+55
+aa
+ENDCHAR
+STARTCHAR CCB
+ENCODING 203
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+44
+aa
+11
+00
+44
+aa
+11
+00
+44
+aa
+11
+00
+44
+aa
+11
+ENDCHAR
+STARTCHAR CCC
+ENCODING 204
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+3c
+6e
+df
+ff
+bf
+ff
+ff
+ff
+7e
+18
+18
+3c
+7e
+00
+00
+ENDCHAR
+STARTCHAR CCD
+ENCODING 205
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+18
+3c
+7e
+7e
+7e
+7e
+7e
+3c
+18
+18
+3c
+00
+00
+ENDCHAR
+STARTCHAR CCE
+ENCODING 206
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+24
+5a
+91
+21
+42
+94
+69
+46
+82
+11
+aa
+44
+00
+00
+00
+ENDCHAR
+STARTCHAR CCF
+ENCODING 207
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+df
+df
+df
+00
+fd
+fd
+fd
+00
+df
+df
+df
+00
+fd
+fd
+fd
+ENDCHAR
+STARTCHAR CD0
+ENCODING 208
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ff
+ENDCHAR
+STARTCHAR CD1
+ENCODING 209
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+42
+00
+42
+42
+42
+ff
+7e
+7e
+7e
+7e
+ff
+00
+00
+ENDCHAR
+STARTCHAR CD2
+ENCODING 210
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+1c
+1c
+08
+3e
+49
+3e
+49
+3e
+49
+1c
+2a
+22
+22
+46
+00
+ENDCHAR
+STARTCHAR CD3
+ENCODING 211
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+48
+84
+02
+25
+18
+98
+64
+62
+14
+08
+12
+21
+42
+04
+08
+ENDCHAR
+STARTCHAR CD4
+ENCODING 212
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+38
+38
+10
+10
+10
+10
+10
+10
+10
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CD5
+ENCODING 213
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+3e
+43
+7d
+45
+45
+7e
+00
+00
+00
+ENDCHAR
+STARTCHAR CD6
+ENCODING 214
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+1c
+26
+5f
+5f
+5f
+2e
+1c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CD7
+ENCODING 215
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+10
+38
+54
+10
+10
+10
+10
+10
+10
+10
+28
+00
+00
+ENDCHAR
+STARTCHAR CD8
+ENCODING 216
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+60
+10
+48
+0c
+4c
+0c
+4c
+0c
+4c
+08
+50
+20
+40
+00
+00
+ENDCHAR
+STARTCHAR CD9
+ENCODING 217
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+7c
+fe
+92
+10
+10
+10
+10
+10
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CDA
+ENCODING 218
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+0f
+0f
+0f
+0f
+10
+a0
+40
+a0
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CDB
+ENCODING 219
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+48
+4c
+5e
+7e
+5e
+4c
+48
+40
+40
+40
+40
+40
+40
+00
+00
+ENDCHAR
+STARTCHAR CDC
+ENCODING 220
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+03
+07
+0e
+1c
+38
+b0
+40
+a0
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CDD
+ENCODING 221
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+60
+60
+60
+60
+70
+7c
+5e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CDE
+ENCODING 222
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+28
+aa
+aa
+be
+fc
+7d
+7d
+3e
+38
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CDF
+ENCODING 223
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+1c
+3e
+7f
+41
+41
+41
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CE0
+ENCODING 224
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+18
+3c
+18
+7e
+db
+db
+7e
+7e
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CE1
+ENCODING 225
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+7e
+7e
+7e
+5a
+66
+3c
+3c
+18
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CE2
+ENCODING 226
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+36
+77
+7f
+77
+7f
+77
+5d
+6b
+77
+7f
+00
+00
+00
+ENDCHAR
+STARTCHAR CE3
+ENCODING 227
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+66
+db
+b5
+2c
+56
+6a
+56
+6a
+7e
+00
+00
+00
+ENDCHAR
+STARTCHAR CE4
+ENCODING 228
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+66
+db
+b5
+2c
+56
+6a
+56
+6a
+7e
+00
+00
+00
+ENDCHAR
+STARTCHAR CE5
+ENCODING 229
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+66
+db
+bd
+3c
+7e
+7e
+7e
+7e
+7e
+00
+00
+00
+ENDCHAR
+STARTCHAR CE6
+ENCODING 230
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+10
+10
+10
+7c
+82
+82
+92
+82
+92
+ba
+fe
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CE7
+ENCODING 231
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+1c
+22
+42
+44
+84
+82
+82
+62
+1c
+70
+d8
+a8
+d8
+70
+ENDCHAR
+STARTCHAR CE8
+ENCODING 232
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+28
+82
+10
+38
+10
+38
+44
+44
+44
+38
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CE9
+ENCODING 233
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+01
+02
+02
+00
+00
+06
+06
+0c
+0c
+18
+18
+30
+30
+60
+60
+00
+ENDCHAR
+STARTCHAR CEA
+ENCODING 234
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+22
+24
+28
+80
+50
+10
+08
+08
+04
+04
+02
+02
+00
+00
+00
+ENDCHAR
+STARTCHAR CEB
+ENCODING 235
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+08
+10
+42
+24
+00
+18
+18
+18
+18
+18
+18
+18
+00
+00
+00
+ENDCHAR
+STARTCHAR CEC
+ENCODING 236
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+3f
+7d
+46
+7c
+44
+7c
+4c
+7c
+54
+7c
+fc
+00
+00
+00
+ENDCHAR
+STARTCHAR CED
+ENCODING 237
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+3c
+00
+18
+18
+18
+3c
+6e
+5e
+5e
+5e
+7e
+7e
+7e
+00
+00
+ENDCHAR
+STARTCHAR CEE
+ENCODING 238
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+38
+7c
+fe
+fe
+10
+10
+38
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CEF
+ENCODING 239
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+7c
+7e
+7d
+55
+7d
+4d
+7d
+7d
+7d
+7d
+7d
+43
+3f
+00
+ENDCHAR
+STARTCHAR CF0
+ENCODING 240
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+92
+54
+01
+98
+3d
+bc
+19
+40
+82
+29
+48
+00
+00
+00
+ENDCHAR
+STARTCHAR CF1
+ENCODING 241
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+01
+02
+08
+7b
+78
+08
+02
+01
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CF2
+ENCODING 242
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+10
+38
+7c
+fe
+fe
+7c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CF3
+ENCODING 243
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+3c
+76
+c1
+d7
+c1
+f5
+c1
+76
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CF4
+ENCODING 244
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+28
+28
+82
+44
+00
+7c
+c6
+7c
+38
+10
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CF5
+ENCODING 245
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+38
+10
+10
+10
+10
+38
+54
+92
+38
+54
+92
+30
+00
+00
+ENDCHAR
+STARTCHAR CF6
+ENCODING 246
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+3c
+18
+24
+42
+42
+7e
+7e
+3c
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CF7
+ENCODING 247
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+08
+0c
+0e
+0a
+0a
+0c
+08
+78
+f8
+70
+00
+00
+00
+ENDCHAR
+STARTCHAR CF8
+ENCODING 248
+SWIDTH 480 0
+DWIDTH 8 0
+BBX 8 16 0 -2
+BITMAP
+00
+00
+00
+00
+3c
+66
+66
+0c
+18
+18
+00
+18
+18
+00
+00
+00
+ENDCHAR
+ENDFONT
diff --git a/lib/xtra/angband.fnt b/lib/xtra/angband.fnt
new file mode 100644
index 00000000..d4db7bf2
--- /dev/null
+++ b/lib/xtra/angband.fnt
Binary files differ
diff --git a/lib/xtra/font/10X20.FON b/lib/xtra/font/10X20.FON
new file mode 100644
index 00000000..5a51ee9d
--- /dev/null
+++ b/lib/xtra/font/10X20.FON
Binary files differ
diff --git a/lib/xtra/font/12X24.FON b/lib/xtra/font/12X24.FON
new file mode 100644
index 00000000..7542c934
--- /dev/null
+++ b/lib/xtra/font/12X24.FON
Binary files differ
diff --git a/lib/xtra/font/5X8.FON b/lib/xtra/font/5X8.FON
new file mode 100644
index 00000000..53cdb63b
--- /dev/null
+++ b/lib/xtra/font/5X8.FON
Binary files differ
diff --git a/lib/xtra/font/6X10.FON b/lib/xtra/font/6X10.FON
new file mode 100644
index 00000000..cb93c326
--- /dev/null
+++ b/lib/xtra/font/6X10.FON
Binary files differ
diff --git a/lib/xtra/font/6X12.FON b/lib/xtra/font/6X12.FON
new file mode 100644
index 00000000..304af0b0
--- /dev/null
+++ b/lib/xtra/font/6X12.FON
Binary files differ
diff --git a/lib/xtra/font/6X13.FON b/lib/xtra/font/6X13.FON
new file mode 100644
index 00000000..9e59e40d
--- /dev/null
+++ b/lib/xtra/font/6X13.FON
Binary files differ
diff --git a/lib/xtra/font/6X13B.FON b/lib/xtra/font/6X13B.FON
new file mode 100644
index 00000000..07fa4932
--- /dev/null
+++ b/lib/xtra/font/6X13B.FON
Binary files differ
diff --git a/lib/xtra/font/6X9.FON b/lib/xtra/font/6X9.FON
new file mode 100644
index 00000000..c0913ac7
--- /dev/null
+++ b/lib/xtra/font/6X9.FON
Binary files differ
diff --git a/lib/xtra/font/7X13.FON b/lib/xtra/font/7X13.FON
new file mode 100644
index 00000000..d7f24c64
--- /dev/null
+++ b/lib/xtra/font/7X13.FON
Binary files differ
diff --git a/lib/xtra/font/7X13B.FON b/lib/xtra/font/7X13B.FON
new file mode 100644
index 00000000..6031925e
--- /dev/null
+++ b/lib/xtra/font/7X13B.FON
Binary files differ
diff --git a/lib/xtra/font/8X13.FON b/lib/xtra/font/8X13.FON
new file mode 100644
index 00000000..adf8ffaf
--- /dev/null
+++ b/lib/xtra/font/8X13.FON
Binary files differ
diff --git a/lib/xtra/font/8X13B.FON b/lib/xtra/font/8X13B.FON
new file mode 100644
index 00000000..e1d35106
--- /dev/null
+++ b/lib/xtra/font/8X13B.FON
Binary files differ
diff --git a/lib/xtra/font/9X15.FON b/lib/xtra/font/9X15.FON
new file mode 100644
index 00000000..7963de76
--- /dev/null
+++ b/lib/xtra/font/9X15.FON
Binary files differ
diff --git a/lib/xtra/font/9X15B.FON b/lib/xtra/font/9X15B.FON
new file mode 100644
index 00000000..ff5ab215
--- /dev/null
+++ b/lib/xtra/font/9X15B.FON
Binary files differ
diff --git a/lib/xtra/font/VeraMono.ttf b/lib/xtra/font/VeraMono.ttf
new file mode 100644
index 00000000..139f0b43
--- /dev/null
+++ b/lib/xtra/font/VeraMono.ttf
Binary files differ
diff --git a/lib/xtra/font/XM10X17.FNT b/lib/xtra/font/XM10X17.FNT
new file mode 100644
index 00000000..bf96f2c1
--- /dev/null
+++ b/lib/xtra/font/XM10X17.FNT
Binary files differ
diff --git a/lib/xtra/font/XM10X17B.FNT b/lib/xtra/font/XM10X17B.FNT
new file mode 100644
index 00000000..4df07431
--- /dev/null
+++ b/lib/xtra/font/XM10X17B.FNT
Binary files differ
diff --git a/lib/xtra/font/XM12X20.FNT b/lib/xtra/font/XM12X20.FNT
new file mode 100644
index 00000000..7d4b3ab9
--- /dev/null
+++ b/lib/xtra/font/XM12X20.FNT
Binary files differ
diff --git a/lib/xtra/font/XM12X20B.FNT b/lib/xtra/font/XM12X20B.FNT
new file mode 100644
index 00000000..d43c199d
--- /dev/null
+++ b/lib/xtra/font/XM12X20B.FNT
Binary files differ
diff --git a/lib/xtra/font/XM16X25.FNT b/lib/xtra/font/XM16X25.FNT
new file mode 100644
index 00000000..abe43d44
--- /dev/null
+++ b/lib/xtra/font/XM16X25.FNT
Binary files differ
diff --git a/lib/xtra/font/XM16X25B.FNT b/lib/xtra/font/XM16X25B.FNT
new file mode 100644
index 00000000..e676a37f
--- /dev/null
+++ b/lib/xtra/font/XM16X25B.FNT
Binary files differ
diff --git a/lib/xtra/font/XM5X8.FNT b/lib/xtra/font/XM5X8.FNT
new file mode 100644
index 00000000..1d3f5977
--- /dev/null
+++ b/lib/xtra/font/XM5X8.FNT
Binary files differ
diff --git a/lib/xtra/font/XM6X12.FNT b/lib/xtra/font/XM6X12.FNT
new file mode 100644
index 00000000..173a687f
--- /dev/null
+++ b/lib/xtra/font/XM6X12.FNT
Binary files differ
diff --git a/lib/xtra/font/XM6X12B.FNT b/lib/xtra/font/XM6X12B.FNT
new file mode 100644
index 00000000..81c2da41
--- /dev/null
+++ b/lib/xtra/font/XM6X12B.FNT
Binary files differ
diff --git a/lib/xtra/font/XM8X16B.FNT b/lib/xtra/font/XM8X16B.FNT
new file mode 100644
index 00000000..54b4e493
--- /dev/null
+++ b/lib/xtra/font/XM8X16B.FNT
Binary files differ
diff --git a/lib/xtra/font/xm4x6.fnt b/lib/xtra/font/xm4x6.fnt
new file mode 100644
index 00000000..f879fe42
--- /dev/null
+++ b/lib/xtra/font/xm4x6.fnt
Binary files differ
diff --git a/lib/xtra/font/xm8x13.fnt b/lib/xtra/font/xm8x13.fnt
new file mode 100644
index 00000000..57d2dd3c
--- /dev/null
+++ b/lib/xtra/font/xm8x13.fnt
Binary files differ
diff --git a/lib/xtra/font/xm8x13b.fnt b/lib/xtra/font/xm8x13b.fnt
new file mode 100644
index 00000000..00c25d6b
--- /dev/null
+++ b/lib/xtra/font/xm8x13b.fnt
Binary files differ
diff --git a/lib/xtra/font/xm8x16.fnt b/lib/xtra/font/xm8x16.fnt
new file mode 100644
index 00000000..0f7de641
--- /dev/null
+++ b/lib/xtra/font/xm8x16.fnt
Binary files differ
diff --git a/lib/xtra/graf/16x16.bmp b/lib/xtra/graf/16x16.bmp
new file mode 100644
index 00000000..2e6b0ebf
--- /dev/null
+++ b/lib/xtra/graf/16x16.bmp
Binary files differ
diff --git a/lib/xtra/graf/16x16.png b/lib/xtra/graf/16x16.png
new file mode 100644
index 00000000..9fc1681a
--- /dev/null
+++ b/lib/xtra/graf/16x16.png
Binary files differ
diff --git a/lib/xtra/graf/8x8.bmp b/lib/xtra/graf/8x8.bmp
new file mode 100644
index 00000000..02d2d1a9
--- /dev/null
+++ b/lib/xtra/graf/8x8.bmp
Binary files differ
diff --git a/lib/xtra/graf/8x8.png b/lib/xtra/graf/8x8.png
new file mode 100644
index 00000000..d56e9d6a
--- /dev/null
+++ b/lib/xtra/graf/8x8.png
Binary files differ
diff --git a/lib/xtra/graf/mask.bmp b/lib/xtra/graf/mask.bmp
new file mode 100644
index 00000000..fced8b05
--- /dev/null
+++ b/lib/xtra/graf/mask.bmp
Binary files differ
diff --git a/lib/xtra/graf/tome-128.png b/lib/xtra/graf/tome-128.png
new file mode 100644
index 00000000..31b79c31
--- /dev/null
+++ b/lib/xtra/graf/tome-128.png
Binary files differ
diff --git a/lib/xtra/music/delete.me b/lib/xtra/music/delete.me
new file mode 100644
index 00000000..2e65efe2
--- /dev/null
+++ b/lib/xtra/music/delete.me
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/lib/xtra/sound/Sound.cfg b/lib/xtra/sound/Sound.cfg
new file mode 100644
index 00000000..eb3a7f39
--- /dev/null
+++ b/lib/xtra/sound/Sound.cfg
@@ -0,0 +1,79 @@
+# sound.cfg
+#
+# Configuration file for the Angband sound events
+#
+# The format is:
+# name of the Angband event = list of the available sample-names seperated by spaces.
+#
+# Example:
+# hit = hit.wav hit1.wav
+#
+# Look at the definition of "angband_sound_name" in variable.c for a complete list of
+# all the available event names.
+
+[Sound]
+hit = hit.wav drop.wav hit1.wav
+miss = miss.wav miss1.wav
+flee = flee.wav
+drop = clunk.wav
+kill = kill.wav destroy.wav kill1.wav
+level = level.wav
+death = death.wav
+study =
+teleport =
+shoot =
+quaff =
+zap =
+walk =
+tpother =
+hitwall =
+eat = eat.wav
+store1 = money.wav
+store2 = money.wav
+store3 = money.wav
+store4 = money.wav
+dig = thump.wav
+opendoor = opendoor.wav
+shutdoor = shutdoor.wav
+tplevel = teleport.wav
+scroll =
+buy =
+sell =
+warn =
+rocket =
+n_kill =
+u_kill =
+quest =
+heal =
+x_heal =
+bite =
+claw =
+m_spell =
+summon =
+breath =
+ball =
+m_heal =
+atkspell =
+evil =
+touch =
+sting =
+crush =
+slime =
+wail =
+winner =
+fire =
+acid =
+elec =
+cold =
+illegal =
+fail =
+wakeup =
+invuln =
+fall =
+pain =
+destitem =
+moan =
+show =
+unused =
+explode =
+
diff --git a/lib/xtra/sound/readme.txt b/lib/xtra/sound/readme.txt
new file mode 100644
index 00000000..49bb86a1
--- /dev/null
+++ b/lib/xtra/sound/readme.txt
@@ -0,0 +1,33 @@
+New Sound Effect For Angband 2.8.1 Windows 95 (beta release)
+
+Changes since Alpha release:
+
+Altered sounds: breath.wav
+ death.wav
+ flee.wav
+ hit.wav
+ kill.wav
+
+
+New sounds: None (no new events yet)
+
+
+Useage:
+
+Unzip files into your angband 2.8.1 sounds directory EG:
+
+C:\angband-281\lib\xtra\sound
+
+That's it!
+
+If you wish to use the sounds for any other purpose or wish to include them as the default sounds
+in your variant of Angband, contact me at either:
+
+tim.haywood@ocean.co.uk or timothy.haywood@virgin.net
+
+Legal Stuff:
+
+This is a patch for Angband 2.8.1 (Windows95 Version).
+Copyright @ 1997 Tim Haywood
+Not for resale.
+Not for release with original version of Angband without permission.
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644
index 00000000..d99b4ed2
--- /dev/null
+++ b/src/.cvsignore
@@ -0,0 +1,8 @@
+.sconsign
+.gdb_history
+makefile
+tome
+tolua
+w_*.c
+TOME.EXE
+TOLUA.EXE
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 00000000..932fef4b
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,72 @@
+# Lua support code.
+ADD_SUBDIRECTORY(lua)
+
+SET(SRCS
+ main-gcu.c main-x11.c main-xaw.c main-sdl.c main-gtk2.c
+ z-rand.c z-util.c z-form.c z-virt.c z-term.c
+ variable.c tables.c plots.c util.c cave.c dungeon.c
+ melee1.c melee2.c modules.c
+ object1.c object2.c randart.c squeltch.c traps.c
+ monster1.c monster2.c monster3.c
+ xtra1.c xtra2.c skills.c powers.c gods.c
+ spells1.c spells2.c
+ status.c files.c notes.c loadsave.c
+ cmd1.c cmd2.c cmd3.c cmd4.c cmd5.c cmd6.c cmd7.c
+ help.c
+ generate.c gen_maze.c gen_evol.c wild.c levels.c store.c bldg.c
+ cmovie.c
+ wizard2.c init2.c birth.c wizard1.c init1.c main.c
+ # Lua bits:
+ lua_bind.c script.c w_mnster.c w_player.c w_play_c.c w_z_pack.c
+ w_obj.c w_util.c w_spells.c w_quest.c w_dun.c
+)
+
+# Need a few additional source files for Windows.
+if(WIN32)
+ SET(SRCS ${SRCS} main-win.c readdib.c)
+ # Resource files require a little workaround.
+ if(MINGW)
+ # Workaround for resource compilation for mingw on CMake.
+ # See http://www.cmake.org/Bug/view.php?id=4068
+ ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/angband_rc.o
+ COMMAND windres.exe -I${CMAKE_CURRENT_SOURCE_DIR}
+ -i${CMAKE_CURRENT_SOURCE_DIR}/angband.rc
+ -o ${CMAKE_CURRENT_BINARY_DIR}/angband_rc.o)
+ SET(SRCS ${SRCS} ${CMAKE_CURRENT_BINARY_DIR}/angband_rc.o)
+ else(MINGW)
+ SET(SRCS ${SRCS} angband.rc)
+ endif(MINGW)
+endif(WIN32)
+
+
+# Macro for defining tolua targets.
+MACRO(TOLUA_FILE MODULE_NAME OUTPUT_FILE_NAME)
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${OUTPUT_FILE_NAME}
+ COMMAND tolua -n ${MODULE_NAME} -o ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_NAME}.pkg
+ DEPENDS tolua ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_NAME}.pkg
+ )
+ SET_SOURCE_FILES_PROPERTIES("${OUTPUT_FILE_NAME}" PROPERTIES GENERATED TRUE)
+ENDMACRO(TOLUA_FILE)
+
+# Process all the needed modules.
+TOLUA_FILE(monster w_mnster.c)
+TOLUA_FILE(player w_player.c)
+TOLUA_FILE(player_c w_play_c.c)
+TOLUA_FILE(z_pack w_z_pack.c)
+TOLUA_FILE(object w_obj.c)
+TOLUA_FILE(util w_util.c)
+TOLUA_FILE(spells w_spells.c)
+TOLUA_FILE(quest w_quest.c)
+TOLUA_FILE(dungeon w_dun.c)
+
+# tome executable
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/lua)
+ADD_EXECUTABLE(tome ${EXECUTABLE_OPTIONS} ${SRCS})
+TARGET_LINK_LIBRARIES(tome lua ${LIBS})
+
+# Installation
+INSTALL(TARGETS tome
+ RUNTIME DESTINATION games
+)
diff --git a/src/ENGLISH.txt b/src/ENGLISH.txt
new file mode 100644
index 00000000..354aa129
--- /dev/null
+++ b/src/ENGLISH.txt
@@ -0,0 +1,35 @@
+ English Text Style
+
+* Use British spelling in preference to American spelling. Quotations,
+ however, should be left intact.
+
+* Capitalize the name of spells and special powers as you would the
+ title of a book.
+
+* Avoid unnecessary modernisms. This helps preserve the mood -- an
+ item "allows", rather than "enables", you to do something.
+
+* When describing a person possessing an item, use "its wielder" or
+ "its wearer" in preference to "the wielder" or "the wearer".
+
+* When describing a gendered person of indeterminate gender, use
+ masculine terms. "This icy sword increases its wielder's statistics
+ and sustains his strength."
+
+* Use the British Imperial system for measurements. This means feet
+ and inches, not meters and centimeters.
+
+
+ Specific Issues
+
+* Use "hit points", not "hitpoints".
+
+* Use "Long Sword", not "Long-sword" or "Longsword".
+
+* Use "Middle-earth", not "middle-earth" or "Middle Earth".
+
+* Use "staves", not "staffs".
+
+* Use "dwarves", not "dwarfs".
+
+-- markrax (Mark Schreiber) <mark7@andrew.cmu.edu>
diff --git a/src/angband.h b/src/angband.h
new file mode 100644
index 00000000..cac38122
--- /dev/null
+++ b/src/angband.h
@@ -0,0 +1,110 @@
+/* File: angband.h */
+
+/* Main "Angband" header file */
+
+#ifndef INCLUDED_ANGBAND_H
+#define INCLUDED_ANGBAND_H
+
+/*
+ * Copyright (c) 1989 James E. Wilson
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+
+/*
+ * C++ guard.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * First, include the low-level includes. Be sure to edit "h-config.h"
+ * to reflect any hardware, operating system, or compiler nuances.
+ */
+#include "h-basic.h"
+
+
+/*
+ * Then, include the header files for the low-level code
+ */
+#include "z-util.h"
+#include "z-virt.h"
+#include "z-form.h"
+#include "z-rand.h"
+#include "z-term.h"
+
+
+/*
+ * Include the "Angband" configuration header
+ */
+#include "config.h"
+
+
+/*
+ * Now, include the define's, the type's, and the extern's
+ */
+#include "defines.h"
+#include "types.h"
+#include "externs.h"
+#include "plots.h"
+
+/***** Some copyright messages follow below *****/
+
+/*
+ * Note that these copyright messages apply to an ancient version
+ * of Angband, as in, from pre-2.4.frog-knows days, and thus the
+ * reference to "5.0" is rather misleading...
+ */
+
+/*
+ * UNIX ANGBAND Version 5.0
+ */
+
+
+/* Original copyright message follows. */
+
+/*
+ * ANGBAND Version 4.8 COPYRIGHT (c) Robert Alan Koeneke
+ *
+ * I lovingly dedicate this game to hackers and adventurers
+ * everywhere...
+ *
+ * Designer and Programmer:
+ * Robert Alan Koeneke
+ * University of Oklahoma
+ *
+ * Assistant Programmer:
+ * Jimmey Wayne Todd
+ * University of Oklahoma
+ *
+ * Assistant Programmer:
+ * Gary D. McAdoo
+ * University of Oklahoma
+ *
+ * UNIX Port:
+ * James E. Wilson
+ * UC Berkeley
+ * wilson@ernie.Berkeley.EDU
+ * ucbvax!ucbernie!wilson
+ */
+
+
+/*
+ * ANGBAND may be copied and modified freely as long as the above
+ * credits are retained. No one who-so-ever may sell or market
+ * this software in any form without the expressed written consent
+ * of the author Robert Alan Koeneke.
+ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+
+
+
diff --git a/src/angband.ico b/src/angband.ico
new file mode 100644
index 00000000..d20d4c7f
--- /dev/null
+++ b/src/angband.ico
Binary files differ
diff --git a/src/angband.rc b/src/angband.rc
new file mode 100644
index 00000000..00e16516
--- /dev/null
+++ b/src/angband.rc
@@ -0,0 +1,132 @@
+/* File: angband.rc */
+
+/*
+ * If the windows command to compile this file understands #ifdef's, please
+ * say #ifdef ALLOW_QUITTING to select from "A&bort" and "Sh&ow scores"
+ */
+
+ANGBAND MENU
+{
+ POPUP "&File"
+ {
+ MENUITEM "&Save", 110
+ MENUITEM SEPARATOR
+ MENUITEM "S&how score", 120
+ /*MENUITEM "A&bort", 120*/
+ MENUITEM "E&xit", 121
+ }
+
+ POPUP "&Window"
+ {
+ POPUP "&Visibility"
+ {
+ MENUITEM "ToME window", 200
+ MENUITEM "Mirror window", 201
+ MENUITEM "Recall window", 202
+ MENUITEM "Choice window", 203
+ MENUITEM "Term-4 window", 204
+ MENUITEM "Term-5 window", 205
+ MENUITEM "Term-6 window", 206
+ MENUITEM "Term-7 window", 207
+ }
+
+ POPUP "&Font"
+ {
+ MENUITEM "ToME window", 210
+ MENUITEM "Mirror window", 211
+ MENUITEM "Recall window", 212
+ MENUITEM "Choice window", 213
+ MENUITEM "Term-4 window", 214
+ MENUITEM "Term-5 window", 215
+ MENUITEM "Term-6 window", 216
+ MENUITEM "Term-7 window", 217
+ }
+
+ MENUITEM SEPARATOR
+
+ POPUP "Bizarre Display"
+ {
+ MENUITEM "ToME window", 230
+ MENUITEM "Mirror window", 231
+ MENUITEM "Recall window", 232
+ MENUITEM "Choice window", 233
+ MENUITEM "Term-4 window", 234
+ MENUITEM "Term-5 window", 235
+ MENUITEM "Term-6 window", 236
+ MENUITEM "Term-7 window", 237
+ }
+
+ POPUP "Increase Tile Width"
+ {
+ MENUITEM "ToME window", 240
+ MENUITEM "Mirror window", 241
+ MENUITEM "Recall window", 242
+ MENUITEM "Choice window", 243
+ MENUITEM "Term-4 window", 244
+ MENUITEM "Term-5 window", 245
+ MENUITEM "Term-6 window", 246
+ MENUITEM "Term-7 window", 247
+ }
+
+ POPUP "Decrease Tile Width"
+ {
+ MENUITEM "ToME window", 250
+ MENUITEM "Mirror window", 251
+ MENUITEM "Recall window", 252
+ MENUITEM "Choice window", 253
+ MENUITEM "Term-4 window", 254
+ MENUITEM "Term-5 window", 255
+ MENUITEM "Term-6 window", 256
+ MENUITEM "Term-7 window", 257
+ }
+
+ POPUP "Increase Tile Height"
+ {
+ MENUITEM "ToME window", 260
+ MENUITEM "Mirror window", 261
+ MENUITEM "Recall window", 262
+ MENUITEM "Choice window", 263
+ MENUITEM "Term-4 window", 264
+ MENUITEM "Term-5 window", 265
+ MENUITEM "Term-6 window", 266
+ MENUITEM "Term-7 window", 267
+ }
+
+ POPUP "Decrease Tile Height"
+ {
+ MENUITEM "ToME window", 270
+ MENUITEM "Mirror window", 271
+ MENUITEM "Recall window", 272
+ MENUITEM "Choice window", 273
+ MENUITEM "Term-4 window", 274
+ MENUITEM "Term-5 window", 275
+ MENUITEM "Term-6 window", 276
+ MENUITEM "Term-7 window", 277
+ }
+ }
+
+ POPUP "&Options"
+ {
+ POPUP "&Graphics"
+ {
+ MENUITEM "&Old tiles", 400
+ MENUITEM "&New tiles", 401
+ MENUITEM "ASCII &Text", 403
+ MENUITEM "&Bigtile mode", 409
+ }
+
+ MENUITEM "&Sound", 402
+ MENUITEM SEPARATOR
+ MENUITEM "Unused menu option", 410
+ MENUITEM "Activate Screensaver", 411
+ }
+
+ POPUP "&Help"
+ {
+ MENUITEM "&General", 901
+ MENUITEM "&Spoilers", 902
+ }
+}
+
+ANGBAND ICON "angband.ico"
+
diff --git a/src/birth.c b/src/birth.c
new file mode 100644
index 00000000..f073b2f6
--- /dev/null
+++ b/src/birth.c
@@ -0,0 +1,3825 @@
+/* File: birth.c */
+
+/* Purpose: create a player character */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * How often the autoroller will update the display and pause
+ * to check for user interuptions.
+ * Bigger values will make the autoroller faster, but slower
+ * system may have problems because the user can't stop the
+ * autoroller for this number of rolls.
+ */
+#define AUTOROLLER_STEP 25L
+
+/*
+ * Maximum number of tries for selection of a proper quest monster
+ */
+#define MAX_TRIES 100
+
+/* Max quests */
+static byte max_quests = 0;
+
+/*
+ * Current stats
+ */
+static s16b stat_use[6];
+
+/*
+ * Autoroll limit
+ */
+static s16b stat_limit[6];
+
+/*
+ * Autoroll matches
+ */
+static s32b stat_match[6];
+
+/*
+ * Autoroll round
+ */
+static s32b auto_round;
+
+/*
+ * Last round
+ */
+static s32b last_round;
+
+/* Human */
+static char *human_syllable1[] =
+{
+ "Ab", "Ac", "Ad", "Af", "Agr", "Ast", "As", "Al", "Adw", "Adr", "Ar",
+ "B", "Br", "C", "Cr", "Ch", "Cad", "D", "Dr", "Dw", "Ed", "Eth", "Et",
+ "Er", "El", "Eow", "F", "Fr", "G", "Gr", "Gw", "Gal", "Gl", "H", "Ha",
+ "Ib", "Jer", "K", "Ka", "Ked", "L", "Loth", "Lar", "Leg", "M", "Mir",
+ "N", "Nyd", "Ol", "Oc", "On", "P", "Pr", "R", "Rh", "S", "Sev", "T",
+ "Tr", "Th", "V", "Y", "Z", "W", "Wic",
+};
+
+static char *human_syllable2[] =
+{
+ "a", "ae", "au", "ao", "are", "ale", "ali", "ay", "ardo", "e", "ei",
+ "ea", "eri", "era", "ela", "eli", "enda", "erra", "i", "ia", "ie",
+ "ire", "ira", "ila", "ili", "ira", "igo", "o", "oa", "oi", "oe",
+ "ore", "u", "y",
+};
+
+static char *human_syllable3[] =
+{
+ "a", "and", "b", "bwyn", "baen", "bard", "c", "ctred", "cred", "ch",
+ "can", "d", "dan", "don", "der", "dric", "dfrid", "dus", "f", "g",
+ "gord", "gan", "l", "li", "lgrin", "lin", "lith", "lath", "loth",
+ "ld", "ldric", "ldan", "m", "mas", "mos", "mar", "mond", "n",
+ "nydd", "nidd", "nnon", "nwan", "nyth", "nad", "nn", "nnor", "nd",
+ "p", "r", "ron", "rd", "s", "sh", "seth", "sean", "t", "th", "tha",
+ "tlan", "trem", "tram", "v", "vudd", "w", "wan", "win", "wyn", "wyr",
+ "wyr", "wyth",
+};
+
+/*
+ * Random Name Generator
+ * based on a Javascript by Michael Hensley
+ * "http://geocities.com/timessquare/castle/6274/"
+ */
+static void create_random_name(int race, char *name)
+{
+ char *syl1, *syl2, *syl3;
+
+ int idx;
+
+
+ /* Paranoia */
+ if (!name) return;
+
+ /* Select the monster type */
+ switch (race)
+ {
+ /* Create the monster name */
+
+ /* Use human ones */
+ default:
+ {
+ idx = rand_int(sizeof(human_syllable1) / sizeof(char *));
+ syl1 = human_syllable1[idx];
+ idx = rand_int(sizeof(human_syllable2) / sizeof(char *));
+ syl2 = human_syllable2[idx];
+ idx = rand_int(sizeof(human_syllable3) / sizeof(char *));
+ syl3 = human_syllable3[idx];
+
+ break;
+ }
+ }
+
+ /* Concatenate selected syllables */
+ strnfmt(name, 32, "%s%s%s", syl1, syl2, syl3);
+}
+
+
+void print_desc_aux(cptr txt, int y, int xx)
+{
+ int i = -1, x = xx;
+
+
+ while (txt[++i] != 0)
+ {
+ if (txt[i] == '\n')
+ {
+ x = xx;
+ y++;
+ }
+ else
+ {
+ Term_putch(x++, y, TERM_YELLOW, txt[i]);
+ }
+ }
+}
+
+void print_desc(cptr txt)
+{
+ print_desc_aux(txt, 12, 1);
+}
+
+/*
+ * Save the current data for later
+ */
+static void save_prev_data(void)
+{
+ int i;
+
+
+ /*** Save the current data ***/
+
+ /* Save the data */
+ previous_char.sex = p_ptr->psex;
+ previous_char.race = p_ptr->prace;
+ previous_char.rmod = p_ptr->pracem;
+ previous_char.pclass = p_ptr->pclass;
+ previous_char.spec = p_ptr->pspec;
+
+ previous_char.quests = max_quests;
+
+ previous_char.god = p_ptr->pgod;
+ previous_char.grace = p_ptr->grace;
+
+ previous_char.age = p_ptr->age;
+ previous_char.wt = p_ptr->wt;
+ previous_char.ht = p_ptr->ht;
+ previous_char.sc = p_ptr->sc;
+ previous_char.au = p_ptr->au;
+
+ /* Save the stats */
+ for (i = 0; i < 6; i++)
+ {
+ previous_char.stat[i] = p_ptr->stat_max[i];
+ }
+ previous_char.luck = p_ptr->luck_base;
+
+ /* Save the chaos patron */
+ previous_char.chaos_patron = p_ptr->chaos_patron;
+
+ /* Save the weapon specialty */
+ previous_char.weapon = 0;
+
+ /* Save the history */
+ for (i = 0; i < 4; i++)
+ {
+ strcpy(previous_char.history[i], history[i]);
+ }
+}
+
+
+/*
+ * Load the previous data
+ */
+static void load_prev_data(bool_ save)
+{
+ int i;
+
+ birther temp;
+
+
+ /*** Save the current data ***/
+
+ /* Save the data */
+ temp.age = p_ptr->age;
+ temp.wt = p_ptr->wt;
+ temp.ht = p_ptr->ht;
+ temp.sc = p_ptr->sc;
+ temp.au = p_ptr->au;
+
+ /* Save the stats */
+ for (i = 0; i < 6; i++)
+ {
+ temp.stat[i] = p_ptr->stat_max[i];
+ }
+ temp.luck = p_ptr->luck_base;
+
+ /* Save the chaos patron */
+ temp.chaos_patron = p_ptr->chaos_patron;
+
+ /* Save the weapon specialty */
+ temp.weapon = 0;
+
+ /* Save the history */
+ for (i = 0; i < 4; i++)
+ {
+ strcpy(temp.history[i], history[i]);
+ }
+
+
+ /*** Load the previous data ***/
+
+ /* Load the data */
+ p_ptr->age = previous_char.age;
+ p_ptr->wt = previous_char.wt;
+ p_ptr->ht = previous_char.ht;
+ p_ptr->sc = previous_char.sc;
+ p_ptr->au = previous_char.au;
+
+ /* Load the stats */
+ for (i = 0; i < 6; i++)
+ {
+ p_ptr->stat_max[i] = previous_char.stat[i];
+ p_ptr->stat_cur[i] = previous_char.stat[i];
+ }
+ p_ptr->luck_base = previous_char.luck;
+ p_ptr->luck_max = previous_char.luck;
+
+ /* Load the chaos patron */
+ p_ptr->chaos_patron = previous_char.chaos_patron;
+
+ /* Load the history */
+ for (i = 0; i < 4; i++)
+ {
+ strcpy(history[i], previous_char.history[i]);
+ }
+
+
+ /*** Save the current data ***/
+ if (!save) return;
+
+ /* Save the data */
+ previous_char.age = temp.age;
+ previous_char.wt = temp.wt;
+ previous_char.ht = temp.ht;
+ previous_char.sc = temp.sc;
+ previous_char.au = temp.au;
+
+ /* Save the stats */
+ for (i = 0; i < 6; i++)
+ {
+ previous_char.stat[i] = temp.stat[i];
+ }
+ previous_char.luck = temp.luck;
+
+ /* Save the chaos patron */
+ previous_char.chaos_patron = temp.chaos_patron;
+
+ /* Save the weapon specialty */
+ previous_char.weapon = temp.weapon;
+
+ /* Save the history */
+ for (i = 0; i < 4; i++)
+ {
+ strcpy(previous_char.history[i], temp.history[i]);
+ }
+}
+
+
+
+
+/*
+ * Returns adjusted stat -JK- Algorithm by -JWT-
+ *
+ * auto_roll is boolean and states maximum changes should be used rather
+ * than random ones to allow specification of higher values to wait for
+ *
+ * The "p_ptr->maximize" code is important -BEN-
+ */
+static int adjust_stat(int value, int amount, int auto_roll)
+{
+ int i;
+
+
+ /* Negative amounts */
+ if (amount < 0)
+ {
+ /* Apply penalty */
+ for (i = 0; i < (0 - amount); i++)
+ {
+ if (value >= 18 + 10)
+ {
+ value -= 10;
+ }
+ else if (value > 18)
+ {
+ value = 18;
+ }
+ else if (value > 3)
+ {
+ value--;
+ }
+ }
+ }
+
+ /* Positive amounts */
+ else if (amount > 0)
+ {
+ /* Apply reward */
+ for (i = 0; i < amount; i++)
+ {
+ if (value < 18)
+ {
+ value++;
+ }
+ else if (p_ptr->maximize)
+ {
+ value += 10;
+ }
+ else if (value < 18 + 70)
+ {
+ value += ((auto_roll ? 15 : randint(15)) + 5);
+ }
+ else if (value < 18 + 90)
+ {
+ value += ((auto_roll ? 6 : randint(6)) + 2);
+ }
+ else if (value < 18 + 100)
+ {
+ value++;
+ }
+ }
+ }
+
+ /* Return the result */
+ return (value);
+}
+
+
+
+
+/*
+ * Roll for a characters stats
+ *
+ * For efficiency, we include a chunk of "calc_bonuses()".
+ */
+static void get_stats(void)
+{
+ int i, j;
+
+ int bonus;
+
+ int dice[18];
+
+
+ /* Roll and verify some stats */
+ while (TRUE)
+ {
+ /* Roll some dice */
+ for (j = i = 0; i < 18; i++)
+ {
+ /* Roll the dice */
+ dice[i] = randint(3 + i % 3);
+
+ /* Collect the maximum */
+ j += dice[i];
+ }
+
+ /*
+ * Verify totals
+ *
+ * 57 was 54... I hate 'magic numbers' :< TY
+ *
+ * (d3 + d4 + d5) ~= 7.5 (+- 4.5)
+ * with 5 makes avg. stat value of 12.5 (min 8, max 17)
+ *
+ * (d3 + d4 + d5) x 6 ~= 45 (+- 18)
+ *
+ * So the original value (still used by Vanilla as of 2.9.3)
+ * allows (avg - 2)..(avg + 8), while this Z version
+ * (avg - 2)..(avg + 11). I don't understand what TY meant
+ * by "magic numbers", but I like big stats :) -- pelpel
+ *
+ */
+ if ((j > 42) && (j < 57)) break;
+ }
+
+ /* Acquire the stats */
+ for (i = 0; i < 6; i++)
+ {
+ /* Extract 5 + 1d3 + 1d4 + 1d5 */
+ j = 5 + dice[3 * i] + dice[3 * i + 1] + dice[3 * i + 2];
+
+ /* Save that value */
+ p_ptr->stat_max[i] = j;
+
+ /* Obtain a "bonus" for "race" and "class" */
+ bonus = rp_ptr->r_adj[i] + rmp_ptr->r_adj[i] + cp_ptr->c_adj[i];
+
+ /* Variable stat maxes */
+ if (p_ptr->maximize)
+ {
+ /* Start fully healed */
+ p_ptr->stat_cur[i] = p_ptr->stat_max[i];
+
+ /* Efficiency -- Apply the racial/class bonuses */
+ stat_use[i] = modify_stat_value(p_ptr->stat_max[i], bonus);
+ }
+
+ /* Fixed stat maxes */
+ else
+ {
+ /* Apply the bonus to the stat (somewhat randomly) */
+ stat_use[i] = adjust_stat(p_ptr->stat_max[i], bonus, FALSE);
+
+ /* Save the resulting stat maximum */
+ p_ptr->stat_cur[i] = p_ptr->stat_max[i] = stat_use[i];
+ }
+
+ /* No temporary drain (yet...) */
+ p_ptr->stat_cnt[i] = 0;
+ p_ptr->stat_los[i] = 0;
+ }
+
+ /* Get luck */
+ p_ptr->luck_base = rp_ptr->luck + rmp_ptr->luck + rand_range( -5, 5);
+ p_ptr->luck_max = p_ptr->luck_base;
+}
+
+
+/*
+ * Roll for some info that the auto-roller ignores
+ */
+static void get_extra(void)
+{
+ int i, j, min_value, max_value;
+
+#ifdef SHOW_LIFE_RATE
+
+ int percent;
+
+#endif
+
+
+ /* Level one */
+ p_ptr->max_plv = p_ptr->lev = 1;
+
+ /* Experience factor */
+ p_ptr->expfact = rp_ptr->r_exp + rmp_ptr->r_exp + cp_ptr->c_exp;
+
+ /* Initialize arena and rewards information -KMW- */
+ p_ptr->arena_number = 0;
+ p_ptr->inside_arena = 0;
+ p_ptr->inside_quest = 0;
+ p_ptr->exit_bldg = TRUE; /* only used for arena now -KMW- */
+
+ /* Hitdice */
+ p_ptr->hitdie = rp_ptr->r_mhp + rmp_ptr->r_mhp + cp_ptr->c_mhp;
+
+ /* Initial hitpoints */
+ p_ptr->mhp = p_ptr->hitdie;
+
+ /* Minimum hitpoints at highest level */
+ min_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 3) / 8;
+ min_value += PY_MAX_LEVEL;
+
+ /* Maximum hitpoints at highest level */
+ max_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 5) / 8;
+ max_value += PY_MAX_LEVEL;
+
+ /* Pre-calculate level 1 hitdice */
+ player_hp[0] = p_ptr->hitdie;
+
+ /* Roll out the hitpoints */
+ while (TRUE)
+ {
+ /* Roll the hitpoint values */
+ for (i = 1; i < PY_MAX_LEVEL; i++)
+ {
+ j = randint(p_ptr->hitdie);
+ player_hp[i] = player_hp[i - 1] + j;
+ }
+
+ /* XXX Could also require acceptable "mid-level" hitpoints */
+
+ /* Require "valid" hitpoints at highest level */
+ if (player_hp[PY_MAX_LEVEL - 1] < min_value) continue;
+ if (player_hp[PY_MAX_LEVEL - 1] > max_value) continue;
+
+ /* Acceptable */
+ break;
+ }
+
+ p_ptr->tactic = 4;
+ p_ptr->movement = 4;
+
+#ifdef SHOW_LIFE_RATE
+
+ percent = (int)(((long)player_hp[PY_MAX_LEVEL - 1] * 200L) /
+ (p_ptr->hitdie + ((PY_MAX_LEVEL - 1) * p_ptr->hitdie)));
+
+ msg_format("Current Life Rating is %d/100.", percent);
+ msg_print(NULL);
+
+#endif /* SHOW_LIFE_RATE */
+}
+
+
+/*
+ * Get the racial history, and social class, using the "history charts".
+ */
+static void get_history(void)
+{
+ int i, n, chart, roll, social_class;
+
+ char *s, *t;
+
+ char buf[240];
+
+
+ /* Clear the previous history strings */
+ for (i = 0; i < 4; i++) history[i][0] = '\0';
+
+ /* Clear the history text */
+ buf[0] = '\0';
+
+ /* Initial social class */
+ social_class = randint(4);
+
+ /* Starting place */
+ chart = rp_ptr->chart;
+
+ /* Process the history */
+ while (chart)
+ {
+ /* Start over */
+ i = 0;
+
+ /* Roll for nobility */
+ roll = randint(100);
+
+
+ /* Access the proper entry in the table */
+ while ((chart != bg[i].chart) || (roll > bg[i].roll)) i++;
+
+ /* Acquire the textual history */
+ (void)strcat(buf, bg[i].info + rp_text);
+
+ /* Add in the social class */
+ social_class += (int)(bg[i].bonus) - 50;
+
+ /* Enter the next chart */
+ chart = bg[i].next;
+ }
+
+
+
+ /* Verify social class */
+ if (social_class > 100) social_class = 100;
+ else if (social_class < 1) social_class = 1;
+
+ /* Save the social class */
+ p_ptr->sc = social_class;
+
+
+ /* Skip leading spaces */
+ for (s = buf; *s == ' '; s++) /* loop */;
+
+ /* Get apparent length */
+ n = strlen(s);
+
+ /* Kill trailing spaces */
+ while ((n > 0) && (s[n - 1] == ' ')) s[--n] = '\0';
+
+
+ /* Start at first line */
+ i = 0;
+
+ /* Collect the history */
+ while (TRUE)
+ {
+ /* Extract remaining length */
+ n = strlen(s);
+
+ /* All done */
+ if (n < 60)
+ {
+ /* Save one line of history */
+ strcpy(history[i++], s);
+
+ /* All done */
+ break;
+ }
+
+ /* Find a reasonable break-point */
+ for (n = 60; ((n > 0) && (s[n - 1] != ' ')); n--) /* loop */;
+
+ /* Save next location */
+ t = s + n;
+
+ /* Wipe trailing spaces */
+ while ((n > 0) && (s[n - 1] == ' ')) s[--n] = '\0';
+
+ /* Save one line of history */
+ strcpy(history[i++], s);
+
+ /* Start next line */
+ for (s = t; *s == ' '; s++) /* loop */;
+ }
+}
+
+
+/*
+ * Fill the random_artifacts array with relevant info.
+ */
+errr init_randart(void)
+{
+ int i;
+
+ long cost;
+
+ random_artifact* ra_ptr;
+
+ char buf[80];
+
+
+ for (i = 0; i < MAX_RANDARTS; i++)
+ {
+ ra_ptr = &random_artifacts[i];
+
+ strcpy(ra_ptr->name_short,
+ get_line("rart_s.txt", ANGBAND_DIR_FILE, buf, i));
+ strcpy(ra_ptr->name_full,
+ get_line("rart_f.txt", ANGBAND_DIR_FILE, buf, i));
+
+ ra_ptr->attr = randint(15);
+ ra_ptr->activation = rand_int(MAX_T_ACT);
+ ra_ptr->generated = FALSE;
+
+ cost = randnor(0, 250);
+
+ if (cost < 0) cost = 0;
+
+ ra_ptr->cost = cost;
+ }
+
+ return 0;
+}
+
+
+/*
+ * A helper function for get_ahw(), also called by polymorph code
+ */
+void get_height_weight(void)
+{
+ int h_mean, h_stddev;
+
+ int w_mean, w_stddev;
+
+
+ /* Extract mean and standard deviation -- Male */
+ if (p_ptr->psex == SEX_MALE)
+ {
+ h_mean = rp_ptr->m_b_ht + rmp_ptr->m_b_ht;
+ h_stddev = rp_ptr->m_m_ht + rmp_ptr->m_m_ht;
+
+ w_mean = rp_ptr->m_b_wt + rmp_ptr->m_b_wt;
+ w_stddev = rp_ptr->m_m_wt + rmp_ptr->m_m_wt;
+ }
+
+ /* Female */
+ else if (p_ptr->psex == SEX_FEMALE)
+ {
+ h_mean = rp_ptr->f_b_ht + rmp_ptr->f_b_ht;
+ h_stddev = rp_ptr->f_m_ht + rmp_ptr->f_m_ht;
+
+ w_mean = rp_ptr->f_b_wt + rmp_ptr->f_b_wt;
+ w_stddev = rp_ptr->f_m_wt + rmp_ptr->f_m_wt;
+ }
+
+ /* Neuter XXX */
+ else
+ {
+ h_mean = (rp_ptr->m_b_ht + rmp_ptr->m_b_ht +
+ rp_ptr->f_b_ht + rmp_ptr->f_b_ht) / 2,
+ h_stddev = (rp_ptr->m_m_ht + rmp_ptr->m_m_ht +
+ rp_ptr->f_m_ht + rmp_ptr->f_m_ht) / 2;
+
+ w_mean = (rp_ptr->m_b_wt + rmp_ptr->m_b_wt +
+ rp_ptr->f_b_wt + rmp_ptr->f_b_wt) / 2,
+ w_stddev = (rp_ptr->m_m_wt + rmp_ptr->m_m_wt +
+ rp_ptr->f_m_wt + rmp_ptr->f_m_wt) / 2;
+ }
+
+ /* Calculate height/weight */
+ p_ptr->ht = randnor(h_mean, h_stddev);
+ p_ptr->wt = randnor(w_mean, w_stddev);
+
+ /* Weight/height shouldn't be negative */
+ if (p_ptr->ht < 1) p_ptr->ht = 1;
+ if (p_ptr->wt < 1) p_ptr->wt = 1;
+}
+
+
+/*
+ * Computes character's age, height, and weight
+ */
+static void get_ahw(void)
+{
+ /* Calculate the age */
+ p_ptr->age = rp_ptr->b_age + rmp_ptr->b_age +
+ randint(rp_ptr->m_age + rmp_ptr->m_age);
+
+ /* Calculate the height/weight */
+ get_height_weight();
+}
+
+
+
+
+/*
+ * Get the player's starting money
+ */
+static void get_money(void)
+{
+ int i, gold;
+
+
+ /* Social Class determines starting gold */
+ gold = (p_ptr->sc * 6) + randint(100) + 300;
+
+ /* Process the stats */
+ for (i = 0; i < 6; i++)
+ {
+ /* Mega-Hack -- reduce gold for high stats */
+ if (stat_use[i] >= 18 + 50) gold -= 300;
+ else if (stat_use[i] >= 18 + 20) gold -= 200;
+ else if (stat_use[i] > 18) gold -= 150;
+ else gold -= (stat_use[i] - 8) * 10;
+ }
+
+ /* Minimum 100 gold */
+ if (gold < 100) gold = 100;
+
+ /* Save the gold */
+ p_ptr->au = gold;
+}
+
+
+
+/*
+ * Display stat values, subset of "put_stats()"
+ *
+ * See 'display_player()' for basic method.
+ */
+static void birth_put_stats(void)
+{
+ int i, p;
+
+ byte attr;
+
+ char buf[80];
+
+
+ /* Put the stats (and percents) */
+ for (i = 0; i < 6; i++)
+ {
+ /* Put the stat */
+ cnv_stat(p_ptr->stat_use[i], buf);
+ c_put_str(TERM_L_GREEN, buf, 2 + i, 66);
+
+ /* Put the percent */
+ if (stat_match[i])
+ {
+ p = 1000L * stat_match[i] / auto_round;
+ attr = (p < 100) ? TERM_YELLOW : TERM_L_GREEN;
+ strnfmt(buf, 80, "%3d.%d%%", p / 10, p % 10);
+ c_put_str(attr, buf, 2 + i, 73);
+ }
+
+ /* Never happened */
+ else
+ {
+ c_put_str(TERM_RED, "(NONE)", 2 + i, 73);
+ }
+ }
+}
+
+
+/*
+ * Clear all the global "character" data
+ */
+static void player_wipe(void)
+{
+ int i, j;
+
+ bool_ *powers;
+ bool_ *corruptions;
+
+
+ /* Wipe special levels */
+ wipe_saved();
+
+ /* Save the powers & corruptions */
+ powers = p_ptr->powers;
+ corruptions = p_ptr->corruptions;
+
+ /* Hack -- zero the struct */
+ p_ptr = WIPE(p_ptr, player_type);
+
+ /* Restore the powers & corruptions */
+ p_ptr->powers = powers;
+ p_ptr->corruptions = corruptions;
+
+ /* Not dead yet */
+ p_ptr->lives = 0;
+
+ /* Wipe the corruptions */
+ (void)C_WIPE(p_ptr->corruptions, max_corruptions, bool_);
+
+ /* Wipe the history */
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 60; j++)
+ {
+ if (j < 59) history[i][j] = ' ';
+ else history[i][j] = '\0';
+ }
+ }
+
+ /* Wipe the towns */
+ for (i = 0; i < max_d_idx; i++)
+ {
+ for (j = 0; j < MAX_DUNGEON_DEPTH; j++)
+ {
+ special_lvl[j][i] = 0;
+ }
+ }
+
+ /* Wipe the towns */
+ for (i = max_real_towns + 1; i < max_towns; i++)
+ {
+ town_info[i].flags = 0;
+ }
+
+ /* Wipe the quests */
+ for (i = 0; i < MAX_Q_IDX_INIT; i++)
+ {
+ quest[i].status = QUEST_STATUS_UNTAKEN;
+ for (j = 0; j < 4; j++)
+ {
+ quest[i].data[j] = 0;
+ }
+ }
+
+ /* Wipe the rune spells */
+ rune_num = 0;
+ for (i = 0; i < MAX_RUNES; i++)
+ {
+ strcpy(rune_spells[i].name, "");
+ rune_spells[i].type = 0;
+ rune_spells[i].rune2 = 0;
+ rune_spells[i].mana = 0;
+ }
+
+ /* No items */
+ inven_cnt = 0;
+ equip_cnt = 0;
+
+ /* Clear the inventory */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_wipe(&p_ptr->inventory[i]);
+ }
+
+ /* Generate random artifacts */
+ init_randart();
+
+ /* Start with no artifacts made yet */
+ for (i = 0; i < max_a_idx; i++)
+ {
+ artifact_type *a_ptr = &a_info[i];
+ a_ptr->cur_num = 0;
+ }
+
+ /* Reset the "objects" */
+ for (i = 1; i < max_k_idx; i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+
+ /* Reset "tried" */
+ k_ptr->tried = FALSE;
+
+ /* Reset "aware" */
+ k_ptr->aware = FALSE;
+
+ /* Reset "know" */
+ k_ptr->know = FALSE;
+
+ /* Reset "artifact" */
+ k_ptr->artifact = 0;
+ }
+
+
+ /* Reset the "monsters" */
+ for (i = 1; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ /* Hack -- Reset the counter */
+ r_ptr->cur_num = 0;
+
+ /* Hack -- Reset the max counter */
+ r_ptr->max_num = 100;
+
+ /* Hack -- Reset the max counter */
+ if (r_ptr->flags1 & RF1_UNIQUE) r_ptr->max_num = 1;
+ if (r_ptr->flags3 & RF3_UNIQUE_4) r_ptr->max_num = 4;
+
+ /* Clear player kills */
+ r_ptr->r_pkills = 0;
+
+ /* Clear saved flag */
+ r_ptr->on_saved = FALSE;
+ }
+
+
+ /* Hack -- Well fed player */
+ p_ptr->food = PY_FOOD_FULL - 1;
+
+ /* Wipe the alchemists' recipes */
+ for ( i = 0 ; i < 32 ; i++)
+ alchemist_known_egos[i] = 0;
+ for ( i = 0 ; i < 6 ; i++)
+ alchemist_known_artifacts[i] = 0;
+ alchemist_gained = 0;
+
+ /* Clear "cheat" options */
+ cheat_peek = FALSE;
+ cheat_hear = FALSE;
+ cheat_room = FALSE;
+ cheat_xtra = FALSE;
+ cheat_know = FALSE;
+ cheat_live = FALSE;
+
+ /* Assume no winning game */
+ total_winner = 0;
+ has_won = FALSE;
+
+ /* Assume no cheating */
+ noscore = 0;
+ wizard = 0;
+
+ /* Assume no innate spells */
+ spell_num = 0;
+
+ /* Clear the fate */
+ for (i = 0; i < MAX_FATES; i++)
+ {
+ fates[i].fate = 0;
+ }
+ p_ptr->no_mortal = FALSE;
+
+ /* Player don't have the black breath from the beginning !*/
+ p_ptr->black_breath = FALSE;
+
+ /* Default pet command settings */
+ p_ptr->pet_follow_distance = 6;
+ p_ptr->pet_open_doors = FALSE;
+ p_ptr->pet_pickup_items = FALSE;
+
+ /* Body changing initialisation */
+ p_ptr->body_monster = 0;
+ p_ptr->disembodied = FALSE;
+
+ /* Wipe the bounties */
+ total_bounties = 0;
+
+ /* Wipe spells */
+ p_ptr->xtra_spells = 0;
+
+ /* Wipe xtra hp */
+ p_ptr->hp_mod = 0;
+
+ /* Wipe the monsters */
+ wipe_m_list();
+
+ /* Wipe the doppleganger */
+ doppleganger = 0;
+
+ /* Wipe the recall depths */
+ for (i = 0; i < max_d_idx; i++)
+ {
+ max_dlv[i] = 0;
+ }
+
+ /* Wipe the known inscription list */
+ for (i = 0; i < MAX_INSCRIPTIONS; i++)
+ {
+ inscription_info[i].know = FALSE;
+ }
+
+ /* Wipe the known traps list */
+ for (i = 0; i < max_t_idx; i++)
+ {
+ t_info[i].known = 0;
+ t_info[i].ident = FALSE;
+ }
+
+ /* Reset wild_mode to FALSE */
+ p_ptr->wild_mode = FALSE;
+ p_ptr->old_wild_mode = FALSE;
+
+ /* Initialize allow_one_death */
+ p_ptr->allow_one_death = 0;
+
+ p_ptr->loan = p_ptr->loan_time = 0;
+
+ /* Wipe the power list */
+ for (i = 0; i < POWER_MAX_INIT; i++)
+ {
+ p_ptr->powers_mod[i] = 0;
+ }
+
+ /* No companions killed */
+ p_ptr->companion_killed = 0;
+}
+
+
+/* Create an object */
+void outfit_obj(int tv, int sv, int pval, int dd, int ds)
+{
+ object_type forge;
+ object_type *q_ptr;
+
+ /* Get local object */
+ q_ptr = &forge;
+ q_ptr->pval = 0;
+ q_ptr->pval2 = 0;
+
+ /* Hack -- Give the player an object */
+ object_prep(q_ptr, lookup_kind(tv, sv));
+
+ if (pval)
+ q_ptr->pval = pval;
+
+ /* These objects are "storebought" */
+ q_ptr->ident |= IDENT_MENTAL;
+ q_ptr->number = damroll(dd, ds);
+
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ (void)inven_carry(q_ptr, FALSE);
+}
+
+
+/*
+ * Init players with some belongings
+ *
+ * Having an item makes the player "aware" of its purpose.
+ */
+static void player_outfit(void)
+{
+ int i;
+
+ /*
+ * Get an adventurer guide describing a bit of the
+ * wilderness.
+ */
+ {
+ object_type forge;
+ object_type *q_ptr = &forge;
+ /* Hack -- Give the player an adventurer guide */
+ object_prep(q_ptr, lookup_kind(TV_PARCHMENT, 20));
+ q_ptr->number = 1;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ (void)inven_carry(q_ptr, FALSE);
+ }
+
+ process_hooks(HOOK_BIRTH_OBJECTS, "()");
+
+ {
+ object_type forge;
+ object_type *q_ptr = &forge;
+ /* Hack -- Give the player some food */
+ object_prep(q_ptr, lookup_kind(TV_FOOD, SV_FOOD_RATION));
+ q_ptr->number = (byte)rand_range(3, 7);
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ (void)inven_carry(q_ptr, FALSE);
+ }
+
+ {
+ object_type forge;
+ object_type *q_ptr = &forge;
+ /* Hack -- Give the player some torches */
+ object_prep(q_ptr, lookup_kind(TV_LITE, SV_LITE_TORCH));
+ q_ptr->number = (byte)rand_range(3, 7);
+ q_ptr->timeout = rand_range(3, 7) * 500;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ (void)inven_carry(q_ptr, FALSE);
+ }
+
+ /* Rogues have a better knowledge of traps */
+ if (has_ability(AB_TRAPPING))
+ {
+ t_info[TRAP_OF_DAGGER_I].known = randint(50) + 50;
+ t_info[TRAP_OF_POISON_NEEDLE].known = randint(50) + 50;
+ t_info[TRAP_OF_FIRE_BOLT].known = randint(50) + 50;
+ t_info[TRAP_OF_DAGGER_I].ident = TRUE;
+ t_info[TRAP_OF_POISON_NEEDLE].ident = TRUE;
+ t_info[TRAP_OF_FIRE_BOLT].ident = TRUE;
+
+ /* Hack -- Give the player a some ammo for the traps */
+ object_type forge;
+ object_type *q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_SHOT, SV_AMMO_NORMAL));
+ q_ptr->number = (byte)rand_range(5, 15);
+ object_aware(q_ptr);
+ object_known(q_ptr);
+
+ /* These objects are "storebought" */
+ q_ptr->ident |= IDENT_MENTAL;
+
+ (void)inven_carry(q_ptr, FALSE);
+ }
+
+ /* Hack -- Give the player some useful objects */
+ for (i = 0; i < rp_ptr->obj_num; i++)
+ outfit_obj(rp_ptr->obj_tval[i], rp_ptr->obj_sval[i], rp_ptr->obj_pval[i], rp_ptr->obj_dd[i], rp_ptr->obj_ds[i]);
+ for (i = 0; i < rmp_ptr->obj_num; i++)
+ outfit_obj(rmp_ptr->obj_tval[i], rmp_ptr->obj_sval[i], rmp_ptr->obj_pval[i], rmp_ptr->obj_dd[i], rmp_ptr->obj_ds[i]);
+ for (i = 0; i < cp_ptr->obj_num; i++)
+ outfit_obj(cp_ptr->obj_tval[i], cp_ptr->obj_sval[i], cp_ptr->obj_pval[i], cp_ptr->obj_dd[i], cp_ptr->obj_ds[i]);
+ for (i = 0; i < cp_ptr->spec[p_ptr->pspec].obj_num; i++)
+ outfit_obj(cp_ptr->spec[p_ptr->pspec].obj_tval[i], cp_ptr->spec[p_ptr->pspec].obj_sval[i], cp_ptr->spec[p_ptr->pspec].obj_pval[i], cp_ptr->spec[p_ptr->pspec].obj_dd[i], cp_ptr->spec[p_ptr->pspec].obj_ds[i]);
+}
+
+
+/* Possible number(and layout) or random quests */
+#define MAX_RANDOM_QUESTS_TYPES ((8 * 3) + (8 * 1))
+int random_quests_types[MAX_RANDOM_QUESTS_TYPES] =
+{
+ 1, 5, 6, 7, 10, 11, 12, 14, /* Princess type */
+ 1, 5, 6, 7, 10, 11, 12, 14, /* Princess type */
+ 1, 5, 6, 7, 10, 11, 12, 14, /* Princess type */
+ 20, 13, 15, 16, 9, 17, 18, 8, /* Hero Sword Quest */
+};
+
+/* Enforce OoD monsters until this level */
+#define RQ_LEVEL_CAP 49
+
+static void gen_random_quests(int n)
+{
+ int step, lvl, i, k;
+ int old_type = dungeon_type;
+
+ /* Factor dlev value by 1000 to keep precision */
+ step = (98 * 1000) / n;
+
+ lvl = step / 2;
+
+ quest[QUEST_RANDOM].status = QUEST_STATUS_TAKEN;
+
+ for (i = 0; i < n; i++)
+ {
+ monster_race *r_ptr = &r_info[2];
+
+ int rl = (lvl / 1000) + 1;
+
+ int min_level;
+
+ int tries = 5000;
+
+ random_quest *q_ptr = &random_quests[rl];
+
+ int j;
+
+ /* Find the appropriate dungeon */
+ for (j = 0; j < max_d_idx; j++)
+ {
+ dungeon_info_type *d_ptr = &d_info[j];
+
+ if (!(d_ptr->flags1 & DF1_PRINCIPAL)) continue;
+
+ if ((d_ptr->mindepth <= rl) && (rl <= d_ptr->maxdepth))
+ {
+ dungeon_type = j;
+ break;
+ }
+ }
+
+ q_ptr->type = random_quests_types[rand_int(MAX_RANDOM_QUESTS_TYPES)];
+
+ /* XXX XXX XXX Try until valid choice is found */
+ while (tries)
+ {
+ bool_ ok;
+
+ tries--;
+
+ /* Random monster 5 - 10 levels out of depth */
+ q_ptr->r_idx = get_mon_num(rl + 4 + randint(6));
+
+ if (!q_ptr->r_idx) continue;
+
+ r_ptr = &r_info[q_ptr->r_idx];
+
+ /* Accept only monsters that can be generated */
+ if (r_ptr->flags9 & RF9_SPECIAL_GENE) continue;
+ if (r_ptr->flags9 & RF9_NEVER_GENE) continue;
+
+ /* Accept only monsters that are not breeders */
+ if (r_ptr->flags4 & RF4_MULTIPLY) continue;
+
+ /* Forbid joke monsters */
+ if (r_ptr->flags8 & RF8_JOKEANGBAND) continue;
+
+ /* Accept only monsters that are not friends */
+ if (r_ptr->flags7 & RF7_PET) continue;
+
+ /* Refuse nazguls */
+ if (r_ptr->flags7 & RF7_NAZGUL) continue;
+
+ /* Accept only monsters that are not good */
+ if (r_ptr->flags3 & RF3_GOOD) continue;
+
+ /* Assume no explosion attacks */
+ ok = TRUE;
+
+ /* Reject monsters with exploding attacks */
+ for (k = 0; k < 4; k++)
+ {
+ if (r_ptr->blow[k].method == RBM_EXPLODE) ok = FALSE;
+ }
+ if (!ok) continue;
+
+ /* No mutliple uniques */
+ if ((r_ptr->flags1 & RF1_UNIQUE) &&
+ ((q_ptr->type != 1) || (r_ptr->max_num == -1))) continue;
+
+ /* No single non uniques */
+ if ((!(r_ptr->flags1 & RF1_UNIQUE)) && (q_ptr->type == 1)) continue;
+
+ /* Level restriction */
+ min_level = (rl > RQ_LEVEL_CAP) ? RQ_LEVEL_CAP : rl;
+
+ /* Accept monsters matching the level restriction */
+ if (r_ptr->level > min_level) break;
+ }
+
+ /* Arg could not find anything ??? */
+ if (!tries)
+ {
+ if (wizard) message_add(MESSAGE_MSG, format("Could not find quest monster on lvl %d", rl), TERM_RED);
+ q_ptr->type = 0;
+ }
+ else
+ {
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ r_ptr->max_num = -1;
+ }
+
+ q_ptr->done = FALSE;
+
+ if (wizard) message_add(MESSAGE_MSG,
+ format("Quest for %d on lvl %d",
+ q_ptr->r_idx, rl), TERM_RED);
+ }
+
+ lvl += step;
+ }
+
+ dungeon_type = old_type;
+}
+
+int dump_classes(s16b *classes, int sel, u32b *restrictions)
+{
+ int n = 0;
+
+ char buf[80];
+ char *desc;
+
+ cptr str;
+
+ C_MAKE(desc, c_head->text_size, char);
+
+ /* Clean up */
+ clear_from(12);
+
+ while (classes[n] != -1)
+ {
+ cptr mod = "";
+ char p2 = ')', p1 = ' ';
+
+ /* Analyze */
+ p_ptr->pclass = classes[n];
+ cp_ptr = &class_info[p_ptr->pclass];
+ str = cp_ptr->title + c_name;
+
+ if (sel == n)
+ {
+ p1 = '[';
+ p2 = ']';
+ }
+
+ /* Display */
+ strnfmt(buf, 80, "%c%c%c %s%s", p1,
+ (n <= 25) ? I2A(n) : I2D(n - 26), p2, str, mod);
+
+ /* Print some more info */
+ if (sel == n)
+ {
+ strnfmt(desc, c_head->text_size, "%s%s", cp_ptr->desc + c_text,
+ cp_ptr->flags1 & PR1_EXPERIMENTAL ? "\nEXPERIMENTAL" : "");
+ print_desc(desc);
+
+ if (!(restrictions[classes[n] / 32] & BIT(classes[n])) ||
+ cp_ptr->flags1 & PR1_EXPERIMENTAL)
+ c_put_str(TERM_BLUE, buf, 18 + (n / 4), 1 + 20 * (n % 4));
+ else
+ c_put_str(TERM_L_BLUE, buf, 18 + (n / 4), 1 + 20 * (n % 4));
+ }
+ else
+ {
+ if (!(restrictions[classes[n] / 32] & BIT(classes[n])) ||
+ cp_ptr->flags1 & PR1_EXPERIMENTAL)
+ c_put_str(TERM_SLATE, buf, 18 + (n / 4), 1 + 20 * (n % 4));
+ else
+ put_str(buf, 18 + (n / 4), 1 + 20 * (n % 4));
+ }
+ n++;
+ }
+
+ C_FREE(desc, c_head->text_size, char);
+
+ return (n);
+}
+
+int dump_specs(int sel)
+{
+ int n = 0;
+
+ char buf[80];
+ char *desc;
+
+ cptr str;
+
+ C_MAKE(desc, c_head->text_size, char);
+
+ /* Clean up */
+ clear_from(12);
+
+ for (n = 0; n < MAX_SPEC; n++)
+ {
+ char p2 = ')', p1 = ' ';
+
+ /* Found the last one ? */
+ if (!class_info[p_ptr->pclass].spec[n].title) break;
+
+ /* Analyze */
+ p_ptr->pspec = n;
+ spp_ptr = &class_info[p_ptr->pclass].spec[p_ptr->pspec];
+ str = spp_ptr->title + c_name;
+
+ if (sel == n)
+ {
+ p1 = '[';
+ p2 = ']';
+ }
+
+ /* Display */
+ strnfmt(buf, 80, "%c%c%c %s", p1, I2A(n), p2, str);
+
+ /* Print some more info */
+ if (sel == n)
+ {
+ strnfmt(desc, c_head->text_size, "%s%s", spp_ptr->desc + c_text,
+ spp_ptr->flags1 & PR1_EXPERIMENTAL ? "\nEXPERIMENTAL" : "");
+ print_desc(desc);
+
+ if (spp_ptr->flags1 & PR1_EXPERIMENTAL)
+ c_put_str(TERM_BLUE, buf, 18 + (n / 4), 1 + 20 * (n % 4));
+ else
+ c_put_str(TERM_L_BLUE, buf, 18 + (n / 4), 1 + 20 * (n % 4));
+ }
+ else
+ {
+ if (spp_ptr->flags1 & PR1_EXPERIMENTAL)
+ c_put_str(TERM_SLATE, buf, 18 + (n / 4), 1 + 20 * (n % 4));
+ else
+ put_str(buf, 18 + (n / 4), 1 + 20 * (n % 4));
+ }
+ }
+
+ C_FREE(desc, c_head->text_size, char);
+
+ return (n);
+}
+
+int dump_races(int sel)
+{
+ int n = 0;
+
+ char buf[80];
+ char *desc;
+
+ cptr str;
+
+ C_MAKE(desc, rp_head->text_size, char);
+
+ /* Clean up */
+ clear_from(12);
+
+ for (n = 0; n < max_rp_idx; n++)
+ {
+ char p2 = ')', p1 = ' ';
+
+ /* Analyze */
+ p_ptr->prace = n;
+ rp_ptr = &race_info[p_ptr->prace];
+ str = rp_ptr->title + rp_name;
+
+ if (sel == n)
+ {
+ p1 = '[';
+ p2 = ']';
+ }
+
+ /* Display */
+ strnfmt(buf, 80, "%c%c%c %s", p1, I2A(n), p2, str);
+
+ /* Print some more info */
+ if (sel == n)
+ {
+ strnfmt(desc, rp_head->text_size, "%s%s", rp_ptr->desc + rp_text,
+ rp_ptr->flags1 & PR1_EXPERIMENTAL ? "\nEXPERIMENTAL" : "");
+ print_desc(desc);
+
+ if (rp_ptr->flags1 & PR1_EXPERIMENTAL)
+ c_put_str(TERM_BLUE, buf, 18 + (n / 5), 1 + 15 * (n % 5));
+ else
+ c_put_str(TERM_L_BLUE, buf, 18 + (n / 5), 1 + 15 * (n % 5));
+ }
+ else
+ {
+ if (rp_ptr->flags1 & PR1_EXPERIMENTAL)
+ c_put_str(TERM_SLATE, buf, 18 + (n / 5), 1 + 15 * (n % 5));
+ else
+ put_str(buf, 18 + (n / 5), 1 + 15 * (n % 5));
+ }
+ }
+
+ C_FREE(desc, rp_head->text_size, char);
+
+ return (n);
+}
+
+
+int dump_rmods(int sel, int *racem, int max)
+{
+ int n = 0;
+
+ char buf[80];
+ char *desc;
+
+ cptr str;
+
+ C_MAKE(desc, rmp_head->text_size, char);
+
+ /* Clean up */
+ clear_from(12);
+
+ /* Dump races */
+ for (n = 0; n < max; n++)
+ {
+ char p2 = ')', p1 = ' ';
+
+ /* Analyze */
+ p_ptr->pracem = racem[n];
+ rmp_ptr = &race_mod_info[p_ptr->pracem];
+ str = rmp_ptr->title + rmp_name;
+
+ if (sel == n)
+ {
+ p1 = '[';
+ p2 = ']';
+ }
+
+ /* Display */
+ if (racem[n])
+ strnfmt(buf, 80, "%c%c%c %s", p1, I2A(n), p2, str);
+ else
+ strnfmt(buf, 80, "%c%c%c Classical", p1, I2A(n), p2);
+
+ /* Print some more info */
+ if (sel == n)
+ {
+ strnfmt(desc, rmp_head->text_size, "%s%s", rmp_ptr->desc + rmp_text,
+ rmp_ptr->flags1 & PR1_EXPERIMENTAL ? "\nEXPERIMENTAL" : "");
+ print_desc(desc);
+
+ if (rmp_ptr->flags1 & PR1_EXPERIMENTAL)
+ c_put_str(TERM_BLUE, buf, 18 + (n / 5), 1 + 15 * (n % 5));
+ else
+ c_put_str(TERM_L_BLUE, buf, 18 + (n / 5), 1 + 15 * (n % 5));
+ }
+ else
+ {
+ if (rmp_ptr->flags1 & PR1_EXPERIMENTAL)
+ c_put_str(TERM_SLATE, buf, 18 + (n / 5), 1 + 15 * (n % 5));
+ else
+ put_str(buf, 18 + (n / 5), 1 + 15 * (n % 5));
+ }
+ }
+
+ C_FREE(desc, rmp_head->text_size, char);
+
+ return (n);
+}
+
+int dump_gods(int sel, int *choice, int max)
+{
+ int i, j;
+ char buf[80];
+ cptr str;
+
+ /* Clean up */
+ clear_from(12);
+
+ Term_putstr(5, 17, -1, TERM_WHITE,
+ "You can choose to worship a god, some class must start with a god.");
+
+ for (i = 0; i < max; i++)
+ {
+ char p2 = ')', p1 = ' ';
+ int n = choice[i];
+ deity_type *g_ptr = &deity_info[0];
+
+ if (!n) str = "No God";
+ else
+ {
+ g_ptr = &deity_info[n];
+ str = g_ptr->name;
+ }
+
+ if (sel == i)
+ {
+ p1 = '[';
+ p2 = ']';
+ }
+
+ /* Display */
+ strnfmt(buf, 80, "%c%c%c %s", p1, I2A(i), p2, str);
+
+ /* Print some more info */
+ if (sel == i)
+ {
+ if (n)
+ {
+ /* Display the first four lines of the god description */
+ for (j = 0; j < 4; j++)
+ if (strcmp(g_ptr->desc[j], ""))
+ print_desc_aux(g_ptr->desc[j], 12 + j, 1);
+ }
+ else print_desc("You can begin as an atheist and still convert to a god later.");
+
+ c_put_str(TERM_L_BLUE, buf, 20 + (i / 4), 1 + 20 * (i % 4));
+ }
+ else
+ {
+ put_str(buf, 20 + (i / 4), 1 + 20 * (i % 4));
+ }
+ }
+
+ return (max);
+}
+
+
+/* Ask questions */
+static bool_ do_quick_start = FALSE;
+
+static bool_ player_birth_aux_ask()
+{
+ int i, k, n, v, sel;
+
+ s32b tmp;
+
+ int racem[100], max_racem = 0;
+
+ u32b restrictions[2];
+
+ cptr str;
+
+ char c;
+
+ char p2 = ')';
+
+ char buf[200];
+ char inp[200];
+
+ s16b *class_types;
+
+ s32b allow_quest;
+
+ /*** Intro ***/
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Title everything */
+ put_str("Name :", 2, 1);
+ put_str("Sex :", 3, 1);
+ put_str("Race :", 4, 1);
+ put_str("Class :", 5, 1);
+
+ /* Dump the default name */
+ c_put_str(TERM_L_BLUE, player_name, 2, 9);
+
+
+ /*** Instructions ***/
+
+ /* Display some helpful information */
+ Term_putstr(5, 8, -1, TERM_WHITE,
+ "Please answer the following questions. Most of the questions");
+ Term_putstr(5, 9, -1, TERM_WHITE,
+ "display a set of standard answers, and many will also accept");
+ Term_putstr(5, 10, -1, TERM_WHITE,
+ "some special responses, including 'Q' to quit, 'S' to restart,");
+ Term_putstr(5, 11, -1, TERM_WHITE,
+ "and '?' for help. Note that 'Q' and 'S' must be capitalized.");
+
+
+ /*** Quick Start ***/
+
+ if (previous_char.quick_ok)
+ {
+ /* Extra info */
+ Term_putstr(1, 15, -1, TERM_WHITE,
+ "Do you want to use the quick start function(same character as your last one).");
+
+ /* Choose */
+ while (1)
+ {
+ put_str("Use quick start (y/n)?", 20, 2);
+ c = inkey();
+ if (c == 'Q') quit(NULL);
+ else if (c == 'S') return (FALSE);
+ else if ((c == 'y') || (c == 'Y'))
+ {
+ do_quick_start = TRUE;
+ break;
+ }
+ else
+ {
+ do_quick_start = FALSE;
+ break;
+ }
+ }
+ }
+
+ /* Clean up */
+ clear_from(15);
+
+ /*** Player sex ***/
+
+ if (do_quick_start)
+ {
+ k = previous_char.sex;
+ }
+ else
+ {
+ /* Extra info */
+ Term_putstr(5, 15, -1, TERM_WHITE,
+ "Your 'sex' does not have any significant gameplay effects.");
+
+ /* Prompt for "Sex" */
+ for (n = 0; n < MAX_SEXES; n++)
+ {
+ /* Analyze */
+ p_ptr->psex = n;
+ sp_ptr = &sex_info[p_ptr->psex];
+ str = sp_ptr->title;
+
+ /* Display */
+ strnfmt(buf, 200, "%c%c %s", I2A(n), p2, str);
+ put_str(buf, 21 + (n / 5), 2 + 15 * (n % 5));
+ }
+
+ /* Choose */
+ while (1)
+ {
+ strnfmt(buf, 200, "Choose a sex (%c-%c), * for random, = for options: ", I2A(0), I2A(n - 1));
+ put_str(buf, 20, 2);
+ c = inkey();
+ if (c == 'Q') quit(NULL);
+ if (c == 'S') return (FALSE);
+ if (c == '*')
+ {
+ k = rand_int(MAX_SEXES);
+ break;
+ }
+ k = (islower(c) ? A2I(c) : -1);
+ if ((k >= 0) && (k < n)) break;
+ if (c == '?') do_cmd_help();
+ else if (c == '=')
+ {
+ screen_save();
+ do_cmd_options_aux(6, "Startup Options", FALSE);
+ screen_load();
+ }
+ else bell();
+ }
+ }
+
+ /* Set sex */
+ p_ptr->psex = k;
+ sp_ptr = &sex_info[p_ptr->psex];
+ str = sp_ptr->title;
+
+ /* Display */
+ c_put_str(TERM_L_BLUE, str, 3, 9);
+
+ /* Clean up */
+ clear_from(15);
+
+
+ /*** Player race ***/
+
+ if (do_quick_start)
+ {
+ k = previous_char.race;
+ }
+ else
+ {
+ /* Only one choice = instant choice */
+ if (max_rp_idx == 1)
+ k = 0;
+ else
+ {
+ /* Extra info */
+ Term_putstr(5, 16, -1, TERM_WHITE,
+ "Your 'race' determines various intrinsic factors and bonuses.");
+ hack_corruption = FALSE;
+
+ /* Dump races */
+ sel = 0;
+ n = dump_races(sel);
+
+ /* Choose */
+ while (1)
+ {
+ strnfmt(buf, 200, "Choose a race (%c-%c), * for a random choice, = for options, 8/2/4/6 for movement: ",
+ I2A(0), I2A(max_rp_idx - 1));
+ put_str(buf, 17, 2);
+
+ c = inkey();
+ if (c == 'Q') quit(NULL);
+ if (c == 'S') return (FALSE);
+ if (c == '*')
+ {
+ k = rand_int(max_rp_idx);
+ break;
+ }
+ k = (islower(c) ? A2I(c) : -1);
+ if ((k >= 0) && (k < n)) break;
+ if (c == '?') exec_lua(format("ingame_help('select_context', 'race', '%s')", race_info[sel].title + rp_name));
+ else if (c == '=')
+ {
+ screen_save();
+ do_cmd_options_aux(6, "Startup Options", FALSE);
+ screen_load();
+ }
+ else if (c == '2')
+ {
+ sel += 5;
+ if (sel >= n) sel %= 5;
+ dump_races(sel);
+ }
+ else if (c == '8')
+ {
+ sel -= 5;
+ if (sel < 0) sel = n - 1 -( ( -sel) % 5);
+ /* C's modulus operator does not have defined
+ results for negative first values. Damn. */
+ dump_races(sel);
+ }
+ else if (c == '6')
+ {
+ sel++;
+ if (sel >= n) sel = 0;
+ dump_races(sel);
+ }
+ else if (c == '4')
+ {
+ sel--;
+ if (sel < 0) sel = n - 1;
+ dump_races(sel);
+ }
+ else if (c == '\r')
+ {
+ k = sel;
+ break;
+ }
+ else bell();
+ }
+ }
+ }
+ /* Set race */
+ p_ptr->prace = k;
+ rp_ptr = &race_info[p_ptr->prace];
+ str = rp_ptr->title + rp_name;
+
+ /* Display */
+ c_put_str(TERM_L_BLUE, str, 4, 9);
+
+ /* Get a random name */
+ if (!do_quick_start) create_random_name(p_ptr->prace, player_name);
+
+ /* Display */
+ c_put_str(TERM_L_BLUE, player_name, 2, 9);
+
+ /* Clean up */
+ clear_from(12);
+
+
+ /*** Player race mod ***/
+ if (do_quick_start)
+ {
+ k = previous_char.rmod;
+ p_ptr->pracem = k;
+ rmp_ptr = &race_mod_info[p_ptr->pracem];
+ }
+ else
+ {
+ /* Only one choice = instant choice */
+ if (max_rmp_idx == 1)
+ k = 0;
+ else
+ {
+ for (n = 0; n < 100; n++) racem[n] = 0;
+
+ max_racem = 0;
+ for (n = 0; n < max_rmp_idx; n++)
+ {
+ /* Analyze */
+ p_ptr->pracem = n;
+ rmp_ptr = &race_mod_info[p_ptr->pracem];
+
+ /* Must be an ok choice */
+ if (!(BIT(p_ptr->prace) & rmp_ptr->choice[p_ptr->prace / 32])) continue;
+
+ /* Ok thats a possibility */
+ racem[max_racem++] = n;
+ }
+
+ /* Ah ! nothing found, lets use the default */
+ if (!max_racem) p_ptr->pracem = 0;
+ /* Only one ? use it */
+ else if (max_racem == 1) p_ptr->pracem = racem[0];
+ /* We got to ask the player */
+ else
+ {
+ /* Extra info */
+ Term_putstr(5, 15, -1, TERM_WHITE,
+ "Your 'race modifier' determines various intrinsic factors and bonuses.");
+
+ /* Dump races */
+ sel = 0;
+ n = dump_rmods(sel, racem, max_racem);
+
+ /* Choose */
+ while (1)
+ {
+ strnfmt(buf, 200, "Choose a race modifier (%c-%c), * for a random choice, = for options: ",
+ I2A(0), I2A(max_racem - 1));
+ put_str(buf, 17, 2);
+ c = inkey();
+ if (c == 'Q') quit(NULL);
+ if (c == 'S') return (FALSE);
+ if (c == '*')
+ {
+ do
+ {
+ k = rand_int(max_racem);
+ }
+ while (!(BIT(racem[k]) & rmp_ptr->choice[racem[k] / 32]));
+ break;
+ }
+ else if (c == '?') exec_lua(format("ingame_help('select_context', 'subrace', '%s')", race_mod_info[racem[sel]].title + rmp_name));
+
+ k = (islower(c) ? A2I(c) : -1);
+ if ((k >= 0) && (k < max_racem) &&
+ (BIT(p_ptr->prace) & race_mod_info[racem[k]].choice[p_ptr->prace / 32])) break;
+
+ else if (c == '=')
+ {
+ screen_save();
+ do_cmd_options_aux(6, "Startup Options", FALSE);
+ screen_load();
+ }
+ else if (c == '2')
+ {
+ sel += 5;
+ if (sel >= n) sel = sel - n + 1;
+ dump_rmods(sel, racem, max_racem);
+ }
+ else if (c == '8')
+ {
+ sel -= 5;
+ if (sel < 0) sel = n - 1 + sel;
+ dump_rmods(sel, racem, max_racem);
+ }
+ else if (c == '6')
+ {
+ sel++;
+ if (sel >= n) sel = 0;
+ dump_rmods(sel, racem, max_racem);
+ }
+ else if (c == '4')
+ {
+ sel--;
+ if (sel < 0) sel = n - 1;
+ dump_rmods(sel, racem, max_racem);
+ }
+ else if (c == '\r')
+ {
+ k = sel;
+ break;
+ }
+ else bell();
+ }
+
+ /* Set race */
+ p_ptr->pracem = racem[k];
+ }
+ rmp_ptr = &race_mod_info[p_ptr->pracem];
+
+ /* Display */
+ c_put_str(TERM_L_BLUE, get_player_race_name(p_ptr->prace, p_ptr->pracem), 4, 9);
+ }
+ }
+
+ /* Clean up */
+ clear_from(12);
+
+
+ /*** Player class ***/
+ if (do_quick_start)
+ {
+ k = previous_char.pclass;
+ p_ptr->pclass = k;
+ cp_ptr = &class_info[p_ptr->pclass];
+ k = previous_char.spec;
+ p_ptr->pspec = k;
+ spp_ptr = &class_info[p_ptr->pclass].spec[p_ptr->pspec];
+ }
+ else
+ {
+ int z;
+
+ for (z = 0; z < 2; z++)
+ restrictions[z] = (rp_ptr->choice[z] | rmp_ptr->pclass[z]) & (~rmp_ptr->mclass[z]);
+
+ if (max_mc_idx > 1)
+ {
+ /* Extra info */
+ Term_putstr(5, 13, -1, TERM_WHITE,
+ "Your 'class' determines various intrinsic abilities and bonuses.");
+
+ /* Get a class type */
+ for (i = 0; i < max_mc_idx; i++)
+ c_put_str(meta_class_info[i].color, format("%c) %s", I2A(i), meta_class_info[i].name), 16 + i, 2);
+ while (1)
+ {
+ strnfmt(buf, 200, "Choose a class type (a-%c), * for random, = for options: ", I2A(max_mc_idx - 1));
+ put_str(buf, 15, 2);
+ c = inkey();
+ if (c == 'Q') quit(NULL);
+ if (c == 'S') return (FALSE);
+ if (c == '*')
+ {
+ k = rand_int(max_mc_idx);
+ break;
+ }
+ k = (islower(c) ? A2I(c) : (D2I(c) + 26));
+ if ((k >= 0) && (k < max_mc_idx)) break;
+ if (c == '?') do_cmd_help();
+ else if (c == '=')
+ {
+ screen_save();
+ do_cmd_options_aux(6, "Startup Options", FALSE);
+ screen_load();
+ }
+ else bell();
+ }
+ }
+ else
+ {
+ k = 0;
+ }
+ class_types = meta_class_info[k].classes;
+ clear_from(15);
+
+ /* Count classes */
+ n = 0;
+ while (class_types[n] != -1) n++;
+
+ /* Only one choice = instant choice */
+ if (n == 1)
+ k = 0;
+ else
+ {
+ /* Dump classes */
+ sel = 0;
+ n = dump_classes(class_types, sel, restrictions);
+
+ /* Get a class */
+ while (1)
+ {
+ strnfmt(buf, 200, "Choose a class (%c-%c), * for random, = for options, 8/2/4 for up/down/back: ", I2A(0), (n <= 25) ? I2A(n - 1) : I2D(n - 26-1));
+ put_str(buf, 15, 2);
+ c = inkey();
+ if (c == 'Q') quit(NULL);
+ if (c == 'S') return (FALSE);
+ if (c == '*')
+ {
+ k = randint(n) - 1;
+ break;
+ }
+ k = (islower(c) ? A2I(c) : (D2I(c) + 26));
+ if ((k >= 0) && (k < n)) break;
+ if (c == '?') exec_lua(format("ingame_help('select_context', 'class', '%s')", class_info[class_types[sel]].title + c_name));
+ else if (c == '=')
+ {
+ screen_save();
+ do_cmd_options_aux(6, "Startup Options", FALSE);
+ screen_load();
+ }
+ else if (c == '2')
+ {
+ sel += 4;
+ if (sel >= n) sel %= 4;
+ dump_classes(class_types, sel, restrictions);
+ }
+ else if (c == '8')
+ {
+ sel -= 4;
+ if (sel < 0) sel = n - 1 -( ( -sel) % 4);
+ /* C's modulus operator does not have defined
+ results for negative first values. Damn. */
+ dump_classes(class_types, sel, restrictions);
+ }
+ else if (c == '6')
+ {
+ sel++;
+ if (sel >= n) sel = 0;
+ dump_classes(class_types, sel, restrictions);
+ }
+ else if (c == '4')
+ {
+ sel--;
+ if (sel < 0) sel = n - 1;
+ dump_classes(class_types, sel, restrictions);
+ }
+ else if (c == '\r')
+ {
+ k = sel;
+ break;
+ }
+ else bell();
+ }
+ }
+
+ /* Set class */
+ p_ptr->pclass = class_types[k];
+
+ /* Choose class spec */
+ clear_from(15);
+
+ /* Count choices */
+ for (n = 0; n < MAX_SPEC; n++)
+ {
+ /* Found the last one ? */
+ if (!class_info[p_ptr->pclass].spec[n].title) break;
+ }
+
+ /* Only one choice = auto choice */
+ if (n == 1)
+ k = 0;
+ else
+ {
+ /* Dump classes spec */
+ sel = 0;
+ n = dump_specs(sel);
+
+ /* Get a class */
+ while (1)
+ {
+ strnfmt(buf, 200, "Choose a class specialisation (%c-%c), * for random, = for options, 8/2/4/6 for up/down/left/right: ", I2A(0), (n <= 25) ? I2A(n - 1) : I2D(n - 26-1));
+ put_str(buf, 15, 2);
+ c = inkey();
+ if (c == 'Q') quit(NULL);
+ if (c == 'S') return (FALSE);
+ if (c == '*')
+ {
+ k = randint(n) - 1;
+ break;
+ }
+ k = (islower(c) ? A2I(c) : (D2I(c) + 26));
+ if ((k >= 0) && (k < n)) break;
+ if (c == '?') exec_lua(format("ingame_help('select_context', 'class', '%s')", class_info[p_ptr->pclass].spec[sel].title + c_name));
+ else if (c == '=')
+ {
+ screen_save();
+ do_cmd_options_aux(6, "Startup Options", FALSE);
+ screen_load();
+ }
+ else if (c == '2')
+ {
+ sel += 4;
+ if (sel >= n) sel = sel - n + 1;
+ dump_specs(sel);
+ }
+ else if (c == '8')
+ {
+ sel -= 4;
+ if (sel < 0) sel = n - 1 + sel;
+ dump_specs(sel);
+ }
+ else if (c == '6')
+ {
+ sel++;
+ if (sel >= n) sel = 0;
+ dump_specs(sel);
+ }
+ else if (c == '4')
+ {
+ sel--;
+ if (sel < 0) sel = n - 1;
+ dump_specs(sel);
+ }
+ else if (c == '\r')
+ {
+ k = sel;
+ break;
+ }
+ else bell();
+ }
+ }
+
+ /* Set class spec */
+ p_ptr->pspec = k;
+ }
+ cp_ptr = &class_info[p_ptr->pclass];
+ spp_ptr = &class_info[p_ptr->pclass].spec[p_ptr->pspec];
+ str = spp_ptr->title + c_name;
+
+ /* Display */
+ c_put_str(TERM_L_BLUE, str, 5, 9);
+
+ /* Clean up */
+ clear_from(15);
+
+ /*** Player god ***/
+ if (do_quick_start)
+ {
+ k = previous_char.god;
+ p_ptr->pgod = k;
+ set_grace(previous_char.grace);
+ }
+ else if (PRACE_FLAG(PR1_NO_GOD))
+ {
+ p_ptr->pgod = GOD_NONE;
+ }
+ else
+ {
+ int *choice;
+ int max = 0;
+
+ C_MAKE(choice, max_gods, int);
+
+ /* Get the list of possible gods */
+ for (n = 0; n < max_gods; n++)
+ {
+ if ((cp_ptr->gods | spp_ptr->gods) & BIT(n))
+ choice[max++] = n;
+ }
+
+ if (!max)
+ {
+ p_ptr->pgod = GOD_NONE;
+ }
+ else if (max == 1)
+ {
+ p_ptr->pgod = choice[0];
+ }
+ else if (max > 1)
+ {
+ sel = 0;
+ n = dump_gods(sel, choice, max);
+
+ /* Choose */
+ while (1)
+ {
+ strnfmt(buf, 200, "Choose a god (%c-%c), * for a random choice, "
+ "= for options, 8/2/4/6 for movement: ",
+ I2A(0), I2A(max - 1));
+ put_str(buf, 19, 2);
+
+ c = inkey();
+ if (c == 'Q') quit(NULL);
+ if (c == 'S')
+ {
+ C_FREE(choice, max_gods, int);
+
+ return (FALSE);
+ }
+ if (c == '*')
+ {
+ k = choice[randint(max) - 1];
+ break;
+ }
+ k = (islower(c) ? A2I(c) : -1);
+ if ((k >= 0) && (k < max))
+ {
+ k = choice[k];
+ break;
+ }
+ if (c == '?') exec_lua(format("ingame_help('select_context', 'god', '%s')", deity_info[choice[sel]].name));
+ else if (c == '=')
+ {
+ screen_save();
+ do_cmd_options_aux(6, "Startup Options", FALSE);
+ screen_load();
+ }
+ else if (c == '2')
+ {
+ sel += 4;
+ if (sel >= n) sel %= 4;
+ dump_gods(sel, choice, max);
+ }
+ else if (c == '8')
+ {
+ sel -= 4;
+ /* C's modulus operator does not have defined
+ results for negative first values. Damn. */
+ if (sel < 0) sel = n - 1 -( ( -sel) % 4);
+ dump_gods(sel, choice, max);
+ }
+ else if (c == '6')
+ {
+ sel++;
+ if (sel >= n) sel = 0;
+ dump_gods(sel, choice, max);
+ }
+ else if (c == '4')
+ {
+ sel--;
+ if (sel < 0) sel = n - 1;
+ dump_gods(sel, choice, max);
+ }
+ else if (c == '\r')
+ {
+ k = choice[sel];
+ break;
+ }
+ else bell();
+ }
+
+ C_FREE(choice, max_gods, int);
+
+ /* Set god */
+ p_ptr->pgod = k;
+ p_ptr->grace = 0;
+ }
+
+ /* A god that like us ? more grace ! */
+ if (PRACE_FLAGS(PR1_GOD_FRIEND))
+ {
+ set_grace(200);
+ }
+ else
+ {
+ set_grace(100);
+ }
+ }
+
+ /* Clean up */
+ clear_from(12);
+
+ if (!do_quick_start)
+ {
+ /* Clear */
+ clear_from(15);
+
+ /* */
+ if (get_check("Do you want to modify the options"))
+ {
+ screen_save();
+ do_cmd_options_aux(6, "Startup Options", FALSE);
+ screen_load();
+ }
+ }
+
+ /* Set birth options: maximize, preserve, sepcial levels and astral */
+ p_ptr->maximize = maximize;
+ p_ptr->preserve = preserve;
+ p_ptr->special = special_lvls;
+ p_ptr->astral = (PRACE_FLAG2(PR2_ASTRAL)) ? TRUE : FALSE;
+
+ /*
+ * A note by pelpel. (remove this please)
+ * Be it the new Vanilla way (adult vs. birth options) or
+ * the old one (player_type members), it would be less confusing
+ * to handle birth-only options in a uniform fashion,the above and
+ * the following:
+ * ironman_rooms,
+ * joke_monsters,
+ * always_small_level, and
+ * fate_option
+ */
+
+
+ /* Set the recall dungeon accordingly */
+ call_lua("get_module_info", "(s)", "d", "base_dungeon", &tmp);
+ dungeon_type = tmp;
+ p_ptr->recall_dungeon = dungeon_type;
+ max_dlv[dungeon_type] = d_info[dungeon_type].mindepth;
+
+ if (p_ptr->astral)
+ {
+ s32b x, y, astral_dun;
+
+ call_lua("get_module_info", "(s)", "d", "astral_dungeon", &astral_dun);
+ dungeon_type = astral_dun;
+
+ /* Somewhere in the misty mountains */
+ call_lua("get_module_info", "(s)", "d", "astral_wild_x", &x);
+ call_lua("get_module_info", "(s)", "d", "astral_wild_y", &y);
+ p_ptr->wilderness_x = x;
+ p_ptr->wilderness_y = y;
+ }
+
+ /* Clean up */
+ clear_from(10);
+
+ /*** User enters number of quests ***/
+ /* Heino Vander Sanden and Jimmy De Laet */
+
+ call_lua("get_module_info", "(s)", "d", "rand_quest", &allow_quest);
+ if (!ironman_rooms && allow_quest)
+ {
+ if (do_quick_start)
+ {
+ v = previous_char.quests;
+ }
+ else
+ {
+ /* Extra info */
+ Term_putstr(5, 15, -1, TERM_WHITE,
+ "Select the number of optional random quests you'd like to receive.");
+ Term_putstr(5, 16, -1, TERM_WHITE,
+ "If you do not want any optional quests, enter 0.");
+
+ /* Ask the number of additional quests */
+ while (TRUE)
+ {
+ put_str(format("Number of quests? (0-%u) ",
+ MAX_RANDOM_QUEST - 1), 20, 2);
+
+ /* Get a the number of additional quest */
+ while (TRUE)
+ {
+ /* Move the cursor */
+ put_str("", 20, 27);
+
+ /* Default */
+ strcpy(inp, "20");
+
+ /* Get a response (or escape) */
+ if (!askfor_aux(inp, 2)) inp[0] = '\0';
+ if (inp[0] == '*') v = rand_int(MAX_RANDOM_QUEST);
+ else v = atoi(inp);
+
+ /* Break on valid input */
+ if ((v < MAX_RANDOM_QUEST) && ( v >= 0 )) break;
+ }
+ break;
+ }
+
+ /* Clear */
+ clear_from(15);
+ }
+ }
+ else
+ {
+ /* NO quests for ironman rooms or persistent levels, since they
+ don't work */
+ v = 0;
+ }
+
+ /* Set the quest monster hook */
+ get_mon_num_hook = monster_quest;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Generate quests */
+ for (i = 0; i < MAX_RANDOM_QUEST; i++) random_quests[i].type = 0;
+ if (v) gen_random_quests(v);
+ max_quests = v;
+
+ p_ptr->inside_quest = 0;
+
+ /* Init the plots */
+ call_lua("get_module_info", "(s)", "d", "C_quest", &allow_quest);
+ if (allow_quest)
+ {
+ plots[PLOT_MAIN] = QUEST_NECRO;
+ quest[plots[PLOT_MAIN]].status = QUEST_STATUS_TAKEN;
+
+ plots[PLOT_BREE] = QUEST_THIEVES;
+ quest[plots[PLOT_BREE]].status = QUEST_STATUS_UNTAKEN;
+
+ plots[PLOT_LORIEN] = QUEST_WOLVES;
+ quest[plots[PLOT_LORIEN]].status = QUEST_STATUS_UNTAKEN;
+
+ plots[PLOT_GONDOLIN] = QUEST_DRAGONS;
+ quest[plots[PLOT_GONDOLIN]].status = QUEST_STATUS_UNTAKEN;
+
+ plots[PLOT_MINAS] = QUEST_HAUNTED;
+ quest[plots[PLOT_MINAS]].status = QUEST_STATUS_UNTAKEN;
+
+ plots[PLOT_KHAZAD] = QUEST_EVIL;
+ quest[plots[PLOT_KHAZAD]].status = QUEST_STATUS_UNTAKEN;
+
+ plots[PLOT_OTHER] = QUEST_NULL;
+ }
+
+ quest_random_init_hook(QUEST_RANDOM);
+
+ /* Ok */
+ return (TRUE);
+}
+
+
+
+
+/*
+ * Initial stat costs (initial stats always range from 10 to 18 inclusive).
+ */
+static const int birth_stat_costs[(18-10) + 1] =
+{
+ 0, 1, 2, 4, 7, 11, 16, 22, 30
+};
+
+
+/*
+ * Helper function for 'player_birth()'.
+ *
+ * This function handles "point-based" character creation.
+ *
+ * The player selects, for each stat, a value from 10 to 18 (inclusive),
+ * each costing a certain amount of points (as above), from a pool of 48
+ * available points, to which race/class modifiers are then applied.
+ *
+ * Each unused point is converted into 100 gold pieces, with a maximum of
+ * 600 gp at birth.
+ *
+ * Taken from V 2.9.0
+ */
+static bool_ player_birth_aux_point(void)
+{
+ int i;
+
+ int row = 3;
+
+ int col = 42;
+
+ int stat = 0;
+
+ int stats[6];
+
+ int cost;
+
+ char ch;
+
+ char buf[80];
+
+ int mode = 0;
+
+
+ /* Initialize stats */
+ for (i = 0; i < 6; i++)
+ {
+ /* Initial stats */
+ stats[i] = 10;
+ }
+
+
+ /* Roll for base hitpoints */
+ get_extra();
+
+ /* Roll for age/height/weight */
+ get_ahw();
+
+ /* Roll for social class */
+ get_history();
+
+ /*** Generate ***/
+ process_hooks(HOOK_BIRTH, "()");
+
+ /* Hack -- get a chaos patron even if you are not a chaos warrior */
+ p_ptr->chaos_patron = (randint(MAX_PATRON)) - 1;
+
+ /* Get luck */
+ p_ptr->luck_base = rp_ptr->luck + rmp_ptr->luck + rand_range( -5, 5);
+ p_ptr->luck_max = p_ptr->luck_base;
+
+ /* Interact */
+ while (1)
+ {
+ /* Reset cost */
+ cost = 0;
+
+ /* Process stats */
+ for (i = 0; i < 6; i++)
+ {
+ /* Variable stat maxes */
+ if (p_ptr->maximize)
+ {
+ /* Reset stats */
+ p_ptr->stat_cur[i] = p_ptr->stat_max[i] = stats[i];
+
+ }
+
+ /* Fixed stat maxes */
+ else
+ {
+ /* Obtain a "bonus" for "race" and "class" */
+ int bonus = rp_ptr->r_adj[i] + cp_ptr->c_adj[i];
+
+ /* Apply the racial/class bonuses */
+ p_ptr->stat_cur[i] = p_ptr->stat_max[i] =
+ modify_stat_value(stats[i], bonus);
+ }
+
+ /* Total cost */
+ cost += birth_stat_costs[stats[i] - 10];
+ }
+
+ /* Restrict cost */
+ if (cost > 48)
+ {
+ /* Warning */
+ bell();
+
+ /* Reduce stat */
+ stats[stat]--;
+
+ /* Recompute costs */
+ continue;
+ }
+
+ /* Gold is inversely proportional to cost */
+ p_ptr->au = (100 * (48 - cost)) + 100;
+
+ /* Maximum of 600 gold */
+ if (p_ptr->au > 600) p_ptr->au = 600;
+
+ /* Calculate the bonuses and hitpoints */
+ p_ptr->update |= (PU_BONUS | PU_HP);
+
+ /* Update stuff */
+ update_stuff();
+
+ /* Fully healed */
+ p_ptr->chp = p_ptr->mhp;
+
+ /* Fully rested */
+ p_ptr->csp = p_ptr->msp;
+
+ /* Display the player */
+ display_player(mode);
+
+ /* Display the costs header */
+ put_str("Cost", row - 2, col + 32);
+
+ /* Display the costs */
+ for (i = 0; i < 6; i++)
+ {
+ /* Display cost */
+ strnfmt(buf, 80, "%4d", birth_stat_costs[stats[i] - 10]);
+ put_str(buf, row + (i - 1), col + 32);
+ }
+
+
+ /* Prompt XXX XXX XXX */
+ strnfmt(buf, 80, "Total Cost %2d/48. Use 2/8 to move, 4/6 to modify, ESC to accept.", cost);
+ prt(buf, 0, 0);
+
+ /* Place cursor just after cost of current stat */
+ Term_gotoxy(col + 36, row + stat - 1);
+
+ /* Get key */
+ ch = inkey();
+
+ /* Quit */
+ if (ch == 'Q') quit(NULL);
+
+ /* Start over */
+ if (ch == 'S') return (FALSE);
+
+ /* Done */
+ if (ch == ESCAPE) break;
+
+ /* Prev stat */
+ if (ch == '8')
+ {
+ stat = (stat + 6 - 1) % 6;
+ }
+
+ /* Next stat */
+ if (ch == '2')
+ {
+ stat = (stat + 1) % 6;
+ }
+
+ /* Decrease stat */
+ if ((ch == '4') && (stats[stat] > 10))
+ {
+ stats[stat]--;
+ }
+
+ /* Increase stat */
+ if ((ch == '6') && (stats[stat] < 18))
+ {
+ stats[stat]++;
+ }
+ }
+
+
+ /* Done */
+ return (TRUE);
+}
+
+/*
+ * Use the autoroller or not to generate a char
+ */
+static bool_ player_birth_aux_auto()
+{
+ int i, j, m, v;
+
+ int mode = 0;
+
+ bool_ flag = FALSE;
+
+ bool_ prev = FALSE;
+
+ char c;
+
+ char b1 = '[';
+
+ char b2 = ']';
+
+ char buf[80];
+
+ char inp[80];
+
+
+#ifdef ALLOW_AUTOROLLER
+
+ /* Initialize */
+ if (autoroll)
+ {
+ int mval[6];
+
+
+ /* Clear fields */
+ auto_round = 0L;
+ last_round = 0L;
+
+ /* Clean up */
+ clear_from(10);
+
+ /* Prompt for the minimum stats */
+ put_str("Enter minimum attribute for: ", 15, 2);
+
+ /* Output the maximum stats */
+ for (i = 0; i < 6; i++)
+ {
+ char stat_buf[15];
+
+ /* Reset the "success" counter */
+ stat_match[i] = 0;
+
+ /* Race/Class bonus */
+ j = rp_ptr->r_adj[i] + rmp_ptr->r_adj[i] + cp_ptr->c_adj[i];
+
+ /* Obtain the "maximal" stat */
+ m = adjust_stat(17, j, TRUE);
+
+
+ /* Save the maximum */
+ mval[i] = m;
+
+ /* Extract a textual format */
+ cnv_stat(m, stat_buf);
+
+ strnfmt(inp, 80, "(Max of %s):", stat_buf);
+
+ /* Prepare a prompt */
+ strnfmt(buf, 80, "%-5s: %-20s", stat_names[i], inp);
+
+ /* Dump the prompt */
+ put_str(buf, 16 + i, 5);
+ }
+
+ /* Input the minimum stats */
+ for (i = 0; i < 6; i++)
+ {
+ /* Get a minimum stat */
+ while (TRUE)
+ {
+ char *s;
+
+ /* Move the cursor */
+ put_str("", 16 + i, 30);
+
+ /* Default */
+ strcpy(inp, "");
+
+ /* Get a response (or escape) */
+ if (!askfor_aux(inp, 8)) inp[0] = '\0';
+
+ /* Weirdos stat display .. erm .. I mean, original stat display */
+ if (!linear_stats)
+ {
+ /* Hack -- add a fake slash */
+ strcat(inp, "/");
+
+ /* Hack -- look for the "slash" */
+ s = strchr(inp, '/');
+
+ /* Hack -- Nuke the slash */
+ *s++ = '\0';
+
+ /* Hack -- Extract an input */
+ v = atoi(inp) + atoi(s);
+ }
+ else
+ {
+ int z = atoi(inp);
+
+ if (z <= 18)
+ v = z;
+ else
+ {
+ int extra = z - 18;
+ v = 18 + (extra * 10);
+ }
+ }
+
+ /* Break on valid input */
+ if (v <= mval[i]) break;
+ }
+
+ /* Save the minimum stat */
+ stat_limit[i] = (v > 0) ? v : 0;
+ }
+ }
+
+#endif /* ALLOW_AUTOROLLER */
+
+ /* Roll */
+ while (TRUE)
+ {
+ /* Feedback */
+ if (autoroll)
+ {
+ Term_clear();
+
+ put_str("Name :", 2, 1);
+ put_str("Sex :", 3, 1);
+ put_str("Race :", 4, 1);
+ put_str("Class:", 5, 1);
+
+ c_put_str(TERM_L_BLUE, player_name, 2, 9);
+ c_put_str(TERM_L_BLUE, sp_ptr->title, 3, 9);
+ strnfmt(buf, 80, "%s", get_player_race_name(p_ptr->prace, p_ptr->pracem));
+ c_put_str(TERM_L_BLUE, buf, 4, 9);
+ c_put_str(TERM_L_BLUE, spp_ptr->title + c_name, 5, 9);
+
+ /* Label stats */
+ put_str("STR:", 2 + A_STR, 61);
+ put_str("INT:", 2 + A_INT, 61);
+ put_str("WIS:", 2 + A_WIS, 61);
+ put_str("DEX:", 2 + A_DEX, 61);
+ put_str("CON:", 2 + A_CON, 61);
+ put_str("CHR:", 2 + A_CHR, 61);
+
+ /* Note when we started */
+ last_round = auto_round;
+
+ /* Indicate the state */
+ put_str("(Hit ESC to abort)", 11, 61);
+
+ /* Label count */
+ put_str("Round:", 9, 61);
+ }
+
+ /* Otherwise just get a character */
+ else
+ {
+ /* Get a new character */
+ get_stats();
+ }
+
+ /* Auto-roll */
+ while (autoroll)
+ {
+ bool_ accept = TRUE;
+
+ /* Get a new character */
+ get_stats();
+
+ /* Advance the round */
+ auto_round++;
+
+ /* Hack -- Prevent overflow */
+ if (auto_round >= 1000000L) break;
+
+ /* Check and count acceptable stats */
+ for (i = 0; i < 6; i++)
+ {
+ /* This stat is okay */
+ if (stat_use[i] >= stat_limit[i])
+ {
+ stat_match[i]++;
+ }
+
+ /* This stat is not okay */
+ else
+ {
+ accept = FALSE;
+ }
+ }
+
+ /* Break if "happy" */
+ if (accept) break;
+
+ /* Take note every 25 rolls */
+ flag = (!(auto_round % AUTOROLLER_STEP));
+
+ /* Update display occasionally */
+ if (flag || (auto_round < last_round + 100))
+ {
+ /* Dump data */
+ birth_put_stats();
+
+ /* Dump round */
+ put_str(format("%6ld", auto_round), 9, 73);
+
+ /* Make sure they see everything */
+ Term_fresh();
+
+#ifndef USE_FAST_AUTOROLLER
+
+ /* Delay 1/10 second */
+ if (fast_autoroller && flag) Term_xtra(TERM_XTRA_DELAY, 100);
+
+#endif
+ /* Do not wait for a key */
+ inkey_scan = TRUE;
+
+ /* Check for a keypress */
+ if (inkey()) break;
+ }
+ }
+
+ /* Flush input */
+ flush();
+
+
+ /*** Display ***/
+
+ /* Mode */
+ mode = 0;
+
+ /* Roll for base hitpoints */
+ get_extra();
+
+ /* Roll for age/height/weight */
+ get_ahw();
+
+ /* Roll for social class */
+ get_history();
+
+ /* Roll for gold */
+ get_money();
+
+ /*** Generate ***/
+ process_hooks(HOOK_BIRTH, "()");
+
+ /* Hack -- get a chaos patron even if you are not a chaos warrior */
+ p_ptr->chaos_patron = (randint(MAX_PATRON)) - 1;
+
+ /* Input loop */
+ while (TRUE)
+ {
+ /* Calculate the bonuses and hitpoints */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_BODY);
+
+ /* Update stuff */
+ update_stuff();
+
+ /* Fully healed */
+ p_ptr->chp = p_ptr->mhp;
+
+ /* Fully rested */
+ p_ptr->csp = p_ptr->msp;
+
+ /* Display the player */
+ display_player(mode);
+
+ /* Prepare a prompt (must squeeze everything in) */
+ Term_gotoxy(2, 23);
+ Term_addch(TERM_WHITE, b1);
+ Term_addstr( -1, TERM_WHITE, "'r' to reroll");
+ if (prev) Term_addstr( -1, TERM_WHITE, ", 'p' for prev");
+ if (mode) Term_addstr( -1, TERM_WHITE, ", 'h' for Misc.");
+ else Term_addstr( -1, TERM_WHITE, ", 'h' for History");
+ Term_addstr( -1, TERM_WHITE, ", or ESC to accept");
+ Term_addch(TERM_WHITE, b2);
+
+ /* Prompt and get a command */
+ c = inkey();
+
+ /* Quit */
+ if (c == 'Q') quit(NULL);
+
+ /* Start over */
+ if (c == 'S') return (FALSE);
+
+ /* Escape accepts the roll */
+ if (c == ESCAPE) break;
+
+ /* Reroll this character */
+ if ((c == ' ') || (c == 'r')) break;
+
+ /* Previous character */
+ if (prev && (c == 'p'))
+ {
+ load_prev_data(TRUE);
+ continue;
+ }
+
+ /* Toggle the display */
+ if ((c == 'H') || (c == 'h'))
+ {
+ mode = ((mode != 0) ? 0 : 1);
+ continue;
+ }
+
+ /* Help */
+ if (c == '?')
+ {
+ do_cmd_help();
+ continue;
+ }
+
+ /* Warning */
+ bell();
+ }
+
+ /* Are we done? */
+ if (c == ESCAPE) break;
+
+ /* Save this for the "previous" character */
+ save_prev_data();
+
+ /* Note that a previous roll exists */
+ prev = TRUE;
+ }
+
+ /* Clear prompt */
+ clear_from(23);
+
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for 'player_birth()'
+ *
+ * The delay may be reduced, but is recommended to keep players
+ * from continuously rolling up characters, which can be VERY
+ * expensive CPU wise. And it cuts down on player stupidity.
+ */
+static bool_ player_birth_aux()
+{
+ char c;
+
+ int i, j;
+
+ int y = 0, x = 0;
+
+ char old_history[4][60];
+
+ /* Ask */
+ if (!player_birth_aux_ask()) return (FALSE);
+
+ for (i = 1; i < max_s_idx; i++)
+ s_info[i].dev = FALSE;
+ for (i = 1; i < max_s_idx; i++)
+ {
+ s32b value = 0, mod = 0;
+
+ compute_skills(&value, &mod, i);
+
+ init_skill(value, mod, i);
+
+ /* Develop only revelant branches */
+ if (s_info[i].value || s_info[i].mod)
+ {
+ int z = s_info[i].father;
+
+ while (z != -1)
+ {
+ s_info[z].dev = TRUE;
+ z = s_info[z].father;
+ if (z == 0)
+ break;
+ }
+ }
+ }
+
+ if (do_quick_start)
+ {
+ load_prev_data(FALSE);
+
+ /* Roll for base hitpoints */
+ get_extra();
+
+ /* Calculate the bonuses and hitpoints */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_BODY);
+
+ /* Update stuff */
+ update_stuff();
+
+ /* Fully healed */
+ p_ptr->chp = p_ptr->mhp;
+
+ /* Fully rested */
+ p_ptr->csp = p_ptr->msp;
+ }
+ else
+ {
+ /* Point based */
+ if (point_based)
+ {
+ if (!player_birth_aux_point()) return FALSE;
+ }
+ /* Auto-roll */
+ else
+ {
+ if (!player_birth_aux_auto()) return FALSE;
+ }
+
+ /* Edit character background */
+ for (i = 0; i < 4; i++)
+ {
+ strnfmt(old_history[i], 60, "%s", history[i]);
+ }
+ /* Turn 0 to space */
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; history[i][j]; j++) /* loop */;
+
+ for (; j < 59; j++) history[i][j] = ' ';
+ }
+ display_player(1);
+ c_put_str(TERM_L_GREEN, "(Character Background - Edit Mode)", 15, 20);
+ while (TRUE)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ put_str(history[i], i + 16, 10);
+ }
+ c_put_str(TERM_L_BLUE, format("%c", history[y][x]), y + 16, x + 10);
+
+ /* Place cursor just after cost of current stat */
+ Term_gotoxy(x + 10, y + 16);
+
+ c = inkey();
+
+ if (c == '8')
+ {
+ y--;
+ if (y < 0) y = 3;
+ }
+ else if (c == '2')
+ {
+ y++;
+ if (y > 3) y = 0;
+ }
+ else if (c == '6')
+ {
+ x++;
+ if (x > 59) x = 0;
+ }
+ else if (c == '4')
+ {
+ x--;
+ if (x < 0) x = 59;
+ }
+ else if (c == '\r')
+ {
+ break;
+ }
+ else if (c == ESCAPE)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ strnfmt(history[i], 60, "%s", old_history[i]);
+ put_str(history[i], i + 16, 10);
+ }
+ break;
+ }
+ else
+ {
+ history[y][x++] = c;
+ if (x > 58)
+ {
+ x = 0;
+ y++;
+ if (y > 3) y = 0;
+ }
+ }
+ }
+
+
+ /*** Finish up ***/
+
+ /* Get a name, recolor it, prepare savefile */
+
+ get_name();
+
+
+ /* Prompt for it */
+ prt("['Q' to suicide, 'S' to start over, or ESC to continue]", 23, 10);
+
+ /* Get a key */
+ c = inkey();
+
+ /* Quit */
+ if (c == 'Q') quit(NULL);
+
+ /* Start over */
+ if (c == 'S') return (FALSE);
+ }
+
+ /* Save this for the next character */
+ previous_char.quick_ok = TRUE;
+ save_prev_data();
+
+ /* Accept */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for validate_bg().
+ */
+static void validate_bg_aux(int chart, bool_ chart_checked[], char *buf)
+{
+ char *s;
+
+ int i;
+
+
+ /* Assume the chart does not exist */
+ bool_ chart_exists = FALSE;
+
+ /* Assume the chart is not complete */
+ bool_ chart_complete = FALSE;
+
+ int bg_max = max_bg_idx;
+
+ /* No chart */
+ if (!chart) return;
+
+ /* Already saw this chart */
+ if (chart_checked[chart]) return;
+
+ /* Build a debug message */
+ s = buf + strlen(buf);
+
+ /* XXX XXX XXX */
+ (void) strnfmt(s, -1, "%d --> ", chart);
+
+ /* Check each chart */
+ for (i = 0; i < bg_max; i++)
+ {
+ /* Require same chart */
+ if (bg[i].chart != chart) continue;
+
+ /* The chart exists */
+ chart_exists = TRUE;
+
+ /* Validate the "next" chart recursively */
+ validate_bg_aux(bg[i].next, chart_checked, buf);
+
+ /* Require a terminator */
+ if (bg[i].roll != 100) continue;
+
+ /* The chart is complete */
+ chart_complete = TRUE;
+ }
+
+ /* Failed: The chart does not exist */
+ if (!chart_exists)
+ {
+ quit_fmt("birth.c: bg[] chart %d does not exist\n%s", chart, buf);
+ }
+
+ /* Failed: The chart is not complete */
+ if (!chart_complete)
+ {
+ quit_fmt("birth.c: bg[] chart %d is not complete", chart);
+ }
+
+ /* Remember we saw this chart */
+ chart_checked[chart] = TRUE;
+
+ /* Build a debug message */
+ *s = 0;
+}
+
+
+/*
+ * Verify that the bg[] table is valid.
+ */
+static void validate_bg(void)
+{
+ int i, race;
+
+ bool_ chart_checked[512];
+
+ char buf[1024];
+
+
+ for (i = 0; i < 512; i++) chart_checked[i] = FALSE;
+
+ /* Check each race */
+ for (race = 0; race < max_rp_idx; race++)
+ {
+ /* Get the first chart for this race */
+ int chart = race_info[race].chart;
+
+ (void) strcpy(buf, "");
+
+ /* Validate the chart recursively */
+ validate_bg_aux(chart, chart_checked, buf);
+ }
+}
+
+/*
+ * Initialize a random town
+ */
+void init_town(int t_idx, int level)
+{
+ town_type *t_ptr = &town_info[t_idx];
+
+ /* Mark it as existent */
+ t_ptr->flags |= (TOWN_REAL);
+
+ /* Mark it as not found */
+ t_ptr->flags &= ~(TOWN_KNOWN);
+
+ /* Generation seed for the town */
+ t_ptr->seed = randint(0x10000000);
+
+ /* Total hack and not even used */
+ t_ptr->numstores = 8;
+}
+
+/*
+ * Create a new character.
+ *
+ * Note that we may be called with "junk" leftover in the various
+ * fields, so we must be sure to clear them first.
+ */
+void player_birth(void)
+{
+ int i, j, rtown = TOWN_RANDOM;
+
+ /* Validate the bg[] table */
+ validate_bg();
+
+ /* Create a new character */
+ while (1)
+ {
+ /* Wipe the player */
+ player_wipe();
+
+ /* Roll up a new character */
+ if (player_birth_aux()) break;
+ }
+
+ /* Finish skills */
+ p_ptr->skill_points = 0;
+ p_ptr->skill_last_level = 1;
+
+ recalc_skills(FALSE);
+
+ /* grab level 1 abilities */
+ for (i = 0; i < max_ab_idx; i++)
+ ab_info[i].acquired = FALSE;
+ apply_level_abilities(1);
+
+ /* Complete the god */
+ i = p_ptr->pgod;
+ p_ptr->pgod = 0;
+ follow_god(i, TRUE);
+
+ /* Select the default melee type */
+ select_default_melee();
+
+ /* Make a note file if that option is set */
+ if (take_notes)
+ {
+ add_note_type(NOTE_BIRTH);
+ }
+
+ /* Note player birth in the message recall */
+ message_add(MESSAGE_MSG, " ", TERM_L_BLUE);
+ message_add(MESSAGE_MSG, " ", TERM_L_BLUE);
+ message_add(MESSAGE_MSG, "====================", TERM_L_BLUE);
+ message_add(MESSAGE_MSG, " ", TERM_L_BLUE);
+ message_add(MESSAGE_MSG, " ", TERM_L_BLUE);
+
+ /* Hack -- outfit the player */
+ player_outfit();
+
+ /* Initialize random towns in the dungeons */
+ for (i = 0; i < max_d_idx; i++)
+ {
+ dungeon_info_type *d_ptr = &d_info[i];
+ int num = 0, z;
+
+ d_ptr->t_num = 0;
+ for (z = 0; z < TOWN_DUNGEON; z++)
+ {
+ d_ptr->t_idx[z] = 0;
+ d_ptr->t_level[z] = 0;
+ }
+ if (!(d_ptr->flags1 & DF1_RANDOM_TOWNS)) continue;
+
+ /* Can we add a town ? */
+ while (magik(TOWN_CHANCE - (num * 10)))
+ {
+ int lev;
+
+ d_ptr->t_idx[num] = rtown;
+ rtown++;
+
+ while (TRUE)
+ {
+ int j;
+ bool_ ok = TRUE;
+
+ lev = rand_range(d_ptr->mindepth, d_ptr->maxdepth - 1);
+
+ /* Be sure it wasnt already used */
+ for (j = 0; j < num; j++)
+ {
+ if (d_ptr->t_level[j] == lev) ok = FALSE;
+ }
+
+ /* Ok found one */
+ if (ok) break;
+ }
+ d_ptr->t_level[num] = lev;
+
+ if (wizard) message_add(MESSAGE_MSG, format("Random dungeon town: d_idx:%d, lev:%d", i, lev), TERM_WHITE);
+
+ /* Create the town */
+ init_town(d_ptr->t_idx[num], d_ptr->t_level[num]);
+
+ num++;
+
+ /* No free slots left */
+ if (num >= TOWN_DUNGEON) break;
+ }
+
+ d_ptr->t_num = num;
+ }
+
+ /* Init the towns */
+ for (i = 1; i < max_towns; i++)
+ {
+ /* Not destroyed ! yet .. ;) */
+ town_info[i].destroyed = FALSE;
+
+ /* Ignore non-existent towns */
+ if (!(town_info[i].flags & (TOWN_REAL))) continue;
+
+ create_stores_stock(i);
+
+ /* Init the stores */
+ for (j = 0; j < max_st_idx; j++)
+ {
+ /* Initialize */
+ store_init(i, j);
+ }
+ }
+
+ /* Init wilderness seeds */
+ for (i = 0; i < max_wild_x; i++)
+ {
+ for (j = 0; j < max_wild_y; j++)
+ {
+ wild_map[j][i].seed = rand_int(0x10000000);
+ wild_map[j][i].entrance = 0;
+ wild_map[j][i].known = FALSE;
+ }
+ }
+
+ /* Select bounty monsters. */
+ select_bounties();
+}
+
+
+
+
+char savefile_module[46][80];
+char savefile_names[46][30];
+char savefile_desc[46][80];
+bool_ savefile_alive[46];
+int savefile_idx[46];
+
+/*
+ * Grab all the names from an index
+ */
+int load_savefile_names()
+{
+ FILE *fff;
+ char buf[1024];
+ char tmp[50];
+ char player_base_save[32];
+ int max = 0, fd;
+
+
+ /* Build the filename */
+ strcpy(tmp, "global.svg");
+ path_build(buf, 1024, ANGBAND_DIR_SAVE, tmp);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Read the file */
+ fff = my_fopen(buf, "r");
+
+ /* Failure */
+ if (!fff) return (0);
+
+
+ /* Save the current 'player_base' */
+ strncpy(player_base_save, player_base, 32);
+
+
+ /*
+ * Parse, use '@' intead of ':' as a separator because it cannot exists
+ * in savefiles
+ */
+ while (0 == my_fgets(fff, buf, 1024))
+ {
+ int i = 0, start, count;
+
+ /* Check for pre-ToME 2.1.2 file */
+ count = 0;
+ i = 0;
+ while (buf[i] && buf[i] != '\n')
+ {
+ if (buf[i] == '@')
+ ++count;
+ ++i;
+ }
+
+ /* Check module if a current svg file */
+ start = 0;
+ i = 0;
+ if (count > 1)
+ {
+ while (buf[i] != '@')
+ {
+ savefile_module[max][i - start] = buf[i];
+ i++;
+ }
+ savefile_module[max][i] = '\0';
+ i++;
+ }
+ /* Default to ToME for old files */
+ else
+ {
+ savefile_module[max][0] = 'T';
+ savefile_module[max][1] = 'o';
+ savefile_module[max][2] = 'M';
+ savefile_module[max][3] = 'E';
+ savefile_module[max][4] = '\0';
+ }
+
+ if (buf[i] == '0') savefile_alive[max] = FALSE;
+ else if (buf[i] == '1') savefile_alive[max] = TRUE;
+
+ i++;
+ start = i;
+ while (buf[i] != '@')
+ {
+ savefile_names[max][i - start] = buf[i];
+ i++;
+ }
+ savefile_names[max][i - start] = '\0';
+ i++;
+ strcpy(savefile_desc[max], buf + i);
+
+ /* Build platform-dependent savefile name */
+ strncpy(player_base, savefile_names[max], 32);
+ process_player_name(TRUE);
+
+ /* File type is 'SAVE' */
+ FILE_TYPE(FILE_TYPE_SAVE);
+
+ /* Try to open the savefile */
+ fd = fd_open(savefile, O_RDONLY);
+
+ /* Still existing ? */
+ if (fd >= 0)
+ {
+ fd_close(fd);
+ max++;
+ }
+ }
+
+ my_fclose(fff);
+
+ /* Restore the values of 'player_base' and 'savefile' */
+ strncpy(player_base, player_base_save, 32);
+ process_player_name(TRUE);
+
+ return (max);
+}
+
+
+/*
+ * Save all the names from an index
+ */
+void save_savefile_names()
+{
+ FILE *fff;
+ char buf[1024];
+ char tmp[50];
+ int max = load_savefile_names(), i;
+
+
+ /* Build the filename */
+ strcpy(tmp, "global.svg");
+ path_build(buf, 1024, ANGBAND_DIR_SAVE, tmp);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Read the file */
+ fff = my_fopen(buf, "w");
+
+ /* Failure */
+ if (!fff) return;
+
+ /*
+ * Save, use '@' intead of ':' as a separator because it cannot exists
+ * in savefiles
+ */
+ fprintf(fff, "%s@%c%s@%s, the %s %s is %s\n", game_module,
+ (death) ? '0' : '1', player_base, player_name,
+ get_player_race_name(p_ptr->prace, p_ptr->pracem),
+ spp_ptr->title + c_name,
+ (!death) ? "alive" : "dead");
+
+ for (i = 0; i < max; i++)
+ {
+ if (!strcmp(savefile_names[i], player_base)) continue;
+ fprintf(fff, "%s@%c%s@%s\n", savefile_module[i],
+ (savefile_alive[i]) ? '1' : '0', savefile_names[i], savefile_desc[i]);
+ }
+
+ my_fclose(fff);
+}
+
+
+static void dump_savefiles(int sel, int max)
+{
+ int i;
+
+ char buf[40], pre = ' ', post = ')';
+
+ char ind;
+
+
+ for (i = 0; i < max; i++)
+ {
+ ind = I2A(i % 26);
+ if (i >= 26) ind = toupper(ind);
+
+ if (sel == i)
+ {
+ pre = '[';
+ post = ']';
+ }
+ else
+ {
+ pre = ' ';
+ post = ')';
+ }
+
+ if (i == 0) strnfmt(buf, 40, "%c%c%c New Character", pre, ind, post);
+ else if (i == 1) strnfmt(buf, 40, "%c%c%c Load Savefile", pre, ind, post);
+ else strnfmt(buf, 40, "%c%c%c %s", pre, ind, post, savefile_names[savefile_idx[i - 2]]);
+
+ if (sel == i)
+ {
+ if (i >= 2)
+ {
+ if (savefile_alive[i - 2]) c_put_str(TERM_L_GREEN, savefile_desc[savefile_idx[i - 2]], 5, 0);
+ else c_put_str(TERM_L_RED, savefile_desc[savefile_idx[i - 2]], 5, 0);
+ }
+ else if (i == 1) c_put_str(TERM_YELLOW, "Load an existing savefile that is not in the list", 5, 0);
+ else c_put_str(TERM_YELLOW, "Create a new character", 5, 0);
+ c_put_str(TERM_L_BLUE, buf, 6 + (i / 4), 20 * (i % 4));
+ }
+ else
+ put_str(buf, 6 + (i / 4), 20 * (i % 4));
+ }
+}
+
+
+/* Asks for new game or load game */
+bool_ no_begin_screen = FALSE;
+
+bool_ begin_screen()
+{
+ int m, k, sel, max;
+
+savefile_try_again:
+ sel = 0;
+
+ /* Grab the savefiles */
+ max = load_savefile_names();
+
+ /* Get only the usable savefiles */
+ for (k = 0, m = 0; k < max; k++)
+ {
+ s32b can_use;
+
+ call_lua("module_savefile_loadable", "(s)", "d", savefile_module[k], &can_use);
+ if (can_use)
+ {
+ savefile_idx[m++] = k;
+ }
+ }
+ max = m + 2;
+ if (max > 2) sel = 2;
+
+ while (TRUE)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Let the user choose */
+ c_put_str(TERM_YELLOW, format("Welcome to %s! To play you will need a character.", game_module), 1, 10);
+ put_str("Press 8/2/4/6 to move, Return to select, Backspace to delete a savefile.", 3, 3);
+ put_str("and Esc to quit.", 4, 32);
+
+ dump_savefiles(sel, max);
+
+ k = inkey();
+
+ if (k == ESCAPE)
+ {
+ quit(NULL);
+ }
+ if (k == '6')
+ {
+ sel++;
+ if (sel >= max) sel = 0;
+ continue;
+ }
+ else if (k == '4')
+ {
+ sel--;
+ if (sel < 0) sel = max - 1;
+ continue;
+ }
+ else if (k == '2')
+ {
+ sel += 4;
+ if (sel >= max) sel = sel % max;
+ continue;
+ }
+ else if (k == '8')
+ {
+ sel -= 4;
+ if (sel < 0) sel = (sel + max - 1) % max;
+ continue;
+ }
+ else if (k == '\r')
+ {
+ if (sel < 26) k = I2A(sel);
+ else k = toupper(I2A(sel));
+ }
+ else if (((k == 0x7F) || (k == '\010')) && (sel >= 2))
+ {
+ char player_base_save[32];
+
+ if (!get_check(format("Really delete '%s'?", savefile_names[savefile_idx[sel - 2]]))) continue;
+
+ /* Save current 'player_base' */
+ strncpy(player_base_save, player_base, 32);
+
+ /* Build platform-dependent save file name */
+ strncpy(player_base, savefile_names[savefile_idx[sel - 2]], 32);
+ process_player_name(TRUE);
+
+ /* Remove the savefile */
+ fd_kill(savefile);
+
+ /* Restore 'player_base' and 'savefile' */
+ strncpy(player_base, player_base_save, 32);
+ process_player_name(TRUE);
+
+ /* Reload, gods I hate using goto .. */
+ goto savefile_try_again;
+
+ continue;
+ }
+
+ if (k == 'a')
+ {
+ /* Display prompt */
+ prt("Enter the name of the savefile that will hold this character: ", 23, 0);
+
+ /* Ask the user for a string */
+ if (!askfor_aux(player_base, 15)) continue;
+
+ /* Process the player name */
+ process_player_name(TRUE);
+
+ return (TRUE);
+ }
+ if (k == 'b')
+ {
+ /* Display prompt */
+ prt("Enter the name of a savefile: ", 23, 0);
+
+ /* Ask the user for a string */
+ if (!askfor_aux(player_base, 15)) continue;
+
+ /* Process the player name */
+ process_player_name(TRUE);
+
+ return (FALSE);
+ }
+ else
+ {
+ int x;
+
+ if (islower(k)) x = A2I(k);
+ else x = A2I(tolower(k)) + 26;
+
+ if ((x < 2) || (x >= max)) continue;
+
+ strnfmt(player_base, 32, "%s", savefile_names[savefile_idx[x - 2]]);
+
+ /* Process the player name */
+ process_player_name(TRUE);
+
+ return (FALSE);
+ }
+ }
+
+ /* Shouldnt happen */
+ return (FALSE);
+}
diff --git a/src/bldg.c b/src/bldg.c
new file mode 100644
index 00000000..48e94e9f
--- /dev/null
+++ b/src/bldg.c
@@ -0,0 +1,2198 @@
+/* File: bldg.c */
+
+/*
+ * Purpose: Building commands
+ * Created by Ken Wigle for Kangband - a variant of Angband 2.8.3
+ * -KMW-
+ *
+ * Rewritten for Kangband 2.8.3i using Kamband's version of
+ * bldg.c as written by Ivan Tkatchev
+ *
+ * Changed for ZAngband by Robert Ruehlmann
+ *
+ * Heavily modified for ToME by DarkGod
+ */
+
+#include "angband.h"
+
+/* hack as in leave_store in store.c */
+static bool_ leave_bldg = FALSE;
+
+/* remember building location */
+static int building_loc = 0;
+
+
+/*
+ * A helper function for is_state
+ */
+bool_ is_state_aux(store_type *s_ptr, int state)
+{
+ owner_type *ow_ptr = &ow_info[s_ptr->owner];
+
+
+ /* Check race */
+ if (ow_ptr->races[state][p_ptr->prace / 32] & (1 << p_ptr->prace))
+ {
+ return (TRUE);
+ }
+
+ /* Check class */
+ if (ow_ptr->classes[state][p_ptr->prace / 32] & (1 << p_ptr->pclass))
+ {
+ return (TRUE);
+ }
+
+ /* All failed */
+ return (FALSE);
+}
+
+
+/*
+ * Test if the state accords with the player
+ */
+bool_ is_state(store_type *s_ptr, int state)
+{
+ if (state == STORE_NORMAL)
+ {
+ if (is_state_aux(s_ptr, STORE_LIKED)) return (FALSE);
+ if (is_state_aux(s_ptr, STORE_HATED)) return (FALSE);
+ return (TRUE);
+ }
+
+ else
+ {
+ return (is_state_aux(s_ptr, state));
+ }
+}
+
+
+/*
+ * Clear the building information
+ */
+static void clear_bldg(int min_row, int max_row)
+{
+ int i;
+
+
+ for (i = min_row; i <= max_row; i++)
+ {
+ prt("", i, 0);
+ }
+}
+
+
+/*
+ * Display a building.
+ */
+void show_building(store_type *s_ptr)
+{
+ char buff[20];
+
+ int i;
+
+ byte action_color;
+
+ char tmp_str[80];
+
+ store_info_type *st_ptr = &st_info[s_ptr->st_idx];
+
+ store_action_type *ba_ptr;
+
+
+ for (i = 0; i < 6; i++)
+ {
+ ba_ptr = &ba_info[st_ptr->actions[i]];
+
+ if (ba_ptr->letter != '.')
+ {
+ if (ba_ptr->action_restr == 0)
+ {
+ if ((is_state(s_ptr, STORE_LIKED) && (ba_ptr->costs[STORE_LIKED] == 0)) ||
+ (is_state(s_ptr, STORE_HATED) && (ba_ptr->costs[STORE_HATED] == 0)) ||
+ (is_state(s_ptr, STORE_NORMAL) && (ba_ptr->costs[STORE_NORMAL] == 0)))
+ {
+ action_color = TERM_WHITE;
+ buff[0] = '\0';
+ }
+ else if (is_state(s_ptr, STORE_LIKED))
+ {
+ action_color = TERM_L_GREEN;
+ strnfmt(buff, 20, "(%dgp)", ba_ptr->costs[STORE_LIKED]);
+ }
+ else if (is_state(s_ptr, STORE_HATED))
+ {
+ action_color = TERM_RED;
+ strnfmt(buff, 20, "(%dgp)", ba_ptr->costs[STORE_HATED]);
+ }
+ else
+ {
+ action_color = TERM_YELLOW;
+ strnfmt(buff, 20, "(%dgp)", ba_ptr->costs[STORE_NORMAL]);
+ }
+ }
+ else if (ba_ptr->action_restr == 1)
+ {
+ if ((is_state(s_ptr, STORE_LIKED) && (ba_ptr->costs[STORE_LIKED] == 0)) ||
+ (is_state(s_ptr, STORE_NORMAL) && (ba_ptr->costs[STORE_NORMAL] == 0)))
+ {
+ action_color = TERM_WHITE;
+ buff[0] = '\0';
+ }
+ else if (is_state(s_ptr, STORE_LIKED))
+ {
+ action_color = TERM_L_GREEN;
+ strnfmt(buff, 20, "(%dgp)", ba_ptr->costs[STORE_LIKED]);
+ }
+ else if (is_state(s_ptr, STORE_HATED))
+ {
+ action_color = TERM_L_DARK;
+ strnfmt(buff, 20, "(closed)");
+ }
+ else
+ {
+ action_color = TERM_YELLOW;
+ strnfmt(buff, 20, "(%dgp)", ba_ptr->costs[STORE_NORMAL]);
+ }
+ }
+ else
+ {
+ if (is_state(s_ptr, STORE_LIKED) && (ba_ptr->costs[STORE_LIKED] == 0))
+ {
+ action_color = TERM_WHITE;
+ buff[0] = '\0';
+ }
+ else if (is_state(s_ptr, STORE_LIKED))
+ {
+ action_color = TERM_L_GREEN;
+ strnfmt(buff, 20, "(%dgp)", ba_ptr->costs[STORE_LIKED]);
+ }
+ else
+ {
+ action_color = TERM_L_DARK;
+ strnfmt(buff, 20, "(closed)");
+ }
+ }
+
+ strnfmt(tmp_str, 80, " %c", ba_ptr->letter);
+ c_put_str(TERM_YELLOW, tmp_str, 21 + (i / 2), 17 + (30 * (i % 2)));
+
+ strnfmt(tmp_str, 80, ") %s %s", ba_ptr->name + ba_name, buff);
+ c_put_str(action_color, tmp_str, 21 + (i / 2), 2 + 17 + (30 * (i % 2)));
+ }
+ }
+}
+
+
+/* reset timed flags */
+static void reset_tim_flags()
+{
+ p_ptr->fast = 0; /* Timed -- Fast */
+ p_ptr->slow = 0; /* Timed -- Slow */
+ p_ptr->blind = 0; /* Timed -- Blindness */
+ p_ptr->paralyzed = 0; /* Timed -- Paralysis */
+ p_ptr->confused = 0; /* Timed -- Confusion */
+ p_ptr->afraid = 0; /* Timed -- Fear */
+ p_ptr->image = 0; /* Timed -- Hallucination */
+ p_ptr->poisoned = 0; /* Timed -- Poisoned */
+ p_ptr->cut = 0; /* Timed -- Cut */
+ p_ptr->stun = 0; /* Timed -- Stun */
+
+ p_ptr->protevil = 0; /* Timed -- Protection */
+ p_ptr->protgood = 0; /* Timed -- Protection */
+ p_ptr->invuln = 0; /* Timed -- Invulnerable */
+ p_ptr->hero = 0; /* Timed -- Heroism */
+ p_ptr->shero = 0; /* Timed -- Super Heroism */
+ p_ptr->shield = 0; /* Timed -- Shield Spell */
+ p_ptr->blessed = 0; /* Timed -- Blessed */
+ p_ptr->tim_invis = 0; /* Timed -- Invisibility */
+ p_ptr->tim_infra = 0; /* Timed -- Infra Vision */
+
+ p_ptr->oppose_acid = 0; /* Timed -- oppose acid */
+ p_ptr->oppose_elec = 0; /* Timed -- oppose lightning */
+ p_ptr->oppose_fire = 0; /* Timed -- oppose heat */
+ p_ptr->oppose_cold = 0; /* Timed -- oppose cold */
+ p_ptr->oppose_pois = 0; /* Timed -- oppose poison */
+
+ p_ptr->confusing = 0; /* Touch of Confusion */
+}
+
+
+/*
+ * arena commands
+ */
+static void arena_comm(int cmd)
+{
+ char tmp_str[80];
+
+ monster_race *r_ptr;
+
+ cptr name;
+
+
+ switch (cmd)
+ {
+ case BACT_ARENA:
+ {
+ if (p_ptr->arena_number == MAX_ARENA_MONS)
+ {
+ clear_bldg(5, 19);
+ prt(" Arena Victor!", 5, 0);
+ prt("Congratulations! You have defeated all before you.", 7, 0);
+ prt("For that, receive the prize: 10,000 gold pieces", 8, 0);
+ prt("", 10, 0);
+ prt("", 11, 0);
+ p_ptr->au += 10000;
+ msg_print("Press the space bar to continue");
+ msg_print(NULL);
+ p_ptr->arena_number++;
+ }
+ else if (p_ptr->arena_number > MAX_ARENA_MONS)
+ {
+ msg_print("You enter the arena briefly and bask in your glory.");
+ msg_print(NULL);
+ }
+ else
+ {
+ p_ptr->inside_arena = TRUE;
+ p_ptr->exit_bldg = FALSE;
+ reset_tim_flags();
+ p_ptr->leaving = TRUE;
+ p_ptr->oldpx = p_ptr->px;
+ p_ptr->oldpy = p_ptr->py;
+ leave_bldg = TRUE;
+ }
+
+ break;
+ }
+
+ case BACT_POSTER:
+ {
+ if (p_ptr->arena_number == MAX_ARENA_MONS)
+ msg_print("You are victorious. Enter the arena for the ceremony.");
+ else if (p_ptr->arena_number > MAX_ARENA_MONS)
+ msg_print("You have won against all foes.");
+ else
+ {
+ r_ptr = &r_info[arena_monsters[p_ptr->arena_number]];
+ name = (r_name + r_ptr->name);
+ strnfmt(tmp_str, 80, "Do I hear any challenges against: %s", name);
+ msg_print(tmp_str);
+ msg_print(NULL);
+ }
+
+ break;
+ }
+
+ case BACT_ARENA_RULES:
+ {
+ /* Save screen */
+ screen_save();
+
+ /* Peruse the arena help file */
+ (void)show_file("arena.txt", NULL, 0, 0);
+
+ /* Load screen */
+ screen_load();
+
+ break;
+ }
+ }
+}
+
+
+/*
+ * display fruit for dice slots
+ */
+static void display_fruit(int row, int col, int fruit)
+{
+ switch (fruit)
+ {
+ case 0: /* lemon */
+ {
+ c_put_str(TERM_YELLOW, " ####.", row, col);
+ c_put_str(TERM_YELLOW, " # #", row + 1, col);
+ c_put_str(TERM_YELLOW, " # #", row + 2, col);
+ c_put_str(TERM_YELLOW, "# #", row + 3, col);
+ c_put_str(TERM_YELLOW, "# #", row + 4, col);
+ c_put_str(TERM_YELLOW, "# # ", row + 5, col);
+ c_put_str(TERM_YELLOW, "# # ", row + 6, col);
+ c_put_str(TERM_YELLOW, ".#### ", row + 7, col);
+ prt(" Lemon ", row + 8, col);
+
+ break;
+ }
+
+ case 1: /* orange */
+ {
+ c_put_str(TERM_ORANGE, " ## ", row, col);
+ c_put_str(TERM_ORANGE, " #..# ", row + 1, col);
+ c_put_str(TERM_ORANGE, " #....# ", row + 2, col);
+ c_put_str(TERM_ORANGE, "#......#", row + 3, col);
+ c_put_str(TERM_ORANGE, "#......#", row + 4, col);
+ c_put_str(TERM_ORANGE, " #....# ", row + 5, col);
+ c_put_str(TERM_ORANGE, " #..# ", row + 6, col);
+ c_put_str(TERM_ORANGE, " ## ", row + 7, col);
+ prt(" Orange ", row + 8, col);
+
+ break;
+ }
+
+ case 2: /* sword */
+ {
+ c_put_str(TERM_SLATE, " /\\ ", row, col);
+ c_put_str(TERM_SLATE, " ## ", row + 1, col);
+ c_put_str(TERM_SLATE, " ## ", row + 2, col);
+ c_put_str(TERM_SLATE, " ## ", row + 3, col);
+ c_put_str(TERM_SLATE, " ## ", row + 4, col);
+ c_put_str(TERM_SLATE, " ## ", row + 5, col);
+ c_put_str(TERM_UMBER, " ###### ", row + 6, col);
+ c_put_str(TERM_UMBER, " ## ", row + 7, col);
+ prt(" Sword ", row + 8, col);
+
+ break;
+ }
+
+ case 3: /* shield */
+ {
+ c_put_str(TERM_SLATE, " ###### ", row, col);
+ c_put_str(TERM_SLATE, "# #", row + 1, col);
+ c_put_str(TERM_SLATE, "# ++++ #", row + 2, col);
+ c_put_str(TERM_SLATE, "# +==+ #", row + 3, col);
+ c_put_str(TERM_SLATE, "# ++ #", row + 4, col);
+ c_put_str(TERM_SLATE, " # # ", row + 5, col);
+ c_put_str(TERM_SLATE, " # # ", row + 6, col);
+ c_put_str(TERM_SLATE, " ## ", row + 7, col);
+ prt(" Shield ", row + 8, col);
+
+ break;
+ }
+
+ case 4: /* plum */
+ {
+ c_put_str(TERM_VIOLET, " ## ", row, col);
+ c_put_str(TERM_VIOLET, " ###### ", row + 1, col);
+ c_put_str(TERM_VIOLET, "########", row + 2, col);
+ c_put_str(TERM_VIOLET, "########", row + 3, col);
+ c_put_str(TERM_VIOLET, "########", row + 4, col);
+ c_put_str(TERM_VIOLET, " ###### ", row + 5, col);
+ c_put_str(TERM_VIOLET, " #### ", row + 6, col);
+ c_put_str(TERM_VIOLET, " ## ", row + 7, col);
+ prt(" Plum ", row + 8, col);
+
+ break;
+ }
+
+ case 5: /* cherry */
+ {
+ c_put_str(TERM_RED, " ##", row, col);
+ c_put_str(TERM_RED, " ### ", row + 1, col);
+ c_put_str(TERM_RED, " #..# ", row + 2, col);
+ c_put_str(TERM_RED, " #..# ", row + 3, col);
+ c_put_str(TERM_RED, " ###### ", row + 4, col);
+ c_put_str(TERM_RED, "#..##..#", row + 5, col);
+ c_put_str(TERM_RED, "#..##..#", row + 6, col);
+ c_put_str(TERM_RED, " ## ## ", row + 7, col);
+ prt(" Cherry ", row + 8, col);
+
+ break;
+ }
+ }
+}
+
+
+/*
+ * gamble_comm
+ */
+static bool_ gamble_comm(int cmd)
+{
+ int roll1, roll2, roll3, choice, odds, win;
+
+ s32b wager;
+
+ s32b maxbet;
+
+ s32b oldgold;
+
+ static const char *fruit[6] =
+ {"Lemon", "Orange", "Sword", "Shield", "Plum", "Cherry"
+ };
+
+ char out_val[160], tmp_str[80], again;
+
+ cptr p;
+
+
+ screen_save();
+
+ if (cmd == BACT_GAMBLE_RULES)
+ {
+ /* Peruse the gambling help file */
+ (void)show_file("gambling.txt", NULL, 0, 0);
+ }
+ else
+ {
+ clear_bldg(5, 23);
+
+ /* Set maximum bet */
+ if (p_ptr->lev < 10)
+ maxbet = (p_ptr->lev * 100);
+ else
+ maxbet = (p_ptr->lev * 1000);
+
+ /* Get the wager */
+ strcpy(out_val, "");
+ strnfmt(tmp_str, 80, "Your wager (1-%ld) ? ", maxbet);
+ get_string(tmp_str, out_val, 32);
+
+ /* Strip spaces */
+ for (p = out_val; *p == ' '; p++);
+
+ wager = atol(p);
+
+ if (wager > p_ptr->au)
+ {
+ msg_print("Hey! You don't have the gold - get out of here!");
+ msg_print(NULL);
+ screen_load();
+ return (FALSE);
+ }
+ else if (wager > maxbet)
+ {
+ msg_format("I'll take $%ld of that. Keep the rest.", maxbet);
+ wager = maxbet;
+ }
+ else if (wager < 1)
+ {
+ msg_print("Ok, we'll start with $1.");
+
+ wager = 1;
+ }
+ msg_print(NULL);
+ win = FALSE;
+ odds = 0;
+ oldgold = p_ptr->au;
+
+ strnfmt(tmp_str, 80, "Gold before game: %9ld", oldgold);
+ prt(tmp_str, 20, 2);
+
+ strnfmt(tmp_str, 80, "Current Wager: %9ld", wager);
+ prt(tmp_str, 21, 2);
+
+ do
+ {
+ switch (cmd)
+ {
+ case BACT_IN_BETWEEN: /* Game of In-Between */
+ {
+ c_put_str(TERM_GREEN, "In Between", 5, 2);
+ odds = 3;
+ win = FALSE;
+ roll1 = randint(10);
+ roll2 = randint(10);
+ choice = randint(10);
+ strnfmt(tmp_str, 80, "Black die: %d Black Die: %d",
+ roll1, roll2);
+ prt(tmp_str, 8, 3);
+ strnfmt(tmp_str, 80, "Red die: %d", choice);
+ prt(tmp_str, 11, 14);
+ if (((choice > roll1) && (choice < roll2)) ||
+ ((choice < roll1) && (choice > roll2)))
+ win = TRUE;
+
+ break;
+ }
+ case BACT_CRAPS: /* Game of Craps */
+ {
+ c_put_str(TERM_GREEN, "Craps", 5, 2);
+ win = 3;
+ odds = 1;
+ roll1 = randint(6);
+ roll2 = randint(6);
+ roll3 = roll1 + roll2;
+ choice = roll3;
+ strnfmt(tmp_str, 80, "First roll: %d %d Total: %d", roll1,
+ roll2, roll3);
+ prt(tmp_str, 7, 5);
+ if ((roll3 == 7) || (roll3 == 11))
+ win = TRUE;
+ else if ((roll3 == 2) || (roll3 == 3) || (roll3 == 12))
+ win = FALSE;
+ else
+ {
+ do
+ {
+ msg_print("Hit any key to roll again");
+ msg_print(NULL);
+ roll1 = randint(6);
+ roll2 = randint(6);
+ roll3 = roll1 + roll2;
+
+ strnfmt(tmp_str, 80, "Roll result: %d %d Total: %d",
+ roll1, roll2, roll3);
+ prt(tmp_str, 8, 5);
+ if (roll3 == choice)
+ win = TRUE;
+ else if (roll3 == 7)
+ win = FALSE;
+ }
+ while ((win != TRUE) && (win != FALSE));
+ }
+
+ break;
+ }
+
+ case BACT_SPIN_WHEEL: /* Spin the Wheel Game */
+ {
+ win = FALSE;
+ odds = 10;
+ c_put_str(TERM_GREEN, "Wheel", 5, 2);
+ prt("0 1 2 3 4 5 6 7 8 9", 7, 5);
+ prt("--------------------------------", 8, 3);
+ strcpy(out_val, "");
+ get_string ("Pick a number (1-9): ", out_val, 32);
+ for (p = out_val; *p == ' '; p++);
+ choice = atol(p);
+ if (choice < 0)
+ {
+ msg_print("I'll put you down for 0.");
+ choice = 0;
+ }
+ else if (choice > 9)
+ {
+ msg_print("Ok, I'll put you down for 9.");
+ choice = 9;
+ }
+ msg_print(NULL);
+ roll1 = randint(10) - 1;
+ strnfmt(tmp_str, 80, "The wheel spins to a stop and the winner is %d",
+ roll1);
+ prt(tmp_str, 13, 3);
+ prt("", 9, 0);
+ prt("*", 9, (3 * roll1 + 5));
+ if (roll1 == choice)
+ win = TRUE;
+
+ break;
+ }
+
+ case BACT_DICE_SLOTS: /* The Dice Slots */
+ {
+ c_put_str(TERM_GREEN, "Dice Slots", 5, 2);
+ win = FALSE;
+ roll1 = randint(6);
+ roll2 = randint(6);
+ choice = randint(6);
+ strnfmt(tmp_str, 80, "%s %s %s",
+ fruit[roll1 - 1], fruit[roll2 - 1],
+ fruit[choice - 1]);
+ prt(tmp_str, 15, 37);
+ prt("/--------------------------\\", 7, 2);
+ prt("\\--------------------------/", 17, 2);
+ display_fruit(8, 3, roll1 - 1);
+ display_fruit(8, 12, roll2 - 1);
+ display_fruit(8, 21, choice - 1);
+ if ((roll1 == roll2) && (roll2 == choice))
+ {
+ win = TRUE;
+ if (roll1 == 1)
+ odds = 4;
+ else if (roll1 == 2)
+ odds = 6;
+ else
+ odds = roll1 * roll1;
+ }
+ else if ((roll1 == 6) && (roll2 == 6))
+ {
+ win = TRUE;
+ odds = choice + 1;
+ }
+
+ break;
+ }
+ }
+
+ if (win)
+ {
+ prt("YOU WON", 16, 37);
+ p_ptr->au = p_ptr->au + (odds * wager);
+ strnfmt(tmp_str, 80, "Payoff: %d", odds);
+ prt(tmp_str, 17, 37);
+ }
+ else
+ {
+ prt("You Lost", 16, 37);
+ p_ptr->au = p_ptr->au - wager;
+ prt("", 17, 37);
+ }
+ strnfmt(tmp_str, 80, "Current Gold: %9ld", p_ptr->au);
+ prt(tmp_str, 22, 2);
+ prt("Again(Y/N)?", 18, 37);
+ move_cursor(18, 49);
+ again = inkey();
+ if (wager > p_ptr->au)
+ {
+ msg_print("Hey! You don't have the gold - get out of here!");
+ msg_print(NULL);
+ screen_load();
+ return (FALSE);
+ /* strnfmt(tmp_str, 80, "Current Wager: %9ld",wager);
+ prt(tmp_str, 17, 2); */
+ }
+ }
+ while ((again == 'y') || (again == 'Y'));
+
+ prt("", 18, 37);
+ if (p_ptr->au >= oldgold)
+ msg_print("You came out a winner! We'll win next time, I'm sure.");
+ else
+ msg_print("You lost gold! Haha, better head home.");
+ msg_print(NULL);
+ }
+
+ screen_load();
+
+ return (TRUE);
+}
+
+
+/*
+ * inn commands
+ * Note that resting for the night was a perfect way to avoid player
+ * ghosts in the town *if* you could only make it to the inn in time (-:
+ * Now that the ghosts are temporarily disabled in 2.8.X, this function
+ * will not be that useful. I will keep it in the hopes the player
+ * ghost code does become a reality again. Does help to avoid filthy urchins.
+ * Resting at night is also a quick way to restock stores -KMW-
+ */
+static bool_ inn_comm(int cmd)
+{
+ bool_ vampire;
+
+
+ /* Extract race info */
+ vampire = ((PRACE_FLAG(PR1_VAMPIRE)) || (p_ptr->mimic_form == resolve_mimic_name("Vampire")));
+
+ switch (cmd)
+ {
+ case BACT_FOOD: /* Buy food & drink */
+ {
+ if (!vampire)
+ {
+ msg_print("The barkeep gives you some gruel and a beer.");
+ msg_print(NULL);
+ (void) set_food(PY_FOOD_MAX - 1);
+ }
+ else
+ msg_print("You're a vampire and I don't have any food for you!");
+
+ break;
+ }
+
+ /*
+ * I revamped this... Don't know why normal races didn't get
+ * mana regenerated. It is the grand tradition of p&p games -- pelpel
+ */
+ case BACT_REST: /* Rest for the night */
+ {
+ bool_ nighttime;
+
+ /* Extract the current time */
+ nighttime = ((bst(HOUR, turn) < 6) || (bst(HOUR, turn) >= 18));
+
+ /* Normal races rest at night */
+ if (!vampire && !nighttime)
+ {
+ msg_print("The rooms are available only at night.");
+ msg_print(NULL);
+ return (FALSE);
+ }
+
+ /* Vampires rest during daytime */
+ if (vampire && nighttime)
+ {
+ msg_print("The rooms are available only during daylight for your kind.");
+ msg_print(NULL);
+ return (FALSE);
+ }
+
+ /* Must cure HP draining status first */
+ if ((p_ptr->poisoned > 0) || (p_ptr->cut > 0))
+ {
+ msg_print("You need a healer, not a room.");
+ msg_print(NULL);
+ msg_print("Sorry, but I don't want anyone dying in here.");
+ return (FALSE);
+ }
+
+ /* Let the time pass XXX XXX XXX */
+ if (vampire)
+ {
+ /* Wait for sunset */
+ while ((bst(HOUR, turn) >= 6) && (bst(HOUR, turn) < 18))
+ {
+ turn += (10L * MINUTE);
+ }
+ }
+ else
+ {
+ /* Wait for sunrise */
+ while ((bst(HOUR, turn) < 6) || (bst(HOUR, turn) >= 18))
+ {
+ turn += (10L * MINUTE);
+ }
+ }
+
+ /* Regen */
+ p_ptr->chp = p_ptr->mhp;
+ p_ptr->csp = p_ptr->msp;
+
+ /* Restore status */
+ set_blind(0);
+ set_confused(0);
+ p_ptr->stun = 0;
+
+ /* Message */
+ if (vampire) msg_print("You awake refreshed for the new night.");
+ else msg_print("You awake refreshed for the new day.");
+
+ /* Dungeon stuff */
+ p_ptr->leaving = TRUE;
+ p_ptr->oldpx = p_ptr->px;
+ p_ptr->oldpy = p_ptr->py;
+
+ /* Select new bounties. */
+ select_bounties();
+
+ break;
+ }
+
+ case BACT_RUMORS: /* Listen for rumors */
+ {
+ char rumor[80];
+
+ get_rnd_line("rumors.txt", rumor);
+ msg_format("%s", rumor);
+ msg_print(NULL);
+
+ break;
+ }
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * Display quest information
+ */
+static void get_questinfo(int questnum)
+{
+ int i;
+
+
+ /* Print the quest info */
+ prt(format("Quest Information (Danger level: %d)", quest[questnum].level), 5, 0);
+
+ prt(quest[questnum].name, 7, 0);
+
+ i = 0;
+ while ((i < 10) && (quest[questnum].desc[i][0] != '\0'))
+ {
+ c_put_str(TERM_YELLOW, quest[questnum].desc[i], i + 8, 0);
+ i++;
+ }
+}
+
+
+/*
+ * Request a quest from the Lord.
+ */
+static bool_ castle_quest(int y, int x)
+{
+ int plot = 0;
+
+ quest_type *q_ptr;
+
+
+ clear_bldg(7, 18);
+
+ /* Current plot of the building */
+ plot = cave[y][x].special;
+
+ /* Is there a quest available at the building? */
+ if ((!plot) || (plots[plot] == QUEST_NULL))
+ {
+ put_str("I don't have a quest for you at the moment.", 8, 0);
+ return FALSE;
+ }
+
+ q_ptr = &quest[plots[plot]];
+
+ /* Quest is completed */
+ if (q_ptr->status == QUEST_STATUS_COMPLETED)
+ {
+ /* Rewarded quest */
+ q_ptr->status = QUEST_STATUS_FINISHED;
+
+ process_hooks(HOOK_QUEST_FINISH, "(d)", plots[plot]);
+
+ return (TRUE);
+ }
+
+ /* Quest is still unfinished */
+ else if (q_ptr->status == QUEST_STATUS_TAKEN)
+ {
+ put_str("You have not completed your current quest yet!", 8, 0);
+ put_str("Use CTRL-Q to check the status of your quest.", 9, 0);
+ put_str("Return when you have completed your quest.", 12, 0);
+
+ return (FALSE);
+ }
+ /* Failed quest */
+ else if (q_ptr->status == QUEST_STATUS_FAILED)
+ {
+ /* Mark quest as done (but failed) */
+ q_ptr->status = QUEST_STATUS_FAILED_DONE;
+
+ process_hooks(HOOK_QUEST_FAIL, "(d)", plots[plot]);
+
+ return (FALSE);
+ }
+ /* No quest yet */
+ else if (q_ptr->status == QUEST_STATUS_UNTAKEN)
+ {
+ if (process_hooks(HOOK_INIT_QUEST, "(d)", plots[plot])) return (FALSE);
+
+ q_ptr->status = QUEST_STATUS_TAKEN;
+
+ /* Assign a new quest */
+ get_questinfo(plots[plot]);
+
+ /* Add the hooks */
+ if (quest[plots[plot]].type == HOOK_TYPE_C) quest[plots[plot]].init(plots[plot]);
+
+ return (TRUE);
+ }
+
+ return FALSE;
+}
+
+/*
+ * Displaying town history -KMW-
+ */
+static void town_history(void)
+{
+ /* Save screen */
+ screen_save();
+
+ /* Peruse the building help file */
+ (void)show_file("bldg.txt", NULL, 0, 0);
+
+ /* Load screen */
+ screen_load();
+}
+
+
+/*
+ * compare_weapon_aux2 -KMW-
+ */
+static void compare_weapon_aux2(object_type *o_ptr, int numblows, int r, int c, int mult, char attr[80], u32b f1, u32b f2, u32b f3, byte color)
+{
+ char tmp_str[80];
+
+ c_put_str(color, attr, r, c);
+ strnfmt(tmp_str, 80, "Attack: %d-%d damage",
+ numblows * ((o_ptr->dd * mult) + o_ptr->to_d),
+ numblows * ((o_ptr->ds * o_ptr->dd * mult) + o_ptr->to_d));
+ put_str(tmp_str, r, c + 8);
+ r++;
+}
+
+
+/*
+ * compare_weapon_aux1 -KMW-
+ */
+static void compare_weapon_aux1(object_type *o_ptr, int col, int r)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+
+ if (f1 & (TR1_SLAY_ANIMAL))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 2, "Animals:",
+ f1, f2, f3, TERM_YELLOW);
+ }
+ if (f1 & (TR1_SLAY_EVIL))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 2, "Evil:",
+ f1, f2, f3, TERM_YELLOW);
+ }
+ if (f1 & (TR1_SLAY_UNDEAD))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Undead:",
+ f1, f2, f3, TERM_YELLOW);
+ }
+ if (f1 & (TR1_SLAY_DEMON))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Demons:",
+ f1, f2, f3, TERM_YELLOW);
+ }
+ if (f1 & (TR1_SLAY_ORC))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Orcs:",
+ f1, f2, f3, TERM_YELLOW);
+ }
+ if (f1 & (TR1_SLAY_TROLL))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Trolls:",
+ f1, f2, f3, TERM_YELLOW);
+ }
+ if (f1 & (TR1_SLAY_GIANT))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Giants:",
+ f1, f2, f3, TERM_YELLOW);
+ }
+ if (f1 & (TR1_SLAY_DRAGON))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Dragons:",
+ f1, f2, f3, TERM_YELLOW);
+ }
+ if (f1 & (TR1_KILL_DRAGON))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 5, "Dragons:",
+ f1, f2, f3, TERM_YELLOW);
+ }
+ if (f1 & (TR1_BRAND_ACID))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Acid:",
+ f1, f2, f3, TERM_RED);
+ }
+ if (f1 & (TR1_BRAND_ELEC))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Elec:",
+ f1, f2, f3, TERM_RED);
+ }
+ if (f1 & (TR1_BRAND_FIRE))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Fire:",
+ f1, f2, f3, TERM_RED);
+ }
+ if (f1 & (TR1_BRAND_COLD))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Cold:",
+ f1, f2, f3, TERM_RED);
+ }
+ if (f1 & (TR1_BRAND_POIS))
+ {
+ compare_weapon_aux2(o_ptr, p_ptr->num_blow, r++, col, 3, "Poison:",
+ f1, f2, f3, TERM_RED);
+ }
+}
+
+
+/*
+ * list_weapon -KMW-
+ */
+static void list_weapon(object_type *o_ptr, int row, int col)
+{
+ char o_name[80];
+
+ char tmp_str[80];
+
+
+ object_desc(o_name, o_ptr, TRUE, 0);
+ c_put_str(TERM_YELLOW, o_name, row, col);
+ strnfmt(tmp_str, 80, "To Hit: %d To Damage: %d", o_ptr->to_h, o_ptr->to_d);
+ put_str(tmp_str, row + 1, col);
+ strnfmt(tmp_str, 80, "Dice: %d Sides: %d", o_ptr->dd, o_ptr->ds);
+ put_str(tmp_str, row + 2, col);
+ strnfmt(tmp_str, 80, "Number of Blows: %d", p_ptr->num_blow);
+ put_str(tmp_str, row + 3, col);
+ c_put_str(TERM_YELLOW, "Possible Damage:", row + 5, col);
+ strnfmt(tmp_str, 80, "One Strike: %d-%d damage", o_ptr->dd + o_ptr->to_d,
+ (o_ptr->ds*o_ptr->dd) + o_ptr->to_d);
+ put_str(tmp_str, row + 6, col + 1);
+ strnfmt(tmp_str, 80, "One Attack: %d-%d damage", p_ptr->num_blow*(o_ptr->dd + o_ptr->to_d),
+ p_ptr->num_blow*(o_ptr->ds*o_ptr->dd + o_ptr->to_d));
+ put_str(tmp_str, row + 7, col + 1);
+}
+
+
+/*
+ * Select melee weapons
+ */
+static bool_ item_tester_hook_melee_weapon(object_type *o_ptr)
+{
+ return (wield_slot(o_ptr) == INVEN_WIELD);
+}
+
+/*
+ * compare_weapons -KMW-
+ */
+static bool_ compare_weapons(void)
+{
+ int item, item2, i;
+
+ object_type *o1_ptr, *o2_ptr, *orig_ptr;
+
+ object_type *i_ptr;
+
+ cptr q, s;
+
+
+ clear_bldg(6, 18);
+
+ o1_ptr = NULL;
+ o2_ptr = NULL;
+ i_ptr = NULL;
+
+ /* Store copy of original wielded weapon in pack slot */
+ i_ptr = &p_ptr->inventory[INVEN_WIELD];
+ orig_ptr = &p_ptr->inventory[INVEN_PACK];
+ object_copy(orig_ptr, i_ptr);
+
+ i = 6;
+ /* Get first weapon */
+ /* Restrict choices to meele weapons */
+ item_tester_hook = item_tester_hook_melee_weapon;
+
+ q = "What is your first melee weapon? ";
+ s = "You have nothing to compare.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN)))
+ {
+ object_wipe(orig_ptr);
+ return (FALSE);
+ }
+
+ /* Get the item (in the pack) */
+ if (item >= 0)
+ o1_ptr = &p_ptr->inventory[item];
+
+ /* Get second weapon */
+ /* Restrict choices to melee weapons */
+ item_tester_hook = item_tester_hook_melee_weapon;
+
+ q = "What is your second melee weapon? ";
+ s = "You have nothing to compare.";
+ if (!get_item(&item2, q, s, (USE_EQUIP | USE_INVEN)))
+ {
+ object_wipe(orig_ptr);
+ return (FALSE);
+ }
+
+ /* Get the item (in the pack) */
+ if (item2 >= 0) o2_ptr = &p_ptr->inventory[item2];
+
+ put_str("Based on your current abilities, here is what your weapons will do", 4, 2);
+
+ i_ptr = &p_ptr->inventory[INVEN_WIELD];
+ object_copy(i_ptr, o1_ptr);
+ calc_bonuses(TRUE);
+
+ list_weapon(o1_ptr, i, 2);
+ compare_weapon_aux1(o1_ptr, 2, i + 8);
+
+ i_ptr = &p_ptr->inventory[INVEN_WIELD];
+ if (item2 == INVEN_WIELD)
+ object_copy(i_ptr, orig_ptr);
+ else
+ object_copy(i_ptr, o2_ptr);
+ calc_bonuses(TRUE);
+
+ list_weapon(o2_ptr, i, 40);
+ compare_weapon_aux1(o2_ptr, 40, i + 8);
+
+ i_ptr = &p_ptr->inventory[INVEN_WIELD];
+ object_copy(i_ptr, orig_ptr);
+ calc_bonuses(TRUE);
+
+ object_wipe(orig_ptr);
+
+ put_str("(Only highest damage applies per monster. Special damage not cumulative)", 20, 0);
+
+ return (TRUE);
+}
+
+
+/*
+ * general all-purpose fixing routine for items from building personnel
+ * sharpen arrows, repair armor, repair weapon
+ * -KMW-
+ */
+static bool_ fix_item(int istart, int iend, int ispecific, bool_ iac,
+ int ireward, bool_ set_reward)
+{
+ int i;
+
+ int j = 9;
+
+ int maxenchant = (p_ptr->lev / 5);
+
+ object_type *o_ptr;
+
+ char out_val[80], tmp_str[80];
+
+ bool_ repaired = FALSE;
+
+ clear_bldg(5, 18);
+ strnfmt(tmp_str, 80, " Based on your skill, we can improve up to +%d", maxenchant);
+ prt(tmp_str, 5, 0);
+ prt("Status", 7, 30);
+
+ for (i = istart; i <= iend; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+ if (ispecific > 0)
+ {
+ if (o_ptr->tval != ispecific)
+ continue;
+ }
+
+ if (o_ptr->tval)
+ {
+ object_desc(tmp_str, o_ptr, FALSE, 1);
+
+ if ((o_ptr->name1 && (o_ptr->ident & 0x08)))
+ strnfmt(out_val, 80, "%-40s: beyond our skills!", tmp_str);
+ else if (o_ptr->name1)
+ strnfmt(out_val, 80, "%-40s: in fine condition", tmp_str);
+ else
+ {
+ if ((iac) && (o_ptr->to_a <= -3))
+ {
+ strnfmt(out_val, 80, "%-40s: beyond repair, buy a new one", tmp_str);
+ }
+ else if ((iac) && (o_ptr->to_a < maxenchant))
+ {
+ o_ptr->to_a++;
+ strnfmt(out_val, 80, "%-40s: polished -> (%d)", tmp_str, o_ptr->to_a);
+ repaired = TRUE;
+ }
+ else if ((!iac) && ((o_ptr->to_h <= -3) || (o_ptr->to_d <= -3)))
+ {
+ strnfmt(out_val, 80, "%-40s: beyond repair, buy a new one", tmp_str);
+ }
+ /* Sharpen a weapon */
+ else if ((!iac) && ((o_ptr->to_h < maxenchant) ||
+ (o_ptr->to_d < maxenchant)))
+ {
+ if (o_ptr->to_h < maxenchant)
+ o_ptr->to_h++;
+ if (o_ptr->to_d < maxenchant)
+ o_ptr->to_d++;
+ strnfmt(out_val, 80, "%-40s: sharpened -> (%d,%d)", tmp_str,
+ o_ptr->to_h, o_ptr->to_d);
+ repaired = TRUE;
+ }
+ else
+ strnfmt(out_val, 80, "%-40s: in fine condition", tmp_str);
+ }
+ prt(out_val, j++, 0);
+ }
+ }
+
+ if (!repaired)
+ {
+ msg_print("You don't have anything appropriate.");
+ msg_print(NULL);
+ }
+ else
+ {
+ msg_print("Press the spacebar to continue");
+ msg_print(NULL);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ p_ptr->update |= (PU_BONUS);
+ }
+ clear_bldg(5, 18);
+
+ return (repaired);
+}
+
+
+/*
+ * Research Item
+ */
+static bool_ research_item(void)
+{
+ clear_bldg(5, 18);
+ return (identify_fully());
+}
+
+
+/*
+ * Show the current quest monster.
+ */
+static void show_quest_monster(void)
+{
+ monster_race* r_ptr = &r_info[bounties[0][0]];
+
+
+ msg_format("Quest monster: %s. "
+ "Need to turn in %d corpse%s to receive reward.",
+ r_name + r_ptr->name, bounties[0][1],
+ (bounties[0][1] > 1 ? "s" : ""));
+ msg_print(NULL);
+}
+
+
+/*
+ * Show the current bounties.
+ */
+static void show_bounties(void)
+{
+ int i, j = 6;
+
+ monster_race* r_ptr;
+
+ char buff[80];
+
+
+ clear_bldg(7, 18);
+
+ c_prt(TERM_YELLOW, "Currently active bounties:", 4, 2);
+
+ for (i = 1; i < MAX_BOUNTIES; i++, j++)
+ {
+ r_ptr = &r_info[bounties[i][0]];
+
+ strnfmt(buff, 80, "%-30s (%d gp)", r_name + r_ptr->name, bounties[i][1]);
+
+ prt(buff, j, 2);
+
+ if (j >= 17)
+ {
+ msg_print("Press space for more.");
+ msg_print(NULL);
+
+ clear_bldg(7, 18);
+ j = 5;
+ }
+ }
+}
+
+
+/*
+ * Filter for corpses that currently have a bounty on them.
+ */
+static bool_ item_tester_hook_bounty(object_type* o_ptr)
+{
+ int i;
+
+
+ if (o_ptr->tval == TV_CORPSE)
+ {
+ for (i = 1; i < MAX_BOUNTIES; i++)
+ {
+ if (bounties[i][0] == o_ptr->pval2) return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+/* Filter to match the quest monster's corpse. */
+static bool_ item_tester_hook_quest_monster(object_type* o_ptr)
+{
+ if ((o_ptr->tval == TV_CORPSE) &&
+ (o_ptr->pval2 == bounties[0][0])) return (TRUE);
+ return (FALSE);
+}
+
+
+/*
+ * Return the boost in the corpse's value depending on how rare the body
+ * part is.
+ */
+static int corpse_value_boost(int sval)
+{
+ switch (sval)
+ {
+ case SV_CORPSE_HEAD:
+ case SV_CORPSE_SKULL:
+ {
+ return (1);
+ }
+
+ /* Default to no boost. */
+ default:
+ {
+ return (0);
+ }
+ }
+}
+
+/*
+ * Sell a corpse, if there's currently a bounty on it.
+ */
+static void sell_corpses(void)
+{
+ object_type* o_ptr;
+
+ int i, boost = 0;
+
+ s16b value;
+
+ int item;
+
+
+ /* Set the hook. */
+ item_tester_hook = item_tester_hook_bounty;
+
+ /* Select a corpse to sell. */
+ if (!get_item(&item, "Sell which corpse",
+ "You have no corpses you can sell.", USE_INVEN)) return;
+
+ o_ptr = &p_ptr->inventory[item];
+
+ /* Exotic body parts are worth more. */
+ boost = corpse_value_boost(o_ptr->sval);
+
+ /* Try to find a match. */
+ for (i = 1; i < MAX_BOUNTIES; i++)
+ {
+ if (o_ptr->pval2 == bounties[i][0])
+ {
+ value = bounties[i][1] + boost * (r_info[o_ptr->pval2].level);
+
+ msg_format("Sold for %ld gold pieces.", value);
+ msg_print(NULL);
+ p_ptr->au += value;
+
+ /* Increase the number of collected bounties */
+ total_bounties++;
+
+ inc_stack_size(item, -1);
+
+ return;
+ }
+ }
+
+ msg_print("Sorry, but that monster does not have a bounty on it.");
+ msg_print(NULL);
+}
+
+
+
+/*
+ * Hook for bounty monster selection.
+ */
+static bool_ mon_hook_bounty(int r_idx)
+{
+ monster_race* r_ptr = &r_info[r_idx];
+
+
+ /* Reject uniques */
+ if (r_ptr->flags1 & RF1_UNIQUE) return (FALSE);
+
+ /* Reject those who cannot leave anything */
+ if (!(r_ptr->flags9 & RF9_DROP_CORPSE) &&
+ !(r_ptr->flags9 & RF9_DROP_SKELETON)) return (FALSE);
+
+ /* Reject pets */
+ if (r_ptr->flags7 & RF7_PET) return (FALSE);
+
+ /* Reject friendly creatures */
+ if (r_ptr->flags7 & RF7_FRIENDLY) return (FALSE);
+
+ /* The rest are acceptable */
+ return (TRUE);
+}
+
+
+static void select_quest_monster(void)
+{
+ monster_race* r_ptr;
+
+ int amt;
+
+
+ /*
+ * Set up the hooks -- no bounties on uniques or monsters
+ * with no corpses
+ */
+ get_mon_num_hook = mon_hook_bounty;
+ get_mon_num_prep();
+
+ /* Set up the quest monster. */
+ bounties[0][0] = get_mon_num(p_ptr->lev);
+
+ r_ptr = &r_info[bounties[0][0]];
+
+ /*
+ * Select the number of monsters needed to kill. Groups and
+ * breeders require more
+ */
+ amt = randnor(5, 3);
+
+ if (amt < 2) amt = 2;
+
+ if (r_ptr->flags1 & RF1_FRIEND) amt *= 3; amt /= 2;
+ if (r_ptr->flags1 & RF1_FRIENDS) amt *= 2;
+ if (r_ptr->flags4 & RF4_MULTIPLY) amt *= 3;
+
+ if (r_ptr->flags7 & RF7_AQUATIC) amt /= 2;
+
+ bounties[0][1] = amt;
+
+ /* Undo the filters */
+ get_mon_num_hook = NULL;
+ get_mon_num_prep();
+}
+
+
+
+/*
+ * Sell a corpse for a reward.
+ */
+static void sell_quest_monster(void)
+{
+ object_type* o_ptr;
+
+ int item;
+
+
+ /* Set the hook. */
+ item_tester_hook = item_tester_hook_quest_monster;
+
+ /* Select a corpse to sell. */
+ if (!get_item(&item, "Sell which corpse",
+ "You have no corpses you can sell.", USE_INVEN)) return;
+
+ o_ptr = &p_ptr->inventory[item];
+
+ bounties[0][1] -= o_ptr->number;
+
+ /* Completed the quest. */
+ if (bounties[0][1] <= 0)
+ {
+ int m;
+ monster_race *r_ptr;
+
+ cmsg_print(TERM_YELLOW, "You have completed your quest!");
+ msg_print(NULL);
+
+ /* Give full knowledge */
+
+ /* Hack -- Maximal info */
+ r_ptr = &r_info[bounties[0][0]];
+
+ msg_print(format("Well done! As a reward I'll teach you everything "
+ "about the %s, (check your recall)",
+ r_name + r_ptr->name));
+
+ r_ptr->r_wake = r_ptr->r_ignore = MAX_UCHAR;
+
+ /* Observe "maximal" attacks */
+ for (m = 0; m < 4; m++)
+ {
+ /* Examine "actual" blows */
+ if (r_ptr->blow[m].effect || r_ptr->blow[m].method)
+ {
+ /* Hack -- maximal observations */
+ r_ptr->r_blows[m] = MAX_UCHAR;
+ }
+ }
+
+ /* Hack -- maximal drops */
+ r_ptr->r_drop_gold = r_ptr->r_drop_item =
+ (((r_ptr->flags1 & (RF1_DROP_4D2)) ? 8 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_3D2)) ? 6 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_2D2)) ? 4 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_1D2)) ? 2 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_90)) ? 1 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_60)) ? 1 : 0));
+
+ /* Hack -- but only "valid" drops */
+ if (r_ptr->flags1 & (RF1_ONLY_GOLD)) r_ptr->r_drop_item = 0;
+ if (r_ptr->flags1 & (RF1_ONLY_ITEM)) r_ptr->r_drop_gold = 0;
+
+ /* Hack -- observe many spells */
+ r_ptr->r_cast_inate = MAX_UCHAR;
+ r_ptr->r_cast_spell = MAX_UCHAR;
+
+ /* Hack -- know all the flags */
+ r_ptr->r_flags1 = r_ptr->flags1;
+ r_ptr->r_flags2 = r_ptr->flags2;
+ r_ptr->r_flags3 = r_ptr->flags3;
+ r_ptr->r_flags4 = r_ptr->flags4;
+ r_ptr->r_flags5 = r_ptr->flags5;
+ r_ptr->r_flags6 = r_ptr->flags6;
+ r_ptr->r_flags4 = r_ptr->flags7;
+ r_ptr->r_flags5 = r_ptr->flags8;
+ r_ptr->r_flags6 = r_ptr->flags9;
+
+ msg_print(NULL);
+
+ select_quest_monster();
+
+ }
+ else
+ {
+ msg_format("Well done, only %d more to go.", bounties[0][1]);
+ msg_print(NULL);
+ }
+
+ inc_stack_size(item, -1);
+}
+
+
+
+/*
+ * Fill the bounty list with monsters.
+ */
+void select_bounties(void)
+{
+ int i, j;
+
+
+ select_quest_monster();
+
+ /*
+ * Set up the hooks -- no bounties on uniques or monsters
+ * with no corpses
+ */
+ get_mon_num_hook = mon_hook_bounty;
+ get_mon_num_prep();
+
+ for (i = 1; i < MAX_BOUNTIES; i++)
+ {
+ int lev = i * 5 + randnor(0, 2);
+ monster_race* r_ptr;
+ s16b r_idx;
+ s16b val;
+
+ if (lev < 1) lev = 1;
+
+ if (lev >= MAX_DEPTH) lev = MAX_DEPTH - 1;
+
+ /* We don't want to duplicate entries in the list */
+ while (TRUE)
+ {
+ r_idx = get_mon_num(lev);
+
+ for (j = 0; j < i; j++)
+ {
+ if (bounties[j][0] == r_idx) continue;
+ }
+
+ break;
+ }
+
+ bounties[i][0] = r_idx;
+
+ r_ptr = &r_info[r_idx];
+
+ val = r_ptr->mexp + r_ptr->level * 20 + randnor(0, r_ptr->level * 2);
+
+ if (val < 1) val = 1;
+
+ bounties[i][1] = val;
+ }
+
+ /* Undo the filters. */
+ get_mon_num_hook = NULL;
+ get_mon_num_prep();
+}
+
+/*
+ * Execute a building command
+ */
+bool_ bldg_process_command(store_type *s_ptr, int i)
+{
+ store_action_type *ba_ptr = &ba_info[st_info[s_ptr->st_idx].actions[i]];
+
+ int bact = ba_ptr->action;
+
+ int bcost;
+
+ bool_ paid = FALSE;
+
+ bool_ set_reward = FALSE;
+
+ bool_ recreate = FALSE;
+
+
+ if (is_state(s_ptr, STORE_LIKED))
+ {
+ bcost = ba_ptr->costs[STORE_LIKED];
+ }
+ else if (is_state(s_ptr, STORE_HATED))
+ {
+ bcost = ba_ptr->costs[STORE_HATED];
+ }
+ else
+ {
+ bcost = ba_ptr->costs[STORE_NORMAL];
+ }
+
+ /* action restrictions */
+ if (((ba_ptr->action_restr == 1) && (is_state(s_ptr, STORE_LIKED))) ||
+ ((ba_ptr->action_restr == 2) && (!is_state(s_ptr, STORE_LIKED))))
+ {
+ msg_print("You have no right to choose that!");
+ msg_print(NULL);
+ return FALSE;
+ }
+
+ /* If player has loan and the time is out, few things work in stores */
+ if (p_ptr->loan && !p_ptr->loan_time)
+ {
+ if ((bact != BACT_SELL) && (bact != BACT_VIEW_BOUNTIES) &&
+ (bact != BACT_SELL_CORPSES) &&
+ (bact != BACT_VIEW_QUEST_MON) &&
+ (bact != BACT_SELL_QUEST_MON) &&
+ (bact != BACT_EXAMINE) && (bact != BACT_STEAL) &&
+ (bact != BACT_PAY_BACK_LOAN))
+ {
+ msg_print("You are not allowed to do that until you have paid back your loan.");
+ msg_print(NULL);
+ return FALSE;
+ }
+ }
+
+ /* check gold */
+ if (bcost > p_ptr->au)
+ {
+ msg_print("You do not have the gold!");
+ msg_print(NULL);
+ return FALSE;
+ }
+
+ if (!bcost) set_reward = TRUE;
+
+ switch (bact)
+ {
+ case BACT_RESEARCH_ITEM:
+ {
+ paid = research_item();
+ break;
+ }
+
+ case BACT_TOWN_HISTORY:
+ {
+ town_history();
+ break;
+ }
+
+ case BACT_RACE_LEGENDS:
+ {
+ race_legends();
+ break;
+ }
+
+ case BACT_QUEST1:
+ case BACT_QUEST2:
+ case BACT_QUEST3:
+ case BACT_QUEST4:
+ {
+ int y = 1, x = 1;
+ bool_ ok = FALSE;
+
+ while ((x < cur_wid - 1) && !ok)
+ {
+ y = 1;
+ while ((y < cur_hgt - 1) && !ok)
+ {
+ /* Found the location of the quest info ? */
+ if (bact - BACT_QUEST1 + FEAT_QUEST1 == cave[y][x].feat)
+ {
+ /* Stop the loop */
+ ok = TRUE;
+ }
+ y++;
+ }
+ x++;
+ }
+
+ if (ok)
+ {
+ recreate = castle_quest(y - 1, x - 1);
+ ;
+ }
+ else
+ {
+ msg_format("ERROR: no quest info feature found: %d", bact - BACT_QUEST1 + FEAT_QUEST1);
+ }
+ break;
+ }
+
+ case BACT_KING_LEGENDS:
+ case BACT_ARENA_LEGENDS:
+ case BACT_LEGENDS:
+ {
+ show_highclass(building_loc);
+ break;
+ }
+
+ case BACT_POSTER:
+ case BACT_ARENA_RULES:
+ case BACT_ARENA:
+ {
+ arena_comm(bact);
+ break;
+ }
+
+ case BACT_IN_BETWEEN:
+ case BACT_CRAPS:
+ case BACT_SPIN_WHEEL:
+ case BACT_DICE_SLOTS:
+ case BACT_GAMBLE_RULES:
+ {
+ gamble_comm(bact);
+ break;
+ }
+
+ case BACT_REST:
+ case BACT_RUMORS:
+ case BACT_FOOD:
+ {
+ paid = inn_comm(bact);
+ break;
+ }
+
+ case BACT_RESEARCH_MONSTER:
+ {
+ paid = !research_mon();
+ break;
+ }
+
+ case BACT_COMPARE_WEAPONS:
+ {
+ paid = compare_weapons();
+ break;
+ }
+
+ case BACT_ENCHANT_WEAPON:
+ {
+ paid = fix_item(INVEN_WIELD, INVEN_WIELD, 0, FALSE,
+ BACT_ENCHANT_WEAPON, set_reward);
+ break;
+ }
+
+ case BACT_ENCHANT_ARMOR:
+ {
+ paid = fix_item(INVEN_BODY, INVEN_FEET, 0, TRUE,
+ BACT_ENCHANT_ARMOR, set_reward);
+ break;
+ }
+
+ /* needs work */
+ case BACT_RECHARGE:
+ {
+ if (recharge(80)) paid = TRUE;
+ break;
+ }
+
+ /* needs work */
+ case BACT_IDENTS:
+ {
+ identify_pack();
+ msg_print("Your possessions have been identified.");
+ msg_print(NULL);
+ paid = TRUE;
+ break;
+ }
+
+ /* needs work */
+ case BACT_STAR_HEAL:
+ {
+ hp_player(200);
+ set_poisoned(0);
+ set_blind(0);
+ set_confused(0);
+ set_cut(0);
+ set_stun(0);
+ if (p_ptr->black_breath)
+ {
+ msg_print("The hold of the Black Breath on you is broken!");
+ p_ptr->black_breath = FALSE;
+ }
+ paid = TRUE;
+ break;
+ }
+
+ /* needs work */
+ case BACT_HEALING:
+ {
+ hp_player(200);
+ set_poisoned(0);
+ set_blind(0);
+ set_confused(0);
+ set_cut(0);
+ set_stun(0);
+ paid = TRUE;
+ break;
+ }
+
+ /* needs work */
+ case BACT_RESTORE:
+ {
+ if (do_res_stat(A_STR, TRUE)) paid = TRUE;
+ if (do_res_stat(A_INT, TRUE)) paid = TRUE;
+ if (do_res_stat(A_WIS, TRUE)) paid = TRUE;
+ if (do_res_stat(A_DEX, TRUE)) paid = TRUE;
+ if (do_res_stat(A_CON, TRUE)) paid = TRUE;
+ if (do_res_stat(A_CHR, TRUE)) paid = TRUE;
+ break;
+ }
+
+ case BACT_ENCHANT_ARROWS:
+ {
+ paid = fix_item(0, INVEN_WIELD, TV_ARROW, FALSE,
+ BACT_ENCHANT_ARROWS, set_reward);
+ break;
+ }
+
+ case BACT_ENCHANT_BOW:
+ {
+ paid = fix_item(INVEN_BOW, INVEN_BOW, TV_BOW, FALSE,
+ BACT_ENCHANT_BOW, set_reward);
+ break;
+ }
+
+ case BACT_RECALL:
+ {
+ p_ptr->word_recall = 1;
+ msg_print("The air about you becomes charged...");
+ paid = TRUE;
+ break;
+ }
+
+ case BACT_TELEPORT_LEVEL:
+ {
+ if (reset_recall(FALSE))
+ {
+ p_ptr->word_recall = 1;
+ msg_print("The air about you becomes charged...");
+ paid = TRUE;
+ }
+ break;
+ }
+
+ case BACT_MIMIC_NORMAL:
+ {
+ set_mimic(0, 0, 0);
+ paid = TRUE;
+ break;
+ }
+
+ case BACT_VIEW_BOUNTIES:
+ {
+ show_bounties();
+ break;
+ }
+
+ case BACT_VIEW_QUEST_MON:
+ {
+ show_quest_monster();
+ break;
+ }
+
+ case BACT_SELL_QUEST_MON:
+ {
+ sell_quest_monster();
+ break;
+ }
+
+ case BACT_SELL_CORPSES:
+ {
+ sell_corpses();
+ break;
+ }
+
+ case BACT_DIVINATION:
+ {
+ int i, count = 0;
+ bool_ something = FALSE;
+
+ while (count < 1000)
+ {
+ count++;
+ i = rand_int(MAX_FATES);
+ if (!fates[i].fate) continue;
+ if (fates[i].know) continue;
+ msg_print("You know a little more of your fate.");
+
+ fates[i].know = TRUE;
+ something = TRUE;
+ break;
+ }
+
+ if (!something) msg_print("Well, you have no fate, but I'll keep your money anyway!");
+
+ paid = TRUE;
+ break;
+
+ }
+
+ case BACT_BUY:
+ {
+ store_purchase();
+ break;
+ }
+
+ case BACT_SELL:
+ {
+ store_sell();
+ break;
+ }
+
+ case BACT_EXAMINE:
+ {
+ store_examine();
+ break;
+ }
+
+ case BACT_STEAL:
+ {
+ store_stole();
+ break;
+ }
+
+ case BACT_REQUEST_ITEM:
+ {
+ store_request_item();
+ paid = TRUE;
+ break;
+ }
+
+ case BACT_GET_LOAN:
+ {
+ s32b i, req;
+ char prompt[80];
+
+ if (p_ptr->loan)
+ {
+ msg_print("You already have a loan!");
+ break;
+ }
+
+ req = p_ptr->au;
+
+ for (i = 0; i < INVEN_TOTAL; i++)
+ req += object_value_real(&p_ptr->inventory[i]);
+
+ if (req > 100000) req = 100000;
+ if ((req + p_ptr->au) > PY_MAX_GOLD) req = PY_MAX_GOLD - p_ptr->au;
+
+ strnfmt(prompt, sizeof (prompt),
+ "How much would you like to get (0-%ld) ?", req);
+
+ req = get_quantity(prompt, req);
+
+ if (req)
+ {
+ p_ptr->loan += req;
+ p_ptr->au += req;
+ p_ptr->loan_time += req;
+
+ msg_format("You receive %i gold pieces", req);
+
+ paid = TRUE;
+ }
+ else
+ msg_format("You did not request any money!");
+
+ break;
+ }
+
+ case BACT_PAY_BACK_LOAN:
+ {
+ s32b req;
+ char prompt[80];
+
+ if (p_ptr->loan)
+ {
+ msg_format("You have nothing to payback!");
+ break;
+ }
+
+ msg_format("You have a loan of %i.", p_ptr->loan);
+
+ req = ((p_ptr->loan + bcost) > p_ptr->au) ? p_ptr->au - bcost : p_ptr->loan;
+
+ strnfmt(prompt, sizeof (prompt),
+ "How much would you like to pay back (0-%ld) ?", req);
+
+ req = get_quantity(prompt, req);
+
+ p_ptr->loan -= req;
+ p_ptr->au -= req;
+
+ if (!p_ptr->loan) p_ptr->loan_time = 0;
+
+ msg_format("You pay back %i gold pieces", req);
+ paid = TRUE;
+ break;
+ }
+
+ default:
+ {
+ if (process_hooks_ret(HOOK_BUILDING_ACTION, "dd", "(d)", bact))
+ {
+ paid = process_hooks_return[0].num;
+ recreate = process_hooks_return[1].num;
+ }
+ break;
+ }
+ }
+
+ if (paid)
+ {
+ p_ptr->au -= bcost;
+
+ /* Display the current gold */
+ store_prt_gold();
+ }
+
+ return (recreate);
+}
+
+
+/*
+ * Enter quest level
+ */
+void enter_quest(void)
+{
+ if (!(cave[p_ptr->py][p_ptr->px].feat == FEAT_QUEST_ENTER))
+ {
+ msg_print("You see no quest level here.");
+ return;
+ }
+ else
+ {
+ /* Player enters a new quest */
+ p_ptr->oldpy = p_ptr->py;
+ p_ptr->oldpx = p_ptr->px;
+
+ leaving_quest = p_ptr->inside_quest;
+
+ p_ptr->inside_quest = cave[p_ptr->py][p_ptr->px].special;
+ dun_level = 1;
+ p_ptr->leaving = TRUE;
+ p_ptr->oldpx = p_ptr->px;
+ p_ptr->oldpy = p_ptr->py;
+ }
+}
+
+
+/*
+ * Do building commands
+ */
+void do_cmd_bldg(void)
+{
+ int i, which, x = p_ptr->px, y = p_ptr->py;
+
+ char command;
+
+ bool_ validcmd;
+
+ store_type *s_ptr;
+
+ store_action_type *ba_ptr;
+
+
+ if (cave[p_ptr->py][p_ptr->px].feat != FEAT_SHOP)
+ {
+ msg_print("You see no building here.");
+ return;
+ }
+
+ which = cave[p_ptr->py][p_ptr->px].special;
+ building_loc = which;
+
+ s_ptr = &town_info[p_ptr->town_num].store[which];
+
+ p_ptr->oldpy = p_ptr->py;
+ p_ptr->oldpx = p_ptr->px;
+
+ /* Forget the lite */
+ /* forget_lite(); */
+
+ /* Forget the view */
+ forget_view();
+
+ /* Hack -- Increase "icky" depth */
+ character_icky++;
+
+ command_arg = 0;
+ command_rep = 0;
+ command_new = 0;
+
+ show_building(s_ptr);
+ leave_bldg = FALSE;
+
+ while (!leave_bldg)
+ {
+ validcmd = FALSE;
+ prt("", 1, 0);
+ command = inkey();
+
+ if (command == ESCAPE)
+ {
+ leave_bldg = TRUE;
+ p_ptr->inside_arena = FALSE;
+ break;
+ }
+
+ for (i = 0; i < 6; i++)
+ {
+ ba_ptr = &ba_info[st_info->actions[i]];
+
+ if (ba_ptr->letter)
+ {
+ if (ba_ptr->letter == command)
+ {
+ validcmd = TRUE;
+ break;
+ }
+ }
+ if (ba_ptr->letter_aux)
+ {
+ if (ba_ptr->letter_aux == command)
+ {
+ validcmd = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (validcmd)
+ bldg_process_command(s_ptr, i);
+
+ /* Notice stuff */
+ notice_stuff();
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Flush messages XXX XXX XXX */
+ msg_print(NULL);
+
+ /* Reinit wilderness to activate quests ... */
+ wilderness_gen(TRUE);
+ p_ptr->py = y;
+ p_ptr->px = x;
+
+ /* Hack -- Decrease "icky" depth */
+ character_icky--;
+
+ /* Clear the screen */
+ Term_clear();
+
+ /* Update the visuals */
+ p_ptr->update |= (PU_VIEW | PU_MON_LITE | PU_MONSTERS | PU_BONUS);
+
+ /* Redraw entire screen */
+ p_ptr->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+
diff --git a/src/carbon/Angband.icns b/src/carbon/Angband.icns
new file mode 100644
index 00000000..3d775739
--- /dev/null
+++ b/src/carbon/Angband.icns
Binary files differ
diff --git a/src/carbon/Carbon.r b/src/carbon/Carbon.r
new file mode 100644
index 00000000..e3194dd2
--- /dev/null
+++ b/src/carbon/Carbon.r
@@ -0,0 +1,1568 @@
+/*
+ * Minimal Resources for T.o.M.E.
+ *
+ * Turned into human-readable and programmer-friendly format by pelpel
+ *
+ *
+ * This might help mac/non-mac coders to play, modify, hack and do
+ * whatever they like with this file.
+ *
+ *
+ * Header files and reasons for their inclusion:
+ *
+ * MacTypes.r - 'STR ' and 'STR#'
+ * Finder.r - 'BNDL' and 'FREF'
+ * Dialogs.r - 'ALRT', 'DITL' and 'DLOG'
+ * Menus.r - 'MENU' and 'MBAR'
+ * Processes.r - 'SIZE'
+ */
+
+#include <MacTypes.r>
+#include <Finder.r>
+#include <Dialogs.r>
+#include <Menus.r>
+#include <Processes.r>
+
+
+#ifndef MACH_O
+
+/*
+ * Signature - Who am I?
+ * Vanilla uses 'A271'
+ * ID should always be 0.
+ */
+#define AngbandSignature 'PrnA'
+
+type AngbandSignature as 'STR ';
+
+resource AngbandSignature (0, "Owner resource", purgeable)
+{
+ "T.o.M.E. 2.3.4"
+};
+
+
+/* OS X Finder requires this to recognise a Carbon-compatible PEF binary */
+data 'plst' (0)
+{
+ "$00";
+};
+
+
+/*
+ * Inform system of program's characteristics
+ * ID should always be -1.
+ */
+resource 'SIZE' (-1)
+{
+ /*
+ * Flags dumped = 0101 1000 1100 0000
+ */
+ reserved,
+
+ /* accepts/ignores suspend&resume events? */
+ acceptSuspendResumeEvents,
+
+ reserved,
+
+ /* can use background null events */
+ canBackground,
+
+ /* activates own windows in response to OS events */
+ doesActivateOnFGSwitch,
+
+ /* app has a user interface */
+ backgroundAndForeground,
+
+ /* don't return mouse events in front window on resume */
+ dontGetFrontClicks,
+
+ /* applications use this */
+ ignoreAppDiedEvents,
+
+ /* works with 24- or 32-bit addr */
+ is32BitCompatible,
+
+ /* can use high-level events */
+ isHighLevelEventAware,
+
+ /* only local high-level events */
+ onlyLocalHLEvents,
+
+ /* can't use stationery documents */
+ notStationeryAware,
+
+ /* can't use inline services */
+ dontUseTextEditServices,
+
+ /* all windows redrawn when monitor(s) change */
+ notDisplayManagerAware,
+
+ reserved,
+ reserved,
+
+ /* preferred memory size */
+ 16 * (1024 * 1024),
+
+ /* minimum memory size */
+ 4 * (1024 * 1024)
+};
+
+
+/*
+ * File types used by Angband
+ */
+resource 'FREF' (128, purgeable)
+{
+ /* file type */
+ 'APPL',
+
+ /* maps to icon list resource w/ local ID 0 in bundle resource */
+ 0,
+
+ /* leave empty string for name */
+ ""
+};
+
+resource 'FREF' (129, purgeable)
+{
+ /* file type */
+ 'SAVE',
+
+ /* maps to icon list resource w/ local ID 1 in bundle resource */
+ 1,
+
+ /* leave empty string for name */
+ ""
+};
+
+resource 'FREF' (130, purgeable)
+{
+ /* file type */
+ 'TEXT',
+
+ /* maps to icon list resource w/ local ID 2 in bundle resource */
+ 2,
+
+ /* leave empty string for name */
+ ""
+};
+
+resource 'FREF' (131, purgeable)
+{
+ /* file type */
+ 'DATA',
+
+ /* maps to icon list resource w/ local ID 3 in bundle resource */
+ 3,
+
+ /* leave empty string for name */
+ ""
+};
+
+
+/*
+ * Bundle information
+ */
+resource 'BNDL' (128, purgeable)
+{
+ /* Our signature */
+ AngbandSignature,
+
+ /* resource ID of signature resource: should always be 0 */
+ 0,
+
+ {
+ /* mapping local IDs in 'FREF's to 'ICN#' IDs */
+ 'ICN#',
+ {
+ /* local ID 0 -> ICN# 128 */
+ 0, 128,
+
+ /* local ID 1 -> ICN# 129 */
+ 1, 129,
+
+ /* local ID 2 -> ICN# 130 */
+ 2, 130,
+
+ /* local ID 3 -> ICN# 131 */
+ 3, 131
+ },
+
+ /* local res IDs for 'FREF's: no duplicates */
+ 'FREF',
+ {
+ /* local ID 0 -> FREF 128 */
+ 0, 128,
+
+ /* local ID 1 -> FREF 129 */
+ 1, 129,
+
+ /* local ID 2 -> FREF 130 */
+ 2, 130,
+
+ /* local ID 3 -> FREF 131 */
+ 3, 131
+ }
+ }
+};
+
+#endif /* !MACH_O */
+
+/*
+ * Menu definitions
+ */
+resource 'MENU' (128, preload)
+{
+ /* menu ID */
+ 128,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* everything but the divider is enabled */
+ 0b11111111111111111111111111111101,
+ /* or we can use 0... */
+
+ /* enable the title */
+ enabled,
+
+ /* menu title */
+ apple,
+
+ /* its contents */
+ {
+ /* First item */
+ "About T.o.M.E. ...", noicon, nokey, nomark, plain;
+
+ /* Second item - divider */
+ "-", noicon, nokey, nomark, plain;
+ }
+};
+
+resource 'MENU' (129, preload)
+{
+ /* menu ID */
+ 129,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* let the program enable/disable them */
+ 0b00000000000000000000000000011011,
+
+ /* enable the title */
+ enabled,
+
+ /* menu title */
+ "File",
+
+ /* its contents */
+ {
+#if 0
+ /* item #1 */
+ "New", noicon, "N", nomark, plain;
+
+ /* item #2 */
+ "Open", noicon, "O", nomark, plain;
+
+ /* item #3 */
+ "Import", noicon, "I", nomark, plain;
+#endif
+ /* item #1 (was #4) */
+ "Close", noicon, "W", nomark, plain;
+
+ /* item #2 (was #5) */
+ "Save", noicon, "S", nomark, plain;
+
+ /* item #3 (was #6) */
+ "-", noicon, nokey, nomark, plain;
+
+ /* item #4 (was #7) */
+ "Score", noicon, "H", nomark, plain;
+
+ /* item #4 (was #7) */
+ "Quit", noicon, "Q", nomark, plain;
+ }
+};
+
+
+resource 'MENU' (130, preload)
+{
+ /* menu ID */
+ 130,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* let the program enable/disable them */
+ 0b00000000000000000000000000111101,
+
+ /* enable the title */
+ enabled,
+
+ /* menu title */
+ "Edit",
+
+ /* its contents */
+ {
+ /* item #1 */
+ "Undo", noicon, "Z", nomark, plain;
+
+ /* item #2 */
+ "-", noicon, nokey, nomark, plain;
+
+ /* item #3 */
+ "Cut", noicon, "X", nomark, plain;
+
+ /* item #4 */
+ "Copy", noicon, "C", nomark, plain;
+
+ /* item #5 */
+ "Paste", noicon, "V", nomark, plain;
+
+ /* item #6 */
+ "Clear", noicon, nokey, nomark, plain;
+ }
+};
+
+resource 'MENU' (131, preload)
+{
+ /* menu ID */
+ 131,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* let the program enable/disable them */
+ 0b00000000000000000000000000000011,
+
+ /* enable the title */
+ enabled,
+
+ /* menu title */
+ "Font",
+
+ /* its contents */
+ {
+ /* item #1 */
+ "Bold", noicon, nokey, nomark, plain;
+
+ /* item #2 */
+ "Wide", noicon, nokey, nomark, plain;
+
+ /* item #3 */
+ "-", noicon, nokey, nomark, plain;
+
+ /* the rest are supplied by the program */
+ }
+};
+
+resource 'MENU' (132, preload)
+{
+ /* menu ID */
+ 132,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* let the program enable/disable them */
+ 0b00000000000000000000000000000000,
+
+ /* enable the title */
+ enabled,
+
+ /* menu title */
+ "Size",
+
+ /* its contents */
+ {
+ /* Let the program fill it in */
+ }
+};
+
+resource 'MENU' (133, preload)
+{
+ /* menu ID */
+ 133,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* let the program enable/disable them */
+ 0b00000000000000000000000000000000,
+
+ /* enable the title */
+ enabled,
+
+ /* menu title */
+ "Windows",
+
+ /* its contents */
+ {
+ /* Let the program create them for us */
+ }
+};
+
+resource 'MENU' (134, preload)
+{
+ /* menu ID */
+ 134,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* let the program enable/disable them */
+ 0b00000000000000000000000000011011,
+
+ /* enable the title */
+ enabled,
+
+ /* menu title */
+ "Special",
+
+ /* its contents */
+ {
+ /* item #1 */
+ "Sound", noicon, nokey, nomark, plain;
+
+ /* item #2 - 0x90 = 144 */
+ "Graphics", noicon, hierarchicalMenu, "\0x90", plain;
+
+ /* item #3 - 0x91 = 145 */
+ "TileWidth", noicon, hierarchicalMenu, "\0x91", plain;
+
+ /* item #4 - 0x92 = 146 */
+ "TileHeight", noicon, hierarchicalMenu, "\0x92", plain;
+
+ /* item #5 */
+ "-", noicon, nokey, nomark, plain;
+
+ /* item #6 */
+ "Fiddle", noicon, nokey, nomark, plain;
+
+ /* item #7 */
+ "Wizard", noicon, nokey, nomark, plain;
+ }
+};
+
+/* Graphics submenu */
+resource 'MENU' (144, preload)
+{
+ /* menu ID */
+ 144,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* let the program enable/disable them */
+ 0b00000000000000000000000000000111,
+
+ /* enable the title */
+ enabled,
+
+ /* menu title (ignored) */
+ "Graphics",
+
+ /* menu items */
+ {
+ /* item #1 */
+ "None", noicon, nokey, nomark, plain;
+
+ /* item #2 */
+ "8x8", noicon, nokey, nomark, plain;
+
+ /* item #3 */
+ "16x16", noicon, nokey, nomark, plain;
+
+ /* item #4 */
+ "32x32", noicon, nokey, nomark, plain;
+
+ /* item #5 */
+ "-", noicon, nokey, nomark, plain;
+
+ /* item #6 */
+ "Enlarge tiles", noicon, nokey, nomark, plain;
+ }
+};
+
+/* Tilewidth submenu */
+resource 'MENU' (145, preload)
+{
+ /* menu ID */
+ 145,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* let the program enable/disable them */
+ 0b00000000000000000000000000000000,
+
+ /* enable the title */
+ enabled,
+
+ /* menu title */
+ "TileWidth",
+
+ /* its contents */
+ {
+ /* Let the program create them for us */
+ }
+};
+
+/* TileHeight submenu */
+resource 'MENU' (146, preload)
+{
+ /* menu ID */
+ 146,
+
+ /* use standard definition proc */
+ textMenuProc,
+
+ /* let the program enable/disable them */
+ 0b00000000000000000000000000000000,
+
+ /* enable the title */
+ enabled,
+
+ /* menu title */
+ "TileHeight",
+
+ /* its contents */
+ {
+ /* Let the program create them for us */
+ }
+};
+
+/* Menu bar definition */
+resource 'MBAR' (128, preload)
+{
+ { 128, 129, 130, 131, 132, 133, 134 }
+};
+
+
+/*
+ * Dialogue item lists
+ */
+resource 'DITL' (129, purgeable)
+{
+ {
+ /** item #1 **/
+
+ /* bounding rect */
+ { 45, 353, 65, 411 },
+
+ /* type */
+ Button
+ {
+ /* enable flag */
+ enabled,
+
+ /* title */
+ "OK"
+ },
+
+ /** item #2 **/
+
+ /* bounding rect */
+ { 19, 68, 90, 339 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "^0"
+ },
+
+ /** item #3 **/
+
+ /* bounding rect */
+ { 38, 21, 70, 53 },
+
+ /* type */
+ Icon
+ {
+ /* enable flag */
+ disabled,
+
+ /* 'ICON' ID */
+ 128
+ }
+ }
+};
+
+
+resource 'DITL' (128, purgeable)
+{
+ {
+ /** item #1 **/
+
+ /* bounding rect */
+ { -4, 0, 225, 308 },
+
+ /* type */
+ UserItem
+ {
+ /* enable flag */
+ enabled
+ },
+
+ /** item #2 **/
+
+ /* bounding rect */
+ { 7, 108, 24, 235 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "T.o.M.E. 2.3.3"
+ },
+
+ /** item #3 **/
+
+ /* bounding rect */
+ { 36, 80, 53, 275 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "Copyright (c) 1998-2003"
+ },
+
+ /** item #4 **/
+ { 53, 122, 70, 220 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "DarkGod"
+ },
+
+ /** item #5 **/
+
+ /* bounding rect */
+ { 70, 81, 87, 255 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "(darkgod@ifrance.com)"
+ },
+
+ /** item #6 **/
+
+ /* bounding rect */
+ { 99, 88, 116, 266 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "Original Copyright by"
+ },
+
+ /** item #7 **/
+
+ /* bounding rect */
+ { 135, 92, 151, 255 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "Robert A. Koeneke"
+ },
+
+ /** item #8 **/
+
+ /* bounding rect */
+ { 119, 103, 135, 255 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "James E. Wilson"
+ },
+
+ /** item #9 **/
+
+ /* bounding rect */
+ { 150, 112, 166, 255 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ "Ben Harrison"
+ },
+
+ /** item #10 */
+
+ /* bounding rect */
+ { 166, 62, 182, 145 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "Topi Ylinen"
+ },
+
+ /** item #11 **/
+
+ /* bounding rect */
+ { 166, 148, 182, 294 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "Robert Ruehlmann"
+ },
+
+ /** item #12 **/
+
+ /* bounding rect */
+ { 190, 96, 207, 255 },
+
+ /* type */
+ StaticText
+ {
+ /* enable flag */
+ disabled,
+
+ /* title */
+ "Macintosh Version"
+ }
+ }
+};
+
+resource 'ALRT' (130, purgeable)
+{
+ /* bounding rect */
+ { 144, 154, 283, 384 },
+
+ /* 'DITL' ID */
+ 130,
+
+ /* bold outline, draw alert and beeps */
+ {
+ /* stage 4 */
+ OK, visible, sound1;
+
+ /* stage 3 */
+ OK, visible, sound1;
+
+ /* stage 2 */
+ OK, visible, sound1;
+
+ /* stage 1 */
+ OK, visible, sound1;
+ },
+
+#if ALRT_RezTemplateVersion == 1
+
+ /* centered to parent window */
+ centerParentWindow
+
+#endif /* ALRT_RezTemplateVersion == 1 */
+};
+
+resource 'ALRT' (129, purgeable)
+{
+ /* bounding rect */
+ { 40, 40, 150, 471 },
+
+ /* 'DITL' ID */
+ 129,
+
+ /* bold outline, draw alert and beeps */
+ {
+ /* stage 4 */
+ OK, visible, sound1;
+
+ /* stage 3 */
+ OK, visible, sound1;
+
+ /* stage 2 */
+ OK, visible, sound1;
+
+ /* stage 1 */
+ OK, visible, sound1;
+ },
+
+#if ALRT_RezTemplateVersion == 1
+
+ /* centered to parent window */
+ centerParentWindow
+
+#endif /* ALRT_RezTemplateVersion == 1 */
+};
+
+resource 'ALRT' (128, purgeable)
+{
+ /* bounding rect */
+ { 40, 40, 150, 471 },
+
+ /* 'DITL' ID */
+ 129,
+
+ /* bold outline, draw alert and beeps */
+ {
+ /* stage 4 */
+ OK, visible, sound1;
+
+ /* stage 3 */
+ OK, visible, sound1;
+
+ /* stage 2 */
+ OK, visible, sound1;
+
+ /* stage 1 */
+ OK, visible, sound1;
+ },
+
+#if ALRT_RezTemplateVersion == 1
+
+ /* centered to parent window */
+ centerParentWindow
+
+#endif /* ALRT_RezTemplateVersion == 1 */
+};
+
+resource 'DLOG' (128, purgeable)
+{
+ /* bounding rect */
+ { 112, 202, 341, 512 },
+
+ /* procID */
+ dBoxProc,
+
+ /* visibility */
+ invisible,
+
+ /* has closebox? */
+ noGoAway,
+
+ /* refCon */
+ 0x0,
+
+ /* 'DITL' ID */
+ 128,
+
+ /* title */
+ "",
+
+#if DLOG_RezTemplateVersion == 1
+
+ /* position */
+ centerMainScreen
+
+#endif /* DLOG_RezTemplateVersion == 1 */
+};
+
+
+/*
+ * Additional resources for Carbon
+ */
+resource 'STR#' (128, purgeable)
+{
+ {
+ /* item #1 */
+ "Please select the \"lib\" folder"
+ }
+};
+
+
+/*
+ * Warning Icon (The ! one)
+ */
+data 'ICON' (128, purgeable) {
+ $"0001 8000 0003 C000 0003 C000 0006 6000"
+ $"0006 6000 000C 3000 000C 3000 0018 1800"
+ $"0019 9800 0033 CC00 0033 CC00 0063 C600"
+ $"0063 C600 00C3 C300 00C3 C300 0183 C180"
+ $"0183 C180 0303 C0C0 0303 C0C0 0603 C060"
+ $"0601 8060 0C01 8030 0C00 0030 1800 0018"
+ $"1801 8018 3003 C00C 3003 C00C 6001 8006"
+ $"6000 0006 C000 0003 FFFF FFFF 7FFF FFFE"
+};
+
+
+#ifndef MACH_O
+
+/*
+ * The JRRT icons we all know and love: you are not expected to change these,
+ * unless you are afraid of Tolkien Estate solicitors...
+ */
+
+data 'icl4' (129, purgeable) {
+ $"000F FFFF FFFF FFFF FFFF FFF0 0000 0000"
+ $"000F 0000 0000 0000 0000 0CFF 0000 0000"
+ $"000F 000F FFFF FFFF 0000 0CF0 F000 0000"
+ $"000F 000F 0F0F 0F0F 0000 0CF0 0F00 0000"
+ $"000F 0FFF FFFF FFFF FFFF FCF0 00F0 0000"
+ $"000F 0F0F 0F0F 0F0F 0F0F 0CF0 000F 0000"
+ $"000F 0FFF FFFF FFFF FFFF FCFF FFFF F000"
+ $"000F 000F 0F0F 0F0F 0000 00CC CCCC FC00"
+ $"000F 000F FFFF FFFF 0000 0000 0FF0 FC00"
+ $"000F 0000 000F 0F00 0000 0000 0F00 FC00"
+ $"000F 0000 000F FF00 0FFF FFFF FFF0 FC00"
+ $"000F 0000 000F 0F00 0F0F 0F0F 0F00 FC00"
+ $"000F 0FFF FFFF FFFF FFFF FFFF FFF0 FC00"
+ $"000F 0F0F 0F0F 0F0F 0F00 0000 0F00 FC00"
+ $"000F 0FFF FFFF FFFF F000 FFC0 0000 FC00"
+ $"000F 0F0F 0000 0000 00FF FC0F C000 FC00"
+ $"000F 0FFF 0000 00FC 000F FC0C 0FC0 FC00"
+ $"000F 0F0F 0000 00FF FFFF FFFF FFC0 FC00"
+ $"000F 0FFF FFFF 0FFC CFFF FFFC CFFC FC00"
+ $"000F 0F0F 0F0F 0CC0 FC0F FC0F CCC0 FC00"
+ $"000F 0FFF FFFF 0000 FC0F FC0F C000 FC00"
+ $"000F 0F0F 0F0F 0F00 0FFF FFFC 0000 FC00"
+ $"000F 0FFF FFFF FFF0 00FF FFC0 0000 FC00"
+ $"000F 0F0F 0F0F 0F00 0FCF FCF0 0000 FC00"
+ $"000F 0FFF FFFF FF0F FC0F FC0F FC00 FC00"
+ $"000F 0F0F 0F0F 0F0C C00F FC0C C000 FC00"
+ $"000F 0FFF FFFF FF00 0FCF FC00 0000 FC00"
+ $"000F 0F0F 0F0F 0F0F 0C0F FC00 0000 FC00"
+ $"000F 0FFF FFFF FFFF 000F CFFC 0000 FC00"
+ $"000F 0F0F 0F0F 0F0F 0FFC 0CC0 0000 FC00"
+ $"000F 0000 0000 0000 0CC0 0000 0000 FC00"
+ $"000F FFFF FFFF FFFF FFFF FFFF FFFF FC00"
+};
+
+data 'icl4' (130, purgeable) {
+ $"000F FFFF FFFF FFFF FFFF FFF0 0000 0000"
+ $"000F 0000 0000 0000 0000 0CFF 0000 0000"
+ $"000F 0000 0000 0000 0000 0CF0 F000 0000"
+ $"000F 0000 FFFF FFFF FFFF CCF0 0F00 0000"
+ $"000F 0000 CCCC CCCC CCCC CCF0 00F0 0000"
+ $"000F 0000 0000 0000 0000 0CF0 000F 0000"
+ $"000F 00FF FFFF FFFF FFFF CCFF FFFF F000"
+ $"000F 00CC CCCC CCCC CCCC C0CC CCCC FC00"
+ $"000F 0000 0000 0000 0000 0000 0000 FC00"
+ $"000F 00FF FFFF FFFF FFFF FFFF FFFC FC00"
+ $"000F 00CC CCCC CCCC CCCC CCCC CCCC FC00"
+ $"000F 0000 0000 0000 0000 0000 0000 FC00"
+ $"000F 00FF FFFF FFFF FFFF FFFF FFFC FC00"
+ $"000F 00CC CCCC CCCC CCCC CCCC CCCC FC00"
+ $"000F 0000 0000 0000 0000 FFC0 0000 FC00"
+ $"000F 00FF FFFF C000 00FF FC0F C000 FC00"
+ $"000F 00CC CCCC C0FC 000F FC0C 0FC0 FC00"
+ $"000F 0000 0000 00FF FFFF FFFF FFC0 FC00"
+ $"000F 00FF FFFC 0FFC CFFF FFFC CFFC FC00"
+ $"000F 00CC CCCC 0CC0 FC0F FC0F CCC0 FC00"
+ $"000F 0000 0000 0000 FC0F FC0F C000 FC00"
+ $"000F 0000 FFFF FC00 0FFF FFFC 0000 FC00"
+ $"000F 0000 CCCC CC00 00FF FFC0 0000 FC00"
+ $"000F 0000 0000 0000 0FCF FCF0 0000 FC00"
+ $"000F 00FF FFFF FC0F FC0F FC0F FC00 FC00"
+ $"000F 00CC CCCC CC0C C00F FC0C C000 FC00"
+ $"000F 0000 0000 0000 0FCF FC00 0000 FC00"
+ $"000F 00FF FFFF FFC0 0C0F FC00 0000 FC00"
+ $"000F 00CC CCCC CCC0 000F CFFC 0000 FC00"
+ $"000F 0000 0000 0000 0FFC 0CC0 0000 FC00"
+ $"000F 0000 0000 0000 0CC0 0000 0000 FC00"
+ $"000F FFFF FFFF FFFF FFFF FFFF FFFF FC00"
+};
+
+data 'icl4' (128, purgeable) {
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"F333 3333 3FFF 000F ED00 FFF3 3333 333F"
+ $"F333 333F F000 00FE D0ED 00FF F333 333F"
+ $"F333 33FF 0000 00DD 0FED 0FDF FF33 333F"
+ $"F333 3F00 0000 00FF 0ED0 00FD 00F3 333F"
+ $"F333 F000 0000 00CF FED0 00D0 000F 333F"
+ $"F33F 000F 0000 000F FED0 0000 0E00 F33F"
+ $"F3FF 00FF FFFF FFFF FFFF FFFF FFE0 FF3F"
+ $"F3F0 0FFF FFFF FFFF FFFF FFFF FFFE 0F3F"
+ $"FF00 FEED DDDD DDDF FEDD DDDD DDFF EDFF"
+ $"FF00 FDD0 000F FFFF FEFF FF00 0000 EDFF"
+ $"FF00 D000 00FF DDDF FEDD DFF0 0000 D0FF"
+ $"F000 0000 0FFD 000F FED0 00FE D000 000F"
+ $"F000 0000 0FFD 000F FED0 00FE D000 000F"
+ $"F000 0000 0FFD 000F FED0 00FE D000 000F"
+ $"F000 0000 00FF D00F FED0 0FFD 0000 000F"
+ $"F000 0000 000F FFFF FEFF FFD0 0000 000F"
+ $"F000 0000 000D DDFF FEFD DD00 0000 000F"
+ $"F000 0000 0000 0FFF FEFF 0000 0000 000F"
+ $"F000 0000 0000 FFDF FEDF F000 0000 000F"
+ $"FF00 0000 000F FD0F FED0 FF00 0000 00FF"
+ $"FF00 000F FFFF D00F FED0 0FFF FFD0 00FF"
+ $"FF00 0000 FFFD 000F FED0 00FF FD00 00FF"
+ $"F3F0 0000 DDD0 000F FED0 00DD D000 0F3F"
+ $"F3FF 0000 0000 F00F FED0 0000 0000 FF3F"
+ $"F33F 0000 000F DFDF FED0 0000 0000 F33F"
+ $"F333 F000 0000 FD0F FFD0 0000 000F 333F"
+ $"F333 3F00 0000 D00F FFF0 FFD0 00F3 333F"
+ $"F333 33FF 00F0 00FF FDFF FD00 FF33 333F"
+ $"F333 333F F00F FFFF D00D D00F F333 333F"
+ $"F333 3333 3FFF FFDD 0000 FFF3 3333 333F"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+};
+
+data 'icl4' (131, purgeable) {
+ $"000F FFFF FFFF FFFF FFFF FFF0 0000 0000"
+ $"000F 0000 0000 0000 0000 00FF 0000 0000"
+ $"000F 0F00 0F00 FF00 0FF0 00FC F000 0000"
+ $"000F 0FF0 FF0F 00F0 F00F 00FC 0F00 0000"
+ $"000F 0F0F 0F0F 00F0 F000 00FC 00F0 0000"
+ $"000F 0F00 0F0F FFF0 F000 00FC 000F 0000"
+ $"000F 0F00 0F0F 00F0 F00F 00FF FFFF F000"
+ $"000F 0F00 0F0F 00F0 0FF0 000C CCCC FC00"
+ $"000F 0000 0000 0000 0000 0000 0000 FC00"
+ $"000F FFFF FFFF FFFF FFFF FFFF FFFF FC00"
+ $"000F CCCC CCCC CCCC CCCC CCCC CCCC FC00"
+ $"000F 0000 0000 0000 0000 0000 0000 FC00"
+ $"000F 0000 0000 0000 0000 0000 0000 FC00"
+ $"000F 0000 0000 0000 0000 0000 0000 FC00"
+ $"000F 0000 0000 0000 0000 FFC0 0000 FC00"
+ $"000F 0000 0000 0000 00FF FC0F C000 FC00"
+ $"000F 0000 0000 00FC 000F FC0C 0FC0 FC00"
+ $"000F 0000 0000 00FF FFFF FFFF FFC0 FC00"
+ $"000F 0000 0000 0FFC CFFF FFFC CFFC FC00"
+ $"000F 0000 0000 0CC0 FC0F FC0F CCC0 FC00"
+ $"000F 0000 0000 0000 FC0F FC0F C000 FC00"
+ $"000F 0000 0000 0000 0FFF FFFC 0000 FC00"
+ $"000F 0000 0000 0000 00FF FFC0 0000 FC00"
+ $"000F 0000 0000 0000 0FCF FCF0 0000 FC00"
+ $"000F 0000 0000 000F FC0F FC0F FC00 FC00"
+ $"000F 0000 0000 000C C00F FC0C C000 FC00"
+ $"000F 0000 0000 0000 0FCF FC00 0000 FC00"
+ $"000F 0000 0000 0000 0C0F FC00 0000 FC00"
+ $"000F 0000 0000 0000 000F CFFC 0000 FC00"
+ $"000F 0000 0000 0000 0FFC 0CC0 0000 FC00"
+ $"000F 0000 0000 0000 0CC0 0000 0000 FC00"
+ $"000F FFFF FFFF FFFF FFFF FFFF FFFF FC00"
+};
+
+data 'ICN#' (128, purgeable) {
+ $"FFFF DFFF FFF1 8FFF FF83 23FF FF00 657F"
+ $"FC03 423F F801 C01F F101 C04F F3FF FFEF"
+ $"E7FF FFF7 CE01 C03B C81F FC0B C031 C603"
+ $"8061 C301 8061 C301 8061 C301 8031 C601"
+ $"801F FC01 8003 E001 8007 F001 800D D801"
+ $"C019 CC03 C1F1 C7C3 C0E1 C383 E001 C007"
+ $"F009 C00F F015 C00F F809 C01F FC01 EC3F"
+ $"FF23 B8FF FF9F 01FF FFFC 0FFF FFF3 FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+};
+
+data 'ICN#' (129, purgeable) {
+ $"1FFF FE00 1000 0300 11FF 0280 1155 0240"
+ $"17FF FA20 1555 5210 17FF FBF8 1155 0008"
+ $"11FF 0068 1014 0048 101C 7FE8 1014 5548"
+ $"17FF FFE8 1555 4008 17FF 8C08 1500 3908"
+ $"1702 1848 1503 FFC8 17F6 7E68 1550 9908"
+ $"17F0 9908 1554 7E08 17FE 3C08 1554 5A08"
+ $"17FD 9988 1554 1808 17FC 5808 1555 1808"
+ $"17FF 1608 1555 6008 1000 0008 1FFF FFF8"
+ $"1FFF FE00 1FFF FF00 1FFF FF80 1FFF FFC0"
+ $"1FFF FFE0 1FFF FFF0 1FFF FFF8 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+};
+
+data 'ICN#' (130, purgeable) {
+ $"1FFF FE00 1000 0300 1000 0280 10FF F240"
+ $"1000 0220 1000 0210 13FF F3F8 1000 0008"
+ $"1000 0008 13FF FFE8 1000 0008 1000 0008"
+ $"13FF FFE8 1000 0008 1000 0C08 13F0 3908"
+ $"1002 1848 1003 FFC8 13E6 7E68 1000 9908"
+ $"1000 9908 10F8 7E08 1000 3C08 1000 5A48"
+ $"13F9 9988 1000 1808 1000 5808 13FC 1808"
+ $"1000 1608 1000 6008 1000 0008 1FFF FFF8"
+ $"1FFF FE00 1FFF FF00 1FFF FF80 1FFF FFC0"
+ $"1FFF FFE0 1FFF FFF0 1FFF FFF8 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+};
+
+data 'ICN#' (131, purgeable) {
+ $"1FFF FE00 1000 0300 144C 6280 16D2 9240"
+ $"1552 8220 145E 8210 1452 93F8 1452 6008"
+ $"1000 0008 1FFF FFF8 1000 0008 1000 0008"
+ $"1000 0008 1000 0008 1000 0C08 1000 3908"
+ $"1002 1848 1003 FFC8 1006 7E68 1000 9908"
+ $"1000 9908 1000 7E08 1000 3C08 1000 5A48"
+ $"1001 9988 1000 1808 1000 5808 1000 1808"
+ $"1000 1608 1000 6008 1000 0008 1FFF FFF8"
+ $"1FFF FE00 1FFF FF00 1FFF FF80 1FFF FFC0"
+ $"1FFF FFE0 1FFF FFF0 1FFF FFF8 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+ $"1FFF FFFC 1FFF FFFC 1FFF FFFC 1FFF FFFC"
+};
+
+data 'ics#' (128, purgeable) {
+ $"FFFF F99F F18F FFFF E7E3 8991 8991 87E1"
+ $"83C1 85A1 9999 C183 E587 F18F F97F FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+};
+
+data 'ics#' (129, purgeable) {
+ $"7FF0 4018 5FD4 555E 5FC2 4412 5FFA 5502"
+ $"5F12 557E 5F3A 5556 5F3A 551A 4022 7FFE"
+ $"7FF0 7FF8 7FFC 7FFE 7FFE 7FFE 7FFE 7FFE"
+ $"7FFE 7FFE 7FFE 7FFE 7FFE 7FFE 7FFE 7FFE"
+};
+
+data 'ics#' (130, purgeable) {
+ $"7FF0 4018 5FD4 401E 5FC2 4002 5FFA 4002"
+ $"5F12 407E 5F3A 4056 5F3A 401A 4022 7FFE"
+ $"7FF0 7FF8 7FFC 7FFE 7FFF 7FFF 7FFF 7FFF"
+ $"7FFF 7FFF 7FFF 7FFF 7FFF 7FFF 7FFF 7FFF"
+};
+
+data 'ics#' (131, purgeable) {
+ $"7FF0 4018 5FD4 5F9E 57C2 4002 7FFE 4002"
+ $"4012 407E 403A 4056 403A 401A 4022 7FFE"
+ $"7FF0 7FF8 7FFC 7FFE 7FFF 7FFF 7FFF 7FFF"
+ $"7FFF 7FFF 7FFF 7FFF 7FFF 7FFF 7FFF 7FFF"
+};
+
+data 'icl8' (129, purgeable) {
+ $"0000 00FF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FF00 0000 0000 0000 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 F5F5 F5F7 FFFF 0000 0000 0000 0000"
+ $"0000 00FF F5F5 F5FF FFFF FFFF FFFF FFFF"
+ $"F5F5 F5F5 F5F7 FFF5 FF00 0000 0000 0000"
+ $"0000 00FF F5F5 F5FF F5FF F5FF F5FF F5FF"
+ $"F5F5 F5F5 F5F7 FFF5 F5FF 0000 0000 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFF7 FFF5 F5F5 FF00 0000 0000"
+ $"0000 00FF F5FF F5FF F5FF F5FF F5FF F5FF"
+ $"F5FF F5FF F5F7 FFF5 F5F5 F5FF 0000 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFF7 FFFF FFFF FFFF FF00 0000"
+ $"0000 00FF F5F5 F5FF F5FF F5FF F5FF F5FF"
+ $"F5F5 F5F5 F5F5 F7F7 F7F7 F7F7 FFF7 0000"
+ $"0000 00FF F5F5 F5FF FFFF FFFF FFFF FFFF"
+ $"F5F5 F5F5 F5F5 F5F5 F5FF FFF5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5FF F5FF F5F5"
+ $"F5F5 F5F5 F5F5 F5F5 F5FF F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5FF FFFF F5F5"
+ $"F5FF FFFF FFFF FFFF FFFF FFF5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5FF F5FF F5F5"
+ $"F5FF F5FF F5FF F5FF F5FF F5F5 FFF7 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFF5 FFF7 0000"
+ $"0000 00FF F5FF F5FF F5FF F5FF F5FF F5FF"
+ $"F5FF F5F5 F5F5 F5F5 F5FF F5F5 FFF7 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF FFFF FFFF"
+ $"FFF5 F5F5 FFFF F8F6 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5FF F5FF F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 FFFF FFF8 F7FF F8F6 F5F5 FFF7 0000"
+ $"0000 00FF F5FF FFFF F5F5 F5F5 F5F5 FFF8"
+ $"F6F5 F5FF FFF8 F6F8 F6FF F8F6 FFF7 0000"
+ $"0000 00FF F5FF F5FF F5F5 F5F5 F5F5 FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF F8F6 FFF7 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF F5FF FFF8"
+ $"F8FF FFFF FFFF FFF8 F6FF FFF8 FFF7 0000"
+ $"0000 00FF F5FF F5FF F5FF F5FF F5F8 F8F6"
+ $"FFF8 F6FF FFF8 F6FF F8F6 F6F5 FFF7 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF F5F6 F6F5"
+ $"FFF8 F6FF FFF8 F6FF F8F6 F5F5 FFF7 0000"
+ $"0000 00FF F5FF F5FF F5FF F5FF F5FF F5F5"
+ $"F5FF FFFF FFFF FFF8 F6F5 F5F5 FFF7 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF FFFF FFF5"
+ $"F5F5 FFFF FFFF F8F6 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5FF F5FF F5FF F5FF F5FF F5F5"
+ $"F5FF F8FF FFF8 FFF5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF FFFF F5FF"
+ $"FFF8 F6FF FFF8 F6FF FFF8 F5F5 FFF7 0000"
+ $"0000 00FF F5FF F5FF F5FF F5FF F5FF F5F8"
+ $"F8F6 F5FF FFF8 F6F8 F8F5 F5F5 FFF7 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF FFFF F5F6"
+ $"F6FF F8FF FFF8 F6F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5FF F5FF F5FF F5FF F5FF F5FF"
+ $"F5F8 F6FF FFF8 F6F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5FF FFFF FFFF FFFF FFFF FFFF"
+ $"F5F6 F5FF F8FF FFF8 F6F5 F5F5 FFF7 0000"
+ $"0000 00FF F5FF F5FF F5FF F5FF F5FF F5FF"
+ $"F5FF FFF8 F7F8 F8F6 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F8 F8F7 F6F6 F6F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFF7 0000"
+};
+
+data 'icl8' (128, purgeable) {
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF F9FF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFD7 D7D7 D7D7 D7D7 D7FF FFFF 0000 00FF"
+ $"FCF9 F7F7 FFFF FFD7 D7D7 D7D7 D7D7 6BFF"
+ $"FFD7 4747 4747 4747 FF00 0000 F5F5 FFFC"
+ $"F9F7 FCF8 F7F5 FFFF FF47 4747 4747 6BFF"
+ $"FFD7 4747 4747 FFFF 00F5 F5F5 F5F5 F9F9"
+ $"F7FF FCF8 F7FF F7FF F9FF 4747 4747 6BFF"
+ $"FFD7 4747 47FF 0000 F5F5 F5F5 F5F5 FFFF"
+ $"F7FC F9F7 F5F5 FFF9 F7F5 FF47 4747 6BFF"
+ $"FFD7 4747 FF00 F5F5 F5F5 F5F5 F5F5 F7FF"
+ $"FFFC F9F7 F5F5 F9F7 F5F5 F5FF 4747 6BFF"
+ $"FFD7 47FF 00F5 F5FF F5F5 F5F5 F5F5 F5FF"
+ $"FFFC F9F7 F5F5 F5F5 F5FC F5F5 FF47 6BFF"
+ $"FFD7 47FF 00F5 FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FCF5 FF47 6BFF"
+ $"FFD7 FF00 F5FF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFC F5FF 6BFF"
+ $"FFFF 00F7 FFFC FCF9 F9F9 F9F9 F9F9 F9FF"
+ $"FFFC F9F9 F9F9 F9F9 F9F9 FFFF FCF9 FFFF"
+ $"FFFF 00F7 FCF9 F9F7 F7F7 F7FF FFFF FFFF"
+ $"FFFC FFFF FFFF F7F7 F7F7 F7F7 FCF9 FFFF"
+ $"FFFF 00F7 F9F7 F7F5 F5F5 FFFF F8F8 F8FF"
+ $"FFFC F9F9 F9FF FFF7 F7F5 F5F7 F9F7 FFFF"
+ $"FFF5 F5F5 F7F5 F5F5 F5FF FFF9 F7F7 F7FF"
+ $"FFFC F9F7 F7F7 FFFC F8F7 F5F5 F7F7 F8FF"
+ $"FF00 F5F5 F5F5 F5F5 F5FF FFF9 F7F5 F5FF"
+ $"FFFC F9F7 F5F5 FFFC F8F7 F5F5 F5F5 F8FF"
+ $"FF00 F5F5 F5F5 F5F5 F5FF FFF9 F7F5 F5FF"
+ $"FFFC F9F7 F5F5 FFFC F8F7 F5F5 F5F5 F8FF"
+ $"FF00 F5F5 F5F5 F5F5 F5F5 FFFF F9F7 F5FF"
+ $"FFFC F9F7 F5FF FFF8 F7F5 F5F5 F5F5 F8FF"
+ $"FF00 F5F5 F5F5 F5F5 F5F5 F5FF FFFF FFFF"
+ $"FFFC FFFF FFFF F8F7 F5F5 F5F5 F5F5 F8FF"
+ $"FF00 F5F5 F5F5 F5F5 F5F5 F5F9 F9F9 FFFF"
+ $"FFFC FFF9 F9F9 F7F5 F5F5 F5F5 F5F5 F8FF"
+ $"FF00 F5F5 F5F5 F5F5 F5F5 F5F5 F5FF FFFF"
+ $"FFFC FFFF F7F7 F5F5 F5F5 F5F5 F5F5 F8FF"
+ $"FF00 F5F5 F5F5 F5F5 F5F5 F5F5 FFFF F9FF"
+ $"FFFC F9FF FFF5 F5F5 F5F5 F5F5 F5F5 F8FF"
+ $"FFFF F5F5 F5F5 F5F5 F5F5 F5FF FFF9 F7FF"
+ $"FFFC F9F7 FFFF F5F5 F5F5 F5F5 F5F8 FFFF"
+ $"FFFF F5F5 F5F5 F7FF FFFF FFFF F9F7 F5FF"
+ $"FFFC F9F7 F7FF FFFF FFFF F9F5 F5F8 FFFF"
+ $"FFFF F5F5 F5F5 F5F7 FFFF FFF9 F7F5 F5FF"
+ $"FFFC F9F7 F5F7 FFFF FFF9 F7F5 F5F8 FFFF"
+ $"FFD7 FFF5 F5F5 F5F7 F9F9 F9F7 F5F5 F5FF"
+ $"FFFC F9F7 F5F5 F9F9 F9F7 F5F5 F8FF 6BFF"
+ $"FFD7 47FF F5F5 F5F5 F7F7 F7F5 FFF6 F5FF"
+ $"FFFC F9F7 F5F5 F5F7 F7F5 F5F8 FF47 6BFF"
+ $"FFD7 47FF F5F5 F5F5 F5F5 F5FF F7FF F8FF"
+ $"FFFC F9F7 F5F5 F5F5 F5F5 F5F8 FF47 6BFF"
+ $"FFD7 4747 FFF5 F5F5 F5F5 F5F5 FFF8 F7FF"
+ $"FFFF F9F7 F5F5 F5F5 F5F5 F8FF 4747 6BFF"
+ $"FFD7 4747 47FF F5F5 F5F5 F5F5 F8F7 F5FF"
+ $"FFFF FFF7 FFFF F9F7 F8F8 FF47 4747 6BFF"
+ $"FFD7 4747 4747 FFFF F5F5 FFF5 F7F5 FFFF"
+ $"FFF8 FFFF FFF9 F7F8 FFFF 4747 4747 6BFF"
+ $"FFD7 4747 4747 4747 FFF5 F5FF FFFF FFFF"
+ $"F8F6 F5F9 F9F7 F5FF 4747 4747 4747 6BFF"
+ $"FFD7 6B6B 6B6B 6B6B 6BFF FFFF FFFF F8F8"
+ $"F8F8 F8F5 FFFF FF6B 6B6B 6B6B 6B6B 6BFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF F8F8 FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+};
+
+data 'icl8' (130, purgeable) {
+ $"0000 00FF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FF00 0000 0000 0000 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 F5F5 F5F8 FFFF 0000 0000 0000 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 F5F5 F5F8 FFF6 FF00 0000 0000 0000"
+ $"0000 00FF F5F5 F5F5 FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF F8F8 FFF6 F6FF 0000 0000 0000"
+ $"0000 00FF F5F5 F5F5 F8F8 F8F8 F8F8 F8F8"
+ $"F8F8 F8F8 F8F8 FFF6 F6F6 FF00 0000 0000"
+ $"0000 00FF F5F5 F5F5 F6F6 F6F6 F6F6 F6F6"
+ $"F6F6 F6F6 F6F8 FFF6 F6F6 F6FF 0000 0000"
+ $"0000 00FF F5F5 FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF F8F8 FFFF FFFF FFFF FF00 0000"
+ $"0000 00FF F5F5 F8F8 F8F8 F8F8 F8F8 F8F8"
+ $"F8F8 F8F8 F8F5 F8F8 F8F8 F8F8 FFF7 0000"
+ $"0000 00FF F5F5 F6F6 F6F6 F6F6 F6F6 F6F6"
+ $"F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 FFF7 0000"
+ $"0000 00FF F5F5 FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFF8 FFF7 0000"
+ $"0000 00FF F5F5 F8F8 F8F8 F8F8 F8F8 F8F8"
+ $"F8F8 F8F8 F8F8 F8F8 F8F8 F8F8 FFF7 0000"
+ $"0000 00FF F5F5 F6F6 F6F6 F6F6 F6F6 F6F6"
+ $"F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 FFF7 0000"
+ $"0000 00FF F5F5 FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFF8 FFF7 0000"
+ $"0000 00FF F5F5 F8F8 F8F8 F8F8 F8F8 F8F8"
+ $"F8F8 F8F8 F8F8 F8F8 F8F8 F8F8 FFF7 0000"
+ $"0000 00FF F5F5 F6F6 F6F6 F6F6 F6F6 F6F6"
+ $"F6F6 F6F6 FFFF F8F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 FFFF FFFF FFFF F8F5 F5F5"
+ $"F5F5 FFFF FFF8 F6FF F8F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F8F8 F8F8 F8F8 F8F5 FFF8"
+ $"F5F5 F5FF FFF8 F5F8 F5FF F8F6 FFF7 0000"
+ $"0000 00FF F5F5 F6F6 F6F6 F6F6 F6F5 FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF F8F6 FFF7 0000"
+ $"0000 00FF F5F5 FFFF FFFF FFF8 F6FF FFF8"
+ $"F8FF FFFF FFFF FFF8 F8FF FFF8 FFF7 0000"
+ $"0000 00FF F5F5 F8F8 F8F8 F8F8 F6F8 F8F5"
+ $"FFF8 F6FF FFF8 F6FF F8F8 F8F6 FFF7 0000"
+ $"0000 00FF F5F5 F6F6 F6F6 F6F6 F6F5 F5F5"
+ $"FFF8 F6FF FFF8 F6FF F8F6 F6F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 FFFF FFFF FFF8 F6F5"
+ $"F5FF FFFF FFFF FFF8 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F8F8 F8F8 F8F8 F6F5"
+ $"F5F5 FFFF FFFF F8F6 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F6F6 F6F6 F6F6 F6F5"
+ $"F5FF F8FF FFF8 FFF6 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 FFFF FFFF FFFF FFF8 F6FF"
+ $"FFF8 F6FF FFF8 F6FF FFF8 F6F5 FFF7 0000"
+ $"0000 00FF F5F5 F8F8 F8F8 F8F8 F8F8 F6F8"
+ $"F8F6 F5FF FFF8 F6F8 F8F6 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F6F6 F6F6 F6F6 F6F6 F6F5"
+ $"F6FF F8FF FFF8 F6F6 F6F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 FFFF FFFF FFFF FFFF F8F6"
+ $"F5F8 F6FF FFF8 F6F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F8F8 F8F8 F8F8 F8F8 F8F6"
+ $"F5F6 F5FF F8FF FFF8 F6F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F6F6 F6F6 F6F6 F6F6 F6F6"
+ $"F5FF FFF8 F6F8 F8F6 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F8 F8F6 F5F5 F6F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFF7 0000"
+};
+
+data 'icl8' (131, purgeable) {
+ $"0000 00FF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FF00 0000 0000 0000 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 F5F5 F5F5 FFFF 0000 0000 0000 0000"
+ $"0000 00FF F5FF F5F5 F5FF F5F5 FFFF F5F5"
+ $"F5FF FFF5 F5F5 FFF8 FF00 0000 0000 0000"
+ $"0000 00FF F5FF FFF5 FFFF F5FF 00F5 FFF5"
+ $"FF00 00FF F5F5 FFF8 F6FF 0000 0000 0000"
+ $"0000 00FF F5FF F5FF F5FF F5FF F5F5 FFF5"
+ $"FF00 0000 F5F5 FFF8 F6F6 FF00 0000 0000"
+ $"0000 00FF F5FF F5F5 F5FF F5FF FFFF FFF5"
+ $"FF00 F5F5 F5F5 FFF8 F6F6 F6FF 0000 0000"
+ $"0000 00FF F5FF F5F5 F5FF F5FF F5F5 FFF5"
+ $"FF00 F5FF 00F5 FFFF FFFF FFFF FF00 0000"
+ $"0000 00FF F5FF F5F5 F5FF F5FF F5F5 FFF5"
+ $"00FF FF00 0000 F5F8 F8F8 F8F8 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F500 00F5 F5F5 F5F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFF7 0000"
+ $"0000 00FF F8F8 F8F8 F8F8 F8F8 F8F8 F8F8"
+ $"F8F8 F8F8 F8F8 F8F8 F8F8 F8F8 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 F500 FFFF F8F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 FFFF FFF8 F6FF F8F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 FFF8"
+ $"F5F5 F5FF FFF8 F5F8 F5FF F8F6 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF F8F6 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5FF FFF8"
+ $"F8FF FFFF FFFF FFF8 F8FF FFF8 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F8 F8F5"
+ $"FFF8 F6FF FFF8 F6FF F8F8 F8F6 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"FFF8 F6FF FFF8 F6FF F8F6 F6F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5FF FFFF FFFF FFF8 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F5 FFFF FFFF F8F6 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5FF F8FF FFF8 FFF6 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5FF"
+ $"FFF8 F6FF FFF8 F6FF FFF8 F6F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F8"
+ $"F8F6 F5FF FFF8 F6F8 F8F6 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F6FF F8FF FFF8 F6F6 F6F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F8 F6FF FFF8 F6F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F6 F5FF F8FF FFF8 F6F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5FF FFF8 F6F8 F8F6 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
+ $"F5F8 F8F6 F5F5 F6F5 F5F5 F5F5 FFF7 0000"
+ $"0000 00FF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFF7 0000"
+};
+
+data 'ics8' (128, purgeable) {
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+ $"FF47 4747 FFFF F6FF FFF8 FFFF 4747 47FF"
+ $"FF47 47FF F6F6 F6FF FFF8 F6F6 FF47 47FF"
+ $"FF47 FFFF FFFF FFFF FFFF FFFF FFFF 47FF"
+ $"FF47 FFF8 F8FF FFFF FFFF FFF8 F8F8 47FF"
+ $"FFFF F8F6 FFF8 F8FF FFF8 F8FF F8F6 FFFF"
+ $"FFF6 F6F6 FFF8 F6FF FFF8 F6FF F8F6 F6FF"
+ $"FFF6 F6F6 F6FF FFFF FFFF FFF8 F6F6 F6FF"
+ $"FFF6 F6F6 F6F6 FFFF FFFF F8F6 F6F6 F6FF"
+ $"FFF6 F6F6 F6FF F8FF FFF8 FFF6 F6F6 F6FF"
+ $"FFFF F6FF FFF8 F6FF FFF8 F6FF FFF8 FFFF"
+ $"FFFF F6F8 F8F6 F6FF FFF8 F6F8 F8F8 47FF"
+ $"FF47 FFF6 F6FF F8FF FFF8 F6F6 F6FF 47FF"
+ $"FF47 47FF F6F8 F6FF FFF8 F6F6 FF47 47FF"
+ $"FF47 4747 FFFF F6FF F8FF FFFF 4747 47FF"
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+};
+
+data 'ics8' (129, purgeable) {
+ $"00FF FFFF FFFF FFFF FFFF FFFF 0000 0000"
+ $"00FF F5F5 F5F5 F5F5 F5F5 F5FF FF00 0000"
+ $"00FF F5FF FFFF FFFF FFFF F5FF F5FF 0000"
+ $"00FF F5FF F5FF F5FF F5FF F5FF FFFF FF00"
+ $"00FF F5FF FFFF FFFF FFFF F5F5 F5F5 FF00"
+ $"00FF F5F5 F5FF F5F5 F5F5 F5FF F5F5 FF00"
+ $"00FF F5FF FFFF FFFF FFFF FFFF FFF5 FF00"
+ $"00FF F5FF F5FF F5FF F5F5 F5F5 F5F5 FF00"
+ $"00FF F5FF FFFF FFFF F5F5 F5FF F5F5 FF00"
+ $"00FF F5FF F5FF F5FF F5FF FFFF FFFF FF00"
+ $"00FF F5FF FFFF FFFF F5F5 FFFF FF00 FF00"
+ $"00FF F5FF F5FF F5FF F5FF 00FF 00FF FF00"
+ $"00FF F5FF FFFF FFFF F5F5 FFFF FFF5 FF00"
+ $"00FF F5FF F5FF F5FF F5F5 F5FF FFF5 FF00"
+ $"00FF F5F5 F5F5 F5F5 F5F5 FFF5 F5F5 FF00"
+ $"00FF FFFF FFFF FFFF FFFF FFFF FFFF FF00"
+};
+
+data 'ics8' (130, purgeable) {
+ $"00FF FFFF FFFF FFFF FFFF FFFF 0000 0000"
+ $"00FF F5F5 F5F5 F5F5 F5F5 F5FF FF00 0000"
+ $"00FF F5FF FFFF FFFF FFFF F7FF F5FF 0000"
+ $"00FF F5F7 F7F7 F7F7 F7F7 F7FF FFFF FF00"
+ $"00FF F5FF FFFF FFFF FFFF F7F5 F5F5 FFF7"
+ $"00FF F5F7 F7F7 F7F7 F7F7 F7F5 F5F5 FFF7"
+ $"00FF F5FF FFFF FFFF FFFF FFFF FFF7 FFF7"
+ $"00FF F5F7 F7F7 F7F7 F7F7 F7F7 F7F7 FFF7"
+ $"00FF F5FF FFFF FFFF F7F5 F5FF F5F5 FFF7"
+ $"00FF F5F7 F7F7 F7F7 F7FF FFFF FFFF FFF7"
+ $"00FF F5FF FFFF FFFF F7F5 FFFF FFF5 FFF7"
+ $"00FF F5F7 F7F7 F7F7 F7FF F5FF F5FF FFF7"
+ $"00FF F5FF FFFF FFFF F7F5 FFFF FFF5 FFF7"
+ $"00FF F5F7 F7F7 F7F7 F7F5 F5FF FFF5 FFF7"
+ $"00FF F5F5 F5F5 F5F5 F5F5 FFF5 F5F5 FFF7"
+ $"00FF FFFF FFFF FFFF FFFF FFFF FFFF FFF7"
+};
+
+data 'ics8' (131, purgeable) {
+ $"00FF FFFF FFFF FFFF FFFF FFFF 0000 0000"
+ $"00FF F5F5 F5F5 F5F5 F5F5 F5FF FF00 0000"
+ $"00FF F5FF FFFF FFFF FFFF F5FF F5FF 0000"
+ $"00FF F5FF FFFF FFFF FF00 F5FF FFFF FF00"
+ $"00FF F5FF 00FF FFFF FFFF F5F5 F7F7 FFF7"
+ $"00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 FFF7"
+ $"00FF FFFF FFFF FFFF FFFF FFFF FFFF FFF7"
+ $"00FF F7F7 F7F7 F7F7 F7F7 F7F7 F7F7 FFF7"
+ $"00FF F5F5 F5F5 F5F5 F5F5 F5FF F5F5 FFF7"
+ $"00FF F5F5 F5F5 F5F5 F5FF FFFF FFFF FFF7"
+ $"00FF F5F5 F5F5 F5F5 F5F5 FFFF FFF5 FFF7"
+ $"00FF F5F5 F5F5 F5F5 F5FF F5FF F5FF FFF7"
+ $"00FF F5F5 F5F5 F5F5 F5F5 FFFF FFF5 FFF7"
+ $"00FF F5F5 F5F5 F5F5 F5F5 F5FF FFF5 FFF7"
+ $"00FF F5F5 F5F5 F5F5 F5F5 FFF5 F5F5 FFF7"
+ $"00FF FFFF FFFF FFFF FFFF FFFF FFFF FFF7"
+};
+
+data 'ics4' (128, purgeable) {
+ $"FFFF FFFF FFFF FFFF F333 FFCF FCFF 333F"
+ $"F33F CCCF FCCC F33F F3FF FFFF FFFF FF3F"
+ $"FFFC CFFF FFFC CCFF FFCC FCCF FCCF CCFF"
+ $"FCCC FCCF FCCF CCCF FCCC CFFF FFFC CCCF"
+ $"FCCC CCFF FFCC CCCF FCCC CFCF FCFC CCCF"
+ $"FFCF FCCF FCCF FCFF FFCC CCCF FCCC CCFF"
+ $"F3FC CFCF FCCC CF3F F33F CCCF FCCC F33F"
+ $"F333 FFCF CFFF 333F FFFF FFFF FFFF FFFF"
+};
+
+data 'ics4' (129, purgeable) {
+ $"0FFF FFFF FFFF 0000 0F00 0000 000F F000"
+ $"0F0F FFFF FF0F 0F00 0F0F 0F0F 0F0F FFF0"
+ $"0F0F FFFF FF00 00F0 0F00 0F00 000F 00F0"
+ $"0F0F FFFF FFFF F0F0 0F0F 0F0F 0000 00F0"
+ $"0F0F FFFF 000F 00F0 0F0F 0F0F 0FFF FFF0"
+ $"0F0F FFFF 00FF F0F0 0F0F 0F0F 0F0F 0FF0"
+ $"0F0F FFFF 00FF F0F0 0F0F 0F0F 000F F0F0"
+ $"0F00 0000 00F0 00F0 0FFF FFFF FFFF FFF0"
+};
+
+data 'ics4' (130, purgeable) {
+ $"0FFF FFFF FFFF 0000 0FCC CCCC CCCF F000"
+ $"0FCF FFFF FFCF CF00 0FCC CCCC CCCF FFF0"
+ $"0FCF FFFF FFCC CCFD 0FCC CCCC CCCC CCFD"
+ $"0FCF FFFF FFFF FCFD 0FCC CCCC CCCC CCFD"
+ $"0FCF FFFF CCCF CCFD 0FCC CCCC CFFF FFFD"
+ $"0FCF FFFF CCFF FCFD 0FCC CCCC CFCF CFFD"
+ $"0FCF FFFF CCFF FCFD 0FCC CCCC CCCF FCFD"
+ $"0FCC CCCC CCFC CCFD 0FFF FFFF FFFF FFFD"
+};
+
+data 'ics4' (131, purgeable) {
+ $"0FFF FFFF FFFF 0000 0FCC CCCC CCCF F000"
+ $"0FCF FFFF FFCF CF00 0FCF FFFF FCCF FFF0"
+ $"0FCF CFFF FFCC DDFD 0FCC CCCC CCCC CCFD"
+ $"0FFF FFFF FFFF FFFD 0FCC CCCC CCCC CCFD"
+ $"0FCC CCCC CCCF CCFD 0FCC CCCC CFFF FFFD"
+ $"0FCC CCCC CCFF FCFD 0FCC CCCC CFCF CFFD"
+ $"0FCC CCCC CCFF FCFD 0FCC CCCC CCCF FCFD"
+ $"0FCC CCCC CCFC CCFD 0FFF FFFF FFFF FFFD"
+};
+
+#endif /* !MACH_O */
+
diff --git a/src/carbon/Data.icns b/src/carbon/Data.icns
new file mode 100644
index 00000000..dbaec173
--- /dev/null
+++ b/src/carbon/Data.icns
Binary files differ
diff --git a/src/carbon/Edit.icns b/src/carbon/Edit.icns
new file mode 100644
index 00000000..5e55c272
--- /dev/null
+++ b/src/carbon/Edit.icns
Binary files differ
diff --git a/src/carbon/Image-DS_Store b/src/carbon/Image-DS_Store
new file mode 100644
index 00000000..efd42e72
--- /dev/null
+++ b/src/carbon/Image-DS_Store
Binary files differ
diff --git a/src/carbon/Info.plist b/src/carbon/Info.plist
new file mode 100644
index 00000000..fff3fb15
--- /dev/null
+++ b/src/carbon/Info.plist
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plist version="1.0">
+ <dict>
+ <key>CFBundleName</key><string>T.o.M.E.</string>
+ <key>CFBundleDisplayName</key><string>T.o.M.E. (OS X)</string>
+ <key>CFBundleExecutable</key><string>tome</string>
+ <key>CFBundlePackageType</key><string>APPL</string>
+ <key>CFBundleSignature</key><string>PrnA</string>
+ <key>CFBundleVersion</key><string>2.3.4</string>
+ <key>CFBundleShortVersionString</key><string>234</string>
+ <key>CFBundleIconFile</key><string>Angband</string>
+ <key>CFBundleIdentifier</key><string>net.t-o-m-e.tome</string>
+ <key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtentions</key><array><string>*</string></array>
+ <key>CFBundleTypeIconFile</key><string>Save</string>
+ <key>CFBundleTypeName</key><string>Angband game data</string>
+ <key>CFBundleTypeOSTypes</key><array><string>SAVE</string></array>
+ <key>CFBundleTypeRole</key><string>Editor</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtentions</key><array><string>*</string></array>
+ <key>CFBundleTypeIconFile</key><string>Edit</string>
+ <key>CFBundleTypeName</key><string>Angband game data</string>
+ <key>CFBundleTypeOSTypes</key><array><string>TEXT</string></array>
+ <key>CFBundleTypeRole</key><string>Editor</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtentions</key><array><string>*</string></array>
+ <key>CFBundleTypeIconFile</key><string>Data</string>
+ <key>CFBundleTypeName</key><string>Angband game data</string>
+ <key>CFBundleTypeOSTypes</key><array><string>DATA</string></array>
+ <key>CFBundleTypeRole</key><string>Editor</string>
+ </dict>
+ </array>
+ </dict>
+</plist>
diff --git a/src/carbon/Save.icns b/src/carbon/Save.icns
new file mode 100644
index 00000000..362f80f6
--- /dev/null
+++ b/src/carbon/Save.icns
Binary files differ
diff --git a/src/carbon/getversion b/src/carbon/getversion
new file mode 100755
index 00000000..786fd14b
--- /dev/null
+++ b/src/carbon/getversion
@@ -0,0 +1,2 @@
+#! /bin/sh
+grep CFBundleVersion carbon/Info.plist | perl -pe "s,.*<string>([^<]*)<.*,\\1,"
diff --git a/src/cave.c b/src/cave.c
new file mode 100644
index 00000000..d23fc44c
--- /dev/null
+++ b/src/cave.c
@@ -0,0 +1,5055 @@
+/* File: cave.c */
+
+/* Purpose: low level dungeon routines -BEN- */
+
+
+#include "angband.h"
+
+
+/*
+ * Support for Adam Bolt's tileset, lighting and transparency effects
+ * by Robert Ruehlmann (rr9@angband.org)
+ */
+
+
+/*
+ * Approximate Distance between two points.
+ *
+ * When either the X or Y component dwarfs the other component,
+ * this function is almost perfect, and otherwise, it tends to
+ * over-estimate about one grid per fifteen grids of distance.
+ *
+ * Algorithm: hypot(dy,dx) = max(dy,dx) + min(dy,dx) / 2
+ */
+int distance(int y1, int x1, int y2, int x2)
+{
+ int dy, dx, d;
+
+
+ /* Find the absolute y/x distance components */
+ dy = (y1 > y2) ? (y1 - y2) : (y2 - y1);
+ dx = (x1 > x2) ? (x1 - x2) : (x2 - x1);
+
+ /* Hack -- approximate the distance */
+ d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
+
+ /* Return the distance */
+ return (d);
+}
+
+
+/*
+ * Returns TRUE if a grid is considered to be a wall for the purpose
+ * of magic mapping / clairvoyance
+ */
+static bool_ is_wall(cave_type *c_ptr)
+{
+ byte feat;
+
+
+ /* Handle feature mimics */
+ if (c_ptr->mimic) feat = c_ptr->mimic;
+ else feat = c_ptr->feat;
+
+ /* Paranoia */
+ if (feat >= max_f_idx) return FALSE;
+
+ /* Vanilla floors and doors aren't considered to be walls */
+ if (feat < FEAT_SECRET) return FALSE;
+
+ /* Exception #1: a glass wall is a wall but doesn't prevent LOS */
+ if (feat == FEAT_GLASS_WALL) return FALSE;
+
+ /* Exception #2: an illusion wall is not a wall but obstructs view */
+ if (feat == FEAT_ILLUS_WALL) return TRUE;
+
+ /* Exception #3: a small tree is a floor but obstructs view */
+ if (feat == FEAT_SMALL_TREES) return TRUE;
+
+ /* Normal cases: use the WALL flag in f_info.txt */
+ return (f_info[feat].flags1 & FF1_WALL) ? TRUE : FALSE;
+}
+
+
+/*
+ * A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall,
+ * 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu.
+ *
+ * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2).
+ *
+ * The LOS begins at the center of the tile (x1,y1) and ends at the center of
+ * the tile (x2,y2). If los() is to return TRUE, all of the tiles this line
+ * passes through must be floor tiles, except for (x1,y1) and (x2,y2).
+ *
+ * We assume that the "mathematical corner" of a non-floor tile does not
+ * block line of sight.
+ *
+ * Because this function uses (short) ints for all calculations, overflow may
+ * occur if dx and dy exceed 90.
+ *
+ * Once all the degenerate cases are eliminated, the values "qx", "qy", and
+ * "m" are multiplied by a scale factor "f1 = abs(dx * dy * 2)", so that
+ * we can use integer arithmetic.
+ *
+ * We travel from start to finish along the longer axis, starting at the border
+ * between the first and second tiles, where the y offset = .5 * slope, taking
+ * into account the scale factor. See below.
+ *
+ * Also note that this function and the "move towards target" code do NOT
+ * share the same properties. Thus, you can see someone, target them, and
+ * then fire a bolt at them, but the bolt may hit a wall, not them. However,
+ * by clever choice of target locations, you can sometimes throw a "curve".
+ *
+ * Note that "line of sight" is not "reflexive" in all cases.
+ *
+ * Use the "projectable()" routine to test "spell/missile line of sight".
+ *
+ * Use the "update_view()" function to determine player line-of-sight.
+ */
+bool_ los(int y1, int x1, int y2, int x2)
+{
+ /* Delta */
+ int dx, dy;
+
+ /* Absolute */
+ int ax, ay;
+
+ /* Signs */
+ int sx, sy;
+
+ /* Fractions */
+ int qx, qy;
+
+ /* Scanners */
+ int tx, ty;
+
+ /* Scale factors */
+ int f1, f2;
+
+ /* Slope, or 1/Slope, of LOS */
+ int m;
+
+
+ /* Extract the offset */
+ dy = y2 - y1;
+ dx = x2 - x1;
+
+ /* Extract the absolute offset */
+ ay = ABS(dy);
+ ax = ABS(dx);
+
+
+ /* Handle adjacent (or identical) grids */
+ if ((ax < 2) && (ay < 2)) return (TRUE);
+
+
+ /* Paranoia -- require "safe" origin */
+ /* if (!in_bounds(y1, x1)) return (FALSE); */
+
+
+ /* Directly South/North */
+ if (!dx)
+ {
+ /* South -- check for walls */
+ if (dy > 0)
+ {
+ for (ty = y1 + 1; ty < y2; ty++)
+ {
+ if (!cave_sight_bold(ty, x1)) return (FALSE);
+ }
+ }
+
+ /* North -- check for walls */
+ else
+ {
+ for (ty = y1 - 1; ty > y2; ty--)
+ {
+ if (!cave_sight_bold(ty, x1)) return (FALSE);
+ }
+ }
+
+ /* Assume los */
+ return (TRUE);
+ }
+
+ /* Directly East/West */
+ if (!dy)
+ {
+ /* East -- check for walls */
+ if (dx > 0)
+ {
+ for (tx = x1 + 1; tx < x2; tx++)
+ {
+ if (!cave_sight_bold(y1, tx)) return (FALSE);
+ }
+ }
+
+ /* West -- check for walls */
+ else
+ {
+ for (tx = x1 - 1; tx > x2; tx--)
+ {
+ if (!cave_sight_bold(y1, tx)) return (FALSE);
+ }
+ }
+
+ /* Assume los */
+ return (TRUE);
+ }
+
+
+ /* Extract some signs */
+ sx = (dx < 0) ? -1 : 1;
+ sy = (dy < 0) ? -1 : 1;
+
+
+ /* Vertical "knights" */
+ if (ax == 1)
+ {
+ if (ay == 2)
+ {
+ if (cave_sight_bold(y1 + sy, x1)) return (TRUE);
+ }
+ }
+
+ /* Horizontal "knights" */
+ else if (ay == 1)
+ {
+ if (ax == 2)
+ {
+ if (cave_sight_bold(y1, x1 + sx)) return (TRUE);
+ }
+ }
+
+
+ /* Calculate scale factor div 2 */
+ f2 = (ax * ay);
+
+ /* Calculate scale factor */
+ f1 = f2 << 1;
+
+
+ /* Travel horizontally */
+ if (ax >= ay)
+ {
+ /* Let m = dy / dx * 2 * (dy * dx) = 2 * dy * dy */
+ qy = ay * ay;
+ m = qy << 1;
+
+ tx = x1 + sx;
+
+ /* Consider the special case where slope == 1. */
+ if (qy == f2)
+ {
+ ty = y1 + sy;
+ qy -= f1;
+ }
+ else
+ {
+ ty = y1;
+ }
+
+ /* Note (below) the case (qy == f2), where */
+ /* the LOS exactly meets the corner of a tile. */
+ while (x2 - tx)
+ {
+ if (!cave_sight_bold(ty, tx)) return (FALSE);
+
+ qy += m;
+
+ if (qy < f2)
+ {
+ tx += sx;
+ }
+ else if (qy > f2)
+ {
+ ty += sy;
+ if (!cave_sight_bold(ty, tx)) return (FALSE);
+ qy -= f1;
+ tx += sx;
+ }
+ else
+ {
+ ty += sy;
+ qy -= f1;
+ tx += sx;
+ }
+ }
+ }
+
+ /* Travel vertically */
+ else
+ {
+ /* Let m = dx / dy * 2 * (dx * dy) = 2 * dx * dx */
+ qx = ax * ax;
+ m = qx << 1;
+
+ ty = y1 + sy;
+
+ if (qx == f2)
+ {
+ tx = x1 + sx;
+ qx -= f1;
+ }
+ else
+ {
+ tx = x1;
+ }
+
+ /* Note (below) the case (qx == f2), where */
+ /* the LOS exactly meets the corner of a tile. */
+ while (y2 - ty)
+ {
+ if (!cave_sight_bold(ty, tx)) return (FALSE);
+
+ qx += m;
+
+ if (qx < f2)
+ {
+ ty += sy;
+ }
+ else if (qx > f2)
+ {
+ tx += sx;
+ if (!cave_sight_bold(ty, tx)) return (FALSE);
+ qx -= f1;
+ ty += sy;
+ }
+ else
+ {
+ tx += sx;
+ qx -= f1;
+ ty += sy;
+ }
+ }
+ }
+
+ /* Assume los */
+ return (TRUE);
+}
+
+
+
+/*
+ * Returns true if the player's grid is dark
+ */
+bool_ no_lite(void)
+{
+ return (!player_can_see_bold(p_ptr->py, p_ptr->px));
+}
+
+
+
+/*
+ * Determine if a given location may be "destroyed"
+ *
+ * Used by destruction spells, and for placing stairs, etc.
+ */
+bool_ cave_valid_bold(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ s16b this_o_idx, next_o_idx = 0;
+
+
+ /* Forbid perma-grids */
+ if (cave_perma_grid(c_ptr)) return (FALSE);
+
+ /* Check objects */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Forbid artifact grids */
+ if ((o_ptr->art_name) || artifact_p(o_ptr)) return (FALSE);
+ }
+
+ /* Accept */
+ return (TRUE);
+}
+
+
+
+
+/*
+ * Hack -- Legal monster codes
+ */
+static cptr image_monster_hack = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+/*
+ * Hack -- Legal monster codes for IBM pseudo-graphics
+ *
+ * Dropped. Although this option has long left unmaintained, hardcoding
+ * code points makes it impossible to update the font and prf files
+ * flexibly. And the normal graphics code still works with it -- pelpel
+ */
+
+/*
+ * Mega-Hack -- Hallucinatory monster
+ */
+static void image_monster(byte *ap, char *cp)
+{
+ int n;
+
+ switch (graphics_mode)
+ {
+ /* Text mode */
+ case GRAPHICS_NONE:
+ {
+ n = strlen(image_monster_hack);
+
+ /* Random symbol from set above */
+ *cp = (image_monster_hack[rand_int(n)]);
+
+ /* Random color */
+ *ap = randint(15);
+
+ break;
+ }
+
+ /* Normal graphics */
+ default:
+ {
+ /* Avoid player ghost */
+ n = randint(max_r_idx);
+
+ *cp = r_info[n].x_char;
+
+ *ap = r_info[n].x_attr;
+
+ break;
+ }
+ }
+}
+
+
+
+
+/*
+ * Hack -- Legal object codes
+ */
+static cptr image_object_hack = "?/|\\\"!$()_-=[]{},~";
+
+/*
+ * Hardcoded IBM pseudo-graphics code points have been removed
+ * for the same reason as stated above -- pelpel
+ */
+
+/*
+ * Mega-Hack -- Hallucinatory object
+ */
+static void image_object(byte *ap, char *cp)
+{
+ int n;
+
+ switch (graphics_mode)
+ {
+ /* Text mode */
+ case GRAPHICS_NONE:
+ {
+ n = strlen(image_object_hack);
+
+ /* Random symbol from set above */
+ *cp = (image_object_hack[rand_int(n)]);
+
+ /* Random color */
+ *ap = randint(15);
+
+ /* Done */
+ break;
+ }
+
+ /* Normal graphics */
+ default:
+ {
+ n = randint(max_k_idx - 1);
+
+ *cp = k_info[n].x_char;
+ *ap = k_info[n].x_attr;
+
+ break;
+ }
+ }
+}
+
+
+/*
+ * Hack -- Random hallucination
+ */
+static void image_random(byte *ap, char *cp)
+{
+ /* Normally, assume monsters */
+ if (rand_int(100) < 75)
+ {
+ image_monster(ap, cp);
+ }
+
+ /* Otherwise, assume objects */
+ else
+ {
+ image_object(ap, cp);
+ }
+}
+
+
+/*
+ * The 16x16 tile of the terrain supports lighting
+ */
+#if 1
+
+#define feat_supports_lighting(F) \
+((f_info[F].flags1 & FF1_SUPPORT_LIGHT) != 0)
+
+#else
+
+static bool_ feat_supports_lighting(byte feat)
+{
+ if (f_info[feat].flags1 & FF1_SUPPORT_LIGHT) return TRUE;
+ else return FALSE;
+}
+
+#endif
+
+
+char get_shimmer_color()
+{
+ switch (randint(7))
+ {
+ case 1:
+ return (TERM_RED);
+ case 2:
+ return (TERM_L_RED);
+ case 3:
+ return (TERM_WHITE);
+ case 4:
+ return (TERM_L_GREEN);
+ case 5:
+ return (TERM_BLUE);
+ case 6:
+ return (TERM_L_DARK);
+ case 7:
+ return (TERM_GREEN);
+ }
+
+ return (TERM_VIOLET);
+}
+
+
+/*
+ * Table of breath colors. Must match listings in a single set of
+ * monster spell flags.
+ *
+ * The value "255" is special. Monsters with that kind of breath
+ * may be any color.
+ */
+static byte breath_to_attr[32][2] =
+{
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { TERM_SLATE, TERM_L_DARK }, /* RF4_BRTH_ACID */
+ { TERM_BLUE, TERM_L_BLUE }, /* RF4_BRTH_ELEC */
+ { TERM_RED, TERM_L_RED }, /* RF4_BRTH_FIRE */
+ { TERM_WHITE, TERM_L_WHITE }, /* RF4_BRTH_COLD */
+ { TERM_GREEN, TERM_L_GREEN }, /* RF4_BRTH_POIS */
+ { TERM_L_GREEN, TERM_GREEN }, /* RF4_BRTH_NETHR */
+ { TERM_YELLOW, TERM_ORANGE }, /* RF4_BRTH_LITE */
+ { TERM_L_DARK, TERM_SLATE }, /* RF4_BRTH_DARK */
+ { TERM_L_UMBER, TERM_UMBER }, /* RF4_BRTH_CONFU */
+ { TERM_YELLOW, TERM_L_UMBER }, /* RF4_BRTH_SOUND */
+ { 255, 255 }, /* (any color) */ /* RF4_BRTH_CHAOS */
+ { TERM_VIOLET, TERM_VIOLET }, /* RF4_BRTH_DISEN */
+ { TERM_L_RED, TERM_VIOLET }, /* RF4_BRTH_NEXUS */
+ { TERM_L_BLUE, TERM_L_BLUE }, /* RF4_BRTH_TIME */
+ { TERM_L_WHITE, TERM_SLATE }, /* RF4_BRTH_INER */
+ { TERM_L_WHITE, TERM_SLATE }, /* RF4_BRTH_GRAV */
+ { TERM_UMBER, TERM_L_UMBER }, /* RF4_BRTH_SHARD */
+ { TERM_ORANGE, TERM_RED }, /* RF4_BRTH_PLAS */
+ { TERM_UMBER, TERM_L_UMBER }, /* RF4_BRTH_FORCE */
+ { TERM_L_BLUE, TERM_WHITE }, /* RF4_BRTH_MANA */
+ { 0, 0 }, /* */
+ { TERM_GREEN, TERM_L_GREEN }, /* RF4_BRTH_NUKE */
+ { 0, 0 }, /* */
+ { TERM_WHITE, TERM_L_RED }, /* RF4_BRTH_DISINT */
+};
+
+
+/*
+ * Multi-hued monsters shimmer acording to their breaths.
+ *
+ * If a monster has only one kind of breath, it uses both colors
+ * associated with that breath. Otherwise, it just uses the first
+ * color for any of its breaths.
+ *
+ * If a monster does not breath anything, it can be any color.
+ */
+static byte multi_hued_attr(monster_race *r_ptr)
+{
+ byte allowed_attrs[15];
+
+ int i, j;
+
+ int stored_colors = 0;
+
+ int breaths = 0;
+
+ int first_color = 0;
+
+ int second_color = 0;
+
+
+ /* Monsters with no ranged attacks can be any color */
+ if (!r_ptr->freq_inate) return (get_shimmer_color());
+
+ /* Check breaths */
+ for (i = 0; i < 32; i++)
+ {
+ bool_ stored = FALSE;
+
+ /* Don't have that breath */
+ if (!(r_ptr->flags4 & (1L << i))) continue;
+
+ /* Get the first color of this breath */
+ first_color = breath_to_attr[i][0];
+
+ /* Breath has no color associated with it */
+ if (first_color == 0) continue;
+
+ /* Monster can be of any color */
+ if (first_color == 255) return (randint(15));
+
+
+ /* Increment the number of breaths */
+ breaths++;
+
+ /* Monsters with lots of breaths may be any color. */
+ if (breaths == 6) return (randint(15));
+
+
+ /* Always store the first color */
+ for (j = 0; j < stored_colors; j++)
+ {
+ /* Already stored */
+ if (allowed_attrs[j] == first_color) stored = TRUE;
+ }
+ if (!stored)
+ {
+ allowed_attrs[stored_colors] = first_color;
+ stored_colors++;
+ }
+
+ /*
+ * Remember (but do not immediately store) the second color
+ * of the first breath.
+ */
+ if (breaths == 1)
+ {
+ second_color = breath_to_attr[i][1];
+ }
+ }
+
+ /* Monsters with no breaths may be of any color. */
+ if (breaths == 0) return (get_shimmer_color());
+
+ /* If monster has one breath, store the second color too. */
+ if (breaths == 1)
+ {
+ allowed_attrs[stored_colors] = second_color;
+ stored_colors++;
+ }
+
+ /* Pick a color at random */
+ return (allowed_attrs[rand_int(stored_colors)]);
+}
+
+
+/*
+ * Extract the attr/char to display at the given (legal) map location
+ *
+ * Note that this function, since it is called by "lite_spot()" which
+ * is called by "update_view()", is a major efficiency concern.
+ *
+ * Basically, we examine each "layer" of the world (terrain, objects,
+ * monsters/players), from the bottom up, extracting a new attr/char
+ * if necessary at each layer, and defaulting to "darkness". This is
+ * not the fastest method, but it is very simple, and it is about as
+ * fast as it could be for grids which contain no "marked" objects or
+ * "visible" monsters.
+ *
+ * We apply the effects of hallucination during each layer. Objects will
+ * always appear as random "objects", monsters will always appear as random
+ * "monsters", and normal grids occasionally appear as random "monsters" or
+ * "objects", but note that these random "monsters" and "objects" are really
+ * just "colored ascii symbols" (which may look silly on some machines).
+ *
+ * The hallucination functions avoid taking any pointers to local variables
+ * because some compilers refuse to use registers for any local variables
+ * whose address is taken anywhere in the function.
+ *
+ * As an optimization, we can handle the "player" grid as a special case.
+ *
+ * Note that the memorization of "objects" and "monsters" is not related
+ * to the memorization of "terrain". This allows the player to memorize
+ * the terrain of a grid without memorizing any objects in that grid, and
+ * to detect monsters without detecting anything about the terrain of the
+ * grid containing the monster.
+ *
+ * The fact that all interesting "objects" and "terrain features" are
+ * memorized as soon as they become visible for the first time means
+ * that we only have to check the "CAVE_SEEN" flag for "boring" grids.
+ *
+ * Note that bizarre things must be done when the "attr" and/or "char"
+ * codes have the "high-bit" set, since these values are used to encode
+ * various "special" pictures in some versions, and certain situations,
+ * such as "multi-hued" or "clear" monsters, cause the attr/char codes
+ * to be "scrambled" in various ways.
+ *
+ * Note that the "zero" entry in the feature/object/monster arrays are
+ * used to provide "special" attr/char codes, with "monster zero" being
+ * used for the player attr/char, "object zero" being used for the "stack"
+ * attr/char, and "feature zero" being used for the "nothing" attr/char.
+ *
+ * Note that eventually we may want to use the "&" symbol for embedded
+ * treasure, and use the "*" symbol to indicate multiple objects, but
+ * currently, we simply use the attr/char of the first "marked" object
+ * in the stack, if any, and so "object zero" is unused. XXX XXX XXX
+ *
+ * Note the assumption that doing "x_ptr = &x_info[x]" plus a few of
+ * "x_ptr->xxx", is quicker than "x_info[x].xxx", even if "x" is a fixed
+ * constant. If this is incorrect then a lot of code should be changed.
+ *
+ *
+ * Some comments on the "terrain" layer...
+ *
+ * Note that "boring" grids (floors, invisible traps, and any illegal grids)
+ * are very different from "interesting" grids (all other terrain features),
+ * and the two types of grids are handled completely separately. The most
+ * important distinction is that "boring" grids may or may not be memorized
+ * when they are first encountered, and so we must use the "CAVE_SEEN" flag
+ * to see if they are "see-able".
+ *
+ *
+ * Some comments on the "terrain" layer (boring grids)...
+ *
+ * Note that "boring" grids are always drawn using the picture for "empty
+ * floors", which is stored in "f_info[FEAT_FLOOR]". Sometimes, special
+ * lighting effects may cause this picture to be modified.
+ *
+ * Note that "invisible traps" are always displayes exactly like "empty
+ * floors", which prevents various forms of "cheating", with no loss of
+ * efficiency. There are still a few ways to "guess" where traps may be
+ * located, for example, objects will never fall into a grid containing
+ * an invisible trap. XXX XXX
+ *
+ * To determine if a "boring" grid should be displayed, we simply check to
+ * see if it is either memorized ("CAVE_MARK"), or currently "see-able" by
+ * the player ("CAVE_SEEN"). Note that "CAVE_SEEN" is now maintained by the
+ * "update_view()" function.
+ *
+ * Note the "special lighting effects" which can be activated for "boring"
+ * grids using the "view_special_lite" option, causing certain such grids
+ * to be displayed using special colors. If the grid is "see-able" by
+ * the player, we will use the normal (except that, if the "view_yellow_lite"
+ * option is set, and the grid is *only* "see-able" because of the player's
+ * torch, then we will use "yellow"), else if the player is "blind", we will
+ * use greyscale, else if the grid is not "illuminated", we will use "dark
+ * gray", if the "view_bright_lite" option is set, we will use "darker" colour
+ * else we will use the normal colour.
+ *
+ *
+ * Some comments on the "terrain" layer (non-boring grids)...
+ *
+ * Note the use of the "mimic" field in the "terrain feature" processing,
+ * which allows any feature to "pretend" to be another feature. This is
+ * used to "hide" secret doors, and to make all "doors" appear the same,
+ * and all "walls" appear the same, and "hidden" treasure stay hidden.
+ * Note that it is possible to use this field to make a feature "look"
+ * like a floor, but the "view_special_lite" flag only affects actual
+ * "boring" grids.
+ *
+ * Since "interesting" grids are always memorized as soon as they become
+ * "see-able" by the player ("CAVE_SEEN"), such a grid only needs to be
+ * displayed if it is memorized ("CAVE_MARK"). Most "interesting" grids
+ * are in fact non-memorized, non-see-able, wall grids, so the fact that
+ * we do not have to check the "CAVE_SEEN" flag adds some efficiency, at
+ * the cost of *forcing* the memorization of all "interesting" grids when
+ * they are first seen. Since the "CAVE_SEEN" flag is now maintained by
+ * the "update_view()" function, this efficiency is not as significant as
+ * it was in previous versions, and could perhaps be removed.
+ * (so I removed this to simplify the terrain feature handling -- pelpel)
+ *
+ * Note the "special lighting effects" which can be activated for "wall"
+ * grids using the "view_granite_lite" option, causing certain such grids
+ * to be displayed using special colors.
+ * If the grid is "see-able" by the player, we will use the normal colour
+ * else if the player is "blind", we will use grey scale, else if the
+ * "view_bright_lite" option is set, we will use reduced colour, else we
+ * will use the normal one.
+ *
+ * Note that "wall" grids are more complicated than "boring" grids, due to
+ * the fact that "CAVE_GLOW" for a "wall" grid means that the grid *might*
+ * be glowing, depending on where the player is standing in relation to the
+ * wall. In particular, the wall of an illuminated room should look just
+ * like any other (dark) wall unless the player is actually inside the room.
+ *
+ * Thus, we do not support as many visual special effects for "wall" grids
+ * as we do for "boring" grids, since many of them would give the player
+ * information about the "CAVE_GLOW" flag of the wall grid, in particular,
+ * it would allow the player to notice the walls of illuminated rooms from
+ * a dark hallway that happened to run beside the room.
+ *
+ *
+ * Some comments on the "object" layer...
+ *
+ * Currently, we do nothing with multi-hued objects, because there are
+ * not any. If there were, they would have to set "shimmer_objects"
+ * when they were created, and then new "shimmer" code in "dungeon.c"
+ * would have to be created handle the "shimmer" effect, and the code
+ * in "cave.c" would have to be updated to create the shimmer effect.
+ * This did not seem worth the effort. XXX XXX
+ *
+ *
+ * Some comments on the "monster"/"player" layer...
+ *
+ * Note that monsters can have some "special" flags, including "ATTR_MULTI",
+ * which means their color changes, and "ATTR_CLEAR", which means they take
+ * the color of whatever is under them, and "CHAR_CLEAR", which means that
+ * they take the symbol of whatever is under them. Technically, the flag
+ * "CHAR_MULTI" is supposed to indicate that a monster looks strange when
+ * examined, but this flag is currently ignored. All of these flags are
+ * ignored if the "avoid_other" option is set, since checking for these
+ * conditions is expensive (and annoying) on some systems.
+ *
+ * Normally, players could be handled just like monsters, except that the
+ * concept of the "torch lite" of others player would add complications.
+ * For efficiency, however, we handle the (only) player first, since the
+ * "player" symbol always "pre-empts" any other facts about the grid.
+ *
+ * The "hidden_player" efficiency option, which only makes sense with a
+ * single player, allows the player symbol to be hidden while running.
+ */
+
+/*
+ * Alternative colours for unseen grids
+ *
+ * Reduced colours - remembered interesting grids and perma-lit floors
+ * B&W - currently only used by blindness effect
+ */
+
+/* Colour */
+static byte dark_attrs[16] =
+{
+ TERM_DARK, TERM_L_WHITE, TERM_L_DARK, TERM_ORANGE,
+ TERM_RED, TERM_GREEN, TERM_BLUE, TERM_UMBER,
+ TERM_L_DARK, TERM_SLATE, TERM_VIOLET, TERM_YELLOW,
+ TERM_RED, TERM_GREEN, TERM_BLUE, TERM_UMBER
+};
+
+/* B&W */
+static byte darker_attrs[16] =
+{
+ TERM_DARK, TERM_L_WHITE, TERM_L_DARK, TERM_SLATE,
+ TERM_L_DARK, TERM_L_DARK, TERM_L_DARK, TERM_L_DARK,
+ TERM_L_DARK, TERM_SLATE, TERM_L_DARK, TERM_SLATE,
+ TERM_SLATE, TERM_SLATE, TERM_SLATE, TERM_SLATE
+};
+
+
+void map_info(int y, int x, byte *ap, char *cp, byte *tap, char *tcp,
+ byte *eap, char *ecp)
+{
+ cave_type *c_ptr;
+
+ feature_type *f_ptr;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ u16b info;
+
+ s16b t_idx;
+
+ byte feat;
+
+ byte a;
+
+ byte c;
+
+ /*
+ * This means that a port supports graphics overlay as well as lighting
+ * effects. See the step 3 below for the detailed information about
+ * lighting. Basically, it requires "darker" tiles for those terrain
+ * features with SUPPORT_LIGHT flag set, and they must be arranged
+ * this way:
+ * col col+1 col+2
+ * row base darker brighter
+ */
+ bool_ graf_new = ((graphics_mode == GRAPHICS_ISO) ||
+ (graphics_mode == GRAPHICS_NEW));
+
+ /*
+ * I never understand why some coders like shimmering so much.
+ * It just serves to hurt my eyes, IMHO. If one feels like to show off,
+ * go for better graphics support... Anyway this means a port allows
+ * changing attr independently from its char -- pelpel
+ */
+ bool_ attr_mutable = (!use_graphics ||
+ (graphics_mode == GRAPHICS_IBM));
+
+
+ /**** Preparation ****/
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+
+ /* Cache some frequently used values */
+
+ /* Grid info */
+ info = c_ptr->info;
+
+ /* Feature code */
+ feat = c_ptr->feat;
+
+ /* Apply "mimic" field */
+ if (c_ptr->mimic)
+ {
+ feat = c_ptr->mimic;
+ }
+ else
+ {
+ feat = f_info[feat].mimic;
+ }
+
+ /* Access floor */
+ f_ptr = &f_info[feat];
+
+
+ /* Reset attr/char */
+ *eap = 0;
+ *ecp = 0;
+
+
+ /**** Layer 1 -- Terrain feature ****/
+
+ /* Only memorised or visible grids are displayed */
+ if (info & (CAVE_MARK | CAVE_SEEN))
+ {
+ /**** Step 1 -- Retrieve base attr/char ****/
+
+ /* 'Sane' terrain features */
+ if (feat != FEAT_SHOP)
+ {
+ /* Normal char */
+ c = f_ptr->x_char;
+
+ /* Normal attr */
+ a = f_ptr->x_attr;
+ }
+
+ /* Mega-Hack 1 -- Building don't conform to f_info */
+ else
+ {
+ c = st_info[c_ptr->special].x_char;
+ a = st_info[c_ptr->special].x_attr;
+ }
+
+ /* Mega-Hack 2 -- stair to dungeon branch are purple */
+ if (c_ptr->special && attr_mutable &&
+ ((feat == FEAT_MORE) || (feat == FEAT_LESS)))
+ {
+ a = TERM_VIOLET;
+ }
+
+ /* Mega-Hack 3 -- Traps don't have f_info entries either */
+ if ((info & (CAVE_TRDT)) && (feat != FEAT_ILLUS_WALL))
+ {
+ /* Trap index */
+ t_idx = c_ptr->t_idx;
+
+ if (use_graphics &&
+ (t_info[t_idx].g_attr != 0) &&
+ (t_info[t_idx].g_char != 0))
+ {
+
+ if (graf_new)
+ {
+ *eap = t_info[t_idx].g_attr;
+ *ecp = t_info[t_idx].g_char;
+ }
+ else
+ {
+ a = t_info[t_idx].g_attr;
+ c = t_info[t_idx].g_char;
+ }
+
+ }
+ else
+ {
+ /*
+ * If trap is set on a floor grid that is not
+ * one of "interesting" features, use a special
+ * symbol to display it. Check for doors is no longer
+ * necessary because they have REMEMBER flag now.
+ *
+ * Cave macros cannot be used safely here, because of
+ * c_ptr->mimic XXX XXX
+ */
+ if (!attr_mutable)
+ {
+ a = f_info[FEAT_TRAP].x_attr;
+ c = f_info[FEAT_TRAP].x_char;
+ }
+ else
+ {
+ if ((f_ptr->flags1 & (FF1_FLOOR | FF1_REMEMBER)) == FF1_FLOOR)
+ {
+ c = f_info[FEAT_TRAP].x_char;
+ }
+
+ /* Add attr XXX XXX XXX */
+ a = t_info[t_idx].color;
+
+ /* Get a new color with a strange formula :) XXX XXX XXX */
+ if (t_info[t_idx].flags & FTRAP_CHANGE)
+ {
+ s32b tmp;
+
+ tmp = dun_level + dungeon_type + feat;
+
+ a = tmp % 16;
+ }
+ }
+ }
+ }
+
+
+ /**** Step 2 -- Apply special random effects ****/
+ if (!avoid_other && !avoid_shimmer && attr_mutable)
+ {
+ /* Special terrain effect */
+ if (c_ptr->effect)
+ {
+ a = spell_color(effects[c_ptr->effect].type);
+ }
+
+ /* Multi-hued attr */
+ else if (f_ptr->flags1 & FF1_ATTR_MULTI)
+ {
+ a = f_ptr->shimmer[rand_int(7)];
+ }
+ }
+
+
+ /*
+ * Step 3
+ *
+ * Special lighting effects, if specified and applicable
+ * This will never happen for
+ * - any grids in the overhead map
+ * - traps
+ * - (graphics modes) terrain features without corresponding
+ * "darker" tiles.
+ *
+ * Note the use of f_ptr->flags1 to avoid problems with
+ * c_ptr->mimic.
+ */
+
+ /* view_special_lite: lighting effects for boring features */
+ if (view_special_lite &&
+ ((f_ptr->flags1 & (FF1_FLOOR | FF1_REMEMBER)) == FF1_FLOOR))
+ {
+ if (!p_ptr->wild_mode && !(info & (CAVE_TRDT)) &&
+ (attr_mutable || (graf_new && feat_supports_lighting(feat))))
+ {
+ /* Handle "seen" grids */
+ if (info & (CAVE_SEEN))
+ {
+ /* Only lit by "torch" light */
+ if (view_yellow_lite && !(info & (CAVE_GLOW)))
+ {
+ if (graf_new)
+ {
+ /* Use a brightly lit tile */
+ c += 2;
+ }
+ else
+ {
+ /* Use "yellow" */
+ a = TERM_YELLOW;
+ }
+ }
+ }
+
+ /* Handle "blind" */
+ else if (p_ptr->blind)
+ {
+ if (graf_new)
+ {
+ /* Use a dark tile */
+ c++;
+ }
+ else
+ {
+ /* Use darker colour */
+ a = darker_attrs[a & 0xF];
+ }
+ }
+
+ /* Handle "dark" grids */
+ else if (!(info & (CAVE_GLOW)))
+ {
+ if (graf_new)
+ {
+ /* Use a dark tile */
+ c++;
+ }
+ else
+ {
+ /* Use darkest colour */
+ a = TERM_L_DARK;
+ }
+ }
+
+ /* "Out-of-sight" glowing grids -- handle "view_bright_lite" */
+ else if (view_bright_lite)
+ {
+ if (graf_new)
+ {
+ /* Use a dark tile */
+ c++;
+ }
+ else
+ {
+ /* Use darker colour */
+ a = dark_attrs[a & 0xF];
+ }
+ }
+ }
+ }
+
+ /* view_granite_lite: lighting effects for walls and doors */
+ else if (view_granite_lite &&
+ (f_ptr->flags1 & (FF1_NO_VISION | FF1_DOOR)))
+ {
+ if (!p_ptr->wild_mode && !(info & (CAVE_TRDT)) &&
+ (attr_mutable || (graf_new && feat_supports_lighting(feat))))
+ {
+ /* Handle "seen" grids */
+ if (info & (CAVE_SEEN))
+ {
+ /* Do nothing */
+ }
+
+ /* Handle "blind" */
+ else if (p_ptr->blind)
+ {
+ if (graf_new)
+ {
+ /* Use a dark tile */
+ c++;
+ }
+ else
+ {
+ /* Use darker colour */
+ a = darker_attrs[a & 0xF];
+ }
+ }
+
+ /* Handle "view_bright_lite" */
+ else if (view_bright_lite)
+ {
+ if (graf_new)
+ {
+ /* Use a dark tile */
+ c++;
+ }
+ else
+ {
+ /* Use darker colour */
+ a = dark_attrs[a & 0xF];
+ }
+ }
+
+ else
+ {
+ if (graf_new)
+ {
+ /* Use a brightly lit tile */
+ c += 2;
+ }
+ else
+ {
+ /* Use normal colour */
+ }
+ }
+ }
+ }
+ }
+
+ /* Unknown grids */
+ else
+ {
+ /* Access darkness */
+ f_ptr = &f_info[FEAT_NONE];
+
+ /* Normal attr */
+ a = f_ptr->x_attr;
+
+ /* Normal char */
+ c = f_ptr->x_char;
+ }
+
+ /*
+ * Hack -- rare random hallucination
+ * Because we cannot be sure which is outer dungeon walls,
+ * the check for 'feat' has been removed
+ */
+ if (p_ptr->image && (rand_int(256) == 0))
+ {
+ /* Hallucinate */
+ image_random(ap, cp);
+ }
+
+ /* Save the terrain info for the transparency effects */
+ *tap = a;
+ *tcp = c;
+
+ /* Save the info */
+ *ap = a;
+ *cp = c;
+
+
+ /**** Layer 2 -- Objects ****/
+
+ if (feat != FEAT_MON_TRAP)
+ {
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Memorized objects */
+ if (o_ptr->marked)
+ {
+ /* Normal char */
+ *cp = object_char(o_ptr);
+
+ /* Normal attr */
+ *ap = object_attr(o_ptr);
+
+ /* Multi-hued attr */
+ if (!avoid_other && attr_mutable &&
+ (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI))
+ {
+ *ap = get_shimmer_color();
+ }
+
+ /* Hack -- hallucination */
+ if (p_ptr->image) image_object(ap, cp);
+
+ /* Done */
+ break;
+ }
+ }
+ }
+
+
+ /**** Layer 3 -- Handle monsters ****/
+
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ if (r_ptr->flags9 & RF9_MIMIC)
+ {
+ object_type *o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[m_ptr->hold_o_idx];
+
+ /* Memorized objects */
+ if (o_ptr->marked)
+ {
+ /* Normal char */
+ *cp = object_char(o_ptr);
+
+ /* Normal attr */
+ *ap = object_attr(o_ptr);
+
+ /* Multi-hued attr */
+ if (!avoid_other && attr_mutable &&
+ (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI))
+ {
+ *ap = get_shimmer_color();
+ }
+
+ /* Hack -- hallucination */
+ if (p_ptr->image) image_object(ap, cp);
+ }
+ }
+ else
+ {
+ /* Visible monster */
+ if (m_ptr->ml)
+ {
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Reset attr/char */
+ *eap = 0;
+ *ecp = 0;
+
+ if (use_graphics)
+ {
+
+ if (graf_new)
+ {
+ monster_ego *re_ptr = &re_info[m_ptr->ego];
+
+ /* Desired attr */
+ *eap = re_ptr->g_attr;
+
+ /* Desired char */
+ *ecp = re_ptr->g_char;
+ }
+
+ /* Use base monster */
+ r_ptr = &r_info[m_ptr->r_idx];
+ }
+
+ /* Desired attr/char */
+ c = r_ptr->x_char;
+ a = r_ptr->x_attr;
+
+ /* Ignore weird codes */
+ if (avoid_other)
+ {
+ /* Use char */
+ *cp = c;
+
+ /* Use attr */
+ *ap = a;
+ }
+
+ /* Special attr/char codes */
+ else if (!attr_mutable)
+ {
+ /* Use char */
+ *cp = c;
+
+ /* Use attr */
+ *ap = a;
+ }
+
+ /* Multi-hued monster */
+ else if (r_ptr->flags1 & (RF1_ATTR_MULTI))
+ {
+ /* Is it a shapechanger? */
+ if (r_ptr->flags2 & (RF2_SHAPECHANGER))
+ {
+ image_random(ap, cp);
+ }
+ else
+ *cp = c;
+
+ /* Multi-hued attr */
+ if (r_ptr->flags2 & (RF2_ATTR_ANY))
+ {
+ *ap = randint(15);
+ }
+ else
+ {
+ *ap = multi_hued_attr(r_ptr);
+ }
+ }
+
+ /* Normal monster (not "clear" in any way) */
+ else if (!(r_ptr->flags1 & (RF1_ATTR_CLEAR | RF1_CHAR_CLEAR)))
+ {
+ /* Use char */
+ *cp = c;
+
+ /* Use attr */
+ *ap = a;
+ }
+
+ /*
+ * Hack -- Bizarre grid under monster
+ * WAS: else if (*ap & 0x80) || (*cp & 0x80) -- pelpel
+ */
+ else if (*ap & 0x80)
+ {
+ /* Use char */
+ *cp = c;
+
+ /* Use attr */
+ *ap = a;
+ }
+
+ /* Normal */
+ else
+ {
+ /* Normal (non-clear char) monster */
+ if (!(r_ptr->flags1 & (RF1_CHAR_CLEAR)))
+ {
+ /* Normal char */
+ *cp = c;
+ }
+
+ /* Normal (non-clear attr) monster */
+ else if (!(r_ptr->flags1 & (RF1_ATTR_CLEAR)))
+ {
+ /* Normal attr */
+ *ap = a;
+ }
+ }
+
+ /* Hack -- hallucination */
+ if (p_ptr->image)
+ {
+ /* Hallucinatory monster */
+ image_monster(ap, cp);
+ }
+ }
+ }
+ }
+
+ /* Handle "player" */
+ if ((y == p_ptr->py) && (x == p_ptr->px) &&
+ (!p_ptr->invis || p_ptr->see_inv))
+ {
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+ /* Reset attr/char */
+ *eap = 0;
+ *ecp = 0;
+
+ /* Get the "player" attr */
+ if (!avoid_other && attr_mutable && (r_ptr->flags1 & RF1_ATTR_MULTI))
+ {
+ a = get_shimmer_color();
+ }
+ else
+ {
+ a = r_ptr->x_attr;
+ }
+
+ /* Get the "player" char */
+ c = r_ptr->x_char;
+
+
+ /* Mega-Hack -- Apply modifications to player graphics XXX XXX XXX */
+ switch (graphics_mode)
+ {
+ case GRAPHICS_NONE:
+ case GRAPHICS_IBM:
+ {
+ if (player_char_health)
+ {
+ int percent = p_ptr->chp * 10 / p_ptr->mhp;
+
+ if (percent < 7)
+ {
+ c = I2D(percent);
+ if (percent < 3) a = TERM_L_RED;
+ }
+ }
+
+ break;
+ }
+
+ case GRAPHICS_OLD:
+ {
+ if (player_symbols)
+ {
+ a = BMP_FIRST_PC_CLASS + p_ptr->pclass;
+ c = BMP_FIRST_PC_RACE + p_ptr->prace;
+ }
+
+ break;
+ }
+
+ case GRAPHICS_ISO:
+ case GRAPHICS_NEW:
+ {
+ if (p_ptr->pracem)
+ {
+ player_race_mod *rmp_ptr = &race_mod_info[p_ptr->pracem];
+
+ /* Desired attr */
+ *eap = rmp_ptr->g_attr;
+
+ /* Desired char */
+ *ecp = rmp_ptr->g_char;
+ }
+
+ /* +AKH 20020421 - Health dispay for graphics, too */
+ if (player_char_health && (graphics_mode == GRAPHICS_NEW))
+ {
+ int percent = p_ptr->chp * 14 / p_ptr->mhp;
+
+ if (percent < 10)
+ {
+ *eap = 10;
+ *ecp = 32 + 14 - percent;
+ }
+ }
+
+ break;
+ }
+
+ }
+
+ /* Save the info */
+ *ap = a;
+ *cp = c;
+
+ }
+}
+
+
+/*
+ * Special version of map_info, for use by cmovie and HTML converter
+ * to obtain pure-ASCII image of dungeon map
+ */
+void map_info_default(int y, int x, byte *ap, char *cp)
+{
+ cave_type *c_ptr;
+
+ feature_type *f_ptr;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ u16b info;
+
+ s16b t_idx;
+
+ byte feat;
+
+ byte a;
+
+ byte c;
+
+ bool_ use_graphics_hack = use_graphics;
+ byte graphics_mode_hack = graphics_mode;
+
+
+ /* Temporarily disable graphics mode -- for some random effects XXX */
+ use_graphics = FALSE;
+ graphics_mode = GRAPHICS_NONE;
+
+ /**** Preparation ****/
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+
+ /* Cache some frequently used values */
+
+ /* Grid info */
+ info = c_ptr->info;
+
+ /* Feature code */
+ feat = c_ptr->feat;
+
+ /* Apply "mimic" field */
+ if (c_ptr->mimic)
+ {
+ feat = c_ptr->mimic;
+ }
+ else
+ {
+ feat = f_info[feat].mimic;
+ }
+
+ /* Access floor */
+ f_ptr = &f_info[feat];
+
+
+ /**** Layer 1 -- Terrain feature ****/
+
+ /* Only memorised or visible grids are displayed */
+ if (info & (CAVE_MARK | CAVE_SEEN))
+ {
+ /**** Step 1 -- Retrieve base attr/char ****/
+
+ /* 'Sane' terrain features */
+ if (feat != FEAT_SHOP)
+ {
+ /* Default char */
+ c = f_ptr->d_char;
+
+ /* Default attr */
+ a = f_ptr->d_attr;
+ }
+
+ /* Mega-Hack 1 -- Building don't conform to f_info */
+ else
+ {
+ c = st_info[c_ptr->special].d_char;
+ a = st_info[c_ptr->special].d_attr;
+ }
+
+ /* Mega-Hack 2 -- stair to dungeon branch are purple */
+ if (c_ptr->special &&
+ ((feat == FEAT_MORE) || (feat == FEAT_LESS)))
+ {
+ a = TERM_VIOLET;
+ }
+
+ /* Mega-Hack 3 -- Traps don't have f_info entries either */
+ if ((info & (CAVE_TRDT)) && (feat != FEAT_ILLUS_WALL))
+ {
+ /* Trap index */
+ t_idx = c_ptr->t_idx;
+
+ /*
+ * If trap is set on a floor grid that is not
+ * one of "interesting" features, use a special
+ * symbol to display it. Check for doors is no longer
+ * necessary because they have REMEMBER flag now.
+ *
+ * Cave macros cannot be used safely here, because of
+ * c_ptr->mimic XXX XXX
+ */
+ if ((f_ptr->flags1 & (FF1_FLOOR | FF1_REMEMBER)) == FF1_FLOOR)
+ {
+ c = f_info[FEAT_TRAP].d_char;
+ }
+
+ /* Add attr */
+ a = t_info[t_idx].color;
+
+ /* Get a new color with a strange formula :) */
+ if (t_info[t_idx].flags & FTRAP_CHANGE)
+ {
+ s32b tmp;
+
+ tmp = dun_level + dungeon_type + feat;
+
+ a = tmp % 16;
+ }
+ }
+
+
+ /**** Step 2 -- Apply special random effects ****/
+ if (!avoid_other)
+ {
+ /* Special terrain effect */
+ if (c_ptr->effect)
+ {
+ a = spell_color(effects[c_ptr->effect].type);
+ }
+
+ /* Multi-hued attr */
+ else if (f_ptr->flags1 & FF1_ATTR_MULTI)
+ {
+ a = f_ptr->shimmer[rand_int(7)];
+ }
+ }
+
+
+ /*
+ * Step 3
+ *
+ * Special lighting effects, if specified and applicable
+ * This will never happen for
+ * - any grids in the overhead map
+ * - traps
+ * - (graphics modes) terrain features without corresponding
+ * "darker" tiles.
+ *
+ * All the if's here are flag checks, so changed order shouldn't
+ * affect performance a lot, I hope...
+ */
+
+ /* view_special_lite: lighting effects for boring features */
+ if (view_special_lite &&
+ ((f_ptr->flags1 & (FF1_FLOOR | FF1_REMEMBER)) == FF1_FLOOR))
+ {
+ if (!p_ptr->wild_mode && !(info & (CAVE_TRDT)))
+ {
+ /* Handle "seen" grids */
+ if (info & (CAVE_SEEN))
+ {
+ /* Only lit by "torch" light */
+ if (view_yellow_lite && !(info & (CAVE_GLOW)))
+ {
+ /* Use "yellow" */
+ a = TERM_YELLOW;
+ }
+ }
+
+ /* Handle "blind" */
+ else if (p_ptr->blind)
+ {
+ /* Use darker colour */
+ a = darker_attrs[a & 0xF];
+ }
+
+ /* Handle "dark" grids */
+ else if (!(info & (CAVE_GLOW)))
+ {
+ /* Use darkest colour */
+ a = TERM_L_DARK;
+ }
+
+ /* "Out-of-sight" glowing grids -- handle "view_bright_lite" */
+ else if (view_bright_lite)
+ {
+ /* Use darker colour */
+ a = dark_attrs[a & 0xF];
+ }
+ }
+ }
+
+ /* view_granite_lite: lighting effects for walls and doors */
+ else if (view_granite_lite &&
+ (f_ptr->flags1 & (FF1_NO_VISION | FF1_DOOR)))
+ {
+ if (!p_ptr->wild_mode && !(info & (CAVE_TRDT)))
+ {
+ /* Handle "seen" grids */
+ if (info & (CAVE_SEEN))
+ {
+ /* Do nothing */
+ }
+
+ /* Handle "blind" */
+ else if (p_ptr->blind)
+ {
+ /* Use darker colour */
+ a = darker_attrs[a & 0xF];
+ }
+
+ /* Handle "view_bright_lite" */
+ else if (view_bright_lite)
+ {
+ /* Use darker colour */
+ a = dark_attrs[a & 0xF];
+ }
+ }
+ }
+ }
+
+ /* Unknown grids */
+ else
+ {
+ /* Access darkness */
+ f_ptr = &f_info[FEAT_NONE];
+
+ /* Default attr */
+ a = f_ptr->d_attr;
+
+ /* Default char */
+ c = f_ptr->d_char;
+ }
+
+ /*
+ * Hack -- rare random hallucination
+ * Because we cannot be sure which is outer dungeon walls,
+ * the check for 'feat' has been removed
+ */
+ if (p_ptr->image && (rand_int(256) == 0))
+ {
+ /* Hallucinate */
+ image_random(ap, cp);
+ }
+
+ /* Save the info */
+ *ap = a;
+ *cp = c;
+
+
+ /**** Layer 2 -- Objects ****/
+
+ if (feat != FEAT_MON_TRAP)
+ {
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Memorized objects */
+ if (o_ptr->marked)
+ {
+ /* Normal char */
+ *cp = object_char_default(o_ptr);
+
+ /* Normal attr */
+ *ap = object_attr_default(o_ptr);
+
+ /* Multi-hued attr */
+ if (!avoid_other &&
+ (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI))
+ {
+ *ap = get_shimmer_color();
+ }
+
+ /* Hack -- hallucination */
+ if (p_ptr->image) image_object(ap, cp);
+
+ /* Done */
+ break;
+ }
+ }
+ }
+
+
+ /**** Layer 3 -- Handle monsters ****/
+
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ if (r_ptr->flags9 & RF9_MIMIC)
+ {
+ object_type *o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[m_ptr->hold_o_idx];
+
+ /* Memorized objects */
+ if (o_ptr->marked)
+ {
+ /* Normal char */
+ *cp = object_char_default(o_ptr);
+
+ /* Normal attr */
+ *ap = object_attr_default(o_ptr);
+
+ /* Multi-hued attr */
+ if (!avoid_other && !use_graphics &&
+ (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI))
+ {
+ *ap = get_shimmer_color();
+ }
+
+ /* Hack -- hallucination */
+ if (p_ptr->image) image_object(ap, cp);
+ }
+ }
+ else
+ {
+ /* Visible monster */
+ if (m_ptr->ml)
+ {
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Default attr/char */
+ c = r_ptr->d_char;
+ a = r_ptr->d_attr;
+
+ /* Ignore weird codes */
+ if (avoid_other)
+ {
+ /* Use char */
+ *cp = c;
+
+ /* Use attr */
+ *ap = a;
+ }
+
+ /* Multi-hued monster */
+ else if (r_ptr->flags1 & (RF1_ATTR_MULTI))
+ {
+ /* Is it a shapechanger? */
+ if (r_ptr->flags2 & (RF2_SHAPECHANGER))
+ {
+ image_random(ap, cp);
+ }
+ else
+ *cp = c;
+
+ /* Multi-hued attr */
+ if (r_ptr->flags2 & (RF2_ATTR_ANY))
+ {
+ *ap = randint(15);
+ }
+ else
+ {
+ *ap = multi_hued_attr(r_ptr);
+ }
+ }
+
+ /* Normal monster (not "clear" in any way) */
+ else if (!(r_ptr->flags1 & (RF1_ATTR_CLEAR | RF1_CHAR_CLEAR)))
+ {
+ /* Use char */
+ *cp = c;
+
+ /* Use attr */
+ *ap = a;
+ }
+
+ /* Hack -- Bizarre grid under monster */
+ else if ((*ap & 0x80) || (*cp & 0x80))
+ {
+ /* Use char */
+ *cp = c;
+
+ /* Use attr */
+ *ap = a;
+ }
+
+ /* Normal */
+ else
+ {
+ /* Normal (non-clear char) monster */
+ if (!(r_ptr->flags1 & (RF1_CHAR_CLEAR)))
+ {
+ /* Normal char */
+ *cp = c;
+ }
+
+ /* Normal (non-clear attr) monster */
+ else if (!(r_ptr->flags1 & (RF1_ATTR_CLEAR)))
+ {
+ /* Normal attr */
+ *ap = a;
+ }
+ }
+
+ /* Hack -- hallucination */
+ if (p_ptr->image)
+ {
+ /* Hallucinatory monster */
+ image_monster(ap, cp);
+ }
+ }
+ }
+ }
+
+
+ /* Handle "player" */
+ if ((y == p_ptr->py) && (x == p_ptr->px) &&
+ (!p_ptr->invis ||
+ (p_ptr->invis && p_ptr->see_inv)))
+ {
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+ /* Get the "player" attr */
+ if (!avoid_other && (r_ptr->flags1 & RF1_ATTR_MULTI))
+ {
+ a = get_shimmer_color();
+ }
+ else
+ {
+ a = r_ptr->d_attr;
+ }
+
+ /* Get the "player" char */
+ c = r_ptr->d_char;
+
+ /* Save the info */
+ *ap = a;
+ *cp = c;
+
+ }
+
+ /* XXX Restore the graphics mode */
+ use_graphics = use_graphics_hack;
+ graphics_mode = graphics_mode_hack;
+}
+
+
+/*
+ * Calculate panel colum of a location in the map
+ */
+static int panel_col_of(int col)
+{
+ col -= panel_col_min;
+ if (use_bigtile) col *= 2;
+ return col + COL_MAP;
+}
+
+
+
+/*
+ * Moves the cursor to a given MAP (y,x) location
+ */
+void move_cursor_relative(int row, int col)
+{
+ /* Real co-ords convert to screen positions */
+ row -= panel_row_prt;
+
+ /* Go there */
+ Term_gotoxy(panel_col_of(col), row);
+}
+
+
+
+/*
+ * Place an attr/char pair at the given map coordinate, if legal.
+ */
+void print_rel(char c, byte a, int y, int x)
+{
+ /* Paranoia -- Only do "legal" locations */
+ if (!panel_contains(y, x)) return;
+
+ /* Draw the char using the attr */
+ Term_draw(panel_col_of(x), y - panel_row_prt, a, c);
+
+ if (use_bigtile)
+ {
+ char c2;
+ byte a2;
+
+ if (a & 0x80)
+ {
+ a2 = 255;
+ c2 = 255;
+ }
+ else
+ {
+ a2 = TERM_WHITE;
+ c2 = ' ';
+ }
+ Term_draw(panel_col_of(x) + 1, y - panel_row_prt, a2, c2);
+ }
+}
+
+
+
+
+
+/*
+ * Memorize interesting viewable object/features in the given grid
+ *
+ * This function should only be called on "legal" grids.
+ *
+ * This function will memorize the object and/or feature in the given
+ * grid, if they are (1) viewable and (2) interesting. Note that all
+ * objects are interesting, all terrain features except floors (and
+ * invisible traps) are interesting, and floors (and invisible traps)
+ * are interesting sometimes (depending on various options involving
+ * the illumination of floor grids).
+ *
+ * The automatic memorization of all objects and non-floor terrain
+ * features as soon as they are displayed allows incredible amounts
+ * of optimization in various places, especially "map_info()".
+ *
+ * Note that the memorization of objects is completely separate from
+ * the memorization of terrain features, preventing annoying floor
+ * memorization when a detected object is picked up from a dark floor,
+ * and object memorization when an object is dropped into a floor grid
+ * which is memorized but out-of-sight.
+ *
+ * This function should be called every time the "memorization" of
+ * a grid (or the object in a grid) is called into question, such
+ * as when an object is created in a grid, when a terrain feature
+ * "changes" from "floor" to "non-floor", when any grid becomes
+ * "illuminated" or "viewable", and when a "floor" grid becomes
+ * "torch-lit".
+ *
+ * Note the relatively efficient use of this function by the various
+ * "update_view()" and "update_lite()" calls, to allow objects and
+ * terrain features to be memorized (and drawn) whenever they become
+ * viewable or illuminated in any way, but not when they "maintain"
+ * or "lose" their previous viewability or illumination.
+ *
+ * Note the butchered "internal" version of "player_can_see_bold()",
+ * optimized primarily for the most common cases, that is, for the
+ * non-marked floor grids.
+ */
+void note_spot(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ u16b info = c_ptr->info;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+
+ /* Require "seen" flag */
+ if (!(info & (CAVE_SEEN))) return;
+
+
+ /* Hack -- memorize objects */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Memorize objects */
+ o_ptr->marked = TRUE;
+ }
+
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ if (r_ptr->flags9 & RF9_MIMIC)
+ {
+ object_type *o_ptr = &o_list[m_ptr->hold_o_idx];
+
+ o_ptr->marked = TRUE;
+ }
+ }
+
+
+ /* Hack -- memorize grids */
+ if (!(info & (CAVE_MARK)))
+ {
+ /* Memorise some "boring" grids */
+ if (cave_plain_floor_grid(c_ptr))
+ {
+ /* Option -- memorise certain floors */
+ if ((info & (CAVE_TRDT)) ||
+ ((info & (CAVE_GLOW)) && view_perma_grids ) ||
+ view_torch_grids)
+ {
+ /* Memorize */
+ c_ptr->info |= (CAVE_MARK);
+ }
+ }
+
+ /* Memorise all "interesting" grids */
+ else
+ {
+ /* Memorize */
+ c_ptr->info |= (CAVE_MARK);
+ }
+ }
+}
+
+
+/*
+ * Redraw (on the screen) a given MAP location
+ *
+ * This function should only be called on "legal" grids
+ */
+void lite_spot(int y, int x)
+{
+ byte a, a2;
+ byte c, c2;
+
+ byte ta;
+ char tc;
+
+ byte ea;
+ char ec;
+
+
+ /* Redraw if on screen */
+ if (panel_contains(y, x))
+ {
+ /* Examine the grid */
+ map_info(y, x, &a, (char*)&c, &ta, &tc, &ea, &ec);
+
+ /* Hack -- Queue it */
+ Term_queue_char(panel_col_of(x), y - panel_row_prt, a, c, ta, tc, ea, ec);
+ if (use_bigtile)
+ {
+ if (a & 0x80)
+ {
+ a2 = 255;
+ c2 = 255;
+ }
+ else
+ {
+ a2 = TERM_WHITE;
+ c2 = ' ';
+ }
+ Term_queue_char(panel_col_of(x) + 1, y - panel_row_prt, a2, c2, 0, 0, 0, 0);
+ }
+
+ }
+}
+
+
+
+
+/*
+ * Prints the map of the dungeon
+ *
+ * Note that, for efficiency, we contain an "optimized" version
+ * of both "lite_spot()" and "print_rel()", and that we use the
+ * "lite_spot()" function to display the player grid, if needed.
+ */
+void prt_map(void)
+{
+ int x, y;
+
+ int v;
+
+ /* Access the cursor state */
+ (void)Term_get_cursor(&v);
+
+ /* Hide the cursor */
+ (void)Term_set_cursor(0);
+
+ /* Dump the map */
+ for (y = panel_row_min; y <= panel_row_max; y++)
+ {
+ /* Scan the columns of row "y" */
+ for (x = panel_col_min; x <= panel_col_max; x++)
+ {
+ byte a, a2;
+ char c, c2;
+
+ byte ta;
+ char tc;
+ byte ea;
+ char ec;
+
+ /* Determine what is there */
+ map_info(y, x, &a, &c, &ta, &tc, &ea, &ec);
+
+ /* Efficiency -- Redraw that grid of the map */
+ Term_queue_char(panel_col_of(x), y - panel_row_prt, a, c, ta, tc, ea, ec);
+ if (use_bigtile)
+ {
+ if (a & 0x80)
+ {
+ a2 = 255;
+ c2 = 255;
+ }
+ else
+ {
+ a2 = TERM_WHITE;
+ c2 = ' ';
+ }
+ Term_queue_char(panel_col_of(x) + 1, y - panel_row_prt, a2, c2, 0, 0, 0, 0);
+ }
+ }
+ }
+
+ /* Display player */
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Restore the cursor */
+ (void)Term_set_cursor(v);
+}
+
+
+
+
+
+/*
+ * Display highest priority object in the RATIO by RATIO area
+ */
+
+/*
+ * Display the entire map
+ */
+#define MAP_HGT (MAX_HGT / RATIO)
+#define MAP_WID (MAX_WID / RATIO)
+
+/*
+ * Hack -- priority array (see below)
+ *
+ * Note that all "walls" always look like "secret doors" (see "map_info()").
+ */
+static byte priority_table[][2] =
+{
+ /* Dark */
+ { FEAT_NONE, 2 },
+
+ /* Floors */
+ { FEAT_FLOOR, 5 },
+
+ /* Walls */
+ { FEAT_SECRET, 10 },
+
+ /* Quartz */
+ { FEAT_QUARTZ, 11 },
+
+ /* Magma */
+ { FEAT_MAGMA, 12 },
+
+ /* Rubble */
+ { FEAT_RUBBLE, 13 },
+
+ /* Sandwall */
+ { FEAT_SANDWALL, 14 },
+
+ /* Open doors */
+ { FEAT_OPEN, 15 },
+ { FEAT_BROKEN, 15 },
+
+ /* Closed doors */
+ { FEAT_DOOR_HEAD + 0x00, 17 },
+
+ /* Hidden gold */
+ { FEAT_QUARTZ_K, 19 },
+ { FEAT_MAGMA_K, 19 },
+ { FEAT_SANDWALL_K, 19 },
+
+ /* water, lava, & trees oh my! -KMW- */
+ { FEAT_DEEP_WATER, 20 },
+ { FEAT_SHAL_WATER, 20 },
+ { FEAT_DEEP_LAVA, 20 },
+ { FEAT_SHAL_LAVA, 20 },
+ { FEAT_DIRT, 20 },
+ { FEAT_GRASS, 20 },
+ { FEAT_DARK_PIT, 20 },
+ { FEAT_TREES, 20 },
+ { FEAT_MOUNTAIN, 20 },
+ { FEAT_ICE, 20},
+ { FEAT_SAND, 20},
+ { FEAT_DEAD_TREE, 20},
+ { FEAT_ASH, 20},
+ { FEAT_MUD, 20},
+
+ /* Fountain */
+ { FEAT_FOUNTAIN, 22 },
+ { FEAT_EMPTY_FOUNTAIN, 22 },
+
+ /* Stairs */
+ { FEAT_LESS, 25 },
+ { FEAT_MORE, 25 },
+
+ /* Stairs */
+ { FEAT_WAY_LESS, 25 },
+ { FEAT_WAY_MORE, 25 },
+
+ { FEAT_SHAFT_UP, 25 },
+ { FEAT_SHAFT_DOWN, 25 },
+
+ /* End */
+ { 0, 0 }
+};
+
+
+/*
+ * Hack -- a priority function (see below)
+ */
+static byte priority(byte a, char c)
+{
+ int i, p0, p1;
+
+ feature_type *f_ptr;
+
+ /* Scan the table */
+ for (i = 0; TRUE; i++)
+ {
+ /* Priority level */
+ p1 = priority_table[i][1];
+
+ /* End of table */
+ if (!p1) break;
+
+ /* Feature index */
+ p0 = priority_table[i][0];
+
+ /* Access the feature */
+ f_ptr = &f_info[p0];
+
+ /* Check character and attribute, accept matches */
+ if ((f_ptr->x_char == c) && (f_ptr->x_attr == a)) return (p1);
+ }
+
+ /* Default */
+ return (20);
+}
+
+
+/*
+ * Display a "small-scale" map of the dungeon in the active Term
+ *
+ * Note that the "map_info()" function must return fully colorized
+ * data or this function will not work correctly.
+ *
+ * Note that this function must "disable" the special lighting
+ * effects so that the "priority" function will work.
+ *
+ * Note the use of a specialized "priority" function to allow this
+ * function to work with any graphic attr/char mappings, and the
+ * attempts to optimize this function where possible.
+ */
+void display_map(int *cy, int *cx)
+{
+ int i, j, x, y;
+
+ byte ta;
+ char tc;
+
+ byte tp;
+
+ byte **ma;
+ char **mc;
+
+ byte **mp;
+
+ bool_ old_view_special_lite;
+ bool_ old_view_granite_lite;
+
+ int hgt, wid, yrat, xrat, yfactor, xfactor;
+
+
+ /* Obtain current size of the Angband window */
+ Term_get_size(&wid, &hgt);
+
+ /* Use two characters as one tile in Bigtile mode */
+ if (use_bigtile) wid /= 2;
+
+ /*
+ * Calculate the size of the dungeon map area
+ */
+ hgt -= ROW_MAP + 2;
+ wid -= COL_MAP + 1;
+
+ /* Paranoia */
+ if ((hgt < 3) || (wid < 3))
+ {
+ /* Map is too small, but place the player anyway */
+ *cy = ROW_MAP;
+ *cx = COL_MAP;
+
+ return;
+ }
+
+
+ /* Save lighting effects */
+ old_view_special_lite = view_special_lite;
+ old_view_granite_lite = view_granite_lite;
+
+ /* Disable lighting effects */
+ view_special_lite = FALSE;
+ view_granite_lite = FALSE;
+
+
+ /* Allocate temporary memory for the maps */
+ C_MAKE(ma, hgt + 2, byte *);
+ C_MAKE(mc, hgt + 2, char *);
+ C_MAKE(mp, hgt + 2, byte *);
+
+ /* Allocate each line in the maps */
+ for (i = 0; i < hgt + 2; i++)
+ {
+ C_MAKE(ma[i], wid + 2, byte);
+ C_MAKE(mc[i], wid + 2, char);
+ C_MAKE(mp[i], wid + 2, byte);
+ }
+
+ /* Clear the chars and attributes */
+ for (y = 0; y < hgt + 2; ++y)
+ {
+ for (x = 0; x < wid + 2; ++x)
+ {
+ /* Nothing here */
+ ma[y][x] = TERM_WHITE;
+ mc[y][x] = ' ';
+
+ /* No priority */
+ mp[y][x] = 0;
+ }
+ }
+
+ /* Calculate scaling factors */
+ yfactor = ((cur_hgt / hgt < 4) && (cur_hgt > hgt)) ? 10 : 1;
+ xfactor = ((cur_wid / wid < 4) && (cur_wid > wid)) ? 10 : 1;
+
+ yrat = (cur_hgt * yfactor + (hgt - 1)) / hgt;
+ xrat = (cur_wid * xfactor + (wid - 1)) / wid;
+
+ /* Fill in the map */
+ for (j = 0; j < cur_hgt; ++j)
+ {
+ for (i = 0; i < cur_wid; ++i)
+ {
+ /* Location */
+ y = j * yfactor / yrat + 1;
+ x = i * xfactor / xrat + 1;
+
+ /* Extract the current attr/char at that map location */
+ map_info(j, i, &ta, &tc, &ta, &tc, &ta, &tc);
+
+ /* Extract the priority of that attr/char */
+ tp = priority(ta, tc);
+
+ /* Player location has the highest priority */
+ if ((p_ptr->py == j) && (p_ptr->px == i)) tp = 255;
+
+ /* Save "best" */
+ if (mp[y][x] < tp)
+ {
+ /* Save the char */
+ mc[y][x] = tc;
+
+ /* Save the attr */
+ ma[y][x] = ta;
+
+ /* Save priority */
+ mp[y][x] = tp;
+ }
+ }
+ }
+
+
+ /* Corners */
+ y = hgt + 1;
+ x = wid + 1;
+
+ /* Draw the corners */
+ mc[0][0] = mc[0][x] = mc[y][0] = mc[y][x] = '+';
+
+ /* Draw the horizontal edges */
+ for (x = 1; x <= wid; x++) mc[0][x] = mc[y][x] = '-';
+
+ /* Draw the vertical edges */
+ for (y = 1; y <= hgt; y++) mc[y][0] = mc[y][x] = '|';
+
+
+ /* Display each map line in order */
+ for (y = 0; y < hgt + 2; ++y)
+ {
+ /* Start a new line */
+ Term_gotoxy(COL_MAP - 1, y);
+
+ /* Display the line */
+ for (x = 0; x < wid + 2; ++x)
+ {
+ ta = ma[y][x];
+ tc = mc[y][x];
+
+ /* Add the character */
+ Term_addch(ta, tc);
+
+ /* Double width tile mode requires filler */
+ if (use_bigtile)
+ {
+ byte a2;
+ char c2;
+
+ if (ta & 0x80)
+ {
+ /* Mega-Hack */
+ a2 = 255;
+ c2 = 255;
+ }
+ else
+ {
+ a2 = TERM_WHITE;
+ c2 = ' ';
+ }
+
+ Term_addch(a2, c2);
+ }
+ }
+ }
+
+ /* Player location in dungeon */
+ *cy = p_ptr->py * yfactor / yrat + ROW_MAP;
+ if (!use_bigtile)
+ {
+ *cx = p_ptr->px * xfactor / xrat + COL_MAP;
+ }
+ else
+ {
+ *cx = (p_ptr->px * xfactor / xrat + 1) * 2 - 1 + COL_MAP;
+ }
+
+ /* Free each line in the maps */
+ for (i = 0; i < hgt + 2; i++)
+ {
+ C_FREE(ma[i], wid + 2, byte);
+ C_FREE(mc[i], wid + 2, char);
+ C_FREE(mp[i], wid + 2, byte);
+ }
+
+ /* Allocate temporary memory for the maps */
+ C_FREE(ma, hgt + 2, byte *);
+ C_FREE(mc, hgt + 2, char *);
+ C_FREE(mp, hgt + 2, byte *);
+
+
+ /* Restore lighting effects */
+ view_special_lite = old_view_special_lite;
+ view_granite_lite = old_view_granite_lite;
+}
+
+
+/*
+ * Display a "small-scale" map of the dungeon for the player
+ *
+ * Currently, the "player" is displayed on the map. XXX XXX XXX
+ */
+void do_cmd_view_map(void)
+{
+ int cy, cx;
+ int wid, hgt;
+
+ /* Retrive current screen size */
+ Term_get_size(&wid, &hgt);
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ /* Note */
+ prt("Please wait...", 0, 0);
+
+ /* Flush */
+ Term_fresh();
+
+ /* Clear the screen */
+ Term_clear();
+
+ /* Display the map */
+ display_map(&cy, &cx);
+
+ /* Wait for it */
+ put_str("Hit any key to continue", hgt - 1, (wid - COL_MAP) / 2);
+
+ /* Hilite the player */
+ move_cursor(cy, cx);
+
+ /* Get any key */
+ inkey();
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+}
+
+
+
+
+
+
+/*
+ * Some comments on the dungeon related data structures and functions...
+ *
+ * Angband is primarily a dungeon exploration game, and it should come as
+ * no surprise that the internal representation of the dungeon has evolved
+ * over time in much the same way as the game itself, to provide semantic
+ * changes to the game itself, to make the code simpler to understand, and
+ * to make the executable itself faster or more efficient in various ways.
+ *
+ * There are a variety of dungeon related data structures, and associated
+ * functions, which store information about the dungeon, and provide methods
+ * by which this information can be accessed or modified.
+ *
+ * Some of this information applies to the dungeon as a whole, such as the
+ * list of unique monsters which are still alive. Some of this information
+ * only applies to the current dungeon level, such as the current depth, or
+ * the list of monsters currently inhabiting the level. And some of the
+ * information only applies to a single grid of the current dungeon level,
+ * such as whether the grid is illuminated, or whether the grid contains a
+ * monster, or whether the grid can be seen by the player. If Angband was
+ * to be turned into a multi-player game, some of the information currently
+ * associated with the dungeon should really be associated with the player,
+ * such as whether a given grid is viewable by a given player.
+ *
+ * One of the major bottlenecks in ancient versions of Angband was in the
+ * calculation of "line of sight" from the player to various grids, such
+ * as those containing monsters, using the relatively expensive "los()"
+ * function. This was such a nasty bottleneck that a lot of silly things
+ * were done to reduce the dependancy on "line of sight", for example, you
+ * could not "see" any grids in a lit room until you actually entered the
+ * room, at which point every grid in the room became "illuminated" and
+ * all of the grids in the room were "memorized" forever. Other major
+ * bottlenecks involved the determination of whether a grid was lit by the
+ * player's torch, and whether a grid blocked the player's line of sight.
+ * These bottlenecks led to the development of special new functions to
+ * optimize issues involved with "line of sight" and "torch lit grids".
+ * These optimizations led to entirely new additions to the game, such as
+ * the ability to display the player's entire field of view using different
+ * colors than were used for the "memorized" portions of the dungeon, and
+ * the ability to memorize dark floor grids, but to indicate by the way in
+ * which they are displayed that they are not actually illuminated. And
+ * of course many of them simply made the game itself faster or more fun.
+ * Also, over time, the definition of "line of sight" has been relaxed to
+ * allow the player to see a wider "field of view", which is slightly more
+ * realistic, and only slightly more expensive to maintain.
+ *
+ * Currently, a lot of the information about the dungeon is stored in ways
+ * that make it very efficient to access or modify the information, while
+ * still attempting to be relatively conservative about memory usage, even
+ * if this means that some information is stored in multiple places, or in
+ * ways which require the use of special code idioms. For example, each
+ * monster record in the monster array contains the location of the monster,
+ * and each cave grid has an index into the monster array, or a zero if no
+ * monster is in the grid. This allows the monster code to efficiently see
+ * where the monster is located, while allowing the dungeon code to quickly
+ * determine not only if a monster is present in a given grid, but also to
+ * find out which monster. The extra space used to store the information
+ * twice is inconsequential compared to the speed increase.
+ *
+ * Some of the information about the dungeon is used by functions which can
+ * constitute the "critical efficiency path" of the game itself, and so the
+ * way in which they are stored and accessed has been optimized in order to
+ * optimize the game itself. For example, the "update_view()" function was
+ * originally created to speed up the game itself (when the player was not
+ * running), but then it took on extra responsibility as the provider of the
+ * new "special effects lighting code", and became one of the most important
+ * bottlenecks when the player was running. So many rounds of optimization
+ * were performed on both the function itself, and the data structures which
+ * it uses, resulting eventually in a function which not only made the game
+ * faster than before, but which was responsible for even more calculations
+ * (including the determination of which grids are "viewable" by the player,
+ * which grids are illuminated by the player's torch, and which grids can be
+ * "seen" in some way by the player), as well as for providing the guts of
+ * the special effects lighting code, and for the efficient redisplay of any
+ * grids whose visual representation may have changed.
+ *
+ * Several pieces of information about each cave grid are stored in various
+ * two dimensional arrays, with one unit of information for each grid in the
+ * dungeon. Some of these arrays have been intentionally expanded by a small
+ * factor to make the two dimensional array accesses faster by allowing the
+ * use of shifting instead of multiplication.
+ *
+ * Several pieces of information about each cave grid are stored in the
+ * "cave_info" array, which is a special two dimensional array of bytes,
+ * one for each cave grid, each containing eight separate "flags" which
+ * describe some property of the cave grid. These flags can be checked and
+ * modified extremely quickly, especially when special idioms are used to
+ * force the compiler to keep a local register pointing to the base of the
+ * array. Special location offset macros can be used to minimize the number
+ * of computations which must be performed at runtime. Note that using a
+ * byte for each flag set may be slightly more efficient than using a larger
+ * unit, so if another flag (or two) is needed later, and it must be fast,
+ * then the two existing flags which do not have to be fast should be moved
+ * out into some other data structure and the new flags should take their
+ * place. This may require a few minor changes in the savefile code.
+ *
+ * The "CAVE_ROOM" flag is saved in the savefile and is used to determine
+ * which grids are part of "rooms", and thus which grids are affected by
+ * "illumination" spells. This flag does not have to be very fast.
+ *
+ * The "CAVE_ICKY" flag is saved in the savefile and is used to determine
+ * which grids are part of "vaults", and thus which grids cannot serve as
+ * the destinations of player teleportation. This flag does not have to
+ * be very fast.
+ *
+ * The "CAVE_MARK" flag is saved in the savefile and is used to determine
+ * which grids have been "memorized" by the player. This flag is used by
+ * the "map_info()" function to determine if a grid should be displayed.
+ * This flag is used in a few other places to determine if the player can
+ * "know" about a given grid. This flag must be very fast.
+ *
+ * The "CAVE_GLOW" flag is saved in the savefile and is used to determine
+ * which grids are "permanently illuminated". This flag is used by the
+ * "update_view()" function to help determine which viewable flags may
+ * be "seen" by the player. This flag is used by the "map_info" function
+ * to determine if a grid is only lit by the player's torch. This flag
+ * has special semantics for wall grids (see "update_view()"). This flag
+ * must be very fast.
+ *
+ * The "CAVE_WALL" flag is used to determine which grids block the player's
+ * line of sight. This flag is used by the "update_view()" function to
+ * determine which grids block line of sight, and to help determine which
+ * grids can be "seen" by the player. This flag must be very fast.
+ *
+ * The "CAVE_VIEW" flag is used to determine which grids are currently in
+ * line of sight of the player. This flag is set by (and used by) the
+ * "update_view()" function. This flag is used by any code which needs to
+ * know if the player can "view" a given grid. This flag is used by the
+ * "map_info()" function for some optional special lighting effects. The
+ * "player_has_los_bold()" macro wraps an abstraction around this flag, but
+ * certain code idioms are much more efficient. This flag is used to check
+ * if a modification to a terrain feature might affect the player's field of
+ * view. This flag is used to see if certain monsters are "visible" to the
+ * player. This flag is used to allow any monster in the player's field of
+ * view to "sense" the presence of the player. This flag must be very fast.
+ *
+ * The "CAVE_SEEN" flag is used to determine which grids are currently in
+ * line of sight of the player and also illuminated in some way. This flag
+ * is set by the "update_view()" function, using computations based on the
+ * "CAVE_VIEW" and "CAVE_WALL" and "CAVE_GLOW" flags of various grids. This
+ * flag is used by any code which needs to know if the player can "see" a
+ * given grid. This flag is used by the "map_info()" function both to see
+ * if a given "boring" grid can be seen by the player, and for some optional
+ * special lighting effects. The "player_can_see_bold()" macro wraps an
+ * abstraction around this flag, but certain code idioms are much more
+ * efficient. This flag is used to see if certain monsters are "visible" to
+ * the player. This flag is never set for a grid unless "CAVE_VIEW" is also
+ * set for the grid. Whenever the "CAVE_WALL" or "CAVE_GLOW" flag changes
+ * for a grid which has the "CAVE_VIEW" flag set, the "CAVE_SEEN" flag must
+ * be recalculated. The simplest way to do this is to call "forget_view()"
+ * and "update_view()" whenever the "CAVE_WALL" or "CAVE_GLOW" flags change
+ * for a grid which has "CAVE_VIEW" set. This flag must be very fast.
+ *
+ * The "CAVE_TEMP" flag is used for a variety of temporary purposes. This
+ * flag is used to determine if the "CAVE_SEEN" flag for a grid has changed
+ * during the "update_view()" function. This flag is used to "spread" light
+ * or darkness through a room. This flag is used by the "monster flow code".
+ * This flag must always be cleared by any code which sets it, often, this
+ * can be optimized by the use of the special "temp_g", "temp_y", "temp_x"
+ * arrays (and the special "temp_n" global). This flag must be very fast.
+ *
+ * Note that the "CAVE_MARK" flag is used for many reasons, some of which
+ * are strictly for optimization purposes. The "CAVE_MARK" flag means that
+ * even if the player cannot "see" the grid, he "knows" about the terrain in
+ * that grid. This is used to "memorize" grids when they are first "seen" by
+ * the player, and to allow certain grids to be "detected" by certain magic.
+ * Note that most grids are always memorized when they are first "seen", but
+ * "boring" grids (floor grids) are only memorized if the "view_torch_grids"
+ * option is set, or if the "view_perma_grids" option is set, and the grid
+ * in question has the "CAVE_GLOW" flag set.
+ *
+ * Objects are "memorized" in a different way, using a special "marked" flag
+ * on the object itself, which is set when an object is observed or detected.
+ * This allows objects to be "memorized" independant of the terrain features.
+ *
+ * The "update_view()" function is an extremely important function. It is
+ * called only when the player moves, significant terrain changes, or the
+ * player's blindness or torch radius changes. Note that when the player
+ * is resting, or performing any repeated actions (like digging, disarming,
+ * farming, etc), there is no need to call the "update_view()" function, so
+ * even if it was not very efficient, this would really only matter when the
+ * player was "running" through the dungeon. It sets the "CAVE_VIEW" flag
+ * on every cave grid in the player's field of view, and maintains an array
+ * of all such grids in the global "view_g" array. It also checks the torch
+ * radius of the player, and sets the "CAVE_SEEN" flag for every grid which
+ * is in the "field of view" of the player and which is also "illuminated",
+ * either by the players torch (if any) or by any permanent light source.
+ * It could use and help maintain information about multiple light sources,
+ * which would be helpful in a multi-player version of Angband.
+ *
+ * The "update_view()" function maintains the special "view_g" array, which
+ * contains exactly those grids which have the "CAVE_VIEW" flag set. This
+ * array is used by "update_view()" to (only) memorize grids which become
+ * newly "seen", and to (only) redraw grids whose "seen" value changes, which
+ * allows the use of some interesting (and very efficient) "special lighting
+ * effects". In addition, this array could be used elsewhere to quickly scan
+ * through all the grids which are in the player's field of view.
+ *
+ * Note that the "update_view()" function allows, among other things, a room
+ * to be "partially" seen as the player approaches it, with a growing cone
+ * of floor appearing as the player gets closer to the door. Also, by not
+ * turning on the "memorize perma-lit grids" option, the player will only
+ * "see" those floor grids which are actually in line of sight. And best
+ * of all, you can now activate the special lighting effects to indicate
+ * which grids are actually in the player's field of view by using dimmer
+ * colors for grids which are not in the player's field of view, and/or to
+ * indicate which grids are illuminated only by the player's torch by using
+ * the color yellow for those grids.
+ *
+ * The old "update_view()" algorithm uses the special "CAVE_EASY" flag as a
+ * temporary internal flag to mark those grids which are not only in view,
+ * but which are also "easily" in line of sight of the player. This flag
+ * is actually just the "CAVE_SEEN" flag, and the "update_view()" function
+ * makes sure to clear it for all old "CAVE_SEEN" grids, and then use it in
+ * the algorithm as "CAVE_EASY", and then clear it for all "CAVE_EASY" grids,
+ * and then reset it as appropriate for all new "CAVE_SEEN" grids. This is
+ * kind of messy, but it works. The old algorithm may disappear eventually.
+ *
+ * The new "update_view()" algorithm uses a faster and more mathematically
+ * correct algorithm, assisted by a large machine generated static array, to
+ * determine the "CAVE_VIEW" and "CAVE_SEEN" flags simultaneously. See below.
+ *
+ * It seems as though slight modifications to the "update_view()" functions
+ * would allow us to determine "reverse" line-of-sight as well as "normal"
+ * line-of-sight", which would allow monsters to have a more "correct" way
+ * to determine if they can "see" the player, since right now, they "cheat"
+ * somewhat and assume that if the player has "line of sight" to them, then
+ * they can "pretend" that they have "line of sight" to the player. But if
+ * such a change was attempted, the monsters would actually start to exhibit
+ * some undesirable behavior, such as "freezing" near the entrances to long
+ * hallways containing the player, and code would have to be added to make
+ * the monsters move around even if the player was not detectable, and to
+ * "remember" where the player was last seen, to avoid looking stupid.
+ *
+ * Note that the "CAVE_GLOW" flag means that a grid is permanently lit in
+ * some way. However, for the player to "see" the grid, as determined by
+ * the "CAVE_SEEN" flag, the player must not be blind, the grid must have
+ * the "CAVE_VIEW" flag set, and if the grid is a "wall" grid, and it is
+ * not lit by the player's torch, then it must touch a grid which does not
+ * have the "CAVE_WALL" flag set, but which does have both the "CAVE_GLOW"
+ * and "CAVE_VIEW" flags set. This last part about wall grids is induced
+ * by the semantics of "CAVE_GLOW" as applied to wall grids, and checking
+ * the technical requirements can be very expensive, especially since the
+ * grid may be touching some "illegal" grids. Luckily, it is more or less
+ * correct to restrict the "touching" grids from the eight "possible" grids
+ * to the (at most) three grids which are touching the grid, and which are
+ * closer to the player than the grid itself, which eliminates more than
+ * half of the work, including all of the potentially "illegal" grids, if
+ * at most one of the three grids is a "diagonal" grid. In addition, in
+ * almost every situation, it is possible to ignore the "CAVE_VIEW" flag
+ * on these three "touching" grids, for a variety of technical reasons.
+ * Finally, note that in most situations, it is only necessary to check
+ * a single "touching" grid, in fact, the grid which is strictly closest
+ * to the player of all the touching grids, and in fact, it is normally
+ * only necessary to check the "CAVE_GLOW" flag of that grid, again, for
+ * various technical reasons. However, one of the situations which does
+ * not work with this last reduction is the very common one in which the
+ * player approaches an illuminated room from a dark hallway, in which the
+ * two wall grids which form the "entrance" to the room would not be marked
+ * as "CAVE_SEEN", since of the three "touching" grids nearer to the player
+ * than each wall grid, only the farthest of these grids is itself marked
+ * "CAVE_GLOW".
+ *
+ *
+ * Here are some pictures of the legal "light source" radius values, in
+ * which the numbers indicate the "order" in which the grids could have
+ * been calculated, if desired. Note that the code will work with larger
+ * radiuses, though currently yields such a radius, and the game would
+ * become slower in some situations if it did.
+ *
+ * Rad=0 Rad=1 Rad=2 Rad=3
+ * No-Lite Torch,etc Lantern Artifacts
+ *
+ * 333
+ * 333 43334
+ * 212 32123 3321233
+ * @ 1@1 31@13 331@133
+ * 212 32123 3321233
+ * 333 43334
+ * 333
+ *
+ *
+ * Here is an illustration of the two different "update_view()" algorithms,
+ * in which the grids marked "%" are pillars, and the grids marked "?" are
+ * not in line of sight of the player.
+ *
+ *
+ * Sample situation
+ *
+ * #####################
+ * ############.%.%.%.%#
+ * #...@..#####........#
+ * #............%.%.%.%#
+ * #......#####........#
+ * ############........#
+ * #####################
+ *
+ *
+ * New Algorithm Old Algorithm
+ *
+ * ########????????????? ########?????????????
+ * #...@..#????????????? #...@..#?????????????
+ * #...........????????? #.........???????????
+ * #......#####.....???? #......####??????????
+ * ########?????????...# ########?????????????
+ *
+ * ########????????????? ########?????????????
+ * #.@....#????????????? #.@....#?????????????
+ * #............%??????? #...........?????????
+ * #......#####........? #......#####?????????
+ * ########??????????..# ########?????????????
+ *
+ * ########????????????? ########?????%???????
+ * #......#####........# #......#####..???????
+ * #.@..........%??????? #.@..........%???????
+ * #......#####........# #......#####..???????
+ * ########????????????? ########?????????????
+ *
+ * ########??????????..# ########?????????????
+ * #......#####........? #......#####?????????
+ * #............%??????? #...........?????????
+ * #.@....#????????????? #.@....#?????????????
+ * ########????????????? ########?????????????
+ *
+ * ########?????????%??? ########?????????????
+ * #......#####.....???? #......####??????????
+ * #...........????????? #.........???????????
+ * #...@..#????????????? #...@..#?????????????
+ * ########????????????? ########?????????????
+ */
+
+
+
+
+/*
+ * Maximum number of grids in a single octant
+ */
+#define VINFO_MAX_GRIDS 161
+
+
+/*
+ * Maximum number of slopes in a single octant
+ */
+#define VINFO_MAX_SLOPES 126
+
+
+/*
+ * Mask of bits used in a single octant
+ */
+#define VINFO_BITS_3 0x3FFFFFFF
+#define VINFO_BITS_2 0xFFFFFFFF
+#define VINFO_BITS_1 0xFFFFFFFF
+#define VINFO_BITS_0 0xFFFFFFFF
+
+
+/*
+ * Forward declare
+ */
+typedef struct vinfo_type vinfo_type;
+
+
+/*
+ * The 'vinfo_type' structure
+ */
+struct vinfo_type
+{
+ s16b grid_y[8];
+ s16b grid_x[8];
+
+ u32b bits_3;
+ u32b bits_2;
+ u32b bits_1;
+ u32b bits_0;
+
+ vinfo_type *next_0;
+ vinfo_type *next_1;
+
+ byte y;
+ byte x;
+ byte d;
+ byte r;
+};
+
+
+
+/*
+ * The array of "vinfo" objects, initialized by "vinfo_init()"
+ */
+static vinfo_type vinfo[VINFO_MAX_GRIDS];
+
+
+
+
+/*
+ * Slope scale factor
+ */
+#define SCALE 100000L
+
+
+/*
+ * The actual slopes (for reference)
+ */
+
+/* Bit : Slope Grids */
+/* --- : ----- ----- */
+/* 0 : 2439 21 */
+/* 1 : 2564 21 */
+/* 2 : 2702 21 */
+/* 3 : 2857 21 */
+/* 4 : 3030 21 */
+/* 5 : 3225 21 */
+/* 6 : 3448 21 */
+/* 7 : 3703 21 */
+/* 8 : 4000 21 */
+/* 9 : 4347 21 */
+/* 10 : 4761 21 */
+/* 11 : 5263 21 */
+/* 12 : 5882 21 */
+/* 13 : 6666 21 */
+/* 14 : 7317 22 */
+/* 15 : 7692 20 */
+/* 16 : 8108 21 */
+/* 17 : 8571 21 */
+/* 18 : 9090 20 */
+/* 19 : 9677 21 */
+/* 20 : 10344 21 */
+/* 21 : 11111 20 */
+/* 22 : 12000 21 */
+/* 23 : 12820 22 */
+/* 24 : 13043 22 */
+/* 25 : 13513 22 */
+/* 26 : 14285 20 */
+/* 27 : 15151 22 */
+/* 28 : 15789 22 */
+/* 29 : 16129 22 */
+/* 30 : 17241 22 */
+/* 31 : 17647 22 */
+/* 32 : 17948 23 */
+/* 33 : 18518 22 */
+/* 34 : 18918 22 */
+/* 35 : 20000 19 */
+/* 36 : 21212 22 */
+/* 37 : 21739 22 */
+/* 38 : 22580 22 */
+/* 39 : 23076 22 */
+/* 40 : 23809 22 */
+/* 41 : 24137 22 */
+/* 42 : 24324 23 */
+/* 43 : 25714 23 */
+/* 44 : 25925 23 */
+/* 45 : 26315 23 */
+/* 46 : 27272 22 */
+/* 47 : 28000 23 */
+/* 48 : 29032 23 */
+/* 49 : 29411 23 */
+/* 50 : 29729 24 */
+/* 51 : 30434 23 */
+/* 52 : 31034 23 */
+/* 53 : 31428 23 */
+/* 54 : 33333 18 */
+/* 55 : 35483 23 */
+/* 56 : 36000 23 */
+/* 57 : 36842 23 */
+/* 58 : 37142 24 */
+/* 59 : 37931 24 */
+/* 60 : 38461 24 */
+/* 61 : 39130 24 */
+/* 62 : 39393 24 */
+/* 63 : 40740 24 */
+/* 64 : 41176 24 */
+/* 65 : 41935 24 */
+/* 66 : 42857 23 */
+/* 67 : 44000 24 */
+/* 68 : 44827 24 */
+/* 69 : 45454 23 */
+/* 70 : 46666 24 */
+/* 71 : 47368 24 */
+/* 72 : 47826 24 */
+/* 73 : 48148 24 */
+/* 74 : 48387 24 */
+/* 75 : 51515 25 */
+/* 76 : 51724 25 */
+/* 77 : 52000 25 */
+/* 78 : 52380 25 */
+/* 79 : 52941 25 */
+/* 80 : 53846 25 */
+/* 81 : 54838 25 */
+/* 82 : 55555 24 */
+/* 83 : 56521 25 */
+/* 84 : 57575 26 */
+/* 85 : 57894 25 */
+/* 86 : 58620 25 */
+/* 87 : 60000 23 */
+/* 88 : 61290 25 */
+/* 89 : 61904 25 */
+/* 90 : 62962 25 */
+/* 91 : 63636 25 */
+/* 92 : 64705 25 */
+/* 93 : 65217 25 */
+/* 94 : 65517 25 */
+/* 95 : 67741 26 */
+/* 96 : 68000 26 */
+/* 97 : 68421 26 */
+/* 98 : 69230 26 */
+/* 99 : 70370 26 */
+/* 100 : 71428 25 */
+/* 101 : 72413 26 */
+/* 102 : 73333 26 */
+/* 103 : 73913 26 */
+/* 104 : 74193 27 */
+/* 105 : 76000 26 */
+/* 106 : 76470 26 */
+/* 107 : 77777 25 */
+/* 108 : 78947 26 */
+/* 109 : 79310 26 */
+/* 110 : 80952 26 */
+/* 111 : 81818 26 */
+/* 112 : 82608 26 */
+/* 113 : 84000 26 */
+/* 114 : 84615 26 */
+/* 115 : 85185 26 */
+/* 116 : 86206 27 */
+/* 117 : 86666 27 */
+/* 118 : 88235 27 */
+/* 119 : 89473 27 */
+/* 120 : 90476 27 */
+/* 121 : 91304 27 */
+/* 122 : 92000 27 */
+/* 123 : 92592 27 */
+/* 124 : 93103 28 */
+/* 125 : 100000 13 */
+
+
+
+/*
+ * Forward declare
+ */
+typedef struct vinfo_hack vinfo_hack;
+
+
+/*
+ * Temporary data used by "vinfo_init()"
+ *
+ * - Number of grids
+ *
+ * - Number of slopes
+ *
+ * - Slope values
+ *
+ * - Slope range per grid
+ */
+struct vinfo_hack
+{
+
+ int num_slopes;
+
+ long slopes[VINFO_MAX_SLOPES];
+
+ long slopes_min[MAX_SIGHT + 1][MAX_SIGHT + 1];
+ long slopes_max[MAX_SIGHT + 1][MAX_SIGHT + 1];
+};
+
+
+
+/*
+ * Sorting hook -- comp function -- array of long's (see below)
+ *
+ * We use "u" to point to an array of long integers.
+ */
+static bool_ ang_sort_comp_hook_longs(vptr u, vptr v, int a, int b)
+{
+ long *x = (long*)(u);
+
+ return (x[a] <= x[b]);
+}
+
+
+/*
+ * Sorting hook -- comp function -- array of long's (see below)
+ *
+ * We use "u" to point to an array of long integers.
+ */
+static void ang_sort_swap_hook_longs(vptr u, vptr v, int a, int b)
+{
+ long *x = (long*)(u);
+
+ long temp;
+
+ /* Swap */
+ temp = x[a];
+ x[a] = x[b];
+ x[b] = temp;
+}
+
+
+
+/*
+ * Save a slope
+ */
+static void vinfo_init_aux(vinfo_hack *hack, int y, int x, long m)
+{
+ int i;
+
+ /* Handle "legal" slopes */
+ if ((m > 0) && (m <= SCALE))
+ {
+ /* Look for that slope */
+ for (i = 0; i < hack->num_slopes; i++)
+ {
+ if (hack->slopes[i] == m) break;
+ }
+
+ /* New slope */
+ if (i == hack->num_slopes)
+ {
+ /* Paranoia */
+ if (hack->num_slopes >= VINFO_MAX_SLOPES)
+ {
+ quit_fmt("Too many slopes (%d)!",
+ VINFO_MAX_SLOPES);
+ }
+
+ /* Save the slope, and advance */
+ hack->slopes[hack->num_slopes++] = m;
+ }
+ }
+
+ /* Track slope range */
+ if (hack->slopes_min[y][x] > m) hack->slopes_min[y][x] = m;
+ if (hack->slopes_max[y][x] < m) hack->slopes_max[y][x] = m;
+}
+
+
+
+/*
+ * Initialize the "vinfo" array
+ *
+ * Full Octagon (radius 20), Grids=1149
+ *
+ * Quadrant (south east), Grids=308, Slopes=251
+ *
+ * Octant (east then south), Grids=161, Slopes=126
+ *
+ * This function assumes that VINFO_MAX_GRIDS and VINFO_MAX_SLOPES
+ * have the correct values, which can be derived by setting them to
+ * a number which is too high, running this function, and using the
+ * error messages to obtain the correct values.
+ */
+errr vinfo_init(void)
+{
+ int i, y, x;
+
+ long m;
+
+ vinfo_hack *hack;
+
+ int num_grids = 0;
+
+ int queue_head = 0;
+ int queue_tail = 0;
+ vinfo_type *queue[VINFO_MAX_GRIDS*2];
+
+
+ /* Make hack */
+ MAKE(hack, vinfo_hack);
+
+
+ /* Analyze grids */
+ for (y = 0; y <= MAX_SIGHT; ++y)
+ {
+ for (x = y; x <= MAX_SIGHT; ++x)
+ {
+ /* Skip grids which are out of sight range */
+ if (distance(0, 0, y, x) > MAX_SIGHT) continue;
+
+ /* Default slope range */
+ hack->slopes_min[y][x] = 999999999;
+ hack->slopes_max[y][x] = 0;
+
+ /* Paranoia */
+ if (num_grids >= VINFO_MAX_GRIDS)
+ {
+ quit_fmt("Too many grids (%d >= %d)!",
+ num_grids, VINFO_MAX_GRIDS);
+ }
+
+ /* Count grids */
+ num_grids++;
+
+ /* Slope to the top right corner */
+ m = SCALE * (1000L * y - 500) / (1000L * x + 500);
+
+ /* Handle "legal" slopes */
+ vinfo_init_aux(hack, y, x, m);
+
+ /* Slope to top left corner */
+ m = SCALE * (1000L * y - 500) / (1000L * x - 500);
+
+ /* Handle "legal" slopes */
+ vinfo_init_aux(hack, y, x, m);
+
+ /* Slope to bottom right corner */
+ m = SCALE * (1000L * y + 500) / (1000L * x + 500);
+
+ /* Handle "legal" slopes */
+ vinfo_init_aux(hack, y, x, m);
+
+ /* Slope to bottom left corner */
+ m = SCALE * (1000L * y + 500) / (1000L * x - 500);
+
+ /* Handle "legal" slopes */
+ vinfo_init_aux(hack, y, x, m);
+ }
+ }
+
+
+ /* Enforce maximal efficiency */
+ if (num_grids < VINFO_MAX_GRIDS)
+ {
+ quit_fmt("Too few grids (%d < %d)!",
+ num_grids, VINFO_MAX_GRIDS);
+ }
+
+ /* Enforce maximal efficiency */
+ if (hack->num_slopes < VINFO_MAX_SLOPES)
+ {
+ quit_fmt("Too few slopes (%d < %d)!",
+ hack->num_slopes, VINFO_MAX_SLOPES);
+ }
+
+
+ /* Sort slopes numerically */
+ ang_sort_comp = ang_sort_comp_hook_longs;
+
+ /* Sort slopes numerically */
+ ang_sort_swap = ang_sort_swap_hook_longs;
+
+ /* Sort the (unique) slopes */
+ ang_sort(hack->slopes, NULL, hack->num_slopes);
+
+
+
+ /* Enqueue player grid */
+ queue[queue_tail++] = &vinfo[0];
+
+ /* Process queue */
+ while (queue_head < queue_tail)
+ {
+ int e;
+
+ /* Index */
+ e = queue_head;
+
+ /* Dequeue next grid */
+ queue_head++;
+
+ /* Location of main grid */
+ y = vinfo[e].grid_y[0];
+ x = vinfo[e].grid_x[0];
+
+
+ /* Compute grid offsets */
+ vinfo[e].grid_y[0] = + y;
+ vinfo[e].grid_x[0] = + x;
+ vinfo[e].grid_y[1] = + x;
+ vinfo[e].grid_x[1] = + y;
+ vinfo[e].grid_y[2] = + x;
+ vinfo[e].grid_x[2] = -y;
+ vinfo[e].grid_y[3] = + y;
+ vinfo[e].grid_x[3] = -x;
+ vinfo[e].grid_y[4] = -y;
+ vinfo[e].grid_x[4] = -x;
+ vinfo[e].grid_y[5] = -x;
+ vinfo[e].grid_x[5] = -y;
+ vinfo[e].grid_y[6] = -x;
+ vinfo[e].grid_x[6] = + y;
+ vinfo[e].grid_y[7] = -y;
+ vinfo[e].grid_x[7] = + x;
+
+
+ /* Analyze slopes */
+ for (i = 0; i < hack->num_slopes; ++i)
+ {
+ m = hack->slopes[i];
+
+ /* Memorize intersection slopes (for non-player-grids) */
+ if ((e > 0) &&
+ (hack->slopes_min[y][x] < m) &&
+ (m < hack->slopes_max[y][x]))
+ {
+ switch (i / 32)
+ {
+ case 3:
+ vinfo[e].bits_3 |= (1L << (i % 32));
+ break;
+ case 2:
+ vinfo[e].bits_2 |= (1L << (i % 32));
+ break;
+ case 1:
+ vinfo[e].bits_1 |= (1L << (i % 32));
+ break;
+ case 0:
+ vinfo[e].bits_0 |= (1L << (i % 32));
+ break;
+ }
+ }
+ }
+
+
+ /* Default */
+ vinfo[e].next_0 = &vinfo[0];
+
+ /* Grid next child */
+ if (distance(0, 0, y, x + 1) <= MAX_SIGHT)
+ {
+ if ((queue[queue_tail - 1]->grid_y[0] != y) ||
+ (queue[queue_tail - 1]->grid_x[0] != x + 1))
+ {
+ vinfo[queue_tail].grid_y[0] = y;
+ vinfo[queue_tail].grid_x[0] = x + 1;
+ queue[queue_tail] = &vinfo[queue_tail];
+ queue_tail++;
+ }
+
+ vinfo[e].next_0 = &vinfo[queue_tail - 1];
+ }
+
+
+ /* Default */
+ vinfo[e].next_1 = &vinfo[0];
+
+ /* Grid diag child */
+ if (distance(0, 0, y + 1, x + 1) <= MAX_SIGHT)
+ {
+ if ((queue[queue_tail - 1]->grid_y[0] != y + 1) ||
+ (queue[queue_tail - 1]->grid_x[0] != x + 1))
+ {
+ vinfo[queue_tail].grid_y[0] = y + 1;
+ vinfo[queue_tail].grid_x[0] = x + 1;
+ queue[queue_tail] = &vinfo[queue_tail];
+ queue_tail++;
+ }
+
+ vinfo[e].next_1 = &vinfo[queue_tail - 1];
+ }
+
+
+ /* Hack -- main diagonal has special children */
+ if (y == x) vinfo[e].next_0 = vinfo[e].next_1;
+
+
+ /* Extra values */
+ vinfo[e].y = y;
+ vinfo[e].x = x;
+ vinfo[e].d = ((y > x) ? (y + x / 2) : (x + y / 2));
+ vinfo[e].r = ((!y) ? x : (!x) ? y : (y == x) ? y : 0);
+ }
+
+
+ /* Verify maximal bits XXX XXX XXX */
+ if (((vinfo[1].bits_3 | vinfo[2].bits_3) != VINFO_BITS_3) ||
+ ((vinfo[1].bits_2 | vinfo[2].bits_2) != VINFO_BITS_2) ||
+ ((vinfo[1].bits_1 | vinfo[2].bits_1) != VINFO_BITS_1) ||
+ ((vinfo[1].bits_0 | vinfo[2].bits_0) != VINFO_BITS_0))
+ {
+ quit("Incorrect bit masks!");
+ }
+
+
+ /* Kill hack */
+ KILL(hack, vinfo_hack);
+
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Forget the "CAVE_VIEW" grids, redrawing as needed
+ */
+void forget_view(void)
+{
+ int i;
+
+ int fast_view_n = view_n;
+
+ cave_type *c_ptr;
+
+
+ /* None to forget */
+ if (!fast_view_n) return;
+
+ /* Clear them all */
+ for (i = 0; i < fast_view_n; i++)
+ {
+ int y = view_y[i];
+ int x = view_x[i];
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Clear "CAVE_VIEW", "CAVE_SEEN" and player torch flags */
+ c_ptr->info &= ~(CAVE_VIEW | CAVE_SEEN | CAVE_PLIT);
+
+ /* Redraw */
+ lite_spot(y, x);
+ }
+
+ /* None left */
+ view_n = 0;
+}
+
+
+
+/*
+ * Calculate the complete field of view using a new algorithm
+ *
+ * If "view_y/x" and "temp_y/x" were global pointers to arrays of grids, as
+ * opposed to actual arrays of grids, then we could be more efficient by
+ * using "pointer swapping".
+ *
+ * Normally, vision along the major axes is more likely than vision
+ * along the diagonal axes, so we check the bits corresponding to
+ * the lines of sight near the major axes first.
+ *
+ * We use the "temp_y/x" array (and the "CAVE_TEMP" flag) to keep track of
+ * which grids were previously marked "CAVE_SEEN", since only those grids
+ * whose "CAVE_SEEN" value changes during this routine must be redrawn.
+ *
+ * This function is now responsible for maintaining the "CAVE_SEEN"
+ * flags as well as the "CAVE_VIEW" flags, which is good, because
+ * the only grids which normally need to be memorized and/or redrawn
+ * are the ones whose "CAVE_SEEN" flag changes during this routine.
+ *
+ * Basically, this function divides the "octagon of view" into octants of
+ * grids (where grids on the main axes and diagonal axes are "shared" by
+ * two octants), and processes each octant one at a time, processing each
+ * octant one grid at a time, processing only those grids which "might" be
+ * viewable, and setting the "CAVE_VIEW" flag for each grid for which there
+ * is an (unobstructed) line of sight from the center of the player grid to
+ * any internal point in the grid (and collecting these "CAVE_VIEW" grids
+ * into the "view_y/x" array), and setting the "CAVE_SEEN" flag for the grid
+ * if, in addition, the grid is "illuminated" in some way.
+ *
+ * This function relies on a theorem (suggested and proven by Mat Hostetter)
+ * which states that in each octant of a field of view, a given grid will
+ * be "intersected" by one or more unobstructed "lines of sight" from the
+ * center of the player grid if and only if it is "intersected" by at least
+ * one such unobstructed "line of sight" which passes directly through some
+ * corner of some grid in the octant which is not shared by any other octant.
+ * The proof is based on the fact that there are at least three significant
+ * lines of sight involving any non-shared grid in any octant, one which
+ * intersects the grid and passes though the corner of the grid closest to
+ * the player, and two which "brush" the grid, passing through the "outer"
+ * corners of the grid, and that any line of sight which intersects a grid
+ * without passing through the corner of a grid in the octant can be "slid"
+ * slowly towards the corner of the grid closest to the player, until it
+ * either reaches it or until it brushes the corner of another grid which
+ * is closer to the player, and in either case, the existanc of a suitable
+ * line of sight is thus demonstrated.
+ *
+ * It turns out that in each octant of the radius 20 "octagon of view",
+ * there are 161 grids (with 128 not shared by any other octant), and there
+ * are exactly 126 distinct "lines of sight" passing from the center of the
+ * player grid through any corner of any non-shared grid in the octant. To
+ * determine if a grid is "viewable" by the player, therefore, you need to
+ * simply show that one of these 126 lines of sight intersects the grid but
+ * does not intersect any wall grid closer to the player. So we simply use
+ * a bit vector with 126 bits to represent the set of interesting lines of
+ * sight which have not yet been obstructed by wall grids, and then we scan
+ * all the grids in the octant, moving outwards from the player grid. For
+ * each grid, if any of the lines of sight which intersect that grid have not
+ * yet been obstructed, then the grid is viewable. Furthermore, if the grid
+ * is a wall grid, then all of the lines of sight which intersect the grid
+ * should be marked as obstructed for future reference. Also, we only need
+ * to check those grids for whom at least one of the "parents" was a viewable
+ * non-wall grid, where the parents include the two grids touching the grid
+ * but closer to the player grid (one adjacent, and one diagonal). For the
+ * bit vector, we simply use 4 32-bit integers. All of the static values
+ * which are needed by this function are stored in the large "vinfo" array
+ * (above), which is machine generated by another program. XXX XXX XXX
+ *
+ * Hack -- The queue must be able to hold more than VINFO_MAX_GRIDS grids
+ * because the grids at the edge of the field of view use "grid zero" as
+ * their children, and the queue must be able to hold several of these
+ * special grids. Because the actual number of required grids is bizarre,
+ * we simply allocate twice as many as we would normally need. XXX XXX XXX
+ */
+void update_view(void)
+{
+ int i, o;
+ int y, x;
+
+ int radius;
+
+ int fast_view_n = view_n;
+
+ int fast_temp_n = 0;
+
+ cave_type *c_ptr;
+
+ u16b info;
+
+
+ /*** Step 0 -- Begin ***/
+
+ /* Save the old "view" grids for later */
+ for (i = 0; i < fast_view_n; i++)
+ {
+ /* Location */
+ y = view_y[i];
+ x = view_x[i];
+
+ /* Grid */
+ c_ptr = &cave[y][x];
+
+ /* Get grid info */
+ info = c_ptr->info;
+ ;
+
+ /* Save "CAVE_SEEN" grids */
+ if (info & (CAVE_SEEN))
+ {
+ /* Set "CAVE_TEMP" flag */
+ info |= (CAVE_TEMP);
+
+ /* Save grid for later */
+ temp_y[fast_temp_n] = y;
+ temp_x[fast_temp_n++] = x;
+ }
+
+ /* Clear "CAVE_VIEW", "CAVE_SEEN" and player torch flags */
+ info &= ~(CAVE_VIEW | CAVE_SEEN | CAVE_PLIT);
+
+ /* Save cave info */
+ c_ptr->info = info;
+ }
+
+ /* Reset the "view" array */
+ fast_view_n = 0;
+
+ /* Extract "radius" value */
+ radius = p_ptr->cur_lite;
+
+ /* Handle real light */
+ if (radius > 0) ++radius;
+
+
+ /*** Step 1 -- player grid ***/
+
+ /* Player grid */
+ c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ /* Get grid info */
+ info = c_ptr->info;
+
+ /* Assume viewable */
+ info |= (CAVE_VIEW);
+
+ /* Torch-lit grid */
+ if (0 < radius)
+ {
+ /* Mark as "CAVE_SEEN" and torch-lit */
+ info |= (CAVE_SEEN | CAVE_PLIT);
+ }
+
+
+ /* Perma-lit grid */
+ else if (info & (CAVE_GLOW))
+ {
+ /* Mark as "CAVE_SEEN" */
+ info |= (CAVE_SEEN);
+ }
+
+ /* Save cave info */
+ c_ptr->info = info;
+
+ /* Save in array */
+ view_y[fast_view_n] = p_ptr->py;
+ view_x[fast_view_n++] = p_ptr->px;
+
+
+ /*** Step 2 -- octants ***/
+
+ /* Scan each octant */
+ for (o = 0; o < 8; o++)
+ {
+ vinfo_type *p;
+
+ /* Last added */
+ vinfo_type *last = &vinfo[0];
+
+ /* Grid queue */
+ int queue_head = 0;
+ int queue_tail = 0;
+ vinfo_type *queue[VINFO_MAX_GRIDS*2];
+
+ /* Slope bit vector */
+ u32b bits0 = VINFO_BITS_0;
+ u32b bits1 = VINFO_BITS_1;
+ u32b bits2 = VINFO_BITS_2;
+ u32b bits3 = VINFO_BITS_3;
+
+ /* Reset queue */
+ queue_head = queue_tail = 0;
+
+ /* Initial grids */
+ queue[queue_tail++] = &vinfo[1];
+ queue[queue_tail++] = &vinfo[2];
+
+ /* Process queue */
+ while (queue_head < queue_tail)
+ {
+ /* Dequeue next grid */
+ p = queue[queue_head++];
+
+ /* Check bits */
+ if ((bits0 & (p->bits_0)) ||
+ (bits1 & (p->bits_1)) ||
+ (bits2 & (p->bits_2)) ||
+ (bits3 & (p->bits_3)))
+ {
+ /* Extract coordinate value */
+ y = p_ptr->py + p->grid_y[o];
+ x = p_ptr->px + p->grid_x[o];
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Get grid info */
+ info = c_ptr->info;
+
+ /* Handle wall */
+ if (info & (CAVE_WALL))
+ {
+ /* Clear bits */
+ bits0 &= ~(p->bits_0);
+ bits1 &= ~(p->bits_1);
+ bits2 &= ~(p->bits_2);
+ bits3 &= ~(p->bits_3);
+
+ /* Newly viewable wall */
+ if (!(info & (CAVE_VIEW)))
+ {
+ /* Mark as viewable */
+ info |= (CAVE_VIEW);
+
+ /* Torch-lit grids */
+ if (p->d < radius)
+ {
+ /* Mark as "CAVE_SEEN" and torch-lit */
+ info |= (CAVE_SEEN | CAVE_PLIT);
+ }
+
+ /* Monster-lit grids */
+ else if (info & (CAVE_MLIT))
+ {
+ /* Mark as "CAVE_SEEN" */
+ info |= (CAVE_SEEN);
+ }
+
+ /* Perma-lit grids */
+ else if (info & (CAVE_GLOW))
+ {
+ /* Hack -- move towards player */
+ int yy = (y < p_ptr->py) ? (y + 1) : (y > p_ptr->py) ? (y - 1) : y;
+ int xx = (x < p_ptr->px) ? (x + 1) : (x > p_ptr->px) ? (x - 1) : x;
+
+#ifdef UPDATE_VIEW_COMPLEX_WALL_ILLUMINATION
+
+ /* Check for "complex" illumination */
+ if ((!(cave[yy][xx].info & (CAVE_WALL)) &&
+ (cave[yy][xx].info & (CAVE_GLOW))) ||
+ (!(cave[y][xx].info & (CAVE_WALL)) &&
+ (cave[y][xx].info & (CAVE_GLOW))) ||
+ (!(cave[yy][x].info & (CAVE_WALL)) &&
+ (cave[yy][x].info & (CAVE_GLOW))))
+ {
+ /* Mark as seen */
+ info |= (CAVE_SEEN);
+ }
+
+#else /* UPDATE_VIEW_COMPLEX_WALL_ILLUMINATION */
+
+ /* Check for "simple" illumination */
+ if (cave[yy][xx].info & (CAVE_GLOW))
+ {
+ /* Mark as seen */
+ info |= (CAVE_SEEN);
+ }
+
+#endif /* UPDATE_VIEW_COMPLEX_WALL_ILLUMINATION */
+
+ }
+
+ /* Save cave info */
+ c_ptr->info = info;
+
+ /* Save in array */
+ view_y[fast_view_n] = y;
+ view_x[fast_view_n++] = x;
+ }
+ }
+
+ /* Handle non-wall */
+ else
+ {
+ /* Enqueue child */
+ if (last != p->next_0)
+ {
+ queue[queue_tail++] = last = p->next_0;
+ }
+
+ /* Enqueue child */
+ if (last != p->next_1)
+ {
+ queue[queue_tail++] = last = p->next_1;
+ }
+
+ /* Newly viewable non-wall */
+ if (!(info & (CAVE_VIEW)))
+ {
+ /* Mark as "viewable" */
+ info |= (CAVE_VIEW);
+
+ /* Torch-lit grids */
+ if (p->d < radius)
+ {
+ /* Mark as "CAVE_SEEN" and torch-lit */
+ info |= (CAVE_SEEN | CAVE_PLIT);
+ }
+
+ /* Perma-lit or monster-lit grids */
+ else if (info & (CAVE_GLOW | CAVE_MLIT))
+ {
+ /* Mark as "CAVE_SEEN" */
+ info |= (CAVE_SEEN);
+ }
+
+ /* Save cave info */
+ c_ptr->info = info;
+
+ /* Save in array */
+ view_y[fast_view_n] = y;
+ view_x[fast_view_n++] = x;
+ }
+ }
+ }
+ }
+ }
+
+
+ /*** Step 3 -- Complete the algorithm ***/
+
+ /* Handle blindness */
+ if (p_ptr->blind)
+ {
+ /* Process "new" grids */
+ for (i = 0; i < fast_view_n; i++)
+ {
+ /* Location */
+ y = view_y[i];
+ x = view_x[i];
+
+ /* Grid cannot be "CAVE_SEEN" */
+ cave[y][x].info &= ~(CAVE_SEEN);
+ }
+ }
+
+ /* Process "new" grids */
+ for (i = 0; i < fast_view_n; i++)
+ {
+ /* Location */
+ y = view_y[i];
+ x = view_x[i];
+
+ /* Get grid info */
+ info = cave[y][x].info;
+
+ /* Was not "CAVE_SEEN", is now "CAVE_SEEN" */
+ if ((info & (CAVE_SEEN)) && !(info & (CAVE_TEMP)))
+ {
+ /* Note */
+ note_spot(y, x);
+
+ /* Redraw */
+ lite_spot(y, x);
+ }
+ }
+
+ /* Process "old" grids */
+ for (i = 0; i < fast_temp_n; i++)
+ {
+ /* Location */
+ y = temp_y[i];
+ x = temp_x[i];
+
+ /* Grid */
+ c_ptr = &cave[y][x];
+
+ /* Get grid info */
+ info = c_ptr->info;
+
+ /* Clear "CAVE_TEMP" flag */
+ info &= ~(CAVE_TEMP);
+
+ /* Save cave info */
+ c_ptr->info = info;
+
+ /* Was "CAVE_SEEN", is now not "CAVE_SEEN" */
+ if (!(info & (CAVE_SEEN)))
+ {
+ /* Redraw */
+ lite_spot(y, x);
+ }
+ }
+
+
+ /* Save 'view_n' */
+ view_n = fast_view_n;
+}
+
+
+/*
+ * Clear monster light
+ */
+void forget_mon_lite(void)
+{
+ int i, y, x;
+
+ /* Process all the monster-lit grids */
+ for (i = 0; i < lite_n; i++)
+ {
+ /* Access location */
+ y = lite_y[i];
+ x = lite_x[i];
+
+ /* Clear monster light flag */
+ cave[y][x].info &= ~(CAVE_MLIT);
+ }
+
+ /* Forget light array */
+ lite_n = 0;
+}
+
+
+/*
+ * Update squares illuminated by monsters
+ *
+ * Code taken from Steven Fuerst's work for ZAngband, without support
+ * for multiple lite radii, and with necessary modifications for different
+ * internal representation of dungeon/wilderness. Other minor changes
+ * are mine...
+ *
+ * I'm not sure if I can handle wide radius well. Consider the following
+ * example, with p carrying a radius 3 light source:
+ *
+ * ##%#
+ * .x..
+ * p##@
+ *
+ * % should be illuminated, although the beam path is entirely out of
+ * player's los (because of grid-based nature of cave representation)...
+ * And I'm extremely reluctant to introduce symmetrical los. The current
+ * asymmetrical system has its own merit, and all the rules of games are
+ * asymmetrical, in some way or another...
+ *
+ * The code below exploits special characteristics of radius one light
+ * where one can fairly safely use light source's visibility (in terms of los)
+ * to determine if we can illuminate walls XXX
+ *
+ * This function works within the current player's field of view
+ * calculated by update_view(), so it should normally be called
+ * whenever FoV is updated (== PU_VIEW | PU_MON_LITE). The other
+ * case is when RF9_HAS_LITE monsters have moved or dead. Monster
+ * creation occurs out of LoS, so I chose not to take this into
+ * consideration.
+ *
+ * The CAVE_TEMP flag is used by the function to remember "old" monster-lit
+ * grids so that it can only redraw squares whose visibility has changed.
+ *
+ * Doing this in the update_view() order (update "new" grids, then "old")
+ * would result in bizarre lighting effects XXX XXX
+ *
+ * It has been made possible again to draw torch/monster-lit grids in
+ * different colours, even when they are in permanently lit locations
+ * by using (CAVE_PLIT|CAVE_MLIT) as if it were old CAVE_LITE, but I don't
+ * think it's appropriate for torch lights to be visible under the Sun :)
+ * or brighter light, and it doesn't work well with PernAngband's already
+ * colourful terrain features in aesthetically pleasing ways... -- pelpel
+ */
+void update_mon_lite(void)
+{
+ int i, y, x, d;
+ int fy, fx;
+
+ cave_type *c_ptr;
+ u16b info;
+
+ bool_ invis;
+
+ s16b fast_lite_n = lite_n;
+ s16b fast_temp_n;
+
+
+ /* Mega-Hack -- It's unnecessary there */
+ if (p_ptr->wild_mode) return;
+
+ /* Handle special case -- Blindness */
+ if (p_ptr->blind)
+ {
+ for (i = 0; i < fast_lite_n; i++)
+ {
+ /* Light location */
+ y = lite_y[i];
+ x = lite_x[i];
+
+ /* Forget monster light and view */
+ cave[y][x].info &= ~(CAVE_MLIT | CAVE_SEEN);
+
+ /* Redraw spot */
+ /* lite_spot(y, x); */
+ }
+
+ /* Clear the light list */
+ lite_n = 0;
+
+ /* Done */
+ return;
+ }
+
+
+ /* Remember and clear all monster-lit grids */
+ for (i = 0; i < fast_lite_n; i++)
+ {
+ /* Lit location */
+ y = lite_y[i];
+ x = lite_x[i];
+
+ /* Access grid */
+ c_ptr = &cave[y][x];
+
+ /* Access cave info of the grid */
+ info = c_ptr->info;
+
+ /* Remember it, by setting the CAVE_TEMP flag */
+ info |= (CAVE_TEMP);
+
+ /* Forget monster light */
+ info &= ~(CAVE_MLIT);
+
+ /* Unseen unless it's glowing or illuminated by player light source */
+ if (!(info & (CAVE_GLOW | CAVE_PLIT)))
+ {
+ info &= ~(CAVE_SEEN);
+ }
+
+ /* Save cave info flags */
+ c_ptr->info = info;
+ }
+
+
+ /* Clear the temp list */
+ fast_temp_n = 0;
+
+ /* Loop through monsters, adding newly lit grids to changes list */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr;
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Skip out-of-sight monsters (MAX_SIGHT + max radius) */
+ if (m_ptr->cdis > MAX_SIGHT + 1) continue;
+
+ /* Access monster race info (with possible ego mods) */
+ r_ptr = race_info_idx(m_ptr->r_idx, m_ptr->ego);
+
+ /* Skip monsters not carrying light source */
+ if (!(r_ptr->flags9 & RF9_HAS_LITE)) continue;
+
+ /* Access the location */
+ fy = m_ptr->fy;
+ fx = m_ptr->fx;
+
+ /* Extract monster grid visibility */
+ invis = !player_has_los_bold(fy, fx);
+
+ /* Nested loops may be a bad idea here XXX */
+ for (d = 0; d < 9; d++)
+ {
+ y = fy + ddy_ddd[d];
+ x = fx + ddx_ddd[d];
+
+ /* Paranoia */
+ /* if (!in_bounds(y, x)) continue; */
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Access cave info flags */
+ info = c_ptr->info;
+
+ /* Don't care grids out of player's los */
+ if (!(info & (CAVE_VIEW))) continue;
+
+ /*
+ * Avoid processing already monster-lit grids,
+ * for efficiency and to avoid temp array overflow
+ */
+ if (info & (CAVE_MLIT)) continue;
+
+ /*
+ * Hack XXX XXX -- light shouldn't penetrate walls
+ *
+ * OK NG
+ * .#. p#. | p. .p. p..
+ * p.@ ..@ | .# .#. .#.
+ * | .@ .@. ..@
+ *
+ * So if a monster carrying light source is out of player LoS,
+ * walls aren't illuminated.
+ *
+ * CAVEAT: % will be illuminated in cases like this:
+ *
+ * #%..@
+ * p....
+ *
+ * We don't have four sides for a wall grid, so...
+ */
+ if (invis && (f_info[c_ptr->feat].flags1 & FF1_NO_VISION)) continue;
+
+ /* Give monster light to the location */
+ c_ptr->info |= (CAVE_MLIT | CAVE_SEEN);
+
+ /* Save the location */
+ temp_y[fast_temp_n] = y;
+ temp_x[fast_temp_n] = x;
+ fast_temp_n++;
+ }
+ }
+
+ /* Process old grids */
+ for (i = 0; i < fast_lite_n; i++)
+ {
+ /* Access location */
+ y = lite_y[i];
+ x = lite_x[i];
+
+ /* Access grid */
+ c_ptr = &cave[y][x];
+
+ /* Was lit, is no longer lit */
+ if (!(c_ptr->info & (CAVE_MLIT)))
+ {
+ /* Clear the temp flag */
+ c_ptr->info &= ~(CAVE_TEMP);
+
+ /* See if there was a visible monster */
+ if (player_has_los_bold(y, x) && c_ptr->m_idx)
+ {
+ /* Hide the monster */
+ update_mon(c_ptr->m_idx, FALSE);
+ }
+ else
+ {
+ /* Redraw */
+ lite_spot(y, x);
+ }
+ }
+ }
+
+ /* Copy the temp array into the light array */
+ for (i = 0; i < fast_temp_n; i++)
+ {
+ /* Access location */
+ y = temp_y[i];
+ x = temp_x[i];
+
+ /* Access grid */
+ c_ptr = &cave[y][x];
+
+
+ /* No changes in illumination */
+ if (c_ptr->info & (CAVE_TEMP))
+ {
+ /* Clear the temp flag */
+ c_ptr->info &= ~(CAVE_TEMP);
+ }
+
+ /* Was not lit, is now lit */
+ else
+ {
+ /* Remember the location, if appropriate */
+ note_spot(y, x);
+
+ /* See if there is a monster */
+ if (c_ptr->m_idx)
+ {
+ /* Show it */
+ update_mon(c_ptr->m_idx, FALSE);
+ }
+ else
+ {
+ /* Redraw */
+ lite_spot(y, x);
+ }
+ }
+
+
+ /* Save the location */
+ lite_y[i] = y;
+ lite_x[i] = x;
+ }
+
+ /* Save lite_n */
+ lite_n = fast_temp_n;
+
+ /* Forget temp */
+ temp_n = 0;
+}
+
+
+
+
+
+
+/*
+ * Hack -- provide some "speed" for the "flow" code
+ * This entry is the "current index" for the "when" field
+ * Note that a "when" value of "zero" means "not used".
+ *
+ * Note that the "cost" indexes from 1 to 127 are for
+ * "old" data, and from 128 to 255 are for "new" data.
+ *
+ * This means that as long as the player does not "teleport",
+ * then any monster up to 128 + MONSTER_FLOW_DEPTH will be
+ * able to track down the player, and in general, will be
+ * able to track down either the player or a position recently
+ * occupied by the player.
+ */
+static int flow_n = 0;
+
+
+/*
+ * Hack -- forget the "flow" information
+ */
+void forget_flow(void)
+{
+ int x, y;
+
+ /* Nothing to forget */
+ if (!flow_n) return;
+
+ /* Check the entire dungeon */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ /* Forget the old data */
+ cave[y][x].cost = 0;
+ cave[y][x].when = 0;
+ }
+ }
+
+ /* Start over */
+ flow_n = 0;
+}
+
+
+/*
+ * Hack -- Allow us to treat the "seen" array as a queue
+ */
+static int flow_head = 0;
+static int flow_tail = 0;
+
+
+/*
+ * Take note of a reachable grid. Assume grid is legal.
+ */
+static void update_flow_aux(int y, int x, int n)
+{
+ cave_type *c_ptr;
+
+ int old_head = flow_head;
+
+
+ /* Get the grid */
+ c_ptr = &cave[y][x];
+
+ /* Ignore "pre-stamped" entries */
+ if (c_ptr->when == flow_n) return;
+
+ /* Ignore "walls" and "rubble" */
+ if (c_ptr->feat >= FEAT_RUBBLE) return;
+
+ /* Save the time-stamp */
+ c_ptr->when = flow_n;
+
+ /* Save the flow cost */
+ c_ptr->cost = n;
+
+ /* Hack -- limit flow depth */
+ if (n == MONSTER_FLOW_DEPTH) return;
+
+ /* Enqueue that entry */
+ temp_y[flow_head] = y;
+ temp_x[flow_head] = x;
+
+ /* Advance the queue */
+ if (++flow_head == TEMP_MAX) flow_head = 0;
+
+ /* Hack -- notice overflow by forgetting new entry */
+ if (flow_head == flow_tail) flow_head = old_head;
+}
+
+
+/*
+ * Hack -- fill in the "cost" field of every grid that the player
+ * can "reach" with the number of steps needed to reach that grid.
+ * This also yields the "distance" of the player from every grid.
+ *
+ * In addition, mark the "when" of the grids that can reach
+ * the player with the incremented value of "flow_n".
+ *
+ * Hack -- use the "seen" array as a "circular queue".
+ *
+ * We do not need a priority queue because the cost from grid
+ * to grid is always "one" and we process them in order.
+ */
+void update_flow(void)
+{
+ int x, y, d;
+
+ /* Hack -- disabled */
+ if (!flow_by_sound) return;
+
+ /* Paranoia -- make sure the array is empty */
+ if (temp_n) return;
+
+ /* Cycle the old entries (once per 128 updates) */
+ if (flow_n == 255)
+ {
+ /* Rotate the time-stamps */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ int w = cave[y][x].when;
+ cave[y][x].when = (w > 128) ? (w - 128) : 0;
+ }
+ }
+
+ /* Restart */
+ flow_n = 127;
+ }
+
+ /* Start a new flow (never use "zero") */
+ flow_n++;
+
+
+ /* Reset the "queue" */
+ flow_head = flow_tail = 0;
+
+ /* Add the player's grid to the queue */
+ update_flow_aux(p_ptr->py, p_ptr->px, 0);
+
+ /* Now process the queue */
+ while (flow_head != flow_tail)
+ {
+ /* Extract the next entry */
+ y = temp_y[flow_tail];
+ x = temp_x[flow_tail];
+
+ /* Forget that entry */
+ if (++flow_tail == TEMP_MAX) flow_tail = 0;
+
+ /* Add the "children" */
+ for (d = 0; d < 8; d++)
+ {
+ /* Add that child if "legal" */
+ update_flow_aux(y + ddy_ddd[d], x + ddx_ddd[d], cave[y][x].cost + 1);
+ }
+ }
+
+ /* Forget the flow info */
+ flow_head = flow_tail = 0;
+}
+
+
+
+
+
+
+
+/*
+ * Hack -- map the current panel (plus some) ala "magic mapping"
+ */
+void map_area(void)
+{
+ int i, x, y, y1, y2, x1, x2;
+
+ cave_type *c_ptr;
+
+
+ /* Pick an area to map */
+ y1 = panel_row_min - randint(10);
+ y2 = panel_row_max + randint(10);
+ x1 = panel_col_min - randint(20);
+ x2 = panel_col_max + randint(20);
+
+ /* Speed -- shrink to fit legal bounds */
+ if (y1 < 1) y1 = 1;
+ if (y2 > cur_hgt - 2) y2 = cur_hgt - 2;
+ if (x1 < 1) x1 = 1;
+ if (x2 > cur_wid - 2) x2 = cur_wid - 2;
+
+ /* Scan that area */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ c_ptr = &cave[y][x];
+
+ /* All non-walls are "checked" */
+ if (!is_wall(c_ptr))
+ {
+ /* Memorize normal features */
+ if (!cave_plain_floor_grid(c_ptr))
+ {
+ /* Memorize the object */
+ c_ptr->info |= (CAVE_MARK);
+ }
+
+ /* Memorize known walls */
+ for (i = 0; i < 8; i++)
+ {
+ c_ptr = &cave[y + ddy_ddd[i]][x + ddx_ddd[i]];
+
+ /* Memorize walls (etc) */
+ if (is_wall(c_ptr))
+ {
+ /* Memorize the walls */
+ c_ptr->info |= (CAVE_MARK);
+ }
+ }
+ }
+ }
+ }
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+
+
+/*
+ * Light up the dungeon using "clairvoyance"
+ *
+ * This function "illuminates" every grid in the dungeon, memorizes all
+ * "objects", memorizes all grids as with magic mapping, and, under the
+ * standard option settings (view_perma_grids but not view_torch_grids)
+ * memorizes all floor grids too.
+ *
+ * Note that if "view_perma_grids" is not set, we do not memorize floor
+ * grids, since this would defeat the purpose of "view_perma_grids", not
+ * that anyone seems to play without this option.
+ *
+ * Note that if "view_torch_grids" is set, we do not memorize floor grids,
+ * since this would prevent the use of "view_torch_grids" as a method to
+ * keep track of what grids have been observed directly.
+ */
+void wiz_lite(void)
+{
+ int i, y, x;
+
+
+ /* Memorize objects */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ /* Skip dead objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Skip held objects */
+ if (o_ptr->held_m_idx) continue;
+
+ /* Memorize */
+ o_ptr->marked = TRUE;
+ }
+
+ /* Scan all normal grids */
+ for (y = 1; y < cur_hgt - 1; y++)
+ {
+ /* Scan all normal grids */
+ for (x = 1; x < cur_wid - 1; x++)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ if (r_ptr->flags9 & RF9_MIMIC)
+ {
+ object_type *o_ptr = &o_list[m_ptr->hold_o_idx];
+
+ o_ptr->marked = TRUE;
+ }
+ }
+
+ /* Process all non-walls */
+ /* if (c_ptr->feat < FEAT_SECRET) */
+ {
+ /* Scan all neighbors */
+ for (i = 0; i < 9; i++)
+ {
+ int yy = y + ddy_ddd[i];
+ int xx = x + ddx_ddd[i];
+
+ /* Get the grid */
+ c_ptr = &cave[yy][xx];
+
+ /* Perma-lite the grid */
+ c_ptr->info |= (CAVE_GLOW);
+
+ /* Memorize normal features */
+ if (!cave_plain_floor_grid(c_ptr))
+ {
+ /* Memorize the grid */
+ c_ptr->info |= (CAVE_MARK);
+ }
+
+ /* Normally, memorize floors (see above) */
+ if (view_perma_grids && !view_torch_grids)
+ {
+ /* Memorize the grid */
+ c_ptr->info |= (CAVE_MARK);
+ }
+ }
+ }
+ }
+ }
+
+ /* Fully update the visuals */
+ p_ptr->update |= (PU_UN_VIEW | PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+void wiz_lite_extra(void)
+{
+ int y, x;
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave[y][x].info |= (CAVE_GLOW | CAVE_MARK);
+ }
+ }
+ wiz_lite();
+}
+
+/*
+ * Forget the dungeon map (ala "Thinking of Maud...").
+ */
+void wiz_dark(void)
+{
+ int i, y, x;
+
+
+ /* Forget every grid */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Process the grid */
+ c_ptr->info &= ~(CAVE_MARK);
+ }
+ }
+
+ /* Forget all objects */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ /* Skip dead objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Skip held objects */
+ if (o_ptr->held_m_idx) continue;
+
+ /* Forget the object */
+ o_ptr->marked = FALSE;
+ }
+
+ /* Fully update the visuals */
+ p_ptr->update |= (PU_UN_VIEW | PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+
+
+
+
+/*
+ * Change the "feat" flag for a grid, and notice/redraw the grid
+ */
+void cave_set_feat(int y, int x, int feat)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Change the feature */
+ c_ptr->feat = feat;
+
+ /*
+ * Handle "wall/door" grids
+ *
+ * XXX XXX XXX This assumes c_ptr->mimic doesn't mimic terrain
+ * features whose LoS behaviour is different from its own, in
+ * most cases. Level boundaries are the most notable exception,
+ * where "real" terrain is always FEAT_PERM_SOLID, and the fact
+ * is (ab)used to prevent out-of-range access to the cave array.
+ * If we were going to implement an evil dungeon type in which
+ * everything is mimicked, then this function, los(), projectable(),
+ * project_path() and maybe some functions in melee2.c might
+ * better use c_ptr->mimic when it's set -- pelpel
+ */
+ if (!cave_sight_grid(c_ptr))
+ {
+ c_ptr->info |= (CAVE_WALL);
+ }
+
+ /* Handle "floor"/etc grids */
+ else
+ {
+ c_ptr->info &= ~(CAVE_WALL);
+ }
+
+ /* Notice & Redraw */
+ if (character_dungeon)
+ {
+ /* Notice */
+ note_spot(y, x);
+
+ /* Redraw */
+ lite_spot(y, x);
+ }
+}
+
+
+/*
+ * Place floor terrain at (y, x) according to dungeon info
+ */
+void place_floor(int y, int x)
+{
+ cave_set_feat(y, x, floor_type[rand_int(100)]);
+}
+
+/*
+ * This routine is used when the current feature gets convert to a floor and
+ * the possible floor types include glass which is permanent. An unpassable
+ * feature is undesirable, so the glass gets convert to molten glass which
+ * is passable.
+ */
+void place_floor_convert_glass(int y, int x)
+{
+ place_floor(y, x);
+
+ if (cave[y][x].feat == 188) cave[y][x].feat = 103;
+}
+
+/*
+ * Place a cave filler at (y, x)
+ */
+void place_filler(int y, int x)
+{
+ cave_set_feat(y, x, fill_type[rand_int(100)]);
+}
+
+
+/*
+ * Calculate "incremental motion". Used by project() and shoot().
+ * Assumes that (*y,*x) lies on the path from (y1,x1) to (y2,x2).
+ */
+void mmove2(int *y, int *x, int y1, int x1, int y2, int x2)
+{
+ int dy, dx, dist, shift;
+
+ /* Extract the distance travelled */
+ dy = (*y < y1) ? y1 - *y : *y - y1;
+ dx = (*x < x1) ? x1 - *x : *x - x1;
+
+ /* Number of steps */
+ dist = (dy > dx) ? dy : dx;
+
+ /* We are calculating the next location */
+ dist++;
+
+
+ /* Calculate the total distance along each axis */
+ dy = (y2 < y1) ? (y1 - y2) : (y2 - y1);
+ dx = (x2 < x1) ? (x1 - x2) : (x2 - x1);
+
+ /* Paranoia -- Hack -- no motion */
+ if (!dy && !dx) return;
+
+
+ /* Move mostly vertically */
+ if (dy > dx)
+ {
+ /* Extract a shift factor */
+ shift = (dist * dx + (dy - 1) / 2) / dy;
+
+ /* Sometimes move along the minor axis */
+ (*x) = (x2 < x1) ? (x1 - shift) : (x1 + shift);
+
+ /* Always move along major axis */
+ (*y) = (y2 < y1) ? (y1 - dist) : (y1 + dist);
+ }
+
+ /* Move mostly horizontally */
+ else
+ {
+ /* Extract a shift factor */
+ shift = (dist * dy + (dx - 1) / 2) / dx;
+
+ /* Sometimes move along the minor axis */
+ (*y) = (y2 < y1) ? (y1 - shift) : (y1 + shift);
+
+ /* Always move along major axis */
+ (*x) = (x2 < x1) ? (x1 - dist) : (x1 + dist);
+ }
+}
+
+
+
+/*
+ * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
+ * at the final destination, assuming no monster gets in the way.
+ *
+ * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
+ */
+bool_ projectable(int y1, int x1, int y2, int x2)
+{
+ int dist, y, x;
+
+ /* Start at the initial location */
+ y = y1, x = x1;
+
+ /* See "project()" */
+ for (dist = 0; dist <= MAX_RANGE; dist++)
+ {
+ /* Check for arrival at "final target" */
+ /*
+ * NB: this check was AFTER the 'never pass
+ * thru walls' clause, below. Switching them
+ * lets monsters shoot a the player if s/he is
+ * visible but in a wall
+ */
+ if ((x == x2) && (y == y2)) return (TRUE);
+
+ /* Never pass through walls */
+ if (dist && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x))) break;
+
+ /* Calculate the new location */
+ mmove2(&y, &x, y1, x1, y2, x2);
+ }
+
+
+ /* Assume obstruction */
+ return (FALSE);
+}
+
+
+
+
+/*
+ * Standard "find me a location" function
+ *
+ * Obtains a legal location within the given distance of the initial
+ * location, and with "los()" from the source to destination location.
+ *
+ * This function is often called from inside a loop which searches for
+ * locations while increasing the "d" distance.
+ *
+ * Currently the "m" parameter is unused.
+ */
+void scatter(int *yp, int *xp, int y, int x, int d)
+{
+ int nx, ny;
+ int attempts_left = 5000;
+
+ /* Pick a location */
+ while (--attempts_left)
+ {
+ /* Pick a new location */
+ ny = rand_spread(y, d);
+ nx = rand_spread(x, d);
+
+ /* Ignore illegal locations and outer walls */
+ if (!in_bounds(ny, nx)) continue;
+
+ /* Ignore "excessively distant" locations */
+ if ((d > 1) && (distance(y, x, ny, nx) > d)) continue;
+
+ /* Require "line of sight" */
+ if (los(y, x, ny, nx)) break;
+ }
+
+ if (attempts_left > 0)
+ {
+ /* Save the location */
+ (*yp) = ny;
+ (*xp) = nx;
+ }
+}
+
+
+
+
+/*
+ * Track a new monster
+ */
+void health_track(int m_idx)
+{
+ /* Track a new guy */
+ health_who = m_idx;
+
+ /* Redraw (later) */
+ p_ptr->redraw |= (PR_HEALTH);
+}
+
+
+
+/*
+ * Hack -- track the given monster race
+ */
+void monster_race_track(int r_idx, int ego)
+{
+ /* Save this monster ID */
+ monster_race_idx = r_idx;
+ monster_ego_idx = ego;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+}
+
+
+
+/*
+ * Hack -- track the given object kind
+ */
+void object_track(object_type *o_ptr)
+{
+ /* Save this monster ID */
+ tracked_object = o_ptr;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OBJECT);
+}
+
+
+
+/*
+ * Something has happened to disturb the player.
+ *
+ * The first arg indicates a major disturbance, which affects search.
+ *
+ * The second arg is currently unused, but could induce output flush.
+ *
+ * All disturbance cancels repeated commands, resting, and running.
+ */
+void disturb(int stop_search, int unused_flag)
+{
+ /* Unused */
+ unused_flag = unused_flag;
+
+ /* Cancel auto-commands */
+ /* command_new = 0; */
+
+ /* Cancel repeated commands */
+ if (command_rep)
+ {
+ /* Cancel */
+ command_rep = 0;
+
+ /* Redraw the state (later) */
+ p_ptr->redraw |= (PR_STATE);
+ }
+
+ /* Cancel Resting */
+ if (resting)
+ {
+ /* Cancel */
+ resting = 0;
+
+ /* Redraw the state (later) */
+ p_ptr->redraw |= (PR_STATE);
+ }
+
+ /* Cancel running */
+ if (running)
+ {
+ /* Cancel */
+ running = 0;
+
+ /* Calculate torch radius */
+ p_ptr->update |= (PU_TORCH);
+ }
+
+ /* Cancel searching if requested */
+ if (stop_search && p_ptr->searching)
+ {
+ /* Cancel */
+ p_ptr->searching = FALSE;
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+ }
+
+ /* Flush the input if requested */
+ if (flush_disturb) flush();
+}
+
+
+/*
+ * Hack -- Check if a level is a "quest" level
+ */
+int is_quest(int level)
+{
+ int i = random_quest_number();
+
+ /* Check quests */
+ if (p_ptr->inside_quest)
+ return (p_ptr->inside_quest);
+
+ if (i) return (QUEST_RANDOM);
+
+ /* Nope */
+ return (0);
+}
+
+
+/*
+ * Return the index of the random quest on this level
+ * (or zero)
+ */
+int random_quest_number()
+{
+ if ((dun_level >= 1) && (dun_level < MAX_RANDOM_QUEST) &&
+ (dungeon_flags1 & DF1_PRINCIPAL) &&
+ (random_quests[dun_level].type) &&
+ (!random_quests[dun_level].done) &&
+ (!is_randhero(dun_level)))
+ {
+ return dun_level;
+ }
+
+ /* Nope */
+ return 0;
+}
+
+
+/*
+ * handle spell effects
+ */
+int effect_pop()
+{
+ int i;
+
+ for (i = 1; i < MAX_EFFECTS; i++)
+ if (!effects[i].time)
+ return i;
+ return -1;
+}
+
+int new_effect(int type, int dam, int time, int cy, int cx, int rad, s32b flags)
+{
+ int i;
+
+ if ((i = effect_pop()) == -1) return -1;
+
+ effects[i].type = type;
+ effects[i].dam = dam;
+ effects[i].time = time;
+ effects[i].flags = flags;
+ effects[i].cx = cx;
+ effects[i].cy = cy;
+ effects[i].rad = rad;
+ return i;
+}
diff --git a/src/cmd1.c b/src/cmd1.c
new file mode 100644
index 00000000..49c0d38f
--- /dev/null
+++ b/src/cmd1.c
@@ -0,0 +1,5125 @@
+/* File: cmd1.c */
+
+/* Purpose: Movement commands (part 1) */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+#define MAX_VAMPIRIC_DRAIN 100
+
+
+/*
+ * Determine if the player "hits" a monster (normal combat).
+ * Note -- Always miss 5%, always hit 5%, otherwise random.
+ */
+bool_ test_hit_fire(int chance, int ac, int vis)
+{
+ int k;
+
+
+ /* Percentile dice */
+ k = rand_int(100);
+
+ /* Hack -- Instant miss or hit */
+ if (k < 10) return (k < 5);
+
+ /* Never hit */
+ if (chance <= 0) return (FALSE);
+
+ /* Invisible monsters are harder to hit */
+ if (!vis) chance = (chance + 1) / 2;
+
+ /* Power competes against armor */
+ if (rand_int(chance + luck( -10, 10)) < (ac * 3 / 4)) return (FALSE);
+
+ /* Assume hit */
+ return (TRUE);
+}
+
+
+
+/*
+ * Determine if the player "hits" a monster (normal combat).
+ *
+ * Note -- Always miss 5%, always hit 5%, otherwise random.
+ */
+bool_ test_hit_norm(int chance, int ac, int vis)
+{
+ int k;
+
+
+ /* Percentile dice */
+ k = rand_int(100);
+
+ /* Hack -- Instant miss or hit */
+ if (k < 10) return (k < 5);
+
+ /* Wimpy attack never hits */
+ if (chance <= 0) return (FALSE);
+
+ /* Penalize invisible targets */
+ if (!vis) chance = (chance + 1) / 2;
+
+ /* Power must defeat armor */
+ if (rand_int(chance + luck( -10, 10)) < (ac * 3 / 4)) return (FALSE);
+
+ /* Assume hit */
+ return (TRUE);
+}
+
+
+
+/*
+ * Critical hits (from objects thrown by player)
+ * Factor in item weight, total plusses, and player level.
+ */
+s16b critical_shot(int weight, int plus, int dam, int skill)
+{
+ int i, k;
+
+
+ /* Extract "shot" power */
+ i = (weight + ((p_ptr->to_h + plus) * 4) +
+ get_skill_scale(skill, 100));
+ i += 50 * p_ptr->xtra_crit;
+ i += luck( -100, 100);
+
+ /* Critical hit */
+ if (randint(5000) <= i)
+ {
+ k = weight + randint(500);
+
+ if (k < 500)
+ {
+ msg_print("It was a good hit!");
+ dam = 2 * dam + 5;
+ }
+ else if (k < 1000)
+ {
+ msg_print("It was a great hit!");
+ dam = 2 * dam + 10;
+ }
+ else
+ {
+ msg_print("It was a superb hit!");
+ dam = 3 * dam + 15;
+ }
+ }
+
+ return (dam);
+}
+
+/*
+ * Critical hits (by player)
+ *
+ * Factor in weapon weight, total plusses, player level.
+ */
+s16b critical_norm(int weight, int plus, int dam, int weapon_tval, bool_ *done_crit)
+{
+ int i, k, num = randint(5000);
+
+ *done_crit = FALSE;
+
+ /* Extract "blow" power */
+ i = (weight + ((p_ptr->to_h + plus) * 5) +
+ get_skill_scale(p_ptr->melee_style, 150));
+ i += 50 * p_ptr->xtra_crit;
+ if ((weapon_tval == TV_SWORD) && (weight < 50) && get_skill(SKILL_CRITS))
+ {
+ i += get_skill_scale(SKILL_CRITS, 40 * 50);
+ }
+ i += luck( -100, 100);
+
+ /* Force good strikes */
+ if (p_ptr->tim_deadly)
+ {
+ set_tim_deadly(p_ptr->tim_deadly - 1);
+ msg_print("It was a *GREAT* hit!");
+ dam = 3 * dam + 20;
+ *done_crit = TRUE;
+ }
+
+ /* Chance */
+ else if (num <= i)
+ {
+ k = weight + randint(650);
+ if ((weapon_tval == TV_SWORD) && (weight < 50) && get_skill(SKILL_CRITS))
+ {
+ k += get_skill_scale(SKILL_CRITS, 400);
+ }
+
+ if (k < 400)
+ {
+ msg_print("It was a good hit!");
+ dam = 2 * dam + 5;
+ }
+ else if (k < 700)
+ {
+ msg_print("It was a great hit!");
+ dam = 2 * dam + 10;
+ }
+ else if (k < 900)
+ {
+ msg_print("It was a superb hit!");
+ dam = 3 * dam + 15;
+ }
+ else if (k < 1300)
+ {
+ msg_print("It was a *GREAT* hit!");
+ dam = 3 * dam + 20;
+ }
+ else
+ {
+ msg_print("It was a *SUPERB* hit!");
+ dam = ((7 * dam) / 2) + 25;
+ }
+ *done_crit = TRUE;
+ }
+
+ return (dam);
+}
+
+
+
+/*
+ * Extract the "total damage" from a given object hitting a given monster.
+ *
+ * Note that "flasks of oil" do NOT do fire damage, although they
+ * certainly could be made to do so. XXX XXX
+ *
+ * Note that most brands and slays are x3, except Slay Animal (x2),
+ * Slay Evil (x2), and Kill dragon (x5).
+ */
+s16b tot_dam_aux(object_type *o_ptr, int tdam, monster_type *m_ptr,
+ s32b *special)
+{
+ int mult = 1;
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Some "weapons" and "ammo" do extra damage */
+ switch (o_ptr->tval)
+ {
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+ case TV_BOOMERANG:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_DIGGING:
+ {
+ /* Slay Animal */
+ if ((f1 & (TR1_SLAY_ANIMAL)) && (r_ptr->flags3 & (RF3_ANIMAL)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_ANIMAL);
+ }
+
+ if (mult < 2) mult = 2;
+ }
+
+ /* Slay Evil */
+ if ((f1 & (TR1_SLAY_EVIL)) && (r_ptr->flags3 & (RF3_EVIL)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_EVIL);
+ }
+
+ if (mult < 2) mult = 2;
+ }
+
+ /* Slay Undead */
+ if ((f1 & (TR1_SLAY_UNDEAD)) && (r_ptr->flags3 & (RF3_UNDEAD)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_UNDEAD);
+ }
+
+ if (mult < 3) mult = 3;
+ }
+
+ /* Slay Demon */
+ if ((f1 & (TR1_SLAY_DEMON)) && (r_ptr->flags3 & (RF3_DEMON)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_DEMON);
+ }
+
+ if (mult < 3) mult = 3;
+ }
+
+ /* Slay Orc */
+ if ((f1 & (TR1_SLAY_ORC)) && (r_ptr->flags3 & (RF3_ORC)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_ORC);
+ }
+
+ if (mult < 3) mult = 3;
+ }
+
+ /* Slay Troll */
+ if ((f1 & (TR1_SLAY_TROLL)) && (r_ptr->flags3 & (RF3_TROLL)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_TROLL);
+ }
+
+ if (mult < 3) mult = 3;
+ }
+
+ /* Slay Giant */
+ if ((f1 & (TR1_SLAY_GIANT)) && (r_ptr->flags3 & (RF3_GIANT)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_GIANT);
+ }
+
+ if (mult < 3) mult = 3;
+ }
+
+ /* Slay Dragon */
+ if ((f1 & (TR1_SLAY_DRAGON)) && (r_ptr->flags3 & (RF3_DRAGON)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_DRAGON);
+ }
+
+ if (mult < 3) mult = 3;
+ }
+
+ /* Execute Dragon */
+ if ((f1 & (TR1_KILL_DRAGON)) && (r_ptr->flags3 & (RF3_DRAGON)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_DRAGON);
+ }
+
+ if (mult < 5) mult = 5;
+ }
+
+ /* Execute Undead */
+ if ((f5 & (TR5_KILL_UNDEAD)) && (r_ptr->flags3 & (RF3_UNDEAD)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_UNDEAD);
+ }
+
+ if (mult < 5) mult = 5;
+ }
+
+ /* Execute Demon */
+ if ((f5 & (TR5_KILL_DEMON)) && (r_ptr->flags3 & (RF3_DEMON)))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_DEMON);
+ }
+
+ if (mult < 5) mult = 5;
+ }
+
+
+ /* Brand (Acid) */
+ if (f1 & (TR1_BRAND_ACID))
+ {
+ /* Notice immunity */
+ if (r_ptr->flags3 & (RF3_IM_ACID))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_IM_ACID);
+ }
+ }
+
+ /* Notice susceptibility */
+ else if (r_ptr->flags9 & (RF9_SUSCEP_ACID))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags9 |= (RF9_SUSCEP_ACID);
+ }
+ if (mult < 6) mult = 6;
+ }
+
+ /* Otherwise, take the damage */
+ else
+ {
+ if (mult < 3) mult = 3;
+ }
+ }
+
+ /* Brand (Elec) */
+ if (f1 & (TR1_BRAND_ELEC))
+ {
+ /* Notice immunity */
+ if (r_ptr->flags3 & (RF3_IM_ELEC))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_IM_ELEC);
+ }
+ }
+
+ /* Notice susceptibility */
+ else if (r_ptr->flags9 & (RF9_SUSCEP_ELEC))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags9 |= (RF9_SUSCEP_ELEC);
+ }
+ if (mult < 6) mult = 6;
+ }
+
+ /* Otherwise, take the damage */
+ else
+ {
+ if (mult < 3) mult = 3;
+ }
+ }
+
+ /* Brand (Fire) */
+ if (f1 & (TR1_BRAND_FIRE))
+ {
+ /* Notice immunity */
+ if (r_ptr->flags3 & (RF3_IM_FIRE))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_IM_FIRE);
+ }
+ }
+
+ /* Notice susceptibility */
+ else if (r_ptr->flags3 & (RF3_SUSCEP_FIRE))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_SUSCEP_FIRE);
+ }
+ if (mult < 6) mult = 6;
+ }
+
+ /* Otherwise, take the damage */
+ else
+ {
+ if (mult < 3) mult = 3;
+ }
+ }
+
+ /* Brand (Cold) */
+ if (f1 & (TR1_BRAND_COLD))
+ {
+ /* Notice immunity */
+ if (r_ptr->flags3 & (RF3_IM_COLD))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_IM_COLD);
+ }
+ }
+
+ /* Notice susceptibility */
+ else if (r_ptr->flags3 & (RF3_SUSCEP_COLD))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_SUSCEP_COLD);
+ }
+ if (mult < 6) mult = 6;
+ }
+
+ /* Otherwise, take the damage */
+ else
+ {
+ if (mult < 3) mult = 3;
+ }
+ }
+
+ /* Brand (Poison) */
+ if (f1 & (TR1_BRAND_POIS) || (p_ptr->tim_poison))
+ {
+ /* Notice immunity */
+ if (r_ptr->flags3 & (RF3_IM_POIS))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_IM_POIS);
+ }
+ }
+
+ /* Notice susceptibility */
+ else if (r_ptr->flags9 & (RF9_SUSCEP_POIS))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags9 |= (RF9_SUSCEP_POIS);
+ }
+ if (mult < 6) mult = 6;
+ if (magik(95)) *special |= SPEC_POIS;
+ }
+
+ /* Otherwise, take the damage */
+ else
+ {
+ if (mult < 3) mult = 3;
+ if (magik(50)) *special |= SPEC_POIS;
+ }
+ }
+
+ /* Wounding */
+ if (f5 & (TR5_WOUNDING))
+ {
+ /* Notice immunity */
+ if (r_ptr->flags8 & (RF8_NO_CUT))
+ {
+ if (m_ptr->ml)
+ {
+ r_info[m_ptr->r_idx].r_flags8 |= (RF8_NO_CUT);
+ }
+ }
+
+ /* Otherwise, take the damage */
+ else
+ {
+ if (magik(50)) *special |= SPEC_CUT;
+ }
+ }
+ break;
+ }
+ }
+
+
+ /* Return the total damage */
+ return (tdam * mult);
+}
+
+
+/*
+ * Search for hidden things
+ */
+void search(void)
+{
+ int y, x, chance;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ cave_type *c_ptr;
+
+
+ /* Start with base search ability */
+ chance = p_ptr->skill_srh;
+
+ /* Penalize various conditions */
+ if (p_ptr->blind || no_lite()) chance = chance / 10;
+ if (p_ptr->confused || p_ptr->image) chance = chance / 10;
+
+ /* Search the nearby grids, which are always in bounds */
+ for (y = (p_ptr->py - 1); y <= (p_ptr->py + 1); y++)
+ {
+ for (x = (p_ptr->px - 1); x <= (p_ptr->px + 1); x++)
+ {
+ /* Sometimes, notice things */
+ if (rand_int(100) < chance)
+ {
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Invisible trap */
+ if ((c_ptr->t_idx != 0) && !(c_ptr->info & CAVE_TRDT))
+ {
+ /* Pick a trap */
+ pick_trap(y, x);
+
+ /* Message */
+ msg_print("You have found a trap.");
+
+ /* Disturb */
+ disturb(0, 0);
+ }
+
+ /* Secret door */
+ if (c_ptr->feat == FEAT_SECRET)
+ {
+ /* Message */
+ msg_print("You have found a secret door.");
+
+ /* Pick a door XXX XXX XXX */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
+ cave[y][x].mimic = 0;
+ lite_spot(y, x);
+
+ /* Disturb */
+ disturb(0, 0);
+ }
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx;
+ this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Skip non-chests */
+ if (o_ptr->tval != TV_CHEST) continue;
+
+ /* Skip non-trapped chests */
+ if (!o_ptr->pval) continue;
+
+ /* Identify once */
+ if (!object_known_p(o_ptr))
+ {
+ /* Message */
+ msg_print("You have discovered a trap on the chest!");
+
+ /* Know the trap */
+ object_known(o_ptr);
+
+ /* Notice it */
+ disturb(0, 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+
+/*
+ * Player "wants" to pick up an object or gold.
+ * Note that we ONLY handle things that can be picked up.
+ * See "move_player()" for handling of other things.
+ */
+void carry(int pickup)
+{
+ if (!p_ptr->disembodied)
+ {
+ py_pickup_floor(pickup);
+ }
+}
+
+
+/*
+ * Handle player hitting a real trap
+ */
+static void hit_trap(void)
+{
+ bool_ ident = FALSE;
+
+ cave_type *c_ptr;
+
+
+ /* Disturb the player */
+ disturb(0, 0);
+
+ /* Get the cave grid */
+ c_ptr = &cave[p_ptr->py][p_ptr->px];
+ if (c_ptr->t_idx != 0)
+ {
+ ident = player_activate_trap_type(p_ptr->py, p_ptr->px, NULL, -1);
+ if (ident)
+ {
+ t_info[c_ptr->t_idx].ident = TRUE;
+ msg_format("You identified the trap as %s.",
+ t_name + t_info[c_ptr->t_idx].name);
+ }
+ }
+}
+
+
+void touch_zap_player(monster_type *m_ptr)
+{
+ int aura_damage = 0;
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+
+ if (r_ptr->flags2 & (RF2_AURA_FIRE))
+ {
+ if (!(p_ptr->immune_fire))
+ {
+ char aura_dam[80];
+
+ aura_damage =
+ damroll(1 + (m_ptr->level / 26), 1 + (m_ptr->level / 17));
+
+ /* Hack -- Get the "died from" name */
+ monster_desc(aura_dam, m_ptr, 0x88);
+
+ msg_print("You are suddenly very hot!");
+
+ if (p_ptr->oppose_fire) aura_damage = (aura_damage + 2) / 3;
+ if (p_ptr->resist_fire) aura_damage = (aura_damage + 2) / 3;
+ if (p_ptr->sensible_fire) aura_damage = (aura_damage + 2) * 2;
+
+ take_hit(aura_damage, aura_dam);
+ r_ptr->r_flags2 |= RF2_AURA_FIRE;
+ handle_stuff();
+ }
+ }
+
+
+ if (r_ptr->flags2 & (RF2_AURA_ELEC))
+ {
+ if (!(p_ptr->immune_elec))
+ {
+ char aura_dam[80];
+
+ aura_damage =
+ damroll(1 + (m_ptr->level / 26), 1 + (m_ptr->level / 17));
+
+ /* Hack -- Get the "died from" name */
+ monster_desc(aura_dam, m_ptr, 0x88);
+
+ if (p_ptr->oppose_elec) aura_damage = (aura_damage + 2) / 3;
+ if (p_ptr->resist_elec) aura_damage = (aura_damage + 2) / 3;
+
+ msg_print("You get zapped!");
+ take_hit(aura_damage, aura_dam);
+ r_ptr->r_flags2 |= RF2_AURA_ELEC;
+ handle_stuff();
+ }
+ }
+}
+
+
+/*
+ * Carried monster can attack too.
+ * Based on monst_attack_monst.
+ */
+static void carried_monster_attack(s16b m_idx, bool_ *fear, bool_ *mdeath,
+ int x, int y)
+{
+ monster_type *t_ptr = &m_list[m_idx];
+
+ monster_race *r_ptr;
+
+ monster_race *tr_ptr = race_inf(t_ptr);
+
+ int ap_cnt;
+
+ int ac, rlev, pt;
+
+ char t_name[80];
+
+ cptr sym_name = symbiote_name(TRUE);
+
+ char temp[80];
+
+ bool_ blinked = FALSE, touched = FALSE;
+
+ byte y_saver = t_ptr->fy;
+
+ byte x_saver = t_ptr->fx;
+
+ object_type *o_ptr;
+
+
+ /* Get the carried monster */
+ o_ptr = &p_ptr->inventory[INVEN_CARRY];
+ if (!o_ptr->k_idx) return;
+
+ r_ptr = &r_info[o_ptr->pval];
+
+ /* Not allowed to attack */
+ if (r_ptr->flags1 & RF1_NEVER_BLOW) return;
+
+ /* Total armor */
+ ac = t_ptr->ac;
+
+ /* Extract the effective monster level */
+ rlev = ((o_ptr->elevel >= 1) ? o_ptr->elevel : 1);
+
+ /* Get the monster name (or "it") */
+ monster_desc(t_name, t_ptr, 0);
+
+ /* Assume no blink */
+ blinked = FALSE;
+
+ if (!t_ptr->ml)
+ {
+ msg_print("You hear noise.");
+ }
+
+ /* Scan through all four blows */
+ for (ap_cnt = 0; ap_cnt < 4; ap_cnt++)
+ {
+ bool_ visible = FALSE;
+ bool_ obvious = FALSE;
+
+ int power = 0;
+ int damage = 0;
+
+ cptr act = NULL;
+
+ /* Extract the attack infomation */
+ int effect = r_ptr->blow[ap_cnt].effect;
+ int method = r_ptr->blow[ap_cnt].method;
+ int d_dice = r_ptr->blow[ap_cnt].d_dice;
+ int d_side = r_ptr->blow[ap_cnt].d_side;
+
+ /* Stop attacking if the target dies! */
+ if (t_ptr->fx != x_saver || t_ptr->fy != y_saver)
+ break;
+
+ /* Hack -- no more attacks */
+ if (!method) break;
+
+ if (blinked) /* Stop! */
+ {
+ /* break; */
+ }
+
+ /* Extract visibility (before blink) */
+ visible = TRUE;
+
+ /* Extract the attack "power" */
+ power = get_attack_power(effect);
+
+ /* Monster hits */
+ if (!effect || check_hit2(power, rlev, ac))
+ {
+ /* Always disturbing */
+ disturb(1, 0);
+
+ /* Describe the attack method */
+ switch (method)
+ {
+ case RBM_HIT:
+ {
+ act = "hits %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_TOUCH:
+ {
+ act = "touches %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_PUNCH:
+ {
+ act = "punches %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_KICK:
+ {
+ act = "kicks %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CLAW:
+ {
+ act = "claws %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_BITE:
+ {
+ act = "bites %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_STING:
+ {
+ act = "stings %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_XXX1:
+ {
+ act = "XXX1's %s.";
+ break;
+ }
+
+ case RBM_BUTT:
+ {
+ act = "butts %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CRUSH:
+ {
+ act = "crushes %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_ENGULF:
+ {
+ act = "engulfs %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CHARGE:
+ {
+ act = "charges %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CRAWL:
+ {
+ act = "crawls on %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_DROOL:
+ {
+ act = "drools on %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_SPIT:
+ {
+ act = "spits on %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_GAZE:
+ {
+ act = "gazes at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_WAIL:
+ {
+ act = "wails at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_SPORE:
+ {
+ act = "releases spores at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_XXX4:
+ {
+ act = "projects XXX4's at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_BEG:
+ {
+ act = "begs %s for money.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+
+ case RBM_INSULT:
+ {
+ act = "insults %s.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+
+ case RBM_MOAN:
+ {
+ act = "moans at %s.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+
+ case RBM_SHOW:
+ {
+ act = "sings to %s.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+ }
+
+ /* Message */
+ if (act)
+ {
+ strfmt(temp, act, t_name);
+ if (t_ptr->ml)
+ msg_format("%s %s", sym_name, temp);
+
+ }
+
+ /* Hack -- assume all attacks are obvious */
+ obvious = TRUE;
+
+ /* Roll out the damage */
+ damage = damroll(d_dice, d_side);
+
+ pt = GF_MISSILE;
+
+ /* Apply appropriate damage */
+ switch (effect)
+ {
+ case 0:
+ {
+ damage = 0;
+ pt = 0;
+ break;
+ }
+
+ case RBE_HURT:
+ case RBE_SANITY:
+ {
+ damage -= (damage * ((ac < 150) ? ac : 150) / 250);
+ break;
+ }
+
+ case RBE_POISON:
+ case RBE_DISEASE:
+ {
+ pt = GF_POIS;
+ break;
+ }
+
+ case RBE_UN_BONUS:
+ case RBE_UN_POWER:
+ case RBE_ABOMINATION:
+ {
+ pt = GF_DISENCHANT;
+ break;
+ }
+
+ case RBE_EAT_FOOD:
+ case RBE_EAT_LITE:
+ {
+ pt = damage = 0;
+ break;
+ }
+
+ case RBE_EAT_ITEM:
+ case RBE_EAT_GOLD:
+ {
+ pt = damage = 0;
+ if (randint(2) == 1) blinked = TRUE;
+ break;
+ }
+
+ case RBE_ACID:
+ {
+ pt = GF_ACID;
+ break;
+ }
+
+ case RBE_ELEC:
+ {
+ pt = GF_ELEC;
+ break;
+ }
+
+ case RBE_FIRE:
+ {
+ pt = GF_FIRE;
+ break;
+ }
+
+ case RBE_COLD:
+ {
+ pt = GF_COLD;
+ break;
+ }
+
+ case RBE_BLIND:
+ {
+ break;
+ }
+
+ case RBE_CONFUSE:
+ case RBE_HALLU:
+ {
+ pt = GF_CONFUSION;
+ break;
+ }
+
+ case RBE_TERRIFY:
+ {
+ pt = GF_TURN_ALL;
+ break;
+ }
+
+ case RBE_PARALYZE:
+ {
+ pt = GF_OLD_SLEEP; /* sort of close... */
+ break;
+ }
+
+ case RBE_LOSE_STR:
+ case RBE_LOSE_INT:
+ case RBE_LOSE_WIS:
+ case RBE_LOSE_DEX:
+ case RBE_LOSE_CON:
+ case RBE_LOSE_CHR:
+ case RBE_LOSE_ALL:
+ case RBE_PARASITE:
+ {
+ break;
+ }
+
+ case RBE_SHATTER:
+ {
+ if (damage > 23)
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(p_ptr->py, p_ptr->px, 8);
+ }
+ break;
+ }
+
+ case RBE_EXP_10:
+ case RBE_EXP_20:
+ case RBE_EXP_40:
+ case RBE_EXP_80:
+ {
+ pt = GF_NETHER;
+ break;
+ }
+
+ case RBE_TIME:
+ {
+ pt = GF_TIME;
+ break;
+ }
+
+ default:
+ {
+ pt = 0;
+ break;
+ }
+ }
+
+ if (pt)
+ {
+ /* Do damage if not exploding */
+ project(0, 0, t_ptr->fy, t_ptr->fx,
+ (pt == GF_OLD_SLEEP ? r_ptr->level : damage), pt,
+ PROJECT_KILL | PROJECT_STOP);
+
+ if (touched)
+ {
+ /* Aura fire */
+ if ((tr_ptr->flags2 & RF2_AURA_FIRE) &&
+ !(r_ptr->flags3 & RF3_IM_FIRE))
+ {
+ if (t_ptr->ml)
+ {
+ blinked = FALSE;
+ msg_format("You are suddenly very hot!");
+ if (t_ptr->ml)
+ tr_ptr->r_flags2 |= RF2_AURA_FIRE;
+ }
+ project(m_idx, 0, p_ptr->py, p_ptr->px,
+ damroll(1 + ((t_ptr->level) / 26),
+ 1 + ((t_ptr->level) / 17)),
+ GF_FIRE, PROJECT_KILL | PROJECT_STOP);
+ }
+
+ /* Aura elec */
+ if ((tr_ptr->flags2 & (RF2_AURA_ELEC)) &&
+ !(r_ptr->flags3 & (RF3_IM_ELEC)))
+ {
+ if (t_ptr->ml)
+ {
+ blinked = FALSE;
+ msg_format("You get zapped!");
+ if (t_ptr->ml)
+ tr_ptr->r_flags2 |= RF2_AURA_ELEC;
+ }
+ project(m_idx, 0, p_ptr->py, p_ptr->px,
+ damroll(1 + ((t_ptr->level) / 26),
+ 1 + ((t_ptr->level) / 17)),
+ GF_ELEC, PROJECT_KILL | PROJECT_STOP);
+ }
+ }
+ }
+ }
+
+ /* Monster missed player */
+ else
+ {
+ /* Analyze failed attacks */
+ switch (method)
+ {
+ case RBM_HIT:
+ case RBM_TOUCH:
+ case RBM_PUNCH:
+ case RBM_KICK:
+ case RBM_CLAW:
+ case RBM_BITE:
+ case RBM_STING:
+ case RBM_XXX1:
+ case RBM_BUTT:
+ case RBM_CRUSH:
+ case RBM_ENGULF:
+ case RBM_CHARGE:
+ {
+ /* Disturb */
+ disturb(1, 0);
+
+ /* Message */
+ msg_format("%s misses %s.", sym_name, t_name);
+ break;
+ }
+ }
+ }
+
+
+ /* Analyze "visible" monsters only */
+ if (visible)
+ {
+ /* Count "obvious" attacks (and ones that cause damage) */
+ if (obvious || damage || (r_ptr->r_blows[ap_cnt] > 10))
+ {
+ /* Count attacks of this type */
+ if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR)
+ {
+ r_ptr->r_blows[ap_cnt]++;
+ }
+ }
+ }
+ }
+
+ /* Blink away */
+ if (blinked)
+ {
+ msg_format("You and %s flee laughing!", symbiote_name(FALSE));
+
+ teleport_player(MAX_SIGHT * 2 + 5);
+ }
+}
+
+/*
+ * Carried monster can attack too.
+ * Based on monst_attack_monst.
+ */
+static void incarnate_monster_attack(s16b m_idx, bool_ *fear, bool_ *mdeath,
+ int x, int y)
+{
+ monster_type *t_ptr = &m_list[m_idx];
+
+ monster_race *r_ptr;
+
+ monster_race *tr_ptr = race_inf(t_ptr);
+
+ int ap_cnt;
+
+ int ac, rlev, pt;
+
+ char t_name[80];
+
+ char temp[80];
+
+ bool_ blinked = FALSE, touched = FALSE;
+
+ byte y_saver = t_ptr->fy;
+
+ byte x_saver = t_ptr->fx;
+
+
+ if (!p_ptr->body_monster) return;
+
+ r_ptr = race_info_idx(p_ptr->body_monster, 0);
+
+ /* Not allowed to attack */
+ if (r_ptr->flags1 & RF1_NEVER_BLOW) return;
+
+ /* Total armor */
+ ac = t_ptr->ac;
+
+ /* Extract the effective monster level */
+ rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1);
+
+ /* Get the monster name (or "it") */
+ monster_desc(t_name, t_ptr, 0);
+
+ /* Assume no blink */
+ blinked = FALSE;
+
+ if (!t_ptr->ml)
+ {
+ msg_print("You hear noise.");
+ }
+
+ /* Scan through all four blows */
+ for (ap_cnt = 0; ap_cnt < (p_ptr->num_blow > 4) ? 4 : p_ptr->num_blow;
+ ap_cnt++)
+ {
+ bool_ visible = FALSE;
+ bool_ obvious = FALSE;
+
+ int power = 0;
+ int damage = 0;
+
+ cptr act = NULL;
+
+ /* Extract the attack infomation */
+ int effect = r_ptr->blow[ap_cnt].effect;
+ int method = r_ptr->blow[ap_cnt].method;
+ int d_dice = r_ptr->blow[ap_cnt].d_dice;
+ int d_side = r_ptr->blow[ap_cnt].d_side;
+
+ /* Stop attacking if the target dies! */
+ if (t_ptr->fx != x_saver || t_ptr->fy != y_saver)
+ break;
+
+ /* Hack -- no more attacks */
+ if (!method) break;
+
+ if (blinked) /* Stop! */
+ {
+ /* break; */
+ }
+
+ /* Extract visibility (before blink) */
+ visible = TRUE;
+
+ /* Extract the attack "power" */
+ effect = get_attack_power(effect);
+
+ /* Monster hits */
+ if (!effect || check_hit2(power, rlev, ac))
+ {
+ /* Always disturbing */
+ disturb(1, 0);
+
+ /* Describe the attack method */
+ switch (method)
+ {
+ case RBM_HIT:
+ {
+ act = "hit %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_TOUCH:
+ {
+ act = "touch %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_PUNCH:
+ {
+ act = "punch %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_KICK:
+ {
+ act = "kick %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CLAW:
+ {
+ act = "claw %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_BITE:
+ {
+ act = "bite %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_STING:
+ {
+ act = "sting %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_XXX1:
+ {
+ act = "XXX1's %s.";
+ break;
+ }
+
+ case RBM_BUTT:
+ {
+ act = "butt %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CRUSH:
+ {
+ act = "crush %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_ENGULF:
+ {
+ act = "engulf %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CHARGE:
+ {
+ act = "charge %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CRAWL:
+ {
+ act = "crawl on %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_DROOL:
+ {
+ act = "drool on %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_SPIT:
+ {
+ act = "spit on %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_GAZE:
+ {
+ act = "gaze at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_WAIL:
+ {
+ act = "wail at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_SPORE:
+ {
+ act = "release spores at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_XXX4:
+ {
+ act = "project XXX4's at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_BEG:
+ {
+ act = "beg %s for money.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+
+ case RBM_INSULT:
+ {
+ act = "insult %s.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+
+ case RBM_MOAN:
+ {
+ act = "moan at %s.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+
+ case RBM_SHOW:
+ {
+ act = "sing to %s.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+ }
+
+ /* Message */
+ if (act)
+ {
+ strfmt(temp, act, t_name);
+ if (t_ptr->ml)
+ msg_format("You %s", temp);
+
+ }
+
+ /* Hack -- assume all attacks are obvious */
+ obvious = TRUE;
+
+ /* Roll out the damage */
+ damage = damroll(d_dice, d_side) + p_ptr->to_d;
+
+ pt = GF_MISSILE;
+
+ /* Apply appropriate damage */
+ switch (effect)
+ {
+ case 0:
+ {
+ damage = 0;
+ pt = 0;
+ break;
+ }
+
+ case RBE_HURT:
+ case RBE_SANITY:
+ {
+ damage -= (damage * ((ac < 150) ? ac : 150) / 250);
+ break;
+ }
+
+ case RBE_POISON:
+ case RBE_DISEASE:
+ {
+ pt = GF_POIS;
+ break;
+ }
+
+ case RBE_UN_BONUS:
+ case RBE_UN_POWER:
+ {
+ pt = GF_DISENCHANT;
+ break;
+ }
+
+ case RBE_EAT_FOOD:
+ case RBE_EAT_LITE:
+ {
+ pt = damage = 0;
+ break;
+ }
+
+ case RBE_EAT_ITEM:
+ case RBE_EAT_GOLD:
+ {
+ pt = damage = 0;
+ if (randint(2) == 1) blinked = TRUE;
+ break;
+ }
+
+ case RBE_ACID:
+ {
+ pt = GF_ACID;
+ break;
+ }
+
+ case RBE_ELEC:
+ {
+ pt = GF_ELEC;
+ break;
+ }
+
+ case RBE_FIRE:
+ {
+ pt = GF_FIRE;
+ break;
+ }
+
+ case RBE_COLD:
+ {
+ pt = GF_COLD;
+ break;
+ }
+
+ case RBE_BLIND:
+ {
+ break;
+ }
+
+ case RBE_HALLU:
+ case RBE_CONFUSE:
+ {
+ pt = GF_CONFUSION;
+ break;
+ }
+
+ case RBE_TERRIFY:
+ {
+ pt = GF_TURN_ALL;
+ break;
+ }
+
+ case RBE_PARALYZE:
+ {
+ pt = GF_OLD_SLEEP; /* sort of close... */
+ break;
+ }
+
+ case RBE_LOSE_STR:
+ case RBE_LOSE_INT:
+ case RBE_LOSE_WIS:
+ case RBE_LOSE_DEX:
+ case RBE_LOSE_CON:
+ case RBE_LOSE_CHR:
+ case RBE_LOSE_ALL:
+ case RBE_PARASITE:
+ {
+ break;
+ }
+
+ case RBE_SHATTER:
+ {
+ if (damage > 23)
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(p_ptr->py, p_ptr->px, 8);
+ }
+ break;
+ }
+
+ case RBE_EXP_10:
+ case RBE_EXP_20:
+ case RBE_EXP_40:
+ case RBE_EXP_80:
+ {
+ pt = GF_NETHER;
+ break;
+ }
+
+ case RBE_TIME:
+ {
+ pt = GF_TIME;
+ break;
+ }
+
+ default:
+ {
+ pt = 0;
+ break;
+ }
+ }
+
+ if (pt)
+ {
+ /* Do damage if not exploding */
+ project(0, 0, t_ptr->fy, t_ptr->fx,
+ (pt == GF_OLD_SLEEP ? p_ptr->lev * 2 : damage), pt,
+ PROJECT_KILL | PROJECT_STOP);
+
+ if (touched)
+ {
+ /* Aura fire */
+ if ((tr_ptr->flags2 & RF2_AURA_FIRE) &&
+ !(r_ptr->flags3 & RF3_IM_FIRE))
+ {
+ if (t_ptr->ml)
+ {
+ blinked = FALSE;
+ msg_format("You are suddenly very hot!");
+ if (t_ptr->ml)
+ tr_ptr->r_flags2 |= RF2_AURA_FIRE;
+ }
+ project(m_idx, 0, p_ptr->py, p_ptr->px,
+ damroll(1 + ((t_ptr->level) / 26),
+ 1 + ((t_ptr->level) / 17)),
+ GF_FIRE, PROJECT_KILL | PROJECT_STOP);
+ }
+
+ /* Aura elec */
+ if ((tr_ptr->flags2 & (RF2_AURA_ELEC)) &&
+ !(r_ptr->flags3 & (RF3_IM_ELEC)))
+ {
+ if (t_ptr->ml)
+ {
+ blinked = FALSE;
+ msg_format("You get zapped!");
+ if (t_ptr->ml)
+ tr_ptr->r_flags2 |= RF2_AURA_ELEC;
+ }
+ project(m_idx, 0, p_ptr->py, p_ptr->px,
+ damroll(1 + ((t_ptr->level) / 26),
+ 1 + ((t_ptr->level) / 17)),
+ GF_ELEC, PROJECT_KILL | PROJECT_STOP);
+ }
+
+ }
+ }
+ }
+
+ /* Monster missed player */
+ else
+ {
+ /* Analyze failed attacks */
+ switch (method)
+ {
+ case RBM_HIT:
+ case RBM_TOUCH:
+ case RBM_PUNCH:
+ case RBM_KICK:
+ case RBM_CLAW:
+ case RBM_BITE:
+ case RBM_STING:
+ case RBM_XXX1:
+ case RBM_BUTT:
+ case RBM_CRUSH:
+ case RBM_ENGULF:
+ case RBM_CHARGE:
+ {
+ /* Disturb */
+ disturb(1, 0);
+
+ /* Message */
+ msg_format("You miss %s.", t_name);
+
+ break;
+ }
+ }
+ }
+
+
+ /* Analyze "visible" monsters only */
+ if (visible)
+ {
+ /* Count "obvious" attacks (and ones that cause damage) */
+ if (obvious || damage || (r_ptr->r_blows[ap_cnt] > 10))
+ {
+ /* Count attacks of this type */
+ if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR)
+ {
+ r_ptr->r_blows[ap_cnt]++;
+ }
+ }
+ }
+ }
+
+ /* Blink away */
+ if (blinked)
+ {
+ msg_print("You flee laughing!");
+
+ teleport_player(MAX_SIGHT * 2 + 5);
+ }
+}
+
+
+/*
+ * Fetch an attack description from dam_*.txt files.
+ */
+
+static void flavored_attack(int percent, char *output)
+{
+ int insanity = (p_ptr->msane - p_ptr->csane) * 100 / p_ptr->msane;
+ bool_ insane = (rand_int(100) < insanity);
+
+ if (percent < 5)
+ {
+ if (!insane)
+ strcpy(output, "You scratch %s.");
+ else
+ get_rnd_line("dam_none.txt", output);
+
+ }
+ else if (percent < 30)
+ {
+ if (!insane)
+ strcpy(output, "You hit %s.");
+ else
+ get_rnd_line("dam_med.txt", output);
+ }
+ else if (percent < 60)
+ {
+ if (!insane)
+ strcpy(output, "You wound %s.");
+ else
+ get_rnd_line("dam_lots.txt", output);
+ }
+ else if (percent < 95)
+ {
+ if (!insane)
+ strcpy(output, "You cripple %s.");
+ else
+ get_rnd_line("dam_huge.txt", output);
+
+ }
+ else
+ {
+ if (!insane)
+ strcpy(output, "You demolish %s.");
+ else
+ get_rnd_line("dam_xxx.txt", output);
+ }
+}
+
+
+/*
+ * Apply the special effects of an attack
+ */
+void attack_special(monster_type *m_ptr, s32b special, int dam)
+{
+ char m_name[80];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+
+ /* Extract monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Special - Cut monster */
+ if (special & SPEC_CUT)
+ {
+ /* Cut the monster */
+ if (r_ptr->flags8 & (RF8_NO_CUT))
+ {
+ if (m_ptr->ml)
+ {
+ r_info[m_ptr->r_idx].r_flags8 |= (RF8_NO_CUT);
+ }
+ }
+ else if (rand_int(100) >= r_ptr->level)
+ {
+ /* Already partially poisoned */
+ if (m_ptr->bleeding) msg_format("%^s is bleeding more strongly.",
+ m_name);
+ /* Was not poisoned */
+ else
+ msg_format("%^s is bleeding.", m_name);
+
+ m_ptr->bleeding += dam * 2;
+ }
+ }
+
+ /* Special - Poison monster */
+ if (special & SPEC_POIS)
+ {
+ /* Poison the monster */
+ if (r_ptr->flags3 & (RF3_IM_POIS))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_IM_POIS);
+ }
+ }
+ /* Notice susceptibility */
+ else if (r_ptr->flags9 & (RF9_SUSCEP_POIS))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags9 |= (RF9_SUSCEP_POIS);
+ }
+ /* Already partially poisoned */
+ if (m_ptr->poisoned) msg_format("%^s is more poisoned.", m_name);
+ /* Was not poisoned */
+ else
+ msg_format("%^s is poisoned.", m_name);
+
+ m_ptr->poisoned += dam * 2;
+ }
+ else if (rand_int(100) >= r_ptr->level)
+ {
+ /* Already partially poisoned */
+ if (m_ptr->poisoned) msg_format("%^s is more poisoned.", m_name);
+ /* Was not poisoned */
+ else
+ msg_format("%^s is poisoned.", m_name);
+
+ m_ptr->poisoned += dam;
+ }
+ }
+}
+
+
+/*
+ * Bare handed attacks
+ */
+static void py_attack_hand(int *k, monster_type *m_ptr, s32b *special)
+{
+ s16b special_effect = 0, stun_effect = 0, times = 0;
+ martial_arts *ma_ptr, *old_ptr, *blow_table = ma_blows;
+ int resist_stun = 0, max = MAX_MA;
+ monster_race *r_ptr = race_inf(m_ptr);
+ char m_name[80];
+ bool_ desc = FALSE;
+ bool_ done_crit;
+ int plev = p_ptr->lev;
+
+ if ((!p_ptr->body_monster) && (p_ptr->mimic_form == resolve_mimic_name("Bear")) &&
+ (p_ptr->melee_style == SKILL_BEAR))
+ {
+ blow_table = bear_blows;
+ max = MAX_BEAR;
+ plev = get_skill(SKILL_BEAR);
+ }
+ if (p_ptr->melee_style == SKILL_HAND)
+ {
+ blow_table = ma_blows;
+ max = MAX_MA;
+ plev = get_skill(SKILL_HAND);
+ }
+ ma_ptr = &blow_table[0];
+ old_ptr = &blow_table[0];
+
+ /* Extract monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0);
+
+ if (r_ptr->flags1 & RF1_UNIQUE) resist_stun += 88;
+ if (r_ptr->flags3 & RF3_NO_CONF) resist_stun += 44;
+ if (r_ptr->flags3 & RF3_NO_SLEEP) resist_stun += 44;
+ if ((r_ptr->flags3 & RF3_UNDEAD) ||
+ (r_ptr->flags3 & RF3_NONLIVING)) resist_stun += 88;
+
+ if (plev)
+ {
+ for (times = 0; times < (plev < 7 ? 1 : plev / 7); times++)
+ {
+ do
+ {
+ ma_ptr = &blow_table[(randint(max)) - 1];
+ }
+ while ((ma_ptr->min_level > plev) || (randint(plev) < ma_ptr->chance));
+
+ /* keep the highest level attack available we found */
+ if ((ma_ptr->min_level > old_ptr->min_level) &&
+ !(p_ptr->stun || p_ptr->confused))
+ {
+ old_ptr = ma_ptr;
+
+ if (wizard && cheat_xtra)
+ {
+ msg_print("Attack re-selected.");
+ }
+ }
+ else
+ {
+ ma_ptr = old_ptr;
+ }
+ }
+ }
+
+ *k = damroll(ma_ptr->dd, ma_ptr->ds);
+
+ if (ma_ptr->effect & MA_KNEE)
+ {
+ if (r_ptr->flags1 & RF1_MALE)
+ {
+ if (!desc) msg_format("You hit %s in the groin with your knee!",
+ m_name);
+ sound(SOUND_PAIN);
+ special_effect = MA_KNEE;
+ }
+ else if (!desc) msg_format(ma_ptr->desc, m_name);
+
+ desc = TRUE;
+ }
+ if (ma_ptr->effect & MA_FULL_SLOW)
+ {
+ special_effect = MA_SLOW;
+ if (!desc) msg_format(ma_ptr->desc, m_name);
+
+ desc = TRUE;
+ }
+ if (ma_ptr->effect & MA_SLOW)
+ {
+ if (!
+ ((r_ptr->flags1 & RF1_NEVER_MOVE) ||
+ strchr("UjmeEv$,DdsbBFIJQSXclnw!=?", r_ptr->d_char)))
+ {
+ if (!desc) msg_format("You kick %s in the ankle.", m_name);
+ special_effect = MA_SLOW;
+ }
+ else if (!desc) msg_format(ma_ptr->desc, m_name);
+
+ desc = TRUE;
+ }
+ if (ma_ptr->effect & MA_STUN)
+ {
+ if (ma_ptr->power)
+ {
+ stun_effect = (ma_ptr->power / 2) + randint(ma_ptr->power / 2);
+ }
+
+ if (!desc) msg_format(ma_ptr->desc, m_name);
+ desc = TRUE;
+ }
+ if (ma_ptr->effect & MA_WOUND)
+ {
+ if (magik(ma_ptr->power))
+ {
+ *special |= SPEC_CUT;
+ }
+ if (!desc) msg_format(ma_ptr->desc, m_name);
+ desc = TRUE;
+ }
+
+ *k = critical_norm(plev * (randint(10)), ma_ptr->min_level, *k, -1, &done_crit);
+
+ if ((special_effect & MA_KNEE) && ((*k + p_ptr->to_d) < m_ptr->hp))
+ {
+ msg_format("%^s moans in agony!", m_name);
+ stun_effect = 7 + randint(13);
+ resist_stun /= 3;
+ }
+ if (((special_effect & MA_FULL_SLOW) || (special_effect & MA_SLOW)) &&
+ ((*k + p_ptr->to_d) < m_ptr->hp))
+ {
+ if (!(r_ptr->flags1 & RF1_UNIQUE) &&
+ (randint(plev) > m_ptr->level) && m_ptr->mspeed > 60)
+ {
+ msg_format("%^s starts limping slower.", m_name);
+ m_ptr->mspeed -= 10;
+ }
+ }
+
+ if (stun_effect && ((*k + p_ptr->to_d) < m_ptr->hp))
+ {
+ if (plev > randint(m_ptr->level + resist_stun + 10))
+ {
+ if (m_ptr->stunned)
+ msg_format("%^s is still stunned.", m_name);
+ else
+ msg_format("%^s is stunned.", m_name);
+
+ m_ptr->stunned += (stun_effect);
+ }
+ }
+}
+
+
+/*
+ * Apply nazgul effects
+ */
+void do_nazgul(int *k, int *num, int num_blow, int weap, monster_race *r_ptr,
+ object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ bool_ mundane;
+ bool_ allow_shatter = TRUE;
+
+ /* Extract mundane-ness of the current weapon */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* It should be Slay Evil, Slay Undead, or *Slay Undead* */
+ mundane = !(f1 & TR1_SLAY_EVIL) && !(f1 & TR1_SLAY_UNDEAD) &&
+ !(f5 & TR5_KILL_UNDEAD);
+
+ /* Some blades can resist shattering */
+ if (f5 & TR5_RES_MORGUL)
+ allow_shatter = FALSE;
+
+ /* Mega Hack -- Hitting Nazgul is REALY dangerous (ideas from Akhronath) */
+ if (r_ptr->flags7 & RF7_NAZGUL)
+ {
+ if ((!o_ptr->name2) && (!artifact_p(o_ptr)) && allow_shatter)
+ {
+ msg_print("Your weapon *DISINTEGRATES*!");
+ *k = 0;
+
+ inc_stack_size_ex(INVEN_WIELD + weap, -1, OPTIMIZE, NO_DESCRIBE);
+
+ /* To stop attacking */
+ *num = num_blow;
+ }
+ else if (o_ptr->name2)
+ {
+ if (mundane)
+ {
+ msg_print
+ ("The Ringwraith is IMPERVIOUS to the mundane weapon.");
+ *k = 0;
+ }
+
+ /* 25% chance of getting destroyed */
+ if (magik(25) && allow_shatter)
+ {
+ msg_print("Your weapon is destroyed!");
+
+ inc_stack_size_ex(INVEN_WIELD + weap, -1, OPTIMIZE, NO_DESCRIBE);
+
+ /* To stop attacking */
+ *num = num_blow;
+ }
+ }
+ else if (artifact_p(o_ptr))
+ {
+ if (mundane)
+ {
+ msg_print
+ ("The Ringwraith is IMPERVIOUS to the mundane weapon.");
+ *k = 0;
+ }
+
+ apply_disenchant(INVEN_WIELD + weap);
+
+ /* 1/1000 chance of getting destroyed */
+ if (!rand_int(1000) && allow_shatter)
+ {
+ msg_print("Your weapon is destroyed!");
+
+ inc_stack_size_ex(INVEN_WIELD + weap, -1, OPTIMIZE, NO_DESCRIBE);
+
+ /* To stop attacking */
+ *num = num_blow;
+ }
+ }
+
+ /* If any damage is done, then 25% chance of getting the Black Breath */
+ if (*k)
+ {
+ if (magik(25))
+ {
+ msg_print("Your foe calls upon your soul!");
+ msg_print
+ ("You feel the Black Breath slowly draining you of life...");
+ p_ptr->black_breath = TRUE;
+ }
+ }
+ }
+}
+
+
+/*
+ * Player attacks a (poor, defenseless) creature -RAK-
+ *
+ * If no "weapon" is available, then "punch" the monster one time.
+ */
+void py_attack(int y, int x, int max_blow)
+{
+ int num = 0, k, bonus, chance;
+
+ s32b special = 0;
+
+ cave_type *c_ptr = &cave[y][x];
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ object_type *o_ptr;
+
+ char m_name[80];
+
+ bool_ fear = FALSE;
+
+ bool_ mdeath = FALSE;
+
+ bool_ backstab = FALSE;
+
+ bool_ vorpal_cut = FALSE;
+
+ int chaos_effect = 0;
+
+ bool_ stab_fleeing = FALSE;
+
+ bool_ do_quake = FALSE;
+
+ bool_ done_crit = FALSE;
+
+ bool_ drain_msg = TRUE;
+
+ int drain_result = 0, drain_heal = 0;
+
+ int drain_left = MAX_VAMPIRIC_DRAIN;
+
+ /* A massive hack -- life-draining weapons */
+ u32b f1, f2, f3, f4, f5, esp;
+
+ int weap;
+
+ /* Disturb the player */
+ disturb(0, 0);
+
+ if (r_info[p_ptr->body_monster].flags1 & RF1_NEVER_BLOW)
+ {
+ msg_print("You cannot attack in this form!");
+ return;
+ }
+
+ if (get_skill(SKILL_BACKSTAB))
+ {
+ if ((m_ptr->csleep) && (m_ptr->ml))
+ {
+ /* Can't backstab creatures that we can't see, right? */
+ backstab = TRUE;
+ }
+ else if ((m_ptr->monfear) && (m_ptr->ml))
+ {
+ stab_fleeing = TRUE;
+ }
+ }
+
+ /* Disturb the monster */
+ m_ptr->csleep = 0;
+
+
+ /* Extract monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Dont even bother */
+ if (r_ptr->flags7 & RF7_IM_MELEE)
+ {
+ msg_format("%^s is immune to melee attacks.");
+ return;
+ }
+
+ /* Auto-Recall if possible and visible */
+ if (m_ptr->ml) monster_race_track(m_ptr->r_idx, m_ptr->ego);
+
+ /* Track a new monster */
+ if (m_ptr->ml) health_track(c_ptr->m_idx);
+
+ /* Stop if friendly */
+ if ((is_friend(m_ptr) >= 0) &&
+ !(p_ptr->stun || p_ptr->confused || p_ptr->image ||
+ !(m_ptr->ml)))
+ {
+ if (!(p_ptr->inventory[INVEN_WIELD].art_name))
+ {
+ msg_format("You stop to avoid hitting %s.", m_name);
+ return;
+ }
+
+ if (!
+ (streq
+ (quark_str(p_ptr->inventory[INVEN_WIELD].art_name), "'Stormbringer'")))
+ {
+ msg_format("You stop to avoid hitting %s.", m_name);
+ return;
+ }
+
+ msg_format("Your black blade greedily attacks %s!", m_name);
+ }
+
+ /* Break goi/manashield */
+ if (p_ptr->invuln)
+ {
+ set_invuln(0);
+ }
+ if (p_ptr->disrupt_shield)
+ {
+ set_disrupt_shield(0);
+ }
+
+ /* Handle player fear */
+ if (p_ptr->afraid)
+ {
+ /* Message */
+ if (m_ptr->ml)
+ msg_format("You are too afraid to attack %s!", m_name);
+ else
+ msg_format("There is something scary in your way!");
+
+ /* Done */
+ return;
+ }
+
+ /* Monsters can use barehanded combat, but not weapon combat */
+ if ((p_ptr->body_monster) &&
+ (!r_info[p_ptr->body_monster].body_parts[BODY_WEAPON]) &&
+ !(p_ptr->melee_style == SKILL_HAND))
+ {
+ incarnate_monster_attack(c_ptr->m_idx, &fear, &mdeath, y, x);
+ }
+ /* Otherwise use your weapon(s) */
+ else
+ {
+ int weapons;
+ if (p_ptr->melee_style == SKILL_MASTERY)
+ weapons = r_info[p_ptr->body_monster].body_parts[BODY_WEAPON];
+ else /* SKILL_HAND */
+ weapons = 1;
+
+ /* Attack with ALL the weapons !!!!! -- ooh that's gonna hurt YOU */
+ for (weap = 0; weap < weapons; ++weap)
+ {
+ /* Monster is already dead ? oh :( */
+ if (mdeath) break;
+
+ /* Reset the blows counter */
+ num = 0;
+
+ /* Access the weapon */
+ o_ptr = &p_ptr->inventory[INVEN_WIELD + weap];
+
+ /* Calculate the "attack quality" */
+ bonus = p_ptr->to_h + p_ptr->to_h_melee + o_ptr->to_h;
+ chance = p_ptr->skill_thn + (bonus * BTH_PLUS_ADJ);
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (!(f4 & TR4_NEVER_BLOW))
+ {
+ int num_blow = p_ptr->num_blow;
+
+ /* Restrict to max_blow(if max_blow >= 0) */
+ if ((max_blow >= 0) &&
+ (num_blow > max_blow)) num_blow = max_blow;
+
+ /* Attack once for each legal blow */
+ while (num++ < num_blow)
+ {
+ /* Test for hit */
+ if (test_hit_norm(chance, m_ptr->ac, m_ptr->ml))
+ {
+ /* Sound */
+ sound(SOUND_HIT);
+
+ /* Hack -- bare hands do one damage */
+ k = 1;
+
+ /* Select a chaotic effect (50% chance) */
+ if ((f1 & TR1_CHAOTIC) && (rand_int(2) == 0))
+ {
+ if (randint(5) < 3)
+ {
+ /* Vampiric (20%) */
+ chaos_effect = 1;
+ }
+ else if (rand_int(250) == 0)
+ {
+ /* Quake (0.12%) */
+ chaos_effect = 2;
+ }
+ else if (rand_int(10))
+ {
+ /* Confusion (26.892%) */
+ chaos_effect = 3;
+ }
+ else if (rand_int(2) == 0)
+ {
+ /* Teleport away (1.494%) */
+ chaos_effect = 4;
+ }
+ else
+ {
+ /* Polymorph (1.494%) */
+ chaos_effect = 5;
+ }
+ }
+
+ /* Vampiric drain */
+ if ((f1 & TR1_VAMPIRIC) || (chaos_effect == 1))
+ {
+ if (!
+ ((r_ptr->flags3 & RF3_UNDEAD) ||
+ (r_ptr->flags3 & RF3_NONLIVING)))
+ drain_result = m_ptr->hp;
+ else
+ drain_result = 0;
+ }
+
+ if (f1 & TR1_VORPAL && (randint(6) == 1))
+ vorpal_cut = TRUE;
+ else
+ vorpal_cut = FALSE;
+
+ /* Should we attack with hands or not ? */
+ if (p_ptr->melee_style != SKILL_MASTERY)
+ {
+ py_attack_hand(&k, m_ptr, &special);
+ }
+ /* Handle normal weapon */
+ else if (o_ptr->k_idx)
+ {
+ k = damroll(o_ptr->dd, o_ptr->ds);
+ k = tot_dam_aux(o_ptr, k, m_ptr, &special);
+
+ if (backstab)
+ {
+ k += (k *
+ get_skill_scale(SKILL_BACKSTAB,
+ 100)) / 100;
+ }
+ else if (stab_fleeing)
+ {
+ k += (k * get_skill_scale(SKILL_BACKSTAB, 70)) /
+ 100;
+ }
+
+ if ((p_ptr->impact && ((k > 50) || randint(7) == 1))
+ || (chaos_effect == 2))
+ {
+ do_quake = TRUE;
+ }
+
+ k = critical_norm(o_ptr->weight, o_ptr->to_h, k, o_ptr->tval, &done_crit);
+
+ /* Stunning blow */
+ if (magik(get_skill(SKILL_STUN)) && (o_ptr->tval == TV_HAFTED) && (o_ptr->weight > 50) && done_crit)
+ {
+ if (!(r_ptr->flags4 & (RF4_BR_SOUN)) && !(r_ptr->flags4 & (RF4_BR_WALL)) && k)
+ {
+ int tmp;
+
+ /* Get stunned */
+ if (m_ptr->stunned)
+ {
+ msg_format("%^s is more dazed.", m_name);
+ tmp = m_ptr->stunned + get_skill_scale(SKILL_STUN, 30) + 10;
+ }
+ else
+ {
+ msg_format("%^s is dazed.", m_name);
+ tmp = get_skill_scale(SKILL_STUN, 60) + 20;
+ }
+
+ /* Apply stun */
+ m_ptr->stunned = (tmp < 200) ? tmp : 200;
+ }
+ }
+
+ if (vorpal_cut)
+ {
+ int step_k = k;
+
+ msg_format("Your weapon cuts deep into %s!",
+ m_name);
+ do
+ {
+ k += step_k;
+ }
+ while (randint(4) == 1);
+ }
+
+ PRAY_GOD(GOD_TULKAS)
+ {
+ if (magik(wisdom_scale(130) - m_ptr->level) && (p_ptr->grace > 1000))
+ {
+ msg_print("You feel the hand of Tulkas helping your blow.");
+ k += (o_ptr->to_d + p_ptr->to_d_melee) * 2;
+ }
+ else k += o_ptr->to_d + p_ptr->to_d_melee;
+ }
+ else k += o_ptr->to_d;
+
+ /* Project some more nasty stuff? */
+ if (p_ptr->tim_project)
+ {
+ project(0, p_ptr->tim_project_rad, y, x, p_ptr->tim_project_dam, p_ptr->tim_project_gf, p_ptr->tim_project_flag | PROJECT_JUMP);
+ if (!c_ptr->m_idx)
+ {
+ mdeath = TRUE;
+ break;
+ }
+ }
+
+ do_nazgul(&k, &num, num_blow, weap, r_ptr, o_ptr);
+
+ }
+
+ /* Melkor can cast curse for you*/
+ PRAY_GOD(GOD_MELKOR)
+ {
+ int lv = exec_lua("return get_level(MELKOR_CURSE, 100)");
+
+ if (lv >= 10)
+ {
+ int chance = (wisdom_scale(30) * lv) / ((m_ptr->level < 1) ? 1 : m_ptr->level);
+
+ if (chance < 1) chance = 1;
+ if ((p_ptr->grace > 5000) && magik(chance))
+ {
+ exec_lua(format("do_melkor_curse(%d)", c_ptr->m_idx));
+ }
+ }
+ }
+
+ /* May it clone the monster ? */
+ if ((f4 & TR4_CLONE) && magik(30))
+ {
+ msg_format("Oh no! Your weapon clones %^s!",
+ m_name);
+ multiply_monster(c_ptr->m_idx, FALSE, TRUE);
+ }
+
+ /* Apply the player damage bonuses */
+ k += p_ptr->to_d + p_ptr->to_d_melee;
+
+ /* No negative damage */
+ if (k < 0) k = 0;
+
+ /* Message */
+ if (!(backstab || stab_fleeing))
+ {
+ /* These monsters never have flavoured combat msgs */
+ if (strchr("vwjmelX,.*", r_ptr->d_char))
+ {
+ msg_format("You hit %s.", m_name);
+ }
+
+ /* Print flavoured messages if requested */
+ else
+ {
+ char buff[255];
+
+ flavored_attack((100 * k) / m_ptr->maxhp, buff);
+ msg_format(buff, m_name);
+ }
+ }
+ else if (backstab)
+ {
+ char buf[80];
+
+ monster_race_desc(buf, m_ptr->r_idx, m_ptr->ego);
+
+ backstab = FALSE;
+
+ msg_format
+ ("You cruelly stab the helpless, sleeping %s!",
+ buf);
+ }
+ else
+ {
+ char buf[80];
+
+ monster_race_desc(buf, m_ptr->r_idx, m_ptr->ego);
+
+ msg_format("You backstab the fleeing %s!", buf);
+ }
+
+ /* Complex message */
+ if (wizard)
+ {
+ msg_format("You do %d (out of %d) damage.", k,
+ m_ptr->hp);
+ }
+
+ if (special) attack_special(m_ptr, special, k);
+
+ /* Damage, check for fear and death */
+ if (mon_take_hit(c_ptr->m_idx, k, &fear, NULL))
+ {
+ /* Hack -- High-level warriors can spread their attacks out
+ * among weaker foes.
+ */
+ if ((has_ability(AB_SPREAD_BLOWS)) && (num < num_blow) &&
+ (energy_use))
+ {
+ energy_use = energy_use * num / num_blow;
+ }
+ mdeath = TRUE;
+ break;
+ }
+
+ switch (is_friend(m_ptr))
+ {
+ case 1:
+ msg_format("%^s gets angry!", m_name);
+ change_side(m_ptr);
+ break;
+ case 0:
+ msg_format("%^s gets angry!", m_name);
+ m_ptr->status = MSTATUS_NEUTRAL_M;
+ break;
+ }
+
+ touch_zap_player(m_ptr);
+
+ /* Are we draining it? A little note: If the monster is
+ dead, the drain does not work... */
+
+ if (drain_result)
+ {
+ drain_result -= m_ptr->hp; /* Calculate the difference */
+
+ if (drain_result > 0) /* Did we really hurt it? */
+ {
+ drain_heal = damroll(4, (drain_result / 6));
+
+ if (cheat_xtra)
+ {
+ msg_format("Draining left: %d", drain_left);
+ }
+
+ if (drain_left)
+ {
+ if (drain_heal < drain_left)
+ {
+ drain_left -= drain_heal;
+ }
+ else
+ {
+ drain_heal = drain_left;
+ drain_left = 0;
+ }
+
+ if (drain_msg)
+ {
+ msg_format
+ ("Your weapon drains life from %s!",
+ m_name);
+ drain_msg = FALSE;
+ }
+
+ hp_player(drain_heal);
+ /* We get to keep some of it! */
+ }
+ }
+ }
+
+ /* Confusion attack */
+ if ((p_ptr->confusing) || (chaos_effect == 3))
+ {
+ /* Cancel glowing hands */
+ if (p_ptr->confusing)
+ {
+ p_ptr->confusing = FALSE;
+ msg_print("Your hands stop glowing.");
+ }
+
+ /* Confuse the monster */
+ if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ msg_format("%^s is unaffected.", m_name);
+ }
+ else if (rand_int(100) < m_ptr->level)
+ {
+ msg_format("%^s is unaffected.", m_name);
+ }
+ else
+ {
+ msg_format("%^s appears confused.", m_name);
+ m_ptr->confused +=
+ 10 + rand_int(get_skill(SKILL_COMBAT)) / 5;
+ }
+ }
+
+ else if (chaos_effect == 4)
+ {
+ msg_format("%^s disappears!", m_name);
+ teleport_away(c_ptr->m_idx, 50);
+ num = num_blow + 1; /* Can't hit it anymore! */
+ }
+
+ else if ((chaos_effect == 5) && cave_floor_bold(y, x) &&
+ (randint(90) > m_ptr->level))
+ {
+ if (!((r_ptr->flags1 & RF1_UNIQUE) ||
+ (r_ptr->flags4 & RF4_BR_CHAO) ||
+ (m_ptr->mflag & MFLAG_QUEST)))
+ {
+ /* Handle polymorph */
+ if (do_poly_monster(y, x))
+ {
+ /* Polymorph succeeded */
+ msg_format("%^s changes!", m_name);
+
+ /* Hack -- Get new monster */
+ m_ptr = &m_list[c_ptr->m_idx];
+
+ /* Oops, we need a different name... */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Hack -- Get new race */
+ r_ptr = race_inf(m_ptr);
+
+ fear = FALSE;
+ }
+ else
+ {
+ msg_format("%^s resists.", m_name);
+ }
+ }
+ else
+ {
+ msg_format("%^s is unaffected.", m_name);
+ }
+ }
+ }
+
+ /* Player misses */
+ else
+ {
+ /* Sound */
+ sound(SOUND_MISS);
+
+ backstab = FALSE; /* Clumsy! */
+
+ /* Message */
+ msg_format("You miss %s.", m_name);
+ }
+ }
+ }
+ else
+ {
+ msg_print("You can't attack with that weapon.");
+ }
+ }
+ }
+
+ /* Carried monster can attack too */
+ if ((!mdeath) && m_list[c_ptr->m_idx].hp)
+ carried_monster_attack(c_ptr->m_idx, &fear, &mdeath, y, x);
+
+ /* Hack -- delay fear messages */
+ if (fear && m_ptr->ml)
+ {
+ /* Sound */
+ sound(SOUND_FLEE);
+
+ /* Message */
+ msg_format("%^s flees in terror!", m_name);
+ }
+
+ /* Mega-Hack -- apply earthquake brand */
+ if (do_quake)
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(p_ptr->py, p_ptr->px, 10);
+ }
+}
+
+
+
+static bool_ pattern_tile(int y, int x)
+{
+ return ((cave[y][x].feat <= FEAT_PATTERN_XTRA2) &&
+ (cave[y][x].feat >= FEAT_PATTERN_START));
+}
+
+
+static bool_ pattern_seq(int c_y, int c_x, int n_y, int n_x)
+{
+ if (!(pattern_tile(c_y, c_x)) && !(pattern_tile(n_y, n_x)))
+ return TRUE;
+
+ if (cave[n_y][n_x].feat == FEAT_PATTERN_START)
+ {
+ if ((!(pattern_tile(c_y, c_x))) &&
+ !(p_ptr->confused || p_ptr->stun || p_ptr->image))
+ {
+ if (get_check
+ ("If you start walking the Straight Road, you must walk the whole way. Ok? "))
+ return TRUE;
+ else
+ return FALSE;
+ }
+ else
+ return TRUE;
+ }
+ else if ((cave[n_y][n_x].feat == FEAT_PATTERN_OLD) ||
+ (cave[n_y][n_x].feat == FEAT_PATTERN_END) ||
+ (cave[n_y][n_x].feat == FEAT_PATTERN_XTRA2))
+ {
+ if (pattern_tile(c_y, c_x))
+ {
+ return TRUE;
+ }
+ else
+ {
+ msg_print
+ ("You must start walking the Straight Road from the startpoint.");
+ return FALSE;
+ }
+ }
+ else if ((cave[n_y][n_x].feat == FEAT_PATTERN_XTRA1) ||
+ (cave[c_y][c_x].feat == FEAT_PATTERN_XTRA1))
+ {
+ return TRUE;
+ }
+ else if (cave[c_y][c_x].feat == FEAT_PATTERN_START)
+ {
+ if (pattern_tile(n_y, n_x))
+ return TRUE;
+ else
+ {
+ msg_print("You must walk the Straight Road in correct order.");
+ return FALSE;
+ }
+ }
+ else if ((cave[c_y][c_x].feat == FEAT_PATTERN_OLD) ||
+ (cave[c_y][c_x].feat == FEAT_PATTERN_END) ||
+ (cave[c_y][c_x].feat == FEAT_PATTERN_XTRA2))
+ {
+ if (!pattern_tile(n_y, n_x))
+ {
+ msg_print("You may not step off from the Straight Road.");
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+ else
+ {
+ if (!pattern_tile(c_y, c_x))
+ {
+ msg_print
+ ("You must start walking the Straight Road from the startpoint.");
+ return FALSE;
+ }
+ else
+ {
+ byte ok_move = FEAT_PATTERN_START;
+ switch (cave[c_y][c_x].feat)
+ {
+ case FEAT_PATTERN_1:
+ ok_move = FEAT_PATTERN_2;
+ break;
+ case FEAT_PATTERN_2:
+ ok_move = FEAT_PATTERN_3;
+ break;
+ case FEAT_PATTERN_3:
+ ok_move = FEAT_PATTERN_4;
+ break;
+ case FEAT_PATTERN_4:
+ ok_move = FEAT_PATTERN_1;
+ break;
+ default:
+ if (wizard)
+ msg_format("Funny Straight Road walking, %d.",
+ cave[c_y][c_x]);
+ return TRUE; /* Goof-up */
+ }
+
+ if ((cave[n_y][n_x].feat == ok_move) ||
+ (cave[n_y][n_x].feat == cave[c_y][c_x].feat))
+ return TRUE;
+ else
+ {
+ if (!pattern_tile(n_y, n_x))
+ msg_print("You may not step off from the Straight Road.");
+ else
+ msg_print
+ ("You must walk the Straight Road in correct order.");
+
+ return FALSE;
+ }
+ }
+ }
+}
+
+
+
+bool_ player_can_enter(byte feature)
+{
+ bool_ pass_wall;
+
+ bool_ only_wall = FALSE;
+
+
+ /* Player can not walk through "walls" unless in Shadow Form */
+ if (p_ptr->wraith_form || (PRACE_FLAG(PR1_SEMI_WRAITH)))
+ pass_wall = TRUE;
+ else
+ pass_wall = FALSE;
+
+ /* Wall mimicry force the player to stay in walls */
+ if (p_ptr->mimic_extra & CLASS_WALL)
+ {
+ only_wall = TRUE;
+ }
+
+ /* Don't let the player kill himself with one keystroke */
+ if (p_ptr->wild_mode)
+ {
+ if (feature == FEAT_DEEP_WATER)
+ {
+ int wt = weight_limit() / 2;
+
+ if ((calc_total_weight() >= wt) && !(p_ptr->ffall))
+ return (FALSE);
+ }
+ else if (feature == FEAT_SHAL_LAVA ||
+ feature == FEAT_DEEP_LAVA)
+ {
+ if (!(p_ptr->resist_fire ||
+ p_ptr->immune_fire ||
+ p_ptr->oppose_fire ||
+ p_ptr->ffall))
+ return (FALSE);
+ }
+ }
+
+ if (feature == FEAT_TREES)
+ {
+ if (p_ptr->fly ||
+ pass_wall ||
+ (has_ability(AB_TREE_WALK)) ||
+ (p_ptr->mimic_form == resolve_mimic_name("Ent")) ||
+ ((p_ptr->grace >= 9000) && (p_ptr->praying) && (p_ptr->pgod == GOD_YAVANNA)))
+ return (TRUE);
+ }
+
+ if ((p_ptr->climb) && (f_info[feature].flags1 & FF1_CAN_CLIMB))
+ return (TRUE);
+ if ((p_ptr->fly) &&
+ ((f_info[feature].flags1 & FF1_CAN_FLY) ||
+ (f_info[feature].flags1 & FF1_CAN_LEVITATE)))
+ return (TRUE);
+ else if (only_wall && (f_info[feature].flags1 & FF1_FLOOR))
+ return (FALSE);
+ else if ((p_ptr->ffall) &&
+ (f_info[feature].flags1 & FF1_CAN_LEVITATE))
+ return (TRUE);
+ else if ((pass_wall || only_wall) &&
+ (f_info[feature].flags1 & FF1_CAN_PASS))
+ return (TRUE);
+ else if (f_info[feature].flags1 & FF1_NO_WALK)
+ return (FALSE);
+ else if ((f_info[feature].flags1 & FF1_WEB) &&
+ ((!(r_info[p_ptr->body_monster].flags7 & RF7_SPIDER)) && (p_ptr->mimic_form != resolve_mimic_name("Spider"))))
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * Move player in the given direction, with the given "pickup" flag.
+ *
+ * This routine should (probably) always induce energy expenditure.
+ *
+ * Note that moving will *always* take a turn, and will *always* hit
+ * any monster which might be in the destination grid. Previously,
+ * moving into walls was "free" and did NOT hit invisible monsters.
+ */
+void move_player_aux(int dir, int do_pickup, int run, bool_ disarm)
+{
+ int y, x, tmp;
+
+ cave_type *c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ monster_type *m_ptr;
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster], *mr_ptr;
+
+ char m_name[80];
+
+ bool_ stormbringer = FALSE;
+
+ bool_ old_dtrap, new_dtrap;
+
+ bool_ oktomove = TRUE;
+
+
+ /* Hack - random movement */
+ if (p_ptr->disembodied)
+ tmp = dir;
+ else if ((r_ptr->flags1 & RF1_RAND_25) && (r_ptr->flags1 & RF1_RAND_50))
+ {
+ if (randint(100) < 75)
+ tmp = randint(9);
+ else
+ tmp = dir;
+ }
+ else if (r_ptr->flags1 & RF1_RAND_50)
+ {
+ if (randint(100) < 50)
+ tmp = randint(9);
+ else
+ tmp = dir;
+ }
+ else if (r_ptr->flags1 & RF1_RAND_25)
+ {
+ if (randint(100) < 25)
+ tmp = randint(9);
+ else
+ tmp = dir;
+ }
+ else
+ {
+ tmp = dir;
+ }
+
+ if ((c_ptr->feat == FEAT_ICE) && (!p_ptr->ffall && !p_ptr->fly))
+ {
+ if (magik(70 - p_ptr->lev))
+ {
+ tmp = randint(9);
+ msg_print("You slip on the icy floor.");
+ }
+ else
+ tmp = dir;
+ }
+
+ /* Find the result of moving */
+ y = p_ptr->py + ddy[tmp];
+ x = p_ptr->px + ddx[tmp];
+
+ /* Examine the destination */
+ c_ptr = &cave[y][x];
+
+ /* Change oldpx and oldpy to place the player well when going back to big mode */
+ if (p_ptr->wild_mode)
+ {
+ if (ddy[tmp] > 0) p_ptr->oldpy = 1;
+ if (ddy[tmp] < 0) p_ptr->oldpy = MAX_HGT - 2;
+ if (ddy[tmp] == 0) p_ptr->oldpy = MAX_HGT / 2;
+ if (ddx[tmp] > 0) p_ptr->oldpx = 1;
+ if (ddx[tmp] < 0) p_ptr->oldpx = MAX_WID - 2;
+ if (ddx[tmp] == 0) p_ptr->oldpx = MAX_WID / 2;
+ }
+
+ /* Exit the area */
+ if (!dun_level && !p_ptr->wild_mode && !is_quest(dun_level) &&
+ ((x == 0) || (x == cur_wid - 1) || (y == 0) || (y == cur_hgt - 1)))
+ {
+ /* Can the player enter the grid? */
+ if (player_can_enter(c_ptr->mimic))
+ {
+ /* Hack: move to new area */
+ if ((y == 0) && (x == 0))
+ {
+ p_ptr->wilderness_y--;
+ p_ptr->wilderness_x--;
+ p_ptr->oldpy = cur_hgt - 2;
+ p_ptr->oldpx = cur_wid - 2;
+ ambush_flag = FALSE;
+ }
+
+ else if ((y == 0) && (x == MAX_WID - 1))
+ {
+ p_ptr->wilderness_y--;
+ p_ptr->wilderness_x++;
+ p_ptr->oldpy = cur_hgt - 2;
+ p_ptr->oldpx = 1;
+ ambush_flag = FALSE;
+ }
+
+ else if ((y == MAX_HGT - 1) && (x == 0))
+ {
+ p_ptr->wilderness_y++;
+ p_ptr->wilderness_x--;
+ p_ptr->oldpy = 1;
+ p_ptr->oldpx = cur_wid - 2;
+ ambush_flag = FALSE;
+ }
+
+ else if ((y == MAX_HGT - 1) && (x == MAX_WID - 1))
+ {
+ p_ptr->wilderness_y++;
+ p_ptr->wilderness_x++;
+ p_ptr->oldpy = 1;
+ p_ptr->oldpx = 1;
+ ambush_flag = FALSE;
+ }
+
+ else if (y == 0)
+ {
+ p_ptr->wilderness_y--;
+ p_ptr->oldpy = cur_hgt - 2;
+ p_ptr->oldpx = x;
+ ambush_flag = FALSE;
+ }
+
+ else if (y == cur_hgt - 1)
+ {
+ p_ptr->wilderness_y++;
+ p_ptr->oldpy = 1;
+ p_ptr->oldpx = x;
+ ambush_flag = FALSE;
+ }
+
+ else if (x == 0)
+ {
+ p_ptr->wilderness_x--;
+ p_ptr->oldpx = cur_wid - 2;
+ p_ptr->oldpy = y;
+ ambush_flag = FALSE;
+ }
+
+ else if (x == cur_wid - 1)
+ {
+ p_ptr->wilderness_x++;
+ p_ptr->oldpx = 1;
+ p_ptr->oldpy = y;
+ ambush_flag = FALSE;
+ }
+
+ p_ptr->leaving = TRUE;
+
+ return;
+ }
+ }
+
+ /* Some hooks */
+ if (process_hooks(HOOK_MOVE, "(d,d)", y, x)) return;
+
+ /* Get the monster */
+ m_ptr = &m_list[c_ptr->m_idx];
+ mr_ptr = race_inf(m_ptr);
+
+ if (p_ptr->inventory[INVEN_WIELD].art_name)
+ {
+ if (streq(quark_str(p_ptr->inventory[INVEN_WIELD].art_name), "'Stormbringer'"))
+ stormbringer = TRUE;
+ }
+
+ /* Hack -- attack monsters */
+ if (c_ptr->m_idx && (m_ptr->ml || player_can_enter(c_ptr->feat)))
+ {
+
+ /* Attack -- only if we can see it OR it is not in a wall */
+ if ((is_friend(m_ptr) > 0) &&
+ !(p_ptr->confused || p_ptr->image || !(m_ptr->ml) || p_ptr->stun) &&
+ (pattern_seq(p_ptr->py, p_ptr->px, y, x)) &&
+ ((player_can_enter(cave[y][x].feat))))
+ {
+ m_ptr->csleep = 0;
+
+ /* Extract monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Auto-Recall if possible and visible */
+ if (m_ptr->ml) monster_race_track(m_ptr->r_idx, m_ptr->ego);
+
+ /* Track a new monster */
+ if (m_ptr->ml) health_track(c_ptr->m_idx);
+
+ /* displace? */
+ if (stormbringer && (randint(1000) > 666))
+ {
+ py_attack(y, x, -1);
+ }
+ else if (cave_floor_bold(p_ptr->py, p_ptr->px) ||
+ (mr_ptr->flags2 & RF2_PASS_WALL))
+ {
+ msg_format("You push past %s.", m_name);
+ m_ptr->fy = p_ptr->py;
+ m_ptr->fx = p_ptr->px;
+ cave[p_ptr->py][p_ptr->px].m_idx = c_ptr->m_idx;
+ c_ptr->m_idx = 0;
+ update_mon(cave[p_ptr->py][p_ptr->px].m_idx, TRUE);
+ }
+ else
+ {
+ msg_format("%^s is in your way!", m_name);
+ energy_use = 0;
+ oktomove = FALSE;
+ }
+
+ /* now continue on to 'movement' */
+ }
+ else
+ {
+ py_attack(y, x, -1);
+ oktomove = FALSE;
+ }
+ }
+
+ else if ((c_ptr->feat == FEAT_DARK_PIT) && !p_ptr->ffall)
+ {
+ msg_print("You can't cross the chasm.");
+ running = 0;
+ oktomove = FALSE;
+ }
+
+ /* Disarm a visible trap */
+ else if (easy_disarm && disarm && (c_ptr->info & (CAVE_TRDT)))
+ {
+ (void)do_cmd_disarm_aux(y, x, tmp, do_pickup);
+ return;
+ }
+
+ /* Don't step on known traps. */
+ else if (disarm && (c_ptr->info & (CAVE_TRDT)) && !(p_ptr->confused || p_ptr->stun || p_ptr->image))
+ {
+ msg_print("You stop to avoid triggering the trap.");
+ energy_use = 0;
+ oktomove = FALSE;
+ }
+
+ /* Player can't enter ? soo bad for him/her ... */
+ else if (!player_can_enter(c_ptr->feat))
+ {
+ oktomove = FALSE;
+
+ /* Disturb the player */
+ disturb(0, 0);
+
+ if (p_ptr->prob_travel)
+ {
+ if (passwall(tmp, TRUE)) return;
+ }
+
+ /* Notice things in the dark */
+ if (!(c_ptr->info & (CAVE_MARK)) && !(c_ptr->info & (CAVE_SEEN)))
+ {
+ /* Rubble */
+ if (c_ptr->feat == FEAT_RUBBLE)
+ {
+ msg_print("You feel some rubble blocking your way.");
+ c_ptr->info |= (CAVE_MARK);
+ lite_spot(y, x);
+ }
+
+ /* Closed door */
+ else if (c_ptr->feat < FEAT_SECRET)
+ {
+ msg_print("You feel a closed door blocking your way.");
+ c_ptr->info |= (CAVE_MARK);
+ lite_spot(y, x);
+ }
+
+ /* Wall (or secret door) */
+ else
+ {
+ int feat;
+
+ if (c_ptr->mimic) feat = c_ptr->mimic;
+ else
+ feat = f_info[c_ptr->feat].mimic;
+
+ msg_format("You feel %s.", f_text + f_info[feat].block);
+ c_ptr->info |= (CAVE_MARK);
+ lite_spot(y, x);
+ }
+ }
+
+ /* Notice things */
+ else
+ {
+ /* Rubble */
+ if (c_ptr->feat == FEAT_RUBBLE)
+ {
+ if (!easy_tunnel)
+ {
+ msg_print("There is rubble blocking your way.");
+
+ if (!(p_ptr->confused || p_ptr->stun || p_ptr->image))
+ energy_use = 0;
+ /*
+ * Well, it makes sense that you lose time bumping into
+ * a wall _if_ you are confused, stunned or blind; but
+ * typing mistakes should not cost you a turn...
+ */
+ }
+ else
+ {
+ do_cmd_tunnel_aux(y, x, dir);
+ return;
+ }
+ }
+ /* Closed doors */
+ else if ((c_ptr->feat >= FEAT_DOOR_HEAD) && (c_ptr->feat <= FEAT_DOOR_TAIL))
+ {
+ if (easy_open)
+ {
+ if (easy_open_door(y, x)) return;
+ }
+ else
+ {
+ msg_print("There is a closed door blocking your way.");
+
+ if (!(p_ptr->confused || p_ptr->stun || p_ptr->image))
+ energy_use = 0;
+ }
+ }
+
+ /* Wall (or secret door) */
+ else
+ {
+ if (!easy_tunnel)
+ {
+ int feat;
+
+ if (c_ptr->mimic) feat = c_ptr->mimic;
+ else
+ feat = f_info[c_ptr->feat].mimic;
+
+ msg_format("There is %s.", f_text + f_info[feat].block);
+
+ if (!(p_ptr->confused || p_ptr->stun || p_ptr->image))
+ energy_use = 0;
+ }
+ else
+ {
+ do_cmd_tunnel_aux(y, x, dir);
+ return;
+ }
+ }
+ }
+
+ /* Sound */
+ sound(SOUND_HITWALL);
+ }
+
+ /* Normal movement */
+ if (!pattern_seq(p_ptr->py, p_ptr->px, y, x))
+ {
+ if (!(p_ptr->confused || p_ptr->stun || p_ptr->image))
+ {
+ energy_use = 0;
+ }
+
+ disturb(0, 0); /* To avoid a loop with running */
+
+ oktomove = FALSE;
+ }
+
+
+ /*
+ * Check trap detection status -- retrieve them here
+ * because they are used by the movement code as well
+ */
+ old_dtrap = ((cave[p_ptr->py][p_ptr->px].info & CAVE_DETECT) != 0);
+ new_dtrap = ((cave[y][x].info & CAVE_DETECT) != 0);
+
+ /* Normal movement */
+ if (oktomove && running && disturb_detect)
+ {
+ /*
+ * Disturb the player when about to leave the trap detected
+ * area
+ */
+ if (old_dtrap && !new_dtrap)
+ {
+ /* Disturb player */
+ disturb(0, 0);
+
+ /* but don't take a turn */
+ energy_use = 0;
+
+ /* Tell player why */
+ cmsg_print(TERM_VIOLET, "You are about to leave a trap detected zone.");
+ /* Flush */
+ /* msg_print(NULL); */
+
+ oktomove = FALSE;
+ }
+ }
+
+ /* Normal movement */
+ if (oktomove)
+ {
+ int oy, ox;
+ int feat;
+
+ /* Rooted means no move */
+ if (p_ptr->tim_roots) return;
+
+ /* Save old location */
+ oy = p_ptr->py;
+ ox = p_ptr->px;
+
+ /* Move the player */
+ p_ptr->py = y;
+ p_ptr->px = x;
+
+ if (cave[p_ptr->py][p_ptr->px].mimic) feat = cave[p_ptr->py][p_ptr->px].mimic;
+ else
+ feat = cave[p_ptr->py][p_ptr->px].feat;
+
+ /* Some hooks */
+ if (process_hooks(HOOK_MOVED, "(d,d)", oy, ox)) return;
+
+ /* Redraw new spot */
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Redraw old spot */
+ lite_spot(oy, ox);
+
+ /* Sound */
+ /* sound(SOUND_WALK); */
+
+ /* Check for new panel (redraw map) */
+ verify_panel();
+
+ /* Check detection status */
+ if (old_dtrap && !new_dtrap)
+ {
+ cmsg_print(TERM_VIOLET, "You leave a trap detected zone.");
+ if (running) msg_print(NULL);
+ p_ptr->redraw |= (PR_DTRAP);
+ }
+ else if (!old_dtrap && new_dtrap)
+ {
+ cmsg_print(TERM_L_BLUE, "You enter a trap detected zone.");
+ if (running) msg_print(NULL);
+ p_ptr->redraw |= (PR_DTRAP);
+ }
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Window stuff */
+ if (!run) p_ptr->window |= (PW_OVERHEAD);
+
+ /* Some feature descs */
+ if (f_info[cave[p_ptr->py][p_ptr->px].feat].text > 1)
+ {
+ /* Mega-hack for dungeon branches */
+ if ((feat == FEAT_MORE) && c_ptr->special)
+ {
+ msg_format("There is %s", d_text + d_info[c_ptr->special].text);
+ }
+ else
+ {
+ msg_print(f_text + f_info[feat].text);
+ }
+
+ /* Flush message while running */
+ if (running) msg_print(NULL);
+ }
+
+ /* Spontaneous Searching */
+ if ((p_ptr->skill_fos >= 50) || (0 == rand_int(50 - p_ptr->skill_fos)))
+ {
+ search();
+ }
+
+ /* Continuous Searching */
+ if (p_ptr->searching)
+ {
+ search();
+ }
+
+ /* Handle "objects" */
+ carry(do_pickup);
+
+ /* Handle "store doors" */
+ if (c_ptr->feat == FEAT_SHOP)
+ {
+ /* Disturb */
+ disturb(0, 0);
+
+ /* Hack -- Enter store */
+ command_new = '_';
+ }
+
+ else if (cave[y][x].feat >= FEAT_ALTAR_HEAD &&
+ cave[y][x].feat <= FEAT_ALTAR_TAIL)
+ {
+ cptr name = f_name + f_info[cave[y][x].feat].name;
+ cptr pref = (is_a_vowel(name[0])) ? "an" : "a";
+
+ msg_format("You see %s %s.", pref, name);
+
+ /* Flush message while running */
+ if (running) msg_print(NULL);
+ }
+
+ /* Discover invisible traps */
+ else if ((c_ptr->t_idx != 0) &&
+ !(f_info[cave[y][x].feat].flags1 & FF1_DOOR))
+ {
+ /* Disturb */
+ disturb(0, 0);
+
+ if (!(c_ptr->info & (CAVE_TRDT)))
+ {
+ /* Message */
+ msg_print("You found a trap!");
+
+ /* Pick a trap */
+ pick_trap(p_ptr->py, p_ptr->px);
+ }
+
+ /* Hit the trap */
+ hit_trap();
+ }
+
+ /* Execute the inscription */
+ else if (c_ptr->inscription)
+ {
+ /* Disturb */
+ disturb(0, 0);
+
+ msg_format("There is an inscription here: %s",
+ inscription_info[c_ptr->inscription].text);
+ if (inscription_info[c_ptr->inscription].when & INSCRIP_EXEC_WALK)
+ {
+ execute_inscription(c_ptr->inscription, p_ptr->py, p_ptr->px);
+ }
+ }
+ }
+
+ /* Update wilderness knowledge */
+ if (p_ptr->wild_mode)
+ {
+ if (wizard) msg_format("y:%d, x:%d", p_ptr->py, p_ptr->px);
+
+ /* Update the known wilderness */
+ reveal_wilderness_around_player(p_ptr->py, p_ptr->px, 0, WILDERNESS_SEE_RADIUS);
+
+ /* Walking the wild isnt meaningfull */
+ p_ptr->did_nothing = TRUE;
+ }
+}
+
+void move_player(int dir, int do_pickup, bool_ disarm)
+{
+ move_player_aux(dir, do_pickup, 0, disarm);
+}
+
+
+/*
+ * Hack -- Grid-based version of see_obstacle
+ */
+static int see_obstacle_grid(cave_type *c_ptr)
+{
+ /*
+ * Hack -- Avoid hitting detected traps, because we cannot rely on
+ * the CAVE_MARK check below, and traps can be set to nearly
+ * everything the player can move on to XXX XXX XXX
+ */
+ if (c_ptr->info & (CAVE_TRDT)) return (TRUE);
+
+
+ /* Hack -- Handle special cases XXX XXX */
+ switch (c_ptr->feat)
+ {
+ /* Require levitation */
+ case FEAT_DARK_PIT:
+ case FEAT_DEEP_WATER:
+ case FEAT_ICE:
+ {
+ if (p_ptr->ffall || p_ptr->fly) return (FALSE);
+ }
+
+ /* Require immunity */
+ case FEAT_DEEP_LAVA:
+ case FEAT_SHAL_LAVA:
+ {
+ if (p_ptr->invuln || p_ptr->immune_fire) return (FALSE);
+ }
+ }
+
+
+ /* "Safe" floor grids aren't obstacles */
+ if (f_info[c_ptr->feat].flags1 & FF1_CAN_RUN) return (FALSE);
+
+ /* Must be known to the player */
+ if (!(c_ptr->info & (CAVE_MARK))) return (FALSE);
+
+ /* Default */
+ return (TRUE);
+}
+
+
+/*
+ * Hack -- Check for a "known wall" or "dangerous" feature (see below)
+ */
+static int see_obstacle(int dir, int y, int x)
+{
+ /* Get the new location */
+ y += ddy[dir];
+ x += ddx[dir];
+
+ /* Illegal grids are not known walls */
+ if (!in_bounds2(y, x)) return (FALSE);
+
+ /* Analyse the grid */
+ return (see_obstacle_grid(&cave[y][x]));
+}
+
+
+/*
+ * Hack -- Check for an "unknown corner" (see below)
+ */
+static int see_nothing(int dir, int y, int x)
+{
+ /* Get the new location */
+ y += ddy[dir];
+ x += ddx[dir];
+
+ /* Illegal grids are unknown */
+ if (!in_bounds2(y, x)) return (TRUE);
+
+ /* Memorized grids are always known */
+ if (cave[y][x].info & (CAVE_MARK)) return (FALSE);
+
+ /* Non-floor grids are unknown */
+ if (!cave_floor_bold(y, x)) return (TRUE);
+
+ /* Viewable door/wall grids are known */
+ if (player_can_see_bold(y, x)) return (FALSE);
+
+ /* Default */
+ return (TRUE);
+}
+
+
+
+
+
+/*
+ * The running algorithm: -CJS-
+ *
+ * In the diagrams below, the player has just arrived in the
+ * grid marked as '@', and he has just come from a grid marked
+ * as 'o', and he is about to enter the grid marked as 'x'.
+ *
+ * Of course, if the "requested" move was impossible, then you
+ * will of course be blocked, and will stop.
+ *
+ * Overview: You keep moving until something interesting happens.
+ * If you are in an enclosed space, you follow corners. This is
+ * the usual corridor scheme. If you are in an open space, you go
+ * straight, but stop before entering enclosed space. This is
+ * analogous to reaching doorways. If you have enclosed space on
+ * one side only (that is, running along side a wall) stop if
+ * your wall opens out, or your open space closes in. Either case
+ * corresponds to a doorway.
+ *
+ * What happens depends on what you can really SEE. (i.e. if you
+ * have no light, then running along a dark corridor is JUST like
+ * running in a dark room.) The algorithm works equally well in
+ * corridors, rooms, mine tailings, earthquake rubble, etc, etc.
+ *
+ * These conditions are kept in static memory:
+ * find_openarea You are in the open on at least one
+ * side.
+ * find_breakleft You have a wall on the left, and will
+ * stop if it opens
+ * find_breakright You have a wall on the right, and will
+ * stop if it opens
+ *
+ * To initialize these conditions, we examine the grids adjacent
+ * to the grid marked 'x', two on each side (marked 'L' and 'R').
+ * If either one of the two grids on a given side is seen to be
+ * closed, then that side is considered to be closed. If both
+ * sides are closed, then it is an enclosed (corridor) run.
+ *
+ * LL L
+ * @x LxR
+ * RR @R
+ *
+ * Looking at more than just the immediate squares is
+ * significant. Consider the following case. A run along the
+ * corridor will stop just before entering the center point,
+ * because a choice is clearly established. Running in any of
+ * three available directions will be defined as a corridor run.
+ * Note that a minor hack is inserted to make the angled corridor
+ * entry (with one side blocked near and the other side blocked
+ * further away from the runner) work correctly. The runner moves
+ * diagonally, but then saves the previous direction as being
+ * straight into the gap. Otherwise, the tail end of the other
+ * entry would be perceived as an alternative on the next move.
+ *
+ * #.#
+ * ##.##
+ * .@x..
+ * ##.##
+ * #.#
+ *
+ * Likewise, a run along a wall, and then into a doorway (two
+ * runs) will work correctly. A single run rightwards from @ will
+ * stop at 1. Another run right and down will enter the corridor
+ * and make the corner, stopping at the 2.
+ *
+ * #@x 1
+ * ########### ######
+ * 2 #
+ * #############
+ * #
+ *
+ * After any move, the function area_affect is called to
+ * determine the new surroundings, and the direction of
+ * subsequent moves. It examines the current player location
+ * (at which the runner has just arrived) and the previous
+ * direction (from which the runner is considered to have come).
+ *
+ * Moving one square in some direction places you adjacent to
+ * three or five new squares (for straight and diagonal moves
+ * respectively) to which you were not previously adjacent,
+ * marked as '!' in the diagrams below.
+ *
+ * ...! ...
+ * .o@! .o.!
+ * ...! ..@!
+ * !!!
+ *
+ * You STOP if any of the new squares are interesting in any way:
+ * for example, if they contain visible monsters or treasure.
+ *
+ * You STOP if any of the newly adjacent squares seem to be open,
+ * and you are also looking for a break on that side. (that is,
+ * find_openarea AND find_break).
+ *
+ * You STOP if any of the newly adjacent squares do NOT seem to be
+ * open and you are in an open area, and that side was previously
+ * entirely open.
+ *
+ * Corners: If you are not in the open (i.e. you are in a corridor)
+ * and there is only one way to go in the new squares, then turn in
+ * that direction. If there are more than two new ways to go, STOP.
+ * If there are two ways to go, and those ways are separated by a
+ * square which does not seem to be open, then STOP.
+ *
+ * Otherwise, we have a potential corner. There are two new open
+ * squares, which are also adjacent. One of the new squares is
+ * diagonally located, the other is straight on (as in the diagram).
+ * We consider two more squares further out (marked below as ?).
+ *
+ * We assign "option" to the straight-on grid, and "option2" to the
+ * diagonal grid, and "check_dir" to the grid marked 's'.
+ *
+ * .s
+ * @x?
+ * #?
+ *
+ * If they are both seen to be closed, then it is seen that no
+ * benefit is gained from moving straight. It is a known corner.
+ * To cut the corner, go diagonally, otherwise go straight, but
+ * pretend you stepped diagonally into that next location for a
+ * full view next time. Conversely, if one of the ? squares is
+ * not seen to be closed, then there is a potential choice. We check
+ * to see whether it is a potential corner or an intersection/room entrance.
+ * If the square two spaces straight ahead, and the space marked with 's'
+ * are both blank, then it is a potential corner and enter if find_examine
+ * is set, otherwise must stop because it is not a corner.
+ */
+
+
+
+
+/*
+ * Hack -- allow quick "cycling" through the legal directions
+ */
+static byte cycle[] = { 1, 2, 3, 6, 9, 8, 7, 4, 1, 2, 3, 6, 9, 8, 7, 4, 1 };
+
+/*
+ * Hack -- map each direction into the "middle" of the "cycle[]" array
+ */
+static byte chome[] = { 0, 8, 9, 10, 7, 0, 11, 6, 5, 4 };
+
+/*
+ * The direction we are running
+ */
+static byte find_current;
+
+/*
+ * The direction we came from
+ */
+static byte find_prevdir;
+
+/*
+ * We are looking for open area
+ */
+static bool_ find_openarea;
+
+/*
+ * We are looking for a break
+ */
+static bool_ find_breakright;
+static bool_ find_breakleft;
+
+
+
+/*
+ * Initialize the running algorithm for a new direction.
+ *
+ * Diagonal Corridor -- allow diaginal entry into corridors.
+ *
+ * Blunt Corridor -- If there is a wall two spaces ahead and
+ * we seem to be in a corridor, then force a turn into the side
+ * corridor, must be moving straight into a corridor here. ???
+ *
+ * Diagonal Corridor Blunt Corridor (?)
+ * # # #
+ * #x# @x#
+ * @p. p
+ */
+static void run_init(int dir)
+{
+ int row, col, deepleft, deepright;
+
+ int i, shortleft, shortright;
+
+
+ /* Save the direction */
+ find_current = dir;
+
+ /* Assume running straight */
+ find_prevdir = dir;
+
+ /* Assume looking for open area */
+ find_openarea = TRUE;
+
+ /* Assume not looking for breaks */
+ find_breakright = find_breakleft = FALSE;
+
+ /* Assume no nearby walls */
+ deepleft = deepright = FALSE;
+ shortright = shortleft = FALSE;
+
+ /* Find the destination grid */
+ row = p_ptr->py + ddy[dir];
+ col = p_ptr->px + ddx[dir];
+
+ /* Extract cycle index */
+ i = chome[dir];
+
+ /* Check for walls */
+ if (see_obstacle(cycle[i + 1], p_ptr->py, p_ptr->px))
+ {
+ find_breakleft = TRUE;
+ shortleft = TRUE;
+ }
+ else if (see_obstacle(cycle[i + 1], row, col))
+ {
+ find_breakleft = TRUE;
+ deepleft = TRUE;
+ }
+
+ /* Check for walls */
+ if (see_obstacle(cycle[i - 1], p_ptr->py, p_ptr->px))
+ {
+ find_breakright = TRUE;
+ shortright = TRUE;
+ }
+ else if (see_obstacle(cycle[i - 1], row, col))
+ {
+ find_breakright = TRUE;
+ deepright = TRUE;
+ }
+
+ /* Looking for a break */
+ if (find_breakleft && find_breakright)
+ {
+ /* Not looking for open area */
+ find_openarea = FALSE;
+
+ /* Hack -- allow angled corridor entry */
+ if (dir & 0x01)
+ {
+ if (deepleft && !deepright)
+ {
+ find_prevdir = cycle[i - 1];
+ }
+ else if (deepright && !deepleft)
+ {
+ find_prevdir = cycle[i + 1];
+ }
+ }
+
+ /* Hack -- allow blunt corridor entry */
+ else if (see_obstacle(cycle[i], row, col))
+ {
+ if (shortleft && !shortright)
+ {
+ find_prevdir = cycle[i - 2];
+ }
+ else if (shortright && !shortleft)
+ {
+ find_prevdir = cycle[i + 2];
+ }
+ }
+ }
+}
+
+
+/*
+ * Update the current "run" path
+ *
+ * Return TRUE if the running should be stopped
+ */
+static bool_ run_test(void)
+{
+ int prev_dir, new_dir, check_dir = 0;
+
+ int row, col;
+
+ int i, max, inv;
+
+ int option = 0, option2 = 0;
+
+ cave_type *c_ptr;
+
+
+ /* Where we came from */
+ prev_dir = find_prevdir;
+
+
+ /* Range of newly adjacent grids */
+ max = (prev_dir & 0x01) + 1;
+
+
+ /* Look at every newly adjacent square. */
+ for (i = -max; i <= max; i++)
+ {
+ s16b this_o_idx, next_o_idx = 0;
+
+
+ /* New direction */
+ new_dir = cycle[chome[prev_dir] + i];
+
+ /* New location */
+ row = p_ptr->py + ddy[new_dir];
+ col = p_ptr->px + ddx[new_dir];
+
+ /* Access grid */
+ c_ptr = &cave[row][col];
+
+
+ /* Visible monsters abort running */
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+
+ /* Visible monster */
+ if (m_ptr->ml) return (TRUE);
+ }
+
+ /* Visible objects abort running */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Visible object */
+ if (o_ptr->marked) return (TRUE);
+ }
+
+
+ /* Assume unknown */
+ inv = TRUE;
+
+ /* Check memorized grids */
+ if (c_ptr->info & (CAVE_MARK))
+ {
+ bool_ notice = TRUE;
+
+ /*
+ * Examine the terrain -- conditional disturbance
+ * If we had more flags, we could make these customisable too
+ */
+ switch (c_ptr->feat)
+ {
+ case FEAT_DEEP_LAVA:
+ case FEAT_SHAL_LAVA:
+ {
+ /* Ignore */
+ if (p_ptr->invuln || p_ptr->immune_fire) notice = FALSE;
+
+ /* Done */
+ break;
+ }
+
+ case FEAT_DEEP_WATER:
+ case FEAT_ICE:
+ {
+ /* Ignore */
+ if (p_ptr->ffall || p_ptr->fly) notice = FALSE;
+
+ /* Done */
+ break;
+ }
+
+ /* Open doors */
+ case FEAT_OPEN:
+ case FEAT_BROKEN:
+ {
+ /* Option -- ignore */
+ if (find_ignore_doors) notice = FALSE;
+
+ /* Done */
+ break;
+ }
+
+ /*
+ * Stairs - too many of them, should find better ways to
+ * handle them (not scripting!, because it can be called
+ * from within the running algo) XXX XXX XXX
+ */
+ case FEAT_LESS:
+ case FEAT_MORE:
+ case FEAT_QUEST_ENTER:
+ case FEAT_QUEST_EXIT:
+ case FEAT_QUEST_DOWN:
+ case FEAT_QUEST_UP:
+ case FEAT_SHAFT_UP:
+ case FEAT_SHAFT_DOWN:
+ case FEAT_WAY_LESS:
+ case FEAT_WAY_MORE:
+ /* XXX */
+ case FEAT_BETWEEN:
+ case FEAT_BETWEEN2:
+ {
+ /* Option -- ignore */
+ if (find_ignore_stairs) notice = FALSE;
+
+ /* Done */
+ break;
+ }
+ }
+
+ /* Check the "don't notice running" flag */
+ if (f_info[c_ptr->feat].flags1 & FF1_DONT_NOTICE_RUNNING)
+ {
+ notice = FALSE;
+ }
+
+ /* A detected trap is interesting */
+ if (c_ptr->info & (CAVE_TRDT)) notice = TRUE;
+
+ /* Interesting feature */
+ if (notice) return (TRUE);
+
+ /* The grid is "visible" */
+ inv = FALSE;
+ }
+
+ /* Mega-Hack -- Maze code removes CAVE_MARK XXX XXX XXX */
+ if (c_ptr->info & (CAVE_TRDT)) return (TRUE);
+
+ /* Analyze unknown grids and floors */
+ if (inv || cave_floor_bold(row, col))
+ {
+ /* Looking for open area */
+ if (find_openarea)
+ {
+ /* Nothing */
+ }
+
+ /* The first new direction. */
+ else if (!option)
+ {
+ option = new_dir;
+ }
+
+ /* Three new directions. Stop running. */
+ else if (option2)
+ {
+ return (TRUE);
+ }
+
+ /* Two non-adjacent new directions. Stop running. */
+ else if (option != cycle[chome[prev_dir] + i - 1])
+ {
+ return (TRUE);
+ }
+
+ /* Two new (adjacent) directions (case 1) */
+ else if (new_dir & 0x01)
+ {
+ check_dir = cycle[chome[prev_dir] + i - 2];
+ option2 = new_dir;
+ }
+
+ /* Two new (adjacent) directions (case 2) */
+ else
+ {
+ check_dir = cycle[chome[prev_dir] + i + 1];
+ option2 = option;
+ option = new_dir;
+ }
+ }
+
+ /* Obstacle, while looking for open area */
+ else
+ {
+ if (find_openarea)
+ {
+ if (i < 0)
+ {
+ /* Break to the right */
+ find_breakright = TRUE;
+ }
+
+ else if (i > 0)
+ {
+ /* Break to the left */
+ find_breakleft = TRUE;
+ }
+ }
+ }
+ }
+
+
+ /* Looking for open area */
+ if (find_openarea)
+ {
+ /* Hack -- look again */
+ for (i = -max; i < 0; i++)
+ {
+ new_dir = cycle[chome[prev_dir] + i];
+
+ row = p_ptr->py + ddy[new_dir];
+ col = p_ptr->px + ddx[new_dir];
+
+ /* Access grid */
+ c_ptr = &cave[row][col];
+
+ /* Unknown grids or non-obstacle */
+ if (!see_obstacle_grid(c_ptr))
+ {
+ /* Looking to break right */
+ if (find_breakright)
+ {
+ return (TRUE);
+ }
+ }
+
+ /* Obstacle */
+ else
+ {
+ /* Looking to break left */
+ if (find_breakleft)
+ {
+ return (TRUE);
+ }
+ }
+ }
+
+ /* Hack -- look again */
+ for (i = max; i > 0; i--)
+ {
+ new_dir = cycle[chome[prev_dir] + i];
+
+ row = p_ptr->py + ddy[new_dir];
+ col = p_ptr->px + ddx[new_dir];
+
+ /* Access grid */
+ c_ptr = &cave[row][col];
+
+ /* Unknown grid or non-obstacle */
+ if (!see_obstacle_grid(c_ptr))
+ {
+ /* Looking to break left */
+ if (find_breakleft)
+ {
+ return (TRUE);
+ }
+ }
+
+ /* Obstacle */
+ else
+ {
+ /* Looking to break right */
+ if (find_breakright)
+ {
+ return (TRUE);
+ }
+ }
+ }
+ }
+
+
+ /* Not looking for open area */
+ else
+ {
+ /* No options */
+ if (!option)
+ {
+ return (TRUE);
+ }
+
+ /* One option */
+ else if (!option2)
+ {
+ /* Primary option */
+ find_current = option;
+
+ /* No other options */
+ find_prevdir = option;
+ }
+
+ /* Two options, examining corners */
+ else if (find_examine && !find_cut)
+ {
+ /* Primary option */
+ find_current = option;
+
+ /* Hack -- allow curving */
+ find_prevdir = option2;
+ }
+
+ /* Two options, pick one */
+ else
+ {
+ /* Get next location */
+ row = p_ptr->py + ddy[option];
+ col = p_ptr->px + ddx[option];
+
+ /* Don't see that it is closed off. */
+ /* This could be a potential corner or an intersection. */
+ if (!see_obstacle(option, row, col) || !see_obstacle(check_dir, row, col))
+ {
+ /* Can not see anything ahead and in the direction we */
+ /* are turning, assume that it is a potential corner. */
+ if (find_examine &&
+ see_nothing(option, row, col) &&
+ see_nothing(option2, row, col))
+ {
+ find_current = option;
+ find_prevdir = option2;
+ }
+
+ /* STOP: we are next to an intersection or a room */
+ else
+ {
+ return (TRUE);
+ }
+ }
+
+ /* This corner is seen to be enclosed; we cut the corner. */
+ else if (find_cut)
+ {
+ find_current = option2;
+ find_prevdir = option2;
+ }
+
+ /* This corner is seen to be enclosed, and we */
+ /* deliberately go the long way. */
+ else
+ {
+ find_current = option;
+ find_prevdir = option2;
+ }
+ }
+ }
+
+
+ /* About to hit a known wall, stop */
+ if (see_obstacle(find_current, p_ptr->py, p_ptr->px))
+ {
+ return (TRUE);
+ }
+
+
+ /* Failure */
+ return (FALSE);
+}
+
+
+
+/*
+ * Take one step along the current "run" path
+ */
+void run_step(int dir)
+{
+ /* Start running */
+ if (dir)
+ {
+ /* Hack -- do not start silly run */
+ if (see_obstacle(dir, p_ptr->py, p_ptr->px) &&
+ (cave[p_ptr->py + ddy[dir]][p_ptr->px + ddx[dir]].feat != FEAT_TREES))
+ {
+ /* Message */
+ msg_print("You cannot run in that direction.");
+
+ /* Disturb */
+ disturb(0, 0);
+
+ /* Done */
+ return;
+ }
+
+ /* Calculate torch radius */
+ p_ptr->update |= (PU_TORCH);
+
+ /* Initialize */
+ run_init(dir);
+ }
+
+ /* Keep running */
+ else
+ {
+ /* Update run */
+ if (run_test())
+ {
+ /* Disturb */
+ disturb(0, 0);
+
+ /* Done */
+ return;
+ }
+ }
+
+ /* Decrease the run counter */
+ if (--running <= 0) return;
+
+ /* Take time */
+ energy_use = 100;
+
+
+ /* Move the player, using the "pickup" flag */
+ move_player_aux(find_current, always_pickup, 1, TRUE);
+}
+
+
+/*
+ * Take care of the various things that can happen when you step
+ * into a space. (Objects, traps, and stores.)
+ */
+void step_effects(int y, int x, int do_pickup)
+{
+ /* Handle "objects" */
+ py_pickup_floor(do_pickup);
+
+ /* Handle "store doors" */
+ if (cave[y][x].feat == FEAT_SHOP)
+ {
+ /* Disturb */
+ disturb(0, 0);
+
+ /* Hack -- Enter store */
+ command_new = KTRL('V');
+ }
+
+ /* Discover/set off traps */
+ else if (cave[y][x].t_idx != 0)
+ {
+ /* Disturb */
+ disturb(0, 0);
+
+ if (!(cave[y][x].info & CAVE_TRDT))
+ {
+ /* Message */
+ msg_print("You found a trap!");
+
+ /* Pick a trap */
+ pick_trap(y, x);
+ }
+
+ /* Hit the trap */
+ hit_trap();
+ }
+}
+
+/*
+ * Issue a pet command
+ */
+void do_cmd_pet(void)
+{
+ int i = 0;
+
+ int num = 0;
+
+ int powers[36];
+
+ char power_desc[36][80];
+
+ bool_ flag, redraw;
+
+ int ask;
+
+ char choice;
+
+ char out_val[160];
+
+ int pets = 0, pet_ctr = 0;
+
+ bool_ all_pets = FALSE;
+
+ monster_type *m_ptr;
+
+
+ for (num = 0; num < 36; num++)
+ {
+ powers[num] = 0;
+ strcpy(power_desc[num], "");
+ }
+
+ num = 0;
+
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused to command your pets.");
+ energy_use = 0;
+ return;
+ }
+
+ /* Calculate pets */
+ /* Process the monsters (backwards) */
+ for (pet_ctr = m_max - 1; pet_ctr >= 1; pet_ctr--)
+ {
+ /* Access the monster */
+ m_ptr = &m_list[pet_ctr];
+
+ if (m_ptr->status >= MSTATUS_FRIEND) pets++;
+ }
+
+ if (pets == 0)
+ {
+ msg_print("You have no pets/companions.");
+ energy_use = 0;
+ return;
+ }
+ else
+ {
+ strcpy(power_desc[num], "dismiss pets");
+ powers[num++] = 1;
+ strcpy(power_desc[num], "dismiss companions");
+ powers[num++] = 10;
+ strcpy(power_desc[num], "call pets");
+ powers[num++] = 2;
+ strcpy(power_desc[num], "follow me");
+ powers[num++] = 6;
+ strcpy(power_desc[num], "seek and destroy");
+ powers[num++] = 3;
+ if (p_ptr->pet_open_doors)
+ strcpy(power_desc[num], "disallow open doors");
+ else
+ strcpy(power_desc[num], "allow open doors");
+ powers[num++] = 4;
+ if (p_ptr->pet_pickup_items)
+ strcpy(power_desc[num], "disallow pickup items");
+ else
+ strcpy(power_desc[num], "allow pickup items");
+ powers[num++] = 5;
+ strcpy(power_desc[num], "give target to a friend");
+ powers[num++] = 7;
+ strcpy(power_desc[num], "give target to all friends");
+ powers[num++] = 8;
+ strcpy(power_desc[num], "friend forget target");
+ powers[num++] = 9;
+ }
+
+ /* Nothing chosen yet */
+ flag = FALSE;
+
+ /* No redraw yet */
+ redraw = FALSE;
+
+ /* Build a prompt (accept all spells) */
+ if (num <= 26)
+ {
+ /* Build a prompt (accept all spells) */
+ strnfmt(out_val, 78,
+ "(Command %c-%c, *=List, ESC=exit) Select a command: ", I2A(0),
+ I2A(num - 1));
+ }
+ else
+ {
+ strnfmt(out_val, 78,
+ "(Command %c-%c, *=List, ESC=exit) Select a command: ", I2A(0),
+ '0' + num - 27);
+ }
+
+ /* Get a command from the user */
+ while (!flag && get_com(out_val, &choice))
+ {
+ /* Request redraw */
+ if ((choice == ' ') || (choice == '*') || (choice == '?'))
+ {
+ /* Show the list */
+ if (!redraw)
+ {
+ byte y = 1, x = 0;
+ int ctr = 0;
+ char dummy[80];
+
+ strcpy(dummy, "");
+
+ /* Show list */
+ redraw = TRUE;
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ prt("", y++, x);
+
+ while (ctr < num)
+ {
+ strnfmt(dummy, 80, "%c) %s", I2A(ctr), power_desc[ctr]);
+ prt(dummy, y + ctr, x);
+ ctr++;
+ }
+
+ if (ctr < 17)
+ {
+ prt("", y + ctr, x);
+ }
+ else
+ {
+ prt("", y + 17, x);
+ }
+ }
+
+ /* Hide the list */
+ else
+ {
+ /* Hide list */
+ redraw = FALSE;
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Redo asking */
+ continue;
+ }
+
+ if (choice == '\r' && num == 1)
+ {
+ choice = 'a';
+ }
+
+ if (isalpha(choice))
+ {
+ /* Note verify */
+ ask = (isupper(choice));
+
+ /* Lowercase */
+ if (ask) choice = tolower(choice);
+
+ /* Extract request */
+ i = (islower(choice) ? A2I(choice) : -1);
+ }
+ else
+ {
+ ask = FALSE; /* Can't uppercase digits */
+
+ i = choice - '0' + 26;
+ }
+
+ /* Totally Illegal */
+ if ((i < 0) || (i >= num))
+ {
+ bell();
+ continue;
+ }
+
+ /* Verify it */
+ if (ask)
+ {
+ char tmp_val[160];
+
+ /* Prompt */
+ strnfmt(tmp_val, 78, "Use %s? ", power_desc[i]);
+
+ /* Belay that order */
+ if (!get_check(tmp_val)) continue;
+ }
+
+ /* Stop the loop */
+ flag = TRUE;
+ }
+
+ /* Restore the screen */
+ if (redraw)
+ {
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Abort if needed */
+ if (!flag)
+ {
+ energy_use = 0;
+ return;
+ }
+
+ switch (powers[i])
+ {
+ /* forget target */
+ case 9:
+ {
+ monster_type *m_ptr;
+ int ii, jj;
+
+ msg_print("Select the friendly monster:");
+ if (!tgt_pt(&ii, &jj)) return;
+
+ if (cave[jj][ii].m_idx)
+ {
+ m_ptr = &m_list[cave[jj][ii].m_idx];
+
+ if (m_ptr->status < MSTATUS_PET)
+ {
+ msg_print("You cannot give orders to this monster.");
+ return;
+ }
+
+ m_ptr->target = -1;
+ }
+ break;
+ }
+ /* Give target to all */
+ case 8:
+ {
+ monster_type *m_ptr;
+ int ii, jj, i;
+
+
+ msg_print("Select the target monster:");
+ if (!tgt_pt(&ii, &jj)) return;
+
+ if (cave[jj][ii].m_idx)
+ {
+ msg_print("Target selected.");
+
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ m_ptr = &m_list[i];
+
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status < MSTATUS_PET) continue;
+
+ m_ptr->target = cave[jj][ii].m_idx;
+ }
+ }
+ else
+ {
+ msg_print("This is not a correct target.");
+ return;
+ }
+ break;
+ }
+ case 1: /* Dismiss pets */
+ {
+ int Dismissed = 0;
+
+ if (get_check("Dismiss all pets? ")) all_pets = TRUE;
+
+ /* Process the monsters (backwards) */
+ for (pet_ctr = m_max - 1; pet_ctr >= 1; pet_ctr--)
+ {
+ monster_race *r_ptr;
+
+ /* Access the monster */
+ m_ptr = &m_list[pet_ctr];
+ r_ptr = &r_info[m_ptr->r_idx];
+
+ if ((!(r_ptr->flags7 & RF7_NO_DEATH)) && ((m_ptr->status == MSTATUS_PET) || (m_ptr->status == MSTATUS_FRIEND))) /* Get rid of it! */
+ {
+ bool_ checked = FALSE;
+ char command;
+ bool_ delete_this = FALSE;
+
+ if (all_pets)
+ {
+ delete_this = TRUE;
+ }
+ else
+ {
+ char friend_name[80], check_friend[80];
+ monster_desc(friend_name, m_ptr, 0x80);
+ strnfmt(check_friend, 80, "Dismiss %s? (Escape to cancel)", friend_name);
+
+ while (!checked)
+ {
+ if (!get_com(check_friend, &command))
+ {
+ /* get out of loop */
+ checked = TRUE;
+ pet_ctr = 0;
+ }
+ else switch (command)
+ {
+ case 'Y':
+ case 'y':
+ delete_this = TRUE;
+ checked = TRUE;
+ break;
+ case 'n':
+ case 'N':
+ checked = TRUE;
+ break;
+ default:
+ bell();
+ break;
+ }
+ }
+ }
+
+ if (delete_this)
+ {
+ delete_monster_idx(pet_ctr);
+ Dismissed++;
+ }
+ }
+ }
+
+ msg_format("You have dismissed %d pet%s.", Dismissed,
+ (Dismissed == 1 ? "" : "s"));
+ break;
+ }
+ case 10: /* Dismiss companions */
+ {
+ int Dismissed = 0;
+
+ if (get_check("Dismiss all companions? ")) all_pets = TRUE;
+
+ /* Process the monsters (backwards) */
+ for (pet_ctr = m_max - 1; pet_ctr >= 1; pet_ctr--)
+ {
+ monster_race *r_ptr;
+
+ /* Access the monster */
+ m_ptr = &m_list[pet_ctr];
+ r_ptr = &r_info[m_ptr->r_idx];
+
+ if ((!(r_ptr->flags7 & RF7_NO_DEATH)) && ((m_ptr->status == MSTATUS_COMPANION))) /* Get rid of it! */
+ {
+ bool_ delete_this = FALSE;
+
+ if (all_pets)
+ delete_this = TRUE;
+ else
+ {
+ char friend_name[80], check_friend[80];
+ monster_desc(friend_name, m_ptr, 0x80);
+ strnfmt(check_friend, 80, "Dismiss %s? ", friend_name);
+
+ if (get_check(check_friend))
+ delete_this = TRUE;
+ }
+
+ if (delete_this)
+ {
+ delete_monster_idx(pet_ctr);
+ Dismissed++;
+ }
+ }
+ }
+
+ msg_format("You have dismissed %d companion%s.", Dismissed,
+ (Dismissed == 1 ? "" : "s"));
+ break;
+ }
+ /* Call pets */
+ case 2:
+ {
+ p_ptr->pet_follow_distance = 1;
+ break;
+ }
+ /* "Seek and destroy" */
+ case 3:
+ {
+ p_ptr->pet_follow_distance = 255;
+ break;
+ }
+ /* flag - allow pets to open doors */
+ case 4:
+ {
+ p_ptr->pet_open_doors = !p_ptr->pet_open_doors;
+ break;
+ }
+ /* flag - allow pets to pickup items */
+ case 5:
+ {
+ p_ptr->pet_pickup_items = !p_ptr->pet_pickup_items;
+
+ /* Drop objects being carried by pets */
+ if (!p_ptr->pet_pickup_items)
+ {
+ for (pet_ctr = m_max - 1; pet_ctr >= 1; pet_ctr--)
+ {
+ /* Access the monster */
+ m_ptr = &m_list[pet_ctr];
+
+ if (m_ptr->status >= MSTATUS_PET)
+ {
+ monster_drop_carried_objects(m_ptr);
+ }
+ }
+ }
+
+ break;
+ }
+ /* "Follow Me" */
+ case 6:
+ {
+ p_ptr->pet_follow_distance = 6;
+ break;
+ }
+ }
+}
+
+/*
+ * Incarnate into a body
+ */
+bool_ do_cmd_integrate_body()
+{
+ cptr q, s;
+
+ int item;
+
+ object_type *o_ptr;
+
+
+ if (!p_ptr->disembodied)
+ {
+ msg_print("You are already in a body.");
+ return FALSE;
+ }
+
+ /* Restrict choices to monsters */
+ item_tester_tval = TV_CORPSE;
+
+ /* Get an item */
+ q = "Incarnate in which body? ";
+ s = "You have no corpse to incarnate in.";
+ if (!get_item(&item, q, s, (USE_FLOOR))) return FALSE;
+
+ o_ptr = &o_list[0 - item];
+
+ if (o_ptr->sval != SV_CORPSE_CORPSE)
+ {
+ msg_print("You must select a corpse.");
+ return FALSE;
+ }
+
+ p_ptr->body_monster = o_ptr->pval2;
+ p_ptr->chp = o_ptr->pval3;
+
+ floor_item_increase(0 - item, -1);
+ floor_item_describe(0 - item);
+ floor_item_optimize(0 - item);
+
+ msg_print("Your spirit is incarnated in your new body.");
+ p_ptr->wraith_form = FALSE;
+ p_ptr->disembodied = FALSE;
+ do_cmd_redraw();
+
+ return TRUE;
+}
+
+/*
+ * Leave a body
+ */
+bool_ do_cmd_leave_body(bool_ drop_body)
+{
+ object_type *o_ptr, forge;
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+ int i;
+
+
+ if (p_ptr->disembodied)
+ {
+ msg_print("You are already disembodied.");
+ return FALSE;
+ }
+
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ if (p_ptr->body_parts[i - INVEN_WIELD] && p_ptr->inventory[i].k_idx &&
+ cursed_p(&p_ptr->inventory[i]))
+ {
+ msg_print("A cursed object is preventing you from leaving your body.");
+ return FALSE;
+ }
+ }
+
+ if (drop_body)
+ {
+ if (magik(25 + get_skill_scale(SKILL_POSSESSION, 25) + get_skill(SKILL_PRESERVATION)))
+ {
+ o_ptr = &forge;
+ object_prep(o_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_CORPSE));
+ o_ptr->number = 1;
+ o_ptr->pval = 0;
+ o_ptr->pval2 = p_ptr->body_monster;
+ o_ptr->pval3 = p_ptr->chp;
+ o_ptr->weight = (r_ptr->weight + rand_int(r_ptr->weight) / 10) + 1;
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ o_ptr->ident |= IDENT_STOREB;
+
+ /* Unique corpses are unique */
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ o_ptr->name1 = 201;
+ }
+
+ drop_near(o_ptr, -1, p_ptr->py, p_ptr->px);
+ }
+ else
+ msg_print
+ ("You do not manage to keep the corpse from rotting away.");
+ }
+
+ msg_print("Your spirit leaves your body.");
+ p_ptr->disembodied = TRUE;
+
+ /* Turn into a lost soul(just for the picture) */
+ p_ptr->body_monster = test_monster_name("Lost soul");
+ do_cmd_redraw();
+
+ return (TRUE);
+}
+
+
+bool_ execute_inscription(byte i, byte y, byte x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+
+ /* Not enough mana in the current grid */
+ if (c_ptr->mana < inscription_info[i].mana) return (TRUE);
+
+
+ /* Reduce the grid mana -- note: it can't be restored */
+ c_ptr->mana -= inscription_info[i].mana;
+
+ /* Analyse inscription type */
+ switch (i)
+ {
+ case INSCRIP_LIGHT:
+ {
+ msg_print("The inscription shines in a bright light!");
+ lite_room(y, x);
+
+ break;
+ }
+
+ case INSCRIP_DARK:
+ {
+ msg_print("The inscription is enveloped in a dark aura!");
+ unlite_room(y, x);
+
+ break;
+ }
+
+ case INSCRIP_STORM:
+ {
+ msg_print("The inscription releases a powerful storm!");
+ project(0, 3, y, x, damroll(10, 10),
+ GF_ELEC, PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM |
+ PROJECT_KILL | PROJECT_JUMP);
+
+ break;
+ }
+
+ case INSCRIP_PROTECTION:
+ {
+ return (FALSE);
+
+ break;
+ }
+
+ case INSCRIP_DWARF_SUMMON:
+ {
+ int yy = y, xx = x;
+
+ scatter(&yy, &xx, y, x, 3);
+ place_monster_one(yy, xx, test_monster_name("Dwarven Warrior"),
+ 0, FALSE, MSTATUS_FRIEND);
+
+ break;
+ }
+
+ case INSCRIP_CHASM:
+ {
+ monster_type *m_ptr;
+ monster_race *r_ptr;
+ cave_type *c_ptr;
+ int ii = x, ij = y;
+
+ cave_set_feat(ij, ii, FEAT_DARK_PIT);
+ msg_print("A chasm appears in the floor!");
+
+ if (cave[ij][ii].m_idx)
+ {
+ m_ptr = &m_list[cave[ij][ii].m_idx];
+ r_ptr = race_inf(m_ptr);
+
+ if (r_ptr->flags7 & RF7_CAN_FLY)
+ {
+ msg_print("The monster simply flies over the chasm.");
+ }
+ else
+ {
+ if (!(r_ptr->flags1 & RF1_UNIQUE))
+ {
+ msg_print("The monster falls in the chasm!");
+ delete_monster_idx(cave[ij][ii].m_idx);
+ }
+ }
+ }
+
+ if (cave[ij][ii].o_idx)
+ {
+ s16b this_o_idx, next_o_idx = 0;
+
+ c_ptr = &cave[ij][ii];
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx;
+ this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+ bool_ plural = FALSE;
+
+ char o_name[80];
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ if (o_ptr->number > 1) plural = TRUE;
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Effect "observed" */
+ if (o_ptr->marked)
+ {
+ object_desc(o_name, o_ptr, FALSE, 0);
+ }
+
+ /* Artifacts get to resist */
+ if (o_ptr->name1)
+ {
+ /* Observe the resist */
+ if (o_ptr->marked)
+ {
+ msg_format("The %s %s simply fly over the chasm!",
+ o_name, (plural ? "are" : "is"));
+ }
+ }
+
+ /* Kill it */
+ else
+ {
+ /* Delete the object */
+ delete_object_idx(this_o_idx);
+
+ /* Redraw */
+ lite_spot(ij, ii);
+ }
+ }
+ }
+
+ break;
+ }
+
+ case INSCRIP_BLACK_FIRE:
+ {
+ msg_print("The inscription releases a blast of hellfire!");
+ project(0, 3, y, x, 200,
+ GF_HELL_FIRE, PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM |
+ PROJECT_KILL | PROJECT_JUMP);
+
+ break;
+ }
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * Choose an inscription and engrave it
+ */
+void do_cmd_engrave()
+{
+ char buf[41] = "";
+
+ byte i;
+
+ strnfmt(buf, 41, "%s", inscription_info[cave[p_ptr->py][p_ptr->px].inscription].text);
+
+ get_string("Engrave what? ", buf, 40);
+
+ /* Silently do nothing when player his escape or enters an empty string */
+ if (!buf[0]) return;
+
+ for (i = 0; i < MAX_INSCRIPTIONS; i++)
+ {
+ if (!strcmp(inscription_info[i].text, buf))
+ {
+ if (inscription_info[i].know)
+ {
+ /* Save the inscription */
+ cave[p_ptr->py][p_ptr->px].inscription = i;
+ }
+ else
+ msg_print("You can't use this inscription for now.");
+ }
+ }
+
+ /* Execute the inscription */
+ if (inscription_info[cave[p_ptr->py][p_ptr->px].inscription].when & INSCRIP_EXEC_ENGRAVE)
+ {
+ execute_inscription(cave[p_ptr->py][p_ptr->px].inscription, p_ptr->py, p_ptr->px);
+ }
+
+ energy_use += 300;
+}
+
+
+/*
+ * Let's do a spinning around attack: -- DG --
+ * aDb
+ * y@k
+ * ooT
+ * Ah ... all of those will get hit.
+ */
+void do_spin()
+{
+ int i, j;
+
+
+ msg_print("You start spinning around...");
+
+ for (j = p_ptr->py - 1; j <= p_ptr->py + 1; j++)
+ {
+ for (i = p_ptr->px - 1; i <= p_ptr->px + 1; i++)
+ {
+ /* Avoid stupid bugs */
+ if (in_bounds(j, i) && cave[j][i].m_idx)
+ py_attack(j, i, 1);
+ }
+ }
+}
diff --git a/src/cmd2.c b/src/cmd2.c
new file mode 100644
index 00000000..2d05c125
--- /dev/null
+++ b/src/cmd2.c
@@ -0,0 +1,5107 @@
+/* File: cmd2.c */
+
+/* Purpose: Movement commands (part 2) */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+void do_cmd_immovable_special(void);
+
+/*
+ * Try to bash an altar
+ */
+static bool_ do_cmd_bash_altar(int y, int x)
+{
+ msg_print("Are you mad? You want to anger the gods?");
+ return (FALSE);
+}
+
+
+/*
+ * Try to bash a fountain
+ */
+static bool_ do_cmd_bash_fountain(int y, int x)
+{
+ int bash, temp;
+
+ bool_ more = TRUE;
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+
+ if ((p_ptr->body_monster != 0) && !(r_ptr->flags2 & RF2_BASH_DOOR))
+ {
+ msg_print("You cannot do that.");
+
+ return (FALSE);
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Message */
+ msg_print("You smash into the fountain!");
+
+ /* Hack -- Bash power based on strength */
+ /* (Ranges from 3 to 20 to 100 to 200) */
+ bash = adj_str_blow[p_ptr->stat_ind[A_STR]];
+
+ /* Compare bash power to door power XXX XXX XXX */
+ temp = (bash - 50);
+
+ /* Hack -- always have a chance */
+ if (temp < 1) temp = 1;
+
+ /* Hack -- attempt to bash down the door */
+ if (rand_int(200) < temp)
+ {
+ /* Message */
+ msg_print("The fountain breaks!");
+
+ fire_ball(GF_WATER, 5, damroll(6, 8), 2);
+
+ cave_set_feat(y, x, FEAT_DEEP_WATER);
+ more = FALSE;
+ }
+
+ return (more);
+}
+
+
+/*
+ * Go up one level
+ */
+void do_cmd_go_up(void)
+{
+ bool_ go_up = FALSE, go_up_many = FALSE, prob_traveling = FALSE;
+
+ cave_type *c_ptr;
+
+ int oldl = dun_level;
+
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+
+ /* Player grid */
+ c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ /* Can we ? */
+ if (process_hooks(HOOK_STAIR, "(s)", "up")) return;
+
+ /* Normal up stairs */
+ if ((c_ptr->feat == FEAT_LESS) || (c_ptr->feat == FEAT_WAY_LESS))
+ {
+ if (!dun_level)
+ {
+ go_up = TRUE;
+ }
+ else if ((dungeon_flags2 & DF2_ASK_LEAVE))
+ {
+ go_up = get_check("Leave this unique level forever? ");
+ }
+ else if (confirm_stairs)
+ {
+ go_up = get_check("Really leave the level? ");
+ }
+ else
+ {
+ go_up = TRUE;
+ }
+ }
+
+ /* Shaft up */
+ else if (c_ptr->feat == FEAT_SHAFT_UP)
+ {
+ if (dun_level == 1)
+ {
+ go_up = TRUE;
+ }
+ else if ((dungeon_flags2 & DF2_ASK_LEAVE))
+ {
+ go_up = get_check("Leave this unique level forever? ");
+ }
+ else if (confirm_stairs)
+ {
+ go_up_many = get_check("Really leave the level? ");
+ }
+ else
+ {
+ go_up_many = TRUE;
+ }
+ }
+
+ /* Quest exit */
+ else if (c_ptr->feat == FEAT_QUEST_EXIT)
+ {
+ leaving_quest = p_ptr->inside_quest;
+
+ if ((dungeon_flags2 & DF2_ASK_LEAVE) &&
+ !get_check("Leave this unique level forever? "))
+ return;
+
+ p_ptr->inside_quest = c_ptr->special;
+ dun_level = 0;
+ p_ptr->oldpx = 0;
+ p_ptr->oldpy = 0;
+ p_ptr->leaving = TRUE;
+
+ return;
+ }
+
+ /* Exits to previous area in flat terrains */
+ else if (!(dungeon_flags1 & DF1_FLAT) &&
+ p_ptr->prob_travel && !p_ptr->inside_quest)
+ {
+ if (d_ptr->mindepth == dun_level) return;
+
+ if (dungeon_flags2 & DF2_NO_EASY_MOVE)
+ {
+ msg_print("Some powerful force prevents your from teleporting.");
+ return;
+ }
+
+ prob_traveling = TRUE;
+
+ if (confirm_stairs)
+ {
+ if (get_check("Really leave the level? "))
+ go_up = TRUE;
+ }
+ else
+ {
+ go_up = TRUE;
+ }
+ }
+ else
+ {
+ msg_print("I see no up staircase here.");
+ return;
+ }
+
+ if (go_up || go_up_many)
+ {
+
+ energy_use = 0;
+
+ /* Success */
+ if (c_ptr->feat == FEAT_WAY_LESS)
+ msg_print("You enter the previous area.");
+ else
+ msg_print("You enter a maze of up staircases.");
+
+ autosave_checkpoint();
+
+ if (p_ptr->inside_quest)
+ {
+ dun_level = 1;
+ leaving_quest = p_ptr->inside_quest;
+
+ p_ptr->inside_quest = c_ptr->special;
+ }
+
+ /* Create a way back */
+ if (go_up_many)
+ create_down_shaft = TRUE;
+ else
+ create_down_stair = TRUE;
+
+ /* New depth */
+ if (go_up)
+ dun_level--;
+ else
+ {
+ dun_level -= randint(3) + 1;
+ if (dun_level <= 0) dun_level = 0;
+ }
+
+ if (c_ptr->special && (!prob_traveling))
+ {
+ dun_level = oldl;
+ dun_level = get_flevel();
+ dungeon_type = c_ptr->special;
+ dun_level += d_info[dungeon_type].mindepth;
+ }
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ }
+}
+
+
+/*
+ * Returns TRUE if we are in the Between...
+ */
+static bool_ between_effect(void)
+{
+ byte bx, by;
+
+
+ if (cave[p_ptr->py][p_ptr->px].feat == FEAT_BETWEEN)
+ {
+
+ bx = cave[p_ptr->py][p_ptr->px].special & 255;
+ by = cave[p_ptr->py][p_ptr->px].special >> 8;
+
+ msg_print("You fall into the void.");
+ msg_print("Brrrr! It's deadly cold.");
+
+ swap_position(by, bx);
+
+ /* To avoid being teleported back */
+ energy_use = 100;
+
+ return (TRUE);
+ }
+
+ else if (cave[p_ptr->py][p_ptr->px].feat == FEAT_BETWEEN2)
+ {
+ between_exit *be_ptr = &between_exits[cave[p_ptr->py][p_ptr->px].special];
+
+ p_ptr->wild_mode = FALSE;
+ p_ptr->wilderness_x = be_ptr->wild_x;
+ p_ptr->wilderness_y = be_ptr->wild_y;
+ p_ptr->oldpx = p_ptr->px = be_ptr->px;
+ p_ptr->oldpy = p_ptr->py = be_ptr->py;
+ dungeon_type = be_ptr->d_idx;
+ dun_level = be_ptr->level;
+ p_ptr->leaving = TRUE;
+
+ return (TRUE);
+ }
+ else
+ return (FALSE);
+}
+
+/*
+ * Go down one level
+ */
+void do_cmd_go_down(void)
+{
+ cave_type *c_ptr;
+
+ bool_ go_down = FALSE, go_down_many = FALSE, prob_traveling = FALSE;
+
+ bool_ fall_trap = FALSE;
+
+ char i;
+
+ int old_dun = dun_level;
+
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+
+ /* MUST be actived now */
+ if (between_effect()) return;
+
+ /* Player grid */
+ c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ if (p_ptr->astral && (dun_level == 98)) return;
+
+ if (c_ptr->t_idx == TRAP_OF_SINKING) fall_trap = TRUE;
+
+ /* test if on special level */
+ if ((dungeon_flags2 & DF2_ASK_LEAVE))
+ {
+ prt("Leave this unique level forever (y/n) ? ", 0, 0);
+ flush();
+ i = inkey();
+ prt("", 0, 0);
+ if (i != 'y') return;
+ }
+
+ /* Can we ? */
+ if (process_hooks(HOOK_STAIR, "(s)", "down")) return;
+
+ /* Normal up stairs */
+ if (c_ptr->feat == FEAT_SHAFT_DOWN)
+ {
+ if (!dun_level)
+ {
+ go_down = TRUE;
+
+ /* Save old player position */
+ p_ptr->oldpx = p_ptr->px;
+ p_ptr->oldpy = p_ptr->py;
+ }
+ else
+ {
+ if (confirm_stairs)
+ {
+ if (get_check("Really leave the level? "))
+ go_down_many = TRUE;
+ }
+ else
+ {
+ go_down_many = TRUE;
+ }
+ }
+ }
+
+ /* Normal stairs */
+ else if ((c_ptr->feat == FEAT_MORE) || (c_ptr->feat == FEAT_WAY_MORE))
+ {
+ if (p_ptr->prob_travel)
+ {
+ if (d_ptr->maxdepth == dun_level) return;
+ }
+ if (!dun_level)
+ {
+ go_down = TRUE;
+
+ /* Save old player position */
+ p_ptr->oldpx = p_ptr->px;
+ p_ptr->oldpy = p_ptr->py;
+ }
+ else
+ {
+ if (confirm_stairs)
+ {
+ if (get_check("Really leave the level? "))
+ go_down = TRUE;
+ }
+ else
+ {
+ go_down = TRUE;
+ }
+ }
+ }
+
+ /* Handle quest areas -KMW- */
+ else if (c_ptr->feat == FEAT_QUEST_ENTER)
+ {
+ /* Enter quest level */
+ enter_quest();
+
+ return;
+ }
+
+ else if (!(dungeon_flags1 & DF1_FLAT) &&
+ p_ptr->prob_travel && !p_ptr->inside_quest)
+ {
+ if (d_ptr->maxdepth == dun_level) return;
+
+ if (dungeon_flags2 & DF2_NO_EASY_MOVE)
+ {
+ msg_print("Some powerfull force prevents your from teleporting.");
+ return;
+ }
+
+ prob_traveling = TRUE;
+
+ if (confirm_stairs)
+ {
+ if (get_check("Really leave the level? "))
+ go_down = TRUE;
+ }
+ else
+ {
+ go_down = TRUE;
+ }
+ }
+
+ else if (!(fall_trap))
+ {
+ msg_print("I see no down staircase here.");
+ return;
+ }
+
+ if (go_down || go_down_many)
+ {
+ energy_use = 0;
+
+ if (fall_trap)
+ msg_print("You deliberately jump through the trap door.");
+ else
+ {
+ if (c_ptr->feat == FEAT_WAY_MORE)
+ msg_print("You enter the next area.");
+ else
+ msg_print("You enter a maze of down staircases.");
+ }
+
+ autosave_checkpoint();
+
+ /* Go down */
+ if (go_down)
+ {
+ dun_level++;
+ }
+ else if (go_down_many)
+ {
+ int i = randint(3) + 1, j;
+
+ for (j = 1; j < i; j++)
+ {
+ dun_level++;
+ if (is_quest(dun_level + i - 1)) break;
+ if (d_ptr->maxdepth == dun_level) break;
+ }
+ }
+
+ /* We change place */
+ if (c_ptr->special && (!prob_traveling))
+ {
+ if (d_info[c_ptr->special].min_plev <= p_ptr->lev)
+ {
+ dungeon_info_type *d_ptr = &d_info[c_ptr->special];
+
+ /* Do the lua scripts refuse ? ;) */
+ if (process_hooks(HOOK_ENTER_DUNGEON, "(d)", c_ptr->special))
+ {
+ dun_level = old_dun;
+ return;
+ }
+
+ /* Ok go in the new dungeon */
+ dungeon_type = c_ptr->special;
+ d_ptr = &d_info[dungeon_type];
+
+ if ((p_ptr->wilderness_x == d_ptr->ix) &&
+ (p_ptr->wilderness_y == d_ptr->iy))
+ {
+ dun_level = d_ptr->mindepth;
+ }
+ else if ((p_ptr->wilderness_x == d_ptr->ox) &&
+ (p_ptr->wilderness_y == d_ptr->oy))
+ {
+ dun_level = d_ptr->maxdepth;
+ }
+ else
+ {
+ dun_level = d_ptr->mindepth;
+ }
+
+ msg_format("You go into %s",
+ d_text + d_info[dungeon_type].text);
+ }
+ else
+ {
+ msg_print
+ ("You don't feel yourself experienced enough to go there...");
+ dun_level = old_dun;
+ return;
+ }
+ }
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+
+ if (!fall_trap)
+ {
+ /* Create a way back */
+ if (go_down_many)
+ create_up_shaft = TRUE;
+ else
+ create_up_stair = TRUE;
+ }
+ }
+}
+
+
+
+/*
+ * Simple command to "search" for one turn
+ */
+void do_cmd_search(void)
+{
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Search */
+ search();
+}
+
+
+/*
+ * Hack -- toggle search mode
+ */
+void do_cmd_toggle_search(void)
+{
+ /* Stop searching */
+ if (p_ptr->searching)
+ {
+ /* Clear the searching flag */
+ p_ptr->searching = FALSE;
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+ }
+
+ /* Start searching */
+ else
+ {
+ /* Set the searching flag */
+ p_ptr->searching = TRUE;
+
+ /* Update stuff */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw stuff */
+ p_ptr->redraw |= (PR_STATE | PR_SPEED);
+ }
+}
+
+
+
+/*
+ * Determine if a grid contains a chest
+ */
+static s16b chest_check(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ s16b this_o_idx, next_o_idx = 0;
+
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Skip unknown chests XXX XXX */
+ /* if (!o_ptr->marked) continue; */
+
+ /* Check for chest */
+ if (o_ptr->tval == TV_CHEST) return (this_o_idx);
+ }
+
+ /* No chest */
+ return (0);
+}
+
+
+/*
+ * Allocates objects upon opening a chest -BEN-
+ *
+ * Disperse treasures from the given chest, centered at (x,y).
+ *
+ * Small chests often contain "gold", while Large chests always contain
+ * items. Wooden chests contain 2 items, Iron chests contain 4 items,
+ * and Steel chests contain 6 items. The "value" of the items in a
+ * chest is based on the "power" of the chest, which is in turn based
+ * on the level on which the chest is generated.
+ */
+static void chest_death(int y, int x, s16b o_idx)
+{
+ int number;
+
+ bool_ small;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ object_type *o_ptr = &o_list[o_idx];
+
+
+ /* Small chests often hold "gold" */
+ small = (o_ptr->sval < SV_CHEST_MIN_LARGE);
+
+ /* Determine how much to drop (see above) */
+ number = (o_ptr->sval % SV_CHEST_MIN_LARGE) * 2;
+
+ /* Zero pval means empty chest */
+ if (!o_ptr->pval) number = 0;
+
+ /* Opening a chest */
+ opening_chest = TRUE;
+
+ /* Determine the "value" of the items */
+ object_level = ABS(o_ptr->pval) + 10;
+
+ /* Drop some objects (non-chests) */
+ for (; number > 0; --number)
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Small chests often drop gold */
+ if (small && (rand_int(100) < 75))
+ {
+ /* Make some gold */
+ if (!make_gold(q_ptr)) continue;
+ }
+
+ /* Otherwise drop an item */
+ else
+ {
+ /* Make an object */
+ if (!make_object(q_ptr, FALSE, FALSE, d_info[dungeon_type].objs))
+ continue;
+ }
+
+ /* Drop it in the dungeon */
+ drop_near(q_ptr, -1, y, x);
+ }
+
+ /* Reset the object level */
+ object_level = dun_level;
+
+ /* No longer opening a chest */
+ opening_chest = FALSE;
+
+ /* Empty */
+ o_ptr->pval = 0;
+ o_ptr->pval2 = 0;
+
+ /* Known */
+ object_known(o_ptr);
+}
+
+
+/*
+ * Chests have traps too.
+ *
+ * Exploding chest destroys contents (and traps).
+ * Note that the chest itself is never destroyed.
+ */
+static void chest_trap(int y, int x, s16b o_idx)
+{
+ int trap;
+
+ object_type *o_ptr = &o_list[o_idx];
+
+ bool_ ident = FALSE;
+
+
+ /* Ignore disarmed chests */
+ if (o_ptr->pval <= 0) return;
+
+ /* Obtain the trap */
+ trap = o_ptr->pval;
+
+ /* Message */
+ msg_print("You found a trap!");
+
+ /* Set off trap */
+ ident = player_activate_trap_type(y, x, o_ptr, o_idx);
+ if (ident)
+ {
+ t_info[o_ptr->pval].ident = TRUE;
+ msg_format("You identified the trap as %s.",
+ t_name + t_info[trap].name);
+ }
+}
+
+
+/*
+ * Attempt to open the given chest at the given location
+ *
+ * Assume there is no monster blocking the destination
+ *
+ * Returns TRUE if repeated commands may continue
+ */
+static bool_ do_cmd_open_chest(int y, int x, s16b o_idx)
+{
+ int i, j;
+
+ bool_ flag = TRUE;
+
+ bool_ more = FALSE;
+
+ object_type *o_ptr = &o_list[o_idx];
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+
+ if ((p_ptr->body_monster != 0) && !(r_ptr->flags2 & RF2_OPEN_DOOR))
+ {
+ msg_print("You cannot open chests.");
+
+ return (FALSE);
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Attempt to unlock it */
+ if (o_ptr->pval > 0)
+ {
+ /* Assume locked, and thus not open */
+ flag = FALSE;
+
+ /* Get the "disarm" factor */
+ i = p_ptr->skill_dis;
+
+ /* Penalize some conditions */
+ if (p_ptr->blind || no_lite()) i = i / 10;
+ if (p_ptr->confused || p_ptr->image) i = i / 10;
+
+ /* Extract the difficulty */
+ j = i - o_ptr->pval;
+
+ /* Always have a small chance of success */
+ if (j < 2) j = 2;
+
+ /* Success -- May still have traps */
+ if (rand_int(100) < j)
+ {
+ msg_print("You have picked the lock.");
+ gain_exp(1);
+ flag = TRUE;
+ }
+
+ /* Failure -- Keep trying */
+ else
+ {
+ /* We may continue repeating */
+ more = TRUE;
+
+ if (flush_failure) flush();
+
+ msg_print("You failed to pick the lock.");
+ }
+ }
+
+ /* Allowed to open */
+ if (flag)
+ {
+ /* Apply chest traps, if any */
+ chest_trap(y, x, o_idx);
+
+ /* Let the Chest drop items */
+ chest_death(y, x, o_idx);
+ }
+
+ /* Result */
+ return (more);
+}
+
+
+/*
+ * Original code by TNB, improvement for Angband 2.9.3 by rr9
+ * Slightly modified for ToME because of its trap implementation
+ */
+
+/*
+ * Return TRUE if the given grid is an open door
+ */
+static bool_ is_open(cave_type *c_ptr)
+{
+ return (c_ptr->feat == FEAT_OPEN);
+}
+
+
+/*
+ * Return TRUE if the given grid is a closed door
+ */
+static bool_ is_closed(cave_type *c_ptr)
+{
+ byte feat;
+
+ if (c_ptr->mimic) feat = c_ptr->mimic;
+ else feat = c_ptr->feat;
+
+ return ((feat >= FEAT_DOOR_HEAD) && (feat <= FEAT_DOOR_TAIL));
+}
+
+
+/*
+ * Return TRUE if the given grid has a trap
+ */
+static bool_ is_trap(cave_type *c_ptr)
+{
+ return ((c_ptr->info & (CAVE_TRDT)) != 0);
+}
+
+
+/*
+ * Return the number of doors/traps around (or under)
+ * the character using the filter function 'test'
+ */
+static int count_feats(int *y, int *x, bool_ (*test) (cave_type *c_ptr),
+ bool_ under)
+{
+ int d;
+
+ int xx, yy;
+
+ int count;
+
+
+ /* Clear match counter */
+ count = 0;
+
+ /* Check around (and under) the character */
+ for (d = 0; d < 9; d++)
+ {
+ /* Ignore current grid if told so -- See tables.c */
+ if ((d == 8) && !under) continue;
+
+ /* Extract adjacent (legal) location */
+ yy = p_ptr->py + ddy_ddd[d];
+ xx = p_ptr->px + ddx_ddd[d];
+
+ /* Paranoia */
+ if (!in_bounds(yy, xx)) continue;
+
+ /* Must have knowledge */
+ if (!(cave[yy][xx].info & (CAVE_MARK))) continue;
+
+ /* Not looking for this feature */
+ if (!(*test) (&cave[yy][xx])) continue;
+
+ /* Count it */
+ count++;
+
+ /* Remember the location. Only meaningful if there's
+ exactly one match */
+ *y = yy;
+ *x = xx;
+ }
+
+ /* All done */
+ return (count);
+}
+
+
+/*
+ * Return the number of chests around (or under) the character.
+ * If requested, count only trapped chests.
+ */
+static int count_chests(int *y, int *x, bool_ trapped)
+{
+ int d, count, o_idx;
+
+ object_type *o_ptr;
+
+
+ /* Count how many matches */
+ count = 0;
+
+ /* Check around (and under) the character */
+ for (d = 0; d < 9; d++)
+ {
+
+ /* Extract adjacent (legal) location */
+ int yy = p_ptr->py + ddy_ddd[d];
+ int xx = p_ptr->px + ddx_ddd[d];
+
+ /* No (visible) chest is there */
+ if ((o_idx = chest_check(yy, xx)) == 0) continue;
+
+ /* Grab the object */
+ o_ptr = &o_list[o_idx];
+
+ /* Already open */
+ if (o_ptr->pval == 0) continue;
+
+ /* No (known) traps here */
+ if (trapped && (!object_known_p(o_ptr) || !o_ptr->pval)) continue;
+
+ /* OK */
+ ++count;
+
+ /* Remember the location. Only useful if only one match */
+ *y = yy;
+ *x = xx;
+ }
+
+ /* All done */
+ return (count);
+}
+
+
+/*
+ * Convert an adjacent location to a direction.
+ */
+static int coords_to_dir(int y, int x)
+{
+ int d[3][3] =
+ {
+ {7, 4, 1},
+ {8, 5, 2},
+ {9, 6, 3} };
+
+ int dy, dx;
+
+
+ dy = y - p_ptr->py;
+ dx = x - p_ptr->px;
+
+ /* Paranoia */
+ if (ABS(dx) > 1 || ABS(dy) > 1) return (0);
+
+ return d[dx + 1][dy + 1];
+}
+
+
+/*
+ * Perform the basic "open" command on doors
+ *
+ * Assume destination is a closed/locked/jammed door
+ *
+ * Assume there is no monster blocking the destination
+ *
+ * Returns TRUE if repeated commands may continue
+ */
+static bool_ do_cmd_open_aux(int y, int x, int dir)
+{
+ int i, j;
+
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+
+ if ((p_ptr->body_monster != 0) && !(r_ptr->flags2 & RF2_OPEN_DOOR))
+ {
+ msg_print("You cannot open doors.");
+
+ return (FALSE);
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Get requested grid */
+ c_ptr = &cave[y][x];
+
+ /* Jammed door */
+ if (c_ptr->feat >= FEAT_DOOR_HEAD + 0x08)
+ {
+ /* Stuck */
+ msg_print("The door appears to be stuck.");
+ }
+
+ /* Locked door */
+ else if (c_ptr->feat >= FEAT_DOOR_HEAD + 0x01)
+ {
+ /* Disarm factor */
+ i = p_ptr->skill_dis;
+
+ /* Penalize some conditions */
+ if (p_ptr->blind || no_lite()) i = i / 10;
+ if (p_ptr->confused || p_ptr->image) i = i / 10;
+
+ /* Extract the lock power */
+ j = c_ptr->feat - FEAT_DOOR_HEAD;
+
+ /* Extract the difficulty XXX XXX XXX */
+ j = i - (j * 4);
+
+ /* Always have a small chance of success */
+ if (j < 2) j = 2;
+
+ /* Success */
+ if (rand_int(100) < j)
+ {
+ /* Message */
+ msg_print("You have picked the lock.");
+
+ /* Set off trap */
+ if (c_ptr->t_idx != 0) player_activate_door_trap(y, x);
+
+ /* Open the door */
+ cave_set_feat(y, x, FEAT_OPEN);
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Sound */
+ sound(SOUND_OPENDOOR);
+
+ /* Experience */
+ gain_exp(1);
+ }
+
+ /* Failure */
+ else
+ {
+ /* Failure */
+ if (flush_failure) flush();
+
+ /* Message */
+ msg_print("You failed to pick the lock.");
+
+ /* We may keep trying */
+ more = TRUE;
+ }
+ }
+
+ /* Closed door */
+ else
+ {
+ /* Set off trap */
+ if (c_ptr->t_idx != 0) player_activate_door_trap(y, x);
+
+ /* Open the door */
+ cave_set_feat(y, x, FEAT_OPEN);
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Sound */
+ sound(SOUND_OPENDOOR);
+ }
+
+ /* Result */
+ return (more);
+}
+
+
+
+/*
+ * Open a closed/locked/jammed door or a closed/locked chest.
+ *
+ * Unlocking a locked door/chest is worth one experience point.
+ */
+void do_cmd_open(void)
+{
+ int y, x, dir;
+
+ s16b o_idx;
+
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+
+ if ((p_ptr->body_monster != 0) && !(r_ptr->flags2 & RF2_OPEN_DOOR))
+ {
+ msg_print("You cannot open doors.");
+
+ return;
+ }
+
+ /* Option: Pick a direction */
+ if (easy_open)
+ {
+ int num_doors, num_chests;
+
+ /* Count closed doors (locked or jammed) */
+ num_doors = count_feats(&y, &x, is_closed, FALSE);
+
+ /* Count chests (locked) */
+ num_chests = count_chests(&y, &x, FALSE);
+
+ /* There is nothing the player can open */
+ if ((num_doors + num_chests) == 0)
+ {
+ /* Message */
+ msg_print("You see nothing there to open.");
+
+ /* Done */
+ return;
+ }
+
+ /* Set direction if there is only one target */
+ else if ((num_doors + num_chests) == 1)
+ {
+ command_dir = coords_to_dir(y, x);
+ }
+ }
+
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+ /* Get a "repeated" direction */
+ if (get_rep_dir(&dir))
+ {
+ /* Get requested location */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ /* Get requested grid */
+ c_ptr = &cave[y][x];
+
+ /* Check for chest */
+ o_idx = chest_check(y, x);
+
+ /* Nothing useful */
+ if (!((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL)) && !o_idx)
+ {
+ /* Message */
+ msg_print("You see nothing there to open.");
+ }
+
+ /* Monster in the way */
+ else if (c_ptr->m_idx)
+ {
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Message */
+ msg_print("There is a monster in the way!");
+
+ /* Attack */
+ py_attack(y, x, -1);
+ }
+
+ /* Handle chests */
+ else if (o_idx)
+ {
+ /* Open the chest */
+ more = do_cmd_open_chest(y, x, o_idx);
+ }
+
+ /* Handle doors */
+ else
+ {
+ /* Open the door */
+ more = do_cmd_open_aux(y, x, dir);
+ }
+ }
+
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_OPEN, "(d)", is_quest(dun_level));
+
+ /* Cancel repeat unless we may continue */
+ if (!more) disturb(0, 0);
+}
+
+
+
+/*
+ * Perform the basic "close" command
+ *
+ * Assume destination is an open/broken door
+ *
+ * Assume there is no monster blocking the destination
+ *
+ * Returns TRUE if repeated commands may continue
+ */
+static bool_ do_cmd_close_aux(int y, int x, int dir)
+{
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+
+ if ((p_ptr->body_monster != 0) && !(r_ptr->flags2 & RF2_OPEN_DOOR))
+ {
+ msg_print("You cannot close doors.");
+
+ return (FALSE);
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Get grid and contents */
+ c_ptr = &cave[y][x];
+
+ /* Set off trap */
+ if (c_ptr->t_idx != 0) player_activate_door_trap(y, x);
+
+ /* Broken door */
+ if (c_ptr->feat == FEAT_BROKEN)
+ {
+ /* Message */
+ msg_print("The door appears to be broken.");
+ }
+
+ /* Open door */
+ else
+ {
+ /* Close the door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Sound */
+ sound(SOUND_SHUTDOOR);
+ }
+
+ /* Result */
+ return (more);
+}
+
+
+/*
+ * Close an open door.
+ */
+void do_cmd_close(void)
+{
+ int y, x, dir;
+
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+
+ /* Option: Pick a direction */
+ if (easy_open)
+ {
+ int num_doors;
+
+ /* Count open doors */
+ num_doors = count_feats(&y, &x, is_open, FALSE);
+
+ /* There are no doors the player can close */
+ if (num_doors == 0)
+ {
+ /* Message */
+ msg_print("You see nothing there to close.");
+
+ /* Done */
+ return;
+ }
+
+ /* Exactly one closeable door */
+ else if (num_doors == 1)
+ {
+ command_dir = coords_to_dir(y, x);
+ }
+ }
+
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+ /* Get a "repeated" direction */
+ if (get_rep_dir(&dir))
+ {
+ /* Get requested location */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ /* Get grid and contents */
+ c_ptr = &cave[y][x];
+
+ /* Require open/broken door */
+ if ((c_ptr->feat != FEAT_OPEN) && (c_ptr->feat != FEAT_BROKEN))
+ {
+ /* Message */
+ msg_print("You see nothing there to close.");
+ }
+
+ /* Monster in the way */
+ else if (c_ptr->m_idx)
+ {
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Message */
+ msg_print("There is a monster in the way!");
+
+ /* Attack */
+ py_attack(y, x, -1);
+ }
+
+ /* Close the door */
+ else
+ {
+ /* Close the door */
+ more = do_cmd_close_aux(y, x, dir);
+ }
+ }
+
+ /* Cancel repeat unless we may continue */
+ if (!more) disturb(0, 0);
+}
+
+
+/*
+ * Determine if a given grid may be "tunneled"
+ */
+static bool_ do_cmd_tunnel_test(int y, int x)
+{
+ /* Must have knowledge(execpt on "forget" levels) */
+ if (!(cave[y][x].info & (CAVE_MARK)))
+ {
+ /* Message */
+ msg_print("You see nothing there.");
+
+ /* Nope */
+ return (FALSE);
+ }
+
+ /* Must be a wall/door/etc */
+ if (cave_floor_bold(y, x))
+ {
+ /* Message */
+ msg_print("You see nothing there to tunnel.");
+
+ /* Nope */
+ return (FALSE);
+ }
+
+ /* Must be tunnelable */
+ if (!(f_info[cave[y][x].feat].flags1 & FF1_TUNNELABLE))
+ {
+ /* Message */
+ msg_print(f_text + f_info[cave[y][x].feat].tunnel);
+
+ /* Nope */
+ return (FALSE);
+ }
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+
+/*
+ * Tunnel through wall. Assumes valid location.
+ *
+ * Note that it is impossible to "extend" rooms past their
+ * outer walls (which are actually part of the room).
+ *
+ * This will, however, produce grids which are NOT illuminated
+ * (or darkened) along with the rest of the room.
+ */
+static bool_ twall(int y, int x, byte feat)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+
+ /* Paranoia -- Require a wall or door or some such */
+ if (cave_floor_bold(y, x)) return (FALSE);
+
+ /* Forget the wall */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Remove the feature */
+ cave_set_feat(y, x, feat);
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Result */
+ return (TRUE);
+}
+
+
+
+/*
+ * Perform the basic "tunnel" command
+ *
+ * Assumes that the destination is a wall, a vein, a secret
+ * door, or rubble.
+ *
+ * Assumes that no monster is blocking the destination
+ *
+ * Returns TRUE if repeated commands may continue
+ */
+bool_ do_cmd_tunnel_aux(int y, int x, int dir)
+{
+ int skill_req = 0, skill_req_1pct = 0;
+ cave_type *c_ptr = &cave[y][x];
+
+ feature_type *f_ptr = &f_info[c_ptr->feat];
+
+ bool_ more = FALSE;
+
+
+ /* Must be have something to dig with (except for sandwalls) */
+ if ((c_ptr->feat < FEAT_SANDWALL) || (c_ptr->feat > FEAT_SANDWALL_K))
+ {
+ if (!p_ptr->inventory[INVEN_TOOL].k_idx ||
+ (p_ptr->inventory[INVEN_TOOL].tval != TV_DIGGING))
+ {
+ msg_print("You need to have a shovel or pick in your tool slot.");
+
+ return (FALSE);
+ }
+ }
+
+ /* Verify legality */
+ if (!do_cmd_tunnel_test(y, x)) return (FALSE);
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Get grid */
+ c_ptr = &cave[y][x];
+
+ /* Sound */
+ sound(SOUND_DIG);
+
+ /* Titanium */
+ if (f_ptr->flags1 & FF1_PERMANENT)
+ {
+ msg_print(f_text + f_ptr->tunnel);
+ }
+
+ else if ((c_ptr->feat == FEAT_TREES) || (c_ptr->feat == FEAT_DEAD_TREE))
+ {
+ /* Chop Down */
+ skill_req = 10;
+ skill_req_1pct = 14;
+ if ((p_ptr->skill_dig > 10 + rand_int(400)) && twall(y, x, FEAT_GRASS))
+ {
+ msg_print("You have cleared away the trees.");
+ }
+
+ /* Keep trying */
+ else
+ {
+ /* We may continue chopping */
+ msg_print(f_text + f_ptr->tunnel);
+ more = TRUE;
+
+ /* Occasional Search XXX XXX */
+ if (rand_int(100) < 25) search();
+ }
+ }
+
+
+ /* Granite */
+ else if ((c_ptr->feat >= FEAT_WALL_EXTRA) &&
+ (c_ptr->feat <= FEAT_WALL_SOLID))
+ {
+ /* Tunnel */
+ skill_req = 40;
+ skill_req_1pct = 56;
+ if ((p_ptr->skill_dig > 40 + rand_int(1600)) && twall(y, x, FEAT_FLOOR))
+ {
+ msg_print("You have finished the tunnel.");
+ }
+
+ /* Keep trying */
+ else
+ {
+ /* We may continue tunelling */
+ msg_print(f_text + f_ptr->tunnel);
+ more = TRUE;
+ }
+ }
+
+
+ /* Quartz / Magma / Sandwall */
+ else if (((c_ptr->feat >= FEAT_MAGMA) &&
+ (c_ptr->feat <= FEAT_QUARTZ_K)) ||
+ ((c_ptr->feat >= FEAT_SANDWALL) &&
+ (c_ptr->feat <= FEAT_SANDWALL_K)))
+ {
+ bool_ okay = FALSE;
+ bool_ gold = FALSE;
+ bool_ hard = FALSE;
+ bool_ soft = FALSE;
+
+ /* Found gold */
+ if ((c_ptr->feat >= FEAT_MAGMA_H) &&
+ (c_ptr->feat <= FEAT_QUARTZ_K)) gold = TRUE;
+
+ if ((c_ptr->feat == FEAT_SANDWALL_H) ||
+ (c_ptr->feat == FEAT_SANDWALL_K))
+ {
+ gold = TRUE;
+ soft = TRUE;
+ }
+ else
+ /* Extract "quartz" flag XXX XXX XXX */
+ if ((c_ptr->feat - FEAT_MAGMA) & 0x01) hard = TRUE;
+
+ /* Quartz */
+ if (hard)
+ {
+ skill_req = 20;
+ skill_req_1pct = 28;
+ okay = (p_ptr->skill_dig > 20 + rand_int(800));
+ }
+
+ /* Sandwall */
+ else if (soft)
+ {
+ skill_req = 5;
+ skill_req_1pct = 8;
+ okay = (p_ptr->skill_dig > 5 + rand_int(250));
+ }
+
+ /* Magma */
+ else
+ {
+ skill_req = 10;
+ skill_req_1pct = 14;
+ okay = (p_ptr->skill_dig > 10 + rand_int(400));
+ }
+
+ /* Success */
+ if (okay && twall(y, x, FEAT_FLOOR))
+ {
+ /* Found treasure */
+ if (gold)
+ {
+ /* Place some gold */
+ place_gold(y, x);
+
+ /* Message */
+ msg_print("You have found something!");
+ }
+
+ /* Found nothing */
+ else
+ {
+ /* Message */
+ msg_print("You have finished the tunnel.");
+ }
+ }
+
+ /* Failure */
+ else
+ {
+ /* Message, continue digging */
+ msg_print(f_text + f_ptr->tunnel);
+ more = TRUE;
+ }
+ }
+
+ /* Rubble */
+ else if (c_ptr->feat == FEAT_RUBBLE)
+ {
+ /* Remove the rubble */
+ skill_req = 0;
+ skill_req_1pct = 2;
+ if ((p_ptr->skill_dig > rand_int(200)) &&
+ twall(y, x, d_info[dungeon_type].floor1))
+ {
+ /* Message */
+ msg_print("You have removed the rubble.");
+
+ /* Hack -- place an object */
+ if (rand_int(100) < 10)
+ {
+ /* Create a simple object */
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_RUBBLE);
+
+ /* Observe new object */
+ if (player_can_see_bold(y, x))
+ {
+ msg_print("You have found something!");
+ }
+ }
+ }
+
+ else
+ {
+ /* Message, keep digging */
+ msg_print(f_text + f_ptr->tunnel);
+ more = TRUE;
+ }
+ }
+
+ /* Secret doors */
+ else if (c_ptr->feat >= FEAT_SECRET)
+ {
+ /* Tunnel */
+ skill_req = 30;
+ skill_req_1pct = 42;
+ if ((p_ptr->skill_dig > 30 + rand_int(1200)) && twall(y, x, FEAT_FLOOR))
+ {
+ msg_print("You have finished the tunnel.");
+ c_ptr->mimic = 0;
+ lite_spot(y, x);
+
+ /* Set off trap */
+ if (c_ptr->t_idx != 0) player_activate_door_trap(y, x);
+ }
+
+ /* Keep trying */
+ else
+ {
+ int feat;
+
+ if (c_ptr->mimic) feat = c_ptr->mimic;
+ else
+ feat = c_ptr->feat;
+
+ /* We may continue tunelling */
+ msg_print(f_text + f_info[feat].tunnel);
+ more = TRUE;
+
+ /* Occasional Search XXX XXX */
+ if (rand_int(100) < 25) search();
+ }
+ }
+
+ /* Doors */
+ else
+ {
+ /* Tunnel */
+ skill_req = 30;
+ skill_req_1pct = 42;
+ if ((p_ptr->skill_dig > 30 + rand_int(1200)) && twall(y, x, FEAT_FLOOR))
+ {
+ msg_print("You have finished the tunnel.");
+ }
+
+ /* Keep trying */
+ else
+ {
+ /* We may continue tunelling */
+ msg_print(f_text + f_ptr->tunnel);
+ more = TRUE;
+ }
+ }
+
+ if (more && magik(2))
+ {
+ if (p_ptr->skill_dig < skill_req)
+ {
+ msg_print("You fail to make even the slightest of progress.");
+ more = FALSE;
+ }
+ else if (p_ptr->skill_dig < skill_req_1pct)
+ {
+ msg_print("This will take some time.");
+ }
+ }
+
+ /* Notice new floor grids */
+ if (!cave_floor_bold(y, x))
+ {
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS | PU_MON_LITE);
+ }
+
+ /* Result */
+ return (more);
+}
+
+
+/*
+ * Tunnels through "walls" (including rubble and closed doors)
+ *
+ * Note that you must tunnel in order to hit invisible monsters
+ * in walls, though moving into walls still takes a turn anyway.
+ *
+ * Digging is very difficult without a "digger" weapon, but can be
+ * accomplished by strong players using heavy weapons.
+ */
+void do_cmd_tunnel(void)
+{
+ int y, x, dir;
+
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+
+ if (p_ptr->wild_mode) return;
+
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+ /* Get a direction to tunnel, or Abort */
+ if (get_rep_dir(&dir))
+ {
+ /* Get location */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ /* Get grid */
+ c_ptr = &cave[y][x];
+
+ /* No tunnelling through doors */
+ if (((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL)) || (c_ptr->feat == FEAT_SHOP))
+ {
+ /* Message */
+ msg_print("You cannot tunnel through doors.");
+ }
+
+ /* No tunnelling through air */
+ else if (cave_floor_grid(c_ptr))
+ {
+ /* Message */
+ msg_print("You cannot tunnel through air.");
+ }
+
+ /* A monster is in the way */
+ else if (c_ptr->m_idx)
+ {
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Message */
+ msg_print("There is a monster in the way!");
+
+ /* Attack */
+ py_attack(y, x, -1);
+ }
+
+ /* Try digging */
+ else
+ {
+ /* Tunnel through walls */
+ more = do_cmd_tunnel_aux(y, x, dir);
+ }
+ }
+
+ /* Cancel repetition unless we can continue */
+ if (!more) disturb(0, 0);
+}
+
+
+/*
+ * easy_open_door --
+ *
+ * If there is a jammed/closed/locked door at the given location,
+ * then attempt to unlock/open it. Return TRUE if an attempt was
+ * made (successful or not), otherwise return FALSE.
+ *
+ * The code here should be nearly identical to that in
+ * do_cmd_open_test() and do_cmd_open_aux().
+ */
+
+bool_ easy_open_door(int y, int x)
+{
+ int i, j;
+
+ cave_type *c_ptr = &cave[y][x];
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+
+ if ((p_ptr->body_monster != 0) && !(r_ptr->flags2 & RF2_OPEN_DOOR))
+ {
+ msg_print("You cannot open doors.");
+
+ return (FALSE);
+ }
+
+ /* Must be a closed door */
+ if (!((c_ptr->feat >= FEAT_DOOR_HEAD) && (c_ptr->feat <= FEAT_DOOR_TAIL)))
+ {
+ /* Nope */
+ return (FALSE);
+ }
+
+ /* Jammed door */
+ if (c_ptr->feat >= FEAT_DOOR_HEAD + 0x08)
+ {
+ /* Stuck */
+ msg_print("The door appears to be stuck.");
+ }
+
+ /* Locked door */
+ else if (c_ptr->feat >= FEAT_DOOR_HEAD + 0x01)
+ {
+ /* Disarm factor */
+ i = p_ptr->skill_dis;
+
+ /* Penalize some conditions */
+ if (p_ptr->blind || no_lite()) i = i / 10;
+ if (p_ptr->confused || p_ptr->image) i = i / 10;
+
+ /* Extract the lock power */
+ j = c_ptr->feat - FEAT_DOOR_HEAD;
+
+ /* Extract the difficulty XXX XXX XXX */
+ j = i - (j * 4);
+
+ /* Always have a small chance of success */
+ if (j < 2) j = 2;
+
+ /* Success */
+ if (rand_int(100) < j)
+ {
+ /* Message */
+ msg_print("You have picked the lock.");
+
+ /* Set off trap */
+ if (c_ptr->t_idx != 0) player_activate_door_trap(y, x);
+
+ /* Open the door */
+ cave_set_feat(y, x, FEAT_OPEN);
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Sound */
+ sound(SOUND_OPENDOOR);
+
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_OPEN, "(d)", is_quest(dun_level));
+
+ /* Experience */
+ gain_exp(1);
+ }
+
+ /* Failure */
+ else
+ {
+ /* Failure */
+ if (flush_failure) flush();
+
+ /* Message */
+ msg_print("You failed to pick the lock.");
+ }
+ }
+
+ /* Closed door */
+ else
+ {
+ /* Set off trap */
+ if (c_ptr->t_idx != 0) player_activate_door_trap(y, x);
+
+ /* Open the door */
+ cave_set_feat(y, x, FEAT_OPEN);
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Sound */
+ sound(SOUND_OPENDOOR);
+ }
+
+ /* Result */
+ return (TRUE);
+}
+
+
+/*
+ * Perform the basic "disarm" command
+ *
+ * Assume destination is a visible trap
+ *
+ * Assume there is no monster blocking the destination
+ *
+ * Returns TRUE if repeated commands may continue
+ */
+static bool_ do_cmd_disarm_chest(int y, int x, s16b o_idx)
+{
+ int i, j;
+
+ bool_ more = FALSE;
+
+ object_type *o_ptr = &o_list[o_idx];
+
+ trap_type *t_ptr = &t_info[o_ptr->pval];
+
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Get the "disarm" factor */
+ i = p_ptr->skill_dis;
+
+ /* Penalize some conditions */
+ if (p_ptr->blind || no_lite()) i = i / 10;
+ if (p_ptr->confused || p_ptr->image) i = i / 10;
+
+ /* Extract the difficulty */
+ j = i - t_ptr->difficulty * 3;
+
+ /* Always have a small chance of success */
+ if (j < 2) j = 2;
+
+ /* Must find the trap first. */
+ if (!object_known_p(o_ptr))
+ {
+ msg_print("I don't see any traps.");
+ }
+
+ /* Already disarmed/unlocked */
+ else if (o_ptr->pval <= 0)
+ {
+ msg_print("The chest is not trapped.");
+ }
+
+ /* Success (get a lot of experience) */
+ else if (rand_int(100) < j)
+ {
+ msg_print("You have disarmed the chest.");
+ gain_exp(t_ptr->difficulty * 3);
+ o_ptr->pval = (0 - o_ptr->pval);
+ }
+
+ /* Failure -- Keep trying */
+ else if ((i > 5) && (randint(i) > 5))
+ {
+ /* We may keep trying */
+ more = TRUE;
+ if (flush_failure) flush();
+ msg_print("You failed to disarm the chest.");
+ }
+
+ /* Failure -- Set off the trap */
+ else
+ {
+ msg_print("You set off a trap!");
+ sound(SOUND_FAIL);
+ chest_trap(y, x, o_idx);
+ }
+
+ /* Result */
+ return (more);
+}
+
+
+/*
+ * Perform the basic "disarm" command
+ *
+ * Assume destination is a visible trap
+ *
+ * Assume there is no monster blocking the destination
+ *
+ * Returns TRUE if repeated commands may continue
+ */
+bool_ do_cmd_disarm_aux(int y, int x, int dir, int do_pickup)
+{
+ int i, j, power;
+
+ cave_type *c_ptr;
+
+ cptr name;
+
+ bool_ more = FALSE;
+
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Get grid and contents */
+ c_ptr = &cave[y][x];
+
+ /* Access trap name */
+ if (t_info[c_ptr->t_idx].ident)
+ name = (t_name + t_info[c_ptr->t_idx].name);
+ else
+ name = "unknown trap";
+
+ /* Get the "disarm" factor */
+ i = p_ptr->skill_dis;
+
+ /* Penalize some conditions */
+ if (p_ptr->blind || no_lite()) i = i / 10;
+ if (p_ptr->confused || p_ptr->image) i = i / 10;
+
+ /* XXX XXX XXX Variable power? */
+
+ /* Extract trap "power" */
+ power = t_info[c_ptr->t_idx].difficulty;
+
+ /* Extract the difficulty */
+ j = i - power;
+
+ /* Always have a small chance of success */
+ if (j < 2) j = 2;
+
+ /* Success */
+ if (rand_int(100) < j)
+ {
+ /* Message */
+ msg_format("You have disarmed the %s.", name);
+
+ /* Reward */
+ gain_exp(power);
+
+ /* Forget the trap */
+ c_ptr->info &= ~(CAVE_MARK | CAVE_TRDT);
+
+ /* Remove the trap */
+ c_ptr->t_idx = 0;
+
+ /* Move the player onto the trap */
+ if (!(f_info[c_ptr->feat].flags1 & FF1_DOOR))
+ move_player_aux(dir, do_pickup, 0, TRUE);
+
+ /* Remove trap attr from grid */
+ note_spot(y, x);
+ lite_spot(y, x);
+ }
+
+ /* Failure -- Keep trying */
+ else if ((i > 5) && (randint(i) > 5))
+ {
+ /* Failure */
+ if (flush_failure) flush();
+
+ /* Message */
+ msg_format("You failed to disarm the %s.", name);
+
+ /* We may keep trying */
+ more = TRUE;
+ }
+
+ /* Failure -- Set off the trap */
+ else
+ {
+ /* Message */
+ msg_format("You set off the %s!", name);
+
+ /* Move the player onto the trap */
+ if (!(f_info[c_ptr->feat].flags1 & FF1_DOOR))
+ move_player_aux(dir, do_pickup, 0, FALSE);
+ }
+
+ /* Result */
+ return (more);
+}
+
+
+/*
+ * Disamrs the monster traps(no failure)
+ */
+void do_cmd_disarm_mon_trap(int y, int x)
+{
+ msg_print("You disarm the monster trap.");
+
+ place_floor_convert_glass(y, x);
+ cave[p_ptr->py][p_ptr->px].special = cave[p_ptr->py][p_ptr->px].special2 = 0;
+}
+
+
+/*
+ * Disarms a trap, or chest
+ */
+void do_cmd_disarm(void)
+{
+ int y, x, dir;
+
+ s16b o_idx;
+
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+
+ /* Option: Pick a direction */
+ if (easy_disarm)
+ {
+ int num_traps, num_chests;
+
+ /* Count visible traps */
+ num_traps = count_feats(&y, &x, is_trap, TRUE);
+
+ /* Count chests (trapped) */
+ num_chests = count_chests(&y, &x, TRUE);
+
+ /* See if only one target */
+ if (num_traps || num_chests)
+ {
+ if (num_traps + num_chests <= 1)
+ command_dir = coords_to_dir(y, x);
+ }
+ }
+
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+ /* Get a direction (or abort) */
+ if (get_rep_dir(&dir))
+ {
+ /* Get location */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ /* Get grid and contents */
+ c_ptr = &cave[y][x];
+
+ /* Check for chests */
+ o_idx = chest_check(y, x);
+
+ /* Disarm a trap */
+ if (((c_ptr->t_idx == 0) || (!(c_ptr->info & CAVE_TRDT))) &&
+ !o_idx && (c_ptr->feat != FEAT_MON_TRAP))
+ {
+ /* Message */
+ msg_print("You see nothing there to disarm.");
+ }
+
+ /* Monster in the way */
+ else if (c_ptr->m_idx)
+ {
+ /* Message */
+ msg_print("There is a monster in the way!");
+
+ /* Attack */
+ py_attack(y, x, -1);
+ }
+
+ /* Disarm chest */
+ else if (o_idx)
+ {
+ /* Disarm the chest */
+ more = do_cmd_disarm_chest(y, x, o_idx);
+ }
+
+ /* Disarm trap */
+ else
+ {
+ /* Disarm the trap */
+ if (c_ptr->feat == FEAT_MON_TRAP)
+ {
+ do_cmd_disarm_mon_trap(y, x);
+ more = FALSE;
+ }
+ else
+ more = do_cmd_disarm_aux(y, x, dir, always_pickup);
+ }
+ }
+
+ /* Cancel repeat unless told not to */
+ if (!more) disturb(0, 0);
+}
+
+
+/*
+ * Perform the basic "bash" command
+ *
+ * Assume destination is a closed/locked/jammed door
+ *
+ * Assume there is no monster blocking the destination
+ *
+ * Returns TRUE if repeated commands may continue
+ */
+static bool_ do_cmd_bash_aux(int y, int x, int dir)
+{
+ int bash, temp;
+
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+
+ if ((p_ptr->body_monster != 0) && !(r_ptr->flags2 & RF2_BASH_DOOR))
+ {
+ msg_print("You cannot do that.");
+
+ return (FALSE);
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Get grid */
+ c_ptr = &cave[y][x];
+
+ /* Message */
+ msg_print("You smash into the door!");
+
+ /* Hack -- Bash power based on strength */
+ /* (Ranges from 3 to 20 to 100 to 200) */
+ bash = adj_str_blow[p_ptr->stat_ind[A_STR]];
+
+ /* Extract door power */
+ temp = ((c_ptr->feat - FEAT_DOOR_HEAD) & 0x07);
+
+ /* Compare bash power to door power XXX XXX XXX */
+ temp = (bash - (temp * 10));
+
+ /* Hack -- always have a chance */
+ if (temp < 1) temp = 1;
+
+ /* Hack -- attempt to bash down the door */
+ if (rand_int(100) < temp)
+ {
+ /* Message */
+ msg_print("The door crashes open!");
+
+ /* Break down the door */
+ if (rand_int(100) < 50)
+ {
+ /* Set off trap */
+ if (c_ptr->t_idx != 0) player_activate_door_trap(y, x);
+
+ cave_set_feat(y, x, FEAT_BROKEN);
+ }
+
+ /* Open the door */
+ else
+ {
+ /* Set off trap */
+ if (c_ptr->t_idx != 0) player_activate_door_trap(y, x);
+
+ cave_set_feat(y, x, FEAT_OPEN);
+ }
+
+ /* Sound */
+ sound(SOUND_OPENDOOR);
+
+ /* Hack -- Fall through the door. Can't disarm while falling. */
+ move_player_aux(dir, always_pickup, 0, FALSE);
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_MON_LITE);
+ p_ptr->update |= (PU_DISTANCE);
+ }
+
+ /* Saving throw against stun */
+ else if (rand_int(100) < adj_dex_safe[p_ptr->stat_ind[A_DEX]] + p_ptr->lev)
+ {
+ /* Message */
+ msg_print("The door holds firm.");
+
+ /* Allow repeated bashing */
+ more = TRUE;
+ }
+
+ /* High dexterity yields coolness */
+ else
+ {
+ /* Message */
+ msg_print("You are off-balance.");
+
+ /* Hack -- Lose balance ala paralysis */
+ (void)set_paralyzed(p_ptr->paralyzed + 2 + rand_int(2));
+ }
+
+ /* Result */
+ return (more);
+}
+
+
+/*
+ * Bash open a door, success based on character strength
+ *
+ * For a closed door, pval is positive if locked; negative if stuck.
+ *
+ * For an open door, pval is positive for a broken door.
+ *
+ * A closed door can be opened - harder if locked. Any door might be
+ * bashed open (and thereby broken). Bashing a door is (potentially)
+ * faster! You move into the door way. To open a stuck door, it must
+ * be bashed. A closed door can be jammed (see do_cmd_spike()).
+ *
+ * Creatures can also open or bash doors, see elsewhere.
+ */
+void do_cmd_bash(void)
+{
+ int y, x, dir;
+
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+
+ if ((p_ptr->body_monster != 0) && !(r_ptr->flags2 & RF2_BASH_DOOR))
+ {
+ msg_print("You cannot do that.");
+
+ return;
+ }
+
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+ /* Get a "repeated" direction */
+ if (get_rep_dir(&dir))
+ {
+ /* Bash location */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ /* Get grid */
+ c_ptr = &cave[y][x];
+
+ /* Nothing useful */
+ if ((c_ptr->feat < FEAT_DOOR_HEAD ||
+ c_ptr->feat > FEAT_DOOR_TAIL) &&
+ (c_ptr->feat < FEAT_ALTAR_HEAD ||
+ c_ptr->feat > FEAT_ALTAR_TAIL) && (c_ptr->feat != FEAT_FOUNTAIN))
+ {
+ /* Message */
+ msg_print("You see nothing there to bash.");
+ }
+
+ /* Monster in the way */
+ else if (c_ptr->m_idx)
+ {
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Message */
+ msg_print("There is a monster in the way!");
+
+ /* Attack */
+ py_attack(y, x, -1);
+ }
+
+ else if (c_ptr->feat >= FEAT_ALTAR_HEAD &&
+ c_ptr->feat <= FEAT_ALTAR_TAIL)
+ {
+ more = do_cmd_bash_altar(y, x);
+ }
+ /* Bash a closed door */
+ else if (c_ptr->feat == FEAT_FOUNTAIN)
+ {
+ more = do_cmd_bash_fountain(y, x);
+ }
+ else
+ {
+ /* Bash the door */
+ more = do_cmd_bash_aux(y, x, dir);
+ }
+ }
+
+ /* Unless valid action taken, cancel bash */
+ if (!more) disturb(0, 0);
+}
+
+
+
+/*
+ * Manipulate an adjacent grid in some way
+ *
+ * Attack monsters, tunnel through walls, disarm traps, open doors.
+ *
+ * Consider confusion XXX XXX XXX
+ *
+ * This command must always take a turn, to prevent free detection
+ * of invisible monsters.
+ */
+void do_cmd_alter(void)
+{
+ int y, x, dir;
+
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+ /* Get a direction */
+ if (get_rep_dir(&dir))
+ {
+ /* Get location */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ /* Get grid */
+ c_ptr = &cave[y][x];
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Attack monsters */
+ if (c_ptr->m_idx)
+ {
+ /* Attack */
+ py_attack(y, x, -1);
+ }
+
+ /* Open closed doors */
+ else if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL))
+ {
+ /* Tunnel */
+ more = do_cmd_open_aux(y, x, dir);
+ }
+
+ /* Tunnel through walls */
+ else if (f_info[c_ptr->feat].flags1 & FF1_TUNNELABLE)
+ {
+ /* Tunnel */
+ more = do_cmd_tunnel_aux(y, x, dir);
+ }
+
+ /* Disarm traps */
+ else if (c_ptr->t_idx != 0)
+ {
+ /* Tunnel */
+ more = do_cmd_disarm_aux(y, x, dir, always_pickup);
+ }
+
+ /* Oops */
+ else
+ {
+ /* Oops */
+ msg_print("You attack the empty air.");
+ }
+ }
+
+ /* Cancel repetition unless we can continue */
+ if (!more) disturb(0, 0);
+}
+
+
+/*
+ * Find the index of some "spikes", if possible.
+ *
+ * XXX XXX XXX Let user choose a pile of spikes, perhaps?
+ */
+static bool_ get_spike(int *ip)
+{
+ int i;
+
+
+ /* Check every item in the pack */
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Check the "tval" code */
+ if (o_ptr->tval == TV_SPIKE)
+ {
+ /* Save the spike index */
+ (*ip) = i;
+
+ /* Success */
+ return (TRUE);
+ }
+ }
+
+ /* Oops */
+ return (FALSE);
+}
+
+
+
+/*
+ * Jam a closed door with a spike
+ *
+ * This command may NOT be repeated
+ */
+void do_cmd_spike(void)
+{
+ int y, x, dir, item;
+
+ cave_type *c_ptr;
+
+
+ /* Get a "repeated" direction */
+ if (get_rep_dir(&dir))
+ {
+ /* Get location */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ /* Get grid and contents */
+ c_ptr = &cave[y][x];
+
+ /* Require closed door */
+ if (!((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL)))
+ {
+ /* Message */
+ msg_print("You see nothing there to spike.");
+ }
+
+ /* Get a spike */
+ else if (!get_spike(&item))
+ {
+ /* Message */
+ msg_print("You have no spikes!");
+ }
+
+ /* Is a monster in the way? */
+ else if (c_ptr->m_idx)
+ {
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Message */
+ msg_print("There is a monster in the way!");
+
+ /* Attack */
+ py_attack(y, x, -1);
+ }
+
+ /* Go for it */
+ else
+ {
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Successful jamming */
+ msg_print("You jam the door with a spike.");
+
+ /* Convert "locked" to "stuck" XXX XXX XXX */
+ if (c_ptr->feat < FEAT_DOOR_HEAD + 0x08) c_ptr->feat += 0x08;
+
+ /* Add one spike to the door */
+ if (c_ptr->feat < FEAT_DOOR_TAIL) c_ptr->feat++;
+
+ /* Use up, and describe, a single spike, from the bottom */
+ inc_stack_size(item, -1);
+ }
+ }
+}
+
+
+static void do_cmd_walk_jump(int pickup, bool_ disarm)
+{
+ int dir;
+
+ bool_ more = FALSE;
+
+
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+ /* Get a "repeated" direction */
+ if (get_rep_dir(&dir))
+ {
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Actually move the character */
+ move_player(dir, pickup, disarm);
+
+ /* Allow more walking */
+ more = TRUE;
+ }
+
+ /* Hack -- In small scale wilderness it takes MUCH more time to move */
+ energy_use *= (p_ptr->wild_mode) ? ((MAX_HGT + MAX_WID) / 2) : 1;
+
+ /* Hack again -- Is there a special encounter ??? */
+ if (p_ptr->wild_mode &&
+ magik(wf_info[wild_map[p_ptr->py][p_ptr->px].feat].level - (p_ptr->lev * 2)))
+ {
+ /* Go into large wilderness view */
+ p_ptr->wilderness_x = p_ptr->px;
+ p_ptr->wilderness_y = p_ptr->py;
+ energy_use = 100;
+ change_wild_mode();
+
+ /* HACk -- set the encouter flag for the wilderness generation */
+ generate_encounter = TRUE;
+ p_ptr->oldpx = MAX_WID / 2;
+ p_ptr->oldpy = MAX_HGT / 2;
+
+ /* Inform the player of his horrible fate :=) */
+ msg_print("You are ambushed!");
+ }
+
+ /* Cancel repeat unless we may continue */
+ if (!more) disturb(0, 0);
+}
+
+
+/*
+ * Support code for the "Walk" and "Jump" commands
+ */
+void do_cmd_walk(int pickup, bool_ disarm)
+{
+ /* Move (usually pickup) */
+
+ if (p_ptr->immovable)
+ {
+ do_cmd_unwalk();
+ }
+ else
+ {
+ do_cmd_walk_jump(pickup, disarm);
+ }
+}
+
+
+void do_cmd_run_run()
+{
+ int dir;
+
+
+ /* Hack -- no running when confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* Get a "repeated" direction */
+ if (get_rep_dir(&dir))
+ {
+ /* Hack -- Set the run counter */
+ running = (command_arg ? command_arg : 1000);
+
+ /* First step */
+ run_step(dir);
+ }
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+
+/*
+ * Start running.
+ */
+void do_cmd_run(void)
+{
+ if (p_ptr->immovable)
+ {
+ return;
+ }
+ else
+ {
+ do_cmd_run_run();
+ }
+}
+
+
+
+/*
+ * Stay still. Search. Enter stores.
+ * Pick up treasure if "pickup" is true.
+ */
+void do_cmd_stay(int pickup)
+{
+ cave_type *c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+
+ /* Take a turn */
+ energy_use = 100;
+
+
+ /* Spontaneous Searching */
+ if ((p_ptr->skill_fos >= 50) || (0 == rand_int(50 - p_ptr->skill_fos)))
+ {
+ search();
+ }
+
+ /* Continuous Searching */
+ if (p_ptr->searching)
+ {
+ search();
+ }
+
+
+ /* Handle "objects" */
+ carry(pickup);
+
+
+ /* Hack -- enter a store if we are on one */
+ if (c_ptr->feat == FEAT_SHOP)
+ {
+ /* Disturb */
+ disturb(0, 0);
+
+ /* Hack -- enter store */
+ command_new = '_';
+ }
+}
+
+/*
+ * Resting allows a player to safely restore his hp -RAK-
+ */
+void do_cmd_rest(void)
+{
+ /* Can't rest on a Void Jumpgate -- too dangerous */
+ if (cave[p_ptr->py][p_ptr->px].feat == FEAT_BETWEEN)
+ {
+ /* 'R&\n' is one of our favourite macros, so we have to do this */
+ if (flush_failure) flush();
+
+ /* Tell the player why */
+ msg_print(format("Resting on a %s is too dangerous!",
+ f_name + f_info[cave[p_ptr->py][p_ptr->px].feat].name));
+
+ /* Done */
+ return;
+ }
+
+ /* Can't rest while undead, it would mean dying */
+ if (p_ptr->necro_extra & CLASS_UNDEAD)
+ {
+ /* 'R&\n' is one of our favourite macros, so we have to do this */
+ if (flush_failure) flush();
+
+ /* Tell the player why */
+ msg_print("Resting is impossible while undead!");
+
+ /* Done */
+ return;
+ }
+
+ /* Prompt for time if needed */
+ if (command_arg <= 0)
+ {
+ cptr p = "Rest (0-9999, '*' for HP/SP, '&' as needed): ";
+
+ char out_val[80];
+
+ /* Default */
+ strcpy(out_val, "&");
+
+ /* Ask for duration */
+ if (!get_string(p, out_val, 4)) return;
+
+ /* Rest until done */
+ if (out_val[0] == '&')
+ {
+ command_arg = ( -2);
+ }
+
+ /* Rest a lot */
+ else if (out_val[0] == '*')
+ {
+ command_arg = ( -1);
+ }
+
+ /* Rest some */
+ else
+ {
+ command_arg = atoi(out_val);
+ if (command_arg <= 0) return;
+ }
+ }
+
+
+ /* Paranoia */
+ if (command_arg > 9999) command_arg = 9999;
+
+
+ /* Take a turn XXX XXX XXX (?) */
+ energy_use = 100;
+
+ /* Save the rest code */
+ resting = command_arg;
+
+ /* Cancel searching */
+ p_ptr->searching = FALSE;
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Refresh */
+ Term_fresh();
+}
+
+
+
+
+
+
+/*
+ * Determines the odds of an object breaking when thrown at a monster
+ *
+ * Note that artifacts never break, see the "drop_near()" function.
+ */
+int breakage_chance(object_type *o_ptr)
+{
+ int reducer =
+ 1 + ((get_skill(SKILL_ARCHERY)) ? (get_skill_scale(SKILL_ARCHERY, 10)) : 0);
+
+ /* Examine the item type */
+ switch (o_ptr->tval)
+ {
+ /* Always break */
+ case TV_FLASK:
+ case TV_POTION:
+ case TV_POTION2:
+ case TV_BOTTLE:
+ case TV_FOOD:
+ {
+ return (100);
+ }
+
+ /* Often break */
+ case TV_LITE:
+ case TV_SCROLL:
+ case TV_SKELETON:
+ {
+ return (50);
+ }
+
+ case TV_ARROW:
+ {
+ return (50 / reducer);
+ }
+
+ /* Sometimes break */
+ case TV_WAND:
+ case TV_SPIKE:
+ {
+ return (25);
+ }
+
+ case TV_SHOT:
+ case TV_BOLT:
+ {
+ return (25 / reducer);
+ }
+ case TV_BOOMERANG:
+ {
+ return 1;
+ }
+ }
+
+ /* Rarely break */
+ return (10);
+}
+
+/*
+ * Return multiplier of an object
+ */
+int get_shooter_mult(object_type *o_ptr)
+{
+ /* Assume a base multiplier */
+ int tmul = 1;
+
+ /* Analyze the launcher */
+ switch (o_ptr->sval)
+ {
+ case SV_SLING:
+ {
+ /* Sling and ammo */
+ tmul = 2;
+ break;
+ }
+
+ case SV_SHORT_BOW:
+ {
+ /* Short Bow and Arrow */
+ tmul = 2;
+ break;
+ }
+
+ case SV_LONG_BOW:
+ {
+ /* Long Bow and Arrow */
+ tmul = 3;
+ break;
+ }
+
+ /* Light Crossbow and Bolt */
+ case SV_LIGHT_XBOW:
+ {
+ tmul = 3;
+ break;
+ }
+
+ /* Heavy Crossbow and Bolt */
+ case SV_HEAVY_XBOW:
+ {
+ tmul = 4;
+ break;
+ }
+ }
+ return tmul;
+}
+
+
+/*
+ * Fire an object from the pack or floor.
+ *
+ * You may only fire items that "match" your missile launcher.
+ *
+ * You must use slings + pebbles/shots, bows + arrows, xbows + bolts.
+ *
+ * See "calc_bonuses()" for more calculations and such.
+ *
+ * Note that "firing" a missile is MUCH better than "throwing" it.
+ *
+ * Note: "unseen" monsters are very hard to hit.
+ *
+ * Objects are more likely to break if they "attempt" to hit a monster.
+ *
+ * Rangers (with Bows) and Anyone (with "Extra Shots") get extra shots.
+ *
+ * The "extra shot" code works by decreasing the amount of energy
+ * required to make each shot, spreading the shots out over time.
+ *
+ * Note that when firing missiles, the launcher multiplier is applied
+ * after all the bonuses are added in, making multipliers very useful.
+ *
+ * Note that Bows of "Extra Might" get extra range and an extra bonus
+ * for the damage multiplier.
+ *
+ * Note that Bows of "Extra Shots" give an extra shot.
+ */
+void do_cmd_fire(void)
+{
+ int dir, item;
+
+ int j, y, x, ny, nx, ty, tx, by, bx;
+
+ int oldtdam, tdam, tdis, thits, tmul;
+
+ int bonus, chance;
+
+ int cur_dis, visible;
+
+ int breakage = -1, num_pierce = 0;
+
+ s32b special = 0;
+
+ object_type forge;
+
+ object_type *q_ptr;
+
+ object_type *o_ptr;
+
+ object_type *j_ptr;
+
+ bool_ hit_body = FALSE;
+
+ byte missile_attr;
+
+ char missile_char;
+
+ char o_name[80];
+
+ cptr q, s;
+
+ int msec = delay_factor * delay_factor * delay_factor;
+
+
+ /* Get the "bow" (if any) */
+ j_ptr = &p_ptr->inventory[INVEN_BOW];
+
+ /* Require a launcher */
+ if (!j_ptr->tval)
+ {
+ msg_print("You have nothing with which to fire.");
+ return;
+ }
+
+ /* XXX HACK */
+ if (j_ptr->tval == TV_INSTRUMENT)
+ {
+ msg_print("You cannot fire with an instrument.");
+ return;
+ }
+
+ /* Get the "ammo" (if any) */
+ o_ptr = &p_ptr->inventory[INVEN_AMMO];
+
+ item = INVEN_AMMO;
+
+ /* If nothing correct try to choose from the backpack */
+ if ((p_ptr->tval_ammo != o_ptr->tval) || (!o_ptr->k_idx))
+ {
+ /* Require proper missile */
+ item_tester_tval = p_ptr->tval_ammo;
+
+ /* Get an item */
+ q = "Your quiver is empty. Fire which item? ";
+ s = "You have nothing to fire.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+
+ /* Access the item */
+ o_ptr = get_object(item);
+ }
+
+
+ /* Get a direction (or cancel) */
+ if (!get_aim_dir(&dir)) return;
+
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Obtain a local object */
+ object_copy(q_ptr, o_ptr);
+
+ /* Single object */
+ q_ptr->number = 1;
+
+ /* Reduce stack and describe */
+ inc_stack_size(item, -1);
+
+ /* Break goi/manashield */
+ if (p_ptr->invuln)
+ {
+ set_invuln(0);
+ }
+ if (p_ptr->disrupt_shield)
+ {
+ set_disrupt_shield(0);
+ }
+
+
+ /* Sound */
+ sound(SOUND_SHOOT);
+
+
+ /* Describe the object */
+ object_desc(o_name, q_ptr, FALSE, 3);
+
+ /* Find the color and symbol for the object for throwing */
+ missile_attr = object_attr(q_ptr);
+ missile_char = object_char(q_ptr);
+
+
+ /* Use the proper number of shots */
+ thits = p_ptr->num_fire;
+
+ /* Use a base distance */
+ tdis = 10;
+
+ /* Base damage from thrown object plus launcher bonus */
+ tdam = damroll(q_ptr->dd, q_ptr->ds) + q_ptr->to_d + j_ptr->to_d;
+
+ /* Actually "fire" the object */
+ bonus = (p_ptr->to_h + p_ptr->to_h_ranged + q_ptr->to_h + j_ptr->to_h);
+
+ chance = (p_ptr->skill_thb + (bonus * BTH_PLUS_ADJ));
+ if (chance < 5) chance = 5;
+
+ tmul = get_shooter_mult(j_ptr);
+
+ /* Get extra "power" from "extra might" */
+ tmul += p_ptr->xtra_might;
+
+ /* Boost the damage */
+ tdam *= tmul;
+
+ /* Add in the player damage */
+ tdam += p_ptr->to_d_ranged;
+
+ /* Base range */
+ tdis = 10 + 5 * tmul;
+
+
+ /* Take a (partial) turn */
+ energy_use = (100 / thits);
+
+ /* piercing shots ? */
+ if (p_ptr->use_piercing_shots)
+ {
+ num_pierce = (get_skill(SKILL_COMBAT) / 10) - 1;
+ num_pierce = (num_pierce < 0) ? 0 : num_pierce;
+ }
+
+ /* Start at the player */
+ by = p_ptr->py;
+ bx = p_ptr->px;
+ y = p_ptr->py;
+ x = p_ptr->px;
+
+ /* Predict the "target" location */
+ tx = p_ptr->px + 99 * ddx[dir];
+ ty = p_ptr->py + 99 * ddy[dir];
+
+ /* Check for "target request" */
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+ }
+
+
+ /* Hack -- Handle stuff */
+ handle_stuff();
+
+ oldtdam = tdam;
+ while (TRUE)
+ {
+ /* Reset after a piercing shot */
+ tdam = oldtdam;
+
+ /* Travel until stopped */
+ for (cur_dis = 0; cur_dis <= tdis; )
+ {
+ /* Hack -- Stop at the target */
+ if ((y == ty) && (x == tx)) break;
+
+ /* Calculate the new location (see "project()") */
+ ny = y;
+ nx = x;
+ mmove2(&ny, &nx, by, bx, ty, tx);
+
+ /* Stopped by walls/doors */
+ if (!cave_floor_bold(ny, nx)) break;
+
+ /* Advance the distance */
+ cur_dis++;
+
+ /* Save the new location */
+ x = nx;
+ y = ny;
+
+
+ /* The player can see the (on screen) missile */
+ if (panel_contains(y, x) && player_can_see_bold(y, x))
+ {
+ /* Draw, Hilite, Fresh, Pause, Erase */
+ print_rel(missile_char, missile_attr, y, x);
+ move_cursor_relative(y, x);
+ Term_fresh();
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ lite_spot(y, x);
+ Term_fresh();
+ }
+
+ /* The player cannot see the missile */
+ else
+ {
+ /* Pause anyway, for consistancy */
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ }
+
+
+ /* Monster here, Try to hit it */
+ if (cave[y][x].m_idx)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Check the visibility */
+ visible = m_ptr->ml;
+
+ /* Note the collision */
+ hit_body = TRUE;
+
+ /* Did we hit it (penalize range) */
+ if (test_hit_fire(chance - cur_dis, m_ptr->ac, m_ptr->ml))
+ {
+ bool_ fear = FALSE;
+
+ /* Assume a default death */
+ cptr note_dies = " dies.";
+
+ /* Some monsters get "destroyed" */
+ if ((r_ptr->flags3 & (RF3_DEMON)) ||
+ (r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags2 & (RF2_STUPID)) ||
+ (strchr("Evg", r_ptr->d_char)))
+ {
+ /* Special note at death */
+ note_dies = " is destroyed.";
+ }
+
+
+ /* Handle unseen monster */
+ if (!visible)
+ {
+ /* Invisible monster */
+ msg_format("The %s finds a mark.", o_name);
+ }
+
+ /* Handle visible monster */
+ else
+ {
+ char m_name[80];
+
+ /* Get "the monster" or "it" */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Message */
+ msg_format("The %s hits %s.", o_name, m_name);
+
+ /* Hack -- Track this monster race */
+ if (m_ptr->ml) monster_race_track(m_ptr->r_idx,
+ m_ptr->ego);
+
+ /* Hack -- Track this monster */
+ if (m_ptr->ml) health_track(c_ptr->m_idx);
+
+ /* Anger friends */
+ {
+ char m_name[80];
+ monster_desc(m_name, m_ptr, 0);
+ switch (is_friend(m_ptr))
+ {
+ case 1:
+ {
+ msg_format("%^s gets angry!", m_name);
+ change_side(m_ptr);
+ break;
+ }
+ case 0:
+ {
+ msg_format("%^s gets angry!", m_name);
+ m_ptr->status = MSTATUS_NEUTRAL_M;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Apply special damage XXX XXX XXX */
+ tdam = tot_dam_aux(q_ptr, tdam, m_ptr, &special);
+ tdam = critical_shot(q_ptr->weight, q_ptr->to_h, tdam, SKILL_ARCHERY);
+
+ /* No negative damage */
+ if (tdam < 0) tdam = 0;
+
+ /* Complex message */
+ if (wizard)
+ {
+ msg_format("You do %d (out of %d) damage.",
+ tdam, m_ptr->hp);
+ }
+
+ /* Hit the monster, check for death */
+ if (mon_take_hit(c_ptr->m_idx, tdam, &fear, note_dies))
+ {
+ /* Dead monster */
+ }
+
+ /* No death */
+ else
+ {
+ /* Message */
+ message_pain(c_ptr->m_idx, tdam);
+
+ if (special) attack_special(m_ptr, special, tdam);
+
+ /* Take note */
+ if (fear && m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Sound */
+ sound(SOUND_FLEE);
+
+ /* Get the monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Message */
+ msg_format("%^s flees in terror!", m_name);
+ }
+ }
+ }
+
+ /* Stop looking */
+ break;
+ }
+ }
+
+ /* Exploding arrow ? */
+ if (q_ptr->pval2 != 0)
+ {
+ int rad = 0, dam =
+ (damroll(q_ptr->dd, q_ptr->ds) + q_ptr->to_d) * 2;
+ int flag =
+ PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL |
+ PROJECT_JUMP;
+ switch (q_ptr->sval)
+ {
+ case SV_AMMO_LIGHT:
+ rad = 2;
+ dam /= 2;
+ break;
+ case SV_AMMO_NORMAL:
+ rad = 3;
+ break;
+ case SV_AMMO_HEAVY:
+ rad = 4;
+ dam *= 2;
+ break;
+ }
+
+ project(0, rad, y, x, dam, q_ptr->pval2, flag);
+ }
+
+ /* Chance of breakage (during attacks) */
+ j = (hit_body ? breakage_chance(q_ptr) : 0);
+
+ /* Break ? */
+ if ((q_ptr->pval2 != 0) || (rand_int(100) < j))
+ {
+ breakage = 100;
+ break;
+ }
+
+ /* If the ammo doesn't break, it can pierce through */
+ if ((num_pierce) && (hit_body) &&
+ (magik(45 + get_skill(SKILL_ARCHERY))))
+ {
+ num_pierce--;
+ hit_body = FALSE;
+
+ /* If target isn't reached, continue moving to target */
+ if ( !((tx < x && x < bx) || (bx < x && x < tx)) &&
+ !((ty < y && y < by) || (by < y && y < ty)))
+ {
+ /* Continue moving in same direction if we reached the target */
+ int dx = tx - bx;
+ int dy = ty - by;
+ tx = x + 99 * dx;
+ ty = y + 99 * dy;
+
+ /* New base location */
+ by = y;
+ bx = x;
+ }
+
+ msg_format("The %s pierces through!", o_name);
+ }
+ else
+ break;
+ }
+
+ /* Drop (or break) near that location */
+ drop_near(q_ptr, breakage, y, x);
+}
+
+
+/*
+ * Why is this here? even if it's temporary boost...
+ * Moved into player_type, hoping it might be useful in future extensions
+ * -- pelpel
+ */
+/* int throw_mult = 1; */
+
+/*
+ * Throw an object from the pack or floor.
+ *
+ * Note: "unseen" monsters are very hard to hit.
+ *
+ * Should throwing a weapon do full damage? Should it allow the magic
+ * to hit bonus of the weapon to have an effect? Should it ever cause
+ * the item to be destroyed? Should it do any damage at all?
+ */
+void do_cmd_throw(void)
+{
+ int dir, item;
+
+ s32b special = 0;
+
+ int j, y, x, ny, nx, ty, tx;
+
+ int chance, tdam, tdis;
+
+ int mul, div;
+
+ int boulder_add = 0;
+ int boulder_mult = 0;
+
+ int cur_dis, visible;
+
+ object_type forge;
+
+ object_type *q_ptr;
+
+ object_type *o_ptr;
+
+ bool_ hit_body = FALSE;
+
+ bool_ hit_wall = FALSE;
+
+ byte missile_attr;
+
+ char missile_char;
+
+ char o_name[80];
+
+ int msec = delay_factor * delay_factor * delay_factor;
+
+ cptr q, s;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Get an item */
+ q = "Throw which item? ";
+ s = "You have nothing to throw.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Access the item */
+ o_ptr = get_object(item);
+
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hack - Cannot throw away 'no drop' cursed items */
+ if (cursed_p(o_ptr) && (f4 & TR4_CURSE_NO_DROP))
+ {
+ /* Oops */
+ msg_print("Hmmm, you seem to be unable to throw it.");
+
+ /* Nope */
+ return;
+ }
+
+ /* Boulder throwing */
+ if ((o_ptr->tval == TV_JUNK) && (o_ptr->sval == SV_BOULDER) && (get_skill(SKILL_BOULDER)))
+ {
+ boulder_add = get_skill_scale(SKILL_BOULDER, 80);
+ boulder_mult = get_skill_scale(SKILL_BOULDER, 6);
+ }
+
+ /* Get a direction (or cancel) */
+ if (!get_aim_dir(&dir)) return;
+
+ /* Break goi/manashield */
+ if (p_ptr->invuln)
+ {
+ set_invuln(0);
+ }
+ if (p_ptr->disrupt_shield)
+ {
+ set_disrupt_shield(0);
+ }
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Obtain a local object */
+ object_copy(q_ptr, o_ptr);
+
+ /*
+ * Hack -- If rods or wands are thrown, the total maximum timeout or
+ * charges need to be allocated between the two stacks.
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ q_ptr->pval = o_ptr->pval / o_ptr->number;
+
+ if (o_ptr->number > 1) o_ptr->pval -= q_ptr->pval;
+ }
+
+ /* Single object */
+ q_ptr->number = 1;
+
+ /* Reduce stack and describe */
+ inc_stack_size(item, -1);
+
+ /* Description */
+ object_desc(o_name, q_ptr, FALSE, 3);
+
+ /* Find the color and symbol for the object for throwing */
+ missile_attr = object_attr(q_ptr);
+ missile_char = object_char(q_ptr);
+
+ /* Extract a "distance multiplier" */
+ /* Changed for 'launcher' corruption */
+ mul = 10 + (2 * (p_ptr->throw_mult - 1)) + (2 * boulder_mult);
+
+ /* Enforce a minimum "weight" of one pound */
+ div = ((q_ptr->weight > 10) ? q_ptr->weight : 10);
+
+ /* Hack -- Distance -- Reward strength, penalize weight */
+ tdis = (adj_str_blow[p_ptr->stat_ind[A_STR]] + 20) * mul / div;
+
+ /* Max distance of 10-18 */
+ if (tdis > mul) tdis = mul;
+
+ /* Hack -- Base damage from thrown object */
+ tdam = damroll(q_ptr->dd, q_ptr->ds) + q_ptr->to_d + boulder_add;
+ tdam *= p_ptr->throw_mult + boulder_mult;
+
+ /* Chance of hitting - adjusted for Weaponmasters -- Gumby */
+ chance = (p_ptr->skill_tht + (p_ptr->to_h * BTH_PLUS_ADJ));
+
+ /* Take a turn */
+ energy_use = 100;
+
+
+ /* Start at the player */
+ y = p_ptr->py;
+ x = p_ptr->px;
+
+ /* Predict the "target" location */
+ tx = p_ptr->px + 99 * ddx[dir];
+ ty = p_ptr->py + 99 * ddy[dir];
+
+ /* Check for "target request" */
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+ }
+
+
+ /* Hack -- Handle stuff */
+ handle_stuff();
+
+
+ /* Travel until stopped */
+ for (cur_dis = 0; cur_dis <= tdis; )
+ {
+ /* Hack -- Stop at the target */
+ if ((y == ty) && (x == tx)) break;
+
+ /* Calculate the new location (see "project()") */
+ ny = y;
+ nx = x;
+ mmove2(&ny, &nx, p_ptr->py, p_ptr->px, ty, tx);
+
+ /* Stopped by walls/doors */
+ if (!cave_floor_bold(ny, nx))
+ {
+ hit_wall = TRUE;
+ break;
+ }
+
+ /* Advance the distance */
+ cur_dis++;
+
+ /* Save the new location */
+ x = nx;
+ y = ny;
+
+
+ /* The player can see the (on screen) missile */
+ if (panel_contains(y, x) && player_can_see_bold(y, x))
+ {
+ /* Draw, Hilite, Fresh, Pause, Erase */
+ print_rel(missile_char, missile_attr, y, x);
+ move_cursor_relative(y, x);
+ Term_fresh();
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ lite_spot(y, x);
+ Term_fresh();
+ }
+
+ /* The player cannot see the missile */
+ else
+ {
+ /* Pause anyway, for consistancy */
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ }
+
+
+ /* Monster here, Try to hit it */
+ if (cave[y][x].m_idx)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Check the visibility */
+ visible = m_ptr->ml;
+
+ /* Note the collision */
+ hit_body = TRUE;
+
+ /* Did we hit it (penalize range) */
+ if (test_hit_fire(chance - cur_dis, m_ptr->ac, m_ptr->ml))
+ {
+ bool_ fear = FALSE;
+
+ /* Assume a default death */
+ cptr note_dies = " dies.";
+
+ /* Some monsters get "destroyed" */
+ if ((r_ptr->flags3 & (RF3_DEMON)) ||
+ (r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags2 & (RF2_STUPID)) ||
+ (strchr("Evg", r_ptr->d_char)))
+ {
+ /* Special note at death */
+ note_dies = " is destroyed.";
+ }
+
+
+ /* Handle unseen monster */
+ if (!visible)
+ {
+ /* Invisible monster */
+ msg_format("The %s finds a mark.", o_name);
+ }
+
+ /* Handle visible monster */
+ else
+ {
+ char m_name[80];
+
+ /* Get "the monster" or "it" */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Message */
+ msg_format("The %s hits %s.", o_name, m_name);
+
+ /* Hack -- Track this monster race */
+ if (m_ptr->ml) monster_race_track(m_ptr->r_idx, m_ptr->ego);
+
+ /* Hack -- Track this monster */
+ if (m_ptr->ml) health_track(c_ptr->m_idx);
+ }
+
+ /* Apply special damage XXX XXX XXX */
+ tdam = tot_dam_aux(q_ptr, tdam, m_ptr, &special);
+ tdam = critical_shot(q_ptr->weight, q_ptr->to_h, tdam, o_ptr->sval == SV_BOULDER ? SKILL_BOULDER : SKILL_ARCHERY);
+
+ /* No negative damage */
+ if (tdam < 0) tdam = 0;
+
+ /* Complex message */
+ if (wizard)
+ {
+ msg_format("You do %d (out of %d) damage.",
+ tdam, m_ptr->hp);
+ }
+
+ /* Hit the monster, check for death */
+ if (mon_take_hit(c_ptr->m_idx, tdam, &fear, note_dies))
+ {
+ /* Dead monster */
+ }
+
+ /* No death */
+ else
+ {
+ /* Message */
+ message_pain(c_ptr->m_idx, tdam);
+
+ if (special) attack_special(m_ptr, special, tdam);
+
+ /* Anger friends */
+ if (!(k_info[q_ptr->k_idx].tval == TV_POTION))
+ {
+ char m_name[80];
+ monster_desc(m_name, m_ptr, 0);
+ switch (is_friend(m_ptr))
+ {
+ case 1:
+ msg_format("%^s gets angry!", m_name);
+ change_side(m_ptr);
+ break;
+ case 0:
+ msg_format("%^s gets angry!", m_name);
+ m_ptr->status = MSTATUS_NEUTRAL_M;
+ break;
+ }
+ }
+
+ /* Take note */
+ if (fear && m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Sound */
+ sound(SOUND_FLEE);
+
+ /* Get the monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Message */
+ msg_format("%^s flees in terror!", m_name);
+ }
+ }
+ }
+
+ /* Stop looking */
+ break;
+ }
+ }
+
+ /* Chance of breakage (during attacks) */
+ j = (hit_body ? breakage_chance(q_ptr) : 0);
+
+ /* Potions smash open */
+ if (k_info[q_ptr->k_idx].tval == TV_POTION)
+ {
+ if ((hit_body) || (hit_wall) || (randint(100) < j))
+ {
+ /* Message */
+ msg_format("The %s shatters!", o_name);
+
+ if (potion_smash_effect(0, y, x, q_ptr->sval))
+ {
+ if (cave[y][x].m_idx)
+ {
+ char m_name[80];
+ monster_desc(m_name, &m_list[cave[y][x].m_idx], 0);
+ switch (is_friend(&m_list[cave[y][x].m_idx]))
+ {
+ case 1:
+ msg_format("%^s gets angry!", m_name);
+ change_side(&m_list[cave[y][x].m_idx]);
+ break;
+ case 0:
+ msg_format("%^s gets angry!", m_name);
+ m_list[cave[y][x].m_idx].status = MSTATUS_NEUTRAL_M;
+ break;
+ }
+ }
+ }
+
+ return;
+ }
+ else
+ {
+ j = 0;
+ }
+ }
+
+ /* Drop (or break) near that location */
+ drop_near(q_ptr, j, y, x);
+}
+
+
+/*
+ * Throw a boomerang object from the equipement(bow).
+ *
+ * Note: "unseen" monsters are very hard to hit.
+ *
+ * Should throwing a weapon do full damage? Should it allow the magic
+ * to hit bonus of the weapon to have an effect? Should it ever cause
+ * the item to be destroyed? Should it do any damage at all?
+ */
+void do_cmd_boomerang(void)
+{
+ int dir;
+
+ int j, y, x, ny, nx, ty, tx;
+
+ int chance, tdam, tdis;
+
+ int mul, div;
+
+ int cur_dis, visible;
+
+ object_type forge;
+
+ object_type *q_ptr;
+
+ object_type *o_ptr;
+
+ bool_ hit_body = FALSE;
+
+ byte missile_attr;
+
+ char missile_char;
+
+ char o_name[80];
+
+ s32b special = 0;
+
+ int msec = delay_factor * delay_factor * delay_factor;
+
+
+ /* Get the "bow" (if any) */
+ o_ptr = &p_ptr->inventory[INVEN_BOW];
+
+
+ /* Get a direction (or cancel) */
+ if (!get_aim_dir(&dir)) return;
+
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Obtain a local object */
+ object_copy(q_ptr, o_ptr);
+
+ /* Single object */
+ q_ptr->number = 1;
+
+ /* Description */
+ object_desc(o_name, q_ptr, FALSE, 3);
+
+ /* Find the color and symbol for the object for throwing */
+ missile_attr = object_attr(q_ptr);
+ missile_char = object_char(q_ptr);
+
+ /* Extract a "distance multiplier" */
+ /* Changed for 'launcher' corruption */
+ mul = 10 + 2 * (p_ptr->throw_mult - 1);
+
+ /* Enforce a minimum "weight" of one pound */
+ div = ((q_ptr->weight > 10) ? q_ptr->weight : 10);
+
+ /* Hack -- Distance -- Reward strength, penalize weight */
+ tdis = (adj_str_blow[p_ptr->stat_ind[A_STR]] + 20) * mul / div;
+
+ /* Max distance of 10-18 */
+ if (tdis > mul) tdis = mul;
+
+ /* Hack -- Base damage from thrown object */
+ tdam = damroll(q_ptr->dd, q_ptr->ds) + q_ptr->to_d;
+ tdam *= p_ptr->throw_mult;
+
+ /* Chance of hitting */
+ chance =
+ (p_ptr->skill_tht +
+ ((p_ptr->to_h + p_ptr->to_h_ranged) * BTH_PLUS_ADJ));
+
+ chance += get_skill(SKILL_BOOMERANG);
+
+ /* Take a turn */
+ energy_use = 100;
+
+
+ /* Start at the player */
+ y = p_ptr->py;
+ x = p_ptr->px;
+
+ /* Predict the "target" location */
+ tx = p_ptr->px + 99 * ddx[dir];
+ ty = p_ptr->py + 99 * ddy[dir];
+
+ /* Check for "target request" */
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+ }
+
+
+ /* Hack -- Handle stuff */
+ handle_stuff();
+
+
+ /* Travel until stopped */
+ for (cur_dis = 0; cur_dis <= tdis; )
+ {
+ /* Hack -- Stop at the target */
+ if ((y == ty) && (x == tx)) break;
+
+ /* Calculate the new location (see "project()") */
+ ny = y;
+ nx = x;
+ mmove2(&ny, &nx, p_ptr->py, p_ptr->px, ty, tx);
+
+ /* Stopped by walls/doors */
+ if (!cave_floor_bold(ny, nx))
+ {
+ break;
+ }
+
+ /* Advance the distance */
+ cur_dis++;
+
+ /* Save the new location */
+ x = nx;
+ y = ny;
+
+
+ /* The player can see the (on screen) missile */
+ if (panel_contains(y, x) && player_can_see_bold(y, x))
+ {
+ /* Draw, Hilite, Fresh, Pause, Erase */
+ print_rel(missile_char, missile_attr, y, x);
+ move_cursor_relative(y, x);
+ Term_fresh();
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ lite_spot(y, x);
+ Term_fresh();
+ }
+
+ /* The player cannot see the missile */
+ else
+ {
+ /* Pause anyway, for consistancy */
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ }
+
+
+ /* Monster here, Try to hit it */
+ if (cave[y][x].m_idx)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Check the visibility */
+ visible = m_ptr->ml;
+
+ /* Note the collision */
+ hit_body = TRUE;
+
+ /* Did we hit it (penalize range) */
+ if (test_hit_fire(chance - cur_dis, m_ptr->ac, m_ptr->ml))
+ {
+ bool_ fear = FALSE;
+
+ /* Assume a default death */
+ cptr note_dies = " dies.";
+
+ /* Some monsters get "destroyed" */
+ if ((r_ptr->flags3 & (RF3_DEMON)) ||
+ (r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags2 & (RF2_STUPID)) ||
+ (strchr("Evg", r_ptr->d_char)))
+ {
+ /* Special note at death */
+ note_dies = " is destroyed.";
+ }
+
+
+ /* Handle unseen monster */
+ if (!visible)
+ {
+ /* Invisible monster */
+ msg_format("The %s finds a mark.", o_name);
+ }
+
+ /* Handle visible monster */
+ else
+ {
+ char m_name[80];
+
+ /* Get "the monster" or "it" */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Message */
+ msg_format("The %s hits %s.", o_name, m_name);
+
+ /* Hack -- Track this monster race */
+ if (m_ptr->ml) monster_race_track(m_ptr->r_idx, m_ptr->ego);
+
+ /* Hack -- Track this monster */
+ if (m_ptr->ml) health_track(c_ptr->m_idx);
+ }
+
+ /* Apply special damage XXX XXX XXX */
+ tdam = tot_dam_aux(q_ptr, tdam, m_ptr, &special);
+ tdam = critical_shot(q_ptr->weight, q_ptr->to_h, tdam, SKILL_ARCHERY);
+
+ /* No negative damage */
+ if (tdam < 0) tdam = 0;
+
+ /* Complex message */
+ if (wizard)
+ {
+ msg_format("You do %d (out of %d) damage.",
+ tdam, m_ptr->hp);
+ }
+
+ /* Hit the monster, check for death */
+ if (mon_take_hit(c_ptr->m_idx, tdam, &fear, note_dies))
+ {
+ /* Dead monster */
+ }
+
+ /* No death */
+ else
+ {
+ /* Message */
+ message_pain(c_ptr->m_idx, tdam);
+
+ if (special) attack_special(m_ptr, special, tdam);
+
+ /* Anger friends */
+ if (!(k_info[q_ptr->k_idx].tval == TV_POTION))
+ {
+ char m_name[80];
+ monster_desc(m_name, m_ptr, 0);
+ switch (is_friend(m_ptr))
+ {
+ case 1:
+ msg_format("%^s gets angry!", m_name);
+ change_side(m_ptr);
+ break;
+ case 0:
+ msg_format("%^s gets angry!", m_name);
+ m_ptr->status = MSTATUS_NEUTRAL_M;
+ break;
+ }
+ }
+
+ /* Take note */
+ if (fear && m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Sound */
+ sound(SOUND_FLEE);
+
+ /* Get the monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Message */
+ msg_format("%^s flees in terror!", m_name);
+ }
+ }
+
+ /* Chance of breakage (during attacks) */
+ j = (hit_body ? breakage_chance(o_ptr) : 0);
+
+ /* Break the boomerang */
+ if (!(o_ptr->art_name || artifact_p(o_ptr)) &&
+ (rand_int(100) < j))
+ {
+ msg_print(format("Your %s is destroyed.", o_name));
+ inc_stack_size_ex(INVEN_BOW, -1, OPTIMIZE, NO_DESCRIBE);
+ }
+ }
+
+ /* Stop looking */
+ break;
+ }
+ }
+
+ /* Travel back to the player */
+ for (cur_dis = 0; cur_dis <= tdis; )
+ {
+ /* Hack -- Stop at the target */
+ if ((y == p_ptr->py) && (x == p_ptr->px)) break;
+
+ /* Calculate the new location (see "project()") */
+ ny = y;
+ nx = x;
+ mmove2(&ny, &nx, ty, tx, p_ptr->py, p_ptr->px);
+
+ /* Advance the distance */
+ cur_dis++;
+
+ /* Save the new location */
+ x = nx;
+ y = ny;
+
+
+ /* The player can see the (on screen) missile */
+ if (panel_contains(y, x) && player_can_see_bold(y, x))
+ {
+ /* Draw, Hilite, Fresh, Pause, Erase */
+ print_rel(missile_char, missile_attr, y, x);
+ move_cursor_relative(y, x);
+ Term_fresh();
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ lite_spot(y, x);
+ Term_fresh();
+ }
+
+ /* The player cannot see the missile */
+ else
+ {
+ /* Pause anyway, for consistancy */
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ }
+ }
+}
+
+
+/*
+ * Try to ``walk'' using phase door.
+ */
+void do_cmd_unwalk()
+{
+ int dir, y, x, feat;
+
+ cave_type *c_ptr;
+
+ bool_ more = FALSE;
+
+
+ if (!get_rep_dir(&dir)) return;
+
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ c_ptr = &cave[y][x];
+ feat = c_ptr->feat;
+
+ /* Must have knowledge to know feature XXX XXX */
+ if (!(c_ptr->info & (CAVE_MARK))) feat = FEAT_NONE;
+
+ /* Take a turn */
+ energy_use = 100;
+ energy_use *= (p_ptr->wild_mode) ? (5 * (MAX_HGT + MAX_WID) / 2) : 1;
+
+
+ /* Allow repeated command */
+ if (command_arg)
+ {
+ /* Set repeat count */
+ command_rep = command_arg - 1;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Cancel the arg */
+ command_arg = 0;
+ }
+
+
+ /* Attack monsters */
+ if (c_ptr->m_idx > 0)
+ {
+ /* Attack */
+ py_attack(y, x, -1);
+ }
+
+ /* Exit the area */
+ else if ((!dun_level) && (!p_ptr->wild_mode) &&
+ ((x == 0) || (x == cur_wid - 1) || (y == 0) || (y == cur_hgt - 1)))
+ {
+ /* Can the player enter the grid? */
+ if (player_can_enter(c_ptr->mimic))
+ {
+ /* Hack: move to new area */
+ if ((y == 0) && (x == 0))
+ {
+ p_ptr->wilderness_y--;
+ p_ptr->wilderness_x--;
+ p_ptr->oldpy = cur_hgt - 2;
+ p_ptr->oldpx = cur_wid - 2;
+ ambush_flag = FALSE;
+ }
+
+ else if ((y == 0) && (x == MAX_WID - 1))
+ {
+ p_ptr->wilderness_y--;
+ p_ptr->wilderness_x++;
+ p_ptr->oldpy = cur_hgt - 2;
+ p_ptr->oldpx = 1;
+ ambush_flag = FALSE;
+ }
+
+ else if ((y == MAX_HGT - 1) && (x == 0))
+ {
+ p_ptr->wilderness_y++;
+ p_ptr->wilderness_x--;
+ p_ptr->oldpy = 1;
+ p_ptr->oldpx = cur_wid - 2;
+ ambush_flag = FALSE;
+ }
+
+ else if ((y == MAX_HGT - 1) && (x == MAX_WID - 1))
+ {
+ p_ptr->wilderness_y++;
+ p_ptr->wilderness_x++;
+ p_ptr->oldpy = 1;
+ p_ptr->oldpx = 1;
+ ambush_flag = FALSE;
+ }
+
+ else if (y == 0)
+ {
+ p_ptr->wilderness_y--;
+ p_ptr->oldpy = cur_hgt - 2;
+ p_ptr->oldpx = x;
+ ambush_flag = FALSE;
+ }
+
+ else if (y == cur_hgt - 1)
+ {
+ p_ptr->wilderness_y++;
+ p_ptr->oldpy = 1;
+ p_ptr->oldpx = x;
+ ambush_flag = FALSE;
+ }
+
+ else if (x == 0)
+ {
+ p_ptr->wilderness_x--;
+ p_ptr->oldpx = cur_wid - 2;
+ p_ptr->oldpy = y;
+ ambush_flag = FALSE;
+ }
+
+ else if (x == cur_wid - 1)
+ {
+ p_ptr->wilderness_x++;
+ p_ptr->oldpx = 1;
+ p_ptr->oldpy = y;
+ ambush_flag = FALSE;
+ }
+
+ p_ptr->leaving = TRUE;
+
+ return;
+ }
+ }
+
+ /* Hack -- Ignore weird terrain types. */
+ else if (!cave_floor_grid(c_ptr))
+ {
+ teleport_player(10);
+ }
+
+ /* Enter quests */
+ else if (((feat >= FEAT_QUEST_ENTER) && (feat <= FEAT_QUEST_UP)) ||
+ ((feat >= FEAT_LESS) && (feat <= FEAT_MORE)))
+ {
+ move_player(dir, always_pickup, TRUE);
+ more = FALSE;
+ }
+
+ /* Hack -- Ignore wilderness mofe. */
+ else if (p_ptr->wild_mode)
+ {
+ /* Chance to not blink right */
+ if (magik(15))
+ {
+ do
+ {
+ dir = rand_range(1, 9);
+ }
+ while (dir == 5);
+ }
+
+ move_player(dir, always_pickup, TRUE);
+ }
+
+ /* Walking semantics */
+ else
+ {
+ teleport_player_directed(10, dir);
+ }
+
+ /* Cancel repetition unless we can continue */
+ if (!more) disturb(0, 0);
+}
+
+
+static bool_ tport_vertically(bool_ how)
+{
+ /* arena or quest -KMW- */
+ if ((p_ptr->inside_arena) || (p_ptr->inside_quest))
+ {
+ msg_print("There is no effect.");
+ return (FALSE);
+ }
+
+ if (dungeon_flags2 & DF2_NO_EASY_MOVE)
+ {
+ msg_print("Some powerful force prevents you from teleporting.");
+ return FALSE;
+ }
+
+ /* Go down */
+ if (how)
+ {
+ if (dun_level >= d_info[dungeon_type].maxdepth)
+ {
+ msg_print("The floor is impermeable.");
+ return (FALSE);
+ }
+
+ msg_print("You sink through the floor.");
+ dun_level++;
+ p_ptr->leaving = TRUE;
+ }
+ else
+ {
+ if (dun_level < d_info[dungeon_type].mindepth)
+ {
+ msg_print("There is nothing above you but air.");
+ return (FALSE);
+ }
+
+ msg_print("You rise through the ceiling.");
+ dun_level--;
+ p_ptr->leaving = TRUE;
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * Do a special ``movement'' action. Meant to be used for ``immovable''
+ * characters.
+ */
+void do_cmd_immovable_special(void)
+{
+ int i, ii, ij, dir;
+
+ int foo = p_ptr->immov_cntr;
+
+ int lose_sp = 0;
+
+ int lose_hp = 0;
+
+ bool_ did_act = FALSE;
+
+ bool_ did_load = FALSE;
+
+
+ if (foo > 1)
+ {
+ if (p_ptr->csp > foo / 2)
+ {
+
+ msg_format("This will drain %d mana points!", foo / 2);
+ if (!get_check("Proceed? ")) return;
+
+ lose_sp = foo / 2;
+
+ }
+ else if (p_ptr->chp > foo / 2)
+ {
+
+ msg_format("Warning: This will drain %d hit points!", foo / 2);
+ if (!get_check("Proceed? ")) return;
+
+ lose_hp = foo / 2;
+
+ }
+ else
+ {
+ msg_print("You can't use your powers yet.");
+ return;
+ }
+ }
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+
+ /* Interact until done */
+ while (1)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Ask for a choice */
+ prt("Do what special action:", 2, 0);
+
+ /* Give some choices */
+ prt("(a) Teleport to a specific place.", 4, 5);
+ prt("(b) Fetch an item.", 5, 5);
+ prt("(c) Go up 50'", 6, 5);
+ prt("(d) Go down 50'", 7, 5);
+
+ /* Prompt */
+ prt("Command: ", 9, 0);
+
+ /* Prompt */
+ i = inkey();
+
+ /* Done */
+ if (i == ESCAPE) break;
+
+ /* Tele-to */
+ if (i == 'a')
+ {
+ Term_load();
+ character_icky = FALSE;
+ did_load = TRUE;
+
+ if (!tgt_pt(&ii, &ij)) break;
+
+ /* Teleport to the target */
+ teleport_player_to(ij, ii);
+
+ did_act = TRUE;
+ break;
+ }
+
+ /* Fetch item */
+ else if (i == 'b')
+ {
+ Term_load();
+ character_icky = FALSE;
+ did_load = TRUE;
+
+ if (!get_aim_dir(&dir)) return;
+ fetch(dir, p_ptr->lev * 15, FALSE);
+ py_pickup_floor(always_pickup);
+
+ did_act = TRUE;
+ break;
+ }
+
+ /* Move up */
+ else if (i == 'c')
+ {
+ Term_load();
+ character_icky = FALSE;
+ did_load = TRUE;
+
+ if (!tport_vertically(FALSE)) return;
+
+ did_act = TRUE;
+ break;
+ }
+
+ /* Move down */
+ else if (i == 'd')
+ {
+ Term_load();
+ character_icky = FALSE;
+ did_load = TRUE;
+
+ if (!tport_vertically(TRUE)) return;
+
+ did_act = TRUE;
+ break;
+ }
+
+ /* Unknown option */
+ else
+ {
+ bell();
+ }
+
+ }
+
+ /* Check if screen was restored before */
+ if (!did_load)
+ {
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+ }
+
+ /* Apply stat losses if something was done */
+ if (did_act)
+ {
+ p_ptr->immov_cntr += 101 - (p_ptr->lev * 2);
+
+ if (lose_sp)
+ {
+ p_ptr->csp -= lose_sp;
+ p_ptr->redraw |= (PR_MANA);
+ }
+
+ if (lose_hp)
+ {
+ p_ptr->chp -= lose_hp;
+ p_ptr->redraw |= (PR_HP);
+ }
+
+ energy_use = 100;
+ }
+}
+
+/* Can we sacrifice it ? */
+static bool_ item_tester_hook_sacrifiable(object_type *o_ptr)
+{
+ GOD(GOD_MELKOR)
+ {
+ /* Corpses are */
+ if (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_CORPSE_CORPSE)
+ return (TRUE);
+
+ /* Books without any udun spells */
+ if ((o_ptr->tval == TV_BOOK) && (exec_lua(format("return udun_in_book(%d, %d)", o_ptr->sval, o_ptr->pval)) == 0))
+ return TRUE;
+ }
+
+ /* Assume not */
+ return (FALSE);
+}
+
+/*
+ * Handle sacrifices.
+ * Grace is increased by value of sacrifice.
+ */
+void do_cmd_sacrifice(void)
+{
+ byte on_what = cave[p_ptr->py][p_ptr->px].feat;
+
+ /* Check valididty */
+ if ((on_what < FEAT_ALTAR_HEAD) || (on_what > FEAT_ALTAR_TAIL))
+ {
+ show_god_info(FALSE);
+ return;
+ }
+ else
+ {
+ int agod = on_what - FEAT_ALTAR_HEAD + 1;
+
+ /* Not worshipping a god ? ahhhh! */
+ GOD(GOD_NONE)
+ {
+ int i;
+
+ for (i = 0; i < 10; i++)
+ {
+ if (deity_info[agod].desc[i] != NULL)
+ msg_print(deity_info[agod].desc[i]);
+ }
+ if (get_check(format("Do you want to worship %s? ", deity_info[agod].name)))
+ {
+ follow_god(agod, FALSE);
+ p_ptr->grace = -200;
+ inc_piety(p_ptr->pgod, 0);
+ }
+ }
+ else if (p_ptr->pgod == agod)
+ {
+ GOD(GOD_MELKOR)
+ {
+ /* One can sacrifice some HP for piety or damage */
+ if ((p_ptr->mhp > 10) && (p_ptr->chp > 10) && get_check("Do you want to sacrifice a part of yourself? "))
+ {
+ /* 10 HP = 300 * wis piety */
+ if (get_check("Do you want to sacrifice for more piety instead of damage? "))
+ {
+ int x = wisdom_scale(6);
+ if (x < 1) x = 1;
+
+ p_ptr->hp_mod -= 10;
+ take_hit(10, "self sacrifice to Melkor");
+ msg_print("Your life slips away, and Melkor seems happier.");
+ inc_piety(GOD_MELKOR, x * 300);
+ p_ptr->update |= (PU_HP);
+ }
+ /* 10 HP = +wis damage */
+ else
+ {
+ take_hit(10, "self sacrifice to Melkor");
+ msg_print("Your life slips away, and your arms grow stronger.");
+ p_ptr->melkor_sacrifice++;
+ p_ptr->update |= (PU_BONUS | PU_HP);
+ }
+ }
+ else
+ {
+ int item;
+ object_type *o_ptr;
+
+ /* Restrict choices to food */
+ item_tester_hook = item_tester_hook_sacrifiable;
+
+ /* Get an item */
+ if (!get_item(&item, "Sacrifice which item? ", "You have nothing to sacrifice.", (USE_INVEN))) return;
+ o_ptr = get_object(item);
+
+ /* Piety for corpses is based on monster level */
+ if (o_ptr->tval == TV_CORPSE)
+ {
+ inc_piety(GOD_MELKOR, 2 * r_info[o_ptr->pval2].level);
+ }
+
+ /* In books it depends of the spell levels*/
+ if (o_ptr->tval == TV_BOOK)
+ {
+ int x = exec_lua(format("return levels_in_book(%d, %d)", o_ptr->sval, o_ptr->pval));
+
+ inc_piety(GOD_MELKOR, 2 * x);
+ }
+
+ /* Remove the item */
+ inc_stack_size(item, -1);
+ }
+ }
+ else
+ {
+ process_hooks(HOOK_SACRIFICE_GOD, "()", "");
+ }
+ }
+ }
+}
+
+
+/*
+ * scan_monst --
+ *
+ * Return a list of o_list[] indexes of items of the given monster
+ */
+bool_ scan_monst(int *items, int *item_num, int m_idx)
+{
+ int this_o_idx, next_o_idx;
+
+ int num = 0;
+
+
+ (*item_num) = 0;
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = m_list[m_idx].hold_o_idx; this_o_idx;
+ this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Accept this item */
+ items[num++] = this_o_idx;
+
+ /* XXX Hack -- Enforce limit */
+ if (num == 23) break;
+ }
+
+ /* Number of items */
+ (*item_num) = num;
+
+ /* Result */
+ return (num != 0);
+}
+
+
+/*
+ * Display a list of the items that the given monster carries.
+ */
+byte show_monster_inven(int m_idx, int *monst_list)
+{
+ int i, j, k, l;
+
+ int col, len, lim;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ char tmp_val[80];
+
+ int out_index[23];
+
+ byte out_color[23];
+
+ char out_desc[23][80];
+
+ int monst_num;
+
+
+ /* Default length */
+ len = 79 - 50;
+
+ /* Maximum space allowed for descriptions */
+ lim = 79 - 3;
+
+ /* Require space for weight (if needed) */
+ if (show_weights) lim -= 9;
+
+ /* Scan for objects on the monster */
+ (void)scan_monst(monst_list, &monst_num, m_idx);
+
+ /* Display the p_ptr->inventory */
+ for (k = 0, i = 0; i < monst_num; i++)
+ {
+ o_ptr = &o_list[monst_list[i]];
+
+ /* Describe the object */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Hack -- enforce max length */
+ o_name[lim] = '\0';
+
+ /* Save the index */
+ out_index[k] = i;
+
+ /* Acquire p_ptr->inventory color */
+ out_color[k] = tval_to_attr[o_ptr->tval & 0x7F];
+
+ /* Save the object description */
+ strcpy(out_desc[k], o_name);
+
+ /* Find the predicted "line length" */
+ l = strlen(out_desc[k]) + 5;
+
+ /* Be sure to account for the weight */
+ if (show_weights) l += 9;
+
+ /* Maintain the maximum length */
+ if (l > len) len = l;
+
+ /* Advance to next "line" */
+ k++;
+ }
+
+ /* Find the column to start in */
+ col = (len > 76) ? 0 : (79 - len);
+
+ /* Output each entry */
+ for (j = 0; j < k; j++)
+ {
+ /* Get the index */
+ i = monst_list[out_index[j]];
+
+ /* Get the item */
+ o_ptr = &o_list[i];
+
+ /* Clear the line */
+ prt("", j + 1, col ? col - 2 : col);
+
+ /* Prepare an index --(-- */
+ strnfmt(tmp_val, 80, "%c)", index_to_label(j));
+
+ /* Clear the line with the (possibly indented) index */
+ put_str(tmp_val, j + 1, col);
+
+ /* Display the entry itself */
+ c_put_str(out_color[j], out_desc[j], j + 1, col + 3);
+
+ /* Display the weight if needed */
+ if (show_weights)
+ {
+ int wgt = o_ptr->weight * o_ptr->number;
+ strnfmt(tmp_val, 80, "%3d.%1d lb", wgt / 10, wgt % 10);
+ put_str(tmp_val, j + 1, 71);
+ }
+ }
+
+ /* Make a "shadow" below the list (only if needed) */
+ if (j && (j < 23)) prt("", j + 1, col ? col - 2 : col);
+
+ return monst_num;
+}
+
+
+/*
+ * Steal an object from a monster
+ */
+void do_cmd_steal()
+{
+ int x, y, dir = 0, item = -1, k = -1;
+
+ cave_type *c_ptr;
+
+ monster_type *m_ptr;
+
+ object_type *o_ptr, forge;
+
+ byte num = 0;
+
+ bool_ done = FALSE;
+
+ int monst_list[23];
+
+
+ /* Only works on adjacent monsters */
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+
+ if (!(c_ptr->m_idx))
+ {
+ msg_print("There is no monster there!");
+ return;
+ }
+
+ m_ptr = &m_list[c_ptr->m_idx];
+
+ /* There were no non-gold items */
+ if (!m_ptr->hold_o_idx)
+ {
+ msg_print("That monster has no objects!");
+ return;
+ }
+
+ /* The monster is immune */
+ if (r_info[m_ptr->r_idx].flags7 & (RF7_NO_THEFT))
+ {
+ msg_print("The monster is guarding the treasures.");
+ return;
+ }
+
+ screen_save();
+
+ num = show_monster_inven(c_ptr->m_idx, monst_list);
+
+ /* Repeat until done */
+ while (!done)
+ {
+ char tmp_val[80];
+ char which = ' ';
+
+ /* Build the prompt */
+ strnfmt(tmp_val, 80, "Choose an item to steal (a-%c) or ESC:",
+ 'a' - 1 + num);
+
+ /* Show the prompt */
+ prt(tmp_val, 0, 0);
+
+ /* Get a key */
+ which = inkey();
+
+ /* Parse it */
+ switch (which)
+ {
+ case ESCAPE:
+ {
+ done = TRUE;
+
+ break;
+ }
+
+ default:
+ {
+ int ver;
+
+ /* Extract "query" setting */
+ ver = isupper(which);
+ which = tolower(which);
+
+ k = islower(which) ? A2I(which) : -1;
+ if (k < 0 || k >= num)
+ {
+ bell();
+
+ break;
+ }
+
+ /* Verify the item */
+ if (ver && !verify("Try", 0 - monst_list[k]))
+ {
+ done = TRUE;
+
+ break;
+ }
+
+ /* Accept that choice */
+ item = monst_list[k];
+ done = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ if (item != -1)
+ {
+ int chance;
+
+ chance = 40 - p_ptr->stat_ind[A_DEX];
+ chance +=
+ o_list[item].weight / (get_skill_scale(SKILL_STEALING, 19) + 1);
+ chance += get_skill_scale(SKILL_STEALING, 29) + 1;
+ chance -= (m_ptr->csleep) ? 10 : 0;
+ chance += m_ptr->level;
+
+ /* Failure check */
+ if (rand_int(chance) > 1 + get_skill_scale(SKILL_STEALING, 25))
+ {
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Wake up */
+ m_ptr->csleep = 0;
+
+ /* Speed up because monsters are ANGRY when you try to thief them */
+ m_ptr->mspeed += 5;
+
+ screen_load();
+
+ msg_print("Oops! The monster is now really *ANGRY*!");
+
+ return;
+ }
+
+ /* Reconnect the objects list */
+ if (num == 1) m_ptr->hold_o_idx = 0;
+ else
+ {
+ if (k > 0) o_list[monst_list[k - 1]].next_o_idx = monst_list[k + 1];
+ if (k + 1 >= num) o_list[monst_list[k - 1]].next_o_idx = 0;
+ if (k == 0) m_ptr->hold_o_idx = monst_list[k + 1];
+ }
+
+ /* Rogues gain some xp */
+ if (PRACE_FLAGS(PR1_EASE_STEAL))
+ {
+ s32b max_point;
+
+ /* Max XP gained from stealing */
+ max_point = (o_list[item].weight / 2) + (m_ptr->level * 10);
+
+ /* Randomise it a bit, with half a max guaranteed */
+ gain_exp((max_point / 2) + (randint(max_point) / 2));
+
+ /* Allow escape */
+ if (get_check("Phase door?")) teleport_player(10);
+ }
+
+ /* Get the item */
+ o_ptr = &forge;
+
+ /* Special handling for gold */
+ if (o_list[item].tval == TV_GOLD)
+ {
+ /* Collect the gold */
+ p_ptr->au += o_list[item].pval;
+
+ /* Redraw gold */
+ p_ptr->redraw |= (PR_GOLD);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+ else
+ {
+ object_copy(o_ptr, &o_list[item]);
+
+ inven_carry(o_ptr, FALSE);
+ }
+
+ /* Delete it */
+ o_list[item].k_idx = 0;
+ }
+
+ screen_load();
+
+ /* Take a turn */
+ energy_use = 100;
+}
+
+
+/*
+ * Give an item to a monster
+ */
+void do_cmd_give()
+{
+ int dir, x, y;
+
+ cave_type *c_ptr;
+
+ cptr q, s;
+
+ int item;
+
+
+ /* Get a "repeated" direction */
+ if (!get_rep_dir(&dir)) return;
+
+ /* Get requested location */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ /* Get requested grid */
+ c_ptr = &cave[y][x];
+
+ /* No monster in the way */
+ if (c_ptr->m_idx == 0)
+ {
+ msg_print("There is no monster there.");
+ return;
+ }
+
+ /* Get an item */
+ q = "What item do you want to offer? ";
+ s = "You have nothing to offer.";
+ if (!get_item(&item, q, s, USE_INVEN)) return;
+
+ /* Process hooks if there are any */
+ if (!process_hooks(HOOK_GIVE, "(d,d)", c_ptr->m_idx, item))
+ {
+ msg_print("The monster does not want your item.");
+ }
+
+ /* Take a turn, even if the offer is declined */
+ energy_use = 100;
+}
+
+
+/*
+ * Chat with a monster
+ */
+void do_cmd_chat()
+{
+ int dir, x, y;
+
+ cave_type *c_ptr;
+
+
+ /* Get a "repeated" direction */
+ if (!get_rep_dir(&dir)) return;
+
+ /* Get requested location */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+
+ /* Get requested grid */
+ c_ptr = &cave[y][x];
+
+ /* No monster in the way */
+ if (c_ptr->m_idx == 0)
+ {
+ msg_print("There is no monster there.");
+ return;
+ }
+
+ /* Process hook if there are any */
+ if (!process_hooks(HOOK_CHAT, "(d)", c_ptr->m_idx))
+ {
+ msg_print("The monster does not want to chat.");
+ }
+
+ /* No energy spent */
+}
diff --git a/src/cmd3.c b/src/cmd3.c
new file mode 100644
index 00000000..02dbc1c4
--- /dev/null
+++ b/src/cmd3.c
@@ -0,0 +1,2331 @@
+/* File: cmd3.c */
+
+/* Purpose: Inventory commands */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Display p_ptr->inventory
+ */
+void do_cmd_inven(void)
+{
+ char out_val[160];
+
+
+ /* Note that we are in "p_ptr->inventory" mode */
+ command_wrk = FALSE;
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Hack -- show empty slots */
+ item_tester_full = TRUE;
+
+ /* Display the p_ptr->inventory */
+ show_inven();
+
+ /* Hack -- hide empty slots */
+ item_tester_full = FALSE;
+
+
+ {
+ s32b total_weight = calc_total_weight();
+
+ strnfmt(out_val, 160,
+ "Inventory: carrying %ld.%ld pounds (%ld%% of capacity). Command: ",
+ total_weight / 10, total_weight % 10,
+ (total_weight * 100) / ((weight_limit()) / 2));
+ }
+
+ /* Get a command */
+ prt(out_val, 0, 0);
+
+ /* Get a new command */
+ command_new = inkey();
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+
+
+ /* Process "Escape" */
+ if (command_new == ESCAPE)
+ {
+ /* Reset stuff */
+ command_new = 0;
+ }
+
+ /* Process normal keys */
+ else
+ {
+ /* Mega-Hack -- Don't disable keymaps for this key */
+ request_command_inven_mode = TRUE;
+ }
+}
+
+
+/*
+ * Display equipment
+ */
+void do_cmd_equip(void)
+{
+ char out_val[160];
+
+
+ /* Note that we are in "equipment" mode */
+ command_wrk = TRUE;
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Hack -- show empty slots */
+ item_tester_full = TRUE;
+
+ /* Display the equipment */
+ show_equip();
+
+ /* Hack -- undo the hack above */
+ item_tester_full = FALSE;
+
+ /* Build a prompt */
+ {
+ s32b total_weight = calc_total_weight();
+
+ /* Build a prompt */
+ strnfmt(out_val, 160,
+ "Equipment: carrying %ld.%ld pounds (%ld%% of capacity). Command: ",
+ total_weight / 10, total_weight % 10,
+ (total_weight * 100) / ((weight_limit()) / 2));
+ }
+
+ /* Get a command */
+ prt(out_val, 0, 0);
+
+ /* Get a new command */
+ command_new = inkey();
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+
+
+ /* Process "Escape" */
+ if (command_new == ESCAPE)
+ {
+ /* Reset stuff */
+ command_new = 0;
+ }
+
+ /* Process normal keys */
+ else
+ {
+ /* Mega-Hack -- Don't disable keymaps for this key */
+ request_command_inven_mode = TRUE;
+ }
+}
+
+
+/*
+ * The "wearable" tester
+ */
+static bool_ item_tester_hook_wear(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+ int slot = wield_slot(o_ptr);
+
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Only one ultimate at a time */
+ if (f4 & TR4_ULTIMATE)
+ {
+ int i;
+
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ object_type *q_ptr = &p_ptr->inventory[i];
+
+ /* Extract the flags */
+ object_flags(q_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (!q_ptr->k_idx) continue;
+
+ if (f4 & TR4_ULTIMATE) return (FALSE);
+ }
+ }
+
+ if ((slot < INVEN_WIELD) || ((p_ptr->body_parts[slot - INVEN_WIELD] == INVEN_WIELD) && (p_ptr->melee_style != SKILL_MASTERY)))
+ return (FALSE);
+
+ /* Check for a usable slot */
+ if (slot >= INVEN_WIELD) return (TRUE);
+
+ /* Assume not wearable */
+ return (FALSE);
+}
+
+
+bool_ is_slot_ok(int slot)
+{
+ if ((slot >= INVEN_WIELD) && (slot < INVEN_TOTAL))
+ {
+ return (TRUE);
+ }
+ else
+ {
+ return (FALSE);
+ }
+}
+
+
+/*
+ * Wield or wear a single item from the pack or floor
+ */
+void do_cmd_wield(void)
+{
+ int item, slot, num = 1;
+
+ object_type forge;
+
+ object_type *q_ptr;
+
+ object_type *o_ptr, *i_ptr;
+
+ cptr act;
+
+ char o_name[80];
+
+ cptr q, s;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Restrict the choices */
+ item_tester_hook = item_tester_hook_wear;
+
+ /* Get an item */
+ q = "Wear/Wield which item? ";
+ s = "You have nothing you can wear or wield.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Check the slot */
+ slot = wield_slot(o_ptr);
+
+ /* Prevent wielding into a cursed slot */
+ if (cursed_p(&p_ptr->inventory[slot]))
+ {
+ /* Describe it */
+ object_desc(o_name, &p_ptr->inventory[slot], FALSE, 0);
+
+ /* Message */
+ msg_format("The %s you are %s appears to be cursed.",
+ o_name, describe_use(slot));
+
+ /* Cancel the command */
+ return;
+ }
+
+ if ((cursed_p(o_ptr)) && (wear_confirm)
+ && (object_known_p(o_ptr) || (o_ptr->ident & (IDENT_SENSE))))
+ {
+ char dummy[512];
+
+ /* Describe it */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ strnfmt(dummy, 512, "Really use the %s {cursed}? ", o_name);
+ if (!(get_check(dummy)))
+ return;
+ }
+
+ /* Can we wield */
+ if (process_hooks(HOOK_WIELD, "(d)", item)) return;
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Two handed weapons can't be wielded with a shield */
+ if ((is_slot_ok(slot - INVEN_WIELD + INVEN_ARM)) &&
+ (f4 & TR4_MUST2H) &&
+ (p_ptr->inventory[slot - INVEN_WIELD + INVEN_ARM].k_idx != 0))
+ {
+ object_desc(o_name, o_ptr, FALSE, 0);
+ msg_format("You cannot wield your %s with a shield.", o_name);
+ return;
+ }
+
+ if (is_slot_ok(slot - INVEN_ARM + INVEN_WIELD))
+ {
+ i_ptr = &p_ptr->inventory[slot - INVEN_ARM + INVEN_WIELD];
+
+ /* Extract the flags */
+ object_flags(i_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Prevent shield from being put on if wielding 2H */
+ if ((f4 & TR4_MUST2H) && (i_ptr->k_idx) &&
+ (p_ptr->body_parts[slot - INVEN_WIELD] == INVEN_ARM))
+ {
+ object_desc(o_name, o_ptr, FALSE, 0);
+ msg_format("You cannot wield your %s with a two-handed weapon.", o_name);
+ return;
+ }
+
+ if ((p_ptr->body_parts[slot - INVEN_WIELD] == INVEN_ARM) &&
+ (f4 & TR4_COULD2H))
+ {
+ if (!get_check("Are you sure you want to restrict your fighting? "))
+ {
+ return;
+ }
+ }
+ }
+
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if ((is_slot_ok(slot - INVEN_WIELD + INVEN_ARM)) &&
+ (p_ptr->inventory[slot - INVEN_WIELD + INVEN_ARM].k_idx != 0) &&
+ (f4 & TR4_COULD2H))
+ {
+ if (!get_check("Are you sure you want to use this weapon with a shield?"))
+ {
+ return;
+ }
+ }
+
+ /* Can we take off existing item */
+ if (slot != INVEN_AMMO)
+ {
+ if (p_ptr->inventory[slot].k_idx)
+ if (process_hooks(HOOK_TAKEOFF, "(d)", slot)) return;
+ }
+ else
+ {
+ if (p_ptr->inventory[slot].k_idx)
+ if (!object_similar(&p_ptr->inventory[slot], o_ptr))
+ if (process_hooks(HOOK_TAKEOFF, "(d)", slot)) return;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Obtain local object */
+ object_copy(q_ptr, o_ptr);
+
+ if (slot == INVEN_AMMO) num = o_ptr->number;
+
+ /* Modify quantity */
+ q_ptr->number = num;
+
+ /* Decrease the item */
+ inc_stack_size_ex(item, -num, OPTIMIZE, NO_DESCRIBE);
+
+ /* Access the wield slot */
+ o_ptr = &p_ptr->inventory[slot];
+
+ /* Take off existing item */
+ if (slot != INVEN_AMMO)
+ {
+ if (o_ptr->k_idx)
+ {
+ /* Take off existing item */
+ (void)inven_takeoff(slot, 255, FALSE);
+ }
+ }
+ else
+ {
+ if (o_ptr->k_idx)
+ {
+ if (!object_similar(o_ptr, q_ptr))
+ {
+ /* Take off existing item */
+ (void)inven_takeoff(slot, 255, FALSE);
+ }
+ else
+ {
+ q_ptr->number += o_ptr->number;
+ }
+ }
+ }
+
+
+ /* Wear the new stuff */
+ object_copy(o_ptr, q_ptr);
+
+ /* Increment the equip counter by hand */
+ equip_cnt++;
+
+ /* Where is the item now */
+ if (slot == INVEN_WIELD)
+ {
+ act = "You are wielding";
+ }
+ else if (( slot == INVEN_BOW ) && (o_ptr->tval == TV_INSTRUMENT))
+ {
+ act = "You are holding";
+ }
+ else if (slot == INVEN_BOW)
+ {
+ act = "You are shooting with";
+ }
+ else if (slot == INVEN_LITE)
+ {
+ act = "Your light source is";
+ }
+ else if (slot == INVEN_AMMO)
+ {
+ act = "In your quiver you have";
+ }
+ else if (slot == INVEN_TOOL)
+ {
+ act = "You are using";
+ }
+ else
+ {
+ act = "You are wearing";
+ }
+
+ /* Describe the result */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("%s %s (%c).", act, o_name, index_to_label(slot));
+
+ /* Cursed! */
+ if (cursed_p(o_ptr))
+ {
+ /* Warn the player */
+ msg_print("Oops! It feels deathly cold!");
+
+ /* Note the curse */
+ o_ptr->ident |= (IDENT_SENSE);
+ o_ptr->sense = SENSE_CURSED;
+ }
+
+ /* Take care of item sets */
+ if (o_ptr->name1)
+ {
+ wield_set(o_ptr->name1, a_info[o_ptr->name1].set, FALSE);
+ }
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Recalculate torch */
+ p_ptr->update |= (PU_TORCH);
+
+ /* Recalculate hitpoint */
+ p_ptr->update |= (PU_HP);
+
+ /* Recalculate mana */
+ p_ptr->update |= (PU_MANA | PU_SPELLS);
+
+ /* Redraw monster hitpoint */
+ p_ptr->redraw |= (PR_MH);
+
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+}
+
+
+
+/*
+ * Take off an item
+ */
+void do_cmd_takeoff(void)
+{
+ int item;
+
+ object_type *o_ptr;
+
+ cptr q, s;
+
+
+ /* Get an item */
+ q = "Take off which item? ";
+ s = "You are not wearing anything to take off.";
+ if (!get_item(&item, q, s, (USE_EQUIP))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Can we take it off */
+ if (process_hooks(HOOK_TAKEOFF, "(d)", item)) return;
+
+ /* Item is cursed */
+ if (cursed_p(o_ptr) && (!wizard))
+ {
+ /* Oops */
+ msg_print("Hmmm, it seems to be cursed.");
+
+ /* Nope */
+ return;
+ }
+
+
+ /* Take a partial turn */
+ energy_use = 50;
+
+ /* Take off the item */
+ (void)inven_takeoff(item, 255, FALSE);
+
+ /* Recalculate hitpoint */
+ p_ptr->update |= (PU_HP);
+
+ p_ptr->redraw |= (PR_MH);
+}
+
+
+/*
+ * Drop an item
+ */
+void do_cmd_drop(void)
+{
+ int item, amt = 1;
+
+ object_type *o_ptr;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ cptr q, s;
+
+
+ /* Get an item */
+ q = "Drop which item? ";
+ s = "You have nothing to drop.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Can we drop */
+ if (process_hooks(HOOK_DROP, "(d)", item)) return;
+
+ /* Hack -- Cannot remove cursed items */
+ if (cursed_p(o_ptr))
+ {
+ if (item >= INVEN_WIELD)
+ {
+ /* Oops */
+ msg_print("Hmmm, it seems to be cursed.");
+
+ /* Nope */
+ return;
+ }
+ else
+ {
+ if (f4 & TR4_CURSE_NO_DROP)
+ {
+ /* Oops */
+ msg_print("Hmmm, you seem to be unable to drop it.");
+
+ /* Nope */
+ return;
+ }
+ }
+ }
+
+
+ /* See how many items */
+ if (o_ptr->number > 1)
+ {
+ /* Get a quantity */
+ amt = get_quantity(NULL, o_ptr->number);
+
+ /* Allow user abort */
+ if (amt <= 0) return;
+ }
+
+ /* Take a partial turn */
+ energy_use = 50;
+
+ /* Drop (some of) the item */
+ inven_drop(item, amt, p_ptr->py, p_ptr->px, FALSE);
+}
+
+
+/*
+ * Destroy an item
+ */
+void do_cmd_destroy(void)
+{
+ int item, amt = 1;
+
+ int old_number;
+
+ bool_ force = FALSE;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ char out_val[160];
+
+ cptr q, s;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Hack -- force destruction */
+ if (command_arg > 0) force = TRUE;
+
+
+ /* Get an item */
+ q = "Destroy which item? ";
+ s = "You have nothing to destroy.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_AUTO))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+
+ /* See how many items */
+ if (o_ptr->number > 1)
+ {
+ /* Get a quantity */
+ amt = get_quantity(NULL, o_ptr->number);
+
+ /* Allow user abort */
+ if (amt <= 0) return;
+ }
+
+
+ /* Describe the object */
+ old_number = o_ptr->number;
+ o_ptr->number = amt;
+ object_desc(o_name, o_ptr, TRUE, 3);
+ o_ptr->number = old_number;
+
+ /* Verify unless quantity given */
+ if (!force)
+ {
+ if (!((auto_destroy) && (object_value(o_ptr) < 1)))
+ {
+ /* Make a verification */
+ strnfmt(out_val, 160, "Really destroy %s? ", o_name);
+ if (!get_check(out_val)) return;
+ }
+ }
+
+ /* Take no time, just like the automatizer */
+ energy_use = 0;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if ((f4 & TR4_CURSE_NO_DROP) && cursed_p(o_ptr))
+ {
+ /* Oops */
+ msg_print("Hmmm, you seem to be unable to destroy it.");
+
+ /* Nope */
+ return;
+ }
+
+
+ /* Artifacts cannot be destroyed */
+ if (artifact_p(o_ptr) || o_ptr->art_name)
+ {
+ byte feel = SENSE_SPECIAL;
+
+ energy_use = 0;
+
+ /* Message */
+ msg_format("You cannot destroy %s.", o_name);
+
+ /* Hack -- Handle icky artifacts */
+ if (cursed_p(o_ptr)) feel = SENSE_TERRIBLE;
+
+ /* Hack -- inscribe the artifact */
+ o_ptr->sense = feel;
+
+ /* We have "felt" it (again) */
+ o_ptr->ident |= (IDENT_SENSE);
+
+ /* Combine the pack */
+ p_ptr->notice |= (PN_COMBINE);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Done */
+ return;
+ }
+
+ /* Message */
+ msg_format("You destroy %s.", o_name);
+ sound(SOUND_DESTITEM);
+
+ /* Create an automatizer rule */
+ if (automatizer_create)
+ {
+ automatizer_add_rule(o_ptr, TRUE);
+ }
+
+ /*
+ * Hack -- If rods or wand are destroyed, the total maximum timeout or
+ * charges of the stack needs to be reduced, unless all the items are
+ * being destroyed. -LM-
+ */
+ if ((o_ptr->tval == TV_WAND) && (amt < o_ptr->number))
+ {
+ o_ptr->pval -= o_ptr->pval * amt / o_ptr->number;
+ }
+
+ /* Eru wont be happy */
+ if (f3 & TR3_BLESSED)
+ inc_piety(GOD_ERU, -10 * k_info[o_ptr->k_idx].level);
+
+ /* Eliminate the item */
+ inc_stack_size(item, -amt);
+}
+
+
+/*
+ * Observe an item which has been *identify*-ed
+ */
+void do_cmd_observe(void)
+{
+ int item;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ cptr q, s;
+
+
+ /* Get an item */
+ q = "Examine which item? ";
+ s = "You have nothing to examine.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Describe */
+ cmsg_format(TERM_L_BLUE, "%s", o_name);
+
+ /* Describe it fully */
+ if (!object_out_desc(o_ptr, NULL, FALSE, TRUE)) msg_print("You see nothing special.");
+}
+
+
+
+/*
+ * Remove the inscription from an object
+ * XXX Mention item (when done)?
+ */
+void do_cmd_uninscribe(void)
+{
+ int item;
+
+ object_type *o_ptr;
+
+ cptr q, s;
+
+
+ /* Get an item */
+ q = "Un-inscribe which item? ";
+ s = "You have nothing to un-inscribe.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Nothing to remove */
+ if (!o_ptr->note)
+ {
+ msg_print("That item had no inscription to remove.");
+ return;
+ }
+
+ /* Message */
+ msg_print("Inscription removed.");
+
+ /* Remove the incription */
+ o_ptr->note = 0;
+
+ /* Combine the pack */
+ p_ptr->notice |= (PN_COMBINE);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+}
+
+
+/*
+ * Inscribe an object with a comment
+ */
+void do_cmd_inscribe(void)
+{
+ int item;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ char out_val[80];
+
+ cptr q, s;
+
+
+ /* Get an item */
+ q = "Inscribe which item? ";
+ s = "You have nothing to inscribe.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Describe the activity */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("Inscribing %s.", o_name);
+ msg_print(NULL);
+
+ /* Start with nothing */
+ strcpy(out_val, "");
+
+ /* Use old inscription */
+ if (o_ptr->note)
+ {
+ /* Start with the old inscription */
+ strcpy(out_val, quark_str(o_ptr->note));
+ }
+
+ /* Get a new inscription (possibly empty) */
+ if (get_string("Inscription: ", out_val, 80))
+ {
+ /* Save the inscription */
+ o_ptr->note = quark_add(out_val);
+
+ /* Combine the pack */
+ p_ptr->notice |= (PN_COMBINE);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+ }
+}
+
+
+
+/*
+ * An "item_tester_hook" for refilling lanterns
+ */
+static bool_ item_tester_refill_lantern(object_type *o_ptr)
+{
+ /* Flasks of oil are okay */
+ if (o_ptr->tval == TV_FLASK) return (TRUE);
+
+ /* Lanterns are okay */
+ if ((o_ptr->tval == TV_LITE) &&
+ (o_ptr->sval == SV_LITE_LANTERN)) return (TRUE);
+
+ /* Assume not okay */
+ return (FALSE);
+}
+
+
+/*
+ * Refill the players lamp (from the pack or floor)
+ */
+static void do_cmd_refill_lamp(void)
+{
+ int item;
+
+ object_type *o_ptr;
+ object_type *j_ptr;
+
+ cptr q, s;
+
+
+ /* Restrict the choices */
+ item_tester_hook = item_tester_refill_lantern;
+
+ /* Get an item */
+ q = "Refill with which flask? ";
+ s = "You have no flasks of oil.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Take a partial turn */
+ energy_use = 50;
+
+ /* Access the lantern */
+ j_ptr = &p_ptr->inventory[INVEN_LITE];
+
+ /* Refuel */
+ if (o_ptr->tval == TV_FLASK)
+ j_ptr->timeout += o_ptr->pval;
+ else
+ j_ptr->timeout += o_ptr->timeout;
+
+ /* Message */
+ msg_print("You fuel your lamp.");
+
+ /* Comment */
+ if (j_ptr->timeout >= FUEL_LAMP)
+ {
+ j_ptr->timeout = FUEL_LAMP;
+ msg_print("Your lamp is full.");
+ }
+
+ /* Decrease the item stack */
+ inc_stack_size(item, -1);
+
+ /* Recalculate torch */
+ p_ptr->update |= (PU_TORCH);
+}
+
+
+/*
+ * An "item_tester_hook" for refilling torches
+ */
+static bool_ item_tester_refill_torch(object_type *o_ptr)
+{
+ /* Torches are okay */
+ if ((o_ptr->tval == TV_LITE) &&
+ (o_ptr->sval == SV_LITE_TORCH)) return (TRUE);
+
+ /* Assume not okay */
+ return (FALSE);
+}
+
+
+/*
+ * Refuel the players torch (from the pack or floor)
+ */
+static void do_cmd_refill_torch(void)
+{
+ int item;
+
+ object_type *o_ptr;
+
+ object_type *j_ptr;
+
+ cptr q, s;
+
+
+ /* Restrict the choices */
+ item_tester_hook = item_tester_refill_torch;
+
+ /* Get an item */
+ q = "Refuel with which torch? ";
+ s = "You have no extra torches.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Take a partial turn */
+ energy_use = 50;
+
+ /* Access the primary torch */
+ j_ptr = &p_ptr->inventory[INVEN_LITE];
+
+ /* Refuel */
+ j_ptr->timeout += o_ptr->timeout + 5;
+
+ /* Message */
+ msg_print("You combine the torches.");
+
+ /* Over-fuel message */
+ if (j_ptr->timeout >= FUEL_TORCH)
+ {
+ j_ptr->timeout = FUEL_TORCH;
+ msg_print("Your torch is fully fueled.");
+ }
+
+ /* Refuel message */
+ else
+ {
+ msg_print("Your torch glows more brightly.");
+ }
+
+ /* Decrease the item stack */
+ inc_stack_size(item, -1);
+
+ /* Recalculate torch */
+ p_ptr->update |= (PU_TORCH);
+}
+
+
+/*
+ * Refill the players lamp, or restock his torches
+ */
+void do_cmd_refill(void)
+{
+ object_type *o_ptr;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Get the light */
+ o_ptr = &p_ptr->inventory[INVEN_LITE];
+
+ /* It is nothing */
+ if (o_ptr->tval != TV_LITE)
+ {
+ msg_print("You are not wielding a light.");
+ return;
+ }
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (f4 & TR4_FUEL_LITE)
+ {
+ /* It's a torch */
+ if (o_ptr->sval == SV_LITE_TORCH ||
+ o_ptr->sval == SV_LITE_TORCH_EVER)
+ {
+ do_cmd_refill_torch();
+ }
+
+ /* It's a lamp */
+ else if (o_ptr->sval == SV_LITE_LANTERN ||
+ o_ptr->sval == SV_LITE_DWARVEN ||
+ o_ptr->sval == SV_LITE_FEANORIAN)
+ {
+ do_cmd_refill_lamp();
+ }
+ }
+
+ /* No torch to refill */
+ else
+ {
+ msg_print("Your light cannot be refilled.");
+ }
+}
+
+
+/*
+ * Target command
+ */
+void do_cmd_target(void)
+{
+ /* Target set */
+ if (target_set(TARGET_KILL))
+ {
+ msg_print("Target Selected.");
+ }
+
+ /* Target aborted */
+ else
+ {
+ msg_print("Target Aborted.");
+ }
+}
+
+
+
+/*
+ * Look command
+ */
+void do_cmd_look(void)
+{
+ /* Look around */
+ if (target_set(TARGET_LOOK))
+ {
+ msg_print("Target Selected.");
+ }
+}
+
+
+
+/*
+ * Allow the player to examine other sectors on the map
+ */
+void do_cmd_locate(void)
+{
+ int dir, y1, x1, y2, x2;
+ int panel_hgt, panel_wid;
+ char tmp_val[80];
+ char out_val[160];
+
+
+ /* Retrieve size of the Angband window */
+ Term_get_size(&panel_wid, &panel_hgt);
+
+ /* Calcurate size of the dungeon map area */
+ panel_hgt = (panel_hgt - (ROW_MAP + 1)) / 2;
+ panel_wid = (panel_wid - (COL_MAP + 1)) / 2;
+
+ /* Start at current panel */
+ y2 = y1 = panel_row_min;
+ x2 = x1 = panel_col_min;
+
+ /* Show panels until done */
+ while (1)
+ {
+ /* Describe the location */
+ if ((y2 == y1) && (x2 == x1))
+ {
+ tmp_val[0] = '\0';
+ }
+ else
+ {
+ strnfmt(tmp_val, 80, "%s%s of",
+ ((y2 < y1) ? " North" : (y2 > y1) ? " South" : ""),
+ ((x2 < x1) ? " West" : (x2 > x1) ? " East" : ""));
+ }
+
+ /* Prepare to ask which way to look */
+ if ((panel_hgt == PANEL_HGT) && (panel_wid == PANEL_WID))
+ {
+ /* Avoid surprising the standard screen users */
+ strnfmt(out_val, 160,
+ "Map sector [%d,%d], which is%s your sector. Direction?",
+ y2 / panel_hgt, x2 / panel_wid, tmp_val);
+ }
+
+ /* Big screen */
+ else
+ {
+ /* Panels are measured by current map area size */
+ strnfmt(out_val, 160,
+ "Map sector [%d(%02d),%d(%02d)], which is%s your sector. Direction?",
+ y2 / panel_hgt, y2 % panel_hgt,
+ x2 / panel_wid, x2 % panel_wid, tmp_val);
+ }
+
+ /* Assume no direction */
+ dir = 0;
+
+ /* Get a direction */
+ while (!dir)
+ {
+ char ch;
+
+ /* Get a command (or cancel) */
+ if (!get_com(out_val, &ch)) break;
+
+ /* Extract the action (if any) */
+ dir = get_keymap_dir(ch);
+
+ /* Error */
+ if (!dir) bell();
+ }
+
+ /* No direction */
+ if (!dir) break;
+
+ /* Apply the motion */
+ if (change_panel(ddy[dir], ddx[dir]))
+ {
+ y2 = panel_row_min;
+ x2 = panel_col_min;
+ }
+ }
+
+ /* Recenter the map around the player */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff */
+ handle_stuff();
+}
+
+
+
+
+
+
+/*
+ * The table of "symbol info" -- each entry is a string of the form
+ * "X:desc" where "X" is the trigger, and "desc" is the "info".
+ */
+static cptr ident_info[] =
+{
+ " :A dark grid",
+ "!:A potion (or oil)",
+ "\":An amulet (or necklace)",
+ "#:A wall (or secret door)",
+ "$:Treasure (gold or gems)",
+ "%:A vein (magma or quartz)",
+ /* "&:unused", */
+ "':An open door",
+ "(:Soft armor",
+ "):A shield",
+ "*:A vein with treasure",
+ "+:A closed door",
+ ",:Food (or mushroom patch)",
+ "-:A wand (or rod)",
+ ".:Floor",
+ "/:A polearm (Axe/Pike/etc)",
+ "0:An altar",
+ "1:Entrance to General Store",
+ "2:Entrance to Armory",
+ "3:Entrance to Weaponsmith",
+ "4:Entrance to Temple",
+ "5:Entrance to Alchemy shop",
+ "6:Entrance to Magic store",
+ "7:Entrance to Black Market",
+ "8:Entrance to your home",
+ "9:Entrance to Bookstore",
+ "::Rubble",
+ ";:A glyph of warding / explosive rune",
+ "<:An up staircase",
+ "=:A ring",
+ ">:A down staircase",
+ "?:A scroll",
+ "@:You",
+ "A:Angel",
+ "B:Bird",
+ "C:Canine",
+ "D:Ancient Dragon/Wyrm",
+ "E:Elemental",
+ "F:Dragon Fly",
+ "G:Ghost",
+ "H:Hybrid",
+ "I:Insect",
+ "J:Snake",
+ "K:Killer Beetle",
+ "L:Lich",
+ "M:Multi-Headed Reptile",
+ /* "N:unused", */
+ "O:Ogre",
+ "P:Giant Humanoid",
+ "Q:Quylthulg (Pulsing Flesh Mound)",
+ "R:Reptile/Amphibian",
+ "S:Spider/Scorpion/Tick",
+ "T:Troll",
+ "U:Major Demon",
+ "V:Vampire",
+ "W:Wight/Wraith/etc",
+ "X:Xorn/Xaren/etc",
+ "Y:Yeti",
+ "Z:Zephyr Hound",
+ "[:Hard armor",
+ "\\:A hafted weapon (mace/whip/etc)",
+ "]:Misc. armor",
+ "^:A trap",
+ "_:A staff",
+ /* "`:unused", */
+ "a:Ant",
+ "b:Bat",
+ "c:Centipede",
+ "d:Dragon",
+ "e:Floating Eye",
+ "f:Feline",
+ "g:Golem",
+ "h:Hobbit/Elf/Dwarf",
+ "i:Icky Thing",
+ "j:Jelly",
+ "k:Kobold",
+ "l:Louse",
+ "m:Mold",
+ "n:Naga",
+ "o:Orc",
+ "p:Person/Human",
+ "q:Quadruped",
+ "r:Rodent",
+ "s:Skeleton",
+ "t:Townsperson",
+ "u:Minor Demon",
+ "v:Vortex",
+ "w:Worm/Worm-Mass",
+ /* "x:unused", */
+ "y:Yeek",
+ "z:Zombie/Mummy",
+ "{:A missile (arrow/bolt/shot)",
+ "|:An edged weapon (sword/dagger/etc)",
+ "}:A launcher (bow/crossbow/sling)",
+ "~:A tool (or miscellaneous item)",
+ NULL
+};
+
+
+
+/*
+ * Sorting hook -- Comp function -- see below
+ *
+ * We use "u" to point to array of monster indexes,
+ * and "v" to select the type of sorting to perform on "u".
+ */
+static bool_ ang_sort_comp_hook(vptr u, vptr v, int a, int b)
+{
+ u16b *who = (u16b*)(u);
+
+ u16b *why = (u16b*)(v);
+
+ int w1 = who[a];
+
+ int w2 = who[b];
+
+ int z1, z2;
+
+
+ /* Sort by player kills */
+ if (*why >= 4)
+ {
+ /* Extract player kills */
+ z1 = r_info[w1].r_pkills;
+ z2 = r_info[w2].r_pkills;
+
+ /* Compare player kills */
+ if (z1 < z2) return (TRUE);
+ if (z1 > z2) return (FALSE);
+ }
+
+
+ /* Sort by total kills */
+ if (*why >= 3)
+ {
+ /* Extract total kills */
+ z1 = r_info[w1].r_tkills;
+ z2 = r_info[w2].r_tkills;
+
+ /* Compare total kills */
+ if (z1 < z2) return (TRUE);
+ if (z1 > z2) return (FALSE);
+ }
+
+
+ /* Sort by monster level */
+ if (*why >= 2)
+ {
+ /* Extract levels */
+ z1 = r_info[w1].level;
+ z2 = r_info[w2].level;
+
+ /* Compare levels */
+ if (z1 < z2) return (TRUE);
+ if (z1 > z2) return (FALSE);
+ }
+
+
+ /* Sort by monster experience */
+ if (*why >= 1)
+ {
+ /* Extract experience */
+ z1 = r_info[w1].mexp;
+ z2 = r_info[w2].mexp;
+
+ /* Compare experience */
+ if (z1 < z2) return (TRUE);
+ if (z1 > z2) return (FALSE);
+ }
+
+
+ /* Compare indexes */
+ return (w1 <= w2);
+}
+
+
+/*
+ * Sorting hook -- Swap function -- see below
+ *
+ * We use "u" to point to array of monster indexes,
+ * and "v" to select the type of sorting to perform.
+ */
+static void ang_sort_swap_hook(vptr u, vptr v, int a, int b)
+{
+ u16b *who = (u16b*)(u);
+
+ u16b holder;
+
+
+ /* XXX XXX */
+ v = v ? v : 0;
+
+ /* Swap */
+ holder = who[a];
+ who[a] = who[b];
+ who[b] = holder;
+}
+
+
+
+/*
+ * Hack -- Display the "name" and "attr/chars" of a monster race
+ */
+static void roff_top(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ byte a1, a2;
+
+ char c1, c2;
+
+
+ /* Access the chars */
+ c1 = r_ptr->d_char;
+ c2 = r_ptr->x_char;
+
+ /* Access the attrs */
+ a1 = r_ptr->d_attr;
+ a2 = r_ptr->x_attr;
+
+
+ /* Clear the top line */
+ Term_erase(0, 0, 255);
+
+ /* Reset the cursor */
+ Term_gotoxy(0, 0);
+
+ /* A title (use "The" for non-uniques) */
+ if (!(r_ptr->flags1 & (RF1_UNIQUE)))
+ {
+ Term_addstr( -1, TERM_WHITE, "The ");
+ }
+
+ /* Dump the name */
+ Term_addstr( -1, TERM_WHITE, (r_name + r_ptr->name));
+
+ /* Append the "standard" attr/char info */
+ Term_addstr( -1, TERM_WHITE, " ('");
+ Term_addch(a1, c1);
+ if (use_bigtile && (a1 & 0x80)) Term_addch(255, 255);
+ Term_addstr( -1, TERM_WHITE, "')");
+
+ /* Append the "optional" attr/char info */
+ Term_addstr( -1, TERM_WHITE, "/('");
+ Term_addch(a2, c2);
+ if (use_bigtile && (a2 & 0x80)) Term_addch(255, 255);
+ Term_addstr( -1, TERM_WHITE, "'):");
+}
+
+
+/*
+ * Identify a character, allow recall of monsters
+ *
+ * Several "special" responses recall "multiple" monsters:
+ * ^A (all monsters)
+ * ^U (all unique monsters)
+ * ^N (all non-unique monsters)
+ * ^M (case insensitive name search)
+ *
+ * The responses may be sorted in several ways, see below.
+ *
+ * Note that the player ghosts are ignored. XXX XXX XXX
+ */
+void do_cmd_query_symbol(void)
+{
+ int i, n, r_idx;
+
+ char sym, query;
+
+ char buf[128];
+
+
+ bool_ all = FALSE;
+
+ bool_ uniq = FALSE;
+
+ bool_ norm = FALSE;
+
+
+ bool_ name = FALSE;
+
+ char temp[80] = "";
+
+
+ bool_ recall = FALSE;
+
+
+ u16b why = 0;
+
+ u16b *who;
+
+
+ /* Get a character, or abort */
+ if (!get_com("Enter character to be identified, "
+ "or (Ctrl-A, Ctrl-U, Ctrl-N, Ctrl-M):", &sym)) return;
+
+ /* Find that character info, and describe it */
+ for (i = 0; ident_info[i]; ++i)
+ {
+ if (sym == ident_info[i][0]) break;
+ }
+
+ /* Describe */
+ if (sym == KTRL('A'))
+ {
+ all = TRUE;
+ strcpy(buf, "Full monster list.");
+ }
+ else if (sym == KTRL('U'))
+ {
+ all = uniq = TRUE;
+ strcpy(buf, "Unique monster list.");
+ }
+ else if (sym == KTRL('N'))
+ {
+ all = norm = TRUE;
+ strcpy(buf, "Non-unique monster list.");
+ }
+ else if (sym == KTRL('M'))
+ {
+ all = name = TRUE;
+ if (!get_string("Name:", temp, 70)) return;
+ strnfmt(buf, 128, "Monsters with a name \"%s\"", temp);
+ strlower(temp);
+ }
+ else if (ident_info[i])
+ {
+ strnfmt(buf, 128, "%c - %s.", sym, ident_info[i] + 2);
+ }
+ else
+ {
+ strnfmt(buf, 128, "%c - %s.", sym, "Unknown Symbol");
+ }
+
+ /* Display the result */
+ prt(buf, 0, 0);
+
+ /* Allocate the "who" array */
+ C_MAKE(who, max_r_idx, u16b);
+
+ /* Collect matching monsters */
+ for (n = 0, i = 1; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ /* Nothing to recall */
+ if (!cheat_know && !r_ptr->r_sights) continue;
+
+ /* Require non-unique monsters if needed */
+ if (norm && (r_ptr->flags1 & (RF1_UNIQUE))) continue;
+
+ /* Require unique monsters if needed */
+ if (uniq && !(r_ptr->flags1 & (RF1_UNIQUE))) continue;
+
+ /* Require monsters with the name requested if needed */
+ if (name)
+ {
+ char mon_name[80];
+
+ strcpy(mon_name, r_name + r_ptr->name);
+ strlower(mon_name);
+
+ if (!strstr(mon_name, temp)) continue;
+ }
+
+ /* Collect "appropriate" monsters */
+ if (all || (r_ptr->d_char == sym)) who[n++] = i;
+ }
+
+ /* Nothing to recall */
+ if (!n)
+ {
+ /* Free the "who" array */
+ C_KILL(who, max_r_idx, u16b);
+
+ return;
+ }
+
+
+ /* Prompt XXX XXX XXX */
+ put_str("Recall details? (k/p/y/n): ", 0, 40);
+
+ /* Query */
+ query = inkey();
+
+ /* Restore */
+ prt(buf, 0, 0);
+
+
+ /* Sort by kills (and level) */
+ if (query == 'k')
+ {
+ why = 4;
+ query = 'y';
+ }
+
+ /* Sort by level */
+ if (query == 'p')
+ {
+ why = 2;
+ query = 'y';
+ }
+
+ /* Catch "escape" */
+ if (query != 'y')
+ {
+ /* Free the "who" array */
+ C_KILL(who, max_r_idx, u16b);
+
+ return;
+ }
+
+
+ /* Sort if needed */
+ if (why)
+ {
+ /* Select the sort method */
+ ang_sort_comp = ang_sort_comp_hook;
+ ang_sort_swap = ang_sort_swap_hook;
+
+ /* Sort the array */
+ ang_sort(who, &why, n);
+ }
+
+
+ /* Start at the end */
+ i = n - 1;
+
+ /* Scan the monster memory */
+ while (1)
+ {
+ /* Extract a race */
+ r_idx = who[i];
+
+ /* Hack -- Auto-recall */
+ monster_race_track(r_idx, 0);
+
+ /* Hack -- Handle stuff */
+ handle_stuff();
+
+ /* Hack -- Begin the prompt */
+ roff_top(r_idx);
+
+ /* Hack -- Complete the prompt */
+ Term_addstr( -1, TERM_WHITE, " [(r)ecall, ESC]");
+
+ /* Interact */
+ while (1)
+ {
+ /* Recall */
+ if (recall)
+ {
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Recall on screen */
+ screen_roff(who[i], 0, 0);
+
+ /* Hack -- Complete the prompt (again) */
+ Term_addstr( -1, TERM_WHITE, " [(r)ecall, ESC]");
+ }
+
+ /* Command */
+ query = inkey();
+
+ /* Unrecall */
+ if (recall)
+ {
+ /* Restore */
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Normal commands */
+ if (query != 'r') break;
+
+ /* Toggle recall */
+ recall = !recall;
+ }
+
+ /* Stop scanning */
+ if (query == ESCAPE) break;
+
+ /* Move to "prev" monster */
+ if (query == '-')
+ {
+ if (++i == n)
+ {
+ i = 0;
+ if (!expand_list) break;
+ }
+ }
+
+ /* Move to "next" monster */
+ else
+ {
+ if (i-- == 0)
+ {
+ i = n - 1;
+ if (!expand_list) break;
+ }
+ }
+ }
+
+ /* Re-display the identity */
+ prt(buf, 0, 0);
+
+ /* Free the "who" array */
+ C_KILL(who, max_r_idx, u16b);
+}
+
+
+/*
+ * research_mon
+ * -KMW-
+ */
+bool_ research_mon()
+{
+ int i, n, r_idx;
+
+ char sym, query;
+
+ char buf[128];
+
+
+ s16b oldkills;
+
+ byte oldwake;
+
+ bool_ oldcheat;
+
+
+ bool_ all = FALSE;
+
+ bool_ uniq = FALSE;
+
+ bool_ norm = FALSE;
+
+ bool_ notpicked;
+
+
+ bool_ recall = FALSE;
+
+ u16b why = 0;
+
+ monster_race *r2_ptr;
+
+ u16b *who;
+
+
+ /* Hack -- Remember "cheat_know" flag */
+ oldcheat = cheat_know;
+
+
+ /* Get a character, or abort */
+ if (!get_com("Enter character of monster: ", &sym)) return (TRUE);
+
+ /* Allocate the "who" array */
+ C_MAKE(who, max_r_idx, u16b);
+
+ /* Find that character info, and describe it */
+ for (i = 0; ident_info[i]; ++i)
+ {
+ if (sym == ident_info[i][0]) break;
+ }
+
+ if (ident_info[i])
+ {
+ strnfmt(buf, 128, "%c - %s.", sym, ident_info[i] + 2);
+ }
+ else
+ {
+ strnfmt(buf, 128, "%c - %s.", sym, "Unknown Symbol");
+ }
+
+ /* Display the result */
+ prt(buf, 16, 10);
+
+
+ /* Collect matching monsters */
+ for (n = 0, i = 1; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ /* Hack -- Force "cheat_know" */
+ cheat_know = TRUE;
+
+ /* Nothing to recall */
+ if (!cheat_know && !r_ptr->r_sights) continue;
+
+ /* Require non-unique monsters if needed */
+ if (norm && (r_ptr->flags1 & (RF1_UNIQUE))) continue;
+
+ /* Require unique monsters if needed */
+ if (uniq && !(r_ptr->flags1 & (RF1_UNIQUE))) continue;
+
+ /* Collect "appropriate" monsters */
+ if (all || (r_ptr->d_char == sym)) who[n++] = i;
+ }
+
+ /* Nothing to recall */
+ if (!n)
+ {
+ /* Free the "who" array */
+ C_KILL(who, max_r_idx, u16b);
+
+ /* Restore the "cheat_know" flag */
+ cheat_know = oldcheat;
+
+ return (TRUE);
+ }
+
+
+ /* Sort by level */
+ why = 2;
+ query = 'y';
+
+ /* Sort if needed */
+ if (why)
+ {
+ /* Select the sort method */
+ ang_sort_comp = ang_sort_comp_hook;
+ ang_sort_swap = ang_sort_swap_hook;
+
+ /* Sort the array */
+ ang_sort(who, &why, n);
+ }
+
+
+ /* Start at the end */
+ i = n - 1;
+
+ notpicked = TRUE;
+
+ /* Scan the monster memory */
+ while (notpicked)
+ {
+ /* Extract a race */
+ r_idx = who[i];
+
+ /* Hack -- Auto-recall */
+ monster_race_track(r_idx, 0);
+
+ /* Hack -- Handle stuff */
+ handle_stuff();
+
+ /* Hack -- Begin the prompt */
+ roff_top(r_idx);
+
+ /* Hack -- Complete the prompt */
+ Term_addstr( -1, TERM_WHITE, " [(r)ecall, ESC, space to continue]");
+
+ /* Interact */
+ while (1)
+ {
+ /* Recall */
+ if (recall)
+ {
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Recall on screen */
+ r2_ptr = &r_info[r_idx];
+
+ oldkills = r2_ptr->r_tkills;
+ oldwake = r2_ptr->r_wake;
+ screen_roff(who[i], 0, 1);
+ r2_ptr->r_tkills = oldkills;
+ r2_ptr->r_wake = oldwake;
+ r2_ptr->r_sights = 1;
+ cheat_know = oldcheat;
+ notpicked = FALSE;
+ break;
+
+ }
+
+ /* Command */
+ query = inkey();
+
+ /* Unrecall */
+ if (recall)
+ {
+ /* Restore */
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Normal commands */
+ if (query != 'r') break;
+
+ /* Toggle recall */
+ recall = !recall;
+ }
+
+ /* Stop scanning */
+ if (query == ESCAPE) break;
+
+ /* Move to "prev" monster */
+ if (query == '-')
+ {
+ if (++i == n)
+ {
+ i = 0;
+ if (!expand_list) break;
+ }
+ }
+
+ /* Move to "next" monster */
+ else
+ {
+ if (i-- == 0)
+ {
+ i = n - 1;
+ if (!expand_list) break;
+ }
+ }
+ }
+
+
+ /* Re-display the identity */
+ /* prt(buf, 5, 5);*/
+
+ /* Free the "who" array */
+ C_KILL(who, max_r_idx, u16b);
+
+ /* Restore the "cheat_know" flag */
+ cheat_know = oldcheat;
+
+ return (notpicked);
+}
+
+
+/*
+ * Try to "sense" the grid's mana
+ */
+bool_ do_cmd_sense_grid_mana()
+{
+ int chance, i;
+
+
+ /* Take (a lot of) time */
+ energy_use = 200;
+
+ /* Base chance of success */
+ chance = p_ptr->skill_dev;
+
+ /* Confusion hurts skill */
+ if (p_ptr->confused) chance = chance / 2;
+
+ /* Hight mana grids are harder */
+ chance = chance - (cave[p_ptr->py][p_ptr->px].mana / 10);
+
+ /* Give everyone a (slight) chance */
+ if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0))
+ {
+ chance = USE_DEVICE;
+ }
+
+ /* Roll for usage */
+ if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE))
+ {
+ if (flush_failure) flush();
+ msg_print("You failed to sense the grid's mana.");
+ sound(SOUND_FAIL);
+ return FALSE;
+ }
+
+ /* Try to give an "average" value */
+ i = (101 - p_ptr->skill_dev) / 2;
+ i = (i < 1) ? 1 : (i > 50) ? 50 : i;
+
+ if (wizard)
+ {
+ msg_format("Grid's mana: %d.", cave[p_ptr->py][p_ptr->px].mana);
+ msg_format("Average grid's mana: %d.", (cave[p_ptr->py][p_ptr->px].mana / i) * i);
+ }
+ else
+ {
+ msg_format("Average Area's mana: %d", (cave[p_ptr->py][p_ptr->px].mana / i) * i);
+ }
+ return TRUE;
+}
+
+
+/*
+ * Calculate the weight of the portable holes
+ */
+s32b portable_hole_weight(void)
+{
+ s32b weight, i;
+
+ store_type *st_ptr = &town_info[TOWN_RANDOM].store[STORE_HOME];
+
+
+ /* Sum the objects in the appropriate home */
+ for (i = 0, weight = 0; i < st_ptr->stock_num; i++)
+ {
+ object_type *o_ptr = &st_ptr->stock[i];
+
+ weight += (o_ptr->weight * o_ptr->number);
+ }
+
+ /* Multiply the sum with 1.5 */
+ weight = (weight * 3) / 2 + 2;
+
+ return (weight);
+}
+
+
+/*
+ * Calculate and set the weight of the portable holes
+ */
+void set_portable_hole_weight(void)
+{
+ s32b weight, i, j;
+
+ /* Calculate the weight of items in home */
+ weight = portable_hole_weight();
+
+ /* Set the weight of portable holes in the shops, ... */
+ for (i = 1; i < max_towns; i++)
+ {
+ for (j = 0; j < max_st_idx; j++)
+ {
+ store_type *st_ptr = &town_info[i].store[j];
+ int k;
+
+ for (k = 0; k < st_ptr->stock_num; k++)
+ {
+ object_type *o_ptr = &st_ptr->stock[k];
+
+ if ((o_ptr->tval == TV_TOOL) &&
+ (o_ptr->sval == SV_PORTABLE_HOLE))
+ o_ptr->weight = weight;
+ }
+ }
+ }
+
+ /* ... in the object list, ... */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ if ((o_ptr->tval == TV_TOOL) &&
+ (o_ptr->sval == SV_PORTABLE_HOLE)) o_ptr->weight = weight;
+ }
+
+ /* ... and in the p_ptr->inventory to the appropriate value */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if ((o_ptr->tval == TV_TOOL) &&
+ (o_ptr->sval == SV_PORTABLE_HOLE)) o_ptr->weight = weight;
+ }
+}
+
+
+/*
+ * Use a portable hole
+ */
+void do_cmd_portable_hole(void)
+{
+ cave_type *c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ int feat, special, town_num;
+
+ /* Is it currently wielded? */
+ if (!p_ptr->inventory[INVEN_TOOL].k_idx ||
+ (p_ptr->inventory[INVEN_TOOL].tval != TV_TOOL) ||
+ (p_ptr->inventory[INVEN_TOOL].sval != SV_PORTABLE_HOLE))
+ {
+ /* No, it isn't */
+ msg_print("You have to wield a portable hole to use your abilities");
+ return;
+ }
+
+ /* Mega-hack: Saving the old values, and then... */
+ feat = c_ptr->feat;
+ special = c_ptr->special;
+ town_num = p_ptr->town_num;
+
+ /* ... change the current grid to the home in town #1 */
+ /* DG -- use the first random town, since random towns cannot have houses */
+ /*
+ * pelpel -- This doesn't affect LoS, so we can manipulate
+ * terrain feature without calling cave_set_feat()
+ */
+ c_ptr->feat = FEAT_SHOP;
+ c_ptr->special = STORE_HOME;
+ p_ptr->town_num = TOWN_RANDOM;
+
+ /* Now use the portable hole */
+ do_cmd_store();
+
+ /* Mega-hack part II: change the current grid to the original value */
+ c_ptr->feat = feat;
+ c_ptr->special = special;
+ p_ptr->town_num = town_num;
+
+ set_portable_hole_weight();
+
+ /* Recalculate bonuses */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ p_ptr->update |= (PU_BONUS);
+}
+
+
+/*
+ * Try to add a CLI action.
+ */
+void cli_add(cptr active, cptr trigger, cptr descr)
+{
+ s16b num;
+ cli_comm *cli_ptr, *old_ptr;
+
+ /* Too many macros. */
+ if (cli_total >= CLI_MAX) return;
+
+ /* First try to read active as a number. */
+ if (strtol(active, 0, 0))
+ {
+ num = strtol(active, 0, 0);
+ }
+ /* Then try to read it as a character. */
+ else if (strlen(active) == 1)
+ {
+ num = active[0];
+ }
+ /* Give up if it doesn't work. */
+ else
+ {
+ return;
+ }
+
+ /* Dump the macro. */
+ cli_ptr = cli_info + cli_total;
+ old_ptr = cli_info + cli_total - 1;
+
+ /*
+ * Trim 's from the ends of a token. This turns '@' into @ and
+ * ''' into '. This may be the intent of the code in tokenize(),
+ * but I've left it for lack of comments to back me up.
+ */
+ if (strchr(trigger, '\''))
+ {
+ char temp[80], *t;
+ cptr s;
+ for (s = trigger, t = temp; ; s++, t++)
+ {
+ /* tokenize() causes each ' to be followed by another character,
+ * and then another '. Trim the 's here. */
+ if (*s == '\'')
+ {
+ *t = *(++s);
+ s++;
+ }
+ else
+ {
+ *t = *s;
+ }
+ if (*t == '\0') break;
+ }
+ cli_ptr->comm = string_make(temp);
+ }
+ else
+ {
+ cli_ptr->comm = string_make(trigger);
+ }
+
+ /* First try copying everything across. */
+ cli_ptr->key = num;
+ cli_ptr->descrip = string_make(descr);
+
+ /* Take description for the previous record if appropriate. */
+ if ((cli_total > 0) && (old_ptr->key == cli_ptr->key) && (cli_ptr->descrip == 0))
+ {
+ cli_ptr->descrip = old_ptr->descrip;
+ }
+
+ /* Accept the macro. */
+ if (cli_ptr->key && cli_ptr->comm && cli_ptr->descrip) cli_total++;
+}
+
+
+
+/*
+ * Get a string using CLI completion.
+ */
+bool_ get_string_cli(cptr prompt, char *buf, int len)
+{
+ bool_ res;
+
+
+ /* Paranoia XXX XXX XXX */
+ msg_print(NULL);
+
+ /* Display prompt */
+ prt(prompt, 0, 0);
+
+ /* Ask the user for a string */
+ askfor_aux_complete = TRUE;
+ res = askfor_aux(buf, len);
+ askfor_aux_complete = FALSE;
+
+ /* Clear prompt */
+ prt("", 0, 0);
+
+ /* Result */
+ return (res);
+}
+
+
+/*
+ * Do a command line command
+ *
+ * This is a wrapper around process command to provide a "reverse keymap"
+ * whereby a set of keypresses is mapped to one.
+ *
+ * This is useful because command_cmd is a s16b, and so allows each command a
+ * unique representation.
+ *
+ * See defines.h for a list of the codes used.
+ */
+void do_cmd_cli(void)
+{
+ char buff[80];
+
+ cli_comm *cli_ptr;
+
+ /* Clear the input buffer */
+ strcpy(buff, "");
+
+ /* Accept command */
+ if (!get_string_cli("Command: ", buff, 30)) return;
+
+
+ /* Analyse the input */
+ for (cli_ptr = cli_info; cli_ptr->comm; cli_ptr++)
+ {
+ if (!strcmp(buff, cli_ptr->comm))
+ {
+ /* Process the command without keymaps or macros. */
+ command_new = cli_ptr->key;
+ return;
+ }
+ }
+
+ msg_format("No such command: %s", buff);
+}
+
+
+/*
+ * Display on-line help for the CLI commands
+ */
+void do_cmd_cli_help()
+{
+ int i, j;
+
+ FILE *fff;
+
+ char file_name[1024];
+
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ for (i = 0, j = -1; i < cli_total; i++)
+ {
+ if (j < i - 1) fprintf(fff, "/");
+ fprintf(fff, "[[[[[G%s]", cli_info[i].comm);
+ if (cli_info[i].descrip != cli_info[i + 1].descrip)
+ {
+ fprintf(fff, " %s\n", cli_info[i].descrip);
+ j = i;
+ }
+ }
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ /* Display the file contents */
+ show_file(file_name, "Command line help", 0, 0);
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+/*
+ * Dump screen shot in HTML
+ */
+void do_cmd_html_dump()
+{
+ char tmp_val[81];
+ bool_ html = TRUE;
+ term_win *save;
+
+ /* Save the screen */
+ save = Term_save_to();
+
+ if (wizard && get_check("WIZARD MODE: Do an help file dump?"))
+ html = FALSE;
+
+ /* Ask for a file */
+ if (html)
+ {
+ strcpy(tmp_val, "dummy.htm");
+ if (!get_string("File(you can post it to http://angband.oook.cz/): ", tmp_val, 80))
+ {
+ /* Now restore the screen to initial state */
+ Term_load_from(save, TRUE);
+ Term_fresh();
+ return;
+ }
+ }
+ else
+ {
+ strcpy(tmp_val, "dummy.txt");
+ if (!get_string("File: ", tmp_val, 80))
+ {
+ /* Now restore the screen to initial state */
+ Term_load_from(save, TRUE);
+ Term_fresh();
+ return;
+ }
+ }
+
+ /* Now restore the screen to dump it */
+ Term_load_from(save, TRUE);
+
+ if (html)
+ html_screenshot(tmp_val);
+ else
+ help_file_screenshot(tmp_val);
+
+ Term_erase(0, 0, 255);
+ msg_print("Dump saved.");
+ Term_fresh();
+ fix_message();
+}
diff --git a/src/cmd4.c b/src/cmd4.c
new file mode 100644
index 00000000..c4440428
--- /dev/null
+++ b/src/cmd4.c
@@ -0,0 +1,4658 @@
+/* File: cmd4.c */
+
+/* Purpose: Interface commands */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Hack -- redraw the screen
+ *
+ * This command performs various low level updates, clears all the "extra"
+ * windows, does a total redraw of the main window, and requests all of the
+ * interesting updates and redraws that I can think of.
+ *
+ * This command is also used to "instantiate" the results of the user
+ * selecting various things, such as graphics mode, so it must call
+ * the "TERM_XTRA_REACT" hook before redrawing the windows.
+ */
+void do_cmd_redraw(void)
+{
+ int j;
+
+ term *old = Term;
+
+
+ /* Hack -- react to changes */
+ Term_xtra(TERM_XTRA_REACT, 0);
+
+
+ /* Combine and Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+
+ /* Update torch */
+ p_ptr->update |= (PU_TORCH);
+
+ /* Update stuff */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_POWERS |
+ PU_SANITY | PU_BODY);
+
+ /* Forget view */
+ p_ptr->update |= (PU_UN_VIEW);
+
+ /* Update view */
+ p_ptr->update |= (PU_VIEW);
+
+ /* Update monster light */
+ p_ptr->update |= (PU_MON_LITE);
+
+ /* Update monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw everything */
+ p_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER | PW_M_LIST);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_MESSAGE | PW_OVERHEAD | PW_MONSTER | PW_OBJECT);
+
+ /* Hack -- update */
+ handle_stuff();
+
+
+ /* Redraw every window */
+ for (j = 0; j < 8; j++)
+ {
+ /* Dead window */
+ if (!angband_term[j]) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Redraw */
+ Term_redraw();
+
+ /* Refresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+
+/*
+ * Hack -- change name
+ */
+void do_cmd_change_name(void)
+{
+ char c;
+
+ int mode = 0;
+
+ char tmp[160];
+
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ /* Forever */
+ while (1)
+ {
+ /* keep mode below 7 */
+ mode = (mode + 6) % 6;
+
+ /* Display the player */
+ display_player(mode);
+
+ /* Prompt */
+ if (mode == 0)
+ {
+ Term_putstr(14, 22, -1, TERM_WHITE,
+ "['t/T' to change tactics, 'e/E' to change movement]");
+ }
+
+ Term_putstr(4, 23, -1, TERM_WHITE,
+ "['c' to change name, 'f' to file, 'p' for previous, 'n' for next, or ESC]");
+
+ /* Query */
+ c = inkey();
+
+ /* Exit */
+ if (c == ESCAPE) break;
+
+ /* Change name */
+ if (c == 'c')
+ {
+ get_name();
+ }
+
+ /* File dump */
+ else if (c == 'f')
+ {
+ strnfmt(tmp, 160, "%s.txt", player_name);
+ if (get_string("Filename(you can post it to http://angband.oook.cz/): ", tmp, 80))
+ {
+ if (tmp[0] && (tmp[0] != ' '))
+ {
+ file_character(tmp, FALSE);
+ }
+ }
+ }
+
+ /* Toggle mode */
+ else if (c == 'n')
+ {
+ mode++;
+ }
+ else if (c == 'p')
+ {
+ mode--;
+ }
+
+ else if (mode == 0)
+ {
+ /* Change tactic */
+ if (c == 't')
+ {
+ (void)do_cmd_change_tactic( -1);
+ }
+ else if (c == 'T')
+ {
+ (void)do_cmd_change_tactic(1);
+ }
+
+ /* Change movement */
+ else if (c == 'e')
+ {
+ do_cmd_change_movement( -1);
+ }
+ else if (c == 'E')
+ {
+ do_cmd_change_movement(1);
+ }
+ else
+ {
+ bell();
+ }
+ }
+ /* Oops */
+ else
+ {
+ bell();
+ }
+
+ /* Flush messages */
+ msg_print(NULL);
+ }
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+
+
+ /* Redraw everything */
+ p_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP);
+
+ handle_stuff();
+}
+
+
+/*
+ * Recall the most recent message
+ */
+void do_cmd_message_one(void)
+{
+ cptr msg = format("> %s", message_str(0));
+
+ /* Recall one message XXX XXX XXX */
+ display_message(0, 0, strlen(msg), message_color(0), msg);
+}
+
+
+/*
+ * Show previous messages to the user -BEN-
+ *
+ * The screen format uses line 0 and (Term->hgt - 1) for headers and prompts,
+ * skips line 1 and (Term->hgt - 2), and uses line 2 thru (Term->hgt - 3) for
+ * old messages.
+ *
+ * This command shows you which commands you are viewing, and allows
+ * you to "search" for strings in the recall.
+ *
+ * Note that messages may be longer than 80 characters, but they are
+ * displayed using "infinite" length, with a special sub-command to
+ * "slide" the virtual display to the left or right.
+ *
+ * Attempt to only hilite the matching portions of the string.
+ *
+ * Now taking advantages of big-screen. -pav-
+ */
+void do_cmd_messages(void)
+{
+ int i, j, k, n;
+ u32b q;
+ int wid, hgt;
+
+ char shower[80];
+ char finder[80];
+
+ /* Wipe finder */
+ strcpy(finder, "");
+
+ /* Wipe shower */
+ strcpy(shower, "");
+
+
+ /* Total messages */
+ n = message_num();
+
+ /* Start on first message */
+ i = 0;
+
+ /* Start at leftmost edge */
+ q = 0;
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ /* Process requests until done */
+ while (1)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Retrieve current screen size */
+ Term_get_size(&wid, &hgt);
+
+ /* Dump up to 20 (or more in bigscreen) lines of messages */
+ for (j = 0; (j < (hgt - 4)) && (i + j < n); j++)
+ {
+ cptr msg = message_str(i + j);
+ byte color = message_color(i + j);
+
+ /* Apply horizontal scroll */
+ msg = (strlen(msg) >= q) ? (msg + q) : "";
+
+ /* Dump the messages, bottom to top */
+ display_message(0, (hgt - 3) - j, strlen(msg), color, msg);
+
+ /* Hilite "shower" */
+ if (shower[0])
+ {
+ cptr str = msg;
+
+ /* Display matches */
+ while ((str = strstr(str, shower)) != NULL)
+ {
+ int len = strlen(shower);
+
+ /* Display the match */
+ Term_putstr(str - msg, (hgt - 3) - j, len, TERM_YELLOW, shower);
+
+ /* Advance */
+ str += len;
+ }
+ }
+ }
+
+ /* Display header XXX XXX XXX */
+ prt(format("Message Recall (%d-%d of %d), Offset %d",
+ i, i + j - 1, n, q), 0, 0);
+
+ /* Display prompt (not very informative) */
+ prt("[Press 'p' for older, 'n' for newer, ..., or ESCAPE]", hgt - 1, 0);
+
+ /* Get a command */
+ k = inkey();
+
+ /* Exit on Escape */
+ if (k == ESCAPE) break;
+
+ /* Hack -- Save the old index */
+ j = i;
+
+ /* Horizontal scroll */
+ if (k == '4')
+ {
+ /* Scroll left */
+ q = (q >= ((u32b)wid / 2)) ? (q - wid / 2) : 0;
+
+ /* Success */
+ continue;
+ }
+
+ /* Horizontal scroll */
+ if (k == '6')
+ {
+ /* Scroll right */
+ q = q + wid / 2;
+
+ /* Success */
+ continue;
+ }
+
+ /* Hack -- handle show */
+ if (k == '=')
+ {
+ /* Prompt */
+ prt("Show: ", hgt - 1, 0);
+
+ /* Get a "shower" string, or continue */
+ if (!askfor_aux(shower, 80)) continue;
+
+ /* Okay */
+ continue;
+ }
+
+ /* Hack -- handle find */
+ if (k == '/')
+ {
+ s16b z;
+
+ /* Prompt */
+ prt("Find: ", hgt - 1, 0);
+
+ /* Get a "finder" string, or continue */
+ if (!askfor_aux(finder, 80)) continue;
+
+ /* Show it */
+ strcpy(shower, finder);
+
+ /* Scan messages */
+ for (z = i + 1; z < n; z++)
+ {
+ cptr msg = message_str(z);
+
+ /* Search for it */
+ if (strstr(msg, finder))
+ {
+ /* New location */
+ i = z;
+
+ /* Done */
+ break;
+ }
+ }
+ }
+
+ /* Recall 1 older message */
+ if ((k == '8') || (k == '\n') || (k == '\r'))
+ {
+ /* Go newer if legal */
+ if (i + 1 < n) i += 1;
+ }
+
+ /* Recall 10 older messages */
+ if (k == '+')
+ {
+ /* Go older if legal */
+ if (i + 10 < n) i += 10;
+ }
+
+ /* Recall one screen of older messages */
+ if ((k == 'p') || (k == KTRL('P')) || (k == ' '))
+ {
+ /* Go older if legal */
+ if (i + (hgt - 4) < n) i += (hgt - 4);
+ }
+
+ /* Recall one screen of newer messages */
+ if ((k == 'n') || (k == KTRL('N')))
+ {
+ /* Go newer (if able) */
+ i = (i >= (hgt - 4)) ? (i - (hgt - 4)) : 0;
+ }
+
+ /* Recall 10 newer messages */
+ if (k == '-')
+ {
+ /* Go newer (if able) */
+ i = (i >= 10) ? (i - 10) : 0;
+ }
+
+ /* Recall 1 newer messages */
+ if (k == '2')
+ {
+ /* Go newer (if able) */
+ i = (i >= 1) ? (i - 1) : 0;
+ }
+
+ /* Hack -- Error of some kind */
+ if (i == j) bell();
+ }
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+}
+
+
+
+/*
+ * Number of cheating options
+ */
+#define CHEAT_MAX 6
+
+/*
+ * Cheating options
+ */
+static option_type cheat_info[CHEAT_MAX] =
+{
+ { &cheat_peek, FALSE, 0, 0, "cheat_peek", "Peek into object creation" },
+ { &cheat_hear, FALSE, 0, 1, "cheat_hear", "Peek into monster creation" },
+ { &cheat_room, FALSE, 0, 2, "cheat_room", "Peek into dungeon creation" },
+ { &cheat_xtra, FALSE, 0, 3, "cheat_xtra", "Peek into something else" },
+ { &cheat_know, FALSE, 0, 4, "cheat_know", "Know complete monster info" },
+ { &cheat_live, FALSE, 0, 5, "cheat_live", "Allow player to avoid death" }
+};
+
+/*
+ * Interact with some options for cheating
+ */
+static void do_cmd_options_cheat(cptr info)
+{
+ char ch;
+
+ int i, k = 0, n = CHEAT_MAX;
+
+ int dir;
+
+ char buf[80];
+
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Interact with the player */
+ while (TRUE)
+ {
+ /* Prompt XXX XXX XXX */
+ strnfmt(buf, 80, "%s (RET to advance, y/n to set, ESC to accept) ", info);
+ prt(buf, 0, 0);
+
+ /* Display the options */
+ for (i = 0; i < n; i++)
+ {
+ byte a = TERM_WHITE;
+
+ /* Color current option */
+ if (i == k) a = TERM_L_BLUE;
+
+ /* Display the option text */
+ strnfmt(buf, 80, "%-48s: %s (%s)",
+ cheat_info[i].o_desc,
+ (*cheat_info[i].o_var ? "yes" : "no "),
+ cheat_info[i].o_text);
+ c_prt(a, buf, i + 2, 0);
+ }
+
+ /* Hilite current option */
+ move_cursor(k + 2, 50);
+
+ /* Get a key */
+ ch = inkey();
+
+ /*
+ * Hack -- Try to translate the key into a direction
+ * to allow the use of roguelike keys for navigation
+ */
+ dir = get_keymap_dir(ch);
+ if ((dir == 2) || (dir == 4) || (dir == 6) || (dir == 8)) ch = I2D(dir);
+
+
+ /* Analyze */
+ switch (ch)
+ {
+ case ESCAPE:
+ {
+ return;
+ }
+
+ case '-':
+ case '8':
+ {
+ k = (n + k - 1) % n;
+
+ break;
+ }
+
+ case ' ':
+ case '\n':
+ case '\r':
+ case '2':
+ {
+ k = (k + 1) % n;
+
+ break;
+ }
+
+ case 'y':
+ case 'Y':
+ case '6':
+ {
+ noscore |= (cheat_info[k].o_page * 256 + cheat_info[k].o_bit);
+ (*cheat_info[k].o_var) = TRUE;
+ k = (k + 1) % n;
+
+ break;
+ }
+
+ case 'n':
+ case 'N':
+ case '4':
+ {
+ (*cheat_info[k].o_var) = FALSE;
+ k = (k + 1) % n;
+
+ break;
+ }
+
+ default:
+ {
+ bell();
+
+ break;
+ }
+ }
+ }
+}
+
+
+static option_type autosave_info[2] =
+{
+ { &autosave_l, FALSE, 0, 6, "autosave_l", "Autosave when entering new levels" },
+ { &autosave_t, FALSE, 0, 7, "autosave_t", "Timed autosave" },
+};
+
+s16b toggle_frequency(s16b current)
+{
+ if (current == 0) return (50);
+ if (current == 50) return (100);
+ if (current == 100) return (250);
+ if (current == 250) return (500);
+ if (current == 500) return (1000);
+ if (current == 1000) return (2500);
+ if (current == 2500) return (5000);
+ if (current == 5000) return (10000);
+ if (current == 10000) return (25000);
+
+ return (0);
+}
+
+
+/*
+ * Interact with some options for cheating
+ */
+static void do_cmd_options_autosave(cptr info)
+{
+ char ch;
+
+ int i, k = 0, n = 2;
+
+ int dir;
+
+ char buf[80];
+
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Interact with the player */
+ while (TRUE)
+ {
+ /* Prompt XXX XXX XXX */
+ strnfmt(buf, 80,
+ "%s (RET to advance, y/n to set, 'F' for frequency, ESC to accept) ",
+ info);
+ prt(buf, 0, 0);
+
+ /* Display the options */
+ for (i = 0; i < n; i++)
+ {
+ byte a = TERM_WHITE;
+
+ /* Color current option */
+ if (i == k) a = TERM_L_BLUE;
+
+ /* Display the option text */
+ strnfmt(buf, 80, "%-48s: %s (%s)",
+ autosave_info[i].o_desc,
+ (*autosave_info[i].o_var ? "yes" : "no "),
+ autosave_info[i].o_text);
+ c_prt(a, buf, i + 2, 0);
+ }
+
+ prt(format("Timed autosave frequency: every %d turns", autosave_freq), 5, 0);
+
+
+ /* Hilite current option */
+ move_cursor(k + 2, 50);
+
+ /* Get a key */
+ ch = inkey();
+
+ /*
+ * Hack -- Try to translate the key into a direction
+ * to allow the use of roguelike keys for navigation
+ */
+ dir = get_keymap_dir(ch);
+ if ((dir == 2) || (dir == 4) || (dir == 6) || (dir == 8)) ch = I2D(dir);
+
+ /* Analyze */
+ switch (ch)
+ {
+ case ESCAPE:
+ {
+ return;
+ }
+
+ case '-':
+ case '8':
+ {
+ k = (n + k - 1) % n;
+
+ break;
+ }
+
+ case ' ':
+ case '\n':
+ case '\r':
+ case '2':
+ {
+ k = (k + 1) % n;
+
+ break;
+ }
+
+ case 'y':
+ case 'Y':
+ case '6':
+ {
+
+ (*autosave_info[k].o_var) = TRUE;
+ k = (k + 1) % n;
+
+ break;
+ }
+
+ case 'n':
+ case 'N':
+ case '4':
+ {
+ (*autosave_info[k].o_var) = FALSE;
+ k = (k + 1) % n;
+
+ break;
+ }
+
+ case 'f':
+ case 'F':
+ {
+ autosave_freq = toggle_frequency(autosave_freq);
+ prt(format("Timed autosave frequency: every %d turns",
+ autosave_freq), 5, 0);
+
+ break;
+ }
+
+ default:
+ {
+ bell();
+
+ break;
+ }
+ }
+ }
+}
+
+/* Switch an option by only knowing its name */
+bool_ change_option(cptr name, bool_ value)
+{
+ int i;
+
+ /* Scan the options */
+ for (i = 0; option_info[i].o_desc; i++)
+ {
+ if (!strcmp(option_info[i].o_text, name))
+ {
+ bool_ old = (*option_info[i].o_var);
+
+ (*option_info[i].o_var) = value;
+
+ return old;
+ }
+ }
+
+ cmsg_format(TERM_VIOLET, "Warning, change_option couldn't find option '%s'.", name);
+ return FALSE;
+}
+
+/*
+ * Interact with some options
+ */
+void do_cmd_options_aux(int page, cptr info, bool_ read_only)
+{
+ char ch;
+
+ int i, k = 0, n = 0;
+
+ int dir;
+
+ int opt[24];
+
+ char buf[80];
+
+
+ /* Lookup the options */
+ for (i = 0; i < 24; i++) opt[i] = 0;
+
+ /* Scan the options */
+ for (i = 0; option_info[i].o_desc; i++)
+ {
+ /* Notice options on this "page" */
+ if (option_info[i].o_page == page) opt[n++] = i;
+ }
+
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Interact with the player */
+ while (TRUE)
+ {
+ /* Prompt XXX XXX XXX */
+ strnfmt(buf, 80, "%s (RET to advance, y/n to set, ESC to accept) ", info);
+ prt(buf, 0, 0);
+
+ /* Display the options */
+ for (i = 0; i < n; i++)
+ {
+ byte a = TERM_WHITE;
+
+ /* Color current option */
+ if (i == k) a = TERM_L_BLUE;
+
+ /* Display the option text */
+ strnfmt(buf, 80, "%-48s: %s (%s)",
+ option_info[opt[i]].o_desc,
+ (*option_info[opt[i]].o_var ? "yes" : "no "),
+ option_info[opt[i]].o_text);
+ c_prt(a, buf, i + 2, 0);
+ }
+
+ /* Hilite current option */
+ move_cursor(k + 2, 50);
+
+ /* Get a key */
+ ch = inkey();
+
+ /*
+ * Hack -- Try to translate the key into a direction
+ * to allow the use of roguelike keys for navigation
+ */
+ dir = get_keymap_dir(ch);
+ if ((dir == 2) || (dir == 4) || (dir == 6) || (dir == 8)) ch = I2D(dir);
+
+ /* Analyze */
+ switch (ch)
+ {
+ case ESCAPE:
+ {
+ return;
+ }
+
+ case '-':
+ case '8':
+ {
+ k = (n + k - 1) % n;
+
+ break;
+ }
+
+ case ' ':
+ case '\n':
+ case '\r':
+ case '2':
+ {
+ k = (k + 1) % n;
+
+ break;
+ }
+
+ case 'y':
+ case 'Y':
+ case '6':
+ {
+ if (read_only) break;
+
+ (*option_info[opt[k]].o_var) = TRUE;
+ k = (k + 1) % n;
+
+ break;
+ }
+
+ case 'n':
+ case 'N':
+ case '4':
+ {
+ if (read_only) break;
+
+ (*option_info[opt[k]].o_var) = FALSE;
+ k = (k + 1) % n;
+
+ break;
+ }
+
+ default:
+ {
+ bell();
+
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+ * Modify the "window" options
+ */
+static void do_cmd_options_win(void)
+{
+ int i, j, d;
+
+ int y = 0;
+
+ int x = 0;
+
+ char ch;
+
+ bool_ go = TRUE;
+
+ u32b old_flag[8];
+
+
+ /* Memorize old flags */
+ for (j = 0; j < 8; j++)
+ {
+ /* Acquire current flags */
+ old_flag[j] = window_flag[j];
+ }
+
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Interact */
+ while (go)
+ {
+ /* Prompt XXX XXX XXX */
+ prt("Window Flags (<dir>, t, y, n, ESC) ", 0, 0);
+
+ /* Display the windows */
+ for (j = 0; j < 8; j++)
+ {
+ byte a = TERM_WHITE;
+
+ cptr s = angband_term_name[j];
+
+ /* Use color */
+ if (j == x) a = TERM_L_BLUE;
+
+ /* Window name, staggered, centered */
+ Term_putstr(35 + j * 5 - strlen(s) / 2, 2 + j % 2, -1, a, s);
+ }
+
+ /* Display the options */
+ for (i = 0; i < 16; i++)
+ {
+ byte a = TERM_WHITE;
+
+ cptr str = window_flag_desc[i];
+
+ /* Use color */
+ if (i == y) a = TERM_L_BLUE;
+
+ /* Unused option */
+ if (!str) str = "(Unused option)";
+
+ /* Flag name */
+ Term_putstr(0, i + 5, -1, a, str);
+
+ /* Display the windows */
+ for (j = 0; j < 8; j++)
+ {
+ byte a = TERM_WHITE;
+
+ char c = '.';
+
+ /* Use color */
+ if ((i == y) && (j == x)) a = TERM_L_BLUE;
+
+ /* Active flag */
+ if (window_flag[j] & (1L << i)) c = 'X';
+
+ /* Flag value */
+ Term_putch(35 + j * 5, i + 5, a, c);
+ }
+ }
+
+ /* Place Cursor */
+ Term_gotoxy(35 + x * 5, y + 5);
+
+ /* Get key */
+ ch = inkey();
+
+ /* Analyze */
+ switch (ch)
+ {
+ case ESCAPE:
+ {
+ go = FALSE;
+
+ break;
+ }
+
+ case 'T':
+ case 't':
+ {
+ /* Clear windows */
+ for (j = 0; j < 8; j++)
+ {
+ window_flag[j] &= ~(1L << y);
+ }
+
+ /* Clear flags */
+ for (i = 0; i < 16; i++)
+ {
+ window_flag[x] &= ~(1L << i);
+ }
+
+ /* Fall through */
+ }
+
+ case 'y':
+ case 'Y':
+ {
+ /* Ignore screen */
+ if (x == 0) break;
+
+ /* Set flag */
+ window_flag[x] |= (1L << y);
+
+ break;
+ }
+
+ case 'n':
+ case 'N':
+ {
+ /* Clear flag */
+ window_flag[x] &= ~(1L << y);
+
+ break;
+ }
+
+ default:
+ {
+ d = get_keymap_dir(ch);
+
+ x = (x + ddx[d] + 8) % 8;
+ y = (y + ddy[d] + 16) % 16;
+
+ if (!d) bell();
+
+ break;
+ }
+ }
+ }
+
+ /* Notice changes */
+ for (j = 0; j < 8; j++)
+ {
+ term *old = Term;
+
+ /* Dead window */
+ if (!angband_term[j]) continue;
+
+ /* Ignore non-changes */
+ if (window_flag[j] == old_flag[j]) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Erase */
+ Term_clear();
+
+ /* Refresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+
+/*
+ * Write all current options to the given preference file in the
+ * lib/user directory. Modified from KAmband 1.8.
+ */
+static errr option_dump(cptr fname)
+{
+ int i, j;
+
+ FILE *fff;
+
+ char buf[1024];
+
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, fname);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Append to the file */
+ fff = my_fopen(buf, "a");
+
+ /* Failure */
+ if (!fff) return ( -1);
+
+
+ /* Skip some lines */
+ fprintf(fff, "\n\n");
+
+ /* Start dumping */
+ fprintf(fff, "# Automatic option dump\n\n");
+
+ /* Dump options (skip cheat, adult, score) */
+ for (i = 0; option_info[i].o_var != NULL; i++)
+ {
+ /* Require a real option */
+ if (!option_info[i].o_text) continue;
+
+ /* No birth options */
+ if (option_info[i].o_page == 6) continue;
+
+ /* Comment */
+ fprintf(fff, "# Option '%s'\n", option_info[i].o_desc);
+
+ /* Dump the option */
+ if ((*option_info[i].o_var))
+ {
+ fprintf(fff, "Y:%s\n", option_info[i].o_text);
+ }
+ else
+ {
+ fprintf(fff, "X:%s\n", option_info[i].o_text);
+ }
+
+ /* Skip a line */
+ fprintf(fff, "\n");
+ }
+
+ /* Dump window flags */
+ for (i = 1; i < ANGBAND_TERM_MAX; i++)
+ {
+ /* Require a real window */
+ if (!angband_term[i]) continue;
+
+ /* Check each flag */
+ for (j = 0; j < 32; j++)
+ {
+ /* Require a real flag */
+ if (!window_flag_desc[j]) continue;
+
+ /* Comment */
+ fprintf(fff, "# Window '%s', Flag '%s'\n",
+ angband_term_name[i], window_flag_desc[j]);
+
+ /* Dump the flag */
+ if (window_flag[i] & (1L << j))
+ {
+ fprintf(fff, "W:%d:%d:1\n", i, j);
+ }
+ else
+ {
+ fprintf(fff, "W:%d:%d:0\n", i, j);
+ }
+
+ /* Skip a line */
+ fprintf(fff, "\n");
+ }
+ }
+
+ /* Close */
+ my_fclose(fff);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Ask for a "user pref file" and process it.
+ *
+ * This function should only be used by standard interaction commands,
+ * in which a standard "Command:" prompt is present on the given row.
+ *
+ * Allow absolute file names? XXX XXX XXX
+ */
+static void do_cmd_pref_file_hack(int row)
+{
+ char ftmp[80];
+
+
+ /* Prompt */
+ prt("Command: Load a user pref file", row, 0);
+
+ /* Prompt */
+ prt("File: ", row + 2, 0);
+
+ /* Default filename */
+ strnfmt(ftmp, 80, "%s.prf", player_base);
+
+ /* Ask for a file (or cancel) */
+ if (!askfor_aux(ftmp, 80)) return;
+
+ /* Process the given filename */
+ if (process_pref_file(ftmp))
+ {
+ /* Mention failure */
+ msg_format("Failed to load '%s'!", ftmp);
+ }
+ else
+ {
+ /* Mention success */
+ msg_format("Loaded '%s'.", ftmp);
+ }
+}
+
+
+/*
+ * Set or unset various options.
+ *
+ * The user must use the "Ctrl-R" command to "adapt" to changes
+ * in any options which control "visual" aspects of the game.
+ */
+void do_cmd_options(void)
+{
+ int k;
+
+
+ /* Save the screen */
+ screen_save();
+
+ /* Interact */
+ while (1)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Why are we here */
+ prt("Options", 2, 0);
+
+ /* Give some choices */
+ prt("(1) User Interface Options", 4, 5);
+ prt("(2) Disturbance Options", 5, 5);
+ prt("(3) Game-Play Options", 6, 5);
+ prt("(4) Efficiency Options", 7, 5);
+ prt("(5) ToME Options", 8, 5);
+ prt("(6) Birth Options(read only)", 9, 5);
+
+ /* Special choices */
+ prt("(D) Base Delay Factor", 10, 5);
+ prt("(H) Hitpoint Warning", 11, 5);
+ prt("(A) Autosave Options", 12, 5);
+
+ /* Automatizer */
+ prt("(T) Automatizer", 14, 5);
+
+
+ /* Window flags */
+ prt("(W) Window Flags", 16, 5);
+
+ /* Cheating */
+ prt("(C) Cheating Options", 18, 5);
+
+ /* Dump */
+ prt("(U) Dump Options setting", 20, 5);
+ prt("(O) Load Options setting", 21, 5);
+
+ /* Prompt */
+ prt("Command: ", 22, 0);
+
+ /* Get command */
+ k = inkey();
+
+ /* Exit */
+ if (k == ESCAPE) break;
+
+ /* Analyze */
+ switch (k)
+ {
+ /* Load a user pref file */
+ case 'o':
+ case 'O':
+ {
+ /* Ask for and load a user pref file */
+ do_cmd_pref_file_hack(21);
+
+ break;
+ }
+
+ /* Append options to a file */
+ case 'u':
+ case 'U':
+ {
+ char ftmp[80];
+
+ /* Prompt */
+ prt("Command: Append options to a file", 21, 0);
+
+ /* Prompt */
+ prt("File: ", 21, 0);
+
+ /* Default filename */
+ strnfmt(ftmp, 80, "%s.prf", player_base);
+
+ /* Ask for a file */
+ if (!askfor_aux(ftmp, 80)) continue;
+
+ /* Dump the options */
+ if (option_dump(ftmp))
+ {
+ /* Failure */
+ msg_print("Failed!");
+ }
+ else
+ {
+ /* Success */
+ msg_print("Done.");
+ }
+
+ break;
+ }
+
+ /* General Options */
+ case '1':
+ {
+ /* Process the general options */
+ do_cmd_options_aux(1, "User Interface Options", FALSE);
+
+ break;
+ }
+
+ /* Disturbance Options */
+ case '2':
+ {
+ /* Spawn */
+ do_cmd_options_aux(2, "Disturbance Options", FALSE);
+
+ break;
+ }
+
+ /* Inventory Options */
+ case '3':
+ {
+ /* Spawn */
+ do_cmd_options_aux(3, "Game-Play Options", FALSE);
+
+ break;
+ }
+
+ /* Efficiency Options */
+ case '4':
+ {
+ /* Spawn */
+ do_cmd_options_aux(4, "Efficiency Options", FALSE);
+
+ break;
+ }
+
+ /* ToME Options */
+ case '5':
+ {
+ do_cmd_options_aux(5, "ToME Options", FALSE);
+
+ break;
+ }
+
+ /* Birth Options - read only */
+ case '6':
+ {
+ do_cmd_options_aux(6, "Birth Options(read only)", TRUE);
+
+ break;
+ }
+ /* Cheating Options */
+ case 'C':
+ {
+ /* Spawn */
+ do_cmd_options_cheat("Cheaters never win");
+
+ break;
+ }
+
+ case 't':
+ case 'T':
+ {
+ do_cmd_automatizer();
+ break;
+ }
+
+ case 'a':
+ case 'A':
+ {
+ do_cmd_options_autosave("Autosave");
+
+ break;
+ }
+
+ /* Window flags */
+ case 'W':
+ case 'w':
+ {
+ /* Spawn */
+ do_cmd_options_win();
+
+ break;
+ }
+
+ /* Hack -- Delay Speed */
+ case 'D':
+ case 'd':
+ {
+ /* Prompt */
+ prt("Command: Base Delay Factor", 21, 0);
+
+ /* Get a new value */
+ while (1)
+ {
+ int msec = delay_factor * delay_factor * delay_factor;
+ prt(format("Current base delay factor: %d (%d msec)",
+ delay_factor, msec), 22, 0);
+ prt("Delay Factor (0-9 or ESC to accept): ", 23, 0);
+ k = inkey();
+ if (k == ESCAPE) break;
+ if (isdigit(k)) delay_factor = D2I(k);
+ else bell();
+ }
+
+ break;
+ }
+
+ /* Hack -- hitpoint warning factor */
+ case 'H':
+ case 'h':
+ {
+ /* Prompt */
+ prt("Command: Hitpoint Warning", 18, 0);
+
+ /* Get a new value */
+ while (1)
+ {
+ prt(format("Current hitpoint warning: %d0%%",
+ hitpoint_warn), 22, 0);
+ prt("Hitpoint Warning (0-9 or ESC to accept): ", 20, 0);
+ k = inkey();
+ if (k == ESCAPE) break;
+ if (isdigit(k)) hitpoint_warn = D2I(k);
+ else bell();
+ }
+
+ break;
+ }
+
+ /* Unknown option */
+ default:
+ {
+ /* Oops */
+ bell();
+
+ break;
+ }
+ }
+
+ /* Flush messages */
+ msg_print(NULL);
+ }
+
+
+ /* Restore the screen */
+ screen_load();
+
+ /* Set the ingame help */
+ ingame_help(p_ptr->help.enabled);
+}
+
+
+
+/*
+ * Ask for a "user pref line" and process it
+ *
+ * XXX XXX XXX Allow absolute file names?
+ */
+void do_cmd_pref(void)
+{
+ char buf[80];
+
+
+ /* Default */
+ strcpy(buf, "");
+
+ /* Ask for a "user pref command" */
+ if (!get_string("Pref: ", buf, 80)) return;
+
+ /* Process that pref command */
+ (void)process_pref_file_aux(buf);
+}
+
+
+/*
+ * Hack -- append all current macros to the given file
+ */
+static errr macro_dump(cptr fname)
+{
+ int i;
+
+ FILE *fff;
+
+ char buf[1024];
+
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, fname);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Append to the file */
+ fff = my_fopen(buf, "a");
+
+ /* Failure */
+ if (!fff) return ( -1);
+
+
+ /* Skip space */
+ fprintf(fff, "\n\n");
+
+ /* Start dumping */
+ fprintf(fff, "# Automatic macro dump\n\n");
+
+ /* Dump them */
+ for (i = 0; i < macro__num; i++)
+ {
+ /* Start the macro */
+ fprintf(fff, "# Macro '%d'\n\n", i);
+
+ /* Extract the action */
+ ascii_to_text(buf, macro__act[i]);
+
+ /* Dump the macro */
+ fprintf(fff, "A:%s\n", buf);
+
+ /* Extract the action */
+ ascii_to_text(buf, macro__pat[i]);
+
+ /* Dump normal macros */
+ fprintf(fff, "P:%s\n", buf);
+
+ /* End the macro */
+ fprintf(fff, "\n\n");
+ }
+
+ /* Start dumping */
+ fprintf(fff, "\n\n\n\n");
+
+
+ /* Close */
+ my_fclose(fff);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Hack -- ask for a "trigger" (see below)
+ *
+ * Note the complex use of the "inkey()" function from "util.c".
+ *
+ * Note that both "flush()" calls are extremely important.
+ */
+static void do_cmd_macro_aux(char *buf, bool_ macro_screen)
+{
+ int i, n = 0;
+
+ char tmp[1024];
+
+
+ /* Flush */
+ flush();
+
+ /* Do not process macros */
+ inkey_base = TRUE;
+
+ /* First key */
+ i = inkey();
+
+ /* Read the pattern */
+ while (i)
+ {
+ /* Save the key */
+ buf[n++] = i;
+
+ /* Do not process macros */
+ inkey_base = TRUE;
+
+ /* Do not wait for keys */
+ inkey_scan = TRUE;
+
+ /* Attempt to read a key */
+ i = inkey();
+ }
+
+ /* Terminate */
+ buf[n] = '\0';
+
+ /* Flush */
+ flush();
+
+
+ if (macro_screen)
+ {
+ /* Convert the trigger */
+ ascii_to_text(tmp, buf);
+
+ /* Hack -- display the trigger */
+ Term_addstr( -1, TERM_WHITE, tmp);
+ }
+}
+
+/*
+ * Hack -- ask for a keymap "trigger" (see below)
+ *
+ * Note that both "flush()" calls are extremely important. This may
+ * no longer be true, since "util.c" is much simpler now. XXX XXX XXX
+ */
+static void do_cmd_macro_aux_keymap(char *buf)
+{
+ char tmp[1024];
+
+
+ /* Flush */
+ flush();
+
+
+ /* Get a key */
+ buf[0] = inkey();
+ buf[1] = '\0';
+
+
+ /* Convert to ascii */
+ ascii_to_text(tmp, buf);
+
+ /* Hack -- display the trigger */
+ Term_addstr( -1, TERM_WHITE, tmp);
+
+
+ /* Flush */
+ flush();
+}
+
+
+/*
+ * Hack -- append all keymaps to the given file
+ */
+static errr keymap_dump(cptr fname)
+{
+ int i;
+
+ FILE *fff;
+
+ char key[1024];
+ char buf[1024];
+
+ int mode;
+
+
+ /* Keymap mode */
+ mode = get_keymap_mode();
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, fname);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Append to the file */
+ fff = my_fopen(buf, "a");
+
+ /* Failure */
+ if (!fff) return ( -1);
+
+
+ /* Skip space */
+ fprintf(fff, "\n\n");
+
+ /* Start dumping */
+ fprintf(fff, "# Automatic keymap dump\n\n");
+
+ /* Dump them */
+ for (i = 0; i < 256; i++)
+ {
+ cptr act;
+
+ /* Loop up the keymap */
+ act = keymap_act[mode][i];
+
+ /* Skip empty keymaps */
+ if (!act) continue;
+
+ /* Encode the key */
+ buf[0] = i;
+ buf[1] = '\0';
+ ascii_to_text(key, buf);
+
+ /* Encode the action */
+ ascii_to_text(buf, act);
+
+ /* Dump the macro */
+ fprintf(fff, "A:%s\n", buf);
+ fprintf(fff, "C:%d:%s\n", mode, key);
+ }
+
+ /* Start dumping */
+ fprintf(fff, "\n\n\n");
+
+
+ /* Close */
+ my_fclose(fff);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Interact with "macros"
+ *
+ * Note that the macro "action" must be defined before the trigger.
+ *
+ * Could use some helpful instructions on this page. XXX XXX XXX
+ */
+void do_cmd_macros(void)
+{
+ int i;
+
+ char tmp[1024];
+
+ char buf[1024];
+
+ int mode;
+
+
+ /* Keymap mode */
+ mode = get_keymap_mode();
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save screen */
+ Term_save();
+
+
+ /* Process requests until done */
+ while (1)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Describe */
+ prt("Interact with Macros", 2, 0);
+
+
+ /* Describe that action */
+ prt("Current action (if any) shown below:", 20, 0);
+
+ /* Analyze the current action */
+ ascii_to_text(buf, macro__buf);
+
+ /* Display the current action */
+ prt(buf, 22, 0);
+
+
+ /* Selections */
+ prt("(1) Load a user pref file", 4, 5);
+ prt("(2) Append macros to a file", 5, 5);
+ prt("(3) Query a macro", 6, 5);
+ prt("(4) Create a macro", 7, 5);
+ prt("(5) Remove a macro", 8, 5);
+ prt("(6) Append keymaps to a file", 9, 5);
+ prt("(7) Query a keymap", 10, 5);
+ prt("(8) Create a keymap", 11, 5);
+ prt("(9) Remove a keymap", 12, 5);
+ prt("(0) Enter a new action", 13, 5);
+
+ /* Prompt */
+ prt("Command: ", 16, 0);
+
+ /* Get a command */
+ i = inkey();
+
+ /* Leave */
+ if (i == ESCAPE) break;
+
+ /* Load a 'macro' file */
+ else if (i == '1')
+ {
+ /* Prompt */
+ prt("Command: Load a user pref file", 16, 0);
+
+ /* Prompt */
+ prt("File: ", 18, 0);
+
+ /* Default filename */
+ strnfmt(tmp, 1024, "%s.prf", player_name);
+
+ /* Ask for a file */
+ if (!askfor_aux(tmp, 80)) continue;
+
+ /* Process the given filename */
+ if (0 != process_pref_file(tmp))
+ {
+ /* Prompt */
+ msg_print("Could not load file!");
+ }
+ }
+
+ /* Save macros */
+ else if (i == '2')
+ {
+ /* Prompt */
+ prt("Command: Append macros to a file", 16, 0);
+
+ /* Prompt */
+ prt("File: ", 18, 0);
+
+ /* Default filename */
+ strnfmt(tmp, 1024, "%s.prf", player_name);
+
+ /* Ask for a file */
+ if (!askfor_aux(tmp, 80)) continue;
+
+ /* Dump the macros */
+ (void)macro_dump(tmp);
+
+ /* Prompt */
+ msg_print("Appended macros.");
+ }
+
+ /* Query a macro */
+ else if (i == '3')
+ {
+ int k;
+
+ /* Prompt */
+ prt("Command: Query a macro", 16, 0);
+
+ /* Prompt */
+ prt("Trigger: ", 18, 0);
+
+ /* Get a macro trigger */
+ do_cmd_macro_aux(buf, TRUE);
+
+ /* Acquire action */
+ k = macro_find_exact(buf);
+
+ /* Nothing found */
+ if (k < 0)
+ {
+ /* Prompt */
+ msg_print("Found no macro.");
+ }
+
+ /* Found one */
+ else
+ {
+ /* Obtain the action */
+ strcpy(macro__buf, macro__act[k]);
+
+ /* Analyze the current action */
+ ascii_to_text(buf, macro__buf);
+
+ /* Display the current action */
+ prt(buf, 22, 0);
+
+ /* Prompt */
+ msg_print("Found a macro.");
+ }
+ }
+
+ /* Create a macro */
+ else if (i == '4')
+ {
+ /* Prompt */
+ prt("Command: Create a macro", 16, 0);
+
+ /* Prompt */
+ prt("Trigger: ", 18, 0);
+
+ /* Get a macro trigger */
+ do_cmd_macro_aux(buf, TRUE);
+
+ /* Clear */
+ clear_from(20);
+
+ /* Prompt */
+ prt("Action: ", 20, 0);
+
+ /* Convert to text */
+ ascii_to_text(tmp, macro__buf);
+
+ /* Get an encoded action */
+ if (askfor_aux(tmp, 80))
+ {
+ /* Convert to ascii */
+ text_to_ascii(macro__buf, tmp);
+
+ /* Link the macro */
+ macro_add(buf, macro__buf);
+
+ /* Prompt */
+ msg_print("Added a macro.");
+ }
+ }
+
+ /* Remove a macro */
+ else if (i == '5')
+ {
+ /* Prompt */
+ prt("Command: Remove a macro", 16, 0);
+
+ /* Prompt */
+ prt("Trigger: ", 18, 0);
+
+ /* Get a macro trigger */
+ do_cmd_macro_aux(buf, TRUE);
+
+ /* Link the macro */
+ macro_add(buf, buf);
+
+ /* Prompt */
+ msg_print("Removed a macro.");
+ }
+
+ /* Save keymaps */
+ else if (i == '6')
+ {
+ /* Prompt */
+ prt("Command: Append keymaps to a file", 16, 0);
+
+ /* Prompt */
+ prt("File: ", 18, 0);
+
+ /* Default filename */
+ strnfmt(tmp, 1024, "%s.prf", player_name);
+
+ /* Ask for a file */
+ if (!askfor_aux(tmp, 80)) continue;
+
+ /* Dump the macros */
+ (void)keymap_dump(tmp);
+
+ /* Prompt */
+ msg_print("Appended keymaps.");
+ }
+
+ /* Query a keymap */
+ else if (i == '7')
+ {
+ cptr act;
+
+ /* Prompt */
+ prt("Command: Query a keymap", 16, 0);
+
+ /* Prompt */
+ prt("Keypress: ", 18, 0);
+
+ /* Get a keymap trigger */
+ do_cmd_macro_aux_keymap(buf);
+
+ /* Look up the keymap */
+ act = keymap_act[mode][(byte)(buf[0])];
+
+ /* Nothing found */
+ if (!act)
+ {
+ /* Prompt */
+ msg_print("Found no keymap.");
+ }
+
+ /* Found one */
+ else
+ {
+ /* Obtain the action */
+ strcpy(macro__buf, act);
+
+ /* Analyze the current action */
+ ascii_to_text(buf, macro__buf);
+
+ /* Display the current action */
+ prt(buf, 22, 0);
+
+ /* Prompt */
+ msg_print("Found a keymap.");
+ }
+ }
+
+ /* Create a keymap */
+ else if (i == '8')
+ {
+ /* Prompt */
+ prt("Command: Create a keymap", 16, 0);
+
+ /* Prompt */
+ prt("Keypress: ", 18, 0);
+
+ /* Get a keymap trigger */
+ do_cmd_macro_aux_keymap(buf);
+
+ /* Clear */
+ clear_from(20);
+
+ /* Prompt */
+ prt("Action: ", 20, 0);
+
+ /* Convert to text */
+ ascii_to_text(tmp, macro__buf);
+
+ /* Get an encoded action */
+ if (askfor_aux(tmp, 80))
+ {
+ /* Convert to ascii */
+ text_to_ascii(macro__buf, tmp);
+
+ /* Free old keymap */
+ string_free(keymap_act[mode][(byte)(buf[0])]);
+
+ /* Make new keymap */
+ keymap_act[mode][(byte)(buf[0])] = string_make(macro__buf);
+
+ /* Prompt */
+ msg_print("Added a keymap.");
+ }
+ }
+
+ /* Remove a keymap */
+ else if (i == '9')
+ {
+ /* Prompt */
+ prt("Command: Remove a keymap", 16, 0);
+
+ /* Prompt */
+ prt("Keypress: ", 18, 0);
+
+ /* Get a keymap trigger */
+ do_cmd_macro_aux_keymap(buf);
+
+ /* Free old keymap */
+ string_free(keymap_act[mode][(byte)(buf[0])]);
+
+ /* Make new keymap */
+ keymap_act[mode][(byte)(buf[0])] = NULL;
+
+ /* Prompt */
+ msg_print("Removed a keymap.");
+ }
+
+ /* Enter a new action */
+ else if (i == '0')
+ {
+ /* Prompt */
+ prt("Command: Enter a new action", 16, 0);
+
+ /* Go to the correct location */
+ Term_gotoxy(0, 22);
+
+ /* Hack -- limit the value */
+ tmp[80] = '\0';
+
+ /* Get an encoded action */
+ if (!askfor_aux(buf, 80)) continue;
+
+ /* Extract an action */
+ text_to_ascii(macro__buf, buf);
+ }
+
+ /* Oops */
+ else
+ {
+ /* Oops */
+ bell();
+ }
+
+ /* Flush messages */
+ msg_print(NULL);
+ }
+
+ /* Load screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+}
+
+
+/*
+ * Interact with "visuals"
+ */
+void do_cmd_visuals(void)
+{
+ int i;
+
+ FILE *fff;
+
+ char tmp[160];
+
+ char buf[1024];
+
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+
+ /* Interact until done */
+ while (1)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Ask for a choice */
+ prt("Interact with Visuals", 2, 0);
+
+ /* Give some choices */
+ prt("(1) Load a user pref file", 4, 5);
+ prt("(2) Dump monster attr/chars", 5, 5);
+ prt("(3) Dump object attr/chars", 6, 5);
+ prt("(4) Dump feature attr/chars", 7, 5);
+ prt("(5) (unused)", 8, 5);
+ prt("(6) Change monster attr/chars", 9, 5);
+ prt("(7) Change object attr/chars", 10, 5);
+ prt("(8) Change feature attr/chars", 11, 5);
+ prt("(9) (unused)", 12, 5);
+ prt("(0) Reset visuals", 13, 5);
+
+ /* Prompt */
+ prt("Command: ", 15, 0);
+
+ /* Prompt */
+ i = inkey();
+
+ /* Done */
+ if (i == ESCAPE) break;
+
+ /* Load a 'pref' file */
+ else if (i == '1')
+ {
+ /* Prompt */
+ prt("Command: Load a user pref file", 15, 0);
+
+ /* Prompt */
+ prt("File: ", 17, 0);
+
+ /* Default filename */
+ strnfmt(tmp, 160, "user-%s.prf", ANGBAND_SYS);
+
+ /* Query */
+ if (!askfor_aux(tmp, 70)) continue;
+
+ /* Process the given filename */
+ (void)process_pref_file(tmp);
+ }
+
+ /* Dump monster attr/chars */
+ else if (i == '2')
+ {
+ /* Prompt */
+ prt("Command: Dump monster attr/chars", 15, 0);
+
+ /* Prompt */
+ prt("File: ", 17, 0);
+
+ /* Default filename */
+ strnfmt(tmp, 160, "user-%s.prf", ANGBAND_SYS);
+
+ /* Get a filename */
+ if (!askfor_aux(tmp, 70)) continue;
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, tmp);
+
+ /* Append to the file */
+ fff = my_fopen(buf, "a");
+
+ /* Failure */
+ if (!fff) continue;
+
+ /* Start dumping */
+ fprintf(fff, "\n\n");
+ fprintf(fff, "# Monster attr/char definitions\n\n");
+
+ /* Dump monsters */
+ for (i = 0; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ /* Skip non-entries */
+ if (!r_ptr->name) continue;
+
+ /* Dump a comment */
+ fprintf(fff, "# %s\n", (r_name + r_ptr->name));
+
+ /* Dump the monster attr/char info */
+ fprintf(fff, "R:%d:0x%02X:0x%02X\n\n", i,
+ (byte)(r_ptr->x_attr), (byte)(r_ptr->x_char));
+ }
+
+ /* All done */
+ fprintf(fff, "\n\n\n\n");
+
+ /* Close */
+ my_fclose(fff);
+
+ /* Message */
+ msg_print("Dumped monster attr/chars.");
+ }
+
+ /* Dump object attr/chars */
+ else if (i == '3')
+ {
+ /* Prompt */
+ prt("Command: Dump object attr/chars", 15, 0);
+
+ /* Prompt */
+ prt("File: ", 17, 0);
+
+ /* Default filename */
+ strnfmt(tmp, 160, "user-%s.prf", ANGBAND_SYS);
+
+ /* Get a filename */
+ if (!askfor_aux(tmp, 70)) continue;
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, tmp);
+
+ /* Append to the file */
+ fff = my_fopen(buf, "a");
+
+ /* Failure */
+ if (!fff) continue;
+
+ /* Start dumping */
+ fprintf(fff, "\n\n");
+ fprintf(fff, "# Object attr/char definitions\n\n");
+
+ /* Dump objects */
+ for (i = 0; i < max_k_idx; i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+
+ /* Skip non-entries */
+ if (!k_ptr->name) continue;
+
+ /* Dump a comment */
+ fprintf(fff, "# %s\n", (k_name + k_ptr->name));
+
+ /* Dump the object attr/char info */
+ fprintf(fff, "K:%d:0x%02X:0x%02X\n\n", i,
+ (byte)(k_ptr->x_attr), (byte)(k_ptr->x_char));
+ }
+
+ /* All done */
+ fprintf(fff, "\n\n\n\n");
+
+ /* Close */
+ my_fclose(fff);
+
+ /* Message */
+ msg_print("Dumped object attr/chars.");
+ }
+
+ /* Dump feature attr/chars */
+ else if (i == '4')
+ {
+ /* Prompt */
+ prt("Command: Dump feature attr/chars", 15, 0);
+
+ /* Prompt */
+ prt("File: ", 17, 0);
+
+ /* Default filename */
+ strnfmt(tmp, 160, "user-%s.prf", ANGBAND_SYS);
+
+ /* Get a filename */
+ if (!askfor_aux(tmp, 70)) continue;
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, tmp);
+
+ /* Append to the file */
+ fff = my_fopen(buf, "a");
+
+ /* Failure */
+ if (!fff) continue;
+
+ /* Start dumping */
+ fprintf(fff, "\n\n");
+ fprintf(fff, "# Feature attr/char definitions\n\n");
+
+ /* Dump features */
+ for (i = 0; i < max_f_idx; i++)
+ {
+ feature_type *f_ptr = &f_info[i];
+
+ /* Skip non-entries */
+ if (!f_ptr->name) continue;
+
+ /* Dump a comment */
+ fprintf(fff, "# %s\n", (f_name + f_ptr->name));
+
+ /* Dump the feature attr/char info */
+ fprintf(fff, "F:%d:0x%02X:0x%02X\n\n", i,
+ (byte)(f_ptr->x_attr), (byte)(f_ptr->x_char));
+ }
+
+ /* All done */
+ fprintf(fff, "\n\n\n\n");
+
+ /* Close */
+ my_fclose(fff);
+
+ /* Message */
+ msg_print("Dumped feature attr/chars.");
+ }
+
+ /* Modify monster attr/chars */
+ else if (i == '6')
+ {
+ static int r = 0;
+
+ /* Prompt */
+ prt("Command: Change monster attr/chars", 15, 0);
+
+ /* Hack -- query until done */
+ while (1)
+ {
+ monster_race *r_ptr = &r_info[r];
+
+ byte da = (r_ptr->d_attr);
+ char dc = (r_ptr->d_char);
+ byte ca = (r_ptr->x_attr);
+ char cc = (r_ptr->x_char);
+
+ /* Label the object */
+ Term_putstr(5, 17, -1, TERM_WHITE,
+ format("Monster = %d, Name = %-40.40s",
+ r, (r_name + r_ptr->name)));
+
+ /* Label the Default values */
+ Term_putstr(10, 19, -1, TERM_WHITE,
+ format("Default attr/char = %3u / %3u", da, (dc & 0xFF)));
+ Term_putstr(40, 19, -1, TERM_WHITE, "<< ? >>");
+ Term_putch(43, 19, da, dc);
+ if (use_bigtile)
+ {
+ if (da & 0x80)
+ Term_putch(44, 19, 255, 255);
+ else
+ Term_putch(44, 19, 0, ' ');
+ }
+
+ /* Label the Current values */
+ Term_putstr(10, 20, -1, TERM_WHITE,
+ format("Current attr/char = %3u / %3u", ca, (cc & 0xFF)));
+ Term_putstr(40, 20, -1, TERM_WHITE, "<< ? >>");
+ Term_putch(43, 20, ca, cc);
+ if (use_bigtile)
+ {
+ if (ca & 0x80)
+ Term_putch(44, 20, 255, 255);
+ else
+ Term_putch(44, 20, 0, ' ');
+ }
+
+ /* Prompt */
+ Term_putstr(0, 22, -1, TERM_WHITE,
+ "Command (n/N/a/A/c/C): ");
+
+ /* Get a command */
+ i = inkey();
+
+ /* All done */
+ if (i == ESCAPE) break;
+
+ /* Analyze */
+ if (i == 'n') r = (r + max_r_idx + 1) % max_r_idx;
+ if (i == 'N') r = (r + max_r_idx - 1) % max_r_idx;
+ if (i == 'a') r_ptr->x_attr = (byte)(ca + 1);
+ if (i == 'A') r_ptr->x_attr = (byte)(ca - 1);
+ if (i == 'c') r_ptr->x_char = (byte)(cc + 1);
+ if (i == 'C') r_ptr->x_char = (byte)(cc - 1);
+ }
+ }
+
+ /* Modify object attr/chars */
+ else if (i == '7')
+ {
+ static int k = 0;
+
+ /* Prompt */
+ prt("Command: Change object attr/chars", 15, 0);
+
+ /* Hack -- query until done */
+ while (1)
+ {
+ object_kind *k_ptr = &k_info[k];
+
+ byte da = (byte)k_ptr->d_attr;
+ char dc = (byte)k_ptr->d_char;
+ byte ca = (byte)k_ptr->x_attr;
+ char cc = (byte)k_ptr->x_char;
+
+ /* Label the object */
+ Term_putstr(5, 17, -1, TERM_WHITE,
+ format("Object = %d, Name = %-40.40s",
+ k, (k_name + k_ptr->name)));
+
+ /* Label the Default values */
+ Term_putstr(10, 19, -1, TERM_WHITE,
+ format("Default attr/char = %3u / %3u", da, (dc & 0xFF)));
+ Term_putstr(40, 19, -1, TERM_WHITE, "<< ? >>");
+ Term_putch(43, 19, da, dc);
+ if (use_bigtile)
+ {
+ if (da & 0x80)
+ Term_putch(44, 19, 255, 255);
+ else
+ Term_putch(44, 19, 0, ' ');
+ }
+
+ /* Label the Current values */
+ Term_putstr(10, 20, -1, TERM_WHITE,
+ format("Current attr/char = %3u / %3u", ca, (cc & 0xFF)));
+ Term_putstr(40, 20, -1, TERM_WHITE, "<< ? >>");
+ Term_putch(43, 20, ca, cc);
+ if (use_bigtile)
+ {
+ if (ca & 0x80)
+ Term_putch(44, 20, 255, 255);
+ else
+ Term_putch(44, 20, 0, ' ');
+ }
+
+ /* Prompt */
+ Term_putstr(0, 22, -1, TERM_WHITE,
+ "Command (n/N/a/A/c/C): ");
+
+ /* Get a command */
+ i = inkey();
+
+ /* All done */
+ if (i == ESCAPE) break;
+
+ /* Analyze */
+ if (i == 'n') k = (k + max_k_idx + 1) % max_k_idx;
+ if (i == 'N') k = (k + max_k_idx - 1) % max_k_idx;
+ if (i == 'a') k_info[k].x_attr = (byte)(ca + 1);
+ if (i == 'A') k_info[k].x_attr = (byte)(ca - 1);
+ if (i == 'c') k_info[k].x_char = (byte)(cc + 1);
+ if (i == 'C') k_info[k].x_char = (byte)(cc - 1);
+ }
+ }
+
+ /* Modify feature attr/chars */
+ else if (i == '8')
+ {
+ static int f = 0;
+
+ /* Prompt */
+ prt("Command: Change feature attr/chars", 15, 0);
+
+ /* Hack -- query until done */
+ while (1)
+ {
+ feature_type *f_ptr = &f_info[f];
+
+ byte da = (byte)f_ptr->d_attr;
+ char dc = (byte)f_ptr->d_char;
+ byte ca = (byte)f_ptr->x_attr;
+ char cc = (byte)f_ptr->x_char;
+
+ /* Label the object */
+ Term_putstr(5, 17, -1, TERM_WHITE,
+ format("Terrain = %d, Name = %-40.40s",
+ f, (f_name + f_ptr->name)));
+
+ /* Label the Default values */
+ Term_putstr(10, 19, -1, TERM_WHITE,
+ format("Default attr/char = %3u / %3u", da, (dc & 0xFF)));
+ Term_putstr(40, 19, -1, TERM_WHITE, "<< ? >>");
+ Term_putch(43, 19, da, dc);
+ if (use_bigtile)
+ {
+ if (da & 0x80)
+ Term_putch(44, 19, 255, 255);
+ else
+ Term_putch(44, 19, 0, ' ');
+ }
+
+ /* Label the Current values */
+ Term_putstr(10, 20, -1, TERM_WHITE,
+ format("Current attr/char = %3u / %3u", ca, (cc & 0xFF)));
+ Term_putstr(40, 20, -1, TERM_WHITE, "<< ? >>");
+ Term_putch(43, 20, ca, cc);
+ if (use_bigtile)
+ {
+ if (ca & 0x80)
+ Term_putch(44, 20, 255, 255);
+ else
+ Term_putch(44, 20, 0, ' ');
+ }
+
+ /* Prompt */
+ Term_putstr(0, 22, -1, TERM_WHITE,
+ "Command (n/N/a/A/c/C/d): ");
+
+ /* Get a command */
+ i = inkey();
+
+ /* All done */
+ if (i == ESCAPE) break;
+
+ /* Analyze */
+ if (i == 'n') f = (f + max_f_idx + 1) % max_f_idx;
+ if (i == 'N') f = (f + max_f_idx - 1) % max_f_idx;
+ if (i == 'a') f_info[f].x_attr = (byte)(ca + 1);
+ if (i == 'A') f_info[f].x_attr = (byte)(ca - 1);
+ if (i == 'c') f_info[f].x_char = (byte)(cc + 1);
+ if (i == 'C') f_info[f].x_char = (byte)(cc - 1);
+ if (i == 'd')
+ {
+ f_info[f].x_char = f_ptr->d_char;
+ f_info[f].x_attr = f_ptr->d_attr;
+ }
+ }
+ }
+
+ /* Reset visuals */
+ else if (i == '0')
+ {
+ /* Reset */
+ reset_visuals();
+
+ /* Message */
+ msg_print("Visual attr/char tables reset.");
+ }
+
+ /* Unknown option */
+ else
+ {
+ bell();
+ }
+
+ /* Flush messages */
+ msg_print(NULL);
+ }
+
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+}
+
+
+/*
+ * Interact with "colors"
+ */
+void do_cmd_colors(void)
+{
+ int i;
+
+ FILE *fff;
+
+ char tmp[160];
+
+ char buf[1024];
+
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+
+ /* Interact until done */
+ while (1)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Ask for a choice */
+ prt("Interact with Colors", 2, 0);
+
+ /* Give some choices */
+ prt("(1) Load a user pref file", 4, 5);
+ prt("(2) Dump colors", 5, 5);
+ prt("(3) Modify colors", 6, 5);
+
+ /* Prompt */
+ prt("Command: ", 8, 0);
+
+ /* Prompt */
+ i = inkey();
+
+ /* Done */
+ if (i == ESCAPE) break;
+
+ /* Load a 'pref' file */
+ if (i == '1')
+ {
+ /* Prompt */
+ prt("Command: Load a user pref file", 8, 0);
+
+ /* Prompt */
+ prt("File: ", 10, 0);
+
+ /* Default file */
+ strnfmt(tmp, 160, "user-%s.prf", ANGBAND_SYS);
+
+ /* Query */
+ if (!askfor_aux(tmp, 70)) continue;
+
+ /* Process the given filename */
+ (void)process_pref_file(tmp);
+
+ /* Mega-Hack -- react to changes */
+ Term_xtra(TERM_XTRA_REACT, 0);
+
+ /* Mega-Hack -- redraw */
+ Term_redraw();
+ }
+
+ /* Dump colors */
+ else if (i == '2')
+ {
+ /* Prompt */
+ prt("Command: Dump colors", 8, 0);
+
+ /* Prompt */
+ prt("File: ", 10, 0);
+
+ /* Default filename */
+ strnfmt(tmp, 160, "user-%s.prf", ANGBAND_SYS);
+
+ /* Get a filename */
+ if (!askfor_aux(tmp, 70)) continue;
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, tmp);
+
+ /* Append to the file */
+ fff = my_fopen(buf, "a");
+
+ /* Failure */
+ if (!fff) continue;
+
+ /* Start dumping */
+ fprintf(fff, "\n\n");
+ fprintf(fff, "# Color redefinitions\n\n");
+
+ /* Dump colors */
+ for (i = 0; i < 256; i++)
+ {
+ int kv = angband_color_table[i][0];
+ int rv = angband_color_table[i][1];
+ int gv = angband_color_table[i][2];
+ int bv = angband_color_table[i][3];
+
+ cptr name = "unknown";
+
+ /* Skip non-entries */
+ if (!kv && !rv && !gv && !bv) continue;
+
+ /* Extract the color name */
+ if (i < 16) name = color_names[i];
+
+ /* Dump a comment */
+ fprintf(fff, "# Color '%s'\n", name);
+
+ /* Dump the monster attr/char info */
+ fprintf(fff, "V:%d:0x%02X:0x%02X:0x%02X:0x%02X\n\n",
+ i, kv, rv, gv, bv);
+ }
+
+ /* All done */
+ fprintf(fff, "\n\n\n\n");
+
+ /* Close */
+ my_fclose(fff);
+
+ /* Message */
+ msg_print("Dumped color redefinitions.");
+ }
+
+ /* Edit colors */
+ else if (i == '3')
+ {
+ static byte a = 0;
+
+ /* Prompt */
+ prt("Command: Modify colors", 8, 0);
+
+ /* Hack -- query until done */
+ while (1)
+ {
+ cptr name;
+
+ /* Clear */
+ clear_from(10);
+
+ /* Exhibit the normal colors */
+ for (i = 0; i < 16; i++)
+ {
+ /* Exhibit this color */
+ Term_putstr(i*4, 20, -1, a, "###");
+
+ /* Exhibit all colors */
+ Term_putstr(i*4, 22, -1, i, format("%3d", i));
+ }
+
+ /* Describe the color */
+ name = ((a < 16) ? color_names[a] : "undefined");
+
+ /* Describe the color */
+ Term_putstr(5, 10, -1, TERM_WHITE,
+ format("Color = %d, Name = %s", a, name));
+
+ /* Label the Current values */
+ Term_putstr(5, 12, -1, TERM_WHITE,
+ format("K = 0x%02x / R,G,B = 0x%02x,0x%02x,0x%02x",
+ angband_color_table[a][0],
+ angband_color_table[a][1],
+ angband_color_table[a][2],
+ angband_color_table[a][3]));
+
+ /* Prompt */
+ Term_putstr(0, 14, -1, TERM_WHITE,
+ "Command (n/N/k/K/r/R/g/G/b/B): ");
+
+ /* Get a command */
+ i = inkey();
+
+ /* All done */
+ if (i == ESCAPE) break;
+
+ /* Analyze */
+ if (i == 'n') a = (byte)(a + 1);
+ if (i == 'N') a = (byte)(a - 1);
+ if (i == 'k') angband_color_table[a][0] = (byte)(angband_color_table[a][0] + 1);
+ if (i == 'K') angband_color_table[a][0] = (byte)(angband_color_table[a][0] - 1);
+ if (i == 'r') angband_color_table[a][1] = (byte)(angband_color_table[a][1] + 1);
+ if (i == 'R') angband_color_table[a][1] = (byte)(angband_color_table[a][1] - 1);
+ if (i == 'g') angband_color_table[a][2] = (byte)(angband_color_table[a][2] + 1);
+ if (i == 'G') angband_color_table[a][2] = (byte)(angband_color_table[a][2] - 1);
+ if (i == 'b') angband_color_table[a][3] = (byte)(angband_color_table[a][3] + 1);
+ if (i == 'B') angband_color_table[a][3] = (byte)(angband_color_table[a][3] - 1);
+
+ /* Hack -- react to changes */
+ Term_xtra(TERM_XTRA_REACT, 0);
+
+ /* Hack -- redraw */
+ Term_redraw();
+ }
+ }
+
+ /* Unknown option */
+ else
+ {
+ bell();
+ }
+
+ /* Flush messages */
+ msg_print(NULL);
+ }
+
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+}
+
+
+/*
+ * Take notes. There are two ways this can happen, either in the message
+ * recall or a file.
+ */
+void do_cmd_note(void)
+{
+ char buf[80];
+
+
+ /* Default */
+ strcpy(buf, "");
+
+ if (!get_string("Note: ", buf, 60)) return;
+
+ /* Ignore empty notes */
+ if (!buf[0] || (buf[0] == ' ')) return;
+
+ if (take_notes)
+ {
+ /* Add note to file */
+ add_note(buf, ' ');
+ }
+ else
+ {
+ /* Add note to message recall */
+ msg_format("Note: %s", buf);
+ }
+}
+
+
+/*
+ * Mention the current version
+ */
+void do_cmd_version(void)
+{
+ cptr author, email;
+
+ call_lua("get_module_info", "(s,d)", "s", "author", 1, &author);
+ call_lua("get_module_info", "(s,d)", "s", "author", 2, &email);
+
+ /* Silly message */
+ msg_format("You are playing %s made by %s (%s).",
+ get_version_string(),
+ author, email);
+ call_lua("patchs_display", "()", "");
+}
+
+
+
+/*
+ * Array of feeling strings
+ */
+static cptr do_cmd_feeling_text[11] =
+{
+ "Looks like any other level.",
+ "You feel there is something special about this level.",
+ "You have a superb feeling about this level.",
+ "You have an excellent feeling...",
+ "You have a very good feeling...",
+ "You have a good feeling...",
+ "You feel strangely lucky...",
+ "You feel your luck is turning...",
+ "You like the look of this place...",
+ "This level can't be all bad...",
+ "What a boring place..."
+};
+
+
+/*
+ * Note that "feeling" is set to zero unless some time has passed.
+ * Note that this is done when the level is GENERATED, not entered.
+ */
+void do_cmd_feeling(void)
+{
+ /* Verify the feeling */
+ if (feeling < 0) feeling = 0;
+ if (feeling > 10) feeling = 10;
+
+ /* Feeling of the fate */
+ if (fate_flag && !(dungeon_flags2 & DF2_SPECIAL) && !p_ptr->inside_quest)
+ {
+ msg_print("You feel that you will meet your fate here.");
+ }
+
+ /* Hooked feelings ? */
+ if (process_hooks(HOOK_FEELING, "(d)", is_quest(dun_level)))
+ {
+ return;
+ }
+
+ /* No useful feeling in special levels */
+ if (dungeon_flags2 & DF2_DESC)
+ {
+ char buf[1024];
+
+ if ((get_dungeon_save(buf)) || (generate_special_feeling) || (dungeon_flags2 & DF2_DESC_ALWAYS))
+ {
+ if (!get_level_desc(buf)) msg_print("Someone forgot to describe this level!");
+ else msg_print(buf);
+ return;
+ }
+ }
+
+ /* No useful feeling in quests */
+ if (p_ptr->inside_quest)
+ {
+ msg_print("Looks like a typical quest level.");
+ return;
+ }
+
+ /* Display feelings in the dungeon, nothing on the surface */
+ if (dun_level)
+ {
+ /* This could be simplified with a correct p_ptr->town_num */
+ int i, town_level = 0;
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ /* Is it a town level ? */
+ for (i = 0; i < TOWN_DUNGEON; i++)
+ {
+ if (d_ptr->t_level[i] == dun_level) town_level = d_ptr->t_idx[i];
+ }
+
+ if (town_level)
+ msg_print("You hear the sound of a market.");
+ else
+ msg_print(do_cmd_feeling_text[feeling]);
+ }
+ return;
+}
+
+
+
+/*
+ * Encode the screen colors
+ */
+static char hack[17] = "dwsorgbuDWvyRGBU";
+
+
+/*
+ * Hack -- load a screen dump from a file
+ */
+void do_cmd_load_screen(void)
+{
+ int i, y, x;
+
+ int wid, hgt;
+ int len;
+
+ byte a = 0;
+ char c = ' ';
+
+ bool_ okay = TRUE;
+
+ FILE *fff;
+
+ char buf[1024];
+
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, "dump.txt");
+
+ /* Append to the file */
+ fff = my_fopen(buf, "r");
+
+ /* Oops */
+ if (!fff) return;
+
+
+ /* Retrieve the current screen size */
+ Term_get_size(&wid, &hgt);
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ /* Clear the screen */
+ Term_clear();
+
+
+ /* Load the screen */
+ for (y = 0; okay; y++)
+ {
+ /* Get a line of data */
+ if (my_fgets(fff, buf, 1024)) okay = FALSE;
+
+ /* Stop on blank line */
+ if (!buf[0]) break;
+
+ /* Ignore off screen lines */
+ if (y >= hgt) continue;
+
+ /* Get width */
+ len = strlen(buf);
+
+ /* Truncate if it's longer than current screen width */
+ if (len > wid) len = wid;
+
+ /* Show each row */
+ for (x = 0; x < len; x++)
+ {
+ /* Put the attr/char */
+ Term_draw(x, y, TERM_WHITE, buf[x]);
+ }
+ }
+
+ /* Dump the screen */
+ for (y = 0; okay; y++)
+ {
+ /* Get a line of data */
+ if (my_fgets(fff, buf, 1024)) okay = FALSE;
+
+ /* Stop on blank line */
+ if (!buf[0]) break;
+
+ /* Ignore off screen lines */
+ if (y >= hgt) continue;
+
+ /* Get width */
+ len = strlen(buf);
+
+ /* Truncate if it's longer than current screen width */
+ if (len > wid) len = wid;
+
+ /* Dump each row */
+ for (x = 0; x < len; x++)
+ {
+ /* Get the attr/char */
+ (void)(Term_what(x, y, &a, &c));
+
+ /* Look up the attr */
+ for (i = 0; i < 16; i++)
+ {
+ /* Use attr matches */
+ if (hack[i] == buf[x]) a = i;
+ }
+
+ /* Put the attr/char */
+ Term_draw(x, y, a, c);
+ }
+ }
+
+
+ /* Close it */
+ my_fclose(fff);
+
+
+ /* Message */
+ msg_print("Screen dump loaded.");
+ msg_print(NULL);
+
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+}
+
+
+
+/*
+ * Redefinable "save_screen" action
+ */
+void (*screendump_aux)(void) = NULL;
+
+
+
+
+
+
+/*
+ * Hack -- save a screen dump to a file
+ */
+void do_cmd_save_screen(void)
+{
+ /* Do we use a special screendump function ? */
+ if (screendump_aux)
+ {
+ /* Dump the screen to a graphics file */
+ (*screendump_aux)();
+ }
+
+ /* Dump the screen as text */
+ else
+ {
+ int y, x;
+ int wid, hgt;
+
+ byte a = 0;
+ char c = ' ';
+
+ FILE *fff;
+
+ char buf[1024];
+
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, "dump.txt");
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Append to the file */
+ fff = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!fff) return;
+
+
+ /* Retrieve the current screen size */
+ Term_get_size(&wid, &hgt);
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+
+ /* Dump the screen */
+ for (y = 0; y < hgt; y++)
+ {
+ /* Dump each row */
+ for (x = 0; x < wid; x++)
+ {
+ /* Get the attr/char */
+ (void)(Term_what(x, y, &a, &c));
+
+ /* Dump it */
+ buf[x] = c;
+ }
+
+ /* Terminate */
+ buf[x] = '\0';
+
+ /* End the row */
+ fprintf(fff, "%s\n", buf);
+ }
+
+ /* Skip a line */
+ fprintf(fff, "\n");
+
+
+ /* Dump the screen */
+ for (y = 0; y < hgt; y++)
+ {
+ /* Dump each row */
+ for (x = 0; x < wid; x++)
+ {
+ /* Get the attr/char */
+ (void)(Term_what(x, y, &a, &c));
+
+ /* Dump it */
+ buf[x] = hack[a & 0x0F];
+ }
+
+ /* Terminate */
+ buf[x] = '\0';
+
+ /* End the row */
+ fprintf(fff, "%s\n", buf);
+ }
+
+ /* Skip a line */
+ fprintf(fff, "\n");
+
+
+ /* Close it */
+ my_fclose(fff);
+
+
+ /* Message */
+ msg_print("Screen dump saved.");
+ msg_print(NULL);
+
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+ }
+}
+
+
+/*
+ * Check the status of "artifacts"
+ */
+void do_cmd_knowledge_artifacts(void)
+{
+ int i, k, z, x, y;
+
+ FILE *fff;
+
+ char file_name[1024];
+
+ char base_name[80];
+
+ bool_ *okay, *okayk;
+
+
+ /* Allocate the "okay" array */
+ C_MAKE(okay, max_a_idx, bool_);
+ C_MAKE(okayk, max_k_idx, bool_);
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ /* Scan the artifacts */
+ for (k = 0; k < max_a_idx; k++)
+ {
+ artifact_type *a_ptr = &a_info[k];
+
+ /* Default */
+ okay[k] = FALSE;
+
+ /* Skip "empty" artifacts */
+ if (!a_ptr->name) continue;
+
+ /* Skip "uncreated" artifacts */
+ if (!a_ptr->cur_num) continue;
+
+ /* Assume okay */
+ okay[k] = TRUE;
+ }
+
+ for (k = 0; k < max_k_idx; k++)
+ {
+ object_kind *k_ptr = &k_info[k];
+
+ /* Default */
+ okayk[k] = FALSE;
+
+ /* Skip "empty" artifacts */
+ if (!(k_ptr->flags3 & TR3_NORM_ART)) continue;
+
+ /* Skip "uncreated" artifacts */
+ if (!k_ptr->artifact) continue;
+
+ /* Assume okay */
+ okayk[k] = TRUE;
+ }
+
+ /* Check the dungeon */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Ignore random artifacts */
+ if (o_ptr->tval == TV_RANDART) continue;
+
+ /* Ignore non-artifacts */
+ if (!artifact_p(o_ptr)) continue;
+
+ /* Ignore known items */
+ if (object_known_p(o_ptr)) continue;
+
+ /* Note the artifact */
+ if (k_info[o_ptr->k_idx].flags3 & TR3_NORM_ART)
+ {
+ okayk[o_ptr->k_idx] = FALSE;
+ }
+ else
+ {
+ okay[o_ptr->name1] = FALSE;
+ }
+ }
+ }
+ }
+
+ /* Check monsters in the dungeon */
+ for (i = 0; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ /* Scan all objects the monster carries */
+ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Ignore random artifacts */
+ if (o_ptr->tval == TV_RANDART) continue;
+
+ /* Ignore non-artifacts */
+ if (!artifact_p(o_ptr)) continue;
+
+ /* Ignore known items */
+ if (object_known_p(o_ptr)) continue;
+
+ /* Note the artifact */
+ if (k_info[o_ptr->k_idx].flags3 & TR3_NORM_ART)
+ {
+ okayk[o_ptr->k_idx] = FALSE;
+ }
+ else
+ {
+ okay[o_ptr->name1] = FALSE;
+ }
+ }
+ }
+
+ /* Check the p_ptr->inventory and equipment */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Ignore non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Ignore random artifacts */
+ if (o_ptr->tval == TV_RANDART) continue;
+
+ /* Ignore non-artifacts */
+ if (!artifact_p(o_ptr)) continue;
+
+ /* Ignore known items */
+ if (object_known_p(o_ptr)) continue;
+
+ /* Note the artifact */
+ if (k_info[o_ptr->k_idx].flags3 & TR3_NORM_ART)
+ {
+ okayk[o_ptr->k_idx] = FALSE;
+ }
+ else
+ {
+ okay[o_ptr->name1] = FALSE;
+ }
+ }
+
+ /* Scan the artifacts */
+ for (k = 0; k < max_a_idx; k++)
+ {
+ artifact_type *a_ptr = &a_info[k];
+
+ /* List "dead" ones */
+ if (!okay[k]) continue;
+
+ /* Paranoia */
+ strcpy(base_name, "Unknown Artifact");
+
+ /* Obtain the base object type */
+ z = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Real object */
+ if (z)
+ {
+ object_type forge;
+ object_type *q_ptr;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Create fake object */
+ object_prep(q_ptr, z);
+
+ /* Make it an artifact */
+ q_ptr->name1 = k;
+
+ /* Spell in it ? no ! */
+ object_flags(q_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if (f5 & TR5_SPELL_CONTAIN)
+ q_ptr->pval2 = -1;
+
+ /* Describe the artifact */
+ object_desc_store(base_name, q_ptr, FALSE, 0);
+ }
+
+ /* Hack -- Build the artifact name */
+ fprintf(fff, " The %s\n", base_name);
+ }
+
+ for (k = 0; k < max_k_idx; k++)
+ {
+ /* List "dead" ones */
+ if (!okayk[k]) continue;
+
+ /* Paranoia */
+ strcpy(base_name, "Unknown Artifact");
+
+ /* Real object */
+ if (k)
+ {
+ object_type forge;
+ object_type *q_ptr;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Create fake object */
+ object_prep(q_ptr, k);
+
+ /* Describe the artifact */
+ object_desc_store(base_name, q_ptr, FALSE, 0);
+ }
+
+ /* Hack -- Build the artifact name */
+ fprintf(fff, " The %s\n", base_name);
+ }
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Artifacts Seen", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+
+ C_FREE(okay, max_a_idx, bool_);
+ C_FREE(okayk, max_k_idx, bool_);
+}
+
+
+/*
+ * Check the status of traps
+ */
+void do_cmd_knowledge_traps(void)
+{
+ int k;
+
+ FILE *fff;
+
+ trap_type *t_ptr;
+
+ char file_name[1024];
+
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ /* Scan the traps */
+ for (k = 0; k < max_t_idx; k++)
+ {
+ /* Get the trap */
+ t_ptr = &t_info[k];
+
+ /* Skip "empty" traps */
+ if (!t_ptr->name) continue;
+
+ /* Skip unidentified traps */
+ if (!t_ptr->ident) continue;
+
+ /* Hack -- Build the trap name */
+ fprintf(fff, " %s\n", t_name + t_ptr->name);
+ }
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Traps known", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+/*
+ * Display known uniques
+ *
+ * Note that the player ghosts are ignored. XXX XXX XXX
+ */
+static void insert_sort_unique(int *sort_uniques, int *num, int r_idx)
+{
+ int i, j;
+
+ monster_race *r_ptr = &r_info[r_idx];
+
+ int level = r_ptr->level;
+
+
+ /* Hack -- Morgoth is always at the bottom of the list */
+ if (r_idx == 862) level = 20000;
+
+ /* Find the place */
+ for (i = 0; i < *num; i++)
+ {
+ monster_race *r2_ptr = &r_info[sort_uniques[i]];
+ int level2 = r2_ptr->level;
+
+ if (sort_uniques[i] == 862) level2 = 20000;
+
+ if (level < level2) break;
+ }
+
+ /* Move the remaining items */
+ for (j = *num - 1; j >= i; j--)
+ {
+ sort_uniques[j + 1] = sort_uniques[j];
+ }
+
+ /* Insert it */
+ sort_uniques[i] = r_idx;
+ (*num)++;
+}
+
+
+static void do_cmd_knowledge_uniques(void)
+{
+ int k;
+
+ int *sort_uniques;
+
+ int num = 0;
+
+ FILE *fff;
+
+ char file_name[1024];
+
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ C_MAKE(sort_uniques, max_r_idx, int);
+
+ /* Sort the monster races */
+ for (k = 1; k < max_r_idx; k++)
+ {
+ monster_race *r_ptr = &r_info[k];
+
+ /* Only print Uniques */
+ if (r_ptr->flags1 & (RF1_UNIQUE) &&
+ !(r_ptr->flags7 & RF7_PET) &&
+ !(r_ptr->flags7 & RF7_NEUTRAL))
+ {
+ insert_sort_unique(sort_uniques, &num, k);
+ }
+ }
+
+ /* Scan the monster races -- sorted */
+ for (k = 0; k < num; k++)
+ {
+ monster_race *r_ptr = &r_info[sort_uniques[k]];
+
+ /* Only print Uniques */
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ bool_ dead = (r_ptr->max_num == 0);
+
+ /* Only display "known" uniques */
+ if (dead || cheat_know || r_ptr->r_sights)
+ {
+ /* Print a message */
+ if (dead)
+ {
+ /* Don't print the unique's ASCII symbol
+ * if use_graphics is on. */
+ if (use_graphics)
+ {
+ fprintf(fff, "[[[[[R%-70s is dead]\n",
+ (r_name + r_ptr->name));
+ }
+ else
+ {
+ fprintf(fff, "[[[[[%c%c] [[[[[R%-68s is dead]\n",
+ conv_color[r_ptr->d_attr],
+ r_ptr->d_char,
+ (r_name + r_ptr->name));
+ }
+ }
+ else
+ {
+ /* Don't print the unique's ASCII symbol
+ * if use_graphics is on. */
+ if (use_graphics)
+ {
+ fprintf(fff, "[[[[[w%-70s is alive]\n",
+ (r_name + r_ptr->name));
+ }
+ else
+ {
+ fprintf(fff, "[[[[[%c%c] [[[[[w%-68s is alive]\n",
+ conv_color[r_ptr->d_attr],
+ r_ptr->d_char,
+ (r_name + r_ptr->name));
+ }
+ }
+ }
+ }
+ }
+
+ C_FREE(sort_uniques, max_r_idx, int);
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Known Uniques", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+void plural_aux(char *name)
+{
+ int name_len = strlen(name);
+
+ /* Hack -- Precedent must be pluralised for this one */
+ if (strstr(name, "Disembodied hand"))
+ {
+ strcpy(name, "Disembodied hands that strangled people");
+ }
+
+ /* "someone of something" */
+ else if (strstr(name, " of "))
+ {
+ cptr aider = strstr(name, " of ");
+ char dummy[80];
+ int i = 0;
+ cptr ctr = name;
+
+ while (ctr < aider)
+ {
+ dummy[i] = *ctr;
+ ctr++;
+ i++;
+ }
+
+ if (dummy[i - 1] == 's')
+ {
+ strcpy(&dummy[i], "es");
+ i++;
+ }
+ else
+ {
+ strcpy(&dummy[i], "s");
+ }
+
+ strcpy(&dummy[i + 1], aider);
+ strcpy(name, dummy);
+ }
+
+ /* Creeping coins */
+ else if (strstr(name, "coins"))
+ {
+ char dummy[80];
+ strcpy(dummy, "piles of ");
+ strcat(dummy, name);
+ strcpy(name, dummy);
+ return;
+ }
+
+ /* Manes stay manes */
+ else if (strstr(name, "Manes"))
+ {
+ return;
+ }
+
+ /* Broken plurals are, well, broken */
+ else if (name[name_len - 1] == 'y')
+ {
+ strcpy(&name[name_len - 1], "ies");
+ }
+ else if (streq(&name[name_len - 4], "ouse"))
+ {
+ strcpy(&name[name_len - 4], "ice");
+ }
+ else if (streq(&name[name_len - 6], "kelman"))
+ {
+ strcpy(&name[name_len - 6], "kelmen");
+ }
+ else if (streq(&name[name_len - 2], "ex"))
+ {
+ strcpy(&name[name_len - 2], "ices");
+ }
+ else if (streq(&name[name_len - 3], "olf"))
+ {
+ strcpy(&name[name_len - 3], "olves");
+ }
+
+ /* Now begins sane cases */
+ else if ((streq(&name[name_len - 2], "ch")) || (name[name_len - 1] == 's'))
+ {
+ strcpy(&name[name_len], "es");
+ }
+ else
+ {
+ strcpy(&name[name_len], "s");
+ }
+}
+
+
+/*
+ * Display current pets
+ */
+static void do_cmd_knowledge_pets(void)
+{
+ int i;
+
+ FILE *fff;
+
+ monster_type *m_ptr;
+
+ int t_friends = 0;
+
+ int t_levels = 0;
+
+ int show_upkeep = 0;
+
+ int upkeep_divider = 20;
+
+ char file_name[1024];
+
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ if (has_ability(AB_PERFECT_CASTING)) upkeep_divider = 15;
+
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Calculate "upkeep" for friendly monsters */
+ if (m_ptr->status >= MSTATUS_PET)
+ {
+ char pet_name[80];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ t_friends++;
+ t_levels += m_ptr->level;
+ monster_desc(pet_name, m_ptr, 0x88);
+ fprintf(fff, "%s%s (%s)\n",
+ (r_ptr->flags1 & RF1_UNIQUE) ? "#####G" : "",
+ pet_name,
+ (m_ptr->status < MSTATUS_COMPANION) ? "pet" : "companion");
+ }
+ }
+
+ if (t_friends > 1 + (p_ptr->lev / (upkeep_divider)))
+ {
+ show_upkeep = (t_levels);
+
+ if (show_upkeep > 100) show_upkeep = 100;
+ else if (show_upkeep < 10) show_upkeep = 10;
+ }
+
+
+ fprintf(fff, "----------------------------------------------\n");
+ fprintf(fff, " Total: %d pet%s.\n", t_friends, (t_friends == 1 ? "" : "s"));
+ fprintf(fff, " Upkeep: %d%% mana.\n", show_upkeep);
+
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Current Pets", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+
+/*
+ * Total kill count
+ *
+ * Note that the player ghosts are ignored. XXX XXX XXX
+ */
+static void do_cmd_knowledge_kill_count(void)
+{
+ int k;
+
+ FILE *fff;
+
+ char file_name[1024];
+
+ s32b Total = 0;
+
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ {
+ /* Monsters slain */
+ int kk;
+
+ /* For all monsters */
+ for (kk = 1; kk < max_r_idx; kk++)
+ {
+ monster_race *r_ptr = &r_info[kk];
+
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ bool_ dead = (r_ptr->max_num == 0);
+
+ if (dead)
+ {
+ Total++;
+ }
+ }
+ else
+ {
+ s16b This = r_ptr->r_pkills;
+
+ if (This > 0)
+ {
+ Total += This;
+ }
+ }
+ }
+
+ if (Total < 1)
+ {
+ fprintf(fff, "You have defeated no enemies yet.\n\n");
+ }
+ else if (Total == 1)
+ {
+ fprintf(fff, "You have defeated one enemy.\n\n");
+ }
+ else
+ {
+ fprintf(fff, "You have defeated %ld enemies.\n\n", (long int) Total);
+ }
+ }
+
+ Total = 0;
+
+ /* Scan the monster races */
+ for (k = 0; k < max_r_idx; k++)
+ {
+ monster_race *r_ptr = &r_info[k];
+
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ bool_ dead = (r_ptr->max_num == 0);
+
+ if (dead)
+ {
+ /* Print a message */
+ fprintf(fff, " %s\n",
+ (r_name + r_ptr->name));
+ Total++;
+ }
+ }
+ else
+ {
+ s16b This = r_ptr->r_pkills;
+
+ if (This > 0)
+ {
+ if (This < 2)
+ {
+ if (strstr(r_name + r_ptr->name, "coins"))
+ {
+ fprintf(fff, " 1 pile of %s\n", (r_name + r_ptr->name));
+ }
+ else
+ {
+ fprintf(fff, " 1 %s\n", (r_name + r_ptr->name));
+ }
+ }
+ else
+ {
+ char to_plural[80];
+ strcpy(to_plural, (r_name + r_ptr->name));
+ plural_aux(to_plural);
+ fprintf(fff, " %d %s\n", This, to_plural);
+ }
+
+ Total += This;
+ }
+ }
+ }
+
+ fprintf(fff, "----------------------------------------------\n");
+ fprintf(fff, " Total: %ld creature%s killed.\n", (long int) Total, (Total == 1 ? "" : "s"));
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Kill Count", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+/*
+ * Display known objects
+ */
+static void do_cmd_knowledge_objects(void)
+{
+ int k;
+
+ FILE *fff;
+
+ char o_name[80];
+
+ char file_name[1024];
+
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ /* Scan the object kinds */
+ for (k = 1; k < max_k_idx; k++)
+ {
+ object_kind *k_ptr = &k_info[k];
+
+ /* Hack -- skip artifacts */
+ if (k_ptr->flags3 & (TR3_INSTA_ART)) continue;
+
+ /* List known flavored objects */
+ if (k_ptr->flavor && k_ptr->aware)
+ {
+ object_type *i_ptr;
+ object_type object_type_body;
+
+ /* Get local object */
+ i_ptr = &object_type_body;
+
+ /* Create fake object */
+ object_prep(i_ptr, k);
+
+ /* Describe the object */
+ object_desc_store(o_name, i_ptr, FALSE, 0);
+
+ /* Print a message */
+ fprintf(fff, " %s\n", o_name);
+ }
+ }
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Known Objects", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+/*
+ * List recall depths
+ */
+static void do_cmd_knowledge_dungeons(void)
+{
+ int y;
+ char file_name[1024];
+ FILE *fff;
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ /* Oops */
+ if (fff == NULL) return;
+
+ /* Scan all dungeons */
+ for (y = 1; y < max_d_idx; y++)
+ {
+ /* The dungeon has a valid recall depth set */
+ if (max_dlv[y])
+ {
+ /* Describe the recall depth */
+ fprintf(fff, " %c%s: Level %d (%d')\n",
+ (p_ptr->recall_dungeon == y) ? '*' : ' ',
+ d_name + d_info[y].name,
+ max_dlv[y], 50 * (max_dlv[y]));
+ }
+ }
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Recall Depths", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+/*
+ * List known towns
+ */
+void do_cmd_knowledge_towns(void)
+{
+ int i, j;
+ char file_name[1024];
+ FILE *fff;
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ /* Oops */
+ if (fff == NULL) return;
+
+ /* Scan all dungeons */
+ for (i = 0; i < max_d_idx; i++)
+ {
+ dungeon_info_type *d_ptr = &d_info[i];
+
+ /* Scan all dungeon town slots */
+ for (j = 0; j < TOWN_DUNGEON; j++)
+ {
+ int town_idx = d_ptr->t_idx[j];
+
+ /* Ignore non-existent towns */
+ if (!(town_info[town_idx].flags & (TOWN_REAL))) continue;
+
+ /* Ignore unknown towns */
+ if (!(town_info[town_idx].flags & (TOWN_KNOWN))) continue;
+
+ /* Describe the dungeon town */
+ fprintf(fff, " %s: Level %d (%d')\n",
+ d_name + d_ptr->name,
+ d_ptr->t_level[j],
+ 50 * d_ptr->t_level[j]);
+ }
+ }
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Dungeon Towns", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+/*
+ * List corruptions
+ */
+void do_cmd_knowledge_corruptions(void)
+{
+ FILE *fff;
+
+ char file_name[1024];
+
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ /* Dump the corruptions to file */
+ if (fff) dump_corruptions(fff, TRUE);
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Corruptions", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+/*
+ * Helper function for do_cmd_knowledge_quests
+ */
+static void insert_sort_quest(int *order, int *num, int q_idx)
+{
+ int i, j;
+
+ quest_type *q_ptr = &quest[q_idx];
+
+ int level = q_ptr->level;
+
+
+ /* Find the place */
+ for (i = 0; i < *num; i++)
+ {
+ quest_type *q2_ptr = &quest[order[i]];
+ int level2 = q2_ptr->level;
+
+ if (level < level2) break;
+ }
+
+ /* Move the remaining items */
+ for (j = *num - 1; j >= i; j--)
+ {
+ order[j + 1] = order[j];
+ }
+
+ /* Insert it */
+ order[i] = q_idx;
+ (*num)++;
+}
+
+
+/*
+ * Print quest status of all active quests
+ */
+static void do_cmd_knowledge_quests(void)
+{
+ FILE *fff;
+
+ char file_name[1024];
+
+ int *order;
+
+ int num = 0;
+
+ int i, j, z;
+
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ C_MAKE(order, max_q_idx, int);
+
+ for (i = 0; i < max_q_idx; i++)
+ {
+ insert_sort_quest(order, &num, i);
+ }
+
+ for (z = 0; z < max_q_idx; z++)
+ {
+ i = order[z];
+
+ /* Dynamic quests */
+ if (quest[i].dynamic_desc)
+ {
+ /* C type quests */
+ if (quest[i].type == HOOK_TYPE_C)
+ {
+ if (!quest[i].gen_desc(fff))
+ {
+ continue;
+ }
+ }
+ /* MUST be a lua quest */
+ else
+ {
+ hook_file = fff;
+ exec_lua(format("__quest_dynamic_desc[%d]()", i));
+ }
+ }
+
+ /* Fixed quests (only known ones) */
+ else if (!quest[i].silent)
+ {
+ if (quest[i].status == QUEST_STATUS_TAKEN)
+ {
+ /* Print the quest info */
+ fprintf(fff, "#####y%s (Danger level: %d)\n",
+ quest[i].name, quest[i].level);
+
+ j = 0;
+ while ((j < 10) && (quest[i].desc[j][0] != '\0'))
+ {
+ fprintf(fff, "%s\n", quest[i].desc[j++]);
+ }
+ fprintf(fff, "\n");
+ }
+ else if (quest[i].status == QUEST_STATUS_COMPLETED)
+ {
+ fprintf(fff , "#####G%s Completed - Unrewarded\n", quest[i].name);
+ fprintf(fff, "\n");
+ }
+ }
+ }
+
+ C_FREE(order, max_q_idx, int);
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Quest status", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+/*
+ * Print fate status
+ */
+static void do_cmd_knowledge_fates(void)
+{
+ FILE *fff;
+
+ char file_name[1024];
+
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ dump_fates(fff);
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Fate status", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
+
+
+/*
+ * Print the note file
+ */
+void do_cmd_knowledge_notes(void)
+{
+ /* Spawn */
+ show_notes_file();
+
+ /* Done */
+ return;
+}
+
+
+/*
+ * Interact with "knowledge"
+ */
+void do_cmd_knowledge(void)
+{
+ int i;
+
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ /* Interact until done */
+ while (1)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Ask for a choice */
+ prt("Display current knowledge", 2, 0);
+
+ /* Give some choices */
+ prt("(1) Display known artifacts", 4, 5);
+ prt("(2) Display known uniques", 5, 5);
+ prt("(3) Display known objects", 6, 5);
+ prt("(4) Display kill count", 7, 5);
+ prt("(5) Display recall depths", 8, 5);
+ prt("(6) Display corruptions", 9, 5);
+ prt("(7) Display current pets", 10, 5);
+ prt("(8) Display current quests", 11, 5);
+ prt("(9) Display current fates", 12, 5);
+ prt("(0) Display known traps", 13, 5);
+ prt("(A) Display known dungeon towns", 14, 5);
+ if (take_notes) prt("(B) Display notes", 15, 5);
+
+ /* Prompt */
+ prt("Command: ", 17, 0);
+
+ /* Prompt */
+ i = inkey();
+
+ /* Done */
+ if (i == ESCAPE) break;
+
+ switch (i)
+ {
+ /* Artifacts */
+ case '1':
+ {
+ do_cmd_knowledge_artifacts();
+
+ break;
+ }
+
+ /* Uniques */
+ case '2':
+ {
+ do_cmd_knowledge_uniques();
+
+ break;
+ }
+
+ /* Objects */
+ case '3':
+ {
+ do_cmd_knowledge_objects();
+
+ break;
+ }
+
+ /* Kill count */
+ case '4':
+ {
+ do_cmd_knowledge_kill_count();
+
+ break;
+ }
+
+ /* Recall depths */
+ case '5':
+ {
+ do_cmd_knowledge_dungeons();
+
+ break;
+ }
+
+ /* corruptions */
+ case '6':
+ {
+ do_cmd_knowledge_corruptions();
+
+ break;
+ }
+
+ /* Pets */
+ case '7':
+ {
+ do_cmd_knowledge_pets();
+
+ break;
+ }
+
+ /* Quests */
+ case '8':
+ {
+ do_cmd_knowledge_quests();
+
+ break;
+ }
+
+ /* Fates */
+ case '9':
+ {
+ do_cmd_knowledge_fates();
+
+ break;
+ }
+
+ /* Traps */
+ case '0':
+ {
+ do_cmd_knowledge_traps();
+
+ break;
+ }
+
+ /* Dungeon towns */
+ case 'A':
+ case 'a':
+ {
+ do_cmd_knowledge_towns();
+
+ break;
+ }
+
+ /* Notes */
+ case 'B':
+ case 'b':
+ {
+ if (take_notes) do_cmd_knowledge_notes();
+ else bell();
+
+ break;
+ }
+
+ /* Unknown option */
+ default:
+ {
+ bell();
+
+ break;
+ }
+ }
+
+ /* Flush messages */
+ msg_print(NULL);
+ }
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+}
+
+
+/*
+ * Check on the status of an active quest -KMW-
+ * TODO: Spill out status when not a simple kill # monster.
+ */
+void do_cmd_checkquest(void)
+{
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ /* Quest info */
+ do_cmd_knowledge_quests();
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+}
+
+
+/*
+ * Change player's "tactic" setting
+ */
+void do_cmd_change_tactic(int i)
+{
+ p_ptr->tactic += i;
+ if (p_ptr->tactic > 8) p_ptr->tactic = 0;
+ if (p_ptr->tactic < 0) p_ptr->tactic = 8;
+
+ p_ptr->update |= (PU_BONUS);
+ update_stuff();
+ prt("", 0, 0);
+}
+
+
+/*
+ * Change player's "movement" setting
+ */
+void do_cmd_change_movement(int i)
+{
+ p_ptr->movement += i;
+ if (p_ptr->movement > 8) p_ptr->movement = 0;
+ if (p_ptr->movement < 0) p_ptr->movement = 8;
+
+ p_ptr->update |= (PU_BONUS);
+ update_stuff();
+ prt("", 0, 0);
+}
+
+
+/*
+ * Display the time and date
+ */
+void do_cmd_time()
+{
+ int day = bst(DAY, turn);
+
+ int hour = bst(HOUR, turn);
+
+ int min = bst(MINUTE, turn);
+
+ int full = hour * 100 + min;
+
+ char buf2[20];
+
+ int start = 9999;
+
+ int end = -9999;
+
+ int num = 0;
+
+ char desc[1024];
+
+ char buf[1024];
+
+ FILE *fff;
+
+
+ /* Note */
+ strcpy(desc, "It is a strange time.");
+
+ /* Format time of the day */
+ strnfmt(buf2, 20, get_day(bst(YEAR, turn) + START_YEAR));
+
+ /* Display current date in the Elvish calendar */
+ msg_format("This is %s of the %s year of the third age.",
+ get_month_name(day, wizard, FALSE), buf2);
+
+ /* Message */
+ msg_format("The time is %d:%02d %s.",
+ (hour % 12 == 0) ? 12 : (hour % 12),
+ min, (hour < 12) ? "AM" : "PM");
+
+ /* Find the path */
+ if (!rand_int(10) || p_ptr->image)
+ {
+ path_build(buf, 1024, ANGBAND_DIR_FILE, "timefun.txt");
+ }
+ else
+ {
+ path_build(buf, 1024, ANGBAND_DIR_FILE, "timenorm.txt");
+ }
+
+ /* Open this file */
+ fff = my_fopen(buf, "rt");
+
+ /* Oops */
+ if (!fff) return;
+
+ /* Find this time */
+ while (!my_fgets(fff, buf, 1024))
+ {
+ /* Ignore comments */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Ignore invalid lines */
+ if (buf[1] != ':') continue;
+
+ /* Process 'Start' */
+ if (buf[0] == 'S')
+ {
+ /* Extract the starting time */
+ start = atoi(buf + 2);
+
+ /* Assume valid for an hour */
+ end = start + 59;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'End' */
+ if (buf[0] == 'E')
+ {
+ /* Extract the ending time */
+ end = atoi(buf + 2);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Ignore incorrect range */
+ if ((start > full) || (full > end)) continue;
+
+ /* Process 'Description' */
+ if (buf[0] == 'D')
+ {
+ num++;
+
+ /* Apply the randomizer */
+ if (!rand_int(num)) strcpy(desc, buf + 2);
+
+ /* Next... */
+ continue;
+ }
+ }
+
+ /* Message */
+ msg_print(desc);
+
+ /* Close the file */
+ my_fclose(fff);
+}
+
+/*
+ * Macro recorder!
+ * It records all keypresses and then put them in a macro
+ * Not as powerful as the macro screen, but much easier for newbies
+ */
+char *macro_recorder_current = NULL;
+void macro_recorder_start()
+{
+ msg_print("Starting macro recording, press this key again to stop. Note that if the action you want to record accepts the @ key, use it; it will remove your the need to inscribe stuff.");
+ C_MAKE(macro_recorder_current, 1, char);
+ macro_recorder_current[0] = '\0';
+}
+
+void macro_recorder_add(char c)
+{
+ char *old_macro_recorder_current = macro_recorder_current;
+
+ if (macro_recorder_current == NULL) return;
+
+ C_MAKE(macro_recorder_current, strlen(macro_recorder_current) + 1 + 1, char);
+ sprintf(macro_recorder_current, "%s%c", old_macro_recorder_current, c);
+ C_FREE(old_macro_recorder_current, strlen(old_macro_recorder_current) + 1, char);
+}
+
+void macro_recorder_stop()
+{
+ char *str, *macro;
+ char buf[1024];
+
+ /* Ok we remove the last key, because it is the key to stop recording */
+ macro_recorder_current[strlen(macro_recorder_current) - 1] = '\0';
+
+ /* Stop the recording */
+ macro = macro_recorder_current;
+ macro_recorder_current = NULL;
+
+ /* Add it */
+ if (get_check("Are you satisfied and want to create the macro? "))
+ {
+ prt("Trigger: ", 0, 0);
+
+ /* Get a macro trigger */
+ do_cmd_macro_aux(buf, FALSE);
+
+ /* Link the macro */
+ macro_add(buf, macro);
+
+ /* Prompt */
+ C_MAKE(str, (strlen(macro) + 1) * 3, char);
+ ascii_to_text(str, macro);
+ msg_format("Added a macro '%s'. If you want it to stay permanently, press @ now and dump macros to a file.", str);
+ C_FREE(str, (strlen(macro) + 1) * 3, char);
+ }
+
+ /* Ok now rid of useless stuff */
+ C_FREE(macro, strlen(macro) + 1, char);
+}
+
+void do_cmd_macro_recorder()
+{
+ if (macro_recorder_current == NULL)
+ macro_recorder_start();
+ else
+ macro_recorder_stop();
+}
diff --git a/src/cmd5.c b/src/cmd5.c
new file mode 100644
index 00000000..b415b166
--- /dev/null
+++ b/src/cmd5.c
@@ -0,0 +1,2562 @@
+/* File: cmd5.c */
+
+/* Purpose: Class commands */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+
+#include "angband.h"
+#include "lua/lua.h"
+#include "tolua.h"
+
+extern lua_State *L;
+
+
+/* Maximum number of tries for teleporting */
+#define MAX_TRIES 300
+
+bool_ is_school_book(object_type *o_ptr)
+{
+ if (o_ptr->tval == TV_BOOK)
+ {
+ return TRUE;
+ }
+ else if (o_ptr->tval == TV_DAEMON_BOOK)
+ {
+ return TRUE;
+ }
+ else if (o_ptr->tval == TV_INSTRUMENT)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/* Does it contains a schooled spell ? */
+static bool_ hook_school_spellable(object_type *o_ptr)
+{
+ if (is_school_book(o_ptr))
+ return TRUE;
+ else
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Extract object flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if ((f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 != -1))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Is it a book */
+bool_ item_tester_hook_browsable(object_type *o_ptr)
+{
+ if (hook_school_spellable(o_ptr)) return TRUE;
+ if (o_ptr->tval >= TV_BOOK) return TRUE;
+ return FALSE;
+}
+
+/*
+ * Are we using a mage staff
+ */
+bool_ is_magestaff()
+{
+ int i;
+
+
+ i = 0;
+
+ while (p_ptr->body_parts[i] == INVEN_WIELD)
+ {
+ object_type *o_ptr = &p_ptr->inventory[INVEN_WIELD + i];
+
+ /* Wielding a mage staff */
+ if ((o_ptr->k_idx) && (o_ptr->tval == TV_MSTAFF)) return (TRUE);
+
+ /* Next slot */
+ i++;
+
+ /* Paranoia */
+ if (i >= (INVEN_TOTAL - INVEN_WIELD)) break;
+ }
+
+ /* Not wielding a mage staff */
+ return (FALSE);
+}
+
+/*
+ * Peruse the spells/prayers in a book
+ *
+ * Note that *all* spells in the book are listed
+ *
+ * Note that browsing is allowed while confused or blind,
+ * and in the dark, primarily to allow browsing in stores.
+ */
+
+extern void do_cmd_browse_aux(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (is_school_book(o_ptr))
+ browse_school_spell(o_ptr->sval, o_ptr->pval, o_ptr);
+ else if (f5 & TR5_SPELL_CONTAIN && o_ptr->pval2 != -1)
+ browse_school_spell(255, o_ptr->pval2, o_ptr);
+}
+
+void do_cmd_browse(void)
+{
+ int item;
+
+ cptr q, s;
+
+ object_type *o_ptr;
+
+ /* Restrict choices to "useful" books */
+ item_tester_hook = item_tester_hook_browsable;
+
+ /* Get an item */
+ q = "Browse which book? ";
+ s = "You have no books that you can read.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_EQUIP | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ do_cmd_browse_aux(o_ptr);
+}
+
+void do_poly_wounds(void)
+{
+ /* Changed to always provide at least _some_ healing */
+ s16b wounds = p_ptr->cut;
+
+ s16b hit_p = (p_ptr->mhp - p_ptr->chp);
+
+ s16b change = damroll(p_ptr->lev, 5);
+
+ bool_ Nasty_effect = (randint(5) == 1);
+
+
+ if (!(wounds || hit_p || Nasty_effect)) return;
+
+ msg_print("Your wounds are polymorphed into less serious ones.");
+ hp_player(change);
+ if (Nasty_effect)
+ {
+ msg_print("A new wound was created!");
+ take_hit(change / 2, "a polymorphed wound");
+ set_cut(change);
+ }
+ else
+ {
+ set_cut((p_ptr->cut) - (change / 2));
+ }
+}
+
+void do_poly_self(void)
+{
+ int power = p_ptr->lev;
+ int poly_power;
+
+ msg_print("You feel a change coming over you...");
+
+ if ((power > rand_int(20)) && (rand_int(3) == 0))
+ {
+ char effect_msg[80] = "";
+ int new_race, expfact, goalexpfact;
+
+ /* Some form of racial polymorph... */
+ power -= 10;
+
+ if ((power > rand_int(5)) && (rand_int(4) == 0))
+ {
+ /* sex change */
+ power -= 2;
+
+ if (p_ptr->psex == SEX_MALE)
+ {
+ p_ptr->psex = SEX_FEMALE;
+ sp_ptr = &sex_info[p_ptr->psex];
+ strcpy(effect_msg, "female");
+ }
+ else
+ {
+ p_ptr->psex = SEX_MALE;
+ sp_ptr = &sex_info[p_ptr->psex];
+ strcpy(effect_msg, "male");
+ }
+ }
+
+ if ((power > rand_int(30)) && (rand_int(5) == 0))
+ {
+ int tmp = 0;
+
+ /* Harmful deformity */
+ power -= 15;
+
+ while (tmp < 6)
+ {
+ if ( rand_int(2) == 0)
+ {
+ (void)dec_stat(tmp, randint(6) + 6, (rand_int(3) == 0));
+ power -= 1;
+ }
+ tmp++;
+ }
+
+ /* Deformities are discriminated against! */
+ (void)dec_stat(A_CHR, randint(6), TRUE);
+
+ if (effect_msg[0])
+ {
+ char tmp_msg[10];
+ strnfmt(tmp_msg, 10, "%s", effect_msg);
+ strnfmt(effect_msg, 80, "deformed %s", tmp_msg);
+ }
+ else
+ {
+ strcpy(effect_msg, "deformed");
+ }
+ }
+
+ while ((power > rand_int(20)) && (rand_int(10) == 0))
+ {
+ /* Polymorph into a less corrupted form */
+ power -= 10;
+
+ lose_corruption(0);
+ }
+
+ /*
+ * I'm not sure 'power' is always positive, with *so* many minuses.
+ * Also, passing zero / negative numbers to randint/rand_int can
+ * cause a zero divide exception, IIRC, not to speak of its absurdity
+ * -- pelpel
+ */
+ poly_power = (power > 1) ? power : 1;
+
+ /*
+ * Restrict the race choices by exp penalty so weak polymorph
+ * always means weak race
+ */
+ goalexpfact = 100 + 3 * rand_int(poly_power);
+
+ /* Roll until an appropriate selection is made */
+ while (1)
+ {
+ new_race = rand_int(max_rp_idx);
+ expfact = race_info[new_race].r_exp;
+
+ if ((new_race != p_ptr->prace) && (expfact <= goalexpfact)) break;
+ }
+
+ if (effect_msg[0])
+ {
+ msg_format("You turn into a%s %s!",
+ ((is_a_vowel(rp_name[race_info[new_race].title])) ? "n" : ""),
+ race_info[new_race].title + rp_name);
+ }
+ else
+ {
+ msg_format("You turn into a %s %s!", effect_msg,
+ race_info[new_race].title);
+ }
+
+ p_ptr->prace = new_race;
+ rp_ptr = &race_info[p_ptr->prace];
+
+ /* Experience factor */
+ p_ptr->expfact = rp_ptr->r_exp + rmp_ptr->r_exp + cp_ptr->c_exp;
+
+ /* Calculate the height/weight */
+ get_height_weight();
+
+
+ check_experience();
+ p_ptr->max_plv = p_ptr->lev;
+
+ p_ptr->redraw |= (PR_BASIC);
+
+ p_ptr->update |= (PU_BONUS);
+
+ handle_stuff();
+ lite_spot(p_ptr->py, p_ptr->px);
+ }
+
+ if ((power > rand_int(30)) && (rand_int(6) == 0))
+ {
+ int tmp = 0;
+
+ /* Abomination! */
+ power -= 20;
+
+ msg_print("Your internal organs are rearranged!");
+ while (tmp < 6)
+ {
+ (void)dec_stat(tmp, randint(6) + 6, (rand_int(3) == 0));
+ tmp++;
+ }
+ if (rand_int(6) == 0)
+ {
+ msg_print("You find living difficult in your present form!");
+ take_hit(damroll(randint(10), p_ptr->lev), "a lethal corruption");
+ power -= 10;
+ }
+ }
+
+ if ((power > rand_int(20)) && (rand_int(4) == 0))
+ {
+ power -= 10;
+
+ do_cmd_rerate();
+ }
+
+ while ((power > rand_int(15)) && (rand_int(3) == 0))
+ {
+ power -= 7;
+ (void) gain_random_corruption(0);
+ }
+
+ if (power > rand_int(5))
+ {
+ power -= 5;
+ do_poly_wounds();
+ }
+
+ /* Note: earlier deductions may have left power < 0 already. */
+ while (power > 0)
+ {
+ corrupt_player();
+ power--;
+ }
+}
+
+
+/*
+ * Brand the current weapon
+ */
+void brand_weapon(int brand_type)
+{
+ object_type *o_ptr;
+
+ cptr act = NULL;
+
+ char o_name[80];
+
+
+ o_ptr = &p_ptr->inventory[INVEN_WIELD];
+
+ /*
+ * You can never modify artifacts / ego-items
+ * You can never modify cursed items
+ *
+ * TY: You _can_ modify broken items (if you're silly enough)
+ */
+ if (!o_ptr->k_idx || artifact_p(o_ptr) || ego_item_p(o_ptr) ||
+ o_ptr->art_name || cursed_p(o_ptr))
+ {
+ if (flush_failure) flush();
+
+ msg_print("The Branding failed.");
+
+ return;
+ }
+
+
+ /* Save the old name */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ switch (brand_type)
+ {
+ case 6:
+ {
+ act = "glows with godly power.";
+ o_ptr->name2 = EGO_BLESS_BLADE;
+ o_ptr->pval = randint(4);
+
+ break;
+ }
+ case 5:
+ {
+ act = "seems very powerful.";
+ o_ptr->name2 = EGO_EARTHQUAKES;
+ o_ptr->pval = randint(3);
+
+ break;
+ }
+ case 4:
+ {
+ act = "seems very unstable now.";
+ o_ptr->name2 = EGO_DRAGON;
+ o_ptr->pval = randint(2);
+
+ break;
+ }
+ case 3:
+ {
+ act = "thirsts for blood!";
+ o_ptr->name2 = EGO_VAMPIRIC;
+
+ break;
+ }
+ case 2:
+ {
+ act = "is coated with poison.";
+ o_ptr->name2 = EGO_BRAND_POIS;
+
+ break;
+ }
+ case 1:
+ {
+ act = "is engulfed in raw chaos!";
+ o_ptr->name2 = EGO_CHAOTIC;
+
+ break;
+ }
+ default:
+ {
+ if (rand_int(100) < 25)
+ {
+ act = "is covered in a fiery shield!";
+ o_ptr->name2 = EGO_BRAND_FIRE;
+ }
+ else
+ {
+ act = "glows deep, icy blue!";
+ o_ptr->name2 = EGO_BRAND_COLD;
+ }
+ }
+ }
+
+ /* Apply the ego */
+ apply_magic(o_ptr, dun_level, FALSE, FALSE, FALSE);
+ o_ptr->discount = 100;
+
+ msg_format("Your %s %s", o_name, act);
+
+ enchant(o_ptr, rand_int(3) + 4, ENCH_TOHIT | ENCH_TODAM);
+}
+
+/*
+ * Fetch an item (teleport it right underneath the caster)
+ */
+void fetch(int dir, int wgt, bool_ require_los)
+{
+ int ty, tx, i;
+
+ cave_type *c_ptr;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+
+ /* Check to see if an object is already there */
+ if (cave[p_ptr->py][p_ptr->px].o_idx)
+ {
+ msg_print("You can't fetch when you're already standing on something.");
+ return;
+ }
+
+ /* Use a target */
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+
+ if (distance(p_ptr->py, p_ptr->px, ty, tx) > MAX_RANGE)
+ {
+ msg_print("You can't fetch something that far away!");
+ return;
+ }
+
+ c_ptr = &cave[ty][tx];
+
+ if (!c_ptr->o_idx)
+ {
+ msg_print("There is no object at this place.");
+ return;
+ }
+
+ if (require_los && (!player_has_los_bold(ty, tx)))
+ {
+ msg_print("You have no direct line of sight to that location.");
+ return;
+ }
+ }
+ else
+ {
+ /* Use a direction */
+ ty = p_ptr->py; /* Where to drop the item */
+ tx = p_ptr->px;
+
+ while (1)
+ {
+ ty += ddy[dir];
+ tx += ddx[dir];
+ c_ptr = &cave[ty][tx];
+
+ if ((distance(p_ptr->py, p_ptr->px, ty, tx) > MAX_RANGE) ||
+ !cave_floor_bold(ty, tx)) return;
+
+ if (c_ptr->o_idx) break;
+ }
+ }
+
+ o_ptr = &o_list[c_ptr->o_idx];
+
+ if (o_ptr->weight > wgt)
+ {
+ /* Too heavy to 'fetch' */
+ msg_print("The object is too heavy.");
+ return;
+ }
+
+ i = c_ptr->o_idx;
+ c_ptr->o_idx = o_ptr->next_o_idx;
+ cave[p_ptr->py][p_ptr->px].o_idx = i; /* 'move' it */
+ o_ptr->next_o_idx = 0;
+ o_ptr->iy = p_ptr->py;
+ o_ptr->ix = p_ptr->px;
+
+ object_desc(o_name, o_ptr, TRUE, 0);
+ msg_format("%^s flies through the air to your feet.", o_name);
+
+ note_spot(p_ptr->py, p_ptr->px);
+ p_ptr->redraw |= PR_MAP;
+}
+
+
+/*
+ * Handle random effects of player shrieking
+ */
+void shriek_effect()
+{
+ switch (randint(9))
+ {
+ case 1:
+ case 5:
+ case 8:
+ case 9:
+ {
+ msg_print("You make a high-pitched shriek!");
+ aggravate_monsters(1);
+
+ break;
+ }
+ case 2:
+ case 6:
+ {
+ msg_print("Oops! You call a monster.");
+ summon_specific(p_ptr->py, p_ptr->px, max_dlv[dungeon_type], 0);
+
+ break;
+ }
+ case 3:
+ case 7:
+ {
+ msg_print("The dungeon collapses!");
+ earthquake(p_ptr->py, p_ptr->px, 5);
+
+ break;
+ }
+ case 4:
+ {
+ msg_print("Your shriek is so horrible that you damage your health!");
+ take_hit(damroll(p_ptr->lev / 5, 8), "inner hemorrhaging");
+
+ break;
+ }
+ }
+}
+
+
+/*
+ * Like all the random effect codes, this is *ugly*,
+ * and there is not a single line of comment, so I can't tell
+ * some fall throughs are really intended. Well, I know it's
+ * intended to be bizarre :) -- pelpel
+ */
+void wild_magic(int spell)
+{
+ int counter = 0;
+ int type = SUMMON_BIZARRE1 - 1 + randint(6);
+
+ if (type < SUMMON_BIZARRE1) type = SUMMON_BIZARRE1;
+ else if (type > SUMMON_BIZARRE6) type = SUMMON_BIZARRE6;
+
+ switch (randint(spell) + randint(8) + 1)
+ {
+ case 1:
+ case 2:
+ case 3:
+ {
+ teleport_player(10);
+
+ break;
+ }
+
+ case 4:
+ case 5:
+ case 6:
+ {
+ teleport_player(100);
+
+ break;
+ }
+
+ case 7:
+ case 8:
+ {
+ teleport_player(200);
+
+ break;
+ }
+
+ case 9:
+ case 10:
+ case 11:
+ {
+ unlite_area(10, 3);
+
+ break;
+ }
+
+ case 12:
+ case 13:
+ case 14:
+ {
+ lite_area(damroll(2, 3), 2);
+
+ break;
+ }
+
+ case 15:
+ {
+ destroy_doors_touch();
+
+ break;
+ }
+
+ case 16:
+ case 17:
+ {
+ wall_breaker();
+
+ /* I don't think this is a fall through -- pelpel */
+ break;
+ }
+
+ case 18:
+ {
+ sleep_monsters_touch();
+
+ break;
+ }
+
+ case 19:
+ case 20:
+ {
+ trap_creation();
+
+ break;
+ }
+
+ case 21:
+ case 22:
+ {
+ door_creation();
+
+ break;
+ }
+
+ case 23:
+ case 24:
+ case 25:
+ {
+ aggravate_monsters(1);
+
+ break;
+ }
+
+ case 26:
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(p_ptr->py, p_ptr->px, 5);
+
+ break;
+ }
+
+ case 27:
+ case 28:
+ {
+ break;
+ }
+
+ case 29:
+ case 30:
+ {
+ apply_disenchant(0);
+
+ break;
+ }
+
+ case 31:
+ {
+ lose_all_info();
+
+ break;
+ }
+
+ case 32:
+ {
+ fire_ball(GF_CHAOS, 0, spell + 5, 1 + (spell / 10));
+
+ break;
+ }
+
+ case 33:
+ {
+ wall_stone(p_ptr->py, p_ptr->px);
+
+ break;
+ }
+
+ case 34:
+ case 35:
+ {
+ while (counter++ < 8)
+ {
+ (void) summon_specific(p_ptr->py, p_ptr->px, (dun_level * 3) / 2, type);
+ }
+
+ break;
+ }
+
+ case 36:
+ case 37:
+ {
+ activate_hi_summon();
+
+ break;
+ }
+
+ case 38:
+ {
+ summon_cyber();
+
+ /* I don't think this is a fall through -- pelpel */
+ break;
+ }
+
+ default:
+ {
+ activate_ty_curse();
+ }
+ }
+
+ return;
+}
+
+
+/*
+ * Hack -- Determine if the player is wearing an artefact ring
+ * specified by art_type, that should be an index into a_info
+ */
+bool_ check_ring(int art_type)
+{
+ int i;
+
+
+ /* We are only interested in ring slots */
+ i = INVEN_RING;
+
+ /* Scan the list of rings until we reach the end */
+ while (p_ptr->body_parts[i - INVEN_WIELD] == INVEN_RING)
+ {
+ /* Found the ring we were looking for */
+ if (p_ptr->inventory[i].k_idx && (p_ptr->inventory[i].name1 == art_type))
+ {
+ return (TRUE);
+ }
+
+ /* Next item */
+ i++;
+ }
+
+ /* Found nothing */
+ return (FALSE);
+}
+
+/*
+ * Return the symbiote's name or description.
+ */
+cptr symbiote_name(bool_ capitalize)
+{
+ object_type *o_ptr = &p_ptr->inventory[INVEN_CARRY];
+ static char buf[80];
+
+ /* Make sure there actually is a symbiote there... */
+ if (!o_ptr->k_idx)
+ {
+ strcpy(buf, "A non-existent symbiote");
+ }
+ else
+ {
+ monster_race *r_ptr = &r_info[o_ptr->pval];
+ cptr s = NULL;
+
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ /* Unique monster; no preceding "your", and ignore our name. */
+ strncpy(buf, r_name + r_ptr->name, sizeof(buf));
+ }
+ else if (o_ptr->note &&
+ (s = strstr(quark_str(o_ptr->note), "#named ")) != NULL)
+ {
+ /* We've named it. */
+ strncpy(buf, s + 7, sizeof(buf));
+ }
+ else
+ {
+ /* No special cases, just return "Your <monster type>". */
+ strcpy(buf, "your ");
+ strncpy(buf + 5, r_name + r_ptr->name, sizeof(buf) - 5);
+ }
+ }
+
+ /* Just in case... */
+ buf[sizeof(buf) - 1] = '\0';
+ if (capitalize) buf[0] = toupper(buf[0]);
+ return buf;
+}
+
+/*
+ * Use a power of the monster in symbiosis
+ */
+int use_symbiotic_power(int r_idx, bool_ great, bool_ only_number, bool_ no_cost)
+{
+ int power = -1;
+
+ int num = 0, dir = 0 , i;
+
+ int powers[96];
+
+ bool_ flag, redraw;
+
+ int ask, plev = p_ptr->lev;
+
+ char choice;
+
+ char out_val[160];
+
+ monster_race *r_ptr = &r_info[r_idx];
+
+ int rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1);
+
+ int x = p_ptr->px, y = p_ptr->py, k;
+
+ int rad;
+
+ int label;
+
+
+ /* List the monster powers -- RF4_* */
+ for (i = 0; i < 32; i++)
+ {
+ if (r_ptr->flags4 & BIT(i))
+ {
+ if (monster_powers[i].great && (!great)) continue;
+ if (!monster_powers[i].power) continue;
+ powers[num++] = i;
+ }
+ }
+
+ /* List the monster powers -- RF5_* */
+ for (i = 0; i < 32; i++)
+ {
+ if (r_ptr->flags5 & BIT(i))
+ {
+ if (monster_powers[i + 32].great && (!great)) continue;
+ if (!monster_powers[i + 32].power) continue;
+ powers[num++] = i + 32;
+ }
+ }
+
+ /* List the monster powers -- RF6_* */
+ for (i = 0; i < 32; i++)
+ {
+ if (r_ptr->flags6 & BIT(i))
+ {
+ if (monster_powers[i + 64].great && (!great)) continue;
+ if (!monster_powers[i + 64].power) continue;
+ powers[num++] = i + 64;
+ }
+ }
+
+ if (!num)
+ {
+ msg_print("You have no powers you can use.");
+ return (0);
+ }
+
+ if (only_number) return (num);
+
+ /* Nothing chosen yet */
+ flag = FALSE;
+
+ /* No redraw yet */
+ redraw = FALSE;
+
+ /* Get the last label */
+ label = (num <= 26) ? I2A(num - 1) : I2D(num - 1 - 26);
+
+ /* Build a prompt (accept all spells) */
+ /* Mega Hack -- if no_cost is false, we're actually a Possessor -dsb */
+ strnfmt(out_val, 78,
+ "(Powers a-%c, *=List, ESC=exit) Use which power of your %s? ",
+ label, (no_cost ? "symbiote" : "body"));
+
+ /* Get a spell from the user */
+ while (!flag && get_com(out_val, &choice))
+ {
+ /* Request redraw */
+ if ((choice == ' ') || (choice == '*') || (choice == '?'))
+ {
+ /* Show the list */
+ if (!redraw)
+ {
+ byte y = 1, x = 0;
+ int ctr = 0;
+ char dummy[80];
+
+ strcpy(dummy, "");
+
+ /* Show list */
+ redraw = TRUE;
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ prt ("", y++, x);
+
+ while (ctr < num)
+ {
+ monster_power *mp_ptr = &monster_powers[powers[ctr]];
+ int mana = mp_ptr->mana / 10;
+
+ if (mana > p_ptr->msp) mana = p_ptr->msp;
+
+ if (!mana) mana = 1;
+
+ label = (ctr < 26) ? I2A(ctr) : I2D(ctr - 26);
+
+ if (!no_cost)
+ {
+ strnfmt(dummy, 80, " %c) %2d %s",
+ label, mana, mp_ptr->name);
+ }
+ else
+ {
+ strnfmt(dummy, 80, " %c) %s",
+ label, mp_ptr->name);
+ }
+
+ if (ctr < 17)
+ {
+ prt(dummy, y + ctr, x);
+ }
+ else
+ {
+ prt(dummy, y + ctr - 17, x + 40);
+ }
+
+ ctr++;
+ }
+
+ if (ctr < 17)
+ {
+ prt ("", y + ctr, x);
+ }
+ else
+ {
+ prt ("", y + 17, x);
+ }
+ }
+
+ /* Hide the list */
+ else
+ {
+ /* Hide list */
+ redraw = FALSE;
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Redo asking */
+ continue;
+ }
+
+ if (choice == '\r' && num == 1)
+ {
+ choice = 'a';
+ }
+
+ if (isalpha(choice))
+ {
+ /* Note verify */
+ ask = (isupper(choice));
+
+ /* Lowercase */
+ if (ask) choice = tolower(choice);
+
+ /* Extract request */
+ i = (islower(choice) ? A2I(choice) : -1);
+ }
+ else
+ {
+ /* Can't uppercase digits XXX XXX XXX */
+ ask = FALSE;
+
+ i = choice - '0' + 26;
+ }
+
+ /* Totally Illegal */
+ if ((i < 0) || (i >= num))
+ {
+ bell();
+ continue;
+ }
+
+ /* Save the spell index */
+ power = powers[i];
+
+ /* Verify it */
+ if (ask)
+ {
+ char tmp_val[160];
+
+ /* Prompt */
+ strnfmt(tmp_val, 78, "Use %s? ", monster_powers[power].name);
+
+ /* Belay that order */
+ if (!get_check(tmp_val)) continue;
+ }
+
+ /* Stop the loop */
+ flag = TRUE;
+ }
+
+ /* Restore the screen */
+ if (redraw)
+ {
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Abort if needed */
+ if (!flag)
+ {
+ energy_use = 0;
+ return -1;
+ }
+
+ /* 'Powerful' monsters have wider radii */
+ if (r_ptr->flags2 & RF2_POWERFUL)
+ {
+ rad = 1 + (p_ptr->lev / 15);
+ }
+ else
+ {
+ rad = 1 + (p_ptr->lev / 20);
+ }
+
+
+ /* Analyse power */
+ switch (power)
+ {
+ /**** RF4 (bit position) ****/
+
+ /* SHRIEK */
+ case 0:
+ {
+ aggravate_monsters( -1);
+
+ break;
+ }
+
+ /* MULTIPLY */
+ case 1:
+ {
+ do_cmd_wiz_named_friendly(p_ptr->body_monster, FALSE);
+
+ break;
+ }
+
+ /* S_ANIMAL */
+ case 2:
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_ANIMAL, TRUE);
+
+ break;
+ }
+
+ /* ROCKET */
+ case 3:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_ROCKET, dir, p_ptr->lev * 12, 1 + (p_ptr->lev / 20));
+
+ break;
+ }
+
+ /* ARROW_1 */
+ case 4:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_ARROW, dir, damroll(1, 6));
+
+ break;
+ }
+
+ /* ARROW_2 */
+ case 5:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_ARROW, dir, damroll(3, 6));
+
+ break;
+ }
+
+ /* ARROW_3 */
+ case 6:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_ARROW, dir, damroll(5, 6));
+
+ break;
+ }
+
+ /* ARROW_4 */
+ case 7:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_ARROW, dir, damroll(7, 6));
+
+ break;
+ }
+
+ /* BR_ACID */
+ case 8:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_ACID, dir, p_ptr->lev * 5, rad);
+
+ break;
+ }
+
+ /* BR_ELEC */
+ case 9:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_ELEC, dir, p_ptr->lev * 5, rad);
+
+ break;
+ }
+
+ /* BR_FIRE */
+ case 10:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_FIRE, dir, p_ptr->lev * 5, rad);
+
+ break;
+ }
+
+ /* BR_COLD */
+ case 11:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_COLD, dir, p_ptr->lev * 5, rad);
+
+ break;
+ }
+
+ /* BR_POIS */
+ case 12:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_POIS, dir, p_ptr->lev * 5, rad);
+
+ break;
+ }
+
+ /* BR_NETH */
+ case 13:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_NETHER, dir, p_ptr->lev * 5, rad);
+
+ break;
+ }
+
+ /* BR_LITE */
+ case 14:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_LITE, dir, p_ptr->lev * 8, rad);
+
+ break;
+ }
+
+ /* BR_DARK */
+ case 15:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_DARK, dir, p_ptr->lev * 8, rad);
+
+ break;
+ }
+
+ /* BR_CONF */
+ case 16:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_CONFUSION, dir, p_ptr->lev * 8, rad);
+
+ break;
+ }
+
+ /* BR_SOUN */
+ case 17:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_SOUND, dir, p_ptr->lev * 8, rad);
+
+ break;
+ }
+
+ /* BR_CHAO */
+ case 18:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_CHAOS, dir, p_ptr->lev * 7, rad);
+
+ break;
+ }
+
+ /* BR_DISE */
+ case 19:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_DISENCHANT, dir, p_ptr->lev * 7, rad);
+
+ break;
+ }
+
+ /* BR_NEXU */
+ case 20:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_NEXUS, dir, p_ptr->lev * 5, rad);
+
+ break;
+ }
+
+ /* BR_TIME */
+ case 21:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_TIME, dir, p_ptr->lev * 3, rad);
+
+ break;
+ }
+
+ /* BR_INER */
+ case 22:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_INERTIA, dir, p_ptr->lev * 4, rad);
+
+ break;
+ }
+
+ /* BR_GRAV */
+ case 23:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_GRAVITY, dir, p_ptr->lev * 4, rad);
+
+ break;
+ }
+
+ /* BR_SHAR */
+ case 24:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_SHARDS, dir, p_ptr->lev * 8, rad);
+
+ break;
+ }
+
+ /* BR_PLAS */
+ case 25:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_PLASMA, dir, p_ptr->lev * 3, rad);
+
+ break;
+ }
+
+ /* BR_WALL */
+ case 26:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_FORCE, dir, p_ptr->lev * 4, rad);
+
+ break;
+ }
+
+ /* BR_MANA */
+ case 27:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_MANA, dir, p_ptr->lev * 5, rad);
+
+ break;
+ }
+
+ /* BA_NUKE */
+ case 28:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_NUKE, dir, p_ptr->lev * 8, 1 + (p_ptr->lev / 20));
+
+ break;
+ }
+
+ /* BR_NUKE */
+ case 29:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_NUKE, dir, p_ptr->lev * 8, 1 + (p_ptr->lev / 20));
+
+ break;
+ }
+
+ /* BA_CHAO */
+ case 30:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_CHAOS, dir, p_ptr->lev * 4, 2);
+
+ break;
+ }
+
+ /* BR_DISI */
+ case 31:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_DISINTEGRATE, dir, p_ptr->lev * 5, 1 + (p_ptr->lev / 20));
+
+ break;
+ }
+
+
+ /**** RF5 (bit position + 32) ****/
+
+ /* BA_ACID */
+ case 32:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_ACID, dir, randint(p_ptr->lev * 6) + 20, 2);
+
+ break;
+ }
+
+ /* BA_ELEC */
+ case 33:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_ELEC, dir, randint(p_ptr->lev * 3) + 20, 2);
+
+ break;
+ }
+
+ /* BA_FIRE */
+ case 34:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_FIRE, dir, randint(p_ptr->lev * 7) + 20, 2);
+
+ break;
+ }
+
+ /* BA_COLD */
+ case 35:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_COLD, dir, randint(p_ptr->lev * 3) + 20, 2);
+
+ break;
+ }
+
+ /* BA_POIS */
+ case 36:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_POIS, dir, damroll(12, 2), 2);
+
+ break;
+ }
+
+ /* BA_NETH */
+ case 37:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_NETHER, dir, randint(p_ptr->lev * 4) + 20, 2);
+
+ break;
+ }
+
+ /* BA_WATE */
+ case 38:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_WATER, dir, randint(p_ptr->lev * 4) + 20, 2);
+
+ break;
+ }
+
+ /* BA_MANA */
+ case 39:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_MANA, dir, randint(p_ptr->lev * 3) + 20, 2);
+
+ break;
+ }
+
+ /* BA_DARK */
+ case 40:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_DARK, dir, randint(p_ptr->lev * 3) + 20, 2);
+
+ break;
+ }
+
+ /* 41 DRAIN_MANA -- Not available */
+
+ /* 42 MIND_BLAST -- Not available */
+
+ /* 43 BRAIN_SMASH -- Not available */
+
+ /* CAUSE_1 */
+ case 44:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_MANA, dir, damroll(3, 8));
+
+ break;
+ }
+
+ /* CAUSE_2 */
+ case 45:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_MANA, dir, damroll(8, 8));
+
+ break;
+ }
+
+ /* CAUSE_3 */
+ case 46:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_MANA, dir, damroll(10, 15));
+
+ break;
+ }
+
+ /* CAUSE_4 */
+ case 47:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_MANA, dir, damroll(15, 15));
+
+ break;
+ }
+
+ /* BO_ACID */
+ case 48:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_ACID, dir, damroll(7, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* BO_ELEC */
+ case 49:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_ELEC, dir, damroll(4, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* BO_FIRE */
+ case 50:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_FIRE, dir, damroll(9, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* BO_COLD */
+ case 51:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_COLD, dir, damroll(6, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* BO_POIS */
+ case 52:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_POIS, dir, damroll(7, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* BO_NETH */
+ case 53:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_NETHER, dir, damroll(5, 5) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* BO_WATE */
+ case 54:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_WATER, dir, damroll(10, 10) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* BO_MANA */
+ case 55:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_MANA, dir, damroll(3, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* BO_PLAS */
+ case 56:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_PLASMA, dir, damroll(8, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* BO_ICEE */
+ case 57:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_ICE, dir, damroll(6, 6) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* MISSILE */
+ case 58:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_MISSILE, dir, damroll(2, 6) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* SCARE */
+ case 59:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fear_monster(dir, plev);
+
+ break;
+ }
+
+ /* BLIND */
+ case 60:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_CONFUSION, dir, damroll(1, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* CONF */
+ case 61:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_CONFUSION, dir, damroll(7, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* SLOW */
+ case 62:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_OLD_SLOW, dir, damroll(6, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+ /* HOLD */
+ case 63:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_OLD_SLEEP, dir, damroll(5, 8) + (p_ptr->lev / 3));
+
+ break;
+ }
+
+
+ /**** RF6 (bit position + 64) ****/
+
+ /* HASTE */
+ case 64:
+ {
+ if (!p_ptr->fast)
+ {
+ (void)set_fast(randint(20 + (plev) ) + plev, 10);
+ }
+ else
+ {
+ (void)set_fast(p_ptr->fast + randint(5), 10);
+ }
+
+ break;
+ }
+
+ /* HAND_DOOM */
+ case 65:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_bolt(GF_MANA, dir, damroll(10, 8) + (p_ptr->lev));
+
+ break;
+ }
+
+ /* HEAL */
+ case 66:
+ {
+ hp_player(damroll(8, 5));
+
+ break;
+ }
+
+ /* S_ANIMALS */
+ case 67:
+ {
+ for (k = 0; k < 4; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_ANIMAL, TRUE);
+ }
+
+ break;
+ }
+
+ /* BLINK */
+ case 68:
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("No teleport on special levels...");
+ break;
+ }
+
+ teleport_player(10);
+
+ break;
+ }
+
+ /* TPORT */
+ case 69:
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("No teleport on special levels...");
+ break;
+ }
+
+ teleport_player(plev * 5);
+
+ break;
+ }
+
+ /* TELE_TO */
+ case 70:
+ {
+ int ii, ij;
+
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("No teleport on special levels...");
+ break;
+ }
+
+ msg_print("You go between.");
+
+ if (!tgt_pt(&ii, &ij)) break;
+
+ p_ptr->energy -= 60 - plev;
+
+ if (!cave_empty_bold(ij, ii) ||
+ (cave[ij][ii].info & CAVE_ICKY) ||
+ (distance(ij, ii, p_ptr->py, p_ptr->px) > plev * 20 + 2))
+ {
+ msg_print("You fail to show the destination correctly!");
+ p_ptr->energy -= 100;
+ teleport_player(10);
+ }
+ else teleport_player_to(ij, ii);
+
+ break;
+ }
+
+ /* TELE_AWAY */
+ case 71:
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("No teleport on special levels...");
+ break;
+ }
+
+ if (!get_aim_dir(&dir)) break;
+
+ (void)fire_beam(GF_AWAY_ALL, dir, plev);
+
+ break;
+ }
+
+ /* TELE_LEVEL */
+ case 72:
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("No teleport on special levels...");
+ break;
+ }
+
+ teleport_player_level();
+
+ break;
+ }
+
+ /* DARKNESS */
+ case 73:
+ {
+ (void)project( -1, 3, p_ptr->py, p_ptr->px, 0, GF_DARK_WEAK,
+ PROJECT_GRID | PROJECT_KILL);
+
+ /* Unlite the room */
+ unlite_room(p_ptr->py, p_ptr->px);
+
+ break;
+ }
+
+ /* TRAPS */
+ case 74:
+ {
+ trap_creation();
+
+ break;
+ }
+
+ /* 75 FORGET -- Not available */
+
+ /* ANIM_DEAD -- Use the same code as the nether spell */
+ case 76:
+ {
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_RAISE, dir, 1, 0);
+
+ break;
+ }
+
+ /* 77 S_BUG -- Not available, well we do that anyway ;) */
+
+ /* 78 S_RNG -- Not available, who dares? */
+
+ /* S_THUNDERLORD */
+ case 79:
+ {
+ for (k = 0; k < 1; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_THUNDERLORD, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_KIN -- Summon Kin, because we code bugs :) */
+ case 80:
+ {
+ /* Big hack */
+ summon_kin_type = r_ptr->d_char;
+
+ for (k = 0; k < 6; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_KIN, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_HI_DEMON */
+ case 81:
+ {
+ for (k = 0; k < 1; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_HI_DEMON, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_MONSTER */
+ case 82:
+ {
+ for (k = 0; k < 1; k++)
+ {
+ summon_specific_friendly(y, x, rlev, 0, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_MONSTERS */
+ case 83:
+ {
+ for (k = 0; k < 6; k++)
+ {
+ summon_specific_friendly(y, x, rlev, 0, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_ANT */
+ case 84:
+ {
+ for (k = 0; k < 6; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_ANT, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_SPIDER */
+ case 85:
+ {
+ for (k = 0; k < 6; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_SPIDER, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_HOUND */
+ case 86:
+ {
+ for (k = 0; k < 6; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_HOUND, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_HYDRA */
+ case 87:
+ {
+ for (k = 0; k < 6; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_HYDRA, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_ANGEL */
+ case 88:
+ {
+ for (k = 0; k < 1; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_ANGEL, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_DEMON */
+ case 89:
+ {
+ for (k = 0; k < 1; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_DEMON, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_UNDEAD */
+ case 90:
+ {
+ for (k = 0; k < 1; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_UNDEAD, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_DRAGON */
+ case 91:
+ {
+ for (k = 0; k < 1; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_DRAGON, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_HI_UNDEAD */
+ case 92:
+ {
+ for (k = 0; k < 8; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_HI_UNDEAD_NO_UNIQUES, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_HI_DRAGON */
+ case 93:
+ {
+ for (k = 0; k < 8; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_HI_DRAGON_NO_UNIQUES, TRUE);
+ }
+
+ break;
+ }
+
+ /* S_WRAITH */
+ case 94:
+ {
+ for (k = 0; k < 8; k++)
+ {
+ summon_specific_friendly(y, x, rlev, SUMMON_WRAITH, TRUE);
+ }
+
+ break;
+ }
+
+ /* 95 S_UNIQUE -- Not available */
+ }
+
+ /* Take some SP */
+ if (!no_cost)
+ {
+ int chance, pchance;
+
+ chance = (monster_powers[power].mana + r_ptr->level);
+ pchance = adj_str_wgt[p_ptr->stat_ind[A_WIS]] / 2 + get_skill(SKILL_POSSESSION);
+
+ if (rand_int(chance) >= pchance)
+ {
+ int m = monster_powers[power].mana / 10;
+
+ if (m > p_ptr->msp) m = p_ptr->msp;
+ if (!m) m = 1;
+
+ p_ptr->csp -= m;
+ }
+ }
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ return (num);
+}
+
+/*
+ * Schooled magic
+ */
+
+/*
+ * Find a spell in any books/objects
+ */
+static int hack_force_spell = -1;
+static object_type *hack_force_spell_obj = NULL;
+bool_ get_item_hook_find_spell(int *item)
+{
+ int i, spell;
+ char buf[80];
+ char buf2[100];
+
+ strcpy(buf, "Manathrust");
+ if (!get_string("Spell name? ", buf, 79))
+ return FALSE;
+ sprintf(buf2, "return find_spell(\"%s\")", buf);
+ spell = exec_lua(buf2);
+ if (spell == -1) return FALSE;
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Must we wield it ? */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if ((wield_slot(o_ptr) != -1) && (i < INVEN_WIELD) && (f5 & TR5_WIELD_CAST)) continue;
+
+ /* Is it a non-book? */
+ if (!is_school_book(o_ptr))
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Extract object flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if ((f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 == spell))
+ {
+ *item = i;
+ hack_force_spell = spell;
+ hack_force_spell_obj = o_ptr;
+ return TRUE;
+ }
+ }
+ /* A random book ? */
+ else if ((o_ptr->sval == 255) && (o_ptr->pval == spell))
+ {
+ *item = i;
+ hack_force_spell = spell;
+ hack_force_spell_obj = o_ptr;
+ return TRUE;
+ }
+ /* A normal book */
+ else if (o_ptr->sval != 255)
+ {
+ sprintf(buf2, "return spell_in_book(%d, %d)", o_ptr->sval, spell);
+ if (exec_lua(buf2))
+ {
+ *item = i;
+ hack_force_spell = spell;
+ hack_force_spell_obj = o_ptr;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Get a spell from a book
+ */
+s32b get_school_spell(cptr do_what, cptr check_fct, s16b force_book)
+{
+ int i, item;
+ s32b spell = -1;
+ int num = 0;
+ s32b where = 1;
+ int ask;
+ bool_ flag, redraw;
+ char choice;
+ char out_val[160];
+ char buf2[40];
+ char buf3[40];
+ object_type *o_ptr, forge;
+ int tmp;
+ int sval, pval;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ hack_force_spell = -1;
+ hack_force_spell_obj = NULL;
+
+ /* Ok do we need to ask for a book ? */
+ if (!force_book)
+ {
+ get_item_extra_hook = get_item_hook_find_spell;
+ item_tester_hook = hook_school_spellable;
+ sprintf(buf2, "You have no book to %s from", do_what);
+ sprintf(buf3, "%s from which book?", do_what);
+ if (!get_item(&item, buf3, buf2, USE_INVEN | USE_EQUIP | USE_EXTRA )) return -1;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* If it can be wielded, it must */
+ if ((wield_slot(o_ptr) != -1) && (item < INVEN_WIELD) && (f5 & TR5_WIELD_CAST))
+ {
+ msg_format("You cannot %s from that object; it must be wielded first.", do_what);
+ return -1;
+ }
+ }
+ else
+ {
+ o_ptr = &forge;
+ o_ptr->tval = TV_BOOK;
+ o_ptr->sval = force_book;
+ o_ptr->pval = 0;
+ }
+
+ if (repeat_pull(&tmp))
+ {
+ return tmp;
+ }
+
+ /* Nothing chosen yet */
+ flag = FALSE;
+
+ /* No redraw yet */
+ redraw = FALSE;
+
+ /* Show choices */
+ if (show_choices)
+ {
+ /* Window stuff */
+ window_stuff();
+ }
+
+ /* No spell to cast by default */
+ spell = -1;
+
+ /* Is it a random book, or something else ? */
+ if (is_school_book(o_ptr))
+ {
+ sval = o_ptr->sval;
+ pval = o_ptr->pval;
+ }
+ else
+ {
+ sval = 255;
+ pval = o_ptr->pval2;
+ }
+
+ if (hack_force_spell == -1)
+ {
+ num = exec_lua(format("return book_spells_num(%d)", sval));
+
+ /* Build a prompt (accept all spells) */
+ strnfmt(out_val, 78, "(Spells %c-%c, Descs %c-%c, *=List, ESC=exit) %^s which spell? ",
+ I2A(0), I2A(num - 1), I2A(0) - 'a' + 'A', I2A(num - 1) - 'a' + 'A', do_what);
+
+ /* Get a spell from the user */
+ while (!flag && get_com(out_val, &choice))
+ {
+ /* Request redraw */
+ if (((choice == ' ') || (choice == '*') || (choice == '?')))
+ {
+ /* Show the list */
+ if (!redraw)
+ {
+ /* Show list */
+ redraw = TRUE;
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Display a list of spells */
+ call_lua("print_book", "(d,d,O)", "d", sval, pval, o_ptr, &where);
+ }
+
+ /* Hide the list */
+ else
+ {
+ /* Hide list */
+ redraw = FALSE;
+ where = 1;
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Redo asking */
+ continue;
+ }
+
+
+ /* Note verify */
+ ask = (isupper(choice));
+
+ /* Lowercase */
+ if (ask) choice = tolower(choice);
+
+ /* Extract request */
+ i = (islower(choice) ? A2I(choice) : -1);
+
+ /* Totally Illegal */
+ if ((i < 0) || (i >= num))
+ {
+ bell();
+ continue;
+ }
+
+ /* Verify it */
+ if (ask)
+ {
+ /* Show the list */
+ if (!redraw)
+ {
+ /* Show list */
+ redraw = TRUE;
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_load();
+ Term_save();
+
+ }
+ /* Rstore the screen */
+ else
+ {
+ /* Restore the screen */
+ Term_load();
+ }
+
+ /* Display a list of spells */
+ call_lua("print_book", "(d,d,O)", "d", sval, pval, o_ptr, &where);
+ exec_lua(format("print_spell_desc(spell_x(%d, %d, %d), %d)", sval, pval, i, where));
+ }
+ else
+ {
+ s32b ok;
+
+ /* Save the spell index */
+ spell = exec_lua(format("return spell_x(%d, %d, %d)", sval, pval, i));
+
+ /* Do we need to do some pre test */
+ call_lua(check_fct, "(d,O)", "d", spell, o_ptr, &ok);
+
+ /* Require "okay" spells */
+ if (!ok)
+ {
+ bell();
+ msg_format("You may not %s that spell.", do_what);
+ spell = -1;
+ continue;
+ }
+
+ /* Stop the loop */
+ flag = TRUE;
+ }
+ }
+ }
+ else
+ {
+ s32b ok;
+
+ /* Require "okay" spells */
+ call_lua(check_fct, "(d, O)", "d", hack_force_spell, hack_force_spell_obj, &ok);
+ if (ok)
+ {
+ flag = TRUE;
+ spell = hack_force_spell;
+ }
+ else
+ {
+ bell();
+ msg_format("You may not %s that spell.", do_what);
+ spell = -1;
+ }
+ }
+
+
+ /* Restore the screen */
+ if (redraw)
+ {
+ Term_load();
+ character_icky = FALSE;
+ }
+
+
+ /* Show choices */
+ if (show_choices)
+ {
+ /* Window stuff */
+ window_stuff();
+ }
+
+
+ /* Abort if needed */
+ if (!flag) return -1;
+
+ tmp = spell;
+ repeat_push(tmp);
+ return spell;
+}
+
+void cast_school_spell()
+{
+ int spell;
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+ spell = get_school_spell("cast", "is_ok_spell", 0);
+
+ /* Actualy cast the choice */
+ if (spell != -1)
+ {
+ exec_lua(format("cast_school_spell(%d, spell(%d))", spell, spell));
+ }
+}
+
+void browse_school_spell(int book, int pval, object_type *o_ptr)
+{
+ int i;
+ int num = 0, where = 1;
+ int ask;
+ char choice;
+ char out_val[160];
+
+ /* Show choices */
+ if (show_choices)
+ {
+ /* Window stuff */
+ window_stuff();
+ }
+
+ num = exec_lua(format("return book_spells_num(%d)", book));
+
+ /* Build a prompt (accept all spells) */
+ strnfmt(out_val, 78, "(Spells %c-%c, ESC=exit) cast which spell? ",
+ I2A(0), I2A(num - 1));
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Display a list of spells */
+ call_lua("print_book", "(d,d,O)", "d", book, pval, o_ptr, &where);
+
+ /* Get a spell from the user */
+ while (get_com(out_val, &choice))
+ {
+ /* Display a list of spells */
+ call_lua("print_book", "(d,d,O)", "d", book, pval, o_ptr, &where);
+
+ /* Note verify */
+ ask = (isupper(choice));
+
+ /* Lowercase */
+ if (ask) choice = tolower(choice);
+
+ /* Extract request */
+ i = (islower(choice) ? A2I(choice) : -1);
+
+ /* Totally Illegal */
+ if ((i < 0) || (i >= num))
+ {
+ bell();
+ continue;
+ }
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Display a list of spells */
+ call_lua("print_book", "(d,d,O)", "d", book, pval, o_ptr, &where);
+ exec_lua(format("print_spell_desc(spell_x(%d, %d, %d), %d)", book, pval, i, where));
+ }
+
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+
+ /* Show choices */
+ if (show_choices)
+ {
+ /* Window stuff */
+ window_stuff();
+ }
+}
+
+/* Can it contains a schooled spell ? */
+static bool_ hook_school_can_spellable(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Extract object flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if ((f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 == -1))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Copy a spell from a bok to an object
+ */
+void do_cmd_copy_spell()
+{
+ int spell = get_school_spell("copy", "is_ok_spell", 0);
+ int item;
+ object_type *o_ptr;
+
+ if (spell == -1) return;
+
+ /* Spells that cannot be randomly created cannot be copied */
+ if (exec_lua(format("return can_spell_random(%d)", spell)) == FALSE)
+ {
+ msg_print("This spell cannot be copied.");
+ return;
+ }
+
+ item_tester_hook = hook_school_can_spellable;
+ if (!get_item(&item, "Copy to which object? ", "You have no object to copy to.", (USE_INVEN | USE_EQUIP))) return;
+ o_ptr = get_object(item);
+
+ msg_print("You copy the spell!");
+ o_ptr->pval2 = spell;
+ inven_item_describe(item);
+}
+
+/*
+ * Finds a spell by name, optimized for speed
+ */
+int find_spell(char *name)
+{
+ int oldtop, spell;
+ oldtop = lua_gettop(L);
+
+ lua_getglobal(L, "find_spell");
+ tolua_pushstring(L, name);
+
+ /* Call the function */
+ if (lua_call(L, 1, 1))
+ {
+ cmsg_format(TERM_VIOLET, "ERROR in lua_call while calling 'find_spell'.");
+ lua_settop(L, oldtop);
+ return -1;
+ }
+
+ spell = tolua_getnumber(L, -(lua_gettop(L) - oldtop), -1);
+
+ lua_settop(L, oldtop);
+
+ return spell;
+}
diff --git a/src/cmd6.c b/src/cmd6.c
new file mode 100644
index 00000000..db89c465
--- /dev/null
+++ b/src/cmd6.c
@@ -0,0 +1,7731 @@
+/* File: cmd6.c */
+
+/* Purpose: Object commands */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Forward declare
+ */
+static bool_ activate_spell(object_type * o_ptr, byte choice);
+
+
+/*
+ * General function to find an item by its name
+ */
+cptr get_item_hook_find_obj_what;
+bool_ get_item_hook_find_obj(int *item)
+{
+ int i;
+ char buf[80];
+ char buf2[100];
+
+ strcpy(buf, "");
+ if (!get_string(get_item_hook_find_obj_what, buf, 79))
+ return FALSE;
+
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ if (!item_tester_okay(o_ptr)) continue;
+
+ object_desc(buf2, o_ptr, -1, 0);
+ if (!strcmp(buf, buf2))
+ {
+ *item = i;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ * This file includes code for eating food, drinking potions,
+ * reading scrolls, aiming wands, using staffs, zapping rods,
+ * and activating artifacts.
+ *
+ * In all cases, if the player becomes "aware" of the item's use
+ * by testing it, mark it as "aware" and reward some experience
+ * based on the object's level, always rounding up. If the player
+ * remains "unaware", mark that object "kind" as "tried".
+ *
+ * This code now correctly handles the unstacking of wands, staffs,
+ * and rods. Note the overly paranoid warning about potential pack
+ * overflow, which allows the player to use and drop a stacked item.
+ *
+ * In all "unstacking" scenarios, the "used" object is "carried" as if
+ * the player had just picked it up. In particular, this means that if
+ * the use of an item induces pack overflow, that item will be dropped.
+ *
+ * For simplicity, these routines induce a full "pack reorganization"
+ * which not only combines similar items, but also reorganizes various
+ * items to obey the current "sorting" method. This may require about
+ * 400 item comparisons, but only occasionally.
+ *
+ * There may be a BIG problem with any "effect" that can cause "changes"
+ * to the p_ptr->inventory. For example, a "scroll of recharging" can cause
+ * a wand/staff to "disappear", moving the p_ptr->inventory up. Luckily, the
+ * scrolls all appear BEFORE the staffs/wands, so this is not a problem.
+ * But, for example, a "staff of recharging" could cause MAJOR problems.
+ * In such a case, it will be best to either (1) "postpone" the effect
+ * until the end of the function, or (2) "change" the effect, say, into
+ * giving a staff "negative" charges, or "turning a staff into a stick".
+ * It seems as though a "rod of recharging" might in fact cause problems.
+ * The basic problem is that the act of recharging (and destroying) an
+ * item causes the inducer of that action to "move", causing "o_ptr" to
+ * no longer point at the correct item, with horrifying results.
+ *
+ * Note that food/potions/scrolls no longer use bit-flags for effects,
+ * but instead use the "sval" (which is also used to sort the objects).
+ */
+
+
+/*
+ * Determine the effects of eating a corpse. A corpse can be
+ * eaten whole or cut into pieces for later.
+ */
+static void corpse_effect(object_type *o_ptr, bool_ cutting)
+{
+ monster_race *r_ptr = &r_info[o_ptr->pval2];
+
+ /* Assume no bad effects */
+ bool_ harmful = FALSE;
+
+ byte method, effect, d_dice, d_side;
+
+ int i, dam, idam = 0, mdam, brpow, brdam = 0;
+
+
+ /* How much of the monster's breath attack remains */
+ if (o_ptr->pval <= r_ptr->weight)
+ {
+ brpow = 0;
+ }
+ else
+ {
+ brpow = (o_ptr->pval - r_ptr->weight) / 5;
+ if (brpow > (r_ptr->weight / 5)) brpow = r_ptr->weight / 5;
+ }
+
+ if (o_ptr->weight <= 0) o_ptr->weight = 1;
+ if (o_ptr->pval <= 0) o_ptr->pval = 1;
+
+ /*
+ * The breath is only discharged by accident or by slicing off pieces
+ * of meat, and only by corpses.
+ */
+ if ((o_ptr->sval != SV_CORPSE_CORPSE) ||
+ (rand_int(o_ptr->weight / 5) && !cutting)) brpow = 0;
+
+ /* Immediate effects - poison, acid, fire, etc. */
+ if (!cutting)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ /* skip empty blow slot */
+ if (!r_ptr->blow[i].method) continue;
+
+ method = r_ptr->blow[i].method;
+ effect = r_ptr->blow[i].effect;
+ d_dice = r_ptr->blow[i].d_dice;
+ d_side = r_ptr->blow[i].d_side;
+ dam = damroll(d_dice, d_side) * o_ptr->pval / o_ptr->weight / 2;
+ idam = damroll(d_dice, d_side) *
+ ((o_ptr->weight / o_ptr->pval > 2) ?
+ o_ptr->weight / o_ptr->pval : 2);
+ mdam = maxroll(d_dice, d_side) * 2;
+
+ /* Analyse method */
+ switch (method)
+ {
+ /* Methods that are meaningless after death */
+ case RBM_BITE:
+ case RBM_STING:
+ case RBM_ENGULF:
+ case RBM_DROOL:
+ case RBM_SPIT:
+ case RBM_GAZE:
+ case RBM_WAIL:
+ case RBM_BEG:
+ case RBM_INSULT:
+ case RBM_MOAN:
+ {
+ continue;
+ }
+ }
+
+ /* Analyse effect */
+ switch (effect)
+ {
+ /* Effects that are meaningless after death */
+ case RBE_HURT:
+ case RBE_UN_BONUS:
+ case RBE_UN_POWER:
+ case RBE_EAT_GOLD:
+ case RBE_EAT_ITEM:
+ case RBE_EAT_FOOD:
+ case RBE_EAT_LITE:
+ case RBE_ELEC:
+ case RBE_COLD:
+ case RBE_SHATTER:
+ {
+ break;
+ }
+
+ case RBE_POISON:
+ {
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ set_poisoned(p_ptr->poisoned + dam + idam + 10);
+ harmful = TRUE;
+ }
+
+ break;
+ }
+
+ case RBE_ACID:
+ {
+ /* Total Immunity */
+ if (!(p_ptr->immune_acid || (dam <= 0)))
+ {
+ /* Resist the damage */
+ if (p_ptr->resist_acid) dam = (dam + 2) / 3;
+ if (p_ptr->oppose_acid) dam = (dam + 2) / 3;
+
+ /* Take damage */
+ take_hit(dam, "acidic food");
+ harmful = TRUE;
+ }
+ else
+ {
+ set_oppose_acid(p_ptr->oppose_acid + idam);
+ }
+
+ break;
+ }
+
+ case RBE_FIRE:
+ {
+ /* Totally immune */
+ if (p_ptr->immune_fire || (dam <= 0))
+ {
+ /* Resist the damage */
+ if (p_ptr->resist_fire) dam = (dam + 2) / 3;
+ if (p_ptr->oppose_fire) dam = (dam + 2) / 3;
+
+ /* Take damage */
+ take_hit(dam, "a fiery meal");
+ harmful = TRUE;
+ }
+ else
+ {
+ set_oppose_fire(p_ptr->oppose_fire + idam);
+ }
+
+ break;
+ }
+
+ case RBE_BLIND:
+ {
+ if (!p_ptr->resist_blind)
+ {
+ set_blind(p_ptr->blind + dam * 2 + idam * 2 + 20);
+ }
+
+ break;
+ }
+
+ case RBE_CONFUSE:
+ {
+ if (!p_ptr->resist_conf)
+ {
+ set_confused(p_ptr->confused + dam + idam + 10);
+ }
+ if (!p_ptr->resist_chaos && rand_int(mdam - dam))
+ {
+ set_image(p_ptr->image + dam * 10 + idam * 10 + 100);
+ }
+
+ break;
+ }
+
+ case RBE_HALLU:
+ {
+ if (!p_ptr->resist_chaos && rand_int(mdam - dam))
+ {
+ set_image(p_ptr->image + dam * 10 + idam * 10 + 50);
+ }
+
+ break;
+ }
+
+ case RBE_TERRIFY:
+ {
+ if (!p_ptr->resist_fear)
+ {
+ set_afraid(p_ptr->afraid + dam + idam + 10);
+ }
+
+ break;
+ }
+
+ case RBE_PARALYZE:
+ {
+ if (!p_ptr->free_act)
+ {
+ set_paralyzed(p_ptr->paralyzed + dam + idam + 10);
+ }
+
+ break;
+ }
+
+ case RBE_LOSE_STR:
+ {
+ do_dec_stat(A_STR, STAT_DEC_NORMAL);
+
+ break;
+ }
+
+ case RBE_LOSE_INT:
+ {
+ do_dec_stat(A_INT, STAT_DEC_NORMAL);
+
+ break;
+ }
+
+ case RBE_LOSE_WIS:
+ {
+ do_dec_stat(A_WIS, STAT_DEC_NORMAL);
+
+ break;
+ }
+
+ case RBE_LOSE_DEX:
+ {
+ do_dec_stat(A_DEX, STAT_DEC_NORMAL);
+
+ break;
+ }
+
+ case RBE_LOSE_CON:
+ {
+ do_dec_stat(A_CON, STAT_DEC_NORMAL);
+
+ break;
+ }
+
+ case RBE_LOSE_CHR:
+ {
+ do_dec_stat(A_CHR, STAT_DEC_NORMAL);
+
+ break;
+ }
+
+ /* Don't eat Morgoth's corpse :) */
+ case RBE_LOSE_ALL:
+ {
+ do_dec_stat(A_STR, STAT_DEC_NORMAL);
+ do_dec_stat(A_INT, STAT_DEC_NORMAL);
+ do_dec_stat(A_WIS, STAT_DEC_NORMAL);
+ do_dec_stat(A_DEX, STAT_DEC_NORMAL);
+ do_dec_stat(A_CON, STAT_DEC_NORMAL);
+ do_dec_stat(A_CHR, STAT_DEC_NORMAL);
+ o_ptr->pval = 1;
+
+ break;
+ }
+
+ case RBE_SANITY:
+ {
+ msg_print("You feel your sanity slipping away!");
+ take_sanity_hit(dam, "eating an insane monster");
+
+ break;
+ }
+
+ /* Unlife is bad to eat */
+ case RBE_EXP_10:
+ {
+ msg_print("A black aura surrounds the corpse!");
+
+ if (p_ptr->hold_life && (rand_int(100) < 50))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(10, 6) +
+ (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+
+ o_ptr->pval = 1;
+
+ break;
+ }
+
+ case RBE_EXP_20:
+ {
+ msg_print("A black aura surrounds the corpse!");
+
+ if (p_ptr->hold_life && (rand_int(100) < 50))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(20, 6) +
+ (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+
+ o_ptr->pval = 1;
+
+ break;
+ }
+
+ case RBE_EXP_40:
+ {
+ msg_print("A black aura surrounds the corpse!");
+
+ if (p_ptr->hold_life && (rand_int(100) < 50))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(40, 6) +
+ (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+
+ o_ptr->pval = 1;
+
+ break;
+ }
+
+ case RBE_EXP_80:
+ {
+ msg_print("A black aura surrounds the corpse!");
+
+ if (p_ptr->hold_life && (rand_int(100) < 50))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(80, 6) +
+ (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+
+ o_ptr->pval = 1;
+
+ break;
+ }
+ }
+ }
+ } /* if (!cutting) */
+
+
+ /*
+ * The organ that supplies breath attacks is not
+ * immediately emptied upon death, although some types
+ * of breath have no effect.
+ * AMHD's make rather risky meals, and deadly snacks.
+ */
+
+ /* Acid */
+ if (r_ptr->flags4 & RF4_BR_ACID && brpow > 0)
+ {
+ brdam = ((brpow / 3) > 1600 ? 1600 : (brpow / 3));
+
+ msg_print("You are hit by a gush of acid!");
+
+ /* Total Immunity */
+ if (!(p_ptr->immune_acid || (brdam <= 0)))
+ {
+ /* Take damage */
+ acid_dam(brdam, "a gush of acid");
+ harmful = TRUE;
+ }
+ o_ptr->pval = 1;
+ }
+ else if (r_ptr->flags4 & RF4_BR_ACID)
+ {
+ set_oppose_acid(p_ptr->oppose_acid + rand_int(10) + 10);
+ }
+
+ /* Electricity */
+ if (r_ptr->flags4 & RF4_BR_ELEC && brpow > 0)
+ {
+ brdam = ((brpow / 3) > 1600 ? 1600 : (brpow / 3));
+
+ msg_print("You receive a heavy shock!");
+
+ /* Total Immunity */
+ if (!(p_ptr->immune_elec || (brdam <= 0)))
+ {
+ /* Take damage */
+ elec_dam(brdam, "an electric shock");
+ harmful = TRUE;
+ }
+ o_ptr->weight = o_ptr->weight - brpow;
+ o_ptr->pval = o_ptr->weight;
+ }
+ else if (r_ptr->flags4 & RF4_BR_ELEC)
+ {
+ set_oppose_elec(p_ptr->oppose_elec + rand_int(10) + 10);
+ }
+
+ /* Fire */
+ if (r_ptr->flags4 & RF4_BR_FIRE && brpow > 0)
+ {
+ brdam = ((brpow / 3) > 1600 ? 1600 : (brpow / 3));
+
+ msg_print("Roaring flames engulf you!");
+
+ /* Total Immunity */
+ if (!(p_ptr->immune_fire || (brdam <= 0)))
+ {
+ /* Take damage */
+ fire_dam(brdam, "an explosion");
+ harmful = TRUE;
+ }
+ o_ptr->pval = 1;
+ }
+ else if (r_ptr->flags4 & RF4_BR_FIRE)
+ {
+ set_oppose_fire(p_ptr->oppose_fire + rand_int(10) + 10);
+ }
+
+ /* Cold */
+ if (r_ptr->flags4 & RF4_BR_COLD && brpow > 0)
+ {
+ brdam = ((brpow / 3) > 1600 ? 1600 : (brpow / 3));
+
+ msg_print("You are caught in a freezing liquid!");
+
+ /* Total Immunity */
+ if (!(p_ptr->immune_cold || (brdam <= 0)))
+ {
+ /* Take damage */
+ cold_dam(brdam, "a chilling blast");
+ harmful = TRUE;
+ }
+ o_ptr->weight = o_ptr->weight - brpow;
+ o_ptr->pval = o_ptr->weight;
+ }
+ else if (r_ptr->flags4 & RF4_BR_COLD)
+ {
+ set_oppose_cold(p_ptr->oppose_cold + rand_int(10) + 10);
+ }
+
+ /* Poison */
+ if (r_ptr->flags4 & RF4_BR_POIS && brpow > 0)
+ {
+ brdam = ((brpow / 3) > 800 ? 800 : (brpow / 3));
+
+ msg_print("You are surrounded by toxic gases!");
+
+ /* Resist the damage */
+ if (p_ptr->resist_pois) brdam = (brdam + 2) / 3;
+ if (p_ptr->oppose_pois) brdam = (brdam + 2) / 3;
+
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ (void)set_poisoned(p_ptr->poisoned + rand_int(brdam) + 10);
+ }
+
+ /* Take damage */
+ take_hit(brdam, "toxic gases");
+ o_ptr->weight = o_ptr->weight - brpow;
+ o_ptr->pval = o_ptr->weight;
+ harmful = TRUE;
+ }
+
+ /* Nether */
+ if (r_ptr->flags4 & RF4_BR_NETH && brpow > 0)
+ {
+ brdam = ((brpow / 6) > 550 ? 550 : (brpow / 6));
+
+ msg_print("A black aura surrounds the corpse!");
+
+ if (p_ptr->resist_neth)
+ {
+ brdam *= 6;
+ brdam /= (randint(6) + 6);
+ }
+ else
+ {
+ if (p_ptr->hold_life && (rand_int(100) < 75))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(200 + (p_ptr->exp / 1000) * MON_DRAIN_LIFE);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(200 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
+ }
+ }
+
+ /* Take damage */
+ take_hit(brdam, "an unholy blast");
+ harmful = TRUE;
+ o_ptr->weight = o_ptr->weight - brpow;
+ o_ptr->pval = o_ptr->weight;
+ }
+
+ /* Confusion */
+ if (r_ptr->flags4 & RF4_BR_CONF && brpow > 0)
+ {
+ msg_print("A strange liquid splashes on you!");
+
+ if (!p_ptr->resist_conf)
+ {
+ set_confused(p_ptr->confused + brdam + idam + 10);
+ }
+ o_ptr->weight = o_ptr->weight - brpow;
+ o_ptr->pval = o_ptr->weight;
+ }
+
+ /* Chaos */
+ if (r_ptr->flags4 & RF4_BR_CHAO && brpow > 0)
+ {
+ brdam = ((brpow / 6) > 600 ? 600 : (brpow / 6));
+
+ msg_print("A swirling cloud surrounds you!");
+
+ if (p_ptr->resist_chaos)
+ {
+ brdam *= 6;
+ brdam /= (randint(6) + 6);
+ }
+
+ if (!p_ptr->resist_conf)
+ {
+ (void)set_confused(p_ptr->confused + rand_int(20) + 10);
+ }
+
+ if (!p_ptr->resist_chaos)
+ {
+ (void)set_image(p_ptr->image + randint(10));
+ }
+
+ if (!p_ptr->resist_neth && !p_ptr->resist_chaos)
+ {
+ if (p_ptr->hold_life && (rand_int(100) < 75))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(500 + (p_ptr->exp / 1000) * MON_DRAIN_LIFE);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(5000 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
+ }
+ }
+
+ /* Take damage */
+ take_hit(brdam, "chaotic forces");
+ o_ptr->pval = 1;
+ }
+
+ /* Disenchantment */
+ if (r_ptr->flags4 & RF4_BR_DISE && brpow > 0)
+ {
+ brdam = ((brpow / 6) > 500 ? 500 : (brpow / 6));
+
+ msg_print("You are blasted by raw mana!");
+
+ if (p_ptr->resist_disen)
+ {
+ brdam *= 6;
+ brdam /= (randint(6) + 6);
+ }
+ else
+ {
+ (void)apply_disenchant(0);
+ }
+
+ /* Take damage */
+ take_hit(brdam, "raw mana");
+ o_ptr->pval = 1;
+ }
+
+ /* Plasma */
+ if (r_ptr->flags4 & RF4_BR_PLAS && brpow > 0)
+ {
+ brdam = ((brpow / 6) > 150 ? 150 : (brpow / 6));
+
+ msg_print("Searing flames engulf the corpse!");
+
+ /* Resist the damage */
+ if (p_ptr->resist_fire || p_ptr->oppose_fire) brdam = (brdam + 2) / 3;
+
+ if (!p_ptr->resist_sound)
+ {
+ int k = (randint((brdam > 40) ? 35 : (brdam * 3 / 4 + 5)));
+ (void)set_stun(p_ptr->stun + k);
+ }
+
+ /* Take damage */
+ take_hit(brdam, "an explosion");
+ harmful = TRUE;
+ o_ptr->pval = 1;
+ }
+
+ /* Hack -- Jellies are immune to acid only if they are already acidic */
+ if (strchr("j", r_ptr->d_char) && (r_ptr->flags3 & RF3_IM_ACID))
+ {
+ dam = damroll(8, 8);
+
+ /* Total Immunity */
+ if (!(p_ptr->immune_acid || (dam <= 0)))
+ {
+ /* Resist the damage */
+ if (p_ptr->resist_acid) dam = (dam + 2) / 3;
+ if (p_ptr->oppose_acid) dam = (dam + 2) / 3;
+
+ /* Take damage */
+ take_hit(dam, "acidic food");
+ }
+ harmful = TRUE;
+ }
+
+ /*
+ * Hack -- Jellies, kobolds, spiders, icky things, molds, and mushrooms
+ * are immune to poison because their body already contains
+ * poisonous chemicals.
+ */
+ if (strchr("ijkmS,", r_ptr->d_char) && (r_ptr->flags3 & RF3_IM_POIS))
+ {
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ set_poisoned(p_ptr->poisoned + rand_int(15) + 10);
+ }
+ harmful = TRUE;
+ }
+
+ /*
+ * Bad effects override good effects
+ * and hacked-up corpses lose intrinsics.
+ */
+ if (!harmful && !cutting && (o_ptr->sval != SV_CORPSE_MEAT))
+ {
+ if (r_ptr->flags3 & RF3_IM_ACID)
+ {
+ set_oppose_acid(p_ptr->oppose_acid + rand_int(10) + 10);
+ }
+ if (r_ptr->flags3 & RF3_IM_ELEC)
+ {
+ set_oppose_elec(p_ptr->oppose_elec + rand_int(10) + 10);
+ }
+ if (r_ptr->flags3 & RF3_IM_FIRE)
+ {
+ set_oppose_fire(p_ptr->oppose_fire + rand_int(10) + 10);
+ }
+ if (r_ptr->flags3 & RF3_IM_COLD)
+ {
+ set_oppose_cold(p_ptr->oppose_cold + rand_int(10) + 10);
+ }
+ if (r_ptr->flags3 & RF3_IM_POIS)
+ {
+ set_oppose_pois(p_ptr->oppose_pois + rand_int(10) + 10);
+ }
+ if (r_ptr->flags3 & RF3_RES_NETH)
+ {
+ set_protevil(p_ptr->protevil + rand_int(25) + 3 * r_ptr->level);
+ }
+ if (r_ptr->flags3 & RF3_RES_PLAS)
+ {
+ set_oppose_fire(p_ptr->oppose_fire + rand_int(20) + 20);
+ }
+ if (r_ptr->flags2 & RF2_SHAPECHANGER)
+ {
+ /* DGDGDG (void)set_mimic(20 , rand_int(MIMIC_VALAR)); */
+ }
+
+ if (r_ptr->flags3 & RF3_DEMON)
+ {
+ /* DGDGDG (void)set_mimic(30 , MIMIC_DEMON); */
+ }
+
+ if (r_ptr->flags3 & RF3_UNDEAD)
+ {
+ /* DGDGDG (void)set_mimic(30 , MIMIC_VAMPIRE); */
+ }
+
+ if (r_ptr->flags3 & RF3_NO_FEAR)
+ {
+ (void)set_afraid(0);
+ }
+ if (r_ptr->flags3 & RF3_NO_STUN)
+ {
+ (void)set_stun(0);
+ }
+ if (r_ptr->flags3 & RF3_NO_CONF)
+ {
+ (void)set_confused(0);
+ }
+ if (r_ptr->flags6 & RF6_S_THUNDERLORD)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_THUNDERLORD, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_DEMON)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_DEMON, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_KIN)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_KIN, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_HI_DEMON)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HI_DEMON, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_MONSTER)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, 0, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_MONSTERS)
+ {
+ int k;
+ for (k = 0; k < 8; k++)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, 0, FALSE);
+ }
+ }
+ if (r_ptr->flags6 & RF6_S_UNDEAD)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_UNDEAD, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_DRAGON)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_DRAGON, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_ANT)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_ANT, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_SPIDER)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_SPIDER, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_HOUND)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HOUND, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_HYDRA)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HYDRA, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_ANGEL)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_ANGEL, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_HI_DRAGON)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HI_DRAGON, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_HI_UNDEAD)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HI_UNDEAD, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_WRAITH)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_WRAITH, FALSE);
+ }
+ if (r_ptr->flags6 & RF6_S_UNIQUE)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_UNIQUE, FALSE);
+ }
+ }
+}
+
+
+/*
+ * Hook to determine if an object is eatable
+ */
+static bool_ item_tester_hook_eatable(object_type *o_ptr)
+{
+ /* Foods and, well, corpses are edible */
+ if ((o_ptr->tval == TV_FOOD) || (o_ptr->tval == TV_CORPSE)) return (TRUE);
+
+ /* Assume not */
+ return (FALSE);
+}
+
+
+/*
+ * Eat some food (from the pack or floor)
+ */
+void do_cmd_eat_food(void)
+{
+ int item, ident, lev, fval = 0;
+
+ object_type *o_ptr;
+ object_type *q_ptr, forge;
+
+ monster_race *r_ptr;
+
+ cptr q, s;
+
+ bool_ destroy = TRUE;
+
+
+ /* Restrict choices to food */
+ item_tester_hook = item_tester_hook_eatable;
+
+ /* Set up the extra finder */
+ get_item_hook_find_obj_what = "Food full name? ";
+ get_item_extra_hook = get_item_hook_find_obj;
+
+ /* Get an item */
+ q = "Eat which item? ";
+ s = "You have nothing to eat.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Sound */
+ sound(SOUND_EAT);
+
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Identity not known yet */
+ ident = FALSE;
+
+ /* Object level */
+ lev = k_info[o_ptr->k_idx].level;
+
+ /* Scripted foods */
+ if (process_hooks_ret(HOOK_EAT, "d", "(O)", o_ptr))
+ {
+ ident = process_hooks_return[0].num;
+ }
+ /* (not quite) Normal foods */
+ else if (o_ptr->tval == TV_FOOD)
+ {
+ /* Analyze the food */
+ switch (o_ptr->sval)
+ {
+ case SV_FOOD_GREAT_HEALTH:
+ {
+ p_ptr->hp_mod += 70;
+ msg_print("As you eat it you begin to feel your life flow getting stronger.");
+ ident = TRUE;
+ p_ptr->update |= (PU_HP);
+
+ break;
+ }
+
+ case SV_FOOD_POISON:
+ {
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ if (set_poisoned(p_ptr->poisoned + rand_int(10) + 10))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_FOOD_BLINDNESS:
+ {
+ if (!p_ptr->resist_blind)
+ {
+ if (set_blind(p_ptr->blind + rand_int(200) + 200))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_FOOD_PARANOIA:
+ {
+ if (!p_ptr->resist_fear)
+ {
+ if (set_afraid(p_ptr->afraid + rand_int(10) + 10))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_FOOD_CONFUSION:
+ {
+ if (!p_ptr->resist_conf)
+ {
+ if (set_confused(p_ptr->confused + rand_int(10) + 10))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_FOOD_HALLUCINATION:
+ {
+ if (!p_ptr->resist_chaos)
+ {
+ if (set_image(p_ptr->image + rand_int(250) + 250))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_FOOD_PARALYSIS:
+ {
+ if (!p_ptr->free_act)
+ {
+ if (set_paralyzed(p_ptr->paralyzed + rand_int(10) + 10))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_FOOD_WEAKNESS:
+ {
+ take_hit(damroll(6, 6), "poisonous food");
+ (void)do_dec_stat(A_STR, STAT_DEC_NORMAL);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_SICKNESS:
+ {
+ take_hit(damroll(6, 6), "poisonous food");
+ (void)do_dec_stat(A_CON, STAT_DEC_NORMAL);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_STUPIDITY:
+ {
+ take_hit(damroll(8, 8), "poisonous food");
+ (void)do_dec_stat(A_INT, STAT_DEC_NORMAL);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_NAIVETY:
+ {
+ take_hit(damroll(8, 8), "poisonous food");
+ (void)do_dec_stat(A_WIS, STAT_DEC_NORMAL);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_UNHEALTH:
+ {
+ take_hit(damroll(10, 10), "poisonous food");
+ (void)do_dec_stat(A_CON, STAT_DEC_NORMAL);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_DISEASE:
+ {
+ take_hit(damroll(10, 10), "poisonous food");
+ (void)do_dec_stat(A_STR, STAT_DEC_NORMAL);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_CURE_POISON:
+ {
+ if (set_poisoned(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_CURE_BLINDNESS:
+ {
+ if (set_blind(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_CURE_PARANOIA:
+ {
+ if (set_afraid(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_CURE_CONFUSION:
+ {
+ if (set_confused(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_CURE_SERIOUS:
+ {
+ if (hp_player(damroll(4, 8))) ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_RESTORE_STR:
+ {
+ if (do_res_stat(A_STR, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_RESTORE_CON:
+ {
+ if (do_res_stat(A_CON, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_RESTORING:
+ {
+ if (do_res_stat(A_STR, TRUE)) ident = TRUE;
+ if (do_res_stat(A_INT, TRUE)) ident = TRUE;
+ if (do_res_stat(A_WIS, TRUE)) ident = TRUE;
+ if (do_res_stat(A_DEX, TRUE)) ident = TRUE;
+ if (do_res_stat(A_CON, TRUE)) ident = TRUE;
+ if (do_res_stat(A_CHR, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_FORTUNE_COOKIE:
+ {
+ char rumour[80];
+
+ msg_print("That tastes good.");
+ msg_print("There is message in the cookie. It says:");
+ msg_print(NULL);
+
+ switch (randint(20))
+ {
+ case 1:
+ {
+ get_rnd_line("chainswd.txt", rumour);
+ break;
+ }
+
+ case 2:
+ {
+ get_rnd_line("error.txt", rumour);
+ break;
+ }
+
+ case 3:
+ case 4:
+ case 5:
+ {
+ get_rnd_line("death.txt", rumour);
+ break;
+ }
+
+ default:
+ {
+ get_rnd_line("rumors.txt", rumour);
+ break;
+ }
+ }
+
+ msg_format("%s", rumour);
+ msg_print(NULL);
+
+ ident = TRUE;
+
+ break;
+ }
+
+
+ case SV_FOOD_RATION:
+ case SV_FOOD_BISCUIT:
+ case SV_FOOD_JERKY:
+ {
+ msg_print("That tastes good.");
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_SLIME_MOLD:
+ {
+ msg_print("That tastes good.");
+
+ /* 2% chance of getting the mold power */
+ if (magik(2))
+ {
+ ADD_POWER(p_ptr->powers_mod, PWR_GROW_MOLD);
+ p_ptr->update |= PU_POWERS;
+ }
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_WAYBREAD:
+ {
+ msg_print("That tastes very good.");
+ (void)set_poisoned(0);
+ (void)hp_player(damroll(4, 8));
+ set_food(PY_FOOD_MAX - 1);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_FOOD_PINT_OF_ALE:
+ case SV_FOOD_PINT_OF_WINE:
+ {
+ msg_print("That tastes good.");
+
+ ident = TRUE;
+
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_BOTTLE, 1));
+ q_ptr->number = 1;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_STOREB;
+ (void)inven_carry(q_ptr, FALSE);
+
+ break;
+ }
+
+ case SV_FOOD_ATHELAS:
+ {
+ msg_print("A fresh, clean essence rises, driving away wounds and poison.");
+
+ (void)set_poisoned(0);
+ (void)set_stun(0);
+ (void)set_cut(0);
+ if (p_ptr->black_breath)
+ {
+ msg_print("The hold of the Black Breath on you is broken!");
+ p_ptr->black_breath = FALSE;
+ }
+
+ ident = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ /* Corpses... */
+ else
+ {
+ r_ptr = &r_info[o_ptr->pval2];
+
+ /* Analyse the corpse */
+ switch (o_ptr->sval)
+ {
+ case SV_CORPSE_CORPSE:
+ {
+ bool_ no_meat = FALSE;
+
+ /* Not all is edible. Apologies if messy. */
+
+ /* Check weight -- they have to have some meat left */
+ if (r_ptr->flags9 & RF9_DROP_SKELETON)
+ {
+ if (o_ptr->weight <= (r_ptr->weight * 3) / 5)
+ {
+ no_meat = TRUE;
+ }
+ }
+
+ /* Non-skeletons are naturally have more allowances */
+ else
+ {
+ if (o_ptr->weight <= (r_ptr->weight * 7) / 20)
+ {
+ no_meat = TRUE;
+ }
+ }
+
+ /* Nothing left to eat */
+ if (no_meat)
+ {
+ msg_print("There is not enough meat.");
+ return;
+ }
+
+
+ /* Check freshness */
+ if (!o_ptr->timeout) msg_print("Ugh! Raw meat!");
+ else msg_print("That tastes good.");
+
+
+ /* A pound of raw meat */
+ o_ptr->pval -= 10;
+ o_ptr->weight -= 10;
+
+ /* Corpses still have meat on them */
+ destroy = FALSE;
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_CORPSE_HEAD:
+ {
+ msg_print("You feel rather sick.");
+
+ /* A pound of raw meat */
+ o_ptr->pval -= 10;
+ o_ptr->weight -= 10;
+
+ /* Corpses still have meat on them */
+ destroy = FALSE;
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_CORPSE_MEAT:
+ {
+ /* Just meat */
+ if (!o_ptr->timeout) msg_print("You quickly swallow the meat.");
+ else msg_print("That tastes good.");
+
+ ident = TRUE;
+
+ /* Those darn microorganisms */
+ if (!o_ptr->timeout && (o_ptr->weight > o_ptr->pval) &&
+ !(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ set_poisoned(p_ptr->poisoned + rand_int(o_ptr->weight - o_ptr->pval) +
+ (o_ptr->weight - o_ptr->pval));
+ }
+
+ break;
+ }
+ }
+
+ corpse_effect(o_ptr, FALSE);
+
+ /* Less nutritious than food rations, but much more of it. */
+ fval = (o_ptr->timeout) ? 2000 : 2500;
+
+ /* Those darn microorganisms */
+ if (!o_ptr->timeout && (o_ptr->weight - o_ptr->pval > 10) &&
+ !(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ set_poisoned(p_ptr->poisoned + rand_int(o_ptr->weight - o_ptr->pval) +
+ (o_ptr->weight - o_ptr->pval));
+ }
+
+ /* Partially cured */
+ if (o_ptr->weight > o_ptr->timeout)
+ {
+ /* Adjust the "timeout" without overflowing */
+ o_ptr->timeout = (o_ptr->timeout * ((100 * o_ptr->timeout) / o_ptr->weight)) / 100;
+ }
+ }
+
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* We have tried it */
+ object_tried(o_ptr);
+
+ /* The player is now aware of the object */
+ if (ident && !object_aware_p(o_ptr))
+ {
+ object_aware(o_ptr);
+ gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);
+ }
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ if (!fval) fval = o_ptr->pval;
+
+ /* Food can feed the player, in a different ways */
+
+ /* Vampires */
+ if ((PRACE_FLAG(PR1_VAMPIRE)) || (p_ptr->mimic_form == resolve_mimic_name("Vampire")))
+ {
+ /* Reduced nutritional benefit */
+ /* (void)set_food(p_ptr->food + (fval / 10)); -- No more */
+ msg_print("Mere victuals hold scant sustenance for a being such as yourself.");
+
+ /* Hungry */
+ if (p_ptr->food < PY_FOOD_ALERT)
+ {
+ msg_print("Your hunger can only be satisfied with fresh blood!");
+ }
+ }
+
+ else if (PRACE_FLAG(PR1_NO_FOOD))
+ {
+ if (PRACE_FLAG(PR1_UNDEAD))
+ {
+ msg_print("The food of mortals is poor sustenance for you.");
+ }
+ else
+ {
+ msg_print("Food is poor sustenance for you.");
+ }
+ set_food(p_ptr->food + ((fval) / 40));
+ }
+
+ /* Those living in fresh */
+ else
+ {
+ (void)set_food(p_ptr->food + fval);
+ }
+
+
+ /* Destroy food? */
+ if (destroy)
+ {
+ inc_stack_size(item, -1);
+ }
+}
+
+
+/*
+ * Cut a corpse up for convenient storage
+ */
+void do_cmd_cut_corpse(void)
+{
+ int item, meat = 0, not_meat = 0;
+
+ object_type *o_ptr;
+
+ object_type *i_ptr;
+
+ object_type object_type_body;
+
+ monster_race *r_ptr;
+
+ cptr q, s;
+
+
+ /* Restrict choices to corpses */
+ item_tester_tval = TV_CORPSE;
+
+ /* Get an item */
+ q = "Hack up which corpse? ";
+ s = "You have no corpses.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ r_ptr = &r_info[o_ptr->pval2];
+
+ if ((o_ptr->sval != SV_CORPSE_CORPSE) && (o_ptr->sval != SV_CORPSE_HEAD))
+ {
+ msg_print ("You cannot split that.");
+ return;
+ }
+
+ switch (o_ptr->sval)
+ {
+ case SV_CORPSE_CORPSE:
+ {
+ if (r_ptr->flags9 & RF9_DROP_SKELETON)
+ {
+ not_meat = (r_ptr->weight * 3) / 5;
+ }
+ else
+ {
+ not_meat = (r_ptr->weight * 7) / 20;
+ }
+ meat = r_ptr->weight + r_ptr->weight / 10 - not_meat;
+
+ break;
+ }
+
+ case SV_CORPSE_HEAD:
+ {
+ not_meat = r_ptr->weight / 150;
+ meat = r_ptr->weight / 30 + r_ptr->weight / 300 - not_meat;
+
+ break;
+ }
+ }
+
+ if ((o_ptr->weight <= not_meat) || (meat < 10))
+ {
+ msg_print("There is not enough meat.");
+ return;
+ }
+
+ /* Hacking 10 pounds off */
+ if (meat > 100) meat = 100;
+
+ /* Take a turn */
+ energy_use = 100;
+
+ o_ptr->pval -= meat;
+ o_ptr->weight -= meat;
+
+ msg_print("You hack some meat off the corpse.");
+
+ corpse_effect(o_ptr, TRUE);
+
+ /* Get local object */
+ i_ptr = &object_type_body;
+
+ /* Make some meat */
+ object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_MEAT));
+
+ i_ptr->number = meat / 10;
+ i_ptr->pval2 = o_ptr->pval2;
+
+ /* Length of time before decay */
+ i_ptr->pval = 1000 + rand_int(1000);
+
+ if (inven_carry_okay(i_ptr))
+ {
+ inven_carry(i_ptr, TRUE);
+ }
+ else
+ {
+ drop_near(i_ptr, 0, p_ptr->py, p_ptr->px);
+ }
+}
+
+
+/*
+ * Use a potion to cure some meat
+ *
+ * Salt water works well.
+ */
+void do_cmd_cure_meat(void)
+{
+ int item, num, cure;
+
+ object_type *o_ptr;
+
+ object_type *i_ptr;
+
+ cptr q, s;
+
+
+ /* Restrict choices to corpses */
+ item_tester_tval = TV_CORPSE;
+ item_tester_hook = item_tester_hook_eatable;
+
+ /* Get some meat */
+ q = "Cure which meat? ";
+ s = "You have no meat to cure.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Restrict choices to potions */
+ item_tester_tval = TV_POTION;
+
+ /* Get a potion */
+ q = "Use which potion? ";
+ s = "You have no potions to use.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ i_ptr = get_object(item);
+
+ if (i_ptr->number > 1)
+ {
+ /* Get a number */
+ get_count(1, i_ptr->number);
+
+ /* Save it */
+ num = command_arg;
+ }
+ else
+ {
+ num = 1;
+ }
+
+ if (num == 0) return;
+
+ /* Take a turn */
+ energy_use = 100;
+
+ q = "You soak the meat.";
+ s = "You soak the meat.";
+
+ switch (i_ptr->sval)
+ {
+ case SV_POTION_SALT_WATER:
+ {
+ q = "You salt the meat.";
+ cure = 200 * num;
+
+ break;
+ }
+
+ case SV_POTION_POISON:
+ {
+ q = "You poison the meat.";
+ cure = 0;
+ o_ptr->pval /= 2;
+ if (o_ptr->pval > o_ptr->weight) o_ptr->pval = o_ptr->weight;
+
+ break;
+ }
+
+ case SV_POTION_CONFUSION:
+ {
+ cure = 80 * num;
+
+ break;
+ }
+
+ case SV_POTION_SLOW_POISON:
+ {
+ cure = 20 * num;
+
+ break;
+ }
+
+ case SV_POTION_CURE_POISON:
+ {
+ cure = 45 * num;
+
+ break;
+ }
+
+ case SV_POTION_DEATH:
+ {
+ q = "You ruin the meat.";
+ cure = 0;
+ o_ptr->pval /= 10;
+ if (o_ptr->pval > o_ptr->weight) o_ptr->pval = o_ptr->weight / 2;
+
+ break;
+ }
+
+ default:
+ {
+ cure = 0;
+
+ break;
+ }
+ }
+
+ /* Message */
+ if (object_known_p(i_ptr)) msg_print(q);
+ else msg_print(s);
+
+ /* The meat is already spoiling */
+ if (((o_ptr->sval == SV_CORPSE_MEAT) && (o_ptr->weight > o_ptr->pval)) ||
+ (o_ptr->weight - o_ptr->pval > 10))
+ {
+ cure = (cure * o_ptr->pval) / (o_ptr->weight * 20);
+ }
+
+ /* Cure the meat */
+ o_ptr->timeout += cure / o_ptr->number;
+
+ if (o_ptr->timeout > o_ptr->pval) o_ptr->timeout = o_ptr->pval;
+
+ /* Use up the potions */
+ inc_stack_size(item, -num);
+}
+
+
+/*
+ * Hook to determine if an object is quaffable
+ */
+static bool_ item_tester_hook_quaffable(object_type *o_ptr)
+{
+ if ((o_ptr->tval == TV_POTION) || (o_ptr->tval == TV_POTION2)) return (TRUE);
+
+ /* Assume not */
+ return (FALSE);
+}
+
+
+static bool_ quaff_potion(int tval, int sval, int pval, int pval2)
+{
+ int ident = FALSE;
+
+
+ /* "Traditional" potions */
+ if (tval == TV_POTION)
+ {
+ switch (sval)
+ {
+ case SV_POTION_WATER:
+ case SV_POTION_APPLE_JUICE:
+ case SV_POTION_SLIME_MOLD:
+ {
+ msg_print("You feel less thirsty.");
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_SLOWNESS:
+ {
+ if (set_slow(p_ptr->slow + randint(25) + 15)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_SALT_WATER:
+ {
+ msg_print("The potion makes you vomit!");
+ (void)set_food(PY_FOOD_STARVE - 1);
+ (void)set_poisoned(0);
+ (void)set_paralyzed(p_ptr->paralyzed + 4);
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_POISON:
+ {
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ if (set_poisoned(p_ptr->poisoned + rand_int(15) + 10))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_POTION_BLINDNESS:
+ {
+ if (!p_ptr->resist_blind)
+ {
+ if (set_blind(p_ptr->blind + rand_int(100) + 100))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ /* Booze */
+ case SV_POTION_CONFUSION:
+ {
+ if (!((p_ptr->resist_conf) || (p_ptr->resist_chaos)))
+ {
+ if (set_confused(p_ptr->confused + rand_int(20) + 15))
+ {
+ ident = TRUE;
+ }
+ if (randint(2) == 1)
+ {
+ if (set_image(p_ptr->image + rand_int(150) + 150))
+ {
+ ident = TRUE;
+ }
+ }
+ if (randint(13) == 1)
+ {
+ ident = TRUE;
+ if (randint(3) == 1) lose_all_info();
+ else wiz_dark();
+ teleport_player(100);
+ wiz_dark();
+ msg_print("You wake up elsewhere with a sore head...");
+ msg_print("You can't remember a thing, or how you got here!");
+ }
+ }
+
+ break;
+ }
+
+ case SV_POTION_SLEEP:
+ {
+ if (!p_ptr->free_act)
+ {
+ if (set_paralyzed(p_ptr->paralyzed + rand_int(4) + 4))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_POTION_LOSE_MEMORIES:
+ {
+ if (!p_ptr->hold_life && (p_ptr->exp > 0))
+ {
+ msg_print("You feel your memories fade.");
+ lose_exp(p_ptr->exp / 4);
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_POTION_RUINATION:
+ {
+ msg_print("Your nerves and muscles feel weak and lifeless!");
+ take_hit(damroll(10, 10), "a potion of Ruination");
+ (void)dec_stat(A_DEX, 25, TRUE);
+ (void)dec_stat(A_WIS, 25, TRUE);
+ (void)dec_stat(A_CON, 25, TRUE);
+ (void)dec_stat(A_STR, 25, TRUE);
+ (void)dec_stat(A_CHR, 25, TRUE);
+ (void)dec_stat(A_INT, 25, TRUE);
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_DEC_STR:
+ {
+ if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_DEC_INT:
+ {
+ if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_DEC_WIS:
+ {
+ if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_DEC_DEX:
+ {
+ if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_DEC_CON:
+ {
+ if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_DEC_CHR:
+ {
+ if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_DETONATIONS:
+ {
+ msg_print("Massive explosions rupture your body!");
+ take_hit(damroll(50, 20), "a potion of Detonation");
+ (void)set_stun(p_ptr->stun + 75);
+ (void)set_cut(p_ptr->cut + 5000);
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_DEATH:
+ {
+ msg_print("A feeling of Death flows through your body.");
+ take_hit(5000, "a potion of Death");
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_INFRAVISION:
+ {
+ if (set_tim_infra(p_ptr->tim_infra + 100 + randint(100)))
+ {
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_POTION_DETECT_INVIS:
+ {
+ if (set_tim_invis(p_ptr->tim_invis + 12 + randint(12)))
+ {
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_POTION_SLOW_POISON:
+ {
+ if (set_poisoned(p_ptr->poisoned / 2)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_CURE_POISON:
+ {
+ if (set_poisoned(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_BOLDNESS:
+ {
+ if (set_afraid(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_SPEED:
+ {
+ if (!p_ptr->fast)
+ {
+ if (set_fast(randint(25) + 15, 10)) ident = TRUE;
+ }
+ else
+ {
+ (void)set_fast(p_ptr->fast + 5, 10);
+ }
+
+ break;
+ }
+
+ case SV_POTION_RESIST_HEAT:
+ {
+ if (set_oppose_fire(p_ptr->oppose_fire + randint(10) + 10))
+ {
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_POTION_RESIST_COLD:
+ {
+ if (set_oppose_cold(p_ptr->oppose_cold + randint(10) + 10))
+ {
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_POTION_HEROISM:
+ {
+ if (set_afraid(0)) ident = TRUE;
+ if (set_hero(p_ptr->hero + randint(25) + 25)) ident = TRUE;
+ if (hp_player(10)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_BESERK_STRENGTH:
+ {
+ if (set_afraid(0)) ident = TRUE;
+ if (set_shero(p_ptr->shero + randint(25) + 25)) ident = TRUE;
+ if (hp_player(30)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_CURE_LIGHT:
+ {
+ if (hp_player(damroll(2, 8))) ident = TRUE;
+ if (set_blind(0)) ident = TRUE;
+ if (set_cut(p_ptr->cut - 10)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_CURE_SERIOUS:
+ {
+ if (hp_player(damroll(4, 8))) ident = TRUE;
+ if (set_blind(0)) ident = TRUE;
+ if (set_confused(0)) ident = TRUE;
+ if (set_cut((p_ptr->cut / 2) - 50)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_CURE_CRITICAL:
+ {
+ if (hp_player(damroll(6, 8))) ident = TRUE;
+ if (set_blind(0)) ident = TRUE;
+ if (set_confused(0)) ident = TRUE;
+ if (set_poisoned(0)) ident = TRUE;
+ if (set_stun(0)) ident = TRUE;
+ if (set_cut(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_HEALING:
+ {
+ if (hp_player(300)) ident = TRUE;
+ if (set_blind(0)) ident = TRUE;
+ if (set_confused(0)) ident = TRUE;
+ if (set_poisoned(0)) ident = TRUE;
+ if (set_stun(0)) ident = TRUE;
+ if (set_cut(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_STAR_HEALING:
+ {
+ if (hp_player(1200)) ident = TRUE;
+ if (set_blind(0)) ident = TRUE;
+ if (set_confused(0)) ident = TRUE;
+ if (set_poisoned(0)) ident = TRUE;
+ if (set_stun(0)) ident = TRUE;
+ if (set_cut(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_LIFE:
+ {
+ msg_print("You feel life flow through your body!");
+ restore_level();
+ hp_player(5000);
+ (void)set_poisoned(0);
+ (void)set_blind(0);
+ (void)set_confused(0);
+ (void)set_image(0);
+ (void)set_stun(0);
+ (void)set_cut(0);
+ (void)do_res_stat(A_STR, TRUE);
+ (void)do_res_stat(A_CON, TRUE);
+ (void)do_res_stat(A_DEX, TRUE);
+ (void)do_res_stat(A_WIS, TRUE);
+ (void)do_res_stat(A_INT, TRUE);
+ (void)do_res_stat(A_CHR, TRUE);
+ if (p_ptr->black_breath)
+ {
+ msg_print("The hold of the Black Breath on you is broken!");
+ }
+ p_ptr->black_breath = FALSE;
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_RESTORE_MANA:
+ {
+ if (p_ptr->csp < p_ptr->msp)
+ {
+ p_ptr->csp = p_ptr->msp;
+ p_ptr->csp_frac = 0;
+ msg_print("Your feel your head clear.");
+ p_ptr->redraw |= (PR_MANA);
+ p_ptr->window |= (PW_PLAYER);
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_POTION_RESTORE_EXP:
+ {
+ if (restore_level()) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_RES_STR:
+ {
+ if (do_res_stat(A_STR, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_RES_INT:
+ {
+ if (do_res_stat(A_INT, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_RES_WIS:
+ {
+ if (do_res_stat(A_WIS, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_RES_DEX:
+ {
+ if (do_res_stat(A_DEX, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_RES_CON:
+ {
+ if (do_res_stat(A_CON, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_RES_CHR:
+ {
+ if (do_res_stat(A_CHR, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_INC_STR:
+ {
+ if (do_inc_stat(A_STR)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_INC_INT:
+ {
+ if (do_inc_stat(A_INT)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_INC_WIS:
+ {
+ if (do_inc_stat(A_WIS)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_INC_DEX:
+ {
+ if (do_inc_stat(A_DEX)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_INC_CON:
+ {
+ if (do_inc_stat(A_CON)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_INC_CHR:
+ {
+ if (do_inc_stat(A_CHR)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_AUGMENTATION:
+ {
+ if (do_inc_stat(A_STR)) ident = TRUE;
+ if (do_inc_stat(A_INT)) ident = TRUE;
+ if (do_inc_stat(A_WIS)) ident = TRUE;
+ if (do_inc_stat(A_DEX)) ident = TRUE;
+ if (do_inc_stat(A_CON)) ident = TRUE;
+ if (do_inc_stat(A_CHR)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_ENLIGHTENMENT:
+ {
+ msg_print("An image of your surroundings forms in your mind...");
+ wiz_lite();
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_STAR_ENLIGHTENMENT:
+ {
+ msg_print("You begin to feel more enlightened...");
+ msg_print(NULL);
+ wiz_lite_extra();
+ (void)do_inc_stat(A_INT);
+ (void)do_inc_stat(A_WIS);
+ (void)detect_traps(DEFAULT_RADIUS);
+ (void)detect_doors(DEFAULT_RADIUS);
+ (void)detect_stairs(DEFAULT_RADIUS);
+ (void)detect_treasure(DEFAULT_RADIUS);
+ (void)detect_objects_gold(DEFAULT_RADIUS);
+ (void)detect_objects_normal(DEFAULT_RADIUS);
+ identify_pack();
+ self_knowledge(NULL);
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_SELF_KNOWLEDGE:
+ {
+ msg_print("You begin to know yourself a little better...");
+ msg_print(NULL);
+ self_knowledge(NULL);
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_EXPERIENCE:
+ {
+ if (p_ptr->exp < PY_MAX_EXP)
+ {
+ s32b ee = (p_ptr->exp / 2) + 10;
+ if (ee > 100000L) ee = 100000L;
+ msg_print("You feel more experienced.");
+ gain_exp(ee);
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_POTION_RESISTANCE:
+ {
+ (void)set_oppose_acid(p_ptr->oppose_acid + randint(20) + 20);
+ (void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20);
+ (void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20);
+ (void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20);
+ (void)set_oppose_pois(p_ptr->oppose_pois + randint(20) + 20);
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_CURING:
+ {
+ if (hp_player(50)) ident = TRUE;
+ if (set_blind(0)) ident = TRUE;
+ if (set_poisoned(0)) ident = TRUE;
+ if (set_confused(0)) ident = TRUE;
+ if (set_stun(0)) ident = TRUE;
+ if (set_cut(0)) ident = TRUE;
+ if (set_image(0)) ident = TRUE;
+ if (heal_insanity(50)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_INVULNERABILITY:
+ {
+ (void)set_invuln(p_ptr->invuln + randint(7) + 7);
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_NEW_LIFE:
+ {
+ do_cmd_rerate();
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION_BLOOD:
+ {
+ msg_print("You feel the blood of life running through your veins!");
+ ident = TRUE;
+ p_ptr->allow_one_death++;
+
+ break;
+ }
+
+ case SV_POTION_MUTATION:
+ {
+ msg_print("You feel the dark corruptions of Morgoth coming over you!");
+ gain_random_corruption(0);
+ ident = TRUE;
+ break;
+ }
+
+ case SV_POTION_INVIS:
+ {
+ int t = 30 + randint(30);
+
+ if (set_invis(p_ptr->tim_invis + t, 35))
+ {
+ ident = TRUE;
+ }
+ set_tim_invis(p_ptr->tim_invis + t);
+
+ break;
+ }
+
+ case SV_POTION_LEARNING:
+ {
+ p_ptr->skill_points += rand_range(4, 10 + luck( -4, 4));
+ cmsg_format(TERM_L_GREEN, "You can increase %d more skills.", p_ptr->skill_points);
+
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ /* "Duplicate" potions */
+ else
+ {
+ switch (sval)
+ {
+ case SV_POTION2_MIMIC:
+ {
+ if (!p_ptr->mimic_form)
+ {
+ s32b time;
+
+ call_lua("get_mimic_rand_dur", "(d)", "d", pval2, &time);
+
+ set_mimic(time, pval2, (p_ptr->lev * 2) / 3);
+
+ /* Redraw title */
+ p_ptr->redraw |= (PR_TITLE);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_POTION2_CURE_LIGHT_SANITY:
+ {
+ if (heal_insanity(damroll(4, 8))) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION2_CURE_SERIOUS_SANITY:
+ {
+ if (heal_insanity(damroll(8, 8))) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION2_CURE_CRITICAL_SANITY:
+ {
+ if (heal_insanity(damroll(12, 8))) ident = TRUE;
+
+ break;
+ }
+
+ case SV_POTION2_CURE_SANITY:
+ {
+ if (heal_insanity(damroll(10, 100))) ident = TRUE;
+
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ return (ident);
+}
+
+
+/*
+ * Quaff a potion (from the pack or the floor)
+ */
+void do_cmd_quaff_potion(void)
+{
+ int item, ident, lev;
+
+ object_type *o_ptr;
+
+ object_type *q_ptr, forge;
+
+ cptr q, s;
+
+
+ /* Restrict choices to potions */
+ item_tester_hook = item_tester_hook_quaffable;
+
+ /* Set up the extra finder */
+ get_item_hook_find_obj_what = "Potion full name? ";
+ get_item_extra_hook = get_item_hook_find_obj;
+
+ /* Get an item */
+ q = "Quaff which potion? ";
+ s = "You have no potions to quaff.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+
+ /* Sound */
+ sound(SOUND_QUAFF);
+
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Not identified yet */
+ ident = FALSE;
+
+ /* Object level */
+ lev = k_info[o_ptr->k_idx].level;
+
+ /* Analyze the potion */
+ if (process_hooks_ret(HOOK_QUAFF, "d", "(O)", o_ptr))
+ {
+ ident = process_hooks_return[0].num;
+ }
+ else
+ {
+ ident = quaff_potion(o_ptr->tval, o_ptr->sval, o_ptr->pval, o_ptr->pval2);
+ }
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* The item has been tried */
+ object_tried(o_ptr);
+
+ /* An identification was made */
+ if (ident && !object_aware_p(o_ptr))
+ {
+ object_aware(o_ptr);
+ gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);
+ }
+
+ if (get_skill(SKILL_ALCHEMY))
+ {
+ if (item >= 0)
+ {
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_BOTTLE, 1));
+ q_ptr->number = 1;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+
+ q_ptr->ident |= IDENT_STOREB;
+
+ (void)inven_carry(q_ptr, FALSE);
+ }
+ }
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+
+ /* Potions can feed the player */
+ (void)set_food(p_ptr->food + o_ptr->pval);
+
+
+ /* Destroy potion */
+ inc_stack_size(item, -1);
+}
+
+
+/*
+ * Drink from a fountain
+ */
+void do_cmd_drink_fountain(void)
+{
+ cave_type *c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ bool_ ident;
+
+ int tval, sval, pval = 0;
+
+ int i;
+
+ char ch;
+
+
+ /* Is the fountain empty? */
+ if (c_ptr->special2 <= 0)
+ {
+ msg_print("The fountain is dried out.");
+ return;
+ }
+
+ /* We quaff or we fill ? */
+ if (!get_com("Do you want to [Q]uaff or [F]ill from the fountain? ", &ch))
+ {
+ return;
+ }
+
+ if ((ch == 'F') || (ch == 'f'))
+ {
+ do_cmd_fill_bottle();
+
+ return;
+ }
+
+ else if ((ch == 'Q') || (ch == 'q'))
+ {
+ if (c_ptr->special <= SV_POTION_LAST)
+ {
+ tval = TV_POTION;
+ sval = c_ptr->special;
+ }
+ else
+ {
+ tval = TV_POTION2;
+ sval = c_ptr->special - SV_POTION_LAST;
+ }
+
+ for (i = 0; i < max_k_idx; i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+
+ if (k_ptr->tval != tval) continue;
+ if (k_ptr->sval != sval) continue;
+
+ pval = k_ptr->pval;
+
+ break;
+ }
+
+ ident = quaff_potion(tval, sval, pval, 0);
+
+ c_ptr->special2--;
+
+ if (c_ptr->special2 <= 0)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_EMPTY_FOUNTAIN);
+ }
+
+ if (ident) c_ptr->info |= CAVE_IDNT;
+ }
+}
+
+
+/*
+ * Fill an empty bottle
+ */
+void do_cmd_fill_bottle(void)
+{
+ cave_type *c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ int tval, sval, item, amt = 1;
+
+ object_type *q_ptr, *o_ptr, forge;
+
+ cptr q, s;
+
+ /* Is the fountain empty? */
+ /*
+ * This check is redundant as it is done in do_cmd_drink_fountain()
+ * but I keep this because someone might want to call this directly.
+ * -- Kusunose
+ */
+ if (c_ptr->special2 <= 0)
+ {
+ msg_print("The fountain has dried up.");
+ return;
+ }
+
+ /* Determine the tval/sval of the potion */
+ if (c_ptr->special <= SV_POTION_LAST)
+ {
+ tval = TV_POTION;
+ sval = c_ptr->special;
+ }
+ else
+ {
+ tval = TV_POTION2;
+ sval = c_ptr->special - SV_POTION_LAST;
+ }
+
+ /* Restrict choices to bottles */
+ item_tester_tval = TV_BOTTLE;
+
+ /* Get an item */
+ q = "Fill which bottle? ";
+ s = "You have no bottles to fill.";
+ if (!get_item(&item, q, s, (USE_INVEN))) return;
+ o_ptr = &p_ptr->inventory[item];
+
+ /* Find out how many the player wants */
+ if (o_ptr->number > 1)
+ {
+ /* Get a quantity */
+ amt = get_quantity(NULL, o_ptr->number);
+
+ /* Allow user abort */
+ if (amt <= 0) return;
+ }
+
+ if (amt > c_ptr->special2) amt = c_ptr->special2;
+
+ /* Destroy bottles */
+ inc_stack_size(item, -amt);
+
+ /* Create the potion */
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(tval, sval));
+ q_ptr->number = amt;
+
+ if (c_ptr->info & CAVE_IDNT)
+ {
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ }
+
+ inven_carry(q_ptr, TRUE);
+
+ c_ptr->special2 -= amt;
+
+ if (c_ptr->special2 <= 0)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_EMPTY_FOUNTAIN);
+ }
+
+ return;
+}
+
+
+/*
+ * Curse the players armor
+ */
+bool_ curse_armor(void)
+{
+ object_type *o_ptr;
+
+ char o_name[80];
+
+
+ /* Curse the body armor */
+ o_ptr = &p_ptr->inventory[INVEN_BODY];
+
+ /* Nothing to curse */
+ if (!o_ptr->k_idx) return (FALSE);
+
+
+ /* Describe */
+ object_desc(o_name, o_ptr, FALSE, 3);
+
+ /* Attempt a saving throw for artifacts */
+ if (((o_ptr->art_name) || artifact_p(o_ptr)) && (rand_int(100) < 50))
+ {
+ /* Cool */
+ msg_format("A terrible black aura tries to surround your armour, "
+ "but your %s resists the effects!", o_name);
+ }
+
+ /* not artifact or failed save... */
+ else
+ {
+ /* Oops */
+ msg_format("A terrible black aura blasts your %s!", o_name);
+
+ /* Blast the armor */
+ o_ptr->name1 = 0;
+ o_ptr->name2 = EGO_BLASTED;
+ o_ptr->to_a = 0 - randint(5) - randint(5);
+ o_ptr->to_h = 0;
+ o_ptr->to_d = 0;
+ o_ptr->ac = 0;
+ o_ptr->dd = 0;
+ o_ptr->ds = 0;
+ o_ptr->art_flags1 = 0;
+ o_ptr->art_flags2 = 0;
+ o_ptr->art_flags3 = 0;
+ o_ptr->art_flags4 = 0;
+
+ /* Curse it */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Recalculate mana */
+ p_ptr->update |= (PU_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * Curse the players weapon
+ */
+bool_ curse_weapon(void)
+{
+ object_type *o_ptr;
+
+ char o_name[80];
+
+
+ /* Curse the weapon */
+ o_ptr = &p_ptr->inventory[INVEN_WIELD];
+
+ /* Nothing to curse */
+ if (!o_ptr->k_idx) return (FALSE);
+
+
+ /* Describe */
+ object_desc(o_name, o_ptr, FALSE, 3);
+
+ /* Attempt a saving throw */
+ if ((artifact_p(o_ptr) || o_ptr->art_name) && (rand_int(100) < 50))
+ {
+ /* Cool */
+ msg_format("A terrible black aura tries to surround your weapon, "
+ "but your %s resists the effects!", o_name);
+ }
+
+ /* not artifact or failed save... */
+ else
+ {
+ /* Oops */
+ msg_format("A terrible black aura blasts your %s!", o_name);
+
+ /* Shatter the weapon */
+ o_ptr->name1 = 0;
+ o_ptr->name2 = EGO_SHATTERED;
+ o_ptr->to_h = 0 - randint(5) - randint(5);
+ o_ptr->to_d = 0 - randint(5) - randint(5);
+ o_ptr->to_a = 0;
+ o_ptr->ac = 0;
+ o_ptr->dd = 0;
+ o_ptr->ds = 0;
+ o_ptr->art_flags1 = 0;
+ o_ptr->art_flags2 = 0;
+ o_ptr->art_flags3 = 0;
+ o_ptr->art_flags4 = 0;
+
+
+ /* Curse it */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Recalculate mana */
+ p_ptr->update |= (PU_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ }
+
+ /* Notice */
+ return (TRUE);
+}
+
+
+/*
+ * Hook to determine if an object is readable
+ */
+static bool_ item_tester_hook_readable(object_type *o_ptr)
+{
+ if ((o_ptr->tval == TV_SCROLL) || (o_ptr->tval == TV_PARCHMENT)) return (TRUE);
+
+ /* Assume not */
+ return (FALSE);
+}
+
+
+/*
+ * Read a scroll (from the pack or floor).
+ *
+ * Certain scrolls can be "aborted" without losing the scroll. These
+ * include scrolls with no effects but recharge or identify, which are
+ * cancelled before use. XXX Reading them still takes a turn, though.
+ */
+void do_cmd_read_scroll(void)
+{
+ int item, k, used_up, ident, lev;
+
+ object_type *o_ptr;
+
+ object_type *q_ptr, forge;
+
+ cptr q, s;
+
+
+ /* Check some conditions */
+ if (p_ptr->blind)
+ {
+ msg_print("You can't see anything.");
+ return;
+ }
+
+ if (no_lite())
+ {
+ msg_print("You have no light by which to read.");
+ return;
+ }
+
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+
+ /* Restrict choices to scrolls */
+ item_tester_hook = item_tester_hook_readable;
+
+ /* Set up the extra finder */
+ get_item_hook_find_obj_what = "Scroll full name? ";
+ get_item_extra_hook = get_item_hook_find_obj;
+
+ /* Get an item */
+ q = "Read which scroll? ";
+ s = "You have no scrolls to read.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Not identified yet */
+ ident = FALSE;
+
+ /* Object level */
+ lev = k_info[o_ptr->k_idx].level;
+
+ /* Assume the scroll will get used up */
+ used_up = TRUE;
+
+ /* New scripts, can override the ingame code */
+ if (process_hooks_ret(HOOK_READ, "dd", "(O)", o_ptr))
+ {
+ used_up = process_hooks_return[0].num;
+ ident = process_hooks_return[1].num;
+ }
+ /* Traditional scrolls */
+ else if (o_ptr->tval == TV_SCROLL)
+ {
+ /* Analyze the scroll */
+ switch (o_ptr->sval)
+ {
+ case SV_SCROLL_MASS_RESURECTION:
+ {
+ int k;
+
+ ident = TRUE;
+ msg_print("You feel the souls of the dead coming back "
+ "from the Halls of Mandos.");
+
+ for (k = 0; k < max_r_idx; k++)
+ {
+ monster_race *r_ptr = &r_info[k];
+
+ if (r_ptr->flags1 & RF1_UNIQUE &&
+ !(r_ptr->flags9 & RF9_SPECIAL_GENE))
+ {
+ r_ptr->max_num = 1;
+ }
+ }
+
+ break;
+ }
+
+ case SV_SCROLL_DEINCARNATION:
+ {
+ if (!get_check("Do you really want to leave your body? "
+ "(beware, it'll be destroyed!) "))
+ {
+ used_up = FALSE;
+ break;
+ }
+
+ do_cmd_leave_body(FALSE);
+
+ ident = TRUE;
+ used_up = TRUE;
+
+ break;
+ }
+
+ /* original didn't set used_up flag ??? -- pelpel */
+ case SV_SCROLL_RESET_RECALL:
+ {
+ if (!reset_recall(TRUE))
+ {
+ used_up = FALSE;
+ break;
+ }
+
+ msg_format("Recall reset to %s at level %d.",
+ d_info[p_ptr->recall_dungeon].name + d_name,
+ max_dlv[p_ptr->recall_dungeon]);
+
+ ident = TRUE;
+ used_up = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_DIVINATION:
+ {
+ int i, count = 0;
+ char buf[120];
+
+ while (count < 1000)
+ {
+ count++;
+ i = rand_int(MAX_FATES);
+ if (!fates[i].fate) continue;
+ if (fates[i].know) continue;
+
+ msg_print("A message appears on the scroll. It says:");
+ msg_print(NULL);
+
+ fate_desc(buf, i);
+ msg_format("%s", buf);
+
+ msg_print(NULL);
+ msg_print("The scroll disappears in a puff of smoke!");
+
+ fates[i].know = TRUE;
+ ident = TRUE;
+
+ break;
+ }
+
+ break;
+ }
+
+ case SV_SCROLL_DARKNESS:
+ {
+ if (!(p_ptr->resist_blind) && !(p_ptr->resist_dark))
+ {
+ (void)set_blind(p_ptr->blind + 3 + randint(5));
+ }
+ if (unlite_area(10, 3)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_AGGRAVATE_MONSTER:
+ {
+ msg_print("There is a high-pitched humming noise.");
+ aggravate_monsters(1);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_CURSE_ARMOR:
+ {
+ if (curse_armor()) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_CURSE_WEAPON:
+ {
+ if (curse_weapon()) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_SUMMON_MONSTER:
+ {
+ for (k = 0; k < randint(3); k++)
+ {
+ if (summon_specific(p_ptr->py, p_ptr->px, dun_level, 0))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_SCROLL_SUMMON_MINE:
+ {
+ if (summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_MINE, FALSE))
+ {
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_SCROLL_SUMMON_UNDEAD:
+ {
+ for (k = 0; k < randint(3); k++)
+ {
+ if (summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_UNDEAD))
+ {
+ ident = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case SV_SCROLL_TRAP_CREATION:
+ {
+ if (trap_creation()) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_PHASE_DOOR:
+ {
+ teleport_player(10);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_TELEPORT:
+ {
+ teleport_player(100);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_TELEPORT_LEVEL:
+ {
+ (void)teleport_player_level();
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_WORD_OF_RECALL:
+ {
+ if ((dungeon_flags2 & DF2_ASK_LEAVE) && !get_check("Leave this unique level forever? "))
+ {
+ used_up = FALSE;
+ }
+ else
+ {
+ recall_player(21, 15);
+
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_SCROLL_IDENTIFY:
+ {
+ ident = TRUE;
+
+ if (!ident_spell()) used_up = FALSE;
+
+ break;
+ }
+
+ case SV_SCROLL_STAR_IDENTIFY:
+ {
+ ident = TRUE;
+
+ if (!identify_fully()) used_up = FALSE;
+
+ break;
+ }
+
+ case SV_SCROLL_REMOVE_CURSE:
+ {
+ if (remove_curse())
+ {
+ msg_print("You feel as if someone is watching over you.");
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_SCROLL_STAR_REMOVE_CURSE:
+ {
+ remove_all_curse();
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_ENCHANT_ARMOR:
+ {
+ ident = TRUE;
+
+ if (!enchant_spell(0, 0, 1, 0)) used_up = FALSE;
+
+ break;
+ }
+
+ case SV_SCROLL_ENCHANT_WEAPON_TO_HIT:
+ {
+ if (!enchant_spell(1, 0, 0, 0)) used_up = FALSE;
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_ENCHANT_WEAPON_TO_DAM:
+ {
+ if (!enchant_spell(0, 1, 0, 0)) used_up = FALSE;
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_ENCHANT_WEAPON_PVAL:
+ {
+ if (!enchant_spell(0, 0, 0, 1)) used_up = FALSE;
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_STAR_ENCHANT_ARMOR:
+ {
+ if (!enchant_spell(0, 0, randint(3) + 2, 0)) used_up = FALSE;
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_STAR_ENCHANT_WEAPON:
+ {
+ if (!enchant_spell(randint(3), randint(3), 0, 0)) used_up = FALSE;
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_RECHARGING:
+ {
+ if (!recharge(60)) used_up = FALSE;
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_LIGHT:
+ {
+ if (lite_area(damroll(2, 8), 2)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_MAPPING:
+ {
+ map_area();
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_DETECT_GOLD:
+ {
+ if (detect_treasure(DEFAULT_RADIUS)) ident = TRUE;
+ if (detect_objects_gold(DEFAULT_RADIUS)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_DETECT_ITEM:
+ {
+ if (detect_objects_normal(DEFAULT_RADIUS)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_DETECT_TRAP:
+ {
+ if (detect_traps(DEFAULT_RADIUS)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_DETECT_DOOR:
+ {
+ if (detect_doors(DEFAULT_RADIUS)) ident = TRUE;
+ if (detect_stairs(DEFAULT_RADIUS)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_DETECT_INVIS:
+ {
+ if (detect_monsters_invis(DEFAULT_RADIUS)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_SATISFY_HUNGER:
+ {
+ if (set_food(PY_FOOD_MAX - 1)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_BLESSING:
+ {
+ if (set_blessed(p_ptr->blessed + randint(12) + 6)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_HOLY_CHANT:
+ {
+ if (set_blessed(p_ptr->blessed + randint(24) + 12)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_HOLY_PRAYER:
+ {
+ if (set_blessed(p_ptr->blessed + randint(48) + 24)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_MONSTER_CONFUSION:
+ {
+ if (p_ptr->confusing == 0)
+ {
+ msg_print("Your hands begin to glow.");
+ p_ptr->confusing = TRUE;
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_SCROLL_PROTECTION_FROM_EVIL:
+ {
+ k = 3 * p_ptr->lev;
+ if (set_protevil(p_ptr->protevil + randint(25) + k)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_RUNE_OF_PROTECTION:
+ {
+ warding_glyph();
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_TRAP_DOOR_DESTRUCTION:
+ {
+ if (destroy_doors_touch()) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_STAR_DESTRUCTION:
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ {
+ destroy_area(p_ptr->py, p_ptr->px, 15, TRUE, FALSE);
+ }
+ else
+ {
+ msg_print("The dungeon trembles...");
+ }
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_DISPEL_UNDEAD:
+ {
+ if (dispel_undead(60)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_GENOCIDE:
+ {
+ (void)genocide(TRUE);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_MASS_GENOCIDE:
+ {
+ (void)mass_genocide(TRUE);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_ACQUIREMENT:
+ {
+ acquirement(p_ptr->py, p_ptr->px, 1, TRUE, FALSE);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_STAR_ACQUIREMENT:
+ {
+ acquirement(p_ptr->py, p_ptr->px, randint(2) + 1, TRUE, FALSE);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ /* ZAngband scrolls */
+ case SV_SCROLL_FIRE:
+ {
+ fire_ball(GF_FIRE, 0, 150, 4);
+
+ /*
+ * Note: "Double" damage since it is centered on
+ * the player ...
+ */
+ if (!p_ptr->oppose_fire && !p_ptr->resist_fire &&
+ !p_ptr->immune_fire)
+ {
+ take_hit(50 + randint(50) + (p_ptr->sensible_fire) ? 20 : 0,
+ "a Scroll of Fire");
+ }
+
+ ident = TRUE;
+
+ break;
+ }
+
+
+ case SV_SCROLL_ICE:
+ {
+ fire_ball(GF_ICE, 0, 175, 4);
+
+ if (!p_ptr->oppose_cold && !p_ptr->resist_cold &&
+ !p_ptr->immune_cold)
+ {
+ take_hit(100 + randint(100), "a Scroll of Ice");
+ }
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_CHAOS:
+ {
+ fire_ball(GF_CHAOS, 0, 222, 4);
+
+ if (!p_ptr->resist_chaos)
+ {
+ take_hit(111 + randint(111), "a Scroll of Chaos");
+ }
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_RUMOR:
+ {
+ char rumour[80];
+
+ msg_print("There is message on the scroll. It says:");
+ msg_print(NULL);
+
+ /* Pick random text */
+ switch (randint(20))
+ {
+ case 1:
+ {
+ get_rnd_line("chainswd.txt", rumour);
+
+ break;
+ }
+
+ case 2:
+ {
+ get_rnd_line("error.txt", rumour);
+
+ break;
+ }
+
+ case 3:
+ case 4:
+ case 5:
+ {
+ get_rnd_line("death.txt", rumour);
+
+ break;
+ }
+
+ default:
+ {
+ get_rnd_line("rumors.txt", rumour);
+
+ break;
+ }
+ }
+
+ msg_format("%s", rumour);
+ msg_print(NULL);
+
+ msg_print("The scroll disappears in a puff of smoke!");
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_SCROLL_ARTIFACT:
+ {
+ ident = TRUE;
+
+ if (!artifact_scroll()) used_up = FALSE;
+
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ /* Other readable items */
+ else
+ {
+ /* Maps */
+ if (o_ptr->sval >= 200)
+ {
+ int i, n;
+ char buf[80], fil[20];
+
+ strnfmt(fil, 20, "book-%d.txt", o_ptr->sval);
+
+ n = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, -1));
+
+ /* Parse all the fields */
+ for (i = 0; i < n; i += 4)
+ {
+ /* Grab the fields */
+ int x = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, i + 0));
+ int y = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, i + 1));
+ int w = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, i + 2));
+ int h = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, i + 3));
+
+ reveal_wilderness_around_player(y, x, h, w);
+ }
+ }
+
+ /* Normal parchements */
+ else
+ {
+ /* Save screen */
+ screen_save();
+
+ /* Get the filename */
+ q = format("book-%d.txt", o_ptr->sval);
+
+ /* Peruse the help file */
+ (void)show_file(q, NULL, 0, 0);
+
+ /* Load screen */
+ screen_load();
+
+ if (o_ptr->sval >= 100)
+ {
+ inscription_info[o_ptr->sval - 100].know = TRUE;
+ }
+
+ used_up = FALSE;
+ }
+ }
+
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* The item was tried */
+ object_tried(o_ptr);
+
+ /* An identification was made */
+ if (ident && !object_aware_p(o_ptr))
+ {
+ object_aware(o_ptr);
+ gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);
+ }
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+
+ /* Hack -- allow certain scrolls to be "preserved" */
+ if (!used_up) return;
+
+ sound(SOUND_SCROLL);
+
+ /* Destroy scroll */
+ inc_stack_size(item, -1);
+
+ if (get_skill(SKILL_ALCHEMY))
+ {
+ if (item >= 0)
+ {
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_SCROLL, SV_SCROLL_NOTHING));
+ object_aware(q_ptr);
+ object_known(q_ptr);
+
+ q_ptr->ident |= IDENT_STOREB;
+
+ (void)inven_carry(q_ptr, FALSE);
+ }
+ }
+}
+
+
+
+/* Set the 'stick mode' on */
+void set_stick_mode(object_type *o_ptr)
+{
+ s32b bonus = o_ptr->pval3 & 0xFFFF;
+ s32b max = o_ptr->pval3 >> 16;
+
+ exec_lua(format("get_level_use_stick = %d; get_level_max_stick = %d", bonus, max));
+}
+/* Remove 'stick mode' */
+void unset_stick_mode()
+{
+ exec_lua("get_level_use_stick = -1; get_level_max_stick = -1");
+}
+
+
+/*
+ * Use a staff. -RAK-
+ *
+ * One charge of one staff disappears.
+ *
+ * Hack -- staffs of identify can be "cancelled".
+ */
+void do_cmd_use_staff(void)
+{
+ int item, ident, chance;
+
+ s32b obvious, use_charge;
+
+ object_type *o_ptr;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ cptr q, s;
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* Restrict choices to wands */
+ item_tester_tval = TV_STAFF;
+
+ /* Set up the extra finder */
+ get_item_hook_find_obj_what = "Staff full name? ";
+ get_item_extra_hook = get_item_hook_find_obj;
+
+ /* Get an item */
+ q = "Use which staff? ";
+ s = "You have no staff to use.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Mega-Hack -- refuse to use a pile from the ground */
+ if ((item < 0) && (o_ptr->number > 1))
+ {
+ msg_print("You must first pick up the staffs.");
+ return;
+ }
+
+ /* Enter device mode */
+ set_stick_mode(o_ptr);
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Not identified yet */
+ ident = FALSE;
+
+ /* get the chance */
+ chance = exec_lua(format("return spell_chance(%d)", o_ptr->pval2));
+
+ /* Extract object flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Is it simple to use ? */
+ if (f4 & TR4_EASY_USE)
+ {
+ chance /= 3;
+ }
+
+ /* Give everyone a (slight) chance */
+ if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0))
+ {
+ chance = USE_DEVICE;
+ }
+
+ /* Roll for usage */
+ if (magik(chance))
+ {
+ if (flush_failure) flush();
+ msg_print("You failed to use the staff properly.");
+ sound(SOUND_FAIL);
+
+ /* Leave device mode */
+ unset_stick_mode();
+ return;
+ }
+
+ /* Notice empty staffs */
+ if (o_ptr->pval <= 0)
+ {
+ if (flush_failure) flush();
+ msg_print("The staff has no charges left.");
+ o_ptr->ident |= (IDENT_EMPTY);
+
+ /* Leave device mode */
+ unset_stick_mode();
+ return;
+ }
+
+
+ /* Sound */
+ sound(SOUND_ZAP);
+
+
+ /* Analyze the staff */
+ call_lua("activate_stick", "(d)", "dd", o_ptr->pval2, &obvious, &use_charge);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Tried the item */
+ object_tried(o_ptr);
+
+ /* An identification was made */
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+
+ /* Hack -- some uses are "free" */
+ if (!use_charge)
+ {
+ /* Leave device mode */
+ unset_stick_mode();
+
+ return;
+ }
+
+ /* An identification was made */
+ if (obvious)
+ {
+ object_aware(o_ptr);
+ }
+
+ /* Use a single charge */
+ o_ptr->pval--;
+
+ /* XXX Hack -- unstack if necessary */
+ if ((item >= 0) && (o_ptr->number > 1))
+ {
+ object_type forge;
+ object_type *q_ptr;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Obtain a local object */
+ object_copy(q_ptr, o_ptr);
+
+ /* Modify quantity */
+ q_ptr->number = 1;
+
+ /* Restore the charges */
+ o_ptr->pval++;
+
+ /* Unstack the used item */
+ o_ptr->number--;
+ item = inven_carry(q_ptr, FALSE);
+
+ /* Message */
+ msg_print("You unstack your staff.");
+ }
+
+ /* Describe charges in the pack */
+ if (item >= 0)
+ {
+ inven_item_charges(item);
+ }
+
+ /* Describe charges on the floor */
+ else
+ {
+ floor_item_charges(0 - item);
+ }
+
+ /* Leave device mode */
+ unset_stick_mode();
+}
+
+
+/*
+ * Aim a wand (from the pack or floor).
+ *
+ * Use a single charge from a single item.
+ * Handle "unstacking" in a logical manner.
+ *
+ * For simplicity, you cannot use a stack of items from the
+ * ground. This would require too much nasty code.
+ *
+ * There are no wands which can "destroy" themselves, in the p_ptr->inventory
+ * or on the ground, so we can ignore this possibility. Note that this
+ * required giving "wand of wonder" the ability to ignore destruction
+ * by electric balls.
+ *
+ * All wands can be "cancelled" at the "Direction?" prompt for free.
+ *
+ * Note that the basic "bolt" wands do slightly less damage than the
+ * basic "bolt" rods, but the basic "ball" wands do the same damage
+ * as the basic "ball" rods.
+ */
+void do_cmd_aim_wand(void)
+{
+ s32b obvious, use_charge;
+
+ int item, ident, chance, sval;
+
+ object_type *o_ptr;
+
+ cptr q, s;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* Restrict choices to wands */
+ item_tester_tval = TV_WAND;
+
+ /* Set up the extra finder */
+ get_item_hook_find_obj_what = "Wand full name? ";
+ get_item_extra_hook = get_item_hook_find_obj;
+
+ /* Get an item */
+ q = "Aim which wand? ";
+ s = "You have no wand to aim.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+
+ /* Mega-Hack -- refuse to aim a pile from the ground */
+ if ((item < 0) && (o_ptr->number > 1))
+ {
+ msg_print("You must first pick up the wands.");
+ return;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Not identified yet */
+ ident = FALSE;
+
+ /* Enter device mode */
+ set_stick_mode(o_ptr);
+
+ /* get the chance */
+ chance = exec_lua(format("return spell_chance(%d)", o_ptr->pval2));
+
+ /* Extract object flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Is it simple to use ? */
+ if (f4 & TR4_EASY_USE)
+ {
+ chance /= 3;
+ }
+
+ /* Roll for usage */
+ if (magik(chance))
+ {
+ if (flush_failure) flush();
+ msg_print("You failed to use the wand properly.");
+ sound(SOUND_FAIL);
+
+ /* Leave device mode */
+ unset_stick_mode();
+ return;
+ }
+
+ /* The wand is already empty! */
+ if (o_ptr->pval <= 0)
+ {
+ if (flush_failure) flush();
+ msg_print("The wand has no charges left.");
+ o_ptr->ident |= (IDENT_EMPTY);
+
+ /* Leave device mode */
+ unset_stick_mode();
+ return;
+ }
+
+
+ /* Sound */
+ sound(SOUND_ZAP);
+
+
+ /* XXX Hack -- Extract the "sval" effect */
+ sval = o_ptr->sval;
+
+ /* Analyze the wand */
+ call_lua("activate_stick", "(d)", "dd", o_ptr->pval2, &obvious, &use_charge);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Mark it as tried */
+ object_tried(o_ptr);
+
+ /* Hack -- some uses are "free" */
+ if (!use_charge)
+ {
+ /* Leave device mode */
+ unset_stick_mode();
+
+ return;
+ }
+
+ /* An identification was made */
+ if (obvious)
+ {
+ object_aware(o_ptr);
+ }
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+
+ /* Use a single charge */
+ o_ptr->pval--;
+
+ /* Describe the charges in the pack */
+ if (item >= 0)
+ {
+ inven_item_charges(item);
+ }
+
+ /* Describe the charges on the floor */
+ else
+ {
+ floor_item_charges(0 - item);
+ }
+
+ /* Leave device mode */
+ unset_stick_mode();
+}
+
+
+
+
+
+
+/*
+ * Activate (zap) a Rod
+ *
+ * Unstack fully charged rods as needed.
+ *
+ * Hack -- rods of perception/genocide can be "cancelled"
+ * All rods can be cancelled at the "Direction?" prompt
+ */
+
+
+/*
+ * Hook to determine if an object is zapable
+ */
+static bool_ item_tester_hook_zapable(object_type *o_ptr)
+{
+ if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_ROD_MAIN)) return (TRUE);
+
+ /* Assume not */
+ return (FALSE);
+}
+
+
+/*
+ * Hook to determine if an object is attachable
+ */
+static bool_ item_tester_hook_attachable(object_type *o_ptr)
+{
+ if ((o_ptr->tval == TV_ROD_MAIN) &&
+ (o_ptr->pval == SV_ROD_NOTHING)) return (TRUE);
+
+ /* Assume not */
+ return (FALSE);
+}
+
+
+/*
+ * Combine a rod and a rod tip
+ */
+void zap_combine_rod_tip(object_type *q_ptr, int tip_item)
+{
+ int item;
+
+ object_type *o_ptr;
+
+ cptr q, s;
+
+ u32b f1, f2, f3, f4, f5, esp;
+ s32b cost;
+
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* Restrict choices to rods */
+ item_tester_hook = item_tester_hook_attachable;
+
+ /* Get an item */
+ q = "Attach the rod tip with which rod? ";
+ s = "You have no rod to attach to.";
+ if (!get_item(&item, q, s, (USE_INVEN))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Examine the rod */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Calculate rod tip's mana cost */
+ cost = q_ptr->pval;
+
+ if (f4 & TR4_CHEAPNESS)
+ {
+ cost /= 2;
+ }
+
+ /*
+ * The rod must have at least the same mana capacity as the
+ * rod tip spell needs
+ */
+ if (o_ptr->pval2 < cost)
+ {
+ msg_print("This rod doesn't have enough mana for the rod tip.");
+ return;
+ }
+
+ /* Attach the tip to the rod */
+ o_ptr->pval = q_ptr->sval;
+
+ /* Destroy rod tip */
+ inc_stack_size(tip_item, -1);
+}
+
+
+/*
+ * Zap a rod, or attack a rod tip to a rod
+ */
+void do_cmd_zap_rod(void)
+{
+ int item, ident, chance, dir, lev;
+
+ int cost;
+
+ bool_ require_dir;
+
+ object_type *o_ptr;
+
+ object_kind *tip_ptr;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ cptr q, s;
+
+ /* Hack -- let perception get aborted */
+ bool_ use_charge = TRUE;
+
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+
+ /* Restrict choices to rods */
+ item_tester_hook = item_tester_hook_zapable;
+
+ /* Set up the extra finder */
+ get_item_hook_find_obj_what = "Rod full name? ";
+ get_item_extra_hook = get_item_hook_find_obj;
+
+ /* Get an item */
+ q = "Zap which rod? ";
+ s = "You have no rod to zap.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+
+ /* "Zapping" a Rod Tip on rod of nothing will attach it */
+ if (o_ptr->tval == TV_ROD)
+ {
+ if (item >= 0)
+ {
+ zap_combine_rod_tip(o_ptr, item);
+ return;
+ }
+ else
+ {
+ msg_print("You can't zap a rod tip that's on the floor.");
+ return;
+ }
+ }
+
+
+ /* Non-directed rods */
+ if (o_ptr->pval < SV_ROD_MIN_DIRECTION)
+ {
+ require_dir = FALSE;
+ }
+
+ /* Some rods always require direction */
+ else
+ {
+ switch (o_ptr->pval)
+ {
+ case SV_ROD_DETECT_TRAP:
+ case SV_ROD_HAVOC:
+ case SV_ROD_HOME:
+ {
+ require_dir = FALSE;
+ break;
+ }
+
+ default:
+ {
+ require_dir = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Get a direction (unless KNOWN not to need it) */
+ if (!object_aware_p(o_ptr) || require_dir)
+ {
+ /* Get a direction, allow cancel */
+ if (!get_aim_dir(&dir)) return;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Examine the rod */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (f4 & TR4_FAST_CAST) energy_use /= 2;
+
+ /* Not identified yet */
+ ident = FALSE;
+
+ /* Extract the item level */
+ tip_ptr = &k_info[lookup_kind(TV_ROD, o_ptr->pval)];
+ lev = k_info[lookup_kind(TV_ROD, o_ptr->pval)].level;
+
+ /* Base chance of success */
+ chance = p_ptr->skill_dev;
+
+ /* Confusion hurts skill */
+ if (p_ptr->confused) chance = chance / 2;
+
+ /* High level objects are harder */
+ chance = chance - ((lev > 50) ? 50 : lev);
+
+ if (chance <= 0)
+ {
+ chance = 1;
+ }
+
+ /* Is it simple to use ? */
+ if (f4 & TR4_EASY_USE)
+ {
+ chance *= 10;
+ }
+
+ /* Give everyone a (slight) chance */
+ if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0))
+ {
+ chance = USE_DEVICE;
+ }
+
+ /* Roll for usage */
+ if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE))
+ {
+ /* Flush input if necessary */
+ if (flush_failure) flush();
+
+ /* Message */
+ msg_print("You failed to use the rod properly.");
+
+ sound(SOUND_FAIL);
+
+ return;
+ }
+
+ /* Extract mana cost */
+ cost = tip_ptr->pval;
+
+ /* "Cheapness" ego halven the cost */
+ if (f4 & TR4_CHEAPNESS) cost = cost / 2;
+
+ /* A single rod is still charging */
+ if (o_ptr->timeout < cost)
+ {
+ /* Flush input if necessary */
+ if (flush_failure) flush();
+
+ /* Message */
+ msg_print("The rod does not have enough mana yet.");
+
+ return;
+ }
+
+ /* Increase the timeout by the rod kind's pval. */
+ o_ptr->timeout -= cost;
+
+ /* Sound */
+ sound(SOUND_ZAP);
+
+ /* Analyze the rod */
+ switch (o_ptr->pval)
+ {
+ case SV_ROD_HOME:
+ {
+ ident = TRUE;
+
+ do_cmd_home_trump();
+
+ break;
+ }
+
+ case SV_ROD_DETECT_TRAP:
+ {
+ if (detect_traps(DEFAULT_RADIUS)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_DETECT_DOOR:
+ {
+ if (detect_doors(DEFAULT_RADIUS)) ident = TRUE;
+ if (detect_stairs(DEFAULT_RADIUS)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_IDENTIFY:
+ {
+ ident = TRUE;
+
+ if (!ident_spell()) use_charge = FALSE;
+
+ break;
+ }
+
+ case SV_ROD_RECALL:
+ {
+ if ((dungeon_flags2 & DF2_ASK_LEAVE) && !get_check("Leave this unique level forever? "))
+ {
+ use_charge = FALSE;
+ }
+ else
+ {
+ recall_player(21, 15);
+
+ ident = TRUE;
+ }
+
+ break;
+ }
+
+ case SV_ROD_ILLUMINATION:
+ {
+ if (lite_area(damroll(2, 8), 2)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_MAPPING:
+ {
+ map_area();
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_DETECTION:
+ {
+ detect_all(DEFAULT_RADIUS);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_PROBING:
+ {
+ probing();
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_CURING:
+ {
+ if (set_blind(0)) ident = TRUE;
+ if (set_poisoned(0)) ident = TRUE;
+ if (set_confused(0)) ident = TRUE;
+ if (set_stun(0)) ident = TRUE;
+ if (set_cut(0)) ident = TRUE;
+ if (set_image(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_HEALING:
+ {
+ if (hp_player(500)) ident = TRUE;
+ if (set_stun(0)) ident = TRUE;
+ if (set_cut(0)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_RESTORATION:
+ {
+ if (restore_level()) ident = TRUE;
+ if (do_res_stat(A_STR, TRUE)) ident = TRUE;
+ if (do_res_stat(A_INT, TRUE)) ident = TRUE;
+ if (do_res_stat(A_WIS, TRUE)) ident = TRUE;
+ if (do_res_stat(A_DEX, TRUE)) ident = TRUE;
+ if (do_res_stat(A_CON, TRUE)) ident = TRUE;
+ if (do_res_stat(A_CHR, TRUE)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_SPEED:
+ {
+ if (!p_ptr->fast)
+ {
+ if (set_fast(randint(30) + 15, 10)) ident = TRUE;
+ }
+ else
+ {
+ (void)set_fast(p_ptr->fast + 5, 10);
+ }
+
+ break;
+ }
+
+ case SV_ROD_TELEPORT_AWAY:
+ {
+ if (teleport_monster(dir)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_DISARMING:
+ {
+ if (disarm_trap(dir)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_LITE:
+ {
+ msg_print("A line of blue shimmering light appears.");
+ lite_line(dir);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_SLEEP_MONSTER:
+ {
+ if (sleep_monster(dir)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_SLOW_MONSTER:
+ {
+ if (slow_monster(dir)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_DRAIN_LIFE:
+ {
+ if (drain_life(dir, 75)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_POLYMORPH:
+ {
+ if (poly_monster(dir)) ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_ACID_BOLT:
+ {
+ fire_bolt_or_beam(10, GF_ACID, dir, damroll(6, 8));
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_ELEC_BOLT:
+ {
+ fire_bolt_or_beam(10, GF_ELEC, dir, damroll(3, 8));
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_FIRE_BOLT:
+ {
+ fire_bolt_or_beam(10, GF_FIRE, dir, damroll(8, 8));
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_COLD_BOLT:
+ {
+ fire_bolt_or_beam(10, GF_COLD, dir, damroll(5, 8));
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_ACID_BALL:
+ {
+ fire_ball(GF_ACID, dir, 60, 2);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_ELEC_BALL:
+ {
+ fire_ball(GF_ELEC, dir, 32, 2);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_FIRE_BALL:
+ {
+ fire_ball(GF_FIRE, dir, 72, 2);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_COLD_BALL:
+ {
+ fire_ball(GF_COLD, dir, 48, 2);
+
+ ident = TRUE;
+
+ break;
+ }
+
+ case SV_ROD_HAVOC:
+ {
+ call_chaos();
+
+ ident = TRUE;
+
+ break;
+ }
+
+ default:
+ {
+ process_hooks(HOOK_ZAP, "(d,d)", o_ptr->tval, o_ptr->sval);
+
+ break;
+ }
+ }
+
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Tried the object */
+ object_tried(o_ptr);
+
+ /* Successfully determined the object function */
+ if (ident && !object_aware_p(o_ptr))
+ {
+ object_aware(o_ptr);
+ gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);
+ }
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Hack -- deal with cancelled zap */
+ if (!use_charge)
+ {
+ o_ptr->timeout += cost;
+
+ return;
+ }
+}
+
+
+
+
+/*
+ * Hook to determine if an object is activable
+ */
+static bool_ item_tester_hook_activate(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Not known */
+ if (!object_known_p(o_ptr)) return (FALSE);
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Check activation flag */
+ if (f3 & (TR3_ACTIVATE)) return (TRUE);
+
+ /* Assume not */
+ return (FALSE);
+}
+
+
+
+/*
+ * Hack -- activate the ring of power
+ */
+int ring_of_power()
+{
+ char ch = 0, p = 0;
+
+ int plev = p_ptr->lev;
+
+ int timeout = 0;
+
+
+ /* Select power to use */
+ while (TRUE)
+ {
+ if (!get_com("[S]ummon a wraith, [R]ule the world or "
+ "[C]ast a powerful attack? ", &ch))
+ {
+ return (0);
+ }
+
+ if (ch == 'S' || ch == 's')
+ {
+ p = 1;
+ break;
+ }
+ if (ch == 'R' || ch == 'r')
+ {
+ p = 2;
+ break;
+ }
+ if (ch == 'C' || ch == 'c')
+ {
+ p = 3;
+ break;
+ }
+ }
+
+ /* Summon a Wraith */
+ if (p == 1)
+ {
+ /* Rewrite this -- pelpel */
+ if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2),
+ (plev > 47 ? SUMMON_HI_UNDEAD_NO_UNIQUES : SUMMON_UNDEAD),
+ (bool_)(((plev > 24) && (randint(3) == 1)) ? TRUE : FALSE)))
+ {
+ msg_print("Cold winds begin to blow around you, "
+ "carrying with them the stench of decay...");
+ msg_print("Ancient, long-dead forms arise from the ground "
+ "to serve you!");
+ }
+ timeout = 200 + rand_int(200);
+ }
+
+ /* Rule the World -- only if we can really do so */
+ else if (p == 2)
+ {
+ msg_print("The power of the ring destroys the world!");
+ msg_print("The world changes!");
+
+ autosave_checkpoint();
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ timeout = 250 + rand_int(250);
+ }
+
+ /* Cast a powerful spell */
+ else if (p == 3)
+ {
+ int dir;
+
+ if (!get_aim_dir(&dir)) return (0);
+
+ if (rand_int(3) == 0)
+ {
+ msg_print("You call the fire of Mount Doom!");
+ fire_ball(GF_METEOR, dir, 600, 4);
+ }
+ else
+ {
+ msg_print("Your ring tries to take possession of your enemy's mind!");
+ fire_bolt(GF_CHARM, dir, 600);
+ }
+ timeout = 300 + rand_int(300);
+ }
+
+ return (timeout);
+}
+
+
+
+
+/*
+ * Enchant some bolts
+ */
+bool_ brand_bolts(void)
+{
+ int i;
+
+
+ /* Use the first acceptable bolts */
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-bolts */
+ if (o_ptr->tval != TV_BOLT) continue;
+
+ /* Skip artifacts and ego-items */
+ if (o_ptr->art_name || artifact_p(o_ptr) || ego_item_p(o_ptr)) continue;
+
+ /* Skip cursed/broken items */
+ if (cursed_p(o_ptr)) continue;
+
+ /* Randomize */
+ if (rand_int(100) < 75) continue;
+
+ /* Message */
+ msg_print("Your bolts are covered in a fiery aura!");
+
+ /* Ego-item */
+ o_ptr->name2 = EGO_FLAME;
+
+ /* Apply the ego */
+ apply_magic(o_ptr, dun_level, FALSE, FALSE, FALSE);
+
+ /* Enchant */
+ enchant(o_ptr, rand_int(3) + 4, ENCH_TOHIT | ENCH_TODAM);
+
+ /* Notice */
+ return (TRUE);
+ }
+
+ /* Flush */
+ if (flush_failure) flush();
+
+ /* Fail */
+ msg_print("The fiery enchantment failed.");
+
+ /* Notice */
+ return (TRUE);
+}
+
+
+/*
+ * Objects in the p_ptr->inventory can now be activated, and
+ * SOME of those may be able to stack (ego wands or something)
+ * in any case, we can't know that it's impossible. *BUT* we'll
+ * ignore it for now, and the timeout will be set on the entire stack
+ * of objects. Reduces their utility, but oh well.
+ *
+ * Note that it always takes a turn to activate an object, even if
+ * the user hits "escape" at the "direction" prompt.
+ */
+void do_cmd_activate(void)
+{
+ int item, lev, chance;
+
+ char ch, spell_choice;
+
+ object_type *o_ptr;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ cptr q, s;
+
+
+ /* Prepare the hook */
+ item_tester_hook = item_tester_hook_activate;
+
+ /* Get an item */
+ command_wrk = USE_EQUIP;
+ q = "Activate which item? ";
+ s = "You have nothing to activate.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Extract object flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Wearable items have to be worn */
+ if (!(f5 & TR5_ACTIVATE_NO_WIELD))
+ {
+ if (item < INVEN_WIELD)
+ {
+ msg_print("You must wear it to activate it.");
+ return;
+ }
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Extract the item level */
+ lev = k_info[o_ptr->k_idx].level;
+
+ /* Hack -- Use artifact level instead */
+ if (artifact_p(o_ptr))
+ {
+ if (o_ptr->tval == TV_RANDART)
+ {
+ lev = random_artifacts[o_ptr->sval].level;
+ }
+ else
+ {
+ lev = a_info[o_ptr->name1].level;
+ }
+ }
+
+ /* Base chance of success */
+ chance = p_ptr->skill_dev;
+
+ /* Confusion hurts skill */
+ if (p_ptr->confused) chance = chance / 2;
+
+ /* Hight level objects are harder */
+ chance = chance - ((lev > 50) ? 50 : lev);
+
+ if (chance <= 0)
+ {
+ chance = 1;
+ }
+
+ /* Is it simple to use ? */
+ if (f4 & TR4_EASY_USE)
+ {
+ chance *= 10;
+ }
+
+ /* Give everyone a (slight) chance */
+ if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0))
+ {
+ chance = USE_DEVICE;
+ }
+
+ /* Roll for usage */
+ if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE))
+ {
+ if (flush_failure) flush();
+ msg_print("You failed to activate it properly.");
+ sound(SOUND_FAIL);
+ return;
+ }
+
+ /* Check the recharge */
+ if (o_ptr->timeout)
+ {
+ /* Mage Staff of Spells -- Have another timeout in xtra2 */
+ if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL) && o_ptr->xtra2)
+ {
+ msg_print("It whines, glows and fades...");
+ return;
+ }
+
+ /* Monster eggs */
+ else if (o_ptr->tval == TV_EGG)
+ {
+ msg_print("You resume the development of the egg.");
+ o_ptr->timeout = 0;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Success */
+ return;
+ }
+
+ /* Normal activatable items */
+ else
+ {
+ msg_print("It whines, glows and fades...");
+ return;
+ }
+ }
+
+
+ /* Activate the item */
+ msg_print("You activate it...");
+
+ /* Sound */
+ sound(SOUND_ZAP);
+
+ /* Lua hook ? -- go first to allow lua to override */
+ if (process_hooks(HOOK_ACTIVATE, "(d)", item))
+ {
+ return;
+ }
+
+ /* New mostly unified activation code
+ This has to be early to allow artifacts to override normal items -- neil */
+
+ if ( activation_aux(o_ptr, TRUE, item) == NULL )
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Success */
+ return;
+ }
+
+ /* Mage Staff of Spells */
+ if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL))
+ {
+ while (TRUE)
+ {
+ if (!get_com("Use Spell [1] or [2]?", &ch))
+ {
+ return;
+ }
+
+ if (ch == '1')
+ {
+ spell_choice = 1;
+ break;
+ }
+
+ if (ch == '2')
+ {
+ spell_choice = 2;
+ break;
+ }
+ }
+
+ if (spell_choice == 1)
+ {
+ /* Still need to check timeouts because there is another counter */
+ if (o_ptr->timeout)
+ {
+ msg_print("The first spell is still charging!");
+ return;
+ }
+
+ /* Cast spell 1 */
+ activate_spell(o_ptr, spell_choice);
+ }
+ else if (spell_choice == 2)
+ {
+ /* Still need to check timeouts because there is another counter */
+ if (o_ptr->xtra2)
+ {
+ msg_print("The second spell is still charging!");
+ return;
+ }
+
+ /* Cast spell 2 */
+ activate_spell(o_ptr, spell_choice);
+ }
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Success */
+ return;
+ }
+
+ /* Monster eggs */
+ if (o_ptr->tval == TV_EGG)
+ {
+ msg_print("You stop the development of the egg.");
+ o_ptr->timeout = -1;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Success */
+ return;
+ }
+
+ /* Musical instruments */
+ if (o_ptr->tval == TV_INSTRUMENT)
+ {
+ /* Horns */
+ if (o_ptr->sval == SV_HORN)
+ {
+ msg_format("Your instrument emits a loud sound!");
+
+ aggravate_monsters(1);
+
+ o_ptr->timeout = 100;
+ }
+
+ /* Success */
+ return;
+ }
+
+ /* Mistake */
+ msg_print("Oops. That object cannot be activated.");
+}
+
+
+
+const char *activation_aux(object_type * o_ptr, bool_ doit, int item)
+{
+ int plev = get_skill(SKILL_DEVICE);
+
+ int i = 0, ii = 0, ij = 0, k, dir, dummy = 0;
+ int chance;
+ bool_ is_junkart = (o_ptr->tval == TV_RANDART);
+
+ int spell = 0;
+
+ /* Junkarts */
+ if (is_junkart)
+ spell = activation_info[o_ptr->pval2].spell;
+
+ /* True Actifacts */
+ if (!spell && o_ptr->name1)
+ spell = a_info[o_ptr->name1].activate;
+
+ /* Random and Alchemist Artifacts */
+ if (!spell && o_ptr->art_name)
+ spell = o_ptr->xtra2;
+
+ /* Ego Items */
+ if (!spell && o_ptr->name2)
+ spell = e_info[o_ptr->name2].activate;
+
+ /* Dual egos with the second ego having the activation */
+ if (!spell && o_ptr->name2b)
+ spell = e_info[o_ptr->name2b].activate;
+
+ /* Intrinsic to item type (rings of Ice, etc) */
+ if (!spell)
+ spell = k_info[o_ptr->k_idx].activate;
+
+ /* Complain about mis-configured .txt files? */
+ if (!spell)
+ return "Unknown!";
+
+ /* Negative means a unified spell index */
+ if (spell < 0)
+ {
+ if (doit)
+ {
+ call_lua("activate_activation", "(d,d)", "", -spell, item);
+ o_ptr->timeout = exec_lua(format("return get_activation_timeout(%d)", -spell));
+ }
+ else
+ {
+ return string_exec_lua(format("return get_activation_desc(%d)", -spell));
+ }
+ }
+ else
+ {
+ /* Activate for attack */
+ switch (spell)
+ {
+ case ACT_GILGALAD:
+ {
+ if (!doit) return "starlight (75) every 75+d75 turns";
+ for (k = 1; k < 10; k++)
+ {
+ if (k - 5) fire_beam(GF_LITE, k, 75);
+ }
+
+ o_ptr->timeout = rand_int(75) + 75;
+
+ break;
+ }
+
+ case ACT_CELEBRIMBOR:
+ {
+ if (!doit) return "temporary ESP (dur 20+d20) every 20+d50 turns";
+ set_tim_esp(p_ptr->tim_esp + randint(20) + 20);
+
+ o_ptr->timeout = rand_int(50) + 20;
+
+ break;
+ }
+
+ case ACT_SKULLCLEAVER:
+ {
+ if (!doit) return "destruction every 200+d200 turns";
+ destroy_area(p_ptr->py, p_ptr->px, 15, TRUE, FALSE);
+
+ o_ptr->timeout = rand_int(200) + 200;
+
+ break;
+ }
+
+ case ACT_HARADRIM:
+ {
+ if (!doit) return "berserk strength every 50+d50 turns";
+ set_afraid(0);
+ set_shero(p_ptr->shero + randint(25) + 25);
+ hp_player(30);
+
+ o_ptr->timeout = rand_int(50) + 50;
+
+ break;
+ }
+
+ case ACT_FUNDIN:
+ {
+ if (!doit) return "dispel evil (x4) every 100+d100 turns";
+ dispel_evil(p_ptr->lev * 4);
+
+ o_ptr->timeout = rand_int(100) + 100;
+
+ break;
+ }
+
+ case ACT_EOL:
+ {
+ if (!doit) return "mana bolt (9d8) 7+d7 turns";
+ if (!get_aim_dir(&dir)) break;
+ fire_bolt(GF_MANA, dir, damroll(9, 8));
+
+ o_ptr->timeout = rand_int(7) + 7;
+
+ break;
+ }
+
+ case ACT_UMBAR:
+ {
+ if (!doit) return "magic arrow (10d10) every 20+d20 turns";
+ if (!get_aim_dir(&dir)) break;
+ fire_bolt(GF_MISSILE, dir, damroll(10, 10));
+
+ o_ptr->timeout = rand_int(20) + 20;
+
+ break;
+ }
+
+ case ACT_NUMENOR:
+ {
+ /* Give full knowledge */
+ /* Hack -- Maximal info */
+ monster_race *r_ptr;
+ cave_type *c_ptr;
+ int x, y, m;
+
+ if (!doit) return "analyze monster every 500+d200 turns";
+
+ if (!tgt_pt(&x, &y)) break;
+
+ c_ptr = &cave[y][x];
+ if (!c_ptr->m_idx) break;
+
+ r_ptr = &r_info[c_ptr->m_idx];
+
+ /* Observe "maximal" attacks */
+ for (m = 0; m < 4; m++)
+ {
+ /* Examine "actual" blows */
+ if (r_ptr->blow[m].effect || r_ptr->blow[m].method)
+ {
+ /* Hack -- maximal observations */
+ r_ptr->r_blows[m] = MAX_UCHAR;
+ }
+ }
+
+ /* Hack -- maximal drops */
+ r_ptr->r_drop_gold = r_ptr->r_drop_item =
+ (((r_ptr->flags1 & (RF1_DROP_4D2)) ? 8 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_3D2)) ? 6 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_2D2)) ? 4 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_1D2)) ? 2 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_90)) ? 1 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_60)) ? 1 : 0));
+
+ /* Hack -- but only "valid" drops */
+ if (r_ptr->flags1 & (RF1_ONLY_GOLD)) r_ptr->r_drop_item = 0;
+ if (r_ptr->flags1 & (RF1_ONLY_ITEM)) r_ptr->r_drop_gold = 0;
+
+ /* Hack -- observe many spells */
+ r_ptr->r_cast_inate = MAX_UCHAR;
+ r_ptr->r_cast_spell = MAX_UCHAR;
+
+ /* Hack -- know all the flags */
+ r_ptr->r_flags1 = r_ptr->flags1;
+ r_ptr->r_flags2 = r_ptr->flags2;
+ r_ptr->r_flags3 = r_ptr->flags3;
+ r_ptr->r_flags4 = r_ptr->flags4;
+ r_ptr->r_flags5 = r_ptr->flags5;
+ r_ptr->r_flags6 = r_ptr->flags6;
+ r_ptr->r_flags7 = r_ptr->flags7;
+ r_ptr->r_flags8 = r_ptr->flags8;
+ r_ptr->r_flags9 = r_ptr->flags9;
+
+ o_ptr->timeout = rand_int(200) + 500;
+
+ break;
+ }
+
+ case ACT_KNOWLEDGE:
+ {
+ if (!doit) return "whispers from beyond(sanity drain) 100+d200 turns";
+ identify_fully();
+ take_sanity_hit(damroll(10, 7), "the sounds of the dead");
+
+ o_ptr->timeout = rand_int(200) + 100;
+
+ break;
+ }
+
+ case ACT_UNDEATH:
+ {
+ if (!doit) return "ruination every 10+d10 turns";
+ msg_print("The phial wells with dark light...");
+ unlite_area(damroll(2, 15), 3);
+ take_hit(damroll(10, 10), "activating The Phial of Undeath");
+ (void)dec_stat(A_DEX, 25, STAT_DEC_PERMANENT);
+ (void)dec_stat(A_WIS, 25, STAT_DEC_PERMANENT);
+ (void)dec_stat(A_CON, 25, STAT_DEC_PERMANENT);
+ (void)dec_stat(A_STR, 25, STAT_DEC_PERMANENT);
+ (void)dec_stat(A_CHR, 25, STAT_DEC_PERMANENT);
+ (void)dec_stat(A_INT, 25, STAT_DEC_PERMANENT);
+
+ o_ptr->timeout = rand_int(10) + 10;
+
+ break;
+ }
+
+ case ACT_THRAIN:
+ {
+ if (!doit) return "detection every 30+d30 turns";
+ msg_print("The stone glows a deep green...");
+ detect_all(DEFAULT_RADIUS);
+
+ o_ptr->timeout = rand_int(30) + 30;
+
+ break;
+ }
+
+ case ACT_BARAHIR:
+ {
+ if (!doit) return "dispel small life every 55+d55 turns";
+ msg_print("You exterminate small life.");
+ (void)dispel_monsters(4);
+
+ o_ptr->timeout = rand_int(55) + 55;
+
+ break;
+ }
+
+ case ACT_TULKAS:
+ {
+ if (!doit) return "haste self (75+d75 turns) every 150+d150 turns";
+ msg_print("The ring glows brightly...");
+ if (!p_ptr->fast)
+ {
+ (void)set_fast(randint(75) + 75, 10);
+ }
+ else
+ {
+ (void)set_fast(p_ptr->fast + 5, 10);
+ }
+
+ o_ptr->timeout = rand_int(150) + 150;
+
+ break;
+ }
+
+ case ACT_NARYA:
+ {
+ if (!doit) return "healing (500) every 200+d100 turns";
+ msg_print("The ring glows deep red...");
+ hp_player(500);
+ set_blind(0);
+ set_confused(0);
+ set_poisoned(0);
+ set_stun(0);
+ set_cut(0);
+
+ o_ptr->timeout = rand_int(100) + 200;
+
+ break;
+ }
+
+ case ACT_NENYA:
+ {
+ if (!doit) return "healing (800) every 100+d200 turns";
+ msg_print("The ring glows bright white...");
+ hp_player(800);
+ set_blind(0);
+ set_confused(0);
+ set_poisoned(0);
+ set_stun(0);
+ set_cut(0);
+
+ o_ptr->timeout = rand_int(200) + 100;
+
+ break;
+ }
+
+ case ACT_VILYA:
+ {
+ if (!doit) return "greater healing (900) every 200+d200 turns";
+ msg_print("The ring glows deep blue...");
+ hp_player(900);
+ set_blind(0);
+ set_confused(0);
+ set_poisoned(0);
+ set_stun(0);
+ set_cut(0);
+ if (p_ptr->black_breath)
+ {
+ p_ptr->black_breath = FALSE;
+ msg_print("The hold of the Black Breath on you is broken!");
+ }
+
+ o_ptr->timeout = rand_int(200) + 200;
+
+ break;
+ }
+
+ case ACT_POWER:
+ {
+ if (!doit) return "powerful things";
+ msg_print("The ring glows intensely black...");
+
+ o_ptr->timeout = ring_of_power();
+
+ break;
+ }
+
+
+ /* The Stone of Lore is perilous, for the sake of game balance. */
+ case ACT_STONE_LORE:
+ {
+ if (!doit) return "perilous identify every turn";
+ msg_print("The stone reveals hidden mysteries...");
+ if (!ident_spell()) break;
+
+ if (has_ability(AB_PERFECT_CASTING))
+ {
+ /* Sufficient mana */
+ if (20 <= p_ptr->csp)
+ {
+ /* Use some mana */
+ p_ptr->csp -= 20;
+ }
+
+ /* Over-exert the player */
+ else
+ {
+ int oops = 20 - p_ptr->csp;
+
+ /* No mana left */
+ p_ptr->csp = 0;
+ p_ptr->csp_frac = 0;
+
+ /* Message */
+ msg_print("You are too weak to control the stone!");
+
+ /* Hack -- Bypass free action */
+ (void)set_paralyzed(p_ptr->paralyzed +
+ randint(5 * oops + 1));
+
+ /* Confusing. */
+ (void)set_confused(p_ptr->confused +
+ randint(5 * oops + 1));
+ }
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_MANA);
+ }
+
+ take_hit(damroll(1, 12), "perilous secrets");
+
+ /* Confusing. */
+ if (rand_int(5) == 0)
+ {
+ (void)set_confused(p_ptr->confused + randint(10));
+ }
+
+ /* Exercise a little care... */
+ if (rand_int(20) == 0)
+ {
+ take_hit(damroll(4, 10), "perilous secrets");
+ }
+
+ o_ptr->timeout = 1;
+
+ break;
+ }
+
+ case ACT_RAZORBACK:
+ {
+ if (!doit) return "star ball (150) every 1000 turns";
+ msg_print("Your armor is surrounded by lightning...");
+ for (i = 0; i < 8; i++) fire_ball(GF_ELEC, ddd[i], 150, 3);
+
+ o_ptr->timeout = 1000;
+
+ break;
+ }
+
+ case ACT_BLADETURNER:
+ {
+ if (!doit) return "invulnerability (4+d8) every 800 turns";
+ set_invuln(p_ptr->invuln + randint(8) + 4);
+
+ o_ptr->timeout = 800;
+
+ break;
+ }
+
+ case ACT_MEDIATOR:
+ {
+ if (!doit) return "breathe elements (300), berserk rage, bless, and resistance every 400 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe the elements.");
+ fire_ball(GF_MISSILE, dir, 300, 4);
+ msg_print("Your armor glows many colours...");
+ (void)set_afraid(0);
+ (void)set_shero(p_ptr->shero + randint(50) + 50);
+ (void)hp_player(30);
+ (void)set_blessed(p_ptr->blessed + randint(50) + 50);
+ (void)set_oppose_acid(p_ptr->oppose_acid + randint(50) + 50);
+ (void)set_oppose_elec(p_ptr->oppose_elec + randint(50) + 50);
+ (void)set_oppose_fire(p_ptr->oppose_fire + randint(50) + 50);
+ (void)set_oppose_cold(p_ptr->oppose_cold + randint(50) + 50);
+ (void)set_oppose_pois(p_ptr->oppose_pois + randint(50) + 50);
+
+ o_ptr->timeout = 400;
+
+ break;
+ }
+
+ case ACT_BELEGENNON:
+ {
+ if (!doit) return ("heal (777), curing and heroism every 300 turns");
+ msg_print("A heavenly choir sings...");
+ (void)set_poisoned(0);
+ (void)set_cut(0);
+ (void)set_stun(0);
+ (void)set_confused(0);
+ (void)set_blind(0);
+ (void)set_hero(p_ptr->hero + randint(25) + 25);
+ (void)hp_player(777);
+
+ o_ptr->timeout = 300;
+
+ break;
+ }
+
+ case ACT_GORLIM:
+ {
+ if (!doit) return "rays of fear in every direction";
+ turn_monsters(40 + p_ptr->lev);
+
+ o_ptr->timeout = 3 * (p_ptr->lev + 10);
+
+ break;
+ }
+
+ case ACT_COLLUIN:
+ {
+ if (!doit) return "resistance (20+d20 turns) every 111 turns";
+ msg_print("Your cloak glows many colours...");
+ (void)set_oppose_acid(p_ptr->oppose_acid + randint(20) + 20);
+ (void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20);
+ (void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20);
+ (void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20);
+ (void)set_oppose_pois(p_ptr->oppose_pois + randint(20) + 20);
+
+ o_ptr->timeout = 111;
+
+ break;
+ }
+
+
+ case ACT_BELANGIL:
+ {
+ if (!doit) return "frost ball (48) every 5+d5 turns";
+ msg_print("Your dagger is covered in frost...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_COLD, dir, 48, 2);
+
+ o_ptr->timeout = rand_int(5) + 5;
+
+ break;
+ }
+
+ case ACT_ANGUIREL:
+ {
+ if (!doit) return "a getaway every 35 turns";
+ switch (randint(13))
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ {
+ teleport_player(10);
+
+ break;
+ }
+
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ {
+ teleport_player(222);
+
+ break;
+ }
+
+ case 11:
+ case 12:
+ {
+ (void)stair_creation();
+
+ break;
+ }
+
+ default:
+ {
+ if (get_check("Leave this level? "))
+ {
+ autosave_checkpoint();
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ }
+
+ break;
+ }
+ }
+
+ o_ptr->timeout = 35;
+
+ break;
+ }
+
+ case ACT_ERU:
+ {
+ if (!doit) return "healing(7000), curing every 500 turns";
+ msg_print("Your sword glows an intense white...");
+ hp_player(7000);
+ heal_insanity(50);
+ set_blind(0);
+ set_poisoned(0);
+ set_confused(0);
+ set_stun(0);
+ set_cut(0);
+ set_image(0);
+
+ o_ptr->timeout = 500;
+
+ break;
+ }
+
+ case ACT_DAWN:
+ {
+ if (!doit) return "summon the Legion of the Dawn every 500+d500 turns";
+ msg_print("You summon the Legion of the Dawn.");
+ (void)summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_DAWN, TRUE);
+
+ o_ptr->timeout = 500 + randint(500);
+
+ break;
+ }
+
+ case ACT_FIRESTAR:
+ {
+ if (!doit) return "large fire ball (72) every 100 turns";
+ msg_print("Your morning star rages in fire...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_FIRE, dir, 72, 3);
+
+ o_ptr->timeout = 100;
+
+ break;
+ }
+
+ case ACT_TURMIL:
+ {
+ if (!doit) return "drain life (90) every 70 turns";
+ msg_print("Your hammer glows white...");
+ if (!get_aim_dir(&dir)) break;
+ drain_life(dir, 90);
+
+ o_ptr->timeout = 70;
+
+ break;
+ }
+
+ case ACT_CUBRAGOL:
+ {
+ if (!doit) return "fire branding of bolts every 999 turns";
+ msg_print("Your crossbow glows deep red...");
+ (void)brand_bolts();
+
+ o_ptr->timeout = 999;
+
+ break;
+ }
+
+ case ACT_ELESSAR:
+ {
+ if (!doit) return "heal and cure black breath every 200 turns";
+ if (p_ptr->black_breath)
+ {
+ msg_print("The hold of the Black Breath on you is broken!");
+ }
+ p_ptr->black_breath = FALSE;
+ hp_player(100);
+
+ o_ptr->timeout = 200;
+
+ break;
+ }
+
+ case ACT_GANDALF:
+ {
+ if (!doit) return "restore mana every 666 turns";
+ msg_print("Your mage staff glows deep blue...");
+ if (p_ptr->csp < p_ptr->msp)
+ {
+ p_ptr->csp = p_ptr->msp;
+ p_ptr->csp_frac = 0;
+ msg_print("Your feel your head clear.");
+ p_ptr->redraw |= (PR_MANA);
+ p_ptr->window |= (PW_PLAYER);
+ }
+
+ o_ptr->timeout = 666;
+
+ break;
+ }
+
+ case ACT_MARDA:
+ {
+ if (!doit) return "summon a thunderlord every 1000 turns";
+ if (randint(3) == 1)
+ {
+ if (summon_specific(p_ptr->py, p_ptr->px, ((plev * 3) / 2), SUMMON_THUNDERLORD))
+ {
+ msg_print("A Thunderlord comes from thin air!");
+ msg_print("'I will burn you!'");
+ }
+ }
+ else
+ {
+ if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2),
+ SUMMON_THUNDERLORD, (bool_)(plev == 50 ? TRUE : FALSE)))
+ {
+ msg_print("A Thunderlord comes from thin air!");
+ msg_print("'I will help you in your difficult task.'");
+ }
+ }
+
+ o_ptr->timeout = 1000;
+
+ break;
+ }
+
+ case ACT_PALANTIR:
+ {
+ if (!doit) return "clairvoyance every 100+d100 turns";
+ msg_print("The stone glows a deep green...");
+ wiz_lite_extra();
+ (void)detect_traps(DEFAULT_RADIUS);
+ (void)detect_doors(DEFAULT_RADIUS);
+ (void)detect_stairs(DEFAULT_RADIUS);
+
+ o_ptr->timeout = rand_int(100) + 100;
+
+ break;
+ }
+
+ case ACT_EREBOR:
+ {
+ if (!doit) return "open a secret passage every 75 turns";
+ msg_print("Your pick twists in your hands.");
+
+ if (!get_aim_dir(&dir)) break;
+ if (passwall(dir, TRUE))
+ {
+ msg_print("A passage opens, and you step through.");
+ }
+ else
+ {
+ msg_print("There is no wall there!");
+ }
+
+ o_ptr->timeout = 75;
+
+ break;
+ }
+
+ case ACT_DRUEDAIN:
+ {
+ if (!doit) return "detection every 99 turns";
+ msg_print("Your drum shows you the world.");
+ detect_all(DEFAULT_RADIUS);
+
+ o_ptr->timeout = 99;
+
+ break;
+ }
+
+ case ACT_ROHAN:
+ {
+ if (!doit) return "heroism, berserker, and haste every 250 turns";
+ msg_print("Your horn glows deep red.");
+ set_afraid(0);
+ set_shero(p_ptr->shero + damroll(5, 10) + 30);
+ set_afraid(0);
+ set_hero(p_ptr->hero + damroll(5, 10) + 30);
+ set_fast(p_ptr->fast + damroll(5, 10) + 30, 10);
+ hp_player(30);
+
+ o_ptr->timeout = 250;
+
+ break;
+ }
+
+ case ACT_HELM:
+ {
+ if (!doit) return "sound ball (300) every 300 turns";
+ msg_print("Your horn emits a loud sound.");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_SOUND, dir, 300, 6);
+
+ o_ptr->timeout = 300;
+
+ break;
+ }
+
+ case ACT_BOROMIR:
+ {
+ if (!doit) return "mass human summoning every 1000 turns";
+ msg_print("Your horn calls for help.");
+ for (i = 0; i < 15; i++)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2), SUMMON_HUMAN, TRUE);
+ }
+
+ o_ptr->timeout = 1000;
+
+ break;
+ }
+
+ case ACT_HURIN:
+ {
+ if (!doit) return "berserker and +10 to speed (50) every 100+d200 turns";
+ if (!p_ptr->fast)
+ {
+ (void)set_fast(randint(50) + 50, 10);
+ }
+ else
+ {
+ (void)set_fast(p_ptr->fast + 5, 10);
+ }
+ hp_player(30);
+ set_afraid(0);
+ set_shero(p_ptr->shero + randint(50) + 50);
+
+ o_ptr->timeout = rand_int(200) + 100;
+
+ break;
+ }
+
+ case ACT_AXE_GOTHMOG:
+ {
+ if (!doit) return "fire ball (300) every 200+d200 turns";
+ msg_print("Your lochaber axe erupts in fire...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_FIRE, dir, 300, 4);
+
+ o_ptr->timeout = 200 + rand_int(200);
+
+ break;
+ }
+
+ case ACT_MELKOR:
+ {
+ if (!doit) return "darkness ball (150) every 100 turns";
+ msg_print("Your spear is covered of darkness...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_DARK, dir, 150, 3);
+
+ o_ptr->timeout = 100;
+
+ break;
+ }
+
+ case ACT_GROND:
+ {
+ if (!doit) return "alter reality every 100 turns";
+ msg_print("Your hammer hits the floor...");
+ alter_reality();
+
+ o_ptr->timeout = 100;
+
+ break;
+ }
+
+ case ACT_NATUREBANE:
+ {
+ if (!doit) return "dispel monsters (300) every 200+d200 turns";
+ msg_print("Your axe glows blood red...");
+ dispel_monsters(300);
+
+ o_ptr->timeout = 200 + randint(200);
+
+ break;
+ }
+
+ case ACT_NIGHT:
+ {
+ if (!doit) return "vampiric drain (3*100) every 250 turns";
+ msg_print("Your axe emits a black aura...");
+ if (!get_aim_dir(&dir)) break;
+ for (i = 0; i < 3; i++)
+ {
+ if (drain_life(dir, 100)) hp_player(100);
+ }
+
+ o_ptr->timeout = 250;
+
+ break;
+ }
+
+ case ACT_ORCHAST:
+ {
+ if (!doit) return "detect orcs every 10 turns";
+ msg_print("Your weapon glows brightly...");
+ (void)detect_monsters_xxx(RF3_ORC, DEFAULT_RADIUS);
+
+ o_ptr->timeout = 10;
+
+ break;
+ }
+ case ACT_SUNLIGHT:
+ {
+ if (!doit) return "beam of sunlight every 10 turns";
+
+ if (!get_aim_dir(&dir)) break;
+ msg_print("A line of sunlight appears.");
+ lite_line(dir);
+
+ o_ptr->timeout = 10;
+
+ break;
+ }
+
+ case ACT_BO_MISS_1:
+ {
+ if (!doit) return "magic missile (2d6) every 2 turns";
+ msg_print("It glows extremely brightly...");
+ if (!get_aim_dir(&dir)) break;
+ fire_bolt(GF_MISSILE, dir, damroll(2, 6));
+
+ o_ptr->timeout = 2;
+
+ break;
+ }
+
+ case ACT_BA_POIS_1:
+ {
+ if (!doit) return "stinking cloud (12), rad. 3, every 4+d4 turns";
+ msg_print("It throbs deep green...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_POIS, dir, 12, 3);
+
+ o_ptr->timeout = rand_int(4) + 4;
+
+ break;
+ }
+
+ case ACT_BO_ELEC_1:
+ {
+ if (!doit) return "lightning bolt (4d8) every 6+d6 turns";
+ msg_print("It is covered in sparks...");
+ if (!get_aim_dir(&dir)) break;
+ fire_bolt(GF_ELEC, dir, damroll(4, 8));
+
+ o_ptr->timeout = rand_int(6) + 6;
+
+ break;
+ }
+
+ case ACT_BO_ACID_1:
+ {
+ if (!doit) return "acid bolt (5d8) every 5+d5 turns";
+ msg_print("It is covered in acid...");
+ if (!get_aim_dir(&dir)) break;
+ fire_bolt(GF_ACID, dir, damroll(5, 8));
+
+ o_ptr->timeout = rand_int(5) + 5;
+
+ break;
+ }
+
+ case ACT_BO_COLD_1:
+ {
+ if (!doit) return "frost bolt (6d8) every 7+d7 turns";
+ msg_print("It is covered in frost...");
+ if (!get_aim_dir(&dir)) break;
+ fire_bolt(GF_COLD, dir, damroll(6, 8));
+
+ o_ptr->timeout = rand_int(7) + 7;
+
+ break;
+ }
+
+ case ACT_BO_FIRE_1:
+ {
+ if (!doit) return "fire bolt (9d8) every 8+d8 turns";
+ msg_print("It is covered in fire...");
+ if (!get_aim_dir(&dir)) break;
+ fire_bolt(GF_FIRE, dir, damroll(9, 8));
+
+ o_ptr->timeout = rand_int(8) + 8;
+
+ break;
+ }
+
+ case ACT_BA_COLD_1:
+ {
+ if (!doit) return "ball of cold (48) every 400 turns";
+ msg_print("It is covered in frost...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_COLD, dir, 48, 2);
+
+ o_ptr->timeout = 400;
+
+ break;
+ }
+
+ case ACT_BA_FIRE_1:
+ {
+ if (!doit) return "ball of fire (72) every 400 turns";
+ msg_print("It glows an intense red...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_FIRE, dir, 72, 2);
+
+ o_ptr->timeout = 400;
+
+ break;
+ }
+
+ case ACT_DRAIN_1:
+ {
+ if (!doit) return "drain life (100) every 100+d100 turns";
+ msg_print("It glows black...");
+ if (!get_aim_dir(&dir)) break;
+ if (drain_life(dir, 100))
+
+ o_ptr->timeout = rand_int(100) + 100;
+
+ break;
+ }
+
+ case ACT_BA_COLD_2:
+ {
+ if (!doit) return "ball of cold (100) every 300 turns";
+ msg_print("It glows an intense blue...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_COLD, dir, 100, 2);
+
+ o_ptr->timeout = 300;
+
+ break;
+ }
+
+ case ACT_BA_ELEC_2:
+ {
+ if (!doit) return "ball of lightning (100) every 500 turns";
+ msg_print("It crackles with electricity...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_ELEC, dir, 100, 3);
+
+ o_ptr->timeout = 500;
+
+ break;
+ }
+
+ case ACT_DRAIN_2:
+ {
+ if (!doit) return "drain life (120) every 400 turns";
+ msg_print("It glows black...");
+ if (!get_aim_dir(&dir)) break;
+ drain_life(dir, 120);
+
+ o_ptr->timeout = 400;
+
+ break;
+ }
+
+ case ACT_VAMPIRE_1:
+ {
+ if (!doit) return "vampiric drain (3*50) every 400 turns";
+ if (!get_aim_dir(&dir)) break;
+ for (dummy = 0; dummy < 3; dummy++)
+ {
+ if (drain_life(dir, 50))
+ hp_player(50);
+ }
+
+ o_ptr->timeout = 400;
+
+ break;
+ }
+
+ case ACT_BO_MISS_2:
+ {
+ if (!doit) return "arrows (150) every 90+d90 turns";
+ msg_print("It grows magical spikes...");
+ if (!get_aim_dir(&dir)) break;
+ fire_bolt(GF_ARROW, dir, 150);
+
+ o_ptr->timeout = rand_int(90) + 90;
+
+ break;
+ }
+
+ case ACT_BA_FIRE_2:
+ {
+ if (!doit) return "fire ball (120) every 225+d225 turns";
+ msg_print("It glows deep red...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_FIRE, dir, 120, 3);
+
+ o_ptr->timeout = rand_int(225) + 225;
+
+ break;
+ }
+
+ case ACT_BA_COLD_3:
+ {
+ if (!doit) return "ball of cold (200) every 325+d325 turns";
+ msg_print("It glows bright white...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_COLD, dir, 200, 3);
+
+ o_ptr->timeout = rand_int(325) + 325;
+
+ break;
+ }
+
+ case ACT_BA_ELEC_3:
+ {
+ if (!doit) return "Lightning Ball (250) every 425+d425 turns";
+ msg_print("It glows deep blue...");
+ if (!get_aim_dir(&dir)) break;
+ fire_ball(GF_ELEC, dir, 250, 3);
+
+ o_ptr->timeout = rand_int(425) + 425;
+
+ break;
+ }
+
+ case ACT_WHIRLWIND:
+ {
+ int y = 0, x = 0;
+ cave_type *c_ptr;
+ monster_type *m_ptr;
+ if (!doit) return "whirlwind attack every 250 turns";
+
+ for (dir = 0; dir <= 9; dir++)
+ {
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+
+ /* Get the monster */
+ m_ptr = &m_list[c_ptr->m_idx];
+
+ /* Hack -- attack monsters */
+ if (c_ptr->m_idx && (m_ptr->ml || cave_floor_bold(y, x)))
+ {
+ py_attack(y, x, -1);
+ }
+ }
+
+ o_ptr->timeout = 250;
+
+ break;
+ }
+
+ case ACT_VAMPIRE_2:
+ {
+ if (!doit) return "vampiric drain (3*100) every 400 turns";
+ if (!get_aim_dir(&dir)) break;
+ for (dummy = 0; dummy < 3; dummy++)
+ {
+ if (drain_life(dir, 100))
+ hp_player(100);
+ }
+
+ o_ptr->timeout = 400;
+
+ break;
+ }
+
+
+ case ACT_CALL_CHAOS:
+ {
+ if (!doit) return "call chaos every 350 turns";
+ msg_print("It glows in scintillating colours...");
+ call_chaos();
+
+ o_ptr->timeout = 350;
+
+ break;
+ }
+
+ case ACT_ROCKET:
+ {
+ if (!doit) return "launch rocket (120+level) every 400 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You launch a rocket!");
+ fire_ball(GF_ROCKET, dir, 120 + (plev), 2);
+
+ o_ptr->timeout = 400;
+
+ break;
+ }
+
+ case ACT_DISP_EVIL:
+ {
+ if (!doit) return "dispel evil (level*5) every 300+d300 turns";
+ msg_print("It floods the area with goodness...");
+ dispel_evil(p_ptr->lev * 5);
+
+ o_ptr->timeout = rand_int(300) + 300;
+
+ break;
+ }
+
+ case ACT_DISP_GOOD:
+ {
+ if (!doit) return "dispel good (level*5) every 300+d300 turns";
+ msg_print("It floods the area with evil...");
+ dispel_good(p_ptr->lev * 5);
+
+ o_ptr->timeout = rand_int(300) + 300;
+
+ break;
+ }
+
+ case ACT_BA_MISS_3:
+ {
+ if (!doit) return "elemental breath (300) every 500 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe the elements.");
+ fire_ball(GF_MISSILE, dir, 300, 4);
+
+ o_ptr->timeout = 500;
+
+ break;
+ }
+
+ /* Activate for other offensive action */
+
+ case ACT_CONFUSE:
+ {
+ if (!doit) return "confuse monster every 15 turns";
+ msg_print("It glows in scintillating colours...");
+ if (!get_aim_dir(&dir)) break;
+ confuse_monster(dir, 20);
+
+ o_ptr->timeout = 15;
+
+ break;
+ }
+
+ case ACT_SLEEP:
+ {
+ if (!doit) return "sleep nearby monsters every 55 turns";
+ msg_print("It glows deep blue...");
+ sleep_monsters_touch();
+
+ o_ptr->timeout = 55;
+
+ break;
+ }
+
+ case ACT_QUAKE:
+ {
+ if (!doit) return "earthquake (rad 10) every 50 turns";
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ {
+ earthquake(p_ptr->py, p_ptr->px, 10);
+ o_ptr->timeout = 50;
+ }
+
+ break;
+ }
+
+ case ACT_TERROR:
+ {
+ if (!doit) return "terror every 3 * (level+10) turns";
+ turn_monsters(40 + p_ptr->lev);
+
+ o_ptr->timeout = 3 * (p_ptr->lev + 10);
+
+ break;
+ }
+
+ case ACT_TELE_AWAY:
+ {
+ if (!doit) return "teleport away every 200 turns";
+ if (!get_aim_dir(&dir)) break;
+ (void)fire_beam(GF_AWAY_ALL, dir, plev);
+
+ o_ptr->timeout = 200;
+
+ break;
+ }
+
+ case ACT_BANISH_EVIL:
+ {
+ if (!doit) return "banish evil every 250+d250 turns";
+ if (banish_evil(100))
+ {
+ msg_print("The power of the artifact banishes evil!");
+ }
+
+ o_ptr->timeout = 250 + randint(250);
+
+ break;
+ }
+
+ case ACT_GENOCIDE:
+ {
+ if (!doit) return "genocide every 500 turns";
+ msg_print("It glows deep blue...");
+ (void)genocide(TRUE);
+
+ o_ptr->timeout = 500;
+
+ break;
+ }
+
+ case ACT_MASS_GENO:
+ {
+ if (!doit) return "mass genocide every 1000 turns";
+ msg_print("It lets out a long, shrill note...");
+ (void)mass_genocide(TRUE);
+
+ o_ptr->timeout = 1000;
+
+ break;
+ }
+
+ /* Activate for summoning / charming */
+
+ case ACT_CHARM_ANIMAL:
+ {
+ if (!doit) return "charm animal every 300 turns";
+ if (!get_aim_dir(&dir)) break;
+ (void) charm_animal(dir, plev);
+
+ o_ptr->timeout = 300;
+
+ break;
+ }
+
+ case ACT_CHARM_UNDEAD:
+ {
+ if (!doit) return "enslave undead every 333 turns";
+ if (!get_aim_dir(&dir)) break;
+ (void)control_one_undead(dir, plev);
+
+ o_ptr->timeout = 333;
+
+ break;
+ }
+
+ case ACT_CHARM_OTHER:
+ {
+ if (!doit) return "charm monster every 400 turns";
+ if (!get_aim_dir(&dir)) break;
+ (void) charm_monster(dir, plev);
+
+ o_ptr->timeout = 400;
+
+ break;
+ }
+
+ case ACT_CHARM_ANIMALS:
+ {
+ if (!doit) return "animal friendship every 500 turns";
+ (void) charm_animals(plev * 2);
+
+ o_ptr->timeout = 500;
+
+ break;
+ }
+
+ case ACT_CHARM_OTHERS:
+ {
+ if (!doit) return "mass charm every 750 turns";
+ charm_monsters(plev * 2);
+
+ o_ptr->timeout = 750;
+
+ break;
+ }
+
+ case ACT_SUMMON_ANIMAL:
+ {
+ if (!doit) return "summon animal every 200+d300 turns";
+ (void)summon_specific_friendly(p_ptr->py, p_ptr->px, plev, SUMMON_ANIMAL_RANGER, TRUE);
+
+ o_ptr->timeout = 200 + randint(300);
+
+ break;
+ }
+
+ case ACT_SUMMON_PHANTOM:
+ {
+ if (!doit) return "summon phantasmal servant every 200+d200 turns";
+ msg_print("You summon a phantasmal servant.");
+ (void)summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_PHANTOM, TRUE);
+
+ o_ptr->timeout = 200 + randint(200);
+
+ break;
+ }
+
+ case ACT_SUMMON_ELEMENTAL:
+ {
+ if (!doit) return "summon elemental every 750 turns";
+ if (randint(3) == 1)
+ {
+ if (summon_specific(p_ptr->py, p_ptr->px, ((plev * 3) / 2), SUMMON_ELEMENTAL))
+ {
+ msg_print("An elemental materialises...");
+ msg_print("You fail to control it!");
+ }
+ }
+ else
+ {
+ if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2),
+ SUMMON_ELEMENTAL, (bool_)(plev == 50 ? TRUE : FALSE)))
+ {
+ msg_print("An elemental materialises...");
+ msg_print("It seems obedient to you.");
+ }
+ }
+
+ o_ptr->timeout = 750;
+
+ break;
+ }
+
+ case ACT_SUMMON_DEMON:
+ {
+ if (!doit) return "summon demon every 666+d333 turns";
+ if (randint(3) == 1)
+ {
+ if (summon_specific(p_ptr->py, p_ptr->px, ((plev * 3) / 2), SUMMON_DEMON))
+ {
+ msg_print("The area fills with a stench of sulphur and brimstone.");
+ msg_print("'NON SERVIAM! Wretch! I shall feast on thy mortal soul!'");
+ }
+ }
+ else
+ {
+ if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2),
+ SUMMON_DEMON, (bool_)(plev == 50 ? TRUE : FALSE)))
+ {
+ msg_print("The area fills with a stench of sulphur and brimstone.");
+ msg_print("'What is thy bidding... Master?'");
+ }
+ }
+
+ o_ptr->timeout = 666 + randint(333);
+
+ break;
+ }
+
+ case ACT_SUMMON_UNDEAD:
+ {
+ if (!doit) return "summon undead every 666+d333 turns";
+ if (randint(3) == 1)
+ {
+ if (summon_specific(p_ptr->py, p_ptr->px, ((plev * 3) / 2),
+ (plev > 47 ? SUMMON_HI_UNDEAD : SUMMON_UNDEAD)))
+ {
+ msg_print("Cold winds begin to blow around you, carrying with them the stench of decay...");
+ msg_print("'The dead arise... to punish you for disturbing them!'");
+ }
+ }
+ else
+ {
+ if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2),
+ (plev > 47 ? SUMMON_HI_UNDEAD_NO_UNIQUES : SUMMON_UNDEAD),
+ (bool_)(((plev > 24) && (randint(3) == 1)) ? TRUE : FALSE)))
+ {
+ msg_print("Cold winds begin to blow around you, carrying with them the stench of decay...");
+ msg_print("Ancient, long-dead forms arise from the ground to serve you!");
+ }
+ }
+
+ o_ptr->timeout = 666 + randint(333);
+
+ break;
+ }
+
+ /* Activate for healing */
+
+ case ACT_CURE_LW:
+ {
+ if (!doit) return format("cure light wounds every %d turns", (is_junkart ? 50 : 10));
+ (void)set_afraid(0);
+ (void)hp_player(30);
+
+ o_ptr->timeout = 10;
+
+ break;
+ }
+
+ case ACT_CURE_MW:
+ {
+ if (!doit) return format("cure serious wounds every %s turns", (is_junkart? "75" : "3+d3"));
+ msg_print("It radiates deep purple...");
+ hp_player(damroll(4, 8));
+ (void)set_cut((p_ptr->cut / 2) - 50);
+
+ o_ptr->timeout = rand_int(3) + 3;
+
+ break;
+ }
+
+ case ACT_CURE_POISON:
+ {
+ if (!doit) return "remove fear and cure poison every 5 turns";
+ msg_print("It glows deep blue...");
+ (void)set_afraid(0);
+ (void)set_poisoned(0);
+
+ o_ptr->timeout = 5;
+
+ break;
+ }
+
+ case ACT_REST_LIFE:
+ {
+ if (!doit) return "restore life levels every 450 turns";
+ msg_print("It glows a deep red...");
+ restore_level();
+
+ o_ptr->timeout = 450;
+
+ break;
+ }
+
+ case ACT_REST_ALL:
+ {
+ if (!doit) return format("restore stats and life levels every %d turns", (is_junkart ? 200 : 750));
+ msg_print("It glows a deep green...");
+ (void)do_res_stat(A_STR, TRUE);
+ (void)do_res_stat(A_INT, TRUE);
+ (void)do_res_stat(A_WIS, TRUE);
+ (void)do_res_stat(A_DEX, TRUE);
+ (void)do_res_stat(A_CON, TRUE);
+ (void)do_res_stat(A_CHR, TRUE);
+ (void)restore_level();
+
+ o_ptr->timeout = 750;
+
+ break;
+ }
+
+ case ACT_CURE_700:
+ {
+ if (!doit) return format("heal 700 hit points every %d turns", (is_junkart ? 100 : 250));
+ msg_print("It glows deep blue...");
+ msg_print("You feel a warm tingling inside...");
+ (void)hp_player(700);
+ (void)set_cut(0);
+
+ o_ptr->timeout = 250;
+
+ break;
+ }
+
+ case ACT_CURE_1000:
+ {
+ if (!doit) return "heal 1000 hit points every 888 turns";
+ msg_print("It glows a bright white...");
+ msg_print("You feel much better...");
+ (void)hp_player(1000);
+ (void)set_cut(0);
+
+ o_ptr->timeout = 888;
+
+ break;
+ }
+
+ case ACT_ESP:
+ {
+ if (!doit) return "temporary ESP (dur 25+d30) every 200 turns";
+ (void)set_tim_esp(p_ptr->tim_esp + randint(30) + 25);
+
+ o_ptr->timeout = 200;
+
+ break;
+ }
+
+ case ACT_BERSERK:
+ {
+ if (!doit) return "heroism and berserk (dur 50+d50) every 100+d100 turns";
+ (void)set_shero(p_ptr->shero + randint(50) + 50);
+ (void)set_blessed(p_ptr->blessed + randint(50) + 50);
+
+ o_ptr->timeout = 100 + randint(100);
+
+ break;
+ }
+
+ case ACT_PROT_EVIL:
+ {
+ if (!doit) return "protection from evil (dur level*3 + d25) every 225+d225 turns";
+ msg_print("It lets out a shrill wail...");
+ k = 3 * p_ptr->lev;
+ (void)set_protevil(p_ptr->protevil + randint(25) + k);
+
+ o_ptr->timeout = rand_int(225) + 225;
+
+ break;
+ }
+
+ case ACT_RESIST_ALL:
+ {
+ if (!doit) return "resist elements (dur 40+d40) every 200 turns";
+ msg_print("It glows many colours...");
+ (void)set_oppose_acid(p_ptr->oppose_acid + randint(40) + 40);
+ (void)set_oppose_elec(p_ptr->oppose_elec + randint(40) + 40);
+ (void)set_oppose_fire(p_ptr->oppose_fire + randint(40) + 40);
+ (void)set_oppose_cold(p_ptr->oppose_cold + randint(40) + 40);
+ (void)set_oppose_pois(p_ptr->oppose_pois + randint(40) + 40);
+
+ o_ptr->timeout = 200;
+
+ break;
+ }
+
+ case ACT_SPEED:
+ {
+ if (!doit) return "speed (dur 20+d20) every 250 turns";
+ msg_print("It glows bright green...");
+ if (!p_ptr->fast)
+ {
+ (void)set_fast(randint(20) + 20, 10);
+ }
+ else
+ {
+ (void)set_fast(p_ptr->fast + 5, 10);
+ }
+
+ o_ptr->timeout = 250;
+
+ break;
+ }
+
+ case ACT_XTRA_SPEED:
+ {
+ if (!doit) return "speed (dur 75+d75) every 200+d200 turns";
+ msg_print("It glows brightly...");
+ if (!p_ptr->fast)
+ {
+ (void)set_fast(randint(75) + 75, 10);
+ }
+ else
+ {
+ (void)set_fast(p_ptr->fast + 5, 10);
+ }
+
+ o_ptr->timeout = rand_int(200) + 200;
+
+ break;
+ }
+
+ case ACT_WRAITH:
+ {
+ if (!doit) return "wraith form (level/2 + d(level/2)) every 1000 turns";
+ set_shadow(p_ptr->tim_wraith + randint(plev / 2) + (plev / 2));
+
+ o_ptr->timeout = 1000;
+
+ break;
+ }
+
+ case ACT_INVULN:
+ {
+ if (!doit) return "invulnerability (dur 8+d8) every 1000 turns";
+ (void)set_invuln(p_ptr->invuln + randint(8) + 8);
+
+ o_ptr->timeout = 1000;
+
+ break;
+ }
+
+ /* Activate for general purpose effect (detection etc.) */
+
+ case ACT_LIGHT:
+ {
+ if (!doit) return format("light area (dam 2d15) every %s turns", (is_junkart ? "100" : "10+d10"));
+ msg_print("It wells with clear light...");
+ lite_area(damroll(2, 15), 3);
+
+ o_ptr->timeout = rand_int(10) + 10;
+
+ break;
+ }
+
+ case ACT_MAP_LIGHT:
+ {
+ if (!doit) return "light (dam 2d15) & map area every 50+d50 turns";
+ msg_print("It shines brightly...");
+ map_area();
+ lite_area(damroll(2, 15), 3);
+
+ o_ptr->timeout = rand_int(50) + 50;
+
+ break;
+ }
+
+ case ACT_DETECT_ALL:
+ {
+ if (!doit) return "detection every 55+d55 turns";
+ msg_print("It glows bright white...");
+ msg_print("An image forms in your mind...");
+ detect_all(DEFAULT_RADIUS);
+
+ o_ptr->timeout = rand_int(55) + 55;
+
+ break;
+ }
+
+ case ACT_DETECT_XTRA:
+ {
+ if (!doit) return "detection, probing and identify true every 1000 turns";
+ msg_print("It glows brightly...");
+ detect_all(DEFAULT_RADIUS);
+ probing();
+ identify_fully();
+
+ o_ptr->timeout = 1000;
+
+ break;
+ }
+
+ case ACT_ID_FULL:
+ {
+ if (!doit) return "identify true every 750 turns";
+ msg_print("It glows yellow...");
+ identify_fully();
+
+ o_ptr->timeout = 750;
+
+ break;
+ }
+
+ case ACT_ID_PLAIN:
+ {
+ if (!doit) return "identify spell every 10 turns";
+ if (!ident_spell()) break;
+
+ o_ptr->timeout = 10;
+
+ break;
+ }
+
+ case ACT_RUNE_EXPLO:
+ {
+ if (!doit) return "explosive rune every 200 turns";
+ msg_print("It glows bright red...");
+ explosive_rune();
+
+ o_ptr->timeout = 200;
+
+ break;
+ }
+
+ case ACT_RUNE_PROT:
+ {
+ if (!doit) return "rune of protection every 400 turns";
+ msg_print("It glows light blue...");
+ warding_glyph();
+
+ o_ptr->timeout = 400;
+
+ break;
+ }
+
+ case ACT_SATIATE:
+ {
+ if (!doit) return "satisfy hunger every 200 turns";
+ (void)set_food(PY_FOOD_MAX - 1);
+
+ o_ptr->timeout = 200;
+
+ break;
+ }
+
+ case ACT_DEST_DOOR:
+ {
+ if (!doit) return "destroy doors and traps every 10 turns";
+ msg_print("It glows bright red...");
+ destroy_doors_touch();
+
+ o_ptr->timeout = 10;
+
+ break;
+ }
+
+ case ACT_STONE_MUD:
+ {
+ if (!doit) return "stone to mud every 5 turns";
+ msg_print("It pulsates...");
+ if (!get_aim_dir(&dir)) break;
+ wall_to_mud(dir);
+
+ o_ptr->timeout = 5;
+
+ break;
+ }
+
+ case ACT_RECHARGE:
+ {
+ if (!doit) return "recharging every 70 turns";
+ recharge(60);
+
+ o_ptr->timeout = 70;
+
+ break;
+ }
+
+ case ACT_ALCHEMY:
+ {
+ if (!doit) return "alchemy every 500 turns";
+ msg_print("It glows bright yellow...");
+ (void) alchemy();
+
+ o_ptr->timeout = 500;
+
+ break;
+ }
+
+ case ACT_DIM_DOOR:
+ {
+ if (!doit) return "dimension door every 100 turns";
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("Not on special levels!");
+ break;
+ }
+
+ msg_print("You open a Void Jumpgate. Choose a destination.");
+ if (!tgt_pt(&ii, &ij)) break;
+
+ p_ptr->energy -= 60 - plev;
+
+ if (!cave_empty_bold(ij, ii) || (cave[ij][ii].info & CAVE_ICKY) ||
+ (distance(ij, ii, p_ptr->py, p_ptr->px) > plev + 2) ||
+ (!rand_int(plev * plev / 2)))
+ {
+ msg_print("You fail to exit the void correctly!");
+ p_ptr->energy -= 100;
+ get_pos_player(10, &ij, &ii);
+ }
+
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_BETWEEN);
+ cave_set_feat(ij, ii, FEAT_BETWEEN);
+ cave[p_ptr->py][p_ptr->px].special = ii + (ij << 8);
+ cave[ij][ii].special = p_ptr->px + (p_ptr->py << 8);
+
+ o_ptr->timeout = 100;
+
+ break;
+ }
+
+ case ACT_TELEPORT:
+ {
+ if (!doit) return format("teleport (range 100) every %d turns", (is_junkart? 100 : 45));
+ msg_print("It twists space around you...");
+ teleport_player(100);
+
+ o_ptr->timeout = 45;
+
+ break;
+ }
+
+ case ACT_RECALL:
+ {
+ if (!(dungeon_flags2 & DF2_ASK_LEAVE) || ((dungeon_flags2 & DF2_ASK_LEAVE) && !get_check("Leave this unique level forever? ")))
+ {
+ if (!doit) return "word of recall every 200 turns";
+ msg_print("It glows soft white...");
+ recall_player(20,15);
+
+ o_ptr->timeout = 200;
+ }
+
+ break;
+ }
+
+ case ACT_DEATH:
+ {
+ if (!doit) return "death";
+ take_hit(5000, "activating a death spell");
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_RUINATION:
+ {
+ if (!doit) return "Ruination";
+ msg_print("Your nerves and muscles feel weak and lifeless!");
+
+ take_hit(damroll(10, 10), "activating Ruination");
+ (void)dec_stat(A_DEX, 25, TRUE);
+ (void)dec_stat(A_WIS, 25, TRUE);
+ (void)dec_stat(A_CON, 25, TRUE);
+ (void)dec_stat(A_STR, 25, TRUE);
+ (void)dec_stat(A_CHR, 25, TRUE);
+ (void)dec_stat(A_INT, 25, TRUE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_DESTRUC:
+ {
+ if (!doit) return "Destruction every 100 turns";
+ earthquake(p_ptr->py, p_ptr->px, 12);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_UNINT:
+ {
+ if (!doit) return "decreasing Intelligence";
+ (void)dec_stat(A_INT, 25, FALSE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_UNSTR:
+ {
+ if (!doit) return "decreasing Strength";
+ (void)dec_stat(A_STR, 25, FALSE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_UNCON:
+ {
+ if (!doit) return "decreasing Constitution";
+ (void)dec_stat(A_CON, 25, FALSE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_UNCHR:
+ {
+ if (!doit) return "decreasing Charisma";
+ (void)dec_stat(A_CHR, 25, FALSE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_UNDEX:
+ {
+ if (!doit) return "decreasing Dexterity";
+ (void)dec_stat(A_DEX, 25, FALSE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_UNWIS:
+ {
+ if (!doit) return "decreasing Wisdom";
+ (void)dec_stat(A_WIS, 25, FALSE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_STATLOSS:
+ {
+ if (!doit) return "stat loss";
+ (void)dec_stat(A_STR, 15, FALSE);
+ (void)dec_stat(A_INT, 15, FALSE);
+ (void)dec_stat(A_WIS, 15, FALSE);
+ (void)dec_stat(A_DEX, 15, FALSE);
+ (void)dec_stat(A_CON, 15, FALSE);
+ (void)dec_stat(A_CHR, 15, FALSE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_HISTATLOSS:
+ {
+ if (!doit) return "high stat loss";
+ (void)dec_stat(A_STR, 25, FALSE);
+ (void)dec_stat(A_INT, 25, FALSE);
+ (void)dec_stat(A_WIS, 25, FALSE);
+ (void)dec_stat(A_DEX, 25, FALSE);
+ (void)dec_stat(A_CON, 25, FALSE);
+ (void)dec_stat(A_CHR, 25, FALSE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_EXPLOSS:
+ {
+ if (!doit) return "experience loss";
+ lose_exp(p_ptr->exp / 20);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_HIEXPLOSS:
+ {
+ if (!doit) return "high experience loss";
+ lose_exp(p_ptr->exp / 10);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_SUMMON_MONST:
+ {
+ if (!doit) return "summon monster";
+ summon_specific(p_ptr->py, p_ptr->px, max_dlv[dungeon_type], 0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_PARALYZE:
+ {
+ if (!doit) return "paralyze";
+ set_paralyzed(p_ptr->paralyzed + 20 + randint(10));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_HALLU:
+ {
+ if (!doit) return "hallucination every 10 turns";
+ set_image(p_ptr->image + 20 + randint(10));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_POISON:
+ {
+ if (!doit) return "poison";
+ set_poisoned(p_ptr->poisoned + 20 + randint(10));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_HUNGER:
+ {
+ if (!doit) return "create hunger";
+ (void)set_food(PY_FOOD_WEAK);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_STUN:
+ {
+ if (!doit) return "stun";
+ set_stun(p_ptr->stun + 20 + randint(10));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CUTS:
+ {
+ if (!doit) return "cuts";
+ set_cut(p_ptr->cut + 20 + randint(10));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_PARANO:
+ {
+ if (!doit) return "confusion";
+ set_confused(p_ptr->confused + 30 + randint(10));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CONFUSION:
+ {
+ if (!doit) return "confusion";
+ set_confused(p_ptr->confused + 20 + randint(10));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_BLIND:
+ {
+ if (!doit) return "blindness";
+ set_blind(p_ptr->blind + 20 + randint(10));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_PET_SUMMON:
+ {
+ if (!doit) return "summon pet every 101 turns";
+ summon_specific_friendly(p_ptr->py, p_ptr->px, max_dlv[dungeon_type], 0, FALSE);
+
+ /* Timeout is set before return */
+ /*FINDME*/
+
+ break;
+ }
+
+ case ACT_CURE_PARA:
+ {
+ if (!doit) return "cure confusion every 500 turns";
+ set_confused(0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_HALLU:
+ {
+ if (!doit) return "cure hallucination every 100 turns";
+ set_image(0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_POIS:
+ {
+ if (!doit) return "cure poison every 100 turns";
+ set_poisoned(0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_HUNGER:
+ {
+ if (!doit) return "satisfy hunger every 100 turns";
+ (void)set_food(PY_FOOD_MAX - 1);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_STUN:
+ {
+ if (!doit) return "cure stun every 100 turns";
+ set_stun(0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_CUTS:
+ {
+ if (!doit) return "cure cuts every 100 turns";
+ set_cut(0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_FEAR:
+ {
+ if (!doit) return "cure fear every 100 turns";
+ set_afraid(0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_CONF:
+ {
+ if (!doit) return "cure confusion every 100 turns";
+ set_confused(0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_BLIND:
+ {
+ if (!doit) return "cure blindness every 100 turns";
+ set_blind(0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURING:
+ {
+ if (!doit) return "curing every 110 turns";
+ set_blind(0);
+ set_poisoned(0);
+ set_confused(0);
+ set_stun(0);
+ set_cut(0);
+ set_image(0);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_DARKNESS:
+ {
+ if (!doit) return "darkness";
+ unlite_area(damroll(2, 10), 10);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_LEV_TELE:
+ {
+ if (!doit) return "teleport level every 50 turns";
+ teleport_player_level();
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_ACQUIREMENT:
+ {
+ if (!doit) return "acquirement every 3000 turns";
+ acquirement(p_ptr->py, p_ptr->px, 1, FALSE, FALSE);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_WEIRD:
+ {
+ if (!doit) return "something weird every 5 turns";
+ /* It doesn't do anything */
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_AGGRAVATE:
+ {
+ if (!doit) return "aggravate";
+ aggravate_monsters(1);
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_MUT:
+ {
+ if (!doit) return "gain corruption every 10 turns";
+ gain_random_corruption(0);
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_INSANITY:
+ {
+ if (!doit) return "cure insanity every 200 turns";
+ heal_insanity(damroll(10, 10));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_CURE_MUT:
+ {
+ msg_print("Ahah, you wish.");
+ /* Timeout is set before return */
+
+ break;
+ }
+
+ case ACT_LIGHT_ABSORBTION:
+ {
+ int y, x, light = 0, dir;
+ cave_type *c_ptr;
+
+ if (!doit) return "light absorption every 80 turns";
+
+ for (y = p_ptr->py - 6; y <= p_ptr->py + 6; y++)
+ {
+ for (x = p_ptr->px - 6; x <= p_ptr->px + 6; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ c_ptr = &cave[y][x];
+
+ if (distance(y, x, p_ptr->py, p_ptr->px) > 6) continue;
+
+ if (c_ptr->info & CAVE_GLOW)
+ {
+ light++;
+
+ /* No longer in the array */
+ c_ptr->info &= ~(CAVE_TEMP);
+
+ /* Darken the grid */
+ c_ptr->info &= ~(CAVE_GLOW);
+
+ /* Hack -- Forget "boring" grids */
+ if (cave_plain_floor_grid(c_ptr) &&
+ !(c_ptr->info & (CAVE_TRDT)))
+ {
+ /* Forget the grid */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Notice */
+ note_spot(y, x);
+ }
+
+ /* Process affected monsters */
+ if (c_ptr->m_idx)
+ {
+ /* Update the monster */
+ update_mon(c_ptr->m_idx, FALSE);
+ }
+
+ /* Redraw */
+ lite_spot(y, x);
+ }
+ }
+ }
+
+ if (!get_aim_dir(&dir)) return (FALSE);
+
+ msg_print("The light around you is absorbed... "
+ "and released in a powerful bolt!");
+ fire_bolt(GF_LITE, dir, damroll(light, p_ptr->lev));
+
+ /* Timeout is set before return */
+
+ break;
+ }
+ /* Horns of DragonKind (Note that these are new egos)*/
+ case ACT_BA_FIRE_H:
+ {
+ if (!doit) return "large fire ball (300) every 100 turns";
+ fire_ball(GF_FIRE, 5, 300, 7);
+
+ o_ptr->timeout = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ break;
+ }
+ case ACT_BA_COLD_H:
+ {
+ if (!doit) return "large cold ball (300) every 100 turns";
+ fire_ball(GF_COLD, 5, 300, 7);
+
+ o_ptr->timeout = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ break;
+ }
+ case ACT_BA_ELEC_H:
+ {
+ if (!doit) return "large lightning ball (300) every 100 turns";
+ fire_ball(GF_ELEC, 5, 300, 7);
+
+ o_ptr->timeout = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ break;
+ }
+ case ACT_BA_ACID_H:
+ {
+ if (!doit) return "large acid ball (300) every 100 turns";
+ fire_ball(GF_ACID, 5, 300, 7);
+
+ o_ptr->timeout = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ break;
+ }
+
+ case ACT_SPIN:
+ {
+ if (!doit) return "spinning around every 50+d25 turns";
+ do_spin();
+
+ o_ptr->timeout = 50 + randint(25);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Done */
+ break;
+ }
+ case ACT_NOLDOR:
+ {
+ if (!doit) return "detect treasure every 10+d20 turns";
+ detect_treasure(DEFAULT_RADIUS);
+
+ o_ptr->timeout = 10 + randint(20);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Done */
+ break;
+ }
+ case ACT_SPECTRAL:
+ {
+ if (!doit) return "wraith-form every 50+d50 turns";
+ if (!p_ptr->wraith_form)
+ {
+ set_shadow(20 + randint(20));
+ }
+ else
+ {
+ set_shadow(p_ptr->tim_wraith + randint(20));
+ }
+
+ o_ptr->timeout = 50 + randint(50);
+
+ /* Window stuff */
+ p_ptr->window |= PW_INVEN | PW_EQUIP;
+
+ /* Done */
+ break;
+ }
+ case ACT_JUMP:
+ {
+ if (!doit) return "phasing every 10+d10 turns";
+ teleport_player(10);
+ o_ptr->timeout = 10 + randint(10);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Done */
+ break;
+ }
+
+ case ACT_DEST_TELE:
+ {
+ if (!doit) return "teleportation and destruction of the ring";
+ if (!item)
+ {
+ msg_print("You can't activate this when it's there!");
+ }
+ if (get_check("This will destroy the ring. Do you wish to continue? "))
+ {
+ msg_print("The ring explodes into a space distortion.");
+ teleport_player(200);
+
+ /* It explodes, doesn't it ? */
+ take_hit(damroll(2, 10), "an exploding ring");
+
+ inc_stack_size_ex(item, -255, OPTIMIZE, NO_DESCRIBE);
+ }
+
+ break;
+ }
+ /*amulet of serpents dam 100, rad 2 timeout 40+d60 */
+ case ACT_BA_POIS_4:
+ {
+ if (!doit) return "venom breathing every 40+d60 turns";
+ /* Get a direction for breathing (or abort) */
+ if (!get_aim_dir(&dir)) break;
+
+ msg_print("You breathe venom...");
+ fire_ball(GF_POIS, dir, 100, 2);
+
+ o_ptr->timeout = rand_int(60) + 40;
+
+ /* Window stuff */
+ p_ptr->window |= PW_INVEN | PW_EQUIP;
+
+ /* Done */
+ break;
+ }
+ /*rings of X 50,50+d50 dur 20+d20 */
+ case ACT_BA_COLD_4:
+ {
+ if (!doit) return "ball of cold and resist cold every 50+d50 turns";
+ /* Get a direction for breathing (or abort) */
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_COLD, dir, 50, 2);
+ (void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20);
+
+ o_ptr->timeout = rand_int(50) + 50;
+
+ break;
+ }
+
+ case ACT_BA_FIRE_4:
+ {
+ if (!doit) return "ball of fire and resist fire every 50+d50 turns";
+ /* Get a direction for breathing (or abort) */
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_FIRE, dir, 50, 2);
+ (void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20);
+
+ o_ptr->timeout = rand_int(50) + 50;
+
+ break;
+ }
+ case ACT_BA_ACID_4:
+ {
+ if (!doit) return "ball of acid and resist acid every 50+d50 turns";
+ /* Get a direction for breathing (or abort) */
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_ACID, dir, 50, 2);
+ (void)set_oppose_acid(p_ptr->oppose_acid + randint(20) + 20);
+
+ o_ptr->timeout = rand_int(50) + 50;
+
+ break;
+ }
+
+ case ACT_BA_ELEC_4:
+ {
+ if (!doit) return "ball of lightning and resist lightning every 50+d50 turns";
+ /* Get a direction for breathing (or abort) */
+ if (!get_aim_dir(&dir)) break;
+
+ fire_ball(GF_ELEC, dir, 50, 2);
+ (void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20);
+
+ o_ptr->timeout = rand_int(50) + 50;
+
+ break;
+ }
+
+ case ACT_BR_ELEC:
+ {
+ if (!doit) return "breathe lightning (100) every 90+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe lightning.");
+ fire_ball(GF_ELEC, dir, 100, 2);
+
+ o_ptr->timeout = rand_int(90) + 90;
+
+ break;
+ }
+
+ case ACT_BR_COLD:
+ {
+ if (!doit) return "breathe frost (110) every 90+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe frost.");
+ fire_ball(GF_COLD, dir, 110, 2);
+
+ o_ptr->timeout = rand_int(90) + 90;
+
+ break;
+ }
+
+ case ACT_BR_FIRE:
+ {
+ if (!doit) return "breathe fire (200) every 90+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe fire.");
+ fire_ball(GF_FIRE, dir, 200, 2);
+
+ o_ptr->timeout = rand_int(90) + 90;
+
+ break;
+ }
+
+ case ACT_BR_ACID:
+ {
+ if (!doit) return "breathe acid (130) every 90+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe acid.");
+ fire_ball(GF_ACID, dir, 130, 2);
+
+ o_ptr->timeout = rand_int(90) + 90;
+
+ break;
+ }
+
+ case ACT_BR_POIS:
+ {
+ if (!doit) return "breathe poison gas (150) every 90+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe poison gas.");
+ fire_ball(GF_POIS, dir, 150, 2);
+
+ o_ptr->timeout = rand_int(90) + 90;
+
+ break;
+ }
+
+ case ACT_BR_MANY:
+ {
+ if (!doit) return "breathe multi-hued (250) every 60+d60 turns";
+ if (!get_aim_dir(&dir)) break;
+ chance = rand_int(5);
+ msg_format("You breathe %s.",
+ ((chance == 1) ? "lightning" :
+ ((chance == 2) ? "frost" :
+ ((chance == 3) ? "acid" :
+ ((chance == 4) ? "poison gas" : "fire")))));
+ fire_ball(((chance == 1) ? GF_ELEC :
+ ((chance == 2) ? GF_COLD :
+ ((chance == 3) ? GF_ACID :
+ ((chance == 4) ? GF_POIS : GF_FIRE)))),
+ dir, 250, 2);
+
+ o_ptr->timeout = rand_int(60) + 60;
+
+ break;
+ }
+
+ case ACT_BR_CONF:
+ {
+ if (!doit) return "breathe confusion (120) every 90+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe confusion.");
+ fire_ball(GF_CONFUSION, dir, 120, 2);
+
+ o_ptr->timeout = rand_int(90) + 90;
+
+ break;
+ }
+
+ case ACT_BR_SOUND:
+ {
+ if (!doit) return "breathe sound (130) every 90+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe sound.");
+ fire_ball(GF_SOUND, dir, 130, 2);
+
+ o_ptr->timeout = rand_int(90) + 90;
+
+ break;
+ }
+
+ case ACT_BR_CHAOS:
+ {
+ if (!doit) return "breathe chaos/disenchant (220) every 60+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ chance = rand_int(2);
+ msg_format("You breathe %s.",
+ ((chance == 1 ? "chaos" : "disenchantment")));
+ fire_ball((chance == 1 ? GF_CHAOS : GF_DISENCHANT),
+ dir, 220, 2);
+
+ o_ptr->timeout = rand_int(90) + 60;
+
+ break;
+ }
+
+ case ACT_BR_SHARD:
+ {
+ if (!doit) return "breathe sound/shards (230) every 60+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ chance = rand_int(2);
+ msg_format("You breathe %s.",
+ ((chance == 1 ? "sound" : "shards")));
+ fire_ball((chance == 1 ? GF_SOUND : GF_SHARDS),
+ dir, 230, 2);
+
+ o_ptr->timeout = rand_int(90) + 60;
+
+ break;
+ }
+
+ case ACT_BR_BALANCE:
+ {
+ if (!doit) return "breathe balance (250) every 60+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ chance = rand_int(4);
+ msg_format("You breathe %s.",
+ ((chance == 1) ? "chaos" :
+ ((chance == 2) ? "disenchantment" :
+ ((chance == 3) ? "sound" : "shards"))));
+ fire_ball(((chance == 1) ? GF_CHAOS :
+ ((chance == 2) ? GF_DISENCHANT :
+ ((chance == 3) ? GF_SOUND : GF_SHARDS))),
+ dir, 250, 2);
+
+ o_ptr->timeout = rand_int(90) + 60;
+
+ break;
+ }
+
+ case ACT_BR_LIGHT:
+ {
+ if (!doit) return "breathe light/darkness (200) every 60+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ chance = rand_int(2);
+ msg_format("You breathe %s.",
+ ((chance == 0 ? "light" : "darkness")));
+ fire_ball((chance == 0 ? GF_LITE : GF_DARK), dir, 200, 2);
+
+ o_ptr->timeout = rand_int(90) + 60;
+
+ break;
+ }
+ case ACT_BR_POWER:
+ {
+ if (!doit) return "breathe the elements (300) every 60+d90 turns";
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You breathe the elements.");
+ fire_ball(GF_MISSILE, dir, 300, 3);
+
+ o_ptr->timeout = rand_int(90) + 60;
+
+ break;
+ }
+ case ACT_GROW_MOLD:
+ {
+ if (!doit) return "grow mushrooms every 50+d50 turns";
+ msg_print("You twirl and spores fly everywhere!");
+ for (i = 0; i < 8; i++)
+ summon_specific_friendly(p_ptr->py, p_ptr->px, p_ptr->lev, SUMMON_BIZARRE1, FALSE);
+
+ o_ptr->timeout = randint(50) + 50;
+
+ break;
+ }
+ case ACT_MUSIC:
+ /*
+ fall through to unknown, as music should be
+ handled by calling procedure.
+ */
+
+ default:
+ {
+ msg_format("Unknown activation effect: %d.", spell);
+ if ( !doit ) return "Unknown Activation";
+ return NULL;
+ }
+ }
+ }
+
+ /* Set timeout for junkarts
+ * Note that I still need to set the timeouts for other
+ * (non-random) artifacts above
+ */
+ if (is_junkart && doit)
+ o_ptr->timeout = activation_info[o_ptr->pval2].cost / 10;
+
+ return NULL;
+}
+
+
+static bool_ activate_spell(object_type * o_ptr, byte choice)
+{
+ int mana = 0, gf = 0, mod = 0;
+
+ rune_spell s_ptr;
+
+
+ if (choice == 1)
+ {
+ gf = o_ptr->pval & 0xFFFF;
+ mod = o_ptr->pval3 & 0xFFFF;
+ mana = o_ptr->pval2 & 0xFF;
+ }
+ else if (choice == 2)
+ {
+ gf = o_ptr->pval >> 16;
+ mod = o_ptr->pval3 >> 16;
+ mana = o_ptr->pval2 >> 8;
+ }
+
+ s_ptr.type = gf;
+ s_ptr.rune2 = 1 << mod;
+ s_ptr.mana = mana;
+
+ /* Execute */
+ rune_exec(&s_ptr, 0);
+
+ if (choice == 1) o_ptr->timeout = mana * 5;
+ if (choice == 2) o_ptr->xtra2 = mana * 5;
+
+ return (TRUE);
+}
diff --git a/src/cmd7.c b/src/cmd7.c
new file mode 100644
index 00000000..aca14dcd
--- /dev/null
+++ b/src/cmd7.c
@@ -0,0 +1,7652 @@
+/* File: cmd7.c */
+
+/* Purpose: More Class commands */
+
+/*
+ * Copyright (c) 1999 Dark God
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+
+#include "angband.h"
+
+
+/*
+ * Describe class powers of Mindcrafters
+ *
+ * 'p' points to a 80 byte long buffer
+ */
+void mindcraft_info(char *p, int power)
+{
+ int plev = get_skill(SKILL_MINDCRAFT);
+
+
+ /* Clear buffer */
+ strcpy(p, "");
+
+ /* Fill the buffer with requested power description */
+ switch (power)
+ {
+ case 0:
+ strnfmt(p, 80, " rad %d", DEFAULT_RADIUS);
+ break;
+ case 1:
+ strnfmt(p, 80, " dam %dd%d", 3 + ((plev - 1) / 4), 3 + plev / 15);
+ break;
+ case 2:
+ strnfmt(p, 80, " range %d", (plev < 25 ? 10 : plev + 2 + p_ptr->to_s * 3));
+ break;
+ case 3:
+ strnfmt(p, 80, " range %d", plev * 5);
+ break;
+ case 4:
+ strnfmt(p, 80, " power %d", plev * (plev < 30 ? 1 : 2));
+ break;
+ case 5:
+ if (plev > 20)
+ strnfmt(p, 80, " dam %dd8 rad %d", 8 + ((plev - 5) / 4), (plev - 20)/8 + 1);
+ else
+ strnfmt(p, 80, " dam %dd8", 8 + ((plev - 5) / 4));
+ break;
+ case 6:
+ strnfmt(p, 80, " dur %d", plev);
+ break;
+ case 7:
+ break;
+ case 8:
+ if (plev < 25)
+ strnfmt(p, 80, " dam %d rad %d", (3 * plev) / 2, 2 + (plev / 10));
+ else
+ strnfmt(p, 80, " dam %d", plev * ((plev - 5) / 10 + 1));
+ break;
+ case 9:
+ strnfmt(p, 80, " dur 11-%d", 10 + plev + plev / 2);
+ break;
+ case 10:
+ strnfmt(p, 80, " dam %dd6 rad %d", plev / 2, 0 + (plev - 25) / 10);
+ break;
+ case 11:
+ strnfmt(p, 80, " dam %d rad %d", plev * (plev > 39 ? 4 : 3), 3 + plev / 10);
+ break;
+ }
+}
+
+
+/*
+ * Describe class powers of Mimics
+ *
+ * 'p' points to a 80 byte long buffer
+ */
+void mimic_info(char *p, int power)
+{
+ int plev = get_skill(SKILL_MIMICRY);
+ object_type *o_ptr = &p_ptr->inventory[INVEN_OUTER];
+
+ /* Clear the buffer */
+ strcpy(p, "");
+
+ /* Fill the buffer with requested power description */
+ switch (power)
+ {
+ case 0:
+ strnfmt(p, 80, " dur %d", k_info[o_ptr->k_idx].pval2 + get_skill_scale(SKILL_MIMICRY, 1000));
+ break;
+ case 1:
+ strnfmt(p, 80, " dur %d+d20", 10 + plev);
+ break;
+ case 2:
+ strnfmt(p, 80, " dur 50+d%d", 50 + (2 * plev));
+ break;
+ case 3:
+ strnfmt(p, 80, " dur 50+d%d", 50 + (2 * plev));
+ break;
+ case 4:
+ strnfmt(p, 80, " dur 50+d%d", 50 + (2 * plev));
+ break;
+ }
+}
+
+
+/*
+ * Allow user to choose a magic power.
+ *
+ * If a valid spell is chosen, saves it in '*sn' and returns TRUE
+ * If the user hits escape, returns FALSE, and set '*sn' to -1
+ * If there are no legal choices, returns FALSE, and sets '*sn' to -2
+ *
+ * The "prompt" should be "cast", "recite", or "study"
+ * The "known" should be TRUE for cast/pray, FALSE for study
+ *
+ * nb: This function has a (trivial) display bug which will be obvious
+ * when you run it. It's probably easy to fix but I haven't tried,
+ * sorry.
+ */
+bool_ get_magic_power(int *sn, magic_power *powers, int max_powers,
+ void (*power_info)(char *p, int power), int plev, int cast_stat)
+{
+ int i;
+
+ int num = 0;
+
+ int y = 2;
+
+ int x = 18;
+
+ int minfail = 0;
+
+ int chance = 0;
+
+ int info;
+
+ char choice;
+
+ char out_val[160];
+
+ char comment[80];
+
+ cptr p = "power";
+
+ magic_power spell;
+
+ bool_ flag, redraw;
+
+
+ /* Assume cancelled */
+ *sn = ( -1);
+
+ /* Get the spell, if available */
+ if (repeat_pull(sn))
+ {
+ /* Verify the spell */
+ if (powers[*sn].min_lev <= plev)
+ {
+ /* Success */
+ return (TRUE);
+ }
+ }
+
+ /* Nothing chosen yet */
+ flag = FALSE;
+
+ /* No redraw yet */
+ redraw = FALSE;
+
+ /* Count number of powers that satisfies minimum plev requirement */
+ for (i = 0; i < max_powers; i++)
+ {
+ if (powers[i].min_lev <= plev)
+ {
+ num++;
+ }
+ }
+
+ /* Build a prompt (accept all spells) */
+ strnfmt(out_val, 78, "(%^ss %c-%c, *=List, ESC=exit, %c-%c=Info) Use which %s? ",
+ p, I2A(0), I2A(num - 1), toupper(I2A(0)), toupper(I2A(num - 1)), p);
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Get a spell from the user */
+ while (!flag && get_com(out_val, &choice))
+ {
+ /* Request redraw */
+ if ((choice == ' ') || (choice == '*') || (choice == '?'))
+ {
+ /* Show the list */
+ if (!redraw)
+ {
+ char psi_desc[80];
+
+ /* Show list */
+ redraw = TRUE;
+
+ /* Display a list of spells */
+ prt("", 1, x);
+ prt("", y, x);
+ put_str("Name", y, x + 5);
+ put_str("Lv Mana Fail Info", y, x + 35);
+
+ /* Dump the spells */
+ for (i = 0; i < max_powers; i++)
+ {
+ /* Access the spell */
+ spell = powers[i];
+ if (spell.min_lev > plev) break;
+
+ chance = spell.fail;
+ /* Reduce failure rate by "effective" level adjustment */
+ chance -= 3 * (plev - spell.min_lev);
+
+ /* Reduce failure rate by INT/WIS adjustment */
+ chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[cast_stat]] - 1);
+
+ /* Not enough mana to cast */
+ if (spell.mana_cost > p_ptr->csp)
+ {
+ chance += 5 * (spell.mana_cost - p_ptr->csp);
+ }
+
+ /* Extract the minimum failure rate */
+ minfail = adj_mag_fail[p_ptr->stat_ind[cast_stat]];
+
+ /* Failure rate */
+ chance = clamp_failure_chance(chance, minfail);
+
+ /* Get info */
+ power_info(comment, i);
+
+ /* Dump the spell --(-- */
+ strnfmt(psi_desc, 80, " %c) %-30s%2d %4d %3d%%%s",
+ I2A(i), spell.name,
+ spell.min_lev, spell.mana_cost, chance, comment);
+ prt(psi_desc, y + i + 1, x);
+ }
+
+ /* Clear the bottom line */
+ prt("", y + i + 1, x);
+ }
+
+ /* Hide the list */
+ else
+ {
+ /* Hide list */
+ redraw = FALSE;
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Redo asking */
+ continue;
+ }
+
+ /* Note verify */
+ info = (isupper(choice));
+
+ /* Lowercase */
+ if (info) choice = tolower(choice);
+
+ /* Extract request */
+ i = (islower(choice) ? A2I(choice) : -1);
+
+ /* Totally Illegal */
+ if ((i < 0) || (i >= num))
+ {
+ bell();
+ continue;
+ }
+
+ /* Save the spell index */
+ spell = powers[i];
+
+ /* Provides info */
+ if (info)
+ {
+ c_prt(TERM_L_BLUE, spell.desc, 1, 0);
+
+ /* Restore the screen */
+ inkey();
+ Term_load();
+ character_icky = FALSE;
+ continue;
+ }
+
+ /* Stop the loop */
+ flag = TRUE;
+ }
+
+ /* Restore the screen */
+ if (redraw)
+ {
+ Term_load();
+ }
+ character_icky = FALSE;
+
+ /* Abort if needed */
+ if (!flag) return (FALSE);
+
+ /* Save the choice */
+ (*sn) = i;
+
+
+ repeat_push(*sn);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * do_cmd_cast calls this function if the player's class
+ * is 'mindcrafter'.
+ */
+void do_cmd_mindcraft(void)
+{
+ int n = 0, b = 0;
+
+ int chance;
+
+ int dir;
+
+ int minfail = 0;
+
+ int plev = get_skill(SKILL_MINDCRAFT);
+
+ magic_power spell;
+
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+
+ /* not if confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* get power */
+ if (!get_magic_power(&n, mindcraft_powers, MAX_MINDCRAFT_POWERS,
+ mindcraft_info, plev, A_WIS)) return;
+
+ spell = mindcraft_powers[n];
+
+ /* Verify "dangerous" spells */
+ if (spell.mana_cost > p_ptr->csp)
+ {
+ /* Warning */
+ msg_print("You do not have enough mana to use this power.");
+
+ /* Verify */
+ if (!get_check("Attempt it anyway? ")) return;
+ }
+
+ /* Spell failure chance */
+ chance = spell.fail;
+
+ /* Reduce failure rate by "effective" level adjustment */
+ chance -= 3 * (get_skill(SKILL_MINDCRAFT) - spell.min_lev);
+
+ /* Reduce failure rate by INT/WIS adjustment */
+ chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[A_WIS]] - 1);
+
+ /* Not enough mana to cast */
+ if (spell.mana_cost > p_ptr->csp)
+ {
+ chance += 5 * (spell.mana_cost - p_ptr->csp);
+ }
+
+ /* Extract the minimum failure rate */
+ minfail = adj_mag_fail[p_ptr->stat_ind[A_WIS]];
+
+ /* Failure rate */
+ chance = clamp_failure_chance(chance, minfail);
+
+ /* Failed spell */
+ if (rand_int(100) < chance)
+ {
+ if (flush_failure) flush();
+
+ msg_format("You failed to concentrate hard enough!");
+
+ sound(SOUND_FAIL);
+
+ if (randint(100) < (chance / 2))
+ {
+ /* Backfire */
+ b = randint(100);
+ if (b < 5)
+ {
+ msg_print("Oh, no! Your mind has gone blank!");
+ lose_all_info();
+ }
+ else if (b < 15)
+ {
+ msg_print("Weird visions seem to dance before your eyes...");
+ set_image(p_ptr->image + 5 + randint(10));
+ }
+ else if (b < 45)
+ {
+ msg_print("Your brain is addled!");
+ set_confused(p_ptr->confused + randint(8));
+ }
+ else if (b < 90)
+ {
+ set_stun(p_ptr->stun + randint(8));
+ }
+ else
+ {
+ /* Mana storm */
+ msg_print("Your mind unleashes its power in an uncontrollable storm!");
+ project(1, 2 + plev / 10, p_ptr->py, p_ptr->px, plev * 2,
+ GF_MANA, PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
+ p_ptr->csp = MAX(0, p_ptr->csp - plev * MAX(1, plev / 10));
+ }
+ }
+ }
+
+ /* Successful spells */
+ else
+ {
+ sound(SOUND_ZAP);
+
+ /* spell code */
+ switch (n)
+ {
+ /* Precog */
+ case 0:
+ {
+ /* Magic mapping */
+ if (plev > 44)
+ {
+ wiz_lite();
+ }
+ else if (plev > 19)
+ {
+ map_area();
+ }
+
+ /* Detection */
+ if (plev < 30)
+ {
+ b = detect_monsters_normal(DEFAULT_RADIUS);
+ if (plev > 14) b |= detect_monsters_invis(DEFAULT_RADIUS);
+ if (plev > 4) b |= detect_traps(DEFAULT_RADIUS);
+ }
+ else
+ {
+ b = detect_all(DEFAULT_RADIUS);
+ }
+
+ /* Telepathy */
+ if (plev > 24)
+ {
+ set_tim_esp(p_ptr->tim_esp + plev);
+
+ /* If plvl >= 40, we should have permanent ESP */
+ }
+
+ if (!b) msg_print("You feel safe.");
+
+ break;
+ }
+
+ /* Mindblast */
+ case 1:
+ {
+ if (!get_aim_dir(&dir)) return;
+
+ if (randint(100) < plev * 2)
+ {
+ fire_beam(GF_PSI, dir, damroll(3 + ((plev - 1) / 4), (3 + plev / 15)));
+ }
+ else
+ {
+ fire_ball(GF_PSI, dir, damroll(3 + ((plev - 1) / 4), (3 + plev / 15)), 0);
+ }
+
+ break;
+ }
+
+ /* Minor displace */
+ case 2:
+ {
+ if (plev < 25)
+ {
+ teleport_player(10);
+ }
+ else
+ {
+ int ii, ij;
+
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("Not on special levels!");
+ break;
+ }
+
+ msg_print("You open a Void Jumpgate. Choose a destination.");
+
+ if (!tgt_pt(&ii, &ij)) return;
+ p_ptr->energy -= 60 - plev;
+
+ if (!cave_empty_bold(ij, ii) ||
+ (cave[ij][ii].info & CAVE_ICKY) ||
+ (distance(ij, ii, p_ptr->py, p_ptr->px) > plev + 2 + (p_ptr->to_s*3)) ||
+ (rand_int(plev * plev / 2) == 0))
+ {
+ msg_print("You fail to exit the void correctly!");
+ p_ptr->energy -= 100;
+ get_pos_player(10 + p_ptr->to_s / 2, &ij, &ii);
+ }
+
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_BETWEEN);
+ cave_set_feat(ij, ii, FEAT_BETWEEN);
+ cave[p_ptr->py][p_ptr->px].special = ii + (ij << 8);
+ cave[ij][ii].special = p_ptr->px + (p_ptr->py << 8);
+ }
+
+ break;
+ }
+
+ /* Major displace */
+ case 3:
+ {
+ if (plev > 29) banish_monsters(plev);
+ teleport_player(plev * 5);
+
+ break;
+ }
+
+ /* Domination */
+ case 4:
+ {
+ if (plev < 30)
+ {
+ if (!get_aim_dir(&dir)) return;
+ fire_ball(GF_DOMINATION, dir, plev, 0);
+ }
+ else
+ {
+ charm_monsters(plev * 2);
+ }
+
+ break;
+ }
+
+ /* Fist of Force --- not 'true' TK */
+ case 5:
+ {
+ if (!get_aim_dir(&dir)) return;
+ fire_ball(GF_SOUND, dir, damroll(8 + ((plev - 5) / 4), 8),
+ (plev > 20 ? (plev - 20) / 8 + 1 : 0));
+
+ break;
+ }
+
+ /* Character Armour */
+ case 6:
+ {
+ set_shield(p_ptr->shield + plev, plev, 0, 0, 0);
+ if (plev > 14) set_oppose_acid(p_ptr->oppose_acid + plev);
+ if (plev > 19) set_oppose_fire(p_ptr->oppose_fire + plev);
+ if (plev > 24) set_oppose_cold(p_ptr->oppose_cold + plev);
+ if (plev > 29) set_oppose_elec(p_ptr->oppose_elec + plev);
+ if (plev > 34) set_oppose_pois(p_ptr->oppose_pois + plev);
+
+ break;
+ }
+
+ /* Psychometry */
+ case 7:
+ {
+ ident_spell();
+ break;
+ }
+
+ /* Mindwave */
+ case 8:
+ {
+ msg_print("Mind-warping forces emanate from your brain!");
+ if (plev < 25)
+ {
+ project(0, 2 + plev / 10, p_ptr->py, p_ptr->px,
+ (plev*3) / 2, GF_PSI, PROJECT_KILL);
+ }
+ else
+ {
+ (void)mindblast_monsters(plev * ((plev - 5) / 10 + 1));
+ }
+
+ break;
+ }
+
+ /* Adrenaline */
+ case 9:
+ {
+ set_afraid(0);
+ set_stun(0);
+ hp_player(plev);
+
+ b = 10 + randint((plev * 3) / 2);
+
+ if (plev < 35)
+ {
+ set_hero(p_ptr->hero + b);
+ }
+ else
+ {
+ set_shero(p_ptr->shero + b);
+ }
+
+ if (!p_ptr->fast)
+ {
+ /* Haste */
+ (void)set_fast(b, plev / 5);
+ }
+ else
+ {
+ (void)set_fast(p_ptr->fast + b, plev / 5);
+ }
+
+ break;
+ }
+
+ /* Psychic Drain */
+ case 10:
+ {
+ if (!get_aim_dir(&dir)) return;
+
+ b = damroll(plev / 2, 6);
+
+ if (fire_ball(GF_PSI_DRAIN, dir, b, 0 + (plev - 25) / 10))
+ {
+ p_ptr->energy -= randint(150);
+ }
+
+ break;
+ }
+
+ /* Telekinesis */
+ case 11:
+ {
+ msg_print("A wave of pure physical force radiates out from your body!");
+ project(0, 3 + plev / 10, p_ptr->py, p_ptr->px,
+ plev * (plev > 39 ? 4 : 3), GF_TELEKINESIS,
+ PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID);
+
+ break;
+ }
+
+ default:
+ {
+ msg_print("Zap?");
+
+ break;
+ }
+ }
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Sufficient mana */
+ if (spell.mana_cost <= p_ptr->csp)
+ {
+ /* Use some mana */
+ p_ptr->csp -= spell.mana_cost;
+ }
+
+ /* Over-exert the player */
+ else
+ {
+ int oops = spell.mana_cost - p_ptr->csp;
+
+ /* No mana left */
+ p_ptr->csp = 0;
+ p_ptr->csp_frac = 0;
+
+ /* Message */
+ msg_print("You faint from the effort!");
+
+ /* Hack -- Bypass free action */
+ (void)set_paralyzed(p_ptr->paralyzed + randint(5 * oops + 1));
+
+ /* Damage WIS (possibly permanently) */
+ if (rand_int(100) < 50)
+ {
+ bool_ perm = (rand_int(100) < 25);
+
+ /* Message */
+ msg_print("You have damaged your mind!");
+
+ /* Reduce constitution */
+ (void)dec_stat(A_WIS, 15 + randint(10), perm);
+ }
+ }
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+}
+
+
+static int get_mimic_chance(int mimic)
+{
+ s32b chance;
+
+ call_lua("get_mimic_info", "(d,s)", "d", mimic, "level", &chance);
+ chance *= 3;
+
+ chance -= get_skill_scale(SKILL_MIMICRY, 150);
+ chance -= 3 * adj_mag_stat[p_ptr->stat_ind[A_DEX]];
+
+ /* Return the chance */
+ return clamp_failure_chance(chance, 2);
+}
+
+
+void do_cmd_mimic_lore()
+{
+ int fail;
+
+ object_type *o_ptr;
+
+
+ /* Player has to be able to see */
+ if (p_ptr->blind || no_lite())
+ {
+ msg_print("You cannot see!");
+ return;
+ }
+
+ /* No transformations when confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+
+ /* Already in a mimic form -- Allow cancelling */
+ if (p_ptr->mimic_form)
+ {
+ msg_print("You morph back to your natural form!");
+
+ set_mimic(0, 0, 0);
+ }
+
+ /* Not in mimic forms -- Allow transformations */
+ else
+ {
+ o_ptr = &p_ptr->inventory[INVEN_OUTER];
+
+ if ((o_ptr->tval != TV_CLOAK) || (o_ptr->sval != SV_MIMIC_CLOAK))
+ {
+ msg_print("You are not wearing any cloaks of mimicry.");
+ return;
+ }
+
+ /* Calculate failure rate */
+ fail = get_mimic_chance(o_ptr->pval2);
+
+ if (fail > 75)
+ {
+ msg_print("You feel uneasy with this shape-change.");
+
+ if (!get_check("Try it anyway? ")) return;
+ }
+
+ /* Fumble */
+ if (randint(100) < fail)
+ {
+ msg_print("Your shape-change goes horribly wrong!");
+
+ if (randint(100) < p_ptr->skill_sav)
+ {
+ msg_print("You manage to wrest your body back under control.");
+ return;
+ }
+
+ set_mimic(30, resolve_mimic_name("Abomination"), get_skill(SKILL_MIMICRY));
+ }
+
+ /* Success */
+ else
+ {
+ set_mimic(k_info[o_ptr->k_idx].pval2 + get_skill_scale(SKILL_MIMICRY, 1000), o_ptr->pval2, get_skill(SKILL_MIMICRY));
+ }
+ }
+
+
+ /* Redraw title */
+ p_ptr->redraw |= (PR_TITLE);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+}
+
+static bool_ mimic_forbid_travel(char *fmt)
+{
+ u32b value = p_ptr->mimic_extra >> 16;
+ u32b att = p_ptr->mimic_extra & 0xFFFF;
+
+ if(value > 0 && (att & CLASS_ARMS || att & CLASS_LEGS))
+ {
+ msg_print("You had best not travel with your extra limbs.");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * do_cmd_cast calls this function if the player's class
+ * is 'mimic'.
+ */
+void do_cmd_mimic(void)
+{
+ int n = 0, b = 0;
+
+ int fail;
+
+ int minfail = 0;
+
+ int plev = get_skill(SKILL_MIMICRY);
+
+ magic_power spell;
+
+ static bool_ added_hooks = FALSE;
+ if(!added_hooks)
+ {
+ add_hook(HOOK_FORBID_TRAVEL, mimic_forbid_travel, "mimic_forbid_travel");
+ added_hooks = TRUE;
+ }
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+
+ /* not if confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* get power */
+ if (!get_magic_power(&n, mimic_powers, MAX_MIMIC_POWERS, mimic_info,
+ plev, A_DEX)) return;
+
+ spell = mimic_powers[n];
+
+ /* Verify "dangerous" spells */
+ if (spell.mana_cost > p_ptr->csp)
+ {
+ /* Warning */
+ msg_print("You do not have enough mana to use this power.");
+
+ /* Verify */
+ if (!get_check("Attempt it anyway? ")) return;
+ }
+
+ /* Spell failure chance */
+ fail = spell.fail;
+
+ /* Reduce failure rate by "effective" level adjustment */
+ fail -= 3 * (plev - spell.min_lev);
+
+ /* Reduce failure rate by INT/WIS adjustment */
+ fail -= 3 * (adj_mag_stat[p_ptr->stat_ind[A_DEX]] - 1);
+
+ /* Not enough mana to cast */
+ if (spell.mana_cost > p_ptr->csp)
+ {
+ fail += 5 * (spell.mana_cost - p_ptr->csp);
+ }
+
+ /* Extract the minimum failure rate */
+ minfail = adj_mag_fail[p_ptr->stat_ind[A_DEX]];
+
+ /* Minimum failure rate */
+ if (fail < minfail) fail = minfail;
+
+ /* Stunning makes spells harder */
+ if (p_ptr->stun > 50) fail += 25;
+ else if (p_ptr->stun) fail += 15;
+
+ /* Always a 5 percent chance of working */
+ if (fail > 95) fail = 95;
+
+ /* Failed spell */
+ if (rand_int(100) < fail)
+ {
+ if (flush_failure) flush();
+
+ msg_format("You failed to concentrate hard enough!");
+
+ sound(SOUND_FAIL);
+
+ if (randint(100) < (fail / 2))
+ {
+ /* Backfire */
+ b = randint(100);
+
+ if (b < 5)
+ {
+ msg_print("Oh, no! Your mind has gone blank!");
+ lose_all_info();
+ }
+ else if (b < 15)
+ {
+ msg_print("Weird visions seem to dance before your eyes...");
+ set_image(p_ptr->image + 5 + randint(10));
+ }
+ else if (b < 45)
+ {
+ msg_print("Your brain is addled!");
+ set_confused(p_ptr->confused + randint(8));
+ }
+ else
+ {
+ set_stun(p_ptr->stun + randint(8));
+ }
+ }
+ }
+
+ /* Successful spells */
+ else
+ {
+ sound(SOUND_ZAP);
+
+ /* spell code */
+ switch (n)
+ {
+ /* Mimic */
+ case 0:
+ {
+ do_cmd_mimic_lore();
+
+ break;
+ }
+
+ /* Invisibility */
+ case 1:
+ {
+ int ii = 10 + plev + randint(20) + p_ptr->to_s;
+
+ set_invis(p_ptr->tim_invisible + ii, 50);
+ set_tim_invis(p_ptr->tim_invisible + ii);
+
+ break;
+ }
+
+ /* Legs Mimicry */
+ case 2:
+ {
+ /* Extract the value and the flags */
+ u32b value = p_ptr->mimic_extra >> 16;
+ u32b att = p_ptr->mimic_extra & 0xFFFF;
+
+ /* Clear useless things */
+ att &= ~(CLASS_ARMS);
+ att &= ~(CLASS_WALL);
+
+ if (att & CLASS_LEGS)
+ {
+ value += 50 + randint(50 + (2 * plev));
+ }
+ else
+ {
+ msg_print("You mimic a new pair of legs.");
+
+ value = 50 + randint(50 + (2 * plev));
+ att |= (CLASS_LEGS);
+ }
+
+ if (value > 10000) value = 10000;
+
+ p_ptr->mimic_extra = att + (value << 16);
+ p_ptr->update |= (PU_BODY);
+
+ break;
+ }
+
+ /* Wall Mimicry */
+ case 3:
+ {
+ /* Extract the value and the flags */
+ u32b value = p_ptr->mimic_extra >> 16;
+ u32b att = p_ptr->mimic_extra & 0xFFFF;
+
+ /* Clear useless things */
+ att &= ~(CLASS_ARMS);
+ att &= ~(CLASS_LEGS);
+
+ if (att & CLASS_WALL)
+ {
+ value += 50 + randint(50 + (2 * plev));
+ }
+ else
+ {
+ msg_print("You grow an affinity for walls.");
+
+ value = 50 + randint(50 + (2 * plev));
+ att |= (CLASS_WALL);
+ }
+
+ if (value > 10000) value = 10000;
+
+ p_ptr->mimic_extra = att + (value << 16);
+ p_ptr->update |= (PU_BODY);
+
+ break;
+ }
+
+ case 4: /* Arms Mimicry */
+ {
+ /* Extract the value and the flags */
+ u32b value = p_ptr->mimic_extra >> 16;
+ u32b att = p_ptr->mimic_extra & 0xFFFF;
+
+ /* Clear useless things */
+ att &= ~(CLASS_LEGS);
+ att &= ~(CLASS_WALL);
+
+ if (att & CLASS_ARMS)
+ {
+ value += 50 + randint(50 + (2 * plev));
+ }
+ else
+ {
+ msg_print("You mimic a new pair of arms.");
+
+ value = 50 + randint(50 + (2 * plev));
+ att |= (CLASS_ARMS);
+ }
+
+ if (value > 10000) value = 10000;
+
+ p_ptr->mimic_extra = att + (value << 16);
+ p_ptr->update |= (PU_BODY);
+
+ break;
+ }
+
+ default:
+ {
+ msg_print("Zap?");
+
+ break;
+ }
+ }
+ }
+
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Sufficient mana */
+ if (spell.mana_cost <= p_ptr->csp)
+ {
+ /* Use some mana */
+ p_ptr->csp -= spell.mana_cost;
+ }
+
+ /* Over-exert the player */
+ else
+ {
+ int oops = spell.mana_cost - p_ptr->csp;
+
+ /* No mana left */
+ p_ptr->csp = 0;
+ p_ptr->csp_frac = 0;
+
+ /* Message */
+ msg_print("You faint from the effort!");
+
+ /* Hack -- Bypass free action */
+ (void)set_paralyzed(p_ptr->paralyzed + randint(5 * oops + 1));
+
+ /* Damage WIS (possibly permanently) */
+ if (rand_int(100) < 50)
+ {
+ bool_ perm = (rand_int(100) < 25);
+
+ /* Message */
+ msg_print("You have damaged your mind!");
+
+ /* Reduce constitution */
+ (void)dec_stat(A_DEX, 15 + randint(10), perm);
+ }
+ }
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+}
+
+
+/*
+ * do_cmd_cast calls this function if the player's class
+ * is 'beastmaster'.
+ */
+void do_cmd_beastmaster(void)
+{
+ int plev = p_ptr->lev, i, num;
+
+ monster_type *m_ptr;
+
+
+ /* Process the monsters (backwards) */
+ num = 0;
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ m_ptr = &m_list[i];
+
+ if (m_ptr->status == MSTATUS_PET)
+ {
+ num++;
+ }
+ }
+
+ if (num < plev * 2)
+ {
+ /* XXX XXX */
+ if (rand_int(80-(plev) - p_ptr->stat_use[5]-p_ptr->to_s) < 20)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, plev, rand_int(plev / 2), FALSE);
+ }
+ }
+ else msg_print("You can't summon more pets");
+
+ /* Take a turn */
+ if (is_magestaff()) energy_use = 80;
+ else energy_use = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+}
+
+
+/*
+ * Set of variables and functions to create an artifact
+ */
+
+
+/* LOG2 is a constant (compile-time) method of converting a single
+ * set bit into a number. Works well, but for variable (runtime)
+ * expressions, use a loop instead.. much smaller code*/
+#define LOG2(x) ( (x) & 0xFFFF? BLOG16(x) : BLOG16((x)>>16) + 16 )
+#define BLOG16(x) ( (x) & 0xFF ? BLOG8(x) : BLOG8 ((x)>>8 ) + 8 )
+#define BLOG8(x) ( (x) & 0xF ? BLOG4(x) : BLOG4 ((x)>>4 ) + 4 )
+#define BLOG4(x) ( (x) & 0x3 ? BLOG2(x) : BLOG2 ((x)>>2 ) + 2 )
+#define BLOG2(x) ( (x) & 0x1 ? 0 : 1 )
+
+int flags_select[32*5];
+int activation_select;
+
+/* Return true if the player is wielding the philosopher's stone
+ */
+bool_ alchemist_has_stone(void)
+{
+ if (p_ptr->inventory[INVEN_LITE].name1 == 209)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*
+ Display a group of flags from a_select flags, and return
+ the number of flags displayed (even invisible ones)
+ */
+int show_flags(byte group, int pval)
+{
+ int i, x, color = TERM_WHITE;
+ int items = 0;
+
+ char ttt[80];
+
+ Term_clear();
+
+ group++; /* Adjust - no zero group */
+
+ for ( i = 0 ; a_select_flags[i].group ; i++)
+ {
+ if (a_select_flags[i].group != group)
+ continue;
+
+ if (a_select_flags[i].xp == 0)
+ break;
+ else
+ {
+ sprintf(ttt, "%c) %s",
+ (items < 26) ? I2A(items) : ('0' + items - 26),
+ al_name + a_select_flags[i].desc);
+ if ( wizard || alchemist_has_stone())
+ sprintf(ttt, "%c) %s (exp %ld)",
+ (items < 26) ? I2A(items) : ('0' + items - 26),
+ al_name + a_select_flags[i].desc,
+ (long int) a_select_flags[i].xp);
+
+ /* Note: Somebody is VERY clever, and it wasn't me. Text printed as
+ * TERM_DARK is actually printed as TERM_BLUE *SPACES* to prevent the
+ * player from using a 'cut-and-paste' enabled terminal to see
+ * what he shouldn't. Thus, simply setting the color to TERM_DARK
+ * will entirely prevent the unspoiled player from knowing that it's
+ * even possible. */
+
+ switch (flags_select[i])
+ {
+ case 1:
+ color = TERM_YELLOW;
+ break; /* Flag was set by the player (just now)*/
+ case 0:
+ color = TERM_WHITE;
+ break; /* This flag can be set, player is 'aware' of it*/
+ case - 1:
+ color = TERM_L_GREEN;
+ break; /* Flag is already set*/
+ case - 2:
+ color = TERM_DARK;
+ break; /* Invisible option */
+ case - 3:
+ color = TERM_RED;
+ break; /* Flag is set, but player isn't 'aware' of it */
+ case - 4:
+ color = TERM_L_DARK;
+ break; /* Flag is not set, player is 'aware', but it's beyond thier skill */
+ default:
+ color = TERM_DARK;
+ break; /* Just in Case*/
+ }
+ }
+ /* For alchemists who have the stone, at least show all the flags... */
+ if ((alchemist_has_stone() || wizard) && color == TERM_DARK)
+ color = TERM_BLUE;
+
+ if (items < 16) x = 5;
+ else x = 45;
+ c_prt(color, ttt, ((items < 16) ? items : items - 16) + 5, x);
+ items++;
+
+ }
+ return items;
+}
+
+void show_levels(void)
+{
+ Term_clear();
+ c_prt(TERM_WHITE, "[a] Stats, sustains, luck, speed, vision, etc. ", 3, 10);
+ c_prt(TERM_WHITE, "[b] Misc. (Auras, light, see invis, etc) ", 4, 10);
+ c_prt(TERM_WHITE, "[c] Weapon Branding ", 5, 10);
+ c_prt(TERM_WHITE, "[d] Resistances and Immunities ", 6, 10);
+ c_prt(TERM_WHITE, "[e] ESP and Curses ", 7, 10);
+ c_prt(TERM_WHITE, "[f] Activation ", 8, 10);
+ c_prt(TERM_DARK , "[g] Abilities Gained ", 9, 10);
+ c_prt(TERM_WHITE, "[h] Display Required Essences and items ", 10, 10);
+ c_prt(TERM_WHITE, "[i] Done! Finalize and commit changes. ", 11, 10);
+ /*No need to return anything - if the valid selections change, it'll be a code level change.*/
+}
+
+s32b get_flags_exp(int pval, int oldpval)
+{
+ int i;
+ s32b exp = 0;
+
+ for (i = 0 ; a_select_flags[i].group ; i++ )
+ {
+ if (a_select_flags[i].xp == 0)
+ break;
+ else
+ {
+ if ( a_select_flags[i].group <= 5 && flags_select[i] )
+ {
+ s32b xp = a_select_flags[i].xp;
+ int factor = 1, oldfactor = 0;
+
+ /* don't even look at flags which the user can't set
+ * because they also can't change the pval when a pval-
+ * dependant flag is set, flags which they can't set
+ * cannot effect the exp in any way, whether their set or not
+ */
+ if ( flags_select[i] < -1 )
+ continue;
+ if ( flags_select[i] == -1 )
+ oldfactor = 1;
+
+ if (a_select_flags[i].pval)
+ {
+ /* (1/4)x^2 + x
+ * I wanted something smaller than x^2 or x^x
+ * this is because although a ring of speed +10 is
+ * more than 10 times better than a ring of speed +1,
+ * I don't think it's 100 times better. More like 30.
+ * this function yields:
+ * 1=1 * 2=3 * 3=5 * 4=8 * 5=11 * 6=15 * 7=21
+ * 8=24 * 9=29 * 10=35 * 11=41 * 12=48 * 13=55
+ * 14=63 * 15=71 * 20=120 * 25=181 * 30=255
+ * which I think is acceptable.
+ * briefly, to get a +30 speed ring, it would be:
+ * 255*50000 or over 12 million experience
+ * points. For reference, a level 50 human requires
+ * 5 million xp. I'm sure it's doable, but it'd be
+ * *HARD*
+ * a speed+10 artifact would require 1.75 million.
+ * much more doable, but not too easily.
+ */
+ factor = (pval * pval / 4 + pval);
+ if ( flags_select[i] == -1 )
+ {
+ oldfactor = oldpval * oldpval / 4 + oldpval;
+ }
+ }
+ exp += xp * factor - xp * oldfactor;
+ }
+ if ( a_select_flags[i].group == 88 && a_select_flags[i].flag == -activation_select )
+ {
+ exp += a_select_flags[i].xp;
+ }
+ }
+ }
+ if ( alchemist_has_stone() ) exp = exp / 4;
+ return exp;
+}
+
+/* returns the 'real quantity' of items needed to empower
+ * a particular flag to a particular pval.
+ * Note that this routine returns zero for any flag that
+ * doesn't require some sort of action.
+ */
+int calc_rqty(int i, int pval, int oldpval)
+{
+ /* return 0 if flag is greater than size of flags_select && ! activation */
+ if ( a_select_flags[i].group > 5 )
+ {
+ if ( activation_select == a_select_flags[i].flag)
+ return 1;
+ else
+ return 0;
+ }
+
+ /* return 0 if the flag wasn't set */
+ if ( flags_select[i] < -1 || flags_select[i] == 0 )
+ return 0;
+
+ /* Return change in pval if the flag was already set */
+ if ( flags_select[i] == -1 && a_select_flags[i].pval)
+ return pval - oldpval;
+
+ /* Return pval if the flag will be set this time */
+ else if ( a_select_flags[i].pval )
+ return pval;
+
+ /* Return 0 if the flag is unknown */
+ else if ( flags_select[i] == -1 )
+ return 0;
+ return 1;
+}
+
+/* Handle the various items that creating artifacts requires.
+ * Mode = 0 to print a description,
+ * 1 to use up the items
+ * -1 to check to see if the items exist
+ * Note that this function is called ONLY from the
+ * other artifact item helper function.
+ */
+
+
+int check_artifact_items(int pval, int oldpval, int mode)
+{
+ int i, j, k, row = 1 , col = 15, rqty, orqty, trqty;
+ bool_ good = TRUE;
+ int temporary = -1;
+ char ch;
+
+ /* For temporary items, waive the item requirements,
+ * except for the corpse... */
+ for ( j = 0 ; a_select_flags[j].group ; j++)
+ if (a_select_flags[j].flag == 4*32 && flags_select[j] == 1 )
+ temporary = j;
+ /* Check for enough items */
+ for (i = 0; a_select_flags[i].group ; i++)
+ {
+ /* For temporary items, ignore
+ everything except the one item
+ */
+ if (temporary != -1 && i != temporary)
+ continue;
+
+ /* Calc quantity is done per flag, because
+ some have a pval, some don't, some where already
+ set at pval=2, etc
+ */
+ rqty = orqty = calc_rqty(i, pval, oldpval);
+
+ /* If no item is associated with this flag,
+ or this flag wasn't set or didn't change */
+ if ( !a_select_flags[i].rtval || !rqty)
+ continue;
+
+ for ( k = 0 ; k < INVEN_WIELD ; k++ )
+ {
+ object_type *o_ptr = &p_ptr->inventory[k];
+
+ /* Note here that an rsval of -1 (which is read is 0xff
+ for a byte..) matches anything. */
+ if (o_ptr->tval == a_select_flags[i].rtval
+ && (o_ptr->sval == a_select_flags[i].rsval
+ || a_select_flags[i].rsval == (byte) - 1 ) )
+ {
+ /* Corpse validation is COMPLICATED!
+ * But at least we don't have to do this twice.
+ */
+ if ( a_select_flags[i].rtval == TV_CORPSE )
+ {
+ bool_ itemgood = TRUE;
+
+ /*Specified race not this one */
+ if ( o_ptr->pval2 != a_select_flags[i].rpval && a_select_flags[i].rpval)
+ continue;
+
+ /* Race flag (any monster who...)*/
+ for ( j = 0 ; !a_select_flags[i].rpval && a_select_flags[i].rflag[j] && j < 6 && itemgood ; j++)
+ {
+ int flag = a_select_flags[i].rflag[j] / 32;
+ u32b mask = 1 << (a_select_flags[i].rflag[j] % 32);
+
+ switch (flag)
+ {
+ case 0:
+ if ( !(r_info[o_ptr->pval2].flags1 & mask) ) itemgood = FALSE;
+ break;
+ case 1:
+ if ( !(r_info[o_ptr->pval2].flags2 & mask) ) itemgood = FALSE;
+ break;
+ case 2:
+ if ( !(r_info[o_ptr->pval2].flags3 & mask) ) itemgood = FALSE;
+ break;
+ case 3:
+ if ( !(r_info[o_ptr->pval2].flags4 & mask) ) itemgood = FALSE;
+ break;
+ case 4:
+ if ( !(r_info[o_ptr->pval2].flags5 & mask) ) itemgood = FALSE;
+ break;
+ case 5:
+ if ( !(r_info[o_ptr->pval2].flags6 & mask) ) itemgood = FALSE;
+ break;
+ case 6:
+ if ( !(r_info[o_ptr->pval2].flags7 & mask) ) itemgood = FALSE;
+ break;
+ case 7:
+ if ( !(r_info[o_ptr->pval2].flags8 & mask) ) itemgood = FALSE;
+ break;
+ case 8:
+ if ( !(r_info[o_ptr->pval2].flags9 & mask) ) itemgood = FALSE;
+ break;
+ default:
+ msg_print("This code should never be hit!");
+ }
+ }
+ if ( ! itemgood )
+ continue;
+
+ }
+ /* Validate pval of good item */
+ else if ( a_select_flags[i].rpval)
+ {
+ /* Must have matching signs */
+ if ( (o_ptr->pval < 0) != (a_select_flags[i].rpval < 0))
+ continue;
+ /* Must be greater than */
+ if ( abs(o_ptr->pval) < abs(a_select_flags[i].rpval))
+ continue;
+ }
+
+ trqty = MIN(o_ptr->number, rqty);
+ rqty -= trqty;
+
+ if ( mode == 1 )
+ {
+ inc_stack_size_ex(k, -trqty, NO_OPTIMIZE, DESCRIBE);
+ }
+ }/* if p_ptr->inventory item is acceptable */
+
+ } /*end of looping through the p_ptr->inventory*/
+
+ if (rqty)
+ {
+ good = FALSE;
+ /* Oops, we didn't have enough of this object
+ when actually creating the artifact.
+ unset this flag
+ */
+ if ( mode == 1 )
+ {
+ flags_select[i] = -4;
+ }
+ /* we only return false for mode -1,
+ * for mode 0 we display stuff, and for
+ * mode 1 we want to continue destroying things
+ * even if the player is missing one small item,
+ * because there's no way to change things now.
+ * We may have already destroyed a unique corpse,
+ * or some other hard-to-find item.
+ */
+ if ( mode == -1 )
+ return FALSE;
+ }
+
+ /* Display a description of the required object, if needed */
+ /* Note that the tests for good items HAVE to be in a different
+ place, because otherwise we don't know how many the player
+ has, as opposed to how many they need.
+ */
+ if ( mode == 0 )
+ {
+ char *o_name = al_name + a_select_flags[i].item_desc;
+ if (orqty > 1 && a_select_flags[i].pval && a_select_flags[i].item_descp)
+ o_name = al_name + a_select_flags[i].item_descp;
+
+ if ( rqty )
+ {
+ if ( orqty > 1 )
+ c_prt(TERM_RED, format(" you are missing %d of the %d %s", rqty, orqty, o_name), row++, col);
+ else if ( is_a_vowel(o_name[0]))
+ c_prt(TERM_RED, format(" you are missing an %s", o_name), row++, col);
+ else
+ c_prt(TERM_RED, format(" you are missing a %s", o_name), row++, col);
+ }
+ else
+ {
+ if ( orqty > 1 )
+ c_prt(TERM_GREEN, format(" you have the %d %s", orqty, o_name), row++, col);
+ else if ( is_a_vowel(o_name[0]))
+ c_prt(TERM_GREEN, format(" you have an %s", o_name), row++, col);
+ else
+ c_prt(TERM_GREEN, format(" you have a %s", o_name), row++, col);
+ }
+
+ if ( row > 21 )
+ {
+ row = 1;
+ if (!good)
+ (void)get_com("You are missing some items:", &ch);
+ else
+ (void)get_com("You have these needed items on hand:", &ch);
+ }
+
+ }
+
+ } /* End of group associated with this a_select_flags entry */
+
+ if ( mode == 0 )
+ {
+ while ( row < 22 )
+ c_prt(TERM_GREEN, " ", row++, col);
+ if (!good)
+ (void)get_com("You are missing some items:", &ch);
+ else
+ (void)get_com("You have these needed items on hand:", &ch);
+ }
+ return good;
+}
+
+/* Display a list of required essences,
+ * and/or use up the essences. */
+bool_ artifact_display_or_use(int pval, int oldpval, bool_ use)
+{
+ int essence[MAX_BATERIE_SVAL];
+ int essenceh[MAX_BATERIE_SVAL];
+ int al_idx, i, j, k;
+ bool_ enough;
+
+ /* Temporary Items require only one item, and no essences. */
+ for ( i = 0 ; a_select_flags[i].group ; i++)
+ if ( a_select_flags[i].flag == 32*4)
+ {
+ if ( use )
+ return check_artifact_items(pval, oldpval, 1);
+ else
+ return check_artifact_items(pval, oldpval, 0);
+ }
+
+ for ( i = 0 ; i < MAX_BATERIE_SVAL ; i++ )
+ essence[i] = essenceh[i] = 0;
+
+ /* Accumulate a list of required essences */
+ for ( al_idx = 0; al_idx < max_al_idx ; al_idx++ )
+ if ( alchemist_recipes[al_idx].tval == 0 )
+ for ( i = 0 ; a_select_flags[i].group ; i++)
+ {
+ int rqty = calc_rqty(i, pval, oldpval);
+
+ /* If the flag isn't being set, rqty will be zero */
+ if ( !rqty)
+ continue;
+
+ if ( alchemist_recipes[al_idx].sval == a_select_flags[i].flag )
+ essence[alchemist_recipes[al_idx].sval_essence] +=
+ alchemist_recipes[al_idx].qty * rqty;
+ }
+
+ /* The essence array now contains a list of all essences
+ * that will be consumed in the creation of this artifact */
+
+ /* Check for existence of required quatities of essences. */
+ for ( i = 0 ; i < INVEN_WIELD ; i++ )
+ {
+ for ( j = 0 ; j < MAX_BATERIE_SVAL ; j++)
+ if ( p_ptr->inventory[i].tval == TV_BATERIE && p_ptr->inventory[i].sval == j + 1)
+ {
+ essenceh[j] += p_ptr->inventory[i].number;
+ }
+ }
+
+ /* Check for enough essences */
+ enough = TRUE;
+ for ( i = 0 ; i < MAX_BATERIE_SVAL ; i++)
+ if ( essenceh[i] < essence[i] )
+ {
+ enough = FALSE;
+ break;
+ }
+
+ /* Check for items */
+ if ( enough )
+ enough = check_artifact_items(pval, oldpval, -1);
+
+
+ /* Display recipe list if they don't have enough, or not enough exp */
+ if (!enough || !use )
+ {
+ int row = 1 , col = 15;
+ bool_ good = FALSE;
+ char ch;
+
+ /* display of list of required essences */
+ /* Note: there are only 12 or so essences, so this list
+ * will ALWAYS fit on the screen */
+ for ( i = 0 ; i < MAX_BATERIE_SVAL ; i++)
+ if ( essence[i] )
+ {
+ int missing = -MIN(essenceh[i] - essence[i], 0);
+ good = TRUE;
+ if ( missing )
+ c_prt(TERM_RED, format("%d of the required %d essences of %s",
+ missing, essence[i],
+ k_name + k_info[lookup_kind(TV_BATERIE, i + 1)].name ),
+ row++, col);
+ else
+ c_prt(TERM_GREEN, format("you have the needed %d essences of %s",
+ essence[i],
+ k_name + k_info[lookup_kind(TV_BATERIE, i + 1)].name ),
+ row++, col);
+ }
+
+ if (good)
+ {
+ /* blank the bottom row */
+ c_prt(TERM_WHITE, " ", row++, col);
+
+ /* and wait for a key */
+ (void)get_com("You are currently missing:", &ch);
+ }
+
+ /* Display a list of needed items as well */
+ check_artifact_items(pval, oldpval, 0);
+
+ return FALSE;
+ }
+
+ /* If we get to this point in the code, then the player
+ * has the required essences and items in their p_ptr->inventory */
+
+ /* If they do have enough, and they have enough exp, consume them */
+ for (i = 0 ; i < MAX_BATERIE_SVAL ; i++)
+ for ( k = 0 ; k < INVEN_WIELD && essence[i] > 0 ; k++)
+ if (p_ptr->inventory[k].tval == TV_BATERIE
+ && p_ptr->inventory[k].sval == i + 1
+ && essence[i])
+ {
+ int num = p_ptr->inventory[k].number;
+
+ inc_stack_size_ex(k, MAX( -essence[i], -num), NO_OPTIMIZE, DESCRIBE);
+
+ essence[i] -= MIN(num, essence[i]);
+ }
+
+ /* Destroy the items needed */
+ check_artifact_items(pval, oldpval, 1);
+
+ return TRUE;
+}
+
+
+void display_activation_info(int num)
+{
+ object_type forge;
+ int i;
+
+
+ /* find the a_select_flags number of this activation type... */
+ for ( i = 0 ; a_select_flags[i].group ; i++)
+ if (a_select_flags[i].group == 88 && a_select_flags[i].flag == -num )
+ break;
+
+ object_wipe(&forge);
+ forge.xtra2 = num;
+ /* Print out various information about this activation... */
+ /* min level, experience, required items (and essences)
+ full description (from activation_aux) */
+ if (wizard)
+ c_prt(TERM_WHITE, format(" number:%d ", num), 5, 5);
+ else
+ c_prt(TERM_WHITE, " ", 5, 5);
+ c_prt(TERM_WHITE, format(" Level:%d ", a_select_flags[i].level), 6, 5);
+ c_prt(TERM_WHITE, format(" Exp :%d ", a_select_flags[i].xp), 7, 5);
+ c_prt(TERM_WHITE, format(" Item :%s ", al_name + a_select_flags[i].item_desc), 8, 5);
+ c_prt(TERM_WHITE, " ", 9, 5);
+ c_prt(TERM_WHITE, format(" %s ", activation_aux(&forge, 0, 0)), 9, 5);
+ c_prt(TERM_WHITE, " ", 10, 5);
+ inkey();
+}
+
+void select_an_activation(void)
+{
+ int i, lev, wid, hgt, begin = 0, sel = 0;
+ u32b max;
+ cptr act_list[150]; /* currently, ~127 hardcoded activations */
+ int act_ref[150];
+ char c;
+ /* How do we want to do this? */
+ /* Ideally, we let them select from a list, which includes all the activations that they've ecountered in any form.
+ Problems with this idea include mainly the lack of any (current) place to store which activations they've seen, and
+ that they'll not get credit for any seen before we start tracking it.
+
+ So - list is everything. If they select one which they're to low-level for
+ or if the explicitly request it, we'll display info about this item.
+ We'll also get our descriptions from the activation_aux(ACT_CONSTANT)
+ function, because they are more complete, and include even lua-scripted ones.
+ msg_print("Since the code to actually let you select one isn't here");
+ msg_print("You will automatically get the activation 'Dawn'");
+ activation_select = ACT_DAWN;
+ */
+
+ /* Build a list of available activations at the player's level */
+ lev = get_skill(SKILL_ALCHEMY);
+ for ( i = max = 0 ; max < (sizeof(act_list) / sizeof(cptr)) && a_select_flags[i].group ; i++)
+ if (a_select_flags[i].group == 88 && a_select_flags[i].level <= lev )
+ {
+ act_ref[max] = -a_select_flags[i].flag; /* Activation number */
+ act_list[max++] = al_name + a_select_flags[i].desc; /* Description */
+ }
+
+ /* Select from that list, using the util.c function display_list to display the scrolled list */
+ /* Note: I think that there is only one other place that uses this function. Should be more! */
+ while (1)
+ {
+ Term_clear();
+ Term_get_size(&wid, &hgt);
+
+ c_prt(TERM_WHITE, "Enter to select, ? for more information, 2 and 8 to scroll ", 0, 0);
+ display_list(1, 0, hgt - 2, wid - 2, "Select an Activation", act_list, max, begin, sel, TERM_L_GREEN);
+
+ c = inkey();
+
+ if (c == ESCAPE) break;
+ else if (c == '8')
+ {
+ sel--;
+ if (sel < 0)
+ {
+ sel = max - 1;
+ begin = max - hgt;
+ if (begin < 0) begin = 0;
+ }
+ if (sel < begin) begin = sel;
+ }
+ else if (c == '2')
+ {
+ sel++;
+ if (sel >= (s32b)max)
+ {
+ sel = 0;
+ begin = 0;
+ }
+ if (sel >= begin + hgt - 1) begin++;
+ }
+ else if (c == '?')
+ {
+ display_activation_info(act_ref[sel]);
+ }
+ else if (c == '\r')
+ {
+ display_activation_info(act_ref[sel]);
+ activation_select = act_ref[sel];
+ return;
+ }
+ }
+ activation_select = 0;
+}
+
+
+/* Consume 'num' magic essences and return true.
+ * If there aren't enough essences, return false */
+
+bool_ magic_essence(int num)
+{
+ int i;
+ int j = 0;
+
+ for (i = 0; i < INVEN_WIELD; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Count the magic essences */
+ if (o_ptr->k_idx && (o_ptr->tval == TV_BATERIE) && (o_ptr->sval == SV_BATERIE_MAGIC)) j += o_ptr->number;
+ }
+
+ /* Abort if not enough essences. */
+ if (j < num) return FALSE;
+
+ /* Consume them */
+ i = 0;
+ j = num;
+ while (i < INVEN_WIELD)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ if (o_ptr->k_idx && (o_ptr->tval == TV_BATERIE) && (o_ptr->sval == SV_BATERIE_MAGIC))
+ {
+ /* This can lead to invalid object pointer for objects
+ * that come after the magic essences. Therefore, every
+ * artifactable object should come before the essences.
+ */
+ j -= o_ptr->number;
+ inc_stack_size(i, -num);
+ num = j;
+ if (num <= 0) break;
+ /* Stay on this slot; do not increment i. */
+ }
+ else
+ {
+ /* Move on to the next slot. */
+ i++;
+ }
+ }
+
+ /* Sanity check. */
+ if (num > 0)
+ {
+ msg_format("ERROR: Couldn't destroy %d essences!", num);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+void do_cmd_create_artifact(object_type *q_ptr)
+{
+ int max, i = 0, j, cur_set = 0, abord = FALSE, done = FALSE;
+ int skill;
+ s32b exp = 0;
+
+ char out_val[160];
+ char choice = 0;
+ bool_ lockpval = FALSE;
+ int pval;
+ int oldpval;
+ energy_use = 100;
+
+ pval = q_ptr->pval;
+ oldpval = pval;
+ skill = get_skill(SKILL_ALCHEMY);
+
+ if ( !pval )
+ pval = 1;
+ /* No activation added on this round */
+ activation_select = 0;
+
+ /* Save the current flags */
+ for (i = 0 ; a_select_flags[i].group ; i++)
+ {
+ if ( a_select_flags[i].flag < 0 || a_select_flags[i].group > 5)
+ continue;
+
+ flags_select[i] = 0;
+
+ switch (a_select_flags[i].flag / 32)
+ {
+ case 0:
+ if (q_ptr->art_flags1 & 1 << (a_select_flags[i].flag % 32)) flags_select[i] = -1;
+ break;
+ case 1:
+ if (q_ptr->art_flags2 & 1 << (a_select_flags[i].flag % 32)) flags_select[i] = -1;
+ break;
+ case 2:
+ if (q_ptr->art_flags3 & 1 << (a_select_flags[i].flag % 32)) flags_select[i] = -1;
+ break;
+ case 3:
+ if (q_ptr->art_flags4 & 1 << (a_select_flags[i].flag % 32)) flags_select[i] = -1;
+ break;
+ case 4:
+ if (q_ptr->art_flags5 & 1 << (a_select_flags[i].flag % 32)) flags_select[i] = -1;
+ break;
+ case 5:
+ if (q_ptr->art_esp & 1 << (a_select_flags[i].flag % 32)) flags_select[i] = -1;
+ break;
+ default:
+ /*This will not be hit, inspite of activations, because of the <= 5 above...*/
+ break;
+ }
+ /*
+ this would learn about ALL flags....
+ if(wizard)
+ alchemist_known_artifacts[a_select_flags[i].flag/32] = 0xffffffffL;
+ */
+
+ /* Set various flags if they haven't *ID*'d an artifact with this flag set.*/
+ if ( !(alchemist_known_artifacts[a_select_flags[i].flag / 32] & (1 << (a_select_flags[i].flag % 32)) ))
+ {
+ /* If this item has an ability that depends on pval which the player
+ * cannot set, don't allow them to change the pval either. */
+ if ( a_select_flags[i].pval && flags_select[i])
+ lockpval = TRUE;
+
+ /* Set the color and set-ablitity of this flag */
+ if ( flags_select[i] )
+ flags_select[i] = -3;
+ else
+ flags_select[i] = -2;
+ continue;
+ }
+ else if ( skill < a_select_flags[i].level )
+ {
+ /* If the alchemist has not passed the skill level for this flag,
+ Set this flag as unsettable.
+ */
+ if ( flags_select[i])
+ lockpval = TRUE;
+ else
+ flags_select[i] = -4;
+ }
+ }
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+ Term_clear();
+
+
+ /* Everlasting love ... ... nevermind :) */
+ while ( !done && !abord)
+ {
+ c_prt((q_ptr->exp - exp > 0) ? TERM_L_GREEN : TERM_L_RED, format("Experience left: %ld", q_ptr->exp - exp), 2, 0);
+
+ /* Display the menu, but don't display it if we just
+ * displayed a message (it erases the screen, creating a blink message */
+ if ( cur_set < 6 || cur_set == 7 )
+ show_levels();
+
+ c_prt((q_ptr->exp - exp > 0) ? TERM_L_GREEN : TERM_L_RED, format("Experience left: %ld", q_ptr->exp - exp), 2, 0);
+
+ prt("Enter to accept, Escape to abort", 1, 0);
+
+ abord = !get_com("Play around with which group of powers?[a-g]", &choice);
+
+ if ( choice == ESCAPE)
+ abord = TRUE;
+
+ if ( abord )
+ continue; /*or break, same diff */
+
+ if ( isalpha(choice))
+ {
+ if (isupper(choice))
+ choice = tolower(choice);
+ cur_set = A2I(choice);
+ }
+ else
+ {
+ bell();
+ continue;
+ }
+
+ if ( cur_set == 5 )
+ {
+ if (q_ptr->xtra2 && !activation_select
+ && !get_check("This item already activates! Choose a different activation?")) continue;
+ select_an_activation();
+ exp = get_flags_exp(pval, oldpval);
+ continue;
+ }
+ if ( cur_set == 6 )
+ {
+ msg_print("This option is not available");
+ continue;
+ }
+ if ( cur_set == 7 )
+ {
+ artifact_display_or_use(pval, oldpval, FALSE);
+ continue;
+ }
+ if ( cur_set == 8 )
+ {
+ if (q_ptr->exp - exp < 0)
+ msg_print("Not enough experience for the flags you've selected.");
+ else
+ done = TRUE;
+ continue;
+ }
+
+ if (cur_set < 0 || cur_set > 4 )
+ {
+ bell();
+ continue;
+ }
+
+
+ while (!done && !abord)
+ {
+ /* Chose the flags */
+ exp = 0;
+ max = show_flags(cur_set, pval);
+ exp = get_flags_exp(pval, oldpval);
+ c_prt((q_ptr->exp - exp > 0) ? TERM_L_GREEN : TERM_L_RED, format("Experience left: %ld", q_ptr->exp - exp), 2, 0);
+
+ /* Build a prompt (accept all flags) */
+ if (max <= 26)
+ {
+ /* Build a prompt (accept all flags) */
+ strnfmt(out_val, 78, "(Flags %c-%c, I,D to change power level) Add/Remove which flag? ",
+ I2A(0), I2A(max - 1));
+ }
+ else
+ {
+ strnfmt(out_val, 78, "(Flags %c-%c, I,D to change power level) Add/Remove which flag? ",
+ I2A(0), '0' + max - 27);
+ }
+ c_prt(TERM_L_BLUE, format("Power(I/D to increase/decrease): %d", pval), 3, 0);
+
+ /* Get a spell from the user */
+ while (!(done = !get_com(out_val, &choice)))
+ {
+ if (choice == 'I')
+ {
+ if ( lockpval )
+ {
+ msg_print("You cannot do that - you don't know how!");
+ continue;
+ }
+ if (q_ptr->exp - exp < 0)
+ {
+ msg_print("Not enough experience. Decrease power or deselect flags.");
+ continue;
+ }
+ pval++;
+ break;
+ }
+ else if (choice == 'D')
+ {
+ if ( lockpval )
+ {
+ msg_print("You cannot do that - you don't know how!");
+ continue;
+ }
+ pval--;
+ if (pval < oldpval) pval = oldpval;
+ break;
+ }
+ else if (choice == '\r' || choice == ESCAPE || choice == ' ')
+ {
+ done = TRUE;
+ break;
+ }
+ else if (isalpha(choice))
+ {
+ /* Lowercase */
+ if (isupper(choice)) choice = tolower(choice);
+
+ /* Extract request */
+ i = (islower(choice) ? A2I(choice) : -1);
+ }
+ else
+ {
+ i = D2I(choice) + 26;
+
+ /* Illegal */
+ if (i < 26) i = -1;
+ }
+
+ /* Totally Illegal */
+ if ((i < 0) || (i >= max))
+ {
+ bell();
+ continue;
+ }
+ else
+ {
+ /*Find the i'th flag in group cur_set...*/
+ for ( j = 0 ; a_select_flags[j].group ; j++)
+ if (a_select_flags[j].group == cur_set + 1)
+ if (!i--) break;
+
+ if ( flags_select[j] == -4 )
+ {
+ msg_format("You need at least %d skill in alchemy.",
+ a_select_flags[j].level);
+ continue;
+ }
+ if ( flags_select[j] != 0 && flags_select[j] != 1)
+ {
+ bell();
+ continue;
+ }
+ if (flags_select[j]) flags_select[j] = 0;
+ else if (!flags_select[j])
+ {
+ if (q_ptr->exp - exp < 0)
+ {
+ msg_print("Not enough experience. Decrease power or deselect flags.");
+ continue;
+ }
+ flags_select[j] = 1;
+ }
+ break;
+ }
+ }
+ }/*sub-screen select and redraw loop*/
+ done = FALSE;
+ Term_clear();
+ }/* main screen (flag select screen) select and redraw loop*/
+
+ /* Abort if not enough experience, or no flags added */
+ if ( q_ptr->exp - exp < 0 || exp == 0 )
+ abord = TRUE;
+
+ /* Display the recipe, or use up the essences.
+ * Note that this has to be done before the screen
+ * is restored. This is because it's also called from
+ * within the loop to display the required items. */
+ if ( !abord )
+ if (!artifact_display_or_use(pval, oldpval, TRUE))
+ abord = TRUE;
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+
+ /* Return if abort, or missing ingredients */
+ if ( abord )
+ return;
+
+ /* Actually create the artifact */
+ q_ptr->exp -= exp;
+ q_ptr->art_flags4 &= ~TR4_ART_EXP;
+ q_ptr->pval = pval;
+
+ /* Just to be sure */
+ q_ptr->art_flags3 |= ( TR3_IGNORE_ACID | TR3_IGNORE_ELEC |
+ TR3_IGNORE_FIRE | TR3_IGNORE_COLD );
+
+ {
+ int now = 0, before = 0;
+ char dummy_name[80];
+ char new_name[80];
+
+ /* Apply the flags */
+ for (i = 0; a_select_flags[i].group ; i++)
+ {
+ if (flags_select[i] < 0)
+ before++;
+ else if ( flags_select[i] == 1)
+ {
+ now++;
+ switch (a_select_flags[i].flag / 32)
+ {
+ case 0:
+ q_ptr->art_flags1 |= 1 << (a_select_flags[i].flag % 32);
+ break;
+ case 1:
+ q_ptr->art_flags2 |= 1 << (a_select_flags[i].flag % 32);
+ break;
+ case 2:
+ q_ptr->art_flags3 |= 1 << (a_select_flags[i].flag % 32);
+ break;
+ case 3:
+ q_ptr->art_flags4 |= 1 << (a_select_flags[i].flag % 32);
+ break;
+ case 4:
+ q_ptr->art_flags5 |= 1 << (a_select_flags[i].flag % 32);
+ break;
+ case 5:
+ q_ptr->art_esp |= 1 << (a_select_flags[i].flag % 32);
+ break;
+ default:
+ msg_print("error: this code can't ever be hit!");
+ }
+ }
+ }
+
+ if ( activation_select )
+ {
+ q_ptr->art_flags3 |= TR3_ACTIVATE;
+ q_ptr->xtra2 = activation_select;
+ }
+
+
+ /* Set the 'show modifier' flag */
+ q_ptr->art_flags3 |= TR3_SHOW_MODS;
+
+ /* For temporary items, set a timeout.
+ * alchemist_skill^2 for now */
+ if ( q_ptr->art_flags5 & TR5_TEMPORARY )
+ {
+ int lev = get_skill(SKILL_ALCHEMY);
+ q_ptr->timeout = lev * lev * 3;
+ }
+
+ /* Describe the new artifact */
+ object_out_desc(q_ptr, NULL, FALSE, TRUE);
+
+
+ /* Name the new artifact */
+ strcpy(dummy_name, "of an Alchemist");
+ if (!(get_string("What do you want to call the artifact? ", dummy_name, 80)))
+ strcpy(new_name, "of an Alchemist");
+ else
+ {
+ if ((strncmp(dummy_name, "of ", 3) == 0) ||
+ (strncmp(dummy_name, "Of ", 3) == 0) ||
+ ((dummy_name[0] == '\'') &&
+ (dummy_name[strlen(dummy_name) - 1] == '\'')))
+ {
+ strcpy(new_name, dummy_name);
+ }
+ else
+ {
+ strcpy(new_name, "called '");
+ strcat(new_name, dummy_name);
+ strcat(new_name, "'");
+ }
+ }
+ /* Identify it fully */
+ object_aware(q_ptr);
+ object_known(q_ptr);
+
+ /* Mark the item as fully known */
+ q_ptr->ident |= (IDENT_MENTAL);
+ q_ptr->ident |= IDENT_STOREB; /* This will be used later on... */
+
+ /* Save the inscription */
+ q_ptr->art_name = quark_add(new_name);
+ q_ptr->found = OBJ_FOUND_SELFMADE;
+
+ done = FALSE;
+ while (!done && get_com("Do you want to let this item continue to gain experience?", &choice))
+ {
+ switch (choice)
+ {
+ case 'y':
+ case 'Y':
+ if (magic_essence(get_skill(SKILL_ALCHEMY)))
+ q_ptr->art_flags4 |= TR4_ART_EXP;
+ else
+ msg_format("Oh, NO! You don't have enough magic essences. You needed %d.", get_skill(SKILL_ALCHEMY));
+ done = TRUE;
+ break;
+ case 'n':
+ case 'N':
+ q_ptr->exp = 0;
+ done = TRUE;
+ break;
+ }
+ }
+
+ /* Cycle through the p_ptr->inventory, and optimize everything.
+ * This wasn't done earlier, because if we had, then
+ * things in the p_ptr->inventory would shift around, and q_ptr
+ * wouldn't point to the right thing. BUT, at this point
+ * we don't need q_ptr anymore, so optimizing the p_ptr->inventory
+ * becomes sane. Sticky bug to figure out, let me tell you.
+ * Note also that this is cycling backwards - this is so
+ * that the same effect doesn't cause us to skip items. */
+ for ( i = INVEN_WIELD - 1 ; i >= 0 ; i-- )
+ inven_item_optimize(i);
+ }
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+}
+
+/*
+ * Test to see if this tval/sval combo is in the alchemists'
+ * recipes as a createable item. Used to determine if we
+ * should extract from it.
+ */
+bool_ alchemist_exists(int tval, int sval, int ego, int artifact)
+{
+ int al_idx;
+
+ /* To prevent conflicts with recipes for ego-items.
+ * artifact not used, simplifies the loop below. */
+ if ((tval == 1) || artifact)
+ return FALSE;
+
+ /*Search for recipes with this tval/sval combo as the final result*/
+ for (al_idx = 0 ; al_idx < max_al_idx ; al_idx++)
+ {
+ int rtval = alchemist_recipes[al_idx].tval;
+ int rsval = alchemist_recipes[al_idx].sval;
+
+ /* Accept ego wands and staves since ego is extracted last */
+ if (((!ego || tval == TV_WAND || tval == TV_STAFF) && rtval == tval && rsval == sval) ||
+ ( ego && rtval == 1 && rsval == ego))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ * Hook to determine if an object can have things extracted from it.
+ */
+bool_ item_tester_hook_extractable(object_type *o_ptr)
+{
+
+ /* No artifacts */
+ if (artifact_p(o_ptr)) return (FALSE);
+
+ /* No cursed things */
+ if (cursed_p(o_ptr)) return (FALSE);
+
+ /* If we REALLY wanted to rebalance alchemists,
+ * we'd test for 'fully identified this object kind' here.
+ */
+
+ return ((o_ptr->tval == TV_ROD_MAIN && o_ptr->pval != 0)
+ || alchemist_exists(o_ptr->tval, o_ptr->sval, o_ptr->name2, o_ptr->name1));
+}
+
+/*
+ * Hook to determine if an object is empowerable (NOT rechargeable)
+ */
+bool_ item_tester_hook_empower(object_type *o_ptr)
+{
+ int sval = -1;
+ int lev = get_skill(SKILL_ALCHEMY);
+ /* after level 25, can empower ego items to create artifacts
+ * and double ego items.
+ * after level 50, can empower artifacts to create powerful artifacts
+ */
+
+ /* Never Empower a cursed item */
+ if ( cursed_p(o_ptr))
+ {
+ return FALSE;
+ }
+
+ /* Allow finalizing a self created artifact */
+ if (artifact_p(o_ptr)
+ && (o_ptr->art_flags4 & TR4_ART_EXP)
+ && !(o_ptr->art_flags4 & TR4_ULTIMATE))
+ return TRUE;
+
+ switch ( o_ptr->tval)
+ {
+ /* Empowerable objects: Traditional alchemist stuff */
+ case TV_WAND:
+ sval = SV_WAND_NOTHING;
+ break;
+ case TV_RING:
+ sval = SV_RING_NOTHING;
+ break;
+ case TV_STAFF:
+ sval = SV_STAFF_NOTHING;
+ break;
+ case TV_BOTTLE:
+ sval = 1;
+ break;
+ case TV_AMULET:
+ sval = SV_AMULET_NOTHING;
+ break;
+ case TV_SCROLL:
+ sval = SV_SCROLL_NOTHING;
+ break;
+ case TV_ROD:
+ sval = SV_ROD_NOTHING;
+ break;
+ case TV_ROD_MAIN:
+ sval = -1;
+ break;
+ case TV_BOOK:
+ sval = -1;
+ break;
+
+ /* Ego item stuff */
+ /* Disallow ego dragon armour before you can create artifacts.*/
+ case TV_DRAG_ARMOR:
+ if ( lev < 25)
+ return FALSE;
+ /* FALL THROUGH! no break here. */
+
+ /* weapons */
+
+ case TV_DAEMON_BOOK:
+ case TV_SWORD:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_AXE:
+ case TV_MSTAFF:
+
+ /* misc other items */
+ case TV_BOW:
+ case TV_BOOMERANG:
+ case TV_INSTRUMENT:
+ case TV_DIGGING:
+ case TV_LITE:
+
+ /* Ammo */
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+
+ /* Armor of various sorts */
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_HELM:
+ case TV_CROWN:
+ case TV_SHIELD:
+ case TV_CLOAK:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+
+ /* Disallow ANY creation of ego items below level 5*/
+ if ( lev < 5)
+ return FALSE;
+
+ /* empowering an ego item creates an artifact or a
+ * double ego item, disallow below level 25 */
+ if ( lev < 25 && o_ptr->name2)
+ return FALSE;
+
+ /* Disallow double-ego and artifact unless the character has
+ * the artifact creation ability. */
+ if (!has_ability(AB_CREATE_ART) &&
+ (artifact_p(o_ptr) || (o_ptr->name2 && o_ptr->name2b)))
+ return FALSE;
+
+ /* Otherwise... */
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+
+ /* Return to the traditional alchemist objects.
+ * All ego items and artifacts returning TRUE are accepted as artifactable
+ * at level 25. If we want double ego non wieldable items (Fireproof Staff
+ * of Plenty) the artifactable test in do_cmd_alchemist() must be changed,
+ * e.g. checking if the item is wearable.
+ * For now, we disallow non-wearable ego-items and artifacts here.
+ */
+
+ if ((o_ptr->name2 || artifact_p(o_ptr)) &&
+ o_ptr->tval != TV_RING && o_ptr->tval != TV_AMULET)
+ return FALSE;
+
+ /* return true if it's a 'of nothing' item;
+ * does nothing for TV_ROD_MAIN and TV_BOOK
+ */
+ return (sval == o_ptr->sval
+
+ /* or if it's artifactable */
+ || ((lev >= 50 || (lev >= 25 && !artifact_p(o_ptr))) &&
+ (o_ptr->tval == TV_RING || o_ptr->tval == TV_AMULET))
+
+ /* or if it's egoable (note that normal egos start at level 5, wands and such start at 15) */
+ || (!o_ptr->name2 && lev >= 15));
+}
+
+/* Extract a rod tip from a rod */
+void rod_tip_extract(object_type *o_ptr)
+{
+ object_type *q_ptr;
+ object_type forge;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Paranoia, return if it's a rod of nothing */
+ if (o_ptr->pval == SV_ROD_NOTHING)
+ return;
+
+ /* Extract the rod tip */
+ object_prep(q_ptr, lookup_kind(TV_ROD, o_ptr->pval));
+
+ q_ptr->number = o_ptr->number;
+
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ (void)inven_carry(q_ptr, FALSE);
+
+ /* Remove it from the rod */
+ o_ptr->pval = SV_ROD_NOTHING;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+}
+
+
+/* Begin & finish an art */
+void do_cmd_toggle_artifact(object_type *o_ptr)
+{
+ char o_name[80];
+
+ if (!(o_ptr->art_flags4 & TR4_ART_EXP))
+ {
+ bool_ okay = TRUE;
+
+ if ( !alchemist_has_stone())
+ {
+ msg_print("Creating an artifact will result into a permanent loss of 10 hp.");
+ if (!get_check("Are you sure you want to do that?")) return;
+ }
+
+ if (!magic_essence(get_skill(SKILL_ALCHEMY)))
+ {
+ msg_format("You need %d magic essences.", get_skill(SKILL_ALCHEMY));
+ return;
+ }
+
+ /* Description */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ if (o_ptr->number > 1)
+ {
+ msg_print("Not enough energy to enchant more than one object!");
+ msg_format("%d of your %s %s destroyed!", (o_ptr->number) - 1, o_name, (o_ptr->number > 2 ? "were" : "was"));
+ o_ptr->number = 1;
+ }
+ okay = TRUE;
+
+ if (!okay) return;
+
+ /* he/she got warned */
+ p_ptr->hp_mod -= 10;
+
+ /* Ok toggle it */
+ o_ptr->art_flags4 |= TR4_ART_EXP;
+ o_ptr->name2 = 0;
+ o_ptr->name2b = 0;
+ o_ptr->art_name = quark_add("Becoming");
+
+ /* Copy the object_kind flags to the artifact flags.
+ * Note that this is only needed so that flags set in the
+ * 'kind' area are visible when finalizing the artifact.
+ */
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ o_ptr->art_flags1 |= f1;
+ o_ptr->art_flags2 |= f2;
+ o_ptr->art_flags3 |= f3;
+ o_ptr->art_flags4 |= f4;
+ o_ptr->art_flags5 |= f5;
+ o_ptr->art_esp |= esp;
+ }
+
+ p_ptr->update |= (PU_HP);
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ }
+ else
+ {
+ do_cmd_create_artifact(o_ptr);
+ }
+}
+
+/*
+ * Test to see if they have all the ingredients to create an item.
+ * (doesn't count base item)
+ * creates 'tocreate' items (may be -1, but no more than that!)
+ * if tocreate=0, will return true if the player has enough
+ * in their p_ptr->inventory to empower that item.
+ */
+bool_ alchemist_items_check(int tval, int sval, int ego, int tocreate, bool_ message)
+{
+ int al_idx, j;
+ bool_ exists = FALSE;
+
+
+ for ( al_idx = 0 ; al_idx < max_al_idx ; al_idx++ )
+ if ((ego && alchemist_recipes[al_idx].sval == ego
+ && alchemist_recipes[al_idx].tval == 1 )
+ || (!ego && alchemist_recipes[al_idx].sval == sval
+ && alchemist_recipes[al_idx].tval == tval))
+ {
+ exists = TRUE;
+ /* Create the essences */
+ if (tocreate > 0)
+ {
+ object_type forge;
+ object_type *o_ptr = &forge;
+
+ object_wipe(o_ptr);
+ object_prep(o_ptr, lookup_kind(TV_BATERIE, alchemist_recipes[al_idx].sval_essence));
+ o_ptr->number = alchemist_recipes[al_idx].qty * tocreate;
+ /* Don't bother with apply_magic */
+
+ /* Randomly decrease the number of essences created */
+ if ( randint(3) == 1
+ && randint(52) > get_skill(SKILL_ALCHEMY)
+ && !alchemist_has_stone())
+ o_ptr->number /= randint(2) + 1;
+ if ( o_ptr->number == 0)
+ continue;
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ if (inven_carry_okay(o_ptr))
+ {
+ int i;
+ inven_carry(o_ptr, FALSE);
+ for (i = 0; i < INVEN_WIELD ; i++)
+ if (p_ptr->inventory[i].tval == o_ptr->tval && p_ptr->inventory[i].sval == o_ptr->sval)
+ {
+ if ( message )
+ inven_item_describe(i);
+ break;
+ }
+
+ }
+ else
+ drop_near(o_ptr, 0, p_ptr->py, p_ptr->px);
+
+ o_ptr->ident |= IDENT_STOREB;
+ }
+ else if ( tocreate < -1)
+ {
+ /*It's not valid to create more than one
+ * thing at a time, so if it's less than -1,
+ * it must be time to display a recipe
+ */
+ msg_format("%d essences of %d",
+ alchemist_recipes[al_idx].qty,
+ al_idx);
+ }
+ else /* Destroy the essences (tocreate == -1)
+ * or check for existence(tocreate == 0)*/
+ {
+ int rqty = alchemist_recipes[al_idx].qty;
+ for (j = 0; j < INVEN_WIELD; j++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[j];
+ if (o_ptr->k_idx
+ && (o_ptr->tval == TV_BATERIE )
+ && (o_ptr->sval == alchemist_recipes[al_idx].sval_essence )
+ && (o_ptr->number >= rqty ))
+ {
+ /* At this point, the item is required, destroy it. */
+ if ( tocreate )
+ {
+ inc_stack_size_ex(j, 0 - rqty, OPTIMIZE, message ? DESCRIBE : NO_DESCRIBE);
+ }
+
+ /* When we find enough of the item, break out of the
+ * 'search through the p_ptr->inventory' loop */
+ break;
+ }
+ }
+ if ( j == INVEN_WIELD)
+ /* This ingredient was not found, cannot do recipe */
+ return FALSE;
+ }/*destroying items, or just checking for existence */
+ }
+ return exists;
+}
+
+/* This function lists all the ingredients
+ * needed to create something.
+ */
+void alchemist_display_recipe(int tval, int sval, int ego)
+{
+ int al_idx;
+ int row = 1, col = 15;
+ char o_name[80];
+ char ch;
+ object_type *o_ptr, forge;
+
+ /* Display the ingredients for a recipe */
+ for ( al_idx = 0 ; al_idx < max_al_idx ; al_idx++ )
+ if ((ego && alchemist_recipes[al_idx].sval == ego
+ && alchemist_recipes[al_idx].tval == 1 )
+ || (!ego && alchemist_recipes[al_idx].sval == sval
+ && alchemist_recipes[al_idx].tval == tval))
+ {
+ int qty = alchemist_recipes[al_idx].qty;
+ c_prt(TERM_GREEN,
+ format(" %d essence%s %s ", qty,
+ qty > 1 ? "s" : "",
+ k_name + k_info[lookup_kind(TV_BATERIE, alchemist_recipes[al_idx].sval_essence)].name ),
+ row++, col);
+ }
+
+ c_prt(TERM_WHITE, " ", row++, col);
+
+ if (!ego)
+ {
+ /* Find the name of that object */
+ o_ptr = &forge;
+ object_prep(o_ptr, lookup_kind(tval, sval));
+ o_ptr->name2 = ego;
+ hack_apply_magic_power = -99;
+ apply_magic(o_ptr, get_skill(SKILL_ALCHEMY) * 2, FALSE, FALSE, FALSE);
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ /* the 0 mode means only the text, leaving off any numbers */
+ object_desc(o_name, o_ptr, FALSE, 0);
+ }
+ else
+ {
+ /* Display the ego item name */
+ strcpy(o_name, e_name + e_info[ego].name);
+ }
+
+ /* Display a short message about it, and wait for a key. */
+ (void)get_com(format("ingredients needed to create a %s", o_name), &ch);
+
+}
+
+/*
+ *
+ * The alchemist_recipe_select was copied from
+ * wiz_create_itemtype
+ * and then changed quite a bit.
+ *
+ */
+
+/*
+ The select array is a simple array of 'use this char to select item x'
+ It has 88 items (three columns of 20 each)
+ selectitem is initilized with the reverse mappings:
+ selectitem[selectchar[x]] == x is always true.
+ */
+char selectchar[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*():;,.<=>[]{}/=?+'~";
+byte selectitem[256];
+
+void strip_and_print(char *str, int color, int num)
+{
+ int row = 2 + (num % 20), col = 40 * (num / 20);
+ int ch, max_len = 0;
+ char buf[80];
+ char *string;
+
+ if (num > 60)
+ {
+ msg_print("Attempting to display too many items!");
+ return;
+ }
+ ch = selectchar[num];
+ if (selectitem[ch] != num)
+ {
+ int i;
+ for ( i = 0 ; i < 256 ; i++)
+ selectitem[i] = 0xff;
+ for ( i = 0 ; selectchar[i] ; i++)
+ selectitem[(byte)selectchar[i]] = i;
+ }
+
+ /* Skip past leading characters */
+ while ((*str == ' ') || (*str == '&')) str++;
+
+ /* Copy useful chars */
+ for (string = buf; *str; str++)
+ if (*str != '~') *string++ = *str;
+
+ /* Terminate the new name */
+ *string = '\0';
+
+ /* strip the name down to size
+ if (76-col < (signed)max_len)
+ max_len = 76-col;
+ else
+ max_len = 30-6;*/
+ max_len = 39;
+
+ string = buf;
+ if (strlen(string) > (unsigned)max_len)
+ string = string + (strlen(string) - max_len);
+
+ /* Print it */
+ c_prt(color, format("[%c] %s", ch, string), row, col);
+}
+
+/* Display a list of recipes that need a particular essence.
+ * Note that we display a list of essences first,
+ * so in effect, this is the alchemist's recipe book.
+ */
+void alchemist_recipe_book(void)
+{
+ int num, max_num, i, al_idx, bat, kidx;
+ int choice[61], choice2[61];
+ int mod40;
+ bool_ essence[MAX_BATERIE_SVAL + 1];
+ char ch;
+
+ /* Save and clear the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ while ( TRUE )
+ {
+ Term_clear();
+
+ num = 0;
+
+ /* Display bateries */
+
+ /* start with assumption that the alchemist knows about no recipes */
+ for (i = 0; i < MAX_BATERIE_SVAL + 1 ; i++)
+ essence[i] = FALSE;
+
+ /* cycle through all alchemist recipes */
+ for (al_idx = 0 ; al_idx < max_al_idx ; al_idx++)
+ /* if we aren't already going to display this essence */
+ if (!essence[alchemist_recipes[al_idx].sval_essence])
+ {
+
+ /*Note that we don't display artifact recipes here...*/
+ /*This is partially because artifacts often require exotic
+ ingredients as well */
+
+ if (!alchemist_recipes[al_idx].tval)
+ continue;
+
+ if (alchemist_recipes[al_idx].tval == 1)
+ {
+ if (alchemist_known_egos[alchemist_recipes[al_idx].sval / 32]
+ & (1 << (alchemist_recipes[al_idx].sval % 32)) )
+ essence[alchemist_recipes[al_idx].sval_essence] = TRUE;
+ continue;
+ }
+
+ kidx = lookup_kind(alchemist_recipes[al_idx].tval, alchemist_recipes[al_idx].sval);
+ if (alchemist_recipes[al_idx].tval != 1 && k_info[kidx].know)
+ essence[alchemist_recipes[al_idx].sval_essence] = TRUE;
+
+ }
+ for (num = 0, i = 0; i < MAX_BATERIE_SVAL + 7 ; i++)
+ if (essence[i] || i > MAX_BATERIE_SVAL)
+ {
+ int kidx = lookup_kind(TV_BATERIE, i);
+ if (i > MAX_BATERIE_SVAL)
+ {
+ switch (i)
+ {
+ case (MAX_BATERIE_SVAL + 1): strip_and_print("Scrolls", TERM_WHITE, num);
+ break;
+ case (MAX_BATERIE_SVAL + 2): strip_and_print("Potions", TERM_WHITE, num);
+ break;
+ case (MAX_BATERIE_SVAL + 3): strip_and_print("Wands", TERM_WHITE, num);
+ break;
+ case (MAX_BATERIE_SVAL + 4): strip_and_print("Rings", TERM_WHITE, num);
+ break;
+ case (MAX_BATERIE_SVAL + 5): strip_and_print("Staves", TERM_WHITE, num);
+ break;
+ case (MAX_BATERIE_SVAL + 6): strip_and_print("Amulets", TERM_WHITE, num);
+ break;
+ default:
+ continue;
+ }
+ }
+ else
+ /* add this essence to the list*/
+ strip_and_print(k_name + k_info[kidx].name, TERM_WHITE, num);
+
+ choice[num++] = i;
+ }
+ max_num = num;
+ if ( max_num == 0)
+ {
+ /*Note that this should never actually happen, as any skill
+ at alchemy automatically gets you some recipes, and this
+ procedure shouldn't be called for players without alchemist skill
+ */
+ msg_print("You don't know any recipes!");
+ msg_print("You can't be an alchemist without recipes!");
+ break;
+ }
+
+ while (num == 0xff || num >= max_num)
+ {
+ ch = selectchar[max_num - 1];
+ /* Choose! */
+ if ( max_num == 0 ||
+ !get_com(format("Which Type of Recipe?[a-%c]", selectchar[max_num - 1]), &ch))
+ break;
+
+ /* Analyze choice - note that the cast to byte prevents overflow*/
+ num = selectitem[(byte)ch];
+
+ }
+ /* This break, and the break for no recipes above,
+ are the only exits from this procedure.
+ */
+ if ( num == 0xff || num >= max_num)
+ break;
+
+ /* Save the baterie index */
+ bat = choice[num];
+ num = 0;
+
+ /*Display the 'type of object' recipe screen*/
+ if (bat > MAX_BATERIE_SVAL)
+ {
+ int tval;
+ switch (bat)
+ {
+ case MAX_BATERIE_SVAL + 1:
+ tval = TV_SCROLL;
+ break;
+ case MAX_BATERIE_SVAL + 2:
+ tval = TV_POTION;
+ break;
+ case MAX_BATERIE_SVAL + 3:
+ tval = TV_WAND;
+ break;
+ case MAX_BATERIE_SVAL + 4:
+ tval = TV_RING;
+ break;
+ case MAX_BATERIE_SVAL + 5:
+ tval = TV_STAFF;
+ break;
+ case MAX_BATERIE_SVAL + 6:
+ tval = TV_AMULET;
+ break;
+ }
+ Term_load();
+ alchemist_recipe_select(&tval, 0, FALSE, TRUE);
+ Term_save();
+ continue;
+ }
+ mod40 = 0;
+ while ( TRUE )
+ {
+ int skipped;
+
+ Term_clear();
+ num = 0;
+
+ if (mod40)
+ {
+ strip_and_print("--MORE--", TERM_WHITE, num);
+ choice[num] = -2;
+ choice2[num++] = 0;
+ }
+
+ /* Display all items made with this essence */
+ for ( al_idx = 0 , skipped = 0 ; al_idx < max_al_idx ; al_idx++)
+ if ( alchemist_recipes[al_idx].sval_essence == bat)
+ {
+ int sval = alchemist_recipes[al_idx].sval;
+ int tval = alchemist_recipes[al_idx].tval;
+ char names[200] = "";
+
+ if (alchemist_recipes[al_idx].tval == 1)
+ {
+ /* Ego items */
+ ego_item_type *e_ptr = &e_info[sval];
+ int j, k;
+
+ if ( !(alchemist_known_egos[sval / 32] & (1 << (sval % 32))))
+ continue;
+
+ for ( j = 0 ; j < 6 && e_ptr->tval[j] ; j ++ )
+ {
+ if ( j > 0 && e_ptr->tval[j] == e_ptr->tval[j - 1])
+ continue;
+ for ( k = 0; tvals[k].tval; k++)
+ if (tvals[k].tval == e_ptr->tval[j])
+ {
+ strcat(names, tvals[k].desc);
+ strcat(names, ", ");
+ break;
+ }
+ }
+ strcat(names, e_name + e_ptr->name);
+ }
+ else
+ {
+ /* Normal Items */
+ int kidx = lookup_kind(tval, sval);
+ int k;
+ if ( !k_info[kidx].know )
+ continue;
+
+ for ( k = 0; tvals[k].tval; k++)
+ if (tvals[k].tval == tval)
+ {
+ strcat(names, tvals[k].desc);
+ break;
+ }
+ strcat(names, " of ");
+ strcat(names, k_name + k_info[kidx].name);
+
+ }
+
+ /*Skip the first mod40 pages of recipes*/
+ if (skipped++ < mod40*38)
+ continue;
+
+ /* add this object kind to the list*/
+ strip_and_print(names, TERM_WHITE, num);
+ choice[num] = tval;
+ choice2[num++] = sval;
+ if (num > 38)
+ {
+ strip_and_print("--MORE--", TERM_WHITE, num);
+ choice[num] = -1;
+ choice2[num++] = 0;
+ break;
+ }
+
+ }/*Loop through tidx/sidx*/
+
+ max_num = num;
+ while (num == 0xff || num >= max_num)
+ {
+ ch = selectchar[max_num - 1];
+ /* Choose! */
+ if ( max_num == 0 || !get_com(
+ format("Examine which recipe?[%c-%c]", selectchar[0], ch)
+ , &ch))
+ {
+ break;
+ }
+
+ /* Analyze choice */
+ num = selectitem[(byte)ch];
+ }
+
+ if ( choice[num] < 0)
+ {
+ if (choice[num] < -1)
+ mod40--;
+ else
+ mod40++;
+ continue;
+ }
+
+ if ( num == 0xff || num >= max_num)
+ break;
+
+ /* Display the recipe */
+ if (choice[num] == 1)
+ alchemist_display_recipe(0, 0, choice2[num]);
+ else
+ alchemist_display_recipe(choice[num], choice2[num], 0);
+ }
+ /*
+ break is at top of loop, after essence list
+ if( num < 0 || num >= max_num)
+ break;
+ */
+
+ }/*show recipes*/
+
+ /* Restore screen contents */
+ Term_load();
+ character_icky = FALSE;
+}
+
+/* Display a list of known recipies that can be made with
+ * materials on hand (including the passed tval). Also
+ * calls the recipe_display function, if requested by the
+ * player or there aren't enough essences to make the
+ * requested object.
+ *
+ * Note: sval is ignored if !ego, tval is the only determinant
+ * of what recipies are available otherwise.
+ *
+ * This function needs to be able to scroll a list, because
+ * there are SO MANY potions. :)
+ */
+int alchemist_recipe_select(int *tval, int sval, int ego, bool_ recipe)
+{
+ int i, mod40 = 0, num, max_num = 0;
+
+ cptr tval_desc2 = "";
+ char ch;
+ bool_ done = FALSE;
+
+ int choice[60];
+ int validc[60];
+
+ char *string;
+
+
+ /* Save and clear the screen */
+ character_icky = TRUE;
+ Term_save();
+ Term_clear();
+
+ /* Base object type chosen, fill in tval */
+ for ( num = 0 ; num < 40 ; num ++)
+ if (tvals[num].tval == *tval)
+ {
+ tval_desc2 = tvals[num].desc;
+ }
+
+ while (!done)
+ {
+ Term_clear();
+ if (ego)
+ {
+ /* Find matching ego items */
+ for (num = 0, i = 1; (num < 40) && (i < max_e_idx) ; i++)
+ {
+ int j;
+ ego_item_type *e_ptr = &e_info[i];
+
+ /* Skip if unknown ego type */
+ if ( !(alchemist_known_egos[i / 32] & (1 << (i % 32))))
+ continue;
+
+ /* search in permitted tvals/svals for allowed egos */
+ for ( j = 0 ; j < 6 ; j ++ )
+ if ( e_ptr->tval[j] == *tval
+ && sval >= e_ptr->min_sval[j]
+ && sval <= e_ptr->max_sval[j])
+ {
+ int color = TERM_GREEN;
+
+ /*Reject if not opposite end of name
+ prefixes only on postfix egos,
+ postfixes only on prefix egos.
+ */
+ if (ego != -1 && e_ptr->before == e_info[ego].before)
+ continue;
+
+ /*Color it red of the alchemist doesn't have the essences to create it*/
+ if (!alchemist_items_check(*tval, 0, i, 0, TRUE))
+ color = TERM_RED;
+
+ /* add this ego to the list*/
+ strip_and_print(e_name + e_info[i].name, color, num);
+ validc[num] = color;
+ choice[num++] = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ char skipped = 0;
+ num = 0;
+ if (mod40 != 0)
+ {
+ strip_and_print("--MORE--", TERM_WHITE, num);
+ validc[num] = TERM_WHITE;
+ choice[num++] = -1;
+ }
+
+ for (i = 1; (num < 39) && (i < max_k_idx); i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+
+ /* Analyze matching items */
+ if (k_ptr->tval == *tval || (k_ptr->tval == TV_POTION2 && *tval == TV_POTION))
+ {
+ char color = TERM_GREEN;
+ /* Hack -- Skip instant artifacts */
+ if (k_ptr->flags3 & (TR3_INSTA_ART)) continue;
+
+ /*Don't display recipes that the alchemist doesn't know about*/
+ if (!k_ptr->know && !wizard) continue;
+
+ /*Skip recipes that are somehow known, but don't exist*/
+ if (!alchemist_exists(k_ptr->tval, k_ptr->sval, 0, 0))
+ continue;
+
+ /* Skip the first 39 if they hit 'more' */
+ if (skipped++ < mod40*39)
+ continue;
+
+ /* Color 'unable to create' items different */
+ if (!alchemist_items_check(k_ptr->tval, k_ptr->sval, 0, 0, TRUE))
+ color = TERM_RED;
+
+ /* Acquire the "name" of object "i" */
+ /* and print it in it's place */
+ strip_and_print(k_name + k_ptr->name, color, num);
+
+ /* Remember the object index */
+ validc[num] = color;
+ choice[num++] = i;
+ }
+ }
+ if (num == 39)
+ {
+ strip_and_print("--MORE--", TERM_WHITE, num);
+ validc[num] = TERM_WHITE;
+ choice[num++] = -1;
+ }
+ }
+
+ /* We need to know the maximal possible remembered object_index */
+ max_num = num;
+ string = "What Kind of %s? (* to see recipe) [%c-%c,*]";
+ num = 0xff;
+
+ /* Pretend they're all undoable if we where called to display recipes */
+ if (recipe)
+ {
+ for ( num = 0 ; num < max_num ; num++)
+ if (validc[num] != TERM_WHITE) validc[num] = TERM_RED;
+ string = "show which %s recipe? [%c-%c]";
+ }
+
+ while (num == 0xff || num >= max_num)
+ {
+ ch = selectchar[max_num - 1];
+ /* Choose! */
+ if ( max_num == 0 || !get_com(format(string, tval_desc2, selectchar[0], ch), &ch))
+ {
+ break;
+ }
+
+ /* Extra breaks for recipe */
+ if (recipe && (ch == '\r' || ch == ' ' || ch == ESCAPE ))
+ break;
+
+ /* Analyze choice */
+ num = selectitem[(byte)ch];
+
+ /* Pretend that we don't have enough essences for anything */
+ if (ch == '*' )
+ {
+ for ( num = 0 ; num < max_num ; num++)
+ if (validc[num] != TERM_WHITE) validc[num] = TERM_RED;
+ string = "Show which %s recipe? [%c-%c]";
+ }
+ }
+ if ( num == 0xff || max_num == 0 || num >= max_num)
+ break;
+
+ if ( validc[num] == TERM_WHITE )
+ {
+ if (num == 0)
+ mod40--;
+ else
+ mod40++;
+ if ( mod40 < 0)
+ mod40 = 0;
+ continue;
+ }
+
+ /* If we don't have enough essences, or user asked for recipes */
+ if ( validc[num] != TERM_GREEN )
+ {
+ /* Display the recipe */
+ if (ego)
+ alchemist_display_recipe(*tval, sval, choice[num]);
+ else
+ alchemist_display_recipe(k_info[choice[num]].tval, k_info[choice[num]].sval, 0);
+ }
+ else
+ done = TRUE;
+
+ }/*while(!done)*/
+
+ /* Restore screen contents */
+ Term_load();
+ character_icky = FALSE;
+
+ /* User abort, or no choices */
+ if (max_num == 0 || num == 0xff || num >= max_num)
+ {
+ if (max_num == 0)
+ msg_print("You don't know of anything you can make using that.");
+ return ( -1);
+ }
+ if ( validc[num] != TERM_GREEN )
+ return ( -1);
+
+ /* And return successful */
+ if ( ego )
+ return choice[num];
+
+ /* Set the tval, should be the same unless they selected a potion2 */
+ if (*tval != k_info[choice[num]].tval && *tval != TV_POTION)
+ msg_print("Coding error: tval != TV_POTION");
+ *tval = k_info[choice[num]].tval;
+ return ( k_info[choice[num]].sval );
+}
+
+/* Set the 'known' flags for all objects with a level <= lev
+ * This lets the budding alchemist create basic items.
+ */
+void alchemist_learn_all(int lev)
+{
+ int i;
+
+ if ( !get_skill(SKILL_ALCHEMY) )
+ return;
+
+ /* msg_format("You learn about level %d items",lev); */
+
+ for ( i = 0 ; i < max_k_idx ; i++ )
+ if ( k_info[i].level <= lev )
+ if (alchemist_exists(k_info[i].tval, k_info[i].sval, 0, 0))
+ k_info[i].know = TRUE;
+}
+
+void alchemist_learn_ego(int ego)
+{
+ char *name;
+ int i;
+
+ /* some Paranoia*/
+ if ( !ego || ego >= max_e_idx )
+ return;
+
+ /* Get the ego items name */
+ name = e_name + e_info[ego].name;
+ while (strchr(name, ' '))
+ name = strchr(name, ' ') + 1;
+
+ /* Don't learn about egos without recipes, and
+ * always learn about the passed ego item. */
+ if (alchemist_exists(0, 0, ego, 0))
+ {
+ alchemist_known_egos[ego / 32] |= (1 << (ego % 32));
+ /* msg_format("You learn about '%s' ego items.",e_name+e_info[ego].name); */
+ }
+ else
+ {
+ return;
+ }
+
+ /* Don't mass learn about egos that have no name. */
+ if ( name[0] == 0 )
+ {
+ return;
+ }
+
+ /* Look through all ego's for matching name */
+ /* Note that the original ego is marked here too */
+ for ( i = 0 ; i < max_e_idx ; i++ )
+ if ( strstr(e_name + e_info[i].name, name) != NULL /*Last word of name exists in this ego's name*/
+ && alchemist_exists(0, 0, i, 0) /*There exists a recipe for this*/
+ && !(alchemist_known_egos[i / 32] & (1 << (i % 32)) ) ) /*Not already known*/
+ /*&& (e_name+e_info[i].name)[0])non-blank name*/
+ {
+ alchemist_known_egos[i / 32] |= (1 << (i % 32));
+ /* msg_format("You learn about '%s' ego items.",e_name+e_info[i].name); */
+ }
+
+ return;
+}
+
+/* Alchemist has learned about a new item.
+ * Learn about not only it, but ALL egos with the
+ * same name.
+ */
+int alchemist_learn_object(object_type *o_ptr)
+{
+
+ /* Allow alchemist to create this item,
+ and.. learn about it even if the player
+ doesn't currently have the alchemy skill
+ */
+ k_info[o_ptr->k_idx].know = TRUE;
+
+ /* Not Paranoia, identify_fully calls this always */
+ if ( !get_skill(SKILL_ALCHEMY) )
+ return FALSE;
+
+ if ( artifact_p(o_ptr) )
+ {
+ char o_name[80];
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Randarts and normal artifacts both*/
+ alchemist_known_artifacts[0] |= f1;
+ alchemist_known_artifacts[1] |= f2;
+ alchemist_known_artifacts[2] |= f3;
+ alchemist_known_artifacts[3] |= f4;
+ alchemist_known_artifacts[4] |= f5;
+ alchemist_known_artifacts[5] |= esp;
+
+ object_desc(o_name, o_ptr, 1, 0);
+ msg_format("You learn all about the abilities of %s!", o_name);
+ }
+ if (o_ptr->name2)
+ alchemist_learn_ego(o_ptr->name2);
+
+ if (o_ptr->name2b)
+ alchemist_learn_ego(o_ptr->name2b);
+
+ return (TRUE);
+}
+
+/* Alchemist has gained a level - set the ego flags
+ * for all egos <= lev/4.
+ */
+void alchemist_gain_level(int lev)
+{
+ object_type forge;
+ object_type *o_ptr = &forge;
+
+ if ( lev == 0)
+ {
+ /* Learn about potions of Detonation */
+ k_info[417].know = TRUE;
+ }
+ if ( lev == 5)
+ {
+ int ego;
+ int egos[] = {
+ 7/*armor of resist fire*/
+ , 18/*shield of resist fire*/
+ , 74/*shocking weapon*/
+ , 75/*fiery weapon*/
+ , 76/*frozen weapon*/
+ , 77/*Venomous weapon*/
+ , 78/*Chaotic weapon*/
+ , 115/*projectile of venom*/
+ , 116/*projectile of Acid*/
+ , 122/*projectile of flame*/
+ , 123/*projectile of frost*/
+ , 137/*Lite of fearlessness*/
+ , 0 /*terminator*/
+ };
+ object_wipe(o_ptr);
+ /* learn about some basic ego items */
+ /* Note that this is just to get you started. */
+ for ( ego = 0 ; egos[ego] ; ego++)
+ {
+ o_ptr->name2 = egos[ego];
+ alchemist_learn_object(o_ptr);
+ }
+ msg_print("You recall your old master teaching you about elemental item infusing.");
+ }
+ if ( lev == 10)
+ {
+ /*For 'hard rooms' Players only, learn about diggers.*/
+ if (ironman_rooms)
+ {
+ msg_print("There's gotta be an easier way to get into all these vaults!");
+ object_wipe(o_ptr);
+ o_ptr->name2 = 101; /* Ego item, 'of digging' */
+ alchemist_learn_object(o_ptr);
+ }
+ }
+ if ( lev == 25)
+ {
+ msg_print("You recall your old master reminiscing about legendary infusings");
+ msg_print("and the Philosophers' stone.");
+
+ /* No auto-learn on artifacts - by this level, you'll have *ID*'d several */
+ }
+ if ( lev == 25)
+ {
+ msg_print("You wonder about shocking daggers of slay evil.");
+ }
+ if ( lev == 50)
+ {
+ /* learn about Temporary item creation */
+ /* Note that this is the ONLY way to learn this,
+ because spells which create a temporary item
+ also fully ID it. */
+ alchemist_known_artifacts[4] |= TR5_TEMPORARY;
+ msg_print("It suddenly occurs to you that artifacts don't *HAVE* to be permanent...");
+ }
+
+ /* Every Four Levels, learn about items that are
+ * less than that.
+ * Note that this isn't a significant effect after the
+ * first few levels, as the level at which you are learning
+ * things here quickly drops behind the level at which you
+ * are finding items.
+ */
+ if ( (lev & 0x3) != 0 )
+ return;
+ lev = (lev >> 2) + 1;
+ alchemist_learn_all(lev);
+
+}
+
+/* This, in combination with some code in loadsave.c,
+ insures that alchemist_gain_level is called EXACTLY
+ once with each possible value during the characters
+ lifetime.
+ */
+void alchemist_check_level()
+{
+ u32b lev = get_skill(SKILL_ALCHEMY);
+ if ( alchemist_gained > lev )
+ return;
+ /*Paranoia*/
+ if ( !lev )
+ return;
+ while ( alchemist_gained <= lev )
+ alchemist_gain_level(alchemist_gained++);
+}
+
+/*
+ * do_cmd_cast calls this function if the player's class
+ * is 'alchemist'.
+ */
+void do_cmd_alchemist(void)
+{
+ int item, ext = 0;
+ int value, basechance;
+ int askill;
+ bool_ repeat = 0;
+ char ch;
+
+ object_type *o_ptr, *q_ptr;
+ object_type forge, forge2;
+ byte carry_o_ptr = FALSE;
+
+ cptr q, s;
+
+ /* With the new skill system, we can no longer depend on
+ * check_exp to handle the changes and learning involved in
+ * gaining levels.
+ * So we'll have to check for it here.
+ */
+ alchemist_check_level();
+ askill = get_skill(SKILL_ALCHEMY);
+
+
+ q_ptr = &forge;
+
+ o_ptr = &p_ptr->inventory[INVEN_HANDS];
+ if ((o_ptr->tval != TV_GLOVES) || (o_ptr->sval != SV_SET_OF_LEATHER_GLOVES))
+ {
+ msg_print("You must wear gloves in order to do alchemy.");
+ return;
+ }
+
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ while (TRUE)
+ {
+ if (!get_com("[P]ower, [R]echarge or [L]eech an item, [E]xtract essences, or recipe [B]ook?", &ch))
+ {
+ ext = 0;
+ break;
+ }
+ if (ch == ' ' )
+ {
+ ext = 0;
+ break;
+ }
+ if (ch == 'P' || ch == 'p')
+ {
+ ext = 1;
+ break;
+ }
+ if (ch == 'E' || ch == 'e')
+ {
+ ext = 2;
+ break;
+ }
+ if (ch == 'R' || ch == 'r')
+ {
+ ext = 3;
+ break;
+ }
+ if (ch == 'L' || ch == 'l')
+ {
+ ext = 2;
+ repeat = 1;
+ break;
+ }
+ if (ch == 'B' || ch == 'b')
+ {
+ ext = 4;
+ break;
+ }
+ }
+
+ /**********Add a power*********/
+ if (ext == 1)
+ {
+ int i, qty, tval, sval = 0, ego = 0;
+ char o_name[200];
+
+ /* Get an item */
+ q = "Empower which item? ";
+ s = "You have no empowerable items.";
+ item_tester_hook = item_tester_hook_empower;
+
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Create an artifact from an ego or double ego item,
+ * from a previous artifact, or finish an artifact
+ */
+ if ((askill >= 25) && (artifact_p(o_ptr) || o_ptr->name2) && has_ability(AB_CREATE_ART))
+ {
+ if (get_check("Create an artifact?"))
+ {
+ do_cmd_toggle_artifact(o_ptr);
+ return;
+ }
+ /* Don't change artifacts or double ego items further */
+ else if (artifact_p(o_ptr) || (o_ptr->name2 && o_ptr->name2b))
+ return;
+ }
+ /*Ok, now we have the item, so we can now pick recipes.
+ Note: No recipe is known unless we have 'extracted' from
+ that object type. I.E. the 'know' flag (also greater identify)
+ is set.
+ */
+
+ /* Here we're not setting what kind of ego item it IS,
+ * where' just deciding that it CAN be an ego item */
+ if ( o_ptr->name2 ) /* creating a DUAL ego */
+ ego = TRUE;
+ if ( o_ptr->tval < 40 && o_ptr->tval != TV_BOTTLE)
+ ego = TRUE;
+ if ( o_ptr->tval == TV_ROD_MAIN || o_ptr->tval == TV_DAEMON_BOOK || o_ptr->tval == TV_BOOK)
+ ego = TRUE;
+
+ sval = o_ptr->sval;
+ if (!ego)
+ {
+ switch ( o_ptr->tval)
+ {
+ case TV_WAND:
+ sval = SV_WAND_NOTHING;
+ break;
+ case TV_RING:
+ sval = SV_RING_NOTHING;
+ break;
+ case TV_STAFF:
+ sval = SV_STAFF_NOTHING;
+ break;
+ case TV_BOTTLE:
+ sval = 1;
+ break;
+ case TV_AMULET:
+ sval = SV_AMULET_NOTHING;
+ break;
+ case TV_SCROLL:
+ sval = SV_SCROLL_NOTHING;
+ break;
+ case TV_ROD:
+ sval = SV_ROD_NOTHING;
+ break;
+ }
+ }
+ if ( o_ptr->sval != sval )
+ ego = TRUE;
+
+ tval = o_ptr->tval;
+ sval = o_ptr->sval;
+
+ /*HACK - bottles don't have the same tval as potions*/
+ /*Everything else will have the same tval after empowering*/
+ if (tval == TV_BOTTLE) tval = TV_POTION;
+ if (ego)
+ if (o_ptr->name2)
+ ego = alchemist_recipe_select(&tval, sval, o_ptr->name2, FALSE);
+ else
+ ego = alchemist_recipe_select(&tval, sval, -1, FALSE);
+ else
+ sval = alchemist_recipe_select(&tval, 0, 0, FALSE);
+
+ if ( sval < 0 || ego < 0)
+ return;
+
+ /* Check to make sure we have enough essences */
+ /* theoretically this is taken care of by recipe_select*/
+ /* but we'll double check just for paranoia. */
+ if (!alchemist_items_check(tval, sval, ego, 0, TRUE))
+ {
+ msg_print("You do not have enough essences.");
+ return;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Use up the essences */
+ (void)alchemist_items_check(tval, sval, ego, -1, TRUE);
+
+ /* Enchant stacks of ammunition at a time */
+ if ( o_ptr->tval == TV_SHOT || o_ptr->tval == TV_ARROW || o_ptr->tval == TV_BOLT )
+ {
+ qty = 1;
+ while (qty < o_ptr->number && alchemist_items_check(tval, sval, ego, -1, FALSE))
+ qty++;
+ }
+ else
+ qty = 1;
+
+ /* Copy the object */
+ q_ptr = &forge;
+ object_copy(q_ptr, o_ptr);
+
+ if ( o_ptr->tval == TV_WAND)
+ {
+ /* distribute charges on wands */
+ q_ptr->pval = o_ptr->pval / o_ptr->number;
+ o_ptr->pval -= q_ptr->pval;
+ }
+
+ o_ptr = q_ptr;
+ o_ptr->number = qty;
+ carry_o_ptr = TRUE;
+
+ /* Destroy the initial object */
+ inc_stack_size(item, -qty);
+
+
+ if ( ego )
+ {
+ int pval, pval2;
+ s32b pval3;
+
+ pval = o_ptr->pval;
+ pval2 = o_ptr->pval2;
+ pval3 = o_ptr->pval3;
+
+ if (o_ptr->name2)
+ o_ptr->name2b = ego;
+ else
+ o_ptr->name2 = ego;
+ o_ptr->pval = randint(e_info[ego].max_pval - 1) + 1;
+ /* dilemma - how to prevent creation of cursed items,
+ * without allowing the creation of artifacts?
+ * We can't, unless we want to finalize the ego flags ourselves.
+ */
+ apply_magic(o_ptr, askill * 2, FALSE, FALSE, FALSE);
+ /* Remember what the old pval was, so that we can re-apply it. */
+ if ( o_ptr->tval == TV_WAND
+ || o_ptr->tval == TV_RING
+ || o_ptr->tval == TV_AMULET
+ || o_ptr->tval == TV_STAFF)
+ {
+ o_ptr->pval = pval;
+ o_ptr->pval2 = pval2;
+ o_ptr->pval3 = pval3;
+ }
+ else if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ o_ptr->pval = pval;
+ }
+ else if ((o_ptr->tval == TV_BOOK) && (o_ptr->sval == 255))
+ {
+ o_ptr->pval = pval;
+ }
+ else if (o_ptr->tval == TV_SHOT
+ || o_ptr->tval == TV_ARROW
+ || o_ptr->tval == TV_BOLT)
+ {
+ o_ptr->pval2 = pval2;
+ }
+ else if (o_ptr->tval == TV_INSTRUMENT)
+ {
+ o_ptr->pval2 = pval2;
+ }
+
+ /* Calculate failure rate, lev=val/2500+5 */
+ value = MIN(e_info[o_ptr->name2].cost, 50000);
+ if (o_ptr->name2b) value += MIN(e_info[o_ptr->name2b].cost, 50000);
+ basechance = (value / 1000 + 5 - get_skill_scale(SKILL_ALCHEMY, 100) ) * 10;
+ if ( basechance < 0) basechance = 0;
+ if ( basechance > 100) basechance = 100;
+
+ value = object_value_real(o_ptr);
+
+ }
+ else /* not an ego item */
+ {
+ o_ptr = &forge;
+ object_wipe(o_ptr);
+ object_prep(o_ptr, lookup_kind(tval, sval));
+ hack_apply_magic_power = -99;
+ apply_magic(o_ptr, askill * 2, FALSE, FALSE, FALSE);
+ if ( o_ptr->tval == TV_WAND || o_ptr->tval == TV_STAFF)
+ o_ptr->pval = 0;
+ value = object_value_real(o_ptr);
+
+ basechance = k_info[o_ptr->k_idx].level - askill * 2;
+ basechance *= 10;
+
+ /* Can't fail more that 100% of the time... */
+ if (basechance > 100)
+ basechance = 100;
+ /* Always success in creation of potion of detonations */
+ if (o_ptr->tval == TV_POTION && o_ptr->sval == SV_POTION_DETONATIONS)
+ {
+ basechance /= 10;
+ }
+ }
+
+ /* Use up gold to create items */
+ /* this has the effect of making the alchemist
+ chronically short of funds, unless he finds the
+ philosopher's stone. It also means the easiest
+ things to make are 'bad', like a potion of
+ detonations...
+ */
+ /* Problem - to restrictive. We need something
+ which requires less money. But at the same time,
+ we don't want an 'easy cash' situation. Maybe something
+ like '10% * level difference', meaning at skill level 5,
+ level one items are free? But egos are frequently level
+ zero! Maybe egos are forced to level 25? with a cost ceiling?
+ I mean, Potions and scrolls are really the problem causing the
+ 'easy cash' situation, it's ego items. Ego items require
+ relatively few essences, and the rewards are HUGE. Most powerful
+ potions and scrolls require rare essences. Maybe force all egos
+ to require a magic essence? But then you'd get lots of magic
+ from distilling them. Maybe consumed in the creation? then when
+ you got a powerful item, you could make one ego item...
+ But if making things doesn't take gold, what about the cash
+ does the Philosopher's stone do?
+ Time*/
+
+ /* 0% failure if you have the stone */
+ if ( alchemist_has_stone())
+ basechance = 0;
+
+ if (basechance > 0 && value)
+ {
+ char string[80];
+ string[0] = '0';
+ string[1] = 0;
+
+ msg_format("The chance of success is only %d%%!", 100-basechance);
+ get_string("How much gold do you want to add?", string, 50);
+ i = atoi(string);
+ /* Note: don't trust the user to enter a positive number... */
+ if ( i < 0)
+ i = 0;
+ if ( i > p_ptr->au)
+ i = p_ptr->au;
+
+ if (i)
+ {
+ basechance = basechance - (i * 20) / value;
+ msg_format("The chance of success improved to %d%%.", 100-basechance);
+ }
+
+ if (randint(100) < basechance )
+ /*creation failed, even with the extra gold...*/
+ carry_o_ptr = FALSE;
+
+ /* Redraw gold */
+ p_ptr->au -= i;
+ p_ptr->redraw |= (PR_GOLD);
+ }
+
+ /* Set fully identified
+ * After all, the player just made it...
+ */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ o_ptr->ident |= IDENT_MENTAL;
+ o_ptr->found = OBJ_FOUND_SELFMADE;
+
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ if ( carry_o_ptr)
+ {
+ msg_format("You have successfully created %s %s",
+ (o_ptr->number > 1 ? "some" : (is_a_vowel(o_name[0]) ? "an" : "a")),
+ o_name);
+
+ if (inven_carry_okay(o_ptr))
+ inven_carry(o_ptr, FALSE);
+ else
+ {
+ drop_near(o_ptr, 0, p_ptr->py, p_ptr->px);
+ msg_format("You drop the %s", o_name);
+ }
+ carry_o_ptr = FALSE;
+ }
+ else /* don't carry, or in other words... */
+ {
+ int level = k_info[o_ptr->k_idx].level;
+ if (o_ptr->name1) /* created ego item */
+ level += e_info[o_ptr->name2].level;
+
+ msg_format("Your attempt backfires! Your %s explodes!", o_name);
+ take_hit(damroll(3, level - askill ) , "Alchemical Explosion");
+ p_ptr->redraw |= (PR_HP);
+ }
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Optimize the entire p_ptr->inventory - needed because we
+ don't know how many essences where used, and we may
+ have 'used up' a wielded item as well.
+ */
+ for ( item = 0 ; item < INVEN_TOTAL ; item++ )
+ inven_item_optimize(item);
+
+ /**********Extract a power*********/
+ }
+ else if (ext == 2)
+ {
+ int ego;
+ bool_ discharge_stick = FALSE;
+
+ /* s_ptr holds the empty items */
+ object_type *s_ptr = NULL;
+ bool_ carry_s_ptr = FALSE;
+
+ item_tester_hook = item_tester_hook_extractable;
+
+ /* Get an item */
+ q = "Extract from which item? ";
+ s = "You have no item to extract power from.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* This is to prevent creating magic essences by extracting
+ * from a recharged wand of dragon breath or something.
+ */
+ if (( o_ptr->tval == TV_WAND || o_ptr->tval == TV_STAFF )
+ && o_ptr->art_flags4 & TR4_RECHARGED)
+ {
+ msg_print("You cannot extract essences after it's been magically recharged.");
+ return;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Handle Rods before the loop, since they don't stack */
+ if (o_ptr->tval == TV_ROD_MAIN && o_ptr->pval != SV_ROD_NOTHING)
+ {
+ rod_tip_extract(o_ptr);
+ return;
+ }
+
+ do
+ { /* Repeat (for leech command) */
+
+ /* Create the items.
+ * we don't care if they drop to the ground,
+ * and if no action was taken, return
+ */
+ ego = 0;
+ if ( o_ptr->name2)
+ ego = o_ptr->name2;
+
+ /* For ego staves and wands (not of nothing), discharge before extracting the ego */
+ discharge_stick = (o_ptr->pval > 0 &&
+ ((o_ptr->tval == TV_STAFF && o_ptr->sval != SV_STAFF_NOTHING) ||
+ (o_ptr->tval == TV_WAND && o_ptr->sval != SV_WAND_NOTHING)));
+ if (discharge_stick)
+ ego = 0;
+
+ if (!alchemist_items_check(o_ptr->tval, o_ptr->sval, ego, 1, TRUE))
+ {
+ msg_print("You cannot extract anything from that item.");
+ return;
+ }
+
+ if (o_ptr->name2b && !alchemist_items_check(o_ptr->tval, o_ptr->sval, o_ptr->name2b, 1, TRUE))
+ {
+ /* do nothing - if the second ego can't be extracted
+ because there is no recipe for it, simply destroy it
+ */
+ }
+
+ /* Once in three times, learn how to make the item */
+ /* Sorry for the complicated if! Basically, if it's an
+ * unknown regular item or an unknown ego item, there's
+ * a one in 3 chance that it'll be id'd */
+ if (((!ego && !k_info[o_ptr->k_idx].know)
+ || (ego && !(alchemist_known_egos[ego / 32] & (1 << (ego % 32)))))
+ && randint(3) == 1)
+ {
+ msg_print("While destroying it, you gain insight into this item.");
+ /* If over level 10, the player has a chance of 'greater ID'
+ * on extracted items
+ */
+ if (askill > 9)
+ object_out_desc(o_ptr, NULL, FALSE, TRUE);
+ alchemist_learn_object(o_ptr);
+ }
+
+ /* Always learn what kind of thing it is */
+ object_known(o_ptr);
+ object_aware(o_ptr);
+
+ /* If it's a wand or staff with charges (but not of nothing),
+ * decrease number of charges, unstacking if needed.
+ * Otherwise, create the 'of nothing' item and destroy the old one.
+ */
+ if (discharge_stick)
+ {
+ /* Unstack staves */
+ if ((o_ptr->tval == TV_STAFF) && (o_ptr->number > 1))
+ {
+ /* Create one local copy of the staff */
+ q_ptr = &forge2;
+ object_copy(q_ptr, o_ptr);
+
+ /* Modify quantity */
+ q_ptr->number = 1;
+
+ /* Unstack the copied staff */
+ o_ptr->number--;
+
+ /* Use the local copy of the staff */
+ o_ptr = q_ptr;
+ carry_o_ptr = TRUE;
+ }
+ /* remove one charge */
+ o_ptr->pval--;
+ }
+ else
+ {
+ /* Create the empty, plain item */
+ /* If the item was already created, increase the number */
+ if (carry_s_ptr)
+ {
+ s_ptr->number++;
+ }
+ else
+ {
+ /* Otherwise we must create a local copy of the empty item */
+ int tval, sval;
+ bool_ create_item = TRUE;
+
+ tval = o_ptr->tval;
+ if ( !ego && (tval == TV_POTION || tval == TV_POTION2))
+ tval = TV_BOTTLE;
+
+ sval = o_ptr->sval;
+
+ if (!ego)
+ {
+ switch ( tval)
+ {
+ case TV_WAND:
+ sval = SV_WAND_NOTHING;
+ break;
+ case TV_RING:
+ sval = SV_RING_NOTHING;
+ break;
+ case TV_STAFF:
+ sval = SV_STAFF_NOTHING;
+ break;
+ case TV_BOTTLE:
+ sval = 1;
+ break;
+ case TV_AMULET:
+ sval = SV_AMULET_NOTHING;
+ break;
+ case TV_SCROLL:
+ sval = SV_SCROLL_NOTHING;
+ break;
+ case TV_ROD:
+ sval = SV_ROD_NOTHING;
+ break;
+ default:
+ create_item = FALSE;
+ }
+ }
+
+ if (create_item)
+ {
+ /* Create the empty item */
+ s_ptr = &forge;
+ object_wipe(s_ptr);
+ object_prep(s_ptr, lookup_kind(tval, sval));
+ s_ptr->number = 1;
+
+ /* Force creation of non ego non cursed */
+ hack_apply_magic_power = -99;
+ apply_magic(s_ptr, 0, FALSE, FALSE, FALSE);
+
+ /* Hack -- remove possible curse */
+ if (cursed_p(s_ptr))
+ {
+ s_ptr->art_flags3 &= ~(TR3_CURSED | TR3_HEAVY_CURSE);
+ s_ptr->ident &= ~(IDENT_CURSED);
+ }
+
+ /* Restore pvals (e.g. charges ==0) of the item */
+ if (ego && ((tval == TV_WAND) || (tval == TV_STAFF) ||
+ (tval == TV_RING) || (tval == TV_AMULET)))
+ {
+ s_ptr->pval = o_ptr->pval;
+ s_ptr->pval2 = o_ptr->pval2;
+ s_ptr->pval3 = o_ptr->pval3;
+ }
+ /* Restore the spell stored in a random book */
+ else if ((o_ptr->tval == TV_BOOK) && (o_ptr->sval == 255))
+ {
+ s_ptr->pval = o_ptr->pval;
+ }
+ /* Restore the type of explosive ammo */
+ else if (o_ptr->tval == TV_SHOT || o_ptr->tval == TV_ARROW
+ || o_ptr->tval == TV_BOLT)
+ {
+ s_ptr->pval2 = o_ptr->pval2;
+ }
+ /* Restore the music stored in an instrument */
+ else if (o_ptr->tval == TV_INSTRUMENT)
+ {
+ s_ptr->pval2 = o_ptr->pval2;
+ }
+
+ object_aware(s_ptr);
+ object_known(s_ptr);
+ s_ptr->ident |= IDENT_STOREB;
+
+ /* The empty item will be added to the p_ptr->inventory later */
+ carry_s_ptr = TRUE;
+ }
+ }
+
+ /* Now, we can delete the original (leeched) object.
+ * Is o_ptr an p_ptr->inventory / floor item or a local copy?
+ */
+ if (!carry_o_ptr)
+ {
+ /* Break the leech-loop if it was the last item */
+ if (o_ptr->number == 1)
+ repeat = 0;
+
+ inc_stack_size(item, -1);
+ }
+ else
+ {
+ /* Forget the local object */
+ carry_o_ptr = FALSE;
+
+ /* reset o_ptr to the original stack,
+ * which contains at least another item */
+ o_ptr = get_object(item);
+ }
+ }
+ }
+ while ( repeat == 1);
+
+ /* If we carry empty items, add them to the p_ptr->inventory */
+ if (carry_s_ptr)
+ inven_carry(s_ptr, TRUE);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /******* Recharge an item *******/
+ }
+ else if (ext == 3)
+ {
+ int item;
+
+ cptr q, s;
+
+ item_tester_hook = item_tester_hook_recharge;
+
+ /* Get an item */
+ q = "Recharge which item? ";
+ s = "You have no rechargable items.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR ))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Make sure we have enough essences to recharge this */
+ if (!alchemist_items_check(o_ptr->tval, o_ptr->sval, 0, 0, TRUE))
+ {
+ msg_print("You don't have the essences to recharge this item.");
+ return;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Destroy the essences */
+ (void)alchemist_items_check(o_ptr->tval, o_ptr->sval, 0, -1, TRUE);
+
+ if ((o_ptr->tval == TV_STAFF) && (o_ptr->number > 1))
+ {
+ /* Unstack staves */
+ /* Get local object */
+ q_ptr = &forge2;
+
+ /* Obtain a local object */
+ object_copy(q_ptr, o_ptr);
+
+ /* Modify quantity */
+ q_ptr->number = 1;
+
+ /* Unstack the used item */
+ o_ptr->number--;
+
+ o_ptr = q_ptr;
+ carry_o_ptr = TRUE;
+ }
+ o_ptr->pval++;
+ }
+ else if ( ext == 4)
+ {
+ alchemist_recipe_book();
+ }
+ /* Just in case - */
+ if (carry_o_ptr)
+ {
+ /* the o_ptr item was probably an unstacked staff
+ * Anyway, we need to add it to the p_ptr->inventory */
+ if (inven_carry_okay(o_ptr))
+ inven_carry(o_ptr, TRUE);
+ else
+ drop_near(o_ptr, 0, p_ptr->py, p_ptr->px);
+ }
+}
+
+
+/*
+ * Command to ask favors from your god.
+ */
+void do_cmd_pray(void)
+{
+ if (p_ptr->pgod == GOD_NONE)
+ {
+ msg_print("Pray hard enough and your prayers might be answered.");
+ return;
+ }
+ else
+ {
+ if (!p_ptr->praying)
+ msg_format("You start praying to %s.", deity_info[p_ptr->pgod].name);
+ else
+ msg_format("You stop praying to %s.", deity_info[p_ptr->pgod].name);
+ p_ptr->praying = !p_ptr->praying;
+
+ /* Update stuffs */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_POWERS |
+ PU_SANITY | PU_BODY);
+
+ p_ptr->redraw |= PR_PIETY | PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP;
+ energy_use = 100;
+ }
+}
+
+
+/*
+ * Return percentage chance of spell failure.
+ */
+int spell_chance_random(random_spell* rspell)
+{
+ int chance, minfail;
+
+
+ /* Extract the base spell failure rate */
+ chance = rspell->level + 10;
+
+ /* Reduce failure rate by "effective" level adjustment */
+ chance -= 3 * (get_skill(SKILL_THAUMATURGY) - rspell->level);
+
+ /* Reduce failure rate by INT/WIS adjustment */
+ chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[A_INT]] - 1);
+
+ /* Not enough mana to cast */
+ if (rspell->mana > p_ptr->csp)
+ {
+ chance += 5 * (rspell->mana - p_ptr->csp);
+ }
+
+ /* Extract the minimum failure rate */
+ minfail = adj_mag_fail[p_ptr->stat_ind[A_INT]];
+
+ /* Failure rate */
+ return clamp_failure_chance(chance, minfail);
+}
+
+
+
+
+/*
+ * Print a batch of spells.
+ */
+static void print_spell_batch(int batch, int max)
+{
+ char buff[80];
+
+ random_spell* rspell;
+
+ int i;
+
+
+ prt(format(" %-30s Lev Fail Mana Damage ", "Name"), 1, 20);
+
+ for (i = 0; i < max; i++)
+ {
+ rspell = &random_spells[batch * 10 + i];
+
+ if (rspell->untried)
+ {
+ strnfmt(buff, 80, " %c) %-30s (Spell untried) ",
+ I2A(i), rspell->name);
+
+ }
+ else
+ {
+ strnfmt(buff, 80, " %c) %-30s %3d %4d%% %3d %3dd%d ",
+ I2A(i), rspell->name,
+ rspell->level, spell_chance_random(rspell), rspell->mana,
+ rspell->dam_dice, rspell->dam_sides);
+ }
+
+ prt(buff, 2 + i, 20);
+ }
+
+ prt("", 2 + i, 20);
+}
+
+
+
+/*
+ * List ten random spells and ask to pick one.
+ */
+static random_spell* select_spell_from_batch(int batch, bool_ quick)
+{
+ char tmp[160];
+
+ char out_val[30];
+
+ char which;
+
+ int mut_max = 10;
+
+ random_spell* ret;
+
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ if (spell_num < (batch + 1) * 10)
+ {
+ mut_max = spell_num - batch * 10;
+ }
+
+ strnfmt(tmp, 160, "(a-%c, * to list, A-%cto browse, / to rename, - to comment) Select a power: ",
+ I2A(mut_max - 1), I2A(mut_max - 1) - 'a' + 'A');
+
+ prt(tmp, 0, 0);
+
+ if (quick)
+ {
+ print_spell_batch(batch, mut_max);
+ }
+
+ while (1)
+ {
+ /* Get a command */
+ which = inkey();
+
+ /* Abort */
+ if (which == ESCAPE)
+ {
+ /* No selection */
+ ret = NULL;
+
+ /* Leave the command loop */
+ break;
+
+ }
+
+ /* List */
+ if (which == '*' || which == '?' || which == ' ')
+ {
+ /* Print power list */
+ print_spell_batch(batch, mut_max);
+
+ /* Wait for next command */
+ continue;
+ }
+
+ /* Accept default */
+ if (which == '\r')
+ {
+ /* There are no other choices */
+ if (mut_max == 1)
+ {
+ ret = &random_spells[batch * 10];
+
+ /* Leave the command loop */
+ break;
+ }
+
+ /* Wait for next command */
+ continue;
+ }
+
+ /* Rename */
+ if (which == '/')
+ {
+ prt("Rename which power: ", 0, 0);
+ which = tolower(inkey());
+
+ if (isalpha(which) && (A2I(which) <= mut_max))
+ {
+ strcpy(out_val, random_spells[batch*10 + A2I(which)].name);
+ if (get_string("Name this power: ", out_val, 29))
+ {
+ strcpy(random_spells[batch*10 + A2I(which)].name, out_val);
+ }
+ prt(tmp, 0, 0);
+ }
+ else
+ {
+ bell();
+ prt(tmp, 0, 0);
+ }
+
+ /* Wait for next command */
+ continue;
+ }
+
+ /* Comment */
+ if (which == '-')
+ {
+ prt("Comment which power: ", 0, 0);
+ which = tolower(inkey());
+
+ if (isalpha(which) && (A2I(which) <= mut_max))
+ {
+ strcpy(out_val, random_spells[batch*10 + A2I(which)].desc);
+ if (get_string("Comment this power: ", out_val, 29))
+ {
+ strcpy(random_spells[batch*10 + A2I(which)].desc, out_val);
+ }
+ prt(tmp, 0, 0);
+ }
+ else
+ {
+ bell();
+ prt(tmp, 0, 0);
+ }
+
+ /* Wait for next command */
+ continue;
+ }
+
+ if (isalpha(which) && isupper(which))
+ {
+ which = tolower(which);
+ c_prt(TERM_L_BLUE, format("%s : %s", random_spells[batch*10 + A2I(which)].name, random_spells[batch*10 + A2I(which)].desc), 0, 0);
+ inkey();
+ prt(tmp, 0, 0);
+ continue;
+ }
+ else if (isalpha(which) && (A2I(which) < mut_max))
+ {
+ /* Pick the power */
+ ret = &random_spells[batch * 10 + A2I(which)];
+
+ /* Leave the command loop */
+ break;
+ }
+ else
+ {
+ bell();
+ }
+ }
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+
+ /* Return selection */
+ return (ret);
+}
+
+
+/*
+ * Pick a random spell from a menu
+ */
+random_spell* select_spell(bool_ quick)
+{
+ char tmp[160];
+
+ char which;
+
+ int batch_max = (spell_num - 1) / 10;
+
+ random_spell *ret;
+
+
+ /* Too confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You can't use your powers while confused!");
+ return NULL;
+ }
+
+ /* No spells available */
+ if (spell_num == 0)
+ {
+ msg_print("There are no spells you can cast.");
+ return NULL;
+ }
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ strnfmt(tmp, 160, "(a-%c) Select batch of powers: ", I2A(batch_max));
+
+ prt(tmp, 0, 0);
+
+ while (1)
+ {
+ which = inkey();
+
+ if (which == ESCAPE)
+ {
+ ret = NULL;
+
+ break;
+ }
+
+ if (which == '\r')
+ {
+ if (batch_max == 0)
+ {
+ ret = select_spell_from_batch(0, quick);
+
+ break;
+ }
+
+ continue;
+ }
+
+ which = tolower(which);
+ if (isalpha(which) && (A2I(which) <= batch_max))
+ {
+ ret = select_spell_from_batch(A2I(which), quick);
+
+ break;
+ }
+ else
+ {
+ bell();
+ }
+ }
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+
+ return (ret);
+}
+
+
+void do_cmd_powermage(void)
+{
+ random_spell *s_ptr;
+
+ u32b proj_flags;
+
+ int dir, chance;
+
+ int ty = 0, tx = 0;
+
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+
+ s_ptr = select_spell(FALSE);
+
+ if (s_ptr == NULL) return;
+
+ if (p_ptr->csp < s_ptr->mana)
+ {
+ msg_print("You do not have enough mana.");
+ return;
+ }
+
+ /* Spell failure chance */
+ chance = spell_chance_random(s_ptr);
+
+ /* Failed spell */
+ if (rand_int(100) < chance)
+ {
+ int insanity = (p_ptr->msane - p_ptr->csane) * 100 / p_ptr->msane;
+ char sfail[80];
+
+ /* Flush input if told so */
+ if (flush_failure) flush();
+
+ /* Insane players can see something strange */
+ if (rand_int(100) < insanity)
+ {
+ get_rnd_line("sfail.txt", sfail);
+ msg_format("A cloud of %s appears above you.", sfail);
+ }
+
+ /* Normal failure messages */
+ else
+ {
+ msg_print("You failed to get the spell off!");
+ }
+
+ sound(SOUND_FAIL);
+
+ /* Let time pass */
+ if (is_magestaff()) energy_use = 80;
+ else energy_use = 100;
+
+ /* Mana is spent anyway */
+ p_ptr->csp -= s_ptr->mana;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+
+ return;
+ }
+
+
+ p_ptr->csp -= s_ptr->mana;
+
+ s_ptr->untried = FALSE;
+ proj_flags = s_ptr->proj_flags;
+
+ /* Hack -- Spell needs a target */
+ if ((s_ptr->proj_flags & PROJECT_BEAM) ||
+ (s_ptr->proj_flags & PROJECT_STOP))
+ {
+ if (!get_aim_dir(&dir)) return;
+
+ /* Hack -- Use an actual "target" */
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+
+ /* Mega-Hack -- Beam spells should continue through
+ * the target; bolt spells should stop at the
+ * target. --dsb */
+ if (s_ptr->proj_flags & PROJECT_BEAM)
+ proj_flags |= PROJECT_THRU;
+ }
+ else
+ {
+ /* Use the given direction */
+ ty = p_ptr->py + ddy[dir];
+ tx = p_ptr->px + ddx[dir];
+
+ /* Mega-Hack -- Both beam and bolt spells should
+ * continue through this fake target. --dsb */
+ proj_flags |= PROJECT_THRU;
+ }
+ }
+
+ if (s_ptr->proj_flags & PROJECT_BLAST)
+ {
+ ty = p_ptr->py;
+ tx = p_ptr->px;
+ }
+
+ if (s_ptr->proj_flags & PROJECT_VIEWABLE)
+ {
+ project_hack(s_ptr->GF, damroll(s_ptr->dam_dice, s_ptr->dam_sides));
+ }
+ else if (s_ptr->proj_flags & PROJECT_METEOR_SHOWER)
+ {
+ project_meteor(s_ptr->radius, s_ptr->GF,
+ damroll(s_ptr->dam_dice, s_ptr->dam_sides),
+ s_ptr->proj_flags);
+ }
+ else
+ {
+ project(0, s_ptr->radius, ty, tx,
+ damroll(s_ptr->dam_dice, s_ptr->dam_sides),
+ s_ptr->GF, proj_flags);
+ }
+
+ /* Take a turn */
+ if (is_magestaff()) energy_use = 80;
+ else energy_use = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+}
+
+
+/*
+ * Brand some ammunition. Used by Cubragol and a mage spell. The spell was
+ * moved here from cmd6.c where it used to be for Cubragol only. I've also
+ * expanded it to do either frost, fire or venom, at random. -GJW -KMW-
+ */
+void brand_ammo(int brand_type, int bolts_only)
+{
+ int a;
+
+ for (a = 0; a < INVEN_PACK; a++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[a];
+
+ if (bolts_only && (o_ptr->tval != TV_BOLT)) continue;
+
+ if (!bolts_only && (o_ptr->tval != TV_BOLT) &&
+ (o_ptr->tval != TV_ARROW) && (o_ptr->tval != TV_SHOT))
+ continue;
+
+ if (!artifact_p(o_ptr) && !ego_item_p(o_ptr) &&
+ !cursed_p(o_ptr))
+ break;
+ }
+
+ /* Enchant the ammo (or fail) */
+ if ((a < INVEN_PACK) && (rand_int(100) < 50))
+ {
+ object_type *o_ptr = &p_ptr->inventory[a];
+ char *ammo_name;
+ char *aura_name;
+ char msg[48];
+ int aura_type, r;
+
+ /* fire only */
+ if (brand_type == 1) r = 0;
+
+ /* cold only */
+ else if (brand_type == 2) r = 99;
+
+ /* No bias */
+ else r = rand_int(100);
+
+ if (r < 50)
+ {
+ aura_name = "fiery";
+ aura_type = EGO_FLAME;
+ }
+ else
+ {
+ aura_name = "frosty";
+ aura_type = EGO_FROST;
+ }
+
+ if (o_ptr->tval == TV_BOLT)
+ {
+ ammo_name = "bolts";
+ }
+ else if (o_ptr->tval == TV_ARROW)
+ {
+ ammo_name = "arrows";
+ }
+ else
+ {
+ ammo_name = "shots";
+ }
+
+ strnfmt(msg, 48, "Your %s are covered in a %s aura!",
+ ammo_name, aura_name);
+ msg_print(msg);
+
+ o_ptr->name2 = aura_type;
+
+ /* Apply the ego */
+ apply_magic(o_ptr, dun_level, FALSE, FALSE, FALSE);
+ o_ptr->discount = 100;
+
+ enchant(o_ptr, rand_int(3) + 4, ENCH_TOHIT | ENCH_TODAM);
+ }
+ else
+ {
+ if (flush_failure) flush();
+ msg_print("The enchantment failed.");
+ }
+}
+
+
+/*
+ * From Kamband by Ivan Tkatchev
+ */
+void summon_monster(int sumtype)
+{
+ /* Take a turn */
+ energy_use = 100;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("This place seems devoid of life.");
+ msg_print(NULL);
+ return;
+ }
+
+ if (summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level + randint(5), sumtype, TRUE))
+ {
+ msg_print("You summon some help.");
+ }
+ else
+ {
+ msg_print("You called, but no help came.");
+ }
+}
+
+
+
+/*
+ * Use a class power of Possessor
+ */
+void do_cmd_possessor()
+{
+ char ch, ext;
+
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+
+ while (TRUE)
+ {
+ if (!get_com("Use your [R]ace powers or your [I]ncarnating powers?", &ch))
+ {
+ ext = 0;
+ break;
+ }
+ if ((ch == 'R') || (ch == 'r'))
+ {
+ ext = 1;
+ break;
+ }
+ if ((ch == 'I') || (ch == 'i'))
+ {
+ ext = 2;
+ break;
+ }
+ }
+
+ if (ext == 1)
+ {
+ bool_ use_great = FALSE;
+
+ if (p_ptr->disembodied)
+ {
+ msg_print("You don't currently own a body to use.");
+ return;
+ }
+
+ /* Do we have access to all the powers ? */
+ if (get_skill_scale(SKILL_POSSESSION, 100) >= r_info[p_ptr->body_monster].level)
+ use_great = TRUE;
+
+ use_symbiotic_power(p_ptr->body_monster, use_great, FALSE, FALSE);
+
+ if (p_ptr->csp < 0)
+ {
+ msg_print("You lose control of your body!");
+ if (!do_cmd_leave_body(FALSE))
+ {
+ cmsg_print(TERM_VIOLET,
+ "You are forced back into your body by your cursed items, "
+ "you suffer a system shock!");
+
+ p_ptr->chp = 1;
+
+ /* Display the hitpoints */
+ p_ptr->redraw |= (PR_HP);
+ }
+ }
+ }
+ else if (ext == 2)
+ {
+ if (p_ptr->disembodied)
+ {
+ do_cmd_integrate_body();
+ }
+ else
+ {
+ do_cmd_leave_body(TRUE);
+ }
+ }
+ else
+ {
+ return;
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+}
+
+
+/*
+ * Hook to determine if an object is contertible in an arrow/bolt
+ */
+static bool_ item_tester_hook_convertible(object_type *o_ptr)
+{
+ if ((o_ptr->tval == TV_JUNK) || (o_ptr->tval == TV_SKELETON)) return TRUE;
+
+ /* Assume not */
+ return (FALSE);
+}
+
+
+/*
+ * do_cmd_cast calls this function if the player's class
+ * is 'archer'.
+ */
+void do_cmd_archer(void)
+{
+ int ext = 0;
+ char ch;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ char com[80];
+
+
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ if (p_ptr->blind)
+ {
+ msg_print("You are blind!");
+ return;
+ }
+
+
+ if (get_skill(SKILL_ARCHERY) >= 20)
+ {
+ strnfmt(com, 80, "Create [S]hots, [A]rrows or [B]olts? ");
+ }
+ else if (get_skill(SKILL_ARCHERY) >= 10)
+ {
+ strnfmt(com, 80, "Create [S]hots or [A]rrows? ");
+ }
+ else
+ {
+ strnfmt(com, 80, "Create [S]hots? ");
+ }
+
+ while (TRUE)
+ {
+ if (!get_com(com, &ch))
+ {
+ ext = 0;
+ break;
+ }
+ if ((ch == 'S') || (ch == 's'))
+ {
+ ext = 1;
+ break;
+ }
+ if (((ch == 'A') || (ch == 'a')) && (get_skill(SKILL_ARCHERY) >= 10))
+ {
+ ext = 2;
+ break;
+ }
+ if (((ch == 'B') || (ch == 'b')) && (get_skill(SKILL_ARCHERY) >= 20))
+ {
+ ext = 3;
+ break;
+ }
+ }
+
+ /* Prepare for object creation */
+ q_ptr = &forge;
+
+ /**********Create shots*********/
+ if (ext == 1)
+ {
+ int x, y, dir;
+ cave_type *c_ptr;
+
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+ if (c_ptr->feat == FEAT_RUBBLE)
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Hack -- Give the player some shots */
+ object_prep(q_ptr, lookup_kind(TV_SHOT, m_bonus(2, dun_level)));
+ if (!artifact_p(q_ptr))
+ q_ptr->number = (byte)rand_range(15, 30);
+ else
+ q_ptr->number = 1;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_MENTAL;
+ apply_magic(q_ptr, dun_level, TRUE, TRUE, (magik(20)) ? TRUE : FALSE);
+ q_ptr->discount = 90;
+ q_ptr->found = OBJ_FOUND_SELFMADE;
+
+ (void)inven_carry(q_ptr, FALSE);
+
+ msg_print("You make some ammo.");
+
+ (void)wall_to_mud(dir);
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+ p_ptr->window |= (PW_OVERHEAD);
+ }
+ }
+
+ /**********Create arrows*********/
+ else if (ext == 2)
+ {
+ int item;
+
+ cptr q, s;
+
+ item_tester_hook = item_tester_hook_convertible;
+
+ /* Get an item */
+ q = "Convert which item? ";
+ s = "You have no item to convert.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Hack -- Give the player some arrows */
+ object_prep(q_ptr, lookup_kind(TV_ARROW, m_bonus(1, dun_level) + 1));
+ q_ptr->number = (byte)rand_range(15, 25);
+ if (!artifact_p(q_ptr))
+ q_ptr->number = (byte)rand_range(15, 30);
+ else
+ q_ptr->number = 1;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_MENTAL;
+ apply_magic(q_ptr, dun_level, TRUE, TRUE, (magik(20)) ? TRUE : FALSE);
+ q_ptr->discount = 90;
+ q_ptr->found = OBJ_FOUND_SELFMADE;
+
+ msg_print("You make some ammo.");
+
+ inc_stack_size(item, -1);
+
+ (void)inven_carry(q_ptr, FALSE);
+ }
+
+ /**********Create bolts*********/
+ else if (ext == 3)
+ {
+ int item;
+
+ cptr q, s;
+
+ item_tester_hook = item_tester_hook_convertible;
+
+ /* Get an item */
+ q = "Convert which item? ";
+ s = "You have no item to convert.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Hack -- Give the player some bolts */
+ object_prep(q_ptr, lookup_kind(TV_BOLT, m_bonus(1, dun_level) + 1));
+ q_ptr->number = (byte)rand_range(15, 25);
+ if (!artifact_p(q_ptr))
+ q_ptr->number = (byte)rand_range(15, 30);
+ else
+ q_ptr->number = 1;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_MENTAL;
+ apply_magic(q_ptr, dun_level, TRUE, TRUE, (magik(20)) ? TRUE : FALSE);
+ q_ptr->discount = 90;
+ q_ptr->found = OBJ_FOUND_SELFMADE;
+
+ msg_print("You make some ammo.");
+
+ inc_stack_size(item, -1);
+
+ (void)inven_carry(q_ptr, FALSE);
+ }
+}
+
+/*
+ * Control whether shots are allowed to pierce
+ */
+void do_cmd_set_piercing(void)
+{
+ char ch;
+ char com[80];
+
+ if ((get_skill(SKILL_BOW) <= 25) && (get_skill(SKILL_XBOW) <= 25) &&
+ (get_skill(SKILL_SLING) <= 25))
+ {
+ msg_print("You can't fire piercing shots yet.");
+ return;
+ }
+
+ strnfmt(com, 80, "Allow shots to pierce? ");
+
+ while (TRUE)
+ {
+ if (!get_com(com, &ch))
+ {
+ break;
+ }
+ if ((ch == 'Y') || (ch == 'y'))
+ {
+ p_ptr->use_piercing_shots = 1;
+ msg_print("Piercing shots activated.");
+ break;
+ }
+ if ((ch == 'N') || (ch == 'n'))
+ {
+ p_ptr->use_piercing_shots = 0;
+ msg_print("Piercing shots deactivated.");
+ break;
+ }
+ }
+}
+/*
+ * Helper function to describe necro powers
+ */
+void necro_info(char *p, int power)
+{
+ int plev = get_skill(SKILL_NECROMANCY);
+
+ strcpy(p, "");
+
+ switch (power)
+ {
+ case 0:
+ {
+ if (p_ptr->to_s)
+ strnfmt(p, 80, " power %dd%d+%d", 2 + (plev * 2 / 3), 4, (p_ptr->to_s * 2));
+ else
+ strnfmt(p, 80, " power %dd%d", 2 + (plev * 2 / 3), 4);
+ break;
+ }
+ case 2:
+ {
+ strnfmt(p, 80, " dur d%d+%d", 100 + (plev * 4), 200 + (plev * 3));
+ break;
+ }
+ case 3:
+ {
+ strnfmt(p, 80, " dur d%d+%d", 30 + (plev * 2), 50 + plev);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Cast a Necromancy spell
+ */
+void do_cmd_necromancer(void)
+{
+ int n = 0, b = 0;
+ int chance;
+ int dir;
+ int minfail = 0;
+ int plev = get_skill(SKILL_NECROMANCY);
+ magic_power spell;
+ int to_s2 = p_ptr->to_s / 2;
+ int mto_s2 = p_ptr->to_s / 2;
+
+
+ if (mto_s2 == 0) mto_s2 = 1;
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+ /* not if confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* get power */
+ if (!get_magic_power(&n, necro_powers, MAX_NECRO_POWERS, necro_info,
+ get_skill(SKILL_NECROMANCY), A_CON)) return;
+
+ spell = necro_powers[n];
+
+ /* Verify "dangerous" spells */
+ if (spell.mana_cost > p_ptr->csp)
+ {
+ /* Warning */
+ msg_print("You do not have enough mana to use this power.");
+
+ /* Verify */
+ if (!get_check("Attempt it anyway? ")) return;
+ }
+
+ /* Spell failure chance */
+ chance = spell.fail;
+
+ /* Reduce failure rate by "effective" level adjustment */
+ chance -= 3 * (plev - spell.min_lev);
+
+ /* Reduce failure rate by INT/WIS adjustment */
+ chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[A_CON]] - 1);
+
+ /* Not enough mana to cast */
+ if (spell.mana_cost > p_ptr->csp)
+ {
+ chance += 5 * (spell.mana_cost - p_ptr->csp);
+ }
+
+ /* Extract the minimum failure rate */
+ minfail = adj_mag_fail[p_ptr->stat_ind[A_CON]];
+
+ /* Failure rate */
+ chance = clamp_failure_chance(chance, minfail);
+
+ /* Failed spell */
+ if (rand_int(100) < chance)
+ {
+ if (flush_failure) flush();
+ msg_format("You failed to concentrate hard enough!");
+ sound(SOUND_FAIL);
+
+ if (randint(100) < (chance / 2))
+ {
+ /* Backfire */
+ b = randint(100);
+ if (b < 10)
+ {
+ msg_print("Oh, no! You become undead!");
+
+ p_ptr->necro_extra |= CLASS_UNDEAD;
+ p_ptr->necro_extra2 = 2 * plev;
+ msg_format("You have to kill %d monster%s to be brought back to life.",
+ p_ptr->necro_extra2,
+ (p_ptr->necro_extra2 == 1) ? "" : "s");
+
+ /* MEGA-HACK !!! */
+ calc_hitpoints();
+
+ /* Enforce maximum */
+ p_ptr->chp = p_ptr->mhp;
+ p_ptr->chp_frac = 0;
+
+ /* Display the hitpoints */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+ else if (b < 40)
+ {
+ msg_print("Suddenly you feel that you're in a bad situation...");
+ summon_specific(p_ptr->py, p_ptr->px, max_dlv[dungeon_type],
+ (plev >= 30) ? SUMMON_HI_UNDEAD : SUMMON_UNDEAD);
+ }
+ else
+ {
+ msg_print("Your body is damaged by the horrible forces of the spell!");
+ take_hit(damroll(5, plev), "using necromancy unwisely");
+ }
+ }
+ }
+ else
+ {
+ sound(SOUND_ZAP);
+
+ /* spell code */
+ switch (n)
+ {
+ /* Horrify */
+ case 0:
+ {
+ int dam = damroll(2 + (plev * 2 / 3), 4) + (p_ptr->to_s * 2);
+
+ if (plev > 45)
+ {
+ project_hack(GF_STUN, dam);
+ project_hack(GF_TURN_ALL, dam);
+ }
+ else if (plev > 35)
+ {
+ if (!get_aim_dir(&dir)) return;
+ fire_ball(GF_STUN, dir, dam, 3 + (plev / 10));
+ fire_ball(GF_TURN_ALL, dir, dam, 3 + (plev / 10));
+ }
+ else if (plev > 20)
+ {
+ if (!get_aim_dir(&dir)) return;
+ fire_beam(GF_STUN, dir, dam);
+ fire_beam(GF_TURN_ALL, dir, dam);
+ }
+ else
+ {
+ if (!get_aim_dir(&dir)) return;
+ fire_bolt(GF_STUN, dir, dam);
+ fire_bolt(GF_TURN_ALL, dir, dam);
+ }
+
+ break;
+ }
+
+ /* Raise Death */
+ case 1:
+ {
+ fire_ball(GF_RAISE, 0, plev * 3, 1 + to_s2 + (plev / 10));
+
+ break;
+ }
+
+ /* Conjures temporary weapon */
+ case 2:
+ {
+ int dur = randint(100 + (plev * 4)) + 200 + (plev * 3);
+ object_type forge, *o_ptr = &forge;
+ int k_idx = test_item_name("& Necromantic Teeth~");
+
+ k_allow_special[k_idx] = TRUE;
+
+ object_prep(o_ptr, k_idx);
+ apply_magic(o_ptr, plev * 2, TRUE, TRUE, TRUE);
+
+ o_ptr->art_flags5 |= TR5_TEMPORARY;
+ o_ptr->timeout = dur;
+
+ /* These objects are "storebought" */
+ o_ptr->ident |= IDENT_MENTAL;
+ o_ptr->number = 1;
+
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ (void)inven_carry(o_ptr, FALSE);
+
+ k_allow_special[k_idx] = FALSE;
+
+ break;
+ }
+
+ /* Absorb souls */
+ case 3:
+ {
+ set_absorb_soul(randint(30 + (plev * 2)) + 50 + plev);
+ break;
+ }
+
+ /* Vampirism */
+ case 4:
+ {
+ int i;
+ if (!get_aim_dir(&dir)) return;
+ for (i = 0; i < 1 + to_s2 + (plev / 15); i++)
+ {
+ if (drain_life(dir, 100))
+ hp_player(100);
+ }
+
+ break;
+ }
+
+ /* Death */
+ case 5:
+ {
+ if (get_check("Using the Death word will leave you undead, with 1 DP. Do you *really* want to use it? "))
+ {
+ if (!get_aim_dir(&dir)) return;
+ fire_bolt(GF_DEATH, dir, 1);
+
+ p_ptr->necro_extra |= CLASS_UNDEAD;
+ p_ptr->necro_extra2 = plev + (rand_int(plev / 2) - (plev / 4));
+ msg_format("You have to kill %d monster%s to be brought back to life.", p_ptr->necro_extra2, (p_ptr->necro_extra2 == 1) ? "" : "s");
+
+ /* MEGA-HACK !!! */
+ calc_hitpoints();
+
+ /* Enforce 1 DP */
+ p_ptr->chp = p_ptr->mhp;
+ p_ptr->chp_frac = 0;
+
+ /* Display the hitpoints */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+
+ break;
+ }
+
+ default:
+ {
+ msg_print("Zap?");
+
+ break;
+ }
+ }
+ }
+
+ /* Take a turn */
+ if (is_magestaff()) energy_use = 80;
+ else energy_use = 100;
+
+ /* Sufficient mana */
+ if (spell.mana_cost <= p_ptr->csp)
+ {
+ /* Use some mana */
+ p_ptr->csp -= spell.mana_cost;
+ }
+
+ /* Over-exert the player */
+ else
+ {
+ int oops = spell.mana_cost - p_ptr->csp;
+
+ /* No mana left */
+ p_ptr->csp = 0;
+ p_ptr->csp_frac = 0;
+
+ /* Message */
+ msg_print("You faint from the effort!");
+
+ /* Hack -- Bypass free action */
+ (void)set_paralyzed(p_ptr->paralyzed + randint(5 * oops + 1));
+
+ /* Damage CON (possibly permanently) */
+ if (rand_int(100) < 50)
+ {
+ bool_ perm = (rand_int(100) < 25);
+
+ /* Message */
+ msg_print("You have damaged your body!");
+
+ /* Reduce constitution */
+ (void)dec_stat(A_CON, 15 + randint(10), perm);
+ }
+ }
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+}
+
+/* Runecrafters -- Move this into variable.c XXX XXX XXX */
+static s32b rune_combine = 0;
+
+/*
+ * Hook to determine if an object is "runestone"
+ */
+static bool_ item_tester_hook_runestone(object_type *o_ptr)
+{
+ if (o_ptr->tval != TV_RUNE2) return (FALSE);
+
+ if (o_ptr->sval != RUNE_STONE) return (FALSE);
+
+ if (o_ptr->pval != 0) return (FALSE);
+
+ /* Assume yes */
+ return (TRUE);
+}
+
+
+static bool_ item_tester_hook_runestone_full(object_type *o_ptr)
+{
+ if (o_ptr->tval != TV_RUNE2) return (FALSE);
+
+ if (o_ptr->sval != RUNE_STONE) return (FALSE);
+
+ if (o_ptr->pval == 0) return (FALSE);
+
+ /* Assume yes */
+ return (TRUE);
+}
+
+
+/*
+ * Hook to determine if an object is "rune-able"
+ */
+static bool_ item_tester_hook_runeable1(object_type *o_ptr)
+{
+ if (o_ptr->tval != TV_RUNE1) return (FALSE);
+
+ /* Assume yes */
+ return (TRUE);
+}
+
+
+/*
+ * Hook to determine if an object is "rune-able"
+ */
+static bool_ item_tester_hook_runeable2(object_type *o_ptr)
+{
+ if (o_ptr->tval != TV_RUNE2) return (FALSE);
+
+ if (o_ptr->sval == RUNE_STONE) return (FALSE);
+
+ if (rune_combine & BIT(o_ptr->sval)) return (FALSE);
+
+ /* Assume yes */
+ return (TRUE);
+}
+
+
+/*
+ * math.h(sqrt) is banned of angband so ... :)
+ */
+s32b sroot(s32b n)
+{
+ s32b i = n / 2;
+
+ if (n < 2) return (n);
+
+ while (1)
+ {
+ s32b err = (i - n / (i + 1)) / 2;
+
+ if (!err) break;
+
+ i -= err;
+ }
+
+ return ((n / i < i) ? (i - 1) : i);
+}
+
+
+/*
+ * Damage formula, for runes
+ */
+void rune_calc_power(s32b *power, s32b *powerdiv)
+{
+ /* Not too weak power(paranoia) */
+ *power = (*power < 1) ? 1 : *power;
+ *power += 3;
+
+ *power = 37 * sroot(*power) / 10;
+
+ /* To reduce the high level power, while increasing the low levels */
+ *powerdiv = *power / 3;
+ if (*powerdiv < 1) *powerdiv = 1;
+
+ /* Use the spell multiplicator */
+ *power *= (p_ptr->to_s / 2) ? (p_ptr->to_s / 2) : 1;
+}
+
+
+/*
+ * Return percentage chance of runespell failure.
+ */
+int spell_chance_rune(rune_spell* spell)
+{
+ int chance, minfail;
+
+ s32b power = spell->mana, power_rune = 0, powerdiv = 0;
+
+
+ if (spell->rune2 & RUNE_POWER_SURGE)
+ {
+ power_rune += 4;
+ }
+ if (spell->rune2 & RUNE_ARMAGEDDON)
+ {
+ power_rune += 3;
+ }
+ if (spell->rune2 & RUNE_SPHERE)
+ {
+ power_rune += 2;
+ }
+ if (spell->rune2 & RUNE_RAY)
+ {
+ power_rune += 1;
+ }
+
+ rune_calc_power(&power, &powerdiv);
+
+ chance = (5 * power_rune) + (power);
+
+ /* Reduce failure rate by INT/WIS adjustment */
+ chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[A_DEX]] - 1);
+
+ /* Extract the minimum failure rate */
+ minfail = adj_mag_fail[p_ptr->stat_ind[A_DEX]];
+
+ /* Return the chance */
+ return clamp_failure_chance(chance, minfail);
+}
+
+
+/*
+ * Combine the Runes
+ */
+int rune_exec(rune_spell *spell, int cost)
+{
+ int dir, power_rune = 0, mana_used, plev = get_skill(SKILL_RUNECRAFT);
+
+ int chance;
+
+ s32b power, powerdiv;
+
+ int rad = 0, ty = -1, tx = -1, dam = 0, flg = 0;
+
+
+ if (spell->rune2 & RUNE_POWER_SURGE)
+ {
+ power_rune += 4;
+ }
+ if (spell->rune2 & RUNE_ARMAGEDDON)
+ {
+ power_rune += 3;
+ }
+ if (spell->rune2 & RUNE_SPHERE)
+ {
+ power_rune += 2;
+ }
+ if (spell->rune2 & RUNE_RAY)
+ {
+ power_rune += 1;
+ }
+
+
+ power = spell->mana;
+
+ if (cost && ((power * cost / 100) > p_ptr->csp - (power_rune * (plev / 5))))
+ {
+ power = p_ptr->csp - (power_rune * (plev / 5));
+ mana_used = power + (power_rune * (plev / 5));
+ }
+ else
+ {
+ mana_used = (power * cost / 100) + (power_rune * (plev / 5));
+ }
+
+ rune_calc_power(&power, &powerdiv);
+
+ dam = damroll(powerdiv, power);
+
+ if (wizard) msg_format("Rune %dd%d = dam %d", powerdiv, power, dam);
+
+ /* Extract the base spell failure rate */
+ chance = spell_chance_rune(spell);
+
+ /* Failure ? */
+ if (rand_int(100) < chance)
+ {
+ int insanity = (p_ptr->msane - p_ptr->csane) * 100 / p_ptr->msane;
+ char sfail[80];
+
+ /* Flush input if told so */
+ if (flush_failure) flush();
+
+ /* Insane players can see something strange */
+ if (rand_int(100) < insanity)
+ {
+ get_rnd_line("sfail.txt", sfail);
+ msg_format("A cloud of %s appears above you.", sfail);
+ }
+
+ /* Normal failure messages */
+ else
+ {
+ msg_print("You failed to get the spell off!");
+ }
+
+ sound(SOUND_FAIL);
+
+ if (is_magestaff()) energy_use = 80;
+ else energy_use = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+ return (mana_used);
+ }
+
+ if (spell->rune2 & RUNE_POWER_SURGE)
+ {
+ flg |= (PROJECT_VIEWABLE);
+ ty = p_ptr->py;
+ tx = p_ptr->px;
+ }
+
+ if (spell->rune2 & RUNE_ARMAGEDDON)
+ {
+ flg |= (PROJECT_THRU);
+ flg |= (PROJECT_KILL);
+ flg |= (PROJECT_ITEM);
+ flg |= (PROJECT_GRID);
+ flg |= (PROJECT_METEOR_SHOWER);
+ rad = (power / 8 == 0) ? 1 : power / 8;
+ rad = (rad > 10) ? 10 : rad;
+ ty = p_ptr->py;
+ tx = p_ptr->px;
+ }
+
+ if (spell->rune2 & RUNE_SPHERE)
+ {
+ flg |= (PROJECT_THRU);
+ flg |= (PROJECT_KILL);
+ flg |= (PROJECT_ITEM);
+ flg |= (PROJECT_GRID);
+ rad = (power / 8 == 0) ? 1 : power / 8;
+ rad = (rad > 10) ? 10 : rad;
+ ty = p_ptr->py;
+ tx = p_ptr->px;
+ }
+
+ if (spell->rune2 & RUNE_RAY)
+ {
+ flg |= (PROJECT_THRU);
+ flg |= (PROJECT_KILL);
+ flg |= (PROJECT_BEAM);
+ ty = -1;
+ tx = -1;
+ }
+ if (spell->rune2 & RUNE_ARROW)
+ {
+ flg |= (PROJECT_THRU);
+ flg |= (PROJECT_STOP);
+ flg |= (PROJECT_KILL);
+ ty = -1;
+ tx = -1;
+ }
+ if (spell->rune2 & RUNE_SELF)
+ {
+ flg |= (PROJECT_THRU);
+ flg |= (PROJECT_STOP);
+ flg |= (PROJECT_KILL);
+ ty = p_ptr->py;
+ tx = p_ptr->px;
+ unsafe = TRUE;
+ }
+
+ if ((ty == -1) && (tx == -1))
+ {
+ if (!get_aim_dir(&dir)) return (mana_used);
+
+ /* Use the given direction */
+ tx = p_ptr->px + ddx[dir];
+ ty = p_ptr->py + ddy[dir];
+
+ /* Hack -- Use an actual "target" */
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+ }
+ }
+
+ if (flg & PROJECT_VIEWABLE)
+ {
+ project_hack(spell->type, dam);
+ }
+ else if (flg & PROJECT_METEOR_SHOWER)
+ {
+ project_meteor(rad, spell->type, dam, flg);
+ }
+ else project(0, rad, ty, tx, dam, spell->type, flg);
+
+ if (unsafe) unsafe = FALSE;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+
+ return (mana_used);
+}
+
+
+/*
+ * Test if all runes needed at in the player p_ptr->inventory
+ */
+bool_ test_runespell(rune_spell *spell)
+{
+ int i;
+
+ object_type *o_ptr;
+
+ bool_ typeok = FALSE;
+
+ int rune2 = 0;
+
+
+ for (i = 0; i < INVEN_WIELD; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ if (!o_ptr->k_idx) continue;
+
+ /* Does the rune1(type) match ? */
+ if ((o_ptr->tval == TV_RUNE1) && (o_ptr->sval == spell->type))
+ {
+ typeok = TRUE;
+ }
+
+ if ((o_ptr->tval == TV_RUNE2) && (o_ptr->sval != RUNE_STONE))
+ {
+ /* Add it to the list */
+ rune2 |= 1 << o_ptr->sval;
+ }
+ }
+
+ /* Need all runes to be present */
+ return (typeok && ((rune2 & spell->rune2) == spell->rune2));
+}
+
+
+/*
+ * Ask for rune, rune2 and mana
+ */
+bool_ get_runespell(rune_spell *spell)
+{
+ int item, power_rune = 0, rune2 = 0, plev = get_skill(SKILL_RUNECRAFT);
+
+ s32b power;
+
+ int type = 0;
+
+ object_type *o_ptr;
+
+ cptr q, s;
+
+ bool_ OK = FALSE;
+
+
+ rune_combine = 0;
+
+ /* Restrict choices to unused runes */
+ item_tester_hook = item_tester_hook_runeable1;
+
+ /* Get an item */
+ q = "Use which rune? ";
+ s = "You have no rune to use.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return FALSE;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+ type = o_ptr->sval;
+
+ while (1)
+ {
+ /* Restrict choices to unused secondary runes */
+ item_tester_hook = item_tester_hook_runeable2;
+
+ OK = !get_item(&item, q, s, (USE_INVEN | USE_FLOOR));
+
+ if (OK) break;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ rune_combine |= 1 << o_ptr->sval;
+ rune2 |= 1 << o_ptr->sval;
+ }
+
+ if (!rune2)
+ {
+ msg_print("You have not selected a second rune!");
+ return (FALSE);
+ }
+
+ power = get_quantity("Which amount of Mana?",
+ p_ptr->csp - (power_rune * (plev / 5)));
+ if (power < 1) power = 1;
+
+ spell->mana = power;
+ spell->type = type;
+ spell->rune2 = rune2;
+
+ return (TRUE);
+}
+
+
+void do_cmd_rune(void)
+{
+ rune_spell spell;
+
+
+ /* Require some mana */
+ if (p_ptr->csp <= 0)
+ {
+ msg_print("You have no mana!");
+ return;
+ }
+
+ /* Require lite */
+ if (p_ptr->blind || no_lite())
+ {
+ msg_print("You cannot see!");
+ return;
+ }
+
+ /* Not when confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ if (!get_runespell(&spell)) return;
+
+ /* Execute at normal mana cost */
+ p_ptr->csp -= rune_exec(&spell, 100);
+
+ /* Safety :) */
+ if (p_ptr->csp < 0) p_ptr->csp = 0;
+
+ /* Take a turn */
+ if (is_magestaff()) energy_use = 80;
+ else energy_use = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+}
+
+
+/*
+ * Print a batch of runespells.
+ */
+static void print_runespell_batch(int batch, int max)
+{
+ char buff[80];
+
+ rune_spell* spell;
+
+ int i;
+
+ s32b power, powerdiv;
+
+ int p, dp;
+
+
+ prt(format(" %-30s Fail Mana Power", "Name"), 1, 20);
+
+ for (i = 0; i < max; i++)
+ {
+ spell = &rune_spells[batch * 10 + i];
+
+ power = spell->mana;
+ rune_calc_power(&power, &powerdiv);
+ p = power;
+ dp = powerdiv;
+
+ strnfmt(buff, 80, " %c) %-30s %4d%% %4d %dd%d ", I2A(i), spell->name,
+ spell_chance_rune(spell), spell->mana, dp, p);
+
+ prt(buff, 2 + i, 20);
+ }
+ prt("", 2 + i, 20);
+}
+
+
+
+/*
+ * List ten random spells and ask to pick one.
+ */
+
+static rune_spell* select_runespell_from_batch(int batch, bool_ quick,
+ int *s_idx)
+{
+ char tmp[160];
+
+ char out_val[30];
+
+ char which;
+
+ int mut_max = 10;
+
+ rune_spell* ret;
+
+
+ character_icky = TRUE;
+ Term_save();
+
+ if (rune_num < (batch + 1) * 10)
+ {
+ mut_max = rune_num - batch * 10;
+ }
+
+ strnfmt(tmp, 160, "(a-%c, * to list, / to rename, - to comment) Select a power: ",
+ I2A(mut_max - 1));
+
+ prt(tmp, 0, 0);
+
+ if (quick)
+ {
+ print_runespell_batch(batch, mut_max);
+ }
+
+ while (1)
+ {
+ which = inkey();
+
+ if (which == ESCAPE)
+ {
+ *s_idx = -1;
+ ret = NULL;
+ break;
+ }
+ else if ((which == '*') || (which == '?') || (which == ' '))
+ {
+ print_runespell_batch(batch, mut_max);
+ }
+ else if ((which == '\r') && (mut_max == 1))
+ {
+ *s_idx = batch * 10;
+ ret = &rune_spells[batch * 10];
+ break;
+ }
+ else if (which == '/')
+ {
+ prt("Rename which power: ", 0, 0);
+ which = tolower(inkey());
+
+ if (isalpha(which) && (A2I(which) <= mut_max))
+ {
+ strcpy(out_val, rune_spells[batch*10 + A2I(which)].name);
+ if (get_string("Name this power: ", out_val, 29))
+ {
+ strcpy(rune_spells[batch*10 + A2I(which)].name, out_val);
+ }
+ prt(tmp, 0, 0);
+ }
+ else
+ {
+ bell();
+ prt(tmp, 0, 0);
+ }
+ }
+ else
+ {
+ which = tolower(which);
+ if (isalpha(which) && (A2I(which) < mut_max))
+ {
+ *s_idx = batch * 10 + A2I(which);
+ ret = &rune_spells[batch * 10 + A2I(which)];
+ break;
+ }
+ else
+ {
+ bell();
+ }
+ }
+ }
+
+ Term_load();
+ character_icky = FALSE;
+
+ return (ret);
+}
+
+
+/*
+ * Pick a random spell from a menu
+ */
+
+rune_spell* select_runespell(bool_ quick, int *s_idx)
+{
+ char tmp[160];
+
+ char which;
+
+ int batch_max = (rune_num - 1) / 10;
+
+ if (rune_num == 0)
+ {
+ msg_print("There are no runespells you can cast.");
+ return (NULL);
+ }
+
+ character_icky = TRUE;
+ Term_save();
+
+ strnfmt(tmp, 160, "(a-%c) Select batch of powers: ", I2A(batch_max));
+
+ prt(tmp, 0, 0);
+
+ while (1)
+ {
+ which = inkey();
+
+ if (which == ESCAPE)
+ {
+ Term_load();
+ character_icky = FALSE;
+ return (NULL);
+ }
+ else if ((which == '\r') && (batch_max == 0))
+ {
+ Term_load();
+ character_icky = FALSE;
+ return (select_runespell_from_batch(0, quick, s_idx));
+
+ }
+ else
+ {
+ which = tolower(which);
+ if (isalpha(which) && (A2I(which) <= batch_max))
+ {
+ Term_load();
+ character_icky = FALSE;
+ return (select_runespell_from_batch(A2I(which), quick, s_idx));
+ }
+ else
+ {
+ bell();
+ }
+ }
+ }
+}
+
+
+/*
+ * Cast a memorized runespell
+ * Note that the only limits are antimagic & conf, NOT blind
+ */
+void do_cmd_rune_cast()
+{
+ rune_spell *s_ptr;
+
+ int s_idx;
+
+
+ /* Require some mana */
+ if (p_ptr->csp <= 0)
+ {
+ msg_print("You have no mana!");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+ /* Not when confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ s_ptr = select_runespell(FALSE, &s_idx);
+
+ if (s_ptr == NULL) return;
+
+ /* Need the runes */
+ if (!test_runespell(s_ptr))
+ {
+ msg_print("You lack some essential rune(s) for this runespell!");
+ return;
+ }
+
+ /* Execute at normal mana cost */
+ p_ptr->csp -= rune_exec(s_ptr, 100);
+
+ /* Safety :) */
+ if (p_ptr->csp < 0) p_ptr->csp = 0;
+
+ /* Take a turn */
+ if (is_magestaff()) energy_use = 80;
+ else energy_use = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+}
+
+
+/*
+ * Cast a runespell from a carved runestone
+ */
+void do_cmd_runestone()
+{
+ rune_spell s_ptr;
+
+ object_type *o_ptr;
+
+ cptr q, s;
+
+ int item;
+
+
+ /* Require some mana */
+ if (p_ptr->csp <= 0)
+ {
+ msg_print("You have no mana!");
+ return;
+ }
+
+ /* Require lite */
+ if (p_ptr->blind || no_lite())
+ {
+ msg_print("You cannot see!");
+ return;
+ }
+
+ /* Not when confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+ /* Restrict choices to unused runes */
+ item_tester_hook = item_tester_hook_runestone_full;
+
+ /* Get an item */
+ q = "Cast from which runestone? ";
+ s = "You have no runestone to cast from.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ s_ptr.type = o_ptr->pval;
+ s_ptr.rune2 = o_ptr->pval2;
+ s_ptr.mana = o_ptr->pval3;
+
+ /* Execute less mana */
+ p_ptr->csp -= rune_exec(&s_ptr, 75);
+
+ /* Safety :) */
+ if (p_ptr->csp < 0) p_ptr->csp = 0;
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+}
+
+
+/*
+ * Add a runespell to the list
+ */
+void do_cmd_rune_add_mem()
+{
+ rune_spell s_ptr;
+
+ rune_spell *ds_ptr = &rune_spells[rune_num];
+
+
+ /* Not when confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+
+ if (rune_num >= MAX_RUNES)
+ {
+ msg_print("You have already learn the maximun number of runespells!");
+ return;
+ }
+
+ if (!get_runespell(&s_ptr)) return;
+
+ ds_ptr->type = s_ptr.type;
+ ds_ptr->rune2 = s_ptr.rune2;
+ ds_ptr->mana = s_ptr.mana;
+ strcpy(ds_ptr->name, "Unnamed Runespell");
+
+ get_string("Name this runespell: ", ds_ptr->name, 29);
+
+ rune_num++;
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+}
+
+
+/*
+ * Carve a runespell onto a Runestone
+ */
+void do_cmd_rune_carve()
+{
+ rune_spell s_ptr;
+
+ object_type *o_ptr;
+
+ cptr q, s;
+
+ int item, i;
+
+ char out_val[80];
+
+
+ /* Not when confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* Require lite */
+ if (p_ptr->blind || no_lite())
+ {
+ msg_print("You cannot see!");
+ return;
+ }
+
+ if (!get_check("Beware, this will destroy the involved runes, continue?"))
+ {
+ return;
+ }
+
+ if (!get_runespell(&s_ptr)) return;
+
+ /* Restrict choices to unused runes */
+ item_tester_hook = item_tester_hook_runestone;
+
+ /* Get an item */
+ q = "Use which runestone? ";
+ s = "You have no runestone to use.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ o_ptr->pval = s_ptr.type;
+ o_ptr->pval2 = s_ptr.rune2;
+ o_ptr->pval3 = s_ptr.mana;
+
+ /* Start with nothing */
+ strcpy(out_val, "");
+
+ /* Use old inscription */
+ if (o_ptr->note)
+ {
+ /* Start with the old inscription */
+ strcpy(out_val, quark_str(o_ptr->note));
+ }
+
+ /* Get a new inscription (possibly empty) */
+ if (get_string("Name this runestone: ", out_val, 80))
+ {
+ /* Save the inscription */
+ o_ptr->note = quark_add(out_val);
+
+ /* Combine the pack */
+ p_ptr->notice |= (PN_COMBINE);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+ }
+
+ /* Delete the runes */
+ for (i = 0; i < INVEN_WIELD; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ if (o_ptr->k_idx)
+ {
+ bool_ do_del = FALSE;
+
+ if ((o_ptr->tval == TV_RUNE1) && (o_ptr->sval == s_ptr.type)) do_del = TRUE;
+ if ((o_ptr->tval == TV_RUNE2) && (BIT(o_ptr->sval) & s_ptr.rune2)) do_del = TRUE;
+
+ if (do_del)
+ {
+ inc_stack_size_ex(i, -1, OPTIMIZE, NO_DESCRIBE);
+ }
+ }
+ }
+
+ /* Take a turn -- Carving takes a LONG time */
+ energy_use = 400;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+}
+
+
+/*
+ * Remove a runespell
+ */
+void do_cmd_rune_del()
+{
+ rune_spell *s_ptr;
+
+ int s_idx;
+
+ int i;
+
+
+ /* Not when confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ s_ptr = select_runespell(FALSE, &s_idx);
+
+ if (s_ptr == NULL) return;
+
+ /* Delete and move */
+ for (i = s_idx + 1; i < rune_num; i++)
+ {
+ rune_spells[i - 1].type = rune_spells[i].type;
+ rune_spells[i - 1].rune2 = rune_spells[i].rune2;
+ rune_spells[i - 1].mana = rune_spells[i].mana;
+ strcpy(rune_spells[i - 1].name, rune_spells[i].name);
+ }
+ rune_num--;
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ p_ptr->redraw |= (PR_MANA);
+}
+
+
+void do_cmd_rune_add()
+{
+ int ext = 0;
+
+ char ch;
+
+
+ /* Select what to do */
+ while (TRUE)
+ {
+ if (!get_com("Add to [M]emory(need runes to cast) or "
+ "Carve a [R]unestone(less mana to cast)", &ch))
+ {
+ ext = 0;
+ break;
+ }
+ if ((ch == 'M') || (ch == 'm'))
+ {
+ ext = 1;
+ break;
+ }
+ if ((ch == 'R') || (ch == 'r'))
+ {
+ ext = 2;
+ break;
+ }
+ }
+
+ switch (ext)
+ {
+ /* Create a Spell in memory */
+ case 1:
+ {
+ do_cmd_rune_add_mem();
+ break;
+ }
+
+ /* Carve a Runestone */
+ case 2:
+ {
+ do_cmd_rune_carve();
+ break;
+ }
+ }
+}
+
+
+void do_cmd_runecrafter()
+{
+ int ext = 0;
+
+ char ch;
+
+
+ /* Select what to do */
+ while (TRUE)
+ {
+ if (!get_com("Rune Spell:[C]reate, [D]elete, C[a]st, D[i]rectly Cast "
+ "or Use [R]unestone", &ch))
+ {
+ ext = 0;
+ break;
+ }
+ if ((ch == 'C') || (ch == 'c'))
+ {
+ ext = 1;
+ break;
+ }
+ if ((ch == 'D') || (ch == 'd'))
+ {
+ ext = 2;
+ break;
+ }
+ if ((ch == 'A') || (ch == 'a'))
+ {
+ ext = 3;
+ break;
+ }
+ if ((ch == 'I') || (ch == 'i'))
+ {
+ ext = 4;
+ break;
+ }
+ if ((ch == 'R') || (ch == 'r'))
+ {
+ ext = 5;
+ break;
+ }
+ }
+
+ switch (ext)
+ {
+ /* Create a Spell */
+ case 1:
+ {
+ do_cmd_rune_add();
+ break;
+ }
+
+ /* Delete a Spell */
+ case 2:
+ {
+ do_cmd_rune_del();
+ break;
+ }
+
+ /* Cast a Spell */
+ case 3:
+ {
+ do_cmd_rune_cast();
+ break;
+ }
+
+ /* Directly Cast a Spell */
+ case 4:
+ {
+ do_cmd_rune();
+ break;
+ }
+
+ /* Cast a Runestone */
+ case 5:
+ {
+ do_cmd_runestone();
+ break;
+ }
+ }
+}
+
+
+void do_cmd_unbeliever_antimagic()
+{
+ if (get_skill(SKILL_ANTIMAGIC) < 20)
+ {
+ msg_print("You must have at least a level 20 antimagic skill "
+ "to be able to disrupt the magic continuum.");
+ return;
+ }
+
+ if (p_ptr->antimagic_extra & CLASS_ANTIMAGIC)
+ {
+ p_ptr->antimagic_extra &= ~CLASS_ANTIMAGIC;
+ msg_print("You stop disrupting the magic continuum.");
+ }
+ else
+ {
+ p_ptr->antimagic_extra |= CLASS_ANTIMAGIC;
+ msg_print("You start disrupting the magic continuum.");
+ }
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+}
+
+
+/*
+ * Detect traps + kill traps
+ */
+void do_cmd_unbeliever()
+{
+ int ext = 0;
+
+ char ch;
+
+
+ /* Select what to do */
+ while (TRUE)
+ {
+ if (!get_com("Disrupt [C]ontinuum or [D]etect Traps", &ch))
+ {
+ ext = 0;
+ break;
+ }
+ if ((ch == 'C') || (ch == 'c'))
+ {
+ ext = 1;
+ break;
+ }
+ if ((ch == 'D') || (ch == 'd'))
+ {
+ ext = 2;
+ break;
+ }
+ }
+
+ switch (ext)
+ {
+ /* Disrupt Continuum */
+ case 1:
+ {
+ do_cmd_unbeliever_antimagic();
+ break;
+ }
+
+ /* Detect Traps */
+ case 2:
+ {
+ s16b skill = get_skill(SKILL_ANTIMAGIC);
+
+ if (skill < 25)
+ {
+ msg_print("You cannot use your detection abilities yet.");
+ break;
+ }
+
+ detect_traps(DEFAULT_RADIUS);
+
+ if (skill >= 35) destroy_doors_touch();
+
+ break;
+ }
+ }
+}
+
+/*
+ * Hook to determine if an object is totemable
+ */
+static bool_ item_tester_hook_totemable(object_type *o_ptr)
+{
+ /* Only full corpse */
+ if ((o_ptr->tval == TV_CORPSE) &&
+ ((o_ptr->sval == SV_CORPSE_CORPSE) || (o_ptr->sval == SV_CORPSE_SKELETON)))
+ {
+ return (TRUE);
+ }
+
+ /* Assume not */
+ return (FALSE);
+}
+
+
+/*
+ * Summoners
+ */
+void do_cmd_summoner_extract()
+{
+ object_type *o_ptr, forge, *q_ptr;
+
+ cptr q, s;
+
+ int item, r;
+
+ bool_ partial;
+
+
+ /* Not when confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* Require lite */
+ if (p_ptr->blind || no_lite())
+ {
+ msg_print("You cannot see!");
+ return;
+ }
+
+ item_tester_hook = item_tester_hook_totemable;
+
+ /* Get an item */
+ q = "Use which corpse? ";
+ s = "You have no corpse to use.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+
+ if (r_info[o_ptr->pval2].flags1 & RF1_UNIQUE)
+ {
+ partial = FALSE;
+ }
+ else
+ {
+ partial = get_check("Do you want to create a partial totem?");
+ }
+
+ r = o_ptr->pval2;
+
+ inc_stack_size(item, -1);
+
+ if (magik(r_info[o_ptr->pval2].level - get_skill(SKILL_SUMMON)))
+ {
+ msg_print("You failed to extract a totem.");
+ energy_use += 100;
+ return;
+ }
+
+ /* Prepare for object creation */
+ q_ptr = &forge;
+
+ /* Create the object */
+ object_prep(q_ptr, lookup_kind(TV_TOTEM, partial ? 1 : 2));
+ q_ptr->pval = r;
+ q_ptr->pval2 = 0;
+ q_ptr->number = 1;
+ q_ptr->found = OBJ_FOUND_SELFMADE;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_MENTAL;
+ (void)inven_carry(q_ptr, FALSE);
+
+ msg_print("You extract a totem from the dead corpse.");
+ energy_use += 100;
+}
+
+
+void summon_true(int r_idx, int item)
+{
+ int i, status, x = 1, y = 1, rx, ry = 0, chance;
+
+ bool_ used;
+
+ monster_race *r_ptr = &r_info[r_idx];
+
+
+ /* Uniques are less likely to be nice */
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ /* Because it's unique, it will always be destroyed */
+ used = TRUE;
+
+ /* About twice as hard as non-uniques */
+ chance = (get_skill(SKILL_SUMMON) * 70 / (r_ptr->level + 1));
+
+ if (magik(chance))
+ {
+ status = MSTATUS_PET;
+ }
+ else
+ {
+ status = MSTATUS_ENEMY;
+ }
+ }
+
+ /* Non-uniques are easier to handle */
+ else
+ {
+ if (get_skill(SKILL_SUMMON) == 0)
+ {
+ used = TRUE;
+ }
+ else
+ {
+ /* It can be used multiple times */
+ used = FALSE;
+
+ /* But it is not 100% sure (note: skill > 0) */
+ chance = (r_ptr->level * 25 / get_skill(SKILL_SUMMON));
+ if (magik(chance)) used = TRUE;
+ }
+
+ chance = (get_skill(SKILL_SUMMON) * 130 / (r_ptr->level + 1));
+
+ if (magik(chance))
+ {
+ status = MSTATUS_PET;
+ }
+ else
+ {
+ status = MSTATUS_ENEMY;
+ }
+ }
+
+ /* Find a grid where the monster is summoned */
+ for (i = 0; i < 40; i++)
+ {
+ rx = (rand_int(8) - 4) + p_ptr->px;
+ ry = (rand_int(8) - 4) + p_ptr->py;
+ if (in_bounds(ry, rx) && cave_empty_bold(ry, rx))
+ {
+ x = rx;
+ y = ry;
+ break;
+ }
+ }
+
+ /* No room found */
+ if (i == 40)
+ {
+ msg_print("The summoning fails due to lack of room.");
+ return;
+ }
+
+ /* Summon the monster */
+ bypass_r_ptr_max_num = TRUE;
+ if (!(i = place_monster_one (y, x, r_idx, 0, 0, status)))
+ {
+ msg_print("The summoning fails.");
+ }
+ else
+ {
+ m_list[i].status = status;
+ m_list[i].mflag |= MFLAG_NO_DROP;
+ }
+ bypass_r_ptr_max_num = FALSE;
+
+ /* Destroy the totem if the used flag is set */
+ if (used)
+ {
+ /* Eliminate the totem */
+ inc_stack_size(item, -1);
+ }
+
+ /* Done */
+ return;
+}
+
+
+void do_cmd_summoner_summon()
+{
+ int item, x = 1, y = 1, rx, ry, m_idx = 0, i;
+
+ cptr q, s;
+
+ object_type *o_ptr;
+
+ monster_type *m_ptr;
+
+
+ /* Which Totem? */
+ item_tester_tval = TV_TOTEM;
+
+ q = "Summon from which Totem?";
+ s = "There are no totems to summon from!";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
+
+ /* Access the item */
+ o_ptr = get_object(item);
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* True Totems have their own function. */
+ if (o_ptr->sval == 2)
+ {
+ summon_true(o_ptr->pval, item);
+ return;
+ }
+
+ /* Handle partial totems */
+
+ /* Find a grid where the monster is summoned */
+ for (i = 0; i < 40; i++)
+ {
+ rx = (rand_int(8) - 4) + p_ptr->px;
+ ry = (rand_int(8) - 4) + p_ptr->py;
+ if (in_bounds(ry, rx) && cave_empty_bold(ry, rx))
+ {
+ x = rx;
+ y = ry;
+ break;
+ }
+ }
+
+ /* No room found */
+ if (i == 40)
+ {
+ msg_print("The summoning fails due to lack of room.");
+ return;
+ }
+
+ /* Summon the monster */
+ bypass_r_ptr_max_num = TRUE;
+ place_monster_one_no_drop = TRUE;
+ m_idx = place_monster_one(y, x, o_ptr->pval, 0, 0, MSTATUS_PET);
+ bypass_r_ptr_max_num = FALSE;
+
+ /* Failure. */
+ if (!m_idx)
+ {
+ msg_print("The summoning fails.");
+ }
+
+ /* Mark the monster as a "partial" ally */
+ m_ptr = &m_list[m_idx];
+ m_ptr->mflag |= MFLAG_PARTIAL | MFLAG_NO_DROP;
+}
+
+
+void do_cmd_summoner(void)
+{
+ int ext = 0;
+
+ char ch;
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+ /* not if confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* not if blind */
+ if (p_ptr->blind || no_lite())
+ {
+ msg_print("You cannot see!");
+ return;
+ }
+
+ /* Select what to do */
+ while (TRUE)
+ {
+ if (!get_com("[E]xtract a totem, [S]ummon", &ch))
+ {
+ ext = 0;
+ break;
+ }
+ if ((ch == 'E') || (ch == 'e'))
+ {
+ ext = 1;
+ break;
+ }
+ if ((ch == 's') || (ch == 'S'))
+ {
+ ext = 2;
+ break;
+ }
+ }
+
+ switch (ext)
+ {
+ case 1:
+ {
+ do_cmd_summoner_extract();
+ break;
+ }
+
+ case 2:
+ {
+ do_cmd_summoner_summon();
+ break;
+ }
+ }
+}
+
+
+/*
+ * Fighters may invoke The Rush.
+ */
+void do_cmd_blade(void)
+{
+ /* Are we already Rushed? */
+ if (p_ptr->rush)
+ {
+ msg_format("You have %d turns of The Rush remaining", p_ptr->rush);
+ return;
+ }
+
+ /* Are you sure? */
+ if (!get_check("Are you sure you want to invoke The Rush?")) return;
+
+ /* Let's Rush! */
+ set_rush(2 + p_ptr->lev / 2 + randint(p_ptr->lev / 2));
+}
+
+
+/*
+ * Dodge Chance Feedback.
+ */
+void use_ability_blade(void)
+{
+ int chance = p_ptr->dodge_chance - ((dun_level * 5) / 6);
+
+ if (chance < 0) chance = 0;
+ if (wizard)
+ {
+ msg_format("You have exactly %d chances of dodging a level %d monster.", chance, dun_level);
+ }
+
+ if (chance < 5)
+ {
+ msg_format("You have almost no chance of dodging a level %d monster.", dun_level);
+ }
+ else if (chance < 10)
+ {
+ msg_format("You have a slight chance of dodging a level %d monster.", dun_level);
+ }
+ else if (chance < 20)
+ {
+ msg_format("You have a significant chance of dodging a level %d monster.", dun_level);
+ }
+ else if (chance < 40)
+ {
+ msg_format("You have a large chance of dodging a level %d monster.", dun_level);
+ }
+ else if (chance < 70)
+ {
+ msg_format("You have a high chance of dodging a level %d monster.", dun_level);
+ }
+ else
+ {
+ msg_format("You will usually dodge successfully a level %d monster.", dun_level);
+ }
+
+ return;
+}
+
+/*
+ * Helper function to describe symbiotic powers
+ */
+void symbiotic_info(char *p, int power)
+{
+ int plev = get_skill(SKILL_SYMBIOTIC);
+
+ strcpy(p, "");
+
+ switch (power)
+ {
+ case 2:
+ {
+ strnfmt(p, 80, " power %d", plev * 3);
+ break;
+ }
+ case 5:
+ {
+ strnfmt(p, 80, " heal %d%%", 15 + get_skill_scale(SKILL_SYMBIOTIC, 35));
+ break;
+ }
+ }
+}
+
+
+/*
+ * Cast a symbiotic spell
+ */
+void do_cmd_symbiotic(void)
+{
+ int n = 0;
+ int chance;
+ int minfail = 0;
+ int plev = get_skill(SKILL_SYMBIOTIC);
+ magic_power spell;
+
+ /* Get the carried monster */
+ object_type *o_ptr = &p_ptr->inventory[INVEN_CARRY];
+
+ /* No magic */
+ if (p_ptr->antimagic)
+ {
+ msg_print("Your anti-magic field disrupts any magic attempts.");
+ return;
+ }
+
+ /* No magic */
+ if (p_ptr->anti_magic)
+ {
+ msg_print("Your anti-magic shell disrupts any magic attempts.");
+ return;
+ }
+
+ /* not if confused */
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* get power */
+ if (!get_magic_power(&n, symbiotic_powers, MAX_SYMBIOTIC_POWERS, symbiotic_info,
+ get_skill(SKILL_SYMBIOTIC), A_INT)) return;
+
+ spell = symbiotic_powers[n];
+
+ /* Verify "dangerous" spells */
+ if (spell.mana_cost > p_ptr->csp)
+ {
+ /* Warning */
+ msg_print("You do not have enough mana to use this power.");
+
+ /* Verify */
+ if (!get_check("Attempt it anyway? ")) return;
+ }
+
+ /* Spell failure chance */
+ chance = spell.fail;
+
+ /* Reduce failure rate by "effective" level adjustment */
+ chance -= 3 * (plev - spell.min_lev);
+
+ /* Reduce failure rate by INT/WIS adjustment */
+ chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[A_INT]] - 1);
+
+ /* Not enough mana to cast */
+ if (spell.mana_cost > p_ptr->csp)
+ {
+ chance += 5 * (spell.mana_cost - p_ptr->csp);
+ }
+
+ /* Extract the minimum failure rate */
+ minfail = adj_mag_fail[p_ptr->stat_ind[A_INT]];
+
+ /* Failure rate */
+ chance = clamp_failure_chance(chance, minfail);
+
+ /* Failed spell */
+ if (rand_int(100) < chance)
+ {
+ if (flush_failure) flush();
+ msg_format("You failed to concentrate hard enough!");
+ sound(SOUND_FAIL);
+ }
+ else
+ {
+ sound(SOUND_ZAP);
+
+ /* spell code */
+ switch (n)
+ {
+ case 0:
+ {
+ int dir, x, y;
+ cave_type *c_ptr;
+ monster_type *m_ptr;
+ monster_race *r_ptr;
+ object_type *q_ptr;
+ object_type forge;
+
+ msg_print("Hypnotise which pet?");
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+ if (c_ptr->m_idx)
+ {
+ m_ptr = &m_list[c_ptr->m_idx];
+ r_ptr = race_inf(m_ptr);
+
+ if (!(r_ptr->flags1 & RF1_NEVER_MOVE))
+ {
+ msg_print("You can only hypnotise monsters that cannot move.");
+ }
+ else if (m_ptr->status < MSTATUS_PET)
+ {
+ msg_print("You can only hypnotise pets and companions.");
+ }
+ else if (r_ptr->flags9 & RF9_SPECIAL_GENE)
+ {
+ msg_print("You cannot hypnotise this monster.");
+ }
+ else
+ {
+ /* TODO fix this hack hack hack hackity hack with ToME 3 flags */
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_HYPNOS, 1));
+ q_ptr->number = 1;
+ q_ptr->pval = m_ptr->r_idx;
+ q_ptr->pval2 = m_ptr->hp;
+ q_ptr->pval3 = m_ptr->maxhp;
+ /* overflow alert */
+ q_ptr->exp = m_ptr->exp;
+ q_ptr->elevel = m_ptr->level;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+
+ q_ptr->ident |= IDENT_STOREB;
+
+ drop_near(q_ptr, 0, y, x);
+
+ delete_monster(y, x);
+ health_who = 0;
+ }
+ }
+ else
+ {
+ msg_print("There is no pet here !");
+ }
+
+ break;
+ }
+
+ case 1:
+ {
+ monster_type *m_ptr;
+ int m_idx;
+ int item, x, y, d;
+ object_type *o_ptr;
+
+ cptr q, s;
+
+ /* Restrict choices to monsters */
+ item_tester_tval = TV_HYPNOS;
+
+ /* Get an item */
+ q = "Awaken which monster? ";
+ s = "You have no monster to awaken.";
+ if (!get_item(&item, q, s, (USE_FLOOR))) return;
+
+ o_ptr = &o_list[0 - item];
+
+ d = 2;
+ while (d < 100)
+ {
+ scatter(&y, &x, p_ptr->py, p_ptr->px, d);
+
+ if (cave_floor_bold(y, x) && (!cave[y][x].m_idx)) break;
+
+ d++;
+ }
+
+ if (d >= 100) return;
+
+ if ((m_idx = place_monster_one(y, x, o_ptr->pval, 0, FALSE, MSTATUS_PET)) == 0) return;
+
+ /* TODO fix this hack hack hack hackity hack with ToME 3 flags */
+ /* Have to be careful here; releasing the symbiote into a
+ * dungeon with leveled monsters will level the symbiote
+ * before we can get hold of it. We'll be nice and use the
+ * larger of the saved exp and the exp that the newly-generated
+ * monster starts with. */
+ m_ptr = &m_list[m_idx];
+ if (m_ptr->exp < o_ptr->exp)
+ {
+ m_ptr->exp = o_ptr->exp;
+ monster_check_experience(m_idx, TRUE);
+ if (m_ptr->level != o_ptr->elevel)
+ cmsg_format(TERM_VIOLET, "ERROR: level-%d HYPNOS becomes level-%d symbiote", o_ptr->elevel, m_ptr->level);
+ }
+ m_ptr->hp = o_ptr->pval2;
+ m_ptr->maxhp = o_ptr->pval3;
+
+ floor_item_increase(0 - item, -1);
+ floor_item_describe(0 - item);
+ floor_item_optimize(0 - item);
+ break;
+ }
+
+ /* Charm */
+ case 2:
+ {
+ int dir;
+
+ if (!get_aim_dir(&dir)) return;
+
+ fire_bolt(GF_CHARM_UNMOVING, dir, plev * 3);
+
+ break;
+ }
+
+ /* Life Share */
+ case 3:
+ {
+ s32b percent1, percent2;
+
+ if (!o_ptr->k_idx)
+ {
+ msg_print("You are not in symbiosis.");
+ break;
+ }
+
+ percent1 = p_ptr->chp;
+ percent1 = (percent1 * 100) / p_ptr->mhp;
+
+ percent2 = o_ptr->pval2;
+ percent2 = (percent2 * 100) / o_ptr->pval3;
+
+ /* Now get the average */
+ percent1 = (percent1 + percent2) / 2;
+
+ /* And set the hp of monster & player to it */
+ p_ptr->chp = (percent1 * p_ptr->mhp) / 100;
+ o_ptr->pval2 = (percent1 * o_ptr->pval3) / 100;
+
+ /* Redraw */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Display the monster hitpoints */
+ p_ptr->redraw |= (PR_MH);
+
+ break;
+ }
+
+ /* Minor Symbiotic Powers */
+ case 4:
+ {
+ if (!o_ptr->k_idx)
+ {
+ msg_print("You are not in symbiosis.");
+ break;
+ }
+
+ if (0 > use_symbiotic_power(o_ptr->pval, FALSE, FALSE, TRUE))
+ return;
+
+ break;
+ }
+
+ /* Heal Symbiote */
+ case 5:
+ {
+ int hp;
+
+ if (!o_ptr->k_idx)
+ {
+ msg_print("You are not in symbiosis.");
+ break;
+ }
+
+ hp = o_ptr->pval3 * (15 + get_skill_scale(SKILL_SYMBIOTIC, 35)) / 100;
+ o_ptr->pval2 += hp;
+ if (o_ptr->pval2 > o_ptr->pval3) o_ptr->pval2 = o_ptr->pval3;
+
+ msg_format("%s is healed.", symbiote_name(TRUE));
+
+ /* Display the monster hitpoints */
+ p_ptr->redraw |= (PR_MH);
+
+ break;
+ }
+
+
+ /* Major Symbiotic Powers */
+ case 6:
+ {
+ if (!o_ptr->k_idx)
+ {
+ msg_print("You are not in symbiosis.");
+ break;
+ }
+
+ if(0 > use_symbiotic_power(o_ptr->pval, TRUE, FALSE, TRUE))
+ return;
+
+ break;
+ }
+
+ /* Summon never-moving pet */
+ case 7:
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_MINE, FALSE);
+
+ break;
+ }
+
+ /* Force Symbiosis */
+ case 8:
+ {
+ int y, x;
+ cave_type *c_ptr;
+ monster_type *m_ptr;
+
+ if (!tgt_pt(&x, &y)) return;
+
+ c_ptr = &cave[y][x];
+
+ if (!c_ptr->m_idx) break;
+
+ m_ptr = &m_list[c_ptr->m_idx];
+ use_symbiotic_power(m_ptr->r_idx, TRUE, FALSE, TRUE);
+
+ break;
+ }
+
+
+ default:
+ {
+ msg_print("Zap?");
+
+ break;
+ }
+ }
+ }
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Sufficient mana */
+ if (spell.mana_cost <= p_ptr->csp)
+ {
+ /* Use some mana */
+ p_ptr->csp -= spell.mana_cost;
+ }
+
+ /* Over-exert the player */
+ else
+ {
+ int oops = spell.mana_cost - p_ptr->csp;
+
+ /* No mana left */
+ p_ptr->csp = 0;
+ p_ptr->csp_frac = 0;
+
+ /* Message */
+ msg_print("You faint from the effort!");
+
+ /* Hack -- Bypass free action */
+ (void)set_paralyzed(p_ptr->paralyzed + randint(5 * oops + 1));
+
+ /* Damage CON (possibly permanently) */
+ if (rand_int(100) < 50)
+ {
+ bool_ perm = (rand_int(100) < 25);
+
+ /* Message */
+ msg_print("You have damaged your body!");
+
+ /* Reduce constitution */
+ (void)dec_stat(A_CHR, 15 + randint(10), perm);
+ }
+ }
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+}
+
+/*
+ * Boulder creation .. sorry :)
+ */
+void do_cmd_create_boulder()
+{
+ int x, y, dir;
+ cave_type *c_ptr;
+
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+
+ /* Granite -- How about other wall types? */
+ if (((c_ptr->feat >= FEAT_WALL_EXTRA) && (c_ptr->feat <= FEAT_WALL_SOLID)) ||
+ ((c_ptr->feat >= FEAT_MAGMA_H) && (c_ptr->feat <= FEAT_QUARTZ_K)) ||
+ ((c_ptr->feat == FEAT_MAGMA) ||
+ (c_ptr->feat == FEAT_QUARTZ)))
+ {
+ object_type forge;
+ object_type *q_ptr;
+
+ (void)wall_to_mud(dir);
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Hack -- Give the player some shots */
+ object_prep(q_ptr, lookup_kind(TV_JUNK, SV_BOULDER));
+ q_ptr->number = (byte)rand_range(2, 5);
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_MENTAL;
+ q_ptr->discount = 90;
+ q_ptr->found = OBJ_FOUND_SELFMADE;
+
+ (void)inven_carry(q_ptr, FALSE);
+
+ msg_print("You make some boulders.");
+
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Take a turn */
+ energy_use = 100;
+ }
+}
+
+/*
+ * Clamp failure chance
+ */
+extern int clamp_failure_chance(int chance, int minfail)
+{
+ if (minfail < 0) minfail = 0;
+
+ /* Minimum failure rate */
+ if (chance < minfail) chance = minfail;
+
+ /* Stunning makes spells harder */
+ if (p_ptr->stun > 50) chance += 25;
+ else if (p_ptr->stun) chance += 15;
+
+ /* Always a 5 percent chance of working */
+ if (chance > 95) chance = 95;
+
+ return chance;
+}
diff --git a/src/cmovie.c b/src/cmovie.c
new file mode 100644
index 00000000..d1459e02
--- /dev/null
+++ b/src/cmovie.c
@@ -0,0 +1,496 @@
+/* File: cmovie.c */
+
+/* Purpose: play cmovie files -DarkGod-Improv- */
+
+#include "angband.h"
+
+/*
+ * Play a given cmovie
+ */
+s16b do_play_cmovie(cptr cmov_file)
+{
+ FILE *fff;
+
+ int y, line = 0, x;
+ int delay;
+
+ char *s;
+
+ char buf[1024];
+ char cbuf[90];
+ char ch;
+
+ char mode = 0;
+
+
+ /* Cmovie files are moved to the user directory on the multiuser systems */
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_CMOV, cmov_file);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Read the file */
+ fff = my_fopen(buf, "r");
+
+ /* Failure */
+ if (!fff) return ( -1);
+
+ /* Save screen */
+ character_icky = TRUE;
+ Term_save();
+ Term_clear();
+
+ /* Give some usefull info */
+ prt("While viewing the movie you can press Escape to exit, t/Space to switch between", 0, 0);
+ prt("fluid more and step by step mode and any other key to step a frame in step by", 1, 0);
+ prt("step mode.", 2, 0);
+ prt("You can press D to do an html screenshot of the current frame.", 3, 0);
+ prt("You can also use + and - to speed up/down the playing speed.", 5, 0);
+ prt("Press any key when ready.", 8, 0);
+
+ inkey();
+
+ Term_clear();
+
+ line = -1;
+
+ delay = 1;
+
+ /* Init to white */
+ for (x = 0; x < 80; x++)
+ {
+ cbuf[x] = 'w';
+ }
+
+ /* Parse */
+ while (0 == my_fgets(fff, buf, 1024))
+ {
+ /* Do not wait */
+ inkey_scan = TRUE;
+ ch = inkey();
+
+ /* Stop */
+ if (ch == ESCAPE) break;
+
+ /* Change mode */
+ else if (ch == 't')
+ {
+ mode = FALSE;
+ }
+ else if (ch == ' ')
+ {
+ mode = TRUE;
+ }
+
+ /* Change speed */
+ else if (ch == '+')
+ {
+ delay--;
+ if (delay < 0) delay = 0;
+ }
+ else if (ch == '-')
+ {
+ delay++;
+ if (delay > 5) delay = 5;
+ }
+ else if (ch == 'D')
+ {
+ do_cmd_html_dump();
+ }
+
+ line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') break;
+
+ /* Clean screen */
+ if (buf[0] == 'C')
+ {
+ Term_clear();
+
+ /* Next */
+ continue;
+ }
+
+ /* Displays a textbox */
+ if (buf[0] == 'B')
+ {
+ int len = strlen(buf + 2);
+
+ /* Clear the line */
+ Term_erase(0, 0, 255);
+
+ /* Display the message */
+ c_put_str(TERM_VIOLET, "###", 0, 0);
+ c_put_str(TERM_ORANGE, buf + 2, 0, 3);
+ c_put_str(TERM_VIOLET, "###", 0, 3 + len);
+ c_put_str(TERM_WHITE, "(more)", 0, 6 + len);
+
+ /* Next */
+ continue;
+ }
+
+ /* Wait a key */
+ if (buf[0] == 'W')
+ {
+ inkey();
+
+ /* Next */
+ continue;
+ }
+
+ /* Sleep */
+ if (buf[0] == 'S')
+ {
+ long msec;
+
+ /* Scan for the values */
+ if (1 != sscanf(buf + 2, "%ld:", &msec))
+ {
+ return ( -2);
+ }
+
+ if (!mode)
+ {
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ }
+ else
+ {
+ bool_ stop = FALSE;
+
+ while (TRUE)
+ {
+ ch = inkey();
+
+ /* Stop */
+ if (ch == ESCAPE)
+ {
+ stop = TRUE;
+ break;
+ }
+ /* Change mode */
+ else if (ch == 't')
+ {
+ mode = FALSE;
+ break;
+ }
+ /* Change mode */
+ else if (ch == ' ')
+ {
+ if (mode) continue;
+ mode = TRUE;
+ break;
+ }
+ /* Change speed */
+ else if (ch == '+')
+ {
+ delay--;
+ if (delay < 0) delay = 0;
+ }
+ else if (ch == '-')
+ {
+ delay++;
+ if (delay > 5) delay = 5;
+ }
+ else if (ch == 'D')
+ {
+ do_cmd_html_dump();
+ }
+ else break;
+ }
+ if (stop) break;
+ }
+
+ /* Next */
+ continue;
+ }
+
+ /* Get color for the NEXT L line */
+ if (buf[0] == 'E')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return ( -2);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return ( -2);
+
+ /* Get the index */
+ y = atoi(buf + 2);
+
+ C_COPY(cbuf, s, 80, char);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Print a line */
+ if (buf[0] == 'L')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return ( -2);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return ( -2);
+
+ /* Get the index */
+ y = atoi(buf + 2);
+
+ for (x = 0; x < 80; x++)
+ {
+ Term_putch(x, y, color_char_to_attr(cbuf[x]), s[x]);
+
+ /* Reinit to white */
+ cbuf[x] = 'w';
+ }
+ Term_redraw_section(0, y, 79, y);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Update 1 char */
+ if (buf[0] == 'P')
+ {
+ int x, y, a, c;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
+ &x, &y, &c, &a))
+ {
+ a = 'w';
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &x, &y, &c)) return ( -2);
+ }
+
+ Term_putch(x, y, color_char_to_attr(cbuf[x]), c);
+ Term_redraw_section(x, y, x + 1, y + 1);
+
+ /* Next... */
+ continue;
+ }
+ }
+
+ /* Load screen */
+ Term_load();
+ character_icky = FALSE;
+
+ /* Close */
+ my_fclose(fff);
+
+ return (0);
+}
+
+
+/*
+ * Start the recording of a cmovie
+ */
+void do_record_cmovie(cptr cmovie)
+{
+ char buf[1024];
+ int fd = -1;
+ int y;
+
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_CMOV, cmovie);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Check for existing file */
+ fd = fd_open(buf, O_RDONLY);
+
+ /* Existing file */
+ if (fd >= 0)
+ {
+ char out_val[160];
+
+ /* Close the file */
+ (void)fd_close(fd);
+
+ /* Build query */
+ (void)sprintf(out_val, "Replace existing file %s? ", cmovie);
+
+ /* Ask */
+ if (get_check(out_val)) fd = -1;
+ }
+
+ /* Be sure */
+ if (!get_check("Ready to record(Press ctrl+D to enter a textual note while recording)?")) return;
+
+ /* Open the non-existing file */
+ if (fd < 0) movfile = my_fopen(buf, "w");
+
+ /* Invalid file */
+ if (movfile == NULL)
+ {
+ msg_format("Cmovie recording failed!");
+
+ return;
+ }
+
+ /* First thing: Record clear screen then enable the recording */
+ fprintf(movfile, "# Generated by %s\n",
+ get_version_string());
+ fprintf(movfile, "C:\n");
+ last_paused = 0;
+ do_movies = 1;
+ cmovie_init_second();
+
+ /* Mega Hack, get the screen */
+ for (y = 0; y < Term->hgt; y++)
+ {
+ cmovie_record_line(y);
+ }
+}
+
+
+/*
+ * Stop the recording
+ */
+void do_stop_cmovie()
+{
+ if (do_movies == 1)
+ {
+ do_movies = 0;
+ my_fclose(movfile);
+ }
+}
+
+
+/*
+ * Start a cmovie
+ */
+void do_start_cmovie()
+{
+ char name[90], rname[94];
+
+
+ /* Should never happen */
+ if (do_movies == 1) return;
+
+ /* Default */
+ sprintf(name, "%s", player_base);
+
+ if (get_string("Cmovie name: ", name, 80))
+ {
+ if (name[0] && (name[0] != ' '))
+ {
+ sprintf(rname, "%s.cmv", name);
+
+ if (get_check("Record(y), Play(n)?")) do_record_cmovie(rname);
+ else do_play_cmovie(rname);
+ }
+ }
+}
+
+
+void cmovie_clean_line(int y, char *abuf, char *cbuf)
+{
+ const byte *ap = Term->scr->a[y];
+ const char *cp = Term->scr->c[y];
+
+ byte a;
+ char c;
+
+ int x;
+ int wid, hgt;
+ int screen_wid, screen_hgt;
+
+
+ /* Retrieve current screen size */
+ Term_get_size(&wid, &hgt);
+
+ /* Calculate the size of dungeon map area */
+ screen_wid = wid - (COL_MAP + 1);
+ screen_hgt = hgt - (ROW_MAP + 1);
+
+ /* For the time being, assume 80 column display XXX XXX XXX */
+ for (x = 0; x < wid; x++)
+ {
+ /* Convert dungeon map into default attr/chars */
+ if (!character_icky &&
+ ((x - COL_MAP) >= 0) &&
+ ((x - COL_MAP) < screen_wid) &&
+ ((y - ROW_MAP) >= 0) &&
+ ((y - ROW_MAP) < screen_hgt))
+ {
+ /* Retrieve default attr/char */
+ map_info_default(y + panel_row_prt, x + panel_col_prt, &a, &c);
+
+ abuf[x] = conv_color[a & 0xf];
+
+ if (c == '\0') cbuf[x] = ' ';
+ else cbuf[x] = c;
+ }
+
+ else
+ {
+ abuf[x] = conv_color[ap[x] & 0xf];
+ cbuf[x] = cp[x];
+ }
+ }
+
+ /* Null-terminate the prepared strings */
+ abuf[x] = '\0';
+ cbuf[x] = '\0';
+}
+
+
+/*
+ * Write a record of a screen row into a cmovie file
+ */
+void cmovie_record_line(int y)
+{
+ char abuf[256];
+ char cbuf[256];
+
+ cmovie_clean_line(y, abuf, cbuf);
+
+ /* Write a colour record */
+ fprintf(movfile, "E:%d:%.80s\n", y, abuf);
+
+ /* Write a char record */
+ fprintf(movfile, "L:%d:%.80s\n", y, cbuf);
+}
+
+
+/*
+ * Record a "text box"
+ */
+void do_cmovie_insert()
+{
+ char buf[81] = "";
+
+ /* Dont record */
+ do_movies = 2;
+
+ while (get_string("Textbox(ESC to end): ", buf, 80))
+ {
+ fprintf(movfile, "B:%s\nW:\n", buf);
+ buf[0] = '\0';
+ }
+
+ /* We reinit the time as to not count the time the user needed ot enter the text */
+ cmovie_init_second();
+
+ /* Continue recording */
+ do_movies = 1;
+}
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 00000000..c9f460e7
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,314 @@
+/* File: config.h */
+
+/* Purpose: Angband specific configuration stuff */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+
+/*
+ * Look through the following lines, and where a comment includes the
+ * tag "OPTION:", examine the associated "#define" statements, and decide
+ * whether you wish to keep, comment, or uncomment them. You should not
+ * have to modify any lines not indicated by "OPTION".
+ *
+ * Note: Also examine the "system" configuration file "h-config.h"
+ * and the variable initialization file "variable.c". If you change
+ * anything in "variable.c", you only need to recompile that file.
+ *
+ * And finally, remember that the "Makefile" will specify some rather
+ * important compile time options, like what visual module to use.
+ */
+
+
+/*
+ * OPTION: See the Makefile(s), where several options may be declared.
+ *
+ * Some popular options include "USE_GCU" (allow use with Unix "curses"),
+ * "USE_X11" (allow basic use with Unix X11) and "USE_XAW" (allow use with
+ * Unix X11 plus the Athena Widget set).
+ *
+ * The old "USE_NCU" option has been replaced with "USE_GCU".
+ *
+ * Several other such options are available for non-unix machines,
+ * such as "MACINTOSH", "WINDOWS".
+ *
+ * You may also need to specify the "system", using defines such as
+ * "SOLARIS" (for Solaris), etc, see "h-config.h" for more info.
+ */
+
+
+/*
+ * OPTION: define "SPECIAL_BSD" for using certain versions of UNIX
+ * that use the 4.4BSD Lite version of Curses in "main-gcu.c"
+ */
+/* #define SPECIAL_BSD */
+
+
+/*
+ * OPTION: Use the POSIX "termios" methods in "main-gcu.c"
+ */
+/* #define USE_TPOSIX */
+
+/*
+ * OPTION: Use the "termio" methods in "main-gcu.c"
+ */
+/* #define USE_TERMIO */
+
+/*
+ * OPTION: Use the icky BSD "tchars" methods in "main-gcu.c"
+ */
+/* #define USE_TCHARS */
+
+
+/*
+ * OPTION: Use "blocking getch() calls" in "main-gcu.c".
+ * Hack -- Note that this option will NOT work on many BSD machines
+ * Currently used whenever available, if you get a warning about
+ * "nodelay()" undefined, then make sure to undefine this.
+ */
+#if defined(SYS_V)
+# define USE_GETCH
+#endif
+
+
+/*
+ * OPTION: Use the "curs_set()" call in "main-gcu.c".
+ * Hack -- This option will not work on most BSD machines
+ */
+#ifdef SYS_V
+# define USE_CURS_SET
+#endif
+
+
+/*
+ * OPTION: Include "ncurses.h" instead of "curses.h" in "main-gcu.c"
+ */
+#define USE_NCURSES
+
+
+/*
+ * OPTION: for multi-user machines running the game setuid to some other
+ * user (like 'games') this SAFE_SETUID option allows the program to drop
+ * its privileges when saving files that allow for user specified pathnames.
+ * This lets the game be installed system wide without major security
+ * concerns. There should not be any side effects on any machines.
+ *
+ * This will handle "gids" correctly once the permissions are set right.
+ */
+#define SAFE_SETUID
+
+
+/*
+ * This flag enables the "POSIX" methods for "SAFE_SETUID".
+ */
+#if defined(_POSIX_SAVED_IDS) && !(defined(SUNOS) && !defined(SOLARIS)) && !defined(__APPLE__)
+# define SAFE_SETUID_POSIX
+#endif
+
+
+/*
+ * OPTION: Allow characteres to be "auto-rolled"
+ */
+#define ALLOW_AUTOROLLER
+
+
+/*
+ * OPTION: Allow monsters to "flee" when hit hard
+ */
+#define ALLOW_FEAR
+
+/*
+ * OPTION: Allow monsters to "flee" from strong players
+ */
+#define ALLOW_TERROR
+
+
+/*
+ * OPTION: Handle signals
+ */
+#define HANDLE_SIGNALS
+
+
+/*
+ * Allow "Wizards" to yield "high scores"
+ */
+/* #define SCORE_WIZARDS */
+
+/*
+ * Allow "Borgs" to yield "high scores"
+ */
+/*#define SCORE_BORGS*/
+
+/*
+ * Allow "Cheaters" to yield "high scores"
+ */
+/* #define SCORE_CHEATERS */
+
+
+
+/*
+ * OPTION: Maximum flow depth
+ */
+#define MONSTER_FLOW_DEPTH 32
+
+
+
+/*
+ * OPTION: Allow use of extended spell info -DRS-
+ */
+#define DRS_SHOW_SPELL_INFO
+
+/*
+ * OPTION: Allow use of the monster health bar -DRS-
+ */
+#define DRS_SHOW_HEALTH_BAR
+
+
+
+/*
+ * OPTION: Allow the use of "sound" in various places.
+ */
+#define USE_SOUND
+
+/*
+ * OPTION: Allow the use of "graphics" in various places
+ */
+#define USE_GRAPHICS
+
+
+/*
+ * OPTION: Hack -- Macintosh stuff
+ */
+#ifdef MACINTOSH
+
+/* Do not handle signals */
+# undef HANDLE_SIGNALS
+
+#endif
+
+
+/*
+ * OPTION: Hack -- Windows stuff
+ */
+#ifdef WINDOWS
+
+/* Do not handle signals */
+# undef HANDLE_SIGNALS
+
+#endif
+
+
+/*
+ * OPTION: Set the "default" path to the angband "lib" directory.
+ *
+ * See "main.c" for usage, and note that this value is only used on
+ * certain machines, primarily Unix machines. If this value is used,
+ * it will be over-ridden by the "ANGBAND_PATH" environment variable,
+ * if that variable is defined and accessable. The final slash is
+ * optional, but it may eventually be required.
+ *
+ * Using the value "./lib/" below tells Angband that, by default,
+ * the user will run "angband" from the same directory that contains
+ * the "lib" directory. This is a reasonable (but imperfect) default.
+ *
+ * If at all possible, you should change this value to refer to the
+ * actual location of the "lib" folder, for example, "/tmp/angband/lib/"
+ * or "/usr/games/lib/angband/", or "/pkg/angband/lib".
+ *
+ * Additional note -- if you are planning to use makefile.org, don't bother
+ * setting this variable, as it is overridden by a value set near the top of
+ * that file.
+ */
+#ifndef DEFAULT_PATH
+# define DEFAULT_PATH "/var/games/tome"
+#endif
+
+
+/*
+ * Where to put the user's files.
+ */
+#if defined(MACH_O_CARBON)
+#define PRIVATE_USER_PATH "~/Library/Application Support/ToME"
+#define PRIVATE_USER_PATH_DATA
+#define PRIVATE_USER_PATH_APEX
+#define PRIVATE_USER_PATH_MODULES
+#else
+#define PRIVATE_USER_PATH "~/.tome"
+#define PRIVATE_USER_PATH_APEX
+#endif
+
+/*
+ * OPTION: For some brain-dead computers with no command line interface,
+ * namely Macintosh, there has to be some way of "naming" your savefiles.
+ * The current "Macintosh" hack is to make it so whenever the character
+ * name changes, the savefile is renamed accordingly. But on normal
+ * machines, once you manage to "load" a savefile, it stays that way.
+ * Macintosh is particularly weird because you can load savefiles that
+ * are not contained in the "lib:save:" folder, and if you change the
+ * player's name, it will then save the savefile elsewhere.
+ */
+#if defined(MACINTOSH) || defined(WINDOWS)
+/* #define SAVEFILE_MUTABLE */
+#endif
+
+
+/*
+ * OPTION: Person to bother if something goes wrong.
+ */
+#define MAINTAINER "tome@packages.debian.org"
+
+
+/*
+ * OPTION: Default font (when using X11).
+ */
+#define DEFAULT_X11_FONT "9x15"
+
+/*
+ * OPTION: Default fonts (when using X11)
+ */
+#define DEFAULT_X11_FONT_SCREEN DEFAULT_X11_FONT
+#define DEFAULT_X11_FONT_MIRROR DEFAULT_X11_FONT
+#define DEFAULT_X11_FONT_RECALL DEFAULT_X11_FONT
+#define DEFAULT_X11_FONT_CHOICE DEFAULT_X11_FONT
+
+
+
+/* ToME options: */
+
+/* Should the player know his / her starting life rate? */
+#define SHOW_LIFE_RATE
+
+/* Allow hordes of 'similar' monsters */
+#define MONSTER_HORDES
+
+/* Wizard mode testing options: */
+
+/* For testing the vaults */
+/* # define FORCE_V_IDX 20 */
+
+/* Testing upkeep */
+/* # define TRACK_FRIENDS */
+
+/*
+ * Using the fast autoroller can be considered as cheating
+ */
+#define USE_FAST_AUTOROLLER
+
+/*
+ * Enable the CTRL + L command to quit without saving
+ * Only use for debugging purpose, otherwise you are a CHEATER
+ */
+/* #define ALLOW_QUITTING */
+
+/*
+ * Allow makefiles to override the default file mode
+ */
+#ifndef FILE_MODE
+#define FILE_MODE 0644
+#endif
diff --git a/src/defines.h b/src/defines.h
new file mode 100644
index 00000000..850bbc7a
--- /dev/null
+++ b/src/defines.h
@@ -0,0 +1,4695 @@
+/* File: defines.h */
+
+/* Purpose: global constants and macro definitions */
+
+
+/*
+ * Do not edit this file unless you know *exactly* what you are doing.
+ *
+ * Some of the values in this file were chosen to preserve game balance,
+ * while others are hard-coded based on the format of old save-files, the
+ * definition of arrays in various places, mathematical properties, fast
+ * computation, storage limits, or the format of external text files.
+ *
+ * Changing some of these values will induce crashes or memory errors or
+ * savefile mis-reads. Most of the comments in this file are meant as
+ * reminders, not complete descriptions, and even a complete knowledge
+ * of the source may not be sufficient to fully understand the effects
+ * of changing certain definitions.
+ *
+ * Lastly, note that the code does not always use the symbolic constants
+ * below, and sometimes uses various hard-coded values that may not even
+ * be defined in this file, but which may be related to definitions here.
+ * This is of course bad programming practice, but nobody is perfect...
+ *
+ * For example, there are MANY things that depend on the screen being
+ * 80x24, with the top line used for messages, the bottom line being
+ * used for status, and exactly 22 lines used to show the dungeon.
+ * Just because your screen can hold 46 lines does not mean that the
+ * game will work if you try to use 44 lines to show the dungeon.
+ *
+ * You have been warned.
+ */
+
+
+/*
+ * Release state, CVS or not, remember to switch it when making releases
+ */
+
+#ifndef IS_CVS
+#define IS_CVS " (ah)"
+/* #define IS_CVS " (ah, git)" */
+#endif
+
+#define USER_PATH_VERSION "/2.3"
+
+#define ANGBAND_2_8_1
+
+#define SAVEFILE_VERSION 104
+
+/*
+ * This value is not currently used
+ */
+#define VERSION_EXTRA 0
+
+/*
+ * Maximum amount of Angband windows.
+ */
+#define ANGBAND_TERM_MAX 8
+
+/*
+ * Number of grids in each block (vertically)
+ * Probably hard-coded to 11, see "generate.c"
+ */
+#define BLOCK_HGT 11
+
+/*
+ * Number of grids in each block (horizontally)
+ * Probably hard-coded to 11, see "generate.c"
+ */
+#define BLOCK_WID 11
+
+
+/*
+ * Number of grids in each panel (vertically)
+ * Must be a multiple of BLOCK_HGT
+ */
+#define PANEL_HGT 11
+
+/*
+ * Number of grids in each panel (horizontally)
+ * Must be a multiple of BLOCK_WID
+ */
+#define PANEL_WID 33
+
+
+/*
+ * Number of grids used to display the dungeon (vertically).
+ * Must be a multiple of 11, probably hard-coded to 22.
+ */
+#define SCREEN_HGT 22
+
+/*
+ * Number of grids used to display the dungeon (horizontally).
+ * Must be a multiple of 33, probably hard-coded to 66.
+ */
+#define SCREEN_WID 66
+
+
+/*
+ * Maximum dungeon height in grids, must be a multiple of SCREEN_HGT,
+ * probably hard-coded to SCREEN_HGT * 3.
+ */
+#define MAX_HGT 66
+
+/*
+ * Maximum dungeon width in grids, must be a multiple of SCREEN_WID,
+ * probably hard-coded to SCREEN_WID * 3.
+ */
+#define MAX_WID 198
+
+/* Used only in object3.c / trap effects */
+#if ((MAX_HGT / SCREEN_HGT) < (MAX_WID / SCREEN_WID))
+ #define RATIO (MAX_WID / SCREEN_WID)
+#else
+ #define RATIO (MAX_HGT / SCREEN_HGT)
+#endif
+
+/*
+ * Default radius of detection spells
+ * Its area must be at least as large as SCREEN_WID * SCREEN_HGT
+ */
+#define DEFAULT_RADIUS 25
+
+
+#define CHANCE_TRAP_JAMMED_DOOR 2500
+#define CHANCE_TRAP_SECRET_DOOR 1500
+#define CHANCE_TRAP_LOCKED_DOOR 1000
+#define CHANCE_TRAP_DOOR 500 /* in 10000 */
+#define CHANCE_TRAP_FLOOR 4 /* in 10000 chance of placing a trap */
+
+#define MAX_BOUNTIES 24
+
+#define MAX_SPELLS 100
+#define MAX_RUNES 100
+
+/*
+ * Arena constants
+ */
+#define MAX_ARENA_MONS 29 /* -KMW- */
+
+/*
+ * Total number of stores (see "store.c", etc)
+ */
+#define STORE_GENERAL 0
+#define STORE_ARMOURY 1
+#define STORE_WEAPON 2
+#define STORE_TEMPLE 3
+#define STORE_ALCHEMIST 4
+#define STORE_MAGIC 5
+#define STORE_BLACK 6
+#define STORE_HOME 7
+#define STORE_BOOK 8
+#define STORE_PET 9
+
+/*
+ * Maximum number of player "sex" types (see "table.c", etc)
+ */
+#define MAX_SEXES 3
+
+/* The number of "patrons" available (for Chaos Warriors) */
+#define MAX_PATRON 16
+
+/* Number of Random Artifacts */
+#define MAX_RANDARTS 84
+#define MAX_T_ACT 51
+
+/* Chaos Warrior: Reward types: */
+#define REW_POLY_SLF 0
+#define REW_GAIN_EXP 1
+#define REW_LOSE_EXP 2
+#define REW_GOOD_OBJ 3
+#define REW_GREA_OBJ 4
+#define REW_CHAOS_WP 5
+#define REW_GOOD_OBS 6
+#define REW_GREA_OBS 7
+#define REW_TY_CURSE 8
+#define REW_SUMMON_M 9
+#define REW_H_SUMMON 10
+#define REW_DO_HAVOC 11
+#define REW_GAIN_ABL 12
+#define REW_LOSE_ABL 13
+#define REW_RUIN_ABL 14
+#define REW_AUGM_ABL 15
+#define REW_POLY_WND 16
+#define REW_HEAL_FUL 17
+#define REW_HURT_LOT 18
+#define REW_CURSE_WP 19
+#define REW_CURSE_AR 20
+#define REW_PISS_OFF 21
+#define REW_WRATH 22
+#define REW_DESTRUCT 23
+#define REW_GENOCIDE 24
+#define REW_MASS_GEN 25
+#define REW_DISPEL_C 26
+#define REW_UNUSED_1 27
+#define REW_UNUSED_2 28
+#define REW_UNUSED_3 29
+#define REW_UNUSED_4 30
+#define REW_UNUSED_5 31
+#define REW_IGNORE 32
+#define REW_SER_UNDE 33
+#define REW_SER_DEMO 34
+#define REW_SER_MONS 35
+
+
+/* bear barehanded attacks ... */
+#define MAX_BEAR 8
+
+/* Monk martial arts... */
+#define MAX_MA 17
+
+#define MA_KNEE 0x0001
+#define MA_SLOW 0x0002
+#define MA_WOUND 0x0004
+#define MA_STUN 0x0008
+#define MA_FULL_SLOW 0x0010
+
+/* Mindcraft */
+#define MAX_MINDCRAFT_POWERS 12
+
+/* Necromancy */
+#define MAX_NECRO_POWERS 6
+
+/* Mimicry */
+#define MAX_MIMIC_POWERS 5
+
+/* Symbiosis */
+#define MAX_SYMBIOTIC_POWERS 9
+
+
+/* A hack for cave.c */
+#define BMP_FIRST_PC_CLASS 164
+#define BMP_FIRST_PC_RACE 128
+
+
+/*
+ * Size of memory reserved for initialization of some arrays
+ */
+#define FAKE_NAME_SIZE 40 * 1024L
+#define FAKE_TEXT_SIZE 120 * 1024L
+
+
+/*
+ * Maximum number of high scores in the high score file
+ */
+#define MAX_HISCORES 100
+
+
+/*
+ * Maximum dungeon level. The player can never reach this level
+ * in the dungeon, and this value is used for various calculations
+ * involving object and monster creation. It must be at least 100.
+ * Setting it below 128 may prevent the creation of some objects.
+ */
+#define MAX_DEPTH 128
+#define MAX_DEPTH_MONSTER 200
+
+
+/*
+ * Maximum size of the "lite" array (see "cave.c")
+ * Note that the "lite radius" will NEVER exceed 5, and even if the "lite"
+ * was rectangular, we would never require more than 128 entries in the array.
+ */
+#define LITE_MAX 1536
+
+/*
+ * Maximum size of the "view" array (see "cave.c")
+ * Note that the "view radius" will NEVER exceed 20, and even if the "view"
+ * was octagonal, we would never require more than 1520 entries in the array.
+ */
+#define VIEW_MAX 1536
+
+/*
+ * Maximum size of the "temp" array (see "cave.c")
+ * We must be as large as "VIEW_MAX" and "LITE_MAX" for proper functioning
+ * of "update_view()" and "update_lite()". We must also be as large as the
+ * largest illuminatable room, but no room is larger than 800 grids. We
+ * must also be large enough to allow "good enough" use as a circular queue,
+ * to calculate monster flow, but note that the flow code is "paranoid".
+ */
+#define TEMP_MAX 16384
+
+
+/*
+ * Number of keymap modes
+ */
+#define KEYMAP_MODES 2
+
+/*
+ * Mode for original keyset commands
+ */
+#define KEYMAP_MODE_ORIG 0
+
+/*
+ * Mode for roguelike keyset commands
+ */
+#define KEYMAP_MODE_ROGUE 1
+
+
+/*
+ * OPTION: Maximum number of macros (see "io.c")
+ * Default: assume at most 256 macros are used
+ */
+#define MACRO_MAX 256
+
+/*
+ * OPTION: Maximum number of "quarks" (see "io.c")
+ * Default: assume at most 512 different inscriptions are used
+ */
+#define QUARK_MAX 768
+ /* Was 512... 256 quarks added for random artifacts */
+
+/*
+ * OPTION: Maximum number of messages to remember (see "io.c")
+ * Default: assume maximal memorization of 2048 total messages
+ */
+#define MESSAGE_MAX 2048
+
+#define MESSAGE_NONE 0
+#define MESSAGE_MSG 1
+
+/*
+ * OPTION: Maximum space for the message text buffer (see "io.c")
+ * Default: assume that each of the 2048 messages is repeated an
+ * average of three times, and has an average length of 48
+ */
+#define MESSAGE_BUF 32768
+
+
+/*
+ * Maximum value storable in a "byte" (hard-coded)
+ */
+#define MAX_UCHAR 255
+
+/*
+ * Maximum value storable in a "s16b" (hard-coded)
+ */
+#define MAX_SHORT 32767
+
+
+/*
+ * Store constants
+ */
+#define STORE_INVEN_MAX 255 /* Max number of discrete objs in inven */
+#define STORE_CHOICES 56 /* Number of items to choose stock from */
+#define STORE_OBJ_LEVEL 5 /* Magic Level for normal stores */
+#define STORE_TURNOVER 9 /* Normal shop turnover, per day */
+#define STORE_MIN_KEEP 6 /* Min slots to "always" keep full */
+#define STORE_MAX_KEEP 18 /* Max slots to "always" keep full */
+#define STORE_SHUFFLE 21 /* 1/Chance (per day) of an owner changing */
+#define STORE_TURNS 1000 /* Number of turns between turnovers */
+
+/*
+ * Misc constants
+ */
+#define DAY 11520 /* Number of turns per day */
+#define YEAR (DAY * 365) /* Number of turns per year */
+#define HOUR (DAY / 24) /* Number of turns per hour */
+#define MINUTE (HOUR / 60) /* Number of turns per minute */
+#define DAY_START (HOUR * 6) /* Sunrise */
+#define START_YEAR 2890 /* Bilbo birthday year */
+#define START_DAY (DAY * (42 + 127)) /* Bilbo birthday */
+
+#define BREAK_GLYPH 550 /* Rune of protection resistance */
+#define BREAK_MINOR_GLYPH 99 /* For explosive runes */
+#define BTH_PLUS_ADJ 3 /* Adjust BTH per plus-to-hit */
+#define MON_MULT_ADJ 10 /* High value slows multiplication */
+#define MON_SUMMON_ADJ 2 /* Adjust level of summoned creatures */
+#define MON_DRAIN_LIFE 2 /* Percent of player exp drained per hit */
+#define USE_DEVICE 3 /* x> Harder devices x< Easier devices */
+
+#define BIAS_ELEC 1 /* "Biases" for random artifact gen */
+#define BIAS_POIS 2
+#define BIAS_FIRE 3
+#define BIAS_COLD 4
+#define BIAS_ACID 5
+#define BIAS_STR 6
+#define BIAS_INT 7
+#define BIAS_WIS 8
+#define BIAS_DEX 9
+#define BIAS_CON 10
+#define BIAS_CHR 11
+#define BIAS_CHAOS 12
+#define BIAS_PRIESTLY 13
+#define BIAS_NECROMANTIC 14
+#define BIAS_LAW 15
+#define BIAS_ROGUE 16
+#define BIAS_MAGE 17
+#define BIAS_WARRIOR 18
+#define BIAS_RANGER 19
+
+/*
+ * Location of objects when they were found
+ */
+#define OBJ_FOUND_MONSTER 1
+#define OBJ_FOUND_FLOOR 2
+#define OBJ_FOUND_VAULT 3
+#define OBJ_FOUND_SPECIAL 4
+#define OBJ_FOUND_RUBBLE 5
+#define OBJ_FOUND_REWARD 6
+#define OBJ_FOUND_STORE 7
+#define OBJ_FOUND_STOLEN 8
+#define OBJ_FOUND_SELFMADE 9
+/*
+ * There is a 1/20 (5%) chance of inflating the requested object_level
+ * during the creation of an object (see "get_obj_num()" in "object.c").
+ * Lower values yield better objects more often.
+ */
+#define GREAT_OBJ 20
+
+#define GREAT_EGO 20
+
+/*
+ * There is a 1/50 (2%) chance of inflating the requested monster_level
+ * during the creation of a monsters (see "get_mon_num()" in "monster.c").
+ * Lower values yield harder monsters more often.
+ */
+#define NASTY_MON 50 /* 1/chance of inflated monster level */
+
+
+
+/*
+ * Refueling constants
+ */
+#define FUEL_TORCH 5000 /* Maximum amount of fuel in a torch */
+#define FUEL_LAMP 15000 /* Maximum amount of fuel in a lantern */
+
+
+/*
+ * More maximum values
+ */
+#define MAX_SIGHT 20 /* Maximum view distance */
+#define MAX_RANGE 18 /* Maximum range (spells, etc) */
+
+
+
+/*
+ * The town starts out with 4 residents during the day
+ */
+#define MIN_M_ALLOC_TD 4
+
+/*
+ * The town starts out with 8 residents during the night
+ */
+#define MIN_M_ALLOC_TN 8
+
+
+/*
+ * A monster can only "multiply" (reproduce) if there are fewer than 100
+ * monsters on the level capable of such spontaneous reproduction. This
+ * is a hack which prevents the "m_list[]" array from exploding due to
+ * reproducing monsters. Messy, but necessary.
+ */
+#define MAX_REPRO 100
+
+
+/*
+ * Player constants
+ */
+#define SUBRACE_SAVE 9 /* Ugly hack, should be in foo-info, the subrace saved to the savefile */
+#define PY_MAX_EXP 99999999L /* Maximum exp */
+#define PY_MAX_GOLD 999999999L /* Maximum gold */
+#define PY_MAX_LEVEL 50 /* Maximum level */
+
+/*
+ * Player "food" crucial values
+ */
+#define PY_FOOD_MAX 15000 /* Food value (Bloated) */
+#define PY_FOOD_FULL 10000 /* Food value (Normal) */
+#define PY_FOOD_ALERT 2000 /* Food value (Hungry) */
+#define PY_FOOD_WEAK 1000 /* Food value (Weak) */
+#define PY_FOOD_FAINT 500 /* Food value (Fainting) */
+#define PY_FOOD_STARVE 100 /* Food value (Starving) */
+
+/*
+ * Player regeneration constants
+ */
+#define PY_REGEN_NORMAL 197 /* Regen factor*2^16 when full */
+#define PY_REGEN_WEAK 98 /* Regen factor*2^16 when weak */
+#define PY_REGEN_FAINT 33 /* Regen factor*2^16 when fainting */
+#define PY_REGEN_HPBASE 1442 /* Min amount hp regen*2^16 */
+#define PY_REGEN_MNBASE 524 /* Min amount mana regen*2^16 */
+
+/*
+ * Maximum number of "normal" pack slots, and the index of the "overflow"
+ * slot, which can hold an item, but only temporarily, since it causes the
+ * pack to "overflow", dropping the "last" item onto the ground. Since this
+ * value is used as an actual slot, it must be less than "INVEN_WIELD" (below).
+ * Note that "INVEN_PACK" is probably hard-coded by its use in savefiles, and
+ * by the fact that the screen can only show 23 items plus a one-line prompt.
+ */
+#define INVEN_PACK 23
+
+/*
+ * Body parts
+ */
+#define BODY_WEAPON 0
+#define BODY_TORSO 1
+#define BODY_ARMS 2
+#define BODY_FINGER 3
+#define BODY_HEAD 4
+#define BODY_LEGS 5
+#define BODY_MAX 6
+
+/*
+ * Indexes used for various "equipment" slots (hard-coded by savefiles, etc).
+ */
+#define INVEN_WIELD 24 /* 3 weapons -- WEAPONS */
+#define INVEN_BOW 27 /* 1 bow -- WEAPON */
+#define INVEN_RING 28 /* 6 rings -- FINGER */
+#define INVEN_NECK 34 /* 2 amulets -- HEAD */
+#define INVEN_LITE 36 /* 1 lite -- TORSO */
+#define INVEN_BODY 37 /* 1 body -- TORSO */
+#define INVEN_OUTER 38 /* 1 cloak -- TORSO */
+#define INVEN_ARM 39 /* 3 arms -- ARMS */
+#define INVEN_HEAD 42 /* 2 heads -- HEAD */
+#define INVEN_HANDS 44 /* 3 hands -- ARMS */
+#define INVEN_FEET 47 /* 2 feets -- LEGS */
+#define INVEN_CARRY 49 /* 1 carried monster -- TORSO */
+#define INVEN_AMMO 50 /* 1 quiver -- TORSO */
+#define INVEN_TOOL 51 /* 1 tool -- ARMS */
+
+/*
+ * Total number of inventory slots (hard-coded).
+ */
+#define INVEN_TOTAL 52
+#define INVEN_EQ (INVEN_TOTAL - INVEN_WIELD)
+
+/*
+ * A "stack" of items is limited to less than 100 items (hard-coded).
+ */
+#define MAX_STACK_SIZE 100
+
+
+
+/*
+ * Indexes of the various "stats" (hard-coded by savefiles, etc).
+ */
+#define A_STR 0
+#define A_INT 1
+#define A_WIS 2
+#define A_DEX 3
+#define A_CON 4
+#define A_CHR 5
+
+/*
+ * Player sex constants (hard-coded by save-files, arrays, etc)
+ */
+#define SEX_FEMALE 0
+#define SEX_MALE 1
+#define SEX_NEUTER 2
+
+
+/* Race flags */
+#define PR1_EXPERIMENTAL 0x00000001L /* Is still under developemnt */
+/* XXX */
+#define PR1_RESIST_BLACK_BREATH 0x00000004L /* Resist black breath */
+#define PR1_NO_STUN 0x00000008L /* Never stunned */
+#define PR1_XTRA_MIGHT_BOW 0x00000010L /* Xtra might with bows */
+#define PR1_XTRA_MIGHT_XBOW 0x00000020L /* Xtra might with xbows */
+#define PR1_XTRA_MIGHT_SLING 0x00000040L /* Xtra might with slings */
+#define PR1_AC_LEVEL 0x00000080L /* More AC with levels */
+#define PR1_HURT_LITE 0x00000100L /* Hurt by light */
+#define PR1_VAMPIRE 0x00000200L /* Vampire */
+#define PR1_UNDEAD 0x00000400L /* Undead */
+#define PR1_NO_CUT 0x00000800L /* no cuts */
+#define PR1_CORRUPT 0x00001000L /* hack-- corrupted */
+#define PR1_NO_FOOD 0x00002000L /* little gain from food */
+#define PR1_NO_GOD 0x00004000L /* cannot worship */
+/* XXX */
+#define PR1_ELF 0x00010000L /* Is an elf */
+#define PR1_SEMI_WRAITH 0x00020000L /* Takes damage when going in walls */
+#define PR1_NO_SUBRACE_CHANGE 0x00040000L /* Impossible to change subrace */
+/* XXX */
+#define PR1_ANTIMAGIC 0x00100000L /* antimagic ... hack */
+#define PR1_MOLD_FRIEND 0x00200000L /* Not attacked by molds wielded */
+#define PR1_GOD_FRIEND 0x00400000L /* Better grace */
+/* XXX */
+#define PR1_INNATE_SPELLS 0x01000000L /* KNown all spells, only need books */
+/* XXX */
+/* XXX */
+#define PR1_EASE_STEAL 0x08000000L /* Gain xp by stealing */
+/* XXX */
+/* XXX */
+/* XXX */
+/* XXX */
+
+/* XXX */
+#define PR2_ASTRAL 0x00000002L /* Is it an astral being coming from th halls of mandos ? */
+/* XXX */
+
+#define PRACE_FLAG2(f) ((rp_ptr->flags2 | rmp_ptr->flags2 | cp_ptr->flags2 | spp_ptr->flags2) & (f))
+#define PRACE_FLAG(f) ((rp_ptr->flags1 | rmp_ptr->flags1 | cp_ptr->flags1 | spp_ptr->flags1) & (f))
+#define PRACE_FLAGS(f) PRACE_FLAG(f)
+
+/* XXX */
+#define MKEY_MINDCRAFT 2
+#define MKEY_ANTIMAGIC 3
+#define MKEY_BLADE 4
+#define MKEY_ALCHEMY 5
+#define MKEY_MIMIC 6
+#define MKEY_NECRO 7
+#define MKEY_POWER_MAGE 8
+#define MKEY_RUNE 9
+#define MKEY_FORGING 10
+#define MKEY_INCARNATION 11
+#define MKEY_TELEKINESIS 12
+#define MKEY_SUMMON 13
+#define MKEY_TRAP 14
+#define MKEY_STEAL 15
+#define MKEY_DODGE 16
+#define MKEY_SCHOOL 17
+#define MKEY_LEARN 18
+#define MKEY_COPY 19
+#define MKEY_SYMBIOTIC 20
+#define MKEY_BOULDER 21
+#define MKEY_COMPANION 22
+#define MKEY_PIERCING 23
+
+
+/*** Screen Locations ***/
+
+/*
+ * Some screen locations for various display routines
+ * Currently, row 8 and 15 are the only "blank" rows.
+ * That leaves a "border" around the "stat" values.
+ */
+
+#define ROW_MAP 1
+#define COL_MAP 13 /* Dungeon map */
+
+#define ROW_RACE 1
+#define COL_RACE 0 /* <race name> */
+
+#define ROW_CLASS 2
+#define COL_CLASS 0 /* <class name> */
+
+#define ROW_TITLE 3
+#define COL_TITLE 0 /* <title> or <mode> */
+
+#define ROW_LEVEL 4
+#define COL_LEVEL 0 /* "LEVEL xxxxxx" */
+
+#define ROW_EXP 5
+#define COL_EXP 0 /* "EXP xxxxxxxx" */
+
+#define ROW_GOLD 6
+#define COL_GOLD 0 /* "AU xxxxxxxxx" */
+
+#define ROW_STAT 8
+#define COL_STAT 0 /* "xxx xxxxxx" */
+
+#define ROW_AC 14
+#define COL_AC 0 /* "Cur AC xxxxx" */
+
+#define ROW_HP 15
+#define COL_HP 0 /* "HP xxxxx/xxxxx" */
+
+#define ROW_SANITY 16 /* "Sanity 100%" */
+#define COL_SANITY 0
+
+#define ROW_SP 17
+#define COL_SP 0 /* "SP xxxxx/xxxxx" */
+
+#define ROW_PIETY 18
+#define COL_PIETY 0 /* "Pt xxxxx/xxxxx" */
+
+#define ROW_MH 19
+#define COL_MH 0 /* "MH xxxxx/xxxxx" */
+
+#define ROW_INFO (Term->hgt - 4)
+#define COL_INFO 0 /* "xxxxxxxxxxxx" */
+
+#define ROW_CUT (Term->hgt - 3)
+#define COL_CUT 0 /* <cut> */
+
+#define ROW_STUN (Term->hgt - 2)
+#define COL_STUN 0 /* <stun> */
+
+#define ROW_HUNGRY (Term->hgt - 1)
+#define COL_HUNGRY 0 /* "Weak" / "Hungry" / "Full" / "Gorged" */
+
+#define ROW_BLIND (Term->hgt - 1)
+#define COL_BLIND 7 /* "Blind" */
+
+#define ROW_CONFUSED (Term->hgt - 1)
+#define COL_CONFUSED 13 /* "Conf" */
+
+#define ROW_AFRAID (Term->hgt - 1)
+#define COL_AFRAID 18 /* "Afraid" */
+
+#define ROW_POISONED (Term->hgt - 1)
+#define COL_POISONED 25 /* "Poison" */
+
+#define ROW_DTRAP (Term->hgt - 1)
+#define COL_DTRAP 32 /* "DTrap" */
+
+#define ROW_STATE (Term->hgt - 1)
+#define COL_STATE 38 /* <state> */
+
+#define ROW_SPEED (Term->hgt - 1)
+#define COL_SPEED 49 /* "Slow (-NN)" or "Fast (+NN)" */
+
+#define ROW_STUDY (Term->hgt - 1)
+#define COL_STUDY 60 /* "Study" */
+
+#define ROW_DEPTH (Term->hgt - 1)
+#define COL_DEPTH (Term->wid - 14) /* "Lev NNN" / "NNNN ft" */
+
+
+
+/*** Terrain Feature Indexes (see "lib/edit/f_info.txt") ***/
+
+/* Nothing */
+#define FEAT_NONE 0x00
+
+/* Basic features */
+#define FEAT_FLOOR 0x01
+#define FEAT_FOUNTAIN 0x02
+#define FEAT_GLYPH 0x03
+#define FEAT_OPEN 0x04
+#define FEAT_BROKEN 0x05
+#define FEAT_LESS 0x06
+#define FEAT_MORE 0x07
+
+/* Quest features -KMW- */
+#define FEAT_QUEST_ENTER 0x08
+#define FEAT_QUEST_EXIT 0x09
+#define FEAT_QUEST_DOWN 0x0A
+#define FEAT_QUEST_UP 0x0B
+
+/* Shafts -GSN- */
+#define FEAT_SHAFT_DOWN 0x0D
+#define FEAT_SHAFT_UP 0x0E
+
+/* Basic feature */
+#define FEAT_EMPTY_FOUNTAIN 0x0F
+
+/* Feature 0x10 -- web */
+
+/* Traps */
+#define FEAT_TRAP 0x11
+
+/* Features 0x12 - 0x1F -- unused */
+
+/* Doors */
+#define FEAT_DOOR_HEAD 0x20
+#define FEAT_DOOR_TAIL 0x2F
+
+/* Extra */
+#define FEAT_SECRET 0x30
+#define FEAT_RUBBLE 0x31
+
+/* Seams */
+#define FEAT_MAGMA 0x32
+#define FEAT_QUARTZ 0x33
+#define FEAT_MAGMA_H 0x34
+#define FEAT_QUARTZ_H 0x35
+#define FEAT_MAGMA_K 0x36
+#define FEAT_QUARTZ_K 0x37
+
+/* Walls */
+#define FEAT_WALL_EXTRA 0x38
+#define FEAT_WALL_INNER 0x39
+#define FEAT_WALL_OUTER 0x3A
+#define FEAT_WALL_SOLID 0x3B
+#define FEAT_PERM_EXTRA 0x3C
+#define FEAT_PERM_INNER 0x3D
+#define FEAT_PERM_OUTER 0x3E
+#define FEAT_PERM_SOLID 0x3F
+
+/* Explosive rune */
+#define FEAT_MINOR_GLYPH 0x40
+
+/* Pattern */
+#define FEAT_PATTERN_START 0x41
+#define FEAT_PATTERN_1 0x42
+#define FEAT_PATTERN_2 0x43
+#define FEAT_PATTERN_3 0x44
+#define FEAT_PATTERN_4 0x45
+#define FEAT_PATTERN_END 0x46
+#define FEAT_PATTERN_OLD 0x47
+#define FEAT_PATTERN_XTRA1 0x48
+#define FEAT_PATTERN_XTRA2 0x49
+
+/* Shops */
+#define FEAT_SHOP 0x4A
+
+/* Permanent walls for quests */
+#define FEAT_QUEST1 0x4B
+#define FEAT_QUEST2 0x4C
+#define FEAT_QUEST3 0x4D
+#define FEAT_QUEST4 0x4E
+
+/* Features 0x4F - 0x53 -- unused */
+
+/* Additional terrains */
+#define FEAT_SHAL_WATER 0x54
+#define FEAT_DEEP_LAVA 0x55
+#define FEAT_SHAL_LAVA 0x56
+#define FEAT_DARK_PIT 0x57
+#define FEAT_DIRT 0x58
+#define FEAT_GRASS 0x59
+#define FEAT_ICE 0x5A
+#define FEAT_SAND 0x5B
+#define FEAT_DEAD_TREE 0x5C
+#define FEAT_DEAD_SMALL_TREE 212
+#define FEAT_ASH 0x5D
+#define FEAT_MUD 0x5E
+#define FEAT_ICE_WALL 0x5F
+#define FEAT_TREES 0x60
+#define FEAT_MOUNTAIN 0x61
+#define FEAT_SANDWALL 0x62
+#define FEAT_SANDWALL_H 0x63
+#define FEAT_SANDWALL_K 0x64
+/* Feature 0x65 -- high mountain chain */
+/* Feature 0x66 -- nether mist */
+
+/* Features 0x67 - 0x9F -- unused */
+
+#define FEAT_BETWEEN 0xA0 /* 160 */
+
+/* Altars */
+#define FEAT_ALTAR_HEAD 0xA1 /* 161 */
+#define FEAT_ALTAR_TAIL 0xAB /* 171 */
+
+#define FEAT_MARKER 0xAC /* 172 */
+/* Feature 0xAD -- Underground Tunnel */
+#define FEAT_TAINTED_WATER 0xAE /* 174 */
+#define FEAT_MON_TRAP 0xAF /* 175 */
+#define FEAT_BETWEEN2 0xB0 /* 176 */
+#define FEAT_LAVA_WALL 0xB1 /* 177 */
+#define FEAT_GREAT_FIRE 0xB2 /* 178 */
+#define FEAT_WAY_MORE 0xB3 /* 179 */
+#define FEAT_WAY_LESS 0xB4 /* 180 */
+/* Feature 0xB5 -- field */
+#define FEAT_EKKAIA 0xB6 /* 182 */
+
+/* Features 0xB7 - 0xBA -- unused */
+
+#define FEAT_DEEP_WATER 0xBB /* 187 */
+#define FEAT_GLASS_WALL 0xBC /* 188 */
+#define FEAT_ILLUS_WALL 0xBD /* 189 */
+/* Feature 0xBE -- grass roof */
+/* Feature 0xBF -- grass roof top */
+/* Feature 0xC0 -- grass roof chimney */
+/* Feature 0xC1 -- brick roof */
+/* Feature 0xC2 -- brick roof top */
+/* Feature 0xC3 -- brick roof chimney */
+/* Feature 0xC4 -- window */
+/* Feature 0xC5 -- small window */
+/* Feature 0xC6 -- rain barrel */
+#define FEAT_FLOWER 0xC7 /* 199 */
+/* Feature 0xC8 -- cobblestone road */
+/* Feature 0xC9 -- cobblestone with outlet */
+#define FEAT_SMALL_TREES 0xCA /* 202 */
+#define FEAT_TOWN 0xCB /* 203 */
+/* Feature 0xCC -- Underground Tunnel */
+#define FEAT_FIRE 0xCD /* 205 */
+/* Feature 0xCE -- pile of rubble (permanent) */
+
+/* Features 0xCF - 0xFF -- unused */
+
+
+#define MAX_BETWEEN_EXITS 2
+
+/*
+ * Number of effects
+ */
+#define MAX_EFFECTS 128
+#define EFF_WAVE 0x00000001 /* A circle whose radius increase */
+#define EFF_LAST 0x00000002 /* The wave lasts */
+#define EFF_STORM 0x00000004 /* The area follows the player */
+#define EFF_DIR1 0x00000008 /* Directed effect */
+#define EFF_DIR2 0x00000010 /* Directed effect */
+#define EFF_DIR3 0x00000020 /* Directed effect */
+#define EFF_DIR4 0x00000040 /* Directed effect */
+#define EFF_DIR6 0x00000080 /* Directed effect */
+#define EFF_DIR7 0x00000100 /* Directed effect */
+#define EFF_DIR8 0x00000200 /* Directed effect */
+#define EFF_DIR9 0x00000400 /* Directed effect */
+
+/*
+ * Wilderness terrains
+ */
+#define TERRAIN_EDGE 0 /* Edge of the World */
+#define TERRAIN_TOWN 1 /* Town */
+#define TERRAIN_DEEP_WATER 2 /* Deep water */
+#define TERRAIN_SHALLOW_WATER 3 /* Shallow water */
+#define TERRAIN_SWAMP 4 /* Swamp */
+#define TERRAIN_DIRT 5 /* Dirt */
+#define TERRAIN_GRASS 6 /* Grass */
+#define TERRAIN_TREES 7 /* Trees */
+#define TERRAIN_DESERT 8 /* Desert */
+#define TERRAIN_SHALLOW_LAVA 9 /* Shallow lava */
+#define TERRAIN_DEEP_LAVA 10 /* Deep lava */
+#define TERRAIN_MOUNTAIN 11 /* Mountain */
+
+#define MAX_WILD_TERRAIN 18
+
+/*** Artifact indexes (see "lib/edit/a_info.txt") ***/
+
+
+/* Lites */
+#define ART_GALADRIEL 1
+#define ART_ELENDIL 2
+#define ART_THRAIN 3
+#define ART_PALANTIR 202
+#define ART_UNDEATH 200
+#define ART_STONE_LORE 15
+#define ART_PALANTIR_ITHIL 208
+
+/* Amulets */
+#define ART_CARLAMMAS 4
+#define ART_INGWE 5
+#define ART_DWARVES 6
+#define ART_ANCHOR 14
+#define ART_ELESSAR 206
+#define ART_EVENSTAR 207
+
+/* Rings */
+#define ART_FLAR 7
+#define ART_BARAHIR 8
+#define ART_TULKAS 9
+#define ART_NARYA 10
+#define ART_NENYA 11
+#define ART_VILYA 12
+#define ART_POWER 13
+/* 14 used by the anchor of space-time */
+/* 15 used by the stone of lore */
+
+/* Dragon Scale */
+#define ART_RAZORBACK 16
+#define ART_BLADETURNER 17
+#define ART_MEDIATOR 166
+
+/* Hard Armour */
+#define ART_HIMRING 167
+#define ART_SOULKEEPER 19
+#define ART_ISILDUR 20
+#define ART_ROHIRRIM 21
+#define ART_BELEGENNON 22
+#define ART_CELEBORN 23
+#define ART_ARVEDUI 24
+#define ART_CASPANION 25
+
+/* Thunderlord flying suit */
+#define ART_MARDA 26
+#define ART_TRON 27
+
+/* Soft Armour */
+#define ART_THALKETTOTH 28
+
+/* Shields */
+#define ART_THORIN 30
+#define ART_CELEGORM 31
+#define ART_ANARION 32
+#define ART_GILGALAD 169
+#define ART_HARADRIM 176
+
+/* Helms and Crowns */
+#define ART_MORGOTH 34
+#define ART_BERUTHIEL 35
+#define ART_THRANDUIL 36
+#define ART_THENGEL 37
+#define ART_HAMMERHAND 38
+#define ART_DOR 39
+#define ART_HOLHENNETH 40
+#define ART_GORLIM 41
+#define ART_GONDOR 42
+#define ART_KNOWLEDGE 160
+#define ART_NUMENOR 43
+#define ART_CELEBRIMBOR 170
+
+/* Cloaks */
+#define ART_COLLUIN 44
+#define ART_HOLCOLLETH 45
+#define ART_THINGOL 46
+#define ART_THORONGIL 47
+#define ART_COLANNON 48
+#define ART_LUTHIEN 49
+#define ART_TUOR 50
+
+/* Gloves */
+#define ART_CAMBELEG 52
+#define ART_CAMMITHRIM 53
+#define ART_PAURHACH 54
+#define ART_PAURNIMMEN 55
+#define ART_PAURAEGEN 56
+#define ART_PAURNEN 57
+#define ART_CAMLOST 58
+#define ART_FINGOLFIN 59
+#define ART_EOL 178
+
+/* Boots */
+#define ART_FEANOR 60
+#define ART_DAL 61
+#define ART_THROR 62
+
+/* Swords */
+#define ART_NARSIL 164
+#define ART_MAEDHROS 64
+#define ART_ANGRIST 65
+#define ART_NARTHANC 66
+#define ART_NIMTHANC 67
+#define ART_DETHANC 68
+#define ART_RILIA 69
+#define ART_BELANGIL 70
+#define ART_CALRIS 71
+#define ART_ARUNRUTH 72
+#define ART_GLAMDRING 73
+#define ART_AEGLIN 74
+#define ART_ORCRIST 75
+#define ART_GURTHANG 76
+#define ART_ZARCUTHRA 77
+#define ART_MORMEGIL 78
+#define ART_GONDRICAM 79
+#define ART_CRISDURIAN 80
+#define ART_AGLARANG 81
+#define ART_RINGIL 82
+#define ART_ANDURIL 83
+#define ART_ANGUIREL 84
+#define ART_ELVAGIL 85
+#define ART_FORASGIL 86
+#define ART_CARETH 87
+#define ART_STING 88
+#define ART_HARADEKKET 89
+#define ART_GILETTAR 90
+#define ART_DOOMCALLER 91
+#define ART_VORPAL_BLADE 92
+#define ART_ERU 147
+
+/* Polearms */
+#define ART_THEODEN 93
+#define ART_PAIN 94
+#define ART_OSONDIR 95
+#define ART_TIL 96
+#define ART_AEGLOS 97
+#define ART_OROME 98
+#define ART_NIMLOTH 99
+#define ART_EORLINGAS 100
+#define ART_DURIN 101
+#define ART_EONWE 102
+#define ART_BALLI 103
+#define ART_LOTHARANG 104
+#define ART_MUNDWINE 105
+#define ART_BARUKKHELED 106
+#define ART_WRATH 107
+#define ART_ULMO 108
+#define ART_AVAVIR 109
+#define ART_FUNDIN 175
+
+/* The sword of the Dawn */
+#define ART_DAWN 110
+
+/* Hafted */
+#define ART_MELKOR 18
+#define ART_HURIN 33
+#define ART_GROND 111
+#define ART_TOTILA 112
+#define ART_THUNDERFIST 113
+#define ART_BLOODSPIKE 114
+#define ART_FIRESTAR 115
+#define ART_TARATOL 116
+#define ART_AULE 117
+#define ART_NAR 118
+#define ART_ERIRIL 119
+#define ART_OLORIN 120
+#define ART_DEATHWREAKER 121
+#define ART_TURMIL 122
+#define ART_GOTHMOG 123
+#define ART_AXE_GOTHMOG 145
+#define ART_SKULLCLEAVER 177
+
+#define ART_NAIN 174
+
+/* Bows */
+#define ART_BELTHRONDING 124
+#define ART_BARD 125
+#define ART_CUBRAGOL 126
+#define ART_UMBAR 171
+
+/* Mage Staffs */
+#define ART_GANDALF 127
+
+/* Boomerangs */
+#define ART_BEOR 128
+#define ART_GLIMDRIR 129
+
+/* Musical Instrument */
+#define ART_MAGLOR 137
+#define ART_SKY 138
+#define ART_DAERON 139
+#define ART_DRUEDAIN 141
+#define ART_ROHAN 142
+#define ART_HELM 143
+#define ART_BOROMIR 144
+
+/* Diggers */
+#define ART_EREBOR 140
+
+#define ART_ORCHAST 156
+#define ART_NIGHT 157
+#define ART_NATUREBANE 158
+
+/* Spell for various object */
+#define SPELL_ID_PLAIN 1
+#define SPELL_BO_FIRE 2
+#define SPELL_BO_COLD 3
+#define SPELL_BO_ELEC 4
+#define SPELL_BO_POIS 5
+#define SPELL_BO_ACID 6
+#define SPELL_MAPPING 7
+#define SPELL_CURE 8
+#define SPELL_ID_FULL 9
+#define SPELL_WRAITH 10
+#define SPELL_INVIS 11
+
+
+/*** Ego-Item indexes (see "lib/edit/e_info.txt") ***/
+
+#define EGO_MANA 1
+#define EGO_POWER 2
+#define EGO_MANA_POWER 3
+#define EGO_MSTAFF_SPELL 4
+#define EGO_BRAND_POIS 77
+#define EGO_BRAND_ELEC 74
+#define EGO_BRAND_FIRE 75
+#define EGO_BRAND_COLD 76
+#define EGO_BRAND_ACID 73
+#define EGO_EARTHQUAKES 80
+#define EGO_BLESS_BLADE 67
+#define EGO_VAMPIRIC 97
+#define EGO_CHAOTIC 78
+#define EGO_BLASTED 127
+#define EGO_SHATTERED 126
+#define EGO_FLAME 122
+#define EGO_FROST 123
+#define EGO_LIGHTNING_BOLT 121
+#define EGO_FREE_ACTION 49
+#define EGO_DF 66
+#define EGO_MOTION 59
+#define EGO_SPECTRAL 102
+#define EGO_NOLDOR 23
+#define EGO_JUMP 15
+#define EGO_SPINING 72
+#define EGO_DRAGON 99
+#define EGO_INST_DRAGONKIND 130
+#define EGO_ENDURE_ELEC 17
+#define EGO_ENDURE_ACID 16
+#define EGO_ENDURE_FIRE 18
+#define EGO_ENDURE_COLD 19
+#define EGO_QUIET 58
+#define EGO_WISDOM 25
+#define EGO_RESIST_ELEC 6
+#define EGO_RESIST_ACID 5
+#define EGO_RESIST_FIRE 7
+#define EGO_RESIST_COLD 8
+#define EGO_LIFE 68
+#define EGO_STEALTH 42
+#define EGO_PROTECTION 41
+#define EGO_MAGI 27
+#define EGO_SPEED 60
+#define EGO_RESISTANCE 9
+#define EGO_LITE 32
+#define EGO_AURA_FIRE 44
+#define EGO_SLAYING_WEAPON 71
+#define EGO_SLAYING 50
+#define EGO_TELEPORTATION 35
+#define EGO_ELVENKIND 10
+#define EGO_LITE_MAGI 163
+#define EGO_HA 65
+
+
+/* Activation effects for random artifacts */
+#define ACT_SUNLIGHT 1
+#define ACT_BO_MISS_1 2
+#define ACT_BA_POIS_1 3
+#define ACT_BO_ELEC_1 4
+#define ACT_BO_ACID_1 5
+#define ACT_BO_COLD_1 6
+#define ACT_BO_FIRE_1 7
+#define ACT_BA_COLD_1 8
+#define ACT_BA_FIRE_1 9
+#define ACT_DRAIN_1 10
+#define ACT_BA_COLD_2 11
+#define ACT_BA_ELEC_2 12
+#define ACT_DRAIN_2 13
+#define ACT_VAMPIRE_1 14
+#define ACT_BO_MISS_2 15
+#define ACT_BA_FIRE_2 16
+#define ACT_BA_COLD_3 17
+#define ACT_BA_ELEC_3 18
+#define ACT_WHIRLWIND 19
+#define ACT_VAMPIRE_2 20
+#define ACT_CALL_CHAOS 21
+#define ACT_ROCKET 22
+#define ACT_DISP_EVIL 23
+#define ACT_BA_MISS_3 24
+#define ACT_DISP_GOOD 25
+#define ACT_GILGALAD 26
+#define ACT_CELEBRIMBOR 27
+#define ACT_SKULLCLEAVER 28
+#define ACT_HARADRIM 29
+#define ACT_FUNDIN 30
+#define ACT_EOL 31
+#define ACT_UMBAR 32
+#define ACT_NUMENOR 33
+#define ACT_KNOWLEDGE 34
+#define ACT_UNDEATH 35
+#define ACT_THRAIN 36
+#define ACT_BARAHIR 37
+#define ACT_TULKAS 38
+#define ACT_NARYA 39
+#define ACT_NENYA 40
+#define ACT_VILYA 41
+#define ACT_POWER 42
+#define ACT_STONE_LORE 43
+#define ACT_RAZORBACK 44
+#define ACT_BLADETURNER 45
+#define ACT_MEDIATOR 46
+#define ACT_BELEGENNON 47
+#define ACT_GORLIM 48
+#define ACT_COLLUIN 49
+#define ACT_BELANGIL 50
+#define ACT_CONFUSE 51
+#define ACT_SLEEP 52
+#define ACT_QUAKE 53
+#define ACT_TERROR 54
+#define ACT_TELE_AWAY 55
+#define ACT_BANISH_EVIL 56
+#define ACT_GENOCIDE 57
+#define ACT_MASS_GENO 58
+#define ACT_ANGUIREL 59
+#define ACT_ERU 60
+#define ACT_DAWN 61
+#define ACT_FIRESTAR 62
+#define ACT_TURMIL 63
+#define ACT_CUBRAGOL 64
+#define ACT_CHARM_ANIMAL 65
+#define ACT_CHARM_UNDEAD 66
+#define ACT_CHARM_OTHER 67
+#define ACT_CHARM_ANIMALS 68
+#define ACT_CHARM_OTHERS 69
+#define ACT_SUMMON_ANIMAL 70
+#define ACT_SUMMON_PHANTOM 71
+#define ACT_SUMMON_ELEMENTAL 72
+#define ACT_SUMMON_DEMON 73
+#define ACT_SUMMON_UNDEAD 74
+#define ACT_ELESSAR 75
+#define ACT_GANDALF 76
+#define ACT_MARDA 77
+#define ACT_PALANTIR 78
+/*
+ 79
+ 80
+*/
+#define ACT_CURE_LW 81
+#define ACT_CURE_MW 82
+#define ACT_CURE_POISON 83
+#define ACT_REST_LIFE 84
+#define ACT_REST_ALL 85
+#define ACT_CURE_700 86
+#define ACT_CURE_1000 87
+/*
+ 88
+*/
+#define ACT_EREBOR 89
+#define ACT_DRUEDAIN 90
+#define ACT_ESP 91
+#define ACT_BERSERK 92
+#define ACT_PROT_EVIL 93
+#define ACT_RESIST_ALL 94
+#define ACT_SPEED 95
+#define ACT_XTRA_SPEED 96
+#define ACT_WRAITH 97
+#define ACT_INVULN 98
+#define ACT_ROHAN 99
+#define ACT_HELM 100
+#define ACT_BOROMIR 101
+#define ACT_HURIN 102
+#define ACT_AXE_GOTHMOG 103
+#define ACT_MELKOR 104
+#define ACT_GROND 105
+#define ACT_NATUREBANE 106
+#define ACT_NIGHT 107
+#define ACT_ORCHAST 108
+#define ACT_LIGHT 111
+#define ACT_MAP_LIGHT 112
+#define ACT_DETECT_ALL 113
+#define ACT_DETECT_XTRA 114
+#define ACT_ID_FULL 115
+#define ACT_ID_PLAIN 116
+#define ACT_RUNE_EXPLO 117
+#define ACT_RUNE_PROT 118
+#define ACT_SATIATE 119
+#define ACT_DEST_DOOR 120
+#define ACT_STONE_MUD 121
+#define ACT_RECHARGE 122
+#define ACT_ALCHEMY 123
+#define ACT_DIM_DOOR 124
+#define ACT_TELEPORT 125
+#define ACT_RECALL 126
+
+#define ACT_DEATH 127
+#define ACT_RUINATION 128
+#define ACT_DESTRUC 129
+#define ACT_UNINT 130
+#define ACT_UNSTR 131
+#define ACT_UNCON 132
+#define ACT_UNCHR 133
+#define ACT_UNDEX 134
+#define ACT_UNWIS 135
+#define ACT_STATLOSS 136
+#define ACT_HISTATLOSS 137
+#define ACT_EXPLOSS 138
+#define ACT_HIEXPLOSS 139
+#define ACT_SUMMON_MONST 140
+#define ACT_PARALYZE 141
+#define ACT_HALLU 142
+#define ACT_POISON 143
+#define ACT_HUNGER 144
+#define ACT_STUN 145
+#define ACT_CUTS 146
+#define ACT_PARANO 147
+#define ACT_CONFUSION 148
+#define ACT_BLIND 149
+#define ACT_PET_SUMMON 150
+#define ACT_CURE_PARA 151
+#define ACT_CURE_HALLU 152
+#define ACT_CURE_POIS 153
+#define ACT_CURE_HUNGER 154
+#define ACT_CURE_STUN 155
+#define ACT_CURE_CUTS 156
+#define ACT_CURE_FEAR 157
+#define ACT_CURE_CONF 158
+#define ACT_CURE_BLIND 159
+#define ACT_CURING 160
+#define ACT_DARKNESS 161
+#define ACT_LEV_TELE 162
+#define ACT_ACQUIREMENT 163
+#define ACT_WEIRD 164
+#define ACT_AGGRAVATE 165
+#define ACT_MUT 166
+#define ACT_CURE_INSANITY 167
+#define ACT_CURE_MUT 168
+#define ACT_LIGHT_ABSORBTION 169
+/* of dragonkind?*/
+#define ACT_BA_FIRE_H 170
+#define ACT_BA_COLD_H 171
+#define ACT_BA_ELEC_H 172
+#define ACT_BA_ACID_H 173
+#define ACT_SPIN 174
+#define ACT_NOLDOR 175
+#define ACT_SPECTRAL 176
+#define ACT_JUMP 177
+#define ACT_DEST_TELE 178
+/*amulet of serpents dam 100, rad 2 timout 40+d60 */
+#define ACT_BA_POIS_4 179
+/*rings of X 50,50+d50 dur 20+d20 */
+#define ACT_BA_COLD_4 180
+#define ACT_BA_FIRE_4 181
+#define ACT_BA_ACID_4 182
+#define ACT_BA_ELEC_4 183
+#define ACT_BR_ELEC 184
+#define ACT_BR_COLD 185
+#define ACT_BR_FIRE 186
+#define ACT_BR_ACID 187
+#define ACT_BR_POIS 188
+#define ACT_BR_MANY 189
+#define ACT_BR_CONF 190
+#define ACT_BR_SOUND 191
+#define ACT_BR_CHAOS 192
+#define ACT_BR_SHARD 193
+#define ACT_BR_BALANCE 194
+#define ACT_BR_LIGHT 195
+#define ACT_BR_POWER 196
+#define ACT_GROW_MOLD 197
+#define ACT_MUSIC 200
+/* 170 -> unused */
+
+/*** Object "tval" and "sval" codes ***/
+
+
+/*
+ * The values for the "tval" field of various objects.
+ *
+ * This value is the primary means by which items are sorted in the
+ * player inventory, followed by "sval" and "cost".
+ *
+ * Note that a "BOW" with tval = 19 and sval S = 10*N+P takes a missile
+ * weapon with tval = 16+N, and does (xP) damage when so combined. This
+ * fact is not actually used in the source, but it kind of interesting.
+ *
+ * Note that as of 2.7.8, the "item flags" apply to all items, though
+ * only armor and weapons and a few other items use any of these flags.
+ */
+
+#define TV_SKELETON 1 /* Skeletons ('s') */
+#define TV_BOTTLE 2 /* Empty bottles ('!') */
+/* XXX */
+#define TV_BATERIE 4 /* For the Alchemists */
+#define TV_SPIKE 5 /* Spikes ('~') */
+#define TV_MSTAFF 6 /* Mage Staffs */
+#define TV_CHEST 7 /* Chests ('~') */
+#define TV_PARCHMENT 8 /* Parchments from Kamband */
+#define TV_PARCHEMENT 8 /* compatibility define */
+#define TV_CORPSE 9 /* Monster corpses */
+#define TV_EGG 10 /* Monster Eggs */
+#define TV_JUNK 11 /* Sticks, Pottery, etc ('~') */
+#define TV_TOOL 12 /* Tools */
+#define TV_INSTRUMENT 14 /* Musical instruments */
+#define TV_BOOMERANG 15 /* Boomerangs */
+#define TV_SHOT 16 /* Ammo for slings */
+#define TV_ARROW 17 /* Ammo for bows */
+#define TV_BOLT 18 /* Ammo for x-bows */
+#define TV_BOW 19 /* Slings/Bows/Xbows */
+#define TV_DIGGING 20 /* Shovels/Picks */
+#define TV_HAFTED 21 /* Priest Weapons */
+#define TV_POLEARM 22 /* Pikes/Glaives/Spears/etc. */
+#define TV_SWORD 23 /* Edged Weapons */
+#define TV_AXE 24 /* Axes/Cleavers */
+#define TV_BOOTS 30 /* Boots */
+#define TV_GLOVES 31 /* Gloves */
+#define TV_HELM 32 /* Helms */
+#define TV_CROWN 33 /* Crowns */
+#define TV_SHIELD 34 /* Shields */
+#define TV_CLOAK 35 /* Cloaks */
+#define TV_SOFT_ARMOR 36 /* Soft Armor */
+#define TV_HARD_ARMOR 37 /* Hard Armor */
+#define TV_DRAG_ARMOR 38 /* Dragon Scale Mail */
+#define TV_LITE 39 /* Lites (including Specials) */
+#define TV_AMULET 40 /* Amulets (including Specials) */
+#define TV_RING 45 /* Rings (including Specials) */
+#define TV_TRAPKIT 46 /* Trapkits */
+#define TV_TOTEM 54 /* Summoner totems */
+#define TV_STAFF 55
+#define TV_WAND 65
+#define TV_ROD 66
+#define TV_ROD_MAIN 67
+#define TV_SCROLL 70
+#define TV_POTION 71
+#define TV_POTION2 72 /* Second set of potion */
+#define TV_FLASK 77
+#define TV_FOOD 80
+#define TV_HYPNOS 99 /* To wield monsters !:) */
+#define TV_GOLD 100 /* Gold can only be picked up by players */
+#define TV_RANDART 102 /* Random Artifacts */
+#define TV_RUNE1 104 /* Base runes */
+#define TV_RUNE2 105 /* Modifier runes */
+
+#define TV_BOOK 111
+#define TV_SYMBIOTIC_BOOK 112
+#define TV_MUSIC_BOOK 113
+#define TV_DRUID_BOOK 114
+#define TV_DAEMON_BOOK 115
+
+
+/* The "sval" codes for TV_JUNK */
+#define SV_BOULDER 1
+
+
+/* The "sval" codes for TV_TOOL */
+#define SV_TOOL_CLIMB 0
+#define SV_PORTABLE_HOLE 1
+
+/* The "sval" codes for TV_MSTAFF */
+#define SV_MSTAFF 1
+
+/* The "sval" codes for TV_SHOT/TV_ARROW/TV_BOLT */
+#define SV_AMMO_LIGHT 0 /* pebbles */
+#define SV_AMMO_NORMAL 1 /* shots, arrows, bolts */
+#define SV_AMMO_HEAVY 2 /* seeker arrows and bolts, mithril shots */
+
+/* The "sval" codes for TV_INSTRUMENT */
+#define SV_DRUM 58
+#define SV_HARP 59
+#define SV_HORN 60
+
+/* The "sval" codes for TV_TRAPKIT */
+#define SV_TRAPKIT_SLING 1
+#define SV_TRAPKIT_BOW 2
+#define SV_TRAPKIT_XBOW 3
+#define SV_TRAPKIT_POTION 4
+#define SV_TRAPKIT_SCROLL 5
+#define SV_TRAPKIT_DEVICE 6
+
+/* The "sval" codes for TV_BOOMERANG */
+#define SV_BOOM_S_WOOD 1 /* 1d4 */
+#define SV_BOOM_WOOD 2 /* 1d8 */
+#define SV_BOOM_S_METAL 3 /* 3d4 */
+#define SV_BOOM_METAL 4 /* 4d5 */
+
+/* The "sval" codes for TV_BOW (note information in "sval") */
+#define SV_SLING 2 /* (x2) */
+#define SV_SHORT_BOW 12 /* (x2) */
+#define SV_LONG_BOW 13 /* (x3) */
+#define SV_LIGHT_XBOW 23 /* (x3) */
+#define SV_HEAVY_XBOW 24 /* (x4) */
+
+/* The "sval" codes for TV_DIGGING */
+#define SV_SHOVEL 1
+#define SV_GNOMISH_SHOVEL 2
+#define SV_DWARVEN_SHOVEL 3
+#define SV_PICK 4
+#define SV_ORCISH_PICK 5
+#define SV_DWARVEN_PICK 6
+#define SV_MATTOCK 7
+
+/* The "sval" values for TV_HAFTED */
+#define SV_CLUB 1 /* 1d4 */
+#define SV_WHIP 2 /* 1d6 */
+#define SV_QUARTERSTAFF 3 /* 1d9 */
+#define SV_NUNCHAKU 4 /* 2d3 */
+#define SV_MACE 5 /* 2d4 */
+#define SV_BALL_AND_CHAIN 6 /* 2d4 */
+#define SV_WAR_HAMMER 8 /* 3d3 */
+#define SV_LUCERN_HAMMER 10 /* 2d5 */
+#define SV_THREE_PIECE_ROD 11 /* 3d3 */
+#define SV_MORNING_STAR 12 /* 2d6 */
+#define SV_FLAIL 13 /* 2d6 */
+#define SV_LEAD_FILLED_MACE 15 /* 3d4 */
+#define SV_TWO_HANDED_FLAIL 18 /* 3d6 */
+#define SV_GREAT_HAMMER 19 /* 4d6 */
+#define SV_MACE_OF_DISRUPTION 20 /* 5d8 */
+#define SV_GROND 50 /* 3d4 */
+
+/* The "sval" values for TV_AXE */
+#define SV_HATCHET 1 /* 1d5 */
+#define SV_CLEAVER 2 /* 2d4 */
+#define SV_LIGHT_WAR_AXE 8 /* 2d5 */
+#define SV_BEAKED_AXE 10 /* 2d6 */
+#define SV_BROAD_AXE 11 /* 2d6 */
+#define SV_BATTLE_AXE 22 /* 2d8 */
+#define SV_GREAT_AXE 25 /* 4d4 */
+#define SV_LOCHABER_AXE 28 /* 3d8 */
+#define SV_SLAUGHTER_AXE 30 /* 5d7 */
+
+/* The "sval" values for TV_POLEARM */
+#define SV_SPEAR 2 /* 1d6 */
+#define SV_SICKLE 3 /* 2d3 */
+#define SV_AWL_PIKE 4 /* 1d8 */
+#define SV_TRIDENT 5 /* 1d9 */
+#define SV_FAUCHARD 6 /* 1d10 */
+#define SV_BROAD_SPEAR 7 /* 1d9 */
+#define SV_PIKE 8 /* 2d5 */
+#define SV_GLAIVE 13 /* 2d6 */
+#define SV_HALBERD 15 /* 3d4 */
+#define SV_GUISARME 16 /* 2d5 */
+#define SV_SCYTHE 17 /* 5d3 */
+#define SV_LANCE 20 /* 2d8 */
+#define SV_TRIFURCATE_SPEAR 26 /* 2d9 */
+#define SV_HEAVY_LANCE 29 /* 4d8 */
+#define SV_SCYTHE_OF_SLICING 30 /* 8d4 */
+
+/* The "sval" codes for TV_SWORD */
+#define SV_BROKEN_DAGGER 1 /* 1d1 */
+#define SV_BROKEN_SWORD 2 /* 1d2 */
+#define SV_DAGGER 4 /* 1d4 */
+#define SV_MAIN_GAUCHE 5 /* 1d5 */
+#define SV_RAPIER 7 /* 1d6 */
+#define SV_SMALL_SWORD 8 /* 1d6 */
+#define SV_BASILLARD 9 /* 1d8 */
+#define SV_SHORT_SWORD 10 /* 1d7 */
+#define SV_SABRE 11 /* 1d7 */
+#define SV_CUTLASS 12 /* 1d7 */
+#define SV_KHOPESH 14 /* 2d4 */
+#define SV_TULWAR 15 /* 2d4 */
+#define SV_BROAD_SWORD 16 /* 2d5 */
+#define SV_LONG_SWORD 17 /* 2d5 */
+#define SV_SCIMITAR 18 /* 2d5 */
+#define SV_KATANA 20 /* 3d4 */
+#define SV_BASTARD_SWORD 21 /* 3d4 */
+#define SV_GREAT_SCIMITAR 22 /* 4d5 */
+#define SV_CLAYMORE 23 /* 2d8 */
+#define SV_ESPADON 24 /* 2d9 */
+#define SV_TWO_HANDED_SWORD 25 /* 3d6 */
+#define SV_FLAMBERGE 26 /* 3d7 */
+#define SV_EXECUTIONERS_SWORD 28 /* 4d5 */
+#define SV_ZWEIHANDER 29 /* 4d6 */
+#define SV_BLADE_OF_CHAOS 30 /* 6d5 */
+#define SV_BLUESTEEL_BLADE 31 /* 3d9 */
+#define SV_SHADOW_BLADE 32 /* 4d4 */
+#define SV_DARK_SWORD 33 /* 3d7 */
+
+/* The "sval" codes for TV_SHIELD */
+#define SV_SMALL_LEATHER_SHIELD 2
+#define SV_SMALL_METAL_SHIELD 3
+#define SV_LARGE_LEATHER_SHIELD 4
+#define SV_LARGE_METAL_SHIELD 5
+#define SV_DRAGON_SHIELD 6
+#define SV_SHIELD_OF_DEFLECTION 10
+
+/* The "sval" codes for TV_HELM */
+#define SV_HARD_LEATHER_CAP 2
+#define SV_METAL_CAP 3
+#define SV_IRON_HELM 5
+#define SV_STEEL_HELM 6
+#define SV_DRAGON_HELM 7
+#define SV_IRON_CROWN 10
+#define SV_GOLDEN_CROWN 11
+#define SV_JEWELED_CROWN 12
+#define SV_MORGOTH 50
+
+/* The "sval" codes for TV_BOOTS */
+#define SV_PAIR_OF_SOFT_LEATHER_BOOTS 2
+#define SV_PAIR_OF_HARD_LEATHER_BOOTS 3
+#define SV_PAIR_OF_METAL_SHOD_BOOTS 6
+
+/* The "sval" codes for TV_CLOAK */
+#define SV_CLOAK 1
+#define SV_ELVEN_CLOAK 2
+#define SV_FUR_CLOAK 3
+#define SV_SHADOW_CLOAK 6
+#define SV_MIMIC_CLOAK 100
+
+/* The "sval" codes for TV_GLOVES */
+#define SV_SET_OF_LEATHER_GLOVES 1
+#define SV_SET_OF_GAUNTLETS 2
+#define SV_SET_OF_CESTI 5
+
+/* The "sval" codes for TV_SOFT_ARMOR */
+#define SV_FILTHY_RAG 1
+#define SV_ROBE 2
+#define SV_PAPER_ARMOR 3 /* 4 */
+#define SV_SOFT_LEATHER_ARMOR 4
+#define SV_SOFT_STUDDED_LEATHER 5
+#define SV_HARD_LEATHER_ARMOR 6
+#define SV_HARD_STUDDED_LEATHER 7
+#define SV_RHINO_HIDE_ARMOR 8
+#define SV_CORD_ARMOR 9 /* 6 */
+#define SV_PADDED_ARMOR 10 /* 4 */
+#define SV_LEATHER_SCALE_MAIL 11
+#define SV_LEATHER_JACK 12
+#define SV_STONE_AND_HIDE_ARMOR 15 /* 15 */
+#define SV_THUNDERLORD_SUIT 16
+
+/* The "sval" codes for TV_HARD_ARMOR */
+#define SV_RUSTY_CHAIN_MAIL 1 /* 14- */
+#define SV_RING_MAIL 2 /* 12 */
+#define SV_METAL_SCALE_MAIL 3 /* 13 */
+#define SV_CHAIN_MAIL 4 /* 14 */
+#define SV_DOUBLE_RING_MAIL 5 /* 15 */
+#define SV_AUGMENTED_CHAIN_MAIL 6 /* 16 */
+#define SV_DOUBLE_CHAIN_MAIL 7 /* 16 */
+#define SV_BAR_CHAIN_MAIL 8 /* 18 */
+#define SV_METAL_BRIGANDINE_ARMOUR 9 /* 19 */
+#define SV_SPLINT_MAIL 10 /* 19 */
+#define SV_PARTIAL_PLATE_ARMOUR 12 /* 22 */
+#define SV_METAL_LAMELLAR_ARMOUR 13 /* 23 */
+#define SV_FULL_PLATE_ARMOUR 15 /* 25 */
+#define SV_RIBBED_PLATE_ARMOUR 18 /* 28 */
+#define SV_MITHRIL_CHAIN_MAIL 20 /* 28+ */
+#define SV_MITHRIL_PLATE_MAIL 25 /* 35+ */
+#define SV_ADAMANTITE_PLATE_MAIL 30 /* 40+ */
+
+/* The "sval" codes for TV_DRAG_ARMOR */
+#define SV_DRAGON_BLACK 1
+#define SV_DRAGON_BLUE 2
+#define SV_DRAGON_WHITE 3
+#define SV_DRAGON_RED 4
+#define SV_DRAGON_GREEN 5
+#define SV_DRAGON_MULTIHUED 6
+#define SV_DRAGON_SHINING 10
+#define SV_DRAGON_LAW 12
+#define SV_DRAGON_BRONZE 14
+#define SV_DRAGON_GOLD 16
+#define SV_DRAGON_CHAOS 18
+#define SV_DRAGON_BALANCE 20
+#define SV_DRAGON_POWER 30
+
+/* The sval codes for TV_LITE */
+#define SV_LITE_TORCH 0
+#define SV_LITE_LANTERN 1
+#define SV_LITE_TORCH_EVER 2
+#define SV_LITE_DWARVEN 3
+#define SV_LITE_FEANORIAN 4
+#define SV_LITE_GALADRIEL 100
+#define SV_LITE_ELENDIL 101
+#define SV_LITE_THRAIN 102
+#define SV_LITE_UNDEATH 103
+#define SV_LITE_PALANTIR 104
+#define SV_ANCHOR_SPACETIME 105
+#define SV_STONE_LORE 106
+
+
+/* The "sval" codes for TV_AMULET */
+#define SV_AMULET_DOOM 0
+#define SV_AMULET_TELEPORT 1
+#define SV_AMULET_ADORNMENT 2
+#define SV_AMULET_SLOW_DIGEST 3
+#define SV_AMULET_RESIST_ACID 4
+#define SV_AMULET_SEARCHING 5
+#define SV_AMULET_BRILLANCE 6
+#define SV_AMULET_CHARISMA 7
+#define SV_AMULET_THE_MAGI 8
+#define SV_AMULET_REFLECTION 9
+#define SV_AMULET_CARLAMMAS 10
+#define SV_AMULET_INGWE 11
+#define SV_AMULET_DWARVES 12
+#define SV_AMULET_NO_MAGIC 13
+#define SV_AMULET_NO_TELE 14
+#define SV_AMULET_RESISTANCE 15
+#define SV_AMULET_NOTHING 16
+#define SV_AMULET_SERPENT 17
+#define SV_AMULET_TORIS_MEJISTOS 18
+#define SV_AMULET_ELESSAR 19
+#define SV_AMULET_EVENSTAR 20
+#define SV_AMULET_SUSTENANCE 21
+#define SV_AMULET_TELEPATHY 22
+#define SV_AMULET_TRICKERY 23
+#define SV_AMULET_WEAPONMASTERY 24
+#define SV_AMULET_DEVOTION 25
+#define SV_AMULET_INFRA 26
+#define SV_AMULET_SPELL 27
+#define SV_AMULET_WISDOM 28
+#define SV_AMULET_RESIST_ELEC 29
+#define SV_AMULET_REGEN 30
+
+/* The sval codes for TV_RING */
+#define SV_RING_WOE 0
+#define SV_RING_AGGRAVATION 1
+#define SV_RING_WEAKNESS 2
+#define SV_RING_STUPIDITY 3
+#define SV_RING_TELEPORTATION 4
+#define SV_RING_SPECIAL 5
+#define SV_RING_SLOW_DIGESTION 6
+#define SV_RING_FEATHER_FALL 7
+#define SV_RING_RESIST_FIRE 8
+#define SV_RING_RESIST_COLD 9
+#define SV_RING_SUSTAIN_STR 10
+#define SV_RING_SUSTAIN_INT 11
+#define SV_RING_SUSTAIN_WIS 12
+#define SV_RING_SUSTAIN_CON 13
+#define SV_RING_SUSTAIN_DEX 14
+#define SV_RING_SUSTAIN_CHR 15
+#define SV_RING_PROTECTION 16
+#define SV_RING_ACID 17
+#define SV_RING_FLAMES 18
+#define SV_RING_ICE 19
+#define SV_RING_RESIST_POIS 20
+#define SV_RING_FREE_ACTION 21
+#define SV_RING_SEE_INVIS 22
+#define SV_RING_SEARCHING 23
+#define SV_RING_STR 24
+#define SV_RING_INT 25
+#define SV_RING_DEX 26
+#define SV_RING_CON 27
+#define SV_RING_ACCURACY 28
+#define SV_RING_DAMAGE 29
+#define SV_RING_SLAYING 30
+#define SV_RING_SPEED 31
+#define SV_RING_BARAHIR 32
+#define SV_RING_TULKAS 33
+#define SV_RING_NARYA 34
+#define SV_RING_NENYA 35
+#define SV_RING_VILYA 36
+#define SV_RING_POWER 37
+#define SV_RING_RES_FEAR 38
+#define SV_RING_RES_LD 39
+#define SV_RING_RES_NETHER 40
+#define SV_RING_RES_NEXUS 41
+#define SV_RING_RES_SOUND 42
+#define SV_RING_RES_CONFUSION 43
+#define SV_RING_RES_SHARDS 44
+#define SV_RING_RES_DISENCHANT 45
+#define SV_RING_RES_CHAOS 46
+#define SV_RING_RES_BLINDNESS 47
+#define SV_RING_LORDLY 48
+#define SV_RING_ATTACKS 49
+#define SV_RING_NOTHING 50
+#define SV_RING_PRECONITION 51
+#define SV_RING_FLAR 52
+#define SV_RING_INVIS 53
+#define SV_RING_FLYING 54
+#define SV_RING_WRAITH 55
+#define SV_RING_ELEC 56
+#define SV_RING_DURIN 57
+#define SV_RING_SPELL 58
+#define SV_RING_CRIT 59
+
+/* The "sval" codes for TV_STAFF */
+#define SV_STAFF_SCHOOL 1
+#define SV_STAFF_NOTHING 2
+
+/* needed for monster traps */
+#define SV_STAFF_LIGHT 3
+#define SV_STAFF_FIERY_SHIELD 4
+#define SV_STAFF_REMOVE_CURSES 5
+#define SV_STAFF_WINGS_WIND 6
+#define SV_STAFF_SHAKE 7
+#define SV_STAFF_DISARM 8
+#define SV_STAFF_TELEPORTATION 9
+#define SV_STAFF_PROBABILITY_TRAVEL 10
+#define SV_STAFF_RECOVERY 11
+#define SV_STAFF_HEALING 12
+#define SV_STAFF_VISION 13
+#define SV_STAFF_IDENTIFY 14
+#define SV_STAFF_SENSE_HIDDEN 15
+#define SV_STAFF_REVEAL_WAYS 16
+#define SV_STAFF_SENSE_MONSTER 17
+#define SV_STAFF_GENOCIDE 18
+#define SV_STAFF_SUMMON 19
+#define SV_STAFF_WISH 20
+#define SV_STAFF_MANA 21
+#define SV_STAFF_MITHRANDIR 22
+
+/* The "sval" codes for TV_WAND */
+#define SV_WAND_SCHOOL 1
+#define SV_WAND_NOTHING 2
+
+/* needed for monster traps */
+#define SV_WAND_MANATHRUST 3
+#define SV_WAND_FIREFLASH 4
+#define SV_WAND_FIREWALL 5
+#define SV_WAND_TIDAL_WAVE 6
+#define SV_WAND_ICE_STORM 7
+#define SV_WAND_NOXIOUS_CLOUD 8
+#define SV_WAND_POISON_BLOOD 9
+#define SV_WAND_THUNDERSTORM 10
+#define SV_WAND_DIG 11
+#define SV_WAND_STONE_PRISON 12
+#define SV_WAND_STRIKE 13
+#define SV_WAND_TELEPORT_AWAY 14
+#define SV_WAND_SUMMON_ANIMAL 15
+#define SV_WAND_MAGELOCK 16
+#define SV_WAND_SLOW_MONSTER 17
+#define SV_WAND_SPEED 18
+#define SV_WAND_BANISHMENT 19
+#define SV_WAND_DISPERSE_MAGIC 20
+#define SV_WAND_CHARM 21
+#define SV_WAND_CONFUSE 22
+#define SV_WAND_DEMON_BLADE 23
+#define SV_WAND_HEAL_MONSTER 24
+#define SV_WAND_HASTE_MONSTER 25
+#define SV_WAND_THRAIN 26
+
+/* The "sval" codes for TV_ROD(Rod Tips) */
+#define SV_ROD_NOTHING 0
+#define SV_ROD_DETECT_DOOR 1
+#define SV_ROD_IDENTIFY 2
+#define SV_ROD_RECALL 3
+#define SV_ROD_ILLUMINATION 4
+#define SV_ROD_MAPPING 5
+#define SV_ROD_DETECTION 6
+#define SV_ROD_PROBING 7
+#define SV_ROD_CURING 8
+#define SV_ROD_HEALING 9
+#define SV_ROD_RESTORATION 10
+#define SV_ROD_SPEED 11
+/* xxx (aimed) */
+#define SV_ROD_TELEPORT_AWAY 13
+#define SV_ROD_DISARMING 14
+#define SV_ROD_LITE 15
+#define SV_ROD_SLEEP_MONSTER 16
+#define SV_ROD_SLOW_MONSTER 17
+#define SV_ROD_DRAIN_LIFE 18
+#define SV_ROD_POLYMORPH 19
+#define SV_ROD_ACID_BOLT 20
+#define SV_ROD_ELEC_BOLT 21
+#define SV_ROD_FIRE_BOLT 22
+#define SV_ROD_COLD_BOLT 23
+#define SV_ROD_ACID_BALL 24
+#define SV_ROD_ELEC_BALL 25
+#define SV_ROD_FIRE_BALL 26
+#define SV_ROD_COLD_BALL 27
+#define SV_ROD_HAVOC 28
+#define SV_ROD_DETECT_TRAP 29
+#define SV_ROD_HOME 30
+
+
+/* The "sval" codes for TV_ROD_MAIN(Rods) */
+/* Note that the sval is the max mana capacity of the rod */
+
+#define SV_ROD_WOODEN 10
+#define SV_ROD_COPPER 20
+#define SV_ROD_IRON 50
+#define SV_ROD_ALUMINIUM 75
+#define SV_ROD_SILVER 100
+#define SV_ROD_GOLDEN 125
+#define SV_ROD_MITHRIL 160
+#define SV_ROD_ADMANTITE 200
+
+
+/* The "sval" codes for TV_SCROLL */
+
+#define SV_SCROLL_DARKNESS 0
+#define SV_SCROLL_AGGRAVATE_MONSTER 1
+#define SV_SCROLL_CURSE_ARMOR 2
+#define SV_SCROLL_CURSE_WEAPON 3
+#define SV_SCROLL_SUMMON_MONSTER 4
+#define SV_SCROLL_SUMMON_UNDEAD 5
+#define SV_SCROLL_SUMMON_MINE 6
+#define SV_SCROLL_TRAP_CREATION 7
+#define SV_SCROLL_PHASE_DOOR 8
+#define SV_SCROLL_TELEPORT 9
+#define SV_SCROLL_TELEPORT_LEVEL 10
+#define SV_SCROLL_WORD_OF_RECALL 11
+#define SV_SCROLL_IDENTIFY 12
+#define SV_SCROLL_STAR_IDENTIFY 13
+#define SV_SCROLL_REMOVE_CURSE 14
+#define SV_SCROLL_STAR_REMOVE_CURSE 15
+#define SV_SCROLL_ENCHANT_ARMOR 16
+#define SV_SCROLL_ENCHANT_WEAPON_TO_HIT 17
+#define SV_SCROLL_ENCHANT_WEAPON_TO_DAM 18
+#define SV_SCROLL_ENCHANT_WEAPON_PVAL 19
+#define SV_SCROLL_STAR_ENCHANT_ARMOR 20
+#define SV_SCROLL_STAR_ENCHANT_WEAPON 21
+#define SV_SCROLL_RECHARGING 22
+#define SV_SCROLL_RESET_RECALL 23
+#define SV_SCROLL_LIGHT 24
+#define SV_SCROLL_MAPPING 25
+#define SV_SCROLL_DETECT_GOLD 26
+#define SV_SCROLL_DETECT_ITEM 27
+#define SV_SCROLL_DETECT_TRAP 28
+#define SV_SCROLL_DETECT_DOOR 29
+#define SV_SCROLL_DETECT_INVIS 30
+#define SV_SCROLL_DIVINATION 31
+#define SV_SCROLL_SATISFY_HUNGER 32
+#define SV_SCROLL_BLESSING 33
+#define SV_SCROLL_HOLY_CHANT 34
+#define SV_SCROLL_HOLY_PRAYER 35
+#define SV_SCROLL_MONSTER_CONFUSION 36
+#define SV_SCROLL_PROTECTION_FROM_EVIL 37
+#define SV_SCROLL_RUNE_OF_PROTECTION 38
+#define SV_SCROLL_TRAP_DOOR_DESTRUCTION 39
+#define SV_SCROLL_DEINCARNATION 40
+#define SV_SCROLL_STAR_DESTRUCTION 41
+#define SV_SCROLL_DISPEL_UNDEAD 42
+#define SV_SCROLL_MASS_RESURECTION 43
+#define SV_SCROLL_GENOCIDE 44
+#define SV_SCROLL_MASS_GENOCIDE 45
+#define SV_SCROLL_ACQUIREMENT 46
+#define SV_SCROLL_STAR_ACQUIREMENT 47
+#define SV_SCROLL_FIRE 48
+#define SV_SCROLL_ICE 49
+#define SV_SCROLL_CHAOS 50
+#define SV_SCROLL_RUMOR 51
+#define SV_SCROLL_ARTIFACT 52
+#define SV_SCROLL_NOTHING 53
+
+/* The "sval" codes for TV_POTION */
+#define SV_POTION_WATER 0
+#define SV_POTION_APPLE_JUICE 1
+#define SV_POTION_SLIME_MOLD 2
+#define SV_POTION_BLOOD 3
+#define SV_POTION_SLOWNESS 4
+#define SV_POTION_SALT_WATER 5
+#define SV_POTION_POISON 6
+#define SV_POTION_BLINDNESS 7
+#define SV_POTION_INVIS 8
+#define SV_POTION_CONFUSION 9
+#define SV_POTION_MUTATION 10
+#define SV_POTION_SLEEP 11
+#define SV_POTION_LEARNING 12
+#define SV_POTION_LOSE_MEMORIES 13
+/* xxx */
+#define SV_POTION_RUINATION 15
+#define SV_POTION_DEC_STR 16
+#define SV_POTION_DEC_INT 17
+#define SV_POTION_DEC_WIS 18
+#define SV_POTION_DEC_DEX 19
+#define SV_POTION_DEC_CON 20
+#define SV_POTION_DEC_CHR 21
+#define SV_POTION_DETONATIONS 22
+#define SV_POTION_DEATH 23
+#define SV_POTION_INFRAVISION 24
+#define SV_POTION_DETECT_INVIS 25
+#define SV_POTION_SLOW_POISON 26
+#define SV_POTION_CURE_POISON 27
+#define SV_POTION_BOLDNESS 28
+#define SV_POTION_SPEED 29
+#define SV_POTION_RESIST_HEAT 30
+#define SV_POTION_RESIST_COLD 31
+#define SV_POTION_HEROISM 32
+#define SV_POTION_BESERK_STRENGTH 33
+#define SV_POTION_CURE_LIGHT 34
+#define SV_POTION_CURE_SERIOUS 35
+#define SV_POTION_CURE_CRITICAL 36
+#define SV_POTION_HEALING 37
+#define SV_POTION_STAR_HEALING 38
+#define SV_POTION_LIFE 39
+#define SV_POTION_RESTORE_MANA 40
+#define SV_POTION_RESTORE_EXP 41
+#define SV_POTION_RES_STR 42
+#define SV_POTION_RES_INT 43
+#define SV_POTION_RES_WIS 44
+#define SV_POTION_RES_DEX 45
+#define SV_POTION_RES_CON 46
+#define SV_POTION_RES_CHR 47
+#define SV_POTION_INC_STR 48
+#define SV_POTION_INC_INT 49
+#define SV_POTION_INC_WIS 50
+#define SV_POTION_INC_DEX 51
+#define SV_POTION_INC_CON 52
+#define SV_POTION_INC_CHR 53
+/* xxx */
+#define SV_POTION_AUGMENTATION 55
+#define SV_POTION_ENLIGHTENMENT 56
+#define SV_POTION_STAR_ENLIGHTENMENT 57
+#define SV_POTION_SELF_KNOWLEDGE 58
+#define SV_POTION_EXPERIENCE 59
+#define SV_POTION_RESISTANCE 60
+#define SV_POTION_CURING 61
+#define SV_POTION_INVULNERABILITY 62
+#define SV_POTION_NEW_LIFE 63
+
+#define SV_POTION_LAST 63
+
+/* The "sval" codes for TV_POTION2 */
+#define SV_POTION2_MIMIC 1
+#define SV_POTION2_CURE_LIGHT_SANITY 14
+#define SV_POTION2_CURE_SERIOUS_SANITY 15
+#define SV_POTION2_CURE_CRITICAL_SANITY 16
+#define SV_POTION2_CURE_SANITY 17
+#define SV_POTION2_CURE_WATER 18
+
+#define SV_POTION2_LAST 18
+
+/* The "sval" codes for TV_FOOD */
+#define SV_FOOD_POISON 0
+#define SV_FOOD_BLINDNESS 1
+#define SV_FOOD_PARANOIA 2
+#define SV_FOOD_CONFUSION 3
+#define SV_FOOD_HALLUCINATION 4
+#define SV_FOOD_PARALYSIS 5
+#define SV_FOOD_WEAKNESS 6
+#define SV_FOOD_SICKNESS 7
+#define SV_FOOD_STUPIDITY 8
+#define SV_FOOD_NAIVETY 9
+#define SV_FOOD_UNHEALTH 10
+#define SV_FOOD_DISEASE 11
+#define SV_FOOD_CURE_POISON 12
+#define SV_FOOD_CURE_BLINDNESS 13
+#define SV_FOOD_CURE_PARANOIA 14
+#define SV_FOOD_CURE_CONFUSION 15
+#define SV_FOOD_CURE_SERIOUS 16
+#define SV_FOOD_RESTORE_STR 17
+#define SV_FOOD_RESTORE_CON 18
+#define SV_FOOD_RESTORING 19
+/* many missing mushrooms */
+#define SV_FOOD_BISCUIT 32
+#define SV_FOOD_JERKY 33
+#define SV_FOOD_RATION 35
+#define SV_FOOD_SLIME_MOLD 36
+#define SV_FOOD_WAYBREAD 37
+#define SV_FOOD_PINT_OF_ALE 38
+#define SV_FOOD_PINT_OF_WINE 39
+#define SV_FOOD_ATHELAS 40
+#define SV_FOOD_GREAT_HEALTH 41
+#define SV_FOOD_FORTUNE_COOKIE 42
+
+/* The "sval" codes for TV_BATERIE */
+#define SV_BATERIE_POISON 1
+#define SV_BATERIE_EXPLOSION 2
+#define SV_BATERIE_TELEPORT 3
+#define SV_BATERIE_COLD 4
+#define SV_BATERIE_FIRE 5
+#define SV_BATERIE_ACID 6
+#define SV_BATERIE_LIFE 7
+#define SV_BATERIE_CONFUSION 8
+#define SV_BATERIE_LITE 9
+#define SV_BATERIE_CHAOS 10
+#define SV_BATERIE_TIME 11
+#define SV_BATERIE_MAGIC 12
+#define SV_BATERIE_XTRA_LIFE 13
+#define SV_BATERIE_DARKNESS 14
+#define SV_BATERIE_KNOWLEDGE 15
+#define SV_BATERIE_FORCE 16
+#define SV_BATERIE_LIGHTNING 17
+#define SV_BATERIE_MANA 18
+#define MAX_BATERIE_SVAL 18
+
+/* The "sval" codes for TV_CORPSE */
+#define SV_CORPSE_CORPSE 1
+#define SV_CORPSE_SKELETON 2
+#define SV_CORPSE_HEAD 3
+#define SV_CORPSE_SKULL 4
+#define SV_CORPSE_MEAT 5
+
+/* The "sval" codes for TV_DAEMON_BOOK */
+#define SV_DEMONBLADE 55
+#define SV_DEMONSHIELD 56
+#define SV_DEMONHORN 57
+
+/*
+ * Special "sval" limit -- first "normal" food
+ */
+#define SV_FOOD_MIN_FOOD 32
+
+/*
+ * Special "sval" limit -- first "aimed" rod
+ */
+#define SV_ROD_MIN_DIRECTION 12
+
+/*
+ * Special "sval" limit -- first "large" chest
+ */
+#define SV_CHEST_MIN_LARGE 4
+
+/*
+ * Special "sval" limit -- last "good" magic/prayer book
+ */
+#define SV_BOOK_MAX_GOOD 49
+
+/* flags for operation in get_random_trap in object3.c */
+
+#define TRAP_EXISTS 0x00000001L
+#define TRAP_FOUND 0x00000002L
+#define TRAP_NOTFOUND 0x00000004L
+#define TRAP_IDENTIFIED 0x00000008L
+
+/*** General flag values ***/
+
+
+/*
+ * Special cave grid flags
+ */
+#define CAVE_MARK 0x0001 /* memorized feature */
+#define CAVE_GLOW 0x0002 /* self-illuminating */
+#define CAVE_ICKY 0x0004 /* part of a vault */
+#define CAVE_ROOM 0x0008 /* part of a room */
+#define CAVE_SEEN 0x0010 /* seen flag */
+#define CAVE_VIEW 0x0020 /* view flag */
+#define CAVE_TEMP 0x0040 /* temp flag */
+#define CAVE_WALL 0x0080 /* wall flag */
+#define CAVE_TRDT 0x0100 /* trap detected */
+#define CAVE_IDNT 0x0200 /* grid identified (fountains) */
+#define CAVE_SPEC 0x0400 /* special mark(quests) */
+#define CAVE_FREE 0x0800 /* no random generation on it */
+#define CAVE_DETECT 0x1000 /* Traps detected here */
+#define CAVE_PLIT 0x2000 /* Player lit grid */
+#define CAVE_MLIT 0x4000 /* Monster lit grid */
+
+/*
+ * Bit flags for the "project()" function
+ *
+ * JUMP: Jump directly to the target location (this is a hack)
+ * BEAM: Work as a beam weapon (affect every grid passed through)
+ * THRU: Continue "through" the target (used for "bolts"/"beams")
+ * WALL: Continue "through" the walls
+ * STOP: Stop as soon as we hit a monster (used for "bolts")
+ * GRID: Affect each grid in the "blast area" in some way
+ * ITEM: Affect each object in the "blast area" in some way
+ * KILL: Affect each monster in the "blast area" in some way
+ * HIDE: Hack -- disable "visual" feedback from projection
+ */
+#define PROJECT_JUMP 0x00000001
+#define PROJECT_BEAM 0x00000002
+#define PROJECT_THRU 0x00000004
+#define PROJECT_STOP 0x00000008
+#define PROJECT_GRID 0x00000010
+#define PROJECT_ITEM 0x00000020
+#define PROJECT_KILL 0x00000040
+#define PROJECT_HIDE 0x00000080
+#define PROJECT_VIEWABLE 0x00000100 /* Affect monsters in LOS */
+#define PROJECT_METEOR_SHOWER 0x00000200 /* Affect random grids */
+#define PROJECT_BLAST 0x00000400 /* Like Mega_blast, but will only affect viewable grids */
+#define PROJECT_PANEL 0x00000800 /* Affect everything in the panel. */
+#define PROJECT_ALL 0x00001000 /* Affect every single grid. */
+#define PROJECT_WALL 0x00002000
+#define PROJECT_MANA_PATH 0x00004000 /* Follow a mana path. */
+#define PROJECT_ABSORB_MANA 0x00008000 /* The spell increase in power as it absord grid's mana. */
+#define PROJECT_STAY 0x00010000
+
+/*
+ * Bit flags for the "enchant()" function
+ */
+#define ENCH_TOHIT 0x01
+#define ENCH_TODAM 0x02
+#define ENCH_TOAC 0x04
+#define ENCH_PVAL 0x08
+
+/*
+ * Bit flags for the "target_set" function XXX XXX XXX
+ *
+ * KILL: Target monsters
+ * LOOK: Describe grid fully
+ * XTRA: Currently unused flag
+ * GRID: Select from all grids
+ */
+#define TARGET_KILL 0x01
+#define TARGET_LOOK 0x02
+#define TARGET_XTRA 0x04
+#define TARGET_GRID 0x08
+
+
+/*
+ * Some bit-flags for the "smart" field
+ */
+#define SM_RES_ACID 0x00000001
+#define SM_RES_ELEC 0x00000002
+#define SM_RES_FIRE 0x00000004
+#define SM_RES_COLD 0x00000008
+#define SM_RES_POIS 0x00000010
+#define SM_RES_NETH 0x00000020
+#define SM_RES_LITE 0x00000040
+#define SM_RES_DARK 0x00000080
+#define SM_RES_FEAR 0x00000100
+#define SM_RES_CONF 0x00000200
+#define SM_RES_CHAOS 0x00000400
+#define SM_RES_DISEN 0x00000800
+#define SM_RES_BLIND 0x00001000
+#define SM_RES_NEXUS 0x00002000
+#define SM_RES_SOUND 0x00004000
+#define SM_RES_SHARD 0x00008000
+#define SM_OPP_ACID 0x00010000
+#define SM_OPP_ELEC 0x00020000
+#define SM_OPP_FIRE 0x00040000
+#define SM_OPP_COLD 0x00080000
+#define SM_OPP_POIS 0x00100000
+#define SM_OPP_XXX1 0x00200000
+#define SM_CLONED 0x00400000
+#define SM_NOTE_TRAP 0x00800000
+#define SM_IMM_ACID 0x01000000
+#define SM_IMM_ELEC 0x02000000
+#define SM_IMM_FIRE 0x04000000
+#define SM_IMM_COLD 0x08000000
+#define SM_IMM_XXX5 0x10000000
+#define SM_IMM_REFLECT 0x20000000
+#define SM_IMM_FREE 0x40000000
+#define SM_IMM_MANA 0x80000000
+
+/*
+ * Monster status(Player POV)
+ */
+#define MSTATUS_ENEMY -2
+#define MSTATUS_NEUTRAL_M -1
+#define MSTATUS_NEUTRAL 0
+#define MSTATUS_NEUTRAL_P 1
+#define MSTATUS_FRIEND 2
+#define MSTATUS_PET 3
+#define MSTATUS_COMPANION 4
+
+/*
+ * Bit flags for the "get_item" function
+ */
+#define USE_EQUIP 0x01 /* Allow equip items */
+#define USE_INVEN 0x02 /* Allow inven items */
+#define USE_FLOOR 0x04 /* Allow floor items */
+#define USE_EXTRA 0x08 /* Allow extra items */
+#define USE_AUTO 0x10 /* Allow creation of automatizer rule */
+/*
+ * Bit flags for the "p_ptr->notice" variable
+ */
+#define PN_COMBINE 0x00000001L /* Combine the pack */
+#define PN_REORDER 0x00000002L /* Reorder the pack */
+/* xxx (many) */
+
+
+/*
+ * Bit flags for the "p_ptr->update" variable
+ */
+#define PU_BONUS 0x00000001L /* Calculate bonuses */
+#define PU_TORCH 0x00000002L /* Calculate torch radius */
+#define PU_BODY 0x00000004L /* Calculate body parts */
+#define PU_SANITY 0x00000008L /* Calculate csan and msan */
+#define PU_HP 0x00000010L /* Calculate chp and mhp */
+#define PU_MANA 0x00000020L /* Calculate csp and msp */
+#define PU_SPELLS 0x00000040L /* Calculate spells */
+#define PU_POWERS 0x00000080L /* Calculate powers */
+/* xxx (many) */
+#define PU_UN_VIEW 0x00010000L /* Forget view */
+/* xxx (many) */
+#define PU_VIEW 0x00100000L /* Update view */
+#define PU_MON_LITE 0x00200000L /* Update monster light */
+/* xxx */
+#define PU_MONSTERS 0x01000000L /* Update monsters */
+#define PU_DISTANCE 0x02000000L /* Update distances */
+/* xxx */
+#define PU_FLOW 0x10000000L /* Update flow */
+/* xxx (many) */
+
+
+/*
+ * Bit flags for the "p_ptr->redraw" variable
+ */
+#define PR_MISC 0x00000001L /* Display Race/Class */
+#define PR_TITLE 0x00000002L /* Display Title */
+#define PR_LEV 0x00000004L /* Display Level */
+#define PR_EXP 0x00000008L /* Display Experience */
+#define PR_STATS 0x00000010L /* Display Stats */
+#define PR_ARMOR 0x00000020L /* Display Armor */
+#define PR_HP 0x00000040L /* Display Hitpoints */
+#define PR_MANA 0x00000080L /* Display Mana */
+#define PR_GOLD 0x00000100L /* Display Gold */
+#define PR_DEPTH 0x00000200L /* Display Depth */
+/****/
+#define PR_HEALTH 0x00000800L /* Display Health Bar */
+#define PR_CUT 0x00001000L /* Display Extra (Cut) */
+#define PR_STUN 0x00002000L /* Display Extra (Stun) */
+#define PR_HUNGER 0x00004000L /* Display Extra (Hunger) */
+#define PR_PIETY 0x00008000L /* Display Piety */
+#define PR_BLIND 0x00010000L /* Display Extra (Blind) */
+#define PR_CONFUSED 0x00020000L /* Display Extra (Confused) */
+#define PR_AFRAID 0x00040000L /* Display Extra (Afraid) */
+#define PR_POISONED 0x00080000L /* Display Extra (Poisoned) */
+#define PR_STATE 0x00100000L /* Display Extra (State) */
+#define PR_SPEED 0x00200000L /* Display Extra (Speed) */
+#define PR_STUDY 0x00400000L /* Display Extra (Study) */
+#define PR_SANITY 0x00800000L /* Display Sanity */
+#define PR_EXTRA 0x01000000L /* Display Extra Info */
+#define PR_BASIC 0x02000000L /* Display Basic Info */
+#define PR_MAP 0x04000000L /* Display Map */
+#define PR_WIPE 0x08000000L /* Hack -- Total Redraw */
+#define PR_MH 0x10000000L /* Display Monster hitpoints */
+#define PR_DTRAP 0x20000000L /* Display Extra (DTrap) */
+/* xxx */
+/* xxx */
+
+/*
+ * Bit flags for the "p_ptr->window" variable (etc)
+ */
+#define PW_INVEN 0x00000001L /* Display inven/equip */
+#define PW_EQUIP 0x00000002L /* Display equip/inven */
+/* xxx */
+#define PW_PLAYER 0x00000008L /* Display character */
+#define PW_M_LIST 0x00000010L /* Show monster list */
+/* xxx */
+#define PW_MESSAGE 0x00000040L /* Display messages */
+#define PW_OVERHEAD 0x00000080L /* Display overhead view */
+#define PW_MONSTER 0x00000100L /* Display monster recall */
+#define PW_OBJECT 0x00000200L /* Display object recall */
+/* xxx */
+#define PW_SNAPSHOT 0x00000800L /* Display snap-shot */
+/* xxx */
+/* xxx */
+#define PW_BORG_1 0x00004000L /* Display borg messages */
+#define PW_BORG_2 0x00008000L /* Display borg status */
+
+
+/* jk */
+#define FTRAP_CHEST 0x000000001 /* may appear on chests */
+#define FTRAP_DOOR 0x000000002 /* may appear on doors/floors */
+#define FTRAP_FLOOR 0x000000004 /* may appear on floor */
+#define FTRAP_CHANGE 0x000000008 /* Color changing */
+#define FTRAP_XXX5 0x000000010
+#define FTRAP_XXX6 0x000000020
+#define FTRAP_XXX7 0x000000040
+#define FTRAP_XXX8 0x000000080
+#define FTRAP_XXX9 0x000000100
+#define FTRAP_XXX10 0x000000200
+#define FTRAP_XXX11 0x000000400
+#define FTRAP_XXX12 0x000000800
+#define FTRAP_XXX13 0x000001000
+#define FTRAP_XXX14 0x000002000
+#define FTRAP_XXX15 0x000004000
+#define FTRAP_XXX16 0x000008000
+#define FTRAP_LEVEL1 0x000010000 /* low level ball/bolt trap */
+#define FTRAP_LEVEL2 0x000020000 /* medium level ball/bolt trap */
+#define FTRAP_LEVEL3 0x000040000 /* high level ball/bolt trap */
+#define FTRAP_LEVEL4 0x000080000 /* oops level ball/bolt trap */
+#define FTRAP_XXX21 0x000100000
+#define FTRAP_XXX22 0x000200000
+#define FTRAP_XXX23 0x000400000
+#define FTRAP_XXX24 0x000800000
+#define FTRAP_XXX25 0x001000000
+#define FTRAP_XXX26 0x002000000
+#define FTRAP_XXX27 0x004000000
+#define FTRAP_XXX28 0x008000000
+#define FTRAP_XXX29 0x010000000
+#define FTRAP_XXX30 0x020000000
+#define FTRAP_XXX31 0x040000000
+#define FTRAP_XXX32 0x080000000
+
+/* jk */
+#define STAT_DEC_TEMPORARY 1
+#define STAT_DEC_NORMAL 2
+#define STAT_DEC_PERMANENT 3
+
+/* jk - which trap is which number */
+#define TRAP_OF_WEAKNESS_I 1
+#define TRAP_OF_WEAKNESS_II 2
+#define TRAP_OF_WEAKNESS_III 3
+#define TRAP_OF_INTELLIGENCE_I 4
+#define TRAP_OF_INTELLIGENCE_II 5
+#define TRAP_OF_INTELLIGENCE_III 6
+#define TRAP_OF_WISDOM_I 7
+#define TRAP_OF_WISDOM_II 8
+#define TRAP_OF_WISDOM_III 9
+#define TRAP_OF_FUMBLING_I 10
+#define TRAP_OF_FUMBLING_II 11
+#define TRAP_OF_FUMBLING_III 12
+#define TRAP_OF_WASTING_I 13
+#define TRAP_OF_WASTING_II 14
+#define TRAP_OF_WASTING_III 15
+#define TRAP_OF_BEAUTY_I 16
+#define TRAP_OF_BEAUTY_II 17
+#define TRAP_OF_BEAUTY_III 18
+
+#define TRAP_OF_CURSE_WEAPON 20
+#define TRAP_OF_CURSE_ARMOR 21
+#define TRAP_OF_EARTHQUAKE 22
+#define TRAP_OF_POISON_NEEDLE 23
+#define TRAP_OF_SUMMON_MONSTER 24
+#define TRAP_OF_SUMMON_UNDEAD 25
+#define TRAP_OF_SUMMON_GREATER_UNDEAD 26
+#define TRAP_OF_TELEPORT 27
+#define TRAP_OF_PARALYZING 28
+#define TRAP_OF_EXPLOSIVE_DEVICE 29
+#define TRAP_OF_TELEPORT_AWAY 30
+#define TRAP_OF_LOSE_MEMORY 31
+#define TRAP_OF_BITTER_REGRET 32
+#define TRAP_OF_BOWEL_CRAMPS 33
+#define TRAP_OF_BLINDNESS_CONFUSION 34
+#define TRAP_OF_AGGRAVATION 35
+#define TRAP_OF_MULTIPLICATION 36
+#define TRAP_OF_STEAL_ITEM 37
+#define TRAP_OF_SUMMON_FAST_QUYLTHULGS 38
+#define TRAP_OF_SINKING 39
+#define TRAP_OF_MANA_DRAIN 40
+#define TRAP_OF_MISSING_MONEY 41
+#define TRAP_OF_NO_RETURN 42
+#define TRAP_OF_SILENT_SWITCHING 43
+#define TRAP_OF_WALLS 44
+#define TRAP_OF_CALLING_OUT 45
+#define TRAP_OF_SLIDING 46
+#define TRAP_OF_CHARGES_DRAIN 47
+#define TRAP_OF_STAIR_MOVEMENT 48
+#define TRAP_OF_NEW 49
+#define TRAP_OF_SCATTER_ITEMS 50
+#define TRAP_OF_DECAY 51
+#define TRAP_OF_WASTING_WANDS 52
+#define TRAP_OF_FILLING 53
+#define TRAP_OF_DRAIN_SPEED 54
+
+#define TRAP_OF_ELEC_BOLT 60
+#define TRAP_OF_POIS_BOLT 61
+#define TRAP_OF_ACID_BOLT 62
+#define TRAP_OF_COLD_BOLT 63
+#define TRAP_OF_FIRE_BOLT 64
+#define TRAP_OF_PLASMA_BOLT 65
+#define TRAP_OF_WATER_BOLT 66
+#define TRAP_OF_LITE_BOLT 67
+#define TRAP_OF_DARK_BOLT 68
+#define TRAP_OF_SHARDS_BOLT 69
+#define TRAP_OF_SOUND_BOLT 70
+#define TRAP_OF_CONFUSION_BOLT 71
+#define TRAP_OF_FORCE_BOLT 72
+#define TRAP_OF_INERTIA_BOLT 73
+#define TRAP_OF_MANA_BOLT 74
+#define TRAP_OF_ICE_BOLT 75
+#define TRAP_OF_CHAOS_BOLT 76
+#define TRAP_OF_NETHER_BOLT 77
+#define TRAP_OF_DISENCHANT_BOLT 78
+#define TRAP_OF_NEXUS_BOLT 79
+#define TRAP_OF_TIME_BOLT 80
+#define TRAP_OF_GRAVITY_BOLT 81
+
+#define TRAP_OF_ELEC_BALL 82
+#define TRAP_OF_POIS_BALL 83
+#define TRAP_OF_ACID_BALL 84
+#define TRAP_OF_COLD_BALL 85
+#define TRAP_OF_FIRE_BALL 86
+#define TRAP_OF_PLASMA_BALL 87
+#define TRAP_OF_WATER_BALL 88
+#define TRAP_OF_LITE_BALL 89
+#define TRAP_OF_DARK_BALL 90
+#define TRAP_OF_SHARDS_BALL 91
+#define TRAP_OF_SOUND_BALL 92
+#define TRAP_OF_CONFUSION_BALL 93
+#define TRAP_OF_FORCE_BALL 94
+#define TRAP_OF_INERTIA_BALL 95
+#define TRAP_OF_MANA_BALL 96
+#define TRAP_OF_ICE_BALL 97
+#define TRAP_OF_CHAOS_BALL 98
+#define TRAP_OF_NETHER_BALL 99
+#define TRAP_OF_DISENCHANT_BALL 100
+#define TRAP_OF_NEXUS_BALL 101
+#define TRAP_OF_TIME_BALL 102
+#define TRAP_OF_GRAVITY_BALL 103
+
+#define TRAP_OF_ARROW_I 110
+#define TRAP_OF_ARROW_II 111
+#define TRAP_OF_ARROW_III 112
+#define TRAP_OF_ARROW_IV 113
+#define TRAP_OF_POISON_ARROW_I 114
+#define TRAP_OF_POISON_ARROW_II 115
+#define TRAP_OF_POISON_ARROW_III 116
+#define TRAP_OF_POISON_ARROW_IV 117
+#define TRAP_OF_DAGGER_I 118
+#define TRAP_OF_DAGGER_II 119
+#define TRAP_OF_POISON_DAGGER_I 120
+#define TRAP_OF_POISON_DAGGER_II 121
+#define TRAP_OF_ARROWS_I 122
+#define TRAP_OF_ARROWS_II 123
+#define TRAP_OF_ARROWS_III 124
+#define TRAP_OF_ARROWS_IV 125
+#define TRAP_OF_POISON_ARROWS_I 126
+#define TRAP_OF_POISON_ARROWS_II 127
+#define TRAP_OF_POISON_ARROWS_III 128
+#define TRAP_OF_POISON_ARROWS_IV 129
+#define TRAP_OF_DAGGERS_I 130
+#define TRAP_OF_DAGGERS_II 131
+#define TRAP_OF_POISON_DAGGERS_I 132
+#define TRAP_OF_POISON_DAGGERS_II 133
+
+#define TRAP_OF_DROP_ITEMS 140
+#define TRAP_OF_DROP_ALL_ITEMS 141
+#define TRAP_OF_DROP_EVERYTHING 142
+
+/* -SC- */
+#define TRAP_OF_FEMINITY 150
+#define TRAP_OF_MASCULINITY 151
+#define TRAP_OF_NEUTRALITY 152
+#define TRAP_OF_AGING 153
+#define TRAP_OF_GROWING 154
+#define TRAP_OF_SHRINKING 155
+#define TRAP_OF_ELDRITCH_HORROR 156
+/* XXX */
+#define TRAP_OF_DIVINE_ANGER 158
+#define TRAP_OF_DIVINE_WRATH 159
+#define TRAP_OF_HALLUCINATION 160
+
+#define TRAP_OF_ROCKET 161
+#define TRAP_OF_NUKE_BOLT 162
+#define TRAP_OF_DEATH_RAY 163
+#define TRAP_OF_HOLY_FIRE 164
+#define TRAP_OF_HELL_FIRE 165
+#define TRAP_OF_PSI_BOLT 166
+#define TRAP_OF_PSI_DRAIN 167
+#define TRAP_OF_NUKE_BALL 168
+#define TRAP_OF_PSI_BALL 169
+
+/* DG */
+#define TRAP_OF_ACQUIREMENT 170
+
+/* Runescrye */
+#define TRAP_G_ELEC_BOLT 171
+#define TRAP_G_POIS_BOLT 172
+#define TRAP_G_ACID_BOLT 173
+#define TRAP_G_COLD_BOLT 174
+#define TRAP_G_FIRE_BOLT 175
+
+/*** General index values ***/
+
+
+/*
+ * Legal restrictions for "summon_specific()"
+ */
+#define SUMMON_ANT 11
+#define SUMMON_SPIDER 12
+#define SUMMON_HOUND 13
+#define SUMMON_HYDRA 14
+#define SUMMON_ANGEL 15
+#define SUMMON_DEMON 16
+#define SUMMON_UNDEAD 17
+#define SUMMON_DRAGON 18
+#define SUMMON_HI_UNDEAD 21
+#define SUMMON_HI_DRAGON 22
+#define SUMMON_WRAITH 31
+#define SUMMON_UNIQUE 32
+#define SUMMON_BIZARRE1 33
+#define SUMMON_BIZARRE2 34
+#define SUMMON_BIZARRE3 35
+#define SUMMON_BIZARRE4 36
+#define SUMMON_BIZARRE5 37
+#define SUMMON_BIZARRE6 38
+#define SUMMON_HI_DEMON 39
+#define SUMMON_KIN 40
+#define SUMMON_DAWN 41
+#define SUMMON_ANIMAL 42
+#define SUMMON_ANIMAL_RANGER 43
+#define SUMMON_HI_UNDEAD_NO_UNIQUES 44
+#define SUMMON_HI_DRAGON_NO_UNIQUES 45
+#define SUMMON_NO_UNIQUES 46
+#define SUMMON_PHANTOM 47
+#define SUMMON_ELEMENTAL 48
+#define SUMMON_THUNDERLORD 49
+#define SUMMON_BLUE_HORROR 50
+#define SUMMON_BUG 51
+#define SUMMON_RNG 52
+#define SUMMON_MINE 53
+#define SUMMON_HUMAN 54
+#define SUMMON_SHADOWS 55
+#define SUMMON_GHOST 56
+#define SUMMON_QUYLTHULG 57
+#define SUMMON_LUA 58
+
+
+/*
+ * Spell types used by project(), and related functions.
+ */
+#define GF_ELEC 1
+#define GF_POIS 2
+#define GF_ACID 3
+#define GF_COLD 4
+#define GF_FIRE 5
+#define GF_UNBREATH 6
+#define GF_CORPSE_EXPL 7
+#define GF_MISSILE 10
+#define GF_ARROW 11
+#define GF_PLASMA 12
+#define GF_WAVE 13
+#define GF_WATER 14
+#define GF_LITE 15
+#define GF_DARK 16
+#define GF_LITE_WEAK 17
+#define GF_DARK_WEAK 18
+#define GF_SHARDS 20
+#define GF_SOUND 21
+#define GF_CONFUSION 22
+#define GF_FORCE 23
+#define GF_INERTIA 24
+#define GF_MANA 26
+#define GF_METEOR 27
+#define GF_ICE 28
+#define GF_CHAOS 30
+#define GF_NETHER 31
+#define GF_DISENCHANT 32
+#define GF_NEXUS 33
+#define GF_TIME 34
+#define GF_GRAVITY 35
+#define GF_KILL_WALL 40
+#define GF_KILL_DOOR 41
+#define GF_KILL_TRAP 42
+#define GF_MAKE_WALL 45
+#define GF_MAKE_DOOR 46
+#define GF_MAKE_TRAP 47
+#define GF_OLD_CLONE 51
+#define GF_OLD_POLY 52
+#define GF_OLD_HEAL 53
+#define GF_OLD_SPEED 54
+#define GF_OLD_SLOW 55
+#define GF_OLD_CONF 56
+#define GF_OLD_SLEEP 57
+#define GF_OLD_DRAIN 58
+#define GF_AWAY_UNDEAD 61
+#define GF_AWAY_EVIL 62
+#define GF_AWAY_ALL 63
+#define GF_TURN_UNDEAD 64
+#define GF_TURN_EVIL 65
+#define GF_TURN_ALL 66
+#define GF_DISP_UNDEAD 67
+#define GF_DISP_EVIL 68
+#define GF_DISP_ALL 69
+#define GF_DISP_DEMON 70 /* New types for Zangband begin here... */
+#define GF_DISP_LIVING 71
+#define GF_ROCKET 72
+#define GF_NUKE 73
+#define GF_MAKE_GLYPH 74
+#define GF_STASIS 75
+#define GF_STONE_WALL 76
+#define GF_DEATH_RAY 77
+#define GF_STUN 78
+#define GF_HOLY_FIRE 79
+#define GF_HELL_FIRE 80
+#define GF_DISINTEGRATE 81
+#define GF_CHARM 82
+#define GF_CONTROL_UNDEAD 83
+#define GF_CONTROL_ANIMAL 84
+#define GF_PSI 85
+#define GF_PSI_DRAIN 86
+#define GF_TELEKINESIS 87
+#define GF_JAM_DOOR 88
+#define GF_DOMINATION 89
+#define GF_DISP_GOOD 90
+#define GF_IDENTIFY 91
+#define GF_RAISE 92
+#define GF_STAR_IDENTIFY 93
+#define GF_DESTRUCTION 94
+#define GF_STUN_CONF 95
+#define GF_STUN_DAM 96
+#define GF_CONF_DAM 98
+#define GF_STAR_CHARM 99
+#define GF_IMPLOSION 100
+#define GF_LAVA_FLOW 101
+#define GF_FEAR 102
+#define GF_BETWEEN_GATE 103
+#define GF_WINDS_MANA 104
+#define GF_DEATH 105
+#define GF_CONTROL_DEMON 106
+#define GF_RAISE_DEMON 107
+#define GF_TRAP_DEMONSOUL 108
+#define GF_ATTACK 109
+#define GF_CHARM_UNMOVING 110
+#define MAX_GF 111
+
+/*
+ * Some things which induce learning
+ */
+#define DRS_ACID 1
+#define DRS_ELEC 2
+#define DRS_FIRE 3
+#define DRS_COLD 4
+#define DRS_POIS 5
+#define DRS_NETH 6
+#define DRS_LITE 7
+#define DRS_DARK 8
+#define DRS_FEAR 9
+#define DRS_CONF 10
+#define DRS_CHAOS 11
+#define DRS_DISEN 12
+#define DRS_BLIND 13
+#define DRS_NEXUS 14
+#define DRS_SOUND 15
+#define DRS_SHARD 16
+#define DRS_FREE 30
+#define DRS_MANA 31
+#define DRS_REFLECT 32
+
+
+
+/*
+ * Hack -- first "normal" artifact in the artifact list. All of
+ * the artifacts with indexes from 1 to 15 are "special" (lights,
+ * rings, amulets), and the ones from 16 to 127 are "normal".
+ */
+#define ART_MIN_NORMAL 16
+#define ART_MIN_SPECIAL 200
+
+
+/*
+ * Hack -- special "xtra" object powers
+ */
+
+/* Sustain one stat */
+#define EGO_XTRA_SUSTAIN 1
+
+/* High resist */
+#define EGO_XTRA_POWER 2
+
+/* Special ability */
+#define EGO_XTRA_ABILITY 3
+
+/*** Object flag values ***/
+
+
+/*
+ * Special Object Flags
+ */
+#define IDENT_SENSE 0x01 /* Item has been "sensed" */
+#define IDENT_FIXED 0x02 /* Item has been "haggled" */
+#define IDENT_EMPTY 0x04 /* Item charges are known */
+#define IDENT_KNOWN 0x08 /* Item abilities are known */
+#define IDENT_STOREB 0x10 /* Item is storebought !!!! */
+#define IDENT_MENTAL 0x20 /* Item information is known */
+#define IDENT_CURSED 0x40 /* Item is temporarily cursed */
+
+
+
+/*
+ * Special Monster Flags
+ */
+#define MFLAG_VIEW 0x00000001 /* Monster is in line of sight */
+#define MFLAG_QUEST 0x00000002 /* Monster is subject to a quest */
+#define MFLAG_PARTIAL 0x00000004 /* Monster is a partial summon */
+#define MFLAG_CONTROL 0x00000008 /* Monster is controlled */
+#define MFLAG_BORN 0x00000010 /* Monster is still being born */
+#define MFLAG_NICE 0x00000020 /* Monster is still being nice */
+#define MFLAG_SHOW 0x00000040 /* Monster is recently memorized */
+#define MFLAG_MARK 0x00000080 /* Monster is currently memorized */
+#define MFLAG_NO_DROP 0x00000100 /* Monster wont drop obj/corpse */
+#define MFLAG_QUEST2 0x00000200 /* Monster is subject to a quest */
+#define PERM_MFLAG_MASK ( \
+ MFLAG_QUEST | MFLAG_QUEST2 | \
+ MFLAG_PARTIAL | MFLAG_CONTROL | MFLAG_NO_DROP \
+ )
+
+
+/*
+ * As of 2.7.8, the "object flags" are valid for all objects, and as
+ * of 2.7.9, these flags are not actually stored with the object.
+ *
+ * Note that "flags1" contains all flags dependant on "pval" (including
+ * stat bonuses, but NOT stat sustainers), plus all "extra attack damage"
+ * flags (SLAY_XXX and BRAND_XXX).
+ *
+ * Note that "flags2" contains all "resistances" (including "Stat Sustainers",
+ * actual immunities, and resistances). Note that "Hold Life" is really an
+ * "immunity" to ExpLoss, and "Free Action" is "immunity to paralysis".
+ *
+ * Note that "flags3" contains everything else -- including the three "CURSED"
+ * flags, and the "BLESSED" flag, several "item display" parameters, some new
+ * flags for powerful Bows, and flags which affect the player in a "general"
+ * way (LITE, TELEPATHY, SEE_INVIS, SLOW_DIGEST, REGEN, FEATHER), including
+ * all the "general" curses (TELEPORT, AGGRAVATE, EXP_DRAIN). It also has
+ * four new flags called "ITEM_IGNORE_XXX" which lets an item specify that
+ * it can not be affected by various forms of destruction. This is NOT as
+ * powerful as actually granting resistance/immunity to the wearer.
+ */
+
+#define TR1_STR 0x00000001L /* STR += "pval" */
+#define TR1_INT 0x00000002L /* INT += "pval" */
+#define TR1_WIS 0x00000004L /* WIS += "pval" */
+#define TR1_DEX 0x00000008L /* DEX += "pval" */
+#define TR1_CON 0x00000010L /* CON += "pval" */
+#define TR1_CHR 0x00000020L /* CHR += "pval" */
+#define TR1_MANA 0x00000040L /* Mana multipler */
+#define TR1_SPELL 0x00000080L /* Spell power increase */
+#define TR1_STEALTH 0x00000100L /* Stealth += "pval" */
+#define TR1_SEARCH 0x00000200L /* Search += "pval" */
+#define TR1_INFRA 0x00000400L /* Infra += "pval" */
+#define TR1_TUNNEL 0x00000800L /* Tunnel += "pval" */
+#define TR1_SPEED 0x00001000L /* Speed += "pval" */
+#define TR1_BLOWS 0x00002000L /* Blows += "pval" */
+#define TR1_CHAOTIC 0x00004000L
+#define TR1_VAMPIRIC 0x00008000L
+#define TR1_SLAY_ANIMAL 0x00010000L
+#define TR1_SLAY_EVIL 0x00020000L
+#define TR1_SLAY_UNDEAD 0x00040000L
+#define TR1_SLAY_DEMON 0x00080000L
+#define TR1_SLAY_ORC 0x00100000L
+#define TR1_SLAY_TROLL 0x00200000L
+#define TR1_SLAY_GIANT 0x00400000L
+#define TR1_SLAY_DRAGON 0x00800000L
+#define TR1_KILL_DRAGON 0x01000000L /* Execute Dragon */
+#define TR1_VORPAL 0x02000000L /* Later */
+#define TR1_IMPACT 0x04000000L /* Cause Earthquakes */
+#define TR1_BRAND_POIS 0x08000000L
+#define TR1_BRAND_ACID 0x10000000L
+#define TR1_BRAND_ELEC 0x20000000L
+#define TR1_BRAND_FIRE 0x40000000L
+#define TR1_BRAND_COLD 0x80000000L
+#define TR1_NULL_MASK 0x00000000L
+
+#define TRAP2_AUTOMATIC_5 0x00000001L /* Trap automatically rearms itself, 1 in 5 failure */
+#define TRAP2_AUTOMATIC_99 0x00000002L /* Trap automatically rearms itself */
+#define TRAP2_KILL_GHOST 0x00000004L /* Trap also affects PASS_WALL creatures */
+#define TRAP2_TELEPORT_TO 0x00000008L /* After everything else, teleport to player */
+#define TRAP2_ONLY_DRAGON 0x00000010L /* Affect only dragons & other AFFECTed creatures */
+#define TRAP2_ONLY_DEMON 0x00000020L /* Affect only demons & other AFFECTed creatures */
+#define TRAP2_ONLY_ANIMAL 0x00000100L /* Affect only animals & other AFFECTed creatures */
+#define TRAP2_ONLY_UNDEAD 0x00000200L /* Affect only undead & others */
+#define TRAP2_ONLY_EVIL 0x00000400L /* Affect only evil creatures &c. */
+
+#define TRAP2_ONLY_MASK (TRAP2_ONLY_DRAGON | TRAP2_ONLY_DEMON | TRAP2_ONLY_ANIMAL | \
+ TRAP2_ONLY_UNDEAD | TRAP2_ONLY_EVIL )
+
+#define TR2_SUST_STR 0x00000001L
+#define TR2_SUST_INT 0x00000002L
+#define TR2_SUST_WIS 0x00000004L
+#define TR2_SUST_DEX 0x00000008L
+#define TR2_SUST_CON 0x00000010L
+#define TR2_SUST_CHR 0x00000020L
+#define TR2_INVIS 0x00000040L /* Invisibility */
+#define TR2_LIFE 0x00000080L /* Life multiplier */
+#define TR2_IM_ACID 0x00000100L
+#define TR2_IM_ELEC 0x00000200L
+#define TR2_IM_FIRE 0x00000400L
+#define TR2_IM_COLD 0x00000800L
+#define TR2_SENS_FIRE 0x00001000L /* Sensibility to fire */
+#define TR2_REFLECT 0x00002000L /* Reflect 'bolts' */
+#define TR2_FREE_ACT 0x00004000L /* Free Action */
+#define TR2_HOLD_LIFE 0x00008000L /* Hold Life */
+#define TR2_RES_ACID 0x00010000L
+#define TR2_RES_ELEC 0x00020000L
+#define TR2_RES_FIRE 0x00040000L
+#define TR2_RES_COLD 0x00080000L
+#define TR2_RES_POIS 0x00100000L
+#define TR2_RES_FEAR 0x00200000L
+#define TR2_RES_LITE 0x00400000L
+#define TR2_RES_DARK 0x00800000L
+#define TR2_RES_BLIND 0x01000000L
+#define TR2_RES_CONF 0x02000000L
+#define TR2_RES_SOUND 0x04000000L
+#define TR2_RES_SHARDS 0x08000000L
+#define TR2_RES_NETHER 0x10000000L
+#define TR2_RES_NEXUS 0x20000000L
+#define TR2_RES_CHAOS 0x40000000L
+#define TR2_RES_DISEN 0x80000000L
+#define TR2_NULL_MASK 0x00000000L
+
+#define TR3_SH_FIRE 0x00000001L /* Immolation (Fire) */
+#define TR3_SH_ELEC 0x00000002L /* Electric Sheath */
+#define TR3_AUTO_CURSE 0x00000004L /* The obj will recurse itself */
+#define TR3_DECAY 0x00000008L /* Decay */
+#define TR3_NO_TELE 0x00000010L /* Anti-teleportation */
+#define TR3_NO_MAGIC 0x00000020L /* Anti-magic */
+#define TR3_WRAITH 0x00000040L /* Wraithform */
+#define TR3_TY_CURSE 0x00000080L /* The Ancient Curse */
+#define TR3_EASY_KNOW 0x00000100L /* Aware -> Known */
+#define TR3_HIDE_TYPE 0x00000200L /* Hide "pval" description */
+#define TR3_SHOW_MODS 0x00000400L /* Always show Tohit/Todam */
+#define TR3_INSTA_ART 0x00000800L /* Item must be an artifact */
+#define TR3_FEATHER 0x00001000L /* Feather Falling */
+#define TR3_LITE1 0x00002000L /* lite radius 1 */
+#define TR3_SEE_INVIS 0x00004000L /* See Invisible */
+#define TR3_NORM_ART 0x00008000L /* Artifact in k_info */
+#define TR3_SLOW_DIGEST 0x00010000L /* Item slows down digestion */
+#define TR3_REGEN 0x00020000L /* Item induces regeneration */
+#define TR3_XTRA_MIGHT 0x00040000L /* Bows get extra multiplier */
+#define TR3_XTRA_SHOTS 0x00080000L /* Bows get extra shots */
+#define TR3_IGNORE_ACID 0x00100000L /* Item ignores Acid Damage */
+#define TR3_IGNORE_ELEC 0x00200000L /* Item ignores Elec Damage */
+#define TR3_IGNORE_FIRE 0x00400000L /* Item ignores Fire Damage */
+#define TR3_IGNORE_COLD 0x00800000L /* Item ignores Cold Damage */
+#define TR3_ACTIVATE 0x01000000L /* Item can be activated */
+#define TR3_DRAIN_EXP 0x02000000L /* Item drains Experience */
+#define TR3_TELEPORT 0x04000000L /* Item teleports player */
+#define TR3_AGGRAVATE 0x08000000L /* Item aggravates monsters */
+#define TR3_BLESSED 0x10000000L /* Item is Blessed */
+#define TR3_CURSED 0x20000000L /* Item is Cursed */
+#define TR3_HEAVY_CURSE 0x40000000L /* Item is Heavily Cursed */
+#define TR3_PERMA_CURSE 0x80000000L /* Item is Perma Cursed */
+#define TR3_NULL_MASK 0x00000000L
+
+
+#define TR4_NEVER_BLOW 0x00000001L /* Weapon can't attack */
+#define TR4_PRECOGNITION 0x00000002L /* Like activating the cheat mode */
+#define TR4_BLACK_BREATH 0x00000004L /* Tolkien's Black Breath */
+#define TR4_RECHARGE 0x00000008L /* For artifact Wands and Staffs */
+#define TR4_FLY 0x00000010L /* This one and ONLY this one allow you to fly over trees */
+#define TR4_DG_CURSE 0x00000020L /* The Ancient Morgothian Curse */
+#define TR4_COULD2H 0x00000040L /* Can wield it 2 Handed */
+#define TR4_MUST2H 0x00000080L /* Must wield it 2 Handed */
+#define TR4_LEVELS 0x00000100L /* Can gain exp/exp levels !! */
+#define TR4_CLONE 0x00000200L /* Can clone monsters */
+#define TR4_SPECIAL_GENE 0x00000400L /* The object can only be generated in special conditions like quests, special dungeons, ... */
+#define TR4_CLIMB 0x00000800L /* Allow climbing mountains */
+#define TR4_FAST_CAST 0x00001000L /* Rod is x2 time faster to use */
+#define TR4_CAPACITY 0x00002000L /* Rod can take x2 mana */
+#define TR4_CHARGING 0x00004000L /* Rod recharge faster */
+#define TR4_CHEAPNESS 0x00008000L /* Rod spells are cheaper(in mana cost) to cast */
+#define TR4_FOUNTAIN 0x00010000L /* Available as fountain (for potions) */
+#define TR4_ANTIMAGIC_50 0x00020000L /* Forbid magic */
+#define TR4_ANTIMAGIC_30 0x00040000L /* Forbid magic */
+#define TR4_ANTIMAGIC_20 0x00080000L /* Forbid magic */
+#define TR4_ANTIMAGIC_10 0x00100000L /* Forbid magic */
+#define TR4_EASY_USE 0x00200000L /* Easily activable */
+#define TR4_IM_NETHER 0x00400000L /* Immunity to nether */
+#define TR4_RECHARGED 0x00800000L /* Object has been recharged once */
+#define TR4_ULTIMATE 0x01000000L /* ULTIMATE artifact */
+#define TR4_AUTO_ID 0x02000000L /* Id stuff on floor */
+#define TR4_LITE2 0x04000000L /* lite radius 2 */
+#define TR4_LITE3 0x08000000L /* lite radius 3 */
+#define TR4_FUEL_LITE 0x10000000L /* fuelable lite */
+#define TR4_ART_EXP 0x20000000L /* Will accumulate xp */
+#define TR4_CURSE_NO_DROP 0x40000000L /* The obj wont be dropped */
+#define TR4_NO_RECHARGE 0x80000000L /* Object Cannot be recharged */
+#define TR4_NULL_MASK 0xFFFFFFFCL
+
+#define TR5_TEMPORARY 0x00000001L /* In timeout turns it is destroyed */
+#define TR5_DRAIN_MANA 0x00000002L /* Drains mana */
+#define TR5_DRAIN_HP 0x00000004L /* Drains hp */
+#define TR5_KILL_DEMON 0x00000008L /* Execute Demon */
+#define TR5_KILL_UNDEAD 0x00000010L /* Execute Undead */
+#define TR5_CRIT 0x00000020L /* More critical hits */
+#define TR5_ATTR_MULTI 0x00000040L /* Object shimmer -- only allowed in k_info */
+#define TR5_WOUNDING 0x00000080L /* Wounds monsters */
+#define TR5_FULL_NAME 0x00000100L /* Uses direct name from k_info */
+#define TR5_LUCK 0x00000200L /* Luck += pval */
+#define TR5_IMMOVABLE 0x00000400L /* Cannot move */
+#define TR5_SPELL_CONTAIN 0x00000800L /* Can contain a spell */
+#define TR5_RES_MORGUL 0x00001000L /* Is not shattered by morgul fiends(nazguls) */
+#define TR5_ACTIVATE_NO_WIELD 0x00002000L /* Can be 'A'ctivated without being wielded */
+#define TR5_MAGIC_BREATH 0x00004000L /* Can breath anywere */
+#define TR5_WATER_BREATH 0x00008000L /* Can breath underwater */
+#define TR5_WIELD_CAST 0x00010000L /* Need to be wielded to cast spelsl fomr it(if it can be wiekded) */
+
+/* ESP defines */
+#define ESP_ORC 0x00000001L
+#define ESP_TROLL 0x00000002L
+#define ESP_DRAGON 0x00000004L
+#define ESP_GIANT 0x00000008L
+#define ESP_DEMON 0x00000010L
+#define ESP_UNDEAD 0x00000020L
+#define ESP_EVIL 0x00000040L
+#define ESP_ANIMAL 0x00000080L
+#define ESP_THUNDERLORD 0x00000100L
+#define ESP_GOOD 0x00000200L
+#define ESP_NONLIVING 0x00000400L
+#define ESP_UNIQUE 0x00000800L
+#define ESP_SPIDER 0x00001000L
+#define ESP_ALL 0x80000000L
+
+/* Number of group of flags to choose from */
+#define MAX_FLAG_GROUP 12
+#define NEW_GROUP_CHANCE 40 /* Chance to get a new group */
+
+/*
+ * Hack masks for "pval-dependant" flags.
+ */
+#define TR1_PVAL_MASK \
+ (TR1_STR | TR1_INT | TR1_WIS | TR1_DEX | \
+ TR1_CON | TR1_CHR | \
+ TR1_STEALTH | TR1_SEARCH | TR1_INFRA | TR1_TUNNEL | \
+ TR1_SPEED | TR1_BLOWS | TR1_SPELL)
+
+#define TR5_PVAL_MASK \
+ (TR5_CRIT | TR5_LUCK)
+
+
+/*** Ego flags ***/
+#define ETR4_SUSTAIN 0x00000001L /* Ego-Item gives a Random Sustain */
+#define ETR4_OLD_RESIST 0x00000002L /* The old "extra power" random high resist */
+#define ETR4_ABILITY 0x00000004L /* Ego-Item has a random Sustain */
+#define ETR4_R_ELEM 0x00000008L /* Item resists Acid/Fire/Cold/Elec or Poison */
+#define ETR4_R_LOW 0x00000010L /* Item has a random low resist */
+#define ETR4_R_HIGH 0x00000020L /* Item has a random high resist */
+#define ETR4_R_ANY 0x00000040L /* Item has one additional resist */
+#define ETR4_R_DRAGON 0x00000080L /* Item gets "Dragon" Resist */
+#define ETR4_SLAY_WEAP 0x00000100L /* Special 'Slaying' bonus */
+#define ETR4_DAM_DIE 0x00000200L /* Item has an additional dam die */
+#define ETR4_DAM_SIZE 0x00000400L /* Item has greater damage dice */
+#define ETR4_PVAL_M1 0x00000800L /* Item has +1 to pval */
+#define ETR4_PVAL_M2 0x00001000L /* Item has +(up to 2) to pval */
+#define ETR4_PVAL_M3 0x00002000L /* Item has +(up to 3) to pval */
+#define ETR4_PVAL_M5 0x00004000L /* Item has +(up to 5) to pval */
+#define ETR4_AC_M1 0x00008000L /* Item has +1 to AC */
+#define ETR4_AC_M2 0x00010000L /* Item has +(up to 2) to AC */
+#define ETR4_AC_M3 0x00020000L /* Item has +(up to 3) to AC */
+#define ETR4_AC_M5 0x00040000L /* Item has +(up to 5) to AC */
+#define ETR4_TH_M1 0x00080000L /* Item has +1 to hit */
+#define ETR4_TH_M2 0x00100000L /* Item has +(up to 2) to hit */
+#define ETR4_TH_M3 0x00200000L /* Item has +(up to 3) to hit */
+#define ETR4_TH_M5 0x00400000L /* Item has +(up to 5) to hit */
+#define ETR4_TD_M1 0x00800000L /* Item has +1 to dam */
+#define ETR4_TD_M2 0x01000000L /* Item has +(up to 2) to dam */
+#define ETR4_TD_M3 0x02000000L /* Item has +(up to 3) to dam */
+#define ETR4_TD_M5 0x04000000L /* Item has +(up to 5) to dam */
+#define ETR4_R_P_ABILITY 0x08000000L /* Item has a random pval-affected ability */
+#define ETR4_R_STAT 0x10000000L /* Item affects a random stat */
+#define ETR4_R_STAT_SUST 0x20000000L /* Item affects a random stat & sustains it */
+#define ETR4_R_IMMUNITY 0x40000000L /* Item gives a random immunity */
+#define ETR4_LIMIT_BLOWS 0x80000000L /* switch the "limit blows" feature */
+
+/*** Features flags -- DG ***/
+#define FF1_NO_WALK 0x00000001L
+#define FF1_NO_VISION 0x00000002L
+#define FF1_CAN_LEVITATE 0x00000004L
+#define FF1_CAN_PASS 0x00000008L
+#define FF1_FLOOR 0x00000010L
+#define FF1_WALL 0x00000020L
+#define FF1_PERMANENT 0x00000040L
+#define FF1_CAN_FLY 0x00000080L
+#define FF1_REMEMBER 0x00000100L
+#define FF1_NOTICE 0x00000200L
+#define FF1_DONT_NOTICE_RUNNING 0x00000400L
+#define FF1_CAN_RUN 0x00000800L
+#define FF1_DOOR 0x00001000L
+#define FF1_SUPPORT_LIGHT 0x00002000L
+#define FF1_CAN_CLIMB 0x00004000L
+#define FF1_TUNNELABLE 0x00008000L
+#define FF1_WEB 0x00010000L
+#define FF1_ATTR_MULTI 0x00020000L
+#define FF1_SUPPORT_GROWTH 0x00040000L
+
+/*** Dungeon type flags -- DG ***/
+#define DF1_PRINCIPAL 0x00000001L /* Is a principal dungeon */
+#define DF1_MAZE 0x00000002L /* Is a maze-type dungeon */
+#define DF1_SMALLEST 0x00000004L /* Creates VERY small levels like The Maze */
+#define DF1_SMALL 0x00000008L /* Creates small levels like Dol Goldor */
+#define DF1_BIG 0x00000010L /* Creates big levels like Moria, and Angband dungeons */
+#define DF1_NO_DOORS 0x00000020L /* No doors on rooms, like Barrowdowns, Old Forest etc) */
+#define DF1_WATER_RIVER 0x00000040L /* Allow a single water streamer on a level */
+#define DF1_LAVA_RIVER 0x00000080L /* Allow a single lava streamer on a level */
+#define DF1_WATER_RIVERS 0x00000100L /* Allow multiple water streamers on a level */
+#define DF1_LAVA_RIVERS 0x00000200L /* Allow multiple lava streamers on a level */
+#define DF1_CAVE 0x00000400L /* Allow rooms */
+#define DF1_CAVERN 0x00000800L /* Allow cavern rooms */
+#define DF1_NO_UP 0x00001000L /* Disallow up stairs */
+#define DF1_HOT 0x00002000L /* Corpses on ground and in pack decay quicker through heat */
+#define DF1_COLD 0x00004000L /* Corpses on ground and in pack decay quicker through cold */
+#define DF1_FORCE_DOWN 0x00008000L /* No up stairs generated */
+#define DF1_FORGET 0x00010000L /* Features are forgotten, like the Maze and Illusory Castle */
+#define DF1_NO_DESTROY 0x00020000L /* No destroyed levels in dungeon */
+#define DF1_SAND_VEIN 0x00040000L /* Like in the sandworm lair */
+#define DF1_CIRCULAR_ROOMS 0x00080000L /* Allow circular rooms */
+#define DF1_EMPTY 0x00100000L /* Allow arena levels */
+#define DF1_DAMAGE_FEAT 0x00200000L
+#define DF1_FLAT 0x00400000L /* Creates paths to next areas at edge of level, like Barrowdowns */
+#define DF1_TOWER 0x00800000L /* You start at bottom and go up rather than the reverse */
+#define DF1_RANDOM_TOWNS 0x01000000L /* Allow random towns */
+#define DF1_DOUBLE 0x02000000L /* Creates double-walled dungeon like Helcaraxe and Erebor */
+#define DF1_LIFE_LEVEL 0x04000000L /* Creates dungeon level on modified 'game of life' algorithm */
+#define DF1_EVOLVE 0x08000000L /* Evolving, pulsing levels like Heart of the Earth */
+#define DF1_ADJUST_LEVEL_1 0x10000000L /* Minimum monster level will be equal to dungeon level */
+#define DF1_ADJUST_LEVEL_2 0x20000000L /* Minimum monster level will be double the dungeon level */
+#define DF1_NO_RECALL 0x40000000L /* No recall allowed */
+#define DF1_NO_STREAMERS 0x80000000L /* No streamers */
+
+#define DF2_ADJUST_LEVEL_1_2 0x00000001L /* Minimum monster level will be half the dungeon level */
+#define DF2_NO_SHAFT 0x00000002L /* No shafts */
+#define DF2_ADJUST_LEVEL_PLAYER 0x00000004L /* Uses player level*2 instead of dungeon level for other ADJUST_LEVEL flags */
+#define DF2_NO_TELEPORT 0x00000008L
+#define DF2_ASK_LEAVE 0x00000010L
+#define DF2_NO_STAIR 0x00000020L
+#define DF2_SPECIAL 0x00000040L
+#define DF2_NO_NEW_MONSTER 0x00000080L
+#define DF2_DESC 0x00000100L
+#define DF2_NO_GENO 0x00000200L
+#define DF2_NO_BREATH 0x00000400L /* Oups, cannot breath here */
+#define DF2_WATER_BREATH 0x00000800L /* Oups, cannot breath here, need water breathing */
+#define DF2_ELVEN 0x00001000L /* Try to create elven monster ego */
+#define DF2_DWARVEN 0x00002000L /* Try to create dwarven monster ego */
+#define DF2_NO_EASY_MOVE 0x00004000L /* Forbid stuff like teleport level, probability travel, ... */
+#define DF2_NO_RECALL_OUT 0x00008000L /* Cannot recall out of the place */
+#define DF2_DESC_ALWAYS 0x00010000L /* Always shows the desc */
+
+/*** Town flags ***/
+#define TOWN_REAL 0x01 /* Town is really present */
+#define TOWN_KNOWN 0x02 /* Town is found by the player */
+
+
+
+/*** Monster blow constants ***/
+
+#define MODIFY_AUX(o, n) ((o) = modify_aux((o), (n) >> 2, (n) & 3))
+#define MODIFY(o, n, min) MODIFY_AUX(o, n); (o) = ((o) < (min))?(min):(o)
+
+/*
+ * New monster blow methods
+ */
+#define RBM_ANY 0
+#define RBM_HIT 1
+#define RBM_TOUCH 2
+#define RBM_PUNCH 3
+#define RBM_KICK 4
+#define RBM_CLAW 5
+#define RBM_BITE 6
+#define RBM_STING 7
+#define RBM_XXX1 8
+#define RBM_BUTT 9
+#define RBM_CRUSH 10
+#define RBM_ENGULF 11
+#define RBM_CHARGE 12
+#define RBM_CRAWL 13
+#define RBM_DROOL 14
+#define RBM_SPIT 15
+#define RBM_EXPLODE 16
+#define RBM_GAZE 17
+#define RBM_WAIL 18
+#define RBM_SPORE 19
+#define RBM_XXX4 20
+#define RBM_BEG 21
+#define RBM_INSULT 22
+#define RBM_MOAN 23
+#define RBM_SHOW 24
+
+
+/*
+ * New monster blow effects
+ */
+#define RBE_ANY 0
+#define RBE_HURT 1
+#define RBE_POISON 2
+#define RBE_UN_BONUS 3
+#define RBE_UN_POWER 4
+#define RBE_EAT_GOLD 5
+#define RBE_EAT_ITEM 6
+#define RBE_EAT_FOOD 7
+#define RBE_EAT_LITE 8
+#define RBE_ACID 9
+#define RBE_ELEC 10
+#define RBE_FIRE 11
+#define RBE_COLD 12
+#define RBE_BLIND 13
+#define RBE_CONFUSE 14
+#define RBE_TERRIFY 15
+#define RBE_PARALYZE 16
+#define RBE_LOSE_STR 17
+#define RBE_LOSE_INT 18
+#define RBE_LOSE_WIS 19
+#define RBE_LOSE_DEX 20
+#define RBE_LOSE_CON 21
+#define RBE_LOSE_CHR 22
+#define RBE_LOSE_ALL 23
+#define RBE_SHATTER 24
+#define RBE_EXP_10 25
+#define RBE_EXP_20 26
+#define RBE_EXP_40 27
+#define RBE_EXP_80 28
+#define RBE_DISEASE 29
+#define RBE_TIME 30
+#define RBE_SANITY 31
+#define RBE_HALLU 32
+#define RBE_PARASITE 33
+#define RBE_ABOMINATION 34
+
+
+/*** Monster flag values (hard-coded) ***/
+
+#define MONSTER_LEVEL_MAX 150
+#define MONSTER_EXP(level) ((((level) > MONSTER_LEVEL_MAX)?MONSTER_LEVEL_MAX:(level)) * (((level) > MONSTER_LEVEL_MAX)?MONSTER_LEVEL_MAX:(level)) * (((level) > MONSTER_LEVEL_MAX)?MONSTER_LEVEL_MAX:(level)) * 6)
+
+/*
+ * New monster race bit flags
+ */
+#define RF1_UNIQUE 0x00000001 /* Unique Monster */
+#define RF1_QUESTOR 0x00000002 /* Quest Monster */
+#define RF1_MALE 0x00000004 /* Male gender */
+#define RF1_FEMALE 0x00000008 /* Female gender */
+#define RF1_CHAR_CLEAR 0x00000010 /* Absorbs symbol */
+#define RF1_CHAR_MULTI 0x00000020 /* Changes symbol */
+#define RF1_ATTR_CLEAR 0x00000040 /* Absorbs color */
+#define RF1_ATTR_MULTI 0x00000080 /* Changes color */
+#define RF1_FORCE_DEPTH 0x00000100 /* Start at "correct" depth */
+#define RF1_FORCE_MAXHP 0x00000200 /* Start with max hitpoints */
+#define RF1_FORCE_SLEEP 0x00000400 /* Start out sleeping */
+#define RF1_FORCE_EXTRA 0x00000800 /* Start out something */
+#define RF1_FRIEND 0x00001000 /* Arrive with a friend */
+#define RF1_FRIENDS 0x00002000 /* Arrive with some friends */
+#define RF1_ESCORT 0x00004000 /* Arrive with an escort */
+#define RF1_ESCORTS 0x00008000 /* Arrive with some escorts */
+#define RF1_NEVER_BLOW 0x00010000 /* Never make physical blow */
+#define RF1_NEVER_MOVE 0x00020000 /* Never make physical move */
+#define RF1_RAND_25 0x00040000 /* Moves randomly (25%) */
+#define RF1_RAND_50 0x00080000 /* Moves randomly (50%) */
+#define RF1_ONLY_GOLD 0x00100000 /* Drop only gold */
+#define RF1_ONLY_ITEM 0x00200000 /* Drop only items */
+#define RF1_DROP_60 0x00400000 /* Drop an item/gold (60%) */
+#define RF1_DROP_90 0x00800000 /* Drop an item/gold (90%) */
+#define RF1_DROP_1D2 0x01000000 /* Drop 1d2 items/gold */
+#define RF1_DROP_2D2 0x02000000 /* Drop 2d2 items/gold */
+#define RF1_DROP_3D2 0x04000000 /* Drop 3d2 items/gold */
+#define RF1_DROP_4D2 0x08000000 /* Drop 4d2 items/gold */
+#define RF1_DROP_GOOD 0x10000000 /* Drop good items */
+#define RF1_DROP_GREAT 0x20000000 /* Drop great items */
+#define RF1_DROP_USEFUL 0x40000000 /* Drop "useful" items */
+#define RF1_DROP_CHOSEN 0x80000000 /* Drop "chosen" items */
+
+/*
+ * New monster race bit flags
+ */
+#define RF2_STUPID 0x00000001 /* Monster is stupid */
+#define RF2_SMART 0x00000002 /* Monster is smart */
+#define RF2_CAN_SPEAK 0x00000004 /* TY: can speak */
+#define RF2_REFLECTING 0x00000008 /* Reflects bolts */
+#define RF2_INVISIBLE 0x00000010 /* Monster avoids vision */
+#define RF2_COLD_BLOOD 0x00000020 /* Monster avoids infra */
+#define RF2_EMPTY_MIND 0x00000040 /* Monster avoids telepathy */
+#define RF2_WEIRD_MIND 0x00000080 /* Monster avoids telepathy? */
+#define RF2_DEATH_ORB 0x00000100 /* Death Orb */
+#define RF2_REGENERATE 0x00000200 /* Monster regenerates */
+#define RF2_SHAPECHANGER 0x00000400 /* TY: shapechanger */
+#define RF2_ATTR_ANY 0x00000800 /* TY: Attr_any */
+#define RF2_POWERFUL 0x00001000 /* Monster has strong breath */
+#define RF2_ELDRITCH_HORROR 0x00002000 /* Sanity-blasting horror */
+#define RF2_AURA_FIRE 0x00004000 /* Burns in melee */
+#define RF2_AURA_ELEC 0x00008000 /* Shocks in melee */
+#define RF2_OPEN_DOOR 0x00010000 /* Monster can open doors */
+#define RF2_BASH_DOOR 0x00020000 /* Monster can bash doors */
+#define RF2_PASS_WALL 0x00040000 /* Monster can pass walls */
+#define RF2_KILL_WALL 0x00080000 /* Monster can destroy walls */
+#define RF2_MOVE_BODY 0x00100000 /* Monster can move monsters */
+#define RF2_KILL_BODY 0x00200000 /* Monster can kill monsters */
+#define RF2_TAKE_ITEM 0x00400000 /* Monster can pick up items */
+#define RF2_KILL_ITEM 0x00800000 /* Monster can crush items */
+#define RF2_BRAIN_1 0x01000000
+#define RF2_BRAIN_2 0x02000000
+#define RF2_BRAIN_3 0x04000000
+#define RF2_BRAIN_4 0x08000000
+#define RF2_BRAIN_5 0x10000000
+#define RF2_BRAIN_6 0x20000000
+#define RF2_BRAIN_7 0x40000000
+#define RF2_BRAIN_8 0x80000000
+
+/*
+ * New monster race bit flags
+ */
+#define RF3_ORC 0x00000001 /* Orc */
+#define RF3_TROLL 0x00000002 /* Troll */
+#define RF3_GIANT 0x00000004 /* Giant */
+#define RF3_DRAGON 0x00000008 /* Dragon */
+#define RF3_DEMON 0x00000010 /* Demon */
+#define RF3_UNDEAD 0x00000020 /* Undead */
+#define RF3_EVIL 0x00000040 /* Evil */
+#define RF3_ANIMAL 0x00000080 /* Animal */
+#define RF3_THUNDERLORD 0x00000100 /* DG: Thunderlord */
+#define RF3_GOOD 0x00000200 /* Good */
+#define RF3_AURA_COLD 0x00000400 /* Freezes in melee */
+#define RF3_NONLIVING 0x00000800 /* TY: Non-Living (?) */
+#define RF3_HURT_LITE 0x00001000 /* Hurt by lite */
+#define RF3_HURT_ROCK 0x00002000 /* Hurt by rock remover */
+#define RF3_SUSCEP_FIRE 0x00004000 /* Hurt badly by fire */
+#define RF3_SUSCEP_COLD 0x00008000 /* Hurt badly by cold */
+#define RF3_IM_ACID 0x00010000 /* Resist acid a lot */
+#define RF3_IM_ELEC 0x00020000 /* Resist elec a lot */
+#define RF3_IM_FIRE 0x00040000 /* Resist fire a lot */
+#define RF3_IM_COLD 0x00080000 /* Resist cold a lot */
+#define RF3_IM_POIS 0x00100000 /* Resist poison a lot */
+#define RF3_RES_TELE 0x00200000 /* Resist teleportation */
+#define RF3_RES_NETH 0x00400000 /* Resist nether a lot */
+#define RF3_RES_WATE 0x00800000 /* Resist water */
+#define RF3_RES_PLAS 0x01000000 /* Resist plasma */
+#define RF3_RES_NEXU 0x02000000 /* Resist nexus */
+#define RF3_RES_DISE 0x04000000 /* Resist disenchantment */
+#define RF3_UNIQUE_4 0x08000000 /* Is a "Nazgul" unique */
+#define RF3_NO_FEAR 0x10000000 /* Cannot be scared */
+#define RF3_NO_STUN 0x20000000 /* Cannot be stunned */
+#define RF3_NO_CONF 0x40000000 /* Cannot be confused */
+#define RF3_NO_SLEEP 0x80000000 /* Cannot be slept */
+
+/*
+ * New monster race bit flags
+ */
+#define RF4_SHRIEK 0x00000001 /* Shriek for help */
+#define RF4_MULTIPLY 0x00000002 /* Monster reproduces */
+#define RF4_S_ANIMAL 0x00000004 /* Summon animals */
+#define RF4_ROCKET 0x00000008 /* TY: Rocket */
+#define RF4_ARROW_1 0x00000010 /* Fire an arrow (light) */
+#define RF4_ARROW_2 0x00000020 /* Fire an arrow (heavy) */
+#define RF4_ARROW_3 0x00000040 /* Fire missiles (light) */
+#define RF4_ARROW_4 0x00000080 /* Fire missiles (heavy) */
+#define RF4_BR_ACID 0x00000100 /* Breathe Acid */
+#define RF4_BR_ELEC 0x00000200 /* Breathe Elec */
+#define RF4_BR_FIRE 0x00000400 /* Breathe Fire */
+#define RF4_BR_COLD 0x00000800 /* Breathe Cold */
+#define RF4_BR_POIS 0x00001000 /* Breathe Poison */
+#define RF4_BR_NETH 0x00002000 /* Breathe Nether */
+#define RF4_BR_LITE 0x00004000 /* Breathe Lite */
+#define RF4_BR_DARK 0x00008000 /* Breathe Dark */
+#define RF4_BR_CONF 0x00010000 /* Breathe Confusion */
+#define RF4_BR_SOUN 0x00020000 /* Breathe Sound */
+#define RF4_BR_CHAO 0x00040000 /* Breathe Chaos */
+#define RF4_BR_DISE 0x00080000 /* Breathe Disenchant */
+#define RF4_BR_NEXU 0x00100000 /* Breathe Nexus */
+#define RF4_BR_TIME 0x00200000 /* Breathe Time */
+#define RF4_BR_INER 0x00400000 /* Breathe Inertia */
+#define RF4_BR_GRAV 0x00800000 /* Breathe Gravity */
+#define RF4_BR_SHAR 0x01000000 /* Breathe Shards */
+#define RF4_BR_PLAS 0x02000000 /* Breathe Plasma */
+#define RF4_BR_WALL 0x04000000 /* Breathe Force */
+#define RF4_BR_MANA 0x08000000 /* Breathe Mana */
+#define RF4_BA_NUKE 0x10000000 /* TY: Nuke Ball */
+#define RF4_BR_NUKE 0x20000000 /* TY: Toxic Breath */
+#define RF4_BA_CHAO 0x40000000 /* Chaos Ball */
+#define RF4_BR_DISI 0x80000000 /* Breathe Disintegration */
+
+/*
+ * New monster race bit flags
+ */
+#define RF5_BA_ACID 0x00000001 /* Acid Ball */
+#define RF5_BA_ELEC 0x00000002 /* Elec Ball */
+#define RF5_BA_FIRE 0x00000004 /* Fire Ball */
+#define RF5_BA_COLD 0x00000008 /* Cold Ball */
+#define RF5_BA_POIS 0x00000010 /* Poison Ball */
+#define RF5_BA_NETH 0x00000020 /* Nether Ball */
+#define RF5_BA_WATE 0x00000040 /* Water Ball */
+#define RF5_BA_MANA 0x00000080 /* Mana Storm */
+#define RF5_BA_DARK 0x00000100 /* Darkness Storm */
+#define RF5_DRAIN_MANA 0x00000200 /* Drain Mana */
+#define RF5_MIND_BLAST 0x00000400 /* Blast Mind */
+#define RF5_BRAIN_SMASH 0x00000800 /* Smash Brain */
+#define RF5_CAUSE_1 0x00001000 /* Cause Light Wound */
+#define RF5_CAUSE_2 0x00002000 /* Cause Serious Wound */
+#define RF5_CAUSE_3 0x00004000 /* Cause Critical Wound */
+#define RF5_CAUSE_4 0x00008000 /* Cause Mortal Wound */
+#define RF5_BO_ACID 0x00010000 /* Acid Bolt */
+#define RF5_BO_ELEC 0x00020000 /* Elec Bolt (unused) */
+#define RF5_BO_FIRE 0x00040000 /* Fire Bolt */
+#define RF5_BO_COLD 0x00080000 /* Cold Bolt */
+#define RF5_BO_POIS 0x00100000 /* Poison Bolt (unused) */
+#define RF5_BO_NETH 0x00200000 /* Nether Bolt */
+#define RF5_BO_WATE 0x00400000 /* Water Bolt */
+#define RF5_BO_MANA 0x00800000 /* Mana Bolt */
+#define RF5_BO_PLAS 0x01000000 /* Plasma Bolt */
+#define RF5_BO_ICEE 0x02000000 /* Ice Bolt */
+#define RF5_MISSILE 0x04000000 /* Magic Missile */
+#define RF5_SCARE 0x08000000 /* Frighten Player */
+#define RF5_BLIND 0x10000000 /* Blind Player */
+#define RF5_CONF 0x20000000 /* Confuse Player */
+#define RF5_SLOW 0x40000000 /* Slow Player */
+#define RF5_HOLD 0x80000000 /* Paralyze Player */
+
+/*
+ * New monster race bit flags
+ */
+#define RF6_HASTE 0x00000001 /* Speed self */
+#define RF6_HAND_DOOM 0x00000002 /* Hand of Doom */
+#define RF6_HEAL 0x00000004 /* Heal self */
+#define RF6_S_ANIMALS 0x00000008 /* Summon animals */
+#define RF6_BLINK 0x00000010 /* Teleport Short */
+#define RF6_TPORT 0x00000020 /* Teleport Long */
+#define RF6_TELE_TO 0x00000040 /* Move player to monster */
+#define RF6_TELE_AWAY 0x00000080 /* Move player far away */
+#define RF6_TELE_LEVEL 0x00000100 /* Move player vertically */
+#define RF6_DARKNESS 0x00000200 /* Create Darkness */
+#define RF6_TRAPS 0x00000400 /* Create Traps */
+#define RF6_FORGET 0x00000800 /* Cause amnesia */
+#define RF6_RAISE_DEAD 0x00001000 /* Raise Dead */
+#define RF6_S_BUG 0x00002000 /* Summon Software bug */
+#define RF6_S_RNG 0x00004000 /* Summon RNG */
+#define RF6_S_THUNDERLORD 0x00008000 /* Summon Thunderlords */
+#define RF6_S_KIN 0x00010000 /* Summon "kin" */
+#define RF6_S_HI_DEMON 0x00020000 /* Summon greater demons! */
+#define RF6_S_MONSTER 0x00040000 /* Summon Monster */
+#define RF6_S_MONSTERS 0x00080000 /* Summon Monsters */
+#define RF6_S_ANT 0x00100000 /* Summon Ants */
+#define RF6_S_SPIDER 0x00200000 /* Summon Spiders */
+#define RF6_S_HOUND 0x00400000 /* Summon Hounds */
+#define RF6_S_HYDRA 0x00800000 /* Summon Hydras */
+#define RF6_S_ANGEL 0x01000000 /* Summon Angel */
+#define RF6_S_DEMON 0x02000000 /* Summon Demon */
+#define RF6_S_UNDEAD 0x04000000 /* Summon Undead */
+#define RF6_S_DRAGON 0x08000000 /* Summon Dragon */
+#define RF6_S_HI_UNDEAD 0x10000000 /* Summon Greater Undead */
+#define RF6_S_HI_DRAGON 0x20000000 /* Summon Ancient Dragon */
+#define RF6_S_WRAITH 0x40000000 /* Summon Unique Wraith */
+#define RF6_S_UNIQUE 0x80000000 /* Summon Unique Monster */
+
+/*
+ * New monster race bit flags
+ */
+#define RF7_AQUATIC 0x00000001 /* Aquatic monster */
+#define RF7_CAN_SWIM 0x00000002 /* Monster can swim */
+#define RF7_CAN_FLY 0x00000004 /* Monster can fly */
+#define RF7_FRIENDLY 0x00000008 /* Monster is friendly */
+#define RF7_PET 0x00000010 /* Monster is a pet */
+#define RF7_MORTAL 0x00000020 /* Monster is a mortal being */
+#define RF7_SPIDER 0x00000040 /* Monster is a spider (can pass webs) */
+#define RF7_NAZGUL 0x00000080 /* Monster is a Nazgul */
+#define RF7_DG_CURSE 0x00000100 /* If killed the monster grant a DG Curse to the player */
+#define RF7_POSSESSOR 0x00000200 /* Is it a dreaded possessor monster ? */
+#define RF7_NO_DEATH 0x00000400 /* Cannot be killed */
+#define RF7_NO_TARGET 0x00000800 /* Cannot be targeted */
+#define RF7_AI_ANNOY 0x00001000 /* Try to tease the player */
+#define RF7_AI_SPECIAL 0x00002000 /* For quests */
+#define RF7_NEUTRAL 0x00004000 /* Monster is neutral */
+#define RF7_DROP_ART 0x00008000 /* Monster drop one art */
+#define RF7_DROP_RANDART 0x00010000 /* Monster drop one randart */
+#define RF7_AI_PLAYER 0x00020000 /* Controlled by the player */
+#define RF7_NO_THEFT 0x00040000 /* Monster is immune to theft */
+#define RF7_SPIRIT 0x00080000 /* This is a Spirit, coming from the Void */
+#define RF7_IM_MELEE 0x00100000 /* IM melee */
+
+
+/*
+ * Monster race flags
+ */
+#define RF8_DUNGEON 0x00000001
+#define RF8_WILD_TOWN 0x00000002
+#define RF8_XXX8X02 0x00000004
+#define RF8_WILD_SHORE 0x00000008
+#define RF8_WILD_OCEAN 0x00000010
+#define RF8_WILD_WASTE 0x00000020
+#define RF8_WILD_WOOD 0x00000040
+#define RF8_WILD_VOLCANO 0x00000080
+#define RF8_XXX8X08 0x00000100
+#define RF8_WILD_MOUNTAIN 0x00000200
+#define RF8_WILD_GRASS 0x00000400
+#define RF8_NO_CUT 0x00000800
+#define RF8_CTHANGBAND 0x00001000 /* Not used in ToME */
+/* XXX */
+#define RF8_ZANGBAND 0x00004000 /* Not used in ToME */
+#define RF8_JOKEANGBAND 0x00008000
+#define RF8_ANGBAND 0x00010000
+
+#define RF8_WILD_TOO 0x80000000
+
+
+/*
+ * Monster race flags
+ */
+#define RF9_DROP_CORPSE 0x00000001
+#define RF9_DROP_SKELETON 0x00000002
+#define RF9_HAS_LITE 0x00000004 /* Carries a lite */
+#define RF9_MIMIC 0x00000008 /* *REALLY* looks like an object ... only nastier */
+#define RF9_HAS_EGG 0x00000010 /* Can be monster's eggs */
+#define RF9_IMPRESED 0x00000020 /* The monster can follow you on each level until he dies */
+#define RF9_SUSCEP_ACID 0x00000040 /* Susceptible to acid */
+#define RF9_SUSCEP_ELEC 0x00000080 /* Susceptible to lightning */
+#define RF9_SUSCEP_POIS 0x00000100 /* Susceptible to poison */
+#define RF9_KILL_TREES 0x00000200 /* Monster can eat trees */
+#define RF9_WYRM_PROTECT 0x00000400 /* The monster is protected by great wyrms of power: They'll be summoned if it's killed */
+#define RF9_DOPPLEGANGER 0x00000800 /* The monster looks like you */
+#define RF9_ONLY_DEPTH 0x00001000 /* The monster can only be generated at the GIVEN depth */
+#define RF9_SPECIAL_GENE 0x00002000 /* The monster can only be generated in special conditions like quests, special dungeons, ... */
+#define RF9_NEVER_GENE 0x00004000 /* The monster cannot be normaly generated */
+
+
+/*
+ * Hack -- choose "intelligent" spells when desperate
+ */
+
+#define RF4_INT_MASK \
+ (RF4_S_ANIMAL)
+
+#define RF5_INT_MASK \
+ (RF5_HOLD | RF5_SLOW | RF5_CONF | RF5_BLIND | RF5_SCARE)
+
+#define RF6_INT_MASK \
+ (RF6_BLINK | RF6_TPORT | RF6_TELE_LEVEL | RF6_TELE_AWAY | \
+ RF6_HEAL | RF6_HASTE | RF6_TRAPS | \
+ RF6_S_KIN | RF6_S_HI_DEMON | RF6_S_MONSTER | RF6_S_MONSTERS | \
+ RF6_S_ANT | RF6_S_SPIDER | RF6_S_HOUND | RF6_S_HYDRA | \
+ RF6_S_ANGEL | RF6_S_DRAGON | RF6_S_UNDEAD | RF6_S_DEMON | \
+ RF6_S_HI_DRAGON | RF6_S_HI_UNDEAD | RF6_S_WRAITH | RF6_S_UNIQUE | \
+ RF6_S_THUNDERLORD | RF6_S_BUG | RF6_S_RNG | RF6_S_ANIMALS)
+
+
+/*
+ * Hack -- "bolt" spells that may hurt fellow monsters
+ */
+#define RF4_BOLT_MASK \
+ (RF4_ARROW_1 | RF4_ARROW_2 | RF4_ARROW_3 | RF4_ARROW_4)
+
+#define RF5_BOLT_MASK \
+ (RF5_BO_ACID | RF5_BO_ELEC | RF5_BO_FIRE | RF5_BO_COLD | \
+ RF5_BO_POIS | RF5_BO_NETH | RF5_BO_WATE | RF5_BO_MANA | \
+ RF5_BO_PLAS | RF5_BO_ICEE | RF5_MISSILE)
+
+#define RF6_BOLT_MASK \
+ 0L
+
+
+/* Hack -- summon spells */
+
+#define RF4_SUMMON_MASK \
+ (RF4_S_ANIMAL)
+
+#define RF5_SUMMON_MASK \
+ 0L
+
+#define RF6_SUMMON_MASK \
+ (RF6_S_KIN | RF6_S_HI_DEMON | RF6_S_MONSTER | RF6_S_MONSTERS | RF6_S_ANT | \
+ RF6_S_SPIDER | RF6_S_HOUND | RF6_S_HYDRA | RF6_S_ANGEL | RF6_S_DEMON | \
+ RF6_S_UNDEAD | RF6_S_DRAGON | RF6_S_HI_UNDEAD | RF6_S_HI_DRAGON | \
+ RF6_S_WRAITH | RF6_S_UNIQUE | RF6_S_THUNDERLORD | RF6_S_BUG | RF6_S_RNG | \
+ RF6_S_ANIMALS)
+
+
+/*** Macro Definitions ***/
+
+
+/*
+ * Hack -- The main "screen"
+ */
+#define term_screen (angband_term[0])
+
+
+/*
+ * Determine if a given inventory item is "aware"
+ */
+#define object_aware_p(T) \
+ (k_info[(T)->k_idx].aware)
+
+/*
+ * Determine if a given inventory item is "tried"
+ */
+#define object_tried_p(T) \
+ (k_info[(T)->k_idx].tried)
+
+
+/*
+ * Determine if a given inventory item is "known"
+ * Test One -- Check for special "known" tag
+ * Test Two -- Check for "Easy Know" + "Aware"
+ */
+#define object_known_p(T) \
+ (((T)->ident & (IDENT_KNOWN)) || \
+ (k_info[(T)->k_idx].easy_know && k_info[(T)->k_idx].aware))
+
+
+/*
+ * Return the "attr" for a given item.
+ * Use "flavor" if available.
+ * Default to user definitions.
+ */
+#define object_attr(T) \
+ (((T)->tval == TV_RANDART) ? \
+ random_artifacts[(T)->sval].attr : \
+ (k_info[(T)->k_idx].flavor) ? \
+ misc_to_attr[k_info[(T)->k_idx].flavor] : \
+ k_info[(T)->k_idx].x_attr)
+
+#define object_attr_default(T) \
+ (((T)->tval == TV_RANDART) ? \
+ random_artifacts[(T)->sval].attr : \
+ (k_info[(T)->k_idx].flavor) ? \
+ misc_to_attr[k_info[(T)->k_idx].flavor] : \
+ k_info[(T)->k_idx].d_attr)
+
+/*
+ * Return the "char" for a given item.
+ * Use "flavor" if available.
+ * Default to user definitions.
+ */
+#define object_char(T) \
+ ((k_info[(T)->k_idx].flavor) ? \
+ misc_to_char[k_info[(T)->k_idx].flavor] : \
+ k_info[(T)->k_idx].x_char)
+
+#define object_char_default(T) \
+ ((k_info[(T)->k_idx].flavor) ? \
+ misc_to_char[k_info[(T)->k_idx].flavor] : \
+ k_info[(T)->k_idx].d_char)
+
+
+
+/*
+ * Artifacts use the "name1" field
+ */
+#define artifact_p(T) \
+ ( \
+ ((T)->tval == TV_RANDART || \
+ ((T)->name1 ? TRUE : FALSE) || \
+ ((T)->art_name ? TRUE : FALSE) || \
+ ((k_info[(T)->k_idx].flags3 & TR3_NORM_ART)? TRUE : FALSE)) \
+ )
+
+/*
+ * Ego-Items use the "name2" field
+ */
+#define ego_item_p(T) \
+ ((T)->name2 || (T)->name2b ? TRUE : FALSE)
+
+/*
+ * Ego-Items use the "name2" field
+ */
+#define is_ego_p(T, e) \
+ (((T)->name2 == (e)) || ((T)->name2b == (e)))
+
+
+
+/*
+ * Cursed items.
+ */
+#define cursed_p(T) \
+ ((T)->ident & (IDENT_CURSED))
+
+
+/*
+ * Convert an "attr"/"char" pair into a "pict" (P)
+ */
+#define PICT(A,C) \
+ ((((u16b)(A)) << 8) | ((byte)(C)))
+
+/*
+ * Convert a "pict" (P) into an "attr" (A)
+ */
+#define PICT_A(P) \
+ ((byte)((P) >> 8))
+
+/*
+ * Convert a "pict" (P) into an "char" (C)
+ */
+#define PICT_C(P) \
+ ((char)((byte)(P)))
+
+
+/*
+ * Convert a "location" (Y,X) into a "grid" (G)
+ */
+#define GRID(Y,X) \
+ (256 * (Y) + (X))
+
+/*
+ * Convert a "grid" (G) into a "location" (Y)
+ */
+#define GRID_Y(G) \
+ ((int)((G) / 256U))
+
+/*
+ * Convert a "grid" (G) into a "location" (X)
+ */
+#define GRID_X(G) \
+ ((int)((G) % 256U))
+
+
+/*
+ * Determines if a map location is fully inside the outer walls
+ */
+#define in_bounds(Y,X) \
+ (((Y) > 0) && ((X) > 0) && ((Y) < cur_hgt-1) && ((X) < cur_wid-1))
+
+/*
+ * Determines if a map location is on or inside the outer walls
+ */
+#define in_bounds2(Y,X) \
+ (((Y) >= 0) && ((X) >= 0) && ((Y) < cur_hgt) && ((X) < cur_wid))
+
+
+/*
+ * Determines if a map location is currently "on screen" -RAK-
+ * Note that "panel_contains(Y,X)" always implies "in_bounds2(Y,X)".
+ */
+#define panel_contains(Y,X) \
+ (((Y) >= panel_row_min) && ((Y) <= panel_row_max) && \
+ ((X) >= panel_col_min) && ((X) <= panel_col_max))
+
+
+
+/*
+ * Determine if a "legal" grid is a "floor" grid
+ *
+ * Line 1 -- forbid doors, rubble, seams, walls
+ *
+ * Note that the terrain features are split by a one bit test
+ * into those features which block line of sight and those that
+ * do not, allowing an extremely fast single bit check below.
+ *
+ * Add in the fact that some new terrain (water & lava) do NOT block sight
+ * -KMW-
+ */
+#define cave_floor_bold(Y,X) \
+ ((f_info[cave[Y][X].feat].flags1 & FF1_FLOOR) && \
+ (cave[Y][X].feat != FEAT_MON_TRAP))
+
+
+/*
+ * Determine if a "legal" grid is floor without the REMEMBER flag set
+ * Sometimes called "boring" grid
+ */
+#define cave_plain_floor_bold(Y,X) \
+ ((f_info[cave[Y][X].feat].flags1 & FF1_FLOOR) && \
+ !(f_info[cave[Y][X].feat].flags1 & FF1_REMEMBER))
+
+
+/*
+ * Determine if a "legal" grid isn't a "blocking line of sight" grid
+ *
+ * Line 1 -- forbid doors, rubble, seams, walls
+ *
+ * Note that the terrain features are split by a one bit test
+ * into those features which block line of sight and those that
+ * do not, allowing an extremely fast single bit check below.
+ *
+ * Add in the fact that some new terrain (water & lava) do NOT block sight
+ * -KMW-
+ */
+#define cave_sight_bold(Y,X) \
+ (!(f_info[cave[Y][X].feat].flags1 & FF1_NO_VISION))
+
+
+/*
+ * Determine if a "legal" grid is a "clean" floor grid
+ *
+ * Line 1 -- forbid non-floors
+ * Line 2 -- forbid deep water -KMW-
+ * Line 3 -- forbid deep lava -KMW-
+ * Line 4 -- forbid normal objects
+ */
+#define cave_clean_bold(Y,X) \
+ ((f_info[cave[Y][X].feat].flags1 & FF1_FLOOR) && \
+ (cave[Y][X].feat != FEAT_MON_TRAP) && \
+ (cave[Y][X].o_idx == 0) && \
+ !(f_info[cave[Y][X].feat].flags1 & FF1_PERMANENT))
+
+
+/*
+ * Determine if a "legal" grid is an "empty" floor grid
+ *
+ * Line 1 -- forbid doors, rubble, seams, walls
+ * Line 2 -- forbid normal monsters
+ * Line 3 -- forbid the player
+ */
+#define cave_empty_bold(Y,X) \
+ (cave_floor_bold(Y,X) && \
+ !(cave[Y][X].m_idx) && \
+ !(((Y) == p_ptr->py) && ((X) == p_ptr->px)))
+
+
+/*
+ * Determine if a "legal" grid is an "naked" floor grid
+ *
+ * Line 1 -- forbid non-floors, non-shallow water & lava -KMW-
+ * Line 2 -- forbid normal objects
+ * Line 3 -- forbid player/monsters
+ */
+#define cave_naked_bold(Y,X) \
+ ((f_info[cave[Y][X].feat].flags1 & FF1_FLOOR) && \
+ (cave[Y][X].feat != FEAT_MON_TRAP) && \
+ !(f_info[cave[Y][X].feat].flags1 & FF1_PERMANENT) && \
+ (cave[Y][X].o_idx == 0) && \
+ (cave[Y][X].m_idx == 0))
+
+#define cave_naked_bold2(Y,X) \
+ ((f_info[cave[Y][X].feat].flags1 & FF1_FLOOR) && \
+ (cave[Y][X].feat != FEAT_MON_TRAP) && \
+ (cave[Y][X].o_idx == 0) && \
+ (cave[Y][X].m_idx == 0))
+
+
+
+/*
+ * Determine if a "legal" grid is "permanent"
+ *
+ * Line 1 -- perma-walls
+ * Line 2-3 -- stairs
+ * Line 4-5 -- building doors -KMW-
+ * Line 6-7 -- shop doors
+ */
+#define cave_perma_bold(Y,X) \
+ (f_info[cave[Y][X].feat].flags1 & FF1_PERMANENT)
+
+
+/*
+ * Grid based version of "cave_floor_bold()"
+ */
+#define cave_floor_grid(C) \
+ ((f_info[(C)->feat].flags1 & FF1_FLOOR) && ((C)->feat != FEAT_MON_TRAP))
+
+
+/*
+ * Grid based version of "cave_plain_floor_bold()"
+ */
+#define cave_plain_floor_grid(C) \
+ ((f_info[(C)->feat].flags1 & FF1_FLOOR) && \
+ !(f_info[(C)->feat].flags1 & FF1_REMEMBER))
+
+
+/*
+ * Grid based version of "cave_clean_bold()"
+ */
+#define cave_clean_grid(C) \
+ ((f_info[(C)->feat].flags1 & FF1_FLOOR) && ((C)->feat != FEAT_MON_TRAP) && \
+ (!(C)->o_idx))
+
+/*
+ * Grid based version of "cave_sight_bold()"
+ */
+#define cave_sight_grid(C) \
+ (!(f_info[(C)->feat].flags1 & FF1_NO_VISION))
+
+/*
+ * Grid based version of "cave_empty_bold()"
+ */
+#define cave_empty_grid(C) \
+ (cave_floor_grid(C) && \
+ !((C)->m_idx) && \
+ !((C) == &cave[p_ptr->py][p_ptr->px]))
+
+/*
+ * Grid based version of "cave_empty_bold()"
+ */
+#define cave_naked_grid(C) \
+ ((f_info[(C)->feat].flags1 & FF1_FLOOR) && ((C)->feat != FEAT_MON_TRAP) && \
+ !((C)->o_idx) && \
+ !((C)->m_idx) && \
+ !((C) == &cave[p_ptr->py][p_ptr->px]))
+
+
+/*
+ * Grid based version of "cave_perma_bold()"
+ */
+#define cave_perma_grid(C) \
+ (f_info[(C)->feat].flags1 & FF1_PERMANENT)
+
+
+
+/*
+ * Determine if a "legal" grid is within "los" of the player
+ *
+ * Note the use of comparison to zero to force a "boolean" result
+ */
+#define player_has_los_bold(Y,X) \
+ ((cave[Y][X].info & (CAVE_VIEW)) != 0)
+
+
+
+/*
+ * Determine if a "legal" grid can be "seen" by the player
+ *
+ * Note the use of comparison to zero to force a "boolean" result
+ */
+#define player_can_see_bold(Y,X) \
+ ((cave[Y][X].info & (CAVE_SEEN)) != 0)
+
+
+
+/*** Color constants ***/
+
+
+/*
+ * Angband "attributes" (with symbols, and base (R,G,B) codes)
+ *
+ * The "(R,G,B)" codes are given in "fourths" of the "maximal" value,
+ * and should "gamma corrected" on most (non-Macintosh) machines.
+ */
+#define TERM_DARK 0 /* 'd' */ /* 0,0,0 */
+#define TERM_WHITE 1 /* 'w' */ /* 4,4,4 */
+#define TERM_SLATE 2 /* 's' */ /* 2,2,2 */
+#define TERM_ORANGE 3 /* 'o' */ /* 4,2,0 */
+#define TERM_RED 4 /* 'r' */ /* 3,0,0 */
+#define TERM_GREEN 5 /* 'g' */ /* 0,2,1 */
+#define TERM_BLUE 6 /* 'b' */ /* 0,0,4 */
+#define TERM_UMBER 7 /* 'u' */ /* 2,1,0 */
+#define TERM_L_DARK 8 /* 'D' */ /* 1,1,1 */
+#define TERM_L_WHITE 9 /* 'W' */ /* 3,3,3 */
+#define TERM_VIOLET 10 /* 'v' */ /* 4,0,4 */
+#define TERM_YELLOW 11 /* 'y' */ /* 4,4,0 */
+#define TERM_L_RED 12 /* 'R' */ /* 4,0,0 */
+#define TERM_L_GREEN 13 /* 'G' */ /* 0,4,0 */
+#define TERM_L_BLUE 14 /* 'B' */ /* 0,4,4 */
+#define TERM_L_UMBER 15 /* 'U' */ /* 3,2,1 */
+
+
+/*** Graphics constants ***/
+
+/*
+ * Possible values of graphics_mode
+ * Good only when use_graphics is set to TRUE
+ * Set by reset_visuals() and used by map_info()
+ */
+#define GRAPHICS_NONE 0
+#define GRAPHICS_UNKNOWN 1
+#define GRAPHICS_IBM 2
+#define GRAPHICS_OLD 3
+#define GRAPHICS_NEW 4
+#define GRAPHICS_ISO 5
+
+
+/*** Sound constants ***/
+
+
+/*
+ * Mega-Hack -- some primitive sound support (see "main-win.c")
+ *
+ * Some "sound" constants for "Term_xtra(TERM_XTRA_SOUND, val)"
+ */
+#define SOUND_HIT 1
+#define SOUND_MISS 2
+#define SOUND_FLEE 3
+#define SOUND_DROP 4
+#define SOUND_KILL 5
+#define SOUND_LEVEL 6
+#define SOUND_DEATH 7
+#define SOUND_STUDY 8
+#define SOUND_TELEPORT 9
+#define SOUND_SHOOT 10
+#define SOUND_QUAFF 11
+#define SOUND_ZAP 12
+#define SOUND_WALK 13
+#define SOUND_TPOTHER 14
+#define SOUND_HITWALL 15
+#define SOUND_EAT 16
+#define SOUND_STORE1 17
+#define SOUND_STORE2 18
+#define SOUND_STORE3 19
+#define SOUND_STORE4 20
+#define SOUND_DIG 21
+#define SOUND_OPENDOOR 22
+#define SOUND_SHUTDOOR 23
+#define SOUND_TPLEVEL 24
+#define SOUND_SCROLL 25
+#define SOUND_BUY 26
+#define SOUND_SELL 27
+#define SOUND_WARN 28
+#define SOUND_ROCKET 29 /* Somebody's shooting rockets */
+#define SOUND_N_KILL 30 /* The player kills a non-living/undead monster */
+#define SOUND_U_KILL 31 /* The player kills a unique */
+#define SOUND_QUEST 32 /* The player has just completed a quest */
+#define SOUND_HEAL 33 /* The player was healed a little bit */
+#define SOUND_X_HEAL 34 /* The player was healed full health */
+#define SOUND_BITE 35 /* A monster bites you */
+#define SOUND_CLAW 36 /* A monster claws you */
+#define SOUND_M_SPELL 37 /* A monster casts a miscellaneous spell */
+#define SOUND_SUMMON 38 /* A monster casts a summoning spell */
+#define SOUND_BREATH 39 /* A monster breathes */
+#define SOUND_BALL 40 /* A monster casts a ball / bolt spell */
+#define SOUND_M_HEAL 41 /* A monster heals itself somehow */
+#define SOUND_ATK_SPELL 42 /* A monster casts a misc. offensive spell */
+#define SOUND_EVIL 43 /* Something nasty has just happened! */
+#define SOUND_TOUCH 44 /* A monster touches you */
+#define SOUND_STING 45 /* A monster stings you */
+#define SOUND_CRUSH 46 /* A monster crushes / envelopes you */
+#define SOUND_SLIME 47 /* A monster drools/spits/etc on you */
+#define SOUND_WAIL 48 /* A monster wails */
+#define SOUND_WINNER 49 /* Just won the game! */
+#define SOUND_FIRE 50 /* An item was burned */
+#define SOUND_ACID 51 /* An item was destroyed by acid */
+#define SOUND_ELEC 52 /* An item was destroyed by electricity */
+#define SOUND_COLD 53 /* An item was shattered */
+#define SOUND_ILLEGAL 54 /* Illegal command attempted */
+#define SOUND_FAIL 55 /* Fail to get a spell off / activate an item */
+#define SOUND_WAKEUP 56 /* A monster wakes up */
+#define SOUND_INVULN 57 /* Invulnerability! */
+#define SOUND_FALL 58 /* Falling through a trapdoor... */
+#define SOUND_PAIN 59 /* A monster is in pain! */
+#define SOUND_DESTITEM 60 /* An item was destroyed by misc. means */
+#define SOUND_MOAN 61 /* A monster makes a moan/beg/insult attack */
+#define SOUND_SHOW 62 /* A monster makes a "show" attack */
+#define SOUND_UNUSED 63 /* (no sound for gaze attacks) */
+#define SOUND_EXPLODE 64 /* Something (or somebody) explodes */
+
+/*
+ * Mega-Hack -- maximum known sounds
+ */
+#define SOUND_MAX 65
+
+
+
+/*** Hack ***/
+
+
+/*
+ * Road flags
+ */
+#define ROAD_NORTH 1
+#define ROAD_SOUTH 2
+#define ROAD_EAST 4
+#define ROAD_WEST 8
+
+
+/*
+ * Buildings actions
+ */
+#define BACT_RESEARCH_ITEM 1
+#define BACT_TOWN_HISTORY 2
+#define BACT_RACE_LEGENDS 3
+#define BACT_GREET_KING 4
+#define BACT_KING_LEGENDS 5
+#define BACT_QUEST1 6
+#define BACT_POSTER 8
+#define BACT_ARENA_RULES 9
+#define BACT_ARENA 10
+#define BACT_ARENA_LEGENDS 11
+#define BACT_IN_BETWEEN 12
+#define BACT_GAMBLE_RULES 13
+#define BACT_CRAPS 14
+#define BACT_SPIN_WHEEL 15
+#define BACT_DICE_SLOTS 16
+#define BACT_REST 17
+#define BACT_FOOD 18
+#define BACT_RUMORS 19
+#define BACT_RESEARCH_MONSTER 20
+#define BACT_COMPARE_WEAPONS 21
+#define BACT_LEGENDS 22
+#define BACT_ENCHANT_WEAPON 23
+#define BACT_ENCHANT_ARMOR 24
+#define BACT_RECHARGE 25
+#define BACT_IDENTS 26
+#define BACT_LEARN 27
+#define BACT_HEALING 28
+#define BACT_RESTORE 29
+#define BACT_ENCHANT_ARROWS 30
+#define BACT_ENCHANT_BOW 31
+#define BACT_GREET 32
+#define BACT_RECALL 33
+#define BACT_TELEPORT_LEVEL 34
+/* XXX */
+/* XXX */
+#define BACT_MIMIC_NORMAL 37
+#define BACT_VIEW_BOUNTIES 38
+#define BACT_SELL_CORPSES 39
+#define BACT_VIEW_QUEST_MON 40
+#define BACT_SELL_QUEST_MON 41
+#define BACT_DIVINATION 42
+#define BACT_SELL 43
+#define BACT_BUY 44
+#define BACT_EXAMINE 45
+#define BACT_STEAL 46
+#define BACT_QUEST2 47
+#define BACT_QUEST3 48
+#define BACT_QUEST4 49
+#define BACT_STAR_HEAL 50
+#define BACT_REQUEST_ITEM 51
+#define BACT_GET_LOAN 52
+#define BACT_PAY_BACK_LOAN 53
+/* If one adds new BACT_ do NOT forget to increase max_bact in variables.c */
+
+
+/*
+ * Quest status
+ */
+#define QUEST_STATUS_IGNORED -1
+#define QUEST_STATUS_UNTAKEN 0
+#define QUEST_STATUS_TAKEN 1
+#define QUEST_STATUS_COMPLETED 2
+#define QUEST_STATUS_REWARDED 3
+#define QUEST_STATUS_FAILED 4
+#define QUEST_STATUS_FINISHED 5
+#define QUEST_STATUS_FAILED_DONE 6
+
+/*
+ * Quest flags
+ */
+#define QUEST_FLAG_SILENT 0x01 /* no messages for completion */
+#define QUEST_FLAG_PRESET 0x02 /* quest is outside the main dungeon */
+#define QUEST_FLAG_ONCE 0x04 /* quest is marked finished after leaving */
+
+/*
+ * Initialization flags
+ */
+#define INIT_SHOW_TEXT 0x01
+#define INIT_ASSIGN 0x02
+#define INIT_CREATE_DUNGEON 0x04
+#define INIT_GET_SIZE 0x08
+#define INIT_POSITION 0x10
+
+/*
+ * Alchemists defines
+ */
+#define MAX_ALCHEMIST_RECIPES 20
+#define ALCHEMIST_ENCHANT_DAM 0x01
+#define ALCHEMIST_ENCHANT_PVAL 0x02
+#define ALCHEMIST_ENCHANT_AC 0x04
+
+/*
+ * Music songs
+ */
+#define MUSIC_NONE 0
+#define MUSIC_SLOW 1
+#define MUSIC_CONF 2
+#define MUSIC_STUN 3
+#define MUSIC_LIFE 4
+#define MUSIC_MIND 5
+#define MUSIC_LITE 6
+#define MUSIC_FURY 7
+#define MUSIC_AWARE 8
+#define MUSIC_ID 9
+#define MUSIC_ILLUSION 10
+#define MUSIC_WALL 11
+#define MUSIC_RESIST 12
+#define MUSIC_TIME 13
+#define MUSIC_BETWEEN 14
+#define MUSIC_CHARME 15
+#define MUSIC_VIBRA 16
+#define MUSIC_HOLY 17
+#define MUSIC_HIDE 18
+#define MUSIC_LIBERTY 19
+#define MUSIC_RAISE 20
+#define MUSIC_SHADOW 21
+#define MUSIC_STAR_ID 22
+
+#define MAX_MUSIC 23
+#define MAX_MUSICS 11
+
+/*
+ * Fate
+ */
+#define MAX_FATES 200
+
+#define FATE_NONE 0
+#define FATE_FIND_O 1
+#define FATE_NO_DIE_MORTAL 2
+#define FATE_FIND_A 3
+#define FATE_FIND_R 4
+#define FATE_FIND_V 5
+#define FATE_DIE 6
+
+/*
+ * Runes definition
+ */
+#define RUNE_SELF 0x00000001
+#define RUNE_ARROW 0x00000002
+#define RUNE_RAY 0x00000004
+#define RUNE_SPHERE 0x00000008
+#define RUNE_POWER_SURGE 0x00000010
+#define RUNE_ARMAGEDDON 0x00000020
+#define RUNE_MOD_MAX 6
+#define RUNE_STONE 0x000000FF
+
+
+/*
+ * Defines of the different dungeon types
+ */
+#define DUNGEON_WILDERNESS 0
+#define DUNGEON_MIRKWOOD 1
+#define DUNGEON_MORDOR 2
+#define DUNGEON_ANGBAND 3
+#define DUNGEON_BARROW_DOWNS 4
+#define DUNGEON_MOUNT_DOOM 5
+#define DUNGEON_NETHER_REALM 6
+#define DUNGEON_NUMENOR 7
+#define DUNGEON_MANDOS 8
+#define DUNGEON_VOID 11
+#define DUNGEON_MAZE 18
+#define DUNGEON_DOL_GULDUR 23
+
+/* Max depth of each dungeon(max_depth - min_depth) */
+#define MAX_DUNGEON_DEPTH 128
+
+#define DUNGEON_MODE_NONE 0
+#define DUNGEON_MODE_AND 1
+#define DUNGEON_MODE_NAND 2
+#define DUNGEON_MODE_OR 3
+#define DUNGEON_MODE_NOR 4
+
+
+/*
+ * Returns the dungeon level or the feat,
+ * if the player is not in a dungeon
+ */
+#define level_or_feat(DTYPE, DLEVEL) \
+ ((DTYPE) == DUNGEON_WILDERNESS ? \
+ wild_map[p_ptr->wilderness_y][p_ptr->wilderness_x].feat : \
+ (DLEVEL) )
+
+
+/*
+ * Defines for the inscriptions
+ */
+#define INSCRIP_EXEC_ENGRAVE 0x01
+#define INSCRIP_EXEC_WALK 0x02
+#define INSCRIP_EXEC_MONST_WALK 0x04
+
+#define INSCRIP_NONE 0
+#define INSCRIP_LIGHT 1
+#define INSCRIP_DARK 2
+#define INSCRIP_STORM 3
+#define INSCRIP_PROTECTION 4
+#define INSCRIP_DWARF_SUMMON 5
+#define INSCRIP_CHASM 6
+#define INSCRIP_BLACK_FIRE 7
+#define MAX_INSCRIPTIONS 8
+
+/*
+ * Various class dependant defines
+ */
+#define CLASS_NONE 0
+#define CLASS_MANA_PATH 1
+#define CLASS_CANALIZE_MANA 2
+#define CLASS_WINDS_MANA 3
+
+#define CLASS_MANA_PATH_ERASE 0x0001
+#define CLASS_FLOOD_LEVEL 0x0002
+#define CLASS_CANALIZE_MANA_EXTRA 0x0004
+#define CLASS_UNDEAD 0x0008
+#define CLASS_ANTIMAGIC 0x0010
+#define CLASS_LEGS 0x0020
+#define CLASS_ARMS 0x0040
+#define CLASS_WALL 0x0080
+
+/*
+ * Types of birth presents
+ */
+#define BIRTH_NONE 0
+#define BIRTH_RING 1
+#define BIRTH_AMULET 2
+
+/*
+ * Automatic note taking types
+ */
+#define NOTE_BIRTH 1
+#define NOTE_WINNER 2
+#define NOTE_SAVE_GAME 3
+#define NOTE_ENTER_DUNGEON 4
+
+/*
+ * Player monsters & ghost defines
+ * NO MORE USED but for savefile compatibility
+ */
+#define GHOST_R_IDX_HEAD 967
+#define GHOST_R_IDX_TAIL 977
+#define MAX_GHOSTS (GHOST_R_IDX_TAIL - GHOST_R_IDX_HEAD)
+
+/* Stores/buildings defines */
+#define STORE_HATED 0
+#define STORE_LIKED 1
+#define STORE_NORMAL 2
+
+/* Pseudo-id defines */
+#define SENSE_NONE 0
+#define SENSE_CURSED 1
+#define SENSE_AVERAGE 2
+#define SENSE_GOOD_LIGHT 3
+#define SENSE_GOOD_HEAVY 4
+#define SENSE_EXCELLENT 5
+#define SENSE_WORTHLESS 6
+#define SENSE_TERRIBLE 7
+#define SENSE_SPECIAL 8
+#define SENSE_BROKEN 9
+#define SENSE_UNCURSED 10
+
+/* Wilderness map related */
+#define WILDERNESS_SEE_RADIUS 3 /* The amount of wilderness seen around the player */
+
+/* Ego monsters defines */
+#define MEGO_CHAR_ANY 127
+#define MEGO_ADD 0
+#define MEGO_SUB 1
+#define MEGO_FIX 2
+#define MEGO_PRC 3
+
+#define MEGO_CHANCE 18 /* % chances of getting ego monsters */
+
+#define race_inf(m_ptr) (((m_ptr)->sr_ptr) ? (m_ptr)->sr_ptr : race_info_idx((m_ptr)->r_idx, (m_ptr)->ego))
+
+/* Object generation */
+#define OBJ_GENE_TREASURE 20
+#define OBJ_GENE_COMBAT 20
+#define OBJ_GENE_MAGIC 20
+#define OBJ_GENE_TOOL 20
+
+/*
+ * Used (or should be) by various functions and tables needing access to
+ * single bits
+ */
+#define BIT(x) (1L << (x))
+
+/* Town defines */
+#define TOWN_RANDOM 20 /* First random town */
+#define TOWN_DUNGEON 4 /* Maximun number of towns per dungeon */
+#define TOWN_CHANCE 50 /* Chance of 1 town */
+
+
+/*
+ * Store flags
+ */
+#define SF1_DEPEND_LEVEL 0x00000001L
+#define SF1_SHALLOW_LEVEL 0x00000002L
+#define SF1_MEDIUM_LEVEL 0x00000004L
+#define SF1_DEEP_LEVEL 0x00000008L
+#define SF1_RARE 0x00000010L
+#define SF1_VERY_RARE 0x00000020L
+#define SF1_COMMON 0x00000040L
+#define SF1_ALL_ITEM 0x00000080L /* Works as the BM */
+#define SF1_RANDOM 0x00000100L
+#define SF1_FORCE_LEVEL 0x00000200L
+#define SF1_MUSEUM 0x00000400L
+
+/*
+ * Powers (mutation, activations, ...)
+ */
+#define POWER_MAX_INIT 62
+
+#define PWR_SPIT_ACID 0
+#define PWR_BR_FIRE 1
+#define PWR_HYPN_GAZE 2
+#define PWR_TELEKINES 3
+#define PWR_VTELEPORT 4
+#define PWR_MIND_BLST 5
+#define PWR_RADIATION 6
+#define PWR_VAMPIRISM 7
+#define PWR_SMELL_MET 8
+#define PWR_SMELL_MON 9
+#define PWR_BLINK 10
+#define PWR_EAT_ROCK 11
+#define PWR_SWAP_POS 12
+#define PWR_SHRIEK 13
+#define PWR_ILLUMINE 14
+#define PWR_DET_CURSE 15
+#define PWR_BERSERK 16
+#define PWR_POLYMORPH 17
+#define PWR_MIDAS_TCH 18
+#define PWR_GROW_MOLD 19
+#define PWR_RESIST 20
+#define PWR_EARTHQUAKE 21
+#define PWR_EAT_MAGIC 22
+#define PWR_WEIGH_MAG 23
+#define PWR_STERILITY 24
+#define PWR_PANIC_HIT 25
+#define PWR_DAZZLE 26
+#define PWR_DARKRAY 27
+#define PWR_RECALL 28
+#define PWR_BANISH 29
+#define PWR_COLD_TOUCH 30
+#define PWR_LAUNCHER 31
+
+#define PWR_PASSWALL 32
+#define PWR_DETECT_TD 33
+#define PWR_COOK_FOOD 34
+#define PWR_UNFEAR 35
+#define PWR_EXPL_RUNE 36
+#define PWR_STM 37
+#define PWR_POIS_DART 38
+#define PWR_MAGIC_MISSILE 39
+#define PWR_GROW_TREE 40
+#define PWR_BR_COLD 41
+#define PWR_BR_CHAOS 42
+#define PWR_BR_ELEM 43
+#define PWR_WRECK_WORLD 44
+#define PWR_SCARE 45
+#define PWR_REST_LIFE 46
+#define PWR_SUMMON_MONSTER 47
+#define PWR_NECRO 48
+#define PWR_ROHAN 49
+#define PWR_THUNDER 50
+#define PWR_DEATHMOLD 51
+#define PWR_HYPNO 52
+#define PWR_UNHYPNO 53
+#define PWR_INCARNATE 54
+#define PWR_MAGIC_MAP 55
+#define PWR_LAY_TRAP 56
+#define PWR_MERCHANT 57
+#define PWR_COMPANION 58
+#define PWR_BEAR 59
+#define PWR_DODGE 60
+#define PWR_BALROG 61
+
+#define ADD_POWER(pow, p) ((pow)[(p)] = TRUE)
+
+/*
+ * Shield effect options
+ */
+#define SHIELD_NONE 0x0000
+#define SHIELD_COUNTER 0x0001
+#define SHIELD_FIRE 0x0002
+#define SHIELD_GREAT_FIRE 0x0004
+#define SHIELD_FEAR 0x0008
+
+/*
+ * Quest constants
+ */
+#define MAX_MON_QUEST 10
+#define MAX_ITEM_QUEST 5
+
+#define MAX_RANDOM_QUEST 99
+
+#define QUEST_NULL 0
+#define QUEST_NECRO 1
+#define QUEST_SAURON 2
+#define QUEST_MORGOTH 3
+#define QUEST_THIEVES 4
+#define QUEST_RANDOM 5
+#define QUEST_HOBBIT 6
+#define QUEST_NAZGUL 7
+#define QUEST_TROLL 8
+#define QUEST_WIGHT 9
+#define QUEST_SPIDER 10
+#define QUEST_POISON 11
+#define QUEST_NARSIL 12
+#define QUEST_EOL 13
+#define QUEST_NIRNAETH 14
+#define QUEST_INVASION 15
+#define QUEST_BETWEEN 16
+#define QUEST_ONE 17
+#define QUEST_SHROOM 18
+#define QUEST_THRAIN 19
+#define QUEST_ULTRA_GOOD 20
+#define QUEST_ULTRA_EVIL 21
+#define QUEST_WOLVES 22
+#define QUEST_DRAGONS 23
+#define QUEST_HAUNTED 24
+#define QUEST_EVIL 25
+#define MAX_Q_IDX_INIT 26
+
+#define PLOT_MAIN 0
+#define PLOT_BREE 1
+#define PLOT_LORIEN 2
+#define PLOT_OTHER 3
+#define PLOT_GONDOLIN 4
+#define PLOT_MINAS 5
+#define PLOT_KHAZAD 6
+#define MAX_PLOTS 7
+
+/*
+ * Hooks
+ */
+#define HOOK_MONSTER_DEATH 0
+#define HOOK_OPEN 1
+#define HOOK_GEN_QUEST 2
+#define HOOK_END_TURN 3
+#define HOOK_FEELING 4
+#define HOOK_NEW_MONSTER 5
+#define HOOK_GEN_LEVEL 6
+#define HOOK_BUILD_ROOM1 7
+#define HOOK_NEW_LEVEL 8
+#define HOOK_QUEST_FINISH 9
+#define HOOK_QUEST_FAIL 10
+#define HOOK_GIVE 11
+#define HOOK_CHAR_DUMP 12
+#define HOOK_INIT_QUEST 13
+#define HOOK_WILD_GEN 14
+#define HOOK_DROP 15
+#define HOOK_IDENTIFY 16
+#define HOOK_MOVE 17
+#define HOOK_STAIR 18
+#define HOOK_MONSTER_AI 19
+#define HOOK_PLAYER_LEVEL 20
+#define HOOK_WIELD 21
+#define HOOK_INIT 22
+#define HOOK_QUAFF 23
+#define HOOK_AIM 24
+#define HOOK_USE 25
+#define HOOK_ACTIVATE 26
+#define HOOK_ZAP 27
+#define HOOK_READ 28
+#define HOOK_CALC_BONUS 29
+#define HOOK_CALC_POWERS 30
+#define HOOK_KEYPRESS 31
+#define HOOK_CHAT 32
+#define HOOK_MON_SPEAK 33
+#define HOOK_MKEY 34
+#define HOOK_BIRTH_OBJECTS 35
+#define HOOK_ACTIVATE_DESC 36
+#define HOOK_INIT_GAME 37
+#define HOOK_ACTIVATE_POWER 38
+#define HOOK_ITEM_NAME 39
+#define HOOK_SAVE_GAME 40
+#define HOOK_LOAD_GAME 41
+#define HOOK_LEVEL_REGEN 42
+#define HOOK_LEVEL_END_GEN 43
+#define HOOK_BUILDING_ACTION 44
+#define HOOK_PROCESS_WORLD 45
+#define HOOK_WIELD_SLOT 46
+#define HOOK_STORE_STOCK 47
+#define HOOK_STORE_BUY 48
+#define HOOK_GEN_LEVEL_BEGIN 49
+#define HOOK_GET 50
+#define HOOK_REDRAW 51
+#define HOOK_RECALC_SKILLS 52
+#define HOOK_ENTER_DUNGEON 53
+#define HOOK_FIRE 54
+#define HOOK_EAT 55
+#define HOOK_DIE 56
+#define HOOK_CALC_HP 57
+#define HOOK_GF_COLOR 58
+#define HOOK_GF_EXEC 59
+#define HOOK_CALC_MANA 60
+#define HOOK_LOAD_END 61
+#define HOOK_RECALL 62
+#define HOOK_FOLLOW_GOD 63
+#define HOOK_SACRIFICE_GOD 64
+#define HOOK_BODY_PARTS 65
+#define HOOK_APPLY_MAGIC 66
+#define HOOK_PLAYER_EXP 67
+#define HOOK_BIRTH 68
+#define HOOK_CALC_LITE 69
+#define HOOK_LEARN_ABILITY 70
+#define HOOK_MOVED 71
+#define HOOK_GAME_START 72
+#define HOOK_TAKEOFF 73
+#define HOOK_CALC_WEIGHT 74
+#define HOOK_FORBID_TRAVEL 75
+#define HOOK_DEBUG_COMMAND 76
+#define HOOK_CALC_BONUS_END 77
+#define MAX_HOOKS 78
+
+#define HOOK_TYPE_C 0
+#define HOOK_TYPE_LUA 1
+
+/*
+ * Defines for loadsave.c
+ * Why 3 and 7? So if it's uninitialized, the code will be able to catch it, as
+ * 0 is an invalid flag. Also, having them apart means that it being accidentally
+ * modified will also result in an invalid value -- Improv
+ */
+#define LS_LOAD 3
+#define LS_SAVE 7
+
+/*
+ * In game help
+ */
+#define HELP1_BETWEEN 0x00000001
+#define HELP1_ALTAR 0x00000002
+#define HELP1_FOUNTAIN 0x00000004
+#define HELP1_IDENTIFY 0x00000008
+#define HELP1_WILD_MODE 0x00000010
+
+/*
+ * Special weapon effects
+ */
+#define SPEC_POIS 0x00000001L
+#define SPEC_CUT 0x00000002L
+
+/*
+ * Ambushes in the wild
+ */
+#define AMBUSH_RACE 1
+#define AMBUSH_MIX 2
+
+/*
+ * Macro trigger
+ */
+#define MAX_MACRO_MOD 12
+#define MAX_MACRO_TRIG 200
+
+
+/*
+ * Skills !
+ */
+#define SKILL_MAX 50000 /* Maximun skill value */
+#define SKILL_STEP 1000 /* 1 skill point */
+
+#define SKILL_EXCLUSIVE 9999 /* Flag to tell exclusive skills */
+
+#define SKILL_CONVEYANCE 1
+#define SKILL_MANA 2
+#define SKILL_FIRE 3
+#define SKILL_AIR 4
+#define SKILL_WATER 5
+#define SKILL_NATURE 6
+#define SKILL_EARTH 7
+#define SKILL_SYMBIOTIC 8
+#define SKILL_MUSIC 9
+#define SKILL_DIVINATION 10
+#define SKILL_TEMPORAL 11
+#define SKILL_DRUID 12
+#define SKILL_DAEMON 13
+#define SKILL_META 14
+#define SKILL_MAGIC 15
+#define SKILL_COMBAT 16
+#define SKILL_MASTERY 17
+#define SKILL_SWORD 18
+#define SKILL_AXE 19
+#define SKILL_POLEARM 20
+#define SKILL_HAFTED 21
+#define SKILL_BACKSTAB 22
+#define SKILL_ARCHERY 23
+#define SKILL_SLING 24
+#define SKILL_BOW 25
+#define SKILL_XBOW 26
+#define SKILL_BOOMERANG 27
+#define SKILL_SPIRITUALITY 28
+#define SKILL_MINDCRAFT 29
+#define SKILL_MISC 30
+#define SKILL_NECROMANCY 31
+#define SKILL_MIMICRY 32
+#define SKILL_ANTIMAGIC 33
+#define SKILL_RUNECRAFT 34
+#define SKILL_SNEAK 35
+#define SKILL_STEALTH 36
+#define SKILL_DISARMING 37
+/* XXX */
+#define SKILL_ALCHEMY 39
+#define SKILL_STEALING 40
+#define SKILL_SORCERY 41
+#define SKILL_HAND 42
+#define SKILL_THAUMATURGY 43
+#define SKILL_SUMMON 44
+#define SKILL_SPELL 45
+#define SKILL_DODGE 46
+#define SKILL_BEAR 47
+#define SKILL_LORE 48
+#define SKILL_PRESERVATION 49
+#define SKILL_POSSESSION 50
+#define SKILL_MIND 51
+#define SKILL_CRITS 52
+#define SKILL_PRAY 53
+#define SKILL_LEARN 54
+#define SKILL_UDUN 55
+#define SKILL_DEVICE 56
+#define SKILL_STUN 57
+#define SKILL_BOULDER 58
+#define SKILL_GEOMANCY 59
+
+/* Ugly but needed */
+#define MAX_SKILLS 200
+
+/* Number of skill choices for Lost Sword quests. */
+#define LOST_SWORD_NSKILLS 4
+
+/* SKill flags */
+#define SKF1_HIDDEN 0x00000001 /* Starts hidden */
+#define SKF1_AUTO_HIDE 0x00000002 /* Tries to rehide at calc_bonus */
+#define SKF1_RANDOM_GAIN 0x00000004 /* Can be randomly gained by certain quests & such */
+
+#define MAX_MELEE 3
+
+/*
+ * Player specialities, should be external but ti would be a mess
+ */
+#define MAX_SPEC 20
+
+
+/*
+ * Spellbinder triggers
+ */
+#define SPELLBINDER_HP75 1
+#define SPELLBINDER_HP50 2
+#define SPELLBINDER_HP25 3
+
+/*
+ * God's defines
+ */
+#define GOD_ALL -1
+#define GOD_NONE 0
+#define GOD_ERU 1
+#define GOD_MANWE 2
+#define GOD_TULKAS 3
+#define GOD_MELKOR 4
+#define GOD_YAVANNA 5
+#define MAX_GODS_INIT 6
+
+#define GOD(g) if (p_ptr->pgod == (g))
+#define PRAY_GOD(g) if ((p_ptr->pgod == (g)) && (p_ptr->praying))
+#define NOT_PRAY_GOD(g) if ((p_ptr->pgod == (g)) && (!p_ptr->praying))
+
+/*
+ * Command numbers for do_cmd_cli().
+ *
+ * As the user is not intended to have a way to enter these codes directly
+ * (doing so isn't harmful, but these codes are not intended as mnemonics),
+ * only codes in the range 0xE000 - 0xF8FF (the private area of Unicode 3.0)
+ * should be used.
+ *
+ * In addition, values at the lower end of this range are preferred as the upper
+ * end may have a system-specific encoding
+ */
+#define CMD_CLI_HELP -8192
+#define CMD_SHOW_TIME -8188
+#define CMD_SHOW_SKILL -8187
+#define CMD_DUMP_HTML -8186
+#define CMD_MACRO -8185
+#define CMD_QUEST -8184
+#define CMD_BLUNDER -8183
+#define CMD_SHOW_ABILITY -8182
+
+#define CLI_MAX 128
+
+
+/*
+ * The various winner state
+ */
+#define WINNER_NORMAL 1
+#define WINNER_ULTRA 2
+
+/*
+ * The abilities
+ */
+#define AB_SPREAD_BLOWS 0
+#define AB_TREE_WALK 1
+#define AB_PERFECT_CASTING 2
+#define AB_MAX_BLOW1 3
+#define AB_MAX_BLOW2 4
+#define AB_AMMO_CREATION 5
+#define AB_DEATH_TOUCH 6
+#define AB_CREATE_ART 7
+#define AB_FAR_REACHING 8
+#define AB_TRAPPING 9
+#define AB_UNDEAD_FORM 10
diff --git a/src/dungeon.c b/src/dungeon.c
new file mode 100644
index 00000000..6d732f00
--- /dev/null
+++ b/src/dungeon.c
@@ -0,0 +1,5664 @@
+/* File: dungeon.c */
+
+/* Purpose: Angband game engine */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+#include "lua/lua.h"
+#include "tolua.h"
+extern lua_State* L;
+
+#define TY_CURSE_CHANCE 100
+#define DG_CURSE_CHANCE 50
+#define AUTO_CURSE_CHANCE 15
+#define CHAINSWORD_NOISE 100
+
+
+/*
+ * Return a "feeling" (or NULL) about an item. Method 1 (Heavy).
+ */
+byte value_check_aux1(object_type *o_ptr)
+{
+ /* Artifacts */
+ if (artifact_p(o_ptr))
+ {
+ /* Cursed/Broken */
+ if (cursed_p(o_ptr)) return (SENSE_TERRIBLE);
+
+ /* Normal */
+ return (SENSE_SPECIAL);
+ }
+
+ /* Ego-Items */
+ if (ego_item_p(o_ptr))
+ {
+ /* Cursed/Broken */
+ if (cursed_p(o_ptr)) return (SENSE_WORTHLESS);
+
+ /* Normal */
+ return (SENSE_EXCELLENT);
+ }
+
+ /* Cursed items */
+ if (cursed_p(o_ptr)) return (SENSE_CURSED);
+
+ /* Good "armor" bonus */
+ if (o_ptr->to_a > 0) return (SENSE_GOOD_HEAVY);
+
+ /* Good "weapon" bonus */
+ if (o_ptr->to_h + o_ptr->to_d > 0) return (SENSE_GOOD_HEAVY);
+
+ /* Default to "average" */
+ return (SENSE_AVERAGE);
+}
+
+byte value_check_aux1_magic(object_type *o_ptr)
+{
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+
+ switch (o_ptr->tval)
+ {
+ /* Scrolls, Potions, Wands, Staves and Rods */
+ case TV_SCROLL:
+ case TV_POTION:
+ case TV_POTION2:
+ case TV_WAND:
+ case TV_STAFF:
+ case TV_ROD:
+ case TV_ROD_MAIN:
+ {
+ /* "Cursed" scrolls/potions have a cost of 0 */
+ if (k_ptr->cost == 0) return (SENSE_TERRIBLE);
+
+ /* Artifacts */
+ if (artifact_p(o_ptr)) return (SENSE_SPECIAL);
+
+ /* Scroll of Nothing, Apple Juice, etc. */
+ if (k_ptr->cost < 3) return (SENSE_WORTHLESS);
+
+ /*
+ * Identify, Phase Door, Cure Light Wounds, etc. are
+ * just average
+ */
+ if (k_ptr->cost < 100) return (SENSE_AVERAGE);
+
+ /* Enchant Armor, *Identify*, Restore Stat, etc. */
+ if (k_ptr->cost < 10000) return (SENSE_GOOD_HEAVY);
+
+ /* Acquirement, Deincarnation, Strength, Blood of Life, ... */
+ if (k_ptr->cost >= 10000) return (SENSE_EXCELLENT);
+
+ break;
+ }
+
+ /* Food */
+ case TV_FOOD:
+ {
+ /* "Cursed" food */
+ if (k_ptr->cost == 0) return (SENSE_TERRIBLE);
+
+ /* Artifacts */
+ if (artifact_p(o_ptr)) return (SENSE_SPECIAL);
+
+ /* Normal food (no magical properties) */
+ if (k_ptr->cost <= 10) return (SENSE_AVERAGE);
+
+ /* Everything else is good */
+ if (k_ptr->cost > 10) return (SENSE_GOOD_HEAVY);
+
+ break;
+ }
+ }
+
+ /* No feeling */
+ return (SENSE_NONE);
+}
+
+
+/*
+ * Return a "feeling" (or NULL) about an item. Method 2 (Light).
+ */
+byte value_check_aux2(object_type *o_ptr)
+{
+ /* Cursed items (all of them) */
+ if (cursed_p(o_ptr)) return (SENSE_CURSED);
+
+ /* Artifacts -- except cursed/broken ones */
+ if (artifact_p(o_ptr)) return (SENSE_GOOD_LIGHT);
+
+ /* Ego-Items -- except cursed/broken ones */
+ if (ego_item_p(o_ptr)) return (SENSE_GOOD_LIGHT);
+
+ /* Good armor bonus */
+ if (o_ptr->to_a > 0) return (SENSE_GOOD_LIGHT);
+
+ /* Good weapon bonuses */
+ if (o_ptr->to_h + o_ptr->to_d > 0) return (SENSE_GOOD_LIGHT);
+
+ /* Default to "average" */
+ return (SENSE_AVERAGE);
+}
+
+
+byte value_check_aux2_magic(object_type *o_ptr)
+{
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+
+ switch (o_ptr->tval)
+ {
+ /* Scrolls, Potions, Wands, Staves and Rods */
+ case TV_SCROLL:
+ case TV_POTION:
+ case TV_POTION2:
+ case TV_WAND:
+ case TV_STAFF:
+ case TV_ROD:
+ case TV_ROD_MAIN:
+ {
+ /* "Cursed" scrolls/potions have a cost of 0 */
+ if (k_ptr->cost == 0) return (SENSE_CURSED);
+
+ /* Artifacts */
+ if (artifact_p(o_ptr)) return (SENSE_GOOD_LIGHT);
+
+ /* Scroll of Nothing, Apple Juice, etc. */
+ if (k_ptr->cost < 3) return (SENSE_AVERAGE);
+
+ /*
+ * Identify, Phase Door, Cure Light Wounds, etc. are
+ * just average
+ */
+ if (k_ptr->cost < 100) return (SENSE_AVERAGE);
+
+ /* Enchant Armor, *Identify*, Restore Stat, etc. */
+ if (k_ptr->cost < 10000) return (SENSE_GOOD_LIGHT);
+
+ /* Acquirement, Deincarnation, Strength, Blood of Life, ... */
+ if (k_ptr->cost >= 10000) return (SENSE_GOOD_LIGHT);
+
+ break;
+ }
+
+ /* Food */
+ case TV_FOOD:
+ {
+ /* "Cursed" food */
+ if (k_ptr->cost == 0) return (SENSE_CURSED);
+
+ /* Artifacts */
+ if (artifact_p(o_ptr)) return (SENSE_GOOD_LIGHT);
+
+ /* Normal food (no magical properties) */
+ if (k_ptr->cost <= 10) return (SENSE_AVERAGE);
+
+ /* Everything else is good */
+ if (k_ptr->cost > 10) return (SENSE_GOOD_LIGHT);
+
+ break;
+ }
+ }
+
+ /* No feeling */
+ return (SENSE_NONE);
+}
+
+
+/*
+ * Can a player be resurrected?
+ */
+static bool_ granted_resurrection(void)
+{
+ PRAY_GOD(GOD_ERU)
+ {
+ if (p_ptr->grace > 100000)
+ {
+ if (magik(70)) return (TRUE);
+ else return (FALSE);
+ }
+ }
+ return (FALSE);
+}
+
+static byte select_sense(object_type *o_ptr)
+{
+ /* Valid "tval" codes */
+ switch (o_ptr->tval)
+ {
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+ case TV_BOW:
+ case TV_DIGGING:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_SWORD:
+ case TV_MSTAFF:
+ case TV_AXE:
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_HELM:
+ case TV_CROWN:
+ case TV_SHIELD:
+ case TV_CLOAK:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ case TV_BOOMERANG:
+ case TV_TRAPKIT:
+ {
+ return 1;
+ break;
+ }
+
+ case TV_POTION:
+ case TV_POTION2:
+ case TV_SCROLL:
+ case TV_WAND:
+ case TV_STAFF:
+ case TV_ROD:
+ case TV_ROD_MAIN:
+ {
+ return 2;
+ break;
+ }
+
+ /* Dual use? */
+ case TV_DAEMON_BOOK:
+ {
+ return 1;
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Sense the inventory
+ *
+ * Combat items (weapons and armour) - Fast, weak if combat skill < 10, strong
+ * otherwise.
+ *
+ * Magic items (scrolls, staffs, wands, potions etc) - Slow, weak if
+ * magic skill < 10, strong otherwise.
+ *
+ * It shouldn't matter a lot to discriminate against magic users, because
+ * they learn one form of ID or another, and because most magic items are
+ * easy_know.
+ */
+void sense_inventory(void)
+{
+ int i, combat_lev, magic_lev;
+
+ bool_ heavy_combat, heavy_magic;
+
+ byte feel;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+
+ /*** Check for "sensing" ***/
+
+ /* No sensing when confused */
+ if (p_ptr->confused) return;
+
+ /*
+ * In Angband, the chance of pseudo-id uses two different formulae:
+ *
+ * (1) Fast. 0 == rand_int(BASE / (plev * plev + 40)
+ * (2) Slow. 0 == rand_int(BASE / (plev + 5)
+ *
+ * Warriors: Fase with BASE == 9000
+ * Magi: Slow with BASE == 240000
+ * Priests: Fast with BASE == 10000
+ * Rogues: Fase with BASE == 20000
+ * Rangers: Slow with BASE == 120000
+ * Paladins: Fast with BASE == 80000
+ *
+ * In other words, those who have identify spells are penalised.
+ * The problems with Pern/Tome since it externalised player classes
+ * is that it uses the same and slow formula for spellcasters and
+ * fighters.
+ *
+ * In the following code, combat item pseudo-ID improves exponentially,
+ * (fast with BASE 9000) and magic one linear (slow with base 60000 --
+ * twice faster than V rangers).
+ *
+ * I hope this makes it closer to the original model -- pelpel
+ */
+
+ /* The combat skill affects weapon/armour pseudo-ID */
+ combat_lev = get_skill(SKILL_COMBAT);
+
+ /* The magic skill affects magic item pseudo-ID */
+ magic_lev = get_skill(SKILL_MAGIC);
+
+ /* Higher skill levels give the player better sense of items */
+ heavy_combat = (combat_lev > 10) ? TRUE : FALSE;
+ heavy_magic = (magic_lev > 10) ? TRUE : FALSE;
+
+
+ /*** Sense everything ***/
+
+ /* Check everything */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ byte okay = 0;
+
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip empty slots */
+ if (!o_ptr->k_idx) continue;
+
+ /* We know about it already, do not tell us again */
+ if (o_ptr->ident & (IDENT_SENSE)) continue;
+
+ /* It is fully known, no information needed */
+ if (object_known_p(o_ptr)) continue;
+
+ /* Valid "tval" codes */
+ okay = select_sense(o_ptr);
+
+ /* Skip non-sense machines */
+ if (!okay) continue;
+
+ /* Check for a feeling */
+ if (okay == 1)
+ {
+ feel = (heavy_combat ? value_check_aux1(o_ptr) : value_check_aux2(o_ptr));
+ }
+ else
+ {
+ feel = (heavy_magic ? value_check_aux1_magic(o_ptr) : value_check_aux2_magic(o_ptr));
+ }
+
+ /* Skip non-feelings */
+ if (feel == SENSE_NONE) continue;
+
+ /* Get an object description */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ /* Message (equipment) */
+ if (i >= INVEN_WIELD)
+ {
+ msg_format("You feel the %s (%c) you are %s %s %s...",
+ o_name, index_to_label(i), describe_use(i),
+ ((o_ptr->number == 1) ? "is" : "are"), sense_desc[feel]);
+ }
+
+ /* Message (inventory) */
+ else
+ {
+ msg_format("You feel the %s (%c) in your pack %s %s...",
+ o_name, index_to_label(i),
+ ((o_ptr->number == 1) ? "is" : "are"), sense_desc[feel]);
+ }
+
+ /* We have "felt" it */
+ o_ptr->ident |= (IDENT_SENSE);
+
+ /* Set sense property */
+ o_ptr->sense = feel;
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+ }
+
+ /* Squelch ! */
+ squeltch_inventory();
+}
+
+
+/*
+ * Go to any level (ripped off from wiz_jump)
+ */
+static void pattern_teleport(void)
+{
+ /* Ask for level */
+ if (get_check("Teleport level? "))
+ {
+ char ppp[80];
+
+ char tmp_val[160];
+
+ /* Prompt */
+ sprintf(ppp, "Teleport to level (0-%d): ", 99);
+
+ /* Default */
+ sprintf(tmp_val, "%d", dun_level);
+
+ /* Ask for a level */
+ if (!get_string(ppp, tmp_val, 10)) return;
+
+ /* Extract request */
+ command_arg = atoi(tmp_val);
+ }
+ else if (get_check("Normal teleport? "))
+ {
+ teleport_player(200);
+ return;
+ }
+ else
+ {
+ return;
+ }
+
+ /* Paranoia */
+ if (command_arg < 0) command_arg = 0;
+
+ /* Paranoia */
+ if (command_arg > 99) command_arg = 99;
+
+ /* Accept request */
+ msg_format("You teleport to dungeon level %d.", command_arg);
+
+ autosave_checkpoint();
+
+ /* Change level */
+ dun_level = command_arg;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+}
+
+
+/*
+ * Returns TRUE if we are on the Straight Road...
+ */
+static bool_ pattern_effect(void)
+{
+ if ((cave[p_ptr->py][p_ptr->px].feat < FEAT_PATTERN_START) ||
+ (cave[p_ptr->py][p_ptr->px].feat > FEAT_PATTERN_XTRA2)) return (FALSE);
+
+ if (cave[p_ptr->py][p_ptr->px].feat == FEAT_PATTERN_END)
+ {
+ (void)set_poisoned(0);
+ (void)set_image(0);
+ (void)set_stun(0);
+ (void)set_cut(0);
+ (void)set_blind(0);
+ (void)set_afraid(0);
+ (void)do_res_stat(A_STR, TRUE);
+ (void)do_res_stat(A_INT, TRUE);
+ (void)do_res_stat(A_WIS, TRUE);
+ (void)do_res_stat(A_DEX, TRUE);
+ (void)do_res_stat(A_CON, TRUE);
+ (void)do_res_stat(A_CHR, TRUE);
+ (void)restore_level();
+ (void)hp_player(1000);
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_PATTERN_OLD);
+ msg_print("This section of the Straight Road looks less powerful.");
+ }
+
+
+ /*
+ * We could make the healing effect of the
+ * Pattern center one-time only to avoid various kinds
+ * of abuse, like luring the win monster into fighting you
+ * in the middle of the pattern...
+ */
+ else if (cave[p_ptr->py][p_ptr->px].feat == FEAT_PATTERN_OLD)
+ {
+ /* No effect */
+ }
+ else if (cave[p_ptr->py][p_ptr->px].feat == FEAT_PATTERN_XTRA1)
+ {
+ pattern_teleport();
+ }
+ else if (cave[p_ptr->py][p_ptr->px].feat == FEAT_PATTERN_XTRA2)
+ {
+ if (!(p_ptr->invuln))
+ take_hit(200, "walking the corrupted Straight Road");
+ }
+
+ else
+ {
+ if (!(p_ptr->invuln))
+ take_hit(damroll(1, 3), "walking the Straight Road");
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * If player has inscribed the object with "!!", let him know when it's
+ * recharged. -LM-
+ */
+static void recharged_notice(object_type *o_ptr)
+{
+ char o_name[80];
+
+ cptr s;
+
+
+ /* No inscription */
+ if (!o_ptr->note) return;
+
+ /* Find a '!' */
+ s = strchr(quark_str(o_ptr->note), '!');
+
+ /* Process notification request. */
+ while (s)
+ {
+ /* Find another '!' */
+ if (s[1] == '!')
+ {
+ /* Describe (briefly) */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ /* Notify the player */
+ if (o_ptr->number > 1)
+ {
+ msg_format("Your %s are recharged.", o_name);
+ }
+ else
+ {
+ msg_format("Your %s is recharged.", o_name);
+ }
+
+ /* Done. */
+ return;
+ }
+
+ /* Keep looking for '!'s */
+ s = strchr(s + 1, '!');
+ }
+}
+
+
+
+/*
+ * Regenerate hit points -RAK-
+ */
+static void regenhp(int percent)
+{
+ s32b new_chp, new_chp_frac;
+
+ int old_chp;
+
+
+ /* Only if alive */
+ if (!(p_ptr->necro_extra & CLASS_UNDEAD))
+ {
+ /* Save the old hitpoints */
+ old_chp = p_ptr->chp;
+
+ /* Extract the new hitpoints */
+ new_chp = ((long)p_ptr->mhp) * percent + PY_REGEN_HPBASE;
+
+ /* div 65536 */
+ p_ptr->chp += new_chp >> 16;
+
+ /* check for overflow */
+ if ((p_ptr->chp < 0) && (old_chp > 0)) p_ptr->chp = MAX_SHORT;
+
+ /* mod 65536 */
+ new_chp_frac = (new_chp & 0xFFFF) + p_ptr->chp_frac;
+
+ if (new_chp_frac >= 0x10000L)
+ {
+ p_ptr->chp_frac = new_chp_frac - 0x10000L;
+ p_ptr->chp++;
+ }
+ else
+ {
+ p_ptr->chp_frac = new_chp_frac;
+ }
+
+ /* Fully healed */
+ if (p_ptr->chp >= p_ptr->mhp)
+ {
+ p_ptr->chp = p_ptr->mhp;
+ p_ptr->chp_frac = 0;
+ }
+
+ /* Notice changes */
+ if (old_chp != p_ptr->chp)
+ {
+ /* Redraw */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+ }
+}
+
+
+/*
+ * Regenerate mana points -RAK-
+ */
+static void regenmana(int percent)
+{
+ s32b new_mana, new_mana_frac;
+
+ int old_csp;
+
+ /* Incraese regen with int */
+ percent += adj_str_blow[p_ptr->stat_ind[A_INT]] * 3;
+
+ old_csp = p_ptr->csp;
+ new_mana = ((long)p_ptr->msp) * percent + PY_REGEN_MNBASE;
+
+ /* div 65536 */
+ p_ptr->csp += new_mana >> 16;
+
+ /* check for overflow */
+ if ((p_ptr->csp < 0) && (old_csp > 0))
+ {
+ p_ptr->csp = MAX_SHORT;
+ }
+
+ /* mod 65536 */
+ new_mana_frac = (new_mana & 0xFFFF) + p_ptr->csp_frac;
+
+ if (new_mana_frac >= 0x10000L)
+ {
+ p_ptr->csp_frac = new_mana_frac - 0x10000L;
+ p_ptr->csp++;
+ }
+ else
+ {
+ p_ptr->csp_frac = new_mana_frac;
+ }
+
+ /* Must set frac to zero even if equal */
+ if (p_ptr->csp >= p_ptr->msp)
+ {
+ p_ptr->csp = p_ptr->msp;
+ p_ptr->csp_frac = 0;
+ }
+
+ /* Redraw mana */
+ if (old_csp != p_ptr->csp)
+ {
+ /* Redraw */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+}
+
+
+
+
+
+
+/*
+ * Regenerate the monsters (once per 100 game turns)
+ *
+ * XXX XXX XXX Should probably be done during monster turns.
+ */
+static void regen_monsters(void)
+{
+ int i, frac;
+
+ object_type *o_ptr = &p_ptr->inventory[INVEN_CARRY];
+
+
+ if (o_ptr->k_idx)
+ {
+ monster_race *r_ptr = &r_info[o_ptr->pval];
+
+ /* Allow regeneration (if needed) */
+ if (o_ptr->pval2 < o_ptr->pval3)
+ {
+ /* Hack -- Base regeneration */
+ frac = o_ptr->pval3 / 100;
+
+ /* Hack -- Minimal regeneration rate */
+ if (!frac) frac = 1;
+
+ /* Hack -- Some monsters regenerate quickly */
+ if (r_ptr->flags2 & (RF2_REGENERATE)) frac *= 2;
+
+
+ /* Hack -- Regenerate */
+ o_ptr->pval2 += frac;
+
+ /* Do not over-regenerate */
+ if (o_ptr->pval2 > o_ptr->pval3) o_ptr->pval2 = o_ptr->pval3;
+
+ /* Redraw (later) */
+ p_ptr->redraw |= (PR_MH);
+ }
+ }
+
+ /* Regenerate everyone */
+ for (i = 1; i < m_max; i++)
+ {
+ /* Check the i'th monster */
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Dont regen bleeding/poisonned monsters */
+ if (m_ptr->bleeding || m_ptr->poisoned) continue;
+
+ /* Allow regeneration (if needed) */
+ if (m_ptr->hp < m_ptr->maxhp)
+ {
+ /* Hack -- Base regeneration */
+ frac = m_ptr->maxhp / 100;
+
+ /* Hack -- Minimal regeneration rate */
+ if (!frac) frac = 1;
+
+ /* Hack -- Some monsters regenerate quickly */
+ if (r_ptr->flags2 & (RF2_REGENERATE)) frac *= 2;
+
+
+ /* Hack -- Regenerate */
+ m_ptr->hp += frac;
+
+ /* Do not over-regenerate */
+ if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
+
+ /* Redraw (later) if needed */
+ if (health_who == i) p_ptr->redraw |= (PR_HEALTH);
+ }
+ }
+}
+
+
+/*
+ * Does an object decay?
+ *
+ * Should belong to object1.c, renamed to object_decays() -- pelpel
+ */
+bool_ decays(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Extract some flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (f3 & TR3_DECAY) return (TRUE);
+
+ return (FALSE);
+}
+
+
+static int process_lasting_spell(s16b music)
+{
+ int oldtop, use_mana;
+
+ if (music > 0) return FALSE;
+
+ oldtop = lua_gettop(L);
+
+ music = -music;
+
+ /* Push the function */
+ lua_getglobal(L, "exec_lasting_spell");
+
+ /* Push the spell */
+ tolua_pushnumber(L, music);
+
+ /* Call the function */
+ if (lua_call(L, 1, 1))
+ {
+ cmsg_format(TERM_VIOLET, "ERROR in lua_call while calling lasting spell");
+ return 0;
+ }
+
+ use_mana = tolua_getnumber(L, -(lua_gettop(L) - oldtop), 0);
+ lua_settop(L, oldtop);
+ return use_mana;
+}
+
+static void gere_class_special()
+{
+ switch (p_ptr->druid_extra2)
+ {
+ /* Lay a path of mana on the floor */
+ case CLASS_MANA_PATH:
+ {
+ /* Does the player have enought mana ? */
+ if (p_ptr->csp < (s32b)(p_ptr->druid_extra & 255))
+ {
+ p_ptr->druid_extra = 0;
+ p_ptr->druid_extra2 = CLASS_NONE;
+ msg_print("You stop laying a mana path.");
+ }
+ else
+ {
+ /* Use some mana */
+ p_ptr->csp -= (p_ptr->druid_extra & 255);
+
+ if ((p_ptr->druid_extra >> 8) & CLASS_MANA_PATH_ERASE)
+ {
+ /* Absorb some of the mana of the grid */
+ p_ptr->csp += cave[p_ptr->py][p_ptr->px].mana / 50;
+ if (p_ptr->csp > p_ptr->msp) p_ptr->csp = p_ptr->msp;
+
+ /* Set the new grid mana */
+ cave[p_ptr->py][p_ptr->px].mana = p_ptr->druid_extra & 255;
+ }
+ else
+ {
+ int m = cave[p_ptr->py][p_ptr->px].mana;
+
+ if (m + (p_ptr->druid_extra & 255) > 255)
+ {
+ cave[p_ptr->py][p_ptr->px].mana = 255;
+ }
+ else
+ {
+ cave[p_ptr->py][p_ptr->px].mana += p_ptr->druid_extra & 255;
+ }
+ }
+ }
+
+ break;
+ }
+
+ /* Lay a path of mana on the floor */
+ case CLASS_WINDS_MANA:
+ {
+ /* Does the player have enought mana ? */
+ if (p_ptr->csp < (s32b)(p_ptr->druid_extra & 255))
+ {
+ p_ptr->druid_extra = CLASS_NONE;
+ msg_print("You stop expulsing mana winds.");
+ }
+ else
+ {
+ int dam = 0;
+
+ /* Use some mana */
+ p_ptr->csp -= (p_ptr->druid_extra & 255);
+
+ if ((p_ptr->druid_extra >> 8) & CLASS_MANA_PATH_ERASE)
+ {
+ dam = (p_ptr->druid_extra & 255) + 256;
+ }
+ else
+ {
+ dam = (p_ptr->druid_extra & 255);
+ }
+
+ fire_explosion(p_ptr->py, p_ptr->px, GF_WINDS_MANA, 2, dam);
+ }
+
+ break;
+ }
+
+ case CLASS_CANALIZE_MANA:
+ {
+ if (p_ptr->druid_extra & CLASS_CANALIZE_MANA_EXTRA)
+ {
+ p_ptr->csp += cave[p_ptr->py][p_ptr->px].mana / 10;
+ }
+ else
+ {
+ p_ptr->csp += cave[p_ptr->py][p_ptr->px].mana / 20;
+ }
+
+ if (p_ptr->csp > p_ptr->msp) p_ptr->csp = p_ptr->msp;
+
+ cave[p_ptr->py][p_ptr->px].mana = 0;
+
+ break;
+ }
+
+ /* CLASS_NONE, possibly others? */
+ default:
+ {
+ /* No mana update */
+ return;
+ }
+ }
+
+ /* Redraw mana */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+}
+
+
+static void check_music()
+{
+ int use_mana;
+
+ /* Music sung by player */
+ if (!p_ptr->music_extra) return;
+
+ use_mana = process_lasting_spell(p_ptr->music_extra);
+
+ if (p_ptr->csp < use_mana)
+ {
+ msg_print("You stop your spell.");
+ p_ptr->music_extra = MUSIC_NONE;
+ p_ptr->music_extra2 = MUSIC_NONE;
+ }
+ else
+ {
+ p_ptr->csp -= use_mana;
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+}
+
+
+/*
+ * Generate the feature effect
+ */
+void apply_effect(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ feature_type *f_ptr = &f_info[c_ptr->feat];
+
+
+ if (f_ptr->d_frequency[0] != 0)
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ /* Check the frequency */
+ if (f_ptr->d_frequency[i] == 0) continue;
+
+ if (((turn % f_ptr->d_frequency[i]) == 0) &&
+ ((f_ptr->d_side[i] != 0) || (f_ptr->d_dice[i] != 0)))
+ {
+ int l, dam = 0;
+ int d = f_ptr->d_dice[i], s = f_ptr->d_side[i];
+
+ if (d == -1) d = p_ptr->lev;
+ if (s == -1) s = p_ptr->lev;
+
+ /* Roll damage */
+ for (l = 0; l < d; l++)
+ {
+ dam += randint(s);
+ }
+
+ /* Apply damage */
+ project( -100, 0, y, x, dam, f_ptr->d_type[i],
+ PROJECT_KILL | PROJECT_HIDE);
+
+ /* Hack -- notice death */
+ if (!alive || death) return;
+ }
+ }
+ }
+}
+
+
+
+/* XXX XXX XXX */
+bool_ is_recall = FALSE;
+
+
+/*
+ * Handle certain things once every 10 game turns
+ *
+ * Note that a single movement in the overhead wilderness mode
+ * consumes 132 times as much energy as a normal one...
+ */
+static void process_world(void)
+{
+ timer_type *t_ptr;
+
+ int x, y, i, j;
+
+ int regen_amount;
+ bool_ cave_no_regen = FALSE;
+ int upkeep_factor = 0;
+
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ cave_type *c_ptr;
+
+ object_type *o_ptr;
+ u32b f1 = 0 , f2 = 0 , f3 = 0, f4 = 0, f5 = 0, esp = 0;
+
+
+ /*
+ * Every 10 game turns -- which means this section is invoked once
+ * in a player turn under the normal speed, and 132 times in a move
+ * in the reduced map mode.
+ */
+ if (turn % 10) return;
+
+ /*
+ * I don't know if this is the right thing to do because I'm totally
+ * ignorant (yes, I must admit that...) about the scripting part of
+ * the game, but since there have been complaints telling us it
+ * runs terribly slow in the reduced map mode... -- pelpel
+ *
+ * Note to coders: if it is desirable to make this active in the
+ * reduced map mode, remove the if condition surrounding the line
+ * and move the code inside into every 1000 game turns section.
+ */
+ if (dun_level || (!p_ptr->wild_mode))
+ {
+ /* Let the script live! */
+ process_hooks(HOOK_PROCESS_WORLD, "()");
+
+ /* Handle the player song */
+ check_music();
+ }
+
+ /* Handle the timers */
+ for (t_ptr = gl_timers; t_ptr != NULL; t_ptr = t_ptr->next)
+ {
+ if (!t_ptr->enabled) continue;
+
+ t_ptr->countdown--;
+ if (!t_ptr->countdown)
+ {
+ t_ptr->countdown = t_ptr->delay;
+ call_lua(t_ptr->callback, "()", "");
+ }
+ }
+
+ /* Handle class special actions */
+ gere_class_special();
+
+ /* Check the fate */
+ if (fate_option && (p_ptr->lev > 10))
+ {
+ /*
+ * WAS: == 666 against randint(50000).
+ * Since CPU's don't know Judeo-Christian / Cabalistic traditions,
+ * and since comparisons with zero is more efficient in many
+ * architectures...
+ */
+ if (rand_int(50000) == 0) gain_fate(0);
+ }
+
+ /*** Is the wielded monsters still hypnotised ***/
+ o_ptr = &p_ptr->inventory[INVEN_CARRY];
+
+ if (o_ptr->k_idx)
+ {
+ monster_race *r_ptr = &r_info[o_ptr->pval];
+
+ if ((randint(1000) < r_ptr->level - ((p_ptr->lev * 2) + get_skill(SKILL_SYMBIOTIC))))
+ {
+ msg_format("%s breaks free from hypnosis!",
+ symbiote_name(TRUE));
+ carried_make_attack_normal(o_ptr->pval);
+ }
+ }
+
+ /*** Attempt timed autosave ***/
+ if (autosave_t && autosave_freq)
+ {
+ if ((turn % ((s32b)autosave_freq * 10)) == 0)
+ {
+ is_autosave = TRUE;
+ msg_print("Autosaving the game...");
+ do_cmd_save_game();
+ is_autosave = FALSE;
+ }
+ }
+
+
+ /*** Handle the wilderness/town (sunshine) ***/
+
+ /* While in town/wilderness and not in the overworld mode */
+ if (!dun_level && !p_ptr->wild_mode)
+ {
+ /* Hack -- Daybreak/Nighfall in town */
+ if ((turn % ((10L * DAY) / 2)) == 0)
+ {
+ bool_ dawn;
+
+ /* Check for dawn */
+ dawn = ((turn % (10L * DAY)) == 0);
+
+ /* Day breaks */
+ if (dawn)
+ {
+ /* Message */
+ msg_print("The sun has risen.");
+
+ /* Hack -- Scan the town */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ /* Get the cave grid */
+ c_ptr = &cave[y][x];
+
+ /* Assume lit */
+ c_ptr->info |= (CAVE_GLOW);
+
+ /* Hack -- Memorize lit grids if allowed */
+ if (view_perma_grids) c_ptr->info |= (CAVE_MARK);
+
+ /* Hack -- Notice spot */
+ note_spot(y, x);
+ }
+ }
+ }
+
+ /* Night falls */
+ else
+ {
+ /* Message */
+ msg_print("The sun has set.");
+
+ /* Hack -- Scan the town */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ /* Get the cave grid */
+ c_ptr = &cave[y][x];
+
+ /* Darken "boring" features */
+ if (cave_plain_floor_grid(c_ptr))
+ {
+ /* Forget the grid */
+ c_ptr->info &= ~(CAVE_GLOW | CAVE_MARK);
+
+ /* Hack -- Notice spot */
+ note_spot(y, x);
+ }
+ }
+ }
+ }
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+ }
+ }
+
+ /* Tell a day passed */
+ if (((turn + (DAY_START * 10L)) % (10L * DAY)) == 0)
+ {
+ char buf[20];
+
+ sprintf(buf, "%s", get_day(bst(YEAR, turn) + START_YEAR));
+ cmsg_format(TERM_L_GREEN,
+ "Today it is %s of the %s year of the third age.",
+ get_month_name(bst(DAY, turn), wizard, FALSE), buf);
+ }
+
+ /* Set back the rewards once a day */
+ if ((turn % (10L * STORE_TURNS)) == 0)
+ {
+ /* Select new bounties. */
+ if (magik(20)) select_bounties();
+ }
+
+ /* Modify loan */
+ if (p_ptr->loan)
+ {
+ if (p_ptr->loan_time) p_ptr->loan_time--;
+
+ if (((turn % 5000) == 0) && !p_ptr->loan_time)
+ {
+ cmsg_print(TERM_RED, "You should pay your loan...");
+
+ p_ptr->loan += p_ptr->loan / 12;
+
+ if (p_ptr->loan > PY_MAX_GOLD) p_ptr->loan = PY_MAX_GOLD;
+
+ /* Do a nasty stuff */
+ if (p_ptr->wild_mode && rand_int(2))
+ {
+ /* Discount player items */
+ int z = 0, tries = 200;
+ object_type *o_ptr = NULL;
+
+ while (tries--)
+ {
+ z = rand_int(INVEN_TOTAL);
+ o_ptr = &p_ptr->inventory[z];
+
+ if (!o_ptr->k_idx) continue;
+
+ if (o_ptr->discount >= 100) continue;
+
+ break;
+ }
+
+ if (tries)
+ {
+ o_ptr->discount += 70;
+ if (o_ptr->discount >= 100) o_ptr->discount = 100;
+
+ inven_item_optimize(z);
+ inven_item_describe(z);
+
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ }
+ }
+
+ else
+ {
+ int merc = test_monster_name("Mean-looking mercenary");
+ int agent = test_monster_name("Agent of the black market");
+ int num = 5 + (p_ptr->lev / 3), z;
+
+ for (z = 0; z < num; z++)
+ {
+ int yy, xx, attempts = 200, m_idx;
+
+ /* Summon */
+ while (1)
+ {
+ scatter(&yy, &xx, p_ptr->py, p_ptr->px, 6);
+
+ /* Accept an empty grid within the boundary */
+ if (in_bounds(yy, xx) && cave_floor_bold(yy, xx)) break;
+
+ /* Max number of retries reached */
+ if (--attempts == 0) break;
+ }
+
+ /* All the attempts failed */
+ if (attempts == 0) continue;
+
+ /* Summon a monster */
+ m_idx = place_monster_one(yy, xx, magik(80) ? merc : agent,
+ 0, FALSE, MSTATUS_ENEMY);
+
+ /* Level it */
+ if (m_idx)
+ {
+ monster_type *m_ptr = &m_list[m_idx];
+
+ m_ptr->exp = MONSTER_EXP(p_ptr->lev * 2);
+ monster_check_experience(m_idx, TRUE);
+ }
+ }
+ }
+ }
+ }
+
+ /*** Process the monsters ***/
+
+ /* Check for creature generation. */
+ if (!p_ptr->wild_mode &&
+ !p_ptr->inside_arena &&
+ !p_ptr->inside_quest &&
+ (rand_int(d_info[(dun_level) ? dungeon_type : DUNGEON_WILDERNESS].max_m_alloc_chance) == 0))
+ {
+ /* Make a new monster */
+ if (!(dungeon_flags2 & DF2_NO_NEW_MONSTER))
+ {
+ (void)alloc_monster(MAX_SIGHT + 5, FALSE);
+ }
+ }
+
+ /* Hack -- Check for creature regeneration */
+ if (!p_ptr->wild_mode && ((turn % 100) == 0)) regen_monsters();
+
+
+ /*** Damage over Time ***/
+
+ /* Take damage from poison */
+ if (p_ptr->poisoned && !p_ptr->invuln)
+ {
+ /* Take damage */
+ take_hit(1, "poison");
+ }
+
+
+ /* Vampires take damage from sunlight */
+ if (p_ptr->sensible_lite)
+ {
+ if ((!dun_level) && (((turn / ((10L * DAY) / 2)) % 2) == 0))
+ {
+ if (cave[p_ptr->py][p_ptr->px].info & (CAVE_GLOW))
+ {
+ /* Take damage */
+ msg_print("The sun's rays scorch your undead flesh!");
+ take_hit(1, "sunlight");
+ cave_no_regen = TRUE;
+ drop_from_wild();
+ }
+ }
+
+ if ((p_ptr->inventory[INVEN_LITE].tval != 0) &&
+ (p_ptr->inventory[INVEN_LITE].sval >= SV_LITE_GALADRIEL) &&
+ (p_ptr->inventory[INVEN_LITE].sval <= SV_STONE_LORE) &&
+ (p_ptr->inventory[INVEN_LITE].sval != SV_LITE_UNDEATH))
+ {
+ object_type * o_ptr = &p_ptr->inventory[INVEN_LITE];
+ char o_name [80];
+ char ouch [80];
+
+ /* Get an object description */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ msg_format("The %s scorches your undead flesh!", o_name);
+
+ cave_no_regen = TRUE;
+
+ /* Get an object description */
+ object_desc(o_name, o_ptr, TRUE, 0);
+
+ sprintf(ouch, "wielding %s", o_name);
+ take_hit(1, ouch);
+ }
+ }
+
+ /* Drown in deep water unless the player have levitation, water walking
+ water breathing, or magic breathing.*/
+ if (!p_ptr->ffall && !p_ptr->walk_water && !p_ptr->magical_breath &&
+ !p_ptr->water_breath &&
+ (cave[p_ptr->py][p_ptr->px].feat == FEAT_DEEP_WATER))
+ {
+ if (calc_total_weight() > ((weight_limit()) / 2))
+ {
+ /* Take damage */
+ msg_print("You are drowning!");
+ take_hit(randint(p_ptr->lev), "drowning");
+ cave_no_regen = TRUE;
+ }
+ }
+
+
+ /* Spectres -- take damage when moving through walls */
+
+ /*
+ * Added: ANYBODY takes damage if inside through walls
+ * without wraith form -- NOTE: Spectres will never be
+ * reduced below 0 hp by being inside a stone wall; others
+ * WILL BE!
+ */
+ if (!cave_floor_bold(p_ptr->py, p_ptr->px))
+ {
+ int feature = cave[p_ptr->py][p_ptr->px].feat;
+
+ /* Player can walk through or fly over trees */
+ if ((has_ability(AB_TREE_WALK) || p_ptr->fly) && (feature == FEAT_TREES))
+ {
+ /* Do nothing */
+ }
+ /* Player can climb over mountains */
+ else if ((p_ptr->climb) && (f_info[feature].flags1 & FF1_CAN_CLIMB))
+ {
+ /* Do nothing */
+ }
+ else if (PRACE_FLAG(PR1_SEMI_WRAITH) && (!p_ptr->wraith_form) && (f_info[cave[p_ptr->py][p_ptr->px].feat].flags1 & FF1_CAN_PASS))
+ {
+ int amt = 1 + ((p_ptr->lev) / 5);
+
+ cave_no_regen = TRUE;
+ if (amt > p_ptr->chp - 1) amt = p_ptr->chp - 1;
+ take_hit(amt, " walls ...");
+ }
+ }
+
+
+ /* Take damage from cuts */
+ if ((p_ptr->cut) && !(p_ptr->invuln))
+ {
+ /* Mortal wound or Deep Gash */
+ if (p_ptr->cut > 200)
+ {
+ i = 3;
+ }
+
+ /* Severe cut */
+ else if (p_ptr->cut > 100)
+ {
+ i = 2;
+ }
+
+ /* Other cuts */
+ else
+ {
+ i = 1;
+ }
+
+ /* Take damage */
+ take_hit(i, "a fatal wound");
+ }
+
+
+ /*** Check the Food, and Regenerate ***/
+
+ /* Digest normally */
+ if (p_ptr->food < PY_FOOD_MAX)
+ {
+ /* Every 100 game turns */
+ if ((turn % 100) == 0)
+ {
+ int speed_use = p_ptr->pspeed;
+
+ /* Maximum */
+ if (speed_use > 199)
+ {
+ speed_use = 199;
+ }
+
+ /* Minimum */
+ else if (speed_use < 0)
+ {
+ speed_use = 0;
+ }
+
+ /* Basic digestion rate based on speed */
+ i = extract_energy[speed_use] * 2;
+
+ /* Regeneration takes more food */
+ if (p_ptr->regenerate) i += 30;
+
+ /* Regeneration takes more food */
+ if (p_ptr->tim_regen) i += p_ptr->tim_regen_pow / 10;
+
+ /* Invisibility consume a lot of food */
+ i += p_ptr->invis / 2;
+
+ /* Invulnerability consume a lot of food */
+ if (p_ptr->invuln) i += 40;
+
+ /* Wraith Form consume a lot of food */
+ if (p_ptr->wraith_form) i += 30;
+
+ /* Get the weapon */
+ o_ptr = &p_ptr->inventory[INVEN_WIELD];
+
+ /* Examine the sword */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hitpoints multiplier consume a lot of food */
+ if (o_ptr->k_idx && (f2 & (TR2_LIFE))) i += o_ptr->pval * 5;
+
+ /* Slow digestion takes less food */
+ if (p_ptr->slow_digest) i -= 10;
+
+ /* Minimal digestion */
+ if (i < 1) i = 1;
+
+ /* Digest some food */
+ (void)set_food(p_ptr->food - i);
+ }
+ }
+
+ /* Digest quickly when gorged */
+ else
+ {
+ /* Digest a lot of food */
+ (void)set_food(p_ptr->food - 100);
+ }
+
+ /* Starve to death (slowly) */
+ if (p_ptr->food < PY_FOOD_STARVE)
+ {
+ /* Calculate damage */
+ i = (PY_FOOD_STARVE - p_ptr->food) / 10;
+
+ /* Take damage */
+ if (!(p_ptr->invuln)) take_hit(i, "starvation");
+ }
+
+ /* Default regeneration */
+ regen_amount = PY_REGEN_NORMAL;
+
+ /* Getting Weak */
+ if (p_ptr->food < PY_FOOD_WEAK)
+ {
+ /* Lower regeneration */
+ if (p_ptr->food < PY_FOOD_STARVE)
+ {
+ regen_amount = 0;
+ }
+ else if (p_ptr->food < PY_FOOD_FAINT)
+ {
+ regen_amount = PY_REGEN_FAINT;
+ }
+ else
+ {
+ regen_amount = PY_REGEN_WEAK;
+ }
+
+ /* Getting Faint */
+ if (p_ptr->food < PY_FOOD_FAINT)
+ {
+ /* Faint occasionally */
+ if (!p_ptr->paralyzed && (rand_int(100) < 10))
+ {
+ /* Message */
+ msg_print("You faint from the lack of food.");
+ disturb(1, 0);
+
+ /* Hack -- faint (bypass free action) */
+ (void)set_paralyzed(p_ptr->paralyzed + 1 + rand_int(5));
+ }
+ }
+ }
+
+ /* Are we walking the pattern? */
+ if (!p_ptr->wild_mode && pattern_effect())
+ {
+ cave_no_regen = TRUE;
+ }
+ else
+ {
+ /* Regeneration ability */
+ if (p_ptr->regenerate)
+ {
+ regen_amount = regen_amount * 2;
+ }
+ }
+
+
+ /* Searching or Resting */
+ if (p_ptr->searching || resting)
+ {
+ regen_amount = regen_amount * 2;
+ }
+
+ if (total_friends)
+ {
+ int upkeep_divider = 20;
+
+ if (has_ability(AB_PERFECT_CASTING))
+ upkeep_divider = 15;
+
+#ifdef TRACK_FRIENDS
+
+ if (wizard) msg_format("Total friends: %d.", total_friends);
+
+#endif /* TRACK_FRIENDS */
+
+ if (total_friends > 1 + (p_ptr->lev / (upkeep_divider)))
+ {
+ upkeep_factor = (total_friend_levels);
+
+ if (upkeep_factor > 100) upkeep_factor = 100;
+ else if (upkeep_factor < 10) upkeep_factor = 10;
+
+#ifdef TRACK_FRIENDS
+
+ if (wizard) msg_format("Levels %d, upkeep %d", total_friend_levels,
+ upkeep_factor);
+
+#endif /* TRACK_FRIENDS */
+ }
+ }
+
+ /* Regenerate the mana */
+ if (p_ptr->csp < p_ptr->msp)
+ {
+ if (upkeep_factor)
+ {
+ s16b upkeep_regen = (((100 - upkeep_factor) * regen_amount) / 100);
+ regenmana(upkeep_regen);
+
+#ifdef TRACK_FRIENDS
+
+ if (wizard)
+ {
+ msg_format("Regen: %d/%d", upkeep_regen, regen_amount);
+ }
+
+#endif /* TRACK_FRIENDS */
+ }
+ else
+ {
+ regenmana(regen_amount);
+ }
+ }
+
+ /* Eru piety incraese with time */
+ if (((turn % 100) == 0) && (!p_ptr->did_nothing) && (!p_ptr->wild_mode))
+ {
+ NOT_PRAY_GOD(GOD_ERU)
+ {
+ int inc = wisdom_scale(10);
+
+ /* Increase by wisdom/4 */
+ if (!inc) inc = 1;
+ inc_piety(GOD_ERU, inc);
+ }
+ }
+ /* Most gods piety decrease with time */
+ if (((turn % 300) == 0) && (!p_ptr->did_nothing) && (!p_ptr->wild_mode) && (dun_level))
+ {
+ GOD(GOD_MANWE)
+ {
+ int dec = 4 - wisdom_scale(3);
+
+ PRAY_GOD(GOD_MANWE)
+ dec++;
+ if (PRACE_FLAG(PR1_ELF))
+ dec -= wisdom_scale(2);
+ if (dec < 1) dec = 1;
+ inc_piety(GOD_MANWE, -dec);
+ }
+ GOD(GOD_MELKOR)
+ {
+ int dec = 8 - wisdom_scale(6);
+
+ PRAY_GOD(GOD_MELKOR)
+ dec++;
+ if (PRACE_FLAG(PR1_ELF))
+ dec += 5 - wisdom_scale(4);
+ if (dec < 1) dec = 1;
+ inc_piety(GOD_MELKOR, -dec);
+ }
+ PRAY_GOD(GOD_TULKAS)
+ {
+ int dec = 4 - wisdom_scale(3);
+
+ if (dec < 1) dec = 1;
+ inc_piety(GOD_TULKAS, -dec);
+ }
+ }
+ /* Yavanna piety decrease with time */
+ if (((turn % 400) == 0) && (!p_ptr->did_nothing) && (!p_ptr->wild_mode) && (dun_level))
+ {
+ GOD(GOD_YAVANNA)
+ {
+ int dec = 5 - wisdom_scale(3);
+
+ /* Blech what an hideous hack */
+ if (!strcmp(rp_ptr->title + rp_name, "Ent"))
+ dec -= wisdom_scale(2);
+ if (dec < 1) dec = 1;
+ inc_piety(GOD_YAVANNA, -dec);
+ }
+ }
+ p_ptr->did_nothing = FALSE;
+
+ /* Increase regen by tim regen */
+ if (p_ptr->tim_regen) regen_amount += p_ptr->tim_regen_pow;
+
+ /* Poisoned or cut yields no healing */
+ if (p_ptr->poisoned) regen_amount = 0;
+ if (p_ptr->cut) regen_amount = 0;
+
+ /* Special floor -- Pattern, in a wall -- yields no healing */
+ if (cave_no_regen) regen_amount = 0;
+
+ /* Being over grass allows Yavanna to regen you */
+ PRAY_GOD(GOD_YAVANNA)
+ {
+ if (cave[p_ptr->py][p_ptr->px].feat == FEAT_GRASS)
+ {
+ regen_amount += 200 + wisdom_scale(800);
+ }
+ }
+
+ /* Regenerate Hit Points if needed */
+ if ((p_ptr->chp < p_ptr->mhp) && !cave_no_regen)
+ {
+ if ((cave[p_ptr->py][p_ptr->px].feat < FEAT_PATTERN_END) &&
+ (cave[p_ptr->py][p_ptr->px].feat >= FEAT_PATTERN_START))
+ {
+ /* Hmmm. this should never happen? */
+ regenhp(regen_amount / 5);
+ }
+ else
+ {
+ regenhp(regen_amount);
+ }
+ }
+
+
+ /*** Timeout Various Things ***/
+
+ /* Handle temporary stat drains */
+ for (i = 0; i < 6; i++)
+ {
+ if (p_ptr->stat_cnt[i] > 0)
+ {
+ p_ptr->stat_cnt[i]--;
+ if (p_ptr->stat_cnt[i] == 0)
+ {
+ do_res_stat(i, FALSE);
+ }
+ }
+ }
+
+ /* Hack -- Hallucinating */
+ if (p_ptr->image)
+ {
+ (void)set_image(p_ptr->image - 1);
+ }
+
+ /* Holy Aura */
+ if (p_ptr->holy)
+ {
+ (void)set_holy(p_ptr->holy - 1);
+ }
+
+ /* Soul absorbtion */
+ if (p_ptr->absorb_soul)
+ {
+ (void)set_absorb_soul(p_ptr->absorb_soul - 1);
+ }
+
+ /* Undead loose Death Points */
+ if (p_ptr->necro_extra & CLASS_UNDEAD)
+ {
+ int old_chp = p_ptr->chp;
+ int warning = (p_ptr->mhp * hitpoint_warn / 10);
+
+ /* Bypass invulnerability and wraithform */
+ p_ptr->chp--;
+
+ /* Display the hitpoints */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Dead player */
+ if (p_ptr->chp < 0)
+ {
+ bool_ old_quick = quick_messages;
+
+ /* Sound */
+ sound(SOUND_DEATH);
+
+ /* Hack -- Note death */
+ if (!last_words)
+ {
+ msg_print("You die.");
+ msg_print(NULL);
+ }
+ else
+ {
+ char death_message[80];
+
+ (void)get_rnd_line("death.txt", death_message);
+ msg_print(death_message);
+ }
+
+ /* Note cause of death */
+ (void)strcpy(died_from, "being undead too long");
+
+ if (p_ptr->image) strcat(died_from, "(?)");
+
+ /* No longer a winner */
+ total_winner = FALSE;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+
+ /* Note death */
+ death = TRUE;
+
+ quick_messages = FALSE;
+ if (get_check("Make a last screenshot? "))
+ {
+ do_cmd_html_dump();
+ }
+ quick_messages = old_quick;
+
+ /* Dead */
+ return;
+ }
+
+ /* Hitpoint warning */
+ if (p_ptr->chp < warning)
+ {
+ /* Hack -- bell on first notice */
+ if (alert_hitpoint && (old_chp > warning)) bell();
+
+ sound(SOUND_WARN);
+
+ /* Message */
+ msg_print("*** LOW DEATHPOINT WARNING! ***");
+ msg_print(NULL);
+ }
+ }
+
+ /* Walk water */
+ if (p_ptr->walk_water)
+ {
+ (void)set_walk_water(p_ptr->walk_water - 1);
+ }
+
+ /* True Strike */
+ if (p_ptr->strike)
+ {
+ (void)set_strike(p_ptr->strike - 1);
+ }
+
+ /* Meditation */
+ if (p_ptr->meditation)
+ {
+ (void)set_meditation(p_ptr->meditation - 1);
+ }
+
+ /* Timed project */
+ if (p_ptr->tim_project)
+ {
+ (void)set_project(p_ptr->tim_project - 1, p_ptr->tim_project_gf, p_ptr->tim_project_dam, p_ptr->tim_project_rad, p_ptr->tim_project_flag);
+ }
+
+ /* Timed roots */
+ if (p_ptr->tim_roots)
+ {
+ (void)set_roots(p_ptr->tim_roots - 1, p_ptr->tim_roots_ac, p_ptr->tim_roots_dam);
+ }
+
+ /* Timed breath */
+ if (p_ptr->tim_water_breath)
+ {
+ (void)set_tim_breath(p_ptr->tim_water_breath - 1, FALSE);
+ }
+ if (p_ptr->tim_magic_breath)
+ {
+ (void)set_tim_breath(p_ptr->tim_magic_breath - 1, TRUE);
+ }
+
+ /* Timed regen */
+ if (p_ptr->tim_regen)
+ {
+ (void)set_tim_regen(p_ptr->tim_regen - 1, p_ptr->tim_regen_pow);
+ }
+
+ /* Timed Disrupt shield */
+ if (p_ptr->disrupt_shield)
+ {
+ (void)set_disrupt_shield(p_ptr->disrupt_shield - 1);
+ }
+
+ /* Timed Parasite */
+ if (p_ptr->parasite)
+ {
+ (void)set_parasite(p_ptr->parasite - 1, p_ptr->parasite_r_idx);
+ }
+
+ /* Timed Reflection */
+ if (p_ptr->tim_reflect)
+ {
+ (void)set_tim_reflect(p_ptr->tim_reflect - 1);
+ }
+
+ /* Timed Prob Travel */
+ if (p_ptr->prob_travel)
+ {
+ (void)set_prob_travel(p_ptr->prob_travel - 1);
+ }
+
+ /* Timed Time Resistance */
+ if (p_ptr->tim_res_time)
+ {
+ (void)set_tim_res_time(p_ptr->tim_res_time - 1);
+ }
+
+ /* Timed Levitation */
+ if (p_ptr->tim_ffall)
+ {
+ (void)set_tim_ffall(p_ptr->tim_ffall - 1);
+ }
+ if (p_ptr->tim_fly)
+ {
+ (void)set_tim_fly(p_ptr->tim_fly - 1);
+ }
+
+ /* Thunderstorm */
+ if (p_ptr->tim_thunder)
+ {
+ int dam = damroll(p_ptr->tim_thunder_p1, p_ptr->tim_thunder_p2);
+ int i, tries = 600;
+ monster_type *m_ptr = NULL;
+
+ while (tries)
+ {
+ /* Access the monster */
+ m_ptr = &m_list[i = rand_range(1, m_max - 1)];
+
+ tries--;
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Cant see ? cant hit */
+ if (!los(p_ptr->py, p_ptr->px, m_ptr->fy, m_ptr->fx)) continue;
+
+ /* Do not hurt friends! */
+ if (is_friend(m_ptr) >= 0) continue;
+ break;
+ }
+
+ if (tries)
+ {
+ char m_name[80];
+
+ monster_desc(m_name, m_ptr, 0);
+ msg_format("Lightning strikes %s.", m_name);
+ project(0, 0, m_ptr->fy, m_ptr->fx, dam / 3, GF_ELEC,
+ PROJECT_KILL | PROJECT_ITEM | PROJECT_HIDE);
+ project(0, 0, m_ptr->fy, m_ptr->fx, dam / 3, GF_LITE,
+ PROJECT_KILL | PROJECT_ITEM | PROJECT_HIDE);
+ project(0, 0, m_ptr->fy, m_ptr->fx, dam / 3, GF_SOUND,
+ PROJECT_KILL | PROJECT_ITEM | PROJECT_HIDE);
+ }
+
+ (void)set_tim_thunder(p_ptr->tim_thunder - 1, p_ptr->tim_thunder_p1, p_ptr->tim_thunder_p2);
+ }
+
+ /* Poisonned hands */
+ if (p_ptr->tim_poison)
+ {
+ (void)set_poison(p_ptr->tim_poison - 1);
+ }
+
+ /* Timed Fire Aura */
+ if (p_ptr->tim_fire_aura)
+ {
+ (void)set_tim_fire_aura(p_ptr->tim_fire_aura - 1);
+ }
+
+ /* Brightness */
+ if (p_ptr->tim_lite)
+ {
+ (void)set_lite(p_ptr->tim_lite - 1);
+ }
+
+ /* Blindness */
+ if (p_ptr->blind)
+ {
+ (void)set_blind(p_ptr->blind - 1);
+ }
+
+ /* Timed no_breeds */
+ if (no_breeds)
+ {
+ (void)set_no_breeders(no_breeds - 1);
+ }
+
+ /* Timed mimic */
+ if (p_ptr->tim_mimic)
+ {
+ (void)set_mimic(p_ptr->tim_mimic - 1, p_ptr->mimic_form, p_ptr->mimic_level);
+ }
+
+ /* Timed special move commands */
+ if (p_ptr->immov_cntr)
+ {
+ p_ptr->immov_cntr--;
+ }
+
+ /* Timed invisibility */
+ if (p_ptr->tim_invisible)
+ {
+ (void)set_invis(p_ptr->tim_invisible - 1, p_ptr->tim_inv_pow);
+ }
+
+ /* Times see-invisible */
+ if (p_ptr->tim_invis)
+ {
+ (void)set_tim_invis(p_ptr->tim_invis - 1);
+ }
+
+ if (multi_rew)
+ {
+ multi_rew = FALSE;
+ }
+
+ /* Timed esp */
+ if (p_ptr->tim_esp)
+ {
+ (void)set_tim_esp(p_ptr->tim_esp - 1);
+ }
+
+ /* Timed infra-vision */
+ if (p_ptr->tim_infra)
+ {
+ (void)set_tim_infra(p_ptr->tim_infra - 1);
+ }
+
+ /* Paralysis */
+ if (p_ptr->paralyzed)
+ {
+ (void)set_paralyzed(p_ptr->paralyzed - 1);
+ }
+
+ /* Confusion */
+ if (p_ptr->confused)
+ {
+ (void)set_confused(p_ptr->confused - 1);
+ }
+
+ /* Afraid */
+ if (p_ptr->afraid)
+ {
+ (void)set_afraid(p_ptr->afraid - 1);
+ }
+
+ /* Fast */
+ if (p_ptr->fast)
+ {
+ (void)set_fast(p_ptr->fast - 1, p_ptr->speed_factor);
+ }
+
+ /* Light speed */
+ if (p_ptr->lightspeed)
+ {
+ (void)set_light_speed(p_ptr->lightspeed - 1);
+ }
+
+ /* Slow */
+ if (p_ptr->slow)
+ {
+ (void)set_slow(p_ptr->slow - 1);
+ }
+
+ /* Protection from evil */
+ if (p_ptr->protevil)
+ {
+ (void)set_protevil(p_ptr->protevil - 1);
+ }
+
+ /* Protection from good */
+ if (p_ptr->protgood)
+ {
+ (void)set_protgood(p_ptr->protgood - 1);
+ }
+
+ /* Protection from undead */
+ if (p_ptr->protundead)
+ {
+ (void)set_protundead(p_ptr->protundead - 1);
+ }
+
+ /* Invulnerability */
+ if (p_ptr->invuln)
+ {
+ (void)set_invuln(p_ptr->invuln - 1);
+ }
+
+ /* Wraith form */
+ if (p_ptr->tim_wraith)
+ {
+ (void)set_shadow(p_ptr->tim_wraith - 1);
+ }
+
+ /* Heroism */
+ if (p_ptr->hero)
+ {
+ (void)set_hero(p_ptr->hero - 1);
+ }
+
+ /* Super Heroism */
+ if (p_ptr->shero)
+ {
+ (void)set_shero(p_ptr->shero - 1);
+ }
+
+ /* Blessed */
+ if (p_ptr->blessed)
+ {
+ (void)set_blessed(p_ptr->blessed - 1);
+ }
+
+ /* Shield */
+ if (p_ptr->shield)
+ {
+ (void)set_shield(p_ptr->shield - 1, p_ptr->shield_power, p_ptr->shield_opt, p_ptr->shield_power_opt, p_ptr->shield_power_opt2);
+ }
+
+ /* Oppose Acid */
+ if (p_ptr->oppose_acid)
+ {
+ (void)set_oppose_acid(p_ptr->oppose_acid - 1);
+ }
+
+ /* Oppose Lightning */
+ if (p_ptr->oppose_elec)
+ {
+ (void)set_oppose_elec(p_ptr->oppose_elec - 1);
+ }
+
+ /* Oppose Fire */
+ if (p_ptr->oppose_fire)
+ {
+ (void)set_oppose_fire(p_ptr->oppose_fire - 1);
+ }
+
+ /* Oppose Cold */
+ if (p_ptr->oppose_cold)
+ {
+ (void)set_oppose_cold(p_ptr->oppose_cold - 1);
+ }
+
+ /* Oppose Poison */
+ if (p_ptr->oppose_pois)
+ {
+ (void)set_oppose_pois(p_ptr->oppose_pois - 1);
+ }
+
+ /* Oppose Light & Dark */
+ if (p_ptr->oppose_ld)
+ {
+ (void)set_oppose_ld(p_ptr->oppose_ld - 1);
+ }
+
+ /* Oppose Chaos & Confusion */
+ if (p_ptr->oppose_cc)
+ {
+ (void)set_oppose_cc(p_ptr->oppose_cc - 1);
+ }
+
+ /* Oppose Sound & Shards */
+ if (p_ptr->oppose_ss)
+ {
+ (void)set_oppose_ss(p_ptr->oppose_ss - 1);
+ }
+
+ /* Oppose Nexus */
+ if (p_ptr->oppose_nex)
+ {
+ (void)set_oppose_nex(p_ptr->oppose_nex - 1);
+ }
+
+ /* Mental Barrier */
+ if (p_ptr->tim_mental_barrier)
+ {
+ (void)set_mental_barrier(p_ptr->tim_mental_barrier - 1);
+ }
+
+ /* The rush */
+ if (p_ptr->rush)
+ {
+ (void)set_rush(p_ptr->rush - 1);
+ }
+
+
+ /* Timed mimicry */
+ if (get_skill(SKILL_MIMICRY))
+ {
+ /* Extract the value and the flags */
+ u32b value = p_ptr->mimic_extra >> 16;
+
+ u32b att = p_ptr->mimic_extra & 0xFFFF;
+
+ if ((att & CLASS_LEGS) || (att & CLASS_WALL) || (att & CLASS_ARMS))
+ {
+ value--;
+
+ if (!value)
+ {
+ if (att & CLASS_LEGS) msg_print("You lose your extra pair of legs.");
+ if (att & CLASS_ARMS) msg_print("You lose your extra pair of arms.");
+ if (att & CLASS_WALL) msg_print("You lose your affinity for walls.");
+
+ att &= ~(CLASS_ARMS);
+ att &= ~(CLASS_LEGS);
+ att &= ~(CLASS_WALL);
+
+ if (disturb_state) disturb(0, 0);
+ }
+
+ p_ptr->update |= (PU_BODY);
+ p_ptr->mimic_extra = att + (value << 16);
+ }
+ }
+
+
+ /*** Poison and Stun and Cut ***/
+
+ /* Poison */
+ if (p_ptr->poisoned)
+ {
+ int adjust = (adj_con_fix[p_ptr->stat_ind[A_CON]] + 1);
+
+ /* Apply some healing */
+ (void)set_poisoned(p_ptr->poisoned - adjust);
+ }
+
+ /* Stun */
+ if (p_ptr->stun)
+ {
+ int adjust = (adj_con_fix[p_ptr->stat_ind[A_CON]] + 1);
+
+ /* Apply some healing */
+ (void)set_stun(p_ptr->stun - adjust);
+ }
+
+ /* Cut */
+ if (p_ptr->cut)
+ {
+ int adjust = (adj_con_fix[p_ptr->stat_ind[A_CON]] + 1);
+
+ /* Hack -- Truly "mortal" wound */
+ if (p_ptr->cut > 1000) adjust = 0;
+
+ /* Apply some healing */
+ (void)set_cut(p_ptr->cut - adjust);
+ }
+
+ /* Hack - damage done by the dungeon -SC- */
+ if ((dun_level != 0) && (d_ptr->d_frequency[0] != 0))
+ {
+ int i, j, k;
+
+ /* Apply damage to every grid in the dungeon */
+ for (i = 0; i < 4; i++)
+ {
+ /* Check the frequency */
+ if (d_ptr->d_frequency[i] == 0) continue;
+
+ if (((turn % d_ptr->d_frequency[i]) == 0) &&
+ ((d_ptr->d_side[i] != 0) || (d_ptr->d_dice[i] != 0)))
+ {
+ for (j = 0; j < cur_hgt - 1; j++)
+ {
+ for (k = 0; k < cur_wid - 1; k++)
+ {
+ int l, dam = 0;
+
+ if (!(dungeon_flags1 & DF1_DAMAGE_FEAT))
+ {
+ /* If the grid is empty, skip it */
+ if ((cave[j][k].o_idx == 0) &&
+ ((j != p_ptr->py) && (i != p_ptr->px))) continue;
+ }
+
+ /* Let's not hurt poor monsters */
+ if (cave[j][k].m_idx) continue;
+
+ /* Roll damage */
+ for (l = 0; l < d_ptr->d_dice[i]; l++)
+ {
+ dam += randint(d_ptr->d_side[i]);
+ }
+
+ /* Apply damage */
+ project( -100, 0, j, k, dam, d_ptr->d_type[i],
+ PROJECT_KILL | PROJECT_ITEM | PROJECT_HIDE);
+ }
+ }
+ }
+ }
+ }
+
+ /* handle spell effects */
+ if (!p_ptr->wild_mode)
+ {
+ /*
+ * I noticed significant performance degrade after the introduction
+ * of staying spell effects. I believe serious optimisation effort
+ * is required before another release.
+ *
+ * More important is to fix that display weirdness...
+ *
+ * It seems that the game never expects that monster deaths and
+ * terrain feature changes should happen here... Moving these
+ * to process_player() [before resting code, with "every 10 game turn"
+ * 'if'] may or may not fix the problem... -- pelpel to DG
+ */
+ for (j = 0; j < cur_hgt - 1; j++)
+ {
+ for (i = 0; i < cur_wid - 1; i++)
+ {
+ int e = cave[j][i].effect;
+
+ if (e)
+ {
+ effect_type *e_ptr = &effects[e];
+
+ if (e_ptr->time)
+ {
+ /* Apply damage */
+ project(0, 0, j, i, e_ptr->dam, e_ptr->type,
+ PROJECT_KILL | PROJECT_ITEM | PROJECT_HIDE);
+ }
+ else
+ {
+ cave[j][i].effect = 0;
+ }
+
+ if ((e_ptr->flags & EFF_WAVE) && !(e_ptr->flags & EFF_LAST))
+ {
+ if (distance(e_ptr->cy, e_ptr->cx, j, i) < e_ptr->rad - 1)
+ cave[j][i].effect = 0;
+ }
+ else if ((e_ptr->flags & EFF_STORM) && !(e_ptr->flags & EFF_LAST))
+ {
+ cave[j][i].effect = 0;
+ }
+
+ lite_spot(j, i);
+ }
+ }
+ }
+
+ /* Reduce & handle effects */
+ for (i = 0; i < MAX_EFFECTS; i++)
+ {
+ /* Skip empty slots */
+ if (effects[i].time == 0) continue;
+
+ /* Reduce duration */
+ effects[i].time--;
+
+ /* Creates a "wave" effect*/
+ if (effects[i].flags & EFF_WAVE)
+ {
+ effect_type *e_ptr = &effects[i];
+ int x, y, z;
+
+ e_ptr->rad++;
+
+ /* What a frelling ugly line of ifs ... */
+ if (effects[i].flags & EFF_DIR8)
+ for (y = e_ptr->cy - e_ptr->rad, z = 0; y <= e_ptr->cy; y++, z++)
+ {
+ for (x = e_ptr->cx - (e_ptr->rad - z); x <= e_ptr->cx + (e_ptr->rad - z); x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) == e_ptr->rad))
+ cave[y][x].effect = i;
+ }
+ }
+ else if (effects[i].flags & EFF_DIR2)
+ for (y = e_ptr->cy, z = e_ptr->rad; y <= e_ptr->cy + e_ptr->rad; y++, z--)
+ {
+ for (x = e_ptr->cx - (e_ptr->rad - z); x <= e_ptr->cx + (e_ptr->rad - z); x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) == e_ptr->rad))
+ cave[y][x].effect = i;
+ }
+ }
+ else if (effects[i].flags & EFF_DIR6)
+ for (x = e_ptr->cx, z = e_ptr->rad; x <= e_ptr->cx + e_ptr->rad; x++, z--)
+ {
+ for (y = e_ptr->cy - (e_ptr->rad - z); y <= e_ptr->cy + (e_ptr->rad - z); y++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) == e_ptr->rad))
+ cave[y][x].effect = i;
+ }
+ }
+ else if (effects[i].flags & EFF_DIR4)
+ for (x = e_ptr->cx - e_ptr->rad, z = 0; x <= e_ptr->cx; x++, z++)
+ {
+ for (y = e_ptr->cy - (e_ptr->rad - z); y <= e_ptr->cy + (e_ptr->rad - z); y++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) == e_ptr->rad))
+ cave[y][x].effect = i;
+ }
+ }
+ else if (effects[i].flags & EFF_DIR9)
+ for (y = e_ptr->cy - e_ptr->rad; y <= e_ptr->cy; y++)
+ {
+ for (x = e_ptr->cx; x <= e_ptr->cx + e_ptr->rad; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) == e_ptr->rad))
+ cave[y][x].effect = i;
+ }
+ }
+ else if (effects[i].flags & EFF_DIR1)
+ for (y = e_ptr->cy; y <= e_ptr->cy + e_ptr->rad; y++)
+ {
+ for (x = e_ptr->cx - e_ptr->rad; x <= e_ptr->cx; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) == e_ptr->rad))
+ cave[y][x].effect = i;
+ }
+ }
+ else if (effects[i].flags & EFF_DIR7)
+ for (y = e_ptr->cy - e_ptr->rad; y <= e_ptr->cy; y++)
+ {
+ for (x = e_ptr->cx - e_ptr->rad; x <= e_ptr->cx; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) == e_ptr->rad))
+ cave[y][x].effect = i;
+ }
+ }
+ else if (effects[i].flags & EFF_DIR3)
+ for (y = e_ptr->cy; y <= e_ptr->cy + e_ptr->rad; y++)
+ {
+ for (x = e_ptr->cx; x <= e_ptr->cx + e_ptr->rad; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) == e_ptr->rad))
+ cave[y][x].effect = i;
+ }
+ }
+ else
+ for (y = e_ptr->cy - e_ptr->rad; y <= e_ptr->cy + e_ptr->rad; y++)
+ {
+ for (x = e_ptr->cx - e_ptr->rad; x <= e_ptr->cx + e_ptr->rad; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ /* This is *slow* -- pelpel */
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) == e_ptr->rad))
+ cave[y][x].effect = i;
+ }
+ }
+ }
+ /* Creates a "storm" effect*/
+ else if (effects[i].flags & EFF_STORM)
+ {
+ effect_type *e_ptr = &effects[i];
+ int x, y;
+
+ e_ptr->cy = p_ptr->py;
+ e_ptr->cx = p_ptr->px;
+ for (y = e_ptr->cy - e_ptr->rad; y <= e_ptr->cy + e_ptr->rad; y++)
+ {
+ for (x = e_ptr->cx - e_ptr->rad; x <= e_ptr->cx + e_ptr->rad; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (los(e_ptr->cy, e_ptr->cx, y, x) &&
+ (distance(e_ptr->cy, e_ptr->cx, y, x) <= e_ptr->rad))
+ {
+ cave[y][x].effect = i;
+ lite_spot(y, x);
+ }
+ }
+ }
+ }
+ }
+
+ apply_effect(p_ptr->py, p_ptr->px);
+ }
+
+ /* Arg cannot breath? */
+ if ((dungeon_flags2 & DF2_WATER_BREATH) && (!p_ptr->water_breath))
+ {
+ cmsg_print(TERM_L_RED, "You cannot breathe water! You suffocate!");
+ take_hit(damroll(3, p_ptr->lev), "suffocating");
+ }
+ if ((dungeon_flags2 & DF2_NO_BREATH) && (!p_ptr->magical_breath))
+ {
+ cmsg_print(TERM_L_RED, "There is no air there! You suffocate!");
+ take_hit(damroll(3, p_ptr->lev), "suffocating");
+ }
+
+ /*
+ * Every 1500 turns, warn about any Black Breath not gotten from
+ * an equipped object, and stop any resting. -LM-
+ *
+ * It's apparent that someone has halved the frequency... -- pelpel
+ */
+ if (((turn % 3000) == 0) && p_ptr->black_breath)
+ {
+ u32b f1, f2, f3, f4, f5;
+
+ bool_ be_silent = FALSE;
+
+ /* check all equipment for the Black Breath flag. */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Extract the item flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* No messages if object has the flag, to avoid annoyance. */
+ if (f4 & (TR4_BLACK_BREATH)) be_silent = TRUE;
+
+ }
+ /* If we are allowed to speak, warn and disturb. */
+
+ if (!be_silent)
+ {
+ cmsg_print(TERM_L_DARK, "The Black Breath saps your soul!");
+ disturb(0, 0);
+ }
+ }
+
+
+ /*** Process Light ***/
+
+ /* Check for light being wielded */
+ o_ptr = &p_ptr->inventory[INVEN_LITE];
+
+ /* Burn some fuel in the current lite */
+ if (o_ptr->tval == TV_LITE)
+ {
+ /* Extract the item flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hack -- Use some fuel */
+ if ((f4 & TR4_FUEL_LITE) && (o_ptr->timeout > 0))
+ {
+ /* Decrease life-span */
+ o_ptr->timeout--;
+
+ /* Hack -- notice interesting fuel steps */
+ if ((o_ptr->timeout < 100) || ((o_ptr->timeout % 100) == 0))
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP);
+ }
+
+ /* Hack -- Special treatment when blind */
+ if (p_ptr->blind)
+ {
+ /* Hack -- save some light for later */
+ if (o_ptr->timeout == 0) o_ptr->timeout++;
+ }
+
+ /* The light is now out */
+ else if (o_ptr->timeout < 1)
+ {
+ disturb(0, 0);
+ cmsg_print(TERM_YELLOW, "Your light has gone out!");
+ }
+
+ /* The light is getting dim */
+ else if ((o_ptr->timeout < 100) && (o_ptr->timeout % 10 == 0))
+ {
+ if (disturb_minor) disturb(0, 0);
+ cmsg_print(TERM_YELLOW, "Your light is growing faint.");
+ }
+ }
+ }
+
+ /* Calculate torch radius */
+ p_ptr->update |= (PU_TORCH);
+
+
+ /*** Process Inventory ***/
+
+ /*
+ * Handle experience draining. In Oangband, the effect is worse,
+ * especially for high-level characters. As per Tolkien, hobbits
+ * are resistant.
+ */
+ if (p_ptr->black_breath)
+ {
+ byte chance = 0;
+ int plev = p_ptr->lev;
+
+ if (PRACE_FLAG(PR1_RESIST_BLACK_BREATH)) chance = 2;
+ else chance = 5;
+
+ if ((rand_int(100) < chance) && (p_ptr->exp > 0))
+ {
+ p_ptr->exp -= 1 + plev / 5;
+ p_ptr->max_exp -= 1 + plev / 5;
+ (void)do_dec_stat(rand_int(6), STAT_DEC_NORMAL);
+ check_experience();
+ }
+ }
+
+ /* Drain Mana */
+ if (p_ptr->drain_mana && p_ptr->csp)
+ {
+ p_ptr->csp -= p_ptr->drain_mana;
+ if (magik(30)) p_ptr->csp -= p_ptr->drain_mana;
+
+ if (p_ptr->csp < 0)
+ {
+ p_ptr->csp = 0;
+ disturb(0, 0);
+ }
+
+ /* Redraw */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+
+ /* Partial summons drain mana */
+ if (p_ptr->maintain_sum)
+ {
+ u32b oldcsp = p_ptr->csp;
+ p_ptr->csp -= p_ptr->maintain_sum / 10000;
+
+ if (p_ptr->csp < 0)
+ {
+ p_ptr->csp = 0;
+ disturb(0, 0);
+
+ p_ptr->maintain_sum = 0;
+ }
+ else
+ {
+ /* Leave behind any fractional sp */
+ p_ptr->maintain_sum -= (oldcsp - p_ptr->csp) * 10000;
+ }
+
+ /* Redraw */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ }
+
+ /* Drain Hitpoints */
+ if (p_ptr->drain_life)
+ {
+ int drain = p_ptr->drain_life + rand_int(p_ptr->mhp / 100);
+
+ p_ptr->chp -= (drain < p_ptr->chp ? drain : p_ptr->chp);
+
+ if (p_ptr->chp == 0)
+ {
+ disturb(0, 0);
+ }
+
+ /* Redraw */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ }
+
+ /* Handle experience draining */
+ if (p_ptr->exp_drain)
+ {
+ if ((rand_int(100) < 10) && (p_ptr->exp > 0))
+ {
+ p_ptr->exp--;
+ p_ptr->max_exp--;
+ check_experience();
+ }
+ }
+
+ /* Process equipment */
+ for (j = 0, i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ /* Get the object */
+ o_ptr = &p_ptr->inventory[i];
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+
+ /* TY Curse */
+ if ((f3 & TR3_TY_CURSE) && (rand_int(TY_CURSE_CHANCE) == 0))
+ {
+ activate_ty_curse();
+ }
+
+ /* DG Curse */
+ if ((f4 & TR4_DG_CURSE) && (rand_int(DG_CURSE_CHANCE) == 0))
+ {
+ activate_dg_curse();
+
+ /* The object recurse itself ! */
+ o_ptr->ident |= IDENT_CURSED;
+ }
+
+ /* Auto Curse */
+ if ((f3 & TR3_AUTO_CURSE) && (rand_int(AUTO_CURSE_CHANCE) == 0))
+ {
+ /* The object recurse itself ! */
+ o_ptr->ident |= IDENT_CURSED;
+ }
+
+ /*
+ * Hack: Uncursed teleporting items (e.g. Dragon Weapons)
+ * can actually be useful!
+ */
+ if ((f3 & TR3_TELEPORT) && (rand_int(100) < 1))
+ {
+ if ((o_ptr->ident & IDENT_CURSED) && !p_ptr->anti_tele)
+ {
+ disturb(0, 0);
+
+ /* Teleport player */
+ teleport_player(40);
+ }
+ else
+ {
+ if (p_ptr->wild_mode ||
+ (o_ptr->note && strchr(quark_str(o_ptr->note), '.')))
+ {
+ /* Do nothing */
+ /* msg_print("Teleport aborted.") */;
+ }
+ else if (get_check("Teleport? "))
+ {
+ disturb(0, 0);
+ teleport_player(50);
+ }
+ }
+ }
+
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Hack: Skip wielded lights that need fuel (already handled above) */
+ if ((i == INVEN_LITE) && (o_ptr->tval == TV_LITE) && (f4 & TR4_FUEL_LITE)) continue;
+
+ /* Recharge activatable objects */
+ if (o_ptr->timeout > 0)
+ {
+ /* Recharge */
+ o_ptr->timeout--;
+
+ /* Notice changes */
+ if (o_ptr->timeout == 0)
+ {
+ recharged_notice(o_ptr);
+ j++;
+ }
+ }
+
+ /* Recharge second spell in Mage Staffs of Spells */
+ if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL) && (o_ptr->xtra2 > 0))
+ {
+ /* Recharge */
+ o_ptr->xtra2--;
+
+ /* Notice changes */
+ if (o_ptr->xtra2 == 0) j++;
+ }
+ }
+
+ /* Notice changes */
+ if (j)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP);
+ }
+
+ /* Recharge rods */
+ for (j = 0, i = 0; i < INVEN_TOTAL; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Examine the rod */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Temporary items are destroyed */
+ if (f5 & TR5_TEMPORARY)
+ {
+ o_ptr->timeout--;
+
+ if (o_ptr->timeout <= 0)
+ {
+ inc_stack_size(i, -99);
+
+ /* Combine and Reorder pack */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+ }
+ }
+
+ /* Examine all charging rods or stacks of charging rods. */
+ if ((o_ptr->tval == TV_ROD_MAIN) && (o_ptr->timeout < o_ptr->pval2))
+ {
+ /* Increase the rod's mana. */
+ o_ptr->timeout += (f4 & TR4_CHARGING) ? 2 : 1;
+
+ /* Always notice */
+ j++;
+
+ /* Notice changes, provide message if object is inscribed. */
+ if (o_ptr->timeout >= o_ptr->pval2)
+ {
+ o_ptr->timeout = o_ptr->pval2;
+ recharged_notice(o_ptr);
+ }
+ }
+
+ /* Examine all charging random artifacts */
+ if ((f5 & TR5_ACTIVATE_NO_WIELD) && (o_ptr->timeout > 0))
+ {
+ /* Charge it */
+ o_ptr->timeout--;
+
+ /* Notice changes */
+ if (o_ptr->timeout == 0)
+ {
+ j++;
+ recharged_notice(o_ptr);
+ }
+ }
+
+ /* Decay objects in pack */
+ if (decays(o_ptr))
+ {
+ /* Decay it */
+ if (o_ptr->pval != 0)
+ {
+ if (o_ptr->timeout > 0)
+ {
+ if (dungeon_flags1 & DF1_HOT)
+ {
+ o_ptr->pval -= 2;
+ }
+ else if ((dungeon_flags1 & DF1_COLD) && rand_int(2))
+ {
+ if (magik(50)) o_ptr->pval--;
+ }
+ else
+ {
+ o_ptr->pval--;
+ }
+ }
+
+ if ((o_ptr->timeout > 0) && o_ptr->timeout < o_ptr->weight) o_ptr->timeout--;
+
+ /* Notice changes */
+ if (o_ptr->pval <= 0)
+ {
+ pack_decay(i);
+ j++;
+ }
+ }
+ }
+
+ /* Hatch eggs */
+ if (o_ptr->tval == TV_EGG)
+ {
+ int mx, my;
+
+ if (o_ptr->timeout == 0)
+ {
+ o_ptr->pval--;
+
+ /* Notice changes */
+ if (o_ptr->pval <= 0)
+ {
+ monster_type *m_ptr;
+ monster_race *r_ptr;
+
+ mx = p_ptr->px;
+ my = p_ptr->py + 1;
+ get_pos_player(5, &my, &mx);
+ msg_print("Your egg hatches!");
+ place_monster_aux(my, mx, o_ptr->pval2, FALSE, FALSE, MSTATUS_PET);
+
+ m_ptr = &m_list[cave[my][mx].m_idx];
+ r_ptr = race_inf(m_ptr);
+
+ if ((r_ptr->flags9 & RF9_IMPRESED) && can_create_companion())
+ {
+ msg_format("And you have given the imprint to your %s!",
+ r_name + r_ptr->name);
+ m_ptr->status = MSTATUS_COMPANION;
+ }
+
+ inc_stack_size(i, -1);
+
+ j++;
+ }
+ }
+ }
+ }
+
+ /* Notice changes */
+ if (j)
+ {
+ /* Combine pack */
+ p_ptr->notice |= (PN_COMBINE);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+ }
+
+ /*** Process Objects ***/
+
+ /* Process objects */
+ for (i = 1; i < o_max; i++)
+ {
+ /* Access object */
+ o_ptr = &o_list[i];
+
+ /* Skip dead objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Examine the rod */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Temporary items are destroyed */
+ if (f5 & TR5_TEMPORARY)
+ {
+ o_ptr->timeout--;
+
+ if (o_ptr->timeout <= 0)
+ {
+ floor_item_increase(i, -99);
+ floor_item_optimize(i);
+
+ /* Combine and Reorder pack */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+ }
+ }
+
+ /* Recharge rods on the ground. No messages. */
+ if ((o_ptr->tval == TV_ROD_MAIN) && (o_ptr->timeout < o_ptr->pval2))
+ {
+ /* Increase the rod's mana. */
+ o_ptr->timeout += (f4 & TR4_CHARGING) ? 2 : 1;
+
+ /* Do not overflow */
+ if (o_ptr->timeout >= o_ptr->pval2)
+ {
+ o_ptr->timeout = o_ptr->pval2;
+ }
+ }
+
+ /* Decay objects on the ground*/
+ if (decays(o_ptr))
+ {
+ /* Decay it */
+ if (o_ptr->pval != 0)
+ {
+ if (o_ptr->timeout > 0)
+ {
+ if (dungeon_flags1 & DF1_HOT)
+ {
+ o_ptr->pval -= 2;
+ }
+ else if ((dungeon_flags1 & DF1_COLD) && rand_int(2))
+ {
+ if (magik(50)) o_ptr->pval--;
+ }
+ else
+ {
+ o_ptr->pval--;
+ }
+ }
+
+ if ((o_ptr->timeout > 0) && o_ptr->timeout < o_ptr->weight) o_ptr->timeout--;
+
+ /* Turn it into a skeleton */
+ if (o_ptr->pval <= 0)
+ {
+ floor_decay(i);
+ }
+ }
+ }
+
+ /* Hatch eggs */
+ if (o_ptr->tval == TV_EGG)
+ {
+ int mx, my;
+ if (o_ptr->timeout > 0) o_ptr->pval--;
+
+ /* Notice changes */
+ if (o_ptr->pval <= 0)
+ {
+ mx = o_ptr->ix;
+ my = o_ptr->iy;
+ get_pos_player(5, &my, &mx);
+ msg_print("An egg hatches!");
+ place_monster_one(my, mx, o_ptr->pval2, 0, FALSE, MSTATUS_ENEMY);
+ floor_item_increase(i, -1);
+ floor_item_describe(i);
+ floor_item_optimize(i);
+ }
+ }
+ }
+
+
+ /*** Involuntary Movement ***/
+
+ /* Delayed Word-of-Recall */
+ if (p_ptr->word_recall)
+ {
+ /* Can we ? */
+ if (process_hooks(HOOK_RECALL, "()", ""))
+ {
+ p_ptr->word_recall = 0;
+ }
+
+ /* No recall. sorry */
+ else if (dungeon_flags2 & DF2_NO_RECALL_OUT)
+ {
+ cmsg_print(TERM_L_DARK, "You cannot recall from here.");
+ p_ptr->word_recall = 0;
+ }
+
+ /* Cannot WoR out of death fate levels */
+ else if (dungeon_type == DUNGEON_DEATH)
+ {
+ cmsg_print(TERM_L_DARK, "You are fated to die here. FIGHT for your life!");
+ p_ptr->word_recall = 0;
+ }
+
+ /* I think the 'inside_quest' code belongs here -- pelpel */
+
+ /* They cannot use word of recall until reaching surface */
+ else if (p_ptr->astral)
+ {
+ msg_print("As an astral being you can't recall.");
+ p_ptr->word_recall = 0;
+ }
+
+ /* Normal WoR */
+ else
+ {
+ /*
+ * HACK: Autosave BEFORE resetting the recall counter (rr9)
+ * The player is yanked up/down as soon as
+ * he loads the autosaved game.
+ */
+ if (p_ptr->word_recall == 1)
+ {
+ autosave_checkpoint();
+ }
+
+ /* Make SURE that persistent levels are saved
+ * I don't know if this is needed, but I'm getting reports,
+ * so I'm adding this extra save -- Neil
+ */
+ save_dungeon();
+
+ /* Count down towards recall */
+ p_ptr->word_recall--;
+
+ /* Activate the recall */
+ if (p_ptr->word_recall == 0)
+ {
+ /* Disturbing! */
+ disturb(0, 0);
+
+ /* Determine the level */
+ if (p_ptr->inside_quest)
+ {
+ msg_print("The recall is cancelled by a powerful magic force!");
+ }
+ else if (dun_level)
+ {
+ msg_print("You feel yourself yanked upwards!");
+
+ p_ptr->recall_dungeon = dungeon_type;
+ dungeon_type = DUNGEON_WILDERNESS;
+ dun_level = 0;
+
+ is_recall = TRUE;
+
+ p_ptr->inside_quest = 0;
+ p_ptr->leaving = TRUE;
+ }
+ else
+ {
+ msg_print("You feel yourself yanked downwards!");
+
+ /* New depth */
+ dungeon_type = p_ptr->recall_dungeon;
+ dun_level = max_dlv[dungeon_type];
+ if (dun_level < 1) dun_level = 1;
+
+ /* Reset player position */
+ p_ptr->oldpx = p_ptr->px;
+ p_ptr->oldpy = p_ptr->py;
+
+ /* Leaving */
+ is_recall = TRUE;
+
+ p_ptr->leaving = TRUE;
+ p_ptr->wild_mode = FALSE;
+ }
+
+ /* Sound */
+ sound(SOUND_TPLEVEL);
+ }
+ }
+ }
+}
+
+
+/*
+ * Verify use of "wizard" mode
+ */
+static bool_ enter_wizard_mode(void)
+{
+ /* Ask first time, but not while loading a dead char with the -w option */
+ if (!noscore && !(p_ptr->chp < 0))
+ {
+ /* Mention effects */
+ msg_print("Wizard mode is for debugging and experimenting.");
+ msg_print("The game will not be scored if you enter wizard mode.");
+ msg_print(NULL);
+
+ /* Verify request */
+ if (!get_check("Are you sure you want to enter wizard mode? "))
+ {
+ return (FALSE);
+ }
+
+ /* Mark savefile */
+ noscore |= 0x0002;
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Verify use of "debug" commands
+ */
+static bool_ enter_debug_mode(void)
+{
+ /* Ask first time */
+ if (!noscore && !wizard)
+ {
+ /* Mention effects */
+ msg_print("The debug commands are for debugging and experimenting.");
+ msg_print("The game will not be scored if you use debug commands.");
+ msg_print(NULL);
+
+ /* Verify request */
+ if (!get_check("Are you sure you want to use debug commands? "))
+ {
+ return (FALSE);
+ }
+
+ /* Mark savefile */
+ noscore |= 0x0008;
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Hack -- Declare the Debug Routines
+ */
+extern void do_cmd_debug(void);
+
+
+/*
+ * Parse and execute the current command
+ * Give "Warning" on illegal commands.
+ *
+ * XXX XXX XXX Make some "blocks"
+ */
+static void process_command(void)
+{
+ char error_m[80];
+
+ /* Handle repeating the last command */
+ repeat_check();
+
+ /* Process the appropriate hooks */
+ if (process_hooks(HOOK_KEYPRESS, "(d)", command_cmd)) return;
+
+ /* Parse the command */
+ switch (command_cmd)
+ {
+ /* Ignore */
+ case ESCAPE:
+ case ' ':
+ case 0:
+ {
+ break;
+ }
+
+ /* Ignore return */
+ case '\r':
+ {
+ break;
+ }
+
+#ifdef ALLOW_QUITTING
+
+ case KTRL('L'):
+ {
+ quit("CHEATER");
+ break;
+ }
+
+#endif
+
+
+ /*** Wizard Commands ***/
+
+ /* Toggle Wizard Mode */
+ case KTRL('W'):
+ {
+ if (wizard)
+ {
+ wizard = FALSE;
+ msg_print("Wizard mode off.");
+ }
+ else if (enter_wizard_mode())
+ {
+ wizard = TRUE;
+ msg_print("Wizard mode on.");
+ }
+
+ /* Update monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw "title" */
+ p_ptr->redraw |= (PR_TITLE);
+
+ break;
+ }
+
+ /* Special "debug" commands */
+ case KTRL('A'):
+ {
+ /* Enter debug mode */
+ if (enter_debug_mode())
+ {
+ do_cmd_debug();
+ }
+ break;
+ }
+
+
+ /*** Inventory Commands ***/
+
+ /* Wear/wield equipment */
+ case 'w':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_wield();
+ break;
+ }
+
+ /* Take off equipment */
+ case 't':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_takeoff();
+ p_ptr->redraw |= (PR_MH);
+ break;
+ }
+
+ /* Drop an item */
+ case 'd':
+ {
+ if (do_control_drop()) break;
+ if (!p_ptr->wild_mode) do_cmd_drop();
+ break;
+ }
+
+ /* Destroy an item */
+ case 'k':
+ {
+ if (p_ptr->control) break;
+ do_cmd_destroy();
+ break;
+ }
+
+ /* Equipment list */
+ case 'e':
+ {
+ if (p_ptr->control) break;
+ do_cmd_equip();
+ break;
+ }
+
+ /* Inventory list */
+ case 'i':
+ {
+ if (do_control_inven()) break;
+ do_cmd_inven();
+ break;
+ }
+
+
+ /*** Various commands ***/
+
+ /* Identify an object */
+ case 'I':
+ {
+ do_cmd_observe();
+ break;
+ }
+
+ /* Hack -- toggle windows */
+ case KTRL('I'):
+ {
+ toggle_inven_equip();
+ break;
+ }
+
+
+ /*** Standard "Movement" Commands ***/
+
+ /* Alter a grid */
+ case '+':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_alter();
+ break;
+ }
+
+ /* Dig a tunnel */
+ case 'T':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_tunnel();
+ break;
+ }
+
+ /* Move (usually pick up things) */
+ case ';':
+ {
+ if (do_control_walk()) break;
+
+ do_cmd_walk(always_pickup, TRUE);
+
+ break;
+ }
+
+ /* Move (usually do not pick up) */
+ case '-':
+ {
+ if (do_control_walk()) break;
+
+ do_cmd_walk(!always_pickup, TRUE);
+
+ break;
+ }
+
+
+ /*** Running, Resting, Searching, Staying */
+
+ /* Begin Running -- Arg is Max Distance */
+ case '.':
+ {
+ if (p_ptr->control || p_ptr->wild_mode) break;
+ do_cmd_run();
+ break;
+ }
+
+ /* Stay still (usually pick things up) */
+ case ',':
+ {
+ if (do_control_pickup()) break;
+ do_cmd_stay(always_pickup);
+ break;
+ }
+
+ /* Stay still (usually do not pick up) */
+ case 'g':
+ {
+ if (p_ptr->control) break;
+ do_cmd_stay(!always_pickup);
+ break;
+ }
+
+ /* Rest -- Arg is time */
+ case 'R':
+ {
+ if (p_ptr->control) break;
+ do_cmd_rest();
+ break;
+ }
+
+ /* Search for traps/doors */
+ case 's':
+ {
+ if (p_ptr->control) break;
+ do_cmd_search();
+ break;
+ }
+
+ /* Toggle search mode */
+ case 'S':
+ {
+ if (p_ptr->control) break;
+ do_cmd_toggle_search();
+ break;
+ }
+
+
+ /*** Stairs and Doors and Chests and Traps ***/
+
+ /* Enter store */
+ case '_':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_store();
+ break;
+ }
+
+ /* Go up staircase */
+ case '<':
+ {
+ object_type *o_ptr;
+ u32b f1 = 0 , f2 = 0 , f3 = 0, f4 = 0, f5 = 0, esp = 0;
+
+
+ /* Check for light being wielded */
+ o_ptr = &p_ptr->inventory[INVEN_LITE];
+ /* Burn some fuel in the current lite */
+ if (o_ptr->tval == TV_LITE)
+ /* Extract the item flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Cannot move if rooted in place */
+ if (p_ptr->tim_roots) break;
+
+ if (p_ptr->control) break;
+ /* Normal cases */
+ if (p_ptr->wild_mode || dun_level || is_quest(dun_level))
+ {
+ do_cmd_go_up();
+ }
+ /* Don't let the player < when he'd just drop right back down */
+ else if (p_ptr->food < PY_FOOD_ALERT)
+ {
+ msg_print("You are too hungry to travel.");
+ }
+ else if (p_ptr->sensible_lite &&
+ (((turn / ((10L * DAY) / 2)) % 2) == 0))
+ {
+ /* Burn vampires! burn! */
+ msg_print("You can't travel during the day!");
+ }
+ else if (p_ptr->sensible_lite &&
+ (o_ptr->tval != 0) &&
+ (o_ptr->sval >= SV_LITE_GALADRIEL) &&
+ (o_ptr->sval <= SV_STONE_LORE) &&
+ (o_ptr->sval != SV_LITE_UNDEATH))
+ {
+ msg_print("Travel with your present light would be unsafe.");
+ }
+ else if (p_ptr->cut || p_ptr->poisoned)
+ {
+ /* I actually died this way once -- neil */
+ msg_print("You are too injured to travel.");
+ }
+ else if (ambush_flag)
+ {
+ msg_print("To flee the ambush you have to reach the edge of the map.");
+ }
+ /* TODO: make the above stuff use this hook */
+ else if (!process_hooks(HOOK_FORBID_TRAVEL, "()"))
+ {
+ p_ptr->oldpx = p_ptr->px;
+ p_ptr->oldpy = p_ptr->py;
+ change_wild_mode();
+
+ /* Update the known wilderness */
+ reveal_wilderness_around_player(p_ptr->wilderness_y,
+ p_ptr->wilderness_x,
+ 0, WILDERNESS_SEE_RADIUS);
+ }
+
+ break;
+ }
+
+ /* Go down staircase */
+ case '>':
+ {
+ /* Cannot move if rooted in place */
+ if (p_ptr->tim_roots) break;
+
+ if (p_ptr->control) break;
+ /* Normal cases */
+ if (!p_ptr->wild_mode)
+ {
+ do_cmd_go_down();
+ }
+
+ /* Special cases */
+ else
+ {
+ if ((wf_info[wild_map[p_ptr->py][p_ptr->px].feat].entrance >= 1000) ||
+ (wild_map[p_ptr->py][p_ptr->px].entrance > 1000))
+ {
+ p_ptr->wilderness_x = p_ptr->px;
+ p_ptr->wilderness_y = p_ptr->py;
+ p_ptr->wild_mode = !p_ptr->wild_mode;
+ do_cmd_go_down();
+
+ if (dun_level == 0)
+ {
+ p_ptr->wild_mode = !p_ptr->wild_mode;
+ }
+ else
+ {
+ p_ptr->wilderness_x = p_ptr->px;
+ p_ptr->wilderness_y = p_ptr->py;
+ change_wild_mode();
+ }
+ }
+ else
+ {
+ p_ptr->wilderness_x = p_ptr->px;
+ p_ptr->wilderness_y = p_ptr->py;
+ change_wild_mode();
+ }
+ }
+
+ break;
+ }
+
+ /* Open a door or chest */
+ case 'o':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_open();
+ break;
+ }
+
+ /* Close a door */
+ case 'c':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_close();
+ break;
+ }
+
+ /* Give an item */
+ case 'y':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_give();
+ break;
+ }
+
+ /* Chat */
+ case 'Y':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_chat();
+ break;
+ }
+
+ /* Jam a door with spikes */
+ case 'j':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_spike();
+ break;
+ }
+
+ /* Bash a door */
+ case 'B':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_bash();
+ break;
+ }
+
+ /* Disarm a trap or chest */
+ case 'D':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_disarm();
+ break;
+ }
+
+
+ /*** Magic and Prayers ***/
+
+ /* Interact with skills */
+ case 'G':
+ {
+ if (p_ptr->control) break;
+ do_cmd_skill();
+ break;
+ }
+
+ /* Interact with abilities */
+ case 'N':
+ {
+ if (p_ptr->control) break;
+ do_cmd_ability();
+ break;
+ }
+
+ /* Browse a book */
+ case 'b':
+ {
+ if (p_ptr->control) break;
+ do_cmd_browse();
+ break;
+ }
+
+ /* Cast a spell */
+ case 'm':
+ {
+ if (do_control_magic()) break;
+
+ /* No magic in the overworld map */
+ if (p_ptr->wild_mode) break;
+
+ /* Neither in the Arena */
+ if (p_ptr->inside_arena)
+ {
+ msg_print("The arena absorbs all attempted magic!");
+
+ break;
+ }
+ do_cmd_activate_skill();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Pray a prayer */
+ case 'p':
+ {
+ if (p_ptr->control || p_ptr->wild_mode) break;
+ do_cmd_pray();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Issue commands to pets */
+ case 'P':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_pet();
+ break;
+ }
+
+ /* Cut up a corpse */
+ case 'h':
+ {
+ if (p_ptr->control || p_ptr->wild_mode) break;
+ do_cmd_cut_corpse();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Cure some meat */
+ case 'K':
+ {
+ if (p_ptr->control) break;
+ do_cmd_cure_meat();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Steal an item form a monster */
+ case 'Z':
+ {
+ if (p_ptr->control || p_ptr->wild_mode) break;
+ do_cmd_steal();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /*** Use various objects ***/
+
+ /* Inscribe an object */
+ case '{':
+ {
+ if (p_ptr->control) break;
+ do_cmd_inscribe();
+ break;
+ }
+
+ /* Uninscribe an object */
+ case '}':
+ {
+ if (p_ptr->control) break;
+ do_cmd_uninscribe();
+ break;
+ }
+
+ /* Activate an artifact */
+ case 'A':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("The arena absorbs all attempted magic!");
+ msg_print(NULL);
+ break;
+ }
+
+ do_cmd_activate();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Eat some food */
+ case 'E':
+ {
+ if (p_ptr->control) break;
+ do_cmd_eat_food();
+ break;
+ }
+
+ /* Fuel your lantern/torch */
+ case 'F':
+ {
+ if (p_ptr->control) break;
+ do_cmd_refill();
+ break;
+ }
+
+ /* Fire an item */
+ case 'f':
+ {
+ object_type *j_ptr;
+
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("You're in the arena now. This is hand-to-hand!");
+ msg_print(NULL);
+ break;
+ }
+
+ j_ptr = &p_ptr->inventory[INVEN_BOW];
+
+ if (process_hooks(HOOK_FIRE, "(O)", j_ptr))
+ break;
+
+ if (j_ptr->tval == TV_BOOMERANG)
+ {
+ do_cmd_boomerang();
+ }
+ else
+ {
+ do_cmd_fire();
+ }
+
+ break;
+ }
+
+ /* Throw an item */
+ case 'v':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("You're in the arena now. This is hand-to-hand!");
+ msg_print(NULL);
+ break;
+ }
+
+ do_cmd_throw();
+ break;
+ }
+
+ /* Aim a wand */
+ case 'a':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("The arena absorbs all attempted magic!");
+ msg_print(NULL);
+ break;
+ }
+
+ do_cmd_aim_wand();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Zap a rod */
+ case 'z':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("The arena absorbs all attempted magic!");
+ msg_print(NULL);
+ break;
+ }
+
+ do_cmd_zap_rod();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Quaff a potion */
+ case 'q':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("The arena absorbs all attempted magic!");
+ msg_print(NULL);
+ break;
+ }
+
+ do_cmd_quaff_potion();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Drink from a fountain -SC- */
+ case 'H':
+ {
+ cave_type *c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ if (p_ptr->control) break;
+ if ((c_ptr->feat == FEAT_FOUNTAIN) ||
+ (c_ptr->feat == FEAT_EMPTY_FOUNTAIN))
+ {
+ do_cmd_drink_fountain();
+ squeltch_inventory();
+ squeltch_grid();
+ }
+ else
+ {
+ msg_print("You see no fountain here.");
+ }
+
+ break;
+ }
+
+ /* Read a scroll */
+ case 'r':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("The arena absorbs all attempted magic!");
+ msg_print(NULL);
+ break;
+ }
+
+ do_cmd_read_scroll();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Use a staff */
+ case 'u':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("The arena absorbs all attempted magic!");
+ msg_print(NULL);
+ break;
+ }
+
+ do_cmd_use_staff();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Use racial power */
+ case 'U':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (p_ptr->inside_arena)
+ {
+ msg_print("The arena absorbs all attempted magic!");
+ msg_print(NULL);
+ break;
+ }
+
+ do_cmd_power();
+ squeltch_inventory();
+ squeltch_grid();
+ break;
+ }
+
+ /* Sacrifice at an altar */
+ case 'O':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ if (PRACE_FLAG(PR1_NO_GOD))
+ {
+ msg_print("You cannot worship gods.");
+ }
+ else
+ {
+ do_cmd_sacrifice();
+ }
+
+ break;
+ }
+
+ /*** Looking at Things (nearby or on map) ***/
+
+ /* Full dungeon map */
+ case 'M':
+ {
+ if (!p_ptr->wild_mode) do_cmd_view_map();
+ break;
+ }
+
+ /* Locate player on map */
+ case 'L':
+ {
+ do_cmd_locate();
+ break;
+ }
+
+ /* Look around */
+ case 'l':
+ {
+ do_cmd_look();
+ break;
+ }
+
+ /* Target monster or location */
+ case '*':
+ {
+ if (p_ptr->control) break;
+ if (!p_ptr->wild_mode) do_cmd_target();
+ break;
+ }
+
+ /* Engrave the floor */
+ case 'x':
+ {
+ if (p_ptr->control) break;
+ if (p_ptr->wild_mode) break;
+
+ /* No point in engraving if there isn't any mana on this grid. */
+ /* DG - actualy there is, it doesnt break macros */
+ do_cmd_sense_grid_mana();
+ do_cmd_engrave();
+
+ break;
+ }
+
+ /*** Help and Such ***/
+
+ /* Help */
+ case '?':
+ {
+ do_cmd_help();
+ break;
+ }
+
+ /* Identify symbol */
+ case '/':
+ {
+ do_cmd_query_symbol();
+ break;
+ }
+
+ /* Character description */
+ case 'C':
+ {
+ do_cmd_change_name();
+ break;
+ }
+
+
+ /*** System Commands ***/
+
+ /* Hack -- User interface */
+ case '!':
+ {
+ (void)Term_user(0);
+ break;
+ }
+
+ /* Single line from a pref file */
+ case '"':
+ {
+ do_cmd_pref();
+ break;
+ }
+
+ /* Interact with macros */
+ case '@':
+ {
+ do_cmd_macros();
+ break;
+ }
+
+ /* Interact with visuals */
+ case '%':
+ {
+ do_cmd_visuals();
+ break;
+ }
+
+ /* Interact with colors */
+ case '&':
+ {
+ do_cmd_colors();
+ break;
+ }
+
+ /* Interact with options */
+ case '=':
+ {
+ do_cmd_options();
+ break;
+ }
+
+
+ /*** Misc Commands ***/
+
+ /* Take notes */
+ case ':':
+ {
+ do_cmd_note();
+ break;
+ }
+
+ /* Version info */
+ case 'V':
+ {
+ do_cmd_version();
+ break;
+ }
+
+ /* Repeat level feeling */
+ case KTRL('F'):
+ {
+ if (!p_ptr->wild_mode)
+ do_cmd_feeling();
+ break;
+ }
+
+ /* Show previous message */
+ case KTRL('O'):
+ {
+ do_cmd_message_one();
+ break;
+ }
+
+ /* Show previous messages */
+ case KTRL('P'):
+ {
+ do_cmd_messages();
+ break;
+ }
+
+ /* Show quest status -KMW- */
+ case KTRL('Q'):
+ case CMD_QUEST:
+{
+ do_cmd_checkquest();
+ break;
+ }
+
+ /* Redraw the screen */
+ case KTRL('R'):
+ {
+ do_cmd_redraw();
+ break;
+ }
+
+ /* Hack -- Save and don't quit */
+ case KTRL('S'):
+ {
+ is_autosave = FALSE;
+ do_cmd_save_game();
+ break;
+ }
+
+ case KTRL('T'):
+ {
+ do_cmd_time();
+ }
+ break;
+
+ /* Save and quit */
+ case KTRL('X'):
+ {
+ alive = FALSE;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+
+ break;
+ }
+
+ /* Quit (commit suicide) */
+ case 'Q':
+ {
+ do_cmd_suicide();
+ break;
+ }
+
+ /* Activate cmovie */
+ case '|':
+ {
+ /* Stop ? */
+ if (do_movies == 1)
+ {
+ do_stop_cmovie();
+ msg_print("Cmovie recording stopped.");
+ }
+ else
+ {
+ do_start_cmovie();
+ }
+ break;
+ }
+
+ /* Extended command */
+ case '#':
+ {
+ do_cmd_cli();
+ break;
+ }
+
+ /* Check artifacts, uniques, objects */
+ case '~':
+ {
+ do_cmd_knowledge();
+ break;
+ }
+
+ /* Commands only available as extended commands: */
+
+ /* Extended command help. */
+ case CMD_CLI_HELP:
+ {
+ do_cmd_cli_help();
+ break;
+ }
+
+ /* Game time. */
+ case CMD_SHOW_TIME:
+ {
+ do_cmd_time();
+ break;
+ }
+
+ /* Check skills. */
+ case CMD_SHOW_SKILL:
+ {
+ do_cmd_skill();
+ break;
+ }
+
+ /* Check abilities. */
+ case CMD_SHOW_ABILITY:
+ {
+ do_cmd_ability();
+ break;
+ }
+
+ /* Save a html screenshot. */
+ case CMD_DUMP_HTML:
+ {
+ do_cmd_html_dump();
+ break;
+ }
+
+ /* Record a macro. */
+ case '$':
+ case CMD_MACRO:
+ {
+ do_cmd_macro_recorder();
+ break;
+ }
+ case CMD_BLUNDER:
+ {
+ if (do_control_walk()) break;
+ do_cmd_walk(always_pickup, FALSE);
+ break;
+ }
+ /* Hack -- Unknown command */
+ default:
+ {
+ int insanity = (p_ptr->msane - p_ptr->csane) * 100 / p_ptr->msane;
+
+ /* Would like to have an option disabling this -- pelpel */
+ if (rand_int(100) < insanity)
+ {
+ get_rnd_line("error.txt", error_m);
+ sound(SOUND_ILLEGAL);
+ msg_print(error_m);
+ }
+ else
+ {
+ prt("Type '?' for help.", 0, 0);
+ }
+
+ break;
+ }
+ }
+}
+
+
+
+
+/*
+ * Process the player
+ *
+ * Notice the annoying code to handle "pack overflow", which
+ * must come first just in case somebody manages to corrupt
+ * the savefiles by clever use of menu commands or something.
+ */
+void process_player(void)
+{
+ int i, j;
+
+ int speed_use;
+
+
+ /*** Apply energy ***/
+
+ if (hack_corruption)
+ {
+ msg_print("You feel different!");
+ (void)gain_random_corruption(0);
+ hack_corruption = FALSE;
+ }
+
+ /* Obtain current speed */
+ speed_use = p_ptr->pspeed;
+
+ /* Maximum value */
+ if (speed_use > 199)
+ {
+ speed_use = 199;
+ }
+
+ /* Minimum value */
+ else if (speed_use < 0)
+ {
+ speed_use = 0;
+ }
+
+ /* Give the player some energy */
+ p_ptr->energy += extract_energy[speed_use];
+
+ /* No turn yet */
+ if (p_ptr->energy < 100) return;
+
+
+ /*** Check for interupts ***/
+
+ /* Complete resting */
+ if (resting < 0)
+ {
+ /* Basic resting */
+ if (resting == -1)
+ {
+ /* Stop resting */
+ if ((p_ptr->chp == p_ptr->mhp) && (p_ptr->csp >= p_ptr->msp))
+ {
+ disturb(0, 0);
+ }
+ }
+
+ /* Complete resting */
+ else if (resting == -2)
+ {
+ bool_ stop = TRUE;
+ object_type *o_ptr;
+
+ /* Get the carried monster */
+ o_ptr = &p_ptr->inventory[INVEN_CARRY];
+
+ /* Stop resting */
+ if ((!p_ptr->drain_life) && (p_ptr->chp != p_ptr->mhp)) stop = FALSE;
+ if ((!p_ptr->drain_mana) && (p_ptr->csp != p_ptr->msp)) stop = FALSE;
+ if (o_ptr->pval2 < o_ptr->pval3) stop = FALSE;
+ if (p_ptr->blind || p_ptr->confused) stop = FALSE;
+ if (p_ptr->poisoned || p_ptr->afraid) stop = FALSE;
+ if (p_ptr->stun || p_ptr->cut) stop = FALSE;
+ if (p_ptr->slow || p_ptr->paralyzed) stop = FALSE;
+ if (p_ptr->image || p_ptr->word_recall) stop = FALSE;
+ if (p_ptr->immov_cntr != 0) stop = FALSE;
+
+ for (i = 0; i < 6; i++)
+ {
+ if (p_ptr->stat_cnt[i] > 0) stop = FALSE;
+ }
+
+ if (stop)
+ {
+ disturb(0, 0);
+ }
+ p_ptr->redraw |= (PR_STATE);
+ }
+ }
+
+ /* Handle "abort" */
+ if (!avoid_abort)
+ {
+ /* Check for "player abort" (semi-efficiently for resting) */
+ if (running || command_rep || (resting && !(resting & 0x0F)))
+ {
+ /* Do not wait */
+ inkey_scan = TRUE;
+
+ /* Check for a key */
+ if (inkey())
+ {
+ /* Flush input */
+ flush();
+
+ /* Disturb */
+ disturb(0, 0);
+
+ /* Hack -- Show a Message */
+ msg_print("Cancelled.");
+ }
+ }
+ }
+
+
+ /*** Handle actual user input ***/
+
+ /* Repeat until out of energy */
+ while (p_ptr->energy >= 100)
+ {
+ /* Notice stuff (if needed) */
+ if (p_ptr->notice) notice_stuff();
+
+ /* Update stuff (if needed) */
+ if (p_ptr->update) update_stuff();
+
+ /* Redraw stuff (if needed) */
+ if (p_ptr->redraw) redraw_stuff();
+
+ /* Redraw stuff (if needed) */
+ if (p_ptr->window) window_stuff();
+
+ /* Hack -- mark current wilderness location as known */
+ if (!p_ptr->wild_mode && dun_level == 0)
+ wild_map[p_ptr->wilderness_y][p_ptr->wilderness_x].known = TRUE;
+
+
+ /* Place the cursor on the player */
+ move_cursor_relative(p_ptr->py, p_ptr->px);
+
+ /* Refresh (optional) */
+ if (fresh_before) Term_fresh();
+
+ /* Hack -- Pack Overflow */
+ if (p_ptr->inventory[INVEN_PACK].k_idx)
+ {
+ int item = INVEN_PACK;
+
+ char o_name[80];
+
+ object_type *o_ptr;
+
+ /* Access the slot to be dropped */
+ o_ptr = &p_ptr->inventory[item];
+
+ /* Disturbing */
+ disturb(0, 0);
+
+ /* Warning */
+ msg_print("Your pack overflows!");
+
+ /* Describe */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("You drop %s (%c).", o_name, index_to_label(item));
+
+ /* Drop it (carefully) near the player */
+ drop_near(o_ptr, 0, p_ptr->py, p_ptr->px);
+
+ /* Modify, Describe, Optimize */
+ inc_stack_size(item, -255);
+
+ /* Notice stuff (if needed) */
+ if (p_ptr->notice) notice_stuff();
+
+ /* Update stuff (if needed) */
+ if (p_ptr->update) update_stuff();
+
+ /* Redraw stuff (if needed) */
+ if (p_ptr->redraw) redraw_stuff();
+
+ /* Redraw stuff (if needed) */
+ if (p_ptr->window) window_stuff();
+ }
+
+
+ /* Assume free turn */
+ energy_use = 0;
+
+
+ /* Paralyzed or Knocked Out */
+ if ((p_ptr->paralyzed) || (p_ptr->stun >= 100))
+ {
+ /* Take a turn */
+ energy_use = 100;
+ }
+
+ /* Resting */
+ else if (resting)
+ {
+ /* Timed rest */
+ if (resting > 0)
+ {
+ /* Reduce rest count */
+ resting--;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+ }
+
+ p_ptr->did_nothing = TRUE;
+
+ /* Take a turn */
+ energy_use = 100;
+ }
+
+ /* Running */
+ else if (running)
+ {
+ /* Take a step */
+ run_step(0);
+
+ /*
+ * Commented out because it doesn't make any sense
+ * to require a player holding down direction keys
+ * instead of using running commands when s/he follows
+ * Eru and do the opposite for the other deities -- pelpel
+ */
+ /* p_ptr->did_nothing = TRUE; */
+ }
+
+ /* Repeated command */
+ else if (command_rep)
+ {
+ /* Count this execution */
+ command_rep--;
+
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Redraw stuff */
+ redraw_stuff();
+
+ /* Hack -- Assume messages were seen */
+ msg_flag = FALSE;
+
+ /* Clear the top line */
+ prt("", 0, 0);
+
+ /* Process the command */
+ process_command();
+
+ p_ptr->did_nothing = TRUE;
+ }
+
+ /* Normal command */
+ else
+ {
+ /* Place the cursor on the player */
+ move_cursor_relative(p_ptr->py, p_ptr->px);
+
+ /* Get a command (normal) */
+ request_command(FALSE);
+
+ /* Process the command */
+ process_command();
+ }
+
+
+ /*** Clean up ***/
+
+ /* Significant */
+ if (energy_use)
+ {
+ /* Use some energy */
+ p_ptr->energy -= energy_use;
+
+
+ /* Hack -- constant hallucination */
+ if (p_ptr->image) p_ptr->redraw |= (PR_MAP);
+
+
+ /* Shimmer monsters if needed */
+ if (!avoid_other && !use_graphics && shimmer_monsters)
+ {
+ /* Clear the flag */
+ shimmer_monsters = FALSE;
+
+ /* Shimmer multi-hued monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr;
+ monster_race *r_ptr;
+
+ /* Access monster */
+ m_ptr = &m_list[i];
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Access the monster race */
+ r_ptr = race_inf(m_ptr);
+
+ /* Skip non-multi-hued monsters */
+ if (!(r_ptr->flags1 & (RF1_ATTR_MULTI))) continue;
+
+ /* Reset the flag */
+ shimmer_monsters = TRUE;
+
+ /* Redraw regardless */
+ lite_spot(m_ptr->fy, m_ptr->fx);
+ }
+ }
+
+ /* Shimmer objects if needed and requested */
+ if (!avoid_other && !avoid_shimmer && !use_graphics &&
+ shimmer_objects)
+ {
+ /* Clear the flag */
+ shimmer_objects = FALSE;
+
+ /* Shimmer multi-hued objects */
+ for (i = 1; i < o_max; i++)
+ {
+ /* Acquire object -- for speed only base items are allowed to shimmer */
+ object_type *o_ptr = &o_list[i];
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Skip dead or carried objects */
+ if ((!o_ptr->k_idx) || (!o_ptr->ix)) continue;
+
+ /* Skip non-multi-hued monsters */
+ if (!(k_ptr->flags5 & (TR5_ATTR_MULTI))) continue;
+
+ /* Reset the flag */
+ shimmer_objects = TRUE;
+
+ /* Redraw regardless */
+ lite_spot(o_ptr->iy, o_ptr->ix);
+ }
+ }
+
+ /*
+ * Shimmer features if needed and requested
+ *
+ * Note: this can be unbearably slow when a player chooses
+ * to use a REALLY big screen in levels filled with shallow
+ * water. I believe this also hurts a lot on multiuser systems.
+ * However fast modern processors are, I/O cannot be made that
+ * fast, and that's why shimmering has been limited to small
+ * number of monsters -- pelpel
+ */
+ if (!avoid_other && !avoid_shimmer && !use_graphics &&
+ !resting && !running)
+ {
+ for (j = panel_row_min; j <= panel_row_max; j++)
+ {
+ for (i = panel_col_min; i <= panel_col_max; i++)
+ {
+ cave_type *c_ptr = &cave[j][i];
+ feature_type *f_ptr;
+
+ /* Apply terrain feature mimics */
+ if (c_ptr->mimic)
+ {
+ f_ptr = &f_info[c_ptr->mimic];
+ }
+ else
+ {
+ f_ptr = &f_info[f_info[c_ptr->feat].mimic];
+ }
+
+ /* Skip normal features */
+ if (!(f_ptr->flags1 & (FF1_ATTR_MULTI))) continue;
+
+ /* Redraw a shimmering spot */
+ lite_spot(j, i);
+ }
+ }
+ }
+
+
+ /* Handle monster detection */
+ if (repair_monsters)
+ {
+ /* Reset the flag */
+ repair_monsters = FALSE;
+
+ /* Rotate detection flags */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr;
+
+ /* Access monster */
+ m_ptr = &m_list[i];
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Nice monsters get mean */
+ if (m_ptr->mflag & (MFLAG_NICE))
+ {
+ /* Nice monsters get mean */
+ m_ptr->mflag &= ~(MFLAG_NICE);
+ }
+
+ /* Handle memorized monsters */
+ if (m_ptr->mflag & (MFLAG_MARK))
+ {
+ /* Maintain detection */
+ if (m_ptr->mflag & (MFLAG_SHOW))
+ {
+ /* Forget flag */
+ m_ptr->mflag &= ~(MFLAG_SHOW);
+
+ /* Still need repairs */
+ repair_monsters = TRUE;
+ }
+
+ /* Remove detection */
+ else
+ {
+ /* Forget flag */
+ m_ptr->mflag &= ~(MFLAG_MARK);
+
+ /* Assume invisible */
+ m_ptr->ml = FALSE;
+
+ /* Update the monster */
+ update_mon(i, FALSE);
+
+ /* Redraw regardless */
+ lite_spot(m_ptr->fy, m_ptr->fx);
+ }
+ }
+ }
+ }
+
+ /*
+ * Moved from dungeon() -- It'll get called whenever player
+ * spends energy, so that maze isn't incredibly easy for
+ * Sorcerors and alike any longer -- pelpel
+ *
+ * Forget everything when requested hehe I'm *NASTY*
+ */
+ if (dun_level && (dungeon_flags1 & DF1_FORGET))
+ {
+ wiz_dark();
+ }
+ }
+
+
+ /* Hack -- notice death */
+ if (!alive || death) break;
+
+ /* Handle "leaving" */
+ if (p_ptr->leaving) break;
+ }
+}
+
+
+
+/*
+ * Interact with the current dungeon level.
+ *
+ * This function will not exit until the level is completed,
+ * the user dies, or the game is terminated.
+ */
+static void dungeon(void)
+{
+ /* Reset various flags */
+ hack_mind = FALSE;
+
+ /* Not leaving */
+ p_ptr->leaving = FALSE;
+
+ /* Reset the "command" vars */
+ command_cmd = 0;
+ command_new = 0;
+ command_rep = 0;
+ command_arg = 0;
+ command_dir = 0;
+
+ /* Make sure partial summoning counter is initialized. */
+ p_ptr->maintain_sum = 0;
+
+ /* Cancel the target */
+ target_who = 0;
+
+ /* Cancel the health bar */
+ health_track(0);
+
+
+ /* Check visual effects */
+ shimmer_monsters = TRUE;
+ shimmer_objects = TRUE;
+ repair_monsters = TRUE;
+ repair_objects = TRUE;
+
+
+ /* Disturb */
+ disturb(1, 0);
+
+ /* Track maximum player level */
+ if (p_ptr->max_plv < p_ptr->lev)
+ {
+ p_ptr->max_plv = p_ptr->lev;
+ }
+
+ /* Track maximum dungeon level (if not in quest -KMW-) */
+ if ((max_dlv[dungeon_type] < dun_level) && !p_ptr->inside_quest)
+ {
+ max_dlv[dungeon_type] = dun_level;
+ }
+
+ /* No stairs down from Quest */
+ if (is_quest(dun_level) && !p_ptr->astral)
+ {
+ create_down_stair = FALSE;
+ create_down_shaft = FALSE;
+ }
+
+ /* Paranoia -- no stairs from town or wilderness */
+ if (!dun_level) create_down_stair = create_up_stair = FALSE;
+ if (!dun_level) create_down_shaft = create_up_shaft = FALSE;
+
+ /* Option -- no connected stairs */
+ if (!dungeon_stair) create_down_stair = create_up_stair = FALSE;
+ if (!dungeon_stair) create_down_shaft = create_up_shaft = FALSE;
+
+ /* no connecting stairs on special levels */
+ if (!(dungeon_flags2 & DF2_NO_STAIR)) create_down_stair = create_up_stair = FALSE;
+ if (!(dungeon_flags2 & DF2_NO_STAIR)) create_down_shaft = create_up_shaft = FALSE;
+
+ /* Make a stairway. */
+ if ((create_up_stair || create_down_stair ||
+ create_up_shaft || create_down_shaft) &&
+ !get_fbranch())
+ {
+ /* Place a stairway */
+ if (cave_valid_bold(p_ptr->py, p_ptr->px))
+ {
+ /* XXX XXX XXX */
+ delete_object(p_ptr->py, p_ptr->px);
+
+ /* Make stairs */
+ if (create_down_stair)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, (dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_MORE : FEAT_MORE);
+ }
+ else if (create_down_shaft)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, (dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_MORE : FEAT_SHAFT_DOWN);
+ }
+ else if (create_up_shaft)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, (dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_LESS : FEAT_SHAFT_UP);
+ }
+ else
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, (dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_LESS : FEAT_LESS);
+ }
+ }
+
+ /* Cancel the stair request */
+ create_down_stair = create_up_stair = FALSE;
+ create_down_shaft = create_up_shaft = FALSE;
+ }
+
+ /* Hack - Assume invalid panel */
+ panel_row_min = cur_hgt;
+ panel_row_max = 0;
+ panel_col_min = cur_wid;
+ panel_col_max = 0;
+
+ /* Center the panel */
+ verify_panel();
+
+ /* Flush messages */
+ msg_print(NULL);
+
+
+ /* Enter "xtra" mode */
+ character_xtra = TRUE;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+
+ /* Redraw dungeon */
+ p_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Update stuff */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_POWERS | PU_SANITY | PU_BODY);
+
+ /* Calculate torch radius */
+ p_ptr->update |= (PU_TORCH);
+
+ /* Update stuff */
+ update_stuff();
+
+ /* Redraw stuff */
+ redraw_stuff();
+
+ /* Redraw stuff */
+ window_stuff();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_DISTANCE | PU_MON_LITE);
+
+ /* Update stuff */
+ update_stuff();
+
+ /* Redraw stuff */
+ redraw_stuff();
+
+ /* Leave "xtra" mode */
+ character_xtra = FALSE;
+
+ /* Update stuff */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_POWERS | PU_BODY);
+
+ /* Combine / Reorder the pack */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Notice stuff */
+ notice_stuff();
+
+ /* Update stuff */
+ update_stuff();
+
+ /* Redraw stuff */
+ redraw_stuff();
+
+ /* Window stuff */
+ window_stuff();
+
+ /* Refresh */
+ Term_fresh();
+
+
+ /* Announce (or repeat) the feeling */
+ if (dun_level) do_cmd_feeling();
+
+
+ /* Hack -- notice death or departure */
+ if (!alive || death) return;
+
+ /*** Process this dungeon level ***/
+
+ /* Reset the monster generation level */
+ monster_level = dun_level;
+
+ /* Reset the object generation level */
+ object_level = dun_level;
+
+ hack_mind = TRUE;
+
+ /* Mega Hack, if needed wipe all stairs */
+ if (dungeon_type == DUNGEON_DEATH)
+ {
+ int i, j;
+
+ for (i = 0; i < cur_wid; i++)
+ {
+ for (j = 0; j < cur_hgt; j++)
+ {
+ cave_type *c_ptr = &cave[j][i];
+
+ switch (c_ptr->feat)
+ {
+ case FEAT_MORE:
+ case FEAT_LESS:
+ case FEAT_SHAFT_UP:
+ case FEAT_SHAFT_DOWN:
+ {
+ cave_set_feat(j, i, FEAT_FLOOR);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Reset the monster generation level */
+ monster_level = 127;
+
+ /* Reset the object generation level */
+ object_level = 0;
+ }
+
+ /* Main loop */
+ while (TRUE)
+ {
+ /* Hack -- Compact the monster list occasionally */
+ if (m_cnt + 32 > max_m_idx) compact_monsters(64);
+
+ /* Hack -- Compress the monster list occasionally */
+ if (m_cnt + 32 < m_max) compact_monsters(0);
+
+
+ /* Hack -- Compact the object list occasionally */
+ if (o_cnt + 32 > max_o_idx) compact_objects(64);
+
+ /* Hack -- Compress the object list occasionally */
+ if (o_cnt + 32 < o_max) compact_objects(0);
+
+
+
+ /* Process the player */
+ process_player();
+
+ /* Notice stuff */
+ if (p_ptr->notice) notice_stuff();
+
+ /* Update stuff */
+ if (p_ptr->update) update_stuff();
+
+ /* Redraw stuff */
+ if (p_ptr->redraw) redraw_stuff();
+
+ /* Redraw stuff */
+ if (p_ptr->window) window_stuff();
+
+ /* Hack -- Hilite the player */
+ move_cursor_relative(p_ptr->py, p_ptr->px);
+
+ /* Optional fresh */
+ if (fresh_after) Term_fresh();
+
+ /* Hack -- Notice death or departure */
+ if (!alive || death) break;
+
+
+ total_friends = 0;
+ total_friend_levels = 0;
+
+ /* Process all of the monsters */
+ process_monsters();
+
+ /* Notice stuff */
+ if (p_ptr->notice) notice_stuff();
+
+ /* Update stuff */
+ if (p_ptr->update) update_stuff();
+
+ /* Redraw stuff */
+ if (p_ptr->redraw) redraw_stuff();
+
+ /* Redraw stuff */
+ if (p_ptr->window) window_stuff();
+
+ /* Hack -- Hilite the player */
+ move_cursor_relative(p_ptr->py, p_ptr->px);
+
+ /* Optional fresh */
+ if (fresh_after) Term_fresh();
+
+ /* Hack -- Notice death or departure */
+ if (!alive || death) break;
+
+
+ /* Process the world */
+ process_world();
+
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_END_TURN, "(d)", is_quest(dun_level));
+
+ /* Make it pulsate and live !!!! */
+ if ((dungeon_flags1 & DF1_EVOLVE) && dun_level)
+ {
+ if (!(turn % 10)) evolve_level(TRUE);
+ }
+
+ /* Notice stuff */
+ if (p_ptr->notice) notice_stuff();
+
+ /* Update stuff */
+ if (p_ptr->update) update_stuff();
+
+ /* Redraw stuff */
+ if (p_ptr->redraw) redraw_stuff();
+
+ /* Window stuff */
+ if (p_ptr->window) window_stuff();
+
+ /* Hack -- Hilite the player */
+ move_cursor_relative(p_ptr->py, p_ptr->px);
+
+ /* Optional fresh */
+ if (fresh_after) Term_fresh();
+
+ /* Hack -- Notice death or departure */
+ if (!alive || death) break;
+
+ /* Handle "leaving" */
+ if (p_ptr->leaving) break;
+
+ /* Count game turns */
+ turn++;
+ }
+
+ /* Did we leave a dungeon ? */
+ if ((dun_level < d_info[dungeon_type].mindepth) && !is_recall)
+ {
+ dun_level = 0;
+
+ if (d_info[dungeon_type].ix > -1)
+ {
+ p_ptr->wilderness_x = d_info[dungeon_type].ix;
+ p_ptr->wilderness_y = d_info[dungeon_type].iy;
+ }
+
+ dungeon_type = DUNGEON_WILDERNESS;
+ }
+
+ if (dun_level > d_info[dungeon_type].maxdepth)
+ {
+ dun_level = 0;
+
+ if (d_info[dungeon_type].ox > -1)
+ {
+ p_ptr->wilderness_x = d_info[dungeon_type].ox;
+ p_ptr->wilderness_y = d_info[dungeon_type].oy;
+ }
+
+ dungeon_type = DUNGEON_WILDERNESS;
+ }
+
+ is_recall = FALSE;
+}
+
+
+
+
+/*
+ * Load some "user pref files"
+ */
+static void load_all_pref_files(void)
+{
+ char buf[1024];
+
+
+ /* Access the "race" pref file */
+ sprintf(buf, "%s.prf", rp_ptr->title + rp_name);
+
+ /* Process that file */
+ process_pref_file(buf);
+
+ /* Access the "class" pref file */
+ sprintf(buf, "%s.prf", spp_ptr->title + c_name);
+
+ /* Process that file */
+ process_pref_file(buf);
+
+ /* Access the "character" pref file */
+ sprintf(buf, "%s.prf", player_name);
+
+ /* Process that file */
+ process_pref_file(buf);
+
+ /* Process player specific automatizer sets */
+ tome_dofile_anywhere(ANGBAND_DIR_USER, format("%s.atm", player_name), FALSE);
+}
+
+/*
+ * Actually play a game
+ *
+ * If the "new_game" parameter is true, then, after loading the
+ * savefile, we will commit suicide, if necessary, to allow the
+ * player to start a new game.
+ */
+void play_game(bool_ new_game)
+{
+ int i, tmp_dun;
+
+ bool_ cheat_death = FALSE;
+
+ hack_corruption = FALSE;
+
+ /* Hack -- Character is "icky" */
+ character_icky = TRUE;
+
+
+ /* Make sure main term is active */
+ Term_activate(angband_term[0]);
+
+ /* Initialise the resize hook XXX XXX XXX */
+ angband_term[0]->resize_hook = resize_map;
+
+ /* XXX XXX XXX hardcoded number of terms */
+ for (i = 1; i < 8; i++)
+ {
+ if (angband_term[i])
+ {
+ /* Add redraw hook */
+ angband_term[i]->resize_hook = resize_window;
+ }
+ }
+
+
+ /* Hack -- turn off the cursor */
+ (void)Term_set_cursor(0);
+
+ /* Character list */
+ if (!new_game && !no_begin_screen) new_game = begin_screen();
+ no_begin_screen = FALSE;
+
+ /* Attempt to load */
+ if (!load_player())
+ {
+ /* Oops */
+ quit("broken savefile");
+ }
+
+ /* Nothing loaded */
+ if (!character_loaded)
+ {
+ /* Make new player */
+ new_game = TRUE;
+
+ /* The dungeon is not ready */
+ character_dungeon = FALSE;
+ }
+ else
+ {
+ int i;
+
+ /* Init new skills to their defaults */
+ for (i = old_max_s_idx; i < max_s_idx; i++)
+ {
+ s32b value = 0, mod = 0;
+
+ compute_skills(&value, &mod, i);
+
+ init_skill(value, mod, i);
+ }
+ }
+
+#if 1
+
+ /* Process old character */
+ if (!new_game)
+ {
+ /* Process the player name */
+ process_player_name(FALSE);
+ }
+
+#endif
+
+ /* Init the RNG */
+ if (Rand_quick)
+ {
+ u32b seed;
+
+ /* Basic seed */
+ seed = (time(NULL));
+
+#ifdef SET_UID
+
+ /* Mutate the seed on Unix machines */
+ seed = ((seed >> 3) * (getpid() << 1));
+
+#endif
+
+ /* Use the complex RNG */
+ Rand_quick = FALSE;
+
+ /* Seed the "complex" RNG */
+ Rand_state_init(seed);
+ }
+
+ /* Extract the options */
+ for (i = 0; option_info[i].o_desc; i++)
+ {
+ int os = option_info[i].o_page;
+ int ob = option_info[i].o_bit;
+
+ /* Set the "default" options */
+ if (option_info[i].o_var)
+ {
+ /* Set */
+ if (option_flag[os] & (1L << ob))
+ {
+ /* Set */
+ (*option_info[i].o_var) = TRUE;
+ }
+
+ /* Clear */
+ else
+ {
+ /* Clear */
+ (*option_info[i].o_var) = FALSE;
+ }
+ }
+ }
+
+ /* Roll new character */
+ if (new_game)
+ {
+ s32b ret;
+
+ /* Are we authorized to create new chars? */
+ call_lua("get_module_info", "(s)", "d", "allow_birth", &ret);
+
+ if (!ret)
+ {
+ msg_box("Sorry, this module does not allow character creation.", -1, -1);
+
+ /* Close stuff */
+ close_game();
+
+ /* Quit */
+ quit(NULL);
+ }
+
+ process_hooks(HOOK_INIT, "()");
+
+ /* The dungeon is not ready */
+ character_dungeon = FALSE;
+
+ /* Hack -- seed for flavors */
+ seed_flavor = rand_int(0x10000000);
+
+ /* Roll up a new character */
+ player_birth();
+
+ /* Start in town, or not */
+ if (p_ptr->astral) dun_level = 98;
+ else dun_level = 0;
+ p_ptr->inside_quest = 0;
+ p_ptr->inside_arena = 0;
+
+ /* Hack -- enter the world */
+ /* Mega-hack Vampires and Spectres start in the dungeon */
+ if (PRACE_FLAG(PR1_UNDEAD))
+ {
+ turn = (10L * DAY / 2) + (START_DAY * 10) + 1;
+ }
+ else
+ {
+ turn = (START_DAY * 10) + 1;
+ }
+ }
+
+ /* Flash a message */
+ prt("Please wait...", 0, 0);
+
+ /* Flush the message */
+ Term_fresh();
+
+ /* Be sure to not bother the player */
+ calc_powers_silent = TRUE;
+
+ /* Hack -- Enter wizard mode */
+ if (arg_wizard && enter_wizard_mode()) wizard = TRUE;
+
+ /* Flavor the objects */
+ flavor_init();
+
+ /* Reset the visual mappings */
+ reset_visuals();
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+
+ /* Window stuff */
+ window_stuff();
+
+ /* load user file */
+ process_pref_file("user.prf");
+
+ /* Load the "pref" files */
+ load_all_pref_files();
+
+ /* Set or clear "rogue_like_commands" if requested */
+ if (arg_force_original) rogue_like_commands = FALSE;
+ if (arg_force_roguelike) rogue_like_commands = TRUE;
+
+ /* Initialize vault info */
+ if (init_v_info()) quit("Cannot initialize vaults");
+
+ /* Initialize hooks */
+ init_hooks();
+ ingame_help(p_ptr->help.enabled);
+
+ /* React to changes */
+ Term_xtra(TERM_XTRA_REACT, 0);
+
+ /* Mega hack, prevent lots of bugs */
+ if ((p_ptr->px == 0) || (p_ptr->py == 0))
+ {
+ p_ptr->px = 1;
+ p_ptr->py = 1;
+ };
+
+ /* Hack - if note file exists, load it */
+ if (!new_game && take_notes)
+ {
+ add_note_type(NOTE_ENTER_DUNGEON);
+ }
+
+ /* Generate a dungeon level if needed */
+ if (!character_dungeon) generate_cave();
+
+ /* Ok tell the scripts that the game is about to start */
+ process_hooks(HOOK_GAME_START, "()");
+
+ /* Character is now "complete" */
+ character_generated = TRUE;
+
+
+ /* Hack -- Character is no longer "icky" */
+ character_icky = FALSE;
+
+
+ /* Start game */
+ alive = TRUE;
+
+ /* Hack -- Enforce "delayed death" */
+ if (p_ptr->chp < 0) death = TRUE;
+
+ /* Should we use old colors */
+ if (autoload_old_colors)
+ {
+ process_pref_file("422color.prf");
+ }
+
+
+ /* Process */
+ while (TRUE)
+ {
+ /* Save the level */
+ old_dun_level = dun_level;
+ p_ptr->old_wild_mode = p_ptr->wild_mode;
+
+ /* We reached surface ? good, lets go down again !! */
+ if (p_ptr->astral && !dun_level)
+ {
+ p_ptr->astral = FALSE;
+ cmsg_print(TERM_L_GREEN,
+ "Well done ! You reached the town ! "
+ "You can now go down again.");
+ }
+
+ /* Update monster list window */
+ p_ptr->window |= (PW_M_LIST);
+
+ /* Process the level */
+ dungeon();
+
+ /* Save the current level if in a persistent level */
+ tmp_dun = dun_level;
+ dun_level = old_dun_level;
+ save_dungeon();
+ dun_level = tmp_dun;
+
+ /* A death fate affects level generation */
+ for (i = 0; i < MAX_FATES; i++)
+ {
+ /* Ignore empty slots */
+ if (!fates[i].fate) continue;
+
+ /* Ignore non-applicable fates */
+ if (fates[i].level != dun_level) continue;
+
+ /* Non-serious fate fails to fire 50% of time */
+ if (!fates[i].serious && (rand_int(2) == 0)) continue;
+
+ /* Analyse fate */
+ switch (fates[i].fate)
+ {
+ /* You are doomed */
+ case FATE_DIE:
+ {
+ cmsg_print(TERM_L_DARK, "You were fated to die here. DIE!");
+
+ /* You shall perish there */
+ dungeon_type = DUNGEON_DEATH;
+ dun_level = d_info[dungeon_type].mindepth; /* was 1 */
+
+ fates[i].fate = FATE_NONE;
+ break;
+ }
+ }
+ }
+
+ /* Notice stuff */
+ if (p_ptr->notice) notice_stuff();
+
+ /* Update stuff */
+ if (p_ptr->update) update_stuff();
+
+ /* Redraw stuff */
+ if (p_ptr->redraw) redraw_stuff();
+
+ /* Window stuff */
+ if (p_ptr->window) window_stuff();
+
+ /* Cancel the target */
+ target_who = 0;
+
+ /* Cancel the health bar */
+ health_track(0);
+
+
+ /* Forget the lite */
+ forget_mon_lite();
+
+ /* Forget the view */
+ forget_view();
+
+ /* Handle "quit and save" */
+ if (!alive && !death) break;
+
+
+ /* Erase the old cave */
+ wipe_o_list();
+
+
+ /* XXX XXX XXX */
+ msg_print(NULL);
+
+ /* Accidental Death */
+ if (alive && death)
+ {
+ cheat_death = FALSE;
+
+ /* Can we die ? please let us die ! */
+ if (process_hooks(HOOK_DIE, "()"))
+ {
+ cheat_death = TRUE;
+ }
+
+ /* Deus ex machina */
+ else if (granted_resurrection())
+ {
+ cheat_death = TRUE;
+ p_ptr->grace = -200000;
+ cmsg_format(TERM_L_GREEN,
+ "The power of %s raises you back from the grave!",
+ deity_info[p_ptr->pgod].name);
+ msg_print(NULL);
+ }
+
+ /* Blood of life */
+ else if (p_ptr->allow_one_death > 0)
+ {
+ cheat_death = TRUE;
+
+ /* Lose one extra life */
+ p_ptr->allow_one_death--;
+
+ cmsg_print(TERM_L_GREEN,
+ "You have been saved by the Blood of Life!");
+ msg_print(NULL);
+ }
+
+ /* Cheat death option */
+ else if ((wizard || cheat_live) && !get_check("Die? "))
+ {
+ cheat_death = TRUE;
+
+ /* Mark social class, reset age, if needed */
+ if (p_ptr->sc) p_ptr->sc = p_ptr->age = 0;
+
+ /* Increase age */
+ p_ptr->age++;
+
+ /* Mark savefile */
+ noscore |= 0x0001;
+ msg_print("You invoke wizard mode and cheat death.");
+ msg_print(NULL);
+ }
+
+ if (cheat_death)
+ {
+ /* Restore the winner status */
+ total_winner = has_won;
+
+ /* One more life spent */
+ p_ptr->lives++;
+
+ /* Restore hit points */
+ p_ptr->chp = p_ptr->mhp;
+ p_ptr->chp_frac = 0;
+
+ /* Heal sanity */
+ p_ptr->csane = p_ptr->msane;
+ p_ptr->csane_frac = 0;
+
+ /* Restore spell points */
+ p_ptr->csp = p_ptr->msp;
+ p_ptr->csp_frac = 0;
+
+ /* Hack -- Healing */
+ (void)set_blind(0);
+ (void)set_confused(0);
+ (void)set_poisoned(0);
+ (void)set_afraid(0);
+ (void)set_paralyzed(0);
+ (void)set_image(0);
+ (void)set_stun(0);
+ (void)set_cut(0);
+
+ /* accounting for a new ailment. -LM- */
+ p_ptr->black_breath = FALSE;
+
+ /* Hack -- don't go to undead form */
+ p_ptr->necro_extra &= ~CLASS_UNDEAD;
+
+ /* Hack -- Prevent starvation */
+ (void)set_food(PY_FOOD_MAX - 1);
+
+ /* Hack -- cancel recall */
+ if (p_ptr->word_recall)
+ {
+ /* Message */
+ msg_print("A tension leaves the air around you...");
+ msg_print(NULL);
+
+ /* Hack -- Prevent recall */
+ p_ptr->word_recall = 0;
+ }
+
+ /* Note cause of death XXX XXX XXX */
+ (void)strcpy(died_from, "Cheating death");
+
+ /* Do not die */
+ death = FALSE;
+
+ /* New depth -KMW- */
+ /* dun_level = 0; */
+ p_ptr->inside_arena = 0;
+ leaving_quest = 0;
+ p_ptr->inside_quest = 0;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ }
+ }
+
+ /* Handle "death" */
+ if (death)
+ {
+ break;
+ }
+
+ /* Mega hack */
+ if (dun_level) p_ptr->wild_mode = FALSE;
+
+ /* Make a new level */
+ process_hooks(HOOK_NEW_LEVEL, "(d)", is_quest(dun_level));
+ generate_cave();
+ }
+
+ /* Close stuff */
+ close_game();
+
+ /* Quit */
+ quit(NULL);
+}
+
diff --git a/src/dungeon.pkg b/src/dungeon.pkg
new file mode 100644
index 00000000..f5e4045f
--- /dev/null
+++ b/src/dungeon.pkg
@@ -0,0 +1,1607 @@
+/* File: dungeon.pkg */
+
+/*
+ * Purpose: Lua interface defitions for dungeon routines.
+ * To be processed by tolua to generate C source code.
+ */
+
+$#include "angband.h"
+
+/** @typedef cptr
+ * @note String
+ */
+typedef char* cptr;
+
+/** @typedef errr
+ * @note Number
+ */
+typedef int errr;
+
+/** @typedef bool
+ * @note Boolean
+ */
+typedef unsigned char bool;
+
+/** @typedef byte
+ * @note Number
+ */
+typedef unsigned char byte;
+
+/** @typedef s16b
+ * @note Number
+ */
+typedef signed short s16b;
+
+/** @typedef u16b
+ * @note Number
+ */
+typedef unsigned short u16b;
+
+/** @typedef s32b
+ * @note Number
+ */
+typedef signed int s32b;
+
+/** @typedef u32b
+ * @note Number
+ */
+typedef unsigned int u32b;
+
+/** @name Cave Grid
+ * @note Special cave grid flags
+ * @{
+ */
+
+/** @def CAVE_MARK
+ * @note memorized feature
+ */
+#define CAVE_MARK 0x0001
+
+/** @def CAVE_GLOW
+ * @note self-illuminating
+ */
+#define CAVE_GLOW 0x0002
+
+/** @def CAVE_ICKY
+ * @note part of a vault
+ */
+#define CAVE_ICKY 0x0004
+
+/** @def CAVE_ROOM
+ * @note part of a room
+ */
+#define CAVE_ROOM 0x0008
+
+/** @def CAVE_SEEN
+ * @note seen flag
+ */
+#define CAVE_SEEN 0x0010
+
+/** @def CAVE_VIEW
+ * @note view flag
+ */
+#define CAVE_VIEW 0x0020
+
+/** @def CAVE_TEMP
+ * @note temp flag
+ */
+#define CAVE_TEMP 0x0040
+
+/** @def CAVE_WALL
+ * @note wall flag
+ */
+#define CAVE_WALL 0x0080
+
+/** @def CAVE_TRDT
+ * @note trap detected
+ */
+#define CAVE_TRDT 0x0100
+
+/** @def CAVE_IDNT
+ * @note grid identified (fountains)
+ */
+#define CAVE_IDNT 0x0200
+
+/** @def CAVE_SPEC
+ * @note special mark(quests)
+ */
+#define CAVE_SPEC 0x0400
+
+/** @def CAVE_FREE
+ * @note no random generation on it
+ */
+#define CAVE_FREE 0x0800
+
+/** @def CAVE_DETECT
+ * @note Traps detected here
+ */
+#define CAVE_DETECT 0x1000
+
+/** @def CAVE_PLIT
+ * @note Player lit grid
+ */
+#define CAVE_PLIT 0x2000
+
+/** @def CAVE_MLIT
+ * @note Monster lit grid
+ */
+#define CAVE_MLIT 0x4000
+/** @} */
+
+/** @name Terrain Feature Indexes
+ * @note (see "lib/edit/f_info.txt")
+ * @{
+ */
+
+/* Nothing */
+/** @def FEAT_NONE */
+#define FEAT_NONE 0x00
+
+
+/* Basic features */
+/** @def FEAT_FLOOR */
+#define FEAT_FLOOR 0x01
+
+/** @def FEAT_FOUNTAIN */
+#define FEAT_FOUNTAIN 0x02
+
+/** @def FEAT_GLYPH */
+#define FEAT_GLYPH 0x03
+
+/** @def FEAT_OPEN */
+#define FEAT_OPEN 0x04
+
+/** @def FEAT_BROKEN */
+#define FEAT_BROKEN 0x05
+
+/** @def FEAT_LESS */
+#define FEAT_LESS 0x06
+
+/** @def FEAT_MORE */
+#define FEAT_MORE 0x07
+
+
+/* Quest features -KMW- */
+/** @def FEAT_QUEST_ENTER */
+#define FEAT_QUEST_ENTER 0x08
+
+/** @def FEAT_QUEST_EXIT */
+#define FEAT_QUEST_EXIT 0x09
+
+/** @def FEAT_QUEST_DOWN */
+#define FEAT_QUEST_DOWN 0x0A
+
+/** @def FEAT_QUEST_UP */
+#define FEAT_QUEST_UP 0x0B
+
+
+/* Shafts -GSN- */
+/** @def FEAT_SHAFT_DOWN */
+#define FEAT_SHAFT_DOWN 0x0D
+
+/** @def FEAT_SHAFT_UP */
+#define FEAT_SHAFT_UP 0x0E
+
+
+/* Basic feature */
+/** @def FEAT_EMPTY_FOUNTAIN */
+#define FEAT_EMPTY_FOUNTAIN 0x0F
+
+
+/* Feature 0x10 -- web */
+
+/* Traps */
+/** @def FEAT_TRAP */
+#define FEAT_TRAP 0x11
+
+
+/* Features 0x12 - 0x1F -- unused */
+
+/* Doors */
+/** @def FEAT_DOOR_HEAD */
+#define FEAT_DOOR_HEAD 0x20
+
+/** @def FEAT_DOOR_TAIL */
+#define FEAT_DOOR_TAIL 0x2F
+
+
+/* Extra */
+/** @def FEAT_SECRET */
+#define FEAT_SECRET 0x30
+
+/** @def FEAT_RUBBLE */
+#define FEAT_RUBBLE 0x31
+
+
+/* Seams */
+/** @def FEAT_MAGMA */
+#define FEAT_MAGMA 0x32
+
+/** @def FEAT_QUARTZ */
+#define FEAT_QUARTZ 0x33
+
+/** @def FEAT_MAGMA_H */
+#define FEAT_MAGMA_H 0x34
+
+/** @def FEAT_QUARTZ_H */
+#define FEAT_QUARTZ_H 0x35
+
+/** @def FEAT_MAGMA_K */
+#define FEAT_MAGMA_K 0x36
+
+/** @def FEAT_QUARTZ_K */
+#define FEAT_QUARTZ_K 0x37
+
+
+/* Walls */
+/** @def FEAT_WALL_EXTRA */
+#define FEAT_WALL_EXTRA 0x38
+
+/** @def FEAT_WALL_INNER */
+#define FEAT_WALL_INNER 0x39
+
+/** @def FEAT_WALL_OUTER */
+#define FEAT_WALL_OUTER 0x3A
+
+/** @def FEAT_WALL_SOLID */
+#define FEAT_WALL_SOLID 0x3B
+
+/** @def FEAT_PERM_EXTRA */
+#define FEAT_PERM_EXTRA 0x3C
+
+/** @def FEAT_PERM_INNER */
+#define FEAT_PERM_INNER 0x3D
+
+/** @def FEAT_PERM_OUTER */
+#define FEAT_PERM_OUTER 0x3E
+
+/** @def FEAT_PERM_SOLID */
+#define FEAT_PERM_SOLID 0x3F
+
+
+/* Explosive rune */
+/** @def FEAT_MINOR_GLYPH */
+#define FEAT_MINOR_GLYPH 0x40
+
+
+/* Pattern */
+/** @def FEAT_PATTERN_START */
+#define FEAT_PATTERN_START 0x41
+
+/** @def FEAT_PATTERN_1 */
+#define FEAT_PATTERN_1 0x42
+
+/** @def FEAT_PATTERN_2 */
+#define FEAT_PATTERN_2 0x43
+
+/** @def FEAT_PATTERN_3 */
+#define FEAT_PATTERN_3 0x44
+
+/** @def FEAT_PATTERN_4 */
+#define FEAT_PATTERN_4 0x45
+
+/** @def FEAT_PATTERN_END */
+#define FEAT_PATTERN_END 0x46
+
+/** @def FEAT_PATTERN_OLD */
+#define FEAT_PATTERN_OLD 0x47
+
+/** @def FEAT_PATTERN_XTRA1 */
+#define FEAT_PATTERN_XTRA1 0x48
+
+/** @def FEAT_PATTERN_XTRA2 */
+#define FEAT_PATTERN_XTRA2 0x49
+
+
+/* Shops */
+/** @def FEAT_SHOP */
+#define FEAT_SHOP 0x4A
+
+
+/* Permanent walls for quests */
+/** @def FEAT_QUEST1 */
+#define FEAT_QUEST1 0x4B
+
+/** @def FEAT_QUEST2 */
+#define FEAT_QUEST2 0x4C
+
+/** @def FEAT_QUEST3 */
+#define FEAT_QUEST3 0x4D
+
+/** @def FEAT_QUEST4 */
+#define FEAT_QUEST4 0x4E
+
+
+/* Features 0x4F - 0x53 -- unused */
+
+/* Additional terrains */
+/** @def FEAT_SHAL_WATER */
+#define FEAT_SHAL_WATER 0x54
+
+/** @def FEAT_DEEP_LAVA */
+#define FEAT_DEEP_LAVA 0x55
+
+/** @def FEAT_SHAL_LAVA */
+#define FEAT_SHAL_LAVA 0x56
+
+/** @def FEAT_DARK_PIT */
+#define FEAT_DARK_PIT 0x57
+
+/** @def FEAT_DIRT */
+#define FEAT_DIRT 0x58
+
+/** @def FEAT_GRASS */
+#define FEAT_GRASS 0x59
+
+/** @def FEAT_ICE */
+#define FEAT_ICE 0x5A
+
+/** @def FEAT_SAND */
+#define FEAT_SAND 0x5B
+
+/** @def FEAT_DEAD_TREE */
+#define FEAT_DEAD_TREE 0x5C
+
+/** @def FEAT_ASH */
+#define FEAT_ASH 0x5D
+
+/** @def FEAT_MUD */
+#define FEAT_MUD 0x5E
+
+/** @def FEAT_ICE_WALL */
+#define FEAT_ICE_WALL 0x5F
+
+/** @def FEAT_TREES */
+#define FEAT_TREES 0x60
+
+/** @def FEAT_MOUNTAIN */
+#define FEAT_MOUNTAIN 0x61
+
+/** @def FEAT_SANDWALL */
+#define FEAT_SANDWALL 0x62
+
+/** @def FEAT_SANDWALL_H */
+#define FEAT_SANDWALL_H 0x63
+
+/** @def FEAT_SANDWALL_K */
+#define FEAT_SANDWALL_K 0x64
+
+/* Feature 0x65 -- high mountain chain */
+/* Feature 0x66 -- nether mist */
+
+/* Features 0x67 - 0x9F -- unused */
+
+/** @def FEAT_BETWEEN
+ * @note 160
+ */
+#define FEAT_BETWEEN 0xA0
+
+/* Altars */
+/** @def FEAT_ALTAR_HEAD
+ * @note 161
+ */
+#define FEAT_ALTAR_HEAD 0xA1
+
+/** @def FEAT_ALTAR_TAIL
+ * @note 171
+ */
+#define FEAT_ALTAR_TAIL 0xAB
+
+/** @def FEAT_MARKER
+ * @note 172
+ */
+#define FEAT_MARKER 0xAC
+
+/* Feature 0xAD -- Underground Tunnel */
+/** @def FEAT_TAINTED_WATER
+ * @note 174
+ */
+#define FEAT_TAINTED_WATER 0xAE
+
+/** @def FEAT_MON_TRAP
+ * @note 175
+ */
+#define FEAT_MON_TRAP 0xAF
+
+/** @def FEAT_BETWEEN2
+ * @note 176
+ */
+#define FEAT_BETWEEN2 0xB0
+
+/** @def FEAT_LAVA_WALL
+ * @note 177
+ */
+#define FEAT_LAVA_WALL 0xB1
+
+/** @def FEAT_GREAT_FIRE
+ * @note 178
+ */
+#define FEAT_GREAT_FIRE 0xB2
+
+/** @def FEAT_WAY_MORE
+ * @note 179
+ */
+#define FEAT_WAY_MORE 0xB3
+
+/** @def FEAT_WAY_LESS
+ * @note 180
+ */
+#define FEAT_WAY_LESS 0xB4
+
+/* Feature 0xB5 -- field */
+
+/** @def FEAT_EKKAIA
+ * @note 182
+ */
+#define FEAT_EKKAIA 0xB6
+
+/* Features 0xB7 - 0xBA -- unused */
+
+/** @def FEAT_DEEP_WATER
+ * @note 187
+ */
+#define FEAT_DEEP_WATER 0xBB
+
+/** @def FEAT_GLASS_WALL
+ * @note 188
+ */
+#define FEAT_GLASS_WALL 0xBC
+
+/** @def FEAT_ILLUS_WALL
+ * @note 189
+ */
+#define FEAT_ILLUS_WALL 0xBD
+
+/* Feature 0xBE -- grass roof */
+/* Feature 0xBF -- grass roof top */
+/* Feature 0xC0 -- grass roof chimney */
+/* Feature 0xC1 -- brick roof */
+/* Feature 0xC2 -- brick roof top */
+/* Feature 0xC3 -- brick roof chimney */
+/* Feature 0xC4 -- window */
+/* Feature 0xC5 -- small window */
+/* Feature 0xC6 -- rain barrel */
+
+/** @def FEAT_FLOWER
+ * @note 199
+ */
+#define FEAT_FLOWER 0xC7
+
+/* Feature 0xC8 -- cobblestone road */
+/* Feature 0xC9 -- cobblestone with outlet */
+
+/** @def FEAT_SMALL_TREES
+ * @note 202
+ */
+#define FEAT_SMALL_TREES 0xCA
+
+/** @def FEAT_TOWN
+ * @note 203
+ */
+#define FEAT_TOWN 0xCB
+
+/* Feature 0xCC -- Underground Tunnel */
+
+/** @def FEAT_FIRE
+ * @note 205
+ */
+#define FEAT_FIRE 0xCD
+
+/* Feature 0xCE -- pile of rubble (permanent) */
+/* Features 0xCF - 0xFF -- unused */
+/** @} */
+
+/** @name Dungeon Type Flags (part 1)
+ * @{ */
+
+/** @def DF1_PRINCIPAL
+ * @note Is a principal dungeon
+ */
+#define DF1_PRINCIPAL 0x00000001L
+/** @def DF1_MAZE
+ * @note Is a maze-type dungeon
+ */
+#define DF1_MAZE 0x00000002L
+/** @def DF1_SMALLEST
+ * @note Creates VERY small levels like The Maze
+ */
+#define DF1_SMALLEST 0x00000004L
+/** @def DF1_SMALL
+ * @note Creates small levels like Dol Goldor
+ */
+#define DF1_SMALL 0x00000008L
+/** @def DF1_BIG
+ * @note Creates big levels like Moria, and Angband dungeons
+ */
+#define DF1_BIG 0x00000010L
+/** @def DF1_NO_DOORS
+ * @note No doors on rooms, like Barrowdowns, Old Forest etc)
+ */
+#define DF1_NO_DOORS 0x00000020L
+/** @def DF1_WATER_RIVER
+ * @note Allow a single water streamer on a level
+ */
+#define DF1_WATER_RIVER 0x00000040L
+/** @def DF1_LAVA_RIVER
+ * @note Allow a single lava streamer on a level
+ */
+#define DF1_LAVA_RIVER 0x00000080L
+/** @def DF1_WATER_RIVERS
+ * @note Allow multiple water streamers on a level
+ */
+#define DF1_WATER_RIVERS 0x00000100L
+/** @def DF1_LAVA_RIVERS
+ * @note Allow multiple lava streamers on a level
+ */
+#define DF1_LAVA_RIVERS 0x00000200L
+/** @def DF1_CAVE
+ * @note Allow orc-cave like 'fractal' rooms
+ */
+#define DF1_CAVE 0x00000400L
+/** @def DF1_CAVERN
+ * @note Allow cavern rooms
+ */
+#define DF1_CAVERN 0x00000800L
+/** @def DF1_NO_UP
+ * @note Disallow up stairs
+ */
+#define DF1_NO_UP 0x00001000L
+/** @def DF1_HOT
+ * @note Corpses on ground and in pack decay quicker through heat
+ */
+#define DF1_HOT 0x00002000L
+/** @def DF1_COLD
+ * @note Corpses on ground and in pack decay quicker through cold
+ */
+#define DF1_COLD 0x00004000L
+/** @def DF1_FORCE_DOWN
+ * @note No up stairs generated
+ */
+#define DF1_FORCE_DOWN 0x00008000L
+/** @def DF1_FORGET
+ * @note Features are forgotten, like the Maze and Illusory Castle
+ */
+#define DF1_FORGET 0x00010000L
+/** @def DF1_NO_DESTROY
+ * @note No destroyed levels in dungeon
+ */
+#define DF1_NO_DESTROY 0x00020000L
+/** @def DF1_SAND_VEIN
+ * @note Like in the sandworm lair
+ */
+#define DF1_SAND_VEIN 0x00040000L
+/** @def DF1_CIRCULAR_ROOMS
+ * @note Allow circular rooms
+ */
+#define DF1_CIRCULAR_ROOMS 0x00080000L
+/** @def DF1_EMPTY
+ * @note Allow arena levels
+ */
+#define DF1_EMPTY 0x00100000L
+/** @def DF1_DAMAGE_FEAT
+ * @note Effect specified in will affect all grids incl. terrain and monsters
+ */
+#define DF1_DAMAGE_FEAT 0x00200000L
+/** @def DF1_FLAT
+ * @note Creates paths to next areas at edge of level, like Barrowdowns
+ */
+#define DF1_FLAT 0x00400000L
+/** @def DF1_TOWER
+ * @note You start at bottom and go up rather than the reverse
+ */
+#define DF1_TOWER 0x00800000L
+/** @def DF1_RANDOM_TOWNS
+ * @note Allow random towns
+ */
+#define DF1_RANDOM_TOWNS 0x01000000L
+/** @def DF1_DOUBLE
+ * @note Generates everything at double size like Helcaraxe and Erebor
+ */
+#define DF1_DOUBLE 0x02000000L
+/** @def DF1_LIFE_LEVEL
+ * @note Creates dungeon level on modified 'game of life' algorithm
+ */
+#define DF1_LIFE_LEVEL 0x04000000L
+/** @def DF1_EVOLVE
+ * @note Evolving, pulsing levels like Heart of the Earth
+ */
+#define DF1_EVOLVE 0x08000000L
+/** @def DF1_ADJUST_LEVEL_1
+ * @note Minimum monster level will be equal to dungeon level
+ */
+#define DF1_ADJUST_LEVEL_1 0x10000000L
+/** @def DF1_ADJUST_LEVEL_2
+ * @note Minimum monster level will be double the dungeon level
+ */
+#define DF1_ADJUST_LEVEL_2 0x20000000L
+/** @def DF1_NO_RECALL
+ * @note No recall allowed
+ */
+#define DF1_NO_RECALL 0x40000000L
+/** @def DF1_NO_STREAMERS
+ * @note No streamers
+ */
+#define DF1_NO_STREAMERS 0x80000000L
+/** @} */
+
+/** @name Dungeon Type Flags (part 2)
+ * @{ */
+
+/** @def DF2_ADJUST_LEVEL_1_2
+ * @note Minimum monster level will be half the dungeon level
+ */
+#define DF2_ADJUST_LEVEL_1_2 0x00000001L
+
+/** @def DF2_NO_SHAFT
+ * @note No shafts
+ */
+#define DF2_NO_SHAFT 0x00000002L
+
+/** @def DF2_ADJUST_LEVEL_PLAYER
+ * @note Uses player level*2 instead of dungeon level for other ADJUST_LEVEL flags
+ */
+#define DF2_ADJUST_LEVEL_PLAYER 0x00000004L
+
+/** @def DF2_NO_TELEPORT */
+#define DF2_NO_TELEPORT 0x00000008L
+
+/** @def DF2_ASK_LEAVE */
+#define DF2_ASK_LEAVE 0x00000010L
+
+/** @def DF2_NO_STAIR */
+#define DF2_NO_STAIR 0x00000020L
+
+/** @def DF2_SPECIAL */
+#define DF2_SPECIAL 0x00000040L
+
+/** @def DF2_NO_NEW_MONSTER */
+#define DF2_NO_NEW_MONSTER 0x00000080L
+
+/** @def DF2_DESC */
+#define DF2_DESC 0x00000100L
+
+/** @def DF2_NO_GENO */
+#define DF2_NO_GENO 0x00000200L
+
+/** @def DF2_NO_BREATH
+ * @note Oups, cannot breath here
+ */
+#define DF2_NO_BREATH 0x00000400L
+
+/** @def DF2_WATER_BREATH
+ * @note Oups, cannot breath here, need water breathing
+ */
+#define DF2_WATER_BREATH 0x00000800L
+
+/** @def DF2_ELVEN
+ * @note Try to create elven monster ego
+ */
+#define DF2_ELVEN 0x00001000L
+
+/** @def DF2_DWARVEN
+ * @note Try to create dwarven monster ego
+ */
+#define DF2_DWARVEN 0x00002000L
+
+/** @def DF2_NO_EASY_MOVE
+ * @note Forbid stuff like teleport level, probability travel, ...
+ */
+#define DF2_NO_EASY_MOVE 0x00004000L
+
+/** @def DF2_NO_RECALL_OUT
+ * @note Cannot recall out of the place
+ */
+#define DF2_NO_RECALL_OUT 0x00008000L
+
+/** @def DF2_DESC_ALWAYS
+ * @note Always shows the desc
+ */
+#define DF2_DESC_ALWAYS 0x00010000L
+/** @} */
+
+/** @var level_flags1;
+ * @brief Number
+ */
+extern u32b dungeon_flags1@level_flags1;
+
+/** @var level_flags2;
+ * @brief Number
+ */
+extern u32b dungeon_flags2@level_flags2;
+
+/** @def MAX_HGT
+ * @note Maximum dungeon height in grids, must be a multiple of SCREEN_HGT,
+ * probably hard-coded to SCREEN_HGT * 3.
+ */
+#define MAX_HGT 66
+
+
+/** @def MAX_WID
+ * @note Maximum dungeon width in grids, must be a multiple of SCREEN_WID,
+ * probably hard-coded to SCREEN_WID * 3.
+ */
+#define MAX_WID 198
+
+
+/** @name Town Defines
+ * @{ */
+
+/** @def TOWN_RANDOM
+ * @note First random town
+ */
+#define TOWN_RANDOM 20
+
+/** @def TOWN_DUNGEON
+ * @note Maximun number of towns per dungeon
+ */
+#define TOWN_DUNGEON 4
+
+/** @def TOWN_CHANCE
+ * @note Chance of 1 town
+ */
+#define TOWN_CHANCE 50
+
+/** @} */
+
+/** @name Wilderness Terrains
+ * @{
+ */
+
+/** @def TERRAIN_EDGE
+ * @note Edge of the World
+ */
+#define TERRAIN_EDGE 0
+
+/** @def TERRAIN_TOWN
+ * @note Town
+ */
+#define TERRAIN_TOWN 1
+
+/** @def TERRAIN_DEEP_WATER
+ * @note Deep water
+ */
+#define TERRAIN_DEEP_WATER 2
+
+/** @def TERRAIN_SHALLOW_WATER
+ * @note Shallow water
+ */
+#define TERRAIN_SHALLOW_WATER 3
+
+/** @def TERRAIN_SWAMP
+ * @note Swamp
+ */
+#define TERRAIN_SWAMP 4
+
+/** @def TERRAIN_DIRT
+ * @note Dirt
+ */
+#define TERRAIN_DIRT 5
+
+/** @def TERRAIN_GRASS
+ * @note Grass
+ */
+#define TERRAIN_GRASS 6
+
+/** @def TERRAIN_TREES
+ * @note Trees
+ */
+#define TERRAIN_TREES 7
+
+/** @def TERRAIN_DESERT
+ * @note Desert
+ */
+#define TERRAIN_DESERT 8
+
+/** @def TERRAIN_SHALLOW_LAVA
+ * @note Shallow lava
+ */
+#define TERRAIN_SHALLOW_LAVA 9
+
+/** @def TERRAIN_DEEP_LAVA
+ * @note Deep lava
+ */
+#define TERRAIN_DEEP_LAVA 10
+
+/** @def TERRAIN_MOUNTAIN
+ * @note Mountain
+ */
+#define TERRAIN_MOUNTAIN 11
+
+/** @def MAX_WILD_TERRAIN */
+#define MAX_WILD_TERRAIN 18
+/** @} */
+
+/** @struct border_type
+ * @note Border
+ */
+struct border_type
+{
+ /** @structvar north[MAX_WID]
+ * @brief Number
+ */
+ byte north[MAX_WID];
+
+ /** @structvar south[MAX_WID]
+ * @brief Number
+ */
+ byte south[MAX_WID];
+
+ /** @structvar east[MAX_HGT]
+ * @brief Number
+ */
+ byte east[MAX_HGT];
+
+ /** @structvar west[MAX_HGT]
+ * @brief Number
+ */
+ byte west[MAX_HGT];
+
+ /** @structvar north_west
+ * @brief Number
+ */
+ byte north_west;
+
+ /** @structvar north_east
+ * @brief Number
+ */
+ byte north_east;
+
+ /** @structvar south_west
+ * @brief Number
+ */
+ byte south_west;
+
+ /** @structvar south_east
+ * @brief Number
+ */
+ byte south_east;
+};
+
+
+/** @struct wilderness_type_info
+ * @note A structure describing a wilderness area
+ * with a terrain, a town or a dungeon entrance
+ */
+struct wilderness_type_info
+{
+ /** @structvar name
+ * @brief Number
+ * @note Name (offset)
+ */
+ u32b name;
+
+ /** @structvar text
+ * @brief Number
+ * @note Text (offset)
+ */
+ u32b text;
+
+ /** @structvar entrance
+ * @brief Number
+ * @note Which town is there(<1000 i's a town, >=1000 it a dungeon)
+ */
+ u16b entrance;
+
+ /** @structvar road
+ * @brief Number
+ * @note Flags of road
+ */
+ byte road;
+
+ /** @structvar level
+ * @brief Number
+ * @note Difficulty level
+ */
+ int level;
+
+ /** @structvar flags1
+ * @brief Number
+ * @note Some flags
+ */
+ u32b flags1;
+
+ /** @structvar feat
+ * @brief Number
+ * @note The feature of f_info.txt that is used to allow passing, ... and to get a char/color/graph
+ */
+ byte feat;
+
+ /** @structvar terrain_idx
+ * @brief Number
+ * @note Terrain index(defined in defines.h)
+ */
+ byte terrain_idx;
+
+ /** @structvar terrain[MAX_WILD_TERRAIN]
+ * @brief Number
+ * @note Feature types for the plasma generator
+ */
+ byte terrain[MAX_WILD_TERRAIN];
+};
+
+/** @struct wilderness_map
+ * @note A structure describing a wilderness map
+ */
+struct wilderness_map
+{
+ /** @structvar feat
+ * @brief Number
+ * @note Wilderness feature
+ */
+ int feat;
+
+ /** @structvar seed
+ * @brief Number
+ * @note Seed for the RNG
+ */
+ u32b seed;
+
+ /** @structvar entrance
+ * @brief Number
+ * @note Entrance for dungeons
+ */
+ u16b entrance;
+
+ /** @structvar known
+ * @brief Boolean
+ * @note Is it seen by the player ?
+ */
+ bool known;
+};
+
+
+/** @struct town_type
+ * @note A structure describing a town with
+ * stores and buildings
+ */
+struct town_type
+{
+ /** @structvar name
+ * @brief String
+ */
+ cptr name;
+
+ /** @structvar seed
+ * @brief Number
+ * @note Seed for RNG
+ */
+ u32b seed;
+
+ /** @structvar *store
+ * @brief store_type
+ * @note The stores [max_st_idx]
+ */
+ store_type store[max_st_idx];
+
+ /** @structvar numstores
+ * @brief Number
+ */
+ byte numstores;
+
+ /** @structvar flags
+ * @brief Number
+ * @note Town flags
+ */
+ byte flags;
+
+ /** @structvar stocked
+ * @brief Boolean
+ * @note Is the town actually stocked ?
+ * Left this for the sake of compatibility
+ */
+ bool stocked;
+
+ /** @structvar destroyed
+ * @brief Boolean
+ * @note Is the town destroyed?
+ */
+ bool destroyed;
+};
+
+/** @var max_towns
+ * @brief Number
+ */
+extern u16b max_towns;
+
+/** @var town_info[max_towns]
+ * @brief town_type
+ */
+extern town_type town_info[max_towns];
+
+/** @struct rule_type
+ * Define monster generation rules
+ */
+struct rule_type
+{
+ /** @structvar mode
+ * @brief Number
+ * @note Mode of combination of the monster flags
+ */
+ byte mode;
+
+ /** @structvar percent
+ * @brief Number
+ * @note Percent of monsters affected by the rule
+ */
+ byte percent;
+
+ /** @structvar mflags1
+ * @brief Number
+ * @note The monster flags that are allowed
+ */
+ u32b mflags1;
+
+ /** @structvar mflags2
+ * @brief Number
+ */
+ u32b mflags2;
+
+ /** @structvar mflags3
+ * @brief Number
+ */
+ u32b mflags3;
+
+ /** @structvar mflags4
+ * @brief Number
+ */
+ u32b mflags4;
+
+ /** @structvar mflags5
+ * @brief Number
+ */
+ u32b mflags5;
+
+ /** @structvar mflags6
+ * @brief Number
+ */
+ u32b mflags6;
+
+ /** @structvar mflags7
+ * @brief Number
+ */
+ u32b mflags7;
+
+ /** @structvar mflags8
+ * @brief Number
+ */
+ u32b mflags8;
+
+ /** @structvar mflags9
+ * @brief Number
+ */
+ u32b mflags9;
+
+ /** @structvar r_char[5]
+ * @brief String
+ * @note Monster race allowed
+ */
+ char r_char[5];
+};
+
+/** @struct obj_theme
+ * @brief "Themed" objects.
+ * @note Probability in percent for each class of objects to be dropped.
+ * This could perhaps be an array - but that wouldn't be as clear.
+ */
+struct obj_theme
+{
+ /** @structvar treasure
+ * @brief Number
+ */
+ byte treasure;
+
+ /** @structvar combat
+ * @brief Number
+ */
+ byte combat;
+
+ /** @structvar magic
+ * @brief Number
+ */
+ byte magic;
+
+ /** @structvar tools
+ * @brief Number
+ */
+ byte tools;
+};
+
+/** @struct dungeon_info_type
+ * A structure for the != dungeon types
+ */
+struct dungeon_info_type
+{
+ /** @structvar name
+ * @brief Number
+ * @note Name
+ */
+ u32b name;
+
+ /** @structvar text
+ * @brief Number
+ * @note Description
+ */
+ u32b text;
+
+ /** @structvar short_name[3]
+ * @brief String
+ * @note Short name
+ */
+ char short_name[3];
+
+ /** @structvar floor1
+ * @brief Number
+ * @note Floor tile 1
+ */
+ s16b floor1;
+
+ /** @structvar floor_percent1[2]
+ * @brief Number
+ * @note Chance of type 1
+ */
+ byte floor_percent1[2];
+
+ /** @structvar floor2
+ * @brief Number
+ * @note Floor tile 2
+ */
+ s16b floor2;
+
+ /** @structvar floor_percent2[2]
+ * @brief Number
+ * @note Chance of type 2
+ */
+ byte floor_percent2[2];
+
+ /** @structvar floor3
+ * @brief Number
+ * @note Floor tile 3
+ */
+ s16b floor3;
+
+ /** @structvar floor_percent3[2]
+ * @brief Number
+ * @note Chance of type 3
+ */
+ byte floor_percent3[2];
+
+ /** @structvar outer_wall
+ * @brief Number
+ * @note Outer wall tile
+ */
+ s16b outer_wall;
+
+ /** @structvar inner_wall
+ * @brief Number
+ * @note Inner wall tile
+ */
+ s16b inner_wall;
+
+ /** @structvar fill_type1
+ * @brief Number
+ * @note Cave tile 1
+ */
+ s16b fill_type1;
+
+ /** @structvar fill_percent1[2]
+ * @brief Number
+ * @note Chance of type 1
+ */
+ byte fill_percent1[2];
+
+ /** @structvar fill_type2
+ * @brief Number
+ * @note Cave tile 2
+ */
+ s16b fill_type2;
+
+ /** @structvar fill_percent2[2]
+ * @brief Number
+ * @note Chance of type 2
+ */
+ byte fill_percent2[2];
+
+ /** @structvar fill_type3
+ * @brief Number
+ * @note Cave tile 3
+ */
+ s16b fill_type3;
+
+ /** @structvar fill_percent3[2]
+ * @brief Number
+ * @note Chance of type 3
+ */
+ byte fill_percent3[2];
+
+ /** @structvar fill_method
+ * @brief Number
+ * @note Smoothing parameter for the above
+ */
+ byte fill_method;
+
+ /** @structvar mindepth
+ * @brief Number
+ * @note Minimal depth
+ */
+ s16b mindepth;
+
+ /** @structvar maxdepth
+ * @brief Number
+ * @note Maximal depth
+ */
+ s16b maxdepth;
+
+ /** @structvar principal
+ * @brief Boolean
+ * @note If it's a part of the main dungeon
+ */
+ bool principal;
+
+ /** @structvar next
+ * @brief Number
+ * @note The next part of the main dungeon
+ */
+ byte next;
+
+ /** @structvar min_plev
+ * @brief Number
+ * @note Minimal plev needed to enter -- it's an anti-cheating mesure
+ */
+ byte min_plev;
+
+ /** @structvar min_m_alloc_level
+ * @brief Number
+ * @note Minimal number of monsters per level
+ */
+ int min_m_alloc_level;
+
+ /** @structvar max_m_alloc_chance
+ * @brief Number
+ * @note There is a 1/max_m_alloc_chance chance per round of creating a new monster
+ */
+ int max_m_alloc_chance;
+
+ /** @structvar flags1
+ * @brief Number
+ * @note Flags 1
+ */
+ u32b flags1;
+
+ /** @structvar flags2
+ * @brief Number
+ * @note Flags 1
+ */
+ u32b flags2;
+
+ /** @structvar size_x
+ * @brief Number
+ */
+ int size_x;
+
+ /** @structvar size_y
+ * @brief Number
+ * @note Desired numers of panels
+ */
+ int size_y;
+
+ /** @structvar rule_percents[100]
+ * @brief Number
+ * @note Flat rule percents
+ */
+ byte rule_percents[100];
+
+ /** @structvar rules[5]
+ * @brief rule_type
+ * @note Monster generation rules
+ */
+ rule_type rules[5];
+
+ /** @structvar final_object
+ * @brief Number
+ * @note The object you'll find at the bottom
+ */
+ int final_object;
+
+ /** @structvar final_artifact
+ * @brief Number
+ * @note The artifact you'll find at the bottom
+ */
+ int final_artifact;
+
+ /** @structvar final_guardian
+ * @brief Number
+ * @note The artifact's guardian. If an artifact is specified, then it's NEEDED
+ */
+ int final_guardian;
+
+ /** @structvar ix
+ * @brief Number
+ */
+ int ix;
+
+ /** @structvar iy
+ * @brief Number
+ */
+ int iy;
+
+ /** @structvar ox
+ * @brief Number
+ */
+ int ox;
+
+ /** @structvar oy
+ * @brief Number
+ * @note Wilderness coordinates of the entrance/output of the dungeon
+ */
+ int oy;
+
+ /** @structvar objs
+ * @brief obj_theme
+ * @note The drops type
+ */
+ obj_theme objs;
+
+ /** @structvar d_dice[4]
+ * @brief Number
+ * @note Number of dices
+ */
+ int d_dice[4];
+
+ /** @structvar d_side[4]
+ * @brief Number
+ * @note Number of sides
+ */
+ int d_side[4];
+
+ /** @structvar d_frequency[4]
+ * @brief Number
+ * @note Frequency of damage (1 is the minimum)
+ */
+ int d_frequency[4];
+
+ /** @structvar d_type[4]
+ * @brief Number
+ * @note Type of damage
+ */
+ int d_type[4];
+
+ /** @structvar t_idx[TOWN_DUNGEON]
+ * @brief Number
+ * @note The towns
+ */
+ s16b t_idx[TOWN_DUNGEON];
+
+ /** @structvar t_level[TOWN_DUNGEON]
+ * @brief Number
+ * @note The towns levels
+ */
+ s16b t_level[TOWN_DUNGEON];
+
+ /** @structvar t_num
+ * @brief Number
+ * @note Number of towns
+ */
+ s16b t_num;
+};
+
+/** @var max_d_idx
+ * @brief Number
+ */
+extern u16b max_d_idx;
+
+/** @var d_info[max_d_idx]
+ * @brief dungeon_info_type
+ */
+extern dungeon_info_type d_info[max_d_idx];
+
+/** @var *d_name
+ * @brief String
+ */
+extern char *d_name;
+
+/** @var *d_text
+ * @brief String
+ */
+extern char *d_text;
+
+/** @var max_wild_x
+ * @brief Number
+ */
+extern u16b max_wild_x;
+
+/** @var max_wild_y
+ * @brief Number
+ */
+extern u16b max_wild_y;
+
+/** @var max_wf_idx
+ * @brief Number
+ */
+extern u16b max_wf_idx;
+
+/** @var wf_info[max_wf_idx]
+ * @brief wilderness_type_info
+ */
+extern wilderness_type_info wf_info[max_wf_idx];
+
+/** @var *wf_name
+ * @brief String
+ */
+extern char *wf_name;
+
+/** @var *wf_text
+ * @brief String
+ */
+extern char *wf_text;
+
+/** @var DUNGEON_DEATH
+ * @brief Number
+ */
+extern s32b DUNGEON_DEATH;
+
+/** @var current_dungeon_idx;
+ * @brief Number
+ */
+extern byte dungeon_type@current_dungeon_idx;
+
+/*
+ * tolua doesnt like wierd arraysn, I'll use accessing functions
+ * extern wilderness_map wild_map[max_wild_y][max_wild_x];
+ */
+$static wilderness_map* lua_get_wild_map(int y, int x) { return &wild_map[y][x]; }
+
+/** @fn wild_map(int y, int x);
+ * @brief Return a map of the wilderness at coordinate (y,x).\n
+ * @param y Number \n y coordinate of wilderness map
+ * @brief Y-coordinate
+ * @param x Number \n x coordinate of wilderness map
+ * @brief X-coordinate
+ * @return wilderness_map \n map of wilderness at coordinate (y,x)
+ * @note (see file w_dun.c)
+ */
+wilderness_map* lua_get_wild_map@wild_map(int y, int x);
+
+/** @fn place_trap(int y, int x)
+ * @brief Place a random trap at the given location.\n
+ * @param y Number \n y coordinate of dungeon
+ * @brief Y-coordinate
+ * @param x Number \n x coordinate of dungeon
+ * @brief X-coordinate
+ * @note
+ * Places a random trap at the given location.\n
+ * The location must be a valid, empty, clean, floor grid.
+ * @note (see file traps.c)
+ */
+extern void place_trap(int y, int x);
+
+/** @fn place_floor(int y, int x)
+ * @brief Place floor terrain at (y, x).\n
+ * @param y Number \n y coordinate of dungeon
+ * @brief Y-coordinate
+ * @param x Number \n x coordinate of dungeon
+ * @brief X-coordinate
+ * @note
+ * Place floor terrain at (y, x) according to dungeon info.
+ * @note (see file cave.c)
+ */
+extern void place_floor(int y, int x);
+
+/** @fn place_filler(int y, int x)
+ * @brief Place a cave filler at (y, x).\n
+ * @param y Number \n y coordinate of dungeon
+ * @brief Y-coordinate
+ * @param x Number \n x coordinate of dungeon
+ * @brief X-coordinate
+ * @note (see file generate.c)
+ */
+extern void place_filler(int y, int x);
+
+/** @fn new_player_spot(int branch)
+ * @brief Places player in a new location.\n
+ * @param branch Number \n branch is the dungeon branch (if any).
+ * @brief Dungeon branch
+ * @return Boolean \n TRUE if player was placed successfully, otherwise FALSE.
+ * The global values py and px are updated.
+ * @note
+ * Up to 5000 attempts are made to place the player in the dungeon. The grid
+ * must be a naked floor and not an anti-teleport grid. In some circumstances
+ * stairs or ways in/out may be created under the player.
+ * @note (see file generate.c)
+ */
+extern bool new_player_spot(int branch);
+
+/** @fn get_level_desc(char *buf)
+ * @brief Return the special level desc.\n
+ * @param *buf String
+ * @brief Description
+ * @return *buf String \n The level description
+ * @return Boolean \n TRUE if a level description was returned, otherwise FALSE
+ * @note
+ * This is the 'D' line in the dngn files.
+ * @note (see file levels.c)
+ */
+extern bool get_level_desc(char *buf);
+
+/** @fn get_level_flags()
+ * These are the 'F' lines in the dngn files.
+ * @note (see file levels.c)
+ */
+extern void get_level_flags();
+
+/** @fn get_dungeon_name(char *buf)
+ * @brief Return the special level name.\n
+ * @param *buf String
+ * @brief Name
+ * @return *buf String \n The level name
+ * @return Boolean \n TRUE if a level name was returned, otherwise FALSE
+ * @note
+ * This is the 'N' line in the dngn files.
+ * @note (see file levels.c)
+ */
+extern bool get_dungeon_name(char *buf);
+
+/** @fn get_dungeon_special(char *buf)
+ * @brief Return the map filename.\n
+ * @param *buf String
+ * @brief Map filename
+ * @return *buf String \n The map filename
+ * @return Boolean \n TRUE if a map filename was returned, otherwise FALSE
+ * @note
+ * This is the 'S' line in the dngn files.
+ * @note (see file levels.c)
+ */
+extern bool get_dungeon_special(char *buf);
+
+/** @fn get_command(const char *file, char comm, char *param)
+ * @brief Return the parameter of command "comm" in file "*file".\n
+ * @param *file String \n name of the dungeon file.
+ * @brief Dungeon file
+ * @param comm String \n The command \n
+ * 'A' = father branch, 'B' = branch, 'D' = desccription, 'L' = father level,
+ * 'N' = name, 'S' = savefile extension, 'U' = map filename
+ * @brief Command
+ * @param *param String
+ * @brief Parameter
+ * @return *param String \n The result of the command
+ * @return Boolean \n TRUE if a result is returned, otherwise FALSE
+ * @note (see file levels.c)
+ */
+extern bool get_command(const char *file, char comm, char *param);
+
+/** @fn get_branch()
+ * @brief return the dungeon branch starting form the current dungeon/level.
+ * @return Number \n The branch
+ * @note
+ * This is the 'B' line in the dngn files.
+ * @note (see file levels.c)
+ */
+extern int get_branch();
+
+/** @fn get_fbranch()
+ * @brief Return the father dungeon branch.
+ * @return Number \n The father branch
+ * @note
+ * This is the 'A' line in the dngn files.
+ * @note (see file levels.c)
+ */
+extern int get_fbranch();
+
+/** @fn get_flevel()
+ * @brief Return the father dungeon level.
+ * @return Number \n The father level
+ * @note
+ * This is the 'L' line in the dngn files.
+ * @note (see file levels.c)
+ */
+extern int get_flevel();
+
+/** @fn get_dungeon_save(char *buf)
+ * @brief Return the extension of the savefile for the level.\n
+ * @param *buf String
+ * @brief Savefile extension
+ * @return *buf String \n The savefile extension
+ * @return Boolean \n TRUE if a savefile extension was returned, otherwise FALSE
+ * This is the 'S' line in the dngn files.
+ * @note (see file levels.c)
+ */
+extern bool get_dungeon_save(char *buf);
diff --git a/src/externs.h b/src/externs.h
new file mode 100644
index 00000000..197c1c8a
--- /dev/null
+++ b/src/externs.h
@@ -0,0 +1,1851 @@
+/* File: externs.h */
+
+/* Purpose: extern declarations (variables and functions) */
+
+/*
+ * Note that some files have their own header files
+ * (z-virt.h, z-util.h, z-form.h, term.h, random.h)
+ */
+
+/*
+ * Options for inc_stack_size_ex
+ */
+typedef enum { OPTIMIZE, NO_OPTIMIZE } optimize_flag;
+typedef enum { DESCRIBE, NO_DESCRIBE } describe_flag;
+
+
+/*
+ * Automatically generated "variable" declarations
+ */
+
+extern int max_macrotrigger;
+extern char *macro_template;
+extern char *macro_modifier_chr;
+extern char *macro_modifier_name[MAX_MACRO_MOD];
+extern char *macro_trigger_name[MAX_MACRO_TRIG];
+extern char *macro_trigger_keycode[2][MAX_MACRO_TRIG];
+
+/* tables.c */
+extern s16b ddd[9];
+extern s16b ddx[10];
+extern s16b ddy[10];
+extern s16b ddx_ddd[9];
+extern s16b ddy_ddd[9];
+extern char hexsym[16];
+extern byte adj_val_min[];
+extern byte adj_val_max[];
+extern byte adj_mag_study[];
+extern byte adj_mag_mana[];
+extern byte adj_mag_fail[];
+extern byte adj_mag_stat[];
+extern byte adj_chr_gold[];
+extern byte adj_int_dev[];
+extern byte adj_wis_sav[];
+extern byte adj_dex_dis[];
+extern byte adj_int_dis[];
+extern byte adj_dex_ta[];
+extern byte adj_str_td[];
+extern byte adj_dex_th[];
+extern byte adj_str_th[];
+extern byte adj_str_wgt[];
+extern byte adj_str_hold[];
+extern byte adj_str_dig[];
+extern byte adj_str_blow[];
+extern byte adj_dex_blow[];
+extern byte adj_dex_safe[];
+extern byte adj_con_fix[];
+extern byte adj_con_mhp[];
+extern byte blows_table[12][12];
+extern s16b arena_monsters[MAX_ARENA_MONS];
+extern byte extract_energy[300];
+extern s32b player_exp[PY_MAX_LEVEL];
+extern player_sex sex_info[MAX_SEXES];
+extern deity_type deity_info_init[MAX_GODS_INIT];
+extern cptr color_names[16];
+extern cptr stat_names[6];
+extern cptr stat_names_reduced[6];
+extern cptr window_flag_desc[32];
+extern option_type option_info[];
+extern cptr chaos_patrons[MAX_PATRON];
+extern int chaos_stats[MAX_PATRON];
+extern int chaos_rewards[MAX_PATRON][20];
+extern martial_arts bear_blows[MAX_BEAR];
+extern martial_arts ma_blows[MAX_MA];
+extern magic_power mindcraft_powers[MAX_MINDCRAFT_POWERS];
+extern magic_power necro_powers[MAX_NECRO_POWERS];
+extern magic_power mimic_powers[MAX_MIMIC_POWERS];
+extern magic_power symbiotic_powers[MAX_SYMBIOTIC_POWERS];
+extern cptr deity_rarity[2];
+extern cptr deity_niceness[10];
+extern cptr deity_standing[11];
+extern move_info_type move_info[9];
+extern tactic_info_type tactic_info[9];
+extern activation activation_info[MAX_T_ACT];
+extern inscription_info_type inscription_info[MAX_INSCRIPTIONS];
+extern cptr sense_desc[];
+extern flags_group flags_groups[MAX_FLAG_GROUP];
+extern power_type powers_type_init[POWER_MAX_INIT];
+extern quest_type quest_info[MAX_Q_IDX_INIT];
+extern cptr artifact_names_list;
+extern monster_power monster_powers[96];
+extern tval_desc tval_descs[];
+extern between_exit between_exits[MAX_BETWEEN_EXITS];
+extern int month_day[9];
+extern cptr month_name[9];
+extern cli_comm *cli_info;
+extern int cli_total;
+extern quest_type quest_init_tome[MAX_Q_IDX_INIT];
+extern int max_body_part[BODY_MAX];
+extern gf_name_type gf_names[];
+
+
+/* variable.c */
+extern cptr copyright[5];
+extern byte version_major;
+extern byte version_minor;
+extern byte version_patch;
+extern byte version_extra;
+extern byte sf_major;
+extern byte sf_minor;
+extern byte sf_patch;
+extern byte sf_extra;
+extern u32b sf_xtra;
+extern u32b sf_when;
+extern u16b sf_lives;
+extern u16b sf_saves;
+extern u32b vernum; /* Version flag */
+extern bool_ arg_fiddle;
+extern bool_ arg_wizard;
+extern bool_ arg_sound;
+extern bool_ arg_graphics;
+extern bool_ arg_force_original;
+extern bool_ arg_force_roguelike;
+extern bool_ arg_bigtile;
+extern bool_ character_generated;
+extern bool_ character_dungeon;
+extern bool_ character_loaded;
+extern bool_ character_saved;
+extern bool_ character_icky;
+extern bool_ character_xtra;
+extern u32b seed_flavor;
+extern s16b command_cmd;
+extern s16b command_arg;
+extern s16b command_rep;
+extern s16b command_dir;
+extern s16b command_wrk;
+extern s16b command_new;
+extern s32b energy_use;
+extern s16b choose_default;
+extern bool_ create_up_stair;
+extern bool_ create_down_stair;
+extern bool_ create_up_shaft;
+extern bool_ create_down_shaft;
+extern bool_ msg_flag;
+extern bool_ alive;
+extern bool_ death;
+extern s16b running;
+extern s16b resting;
+extern s16b cur_hgt;
+extern s16b cur_wid;
+extern s16b dun_level;
+extern s16b old_dun_level;
+extern s16b num_repro;
+extern s16b object_level;
+extern s16b monster_level;
+extern s32b turn;
+extern s32b old_turn;
+extern bool_ wizard;
+extern bool_ use_sound;
+extern bool_ use_graphics;
+extern bool_ use_bigtile;
+extern byte graphics_mode;
+extern u16b total_winner;
+extern u16b has_won;
+extern u16b noscore;
+extern s16b signal_count;
+extern bool_ inkey_base;
+extern bool_ inkey_xtra;
+extern bool_ inkey_scan;
+extern bool_ inkey_flag;
+extern s16b coin_type;
+extern bool_ opening_chest;
+extern bool_ shimmer_monsters;
+extern bool_ shimmer_objects;
+extern bool_ repair_monsters;
+extern bool_ repair_objects;
+extern s16b inven_nxt;
+extern s16b inven_cnt;
+extern s16b equip_cnt;
+extern s16b o_max;
+extern s16b o_cnt;
+extern s16b m_max;
+extern s16b m_cnt;
+extern s16b hack_m_idx;
+extern s16b hack_m_idx_ii;
+extern int total_friends;
+extern s32b total_friend_levels;
+extern int leaving_quest;
+extern bool_ multi_rew;
+extern char summon_kin_type;
+extern bool_ hack_mind;
+extern bool_ hack_corruption;
+extern bool_ is_autosave;
+extern int artifact_bias;
+extern FILE *text_out_file;
+extern void (*text_out_hook)(byte a, cptr str);
+extern int text_out_wrap;
+extern int text_out_indent;
+extern int highscore_fd;
+extern bool_ show_inven_graph;
+extern bool_ show_store_graph;
+extern bool_ show_equip_graph;
+extern bool_ rogue_like_commands;
+extern bool_ quick_messages;
+extern bool_ other_query_flag;
+extern bool_ carry_query_flag;
+extern bool_ always_pickup;
+extern bool_ prompt_pickup_heavy;
+extern bool_ always_repeat;
+extern bool_ use_old_target;
+extern bool_ depth_in_feet;
+extern bool_ hilite_player;
+extern bool_ ring_bell;
+extern bool_ find_ignore_stairs;
+extern bool_ find_ignore_doors;
+extern bool_ find_cut;
+extern bool_ find_examine;
+extern bool_ disturb_near;
+extern bool_ disturb_move;
+extern bool_ disturb_panel;
+extern bool_ disturb_detect;
+extern bool_ disturb_state;
+extern bool_ disturb_minor;
+extern bool_ disturb_other;
+extern bool_ avoid_abort;
+extern bool_ avoid_shimmer;
+extern bool_ avoid_other;
+extern bool_ flush_disturb;
+extern bool_ flush_failure;
+extern bool_ flush_command;
+extern bool_ fresh_before;
+extern bool_ fresh_after;
+extern bool_ fresh_message;
+extern bool_ alert_hitpoint;
+extern bool_ alert_failure;
+extern bool_ view_yellow_lite;
+extern bool_ view_bright_lite;
+extern bool_ view_granite_lite;
+extern bool_ view_special_lite;
+extern bool_ plain_descriptions;
+extern bool_ stupid_monsters;
+extern bool_ auto_destroy;
+extern bool_ wear_confirm;
+extern bool_ confirm_stairs;
+extern bool_ disturb_pets;
+extern bool_ view_perma_grids;
+extern bool_ view_torch_grids;
+extern bool_ monster_lite;
+extern bool_ flow_by_sound;
+extern bool_ track_follow;
+extern bool_ track_target;
+extern bool_ stack_allow_items;
+extern bool_ stack_allow_wands;
+extern bool_ stack_force_notes;
+extern bool_ stack_force_costs;
+extern bool_ view_reduce_lite;
+extern bool_ view_reduce_view;
+extern bool_ auto_haggle;
+extern bool_ auto_scum;
+extern bool_ expand_look;
+extern bool_ expand_list;
+extern bool_ dungeon_align;
+extern bool_ dungeon_stair;
+extern bool_ smart_learn;
+extern bool_ smart_cheat;
+extern bool_ show_labels;
+extern bool_ show_weights;
+extern bool_ show_choices;
+extern bool_ show_details;
+extern bool_ testing_stack;
+extern bool_ testing_carry;
+extern bool_ cheat_peek;
+extern bool_ cheat_hear;
+extern bool_ cheat_room;
+extern bool_ cheat_xtra;
+extern bool_ cheat_know;
+extern bool_ cheat_live;
+extern bool_ last_words; /* Zangband options */
+extern bool_ speak_unique;
+extern bool_ small_levels;
+extern bool_ empty_levels;
+extern bool_ always_small_level;
+extern bool_ player_symbols;
+extern byte hitpoint_warn;
+extern byte delay_factor;
+extern s16b autosave_freq;
+extern bool_ autosave_t;
+extern bool_ autosave_l;
+extern s16b feeling;
+extern s16b rating;
+extern bool_ good_item_flag;
+extern bool_ closing_flag;
+extern s16b max_panel_rows, max_panel_cols;
+extern s16b panel_row_min, panel_row_max;
+extern s16b panel_col_min, panel_col_max;
+extern s16b panel_col_prt, panel_row_prt;
+extern byte feat_wall_outer;
+extern byte feat_wall_inner;
+extern s16b floor_type[100];
+extern s16b fill_type[100];
+extern s16b py;
+extern s16b px;
+extern s16b target_who;
+extern s16b target_col;
+extern s16b target_row;
+extern s16b health_who;
+extern s16b monster_race_idx;
+extern s16b monster_ego_idx;
+extern object_type *tracked_object;
+extern int player_uid;
+extern char player_name[32];
+extern char player_base[32];
+extern char died_from[80];
+extern char history[4][60];
+extern char savefile[1024];
+extern s16b lite_n;
+extern s16b lite_y[LITE_MAX];
+extern s16b lite_x[LITE_MAX];
+extern s16b view_n;
+extern byte view_y[VIEW_MAX];
+extern byte view_x[VIEW_MAX];
+extern s16b temp_n;
+extern byte temp_y[TEMP_MAX];
+extern byte temp_x[TEMP_MAX];
+extern s16b macro__num;
+extern cptr *macro__pat;
+extern cptr *macro__act;
+extern bool_ *macro__cmd;
+extern char *macro__buf;
+extern s16b quark__num;
+extern cptr *quark__str;
+extern u16b message__next;
+extern u16b message__last;
+extern u16b message__head;
+extern u16b message__tail;
+extern u16b *message__ptr;
+extern byte *message__color;
+extern byte *message__type;
+extern u16b *message__count;
+extern char *message__buf;
+extern u32b option_flag[8];
+extern u32b option_mask[8];
+extern u32b window_flag[ANGBAND_TERM_MAX];
+extern u32b window_mask[ANGBAND_TERM_MAX];
+extern term *angband_term[ANGBAND_TERM_MAX];
+extern char angband_term_name[ANGBAND_TERM_MAX][80];
+extern byte angband_color_table[256][4];
+extern char angband_sound_name[SOUND_MAX][16];
+extern cave_type *cave[MAX_HGT];
+extern object_type *o_list;
+extern monster_type *m_list;
+extern monster_type *km_list;
+extern u16b max_real_towns;
+extern u16b max_towns;
+extern town_type *town_info;
+extern s16b alloc_kind_size;
+extern alloc_entry *alloc_kind_table;
+extern bool_ alloc_kind_table_valid;
+extern s16b alloc_race_size;
+extern alloc_entry *alloc_race_table;
+extern byte misc_to_attr[256];
+extern char misc_to_char[256];
+extern byte tval_to_attr[128];
+extern char tval_to_char[128];
+extern cptr keymap_act[KEYMAP_MODES][256];
+extern player_type p_body;
+extern player_type *p_ptr;
+extern player_sex *sp_ptr;
+extern player_race *rp_ptr;
+extern player_race_mod *rmp_ptr;
+extern player_class *cp_ptr;
+extern player_spec *spp_ptr;
+extern u32b alchemist_known_egos[32];
+extern alchemist_recipe *alchemist_recipes;
+extern u32b alchemist_known_artifacts[6];
+extern u32b alchemist_gained;
+extern s16b player_hp[PY_MAX_LEVEL];
+extern header *al_head;
+extern char *al_name;
+extern artifact_select_flag *a_select_flags;
+
+extern header *ab_head;
+extern ability_type *ab_info;
+extern char *ab_name;
+extern char *ab_text;
+
+extern header *s_head;
+extern skill_type *s_info;
+extern char *s_name;
+extern char *s_text;
+
+extern header *v_head;
+extern vault_type *v_info;
+extern char *v_name;
+extern char *v_text;
+extern header *f_head;
+extern feature_type *f_info;
+extern char *f_name;
+extern char *f_text;
+extern header *k_head;
+extern object_kind *k_info;
+extern char *k_name;
+extern char *k_text;
+extern header *a_head;
+extern artifact_type *a_info;
+extern char *a_name;
+extern char *a_text;
+extern header *e_head;
+extern ego_item_type *e_info;
+extern char *e_name;
+extern char *e_text;
+extern header *ra_head;
+extern randart_part_type *ra_info;
+extern randart_gen_type ra_gen[30];
+extern header *r_head;
+extern monster_race *r_info;
+extern char *r_name;
+extern char *r_text;
+extern header *re_head;
+extern monster_ego *re_info;
+extern char *re_name;
+extern header *d_head;
+extern dungeon_info_type *d_info;
+extern char *d_name;
+extern char *d_text;
+extern header *c_head;
+extern player_class *class_info;
+extern char *c_name;
+extern char *c_text;
+extern meta_class_type *meta_class_info;
+extern header *rp_head;
+extern player_race *race_info;
+extern char *rp_name;
+extern char *rp_text;
+extern header *rmp_head;
+extern player_race_mod *race_mod_info;
+extern char *rmp_name;
+extern char *rmp_text;
+extern header *t_head;
+extern trap_type *t_info;
+extern char *t_name;
+extern char *t_text;
+extern header *wf_head;
+extern wilderness_type_info *wf_info;
+extern char *wf_name;
+extern char *wf_text;
+extern int wildc2i[256];
+extern header *st_head;
+extern store_info_type *st_info;
+extern char *st_name;
+extern header *ba_head;
+extern store_action_type *ba_info;
+extern char *ba_name;
+extern header *ow_head;
+extern owner_type *ow_info;
+extern char *ow_name;
+extern header *set_head;
+extern set_type *set_info;
+extern char *set_name;
+extern char *set_text;
+extern cptr ANGBAND_SYS;
+extern cptr ANGBAND_KEYBOARD;
+extern cptr ANGBAND_GRAF;
+extern cptr ANGBAND_DIR;
+extern cptr ANGBAND_DIR_APEX;
+extern cptr ANGBAND_DIR_CORE;
+extern cptr ANGBAND_DIR_DNGN;
+extern cptr ANGBAND_DIR_DATA;
+extern cptr ANGBAND_DIR_EDIT;
+extern cptr ANGBAND_DIR_FILE;
+extern cptr ANGBAND_DIR_HELP;
+extern cptr ANGBAND_DIR_INFO;
+extern cptr ANGBAND_DIR_MODULES;
+extern cptr ANGBAND_DIR_NOTE;
+extern cptr ANGBAND_DIR_SAVE;
+extern cptr ANGBAND_DIR_SCPT;
+extern cptr ANGBAND_DIR_PATCH;
+extern cptr ANGBAND_DIR_PREF;
+extern cptr ANGBAND_DIR_USER;
+extern cptr ANGBAND_DIR_XTRA;
+extern cptr ANGBAND_DIR_CMOV;
+extern char pref_tmp_value[8];
+extern bool_ item_tester_full;
+extern byte item_tester_tval;
+extern bool_ (*item_tester_hook)(object_type *o_ptr);
+extern bool_ (*ang_sort_comp)(vptr u, vptr v, int a, int b);
+extern void (*ang_sort_swap)(vptr u, vptr v, int a, int b);
+extern bool_ (*get_mon_num_hook)(int r_idx);
+extern bool_ (*get_mon_num2_hook)(int r_idx);
+extern bool_ (*get_obj_num_hook)(int k_idx);
+extern bool_ monk_armour_aux;
+extern bool_ monk_notify_aux;
+extern u16b max_wild_x;
+extern u16b max_wild_y;
+extern wilderness_map **wild_map;
+extern u16b old_max_s_idx;
+extern u16b max_ab_idx;
+extern u16b max_s_idx;
+extern u16b max_al_idx;
+extern u16b max_r_idx;
+extern u16b max_re_idx;
+extern u16b max_k_idx;
+extern u16b max_v_idx;
+extern u16b max_f_idx;
+extern u16b max_a_idx;
+extern u16b max_e_idx;
+extern u16b max_ra_idx;
+extern u16b max_d_idx;
+extern u16b max_o_idx;
+extern u16b max_m_idx;
+extern u16b max_t_idx;
+extern u16b max_rp_idx;
+extern u16b max_c_idx;
+extern u16b max_mc_idx;
+extern u16b max_rmp_idx;
+extern u16b max_st_idx;
+extern u16b max_ba_idx;
+extern u16b max_ow_idx;
+extern u16b max_wf_idx;
+extern s16b max_set_idx;
+extern int init_flags;
+extern bool_ ambush_flag;
+extern bool_ fate_flag;
+extern s16b no_breeds;
+extern bool_ carried_monster_hit;
+extern random_artifact random_artifacts[MAX_RANDARTS];
+extern s32b RANDART_WEAPON;
+extern s32b RANDART_ARMOR;
+extern s32b RANDART_JEWEL;
+extern s16b bounties[MAX_BOUNTIES][2];
+extern random_spell random_spells[MAX_SPELLS];
+extern s16b spell_num;
+extern rune_spell rune_spells[MAX_RUNES];
+extern s16b rune_num;
+extern fate fates[MAX_FATES];
+extern byte dungeon_type;
+extern s16b *max_dlv;
+extern u32b total_bounties;
+extern s16b doppleganger;
+extern bool_ generate_encounter;
+extern bool_ autoroll;
+extern bool_ point_based;
+extern bool_ maximize, preserve, special_lvls, ironman_rooms;
+extern bool_ inventory_no_move;
+extern bool_ take_notes, auto_notes;
+extern bool_ *m_allow_special;
+extern bool_ *k_allow_special;
+extern bool_ *a_allow_special;
+extern bool_ rand_birth;
+extern bool_ fast_autoroller;
+extern bool_ joke_monsters;
+extern bool_ munchkin_multipliers;
+extern bool_ center_player;
+extern s16b plots[MAX_PLOTS];
+extern random_quest random_quests[MAX_RANDOM_QUEST];
+extern bool_ exp_need;
+extern bool_ autoload_old_colors;
+extern bool_ fate_option;
+extern bool_ *special_lvl[MAX_DUNGEON_DEPTH];
+extern bool_ generate_special_feeling;
+extern bool_ auto_more;
+extern u32b dungeon_flags1;
+extern u32b dungeon_flags2;
+extern birther previous_char;
+extern hist_type *bg;
+extern int max_bg_idx;
+extern power_type *powers_type;
+extern s16b power_max;
+extern s32b extra_savefile_parts;
+extern s16b max_q_idx;
+extern quest_type *quest;
+extern bool_ player_char_health;
+extern s16b max_spells;
+extern spell_type *school_spells;
+extern s16b max_schools;
+extern school_type *schools;
+extern int project_time;
+extern s32b project_time_effect;
+extern effect_type effects[MAX_EFFECTS];
+extern char gen_skill_basem[MAX_SKILLS];
+extern u32b gen_skill_base[MAX_SKILLS];
+extern char gen_skill_modm[MAX_SKILLS];
+extern s16b gen_skill_mod[MAX_SKILLS];
+extern bool_ linear_stats;
+extern int max_bact;
+extern s16b max_corruptions;
+extern bool_ option_ingame_help;
+extern bool_ automatizer_enabled;
+extern s16b last_teleportation_y;
+extern s16b last_teleportation_x;
+extern cptr game_module;
+extern s32b VERSION_MAJOR;
+extern s32b VERSION_MINOR;
+extern s32b VERSION_PATCH;
+extern s32b max_plev;
+extern s32b DUNGEON_DEATH;
+extern deity_type *deity_info;
+extern s32b max_gods;
+extern timer_type *gl_timers;
+extern const char *get_version_string();
+
+/* plots.c */
+extern FILE *hook_file;
+extern bool_ check_hook(int h_idx);
+extern void wipe_hooks(void);
+extern void dump_hooks(int h_idx);
+extern void init_hooks(void);
+extern hooks_chain* add_hook(int h_idx, hook_type hook, cptr name);
+extern void add_hook_script(int h_idx, char *script, cptr name);
+extern void del_hook(int h_idx, hook_type hook);
+extern void del_hook_name(int h_idx, cptr name);
+extern s32b get_next_arg(char *fmt);
+extern int process_hooks_restart;
+extern hook_return process_hooks_return[20];
+extern bool_ process_hooks_ret(int h_idx, char *ret, char *fmt, ...);
+extern bool_ process_hooks(int h_idx, char *fmt, ...);
+
+/* help.c */
+extern void ingame_help(bool_ enable);
+
+/* birth.c */
+extern void print_desc_aux(cptr txt, int y, int x);
+extern void save_savefile_names(void);
+extern bool_ no_begin_screen;
+extern bool_ begin_screen(void);
+extern errr init_randart(void);
+extern void get_height_weight(void);
+extern void player_birth(void);
+
+/* cave.c */
+extern int distance(int y1, int x1, int y2, int x2);
+extern bool_ los(int y1, int x1, int y2, int x2);
+extern bool_ cave_valid_bold(int y, int x);
+extern bool_ no_lite(void);
+extern void map_info(int y, int x, byte *ap, char *cp, byte *tap, char *tcp, byte *eap, char *ecp);
+extern void map_info_default(int y, int x, byte *ap, char *cp);
+extern void move_cursor_relative(int row, int col);
+extern void print_rel(char c, byte a, int y, int x);
+extern void note_spot(int y, int x);
+extern void lite_spot(int y, int x);
+extern void prt_map(void);
+extern void display_map(int *cy, int *cx);
+extern void do_cmd_view_map(void);
+extern errr vinfo_init(void);
+extern void forget_view(void);
+extern void update_view(void);
+extern void forget_mon_lite(void);
+extern void update_mon_lite(void);
+extern void forget_flow(void);
+extern void update_flow(void);
+extern void map_area(void);
+extern void wiz_lite(void);
+extern void wiz_lite_extra(void);
+extern void wiz_dark(void);
+extern void cave_set_feat(int y, int x, int feat);
+extern void place_floor(int y, int x);
+extern void place_floor_convert_glass(int y, int x);
+extern void place_filler(int y, int x);
+extern void mmove2(int *y, int *x, int y1, int x1, int y2, int x2);
+extern bool_ projectable(int y1, int x1, int y2, int x2);
+extern void scatter(int *yp, int *xp, int y, int x, int d);
+extern void health_track(int m_idx);
+extern void monster_race_track(int r_idx, int ego);
+extern void object_track(object_type *o_ptr);
+extern void disturb(int stop_search, int flush_output);
+extern int is_quest(int level);
+extern int random_quest_number(void);
+extern int new_effect(int type, int dam, int time, int cy, int cx, int rad, s32b flags);
+
+/* cmovie.c */
+extern void cmovie_init_second(void);
+extern s16b do_play_cmovie(cptr cmov_file);
+extern void do_record_cmovie(cptr cmovie);
+extern void do_stop_cmovie(void);
+extern void do_start_cmovie(void);
+extern void cmovie_clean_line(int y, char *abuf, char *cbuf);
+extern void cmovie_record_line(int y);
+extern void do_cmovie_insert(void);
+
+/* cmd1.c */
+extern void attack_special(monster_type *m_ptr, s32b special, int dam);
+extern bool_ test_hit_fire(int chance, int ac, int vis);
+extern bool_ test_hit_norm(int chance, int ac, int vis);
+extern s16b critical_shot(int weight, int plus, int dam, int skill);
+extern s16b critical_norm(int weight, int plus, int dam, int weapon_tval, bool_ *done_crit);
+extern s16b tot_dam_aux(object_type *o_ptr, int tdam, monster_type *m_ptr, s32b *special);
+extern void search(void);
+extern void carry(int pickup);
+extern void py_attack(int y, int x, int max_blow);
+extern bool_ player_can_enter(byte feature);
+extern void move_player(int dir, int do_pickup, bool_ disarm);
+extern void move_player_aux(int dir, int do_pickup, int run, bool_ disarm);
+extern void run_step(int dir);
+extern void step_effects(int y, int x, int do_pickup);
+extern void do_cmd_pet(void);
+extern bool_ do_cmd_integrate_body(void);
+extern bool_ do_cmd_leave_body(bool_ drop_body);
+extern bool_ execute_inscription(byte i, byte y, byte x);
+extern void do_cmd_engrave(void);
+extern void do_spin(void);
+
+/* cmd2.c */
+extern byte show_monster_inven(int m_idx, int *monst_list);
+extern int breakage_chance(object_type *o_ptr);
+extern void do_cmd_go_up(void);
+extern void do_cmd_go_down(void);
+extern void do_cmd_search(void);
+extern void do_cmd_toggle_search(void);
+extern void do_cmd_open(void);
+extern void do_cmd_close(void);
+extern void do_cmd_chat(void);
+extern void do_cmd_give(void);
+extern bool_ do_cmd_tunnel_aux(int y, int x, int dir);
+extern void do_cmd_tunnel(void);
+extern void do_cmd_disarm(void);
+extern void do_cmd_disarm(void);
+extern void do_cmd_bash(void);
+extern void do_cmd_alter(void);
+extern void do_cmd_spike(void);
+extern void do_cmd_walk(int pickup, bool_ disarm);
+extern void do_cmd_stay(int pickup);
+extern void do_cmd_run(void);
+extern void do_cmd_rest(void);
+extern int get_shooter_mult(object_type *o_ptr);
+extern void do_cmd_fire(void);
+extern void do_cmd_throw(void);
+extern void do_cmd_boomerang(void);
+extern void do_cmd_unwalk(void);
+extern void do_cmd_immovable_special(void);
+extern void fetch(int dir, int wgt, bool_ require_los);
+extern void do_cmd_sacrifice(void);
+extern void do_cmd_create_artifact(object_type *q_ptr);
+extern void do_cmd_steal(void);
+extern void do_cmd_racial_power(void);
+
+/* cmd3.c */
+extern void do_cmd_html_dump(void);
+extern void cli_add(cptr active, cptr trigger, cptr descr);
+extern void do_cmd_cli(void);
+extern void do_cmd_cli_help(void);
+extern void do_cmd_inven(void);
+extern void do_cmd_equip(void);
+extern void do_cmd_wield(void);
+extern void do_cmd_takeoff(void);
+extern void do_cmd_drop(void);
+extern void do_cmd_destroy(void);
+extern void do_cmd_observe(void);
+extern void do_cmd_uninscribe(void);
+extern void do_cmd_inscribe(void);
+extern void do_cmd_refill(void);
+extern void do_cmd_target(void);
+extern void do_cmd_look(void);
+extern void do_cmd_locate(void);
+extern void do_cmd_query_symbol(void);
+extern bool_ do_cmd_sense_grid_mana(void);
+extern bool_ research_mon(void);
+extern s32b portable_hole_weight(void);
+extern void set_portable_hole_weight(void);
+extern void do_cmd_portable_hole(void);
+
+/* cmd4.c */
+extern bool_ change_option(cptr name, bool_ value);
+extern void macro_recorder_start(void);
+extern void macro_recorder_add(char c);
+extern void macro_recorder_stop(void);
+extern void do_cmd_macro_recorder(void);
+extern void do_cmd_redraw(void);
+extern void do_cmd_change_name(void);
+extern void do_cmd_message_one(void);
+extern void do_cmd_messages(void);
+extern void do_cmd_options(void);
+extern void do_cmd_pref(void);
+extern void do_cmd_macros(void);
+extern void do_cmd_visuals(void);
+extern void do_cmd_colors(void);
+extern void do_cmd_note(void);
+extern void do_cmd_version(void);
+extern void do_cmd_feeling(void);
+extern void do_cmd_load_screen(void);
+extern void do_cmd_save_screen(void);
+extern void do_cmd_knowledge(void);
+extern void plural_aux(char * Name);
+extern void do_cmd_checkquest(void);
+extern void do_cmd_change_tactic(int i);
+extern void do_cmd_change_movement(int i);
+extern void do_cmd_time(void);
+extern void do_cmd_options_aux(int page, cptr info, bool_ read_only);
+
+
+/* cmd5.c */
+extern bool_ is_magestaff(void);
+extern void calc_magic_bonus(void);
+extern void do_cmd_browse_aux(object_type *o_ptr);
+extern void do_cmd_browse(void);
+extern void do_cmd_cast(void);
+extern void do_cmd_pray(void);
+extern void do_cmd_rerate(void);
+extern void corrupt_player(void);
+extern bool_ item_tester_hook_armour(object_type *o_ptr);
+extern void fetch(int dir, int wgt, bool_ require_los);
+extern void do_poly_self(void);
+extern void brand_weapon(int brand_type);
+extern cptr symbiote_name(bool_ capitalize);
+extern int use_symbiotic_power(int r_idx, bool_ great, bool_ only_number, bool_ no_cost);
+extern s32b get_school_spell(cptr do_what, cptr check_fct, s16b force_book);
+extern void do_cmd_copy_spell(void);
+extern void cast_school_spell(void);
+extern void browse_school_spell(int book, int pval, object_type *o_ptr);
+extern int find_spell(char *name);
+extern bool_ is_school_book(object_type *o_ptr);
+
+/* cmd6.c */
+extern void set_stick_mode(object_type *o_ptr);
+extern void unset_stick_mode(void);
+extern void do_cmd_eat_food(void);
+extern void do_cmd_quaff_potion(void);
+extern void do_cmd_read_scroll(void);
+extern void do_cmd_aim_wand(void);
+extern void do_cmd_use_staff(void);
+extern void do_cmd_zap_rod(void);
+extern const char *activation_aux(object_type *o_ptr, bool_ desc, int item);
+extern void do_cmd_activate(void);
+extern void do_cmd_rerate(void);
+extern void do_cmd_cut_corpse(void);
+extern void do_cmd_cure_meat(void);
+extern void do_cmd_drink_fountain(void);
+extern void do_cmd_fill_bottle(void);
+
+/* cmd7.c */
+extern void do_cmd_create_boulder(void);
+extern int rune_exec(rune_spell *spell, int cost);
+extern void necro_info(char *p, int power);
+extern void mindcraft_info(char *p, int power);
+extern void symbiotic_info(char *p, int power);
+extern void mimic_info(char *p, int power);
+extern random_spell* select_spell(bool_ quick);
+extern void cast_magic_spell(int spell, byte level);
+extern void do_cmd_summoner(void);
+extern void do_cmd_mindcraft(void);
+extern void do_cmd_mimic(void);
+extern void do_cmd_blade(void);
+extern void use_ability_blade(void);
+extern bool_ alchemist_exists(int tval, int sval, int ego, int artifact);
+extern void rod_tip_extract(object_type *o_ptr);
+extern void do_cmd_toggle_artifact(object_type *o_ptr);
+extern bool_ alchemist_items_check(int tval, int sval, int ego, int tocreate, bool_ message);
+extern void alchemist_display_recipe(int tval, int sval, int ego);
+extern void alchemist_recipe_book(void);
+extern int alchemist_recipe_select(int *tval, int sval, int ego, bool_ recipe);
+extern int alchemist_learn_object(object_type *o_ptr);
+extern void alchemist_gain_level(int lev);
+extern void do_cmd_alchemist(void);
+extern void do_cmd_beastmaster(void);
+extern void do_cmd_powermage(void);
+extern void do_cmd_possessor(void);
+extern void do_cmd_archer(void);
+extern void do_cmd_set_piercing(void);
+extern void do_cmd_necromancer(void);
+extern void do_cmd_unbeliever(void);
+extern void cast_daemon_spell(int spell, byte level);
+extern void do_cmd_unbeliever(void);
+extern void do_cmd_runecrafter(void);
+extern void do_cmd_symbiotic(void);
+extern s32b sroot(s32b n);
+extern int clamp_failure_chance(int chance, int minfail);
+
+/* dungeon.c */
+extern byte value_check_aux1(object_type *o_ptr);
+extern byte value_check_aux1_magic(object_type *o_ptr);
+extern byte value_check_aux2(object_type *o_ptr);
+extern byte value_check_aux2_magic(object_type *o_ptr);
+extern void play_game(bool_ new_game);
+extern void sense_inventory();
+
+/* files.c */
+extern void html_screenshot(cptr name);
+extern void help_file_screenshot(cptr name);
+extern void player_flags(u32b* f1, u32b* f2, u32b* f3, u32b* f4, u32b* f5, u32b* esp);
+extern void wipe_saved(void);
+extern s16b tokenize(char *buf, s16b num, char **tokens, char delim1, char delim2);
+extern void display_player(int mode);
+extern cptr describe_player_location(void);
+extern errr file_character(cptr name, bool_ full);
+extern errr process_pref_file_aux(char *buf);
+extern errr process_pref_file(cptr name);
+extern void read_times(void);
+extern bool_ txt_to_html(cptr head, cptr food, cptr base, cptr ext, bool_ force, bool_ recur);
+extern bool_ show_file(cptr name, cptr what, int line, int mode);
+extern void do_cmd_help(void);
+extern void process_player_base(void);
+extern void process_player_name(bool_ sf);
+extern void get_name(void);
+extern void do_cmd_suicide(void);
+extern void do_cmd_save_game(void);
+extern void autosave_checkpoint();
+extern long total_points(void);
+extern void display_scores(int from, int to);
+extern errr predict_score(void);
+extern void close_game(void);
+extern void signals_ignore_tstp(void);
+extern void signals_handle_tstp(void);
+extern void signals_init(void);
+extern errr get_rnd_line(char * file_name, char * output);
+extern char *get_line(char* fname, cptr fdir, char *linbuf, int line);
+extern void do_cmd_knowledge_corruptions(void);
+extern void race_legends(void);
+extern void show_highclass(int building);
+extern errr get_xtra_line(char * file_name, monster_type *m_ptr, char * output);
+
+/* gen_maze.c */
+extern bool_ level_generate_maze();
+
+/* gen_life.c */
+extern bool_ level_generate_life();
+extern void evolve_level(bool_ noise);
+
+/* generate.c */
+extern bool_ new_player_spot(int branch);
+extern void add_level_generator(cptr name, bool_ (*generator)(), bool_ stairs, bool_ monsters, bool_ objects, bool_ miscs);
+extern bool_ level_generate_dungeon();
+extern bool_ generate_fracave(int y0, int x0,int xsize,int ysize,int cutoff,bool_ light,bool_ room);
+extern void generate_hmap(int y0, int x0,int xsiz,int ysiz,int grd,int roug,int cutoff);
+extern bool_ room_alloc(int x,int y,bool_ crowded,int by0,int bx0,int *xx,int *yy);
+extern void generate_grid_mana(void);
+extern byte calc_dungeon_type(void);
+extern void generate_cave(void);
+extern void build_rectangle(int y1, int x1, int y2, int x2, int feat, int info);
+
+
+/* wild.c */
+extern int generate_area(int y, int x, bool_ border, bool_ corner, bool_ refresh);
+extern void wilderness_gen(int refresh);
+extern void wilderness_gen_small(void);
+extern void reveal_wilderness_around_player(int y, int x, int h, int w);
+extern void town_gen(int t_idx);
+
+
+/* init1.c */
+extern int color_char_to_attr(char c);
+extern byte conv_color[16];
+extern errr init_player_info_txt(FILE *fp, char *buf);
+extern errr init_ab_info_txt(FILE *fp, char *buf);
+extern errr init_s_info_txt(FILE *fp, char *buf);
+extern errr init_set_info_txt(FILE *fp, char *buf);
+extern errr init_v_info_txt(FILE *fp, char *buf, bool_ start);
+extern errr init_f_info_txt(FILE *fp, char *buf);
+extern errr init_k_info_txt(FILE *fp, char *buf);
+extern errr init_a_info_txt(FILE *fp, char *buf);
+extern errr init_al_info_txt(FILE *fp, char *buf);
+extern errr init_ra_info_txt(FILE *fp, char *buf);
+extern errr init_e_info_txt(FILE *fp, char *buf);
+extern errr init_r_info_txt(FILE *fp, char *buf);
+extern errr init_re_info_txt(FILE *fp, char *buf);
+extern errr grab_one_dungeon_flag(u32b *flags1, u32b *flags2, cptr what);
+extern errr init_d_info_txt(FILE *fp, char *buf);
+extern errr init_t_info_txt(FILE *fp, char *buf);
+extern errr init_ba_info_txt(FILE *fp, char *buf);
+extern errr init_st_info_txt(FILE *fp, char *buf);
+extern errr init_ow_info_txt(FILE *fp, char *buf);
+extern errr init_wf_info_txt(FILE *fp, char *buf);
+extern errr process_dungeon_file(cptr name, int *yval, int *xval, int ymax, int xmax, bool_ init, bool_ full);
+
+/* init2.c */
+extern void init_corruptions(s16b new_size);
+extern void init_spells(s16b new_size);
+extern void init_schools(s16b new_size);
+extern void reinit_gods(s16b new_size);
+extern void reinit_quests(s16b new_size);
+extern void reinit_powers_type(s16b new_size);
+extern void create_stores_stock(int t);
+extern errr init_v_info(void);
+extern void init_file_paths(char *path);
+extern void init_angband(void);
+extern errr init_buildings(void);
+extern s16b error_idx;
+extern s16b error_line;
+extern u32b fake_name_size;
+extern u32b fake_text_size;
+
+/* loadsave.c */
+extern void register_savefile(int num);
+extern bool_ file_exist(char *buf);
+extern s16b rd_variable(void);
+extern void wr_variable(s16b *var);
+extern void wr_scripts(void);
+extern bool_ load_dungeon(char *ext);
+extern void save_dungeon(void);
+extern bool_ save_player(void);
+extern bool_ load_player(void);
+extern errr rd_savefile_new(void);
+extern void load_number_key(char *key, u32b *val);
+extern void save_number_key(char *key, u32b val);
+
+/* melee1.c */
+/* melee2.c */
+extern int monst_spell_monst_spell;
+extern bool_ mon_take_hit_mon(int s_idx, int m_idx, int dam, bool_ *fear, cptr note);
+extern int check_hit2(int power, int level, int ac);
+extern int get_attack_power(int effect);
+extern bool_ carried_make_attack_normal(int r_idx);
+extern bool_ make_attack_normal(int m_idx, byte divis);
+extern bool_ make_attack_spell(int m_idx);
+extern void process_monsters(void);
+extern void curse_equipment(int chance, int heavy_chance);
+extern void curse_equipment_dg(int chance, int heavy_chance);
+
+/* monster1.c */
+extern void screen_roff(int r_idx, int ego, int remember);
+extern void display_roff(int r_idx, int ego);
+extern void monster_description_out(int r_idx, int ego);
+
+/* monster2.c */
+extern void monster_set_level(int m_idx, int level);
+extern s32b modify_aux(s32b a, s32b b, char mod);
+extern void monster_msg(cptr fmt, ...);
+extern void cmonster_msg(char a, cptr fmt, ...);
+extern bool_ mego_ok(int r_idx, int ego);
+extern void monster_check_experience(int m_idx, bool_ silent);
+extern void monster_gain_exp(int m_idx, u32b exp, bool_ silent);
+extern monster_race* race_info_idx(int r_idx, int ego);
+extern int get_wilderness_flag(void);
+extern void sanity_blast(monster_type * m_ptr, bool_ necro);
+extern void delete_monster_idx(int i);
+extern void delete_monster(int y, int x);
+extern void compact_monsters(int size);
+extern void wipe_m_list(void);
+extern s16b m_pop(void);
+extern errr get_mon_num_prep(void);
+extern s16b get_mon_num(int level);
+extern void monster_desc(char *desc, monster_type *m_ptr, int mode);
+extern void monster_race_desc(char *desc, int r_idx, int ego);
+extern void lore_do_probe(int m_idx);
+extern void lore_treasure(int m_idx, int num_item, int num_gold);
+extern void update_mon(int m_idx, bool_ full);
+extern void update_monsters(bool_ full);
+extern void monster_carry(monster_type *m_ptr, int m_idx, object_type *q_ptr);
+extern bool_ bypass_r_ptr_max_num ;
+extern bool_ place_monster_aux(int y, int x, int r_idx, bool_ slp, bool_ grp, int status);
+extern bool_ place_monster(int y, int x, bool_ slp, bool_ grp);
+extern bool_ alloc_horde(int y, int x);
+extern bool_ alloc_monster(int dis, bool_ slp);
+extern bool_ summon_specific_okay(int r_idx);
+extern int summon_specific_level;
+extern bool_ summon_specific(int y1, int x1, int lev, int type);
+extern void monster_swap(int y1, int x1, int y2, int x2);
+extern bool_ multiply_monster(int m_idx, bool_ charm, bool_ clone);
+extern bool_ hack_message_pain_may_silent;
+extern void message_pain(int m_idx, int dam);
+extern void update_smart_learn(int m_idx, int what);
+extern bool_ summon_specific_friendly(int y1, int x1, int lev, int type, bool_ Group_ok);
+extern bool_ place_monster_one_no_drop;
+extern monster_race *place_monster_one_race;
+extern s16b place_monster_one(int y, int x, int r_idx, int ego, bool_ slp, int status);
+extern s16b player_place(int y, int x);
+extern void monster_drop_carried_objects(monster_type *m_ptr);
+extern bool_ monster_dungeon(int r_idx);
+extern bool_ monster_quest(int r_idx);
+extern bool_ monster_ocean(int r_idx);
+extern bool_ monster_shore(int r_idx);
+extern bool_ monster_town(int r_idx);
+extern bool_ monster_wood(int r_idx);
+extern bool_ monster_volcano(int r_idx);
+extern bool_ monster_mountain(int r_idx);
+extern bool_ monster_grass(int r_idx);
+extern bool_ monster_deep_water(int r_idx);
+extern bool_ monster_shallow_water(int r_idx);
+extern bool_ monster_lava(int r_idx);
+extern void set_mon_num_hook(void);
+extern void set_mon_num2_hook(int y, int x);
+extern bool_ monster_can_cross_terrain(byte feat, monster_race *r_ptr);
+extern void corrupt_corrupted(void);
+
+/* monster3.c */
+extern void dump_companions(FILE *outfile);
+extern void do_cmd_companion(void);
+extern bool_ do_control_reconnect(void);
+extern bool_ do_control_drop(void);
+extern bool_ do_control_magic(void);
+extern bool_ do_control_pickup(void);
+extern bool_ do_control_inven(void);
+extern bool_ do_control_walk(void);
+extern bool_ can_create_companion(void);
+extern void ai_deincarnate(int m_idx);
+extern bool_ ai_possessor(int m_idx, int o_idx);
+extern bool_ ai_multiply(int m_idx);
+extern bool_ change_side(monster_type *m_ptr);
+extern int is_friend(monster_type *m_ptr);
+extern bool_ is_enemy(monster_type *m_ptr, monster_type *t_ptr);
+
+/* object1.c */
+/* object2.c */
+extern byte get_item_letter_color(object_type *o_ptr);
+extern void describe_device(object_type *o_ptr);
+extern void inc_stack_size(int item, int delta);
+extern void inc_stack_size_ex(int item, int delta, optimize_flag opt, describe_flag desc);
+extern void object_pickup(int this_o_idx);
+extern int get_slot(int slot);
+extern bool_ apply_flags_set(s16b a_idx, s16b set_idx, u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp);
+extern bool_ apply_set(s16b a_idx, s16b set_idx);
+extern bool_ takeoff_set(s16b a_idx, s16b set_idx);
+extern bool_ wield_set(s16b a_idx, s16b set_idx, bool_ silent);
+extern object_type *get_object(int item);
+extern s32b calc_total_weight(void);
+extern void add_random_ego_flag(object_type *o_ptr, int fego, bool_ *limit_blows);
+extern bool_ info_spell;
+extern char spell_txt[50];
+extern bool_ grab_tval_desc(int tval);
+extern void init_match_theme(obj_theme theme);
+extern bool_ kind_is_artifactable(int k_idx);
+extern bool_ kind_is_good(int k_idx);
+extern int kind_is_legal_special;
+extern bool_ kind_is_legal(int k_idx);
+extern bool_ verify(cptr prompt, int item);
+extern void flavor_init(void);
+extern void reset_visuals(void);
+extern int object_power(object_type *o_ptr);
+extern bool_ object_flags_no_set;
+extern void object_flags(object_type *o_ptr, u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp);
+extern void object_flags_known(object_type *o_ptr, u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp);
+extern void object_desc(char *buf, object_type *o_ptr, int pref, int mode);
+extern void object_desc_store(char *buf, object_type *o_ptr, int pref, int mode);
+extern bool_ object_out_desc(object_type *o_ptr, FILE *fff, bool_ trim_down, bool_ wait_for_it);
+extern char index_to_label(int i);
+extern s16b label_to_inven(int c);
+extern s16b label_to_equip(int c);
+extern s16b wield_slot_ideal(object_type *o_ptr, bool_ ideal);
+extern s16b wield_slot(object_type *o_ptr);
+extern cptr mention_use(int i);
+extern cptr describe_use(int i);
+extern void inven_item_charges(int item);
+extern void inven_item_describe(int item);
+extern void inven_item_increase(int item, int num);
+extern bool_ inven_item_optimize(int item);
+extern void floor_item_charges(int item);
+extern void floor_item_describe(int item);
+extern void floor_item_increase(int item, int num);
+extern void floor_item_optimize(int item);
+extern bool_ inven_carry_okay(object_type *o_ptr);
+extern s16b inven_carry(object_type *o_ptr, bool_ final);
+extern s16b inven_takeoff(int item, int amt, bool_ force_drop);
+extern void inven_drop(int item, int amt, int dy, int dx, bool_ silent);
+extern bool_ item_tester_okay(object_type *o_ptr);
+extern void display_inven(void);
+extern void display_equip(void);
+extern void show_inven();
+extern void show_equip();
+extern void toggle_inven_equip(void);
+extern bool_ (*get_item_extra_hook)(int *cp);
+extern bool_ get_item(int *cp, cptr pmt, cptr str, int mode);
+extern void excise_object_idx(int o_idx);
+extern void delete_object_idx(int o_idx);
+extern void delete_object(int y, int x);
+extern void compact_objects(int size);
+extern void wipe_o_list(void);
+extern s16b o_pop(void);
+extern errr get_obj_num_prep(void);
+extern s16b get_obj_num(int level);
+extern void object_known(object_type *o_ptr);
+extern void object_aware(object_type *o_ptr);
+extern void object_tried(object_type *o_ptr);
+extern s32b object_value(object_type *o_ptr);
+extern s32b object_value_real(object_type *o_ptr);
+extern bool_ object_similar(object_type *o_ptr, object_type *j_ptr);
+extern void object_absorb(object_type *o_ptr, object_type *j_ptr);
+extern s16b lookup_kind(int tval, int sval);
+extern void object_wipe(object_type *o_ptr);
+extern void object_prep(object_type *o_ptr, int k_idx);
+extern void object_copy(object_type *o_ptr, object_type *j_ptr);
+extern int hack_apply_magic_power;
+extern void apply_magic(object_type *o_ptr, int lev, bool_ okay, bool_ good, bool_ great);
+extern bool_ make_object(object_type *j_ptr, bool_ good, bool_ great, obj_theme theme);
+extern void place_object(int y, int x, bool_ good, bool_ great, int where);
+extern bool_ make_gold(object_type *j_ptr);
+extern void place_gold(int y, int x);
+extern void process_objects(void);
+extern s16b drop_near(object_type *o_ptr, int chance, int y, int x);
+extern void acquirement(int y1, int x1, int num, bool_ great, bool_ known);
+extern void pick_trap(int y, int x);
+extern cptr item_activation(object_type *o_ptr,byte num);
+extern void combine_pack(void);
+extern void reorder_pack(void);
+extern void display_koff(int k_idx);
+extern void random_artifact_resistance (object_type * o_ptr);
+extern void random_resistance (object_type * o_ptr, bool_ is_scroll, int specific);
+extern s16b floor_carry(int y, int x, object_type *j_ptr);
+extern void pack_decay(int item);
+extern void floor_decay(int item);
+extern bool_ scan_floor(int *items, int *item_num, int y, int x, int mode);
+extern void show_floor(int y, int x);
+extern bool_ get_item_floor(int *cp, cptr pmt, cptr str, int mode);
+extern void py_pickup_floor(int pickup);
+extern s16b m_bonus(int max, int level);
+extern void object_gain_level(object_type *o_ptr);
+extern void gain_flag_group_flag(object_type *o_ptr, bool_ silent);
+extern void gain_flag_group(object_type *o_ptr, bool_ silent);
+extern void get_table_name(char * out_string);
+extern s32b flag_cost(object_type * o_ptr, int plusses);
+
+/* powers.c */
+extern void do_cmd_power(void);
+
+/* traps.c */
+extern bool_ player_activate_trap_type(s16b y, s16b x, object_type *i_ptr, s16b item);
+extern void player_activate_door_trap(s16b y, s16b x);
+extern void place_trap(int y, int x);
+extern void place_trap_object(object_type *o_ptr);
+extern void wiz_place_trap(int y, int x, int idx);
+extern void do_cmd_set_trap(void);
+extern bool_ mon_hit_trap(int);
+
+/* spells1.c */
+extern byte spell_color(int type);
+extern s16b poly_r_idx(int r_idx);
+extern void get_pos_player(int dis, int *ny, int *nx);
+extern bool_ teleport_player_bypass;
+extern void teleport_to_player(int m_idx);
+extern void teleport_player_directed(int rad, int dir);
+extern void teleport_away(int m_idx, int dis);
+extern void teleport_player(int dis);
+extern void teleport_player_to(int ny, int nx);
+extern void teleport_monster_to(int m_idx, int ny, int nx);
+extern void teleport_player_level(void);
+extern void recall_player(int d, int f);
+extern void take_hit(int damage, cptr kb_str);
+extern void take_sanity_hit(int damage, cptr hit_from);
+extern void acid_dam(int dam, cptr kb_str);
+extern void elec_dam(int dam, cptr kb_str);
+extern void fire_dam(int dam, cptr kb_str);
+extern void cold_dam(int dam, cptr kb_str);
+extern bool_ inc_stat(int stat);
+extern bool_ dec_stat(int stat, int amount, int mode);
+extern bool_ res_stat(int stat, bool_ full);
+extern bool_ apply_disenchant(int mode);
+extern bool_ project_m(int who, int r, int y, int x, int dam, int typ);
+extern sint project_path(u16b *gp, int range, int y1, int x1, int y2, int x2, int flg);
+extern bool_ project(int who, int rad, int y, int x, int dam, int typ, int flg);
+extern bool_ potion_smash_effect(int who, int y, int x, int o_sval);
+extern void do_poly_self(void);
+extern void corrupt_player(void);
+extern void generate_spell(int plev);
+extern bool_ unsafe;
+extern void describe_attack_fully(int type, char* r);
+extern s16b do_poly_monster(int y, int x);
+
+
+/* spells2.c */
+extern bool_ remove_curse_object(object_type *o_ptr, bool_ all);
+extern void curse_artifact(object_type * o_ptr);
+extern void grow_things(s16b type, int rad);
+extern void grow_grass(int rad);
+extern void grow_trees(int rad);
+extern bool_ hp_player(int num);
+extern bool_ heal_insanity(int val);
+extern void warding_glyph(void);
+extern void explosive_rune(void);
+extern bool_ do_dec_stat(int stat, int mode);
+extern bool_ do_res_stat(int stat, bool_ full);
+extern bool_ do_inc_stat(int stat);
+extern void identify_pack(void);
+extern void identify_pack_fully(void);
+extern bool_ remove_curse(void);
+extern bool_ remove_all_curse(void);
+extern bool_ restore_level(void);
+extern void self_knowledge(FILE *fff);
+extern bool_ lose_all_info(void);
+extern bool_ detect_traps(int rad);
+extern bool_ detect_doors(int rad);
+extern bool_ detect_stairs(int rad);
+extern bool_ detect_treasure(int rad);
+extern bool_ hack_no_detect_message;
+extern bool_ detect_objects_gold(int rad);
+extern bool_ detect_objects_normal(int rad);
+extern bool_ detect_objects_magic(int rad);
+extern bool_ detect_monsters_normal(int rad);
+extern bool_ detect_monsters_invis(int rad);
+extern bool_ detect_monsters_evil(int rad);
+extern bool_ detect_monsters_good(int rad);
+extern bool_ detect_monsters_xxx(u32b match_flag, int rad);
+extern bool_ detect_monsters_string(cptr chars, int rad);
+extern bool_ detect_monsters_nonliving(int rad);
+extern bool_ detect_all(int rad);
+extern void stair_creation(void);
+extern bool_ wall_stone(int y, int x);
+extern bool_ enchant(object_type *o_ptr, int n, int eflag);
+extern bool_ enchant_spell(int num_hit, int num_dam, int num_ac, int num_pval);
+extern bool_ ident_spell(void);
+extern bool_ ident_all(void);
+extern bool_ identify_fully(void);
+extern bool_ recharge(int num);
+extern bool_ speed_monsters(void);
+extern bool_ slow_monsters(void);
+extern bool_ sleep_monsters(void);
+extern bool_ conf_monsters(void);
+extern void aggravate_monsters(int who);
+extern bool_ genocide_aux(bool_ player_cast, char typ);
+extern bool_ genocide(bool_ player_cast);
+extern bool_ mass_genocide(bool_ player_cast);
+extern void do_probe(int m_idx);
+extern bool_ probing(void);
+extern void change_wild_mode(void);
+extern bool_ banish_evil(int dist);
+extern bool_ dispel_evil(int dam);
+extern bool_ dispel_good(int dam);
+extern bool_ dispel_undead(int dam);
+extern bool_ dispel_monsters(int dam);
+extern bool_ dispel_living(int dam);
+extern bool_ dispel_demons(int dam);
+extern bool_ turn_undead(void);
+extern void wipe(int y1, int x1, int r);
+extern void destroy_area(int y1, int x1, int r, bool_ full, bool_ bypass);
+extern void earthquake(int cy, int cx, int r);
+extern void lite_room(int y1, int x1);
+extern void unlite_room(int y1, int x1);
+extern bool_ lite_area(int dam, int rad);
+extern bool_ unlite_area(int dam, int rad);
+extern bool_ fire_ball_beam(int typ, int dir, int dam, int rad);
+extern bool_ fire_cloud(int typ, int dir, int dam, int rad, int time);
+extern bool_ fire_wave(int typ, int dir, int dam, int rad, int time, s32b eff);
+extern bool_ fire_wall(int typ, int dir, int dam, int time);
+extern bool_ fire_ball(int typ, int dir, int dam, int rad);
+extern bool_ fire_bolt(int typ, int dir, int dam);
+extern bool_ fire_beam(int typ, int dir, int dam);
+extern bool_ fire_druid_ball(int typ, int dir, int dam, int rad);
+extern bool_ fire_druid_bolt(int typ, int dir, int dam);
+extern bool_ fire_druid_beam(int typ, int dir, int dam);
+extern void call_chaos(void);
+extern bool_ fire_bolt_or_beam(int prob, int typ, int dir, int dam);
+extern bool_ lite_line(int dir);
+extern bool_ drain_life(int dir, int dam);
+extern bool_ death_ray(int dir, int plev);
+extern bool_ wall_to_mud(int dir);
+extern bool_ destroy_door(int dir);
+extern bool_ disarm_trap(int dir);
+extern bool_ wizard_lock(int dir);
+extern bool_ heal_monster(int dir);
+extern bool_ speed_monster(int dir);
+extern bool_ slow_monster(int dir);
+extern bool_ sleep_monster(int dir);
+extern bool_ stasis_monster(int dir);
+extern bool_ confuse_monster(int dir, int plev);
+extern bool_ stun_monster(int dir, int plev);
+extern bool_ fear_monster(int dir, int plev);
+extern bool_ scare_monsters(void);
+extern bool_ poly_monster(int dir);
+extern bool_ clone_monster(int dir);
+extern bool_ teleport_monster(int dir);
+extern bool_ door_creation(void);
+extern bool_ trap_creation(void);
+extern bool_ glyph_creation(void);
+extern bool_ destroy_doors_touch(void);
+extern bool_ destroy_traps_touch(void);
+extern bool_ sleep_monsters_touch(void);
+extern bool_ alchemy(void);
+extern void activate_ty_curse(void);
+extern void activate_dg_curse(void);
+extern void activate_hi_summon(void);
+extern void summon_cyber(void);
+extern void wall_breaker(void);
+extern void bless_weapon(void);
+extern bool_ confuse_monsters(int dam);
+extern bool_ charm_monsters(int dam);
+extern bool_ charm_animals(int dam);
+extern bool_ charm_demons(int dam);
+extern bool_ stun_monsters(int dam);
+extern bool_ stasis_monsters(int dam);
+extern bool_ banish_monsters(int dist);
+extern bool_ turn_monsters(int dam);
+extern bool_ turn_evil(int dam);
+extern bool_ deathray_monsters(void);
+extern bool_ charm_monster(int dir, int plev);
+extern bool_ star_charm_monster(int dir, int plev);
+extern bool_ control_one_undead(int dir, int plev);
+extern bool_ charm_animal(int dir, int plev);
+extern bool_ mindblast_monsters(int dam);
+extern void alter_reality(void);
+extern void report_magics(void);
+extern void teleport_swap(int dir);
+extern void swap_position(int lty, int ltx);
+extern bool_ item_tester_hook_recharge(object_type *o_ptr);
+extern bool_ fire_explosion(int y, int x, int typ, int rad, int dam);
+extern bool_ fire_godly_wrath(int y, int x, int typ, int dir, int dam);
+extern bool_ invoke(int dam, int typ);
+extern bool_ project_hack(int typ, int dam);
+extern void project_meteor(int radius, int typ, int dam, u32b flg);
+extern bool_ item_tester_hook_artifactable(object_type *o_ptr);
+extern bool_ passwall(int dir, bool_ safe);
+extern bool_ project_hook(int typ, int dir, int dam, int flg);
+extern void random_misc (object_type * o_ptr, bool_ is_scroll);
+extern void random_plus(object_type * o_ptr, bool_ is_scroll);
+extern bool_ reset_recall(bool_ no_trepas_max_depth);
+extern void remove_dg_curse(void);
+
+/* randart.c */
+extern int get_activation_power(void);
+extern void build_prob(cptr learn);
+extern bool_ create_artifact(object_type *o_ptr, bool_ a_scroll, bool_ get_name);
+extern bool_ artifact_scroll(void);
+
+/* store.c */
+extern bool_ is_blessed(object_type *o_ptr);
+extern void do_cmd_store(void);
+extern void store_shuffle(int which);
+extern void store_maint(int town_num, int store_num);
+extern void store_init(int town_num, int store_num);
+extern void move_to_black_market(object_type * o_ptr);
+extern void do_cmd_home_trump(void);
+extern void store_sell(void);
+extern void store_purchase(void);
+extern void store_examine(void);
+extern void store_stole(void);
+extern void store_prt_gold(void);
+extern void store_request_item(void);
+
+/* bldg.c -KMW- */
+extern bool_ bldg_process_command(store_type *s_ptr, int i);
+extern void show_building(store_type *s_ptr);
+extern bool_ is_state(store_type *s_ptr, int state);
+extern void do_cmd_bldg(void);
+extern bool_ show_god_info(bool_ ext);
+extern void enter_quest(void);
+extern void select_bounties(void);
+
+/* util.c */
+extern void scansubdir(cptr dir);
+extern s32b rescale(s32b x, s32b max, s32b new_max);
+extern bool_ input_box(cptr text, int y, int x, char *buf, int max);
+extern void draw_box(int y, int x, int h, int w);
+extern void display_list(int y, int x, int h, int w, cptr title, cptr *list, int max, int begin, int sel, byte sel_color);
+extern s32b value_scale(int value, int vmax, int max, int min);
+extern int ask_menu(cptr ask, char **items, int max);
+extern cptr get_player_race_name(int pr, int ps);
+extern cptr get_month_name(int month, bool_ full, bool_ compact);
+extern cptr get_day(int day);
+extern s32b bst(s32b what, s32b t);
+extern errr path_parse(char *buf, int max, cptr file);
+extern errr path_temp(char *buf, int max);
+extern errr path_build(char *buf, int max, cptr path, cptr file);
+extern FILE *my_fopen(cptr file, cptr mode);
+extern errr my_fgets(FILE *fff, char *buf, huge n);
+extern errr my_fputs(FILE *fff, cptr buf, huge n);
+extern errr my_fclose(FILE *fff);
+extern errr fd_kill(cptr file);
+extern errr fd_move(cptr file, cptr what);
+extern errr fd_copy(cptr file, cptr what);
+extern int fd_make(cptr file, int mode);
+extern int fd_open(cptr file, int flags);
+extern errr fd_lock(int fd, int what);
+extern errr fd_seek(int fd, huge n);
+extern errr fd_read(int fd, char *buf, huge n);
+extern errr fd_write(int fd, cptr buf, huge n);
+extern errr fd_close(int fd);
+extern void flush(void);
+extern void bell(void);
+extern void sound(int num);
+extern void move_cursor(int row, int col);
+extern void text_to_ascii(char *buf, cptr str);
+extern void ascii_to_text(char *buf, cptr str);
+extern void keymap_init(void);
+extern errr macro_add(cptr pat, cptr act);
+extern sint macro_find_exact(cptr pat);
+extern char inkey(void);
+extern cptr quark_str(s16b num);
+extern s16b quark_add(cptr str);
+extern s16b message_num(void);
+extern cptr message_str(int age);
+extern byte message_color(int age);
+extern byte message_type(int age);
+extern void message_add(byte type, cptr msg, byte color);
+extern void display_message(int x, int y, int split, byte color, cptr t);
+extern void cmsg_print(byte color, cptr msg);
+extern void msg_print(cptr msg);
+extern void cmsg_format(byte color, cptr fmt, ...);
+extern void msg_format(cptr fmt, ...);
+extern void screen_save(void);
+extern void screen_load(void);
+extern void c_put_str(byte attr, cptr str, int row, int col);
+extern void put_str(cptr str, int row, int col);
+extern void c_prt(byte attr, cptr str, int row, int col);
+extern void prt(cptr str, int row, int col);
+extern void text_out_to_screen(byte a, cptr str);
+extern void text_out_to_file(byte a, cptr str);
+extern void text_out(cptr str);
+extern void text_out_c(byte a, cptr str);
+extern void clear_screen(void);
+extern void clear_from(int row);
+extern bool_ askfor_aux_complete;
+extern bool_ askfor_aux(char *buf, int len);
+extern bool_ get_string(cptr prompt, char *buf, int len);
+extern bool_ get_check(cptr prompt);
+extern bool_ get_com(cptr prompt, char *command);
+extern s32b get_quantity(cptr prompt, s32b max);
+extern void pause_line(int row);
+extern char request_command_ignore_keymaps[];
+extern bool_ request_command_inven_mode;
+extern void request_command(int shopping);
+extern bool_ is_a_vowel(int ch);
+extern int get_keymap_dir(char ch);
+extern byte count_bits(u32b array);
+extern void strlower(char *buf);
+extern int test_monster_name(cptr name);
+extern int test_mego_name(cptr name);
+extern int test_item_name(cptr name);
+extern char msg_box(cptr text, int y, int x);
+extern timer_type *new_timer(cptr callback, s32b delay);
+extern void del_timer(timer_type *t_ptr);
+extern int get_keymap_mode();
+
+/* main.c */
+extern bool_ private_check_user_directory(cptr dirpath);
+
+/* xtra1.c */
+extern void fix_message(void);
+extern void apply_flags(u32b f1, u32b f2, u32b f3, u32b f4, u32b f5, u32b esp, s16b pval, s16b tval, s16b to_h, s16b to_d, s16b to_a);
+extern int luck(int min, int max);
+extern int weight_limit(void);
+extern bool_ calc_powers_silent;
+extern void cnv_stat(int i, char *out_val);
+extern s16b modify_stat_value(int value, int amount);
+extern void calc_hitpoints(void);
+extern void notice_stuff(void);
+extern void update_stuff(void);
+extern void redraw_stuff(void);
+extern void window_stuff(void);
+extern void handle_stuff(void);
+extern bool_ monk_empty_hands(void);
+extern bool_ monk_heavy_armor(void);
+extern bool_ beastmaster_whip(void);
+extern void calc_bonuses(bool_ silent);
+extern void calc_sanity(void);
+extern void gain_fate(byte fate);
+extern void fate_desc(char *desc, int fate);
+extern void dump_fates(FILE *OutFile);
+
+/* xtra2.c */
+extern int resolve_mimic_name(cptr name);
+extern void do_rebirth(void);
+extern cptr get_subrace_title(int racem);
+extern void set_subrace_title(int racem, cptr name);
+extern void switch_subrace(int racem, bool_ copy_old);
+extern void switch_class(int sclass);
+extern void switch_subclass(int sclass);
+extern void drop_from_wild(void);
+extern void clean_wish_name(char *buf, char *name);
+extern bool_ test_object_wish(char *name, object_type *o_ptr, object_type *forge, char *what);
+extern bool_ set_roots(int v, s16b ac, s16b dam);
+extern bool_ set_project(int v, s16b gf, s16b dam, s16b rad, s16b flag);
+extern bool_ set_rush(int v);
+extern bool_ set_parasite(int v, int r);
+extern bool_ set_disrupt_shield(int v);
+extern bool_ set_prob_travel(int v);
+extern bool_ set_absorb_soul(int v);
+extern bool_ set_tim_breath(int v, bool_ magical);
+extern bool_ set_tim_deadly(int v);
+extern bool_ set_tim_res_time(int v);
+extern bool_ set_tim_reflect(int v);
+extern bool_ set_tim_thunder(int v, int p1, int p2);
+extern bool_ set_meditation(int v);
+extern bool_ set_strike(int v);
+extern bool_ set_walk_water(int v);
+extern bool_ set_tim_regen(int v, int p);
+extern bool_ set_tim_ffall(int v);
+extern bool_ set_tim_fly(int v);
+extern bool_ set_poison(int v);
+extern bool_ set_tim_fire_aura(int v);
+extern bool_ set_holy(int v);
+extern void set_grace(s32b v);
+extern bool_ set_mimic(int v, int p, int level);
+extern bool_ set_no_breeders(int v);
+extern bool_ set_invis(int v,int p);
+extern bool_ set_lite(int v);
+extern bool_ set_blind(int v);
+extern bool_ set_confused(int v);
+extern bool_ set_poisoned(int v);
+extern bool_ set_afraid(int v);
+extern bool_ set_paralyzed(int v);
+extern bool_ set_image(int v);
+extern bool_ set_fast(int v, int p);
+extern bool_ set_light_speed(int v);
+extern bool_ set_slow(int v);
+extern bool_ set_shield(int v, int p, s16b o, s16b d1, s16b d2);
+extern bool_ set_blessed(int v);
+extern bool_ set_hero(int v);
+extern bool_ set_shero(int v);
+extern bool_ set_protevil(int v);
+extern bool_ set_protgood(int v);
+extern bool_ set_protundead(int v);
+extern bool_ set_invuln(int v);
+extern bool_ set_tim_invis(int v);
+extern bool_ set_tim_infra(int v);
+extern bool_ set_mental_barrier(int v);
+extern bool_ set_oppose_acid(int v);
+extern bool_ set_oppose_elec(int v);
+extern bool_ set_oppose_fire(int v);
+extern bool_ set_oppose_cold(int v);
+extern bool_ set_oppose_pois(int v);
+extern bool_ set_oppose_ld(int v);
+extern bool_ set_oppose_cc(int v);
+extern bool_ set_oppose_ss(int v);
+extern bool_ set_oppose_nex(int v);
+extern bool_ set_stun(int v);
+extern bool_ set_cut(int v);
+extern bool_ set_food(int v);
+extern void check_experience(void);
+extern void check_experience_obj(object_type *o_ptr);
+extern void gain_exp(s32b amount);
+extern void lose_exp(s32b amount);
+extern int get_coin_type(monster_race *r_ptr);
+extern void monster_death(int m_idx);
+extern bool_ mon_take_hit(int m_idx, int dam, bool_ *fear, cptr note);
+extern bool_ change_panel(int dy, int dx);
+extern void verify_panel(void);
+extern void resize_map(void);
+extern void resize_window(void);
+extern cptr look_mon_desc(int m_idx);
+extern void ang_sort_aux(vptr u, vptr v, int p, int q);
+extern void ang_sort(vptr u, vptr v, int n);
+extern bool_ target_able(int m_idx);
+extern bool_ target_okay(void);
+extern bool_ target_set(int mode);
+extern bool_ get_aim_dir(int *dp);
+extern bool_ get_hack_dir(int *dp);
+extern bool_ get_rep_dir(int *dp);
+extern int get_chaos_patron(void);
+extern void gain_level_reward(int chosen_reward);
+extern bool_ set_shadow(int v);
+extern bool_ set_tim_esp(int v);
+extern bool_ tgp_pt(int *x, int * y);
+extern bool_ tgt_pt (int *x, int *y);
+extern bool_ gain_random_corruption(int choose_mut);
+extern bool_ got_corruptions(void);
+extern void dump_corruptions(FILE *OutFile, bool_ color);
+extern void do_poly_self(void);
+extern void do_poly_wounds(void);
+extern bool_ curse_weapon(void);
+extern bool_ curse_armor(void);
+extern void random_resistance(object_type * q_ptr, bool_ is_scroll, int specific);
+extern bool_ lose_corruption(int choose_mut);
+extern bool_ lose_all_corruptions(void);
+extern void great_side_effect(void);
+extern void nasty_side_effect(void);
+extern void deadly_side_effect(bool_ god);
+extern void godly_wrath_blast(void);
+extern int interpret_grace(void);
+extern int interpret_favor(void);
+extern void make_wish(void);
+extern bool_ set_sliding(s16b v);
+extern void create_between_gate(int dist, int y, int x);
+
+/* levels.c */
+extern bool_ get_dungeon_generator(char *buf);
+extern bool_ get_level_desc(char *buf);
+extern void get_level_flags(void);
+extern bool_ get_dungeon_name(char *buf);
+extern bool_ get_dungeon_special(char *buf);
+extern bool_ get_command(const char *file, char comm, char *param);
+extern int get_branch(void);
+extern int get_fbranch(void);
+extern int get_flevel(void);
+extern bool_ get_dungeon_save(char *buf);
+
+/* wizard2.c */
+extern void do_cmd_wiz_cure_all(void);
+extern void do_cmd_wiz_named_friendly(int r_idx, bool_ slp);
+extern tval_desc2 tvals[];
+
+/* notes.c */
+extern void show_notes_file(void);
+extern void output_note(char *final_note);
+extern void add_note(char *note, char code);
+extern void add_note_type(int note_number);
+
+/* squeltch.c */
+extern void squeltch_inventory(void);
+extern void squeltch_grid(void);
+extern void do_cmd_automatizer(void);
+extern void automatizer_add_rule(object_type *o_ptr, bool_ destroy);
+extern bool_ automatizer_create;
+
+
+
+/*
+ * Hack -- conditional (or "bizarre") externs
+ */
+
+#ifdef SET_UID
+/* util.c */
+extern void user_name(char *buf, int id);
+#endif
+
+#ifndef HAS_MEMSET
+/* util.c */
+extern char *memset(char*, int, huge);
+#endif
+
+#ifndef HAS_STRICMP
+/* util.c */
+extern int stricmp(cptr a, cptr b);
+#endif
+
+#ifndef HAS_USLEEP
+/* util.c */
+extern int usleep(huge usecs);
+#endif
+
+#ifdef MACINTOSH
+/* main-mac.c */
+/* extern void main(void); */
+#endif
+
+#ifdef MACH_O_CARBON
+/* main-crb.c */
+extern int fsetfileinfo(char *path, u32b fcreator, u32b ftype);
+extern u32b _fcreator;
+extern u32b _ftype;
+#endif /* MACH_O_CARBON */
+
+#ifdef WINDOWS
+/* main-win.c */
+/* extern int FAR PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, ...); */
+#endif
+
+#if !defined(WINDOWS) && !defined(MACINTOSH)
+/* files.c */
+extern bool_ chg_to_txt(cptr base, cptr newname);
+#endif /* !WINDOWS && !MACINTOSH */
+
+/* util.c */
+extern void repeat_push(int what);
+extern bool_ repeat_pull(int *what);
+extern void repeat_check(void);
+extern void get_count(int number, int max);
+
+/* variable.c */
+extern bool_ easy_open;
+extern bool_ easy_tunnel;
+extern bool_ easy_disarm;
+
+/* cmd2.c */
+extern bool_ easy_open_door(int y, int x);
+
+/* cmd2.c */
+extern bool_ do_cmd_disarm_aux(int y, int x, int dir, int do_pickup);
+
+extern bool_ easy_floor;
+
+
+/* script.c */
+extern void init_lua(void);
+extern void init_lua_init(void);
+extern int exec_lua(char *file);
+extern cptr string_exec_lua(char *file);
+extern bool_ tome_dofile(char *file);
+extern bool_ tome_dofile_anywhere(cptr dir, char *file, bool_ test_exist);
+extern void dump_lua_stack(int min, int max);
+extern bool_ call_lua(cptr function, cptr args, cptr ret, ...);
+extern bool_ get_lua_var(cptr name, char type, void *arg);
+
+/* modules.c */
+extern void module_reset_dir(cptr dir, cptr new_path);
+extern cptr force_module;
+extern bool_ select_module(void);
+
+
+/* lua_bind.c */
+extern magic_power *grab_magic_power(magic_power *m_ptr, int num);
+extern bool_ get_magic_power(int *sn, magic_power *powers, int max_powers, void (*power_info)(char *p, int power), int plev, int cast_stat);
+extern bool_ lua_spell_success(magic_power *spell, int stat, char *oups_fct);
+
+extern object_type *new_object(void);
+extern void end_object(object_type *o_ptr);
+extern void lua_set_item_tester(int tval, char *fct);
+extern char *lua_object_desc(object_type *o_ptr, int pref, int mode);
+
+extern s16b add_new_power(cptr name, cptr desc, cptr gain, cptr lose, byte level, byte cost, byte stat, byte diff);
+
+extern void find_position(int y, int x, int *yy, int *xx);
+extern bool_ summon_lua_okay(int r_idx);
+extern bool_ lua_summon_monster(int y, int x, int lev, bool_ ffriend, char *fct);
+
+extern s16b add_new_quest(char *name);
+extern void desc_quest(int q_idx, int d, char *desc);
+
+extern s16b add_new_gods(char *name);
+extern void desc_god(int g_idx, int d, char *desc);
+
+extern bool_ get_com_lua(cptr promtp, int *com);
+
+extern s16b new_school(int i, cptr name, s16b skill);
+extern s16b new_spell(int i, cptr name);
+extern spell_type *grab_spell_type(s16b num);
+extern school_type *grab_school_type(s16b num);
+extern s32b lua_get_level(s32b s, s32b lvl, s32b max, s32b min, s32b bonus);
+extern s32b lua_spell_chance(s32b chance, int level, int skill_level, int mana, int cur_mana, int stat);
+extern s32b lua_spell_device_chance(s32b chance, int level, int base_level);
+
+extern cave_type *lua_get_cave(int y, int x);
+extern void set_target(int y, int x);
+extern void get_target(int dir, int *y, int *x);
+
+extern void get_map_size(char *name, int *ysize, int *xsize);
+extern void load_map(char *name, int *y, int *x);
+extern bool_ alloc_room(int by0, int bx0, int ysize, int xsize, int *y1, int *x1, int *y2, int *x2);
+
+extern void lua_print_hook(cptr str);
+
+extern int lua_get_new_bounty_monster(int lev);
+
+extern char *lua_input_box(cptr title, int max);
+extern char lua_msg_box(cptr title);
+
+extern list_type *lua_create_list(int size);
+extern void lua_delete_list(list_type *, int size);
+extern void lua_add_to_list(list_type *, int idx, cptr str);
+extern void lua_display_list(int y, int x, int h, int w, cptr title, list_type *list, int max, int begin, int sel, byte sel_color);
+
+extern cptr compass(int y, int x, int y2, int x2);
+extern cptr approximate_distance(int y, int x, int y2, int x2);
+
+extern bool_ drop_text_left(byte c, cptr s, int y, int o);
+extern bool_ drop_text_right(byte c, cptr s, int y, int o);
+
+/* skills.c */
+extern void dump_skills(FILE *fff);
+extern s16b find_skill(cptr name);
+extern s16b find_skill_i(cptr name);
+extern s16b get_skill(int skill);
+extern s16b get_skill_scale(int skill, u32b scale);
+extern void do_cmd_skill(void);
+extern void do_cmd_activate_skill(void);
+extern s16b melee_skills[MAX_MELEE];
+extern char *melee_names[MAX_MELEE];
+extern s16b get_melee_skills(void);
+extern s16b get_melee_skill(void);
+extern bool_ forbid_gloves(void);
+extern bool_ forbid_non_blessed(void);
+extern void compute_skills(s32b *v, s32b *m, int i);
+extern void select_default_melee(void);
+extern void do_get_new_skill(void);
+extern void init_skill(s32b value, s32b mod, int i);
+extern s16b find_ability(cptr name);
+extern void dump_abilities(FILE *fff);
+extern void do_cmd_ability(void);
+extern bool_ has_ability(int ab);
+extern void apply_level_abilities(int level);
+extern void recalc_skills(bool_ init);
+
+/* gods.c */
+extern void inc_piety(int god, s32b amt);
+extern void abandon_god(int god);
+extern int wisdom_scale(int max);
+extern int find_god(cptr name);
+extern void follow_god(int god, bool_ silent);
diff --git a/src/files.c b/src/files.c
new file mode 100644
index 00000000..56e57975
--- /dev/null
+++ b/src/files.c
@@ -0,0 +1,6058 @@
+/* File: files.c */
+
+/* Purpose: code dealing with files (and death) */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Extract the first few "tokens" from a buffer
+ *
+ * This function uses "colon" and "slash" and delim arg as the delimeter characters.
+ *
+ * We never extract more than "num" tokens. The "last" token may include
+ * "delimeter" characters, allowing the buffer to include a "string" token.
+ *
+ * We save pointers to the tokens in "tokens", and return the number found.
+ *
+ * Hack -- Attempt to handle the 'c' character formalism
+ *
+ * Hack -- An empty buffer, or a final delimeter, yields an "empty" token.
+ *
+ * Hack -- We will always extract at least one token
+ */
+s16b tokenize(char *buf, s16b num, char **tokens, char delim1, char delim2)
+{
+ int i = 0;
+
+ char *s = buf;
+
+
+ /* Process */
+ while (i < num - 1)
+ {
+ char *t;
+
+ /* Scan the string */
+ for (t = s; *t; t++)
+ {
+ /* Found a delimiter */
+ if ((*t == delim1) || (*t == delim2)) break;
+
+ /* Handle single quotes */
+ if (*t == '\'')
+ {
+ /* Advance */
+ t++;
+
+ /* Handle backslash */
+ if (*t == '\\') t++;
+
+ /* Require a character */
+ if (!*t) break;
+
+ /* Advance */
+ t++;
+
+ /* Hack -- Require a close quote */
+ if (*t != '\'') *t = '\'';
+ }
+
+ /* Handle back-slash */
+ if (*t == '\\') t++;
+ }
+
+ /* Nothing left */
+ if (!*t) break;
+
+ /* Nuke and advance */
+ *t++ = '\0';
+
+ /* Save the token */
+ tokens[i++] = s;
+
+ /* Advance */
+ s = t;
+ }
+
+ /* Save the token */
+ tokens[i++] = s;
+
+ /* Number found */
+ return (i);
+}
+
+
+
+/*
+ * Parse a sub-file of the "extra info" (format shown below)
+ *
+ * Each "action" line has an "action symbol" in the first column,
+ * followed by a colon, followed by some command specific info,
+ * usually in the form of "tokens" separated by colons or slashes.
+ *
+ * Blank lines, lines starting with white space, and lines starting
+ * with pound signs ("#") are ignored (as comments).
+ *
+ * Note the use of "tokenize()" to allow the use of both colons and
+ * slashes as delimeters, while still allowing final tokens which
+ * may contain any characters including "delimiters".
+ *
+ * Note the use of "strtol()" to allow all "integers" to be encoded
+ * in decimal, hexidecimal, or octal form.
+ *
+ * Note that "monster zero" is used for the "player" attr/char, "object
+ * zero" will be used for the "stack" attr/char, and "feature zero" is
+ * used for the "nothing" attr/char.
+ *
+ * Parse another file recursively, see below for details
+ * %:<filename>
+ *
+ * Specify the attr/char values for "monsters" by race index
+ * R:<num>:<a>:<c>
+ *
+ * Specify the attr/char values for "objects" by kind index
+ * K:<num>:<a>:<c>
+ *
+ * Specify the attr/char values for "features" by feature index
+ * F:<num>:<a>:<c>
+ *
+ * Specify the attr/char values for "stores" by store index
+ * B:<num>:<a>:<c>
+ *
+ * Specify the attr/char values for unaware "objects" by kind tval
+ * U:<tv>:<a>:<c>
+ *
+ * Specify the attr/char values for inventory "objects" by kind tval
+ * E:<tv>:<a>:<c>
+ *
+ * Define a macro action, given an encoded macro action
+ * A:<str>
+ *
+ * Create a normal macro, given an encoded macro trigger
+ * P:<str>
+ *
+ * Create a command macro, given an encoded macro trigger
+ * C:<str>
+ *
+ * Create a keyset mapping
+ * S:<key>:<key>:<dir>
+ *
+ * Turn an option off, given its name
+ * X:<str>
+ *
+ * Turn an option on, given its name
+ * Y:<str>
+ *
+ * Specify visual information, given an index, and some data
+ * V:<num>:<kv>:<rv>:<gv>:<bv>
+ *
+ * Specify squelch settings
+ * Q:<num>:<squelch>
+ */
+errr process_pref_file_aux(char *buf)
+{
+ int i, j, n1, n2;
+
+ char *zz[16];
+
+
+ /* Skip "empty" lines */
+ if (!buf[0]) return (0);
+
+ /* Skip "blank" lines */
+ if (isspace(buf[0])) return (0);
+
+ /* Skip comments */
+ if (buf[0] == '#') return (0);
+
+ /* Require "?:*" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Process "%:<fname>" */
+ if (buf[0] == '%')
+ {
+ /* Attempt to Process the given file */
+ return (process_pref_file(buf + 2));
+ }
+
+
+ /* Process "R:<num>:<a>/<c>" -- attr/char for monster races */
+ if (buf[0] == 'R')
+ {
+ if (tokenize(buf + 2, 3, zz, ':', '/') == 3)
+ {
+ monster_race *r_ptr;
+ i = (huge)strtol(zz[0], NULL, 0);
+ n1 = strtol(zz[1], NULL, 0);
+ n2 = strtol(zz[2], NULL, 0);
+ if (i >= max_r_idx) return (1);
+ r_ptr = &r_info[i];
+ if (n1) r_ptr->x_attr = n1;
+ if (n2)
+ {
+ r_ptr->x_char = n2;
+ }
+ return (0);
+ }
+ }
+
+
+ /* Process "G:<type>:<num>:<a>/<c>" -- attr/char for overlay graphics */
+ if (buf[0] == 'G')
+ {
+ /* Process "G:M:<num>:<a>/<c>" -- attr/char for ego monsters */
+ if (buf[2] == 'M')
+ {
+ if (tokenize(buf + 4, 3, zz, ':', '/') == 3)
+ {
+ monster_ego *re_ptr;
+ i = (huge)strtol(zz[0], NULL, 0);
+ n1 = strtol(zz[1], NULL, 0);
+ n2 = strtol(zz[2], NULL, 0);
+ if (i >= max_re_idx) return (1);
+ re_ptr = &re_info[i];
+ if (n1) re_ptr->g_attr = n1;
+ if (n2)
+ {
+ re_ptr->g_char = n2;
+ }
+ return (0);
+ }
+ }
+
+ /* Process "G:P:<num>:<a>/<c>" -- attr/char for race modifiers */
+ if (buf[2] == 'P')
+ {
+ if (tokenize(buf + 4, 3, zz, ':', '/') == 3)
+ {
+ player_race_mod *rmp_ptr;
+ i = (huge)strtol(zz[0], NULL, 0);
+ n1 = strtol(zz[1], NULL, 0);
+ n2 = strtol(zz[2], NULL, 0);
+ if (i >= max_rmp_idx) return (1);
+ rmp_ptr = &race_mod_info[i];
+ if (n1) rmp_ptr->g_attr = n1;
+ if (n2)
+ {
+ rmp_ptr->g_char = n2;
+ }
+ return (0);
+ }
+ }
+
+ /* Process "G:T:<num>:<a>/<c>" -- attr/char for traps */
+ if (buf[2] == 'T')
+ {
+ if (tokenize(buf + 4, 3, zz, ':', '/') == 3)
+ {
+ trap_type *t_ptr;
+ i = (huge)strtol(zz[0], NULL, 0);
+ n1 = strtol(zz[1], NULL, 0);
+ n2 = strtol(zz[2], NULL, 0);
+ if (i >= max_t_idx) return (1);
+ t_ptr = &t_info[i];
+ if (n1) t_ptr->g_attr = n1;
+ if (n2)
+ {
+ t_ptr->g_char = n2;
+ }
+ return (0);
+ }
+ }
+ }
+
+
+ /* Process "K:<num>:<a>/<c>" -- attr/char for object kinds */
+ else if (buf[0] == 'K')
+ {
+ if (tokenize(buf + 2, 3, zz, ':', '/') == 3)
+ {
+ object_kind *k_ptr;
+ i = (huge)strtol(zz[0], NULL, 0);
+ n1 = strtol(zz[1], NULL, 0);
+ n2 = strtol(zz[2], NULL, 0);
+ if (i >= max_k_idx) return (1);
+ k_ptr = &k_info[i];
+ if (n1) k_ptr->x_attr = n1;
+ if (n2)
+ {
+ k_ptr->x_char = n2;
+ }
+ return (0);
+ }
+ }
+
+
+ /* Process "F:<num>:<a>/<c>" -- attr/char for terrain features */
+ else if (buf[0] == 'F')
+ {
+ if (tokenize(buf + 2, 3, zz, ':', '/') == 3)
+ {
+ feature_type *f_ptr;
+ i = (huge)strtol(zz[0], NULL, 0);
+ n1 = strtol(zz[1], NULL, 0);
+ n2 = strtol(zz[2], NULL, 0);
+ if (i >= max_f_idx) return (1);
+ f_ptr = &f_info[i];
+ if (n1) f_ptr->x_attr = n1;
+ if (n2)
+ {
+ f_ptr->x_char = n2;
+ }
+ return (0);
+ }
+ }
+
+ /* Process "B:<num>:<a>/<c>" -- attr/char for stores */
+ else if (buf[0] == 'B')
+ {
+ if (tokenize(buf + 2, 3, zz, ':', '/') == 3)
+ {
+ store_info_type *st_ptr;
+ i = (huge)strtol(zz[0], NULL, 0);
+ n1 = strtol(zz[1], NULL, 0);
+ n2 = strtol(zz[2], NULL, 0);
+ if (i >= max_st_idx) return (1);
+ st_ptr = &st_info[i];
+ if (n1) st_ptr->x_attr = n1;
+ if (n2) st_ptr->x_char = n2;
+ return (0);
+ }
+ }
+
+ /* Process "S:<num>:<a>/<c>" -- attr/char for special things */
+ else if (buf[0] == 'S')
+ {
+ if (tokenize(buf + 2, 3, zz, ':', '/') == 3)
+ {
+ j = (byte)strtol(zz[0], NULL, 0);
+ n1 = strtol(zz[1], NULL, 0);
+ n2 = strtol(zz[2], NULL, 0);
+ misc_to_attr[j] = n1;
+ misc_to_char[j] = n2;
+ return (0);
+ }
+ }
+
+ /* Process "U:<tv>:<a>/<c>" -- attr/char for unaware items */
+ else if (buf[0] == 'U')
+ {
+ if (tokenize(buf + 2, 3, zz, ':', '/') == 3)
+ {
+ j = (huge)strtol(zz[0], NULL, 0);
+ n1 = strtol(zz[1], NULL, 0);
+ n2 = strtol(zz[2], NULL, 0);
+ for (i = 1; i < max_k_idx; i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+ if (k_ptr->tval == j)
+ {
+ if (n1) k_ptr->d_attr = n1;
+ if (n2) k_ptr->d_char = n2;
+ }
+ }
+ return (0);
+ }
+ }
+
+
+ /* Process "E:<tv>:<a>" -- attribute for inventory objects */
+ else if (buf[0] == 'E')
+ {
+ if (tokenize(buf + 2, 2, zz, ':', '/') == 2)
+ {
+ j = (byte)strtol(zz[0], NULL, 0) % 128;
+ n1 = strtol(zz[1], NULL, 0);
+ if (n1) tval_to_attr[j] = n1;
+ return (0);
+ }
+ }
+
+
+ /* Process "A:<str>" -- save an "action" for later */
+ else if (buf[0] == 'A')
+ {
+ text_to_ascii(macro__buf, buf + 2);
+ return (0);
+ }
+
+ /* Process "P:<str>" -- normal macro */
+ else if (buf[0] == 'P')
+ {
+ char tmp[1024];
+ text_to_ascii(tmp, buf + 2);
+ macro_add(tmp, macro__buf);
+ return (0);
+ }
+
+ /* Process "L:<num>:<trigger>:<descr> -- extended command macro */
+ else if (buf[0] == 'L')
+ {
+ switch (tokenize(buf + 2, 3, zz, ':', 0))
+ {
+ case 3:
+ cli_add(zz[0], zz[1], zz[2]);
+ return 0;
+ case 2:
+ cli_add(zz[0], zz[1], 0);
+ return 0;
+ default:
+ return 1;
+ }
+ }
+
+ /* Process "C:<str>" -- create keymap */
+ else if (buf[0] == 'C')
+ {
+ int mode;
+
+ char tmp[1024];
+
+ if (tokenize(buf + 2, 2, zz, ':', '/') != 2) return (1);
+
+ mode = strtol(zz[0], NULL, 0);
+ if ((mode < 0) || (mode >= KEYMAP_MODES)) return (1);
+
+ text_to_ascii(tmp, zz[1]);
+ if (!tmp[0] || tmp[1]) return (1);
+ i = (byte)(tmp[0]);
+
+ string_free(keymap_act[mode][i]);
+
+ keymap_act[mode][i] = string_make(macro__buf);
+
+ return (0);
+ }
+
+
+ /* Process "V:<num>:<kv>:<rv>:<gv>:<bv>" -- visual info */
+ else if (buf[0] == 'V')
+ {
+ if (tokenize(buf + 2, 5, zz, ':', '/') == 5)
+ {
+ i = (byte)strtol(zz[0], NULL, 0);
+ angband_color_table[i][0] = (byte)strtol(zz[1], NULL, 0);
+ angband_color_table[i][1] = (byte)strtol(zz[2], NULL, 0);
+ angband_color_table[i][2] = (byte)strtol(zz[3], NULL, 0);
+ angband_color_table[i][3] = (byte)strtol(zz[4], NULL, 0);
+ return (0);
+ }
+ }
+ /* set macro trigger names and a template */
+ /* Process "T:<trigger>:<keycode>:<shift-keycode>" */
+ /* Process "T:<template>:<modifier chr>:<modifier name>:..." */
+ else if (buf[0] == 'T')
+ {
+ int len, tok;
+ tok = tokenize(buf + 2, 2 + MAX_MACRO_MOD, zz, ':', '/');
+ if (tok >= 4)
+ {
+ int i;
+ int num;
+
+ if (macro_template != NULL)
+ {
+ free(macro_template);
+ macro_template = NULL;
+ for (i = 0; i < max_macrotrigger; i++)
+ free(macro_trigger_name[i]);
+ max_macrotrigger = 0;
+ }
+
+ if (*zz[0] == '\0') return 0; /* clear template */
+ num = strlen(zz[1]);
+ if (2 + num != tok) return 1; /* error */
+
+ len = strlen(zz[0]) + 1 + num + 1;
+ for (i = 0; i < num; i++)
+ len += strlen(zz[2 + i]) + 1;
+ macro_template = malloc(len);
+
+ strcpy(macro_template, zz[0]);
+ macro_modifier_chr =
+ macro_template + strlen(macro_template) + 1;
+ strcpy(macro_modifier_chr, zz[1]);
+ macro_modifier_name[0] =
+ macro_modifier_chr + strlen(macro_modifier_chr) + 1;
+ for (i = 0; i < num; i++)
+ {
+ strcpy(macro_modifier_name[i], zz[2 + i]);
+ macro_modifier_name[i + 1] = macro_modifier_name[i] +
+ strlen(macro_modifier_name[i]) + 1;
+ }
+ }
+ else if (tok >= 2)
+ {
+ int m;
+ char *t, *s;
+ if (max_macrotrigger >= MAX_MACRO_TRIG)
+ {
+ msg_print("Too many macro triggers!");
+ return 1;
+ }
+ m = max_macrotrigger;
+ max_macrotrigger++;
+
+ len = strlen(zz[0]) + 1 + strlen(zz[1]) + 1;
+ if (tok == 3)
+ len += strlen(zz[2]) + 1;
+ macro_trigger_name[m] = malloc(len);
+
+ t = macro_trigger_name[m];
+ s = zz[0];
+ while (*s)
+ {
+ if ('\\' == *s) s++;
+ *t++ = *s++;
+ }
+ *t = '\0';
+
+ macro_trigger_keycode[0][m] = macro_trigger_name[m] +
+ strlen(macro_trigger_name[m]) + 1;
+ strcpy(macro_trigger_keycode[0][m], zz[1]);
+ if (tok == 3)
+ {
+ macro_trigger_keycode[1][m] = macro_trigger_keycode[0][m] +
+ strlen(macro_trigger_keycode[0][m]) + 1;
+ strcpy(macro_trigger_keycode[1][m], zz[2]);
+ }
+ else
+ {
+ macro_trigger_keycode[1][m] = macro_trigger_keycode[0][m];
+ }
+ }
+ return 0;
+ }
+
+ /* Process "X:<str>" -- turn option off */
+ else if (buf[0] == 'X')
+ {
+ for (i = 0; option_info[i].o_desc; i++)
+ {
+ if (option_info[i].o_var &&
+ option_info[i].o_text &&
+ streq(option_info[i].o_text, buf + 2))
+ {
+ (*option_info[i].o_var) = FALSE;
+ return (0);
+ }
+ }
+ }
+
+ /* Process "Y:<str>" -- turn option on */
+ else if (buf[0] == 'Y')
+ {
+ for (i = 0; option_info[i].o_desc; i++)
+ {
+ if (option_info[i].o_var &&
+ option_info[i].o_text &&
+ streq(option_info[i].o_text, buf + 2))
+ {
+ (*option_info[i].o_var) = TRUE;
+ return (0);
+ }
+ }
+ }
+
+ /* Process "W:<win>:<flag>:<value>" -- window flags */
+ else if (buf[0] == 'W')
+ {
+ int win, flag, value;
+
+ if (tokenize(buf + 2, 3, zz, ':', '/') == 3)
+ {
+ win = strtol(zz[0], NULL, 0);
+ flag = strtol(zz[1], NULL, 0);
+ value = strtol(zz[2], NULL, 0);
+
+ /* Ignore illegal windows */
+ /* Hack -- Ignore the main window */
+ if ((win <= 0) || (win >= ANGBAND_TERM_MAX)) return (1);
+
+ /* Ignore illegal flags */
+ if ((flag < 0) || (flag >= 32)) return (1);
+
+ /* Require a real flag */
+ if (window_flag_desc[flag])
+ {
+ if (value)
+ {
+ /* Turn flag on */
+ window_flag[win] |= (1L << flag);
+ }
+ else
+ {
+ /* Turn flag off */
+ window_flag[win] &= ~(1L << flag);
+ }
+ }
+
+ /* Success */
+ return (0);
+ }
+ }
+
+ /* Process "Q:<num>:<squelch>" -- item squelch flags */
+ else if (buf[0] == 'Q')
+ {
+ /* This option isn't used anymore */
+ return (0);
+ }
+ /* Failure */
+ return (1);
+}
+
+
+/*
+ * Helper function for "process_pref_file()"
+ *
+ * Input:
+ * v: output buffer array
+ * f: final character
+ *
+ * Output:
+ * result
+ */
+static cptr process_pref_file_expr(char **sp, char *fp)
+{
+ cptr v;
+
+ char *b;
+ char *s;
+
+ char b1 = '[';
+ char b2 = ']';
+
+ char f = ' ';
+
+ /* Initial */
+ s = (*sp);
+
+ /* Skip spaces */
+ while (isspace(*s)) s++;
+
+ /* Save start */
+ b = s;
+
+ /* Default */
+ v = "?o?o?";
+
+ /* Analyze */
+ if (*s == b1)
+ {
+ const char *p;
+ const char *t;
+
+ /* Skip b1 */
+ s++;
+
+ /* First */
+ t = process_pref_file_expr(&s, &f);
+
+ /* Oops */
+ if (!*t)
+ {
+ /* Nothing */
+ }
+
+ /* Function: IOR */
+ else if (streq(t, "IOR"))
+ {
+ v = "0";
+ while (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ if (*t && !streq(t, "0")) v = "1";
+ }
+ }
+
+ /* Function: AND */
+ else if (streq(t, "AND"))
+ {
+ v = "1";
+ while (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ if (*t && streq(t, "0")) v = "0";
+ }
+ }
+
+ /* Function: NOT */
+ else if (streq(t, "NOT"))
+ {
+ v = "1";
+ while (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ if (*t && !streq(t, "0")) v = "0";
+ }
+ }
+
+ /* Function: EQU */
+ else if (streq(t, "EQU"))
+ {
+ v = "1";
+ if (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ }
+ while (*s && (f != b2))
+ {
+ p = t;
+ t = process_pref_file_expr(&s, &f);
+ if (*t && !streq(p, t)) v = "0";
+ }
+ }
+
+ /* Function: LEQ */
+ else if (streq(t, "LEQ"))
+ {
+ v = "1";
+ if (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ }
+ while (*s && (f != b2))
+ {
+ p = t;
+ t = process_pref_file_expr(&s, &f);
+ if (*t && (strcmp(p, t) > 0)) v = "0";
+ }
+ }
+
+ /* Function: GEQ */
+ else if (streq(t, "GEQ"))
+ {
+ v = "1";
+ if (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ }
+ while (*s && (f != b2))
+ {
+ p = t;
+ t = process_pref_file_expr(&s, &f);
+ if (*t && (strcmp(p, t) < 0)) v = "0";
+ }
+ }
+
+ /* Function: LEQN */
+ else if (streq(t, "LEQN"))
+ {
+ int n = 0;
+ v = "1";
+ if (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ n = atoi(t);
+ }
+ while (*s && (f != b2))
+ {
+ p = t;
+ t = process_pref_file_expr(&s, &f);
+ if (*t && (atoi(t) < n)) v = "0";
+ }
+ }
+
+ /* Function: GEQN */
+ else if (streq(t, "GEQN"))
+ {
+ int n = 0;
+ v = "1";
+ if (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ n = atoi(t);
+ }
+ while (*s && (f != b2))
+ {
+ p = t;
+ t = process_pref_file_expr(&s, &f);
+ if (*t && (atoi(t) > n)) v = "0";
+ }
+ }
+
+ /* Function SKILL */
+ else if (streq(t, "SKILL"))
+ {
+ static char skill_val[4*sizeof(int) + 1];
+ s16b skill = -1;
+ v = "0";
+ while (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ if (*t) skill = find_skill_i(t);
+ }
+ if (skill > 0)
+ {
+ sprintf(skill_val, "%d", (int)get_skill(skill));
+ v = skill_val;
+ }
+ }
+
+ /* Oops */
+ else
+ {
+ while (*s && (f != b2))
+ {
+ t = process_pref_file_expr(&s, &f);
+ }
+ }
+
+ /* Verify ending */
+ if (f != b2) v = "?x?x?";
+
+ /* Extract final and Terminate */
+ if ((f = *s) != '\0') * s++ = '\0';
+ }
+
+ /* Other */
+ else
+ {
+ /* Accept all printables except spaces and brackets */
+ while (isprint(*s) && !strchr(" []", *s)) ++s;
+
+ /* Extract final and Terminate */
+ if ((f = *s) != '\0') * s++ = '\0';
+
+ /* Variable */
+ if (*b == '$')
+ {
+ /* System */
+ if (streq(b + 1, "SYS"))
+ {
+ v = ANGBAND_SYS;
+ }
+
+ else if (streq(b + 1, "KEYBOARD"))
+ {
+ v = ANGBAND_KEYBOARD;
+ }
+
+ /* Graphics */
+ if (streq(b + 1, "GRAF"))
+ {
+ v = ANGBAND_GRAF;
+ }
+
+ /* Race */
+ else if (streq(b + 1, "RACE"))
+ {
+ v = rp_ptr->title + rp_name;
+ }
+
+ /* Race */
+ else if (streq(b + 1, "RACEMOD"))
+ {
+ v = rmp_ptr->title + rmp_name;
+ }
+
+ /* Class */
+ else if (streq(b + 1, "CLASS"))
+ {
+ v = spp_ptr->title + c_name;
+ }
+
+ /* Player */
+ else if (streq(b + 1, "PLAYER"))
+ {
+ v = player_base;
+ }
+ }
+
+ /* Constant */
+ else
+ {
+ v = b;
+ }
+ }
+
+ /* Save */
+ (*fp) = f;
+
+ /* Save */
+ (*sp) = s;
+
+ /* Result */
+ return (v);
+}
+
+
+
+
+/*
+ * Process the "user pref file" with the given name
+ *
+ * See the function above for a list of legal "commands".
+ *
+ * We also accept the special "?" and "%" directives, which
+ * allow conditional evaluation and filename inclusion.
+ */
+errr process_pref_file(cptr name)
+{
+ FILE *fp;
+
+ char buf[1024];
+
+ int num = -1;
+
+ errr err = 0;
+
+ bool_ bypass = FALSE;
+
+ /* Build the filename -- Allow users to override system pref files */
+ path_build(buf, 1024, ANGBAND_DIR_USER, name);
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* No such file -- Try system pref file */
+ if (!fp)
+ {
+ /* Build the pathname, this time using the system pref directory */
+ path_build(buf, 1024, ANGBAND_DIR_PREF, name);
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Failed again */
+ if (!fp) return ( -1);
+ }
+
+
+ /* Process the file */
+ while (0 == my_fgets(fp, buf, 1024))
+ {
+ /* Count lines */
+ num++;
+
+
+ /* Skip "empty" lines */
+ if (!buf[0]) continue;
+
+ /* Skip "blank" lines */
+ if (isspace(buf[0])) continue;
+
+ /* Skip comments */
+ if (buf[0] == '#') continue;
+
+
+ /* Process "?:<expr>" */
+ if ((buf[0] == '?') && (buf[1] == ':'))
+ {
+ char f;
+ cptr v;
+ char *s;
+
+ /* Start */
+ s = buf + 2;
+
+ /* Parse the expr */
+ v = process_pref_file_expr(&s, &f);
+
+ /* Set flag */
+ bypass = (streq(v, "0") ? TRUE : FALSE);
+
+ /* Continue */
+ continue;
+ }
+
+ /* Apply conditionals */
+ if (bypass) continue;
+
+
+ /* Process "%:<file>" */
+ if (buf[0] == '%')
+ {
+ /* Process that file if allowed */
+ (void)process_pref_file(buf + 2);
+
+ /* Continue */
+ continue;
+ }
+
+
+ /* Process the line */
+ err = process_pref_file_aux(buf);
+
+ /* Oops */
+ if (err) break;
+ }
+
+
+ /* Error */
+ if (err)
+ {
+ /* Useful error message */
+ msg_format("Error %d in line %d of file '%s'.", err, num, name);
+ msg_format("Parsing '%s'", buf);
+ }
+
+ /* Close the file */
+ my_fclose(fp);
+
+ /* Result */
+ return (err);
+}
+
+
+
+
+/*
+ * Print long number with header at given row, column
+ * Use the color for the number, not the header
+ */
+static void prt_lnum(cptr header, s32b num, int row, int col, byte color)
+{
+ int len = strlen(header);
+ char out_val[32];
+
+ put_str(header, row, col);
+ (void)sprintf(out_val, "%9ld", (long)num);
+ c_put_str(color, out_val, row, col + len);
+}
+
+
+/*
+ * Print number with header at given row, column
+ */
+static void prt_num(cptr header, int num, int row, int col, byte color,
+ char *space)
+{
+ int len = strlen(header);
+ char out_val[32];
+
+ put_str(header, row, col);
+ put_str(space, row, col + len);
+ (void)sprintf(out_val, "%6ld", (long)num);
+ c_put_str(color, out_val, row, col + len + strlen(space));
+}
+
+
+/*
+ * Print str with header at given row, column
+ */
+static void prt_str(cptr header, cptr str, int row, int col, byte color)
+{
+ int len = strlen(header);
+ char out_val[32];
+
+ put_str(header, row, col);
+ put_str(" ", row, col + len);
+ (void)sprintf(out_val, "%6s", str);
+ c_put_str(color, out_val, row, col + len + 3);
+}
+
+
+/*
+ * Prints the following information on the screen.
+ *
+ * For this to look right, the following should be spaced the
+ * same as in the prt_lnum code... -CFT
+ */
+static void display_player_middle(void)
+{
+ int show_tohit = p_ptr->dis_to_h;
+ int show_todam = p_ptr->dis_to_d;
+
+ object_type *o_ptr = &p_ptr->inventory[INVEN_WIELD];
+ char num[7];
+ byte color;
+ int speed;
+
+
+ /* Hack -- add in weapon info if known */
+ if (object_known_p(o_ptr)) show_tohit = p_ptr->dis_to_h + p_ptr->to_h_melee + o_ptr->to_h;
+ else show_tohit = p_ptr->dis_to_h + p_ptr->to_h_melee;
+ if (object_known_p(o_ptr)) show_todam = p_ptr->dis_to_d + p_ptr->to_d_melee + o_ptr->to_d;
+ else show_todam = p_ptr->dis_to_d + p_ptr->to_d_melee;
+
+ /* Dump the bonuses to hit/dam */
+ prt_num("+ To Melee Hit ", show_tohit, 9, 1, TERM_L_BLUE, " ");
+ prt_num("+ To Melee Damage", show_todam, 10, 1, TERM_L_BLUE, " ");
+
+ o_ptr = &p_ptr->inventory[INVEN_BOW];
+
+ /* Hack -- add in weapon info if known */
+ if (object_known_p(o_ptr)) show_tohit = p_ptr->dis_to_h + p_ptr->to_h_ranged + o_ptr->to_h;
+ else show_tohit = p_ptr->dis_to_h + p_ptr->to_h_ranged;
+ if (object_known_p(o_ptr)) show_todam = p_ptr->to_d_ranged + o_ptr->to_d;
+ else show_todam = p_ptr->to_d_ranged;
+
+ prt_num("+ To Ranged Hit ", show_tohit, 11, 1, TERM_L_BLUE, " ");
+ prt_num("+ To Ranged Damage", show_todam, 12, 1, TERM_L_BLUE, " ");
+
+ /* Dump the total armor class */
+ prt_str(" AC ", format("%d+%d", p_ptr->ac, p_ptr->dis_to_a), 13, 1, TERM_L_BLUE);
+
+ prt_num("Level ", (int)p_ptr->lev, 9, 28, TERM_L_GREEN, " ");
+
+ if (p_ptr->exp >= p_ptr->max_exp)
+ {
+ prt_lnum("Experience ", p_ptr->exp, 10, 28, TERM_L_GREEN);
+ }
+ else
+ {
+ prt_lnum("Experience ", p_ptr->exp, 10, 28, TERM_YELLOW);
+ }
+
+ prt_lnum("Max Exp ", p_ptr->max_exp, 11, 28, TERM_L_GREEN);
+
+ if ((p_ptr->lev >= PY_MAX_LEVEL) || (p_ptr->lev >= max_plev))
+ {
+ put_str("Exp to Adv.", 12, 28);
+ c_put_str(TERM_L_GREEN, " *****", 12, 28 + 11);
+ }
+ else
+ {
+ prt_lnum("Exp to Adv.",
+ (s32b)(player_exp[p_ptr->lev - 1] * p_ptr->expfact / 100L),
+ 12, 28, TERM_L_GREEN);
+ }
+
+ prt_lnum("Gold ", p_ptr->au, 13, 28, TERM_L_GREEN);
+
+ if (p_ptr->necro_extra & CLASS_UNDEAD)
+ {
+ put_str("Death Points ", 9, 52);
+ if (p_ptr->chp >= p_ptr->mhp)
+ {
+ color = TERM_L_BLUE;
+ }
+ else if (p_ptr->chp > (p_ptr->mhp * hitpoint_warn) / 10)
+ {
+ color = TERM_VIOLET;
+ }
+ else
+ {
+ color = TERM_L_RED;
+ }
+ (void)sprintf(num, "%6ld", (long)p_ptr->chp);
+ c_put_str(color, num, 9, 65);
+ put_str("/", 9, 71);
+ (void)sprintf(num, "%6ld", (long)p_ptr->mhp);
+ c_put_str(TERM_L_BLUE, num, 9, 72);
+ }
+ else
+ {
+ put_str("Hit Points ", 9, 52);
+ if (p_ptr->chp >= p_ptr->mhp)
+ {
+ color = TERM_L_GREEN;
+ }
+ else if (p_ptr->chp > (p_ptr->mhp * hitpoint_warn) / 10)
+ {
+ color = TERM_YELLOW;
+ }
+ else
+ {
+ color = TERM_RED;
+ }
+ (void)sprintf(num, "%6ld", (long)p_ptr->chp);
+ c_put_str(color, num, 9, 65);
+ put_str("/", 9, 71);
+ (void)sprintf(num, "%6ld", (long)p_ptr->mhp);
+ c_put_str(TERM_L_GREEN, num, 9, 72);
+ }
+
+ put_str("Spell Points ", 10, 52);
+ if (p_ptr->csp >= p_ptr->msp)
+ {
+ color = TERM_L_GREEN;
+ }
+ else if (p_ptr->csp > (p_ptr->msp * hitpoint_warn) / 10)
+ {
+ color = TERM_YELLOW;
+ }
+ else
+ {
+ color = TERM_RED;
+ }
+ (void)sprintf(num, "%6ld", (long)p_ptr->csp);
+ c_put_str(color, num, 10, 65);
+ put_str("/", 10, 71);
+ (void)sprintf(num, "%6ld", (long)p_ptr->msp);
+ c_put_str(TERM_L_GREEN, num, 10, 72);
+
+ put_str("Sanity ", 11, 52);
+ if (p_ptr->csane >= p_ptr->msane)
+ {
+ color = TERM_L_GREEN;
+ }
+ else if (p_ptr->csane > (p_ptr->msane * hitpoint_warn) / 10)
+ {
+ color = TERM_YELLOW;
+ }
+ else
+ {
+ color = TERM_RED;
+ }
+ (void)sprintf(num, "%6ld", (long)p_ptr->csane);
+ c_put_str(color, num, 11, 65);
+ put_str("/", 11, 71);
+ (void)sprintf(num, "%6ld", (long)p_ptr->msane);
+ c_put_str(TERM_L_GREEN, num, 11, 72);
+
+ if (p_ptr->pgod != GOD_NONE)
+ {
+ prt_num("Piety ", p_ptr->grace, 12, 52, TERM_L_GREEN, " ");
+ }
+
+ put_str("Speed ", 13, 52);
+ speed = p_ptr->pspeed;
+ /* Hack -- Visually "undo" the Search Mode Slowdown */
+ if (p_ptr->searching) speed += 10;
+ if (speed > 110)
+ {
+ char s[11];
+ (void)sprintf(s, "Fast (+%d)", speed - 110);
+ c_put_str(TERM_L_GREEN, s, 13, (speed >= 120) ? 68 : 69);
+ }
+ else if (speed < 110)
+ {
+ char s[11];
+ (void)sprintf(s, "Slow (-%d)", 110 - speed);
+ c_put_str(TERM_L_UMBER, s, 13, (speed <= 100) ? 68 : 69);
+ }
+ else
+ {
+ put_str("Normal", 13, 72);
+ }
+}
+
+
+
+
+/*
+ * Hack -- pass color info around this file
+ */
+static byte likert_color = TERM_WHITE;
+
+
+/*
+ * Returns a "rating" of x depending on y
+ */
+static cptr likert(int x, int y)
+{
+ static char dummy[20] = "";
+
+ /* Paranoia */
+ if (y <= 0) y = 1;
+
+ /* Negative value */
+ if (x < 0)
+ {
+ likert_color = TERM_L_DARK;
+ return ("Very Bad");
+ }
+
+ /* Analyze the value */
+ switch ((x / y))
+ {
+ case 0:
+ case 1:
+ {
+ likert_color = TERM_RED;
+ return ("Bad");
+ }
+ case 2:
+ {
+ likert_color = TERM_L_RED;
+ return ("Poor");
+ }
+ case 3:
+ case 4:
+ {
+ likert_color = TERM_ORANGE;
+ return ("Fair");
+ }
+ case 5:
+ {
+ likert_color = TERM_YELLOW;
+ return ("Good");
+ }
+ case 6:
+ {
+ likert_color = TERM_YELLOW;
+ return ("Very Good");
+ }
+ case 7:
+ case 8:
+ {
+ likert_color = TERM_L_GREEN;
+ return ("Excellent");
+ }
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ {
+ likert_color = TERM_GREEN;
+ return ("Superb");
+ }
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ {
+ likert_color = TERM_L_GREEN;
+ return ("Heroic");
+ }
+ default:
+ {
+ likert_color = TERM_L_GREEN;
+ sprintf(dummy, "Legendary[%d]", (int)((((x / y) - 17) * 5) / 2));
+ return dummy;
+ }
+ }
+}
+
+
+/*
+ * Prints ratings on certain abilities
+ *
+ * This code is "imitated" elsewhere to "dump" a character sheet.
+ */
+static void display_player_various(void)
+{
+ int tmp, tmp2, damdice, damsides, dambonus, blows;
+ int xthn, xthb, xfos, xsrh;
+ int xdis, xdev, xsav, xstl;
+ cptr desc;
+ int i;
+
+ object_type *o_ptr;
+
+
+ /* Fighting Skill (with current weapon) */
+ o_ptr = &p_ptr->inventory[INVEN_WIELD];
+ tmp = p_ptr->to_h + o_ptr->to_h + p_ptr->to_h_melee;
+ xthn = p_ptr->skill_thn + (tmp * BTH_PLUS_ADJ);
+
+ /* Shooting Skill (with current bow and normal missile) */
+ o_ptr = &p_ptr->inventory[INVEN_BOW];
+ tmp = p_ptr->to_h + o_ptr->to_h + p_ptr->to_h_ranged;
+ xthb = p_ptr->skill_thb + (tmp * BTH_PLUS_ADJ);
+
+ /* variables for all types of melee damage */
+ dambonus = p_ptr->dis_to_d;
+ blows = p_ptr->num_blow;
+
+ /* Basic abilities */
+ xdis = p_ptr->skill_dis;
+ xdev = p_ptr->skill_dev;
+ xsav = p_ptr->skill_sav;
+ xstl = p_ptr->skill_stl;
+ xsrh = p_ptr->skill_srh;
+ xfos = p_ptr->skill_fos;
+
+
+ put_str("Fighting :", 16, 1);
+ desc = likert(xthn, 12);
+ c_put_str(likert_color, desc, 16, 15);
+
+ put_str("Bows/Throw :", 17, 1);
+ desc = likert(xthb, 12);
+ c_put_str(likert_color, desc, 17, 15);
+
+ put_str("Saving Throw:", 18, 1);
+ desc = likert(xsav, 6);
+ c_put_str(likert_color, desc, 18, 15);
+
+ put_str("Stealth :", 19, 1);
+ desc = likert(xstl, 1);
+ c_put_str(likert_color, desc, 19, 15);
+
+
+ put_str("Perception :", 16, 28);
+ desc = likert(xfos, 6);
+ c_put_str(likert_color, desc, 16, 42);
+
+ put_str("Searching :", 17, 28);
+ desc = likert(xsrh, 6);
+ c_put_str(likert_color, desc, 17, 42);
+
+ put_str("Disarming :", 18, 28);
+ desc = likert(xdis, 8);
+ c_put_str(likert_color, desc, 18, 42);
+
+ put_str("Magic Device:", 19, 28);
+ desc = likert(xdev, 6);
+ c_put_str(likert_color, desc, 19, 42);
+
+
+ put_str("Blows/Round:", 16, 55);
+ put_str(format("%d", p_ptr->num_blow), 16, 69);
+
+ put_str("Shots/Round:", 17, 55);
+ put_str(format("%d", p_ptr->num_fire), 17, 69);
+
+ put_str("Mel.dmg/Rnd:", 18, 55); /* From PsiAngband */
+
+ if (p_ptr->melee_style == SKILL_HAND || p_ptr->melee_style == SKILL_BEAR)
+ {
+ /* This is all based on py_attack_hand */
+ martial_arts *blow_table, *min_attack, *max_attack;
+ int max_blow, plev, i;
+
+ if (p_ptr->melee_style == SKILL_HAND)
+ {
+ blow_table = ma_blows;
+ max_blow = MAX_MA;
+ plev = get_skill(SKILL_HAND);
+ }
+ else /* SKILL_BEAR */
+ {
+ blow_table = bear_blows;
+ max_blow = MAX_BEAR;
+ plev = get_skill(SKILL_BEAR);
+ }
+ min_attack = blow_table;
+ i = max_blow - 1;
+ while (blow_table[i].min_level > plev && i != 0)
+ --i;
+ max_attack = &blow_table[i];
+
+ dambonus += p_ptr->to_d_melee;
+ tmp = min_attack->dd + dambonus;
+ if (tmp < 0) tmp = 0;
+ tmp2 = maxroll(max_attack->dd, max_attack->ds) + dambonus;
+ if (tmp2 < 0) tmp2 = 0;
+ if (!tmp && !tmp2)
+ desc = "0";
+ else
+ desc = format("%d-%d", blows * tmp, blows * tmp2);
+ }
+ else if (!r_info[p_ptr->body_monster].body_parts[BODY_WEAPON])
+ {
+ if (r_info[p_ptr->body_monster].flags1 & RF1_NEVER_BLOW)
+ desc = "nil!";
+ else
+ {
+ tmp = tmp2 = 0;
+ for (i = 0; i < blows; i++)
+ {
+ tmp += r_info[p_ptr->body_monster].blow[i].d_dice;
+ tmp2 += maxroll(r_info[p_ptr->body_monster].blow[i].d_dice,
+ r_info[p_ptr->body_monster].blow[i].d_side);
+ }
+ if (dambonus > 0)
+ {
+ tmp += dambonus;
+ tmp2 += dambonus;
+ }
+ desc = format("%d-%d", tmp, tmp2);
+ }
+ }
+ else
+ {
+ /* Increase the bonus to damage for weapon combat */
+ dambonus += p_ptr->to_d_melee;
+
+ /* Access the first weapon */
+ o_ptr = &p_ptr->inventory[INVEN_WIELD];
+
+ if (object_known_p(o_ptr)) dambonus += o_ptr->to_d;
+
+ damdice = o_ptr->dd;
+ damsides = o_ptr->ds;
+
+ if ((damdice == 0) || (damsides == 0))
+ {
+ if (dambonus <= 0)
+ desc = "nil!";
+ else
+ desc = format("%d", blows * dambonus);
+ }
+ else
+ {
+ if (dambonus == 0)
+ desc = format("%dd%d", blows * damdice, damsides);
+ else
+ desc = format("%dd%d%c%d", blows * damdice, damsides,
+ ( dambonus > 0 ? '+' : '\0' ), blows * dambonus );
+ }
+ }
+ put_str(desc, 18, 69);
+
+
+ put_str("Infra-Vision:", 19, 55);
+ put_str(format("%d feet", p_ptr->see_infra * 10), 19, 69);
+
+ /* jk - add tactic */
+ put_str("Tactic:", 20, 55);
+ c_put_str(TERM_L_BLUE, tactic_info[(byte)p_ptr->tactic].name, 20, 69);
+
+ /* jk - add movement */
+ put_str("Explor:", 21, 55);
+ c_put_str(TERM_L_BLUE, move_info[(byte)p_ptr->movement].name, 21, 69);
+}
+
+
+
+/*
+ * Obtain the "flags" of the wielded symbiote
+ */
+
+void wield_monster_flags(u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp)
+{
+ object_type *o_ptr;
+ monster_race *r_ptr;
+
+ /* Clear */
+ (*f1) = (*f2) = (*f3) = (*f4) = (*f5) = (*esp) = 0L;
+
+ /* Get the carried monster */
+ o_ptr = &p_ptr->inventory[INVEN_CARRY];
+
+ if (o_ptr->k_idx)
+ {
+ r_ptr = &r_info[o_ptr->pval];
+
+ if (r_ptr->flags2 & RF2_INVISIBLE)
+ (*f2) |= TR2_INVIS;
+ if (r_ptr->flags2 & RF2_REFLECTING)
+ (*f2) |= TR2_REFLECT;
+ if (r_ptr->flags7 & RF7_CAN_FLY)
+ (*f3) |= TR3_FEATHER;
+ if (r_ptr->flags7 & RF7_AQUATIC)
+ (*f5) |= TR5_WATER_BREATH;
+ }
+}
+
+
+/*
+ * Obtain the "flags" for the player as if he was an item
+ */
+void player_flags(u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp)
+{
+ int i;
+
+ /* Clear */
+ (*f1) = (*f2) = (*f3) = (*f4) = (*f5) = (*esp) = 0L;
+
+ /* Astral chars */
+ if (p_ptr->astral)
+ {
+ (*f3) |= TR3_WRAITH;
+ }
+
+/* Skills */
+ if (get_skill(SKILL_DAEMON) > 20) (*f2) |= TR2_RES_CONF;
+ if (get_skill(SKILL_DAEMON) > 30) (*f2) |= TR2_RES_FEAR;
+ if (get_skill(SKILL_MINDCRAFT) >= 40) (*esp) |= ESP_ALL;
+ if (p_ptr->melee_style == SKILL_HAND && get_skill(SKILL_HAND) > 24 && !monk_heavy_armor())
+ (*f2) |= TR2_FREE_ACT;
+/* Hack - from Lua */
+ if (get_skill(SKILL_MANA) >= 35) (*f1) |= TR1_MANA;
+ if (get_skill(SKILL_AIR) >= 50) (*f5) |= (TR5_MAGIC_BREATH | TR5_WATER_BREATH);
+ if (get_skill(SKILL_WATER) >= 30) (*f5) |= TR5_WATER_BREATH;
+
+/* Gods */
+ GOD(GOD_ERU)
+ {
+ if ((p_ptr->grace >= 100) || (p_ptr->grace <= -100)) (*f1) |= TR1_MANA;
+ if (p_ptr->grace > 10000) (*f1) |= TR1_WIS;
+ }
+
+ GOD(GOD_MELKOR)
+ {
+ (*f2) |= TR2_RES_FIRE;
+ if (p_ptr->melkor_sacrifice > 0) (*f2) |= TR2_LIFE;
+ if (p_ptr->grace > 10000) (*f1) |= (TR1_STR | TR1_CON | TR1_INT | TR1_WIS | TR1_CHR);
+ PRAY_GOD(GOD_MELKOR)
+ {
+ if (p_ptr->grace > 5000) (*f2) |= TR2_INVIS;
+ if (p_ptr->grace > 15000) (*f2) |= TR2_IM_FIRE;
+ }
+ }
+
+ GOD(GOD_MANWE)
+ {
+ if (p_ptr->grace >= 2000) (*f3) |= TR3_FEATHER;
+ PRAY_GOD(GOD_MANWE)
+ {
+ if (p_ptr->grace >= 7000) (*f2) |= TR2_FREE_ACT;
+ if (p_ptr->grace >= 15000) (*f4) |= TR4_FLY;
+ if ((p_ptr->grace >= 5000) || (p_ptr->grace <= -5000)) (*f1) |= TR1_SPEED;
+ }
+ }
+
+ GOD(GOD_TULKAS)
+ {
+ if (p_ptr->grace > 5000) (*f1) |= TR1_CON;
+ if (p_ptr->grace > 10000) (*f1) |= TR1_STR;
+ }
+
+ /* Classes */
+ for (i = 1; i <= p_ptr->lev; i++)
+ {
+ (*f1) |= cp_ptr->oflags1[i];
+ (*f2) |= cp_ptr->oflags2[i];
+ (*f3) |= cp_ptr->oflags3[i];
+ (*f4) |= cp_ptr->oflags4[i];
+ (*f5) |= cp_ptr->oflags5[i];
+ (*esp) |= cp_ptr->oesp[i];
+ }
+
+ /* Races */
+ if ((!p_ptr->mimic_form) && (!p_ptr->body_monster))
+ {
+ for (i = 1; i <= p_ptr->lev; i++)
+ {
+ (*f1) |= rp_ptr->oflags1[i];
+ (*f2) |= rp_ptr->oflags2[i];
+ (*f3) |= rp_ptr->oflags3[i];
+ (*f4) |= rp_ptr->oflags4[i];
+ (*f5) |= rp_ptr->oflags5[i];
+ (*esp) |= rp_ptr->oesp[i];
+
+ (*f1) |= rmp_ptr->oflags1[i];
+ (*f2) |= rmp_ptr->oflags2[i];
+ (*f3) |= rmp_ptr->oflags3[i];
+ (*f4) |= rmp_ptr->oflags4[i];
+ (*f5) |= rmp_ptr->oflags5[i];
+ (*esp) |= rmp_ptr->oesp[i];
+ }
+ }
+ else
+ {
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+ if (r_ptr->flags2 & RF2_REFLECTING) (*f2) |= TR2_REFLECT;
+ if (r_ptr->flags2 & RF2_REGENERATE) (*f3) |= TR3_REGEN;
+ if (r_ptr->flags2 & RF2_AURA_FIRE) (*f3) |= TR3_SH_FIRE;
+ if (r_ptr->flags2 & RF2_AURA_ELEC) (*f3) |= TR3_SH_ELEC;
+ if (r_ptr->flags2 & RF2_PASS_WALL) (*f3) |= TR3_WRAITH;
+ if (r_ptr->flags3 & RF3_SUSCEP_FIRE) (*f2) |= TR2_SENS_FIRE;
+ if (r_ptr->flags3 & RF3_IM_ACID) (*f2) |= TR2_RES_ACID;
+ if (r_ptr->flags3 & RF3_IM_ELEC) (*f2) |= TR2_RES_ELEC;
+ if (r_ptr->flags3 & RF3_IM_FIRE) (*f2) |= TR2_RES_FIRE;
+ if (r_ptr->flags3 & RF3_IM_POIS) (*f2) |= TR2_RES_POIS;
+ if (r_ptr->flags3 & RF3_IM_COLD) (*f2) |= TR2_RES_COLD;
+ if (r_ptr->flags3 & RF3_RES_NETH) (*f2) |= TR2_RES_NETHER;
+ if (r_ptr->flags3 & RF3_RES_NEXU) (*f2) |= TR2_RES_NEXUS;
+ if (r_ptr->flags3 & RF3_RES_DISE) (*f2) |= TR2_RES_DISEN;
+ if (r_ptr->flags3 & RF3_NO_FEAR) (*f2) |= TR2_RES_FEAR;
+ if (r_ptr->flags3 & RF3_NO_SLEEP) (*f2) |= TR2_FREE_ACT;
+ if (r_ptr->flags3 & RF3_NO_CONF) (*f2) |= TR2_RES_CONF;
+ if (r_ptr->flags7 & RF7_CAN_FLY) (*f3) |= TR3_FEATHER;
+ }
+
+ (*f1) |= p_ptr->xtra_f1;
+ (*f2) |= p_ptr->xtra_f2;
+ (*f3) |= p_ptr->xtra_f3;
+ (*f4) |= p_ptr->xtra_f4;
+ (*f5) |= p_ptr->xtra_f5;
+ (*esp) |= p_ptr->xtra_esp;
+
+ if (p_ptr->black_breath)
+ {
+ (*f4) |= TR4_BLACK_BREATH;
+ }
+
+ if (p_ptr->hp_mod != 0)
+ {
+ (*f2) |= TR2_LIFE;
+ }
+}
+
+/*
+ * Object flag names
+ */
+static cptr object_flag_names[192] =
+{
+ "Add Str",
+ "Add Int",
+ "Add Wis",
+ "Add Dex",
+ "Add Con",
+ "Add Chr",
+ "Mul Mana",
+ "Mul SPower",
+ "Add Stea.",
+ "Add Sear.",
+ "Add Infra",
+ "Add Tun..",
+ "Add Speed",
+ "Add Blows",
+ "Chaotic",
+ "Vampiric",
+ "Slay Anim.",
+ "Slay Evil",
+ "Slay Und.",
+ "Slay Demon",
+ "Slay Orc",
+ "Slay Troll",
+ "Slay Giant",
+ "Slay Drag.",
+ "Kill Drag.",
+ "Sharpness",
+ "Impact",
+ "Poison Brd",
+ "Acid Brand",
+ "Elec Brand",
+ "Fire Brand",
+ "Cold Brand",
+
+ "Sust Str",
+ "Sust Int",
+ "Sust Wis",
+ "Sust Dex",
+ "Sust Con",
+ "Sust Chr",
+ "Invisible",
+ "Mul life",
+ "Imm Acid",
+ "Imm Elec",
+ "Imm Fire",
+ "Imm Cold",
+ "Sens Fire",
+ "Reflect",
+ "Free Act",
+ "Hold Life",
+ "Res Acid",
+ "Res Elec",
+ "Res Fire",
+ "Res Cold",
+ "Res Pois",
+ "Res Fear",
+ "Res Light",
+ "Res Dark",
+ "Res Blind",
+ "Res Conf",
+ "Res Sound",
+ "Res Shard",
+ "Res Neth",
+ "Res Nexus",
+ "Res Chaos",
+ "Res Disen",
+
+
+
+ "Aura Fire",
+ "Aura Elec",
+ "Auto Curse",
+ NULL,
+ "NoTeleport",
+ "AntiMagic",
+ "WraithForm",
+ "EvilCurse",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Levitate",
+ "Lite",
+ "See Invis",
+ NULL,
+ "Digestion",
+ "Regen",
+ "Xtra Might",
+ "Xtra Shots",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Activate",
+ "Drain Exp",
+ "Teleport",
+ "Aggravate",
+ "Blessed",
+ "Cursed",
+ "Hvy Curse",
+ "Prm Curse",
+
+ "No blows",
+ "Precogn.",
+ "B.Breath",
+ "Recharge",
+ "Fly",
+ "Mrg.Curse",
+ NULL,
+ NULL,
+ "Sentient",
+ "Clone",
+ NULL,
+ "Climb",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Imm Neth",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ "Orc.ESP",
+ "Troll.ESP",
+ "Dragon.ESP",
+ "Giant.ESP",
+ "Demon.ESP",
+ "Undead.ESP",
+ "Evil.ESP",
+ "Animal.ESP",
+ "TLord.ESP",
+ "Good.ESP",
+ "Nlive.ESP",
+ "Unique.ESP",
+ "Spider ESP",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Full ESP",
+};
+
+/*
+ * Summarize resistances
+ */
+static void display_player_ben_one(int mode)
+{
+ int i, n, x, y, z, dispx, modetemp, xtemp;
+
+ object_type *o_ptr;
+
+ char dummy[80], c;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ u16b b[INVEN_TOTAL - INVEN_WIELD + 1][10];
+
+ int d[INVEN_TOTAL - INVEN_WIELD + 1];
+
+ bool_ got;
+
+ byte a;
+
+ cptr name;
+
+ /* Scan equipment */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ /* Index */
+ n = (i - INVEN_WIELD);
+
+ /* Object */
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Known object flags */
+ object_flags_known(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Incorporate */
+ b[n][0] = (u16b)(f1 & 0xFFFF);
+ b[n][1] = (u16b)(f1 >> 16);
+ b[n][2] = (u16b)(f2 & 0xFFFF);
+ b[n][3] = (u16b)(f2 >> 16);
+ b[n][4] = (u16b)(f3 & 0xFFFF);
+ b[n][5] = (u16b)(f3 >> 16);
+ b[n][6] = (u16b)(f4 & 0xFFFF);
+ b[n][7] = (u16b)(f4 >> 16);
+ b[n][8] = (u16b)(esp & 0xFFFF);
+ b[n][9] = (u16b)(esp >> 16);
+ d[n] = o_ptr->pval;
+ }
+
+ /* Carried symbiote */
+ n = INVEN_CARRY - INVEN_WIELD;
+
+ /* Player flags */
+ wield_monster_flags(&f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Incorporate */
+ b[n][0] = (u16b)(f1 & 0xFFFF);
+ b[n][1] = (u16b)(f1 >> 16);
+ b[n][2] = (u16b)(f2 & 0xFFFF);
+ b[n][3] = (u16b)(f2 >> 16);
+ b[n][4] = (u16b)(f3 & 0xFFFF);
+ b[n][5] = (u16b)(f3 >> 16);
+ b[n][6] = (u16b)(f4 & 0xFFFF);
+ b[n][7] = (u16b)(f4 >> 16);
+ b[n][8] = (u16b)(esp & 0xFFFF);
+ b[n][9] = (u16b)(esp >> 16);
+
+ /* Index */
+ n = INVEN_TOTAL - INVEN_WIELD;
+
+ /* Player flags */
+ player_flags(&f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Incorporate */
+ b[n][0] = (u16b)(f1 & 0xFFFF);
+ b[n][1] = (u16b)(f1 >> 16);
+ b[n][2] = (u16b)(f2 & 0xFFFF);
+ b[n][3] = (u16b)(f2 >> 16);
+ b[n][4] = (u16b)(f3 & 0xFFFF);
+ b[n][5] = (u16b)(f3 >> 16);
+ b[n][6] = (u16b)(f4 & 0xFFFF);
+ b[n][7] = (u16b)(f4 >> 16);
+ b[n][8] = (u16b)(esp & 0xFFFF);
+ b[n][9] = (u16b)(esp >> 16);
+
+ /* Generate the equip chars */
+ sprintf(dummy, " ");
+ for (i = 0; i < INVEN_TOTAL - INVEN_WIELD; i++)
+ {
+ /* If you have that body part then show it */
+ if (p_ptr->body_parts[i])
+ {
+ strcat(dummy, format("%c", i + 'a'));
+ }
+ }
+ strcat(dummy, "@");
+
+ /* Scan cols */
+ for (x = 1; x > -1; x--)
+ {
+ /* Label */
+ Term_putstr(x * 40 + 11, 3, -1, TERM_WHITE, dummy);
+
+ /* Scan rows */
+ for (y = 0; y < 16; y++)
+ {
+ if (mode == 3 && x == 1)
+ {
+ modetemp = 4;
+ xtemp = 0;
+ }
+ else
+ {
+ modetemp = mode;
+ xtemp = x;
+ }
+
+ for (z = mode; z <= modetemp; z++)
+ {
+ if (mode == 3 && x == 1 && z == modetemp) xtemp = 1;
+ name = object_flag_names[32 * modetemp + 16 * xtemp + y];
+ got = FALSE;
+
+ /* No name */
+ if (!name) continue;
+
+ /* Dump colon */
+ if (!(modetemp == 1 && x == 0 && y > 7 && y < 12))
+ {
+ Term_putch(x * 40 + 10, y + 4, TERM_WHITE, ':');
+ }
+
+ /* Check flags */
+ dispx = 0;
+ for (n = 0; n < INVEN_TOTAL - INVEN_WIELD + 1; n++)
+ {
+ /* Change colour every two columns */
+ bool_ is_green = (dispx & 0x02);
+ a = (is_green ? TERM_GREEN : TERM_SLATE);
+ c = '.';
+
+ /* If the body part doesn't exists then skip it :) */
+ if ((n < INVEN_TOTAL - INVEN_WIELD) && (!p_ptr->body_parts[n])) continue;
+
+ /* Increment the drawing coordinates */
+ dispx++;
+
+ /* Check flag */
+ if (b[n][2 * modetemp + xtemp] & (1 << y))
+ {
+ a = (is_green ? TERM_L_GREEN : TERM_WHITE);
+ if (modetemp == 1 && x == 0 && y > 7 && y < 12)
+ {
+ c = '*';
+ }
+ else if (modetemp == 0 && x == 0 && y < 14 && (y < 6 || y > 7))
+ {
+ if (n == INVEN_TOTAL - INVEN_WIELD)
+ {
+ c = '+';
+ }
+ else
+ {
+ c = d[n];
+ if (c < 0)
+ {
+ c = -c;
+ a = TERM_RED;
+ }
+ c = (c > 9 ? '*' : I2D(c));
+ }
+ }
+ else
+ {
+ c = '+';
+ }
+ got = TRUE;
+ }
+
+ /* HACK - Check for nether immunity and
+ apply to Res Neth line */
+ if (modetemp == 1 && x == 1 && y == 12)
+ {
+ if (b[n][7] & (1 << 6))
+ {
+ a = (is_green ? TERM_L_GREEN : TERM_WHITE);
+ c = '*';
+ got = TRUE;
+ }
+ }
+
+ /* Dump flag */
+ if (modetemp == 1 && x == 0 && y > 7 && y < 12)
+ {
+ if (c == '*') Term_putch(40 + 11 + dispx, y - 4, a, c);
+ }
+ else
+ {
+ Term_putch(x * 40 + 11 + dispx, y + 4, a, c);
+ }
+ }
+
+ a = TERM_WHITE;
+ if (got)
+ {
+ if (modetemp == 1 && x == 0 && y > 7 && y < 12)
+ {
+ a = TERM_L_GREEN;
+ }
+ else if (modetemp != 0)
+ {
+ a = TERM_GREEN;
+ }
+ }
+
+ /* HACK - Check for nether immunity and change "Res Neth" */
+ if (modetemp == 1 && x == 1 && y == 12 && p_ptr->immune_neth)
+ {
+ name = "Imm Neth";
+ a = TERM_L_GREEN;
+ }
+
+ /* Dump name */
+ if (modetemp == 1 && x == 0 && y > 7 && y < 12)
+ {
+ if (got) Term_putstr(40, y - 4, -1, a, name);
+ }
+ else
+ {
+ Term_putstr(x * 40, y + 4, -1, a, name);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Display the character on the screen (various modes)
+ *
+ * The top two and bottom two lines are left blank.
+ *
+ * Mode 0 = standard display with skills
+ * Mode 1 = standard display with history
+ * Mode 2 = current flags (part 1)
+ * Mode 3 = current flags (part 2)
+ * Mode 4 = current flags (part 3)
+ * Mode 5 = current flags (part 4)
+ * Mode 6 = current flags (part 5 -- esp)
+ */
+void display_player(int mode)
+{
+ int i;
+
+ char buf[80];
+
+
+ /* Erase screen */
+ clear_from(0);
+
+ /* Standard */
+ if ((mode == 0) || (mode == 1))
+ {
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+ /* Name, Sex, Race, Class */
+ put_str("Name :", 2, 1);
+ put_str("Sex :", 3, 1);
+ put_str("Race :", 4, 1);
+ put_str("Class :", 5, 1);
+ put_str("Body :", 6, 1);
+ put_str("God :", 7, 1);
+ c_put_str(TERM_L_BLUE, player_name, 2, 9);
+ if (p_ptr->body_monster != 0)
+ {
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+ char tmp[12];
+
+ if ((r_ptr->flags1 & RF1_MALE) != 0)
+ strcpy(tmp, "Male");
+ else if ((r_ptr->flags1 & RF1_FEMALE) != 0)
+ strcpy(tmp, "Female");
+ else
+ strcpy(tmp, "Neuter");
+ c_put_str(TERM_L_BLUE, tmp, 3, 9);
+ }
+ else
+ c_put_str(TERM_L_BLUE, sp_ptr->title, 3, 9);
+ sprintf(buf, "%s", get_player_race_name(p_ptr->prace, p_ptr->pracem));
+ c_put_str(TERM_L_BLUE, buf, 4, 9);
+ c_put_str(TERM_L_BLUE, spp_ptr->title + c_name, 5, 9);
+ c_put_str(TERM_L_BLUE, r_name + r_ptr->name, 6, 9);
+ c_put_str(TERM_L_BLUE, deity_info[p_ptr->pgod].name, 7, 9);
+
+ /* Age, Height, Weight, Social */
+ prt_num("Age ", (int)p_ptr->age + bst(YEAR, turn - (START_DAY * 10)), 2, 32, TERM_L_BLUE, " ");
+ prt_num("Height ", (int)p_ptr->ht, 3, 32, TERM_L_BLUE, " ");
+ prt_num("Weight ", (int)p_ptr->wt, 4, 32, TERM_L_BLUE, " ");
+ prt_num("Social Class ", (int)p_ptr->sc, 5, 32, TERM_L_BLUE, " ");
+
+ /* Display the stats */
+ for (i = 0; i < 6; i++)
+ {
+ char punctuation = p_ptr->stat_max[i] == 18 + 100 ? '!' : ':';
+ /* Special treatment of "injured" stats */
+ if (p_ptr->stat_cur[i] < p_ptr->stat_max[i])
+ {
+ int value;
+ int colour;
+
+ if (p_ptr->stat_cnt[i])
+ colour = TERM_ORANGE;
+ else
+ colour = TERM_YELLOW;
+
+ /* Use lowercase stat name */
+ put_str(format("%s%c ", stat_names_reduced[i], punctuation), 2 + i, 61);
+
+ /* Get the current stat */
+ value = p_ptr->stat_use[i];
+
+ /* Obtain the current stat (modified) */
+ cnv_stat(value, buf);
+
+ /* Display the current stat (modified) */
+ c_put_str(colour, buf, 2 + i, 66);
+
+ /* Acquire the max stat */
+ value = p_ptr->stat_top[i];
+
+ /* Obtain the maximum stat (modified) */
+ cnv_stat(value, buf);
+
+ /* Display the maximum stat (modified) */
+ c_put_str(TERM_L_GREEN, buf, 2 + i, 73);
+ }
+
+ /* Normal treatment of "normal" stats */
+ else
+ {
+ /* Assume uppercase stat name */
+ put_str(format("%s%c ", stat_names[i], punctuation), 2 + i, 61);
+
+ /* Obtain the current stat (modified) */
+ cnv_stat(p_ptr->stat_use[i], buf);
+
+ /* Display the current stat (modified) */
+ c_put_str(TERM_L_GREEN, buf, 2 + i, 66);
+ }
+ }
+
+ /* Extra info */
+ display_player_middle();
+
+ /* Display "history" info */
+ if (mode == 1)
+ {
+ put_str("(Character Background)", 15, 25);
+
+ for (i = 0; i < 4; i++)
+ {
+ put_str(history[i], i + 16, 10);
+ }
+ }
+
+ /* Display "various" info */
+ else
+ {
+ put_str("(Miscellaneous Abilities)", 15, 25);
+
+ display_player_various();
+ }
+ }
+
+ /* Special */
+ else
+ {
+ display_player_ben_one(mode - 2);
+ }
+}
+
+/*
+ * Utility function; should probably be in some other file...
+ *
+ * Describe the player's location -- either by dungeon level, town, or in
+ * wilderness with landmark reference.
+ */
+cptr describe_player_location()
+{
+ int i;
+ static char desc[80];
+ int pwx = (p_ptr->wild_mode ? p_ptr->px : p_ptr->wilderness_x);
+ int pwy = (p_ptr->wild_mode ? p_ptr->py : p_ptr->wilderness_y);
+ int feat = wild_map[pwy][pwx].feat;
+
+ if (dungeon_type != DUNGEON_WILDERNESS && dun_level > 0)
+ sprintf(desc, "on level %d of %s", dun_level, d_info[dungeon_type].name + d_name);
+ else if (wf_info[feat].terrain_idx == TERRAIN_TOWN)
+ sprintf(desc, "in the town of %s", wf_info[feat].name + wf_name);
+ else if (wf_info[feat].entrance)
+ sprintf(desc, "near %s", wf_info[feat].name + wf_name);
+ else
+ {
+ /*
+ * The complicated case. Find the nearest known landmark,
+ * and describe our position relative to that. Note that
+ * we may not even have any known landmarks (for instance,
+ * a Lost Soul character just after escaping the Halls of
+ * Mandos).
+ */
+ int landmark = 0, lwx = 0, lwy = 0;
+ int l_dist = -1;
+ int i;
+
+ for (i = 0; i < max_wf_idx; i++)
+ {
+ int wx = wf_info[i].wild_x;
+ int wy = wf_info[i].wild_y;
+ int dist;
+
+ /* Skip if not a landmark */
+ if (!wf_info[i].entrance) continue;
+
+ /* Skip if we haven't seen it */
+ if (!wild_map[wy][wx].known) continue;
+
+ dist = distance(wy, wx, pwy, pwx);
+ if (dist < l_dist || l_dist < 0)
+ {
+ landmark = i;
+ l_dist = dist;
+ lwx = wx;
+ lwy = wy;
+ }
+ }
+
+ if (!landmark)
+ sprintf(desc, "in %s", wf_info[feat].text + wf_text);
+ else if (pwx == lwx && pwy == lwy)
+ /* Paranoia; this should have been caught above */
+ sprintf(desc, "near %s", wf_info[feat].name + wf_name);
+ else
+ {
+ /*
+ * We split the circle into eight equal octants of
+ * size pi/4 radians; the "east" octant, for
+ * instance, is defined as due east plus or minus
+ * pi/8 radians. Now sin(pi/8) ~= 0.3826 ~= 31/81,
+ * so we check |dx|/|dy| and |dy|/|dx| against that
+ * ratio to determine which octant we're in.
+ */
+ int dx = pwx - lwx;
+ int dy = pwy - lwy;
+ cptr ns = (dy > 0 ? "south" : "north");
+ cptr ew = (dx > 0 ? "east" : "west");
+
+ dx = (dx < 0 ? -dx : dx);
+ dy = (dy < 0 ? -dy : dy);
+ if (dy * 81 < dx * 31) ns = "";
+ if (dx * 81 < dy * 31) ew = "";
+
+ sprintf(desc, "in %s %s%s of %s",
+ wf_info[feat].text + wf_text, ns, ew,
+ wf_info[landmark].name + wf_name);
+ }
+ }
+
+ /* strip trailing whitespace */
+ for (i = 0; desc[i]; ++i);
+ while (desc[--i] == ' ')
+ desc[i] = 0;
+
+ return desc;
+}
+
+/*
+ * Helper function or file_character_print_grid
+ *
+ * Figure out if a row on the grid is empty
+ */
+static bool_ file_character_print_grid_check_row(const char *buf)
+{
+ if (strstr(buf + 12, "+")) return TRUE;
+ if (strstr(buf + 12, "*")) return TRUE;
+ if (strstr(buf + 12, "1")) return TRUE;
+ if (strstr(buf + 12, "2")) return TRUE;
+ if (strstr(buf + 12, "3")) return TRUE;
+ if (strstr(buf + 12, "4")) return TRUE;
+ if (strstr(buf + 12, "5")) return TRUE;
+ if (strstr(buf + 12, "6")) return TRUE;
+ if (strstr(buf + 12, "7")) return TRUE;
+ if (strstr(buf + 12, "8")) return TRUE;
+ if (strstr(buf + 12, "9")) return TRUE;
+ return FALSE;
+}
+
+/*
+ * Helper function for file_character
+ *
+ * Prints the big ugly grid
+ */
+static void file_character_print_grid(FILE *fff, bool_ show_gaps, bool_ show_legend)
+{
+ static cptr blank_line = " ";
+ static char buf[1024];
+ byte a;
+ char c;
+ int x, y;
+
+ y = show_legend ? 3 : 4;
+ for (; y < 23; y++)
+ {
+ for (x = 0; x < 40; x++)
+ {
+ (void)(Term_what(x, y, &a, &c));
+ buf[x] = c;
+ }
+
+ buf[x] = '\0';
+ if (strcmp(buf, blank_line) &&
+ (y == 3 || show_gaps || file_character_print_grid_check_row(buf)))
+ fprintf (fff, " %s\n", buf);
+ }
+ for (y = 4; y < 23; y++)
+ {
+ for (x = 40; x < 80; x++)
+ {
+ (void)(Term_what(x, y, &a, &c));
+ buf[x - 40] = c;
+ }
+
+ buf[x] = '\0';
+ if (strcmp(buf, blank_line) &&
+ (show_gaps || file_character_print_grid_check_row(buf)))
+ fprintf (fff, " %s\n", buf);
+ }
+}
+
+/*
+ * Helper function for file_character
+ *
+ * Outputs one item (for Inventory, Equipment, Home, and Mathom-house)
+ */
+void file_character_print_item(FILE *fff, char label, object_type *obj, bool_ full)
+{
+ static char o_name[80];
+ static cptr paren = ")";
+ object_desc(o_name, obj, TRUE, 3);
+ fprintf(fff, "%c%s %s\n", label, paren, o_name);
+
+ if ((artifact_p(obj) || ego_item_p(obj) || obj->tval == TV_RING || obj->tval == TV_AMULET || full) &&
+ (obj->ident & IDENT_MENTAL))
+ {
+ object_out_desc(obj, fff, TRUE, TRUE);
+ }
+}
+
+/*
+ * Helper function for file_character
+ *
+ * Prints out one "store" (for Home and Mathom-house)
+ */
+void file_character_print_store(FILE *fff, wilderness_type_info *place, int store, bool_ full)
+{
+ int i;
+ town_type *town = &town_info[place->entrance];
+ store_type *st_ptr = &town->store[store];
+
+ if (st_ptr->stock_num)
+ {
+ /* Header with name of the town */
+ fprintf(fff, " [%s Inventory - %s]\n\n", st_name + st_info[store].name, wf_name + place->name);
+
+ /* Dump all available items */
+ for (i = 0; i < st_ptr->stock_num; i++)
+ {
+ file_character_print_item(fff, I2A(i%24), &st_ptr->stock[i], full);
+ }
+
+ /* Add an empty line */
+ fprintf(fff, "\n\n");
+ }
+}
+
+/*
+ * Helper function for file_character
+ *
+ * Checks if the store hasn't been added to the list yet, and then adds it if it
+ * was not already there. XXX This is an ugly workaround for the double Gondolin
+ * problem.
+ *
+ * Beware of the ugly pointer gymnastics.
+ */
+bool_ file_character_check_stores(store_type ***store_list, int *store_list_count, wilderness_type_info *place, int store)
+{
+ town_type *town = &town_info[place->entrance];
+ store_type *st_ptr = &town->store[store];
+ store_type **head = *store_list;
+ int i;
+
+ /* check the list for this store */
+ for (i = 0; i < *store_list_count; ++i)
+ {
+ if (*head == st_ptr) return FALSE;
+ ++head;
+ }
+
+ /* make room for the new one in the array */
+ if (*store_list)
+ {
+ head = *store_list;
+ *store_list = C_RNEW(*store_list_count + 1, store_type *);
+ C_COPY(*store_list, head, *store_list_count, store_type *);
+ C_FREE(head, *store_list_count, store_type *);
+ }
+ else
+ {
+ *store_list = RNEW(store_type *);
+ }
+
+ /* update data */
+ (*store_list)[*store_list_count] = st_ptr;
+ ++*store_list_count;
+
+ return TRUE;
+}
+
+/*
+ * Hack -- Dump a character description file
+ *
+ * XXX XXX XXX Allow the "full" flag to dump additional info,
+ * and trigger its usage from various places in the code.
+ */
+errr file_character(cptr name, bool_ full)
+{
+ int i, j, x, y;
+ byte a;
+ char c;
+ int fd = -1;
+ FILE *fff = NULL;
+ char buf[1024];
+ store_type **store_list = NULL;
+ int store_list_count = 0;
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, name);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Check for existing file */
+ fd = fd_open(buf, O_RDONLY);
+
+ /* Existing file */
+ if (fd >= 0)
+ {
+ char out_val[160];
+
+ /* Close the file */
+ (void)fd_close(fd);
+
+ /* Build query */
+ (void)sprintf(out_val, "Replace existing file %s? ", buf);
+
+ /* Ask */
+ if (get_check(out_val)) fd = -1;
+ }
+
+ /* Open the non-existing file */
+ if (fd < 0) fff = my_fopen(buf, "w");
+
+ /* Invalid file */
+ if (!fff)
+ {
+ /* Message */
+ msg_format("Character sheet creation failed!");
+ msg_print(NULL);
+
+ /* Error */
+ return ( -1);
+ }
+
+
+ /* Begin dump */
+ fprintf(fff, " [%s Character Sheet]\n\n", get_version_string());
+
+
+ /* Display player */
+ display_player(0);
+
+ /* Dump part of the screen */
+ for (y = 2; y < 22; y++)
+ {
+ /* Dump each row */
+ for (x = 0; x < 79; x++)
+ {
+ /* Get the attr/char */
+ (void)(Term_what(x, y, &a, &c));
+
+ /* Dump it */
+ buf[x] = c;
+ }
+
+ /* Terminate */
+ buf[x] = '\0';
+
+ /* End the row */
+ fprintf(fff, "%s\n", buf);
+ }
+
+ /* Display history */
+ display_player(1);
+
+ /* Dump part of the screen */
+ for (y = 15; y < 20; y++)
+ {
+ /* Dump each row */
+ for (x = 0; x < 79; x++)
+ {
+ /* Get the attr/char */
+ (void)(Term_what(x, y, &a, &c));
+
+ /* Dump it */
+ buf[x] = c;
+ }
+
+ /* Terminate */
+ buf[x] = '\0';
+
+ /* End the row */
+ fprintf(fff, "%s\n", buf);
+ }
+
+ /* List the patches */
+ hook_file = fff;
+ exec_lua("patchs_list()");
+
+ fprintf(fff, "\n\n [Miscellaneous information]\n");
+ if (joke_monsters)
+ fprintf(fff, "\n Joke monsters: ON");
+ else
+ fprintf(fff, "\n Joke monsters: OFF");
+
+ if (p_ptr->maximize)
+ fprintf(fff, "\n Maximize mode: ON");
+ else
+ fprintf(fff, "\n Maximize mode: OFF");
+
+ if (p_ptr->preserve)
+ fprintf(fff, "\n Preserve Mode: ON");
+ else
+ fprintf(fff, "\n Preserve Mode: OFF");
+
+ if (auto_scum)
+ fprintf(fff, "\n Autoscum: ON");
+ else
+ fprintf(fff, "\n Autoscum: OFF");
+
+ if (always_small_level)
+ fprintf(fff, "\n Small Levels: ALWAYS");
+ else if (small_levels)
+ fprintf(fff, "\n Small Levels: ON");
+ else
+ fprintf(fff, "\n Small Levels: OFF");
+
+ if (empty_levels)
+ fprintf(fff, "\n Arena Levels: ON");
+ else
+ fprintf(fff, "\n Arena Levels: OFF");
+
+ if (ironman_rooms)
+ fprintf(fff, "\n Always unusual rooms: ON");
+ else
+ fprintf(fff, "\n Always unusual rooms: OFF");
+
+ fprintf(fff, "\n\n Recall Depth:");
+ for (y = 1; y < max_d_idx; y++)
+ {
+ if (max_dlv[y])
+ fprintf(fff, "\n %s: Level %d (%d')",
+ d_name + d_info[y].name,
+ max_dlv[y], 50 * (max_dlv[y]));
+ }
+ fprintf(fff, "\n");
+
+ if (noscore)
+ fprintf(fff, "\n You have done something illegal.");
+
+ if (PRACE_FLAGS(PR1_EXPERIMENTAL))
+ fprintf(fff, "\n You have done something experimental.");
+
+ if (stupid_monsters)
+ fprintf(fff, "\n Your opponents are behaving stupidly.");
+
+ {
+ char desc[80];
+ cptr mimic;
+
+ monster_race_desc(desc, p_ptr->body_monster, 0);
+ fprintf(fff, "\n Your body %s %s.", (death ? "was" : "is"), desc);
+
+ if (p_ptr->tim_mimic)
+ {
+ call_lua("get_mimic_info", "(d,s)", "s", p_ptr->mimic_form, "name", &mimic);
+ fprintf(fff, "\n You %s disguised as a %s.", (death ? "were" : "are"), mimic);
+ }
+ }
+
+ /* Where we are, if we're alive */
+ if (!death) fprintf(fff, "\n You are currently %s.", describe_player_location());
+
+ /* Monsters slain */
+ {
+ int k;
+ s32b Total = 0;
+
+ for (k = 1; k < max_r_idx; k++)
+ {
+ monster_race *r_ptr = &r_info[k];
+
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ bool_ dead = (r_ptr->max_num == 0);
+ if (dead)
+ {
+ Total++;
+ }
+ }
+ else
+ {
+ s16b This = r_ptr->r_pkills;
+ if (This > 0)
+ {
+ Total += This;
+ }
+ }
+ }
+
+ if (Total < 1)
+ fprintf(fff, "\n You have defeated no enemies yet.");
+ else if (Total == 1)
+ fprintf(fff, "\n You have defeated one enemy.");
+ else
+ fprintf(fff, "\n You have defeated %ld enemies.", (long int) Total);
+ }
+
+ hook_file = fff;
+ process_hooks(HOOK_CHAR_DUMP, "()");
+
+ /* Date */
+ {
+ char buf2[20];
+ u32b days = bst(DAY, turn - (START_DAY * 10));
+
+ strnfmt(buf2, 20, get_day(bst(YEAR, START_DAY * 10) + START_YEAR));
+ fprintf(fff, "\n\n You started your adventure the %s of the %s year of the third age.",
+ get_month_name(bst(DAY, START_DAY * 10), wizard, FALSE), buf2);
+
+ strnfmt(buf2, 20, get_day(bst(YEAR, turn) + START_YEAR));
+ fprintf(fff, "\n %s the %s of the %s year of the third age.",
+ (death ? "You ended your adventure" : "It is currently"),
+ get_month_name(bst(DAY, turn), wizard, FALSE), buf2);
+ fprintf(fff,
+ (death ? "\n Your adventure lasted %ld day%s." : "\n You have been adventuring for %ld day%s."),
+ (long int) days, (days == 1) ? "" : "s");
+ }
+
+ fprintf (fff, "\n\n");
+
+ /* Emit the self-knowledge lines, even though they duplicate the
+ information in the grids (below), because they contain information
+ that's not in the grids (racial abilities, luck, etc.). */
+ if (full)
+ {
+ self_knowledge(fff);
+ fprintf(fff, "\n\n");
+ }
+
+ /* adds and slays */
+ display_player (2);
+ file_character_print_grid(fff, FALSE, TRUE);
+
+ /* sustains and resistances */
+ display_player (3);
+ file_character_print_grid(fff, TRUE, FALSE);
+
+ /* stuff */
+ display_player (4);
+ file_character_print_grid(fff, FALSE, FALSE);
+
+ /* a little bit of stuff */
+ display_player (5);
+ file_character_print_grid(fff, FALSE, FALSE);
+
+ /* Dump corruptions */
+ if (got_corruptions())
+ {
+ fprintf(fff, "\n Corruption list:\n");
+ dump_corruptions(fff, FALSE);
+ }
+
+ /* Dump skills */
+ dump_skills(fff);
+ dump_abilities(fff);
+
+ /* Dump companions. */
+ dump_companions(fff);
+
+ if (p_ptr->companion_killed)
+ {
+ if (p_ptr->companion_killed == 1)
+ fprintf(fff, "\n One of your companion(s) has been killed.");
+ else
+ fprintf(fff, "\n %d of your companions have been killed.", p_ptr->companion_killed);
+ }
+
+ for (i = 0; i < MAX_FATES; i++)
+ {
+ if ((fates[i].fate) && (fates[i].know))
+ {
+ fprintf(fff, "\n\n [Fates]\n\n");
+ dump_fates(fff);
+ break;
+ }
+ }
+
+ /* Skip some lines */
+ fprintf(fff, "\n\n");
+
+
+ /* Dump the equipment */
+ text_out_indent = 4;
+ if (equip_cnt)
+ {
+ fprintf(fff, " [Character Equipment]\n\n");
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ if (!p_ptr->body_parts[i - INVEN_WIELD]) continue;
+
+ file_character_print_item(fff, index_to_label(i), &p_ptr->inventory[i], full);
+ }
+ fprintf(fff, "\n\n");
+ }
+
+ /* Dump the inventory */
+ fprintf(fff, " [Character Inventory]\n\n");
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ file_character_print_item(fff, index_to_label(i), &p_ptr->inventory[i], full);
+ }
+ fprintf(fff, "\n\n");
+
+ /* Print all homes in the different towns */
+ for (j = 0; j < max_wf_idx; j++)
+ {
+ if (wf_info[j].feat == FEAT_TOWN &&
+ file_character_check_stores(&store_list, &store_list_count, &wf_info[j], 7))
+ file_character_print_store(fff, &wf_info[j], 7, full);
+ }
+ store_list = C_FREE(store_list, store_list_count, store_type *);
+ store_list_count = 0;
+
+ /* Print all Mathom-houses in the different towns */
+ for (j = 0; j < max_wf_idx; j++)
+ {
+ if (wf_info[j].feat == FEAT_TOWN &&
+ file_character_check_stores(&store_list, &store_list_count, &wf_info[j], 57))
+ file_character_print_store(fff, &wf_info[j], 57, full);
+ }
+ store_list = C_FREE(store_list, store_list_count, store_type *);
+ store_list_count = 0;
+
+ text_out_indent = 0;
+
+ /* Close it */
+ my_fclose(fff);
+
+
+ /* Message */
+ msg_print("Character sheet creation successful.");
+ msg_print(NULL);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Recursive file perusal.
+ *
+ * Return FALSE on "ESCAPE", otherwise TRUE.
+ *
+ * Process various special text in the input file, including
+ * the "menu" structures used by the "help file" system.
+ *
+ * XXX XXX XXX Consider using a temporary file.
+ *
+ * XXX XXX XXX Allow the user to "save" the current file.
+ */
+
+/*
+ * A structure to hold (some of == XXX) the hyperlink information.
+ * This prevents excessive use of stack.
+ */
+#define MAX_LINKS 1024
+struct hyperlink
+{
+ /* Path buffer */
+ char path[1024];
+
+ /* General buffer */
+ char rbuf[1024];
+
+ /* Hold a string to find */
+ char finder[81];
+
+ /* Hold a string to show */
+ char shower[81];
+
+ /* Describe this thing */
+ char caption[128];
+
+ /* Hypertext info */
+ char link[MAX_LINKS][32], link_key[MAX_LINKS];
+ int link_x[MAX_LINKS], link_y[MAX_LINKS], link_line[MAX_LINKS];
+};
+
+typedef struct hyperlink hyperlink_type;
+
+bool_ show_file(cptr name, cptr what, int line, int mode)
+{
+ int i, k, x;
+
+ byte link_color = TERM_ORANGE, link_color_sel = TERM_YELLOW;
+
+ /* Number of "real" lines passed by */
+ int next = 0;
+
+ /* Number of "real" lines in the file */
+ int size = 0;
+
+ /* Backup value for "line" */
+ int back = 0;
+
+ /* Color of the next line */
+ byte color = TERM_WHITE;
+
+ /* This screen has sub-screens */
+ bool_ menu = FALSE;
+
+ /* Current help file */
+ FILE *fff = NULL;
+
+ /* Find this string (if any) */
+ cptr find = NULL;
+
+ /* Char array type of hyperlink info */
+ hyperlink_type *h_ptr;
+
+ /* Pointer to general buffer in the above */
+ char *buf;
+
+ int cur_link = 0, max_link = 0;
+
+ /* Read size of screen for big-screen stuff -pav- */
+ int wid, hgt;
+
+ /* Allocate hyperlink data */
+ MAKE(h_ptr, hyperlink_type);
+
+ /* Setup buffer pointer */
+ buf = h_ptr->rbuf;
+
+ /* Wipe the links */
+ for (i = 0; i < MAX_LINKS; i++)
+ {
+ h_ptr->link_x[i] = -1;
+ }
+
+ /* Hack XXX XXX XXX */
+ if (what)
+ {
+ /* h_ptr->caption */
+ strcpy(h_ptr->caption, what);
+
+ /* Access the "file" */
+ strcpy(h_ptr->path, name);
+
+ /* Open */
+ fff = my_fopen(h_ptr->path, "r");
+ }
+
+ /* Look in "help" */
+ if (!fff)
+ {
+ /* h_ptr->caption */
+ sprintf(h_ptr->caption, "Help file '%s'", name);
+
+ /* Build the filename */
+ path_build(h_ptr->path, 1024, ANGBAND_DIR_HELP, name);
+
+ /* Open the file */
+ fff = my_fopen(h_ptr->path, "r");
+ }
+
+ /* Look in "info" */
+ if (!fff)
+ {
+ /* h_ptr->caption */
+ sprintf(h_ptr->caption, "Info file '%s'", name);
+
+ /* Build the filename */
+ path_build(h_ptr->path, 1024, ANGBAND_DIR_INFO, name);
+
+ /* Open the file */
+ fff = my_fopen(h_ptr->path, "r");
+ }
+
+ /* Look in "file" */
+ if (!fff)
+ {
+ /* h_ptr->caption */
+ sprintf(h_ptr->caption, "File '%s'", name);
+
+ /* Build the filename */
+ path_build(h_ptr->path, 1024, ANGBAND_DIR_FILE, name);
+
+ /* Open the file */
+ fff = my_fopen(h_ptr->path, "r");
+ }
+
+ /* Oops */
+ if (!fff)
+ {
+ /* Message */
+ msg_format("Cannot open '%s'.", name);
+ msg_print(NULL);
+
+ /* Free hyperlink info */
+ KILL(h_ptr, hyperlink_type);
+
+ /* Oops */
+ return (TRUE);
+ }
+
+
+ /* Pre-Parse the file */
+ while (TRUE)
+ {
+ /* Read a line or stop */
+ if (my_fgets(fff, h_ptr->rbuf, 1024)) break;
+
+ /* Get a color */
+ if (prefix(h_ptr->rbuf, "#####"))
+ {
+ buf = &h_ptr->rbuf[6];
+ }
+ else buf = h_ptr->rbuf;
+
+ /* Get the link colors */
+ if (prefix(buf, "|||||"))
+ {
+ link_color = color_char_to_attr(buf[5]);
+ link_color_sel = color_char_to_attr(buf[6]);
+ }
+
+ /* Tag ? */
+ if (prefix(buf, "~~~~~"))
+ {
+ if (line < 0)
+ {
+ int i;
+ char old_c;
+
+ for (i = 5; (buf[i] >= '0') && (buf[i] <= '9'); i++)
+ ;
+ old_c = buf[i];
+ buf[i] = '\0';
+
+ if (atoi(buf + 5) == -line)
+ {
+ line = next + 1;
+ }
+ buf[i] = old_c;
+ }
+ }
+
+ x = 0;
+ while (buf[x])
+ {
+ /* Hyperlink ? */
+ if (prefix(buf + x, "*****"))
+ {
+ int xx = x + 5, stmp, xdeb = x + 5, z;
+ char tmp[20];
+
+ for (z = 0; z < 20; z++) tmp[z] = '\0';
+
+ h_ptr->link_x[max_link] = x;
+ h_ptr->link_y[max_link] = next;
+
+ if (buf[xx] == '/')
+ {
+ xx++;
+ h_ptr->link_key[max_link] = buf[xx];
+ xx++;
+ xdeb += 2;
+ }
+ else
+ {
+ h_ptr->link_key[max_link] = 0;
+ }
+
+ /* Zap the link info */
+ while (buf[xx] != '*')
+ {
+ h_ptr->link[max_link][xx - xdeb] = buf[xx];
+ xx++;
+ }
+ h_ptr->link[max_link][xx - xdeb] = '\0';
+ xx++;
+ stmp = xx;
+ while (buf[xx] != '[')
+ {
+ tmp[xx - stmp] = buf[xx];
+ xx++;
+ }
+ xx++;
+ tmp[xx - stmp] = '\0';
+ h_ptr->link_line[max_link] = -atoi(tmp);
+ max_link++;
+ }
+ x++;
+ }
+
+ /* Count the "real" lines */
+ next++;
+ }
+
+ /* Save the number of "real" lines */
+ size = next;
+
+
+
+ /* Display the file */
+ while (TRUE)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ Term_get_size(&wid, &hgt);
+
+ /* Restart when necessary */
+ if (line >= size) line = 0;
+
+
+ /* Re-open the file if needed */
+ if (next > line)
+ {
+ /* Close it */
+ my_fclose(fff);
+
+ /* Hack -- Re-Open the file */
+ fff = my_fopen(h_ptr->path, "r");
+
+ /* Oops */
+ if (!fff)
+ {
+ /* Free hyperlink info */
+ KILL(h_ptr, hyperlink_type);
+
+ return (FALSE);
+ }
+
+ /* File has been restarted */
+ next = 0;
+ }
+
+ /* Skip lines if needed */
+ for (; next < line; next++)
+ {
+ /* Skip a line */
+ if (my_fgets(fff, buf, 1024)) break;
+ }
+
+
+ /* Dump the next 20 (or more in bigscreen) lines of the file */
+ for (i = 0; i < (hgt - 4); )
+ {
+ int print_x;
+
+ /* Hack -- track the "first" line */
+ if (!i) line = next;
+
+ /* Get a line of the file or stop */
+ if (my_fgets(fff, h_ptr->rbuf, 1024)) break;
+
+ /* Get a color */
+ if (prefix(h_ptr->rbuf, "#####"))
+ {
+ color = color_char_to_attr(h_ptr->rbuf[5]);
+ buf = &h_ptr->rbuf[6];
+ }
+ else buf = h_ptr->rbuf;
+
+ /* Count the "real" lines */
+ next++;
+
+ /* Skip link colors */
+ if (prefix(buf, "|||||")) continue;
+
+ /* Skip tags */
+ if (prefix(buf, "~~~~~"))
+ {
+ i++;
+ continue;
+ }
+
+ /* Hack -- keep searching */
+ if (find && !i && !strstr(buf, find)) continue;
+
+ /* Hack -- stop searching */
+ find = NULL;
+
+ /* Be sure to get a correct cur_link */
+ if (h_ptr->link_y[cur_link] >= line + (hgt - 4))
+ {
+ while ((cur_link > 0) && (h_ptr->link_y[cur_link] >= line + (hgt - 4)))
+ {
+ cur_link--;
+ }
+ }
+ if (h_ptr->link_y[cur_link] < line)
+ {
+ while ((cur_link < max_link) && (h_ptr->link_y[cur_link] < line))
+ {
+ cur_link++;
+ }
+ }
+
+ /* Dump the line */
+ print_x = 0;
+ if (!prefix(buf, "&&&&&"))
+ {
+ x = 0;
+ while (buf[x])
+ {
+ /* Hyperlink ? */
+ if (prefix(buf + x, "*****"))
+ {
+ int xx = x + 5;
+
+ /* Zap the link info */
+ while (buf[xx] != '[')
+ {
+ xx++;
+ }
+ xx++;
+ /* Ok print the link name */
+ while (buf[xx] != ']')
+ {
+ byte color = link_color;
+
+ if ((h_ptr->link_x[cur_link] == x) && (h_ptr->link_y[cur_link] == line + i))
+ color = link_color_sel;
+
+ /* Now we treat the next char as printable */
+ if (buf[xx] == '\\')
+ xx++;
+
+ Term_putch(print_x, i + 2, color, buf[xx]);
+ xx++;
+ print_x++;
+ }
+ x = xx;
+ }
+ /* Color ? */
+ else if (prefix(buf + x, "[[[[["))
+ {
+ int xx = x + 6;
+
+ /* Ok print the link name */
+ while (buf[xx] != ']')
+ {
+ /* Now we treat the next char as printable */
+ if (buf[xx] == '\\')
+ xx++;
+ Term_putch(print_x, i + 2, color_char_to_attr(buf[x + 5]), buf[xx]);
+ xx++;
+ print_x++;
+ }
+ x = xx;
+ }
+ /* Remove HTML ? */
+ else if (prefix(buf + x, "{{{{{"))
+ {
+ int xx = x + 6;
+
+ /* Ok remove this section */
+ while (buf[xx] != '}')
+ {
+ xx++;
+ }
+ x = xx;
+ }
+ else
+ {
+ Term_putch(print_x, i + 2, color, buf[x]);
+ print_x++;
+ }
+
+ x++;
+ }
+ }
+ /* Verbatim mode: i.e: acacacac */
+ else
+ {
+ x = 5;
+ while (buf[x])
+ {
+ Term_putch(print_x, i + 2, color_char_to_attr(buf[x]), buf[x + 1]);
+ print_x++;
+ x += 2;
+ }
+ }
+ color = TERM_WHITE;
+
+ /* Hilite "h_ptr->shower" */
+ if (h_ptr->shower[0])
+ {
+ cptr str = buf;
+
+ /* Display matches */
+ while ((str = strstr(str, h_ptr->shower)) != NULL)
+ {
+ int len = strlen(h_ptr->shower);
+
+ /* Display the match */
+ Term_putstr(str - buf, i + 2, len, TERM_YELLOW, h_ptr->shower);
+
+ /* Advance */
+ str += len;
+ }
+ }
+
+ /* Count the printed lines */
+ i++;
+ }
+
+ /* Hack -- failed search */
+ if (find)
+ {
+ bell();
+ line = back;
+ find = NULL;
+ continue;
+ }
+
+
+ /* Show a general "title" */
+ prt(format("[%s, %s, Line %d/%d]", get_version_string(),
+ h_ptr->caption, line, size), 0, 0);
+
+ /* Prompt -- menu screen */
+ if (menu)
+ {
+ /* Wait for it */
+ prt("[Press a Number, or ESC to exit.]", hgt - 1, 0);
+ }
+
+ /* Prompt -- small files */
+ else if (size <= (hgt - 4))
+ {
+ /* Wait for it */
+ prt("[Press ESC to exit.]", hgt - 1, 0);
+ }
+
+ /* Prompt -- large files */
+ else
+ {
+ /* Wait for it */
+ prt("[Press 2, 8, 4, 6, /, =, #, %, backspace, or ESC to exit.]", hgt - 1, 0);
+ }
+
+ /* Get a keypress */
+ k = inkey();
+
+ /* Hack -- return to last screen */
+ if ((k == '?') || (k == 0x7F) || (k == '\010')) break;
+
+ /* Hack -- try showing */
+ if (k == '=')
+ {
+ /* Get "h_ptr->shower" */
+ prt("Show: ", hgt - 1, 0);
+ (void)askfor_aux(h_ptr->shower, 80);
+ }
+
+ /* Hack -- try finding */
+ if (k == '/')
+ {
+ /* Get "h_ptr->finder" */
+ prt("Find: ", hgt - 1, 0);
+ if (askfor_aux(h_ptr->finder, 80))
+ {
+ /* Find it */
+ find = h_ptr->finder;
+ back = line;
+ line = line + 1;
+
+ /* Show it */
+ strcpy(h_ptr->shower, h_ptr->finder);
+ }
+ }
+
+ /* Hack -- go to a specific line */
+ if (k == '#')
+ {
+ char tmp[81];
+ prt("Goto Line: ", hgt - 1, 0);
+ strcpy(tmp, "0");
+ if (askfor_aux(tmp, 80))
+ {
+ line = atoi(tmp);
+ }
+ }
+
+ /* Hack -- go to a specific file */
+ if (k == '%')
+ {
+ char tmp[81];
+ prt("Goto File: ", hgt - 1, 0);
+ strcpy(tmp, "help.hlp");
+ if (askfor_aux(tmp, 80))
+ {
+ if (!show_file(tmp, NULL, 0, mode)) k = ESCAPE;
+ }
+ }
+
+ /* Hack -- Allow backing up */
+ if (k == '-')
+ {
+ line = line - (hgt - 4);
+ if (line < 0) line = 0;
+ }
+
+ if (k == '8')
+ {
+ line--;
+ if (line < 0) line = 0;
+ }
+
+ /* Hack -- Advance a single line */
+ if (k == '2')
+ {
+ line = line + 1;
+ }
+
+ /* Advance one page */
+ if (k == ' ')
+ {
+ line = line + (hgt - 4);
+ }
+
+ /* Advance one link */
+ if ((k == '6') || (k == '\t'))
+ {
+ cur_link++;
+ if (cur_link >= max_link) cur_link = max_link - 1;
+
+ if (h_ptr->link_y[cur_link] < line) line = h_ptr->link_y[cur_link];
+ if (h_ptr->link_y[cur_link] >= line + (hgt - 4)) line = h_ptr->link_y[cur_link] - (hgt - 4);
+ }
+ /* Return one link */
+ if (k == '4')
+ {
+ cur_link--;
+ if (cur_link < 0) cur_link = 0;
+
+ if (h_ptr->link_y[cur_link] < line) line = h_ptr->link_y[cur_link];
+ if (h_ptr->link_y[cur_link] >= line + (hgt - 4)) line = h_ptr->link_y[cur_link] - (hgt - 4);
+ }
+
+ /* Recurse on numbers */
+ if (k == '\r')
+ {
+ if (h_ptr->link_x[cur_link] != -1)
+ {
+ /* Recurse on that file */
+ if (!show_file(h_ptr->link[cur_link], NULL, h_ptr->link_line[cur_link], mode)) k = ESCAPE;
+ }
+ }
+
+ /* Exit on escape */
+ if (k == ESCAPE) break;
+
+ /* No other key ? lets look for a shortcut */
+ for (i = 0; i < max_link; i++)
+ {
+ if (h_ptr->link_key[i] == k)
+ {
+ /* Recurse on that file */
+ if (!show_file(h_ptr->link[i], NULL, h_ptr->link_line[i], mode)) k = ESCAPE;
+ break;
+ }
+ }
+ }
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Free hyperlink buffers */
+ KILL(h_ptr, hyperlink_type);
+
+ /* Escape */
+ if (k == ESCAPE) return (FALSE);
+
+ /* Normal return */
+ return (TRUE);
+}
+
+bool_ txt_to_html(cptr head, cptr foot, cptr base, cptr ext, bool_ force, bool_ recur)
+{
+ int i, x;
+
+ /* Number of "real" lines passed by */
+ int next = 0;
+
+ char buf_name[80];
+
+ /* Color of the next line */
+ byte color = TERM_WHITE;
+
+ /* Current help file */
+ FILE *fff = NULL;
+
+ /* Current aux file */
+ FILE *aux = NULL;
+
+ /* Current html file */
+ FILE *htm = NULL;
+
+ /* Char array type of hyperlink info */
+ hyperlink_type *h_ptr;
+
+ cptr file_ext;
+ cptr link_prefix;
+ cptr link_suffix;
+
+ /* Pointer to general buffer in the above */
+ char *buf;
+
+ /* Allocate hyperlink data */
+ MAKE(h_ptr, hyperlink_type);
+
+ /* Setup buffer pointer */
+ buf = h_ptr->rbuf;
+
+ /* Wipe the links */
+ for (i = 0; i < MAX_LINKS; i++)
+ {
+ h_ptr->link_x[i] = -1;
+ }
+
+ /* Parse it(yeah lua is neat :) */
+ tome_dofile_anywhere(ANGBAND_DIR_HELP, "def.aux", TRUE);
+
+ /* Ok now get the parameters */
+ file_ext = string_exec_lua("return file_ext");
+ link_prefix = string_exec_lua("return link_prefix");
+ link_suffix = string_exec_lua("return link_suffix");
+
+ sprintf(buf_name, "%s.%s", base, file_ext);
+
+ if ((!force) && file_exist(buf_name)) return FALSE;
+
+ /* Build the filename */
+ path_build(h_ptr->path, 1024, ANGBAND_DIR_HELP, buf_name);
+
+ /* Open the file */
+ htm = my_fopen(h_ptr->path, "w");
+
+ sprintf(buf_name, "%s.%s", base, ext);
+
+ /* h_ptr->caption */
+ sprintf(h_ptr->caption, "Help file '%s'", buf_name);
+
+ /* Build the filename */
+ path_build(h_ptr->path, 1024, ANGBAND_DIR_HELP, buf_name);
+
+ /* Open the file */
+ fff = my_fopen(h_ptr->path, "r");
+
+ /* Oops */
+ if (!fff || !htm)
+ {
+ /* Free hyperlink info */
+ KILL(h_ptr, hyperlink_type);
+
+ my_fclose(fff);
+ my_fclose(htm);
+
+ /* Oops */
+ return (TRUE);
+ }
+
+ /* Build the filename */
+ path_build(h_ptr->path, 1024, ANGBAND_DIR_HELP, head);
+
+ /* Open the file */
+ aux = my_fopen(h_ptr->path, "r");
+
+ /* Copy the header */
+ if (aux)
+ {
+ while (TRUE)
+ {
+ char *find;
+
+ if (my_fgets(aux, h_ptr->rbuf, 1024)) break;
+ find = strstr(h_ptr->rbuf, "%t");
+ if (find != NULL)
+ {
+ *find = '\0';
+ find += 2;
+ fprintf(htm, "%s", h_ptr->rbuf);
+ fprintf(htm, "%s", base);
+ fprintf(htm, "%s\n", find);
+ }
+ else
+ fprintf(htm, "%s\n", h_ptr->rbuf);
+ }
+ my_fclose(aux);
+ }
+
+ /* Display the file */
+ while (TRUE)
+ {
+ bool_ do_color = FALSE;
+
+ /* Skip a line */
+ if (my_fgets(fff, h_ptr->rbuf, 1024)) break;
+
+ color = TERM_WHITE;
+
+ {
+ int print_x;
+
+ /* Get a color */
+ if (prefix(h_ptr->rbuf, "#####"))
+ {
+ color = color_char_to_attr(h_ptr->rbuf[5]);
+ do_color = TRUE;
+ fprintf(htm, "<FONT COLOR=\"#%02X%02X%02X\">",
+ angband_color_table[color][1],
+ angband_color_table[color][2],
+ angband_color_table[color][3]);
+ buf = &h_ptr->rbuf[6];
+ }
+ else buf = h_ptr->rbuf;
+
+ /* Count the "real" lines */
+ next++;
+
+ /* Skip link colors */
+ if (prefix(buf, "|||||")) continue;
+
+ /* Skip tags */
+ if (prefix(buf, "~~~~~"))
+ {
+ int i;
+
+ for (i = 5; (buf[i] >= '0') && (buf[i] <= '9'); i++)
+ ;
+ buf[i] = '\0';
+ fprintf(htm, "<A NAME=\"%s\"></A>", buf + 5);
+ continue;
+ }
+
+ /* Dump the line */
+ print_x = 0;
+ if (!prefix(buf, "&&&&&"))
+ {
+ x = 0;
+ while (buf[x])
+ {
+ /* Hyperlink ? */
+ if (prefix(buf + x, "*****"))
+ {
+ int xx = x + 5, z = 0;
+ char buff[80];
+ char link_line[80], *s;
+
+ if (buf[xx] == '/') xx += 2;
+
+ /* Zap the link info */
+ while (buf[xx] != '*')
+ {
+ buff[z++] = buf[xx];
+ xx++;
+ }
+ xx++;
+ buff[z] = '\0';
+
+ /* Zap the link info */
+ z = 0;
+ while (buf[xx] != '[')
+ {
+ link_line[z++] = buf[xx];
+ xx++;
+ }
+ xx++;
+ link_line[z] = '\0';
+
+ /* parse it */
+ s = buff;
+ while (*s != '.') s++;
+ *s = '\0';
+ s++;
+ if (recur) txt_to_html(head, foot, buff, s, FALSE, recur);
+
+ if (atoi(link_line)) fprintf(htm, "<A HREF=\"%s%s.%s%s#%d\">", link_prefix, buff, file_ext, link_suffix, atoi(link_line));
+ else fprintf(htm, "<A HREF=\"%s%s.%s%s\">", link_prefix, buff, file_ext, link_suffix);
+
+ /* Ok print the link name */
+ while (buf[xx] != ']')
+ {
+ /* Now we treat the next char as printable */
+ if (buf[xx] == '\\')
+ xx++;
+ fprintf(htm, "%c", buf[xx]);
+ xx++;
+ print_x++;
+ }
+ x = xx;
+
+ fprintf(htm, "</A>");
+ }
+ /* Color ? */
+ else if (prefix(buf + x, "[[[[["))
+ {
+ int xx = x + 6;
+
+ color = color_char_to_attr(buf[x + 5]);
+ fprintf(htm, "<FONT COLOR=\"#%02X%02X%02X\">",
+ angband_color_table[color][1],
+ angband_color_table[color][2],
+ angband_color_table[color][3]);
+
+ /* Ok print the link name */
+ while (buf[xx] != ']')
+ {
+ /* Now we treat the next char as printable */
+ if (buf[xx] == '\\')
+ xx++;
+ fprintf(htm, "%c", buf[xx]);
+ xx++;
+ print_x++;
+ }
+ x++;
+ x = xx;
+
+ fprintf(htm, "</FONT>");
+ }
+ /* Hidden HTML tag? */
+ else if (prefix(buf + x, "{{{{{"))
+ {
+ int xx = x + 5;
+
+ /* Ok output the tag inside */
+ while (buf[xx] != '}')
+ {
+ fprintf(htm, "%c", buf[xx]);
+ xx++;
+ }
+ x++;
+ x = xx;
+ }
+ else
+ {
+ fprintf(htm, "%c", buf[x]);
+ print_x++;
+ }
+
+ x++;
+ }
+ }
+ /* Verbatim mode: i.e: acacacac */
+ else
+ {
+ byte old_color;
+
+ x = 5;
+ old_color = color_char_to_attr(buf[x]);
+ fprintf(htm, "<FONT COLOR=\"#%02X%02X%02X\">",
+ angband_color_table[color][1],
+ angband_color_table[color][2],
+ angband_color_table[color][3]);
+ while (buf[x])
+ {
+ color = color_char_to_attr(buf[x]);
+ if (color != old_color)
+ fprintf(htm, "</FONT><FONT COLOR=\"#%02X%02X%02X\">",
+ angband_color_table[color][1],
+ angband_color_table[color][2],
+ angband_color_table[color][3]);
+
+ fprintf(htm, "%c", buf[x + 1]);
+ print_x++;
+ x += 2;
+ }
+ fprintf(htm, "</FONT>");
+ }
+ }
+ if (do_color)
+ {
+ fprintf(htm, "</FONT>");
+ }
+ fprintf(htm, "\n");
+ }
+
+ /* Build the filename */
+ path_build(h_ptr->path, 1024, ANGBAND_DIR_HELP, foot);
+
+ /* Open the file */
+ aux = my_fopen(h_ptr->path, "r");
+
+ /* Copy the footer */
+ if (aux)
+ {
+ while (TRUE)
+ {
+ if (my_fgets(aux, h_ptr->rbuf, 1024)) break;
+ fprintf(htm, "%s\n", h_ptr->rbuf);
+ }
+ my_fclose(aux);
+ }
+
+ /* Close the file */
+ my_fclose(htm);
+ my_fclose(fff);
+
+ /* Free hyperlink buffers */
+ KILL(h_ptr, hyperlink_type);
+
+ /* Normal return */
+ return (TRUE);
+}
+
+/* Take an help file screenshot(yes yes I know..) */
+void help_file_screenshot(cptr name)
+{
+ int y, x;
+ int wid, hgt;
+
+ byte a = 0;
+ char c = ' ';
+
+ FILE *htm;
+
+ char buf[1024];
+
+ /* The terms package supports up to 255x255 screen size */
+ char abuf[256];
+ char cbuf[256];
+
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, name);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Append to the file */
+ htm = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!htm) return;
+
+ /* Retrieve current screen size */
+ Term_get_size(&wid, &hgt);
+
+ /* Dump the screen */
+ for (y = 0; y < hgt; y++)
+ {
+ cmovie_clean_line(y, abuf, cbuf);
+
+ /* Dump each row */
+ fprintf(htm, "&&&&&");
+ for (x = 0; x < wid; x++)
+ {
+ a = abuf[x];
+ c = cbuf[x];
+
+ fprintf(htm, "%c%c", a, c);
+ }
+
+ /* End the row */
+ fprintf(htm, "\n");
+ }
+
+ /* Close it */
+ my_fclose(htm);
+}
+
+/* Take an html screenshot */
+void html_screenshot(cptr name)
+{
+ int y, x;
+ int wid, hgt;
+
+ byte a = 0, oa = TERM_WHITE;
+ char c = ' ';
+
+ FILE *htm;
+
+ char buf[1024];
+
+ /* The terms package supports up to 255x255 screen size */
+ char abuf[256];
+ char cbuf[256];
+
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, name);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Append to the file */
+ htm = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!htm) return;
+
+ /* Retrieve current screen size */
+ Term_get_size(&wid, &hgt);
+
+ fprintf(htm, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
+ "<head>\n");
+ fprintf(htm, "<meta name=\"GENERATOR\" content=\"%s\"/>\n",
+ get_version_string());
+ fprintf(htm, "<title>%s</title>\n", name);
+ fprintf(htm, "</head>\n"
+ "<body>\n"
+ "<pre style=\"color: #ffffff; background-color: #000000; font-family: monospace\">\n");
+ fprintf(htm, "<span style=\"color: #%02X%02X%02X\">\n",
+ angband_color_table[TERM_WHITE][1],
+ angband_color_table[TERM_WHITE][2],
+ angband_color_table[TERM_WHITE][3]);
+
+ /* Dump the screen */
+ for (y = 0; y < hgt; y++)
+ {
+ cmovie_clean_line(y, abuf, cbuf);
+
+ /* Dump each row */
+ for (x = 0; x < wid; x++)
+ {
+ a = color_char_to_attr(abuf[x]);
+ c = cbuf[x];
+
+ if (oa != a)
+ {
+ fprintf(htm, "</span><span style=\"color: #%02X%02X%02X\">", angband_color_table[a][1], angband_color_table[a][2], angband_color_table[a][3]);
+ oa = a;
+ }
+ if (c == '<')
+ fprintf(htm, "&lt;");
+ else if (c == '>')
+ fprintf(htm, "&gt;");
+ else if (c == '&')
+ fprintf(htm, "&amp;");
+ else
+ fprintf(htm, "%c", c);
+ }
+
+ /* End the row */
+ fprintf(htm, "\n");
+ }
+ fprintf(htm, "</span>\n"
+ "</pre>\n"
+ "</body>\n"
+ "</html>\n");
+
+ /* Close it */
+ my_fclose(htm);
+}
+
+
+/*
+ * Peruse the On-Line-Help
+ */
+void do_cmd_help(void)
+{
+ /* Save screen */
+ screen_save();
+
+ /* Peruse the main help file */
+ (void)show_file("help.hlp", NULL, 0, 0);
+
+ /* Load screen */
+ screen_load();
+}
+
+
+
+
+/*
+ * Process the player name.
+ * Extract a clean "base name".
+ * Build the savefile name if needed.
+ */
+void process_player_base()
+{
+ char temp[128];
+
+ /* Rename the savefile, using the player_base */
+ (void)sprintf(temp, "%s", player_base);
+
+ /* Build the filename */
+ path_build(savefile, 1024, ANGBAND_DIR_SAVE, temp);
+}
+
+void process_player_name(bool_ sf)
+{
+ int i, k = 0;
+ char tmp[50];
+
+ /* Cannot be too long */
+ if (strlen(player_base) > 15)
+ {
+ /* Name too long */
+ quit_fmt("The name '%s' is too long!", player_base);
+ }
+
+ /* Cannot contain "icky" characters */
+ for (i = 0; player_base[i]; i++)
+ {
+ /* No control characters */
+ if (iscntrl(player_base[i]))
+ {
+ /* Illegal characters */
+ quit_fmt("The name '%s' contains control chars!", player_base);
+ }
+ }
+
+
+#ifdef MACINTOSH
+
+ /* Extract "useful" letters */
+ for (i = 0; player_base[i]; i++)
+ {
+ char c = player_base[i];
+
+ /* Convert "dot" to "underscore" */
+ if (c == '@.') c = '_';
+
+ /* Accept all the letters */
+ tmp[k++] = c;
+ }
+
+#else
+
+ /* Extract "useful" letters */
+ for (i = 0; player_base[i]; i++)
+ {
+ char c = player_base[i];
+
+ /* Accept some letters */
+ if (isalpha(c) || isdigit(c)) tmp[k++] = c;
+
+ /* Convert space, dot, and underscore to underscore */
+ else if (strchr("@. _", c)) tmp[k++] = '_';
+ }
+
+#endif
+
+
+#if defined(WINDOWS) || defined(MSDOS)
+
+ /* Hack -- max length */
+ if (k > 8) k = 8;
+
+#endif
+
+ /* Terminate */
+ tmp[k] = '\0';
+ sprintf(player_base, "%s", tmp);
+
+ /* Require a "base" name */
+ if (!player_base[0]) strcpy(player_base, "PLAYER");
+
+
+#ifdef SAVEFILE_MUTABLE
+
+ /* Accept */
+ sf = TRUE;
+
+#endif
+
+ /* Change the savefile name */
+ if (sf)
+ {
+ process_player_base();
+ }
+}
+
+
+/*
+ * Gets a name for the character, reacting to name changes.
+ *
+ * Assumes that "display_player(0)" has just been called
+ *
+ * Perhaps we should NOT ask for a name (at "birth()") on
+ * Unix machines? XXX XXX
+ *
+ * What a horrible name for a global function. XXX XXX XXX
+ */
+void get_name(void)
+{
+ char tmp[32];
+
+ /* Clear last line */
+ clear_from(22);
+
+ /* Prompt and ask */
+ prt("[Enter your player's name above, or hit ESCAPE]", 23, 2);
+
+ /* Ask until happy */
+ while (1)
+ {
+ /* Go to the "name" field */
+ move_cursor(2, 9);
+
+ /* Save the player name */
+ strcpy(tmp, player_name);
+
+ /* Get an input, ignore "Escape" */
+ if (askfor_aux(tmp, 31)) strcpy(player_name, tmp);
+
+ /* Process the player name */
+ process_player_name(FALSE);
+
+ /* All done */
+ break;
+ }
+
+ /* Pad the name (to clear junk) */
+ sprintf(tmp, "%-31.31s", player_name);
+
+ /* Re-Draw the name (in light blue) */
+ c_put_str(TERM_L_BLUE, tmp, 2, 9);
+
+ /* Erase the prompt, etc */
+ clear_from(22);
+}
+
+
+
+/*
+ * Hack -- commit suicide
+ */
+void do_cmd_suicide(void)
+{
+ int i;
+
+ /* Flush input */
+ flush();
+
+ /* Verify Retirement */
+ if (total_winner)
+ {
+ /* Verify */
+ if (!get_check("Do you want to retire? ")) return;
+ }
+
+ /* Verify Suicide */
+ else
+ {
+ /* Verify */
+ if (!get_check("Do you really want to quit? ")) return;
+
+ if (!noscore)
+ {
+ /* Special Verification for suicide */
+ prt("Please verify QUITTING by typing the '@' sign: ", 0, 0);
+ flush();
+ i = inkey();
+ prt("", 0, 0);
+ if (i != '@') return;
+ }
+ }
+
+ /* Stop playing */
+ alive = FALSE;
+
+ /* Kill the player */
+ death = TRUE;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+
+ /* Cause of death */
+ (void)strcpy(died_from, "Quitting");
+}
+
+
+ /* HACK - Remove / set the CAVE_VIEW flag, since view_x / view_y
+ * is not saved, and the visible locations are not lighted correctly
+ * when the game is loaded again
+ * Alternatively forget_view() and update_view() can be used
+ */
+void remove_cave_view(bool_ remove)
+{
+ int i;
+ cave_type *c_ptr;
+
+ if (view_n)
+ {
+ /* Clear them all */
+ for (i = 0; i < view_n; i++)
+ {
+ int y = view_y[i];
+ int x = view_x[i];
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ if (remove)
+ c_ptr->info &= ~(CAVE_VIEW);
+ else
+ c_ptr->info |= (CAVE_VIEW);
+ }
+ }
+}
+
+/*
+ * Save the game
+ */
+void do_cmd_save_game(void)
+{
+ remove_cave_view(TRUE);
+
+ /* Save the current level if in a persistent level */
+ save_dungeon();
+
+ /* Autosaves do not disturb */
+ if (!is_autosave)
+ {
+ /* Disturb the player */
+ disturb(1, 0);
+ }
+
+ /* Clear messages */
+ msg_print(NULL);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Message */
+ prt("Saving game...", 0, 0);
+
+ /* Refresh */
+ Term_fresh();
+
+ /* The player is not dead */
+ (void)strcpy(died_from, "(saved)");
+
+ /* Forbid suspend */
+ signals_ignore_tstp();
+
+ /* Save the player */
+ if (save_player())
+ {
+ prt("Saving game... done.", 0, 0);
+ }
+
+ /* Save failed (oops) */
+ else
+ {
+ prt("Saving game... failed!", 0, 0);
+ }
+
+ remove_cave_view(FALSE);
+
+ /* Allow suspend again */
+ signals_handle_tstp();
+
+ /* Refresh */
+ Term_fresh();
+
+ /* Note that the player is not dead */
+ (void)strcpy(died_from, "(alive and well)");
+}
+
+/*
+ * Auto-save depending on whether the auto save flag is set.
+ */
+void autosave_checkpoint()
+{
+ if (autosave_l)
+ {
+ is_autosave = TRUE;
+ msg_print("Autosaving the game...");
+ do_cmd_save_game();
+ is_autosave = FALSE;
+ }
+}
+
+/*
+ * Hack -- Calculates the total number of points earned -JWT-
+ */
+long total_points(void)
+{
+ s16b max_dl = 0, i, k;
+ long temp, Total = 0;
+ long mult = 20; /* was 100. Divided values by 5 because of an overflow error */
+ long comp_death = (p_ptr->companion_killed * 2 / 5);
+
+ if (!comp_death) comp_death = 1;
+
+ if (p_ptr->preserve) mult -= 1; /* Penalize preserve, maximize modes */
+ if (p_ptr->maximize) mult -= 1;
+ if (auto_scum) mult -= 4;
+ if (stupid_monsters) mult -= 10;
+ if (small_levels) mult += ((always_small_level) ? 4 : 10);
+ if (empty_levels) mult += 2;
+ if (smart_learn) mult += 4;
+ if (smart_cheat) mult += 4;
+
+ if (mult < 2) mult = 2; /* At least 10% of the original score */
+ /* mult is now between 2 and 40, i.e. 10% and 200% */
+
+ for (i = 0; i < max_d_idx; i++)
+ if (max_dlv[i] > max_dl)
+ max_dl = max_dlv[i];
+
+ temp = p_ptr->lev * p_ptr->lev * p_ptr->lev * p_ptr->lev + (100 * max_dl);
+
+ temp += p_ptr->max_exp / 5;
+
+ temp = (temp * mult / 20);
+
+ /* Gold increases score */
+ temp += p_ptr->au / 5;
+
+ /* Completing quest increase score */
+ for (i = 0; i < max_q_idx; i++)
+ {
+ if (quest[i].status >= QUEST_STATUS_COMPLETED)
+ {
+ temp += 2000;
+ temp += quest[i].level * 100;
+ }
+ }
+
+ /* Death of a companion is BAD */
+ temp /= comp_death;
+
+ /* The know objects increase the score */
+ /* Scan the object kinds */
+ for (k = 1; k < max_k_idx; k++)
+ {
+ object_kind *k_ptr = &k_info[k];
+
+ /* Hack -- skip artifacts */
+ if (k_ptr->flags3 & (TR3_INSTA_ART)) continue;
+
+ /* List known flavored objects */
+ if (k_ptr->flavor && k_ptr->aware)
+ {
+ object_type *i_ptr;
+ object_type object_type_body;
+
+ /* Get local object */
+ i_ptr = &object_type_body;
+
+ /* Create fake object */
+ object_prep(i_ptr, k);
+
+ temp += object_value_real(i_ptr);
+ }
+ }
+
+ for (k = 1; k < max_r_idx; k++)
+ {
+ monster_race *r_ptr = &r_info[k];
+
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ bool_ dead = (r_ptr->max_num == 0);
+
+ if (dead)
+ {
+ /* Uniques are supposed to be harder */
+ Total += 50;
+ }
+ }
+ else
+ {
+ s16b This = r_ptr->r_pkills;
+
+ if (This > 0)
+ {
+ Total += This;
+ }
+ }
+ }
+ temp += Total * 50;
+
+ temp += total_bounties * 100;
+
+ if (total_winner) temp += 1000000;
+
+
+
+ return (temp);
+}
+
+
+
+/*
+ * Centers a string within a 31 character string -JWT-
+ */
+static void center_string(char *buf, cptr str)
+{
+ int i, j;
+
+ /* Total length */
+ i = strlen(str);
+
+ /* Necessary border */
+ j = 15 - i / 2;
+
+ /* Mega-Hack */
+ (void)sprintf(buf, "%*s%s%*s", j, "", str, 31 - i - j, "");
+}
+
+
+/*
+ * Redefinable "print_tombstone" action
+ */
+bool_ (*tombstone_aux)(void) = NULL;
+
+
+/*
+ * Display a "tomb-stone"
+ */
+static void print_tomb(void)
+{
+ bool_ done = FALSE;
+
+ /* Do we use a special tombstone ? */
+ if (tombstone_aux)
+ {
+ /* Use tombstone hook */
+ done = (*tombstone_aux)();
+ }
+
+ /* Print the text-tombstone */
+ if (!done)
+ {
+ cptr p;
+
+ char tmp[160];
+
+ char buf[1024];
+ char dummy[80];
+
+ FILE *fp;
+
+ time_t ct = time((time_t)0);
+
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_FILE, "dead.txt");
+
+ /* Open the News file */
+ fp = my_fopen(buf, "r");
+
+ /* Dump */
+ if (fp)
+ {
+ int i = 0;
+
+ /* Dump the file to the screen */
+ while (0 == my_fgets(fp, buf, 1024))
+ {
+ /* Display and advance */
+ display_message(0, i++, strlen(buf), TERM_WHITE, buf);
+ }
+
+ /* Close */
+ my_fclose(fp);
+ }
+
+
+ /* King or Queen */
+ if (total_winner || (p_ptr->lev > PY_MAX_LEVEL))
+ {
+ p = "Magnificent";
+ }
+
+ /* Normal */
+ else
+ {
+ p = cp_ptr->titles[(p_ptr->lev - 1) / 5] + c_text;
+ }
+
+ center_string(buf, player_name);
+ put_str(buf, 6, 11);
+
+ center_string(buf, "the");
+ put_str(buf, 7, 11);
+
+ center_string(buf, p);
+ put_str(buf, 8, 11);
+
+
+ center_string(buf, spp_ptr->title + c_name);
+ put_str(buf, 10, 11);
+
+ (void)sprintf(tmp, "Level: %d", (int)p_ptr->lev);
+ center_string(buf, tmp);
+ put_str(buf, 11, 11);
+
+ (void)sprintf(tmp, "Exp: %ld", (long)p_ptr->exp);
+ center_string(buf, tmp);
+ put_str(buf, 12, 11);
+
+ (void)sprintf(tmp, "AU: %ld", (long)p_ptr->au);
+ center_string(buf, tmp);
+ put_str(buf, 13, 11);
+
+ (void)sprintf(tmp, "Killed on Level %d", dun_level);
+ center_string(buf, tmp);
+ put_str(buf, 14, 11);
+
+
+ if (strlen(died_from) > 24)
+ {
+ strncpy(dummy, died_from, 24);
+ dummy[24] = '\0';
+ (void)sprintf(tmp, "by %s.", dummy);
+ }
+ else
+ (void)sprintf(tmp, "by %s.", died_from);
+
+ center_string(buf, tmp);
+ put_str(buf, 15, 11);
+
+
+ (void)sprintf(tmp, "%-.24s", ctime(&ct));
+ center_string(buf, tmp);
+ put_str(buf, 17, 11);
+ }
+}
+
+
+/*
+ * Display some character info
+ */
+static void show_info(void)
+{
+ int i, j, k;
+ object_type *o_ptr;
+ store_type *st_ptr;
+
+ /* Hack -- Know everything in the inven/equip */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Aware and Known */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ }
+
+ for (i = 1; i < max_towns; i++)
+ {
+ st_ptr = &town_info[i].store[7];
+
+ /* Hack -- Know everything in the home */
+ for (j = 0; j < st_ptr->stock_num; j++)
+ {
+ o_ptr = &st_ptr->stock[j];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Aware and Known */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ }
+ }
+
+ /* Hack -- Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Flush all input keys */
+ flush();
+
+ /* Flush messages */
+ msg_print(NULL);
+
+
+ /* Describe options */
+ prt("You may now dump a character record to one or more files.", 21, 0);
+ prt("Then, hit RETURN to see the character, or ESC to abort.", 22, 0);
+
+ /* Dump character records as requested */
+ while (TRUE)
+ {
+ char out_val[160];
+
+ /* Prompt */
+ put_str("Filename(you can post it to http://angband.oook.cz/): ", 23, 0);
+
+ /* Default */
+ strcpy(out_val, "");
+
+ /* Ask for filename (or abort) */
+ if (!askfor_aux(out_val, 60)) return;
+
+ /* Return means "show on screen" */
+ if (!out_val[0]) break;
+
+ /* Save screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Dump a character file */
+ (void)file_character(out_val, TRUE);
+
+ /* Load screen */
+ Term_load();
+ character_icky = FALSE;
+ }
+
+
+ /* Display player */
+ display_player(0);
+
+ /* Prompt for p_ptr->inventory */
+ prt("Hit any key to see more information (ESC to abort): ", 23, 0);
+
+ /* Allow abort at this point */
+ if (inkey() == ESCAPE) return;
+
+
+ /* Show equipment and inventory */
+
+ /* Equipment -- if any */
+ if (equip_cnt)
+ {
+ Term_clear();
+ item_tester_full = TRUE;
+ show_equip();
+ prt("You are using: -more-", 0, 0);
+ if (inkey() == ESCAPE) return;
+ }
+
+ /* Inventory -- if any */
+ if (inven_cnt)
+ {
+ Term_clear();
+ item_tester_full = TRUE;
+ show_inven();
+ prt("You are carrying: -more-", 0, 0);
+ if (inkey() == ESCAPE) return;
+ }
+
+ /* Homes in the different towns */
+ for (k = 1; k < max_towns; k++)
+ {
+ st_ptr = &town_info[k].store[7];
+
+ /* Home -- if anything there */
+ if (st_ptr->stock_num)
+ {
+ /* Display contents of the home */
+ for (k = 0, i = 0; i < st_ptr->stock_num; k++)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Show 12 items */
+ for (j = 0; (j < 12) && (i < st_ptr->stock_num); j++, i++)
+ {
+ char o_name[80];
+ char tmp_val[80];
+
+ /* Acquire item */
+ o_ptr = &st_ptr->stock[i];
+
+ /* Print header, clear line */
+ sprintf(tmp_val, "%c) ", I2A(j));
+ prt(tmp_val, j + 2, 4);
+
+ /* Display object description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+ c_put_str(tval_to_attr[o_ptr->tval], o_name, j + 2, 7);
+ }
+
+ /* h_ptr->caption */
+ prt(format("Your home contains (page %d): -more-", k + 1), 0, 0);
+
+ /* Wait for it */
+ if (inkey() == ESCAPE) return;
+ }
+ }
+ }
+}
+
+
+
+
+
+/*
+ * Semi-Portable High Score List Entry (128 bytes) -- BEN
+ *
+ * All fields listed below are null terminated ascii strings.
+ *
+ * In addition, the "number" fields are right justified, and
+ * space padded, to the full available length (minus the "null").
+ *
+ * Note that "string comparisons" are thus valid on "pts".
+ */
+
+typedef struct high_score high_score;
+
+struct high_score
+{
+ char what[8]; /* Version info (string) */
+
+ char pts[10]; /* Total Score (number) */
+
+ char gold[10]; /* Total Gold (number) */
+
+ char turns[10]; /* Turns Taken (number) */
+
+ char day[10]; /* Time stamp (string) */
+
+ char who[16]; /* Player Name (string) */
+
+ char uid[8]; /* Player UID (number) */
+
+ char sex[2]; /* Player Sex (string) */
+ char p_r[3]; /* Player Race (number) */
+ char p_s[3]; /* Player Subrace (number) */
+ char p_c[3]; /* Player Class (number) */
+ char p_cs[3]; /* Player Class spec (number) */
+
+ char cur_lev[4]; /* Current Player Level (number) */
+ char cur_dun[4]; /* Current Dungeon Level (number) */
+ char max_lev[4]; /* Max Player Level (number) */
+ char max_dun[4]; /* Max Dungeon Level (number) */
+
+ char arena_number[4]; /* Arena level attained -KMW- */
+ char inside_arena[4]; /* Did the player die in the arena? */
+ char inside_quest[4]; /* Did the player die in a quest? */
+ char exit_bldg[4]; /* Can the player exit arena? Goal obtained? -KMW- */
+
+ char how[32]; /* Method of death (string) */
+};
+
+
+
+/*
+ * Seek score 'i' in the highscore file
+ */
+static int highscore_seek(int i)
+{
+ /* Seek for the requested record */
+ return (fd_seek(highscore_fd, (huge)(i) * sizeof(high_score)));
+}
+
+
+/*
+ * Read one score from the highscore file
+ */
+static errr highscore_read(high_score *score)
+{
+ /* Read the record, note failure */
+ return (fd_read(highscore_fd, (char*)(score), sizeof(high_score)));
+}
+
+
+/*
+ * Write one score to the highscore file
+ */
+static int highscore_write(high_score *score)
+{
+ /* Write the record, note failure */
+ return (fd_write(highscore_fd, (char*)(score), sizeof(high_score)));
+}
+
+
+
+
+/*
+ * Just determine where a new score *would* be placed
+ * Return the location (0 is best) or -1 on failure
+ */
+static int highscore_where(high_score *score)
+{
+ int i;
+
+ high_score the_score;
+
+ /* Paranoia -- it may not have opened */
+ if (highscore_fd < 0) return ( -1);
+
+ /* Go to the start of the highscore file */
+ if (highscore_seek(0)) return ( -1);
+
+ /* Read until we get to a higher score */
+ for (i = 0; i < MAX_HISCORES; i++)
+ {
+ if (highscore_read(&the_score)) return (i);
+ if (strcmp(the_score.pts, score->pts) < 0) return (i);
+ }
+
+ /* The "last" entry is always usable */
+ return (MAX_HISCORES - 1);
+}
+
+
+/*
+ * Actually place an entry into the high score file
+ * Return the location (0 is best) or -1 on "failure"
+ */
+static int highscore_add(high_score *score)
+{
+ int i, slot;
+ bool_ done = FALSE;
+
+ high_score the_score, tmpscore;
+
+
+ /* Paranoia -- it may not have opened */
+ if (highscore_fd < 0) return ( -1);
+
+ /* Determine where the score should go */
+ slot = highscore_where(score);
+
+ /* Hack -- Not on the list */
+ if (slot < 0) return ( -1);
+
+ /* Hack -- prepare to dump the new score */
+ the_score = (*score);
+
+ /* Slide all the scores down one */
+ for (i = slot; !done && (i < MAX_HISCORES); i++)
+ {
+ /* Read the old guy, note errors */
+ if (highscore_seek(i)) return ( -1);
+ if (highscore_read(&tmpscore)) done = TRUE;
+
+ /* Back up and dump the score we were holding */
+ if (highscore_seek(i)) return ( -1);
+ if (highscore_write(&the_score)) return ( -1);
+
+ /* Hack -- Save the old score, for the next pass */
+ the_score = tmpscore;
+ }
+
+ /* Return location used */
+ return (slot);
+}
+
+
+
+/*
+ * Display the scores in a given range.
+ * Assumes the high score list is already open.
+ * Only five entries per line, too much info.
+ *
+ * Mega-Hack -- allow "fake" entry at the given position.
+ */
+static void display_scores_aux(int from, int to, int note, high_score *score)
+{
+ int i, j, k, n, place;
+ byte attr;
+ char out_val[256];
+ char tmp_val[160];
+ high_score the_score;
+
+
+ /* Paranoia -- it may not have opened */
+ if (highscore_fd < 0) return;
+
+
+ /* Assume we will show the first 10 */
+ if (from < 0) from = 0;
+ if (to < 0) to = 10;
+ if (to > MAX_HISCORES) to = MAX_HISCORES;
+
+
+ /* Seek to the beginning */
+ if (highscore_seek(0)) return;
+
+ /* Hack -- Count the high scores */
+ for (i = 0; i < MAX_HISCORES; i++)
+ {
+ if (highscore_read(&the_score)) break;
+ }
+
+ /* Hack -- allow "fake" entry to be last */
+ if ((note == i) && score) i++;
+
+ /* Forget about the last entries */
+ if (i > to) i = to;
+
+
+ /* Show 5 per page, until "done" */
+ for (k = from, place = k + 1; k < i; k += 5)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Title */
+ put_str(format(" %s Hall of Fame", game_module), 0, 0);
+
+ /* Indicate non-top scores */
+ if (k > 0)
+ {
+ sprintf(tmp_val, "(from position %d)", k + 1);
+ put_str(tmp_val, 0, 40);
+ }
+
+ /* Dump 5 entries */
+ for (j = k, n = 0; j < i && n < 5; place++, j++, n++)
+ {
+ int pcs, pr, ps, pc, clev, mlev, cdun, mdun;
+
+ cptr user, gold, when, aged;
+
+ int in_arena, in_quest;
+
+ /* Hack -- indicate death in yellow */
+ attr = (j == note) ? TERM_YELLOW : TERM_WHITE;
+
+
+ /* Mega-Hack -- insert a "fake" record */
+ if ((note == j) && score)
+ {
+ the_score = (*score);
+ attr = TERM_L_GREEN;
+ score = NULL;
+ note = -1;
+ j--;
+ }
+
+ /* Read a normal record */
+ else
+ {
+ /* Read the proper record */
+ if (highscore_seek(j)) break;
+ if (highscore_read(&the_score)) break;
+ }
+
+ /* Extract the race/class */
+ pr = atoi(the_score.p_r);
+ ps = atoi(the_score.p_s);
+ pc = atoi(the_score.p_c);
+ pcs = atoi(the_score.p_cs);
+
+ /* Extract the level info */
+ clev = atoi(the_score.cur_lev);
+ mlev = atoi(the_score.max_lev);
+ cdun = atoi(the_score.cur_dun);
+ mdun = atoi(the_score.max_dun);
+
+ in_arena = atoi(the_score.inside_arena);
+ in_quest = atoi(the_score.inside_quest);
+
+ /* Hack -- extract the gold and such */
+ for (user = the_score.uid; isspace(*user); user++) /* loop */;
+ for (when = the_score.day; isspace(*when); when++) /* loop */;
+ for (gold = the_score.gold; isspace(*gold); gold++) /* loop */;
+ for (aged = the_score.turns; isspace(*aged); aged++) /* loop */;
+
+ /* Dump some info */
+ sprintf(out_val, "%3d.%9s %s the %s %s, Level %d",
+ place, the_score.pts, the_score.who,
+ get_player_race_name(pr, ps), class_info[pc].spec[pcs].title + c_name,
+ clev);
+
+ /* Append a "maximum level" */
+ if (mlev > clev) strcat(out_val, format(" (Max %d)", mlev));
+
+ /* Dump the first line */
+ c_put_str(attr, out_val, n*4 + 2, 0);
+
+ /* Another line of info */
+ if (in_arena)
+ {
+ sprintf(out_val, " Killed by %s in the Arena",
+ the_score.how);
+ }
+ else if (in_quest)
+ {
+ sprintf(out_val, " Killed by %s while questing",
+ the_score.how);
+ }
+ /* Hack -- some people die in the town */
+ else if (!cdun)
+ {
+ sprintf(out_val, " Killed by %s in the Town",
+ the_score.how);
+ }
+ else
+ {
+ sprintf(out_val, " Killed by %s on %s %d",
+ the_score.how, "Dungeon Level", cdun);
+ }
+
+ /* Append a "maximum level" */
+ if (mdun > cdun) strcat(out_val, format(" (Max %d)", mdun));
+
+ /* Dump the info */
+ c_put_str(attr, out_val, n*4 + 3, 0);
+
+ /* And still another line of info */
+ sprintf(out_val,
+ " (User %s, Date %s, Gold %s, Turn %s).",
+ user, when, gold, aged);
+ c_put_str(attr, out_val, n*4 + 4, 0);
+ }
+
+
+ /* Wait for response */
+ prt("[Press ESC to quit, any other key to continue.]", 23, 17);
+ j = inkey();
+ prt("", 23, 0);
+
+ /* Hack -- notice Escape */
+ if (j == ESCAPE) break;
+ }
+}
+
+
+/*
+ * Hack -- Display the scores in a given range and quit.
+ *
+ * This function is only called from "main.c" when the user asks
+ * to see the "high scores".
+ */
+void display_scores(int from, int to)
+{
+ char buf[1024];
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
+
+ /* Open the binary high score file, for reading */
+ highscore_fd = fd_open(buf, O_RDONLY);
+
+ /* Paranoia -- No score file */
+ if (highscore_fd < 0) quit("Score file unavailable.");
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Display the scores */
+ display_scores_aux(from, to, -1, NULL);
+
+ /* Shut the high score file */
+ (void)fd_close(highscore_fd);
+
+ /* Forget the high score fd */
+ highscore_fd = -1;
+
+ /* Quit */
+ quit(NULL);
+}
+
+
+/*
+ * show_highclass - selectively list highscores based on class
+ * -KMW-
+ */
+void show_highclass(int building)
+{
+
+ register int i = 0, j, m = 0;
+ int pr, pc, clev, al;
+ high_score the_score;
+ char buf[1024], out_val[256];
+
+ switch (building)
+ {
+ case 1:
+ prt(" Busts of Greatest Kings", 5, 0);
+ break;
+ case 2:
+ prt(" Plaque - Greatest Arena Champions", 5, 0);
+ break;
+ case 10:
+ prt(" Plaque - Greatest Fighters", 5, 0);
+ break;
+ case 11:
+ prt(" Spires of the Greatest Magic-Users", 5, 0);
+ break;
+ case 12:
+ prt(" Busts of Greatest Priests", 5, 0);
+ break;
+ case 13:
+ prt(" Wall Inscriptions - Greatest Thieves", 5, 0);
+ break;
+ case 14:
+ prt(" Plaque - Greatest Rangers", 5, 0);
+ break;
+ case 15:
+ prt(" Plaque - Greatest Paladins", 5, 0);
+ break;
+ case 16:
+ prt(" Spires of the Greatest Illusionists", 5, 0);
+ break;
+ default:
+ bell();
+ break;
+ }
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
+
+ /* Open file */
+ highscore_fd = fd_open(buf, O_RDONLY);
+
+ if (highscore_fd < 0)
+ {
+ msg_print("Score file unavailable.");
+ msg_print(NULL);
+ return;
+ }
+
+ if (highscore_seek(0)) return;
+
+ for (i = 0; i < MAX_HISCORES; i++)
+ if (highscore_read(&the_score)) break;
+
+ m = 0;
+ j = 0;
+ clev = 0;
+
+ while ((m < 9) || (j < MAX_HISCORES))
+ {
+ if (highscore_seek(j)) break;
+ if (highscore_read(&the_score)) break;
+ pr = atoi(the_score.p_r);
+ pc = atoi(the_score.p_c);
+ clev = atoi(the_score.cur_lev);
+ al = atoi(the_score.arena_number);
+ if (((pc == (building - 10)) && (building != 1) && (building != 2)) ||
+ ((building == 1) && (clev >= PY_MAX_LEVEL)) ||
+ ((building == 2) && (al > MAX_ARENA_MONS)))
+ {
+ sprintf(out_val, "%3d) %s the %s (Level %2d)",
+ (m + 1), the_score.who, rp_name + race_info[pr].title, clev);
+ prt(out_val, (m + 7), 0);
+ m++;
+ }
+ j++;
+ }
+
+ /* Now, list the active player if they qualify */
+ if ((building == 1) && (p_ptr->lev >= PY_MAX_LEVEL))
+ {
+ sprintf(out_val, "You) %s the %s (Level %2d)",
+ player_name, rp_name + race_info[p_ptr->prace].title, p_ptr->lev);
+ prt(out_val, (m + 8), 0);
+ }
+ else if ((building == 2) && (p_ptr->arena_number > MAX_ARENA_MONS))
+ {
+ sprintf(out_val, "You) %s the %s (Level %2d)",
+ player_name, rp_name + race_info[p_ptr->prace].title, p_ptr->lev);
+ prt(out_val, (m + 8), 0);
+ }
+ else if ((building != 1) && (building != 2))
+ {
+ if ((p_ptr->lev > clev) && (p_ptr->pclass == (building - 10)))
+ {
+ sprintf(out_val, "You) %s the %s (Level %2d)",
+ player_name, rp_name + race_info[p_ptr->prace].title, p_ptr->lev);
+ prt(out_val, (m + 8), 0);
+ }
+ }
+
+ (void)fd_close(highscore_fd);
+ highscore_fd = -1;
+ msg_print("Hit any key to continue");
+ msg_print(NULL);
+ for (j = 5; j < 18; j++)
+ prt("", j, 0);
+}
+
+
+/*
+ * Race Legends
+ * -KMW-
+ */
+void race_score(int race_num)
+{
+ register int i = 0, j, m = 0;
+ int pr, clev, lastlev;
+ high_score the_score;
+ char buf[1024], out_val[256], tmp_str[80];
+
+ lastlev = 0;
+
+ /* rr9: TODO - pluralize the race */
+ sprintf(tmp_str, "The Greatest of all the %s", rp_name + race_info[race_num].title);
+ prt(tmp_str, 5, 3);
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
+
+ /* Open the highscore file */
+ highscore_fd = fd_open(buf, O_RDONLY);
+
+ if (highscore_fd < 0)
+ {
+ msg_print("Score file unavailable.");
+ msg_print(NULL);
+ return;
+ }
+
+ if (highscore_seek(0)) return;
+
+ for (i = 0; i < MAX_HISCORES; i++)
+ {
+ if (highscore_read(&the_score)) break;
+ }
+
+ m = 0;
+ j = 0;
+
+ while ((m < 10) && (j < i))
+ {
+ if (highscore_seek(j)) break;
+ if (highscore_read(&the_score)) break;
+ pr = atoi(the_score.p_r);
+ clev = atoi(the_score.cur_lev);
+ if (pr == race_num)
+ {
+ sprintf(out_val, "%3d) %s the %s (Level %3d)",
+ (m + 1), the_score.who,
+ rp_name + race_info[pr].title, clev);
+ prt(out_val, (m + 7), 0);
+ m++;
+ lastlev = clev;
+ }
+ j++;
+ }
+
+ /* add player if qualified */
+ if ((p_ptr->prace == race_num) && (p_ptr->lev >= lastlev))
+ {
+ sprintf(out_val, "You) %s the %s (Level %3d)",
+ player_name, rp_name + race_info[p_ptr->prace].title, p_ptr->lev);
+ prt(out_val, (m + 8), 0);
+ }
+
+ (void)fd_close(highscore_fd);
+ highscore_fd = -1;
+}
+
+
+/*
+ * Race Legends
+ * -KMW-
+ */
+void race_legends(void)
+{
+ int i, j;
+
+ for (i = 0; i < max_rp_idx; i++)
+ {
+ race_score(i);
+ msg_print("Hit any key to continue");
+ msg_print(NULL);
+ for (j = 5; j < 19; j++)
+ prt("", j, 0);
+ }
+}
+
+
+
+
+/*
+ * Enters a players name on a hi-score table, if "legal", and in any
+ * case, displays some relevant portion of the high score list.
+ *
+ * Assumes "signals_ignore_tstp()" has been called.
+ */
+static errr top_twenty(void)
+{
+ int j;
+
+ high_score the_score;
+
+ time_t ct = time((time_t*)0);
+
+
+ /* Clear screen */
+ Term_clear();
+
+ /* No score file */
+ if (highscore_fd < 0)
+ {
+ msg_print("Score file unavailable.");
+ msg_print(NULL);
+ return (0);
+ }
+
+#ifndef SCORE_WIZARDS
+ /* Wizard-mode pre-empts scoring */
+ if (noscore & 0x000F)
+ {
+ msg_print("Score not registered for wizards.");
+ msg_print(NULL);
+ display_scores_aux(0, 10, -1, NULL);
+ return (0);
+ }
+#endif
+
+#ifndef SCORE_BORGS
+ /* Borg-mode pre-empts scoring */
+ if (noscore & 0x00F0)
+ {
+ msg_print("Score not registered for borgs.");
+ msg_print(NULL);
+ display_scores_aux(0, 10, -1, NULL);
+ return (0);
+ }
+#endif
+
+#ifndef SCORE_CHEATERS
+ /* Cheaters are not scored */
+ if (noscore & 0xFF00)
+ {
+ msg_print("Score not registered for cheaters.");
+ msg_print(NULL);
+ display_scores_aux(0, 10, -1, NULL);
+ return (0);
+ }
+#endif
+
+ /* Interupted */
+ if (!total_winner && streq(died_from, "Interrupting"))
+ {
+ msg_print("Score not registered due to interruption.");
+ msg_print(NULL);
+ display_scores_aux(0, 10, -1, NULL);
+ return (0);
+ }
+
+ /* Quitter */
+ if (!total_winner && streq(died_from, "Quitting"))
+ {
+ msg_print("Score not registered due to quitting.");
+ msg_print(NULL);
+ display_scores_aux(0, 10, -1, NULL);
+ return (0);
+ }
+
+
+ /* Clear the record */
+ WIPE(&the_score, high_score);
+
+ /* Save the version */
+ sprintf(the_score.what, "%ld.%ld.%ld",
+ (long int) VERSION_MAJOR, (long int) VERSION_MINOR, (long int) VERSION_PATCH);
+
+ /* Calculate and save the points */
+ sprintf(the_score.pts, "%9lu", (long)total_points());
+ the_score.pts[9] = '\0';
+
+ /* Save the current gold */
+ sprintf(the_score.gold, "%9lu", (long)p_ptr->au);
+ the_score.gold[9] = '\0';
+
+ /* Save the current turn */
+ sprintf(the_score.turns, "%9lu", (long)turn - (START_DAY * 10L));
+ the_score.turns[9] = '\0';
+
+#ifdef HIGHSCORE_DATE_HACK
+ /* Save the date in a hacked up form (9 chars) */
+ sprintf(the_score.day, "%-.6s %-.2s", ctime(&ct) + 4, ctime(&ct) + 22);
+#else
+ /* Save the date in standard form (8 chars) */
+ strftime(the_score.day, 9, "%m/%d/%y", localtime(&ct));
+#endif
+
+ /* Save the player name (15 chars) */
+ sprintf(the_score.who, "%-.15s", player_name);
+
+ /* Save the player info XXX XXX XXX */
+ sprintf(the_score.uid, "%7u", player_uid);
+ sprintf(the_score.sex, "%c", (p_ptr->psex ? 'm' : 'f'));
+ sprintf(the_score.p_r, "%2d", p_ptr->prace);
+ sprintf(the_score.p_s, "%2d", p_ptr->pracem);
+ sprintf(the_score.p_c, "%2d", p_ptr->pclass);
+ sprintf(the_score.p_cs, "%2d", p_ptr->pspec);
+
+ /* Save the level and such */
+ sprintf(the_score.cur_lev, "%3d", p_ptr->lev);
+ sprintf(the_score.cur_dun, "%3d", dun_level);
+ sprintf(the_score.max_lev, "%3d", p_ptr->max_plv);
+ sprintf(the_score.max_dun, "%3d", max_dlv[dungeon_type]);
+
+ sprintf(the_score.arena_number, "%3d", p_ptr->arena_number); /* -KMW- */
+ sprintf(the_score.inside_arena, "%3d", p_ptr->inside_arena);
+ sprintf(the_score.inside_quest, "%3d", p_ptr->inside_quest);
+ sprintf(the_score.exit_bldg, "%3d", p_ptr->exit_bldg); /* -KMW- */
+
+ /* Save the cause of death (31 chars) */
+ sprintf(the_score.how, "%-.31s", died_from);
+
+
+ /* Lock (for writing) the highscore file, or fail */
+ if (fd_lock(highscore_fd, F_WRLCK)) return (1);
+
+ /* Add a new entry to the score list, see where it went */
+ j = highscore_add(&the_score);
+
+ /* Unlock the highscore file, or fail */
+ if (fd_lock(highscore_fd, F_UNLCK)) return (1);
+
+
+ /* Hack -- Display the top fifteen scores */
+ if (j < 10)
+ {
+ display_scores_aux(0, 15, j, NULL);
+ }
+
+ /* Display the scores surrounding the player */
+ else
+ {
+ display_scores_aux(0, 5, j, NULL);
+ display_scores_aux(j - 2, j + 7, j, NULL);
+ }
+
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Predict the players location, and display it.
+ */
+errr predict_score(void)
+{
+ int j;
+
+ high_score the_score;
+
+
+ /* No score file */
+ if (highscore_fd < 0)
+ {
+ msg_print("Score file unavailable.");
+ msg_print(NULL);
+ return (0);
+ }
+
+
+ /* Save the version */
+ sprintf(the_score.what, "%ld.%ld.%ld",
+ (long int) VERSION_MAJOR, (long int) VERSION_MINOR, (long int) VERSION_PATCH);
+
+ /* Calculate and save the points */
+ sprintf(the_score.pts, "%9lu", (long)total_points());
+ the_score.pts[9] = '\0';
+
+ /* Save the current gold */
+ sprintf(the_score.gold, "%9lu", (long)p_ptr->au);
+ the_score.gold[9] = '\0';
+
+ /* Save the current turn */
+ sprintf(the_score.turns, "%9lu", (long)turn - (START_DAY * 10L));
+ the_score.turns[9] = '\0';
+
+ /* Hack -- no time needed */
+ strcpy(the_score.day, "TODAY");
+
+ /* Save the player name (15 chars) */
+ sprintf(the_score.who, "%-.15s", player_name);
+
+ /* Save the player info XXX XXX XXX */
+ sprintf(the_score.uid, "%7u", player_uid);
+ sprintf(the_score.sex, "%c", (p_ptr->psex ? 'm' : 'f'));
+ sprintf(the_score.p_r, "%2d", p_ptr->prace);
+ sprintf(the_score.p_s, "%2d", p_ptr->pracem);
+ sprintf(the_score.p_c, "%2d", p_ptr->pclass);
+ sprintf(the_score.p_cs, "%2d", p_ptr->pspec);
+
+ /* Save the level and such */
+ sprintf(the_score.cur_lev, "%3d", p_ptr->lev);
+ sprintf(the_score.cur_dun, "%3d", dun_level);
+ sprintf(the_score.max_lev, "%3d", p_ptr->max_plv);
+ sprintf(the_score.max_dun, "%3d", max_dlv[dungeon_type]);
+
+ sprintf(the_score.arena_number, "%3d", p_ptr->arena_number); /* -KMW- */
+ sprintf(the_score.inside_arena, "%3d", p_ptr->inside_arena);
+ sprintf(the_score.inside_quest, "%3d", p_ptr->inside_quest);
+ sprintf(the_score.exit_bldg, "%3d", p_ptr->exit_bldg); /* -KMW- */
+
+ /* Hack -- no cause of death */
+ strcpy(the_score.how, "nobody (yet!)");
+
+
+ /* See where the entry would be placed */
+ j = highscore_where(&the_score);
+
+
+ /* Hack -- Display the top fifteen scores */
+ if (j < 10)
+ {
+ display_scores_aux(0, 15, j, &the_score);
+ }
+
+ /* Display some "useful" scores */
+ else
+ {
+ display_scores_aux(0, 5, -1, NULL);
+ display_scores_aux(j - 2, j + 7, j, &the_score);
+ }
+
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Change the player into a King! -RAK-
+ */
+static void kingly(void)
+{
+ /* Hack -- retire in town */
+ dun_level = 0;
+
+ /* Fake death */
+ (void)strcpy(died_from, "Ripe Old Age");
+
+ /* Restore the experience */
+ p_ptr->exp = p_ptr->max_exp;
+
+ /* Restore the level */
+ p_ptr->lev = p_ptr->max_plv;
+
+ /* Hack -- Instant Gold */
+ p_ptr->au += 10000000L;
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Would like to see something more Tolkienian here... */
+
+ /* Display a crown */
+ put_str("#", 1, 34);
+ put_str("#####", 2, 32);
+ put_str("#", 3, 34);
+ put_str(",,, $$$ ,,,", 4, 28);
+ put_str(",,=$ \"$$$$$\" $=,,", 5, 24);
+ put_str(",$$ $$$ $$,", 6, 22);
+ put_str("*> <*> <*", 7, 22);
+ put_str("$$ $$$ $$", 8, 22);
+ put_str("\"$$ $$$ $$\"", 9, 22);
+ put_str("\"$$ $$$ $$\"", 10, 23);
+ put_str("*#########*#########*", 11, 24);
+ put_str("*#########*#########*", 12, 24);
+
+ /* Display a message */
+ put_str("Veni, Vidi, Vici!", 15, 26);
+ put_str("I came, I saw, I conquered!", 16, 21);
+ put_str(format("All Hail the Mighty %s!", sp_ptr->winner), 17, 22);
+
+ /* Flush input */
+ flush();
+
+ /* Wait for response */
+ pause_line(23);
+}
+
+
+/*
+ * Wipe the saved levels
+ */
+void wipe_saved()
+{
+ int d, l, od = dungeon_type, ol = dun_level;
+
+ for (d = 0; d < max_d_idx; d++)
+ {
+ dungeon_info_type *d_ptr = &d_info[d];
+
+ for (l = d_ptr->mindepth; l <= d_ptr->maxdepth; l++)
+ {
+ char buf[10];
+
+ dun_level = l;
+ dungeon_type = d;
+ if (get_dungeon_save(buf))
+ {
+ char tmp[80], name[1024];
+
+ sprintf(tmp, "%s.%s", player_base, buf);
+ path_build(name, 1024, ANGBAND_DIR_SAVE, tmp);
+
+ /* Remove the dungeon save file */
+ fd_kill(name);
+ }
+ }
+ }
+
+ dungeon_type = od;
+ dun_level = ol;
+}
+
+
+/*
+ * Close up the current game (player may or may not be dead)
+ *
+ * This function is called only from "main.c" and "signals.c".
+ */
+void close_game(void)
+{
+ char buf[1024];
+
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Flush the messages */
+ msg_print(NULL);
+
+ /* Flush the input */
+ flush();
+
+
+ /* No suspending now */
+ signals_ignore_tstp();
+
+ /* Hack -- Character is now "icky" */
+ character_icky = TRUE;
+
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
+
+ /* Open the high score file, for reading/writing */
+ highscore_fd = fd_open(buf, O_RDWR);
+
+ /* Handle death */
+ if (death)
+ {
+ /* Handle retirement */
+ if (total_winner)
+ {
+ /* Write a note, if that option is on */
+ if (take_notes)
+ {
+ add_note_type(NOTE_WINNER);
+ }
+
+ kingly();
+ }
+
+ /* Wipe the saved levels */
+ wipe_saved();
+
+ /* Save memories */
+ if (!save_player()) msg_print("Death save failed!");
+
+ /* You are dead */
+ print_tomb();
+
+ /* Show more info */
+ show_info();
+
+ /* Write a note */
+ if (take_notes)
+ {
+ char long_day[30];
+ char buf[80];
+ time_t ct = time((time_t*)NULL);
+
+ /* Get the date */
+ strftime(long_day, 30,
+ "%Y-%m-%d at %H:%M:%S", localtime(&ct));
+
+ /* Create string */
+ sprintf(buf, "\n%s was killed by %s on %s\n", player_name,
+ died_from, long_day);
+
+ /* Output to the notes file */
+ output_note(buf);
+ }
+
+ /* Handle score, show Top scores */
+ top_twenty();
+ }
+
+ /* Still alive */
+ else
+ {
+ is_autosave = FALSE;
+
+ /* Save the game */
+ do_cmd_save_game();
+
+ /* If note-taking enabled, write session end to notes file */
+ if (take_notes)
+ {
+ add_note_type(NOTE_SAVE_GAME);
+ }
+
+ /* Prompt for scores XXX XXX XXX */
+ prt("Press Return (or Escape).", 0, 40);
+
+ /* Predict score (or ESCAPE) */
+ if (inkey() != ESCAPE) predict_score();
+ }
+
+
+ /* Shut the high score file */
+ (void)fd_close(highscore_fd);
+
+ /* Forget the high score fd */
+ highscore_fd = -1;
+
+ /* Allow suspending now */
+ signals_handle_tstp();
+}
+
+
+/*
+ * Grab a randomly selected line in lib/file/file_name
+ */
+errr get_rnd_line(char *file_name, char *output)
+{
+ FILE *fp;
+
+ char buf[1024];
+
+ int lines = 0;
+
+ int line;
+
+ int i;
+
+
+ /* Clear the output buffer */
+ strcpy(output, "");
+
+ /* test hack */
+ if (wizard && cheat_xtra) msg_print(file_name);
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_FILE, file_name);
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Failed */
+ if (!fp) return ( -1);
+
+ /* Read the first line */
+ if (0 != my_fgets(fp, buf, 80))
+ {
+ my_fclose(fp);
+ return ( -1);
+ }
+
+ /* Retrieve number of valid lines in the file */
+ lines = atoi(buf);
+
+ /* Pick a line in the file */
+ line = randint(lines);
+
+ /*
+ * Scan through the file XXX XXX XXX
+ * Seemingly wrong use of the counter is justified by the
+ * stupid 'buffer' lines in the random text files.
+ */
+ for (i = 0; i <= line; i++)
+ {
+ if (0 != my_fgets(fp, buf, 80))
+ {
+ my_fclose(fp);
+ return ( -1);
+ }
+
+ /* Found the line */
+ if (i == line) break;
+ }
+
+ /* Copy the line to the output buffer */
+ strcpy(output, buf);
+
+ /* Close the file */
+ my_fclose(fp);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Read line'th line file the file
+ * and return pointer to it, or NULL if it fails.
+ *
+ * Nuked the static buffer. Caller should provide one. -- pelpel
+ *
+ * Caution: 'linbuf' should be at least 80 byte long.
+ */
+char *get_line(char* fname, cptr fdir, char *linbuf, int line)
+{
+ FILE* fp;
+ int i;
+ char buf[1024];
+
+
+ /* Don't count the first line in the file, which is a comment line */
+ line++;
+
+ /* Build the filename */
+ path_build(buf, 1024, fdir, fname);
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Failed */
+ if (!fp) return (NULL);
+
+ /* Read past specified number of lines */
+ for (i = 0; i <= line; i++)
+ {
+ /* Oops */
+ if (my_fgets(fp, linbuf, 80) != 0)
+ {
+ my_fclose(fp);
+ return (NULL);
+ }
+ }
+
+ my_fclose(fp);
+
+ return (linbuf);
+}
+
+
+/*
+ * Return a line for a speaking unique, by Matt G.
+ *
+ * XXX XXX XXX Opening a file and scanning it through whenever a unique
+ * tries to say something? Something like DELAY_LOAD_?_TEXT would be
+ * much better -- pelpel
+ *
+ * XXX XXX XXX I must say the original is an extremely poor and unreliable
+ * implementation... I removed noxious flag -- I'm too stupid to
+ * understand such complexities -- and added extra error checkings
+ * and made sure fd is always closed -- pelpel
+ */
+errr get_xtra_line(char *file_name, monster_type *m_ptr, char *output)
+{
+ FILE *fp;
+ char buf[1024];
+ int line;
+ int num_entries;
+ int i;
+ int mnum;
+
+
+ /* Clear the message buffer */
+ strcpy(output, "");
+
+ /* test and DEBUG hack */
+ if (wizard && cheat_xtra)
+ {
+ msg_print(file_name);
+ }
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_FILE, file_name);
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Failed */
+ if (!fp) return ( -1);
+
+ /* Monster number we are looking for */
+ mnum = m_ptr->r_idx;
+
+ /* Find matching N: line */
+ while (1)
+ {
+ int n;
+
+ /* Read a line */
+ if (my_fgets(fp, buf, 90) != 0)
+ {
+ my_fclose(fp);
+ return ( -1);
+ }
+
+ /* Not a N: line */
+ if (buf[0] != 'N') continue;
+
+ /* Skip "N:" and parse off a number */
+ sscanf(buf + 2, "%d", &n);
+
+ /* Match found */
+ if (n == mnum) break;
+ }
+
+ /* Retrieve number of normal messages */
+ while (1)
+ {
+ /* Read next line */
+ if (my_fgets(fp, buf, 90) != 0)
+ {
+ my_fclose(fp);
+ return ( -1);
+ }
+
+ /* The first line not beginning with 'N:' holds number of lines */
+ if (buf[0] != 'N')
+ {
+ num_entries = atoi(buf);
+ break;
+ }
+ }
+
+ /* The monster is afraid */
+ if (m_ptr->monfear)
+ {
+ /* Read past normal lines */
+ for (line = 0; line < num_entries + 1; line++)
+ {
+ if (my_fgets(fp, buf, 90))
+ {
+ my_fclose(fp);
+ return ( -1);
+ }
+ }
+
+ /* Retrieve number of 'afraid' lines */
+ num_entries = atoi(buf);
+ }
+
+
+ /* Pick a random line */
+ line = rand_int(num_entries);
+
+ /* test and DEBUG hack */
+ if (wizard && cheat_xtra)
+ {
+ sprintf(buf, "Line number %d", line);
+ msg_print(buf);
+ }
+
+ /* Find the selected line */
+ for (i = 0; i <= line; i++)
+ {
+ /* Oops */
+ if (0 != my_fgets(fp, buf, 90))
+ {
+ my_fclose(fp);
+ return ( -1);
+ }
+
+ /* Found it */
+ if (i == line) break;
+ }
+
+ /* Copy it to the output buffer */
+ strcpy(output, buf);
+
+ /* Close the file */
+ my_fclose(fp);
+
+ /* Success */
+ return (0);
+}
+
+
+#ifdef HANDLE_SIGNALS
+
+
+#include <signal.h>
+
+
+/*
+ * Handle signals -- suspend
+ *
+ * Actually suspend the game, and then resume cleanly
+ */
+static void handle_signal_suspend(int sig)
+{
+ /* Disable handler */
+ (void)signal(sig, SIG_IGN);
+
+#ifdef SIGSTOP
+
+ /* Flush output */
+ Term_fresh();
+
+ /* Suspend the "Term" */
+ Term_xtra(TERM_XTRA_ALIVE, 0);
+
+ /* Suspend ourself */
+ (void)kill(0, SIGSTOP);
+
+ /* Resume the "Term" */
+ Term_xtra(TERM_XTRA_ALIVE, 1);
+
+ /* Redraw the term */
+ Term_redraw();
+
+ /* Flush the term */
+ Term_fresh();
+
+#endif
+
+ /* Restore handler */
+ (void)signal(sig, handle_signal_suspend);
+}
+
+
+/*
+ * Ignore SIGTSTP signals (keyboard suspend)
+ */
+void signals_ignore_tstp(void)
+{
+
+#ifdef SIGTSTP
+ (void)signal(SIGTSTP, SIG_IGN);
+#endif
+
+}
+
+/*
+ * Handle SIGTSTP signals (keyboard suspend)
+ */
+void signals_handle_tstp(void)
+{
+
+#ifdef SIGTSTP
+ (void)signal(SIGTSTP, handle_signal_suspend);
+#endif
+
+}
+
+
+/*
+ * Prepare to handle the relevant signals
+ */
+void signals_init(void)
+{
+
+#ifdef SIGHUP
+ (void)signal(SIGHUP, SIG_IGN);
+#endif
+
+
+#ifdef SIGTSTP
+ (void)signal(SIGTSTP, handle_signal_suspend);
+#endif
+
+}
+
+
+#else /* HANDLE_SIGNALS */
+
+
+/*
+* Do nothing
+*/
+void signals_ignore_tstp(void)
+{}
+
+/*
+* Do nothing
+*/
+void signals_handle_tstp(void)
+{}
+
+/*
+* Do nothing
+*/
+void signals_init(void)
+{}
+
+
+#endif /* HANDLE_SIGNALS */
diff --git a/src/gen_evol.c b/src/gen_evol.c
new file mode 100644
index 00000000..bfdfbd68
--- /dev/null
+++ b/src/gen_evol.c
@@ -0,0 +1,156 @@
+/*
+ * Generate a game of life level and make it evolve
+ */
+
+/*
+ * Copyright (c) 2003 DarkGod.
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Generate a game of life level :) and make it evolve
+ */
+void evolve_level(bool_ noise)
+{
+ int i, j;
+
+ int cw = 0, cf = 0;
+
+
+ /* Add a bit of noise */
+ if (noise)
+ {
+ for (i = 1; i < cur_wid - 1; i++)
+ {
+ for (j = 1; j < cur_hgt - 1; j++)
+ {
+ if (f_info[cave[j][i].feat].flags1 & FF1_WALL) cw++;
+ if (f_info[cave[j][i].feat].flags1 & FF1_FLOOR) cf++;
+ }
+ }
+
+ for (i = 1; i < cur_wid - 1; i++)
+ {
+ for (j = 1; j < cur_hgt - 1; j++)
+ {
+ cave_type *c_ptr;
+
+ /* Access the grid */
+ c_ptr = &cave[j][i];
+
+ /* Permanent features should stay */
+ if (f_info[c_ptr->feat].flags1 & FF1_PERMANENT) continue;
+
+ /* Avoid evolving grids with object or monster */
+ if (c_ptr->o_idx || c_ptr->m_idx) continue;
+
+ /* Avoid evolving player grid */
+ if ((j == p_ptr->py) && (i == p_ptr->px)) continue;
+
+ if (magik(7))
+ {
+ if (cw > cf)
+ {
+ place_floor(j, i);
+ }
+ else
+ {
+ place_filler(j, i);
+ }
+ }
+ }
+ }
+ }
+
+ for (i = 1; i < cur_wid - 1; i++)
+ {
+ for (j = 1; j < cur_hgt - 1; j++)
+ {
+ int x, y, c;
+ cave_type *c_ptr;
+
+ /* Access the grid */
+ c_ptr = &cave[j][i];
+
+ /* Permanent features should stay */
+ if (f_info[c_ptr->feat].flags1 & FF1_PERMANENT) continue;
+
+ /* Avoid evolving grids with object or monster */
+ if (c_ptr->o_idx || c_ptr->m_idx) continue;
+
+ /* Avoid evolving player grid */
+ if ((j == p_ptr->py) && (i == p_ptr->px)) continue;
+
+
+ /* Reset tally */
+ c = 0;
+
+ /* Count number of surrounding walls */
+ for (x = i - 1; x <= i + 1; x++)
+ {
+ for (y = j - 1; y <= j + 1; y++)
+ {
+ if ((x == i) && (y == j)) continue;
+ if (f_info[cave[y][x].feat].flags1 & FF1_WALL) c++;
+ }
+ }
+
+ /*
+ * Changed these parameters a bit, so that it doesn't produce
+ * too open or too narrow levels -- pelpel
+ */
+ /* Starved or suffocated */
+ if ((c < 4) || (c >= 7))
+ {
+ if (f_info[c_ptr->feat].flags1 & FF1_WALL)
+ {
+ place_floor(j, i);
+ }
+ }
+
+ /* Spawned */
+ else if ((c == 4) || (c == 5))
+ {
+ if (!(f_info[c_ptr->feat].flags1 & FF1_WALL))
+ {
+ place_filler(j, i);
+ }
+ }
+ }
+ }
+
+ /* Notice changes */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_FLOW | PU_MON_LITE);
+}
+
+
+bool_ level_generate_life()
+{
+ int i, j;
+
+ for (i = 1; i < cur_wid - 1; i++)
+ {
+ for (j = 1; j < cur_hgt - 1; j++)
+ {
+ cave[j][i].info = (CAVE_ROOM | CAVE_GLOW | CAVE_MARK);
+ if (magik(45)) place_floor(j, i);
+ else place_filler(j, i);
+ }
+ }
+
+ evolve_level(FALSE);
+ evolve_level(FALSE);
+ evolve_level(FALSE);
+
+ /* Determine the character location */
+ if (!new_player_spot(get_branch()))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/src/gen_maze.c b/src/gen_maze.c
new file mode 100644
index 00000000..92cb482f
--- /dev/null
+++ b/src/gen_maze.c
@@ -0,0 +1,294 @@
+/*
+ * Maze dungeon generator
+ */
+
+/*
+ * Copyright (c) 2003 DarkGod. And somebody who posted the algorith on
+ * rec.games.roguelike.development. I can't remember teh name :( please mail me
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * If we wasted static memory for this, it would look like:
+ *
+ * static char maze[(MAX_HGT / 2) + 2][(MAX_WID / 2) + 2];
+ */
+typedef signed char maze_row[(MAX_WID / 2) + 2];
+
+void dig(maze_row *maze, int y, int x, int d)
+{
+ int k;
+ int dy = 0, dx = 0;
+
+ /*
+ * first, open the wall of the new cell
+ * in the direction we come from.
+ */
+ switch (d)
+ {
+ case 0:
+ {
+ maze[y][x] |= 4;
+ break;
+ }
+
+ case 1:
+ {
+ maze[y][x] |= 8;
+ break;
+ }
+
+ case 2:
+ {
+ maze[y][x] |= 1;
+ break;
+ }
+
+ case 3:
+ {
+ maze[y][x] |= 2;
+ break;
+ }
+ }
+
+ /*
+ * try to chage direction, here 50% times.
+ * with smaller values (say 25%) the maze
+ * is made of long straight corridors. with
+ * greaters values (say 75%) the maze is
+ * very "turny".
+ */
+ if (rand_range(1, 100) < 50) d = rand_range(0, 3);
+
+ for (k = 1; k <= 4; k++)
+ {
+ switch (d)
+ {
+ case 0:
+ {
+ dy = 0;
+ dx = 1;
+ break;
+ }
+
+ case 1:
+ {
+ dy = -1;
+ dx = 0;
+ break;
+ }
+
+ case 2:
+ {
+ dy = 0;
+ dx = -1;
+ break;
+ }
+
+ case 3:
+ {
+ dy = 1;
+ dx = 0;
+ break;
+ }
+ }
+
+ if (maze[y + dy][x + dx] == 0)
+ {
+ /*
+ * now, open the wall of the new cell
+ * in the direction we go to.
+ */
+ switch (d)
+ {
+ case 0:
+ {
+ maze[y][x] |= 1;
+ break;
+ }
+
+ case 1:
+ {
+ maze[y][x] |= 2;
+ break;
+ }
+
+ case 2:
+ {
+ maze[y][x] |= 4;
+ break;
+ }
+
+ case 3:
+ {
+ maze[y][x] |= 8;
+ break;
+ }
+ }
+
+ dig(maze, y + dy, x + dx, d);
+ }
+
+ d = (d + 1) % 4;
+ }
+}
+
+
+bool_ level_generate_maze()
+{
+ int i, j, d;
+ int y, dy = 0;
+ int x, dx = 0;
+ int m_1 = 0, m_2 = 0;
+ maze_row *maze;
+
+ /* Allocate temporary memory */
+ C_MAKE(maze, (MAX_HGT / 2) + 2, maze_row);
+
+ /*
+ * the empty maze is:
+ *
+ * -1 -1 ... -1 -1
+ * -1 0 0 -1
+ * . .
+ * . .
+ * -1 0 0 -1
+ * -1 -1 ... -1 -1
+ *
+ * -1 are so-called "sentinel value".
+ * 0 are empty cells.
+ *
+ * walls are not represented, only cells.
+ * at the end of the algorithm each cell
+ * contains a value that is bit mask
+ * representing surrounding walls:
+ *
+ * bit #1
+ *
+ * +------+
+ * | |
+ * bit #2 | | bit #0
+ * | |
+ * +------+
+ *
+ * bit #3
+ *
+ * d is the direction you are digging
+ * to. d value is the bit number:
+ * d=0 --> go east
+ * d=1 --> go north
+ * etc
+ *
+ * you need only 4 bits per cell.
+ * this gives you a very compact
+ * maze representation.
+ *
+ */
+ for (j = 0; j <= (cur_hgt / 2) + 1; j++)
+ {
+ for (i = 0; i <= (cur_wid / 2) + 1; i++)
+ {
+ maze[j][i] = -1;
+ }
+ }
+
+ for (j = 1; j <= (cur_hgt / 2); j++)
+ {
+ for (i = 1; i <= (cur_wid / 2); i++)
+ {
+ maze[j][i] = 0;
+ }
+ }
+
+ y = rand_range(1, (cur_hgt / 2));
+ x = rand_range(1, (cur_wid / 2));
+ d = rand_range(0, 3);
+
+ dig(maze, y, x, d);
+
+ maze[y][x] = 0;
+
+ for (d = 0; d <= 3; d++)
+ {
+ switch (d)
+ {
+ case 0:
+ {
+ dy = 0;
+ dx = 1;
+ m_1 = 1;
+ m_2 = 4;
+ break;
+ }
+
+ case 1:
+ {
+ dy = -1;
+ dx = 0;
+ m_1 = 2;
+ m_2 = 8;
+ break;
+ }
+
+ case 2:
+ {
+ dy = 0;
+ dx = -1;
+ m_1 = 4;
+ m_2 = 1;
+ break;
+ }
+
+ case 3:
+ {
+ dy = 1;
+ dx = 0;
+ m_1 = 8;
+ m_2 = 2;
+ break;
+ }
+ }
+
+ if ((maze[y + dy][x + dx] != -1) &&
+ ((maze[y + dy][x + dx] & m_2) != 0))
+ {
+ maze[y][x] |= m_1;
+ }
+ }
+
+ /* Translate the maze bit array into a real dungeon map -- DG */
+ for (j = 1; j <= (cur_hgt / 2) - 2; j++)
+ {
+ for (i = 1; i <= (cur_wid / 2) - 2; i++)
+ {
+ if (maze[j][i])
+ {
+ place_floor(j * 2, i * 2);
+ }
+
+ if (maze[j][i] & 1)
+ {
+ place_floor(j * 2, i * 2 + 1);
+ }
+
+ if (maze[j][i] & 8)
+ {
+ place_floor(j * 2 + 1, i * 2);
+ }
+ }
+ }
+
+ /* Free temporary memory */
+ C_FREE(maze, (MAX_HGT / 2) + 2, maze_row);
+
+ /* Determine the character location */
+ if (!new_player_spot(get_branch()))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/src/generate.c b/src/generate.c
new file mode 100644
index 00000000..6d83c321
--- /dev/null
+++ b/src/generate.c
@@ -0,0 +1,8890 @@
+/* File: generate.c */
+
+/* Purpose: Dungeon generation */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+#define SAFE_MAX_ATTEMPTS 5000
+
+/*
+ * Note that Level generation is *not* an important bottleneck,
+ * though it can be annoyingly slow on older machines... Thus
+ * we emphasize "simplicity" and "correctness" over "speed".
+ *
+ * This entire file is only needed for generating levels.
+ * This may allow smart compilers to only load it when needed.
+ *
+ * Consider the "v_info.txt" file for vault generation.
+ *
+ * In this file, we use the "special" granite and perma-wall sub-types,
+ * where "basic" is normal, "inner" is inside a room, "outer" is the
+ * outer wall of a room, and "solid" is the outer wall of the dungeon
+ * or any walls that may not be pierced by corridors. Thus the only
+ * wall type that may be pierced by a corridor is the "outer granite"
+ * type. The "basic granite" type yields the "actual" corridors.
+ *
+ * Note that we use the special "solid" granite wall type to prevent
+ * multiple corridors from piercing a wall in two adjacent locations,
+ * which would be messy, and we use the special "outer" granite wall
+ * to indicate which walls "surround" rooms, and may thus be "pierced"
+ * by corridors entering or leaving the room.
+ *
+ * Note that a tunnel which attempts to leave a room near the "edge"
+ * of the dungeon in a direction toward that edge will cause "silly"
+ * wall piercings, but will have no permanently incorrect effects,
+ * as long as the tunnel can *eventually* exit from another side.
+ * And note that the wall may not come back into the room by the
+ * hole it left through, so it must bend to the left or right and
+ * then optionally re-enter the room (at least 2 grids away). This
+ * is not a problem since every room that is large enough to block
+ * the passage of tunnels is also large enough to allow the tunnel
+ * to pierce the room itself several times.
+ *
+ * Note that no two corridors may enter a room through adjacent grids,
+ * they must either share an entryway or else use entryways at least
+ * two grids apart. This prevents "large" (or "silly") doorways.
+ *
+ * To create rooms in the dungeon, we first divide the dungeon up
+ * into "blocks" of 11x11 grids each, and require that all rooms
+ * occupy a rectangular group of blocks. As long as each room type
+ * reserves a sufficient number of blocks, the room building routines
+ * will not need to check bounds. Note that most of the normal rooms
+ * actually only use 23x11 grids, and so reserve 33x11 grids.
+ *
+ * Note that the use of 11x11 blocks (instead of the old 33x11 blocks)
+ * allows more variability in the horizontal placement of rooms, and
+ * at the same time has the disadvantage that some rooms (two thirds
+ * of the normal rooms) may be "split" by panel boundaries. This can
+ * induce a situation where a player is in a room and part of the room
+ * is off the screen. It may be annoying enough to go back to 33x11
+ * blocks to prevent this visual situation.
+ *
+ * Note that the dungeon generation routines are much different (2.7.5)
+ * and perhaps "DUN_ROOMS" should be less than 50.
+ *
+ * XXX XXX XXX Note that it is possible to create a room which is only
+ * connected to itself, because the "tunnel generation" code allows a
+ * tunnel to leave a room, wander around, and then re-enter the room.
+ *
+ * XXX XXX XXX Note that it is possible to create a set of rooms which
+ * are only connected to other rooms in that set, since there is nothing
+ * explicit in the code to prevent this from happening. But this is less
+ * likely than the "isolated room" problem, because each room attempts to
+ * connect to another room, in a giant cycle, thus requiring at least two
+ * bizarre occurances to create an isolated section of the dungeon.
+ *
+ * Note that (2.7.9) monster pits have been split into monster "nests"
+ * and monster "pits". The "nests" have a collection of monsters of a
+ * given type strewn randomly around the room (jelly, animal, or undead),
+ * while the "pits" have a collection of monsters of a given type placed
+ * around the room in an organized manner (orc, troll, giant, dragon, or
+ * demon). Note that both "nests" and "pits" are now "level dependant",
+ * and both make 16 "expensive" calls to the "get_mon_num()" function.
+ *
+ * Note that the cave grid flags changed in a rather drastic manner
+ * for Angband 2.8.0 (and 2.7.9+), in particular, dungeon terrain
+ * features, such as doors and stairs and traps and rubble and walls,
+ * are all handled as a set of 64 possible "terrain features", and
+ * not as "fake" objects (440-479) as in pre-2.8.0 versions.
+ *
+ * The 64 new "dungeon features" will also be used for "visual display"
+ * but we must be careful not to allow, for example, the user to display
+ * hidden traps in a different way from floors, or secret doors in a way
+ * different from granite walls, or even permanent granite in a different
+ * way from granite. XXX XXX XXX
+ */
+
+
+/*
+ * Dungeon generation values
+ */
+#define DUN_ROOMS 50 /* Number of rooms to attempt */
+#define DUN_UNUSUAL 194 /* Level/chance of unusual room (was 200) */
+#define DUN_DEST 18 /* 1/chance of having a destroyed level */
+#define SMALL_LEVEL 6 /* 1/chance of smaller size (3->6) */
+#define EMPTY_LEVEL 15 /* 1/chance of being 'empty' (15)*/
+#define DARK_EMPTY 5 /* 1/chance of arena level NOT being lit (2)*/
+#define XTRA_MAGIC 10 /* 1/chance of having a level with more magic (10)*/
+#define DUN_WILD_VAULT 50 /* Chance of finding a wilderness vault. */
+#define DUN_WAT_RNG 2 /* Width of rivers */
+#define DUN_WAT_CHG 50 /* 1 in 50 chance of junction in river */
+#define DUN_CAVERN 30 /* 1/chance of having a cavern level */
+
+/*
+ * Dungeon tunnel generation values
+ */
+#define DUN_TUN_RND 10 /* Chance of random direction */
+#define DUN_TUN_CHG 30 /* Chance of changing direction */
+#define DUN_TUN_CON 15 /* Chance of extra tunneling */
+#define DUN_TUN_PEN 25 /* Chance of doors at room entrances */
+#define DUN_TUN_JCT 90 /* Chance of doors at tunnel junctions */
+
+/*
+ * Dungeon streamer generation values
+ */
+#define DUN_STR_DEN 5 /* Density of streamers */
+#define DUN_STR_RNG 2 /* Width of streamers */
+#define DUN_STR_MAG 3 /* Number of magma streamers */
+#define DUN_STR_MC 90 /* 1/chance of treasure per magma */
+#define DUN_STR_QUA 2 /* Number of quartz streamers */
+#define DUN_STR_QC 40 /* 1/chance of treasure per quartz */
+#define DUN_STR_SAN 1 /* Number of sand streamers */
+#define DUN_STR_SC 10 /* 1/chance of treasure per sandwall */
+#define DUN_STR_WLW 1 /* Width of lava & water streamers -KMW- */
+#define DUN_STR_DWLW 8 /* Density of water & lava streams -KMW- */
+
+
+/*
+ * Dungeon treausre allocation values
+ */
+#define DUN_AMT_ROOM 9 /* Amount of objects for rooms */
+#define DUN_AMT_ITEM 3 /* Amount of objects for rooms/corridors */
+#define DUN_AMT_GOLD 3 /* Amount of treasure for rooms/corridors */
+#define DUN_AMT_ALTAR 1 /* Amount of altars */
+#define DUN_AMT_BETWEEN 2 /* Amount of between gates */
+#define DUN_AMT_FOUNTAIN 1 /* Amount of fountains */
+
+/*
+ * Hack -- Dungeon allocation "places"
+ */
+#define ALLOC_SET_CORR 1 /* Hallway */
+#define ALLOC_SET_ROOM 2 /* Room */
+#define ALLOC_SET_BOTH 3 /* Anywhere */
+
+/*
+ * Hack -- Dungeon allocation "types"
+ */
+#define ALLOC_TYP_RUBBLE 1 /* Rubble */
+#define ALLOC_TYP_TRAP 3 /* Trap */
+#define ALLOC_TYP_GOLD 4 /* Gold */
+#define ALLOC_TYP_OBJECT 5 /* Object */
+#define ALLOC_TYP_ALTAR 6 /* Altar */
+#define ALLOC_TYP_BETWEEN 7 /* Between */
+#define ALLOC_TYP_FOUNTAIN 8 /* Fountain */
+
+
+/*
+ * The "size" of a "generation block" in grids
+ */
+#define BLOCK_HGT 11
+#define BLOCK_WID 11
+
+/*
+ * Maximum numbers of rooms along each axis (currently 6x6)
+ */
+#define MAX_ROOMS_ROW (MAX_HGT / BLOCK_HGT)
+#define MAX_ROOMS_COL (MAX_WID / BLOCK_WID)
+
+
+/*
+ * Bounds on some arrays used in the "dun_data" structure.
+ * These bounds are checked, though usually this is a formality.
+ */
+#define CENT_MAX 100
+#define DOOR_MAX 200
+#define WALL_MAX 500
+#define TUNN_MAX 900
+
+
+/*
+ * Maximal number of room types
+ */
+#define ROOM_MAX 12
+
+
+
+/*
+ * Simple structure to hold a map location
+ */
+
+
+typedef struct coord coord;
+
+struct coord
+{
+ byte y;
+ byte x;
+};
+
+
+/*
+ * Room type information
+ */
+
+typedef struct room_data room_data;
+
+struct room_data
+{
+ /* Required size in blocks */
+ s16b dy1, dy2, dx1, dx2;
+
+ /* Hack -- minimum level */
+ s16b level;
+};
+
+
+/*
+ * Structure to hold all "dungeon generation" data
+ */
+
+typedef struct dun_data dun_data;
+
+struct dun_data
+{
+ /* Array of centers of rooms */
+ int cent_n;
+ coord cent[CENT_MAX];
+
+ /* Array of possible door locations */
+ int door_n;
+ coord door[DOOR_MAX];
+
+ /* Array of wall piercing locations */
+ int wall_n;
+ coord wall[WALL_MAX];
+
+ /* Array of tunnel grids */
+ int tunn_n;
+ coord tunn[TUNN_MAX];
+
+ /* Number of blocks along each axis */
+ int row_rooms;
+ int col_rooms;
+
+ /* Array of which blocks are used */
+ bool_ room_map[MAX_ROOMS_ROW][MAX_ROOMS_COL];
+
+ /* Hack -- there is a pit/nest on this level */
+ bool_ crowded;
+};
+
+/*
+ * Level generator type
+ */
+
+typedef struct level_generator_type level_generator_type;
+struct level_generator_type
+{
+ cptr name;
+ bool_ (*generator)(cptr);
+
+ bool_ default_stairs;
+ bool_ default_monsters;
+ bool_ default_objects;
+ bool_ default_miscs;
+
+ struct level_generator_type *next;
+};
+
+static level_generator_type *level_generators = NULL;
+
+/*
+ * Add a new generator
+ */
+void add_level_generator(cptr name, bool_ (*generator)(), bool_ stairs, bool_ monsters, bool_ objects, bool_ miscs)
+{
+ level_generator_type *g;
+
+ MAKE(g, level_generator_type);
+ g->name = string_make(name);
+ g->generator = generator;
+
+ g->default_stairs = stairs;
+ g->default_monsters = monsters;
+ g->default_objects = objects;
+ g->default_miscs = miscs;
+
+ g->next = level_generators;
+ level_generators = g;
+}
+
+
+/*
+ * Dungeon generation data -- see "cave_gen()"
+ */
+static dun_data *dun;
+
+/*
+ * ???
+ */
+static int template_race;
+
+
+
+/*
+ * Array of room types depths
+ */
+static s16b roomdep[] =
+{
+ 0, /* 0 = Nothing */
+ 1, /* 1 = Simple (33x11) */
+ 1, /* 2 = Overlapping (33x11) */
+ 3, /* 3 = Crossed (33x11) */
+ 3, /* 4 = Large (33x11) */
+ 5, /* 5 = Monster nest (33x11) */
+ 5, /* 6 = Monster pit (33x11) */
+ 5, /* 7 = Lesser vault (33x22) */
+ 10, /* 8 = Greater vault (66x44) */
+ 1, /* 9 = Circular rooms (22x22) */
+ 3, /* 10 = Fractal cave (42x24) */
+ 10, /* 11 = Random vault (44x22) */
+ 10, /* 12 = Crypts (22x22) */
+};
+
+
+/*
+ * Always picks a correct direction
+ */
+static void correct_dir(int *rdir, int *cdir, int y1, int x1, int y2, int x2)
+{
+ /* Extract vertical and horizontal directions */
+ *rdir = (y1 == y2) ? 0 : (y1 < y2) ? 1 : -1;
+ *cdir = (x1 == x2) ? 0 : (x1 < x2) ? 1 : -1;
+
+ /* Never move diagonally */
+ if (*rdir && *cdir)
+ {
+ if (rand_int(100) < 50)
+ {
+ *rdir = 0;
+ }
+ else
+ {
+ *cdir = 0;
+ }
+ }
+}
+
+
+/*
+ * Pick a random direction
+ */
+static void rand_dir(int *rdir, int *cdir)
+{
+ /* Pick a random direction */
+ int i = rand_int(4);
+
+ /* Extract the dy/dx components */
+ *rdir = ddy_ddd[i];
+ *cdir = ddx_ddd[i];
+}
+
+
+/*
+ * Convert existing terrain type to "up stairs"
+ */
+static void place_up_stairs(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Create up stairs */
+ if ((rand_int(3) != 0) || (dungeon_flags2 & DF2_NO_SHAFT))
+ {
+ cave_set_feat(y, x, FEAT_LESS);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_SHAFT_UP);
+ }
+
+ c_ptr->special = 0;
+}
+
+
+/*
+ * Convert existing terrain type to "down stairs" with dungeon changing.
+ */
+static void place_magical_stairs(int y, int x, byte next)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Create up stairs */
+ cave_set_feat(y, x, FEAT_MORE);
+ c_ptr->special = next;
+}
+
+
+/*
+ * Convert existing terrain type to "down stairs"
+ */
+static void place_down_stairs(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /*
+ * Create down stairs
+ * All thoses tests are necesary because a shaft can jump up to 4 levels
+ */
+ if ((dun_level + 4 > d_info[dungeon_type].maxdepth) ||
+ (rand_int(3) != 0) || (dungeon_flags2 & DF2_NO_SHAFT))
+ {
+ cave_set_feat(y, x, FEAT_MORE);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_SHAFT_DOWN);
+ }
+
+ c_ptr->special = 0;
+}
+
+
+/*
+ * Helper function for place_new_way. Determine if y, x is one of
+ * floor features of the current dungeon
+ */
+static bool_ is_safe_floor(int y, int x)
+{
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+ byte feat = cave[y][x].feat;
+
+ /* One of the legal floor types */
+ if (feat == d_ptr->floor1) return (TRUE);
+ if (feat == d_ptr->floor2) return (TRUE);
+ if (feat == d_ptr->floor3) return (TRUE);
+
+ /* Assume non-floor */
+ return (FALSE);
+}
+
+
+/*
+ * Place a way to next / previoous level on flat places
+ */
+void place_new_way(int *y, int *x)
+{
+ int xx, yy;
+ int x0, x1, x2;
+ int y0, y1, y2;
+ cave_type *c_ptr;
+ bool_ ok;
+ int i, way_n;
+ byte way_x[MAX_WID], way_y[MAX_WID];
+
+
+ /* Find valid location XXX XXX XXX */
+ while (TRUE)
+ {
+ /* A way on vertical edge */
+ if (rand_int(cur_hgt + cur_wid) < cur_hgt)
+ {
+ /* Pick a random grid */
+ yy = *y = rand_int(cur_hgt - 2) + 1;
+ xx = *x = 1 + (rand_int(2) * (cur_wid - 3));
+
+ /* Pick a direction */
+ if (xx == 1)
+ {
+ /* Left */
+ x0 = + 1;
+ y0 = 0;
+
+ /* Sides */
+ x1 = 0;
+ y1 = -1;
+ x2 = 0;
+ y2 = + 1;
+ }
+ else
+ {
+ /* Right */
+ x0 = -1;
+ y0 = 0;
+
+ /* Sides */
+ x1 = 0;
+ y1 = -1;
+ x2 = 0;
+ y2 = + 1;
+ }
+ }
+
+ /* A way on horizontal edge */
+ else
+ {
+ /* Pick a random grid */
+ xx = *x = rand_int(cur_wid - 2) + 1;
+ yy = *y = 1 + (rand_int(2) * (cur_hgt - 3));
+
+ /* Pick a direction */
+ if (yy == 1)
+ {
+ /* Down */
+ x0 = 0;
+ y0 = + 1;
+
+ /* Sides */
+ x1 = -1;
+ y1 = 0;
+ x2 = + 1;
+ y2 = 0;
+ }
+ else
+ {
+ /* Up */
+ x0 = 0;
+ y0 = -1;
+
+ /* Sides */
+ x1 = -1;
+ y1 = 0;
+ x2 = + 1;
+ y2 = 0;
+ }
+ }
+
+
+ /* Look at the starting location */
+ c_ptr = &cave[yy][xx];
+
+ /* Reject locations inside vaults */
+ if (c_ptr->info & (CAVE_ICKY)) continue;
+
+ /* Reject permanent features */
+ if ((f_info[c_ptr->feat].flags1 & (FF1_PERMANENT)) &&
+ (f_info[c_ptr->feat].flags1 & (FF1_FLOOR))) continue;
+
+ /* Reject room walls */
+ if ((c_ptr->info & (CAVE_ROOM)) &&
+ (c_ptr->feat == feat_wall_outer)) continue;
+
+ /* Look at a neighbouring edge */
+ c_ptr = &cave[yy + y1][xx + x1];
+
+ /* Reject two adjacent ways */
+ if ((c_ptr->feat == FEAT_WAY_MORE) ||
+ (c_ptr->feat == FEAT_WAY_LESS)) continue;
+
+ /* Look at the other neighbouring edge */
+ c_ptr = &cave[yy + y2][xx + x2];
+
+ /* Reject two adjacent ways */
+ if ((c_ptr->feat == FEAT_WAY_MORE) ||
+ (c_ptr->feat == FEAT_WAY_LESS)) continue;
+
+ /* Look ahead */
+ c_ptr = &cave[yy + y0][xx + x0];
+
+ /* Reject two adjacent ways -- relatively rare, but this can happen */
+ if ((c_ptr->feat == FEAT_WAY_MORE) ||
+ (c_ptr->feat == FEAT_WAY_LESS)) continue;
+
+
+ /* Reset counter */
+ way_n = 0;
+
+ /* Assume bad location */
+ ok = FALSE;
+
+ /* Check if it connects to current dungeon */
+ while (in_bounds(yy, xx))
+ {
+#if 1
+
+ /* Check grids ahead */
+ if (is_safe_floor(yy + y0, xx + x0)) ok = TRUE;
+
+ /* Check side grids */
+ if (is_safe_floor(yy + y1, xx + x1)) ok = TRUE;
+ if (is_safe_floor(yy + y2, xx + x2)) ok = TRUE;
+
+#else
+
+ /*
+ * This can create unconnected sections if it bumps into a
+ * non-penetrating streamer
+ */
+ /* Check grids ahead */
+ if (cave_floor_bold(yy + y0, xx + x0)) ok = TRUE;
+
+ /* Check side grids */
+ if (cave_floor_bold(yy + y1, xx + x1)) ok = TRUE;
+ if (cave_floor_bold(yy + y2, xx + x2)) ok = TRUE;
+
+#endif
+
+ /* Connected */
+ if (ok) break;
+
+ /* Access grid (ahead) */
+ c_ptr = &cave[yy + y0][xx + x0];
+
+ /* Avoid opening vaults */
+ if (c_ptr->feat == FEAT_PERM_OUTER)
+ {
+ /* Comment this out if you find any problems... */
+ ok = TRUE;
+
+ break;
+ }
+
+ /* Paranoia */
+ if (c_ptr->feat == FEAT_PERM_SOLID) break;
+
+ /*
+ * Hack -- Avoid digging room corner
+ *
+ * CAVEAT: Can't handle situations like this:
+ *
+ * .....########
+ * .....########
+ * ######.....>#
+ * #############
+ * .....#
+ * .....#
+ */
+ if (c_ptr->info & (CAVE_ROOM))
+ {
+ cave_type *c1_ptr = &cave[yy + y0 + y1][xx + x0 + x1];
+ cave_type *c2_ptr = &cave[yy + y0 + y2][xx + x0 + x2];
+
+ /* Bend the way */
+ if ((c1_ptr->info & (CAVE_ROOM)) &&
+ !(c2_ptr->info & (CAVE_ROOM)))
+ {
+ way_x[way_n] = xx + x1;
+ way_y[way_n] = yy + y1;
+ way_n++;
+ way_x[way_n] = xx + x1 + x0;
+ way_y[way_n] = yy + y1 + y0;
+ way_n++;
+ }
+
+ /* Bend the way -- the other direction */
+ else if ((c2_ptr->info & (CAVE_ROOM)) &&
+ !(c1_ptr->info & (CAVE_ROOM)))
+ {
+ way_x[way_n] = xx + x2;
+ way_y[way_n] = yy + y2;
+ way_n++;
+ way_x[way_n] = xx + x2 + x0;
+ way_y[way_n] = yy + y2 + y0;
+ way_n++;
+ }
+
+ else
+ {
+ way_x[way_n] = xx + x0;
+ way_y[way_n] = yy + y0;
+ way_n++;
+ }
+
+ ok = TRUE;
+ break;
+ }
+
+ /* Remember the location */
+ way_x[way_n] = xx + x0;
+ way_y[way_n] = yy + y0;
+ way_n++;
+
+ /* Advance */
+ xx += x0;
+ yy += y0;
+ }
+
+ /* Accept connected corridor */
+ if (ok) break;
+
+ /* Try again, until valid location is found */
+ }
+
+
+ /* Actually dig a corridor connecting the way to dungeon */
+ for (i = 0; i < way_n; i++)
+ {
+ /* Dig */
+ place_floor(way_y[i], way_x[i]);
+ }
+}
+
+
+/*
+ * Returns random co-ordinates for player/monster/object
+ */
+bool_ new_player_spot(int branch)
+{
+ int y, x;
+ int max_attempts = 5000;
+
+ /* Place the player */
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ place_new_way(&y, &x);
+ }
+ else
+ {
+ while (max_attempts--)
+ {
+ /* Pick a legal spot */
+ y = rand_range(1, cur_hgt - 2);
+ x = rand_range(1, cur_wid - 2);
+
+ /* Must be a "naked" floor grid */
+ if (!cave_naked_bold(y, x)) continue;
+
+ /* Refuse to start on anti-teleport grids */
+ if (cave[y][x].info & (CAVE_ICKY)) continue;
+
+ /* Done */
+ break;
+
+ }
+ }
+
+ /* Should be -1, actually if we failed... */
+ if (max_attempts < 1) return (FALSE);
+
+
+ /* Save the new player grid */
+ p_ptr->py = y;
+ p_ptr->px = x;
+
+ /* XXX XXX XXX */
+ if (dungeon_stair && !(dungeon_flags2 & DF2_NO_STAIR) && dun_level &&
+ (!is_quest(dun_level) || (old_dun_level < dun_level)) && !branch)
+ {
+ if (old_dun_level < dun_level)
+ {
+ place_up_stairs(p_ptr->py , p_ptr->px);
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_WAY_LESS);
+ }
+ }
+ else
+ {
+ place_down_stairs(p_ptr->py , p_ptr->px);
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_WAY_MORE);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+
+/*
+ * Count the number of walls adjacent to the given grid.
+ *
+ * Note -- Assumes "in_bounds(y, x)"
+ *
+ * We count only granite walls and permanent walls.
+ */
+static int next_to_walls(int y, int x)
+{
+ int k = 0;
+
+ if (f_info[cave[y + 1][x].feat].flags1 & FF1_WALL) k++;
+ if (f_info[cave[y - 1][x].feat].flags1 & FF1_WALL) k++;
+ if (f_info[cave[y][x + 1].feat].flags1 & FF1_WALL) k++;
+ if (f_info[cave[y][x - 1].feat].flags1 & FF1_WALL) k++;
+
+ return (k);
+}
+
+
+
+/*
+ * Convert existing terrain type to rubble
+ */
+static void place_rubble(int y, int x)
+{
+ /* Create rubble */
+ cave_set_feat(y, x, FEAT_RUBBLE);
+}
+
+
+/*
+ * Place an altar at the given location
+ */
+static void place_altar(int y, int x)
+{
+ if (magik(10))
+ cave_set_feat(y, x, 164);
+}
+
+
+/*
+ * Place a fountain at the given location
+ */
+static void place_fountain(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+ int svals[SV_POTION_LAST + SV_POTION2_LAST + 1], maxsval = 0, k;
+
+ /* List of usable svals */
+ for (k = 1; k < max_k_idx; k++)
+ {
+ object_kind *k_ptr = &k_info[k];
+
+ if (((k_ptr->tval == TV_POTION) || (k_ptr->tval == TV_POTION2)) &&
+ (k_ptr->level <= dun_level) && (k_ptr->flags4 & TR4_FOUNTAIN))
+ {
+ if (k_ptr->tval == TV_POTION2) svals[maxsval] = k_ptr->sval + SV_POTION_LAST;
+ else svals[maxsval] = k_ptr->sval;
+ maxsval++;
+ }
+ }
+
+ if (maxsval == 0) return;
+
+ /* Place the fountain */
+ if (randint(100) < 30)
+ {
+ cave_set_feat(y, x, FEAT_EMPTY_FOUNTAIN);
+ c_ptr->special2 = 0;
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_FOUNTAIN);
+ c_ptr->special2 = damroll(3, 4);
+ }
+
+ c_ptr->special = svals[rand_int(maxsval)];
+}
+
+
+/*
+ * Place a between gate at the given location
+ */
+static void place_between(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x], *c1_ptr;
+ int gx, gy;
+
+ while (TRUE)
+ {
+ /* Location */
+ gy = rand_int(cur_hgt);
+ gx = rand_int(cur_wid);
+
+ /* Require "naked" floor grid */
+ if (cave_naked_bold(gy, gx)) break;
+ }
+
+ /* Access the target grid */
+ c1_ptr = &cave[gy][gx];
+
+ /* Place a pair of between gates */
+ cave_set_feat(y, x, FEAT_BETWEEN);
+ c_ptr->special = gx + (gy << 8);
+ cave_set_feat(gy, gx, FEAT_BETWEEN);
+ c1_ptr->special = x + (y << 8);
+}
+
+
+/*
+ * Place an up/down staircase at given location
+ */
+static void place_random_stairs(int y, int x)
+{
+ /* Paranoia */
+ if (!cave_clean_bold(y, x)) return;
+
+ /* Choose a staircase */
+ if (!dun_level)
+ {
+ place_down_stairs(y, x);
+ }
+ else if (is_quest(dun_level) && (dun_level > 1))
+ {
+ place_up_stairs(y, x);
+ }
+ else if (dun_level >= d_info[dungeon_type].maxdepth)
+ {
+ if (d_info[dungeon_type].next)
+ {
+ place_magical_stairs(y, x, d_info[dungeon_type].next);
+ }
+ else
+ {
+ place_up_stairs(y, x);
+ }
+ }
+ else if (rand_int(100) < 50)
+ {
+ place_down_stairs(y, x);
+ }
+ else
+ {
+ place_up_stairs(y, x);
+ }
+}
+
+
+/*
+ * Place a locked door at the given location
+ */
+static void place_locked_door(int y, int x)
+{
+ /* Create locked door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + randint(7));
+}
+
+
+/*
+ * Place a secret door at the given location
+ */
+static void place_secret_door(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Vaults */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ c_ptr->mimic = FEAT_WALL_INNER;
+ }
+
+ /* Ordinary room -- use current outer or inner wall */
+ else if (c_ptr->info & CAVE_ROOM)
+ {
+ /* Determine if it's inner or outer XXX XXX XXX */
+ if ((cave[y - 1][x].info & CAVE_ROOM) &&
+ (cave[y + 1][x].info & CAVE_ROOM) &&
+ (cave[y][x - 1].info & CAVE_ROOM) &&
+ (cave[y][x + 1].info & CAVE_ROOM))
+ {
+ c_ptr->mimic = feat_wall_inner;
+ }
+ else
+ {
+ c_ptr->mimic = feat_wall_outer;
+ }
+ }
+ else
+ {
+ c_ptr->mimic = fill_type[rand_int(100)];
+ }
+
+ /* Create secret door */
+ cave_set_feat(y, x, FEAT_SECRET);
+}
+
+
+/*
+ * Place a random type of door at the given location
+ */
+static void place_random_door(int y, int x)
+{
+ int tmp;
+
+ /* Choose an object */
+ tmp = rand_int(1000);
+
+ /* Open doors (300/1000) */
+ if (tmp < 300)
+ {
+ /* Create open door */
+ cave_set_feat(y, x, FEAT_OPEN);
+ }
+
+ /* Broken doors (100/1000) */
+ else if (tmp < 400)
+ {
+ /* Create broken door */
+ cave_set_feat(y, x, FEAT_BROKEN);
+ }
+
+ /* Secret doors (200/1000) */
+ else if (tmp < 600)
+ {
+ /* Create secret door */
+ place_secret_door(y, x);
+ }
+
+ /* Closed doors (300/1000) */
+ else if (tmp < 900)
+ {
+ /* Create closed door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
+ }
+
+ /* Locked doors (99/1000) */
+ else if (tmp < 999)
+ {
+ /* Create locked door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + randint(7));
+ }
+
+ /* Stuck doors (1/1000) */
+ else
+ {
+ /* Create jammed door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x08 + (byte)rand_int(8));
+ }
+}
+
+
+
+/*
+ * Places some staircases near walls
+ */
+static void alloc_stairs(int feat, int num, int walls, int branch)
+{
+ int y, x, i, j, cnt;
+
+ /* Place "num" stairs */
+ for (cnt = 0, i = 0; i < num || (cnt < 1 && num > 1); i++)
+ {
+ /* Try several times, then decrease "walls" */
+ for (j = 0; j <= SAFE_MAX_ATTEMPTS; j++)
+ {
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ place_new_way(&y, &x);
+ }
+ else
+ {
+ /* Pick a random grid */
+ y = rand_int(cur_hgt);
+ x = rand_int(cur_wid);
+
+ /* Require "naked" floor grid */
+ if (!cave_naked_bold(y, x)) continue;
+
+ /* Require a certain number of adjacent walls */
+ if (next_to_walls(y, x) < walls) continue;
+ }
+
+ /* Town -- must go down */
+ if (!dun_level)
+ {
+ /* Clear previous contents, add down stairs */
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ cave_set_feat(y, x, FEAT_WAY_MORE);
+ }
+ else if ((rand_int(3) == 0) && (!(dungeon_flags2 & DF2_NO_SHAFT)))
+ {
+ cave_set_feat(y, x, FEAT_SHAFT_DOWN);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_MORE);
+ }
+ }
+
+ /* Quest -- must go up */
+ else if ((is_quest(dun_level) && (dun_level >= 1)) ||
+ ((dun_level >= d_info[dungeon_type].maxdepth) &&
+ (!(dungeon_flags1 & DF1_FORCE_DOWN))))
+ {
+ /* Clear previous contents, add up stairs */
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ cave_set_feat(y, x, FEAT_WAY_LESS);
+ }
+ else if ((rand_int(3) == 0) && (!(dungeon_flags2 & DF2_NO_SHAFT)))
+ {
+ cave_set_feat(y, x, FEAT_SHAFT_UP);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_LESS);
+ }
+ }
+
+ /* Requested type */
+ else
+ {
+ /* Clear previous contents, add stairs */
+ cave_set_feat(y, x, feat);
+ }
+
+ cave[y][x].special = branch;
+
+ /* Count the number of stairs we've actually managed to place. */
+ cnt++;
+
+ /* All done */
+ break;
+ }
+
+ /* Require fewer walls */
+ if (walls) walls--;
+ }
+}
+
+
+
+
+/*
+ * Allocates some objects (using "place" and "type")
+ */
+static void alloc_object(int set, int typ, int num)
+{
+ int y = 1, x = 1, k;
+ int dummy = 0;
+
+ /* Place some objects */
+ for (k = 0; k < num; k++)
+ {
+ /* Pick a "legal" spot */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ bool_ room;
+
+ dummy++;
+
+ /* Location */
+ y = rand_int(cur_hgt);
+ x = rand_int(cur_wid);
+
+ /* Require "naked" floor grid */
+ if (!cave_naked_bold(y, x)) continue;
+
+ /* Check for "room" */
+ room = (cave[y][x].info & (CAVE_ROOM)) ? TRUE : FALSE;
+
+ /* Require corridor? */
+ if ((set == ALLOC_SET_CORR) && room) continue;
+
+ /* Require room? */
+ if ((set == ALLOC_SET_ROOM) && !room) continue;
+
+ /* Accept it */
+ break;
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_format("Warning! Could not place object, type : %d!", typ);
+ }
+
+ return;
+ }
+
+
+ /* Place something */
+ switch (typ)
+ {
+ case ALLOC_TYP_RUBBLE:
+ {
+ place_rubble(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_TRAP:
+ {
+ place_trap(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_GOLD:
+ {
+ place_gold(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_OBJECT:
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ break;
+ }
+
+ case ALLOC_TYP_ALTAR:
+ {
+ place_altar(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_BETWEEN:
+ {
+ place_between(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_FOUNTAIN:
+ {
+ place_fountain(y, x);
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+ * The following functions create a rectangle (e.g. outer wall of rooms)
+ */
+void build_rectangle(int y1, int x1, int y2, int x2, int feat, int info)
+{
+ int y, x;
+
+ /* Top and bottom boundaries */
+ for (x = x1; x <= x2; x++)
+ {
+ cave_set_feat(y1, x, feat);
+ cave[y1][x].info |= (info);
+
+ cave_set_feat(y2, x, feat);
+ cave[y2][x].info |= (info);
+ }
+
+ /* Top and bottom boundaries */
+ for (y = y1; y <= y2; y++)
+ {
+ cave_set_feat(y, x1, feat);
+ cave[y][x1].info |= (info);
+
+ cave_set_feat(y, x2, feat);
+ cave[y][x2].info |= (info);
+ }
+}
+
+
+/*
+ * Place water through the dungeon using recursive fractal algorithm
+ *
+ * Why do those good at math and/or algorithms tend *not* to
+ * place any spaces around binary operators? I've been always
+ * wondering. This seems almost a unversal phenomenon...
+ * Tried to make those conform to the rule, but there may still
+ * some left untouched...
+ */
+static void recursive_river(int x1, int y1, int x2, int y2,
+ int feat1, int feat2, int width)
+{
+ int dx, dy, length, l, x, y;
+ int changex, changey;
+ int ty, tx;
+
+
+ length = distance(x1, y1, x2, y2);
+
+ if (length > 4)
+ {
+ /*
+ * Divide path in half and call routine twice.
+ * There is a small chance of splitting the river
+ */
+ dx = (x2 - x1) / 2;
+ dy = (y2 - y1) / 2;
+
+ if (dy != 0)
+ {
+ /* perturbation perpendicular to path */
+ changex = randint(abs(dy)) * 2 - abs(dy);
+ }
+ else
+ {
+ changex = 0;
+ }
+
+ if (dx != 0)
+ {
+ /* perturbation perpendicular to path */
+ changey = randint(abs(dx)) * 2 - abs(dx);
+ }
+ else
+ {
+ changey = 0;
+ }
+
+
+
+ /* construct river out of two smaller ones */
+ recursive_river(x1, y1, x1 + dx + changex, y1 + dy + changey,
+ feat1, feat2, width);
+ recursive_river(x1 + dx + changex, y1 + dy + changey, x2, y2,
+ feat1, feat2, width);
+
+ /* Split the river some of the time -junctions look cool */
+ if ((width > 0) && (rand_int(DUN_WAT_CHG) == 0))
+ {
+ recursive_river(x1 + dx + changex, y1 + dy + changey,
+ x1 + 8 * (dx + changex), y1 + 8 * (dy + changey),
+ feat1, feat2, width - 1);
+ }
+ }
+
+ /* Actually build the river */
+ else
+ {
+ for (l = 0; l < length; l++)
+ {
+ x = x1 + l * (x2 - x1) / length;
+ y = y1 + l * (y2 - y1) / length;
+
+ for (ty = y - width - 1; ty <= y + width + 1; ty++)
+ {
+ for (tx = x - width - 1; tx <= x + width + 1; tx++)
+ {
+ if (!in_bounds(ty, tx)) continue;
+
+ if (cave[ty][tx].feat == feat1) continue;
+ if (cave[ty][tx].feat == feat2) continue;
+
+ if (distance(ty, tx, y, x) > rand_spread(width, 1)) continue;
+
+ /* Do not convert permanent features */
+ if (cave_perma_bold(ty, tx)) continue;
+
+ /*
+ * Clear previous contents, add feature
+ * The border mainly gets feat2, while the center
+ * gets feat1
+ */
+ if (distance(ty, tx, y, x) > width)
+ {
+ cave_set_feat(ty, tx, feat2);
+ }
+ else
+ {
+ cave_set_feat(ty, tx, feat1);
+ }
+
+ /* Lava terrain glows */
+ if ((feat1 == FEAT_DEEP_LAVA) ||
+ (feat1 == FEAT_SHAL_LAVA))
+ {
+ cave[ty][tx].info |= CAVE_GLOW;
+ }
+
+ /* Hack -- don't teleport here */
+ cave[ty][tx].info |= CAVE_ICKY;
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Places water through dungeon.
+ */
+static void add_river(int feat1, int feat2)
+{
+ int y2, x2;
+ int y1 = 0, x1 = 0, wid;
+
+
+ /* Hack -- Choose starting point */
+ y2 = randint(cur_hgt / 2 - 2) + cur_hgt / 2;
+ x2 = randint(cur_wid / 2 - 2) + cur_wid / 2;
+
+ /* Hack -- Choose ending point somewhere on boundary */
+ switch (randint(4))
+ {
+ case 1:
+ {
+ /* top boundary */
+ x1 = randint(cur_wid - 2) + 1;
+ y1 = 1;
+ break;
+ }
+ case 2:
+ {
+ /* left boundary */
+ x1 = 1;
+ y1 = randint(cur_hgt - 2) + 1;
+ break;
+ }
+ case 3:
+ {
+ /* right boundary */
+ x1 = cur_wid - 1;
+ y1 = randint(cur_hgt - 2) + 1;
+ break;
+ }
+ case 4:
+ {
+ /* bottom boundary */
+ x1 = randint(cur_wid - 2) + 1;
+ y1 = cur_hgt - 1;
+ break;
+ }
+ }
+ wid = randint(DUN_WAT_RNG);
+ recursive_river(x1, y1, x2, y2, feat1, feat2, wid);
+}
+
+
+/*
+ * Places "streamers" of rock through dungeon
+ *
+ * Note that their are actually six different terrain features used
+ * to represent streamers. Three each of magma and quartz, one for
+ * basic vein, one with hidden gold, and one with known gold. The
+ * hidden gold types are currently unused.
+ */
+static void build_streamer(int feat, int chance)
+{
+ int i, tx, ty;
+ int y, x, dir;
+ int dummy = 0;
+ cave_type *c_ptr;
+
+
+ /* Hack -- Choose starting point */
+ y = rand_spread(cur_hgt / 2, 10);
+ x = rand_spread(cur_wid / 2, 15);
+
+ /* Choose a random compass direction */
+ dir = ddd[rand_int(8)];
+
+ /* Place streamer into dungeon */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ dummy++;
+
+ /* One grid per density */
+ for (i = 0; i < DUN_STR_DEN; i++)
+ {
+ int d = DUN_STR_RNG;
+
+ /* Pick a nearby grid */
+ while (1)
+ {
+ ty = rand_spread(y, d);
+ tx = rand_spread(x, d);
+ if (!in_bounds2(ty, tx)) continue;
+ break;
+ }
+
+ /* Access the grid */
+ c_ptr = &cave[ty][tx];
+
+ /* Only convert "granite" walls */
+ if ((c_ptr->feat != feat_wall_inner) &&
+ (c_ptr->feat != feat_wall_outer) &&
+ (c_ptr->feat != d_info[dungeon_type].fill_type1) &&
+ (c_ptr->feat != d_info[dungeon_type].fill_type2) &&
+ (c_ptr->feat != d_info[dungeon_type].fill_type3)) continue;
+
+ /* Clear mimic feature to avoid nasty consequences */
+ c_ptr->mimic = 0;
+
+ /* Clear previous contents, add proper vein type */
+ cave_set_feat(ty, tx, feat);
+
+ /* Hack -- Add some (known) treasure */
+ if (rand_int(chance) == 0)
+ {
+ cave_set_feat(ty, tx, c_ptr->feat + 0x04);
+ }
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place streamer!");
+ }
+ return;
+ }
+
+
+ /* Advance the streamer */
+ y += ddy[dir];
+ x += ddx[dir];
+
+ /* Quit before leaving the dungeon */
+ if (!in_bounds(y, x)) break;
+ }
+}
+
+
+
+/*
+ * Place streams of water, lava, & trees -KMW-
+ * This routine varies the placement based on dungeon level
+ * otherwise is similar to build_streamer
+ */
+static void build_streamer2(int feat, int killwall)
+{
+ int i, j, mid, tx, ty;
+ int y, x, dir;
+ int poolchance;
+ int poolsize;
+ cave_type *c_ptr;
+
+ poolchance = randint(10);
+
+ /* Hack -- Choose starting point */
+ y = rand_spread(cur_hgt / 2, 10);
+ x = rand_spread(cur_wid / 2, 15);
+
+ /* Choose a random compass direction */
+ dir = ddd[rand_int(8)];
+
+ /* Place streamer into dungeon */
+ if (poolchance > 2)
+ {
+ while (TRUE)
+ {
+ /* One grid per density */
+ for (i = 0; i < (DUN_STR_DWLW + 1); i++)
+ {
+ int d = DUN_STR_WLW;
+
+ /* Pick a nearby grid */
+ while (1)
+ {
+ ty = rand_spread(y, d);
+ tx = rand_spread(x, d);
+ if (in_bounds(ty, tx)) break;
+ }
+
+ /* Access grid */
+ c_ptr = &cave[ty][tx];
+
+ /* Never convert vaults */
+ if (c_ptr->info & (CAVE_ICKY)) continue;
+
+ /* Reject permanent features */
+ if ((f_info[c_ptr->feat].flags1 & (FF1_PERMANENT)) &&
+ (f_info[c_ptr->feat].flags1 & (FF1_FLOOR))) continue;
+
+ /* Avoid converting walls when told so */
+ if (killwall == 0)
+ {
+ if (f_info[c_ptr->feat].flags1 & FF1_WALL) continue;
+ }
+
+ /* Clear mimic feature to avoid nasty consequences */
+ c_ptr->mimic = 0;
+
+ /* Clear previous contents, add proper vein type */
+ cave_set_feat(ty, tx, feat);
+ }
+
+ /* Advance the streamer */
+ y += ddy[dir];
+ x += ddx[dir];
+
+ /* Change direction */
+ if (rand_int(20) == 0) dir = ddd[rand_int(8)];
+
+ /* Stop at dungeon edge */
+ if (!in_bounds(y, x)) break;
+ }
+ }
+
+ /* Create pool */
+ else if ((feat == FEAT_DEEP_WATER) || (feat == FEAT_DEEP_LAVA))
+ {
+ poolsize = 5 + randint(10);
+ mid = poolsize / 2;
+
+ /* One grid per density */
+ for (i = 0; i < poolsize; i++)
+ {
+ for (j = 0; j < poolsize; j++)
+ {
+ tx = x + j;
+ ty = y + i;
+
+ if (!in_bounds(ty, tx)) continue;
+
+ if (i < mid)
+ {
+ if (j < mid)
+ {
+ if ((i + j + 1) < mid)
+ continue;
+ }
+ else if (j > (mid + i))
+ continue;
+ }
+ else if (j < mid)
+ {
+ if (i > (mid + j))
+ continue;
+ }
+ else if ((i + j) > ((mid * 3)-1))
+ continue;
+
+ /* Only convert non-permanent features */
+ if (f_info[cave[ty][tx].feat].flags1 & FF1_PERMANENT) continue;
+
+ /* Clear mimic feature to avoid nasty consequences */
+ cave[ty][tx].mimic = 0;
+
+ /* Clear previous contents, add proper vein type */
+ cave_set_feat(ty, tx, feat);
+ }
+ }
+ }
+}
+
+
+
+/*
+ * Build a destroyed level
+ */
+static void destroy_level(void)
+{
+ int y1, x1, y, x, k, t, n;
+
+ cave_type *c_ptr;
+
+ /* Note destroyed levels */
+ if ((cheat_room) || (p_ptr->precognition)) msg_print("Destroyed Level");
+
+ /* Drop a few epi-centers (usually about two) */
+ for (n = 0; n < randint(5); n++)
+ {
+ /* Pick an epi-center */
+ x1 = rand_range(5, cur_wid - 1 - 5);
+ y1 = rand_range(5, cur_hgt - 1 - 5);
+
+ /* Big area of affect */
+ for (y = (y1 - 15); y <= (y1 + 15); y++)
+ {
+ for (x = (x1 - 15); x <= (x1 + 15); x++)
+ {
+ /* Skip illegal grids */
+ if (!in_bounds(y, x)) continue;
+
+ /* Extract the distance */
+ k = distance(y1, x1, y, x);
+
+ /* Stay in the circle of death */
+ if (k >= 16) continue;
+
+ /* Delete the monster (if any) */
+ delete_monster(y, x);
+
+ /* Destroy valid grids */
+ if (cave_valid_bold(y, x))
+ {
+ /* Delete objects */
+ delete_object(y, x);
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Wall (or floor) type */
+ t = rand_int(200);
+
+ /* Granite */
+ if (t < 20)
+ {
+ /* Create granite wall */
+ cave_set_feat(y, x, FEAT_WALL_EXTRA);
+ }
+
+ /* Quartz */
+ else if (t < 60)
+ {
+ /* Create quartz vein */
+ cave_set_feat(y, x, FEAT_QUARTZ);
+ }
+
+ /* Magma */
+ else if (t < 90)
+ {
+ /* Create magma vein */
+ cave_set_feat(y, x, FEAT_MAGMA);
+ }
+
+ /* Sand */
+ else if (t < 110)
+ {
+ /* Create sand vein */
+ cave_set_feat(y, x, FEAT_SANDWALL);
+ }
+
+ /* Floor */
+ else
+ {
+ /* Create floor */
+ place_floor(y, x);
+ }
+
+ /* No longer part of a room or vault */
+ c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
+
+ /* No longer illuminated or known */
+ c_ptr->info &= ~(CAVE_MARK | CAVE_GLOW);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Function that sees if a square is a floor (Includes range checking)
+ */
+static bool_ get_is_floor(int x, int y)
+{
+ /* Out of bounds */
+ if (!in_bounds(y, x)) return (FALSE);
+
+ /* Do the real check: */
+ if (f_info[cave[y][x].feat].flags1 & FF1_FLOOR) return (TRUE);
+
+ return (FALSE);
+}
+
+
+/*
+ * Tunnel around a room if it will cut off part of a cave system
+ */
+static void check_room_boundary(int x1, int y1, int x2, int y2)
+{
+ int count, x, y;
+ bool_ old_is_floor, new_is_floor;
+
+ /* Avoid doing this in irrelevant places -- pelpel */
+ if (!(dungeon_flags1 & DF1_CAVERN)) return;
+
+ /* Initialize */
+ count = 0;
+
+ old_is_floor = get_is_floor(x1 - 1, y1);
+
+ /*
+ * Count the number of floor-wall boundaries around the room
+ * Note: diagonal squares are ignored since the player can move diagonally
+ * to bypass these if needed.
+ */
+
+ /* Above the top boundary */
+ for (x = x1; x <= x2; x++)
+ {
+ new_is_floor = get_is_floor(x, y1 - 1);
+
+ /* increment counter if they are different */
+ if (new_is_floor != old_is_floor) count++;
+
+ old_is_floor = new_is_floor;
+ }
+
+ /* Right boundary */
+ for (y = y1; y <= y2; y++)
+ {
+ new_is_floor = get_is_floor(x2 + 1, y);
+
+ /* increment counter if they are different */
+ if (new_is_floor != old_is_floor) count++;
+
+ old_is_floor = new_is_floor;
+ }
+
+ /* Bottom boundary*/
+ for (x = x2; x >= x1; x--)
+ {
+ new_is_floor = get_is_floor(x, y2 + 1);
+
+ /* Increment counter if they are different */
+ if (new_is_floor != old_is_floor) count++;
+
+ old_is_floor = new_is_floor;
+ }
+
+ /* Left boundary */
+ for (y = y2; y >= y1; y--)
+ {
+ new_is_floor = get_is_floor(x1 - 1, y);
+
+ /* Increment counter if they are different */
+ if (new_is_floor != old_is_floor) count++;
+
+ old_is_floor = new_is_floor;
+ }
+
+
+ /* If all the same, or only one connection exit */
+ if ((count == 0) || (count == 2)) return;
+
+
+ /* Tunnel around the room so to prevent problems with caves */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ if (in_bounds(y, x)) place_floor(y, x);
+ }
+ }
+}
+
+
+/*
+ * Create up to "num" objects near the given coordinates
+ * Only really called by some of the "vault" routines.
+ */
+static void vault_objects(int y, int x, int num)
+{
+ int dummy = 0;
+ int i = 0, j = y, k = x;
+
+
+ /* Attempt to place 'num' objects */
+ for (; num > 0; --num)
+ {
+ /* Try up to 11 spots looking for empty space */
+ for (i = 0; i < 11; ++i)
+ {
+ /* Pick a random location */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ j = rand_spread(y, 2);
+ k = rand_spread(x, 3);
+ dummy++;
+ if (in_bounds(j, k)) break;
+ }
+
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place vault object!");
+ }
+ }
+
+
+ /* Require "clean" floor space */
+ if (!cave_clean_bold(j, k)) continue;
+
+ /* Place an item */
+ if (rand_int(100) < 75)
+ {
+ place_object(j, k, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+
+ /* Place gold */
+ else
+ {
+ place_gold(j, k);
+ }
+
+ /* Placement accomplished */
+ break;
+ }
+ }
+}
+
+
+/*
+ * Place a trap with a given displacement of point
+ */
+static void vault_trap_aux(int y, int x, int yd, int xd)
+{
+ int count = 0, y1 = y, x1 = x;
+ int dummy = 0;
+
+ /* Place traps */
+ for (count = 0; count <= 5; count++)
+ {
+ /* Get a location */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ y1 = rand_spread(y, yd);
+ x1 = rand_spread(x, xd);
+ dummy++;
+ if (in_bounds(y1, x1)) break;
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place vault trap!");
+ }
+ }
+
+
+ /* Require "naked" floor grids */
+ if (!cave_naked_bold(y1, x1)) continue;
+
+ /* Place the trap */
+ place_trap(y1, x1);
+
+ /* Done */
+ break;
+ }
+}
+
+
+/*
+ * Place some traps with a given displacement of given location
+ */
+static void vault_traps(int y, int x, int yd, int xd, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ {
+ vault_trap_aux(y, x, yd, xd);
+ }
+}
+
+
+/*
+ * Hack -- Place some sleeping monsters near the given location
+ */
+static void vault_monsters(int y1, int x1, int num)
+{
+ int k, i, y, x;
+
+ /* Try to summon "num" monsters "near" the given location */
+ for (k = 0; k < num; k++)
+ {
+ /* Try nine locations */
+ for (i = 0; i < 9; i++)
+ {
+ int d = 1;
+
+ /* Pick a nearby location */
+ scatter(&y, &x, y1, x1, d);
+
+ /* Require "empty" floor grids */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Place the monster (allow groups) */
+ monster_level = dun_level + 2;
+ (void)place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ }
+ }
+}
+
+/*
+ * Allocate the space needed by a room in the room_map array.
+ *
+ * width, height represent the size of the room (0...x-1) by (0...y-1).
+ * crowded is used to denote a monset nest.
+ * by0, bx0 are the positions in the room_map array given to the build_type'x'
+ * function.
+ * cx, cy are the returned center of the allocated room in coordinates for
+ * cave.feat and cave.info etc.
+ */
+bool_ room_alloc(int width, int height, bool_ crowded, int by0, int bx0, int *cx, int *cy)
+{
+ int temp, eby, ebx, by, bx;
+
+ /* Calculate number of room_map squares to allocate */
+
+ /* Total number along width */
+ temp = ((width - 1) / BLOCK_WID) + 1;
+
+ for (ebx = bx0 + temp; bx0 > 0 && ebx > dun->col_rooms; bx0--, ebx--);
+
+ if (ebx > dun->col_rooms) return (FALSE);
+
+ /* Total number along height */
+ temp = ((height - 1) / BLOCK_HGT) + 1;
+
+ for (eby = by0 + temp; by0 > 0 && eby > dun->row_rooms; by0--, eby--);
+
+ /* Never run off the screen */
+ if (eby > dun->row_rooms) return (FALSE);
+
+ /* Verify open space */
+ for (by = by0; by < eby; by++)
+ {
+ for (bx = bx0; bx < ebx; bx++)
+ {
+ if (dun->room_map[by][bx]) return (FALSE);
+ }
+ }
+
+ /*
+ * It is *extremely* important that the following calculation
+ * be *exactly* correct to prevent memory errors XXX XXX XXX
+ */
+
+ /* Acquire the location of the room */
+ *cy = ((by0 + eby) * BLOCK_HGT) / 2;
+ *cx = ((bx0 + ebx) * BLOCK_WID) / 2;
+
+ /* Save the room location */
+ if (dun->cent_n < CENT_MAX)
+ {
+ dun->cent[dun->cent_n].y = *cy;
+ dun->cent[dun->cent_n].x = *cx;
+ dun->cent_n++;
+ }
+
+ /* Reserve some blocks */
+ for (by = by0; by < eby; by++)
+ {
+ for (bx = bx0; bx < ebx; bx++)
+ {
+ dun->room_map[by][bx] = TRUE;
+ }
+ }
+
+ /* Count "crowded" rooms */
+ if (crowded) dun->crowded = TRUE;
+
+ /*
+ * Hack -- See if room will cut off a cavern.
+ * If so, fix by tunneling outside the room in such a way as
+ * to conect the caves.
+ */
+ check_room_boundary(*cx - width / 2 - 1, *cy - height / 2 - 1,
+ *cx + width / 2 + 1, *cy + height / 2 + 1);
+
+ /* Success */
+ return (TRUE);
+}
+
+/*
+ * Room building routines.
+ *
+ * Room types:
+ * 1 -- normal
+ * 2 -- overlapping
+ * 3 -- cross shaped
+ * 4 -- large room with features
+ * 5 -- monster nests
+ * 6 -- monster pits
+ * 7 -- simple vaults
+ * 8 -- greater vaults
+ * 9 -- circular rooms
+ */
+
+/*
+ * Type 1 -- normal rectangular rooms
+ */
+static void build_type1(int by0, int bx0)
+{
+ u16b info;
+ int y, x = 1, y2, x2, yval, xval;
+ int y1, x1, xsize, ysize;
+
+ /* Pick a room size */
+ y1 = rand_range(1, 4);
+ x1 = rand_range(1, 10);
+ y2 = rand_range(1, 3);
+ x2 = rand_range(1, 9);
+
+ xsize = x1 + x2;
+ ysize = y1 + y2;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &xval, &yval)) return;
+
+ /* Get corner values */
+ y1 = yval - ysize / 2;
+ x1 = xval - xsize / 2;
+ y2 = y1 + ysize - 1;
+ x2 = x1 + xsize - 1;
+
+ info = (dun_level <= randint(25)) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ /* Place a full floor under the room */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Walls around the room */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, info);
+
+ /* Hack -- Occasional pillar room */
+ if (ysize > 2 && xsize > 2)
+ {
+ if (rand_int(20) == 0)
+ {
+ for (y = y1; y <= y2; y += 2)
+ {
+ for (x = x1; x <= x2; x += 2)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Hack -- Occasional ragged-edge room */
+ else if (rand_int(50) == 0)
+ {
+ for (y = y1 + 2; y <= y2 - 2; y += 2)
+ {
+ cave_set_feat(y, x1, feat_wall_inner);
+ cave_set_feat(y, x2, feat_wall_inner);
+ }
+ for (x = x1 + 2; x <= x2 - 2; x += 2)
+ {
+ cave_set_feat(y1, x, feat_wall_inner);
+ cave_set_feat(y2, x, feat_wall_inner);
+ }
+ }
+ }
+}
+
+/*
+ * Type 2 -- Overlapping rectangular rooms
+ */
+static void build_type2(int by0, int bx0)
+{
+ u16b info;
+ int y, x, yval, xval;
+ int y1a, x1a, y2a, x2a;
+ int y1b, x1b, y2b, x2b;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, FALSE, by0, bx0, &xval, &yval)) return;
+
+ /* Determine extents of the first room */
+ y1a = yval - randint(4);
+ y2a = yval + randint(3);
+ x1a = xval - randint(14);
+ x2a = xval + randint(6);
+
+ /* Determine extents of the second room */
+ y1b = yval - randint(3);
+ y2b = yval + randint(4);
+ x1b = xval - randint(6);
+ x2b = xval + randint(14);
+
+ info = (dun_level <= randint(25)) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ /* Place the walls around room "a" */
+ build_rectangle(y1a - 1, x1a - 1, y2a + 1, x2a + 1, feat_wall_outer, info);
+
+ /* Place the walls around room "a" */
+ build_rectangle(y1b - 1, x1b - 1, y2b + 1, x2b + 1, feat_wall_outer, info);
+
+ /* Replace the floor for room "a" */
+ for (y = y1a; y <= y2a; y++)
+ {
+ for (x = x1a; x <= x2a; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Replace the floor for room "b" */
+ for (y = y1b; y <= y2b; y++)
+ {
+ for (x = x1b; x <= x2b; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+}
+
+/*
+ * Type 3 -- Cross shaped rooms
+ *
+ * Builds a room at a row, column coordinate
+ *
+ * Room "a" runs north/south, and Room "b" runs east/east
+ * So the "central pillar" runs from x1a,y1b to x2a,y2b.
+ *
+ * Note that currently, the "center" is always 3x3, but I think that
+ * the code below will work (with "bounds checking") for 5x5, or even
+ * for unsymetric values like 4x3 or 5x3 or 3x4 or 3x5, or even larger.
+ */
+static void build_type3(int by0, int bx0)
+{
+ u16b info;
+ int y, x, dy, dx, wy, wx;
+ int y1a, x1a, y2a, x2a;
+ int y1b, x1b, y2b, x2b;
+ int yval, xval;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, FALSE, by0, bx0, &xval, &yval)) return;
+
+ /* For now, always 3x3 */
+ wx = wy = 1;
+
+ /* Pick max vertical size (at most 4) */
+ dy = rand_range(3, 4);
+
+ /* Pick max horizontal size (at most 11) */
+ dx = rand_range(3, 11);
+
+ /* Determine extents of the north/south room */
+ y1a = yval - dy;
+ y2a = yval + dy;
+ x1a = xval - wx;
+ x2a = xval + wx;
+
+ /* Determine extents of the east/west room */
+ y1b = yval - wy;
+ y2b = yval + wy;
+ x1b = xval - dx;
+ x2b = xval + dx;
+
+ info = (dun_level <= randint(25)) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ /* Place the walls around room "a" */
+ build_rectangle(y1a - 1, x1a - 1, y2a + 1, x2a + 1, feat_wall_outer, info);
+
+ /* Place the walls around room "a" */
+ build_rectangle(y1b - 1, x1b - 1, y2b + 1, x2b + 1, feat_wall_outer, info);
+
+ /* Replace the floor for room "a" */
+ for (y = y1a; y <= y2a; y++)
+ {
+ for (x = x1a; x <= x2a; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Replace the floor for room "b" */
+ for (y = y1b; y <= y2b; y++)
+ {
+ for (x = x1b; x <= x2b; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Special features (3/4) */
+ switch (rand_int(4))
+ {
+ /* Large solid middle pillar */
+ case 1:
+ {
+ for (y = y1b; y <= y2b; y++)
+ {
+ for (x = x1a; x <= x2a; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ break;
+ }
+
+ /* Inner treasure vault */
+ case 2:
+ {
+ /* Build the vault */
+ build_rectangle(y1b, x1a, y2b, x2a, feat_wall_inner, info);
+
+ /* Place a secret door on the inner room */
+ switch (rand_int(4))
+ {
+ case 0:
+ place_secret_door(y1b, xval);
+ break;
+ case 1:
+ place_secret_door(y2b, xval);
+ break;
+ case 2:
+ place_secret_door(yval, x1a);
+ break;
+ case 3:
+ place_secret_door(yval, x2a);
+ break;
+ }
+
+ /* Place a treasure in the vault */
+ place_object(yval, xval, FALSE, FALSE, OBJ_FOUND_FLOOR);
+
+ /* Let's guard the treasure well */
+ vault_monsters(yval, xval, rand_int(2) + 3);
+
+ /* Traps naturally */
+ vault_traps(yval, xval, 4, 4, rand_int(3) + 2);
+
+ break;
+ }
+
+ /* Something else */
+ case 3:
+ {
+ /* Occasionally pinch the center shut */
+ if (rand_int(3) == 0)
+ {
+ /* Pinch the east/west sides */
+ for (y = y1b; y <= y2b; y++)
+ {
+ if (y == yval) continue;
+ cave_set_feat(y, x1a - 1, feat_wall_inner);
+ cave_set_feat(y, x2a + 1, feat_wall_inner);
+ }
+
+ /* Pinch the north/south sides */
+ for (x = x1a; x <= x2a; x++)
+ {
+ if (x == xval) continue;
+ cave_set_feat(y1b - 1, x, feat_wall_inner);
+ cave_set_feat(y2b + 1, x, feat_wall_inner);
+ }
+
+ /* Sometimes shut using secret doors */
+ if (rand_int(3) == 0)
+ {
+ place_secret_door(yval, x1a - 1);
+ place_secret_door(yval, x2a + 1);
+ place_secret_door(y1b - 1, xval);
+ place_secret_door(y2b + 1, xval);
+ }
+ }
+
+ /* Occasionally put a "plus" in the center */
+ else if (rand_int(3) == 0)
+ {
+ cave_set_feat(yval, xval, feat_wall_inner);
+ cave_set_feat(y1b, xval, feat_wall_inner);
+ cave_set_feat(y2b, xval, feat_wall_inner);
+ cave_set_feat(yval, x1a, feat_wall_inner);
+ cave_set_feat(yval, x2a, feat_wall_inner);
+ }
+
+ /* Occasionally put a pillar in the center */
+ else if (rand_int(3) == 0)
+ {
+ cave_set_feat(yval, xval, feat_wall_inner);
+ }
+
+ break;
+ }
+ }
+}
+
+/*
+ * Type 4 -- Large room with inner features
+ *
+ * Possible sub-types:
+ * 1 - Just an inner room with one door
+ * 2 - An inner room within an inner room
+ * 3 - An inner room with pillar(s)
+ * 4 - Inner room has a maze
+ * 5 - A set of four inner rooms
+ */
+static void build_type4(int by0, int bx0)
+{
+ u16b info;
+ int y, x, y1, x1;
+ int y2, x2, tmp, yval, xval;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, FALSE, by0, bx0, &xval, &yval)) return;
+
+ /* Large room */
+ y1 = yval - 4;
+ y2 = yval + 4;
+ x1 = xval - 11;
+ x2 = xval + 11;
+
+ info = (dun_level <= randint(25)) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ /* Place a full floor under the room */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Outer Walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, info);
+
+ /* The inner room */
+ y1 = y1 + 2;
+ y2 = y2 - 2;
+ x1 = x1 + 2;
+ x2 = x2 - 2;
+
+ /* The inner walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_inner, info);
+
+ /* Inner room variations */
+ switch (randint(5))
+ {
+ /* Just an inner room with a monster */
+ case 1:
+ {
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Place a monster in the room */
+ vault_monsters(yval, xval, 1);
+
+ break;
+ }
+
+ /* Treasure Vault (with a door) */
+ case 2:
+ {
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Place another inner room */
+ build_rectangle(yval - 1, xval - 1, yval + 1, xval + 1,
+ feat_wall_inner, info);
+
+ /* Place a locked door on the inner room */
+ switch (randint(4))
+ {
+ case 1:
+ place_locked_door(yval - 1, xval);
+ break;
+ case 2:
+ place_locked_door(yval + 1, xval);
+ break;
+ case 3:
+ place_locked_door(yval, xval - 1);
+ break;
+ case 4:
+ place_locked_door(yval, xval + 1);
+ break;
+ }
+
+ /* Monsters to guard the "treasure" */
+ vault_monsters(yval, xval, randint(3) + 2);
+
+ /* Object (80%) */
+ if (rand_int(100) < 80)
+ {
+ place_object(yval, xval, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+
+ /* Stairs (20%) */
+ else
+ {
+ place_random_stairs(yval, xval);
+ }
+
+ /* Traps to protect the treasure */
+ vault_traps(yval, xval, 4, 10, 2 + randint(3));
+
+ break;
+ }
+
+ /* Inner pillar(s). */
+ case 3:
+ {
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Large Inner Pillar */
+ for (y = yval - 1; y <= yval + 1; y++)
+ {
+ for (x = xval - 1; x <= xval + 1; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+
+ /* Occasionally, two more Large Inner Pillars */
+ if (rand_int(2) == 0)
+ {
+ tmp = randint(2);
+ for (y = yval - 1; y <= yval + 1; y++)
+ {
+ for (x = xval - 5 - tmp; x <= xval - 3 - tmp; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ for (x = xval + 3 + tmp; x <= xval + 5 + tmp; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Occasionally, some Inner rooms */
+ if (rand_int(3) == 0)
+ {
+ /* Long horizontal walls */
+ for (x = xval - 5; x <= xval + 5; x++)
+ {
+ cave_set_feat(yval - 1, x, feat_wall_inner);
+ cave_set_feat(yval + 1, x, feat_wall_inner);
+ }
+
+ /* Close off the left/right edges */
+ cave_set_feat(yval, xval - 5, feat_wall_inner);
+ cave_set_feat(yval, xval + 5, feat_wall_inner);
+
+ /* Secret doors (random top/bottom) */
+ place_secret_door(yval - 3 + (randint(2) * 2), xval - 3);
+ place_secret_door(yval - 3 + (randint(2) * 2), xval + 3);
+
+ /* Monsters */
+ vault_monsters(yval, xval - 2, randint(2));
+ vault_monsters(yval, xval + 2, randint(2));
+
+ /* Objects */
+ if (rand_int(3) == 0) place_object(yval, xval - 2, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ if (rand_int(3) == 0) place_object(yval, xval + 2, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+
+ break;
+ }
+
+ /* Maze inside. */
+ case 4:
+ {
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Maze (really a checkerboard) */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ if (0x1 & (x + y))
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Monsters just love mazes. */
+ vault_monsters(yval, xval - 5, randint(3));
+ vault_monsters(yval, xval + 5, randint(3));
+
+ /* Traps make them entertaining. */
+ vault_traps(yval, xval - 3, 2, 8, randint(3));
+ vault_traps(yval, xval + 3, 2, 8, randint(3));
+
+ /* Mazes should have some treasure too. */
+ vault_objects(yval, xval, 3);
+
+ break;
+ }
+
+ /* Four small rooms. */
+ case 5:
+ {
+ /* Inner "cross" */
+ for (y = y1; y <= y2; y++)
+ {
+ cave_set_feat(y, xval, feat_wall_inner);
+ }
+
+ for (x = x1; x <= x2; x++)
+ {
+ cave_set_feat(yval, x, feat_wall_inner);
+ }
+
+ /* Doors into the rooms */
+ if (rand_int(100) < 50)
+ {
+ int i = randint(10);
+ place_secret_door(y1 - 1, xval - i);
+ place_secret_door(y1 - 1, xval + i);
+ place_secret_door(y2 + 1, xval - i);
+ place_secret_door(y2 + 1, xval + i);
+ }
+ else
+ {
+ int i = randint(3);
+ place_secret_door(yval + i, x1 - 1);
+ place_secret_door(yval - i, x1 - 1);
+ place_secret_door(yval + i, x2 + 1);
+ place_secret_door(yval - i, x2 + 1);
+ }
+
+ /* Treasure, centered at the center of the cross */
+ vault_objects(yval, xval, 2 + randint(2));
+
+ /* Gotta have some monsters. */
+ vault_monsters(yval + 1, xval - 4, randint(4));
+ vault_monsters(yval + 1, xval + 4, randint(4));
+ vault_monsters(yval - 1, xval - 4, randint(4));
+ vault_monsters(yval - 1, xval + 4, randint(4));
+
+ break;
+ }
+ }
+}
+
+
+/*
+ * Determine if the given monster is appropriate for inclusion in
+ * a monster nest or monster pit or the given type.
+ *
+ * None of the pits/nests are allowed to include "unique" monsters,
+ * or monsters which can "multiply".
+ *
+ * Some of the pits/nests are asked to avoid monsters which can blink
+ * away or which are invisible. This is probably a hack.
+ *
+ * The old method made direct use of monster "names", which is bad.
+ *
+ * Note the use of Angband 2.7.9 monster race pictures in various places.
+ */
+
+
+/*
+ * Helper function for "monster nest (jelly)"
+ */
+static bool_ vault_aux_jelly(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Also decline evil jellies (like death molds and shoggoths) */
+ if (r_ptr->flags3 & (RF3_EVIL)) return (FALSE);
+
+ /* Require icky thing, jelly, mold, or mushroom */
+ if (!strchr("ijm,", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (animal)"
+ */
+static bool_ vault_aux_animal(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require "animal" flag */
+ if (!(r_ptr->flags3 & (RF3_ANIMAL))) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (undead)"
+ */
+static bool_ vault_aux_undead(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require Undead */
+ if (!(r_ptr->flags3 & (RF3_UNDEAD))) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (chapel)"
+ */
+static bool_ vault_aux_chapel(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require "priest" or Angel */
+ if (!((r_ptr->d_char == 'A') ||
+ strstr((r_name + r_ptr->name), "riest")))
+ {
+ return (FALSE);
+ }
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (kennel)"
+ */
+static bool_ vault_aux_kennel(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require a Zephyr Hound or a dog */
+ return ((r_ptr->d_char == 'Z') || (r_ptr->d_char == 'C'));
+
+}
+
+
+/*
+ * Helper function for "monster nest (treasure)"
+ */
+static bool_ vault_aux_treasure(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require "priest" or Angel */
+ if (!((r_ptr->d_char == '!') || (r_ptr->d_char == '|') ||
+ (r_ptr->d_char == '$') || (r_ptr->d_char == '?') ||
+ (r_ptr->d_char == '=')))
+ {
+ return (FALSE);
+ }
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (clone)"
+ */
+static bool_ vault_aux_clone(int r_idx)
+{
+ return (r_idx == template_race);
+}
+
+
+/*
+ * Helper function for "monster nest (symbol clone)"
+ */
+static bool_ vault_aux_symbol(int r_idx)
+{
+ return ((r_info[r_idx].d_char == (r_info[template_race].d_char))
+ && !(r_info[r_idx].flags1 & RF1_UNIQUE));
+}
+
+
+/*
+ * Helper function for "monster pit (orc)"
+ */
+static bool_ vault_aux_orc(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "o" monsters */
+ if (!strchr("o", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+
+/*
+ * Helper function for "monster pit (troll)"
+ */
+static bool_ vault_aux_troll(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "T" monsters */
+ if (!strchr("T", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster pit (giant)"
+ */
+static bool_ vault_aux_giant(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "P" monsters */
+ if (!strchr("P", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Hack -- breath type for "vault_aux_dragon()"
+ */
+static u32b vault_aux_dragon_mask4;
+
+
+/*
+ * Helper function for "monster pit (dragon)"
+ */
+static bool_ vault_aux_dragon(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "d" or "D" monsters */
+ if (!strchr("Dd", r_ptr->d_char)) return (FALSE);
+
+ /* Hack -- Require correct "breath attack" */
+ if (r_ptr->flags4 != vault_aux_dragon_mask4) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster pit (demon)"
+ */
+static bool_ vault_aux_demon(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "U" monsters */
+ if (!strchr("U", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Type 5 -- Monster nests
+ *
+ * A monster nest is a "big" room, with an "inner" room, containing
+ * a "collection" of monsters of a given type strewn about the room.
+ *
+ * The monsters are chosen from a set of 64 randomly selected monster
+ * races, to allow the nest creation to fail instead of having "holes".
+ *
+ * Note the use of the "get_mon_num_prep()" function, and the special
+ * "get_mon_num_hook()" restriction function, to prepare the "monster
+ * allocation table" in such a way as to optimize the selection of
+ * "appropriate" non-unique monsters for the nest.
+ *
+ * Currently, a monster nest is one of
+ * a nest of "jelly" monsters (Dungeon level 5 and deeper)
+ * a nest of "animal" monsters (Dungeon level 30 and deeper)
+ * a nest of "undead" monsters (Dungeon level 50 and deeper)
+ *
+ * Note that the "get_mon_num()" function may (rarely) fail, in which
+ * case the nest will be empty, and will not affect the level rating.
+ *
+ * Note that "monster nests" will never contain "unique" monsters.
+ */
+static void build_type5(int by0, int bx0)
+{
+ int y, x, y1, x1, y2, x2, xval, yval;
+ int tmp, i;
+ cptr name;
+ bool_ empty = FALSE;
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+ s16b what[64];
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, TRUE, by0, bx0, &xval, &yval)) return;
+
+ /* Large room */
+ y1 = yval - 4;
+ y2 = yval + 4;
+ x1 = xval - 11;
+ x2 = xval + 11;
+
+ /* Place the floor area */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= (CAVE_ROOM);
+ }
+ }
+
+ /* Place the outer walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, CAVE_ROOM);
+
+ /* Advance to the center room */
+ y1 = y1 + 2;
+ y2 = y2 - 2;
+ x1 = x1 + 2;
+ x2 = x2 - 2;
+
+ /* The inner walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_inner, CAVE_ROOM);
+
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Hack -- Choose a nest type */
+ tmp = randint(dun_level);
+
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ if ((tmp < 25) && (rand_int(2) != 0))
+ {
+ while (1)
+ {
+ template_race = randint(max_r_idx - 2);
+
+ /* Reject uniques */
+ if (r_info[template_race].flags1 & RF1_UNIQUE) continue;
+
+ /* Reject OoD monsters in a loose fashion */
+ if (((r_info[template_race].level) + randint(5)) >
+ (dun_level + randint(5))) continue;
+
+ /* Don't like 'break's like this, but this cannot be made better */
+ break;
+ }
+
+ if ((dun_level >= (25 + randint(15))) && (rand_int(2) != 0))
+ {
+ name = "symbol clone";
+ get_mon_num_hook = vault_aux_symbol;
+ }
+ else
+ {
+ name = "clone";
+ get_mon_num_hook = vault_aux_clone;
+ }
+ }
+ else if (tmp < 25)
+ /* Monster nest (jelly) */
+ {
+ /* Describe */
+ name = "jelly";
+
+ /* Restrict to jelly */
+ get_mon_num_hook = vault_aux_jelly;
+ }
+
+ else if (tmp < 50)
+ {
+ name = "treasure";
+ get_mon_num_hook = vault_aux_treasure;
+ }
+
+ /* Monster nest (animal) */
+ else if (tmp < 65)
+ {
+ if (rand_int(3) == 0)
+ {
+ name = "kennel";
+ get_mon_num_hook = vault_aux_kennel;
+ }
+ else
+ {
+ /* Describe */
+ name = "animal";
+
+ /* Restrict to animal */
+ get_mon_num_hook = vault_aux_animal;
+ }
+ }
+
+ /* Monster nest (undead) */
+ else
+ {
+ if (rand_int(3) == 0)
+ {
+ name = "chapel";
+ get_mon_num_hook = vault_aux_chapel;
+ }
+ else
+ {
+ /* Describe */
+ name = "undead";
+
+ /* Restrict to undead */
+ get_mon_num_hook = vault_aux_undead;
+ }
+ }
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Pick some monster types */
+ for (i = 0; i < 64; i++)
+ {
+ /* Get a (hard) monster type */
+ what[i] = get_mon_num(dun_level + 10);
+
+ /* Notice failure */
+ if (!what[i]) empty = TRUE;
+ }
+
+ /* Remove restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Oops */
+ if (empty) return;
+
+ /* Describe */
+ if (cheat_room || p_ptr->precognition)
+ {
+ /* Room type */
+ msg_format("Monster nest (%s)", name);
+ }
+
+ /* Increase the level rating */
+ rating += 10;
+
+ /* (Sometimes) Cause a "special feeling" (for "Monster Nests") */
+ if ((dun_level <= 40) && (randint(dun_level * dun_level + 50) < 300))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Place some monsters */
+ for (y = yval - 2; y <= yval + 2; y++)
+ {
+ for (x = xval - 9; x <= xval + 9; x++)
+ {
+ int r_idx = what[rand_int(64)];
+
+ /* Place that "random" monster (no groups) */
+ (void)place_monster_aux(y, x, r_idx, FALSE, FALSE, MSTATUS_ENEMY);
+ }
+ }
+}
+
+
+
+/*
+ * Type 6 -- Monster pits
+ *
+ * A monster pit is a "big" room, with an "inner" room, containing
+ * a "collection" of monsters of a given type organized in the room.
+ *
+ * Monster types in the pit (list out of date...)
+ * orc pit (Dungeon Level 5 and deeper)
+ * troll pit (Dungeon Level 20 and deeper)
+ * giant pit (Dungeon Level 40 and deeper)
+ * dragon pit (Dungeon Level 60 and deeper)
+ * demon pit (Dungeon Level 80 and deeper)
+ *
+ * The inside room in a monster pit appears as shown below, where the
+ * actual monsters in each location depend on the type of the pit
+ *
+ * #####################
+ * #0000000000000000000#
+ * #0112233455543322110#
+ * #0112233467643322110#
+ * #0112233455543322110#
+ * #0000000000000000000#
+ * #####################
+ *
+ * Note that the monsters in the pit are now chosen by using "get_mon_num()"
+ * to request 16 "appropriate" monsters, sorting them by level, and using
+ * the "even" entries in this sorted list for the contents of the pit.
+ *
+ * Hack -- all of the "dragons" in a "dragon" pit must be the same "color",
+ * which is handled by requiring a specific "breath" attack for all of the
+ * dragons. This may include "multi-hued" breath. Note that "wyrms" may
+ * be present in many of the dragon pits, if they have the proper breath.
+ *
+ * Note the use of the "get_mon_num_prep()" function, and the special
+ * "get_mon_num_hook()" restriction function, to prepare the "monster
+ * allocation table" in such a way as to optimize the selection of
+ * "appropriate" non-unique monsters for the pit.
+ *
+ * Note that the "get_mon_num()" function may (rarely) fail, in which case
+ * the pit will be empty, and will not effect the level rating.
+ *
+ * Note that "monster pits" will never contain "unique" monsters.
+ */
+static void build_type6(int by0, int bx0)
+{
+ int tmp, what[16];
+ int i, j, y, x, y1, x1, y2, x2, xval, yval;
+ bool_ empty = FALSE;
+ cptr name;
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, TRUE, by0, bx0, &xval, &yval)) return;
+
+ /* Large room */
+ y1 = yval - 4;
+ y2 = yval + 4;
+ x1 = xval - 11;
+ x2 = xval + 11;
+
+ /* Place the floor area */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= (CAVE_ROOM);
+ }
+ }
+
+ /* Place the outer walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, CAVE_ROOM);
+
+ /* Advance to the center room */
+ y1 = y1 + 2;
+ y2 = y2 - 2;
+ x1 = x1 + 2;
+ x2 = x2 - 2;
+
+ /* The inner walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, CAVE_ROOM);
+
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Choose a pit type */
+ tmp = randint(dun_level);
+
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ /* Orc pit */
+ if (tmp < 20)
+ {
+ /* Message */
+ name = "orc";
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_orc;
+ }
+
+ /* Troll pit */
+ else if (tmp < 40)
+ {
+ /* Message */
+ name = "troll";
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_troll;
+ }
+
+ /* Giant pit */
+ else if (tmp < 55)
+ {
+ /* Message */
+ name = "giant";
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_giant;
+ }
+
+ else if (tmp < 70)
+ {
+ if (randint(4) != 1)
+ {
+ /* Message */
+ name = "ordered clones";
+
+ do
+ {
+ template_race = randint(max_r_idx - 2);
+ }
+ while ((r_info[template_race].flags1 & RF1_UNIQUE)
+ || (((r_info[template_race].level) + randint(5)) >
+ (dun_level + randint(5))));
+
+ /* Restrict selection */
+ get_mon_num_hook = vault_aux_symbol;
+ }
+ else
+ {
+ name = "ordered chapel";
+ get_mon_num_hook = vault_aux_chapel;
+ }
+
+ }
+
+ /* Dragon pit */
+ else if (tmp < 80)
+ {
+ /* Pick dragon type */
+ switch (rand_int(6))
+ {
+ /* Black */
+ case 0:
+ {
+ /* Message */
+ name = "acid dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_ACID;
+
+ /* Done */
+ break;
+ }
+
+ /* Blue */
+ case 1:
+ {
+ /* Message */
+ name = "electric dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_ELEC;
+
+ /* Done */
+ break;
+ }
+
+ /* Red */
+ case 2:
+ {
+ /* Message */
+ name = "fire dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_FIRE;
+
+ /* Done */
+ break;
+ }
+
+ /* White */
+ case 3:
+ {
+ /* Message */
+ name = "cold dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_COLD;
+
+ /* Done */
+ break;
+ }
+
+ /* Green */
+ case 4:
+ {
+ /* Message */
+ name = "poison dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_POIS;
+
+ /* Done */
+ break;
+ }
+
+ /* Multi-hued */
+ default:
+ {
+ /* Message */
+ name = "multi-hued dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = (RF4_BR_ACID | RF4_BR_ELEC |
+ RF4_BR_FIRE | RF4_BR_COLD |
+ RF4_BR_POIS);
+
+ /* Done */
+ break;
+ }
+
+ }
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_dragon;
+ }
+
+ /* Demon pit */
+ else
+ {
+ /* Message */
+ name = "demon";
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_demon;
+ }
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Pick some monster types */
+ for (i = 0; i < 16; i++)
+ {
+ /* Get a (hard) monster type */
+ what[i] = get_mon_num(dun_level + 10);
+
+ /* Notice failure */
+ if (!what[i]) empty = TRUE;
+ }
+
+ /* Remove restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Oops */
+ if (empty) return;
+
+ /* XXX XXX XXX */
+ /* Sort the entries */
+ for (i = 0; i < 16 - 1; i++)
+ {
+ /* Sort the entries */
+ for (j = 0; j < 16 - 1; j++)
+ {
+ int i1 = j;
+ int i2 = j + 1;
+
+ int p1 = r_info[what[i1]].level;
+ int p2 = r_info[what[i2]].level;
+
+ /* Bubble */
+ if (p1 > p2)
+ {
+ int tmp = what[i1];
+ what[i1] = what[i2];
+ what[i2] = tmp;
+ }
+ }
+ }
+
+ /* Select the entries */
+ for (i = 0; i < 8; i++)
+ {
+ /* Every other entry */
+ what[i] = what[i * 2];
+ }
+
+ /* Message */
+ if (cheat_room || p_ptr->precognition)
+ {
+ /* Room type */
+ msg_format("Monster pit (%s)", name);
+
+ if (cheat_hear || p_ptr->precognition)
+ {
+ /* Contents */
+ for (i = 0; i < 8; i++)
+ {
+ /* Message */
+ msg_print(r_name + r_info[what[i]].name);
+ }
+ }
+ }
+
+ /* Increase the level rating */
+ rating += 10;
+
+ /* (Sometimes) Cause a "special feeling" (for "Monster Pits") */
+ if ((dun_level <= 40) && (randint(dun_level * dun_level + 50) < 300))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Top and bottom rows */
+ for (x = xval - 9; x <= xval + 9; x++)
+ {
+ place_monster_aux(yval - 2, x, what[0], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(yval + 2, x, what[0], FALSE, FALSE, MSTATUS_ENEMY);
+ }
+
+ /* Middle columns */
+ for (y = yval - 1; y <= yval + 1; y++)
+ {
+ place_monster_aux(y, xval - 9, what[0], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 9, what[0], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 8, what[1], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 8, what[1], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 7, what[1], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 7, what[1], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 6, what[2], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 6, what[2], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 5, what[2], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 5, what[2], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 4, what[3], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 4, what[3], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 3, what[3], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 3, what[3], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 2, what[4], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 2, what[4], FALSE, FALSE, MSTATUS_ENEMY);
+ }
+
+ /* Above/Below the center monster */
+ for (x = xval - 1; x <= xval + 1; x++)
+ {
+ place_monster_aux(yval + 1, x, what[5], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(yval - 1, x, what[5], FALSE, FALSE, MSTATUS_ENEMY);
+ }
+
+ /* Next to the center monster */
+ place_monster_aux(yval, xval + 1, what[6], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(yval, xval - 1, what[6], FALSE, FALSE, MSTATUS_ENEMY);
+
+ /* Center monster */
+ place_monster_aux(yval, xval, what[7], FALSE, FALSE, MSTATUS_ENEMY);
+}
+
+/*
+ * Hack -- fill in "vault" rooms
+ */
+static void build_vault(int yval, int xval, int ymax, int xmax, cptr data)
+{
+ int dx, dy, x, y, bwy[8], bwx[8], i;
+
+ cptr t;
+
+ cave_type *c_ptr;
+
+ /* Clean the between gates arrays */
+ for (i = 0; i < 8; i++)
+ {
+ bwy[i] = bwx[i] = 9999;
+ }
+
+ /* Place dungeon features and objects */
+ for (t = data, dy = 0; dy < ymax; dy++)
+ {
+ for (dx = 0; dx < xmax; dx++, t++)
+ {
+ /* Extract the location */
+ x = xval - (xmax / 2) + dx;
+ y = yval - (ymax / 2) + dy;
+
+ /* Hack -- skip "non-grids" */
+ if (*t == ' ') continue;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Lay down a floor */
+ place_floor(y, x);
+
+ /* Part of a vault */
+ c_ptr->info |= (CAVE_ROOM | CAVE_ICKY);
+
+ /* Analyze the grid */
+ switch (*t)
+ {
+ /* Granite wall (outer) */
+ case '%':
+ {
+ cave_set_feat(y, x, FEAT_WALL_OUTER);
+ break;
+ }
+
+ /* Granite wall (inner) */
+ case '#':
+ {
+ cave_set_feat(y, x, FEAT_WALL_INNER);
+ break;
+ }
+
+ /* Permanent wall (inner) */
+ case 'X':
+ {
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+ break;
+ }
+
+ /* Treasure/trap */
+ case '*':
+ {
+ if (rand_int(100) < 75)
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_VAULT);
+ }
+ else
+ {
+ place_trap(y, x);
+ }
+ break;
+ }
+
+ /* Secret doors */
+ case '+':
+ {
+ place_secret_door(y, x);
+ break;
+ }
+
+ /* Trap */
+ case '^':
+ {
+ place_trap(y, x);
+ break;
+ }
+
+ /* Glass wall */
+ case 'G':
+ {
+ cave_set_feat(y, x, FEAT_GLASS_WALL);
+ break;
+ }
+
+ /* Illusion wall */
+ case 'I':
+ {
+ cave_set_feat(y, x, FEAT_ILLUS_WALL);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Place dungeon monsters and objects */
+ for (t = data, dy = 0; dy < ymax; dy++)
+ {
+ for (dx = 0; dx < xmax; dx++, t++)
+ {
+ /* Extract the grid */
+ x = xval - (xmax / 2) + dx;
+ y = yval - (ymax / 2) + dy;
+
+ /* Hack -- skip "non-grids" */
+ if (*t == ' ') continue;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Analyze the symbol */
+ switch (*t)
+ {
+ /* Monster */
+ case '&':
+ {
+ monster_level = dun_level + 5;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ break;
+ }
+
+ /* Meaner monster */
+ case '@':
+ {
+ monster_level = dun_level + 11;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ break;
+ }
+
+ /* Meaner monster, plus treasure */
+ case '9':
+ {
+ monster_level = dun_level + 9;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ object_level = dun_level + 7;
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_VAULT);
+ object_level = dun_level;
+ break;
+ }
+
+ /* Nasty monster and treasure */
+ case '8':
+ {
+ monster_level = dun_level + 40;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ object_level = dun_level + 20;
+ place_object(y, x, TRUE, TRUE, OBJ_FOUND_VAULT);
+ object_level = dun_level;
+ break;
+ }
+
+ /* Monster and/or object */
+ case ',':
+ {
+ if (rand_int(100) < 50)
+ {
+ monster_level = dun_level + 3;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ }
+ if (rand_int(100) < 50)
+ {
+ object_level = dun_level + 7;
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_VAULT);
+ object_level = dun_level;
+ }
+ break;
+ }
+
+ case 'p':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_START);
+ break;
+ }
+
+ case 'a':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_1);
+ break;
+ }
+
+ case 'b':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_2);
+ break;
+ }
+
+ case 'c':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_3);
+ break;
+ }
+
+ case 'd':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_4);
+ break;
+ }
+
+ case 'P':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_END);
+ break;
+ }
+
+ case 'B':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_XTRA1);
+ break;
+ }
+
+ case 'A':
+ {
+ object_level = dun_level + 12;
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_VAULT);
+ object_level = dun_level;
+ break;
+ }
+
+
+ /* Between gates */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ /* Not found before */
+ if (bwy[*t - '0'] == 9999)
+ {
+ cave_set_feat(y, x, FEAT_BETWEEN);
+ bwy[*t - '0'] = y;
+ bwx[*t - '0'] = x;
+ }
+ /* The second time */
+ else
+ {
+ cave_set_feat(y, x, FEAT_BETWEEN);
+ c_ptr->special = bwx[*t - '0'] + (bwy[*t - '0'] << 8);
+ cave[bwy[*t - '0']][bwx[*t - '0']].special = x + (y << 8);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Type 7 -- simple vaults (see "v_info.txt")
+ */
+static void build_type7(int by0, int bx0)
+{
+ vault_type *v_ptr = NULL;
+ int dummy = 0, xval, yval;
+
+ /* Pick a lesser vault */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ dummy++;
+
+ /* Access a random vault record */
+ v_ptr = &v_info[rand_int(max_v_idx)];
+
+ /* Accept the first lesser vault */
+ if (v_ptr->typ == 7) break;
+ }
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(v_ptr->wid, v_ptr->hgt, FALSE, by0, bx0, &xval, &yval))
+ {
+ if (cheat_room) msg_print("Could not allocate this vault here");
+ return;
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place lesser vault!");
+ }
+ return;
+ }
+
+
+#ifdef FORCE_V_IDX
+ v_ptr = &v_info[FORCE_V_IDX];
+#endif
+
+ /* Message */
+ if (cheat_room || p_ptr->precognition) msg_print("Lesser Vault");
+
+ /* Boost the rating */
+ rating += v_ptr->rat;
+
+ /* (Sometimes) Cause a special feeling */
+ if ((dun_level <= 50) ||
+ (randint((dun_level - 40) * (dun_level - 40) + 50) < 400))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Hack -- Build the vault */
+ build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, v_text + v_ptr->text);
+}
+
+
+
+/*
+ * Type 8 -- greater vaults (see "v_info.txt")
+ */
+static void build_type8(int by0, int bx0)
+{
+ vault_type *v_ptr = NULL;
+ int dummy = 0, xval, yval;
+
+ /* Pick a lesser vault */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ dummy++;
+
+ /* Access a random vault record */
+ v_ptr = &v_info[rand_int(max_v_idx)];
+
+ /* Accept the first greater vault */
+ if (v_ptr->typ == 8) break;
+ }
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(v_ptr->wid, v_ptr->hgt, FALSE, by0, bx0, &xval, &yval))
+ {
+ if (cheat_room) msg_print("Could not allocate this vault here");
+ return;
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place greater vault!");
+ }
+ return;
+ }
+
+
+#ifdef FORCE_V_IDX
+ v_ptr = &v_info[FORCE_V_IDX];
+#endif
+
+ /* Message */
+ if (cheat_room || p_ptr->precognition) msg_print("Greater Vault");
+
+ /* Boost the rating */
+ rating += v_ptr->rat;
+
+ /* (Sometimes) Cause a special feeling */
+ if ((dun_level <= 50) ||
+ (randint((dun_level - 40) * (dun_level - 40) + 50) < 400))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Hack -- Build the vault */
+ build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, v_text + v_ptr->text);
+}
+
+/*
+ * DAG:
+ * Build an vertical oval room.
+ * For every grid in the possible square, check the distance.
+ * If it's less than or == than the radius, make it a room square.
+ * If its less, make it a normal grid. If it's == make it an outer
+ * wall.
+ */
+static void build_type9(int by0, int bx0)
+{
+ u16b info;
+ int rad, x, y, x0, y0;
+
+ rad = 2 + rand_int(8);
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(rad*2 + 1, rad*2 + 1, FALSE, by0, bx0, &x0, &y0)) return;
+
+ info = (randint(dun_level) <= 5) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ for (x = x0 - rad; x <= x0 + rad; x++)
+ {
+ for (y = y0 - rad; y <= y0 + rad; y++)
+ {
+ if (distance(y0, x0, y, x) == rad)
+ {
+ cave[y][x].info |= info;
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+
+ if (distance(y0, x0, y, x) < rad)
+ {
+ cave[y][x].info |= info;
+ place_floor(y, x);
+ }
+ }
+ }
+}
+
+
+/*
+ * Store routine for the fractal cave generator
+ * this routine probably should be an inline function or a macro
+ */
+static void store_height(int x, int y, int x0, int y0, byte val,
+ int xhsize, int yhsize, int cutoff)
+{
+ /* Only write to points that are "blank" */
+ if (cave[y + y0 - yhsize][x + x0 - xhsize].feat != 255) return;
+
+ /* If on boundary set val > cutoff so walls are not as square */
+ if (((x == 0) || (y == 0) || (x == xhsize * 2) || (y == yhsize * 2)) &&
+ (val <= cutoff)) val = cutoff + 1;
+
+ /* Store the value in height-map format */
+ /* Meant to be temporary, hence no cave_set_feat */
+ cave[y + y0 - yhsize][x + x0 - xhsize].feat = val;
+
+ return;
+}
+
+
+
+/*
+ * Explanation of the plasma fractal algorithm:
+ *
+ * A grid of points is created with the properties of a 'height-map'
+ * This is done by making the corners of the grid have a random value.
+ * The grid is then subdivided into one with twice the resolution.
+ * The new points midway between two 'known' points can be calculated
+ * by taking the average value of the 'known' ones and randomly adding
+ * or subtracting an amount proportional to the distance between those
+ * points. The final 'middle' points of the grid are then calculated
+ * by averaging all four of the originally 'known' corner points. An
+ * random amount is added or subtracted from this to get a value of the
+ * height at that point. The scaling factor here is adjusted to the
+ * slightly larger distance diagonally as compared to orthogonally.
+ *
+ * This is then repeated recursively to fill an entire 'height-map'
+ * A rectangular map is done the same way, except there are different
+ * scaling factors along the x and y directions.
+ *
+ * A hack to change the amount of correlation between points is done using
+ * the grd variable. If the current step size is greater than grd then
+ * the point will be random, otherwise it will be calculated by the
+ * above algorithm. This makes a maximum distance at which two points on
+ * the height map can affect each other.
+ *
+ * How fractal caves are made:
+ *
+ * When the map is complete, a cut-off value is used to create a cave.
+ * Heights below this value are "floor", and heights above are "wall".
+ * This also can be used to create lakes, by adding more height levels
+ * representing shallow and deep water/ lava etc.
+ *
+ * The grd variable affects the width of passages.
+ * The roug variable affects the roughness of those passages
+ *
+ * The tricky part is making sure the created cave is connected. This
+ * is done by 'filling' from the inside and only keeping the 'filled'
+ * floor. Walls bounding the 'filled' floor are also kept. Everything
+ * else is converted to the normal granite FEAT_WALL_EXTRA.
+ */
+
+
+/*
+ * Note that this uses the cave.feat array in a very hackish way
+ * the values are first set to zero, and then each array location
+ * is used as a "heightmap"
+ * The heightmap then needs to be converted back into the "feat" format.
+ *
+ * grd=level at which fractal turns on. smaller gives more mazelike caves
+ * roug=roughness level. 16=normal. higher values make things more
+ * convoluted small values are good for smooth walls.
+ * size=length of the side of the square cave system.
+ */
+
+void generate_hmap(int y0, int x0, int xsiz, int ysiz, int grd,
+ int roug, int cutoff)
+{
+ int xhsize, yhsize, xsize, ysize, maxsize;
+
+ /*
+ * fixed point variables- these are stored as 256 x normal value
+ * this gives 8 binary places of fractional part + 8 places of normal part
+ */
+ u16b xstep, xhstep, ystep, yhstep, i, j, diagsize, xxsize, yysize;
+
+
+ /* Redefine size so can change the value if out of range */
+ xsize = xsiz;
+ ysize = ysiz;
+
+ /* Paranoia about size of the system of caves*/
+ if (xsize > 254) xsize = 254;
+ if (xsize < 4) xsize = 4;
+ if (ysize > 254) ysize = 254;
+ if (ysize < 4) ysize = 4;
+
+ /* Get offsets to middle of array */
+ xhsize = xsize / 2;
+ yhsize = ysize / 2;
+
+ /* Fix rounding problem */
+ xsize = xhsize * 2;
+ ysize = yhsize * 2;
+
+ /*
+ * Scale factor for middle points:
+ * About sqrt(2)*256 - correct for a square lattice
+ * approximately correct for everything else.
+ */
+ diagsize = 362;
+
+ /* Maximum of xsize and ysize */
+ maxsize = (xsize > ysize) ? xsize : ysize;
+
+ /* Clear the section */
+ for (i = 0; i <= xsize; i++)
+ {
+ for (j = 0; j <= ysize; j++)
+ {
+ cave_type *c_ptr;
+
+ /* Access the grid */
+ c_ptr = &cave[j + y0 - yhsize][i + x0 - xhsize];
+
+ /* 255 is a flag for "not done yet" */
+ c_ptr->feat = 255;
+
+ /* Clear icky flag because may be redoing the cave */
+ c_ptr->info &= ~(CAVE_ICKY);
+ }
+ }
+
+ /* Set the corner values just in case grd>size. */
+ store_height(0, 0, x0, y0, maxsize, xhsize, yhsize, cutoff);
+ store_height(0, ysize, x0, y0, maxsize, xhsize, yhsize, cutoff);
+ store_height(xsize, 0, x0, y0, maxsize, xhsize, yhsize, cutoff);
+ store_height(xsize, ysize, x0, y0, maxsize, xhsize, yhsize, cutoff);
+
+ /* Set the middle square to be an open area. */
+ store_height(xhsize, yhsize, x0, y0, 0, xhsize, yhsize, cutoff);
+
+
+ /* Initialise the step sizes */
+ xstep = xhstep = xsize * 256;
+ ystep = yhstep = ysize * 256;
+ xxsize = xsize * 256;
+ yysize = ysize * 256;
+
+ /*
+ * Fill in the rectangle with fractal height data - like the
+ * 'plasma fractal' in fractint
+ */
+ while ((xstep / 256 > 1) || (ystep / 256 > 1))
+ {
+ /* Halve the step sizes */
+ xstep = xhstep;
+ xhstep /= 2;
+ ystep = yhstep;
+ yhstep /= 2;
+
+ /* Middle top to bottom */
+ for (i = xhstep; i <= xxsize - xhstep; i += xstep)
+ {
+ for (j = 0; j <= yysize; j += ystep)
+ {
+ /* If greater than 'grid' level then is random */
+ if (xhstep / 256 > grd)
+ {
+ store_height(i / 256, j / 256, x0, y0, randint(maxsize),
+ xhsize, yhsize, cutoff);
+ }
+ else
+ {
+ cave_type *l, *r;
+ byte val;
+
+ /* Left point */
+ l = &cave[j / 256 + y0 - yhsize][(i - xhstep) / 256 + x0 - xhsize];
+
+ /* Right point */
+ r = &cave[j / 256 + y0 - yhsize][(i + xhstep) / 256 + x0 - xhsize];
+
+ /* Average of left and right points + random bit */
+ val = (l->feat + r->feat) / 2 +
+ (randint(xstep / 256) - xhstep / 256) * roug / 16;
+
+ store_height(i / 256, j / 256, x0, y0, val,
+ xhsize, yhsize, cutoff);
+ }
+ }
+ }
+
+
+ /* Middle left to right */
+ for (j = yhstep; j <= yysize - yhstep; j += ystep)
+ {
+ for (i = 0; i <= xxsize; i += xstep)
+ {
+ /* If greater than 'grid' level then is random */
+ if (xhstep / 256 > grd)
+ {
+ store_height(i / 256, j / 256, x0, y0, randint(maxsize),
+ xhsize, yhsize, cutoff);
+ }
+ else
+ {
+ cave_type *u, *d;
+ byte val;
+
+ /* Up point */
+ u = &cave[(j - yhstep) / 256 + y0 - yhsize][i / 256 + x0 - xhsize];
+
+ /* Down point */
+ d = &cave[(j + yhstep) / 256 + y0 - yhsize][i / 256 + x0 - xhsize];
+
+ /* Average of up and down points + random bit */
+ val = (u->feat + d->feat) / 2 +
+ (randint(ystep / 256) - yhstep / 256) * roug / 16;
+
+ store_height(i / 256, j / 256, x0, y0, val,
+ xhsize, yhsize, cutoff);
+ }
+ }
+ }
+
+ /* Center */
+ for (i = xhstep; i <= xxsize - xhstep; i += xstep)
+ {
+ for (j = yhstep; j <= yysize - yhstep; j += ystep)
+ {
+ /* If greater than 'grid' level then is random */
+ if (xhstep / 256 > grd)
+ {
+ store_height(i / 256, j / 256, x0, y0, randint(maxsize),
+ xhsize, yhsize, cutoff);
+ }
+ else
+ {
+ cave_type *ul, *dl, *ur, *dr;
+ byte val;
+
+ /* Up-left point */
+ ul = &cave[(j - yhstep) / 256 + y0 - yhsize][(i - xhstep) / 256 + x0 - xhsize];
+
+ /* Down-left point */
+ dl = &cave[(j + yhstep) / 256 + y0 - yhsize][(i - xhstep) / 256 + x0 - xhsize];
+
+ /* Up-right point */
+ ur = &cave[(j - yhstep) / 256 + y0 - yhsize][(i + xhstep) / 256 + x0 - xhsize];
+
+ /* Down-right point */
+ dr = &cave[(j + yhstep) / 256 + y0 - yhsize][(i + xhstep) / 256 + x0 - xhsize];
+
+ /*
+ * average over all four corners + scale by diagsize to
+ * reduce the effect of the square grid on the shape
+ * of the fractal
+ */
+ val = (ul->feat + dl->feat + ur->feat + dr->feat) / 4 +
+ (randint(xstep / 256) - xhstep / 256) *
+ (diagsize / 16) / 256 * roug;
+
+ store_height(i / 256, j / 256, x0, y0, val,
+ xhsize, yhsize , cutoff);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Convert from height-map back to the normal Angband cave format
+ */
+static bool_ hack_isnt_wall(int y, int x, int cutoff)
+{
+ /* Already done */
+ if (cave[y][x].info & CAVE_ICKY)
+ {
+ return (FALSE);
+ }
+
+ else
+ {
+ /* Show that have looked at this square */
+ cave[y][x].info |= (CAVE_ICKY);
+
+ /* If less than cutoff then is a floor */
+ if (cave[y][x].feat <= cutoff)
+ {
+ place_floor(y, x);
+ return (TRUE);
+ }
+
+ /* If greater than cutoff then is a wall */
+ else
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ return (FALSE);
+ }
+ }
+}
+
+
+/*
+ * Quick and nasty fill routine used to find the connected region
+ * of floor in the middle of the cave
+ */
+static void fill_hack(int y0, int x0, int y, int x, int xsize, int ysize,
+ int cutoff, int *amount)
+{
+ int i, j;
+
+ /* check 8 neighbours +self (self is caught in the isnt_wall function) */
+ for (i = -1; i <= 1; i++)
+ {
+ for (j = -1; j <= 1; j++)
+ {
+ /* If within bounds */
+ if ((x + i > 0) && (x + i < xsize) &&
+ (y + j > 0) && (y + j < ysize))
+ {
+ /* If not a wall or floor done before */
+ if (hack_isnt_wall(y + j + y0 - ysize / 2,
+ x + i + x0 - xsize / 2, cutoff))
+ {
+ /* then fill from the new point*/
+ fill_hack(y0, x0, y + j, x + i, xsize, ysize,
+ cutoff, amount);
+
+ /* keep tally of size of cave system */
+ (*amount)++;
+ }
+ }
+
+ /* Affect boundary */
+ else
+ {
+ cave[y0 + y + j - ysize / 2][x0 + x + i - xsize / 2].info |= (CAVE_ICKY);
+ }
+ }
+ }
+}
+
+
+bool_ generate_fracave(int y0, int x0, int xsize, int ysize,
+ int cutoff, bool_ light, bool_ room)
+{
+ int x, y, i, amount, xhsize, yhsize;
+ cave_type *c_ptr;
+
+ /* Offsets to middle from corner */
+ xhsize = xsize / 2;
+ yhsize = ysize / 2;
+
+ /* Reset tally */
+ amount = 0;
+
+ /*
+ * Select region connected to center of cave system
+ * this gets rid of alot of isolated one-sqaures that
+ * can make teleport traps instadeaths...
+ */
+ fill_hack(y0, x0, yhsize, xhsize, xsize, ysize, cutoff, &amount);
+
+ /* If tally too small, try again */
+ if (amount < 10)
+ {
+ /* Too small -- clear area and try again later */
+ for (x = 0; x <= xsize; ++x)
+ {
+ for (y = 0; y < ysize; ++y)
+ {
+ place_filler(y0 + y - yhsize, x0 + x - xhsize);
+ cave[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY | CAVE_ROOM);
+ }
+ }
+ return FALSE;
+ }
+
+
+ /*
+ * Do boundaries -- check to see if they are next to a filled region
+ * If not then they are set to normal granite
+ * If so then they are marked as room walls
+ */
+ for (i = 0; i <= xsize; ++i)
+ {
+ /* Access top boundary grid */
+ c_ptr = &cave[0 + y0 - yhsize][i + x0 - xhsize];
+
+ /* Next to a 'filled' region? -- set to be room walls */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ cave_set_feat(0 + y0 - yhsize, i + x0 - xhsize, feat_wall_outer);
+
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(0 + y0 - yhsize, i + x0 - xhsize);
+ }
+ }
+
+ /* Outside of the room -- set to be normal granite */
+ else
+ {
+ place_filler(0 + y0 - yhsize, i + x0 - xhsize);
+ }
+
+ /* Clear the icky flag -- don't need it any more */
+ c_ptr->info &= ~(CAVE_ICKY);
+
+
+ /* Access bottom boundary grid */
+ c_ptr = &cave[ysize + y0 - yhsize][i + x0 - xhsize];
+
+ /* Next to a 'filled' region? -- set to be room walls */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ cave_set_feat(ysize + y0 - yhsize, i + x0 - xhsize, feat_wall_outer);
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(ysize + y0 - yhsize, i + x0 - xhsize);
+ }
+ }
+
+ /* Outside of the room -- set to be normal granite */
+ else
+ {
+ place_filler(ysize + y0 - yhsize, i + x0 - xhsize);
+ }
+
+ /* Clear the icky flag -- don't need it any more */
+ c_ptr->info &= ~(CAVE_ICKY);
+ }
+
+
+ /* Do the left and right boundaries minus the corners (done above) */
+ for (i = 1; i < ysize; ++i)
+ {
+ /* Access left boundary grid */
+ c_ptr = &cave[i + y0 - yhsize][0 + x0 - xhsize];
+
+ /* Next to a 'filled' region? -- set to be room walls */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ cave_set_feat(i + y0 - yhsize, 0 + x0 - xhsize, feat_wall_outer);
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(i + y0 - yhsize, 0 + x0 - xhsize);
+ }
+ }
+
+ /* Outside of the room -- set to be normal granite */
+ else
+ {
+ place_filler(i + y0 - yhsize, 0 + x0 - xhsize);
+ }
+
+ /* Clear the icky flag -- don't need it any more */
+ c_ptr->info &= ~(CAVE_ICKY);
+
+
+ /* Access left boundary grid */
+ c_ptr = &cave[i + y0 - yhsize][xsize + x0 - xhsize];
+
+ /* Next to a 'filled' region? -- set to be room walls */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ cave_set_feat(i + y0 - yhsize, xsize + x0 - xhsize, feat_wall_outer);
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(i + y0 - yhsize, xsize + x0 - xhsize);
+ }
+ }
+
+ /* Outside of the room -- set to be normal granite */
+ else
+ {
+ place_filler(i + y0 - yhsize, xsize + x0 - xhsize);
+ }
+
+ /* Clear the icky flag -- don't need it any more */
+ c_ptr->info &= ~(CAVE_ICKY);
+ }
+
+
+ /*
+ * Do the rest: convert back to the normal format
+ * In other variants, may want to check to see if cave.feat< some value
+ * if so, set to be water:- this will make interesting pools etc.
+ * (I don't do this for standard Angband.)
+ */
+ for (x = 1; x < xsize; ++x)
+ {
+ for (y = 1; y < ysize; ++y)
+ {
+ /* Access the grid */
+ c_ptr = &cave[y + y0 - yhsize][x + x0 - xhsize];
+
+ /* A floor grid to be converted */
+ if ((f_info[c_ptr->feat].flags1 & FF1_FLOOR) &&
+ (c_ptr->info & CAVE_ICKY))
+
+ {
+ /* Clear the icky flag in the filled region */
+ c_ptr->info &= ~(CAVE_ICKY);
+
+ /* Set appropriate flags */
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room) c_ptr->info |= (CAVE_ROOM);
+ }
+
+ /* A wall grid to be convereted */
+ else if ((c_ptr->feat == feat_wall_outer) &&
+ (c_ptr->info & CAVE_ICKY))
+ {
+ /* Clear the icky flag in the filled region */
+ c_ptr->info &= ~(CAVE_ICKY);
+
+ /* Set appropriate flags */
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(y + y0 - yhsize, x + x0 - xhsize);
+ }
+ }
+
+ /* None of the above -- clear the unconnected regions */
+ else
+ {
+ place_filler(y + y0 - yhsize, x + x0 - xhsize);
+ c_ptr->info &= ~(CAVE_ICKY | CAVE_ROOM);
+ }
+ }
+ }
+
+ /*
+ * XXX XXX XXX There is a slight problem when tunnels pierce the caves:
+ * Extra doors appear inside the system. (Its not very noticeable though.)
+ * This can be removed by "filling" from the outside in. This allows
+ * a separation from FEAT_WALL_OUTER with FEAT_WALL_INNER. (Internal
+ * walls are F.W.OUTER instead.)
+ * The extra effort for what seems to be only a minor thing (even
+ * non-existant if you think of the caves not as normal rooms, but as
+ * holes in the dungeon), doesn't seem worth it.
+ */
+
+ return (TRUE);
+}
+
+
+/*
+ * Makes a cave system in the center of the dungeon
+ */
+static void build_cavern(void)
+{
+ int grd, roug, cutoff, xsize, ysize, x0, y0;
+ bool_ done, light, room;
+
+ light = done = room = FALSE;
+ if (dun_level <= randint(25)) light = TRUE;
+
+ /* Make a cave the size of the dungeon */
+ xsize = cur_wid - 1;
+ ysize = cur_hgt - 1;
+ x0 = xsize / 2;
+ y0 = ysize / 2;
+
+ /* Paranoia: make size even */
+ xsize = x0 * 2;
+ ysize = y0 * 2;
+
+ while (!done)
+ {
+ /* Testing values for these parameters: feel free to adjust */
+ grd = 1 << (randint(4) + 4);
+
+ /* Want average of about 16 */
+ roug = randint(8) * randint(4);
+
+ /* About size/2 */
+ cutoff = xsize / 2;
+
+ /* Make it */
+ generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff);
+
+ /* Convert to normal format+ clean up*/
+ done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room);
+ }
+}
+
+/*
+ * Driver routine to create fractal cave system
+ */
+static void build_type10(int by0, int bx0)
+{
+ int grd, roug, cutoff, xsize, ysize, y0, x0;
+
+ bool_ done, light, room;
+
+ /* Get size: note 'Evenness'*/
+ xsize = randint(22) * 2 + 6;
+ ysize = randint(15) * 2 + 6;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(xsize + 1, ysize + 1, FALSE, by0, bx0, &x0, &y0)) return;
+
+ light = done = FALSE;
+ room = TRUE;
+
+ if (dun_level <= randint(25)) light = TRUE;
+
+ while (!done)
+ {
+ /*
+ * Note: size must be even or there are rounding problems
+ * This causes the tunnels not to connect properly to the room
+ */
+
+ /* Testing values for these parameters feel free to adjust */
+ grd = 1 << (randint(4));
+
+ /* Want average of about 16 */
+ roug = randint(8) * randint(4);
+
+ /* About size/2 */
+ cutoff = randint(xsize / 4) + randint(ysize / 4) +
+ randint(xsize / 4) + randint(ysize / 4);
+
+ /* Make it */
+ generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff);
+
+ /* Convert to normal format + clean up*/
+ done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room);
+ }
+}
+
+
+/*
+ * Random vault generation from Z 2.5.1
+ */
+
+/*
+ * Make a very small room centred at (x0, y0)
+ *
+ * This is used in crypts, and random elemental vaults.
+ *
+ * Note - this should be used only on allocated regions
+ * within another room.
+ */
+static void build_small_room(int x0, int y0)
+{
+ build_rectangle(y0 - 1, x0 - 1, y0 + 1, x0 + 1, feat_wall_inner, CAVE_ROOM);
+
+ /* Place a secret door on one side */
+ switch (rand_int(4))
+ {
+ case 0:
+ {
+ place_secret_door(y0, x0 - 1);
+ break;
+ }
+
+ case 1:
+ {
+ place_secret_door(y0, x0 + 1);
+ break;
+ }
+
+ case 2:
+ {
+ place_secret_door(y0 - 1, x0);
+ break;
+ }
+
+ case 3:
+ {
+ place_secret_door(y0 + 1, x0);
+ break;
+ }
+ }
+
+ /* Add inner open space */
+ place_floor(y0, x0);
+}
+
+
+/*
+ * Add a door to a location in a random vault
+ *
+ * Note that range checking has to be done in the calling routine.
+ *
+ * The doors must be INSIDE the allocated region.
+ */
+static void add_door(int x, int y)
+{
+ /* Need to have a wall in the center square */
+ if (cave[y][x].feat != feat_wall_outer) return;
+
+ /*
+ * Look at:
+ * x#x
+ * .#.
+ * x#x
+ *
+ * where x=don't care
+ * .=floor, #=wall
+ */
+
+ if (get_is_floor(x, y - 1) && get_is_floor(x, y + 1) &&
+ (cave[y][x - 1].feat == feat_wall_outer) &&
+ (cave[y][x + 1].feat == feat_wall_outer))
+ {
+ /* secret door */
+ place_secret_door(y, x);
+
+ /* set boundarys so don't get wide doors */
+ place_filler(y, x - 1);
+ place_filler(y, x + 1);
+ }
+
+
+ /*
+ * Look at:
+ * x#x
+ * .#.
+ * x#x
+ *
+ * where x = don't care
+ * .=floor, #=wall
+ */
+ if ((cave[y - 1][x].feat == feat_wall_outer) &&
+ (cave[y + 1][x].feat == feat_wall_outer) &&
+ get_is_floor(x - 1, y) && get_is_floor(x + 1, y))
+ {
+ /* secret door */
+ place_secret_door(y, x);
+
+ /* set boundarys so don't get wide doors */
+ place_filler(y - 1, x);
+ place_filler(y + 1, x);
+ }
+}
+
+
+/*
+ * Fill the empty areas of a room with treasure and monsters.
+ */
+static void fill_treasure(int x1, int x2, int y1, int y2, int difficulty)
+{
+ int x, y, cx, cy, size;
+ s32b value;
+
+ /* center of room:*/
+ cx = (x1 + x2) / 2;
+ cy = (y1 + y2) / 2;
+
+ /* Rough measure of size of vault= sum of lengths of sides */
+ size = abs(x2 - x1) + abs(y2 - y1);
+
+ for (x = x1; x <= x2; x++)
+ {
+ for (y = y1; y <= y2; y++)
+ {
+ /*
+ * Thing added based on distance to center of vault
+ * Difficulty is 1-easy to 10-hard
+ */
+ value = (((s32b)distance(cx, cy, x, y) * 100) / size) +
+ randint(10) - difficulty;
+
+ /* Hack -- Empty square part of the time */
+ if ((randint(100) - difficulty * 3) > 50) value = 20;
+
+ /* If floor, shallow water or lava */
+ if (get_is_floor(x, y) ||
+ (cave[y][x].feat == FEAT_SHAL_WATER) ||
+ (cave[y][x].feat == FEAT_SHAL_LAVA))
+ {
+ /* The smaller 'value' is, the better the stuff */
+ if (value < 0)
+ {
+ /* Meanest monster + treasure */
+ monster_level = dun_level + 40;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ object_level = dun_level + 20;
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_FLOOR);
+ object_level = dun_level;
+ }
+ else if (value < 5)
+ {
+ /* Mean monster +treasure */
+ monster_level = dun_level + 20;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ object_level = dun_level + 10;
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_FLOOR);
+ object_level = dun_level;
+ }
+ else if (value < 10)
+ {
+ /* Monster */
+ monster_level = dun_level + 9;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ }
+ else if (value < 17)
+ {
+ /* Intentional Blank space */
+
+ /*
+ * (Want some of the vault to be empty
+ * so have room for group monsters.
+ * This is used in the hack above to lower
+ * the density of stuff in the vault.)
+ */
+ }
+ else if (value < 23)
+ {
+ /* Object or trap */
+ if (rand_int(100) < 25)
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+ else
+ {
+ place_trap(y, x);
+ }
+ }
+ else if (value < 30)
+ {
+ /* Monster and trap */
+ monster_level = dun_level + 5;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ place_trap(y, x);
+ }
+ else if (value < 40)
+ {
+ /* Monster or object */
+ if (rand_int(100) < 50)
+ {
+ monster_level = dun_level + 3;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ }
+ if (rand_int(100) < 50)
+ {
+ object_level = dun_level + 7;
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ object_level = dun_level;
+ }
+ }
+ else if (value < 50)
+ {
+ /* Trap */
+ place_trap(y, x);
+ }
+ else
+ {
+ /* Various Stuff */
+
+ /* 20% monster, 40% trap, 20% object, 20% blank space */
+ if (rand_int(100) < 20)
+ {
+ place_monster(y, x, TRUE, TRUE);
+ }
+ else if (rand_int(100) < 50)
+ {
+ place_trap(y, x);
+ }
+ else if (rand_int(100) < 50)
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+ }
+
+ }
+ }
+ }
+}
+
+
+/*
+ * Creates a random vault that looks like a collection of bubbles
+ *
+ * It works by getting a set of coordinates that represent the center of
+ * each bubble. The entire room is made by seeing which bubble center is
+ * closest. If two centers are equidistant then the square is a wall,
+ * otherwise it is a floor. The only exception is for squares really
+ * near a center, these are always floor.
+ * (It looks better than without this check.)
+ *
+ * Note: If two centers are on the same point then this algorithm will create a
+ * blank bubble filled with walls. - This is prevented from happening.
+ */
+
+#define BUBBLENUM 10 /* number of bubbles */
+
+static void build_bubble_vault(int x0, int y0, int xsize, int ysize)
+{
+ /* array of center points of bubbles */
+ coord center[BUBBLENUM];
+
+ int i, j, k, x = 0, y = 0;
+ u16b min1, min2, temp;
+ bool_ done;
+
+ /* Offset from center to top left hand corner */
+ int xhsize = xsize / 2;
+ int yhsize = ysize / 2;
+
+ if (cheat_room) msg_print("Bubble Vault");
+
+ /* Allocate center of bubbles */
+ center[0].x = randint(xsize - 3) + 1;
+ center[0].y = randint(ysize - 3) + 1;
+
+ for (i = 1; i < BUBBLENUM; i++)
+ {
+ done = FALSE;
+
+ /* Get center and check to see if it is unique */
+ for (k = 0; !done && (k < 2000); k++)
+ {
+ done = TRUE;
+
+ x = randint(xsize - 3) + 1;
+ y = randint(ysize - 3) + 1;
+
+ for (j = 0; j < i; j++)
+ {
+ /* Rough test to see if there is an overlap */
+ if ((x == center[j].x) || (y == center[j].y)) done = FALSE;
+ }
+ }
+
+ /* Too many failures */
+ if (k >= 2000) return;
+
+ center[i].x = x;
+ center[i].y = y;
+ }
+
+ build_rectangle(y0 - yhsize, x0 - xhsize,
+ y0 - yhsize + ysize - 1, x0 - xhsize + xsize - 1,
+ feat_wall_outer, CAVE_ROOM | CAVE_ICKY);
+
+ /* Fill in middle with bubbles */
+ for (x = 1; x < xsize - 1; x++)
+ {
+ for (y = 1; y < ysize - 1; y++)
+ {
+ cave_type *c_ptr;
+
+ /* Get distances to two closest centers */
+
+ /* Initialise */
+ min1 = distance(x, y, center[0].x, center[0].y);
+ min2 = distance(x, y, center[1].x, center[1].y);
+
+ if (min1 > min2)
+ {
+ /* Swap if in wrong order */
+ temp = min1;
+ min1 = min2;
+ min2 = temp;
+ }
+
+ /* Scan the rest */
+ for (i = 2; i < BUBBLENUM; i++)
+ {
+ temp = distance(x, y, center[i].x, center[i].y);
+
+ if (temp < min1)
+ {
+ /* Smallest */
+ min2 = min1;
+ min1 = temp;
+ }
+ else if (temp < min2)
+ {
+ /* Second smallest */
+ min2 = temp;
+ }
+ }
+
+ /* Access the grid */
+ c_ptr = &cave[y + y0 - yhsize][x + x0 - xhsize];
+
+ /*
+ * Boundary at midpoint+ not at inner region of bubble
+ *
+ * SCSCSC: was feat_wall_outer
+ */
+ if (((min2 - min1) <= 2) && (!(min1 < 3)))
+ {
+ place_filler(y + y0 - yhsize, x + x0 - xhsize);
+ }
+
+ /* Middle of a bubble */
+ else
+ {
+ place_floor(y + y0 - yhsize, x + x0 - xhsize);
+ }
+
+ /* Clean up rest of flags */
+ c_ptr->info |= (CAVE_ROOM | CAVE_ICKY);
+ }
+ }
+
+ /* Try to add some random doors */
+ for (i = 0; i < 500; i++)
+ {
+ x = randint(xsize - 3) - xhsize + x0 + 1;
+ y = randint(ysize - 3) - yhsize + y0 + 1;
+ add_door(x, y);
+ }
+
+ /* Fill with monsters and treasure, low difficulty */
+ fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 2,
+ y0 - yhsize + 1, y0 - yhsize + ysize - 2, randint(5));
+}
+
+
+/*
+ * Convert FEAT_WALL_EXTRA (used by random vaults) to normal dungeon wall
+ */
+static void convert_extra(int y1, int x1, int y2, int x2)
+{
+ int x, y;
+
+ for (x = x1; x <= x2; x++)
+ {
+ for (y = y1; y <= y2; y++)
+ {
+ if (cave[y][x].feat == FEAT_WALL_OUTER)
+ {
+ place_filler(y, x);
+ }
+ }
+ }
+}
+
+
+/*
+ * Overlay a rectangular room given its bounds
+ *
+ * This routine is used by build_room_vault (hence FEAT_WALL_OUTER)
+ * The area inside the walls is not touched: only granite is removed
+ * and normal walls stay
+ */
+static void build_room(int x1, int x2, int y1, int y2)
+{
+ int x, y, xsize, ysize, temp;
+
+ /* Check if rectangle has no width */
+ if ((x1 == x2) || (y1 == y2)) return;
+
+ /* initialize */
+ if (x1 > x2)
+ {
+ /* Swap boundaries if in wrong order */
+ temp = x1;
+ x1 = x2;
+ x2 = temp;
+ }
+
+ if (y1 > y2)
+ {
+ /* Swap boundaries if in wrong order */
+ temp = y1;
+ y1 = y2;
+ y2 = temp;
+ }
+
+ /* Get total widths */
+ xsize = x2 - x1;
+ ysize = y2 - y1;
+
+ build_rectangle(y1, x1, y2, x2, feat_wall_outer, CAVE_ROOM | CAVE_ICKY);
+
+ /* Middle */
+ for (x = 1; x < xsize; x++)
+ {
+ for (y = 1; y < ysize; y++)
+ {
+ if (cave[y1 + y][x1 + x].feat == FEAT_WALL_OUTER)
+ {
+ /* Clear the untouched region */
+ place_floor(y1 + y, x1 + x);
+ cave[y1 + y][x1 + x].info |= (CAVE_ROOM | CAVE_ICKY);
+ }
+ else
+ {
+ /* Make it a room -- but don't touch */
+ cave[y1 + y][x1 + x].info |= (CAVE_ROOM | CAVE_ICKY);
+ }
+ }
+ }
+}
+
+
+/*
+ * Create a random vault that looks like a collection of overlapping rooms
+ */
+static void build_room_vault(int x0, int y0, int xsize, int ysize)
+{
+ int i, x1, x2, y1, y2, xhsize, yhsize;
+
+ /* Get offset from center */
+ xhsize = xsize / 2;
+ yhsize = ysize / 2;
+
+ if (cheat_room) msg_print("Room Vault");
+
+ /* Fill area so don't get problems with arena levels */
+ for (x1 = 0; x1 <= xsize; x1++)
+ {
+ int x = x0 - xhsize + x1;
+
+ for (y1 = 0; y1 <= ysize; y1++)
+ {
+ int y = y0 - yhsize + y1;
+
+ cave_set_feat(y, x, FEAT_WALL_OUTER);
+ cave[y][x].info &= ~(CAVE_ICKY);
+ }
+ }
+
+ /* Add ten random rooms */
+ for (i = 0; i < 10; i++)
+ {
+ x1 = randint(xhsize) * 2 + x0 - xhsize;
+ x2 = randint(xhsize) * 2 + x0 - xhsize;
+ y1 = randint(yhsize) * 2 + y0 - yhsize;
+ y2 = randint(yhsize) * 2 + y0 - yhsize;
+
+ build_room(x1, x2, y1, y2);
+ }
+
+ convert_extra(y0 - yhsize, x0 - xhsize, y0 - yhsize + ysize,
+ x0 - xhsize + xsize);
+
+ /* Add some random doors */
+ for (i = 0; i < 500; i++)
+ {
+ x1 = randint(xsize - 2) - xhsize + x0 + 1;
+ y1 = randint(ysize - 2) - yhsize + y0 + 1;
+ add_door(x1, y1);
+ }
+
+ /* Fill with monsters and treasure, high difficulty */
+ fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 1,
+ y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint(5) + 5);
+}
+
+
+/*
+ * Create a random vault out of a fractal cave
+ */
+static void build_cave_vault(int x0, int y0, int xsiz, int ysiz)
+{
+ int grd, roug, cutoff, xhsize, yhsize, xsize, ysize, x, y;
+ bool_ done, light, room;
+
+ /* Round to make sizes even */
+ xhsize = xsiz / 2;
+ yhsize = ysiz / 2;
+ xsize = xhsize * 2;
+ ysize = yhsize * 2;
+
+ if (cheat_room) msg_print("Cave Vault");
+
+ light = done = FALSE;
+ room = TRUE;
+
+ while (!done)
+ {
+ /* Testing values for these parameters feel free to adjust */
+ grd = 1 << rand_int(4);
+
+ /* Want average of about 16 */
+ roug = randint(8) * randint(4);
+
+ /* About size/2 */
+ cutoff = randint(xsize / 4) + randint(ysize / 4) +
+ randint(xsize / 4) + randint(ysize / 4);
+
+ /* Make it */
+ generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff);
+
+ /* Convert to normal format + clean up */
+ done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room);
+ }
+
+ /* Set icky flag because is a vault */
+ for (x = 0; x <= xsize; x++)
+ {
+ for (y = 0; y <= ysize; y++)
+ {
+ cave[y0 - yhsize + y][x0 - xhsize + x].info |= CAVE_ICKY;
+ }
+ }
+
+ /* Fill with monsters and treasure, low difficulty */
+ fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 1,
+ y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint(5));
+}
+
+
+/*
+ * Maze vault -- rectangular labyrinthine rooms
+ *
+ * maze vault uses two routines:
+ * r_visit - a recursive routine that builds the labyrinth
+ * build_maze_vault - a driver routine that calls r_visit and adds
+ * monsters, traps and treasure
+ *
+ * The labyrinth is built by creating a spanning tree of a graph.
+ * The graph vertices are at
+ * (x, y) = (2j + x1, 2k + y1) j = 0,...,m-1 k = 0,...,n-1
+ * and the edges are the vertical and horizontal nearest neighbors.
+ *
+ * The spanning tree is created by performing a suitably randomized
+ * depth-first traversal of the graph. The only adjustable parameter
+ * is the rand_int(3) below; it governs the relative density of
+ * twists and turns in the labyrinth: smaller number, more twists.
+ */
+static void r_visit(int y1, int x1, int y2, int x2,
+ int node, int dir, int *visited)
+{
+ int i, j, m, n, temp, x, y, adj[4];
+
+ /* Dimensions of vertex array */
+ m = (x2 - x1) / 2 + 1;
+ n = (y2 - y1) / 2 + 1;
+
+ /* Mark node visited and set it to a floor */
+ visited[node] = 1;
+ x = 2 * (node % m) + x1;
+ y = 2 * (node / m) + y1;
+ place_floor(y, x);
+
+ /* Setup order of adjacent node visits */
+ if (rand_int(3) == 0)
+ {
+ /* Pick a random ordering */
+ for (i = 0; i < 4; i++)
+ {
+ adj[i] = i;
+ }
+ for (i = 0; i < 4; i++)
+ {
+ j = rand_int(4);
+ temp = adj[i];
+ adj[i] = adj[j];
+ adj[j] = temp;
+ }
+ dir = adj[0];
+ }
+ else
+ {
+ /* Pick a random ordering with dir first */
+ adj[0] = dir;
+ for (i = 1; i < 4; i++)
+ {
+ adj[i] = i;
+ }
+ for (i = 1; i < 4; i++)
+ {
+ j = 1 + rand_int(3);
+ temp = adj[i];
+ adj[i] = adj[j];
+ adj[j] = temp;
+ }
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ switch (adj[i])
+ {
+ /* (0,+) - check for bottom boundary */
+ case 0:
+ {
+ if ((node / m < n - 1) && (visited[node + m] == 0))
+ {
+ place_floor(y + 1, x);
+ r_visit(y1, x1, y2, x2, node + m, dir, visited);
+ }
+ break;
+ }
+
+ /* (0,-) - check for top boundary */
+ case 1:
+ {
+ if ((node / m > 0) && (visited[node - m] == 0))
+ {
+ place_floor(y - 1, x);
+ r_visit(y1, x1, y2, x2, node - m, dir, visited);
+ }
+ break;
+ }
+
+ /* (+,0) - check for right boundary */
+ case 2:
+ {
+ if ((node % m < m - 1) && (visited[node + 1] == 0))
+ {
+ place_floor(y, x + 1);
+ r_visit(y1, x1, y2, x2, node + 1, dir, visited);
+ }
+ break;
+ }
+
+ /* (-,0) - check for left boundary */
+ case 3:
+ {
+ if ((node % m > 0) && (visited[node - 1] == 0))
+ {
+ place_floor(y, x - 1);
+ r_visit(y1, x1, y2, x2, node - 1, dir, visited);
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+static void build_maze_vault(int x0, int y0, int xsize, int ysize)
+{
+ int y, x, dy, dx;
+ int y1, x1, y2, x2;
+ int i, m, n, num_vertices, *visited;
+ bool_ light;
+ cave_type *c_ptr;
+
+
+ if (cheat_room) msg_print("Maze Vault");
+
+ /* Choose lite or dark */
+ light = (dun_level <= randint(25));
+
+ /* Pick a random room size - randomized by calling routine */
+ dy = ysize / 2 - 1;
+ dx = xsize / 2 - 1;
+
+ y1 = y0 - dy;
+ x1 = x0 - dx;
+ y2 = y0 + dy;
+ x2 = x0 + dx;
+
+ /* Generate the room */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ c_ptr = &cave[y][x];
+
+ c_ptr->info |= (CAVE_ROOM | CAVE_ICKY);
+
+ if ((x == x1 - 1) || (x == x2 + 1) ||
+ (y == y1 - 1) || (y == y2 + 1))
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+ else
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ }
+ }
+
+ /* Dimensions of vertex array */
+ m = dx + 1;
+ n = dy + 1;
+ num_vertices = m * n;
+
+ /* Allocate an array for visited vertices */
+ C_MAKE(visited, num_vertices, int);
+
+ /* Initialise array of visited vertices */
+ for (i = 0; i < num_vertices; i++)
+ {
+ visited[i] = 0;
+ }
+
+ /* Traverse the graph to create a spaning tree, pick a random root */
+ r_visit(y1, x1, y2, x2, rand_int(num_vertices), 0, visited);
+
+ /* Fill with monsters and treasure, low difficulty */
+ fill_treasure(x1, x2, y1, y2, randint(5));
+
+ /* Free the array for visited vertices */
+ C_FREE(visited, num_vertices, int);
+}
+
+
+/*
+ * Build a "mini" checkerboard vault
+ *
+ * This is done by making a permanent wall maze and setting
+ * the diagonal sqaures of the checker board to be granite.
+ * The vault has two entrances on opposite sides to guarantee
+ * a way to get in even if the vault abuts a side of the dungeon.
+ */
+static void build_mini_c_vault(int x0, int y0, int xsize, int ysize)
+{
+ int dy, dx;
+ int y1, x1, y2, x2, y, x, total;
+ int i, m, n, num_vertices;
+ int *visited;
+
+ if (cheat_room) msg_print("Mini Checker Board Vault");
+
+ /* Pick a random room size */
+ dy = ysize / 2 - 1;
+ dx = xsize / 2 - 1;
+
+ y1 = y0 - dy;
+ x1 = x0 - dx;
+ y2 = y0 + dy;
+ x2 = x0 + dx;
+
+
+ /* Generate the room */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ cave[y][x].info |= (CAVE_ROOM | CAVE_ICKY);
+
+ /* Permanent walls */
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+ }
+ }
+
+
+ /* Dimensions of vertex array */
+ m = dx + 1;
+ n = dy + 1;
+ num_vertices = m * n;
+
+ /* Allocate an array for visited vertices */
+ C_MAKE(visited, num_vertices, int);
+
+ /* Initialise array of visited vertices */
+ for (i = 0; i < num_vertices; i++)
+ {
+ visited[i] = 0;
+ }
+
+ /* Traverse the graph to create a spannng tree, pick a random root */
+ r_visit(y1, x1, y2, x2, rand_int(num_vertices), 0, visited);
+
+ /* Make it look like a checker board vault */
+ for (x = x1; x <= x2; x++)
+ {
+ for (y = y1; y <= y2; y++)
+ {
+ total = x - x1 + y - y1;
+
+ /* If total is odd and is a floor, then make a wall */
+ if ((total % 2 == 1) && get_is_floor(x, y))
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Make a couple of entrances */
+ if (rand_int(2) == 0)
+ {
+ /* Left and right */
+ y = randint(dy) + dy / 2;
+ cave_set_feat(y1 + y, x1 - 1, feat_wall_outer);
+ cave_set_feat(y1 + y, x2 + 1, feat_wall_outer);
+ }
+ else
+ {
+ /* Top and bottom */
+ x = randint(dx) + dx / 2;
+ cave_set_feat(y1 - 1, x1 + x, feat_wall_outer);
+ cave_set_feat(y2 + 1, x1 + x, feat_wall_outer);
+ }
+
+ /* Fill with monsters and treasure, highest difficulty */
+ fill_treasure(x1, x2, y1, y2, 10);
+
+ /* Free the array for visited vertices */
+ C_FREE(visited, num_vertices, int);
+}
+
+
+/*
+ * Build a town/ castle by using a recursive algorithm.
+ * Basically divide each region in a probalistic way to create
+ * smaller regions. When the regions get too small stop.
+ *
+ * The power variable is a measure of how well defended a region is.
+ * This alters the possible choices.
+ */
+static void build_recursive_room(int x1, int y1, int x2, int y2, int power)
+{
+ int xsize, ysize;
+ int x, y;
+ int choice;
+
+ /* Temp variables */
+ int t1, t2, t3, t4;
+
+ xsize = x2 - x1;
+ ysize = y2 - y1;
+
+ if ((power < 3) && (xsize > 12) && (ysize > 12))
+ {
+ /* Need outside wall +keep */
+ choice = 1;
+ }
+ else
+ {
+ if (power < 10)
+ {
+ /* Make rooms + subdivide */
+ if ((randint(10) > 2) && (xsize < 8) && (ysize < 8))
+ {
+ choice = 4;
+ }
+ else
+ {
+ choice = randint(2) + 1;
+ }
+ }
+ else
+ {
+ /* Mostly subdivide */
+ choice = randint(3) + 1;
+ }
+ }
+
+ /* Based on the choice made above, do something */
+ switch (choice)
+ {
+ /* Outer walls */
+ case 1:
+ {
+ /* Top and bottom */
+ for (x = x1; x <= x2; x++)
+ {
+ cave_set_feat(y1, x, feat_wall_outer);
+ cave_set_feat(y2, x, feat_wall_outer);
+ }
+
+ /* Left and right */
+ for (y = y1 + 1; y < y2; y++)
+ {
+ cave_set_feat(y, x1, feat_wall_outer);
+ cave_set_feat(y, x2, feat_wall_outer);
+ }
+
+ /* Make a couple of entrances */
+ if (rand_int(2) == 0)
+ {
+ /* Left and right */
+ y = randint(ysize) + y1;
+ place_floor(y, x1);
+ place_floor(y, x2);
+ }
+ else
+ {
+ /* Top and bottom */
+ x = randint(xsize) + x1;
+ place_floor(y1, x);
+ place_floor(y2, x);
+ }
+
+ /* Select size of keep */
+ t1 = randint(ysize / 3) + y1;
+ t2 = y2 - randint(ysize / 3);
+ t3 = randint(xsize / 3) + x1;
+ t4 = x2 - randint(xsize / 3);
+
+ /* Do outside areas */
+
+ /* Above and below keep */
+ build_recursive_room(x1 + 1, y1 + 1, x2 - 1, t1, power + 1);
+ build_recursive_room(x1 + 1, t2, x2 - 1, y2, power + 1);
+
+ /* Left and right of keep */
+ build_recursive_room(x1 + 1, t1 + 1, t3, t2 - 1, power + 3);
+ build_recursive_room(t4, t1 + 1, x2 - 1, t2 - 1, power + 3);
+
+ /* Make the keep itself: */
+ x1 = t3;
+ x2 = t4;
+ y1 = t1;
+ y2 = t2;
+ xsize = x2 - x1;
+ ysize = y2 - y1;
+ power += 2;
+
+ /* Fall through */
+ }
+
+ /* Try to build a room */
+ case 4:
+ {
+ if ((xsize < 3) || (ysize < 3))
+ {
+ for (y = y1; y < y2; y++)
+ {
+ for (x = x1; x < x2; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+
+ /* Too small */
+ return;
+ }
+
+ /* Make outside walls */
+
+ /* Top and bottom */
+ for (x = x1 + 1; x <= x2 - 1; x++)
+ {
+ cave_set_feat(y1 + 1, x, feat_wall_inner);
+ cave_set_feat(y2 - 1, x, feat_wall_inner);
+ }
+
+ /* Left and right */
+ for (y = y1 + 1; y <= y2 - 1; y++)
+ {
+ cave_set_feat(y, x1 + 1, feat_wall_inner);
+ cave_set_feat(y, x2 - 1, feat_wall_inner);
+ }
+
+ /* Make a door */
+ y = randint(ysize - 3) + y1 + 1;
+
+ if (rand_int(2) == 0)
+ {
+ /* Left */
+ place_floor(y, x1 + 1);
+ }
+ else
+ {
+ /* Right */
+ place_floor(y, x2 - 1);
+ }
+
+ /* Build the room */
+ build_recursive_room(x1 + 2, y1 + 2, x2 - 2, y2 - 2, power + 3);
+
+ break;
+ }
+
+ /* Try and divide vertically */
+ case 2:
+ {
+ if (xsize < 3)
+ {
+ /* Too small */
+ for (y = y1; y < y2; y++)
+ {
+ for (x = x1; x < x2; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ return;
+ }
+
+ t1 = randint(xsize - 2) + x1 + 1;
+ build_recursive_room(x1, y1, t1, y2, power - 2);
+ build_recursive_room(t1 + 1, y1, x2, y2, power - 2);
+
+ break;
+ }
+
+ /* Try and divide horizontally */
+ case 3:
+ {
+ if (ysize < 3)
+ {
+ /* Too small */
+ for (y = y1; y < y2; y++)
+ {
+ for (x = x1; x < x2; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ return;
+ }
+
+ t1 = randint(ysize - 2) + y1 + 1;
+ build_recursive_room(x1, y1, x2, t1, power - 2);
+ build_recursive_room(x1, t1 + 1, x2, y2, power - 2);
+
+ break;
+ }
+ }
+}
+
+
+/*
+ * Build a castle
+ *
+ * Clear the region and call the recursive room routine.
+ *
+ * This makes a vault that looks like a castle or city in the dungeon.
+ */
+static void build_castle_vault(int x0, int y0, int xsize, int ysize)
+{
+ int dy, dx;
+ int y1, x1, y2, x2;
+ int y, x;
+
+ /* Pick a random room size */
+ dy = ysize / 2 - 1;
+ dx = xsize / 2 - 1;
+
+ y1 = y0 - dy;
+ x1 = x0 - dx;
+ y2 = y0 + dy;
+ x2 = x0 + dx;
+
+ if (cheat_room) msg_print("Castle Vault");
+
+ /* Generate the room */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ cave[y][x].info |= (CAVE_ROOM | CAVE_ICKY);
+
+ /* Make everything a floor */
+ place_floor(y, x);
+ }
+ }
+
+ /* Make the castle */
+ build_recursive_room(x1, y1, x2, y2, randint(5));
+
+ /* Fill with monsters and treasure, low difficulty */
+ fill_treasure(x1, x2, y1, y2, randint(3));
+}
+
+
+/*
+ * Add outer wall to a floored region
+ *
+ * Note: no range checking is done so must be inside dungeon
+ * This routine also stomps on doors
+ */
+static void add_outer_wall(int x, int y, int light, int x1, int y1,
+ int x2, int y2)
+{
+ int i, j;
+
+ if (!in_bounds(y, x)) return;
+
+ /*
+ * Hack -- Check to see if square has been visited before
+ * if so, then exit (use room flag to do this)
+ */
+ if (cave[y][x].info & CAVE_ROOM) return;
+
+ /* Set room flag */
+ cave[y][x].info |= (CAVE_ROOM);
+
+ if (get_is_floor(x, y))
+ {
+ for (i = -1; i <= 1; i++)
+ {
+ for (j = -1; j <= 1; j++)
+ {
+ if ((x + i >= x1) && (x + i <= x2) &&
+ (y + j >= y1) && (y + j <= y2))
+ {
+ add_outer_wall(x + i, y + j, light, x1, y1, x2, y2);
+ if (light) cave[y][x].info |= CAVE_GLOW;
+ }
+ }
+ }
+ }
+
+ /* Set bounding walls */
+ else if (cave[y][x].feat == FEAT_WALL_EXTRA)
+ {
+ cave[y][x].feat = feat_wall_outer;
+ if (light == TRUE) cave[y][x].info |= CAVE_GLOW;
+ }
+
+ /* Set bounding walls */
+ else if (cave[y][x].feat == FEAT_PERM_OUTER)
+ {
+ if (light == TRUE) cave[y][x].info |= CAVE_GLOW;
+ }
+}
+
+
+/*
+ * Hacked distance formula - gives the 'wrong' answer
+ *
+ * Used to build crypts
+ */
+static int dist2(int x1, int y1, int x2, int y2,
+ int h1, int h2, int h3, int h4)
+{
+ int dx, dy;
+ dx = abs(x2 - x1);
+ dy = abs(y2 - y1);
+
+ /*
+ * Basically this works by taking the normal pythagorean formula
+ * and using an expansion to express this in a way without the
+ * square root. This approximate formula is then perturbed to give
+ * the distorted results. (I found this by making a mistake when I was
+ * trying to fix the circular rooms.)
+ */
+
+ /* h1-h4 are constants that describe the metric */
+ if (dx >= 2 * dy) return (dx + (dy * h1) / h2);
+ if (dy >= 2 * dx) return (dy + (dx * h1) / h2);
+
+ /* 128/181 is approx. 1/sqrt(2) */
+ return (((dx + dy) * 128) / 181 +
+ (dx * dx / (dy * h3) + dy * dy / (dx * h3)) * h4);
+}
+
+
+/*
+ * Build target vault
+ *
+ * This is made by two concentric "crypts" with perpendicular
+ * walls creating the cross-hairs.
+ */
+static void build_target_vault(int x0, int y0, int xsize, int ysize)
+{
+ int rad, x, y;
+
+ int h1, h2, h3, h4;
+
+
+ /* Make a random metric */
+ h1 = randint(32) - 16;
+ h2 = randint(16);
+ h3 = randint(32);
+ h4 = randint(32) - 16;
+
+ if (cheat_room) msg_print("Target Vault");
+
+ /* Work out outer radius */
+ if (xsize > ysize)
+ {
+ rad = ysize / 2;
+ }
+ else
+ {
+ rad = xsize / 2;
+ }
+
+ /* Make floor */
+ for (x = x0 - rad; x <= x0 + rad; x++)
+ {
+ for (y = y0 - rad; y <= y0 + rad; y++)
+ {
+ cave_type *c_ptr;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Clear room flag */
+ c_ptr->info &= ~(CAVE_ROOM);
+
+ /* Grids in vaults are required to be "icky" */
+ c_ptr->info |= (CAVE_ICKY);
+
+ /* Inside -- floor */
+ if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1)
+ {
+ place_floor(y, x);
+ }
+
+ /* Outside -- make it granite so that arena works */
+ else
+ {
+ c_ptr->feat = FEAT_WALL_EXTRA;
+ }
+
+ /* Proper boundary for arena */
+ if (((y + rad) == y0) || ((y - rad) == y0) ||
+ ((x + rad) == x0) || ((x - rad) == x0))
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+ }
+ }
+
+ /* Find visible outer walls and set to be FEAT_OUTER */
+ add_outer_wall(x0, y0, FALSE, x0 - rad - 1, y0 - rad - 1,
+ x0 + rad + 1, y0 + rad + 1);
+
+ /* Add inner wall */
+ for (x = x0 - rad / 2; x <= x0 + rad / 2; x++)
+ {
+ for (y = y0 - rad / 2; y <= y0 + rad / 2; y++)
+ {
+ if (dist2(y0, x0, y, x, h1, h2, h3, h4) == rad / 2)
+ {
+ /* Make an internal wall */
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Add perpendicular walls */
+ for (x = x0 - rad; x <= x0 + rad; x++)
+ {
+ cave_set_feat(y0, x, feat_wall_inner);
+ }
+
+ for (y = y0 - rad; y <= y0 + rad; y++)
+ {
+ cave_set_feat(y, x0, feat_wall_inner);
+ }
+
+ /* Make inner vault */
+ for (y = y0 - 1; y <= y0 + 1; y++)
+ {
+ cave_set_feat(y, x0 - 1, feat_wall_inner);
+ cave_set_feat(y, x0 + 1, feat_wall_inner);
+ }
+ for (x = x0 - 1; x <= x0 + 1; x++)
+ {
+ cave_set_feat(y0 - 1, x, feat_wall_inner);
+ cave_set_feat(y0 + 1, x, feat_wall_inner);
+ }
+
+ place_floor(y0, x0);
+
+
+ /*
+ * Add doors to vault
+ *
+ * Get two distances so can place doors relative to centre
+ */
+ x = (rad - 2) / 4 + 1;
+ y = rad / 2 + x;
+
+ add_door(x0 + x, y0);
+ add_door(x0 + y, y0);
+ add_door(x0 - x, y0);
+ add_door(x0 - y, y0);
+ add_door(x0, y0 + x);
+ add_door(x0, y0 + y);
+ add_door(x0, y0 - x);
+ add_door(x0, y0 - y);
+
+ /* Fill with stuff - medium difficulty */
+ fill_treasure(x0 - rad, x0 + rad, y0 - rad, y0 + rad, randint(3) + 3);
+}
+
+
+/*
+ * Random vaults
+ */
+static void build_type11(int by0, int bx0)
+{
+ int y0, x0, xsize, ysize, vtype;
+
+ /* Get size -- gig enough to look good, small enough to be fairly common */
+ xsize = randint(22) + 22;
+ ysize = randint(11) + 11;
+
+ /* Allocate in room_map. If will not fit, exit */
+ if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &x0, &y0)) return;
+
+ /*
+ * Boost the rating -- Higher than lesser vaults and lower than
+ * greater vaults
+ */
+ rating += 10;
+
+ /* (Sometimes) Cause a special feeling */
+ if ((dun_level <= 50) ||
+ (randint((dun_level - 40) * (dun_level - 40) + 1) < 400))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Select type of vault */
+ vtype = randint(8);
+
+ switch (vtype)
+ {
+ /* Build an appropriate room */
+ case 1:
+ {
+ build_bubble_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 2:
+ {
+ build_room_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 3:
+ {
+ build_cave_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 4:
+ {
+ build_maze_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 5:
+ {
+ build_mini_c_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 6:
+ {
+ build_castle_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 7:
+ {
+ build_target_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ /* I know how to add a few more... give me some time. */
+
+ /* Paranoia */
+ default:
+ {
+ return;
+ }
+ }
+}
+
+/*
+ * Crypt room generation from Z 2.5.1
+ */
+
+/*
+ * Build crypt room.
+ * For every grid in the possible square, check the (fake) distance.
+ * If it's less than the radius, make it a room square.
+ *
+ * When done fill from the inside to find the walls,
+ */
+static void build_type12(int by0, int bx0)
+{
+ int light, rad, x, y, x0, y0;
+ bool_ emptyflag = TRUE;
+ int h1, h2, h3, h4;
+
+ /* Make a random metric */
+ h1 = randint(32) - 16;
+ h2 = randint(16);
+ h3 = randint(32);
+ h4 = randint(32) - 16;
+
+ /* Occasional light */
+ light = (randint(dun_level) <= 5) ? TRUE : FALSE;
+
+ rad = randint(9);
+
+ /* Allocate in room_map. If will not fit, exit */
+ if (!room_alloc(rad * 2 + 3, rad * 2 + 3, FALSE, by0, bx0, &x0, &y0)) return;
+
+ /* Make floor */
+ for (x = x0 - rad; x <= x0 + rad; x++)
+ {
+ for (y = y0 - rad; y <= y0 + rad; y++)
+ {
+ /* Clear room flag */
+ cave[y][x].info &= ~(CAVE_ROOM);
+
+ /* Inside -- floor */
+ if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1)
+ {
+ place_floor(y, x);
+ }
+ else if (distance(y0, x0, y, x) < 3)
+ {
+ place_floor(y, x);
+ }
+
+ /* Outside -- make it granite so that arena works */
+ else
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+
+ /* Proper boundary for arena */
+ if (((y + rad) == y0) || ((y - rad) == y0) ||
+ ((x + rad) == x0) || ((x - rad) == x0))
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+ }
+ }
+
+ /* Find visible outer walls and set to be FEAT_OUTER */
+ add_outer_wall(x0, y0, light, x0 - rad - 1, y0 - rad - 1,
+ x0 + rad + 1, y0 + rad + 1);
+
+ /* Check to see if there is room for an inner vault */
+ for (x = x0 - 2; x <= x0 + 2; x++)
+ {
+ for (y = y0 - 2; y <= y0 + 2; y++)
+ {
+ if (!get_is_floor(x, y))
+ {
+ /* Wall in the way */
+ emptyflag = FALSE;
+ }
+ }
+ }
+
+ if (emptyflag && (rand_int(2) == 0))
+ {
+ /* Build the vault */
+ build_small_room(x0, y0);
+
+ /* Place a treasure in the vault */
+ place_object(y0, x0, FALSE, FALSE, OBJ_FOUND_FLOOR);
+
+ /* Let's guard the treasure well */
+ vault_monsters(y0, x0, rand_int(2) + 3);
+
+ /* Traps naturally */
+ vault_traps(y0, x0, 4, 4, rand_int(3) + 2);
+ }
+}
+
+
+/*
+ * Constructs a tunnel between two points
+ *
+ * This function must be called BEFORE any streamers are created,
+ * since we use the special "granite wall" sub-types to keep track
+ * of legal places for corridors to pierce rooms.
+ *
+ * We use "door_flag" to prevent excessive construction of doors
+ * along overlapping corridors.
+ *
+ * We queue the tunnel grids to prevent door creation along a corridor
+ * which intersects itself.
+ *
+ * We queue the wall piercing grids to prevent a corridor from leaving
+ * a room and then coming back in through the same entrance.
+ *
+ * We "pierce" grids which are "outer" walls of rooms, and when we
+ * do so, we change all adjacent "outer" walls of rooms into "solid"
+ * walls so that no two corridors may use adjacent grids for exits.
+ *
+ * The "solid" wall check prevents corridors from "chopping" the
+ * corners of rooms off, as well as "silly" door placement, and
+ * "excessively wide" room entrances.
+ *
+ * Useful "feat" values:
+ * FEAT_WALL_EXTRA -- granite walls
+ * FEAT_WALL_INNER -- inner room walls
+ * FEAT_WALL_OUTER -- outer room walls
+ * FEAT_WALL_SOLID -- solid room walls
+ * FEAT_PERM_EXTRA -- shop walls (perma)
+ * FEAT_PERM_INNER -- inner room walls (perma)
+ * FEAT_PERM_OUTER -- outer room walls (perma)
+ * FEAT_PERM_SOLID -- dungeon border (perma)
+ */
+static void build_tunnel(int row1, int col1, int row2, int col2, bool_ water)
+{
+ int i, y, x;
+ int tmp_row, tmp_col;
+ int row_dir, col_dir;
+ int start_row, start_col;
+ int main_loop_count = 0;
+
+ bool_ door_flag = FALSE;
+
+ cave_type *c_ptr;
+
+
+ /* Reset the arrays */
+ dun->tunn_n = 0;
+ dun->wall_n = 0;
+
+ /* Save the starting location */
+ start_row = row1;
+ start_col = col1;
+
+ /* Start out in the correct direction */
+ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
+
+ /* Keep going until done (or bored) */
+ while ((row1 != row2) || (col1 != col2))
+ {
+ /* Mega-Hack -- Paranoia -- prevent infinite loops */
+ if (main_loop_count++ > 2000) break;
+
+ /* Allow bends in the tunnel */
+ if (rand_int(100) < DUN_TUN_CHG)
+ {
+ /* Acquire the correct direction */
+ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
+
+ /* Random direction */
+ if (rand_int(100) < DUN_TUN_RND)
+ {
+ rand_dir(&row_dir, &col_dir);
+ }
+ }
+
+ /* Get the next location */
+ tmp_row = row1 + row_dir;
+ tmp_col = col1 + col_dir;
+
+
+ /* Extremely Important -- do not leave the dungeon */
+ while (!in_bounds(tmp_row, tmp_col))
+ {
+ /* Acquire the correct direction */
+ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
+
+ /* Random direction */
+ if (rand_int(100) < DUN_TUN_RND)
+ {
+ rand_dir(&row_dir, &col_dir);
+ }
+
+ /* Get the next location */
+ tmp_row = row1 + row_dir;
+ tmp_col = col1 + col_dir;
+ }
+
+
+ /* Access the location */
+ c_ptr = &cave[tmp_row][tmp_col];
+
+
+ /* Avoid the edge of the dungeon */
+ if (c_ptr->feat == FEAT_PERM_SOLID) continue;
+
+ /* Avoid the edge of vaults */
+ if (c_ptr->feat == FEAT_PERM_OUTER) continue;
+
+ /* Avoid "solid" granite walls */
+ if (c_ptr->feat == FEAT_WALL_SOLID) continue;
+
+ /*
+ * Pierce "outer" walls of rooms
+ * Cannot trust feat code any longer...
+ */
+ if ((c_ptr->feat == feat_wall_outer) &&
+ (c_ptr->info & CAVE_ROOM))
+ {
+ /* Acquire the "next" location */
+ y = tmp_row + row_dir;
+ x = tmp_col + col_dir;
+
+ /* Hack -- Avoid outer/solid permanent walls */
+ if (cave[y][x].feat == FEAT_PERM_SOLID) continue;
+ if (cave[y][x].feat == FEAT_PERM_OUTER) continue;
+
+ /* Hack -- Avoid outer/solid granite walls */
+ if ((cave[y][x].feat == feat_wall_outer) &&
+ (cave[y][x].info & CAVE_ROOM)) continue;
+ if (cave[y][x].feat == FEAT_WALL_SOLID) continue;
+
+ /* Accept this location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+
+ /* Save the wall location */
+ if (dun->wall_n < WALL_MAX)
+ {
+ dun->wall[dun->wall_n].y = row1;
+ dun->wall[dun->wall_n].x = col1;
+ dun->wall_n++;
+ }
+
+ /* Forbid re-entry near this piercing */
+ for (y = row1 - 1; y <= row1 + 1; y++)
+ {
+ for (x = col1 - 1; x <= col1 + 1; x++)
+ {
+ /* Convert adjacent "outer" walls as "solid" walls */
+ if ((cave[y][x].feat == feat_wall_outer) &&
+ (cave[y][x].info & CAVE_ROOM))
+ {
+ /* Change the wall to a "solid" wall */
+ /* Mega-Hack -- to be brought back later... */
+ cave_set_feat(y, x, FEAT_WALL_SOLID);
+ }
+ }
+ }
+ }
+
+ /* Travel quickly through rooms */
+ else if (c_ptr->info & (CAVE_ROOM))
+ {
+ /* Accept the location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+ }
+
+ /* Tunnel through all other walls */
+ else if ((c_ptr->feat == d_info[dungeon_type].fill_type1) ||
+ (c_ptr->feat == d_info[dungeon_type].fill_type2) ||
+ (c_ptr->feat == d_info[dungeon_type].fill_type3))
+ {
+ /* Accept this location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+
+ /* Save the tunnel location */
+ if (dun->tunn_n < TUNN_MAX)
+ {
+ dun->tunn[dun->tunn_n].y = row1;
+ dun->tunn[dun->tunn_n].x = col1;
+ dun->tunn_n++;
+ }
+
+ /* Allow door in next grid */
+ door_flag = FALSE;
+ }
+
+ /* Handle corridor intersections or overlaps */
+ else
+ {
+ /* Accept the location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+
+ /* Collect legal door locations */
+ if (!door_flag)
+ {
+ /* Save the door location */
+ if (dun->door_n < DOOR_MAX)
+ {
+ dun->door[dun->door_n].y = row1;
+ dun->door[dun->door_n].x = col1;
+ dun->door_n++;
+ }
+
+ /* No door in next grid */
+ door_flag = TRUE;
+ }
+
+ /* Hack -- allow pre-emptive tunnel termination */
+ if (rand_int(100) >= DUN_TUN_CON)
+ {
+ /* Distance between row1 and start_row */
+ tmp_row = row1 - start_row;
+ if (tmp_row < 0) tmp_row = ( -tmp_row);
+
+ /* Distance between col1 and start_col */
+ tmp_col = col1 - start_col;
+ if (tmp_col < 0) tmp_col = ( -tmp_col);
+
+ /* Terminate the tunnel */
+ if ((tmp_row > 10) || (tmp_col > 10)) break;
+ }
+ }
+ }
+
+
+ /* Turn the tunnel into corridor */
+ for (i = 0; i < dun->tunn_n; i++)
+ {
+ /* Access the grid */
+ y = dun->tunn[i].y;
+ x = dun->tunn[i].x;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Clear previous contents, add a floor */
+ if (!water)
+ {
+ place_floor(y, x);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_SHAL_WATER);
+ }
+ }
+
+
+ /* Apply the piercings that we found */
+ for (i = 0; i < dun->wall_n; i++)
+ {
+ /* Access the grid */
+ y = dun->wall[i].y;
+ x = dun->wall[i].x;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Clear previous contents, add up floor */
+ place_floor(y, x);
+
+ /* Occasional doorway */
+ if (!(dungeon_flags1 & DF1_NO_DOORS) &&
+ (rand_int(100) < DUN_TUN_PEN))
+ {
+ /* Place a random door */
+ place_random_door(y, x);
+ }
+ }
+}
+
+
+
+
+/*
+ * Count the number of "corridor" grids adjacent to the given grid.
+ *
+ * Note -- Assumes "in_bounds(y1, x1)"
+ *
+ * XXX XXX This routine currently only counts actual "empty floor"
+ * grids which are not in rooms. We might want to also count stairs,
+ * open doors, closed doors, etc.
+ */
+static int next_to_corr(int y1, int x1)
+{
+ int i, y, x, k = 0;
+
+ cave_type *c_ptr;
+
+ /* Scan adjacent grids */
+ for (i = 0; i < 4; i++)
+ {
+ /* Extract the location */
+ y = y1 + ddy_ddd[i];
+ x = x1 + ddx_ddd[i];
+
+ /* Skip non floors */
+ if (!cave_floor_bold(y, x)) continue;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Skip non "empty floor" grids */
+ if ((c_ptr->feat != d_info[dungeon_type].floor1) &&
+ (c_ptr->feat != d_info[dungeon_type].floor2) &&
+ (c_ptr->feat != d_info[dungeon_type].floor3))
+ {
+ continue;
+ }
+
+ /* Skip grids inside rooms */
+ if (c_ptr->info & (CAVE_ROOM)) continue;
+
+ /* Count these grids */
+ k++;
+ }
+
+ /* Return the number of corridors */
+ return (k);
+}
+
+
+/*
+ * Determine if the given location is "between" two walls,
+ * and "next to" two corridor spaces. XXX XXX XXX
+ *
+ * Assumes "in_bounds(y,x)"
+ */
+static bool_ possible_doorway(int y, int x)
+{
+ /* Count the adjacent corridors */
+ if (next_to_corr(y, x) >= 2)
+ {
+ /* Check Vertical */
+ if ((f_info[cave[y - 1][x].feat].flags1 & FF1_WALL) &&
+ (f_info[cave[y + 1][x].feat].flags1 & FF1_WALL))
+ {
+ return (TRUE);
+ }
+
+ /* Check Horizontal */
+ if ((f_info[cave[y][x - 1].feat].flags1 & FF1_WALL) &&
+ (f_info[cave[y][x + 1].feat].flags1 & FF1_WALL))
+ {
+ return (TRUE);
+ }
+ }
+
+ /* No doorway */
+ return (FALSE);
+}
+
+
+/*
+ * Places doors around y, x position
+ */
+static void try_doors(int y, int x)
+{
+ bool_ dir_ok[4];
+ int i, k, n;
+ int yy, xx;
+
+ /* Paranoia */
+ /* if (!in_bounds(y, x)) return; */
+
+ /* Some dungeons don't have doors at all */
+ if (dungeon_flags1 & (DF1_NO_DOORS)) return;
+
+ /* Reset tally */
+ n = 0;
+
+ /* Look four cardinal directions */
+ for (i = 0; i < 4; i++)
+ {
+ /* Assume NG */
+ dir_ok[i] = FALSE;
+
+ /* Access location */
+ yy = y + ddy_ddd[i];
+ xx = x + ddx_ddd[i];
+
+ /* Out of level boundary */
+ if (!in_bounds(yy, xx)) continue;
+
+ /* Ignore walls */
+ if (f_info[cave[yy][xx].feat].flags1 & (FF1_WALL)) continue;
+
+ /* Ignore room grids */
+ if (cave[yy][xx].info & (CAVE_ROOM)) continue;
+
+ /* Not a doorway */
+ if (!possible_doorway(yy, xx)) continue;
+
+ /* Accept the direction */
+ dir_ok[i] = TRUE;
+
+ /* Count good spots */
+ n++;
+ }
+
+ /* Use the traditional method 75% of time */
+ if (rand_int(100) < 75)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ /* Bad locations */
+ if (!dir_ok[i]) continue;
+
+ /* Place one of various kinds of doors */
+ if (rand_int(100) < DUN_TUN_JCT)
+ {
+ /* Access location */
+ yy = y + ddy_ddd[i];
+ xx = x + ddx_ddd[i];
+
+ /* Place a door */
+ place_random_door(yy, xx);
+ }
+ }
+ }
+
+ /* Use alternative method */
+ else
+ {
+ /* A crossroad */
+ if (n == 4)
+ {
+ /* Clear OK flags XXX */
+ for (i = 0; i < 4; i++) dir_ok[i] = FALSE;
+
+ /* Put one or two secret doors */
+ dir_ok[rand_int(4)] = TRUE;
+ dir_ok[rand_int(4)] = TRUE;
+ }
+
+ /* A T-shaped intersection or two possible doorways */
+ else if ((n == 3) || (n == 2))
+ {
+ /* Pick one random location from the list */
+ k = rand_int(n);
+
+ for (i = 0; i < 4; i++)
+ {
+ /* Reject all but k'th OK direction */
+ if (dir_ok[i] && (k-- != 0)) dir_ok[i] = FALSE;
+ }
+ }
+
+ /* Place secret door(s) */
+ for (i = 0; i < 4; i++)
+ {
+ /* Bad location */
+ if (!dir_ok[i]) continue;
+
+ /* Access location */
+ yy = y + ddy_ddd[i];
+ xx = x + ddx_ddd[i];
+
+ /* Place a secret door */
+ place_secret_door(yy, xx);
+ }
+ }
+}
+
+
+/*
+ * Attempt to build a room of the given type at the given block
+ *
+ * Note that we restrict the number of "crowded" rooms to reduce
+ * the chance of overflowing the monster list during level creation.
+ */
+static bool_ room_build(int y, int x, int typ)
+{
+ /* Restrict level */
+ if ((dun_level < roomdep[typ]) && !ironman_rooms) return (FALSE);
+
+ /* Restrict "crowded" rooms */
+ if (dun->crowded && ((typ == 5) || (typ == 6))) return (FALSE);
+
+ /* Build a room */
+ switch (typ)
+ {
+ /* Build an appropriate room */
+ case 12:
+ build_type12(y, x);
+ break;
+ case 11:
+ build_type11(y, x);
+ break;
+ case 10:
+ build_type10(y, x);
+ break;
+ case 9:
+ build_type9 (y, x);
+ break;
+ case 8:
+ build_type8 (y, x);
+ break;
+ case 7:
+ build_type7 (y, x);
+ break;
+ case 6:
+ build_type6 (y, x);
+ break;
+ case 5:
+ build_type5 (y, x);
+ break;
+ case 4:
+ build_type4 (y, x);
+ break;
+ case 3:
+ build_type3 (y, x);
+ break;
+ case 2:
+ build_type2 (y, x);
+ break;
+ case 1:
+ build_type1 (y, x);
+ break;
+
+ /* Paranoia */
+ default:
+ return (FALSE);
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+/*
+ * Set level boundaries
+ */
+void set_bounders(bool_ empty_level)
+{
+ int y, x;
+
+ /* Special boundary walls -- Top */
+ for (x = 0; x < cur_wid; x++)
+ {
+ /* XXX XXX */
+ if (empty_level) cave[0][x].mimic = fill_type[rand_int(100)];
+ else cave[0][x].mimic = cave[0][x].feat;
+
+ /* Clear previous contents, add "solid" perma-wall */
+ cave_set_feat(0, x, FEAT_PERM_SOLID);
+ }
+
+ /* Special boundary walls -- Bottom */
+ for (x = 0; x < cur_wid; x++)
+ {
+ /* XXX XXX */
+ if (empty_level) cave[cur_hgt - 1][x].mimic = fill_type[rand_int(100)];
+ else cave[cur_hgt - 1][x].mimic = cave[cur_hgt - 1][x].feat;
+
+ /* Clear previous contents, add "solid" perma-wall */
+ cave_set_feat(cur_hgt - 1, x, FEAT_PERM_SOLID);
+ }
+
+ /* Special boundary walls -- Left */
+ for (y = 1; y < cur_hgt - 1; y++)
+ {
+ /* XXX XXX */
+ if (empty_level) cave[y][0].mimic = fill_type[rand_int(100)];
+ else cave[y][0].mimic = cave[y][0].feat;
+
+ /* Clear previous contents, add "solid" perma-wall */
+ cave_set_feat(y, 0, FEAT_PERM_SOLID);
+ }
+
+ /* Special boundary walls -- Right */
+ for (y = 1; y < cur_hgt - 1; y++)
+ {
+ /* XXX XXX */
+ if (empty_level) cave[y][cur_wid - 1].mimic = fill_type[rand_int(100)];
+ else cave[y][cur_wid - 1].mimic = cave[y][cur_wid - 1].feat;
+
+ /* Clear previous contents, add "solid" perma-wall */
+ cave_set_feat(y, cur_wid - 1, FEAT_PERM_SOLID);
+ }
+}
+
+/* Needed to refill empty levels */
+static void fill_level(bool_ use_floor, byte smooth);
+
+/*
+ * Generate a normal dungeon level
+ */
+bool_ level_generate_dungeon()
+{
+ int i, k, y, x, y1, x1, branch = get_branch();
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ int max_vault_ok = 2;
+
+ bool_ destroyed = FALSE;
+ bool_ empty_level = FALSE;
+ bool_ cavern = FALSE;
+ s16b town_level = 0;
+
+ /* Is it a town level ? */
+ for (i = 0; i < TOWN_DUNGEON; i++)
+ {
+ if (d_ptr->t_level[i] == dun_level) town_level = d_ptr->t_idx[i];
+ }
+
+ /* Check for arena level */
+ if ((dungeon_flags1 & (DF1_EMPTY)) ||
+ (empty_levels && (rand_int(EMPTY_LEVEL) == 0)))
+ {
+ empty_level = TRUE;
+
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print("Arena level.");
+ }
+
+ /* Refill the level with floor tiles */
+ fill_level(empty_level, d_ptr->fill_method);
+ }
+
+ /* Possible cavern */
+ if ((dungeon_flags1 & DF1_CAVERN) && (rand_int(dun_level / 2) > DUN_CAVERN))
+ {
+ cavern = TRUE;
+
+ /* Make a large fractal cave in the middle of the dungeon */
+ if (cheat_room)
+ {
+ msg_print("Cavern on level.");
+ }
+
+ build_cavern();
+ }
+
+ /* Possible "destroyed" level */
+ if ((dun_level > 10) && (rand_int(DUN_DEST) == 0))
+ {
+ destroyed = TRUE;
+ }
+
+ /* Hack -- No destroyed "quest" levels */
+ if (is_quest(dun_level)) destroyed = FALSE;
+
+ /* Hack -- No destroyed "small" levels */
+ if ((cur_wid != MAX_WID) || (cur_hgt != MAX_HGT)) destroyed = FALSE;
+
+ /* Hack -- No destroyed levels */
+ if (dungeon_flags1 & DF1_NO_DESTROY) destroyed = FALSE;
+
+ /* Actual maximum number of rooms on this level */
+ dun->row_rooms = cur_hgt / BLOCK_HGT;
+ dun->col_rooms = cur_wid / BLOCK_WID;
+
+
+ /* Initialize the room table */
+ for (y = 0; y < dun->row_rooms; y++)
+ {
+ for (x = 0; x < dun->col_rooms; x++)
+ {
+ dun->room_map[y][x] = FALSE;
+ }
+ }
+
+ /* No "crowded" rooms yet */
+ dun->crowded = FALSE;
+
+ /* No rooms yet */
+ dun->cent_n = 0;
+
+ /* Pick a block for the room */
+ y = rand_int(dun->row_rooms);
+ x = rand_int(dun->col_rooms);
+
+ /* Align dungeon rooms */
+ if (dungeon_align)
+ {
+ /* Slide some rooms right */
+ if ((x % 3) == 0) x++;
+
+ /* Slide some rooms left */
+ if ((x % 3) == 2) x--;
+ }
+
+ /* Ugly */
+ process_hooks(HOOK_BUILD_ROOM1, "(d,d)", y, x);
+
+ /* Build some rooms */
+ for (i = 0; i < DUN_ROOMS; i++)
+ {
+ /* Pick a block for the room */
+ y = rand_int(dun->row_rooms);
+ x = rand_int(dun->col_rooms);
+
+ /* Align dungeon rooms */
+ if (dungeon_align)
+ {
+ /* Slide some rooms right */
+ if ((x % 3) == 0) x++;
+
+ /* Slide some rooms left */
+ if ((x % 3) == 2) x--;
+ }
+
+ /* Destroyed levels are boring */
+ if (destroyed)
+ {
+ /* The deeper you are, the more cavelike the rooms are */
+
+ /* no caves when cavern exists: they look bad */
+ k = randint(100);
+
+ if (!cavern && (k < dun_level))
+ {
+ /* Type 10 -- Fractal cave */
+ if (room_build(y, x, 10)) continue;
+ }
+ else
+ {
+ /* Attempt a "trivial" room */
+ if ((dungeon_flags1 & DF1_CIRCULAR_ROOMS) &&
+ room_build(y, x, 9))
+ {
+ continue;
+ }
+ else if (room_build(y, x, 1)) continue;
+ }
+
+ /* Never mind */
+ continue;
+ }
+
+ /* Attempt an "unusual" room -- no vaults on town levels */
+ if (!town_level &&
+ (ironman_rooms || (rand_int(DUN_UNUSUAL) < dun_level)))
+ {
+ /* Roll for room type */
+ k = (ironman_rooms ? 0 : rand_int(100));
+
+ /* Attempt a very unusual room */ /* test hack */
+ if (ironman_rooms || (rand_int(DUN_UNUSUAL) < dun_level))
+ {
+#ifdef FORCE_V_IDX
+ if (room_build(y, x, 8)) continue;
+#else
+/* Type 8 -- Greater vault (10%) */
+ if (k < 10)
+ {
+ if (max_vault_ok > 1)
+ {
+ if (room_build(y, x, 8)) continue;
+ }
+ else
+ {
+ if (cheat_room) msg_print("Refusing a greater vault.");
+ }
+ }
+
+ /* Type 7 -- Lesser vault (15%) */
+ if (k < 25)
+ {
+ if (max_vault_ok > 0)
+ {
+ if (room_build(y, x, 7)) continue;
+ }
+ else
+ {
+ if (cheat_room) msg_print("Refusing a lesser vault.");
+ }
+ }
+
+
+ /* Type 5 -- Monster nest (15%) */
+ if ((k < 40) && room_build(y, x, 5)) continue;
+
+ /* Type 6 -- Monster pit (15%) */
+ if ((k < 55) && room_build(y, x, 6)) continue;
+
+ /* Type 11 -- Random vault (5%) */
+ if ((k < 60) && room_build(y, x, 11)) continue;
+#endif
+ }
+
+ /* Type 4 -- Large room (25%) */
+ if ((k < 25) && room_build(y, x, 4)) continue;
+
+ /* Type 3 -- Cross room (20%) */
+ if ((k < 45) && room_build(y, x, 3)) continue;
+
+ /* Type 2 -- Overlapping (20%) */
+ if ((k < 65) && room_build(y, x, 2)) continue;
+
+ /* Type 10 -- Fractal cave (15%) */
+ if ((k < 80) && room_build(y, x, 10)) continue;
+
+ /* Type 9 -- Circular (10%) */
+ /* Hack - build standard rectangular rooms if needed */
+ if (k < 90)
+ {
+ if ((dungeon_flags1 & DF1_CIRCULAR_ROOMS) && room_build(y, x, 1)) continue;
+ else if (room_build(y, x, 9)) continue;
+ }
+
+ /* Type 12 -- Crypt (10%) */
+ if ((k < 100) && room_build(y, x, 12)) continue;
+ }
+
+ /* Attempt a trivial room */
+ if (dungeon_flags1 & DF1_CAVE)
+ {
+ if (room_build(y, x, 10)) continue;
+ }
+ else
+ {
+ if ((dungeon_flags1 & DF1_CIRCULAR_ROOMS) && room_build(y, x, 9)) continue;
+ else if (room_build(y, x, 1)) continue;
+ }
+ }
+
+ /* If no rooms are allocated... */
+ while (dun->cent_n == 0)
+ {
+ /* ...force the creation of a small rectangular room */
+ (void)room_build(0, 0, 1);
+ }
+
+ /* Hack -- Scramble the room order */
+ for (i = 0; i < dun->cent_n; i++)
+ {
+ int pick1 = rand_int(dun->cent_n);
+ int pick2 = rand_int(dun->cent_n);
+ y1 = dun->cent[pick1].y;
+ x1 = dun->cent[pick1].x;
+ dun->cent[pick1].y = dun->cent[pick2].y;
+ dun->cent[pick1].x = dun->cent[pick2].x;
+ dun->cent[pick2].y = y1;
+ dun->cent[pick2].x = x1;
+ }
+
+ /* Start with no tunnel doors */
+ dun->door_n = 0;
+
+ /* Hack -- connect the first room to the last room */
+ y = dun->cent[dun->cent_n - 1].y;
+ x = dun->cent[dun->cent_n - 1].x;
+
+ /* Connect all the rooms together */
+ for (i = 0; i < dun->cent_n; i++)
+ {
+ /* Connect the room to the previous room */
+ build_tunnel(dun->cent[i].y, dun->cent[i].x, y, x, FALSE);
+
+ /* Remember the "previous" room */
+ y = dun->cent[i].y;
+ x = dun->cent[i].x;
+ }
+
+ /* Mega-Hack -- Convert FEAT_WALL_SOLID back into outer walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ if (cave[y][x].feat == FEAT_WALL_SOLID)
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+ }
+ }
+
+ /* Place intersection doors */
+ for (i = 0; i < dun->door_n; i++)
+ {
+ /* Extract junction location */
+ y = dun->door[i].y;
+ x = dun->door[i].x;
+
+ /* Try placing doors */
+ try_doors(y, x);
+ }
+
+ if (strcmp(game_module, "ToME") == 0)
+ {
+ /* Hack -- Add some magma streamers */
+ if ((dungeon_type == DUNGEON_MORDOR) || (dungeon_type == DUNGEON_ANGBAND))
+ for (i = 0; i < DUN_STR_MAG; i++)
+ {
+ build_streamer(FEAT_MAGMA, DUN_STR_MC);
+ }
+
+ /* Hack -- Add some quartz streamers */
+ if ((dungeon_type == DUNGEON_MORDOR) || (dungeon_type == DUNGEON_ANGBAND))
+ for (i = 0; i < DUN_STR_QUA; i++)
+ {
+ build_streamer(FEAT_QUARTZ, DUN_STR_QC);
+ }
+ }
+
+ /* Add some sand streamers */
+ if ((dungeon_flags1 & DF1_SAND_VEIN) && !rand_int(4))
+ {
+ if ((cheat_room) || (p_ptr->precognition)) msg_print("Sand vein.");
+ build_streamer(FEAT_SANDWALL, DUN_STR_SC);
+ }
+
+ /* Destroy the level if necessary */
+ if (destroyed) destroy_level();
+
+ /* Create the town if needed */
+ if (town_level)
+ {
+ town_gen(town_level);
+ }
+
+ /* Hack -- Add some rivers if requested */
+ if ((dungeon_flags1 & DF1_WATER_RIVER) && !rand_int(4))
+ {
+ if (cheat_room || p_ptr->precognition) msg_print("River of water.");
+ add_river(FEAT_DEEP_WATER, FEAT_SHAL_WATER);
+ }
+ if ((dungeon_flags1 & DF1_LAVA_RIVER) && !rand_int(4))
+ {
+ if ((cheat_room) || (p_ptr->precognition)) msg_print("River of lava.");
+ add_river(FEAT_DEEP_LAVA, FEAT_SHAL_LAVA);
+ }
+
+ if (dungeon_flags1 & DF1_WATER_RIVERS)
+ {
+ int max = 3 + rand_int(2);
+ bool_ said = FALSE;
+
+ for (i = 0; i < max; i++)
+ {
+ if (rand_int(3) == 0)
+ {
+ add_river(FEAT_DEEP_WATER, FEAT_SHAL_WATER);
+ if (!said && ((cheat_room) || (p_ptr->precognition))) msg_print("Rivers of water.");
+ said = TRUE;
+ }
+ }
+ }
+
+ if (dungeon_flags1 & DF1_LAVA_RIVERS)
+ {
+ int max = 2 + rand_int(2);
+ bool_ said = FALSE;
+
+ for (i = 0; i < max; i++)
+ {
+ if (rand_int(3) == 0)
+ {
+ add_river(FEAT_DEEP_LAVA, FEAT_SHAL_LAVA);
+ if (!said && ((cheat_room) || (p_ptr->precognition))) msg_print("Rivers of lava.");
+ said = TRUE;
+ }
+ }
+ }
+
+ /* Add streamers of trees, water, or lava -KMW- */
+ if (!(dungeon_flags1 & DF1_NO_STREAMERS))
+ {
+ int num;
+
+ /*
+ * Flat levels (was: levels 1--2)
+ *
+ * Small trees (penetrate walls)
+ */
+ if ((dungeon_flags1 & DF1_FLAT) && (randint(20) > 15))
+ {
+ num = randint(DUN_STR_QUA);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_SMALL_TREES, 1);
+ }
+ }
+
+ /*
+ * Levels 1 -- 33 (was: 1 -- 19)
+ *
+ * Shallow water (preserve walls)
+ * Deep water (penetrate walls)
+ */
+ if (!(dun_level <= 33) && (randint(20) > 15))
+ {
+ num = randint(DUN_STR_QUA - 1);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_SHAL_WATER, 0);
+ }
+
+ if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_DEEP_WATER, 1);
+ }
+ }
+ }
+
+ /*
+ * Levels 34 -- (was: 20 --)
+ */
+ else if (dun_level > 33)
+ {
+ /*
+ * Shallow lava (preserve walls)
+ * Deep lava (penetrate walls)
+ */
+ if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_SHAL_LAVA, 0);
+ }
+
+ if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA - 1);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_DEEP_LAVA, 1);
+ }
+ }
+ }
+
+ /*
+ * Shallow water (preserve walls)
+ * Deep water (penetrate walls)
+ */
+ else if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA - 1);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_SHAL_WATER, 0);
+ }
+
+ if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_DEEP_WATER, 1);
+ }
+ }
+ }
+ }
+ }
+
+ /* Hack, seems like once a room overrode the level boundaries, this is BAD */
+ set_bounders(empty_level);
+
+ /* Determine the character location */
+ if (!new_player_spot(branch))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Bring the imprinted pets from the old level
+ */
+void replace_all_friends()
+{
+ int i;
+
+ if (p_ptr->wild_mode) return;
+
+ /* Scan every saved pet */
+ for (i = 0; i < max_m_idx; i++)
+ {
+ if ((km_list[i].r_idx) && (km_list[i].status == MSTATUS_COMPANION))
+ {
+ int y = p_ptr->py, x = p_ptr->px;
+ cave_type *c_ptr;
+ monster_type *m_ptr;
+
+ /* Find a suitable location */
+ get_pos_player(5, &y, &x);
+ c_ptr = &cave[y][x];
+
+ /* Get a m_idx to use */
+ c_ptr->m_idx = m_pop();
+ m_ptr = &m_list[c_ptr->m_idx];
+
+ /* Actualy place the monster */
+ m_list[c_ptr->m_idx] = km_list[i];
+ m_ptr->fy = y;
+ m_ptr->fx = x;
+ m_ptr->hold_o_idx = 0;
+ }
+ }
+}
+
+/*
+ * Save the imprinted pets from the old level
+ */
+void save_all_friends()
+{
+ if (p_ptr->old_wild_mode) return;
+
+ C_COPY(km_list, m_list, max_m_idx, monster_type);
+}
+
+
+
+/*
+ * Return the dungeon type of the current level(it can only return the
+ * principal dungeons)
+ */
+byte calc_dungeon_type()
+{
+ int i;
+
+ for (i = 0; i < max_d_idx; i++)
+ {
+ if ((dun_level >= d_info[i].mindepth) &&
+ (dun_level <= d_info[i].maxdepth) &&
+ (d_info[i].flags1 & DF1_PRINCIPAL))
+ return (i);
+ }
+ return (0);
+}
+
+
+/*
+ * Build probability tables for walls and floors and set feat_wall_outer
+ * and feat_wall_inner according to the current information in d_info.txt
+ *
+ * *hint* *hint* with this made extern, and we no longer have to
+ * store fill_type and floor_type in the savefile...
+ */
+static void init_feat_info(void)
+{
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+ int i;
+ int cur_depth, max_depth;
+ int p1, p2;
+ int floor_lim1, floor_lim2;
+ int fill_lim1, fill_lim2;
+
+
+ /* Retrieve dungeon depth info (base 1, to avoid zero divide errors) */
+ cur_depth = (dun_level - d_ptr->mindepth) + 1;
+ max_depth = (d_ptr->maxdepth - d_ptr->mindepth) + 1;
+
+
+ /* Set room wall types */
+ feat_wall_outer = d_ptr->outer_wall;
+ feat_wall_inner = d_ptr->inner_wall;
+
+
+ /* Setup probability info -- Floors */
+ p1 = d_ptr->floor_percent1[0];
+ p2 = d_ptr->floor_percent1[1];
+ floor_lim1 = p1 + (p2 - p1) * cur_depth / max_depth;
+
+ p1 = d_ptr->floor_percent2[0];
+ p2 = d_ptr->floor_percent2[1];
+ floor_lim2 = floor_lim1 + p1 + (p2 - p1) * cur_depth / max_depth;
+
+ /* Setup probability info -- Fillers */
+ p1 = d_ptr->fill_percent1[0];
+ p2 = d_ptr->fill_percent1[1];
+ fill_lim1 = p1 + (p2 - p1) * cur_depth / max_depth;
+
+ p1 = d_ptr->fill_percent2[0];
+ p2 = d_ptr->fill_percent2[1];
+ fill_lim2 = fill_lim1 + p1 + (p2 - p1) * cur_depth / max_depth;
+
+
+ /* Fill the arrays of floors and walls in the good proportions */
+ for (i = 0; i < 100; i++)
+ {
+ if (i < floor_lim1)
+ {
+ floor_type[i] = d_ptr->floor1;
+ }
+ else if (i < floor_lim2)
+ {
+ floor_type[i] = d_ptr->floor2;
+ }
+ else
+ {
+ floor_type[i] = d_ptr->floor3;
+ }
+
+ if (i < fill_lim1)
+ {
+ fill_type[i] = d_ptr->fill_type1;
+ }
+ else if (i < fill_lim2)
+ {
+ fill_type[i] = d_ptr->fill_type2;
+ }
+ else
+ {
+ fill_type[i] = d_ptr->fill_type3;
+ }
+ }
+}
+
+
+/*
+ * Fill a level with wall type specified in A: or L: line of d_info.txt
+ *
+ * 'use_floor', when it is TRUE, tells the function to use floor type
+ * terrains (L:) instead of walls (A:).
+ *
+ * Filling behaviour can be controlled by the second parameter 'smooth',
+ * with the following options available:
+ *
+ * smooth behaviour
+ * ------ ------------------------------------------------------------
+ * 0 Fill the entire level with fill_type1 / floor1
+ * 1 All the grids are randomly selected (== --P5.1.2)
+ * 2 Slightly smoothed -- look like scattered patches
+ * 3 More smoothed -- tend to look like caverns / small scale map
+ * 4-- Max smoothing -- tend to look like landscape/island/
+ * continent etc.
+ *
+ * I put it here, because there's another filler generator in
+ * wild.c, but it works better there, in fact...
+ *
+ * CAVEAT: smoothness of 3 or greater doesn't work well with the
+ * current secret door implementation. Outer walls also need some
+ * rethinking.
+ *
+ * -- pelpel
+ */
+
+/*
+ * Thou shalt not invoke the name of thy RNG in vain.
+ * The Angband RNG generates 28 bit pseudo-random number, hence
+ * 28 / 2 = 14
+ */
+#define MAX_SHIFTS 14
+
+static void fill_level(bool_ use_floor, byte smooth)
+{
+ int y, x;
+ int step;
+ int shift;
+
+
+ /* Convert smoothness to initial step */
+ if (smooth == 0) step = 0;
+ else if (smooth == 1) step = 1;
+ else if (smooth == 2) step = 2;
+ else if (smooth == 3) step = 4;
+ else step = 8;
+
+ /*
+ * Paranoia -- step must be less than or equal to a half of
+ * width or height, whichever shorter
+ */
+ if ((cur_hgt < 16) && (step > 4)) step = 4;
+ if ((cur_wid < 16) && (step > 4)) step = 4;
+
+
+ /* Special case -- simple fill */
+ if (step == 0)
+ {
+ byte filler;
+
+ /* Pick a filler XXX XXX XXX */
+ if (use_floor) filler = d_info[dungeon_type].floor1;
+ else filler = d_info[dungeon_type].fill_type1;
+
+ /* Fill the level with the filler without calling RNG */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, filler);
+ }
+ }
+
+ /* Done */
+ return;
+ }
+
+
+ /*
+ * Fill starting positions -- every 'step' grids horizontally and
+ * vertically
+ */
+ for (y = 0; y < cur_hgt; y += step)
+ {
+ for (x = 0; x < cur_wid; x += step)
+ {
+ /*
+ * Place randomly selected terrain feature using the prebuilt
+ * probability table
+ *
+ * By slightly modifying this, you can build streamers as
+ * well as normal fillers all at once, but this calls for
+ * modifications to the other part of the dungeon generator.
+ */
+ if (use_floor) place_floor(y, x);
+ else place_filler(y, x);
+ }
+ }
+
+
+ /*
+ * Fill spaces between, randomly picking one of their neighbours
+ *
+ * This simple yet powerful algorithm was described by Mike Anderson:
+ *
+ * A B A | B A a B
+ * -> --+-- -> d e b
+ * D C D | C D c C
+ *
+ * a can be either A or B, b B or C, c C or D and d D or A.
+ * e is chosen from A, B, C and D.
+ * Subdivide and repeat the process as many times as you like.
+ *
+ * All the nasty tricks that obscure this simplicity are mine (^ ^;)
+ */
+
+ /* Initialise bit shift counter */
+ shift = MAX_SHIFTS;
+
+ /* Repeat subdivision until all the grids are filled in */
+ while ((step = step >> 1) > 0)
+ {
+ bool_ y_even, x_even;
+ s16b y_wrap, x_wrap;
+ s16b y_sel, x_sel;
+ u32b selector = 0;
+
+ /* Hacklette -- Calculate wrap-around locations */
+ y_wrap = ((cur_hgt - 1) / (step * 2)) * (step * 2);
+ x_wrap = ((cur_wid - 1) / (step * 2)) * (step * 2);
+
+ /* Initialise vertical phase */
+ y_even = 0;
+
+ for (y = 0; y < cur_hgt; y += step)
+ {
+ /* Flip vertical phase */
+ y_even = !y_even;
+
+ /* Initialise horizontal phase */
+ x_even = 0;
+
+ for (x = 0; x < cur_wid; x += step)
+ {
+ /* Flip horizontal phase */
+ x_even = !x_even;
+
+ /* Already filled in by previous iterations */
+ if (y_even && x_even) continue;
+
+ /*
+ * Retrieve next two bits from pseudo-random bit sequence
+ *
+ * You can do well not caring so much about their randomness.
+ *
+ * This is not really necessary, but I don't like to invoke
+ * relatively expensive RNG when we can do with much smaller
+ * number of calls.
+ */
+ if (shift >= MAX_SHIFTS)
+ {
+ selector = rand_int(0x10000000L);
+ shift = 0;
+ }
+ else
+ {
+ selector >>= 2;
+ shift++;
+ }
+
+ /* Vertically in sync */
+ if (y_even) y_sel = y;
+
+ /* Bit 1 selects neighbouring y */
+ else y_sel = (selector & 2) ? y + step : y - step;
+
+ /* Horizontally in sync */
+ if (x_even) x_sel = x;
+
+ /* Bit 0 selects neighbouring x */
+ else x_sel = (selector & 1) ? x + step : x - step;
+
+ /* Hacklette -- Fix out of range indices by wrapping around */
+ if (y_sel >= cur_hgt) y_sel = 0;
+ else if (y_sel < 0) y_sel = y_wrap;
+ if (x_sel >= cur_wid) x_sel = 0;
+ else if (x_sel < 0) x_sel = x_wrap;
+
+ /*
+ * Fill the grid with terrain feature of the randomly
+ * picked up neighbour
+ */
+ cave_set_feat(y, x, cave[y_sel][x_sel].feat);
+ }
+ }
+ }
+}
+
+
+/*
+ * Generate a new dungeon level
+ *
+ * Note that "dun_body" adds about 4000 bytes of memory to the stack.
+ */
+static bool_ cave_gen(void)
+{
+ int i, k, y, x, y1, x1, branch;
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ int max_vault_ok = 2;
+
+ bool_ empty_level = FALSE;
+
+ level_generator_type *generator;
+
+ dun_data dun_body;
+
+ char generator_name[100];
+
+ if (!get_dungeon_generator(generator_name))
+ strnfmt(generator_name, 99, "%s", d_ptr->generator);
+
+ /*
+ * We generate a double dungeon. First we should halve the desired
+ * width/height, generate the dungeon normally, then double it
+ * in both directions
+ */
+ if (dungeon_flags1 & DF1_DOUBLE)
+ {
+ cur_wid /= 2;
+ cur_hgt /= 2;
+ }
+
+ /* Fill the arrays of floors and walls in the good proportions */
+ init_feat_info();
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Global data */
+ dun = &dun_body;
+
+ if (!(max_panel_rows)) max_vault_ok--;
+ if (!(max_panel_cols)) max_vault_ok--;
+
+ /*
+ * Hack -- Start with fill_type's
+ *
+ * Need a way to know appropriate smoothing factor for the current
+ * dungeon. Maybe we need another d_info flag/value.
+ */
+ fill_level(empty_level, d_ptr->fill_method);
+
+ set_bounders(empty_level);
+
+ /*
+ * Call the good level generator
+ */
+ generator = level_generators;
+ while (generator)
+ {
+ if (!strcmp(generator->name, generator_name))
+ {
+ if (!generator->generator(generator->name))
+ return FALSE;
+ break;
+ }
+
+ generator = generator->next;
+ }
+
+ /* Only if requested */
+ if (generator->default_stairs)
+ {
+ /* Is there a dungeon branch ? */
+ if ((branch = get_branch()))
+ {
+ /* Place 5 down stair some walls */
+ alloc_stairs(FEAT_MORE, 5, 3, branch);
+ }
+
+ /* Is there a father dungeon branch ? */
+ if ((branch = get_fbranch()))
+ {
+ /* Place 1 down stair some walls */
+ alloc_stairs(FEAT_LESS, 5, 3, branch);
+ }
+
+ if ((dun_level < d_ptr->maxdepth) || ((dun_level == d_ptr->maxdepth) && (dungeon_flags1 & DF1_FORCE_DOWN)))
+ {
+ /* Place 3 or 4 down stairs near some walls */
+ alloc_stairs((dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_MORE : FEAT_MORE, rand_range(3, 4), 3, 0);
+
+ /* Place 0 or 1 down shafts near some walls */
+ if (!(dungeon_flags2 & DF2_NO_SHAFT)) alloc_stairs((dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_MORE : FEAT_SHAFT_DOWN, rand_range(0, 1), 3, 0);
+ }
+
+ if ((dun_level > d_ptr->mindepth) || ((dun_level == d_ptr->mindepth) && (!(dungeon_flags1 & DF1_NO_UP))))
+ {
+ /* Place 1 or 2 up stairs near some walls */
+ alloc_stairs((dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_LESS : FEAT_LESS, rand_range(1, 2), 3, 0);
+
+ /* Place 0 or 1 up shafts near some walls */
+ if (!(dungeon_flags2 & DF2_NO_SHAFT)) alloc_stairs((dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_LESS : FEAT_SHAFT_UP, rand_range(0, 1), 3, 0);
+ }
+ }
+
+ process_hooks(HOOK_GEN_LEVEL, "(d)", is_quest(dun_level));
+
+ /* Basic "amount" */
+ k = (dun_level / 3);
+ if (k > 10) k = 10;
+ if (k < 2) k = 2;
+
+ /* Only if requested */
+ if (generator->default_monsters)
+ {
+
+ /*
+ * Pick a base number of monsters
+ */
+ i = d_ptr->min_m_alloc_level;
+
+ /* To make small levels a bit more playable */
+ if ((cur_hgt < MAX_HGT) || (cur_wid < MAX_WID))
+ {
+ int small_tester = i;
+
+ i = (i * cur_hgt) / MAX_HGT;
+ i = (i * cur_wid) / MAX_WID;
+ i += 1;
+
+ if (i > small_tester) i = small_tester;
+ else if (cheat_hear)
+ {
+ msg_format("Reduced monsters base from %d to %d", small_tester, i);
+ }
+ }
+
+ i += randint(8);
+
+ /* Put some monsters in the dungeon */
+ for (i = i + k; i > 0; i--)
+ {
+ (void)alloc_monster(0, TRUE);
+ }
+ }
+
+ /* Check fates */
+ for (i = 0; i < MAX_FATES; i++)
+ {
+ /* Ignore empty slots */
+ if (fates[i].fate == FATE_NONE) continue;
+
+ /* Check dungeon depth */
+ if (fates[i].level != dun_level) continue;
+
+ /* Non-serious fates don't always fire */
+ if ((!fates[i].serious) && (randint(2) != 1)) continue;
+
+ /* Player meets his/her fate now... */
+ fate_flag = TRUE;
+
+ switch (fates[i].fate)
+ {
+ case FATE_FIND_O:
+ {
+ int oy = p_ptr->py + 1;
+ int ox = p_ptr->px;
+ object_type *q_ptr, forge;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Mega-Hack */
+ object_prep(q_ptr, fates[i].o_idx);
+
+ /* Mega-Hack */
+ apply_magic(q_ptr, dun_level, TRUE, TRUE, fates[i].serious);
+
+ get_pos_player(10, &oy, &ox);
+
+ /* Drop it from the heaven */
+ drop_near(q_ptr, -1, oy, ox);
+
+ /* Make it icky */
+ fates[i].icky = TRUE;
+ break;
+ }
+ case FATE_FIND_R:
+ {
+ int oy = p_ptr->py + 1;
+ int ox = p_ptr->px;
+
+ get_pos_player(10, &oy, &ox);
+
+ place_monster_one(oy, ox, fates[i].r_idx, 0, fates[i].serious, MSTATUS_ENEMY);
+
+ fates[i].icky = TRUE;
+ break;
+ }
+ case FATE_FIND_A:
+ {
+ int oy = p_ptr->py + 1;
+ int ox = p_ptr->px;
+ object_type *q_ptr = NULL, forge;
+
+ get_pos_player(10, &oy, &ox);
+
+ /* XXX XXX XXX Grant a randart */
+ if (fates[i].a_idx == 0)
+ {
+ int obj_lev;
+ s16b k_idx;
+
+ /* Apply restriction */
+ get_obj_num_hook = kind_is_artifactable;
+
+ /* Object level a la find object fates */
+ obj_lev = max_dlv[dungeon_type] + randint(10);
+
+ /* Rebuild allocation table */
+ get_obj_num_prep();
+
+ /* Roll for an object */
+ k_idx = get_obj_num(obj_lev);
+
+ /* Reset restriction */
+ get_obj_num_hook = kind_is_legal;
+
+ /* Invalidate the allocation table */
+ alloc_kind_table_valid = FALSE;
+
+ /* Get a local object */
+ q_ptr = &forge;
+
+ /* Wipe it */
+ object_wipe(q_ptr);
+
+ /* Create the object */
+ object_prep(q_ptr, k_idx);
+
+ /* SoAC it */
+ create_artifact(q_ptr, FALSE, TRUE);
+
+ /* Drop the artifact from heaven */
+ drop_near(q_ptr, -1, oy, ox);
+ }
+
+ /* Grant a normal artefact */
+ else if (a_info[fates[i].a_idx].cur_num == 0)
+ {
+ artifact_type *a_ptr = &a_info[fates[i].a_idx];
+ s16b I_kind;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Acquire the "kind" index */
+ I_kind = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Create the artifact */
+ object_prep(q_ptr, I_kind);
+
+ /* Save the name */
+ q_ptr->name1 = fates[i].a_idx;
+
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+
+ /* Drop the artifact from heaven */
+ drop_near(q_ptr, -1, oy, ox);
+ }
+
+ fates[i].icky = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Re scan the list to eliminate the inutile fate */
+ for (i = 0; i < MAX_FATES; i++)
+ {
+ switch (fates[i].fate)
+ {
+ case FATE_FIND_A:
+ {
+ if (a_info[fates[i].a_idx].cur_num == 1) fates[i].icky = TRUE;
+ break;
+ }
+ case FATE_FIND_R:
+ {
+ if ((r_info[fates[i].r_idx].cur_num == 1) && (r_info[fates[i].r_idx].flags1 & RF1_UNIQUE)) fates[i].icky = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Only if requested */
+ if (generator->default_miscs)
+ {
+ /* Place some traps in the dungeon */
+ alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_TRAP, randint(k * 2));
+
+ /* Put some rubble in corridors */
+ alloc_object(ALLOC_SET_CORR, ALLOC_TYP_RUBBLE, randint(k));
+ }
+
+ /* Only if requested */
+ if (generator->default_objects)
+ {
+ /* Put some objects in rooms */
+ if (dungeon_type != DUNGEON_DEATH) alloc_object(ALLOC_SET_ROOM, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ROOM, 3));
+
+ /* Put some objects/gold in the dungeon */
+ if (dungeon_type != DUNGEON_DEATH) alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ITEM, 3));
+ if (dungeon_type != DUNGEON_DEATH) alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_GOLD, randnor(DUN_AMT_GOLD, 3));
+ }
+
+ /* Only if requested */
+ if (generator->default_miscs)
+ {
+ /* Put some altars */
+ alloc_object(ALLOC_SET_ROOM, ALLOC_TYP_ALTAR, randnor(DUN_AMT_ALTAR, 3));
+
+ /* Put some between gates */
+ alloc_object(ALLOC_SET_ROOM, ALLOC_TYP_BETWEEN, randnor(DUN_AMT_BETWEEN, 3));
+
+ /* Put some fountains */
+ alloc_object(ALLOC_SET_ROOM, ALLOC_TYP_FOUNTAIN, randnor(DUN_AMT_FOUNTAIN, 3));
+ }
+
+ /* Put an Artifact and Artifact Guardian is requested */
+ if (d_ptr->final_guardian && (d_ptr->maxdepth == dun_level))
+ {
+ int oy;
+ int ox;
+ int m_idx, tries = 10000;
+
+ /* Find a good position */
+ while (tries)
+ {
+ /* Get a random spot */
+ oy = randint(cur_hgt - 4) + 2;
+ ox = randint(cur_wid - 4) + 2;
+
+ /* Is it a good spot ? */
+ if (cave_empty_bold(oy, ox)) break;
+
+ /* One less try */
+ tries--;
+ }
+
+ /* Place the guardian */
+ m_allow_special[d_ptr->final_guardian] = TRUE;
+ place_monster_one(oy, ox, d_ptr->final_guardian, 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[d_ptr->final_guardian] = FALSE;
+
+
+ m_idx = cave[oy][ox].m_idx;
+
+ if (!m_idx && wizard) cmsg_print(TERM_L_RED, "WARNING: Could not place guardian.");
+
+ /*
+ * If guardian is successfully created and his/her/its
+ * treasure hasn't been found, let him/her/it own that
+ */
+ if (m_idx && d_ptr->final_artifact &&
+ (a_info[d_ptr->final_artifact].cur_num == 0))
+ {
+ artifact_type *a_ptr = &a_info[d_ptr->final_artifact];
+ object_type *q_ptr, forge, *o_ptr;
+ int I_kind, o_idx;
+
+ /* Get new object */
+ o_idx = o_pop();
+
+ /* Proceed only if there's an object slot available */
+ if (o_idx)
+ {
+ a_allow_special[d_ptr->final_artifact] = TRUE;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Acquire the "kind" index */
+ I_kind = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Create the artifact */
+ object_prep(q_ptr, I_kind);
+
+ /* Save the name */
+ q_ptr->name1 = d_ptr->final_artifact;
+
+ /* Actually create it */
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+
+ /* Where it is found ? */
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = d_ptr->final_guardian;
+ q_ptr->found_aux2 = 0;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ a_allow_special[d_ptr->final_artifact] = FALSE;
+
+ /* Get the item */
+ o_ptr = &o_list[o_idx];
+
+ /* Structure copy */
+ object_copy(o_ptr, q_ptr);
+
+ /* Build a stack */
+ o_ptr->next_o_idx = m_list[m_idx].hold_o_idx;
+
+ o_ptr->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_list[m_idx].hold_o_idx = o_idx;
+ }
+ }
+
+ if (m_idx && d_ptr->final_object &&
+ (k_info[d_ptr->final_object].artifact == FALSE))
+ {
+ object_type *q_ptr, forge, *o_ptr;
+ int o_idx;
+
+ /* Get new object */
+ o_idx = o_pop();
+
+ /* Proceed only if there's an object slot available */
+ if (o_idx)
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ k_allow_special[d_ptr->final_object] = TRUE;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Create the final object */
+ object_prep(q_ptr, d_ptr->final_object);
+ apply_magic(q_ptr, 1, FALSE, FALSE, FALSE);
+
+ /* Where it is found ? */
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = d_ptr->final_guardian;
+ q_ptr->found_aux2 = 0;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ k_allow_special[d_ptr->final_object] = FALSE;
+
+ k_info[d_ptr->final_object].artifact = TRUE;
+
+ /* Get the item */
+ o_ptr = &o_list[o_idx];
+
+ /* Structure copy */
+ object_copy(o_ptr, q_ptr);
+
+ /* Build a stack */
+ o_ptr->next_o_idx = m_list[m_idx].hold_o_idx;
+
+ o_ptr->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_list[m_idx].hold_o_idx = o_idx;
+ }
+ }
+ }
+
+ if ((empty_level) && (randint(DARK_EMPTY) != 1 || (randint(100) > dun_level)))
+ wiz_lite();
+
+ /* Now double the generated dungeon */
+ if (dungeon_flags1 & DF1_DOUBLE)
+ {
+ /* We begin at the bottom-right corner and from there move
+ * up/left (this way we don't need another array for the
+ * dungeon data) */
+ /* Note: we double the border permanent walls, too. It is
+ * easier this way and I think it isn't too ugly */
+ for (y = cur_hgt - 1, y1 = y * 2; y >= 0; y--, y1 -= 2)
+ for (x = cur_wid - 1, x1 = x * 2; x >= 0; x--, x1 -= 2)
+ {
+ int disp[4][2] = {{0, 0}, {0, + 1}, { + 1, 0}, { + 1, + 1}};
+
+ cave_type *c_ptr[4], *cc_ptr = &cave[y][x];
+ object_type *o_ptr = &o_list[cc_ptr->o_idx];
+ monster_type *m_ptr = &m_list[cc_ptr->m_idx];
+
+ /*
+ * Now we copy the generated data to the
+ * appropriate grids
+ */
+ for (i = 0; i < 4; i++)
+ {
+ c_ptr[i] = &cave[y1 + disp[i][0]][x1 + disp[i][1]];
+ *c_ptr[i] = *cc_ptr;
+ c_ptr[i]->o_idx = 0;
+ c_ptr[i]->m_idx = 0;
+
+ if (cc_ptr->feat == FEAT_BETWEEN)
+ {
+ int xxx = cc_ptr->special & 0xFF;
+ int yyy = cc_ptr->special >> 8;
+
+ xxx *= 2;
+ yyy *= 2;
+ xxx += disp[i][1];
+ yyy += disp[i][0];
+ c_ptr[i]->special = xxx + (yyy << 8);
+ }
+ }
+
+ /* Objects should be put only in 1 of the
+ * new grids (otherwise we would segfault
+ * a lot) ... */
+ if (cc_ptr->o_idx != 0)
+ {
+ i = rand_int(4);
+ c_ptr[i]->o_idx = cc_ptr->o_idx;
+ o_ptr->iy = y1 + disp[i][0];
+ o_ptr->ix = x1 + disp[i][1];
+ }
+
+ /* ..just like monsters */
+ if (cc_ptr->m_idx != 0)
+ {
+ i = rand_int(4);
+ c_ptr[i]->m_idx = cc_ptr->m_idx;
+ m_ptr->fy = y1 + disp[i][0];
+ m_ptr->fx = x1 + disp[i][1];
+ }
+ }
+
+ /* Set the width/height ... */
+ cur_wid *= 2;
+ cur_hgt *= 2;
+
+ /* ... and player position to the right place */
+ p_ptr->py *= 2;
+ p_ptr->px *= 2;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Builds the arena after it is entered -KMW-
+ */
+static void build_arena(void)
+{
+ int yval, y_height, y_depth, xval, x_left, x_right;
+ register int i, j;
+
+ yval = SCREEN_HGT / 2;
+ xval = SCREEN_WID / 2;
+ y_height = yval - 10 + SCREEN_HGT;
+ y_depth = yval + 10 + SCREEN_HGT;
+ x_left = xval - 32 + SCREEN_WID;
+ x_right = xval + 32 + SCREEN_WID;
+
+ for (i = y_height; i <= y_height + 5; i++)
+ {
+ for (j = x_left; j <= x_right; j++)
+ {
+ cave_set_feat(i, j, FEAT_PERM_EXTRA);
+ cave[i][j].info |= (CAVE_GLOW | CAVE_MARK);
+ }
+ }
+ for (i = y_depth; i >= y_depth - 5; i--)
+ {
+ for (j = x_left; j <= x_right; j++)
+ {
+ cave_set_feat(i, j, FEAT_PERM_EXTRA);
+ cave[i][j].info |= (CAVE_GLOW | CAVE_MARK);
+ }
+ }
+ for (j = x_left; j <= x_left + 17; j++)
+ {
+ for (i = y_height; i <= y_depth; i++)
+ {
+ cave_set_feat(i, j, FEAT_PERM_EXTRA);
+ cave[i][j].info |= (CAVE_GLOW | CAVE_MARK);
+ }
+ }
+ for (j = x_right; j >= x_right - 17; j--)
+ {
+ for (i = y_height; i <= y_depth; i++)
+ {
+ cave_set_feat(i, j, FEAT_PERM_EXTRA);
+ cave[i][j].info |= (CAVE_GLOW | CAVE_MARK);
+ }
+ }
+
+ cave_set_feat(y_height + 6, x_left + 18, FEAT_PERM_EXTRA);
+ cave[y_height + 6][x_left + 18].info |= (CAVE_GLOW | CAVE_MARK);
+ cave_set_feat(y_depth - 6, x_left + 18, FEAT_PERM_EXTRA);
+ cave[y_depth - 6][x_left + 18].info |= (CAVE_GLOW | CAVE_MARK);
+ cave_set_feat(y_height + 6, x_right - 18, FEAT_PERM_EXTRA);
+ cave[y_height + 6][x_right - 18].info |= (CAVE_GLOW | CAVE_MARK);
+ cave_set_feat(y_depth - 6, x_right - 18, FEAT_PERM_EXTRA);
+ cave[y_depth - 6][x_right - 18].info |= (CAVE_GLOW | CAVE_MARK);
+
+ i = y_height + 5;
+ j = xval + SCREEN_WID;
+ cave_set_feat(i, j, FEAT_SHOP);
+ cave[i][j].info |= (CAVE_GLOW | CAVE_MARK);
+ player_place(i + 1, j);
+}
+
+
+/*
+ * Town logic flow for generation of arena -KMW-
+ */
+static void arena_gen(void)
+{
+ int y, x;
+ int qy = SCREEN_HGT;
+ int qx = SCREEN_WID;
+ bool_ daytime;
+
+ /* Day time */
+ if ((turn % (10L * DAY)) < ((10L * DAY) / 2))
+ daytime = TRUE;
+
+ /* Night time */
+ else
+ daytime = FALSE;
+
+ /* Start with solid walls */
+ for (y = 0; y < MAX_HGT; y++)
+ {
+ for (x = 0; x < MAX_WID; x++)
+ {
+ /* Create "solid" perma-wall */
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+
+ /* Illuminate and memorize the walls */
+ cave[y][x].info |= (CAVE_GLOW | CAVE_MARK);
+ }
+ }
+
+ /* Then place some floors */
+ for (y = qy + 1; y < qy + SCREEN_HGT - 1; y++)
+ {
+ for (x = qx + 1; x < qx + SCREEN_WID - 1; x++)
+ {
+ /* Create empty floor */
+ cave_set_feat(y, x, FEAT_FLOOR);
+
+ /* Darken and forget the floors */
+ cave[y][x].info &= ~(CAVE_GLOW | CAVE_MARK);
+
+ /* Day time */
+ if (daytime)
+ {
+ /* Perma-Lite */
+ cave[y][x].info |= (CAVE_GLOW);
+
+ /* Memorize */
+ if (view_perma_grids) cave[y][x].info |= (CAVE_MARK);
+ }
+ }
+ }
+
+ build_arena();
+
+ place_monster_aux(p_ptr->py + 5, p_ptr->px, arena_monsters[p_ptr->arena_number],
+ FALSE, FALSE, MSTATUS_ENEMY);
+}
+
+
+/*
+ * Generate a quest level
+ */
+static void quest_gen(void)
+{
+ process_hooks(HOOK_GEN_QUEST, "(d)", is_quest(dun_level));
+}
+
+/*
+ * Creates a special level
+ */
+
+/* Mega-Hack */
+#define REGEN_HACK 0x02
+
+bool_ build_special_level(void)
+{
+ char buf[80];
+ int y, x, ystart = 2, xstart = 2;
+ s16b level;
+
+ /* No special levels on the surface */
+ if (!dun_level) return FALSE;
+
+ level = dun_level - d_info[dungeon_type].mindepth;
+ if ((!get_dungeon_save(buf)) && (special_lvl[level][dungeon_type])) return FALSE;
+ if (!get_dungeon_special(buf)) return FALSE;
+
+ /* Big town */
+ cur_hgt = MAX_HGT;
+ cur_wid = MAX_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON | INIT_POSITION;
+ process_dungeon_file(buf, &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ special_lvl[level][dungeon_type] = REGEN_HACK;
+ generate_special_feeling = TRUE;
+
+ /* Special feeling because it's special */
+ good_item_flag = TRUE;
+
+ /*
+ * Hack -- It's better/more dangerous than a greater vault.
+ * Better to have a rating field in special level description.
+ */
+ rating += 40;
+
+ return TRUE;
+}
+
+/*
+ * Prepare regeneration of a special level, which should not happen,
+ * but just in case...
+ */
+static void wipe_special_level(void)
+{
+ s16b level;
+ char buf[80];
+
+ /* No special levels on the surface */
+ if (!dun_level) return;
+
+ process_hooks(HOOK_LEVEL_REGEN, "()");
+
+ /* Calculate relative depth */
+ level = dun_level - d_info[dungeon_type].mindepth;
+
+ /* No special level at this depth */
+ if ((!get_dungeon_save(buf)) &&
+ special_lvl[level][dungeon_type]) return;
+ if (!get_dungeon_special(buf)) return;
+
+ /* Clear the Mega-Hack flag */
+ if (special_lvl[level][dungeon_type] == REGEN_HACK)
+ special_lvl[level][dungeon_type] = FALSE;
+}
+
+/*
+ * Finalise generation of a special level
+ */
+static void finalise_special_level(void)
+{
+ s16b level;
+ char buf[80];
+
+ /* No special levels on the surface */
+ if (!dun_level) return;
+
+ process_hooks(HOOK_LEVEL_END_GEN, "()");
+
+ /* Calculate relative depth */
+ level = dun_level - d_info[dungeon_type].mindepth;
+
+ /* No special level at this depth */
+ if ((!get_dungeon_save(buf)) &&
+ special_lvl[level][dungeon_type]) return;
+ if (!get_dungeon_special(buf)) return;
+
+ /* Set the "generated" flag */
+ if (special_lvl[level][dungeon_type] == REGEN_HACK)
+ special_lvl[level][dungeon_type] = TRUE;
+}
+
+/*
+ * Give some magical energy to the each grid of the level
+ */
+void generate_grid_mana()
+{
+ int y, x, mana, mult;
+ bool_ xtra_magic = FALSE;
+
+ if (randint(XTRA_MAGIC) == 1)
+ {
+ xtra_magic = TRUE;
+
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print("Magical level");
+ }
+ }
+
+ mult = ((xtra_magic) ? 3 : 2);
+
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Calculate the amount of mana in each grid */
+ mana = mult * m_bonus(255, dun_level) / 2;
+ if (xtra_magic) mana += 10 + rand_int(10);
+
+ /* Never more than 255 or less than 0(paranoia) */
+ if (mana < 0) mana = 0;
+ if (mana > 255) mana = 255;
+
+ c_ptr->mana = mana;
+ }
+ }
+}
+
+
+/*
+ * Generates a random dungeon level -RAK-
+ *
+ * Hack -- regenerate any "overflow" levels
+ *
+ * Hack -- allow auto-scumming via a gameplay option.
+ */
+void generate_cave(void)
+{
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+ int tester_1, tester_2;
+ int y, x, num, i;
+ bool_ loaded = FALSE;
+ char buf[80];
+ s16b town_level = 0;
+
+ /* The dungeon is not ready */
+ character_dungeon = FALSE;
+ generate_special_feeling = FALSE;
+
+ /* Initialize the flags with the basic dungeon flags */
+ if (!dun_level)
+ {
+ dungeon_flags1 = d_info[DUNGEON_WILDERNESS].flags1;
+ dungeon_flags2 = d_info[DUNGEON_WILDERNESS].flags2;
+ }
+ else
+ {
+ dungeon_flags1 = d_ptr->flags1;
+ dungeon_flags2 = d_ptr->flags2;
+ }
+
+ /* Is it a town level ? */
+ for (i = 0; i < TOWN_DUNGEON; i++)
+ {
+ if (d_ptr->t_level[i] == dun_level) town_level = d_ptr->t_idx[i];
+ }
+
+ /* Save the imprinted monsters */
+ save_all_friends();
+ wipe_m_list();
+
+ /* Seed the RNG if appropriate */
+ if (town_level)
+ {
+ Rand_quick = TRUE;
+ Rand_value = town_info[town_level].seed;
+ }
+
+ process_hooks(HOOK_GEN_LEVEL_BEGIN, "");
+
+ /* Try to load a saved level */
+ if (get_dungeon_save(buf))
+ {
+ /* No effects */
+ for (i = 0; i < MAX_EFFECTS; i++)
+ {
+ effects[i].time = 0;
+ }
+
+ /* Start with a blank cave */
+ for (y = 0; y < MAX_HGT; y++)
+ {
+ for (x = 0; x < MAX_WID; x++)
+ {
+ /* No flags */
+ cave[y][x].info = 0;
+
+ /* No features */
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+
+ /* No objects */
+ cave[y][x].o_idx = 0;
+
+ /* No monsters */
+ cave[y][x].m_idx = 0;
+
+ /* No traps */
+ cave[y][x].t_idx = 0;
+
+ /* No mimic */
+ cave[y][x].mimic = 0;
+
+ /* No effects */
+ cave[y][x].effect = 0;
+
+ /* No inscription */
+ cave[y][x].inscription = 0;
+
+ /* No flow */
+ cave[y][x].cost = 0;
+ cave[y][x].when = 0;
+ }
+ }
+
+ loaded = load_dungeon(buf);
+ }
+
+ /* No saved level -- generate new one */
+ if (!loaded)
+ {
+ if (!get_dungeon_special(buf) ||
+ !special_lvl[dun_level - d_info[dungeon_type].mindepth][dungeon_type])
+ {
+ get_level_flags();
+ }
+
+ /* Generate */
+ for (num = 0; TRUE; num++)
+ {
+ bool_ okay = TRUE;
+
+ cptr why = NULL;
+
+ /* No effects */
+ for (i = 0; i < MAX_EFFECTS; i++)
+ {
+ effects[i].time = 0;
+ }
+
+ /* Start with a blank cave */
+ for (y = 0; y < MAX_HGT; y++)
+ {
+ for (x = 0; x < MAX_WID; x++)
+ {
+ /* No flags */
+ cave[y][x].info = 0;
+
+ /* No features */
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+
+ /* No objects */
+ cave[y][x].o_idx = 0;
+
+ /* No monsters */
+ cave[y][x].m_idx = 0;
+
+ /* No traps */
+ cave[y][x].t_idx = 0;
+
+ /* No mimic */
+ cave[y][x].mimic = 0;
+
+ /* No effect */
+ cave[y][x].effect = 0;
+
+ /* No inscription */
+ cave[y][x].inscription = 0;
+
+ /* No flow */
+ cave[y][x].cost = 0;
+ cave[y][x].when = 0;
+ }
+ }
+
+
+ /* XXX XXX XXX XXX */
+ o_max = 1;
+
+
+ /* Mega-Hack -- no player yet */
+ p_ptr->px = p_ptr->py = 0;
+
+
+ /* Mega-Hack -- no panel yet */
+ panel_row_min = 0;
+ panel_row_max = 0;
+ panel_col_min = 0;
+ panel_col_max = 0;
+
+
+ /* Reset the monster generation level */
+ if (dungeon_type != DUNGEON_DEATH) monster_level = dun_level;
+ else monster_level = (p_ptr->lev * 2) + 10 + rand_int(40);
+
+ /* Reset the object generation level */
+ object_level = dun_level;
+
+ /* Nothing special here yet */
+ good_item_flag = FALSE;
+
+ /* Nothing good here yet */
+ rating = 0;
+
+ /* No ambush here yet */
+ ambush_flag = FALSE;
+
+ /* No fated level here yet */
+ fate_flag = FALSE;
+
+ /* Build the arena -KMW- */
+ if (p_ptr->inside_arena)
+ {
+ /* Small arena */
+ arena_gen();
+ }
+
+ /* Quest levels -KMW- */
+ else if (p_ptr->inside_quest)
+ {
+ quest_gen();
+ }
+
+ /* Special levels */
+ else if (build_special_level())
+ {
+ /* nothing */
+ }
+
+ /* Build the town */
+ else if (!dun_level)
+ {
+ /* Big town */
+ cur_hgt = MAX_HGT;
+ cur_wid = MAX_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ /* Big wilderness mode */
+ if (!p_ptr->wild_mode)
+ {
+ /* Make the wilderness */
+ wilderness_gen(0);
+ }
+
+ /* Small wilderness mode */
+ else
+ {
+ /* Make the wilderness */
+ wilderness_gen_small();
+ }
+
+
+ okay = TRUE;
+ }
+
+ /* Build a dungeon level */
+ else
+ {
+ /* Requested size level */
+ if (d_ptr->size_x != -1)
+ {
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print ("A 'size' dungeon level.");
+ }
+
+ cur_hgt = d_ptr->size_y * SCREEN_HGT;
+ cur_wid = d_ptr->size_x * SCREEN_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ if (cheat_room)
+ {
+ msg_format("X:%d, Y:%d.", max_panel_cols, max_panel_rows);
+ }
+ }
+ /* Very small (1 x 1 panel) level */
+ else if (!(dungeon_flags1 & DF1_BIG) &&
+ (dungeon_flags1 & DF1_SMALLEST))
+ {
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print ("A 'small' dungeon level.");
+ }
+
+ cur_hgt = SCREEN_HGT;
+ cur_wid = SCREEN_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = 1;
+ max_panel_cols = 1;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ if (cheat_room)
+ {
+ msg_format("X:1, Y:1.");
+ }
+ }
+
+ /* Small level */
+ else if (!(dungeon_flags1 & DF1_BIG) &&
+ (always_small_level ||
+ (dungeon_flags1 & DF1_SMALL) ||
+ (small_levels && rand_int(SMALL_LEVEL) == 0)))
+ {
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print ("A 'small' dungeon level.");
+ }
+
+ tester_1 = rand_range(1, (MAX_HGT / SCREEN_HGT));
+ tester_2 = rand_range(1, (MAX_WID / SCREEN_WID) - 1);
+
+ cur_hgt = tester_1 * SCREEN_HGT;
+ cur_wid = tester_2 * SCREEN_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ if (cheat_room)
+ {
+ msg_format("X:%d, Y:%d.", max_panel_cols, max_panel_rows);
+ }
+ }
+
+ /* Normal level */
+ else
+ {
+ /* Use full panels */
+ cur_hgt = MAX_HGT;
+ cur_wid = MAX_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+ }
+
+ /* Generate a level */
+ if (!cave_gen())
+ {
+ why = "could not place player";
+ okay = FALSE;
+ }
+ }
+
+ /* Extract the feeling */
+ if (rating > 100) feeling = 2;
+ else if (rating > 80) feeling = 3;
+ else if (rating > 60) feeling = 4;
+ else if (rating > 40) feeling = 5;
+ else if (rating > 30) feeling = 6;
+ else if (rating > 20) feeling = 7;
+ else if (rating > 10) feeling = 8;
+ else if (rating > 0) feeling = 9;
+ else feeling = 10;
+
+ /* Hack -- Have a special feeling sometimes */
+ if (good_item_flag && !p_ptr->preserve) feeling = 1;
+
+ /* It takes 1000 game turns for "feelings" to recharge */
+ if ((turn - old_turn) < 1000) feeling = 0;
+
+ /* Hack -- no feeling in the town */
+ if (!dun_level) feeling = 0;
+
+
+ /* Prevent object over-flow */
+ if (o_max >= max_o_idx)
+ {
+ /* Message */
+ why = "too many objects";
+
+ /* Message */
+ okay = FALSE;
+ }
+
+ /* Prevent monster over-flow */
+ if (m_max >= max_m_idx)
+ {
+ /* Message */
+ why = "too many monsters";
+
+ /* Message */
+ okay = FALSE;
+ }
+
+ /* Mega-Hack -- "auto-scum" */
+ if (auto_scum && (num < 100) && !p_ptr->inside_quest && dun_level)
+ {
+ /* Require "goodness" */
+ if ((feeling > 9) ||
+ ((dun_level >= 5) && (feeling > 8)) ||
+ ((dun_level >= 10) && (feeling > 7)) ||
+ ((dun_level >= 20) && (feeling > 6)) ||
+ ((dun_level >= 40) && (feeling > 5)))
+ {
+ /* Give message to cheaters */
+ if (cheat_room || cheat_hear ||
+ cheat_peek || cheat_xtra || p_ptr->precognition)
+ {
+ /* Message */
+ why = "boring level";
+ }
+
+ /* Try again */
+ okay = FALSE;
+ }
+ }
+
+ /* Accept */
+ if (okay || town_level) break;
+
+ /* Message */
+ if (why) msg_format("Generation restarted (%s)", why);
+
+ /* Wipe the objects */
+ wipe_o_list();
+
+ /* Wipe the monsters */
+ wipe_m_list();
+
+ /* Clear the fate icky flags */
+ for (i = 0; i < MAX_FATES; i++) fates[i].icky = FALSE;
+
+ /*
+ * Mega-Hack -- Reset special level flag if necessary
+ * XXX XXX XXX
+ */
+ wipe_special_level();
+ }
+
+ /* Give some mana to each grid -- DG */
+ generate_grid_mana();
+ }
+
+ /* Put the kept monsters -- DG */
+ if (!p_ptr->wild_mode) replace_all_friends();
+
+ /* Hack -- Clear used up fates */
+ for (i = 0; i < MAX_FATES; i++)
+ {
+ if (fates[i].icky)
+ {
+ /* Mark the artefact as generated */
+ if ((fates[i].fate == FATE_FIND_A) && fates[i].a_idx)
+ {
+ a_info[fates[i].a_idx].cur_num = 1;
+ }
+ fates[i].fate = FATE_NONE;
+ fates[i].icky = FALSE;
+ }
+ }
+
+ /* Set special level generated flag if applicable */
+ finalise_special_level();
+
+ /* No teleporatations yet */
+ last_teleportation_y = -1;
+ last_teleportation_x = -1;
+
+ /* Mark the dungeon town as found */
+ if (town_level)
+ {
+ /* Set the known flag */
+ town_info[town_level].flags |= (TOWN_KNOWN);
+ }
+
+ /* The dungeon is ready */
+ character_dungeon = TRUE;
+
+ /* Remember when this level was "created" */
+ old_turn = turn;
+
+ /* Provide astral chars with the full map */
+ if (p_ptr->astral && dun_level)
+ {
+ wiz_lite_extra();
+ }
+
+ /* Player should get the first move upon entering the dungeon */
+ p_ptr->energy = 100;
+}
diff --git a/src/gods.c b/src/gods.c
new file mode 100644
index 00000000..b8b8fd3a
--- /dev/null
+++ b/src/gods.c
@@ -0,0 +1,139 @@
+/* File: gods.c */
+
+/* Purpose: Deities code */
+
+/*
+ * Copyright (c) 2002 DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * Add amt piety is god is god
+ */
+void inc_piety(int god, s32b amt)
+{
+ s32b old = p_ptr->grace;
+
+ if ((god == GOD_ALL) || (god == p_ptr->pgod))
+ {
+ set_grace(p_ptr->grace + amt);
+
+ if(amt > 0 && p_ptr->grace <= old)
+ set_grace(300000);
+
+ if(amt < 0 && p_ptr->grace >= old)
+ set_grace(-300000);
+ }
+}
+
+/*
+ * Renounce to religion
+ */
+void abandon_god(int god)
+{
+ if ((god == GOD_ALL) || (god == p_ptr->pgod))
+ {
+ p_ptr->pgod = GOD_NONE;
+ set_grace(0);
+ }
+}
+
+/*
+ * Get a religion
+ */
+void follow_god(int god, bool_ silent)
+{
+ /* Poor unbelievers, i'm so mean ... BOUHAHAHA */
+ if (get_skill(SKILL_ANTIMAGIC))
+ {
+ msg_print("Don't be silly; you don't believe in gods.");
+ return;
+ }
+
+ /* Are we allowed ? */
+ if (process_hooks(HOOK_FOLLOW_GOD, "(d,s)", god, "ask"))
+ return;
+
+ if (p_ptr->pgod == GOD_NONE)
+ {
+ p_ptr->pgod = god;
+
+ /* Melkor offer Udun magic */
+ GOD(GOD_MELKOR)
+ {
+ s_info[SKILL_UDUN].hidden = FALSE;
+ if (!silent) msg_print("You feel the dark powers of Melkor in you. You can now use the Udun skill.");
+ }
+
+ /* Anything to be done? */
+ process_hooks(HOOK_FOLLOW_GOD, "(d,s)", god, "done");
+ }
+}
+
+/*
+ * Show religious info.
+ */
+bool_ show_god_info(bool_ ext)
+{
+ int pgod = p_ptr->pgod;
+
+ deity_type *d_ptr;
+
+ if (pgod < 0)
+ {
+ msg_print("You don't worship anyone.");
+ msg_print(NULL);
+ return FALSE;
+ }
+ else
+ {
+ int i;
+
+ d_ptr = &deity_info[pgod];
+
+ msg_print(NULL);
+
+ character_icky = TRUE;
+ Term_save();
+
+ text_out(format("You worship %s. ", d_ptr->name));
+ for (i = 0; (i < 10) && (strcmp(d_ptr->desc[i], "")); i++)
+ text_out(d_ptr->desc[i]);
+ text_out("\n");
+
+ inkey();
+
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Rescale the wisdom value to a 0 <-> max range
+ */
+int wisdom_scale(int max)
+{
+ int i = p_ptr->stat_ind[A_WIS];
+
+ return (i * max) / 37;
+}
+
+/* Find a god by name */
+int find_god(cptr name)
+{
+ int i;
+
+ for (i = 0; i < max_gods; i++)
+ {
+ /* The name matches */
+ if (streq(deity_info[i].name, name)) return (i);
+ }
+ return -1;
+}
diff --git a/src/h-basic.h b/src/h-basic.h
new file mode 100644
index 00000000..b5ea5d87
--- /dev/null
+++ b/src/h-basic.h
@@ -0,0 +1,25 @@
+/* File: h-basic.h */
+
+#ifndef INCLUDED_H_BASIC_H
+#define INCLUDED_H_BASIC_H
+
+/*
+ * The most basic "include" file.
+ *
+ * This file simply includes other low level header files.
+ */
+
+/* System Configuration */
+#include "h-config.h"
+
+/* System includes/externs */
+#include "h-system.h"
+
+/* Basic types */
+#include "h-type.h"
+
+/* Basic constants and macros */
+#include "h-define.h"
+
+#endif
+
diff --git a/src/h-config.h b/src/h-config.h
new file mode 100644
index 00000000..53670e8f
--- /dev/null
+++ b/src/h-config.h
@@ -0,0 +1,274 @@
+/* File: h-config.h */
+
+#ifndef INCLUDED_H_CONFIG_H
+#define INCLUDED_H_CONFIG_H
+
+/*
+ * Choose the hardware, operating system, and compiler.
+ * Also, choose various "system level" compilation options.
+ * A lot of these definitions take effect in "h-system.h"
+ *
+ * Note that you may find it simpler to define some of these
+ * options in the "Makefile", especially any options describing
+ * what "system" is being used.
+ */
+
+
+/*
+ * no system definitions are needed for 4.3BSD, SUN OS, DG/UX
+ */
+
+/*
+ * OPTION: Compile on a Macintosh (see "A-mac-h" or "A-mac-pch")
+ */
+#ifndef MACINTOSH
+/* #define MACINTOSH */
+#endif
+
+/*
+ * OPTION: Compile on Windows (automatic)
+ */
+#ifndef WINDOWS
+/* #define WINDOWS */
+#endif
+
+/*
+ * OPTION: Compile on a SYS III version of UNIX
+ */
+#ifndef SYS_III
+/* #define SYS_III */
+#endif
+
+/*
+ * OPTION: Compile on a SYS V version of UNIX (not Solaris)
+ */
+#ifndef SYS_V
+/* #define SYS_V */
+#endif
+
+/*
+ * OPTION: Compile on a HPUX version of UNIX
+ */
+#ifndef HPUX
+/* #define HPUX */
+#endif
+
+/*
+ * OPTION: Compile on an SGI running IRIX
+ */
+#ifndef SGI
+/* #define SGI */
+#endif
+
+/*
+ * OPTION: Compile on a SunOS machine
+ */
+#ifndef SUNOS
+/* #define SUNOS */
+#endif
+
+/*
+ * OPTION: Compile on a Solaris machine
+ */
+#ifndef SOLARIS
+/* #define SOLARIS */
+#endif
+
+/*
+ * OPTION: Compile on an ultrix/4.2BSD/Dynix/etc. version of UNIX,
+ * Do not define this if you are on any kind of SunOS.
+ */
+#ifndef ULTRIX
+/* #define ULTRIX */
+#endif
+
+
+
+/*
+ * Extract the "SUNOS" flag from the compiler
+ */
+#if defined(sun)
+# ifndef SUNOS
+# define SUNOS
+# endif
+#endif
+
+/*
+ * Extract the "ULTRIX" flag from the compiler
+ */
+#if defined(ultrix) || defined(Pyramid)
+# ifndef ULTRIX
+# define ULTRIX
+# endif
+#endif
+
+/*
+ * Extract the "ATARI" flag from the compiler [cjh]
+ */
+#if defined(__atarist) || defined(__atarist__)
+# ifndef ATARI
+# define ATARI
+# endif
+#endif
+
+/*
+ * Extract the "SGI" flag from the compiler
+ */
+#ifdef sgi
+# ifndef SGI
+# define SGI
+# endif
+#endif
+
+/*
+ * Extract the "MSDOS" flag from the compiler
+ */
+#ifdef __MSDOS__
+# ifndef MSDOS
+# define MSDOS
+# endif
+#endif
+
+/*
+ * Extract the "WINDOWS" flag from the compiler
+ */
+#if defined(_Windows) || defined(__WINDOWS__) || \
+ defined(__WIN32__) || defined(WIN32) || \
+ defined(__WINNT__) || defined(__NT__)
+# ifndef WINDOWS
+# define WINDOWS
+# endif
+#endif
+
+
+
+/*
+ * OPTION: Define "L64" if a "long" is 64-bits. See "h-types.h".
+ * The only such platform that angband is ported to is currently
+ * DEC Alpha AXP running OSF/1 (OpenVMS uses 32-bit longs).
+ */
+#if defined(__alpha) && defined(__osf__) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__ia64) || defined(__ia64__) || defined(__mips64) || defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__) || defined(__64BIT__) || defined(__sparc64__) || defined(__LP64__)
+# define L64
+#endif
+
+
+
+/*
+ * OPTION: set "SET_UID" if the machine is a "multi-user" machine.
+ * This option is used to verify the use of "uids" and "gids" for
+ * various "Unix" calls, and of "pids" for getting a random seed,
+ * and of the "umask()" call for various reasons, and to guess if
+ * the "kill()" function is available, and for permission to use
+ * functions to extract user names and expand "tildes" in filenames.
+ * It is also used for "locking" and "unlocking" the score file.
+ * Basically, SET_UID should *only* be set for "Unix" machines,
+ * or for the "Atari" platform which is Unix-like, apparently
+ */
+#if !defined(MACINTOSH) && !defined(WINDOWS) && \
+ !defined(MSDOS)
+# define SET_UID
+#endif
+
+
+/*
+ * OPTION: Set "USG" for "System V" versions of Unix
+ * This is used to choose a "lock()" function, and to choose
+ * which header files ("string.h" vs "strings.h") to include.
+ * It is also used to allow certain other options, such as options
+ * involving userid's, or multiple users on a single machine, etc.
+ */
+#ifdef SET_UID
+# if defined(SYS_III) || defined(SYS_V) || defined(SOLARIS) || \
+ defined(HPUX) || defined(SGI) || defined(ATARI)
+# ifndef USG
+# define USG
+# endif
+# endif
+#endif
+
+
+/*
+ * Every system seems to use its own symbol as a path separator.
+ * Default to the standard Unix slash, but attempt to change this
+ * for various other systems. Note that any system that uses the
+ * "period" as a separator (i.e. ACORN) will have to pretend that
+ * it uses the slash, and do its own mapping of period <-> slash.
+ */
+#undef PATH_SEP
+#define PATH_SEP "/"
+#ifdef MACINTOSH
+# undef PATH_SEP
+# define PATH_SEP ":"
+#endif
+#if defined(WINDOWS) || defined(WINNT)
+# undef PATH_SEP
+# define PATH_SEP "\\"
+#endif
+#if defined(MSDOS) || defined(OS2)
+# undef PATH_SEP
+# define PATH_SEP "\\"
+#endif
+#ifdef __GO32__
+# undef PATH_SEP
+# define PATH_SEP "/"
+#endif
+
+
+/*
+ * The Macintosh allows the use of a "file type" when creating a file
+ */
+#if defined(MACINTOSH) && !defined(applec) || defined(MACH_O_CARBON)
+# define FILE_TYPE_TEXT 'TEXT'
+# define FILE_TYPE_DATA 'DATA'
+# define FILE_TYPE_SAVE 'SAVE'
+# define FILE_TYPE(X) (_ftype = (X))
+#else
+# define FILE_TYPE(X) ((void)0)
+#endif
+
+
+/*
+ * OPTION: Hack -- Make sure "strchr()" and "strrchr()" will work
+ */
+#if defined(SYS_III) || defined(SYS_V) || defined(MSDOS)
+# if !defined(__TURBOC__) && !defined(__WATCOMC__)
+# define strchr index
+# define strrchr rindex
+# endif
+#endif
+
+
+/*
+ * OPTION: Define "HAS_STRICMP" only if "stricmp()" exists.
+ * Note that "stricmp()" is not actually used by Angband.
+ */
+/* #define HAS_STRICMP */
+
+/*
+ * Linux has "stricmp()" with a different name
+ */
+#if defined(linux)
+# define HAS_STRICMP
+# define stricmp strcasecmp
+#endif
+
+
+/*
+ * OPTION: Define "HAS_MEMSET" only if "memset()" exists.
+ * Note that the "memset()" routines are used in "z-virt.h"
+ */
+#define HAS_MEMSET
+
+
+/*
+ * OPTION: Define "HAS_USLEEP" only if "usleep()" exists.
+ * Note that this is only relevant for "SET_UID" machines
+ */
+#ifdef SET_UID
+# if !defined(HPUX) && !defined(ULTRIX) && !defined(SOLARIS) && \
+ !defined(SGI) && !defined(ISC)
+# define HAS_USLEEP
+# endif
+#endif
+
+#endif
diff --git a/src/h-define.h b/src/h-define.h
new file mode 100644
index 00000000..cb36b189
--- /dev/null
+++ b/src/h-define.h
@@ -0,0 +1,111 @@
+/* File: h-define.h */
+
+#ifndef INCLUDED_H_DEFINE_H
+#define INCLUDED_H_DEFINE_H
+
+/*
+ * Define some simple constants
+ */
+
+
+/*
+ * Hack -- Define NULL
+ */
+#ifndef NULL
+# ifdef __STDC__
+# define NULL ((void*)0)
+# else
+# define NULL ((char*)0)
+# endif /* __STDC__ */
+#endif /* NULL */
+
+
+/*
+ * Hack -- force definitions -- see fd_seek()
+ */
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+/*
+ * Hack -- force definitions -- see fd_lock() XXX XXX XXX
+ */
+#ifndef F_UNLCK
+# define F_UNLCK 0
+#endif
+#ifndef F_RDLCK
+# define F_RDLCK 1
+#endif
+#ifndef F_WRLCK
+# define F_WRLCK 2
+#endif
+
+
+/*
+ * The constants "TRUE" and "FALSE"
+ */
+
+#undef TRUE
+#define TRUE 1
+
+#undef FALSE
+#define FALSE 0
+
+
+
+
+/**** Simple "Macros" ****/
+
+/*
+ * Force a character to lowercase/uppercase
+ */
+#define FORCELOWER(A) ((isupper((A))) ? tolower((A)) : (A))
+#define FORCEUPPER(A) ((islower((A))) ? toupper((A)) : (A))
+
+
+/*
+ * Non-typed minimum value macro
+ */
+#undef MIN
+#define MIN(a,b) (((a) > (b)) ? (b) : (a))
+
+/*
+ * Non-typed maximum value macro
+ */
+#undef MAX
+#define MAX(a,b) (((a) < (b)) ? (b) : (a))
+
+/*
+ * Non-typed absolute value macro
+ */
+#undef ABS
+#define ABS(a) (((a) < 0) ? (-(a)) : (a))
+
+/*
+ * Non-typed sign extractor macro
+ */
+#undef SGN
+#define SGN(a) (((a) < 0) ? (-1) : ((a) != 0))
+
+
+/*
+ * Note that all "index" values must be "lowercase letters", while
+ * all "digits" must be "digits". Control characters can be made
+ * from any legal characters. XXX XXX XXX
+ */
+#define A2I(X) ((X) - 'a')
+#define I2A(X) ((X) + 'a')
+#define D2I(X) ((X) - '0')
+#define I2D(X) ((X) + '0')
+#define KTRL(X) ((X) & 0x1F)
+#define ESCAPE '\033'
+
+
+#endif
+
diff --git a/src/h-system.h b/src/h-system.h
new file mode 100644
index 00000000..50cc0af8
--- /dev/null
+++ b/src/h-system.h
@@ -0,0 +1,138 @@
+/* File: h-system.h */
+
+#ifndef INCLUDED_H_SYSTEM_H
+#define INCLUDED_H_SYSTEM_H
+
+/*
+ * Include the basic "system" files.
+ *
+ * Make sure all "system" constants/macros are defined.
+ * Make sure all "system" functions have "extern" declarations.
+ *
+ * This file is a big hack to make other files less of a hack.
+ * This file has been rebuilt -- it may need a little more work.
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#if defined(NeXT)
+# include <libc.h>
+#else
+# include <stdlib.h>
+#endif
+
+
+#ifdef SET_UID
+
+# include <sys/types.h>
+
+# if defined(Pyramid) || defined(NeXT) || defined(SUNOS) || \
+ defined(NCR3K) || defined(SUNOS) || defined(ibm032) || \
+ defined(__osf__) || defined(ISC) || defined(SGI) || \
+ defined(linux)
+# include <sys/time.h>
+# endif
+
+# if !defined(SGI) && !defined(ULTRIX)
+# include <sys/timeb.h>
+# endif
+
+#endif
+
+
+#include <time.h>
+
+
+
+#ifdef MACINTOSH
+# include <unix.h>
+#endif
+
+#if defined(WINDOWS) || defined(MSDOS)
+# include <io.h>
+#endif
+
+#if !defined(MACINTOSH) && \
+ !defined(__MWERKS__)
+# if defined(__TURBOC__) || defined(__WATCOMC__)
+# include <mem.h>
+# else
+# include <memory.h>
+# endif
+#endif
+
+
+#if !defined(NeXT) && !defined(__MWERKS__)
+# include <fcntl.h>
+#endif
+
+
+#ifdef SET_UID
+
+# ifndef USG
+# include <sys/param.h>
+# include <sys/file.h>
+# endif
+
+# ifdef linux
+# include <sys/file.h>
+# endif
+
+# include <pwd.h>
+
+# include <unistd.h>
+
+# include <sys/stat.h>
+
+# if defined(SOLARIS)
+# include <netdb.h>
+# endif
+
+#endif
+
+#ifdef __DJGPP__
+#include <unistd.h>
+#endif /* __DJGPP__ */
+
+#ifdef SET_UID
+
+#ifdef USG
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef strstr
+extern char *strstr();
+# endif
+# ifndef strchr
+extern char *strchr();
+# endif
+# ifndef strrchr
+extern char *strrchr();
+# endif
+#endif
+
+#else
+
+# include <string.h>
+
+#endif
+
+
+
+#if !defined(linux) && !defined(__MWERKS__)
+extern long atol();
+#endif
+
+
+#include <stdarg.h>
+
+
+#endif
+
+/* There was a bug introduced in 10.4.11; working around it */
+#ifdef __APPLE__
+#define GETLOGIN_BROKEN
+#endif
diff --git a/src/h-type.h b/src/h-type.h
new file mode 100644
index 00000000..5dbb4975
--- /dev/null
+++ b/src/h-type.h
@@ -0,0 +1,178 @@
+/* File: h-type.h */
+
+#ifndef INCLUDED_H_TYPE_H
+#define INCLUDED_H_TYPE_H
+
+/*
+ * Basic "types".
+ *
+ * Note the attempt to make all basic types have 4 letters.
+ * This improves readibility and standardizes the code.
+ *
+ * Likewise, all complex types are at least 4 letters.
+ * Thus, almost every three letter word is a legal variable.
+ * But beware of certain reserved words ('for' and 'if' and 'do').
+ *
+ * Note that the type used in structures for bit flags should be uint.
+ * As long as these bit flags are sequential, they will be space smart.
+ *
+ * Note that on some machines, apparently "signed char" is illegal.
+ *
+ * It must be true that char/byte takes exactly 1 byte
+ * It must be true that sind/uind takes exactly 2 bytes
+ * It must be true that sbig/ubig takes exactly 4 bytes
+ *
+ * On Sparc's, a sint takes 4 bytes (2 is legal)
+ * On Sparc's, a uint takes 4 bytes (2 is legal)
+ * On Sparc's, a long takes 4 bytes (8 is legal)
+ * On Sparc's, a huge takes 4 bytes (8 is legal)
+ * On Sparc's, a vptr takes 4 bytes (8 is legal)
+ * On Sparc's, a real takes 8 bytes (4 is legal)
+ *
+ * Note that some files have already been included by "h-include.h"
+ * These include <stdio.h> and <sys/types>, which define some types
+ * In particular, uint is defined so we do not have to define it
+ *
+ * Also, see <limits.h> for min/max values for sind, uind, long, huge
+ * (SHRT_MIN, SHRT_MAX, USHRT_MAX, LONG_MIN, LONG_MAX, ULONG_MAX)
+ * These limits should be verified and coded into "h-constant.h".
+ */
+
+
+
+/*** Special 4 letter names for some standard types ***/
+
+
+/* A standard pointer (to "void" because ANSI C says so) */
+typedef void *vptr;
+
+/* A simple pointer (to unmodifiable strings) */
+typedef const char *cptr;
+typedef char *mcptr;
+
+
+/* Since float's are silly, hard code real numbers as doubles */
+typedef double real;
+
+
+/* Error codes for function return values */
+/* Success = 0, Failure = -N, Problem = +N */
+typedef int errr;
+
+
+/*
+ * Hack -- prevent problems with non-MACINTOSH
+ */
+#undef uint
+#define uint uint_hack
+
+/*
+ * Hack -- prevent problems with MSDOS and WINDOWS
+ */
+#undef huge
+#define huge huge_hack
+
+/*
+ * Hack -- prevent problems with AMIGA
+ */
+#undef byte
+#define byte byte_hack
+
+/* Note that "signed char" is not always "defined" */
+/* So always use "s16b" to hold small signed values */
+/* A signed byte of memory */
+/* typedef signed char syte; */
+
+/* Note that unsigned values can cause math problems */
+/* An unsigned byte of memory */
+typedef unsigned char byte;
+
+/* Note that a bool is smaller than a full "int" */
+/* Simple True/False type */
+typedef char bool_;
+
+
+/* A signed, standard integer (at least 2 bytes) */
+typedef int sint;
+
+/* An unsigned, "standard" integer (often pre-defined) */
+typedef unsigned int uint;
+
+
+/* The largest possible signed integer (pre-defined) */
+/* typedef long long; */
+
+/* The largest possible unsigned integer */
+typedef unsigned long huge;
+
+
+/* Signed/Unsigned 16 bit value */
+typedef signed short s16b;
+typedef unsigned short u16b;
+
+/* Signed/Unsigned 32 bit value */
+#ifdef L64 /* 64 bit longs */
+typedef signed int s32b;
+typedef unsigned int u32b;
+#else
+typedef signed long s32b;
+typedef unsigned long u32b;
+#endif
+
+
+/*** Pointers to all the basic types defined above ***/
+
+typedef real *real_ptr;
+typedef errr *errr_ptr;
+typedef char *char_ptr;
+typedef byte *byte_ptr;
+typedef bool_ *bool_ptr;
+typedef sint *sint_ptr;
+typedef uint *uint_ptr;
+typedef long *long_ptr;
+typedef huge *huge_ptr;
+typedef s16b *s16b_ptr;
+typedef u16b *u16b_ptr;
+typedef s32b *s32b_ptr;
+typedef u32b *u32b_ptr;
+typedef vptr *vptr_ptr;
+typedef cptr *cptr_ptr;
+
+
+
+/*** Pointers to Functions with simple return types and any args ***/
+
+typedef void (*func_void)();
+typedef errr (*func_errr)();
+typedef char (*func_char)();
+typedef byte (*func_byte)();
+typedef bool_ (*func_bool)();
+typedef sint (*func_sint)();
+typedef uint (*func_uint)();
+typedef real (*func_real)();
+typedef vptr (*func_vptr)();
+typedef cptr (*func_cptr)();
+
+
+
+/*** Pointers to Functions of special types (for various purposes) ***/
+
+/* A generic function takes a user data and a special data */
+typedef errr (*func_gen)(vptr, vptr);
+
+/* An equality testing function takes two things to compare (bool) */
+typedef bool_ (*func_eql)(vptr, vptr);
+
+/* A comparison function takes two things and to compare (-1,0,+1) */
+typedef sint (*func_cmp)(vptr, vptr);
+
+/* A hasher takes a thing (and a max hash size) to hash (0 to siz - 1) */
+typedef uint (*func_hsh)(vptr, uint);
+
+/* A key extractor takes a thing and returns (a pointer to) some key */
+typedef vptr (*func_key)(vptr);
+
+
+
+#endif
+
diff --git a/src/help.c b/src/help.c
new file mode 100644
index 00000000..d0bdbedf
--- /dev/null
+++ b/src/help.c
@@ -0,0 +1,23 @@
+/* File: help.c */
+
+/* Purpose: ingame help */
+/*
+ * Actually this is now handled by lua,
+ * I'll remove this file when I feel un-lazy
+ */
+
+/*
+ * Copyright (c) 2001 DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * Driver for the context-sensitive help system
+ */
+void ingame_help(bool_ enable)
+{}
diff --git a/src/init1.c b/src/init1.c
new file mode 100644
index 00000000..9715831d
--- /dev/null
+++ b/src/init1.c
@@ -0,0 +1,11819 @@
+/* File: init1.c */
+
+/* Purpose: Initialization (part 1) -BEN- */
+
+#include "angband.h"
+
+
+/*
+ * This file is used to initialize various variables and arrays for the
+ * Angband game. Note the use of "fd_read()" and "fd_write()" to bypass
+ * the common limitation of "read()" and "write()" to only 32767 bytes
+ * at a time.
+ *
+ * Several of the arrays for Angband are built from "template" files in
+ * the "lib/file" directory, from which quick-load binary "image" files
+ * are constructed whenever they are not present in the "lib/data"
+ * directory, or if those files become obsolete, if we are allowed.
+ *
+ * Warning -- the "ascii" file parsers use a minor hack to collect the
+ * name and text information in a single pass. Thus, the game will not
+ * be able to load any template file with more than 20K of names or 60K
+ * of text, even though technically, up to 64K should be legal.
+ */
+
+
+/*** Helper arrays for parsing ascii template files ***/
+
+/*
+ * Monster Blow Methods
+ */
+static cptr r_info_blow_method[] =
+{
+ "*",
+ "HIT",
+ "TOUCH",
+ "PUNCH",
+ "KICK",
+ "CLAW",
+ "BITE",
+ "STING",
+ "XXX1",
+ "BUTT",
+ "CRUSH",
+ "ENGULF",
+ "CHARGE",
+ "CRAWL",
+ "DROOL",
+ "SPIT",
+ "EXPLODE",
+ "GAZE",
+ "WAIL",
+ "SPORE",
+ "XXX4",
+ "BEG",
+ "INSULT",
+ "MOAN",
+ "SHOW",
+ NULL
+};
+
+
+/*
+ * Monster Blow Effects
+ */
+static cptr r_info_blow_effect[] =
+{
+ "*",
+ "HURT",
+ "POISON",
+ "UN_BONUS",
+ "UN_POWER",
+ "EAT_GOLD",
+ "EAT_ITEM",
+ "EAT_FOOD",
+ "EAT_LITE",
+ "ACID",
+ "ELEC",
+ "FIRE",
+ "COLD",
+ "BLIND",
+ "CONFUSE",
+ "TERRIFY",
+ "PARALYZE",
+ "LOSE_STR",
+ "LOSE_INT",
+ "LOSE_WIS",
+ "LOSE_DEX",
+ "LOSE_CON",
+ "LOSE_CHR",
+ "LOSE_ALL",
+ "SHATTER",
+ "EXP_10",
+ "EXP_20",
+ "EXP_40",
+ "EXP_80",
+ "DISEASE",
+ "TIME",
+ "INSANITY",
+ "HALLU",
+ "PARASITE",
+ "ABOMINATION",
+ NULL
+};
+
+
+/*
+ * Monster race flags
+ */
+static cptr r_info_flags1[] =
+{
+ "UNIQUE",
+ "QUESTOR",
+ "MALE",
+ "FEMALE",
+ "CHAR_CLEAR",
+ "CHAR_MULTI",
+ "ATTR_CLEAR",
+ "ATTR_MULTI",
+ "FORCE_DEPTH",
+ "FORCE_MAXHP",
+ "FORCE_SLEEP",
+ "FORCE_EXTRA",
+ "FRIEND",
+ "FRIENDS",
+ "ESCORT",
+ "ESCORTS",
+ "NEVER_BLOW",
+ "NEVER_MOVE",
+ "RAND_25",
+ "RAND_50",
+ "ONLY_GOLD",
+ "ONLY_ITEM",
+ "DROP_60",
+ "DROP_90",
+ "DROP_1D2",
+ "DROP_2D2",
+ "DROP_3D2",
+ "DROP_4D2",
+ "DROP_GOOD",
+ "DROP_GREAT",
+ "DROP_USEFUL",
+ "DROP_CHOSEN"
+};
+
+/*
+ * Monster race flags
+ */
+static cptr r_info_flags2[] =
+{
+ "STUPID",
+ "SMART",
+ "CAN_SPEAK",
+ "REFLECTING",
+ "INVISIBLE",
+ "COLD_BLOOD",
+ "EMPTY_MIND",
+ "WEIRD_MIND",
+ "DEATH_ORB",
+ "REGENERATE",
+ "SHAPECHANGER",
+ "ATTR_ANY",
+ "POWERFUL",
+ "ELDRITCH_HORROR",
+ "AURA_FIRE",
+ "AURA_ELEC",
+ "OPEN_DOOR",
+ "BASH_DOOR",
+ "PASS_WALL",
+ "KILL_WALL",
+ "MOVE_BODY",
+ "KILL_BODY",
+ "TAKE_ITEM",
+ "KILL_ITEM",
+ "BRAIN_1",
+ "BRAIN_2",
+ "BRAIN_3",
+ "BRAIN_4",
+ "BRAIN_5",
+ "BRAIN_6",
+ "BRAIN_7",
+ "BRAIN_8"
+};
+
+/*
+ * Monster race flags
+ */
+static cptr r_info_flags3[] =
+{
+ "ORC",
+ "TROLL",
+ "GIANT",
+ "DRAGON",
+ "DEMON",
+ "UNDEAD",
+ "EVIL",
+ "ANIMAL",
+ "THUNDERLORD",
+ "GOOD",
+ "AURA_COLD", /* TODO: Implement aura_cold */
+ "NONLIVING",
+ "HURT_LITE",
+ "HURT_ROCK",
+ "SUSCEP_FIRE",
+ "SUSCEP_COLD",
+ "IM_ACID",
+ "IM_ELEC",
+ "IM_FIRE",
+ "IM_COLD",
+ "IM_POIS",
+ "RES_TELE",
+ "RES_NETH",
+ "RES_WATE",
+ "RES_PLAS",
+ "RES_NEXU",
+ "RES_DISE",
+ "UNIQUE_4",
+ "NO_FEAR",
+ "NO_STUN",
+ "NO_CONF",
+ "NO_SLEEP"
+};
+
+/*
+ * Monster race flags
+ */
+static cptr r_info_flags4[] =
+{
+ "SHRIEK",
+ "MULTIPLY",
+ "S_ANIMAL",
+ "ROCKET",
+ "ARROW_1",
+ "ARROW_2",
+ "ARROW_3",
+ "ARROW_4",
+ "BR_ACID",
+ "BR_ELEC",
+ "BR_FIRE",
+ "BR_COLD",
+ "BR_POIS",
+ "BR_NETH",
+ "BR_LITE",
+ "BR_DARK",
+ "BR_CONF",
+ "BR_SOUN",
+ "BR_CHAO",
+ "BR_DISE",
+ "BR_NEXU",
+ "BR_TIME",
+ "BR_INER",
+ "BR_GRAV",
+ "BR_SHAR",
+ "BR_PLAS",
+ "BR_WALL",
+ "BR_MANA",
+ "BA_NUKE",
+ "BR_NUKE",
+ "BA_CHAO",
+ "BR_DISI",
+};
+
+/*
+ * Monster race flags
+ */
+static cptr r_info_flags5[] =
+{
+ "BA_ACID",
+ "BA_ELEC",
+ "BA_FIRE",
+ "BA_COLD",
+ "BA_POIS",
+ "BA_NETH",
+ "BA_WATE",
+ "BA_MANA",
+ "BA_DARK",
+ "DRAIN_MANA",
+ "MIND_BLAST",
+ "BRAIN_SMASH",
+ "CAUSE_1",
+ "CAUSE_2",
+ "CAUSE_3",
+ "CAUSE_4",
+ "BO_ACID",
+ "BO_ELEC",
+ "BO_FIRE",
+ "BO_COLD",
+ "BO_POIS",
+ "BO_NETH",
+ "BO_WATE",
+ "BO_MANA",
+ "BO_PLAS",
+ "BO_ICEE",
+ "MISSILE",
+ "SCARE",
+ "BLIND",
+ "CONF",
+ "SLOW",
+ "HOLD"
+};
+
+/*
+ * Monster race flags
+ */
+static cptr r_info_flags6[] =
+{
+ "HASTE",
+ "HAND_DOOM",
+ "HEAL",
+ "S_ANIMALS",
+ "BLINK",
+ "TPORT",
+ "TELE_TO",
+ "TELE_AWAY",
+ "TELE_LEVEL",
+ "DARKNESS",
+ "TRAPS",
+ "FORGET",
+ "ANIM_DEAD", /* ToDo: Implement ANIM_DEAD */
+ "S_BUG",
+ "S_RNG",
+ "S_THUNDERLORD", /* DG : Summon Thunderlord */
+ "S_KIN",
+ "S_HI_DEMON",
+ "S_MONSTER",
+ "S_MONSTERS",
+ "S_ANT",
+ "S_SPIDER",
+ "S_HOUND",
+ "S_HYDRA",
+ "S_ANGEL",
+ "S_DEMON",
+ "S_UNDEAD",
+ "S_DRAGON",
+ "S_HI_UNDEAD",
+ "S_HI_DRAGON",
+ "S_WRAITH",
+ "S_UNIQUE"
+};
+
+
+/*
+ * Monster race flags
+ */
+static cptr r_info_flags7[] =
+{
+ "AQUATIC",
+ "CAN_SWIM",
+ "CAN_FLY",
+ "FRIENDLY",
+ "PET",
+ "MORTAL",
+ "SPIDER",
+ "NAZGUL",
+ "DG_CURSE",
+ "POSSESSOR",
+ "NO_DEATH",
+ "NO_TARGET",
+ "AI_ANNOY",
+ "AI_SPECIAL",
+ "NEUTRAL",
+ "DROP_ART",
+ "DROP_RANDART",
+ "AI_PLAYER",
+ "NO_THEFT",
+ "SPIRIT",
+ "IM_MELEE",
+ "XXX7X21",
+ "XXX7X22",
+ "XXX7X23",
+ "XXX7X24",
+ "XXX7X25",
+ "XXX7X26",
+ "XXX7X27",
+ "XXX7X28",
+ "XXX7X29",
+ "XXX7X30",
+ "XXX7X31",
+};
+
+/*
+ * Monster race flags
+ */
+static cptr r_info_flags8[] =
+{
+ "WILD_ONLY",
+ "WILD_TOWN",
+ "XXX8X02",
+ "WILD_SHORE",
+ "WILD_OCEAN",
+ "WILD_WASTE",
+ "WILD_WOOD",
+ "WILD_VOLCANO",
+ "XXX8X08",
+ "WILD_MOUNTAIN",
+ "WILD_GRASS",
+ "NO_CUT",
+ "CTHANGBAND",
+ "XXX8X13",
+ "ZANGBAND",
+ "JOKEANGBAND",
+ "BASEANGBAND",
+ "XXX8X17",
+ "XXX8X18",
+ "XXX8X19",
+ "XXX8X20",
+ "XXX8X21",
+ "XXX8X22",
+ "XXX8X23",
+ "XXX8X24",
+ "XXX8X25",
+ "XXX8X26",
+ "XXX8X27",
+ "XXX8X28",
+ "XXX8X29",
+ "WILD_SWAMP", /* ToDo: Implement Swamp */
+ "WILD_TOO",
+};
+
+
+/*
+ * Monster race flags - Drops
+ */
+static cptr r_info_flags9[] =
+{
+ "DROP_CORPSE",
+ "DROP_SKELETON",
+ "HAS_LITE",
+ "MIMIC",
+ "HAS_EGG",
+ "IMPRESED",
+ "SUSCEP_ACID",
+ "SUSCEP_ELEC",
+ "SUSCEP_POIS",
+ "KILL_TREES",
+ "WYRM_PROTECT",
+ "DOPPLEGANGER",
+ "ONLY_DEPTH",
+ "SPECIAL_GENE",
+ "NEVER_GENE",
+ "XXX9X15",
+ "XXX9X16",
+ "XXX9X17",
+ "XXX9X18",
+ "XXX9X19",
+ "XXX9X20",
+ "XXX9X21",
+ "XXX9X22",
+ "XXX9X23",
+ "XXX9X24",
+ "XXX9X25",
+ "XXX9X26",
+ "XXX9X27",
+ "XXX9X28",
+ "XXX9X29",
+ "XXX9X30",
+ "XXX9X31",
+};
+
+
+/*
+ * Object flags
+ */
+cptr k_info_flags1[] =
+{
+ "STR",
+ "INT",
+ "WIS",
+ "DEX",
+ "CON",
+ "CHR",
+ "MANA",
+ "SPELL",
+ "STEALTH",
+ "SEARCH",
+ "INFRA",
+ "TUNNEL",
+ "SPEED",
+ "BLOWS",
+ "CHAOTIC",
+ "VAMPIRIC",
+ "SLAY_ANIMAL",
+ "SLAY_EVIL",
+ "SLAY_UNDEAD",
+ "SLAY_DEMON",
+ "SLAY_ORC",
+ "SLAY_TROLL",
+ "SLAY_GIANT",
+ "SLAY_DRAGON",
+ "KILL_DRAGON",
+ "VORPAL",
+ "IMPACT",
+ "BRAND_POIS",
+ "BRAND_ACID",
+ "BRAND_ELEC",
+ "BRAND_FIRE",
+ "BRAND_COLD"
+};
+
+/*
+ * Object flags
+ */
+cptr k_info_flags2[] =
+{
+ "SUST_STR",
+ "SUST_INT",
+ "SUST_WIS",
+ "SUST_DEX",
+ "SUST_CON",
+ "SUST_CHR",
+ "INVIS",
+ "LIFE",
+ "IM_ACID",
+ "IM_ELEC",
+ "IM_FIRE",
+ "IM_COLD",
+ "SENS_FIRE",
+ "REFLECT",
+ "FREE_ACT",
+ "HOLD_LIFE",
+ "RES_ACID",
+ "RES_ELEC",
+ "RES_FIRE",
+ "RES_COLD",
+ "RES_POIS",
+ "RES_FEAR",
+ "RES_LITE",
+ "RES_DARK",
+ "RES_BLIND",
+ "RES_CONF",
+ "RES_SOUND",
+ "RES_SHARDS",
+ "RES_NETHER",
+ "RES_NEXUS",
+ "RES_CHAOS",
+ "RES_DISEN"
+};
+
+/*
+ * Trap flags
+ */
+cptr k_info_flags2_trap[] =
+{
+ "AUTOMATIC_5",
+ "AUTOMATIC_99",
+ "KILL_GHOST",
+ "TELEPORT_TO",
+ "ONLY_DRAGON",
+ "ONLY_DEMON",
+ "XXX3",
+ "XXX3",
+ "ONLY_ANIMAL",
+ "ONLY_UNDEAD",
+ "ONLY_EVIL",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+ "XXX3",
+};
+
+
+/*
+ * Object flags
+ */
+cptr k_info_flags3[] =
+{
+ "SH_FIRE",
+ "SH_ELEC",
+ "AUTO_CURSE",
+ "DECAY",
+ "NO_TELE",
+ "NO_MAGIC",
+ "WRAITH",
+ "TY_CURSE",
+ "EASY_KNOW",
+ "HIDE_TYPE",
+ "SHOW_MODS",
+ "INSTA_ART",
+ "FEATHER",
+ "LITE1",
+ "SEE_INVIS",
+ "NORM_ART",
+ "SLOW_DIGEST",
+ "REGEN",
+ "XTRA_MIGHT",
+ "XTRA_SHOTS",
+ "IGNORE_ACID",
+ "IGNORE_ELEC",
+ "IGNORE_FIRE",
+ "IGNORE_COLD",
+ "ACTIVATE",
+ "DRAIN_EXP",
+ "TELEPORT",
+ "AGGRAVATE",
+ "BLESSED",
+ "CURSED",
+ "HEAVY_CURSE",
+ "PERMA_CURSE"
+};
+
+/*
+ * Object flags
+ */
+cptr k_info_flags4[] =
+{
+ "NEVER_BLOW",
+ "PRECOGNITION",
+ "BLACK_BREATH",
+ "RECHARGE",
+ "FLY",
+ "DG_CURSE",
+ "COULD2H",
+ "MUST2H",
+ "LEVELS",
+ "CLONE",
+ "SPECIAL_GENE",
+ "CLIMB",
+ "FAST_CAST",
+ "CAPACITY",
+ "CHARGING",
+ "CHEAPNESS",
+ "FOUNTAIN",
+ "ANTIMAGIC_50",
+ "ANTIMAGIC_30",
+ "ANTIMAGIC_20",
+ "ANTIMAGIC_10",
+ "EASY_USE",
+ "IM_NETHER",
+ "RECHARGED",
+ "ULTIMATE",
+ "AUTO_ID",
+ "LITE2",
+ "LITE3",
+ "FUEL_LITE",
+ "ART_EXP",
+ "CURSE_NO_DROP",
+ "NO_RECHARGE"
+};
+
+/*
+ * Object flags
+ */
+cptr k_info_flags5[] =
+{
+ "TEMPORARY",
+ "DRAIN_MANA",
+ "DRAIN_HP",
+ "KILL_DEMON",
+ "KILL_UNDEAD",
+ "CRIT",
+ "ATTR_MULTI",
+ "WOUNDING",
+ "FULL_NAME",
+ "LUCK",
+ "IMMOVABLE",
+ "SPELL_CONTAIN",
+ "RES_MORGUL",
+ "ACTIVATE_NO_WIELD",
+ "MAGIC_BREATH",
+ "WATER_BREATH",
+ "WIELD_CAST",
+ "XXX8X17",
+ "XXX8X18",
+ "XXX8X19",
+ "XXX8X20",
+ "XXX8X21",
+ "XXX8X22",
+ "XXX8X23",
+ "XXX8X24",
+ "XXX8X25",
+ "XXX8X26",
+ "XXX8X27",
+ "XXX8X28",
+ "XXX8X29",
+ "XXX8X02",
+ "XXX8X22",
+};
+
+/*
+ * ESP flags
+ */
+cptr esp_flags[] =
+{
+ "ESP_ORC",
+ "ESP_TROLL",
+ "ESP_DRAGON",
+ "ESP_GIANT",
+ "ESP_DEMON",
+ "ESP_UNDEAD",
+ "ESP_EVIL",
+ "ESP_ANIMAL",
+ "ESP_THUNDERLORD",
+ "ESP_GOOD",
+ "ESP_NONLIVING",
+ "ESP_UNIQUE",
+ "ESP_SPIDER",
+ "XXX8X02",
+ "XXX8X02",
+ "XXX8X02",
+ "XXX8X02",
+ "XXX8X17",
+ "XXX8X18",
+ "XXX8X19",
+ "XXX8X20",
+ "XXX8X21",
+ "XXX8X22",
+ "XXX8X23",
+ "XXX8X24",
+ "XXX8X25",
+ "XXX8X26",
+ "XXX8X27",
+ "XXX8X28",
+ "XXX8X29",
+ "XXX8X02",
+ "ESP_ALL",
+};
+
+/* Specially handled properties for ego-items */
+
+static cptr ego_flags[] =
+{
+ "SUSTAIN",
+ "OLD_RESIST",
+ "ABILITY",
+ "R_ELEM",
+ "R_LOW",
+ "R_HIGH",
+ "R_ANY",
+ "R_DRAGON",
+ "SLAY_WEAP",
+ "DAM_DIE",
+ "DAM_SIZE",
+ "PVAL_M1",
+ "PVAL_M2",
+ "PVAL_M3",
+ "PVAL_M5",
+ "AC_M1",
+ "AC_M2",
+ "AC_M3",
+ "AC_M5",
+ "TH_M1",
+ "TH_M2",
+ "TH_M3",
+ "TH_M5",
+ "TD_M1",
+ "TD_M2",
+ "TD_M3",
+ "TD_M5",
+ "R_P_ABILITY",
+ "R_STAT",
+ "R_STAT_SUST",
+ "R_IMMUNITY",
+ "LIMIT_BLOWS"
+};
+
+/*
+ * Feature flags
+ */
+static cptr f_info_flags1[] =
+{
+ "NO_WALK",
+ "NO_VISION",
+ "CAN_LEVITATE",
+ "CAN_PASS",
+ "FLOOR",
+ "WALL",
+ "PERMANENT",
+ "CAN_FLY",
+ "REMEMBER",
+ "NOTICE",
+ "DONT_NOTICE_RUNNING",
+ "CAN_RUN",
+ "DOOR",
+ "SUPPORT_LIGHT",
+ "CAN_CLIMB",
+ "TUNNELABLE",
+ "WEB",
+ "ATTR_MULTI",
+ "SUPPORT_GROWTH",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1"
+};
+
+/*
+ * Dungeon flags
+ */
+static cptr d_info_flags1[] =
+{
+ "PRINCIPAL",
+ "MAZE",
+ "SMALLEST",
+ "SMALL",
+ "BIG",
+ "NO_DOORS",
+ "WATER_RIVER",
+ "LAVA_RIVER",
+ "WATER_RIVERS",
+ "LAVA_RIVERS",
+ "CAVE",
+ "CAVERN",
+ "NO_UP",
+ "HOT",
+ "COLD",
+ "FORCE_DOWN",
+ "FORGET",
+ "NO_DESTROY",
+ "SAND_VEIN",
+ "CIRCULAR_ROOMS",
+ "EMPTY",
+ "DAMAGE_FEAT",
+ "FLAT",
+ "TOWER",
+ "RANDOM_TOWNS",
+ "DOUBLE",
+ "LIFE_LEVEL",
+ "EVOLVE",
+ "ADJUST_LEVEL_1",
+ "ADJUST_LEVEL_2",
+ "NO_RECALL",
+ "NO_STREAMERS"
+};
+
+static cptr d_info_flags2[] =
+{
+ "ADJUST_LEVEL_1_2",
+ "NO_SHAFT",
+ "ADJUST_LEVEL_PLAYER",
+ "NO_TELEPORT",
+ "ASK_LEAVE",
+ "NO_STAIR",
+ "SPECIAL",
+ "NO_NEW_MONSTER",
+ "DESC",
+ "NO_GENO",
+ "NO_BREATH",
+ "WATER_BREATH",
+ "ELVEN",
+ "DWARVEN",
+ "NO_EASY_MOVE",
+ "NO_RECALL_OUT",
+ "DESC_ALWAYS",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1"
+};
+
+/*
+ * Trap flags
+ */
+static cptr t_info_flags[] =
+{
+ "CHEST",
+ "DOOR",
+ "FLOOR",
+ "XXX4",
+ "XXX5",
+ "XXX6",
+ "XXX7",
+ "XXX8",
+ "XXX9",
+ "XXX10",
+ "XXX11",
+ "XXX12",
+ "XXX13",
+ "XXX14",
+ "XXX15",
+ "XXX16",
+ "LEVEL1",
+ "LEVEL2",
+ "LEVEL3",
+ "LEVEL4",
+ "XXX21",
+ "XXX22",
+ "XXX23",
+ "XXX24",
+ "XXX25",
+ "XXX26",
+ "XXX27",
+ "XXX28",
+ "XXX29",
+ "XXX30",
+ "XXX31",
+ "XXX32"
+};
+
+/*
+ * Wilderness feature flags
+ */
+static cptr wf_info_flags1[] =
+{
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1"
+};
+
+/*
+ * Stores flags
+ */
+static cptr st_info_flags1[] =
+{
+ "DEPEND_LEVEL",
+ "SHALLOW_LEVEL",
+ "MEDIUM_LEVEL",
+ "DEEP_LEVEL",
+ "RARE",
+ "VERY_RARE",
+ "COMMON",
+ "ALL_ITEM",
+ "RANDOM",
+ "FORCE_LEVEL",
+ "MUSEUM",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1"
+};
+
+/*
+ * Race flags
+ */
+cptr rp_info_flags1[] =
+{
+ "EXPERIMENTAL",
+ "XXX",
+ "RESIST_BLACK_BREATH",
+ "NO_STUN",
+ "XTRA_MIGHT_BOW",
+ "XTRA_MIGHT_XBOW",
+ "XTRA_MIGHT_SLING",
+ "AC_LEVEL",
+ "HURT_LITE",
+ "VAMPIRE",
+ "UNDEAD",
+ "NO_CUT",
+ "CORRUPT",
+ "NO_FOOD",
+ "NO_GOD",
+ "XXX",
+ "ELF",
+ "SEMI_WRAITH",
+ "NO_SUBRACE_CHANGE",
+ "XXX",
+ "XXX",
+ "MOLD_FRIEND",
+ "GOD_FRIEND",
+ "XXX",
+ "INNATE_SPELLS",
+ "XXX",
+ "XXX",
+ "EASE_STEAL",
+ "XXX",
+ "XXX",
+ "XXX",
+ "XXX"
+};
+
+/*
+ * Race flags
+ */
+cptr rp_info_flags2[] =
+{
+ "XXX",
+ "ASTRAL",
+ "XXX",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1"
+};
+
+/* Skill flags */
+static cptr s_info_flags1[] =
+{
+ "HIDDEN",
+ "AUTO_HIDE",
+ "RANDOM_GAIN",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1",
+ "XXX1"
+};
+
+/*
+ * Dungeon effect types (used in E:damage:frequency:type entry in d_info.txt)
+ */
+static struct
+{
+cptr name;
+int feat;
+}
+d_info_dtypes[] =
+{
+ {"ELEC", GF_ELEC},
+ {"POISON", GF_POIS},
+ {"ACID", GF_ACID},
+ {"COLD", GF_COLD},
+ {"FIRE", GF_FIRE},
+ {"MISSILE", GF_MISSILE},
+ {"ARROW", GF_ARROW},
+ {"PLASMA", GF_PLASMA},
+ {"WATER", GF_WATER},
+ {"LITE", GF_LITE},
+ {"DARK", GF_DARK},
+ {"LITE_WEAK", GF_LITE_WEAK},
+ {"LITE_DARK", GF_DARK_WEAK},
+ {"SHARDS", GF_SHARDS},
+ {"SOUND", GF_SOUND},
+ {"CONFUSION", GF_CONFUSION},
+ {"FORCE", GF_FORCE},
+ {"INERTIA", GF_INERTIA},
+ {"MANA", GF_MANA},
+ {"METEOR", GF_METEOR},
+ {"ICE", GF_ICE},
+ {"CHAOS", GF_CHAOS},
+ {"NETHER", GF_NETHER},
+ {"DISENCHANT", GF_DISENCHANT},
+ {"NEXUS", GF_NEXUS},
+ {"TIME", GF_TIME},
+ {"GRAVITY", GF_GRAVITY},
+ {"ROCKET", GF_ROCKET},
+ {"NUKE", GF_NUKE},
+ {"HOLY_FIRE", GF_HOLY_FIRE},
+ {"HELL_FIRE", GF_HELL_FIRE},
+ {"DISINTEGRATE", GF_DISINTEGRATE},
+ {"DESTRUCTION", GF_DESTRUCTION},
+ {"RAISE", GF_RAISE},
+ {NULL, 0}
+};
+
+/* Essence names for al_info.txt */
+static const char *essence_names[] =
+{
+ "No name here", /* can't be matched, sscanf stops at spaces */
+ "POISON",
+ "EXPLOSION",
+ "TELEPORT",
+ "COLD",
+ "FIRE",
+ "ACID",
+ "LIFE",
+ "CONFUSION",
+ "LITE",
+ "CHAOS",
+ "TIME",
+ "MAGIC",
+ "EXTRALIFE",
+ "DARKNESS",
+ "KNOWLEDGE",
+ "FORCE",
+ "LIGHTNING",
+ "MANA",
+ ""
+};
+static const char *activation_names[] =
+{
+ "NO_ACTIVATION", /* 0*/
+ "SUNLIGHT", /* 1*/
+ "BO_MISS_1", /* 2*/
+ "BA_POIS_1", /* 3*/
+ "BO_ELEC_1", /* 4*/
+ "BO_ACID_1", /* 5*/
+ "BO_COLD_1", /* 6*/
+ "BO_FIRE_1", /* 7*/
+ "BA_COLD_1", /* 8*/
+ "BA_FIRE_1", /* 9*/
+ "DRAIN_1", /* 10*/
+ "BA_COLD_2", /* 11*/
+ "BA_ELEC_2", /* 12*/
+ "DRAIN_2", /* 13*/
+ "VAMPIRE_1", /* 14*/
+ "BO_MISS_2", /* 15*/
+ "BA_FIRE_2", /* 16*/
+ "BA_COLD_3", /* 17*/
+ "BA_ELEC_3", /* 18*/
+ "WHIRLWIND", /* 19*/
+ "VAMPIRE_2", /* 20*/
+ "CALL_CHAOS", /* 21*/
+ "ROCKET", /* 22*/
+ "DISP_EVIL", /* 23*/
+ "BA_MISS_3", /* 24*/
+ "DISP_GOOD", /* 25*/
+ "GILGALAD", /* 26*/
+ "CELEBRIMBOR", /* 27*/
+ "SKULLCLEAVER", /* 28*/
+ "HARADRIM", /* 29*/
+ "FUNDIN", /* 30*/
+ "EOL", /* 31*/
+ "UMBAR", /* 32*/
+ "NUMENOR", /* 33*/
+ "KNOWLEDGE", /* 34*/
+ "UNDEATH", /* 35*/
+ "THRAIN", /* 36*/
+ "BARAHIR", /* 37*/
+ "TULKAS", /* 38*/
+ "NARYA", /* 39*/
+ "NENYA", /* 40*/
+ "VILYA", /* 41*/
+ "POWER", /* 42*/
+ "STONE_LORE", /* 43*/
+ "RAZORBACK", /* 44*/
+ "BLADETURNER", /* 45*/
+ "MEDIATOR", /* 46*/
+ "BELEGENNON", /* 47*/
+ "GORLIM", /* 48*/
+ "COLLUIN", /* 49*/
+ "BELANGIL", /* 50*/
+ "CONFUSE", /* 51*/
+ "SLEEP", /* 52*/
+ "QUAKE", /* 53*/
+ "TERROR", /* 54*/
+ "TELE_AWAY", /* 55*/
+ "BANISH_EVIL", /* 56*/
+ "GENOCIDE", /* 57*/
+ "MASS_GENO", /* 58*/
+ "ANGUIREL", /* 59*/
+ "ERU", /* 60*/
+ "DAWN", /* 61*/
+ "FIRESTAR", /* 62*/
+ "TURMIL", /* 63*/
+ "CUBRAGOL", /* 64*/
+ "CHARM_ANIMAL", /* 65*/
+ "CHARM_UNDEAD", /* 66*/
+ "CHARM_OTHER", /* 67*/
+ "CHARM_ANIMALS", /* 68*/
+ "CHARM_OTHERS", /* 69*/
+ "SUMMON_ANIMAL", /* 70*/
+ "SUMMON_PHANTOM", /* 71*/
+ "SUMMON_ELEMENTAL", /* 72*/
+ "SUMMON_DEMON", /* 73*/
+ "SUMMON_UNDEAD", /* 74*/
+ "ELESSAR", /* 75*/
+ "GANDALF", /* 76*/
+ "MARDA", /* 77*/
+ "PALANTIR", /* 78*/
+ "XXX79",
+ "XXX80",
+ "CURE_LW", /* 81*/
+ "CURE_MW", /* 82*/
+ "CURE_POISON", /* 83*/
+ "REST_LIFE", /* 84*/
+ "REST_ALL", /* 85*/
+ "CURE_700", /* 86*/
+ "CURE_1000", /* 87*/
+ "XXX88",
+ "EREBOR", /* 89*/
+ "DRUEDAIN", /* 90*/
+ "ESP", /* 91*/
+ "BERSERK", /* 92*/
+ "PROT_EVIL", /* 93*/
+ "RESIST_ALL", /* 94*/
+ "SPEED", /* 95*/
+ "XTRA_SPEED", /* 96*/
+ "WRAITH", /* 97*/
+ "INVULN", /* 98*/
+ "ROHAN", /* 99*/
+ "HELM", /* 100*/
+ "BOROMIR", /* 101*/
+ "HURIN", /* 102*/
+ "AXE_GOTHMOG", /* 103*/
+ "MELKOR", /* 104*/
+ "GROND", /* 105*/
+ "NATUREBANE", /* 106*/
+ "NIGHT", /* 107*/
+ "ORCHAST", /* 108*/
+ "XXX109",
+ "XXX110",
+ "LIGHT", /* 111*/
+ "MAP_LIGHT", /* 112*/
+ "DETECT_ALL", /* 113*/
+ "DETECT_XTRA", /* 114*/
+ "ID_FULL", /* 115*/
+ "ID_PLAIN", /* 116*/
+ "RUNE_EXPLO", /* 117*/
+ "RUNE_PROT", /* 118*/
+ "SATIATE", /* 119*/
+ "DEST_DOOR", /* 120*/
+ "STONE_MUD", /* 121*/
+ "RECHARGE", /* 122*/
+ "ALCHEMY", /* 123*/
+ "DIM_DOOR", /* 124*/
+ "TELEPORT", /* 125*/
+ "RECALL", /* 126*/
+ "DEATH", /* 127*/
+ "RUINATION", /* 128*/
+ "DESTRUC", /* 129*/
+ "UNINT", /* 130*/
+ "UNSTR", /* 131*/
+ "UNCON", /* 132*/
+ "UNCHR", /* 133*/
+ "UNDEX", /* 134*/
+ "UNWIS", /* 135*/
+ "STATLOSS", /* 136*/
+ "HISTATLOSS", /* 137*/
+ "EXPLOSS", /* 138*/
+ "HIEXPLOSS", /* 139*/
+ "SUMMON_MONST", /* 140*/
+ "PARALYZE", /* 141*/
+ "HALLU", /* 142*/
+ "POISON", /* 143*/
+ "HUNGER", /* 144*/
+ "STUN", /* 145*/
+ "CUTS", /* 146*/
+ "PARANO", /* 147*/
+ "CONFUSION", /* 148*/
+ "BLIND", /* 149*/
+ "PET_SUMMON", /* 150*/
+ "CURE_PARA", /* 151*/
+ "CURE_HALLU", /* 152*/
+ "CURE_POIS", /* 153*/
+ "CURE_HUNGER", /* 154*/
+ "CURE_STUN", /* 155*/
+ "CURE_CUTS", /* 156*/
+ "CURE_FEAR", /* 157*/
+ "CURE_CONF", /* 158*/
+ "CURE_BLIND", /* 159*/
+ "CURING", /* 160*/
+ "DARKNESS", /* 161*/
+ "LEV_TELE", /* 162*/
+ "ACQUIREMENT", /* 163*/
+ "WEIRD", /* 164*/
+ "AGGRAVATE", /* 165*/
+ "MUT", /* 166*/
+ "CURE_INSANITY", /* 167*/
+ "CURE_MUT", /* 168*/
+ "LIGHT_ABSORBTION", /* 169*/
+ "BA_FIRE_H", /* 170*/
+ "BA_COLD_H", /* 171*/
+ "BA_ELEC_H", /* 172*/
+ "BA_ACID_H", /* 173*/
+ "SPIN", /* 174*/
+ "NOLDOR", /* 175*/
+ "SPECTRAL", /* 176*/
+ "JUMP", /* 177*/
+ "DEST_TELE", /* 178*/
+ "BA_POIS_4", /* 179*/
+ "BA_COLD_4", /* 180*/
+ "BA_FIRE_4", /* 181*/
+ "BA_ACID_4", /* 182*/
+ "BA_ELEC_4", /* 183*/
+ "BR_ELEC", /* 184*/
+ "BR_COLD", /* 185*/
+ "BR_FIRE", /* 186*/
+ "BR_ACID", /* 187*/
+ "BR_POIS", /* 188*/
+ "BR_MANY", /* 189*/
+ "BR_CONF", /* 190*/
+ "BR_SOUND", /* 191*/
+ "BR_CHAOS", /* 192*/
+ "BR_SHARD", /* 193*/
+ "BR_BALANCE", /* 194*/
+ "BR_LIGHT", /* 195*/
+ "BR_POWER", /* 196*/
+ "GROW_MOLD", /* 197*/
+ "XXX198",
+ "XXX199",
+ "MUSIC", /* 200*/
+ ""
+};
+
+/*
+ * Convert a "color letter" into an "actual" color
+ * The colors are: dwsorgbuDWvyRGBU, as shown below
+ */
+int color_char_to_attr(char c)
+{
+ switch (c)
+ {
+ case 'd':
+ return (TERM_DARK);
+ case 'w':
+ return (TERM_WHITE);
+ case 's':
+ return (TERM_SLATE);
+ case 'o':
+ return (TERM_ORANGE);
+ case 'r':
+ return (TERM_RED);
+ case 'g':
+ return (TERM_GREEN);
+ case 'b':
+ return (TERM_BLUE);
+ case 'u':
+ return (TERM_UMBER);
+
+ case 'D':
+ return (TERM_L_DARK);
+ case 'W':
+ return (TERM_L_WHITE);
+ case 'v':
+ return (TERM_VIOLET);
+ case 'y':
+ return (TERM_YELLOW);
+ case 'R':
+ return (TERM_L_RED);
+ case 'G':
+ return (TERM_L_GREEN);
+ case 'B':
+ return (TERM_L_BLUE);
+ case 'U':
+ return (TERM_L_UMBER);
+ }
+
+ return ( -1);
+}
+
+/*
+ * Attr value-to-char convertion table
+ */
+byte conv_color[16] =
+{
+ 'd',
+ 'w',
+ 's',
+ 'o',
+ 'r',
+ 'g',
+ 'b',
+ 'u',
+ 'D',
+ 'W',
+ 'v',
+ 'y',
+ 'R',
+ 'G',
+ 'B',
+ 'U',
+};
+
+
+/* Values in re_info can be fixed, added, substracted or percented */
+static byte monster_ego_modify(char c)
+{
+ switch (c)
+ {
+ case '+':
+ return MEGO_ADD;
+ case '-':
+ return MEGO_SUB;
+ case '=':
+ return MEGO_FIX;
+ case '%':
+ return MEGO_PRC;
+ default:
+ {
+ msg_format("Unknown mego value modifier %c.", c);
+ return MEGO_ADD;
+ }
+ }
+}
+
+/*
+ * Implements fp stacks, for included files
+ */
+static FILE *fp_stack[10];
+static int fp_stack_idx = 0;
+
+/*
+ * Must be caleld before the main loop
+ */
+static void fp_stack_init(FILE *fp)
+{
+ fp_stack[0] = fp;
+ fp_stack_idx = 0;
+}
+
+static void fp_stack_push(cptr name)
+{
+ if (fp_stack_idx < 9)
+ {
+ char buf[1024];
+ FILE *fp;
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, name);
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit(format("Cannot open '%s' file.", name));
+
+ printf("ibncluding %s\n", name);
+
+ fp_stack[++fp_stack_idx] = fp;
+ }
+}
+
+static bool_ fp_stack_pop()
+{
+ if (fp_stack_idx > 0)
+ {
+ FILE *fp = fp_stack[fp_stack_idx--];
+ my_fclose(fp);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/*
+ * Must be used instead of my_fgets for teh main loop
+ */
+static int my_fgets_dostack(char *buf, int len)
+{
+ // End of a file
+ if (0 != my_fgets(fp_stack[fp_stack_idx], buf, len))
+ {
+ // If any left, use them
+ if (fp_stack_pop())
+ return my_fgets_dostack(buf, len);
+ // If not, this is the end
+ else
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+/*** Initialize from ascii template files ***/
+
+/*
+ * Grab one race flag from a textual string
+ */
+static bool_ unknown_shut_up = FALSE;
+static errr grab_one_class_flag(u32b *choice, cptr what)
+{
+ int i;
+ cptr s;
+
+ /* Scan classes flags */
+ for (i = 0; i < max_c_idx && (s = class_info[i].title + c_name); i++)
+ {
+ if (streq(what, s))
+ {
+ (choice[i / 32]) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ if (!unknown_shut_up) msg_format("Unknown class flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+static errr grab_one_race_allow_flag(u32b *choice, cptr what)
+{
+ int i;
+ cptr s;
+
+ /* Scan classes flags */
+ for (i = 0; i < max_rp_idx && (s = race_info[i].title + rp_name); i++)
+ {
+ if (streq(what, s))
+ {
+ (choice[i / 32]) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ if (!unknown_shut_up) msg_format("(1)Unknown race flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+/*
+ * Grab one flag from a textual string
+ */
+static errr grab_one_skill_flag(u32b *f1, cptr what)
+{
+ int i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, s_info_flags1[i]))
+ {
+ (*f1) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("(2)Unknown skill flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+/*
+ * Grab one flag from a textual string
+ */
+static errr grab_one_player_race_flag(u32b *f1, u32b *f2, cptr what)
+{
+ int i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, rp_info_flags1[i]))
+ {
+ (*f1) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, rp_info_flags2[i]))
+ {
+ (*f2) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("(2)Unknown race flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+
+/* Get an activation number (good for artifacts, recipes, egos, and object kinds) */
+int get_activation(char *activation)
+{
+ int i;
+ for ( i = 0 ; activation_names[i][0] ; i++)
+ if (!strncmp(activation_names[i], activation, 19))
+ {
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * Grab one flag in an object_kind from a textual string
+ */
+static errr grab_one_race_kind_flag(u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp, cptr what)
+{
+ int i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags1[i]))
+ {
+ (*f1) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2[i]))
+ {
+ (*f2) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 -- traps*/
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2_trap[i]))
+ {
+ (*f3) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags3[i]))
+ {
+ (*f3) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags4 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags4[i]))
+ {
+ (*f4) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags5 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags5[i]))
+ {
+ (*f5) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check esp_flags */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, esp_flags[i]))
+ {
+ (*esp) |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown object flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+
+/*
+ * Initialize the "player" arrays, by parsing an ascii "template" file
+ */
+errr init_player_info_txt(FILE *fp, char *buf)
+{
+ int i = 0, z;
+ int powers = 0;
+ int lev = 1;
+ int tit_idx = 0;
+ int spec_idx = 0;
+ int cur_ab = -1;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ player_race *rp_ptr = NULL;
+ player_race_mod *rmp_ptr = NULL;
+ player_class *c_ptr = NULL;
+ player_spec *s_ptr = NULL;
+ meta_class_type *mc_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Start the "fake" stuff */
+ rp_head->name_size = 0;
+ rp_head->text_size = 0;
+ rmp_head->name_size = 0;
+ rmp_head->text_size = 0;
+ c_head->name_size = 0;
+ c_head->text_size = 0;
+
+ /* Init general skills */
+ for (z = 0; z < MAX_SKILLS; z++)
+ {
+ gen_skill_basem[z] = 0;
+ gen_skill_base[z] = 0;
+ gen_skill_modm[z] = 0;
+ gen_skill_mod[z] = 0;
+ }
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Reinit error_idx */
+ if (buf[0] == 'I')
+ {
+ error_idx = -1;
+ continue;
+ }
+
+ /* Process 'H' for "History" */
+ if (buf[0] == 'H')
+ {
+ int idx;
+ char *zz[6];
+
+ /* Scan for the values */
+ if (tokenize(buf + 2, 6, zz, ':', ':') != 6) return (1);
+
+ idx = atoi(zz[0]);
+ bg[idx].roll = atoi(zz[1]);
+ bg[idx].chart = atoi(zz[2]);
+ bg[idx].next = atoi(zz[3]);
+ bg[idx].bonus = atoi(zz[4]);
+
+ bg[idx].info = ++rp_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(rp_text + rp_head->text_size, zz[5]);
+
+ /* Advance the index */
+ rp_head->text_size += strlen(zz[5]);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G:k' for "General skills" */
+ if ((buf[0] == 'G') && (buf[2] == 'k'))
+ {
+ long val, mod, i;
+ char name[200], v, m;
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 4, "%c%ld:%c%ld:%s",
+ &v, &val, &m, &mod, name)) return (1);
+
+ if ((i = find_skill(name)) == -1) return (1);
+ gen_skill_basem[i] = monster_ego_modify(v);
+ gen_skill_base[i] = val;
+ gen_skill_modm[i] = monster_ego_modify(m);
+ gen_skill_mod[i] = mod;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if ((buf[0] == 'R') && (buf[2] == 'N'))
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 4, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 4);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= rp_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ rp_ptr = &race_info[i];
+
+ /* Hack -- Verify space */
+ if (rp_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!rp_ptr->title) rp_ptr->title = ++rp_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(rp_name + rp_head->name_size, s);
+
+ /* Advance the index */
+ rp_head->name_size += strlen(s);
+
+ rp_ptr->powers[0] = rp_ptr->powers[1] = rp_ptr->powers[2] = rp_ptr->powers[3] = -1;
+ powers = 0;
+ lev = 1;
+ cur_ab = 0;
+ for (z = 0; z < 10; z++)
+ rp_ptr->abilities[z].level = -1;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'D' for "Description" */
+ if ((buf[0] == 'R') && (buf[2] == 'D'))
+ {
+ /* Acquire the text */
+ s = buf + 4;
+
+ /* Hack -- Verify space */
+ if (rp_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!rp_ptr->desc)
+ {
+ rp_ptr->desc = ++rp_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(rp_text + rp_head->text_size, s);
+
+ /* Advance the index */
+ rp_head->text_size += strlen(s);
+ }
+ else
+ {
+ /* Append chars to the name */
+ strcpy(rp_text + rp_head->text_size, format("\n%s", s));
+
+ /* Advance the index */
+ rp_head->text_size += strlen(s) + 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'E' for "body parts" */
+ if ((buf[0] == 'R') && (buf[2] == 'E'))
+ {
+ int s[BODY_MAX], z;
+
+ /* Scan for the values */
+ if (BODY_MAX != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5])) return (1);
+
+ for (z = 0; z < BODY_MAX; z++)
+ rp_ptr->body_parts[z] = s[z];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'R' for "flag level" */
+ if ((buf[0] == 'R') && (buf[2] == 'R'))
+ {
+ int s[2];
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 4, "%d:%d",
+ &s[0], &s[1])) return (1);
+
+ lev = s[0];
+ rp_ptr->opval[lev] = s[1];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'S' for "Stats" */
+ if ((buf[0] == 'R') && (buf[2] == 'S'))
+ {
+ int s[7], z;
+
+ /* Scan for the values */
+ if (7 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6])) return (1);
+
+ rp_ptr->luck = s[6];
+ for (z = 0; z < 6; z++)
+ rp_ptr->r_adj[z] = s[z];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'Z' for "powers" */
+ if ((buf[0] == 'R') && (buf[2] == 'Z'))
+ {
+ int i;
+
+ /* Acquire the text */
+ s = buf + 4;
+
+ /* Find it in the list */
+ for (i = 0; i < power_max; i++)
+ {
+ if (!stricmp(s, powers_type[i].name)) break;
+ }
+
+ if (i == power_max) return (6);
+
+ rp_ptr->powers[powers++] = i;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'K' for "sKills" */
+ if ((buf[0] == 'R') && (buf[2] == 'K'))
+ {
+ int s[8];
+
+ /* Scan for the values */
+ if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1);
+
+ rp_ptr->r_dis = s[0];
+ rp_ptr->r_dev = s[1];
+ rp_ptr->r_sav = s[2];
+ rp_ptr->r_stl = s[3];
+ rp_ptr->r_srh = s[4];
+ rp_ptr->r_fos = s[5];
+ rp_ptr->r_thn = s[6];
+ rp_ptr->r_thb = s[7];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'k' for "skills" */
+ if ((buf[0] == 'R') && (buf[2] == 'k'))
+ {
+ long val, mod, i;
+ char name[200], v, m;
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 4, "%c%ld:%c%ld:%s",
+ &v, &val, &m, &mod, name)) return (1);
+
+ if ((i = find_skill(name)) == -1) return (1);
+ rp_ptr->skill_basem[i] = monster_ego_modify(v);
+ rp_ptr->skill_base[i] = val;
+ rp_ptr->skill_modm[i] = monster_ego_modify(m);
+ rp_ptr->skill_mod[i] = mod;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'b' for "abilities" */
+ if ((buf[0] == 'R') && (buf[2] == 'b'))
+ {
+ char *sec;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 4, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+
+ if ((i = find_ability(sec)) == -1) return (1);
+
+ rp_ptr->abilities[cur_ab].ability = i;
+ rp_ptr->abilities[cur_ab].level = atoi(buf + 4);
+ cur_ab++;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'M' for "Mods" */
+ if ((buf[0] == 'R') && (buf[2] == 'M'))
+ {
+ int s[10];
+
+ /* Scan for the values */
+ if (10 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7], &s[8], &s[9])) return (1);
+
+ rp_ptr->b_age = s[0];
+ rp_ptr->m_age = s[1];
+ rp_ptr->m_b_ht = s[2];
+ rp_ptr->m_m_ht = s[3];
+ rp_ptr->m_b_wt = s[4];
+ rp_ptr->m_m_wt = s[5];
+ rp_ptr->f_b_ht = s[6];
+ rp_ptr->f_m_ht = s[7];
+ rp_ptr->f_b_wt = s[8];
+ rp_ptr->f_m_wt = s[9];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'P' for "xtra" */
+ if ((buf[0] == 'R') && (buf[2] == 'P'))
+ {
+ int s[4];
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 4, "%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3])) return (1);
+
+ rp_ptr->r_mhp = s[0];
+ rp_ptr->r_exp = s[1];
+ rp_ptr->infra = s[2];
+ rp_ptr->chart = s[3];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G' for "Player flags" (multiple lines) */
+ if ((buf[0] == 'R') && (buf[2] == 'G'))
+ {
+ /* Parse every entry */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_player_race_flag(&rp_ptr->flags1, &rp_ptr->flags2, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for "level Flags" (multiple lines) */
+ if ((buf[0] == 'R') && (buf[2] == 'F'))
+ {
+ /* Parse every entry */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_race_kind_flag(&rp_ptr->oflags1[lev], &rp_ptr->oflags2[lev], &rp_ptr->oflags3[lev], &rp_ptr->oflags4[lev], &rp_ptr->oflags5[lev], &rp_ptr->oesp[lev], s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'O' for "Object birth" */
+ if ((buf[0] == 'R') && (buf[2] == 'O'))
+ {
+ int s[5];
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 4, "%d:%d:%d:%dd%d",
+ &s[0], &s[1], &s[4], &s[2], &s[3]))
+ {
+ s[4] = 0;
+
+ if (4 != sscanf(buf + 4, "%d:%d:%dd%d",
+ &s[0], &s[1], &s[2], &s[3]))
+ {
+ return (1);
+ }
+ }
+
+ rp_ptr->obj_pval[rp_ptr->obj_num] = s[4];
+ rp_ptr->obj_tval[rp_ptr->obj_num] = s[0];
+ rp_ptr->obj_sval[rp_ptr->obj_num] = s[1];
+ rp_ptr->obj_dd[rp_ptr->obj_num] = s[2];
+ rp_ptr->obj_ds[rp_ptr->obj_num++] = s[3];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'C' for "Class choice flags" (multiple lines) */
+ if ((buf[0] == 'R') && (buf[2] == 'C'))
+ {
+ /* Parse every entry */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_class_flag(rp_ptr->choice, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if ((buf[0] == 'S') && (buf[2] == 'N'))
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 4, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 4);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= rmp_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ rmp_ptr = &race_mod_info[i];
+
+ /* Hack -- Verify space */
+ if (rmp_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!rmp_ptr->title) rmp_ptr->title = ++rmp_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(rmp_name + rmp_head->name_size, s);
+
+ /* Advance the index */
+ rmp_head->name_size += strlen(s);
+
+ rmp_ptr->powers[0] = rmp_ptr->powers[1] = rmp_ptr->powers[2] = rmp_ptr->powers[3] = -1;
+ powers = 0;
+ lev = 1;
+ cur_ab = 0;
+ for (z = 0; z < 10; z++)
+ rmp_ptr->abilities[z].level = -1;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'D' for "Description" */
+ if ((buf[0] == 'S') && (buf[2] == 'D'))
+ {
+ /* Acquire the text */
+ s = buf + 6;
+
+ if (buf[4] == 'A') rmp_ptr->place = TRUE;
+ else rmp_ptr->place = FALSE;
+
+ /* Hack -- Verify space */
+ if (rmp_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!rmp_ptr->desc)
+ {
+ rmp_ptr->desc = ++rmp_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(rmp_text + rmp_head->text_size, s);
+
+ /* Advance the index */
+ rmp_head->text_size += strlen(s);
+ }
+ else
+ {
+ /* Append chars to the name */
+ strcpy(rmp_text + rmp_head->text_size, format("\n%s", s));
+
+ /* Advance the index */
+ rmp_head->text_size += strlen(s) + 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'E' for "body parts" */
+ if ((buf[0] == 'S') && (buf[2] == 'E'))
+ {
+ int s[BODY_MAX], z;
+
+ /* Scan for the values */
+ if (BODY_MAX != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5])) return (1);
+
+ for (z = 0; z < BODY_MAX; z++)
+ rmp_ptr->body_parts[z] = s[z];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'R' for "flag level" */
+ if ((buf[0] == 'S') && (buf[2] == 'R'))
+ {
+ int s[2];
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 4, "%d:%d",
+ &s[0], &s[1])) return (1);
+
+ lev = s[0];
+ rmp_ptr->opval[lev] = s[1];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'S' for "Stats" */
+ if ((buf[0] == 'S') && (buf[2] == 'S'))
+ {
+ int s[8], z;
+
+ /* Scan for the values */
+ if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1);
+
+ rmp_ptr->mana = s[7];
+ rmp_ptr->luck = s[6];
+ for (z = 0; z < 6; z++)
+ rmp_ptr->r_adj[z] = s[z];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'Z' for "powers" */
+ if ((buf[0] == 'S') && (buf[2] == 'Z'))
+ {
+ int i;
+
+ /* Acquire the text */
+ s = buf + 4;
+
+ /* Find it in the list */
+ for (i = 0; i < power_max; i++)
+ {
+ if (!stricmp(s, powers_type[i].name)) break;
+ }
+
+ if (i == power_max) return (6);
+
+ rmp_ptr->powers[powers++] = i;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'k' for "skills" */
+ if ((buf[0] == 'S') && (buf[2] == 'k'))
+ {
+ long val, mod, i;
+ char name[200], v, m;
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 4, "%c%ld:%c%ld:%s",
+ &v, &val, &m, &mod, name)) return (1);
+
+ if ((i = find_skill(name)) == -1) return (1);
+ rmp_ptr->skill_basem[i] = monster_ego_modify(v);
+ rmp_ptr->skill_base[i] = val;
+ rmp_ptr->skill_modm[i] = monster_ego_modify(m);
+ rmp_ptr->skill_mod[i] = mod;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'b' for "abilities" */
+ if ((buf[0] == 'S') && (buf[2] == 'b'))
+ {
+ char *sec;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 4, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+
+ if ((i = find_ability(sec)) == -1) return (1);
+
+ rmp_ptr->abilities[cur_ab].ability = i;
+ rmp_ptr->abilities[cur_ab].level = atoi(buf + 4);
+ cur_ab++;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'K' for "sKills" */
+ if ((buf[0] == 'S') && (buf[2] == 'K'))
+ {
+ int s[8];
+
+ /* Scan for the values */
+ if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1);
+
+ rmp_ptr->r_dis = s[0];
+ rmp_ptr->r_dev = s[1];
+ rmp_ptr->r_sav = s[2];
+ rmp_ptr->r_stl = s[3];
+ rmp_ptr->r_srh = s[4];
+ rmp_ptr->r_fos = s[5];
+ rmp_ptr->r_thn = s[6];
+ rmp_ptr->r_thb = s[7];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'M' for "Mods" */
+ if ((buf[0] == 'S') && (buf[2] == 'M'))
+ {
+ int s[10];
+
+ /* Scan for the values */
+ if (10 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7], &s[8], &s[9])) return (1);
+
+ rmp_ptr->b_age = s[0];
+ rmp_ptr->m_age = s[1];
+ rmp_ptr->m_b_ht = s[2];
+ rmp_ptr->m_m_ht = s[3];
+ rmp_ptr->m_b_wt = s[4];
+ rmp_ptr->m_m_wt = s[5];
+ rmp_ptr->f_b_ht = s[6];
+ rmp_ptr->f_m_ht = s[7];
+ rmp_ptr->f_b_wt = s[8];
+ rmp_ptr->f_m_wt = s[9];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'P' for "xtra" */
+ if ((buf[0] == 'S') && (buf[2] == 'P'))
+ {
+ int s[3];
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 4, "%d:%d:%d",
+ &s[0], &s[1], &s[2])) return (1);
+
+ rmp_ptr->r_mhp = s[0];
+ rmp_ptr->r_exp = s[1];
+ rmp_ptr->infra = s[2];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G' for "Player flags" (multiple lines) */
+ if ((buf[0] == 'S') && (buf[2] == 'G'))
+ {
+ /* Parse every entry */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_player_race_flag(&rmp_ptr->flags1, &rmp_ptr->flags2, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for "level Flags" (multiple lines) */
+ if ((buf[0] == 'S') && (buf[2] == 'F'))
+ {
+ /* Parse every entry */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_race_kind_flag(&rmp_ptr->oflags1[lev], &rmp_ptr->oflags2[lev], &rmp_ptr->oflags3[lev], &rmp_ptr->oflags4[lev], &rmp_ptr->oflags5[lev], &rmp_ptr->oesp[lev], s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'O' for "Object birth" */
+ if ((buf[0] == 'S') && (buf[2] == 'O'))
+ {
+ int s[5];
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 4, "%d:%d:%d:%dd%d",
+ &s[0], &s[1], &s[4], &s[2], &s[3]))
+ {
+ s[4] = 0;
+
+ if (4 != sscanf(buf + 4, "%d:%d:%dd%d",
+ &s[0], &s[1], &s[2], &s[3]))
+ {
+ return (1);
+ }
+ }
+
+ rmp_ptr->obj_pval[rmp_ptr->obj_num] = s[4];
+ rmp_ptr->obj_tval[rmp_ptr->obj_num] = s[0];
+ rmp_ptr->obj_sval[rmp_ptr->obj_num] = s[1];
+ rmp_ptr->obj_dd[rmp_ptr->obj_num] = s[2];
+ rmp_ptr->obj_ds[rmp_ptr->obj_num++] = s[3];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'A' for "Allowed races" (multiple lines) */
+ if ((buf[0] == 'S') && (buf[2] == 'A'))
+ {
+ /* Parse every entry */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_race_allow_flag(rmp_ptr->choice, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'C' for "Class choice flags" (multiple lines) */
+ if ((buf[0] == 'S') && (buf[2] == 'C'))
+ {
+ u32b choice[2] = {0, 0}, z;
+
+ /* Parse every entry */
+ for (s = buf + 6; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_class_flag(choice, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ for (z = 0; z < 2; z++)
+ {
+ if (buf[4] == 'A') rmp_ptr->pclass[z] |= choice[z];
+ else rmp_ptr->mclass[z] |= choice[z];
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if ((buf[0] == 'C') && (buf[2] == 'N'))
+ {
+ int z;
+
+ /* Find the colon before the name */
+ s = strchr(buf + 4, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 4);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= c_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ c_ptr = &class_info[i];
+
+ /* Hack -- Verify space */
+ if (c_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!c_ptr->title) c_ptr->title = ++c_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(c_name + c_head->name_size, s);
+
+ /* Advance the index */
+ c_head->name_size += strlen(s);
+
+ c_ptr->powers[0] = c_ptr->powers[1] = c_ptr->powers[2] = c_ptr->powers[3] = -1;
+ powers = 0;
+ lev = 1;
+ for (z = 0; z < 10; z++)
+ c_ptr->abilities[z].level = -1;
+ cur_ab = 0;
+ c_ptr->obj_num = 0;
+ tit_idx = 0;
+ spec_idx = -1;
+ for (z = 0; z < MAX_SPEC; z++)
+ c_ptr->spec[z].title = 0;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'D' for "Description" */
+ if ((buf[0] == 'C') && (buf[2] == 'D'))
+ {
+ /* Acquire the text */
+ s = buf + 6;
+
+ /* Hack -- Verify space */
+ if (c_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ switch (buf[4])
+ {
+ case '0':
+ /* Advance and Save the text index */
+ if (!c_ptr->desc)
+ {
+ c_ptr->desc = ++c_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(c_text + c_head->text_size, s);
+
+ /* Advance the index */
+ c_head->text_size += strlen(s);
+ }
+ else
+ {
+ /* Append chars to the name */
+ strcpy(c_text + c_head->text_size, format("\n%s", s));
+
+ /* Advance the index */
+ c_head->text_size += strlen(s) + 1;
+ }
+ break;
+ case '1':
+ /* Advance and Save the text index */
+ c_ptr->titles[tit_idx++] = ++c_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(c_text + c_head->text_size, s);
+
+ /* Advance the index */
+ c_head->text_size += strlen(s);
+ break;
+ default:
+ return (6);
+ break;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'O' for "Object birth" */
+ if ((buf[0] == 'C') && (buf[2] == 'O'))
+ {
+ int s[5];
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 4, "%d:%d:%d:%dd%d",
+ &s[0], &s[1], &s[4], &s[2], &s[3]))
+ {
+ s[4] = 0;
+
+ if (4 != sscanf(buf + 4, "%d:%d:%dd%d",
+ &s[0], &s[1], &s[2], &s[3]))
+ {
+ return (1);
+ }
+ }
+
+ c_ptr->obj_pval[c_ptr->obj_num] = s[4];
+ c_ptr->obj_tval[c_ptr->obj_num] = s[0];
+ c_ptr->obj_sval[c_ptr->obj_num] = s[1];
+ c_ptr->obj_dd[c_ptr->obj_num] = s[2];
+ c_ptr->obj_ds[c_ptr->obj_num++] = s[3];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'E' for "body parts" */
+ if ((buf[0] == 'C') && (buf[2] == 'E'))
+ {
+ int s[BODY_MAX], z;
+
+ /* Scan for the values */
+ if (BODY_MAX != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5])) return (1);
+
+ for (z = 0; z < BODY_MAX; z++)
+ c_ptr->body_parts[z] = s[z];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'R' for "flag level" */
+ if ((buf[0] == 'C') && (buf[2] == 'R'))
+ {
+ int s[2];
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 4, "%d:%d",
+ &s[0], &s[1])) return (1);
+
+ lev = s[0];
+ c_ptr->opval[lev] = s[1];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'C' for "Stats" */
+ if ((buf[0] == 'C') && (buf[2] == 'S'))
+ {
+ int s[8], z;
+
+ /* Scan for the values */
+ if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1);
+
+ c_ptr->mana = s[6];
+ c_ptr->extra_blows = s[7];
+ for (z = 0; z < 6; z++)
+ c_ptr->c_adj[z] = s[z];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'k' for "skills" */
+ if ((buf[0] == 'C') && (buf[2] == 'k'))
+ {
+ long val, mod, i;
+ char name[200], v, m;
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 4, "%c%ld:%c%ld:%s",
+ &v, &val, &m, &mod, name)) return (1);
+
+ if ((i = find_skill(name)) == -1) return (1);
+ c_ptr->skill_basem[i] = monster_ego_modify(v);
+ c_ptr->skill_base[i] = val;
+ c_ptr->skill_modm[i] = monster_ego_modify(m);
+ c_ptr->skill_mod[i] = mod;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'b' for "abilities" */
+ if ((buf[0] == 'C') && (buf[2] == 'b'))
+ {
+ char *sec;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 4, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+
+ if ((i = find_ability(sec)) == -1) return (1);
+
+ c_ptr->abilities[cur_ab].ability = i;
+ c_ptr->abilities[cur_ab].level = atoi(buf + 4);
+ cur_ab++;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'g' for "gods" */
+ if ((buf[0] == 'C') && (buf[2] == 'g'))
+ {
+ int i;
+
+ if (streq(buf + 4, "All Gods"))
+ c_ptr->gods = 0xFFFFFFFF;
+ else
+ {
+ if ((i = find_god(buf + 4)) == -1) return (1);
+ c_ptr->gods |= BIT(i);
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'Z' for "powers" */
+ if ((buf[0] == 'C') && (buf[2] == 'Z'))
+ {
+ int i;
+
+ /* Acquire the text */
+ s = buf + 4;
+
+ /* Find it in the list */
+ for (i = 0; i < power_max; i++)
+ {
+ if (!stricmp(s, powers_type[i].name)) break;
+ }
+
+ if (i == power_max) return (6);
+
+ c_ptr->powers[powers++] = i;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'K' for "sKills" */
+ if ((buf[0] == 'C') && (buf[2] == 'K'))
+ {
+ int s[8];
+
+ /* Scan for the values */
+ if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1);
+
+ c_ptr->c_dis = s[0];
+ c_ptr->c_dev = s[1];
+ c_ptr->c_sav = s[2];
+ c_ptr->c_stl = s[3];
+ c_ptr->c_srh = s[4];
+ c_ptr->c_fos = s[5];
+ c_ptr->c_thn = s[6];
+ c_ptr->c_thb = s[7];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'x' for "Xtra skills" */
+ if ((buf[0] == 'C') && (buf[2] == 'X'))
+ {
+ int s[8];
+
+ /* Scan for the values */
+ if (8 != sscanf(buf + 4, "%d:%d:%d:%d:%d:%d:%d:%d",
+ &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7])) return (1);
+
+ c_ptr->x_dis = s[0];
+ c_ptr->x_dev = s[1];
+ c_ptr->x_sav = s[2];
+ c_ptr->x_stl = s[3];
+ c_ptr->x_srh = s[4];
+ c_ptr->x_fos = s[5];
+ c_ptr->x_thn = s[6];
+ c_ptr->x_thb = s[7];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'P' for "xtra" */
+ if ((buf[0] == 'C') && (buf[2] == 'P'))
+ {
+ int s[2];
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 4, "%d:%d",
+ &s[0], &s[1])) return (1);
+
+ c_ptr->c_mhp = s[0];
+ c_ptr->c_exp = s[1];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'C' for "sensing" */
+ if ((buf[0] == 'C') && (buf[2] == 'C'))
+ {
+ long int s[3];
+ char h, m;
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 4, "%c:%c:%ld:%ld:%ld",
+ &h, &m, &s[0], &s[1], &s[2])) return (1);
+
+ c_ptr->sense_heavy = (h == 'H') ? TRUE : FALSE;
+ c_ptr->sense_heavy_magic = (m == 'H') ? TRUE : FALSE;
+ c_ptr->sense_base = s[0];
+ c_ptr->sense_pl = s[1];
+ c_ptr->sense_plus = s[2];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'B' for "blows" */
+ if ((buf[0] == 'C') && (buf[2] == 'B'))
+ {
+ int s[3];
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 4, "%d:%d:%d",
+ &s[0], &s[1], &s[2])) return (1);
+
+ c_ptr->blow_num = s[0];
+ c_ptr->blow_wgt = s[1];
+ c_ptr->blow_mul = s[2];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G' for "Player flags" (multiple lines) */
+ if ((buf[0] == 'C') && (buf[2] == 'G'))
+ {
+ /* Parse every entry */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_player_race_flag(&c_ptr->flags1, &c_ptr->flags2, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for "level Flags" (multiple lines) */
+ if ((buf[0] == 'C') && (buf[2] == 'F'))
+ {
+ /* Parse every entry */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_race_kind_flag(&c_ptr->oflags1[lev], &c_ptr->oflags2[lev], &c_ptr->oflags3[lev], &c_ptr->oflags4[lev], &c_ptr->oflags5[lev], &c_ptr->oesp[lev], s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Specialities */
+ if ((buf[0] == 'C') && (buf[2] == 'a'))
+ {
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[4] == 'N')
+ {
+ /* Find the colon before the name */
+ s = buf + 6;
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+ /* Get the index */
+ spec_idx++;
+
+ /* Verify information */
+ if (spec_idx >= MAX_SPEC) return (2);
+
+ /* Point at the "info" */
+ s_ptr = &c_ptr->spec[spec_idx];
+
+ /* Hack -- Verify space */
+ if (c_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!s_ptr->title) s_ptr->title = ++c_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(c_name + c_head->name_size, s);
+
+ /* Advance the index */
+ c_head->name_size += strlen(s);
+
+ s_ptr->obj_num = 0;
+ cur_ab = 0;
+ for (z = 0; z < 10; z++)
+ s_ptr->abilities[z].level = -1;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'D' for "Description" */
+ if (buf[4] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 6;
+
+ /* Hack -- Verify space */
+ if (c_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!s_ptr->desc)
+ {
+ s_ptr->desc = ++c_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(c_text + c_head->text_size, s);
+
+ /* Advance the index */
+ c_head->text_size += strlen(s);
+ }
+ else
+ {
+ /* Append chars to the name */
+ strcpy(c_text + c_head->text_size, format("\n%s", s));
+
+ /* Advance the index */
+ c_head->text_size += strlen(s) + 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'O' for "Object birth" */
+ if (buf[4] == 'O')
+ {
+ int s[5];
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 6, "%d:%d:%d:%dd%d",
+ &s[0], &s[1], &s[4], &s[2], &s[3]))
+ {
+ s[4] = 0;
+
+ if (4 != sscanf(buf + 6, "%d:%d:%dd%d",
+ &s[0], &s[1], &s[2], &s[3]))
+ {
+ return (1);
+ }
+ }
+
+ s_ptr->obj_pval[s_ptr->obj_num] = s[4];
+ s_ptr->obj_tval[s_ptr->obj_num] = s[0];
+ s_ptr->obj_sval[s_ptr->obj_num] = s[1];
+ s_ptr->obj_dd[s_ptr->obj_num] = s[2];
+ s_ptr->obj_ds[s_ptr->obj_num++] = s[3];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'g' for "gods" */
+ if (buf[4] == 'g')
+ {
+ int i;
+
+ if (streq(buf + 6, "All Gods"))
+ s_ptr->gods = 0xFFFFFFFF;
+ else
+ {
+ if ((i = find_god(buf + 6)) == -1) return (1);
+ s_ptr->gods |= BIT(i);
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'k' for "skills" */
+ if (buf[4] == 'k')
+ {
+ long val, mod, i;
+ char name[200], v, m;
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 6, "%c%ld:%c%ld:%s",
+ &v, &val, &m, &mod, name)) return (1);
+
+ if ((i = find_skill(name)) == -1) return (1);
+ s_ptr->skill_basem[i] = monster_ego_modify(v);
+ s_ptr->skill_base[i] = val;
+ s_ptr->skill_modm[i] = monster_ego_modify(m);
+ s_ptr->skill_mod[i] = mod;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'b' for "abilities" */
+ if (buf[4] == 'b')
+ {
+ char *sec;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 6, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+
+ if ((i = find_ability(sec)) == -1) return (1);
+
+ s_ptr->abilities[cur_ab].ability = i;
+ s_ptr->abilities[cur_ab].level = atoi(buf + 6);
+ cur_ab++;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G' for "Player flags" (multiple lines) */
+ if (buf[4] == 'G')
+ {
+ /* Parse every entry */
+ for (s = buf + 6; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_player_race_flag(&s_ptr->flags1, &s_ptr->flags2, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Process 'K' for "desired skills" */
+ if (buf[4] == 'K')
+ {
+ long val;
+ char name[200];
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 6, "%ld:%s",
+ &val, name)) return (1);
+
+ if ((i = find_skill(name)) == -1) return (1);
+ s_ptr->skill_ideal[i] = val;
+
+ /* Next... */
+ continue;
+ }
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if ((buf[0] == 'M') && (buf[2] == 'N'))
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 4, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 4);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= max_mc_idx) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ mc_ptr = &meta_class_info[i];
+
+ /* Append chars to the name */
+ strcpy(mc_ptr->name, s + 2);
+ mc_ptr->color = color_char_to_attr(s[0]);
+ for (powers = 0; powers < max_c_idx; powers++)
+ mc_ptr->classes[powers] = -1;
+ powers = 0;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'C' for "Classes" */
+ if ((buf[0] == 'M') && (buf[2] == 'C'))
+ {
+ int i;
+
+ /* Acquire the text */
+ s = buf + 4;
+
+ /* Find it in the list */
+ for (i = 0; i < max_c_idx; i++)
+ {
+ if (!stricmp(s, class_info[i].title + c_name)) break;
+ }
+
+ if (i == max_c_idx) return (6);
+
+ mc_ptr->classes[powers++] = i;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+ /* Complete the "name" and "text" sizes */
+ ++rp_head->name_size;
+ ++rp_head->text_size;
+ ++rmp_head->name_size;
+ ++rmp_head->text_size;
+ ++c_head->name_size;
+ ++c_head->text_size;
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialize the "v_info" array, by parsing an ascii "template" file
+ */
+errr init_v_info_txt(FILE *fp, char *buf, bool_ start)
+{
+ int i;
+ char *s;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ vault_type *v_ptr = NULL;
+
+ if (start)
+ {
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Prepare the "fake" stuff */
+ v_head->name_size = 0;
+ v_head->text_size = 0;
+ }
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+ if ((buf[0] == 'Q') || (buf[0] == 'T')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf, "V:%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i <= error_idx) return (4);
+
+ /* Verify information */
+ if (i >= v_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ v_ptr = &v_info[i];
+
+ /* Hack -- Verify space */
+ if (v_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!v_ptr->name) v_ptr->name = ++v_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(v_name + v_head->name_size, s);
+
+ /* Advance the index */
+ v_head->name_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current v_ptr */
+ if (!v_ptr) return (3);
+
+ /* Process 'D' for "Description" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (v_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!v_ptr->text) v_ptr->text = ++v_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(v_text + v_head->text_size, s);
+
+ /* Advance the index */
+ v_head->text_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Process 'X' for "Extra info" (one line only) */
+ if (buf[0] == 'X')
+ {
+ int typ, rat, hgt, wid;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
+ &typ, &rat, &hgt, &wid)) return (1);
+
+ /* Save the values */
+ v_ptr->typ = typ;
+ v_ptr->rat = rat;
+ v_ptr->hgt = hgt;
+ v_ptr->wid = wid;
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current v_ptr */
+ if (!v_ptr) return (3);
+
+ /* Process monster, item and level info for special levels */
+ if (buf[0] == 'Y')
+ {
+
+ int mon1, mon2, mon3, mon4, mon5, mon6, mon7, mon8, mon9;
+ int mon10, item1, item2, item3, lvl, dun_type;
+
+ /* Scan for the values */
+ if (15 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ &mon1, &mon2, &mon3, &mon4, &mon5, &mon6, &mon7, &mon8, &mon9, &mon10, &item1, &item2, &item3, &lvl, &dun_type)) return (1);
+
+ /* Save the values */
+ v_ptr->mon[0] = mon1;
+ v_ptr->mon[1] = mon2;
+ v_ptr->mon[2] = mon3;
+ v_ptr->mon[3] = mon4;
+ v_ptr->mon[4] = mon5;
+ v_ptr->mon[5] = mon6;
+ v_ptr->mon[6] = mon7;
+ v_ptr->mon[7] = mon8;
+ v_ptr->mon[8] = mon9;
+ v_ptr->mon[9] = mon10;
+ v_ptr->item[0] = item1;
+ v_ptr->item[1] = item2;
+ v_ptr->item[2] = item3;
+ v_ptr->lvl = lvl;
+ v_ptr->dun_type = dun_type;
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ if (!start)
+ {
+ ++v_head->name_size;
+ ++v_head->text_size;
+ }
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Grab one flag in an feature_type from a textual string
+ */
+static errr grab_one_feature_flag(feature_type *f_ptr, cptr what)
+{
+ int i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, f_info_flags1[i]))
+ {
+ f_ptr->flags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown object flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+
+
+/*
+ * Initialize the "f_info" array, by parsing an ascii "template" file
+ */
+errr init_f_info_txt(FILE *fp, char *buf)
+{
+ int i;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+ u32b default_desc = 0, default_tunnel = 0, default_block = 0;
+
+ /* Current entry */
+ feature_type *f_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Prepare the "fake" stuff */
+ f_head->name_size = 0;
+ f_head->text_size = 0;
+
+ /* Add some fake descs */
+ default_desc = ++f_head->text_size;
+ strcpy(f_text + f_head->text_size, "a wall blocking your way");
+ f_head->text_size += strlen("a wall blocking your way");
+
+ default_tunnel = ++f_head->text_size;
+ strcpy(f_text + f_head->text_size, "You cannot tunnel through that.");
+ f_head->text_size += strlen("You cannot tunnel through that.");
+
+ default_block = ++f_head->text_size;
+ strcpy(f_text + f_head->text_size, "a wall blocking your way");
+ f_head->text_size += strlen("a wall blocking your way");
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i <= error_idx) return (4);
+
+ /* Verify information */
+ if (i >= f_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ f_ptr = &f_info[i];
+
+ /* Hack -- Verify space */
+ if (f_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!f_ptr->name) f_ptr->name = ++f_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(f_name + f_head->name_size, s);
+
+ /* Advance the index */
+ f_head->name_size += strlen(s);
+
+ /* Default "mimic" */
+ f_ptr->mimic = i;
+ f_ptr->text = default_desc;
+ f_ptr->block = default_desc;
+ f_ptr->tunnel = default_tunnel;
+ f_ptr->block = default_block;
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current f_ptr */
+ if (!f_ptr) return (3);
+
+
+ /* Process 'D' for "Descriptions" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 4;
+
+ /* Hack -- Verify space */
+ if (f_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ switch (buf[2])
+ {
+ case '0':
+ /* Advance and Save the text index */
+ f_ptr->text = ++f_head->text_size;
+ break;
+ case '1':
+ /* Advance and Save the text index */
+ f_ptr->tunnel = ++f_head->text_size;
+ break;
+ case '2':
+ /* Advance and Save the text index */
+ f_ptr->block = ++f_head->text_size;
+ break;
+ default:
+ return (6);
+ break;
+ }
+
+ /* Append chars to the name */
+ strcpy(f_text + f_head->text_size, s);
+
+ /* Advance the index */
+ f_head->text_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Process 'M' for "Mimic" (one line only) */
+ if (buf[0] == 'M')
+ {
+ int mimic;
+
+ /* Scan for the values */
+ if (1 != sscanf(buf + 2, "%d",
+ &mimic)) return (1);
+
+ /* Save the values */
+ f_ptr->mimic = mimic;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'S' for "Shimmer" (one line only) */
+ if (buf[0] == 'S')
+ {
+ char s0, s1, s2, s3, s4, s5, s6;
+
+ /* Scan for the values */
+ if (7 != sscanf(buf + 2, "%c:%c:%c:%c:%c:%c:%c",
+ &s0, &s1, &s2, &s3, &s4, &s5, &s6)) return (1);
+
+ /* Save the values */
+ f_ptr->shimmer[0] = color_char_to_attr(s0);
+ f_ptr->shimmer[1] = color_char_to_attr(s1);
+ f_ptr->shimmer[2] = color_char_to_attr(s2);
+ f_ptr->shimmer[3] = color_char_to_attr(s3);
+ f_ptr->shimmer[4] = color_char_to_attr(s4);
+ f_ptr->shimmer[5] = color_char_to_attr(s5);
+ f_ptr->shimmer[6] = color_char_to_attr(s6);
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Process 'G' for "Graphics" (one line only) */
+ if (buf[0] == 'G')
+ {
+ int tmp;
+
+ /* Paranoia */
+ if (!buf[2]) return (1);
+ if (!buf[3]) return (1);
+ if (!buf[4]) return (1);
+
+ /* Extract the color */
+ tmp = color_char_to_attr(buf[4]);
+
+ /* Paranoia */
+ if (tmp < 0) return (1);
+
+ /* Save the values */
+ f_ptr->d_attr = tmp;
+ f_ptr->d_char = buf[2];
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'E' for "Effects" (up to four lines) -SC- */
+ if (buf[0] == 'E')
+ {
+ int side, dice, freq, type;
+ cptr tmp;
+
+ /* Find the next empty blow slot (if any) */
+ for (i = 0; i < 4; i++) if ((!f_ptr->d_side[i]) &&
+ (!f_ptr->d_dice[i])) break;
+
+ /* Oops, no more slots */
+ if (i == 4) return (1);
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%dd%d:%d:%d",
+ &dice, &side, &freq, &type))
+ {
+ int j;
+
+ if (3 != sscanf(buf + 2, "%dd%d:%d",
+ &dice, &side, &freq)) return (1);
+
+ tmp = buf + 2;
+ for (j = 0; j < 2; j++)
+ {
+ tmp = strchr(tmp, ':');
+ if (tmp == NULL) return (1);
+ tmp++;
+ }
+
+ j = 0;
+
+ while (d_info_dtypes[j].name != NULL)
+ if (strcmp(d_info_dtypes[j].name, tmp) == 0)
+ {
+ f_ptr->d_type[i] = d_info_dtypes[j].feat;
+ break;
+ }
+ else j++;
+
+ if (d_info_dtypes[j].name == NULL) return (1);
+ }
+ else
+ f_ptr->d_type[i] = type;
+
+ freq *= 10;
+ /* Save the values */
+ f_ptr->d_side[i] = side;
+ f_ptr->d_dice[i] = dice;
+ f_ptr->d_frequency[i] = freq;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'F' for flags */
+ if (buf[0] == 'F')
+ {
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_feature_flag(f_ptr, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++f_head->name_size;
+ ++f_head->text_size;
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Grab one flag in an object_kind from a textual string
+ */
+static errr grab_one_kind_flag(object_kind *k_ptr, cptr what, bool_ obvious)
+{
+ int i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags1[i]))
+ {
+ if (obvious)
+ k_ptr->oflags1 |= (1L << i);
+ else
+ k_ptr->flags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2[i]))
+ {
+ if (obvious)
+ k_ptr->oflags2 |= (1L << i);
+ else
+ k_ptr->flags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 -- traps*/
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2_trap[i]))
+ {
+ if (obvious)
+ k_ptr->oflags2 |= (1L << i);
+ else
+ k_ptr->flags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags3[i]))
+ {
+ if (obvious)
+ k_ptr->oflags3 |= (1L << i);
+ else
+ k_ptr->flags3 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags4 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags4[i]))
+ {
+ if (obvious)
+ k_ptr->oflags4 |= (1L << i);
+ else
+ k_ptr->flags4 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags5 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags5[i]))
+ {
+ if (obvious)
+ k_ptr->oflags5 |= (1L << i);
+ else
+ k_ptr->flags5 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check esp_flags */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, esp_flags[i]))
+ {
+ if (obvious)
+ k_ptr->oesp |= (1L << i);
+ else
+ k_ptr->esp |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown object flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+
+/*
+ * Initialize the "k_info" array, by parsing an ascii "template" file
+ */
+errr init_k_info_txt(FILE *fp, char *buf)
+{
+ int i;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ object_kind *k_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Prepare the "fake" stuff */
+ k_head->name_size = 0;
+ k_head->text_size = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i <= error_idx) return (4);
+
+ /* Verify information */
+ if (i >= k_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ k_ptr = &k_info[i];
+
+ /* Hack -- Verify space */
+ if (k_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!k_ptr->name) k_ptr->name = ++k_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(k_name + k_head->name_size, s);
+
+ /* Advance the index */
+ k_head->name_size += strlen(s);
+
+ /* Needed hack */
+ k_ptr->esp = 0;
+ k_ptr->power = -1;
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current k_ptr */
+ if (!k_ptr) return (3);
+
+ /* Process 'D' for "Description" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (k_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!k_ptr->text) k_ptr->text = ++k_head->text_size;
+
+ /* Append a space if needed */
+ else if (k_text[k_head->text_size - 1] != ' ')
+ {
+ /* Append chars to the name */
+ strcpy(k_text + k_head->text_size, " ");
+
+ /* Advance the index */
+ k_head->text_size += 1;
+ }
+
+ /* Append chars to the name */
+ strcpy(k_text + k_head->text_size, s);
+
+ /* Advance the index */
+ k_head->text_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G' for "Graphics" (one line only) */
+ if (buf[0] == 'G')
+ {
+ char sym;
+ int tmp;
+
+ /* Paranoia */
+ if (!buf[2]) return (1);
+ if (!buf[3]) return (1);
+ if (!buf[4]) return (1);
+
+ /* Extract the char */
+ sym = buf[2];
+
+ /* Extract the attr */
+ tmp = color_char_to_attr(buf[4]);
+
+ /* Paranoia */
+ if (tmp < 0) return (1);
+
+ /* Save the values */
+ k_ptr->d_attr = tmp;
+ k_ptr->d_char = sym;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'I' for "Info" (one line only) */
+ if (buf[0] == 'I')
+ {
+ int tval, sval, pval, pval2 = 0;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
+ &tval, &sval, &pval, &pval2))
+ {
+ char spl[70];
+
+ if (4 != sscanf(buf + 2, "%d:%d:%d:SPELL=%s",
+ &tval, &sval, &pval, spl))
+ {
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &tval, &sval, &pval))
+ return (1);
+ }
+ else
+ {
+ char *spl = strchr(buf + 2, '=') + 1;
+
+ pval2 = find_spell(spl);
+ }
+ }
+
+ /* Save the values */
+ k_ptr->tval = tval;
+ k_ptr->sval = sval;
+ k_ptr->pval = pval;
+ k_ptr->pval2 = pval2;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'W' for "More Info" (one line only) */
+ if (buf[0] == 'W')
+ {
+ int level, extra, wgt;
+ long cost;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%ld",
+ &level, &extra, &wgt, &cost)) return (1);
+
+ /* Save the values */
+ k_ptr->level = level;
+ k_ptr->extra = extra;
+ k_ptr->weight = wgt;
+ k_ptr->cost = cost;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'T' for "arTifact Info" (one line only) */
+ if (buf[0] == 'T')
+ {
+ int btval, bsval;
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 2, "%d:%d",
+ &btval, &bsval)) return (1);
+
+ /* Save the values */
+ k_ptr->btval = btval;
+ k_ptr->bsval = bsval;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'Z' for "Granted power" */
+ if (buf[0] == 'Z')
+ {
+ int i;
+
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Find it in the list */
+ for (i = 0; i < power_max; i++)
+ {
+ if (!stricmp(s, powers_type[i].name)) break;
+ }
+
+ if (i == power_max) return (6);
+
+ k_ptr->power = i;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'a' for Activation */
+ if ( buf[0] == 'a')
+ {
+ if (prefix(buf + 2, "HARDCORE="))
+ {
+ k_ptr->activate = get_activation(buf + 11);
+ if (k_ptr->activate == -1)
+ return 1;
+ }
+ else if (prefix(buf + 2, "SPELL="))
+ {
+ k_ptr->activate = -find_spell(buf + 8);
+ if (k_ptr->activate == -( -1))
+ return 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'A' for "Allocation" (one line only) */
+ if (buf[0] == 'A')
+ {
+ int i;
+
+ /* XXX XXX XXX Simply read each number following a colon */
+ for (i = 0, s = buf + 1; s && (s[0] == ':') && s[1]; ++i)
+ {
+ /* Default chance */
+ k_ptr->chance[i] = 1;
+
+ /* Store the level */
+ k_ptr->locale[i] = atoi(s + 1);
+
+ /* Find the slash */
+ t = strchr(s + 1, '/');
+
+ /* Find the next colon */
+ s = strchr(s + 1, ':');
+
+ /* If the slash is "nearby", use it */
+ if (t && (!s || t < s))
+ {
+ int chance = atoi(t + 1);
+ if (chance > 0) k_ptr->chance[i] = chance;
+ }
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'P' for "power" and such */
+ if (buf[0] == 'P')
+ {
+ int ac, hd1, hd2, th, td, ta;
+
+ /* Scan for the values */
+ if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d",
+ &ac, &hd1, &hd2, &th, &td, &ta)) return (1);
+
+ k_ptr->ac = ac;
+ k_ptr->dd = hd1;
+ k_ptr->ds = hd2;
+ k_ptr->to_h = th;
+ k_ptr->to_d = td;
+ k_ptr->to_a = ta;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'F' for flags */
+ if (buf[0] == 'F')
+ {
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_kind_flag(k_ptr, s, FALSE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'f' for obvious flags */
+ if (buf[0] == 'f')
+ {
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_kind_flag(k_ptr, s, TRUE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++k_head->name_size;
+ ++k_head->text_size;
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+/*Get a kind flag, return flag*32+bit number or -1 for unknown*/
+
+int get_k_flag(char *what)
+{
+ int i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags1[i]))
+ return i;
+ if (streq(what, k_info_flags2[i]))
+ return 1*32 + i;
+ if (streq(what, k_info_flags2_trap[i]))
+ return 1*32 + i;
+ if (streq(what, k_info_flags3[i]))
+ return 2*32 + i;
+ if (streq(what, k_info_flags4[i]))
+ return 3*32 + i;
+ if (streq(what, k_info_flags5[i]))
+ return 4*32 + i;
+ if (streq(what, esp_flags[i]))
+ return 5*32 + i;
+ }
+
+ /* Oops */
+ msg_format("Unknown object flag '%s'.", what);
+
+ /* Error */
+ return ( -1);
+
+}
+
+int get_r_flag(char *what)
+{
+ int i;
+
+ /* Check flags */
+ /* this processes all r_info_flag arrays in parallel.
+ Seemed like a good idea at the time..
+ */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags1[i]))
+ return i;
+ if (streq(what, r_info_flags2[i]))
+ return 1*32 + i;
+ if (streq(what, r_info_flags3[i]))
+ return 2*32 + i;
+ if (streq(what, r_info_flags4[i]))
+ return 3*32 + i;
+ if (streq(what, r_info_flags5[i]))
+ return 4*32 + i;
+ if (streq(what, r_info_flags6[i]))
+ return 5*32 + i;
+ if (streq(what, r_info_flags7[i]))
+ return 6*32 + i;
+ if (streq(what, r_info_flags8[i]))
+ return 7*32 + i;
+ if (streq(what, r_info_flags9[i]))
+ return 8*32 + i;
+ }
+
+ /* Oops */
+ msg_format("Unknown race flag '%s'.", what);
+
+ /* Error */
+ return ( -1);
+}
+int init_al_info_essence(char *essence)
+{
+ int i;
+ for ( i = 0 ; essence_names[i][0] ; i++)
+ if (!strncmp(essence_names[i], essence, 9))
+ {
+ return i;
+ }
+ return -1;
+}
+/*
+ * Initialize the "al_info" array, by parsing an ascii "template" file
+ */
+errr init_al_info_txt(FILE *fp, char *buf)
+{
+ int al_idx = 0, a_idx = 0;
+ char *s, *t;
+ struct artifact_select_flag *a_ptr = NULL;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+ /* Fun! */
+ al_head->name_size = 0;
+ *al_name = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'I' for "Info" (one line only) */
+ if (buf[0] == 'I')
+ {
+ int tval, sval, qty;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &tval, &sval, &qty))
+ {
+ return (1);
+ }
+
+ /* ignore everything after the first space. */
+ s = strchr(buf, ' ');
+ if (s != NULL)
+ *s = 0;
+
+ /* Save the values */
+ alchemist_recipes[al_idx].tval = tval;
+ alchemist_recipes[al_idx].sval = sval;
+ alchemist_recipes[al_idx].qty = qty;
+ alchemist_recipes[al_idx].sval_essence = init_al_info_essence(strrchr(buf, ':') + 1);
+ if (alchemist_recipes[al_idx].sval_essence < 0)
+ return 5;
+
+ al_idx++;
+ if (al_idx >= max_al_idx)
+ return 7;
+ /* Next... */
+ continue;
+ }
+ if (buf[0] == 'a')
+ {
+ int qty;
+ if ( 1 != sscanf(buf + 2, "%d", &qty))
+ {
+ return (1);
+ }
+ s = strrchr(buf, ':');
+ *(s++) = 0;
+ t = strchr(s, ' ');
+ *(t++) = 0;
+ alchemist_recipes[al_idx].tval = 0;
+ alchemist_recipes[al_idx].sval = get_k_flag(s);
+ alchemist_recipes[al_idx].qty = qty;
+ alchemist_recipes[al_idx].sval_essence = init_al_info_essence(t);
+ if (alchemist_recipes[al_idx].sval_essence < 0)
+ return 1;
+
+ al_idx++;
+ if (al_idx >= max_al_idx)
+ return 7; /* 7 is an 'out of memory' error */
+
+ continue;
+ }
+ if (buf[0] == 'A')
+ {
+ int group, level, pval, rtval, rsval, rpval;
+ long xp;
+ /*Verify that complete description information is
+ Recorded for previous Artifact flag
+ */
+ if (a_ptr
+ && (!a_ptr->group || !a_ptr->desc || !a_ptr->item_desc != !a_ptr->rtval)
+ )
+ return (1);
+
+ a_ptr = &a_select_flags[a_idx++];
+
+ if ( 7 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%ld",
+ &group, &rtval, &rsval, &rpval, &pval, &level, &xp))
+ return (1);
+ a_ptr->group = group;
+ a_ptr->rtval = rtval;
+ a_ptr->rsval = rsval;
+ a_ptr->rpval = rpval;
+ a_ptr->pval = pval;
+ a_ptr->level = level;
+ a_ptr->xp = xp;
+ continue;
+ }
+
+ /*Anything else here MUST be a artifact flag line*/
+ if ( !a_ptr)
+ return (3);
+
+ if (buf[0] == 'F')
+ {
+ /* Get the Item flag associated with this */
+ a_ptr->flag = get_k_flag(buf + 2);
+ if (a_ptr->flag == -1)
+ return (1);
+ continue;
+ }
+ if (buf[0] == 'x')
+ {
+ /* Get the activation name associated with this */
+ a_ptr->flag = -get_activation(buf + 2);
+ if (a_ptr->flag == 1)
+ return (1);
+ a_ptr->group = 88;
+ a_ptr->pval = 0;
+ continue;
+ }
+ /* Get the race flags associated with this */
+ if (buf[0] == 'f')
+ {
+ char *s, *t;
+ int idx = 0;
+
+ if ( a_ptr->rflag[0] )
+ {
+ msg_print("duplicate f: entries for one corpse");
+ return (5);
+ }
+
+ if ( a_ptr->rtval != TV_CORPSE )
+ {
+ msg_print("f: section for corpse flags only");
+ return (5);
+ }
+ if ( a_ptr->rpval )
+ {
+ msg_print("Can't specify r_info.txt index with f: section");
+ return (5);
+ }
+
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ if ( idx > 5 )
+ {
+ msg_print("Limit on race flags is currently 6");
+ return (5);
+ }
+
+ /* Parse this entry */
+ a_ptr->rflag[idx] = get_r_flag(s);
+ if (a_ptr->rflag[idx++] == -1)
+ return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'p' for "Plural Description" */
+ /* Only valid for flag which depend on pval */
+ if (buf[0] == 'p')
+ {
+ /* Reject if doesn't depend on pval */
+
+ if (!a_ptr->pval)
+ return (1);
+
+ /* Acquire the description */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (al_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ a_ptr->item_descp = ++al_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(al_name + al_head->name_size, s);
+
+ /* Advance the index */
+ al_head->name_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'D' for "Description" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the description */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (al_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ a_ptr->desc = ++al_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(al_name + al_head->name_size, s);
+
+ /* Advance the index */
+ al_head->name_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'd' for "Item Description" */
+ if (buf[0] == 'd')
+ {
+ /* Acquire the name */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (al_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ if (a_ptr->item_desc)
+ return (7);
+
+ /* Advance and Save the name index */
+ a_ptr->item_desc = ++al_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(al_name + al_head->name_size, s);
+
+ /* Advance the index */
+ al_head->name_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Hack - set the al_head->text_size to byte size of array */
+ al_head->text_size = (a_idx + 1) * sizeof(artifact_select_flag);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Grab one flag in an artifact_type from a textual string
+ */
+static errr grab_one_artifact_flag(artifact_type *a_ptr, cptr what, bool_ obvious)
+{
+ int i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags1[i]))
+ {
+ if (obvious)
+ a_ptr->oflags1 |= (1L << i);
+ else
+ a_ptr->flags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2[i]))
+ {
+ if (obvious)
+ a_ptr->oflags2 |= (1L << i);
+ else
+ a_ptr->flags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 -- traps*/
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2_trap[i]))
+ {
+ if (obvious)
+ a_ptr->oflags2 |= (1L << i);
+ else
+ a_ptr->flags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags3[i]))
+ {
+ if (obvious)
+ a_ptr->oflags3 |= (1L << i);
+ else
+ a_ptr->flags3 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags4 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags4[i]))
+ {
+ if (obvious)
+ a_ptr->oflags4 |= (1L << i);
+ else
+ a_ptr->flags4 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags5 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags5[i]))
+ {
+ if (obvious)
+ a_ptr->oflags5 |= (1L << i);
+ else
+ a_ptr->flags5 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check esp_flags */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, esp_flags[i]))
+ {
+ if (obvious)
+ a_ptr->oesp |= (1L << i);
+ else
+ a_ptr->esp |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown artifact flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+
+
+
+
+/*
+ * Initialize the "a_info" array, by parsing an ascii "template" file
+ */
+errr init_a_info_txt(FILE *fp, char *buf)
+{
+ int i;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ artifact_type *a_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= a_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ a_ptr = &a_info[i];
+
+ /* Hack -- Verify space */
+ if (a_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!a_ptr->name) a_ptr->name = ++a_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(a_name + a_head->name_size, s);
+
+ /* Advance the index */
+ a_head->name_size += strlen(s);
+
+ /* Ignore everything */
+ a_ptr->flags3 |= (TR3_IGNORE_ACID);
+ a_ptr->flags3 |= (TR3_IGNORE_ELEC);
+ a_ptr->flags3 |= (TR3_IGNORE_FIRE);
+ a_ptr->flags3 |= (TR3_IGNORE_COLD);
+
+ /* Needed hack */
+ a_ptr->esp = 0;
+ a_ptr->power = -1;
+
+ /*Require activating artifacts to have a activation type */
+ if (a_ptr && a_ptr->flags3 & TR3_ACTIVATE && !a_ptr->activate)
+ {
+ msg_print("Activate flag without activate type");
+ return 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current a_ptr */
+ if (!a_ptr) return (3);
+
+ /* Process 'D' for "Description" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (a_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!a_ptr->text) a_ptr->text = ++a_head->text_size;
+
+ /* Append a space at the end of the line, if needed */
+ else if (a_text[a_head->text_size - 1] != ' ')
+ {
+ /* Append the space */
+ strcpy(a_text + a_head->text_size, " ");
+
+ /* Advance the index */
+ a_head->text_size += 1;
+ }
+
+ /* Append chars to the name */
+ strcpy(a_text + a_head->text_size, s);
+
+ /* Advance the index */
+ a_head->text_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'I' for "Info" (one line only) */
+ if (buf[0] == 'I')
+ {
+ int tval, sval, pval;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &tval, &sval, &pval))
+ {
+ return (1);
+ }
+
+ /* Save the values */
+ a_ptr->tval = tval;
+ a_ptr->sval = sval;
+ a_ptr->pval = pval;
+
+ /* Verify */
+ if (!lookup_kind(tval, sval)) return (6);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'W' for "More Info" (one line only) */
+ if (buf[0] == 'W')
+ {
+ int level, rarity, wgt;
+ long cost;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%ld",
+ &level, &rarity, &wgt, &cost)) return (1);
+
+ /* Save the values */
+ a_ptr->level = level;
+ a_ptr->rarity = rarity;
+ a_ptr->weight = wgt;
+ a_ptr->cost = cost;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'P' for "power" and such */
+ if (buf[0] == 'P')
+ {
+ int ac, hd1, hd2, th, td, ta;
+
+ /* Scan for the values */
+ if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d",
+ &ac, &hd1, &hd2, &th, &td, &ta)) return (1);
+
+ a_ptr->ac = ac;
+ a_ptr->dd = hd1;
+ a_ptr->ds = hd2;
+ a_ptr->to_h = th;
+ a_ptr->to_d = td;
+ a_ptr->to_a = ta;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'Z' for "Granted power" */
+ if (buf[0] == 'Z')
+ {
+ int i;
+
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Find it in the list */
+ for (i = 0; i < power_max; i++)
+ {
+ if (!stricmp(s, powers_type[i].name)) break;
+ }
+
+ if (i == power_max) return (6);
+
+ a_ptr->power = i;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'F' for flags */
+ if (buf[0] == 'F')
+ {
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_artifact_flag(a_ptr, s, FALSE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'f' for obvious flags */
+ if (buf[0] == 'f')
+ {
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_artifact_flag(a_ptr, s, TRUE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Read activation type. */
+ if (buf[0] == 'a')
+ {
+ if (prefix(buf + 2, "HARDCORE="))
+ {
+ a_ptr->activate = get_activation(buf + 11);
+ if (a_ptr->activate == -1)
+ return 1;
+ }
+ else if (prefix(buf + 2, "SPELL="))
+ {
+ a_ptr->activate = -find_spell(buf + 8);
+ if (a_ptr->activate == -( -1))
+ return 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++a_head->name_size;
+ ++a_head->text_size;
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+/*
+* Initialize the "set_info" array, by parsing an ascii "template" file
+*/
+errr init_set_info_txt(FILE *fp, char *buf)
+{
+ int i;
+ int cur_art = 0, cur_num = 0;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ set_type *set_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ int z, y;
+
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= set_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ set_ptr = &set_info[i];
+
+ /* Hack -- Verify space */
+ if (set_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!set_ptr->name) set_ptr->name = ++set_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(set_name + set_head->name_size, s);
+
+ /* Advance the index */
+ set_head->name_size += strlen(s);
+
+ /* Needed hack */
+ set_ptr->num = 0;
+ set_ptr->num_use = 0;
+ for (z = 0; z < 6; z++)
+ {
+ set_ptr->arts[z].a_idx = 0;
+ set_ptr->arts[z].present = FALSE;
+ for (y = 0; y < 6; y++)
+ {
+ set_ptr->arts[z].flags1[y] = 0;
+ set_ptr->arts[z].flags2[y] = 0;
+ set_ptr->arts[z].flags3[y] = 0;
+ set_ptr->arts[z].flags4[y] = 0;
+ set_ptr->arts[z].flags5[y] = 0;
+ set_ptr->arts[z].esp[y] = 0;
+ set_ptr->arts[z].pval[y] = 0;
+ }
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current set_ptr */
+ if (!set_ptr) return (3);
+
+ /* Process 'D' for "Description" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (set_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!set_ptr->desc) set_ptr->desc = ++set_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(set_text + set_head->text_size, s);
+
+ /* Advance the index */
+ set_head->text_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'P' for "Power" (up to 6) */
+ if (buf[0] == 'P')
+ {
+ int a_idx, num, pval;
+ int z;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &a_idx, &num, &pval))
+ {
+ return (1);
+ }
+
+ for (z = 0; z < set_ptr->num; z++)
+ if (set_ptr->arts[z].a_idx == a_idx) break;
+ if (z == set_ptr->num)
+ {
+ set_ptr->num++;
+ set_ptr->arts[z].a_idx = a_idx;
+ }
+
+ /* Save the values */
+ set_ptr->arts[z].pval[num - 1] = pval;
+ cur_art = z;
+ cur_num = num - 1;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for flags */
+ if (buf[0] == 'F')
+ {
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_race_kind_flag(&set_ptr->arts[cur_art].flags1[cur_num],
+ &set_ptr->arts[cur_art].flags2[cur_num],
+ &set_ptr->arts[cur_art].flags3[cur_num],
+ &set_ptr->arts[cur_art].flags4[cur_num],
+ &set_ptr->arts[cur_art].flags5[cur_num],
+ &set_ptr->arts[cur_art].esp[cur_num],
+ s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++set_head->name_size;
+ ++set_head->text_size;
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialize the "s_info" array, by parsing an ascii "template" file
+ */
+errr init_s_info_txt(FILE *fp, char *buf)
+{
+ int i, z, order = 1;
+
+ char *s;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ skill_type *s_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'T' for "skill Tree" */
+ if (buf[0] == 'T')
+ {
+ char *sec;
+ s16b s1, s2;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 2, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+
+ s1 = find_skill(buf + 2);
+ s2 = find_skill(sec);
+ if (s2 == -1) return (1);
+
+ s_info[s2].father = s1;
+ s_info[s2].order = order++;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'E' for "Exclusive" */
+ if (buf[0] == 'E')
+ {
+ char *sec;
+ s16b s1, s2;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 2, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+
+ s1 = find_skill(buf + 2);
+ s2 = find_skill(sec);
+ if ((s1 == -1) || (s2 == -1)) return (1);
+
+ s_info[s1].action[s2] = SKILL_EXCLUSIVE;
+ s_info[s2].action[s1] = SKILL_EXCLUSIVE;
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Process 'O' for "Opposite" */
+ if (buf[0] == 'O')
+ {
+ char *sec, *cval;
+ s16b s1, s2;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 2, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+ if (NULL == (cval = strchr(sec, '%')))
+ {
+ return (1);
+ }
+ *cval = '\0';
+ cval++;
+ if (!*cval) return (1);
+
+ s1 = find_skill(buf + 2);
+ s2 = find_skill(sec);
+ if ((s1 == -1) || (s2 == -1)) return (1);
+
+ s_info[s1].action[s2] = -atoi(cval);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'A' for "Amical/friendly" */
+ if (buf[0] == 'f')
+ {
+ char *sec, *cval;
+ s16b s1, s2;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 2, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+ if (NULL == (cval = strchr(sec, '%')))
+ {
+ return (1);
+ }
+ *cval = '\0';
+ cval++;
+ if (!*cval) return (1);
+
+ s1 = find_skill(buf + 2);
+ s2 = find_skill(sec);
+ if ((s1 == -1) || (s2 == -1)) return (1);
+
+ s_info[s1].action[s2] = atoi(cval);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i >= s_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ s_ptr = &s_info[i];
+
+ /* Hack -- Verify space */
+ if (s_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!s_ptr->name) s_ptr->name = ++s_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(s_name + s_head->name_size, s);
+
+ /* Advance the index */
+ s_head->name_size += strlen(s);
+
+ /* Init */
+ s_ptr->action_mkey = 0;
+ s_ptr->dev = FALSE;
+ s_ptr->random_gain_chance = 100;
+ for (z = 0; z < max_s_idx; z++)
+ {
+ s_ptr->action[z] = 0;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current s_ptr */
+ if (!s_ptr) return (3);
+
+ /* Process 'D' for "Description" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (s_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!s_ptr->desc)
+ {
+ s_ptr->desc = ++s_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(s_text + s_head->text_size, s);
+
+ /* Advance the index */
+ s_head->text_size += strlen(s);
+ }
+ else
+ {
+ /* Append chars to the name */
+ strcpy(s_text + s_head->text_size, format("\n%s", s));
+
+ /* Advance the index */
+ s_head->text_size += strlen(s) + 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'A' for "Activation Description" */
+ if (buf[0] == 'A')
+ {
+ char *txt;
+
+ /* Acquire the text */
+ s = buf + 2;
+
+ if (NULL == (txt = strchr(s, ':'))) return (1);
+ *txt = '\0';
+ txt++;
+
+ /* Hack -- Verify space */
+ if (s_head->text_size + strlen(txt) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!s_ptr->action_desc) s_ptr->action_desc = ++s_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(s_text + s_head->text_size, txt);
+ s_ptr->action_mkey = atoi(s);
+
+ /* Advance the index */
+ s_head->text_size += strlen(txt);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'I' for "Info" (one line only) */
+ if (buf[0] == 'I')
+ {
+ int rate;
+
+ /* Scan for the values */
+ if (1 != sscanf(buf + 2, "%d", &rate))
+ {
+ return (1);
+ }
+
+ /* Save the values */
+ s_ptr->rate = rate;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G' for "random Gain" (one line only) */
+ if (buf[0] == 'G')
+ {
+ int chance;
+
+ /* Scan for the values */
+ if (1 != sscanf(buf + 2, "%d", &chance))
+ {
+ return (1);
+ }
+
+ /* Save the values */
+ s_ptr->random_gain_chance = chance;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for flags */
+ if (buf[0] == 'F')
+ {
+ char *t;
+
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_skill_flag(&(s_ptr->flags1), s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++s_head->name_size;
+ ++s_head->text_size;
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialize the "ab_info" array, by parsing an ascii "template" file
+ */
+errr init_ab_info_txt(FILE *fp, char *buf)
+{
+ int i, z;
+
+ char *s;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ ability_type *ab_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i >= ab_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ ab_ptr = &ab_info[i];
+
+ /* Hack -- Verify space */
+ if (ab_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!ab_ptr->name) ab_ptr->name = ++ab_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(ab_name + ab_head->name_size, s);
+
+ /* Advance the index */
+ ab_head->name_size += strlen(s);
+
+ /* Init */
+ ab_ptr->action_mkey = 0;
+ ab_ptr->acquired = FALSE;
+ for (z = 0; z < 10; z++)
+ {
+ ab_ptr->skills[z] = -1;
+ ab_ptr->need_abilities[z] = -1;
+ ab_ptr->forbid_abilities[z] = -1;
+ }
+ for (z = 0; z < 6; z++)
+ {
+ ab_ptr->stat[z] = -1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current ab_ptr */
+ if (!ab_ptr) return (3);
+
+ /* Process 'D' for "Description" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (ab_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!ab_ptr->desc)
+ {
+ ab_ptr->desc = ++ab_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(ab_text + ab_head->text_size, s);
+
+ /* Advance the index */
+ ab_head->text_size += strlen(s);
+ }
+ else
+ {
+ /* Append chars to the name */
+ strcpy(ab_text + ab_head->text_size, format("\n%s", s));
+
+ /* Advance the index */
+ ab_head->text_size += strlen(s) + 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'A' for "Activation Description" */
+ if (buf[0] == 'A')
+ {
+ char *txt;
+
+ /* Acquire the text */
+ s = buf + 2;
+
+ if (NULL == (txt = strchr(s, ':'))) return (1);
+ *txt = '\0';
+ txt++;
+
+ /* Hack -- Verify space */
+ if (ab_head->text_size + strlen(txt) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!ab_ptr->action_desc) ab_ptr->action_desc = ++ab_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(ab_text + ab_head->text_size, txt);
+ ab_ptr->action_mkey = atoi(s);
+
+ /* Advance the index */
+ ab_head->text_size += strlen(txt);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'I' for "Info" (one line only) */
+ if (buf[0] == 'I')
+ {
+ int cost;
+
+ /* Scan for the values */
+ if (1 != sscanf(buf + 2, "%d", &cost))
+ {
+ return (1);
+ }
+
+ /* Save the values */
+ ab_ptr->cost = cost;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'k' for "Skill" */
+ if (buf[0] == 'k')
+ {
+ char *sec;
+ s16b level, skill;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 2, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+
+ level = atoi(buf + 2);
+ skill = find_skill(sec);
+
+ if (skill == -1) return (1);
+
+ for (z = 0; z < 10; z++)
+ if (ab_ptr->skills[z] == -1) break;
+
+ if (z < 10)
+ {
+ ab_ptr->skills[z] = skill;
+ ab_ptr->skill_levels[z] = level;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'a' for "needed ability" */
+ if (buf[0] == 'a')
+ {
+ s16b ab;
+
+ ab = find_ability(buf + 2);
+
+ if (ab == -1) return (1);
+
+ for (z = 0; z < 10; z++)
+ if (ab_ptr->need_abilities[z] == -1) break;
+
+ if (z < 10)
+ {
+ ab_ptr->need_abilities[z] = ab;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'S' for "Stat" */
+ if (buf[0] == 'S')
+ {
+ char *sec;
+ s16b stat;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 2, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+
+ for (stat = 0; stat < 6; stat++)
+ {
+ if (!strcmp(stat_names[stat], sec))
+ break;
+ }
+
+ if (stat == 6) return (1);
+
+ ab_ptr->stat[stat] = atoi(buf + 2);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'E' for "Excluding ability" */
+ if (buf[0] == 'E')
+ {
+ char *sec;
+ s16b ab1, ab2;
+
+ /* Scan for the values */
+ if (NULL == (sec = strchr(buf + 2, ':')))
+ {
+ return (1);
+ }
+ *sec = '\0';
+ sec++;
+ if (!*sec) return (1);
+
+ ab1 = find_ability(buf + 2);
+ ab2 = find_ability(sec);
+
+ if ((ab1 == -1) || (ab2 == -1)) return (1);
+
+ for (z = 0; z < 10; z++)
+ if (ab_info[ab1].forbid_abilities[z] == -1) break;
+ if (z < 10)
+ {
+ ab_info[ab1].forbid_abilities[z] = ab2;
+ }
+
+ for (z = 0; z < 10; z++)
+ if (ab_info[ab2].forbid_abilities[z] == -1) break;
+ if (z < 10)
+ {
+ ab_info[ab2].forbid_abilities[z] = ab1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++ab_head->name_size;
+ ++ab_head->text_size;
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Grab one flag in a ego-item_type from a textual string
+ */
+static bool_ grab_one_ego_item_flag(ego_item_type *e_ptr, cptr what, int n, bool_ obvious)
+{
+ int i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags1[i]))
+ {
+ if (obvious)
+ e_ptr->oflags1[n] |= (1L << i);
+ else
+ e_ptr->flags1[n] |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2[i]))
+ {
+ if (obvious)
+ e_ptr->oflags2[n] |= (1L << i);
+ else
+ e_ptr->flags2[n] |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 -- traps */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2_trap[i]))
+ {
+ if (obvious)
+ e_ptr->oflags2[n] |= (1L << i);
+ else
+ e_ptr->flags2[n] |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags3[i]))
+ {
+ if (obvious)
+ e_ptr->oflags3[n] |= (1L << i);
+ else
+ e_ptr->flags3[n] |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags4 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags4[i]))
+ {
+ if (obvious)
+ e_ptr->oflags4[n] |= (1L << i);
+ else
+ e_ptr->flags4[n] |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags5 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags5[i]))
+ {
+ if (obvious)
+ e_ptr->oflags5[n] |= (1L << i);
+ else
+ e_ptr->flags5[n] |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check esp_flags */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, esp_flags[i]))
+ {
+ if (obvious)
+ e_ptr->oesp[n] |= (1L << i);
+ else
+ e_ptr->esp[n] |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check ego_flags */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, ego_flags[i]))
+ {
+ e_ptr->fego[n] |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown ego-item flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+
+static bool_ grab_one_ego_item_flag_restrict(ego_item_type *e_ptr, cptr what, bool_ need)
+{
+ int i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags1[i]))
+ {
+ if (need)
+ e_ptr->need_flags1 |= (1L << i);
+ else
+ e_ptr->forbid_flags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2[i]))
+ {
+ if (need)
+ e_ptr->need_flags2 |= (1L << i);
+ else
+ e_ptr->forbid_flags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 -- traps */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2_trap[i]))
+ {
+ if (need)
+ e_ptr->need_flags2 |= (1L << i);
+ else
+ e_ptr->forbid_flags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags3[i]))
+ {
+ if (need)
+ e_ptr->need_flags3 |= (1L << i);
+ else
+ e_ptr->forbid_flags3 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags4 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags4[i]))
+ {
+ if (need)
+ e_ptr->need_flags4 |= (1L << i);
+ else
+ e_ptr->forbid_flags4 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags5 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags5[i]))
+ {
+ if (need)
+ e_ptr->need_flags5 |= (1L << i);
+ else
+ e_ptr->forbid_flags5 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check esp_flags */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, esp_flags[i]))
+ {
+ if (need)
+ e_ptr->need_esp |= (1L << i);
+ else
+ e_ptr->forbid_esp |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown ego-item restrict flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+
+
+
+
+/*
+ * Initialize the "e_info" array, by parsing an ascii "template" file
+ */
+errr init_e_info_txt(FILE *fp, char *buf)
+{
+ int i, cur_r = -1, cur_t = 0, j;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ ego_item_type *e_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= e_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ e_ptr = &e_info[i];
+
+ /* Hack -- Verify space */
+ if (e_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!e_ptr->name) e_ptr->name = ++e_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(e_name + e_head->name_size, s);
+
+ /* Advance the index */
+ e_head->name_size += strlen(s);
+
+ /* Needed hack */
+ e_ptr->power = -1;
+ cur_r = -1;
+ cur_t = 0;
+
+ for (j = 0; j < 10; j++)
+ {
+ e_ptr->tval[j] = 255;
+ }
+ for (j = 0; j < 5; j++)
+ {
+ e_ptr->rar[j] = 0;
+ e_ptr->flags1[j] = 0;
+ e_ptr->flags2[j] = 0;
+ e_ptr->flags3[j] = 0;
+ e_ptr->flags4[j] = 0;
+ e_ptr->flags5[j] = 0;
+ e_ptr->esp[j] = 0;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current e_ptr */
+ if (!e_ptr) return (3);
+
+
+ /* Process 'T' for "Tval/Sval" (up to 5 lines) */
+ if (buf[0] == 'T')
+ {
+ int tv, minsv, maxsv;
+
+ if (cur_t == 10) return 1;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &tv, &minsv, &maxsv)) return (1);
+
+ /* Save the values */
+ e_ptr->tval[cur_t] = tv;
+ e_ptr->min_sval[cur_t] = minsv;
+ e_ptr->max_sval[cur_t] = maxsv;
+
+ cur_t++;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'R' for "flags rarity" (up to 5 lines) */
+ if (buf[0] == 'R')
+ {
+ int rar;
+
+ if (cur_r == 5) return 1;
+
+ /* Scan for the values */
+ if (1 != sscanf(buf + 2, "%d",
+ &rar)) return (1);
+
+ cur_r++;
+
+ /* Save the values */
+ e_ptr->rar[cur_r] = rar;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'X' for "Xtra" (one line only) */
+ if (buf[0] == 'X')
+ {
+ int slot, rating;
+ char pos;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%c:%d:%d",
+ &pos, &slot, &rating)) return (1);
+
+ /* Save the values */
+ /* e_ptr->slot = slot; */
+ e_ptr->rating = rating;
+ e_ptr->before = (pos == 'B') ? TRUE : FALSE;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'W' for "More Info" (one line only) */
+ if (buf[0] == 'W')
+ {
+ int level, rarity, rarity2;
+ long cost;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%ld",
+ &level, &rarity, &rarity2, &cost)) return (1);
+
+ /* Save the values */
+ e_ptr->level = level;
+ e_ptr->rarity = rarity;
+ e_ptr->mrarity = rarity2;
+ e_ptr->cost = cost;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'C' for "creation" */
+ if (buf[0] == 'C')
+ {
+ int th, td, ta, pv;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
+ &th, &td, &ta, &pv)) return (1);
+
+ e_ptr->max_to_h = th;
+ e_ptr->max_to_d = td;
+ e_ptr->max_to_a = ta;
+ e_ptr->max_pval = pv;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'Z' for "Granted power" */
+ if (buf[0] == 'Z')
+ {
+ int i;
+
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Find it in the list */
+ for (i = 0; i < power_max; i++)
+ {
+ if (!stricmp(s, powers_type[i].name)) break;
+ }
+
+ if (i == power_max) return (6);
+
+ e_ptr->power = i;
+
+ /* Next... */
+ continue;
+ }
+
+ if (buf[0] == 'a')
+ {
+ if (prefix(buf + 2, "HARDCORE="))
+ {
+ e_ptr->activate = get_activation(buf + 11);
+ if (e_ptr->activate == -1)
+ return 1;
+ }
+ else if (prefix(buf + 2, "SPELL="))
+ {
+ e_ptr->activate = -find_spell(buf + 8);
+ if (e_ptr->activate == -( -1))
+ return 1;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'r:N' for needed flags */
+ if ((buf[0] == 'r') && (buf[2] == 'N'))
+ {
+ /* Parse every entry textually */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_ego_item_flag_restrict(e_ptr, s, TRUE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'r:F' for forbidden flags */
+ if ((buf[0] == 'r') && (buf[2] == 'F'))
+ {
+ /* Parse every entry textually */
+ for (s = buf + 4; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_ego_item_flag_restrict(e_ptr, s, FALSE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'F' for flags */
+ if (buf[0] == 'F')
+ {
+ if (cur_r == -1) return (6);
+
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_ego_item_flag(e_ptr, s, cur_r, FALSE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'f' for obvious flags */
+ if (buf[0] == 'f')
+ {
+ if (cur_r == -1) return (6);
+
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_ego_item_flag(e_ptr, s, cur_r, TRUE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++e_head->name_size;
+ ++e_head->text_size;
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Grab one flag in a randart_part_type from a textual string
+ */
+static bool_ grab_one_randart_item_flag(randart_part_type *ra_ptr, cptr what, char c)
+{
+ int i;
+ u32b *f1, *f2, *f3, *f4, *f5, *esp;
+
+ if (c == 'F')
+ {
+ f1 = &ra_ptr->flags1;
+ f2 = &ra_ptr->flags2;
+ f3 = &ra_ptr->flags3;
+ f4 = &ra_ptr->flags4;
+ f5 = &ra_ptr->flags5;
+ esp = &ra_ptr->esp;
+ }
+ else
+ {
+ f1 = &ra_ptr->aflags1;
+ f2 = &ra_ptr->aflags2;
+ f3 = &ra_ptr->aflags3;
+ f4 = &ra_ptr->aflags4;
+ f5 = &ra_ptr->aflags5;
+ esp = &ra_ptr->aesp;
+ }
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags1[i]))
+ {
+ *f1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2[i]))
+ {
+ *f2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags2 -- traps */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags2_trap[i]))
+ {
+ *f2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags3[i]))
+ {
+ *f3 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags4 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags4[i]))
+ {
+ *f4 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check flags5 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, k_info_flags5[i]))
+ {
+ *f5 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check esp_flags */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, esp_flags[i]))
+ {
+ *esp |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Check ego_flags */
+ if (c == 'F')
+ {
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, ego_flags[i]))
+ {
+ ra_ptr->fego |= (1L << i);
+ return (0);
+ }
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown ego-item flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+
+
+
+
+/*
+ * Initialize the "ra_info" array, by parsing an ascii "template" file
+ */
+errr init_ra_info_txt(FILE *fp, char *buf)
+{
+ int i, cur_t = 0, j, cur_g = 0;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ randart_part_type *ra_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'G' for "General" (up to 30 lines) */
+ if (buf[0] == 'G')
+ {
+ int chance, dd, ds, plus;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%dd%d:%d",
+ &chance, &dd, &ds, &plus)) return (1);
+
+ /* Save the values */
+ ra_gen[cur_g].chance = chance;
+ ra_gen[cur_g].dd = dd;
+ ra_gen[cur_g].ds = ds;
+ ra_gen[cur_g].plus = plus;
+ cur_g++;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'N' for "New/Number" */
+ if (buf[0] == 'N')
+ {
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= ra_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ ra_ptr = &ra_info[i];
+
+ /* Needed hack */
+ ra_ptr->power = -1;
+ cur_t = 0;
+
+ for (j = 0; j < 20; j++)
+ {
+ ra_ptr->tval[j] = 255;
+ }
+ ra_ptr->flags1 = 0;
+ ra_ptr->flags2 = 0;
+ ra_ptr->flags3 = 0;
+ ra_ptr->flags4 = 0;
+ ra_ptr->flags5 = 0;
+ ra_ptr->esp = 0;
+ ra_ptr->fego = 0;
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current ra_ptr */
+ if (!ra_ptr) return (3);
+
+ /* Process 'T' for "Tval/Sval" (up to 5 lines) */
+ if (buf[0] == 'T')
+ {
+ int tv, minsv, maxsv;
+
+ if (cur_t == 20) return 1;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &tv, &minsv, &maxsv)) return (1);
+
+ /* Save the values */
+ ra_ptr->tval[cur_t] = tv;
+ ra_ptr->min_sval[cur_t] = minsv;
+ ra_ptr->max_sval[cur_t] = maxsv;
+
+ cur_t++;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'X' for "Xtra" (one line only) */
+ if (buf[0] == 'X')
+ {
+ int power, max;
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 2, "%d:%d",
+ &power, &max)) return (1);
+
+ /* Save the values */
+ ra_ptr->value = power;
+ ra_ptr->max = max;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'W' for "More Info" (one line only) */
+ if (buf[0] == 'W')
+ {
+ int level, rarity, rarity2;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &level, &rarity, &rarity2)) return (1);
+
+ /* Save the values */
+ ra_ptr->level = level;
+ ra_ptr->rarity = rarity;
+ ra_ptr->mrarity = rarity2;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'C' for "creation" */
+ if (buf[0] == 'C')
+ {
+ int th, td, ta, pv;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
+ &th, &td, &ta, &pv)) return (1);
+
+ ra_ptr->max_to_h = th;
+ ra_ptr->max_to_d = td;
+ ra_ptr->max_to_a = ta;
+ ra_ptr->max_pval = pv;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'Z' for "Granted power" */
+ if (buf[0] == 'Z')
+ {
+ int i;
+
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Find it in the list */
+ for (i = 0; i < power_max; i++)
+ {
+ if (!stricmp(s, powers_type[i].name)) break;
+ }
+
+ if (i == power_max) return (6);
+
+ ra_ptr->power = i;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'F' for flags */
+ if (buf[0] == 'F')
+ {
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_randart_item_flag(ra_ptr, s, 'F')) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Hack -- Process 'A' for antagonic flags */
+ if (buf[0] == 'A')
+ {
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_randart_item_flag(ra_ptr, s, 'A')) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Grab one (basic) flag in a monster_race from a textual string
+ */
+static errr grab_one_basic_flag(monster_race *r_ptr, cptr what)
+{
+ int i;
+
+ /* Scan flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags1[i]))
+ {
+ r_ptr->flags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags2[i]))
+ {
+ r_ptr->flags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags3[i]))
+ {
+ r_ptr->flags3 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags7 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags7[i]))
+ {
+ r_ptr->flags7 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags8 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags8[i]))
+ {
+ r_ptr->flags8 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags9 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags9[i]))
+ {
+ r_ptr->flags9 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown monster flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+
+/*
+ * Grab one (spell) flag in a monster_race from a textual string
+ */
+static errr grab_one_spell_flag(monster_race *r_ptr, cptr what)
+{
+ int i;
+
+ /* Scan flags4 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags4[i]))
+ {
+ r_ptr->flags4 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags5 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags5[i]))
+ {
+ r_ptr->flags5 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags6 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags6[i]))
+ {
+ r_ptr->flags6 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown monster flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+
+/*
+ * Initialize the "r_info" array, by parsing an ascii "template" file
+ */
+errr init_r_info_txt(FILE *fp, char *buf)
+{
+ int i;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ monster_race *r_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Start the "fake" stuff */
+ r_head->name_size = 0;
+ r_head->text_size = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= r_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ r_ptr = &r_info[i];
+
+ /* Hack -- Verify space */
+ if (r_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!r_ptr->name) r_ptr->name = ++r_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(r_name + r_head->name_size, s);
+
+ /* Advance the index */
+ r_head->name_size += strlen(s);
+
+ /* HACK -- Those ones HAVE to have a set default value */
+ r_ptr->drops.treasure = OBJ_GENE_TREASURE;
+ r_ptr->drops.combat = OBJ_GENE_COMBAT;
+ r_ptr->drops.magic = OBJ_GENE_MAGIC;
+ r_ptr->drops.tools = OBJ_GENE_TOOL;
+ r_ptr->freq_inate = r_ptr->freq_spell = 0;
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current r_ptr */
+ if (!r_ptr) return (3);
+
+
+ /* Process 'D' for "Description" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (r_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!r_ptr->text) r_ptr->text = ++r_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(r_text + r_head->text_size, s);
+
+ /* Advance the index */
+ r_head->text_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G' for "Graphics" (one line only) */
+ if (buf[0] == 'G')
+ {
+ char sym;
+ int tmp;
+
+ /* Paranoia */
+ if (!buf[2]) return (1);
+ if (!buf[3]) return (1);
+ if (!buf[4]) return (1);
+
+ /* Extract the char */
+ sym = buf[2];
+
+ /* Extract the attr */
+ tmp = color_char_to_attr(buf[4]);
+
+ /* Paranoia */
+ if (tmp < 0) return (1);
+
+ /* Save the values */
+ r_ptr->d_char = sym;
+ r_ptr->d_attr = tmp;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'I' for "Info" (one line only) */
+ if (buf[0] == 'I')
+ {
+ int spd, hp1, hp2, aaf, ac, slp;
+
+ /* Scan for the other values */
+ if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d",
+ &spd, &hp1, &hp2, &aaf, &ac, &slp)) return (1);
+
+ /* Save the values */
+ r_ptr->speed = spd;
+ r_ptr->hdice = hp1;
+ r_ptr->hside = hp2;
+ r_ptr->aaf = aaf;
+ r_ptr->ac = ac;
+ r_ptr->sleep = slp;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'E' for "Body Parts" (one line only) */
+ if (buf[0] == 'E')
+ {
+ int weap, tors, fing, head, arms, legs;
+
+ /* Scan for the other values */
+ if (BODY_MAX != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d",
+ &weap, &tors, &arms, &fing, &head, &legs)) return (1);
+
+ /* Save the values */
+ r_ptr->body_parts[BODY_WEAPON] = weap;
+ r_ptr->body_parts[BODY_TORSO] = tors;
+ r_ptr->body_parts[BODY_ARMS] = arms;
+ r_ptr->body_parts[BODY_FINGER] = fing;
+ r_ptr->body_parts[BODY_HEAD] = head;
+ r_ptr->body_parts[BODY_LEGS] = legs;
+
+ /* Mega debugging hack */
+ if (weap > arms) quit(format("monster %d, %d weapon(s), %d arm(s) !", error_idx, weap, arms));
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'O' for "Object type" (one line only) */
+ if (buf[0] == 'O')
+ {
+ int treasure, combat, magic, tools;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
+ &treasure, &combat, &magic, &tools)) return (1);
+
+ /* Save the values */
+ r_ptr->drops.treasure = treasure;
+ r_ptr->drops.combat = combat;
+ r_ptr->drops.magic = magic;
+ r_ptr->drops.tools = tools;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'W' for "More Info" (one line only) */
+ if (buf[0] == 'W')
+ {
+ int lev, rar, wt;
+ long exp;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%ld",
+ &lev, &rar, &wt, &exp)) return (1);
+
+ /* Save the values */
+ r_ptr->level = lev;
+ r_ptr->rarity = rar;
+ /* MEGA HACK */
+ if (!wt) wt = 100;
+ r_ptr->weight = wt;
+ r_ptr->mexp = exp;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'B' for "Blows" (up to four lines) */
+ if (buf[0] == 'B')
+ {
+ int n1, n2;
+
+ /* Find the next empty blow slot (if any) */
+ for (i = 0; i < 4; i++) if (!r_ptr->blow[i].method) break;
+
+ /* Oops, no more slots */
+ if (i == 4) return (1);
+
+ /* Analyze the first field */
+ for (s = t = buf + 2; *t && (*t != ':'); t++) /* loop */;
+
+ /* Terminate the field (if necessary) */
+ if (*t == ':') *t++ = '\0';
+
+ /* Analyze the method */
+ for (n1 = 0; r_info_blow_method[n1]; n1++)
+ {
+ if (streq(s, r_info_blow_method[n1])) break;
+ }
+
+ /* Invalid method */
+ if (!r_info_blow_method[n1]) return (1);
+
+ /* Analyze the second field */
+ for (s = t; *t && (*t != ':'); t++) /* loop */;
+
+ /* Terminate the field (if necessary) */
+ if (*t == ':') *t++ = '\0';
+
+ /* Analyze effect */
+ for (n2 = 0; r_info_blow_effect[n2]; n2++)
+ {
+ if (streq(s, r_info_blow_effect[n2])) break;
+ }
+
+ /* Invalid effect */
+ if (!r_info_blow_effect[n2]) return (1);
+
+ /* Analyze the third field */
+ for (s = t; *t && (*t != 'd'); t++) /* loop */;
+
+ /* Terminate the field (if necessary) */
+ if (*t == 'd') *t++ = '\0';
+
+ /* Save the method */
+ r_ptr->blow[i].method = n1;
+
+ /* Save the effect */
+ r_ptr->blow[i].effect = n2;
+
+ /* Extract the damage dice and sides */
+ r_ptr->blow[i].d_dice = atoi(s);
+ r_ptr->blow[i].d_side = atoi(t);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for "Basic Flags" (multiple lines) */
+ if (buf[0] == 'F')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_basic_flag(r_ptr, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'S' for "Spell Flags" (multiple lines) */
+ if (buf[0] == 'S')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* XXX XXX XXX Hack -- Read spell frequency */
+ if (1 == sscanf(s, "1_IN_%d", &i))
+ {
+ /* Extract a "frequency" */
+ r_ptr->freq_spell = r_ptr->freq_inate = 100 / i;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_spell_flag(r_ptr, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++r_head->name_size;
+ ++r_head->text_size;
+
+ for (i = 1; i < max_r_idx; i++)
+ {
+ /* Invert flag WILD_ONLY <-> RF8_DUNGEON */
+ r_info[i].flags8 ^= 1L;
+
+ /* WILD_TOO without any other wilderness flags enables all flags */
+ if ((r_info[i].flags8 & RF8_WILD_TOO) && !(r_info[i].flags8 & 0x7FFFFFFE))
+ r_info[i].flags8 = 0x0463;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Grab one (basic) flag in a monster_race from a textual string
+ */
+static errr grab_one_basic_ego_flag(monster_ego *re_ptr, cptr what, bool_ add)
+{
+ int i;
+
+ /* Scan flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags1[i]))
+ {
+ if (add)
+ re_ptr->mflags1 |= (1L << i);
+ else
+ re_ptr->nflags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags2[i]))
+ {
+ if (add)
+ re_ptr->mflags2 |= (1L << i);
+ else
+ re_ptr->nflags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags3[i]))
+ {
+ if (add)
+ re_ptr->mflags3 |= (1L << i);
+ else
+ re_ptr->nflags3 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags7 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags7[i]))
+ {
+ if (add)
+ re_ptr->mflags7 |= (1L << i);
+ else
+ re_ptr->nflags7 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags8 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags8[i]))
+ {
+ if (add)
+ re_ptr->mflags8 |= (1L << i);
+ else
+ re_ptr->nflags8 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags9 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags9[i]))
+ {
+ if (add)
+ re_ptr->mflags9 |= (1L << i);
+ else
+ re_ptr->nflags9 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown monster flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+
+/*
+ * Grab one (spell) flag in a monster_race from a textual string
+ */
+static errr grab_one_spell_ego_flag(monster_ego *re_ptr, cptr what, bool_ add)
+{
+ int i;
+
+ /* Scan flags4 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags4[i]))
+ {
+ if (add)
+ re_ptr->mflags4 |= (1L << i);
+ else
+ re_ptr->nflags4 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags5 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags5[i]))
+ {
+ if (add)
+ re_ptr->mflags5 |= (1L << i);
+ else
+ re_ptr->nflags5 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags6 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags6[i]))
+ {
+ if (add)
+ re_ptr->mflags6 |= (1L << i);
+ else
+ re_ptr->nflags6 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown monster flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+/*
+ * Grab one (basic) flag in a monster_race from a textual string
+ */
+static errr grab_one_ego_flag(monster_ego *re_ptr, cptr what, bool_ must)
+{
+ int i;
+
+ /* Scan flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags1[i]))
+ {
+ if (must) re_ptr->flags1 |= (1L << i);
+ else re_ptr->hflags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags2[i]))
+ {
+ if (must) re_ptr->flags2 |= (1L << i);
+ else re_ptr->hflags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags3[i]))
+ {
+ if (must) re_ptr->flags3 |= (1L << i);
+ else re_ptr->hflags3 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags7 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags7[i]))
+ {
+ if (must) re_ptr->flags7 |= (1L << i);
+ else re_ptr->hflags7 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags8 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags8[i]))
+ {
+ if (must) re_ptr->flags8 |= (1L << i);
+ else re_ptr->hflags8 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags9 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags9[i]))
+ {
+ if (must) re_ptr->flags9 |= (1L << i);
+ else re_ptr->hflags9 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown monster flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+/*
+ * Initialize the "re_info" array, by parsing an ascii "template" file
+ */
+errr init_re_info_txt(FILE *fp, char *buf)
+{
+ int i, j;
+
+ byte blow_num = 0;
+ int r_char_number = 0, nr_char_number = 0;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ monster_ego *re_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Start the "fake" stuff */
+ re_head->name_size = 0;
+ re_head->text_size = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= re_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ re_ptr = &re_info[i];
+
+ /* Hack -- Verify space */
+ if (re_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!re_ptr->name) re_ptr->name = ++re_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(re_name + re_head->name_size, s);
+
+ /* Advance the index */
+ re_head->name_size += strlen(s);
+
+ /* Some inits */
+ blow_num = 0;
+ r_char_number = 0;
+ nr_char_number = 0;
+ for (j = 0; j < 5; j++) re_ptr->r_char[j] = 0;
+ for (j = 0; j < 5; j++) re_ptr->nr_char[j] = 0;
+ for (j = 0; j < 4; j++)
+ {
+ re_ptr->blow[j].method = 0;
+ re_ptr->blow[j].effect = 0;
+ re_ptr->blow[j].d_dice = 0;
+ re_ptr->blow[j].d_side = 0;
+ re_ptr->blowm[j][0] = MEGO_ADD;
+ re_ptr->blowm[j][1] = MEGO_ADD;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current re_ptr */
+ if (!re_ptr) return (3);
+
+ /* Process 'G' for "Graphics" (one line only) */
+ if (buf[0] == 'G')
+ {
+ char sym;
+ int tmp;
+
+ /* Paranoia */
+ if (!buf[2]) return (1);
+ if (!buf[3]) return (1);
+ if (!buf[4]) return (1);
+
+ /* Extract the char */
+ if (buf[2] != '*') sym = buf[2];
+ else sym = MEGO_CHAR_ANY;
+
+ /* Extract the attr */
+ if (buf[4] != '*') tmp = color_char_to_attr(buf[4]);
+ else tmp = MEGO_CHAR_ANY;
+
+ /* Paranoia */
+ if (tmp < 0) return (1);
+
+ /* Save the values */
+ re_ptr->d_char = sym;
+ re_ptr->d_attr = tmp;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'I' for "Info" (one line only) */
+ if (buf[0] == 'I')
+ {
+ int spd, hp1, hp2, aaf, ac, slp;
+ char mspd, mhp1, mhp2, maaf, mac, mslp;
+
+ /* Scan for the other values */
+ if (12 != sscanf(buf + 2, "%c%d:%c%dd%c%d:%c%d:%c%d:%c%d",
+ &mspd, &spd, &mhp1, &hp1, &mhp2, &hp2, &maaf, &aaf, &mac, &ac, &mslp, &slp)) return (1);
+
+ /* Save the values */
+ re_ptr->speed = (spd << 2) + monster_ego_modify(mspd);
+ re_ptr->hdice = (hp1 << 2) + monster_ego_modify(mhp1);
+ re_ptr->hside = (hp2 << 2) + monster_ego_modify(mhp2);
+ re_ptr->aaf = (aaf << 2) + monster_ego_modify(maaf);
+ re_ptr->ac = (ac << 2) + monster_ego_modify(mac);
+ re_ptr->sleep = (slp << 2) + monster_ego_modify(mslp);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'W' for "More Info" (one line only) */
+ if (buf[0] == 'W')
+ {
+ int lev, rar, wt;
+ char mlev, mwt, mexp, pos;
+ long exp;
+
+ /* Scan for the values */
+ if (8 != sscanf(buf + 2, "%c%d:%d:%c%d:%c%ld:%c",
+ &mlev, &lev, &rar, &mwt, &wt, &mexp, &exp, &pos)) return (1);
+
+ /* Save the values */
+ re_ptr->level = (lev << 2) + monster_ego_modify(mlev);
+ re_ptr->rarity = rar;
+ re_ptr->weight = (wt << 2) + monster_ego_modify(mwt);
+ re_ptr->mexp = (exp << 2) + monster_ego_modify(mexp);
+ re_ptr->before = (pos == 'B') ? TRUE : FALSE;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'B' for "Blows" (up to four lines) */
+ if (buf[0] == 'B')
+ {
+ int n1, n2, dice, side;
+ char mdice, mside;
+
+ /* Oops, no more slots */
+ if (blow_num == 4) return (1);
+
+ /* Analyze the first field */
+ for (s = t = buf + 2; *t && (*t != ':'); t++) /* loop */;
+
+ /* Terminate the field (if necessary) */
+ if (*t == ':') *t++ = '\0';
+
+ /* Analyze the method */
+ for (n1 = 0; r_info_blow_method[n1]; n1++)
+ {
+ if (streq(s, r_info_blow_method[n1])) break;
+ }
+
+ /* Invalid method */
+ if (!r_info_blow_method[n1]) return (1);
+
+ /* Analyze the second field */
+ for (s = t; *t && (*t != ':'); t++) /* loop */;
+
+ /* Terminate the field (if necessary) */
+ if (*t == ':') *t++ = '\0';
+
+ /* Analyze effect */
+ for (n2 = 0; r_info_blow_effect[n2]; n2++)
+ {
+ if (streq(s, r_info_blow_effect[n2])) break;
+ }
+
+ /* Invalid effect */
+ if (!r_info_blow_effect[n2]) return (1);
+
+ /* Save the method */
+ re_ptr->blow[blow_num].method = n1;
+
+ /* Save the effect */
+ re_ptr->blow[blow_num].effect = n2;
+
+ /* Extract the damage dice and sides */
+ if (4 != sscanf(t, "%c%dd%c%d",
+ &mdice, &dice, &mside, &side)) return (1);
+
+ re_ptr->blow[blow_num].d_dice = dice;
+ re_ptr->blow[blow_num].d_side = side;
+ re_ptr->blowm[blow_num][0] = monster_ego_modify(mdice);
+ re_ptr->blowm[blow_num][1] = monster_ego_modify(mside);
+ blow_num++;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for "Flags monster must have" (multiple lines) */
+ if (buf[0] == 'F')
+ {
+ char r_char;
+
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* XXX XXX XXX Hack -- Read monster symbols */
+ if (1 == sscanf(s, "R_CHAR_%c", &r_char))
+ {
+ /* Limited to 5 races */
+ if (r_char_number >= 5) continue;
+
+ /* Extract a "frequency" */
+ re_ptr->r_char[r_char_number++] = r_char;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_ego_flag(re_ptr, s, TRUE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'H' for "Flags monster must not have" (multiple lines) */
+ if (buf[0] == 'H')
+ {
+ char r_char;
+
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* XXX XXX XXX Hack -- Read monster symbols */
+ if (1 == sscanf(s, "R_CHAR_%c", &r_char))
+ {
+ /* Limited to 5 races */
+ if (nr_char_number >= 5) continue;
+
+ /* Extract a "frequency" */
+ re_ptr->nr_char[nr_char_number++] = r_char;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_ego_flag(re_ptr, s, FALSE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'M' for "Basic Monster Flags" (multiple lines) */
+ if (buf[0] == 'M')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_basic_ego_flag(re_ptr, s, TRUE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'O' for "Basic Monster -Flags" (multiple lines) */
+ if (buf[0] == 'O')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* XXX XXX XXX Hack -- Read no flags */
+ if (!strcmp(s, "MF_ALL"))
+ {
+ /* No flags */
+ re_ptr->nflags1 = re_ptr->nflags2 = re_ptr->nflags3 = re_ptr->nflags7 = re_ptr->nflags8 = re_ptr->nflags9 = 0xFFFFFFFF;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_basic_ego_flag(re_ptr, s, FALSE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'S' for "Spell Flags" (multiple lines) */
+ if (buf[0] == 'S')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* XXX XXX XXX Hack -- Read spell frequency */
+ if (1 == sscanf(s, "1_IN_%d", &i))
+ {
+ /* Extract a "frequency" */
+ re_ptr->freq_spell = re_ptr->freq_inate = 100 / i;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_spell_ego_flag(re_ptr, s, TRUE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'T' for "Spell -Flags" (multiple lines) */
+ if (buf[0] == 'T')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* XXX XXX XXX Hack -- Read no flags */
+ if (!strcmp(s, "MF_ALL"))
+ {
+ /* No flags */
+ re_ptr->nflags4 = re_ptr->nflags5 = re_ptr->nflags6 = 0xFFFFFFFF;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_spell_ego_flag(re_ptr, s, FALSE)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++re_head->name_size;
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Grab one flag in an trap_type from a textual string
+ */
+static errr grab_one_trap_type_flag(trap_type *t_ptr, cptr what)
+{
+ s16b i;
+
+ /* Check flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, t_info_flags[i]))
+ {
+ t_ptr->flags |= (1L << i);
+ return (0);
+ }
+ }
+ /* Oops */
+ msg_format("Unknown trap_type flag '%s'.", what);
+
+ /* Error */
+ return (1);
+}
+
+
+/*
+ * Initialize the "tr_info" array, by parsing an ascii "template" file
+ */
+errr init_t_info_txt(FILE *fp, char *buf)
+{
+ int i;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ trap_type *t_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Prepare the "fake" stuff */
+ t_head->name_size = 0;
+ t_head->text_size = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i <= error_idx) return (4);
+
+ /* Verify information */
+ if (i >= t_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ t_ptr = &t_info[i];
+
+ /* Hack -- Verify space */
+ if (t_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!t_ptr->name) t_ptr->name = ++t_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(t_name + t_head->name_size, s);
+
+ /* Advance the index */
+ t_head->name_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current t_ptr */
+ if (!t_ptr) return (3);
+
+
+ /* Process 'I' for "Information" */
+ if (buf[0] == 'I')
+ {
+ int probability, another, p1valinc, difficulty;
+ int minlevel;
+ int dd, ds;
+ char color;
+
+ /* Scan for the values */
+ if (8 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%dd%d:%c",
+ &difficulty, &probability, &another,
+ &p1valinc, &minlevel, &dd, &ds,
+ &color)) return (1);
+
+ t_ptr->difficulty = (byte)difficulty;
+ t_ptr->probability = (s16b)probability;
+ t_ptr->another = (s16b)another;
+ t_ptr->p1valinc = (s16b)p1valinc;
+ t_ptr->minlevel = (byte)minlevel;
+ t_ptr->dd = (s16b)dd;
+ t_ptr->ds = (s16b)ds;
+ t_ptr->color = color_char_to_attr(color);
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Process 'D' for "Description" */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (t_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!t_ptr->text) t_ptr->text = ++t_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(t_text + t_head->text_size, s);
+
+ /* Advance the index */
+ t_head->text_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Hack -- Process 'F' for flags */
+ if (buf[0] == 'F')
+ {
+
+ t_ptr->flags = 0;
+
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_trap_type_flag(t_ptr, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++t_head->name_size;
+ ++t_head->text_size;
+
+
+ /* No version yet */
+ if (!okay) return (2);
+
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Grab one flag for a dungeon type from a textual string
+ */
+errr grab_one_dungeon_flag(u32b *flags1, u32b *flags2, cptr what)
+{
+ int i;
+
+ /* Scan flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, d_info_flags1[i]))
+ {
+ *flags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, d_info_flags2[i]))
+ {
+ *flags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown dungeon type flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+/*
+ * Grab one (basic) flag in a monster_race from a textual string
+ */
+static errr grab_one_basic_monster_flag(dungeon_info_type *d_ptr, cptr what, byte rule)
+{
+ int i;
+
+ /* Scan flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags1[i]))
+ {
+ d_ptr->rules[rule].mflags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags2 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags2[i]))
+ {
+ d_ptr->rules[rule].mflags2 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags3 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags3[i]))
+ {
+ d_ptr->rules[rule].mflags3 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags7 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags7[i]))
+ {
+ d_ptr->rules[rule].mflags7 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags8 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags8[i]))
+ {
+ d_ptr->rules[rule].mflags8 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags9 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags9[i]))
+ {
+ d_ptr->rules[rule].mflags9 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown monster flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+
+/*
+ * Grab one (spell) flag in a monster_race from a textual string
+ */
+static errr grab_one_spell_monster_flag(dungeon_info_type *d_ptr, cptr what, byte rule)
+{
+ int i;
+
+ /* Scan flags4 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags4[i]))
+ {
+ d_ptr->rules[rule].mflags4 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags5 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags5[i]))
+ {
+ d_ptr->rules[rule].mflags5 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Scan flags6 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, r_info_flags6[i]))
+ {
+ d_ptr->rules[rule].mflags6 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown monster flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+/*
+ * Initialize the "d_info" array, by parsing an ascii "template" file
+ */
+errr init_d_info_txt(FILE *fp, char *buf)
+{
+ int i, j;
+
+ s16b rule_num = 0;
+
+ byte r_char_number = 0;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ dungeon_info_type *d_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Start the "fake" stuff */
+ d_head->name_size = 0;
+ d_head->text_size = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= d_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ d_ptr = &d_info[i];
+
+ /* Hack -- Verify space */
+ if (d_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!d_ptr->name) d_ptr->name = ++d_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(d_name + d_head->name_size, s);
+
+ /* Advance the index */
+ d_head->name_size += strlen(s);
+
+ /* HACK -- Those ones HAVE to have a set default value */
+ d_ptr->size_x = -1;
+ d_ptr->size_y = -1;
+ d_ptr->ix = -1;
+ d_ptr->iy = -1;
+ d_ptr->ox = -1;
+ d_ptr->oy = -1;
+ d_ptr->fill_method = 1;
+ rule_num = -1;
+ r_char_number = 0;
+ for (j = 0; j < 5; j++)
+ {
+ int k;
+
+ d_ptr->rules[j].mode = DUNGEON_MODE_NONE;
+ d_ptr->rules[j].percent = 0;
+
+ for (k = 0; k < 5; k++) d_ptr->rules[j].r_char[k] = 0;
+ }
+
+ /* HACK -- Those ones HAVE to have a set default value */
+ d_ptr->objs.treasure = OBJ_GENE_TREASURE;
+ d_ptr->objs.combat = OBJ_GENE_COMBAT;
+ d_ptr->objs.magic = OBJ_GENE_MAGIC;
+ d_ptr->objs.tools = OBJ_GENE_TOOL;
+
+ /* The default generator */
+ strcpy(d_ptr->generator, "dungeon");
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current d_ptr */
+ if (!d_ptr) return (3);
+
+ /* Process 'D' for "Description */
+ if (buf[0] == 'D')
+ {
+ /* Acquire short name */
+ d_ptr->short_name[0] = buf[2];
+ d_ptr->short_name[1] = buf[3];
+ d_ptr->short_name[2] = buf[4];
+
+ /* Acquire the text */
+ s = buf + 6;
+
+ /* Hack -- Verify space */
+ if (d_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!d_ptr->text) d_ptr->text = ++d_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(d_text + d_head->text_size, s);
+
+ /* Advance the index */
+ d_head->text_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'W' for "More Info" (one line only) */
+ if (buf[0] == 'W')
+ {
+ int min_lev, max_lev;
+ int min_plev, next;
+ int min_alloc, max_chance;
+
+ /* Scan for the values */
+ if (6 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d",
+ &min_lev, &max_lev, &min_plev, &next, &min_alloc, &max_chance)) return (1);
+
+ /* Save the values */
+ d_ptr->mindepth = min_lev;
+ d_ptr->maxdepth = max_lev;
+ d_ptr->min_plev = min_plev;
+ d_ptr->next = next;
+ d_ptr->min_m_alloc_level = min_alloc;
+ d_ptr->max_m_alloc_chance = max_chance;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'L' for "fLoor type" (one line only) */
+ if (buf[0] == 'L')
+ {
+ int f1, f2, f3;
+ int p1, p2, p3;
+ int i;
+
+ /* Scan for the values */
+ if (6 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d",
+ &f1, &p1, &f2, &p2, &f3, &p3))
+ {
+ /* Scan for the values - part ii*/
+ if (3 != sscanf(buf + 2, "%d:%d:%d", &p1, &p2,
+ &p3)) return (1);
+
+ /* Save the values */
+ d_ptr->floor_percent1[1] = p1;
+ d_ptr->floor_percent2[1] = p2;
+ d_ptr->floor_percent3[1] = p3;
+
+ continue;
+ }
+
+ /* Save the values */
+ d_ptr->floor1 = f1;
+ d_ptr->floor2 = f2;
+ d_ptr->floor3 = f3;
+
+ for (i = 0; i < 2; i++)
+ {
+ d_ptr->floor_percent1[i] = p1;
+ d_ptr->floor_percent2[i] = p2;
+ d_ptr->floor_percent3[i] = p3;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'O' for "Object type" (one line only) */
+ if (buf[0] == 'O')
+ {
+ int treasure, combat, magic, tools;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
+ &treasure, &combat, &magic, &tools)) return (1);
+
+ /* Save the values */
+ d_ptr->objs.treasure = treasure;
+ d_ptr->objs.combat = combat;
+ d_ptr->objs.magic = magic;
+ d_ptr->objs.tools = tools;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G' for "Generator" (one line only) */
+ if (buf[0] == 'G')
+ {
+ strnfmt(d_ptr->generator, 30, "%s", buf + 2);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'A' for "wAll type" (one line only) */
+ if (buf[0] == 'A')
+ {
+ int w1, w2, w3, outer, inner;
+ int p1, p2, p3;
+ int i;
+
+ /* Scan for the values */
+ if (8 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%d:%d",
+ &w1, &p1, &w2, &p2, &w3, &p3, &outer, &inner))
+ {
+ /* Scan for the values - part ii*/
+ if (3 != sscanf(buf + 2, "%d:%d:%d", &p1, &p2,
+ &p3)) return (1);
+
+ /* Save the values */
+ d_ptr->fill_percent1[1] = p1;
+ d_ptr->fill_percent2[1] = p2;
+ d_ptr->fill_percent3[1] = p3;
+ continue;
+ }
+
+ /* Save the values */
+ d_ptr->fill_type1 = w1;
+ d_ptr->fill_type2 = w2;
+ d_ptr->fill_type3 = w3;
+
+ for (i = 0; i < 2; i++)
+ {
+ d_ptr->fill_percent1[i] = p1;
+ d_ptr->fill_percent2[i] = p2;
+ d_ptr->fill_percent3[i] = p3;
+ }
+
+ d_ptr->outer_wall = outer;
+ d_ptr->inner_wall = inner;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'E' for "Effects" (up to four lines) -SC- */
+ if (buf[0] == 'E')
+ {
+ int side, dice, freq, type;
+ cptr tmp;
+
+ /* Find the next empty blow slot (if any) */
+ for (i = 0; i < 4; i++) if ((!d_ptr->d_side[i]) &&
+ (!d_ptr->d_dice[i])) break;
+
+ /* Oops, no more slots */
+ if (i == 4) return (1);
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%dd%d:%d:%d",
+ &dice, &side, &freq, &type))
+ {
+ int j;
+
+ if (3 != sscanf(buf + 2, "%dd%d:%d",
+ &dice, &side, &freq)) return (1);
+
+ tmp = buf + 2;
+ for (j = 0; j < 2; j++)
+ {
+ tmp = strchr(tmp, ':');
+ if (tmp == NULL) return (1);
+ tmp++;
+ }
+
+ j = 0;
+
+ while (d_info_dtypes[j].name != NULL)
+ if (strcmp(d_info_dtypes[j].name, tmp) == 0)
+ {
+ d_ptr->d_type[i] = d_info_dtypes[j].feat;
+ break;
+ }
+ else j++;
+
+ if (d_info_dtypes[j].name == NULL) return (1);
+ }
+ else
+ d_ptr->d_type[i] = type;
+
+ freq *= 10;
+ /* Save the values */
+ d_ptr->d_side[i] = side;
+ d_ptr->d_dice[i] = dice;
+ d_ptr->d_frequency[i] = freq;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for "Dungeon Flags" (multiple lines) */
+ if (buf[0] == 'F')
+ {
+ int artif = 0, monst = 0, obj = 0;
+ int ix = -1, iy = -1, ox = -1, oy = -1;
+ int fill_method;
+
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Read dungeon in/out coords */
+ if (4 == sscanf(s, "WILD_%d_%d__%d_%d", &ix, &iy, &ox, &oy))
+ {
+ d_ptr->ix = ix;
+ d_ptr->iy = iy;
+ d_ptr->ox = ox;
+ d_ptr->oy = oy;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Read dungeon size */
+ if (2 == sscanf(s, "SIZE_%d_%d", &ix, &iy))
+ {
+ d_ptr->size_x = ix;
+ d_ptr->size_y = iy;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Read dungeon fill method */
+ if (1 == sscanf(s, "FILL_METHOD_%d", &fill_method))
+ {
+ d_ptr->fill_method = fill_method;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Read Final Object */
+ if (1 == sscanf(s, "FINAL_OBJECT_%d", &obj))
+ {
+ /* Extract a "Final Artifact" */
+ d_ptr->final_object = obj;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Read Final Artifact */
+ if (1 == sscanf(s, "FINAL_ARTIFACT_%d", &artif ))
+ {
+ /* Extract a "Final Artifact" */
+ d_ptr->final_artifact = artif ;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Read Artifact Guardian */
+ if (1 == sscanf(s, "FINAL_GUARDIAN_%d", &monst))
+ {
+ /* Extract a "Artifact Guardian" */
+ d_ptr->final_guardian = monst;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_dungeon_flag(&(d_ptr->flags1), &(d_ptr->flags2), s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'R' for "monster generation Rule" (up to 5 lines) */
+ if (buf[0] == 'R')
+ {
+ int percent, mode;
+ int z, y, lims[5];
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 2, "%d:%d",
+ &percent, &mode)) return (1);
+
+ /* Save the values */
+ r_char_number = 0;
+ rule_num++;
+
+ d_ptr->rules[rule_num].percent = percent;
+ d_ptr->rules[rule_num].mode = mode;
+
+ /* Lets remap the flat percents */
+ lims[0] = d_ptr->rules[0].percent;
+ for (y = 1; y <= rule_num; y++)
+ {
+ lims[y] = lims[y - 1] + d_ptr->rules[y].percent;
+ }
+ for (z = 0; z < 100; z++)
+ {
+ for (y = rule_num; y >= 0; y--)
+ {
+ if (z < lims[y]) d_ptr->rule_percents[z] = y;
+ }
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'M' for "Basic Flags" (multiple lines) */
+ if (buf[0] == 'M')
+ {
+ byte r_char;
+
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Read monster symbols */
+ if (1 == sscanf(s, "R_CHAR_%c", &r_char))
+ {
+ /* Limited to 5 races */
+ if (r_char_number >= 5) continue;
+
+ /* Extract a "frequency" */
+ d_ptr->rules[rule_num].r_char[r_char_number++] = r_char;
+
+ /* Start at next entry */
+ s = t;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_basic_monster_flag(d_ptr, s, rule_num)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'S' for "Spell Flags" (multiple lines) */
+ if (buf[0] == 'S')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while ((*t == ' ') || (*t == '|')) t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_spell_monster_flag(d_ptr, s, rule_num)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++d_head->name_size;
+ ++d_head->text_size;
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Grab one race flag from a textual string
+ */
+static errr grab_one_race_flag(owner_type *ow_ptr, int state, cptr what)
+{
+ /* int i;
+ cptr s; */
+
+ /* Scan race flags */
+ unknown_shut_up = TRUE;
+ if (!grab_one_race_allow_flag(ow_ptr->races[state], what))
+ {
+ unknown_shut_up = FALSE;
+ return (0);
+ }
+
+ /* Scan classes flags */
+ if (!grab_one_class_flag(ow_ptr->classes[state], what))
+ {
+ unknown_shut_up = FALSE;
+ return (0);
+ }
+
+ /* Oops */
+ unknown_shut_up = FALSE;
+ msg_format("Unknown race/class flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+/*
+ * Grab one store flag from a textual string
+ */
+static errr grab_one_store_flag(store_info_type *st_ptr, cptr what)
+{
+ int i;
+
+ /* Scan store flags */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, st_info_flags1[i]))
+ {
+ st_ptr->flags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown store flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+/*
+ * Initialize the "st_info" array, by parsing an ascii "template" file
+ */
+errr init_st_info_txt(FILE *fp, char *buf)
+{
+ int i = 0, item_idx = 0;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ store_info_type *st_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Start the "fake" stuff */
+ st_head->name_size = 0;
+ st_head->text_size = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= st_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ st_ptr = &st_info[i];
+
+ /* Hack -- Verify space */
+ if (st_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!st_ptr->name) st_ptr->name = ++st_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(st_name + st_head->name_size, s);
+
+ /* Advance the index */
+ st_head->name_size += strlen(s);
+
+ /* We are ready for a new set of objects */
+ item_idx = 0;
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current st_ptr */
+ if (!st_ptr) return (3);
+
+ /* Process 'I' for "Items" (multiple lines) */
+ if (buf[0] == 'I')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ st_ptr->table[item_idx][1] = atoi(buf + 2);
+
+ /* Append chars to the name */
+ st_ptr->table[item_idx++][0] = test_item_name(s);
+
+ st_ptr->table_num = item_idx;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'T' for "Tval/sval" */
+ if (buf[0] == 'T')
+ {
+ int tv1, sv1, rar1;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &rar1, &tv1, &sv1)) return (1);
+
+ /* Get the index */
+ st_ptr->table[item_idx][1] = rar1;
+ /* Hack -- 256 as a sval means all possible items */
+ st_ptr->table[item_idx++][0] = (sv1 < 256) ? lookup_kind(tv1, sv1) : tv1 + 10000;
+
+ st_ptr->table_num = item_idx;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'G' for "Graphics" one line only) */
+ if (buf[0] == 'G')
+ {
+ char c, a;
+ int attr;
+
+ /* Scan for the values */
+ if (2 != sscanf(buf + 2, "%c:%c",
+ &c, &a)) return (1);
+
+ /* Extract the color */
+ attr = color_char_to_attr(a);
+
+ /* Paranoia */
+ if (attr < 0) return (1);
+
+ /* Save the values */
+ st_ptr->d_char = c;
+ st_ptr->d_attr = attr;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'A' for "Actions" (one line only) */
+ if (buf[0] == 'A')
+ {
+ int a1, a2, a3, a4, a5, a6;
+
+ /* Scan for the values */
+ if (6 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d",
+ &a1, &a2, &a3, &a4, &a5, &a6)) return (1);
+
+ /* Save the values */
+ st_ptr->actions[0] = a1;
+ st_ptr->actions[1] = a2;
+ st_ptr->actions[2] = a3;
+ st_ptr->actions[3] = a4;
+ st_ptr->actions[4] = a5;
+ st_ptr->actions[5] = a6;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for "store Flags" (multiple lines) */
+ if (buf[0] == 'F')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_store_flag(st_ptr, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'O' for "Owners" (one line only) */
+ if (buf[0] == 'O')
+ {
+ int a1, a2, a3, a4;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%d:%d",
+ &a1, &a2, &a3, &a4)) return (1);
+
+ /* Save the values */
+ st_ptr->owners[0] = a1;
+ st_ptr->owners[1] = a2;
+ st_ptr->owners[2] = a3;
+ st_ptr->owners[3] = a4;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'W' for "Extra info" (one line only) */
+ if (buf[0] == 'W')
+ {
+ int max_obj;
+
+ /* Scan for the values */
+ if (1 != sscanf(buf + 2, "%d",
+ &max_obj)) return (1);
+
+ /* Save the values */
+ if (max_obj > STORE_INVEN_MAX) max_obj = STORE_INVEN_MAX;
+ st_ptr->max_obj = max_obj;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++st_head->name_size;
+ ++st_head->text_size;
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialize the "ba_info" array, by parsing an ascii "template" file
+ */
+errr init_ba_info_txt(FILE *fp, char *buf)
+{
+ int i = 0;
+
+ char *s;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ store_action_type *ba_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Start the "fake" stuff */
+ ba_head->name_size = 0;
+ ba_head->text_size = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= ba_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ ba_ptr = &ba_info[i];
+
+ /* Hack -- Verify space */
+ if (ba_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!ba_ptr->name) ba_ptr->name = ++ba_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(ba_name + ba_head->name_size, s);
+
+ /* Advance the index */
+ ba_head->name_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current ba_ptr */
+ if (!ba_ptr) return (3);
+
+ /* Process 'C' for "Costs" (one line only) */
+ if (buf[0] == 'C')
+ {
+ int ch, cn, cl;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &ch, &cn, &cl)) return (1);
+
+ /* Save the values */
+ ba_ptr->costs[STORE_HATED] = ch;
+ ba_ptr->costs[STORE_NORMAL] = cn;
+ ba_ptr->costs[STORE_LIKED] = cl;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'I' for "Infos" (one line only) */
+ if (buf[0] == 'I')
+ {
+ int act, act_res;
+ char letter, letter_aux = 0;
+
+ /* Scan for the values */
+ if (4 != sscanf(buf + 2, "%d:%d:%c:%c", &act, &act_res, &letter, &letter_aux))
+ if (3 != sscanf(buf + 2, "%d:%d:%c", &act, &act_res, &letter))
+ return (1);
+
+ /* Save the values */
+ ba_ptr->action = act;
+ ba_ptr->action_restr = act_res;
+ ba_ptr->letter = letter;
+ ba_ptr->letter_aux = letter_aux;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++ba_head->name_size;
+ ++ba_head->text_size;
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialize the "ow_info" array, by parsing an ascii "template" file
+ */
+errr init_ow_info_txt(FILE *fp, char *buf)
+{
+ int i;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ owner_type *ow_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Start the "fake" stuff */
+ ow_head->name_size = 0;
+ ow_head->text_size = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= ow_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ ow_ptr = &ow_info[i];
+
+ /* Hack -- Verify space */
+ if (ow_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!ow_ptr->name) ow_ptr->name = ++ow_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(ow_name + ow_head->name_size, s);
+
+ /* Advance the index */
+ ow_head->name_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current ow_ptr */
+ if (!ow_ptr) return (3);
+
+
+ /* Process 'C' for "Costs" (one line only) */
+ if (buf[0] == 'C')
+ {
+ int ch, cn, cl;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d:%d:%d",
+ &ch, &cn, &cl)) return (1);
+
+ /* Save the values */
+ ow_ptr->costs[STORE_HATED] = ch;
+ ow_ptr->costs[STORE_NORMAL] = cn;
+ ow_ptr->costs[STORE_LIKED] = cl;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'I' for "Info" (multiple lines line only) */
+ if (buf[0] == 'I')
+ {
+ int cost, max_inf, min_inf, haggle, insult;
+
+ /* Scan for the values */
+ if (5 != sscanf(buf + 2, "%d:%d:%d:%d:%d",
+ &cost, &max_inf, &min_inf, &haggle, &insult)) return (1);
+
+ /* Save the values */
+ ow_ptr->max_cost = cost;
+ ow_ptr->max_inflate = max_inf;
+ ow_ptr->min_inflate = min_inf;
+ ow_ptr->haggle_per = haggle;
+ ow_ptr->insult_max = insult;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'L' for "Liked races/classes" (multiple lines) */
+ if (buf[0] == 'L')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_race_flag(ow_ptr, STORE_LIKED, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+ /* Process 'H' for "Hated races/classes" (multiple lines) */
+ if (buf[0] == 'H')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_race_flag(ow_ptr, STORE_HATED, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++ow_head->name_size;
+ ++ow_head->text_size;
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Grab one flag for a dungeon type from a textual string
+ */
+static errr grab_one_wf_info_flag(wilderness_type_info *wf_ptr, cptr what)
+{
+ int i;
+
+ /* Scan flags1 */
+ for (i = 0; i < 32; i++)
+ {
+ if (streq(what, wf_info_flags1[i]))
+ {
+ wf_ptr->flags1 |= (1L << i);
+ return (0);
+ }
+ }
+
+ /* Oops */
+ msg_format("Unknown monster flag '%s'.", what);
+
+ /* Failure */
+ return (1);
+}
+
+/*
+ * Initialize the "wf_info" array, by parsing an ascii "template" file
+ */
+errr init_wf_info_txt(FILE *fp, char *buf)
+{
+ int i;
+
+ char *s, *t;
+
+ /* Not ready yet */
+ bool_ okay = FALSE;
+
+ /* Current entry */
+ wilderness_type_info *wf_ptr = NULL;
+
+
+ /* Just before the first record */
+ error_idx = -1;
+
+ /* Just before the first line */
+ error_line = -1;
+
+
+ /* Start the "fake" stuff */
+ wf_head->name_size = 0;
+ wf_head->text_size = 0;
+
+ /* Parse */
+ fp_stack_init(fp);
+ while (0 == my_fgets_dostack(buf, 1024))
+ {
+ /* Advance the line number */
+ error_line++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Verify correct "colon" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Hack -- Process 'V' for "Version" */
+ if (buf[0] == 'V')
+ {
+ int v1, v2, v3;
+
+ /* Scan for the values */
+ if (3 != sscanf(buf + 2, "%d.%d.%d", &v1, &v2, &v3)) return (2);
+
+ /* Okay to proceed */
+ okay = TRUE;
+
+ /* Continue */
+ continue;
+ }
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Included file */
+ if (buf[0] == '<')
+ {
+ fp_stack_push(buf + 2);
+ continue;
+ }
+
+ /* Process 'N' for "New/Number/Name" */
+ if (buf[0] == 'N')
+ {
+ /* Find the colon before the name */
+ s = strchr(buf + 2, ':');
+
+ /* Verify that colon */
+ if (!s) return (1);
+
+ /* Nuke the colon, advance to the name */
+ *s++ = '\0';
+
+ /* Paranoia -- require a name */
+ if (!*s) return (1);
+
+ /* Get the index */
+ i = atoi(buf + 2);
+
+ /* Verify information */
+ if (i < error_idx) return (4);
+
+ /* Verify information */
+ if (i >= wf_head->info_num) return (2);
+
+ /* Save the index */
+ error_idx = i;
+
+ /* Point at the "info" */
+ wf_ptr = &wf_info[i];
+
+ /* Hack -- Verify space */
+ if (wf_head->name_size + strlen(s) + 8 > fake_name_size) return (7);
+
+ /* Advance and Save the name index */
+ if (!wf_ptr->name) wf_ptr->name = ++wf_head->name_size;
+
+ /* Append chars to the name */
+ strcpy(wf_name + wf_head->name_size, s);
+
+ /* Advance the index */
+ wf_head->name_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* There better be a current wf_ptr */
+ if (!wf_ptr) return (3);
+
+ /* Process 'D' for "Description */
+ if (buf[0] == 'D')
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ /* Hack -- Verify space */
+ if (wf_head->text_size + strlen(s) + 8 > fake_text_size) return (7);
+
+ /* Advance and Save the text index */
+ if (!wf_ptr->text) wf_ptr->text = ++wf_head->text_size;
+
+ /* Append chars to the name */
+ strcpy(wf_text + wf_head->text_size, s);
+
+ /* Advance the index */
+ wf_head->text_size += strlen(s);
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'W' for "More Info" (one line only) */
+ if (buf[0] == 'W')
+ {
+ int entrance, level;
+ int road, feat, ter_idx;
+ char car;
+
+ /* Scan for the values */
+ if (6 != sscanf(buf + 2, "%d:%d:%d:%d:%d:%c",
+ &level, &entrance, &road, &feat, &ter_idx, &car)) return (1);
+
+ /* Save the values */
+ wf_ptr->level = level;
+ wf_ptr->entrance = entrance;
+ wf_ptr->road = road;
+ wf_ptr->feat = feat;
+ wf_ptr->terrain_idx = ter_idx;
+
+ /* To acces it easily from the map structure */
+ wildc2i[(int)car] = error_idx;
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'X' for "More Info" (one line only) */
+ if (buf[0] == 'X')
+ {
+ int terrain[MAX_WILD_TERRAIN], i;
+
+ /* Scan for the values */
+ if (MAX_WILD_TERRAIN != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ &terrain[0], &terrain[1], &terrain[2],
+ &terrain[3], &terrain[4], &terrain[5],
+ &terrain[6], &terrain[7], &terrain[8],
+ &terrain[9], &terrain[10], &terrain[11],
+ &terrain[12], &terrain[13], &terrain[14],
+ &terrain[15], &terrain[16], &terrain[17])) return (1);
+
+ /* Save the values */
+ for (i = 0; i < MAX_WILD_TERRAIN; i++)
+ {
+ wf_ptr->terrain[i] = terrain[i];
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Process 'F' for "Wilderness feature Flags" (multiple lines) */
+ if (buf[0] == 'F')
+ {
+ /* Parse every entry */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_wf_info_flag(wf_ptr, s)) return (5);
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ /* Next... */
+ continue;
+ }
+
+ /* Oops */
+ return (6);
+ }
+
+
+ /* Complete the "name" and "text" sizes */
+ ++wf_head->name_size;
+ ++wf_head->text_size;
+
+ /* No version yet */
+ if (!okay) return (2);
+
+ /* Success */
+ return (0);
+}
+
+
+/* Random dungeon grid effects */
+#define RANDOM_NONE 0x00
+#define RANDOM_FEATURE 0x01
+#define RANDOM_MONSTER 0x02
+#define RANDOM_OBJECT 0x04
+#define RANDOM_EGO 0x08
+#define RANDOM_ARTIFACT 0x10
+#define RANDOM_TRAP 0x20
+
+
+typedef struct dungeon_grid dungeon_grid;
+
+struct dungeon_grid
+{
+ int feature; /* Terrain feature */
+ int monster; /* Monster */
+ int object; /* Object */
+ int ego; /* Ego-Item */
+ int artifact; /* Artifact */
+ int trap; /* Trap */
+ int cave_info; /* Flags for CAVE_MARK, CAVE_GLOW, CAVE_ICKY, CAVE_ROOM */
+ int special; /* Reserved for special terrain info */
+ int random; /* Number of the random effect */
+ int bx, by; /* For between gates */
+ int mimic; /* Mimiced features */
+ s32b mflag; /* monster's mflag */
+ bool_ ok;
+ bool_ defined;
+};
+static bool_ meta_sleep = TRUE;
+
+static dungeon_grid letter[255];
+
+/*
+ * Parse a sub-file of the "extra info"
+ */
+static errr process_dungeon_file_aux(char *buf, int *yval, int *xval, int xvalstart, int ymax, int xmax, bool_ full)
+{
+ int i;
+
+ char *zz[33];
+
+
+ /* Skip "empty" lines */
+ if (!buf[0]) return (0);
+
+ /* Skip "blank" lines */
+ if (isspace(buf[0])) return (0);
+
+ /* Skip comments */
+ if (buf[0] == '#') return (0);
+
+ /* Require "?:*" format */
+ if (buf[1] != ':') return (1);
+
+
+ /* Process "%:<fname>" */
+ if (buf[0] == '%')
+ {
+ /* Attempt to Process the given file */
+ return (process_dungeon_file(buf + 2, yval, xval, ymax, xmax, FALSE, full));
+ }
+
+ /* Process "N:<sleep>" */
+ if (buf[0] == 'N')
+ {
+ int num;
+
+ if ((num = tokenize(buf + 2, 1, zz, ':', '/')) > 0)
+ {
+ meta_sleep = atoi(zz[0]);
+ }
+
+ return (0);
+ }
+
+ /* Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>:<mimic>:<mflag>" -- info for dungeon grid */
+ if (buf[0] == 'F')
+ {
+ int num;
+
+ if ((num = tokenize(buf + 2, 11, zz, ':', '/')) > 1)
+ {
+ int index = zz[0][0];
+
+ /* Reset the feature */
+ letter[index].feature = 0;
+ letter[index].monster = 0;
+ letter[index].object = 0;
+ letter[index].ego = 0;
+ letter[index].artifact = 0;
+ letter[index].trap = 0;
+ letter[index].cave_info = 0;
+ letter[index].special = 0;
+ letter[index].random = 0;
+ letter[index].mimic = 0;
+ letter[index].mflag = 0;
+ letter[index].ok = TRUE;
+ letter[index].defined = TRUE;
+
+ if (num > 1)
+ {
+ if (zz[1][0] == '*')
+ {
+ letter[index].random |= RANDOM_FEATURE;
+ if (zz[1][1])
+ {
+ zz[1]++;
+ letter[index].feature = atoi(zz[1]);
+ }
+ }
+ else
+ {
+ letter[index].feature = atoi(zz[1]);
+ }
+ }
+
+ if (num > 2)
+ letter[index].cave_info = atoi(zz[2]);
+
+ /* Monster */
+ if (num > 3)
+ {
+ if (zz[3][0] == '*')
+ {
+ letter[index].random |= RANDOM_MONSTER;
+ if (zz[3][1])
+ {
+ zz[3]++;
+ letter[index].monster = atoi(zz[3]);
+ }
+ }
+ else
+ {
+ letter[index].monster = atoi(zz[3]);
+ }
+ }
+
+ /* Object */
+ if (num > 4)
+ {
+ if (zz[4][0] == '*')
+ {
+ letter[index].random |= RANDOM_OBJECT;
+
+ if (zz[4][1])
+ {
+ zz[4]++;
+ letter[index].object = atoi(zz[4]);
+ }
+ }
+ else
+ {
+ letter[index].object = atoi(zz[4]);
+ }
+ }
+
+ /* Ego-Item */
+ if (num > 5)
+ {
+ if (zz[5][0] == '*')
+ {
+ letter[index].random |= RANDOM_EGO;
+
+ if (zz[5][1])
+ {
+ zz[5]++;
+ letter[index].ego = atoi(zz[5]);
+ }
+ }
+ else
+ {
+ letter[index].ego = atoi(zz[5]);
+ }
+ }
+
+ /* Artifact */
+ if (num > 6)
+ {
+ if (zz[6][0] == '*')
+ {
+ letter[index].random |= RANDOM_ARTIFACT;
+
+ if (zz[6][1])
+ {
+ zz[6]++;
+ letter[index].artifact = atoi(zz[6]);
+ }
+ }
+ else
+ {
+ letter[index].artifact = atoi(zz[6]);
+ }
+ }
+
+ if (num > 7)
+ {
+ if (zz[7][0] == '*')
+ {
+ letter[index].random |= RANDOM_TRAP;
+
+ if (zz[7][1])
+ {
+ zz[7]++;
+ letter[index].trap = atoi(zz[7]);
+ }
+ }
+ else
+ letter[index].trap = atoi(zz[7]);
+ }
+
+ if (num > 8)
+ {
+ /* Quests can be defined by name only */
+ if (zz[8][0] == '"')
+ {
+ int i;
+
+ /* Hunt & shoot the ending " */
+ i = strlen(zz[8]) - 1;
+ if (zz[8][i] == '"') zz[8][i] = '\0';
+ letter[index].special = 0;
+ for (i = 0; i < max_q_idx; i++)
+ {
+ if (!strcmp(&zz[8][1], quest[i].name))
+ {
+ letter[index].special = i;
+ break;
+ }
+ }
+ }
+ else
+ letter[index].special = atoi(zz[8]);
+ }
+
+ if (num > 9)
+ {
+ letter[index].mimic = atoi(zz[9]);
+ }
+
+ if (num > 10)
+ {
+ letter[index].mflag = atoi(zz[10]);
+ }
+
+ return (0);
+ }
+ }
+
+ /* Process "f:flags" -- level flags */
+ else if (buf[0] == 'f')
+ {
+ char *s, *t;
+
+ /* Parse every entry textually */
+ for (s = buf + 2; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_dungeon_flag(&dungeon_flags1, &dungeon_flags2, s)) return 1;
+
+ /* Start the next entry */
+ s = t;
+ }
+
+ return 0;
+ }
+
+ /* Process "D:<dungeon>" -- info for the cave grids */
+ else if (buf[0] == 'D')
+ {
+ int x, m_idx = 0;
+
+ object_type object_type_body;
+
+ /* Acquire the text */
+ char *s = buf + 2;
+
+ /* Length of the text */
+ int len = strlen(s);
+
+ int y = *yval;
+ *xval = xvalstart;
+ for (x = *xval, i = 0; ((x < xmax) && (i < len)); x++, s++, i++)
+ {
+ /* Access the grid */
+ cave_type *c_ptr = &cave[y][x];
+
+ int idx = s[0];
+
+ int object_index = letter[idx].object;
+ int monster_index = letter[idx].monster;
+ int random = letter[idx].random;
+ int artifact_index = letter[idx].artifact;
+
+ if (!letter[idx].ok) msg_format("Warning '%c' not defined but used.", idx);
+
+ if (init_flags & INIT_GET_SIZE) continue;
+
+ /* use the plasma generator wilderness */
+ if (((!dun_level) || (!letter[idx].defined)) && (idx == ' ')) continue;
+
+ /* Clear some info */
+ c_ptr->info = 0;
+
+ /* Lay down a floor */
+ c_ptr->mimic = letter[idx].mimic;
+ cave_set_feat(y, x, letter[idx].feature);
+
+ /* Cave info */
+ c_ptr->info |= letter[idx].cave_info;
+
+ /* Create a monster */
+ if (random & RANDOM_MONSTER)
+ {
+ int level = monster_level;
+
+ monster_level = quest[p_ptr->inside_quest].level + monster_index;
+
+ m_idx = place_monster(y, x, meta_sleep, FALSE);
+
+ monster_level = level;
+ }
+ else if (monster_index)
+ {
+ /* Place it */
+ m_allow_special[monster_index] = TRUE;
+ m_idx = place_monster_aux(y, x, monster_index, meta_sleep, FALSE, MSTATUS_ENEMY);
+ m_allow_special[monster_index] = FALSE;
+ }
+
+ /* Set the mflag of the monster */
+ if (m_idx) m_list[m_idx].mflag |= letter[idx].mflag;
+
+ /* Object (and possible trap) */
+ if ((random & RANDOM_OBJECT) && (random & RANDOM_TRAP))
+ {
+ int level = object_level;
+
+ object_level = quest[p_ptr->inside_quest].level;
+
+ /*
+ * Random trap and random treasure defined
+ * 25% chance for trap and 75% chance for object
+ */
+ if (rand_int(100) < 75)
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_SPECIAL);
+ }
+ else
+ {
+ place_trap(y, x);
+ }
+
+ object_level = level;
+ }
+ else if (random & RANDOM_OBJECT)
+ {
+ /* Create an out of deep object */
+ if (object_index)
+ {
+ int level = object_level;
+
+ object_level = quest[p_ptr->inside_quest].level + object_index;
+ if (rand_int(100) < 75)
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_SPECIAL);
+ else if (rand_int(100) < 80)
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_SPECIAL);
+ else
+ place_object(y, x, TRUE, TRUE, OBJ_FOUND_SPECIAL);
+
+ object_level = level;
+ }
+ else if (rand_int(100) < 75)
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_SPECIAL);
+ }
+ else if (rand_int(100) < 80)
+ {
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_SPECIAL);
+ }
+ else
+ {
+ place_object(y, x, TRUE, TRUE, OBJ_FOUND_SPECIAL);
+ }
+ }
+ /* Random trap */
+ else if (random & RANDOM_TRAP)
+ {
+ place_trap(y, x);
+ }
+ else if (object_index)
+ {
+ /* Get local object */
+ object_type *o_ptr = &object_type_body;
+
+ k_allow_special[object_index] = TRUE;
+
+ /* Create the item */
+ object_prep(o_ptr, object_index);
+
+ /* Apply magic (no messages, no artifacts) */
+ apply_magic(o_ptr, dun_level, FALSE, TRUE, FALSE);
+
+ o_ptr->found = OBJ_FOUND_SPECIAL;
+
+ k_allow_special[object_index] = FALSE;
+
+ drop_near(o_ptr, -1, y, x);
+ }
+
+ /* Artifact */
+ if (artifact_index)
+ {
+ int I_kind = 0;
+
+ artifact_type *a_ptr = &a_info[artifact_index];
+
+ object_type forge;
+
+ /* Get local object */
+ object_type *q_ptr = &forge;
+
+ a_allow_special[artifact_index] = TRUE;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Acquire the "kind" index */
+ I_kind = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Create the artifact */
+ object_prep(q_ptr, I_kind);
+
+ /* Save the name */
+ q_ptr->name1 = artifact_index;
+
+ /* Extract the fields */
+ q_ptr->pval = a_ptr->pval;
+ q_ptr->ac = a_ptr->ac;
+ q_ptr->dd = a_ptr->dd;
+ q_ptr->ds = a_ptr->ds;
+ q_ptr->to_a = a_ptr->to_a;
+ q_ptr->to_h = a_ptr->to_h;
+ q_ptr->to_d = a_ptr->to_d;
+ q_ptr->weight = a_ptr->weight;
+ q_ptr->found = OBJ_FOUND_SPECIAL;
+
+ random_artifact_resistance(q_ptr);
+
+ a_info[artifact_index].cur_num = 1;
+
+ a_allow_special[artifact_index] = FALSE;
+
+ /* It's amazing that this "creating objects anywhere"
+ junk ever worked.
+ Let's just HACK around one observed bug: Shadow Cloak
+ of Luthien [Globe of Light] */
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags(q_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if (f5 & TR5_SPELL_CONTAIN)
+ q_ptr->pval2 = -1;
+ }
+
+ /* Drop the artifact */
+ drop_near(q_ptr, -1, y, x);
+
+ }
+
+ /* Terrain special */
+ if (letter[idx].special == -1)
+ {
+ if (!letter[idx].bx)
+ {
+ letter[idx].bx = x;
+ letter[idx].by = y;
+ }
+ else
+ {
+ c_ptr->special = (letter[idx].by << 8) + letter[idx].bx;
+ cave[letter[idx].by][letter[idx].bx].special = (y << 8) + x;
+ }
+ }
+ else
+ {
+ c_ptr->special = letter[idx].special;
+ }
+ }
+ if (full && (*xval < x)) *xval = x;
+ (*yval)++;
+
+ return (0);
+ }
+
+ /* Process "W:<command>: ..." -- info for the wilderness */
+ else if (buf[0] == 'W')
+ {
+ /* Process "W:D:<layout> */
+ /* Layout of the wilderness */
+ if (buf[2] == 'D')
+ {
+ int x;
+ char i;
+
+ /* Acquire the text */
+ char *s = buf + 4;
+
+ int y = *yval;
+
+ for (x = 0; x < max_wild_x; x++)
+ {
+ if (1 != sscanf(s + x, "%c", &i)) return (1);
+ wild_map[y][x].feat = wildc2i[(int)i];
+
+ /*
+ * If this is a town/dungeon entrance, note
+ * its coordinates. (Have to check for
+ * duplicate Morias...)
+ */
+ if (wf_info[wildc2i[(int)i]].entrance &&
+ wf_info[wildc2i[(int)i]].wild_x == 0)
+ {
+ wf_info[wildc2i[(int)i]].wild_x = x;
+ wf_info[wildc2i[(int)i]].wild_y = y;
+ }
+ }
+
+ (*yval)++;
+
+ return (0);
+ }
+ /* Process "M:<plus>:<line>" -- move line lines */
+ else if (buf[2] == 'M')
+ {
+ if (tokenize(buf + 4, 2, zz, ':', '/') == 2)
+ {
+ if (atoi(zz[0]))
+ {
+ (*yval) += atoi(zz[1]);
+ }
+ else
+ {
+ (*yval) -= atoi(zz[1]);
+ }
+ }
+ else
+ {
+ return (1);
+ }
+ return (0);
+ }
+ /* Process "W:P:<x>:<y> - starting position in the wilderness */
+ else if (buf[2] == 'P')
+ {
+ if ((p_ptr->wilderness_x == 0) &&
+ (p_ptr->wilderness_y == 0))
+ {
+ if (tokenize(buf + 4, 2, zz, ':', '/') == 2)
+ {
+ p_ptr->wilderness_x = atoi(zz[0]);
+ p_ptr->wilderness_y = atoi(zz[1]);
+ }
+ else
+ {
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+ /* Process "W:E:<dungeon>:<y>:<x> - entrance to the dungeon <dungeon> */
+ else if (buf[2] == 'E')
+ {
+ if (tokenize(buf + 4, 3, zz, ':', '/') == 3)
+ {
+ wild_map[atoi(zz[1])][atoi(zz[2])].entrance = 1000 + atoi(zz[0]);
+ }
+ else
+ {
+ return (1);
+ }
+
+ return (0);
+ }
+ }
+
+ /* Process "P:<y>:<x>" -- player position */
+ else if (buf[0] == 'P')
+ {
+ if (init_flags & INIT_CREATE_DUNGEON)
+ {
+ if (tokenize(buf + 2, 2, zz, ':', '/') == 2)
+ {
+ /* Place player in a quest level */
+ if (p_ptr->inside_quest || (init_flags & INIT_POSITION))
+ {
+ p_ptr->py = atoi(zz[0]);
+ p_ptr->px = atoi(zz[1]);
+ }
+ /* Place player in the town */
+ else if ((p_ptr->oldpx == 0) && (p_ptr->oldpy == 0))
+ {
+ p_ptr->oldpy = atoi(zz[0]);
+ p_ptr->oldpx = atoi(zz[1]);
+ }
+ }
+ }
+
+ return (0);
+ }
+
+ /* Process "M:<type>:<maximum>" -- set maximum values */
+ else if (buf[0] == 'M')
+ {
+ if (tokenize(buf + 2, 3, zz, ':', '/') >= 2)
+ {
+ /* Maximum towns */
+ if (zz[0][0] == 'T')
+ {
+ max_towns = atoi(zz[1]);
+ }
+
+ /* Maximum real towns */
+ if (zz[0][0] == 't')
+ {
+ max_real_towns = atoi(zz[1]);
+ }
+
+ /* Maximum r_idx */
+ else if (zz[0][0] == 'R')
+ {
+ max_r_idx = atoi(zz[1]);
+ }
+
+ /* Maximum re_idx */
+ else if (zz[0][0] == 'r')
+ {
+ max_re_idx = atoi(zz[1]);
+ }
+
+ /* Maximum s_idx */
+ else if (zz[0][0] == 'k')
+ {
+ max_s_idx = atoi(zz[1]);
+ if (max_s_idx > MAX_SKILLS) return (1);
+ }
+
+ /* Maximum ab_idx */
+ else if (zz[0][0] == 'b')
+ {
+ max_ab_idx = atoi(zz[1]);
+ }
+
+ /* Maximum k_idx */
+ else if (zz[0][0] == 'K')
+ {
+ max_k_idx = atoi(zz[1]);
+ }
+
+ /* Maximum v_idx */
+ else if (zz[0][0] == 'V')
+ {
+ max_v_idx = atoi(zz[1]);
+ }
+
+ /* Maximum f_idx */
+ else if (zz[0][0] == 'F')
+ {
+ max_f_idx = atoi(zz[1]);
+ }
+
+ /* Maximum a_idx */
+ else if (zz[0][0] == 'A')
+ {
+ max_a_idx = atoi(zz[1]);
+ }
+
+ /* Maximum al_idx */
+ else if (zz[0][0] == 'a')
+ {
+ max_al_idx = atoi(zz[1]);
+ }
+
+ /* Maximum e_idx */
+ else if (zz[0][0] == 'E')
+ {
+ max_e_idx = atoi(zz[1]);
+ }
+
+ /* Maximum ra_idx */
+ else if (zz[0][0] == 'Z')
+ {
+ max_ra_idx = atoi(zz[1]);
+ }
+
+ /* Maximum o_idx */
+ else if (zz[0][0] == 'O')
+ {
+ max_o_idx = atoi(zz[1]);
+ }
+
+ /* Maximum player types */
+ else if (zz[0][0] == 'P')
+ {
+ if (zz[1][0] == 'R')
+ {
+ max_rp_idx = atoi(zz[2]);
+ }
+ else if (zz[1][0] == 'S')
+ {
+ max_rmp_idx = atoi(zz[2]);
+ }
+ else if (zz[1][0] == 'C')
+ {
+ max_c_idx = atoi(zz[2]);
+ }
+ else if (zz[1][0] == 'M')
+ {
+ max_mc_idx = atoi(zz[2]);
+ }
+ else if (zz[1][0] == 'H')
+ {
+ max_bg_idx = atoi(zz[2]);
+ }
+ }
+
+ /* Maximum m_idx */
+ else if (zz[0][0] == 'M')
+ {
+ max_m_idx = atoi(zz[1]);
+ }
+
+ /* Maximum tr_idx */
+ else if (zz[0][0] == 'U')
+ {
+ max_t_idx = atoi(zz[1]);
+ }
+
+ /* Maximum wf_idx */
+ else if (zz[0][0] == 'W')
+ {
+ max_wf_idx = atoi(zz[1]);
+ }
+
+ /* Maximum ba_idx */
+ else if (zz[0][0] == 'B')
+ {
+ max_ba_idx = atoi(zz[1]);
+ }
+
+ /* Maximum st_idx */
+ else if (zz[0][0] == 'S')
+ {
+ max_st_idx = atoi(zz[1]);
+ }
+
+ /* Maximum set_idx */
+ else if (zz[0][0] == 's')
+ {
+ max_set_idx = atoi(zz[1]);
+ }
+
+ /* Maximum ow_idx */
+ else if (zz[0][0] == 'N')
+ {
+ max_ow_idx = atoi(zz[1]);
+ }
+
+ /* Maximum wilderness x size */
+ else if (zz[0][0] == 'X')
+ {
+ max_wild_x = atoi(zz[1]);
+ }
+
+ /* Maximum wilderness y size */
+ else if (zz[0][0] == 'Y')
+ {
+ max_wild_y = atoi(zz[1]);
+ }
+
+ /* Maximum d_idx */
+ else if (zz[0][0] == 'D')
+ {
+ max_d_idx = atoi(zz[1]);
+ }
+
+ return (0);
+ }
+ }
+
+ /* Failure */
+ return (1);
+}
+
+
+
+
+/*
+ * Helper function for "process_dungeon_file()"
+ */
+static cptr process_dungeon_file_expr(char **sp, char *fp)
+{
+ cptr v;
+
+ char *b;
+ char *s;
+
+ char b1 = '[';
+ char b2 = ']';
+
+ char f = ' ';
+
+ /* Initial */
+ s = (*sp);
+
+ /* Skip spaces */
+ while (isspace(*s)) s++;
+
+ /* Save start */
+ b = s;
+
+ /* Default */
+ v = "?o?o?";
+
+ /* Analyze */
+ if (*s == b1)
+ {
+ const char *p;
+ const char *t;
+
+ /* Skip b1 */
+ s++;
+
+ /* First */
+ t = process_dungeon_file_expr(&s, &f);
+
+ /* Oops */
+ if (!*t)
+ {
+ /* Nothing */
+ }
+
+ /* Function: IOR */
+ else if (streq(t, "IOR"))
+ {
+ v = "0";
+ while (*s && (f != b2))
+ {
+ t = process_dungeon_file_expr(&s, &f);
+ if (*t && !streq(t, "0")) v = "1";
+ }
+ }
+
+ /* Function: AND */
+ else if (streq(t, "AND"))
+ {
+ v = "1";
+ while (*s && (f != b2))
+ {
+ t = process_dungeon_file_expr(&s, &f);
+ if (*t && streq(t, "0")) v = "0";
+ }
+ }
+
+ /* Function: NOT */
+ else if (streq(t, "NOT"))
+ {
+ v = "1";
+ while (*s && (f != b2))
+ {
+ t = process_dungeon_file_expr(&s, &f);
+ if (*t && streq(t, "1")) v = "0";
+ }
+ }
+
+ /* Function: EQU */
+ else if (streq(t, "EQU"))
+ {
+ v = "1";
+ if (*s && (f != b2))
+ {
+ t = process_dungeon_file_expr(&s, &f);
+ }
+ while (*s && (f != b2))
+ {
+ p = t;
+ t = process_dungeon_file_expr(&s, &f);
+ if (*t && !streq(p, t)) v = "0";
+ }
+ }
+
+ /* Function: LEQ */
+ else if (streq(t, "LEQ"))
+ {
+ v = "1";
+ if (*s && (f != b2))
+ {
+ t = process_dungeon_file_expr(&s, &f);
+ }
+ while (*s && (f != b2))
+ {
+ p = t;
+ t = process_dungeon_file_expr(&s, &f);
+ if (*t && (strcmp(p, t) > 0)) v = "0";
+ }
+ }
+
+ /* Function: GEQ */
+ else if (streq(t, "GEQ"))
+ {
+ v = "1";
+ if (*s && (f != b2))
+ {
+ t = process_dungeon_file_expr(&s, &f);
+ }
+ while (*s && (f != b2))
+ {
+ p = t;
+ t = process_dungeon_file_expr(&s, &f);
+ if (*t && (strcmp(p, t) < 0)) v = "0";
+ }
+ }
+
+ /* Oops */
+ else
+ {
+ while (*s && (f != b2))
+ {
+ t = process_dungeon_file_expr(&s, &f);
+ }
+ }
+
+ /* Verify ending */
+ if (f != b2) v = "?x?x?";
+
+ /* Extract final and Terminate */
+ if ((f = *s) != '\0') * s++ = '\0';
+ }
+
+ /* Other */
+ else
+ {
+ bool_ text_mode = FALSE;
+
+ /* Accept all printables except spaces and brackets */
+ while (isprint(*s))
+ {
+ if (*s == '"') text_mode = !text_mode;
+ if (!text_mode)
+ {
+ if (strchr(" []", *s))
+ break;
+ }
+ else
+ {
+ if (strchr("[]", *s))
+ break;
+ }
+
+ ++s;
+ }
+
+ /* Extract final and Terminate */
+ if ((f = *s) != '\0') * s++ = '\0';
+
+ /* Variable */
+ if (*b == '$')
+ {
+ /* System */
+ if (streq(b + 1, "SYS"))
+ {
+ v = ANGBAND_SYS;
+ }
+
+ /* Graphics */
+ else if (streq(b + 1, "GRAF"))
+ {
+ v = ANGBAND_GRAF;
+ }
+
+ /* Race */
+ else if (streq(b + 1, "RACE"))
+ {
+ v = rp_ptr->title + rp_name;
+ }
+
+ /* Race Mod */
+ else if (streq(b + 1, "RACEMOD"))
+ {
+ v = rmp_ptr->title + rmp_name;
+ }
+
+ /* Class */
+ else if (streq(b + 1, "CLASS"))
+ {
+ v = cp_ptr->title + c_name;
+ }
+
+ /* Player */
+ else if (streq(b + 1, "PLAYER"))
+ {
+ v = player_base;
+ }
+
+ /* Town */
+ else if (streq(b + 1, "TOWN"))
+ {
+ strnfmt(pref_tmp_value, 8, "%d", p_ptr->town_num);
+ v = pref_tmp_value;
+ }
+
+ /* Town destroyed */
+ else if (prefix(b + 1, "TOWN_DESTROY"))
+ {
+ strnfmt(pref_tmp_value, 8, "%d", town_info[atoi(b + 13)].destroyed);
+ v = pref_tmp_value;
+ }
+
+ /* Current quest number */
+ else if (streq(b + 1, "QUEST_NUMBER"))
+ {
+ strnfmt(pref_tmp_value, 8, "%d", p_ptr->inside_quest);
+ v = pref_tmp_value;
+ }
+
+ /* Number of last quest */
+ else if (streq(b + 1, "LEAVING_QUEST"))
+ {
+ strnfmt(pref_tmp_value, 8, "%d", leaving_quest);
+ v = pref_tmp_value;
+ }
+
+ /* DAYTIME status */
+ else if (prefix(b + 1, "DAYTIME"))
+ {
+ if ((bst(HOUR, turn) >= 6) && (bst(HOUR, turn) < 18))
+ v = "1";
+ else
+ v = "0";
+ }
+
+ /* Quest status */
+ else if (prefix(b + 1, "QUEST"))
+ {
+ /* "QUEST" uses a special parameter to determine the number of the quest */
+ if (*(b + 6) != '"')
+ strnfmt(pref_tmp_value, 8, "%d", quest[atoi(b + 6)].status);
+ else
+ {
+ char c[80];
+ int i;
+
+ /* Copy it to temp array, so that we can modify it safely */
+ strcpy(c, b + 7);
+
+ /* Hunt & shoot the ending " */
+ for (i = 0; (c[i] != '"') && (c[i] != '\0'); i++);
+ if (c[i] == '"') c[i] = '\0';
+ strcpy(pref_tmp_value, "-1");
+ for (i = 0; i < max_q_idx; i++)
+ {
+ if (streq(c, quest[i].name))
+ {
+ strnfmt(pref_tmp_value, 8, "%d", quest[i].status);
+ break;
+ }
+ }
+ }
+ v = pref_tmp_value;
+ }
+
+ /* Variant name */
+ else if (streq(b + 1, "VARIANT"))
+ {
+ v = "ToME";
+ }
+
+ /* Wilderness */
+ else if (streq(b + 1, "WILDERNESS"))
+ {
+ v = "NORMAL";
+ }
+ }
+
+ /* Constant */
+ else
+ {
+ v = b;
+ }
+ }
+
+ /* Save */
+ (*fp) = f;
+
+ /* Save */
+ (*sp) = s;
+
+ /* Result */
+ return (v);
+}
+
+
+errr process_dungeon_file(cptr name, int *yval, int *xval, int ymax, int xmax, bool_ init, bool_ full)
+{
+ FILE *fp = 0;
+
+ char buf[1024];
+
+ int num = -1, i;
+
+ errr err = 0;
+
+ bool_ bypass = FALSE;
+
+ /* Save the start since it ought to be modified */
+ int xmin = *xval;
+
+ if (init)
+ {
+ meta_sleep = TRUE;
+ for (i = 0; i < 255; i++)
+ {
+ letter[i].defined = FALSE;
+ if (i == ' ') letter[i].ok = TRUE;
+ else letter[i].ok = FALSE;
+ letter[i].bx = 0;
+ letter[i].by = 0;
+ }
+ }
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, name);
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* No such file */
+ if (!fp)
+ {
+ msg_format("Cannot find file %s at %s", name, buf);
+ return ( -1);
+ }
+
+ /* Process the file */
+ while (0 == my_fgets(fp, buf, 1024))
+ {
+ /* Count lines */
+ num++;
+
+
+ /* Skip "empty" lines */
+ if (!buf[0]) continue;
+
+ /* Skip "blank" lines */
+ if (isspace(buf[0])) continue;
+
+ /* Skip comments */
+ if (buf[0] == '#') continue;
+
+
+ /* Process "?:<expr>" */
+ if ((buf[0] == '?') && (buf[1] == ':'))
+ {
+ char f;
+ cptr v;
+ char *s;
+
+ /* Start */
+ s = buf + 2;
+
+ /* Parse the expr */
+ v = process_dungeon_file_expr(&s, &f);
+
+ /* Set flag */
+ bypass = (streq(v, "0") ? TRUE : FALSE);
+
+ /* Continue */
+ continue;
+ }
+
+ /* Apply conditionals */
+ if (bypass) continue;
+
+
+ /* Process "%:<file>" */
+ if (buf[0] == '%')
+ {
+ /* Process that file if allowed */
+ (void)process_dungeon_file(buf + 2, yval, xval, ymax, xmax, FALSE, full);
+
+ /* Continue */
+ continue;
+ }
+
+
+ /* Process the line */
+ err = process_dungeon_file_aux(buf, yval, xval, xmin, ymax, xmax, full);
+
+ /* Oops */
+ if (err) break;
+ }
+
+
+ /* Error */
+ if (err)
+ {
+ /* Useful error message */
+ msg_format("Error %d in line %d of file '%s'.", err, num, name);
+ msg_format("Parsing '%s'", buf);
+ }
+
+ /* Close the file */
+ my_fclose(fp);
+
+ /* Result */
+ return (err);
+}
diff --git a/src/init2.c b/src/init2.c
new file mode 100644
index 00000000..5239426c
--- /dev/null
+++ b/src/init2.c
@@ -0,0 +1,2918 @@
+/* File: init2.c */
+
+/* Purpose: Initialisation (part 2) -BEN- */
+
+#include "angband.h"
+
+
+/*
+ * This file is used to initialise various variables and arrays for the
+ * Angband game. Note the use of "fd_read()" and "fd_write()" to bypass
+ * the common limitation of "read()" and "write()" to only 32767 bytes
+ * at a time.
+ *
+ * Several of the arrays for Angband are built from "template" files in
+ * the "lib/file" directory, from which quick-load binary "image" files
+ * are constructed whenever they are not present in the "lib/data"
+ * directory, or if those files become obsolete, if we are allowed.
+ *
+ * Warning -- the "ascii" file parsers use a minor hack to collect the
+ * name and text information in a single pass. Thus, the game will not
+ * be able to load any template file with more than 20K of names or 60K
+ * of text, even though technically, up to 64K should be legal.
+ *
+ * The "init1.c" file is used only to parse the ascii template files.
+ */
+
+
+
+/*
+ * Find the default paths to all of our important sub-directories.
+ *
+ * The purpose of each sub-directory is described in "variable.c".
+ *
+ * All of the sub-directories should, by default, be located inside
+ * the main "lib" directory, whose location is very system dependant.
+ *
+ * This function takes a writable buffer, initially containing the
+ * "path" to the "lib" directory, for example, "/pkg/lib/angband/",
+ * or a system dependant string, for example, ":lib:". The buffer
+ * must be large enough to contain at least 32 more characters.
+ *
+ * Various command line options may allow some of the important
+ * directories to be changed to user-specified directories, most
+ * importantly, the "info" and "user" and "save" directories,
+ * but this is done after this function, see "main.c".
+ *
+ * In general, the initial path should end in the appropriate "PATH_SEP"
+ * string. All of the "sub-directory" paths (created below or supplied
+ * by the user) will NOT end in the "PATH_SEP" string, see the special
+ * "path_build()" function in "util.c" for more information.
+ *
+ * Mega-Hack -- support fat raw files under NEXTSTEP, using special
+ * "suffixed" directories for the "ANGBAND_DIR_DATA" directory, but
+ * requiring the directories to be created by hand by the user.
+ *
+ * Hack -- first we free all the strings, since this is known
+ * to succeed even if the strings have not been allocated yet,
+ * as long as the variables start out as "NULL". This allows
+ * this function to be called multiple times, for example, to
+ * try several base "path" values until a good one is found.
+ */
+void init_file_paths(char *path)
+{
+ char *tail;
+ int pathlen;
+
+ /*** Free everything ***/
+
+ /* Free the main path */
+ string_free(ANGBAND_DIR);
+
+ /* Free the sub-paths */
+ string_free(ANGBAND_DIR_APEX);
+ string_free(ANGBAND_DIR_CORE);
+ string_free(ANGBAND_DIR_DNGN);
+ string_free(ANGBAND_DIR_DATA);
+ string_free(ANGBAND_DIR_EDIT);
+ string_free(ANGBAND_DIR_FILE);
+ string_free(ANGBAND_DIR_HELP);
+ string_free(ANGBAND_DIR_INFO);
+ string_free(ANGBAND_DIR_MODULES);
+ string_free(ANGBAND_DIR_NOTE);
+ string_free(ANGBAND_DIR_SAVE);
+ string_free(ANGBAND_DIR_SCPT);
+ string_free(ANGBAND_DIR_PREF);
+ string_free(ANGBAND_DIR_PATCH);
+ string_free(ANGBAND_DIR_USER);
+ string_free(ANGBAND_DIR_XTRA);
+ string_free(ANGBAND_DIR_CMOV);
+
+
+ /*** Prepare the "path" ***/
+
+ pathlen = strlen(path);
+
+ /* Hack -- save the main directory without trailing PATH_SEP if present */
+ if (strlen(PATH_SEP) > 0 && pathlen > 0)
+ {
+ int seplen = strlen(PATH_SEP);
+
+ if (strcmp(path + pathlen - seplen, PATH_SEP) == 0)
+ {
+ path[pathlen - seplen] = '\0';
+ ANGBAND_DIR = string_make(path);
+ path[pathlen - seplen] = *PATH_SEP;
+ }
+ else
+ {
+ ANGBAND_DIR = string_make(path);
+ }
+ }
+ else
+ {
+ ANGBAND_DIR = string_make(path);
+ }
+
+ /* Prepare to append to the Base Path */
+ tail = path + pathlen;
+
+
+
+ /*** Build the sub-directory names ***/
+
+ /* Build a path name */
+ strcpy(tail, "apex");
+ ANGBAND_DIR_APEX = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "core");
+ ANGBAND_DIR_CORE = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "dngn");
+ ANGBAND_DIR_DNGN = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "data");
+ ANGBAND_DIR_DATA = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "edit");
+ ANGBAND_DIR_EDIT = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "file");
+ ANGBAND_DIR_FILE = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "help");
+ ANGBAND_DIR_HELP = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "info");
+ ANGBAND_DIR_INFO = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "mods");
+ ANGBAND_DIR_MODULES = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "patch");
+ ANGBAND_DIR_PATCH = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "scpt");
+ ANGBAND_DIR_SCPT = string_make(path);
+
+ /* Build a path name */
+ strcpy(tail, "pref");
+ ANGBAND_DIR_PREF = string_make(path);
+
+ /* synchronize with module_reset_dir */
+ {
+ char user_path[1024];
+
+ /* Get an absolute path from the file name */
+ path_parse(user_path, 1024, PRIVATE_USER_PATH);
+ strcat(user_path, USER_PATH_VERSION);
+ ANGBAND_DIR_USER = string_make(user_path);
+ ANGBAND_DIR_NOTE = string_make(user_path);
+ ANGBAND_DIR_CMOV = string_make(user_path);
+#ifdef PRIVATE_USER_PATH_MODULES
+ ANGBAND_DIR_MODULES = string_make(user_path);
+#endif
+#ifdef PRIVATE_USER_PATH_APEX
+ ANGBAND_DIR_APEX = string_make(user_path);
+#endif
+#ifdef PRIVATE_USER_PATH_DATA
+ {
+ char user_path_data[1024];
+ strcpy(user_path_data, user_path);
+ strcat(user_path_data, "/data");
+ ANGBAND_DIR_DATA = string_make(user_path_data);
+ }
+#endif
+
+ /* Savefiles are in user directory */
+ strcat(user_path, "/save");
+ ANGBAND_DIR_SAVE = string_make(user_path);
+ }
+
+ /* Build a path name */
+ strcpy(tail, "xtra");
+ ANGBAND_DIR_XTRA = string_make(path);
+
+#ifdef NeXT
+
+ /* Allow "fat binary" usage with NeXT */
+ if (TRUE)
+ {
+ cptr next = NULL;
+
+# if defined(m68k)
+ next = "m68k";
+# endif
+
+# if defined(i386)
+ next = "i386";
+# endif
+
+# if defined(sparc)
+ next = "sparc";
+# endif
+
+# if defined(hppa)
+ next = "hppa";
+# endif
+
+ /* Use special directory */
+ if (next)
+ {
+ /* Forget the old path name */
+ string_free(ANGBAND_DIR_DATA);
+
+ /* Build a new path name */
+ sprintf(tail, "data-%s", next);
+ ANGBAND_DIR_DATA = string_make(path);
+ }
+ }
+
+#endif /* NeXT */
+
+}
+
+
+/**
+ * Realloc the given character array.
+ */
+static void z_realloc(char **p, size_t n) {
+ /* realloc doesn't really support size 0, but we want to shrink the allocated area regardless. */
+ if (n == 0) {
+ n = 1;
+ }
+ /* do the reallocation */
+ *p = realloc(*p, n);
+ if (*p == NULL) {
+ quit("Error during realloc.");
+ }
+}
+
+/*
+ * Hack -- help give useful error messages
+ */
+s16b error_idx;
+s16b error_line;
+
+
+/*
+ * Hack -- help initialise the fake "name" and "text" arrays when
+ * parsing an "ascii" template file.
+ */
+u32b fake_name_size;
+u32b fake_text_size;
+
+
+/*
+ * Standard error message text
+ */
+static cptr err_str[9] =
+{
+ NULL,
+ "parse error",
+ "obsolete file",
+ "missing record header",
+ "non-sequential records",
+ "invalid flag specification",
+ "undefined directive",
+ "out of memory",
+ "invalid skill chart"
+};
+
+
+/*
+ * Hack -- take notes on line 23
+ */
+static void note(cptr str)
+{
+ Term_erase(0, 23, 255);
+ Term_putstr(20, 23, -1, TERM_WHITE, str);
+ Term_fresh();
+}
+
+
+
+/*
+ * Initialise the "f_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_f_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(f_head, header);
+
+ /* Save the "record" information */
+ f_head->info_num = max_f_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "f_name" and "f_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "f_info" array */
+ C_MAKE(f_info, f_head->info_num, feature_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(f_name, fake_name_size, char);
+ C_MAKE(f_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "f_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'f_info.txt' file.");
+
+ /* Parse the file */
+ err = init_f_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'f_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'f_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&f_name, f_head->name_size);
+ z_realloc(&f_text, f_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Initialise the "k_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_k_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(k_head, header);
+
+ /* Save the "record" information */
+ k_head->info_num = max_k_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "k_name" and "k_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "k_info" array */
+ C_MAKE(k_info, k_head->info_num, object_kind);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(k_name, fake_name_size, char);
+ C_MAKE(k_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "k_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'k_info.txt' file.");
+
+ /* Parse the file */
+ err = init_k_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'k_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'k_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&k_name, k_head->name_size);
+ z_realloc(&k_text, k_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Initialise the "set_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_set_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the "header" ***/
+
+ /* Allocate the "header" */
+ MAKE(set_head, header);
+
+ /* Save the "record" information */
+ set_head->info_num = max_set_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "set_name" and "set_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "set_info" array */
+ C_MAKE(set_info, set_head->info_num, set_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(set_name, fake_name_size, char);
+ C_MAKE(set_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "set_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'set_info.txt' file.");
+
+ /* Parse the file */
+ err = init_set_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'set_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'set_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&set_name, set_head->name_size);
+ z_realloc(&set_text, set_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialise the "a_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_a_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the "header" ***/
+
+ /* Allocate the "header" */
+ MAKE(a_head, header);
+
+ /* Save the "record" information */
+ a_head->info_num = max_a_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "a_name" and "a_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "a_info" array */
+ C_MAKE(a_info, a_head->info_num, artifact_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(a_name, fake_name_size, char);
+ C_MAKE(a_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "a_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'a_info.txt' file.");
+
+ /* Parse the file */
+ err = init_a_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'a_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'a_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&a_name, a_head->name_size);
+ z_realloc(&a_text, a_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialise the "s_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_s_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the "header" ***/
+
+ /* Allocate the "header" */
+ MAKE(s_head, header);
+
+ /* Save the "record" information */
+ s_head->info_num = max_s_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "a_name" and "a_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "s_info" array */
+ C_MAKE(s_info, s_head->info_num, skill_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(s_name, fake_name_size, char);
+ C_MAKE(s_text, fake_text_size, char);
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "s_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 's_info.txt' file.");
+
+ /* Parse the file */
+ err = init_s_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 's_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 's_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&s_name, s_head->name_size);
+ z_realloc(&s_text, s_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialise the "ab_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_ab_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+
+ /*** Make the "header" ***/
+
+ /* Allocate the "header" */
+ MAKE(ab_head, header);
+
+ /* Save the "record" information */
+ ab_head->info_num = max_ab_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "a_name" and "a_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "ab_info" array */
+ C_MAKE(ab_info, ab_head->info_num, ability_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(ab_name, fake_name_size, char);
+ C_MAKE(ab_text, fake_text_size, char);
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "ab_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'ab_info.txt' file.");
+
+ /* Parse the file */
+ err = init_ab_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'ab_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'ab_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&ab_name, ab_head->name_size);
+ z_realloc(&ab_text, ab_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Initialise the "e_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_e_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the "header" ***/
+
+ /* Allocate the "header" */
+ MAKE(e_head, header);
+
+ /* Save the "record" information */
+ e_head->info_num = max_e_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "e_name" and "e_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "e_info" array */
+ C_MAKE(e_info, e_head->info_num, ego_item_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(e_name, fake_name_size, char);
+ C_MAKE(e_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "e_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'e_info.txt' file.");
+
+ /* Parse the file */
+ err = init_e_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'e_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'e_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&e_name, e_head->name_size);
+ z_realloc(&e_text, e_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Initialise the "ra_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_ra_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+ /*** Make the "header" ***/
+
+ /* Allocate the "header" */
+ MAKE(ra_head, header);
+
+ /* Save the "record" information */
+ ra_head->info_num = max_ra_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "ra_name" and "ra_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "ra_info" array */
+ C_MAKE(ra_info, ra_head->info_num, randart_part_type);
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "ra_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'ra_info.txt' file.");
+
+ /* Parse the file */
+ err = init_ra_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'ra_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'ra_info.txt' file.");
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Initialise the "r_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_r_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(r_head, header);
+
+ /* Save the "record" information */
+ r_head->info_num = max_r_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Assume the size of "r_name" and "r_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "r_info" array */
+ C_MAKE(r_info, r_head->info_num, monster_race);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(r_name, fake_name_size, char);
+ C_MAKE(r_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "r_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'r_info.txt' file.");
+
+ /* Parse the file */
+ err = init_r_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'r_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'r_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&r_name, r_head->name_size);
+ z_realloc(&r_text, r_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialise the "re_info" array
+ *
+ * Note that we let each entry have a unique "name" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_re_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(re_head, header);
+
+ /* Save the "record" information */
+ re_head->info_num = max_re_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Assume the size of "re_name" */
+ fake_name_size = FAKE_NAME_SIZE;
+
+ /* Allocate the "re_info" array */
+ C_MAKE(re_info, re_head->info_num, monster_ego);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(re_name, fake_name_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "re_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 're_info.txt' file.");
+
+ /* Parse the file */
+ err = init_re_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 're_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 're_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&re_name, re_head->name_size);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialise the "d_info" array
+ *
+ * Note that we let each entry have a unique "name" and "short name" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_d_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(d_head, header);
+
+ /* Save the "record" information */
+ d_head->info_num = max_d_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Assume the size of "d_name" and "d_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "d_info" array */
+ C_MAKE(d_info, d_head->info_num, dungeon_info_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(d_name, fake_name_size, char);
+ C_MAKE(d_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "d_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'd_info.txt' file.");
+
+ /* Parse the file */
+ err = init_d_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d df 'd_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'd_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&d_name, d_head->name_size);
+ z_realloc(&d_text, d_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialise the "player" arrays
+ *
+ * Note that we let each entry have a unique "name" and "short name" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_player_info(void)
+{
+ int i;
+
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(rp_head, header);
+
+ /* Save the "record" information */
+ rp_head->info_num = max_rp_idx;
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(rmp_head, header);
+
+ /* Save the "record" information */
+ rmp_head->info_num = max_rmp_idx;
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(c_head, header);
+
+ /* Save the "record" information */
+ c_head->info_num = max_c_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Assume the size of "rp_name" and "rp_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "rp_info" array */
+ C_MAKE(race_info, rp_head->info_num, player_race);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(rp_name, fake_name_size, char);
+ C_MAKE(rp_text, fake_text_size, char);
+
+ /* Allocate the "rmp_info" array */
+ C_MAKE(race_mod_info, rmp_head->info_num, player_race_mod);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(rmp_name, fake_name_size, char);
+ C_MAKE(rmp_text, fake_text_size, char);
+
+ /* Allocate the "c_info" array */
+ C_MAKE(class_info, c_head->info_num, player_class);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(c_name, fake_name_size, char);
+ C_MAKE(c_text, fake_text_size, char);
+
+ /* Allocate the "bg" array */
+ C_MAKE(bg, max_bg_idx, hist_type);
+
+ /* Allocate the "meta_class" array */
+ C_MAKE(meta_class_info, max_mc_idx, meta_class_type);
+ for (i = 0; i < max_mc_idx; i++)
+ {
+ C_MAKE(meta_class_info[i].classes, max_c_idx, s16b);
+ }
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "p_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'p_info.txt' file.");
+
+ /* Parse the file */
+ err = init_player_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d df 'p_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'p_info.txt' file.");
+ }
+
+ /* Reallocate arrays. */
+ z_realloc(&rp_name, rp_head->name_size);
+ z_realloc(&rp_text, rp_head->text_size);
+ z_realloc(&rmp_name, rmp_head->name_size);
+ z_realloc(&rmp_text, rmp_head->text_size);
+ z_realloc(&c_name, c_head->name_size);
+ z_realloc(&c_text, c_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialise the "st_info" array
+ *
+ * Note that we let each entry have a unique "name" and "short name" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_st_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(st_head, header);
+
+ /* Save the "record" information */
+ st_head->info_num = max_st_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Assume the size of "st_name" and "st_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+
+ /* Allocate the "st_info" array */
+ C_MAKE(st_info, st_head->info_num, store_info_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(st_name, fake_name_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "st_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'st_info.txt' file.");
+
+ /* Parse the file */
+ err = init_st_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d df 'st_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'st_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&st_name, st_head->name_size);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialise the "ow_info" array
+ *
+ * Note that we let each entry have a unique "name" and "short name" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_ow_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(ow_head, header);
+
+ /* Save the "record" information */
+ ow_head->info_num = max_ow_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Assume the size of "ow_name" and "ow_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+
+ /* Allocate the "ow_info" array */
+ C_MAKE(ow_info, ow_head->info_num, owner_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(ow_name, fake_name_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "ow_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'ow_info.txt' file.");
+
+ /* Parse the file */
+ err = init_ow_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d df 'ow_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'ow_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&ow_name, ow_head->name_size);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialise the "ba_info" array
+ *
+ * Note that we let each entry have a unique "name" and "short name" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_ba_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(ba_head, header);
+
+ /* Save the "record" information */
+ ba_head->info_num = max_ba_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Assume the size of "ba_name" and "ba_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+
+ /* Allocate the "ba_info" array */
+ C_MAKE(ba_info, ba_head->info_num, store_action_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(ba_name, fake_name_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "ba_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'ba_info.txt' file.");
+
+ /* Parse the file */
+ err = init_ba_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d df 'ba_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'ba_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&ba_name, ba_head->name_size);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialise the "wf_info" array
+ *
+ * Note that we let each entry have a unique "name" and "short name" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_wf_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(wf_head, header);
+
+ /* Save the "record" information */
+ wf_head->info_num = max_wf_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Assume the size of "wf_name" and "wf_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "r_info" array */
+ C_MAKE(wf_info, wf_head->info_num, wilderness_type_info);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(wf_name, fake_name_size, char);
+ C_MAKE(wf_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "wf_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'wf_info.txt' file.");
+
+ /* Parse the file */
+ err = init_wf_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d df 'wf_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'wf_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&wf_name, wf_head->name_size);
+ z_realloc(&wf_text, wf_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialise the "t_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+static errr init_t_info(void)
+{
+ errr err = 0;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(t_head, header);
+
+ /* Save the "record" information */
+ t_head->info_num = max_t_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "t_name" and "t_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "t_info" array */
+ C_MAKE(t_info, t_head->info_num, trap_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(t_name, fake_name_size, char);
+ C_MAKE(t_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "tr_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'tr_info.txt' file.");
+
+ /* Parse the file */
+ err = init_t_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'tr_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'tr_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&t_name, t_head->name_size);
+ z_realloc(&t_text, t_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialise the "al_info" array
+ *
+ * Not a flat array, but an array none the less
+ */
+errr init_al_info(void)
+{
+ errr err;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(al_head, header);
+
+ /* Save the "record" information */
+ al_head->info_num = max_al_idx;
+
+
+
+
+ fake_text_size = FAKE_TEXT_SIZE;
+ fake_name_size = FAKE_NAME_SIZE;
+
+ /* Allocate the "al_info" array */
+ C_MAKE(alchemist_recipes, al_head->info_num, alchemist_recipe);
+
+ /* Allocate the fake arrays */
+ /* ok, so we fudge a bit, but
+ fake text size will ALWAYS be larger
+ than 32*5*sizeof(artifact_select_flag) = 10 int and 5 bytes
+ which is the maximum size of the a_select_flags array
+ */
+ C_MAKE(al_name, fake_name_size, char);
+
+ {
+ char *hack;
+ C_MAKE(hack, fake_text_size, char);
+ a_select_flags = (artifact_select_flag *) hack;
+ }
+
+ /*** Load the ascii template file ***/
+
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "al_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'al_info.txt' file.");
+
+ /* Parse the file */
+ err = init_al_info_txt(fp, buf);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'al_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'al_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&al_name, al_head->name_size);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialise the "v_info" array
+ *
+ * Note that we let each entry have a unique "name" and "text" string,
+ * even if the string happens to be empty (everyone has a unique '\0').
+ */
+errr init_v_info(void)
+{
+ errr err;
+
+ FILE *fp;
+
+ /* General buffer */
+ char buf[1024];
+
+
+ /*** Make the header ***/
+
+ /* Allocate the "header" */
+ MAKE(v_head, header);
+
+ /* Save the "record" information */
+ v_head->info_num = max_v_idx;
+
+
+ /*** Make the fake arrays ***/
+
+ /* Fake the size of "v_name" and "v_text" */
+ fake_name_size = FAKE_NAME_SIZE;
+ fake_text_size = FAKE_TEXT_SIZE;
+
+ /* Allocate the "k_info" array */
+ C_MAKE(v_info, v_head->info_num, vault_type);
+
+ /* Hack -- make "fake" arrays */
+ C_MAKE(v_name, fake_name_size, char);
+ C_MAKE(v_text, fake_text_size, char);
+
+
+ /*** Load the ascii template file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_EDIT, "v_info.txt");
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* Parse it */
+ if (!fp) quit("Cannot open 'v_info.txt' file.");
+
+ /* Parse the file */
+ err = init_v_info_txt(fp, buf, TRUE);
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Errors */
+ if (err)
+ {
+ cptr oops;
+
+ /* Error string */
+ oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");
+
+ /* Oops */
+ msg_format("Error %d at line %d of 'v_info.txt'.", err, error_line);
+ msg_format("Record %d contains a '%s' error.", error_idx, oops);
+ msg_format("Parsing '%s'.", buf);
+ msg_print(NULL);
+
+ /* Quit */
+ quit("Error in 'v_info.txt' file.");
+ }
+
+ /* Reduce sizes of the arrays */
+ z_realloc(&v_name, v_head->name_size);
+ z_realloc(&v_text, v_head->text_size);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Initialize the very basic arrays
+ */
+static void init_basic()
+{
+ int i;
+
+ /* Macro variables */
+ C_MAKE(macro__pat, MACRO_MAX, cptr);
+ C_MAKE(macro__act, MACRO_MAX, cptr);
+ C_MAKE(macro__cmd, MACRO_MAX, bool_);
+
+ /* Macro action buffer */
+ C_MAKE(macro__buf, 1024, char);
+
+ /* Extended trigger macros */
+ C_MAKE(cli_info, CLI_MAX, cli_comm);
+
+ /* Wipe the directory list */
+ for (i = 0; i < 255; i++)
+ {
+ scansubdir_result[i] = NULL;
+ }
+}
+
+/*
+ * Pseudo, dummy quest initializer, to actualy disable them
+ */
+static bool_ quest_disable_init_hook(int q_idx)
+{
+ q_idx = q_idx;
+ return FALSE;
+}
+
+
+/*
+ * Initialise misc. values
+ */
+static errr init_misc(void)
+{
+ int xstart = 0;
+ int ystart = 0;
+ int i;
+ s32b allow_quest;
+ s32b allow_rquest;
+
+ /*** Prepare the various "bizarre" arrays ***/
+
+ /* Quark variables */
+ C_MAKE(quark__str, QUARK_MAX, cptr);
+
+ /* Message variables */
+ C_MAKE(message__ptr, MESSAGE_MAX, u16b);
+ C_MAKE(message__color, MESSAGE_MAX, byte);
+ C_MAKE(message__type, MESSAGE_MAX, byte);
+ C_MAKE(message__count, MESSAGE_MAX, u16b);
+ C_MAKE(message__buf, MESSAGE_BUF, char);
+
+ /* Hack -- No messages yet */
+ message__tail = MESSAGE_BUF;
+
+ /* Prepare powers */
+ p_ptr->powers = NULL;
+ powers_type = NULL;
+ power_max = POWER_MAX_INIT;
+ reinit_powers_type(power_max);
+ C_COPY(powers_type, powers_type_init, POWER_MAX_INIT, power_type);
+
+ /* Prepare quests */
+ call_lua("get_module_info", "(s)", "d", "C_quest", &allow_quest);
+ call_lua("get_module_info", "(s)", "d", "rand_quest", &allow_rquest);
+
+ quest = NULL;
+ max_q_idx = MAX_Q_IDX_INIT;
+ reinit_quests(max_q_idx);
+
+ C_COPY(quest, quest_init_tome, MAX_Q_IDX_INIT, quest_type);
+
+ /* If we dont allow C quests, we dont let them init */
+ if (!allow_quest)
+ {
+ for (i = 0; i < MAX_Q_IDX_INIT; i++)
+ {
+ if (allow_rquest && (i == QUEST_RANDOM))
+ continue;
+ quest[i].init = quest_disable_init_hook;
+ }
+ }
+
+ /* Prepare gods */
+ deity_info = NULL;
+ max_gods = MAX_GODS_INIT;
+ reinit_gods(max_gods);
+
+ C_COPY(deity_info, deity_info_init, MAX_GODS_INIT, deity_type);
+
+ /* Prepare schools */
+ max_spells = 0;
+ max_schools = 0;
+ schools = NULL;
+ school_spells = NULL;
+
+ process_hooks(HOOK_INIT_GAME, "(s)", "begin");
+
+ /* Initialise the values */
+ process_dungeon_file("misc.txt", &ystart, &xstart, 0, 0, TRUE, FALSE);
+
+ /* Init the spell effects */
+ for (i = 0; i < MAX_EFFECTS; i++)
+ effects[i].time = 0;
+
+ return 0;
+}
+
+
+/*
+ * Initialise town array
+ */
+static errr init_towns(void)
+{
+ int i = 0, j = 0;
+
+ /*** Prepare the Towns ***/
+
+ /* Allocate the towns */
+ C_MAKE(town_info, max_towns, town_type);
+
+ for (i = 1; i < max_towns; i++)
+ {
+ if (i <= max_real_towns) town_info[i].flags |= (TOWN_REAL);
+
+ /* Allocate the stores */
+ C_MAKE(town_info[i].store, max_st_idx, store_type);
+
+ /* Fill in each store */
+ for (j = 0; j < max_st_idx; j++)
+ {
+ /* Access the store */
+ store_type *st_ptr = &town_info[i].store[j];
+
+ /* Know who we are */
+ st_ptr->st_idx = j;
+
+ /* Assume full stock */
+ st_ptr->stock_size = 0;
+ }
+ }
+ return 0;
+}
+
+void create_stores_stock(int t)
+{
+ int j;
+ town_type *t_ptr = &town_info[t];
+
+ if (t_ptr->stocked) return;
+
+ for (j = 0; j < max_st_idx; j++)
+ {
+ store_type *st_ptr = &t_ptr->store[j];
+
+ /* Assume full stock */
+ st_ptr->stock_size = st_info[j].max_obj;
+
+ /* Allocate the stock */
+ C_MAKE(st_ptr->stock, st_ptr->stock_size, object_type);
+ }
+ t_ptr->stocked = TRUE;
+}
+
+/*
+ * Pointer to wilderness_map
+ */
+typedef wilderness_map *wilderness_map_ptr;
+
+/*
+ * Initialise wilderness map array
+ */
+static errr init_wilderness(void)
+{
+ int i;
+
+ /* Allocate the wilderness (two-dimension array) */
+ C_MAKE(wild_map, max_wild_y, wilderness_map_ptr);
+ C_MAKE(wild_map[0], max_wild_x * max_wild_y, wilderness_map);
+
+ /* Init the other pointers */
+ for (i = 1; i < max_wild_y; i++)
+ wild_map[i] = wild_map[0] + i * max_wild_x;
+
+ /* No encounter right now */
+ generate_encounter = FALSE;
+
+ return 0;
+}
+
+/*
+ * XXX XXX XXX XXX XXX Realloc is not guaranteed to work (see main-gtk.c
+ * and main-mac.c.
+ */
+void reinit_powers_type(s16b new_size)
+{
+ power_type *new_powers_type;
+ bool_ *new_powers;
+
+ C_MAKE(new_powers_type, new_size, power_type);
+ C_MAKE(new_powers, new_size, bool_);
+
+ /* Reallocate the extra memory */
+ if (powers_type && p_ptr->powers)
+ {
+ C_COPY(new_powers_type, powers_type, power_max, power_type);
+ C_COPY(new_powers, p_ptr->powers, power_max, bool_);
+
+ C_FREE(powers_type, power_max, power_type);
+ C_FREE(p_ptr->powers, power_max, bool_);
+ }
+
+ powers_type = new_powers_type;
+ p_ptr->powers = new_powers;
+
+ power_max = new_size;
+}
+
+void reinit_quests(s16b new_size)
+{
+ quest_type *new_quest;
+
+ C_MAKE(new_quest, new_size, quest_type);
+
+ /* Reallocate the extra memory */
+ if (quest)
+ {
+ C_COPY(new_quest, quest, max_q_idx, quest_type);
+
+ C_FREE(quest, max_q_idx, quest_type);
+ }
+
+ quest = new_quest;
+
+ max_q_idx = new_size;
+}
+
+void reinit_gods(s16b new_size)
+{
+ deity_type *new_deity;
+
+ C_MAKE(new_deity, new_size, deity_type);
+
+ /* Reallocate the extra memory */
+ if (deity_info)
+ {
+ C_COPY(new_deity, deity_info, max_gods, deity_type);
+
+ C_FREE(deity_info, max_gods, deity_type);
+ }
+
+ deity_info = new_deity;
+
+ max_gods = new_size;
+}
+
+void init_spells(s16b new_size)
+{
+ /* allocate the extra memory */
+ C_MAKE(school_spells, new_size, spell_type);
+ max_spells = new_size;
+}
+
+void init_schools(s16b new_size)
+{
+ /* allocate the extra memory */
+ C_MAKE(schools, new_size, school_type);
+ max_schools = new_size;
+}
+
+void init_corruptions(s16b new_size)
+{
+ /* allocate the extra memory */
+ C_MAKE(p_ptr->corruptions, new_size, bool_);
+ max_corruptions = new_size;
+}
+
+/*
+ * Initialise some other arrays
+ */
+static errr init_other(void)
+{
+ int i, n;
+
+ /*** Prepare the "dungeon" information ***/
+
+ /* Allocate and Wipe the special gene flags */
+ C_MAKE(m_allow_special, max_r_idx, bool_);
+ C_MAKE(k_allow_special, max_k_idx, bool_);
+ C_MAKE(a_allow_special, max_a_idx, bool_);
+
+
+ /*** Prepare "vinfo" array ***/
+
+ /* Used by "update_view()" */
+ (void)vinfo_init();
+
+
+ /* Allocate and Wipe the object list */
+ C_MAKE(o_list, max_o_idx, object_type);
+
+ /* Allocate and Wipe the monster list */
+ C_MAKE(m_list, max_m_idx, monster_type);
+
+ /* Allocate and Wipe the to keep monster list */
+ C_MAKE(km_list, max_m_idx, monster_type);
+
+ /* Allocate and Wipe the max dungeon level */
+ C_MAKE(max_dlv, max_d_idx, s16b);
+
+ /* Allocate and Wipe the special levels */
+ for (i = 0; i < MAX_DUNGEON_DEPTH; i++)
+ {
+ C_MAKE(special_lvl[i], max_d_idx, bool_);
+ }
+
+ /* Allocate and wipe each line of the cave */
+ for (i = 0; i < MAX_HGT; i++)
+ {
+ /* Allocate one row of the cave */
+ C_MAKE(cave[i], MAX_WID, cave_type);
+ }
+
+ /*** Pre-allocate the basic "auto-inscriptions" ***/
+
+ /* The "basic" feelings */
+ (void)quark_add("cursed");
+ (void)quark_add("broken");
+ (void)quark_add("average");
+ (void)quark_add("good");
+
+ /* The "extra" feelings */
+ (void)quark_add("excellent");
+ (void)quark_add("worthless");
+ (void)quark_add("special");
+ (void)quark_add("terrible");
+
+ /* Some extra strings */
+ (void)quark_add("uncursed");
+ (void)quark_add("on sale");
+
+
+ /*** Prepare the options ***/
+
+ /* Scan the options */
+ for (i = 0; option_info[i].o_desc; i++)
+ {
+ int os = option_info[i].o_page;
+ int ob = option_info[i].o_bit;
+
+ /* Set the "default" options */
+ if (option_info[i].o_var)
+ {
+ /* Accept */
+ option_mask[os] |= (1L << ob);
+
+ /* Set */
+ if (option_info[i].o_norm)
+ {
+ /* Set */
+ option_flag[os] |= (1L << ob);
+ }
+
+ /* Clear */
+ else
+ {
+ /* Clear */
+ option_flag[os] &= ~(1L << ob);
+ }
+ }
+ }
+
+ /* Analyze the windows */
+ for (n = 0; n < 8; n++)
+ {
+ /* Analyze the options */
+ for (i = 0; i < 32; i++)
+ {
+ /* Accept */
+ if (window_flag_desc[i])
+ {
+ /* Accept */
+ window_mask[n] |= (1L << i);
+ }
+ }
+ }
+
+
+ /*
+ * Install the various level generators
+ */
+ add_level_generator("dungeon", level_generate_dungeon, TRUE, TRUE, TRUE, TRUE);
+ add_level_generator("maze", level_generate_maze, TRUE, TRUE, TRUE, TRUE);
+ add_level_generator("life", level_generate_life, TRUE, TRUE, TRUE, TRUE);
+
+ /*** Pre-allocate space for the "format()" buffer ***/
+
+ /* Hack -- Just call the "format()" function */
+ (void)format("%s (%s).", "Dark God <darkgod@t-o-m-e.net>", MAINTAINER);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Initialise some other arrays
+ */
+static errr init_alloc(void)
+{
+ int i, j;
+
+ object_kind *k_ptr;
+
+ monster_race *r_ptr;
+
+ alloc_entry *table;
+
+ s16b num[MAX_DEPTH_MONSTER];
+
+ s16b aux[MAX_DEPTH_MONSTER];
+
+ /*** Analyze object allocation info ***/
+
+ /* Clear the "aux" array */
+ C_WIPE(&aux, MAX_DEPTH_MONSTER, s16b);
+
+ /* Clear the "num" array */
+ C_WIPE(&num, MAX_DEPTH_MONSTER, s16b);
+
+ /* Size of "alloc_kind_table" */
+ alloc_kind_size = 0;
+
+ /* Scan the objects */
+ for (i = 1; i < max_k_idx; i++)
+ {
+ k_ptr = &k_info[i];
+
+ /* Scan allocation pairs */
+ for (j = 0; j < 4; j++)
+ {
+ /* Count the "legal" entries */
+ if (k_ptr->chance[j])
+ {
+ /* Count the entries */
+ alloc_kind_size++;
+
+ /* Group by level */
+ num[k_ptr->locale[j]]++;
+ }
+ }
+ }
+
+ /* Collect the level indexes */
+ for (i = 1; i < MAX_DEPTH_MONSTER; i++)
+ {
+ /* Group by level */
+ num[i] += num[i - 1];
+ }
+
+ /* Paranoia */
+ if (!num[0]) quit("No town objects!");
+
+
+ /*** Initialise object allocation info ***/
+
+ /* Allocate the alloc_kind_table */
+ C_MAKE(alloc_kind_table, alloc_kind_size, alloc_entry);
+
+ /* Access the table entry */
+ table = alloc_kind_table;
+
+ /* Scan the objects */
+ for (i = 1; i < max_k_idx; i++)
+ {
+ k_ptr = &k_info[i];
+
+ /* Scan allocation pairs */
+ for (j = 0; j < 4; j++)
+ {
+ /* Count the "legal" entries */
+ if (k_ptr->chance[j])
+ {
+ int p, x, y, z;
+
+ /* Extract the base level */
+ x = k_ptr->locale[j];
+
+ /* Extract the base probability */
+ p = (100 / k_ptr->chance[j]);
+
+ /* Skip entries preceding our locale */
+ y = (x > 0) ? num[x - 1] : 0;
+
+ /* Skip previous entries at this locale */
+ z = y + aux[x];
+
+ /* Load the entry */
+ table[z].index = i;
+ table[z].level = x;
+ table[z].prob1 = p;
+ table[z].prob2 = p;
+ table[z].prob3 = p;
+
+ /* Another entry complete for this locale */
+ aux[x]++;
+ }
+ }
+ }
+
+
+ /*** Analyze monster allocation info ***/
+
+ /* Clear the "aux" array */
+ C_WIPE(&aux, MAX_DEPTH_MONSTER, s16b);
+
+ /* Clear the "num" array */
+ C_WIPE(&num, MAX_DEPTH_MONSTER, s16b);
+
+ /* Size of "alloc_race_table" */
+ alloc_race_size = 0;
+
+ /* Scan the monsters */
+ for (i = 1; i < max_r_idx; i++)
+ {
+ /* Get the i'th race */
+ r_ptr = &r_info[i];
+
+ /* Legal monsters */
+ if (r_ptr->rarity)
+ {
+ /* Count the entries */
+ alloc_race_size++;
+
+ /* Group by level */
+ num[r_ptr->level]++;
+ }
+ }
+
+ /* Collect the level indexes */
+ for (i = 1; i < MAX_DEPTH_MONSTER; i++)
+ {
+ /* Group by level */
+ num[i] += num[i - 1];
+ }
+
+ /* Paranoia */
+ if (!num[0]) quit("No town monsters!");
+
+
+ /*** Initialise monster allocation info ***/
+
+ /* Allocate the alloc_race_table */
+ C_MAKE(alloc_race_table, alloc_race_size, alloc_entry);
+
+ /* Access the table entry */
+ table = alloc_race_table;
+
+ /* Scan the monsters */
+ for (i = 1; i < max_r_idx; i++)
+ {
+ /* Get the i'th race */
+ r_ptr = &r_info[i];
+
+ /* Count valid pairs */
+ if (r_ptr->rarity)
+ {
+ int p, x, y, z;
+
+ /* Extract the base level */
+ x = r_ptr->level;
+
+ /* Extract the base probability */
+ p = (100 / r_ptr->rarity);
+
+ /* Skip entries preceding our locale */
+ y = (x > 0) ? num[x - 1] : 0;
+
+ /* Skip previous entries at this locale */
+ z = y + aux[x];
+
+ /* Load the entry */
+ table[z].index = i;
+ table[z].level = x;
+ table[z].prob1 = p;
+ table[z].prob2 = p;
+ table[z].prob3 = p;
+
+ /* Another entry complete for this locale */
+ aux[x]++;
+ }
+ }
+
+
+ /* Success */
+ return (0);
+}
+
+/* Init the sets in a_info */
+void init_sets_aux()
+{
+ int i, j;
+
+ for (i = 0; i < max_a_idx; i++)
+ a_info[i].set = -1;
+ for (i = 0; i < max_set_idx; i++)
+ {
+ for (j = 0; j < set_info[i].num; j++)
+ {
+ a_info[set_info[i].arts[j].a_idx].set = i;
+ }
+ }
+}
+
+/*
+ * Mark guardians and their artifacts with SPECIAL_GENE flag
+ */
+static void init_guardians(void)
+{
+ int i;
+
+ /* Scan dungeons */
+ for (i = 0; i < max_d_idx; i++)
+ {
+ dungeon_info_type *d_ptr = &d_info[i];
+
+ /* Mark the guadian monster */
+ if (d_ptr->final_guardian)
+ {
+ monster_race *r_ptr = &r_info[d_ptr->final_guardian];
+
+ r_ptr->flags9 |= RF9_SPECIAL_GENE;
+
+ /* Mark the final artifact */
+ if (d_ptr->final_artifact)
+ {
+ artifact_type *a_ptr = &a_info[d_ptr->final_artifact];
+
+ a_ptr->flags4 |= TR4_SPECIAL_GENE;
+ }
+
+ /* Mark the final object */
+ if (d_ptr->final_object)
+ {
+ object_kind *k_ptr = &k_info[d_ptr->final_object];
+
+ k_ptr->flags4 |= TR4_SPECIAL_GENE;
+ }
+
+ /* Give randart if there are no final artifacts */
+ if (!(d_ptr->final_artifact) && !(d_ptr->final_object))
+ {
+ r_ptr->flags7 |= RF7_DROP_RANDART;
+ }
+ }
+ }
+}
+
+/*
+ * Hack -- Explain a broken "lib" folder and quit (see below).
+ *
+ * XXX XXX XXX This function is "messy" because various things
+ * may or may not be initialised, but the "plog()" and "quit()"
+ * functions are "supposed" to work under any conditions.
+ */
+static void init_angband_aux(cptr why)
+{
+ /* Why */
+ plog(why);
+
+ /* Explain */
+ plog("The 'lib' directory is probably missing or broken.");
+
+ /* More details */
+ plog("Perhaps the archive was not extracted correctly.");
+
+ /* Explain */
+ plog("See the 'README' file for more information.");
+
+ /* Quit with error */
+ quit("Fatal Error.");
+}
+
+/*
+ * Hack -- main Angband initialisation entry point
+ *
+ * Verify some files, display the "news.txt" file, create
+ * the high score file, initialise all internal arrays, and
+ * load the basic "user pref files".
+ *
+ * Note that we blindly assume that "news2.txt" exists. XXX
+ *
+ * Be very careful to keep track of the order in which things
+ * are initialised, in particular, the only thing *known* to
+ * be available when this function is called is the "z-term.c"
+ * package, and that may not be fully initialised until the
+ * end of this function, when the default "user pref files"
+ * are loaded and "Term_xtra(TERM_XTRA_REACT,0)" is called.
+ *
+ * Note that this function attempts to verify the "news" file,
+ * and the game aborts (cleanly) on failure, since without the
+ * "news" file, it is likely that the "lib" folder has not been
+ * correctly located. Otherwise, the news file is displayed for
+ * the user.
+ *
+ * Note that this function attempts to verify (or create) the
+ * "high score" file, and the game aborts (cleanly) on failure,
+ * since one of the most common "extraction" failures involves
+ * failing to extract all sub-directories (even empty ones), such
+ * as by failing to use the "-d" option of "pkunzip", or failing
+ * to use the "save empty directories" option with "Compact Pro".
+ * This error will often be caught by the "high score" creation
+ * code below, since the "lib/apex" directory, being empty in the
+ * standard distributions, is most likely to be "lost", making it
+ * impossible to create the high score file.
+ *
+ * Note that various things are initialised by this function,
+ * including everything that was once done by "init_some_arrays".
+ *
+ * This initialisation involves the parsing of special files
+ * in the "lib/data" and sometimes the "lib/edit" directories.
+ *
+ * Note that the "template" files are initialised first, since they
+ * often contain errors. This means that macros and message recall
+ * and things like that are not available until after they are done.
+ *
+ * We load the default "user pref files" here in case any "color"
+ * changes are needed before character creation.
+ *
+ * Note that the "graf-xxx.prf" file must be loaded separately,
+ * if needed, in the first (?) pass through "TERM_XTRA_REACT".
+ */
+void init_angband(void)
+{
+ int fd = -1;
+
+ int mode = FILE_MODE;
+
+ FILE *fp;
+
+ char *news_file;
+
+ char buf[1024];
+
+ /* Init some VERY basic stuff, like macro arrays */
+ init_basic();
+
+ /* Select & init a module if needed */
+ select_module();
+
+ /*** Choose which news.txt file to use ***/
+
+ /* Choose the news file */
+ switch (time(NULL) % 2)
+ {
+ default:
+ {
+ news_file = "news.txt";
+ break;
+ }
+
+ case 0:
+ {
+ news_file = "news2.txt";
+ break;
+ }
+ }
+
+ /*** Verify the "news" file ***/
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, news_file);
+
+ /* Attempt to open the file */
+ fd = fd_open(buf, O_RDONLY);
+
+ /* Failure */
+ if (fd < 0)
+ {
+ char why[1024];
+
+ /* Message */
+ sprintf(why, "Cannot access the '%s' file!", buf);
+
+ /* Crash and burn */
+ init_angband_aux(why);
+ }
+
+ /* Close it */
+ (void)fd_close(fd);
+
+
+ /*** Display the "news" file ***/
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, news_file);
+
+ /* Open the News file */
+ fp = my_fopen(buf, "r");
+
+ /* Dump */
+ if (fp)
+ {
+ int i = 0;
+
+ /* Dump the file to the screen */
+ while (0 == my_fgets(fp, buf, 1024))
+ {
+ /* Display and advance - we use display_message to parse colour codes XXX */
+ display_message(0, i++, strlen(buf), TERM_WHITE, buf);
+ }
+
+ /* Close */
+ my_fclose(fp);
+ }
+
+ /* Flush it */
+ Term_fresh();
+
+
+ /*** Verify (or create) the "high score" file ***/
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
+
+ /* Attempt to open the high score file */
+ fd = fd_open(buf, O_RDONLY);
+
+ /* Failure */
+ if (fd < 0)
+ {
+ /* File type is "DATA" */
+ FILE_TYPE(FILE_TYPE_DATA);
+
+ /* Create a new high score file */
+ fd = fd_make(buf, mode);
+
+ /* Failure */
+ if (fd < 0)
+ {
+ char why[1024];
+
+ /* Message */
+ sprintf(why, "Cannot create the '%s' file!", buf);
+
+ /* Crash and burn */
+ init_angband_aux(why);
+ }
+ }
+
+ /* Close it */
+ (void)fd_close(fd);
+
+
+ /*** Initialise some arrays ***/
+
+ /* Initialise misc. values */
+ note("[Initialising values... (misc)]");
+ if (init_misc()) quit("Cannot initialise misc. values");
+
+ wipe_hooks();
+
+ /* Initialise some other arrays */
+ note("[Initialising lua scripting... (lua)]");
+ init_lua();
+ init_lua_init();
+
+ /* Initialise skills info */
+ note("[Initialising arrays... (skills)]");
+ if (init_s_info()) quit("Cannot initialise skills");
+
+ /* Initialise abilities info */
+ note("[Initialising arrays... (abilities)]");
+ if (init_ab_info()) quit("Cannot initialise abilities");
+
+ /* Initialise alchemy info */
+ note("[Initialising arrays... (alchemy)]");
+ if (init_al_info()) quit("Cannot initialise alchemy");
+
+ /* Initialise player info */
+ note("[Initialising arrays... (players)]");
+ if (init_player_info()) quit("Cannot initialise players");
+
+ /* Initialise feature info */
+ note("[Initialising arrays... (features)]");
+ if (init_f_info()) quit("Cannot initialise features");
+
+ /* Initialise object info */
+ note("[Initialising arrays... (objects)]");
+ if (init_k_info()) quit("Cannot initialise objects");
+
+ /* Initialise artifact info */
+ note("[Initialising arrays... (artifacts)]");
+ if (init_a_info()) quit("Cannot initialise artifacts");
+
+ /* Initialise set info */
+ note("[Initialising item sets... (sets)]");
+ if (init_set_info()) quit("Cannot initialise item sets");
+ init_sets_aux();
+
+ /* Initialise ego-item info */
+ note("[Initialising arrays... (ego-items)]");
+ if (init_e_info()) quit("Cannot initialise ego-items");
+
+ /* Initialise randart parts info */
+ note("[Initialising arrays... (randarts)]");
+ if (init_ra_info()) quit("Cannot initialise randarts");
+
+ /* Initialise monster info */
+ note("[Initialising arrays... (monsters)]");
+ if (init_r_info()) quit("Cannot initialise monsters");
+
+ /* Initialise ego monster info */
+ note("[Initialising arrays... (ego monsters)]");
+ if (init_re_info()) quit("Cannot initialise ego monsters");
+
+ /* Initialise dungeon type info */
+ note("[Initialising arrays... (dungeon types)]");
+ if (init_d_info()) quit("Cannot initialise dungeon types");
+ init_guardians();
+
+ /* Initialise actions type info */
+ note("[Initialising arrays... (action types)]");
+ if (init_ba_info()) quit("Cannot initialise action types");
+
+ /* Initialise owners type info */
+ note("[Initialising arrays... (owners types)]");
+ if (init_ow_info()) quit("Cannot initialise owners types");
+
+ /* Initialise stores type info */
+ note("[Initialising arrays... (stores types)]");
+ if (init_st_info()) quit("Cannot initialise stores types");
+
+ /* Initialise wilderness features array */
+ note("[Initialising arrays... (wilderness features)]");
+ if (init_wf_info()) quit("Cannot initialise wilderness features");
+
+ /* Initialise wilderness map array */
+ note("[Initialising arrays... (wilderness map)]");
+ if (init_wilderness()) quit("Cannot initialise wilderness map");
+
+ /* Initialise town array */
+ note("[Initialising arrays... (towns)]");
+ if (init_towns()) quit("Cannot initialise towns");
+
+ /* Initialise trap info */
+ note("[Initialising arrays... (traps)]");
+ if (init_t_info()) quit("Cannot initialise traps");
+
+ /* Initialise some other arrays */
+ note("[Initialising arrays... (other)]");
+ if (init_other()) quit("Cannot initialise other stuff");
+
+ /* Initialise some other arrays */
+ note("[Initialising arrays... (alloc)]");
+ if (init_alloc()) quit("Cannot initialise alloc stuff");
+
+ /* Init random artifact names */
+ build_prob(artifact_names_list);
+
+ /*** Load default user pref files ***/
+
+ /* Initialise feature info */
+ note("[Initialising user pref files...]");
+
+ /* Access the "basic" pref file */
+ strcpy(buf, "pref.prf");
+
+ /* Process that file */
+ process_pref_file(buf);
+
+ /* Access the "basic" system pref file */
+ sprintf(buf, "pref-%s.prf", ANGBAND_SYS);
+
+ /* Process that file */
+ process_pref_file(buf);
+
+ /* Access the "user" pref file */
+ sprintf(buf, "user.prf");
+
+ /* Process that file */
+ process_pref_file(buf);
+
+ /* Access the "user" system pref file */
+ sprintf(buf, "user-%s.prf", ANGBAND_SYS);
+
+ /* Process that file */
+ process_pref_file(buf);
+
+ /* Initialise the automatizer */
+ tome_dofile_anywhere(ANGBAND_DIR_CORE, "auto.lua", TRUE);
+ tome_dofile_anywhere(ANGBAND_DIR_USER, "automat.atm", FALSE);
+
+ /* Done */
+ note("[Initialisation complete]");
+
+ process_hooks(HOOK_INIT_GAME, "(s)", "end");
+}
diff --git a/src/iso/.cvsignore b/src/iso/.cvsignore
new file mode 100644
index 00000000..f8d9fd47
--- /dev/null
+++ b/src/iso/.cvsignore
@@ -0,0 +1 @@
+.sconsign
diff --git a/src/lauxlib.h b/src/lauxlib.h
new file mode 100644
index 00000000..8b6db343
--- /dev/null
+++ b/src/lauxlib.h
@@ -0,0 +1,100 @@
+/*
+** $Id: lauxlib.h,v 1.4 2002/01/04 03:31:23 pelpel Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_h
+#define lauxlib_h
+
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "lua.h"
+
+
+#ifndef LUALIB_API
+#define LUALIB_API extern
+#endif
+
+
+struct luaL_reg {
+ const char *name;
+ lua_CFunction func;
+};
+
+
+LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n);
+LUALIB_API void luaL_argerror (lua_State *L, int numarg, const char *extramsg);
+LUALIB_API const char *luaL_check_lstr (lua_State *L, int numArg, size_t *len);
+LUALIB_API const char *luaL_opt_lstr (lua_State *L, int numArg, const char *def, size_t *len);
+LUALIB_API long luaL_check_number (lua_State *L, int numArg);
+LUALIB_API long luaL_opt_number (lua_State *L, int numArg, long def);
+
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg);
+LUALIB_API void luaL_checktype (lua_State *L, int narg, int t);
+LUALIB_API void luaL_checkany (lua_State *L, int narg);
+
+LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...);
+LUALIB_API int luaL_findstring (const char *name, const char *const list[]);
+
+
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define luaL_arg_check(L, cond,numarg,extramsg) if (!(cond)) \
+ luaL_argerror(L, numarg,extramsg)
+#define luaL_check_string(L,n) (luaL_check_lstr(L, (n), NULL))
+#define luaL_opt_string(L,n,d) (luaL_opt_lstr(L, (n), (d), NULL))
+#define luaL_check_int(L,n) ((int)luaL_check_number(L, n))
+#define luaL_check_long(L,n) ((long)luaL_check_number(L, n))
+#define luaL_opt_int(L,n,d) ((int)luaL_opt_number(L, n,d))
+#define luaL_opt_long(L,n,d) ((long)luaL_opt_number(L, n,d))
+#define luaL_openl(L,a) luaL_openlib(L, a, (sizeof(a)/sizeof(a[0])))
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+
+#ifndef LUAL_BUFFERSIZE
+#define LUAL_BUFFERSIZE BUFSIZ
+#endif
+
+
+typedef struct luaL_Buffer {
+ char *p; /* current position in buffer */
+ int level;
+ lua_State *L;
+ char buffer[LUAL_BUFFERSIZE];
+} luaL_Buffer;
+
+#define luaL_putchar(B,c) \
+ ((void)((B)->p < &(B)->buffer[LUAL_BUFFERSIZE] || luaL_prepbuffer(B)), \
+ (*(B)->p++ = (char)(c)))
+
+#define luaL_addsize(B,n) ((B)->p += (n))
+
+LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B);
+LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s);
+LUALIB_API void luaL_addvalue (luaL_Buffer *B);
+LUALIB_API void luaL_pushresult (luaL_Buffer *B);
+
+
+/* }====================================================== */
+
+
+#endif
+
+
diff --git a/src/levels.c b/src/levels.c
new file mode 100644
index 00000000..71148fc5
--- /dev/null
+++ b/src/levels.c
@@ -0,0 +1,234 @@
+/* File: levels.c */
+
+/* Purpose: Levels functions */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Return the parameter of the given command in the given file
+ */
+static int start_line = 0;
+bool_ get_command(const char *file, char comm, char *param)
+{
+ char buf[1024];
+ int i = -1;
+ FILE *fp;
+ char *s;
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_DNGN, file);
+
+ /* Open the file */
+ fp = my_fopen(buf, "r");
+
+ /* The file exists ? */
+ /* no ? then command not found */
+ if (!fp) return FALSE;
+
+ /* Parse to the end of the file or when the command is found */
+ while (0 == my_fgets(fp, buf, 1024))
+ {
+ /* Advance the line number */
+ i++;
+
+ /* Skip comments and blank lines */
+ if (!buf[0] || (buf[0] == '#')) continue;
+
+ /* Is it the command we are looking for ? */
+ if ((i > start_line) && (buf[0] == comm))
+ {
+ /* Acquire the text */
+ s = buf + 2;
+
+ start_line = i;
+
+ /* Get the parameter */
+ strcpy(param, s);
+
+ /* Close it */
+ my_fclose(fp);
+
+ return TRUE;
+ }
+
+ }
+
+ /* Close it */
+ my_fclose(fp);
+
+ /* Assume command not found */
+ return FALSE;
+}
+
+
+/*
+ * Return the dungeon branch starting form the current dungeon/level
+ */
+int get_branch()
+{
+ char file[20], buf[5];
+
+ sprintf(file, "dun%d.%d", dungeon_type, dun_level - d_info[dungeon_type].mindepth);
+
+ /* Get and return the branch */
+ start_line = -1;
+ if (get_command(file, 'B', buf)) return (atoi(buf));
+
+ /* No branch ? return 0 */
+ else return 0;
+}
+
+/*
+ * Return the father dungeon branch
+ */
+int get_fbranch()
+{
+ char file[20], buf[5];
+
+ sprintf(file, "dun%d.%d", dungeon_type, dun_level - d_info[dungeon_type].mindepth);
+
+ /* Get and return the branch */
+ start_line = -1;
+ if (get_command(file, 'A', buf)) return (atoi(buf));
+
+ /* No branch ? return 0 */
+ else return 0;
+}
+
+/*
+ * Return the father dungeon level
+ */
+int get_flevel()
+{
+ char file[20], buf[5];
+
+ sprintf(file, "dun%d.%d", dungeon_type, dun_level - d_info[dungeon_type].mindepth);
+
+ /* Get and return the level */
+ start_line = -1;
+ if (get_command(file, 'L', buf)) return (atoi(buf));
+
+ /* No level ? return 0 */
+ else return 0;
+}
+
+/*
+ * Return the extension of the savefile for the level
+ */
+bool_ get_dungeon_save(char *buf)
+{
+ char file[20];
+
+ sprintf(file, "dun%d.%d", dungeon_type, dun_level - d_info[dungeon_type].mindepth);
+
+ /* Get and return the level */
+ start_line = -1;
+ if (get_command(file, 'S', buf)) return (TRUE);
+ else return FALSE;
+}
+
+/*
+ * Return the level generator
+ */
+bool_ get_dungeon_generator(char *buf)
+{
+ char file[20];
+
+ sprintf(file, "dun%d.%d", dungeon_type, dun_level - d_info[dungeon_type].mindepth);
+
+ /* Get and return the level */
+ start_line = -1;
+ if (get_command(file, 'G', buf)) return (TRUE);
+ else return FALSE;
+}
+
+/*
+ * Return the special level
+ */
+bool_ get_dungeon_special(char *buf)
+{
+ char file[20];
+
+ sprintf(file, "dun%d.%d", dungeon_type, dun_level - d_info[dungeon_type].mindepth);
+
+ /* Get and return the level */
+ start_line = -1;
+ if (get_command(file, 'U', buf)) return (TRUE);
+ else return FALSE;
+}
+
+/*
+ * Return the special level name
+ */
+bool_ get_dungeon_name(char *buf)
+{
+ char file[20];
+
+ sprintf(file, "dun%d.%d", dungeon_type, dun_level - d_info[dungeon_type].mindepth);
+
+ /* Get and return the level */
+ start_line = -1;
+ if (get_command(file, 'N', buf)) return (TRUE);
+ else return FALSE;
+}
+
+/*
+ * Return the special level name
+ */
+void get_level_flags()
+{
+ char file[20];
+ char buf[1024], *s, *t;
+
+ sprintf(file, "dun%d.%d", dungeon_type, dun_level - d_info[dungeon_type].mindepth);
+
+ start_line = -1;
+
+ /* Parse until done */
+ while (get_command(file, 'F', buf))
+ {
+ /* Parse every entry textually */
+ for (s = buf; *s; )
+ {
+ /* Find the end of this entry */
+ for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) /* loop */;
+
+ /* Nuke and skip any dividers */
+ if (*t)
+ {
+ *t++ = '\0';
+ while (*t == ' ' || *t == '|') t++;
+ }
+
+ /* Parse this entry */
+ if (0 != grab_one_dungeon_flag(&dungeon_flags1, &dungeon_flags2, s)) return;
+
+ /* Start the next entry */
+ s = t;
+ }
+ }
+}
+
+/*
+ * Return the special level desc
+ */
+bool_ get_level_desc(char *buf)
+{
+ char file[20];
+
+ sprintf(file, "dun%d.%d", dungeon_type, dun_level - d_info[dungeon_type].mindepth);
+
+ /* Get and return the level */
+ start_line = -1;
+ if (get_command(file, 'D', buf)) return (TRUE);
+ else return FALSE;
+}
diff --git a/src/loadsave.c b/src/loadsave.c
new file mode 100644
index 00000000..8cdb9f72
--- /dev/null
+++ b/src/loadsave.c
@@ -0,0 +1,3288 @@
+/* File: loadsave.c */
+
+/* Purpose: interact with savefiles. This file was made by
+ unifying load2.c and save.c from the old codebase. Doing it
+ this way makes maintenance easier and lets us share code. */
+
+#include "angband.h"
+
+static void do_byte(byte *, int);
+static void do_u16b(u16b *, int);
+static void do_s16b(s16b *, int);
+static void do_u32b(u32b *, int);
+static void do_s32b(s32b *, int);
+static void do_string(char *, int, int);
+static void do_lore(int, int);
+static void do_monster(monster_type *, int);
+static void do_randomizer(int flag);
+static void do_spells(int, int);
+static void note(cptr);
+static void do_fate(int, int);
+static void do_item(object_type *, int);
+static void do_options(int);
+static bool_ do_store(store_type *, int);
+static void do_messages(int flag);
+static void do_xtra(int, int);
+static bool_ do_savefile_aux(int);
+static void junkinit(void);
+static void morejunk(void);
+static bool_ do_inventory(int);
+static bool_ do_dungeon(int, bool_);
+static void do_grid(int);
+static void my_sentinel(char *, u16b, int);
+
+static void do_ver_s16b(s16b *, u32b, s16b, int);
+
+static void skip_ver_byte(u32b, int);
+
+errr rd_savefile(void);
+
+static FILE *fff; /* Local savefile ptr */
+
+/*
+ * Basic byte-level reading from savefile. This provides a single point
+ * of interface to the pseudoencryption that ToME (and Angband)
+ * uses. I'm thinking about if it might be faster/better to modify all
+ * the do_* functions to directly do this stuff -- it'd make the code
+ * somewhat uglier to maintain, but concievably might be much faster. Or
+ * is it better maybe to scrap the pseudoencryption entirely and adopt
+ * some other means of obfuscation, should it still prove useful in any
+ * way? -- Improv
+ *
+ * What's the point of encryption on savefiles anyway? If I wanted to
+ * make a cheater savefile, I'd activate debug mode, and hack the game
+ * not to save it. There's no point. -- takkaria
+ */
+
+static byte sf_get(void)
+{
+ byte c;
+
+ /* Get a character, decode the value */
+ c = getc(fff) & 0xFF;
+
+ /* Return the value */
+ return (c);
+}
+
+
+static void sf_put(byte v)
+{
+ (void)putc((int)v, fff);
+}
+
+/*
+ * Do object memory and similar stuff
+ */
+static void do_xtra(int k_idx, int flag)
+{
+ byte tmp8u = 0;
+ object_kind *k_ptr = &k_info[k_idx];
+
+ if (flag == LS_SAVE)
+ {
+ if (k_ptr->aware) tmp8u |= 0x01;
+ if (k_ptr->tried) tmp8u |= 0x02;
+ if (k_ptr->know) tmp8u |= 0x04;
+ if (k_ptr->artifact) tmp8u |= 0x80;
+
+ do_byte(&tmp8u, flag);
+ }
+ if (flag == LS_LOAD)
+ {
+ do_byte(&tmp8u, flag);
+ k_ptr->aware = ((tmp8u & 0x01) ? TRUE : FALSE);
+ k_ptr->tried = ((tmp8u & 0x02) ? TRUE : FALSE);
+ k_ptr->know = ((tmp8u & 0x04) ? TRUE : FALSE);
+ k_ptr->artifact = ((tmp8u & 0x80) ? TRUE : FALSE);
+ }
+}
+
+/*
+ * Load/Save quick start data
+ */
+void do_quick_start(int flag)
+{
+ int i;
+
+ do_s16b(&previous_char.sex, flag);
+ do_s16b(&previous_char.race, flag);
+ do_s16b(&previous_char.rmod, flag);
+ do_s16b(&previous_char.pclass, flag);
+ do_s16b(&previous_char.spec, flag);
+ do_byte(&previous_char.quests, flag);
+ do_byte(&previous_char.god, flag);
+ do_s32b(&previous_char.grace, flag);
+ do_s16b(&previous_char.age, flag);
+ do_s16b(&previous_char.wt, flag);
+ do_s16b(&previous_char.ht, flag);
+ do_s16b(&previous_char.sc, flag);
+ do_s32b(&previous_char.au, flag);
+
+ for (i = 0; i < 6; i++) do_s16b(&(previous_char.stat[i]), flag);
+ do_s16b(&previous_char.luck, flag);
+
+ do_s16b(&previous_char.chaos_patron, flag);
+ do_u32b(&previous_char.weapon, flag);
+ do_byte((byte*)&previous_char.quick_ok, flag);
+
+ for (i = 0; i < 4; i++) do_string(previous_char.history[i], 60, flag);
+}
+
+/*
+ * The special saved subrace
+ */
+static void do_subrace(int flag)
+{
+ player_race_mod *sr_ptr = &race_mod_info[SUBRACE_SAVE];
+ int i;
+ char buf[81];
+
+ if (flag == LS_SAVE)
+ strncpy(buf, sr_ptr->title + rmp_name, 80);
+ do_string(buf, 80, flag);
+ if (flag == LS_LOAD)
+ strncpy(sr_ptr->title + rmp_name, buf, 80);
+
+ if (flag == LS_SAVE)
+ strncpy(buf, sr_ptr->desc + rmp_text, 80);
+ do_string(buf, 80, flag);
+ if (flag == LS_LOAD)
+ strncpy(sr_ptr->desc + rmp_text, buf, 80);
+
+ do_byte((byte*)&sr_ptr->place, flag);
+
+ for (i = 0; i < 6; i++)
+ do_s16b(&sr_ptr->r_adj[i], flag);
+
+ do_byte((byte*)&sr_ptr->luck, flag);
+ do_s16b(&sr_ptr->mana, flag);
+
+ do_s16b(&sr_ptr->r_dis, flag);
+ do_s16b(&sr_ptr->r_dev, flag);
+ do_s16b(&sr_ptr->r_sav, flag);
+ do_s16b(&sr_ptr->r_stl, flag);
+ do_s16b(&sr_ptr->r_srh, flag);
+ do_s16b(&sr_ptr->r_fos, flag);
+ do_s16b(&sr_ptr->r_thn, flag);
+ do_s16b(&sr_ptr->r_thb, flag);
+
+ do_byte((byte*)&sr_ptr->r_mhp, flag);
+ do_s16b(&sr_ptr->r_exp, flag);
+
+ do_byte((byte*)&sr_ptr->b_age, flag);
+ do_byte((byte*)&sr_ptr->m_age, flag);
+
+ do_byte((byte*)&sr_ptr->m_b_ht, flag);
+ do_byte((byte*)&sr_ptr->m_m_ht, flag);
+ do_byte((byte*)&sr_ptr->f_b_ht, flag);
+ do_byte((byte*)&sr_ptr->f_m_ht, flag);
+
+ do_byte((byte*)&sr_ptr->m_b_wt, flag);
+ do_byte((byte*)&sr_ptr->m_m_wt, flag);
+ do_byte((byte*)&sr_ptr->f_b_wt, flag);
+ do_byte((byte*)&sr_ptr->f_m_wt, flag);
+
+ do_byte((byte*)&sr_ptr->infra, flag);
+
+ for (i = 0; i < 4; i++)
+ do_s16b(&sr_ptr->powers[i], flag);
+
+ for (i = 0; i < BODY_MAX; i++)
+ do_byte((byte*)&sr_ptr->body_parts[i], flag);
+
+ do_u32b(&sr_ptr->flags1, flag);
+ do_u32b(&sr_ptr->flags2, flag);
+
+ for (i = 0; i < PY_MAX_LEVEL + 1; i++)
+ {
+ do_u32b(&sr_ptr->oflags1[i], flag);
+ do_u32b(&sr_ptr->oflags2[i], flag);
+ do_u32b(&sr_ptr->oflags3[i], flag);
+ do_u32b(&sr_ptr->oflags4[i], flag);
+ do_u32b(&sr_ptr->oflags5[i], flag);
+ do_u32b(&sr_ptr->oesp[i], flag);
+ do_s16b(&sr_ptr->opval[i], flag);
+ }
+
+ do_byte(&sr_ptr->g_attr, flag);
+ do_byte((byte*)&sr_ptr->g_char, flag);
+
+ for (i = 0; i < MAX_SKILLS; i++)
+ {
+ do_byte((byte*)&sr_ptr->skill_basem[i], flag);
+ do_u32b(&sr_ptr->skill_base[i], flag);
+ do_byte((byte*)&sr_ptr->skill_modm[i], flag);
+ do_s16b(&sr_ptr->skill_mod[i], flag);
+ }
+}
+
+/*
+ * Misc. other data
+ */
+static char loaded_game_module[80];
+static bool_ do_extra(int flag)
+{
+ int i, j;
+ byte tmp8u;
+ s16b tmp16s;
+ u32b tmp32u;
+ u16b tmp16b;
+ u32b dummy32u = 0;
+
+ do_string(player_name, 32, flag);
+
+ do_string(died_from, 80, flag);
+
+ for (i = 0; i < 4; i++)
+ {
+ do_string(history[i], 60, flag);
+ }
+
+ /* Handle the special levels info */
+ if (flag == LS_SAVE)
+ {
+ tmp8u = max_d_idx;
+ tmp16s = MAX_DUNGEON_DEPTH;
+ }
+ do_byte(&tmp8u, flag);
+
+ if (flag == LS_LOAD)
+ {
+ if (tmp8u > max_d_idx)
+ {
+ note(format("Too many (%d) dungeon types!", tmp8u));
+ }
+ }
+
+ do_s16b(&tmp16s, flag);
+
+ if (flag == LS_LOAD)
+ {
+ if (tmp16s > MAX_DUNGEON_DEPTH)
+ {
+ note(format("Too many (%d) max level by dungeon type!", tmp16s));
+ }
+ }
+
+ /* Load the special levels history */
+ for (i = 0; i < tmp8u; i++)
+ {
+ for (j = 0; j < tmp16s; j++)
+ {
+ do_byte((byte*)&special_lvl[j][i], flag);
+ }
+ }
+
+ do_byte((byte*)&generate_special_feeling, flag);
+
+ /* Load the quick start data */
+ do_quick_start(flag);
+
+ /* Load/save the special subrace */
+ do_subrace(flag);
+
+ /* Race/Class/Gender/Spells */
+ do_s32b(&p_ptr->lives, flag);
+ do_byte(&p_ptr->prace, flag);
+ do_byte(&p_ptr->pracem, flag);
+ do_byte(&p_ptr->pclass, flag);
+ do_byte(&p_ptr->pspec, flag);
+ do_byte(&p_ptr->psex, flag);
+ do_u16b(&tmp16b, flag);
+ do_u16b(&tmp16b, flag);
+ do_byte(&p_ptr->mimic_form, flag);
+ do_s16b(&p_ptr->mimic_level, flag);
+ if (flag == LS_SAVE) tmp8u = 0;
+
+ do_byte(&p_ptr->hitdie, flag);
+ do_u16b(&p_ptr->expfact, flag);
+
+ do_s16b(&p_ptr->age, flag);
+ do_s16b(&p_ptr->ht, flag);
+ do_s16b(&p_ptr->wt, flag);
+
+ /* Dump the stats (maximum and current) */
+ for (i = 0; i < 6; ++i) do_s16b(&p_ptr->stat_max[i], flag);
+ for (i = 0; i < 6; ++i) do_s16b(&p_ptr->stat_cur[i], flag);
+ for (i = 0; i < 6; ++i) do_s16b(&p_ptr->stat_cnt[i], flag);
+ for (i = 0; i < 6; ++i) do_s16b(&p_ptr->stat_los[i], flag);
+
+ /* Dump the skills */
+ do_s16b(&p_ptr->skill_points, flag);
+ do_s16b(&p_ptr->skill_last_level, flag);
+ do_s16b(&p_ptr->melee_style, flag);
+ do_s16b(&p_ptr->use_piercing_shots, flag);
+
+ tmp16s = MAX_SKILLS;
+ do_s16b(&tmp16s, flag);
+
+ if ((flag == LS_LOAD) && (tmp16s > MAX_SKILLS))
+ {
+ quit("Too many skills");
+ }
+
+ if (flag == LS_SAVE) old_max_s_idx = max_s_idx;
+ do_u16b(&old_max_s_idx, flag);
+ for (i = 0; i < tmp16s; ++i)
+ {
+ if (i < old_max_s_idx)
+ {
+ do_s32b(&s_info[i].value, flag);
+ do_s32b(&s_info[i].mod, flag);
+ do_byte((byte*)&s_info[i].dev, flag);
+ do_byte((byte*)&s_info[i].hidden, flag);
+ do_u32b(&s_info[i].uses, flag);
+ }
+ else
+ {
+ do_u32b(&tmp32u, flag);
+ do_s16b(&tmp16s, flag);
+ do_byte(&tmp8u, flag);
+ do_byte(&tmp8u, flag);
+ do_u32b(&tmp32u, flag);
+ }
+ }
+
+ tmp16s = max_ab_idx;
+ do_s16b(&tmp16s, flag);
+
+ if ((flag == LS_LOAD) && (tmp16s > max_ab_idx))
+ {
+ quit("Too many abilities");
+ }
+
+ for (i = 0; i < tmp16s; ++i)
+ {
+ do_byte((byte*)&ab_info[i].acquired, flag);
+ }
+
+ do_s16b(&p_ptr->luck_base, flag);
+ do_s16b(&p_ptr->luck_max, flag);
+
+ /* Found 24 unused bytes here...
+ Converted it to be the alchemist's
+ known artifact flags.
+ Note that the ego flags and the gained levels
+ record are recorded here too, but we use the
+ _ver_ format to protect save file compatablity.
+ Note that the other alchemist knowledge (item types known)
+ is stored in do_aux, and is a bit flag in a previously
+ unused bit.
+ */
+ for (i = 0; i < 6 ; ++i)
+ do_u32b(&alchemist_known_artifacts[i], flag);
+
+ for (i = 0; i < 32 ; ++i)
+ do_u32b(&alchemist_known_egos[i], flag);
+
+ do_u32b(&alchemist_gained, flag);
+
+ do_s32b(&p_ptr->au, flag);
+
+ do_s32b(&p_ptr->max_exp, flag);
+ do_s32b(&p_ptr->exp, flag);
+ do_u16b(&p_ptr->exp_frac, flag);
+ do_s16b(&p_ptr->lev, flag);
+
+ do_s16b(&p_ptr->town_num, flag); /* -KMW- */
+
+ /* Write arena and rewards information -KMW- */
+ do_s16b(&p_ptr->arena_number, flag);
+ do_s16b(&p_ptr->inside_arena, flag);
+ do_s16b(&p_ptr->inside_quest, flag);
+ do_byte((byte*)&p_ptr->exit_bldg, flag);
+
+
+ /* Save/load spellbinder */
+ do_byte(&p_ptr->spellbinder_num, flag);
+ do_byte(&p_ptr->spellbinder_trigger, flag);
+ for (i = 0; i < 4; i++)
+ do_u32b(&p_ptr->spellbinder[i], flag);
+
+
+ do_byte(&tmp8u, flag); /* tmp8u should be 0 at this point */
+
+ if (flag == LS_SAVE) tmp8u = MAX_PLOTS;
+ do_byte(&tmp8u, flag);
+
+ if ((flag == LS_LOAD) && (tmp8u > MAX_PLOTS))
+ {
+ quit(format("Too many plots, %d %d", tmp8u, MAX_PLOTS));
+ }
+
+ for (i = 0; i < tmp8u; i++)
+ {
+ do_s16b(&plots[i], flag);
+ }
+
+ if (flag == LS_SAVE)
+ {
+ tmp8u = MAX_RANDOM_QUEST;
+ }
+ do_byte(&tmp8u, flag);
+
+ if ((flag == LS_LOAD) &&
+ (tmp8u > MAX_RANDOM_QUEST)) quit("Too many random quests");
+ for (i = 0; i < tmp8u; i++)
+ {
+ do_byte(&random_quests[i].type, flag);
+ do_s16b(&random_quests[i].r_idx, flag);
+ do_byte((byte*)&random_quests[i].done, flag);
+ }
+
+ do_s16b(&p_ptr->oldpx, flag);
+ do_s16b(&p_ptr->oldpy, flag);
+
+ do_s16b(&p_ptr->mhp, flag);
+ do_s16b(&p_ptr->chp, flag);
+ do_u16b(&p_ptr->chp_frac, flag);
+ do_s16b(&p_ptr->hp_mod, flag);
+
+ do_s16b(&p_ptr->msane, flag);
+ do_s16b(&p_ptr->csane, flag);
+ do_u16b(&p_ptr->csane_frac, flag);
+
+ do_s16b(&p_ptr->msp, flag);
+ do_s16b(&p_ptr->csp, flag);
+ do_u16b(&p_ptr->csp_frac, flag);
+
+ /* XXX
+ Here's where tank points were.
+ Those who run the estate of you-know-who is really stupid.
+ I'll never even consider reading her books now. -- neil */
+ do_s16b(&tmp16s, flag);
+ do_s16b(&tmp16s, flag);
+ do_s16b(&tmp16s, flag);
+ do_s16b(&tmp16s, flag);
+
+ /* Gods */
+ do_s32b(&p_ptr->grace, flag);
+ do_byte((byte*)&p_ptr->praying, flag);
+ do_s16b(&p_ptr->melkor_sacrifice, flag);
+ do_byte(&p_ptr->pgod, flag);
+
+ /* Max Player and Dungeon Levels */
+ do_s16b(&p_ptr->max_plv, flag);
+
+ if (flag == LS_SAVE)
+ tmp8u = max_d_idx;
+ do_byte(&tmp8u, flag);
+ for (i = 0; i < tmp8u; i++)
+ {
+ if (flag == LS_SAVE)
+ tmp16s = max_dlv[i];
+ do_s16b(&tmp16s, flag);
+ if ((flag == LS_LOAD) && (i <= max_d_idx))
+ max_dlv[i] = tmp16s;
+ }
+ /* Repair max player level??? */
+ if ((flag == LS_LOAD) && (p_ptr->max_plv < p_ptr->lev))
+ p_ptr->max_plv = p_ptr->lev;
+
+ do_byte((byte*)&(p_ptr->help.enabled), flag);
+ do_u32b(&(p_ptr->help.help1), flag);
+
+ /* More info */
+ tmp16s = 0;
+ do_s16b(&p_ptr->sc, flag);
+ do_s16b(&p_ptr->blind, flag);
+ do_s16b(&p_ptr->paralyzed, flag);
+ do_s16b(&p_ptr->confused, flag);
+ do_s16b(&p_ptr->food, flag);
+ do_s32b(&p_ptr->energy, flag);
+ do_s16b(&p_ptr->fast, flag);
+ do_s16b(&p_ptr->speed_factor, flag);
+ do_s16b(&p_ptr->slow, flag);
+ do_s16b(&p_ptr->afraid, flag);
+ do_s16b(&p_ptr->cut, flag);
+ do_s16b(&p_ptr->stun, flag);
+ do_s16b(&p_ptr->poisoned, flag);
+ do_s16b(&p_ptr->image, flag);
+ do_s16b(&p_ptr->protevil, flag);
+ do_s16b(&p_ptr->protundead, flag);
+ do_s16b(&p_ptr->invuln, flag);
+ do_s16b(&p_ptr->hero, flag);
+ do_s16b(&p_ptr->shero, flag);
+ do_s16b(&p_ptr->shield, flag);
+ do_s16b(&p_ptr->shield_power, flag);
+ do_s16b(&p_ptr->shield_power_opt, flag);
+ do_s16b(&p_ptr->shield_power_opt2, flag);
+ do_s16b(&p_ptr->shield_opt, flag);
+ do_s16b(&p_ptr->blessed, flag);
+ do_s16b(&p_ptr->control, flag);
+ do_byte(&p_ptr->control_dir, flag);
+ do_s16b(&p_ptr->tim_thunder, flag);
+ do_s16b(&p_ptr->tim_thunder_p1, flag);
+ do_s16b(&p_ptr->tim_thunder_p2, flag);
+ do_s16b(&p_ptr->tim_project, flag);
+ do_s16b(&p_ptr->tim_project_dam, flag);
+ do_s16b(&p_ptr->tim_project_gf, flag);
+ do_s16b(&p_ptr->tim_project_rad, flag);
+ do_s16b(&p_ptr->tim_project_flag, flag);
+
+ do_s16b(&p_ptr->tim_magic_breath, flag);
+ do_s16b(&p_ptr->tim_water_breath, flag);
+
+ do_s16b(&p_ptr->tim_roots, flag);
+ do_s16b(&p_ptr->tim_roots_ac, flag);
+ do_s16b(&p_ptr->tim_roots_dam, flag);
+
+ do_s16b(&p_ptr->tim_invis, flag);
+ do_s16b(&p_ptr->word_recall, flag);
+ do_s16b(&p_ptr->recall_dungeon, flag);
+ do_s16b(&p_ptr->see_infra, flag);
+ do_s16b(&p_ptr->tim_infra, flag);
+ do_s16b(&p_ptr->oppose_fire, flag);
+ do_s16b(&p_ptr->oppose_cold, flag);
+ do_s16b(&p_ptr->oppose_acid, flag);
+ do_s16b(&p_ptr->oppose_elec, flag);
+ do_s16b(&p_ptr->oppose_pois, flag);
+ do_s16b(&p_ptr->oppose_ld, flag);
+ do_s16b(&p_ptr->oppose_cc, flag);
+ do_s16b(&p_ptr->oppose_ss, flag);
+ do_s16b(&p_ptr->oppose_nex, flag);
+
+ do_s16b(&p_ptr->tim_esp, flag);
+ do_s16b(&p_ptr->tim_wraith, flag);
+ do_s16b(&p_ptr->tim_ffall, flag);
+ do_ver_s16b(&p_ptr->tim_fly, SAVEFILE_VERSION, 0, flag);
+ do_s16b(&p_ptr->tim_fire_aura, flag);
+ do_ver_s16b(&p_ptr->tim_poison, SAVEFILE_VERSION, 0, flag);
+ do_s16b(&p_ptr->resist_magic, flag);
+ do_s16b(&p_ptr->tim_invisible, flag);
+ do_s16b(&p_ptr->tim_inv_pow, flag);
+ do_s16b(&p_ptr->tim_mimic, flag);
+ do_s16b(&p_ptr->lightspeed, flag);
+ do_s16b(&p_ptr->tim_lite, flag);
+ do_ver_s16b(&p_ptr->tim_regen, SAVEFILE_VERSION, 0, flag);
+ do_ver_s16b(&p_ptr->tim_regen_pow, SAVEFILE_VERSION, 0, flag);
+ do_s16b(&p_ptr->holy, flag);
+ do_s16b(&p_ptr->walk_water, flag);
+ do_s16b(&p_ptr->tim_mental_barrier, flag);
+ do_s16b(&p_ptr->immov_cntr, flag);
+ do_s16b(&p_ptr->strike, flag);
+ do_s16b(&p_ptr->meditation, flag);
+ do_s16b(&p_ptr->tim_reflect, flag);
+ do_s16b(&p_ptr->tim_res_time, flag);
+ do_s16b(&p_ptr->tim_deadly, flag);
+ do_s16b(&p_ptr->prob_travel, flag);
+ do_s16b(&p_ptr->disrupt_shield, flag);
+ do_s16b(&p_ptr->parasite, flag);
+ do_s16b(&p_ptr->parasite_r_idx, flag);
+ do_s32b(&p_ptr->loan, flag);
+ do_s32b(&p_ptr->loan_time, flag);
+ do_s16b(&p_ptr->absorb_soul, flag);
+
+ do_s16b(&p_ptr->chaos_patron, flag);
+
+ if (flag == LS_SAVE) tmp16s = max_corruptions;
+ do_s16b(&tmp16s, flag);
+
+ for (i = 0; i < tmp16s; i++)
+ {
+ if ((flag == LS_SAVE) && (i < max_corruptions))
+ tmp8u = p_ptr->corruptions[i];
+
+ do_byte(&tmp8u, flag);
+
+ if ((flag == LS_LOAD) && (i < max_corruptions))
+ p_ptr->corruptions[i] = tmp8u;
+ }
+
+ do_byte(&p_ptr->confusing, flag);
+ do_byte((byte*)&p_ptr->black_breath, flag);
+ do_byte((byte*)&fate_flag, flag);
+ do_byte(&p_ptr->searching, flag);
+ do_byte(&p_ptr->maximize, flag);
+ do_byte(&p_ptr->preserve, flag);
+ do_byte(&p_ptr->special, flag);
+ do_byte((byte*)&ambush_flag, flag);
+ do_byte(&p_ptr->allow_one_death, flag);
+ do_s16b(&p_ptr->xtra_spells, flag);
+
+ do_byte(&tmp8u, flag);
+
+ do_s16b(&no_breeds, flag);
+ do_s16b(&p_ptr->protgood, flag);
+
+ /* Auxilliary variables */
+ do_u32b(&p_ptr->mimic_extra, flag);
+ do_u32b(&p_ptr->antimagic_extra, flag);
+ do_u32b(&p_ptr->druid_extra, flag);
+ do_u32b(&p_ptr->druid_extra2, flag);
+ do_u32b(&p_ptr->druid_extra3, flag);
+ do_u32b(&p_ptr->music_extra, flag);
+ do_u32b(&p_ptr->music_extra2, flag);
+ do_u32b(&p_ptr->necro_extra, flag);
+ do_u32b(&p_ptr->necro_extra2, flag);
+
+ do_u32b(&p_ptr->race_extra1, flag);
+ do_u32b(&p_ptr->race_extra2, flag);
+ do_u32b(&p_ptr->race_extra3, flag);
+ do_u32b(&p_ptr->race_extra4, flag);
+ do_u32b(&p_ptr->race_extra5, flag);
+ do_u32b(&p_ptr->race_extra6, flag);
+ do_u32b(&p_ptr->race_extra7, flag);
+
+ do_u16b(&p_ptr->body_monster, flag);
+ do_byte((byte*)&p_ptr->disembodied, flag);
+
+ /* Are we in astral mode? */
+ do_byte((byte*)&p_ptr->astral, flag);
+
+ if (flag == LS_SAVE) tmp16s = POWER_MAX_INIT;
+ do_s16b(&tmp16s, flag);
+ if ((flag == LS_LOAD) && (tmp16s > POWER_MAX_INIT))
+ note(format("Too many (%u) powers!", tmp16s));
+ if (flag == LS_SAVE) tmp16s = POWER_MAX_INIT;
+ for (i = 0; i < tmp16s; i++)
+ do_byte((byte*)&p_ptr->powers_mod[i], flag);
+
+ skip_ver_byte(100, flag);
+
+ /* The tactic */
+ do_byte((byte*)&p_ptr->tactic, flag);
+
+ /* The movement */
+ do_byte((byte*)&p_ptr->movement, flag);
+
+ /* The comapnions killed */
+ do_s16b(&p_ptr->companion_killed, flag);
+
+ /* The fate */
+ do_byte((byte*)&p_ptr->no_mortal, flag);
+
+ /* The bounties */
+ for (i = 0; i < MAX_BOUNTIES; i++)
+ {
+ do_s16b(&bounties[i][0], flag);
+ do_s16b(&bounties[i][1], flag);
+ }
+ do_u32b(&total_bounties, flag);
+ do_s16b(&spell_num, flag);
+ for (i = 0; i < MAX_SPELLS; i++)
+ do_spells(i, flag);
+ do_s16b(&rune_num, flag);
+ for (i = 0; i < MAX_RUNES; i++)
+ {
+ do_string(rune_spells[i].name, 30, flag);
+ do_s16b(&rune_spells[i].type, flag);
+ do_s16b(&rune_spells[i].rune2, flag);
+ do_s16b(&rune_spells[i].mana, flag);
+ }
+
+ /* Load random seeds */
+ do_u32b(&dummy32u, flag); /* Load-compatibility with old savefiles. */
+ do_u32b(&seed_flavor, flag); /* For consistent object flavors. */
+ do_u32b(&dummy32u, flag); /* Load-compatibility with old savefiles. */
+
+ /* Special stuff */
+ do_u16b(&tmp16b, flag); /* Dummy */
+ do_u16b(&total_winner, flag);
+ do_u16b(&has_won, flag);
+ do_u16b(&noscore, flag);
+
+ /* Write death */
+ if (flag == LS_SAVE) tmp8u = death;
+ do_byte(&tmp8u, flag);
+ if (flag == LS_LOAD) death = tmp8u;
+
+ /* Incompatible module? */
+ if (flag == LS_LOAD)
+ {
+ s32b ok;
+
+ call_lua("module_savefile_loadable", "(s,d)", "d", loaded_game_module, death, &ok);
+
+ /* Argh bad game module! */
+ if (!ok)
+ {
+ note(format("Bad game module. Savefile was saved with module '%s' but game is '%s'.", loaded_game_module, game_module));
+ return (FALSE);
+ }
+ }
+
+ /* Write feeling */
+ if (flag == LS_SAVE) tmp8u = feeling;
+ do_byte(&tmp8u, flag);
+ if (flag == LS_LOAD) feeling = tmp8u;
+
+ /* Turn of last "feeling" */
+ do_s32b(&old_turn, flag);
+
+ /* Current turn */
+ do_s32b(&turn, flag);
+
+ return TRUE;
+}
+
+/* Save the current persistent dungeon -SC- */
+void save_dungeon(void)
+{
+ char tmp[16];
+ char name[1024], buf[5];
+
+ /* Save only persistent dungeons */
+ if (!get_dungeon_save(buf) || (!dun_level)) return;
+
+ /* Construct filename */
+ sprintf(tmp, "%s.%s", player_base, buf);
+ path_build(name, 1024, ANGBAND_DIR_SAVE, tmp);
+
+ /* Open the file */
+ fff = my_fopen(name, "wb");
+
+ /* Save the dungeon */
+ do_dungeon(LS_SAVE, TRUE);
+
+ my_fclose(fff);
+}
+
+/*
+ * Medium level player saver
+ */
+static bool_ save_player_aux(char *name)
+{
+ bool_ ok = FALSE;
+ int fd = -1;
+ int mode = 0644;
+
+ /* No file yet */
+ fff = NULL;
+
+ /* File type is "SAVE" */
+ FILE_TYPE(FILE_TYPE_SAVE);
+
+ /* Create the savefile */
+ fd = fd_make(name, mode);
+
+ /* File is okay */
+ if (fd >= 0)
+ {
+ /* Close the "fd" */
+ (void)fd_close(fd);
+
+ /* Open the savefile */
+ fff = my_fopen(name, "wb");
+
+ /* Successful open */
+ if (fff)
+ {
+ /* Write the savefile */
+ if (do_savefile_aux(LS_SAVE)) ok = TRUE;
+
+ /* Attempt to close it */
+ if (my_fclose(fff)) ok = FALSE;
+ }
+
+ /* "broken" savefile */
+ if (!ok)
+ {
+ /* Remove "broken" files */
+ (void)fd_kill(name);
+ }
+ }
+
+ /* Failure */
+ if (!ok) return (FALSE);
+
+ /* Successful save */
+ character_saved = TRUE;
+
+ /* Success */
+ return (TRUE);
+}
+
+/*
+ * Attempt to save the player in a savefile
+ */
+bool_ save_player(void)
+{
+ int result = FALSE;
+ char safe[1024];
+
+ /* New savefile */
+ strcpy(safe, savefile);
+ strcat(safe, ".new");
+
+ /* Remove it */
+ fd_kill(safe);
+
+ /* Attempt to save the player */
+ if (save_player_aux(safe))
+ {
+ char temp[1024];
+
+ /* Old savefile */
+ strcpy(temp, savefile);
+ strcat(temp, ".old");
+
+ /* Remove it */
+ fd_kill(temp);
+
+ /* Preserve old savefile */
+ fd_move(savefile, temp);
+
+ /* Activate new savefile */
+ fd_move(safe, savefile);
+
+ /* Remove preserved savefile */
+ fd_kill(temp);
+
+ /* Hack -- Pretend the character was loaded */
+ character_loaded = TRUE;
+
+ /* Success */
+ result = TRUE;
+ }
+
+ save_savefile_names();
+
+ /* Return the result */
+ return (result);
+}
+
+bool_ file_exist(char *buf)
+{
+ int fd;
+ bool_ result;
+
+ /* Open savefile */
+ fd = fd_open(buf, O_RDONLY);
+
+ /* File exists */
+ if (fd >= 0)
+ {
+ fd_close(fd);
+ result = TRUE;
+ }
+ else
+ result = FALSE;
+
+ return result;
+}
+
+/*
+ * Attempt to Load a "savefile"
+ *
+ * On multi-user systems, you may only "read" a savefile if you will be
+ * allowed to "write" it later, this prevents painful situations in which
+ * the player loads a savefile belonging to someone else, and then is not
+ * allowed to save his game when he quits.
+ *
+ * We return "TRUE" if the savefile was usable, and we set the global
+ * flag "character_loaded" if a real, living, character was loaded.
+ *
+ * Note that we always try to load the "current" savefile, even if
+ * there is no such file, so we must check for "empty" savefile names.
+ */
+bool_ load_player(void)
+{
+ int fd = -1;
+
+ errr err = 0;
+
+ cptr what = "generic";
+
+ /* Paranoia */
+ turn = 0;
+
+ /* Paranoia */
+ death = FALSE;
+
+
+ /* Allow empty savefile name */
+ if (!savefile[0]) return (TRUE);
+
+
+ /* XXX XXX XXX Fix this */
+
+ /* Verify the existance of the savefile */
+ if (!file_exist(savefile))
+ {
+ /* Give a message */
+ msg_format("Savefile does not exist: %s", savefile);
+ msg_print(NULL);
+
+ /* Allow this */
+ return (TRUE);
+ }
+
+ /* Okay */
+ if (!err)
+ {
+ /* Open the savefile */
+ fd = fd_open(savefile, O_RDONLY);
+
+ /* No file */
+ if (fd < 0) err = -1;
+
+ /* Message (below) */
+ if (err) what = "Cannot open savefile";
+ }
+
+ /* Process file */
+ if (!err)
+ {
+ /* Open the file XXX XXX XXX XXX Should use Angband file interface */
+ fff = my_fopen(savefile, "rb");
+/* fff = fdopen(fd, "r"); */
+
+ /* Read the first four bytes */
+ do_u32b(&vernum, LS_LOAD);
+ do_byte(&sf_extra, LS_LOAD);
+
+ /* XXX XXX XXX XXX Should use Angband file interface */
+ my_fclose(fff);
+ /* fclose(fff) */
+
+ /* Close the file */
+ fd_close(fd);
+ }
+
+ /* Process file */
+ if (!err)
+ {
+
+ /* Extract version */
+ sf_major = VERSION_MAJOR;
+ sf_minor = VERSION_MINOR;
+ sf_patch = VERSION_PATCH;
+ sf_extra = VERSION_EXTRA;
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Attempt to load */
+ err = rd_savefile();
+
+ /* Message (below) */
+ if (err) what = "Cannot parse savefile";
+ }
+
+ /* Paranoia */
+ if (!err)
+ {
+ /* Invalid turn */
+ if (!turn) err = -1;
+
+ /* Message (below) */
+ if (err) what = "Broken savefile";
+ }
+
+
+ /* Okay */
+ if (!err)
+ {
+ /* Maybe the scripts want to resurrect char */
+ if (process_hooks_ret(HOOK_LOAD_END, "d", "(d)", death))
+ {
+ character_loaded = process_hooks_return[0].num;
+ death = process_hooks_return[1].num;
+ return TRUE;
+ }
+
+ /* Player is dead */
+ if (death)
+ {
+ /* Player is no longer "dead" */
+ death = FALSE;
+
+ /* Cheat death (unless the character retired) */
+ if (arg_wizard && !total_winner)
+ {
+ /* A character was loaded */
+ character_loaded = TRUE;
+
+ /* Done */
+ return (TRUE);
+ }
+
+ /* Count lives */
+ sf_lives++;
+
+ /* Forget turns */
+ turn = old_turn = 0;
+
+ /* Done */
+ return (TRUE);
+ }
+
+ /* A character was loaded */
+ character_loaded = TRUE;
+
+ /* Still alive */
+ if (p_ptr->chp >= 0)
+ {
+ /* Reset cause of death */
+ (void)strcpy(died_from, "(alive and well)");
+ }
+
+ /* Success */
+ return (TRUE);
+ }
+
+
+ /* Message */
+ msg_format("Error (%s) reading %d.%d.%d savefile.",
+ what, sf_major, sf_minor, sf_patch);
+ msg_print(NULL);
+
+ /* Oops */
+ return (FALSE);
+}
+
+
+/*
+ * Size-aware read/write routines for the savefile, do all their
+ * work through sf_get and sf_put.
+ */
+
+static void do_byte(byte *v, int flag)
+{
+ if (flag == LS_LOAD)
+ {
+ *v = sf_get();
+ return;
+ }
+ if (flag == LS_SAVE)
+ {
+ byte val = *v;
+ sf_put(val);
+ return;
+ }
+ /* We should never reach here, so bail out */
+ printf("FATAL: do_byte passed %d\n", flag);
+ exit(0);
+}
+
+static void do_u16b(u16b *v, int flag)
+{
+ if (flag == LS_LOAD)
+ {
+ (*v) = sf_get();
+ (*v) |= ((u16b)(sf_get()) << 8);
+ return;
+ }
+ if (flag == LS_SAVE)
+ {
+ u16b val;
+ val = *v;
+ sf_put((byte)(val & 0xFF));
+ sf_put((byte)((val >> 8) & 0xFF));
+ return;
+ }
+ /* Never should reach here, bail out */
+ printf("FATAL: do_u16b passed %d\n", flag);
+ exit(0);
+}
+
+static void do_s16b(s16b *ip, int flag)
+{
+ if (flag == LS_LOAD)
+ {
+ do_u16b((u16b *)ip, flag);
+ return;
+ }
+ if (flag == LS_SAVE)
+ {
+ do_u16b((u16b *)ip, flag);
+ return;
+ }
+ /* Blah blah, never should reach here, die */
+ printf("FATAL: do_s16b passed %d\n", flag);
+ exit(0);
+}
+
+static void do_u32b(u32b *ip, int flag)
+{
+ if (flag == LS_LOAD)
+ {
+ (*ip) = sf_get();
+ (*ip) |= ((u32b)(sf_get()) << 8);
+ (*ip) |= ((u32b)(sf_get()) << 16);
+ (*ip) |= ((u32b)(sf_get()) << 24);
+ return;
+ }
+ if (flag == LS_SAVE)
+ {
+ u32b val = *ip;
+ sf_put((byte)(val & 0xFF));
+ sf_put((byte)((val >> 8) & 0xFF));
+ sf_put((byte)((val >> 16) & 0xFF));
+ sf_put((byte)((val >> 24) & 0xFF));
+ return;
+ }
+ /* Bad news if you're here, because you're going down */
+ printf("FATAL: do_u32b passed %d\n", flag);
+ exit(0);
+}
+
+static void do_s32b(s32b *ip, int flag)
+{
+ if (flag == LS_LOAD)
+ {
+ do_u32b((u32b *)ip, flag);
+ return;
+ }
+ if (flag == LS_SAVE)
+ {
+ do_u32b((u32b *)ip, flag);
+ return;
+ }
+ /* Raus! Schnell! */
+ printf("FATAL: do_s32b passed %d\n", flag);
+ exit(0);
+}
+
+static void do_string(char *str, int max, int flag)
+/* Max is ignored for writing */
+{
+ if (flag == LS_LOAD)
+ {
+ int i;
+
+ /* Read the string */
+ for (i = 0; TRUE; i++)
+ {
+ byte tmp8u;
+
+ /* Read a byte */
+ do_byte(&tmp8u, LS_LOAD);
+
+ /* Collect string while legal */
+ if (i < max) str[i] = tmp8u;
+
+ /* End of string */
+ if (!tmp8u) break;
+ }
+ /* Terminate */
+ str[max - 1] = '\0';
+ return;
+ }
+ if (flag == LS_SAVE)
+ {
+ while (*str)
+ {
+ do_byte((byte*)str, flag);
+ str++;
+ }
+ do_byte((byte*)str, flag); /* Output a terminator */
+ return;
+ }
+ printf("FATAL: do_string passed flag %d\n", flag);
+ exit(0);
+}
+
+static void skip_ver_byte(u32b version, int flag)
+/* Reads and discards a byte if the savefile is as old as/older than version */
+{
+ if ((flag == LS_LOAD) && (vernum <= version))
+ {
+ byte forget;
+ do_byte(&forget, flag);
+ }
+ return;
+}
+
+static void do_ver_s16b(s16b *v, u32b version, s16b defval, int flag)
+{
+ if ((flag == LS_LOAD) && (vernum < version))
+ {
+ *v = defval;
+ return;
+ }
+ do_s16b(v, flag);
+}
+
+/*
+ * Show information on the screen, one line at a time.
+ *
+ * Avoid the top two lines, to avoid interference with "msg_print()".
+ */
+static void note(cptr msg)
+{
+ static int y = 2;
+
+ /* Draw the message */
+ prt(msg, y, 0);
+
+ /* Advance one line (wrap if needed) */
+ if (++y >= 24) y = 2;
+
+ /* Flush it */
+ Term_fresh();
+}
+
+
+/*
+ * Determine if an item can be wielded/worn (e.g. helmet, sword, bow, arrow)
+ */
+static bool_ wearable_p(object_type *o_ptr)
+{
+ /* Valid "tval" codes */
+ switch (o_ptr->tval)
+ {
+ case TV_WAND:
+ case TV_STAFF:
+ case TV_ROD:
+ case TV_ROD_MAIN:
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+ case TV_BOOMERANG:
+ case TV_BOW:
+ case TV_DIGGING:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_MSTAFF:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_HELM:
+ case TV_CROWN:
+ case TV_SHIELD:
+ case TV_CLOAK:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ case TV_SCROLL:
+ case TV_LITE:
+ case TV_POTION:
+ case TV_POTION2:
+ case TV_AMULET:
+ case TV_RING:
+ case TV_HYPNOS:
+ case TV_INSTRUMENT:
+ case TV_DAEMON_BOOK:
+ case TV_TRAPKIT:
+ case TV_TOOL:
+ {
+ return (TRUE);
+ }
+ }
+
+ /* Nope */
+ return (FALSE);
+}
+
+
+/*
+ * rd/wr an object
+ *
+ * FIXME! This code probably has a lot of cruft from the old Z/V codebase.
+ *
+ */
+static void do_item(object_type *o_ptr, int flag)
+{
+ byte old_dd;
+ byte old_ds;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_kind *k_ptr;
+
+ /* Kind */
+ do_s16b(&o_ptr->k_idx, flag);
+
+ /* Location */
+ do_byte(&o_ptr->iy, flag);
+ do_byte(&o_ptr->ix, flag);
+
+ /* Type/Subtype */
+ do_byte(&o_ptr->tval, flag);
+ do_byte(&o_ptr->sval, flag);
+
+ /* Special pval */
+ do_s32b(&o_ptr->pval, flag);
+
+ /* Special pval */
+ do_s16b(&o_ptr->pval2, flag);
+
+ /* Special pval */
+ do_s32b(&o_ptr->pval3, flag);
+
+ do_byte(&o_ptr->discount, flag);
+ do_byte(&o_ptr->number, flag);
+ do_s32b(&o_ptr->weight, flag);
+
+ do_byte(&o_ptr->name1, flag);
+ do_s16b(&o_ptr->name2, flag);
+ do_s16b(&o_ptr->name2b, flag);
+ do_s16b(&o_ptr->timeout, flag);
+
+ do_s16b(&o_ptr->to_h, flag);
+ do_s16b(&o_ptr->to_d, flag);
+ do_s16b(&o_ptr->to_a, flag);
+
+ do_s16b(&o_ptr->ac, flag);
+
+ /* We do special processing of this flag when reading */
+ if (flag == LS_LOAD)
+ {
+ do_byte(&old_dd, LS_LOAD);
+ do_byte(&old_ds, LS_LOAD);
+ }
+ if (flag == LS_SAVE)
+ {
+ do_byte(&o_ptr->dd, LS_SAVE);
+ do_byte(&o_ptr->ds, LS_SAVE);
+ }
+
+ do_byte(&o_ptr->ident, flag);
+
+ do_byte(&o_ptr->marked, flag);
+
+ /* flags */
+ do_u32b(&o_ptr->art_flags1, flag);
+ do_u32b(&o_ptr->art_flags2, flag);
+ do_u32b(&o_ptr->art_flags3, flag);
+ do_u32b(&o_ptr->art_flags4, flag);
+ do_u32b(&o_ptr->art_flags5, flag);
+ do_u32b(&o_ptr->art_esp, flag);
+
+ /* obvious flags */
+ do_u32b(&o_ptr->art_oflags1, flag);
+ do_u32b(&o_ptr->art_oflags2, flag);
+ do_u32b(&o_ptr->art_oflags3, flag);
+ do_u32b(&o_ptr->art_oflags4, flag);
+ do_u32b(&o_ptr->art_oflags5, flag);
+ do_u32b(&o_ptr->art_oesp, flag);
+
+ /* Monster holding object */
+ do_s16b(&o_ptr->held_m_idx, flag);
+
+ /* Special powers */
+ do_byte(&o_ptr->xtra1, flag);
+ do_s16b(&o_ptr->xtra2, flag);
+
+ do_byte(&o_ptr->elevel, flag);
+ do_s32b(&o_ptr->exp, flag);
+
+ /* Read the pseudo-id */
+ do_byte(&o_ptr->sense, flag);
+
+ /* Read the found info */
+ do_byte(&o_ptr->found, flag);
+ do_s16b(&o_ptr->found_aux1, flag);
+ do_s16b(&o_ptr->found_aux2, flag);
+ do_s16b(&o_ptr->found_aux3, flag);
+ do_s16b(&o_ptr->found_aux4, flag);
+
+ if (flag == LS_LOAD)
+ {
+ char buf[128];
+ /* Inscription */
+ do_string(buf, 128, LS_LOAD);
+ /* Save the inscription */
+ if (buf[0]) o_ptr->note = quark_add(buf);
+
+ do_string(buf, 128, LS_LOAD);
+ if (buf[0]) o_ptr->art_name = quark_add(buf);
+ }
+ if (flag == LS_SAVE)
+ {
+ /* Save the inscription (if any) */
+ if (o_ptr->note)
+ {
+ do_string((char *)quark_str(o_ptr->note), 0, LS_SAVE);
+ }
+ else
+ {
+ do_string("", 0, LS_SAVE);
+ }
+ if (o_ptr->art_name)
+ {
+ do_string((char *)quark_str(o_ptr->art_name), 0, LS_SAVE);
+ }
+ else
+ {
+ do_string("", 0, LS_SAVE);
+ }
+ }
+
+ if (flag == LS_SAVE) return ; /* Stick any more shared code before this. The rest
+ of this function is reserved for LS_LOAD's
+ cleanup functions */
+ /*********** END OF LS_SAVE ***************/
+
+ /* Obtain the "kind" template */
+ k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Obtain tval/sval from k_info */
+ o_ptr->tval = k_ptr->tval;
+ if (o_ptr->tval != TV_RANDART) o_ptr->sval = k_ptr->sval;
+
+
+ /* Repair non "wearable" items */
+ if (!wearable_p(o_ptr))
+ {
+ /* Acquire correct fields */
+ o_ptr->to_h = k_ptr->to_h;
+ o_ptr->to_d = k_ptr->to_d;
+ o_ptr->to_a = k_ptr->to_a;
+
+ /* Acquire correct fields */
+ o_ptr->ac = k_ptr->ac;
+ o_ptr->dd = k_ptr->dd;
+ o_ptr->ds = k_ptr->ds;
+
+ /* All done */
+ return;
+ }
+
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Paranoia */
+ if (o_ptr->name1)
+ {
+ artifact_type *a_ptr;
+
+ /* Obtain the artifact info */
+ a_ptr = &a_info[o_ptr->name1];
+
+ /* Verify that artifact */
+ if (!a_ptr->name) o_ptr->name1 = 0;
+ }
+
+ /* Paranoia */
+ if (o_ptr->name2)
+ {
+ ego_item_type *e_ptr;
+
+ /* Obtain the ego-item info */
+ e_ptr = &e_info[o_ptr->name2];
+
+ /* Verify that ego-item */
+ if (!e_ptr->name) o_ptr->name2 = 0;
+ }
+
+
+ /* Acquire standard fields */
+ o_ptr->ac = k_ptr->ac;
+ o_ptr->dd = k_ptr->dd;
+ o_ptr->ds = k_ptr->ds;
+
+ /* Artifacts */
+ if (o_ptr->name1)
+ {
+ artifact_type *a_ptr;
+
+ /* Obtain the artifact info */
+ a_ptr = &a_info[o_ptr->name1];
+
+ /* Acquire new artifact fields */
+ o_ptr->ac = a_ptr->ac;
+ o_ptr->dd = a_ptr->dd;
+ o_ptr->ds = a_ptr->ds;
+
+ /* Acquire new artifact weight */
+ o_ptr->weight = a_ptr->weight;
+ }
+
+ /* Ego items */
+ if (o_ptr->name2)
+ {
+ o_ptr->dd = old_dd;
+ o_ptr->ds = old_ds;
+ }
+
+ if (o_ptr->art_name) /* A random artifact */
+ {
+ o_ptr->dd = old_dd;
+ o_ptr->ds = old_ds;
+ }
+}
+
+
+
+
+/*
+ * Read a monster
+ */
+static void do_monster(monster_type *m_ptr, int flag)
+{
+ int i;
+ bool_ tmp;
+
+ /* Read the monster race */
+ do_s16b(&m_ptr->r_idx, flag);
+
+ do_u16b(&m_ptr->ego, flag);
+
+ /* Read the other information */
+ do_byte(&m_ptr->fy, flag);
+ do_byte(&m_ptr->fx, flag);
+
+ do_s32b(&m_ptr->hp, flag);
+ do_s32b(&m_ptr->maxhp, flag);
+
+ do_s16b(&m_ptr->csleep, flag);
+ do_byte(&m_ptr->mspeed, flag);
+ do_byte(&m_ptr->energy, flag);
+ do_byte(&m_ptr->stunned, flag);
+ do_byte(&m_ptr->confused, flag);
+ do_byte(&m_ptr->monfear, flag);
+ do_u32b(&m_ptr->smart, flag);
+ do_s16b(&m_ptr->status, flag);
+ do_s16b(&m_ptr->possessor, flag);
+ do_byte(&m_ptr->speed, flag);
+ do_byte(&m_ptr->level, flag);
+ do_s16b(&m_ptr->ac, flag);
+ do_u32b(&m_ptr->exp, flag);
+ do_s16b(&m_ptr->target, flag);
+
+ do_s16b(&m_ptr->bleeding, flag);
+ do_s16b(&m_ptr->poisoned, flag);
+
+ do_s32b(&m_ptr->mflag, flag);
+
+ if (flag == LS_LOAD) m_ptr->mflag &= PERM_MFLAG_MASK;
+
+ /* Attacks */
+ for (i = 0; i < 4; i++)
+ {
+ do_byte(&m_ptr->blow[i].method, flag);
+ do_byte(&m_ptr->blow[i].effect, flag);
+ do_byte(&m_ptr->blow[i].d_dice, flag);
+ do_byte(&m_ptr->blow[i].d_side, flag);
+ }
+
+ /* Mind */
+ tmp = (m_ptr->mind) ? TRUE : FALSE;
+ do_byte((byte*)&tmp, flag);
+ if (tmp)
+ {
+ if (flag == LS_LOAD)
+ {
+ MAKE(m_ptr->mind, monster_mind);
+ }
+ }
+
+ /* Special race */
+ tmp = (m_ptr->sr_ptr) ? TRUE : FALSE;
+ do_byte((byte*)&tmp, flag);
+ if (tmp)
+ {
+ if (flag == LS_LOAD)
+ {
+ MAKE(m_ptr->sr_ptr, monster_race);
+ }
+ do_u32b(&m_ptr->sr_ptr->name, flag);
+ do_u32b(&m_ptr->sr_ptr->text, flag);
+
+ do_u16b(&m_ptr->sr_ptr->hdice, flag);
+ do_u16b(&m_ptr->sr_ptr->hside, flag);
+
+ do_s16b(&m_ptr->sr_ptr->ac, flag);
+
+ do_s16b(&m_ptr->sr_ptr->sleep, flag);
+ do_byte(&m_ptr->sr_ptr->aaf, flag);
+ do_byte(&m_ptr->sr_ptr->speed, flag);
+
+ do_s32b(&m_ptr->sr_ptr->mexp, flag);
+
+ do_s32b(&m_ptr->sr_ptr->weight, flag);
+
+ do_byte(&m_ptr->sr_ptr->freq_inate, flag);
+ do_byte(&m_ptr->sr_ptr->freq_spell, flag);
+
+ do_u32b(&m_ptr->sr_ptr->flags1, flag);
+ do_u32b(&m_ptr->sr_ptr->flags2, flag);
+ do_u32b(&m_ptr->sr_ptr->flags3, flag);
+ do_u32b(&m_ptr->sr_ptr->flags4, flag);
+ do_u32b(&m_ptr->sr_ptr->flags5, flag);
+ do_u32b(&m_ptr->sr_ptr->flags6, flag);
+ do_u32b(&m_ptr->sr_ptr->flags7, flag);
+ do_u32b(&m_ptr->sr_ptr->flags8, flag);
+ do_u32b(&m_ptr->sr_ptr->flags9, flag);
+
+ /* Attacks */
+ for (i = 0; i < 4; i++)
+ {
+ do_byte(&m_ptr->sr_ptr->blow[i].method, flag);
+ do_byte(&m_ptr->sr_ptr->blow[i].effect, flag);
+ do_byte(&m_ptr->sr_ptr->blow[i].d_dice, flag);
+ do_byte(&m_ptr->sr_ptr->blow[i].d_side, flag);
+ }
+
+ for (i = 0; i < BODY_MAX; i++)
+ do_byte(&m_ptr->sr_ptr->body_parts[i], flag);
+
+ do_byte(&m_ptr->sr_ptr->level, flag);
+ do_byte(&m_ptr->sr_ptr->rarity, flag);
+
+ do_byte((byte*)&m_ptr->sr_ptr->d_char, flag);
+ do_byte(&m_ptr->sr_ptr->d_attr, flag);
+
+ do_byte((byte*)&m_ptr->sr_ptr->x_char, flag);
+ do_byte(&m_ptr->sr_ptr->x_attr, flag);
+
+ do_s16b(&m_ptr->sr_ptr->max_num, flag);
+ do_byte(&m_ptr->sr_ptr->cur_num, flag);
+ }
+}
+
+
+
+
+
+/*
+ * Handle monster lore
+ */
+static void do_lore(int r_idx, int flag)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Count sights/deaths/kills */
+ do_s16b(&r_ptr->r_sights, flag);
+ do_s16b(&r_ptr->r_deaths, flag);
+ do_s16b(&r_ptr->r_pkills, flag);
+ do_s16b(&r_ptr->r_tkills, flag);
+
+ /* Count wakes and ignores */
+ do_byte(&r_ptr->r_wake, flag);
+ do_byte(&r_ptr->r_ignore, flag);
+
+ /* Extra stuff */
+ do_byte(&r_ptr->r_xtra1, flag);
+ do_byte(&r_ptr->r_xtra2, flag);
+
+ /* Count drops */
+ do_byte(&r_ptr->r_drop_gold, flag);
+ do_byte(&r_ptr->r_drop_item, flag);
+
+ /* Count spells */
+ do_byte(&r_ptr->r_cast_inate, flag);
+ do_byte(&r_ptr->r_cast_spell, flag);
+
+ /* Count blows of each type */
+ do_byte(&r_ptr->r_blows[0], flag);
+ do_byte(&r_ptr->r_blows[1], flag);
+ do_byte(&r_ptr->r_blows[2], flag);
+ do_byte(&r_ptr->r_blows[3], flag);
+
+ /* Memorize flags */
+ do_u32b(&r_ptr->r_flags1, flag); /* Just to remind you */
+ do_u32b(&r_ptr->r_flags2, flag); /* flag is unrelated to */
+ do_u32b(&r_ptr->r_flags3, flag); /* the other argument */
+ do_u32b(&r_ptr->r_flags4, flag);
+ do_u32b(&r_ptr->r_flags5, flag);
+ do_u32b(&r_ptr->r_flags6, flag);
+ do_u32b(&r_ptr->r_flags7, flag);
+ do_u32b(&r_ptr->r_flags8, flag);
+ do_u32b(&r_ptr->r_flags9, flag);
+
+ /* Read the "Racial" monster tmp16b per level */
+ do_s16b(&r_ptr->max_num, flag);
+
+ do_byte((byte*)&r_ptr->on_saved, flag);
+
+ if (flag == LS_LOAD)
+ {
+ /* Lore flag repair? */
+ r_ptr->r_flags1 &= r_ptr->flags1;
+ r_ptr->r_flags2 &= r_ptr->flags2;
+ r_ptr->r_flags3 &= r_ptr->flags3;
+ r_ptr->r_flags4 &= r_ptr->flags4;
+ r_ptr->r_flags5 &= r_ptr->flags5;
+ r_ptr->r_flags6 &= r_ptr->flags6;
+ }
+}
+
+
+
+
+/*
+ * Read a store
+ */
+static bool_ do_store(store_type *str, int flag)
+/* FIXME! Why does this return anything when
+ it always returns the same thing? */
+{
+ int j;
+
+ byte num;
+
+ byte store_inven_max = STORE_INVEN_MAX;
+
+ /* Some basic info */
+ do_s32b(&str->store_open, flag);
+ do_s16b(&str->insult_cur, flag);
+ do_u16b(&str->owner, flag);
+ if (flag == LS_SAVE) num = str->stock_num;
+
+ /* Could be cleaner, done this way for benefit of the for loop later on */
+ do_byte(&num, flag);
+
+ do_s16b(&str->good_buy, flag);
+ do_s16b(&str->bad_buy, flag);
+
+ /* Last visit */
+ do_s32b(&str->last_visit, flag);
+
+ /* Items */
+ for (j = 0; j < num; j++)
+ {
+ if (flag == LS_LOAD)
+ /* Can't this be cleaner? */
+ {
+ object_type forge;
+ /* Wipe the object */
+ object_wipe(&forge);
+ /* Read the item */
+ do_item(&forge, LS_LOAD);
+ /* Acquire valid items */
+ if ((str->stock_num < store_inven_max) && (str->stock_num < str->stock_size))
+ {
+ int k = str->stock_num++;
+
+ /* Acquire the item */
+ object_copy(&str->stock[k], &forge);
+ }
+ }
+ if (flag == LS_SAVE) do_item(&str->stock[j], flag);
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+/*
+ * RNG state
+ */
+static void do_randomizer(int flag)
+{
+ int i;
+
+ u16b tmp16u = 0;
+
+ /* Tmp */
+ do_u16b(&tmp16u, flag);
+
+ /* Place */
+ do_u16b(&Rand_place, flag);
+
+ /* State */
+ for (i = 0; i < RAND_DEG; i++)
+ {
+ do_u32b(&Rand_state[i], flag);
+ }
+
+ /* Accept */
+ if (flag == LS_LOAD)
+ {
+ Rand_quick = FALSE;
+ }
+}
+
+/*
+ * Handle options
+ *
+ * Normal options are stored as a set of 256 bit flags,
+ * plus a set of 256 bit masks to indicate which bit flags were defined
+ * at the time the savefile was created. This will allow new options
+ * to be added, and old options to be removed, at any time, without
+ * hurting old savefiles.
+ *
+ * The window options are stored in the same way, but note that each
+ * window gets 32 options, and their order is fixed by certain defines.
+ */
+static void do_options(int flag)
+{
+ int i, n;
+
+ u32b oflag[8];
+ u32b mask[8];
+
+ /*** Special info */
+
+ /* Read "delay_factor" */
+ do_byte(&delay_factor, flag);
+
+ /* Read "hitpoint_warn" */
+ do_byte(&hitpoint_warn, flag);
+
+ /*** Cheating options ***/
+ if (flag == LS_LOAD) /* There *MUST* be some nice way to unify this! */
+ {
+ u16b c;
+ do_u16b(&c, LS_LOAD);
+ if (c & 0x0002) wizard = TRUE;
+ cheat_peek = (c & 0x0100) ? TRUE : FALSE;
+ cheat_hear = (c & 0x0200) ? TRUE : FALSE;
+ cheat_room = (c & 0x0400) ? TRUE : FALSE;
+ cheat_xtra = (c & 0x0800) ? TRUE : FALSE;
+ cheat_know = (c & 0x1000) ? TRUE : FALSE;
+ cheat_live = (c & 0x2000) ? TRUE : FALSE;
+ }
+ if (flag == LS_SAVE)
+ {
+ u16b c = 0;
+ if (wizard) c |= 0x0002;
+ if (cheat_peek) c |= 0x0100;
+ if (cheat_hear) c |= 0x0200;
+ if (cheat_room) c |= 0x0400;
+ if (cheat_xtra) c |= 0x0800;
+ if (cheat_know) c |= 0x1000;
+ if (cheat_live) c |= 0x2000;
+ do_u16b(&c, LS_SAVE);
+ }
+
+ do_byte((byte*)&autosave_l, flag);
+ do_byte((byte*)&autosave_t, flag);
+ do_s16b(&autosave_freq, flag);
+
+ if (flag == LS_LOAD)
+ {
+ /* Read the option flags */
+ for (n = 0; n < 8; n++) do_u32b(&oflag[n], flag);
+
+ /* Read the option masks */
+ for (n = 0; n < 8; n++) do_u32b(&mask[n], flag);
+
+ /* Analyze the options */
+ for (n = 0; n < 8; n++)
+ {
+ /* Analyze the options */
+ for (i = 0; i < 32; i++)
+ {
+ /* Process valid flags */
+ if (mask[n] & (1L << i))
+ {
+ /* Process valid flags */
+ if (option_mask[n] & (1L << i))
+ {
+ /* Set */
+ if (oflag[n] & (1L << i))
+ {
+ /* Set */
+ option_flag[n] |= (1L << i);
+ }
+
+ /* Clear */
+ else
+ {
+ /* Clear */
+ option_flag[n] &= ~(1L << i);
+ }
+ }
+ }
+ }
+ }
+
+
+ /*** Window Options ***/
+
+ /* Read the window flags */
+ for (n = 0; n < 8; n++) do_u32b(&oflag[n], flag);
+
+ /* Read the window masks */
+ for (n = 0; n < 8; n++) do_u32b(&mask[n], flag);
+
+ /* Analyze the options */
+ for (n = 0; n < 8; n++)
+ {
+ /* Analyze the options */
+ for (i = 0; i < 32; i++)
+ {
+ /* Process valid flags */
+ if (mask[n] & (1L << i))
+ {
+ /* Process valid flags */
+ if (window_mask[n] & (1L << i))
+ {
+ /* Set */
+ if (oflag[n] & (1L << i))
+ {
+ /* Set */
+ window_flag[n] |= (1L << i);
+ }
+
+ /* Clear */
+ else
+ {
+ /* Clear */
+ window_flag[n] &= ~(1L << i);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (flag == LS_SAVE)
+ {
+ /* Analyze the options */
+ for (i = 0; option_info[i].o_desc; i++)
+ {
+ int os = option_info[i].o_page;
+ int ob = option_info[i].o_bit;
+
+ /* Process real entries */
+ if (option_info[i].o_var)
+ {
+ /* Set */
+ if (*option_info[i].o_var)
+ {
+ /* Set */
+ option_flag[os] |= (1L << ob);
+ }
+
+ /* Clear */
+ else
+ {
+ /* Clear */
+ option_flag[os] &= ~(1L << ob);
+ }
+ }
+ }
+
+
+ /*** Normal options ***/
+
+ /* Dump the flags */
+ for (i = 0; i < 8; i++) do_u32b(&option_flag[i], flag);
+
+ /* Dump the masks */
+ for (i = 0; i < 8; i++) do_u32b(&option_mask[i], flag);
+
+ /*** Window options ***/
+
+ /* Dump the flags */
+ for (i = 0; i < 8; i++) do_u32b(&window_flag[i], flag);
+
+ /* Dump the masks */
+ for (i = 0; i < 8; i++) do_u32b(&window_mask[i], flag);
+ }
+}
+
+
+/* Load/Save the random spells info */
+static void do_spells(int i, int flag)
+{
+ random_spell *s_ptr = &random_spells[i];
+ do_string(s_ptr->name, 30, flag);
+ do_string(s_ptr->desc, 30, flag);
+ do_s16b(&s_ptr->mana, flag);
+ do_s16b(&s_ptr->fail, flag);
+ do_u32b(&s_ptr->proj_flags, flag);
+ do_byte(&s_ptr->GF, flag);
+ do_byte(&s_ptr->radius, flag);
+ do_byte(&s_ptr->dam_sides, flag);
+ do_byte(&s_ptr->dam_dice, flag);
+ do_byte(&s_ptr->level, flag);
+ do_byte((byte*)&s_ptr->untried, flag);
+}
+
+
+/*
+ * Handle player inventory
+ *
+ * FIXME! This function probably could be unified better
+ * Note that the inventory is "re-sorted" later by "dungeon()".
+ */
+static bool_ do_inventory(int flag)
+{
+ if (flag == LS_LOAD)
+ {
+ int slot = 0;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ /* No items */
+ inven_cnt = 0;
+ equip_cnt = 0;
+
+ /* Read until done */
+ while (1)
+ {
+ u16b n;
+
+ /* Get the next item index */
+ do_u16b(&n, LS_LOAD);
+
+ /* Nope, we reached the end */
+ if (n == 0xFFFF) break;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Read the item */
+ do_item(q_ptr, LS_LOAD);
+
+ /* Hack -- verify item */
+ if (!q_ptr->k_idx) return (FALSE);
+
+ /* Wield equipment */
+ if (n >= INVEN_WIELD)
+ {
+ /* Copy object */
+ object_copy(&p_ptr->inventory[n], q_ptr);
+
+ /* Take care of item sets */
+ if (q_ptr->name1)
+ {
+ wield_set(q_ptr->name1, a_info[q_ptr->name1].set, TRUE);
+ }
+
+ /* One more item */
+ equip_cnt++;
+ }
+
+ /* Warning -- backpack is full */
+ else if (inven_cnt == INVEN_PACK)
+ {
+ /* Oops */
+ note("Too many items in the inventory!");
+
+ /* Fail */
+ return (FALSE);
+ }
+
+ /* Carry inventory */
+ else
+ {
+ /* Get a slot */
+ n = slot++;
+
+ /* Copy object */
+ object_copy(&p_ptr->inventory[n], q_ptr);
+
+ /* One more item */
+ inven_cnt++;
+ }
+ }
+ }
+ if (flag == LS_SAVE)
+ {
+ u16b i;
+ u16b sent = 0xFFFF;
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+ if (!o_ptr->k_idx) continue;
+ do_u16b(&i, flag);
+ do_item(o_ptr, flag);
+ }
+ do_u16b(&sent, LS_SAVE); /* Sentinel */
+ }
+ /* Success */
+ return (TRUE);
+}
+
+
+
+/*
+ * Read the saved messages
+ */
+static void do_messages(int flag) /* FIXME! We should be able to unify this better */
+{
+ int i;
+ char buf[128];
+ byte color, type;
+
+ s16b num;
+
+ if (flag == LS_SAVE) num = message_num();
+
+ /* Total */
+ do_s16b(&num, flag);
+
+ /* Read the messages */
+ if (flag == LS_LOAD)
+ {
+ for (i = 0; i < num; i++)
+ {
+ /* Read the message */
+ do_string(buf, 128, LS_LOAD);
+ do_byte(&color, flag);
+ do_byte(&type, flag);
+
+ /* Save the message */
+ message_add(type, buf, color);
+ }
+ }
+ if (flag == LS_SAVE)
+ {
+ byte holder;
+ for (i = num - 1; i >= 0; i--)
+ {
+ do_string((char *)message_str((s16b)i), 0, LS_SAVE);
+ holder = message_color((s16b)i);
+ do_byte(&holder, flag);
+ holder = message_type((s16b)i);
+ do_byte(&holder, flag);
+ }
+ }
+}
+
+/*
+ * Handle dungeon
+ *
+ * The monsters/objects must be loaded in the same order
+ * that they were stored, since the actual indexes matter.
+ */
+static bool_ do_dungeon(int flag, bool_ no_companions)
+{
+ int i;
+
+ cave_type *c_ptr;
+
+ /* Read specific */
+ u16b tmp16b = 0;
+
+ my_sentinel("Before do_dungeon", 324, flag);
+
+ /* Header info */
+ do_s16b(&dun_level, flag);
+ do_byte(&dungeon_type, flag);
+ do_s16b(&num_repro, flag);
+ do_s16b(&p_ptr->py, flag);
+ do_s16b(&p_ptr->px, flag);
+ do_s16b(&cur_hgt, flag);
+ do_s16b(&cur_wid, flag);
+ do_s16b(&max_panel_rows, flag);
+ do_s16b(&max_panel_cols, flag);
+
+ do_u32b(&dungeon_flags1, flag);
+ do_u32b(&dungeon_flags2, flag);
+
+ /* Last teleportation */
+ do_s16b(&last_teleportation_y, flag);
+ do_s16b(&last_teleportation_y, flag);
+
+ /* Spell effects */
+ tmp16b = MAX_EFFECTS;
+ do_u16b(&tmp16b, flag);
+
+ if ((flag == LS_LOAD) && (tmp16b > MAX_EFFECTS))
+ {
+ quit("Too many spell effects");
+ }
+
+ for (i = 0; i < tmp16b; ++i)
+ {
+ do_s16b(&effects[i].type, flag);
+ do_s16b(&effects[i].dam, flag);
+ do_s16b(&effects[i].time, flag);
+ do_u32b(&effects[i].flags, flag);
+ do_s16b(&effects[i].cx, flag);
+ do_s16b(&effects[i].cy, flag);
+ do_s16b(&effects[i].rad, flag);
+ }
+
+ /* TO prevent bugs with evolving dungeons */
+ for (i = 0; i < 100; i++)
+ {
+ do_s16b(&floor_type[i], flag);
+ do_s16b(&fill_type[i], flag);
+ }
+
+ if ((flag == LS_LOAD) && (!dun_level && !p_ptr->inside_quest))
+ {
+ int xstart = 0;
+ int ystart = 0;
+ /* Init the wilderness */
+ process_dungeon_file("w_info.txt", &ystart, &xstart, cur_hgt, cur_wid,
+ TRUE, FALSE);
+
+ /* Init the town */
+ xstart = 0;
+ ystart = 0;
+ init_flags = 0;
+ process_dungeon_file("t_info.txt", &ystart, &xstart, cur_hgt, cur_wid,
+ TRUE, FALSE);
+ }
+
+ do_grid(flag);
+
+ /*** Objects ***/
+
+ if (flag == LS_SAVE) compact_objects(0);
+ if (flag == LS_SAVE) compact_monsters(0);
+ if (flag == LS_SAVE)
+ {
+ tmp16b = o_max;
+
+ if (no_companions)
+ {
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ if (o_ptr->held_m_idx && (m_list[o_ptr->held_m_idx].status == MSTATUS_COMPANION)) tmp16b--;
+ }
+ }
+
+ /* Item count */
+ do_u16b(&tmp16b, flag);
+
+ tmp16b = o_max;
+ }
+ else
+ /* Read item count */
+ do_u16b(&tmp16b, flag);
+
+ /* Verify maximum */
+ if ((flag == LS_LOAD) && (tmp16b > max_o_idx))
+ {
+ note(format("Too many (%d) object entries!", tmp16b));
+ return (FALSE);
+ }
+
+ /* Dungeon items */
+ for (i = 1; i < tmp16b; i++)
+ {
+ int o_idx;
+
+ object_type *o_ptr;
+
+ if (flag == LS_SAVE)
+ {
+ o_ptr = &o_list[i];
+ /* Don't save objects held by companions when no_companions is set */
+ if (no_companions && o_ptr->held_m_idx && (m_list[o_ptr->held_m_idx].status == MSTATUS_COMPANION)) continue;
+
+ do_item(o_ptr, LS_SAVE);
+ continue; /* Saving is easy */
+ }
+ /* Until the end of the loop, this is all LS_LOAD */
+
+ /* Get a new record */
+ o_idx = o_pop();
+
+ /* Oops */
+ if (i != o_idx)
+ {
+ note(format("Object allocation error (%d <> %d)", i, o_idx));
+ return (FALSE);
+ }
+
+
+ /* Acquire place */
+ o_ptr = &o_list[o_idx];
+
+ /* Read the item */
+ do_item(o_ptr, LS_LOAD);
+
+ /* Monster */
+ if (o_ptr->held_m_idx)
+ {
+ monster_type *m_ptr;
+
+ /* Monster */
+ m_ptr = &m_list[o_ptr->held_m_idx];
+
+ /* Build a stack */
+ o_ptr->next_o_idx = m_ptr->hold_o_idx;
+
+ /* Place the object */
+ m_ptr->hold_o_idx = o_idx;
+ }
+
+ /* Dungeon */
+ else
+ {
+ /* Access the item location */
+ c_ptr = &cave[o_ptr->iy][o_ptr->ix];
+
+ /* Build a stack */
+ o_ptr->next_o_idx = c_ptr->o_idx;
+
+ /* Place the object */
+ c_ptr->o_idx = o_idx;
+ }
+ }
+
+ /*** Monsters ***/
+
+ if (flag == LS_SAVE)
+ {
+ tmp16b = m_max;
+
+ if (no_companions)
+ {
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+
+ if (m_ptr->status == MSTATUS_COMPANION) tmp16b--;
+ }
+ }
+
+ /* Write the monster count */
+ do_u16b(&tmp16b, flag);
+
+ tmp16b = m_max;
+ }
+ else
+ /* Read the monster count */
+ do_u16b(&tmp16b, flag);
+
+ /* Validate */
+ if ((flag == LS_LOAD) && (tmp16b > max_m_idx))
+ {
+ note(format("Too many (%d) monster entries!", tmp16b));
+ return (FALSE);
+ }
+
+ /* Read the monsters */
+ for (i = 1; i < tmp16b; i++)
+ {
+ int m_idx;
+ monster_type *m_ptr;
+ monster_race *r_ptr;
+
+ if (flag == LS_SAVE)
+ {
+ m_ptr = &m_list[i];
+
+ /* Don't save companions when no_companions is set */
+ if (no_companions && m_ptr->status == MSTATUS_COMPANION) continue;
+
+ do_monster(m_ptr, LS_SAVE);
+ continue; /* Easy to save a monster */
+ }
+ /* From here on, it's all LS_LOAD */
+ /* Get a new record */
+ m_idx = m_pop();
+
+ /* Oops */
+ if (i != m_idx)
+ {
+ note(format("Monster allocation error (%d <> %d)", i, m_idx));
+ return (FALSE);
+ }
+
+ /* Acquire monster */
+ m_ptr = &m_list[m_idx];
+
+ /* Read the monster */
+ do_monster(m_ptr, LS_LOAD);
+
+ /* Access grid */
+ c_ptr = &cave[m_ptr->fy][m_ptr->fx];
+
+ /* Mark the location */
+ c_ptr->m_idx = m_idx;
+
+ /* Controlled ? */
+ if (m_ptr->mflag & MFLAG_CONTROL)
+ p_ptr->control = m_idx;
+
+ /* Access race */
+ r_ptr = &r_info[m_ptr->r_idx];
+
+ /* Count XXX XXX XXX */
+ r_ptr->cur_num++;
+ }
+
+ /* Read the kept monsters */
+
+ tmp16b = (flag == LS_SAVE && !no_companions) ? max_m_idx : 0;
+
+ /* Read the monster count */
+ do_u16b(&tmp16b, flag);
+
+ /* Hack -- verify */
+ if ((flag == LS_LOAD) && (tmp16b > max_m_idx))
+ {
+ note(format("Too many (%d) monster entries!", tmp16b));
+ return (FALSE);
+ }
+ for (i = 1; i < tmp16b; i++)
+ {
+ monster_type *m_ptr;
+
+ /* Acquire monster */
+ m_ptr = &km_list[i];
+
+ /* Read the monster */
+ do_monster(m_ptr, flag);
+ }
+
+ /*** Success ***/
+
+ /* The dungeon is ready */
+ if (flag == LS_LOAD) character_dungeon = TRUE;
+
+ /* Success */
+ return (TRUE);
+}
+
+/* Returns TRUE if we successfully load the dungeon */
+bool_ load_dungeon(char *ext)
+{
+ char tmp[16];
+ char name[1024];
+ byte old_dungeon_type = dungeon_type;
+ s16b old_dun = dun_level;
+
+ /* Construct name */
+ sprintf(tmp, "%s.%s", player_base, ext);
+ path_build(name, 1024, ANGBAND_DIR_SAVE, tmp);
+
+ /* Open the file */
+ fff = my_fopen(name, "rb");
+
+ if (fff == NULL)
+ {
+ dun_level = old_dun;
+ dungeon_type = old_dungeon_type;
+
+ my_fclose(fff);
+ return (FALSE);
+ }
+
+ /* Read the dungeon */
+ if (!do_dungeon(LS_LOAD, FALSE))
+ {
+ dun_level = old_dun;
+ dungeon_type = old_dungeon_type;
+
+ my_fclose(fff);
+ return (FALSE);
+ }
+
+ dun_level = old_dun;
+ dungeon_type = old_dungeon_type;
+
+ /* Done */
+ my_fclose(fff);
+ return (TRUE);
+}
+
+void do_blocks(int flag)
+/* Handle blocked-allocation stuff for quests and lua stuff
+ This depends on a dyn_tosave array of s32b's. Adjust as needed
+ if other data structures are desirable. This also is not hooked
+ in yet. Ideally, plug it near the end of the savefile.
+ */
+{
+ s16b numblks, n_iter = 0; /* How many blocks do we have? */
+ do_s16b(&numblks, flag);
+ while (n_iter < numblks)
+ {
+ /* do_s32b(dyn_tosave[n_iter], flag); */
+ n_iter++;
+ }
+ my_sentinel("In blocked-allocation area", 37, flag);
+}
+
+void do_fate(int i, int flag)
+{
+ if ((flag == LS_LOAD) && (i >= MAX_FATES)) i = MAX_FATES - 1;
+
+ do_byte(&fates[i].fate, flag);
+ do_byte(&fates[i].level, flag);
+ do_byte(&fates[i].serious, flag);
+ do_s16b(&fates[i].o_idx, flag);
+ do_s16b(&fates[i].e_idx, flag);
+ do_s16b(&fates[i].a_idx, flag);
+ do_s16b(&fates[i].v_idx, flag);
+ do_s16b(&fates[i].r_idx, flag);
+ do_s16b(&fates[i].count, flag);
+ do_s16b(&fates[i].time, flag);
+ do_byte((byte*)&fates[i].know, flag);
+}
+
+/*
+ * Actually read the savefile
+ */
+static bool_ do_savefile_aux(int flag)
+{
+ int i, j;
+
+ byte tmp8u;
+ u16b tmp16u;
+ u32b tmp32u;
+
+ bool_ *reals;
+ u16b real_max = 0;
+
+ /* Mention the savefile version */
+ if (flag == LS_LOAD)
+ {
+ if (vernum < 100)
+ {
+ note(format("Savefile version %lu too old! ", vernum));
+ return FALSE;
+ }
+ else
+ {
+ note(format("Loading version %lu savefile... ", vernum));
+ }
+ }
+ if (flag == LS_SAVE)
+ {
+ sf_when = time((time_t *) 0); /* Note when file was saved */
+ sf_xtra = 0L; /* What the hell is this? */
+ sf_saves++; /* Increment the saves ctr */
+ }
+
+ /* Handle version bytes. FIXME! DG wants me to change this all around */
+ if (flag == LS_LOAD)
+ {
+ u32b mt32b;
+ byte mtbyte;
+
+ /* Discard all this, we've already read it */
+ do_u32b(&mt32b, flag);
+ do_byte(&mtbyte, flag);
+ }
+ if (flag == LS_SAVE)
+ {
+ u32b saver;
+ saver = SAVEFILE_VERSION;
+ do_u32b(&saver, flag);
+ tmp8u = (byte)rand_int(256);
+ do_byte(&tmp8u, flag); /* 'encryption' */
+ }
+
+ /* Operating system info? Not really. This is just set to 0L */
+ do_u32b(&sf_xtra, flag);
+
+ /* Time of last save */
+ do_u32b(&sf_when, flag);
+
+ /* Number of past lives */
+ do_u16b(&sf_lives, flag);
+
+ /* Number of times saved */
+ do_u16b(&sf_saves, flag);
+
+ /* Game module */
+ if (flag == LS_SAVE)
+ strcpy(loaded_game_module, game_module);
+ do_string(loaded_game_module, 80, flag);
+
+ /* Read RNG state */
+ do_randomizer(flag);
+ if ((flag == LS_LOAD) && (arg_fiddle)) note("Loaded Randomizer Info");
+
+ /* Automatizer state */
+ do_byte((byte*)&automatizer_enabled, flag);
+
+ /* Then the options */
+ do_options(flag);
+ if ((flag == LS_LOAD) && (arg_fiddle)) note("Loaded Option Flags");
+
+ /* Then the "messages" */
+ do_messages(flag);
+ if ((flag == LS_LOAD) && (arg_fiddle)) note("Loaded Messages");
+
+ /* Monster Memory */
+ if (flag == LS_SAVE) tmp16u = max_r_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (tmp16u > max_r_idx))
+ {
+ note(format("Too many (%u) monster races!", tmp16u));
+ return (FALSE);
+ }
+
+ /* Read the available records */
+ for (i = 0; i < tmp16u; i++)
+ {
+ /* Read the lore */
+ do_lore(i, flag);
+ }
+
+ if ((flag == LS_LOAD) && (arg_fiddle)) note("Loaded Monster Memory");
+ /* Object Memory */
+ if (flag == LS_SAVE) tmp16u = max_k_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (tmp16u > max_k_idx))
+ {
+ note(format("Too many (%u) object kinds!", tmp16u));
+ return (FALSE);
+ }
+
+ /* Read the object memory */
+ for (i = 0; i < tmp16u; i++) do_xtra(i, flag);
+ if ((flag == LS_LOAD) && (arg_fiddle)) note("Loaded Object Memory");
+ if (flag == LS_LOAD) junkinit();
+
+ {
+ u16b max_towns_ldsv;
+ u16b max_quests_ldsv;
+ if (flag == LS_SAVE) max_towns_ldsv = max_towns;
+ /* Number of towns */
+ do_u16b(&max_towns_ldsv, flag);
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (max_towns_ldsv > max_towns))
+ {
+ note(format("Too many (%u) towns!", max_towns_ldsv));
+ return (FALSE);
+ }
+ /* Min of random towns */
+ if (flag == LS_SAVE) max_towns_ldsv = TOWN_RANDOM;
+ do_u16b(&max_towns_ldsv, flag);
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (max_towns_ldsv != TOWN_RANDOM))
+ {
+ note(format("Different random towns base (%u)!", max_towns_ldsv));
+ return (FALSE);
+ }
+
+ for (i = 0; i < max_towns; i++)
+ {
+ do_byte((byte*)&town_info[i].destroyed, flag);
+
+ if (i >= TOWN_RANDOM)
+ {
+ do_u32b(&town_info[i].seed, flag);
+ do_byte(&town_info[i].numstores, flag);
+ do_byte(&town_info[i].flags, flag);
+
+ /* If the town is realy used create a sock */
+ if ((town_info[i].flags & (TOWN_REAL)) && (flag == LS_LOAD))
+ {
+ create_stores_stock(i);
+ }
+ }
+ }
+
+ /* Number of dungeon */
+ if (flag == LS_SAVE) max_towns_ldsv = max_d_idx;
+ do_u16b(&max_towns_ldsv, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (max_towns_ldsv > max_d_idx))
+ {
+ note(format("Too many dungeon types (%u)!", max_towns_ldsv));
+ return (FALSE);
+ }
+
+ /* Number of towns per dungeon */
+ if (flag == LS_SAVE) max_quests_ldsv = TOWN_DUNGEON;
+ do_u16b(&max_quests_ldsv, flag);
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (max_quests_ldsv > TOWN_DUNGEON))
+ {
+ note(format("Too many town per dungeons (%u)!", max_quests_ldsv));
+ return (FALSE);
+ }
+
+ for (i = 0; i < max_towns_ldsv; i++)
+ {
+ for (j = 0; j < max_quests_ldsv; j++)
+ {
+ do_s16b(&(d_info[i].t_idx[j]), flag);
+ do_s16b(&(d_info[i].t_level[j]), flag);
+ }
+ do_s16b(&(d_info[i].t_num), flag);
+ }
+
+ if (flag == LS_SAVE) max_quests_ldsv = MAX_Q_IDX_INIT;
+ /* Number of quests */
+ do_u16b(&max_quests_ldsv, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (max_quests_ldsv > MAX_Q_IDX_INIT))
+ {
+ note(format("Too many (%u) quests!", max_quests_ldsv));
+ return (FALSE);
+ }
+
+ for (i = 0; i < max_quests_ldsv; i++)
+ {
+ do_s16b(&quest[i].status, flag);
+ for (j = 0; j < 4; j++)
+ {
+ do_s32b(&(quest[i].data[j]), flag);
+ }
+
+ /* Init the hooks */
+ if ((flag == LS_LOAD) && (quest[i].type == HOOK_TYPE_C)) quest[i].init(i);
+ }
+
+ /* Position in the wilderness */
+ do_s32b(&p_ptr->wilderness_x, flag);
+ do_s32b(&p_ptr->wilderness_y, flag);
+ do_byte((byte*)&p_ptr->wild_mode, flag);
+ do_byte((byte*)&p_ptr->old_wild_mode, flag);
+
+ {
+ s32b wild_x_size, wild_y_size;
+ if (flag == LS_SAVE)
+ {
+ wild_x_size = max_wild_x;
+ wild_y_size = max_wild_y;
+ }
+ /* Size of the wilderness */
+ do_s32b(&wild_x_size, flag);
+ do_s32b(&wild_y_size, flag);
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) &&
+ ((wild_x_size > max_wild_x) || (wild_y_size > max_wild_y)))
+ {
+ note(format("Wilderness is too big (%u/%u)!",
+ wild_x_size, wild_y_size));
+ return (FALSE);
+ }
+ /* Wilderness seeds */
+ for (i = 0; i < wild_x_size; i++)
+ {
+ for (j = 0; j < wild_y_size; j++)
+ {
+ do_u32b(&wild_map[j][i].seed, flag);
+ do_u16b(&wild_map[j][i].entrance, flag);
+ do_byte((byte*)&wild_map[j][i].known, flag);
+ }
+ }
+ }
+ }
+ if ((flag == LS_LOAD) && (arg_fiddle)) note("Loaded Quests");
+
+ /* Load the random artifacts. */
+ if (flag == LS_SAVE) tmp16u = MAX_RANDARTS;
+ do_u16b(&tmp16u, flag);
+ if ((flag == LS_LOAD) && (tmp16u > MAX_RANDARTS))
+ {
+ note(format("Too many (%u) random artifacts!", tmp16u));
+ return (FALSE);
+ }
+ for (i = 0; i < tmp16u; i++)
+ {
+ random_artifact *ra_ptr = &random_artifacts[i];
+
+ do_string(ra_ptr->name_full, 80, flag);
+ do_string(ra_ptr->name_short, 80, flag);
+ do_byte(&ra_ptr->level, flag);
+ do_byte(&ra_ptr->attr, flag);
+ do_u32b(&ra_ptr->cost, flag);
+ do_byte(&ra_ptr->activation, flag);
+ do_byte(&ra_ptr->generated, flag);
+ }
+
+ /* Load the Artifacts */
+ if (flag == LS_SAVE) tmp16u = max_a_idx;
+ do_u16b(&tmp16u, flag);
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (tmp16u > max_a_idx))
+ {
+ note(format("Too many (%u) artifacts!", tmp16u));
+ return (FALSE);
+ }
+
+ /* Read the artifact flags */
+ for (i = 0; i < tmp16u; i++)
+ {
+ do_byte(&(&a_info[i])->cur_num, flag);
+ }
+ if ((flag == LS_LOAD) && arg_fiddle) note("Loaded Artifacts");
+
+ /* Fates */
+ if (flag == LS_SAVE) tmp16u = MAX_FATES;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (tmp16u > MAX_FATES))
+ {
+ note(format("Too many (%u) fates!", tmp16u));
+ return (FALSE);
+ }
+
+ /* Read the fate flags */
+ for (i = 0; i < tmp16u; i++)
+ {
+ do_fate(i, flag);
+ }
+ if ((flag == LS_LOAD) && arg_fiddle) note("Loaded Fates");
+
+ /* Load the Traps */
+ if (flag == LS_SAVE) tmp16u = max_t_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (tmp16u > max_t_idx))
+ {
+ note(format("Too many (%u) traps!", tmp16u));
+ return (FALSE);
+ }
+
+ /* fate flags */
+ for (i = 0; i < tmp16u; i++)
+ {
+ do_byte((byte*)&t_info[i].ident, flag);
+ }
+ if ((flag == LS_LOAD) && (arg_fiddle)) note("Loaded Traps");
+
+ /* inscription knowledge */
+ if (flag == LS_SAVE) tmp16u = MAX_INSCRIPTIONS;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (tmp16u > MAX_INSCRIPTIONS))
+ {
+ note(format("Too many (%u) inscriptions!", tmp16u));
+ return (FALSE);
+ }
+
+ /* Read the inscription flag */
+ for (i = 0; i < tmp16u; i++)
+ do_byte((byte*)&inscription_info[i].know, flag);
+ if ((flag == LS_LOAD) && arg_fiddle) note("Loaded Inscriptions");
+
+
+ /* Read the extra stuff */
+ if (!do_extra(flag))
+ return FALSE;
+ if ((flag == LS_LOAD) && arg_fiddle) note("Loaded extra information");
+
+
+ /* player_hp array */
+ if (flag == LS_SAVE) tmp16u = PY_MAX_LEVEL;
+ do_u16b(&tmp16u, flag);
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (tmp16u > PY_MAX_LEVEL))
+ {
+ note(format("Too many (%u) hitpoint entries!", tmp16u));
+ return (FALSE);
+ }
+
+ /* Read the player_hp array */
+ for (i = 0; i < tmp16u; i++)
+ {
+ do_s16b(&player_hp[i], flag);
+ }
+
+ if (flag == LS_LOAD) morejunk();
+
+ /* Read the pet command settings */
+ do_byte(&p_ptr->pet_follow_distance, flag);
+ do_byte(&p_ptr->pet_open_doors, flag);
+ do_byte(&p_ptr->pet_pickup_items, flag);
+
+ /* Read the inventory */
+ if (!do_inventory(flag) && (flag == LS_LOAD)) /* do NOT reverse this ordering */
+ {
+ note("Unable to read inventory");
+ return (FALSE);
+ }
+
+ /* Note that this forbids max_towns from shrinking, but that is fine */
+ C_MAKE(reals, max_towns, bool_);
+
+ /* Find the real towns */
+ if (flag == LS_SAVE)
+ {
+ for (i = 1; i < max_towns; i++)
+ {
+ if (!(town_info[i].flags & (TOWN_REAL))) continue;
+ reals[real_max++] = i;
+ }
+ }
+ do_u16b(&real_max, flag);
+ for (i = 0; i < real_max; i++)
+ {
+ do_byte((byte*)&reals[i], flag);
+ }
+
+ /* Read the stores */
+ if (flag == LS_SAVE) tmp16u = max_st_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Ok now read the real towns */
+ for (i = 0; i < real_max; i++)
+ {
+ int z = reals[i];
+
+ /* Ultra paranoia */
+ if (!town_info[z].stocked) create_stores_stock(z);
+
+ for (j = 0; j < tmp16u; j++)
+ do_store(&town_info[z].store[j], flag);
+ }
+
+ C_FREE(reals, max_towns, bool_);
+
+ if (flag == LS_SAVE) tmp32u = extra_savefile_parts;
+ do_u32b(&tmp32u, flag);
+ if (flag == LS_SAVE)
+ {
+ /* Save the stuff */
+ process_hooks(HOOK_SAVE_GAME, "()");
+ }
+
+ if (flag == LS_LOAD)
+ {
+ u32b len = tmp32u;
+
+ while (len)
+ {
+ char key_buf[100];
+
+ /* Load a key */
+ load_number_key(key_buf, &tmp32u);
+
+ /* Process it -- the hooks can use it or ignore it */
+ process_hooks(HOOK_LOAD_GAME, "(s,l)", key_buf, tmp32u);
+ len--;
+ }
+ }
+
+ /* I'm not dead yet... */
+ if (!death)
+ {
+ /* Dead players have no dungeon */
+ if (flag == LS_LOAD) note("Restoring Dungeon...");
+ if ((flag == LS_LOAD) && (!do_dungeon(LS_LOAD, FALSE)))
+ {
+ note("Error reading dungeon data");
+ return (FALSE);
+ }
+ if (flag == LS_SAVE) do_dungeon(LS_SAVE, FALSE);
+ my_sentinel("Before ghost data", 435, flag);
+ my_sentinel("After ghost data", 320, flag);
+ }
+
+ {
+ byte foo = 0;
+ if (flag == LS_SAVE)
+ {
+ /*
+ * Safety Padding. It's there
+ * for a good reason. Trust me on
+ * this. Keep this at the *END*
+ * of the file, and do *NOT* try to
+ * read it. Insert any new stuff before
+ * this position.
+ */
+ do_byte(&foo, LS_SAVE);
+ }
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Actually read the savefile
+ */
+errr rd_savefile(void)
+{
+ errr err = 0;
+
+ /* The savefile is a binary file */
+ fff = my_fopen(savefile, "rb");
+
+ /* Paranoia */
+ if (!fff) return ( -1);
+
+ /* Call the sub-function */
+ err = !do_savefile_aux(LS_LOAD);
+
+ /* Check for errors */
+ if (ferror(fff)) err = -1;
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Result */
+ return (err);
+}
+
+/*
+ * Note that this function may not be needed at all.
+ * It was taken out of load_player_aux(). Do we need it?
+ */
+static void junkinit(void)
+{
+ int i, j;
+ p_ptr->arena_number = 0;
+ p_ptr->inside_arena = 0;
+ p_ptr->inside_quest = 0;
+ p_ptr->exit_bldg = TRUE;
+ p_ptr->exit_bldg = TRUE;
+ p_ptr->town_num = 1;
+ p_ptr->wilderness_x = 4;
+ p_ptr->wilderness_y = 4;
+ for (i = 0; i < max_wild_x; i++)
+ {
+ for (j = 0; j < max_wild_y; j++)
+ {
+ wild_map[j][i].seed = rand_int(0x10000000);
+ }
+ }
+}
+
+static void morejunk(void)
+{
+ sp_ptr = &sex_info[p_ptr->psex]; /* Sex */
+ rp_ptr = &race_info[p_ptr->prace]; /* Raceclass */
+ rmp_ptr = &race_mod_info[p_ptr->pracem];
+ cp_ptr = &class_info[p_ptr->pclass];
+ spp_ptr = &class_info[p_ptr->pclass].spec[p_ptr->pspec];
+}
+
+static void do_grid(int flag)
+/* Does the grid, RLE, blahblah. RLE sucks. I hate it. */
+{
+ int i = 0, y = 0, x = 0;
+ byte count = 0;
+ byte tmp8u = 0;
+ s16b tmp16s = 0;
+ cave_type *c_ptr;
+ byte prev_char = 0;
+ s16b prev_s16b = 0;
+ int ymax = cur_hgt, xmax = cur_wid;
+
+ int part; /* Which section of the grid we're on */
+
+ for (part = 0; part < 9; part++) /* There are 8 fields to the grid, each stored
+ in a seperate RLE data structure */
+ {
+ if (flag == LS_SAVE)
+ {
+ count = 0;
+ prev_s16b = 0;
+ prev_char = 0; /* Clear, prepare for RLE */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ c_ptr = &cave[y][x];
+ switch (part)
+ {
+ case 0:
+ tmp16s = c_ptr->info;
+ break;
+
+ case 1:
+ tmp8u = c_ptr->feat;
+ break;
+
+ case 2:
+ tmp8u = c_ptr->mimic;
+ break;
+
+ case 3:
+ tmp16s = c_ptr->special;
+ break;
+
+ case 4:
+ tmp16s = c_ptr->special2;
+ break;
+
+ case 5:
+ tmp16s = c_ptr->t_idx;
+ break;
+
+ case 6:
+ tmp16s = c_ptr->inscription;
+ break;
+
+ case 7:
+ tmp8u = c_ptr->mana;
+ break;
+
+ case 8:
+ tmp16s = c_ptr->effect;
+ break;
+ }
+ /* Flush a full run */
+ if ((((part != 1) && (part != 2) && (part != 7)) &&
+ (tmp16s != prev_s16b)) || (((part == 1) || (part == 2)
+ || (part == 7)) &&
+ (tmp8u != prev_char)) ||
+ (count == MAX_UCHAR))
+ {
+ do_byte(&count, LS_SAVE);
+ switch (part)
+ {
+ case 0:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 8:
+ do_s16b(&prev_s16b, LS_SAVE);
+ prev_s16b = tmp16s;
+ break;
+
+ case 1:
+ case 2:
+ case 7:
+ do_byte(&prev_char, LS_SAVE);
+ prev_char = tmp8u;
+ break;
+ }
+ count = 1; /* Reset RLE */
+ }
+ else
+ count++; /* Otherwise, keep going */
+ }
+ }
+ /* Fallen off the end of the world, flush anything left */
+ if (count)
+ {
+ do_byte(&count, LS_SAVE);
+ switch (part)
+ {
+ case 0:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 8:
+ do_s16b(&prev_s16b, LS_SAVE);
+ break;
+
+ case 1:
+ case 2:
+ case 7:
+ do_byte(&prev_char, LS_SAVE);
+ break;
+ }
+ }
+ }
+ if (flag == LS_LOAD)
+ {
+ x = 0;
+ for (y = 0; y < ymax; )
+ {
+ do_byte(&count, LS_LOAD);
+ switch (part)
+ {
+ case 0:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 8:
+ do_s16b(&tmp16s, LS_LOAD);
+ break;
+
+ case 1:
+ case 2:
+ case 7:
+ do_byte(&tmp8u, LS_LOAD);
+ break;
+ }
+ for (i = count; i > 0; i--) /* RLE */
+ {
+ c_ptr = &cave[y][x];
+ switch (part)
+ {
+ case 0:
+ c_ptr->info = tmp16s;
+ break;
+
+ case 1:
+ c_ptr->feat = tmp8u;
+ break;
+
+ case 2:
+ c_ptr->mimic = tmp8u;
+ break;
+
+ case 3:
+ c_ptr->special = tmp16s;
+ break;
+
+ case 4:
+ c_ptr->special2 = tmp16s;
+ break;
+
+ case 5:
+ c_ptr->t_idx = tmp16s;
+ break;
+
+ case 6:
+ c_ptr->inscription = tmp16s;
+ break;
+
+ case 7:
+ c_ptr->mana = tmp8u;
+ break;
+
+ case 8:
+ c_ptr->effect = tmp16s;
+ break;
+ }
+ if (++x >= xmax)
+ {
+ /* Wrap */
+ x = 0;
+ if ((++y) >= ymax) break;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void my_sentinel(char *place, u16b value, int flag)
+/* This function lets us know exactly where a savefile is
+ broken by reading/writing conveniently a sentinel at this
+ spot */
+{
+ if (flag == LS_SAVE)
+ {
+ do_u16b(&value, flag);
+ return;
+ }
+ if (flag == LS_LOAD)
+ {
+ u16b found;
+ do_u16b(&found, flag);
+ if (found == value) /* All is good */
+ return;
+ /* All is bad */
+ note(format("Savefile broken %s", place));
+ return;
+ }
+ note(format("Impossible has occurred")); /* Programmer error */
+ exit(0);
+}
+
+/********** Variable savefile stuff **************/
+
+/*
+ * Add num slots to the savefile
+ */
+void register_savefile(int num)
+{
+ extra_savefile_parts += (num > 0) ? num : 0;
+}
+
+void save_number_key(char *key, u32b val)
+{
+ byte len = strlen(key);
+
+ do_byte(&len, LS_SAVE);
+ while (*key)
+ {
+ do_byte((byte*)key, LS_SAVE);
+ key++;
+ }
+ do_u32b(&val, LS_SAVE);
+}
+
+void load_number_key(char *key, u32b *val)
+{
+ byte len, i = 0;
+
+ do_byte(&len, LS_LOAD);
+ while (i < len)
+ {
+ do_byte((byte*)&key[i], LS_LOAD);
+ i++;
+ }
+ key[i] = '\0';
+ do_u32b(val, LS_LOAD);
+}
diff --git a/src/lua/.cvsignore b/src/lua/.cvsignore
new file mode 100644
index 00000000..0b086004
--- /dev/null
+++ b/src/lua/.cvsignore
@@ -0,0 +1,2 @@
+tolua
+host
diff --git a/src/lua/.gitignore b/src/lua/.gitignore
new file mode 100644
index 00000000..26548e17
--- /dev/null
+++ b/src/lua/.gitignore
@@ -0,0 +1,2 @@
+/liblua.a
+/tolua
diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt
new file mode 100644
index 00000000..df2b30e7
--- /dev/null
+++ b/src/lua/CMakeLists.txt
@@ -0,0 +1,11 @@
+ADD_LIBRARY (lua STATIC
+ lapi.c lcode.c ldebug.c ldo.c lfunc.c lgc.c
+ llex.c lmem.c lobject.c lparser.c lstate.c lstring.c
+ ltable.c ltests.c ltm.c lundump.c lvm.c lzio.c
+ lauxlib.c lbaselib.c ldblib.c liolib.c lstrlib.c
+ tolua_lb.c tolua_rg.c tolua_tt.c tolua_tm.c tolua_gp.c
+ tolua_eh.c tolua_bd.c)
+
+ADD_EXECUTABLE(tolua tolua.c tolualua.c lua)
+
+TARGET_LINK_LIBRARIES(tolua lua)
diff --git a/src/lua/array.lua b/src/lua/array.lua
new file mode 100644
index 00000000..7929f8cd
--- /dev/null
+++ b/src/lua/array.lua
@@ -0,0 +1,203 @@
+-- tolua: array class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1999
+-- $Id: array.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Array class
+-- Represents a extern array variable or a public member of a class.
+-- Stores all fields present in a declaration.
+classArray = {
+ _base = classDeclaration,
+}
+
+settag(classArray,tolua_tag)
+
+-- Print method
+function classArray:print (ident,close)
+ print(ident.."Array{")
+ print(ident.." mod = '"..self.mod.."',")
+ print(ident.." type = '"..self.type.."',")
+ print(ident.." ptr = '"..self.ptr.."',")
+ print(ident.." name = '"..self.name.."',")
+ print(ident.." def = '"..self.def.."',")
+ print(ident.." dim = '"..self.dim.."',")
+ print(ident.." ret = '"..self.ret.."',")
+ print(ident.."}"..close)
+end
+
+-- get variable value
+function classArray:getvalue (class,static)
+ if class and static then
+ return class..'::'..self.name..'[toluaI_index]'
+ elseif class then
+ return 'self->'..self.name..'[toluaI_index]'
+ else
+ return self.name..'[toluaI_index]'
+ end
+end
+
+-- Write binding functions
+function classArray:supcode ()
+ local class = self:inclass()
+
+ -- get function ------------------------------------------------
+ if class then
+ output("/* get function:",self.name," of class ",class," */")
+ else
+ output("/* get function:",self.name," */")
+ end
+ self.cgetname = self:cfuncname("toluaI_get")
+ output("static int",self.cgetname,"(lua_State* tolua_S)")
+ output("{")
+
+ -- declare index
+ output(' int toluaI_index;')
+
+ -- declare self, if the case
+ local _,_,static = strfind(self.mod,'^%s*(static)')
+ if class and static==nil then
+ output(' ',class,'*','self;')
+ output(' lua_pushstring(tolua_S,".self");')
+ output(' lua_rawget(tolua_S,1);')
+ output(' self = ')
+ output('(',class,'*) ')
+ output('lua_touserdata(tolua_S,-1);')
+ elseif static then
+ _,_,self.mod = strfind(self.mod,'^%s*static%s%s*(.*)')
+ end
+
+ -- check index
+ output(' if (!tolua_istype(tolua_S,2,LUA_TNUMBER,0))')
+ output(' tolua_error(tolua_S,"invalid type in array indexing.");')
+ output(' toluaI_index = (int)tolua_getnumber(tolua_S,2,0)-1;')
+ output(' if (toluaI_index<0 || toluaI_index>='..self.dim..')')
+ output(' tolua_error(tolua_S,"array indexing out of range.");')
+
+ -- return value
+ local t,ct = isbasic(self.type)
+ if t then
+ output(' tolua_push'..t..'(tolua_S,(',ct,')'..self:getvalue(class,static)..');')
+ else
+ if self.ptr == '&' or self.ptr == '' then
+ output(' tolua_pushusertype(tolua_S,(void*)&'..self:getvalue(class,static)..',',self.tag,');')
+ else
+ output(' tolua_pushusertype(tolua_S,(void*)'..self:getvalue(class,static)..',',self.tag,');')
+ end
+ end
+ output(' return 1;')
+ output('}')
+ output('\n')
+
+ -- set function ------------------------------------------------
+ if not strfind(self.mod,'const') then
+ if class then
+ output("/* set function:",self.name," of class ",class," */")
+ else
+ output("/* set function:",self.name," */")
+ end
+ self.csetname = self:cfuncname("toluaI_set")
+ output("static int",self.csetname,"(lua_State* tolua_S)")
+ output("{")
+
+ -- declare index
+ output(' int toluaI_index;')
+
+ -- declare self, if the case
+ local _,_,static = strfind(self.mod,'^%s*(static)')
+ if class and static==nil then
+ output(' ',class,'*','self;')
+ output(' lua_pushstring(tolua_S,".self");')
+ output(' lua_rawget(tolua_S,1);')
+ output(' self = ')
+ output('(',class,'*) ')
+ output('lua_touserdata(tolua_S,-1);')
+ elseif static then
+ _,_,self.mod = strfind(self.mod,'^%s*static%s%s*(.*)')
+ end
+
+ -- check index
+ output(' if (!tolua_istype(tolua_S,2,LUA_TNUMBER,0))')
+ output(' tolua_error(tolua_S,"invalid type in array indexing.");')
+ output(' toluaI_index = (int)tolua_getnumber(tolua_S,2,0)-1;')
+ output(' if (toluaI_index<0 || toluaI_index>='..self.dim..')')
+ output(' tolua_error(tolua_S,"array indexing out of range.");')
+
+ -- assign value
+ local ptr = ''
+ if self.ptr~='' then ptr = '*' end
+ output(' ')
+ if class and static then
+ output(class..'::'..self.name..'[toluaI_index]')
+ elseif class then
+ output('self->'..self.name..'[toluaI_index]')
+ else
+ output(self.name..'[toluaI_index]')
+ end
+ local t = isbasic(self.type)
+ output(' = ')
+ if not t and ptr=='' then output('*') end
+ output('((',self.mod,self.type)
+ if not t then
+ output('*')
+ end
+ output(') ')
+ local def = 0
+ if self.def ~= '' then def = self.def end
+ if t then
+ output('tolua_get'..t,'(tolua_S,3,',def,'));')
+ else
+ output('tolua_getusertype(tolua_S,3,',def,'));')
+ end
+ output(' return 0;')
+ output('}')
+ output('\n')
+ end
+
+end
+
+function classArray:register ()
+ local parent = self:inclass() or self:inmodule()
+ if parent then
+ if self.csetname then
+ output(' tolua_tablearray(tolua_S,"'..parent..'","'..self.lname..'",'..self.cgetname..','..self.csetname..');')
+ else
+ output(' tolua_tablearray(tolua_S,"'..parent..'","'..self.lname..'",'..self.cgetname..',NULL);')
+ end
+ else
+ if self.csetname then
+ output(' tolua_globalarray(tolua_S,"'..self.lname..'",'..self.cgetname..','..self.csetname..');')
+ else
+ output(' tolua_globalarray(tolua_S,"'..self.lname..'",'..self.cgetname..',NULL);')
+ end
+ end
+end
+
+function classArray:unregister ()
+ if self:inclass()==nil and self:inmodule()==nil then
+ output(' lua_pushnil(tolua_S); lua_setglobal(tolua_S,"'..self.lname..'");')
+ end
+end
+
+
+-- Internal constructor
+function _Array (t)
+ t._base = classArray
+ settag(t,tolua_tag)
+ append(t)
+ return t
+end
+
+-- Constructor
+-- Expects a string representing the variable declaration.
+function Array (s)
+ return _Array (Declaration(s,'var'))
+end
+
+
diff --git a/src/lua/basic.lua b/src/lua/basic.lua
new file mode 100644
index 00000000..2bac463f
--- /dev/null
+++ b/src/lua/basic.lua
@@ -0,0 +1,190 @@
+-- tolua: basic utility functions
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: basic.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Basic C types and their corresponding Lua types
+-- All occurrences of "char*" will be replaced by "_cstring",
+-- and all occurrences of "void*" will be replaced by "_userdata"
+_basic = {
+ ['void'] = '',
+ ['char'] = 'number',
+ ['int'] = 'number',
+ ['short'] = 'number',
+ ['long'] = 'number',
+ ['_cstring'] = 'string',
+ ['_userdata'] = 'userdata',
+ ['char*'] = 'string',
+ ['void*'] = 'userdata',
+ ['bool'] = 'bool',
+ ['LUA_VALUE'] = 'value',
+ ['byte'] = 'number',
+ ['s16b'] = 'number',
+ ['u16b'] = 'number',
+ ['s32b'] = 'number',
+ ['u32b'] = 'number',
+}
+
+_basic_tag = {
+ ['void'] = '',
+ ['char'] = 'LUA_TNUMBER',
+ ['int'] = 'LUA_TNUMBER',
+ ['short'] = 'LUA_TNUMBER',
+ ['long'] = 'LUA_TNUMBER',
+ ['_cstring'] = 'LUA_TSTRING',
+ ['_userdata'] = 'LUA_TUSERDATA',
+ ['char*'] = 'LUA_TSTRING',
+ ['void*'] = 'LUA_TUSERDATA',
+ ['bool'] = 'tolua_tag(tolua_S,"bool")',
+ ['byte'] = 'LUA_TNUMBER',
+ ['s16b'] = 'LUA_TNUMBER',
+ ['u16b'] = 'LUA_TNUMBER',
+ ['s32b'] = 'LUA_TNUMBER',
+ ['u32b'] = 'LUA_TNUMBER',
+}
+
+_basic_ctype = {
+ number = "long",
+ string = "const char*",
+ userdata = "void*",
+ bool = "int",
+}
+
+-- List of user defined types
+-- Each type corresponds to a variable name that stores its tag value.
+_usertype = {}
+
+-- Tag method to provide inheritance
+function tolua_index (t,f)
+ if f == '_base' then -- to avoid loop
+ return tolua_old_index(t,f)
+ else
+ return t._base[f]
+ end
+end
+
+tolua_tag = newtag()
+tolua_old_index = settagmethod(tolua_tag,"index",tolua_index)
+
+-- Error handler
+function tolua_error (s)
+ local out = _OUTPUT
+ _OUTPUT = _STDERR
+ if strsub(s,1,1) == '#' then
+ write("\n** tolua: "..strsub(s,2)..".\n\n")
+ else
+ write("\n** tolua internal error: "..s..".\n\n")
+ return
+ end
+
+ if _curr_code then
+ local _,_,s = strfind(_curr_code,"^%s*(.-\n)") -- extract first line
+ if s==nil then s = _curr_code end
+ s = gsub(s,"_userdata","void*") -- return with 'void*'
+ s = gsub(s,"_cstring","char*") -- return with 'char*'
+ write("Code being processed:\n"..s.."\n")
+ end
+ _OUTPUT = out
+end
+
+
+_ERRORMESSAGE = tolua_error
+
+-- register an user defined type
+function regtype (t)
+ if not istype(t) then
+ _usertype[t] = t
+ end
+ return t
+end
+
+-- return tag name
+function tagvar(type,const)
+ if type == '' or type == 'void' then
+ return type,0
+ else
+ local m,t = findtypedef(type)
+ if isbasic(t) then
+ return t, _basic_tag[t]
+ end
+ if strfind(m,'const') then const = 'const' end
+ regtype(t)
+ if const and const ~= '' then
+ t = 'const '..t
+ end
+ return t,'tolua_tag(tolua_S,"'..t..'")'
+ end
+end
+
+-- check if basic type
+function isbasic (type)
+ local m,t = findtypedef(type)
+ local b = _basic[t]
+ if b then
+ return b,_basic_ctype[b]
+ end
+ return nil
+end
+
+-- check if type
+function istype (t)
+ return _basic[t] or _usertype[t] or istypedef(t)
+end
+
+
+-- split string using a token
+function split (s,t)
+ local l = {n=0}
+ local f = function (s)
+ %l.n = %l.n + 1
+ %l[%l.n] = s
+ end
+ local p = "%s*(.-)%s*"..t.."%s*"
+ s = gsub(s,"^%s+","")
+ s = gsub(s,"%s+$","")
+ s = gsub(s,p,f)
+ l.n = l.n + 1
+ l[l.n] = gsub(s,"(%s%s*)$","")
+ return l
+end
+
+
+-- concatenate strings of a table
+function concat (t,f,l)
+ local s = ''
+ local i=f
+ while i<=l do
+ s = s..t[i]
+ i = i+1
+ if i <= l then s = s..' ' end
+ end
+ return s
+end
+
+-- output line
+function output (...)
+ local i=1
+ while i<=arg.n do
+ if _cont and not strfind(_cont,'[%(,"]') and
+ strfind(arg[i],"^[%a_~]") then
+ write(' ')
+ end
+ write(arg[i])
+ if arg[i] ~= '' then
+ _cont = strsub(arg[i],-1,-1)
+ end
+ i = i+1
+ end
+ if strfind(arg[arg.n],"[%/%)%;%{%}]$") then
+ _cont=nil write('\n')
+ end
+end
+
+
diff --git a/src/lua/class.lua b/src/lua/class.lua
new file mode 100644
index 00000000..01385178
--- /dev/null
+++ b/src/lua/class.lua
@@ -0,0 +1,85 @@
+-- tolua: class class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: class.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Class class
+-- Represents a class definition.
+-- Stores the following fields:
+-- name = class name
+-- base = class base, if any (only single inheritance is supported)
+-- {i} = list of members
+classClass = {
+ _base = classContainer,
+ type = 'class',
+ name = '',
+ base = '',
+}
+settag(classClass,tolua_tag)
+
+
+-- register class
+function classClass:register ()
+ output(' tolua_cclass(tolua_S,"'..self.name..'","'..self.base..'");')
+ local i=1
+ while self[i] do
+ self[i]:register()
+ i = i+1
+ end
+end
+
+-- unregister class
+function classClass:unregister ()
+ output(' lua_pushnil(tolua_S); lua_setglobal(tolua_S,"'..self.name..'");')
+end
+
+-- output tags
+function classClass:decltag ()
+ self.itype,self.tag = tagvar(self.name);
+ self.citype,self.ctag = tagvar(self.name,'const');
+ local i=1
+ while self[i] do
+ self[i]:decltag()
+ i = i+1
+ end
+end
+
+
+-- Print method
+function classClass:print (ident,close)
+ print(ident.."Class{")
+ print(ident.." name = '"..self.name.."',")
+ print(ident.." base = '"..self.base.."';")
+ local i=1
+ while self[i] do
+ self[i]:print(ident.." ",",")
+ i = i+1
+ end
+ print(ident.."}"..close)
+end
+
+-- Internal constructor
+function _Class (t)
+ t._base = classClass
+ settag(t,tolua_tag)
+ append(t)
+ return t
+end
+
+-- Constructor
+-- Expects the name, the base and the body of the class.
+function Class (n,p,b)
+ local c = _Class(_Container{name=n, base=p})
+ push(c)
+ c:parse(strsub(b,2,strlen(b)-1)) -- eliminate braces
+ pop()
+end
+
+
diff --git a/src/lua/clean.lua b/src/lua/clean.lua
new file mode 100644
index 00000000..ba08d534
--- /dev/null
+++ b/src/lua/clean.lua
@@ -0,0 +1,74 @@
+-- mark up comments and strings
+STR1 = "\001"
+STR2 = "\002"
+STR3 = "\003"
+STR4 = "\004"
+REM = "\005"
+ANY = "([\001-\005])"
+ESC1 = "\006"
+ESC2 = "\007"
+
+MASK = { -- the substitution order is important
+ {ESC1, "\\'"},
+ {ESC2, '\\"'},
+ {STR1, "'"},
+ {STR2, '"'},
+ {STR3, "%[%["},
+ {STR4, "%]%]"},
+ {REM , "%-%-"},
+}
+
+function mask (s)
+ for i = 1,getn(MASK) do
+ s = gsub(s,MASK[i][2],MASK[i][1])
+ end
+ return s
+end
+
+function unmask (s)
+ for i = 1,getn(MASK) do
+ s = gsub(s,MASK[i][1],MASK[i][2])
+ end
+ return s
+end
+
+function clean (s)
+ -- check for compilation error
+ local code = "return function () " .. s .. " end"
+ if not dostring(code) then
+ return nil
+ end
+
+ local S = "" -- saved string
+
+ s = mask(s)
+
+ -- remove blanks and comments
+ while 1 do
+ local b,e,d = strfind(s,ANY)
+ if b then
+ S = S..strsub(s,1,b-1)
+ s = strsub(s,b+1)
+ if d==STR1 or d==STR2 then
+ e = strfind(s,d)
+ S = S ..d..strsub(s,1,e)
+ s = strsub(s,e+1)
+ elseif d==STR3 then
+ e = strfind(s,STR4)
+ S = S..d..strsub(s,1,e)
+ s = strsub(s,e+1)
+ elseif d==REM then
+ s = gsub(s,"[^\n]*(\n?)","%1",1)
+ end
+ else
+ S = S..s
+ break
+ end
+ end
+ -- eliminate unecessary spaces
+ S = gsub(S,"[ \t]+"," ")
+ S = gsub(S,"[ \t]*\n[ \t]*","\n")
+ S = unmask(S)
+ return S
+end
+
diff --git a/src/lua/code.lua b/src/lua/code.lua
new file mode 100644
index 00000000..08f38ad2
--- /dev/null
+++ b/src/lua/code.lua
@@ -0,0 +1,73 @@
+-- tolua: code class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1999
+-- $Id: code.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Code class
+-- Represents Lua code to be compiled and included
+-- in the initialization function.
+-- The following fields are stored:
+-- text = text code
+classCode = {
+ text = '',
+ _base = classFeature,
+}
+settag(classCode,tolua_tag)
+
+-- register code
+function classCode:register ()
+ -- clean Lua code
+ local s = clean(self.text)
+ if not s then
+ error("parser error in embedded code")
+ end
+
+ -- convert to C
+ output('\n { /* begin embedded lua code */\n')
+ output(' static unsigned char B[] = {\n ')
+ local t={n=0}
+ local b = gsub(s,'(.)',function (c)
+ local e = ''
+ %t.n=%t.n+1 if %t.n==15 then %t.n=0 e='\n ' end
+ return format('%3u,%s',strbyte(c),e)
+ end
+ )
+ output(b..strbyte(" "))
+ output('\n };\n')
+ output(' lua_dobuffer(tolua_S,(char*)B,sizeof(B),"tolua: embedded Lua code");')
+ output(' } /* end of embedded lua code */\n\n')
+end
+
+
+-- Print method
+function classCode:print (ident,close)
+ print(ident.."Code{")
+ print(ident.." text = [["..self.text.."]],")
+ print(ident.."}"..close)
+end
+
+
+-- Internal constructor
+function _Code (t)
+ t._base = classCode
+ settag(t,tolua_tag)
+ append(t)
+ return t
+end
+
+-- Constructor
+-- Expects a string representing the code text
+function Code (l)
+ return _Code {
+ text = l
+ }
+end
+
+
diff --git a/src/lua/container.lua b/src/lua/container.lua
new file mode 100644
index 00000000..cbbf11c1
--- /dev/null
+++ b/src/lua/container.lua
@@ -0,0 +1,311 @@
+-- tolua: container abstract class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: container.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Container class
+-- Represents a container of features to be bound
+-- to lua.
+classContainer =
+{
+ curr = nil,
+ _base = classFeature,
+}
+settag(classContainer,tolua_tag)
+
+-- output tags
+function classContainer:decltag ()
+ push(self)
+ local i=1
+ while self[i] do
+ self[i]:decltag()
+ i = i+1
+ end
+ pop()
+end
+
+
+-- write support code
+function classContainer:supcode ()
+ push(self)
+ local i=1
+ while self[i] do
+ self[i]:supcode()
+ i = i+1
+ end
+ pop()
+end
+
+
+-- Internal container constructor
+function _Container (self)
+ self._base = classContainer
+ settag(self,tolua_tag)
+ self.n = 0
+ self.typedefs = {n=0}
+ self.lnames = {}
+ return self
+end
+
+-- push container
+function push (t)
+ classContainer.curr = t
+end
+
+-- pop container
+function pop ()
+ classContainer.curr = classContainer.curr.parent
+end
+
+-- append to current container
+function append (t)
+ return classContainer.curr:append(t)
+end
+
+-- append typedef to current container
+function appendtypedef (t)
+ return classContainer.curr:appendtypedef(t)
+end
+
+-- substitute typedef
+function findtypedef (type)
+ return classContainer.curr:findtypedef(type)
+end
+
+-- check if is typedef
+function istypedef (type)
+ return classContainer.curr:istypedef(type)
+end
+
+-- append feature to container
+function classContainer:append (t)
+ self.n = self.n + 1
+ self[self.n] = t
+ t.parent = self
+end
+
+-- append typedef
+function classContainer:appendtypedef (t)
+ self.typedefs.n = self.typedefs.n + 1
+ self.typedefs[self.typedefs.n] = t
+end
+
+-- determine lua function name overload
+function classContainer:overload (lname)
+ if not self.lnames[lname] then
+ self.lnames[lname] = 0
+ else
+ self.lnames[lname] = self.lnames[lname] + 1
+ end
+ return format("%02d",self.lnames[lname])
+end
+
+function classContainer:findtypedef (type)
+ local env = self
+ while env do
+ if env.typedefs then
+ local i=1
+ while env.typedefs[i] do
+ if env.typedefs[i].utype == type then
+ local mod1,type1 = env.typedefs[i].mod,env.typedefs[i].type
+ local mod2,type2 = findtypedef(type1)
+ return mod2..' '..mod1,type2
+ end
+ i = i+1
+ end
+ end
+ env = env.parent
+ end
+ return '',type
+end
+
+function classContainer:istypedef (type)
+ local env = self
+ while env do
+ if env.typedefs then
+ local i=1
+ while env.typedefs[i] do
+ if env.typedefs[i].utype == type then
+ return 1
+ end
+ i = i+1
+ end
+ end
+ env = env.parent
+ end
+ return nil
+end
+
+-- parse chunk
+function classContainer:doparse (s)
+
+ -- try module
+ do
+ local b,e,name,body = strfind(s,"^%s*module%s%s*([_%w][_%w]*)%s*(%b{})%s*")
+ if b then
+ _curr_code = strsub(s,b,e)
+ Module(name,body)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try define
+ do
+ local b,e,name = strfind(s,"^%s*#define%s%s*([^%s]*)[^\n]*\n%s*")
+ if b then
+ _curr_code = strsub(s,b,e)
+ Define(name)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try enumerates
+ do
+ local b,e,body = strfind(s,"^%s*enum[^{]*(%b{})%s*;?%s*")
+ if b then
+ _curr_code = strsub(s,b,e)
+ Enumerate(body)
+ return strsub(s,e+1)
+ end
+ end
+
+ do
+ local b,e,body,name = strfind(s,"^%s*typedef%s%s*enum[^{]*(%b{})%s*([%w_][^%s]*)%s*;%s*")
+ if b then
+ _curr_code = strsub(s,b,e)
+ Enumerate(body)
+ Typedef("int "..name)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try operator
+ do
+ local b,e,decl,kind,arg,const = strfind(s,"^%s*([_%w][_%w%s%*&]*operator)%s*([^%s][^%s]*)%s*(%b())%s*(c?o?n?s?t?)%s*;%s*")
+ if b then
+ _curr_code = strsub(s,b,e)
+ Operator(decl,kind,arg,const)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try function
+ do
+ local b,e,decl,arg,const = strfind(s,"^%s*([~_%w][_@%w%s%*&]*[_%w])%s*(%b())%s*(c?o?n?s?t?)%s*=?%s*0?%s*;%s*")
+ if not b then
+ -- try a single letter function name
+ b,e,decl,arg,const = strfind(s,"^%s*([_%w])%s*(%b())%s*(c?o?n?s?t?)%s*;%s*")
+ end
+ if b then
+ _curr_code = strsub(s,b,e)
+ Function(decl,arg,const)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try inline function
+ do
+ local b,e,decl,arg,const = strfind(s,"^%s*([~_%w][_@%w%s%*&]*[_%w])%s*(%b())%s*(c?o?n?s?t?)%s*%b{}%s*")
+ if not b then
+ -- try a single letter function name
+ b,e,decl,arg,const = strfind(s,"^%s*([_%w])%s*(%b())%s*(c?o?n?s?t?)%s*%b{}%s*")
+ end
+ if b then
+ _curr_code = strsub(s,b,e)
+ Function(decl,arg,const)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try class
+ do
+ local b,e,name,base,body = strfind(s,"^%s*class%s*([_%w][_%w]*)%s*(.-)%s*(%b{})%s*;%s*")
+ if not b then
+ b,e,name,base,body = strfind(s,"^%s*struct%s*([_%w][_%w]*)%s*(.-)%s*(%b{})%s*;%s*")
+ if not b then
+ base = ''
+ b,e,body,name = strfind(s,"^%s*typedef%s%s*struct%s%s*[_%w]*%s*(%b{})%s*([_%w][_%w]*)%s*;%s*")
+ end
+ end
+ if b then
+ if base ~= '' then
+ local b,e
+ b,e,base = strfind(base,".-([_%w][_%w]*)$")
+ end
+ _curr_code = strsub(s,b,e)
+ Class(name,base,body)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try typedef
+ do
+ local b,e,types = strfind(s,"^%s*typedef%s%s*(.-)%s*;%s*")
+ if b then
+ _curr_code = strsub(s,b,e)
+ Typedef(types)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try variable
+ do
+ local b,e,decl = strfind(s,"^%s*([_%w][_@%s%w%d%*&]*[_%w%d])%s*;%s*")
+ if b then
+ _curr_code = strsub(s,b,e)
+ Variable(decl)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try array
+ do
+ local b,e,decl = strfind(s,"^%s*([_%w][][_@%s%w%d%*&%-%>]*[]_%w%d])%s*;%s*")
+ if b then
+ _curr_code = strsub(s,b,e)
+ Array(decl)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try code
+ do
+ local b,e,code = strfind(s,"^%s*(%b\1\2)")
+ if b then
+ Code(strsub(code,2,-2))
+ return strsub(s,e+1)
+ end
+ end
+
+ -- try verbatim
+ do
+ local b,e,line = strfind(s,"^%s*%$(.-\n)")
+ if b then
+ Verbatim(line)
+ return strsub(s,e+1)
+ end
+ end
+
+ -- no matching
+ if gsub(s,"%s%s*","") ~= "" then
+ _curr_code = s
+ error("#parse error")
+ else
+ return ""
+ end
+end
+
+function classContainer:parse (s)
+ while s ~= '' do
+ s = self:doparse(s)
+ end
+end
+
+
diff --git a/src/lua/declaration.lua b/src/lua/declaration.lua
new file mode 100644
index 00000000..e4d5c688
--- /dev/null
+++ b/src/lua/declaration.lua
@@ -0,0 +1,399 @@
+-- tolua: declaration class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: declaration.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Declaration class
+-- Represents variable, function, or argument declaration.
+-- Stores the following fields:
+-- mod = type modifiers
+-- type = type
+-- ptr = "*" or "&", if representing a pointer or a reference
+-- name = name
+-- dim = dimension, if a vector
+-- def = default value, if any (only for arguments)
+-- ret = "*" or "&", if value is to be returned (only for arguments)
+classDeclaration = {
+ _base = classFeature,
+ mod = '',
+ type = '',
+ ptr = '',
+ name = '',
+ dim = '',
+ ret = '',
+ def = ''
+}
+settag(classDeclaration,tolua_tag)
+
+-- Create an unique variable name
+function create_varname ()
+ if not _varnumber then _varnumber = 0 end
+ _varnumber = _varnumber + 1
+ return "tolua_var_".._varnumber
+end
+
+-- Check declaration name
+-- It also identifies default values
+function classDeclaration:checkname ()
+
+ if strsub(self.name,1,1) == '[' and not istype(self.type) then
+ self.name = self.type..self.name
+ local m = split(self.mod,'%s%s*')
+ self.type = m[m.n]
+ self.mod = concat(m,1,m.n-1)
+ end
+
+ local t = split(self.name,'=')
+ if t.n==2 then
+ self.name = t[1]
+ self.def = t[t.n]
+ end
+
+ local b,e,d = strfind(self.name,"%[(.-)%]")
+ if b then
+ self.name = strsub(self.name,1,b-1)
+ self.dim = d
+ end
+
+
+ if self.type ~= '' and self.type ~= 'void' and self.name == '' then
+ self.name = create_varname()
+ elseif self.kind=='var' then
+ if self.type=='' and self.name~='' then
+ self.type = self.type..self.name
+ self.name = create_varname()
+ elseif istype(self.name) then
+ if self.type=='' then self.type = self.name
+ else self.type = self.type..' '..self.name end
+ self.name = create_varname()
+ end
+ end
+
+end
+
+-- Check declaration type
+-- Substitutes typedef's.
+function classDeclaration:checktype ()
+
+ -- check if there is a pointer to basic type
+ if isbasic(self.type) and self.ptr~='' then
+ self.ret = self.ptr
+ self.ptr = nil
+ end
+
+ -- check if there is array to be returned
+ if self.dim~='' and self.ret~='' then
+ error('#invalid parameter: cannot return an array of values')
+ end
+
+ -- register type
+ if self.type~='' then
+ regtype(self.type)
+ end
+
+ -- restore 'void*' and 'string*'
+ if self.type == '_userdata' then self.type = 'void*'
+ elseif self.type == '_cstring' then self.type = 'char*'
+ end
+
+--
+-- -- if returning value, automatically set default value
+-- if self.ret ~= '' and self.def == '' then
+-- self.def = '0'
+-- end
+--
+
+end
+
+-- Print method
+function classDeclaration:print (ident,close)
+ print(ident.."Declaration{")
+ print(ident.." mod = '"..self.mod.."',")
+ print(ident.." type = '"..self.type.."',")
+ print(ident.." ptr = '"..self.ptr.."',")
+ print(ident.." name = '"..self.name.."',")
+ print(ident.." dim = '"..self.dim.."',")
+ print(ident.." def = '"..self.def.."',")
+ print(ident.." ret = '"..self.ret.."',")
+ print(ident.."}"..close)
+end
+
+-- declare tag
+function classDeclaration:decltag ()
+ self.itype, self.tag = tagvar(self.type,strfind(self.mod,'const'))
+end
+
+
+-- output type checking
+function classDeclaration:outchecktype (narg)
+ local tag, def
+ if self.dim ~= '' then
+ tag = 'LUA_TTABLE'
+ def = 0
+ else
+ tag = self.tag
+ def = self.def~='' or 0
+ end
+ return 'tolua_istype(tolua_S,'..narg..','..tag..','..def..')'
+end
+
+-- Declare variable
+function classDeclaration:declare (narg)
+ local ptr = ''
+ if self.ptr~='' then ptr = '*' end
+ output(" ",self.mod,self.type,ptr)
+ if self.dim ~= '' and tonumber(self.dim)==nil then
+ output('*')
+ end
+ output(self.name)
+ if self.dim ~= '' then
+ if tonumber(self.dim)~=nil then
+ output('[',self.dim,'];')
+ else
+ output(' = (',self.mod,self.type,ptr,'*)',
+ 'malloc(',self.dim,'*sizeof(',self.type,ptr,'));')
+ end
+ else
+ local t = isbasic(self.type)
+ output(' = ')
+ if not t and ptr=='' then output('*') end
+ output('((',self.mod,self.type)
+ if not t then
+ output('*')
+ end
+ output(') ')
+ local def = 0
+ if self.def ~= '' then def = self.def end
+ if t then
+ output('tolua_get'..t,'(tolua_S,',narg,',',def,'));')
+ else
+ output('tolua_getusertype(tolua_S,',narg,',',def,'));')
+ end
+ end
+end
+
+-- Get parameter value
+function classDeclaration:getarray (narg)
+ if self.dim ~= '' then
+ output(' {')
+ local def = self.def~='' or 0
+ output(' if (!tolua_arrayistype(tolua_S,',narg,',',self.tag,',',self.dim,',',def,'))')
+ output(' goto tolua_lerror;')
+ output(' else\n')
+ output(' {')
+ output(' int i;')
+ output(' for(i=0; i<'..self.dim..';i++)')
+ local t = isbasic(self.type)
+ local ptr = ''
+ if self.ptr~='' then ptr = '*' end
+ output(' ',self.name..'[i] = ')
+ if not t and ptr=='' then output('*') end
+ output('((',self.mod,self.type)
+ if not t then
+ output('*')
+ end
+ output(') ')
+ local def = 0
+ if self.def ~= '' then def = self.def end
+ if t then
+ output('tolua_getfield'..t..'(tolua_S,',narg,',i+1,',def,'));')
+ else
+ output('tolua_getfieldusertype(tolua_S,',narg,',i+1,',def,'));')
+ end
+ output(' }')
+ output(' }')
+ end
+end
+
+-- Get parameter value
+function classDeclaration:setarray (narg)
+ if self.dim ~= '' then
+ output(' {')
+ output(' int i;')
+ output(' for(i=0; i<'..self.dim..';i++)')
+ local t,ct = isbasic(self.type)
+ if t then
+ output(' tolua_pushfield'..t..'(tolua_S,',narg,',i+1,(',ct,')',self.name,'[i]);')
+ else
+ if self.ptr == '' then
+ output(' {')
+ output('#ifdef __cplusplus\n')
+ output(' void* toluaI_clone = new',self.type,'(',self.name,'[i]);')
+ output('#else\n')
+ output(' void* toluaI_clone = tolua_copy(tolua_S,(void*)&',self.name,'[i],sizeof(',self.type,'));')
+ output('#endif\n')
+ output(' tolua_pushfieldusertype(tolua_S,',narg,',i+1,tolua_doclone(tolua_S,toluaI_clone,',self.tag,'),',self.tag,');')
+ output(' }')
+
+ --output(' tolua_pushfieldclone(tolua_S,',narg,',i+1,(void*)&',self.name,'[i],sizeof(',self.type,'),',self.tag,');')
+ else
+ output(' tolua_pushfieldusertype(tolua_S,',narg,',i+1,(void*)',self.name,'[i],',self.tag,');')
+ end
+ end
+ output(' }')
+ end
+end
+
+-- Free dynamically allocated array
+function classDeclaration:freearray ()
+ if self.dim ~= '' and tonumber(self.dim)==nil then
+ output(' free(',self.name,');')
+ end
+end
+
+-- Pass parameter
+function classDeclaration:passpar ()
+ if self.ptr=='&' then
+ output('*'..self.name)
+ elseif self.ret=='*' then
+ output('&'..self.name)
+ else
+ output(self.name)
+ end
+end
+
+-- Return parameter value
+function classDeclaration:retvalue ()
+ if self.ret ~= '' then
+ local t,ct = isbasic(self.type)
+ if t then
+ output(' tolua_push'..t..'(tolua_S,(',ct,')'..self.name..');')
+ else
+ output(' tolua_pushusertype(tolua_S,(void*)'..self.name..',',self.tag,');')
+ end
+ return 1
+ end
+ return 0
+end
+
+-- Internal constructor
+function _Declaration (t)
+ if t.name and t.name~='' then
+ local n = split(t.name,'@')
+ t.name = n[1]
+ t.lname = gsub(n[2] or n[1],"%[.-%]","")
+ end
+ t._base = classDeclaration
+ settag(t,tolua_tag)
+ t:checkname()
+ t:checktype()
+ return t
+end
+
+-- Constructor
+-- Expects the string declaration.
+-- The kind of declaration can be "var" or "func".
+function Declaration (s,kind)
+ -- eliminate spaces if default value is provided
+ s = gsub(s,"%s*=%s*","=")
+
+ if kind == "var" then
+ -- check the form: void
+ if s == '' or s == 'void' then
+ return _Declaration{type = 'void', kind = kind}
+ end
+ end
+
+ -- check the form: mod type*& name
+ local t = split(s,'%*%s*&')
+ if t.n == 2 then
+ if kind == 'func' then
+ error("#invalid function return type: "..s)
+ end
+ local m = split(t[1],'%s%s*')
+ return _Declaration{
+ name = t[2],
+ ptr = '*',
+ ret = '&',
+ type = m[m.n],
+ mod = concat(m,1,m.n-1),
+ kind = kind
+ }
+ end
+
+ -- check the form: mod type** name
+ t = split(s,'%*%s*%*')
+ if t.n == 2 then
+ if kind == 'func' then
+ error("#invalid function return type: "..s)
+ end
+ local m = split(t[1],'%s%s*')
+ return _Declaration{
+ name = t[2],
+ ptr = '*',
+ ret = '*',
+ type = m[m.n],
+ mod = concat(m,1,m.n-1),
+ kind = kind
+ }
+ end
+
+ -- check the form: mod type& name
+ t = split(s,'&')
+ if t.n == 2 then
+ local m = split(t[1],'%s%s*')
+ return _Declaration{
+ name = t[2],
+ ptr = '&',
+ type = m[m.n],
+ mod = concat(m,1,m.n-1) ,
+ kind = kind
+ }
+ end
+
+ -- check the form: mod type* name
+ local s1 = gsub(s,"(%b\[\])",function (n) return gsub(n,'%*','\1') end)
+ t = split(s1,'%*')
+ if t.n == 2 then
+ t[2] = gsub(t[2],'\1','%*') -- restore * in dimension expression
+ local m = split(t[1],'%s%s*')
+ return _Declaration{
+ name = t[2],
+ ptr = '*',
+ type = m[m.n],
+ mod = concat(m,1,m.n-1) ,
+ kind = kind
+ }
+ end
+
+ if kind == 'var' then
+ -- check the form: mod type name
+ t = split(s,'%s%s*')
+ local v
+ if istype(t[t.n]) then v = '' else v = t[t.n]; t.n = t.n-1 end
+ return _Declaration{
+ name = v,
+ type = t[t.n],
+ mod = concat(t,1,t.n-1),
+ kind = kind
+ }
+
+ else -- kind == "func"
+
+ -- check the form: mod type name
+ t = split(s,'%s%s*')
+ local v = t[t.n] -- last word is the function name
+ local tp,md
+ if t.n>1 then
+ tp = t[t.n-1]
+ md = concat(t,1,t.n-2)
+ end
+ return _Declaration{
+ name = v,
+ type = tp,
+ mod = md,
+ kind = kind
+ }
+ end
+
+end
+
+
+
diff --git a/src/lua/define.lua b/src/lua/define.lua
new file mode 100644
index 00000000..db64db50
--- /dev/null
+++ b/src/lua/define.lua
@@ -0,0 +1,72 @@
+-- tolua: define class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: define.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Define class
+-- Represents a numeric const definition
+-- The following filds are stored:
+-- name = constant name
+classDefine = {
+ name = '',
+ _base = classFeature,
+}
+settag(classDefine,tolua_tag)
+
+-- register define
+function classDefine:register ()
+ local p = self:inmodule()
+ if p then
+ output(' tolua_constant(tolua_S,"'..p..'","'..self.lname..'",'..self.name..');')
+ else
+ output(' tolua_constant(tolua_S,NULL,"'..self.lname..'",'..self.name..');')
+ end
+end
+
+-- unregister define
+function classDefine:unregister ()
+ if not self:inmodule() then
+ output(' lua_pushnil(tolua_S); lua_setglobal(tolua_S,"'..self.lname..'");')
+ end
+end
+
+-- Print method
+function classDefine:print (ident,close)
+ print(ident.."Define{")
+ print(ident.." name = '"..self.name.."',")
+ print(ident.." lname = '"..self.lname.."',")
+ print(ident.."}"..close)
+end
+
+
+-- Internal constructor
+function _Define (t)
+ t._base = classDefine
+ settag(t,tolua_tag)
+
+ if t.name == '' then
+ error("#invalid define")
+ end
+
+ append(t)
+ return t
+end
+
+-- Constructor
+-- Expects a string representing the constant name
+function Define (n)
+ local t = split(n,'@')
+ return _Define {
+ name = t[1],
+ lname = t[2] or t[1]
+ }
+end
+
+
diff --git a/src/lua/doit.lua b/src/lua/doit.lua
new file mode 100644
index 00000000..aa184d62
--- /dev/null
+++ b/src/lua/doit.lua
@@ -0,0 +1,73 @@
+-- Generate binding code
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: doit.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- open input file, if any
+if flags.f then
+ local st, msg = readfrom(flags.f)
+ if not st then
+ error('#'..msg)
+ end
+end
+
+-- define package name, if not provided
+if not flags.n then
+ if flags.f then
+ flags.n = gsub(flags.f,"%..*","")
+ else
+ error("#no package name nor input file provided")
+ end
+end
+
+local p = Package(flags.n)
+
+if flags.f then
+ readfrom()
+end
+
+if flags.p then
+ return -- only parse
+end
+
+if flags.o then
+ local st,msg = writeto(flags.o)
+ if not st then
+ error('#'..msg)
+ end
+end
+
+if flags.P then
+ p:print()
+else
+ p:decltag()
+ p:preamble()
+ p:supcode()
+ p:register()
+ p:unregister()
+end
+
+if flags.o then
+ writeto()
+end
+
+-- write header file
+if not flags.P then
+ if flags.H then
+ local st,msg = writeto(flags.H)
+ if not st then
+ error('#'..msg)
+ end
+ p:header()
+ writeto()
+ end
+end
+
diff --git a/src/lua/enumerate.lua b/src/lua/enumerate.lua
new file mode 100644
index 00000000..6b2b7466
--- /dev/null
+++ b/src/lua/enumerate.lua
@@ -0,0 +1,93 @@
+-- tolua: enumerate class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: enumerate.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Enumerate class
+-- Represents enumeration
+-- The following fields are stored:
+-- {i} = list of constant names
+classEnumerate = {
+ _base = classFeature,
+}
+settag(classEnumerate,tolua_tag)
+
+-- register enumeration
+function classEnumerate:register ()
+ local p = self:inclass() or self:inmodule()
+ local i=1
+ while self[i] do
+ if p then
+ if self:inclass() then
+ output(' tolua_constant(tolua_S,"'..p..'","'..self.lnames[i]..'",'..p..'::'..self[i]..');')
+ else
+ output(' tolua_constant(tolua_S,"'..p..'","'..self.lnames[i]..'",'..self[i]..');')
+ end
+ else
+ output(' tolua_constant(tolua_S,NULL,"'..self.lnames[i]..'",'..self[i]..');')
+ end
+ i = i+1
+ end
+end
+-- register enumeration
+function classEnumerate:unregister ()
+ if self:inclass()==nil and self:inmodule()==nil then
+ local i=1
+ while self[i] do
+ output(' lua_pushnil(tolua_S); lua_setglobal(tolua_S,"'..self.lnames[i]..'");')
+ i = i+1
+ end
+ end
+end
+
+-- Print method
+function classEnumerate:print (ident,close)
+ print(ident.."Enumerate{")
+ local i=1
+ while self[i] do
+ print(ident.." '"..self[i].."'("..self.lnames[i].."),")
+ i = i+1
+ end
+ print(ident.."}"..close)
+end
+
+-- Internal constructor
+function _Enumerate (t)
+ t._base = classEnumerate
+ settag(t,tolua_tag)
+ append(t)
+ return t
+end
+
+-- Constructor
+-- Expects a string representing the enumerate body
+function Enumerate (b)
+ local t = split(strsub(b,2,-2),',') -- eliminate braces
+ local i = 1
+ local e = {n=0}
+ while t[i] do
+ local tt = split(t[i],'=') -- discard initial value
+ e.n = e.n + 1
+ e[e.n] = tt[1]
+ i = i+1
+ end
+ -- set lua names
+ i = 1
+ e.lnames = {}
+ while e[i] do
+ local t = split(e[i],'@')
+ e[i] = t[1]
+ e.lnames[i] = t[2] or t[1]
+ i = i+1
+ end
+ return _Enumerate(e)
+end
+
+
diff --git a/src/lua/feature.lua b/src/lua/feature.lua
new file mode 100644
index 00000000..4a4379e1
--- /dev/null
+++ b/src/lua/feature.lua
@@ -0,0 +1,72 @@
+-- tolua: abstract feature class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: feature.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Feature class
+-- Represents the base class of all mapped feature.
+classFeature = {
+}
+
+-- write support code
+function classFeature:supcode ()
+end
+
+-- output tag
+function classFeature:decltag ()
+end
+
+-- register feature
+function classFeature:register ()
+end
+
+-- unregister feature
+function classFeature:unregister ()
+end
+
+-- translate verbatim
+function classFeature:preamble ()
+end
+
+-- check if feature is inside a class definition
+-- it returns the feature class name or nil.
+function classFeature:inclass ()
+ if self.parent and self.parent.type == 'class' then
+ return self.parent.name
+ else
+ return nil
+ end
+end
+
+-- check if feature is inside a module
+-- it returns the feature module name or nil.
+function classFeature:inmodule ()
+ if self.parent and self.parent.type == 'module' then
+ return self.parent.name
+ else
+ return nil
+ end
+end
+
+-- return C binding function name based on name
+-- the client specifies a prefix
+-- return C binding function name
+-- the client specifies a prefix
+function classFeature:cfuncname (n)
+ if self.parent then
+ n = self.parent:cfuncname(n)
+ end
+ if self.lname then
+ return n..'_'..self.lname
+ else
+ return n..'_'..self.name
+ end
+end
+
diff --git a/src/lua/function.lua b/src/lua/function.lua
new file mode 100644
index 00000000..b87e3488
--- /dev/null
+++ b/src/lua/function.lua
@@ -0,0 +1,317 @@
+-- tolua: function class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: function.lua,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+
+-- Function class
+-- Represents a function or a class method.
+-- The following fields are stored:
+-- mod = type modifiers
+-- type = type
+-- ptr = "*" or "&", if representing a pointer or a reference
+-- name = name
+-- args = list of argument declarations
+-- const = if it is a method receiving a const "this".
+classFunction = {
+ mod = '',
+ type = '',
+ ptr = '',
+ name = '',
+ args = {n=0},
+ const = '',
+ _base = classFeature,
+}
+settag(classFunction,tolua_tag)
+
+-- declare tags
+function classFunction:decltag ()
+ self.itype,self.tag = tagvar(self.type,strfind(self.mod,'const'))
+ local i=1
+ while self.args[i] do
+ self.args[i]:decltag()
+ i = i+1
+ end
+end
+
+
+-- Write binding function
+-- Outputs C/C++ binding function.
+function classFunction:supcode ()
+ local nret = 0 -- number of returned values
+ local class = self:inclass()
+ local _,_,static = strfind(self.mod,'^%s*(static)')
+
+ if class then
+ output("/* method:",self.name," of class ",class," */")
+ else
+ output("/* function:",self.name," */")
+ end
+ output("static int",self.cname,"(lua_State* tolua_S)")
+ output("{")
+
+ -- check types
+ output(' if (\n')
+ -- check self
+ local narg
+ if class then narg=2 else narg=1 end
+ if class and self.name~='new' and static==nil then
+ if self.const == 'const' then
+ output(' !tolua_istype(tolua_S,1,',self.parent.ctag,',0) ||\n')
+ else
+ output(' !tolua_istype(tolua_S,1,',self.parent.tag,',0) ||\n')
+ end
+ end
+ -- check args
+ if self.args[1].type ~= 'void' then
+ local i=1
+ while self.args[i] do
+ if isbasic(self.args[i].type) ~= 'value' then
+ output(' !'..self.args[i]:outchecktype(narg)..' ||\n')
+ end
+ narg = narg+1
+ i = i+1
+ end
+ end
+ -- check end of list
+ output(' !tolua_isnoobj(tolua_S,'..narg..')\n )\n goto tolua_lerror;')
+
+ output(' else\n {')
+
+ -- declare self, if the case
+ local narg
+ if class then narg=2 else narg=1 end
+ if class and self.name~='new' and static==nil then
+ output(' ',self.const,class,'*','self = ')
+ output('(',self.const,class,'*) ')
+ output('tolua_getusertype(tolua_S,1,0);')
+ elseif static then
+ _,_,self.mod = strfind(self.mod,'^%s*static%s%s*(.*)')
+ end
+ -- declare parameters
+ if self.args[1].type ~= 'void' then
+ local i=1
+ while self.args[i] do
+ self.args[i]:declare(narg)
+ narg = narg+1
+ i = i+1
+ end
+ end
+
+ -- check self
+ if class and self.name~='new' and static==nil then
+ output(' if (!self) tolua_error(tolua_S,"invalid \'self\' in function \''..self.name..'\'");');
+ end
+
+ -- get array element values
+ if class then narg=2 else narg=1 end
+ if self.args[1].type ~= 'void' then
+ local i=1
+ while self.args[i] do
+ self.args[i]:getarray(narg)
+ narg = narg+1
+ i = i+1
+ end
+ end
+
+ -- call function
+ if class and self.name=='delete' then
+ output(' delete self;')
+ elseif class and self.name == 'operator&[]' then
+ output(' self->operator[](',self.args[1].name,') = ',self.args[2].name,';')
+ else
+ output(' {')
+ if self.type ~= '' and self.type ~= 'void' then
+ output(' ',self.mod,self.type,self.ptr,'toluaI_ret = ')
+ output('(',self.mod,self.type,self.ptr,') ')
+ else
+ output(' ')
+ end
+ if class and self.name=='new' then
+ output('new',class,'(')
+ elseif class and static then
+ output(class..'::'..self.name,'(')
+ elseif class then
+ output('self->'..self.name,'(')
+ else
+ output(self.name,'(')
+ end
+
+ -- write parameters
+ local i=1
+ while self.args[i] do
+ self.args[i]:passpar()
+ i = i+1
+ if self.args[i] then
+ output(',')
+ end
+ end
+
+ output(');')
+
+ -- return values
+ if self.type ~= '' and self.type ~= 'void' then
+ nret = nret + 1
+ local t,ct = isbasic(self.type)
+ if t then
+ output(' tolua_push'..t..'(tolua_S,(',ct,')toluaI_ret);')
+ else
+ if self.ptr == '' then
+ output(' {')
+ output('#ifdef __cplusplus\n')
+ output(' void* toluaI_clone = new',self.type,'(toluaI_ret);')
+ output('#else\n')
+ output(' void* toluaI_clone = tolua_copy(tolua_S,(void*)&toluaI_ret,sizeof(',self.type,'));')
+ output('#endif\n')
+ output(' tolua_pushusertype(tolua_S,tolua_doclone(tolua_S,toluaI_clone,',self.tag,'),',self.tag,');')
+ output(' }')
+ --output(' tolua_pushclone((void*)&toluaI_ret,sizeof(',self.type,'),',self.tag,');')
+ elseif self.ptr == '&' then
+ output(' tolua_pushusertype(tolua_S,(void*)&toluaI_ret,',self.tag,');')
+ else
+ output(' tolua_pushusertype(tolua_S,(void*)toluaI_ret,',self.tag,');')
+ end
+ end
+ end
+ local i=1
+ while self.args[i] do
+ nret = nret + self.args[i]:retvalue()
+ i = i+1
+ end
+ output(' }')
+
+ -- set array element values
+ if class then narg=2 else narg=1 end
+ if self.args[1].type ~= 'void' then
+ local i=1
+ while self.args[i] do
+ self.args[i]:setarray(narg)
+ narg = narg+1
+ i = i+1
+ end
+ end
+
+ -- free dynamically allocated array
+ if self.args[1].type ~= 'void' then
+ local i=1
+ while self.args[i] do
+ self.args[i]:freearray()
+ i = i+1
+ end
+ end
+ end
+
+ output(' }')
+ output(' return '..nret..';')
+
+ -- call overloaded function or generate error
+ output('tolua_lerror:\n')
+ local overload = strsub(self.cname,-2,-1) - 1
+ if overload >= 0 then
+ output(' return '..strsub(self.cname,1,-3)..format("%02d",overload)..'(tolua_S);')
+ else
+ output(' tolua_error(tolua_S,"#ferror in function \''..self.lname..'\'.");')
+ output(' return 0;')
+ end
+
+ output('}')
+ output('\n')
+end
+
+-- register function
+function classFunction:register ()
+ local parent = self:inclass() or self:inmodule()
+ if parent then
+ output(' tolua_function(tolua_S,"'..parent..'","'..self.lname..'",'..self.cname..');')
+ else
+ output(' tolua_function(tolua_S,NULL,"'..self.lname..'",'..self.cname..');')
+ end
+end
+
+-- unregister function
+function classFunction:unregister ()
+ if self:inclass()==nil and self:inmodule()==nil then
+ output(' lua_pushnil(tolua_S); lua_setglobal(tolua_S,"'..self.lname..'");')
+ end
+end
+
+
+-- Print method
+function classFunction:print (ident,close)
+ print(ident.."Function{")
+ print(ident.." mod = '"..self.mod.."',")
+ print(ident.." type = '"..self.type.."',")
+ print(ident.." ptr = '"..self.ptr.."',")
+ print(ident.." name = '"..self.name.."',")
+ print(ident.." const = '"..self.const.."',")
+ print(ident.." cname = '"..self.cname.."',")
+ print(ident.." lname = '"..self.lname.."',")
+ print(ident.." args = {")
+ local i=1
+ while self.args[i] do
+ self.args[i]:print(ident.." ",",")
+ i = i+1
+ end
+ print(ident.." }")
+ print(ident.."}"..close)
+end
+
+-- determine lua function name overload
+function classFunction:overload ()
+ return self.parent:overload(self.lname)
+end
+
+
+
+-- Internal constructor
+function _Function (t)
+ t._base = classFunction
+ settag(t,tolua_tag)
+
+ if t.const ~= 'const' and t.const ~= '' then
+ error("#invalid 'const' specification")
+ end
+
+ append(t)
+ if t:inclass() then
+ if t.name == t.parent.name then
+ t.name = 'new'
+ t.lname = 'new'
+ t.type = t.parent.name
+ t.ptr = '*'
+ elseif t.name == '~'..t.parent.name then
+ t.name = 'delete'
+ t.lname = 'delete'
+ end
+ end
+ t.cname = t:cfuncname("toluaI")..t:overload(t)
+ return t
+end
+
+-- Constructor
+-- Expects three strings: one representing the function declaration,
+-- another representing the argument list, and the third representing
+-- the "const" or empty string.
+function Function (d,a,c)
+ local t = split(strsub(a,2,-2),',') -- eliminate braces
+ local i=1
+ local l = {n=0}
+ while t[i] do
+ l.n = l.n+1
+ l[l.n] = Declaration(t[i],'var')
+ i = i+1
+ end
+ local f = Declaration(d,'func')
+ f.args = l
+ f.const = c
+ return _Function(f)
+end
+
+
diff --git a/src/lua/lapi.c b/src/lua/lapi.c
new file mode 100644
index 00000000..b597e00a
--- /dev/null
+++ b/src/lua/lapi.c
@@ -0,0 +1,499 @@
+/*
+** $Id: lapi.c,v 1.3 2001/11/26 23:00:23 darkgod Exp $
+** Lua API
+** See Copyright Notice in lua.h
+*/
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+const char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n"
+ "$Authors: " LUA_AUTHORS " $";
+
+
+
+#define Index(L,i) ((i) >= 0 ? (L->Cbase+((i)-1)) : (L->top+(i)))
+
+#define api_incr_top(L) incr_top
+
+
+
+
+TObject *luaA_index (lua_State *L, int index) {
+ return Index(L, index);
+}
+
+
+static TObject *luaA_indexAcceptable (lua_State *L, int index) {
+ if (index == 0) {
+ return NULL;
+ } else if (index > 0) {
+ TObject *o = L->Cbase+(index-1);
+ if (o >= L->top) return NULL;
+ else return o;
+ } else {
+ TObject *o = L->top+index;
+ if(o < L->Cbase) return NULL;
+ else return o;
+ }
+}
+
+
+void luaA_pushobject (lua_State *L, const TObject *o) {
+ *L->top = *o;
+ incr_top;
+}
+
+LUA_API int lua_stackspace (lua_State *L) {
+ return (L->stack_last - L->top);
+}
+
+
+
+/*
+** basic stack manipulation
+*/
+
+
+LUA_API int lua_gettop (lua_State *L) {
+ return (L->top - L->Cbase);
+}
+
+
+LUA_API void lua_settop (lua_State *L, int index) {
+ if (index >= 0)
+ luaD_adjusttop(L, L->Cbase, index);
+ else
+ L->top = L->top+index+1; /* index is negative */
+}
+
+
+LUA_API void lua_remove (lua_State *L, int index) {
+ StkId p = luaA_index(L, index);
+ while (++p < L->top) *(p-1) = *p;
+ L->top--;
+}
+
+
+LUA_API void lua_insert (lua_State *L, int index) {
+ StkId p = luaA_index(L, index);
+ StkId q;
+ for (q = L->top; q>p; q--)
+ *q = *(q-1);
+ *p = *L->top;
+}
+
+
+LUA_API void lua_pushvalue (lua_State *L, int index) {
+ *L->top = *luaA_index(L, index);
+ api_incr_top(L);
+}
+
+
+
+/*
+** access functions (stack -> C)
+*/
+
+
+LUA_API int lua_type (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL) ? LUA_TNONE : ttype(o);
+}
+
+LUA_API const char *lua_typename (lua_State *L, int t) {
+ UNUSED(L);
+ return (t == LUA_TNONE) ? "no value" : luaO_typenames[t];
+}
+
+
+LUA_API int lua_iscfunction (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL) ? 0 : iscfunction(o);
+}
+
+LUA_API int lua_isnumber (lua_State *L, int index) {
+ TObject *o = luaA_indexAcceptable(L, index);
+ return (o == NULL) ? 0 : (tonumber(o) == 0);
+}
+
+LUA_API int lua_isstring (lua_State *L, int index) {
+ int t = lua_type(L, index);
+ return (t == LUA_TSTRING || t == LUA_TNUMBER);
+}
+
+
+LUA_API int lua_tag (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL) ? LUA_NOTAG : luaT_tag(o);
+}
+
+LUA_API int lua_equal (lua_State *L, int index1, int index2) {
+ StkId o1 = luaA_indexAcceptable(L, index1);
+ StkId o2 = luaA_indexAcceptable(L, index2);
+ if (o1 == NULL || o2 == NULL) return 0; /* index out-of-range */
+ else return luaO_equalObj(o1, o2);
+}
+
+LUA_API int lua_lessthan (lua_State *L, int index1, int index2) {
+ StkId o1 = luaA_indexAcceptable(L, index1);
+ StkId o2 = luaA_indexAcceptable(L, index2);
+ if (o1 == NULL || o2 == NULL) return 0; /* index out-of-range */
+ else return luaV_lessthan(L, o1, o2, L->top);
+}
+
+
+
+LUA_API long lua_tonumber (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || tonumber(o)) ? 0 : nvalue(o);
+}
+
+LUA_API const char *lua_tostring (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || tostring(L, o)) ? NULL : svalue(o);
+}
+
+LUA_API size_t lua_strlen (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || tostring(L, o)) ? 0 : tsvalue(o)->len;
+}
+
+LUA_API lua_CFunction lua_tocfunction (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->f.c;
+}
+
+LUA_API void *lua_touserdata (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || ttype(o) != LUA_TUSERDATA) ? NULL :
+ tsvalue(o)->u.d.value;
+}
+
+LUA_API const void *lua_topointer (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ if (o == NULL) return NULL;
+ switch (ttype(o)) {
+ case LUA_TTABLE:
+ return hvalue(o);
+ case LUA_TFUNCTION:
+ return clvalue(o);
+ default: return NULL;
+ }
+}
+
+
+
+/*
+** push functions (C -> stack)
+*/
+
+
+LUA_API void lua_pushnil (lua_State *L) {
+ ttype(L->top) = LUA_TNIL;
+ api_incr_top(L);
+}
+
+
+LUA_API void lua_pushnumber (lua_State *L, long n) {
+ nvalue(L->top) = n;
+ ttype(L->top) = LUA_TNUMBER;
+ api_incr_top(L);
+}
+
+
+LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) {
+ tsvalue(L->top) = luaS_newlstr(L, s, len);
+ ttype(L->top) = LUA_TSTRING;
+ api_incr_top(L);
+}
+
+
+LUA_API void lua_pushstring (lua_State *L, const char *s) {
+ if (s == NULL)
+ lua_pushnil(L);
+ else
+ lua_pushlstring(L, s, strlen(s));
+}
+
+
+LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
+ luaV_Cclosure(L, fn, n);
+}
+
+
+LUA_API void lua_pushusertag (lua_State *L, void *u, int tag) {
+ /* ORDER LUA_T */
+ if (!(tag == LUA_ANYTAG || tag == LUA_TUSERDATA || validtag(tag)))
+ luaO_verror(L, "invalid tag for a userdata (%d)", tag);
+ tsvalue(L->top) = luaS_createudata(L, u, tag);
+ ttype(L->top) = LUA_TUSERDATA;
+ api_incr_top(L);
+}
+
+
+
+/*
+** get functions (Lua -> stack)
+*/
+
+
+LUA_API void lua_getglobal (lua_State *L, const char *name) {
+ StkId top = L->top;
+ *top = *luaV_getglobal(L, luaS_new(L, name));
+ L->top = top;
+ api_incr_top(L);
+}
+
+
+LUA_API void lua_gettable (lua_State *L, int index) {
+ StkId t = Index(L, index);
+ StkId top = L->top;
+ *(top-1) = *luaV_gettable(L, t);
+ L->top = top; /* tag method may change top */
+}
+
+
+LUA_API void lua_rawget (lua_State *L, int index) {
+ StkId t = Index(L, index);
+ LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected");
+ *(L->top - 1) = *luaH_get(L, hvalue(t), L->top - 1);
+}
+
+
+LUA_API void lua_rawgeti (lua_State *L, int index, int n) {
+ StkId o = Index(L, index);
+ LUA_ASSERT(ttype(o) == LUA_TTABLE, "table expected");
+ *L->top = *luaH_getnum(hvalue(o), n);
+ api_incr_top(L);
+}
+
+
+LUA_API void lua_getglobals (lua_State *L) {
+ hvalue(L->top) = L->gt;
+ ttype(L->top) = LUA_TTABLE;
+ api_incr_top(L);
+}
+
+
+LUA_API int lua_getref (lua_State *L, int ref) {
+ if (ref == LUA_REFNIL)
+ ttype(L->top) = LUA_TNIL;
+ else if (0 <= ref && ref < L->refSize &&
+ (L->refArray[ref].st == LOCK || L->refArray[ref].st == HOLD))
+ *L->top = L->refArray[ref].o;
+ else
+ return 0;
+ api_incr_top(L);
+ return 1;
+}
+
+
+LUA_API void lua_newtable (lua_State *L) {
+ hvalue(L->top) = luaH_new(L, 0);
+ ttype(L->top) = LUA_TTABLE;
+ api_incr_top(L);
+}
+
+
+
+/*
+** set functions (stack -> Lua)
+*/
+
+
+LUA_API void lua_setglobal (lua_State *L, const char *name) {
+ StkId top = L->top;
+ luaV_setglobal(L, luaS_new(L, name));
+ L->top = top-1; /* remove element from the top */
+}
+
+
+LUA_API void lua_settable (lua_State *L, int index) {
+ StkId t = Index(L, index);
+ StkId top = L->top;
+ luaV_settable(L, t, top-2);
+ L->top = top-2; /* pop index and value */
+}
+
+
+LUA_API void lua_rawset (lua_State *L, int index) {
+ StkId t = Index(L, index);
+ LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected");
+ *luaH_set(L, hvalue(t), L->top-2) = *(L->top-1);
+ L->top -= 2;
+}
+
+
+LUA_API void lua_rawseti (lua_State *L, int index, int n) {
+ StkId o = Index(L, index);
+ LUA_ASSERT(ttype(o) == LUA_TTABLE, "table expected");
+ *luaH_setint(L, hvalue(o), n) = *(L->top-1);
+ L->top--;
+}
+
+
+LUA_API void lua_setglobals (lua_State *L) {
+ StkId newtable = --L->top;
+ LUA_ASSERT(ttype(newtable) == LUA_TTABLE, "table expected");
+ L->gt = hvalue(newtable);
+}
+
+
+LUA_API int lua_ref (lua_State *L, int lock) {
+ int ref;
+ if (ttype(L->top-1) == LUA_TNIL)
+ ref = LUA_REFNIL;
+ else {
+ if (L->refFree != NONEXT) { /* is there a free place? */
+ ref = L->refFree;
+ L->refFree = L->refArray[ref].st;
+ }
+ else { /* no more free places */
+ luaM_growvector(L, L->refArray, L->refSize, 1, struct Ref,
+ "reference table overflow", MAX_INT);
+ L->nblocks += sizeof(struct Ref);
+ ref = L->refSize++;
+ }
+ L->refArray[ref].o = *(L->top-1);
+ L->refArray[ref].st = lock ? LOCK : HOLD;
+ }
+ L->top--;
+ return ref;
+}
+
+
+/*
+** "do" functions (run Lua code)
+** (most of them are in ldo.c)
+*/
+
+LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults) {
+ luaD_call(L, L->top-(nargs+1), nresults);
+}
+
+
+/*
+** Garbage-collection functions
+*/
+
+/* GC values are expressed in Kbytes: #bytes/2^10 */
+#define GCscale(x) ((int)((x)>>10))
+#define GCunscale(x) ((unsigned long)(x)<<10)
+
+LUA_API int lua_getgcthreshold (lua_State *L) {
+ return GCscale(L->GCthreshold);
+}
+
+LUA_API int lua_getgccount (lua_State *L) {
+ return GCscale(L->nblocks);
+}
+
+LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) {
+ if (newthreshold > GCscale(ULONG_MAX))
+ L->GCthreshold = ULONG_MAX;
+ else
+ L->GCthreshold = GCunscale(newthreshold);
+ luaC_checkGC(L);
+}
+
+
+/*
+** miscellaneous functions
+*/
+
+LUA_API void lua_settag (lua_State *L, int tag) {
+ luaT_realtag(L, tag);
+ switch (ttype(L->top-1)) {
+ case LUA_TTABLE:
+ hvalue(L->top-1)->htag = tag;
+ break;
+ case LUA_TUSERDATA:
+ tsvalue(L->top-1)->u.d.tag = tag;
+ break;
+ default:
+ luaO_verror(L, "cannot change the tag of a %.20s",
+ luaO_typename(L->top-1));
+ }
+}
+
+
+LUA_API void lua_unref (lua_State *L, int ref) {
+ if (ref >= 0) {
+ LUA_ASSERT(ref < L->refSize && L->refArray[ref].st < 0, "invalid ref");
+ L->refArray[ref].st = L->refFree;
+ L->refFree = ref;
+ }
+}
+
+
+LUA_API int lua_next (lua_State *L, int index) {
+ StkId t = luaA_index(L, index);
+ Node *n;
+ LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected");
+ n = luaH_next(L, hvalue(t), luaA_index(L, -1));
+ if (n) {
+ *(L->top-1) = *key(n);
+ *L->top = *val(n);
+ api_incr_top(L);
+ return 1;
+ }
+ else { /* no more elements */
+ L->top -= 1; /* remove key */
+ return 0;
+ }
+}
+
+
+LUA_API int lua_getn (lua_State *L, int index) {
+ Hash *h = hvalue(luaA_index(L, index));
+ const TObject *value = luaH_getstr(h, luaS_new(L, "n")); /* value = h.n */
+ if (ttype(value) == LUA_TNUMBER)
+ return (int)nvalue(value);
+ else {
+ Number max = 0;
+ int i = h->size;
+ Node *n = h->node;
+ while (i--) {
+ if (ttype(key(n)) == LUA_TNUMBER &&
+ ttype(val(n)) != LUA_TNIL &&
+ nvalue(key(n)) > max)
+ max = nvalue(key(n));
+ n++;
+ }
+ return (int)max;
+ }
+}
+
+
+LUA_API void lua_concat (lua_State *L, int n) {
+ StkId top = L->top;
+ luaV_strconc(L, n, top);
+ L->top = top-(n-1);
+ luaC_checkGC(L);
+}
+
+
+LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
+ TString *ts = luaS_newudata(L, size, NULL);
+ tsvalue(L->top) = ts;
+ ttype(L->top) = LUA_TUSERDATA;
+ api_incr_top(L);
+ return ts->u.d.value;
+}
+
diff --git a/src/lua/lapi.h b/src/lua/lapi.h
new file mode 100644
index 00000000..d6e1c44f
--- /dev/null
+++ b/src/lua/lapi.h
@@ -0,0 +1,17 @@
+/*
+** $Id: lapi.h,v 1.3 2001/11/26 23:00:23 darkgod Exp $
+** Auxiliary functions from Lua API
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lapi_h
+#define lapi_h
+
+
+#include "lobject.h"
+
+
+TObject *luaA_index (lua_State *L, int index);
+void luaA_pushobject (lua_State *L, const TObject *o);
+
+#endif
diff --git a/src/lua/lauxlib.c b/src/lua/lauxlib.c
new file mode 100644
index 00000000..810bca20
--- /dev/null
+++ b/src/lua/lauxlib.c
@@ -0,0 +1,216 @@
+/*
+** $Id: lauxlib.c,v 1.3 2001/11/26 23:00:23 darkgod Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+/* This file uses only the official API of Lua.
+** Any function declared here could be written as an application function.
+** With care, these functions can be used by other libraries.
+*/
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "luadebug.h"
+
+
+
+LUALIB_API int luaL_findstring (const char *name, const char *const list[]) {
+ int i;
+ for (i=0; list[i]; i++)
+ if (strcmp(list[i], name) == 0)
+ return i;
+ return -1; /* name not found */
+}
+
+LUALIB_API void luaL_argerror (lua_State *L, int narg, const char *extramsg) {
+ lua_Debug ar;
+ lua_getstack(L, 0, &ar);
+ lua_getinfo(L, "n", &ar);
+ if (ar.name == NULL)
+ ar.name = "?";
+ luaL_verror(L, "bad argument #%d to `%.50s' (%.100s)",
+ narg, ar.name, extramsg);
+}
+
+
+static void type_error (lua_State *L, int narg, int t) {
+ char buff[50];
+ sprintf(buff, "%.8s expected, got %.8s", lua_typename(L, t),
+ lua_typename(L, lua_type(L, narg)));
+ luaL_argerror(L, narg, buff);
+}
+
+
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
+ if (space > lua_stackspace(L))
+ luaL_verror(L, "stack overflow (%.30s)", mes);
+}
+
+
+LUALIB_API void luaL_checktype(lua_State *L, int narg, int t) {
+ if (lua_type(L, narg) != t)
+ type_error(L, narg, t);
+}
+
+
+LUALIB_API void luaL_checkany (lua_State *L, int narg) {
+ if (lua_type(L, narg) == LUA_TNONE)
+ luaL_argerror(L, narg, "value expected");
+}
+
+
+LUALIB_API const char *luaL_check_lstr (lua_State *L, int narg, size_t *len) {
+ const char *s = lua_tostring(L, narg);
+ if (!s) type_error(L, narg, LUA_TSTRING);
+ if (len) *len = lua_strlen(L, narg);
+ return s;
+}
+
+
+LUALIB_API const char *luaL_opt_lstr (lua_State *L, int narg, const char *def, size_t *len) {
+ if (lua_isnull(L, narg)) {
+ if (len)
+ *len = (def ? strlen(def) : 0);
+ return def;
+ }
+ else return luaL_check_lstr(L, narg, len);
+}
+
+
+LUALIB_API long luaL_check_number (lua_State *L, int narg) {
+ long d = lua_tonumber(L, narg);
+ if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
+ type_error(L, narg, LUA_TNUMBER);
+ return d;
+}
+
+
+LUALIB_API long luaL_opt_number (lua_State *L, int narg, long def) {
+ if (lua_isnull(L, narg)) return def;
+ else return luaL_check_number(L, narg);
+}
+
+
+LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n) {
+ int i;
+ for (i=0; i<n; i++)
+ lua_register(L, l[i].name, l[i].func);
+}
+
+
+LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...) {
+ char buff[500];
+ va_list argp;
+ va_start(argp, fmt);
+ vsprintf(buff, fmt, argp);
+ va_end(argp);
+ lua_error(L, buff);
+}
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+
+#define buffempty(B) ((B)->p == (B)->buffer)
+#define bufflen(B) ((B)->p - (B)->buffer)
+#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
+
+#define LIMIT (LUA_MINSTACK/2)
+
+
+static int emptybuffer (luaL_Buffer *B) {
+ size_t l = bufflen(B);
+ if (l == 0) return 0; /* put nothing on stack */
+ else {
+ lua_pushlstring(B->L, B->buffer, l);
+ B->p = B->buffer;
+ B->level++;
+ return 1;
+ }
+}
+
+
+static void adjuststack (luaL_Buffer *B) {
+ if (B->level > 1) {
+ lua_State *L = B->L;
+ int toget = 1; /* number of levels to concat */
+ size_t toplen = lua_strlen(L, -1);
+ do {
+ size_t l = lua_strlen(L, -(toget+1));
+ if (B->level - toget + 1 >= LIMIT || toplen > l) {
+ toplen += l;
+ toget++;
+ }
+ else break;
+ } while (toget < B->level);
+ if (toget >= 2) {
+ lua_concat(L, toget);
+ B->level = B->level - toget + 1;
+ }
+ }
+}
+
+
+LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) {
+ if (emptybuffer(B))
+ adjuststack(B);
+ return B->buffer;
+}
+
+
+LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
+ while (l--)
+ luaL_putchar(B, *s++);
+}
+
+
+LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
+ luaL_addlstring(B, s, strlen(s));
+}
+
+
+LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
+ emptybuffer(B);
+ if (B->level == 0)
+ lua_pushlstring(B->L, NULL, 0);
+ else if (B->level > 1)
+ lua_concat(B->L, B->level);
+ B->level = 1;
+}
+
+
+LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
+ lua_State *L = B->L;
+ size_t vl = lua_strlen(L, -1);
+ if (vl <= bufffree(B)) { /* fit into buffer? */
+ memcpy(B->p, lua_tostring(L, -1), vl); /* put it there */
+ B->p += vl;
+ lua_pop(L, 1); /* remove from stack */
+ }
+ else {
+ if (emptybuffer(B))
+ lua_insert(L, -2); /* put buffer before new value */
+ B->level++; /* add new value into B stack */
+ adjuststack(B);
+ }
+}
+
+
+LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
+ B->L = L;
+ B->p = B->buffer;
+ B->level = 0;
+}
+
+/* }====================================================== */
diff --git a/src/lua/lauxlib.h b/src/lua/lauxlib.h
new file mode 100644
index 00000000..a8d35aff
--- /dev/null
+++ b/src/lua/lauxlib.h
@@ -0,0 +1,100 @@
+/*
+** $Id: lauxlib.h,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_h
+#define lauxlib_h
+
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "lua.h"
+
+
+#ifndef LUALIB_API
+#define LUALIB_API extern
+#endif
+
+
+struct luaL_reg {
+ const char *name;
+ lua_CFunction func;
+};
+
+
+LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n);
+LUALIB_API void luaL_argerror (lua_State *L, int numarg, const char *extramsg);
+LUALIB_API const char *luaL_check_lstr (lua_State *L, int numArg, size_t *len);
+LUALIB_API const char *luaL_opt_lstr (lua_State *L, int numArg, const char *def, size_t *len);
+LUALIB_API long luaL_check_number (lua_State *L, int numArg);
+LUALIB_API long luaL_opt_number (lua_State *L, int numArg, long def);
+
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg);
+LUALIB_API void luaL_checktype (lua_State *L, int narg, int t);
+LUALIB_API void luaL_checkany (lua_State *L, int narg);
+
+LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...);
+LUALIB_API int luaL_findstring (const char *name, const char *const list[]);
+
+
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define luaL_arg_check(L, cond,numarg,extramsg) if (!(cond)) \
+ luaL_argerror(L, numarg,extramsg)
+#define luaL_check_string(L,n) (luaL_check_lstr(L, (n), NULL))
+#define luaL_opt_string(L,n,d) (luaL_opt_lstr(L, (n), (d), NULL))
+#define luaL_check_int(L,n) ((int)luaL_check_number(L, n))
+#define luaL_check_long(L,n) ((long)luaL_check_number(L, n))
+#define luaL_opt_int(L,n,d) ((int)luaL_opt_number(L, n,d))
+#define luaL_opt_long(L,n,d) ((long)luaL_opt_number(L, n,d))
+#define luaL_openl(L,a) luaL_openlib(L, a, (sizeof(a)/sizeof(a[0])))
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+
+#ifndef LUAL_BUFFERSIZE
+#define LUAL_BUFFERSIZE BUFSIZ
+#endif
+
+
+typedef struct luaL_Buffer {
+ char *p; /* current position in buffer */
+ int level;
+ lua_State *L;
+ char buffer[LUAL_BUFFERSIZE];
+} luaL_Buffer;
+
+#define luaL_putchar(B,c) \
+ ((void)((B)->p < &(B)->buffer[LUAL_BUFFERSIZE] || luaL_prepbuffer(B)), \
+ (*(B)->p++ = (char)(c)))
+
+#define luaL_addsize(B,n) ((B)->p += (n))
+
+LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B);
+LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s);
+LUALIB_API void luaL_addvalue (luaL_Buffer *B);
+LUALIB_API void luaL_pushresult (luaL_Buffer *B);
+
+
+/* }====================================================== */
+
+
+#endif
+
+
diff --git a/src/lua/lbaselib.c b/src/lua/lbaselib.c
new file mode 100644
index 00000000..71c643aa
--- /dev/null
+++ b/src/lua/lbaselib.c
@@ -0,0 +1,651 @@
+/*
+** $Id: lbaselib.c,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+** Basic library
+** See Copyright Notice in lua.h
+*/
+
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "luadebug.h"
+#include "lualib.h"
+
+
+
+/*
+** If your system does not support `stderr', redefine this function, or
+** redefine _ERRORMESSAGE so that it won't need _ALERT.
+*/
+static int luaB__ALERT (lua_State *L) {
+ fputs(luaL_check_string(L, 1), stderr);
+ return 0;
+}
+
+
+/*
+** Basic implementation of _ERRORMESSAGE.
+** The library `liolib' redefines _ERRORMESSAGE for better error information.
+*/
+static int luaB__ERRORMESSAGE (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TSTRING);
+ lua_getglobal(L, LUA_ALERT);
+ if (lua_isfunction(L, -1)) { /* avoid error loop if _ALERT is not defined */
+ lua_Debug ar;
+ lua_pushstring(L, "error: ");
+ lua_pushvalue(L, 1);
+ if (lua_getstack(L, 1, &ar)) {
+ lua_getinfo(L, "Sl", &ar);
+ if (ar.source && ar.currentline > 0) {
+ char buff[100];
+ sprintf(buff, "\n <%.70s: line %d>", ar.short_src, ar.currentline);
+ lua_pushstring(L, buff);
+ lua_concat(L, 2);
+ }
+ }
+ lua_pushstring(L, "\n");
+ lua_concat(L, 3);
+ lua_rawcall(L, 1, 0);
+ }
+ return 0;
+}
+
+
+/*
+** If your system does not support `stdout', you can just remove this function.
+** If you need, you can define your own `print' function, following this
+** model but changing `fputs' to put the strings at a proper place
+** (a console window or a log file, for instance).
+*/
+static int luaB_print (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int i;
+ lua_getglobal(L, "tostring");
+ for (i=1; i<=n; i++) {
+ const char *s;
+ lua_pushvalue(L, -1); /* function to be called */
+ lua_pushvalue(L, i); /* value to print */
+ lua_rawcall(L, 1, 1);
+ s = lua_tostring(L, -1); /* get result */
+ if (s == NULL)
+ lua_error(L, "`tostring' must return a string to `print'");
+ if (i>1) fputs("\t", stdout);
+ fputs(s, stdout);
+ lua_pop(L, 1); /* pop result */
+ }
+ fputs("\n", stdout);
+ return 0;
+}
+
+
+static int luaB_tonumber (lua_State *L) {
+ int base = luaL_opt_int(L, 2, 10);
+ if (base == 10) { /* standard conversion */
+ luaL_checkany(L, 1);
+ if (lua_isnumber(L, 1)) {
+ lua_pushnumber(L, lua_tonumber(L, 1));
+ return 1;
+ }
+ }
+ else {
+ const char *s1 = luaL_check_string(L, 1);
+ char *s2;
+ unsigned long n;
+ luaL_arg_check(L, 2 <= base && base <= 36, 2, "base out of range");
+ n = strtoul(s1, &s2, base);
+ if (s1 != s2) { /* at least one valid digit? */
+ while (isspace((unsigned char)*s2)) s2++; /* skip trailing spaces */
+ if (*s2 == '\0') { /* no invalid trailing characters? */
+ lua_pushnumber(L, n);
+ return 1;
+ }
+ }
+ }
+ lua_pushnil(L); /* else not a number */
+ return 1;
+}
+
+
+static int luaB_error (lua_State *L) {
+ lua_error(L, luaL_opt_string(L, 1, NULL));
+ return 0; /* to avoid warnings */
+}
+
+static int luaB_setglobal (lua_State *L) {
+ luaL_checkany(L, 2);
+ lua_setglobal(L, luaL_check_string(L, 1));
+ return 0;
+}
+
+static int luaB_getglobal (lua_State *L) {
+ lua_getglobal(L, luaL_check_string(L, 1));
+ return 1;
+}
+
+static int luaB_tag (lua_State *L) {
+ luaL_checkany(L, 1);
+ lua_pushnumber(L, lua_tag(L, 1));
+ return 1;
+}
+
+static int luaB_settag (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_pushvalue(L, 1); /* push table */
+ lua_settag(L, luaL_check_int(L, 2));
+ return 1; /* return table */
+}
+
+static int luaB_newtag (lua_State *L) {
+ lua_pushnumber(L, lua_newtag(L));
+ return 1;
+}
+
+static int luaB_copytagmethods (lua_State *L) {
+ lua_pushnumber(L, lua_copytagmethods(L, luaL_check_int(L, 1),
+ luaL_check_int(L, 2)));
+ return 1;
+}
+
+static int luaB_globals (lua_State *L) {
+ lua_getglobals(L); /* value to be returned */
+ if (!lua_isnull(L, 1)) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_pushvalue(L, 1); /* new table of globals */
+ lua_setglobals(L);
+ }
+ return 1;
+}
+
+static int luaB_rawget (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checkany(L, 2);
+ lua_rawget(L, -2);
+ return 1;
+}
+
+static int luaB_rawset (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checkany(L, 2);
+ luaL_checkany(L, 3);
+ lua_rawset(L, -3);
+ return 1;
+}
+
+static int luaB_settagmethod (lua_State *L) {
+ int tag = luaL_check_int(L, 1);
+ const char *event = luaL_check_string(L, 2);
+ luaL_arg_check(L, lua_isfunction(L, 3) || lua_isnil(L, 3), 3,
+ "function or nil expected");
+ if (strcmp(event, "gc") == 0)
+ lua_error(L, "deprecated use: cannot set the `gc' tag method from Lua");
+ lua_gettagmethod(L, tag, event);
+ lua_pushvalue(L, 3);
+ lua_settagmethod(L, tag, event);
+ return 1;
+}
+
+
+static int luaB_gettagmethod (lua_State *L) {
+ int tag = luaL_check_int(L, 1);
+ const char *event = luaL_check_string(L, 2);
+ if (strcmp(event, "gc") == 0)
+ lua_error(L, "deprecated use: cannot get the `gc' tag method from Lua");
+ lua_gettagmethod(L, tag, event);
+ return 1;
+}
+
+
+static int luaB_gcinfo (lua_State *L) {
+ lua_pushnumber(L, lua_getgccount(L));
+ lua_pushnumber(L, lua_getgcthreshold(L));
+ return 2;
+}
+
+
+static int luaB_collectgarbage (lua_State *L) {
+ lua_setgcthreshold(L, luaL_opt_int(L, 1, 0));
+ return 0;
+}
+
+
+static int luaB_type (lua_State *L) {
+ luaL_checkany(L, 1);
+ lua_pushstring(L, lua_typename(L, lua_type(L, 1)));
+ return 1;
+}
+
+
+static int luaB_next (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_settop(L, 2); /* create a 2nd argument if there isn't one */
+ if (lua_next(L, 1))
+ return 2;
+ else {
+ lua_pushnil(L);
+ return 1;
+ }
+}
+
+
+static int passresults (lua_State *L, int status, int oldtop) {
+ static const char *const errornames[] =
+ {"ok", "run-time error", "file error", "syntax error",
+ "memory error", "error in error handling"};
+ if (status == 0) {
+ int nresults = lua_gettop(L) - oldtop;
+ if (nresults > 0)
+ return nresults; /* results are already on the stack */
+ else {
+ lua_pushuserdata(L, NULL); /* at least one result to signal no errors */
+ return 1;
+ }
+ }
+ else { /* error */
+ lua_pushnil(L);
+ lua_pushstring(L, errornames[status]); /* error code */
+ return 2;
+ }
+}
+
+static int luaB_dostring (lua_State *L) {
+ int oldtop = lua_gettop(L);
+ size_t l;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ if (*s == '\27') /* binary files start with ESC... */
+ lua_error(L, "`dostring' cannot run pre-compiled code");
+ return passresults(L, lua_dobuffer(L, s, l, luaL_opt_string(L, 2, s)), oldtop);
+}
+
+
+static int luaB_dofile (lua_State *L) {
+ int oldtop = lua_gettop(L);
+ const char *fname = luaL_opt_string(L, 1, NULL);
+ return passresults(L, lua_dofile(L, fname), oldtop);
+}
+
+
+static int luaB_call (lua_State *L) {
+ int oldtop;
+ const char *options = luaL_opt_string(L, 3, "");
+ int err = 0; /* index of old error method */
+ int i, status;
+ int n;
+ luaL_checktype(L, 2, LUA_TTABLE);
+ n = lua_getn(L, 2);
+ if (!lua_isnull(L, 4)) { /* set new error method */
+ lua_getglobal(L, LUA_ERRORMESSAGE);
+ err = lua_gettop(L); /* get index */
+ lua_pushvalue(L, 4);
+ lua_setglobal(L, LUA_ERRORMESSAGE);
+ }
+ oldtop = lua_gettop(L); /* top before function-call preparation */
+ /* push function */
+ lua_pushvalue(L, 1);
+ luaL_checkstack(L, n, "too many arguments");
+ for (i=0; i<n; i++) /* push arg[1...n] */
+ lua_rawgeti(L, 2, i+1);
+ status = lua_call(L, n, LUA_MULTRET);
+ if (err != 0) { /* restore old error method */
+ lua_pushvalue(L, err);
+ lua_setglobal(L, LUA_ERRORMESSAGE);
+ }
+ if (status != 0) { /* error in call? */
+ if (strchr(options, 'x'))
+ lua_pushnil(L); /* return nil to signal the error */
+ else
+ lua_error(L, NULL); /* propagate error without additional messages */
+ return 1;
+ }
+ if (strchr(options, 'p')) /* pack results? */
+ lua_error(L, "deprecated option `p' in `call'");
+ return lua_gettop(L) - oldtop; /* results are already on the stack */
+}
+
+
+static int luaB_tostring (lua_State *L) {
+ char buff[64];
+ switch (lua_type(L, 1)) {
+ case LUA_TNUMBER:
+ lua_pushstring(L, lua_tostring(L, 1));
+ return 1;
+ case LUA_TSTRING:
+ lua_pushvalue(L, 1);
+ return 1;
+ case LUA_TTABLE:
+ sprintf(buff, "table: %p", lua_topointer(L, 1));
+ break;
+ case LUA_TFUNCTION:
+ sprintf(buff, "function: %p", lua_topointer(L, 1));
+ break;
+ case LUA_TUSERDATA:
+ sprintf(buff, "userdata(%d): %p", lua_tag(L, 1), lua_touserdata(L, 1));
+ break;
+ case LUA_TNIL:
+ lua_pushstring(L, "nil");
+ return 1;
+ default:
+ luaL_argerror(L, 1, "value expected");
+ }
+ lua_pushstring(L, buff);
+ return 1;
+}
+
+
+static int luaB_foreachi (lua_State *L) {
+ int n, i;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ n = lua_getn(L, 1);
+ for (i=1; i<=n; i++) {
+ lua_pushvalue(L, 2); /* function */
+ lua_pushnumber(L, i); /* 1st argument */
+ lua_rawgeti(L, 1, i); /* 2nd argument */
+ lua_rawcall(L, 2, 1);
+ if (!lua_isnil(L, -1))
+ return 1;
+ lua_pop(L, 1); /* remove nil result */
+ }
+ return 0;
+}
+
+
+static int luaB_foreach (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ lua_pushnil(L); /* first index */
+ for (;;) {
+ if (lua_next(L, 1) == 0)
+ return 0;
+ lua_pushvalue(L, 2); /* function */
+ lua_pushvalue(L, -3); /* key */
+ lua_pushvalue(L, -3); /* value */
+ lua_rawcall(L, 2, 1);
+ if (!lua_isnil(L, -1))
+ return 1;
+ lua_pop(L, 2); /* remove value and result */
+ }
+}
+
+
+static int luaB_assert (lua_State *L) {
+ luaL_checkany(L, 1);
+ if (lua_isnil(L, 1))
+ luaL_verror(L, "assertion failed! %.90s", luaL_opt_string(L, 2, ""));
+ return 0;
+}
+
+
+static int luaB_getn (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_pushnumber(L, lua_getn(L, 1));
+ return 1;
+}
+
+
+static int luaB_tinsert (lua_State *L) {
+ int v = lua_gettop(L); /* last argument: to be inserted */
+ int n, pos;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ n = lua_getn(L, 1);
+ if (v == 2) /* called with only 2 arguments */
+ pos = n+1;
+ else
+ pos = luaL_check_int(L, 2); /* 2nd argument is the position */
+ lua_pushstring(L, "n");
+ lua_pushnumber(L, n+1);
+ lua_rawset(L, 1); /* t.n = n+1 */
+ for (; n>=pos; n--) {
+ lua_rawgeti(L, 1, n);
+ lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */
+ }
+ lua_pushvalue(L, v);
+ lua_rawseti(L, 1, pos); /* t[pos] = v */
+ return 0;
+}
+
+
+static int luaB_tremove (lua_State *L) {
+ int pos, n;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ n = lua_getn(L, 1);
+ pos = luaL_opt_int(L, 2, n);
+ if (n <= 0) return 0; /* table is "empty" */
+ lua_rawgeti(L, 1, pos); /* result = t[pos] */
+ for ( ;pos<n; pos++) {
+ lua_rawgeti(L, 1, pos+1);
+ lua_rawseti(L, 1, pos); /* a[pos] = a[pos+1] */
+ }
+ lua_pushstring(L, "n");
+ lua_pushnumber(L, n-1);
+ lua_rawset(L, 1); /* t.n = n-1 */
+ lua_pushnil(L);
+ lua_rawseti(L, 1, n); /* t[n] = nil */
+ return 1;
+}
+
+
+
+
+/*
+** {======================================================
+** Quicksort
+** (based on `Algorithms in MODULA-3', Robert Sedgewick;
+** Addison-Wesley, 1993.)
+*/
+
+
+static void set2 (lua_State *L, int i, int j) {
+ lua_rawseti(L, 1, i);
+ lua_rawseti(L, 1, j);
+}
+
+static int sort_comp (lua_State *L, int a, int b) {
+ /* WARNING: the caller (auxsort) must ensure stack space */
+ if (!lua_isnil(L, 2)) { /* function? */
+ int res;
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, a-1); /* -1 to compensate function */
+ lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
+ lua_rawcall(L, 2, 1);
+ res = !lua_isnil(L, -1);
+ lua_pop(L, 1);
+ return res;
+ }
+ else /* a < b? */
+ return lua_lessthan(L, a, b);
+}
+
+static void auxsort (lua_State *L, int l, int u) {
+ while (l < u) { /* for tail recursion */
+ int i, j;
+ /* sort elements a[l], a[(l+u)/2] and a[u] */
+ lua_rawgeti(L, 1, l);
+ lua_rawgeti(L, 1, u);
+ if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
+ set2(L, l, u); /* swap a[l] - a[u] */
+ else
+ lua_pop(L, 2);
+ if (u-l == 1) break; /* only 2 elements */
+ i = (l+u)/2;
+ lua_rawgeti(L, 1, i);
+ lua_rawgeti(L, 1, l);
+ if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
+ set2(L, i, l);
+ else {
+ lua_pop(L, 1); /* remove a[l] */
+ lua_rawgeti(L, 1, u);
+ if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
+ set2(L, i, u);
+ else
+ lua_pop(L, 2);
+ }
+ if (u-l == 2) break; /* only 3 elements */
+ lua_rawgeti(L, 1, i); /* Pivot */
+ lua_pushvalue(L, -1);
+ lua_rawgeti(L, 1, u-1);
+ set2(L, i, u-1);
+ /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
+ i = l; j = u-1;
+ for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
+ /* repeat ++i until a[i] >= P */
+ while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
+ if (i>u) lua_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[i] */
+ }
+ /* repeat --j until a[j] <= P */
+ while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
+ if (j<l) lua_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[j] */
+ }
+ if (j<i) {
+ lua_pop(L, 3); /* pop pivot, a[i], a[j] */
+ break;
+ }
+ set2(L, i, j);
+ }
+ lua_rawgeti(L, 1, u-1);
+ lua_rawgeti(L, 1, i);
+ set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
+ /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
+ /* adjust so that smaller "half" is in [j..i] and larger one in [l..u] */
+ if (i-l < u-i) {
+ j=l; i=i-1; l=i+2;
+ }
+ else {
+ j=i+1; i=u; u=j-2;
+ }
+ auxsort(L, j, i); /* call recursively the smaller one */
+ } /* repeat the routine for the larger one */
+}
+
+static int luaB_sort (lua_State *L) {
+ int n;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ n = lua_getn(L, 1);
+ if (!lua_isnull(L, 2)) /* is there a 2nd argument? */
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ lua_settop(L, 2); /* make sure there is two arguments */
+ auxsort(L, 1, n);
+ return 0;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** Deprecated functions to manipulate global environment.
+** =======================================================
+*/
+
+
+#define num_deprecated 4
+
+static const struct luaL_reg deprecated_names [num_deprecated] = {
+ {"foreachvar", luaB_foreach},
+ {"nextvar", luaB_next},
+ {"rawgetglobal", luaB_rawget},
+ {"rawsetglobal", luaB_rawset}
+};
+
+
+#ifdef LUA_DEPRECATEDFUNCS
+
+/*
+** call corresponding function inserting `globals' as first argument
+*/
+static int deprecated_func (lua_State *L) {
+ lua_insert(L, 1); /* upvalue is the function to be called */
+ lua_getglobals(L);
+ lua_insert(L, 2); /* table of globals is 1o argument */
+ lua_rawcall(L, lua_gettop(L)-1, LUA_MULTRET);
+ return lua_gettop(L); /* return all results */
+}
+
+
+static void deprecated_funcs (lua_State *L) {
+ int i;
+ for (i=0; i<num_deprecated; i++) {
+ lua_pushcfunction(L, deprecated_names[i].func);
+ lua_pushcclosure(L, deprecated_func, 1);
+ lua_setglobal(L, deprecated_names[i].name);
+ }
+}
+
+
+#else
+
+/*
+** gives an explicit error in any attempt to call a deprecated function
+*/
+static int deprecated_func (lua_State *L) {
+ luaL_verror(L, "function `%.20s' is deprecated", lua_tostring(L, -1));
+ return 0; /* to avoid warnings */
+}
+
+
+static void deprecated_funcs (lua_State *L) {
+ int i;
+ for (i=0; i<num_deprecated; i++) {
+ lua_pushstring(L, deprecated_names[i].name);
+ lua_pushcclosure(L, deprecated_func, 1);
+ lua_setglobal(L, deprecated_names[i].name);
+ }
+}
+
+#endif
+
+/* }====================================================== */
+
+static const struct luaL_reg base_funcs[] = {
+ {LUA_ALERT, luaB__ALERT},
+ {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE},
+ {"call", luaB_call},
+ {"collectgarbage", luaB_collectgarbage},
+ {"copytagmethods", luaB_copytagmethods},
+ {"dofile", luaB_dofile},
+ {"dostring", luaB_dostring},
+ {"error", luaB_error},
+ {"foreach", luaB_foreach},
+ {"foreachi", luaB_foreachi},
+ {"gcinfo", luaB_gcinfo},
+ {"getglobal", luaB_getglobal},
+ {"gettagmethod", luaB_gettagmethod},
+ {"globals", luaB_globals},
+ {"newtag", luaB_newtag},
+ {"next", luaB_next},
+ {"print", luaB_print},
+ {"rawget", luaB_rawget},
+ {"rawset", luaB_rawset},
+ {"rawgettable", luaB_rawget}, /* for compatibility */
+ {"rawsettable", luaB_rawset}, /* for compatibility */
+ {"setglobal", luaB_setglobal},
+ {"settag", luaB_settag},
+ {"settagmethod", luaB_settagmethod},
+ {"tag", luaB_tag},
+ {"tonumber", luaB_tonumber},
+ {"tostring", luaB_tostring},
+ {"type", luaB_type},
+ {"assert", luaB_assert},
+ {"getn", luaB_getn},
+ {"sort", luaB_sort},
+ {"tinsert", luaB_tinsert},
+ {"tremove", luaB_tremove}
+};
+
+
+
+LUALIB_API void lua_baselibopen (lua_State *L) {
+ luaL_openl(L, base_funcs);
+ lua_pushstring(L, LUA_VERSION);
+ lua_setglobal(L, "_VERSION");
+ deprecated_funcs(L);
+}
+
diff --git a/src/lua/lcode.c b/src/lua/lcode.c
new file mode 100644
index 00000000..89de4a55
--- /dev/null
+++ b/src/lua/lcode.c
@@ -0,0 +1,701 @@
+/*
+** $Id: lcode.c,v 1.4 2004/06/04 13:42:10 neil Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#include "stdlib.h"
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldo.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+
+
+void luaK_error (LexState *ls, const char *msg) {
+ luaX_error(ls, msg, ls->t.token);
+}
+
+
+/*
+** Returns the the previous instruction, for optimizations.
+** If there is a jump target between this and the current instruction,
+** returns a dummy instruction to avoid wrong optimizations.
+*/
+static Instruction previous_instruction (FuncState *fs) {
+ if (fs->pc > fs->lasttarget) /* no jumps to current position? */
+ return fs->f->code[fs->pc-1]; /* returns previous instruction */
+ else
+ return CREATE_0(OP_END); /* no optimizations after an `END' */
+}
+
+
+int luaK_jump (FuncState *fs) {
+ int j = luaK_code1(fs, OP_JMP, NO_JUMP);
+ if (j == fs->lasttarget) { /* possible jumps to this jump? */
+ luaK_concat(fs, &j, fs->jlt); /* keep them on hold */
+ fs->jlt = NO_JUMP;
+ }
+ return j;
+}
+
+
+static void luaK_fixjump (FuncState *fs, int pc, int dest) {
+ Instruction *jmp = &fs->f->code[pc];
+ if (dest == NO_JUMP)
+ SETARG_S(*jmp, NO_JUMP); /* point to itself to represent end of list */
+ else { /* jump is relative to position following jump instruction */
+ int offset = dest-(pc+1);
+ if (abs(offset) > MAXARG_S)
+ luaK_error(fs->ls, "control structure too long");
+ SETARG_S(*jmp, offset);
+ }
+}
+
+
+static int luaK_getjump (FuncState *fs, int pc) {
+ int offset = GETARG_S(fs->f->code[pc]);
+ if (offset == NO_JUMP) /* point to itself represents end of list */
+ return NO_JUMP; /* end of list */
+ else
+ return (pc+1)+offset; /* turn offset into absolute position */
+}
+
+
+/*
+** returns current `pc' and marks it as a jump target (to avoid wrong
+** optimizations with consecutive instructions not in the same basic block).
+** discharge list of jumps to last target.
+*/
+int luaK_getlabel (FuncState *fs) {
+ if (fs->pc != fs->lasttarget) {
+ int lasttarget = fs->lasttarget;
+ fs->lasttarget = fs->pc;
+ luaK_patchlist(fs, fs->jlt, lasttarget); /* discharge old list `jlt' */
+ fs->jlt = NO_JUMP; /* nobody jumps to this new label (yet) */
+ }
+ return fs->pc;
+}
+
+
+void luaK_deltastack (FuncState *fs, int delta) {
+ fs->stacklevel += delta;
+ if (fs->stacklevel > fs->f->maxstacksize) {
+ if (fs->stacklevel > MAXSTACK)
+ luaK_error(fs->ls, "function or expression too complex");
+ fs->f->maxstacksize = fs->stacklevel;
+ }
+}
+
+
+void luaK_kstr (LexState *ls, int c) {
+ luaK_code1(ls->fs, OP_PUSHSTRING, c);
+}
+
+
+static int number_constant (FuncState *fs, Number r) {
+ /* check whether `r' has appeared within the last LOOKBACKNUMS entries */
+ Proto *f = fs->f;
+ int c = f->nknum;
+ int lim = c < LOOKBACKNUMS ? 0 : c-LOOKBACKNUMS;
+ while (--c >= lim)
+ if (f->knum[c] == r) return c;
+ /* not found; create a new entry */
+ luaM_growvector(fs->L, f->knum, f->nknum, 1, Number,
+ "constant table overflow", MAXARG_U);
+ c = f->nknum++;
+ f->knum[c] = r;
+ return c;
+}
+
+
+void luaK_number (FuncState *fs, Number f) {
+ if (f <= (Number)MAXARG_S && (Number)(int)f == f)
+ luaK_code1(fs, OP_PUSHINT, (int)f); /* f has a short integer value */
+ else
+ luaK_code1(fs, OP_PUSHNUM, number_constant(fs, f));
+}
+
+
+void luaK_adjuststack (FuncState *fs, int n) {
+ if (n > 0)
+ luaK_code1(fs, OP_POP, n);
+ else
+ luaK_code1(fs, OP_PUSHNIL, -n);
+}
+
+
+int luaK_lastisopen (FuncState *fs) {
+ /* check whether last instruction is an open function call */
+ Instruction i = previous_instruction(fs);
+ if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET)
+ return 1;
+ else return 0;
+}
+
+
+void luaK_setcallreturns (FuncState *fs, int nresults) {
+ if (luaK_lastisopen(fs)) { /* expression is an open function call? */
+ SETARG_B(fs->f->code[fs->pc-1], nresults); /* set number of results */
+ luaK_deltastack(fs, nresults); /* push results */
+ }
+}
+
+
+static int discharge (FuncState *fs, expdesc *var) {
+ switch (var->k) {
+ case VLOCAL:
+ luaK_code1(fs, OP_GETLOCAL, var->u.index);
+ break;
+ case VGLOBAL:
+ luaK_code1(fs, OP_GETGLOBAL, var->u.index);
+ break;
+ case VINDEXED:
+ luaK_code0(fs, OP_GETTABLE);
+ break;
+ case VEXP:
+ return 0; /* nothing to do */
+ }
+ var->k = VEXP;
+ var->u.l.t = var->u.l.f = NO_JUMP;
+ return 1;
+}
+
+
+static void discharge1 (FuncState *fs, expdesc *var) {
+ discharge(fs, var);
+ /* if it has jumps then it is already discharged */
+ if (var->u.l.t == NO_JUMP && var->u.l.f == NO_JUMP)
+ luaK_setcallreturns(fs, 1); /* call must return 1 value */
+}
+
+
+void luaK_storevar (LexState *ls, const expdesc *var) {
+ FuncState *fs = ls->fs;
+ switch (var->k) {
+ case VLOCAL:
+ luaK_code1(fs, OP_SETLOCAL, var->u.index);
+ break;
+ case VGLOBAL:
+ luaK_code1(fs, OP_SETGLOBAL, var->u.index);
+ break;
+ case VINDEXED: /* table is at top-3; pop 3 elements after operation */
+ luaK_code2(fs, OP_SETTABLE, 3, 3);
+ break;
+ default:
+ LUA_INTERNALERROR("invalid var kind to store");
+ }
+}
+
+
+static OpCode invertjump (OpCode op) {
+ switch (op) {
+ case OP_JMPNE: return OP_JMPEQ;
+ case OP_JMPEQ: return OP_JMPNE;
+ case OP_JMPLT: return OP_JMPGE;
+ case OP_JMPLE: return OP_JMPGT;
+ case OP_JMPGT: return OP_JMPLE;
+ case OP_JMPGE: return OP_JMPLT;
+ case OP_JMPT: case OP_JMPONT: return OP_JMPF;
+ case OP_JMPF: case OP_JMPONF: return OP_JMPT;
+ default:
+ LUA_INTERNALERROR("invalid jump instruction");
+ return OP_END; /* to avoid warnings */
+ }
+}
+
+
+static void luaK_patchlistaux (FuncState *fs, int list, int target,
+ OpCode special, int special_target) {
+ Instruction *code = fs->f->code;
+ while (list != NO_JUMP) {
+ int next = luaK_getjump(fs, list);
+ Instruction *i = &code[list];
+ OpCode op = GET_OPCODE(*i);
+ if (op == special) /* this `op' already has a value */
+ luaK_fixjump(fs, list, special_target);
+ else {
+ luaK_fixjump(fs, list, target); /* do the patch */
+ if (op == OP_JMPONT) /* remove eventual values */
+ SET_OPCODE(*i, OP_JMPT);
+ else if (op == OP_JMPONF)
+ SET_OPCODE(*i, OP_JMPF);
+ }
+ list = next;
+ }
+}
+
+
+void luaK_patchlist (FuncState *fs, int list, int target) {
+ if (target == fs->lasttarget) /* same target that list `jlt'? */
+ luaK_concat(fs, &fs->jlt, list); /* delay fixing */
+ else
+ luaK_patchlistaux(fs, list, target, OP_END, 0);
+}
+
+
+static int need_value (FuncState *fs, int list, OpCode hasvalue) {
+ /* check whether list has a jump without a value */
+ for (; list != NO_JUMP; list = luaK_getjump(fs, list))
+ if (GET_OPCODE(fs->f->code[list]) != hasvalue) return 1;
+ return 0; /* not found */
+}
+
+
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+ if (*l1 == NO_JUMP)
+ *l1 = l2;
+ else {
+ int list = *l1;
+ for (;;) { /* traverse `l1' */
+ int next = luaK_getjump(fs, list);
+ if (next == NO_JUMP) { /* end of list? */
+ luaK_fixjump(fs, list, l2);
+ return;
+ }
+ list = next;
+ }
+ }
+}
+
+
+static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) {
+ int prevpos; /* position of last instruction */
+ Instruction *previous;
+ int *golist, *exitlist;
+ if (!invert) {
+ golist = &v->u.l.f; /* go if false */
+ exitlist = &v->u.l.t; /* exit if true */
+ }
+ else {
+ golist = &v->u.l.t; /* go if true */
+ exitlist = &v->u.l.f; /* exit if false */
+ }
+ discharge1(fs, v);
+ prevpos = fs->pc-1;
+ previous = &fs->f->code[prevpos];
+ LUA_ASSERT(*previous==previous_instruction(fs), "no jump allowed here");
+ if (!ISJUMP(GET_OPCODE(*previous)))
+ prevpos = luaK_code1(fs, jump, NO_JUMP);
+ else { /* last instruction is already a jump */
+ if (invert)
+ SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
+ }
+ luaK_concat(fs, exitlist, prevpos); /* insert last jump in `exitlist' */
+ luaK_patchlist(fs, *golist, luaK_getlabel(fs));
+ *golist = NO_JUMP;
+}
+
+
+void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue) {
+ luaK_testgo(fs, v, 1, keepvalue ? OP_JMPONF : OP_JMPF);
+}
+
+
+static void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue) {
+ luaK_testgo(fs, v, 0, keepvalue ? OP_JMPONT : OP_JMPT);
+}
+
+
+static int code_label (FuncState *fs, OpCode op, int arg) {
+ luaK_getlabel(fs); /* those instructions may be jump targets */
+ return luaK_code1(fs, op, arg);
+}
+
+
+void luaK_tostack (LexState *ls, expdesc *v, int onlyone) {
+ FuncState *fs = ls->fs;
+ if (!discharge(fs, v)) { /* `v' is an expression? */
+ OpCode previous = GET_OPCODE(fs->f->code[fs->pc-1]);
+ if (!ISJUMP(previous) && v->u.l.f == NO_JUMP && v->u.l.t == NO_JUMP) {
+ /* expression has no jumps */
+ if (onlyone)
+ luaK_setcallreturns(fs, 1); /* call must return 1 value */
+ }
+ else { /* expression has jumps */
+ int final; /* position after whole expression */
+ int j = NO_JUMP; /* eventual jump over values */
+ int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */
+ int p_1 = NO_JUMP; /* position of an eventual PUSHINT */
+ if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF)
+ || need_value(fs, v->u.l.t, OP_JMPONT)) {
+ /* expression needs values */
+ if (ISJUMP(previous))
+ luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in t. list */
+ else {
+ j = code_label(fs, OP_JMP, NO_JUMP); /* to jump over both pushes */
+ /* correct stack for compiler and symbolic execution */
+ luaK_adjuststack(fs, 1);
+ }
+ p_nil = code_label(fs, OP_PUSHNILJMP, 0);
+ p_1 = code_label(fs, OP_PUSHINT, 1);
+ luaK_patchlist(fs, j, luaK_getlabel(fs));
+ }
+ final = luaK_getlabel(fs);
+ luaK_patchlistaux(fs, v->u.l.f, p_nil, OP_JMPONF, final);
+ luaK_patchlistaux(fs, v->u.l.t, p_1, OP_JMPONT, final);
+ v->u.l.f = v->u.l.t = NO_JUMP;
+ }
+ }
+}
+
+
+void luaK_prefix (LexState *ls, UnOpr op, expdesc *v) {
+ FuncState *fs = ls->fs;
+ if (op == OPR_MINUS) {
+ luaK_tostack(ls, v, 1);
+ luaK_code0(fs, OP_MINUS);
+ }
+ else { /* op == NOT */
+ Instruction *previous;
+ discharge1(fs, v);
+ previous = &fs->f->code[fs->pc-1];
+ if (ISJUMP(GET_OPCODE(*previous)))
+ SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
+ else
+ luaK_code0(fs, OP_NOT);
+ /* interchange true and false lists */
+ { int temp = v->u.l.f; v->u.l.f = v->u.l.t; v->u.l.t = temp; }
+ }
+}
+
+
+void luaK_infix (LexState *ls, BinOpr op, expdesc *v) {
+ FuncState *fs = ls->fs;
+ switch (op) {
+ case OPR_AND:
+ luaK_goiftrue(fs, v, 1);
+ break;
+ case OPR_OR:
+ luaK_goiffalse(fs, v, 1);
+ break;
+ default:
+ luaK_tostack(ls, v, 1); /* all other binary operators need a value */
+ }
+}
+
+
+
+static const struct {
+ OpCode opcode; /* opcode for each binary operator */
+ int arg; /* default argument for the opcode */
+} codes[] = { /* ORDER OPR */
+ {OP_ADD, 0}, {OP_SUB, 0}, {OP_MULT, 0}, {OP_DIV, 0},
+ {OP_POW, 0}, {OP_CONCAT, 2},
+ {OP_JMPNE, NO_JUMP}, {OP_JMPEQ, NO_JUMP},
+ {OP_JMPLT, NO_JUMP}, {OP_JMPLE, NO_JUMP},
+ {OP_JMPGT, NO_JUMP}, {OP_JMPGE, NO_JUMP}
+};
+
+
+void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2) {
+ FuncState *fs = ls->fs;
+ switch (op) {
+ case OPR_AND: {
+ LUA_ASSERT(v1->u.l.t == NO_JUMP, "list must be closed");
+ discharge1(fs, v2);
+ v1->u.l.t = v2->u.l.t;
+ luaK_concat(fs, &v1->u.l.f, v2->u.l.f);
+ break;
+ }
+ case OPR_OR: {
+ LUA_ASSERT(v1->u.l.f == NO_JUMP, "list must be closed");
+ discharge1(fs, v2);
+ v1->u.l.f = v2->u.l.f;
+ luaK_concat(fs, &v1->u.l.t, v2->u.l.t);
+ break;
+ }
+ default: {
+ luaK_tostack(ls, v2, 1); /* `v2' must be a value */
+ luaK_code1(fs, codes[op].opcode, codes[op].arg);
+ }
+ }
+}
+
+
+static void codelineinfo (FuncState *fs) {
+ Proto *f = fs->f;
+ LexState *ls = fs->ls;
+ if (ls->lastline > fs->lastline) {
+ luaM_growvector(fs->L, f->lineinfo, f->nlineinfo, 2, int,
+ "line info overflow", MAX_INT);
+ if (ls->lastline > fs->lastline+1)
+ f->lineinfo[f->nlineinfo++] = -(ls->lastline - (fs->lastline+1));
+ f->lineinfo[f->nlineinfo++] = fs->pc;
+ fs->lastline = ls->lastline;
+ }
+}
+
+
+int luaK_code0 (FuncState *fs, OpCode o) {
+ return luaK_code2(fs, o, 0, 0);
+}
+
+
+int luaK_code1 (FuncState *fs, OpCode o, int arg1) {
+ return luaK_code2(fs, o, arg1, 0);
+}
+
+
+int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
+ Instruction i = previous_instruction(fs);
+ int delta = luaK_opproperties[o].push - luaK_opproperties[o].pop;
+ int optm = 0; /* 1 when there is an optimization */
+ switch (o) {
+ case OP_CLOSURE: {
+ delta = -arg2+1;
+ break;
+ }
+ case OP_SETTABLE: {
+ delta = -arg2;
+ break;
+ }
+ case OP_SETLIST: {
+ if (arg2 == 0) return NO_JUMP; /* nothing to do */
+ delta = -arg2;
+ break;
+ }
+ case OP_SETMAP: {
+ if (arg1 == 0) return NO_JUMP; /* nothing to do */
+ delta = -2*arg1;
+ break;
+ }
+ case OP_RETURN: {
+ if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) {
+ SET_OPCODE(i, OP_TAILCALL);
+ SETARG_B(i, arg1);
+ optm = 1;
+ }
+ break;
+ }
+ case OP_PUSHNIL: {
+ if (arg1 == 0) return NO_JUMP; /* nothing to do */
+ delta = arg1;
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHNIL: SETARG_U(i, GETARG_U(i)+arg1); optm = 1; break;
+ default: break;
+ }
+ break;
+ }
+ case OP_POP: {
+ if (arg1 == 0) return NO_JUMP; /* nothing to do */
+ delta = -arg1;
+ switch(GET_OPCODE(i)) {
+ case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); optm = 1; break;
+ default: break;
+ }
+ break;
+ }
+ case OP_GETTABLE: {
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHSTRING: /* `t.x' */
+ SET_OPCODE(i, OP_GETDOTTED);
+ optm = 1;
+ break;
+ case OP_GETLOCAL: /* `t[i]' */
+ SET_OPCODE(i, OP_GETINDEXED);
+ optm = 1;
+ break;
+ default: break;
+ }
+ break;
+ }
+ case OP_ADD: {
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break; /* `a+k' */
+ default: break;
+ }
+ break;
+ }
+ case OP_SUB: {
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHINT: /* `a-k' */
+ i = CREATE_S(OP_ADDI, -GETARG_S(i));
+ optm = 1;
+ break;
+ default: break;
+ }
+ break;
+ }
+ case OP_CONCAT: {
+ delta = -arg1+1;
+ switch(GET_OPCODE(i)) {
+ case OP_CONCAT: /* `a..b..c' */
+ SETARG_U(i, GETARG_U(i)+1);
+ optm = 1;
+ break;
+ default: break;
+ }
+ break;
+ }
+ case OP_MINUS: {
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHINT: /* `-k' */
+ SETARG_S(i, -GETARG_S(i));
+ optm = 1;
+ break;
+ case OP_PUSHNUM: /* `-k' */
+ SET_OPCODE(i, OP_PUSHNEGNUM);
+ optm = 1;
+ break;
+ default: break;
+ }
+ break;
+ }
+ case OP_JMPNE: {
+ if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a~=nil' */
+ i = CREATE_S(OP_JMPT, NO_JUMP);
+ optm = 1;
+ }
+ break;
+ }
+ case OP_JMPEQ: {
+ if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a==nil' */
+ i = CREATE_0(OP_NOT);
+ delta = -1; /* just undo effect of previous PUSHNIL */
+ optm = 1;
+ }
+ break;
+ }
+ case OP_JMPT:
+ case OP_JMPONT: {
+ switch (GET_OPCODE(i)) {
+ case OP_NOT: {
+ i = CREATE_S(OP_JMPF, NO_JUMP);
+ optm = 1;
+ break;
+ }
+ case OP_PUSHINT: {
+ if (o == OP_JMPT) { /* JMPONT must keep original integer value */
+ i = CREATE_S(OP_JMP, NO_JUMP);
+ optm = 1;
+ }
+ break;
+ }
+ case OP_PUSHNIL: {
+ if (GETARG_U(i) == 1) {
+ fs->pc--; /* erase previous instruction */
+ luaK_deltastack(fs, -1); /* correct stack */
+ return NO_JUMP;
+ }
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+ case OP_JMPF:
+ case OP_JMPONF: {
+ switch (GET_OPCODE(i)) {
+ case OP_NOT: {
+ i = CREATE_S(OP_JMPT, NO_JUMP);
+ optm = 1;
+ break;
+ }
+ case OP_PUSHINT: { /* `while 1 do ...' */
+ fs->pc--; /* erase previous instruction */
+ luaK_deltastack(fs, -1); /* correct stack */
+ return NO_JUMP;
+ }
+ case OP_PUSHNIL: { /* `repeat ... until nil' */
+ if (GETARG_U(i) == 1) {
+ i = CREATE_S(OP_JMP, NO_JUMP);
+ optm = 1;
+ }
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+ case OP_GETDOTTED:
+ case OP_GETINDEXED:
+ case OP_TAILCALL:
+ case OP_ADDI: {
+ LUA_INTERNALERROR("instruction used only for optimizations");
+ break;
+ }
+ default: {
+ LUA_ASSERT(delta != VD, "invalid delta");
+ break;
+ }
+ }
+ luaK_deltastack(fs, delta);
+ if (optm) { /* optimize: put instruction in place of last one */
+ fs->f->code[fs->pc-1] = i; /* change previous instruction */
+ return fs->pc-1; /* do not generate new instruction */
+ }
+ /* else build new instruction */
+ switch ((enum Mode)luaK_opproperties[o].mode) {
+ case iO: i = CREATE_0(o); break;
+ case iU: i = CREATE_U(o, arg1); break;
+ case iS: i = CREATE_S(o, arg1); break;
+ case iAB: i = CREATE_AB(o, arg1, arg2); break;
+ }
+ codelineinfo(fs);
+ /* put new instruction in code array */
+ luaM_growvector(fs->L, fs->f->code, fs->pc, 1, Instruction,
+ "code size overflow", MAX_INT);
+ fs->f->code[fs->pc] = i;
+ return fs->pc++;
+}
+
+
+const struct OpProperties luaK_opproperties[NUM_OPCODES] = {
+ {iO, 0, 0}, /* OP_END */
+ {iU, 0, 0}, /* OP_RETURN */
+ {iAB, 0, 0}, /* OP_CALL */
+ {iAB, 0, 0}, /* OP_TAILCALL */
+ {iU, VD, 0}, /* OP_PUSHNIL */
+ {iU, VD, 0}, /* OP_POP */
+ {iS, 1, 0}, /* OP_PUSHINT */
+ {iU, 1, 0}, /* OP_PUSHSTRING */
+ {iU, 1, 0}, /* OP_PUSHNUM */
+ {iU, 1, 0}, /* OP_PUSHNEGNUM */
+ {iU, 1, 0}, /* OP_PUSHUPVALUE */
+ {iU, 1, 0}, /* OP_GETLOCAL */
+ {iU, 1, 0}, /* OP_GETGLOBAL */
+ {iO, 1, 2}, /* OP_GETTABLE */
+ {iU, 1, 1}, /* OP_GETDOTTED */
+ {iU, 1, 1}, /* OP_GETINDEXED */
+ {iU, 2, 1}, /* OP_PUSHSELF */
+ {iU, 1, 0}, /* OP_CREATETABLE */
+ {iU, 0, 1}, /* OP_SETLOCAL */
+ {iU, 0, 1}, /* OP_SETGLOBAL */
+ {iAB, VD, 0}, /* OP_SETTABLE */
+ {iAB, VD, 0}, /* OP_SETLIST */
+ {iU, VD, 0}, /* OP_SETMAP */
+ {iO, 1, 2}, /* OP_ADD */
+ {iS, 1, 1}, /* OP_ADDI */
+ {iO, 1, 2}, /* OP_SUB */
+ {iO, 1, 2}, /* OP_MULT */
+ {iO, 1, 2}, /* OP_DIV */
+ {iO, 1, 2}, /* OP_POW */
+ {iU, VD, 0}, /* OP_CONCAT */
+ {iO, 1, 1}, /* OP_MINUS */
+ {iO, 1, 1}, /* OP_NOT */
+ {iS, 0, 2}, /* OP_JMPNE */
+ {iS, 0, 2}, /* OP_JMPEQ */
+ {iS, 0, 2}, /* OP_JMPLT */
+ {iS, 0, 2}, /* OP_JMPLE */
+ {iS, 0, 2}, /* OP_JMPGT */
+ {iS, 0, 2}, /* OP_JMPGE */
+ {iS, 0, 1}, /* OP_JMPT */
+ {iS, 0, 1}, /* OP_JMPF */
+ {iS, 0, 1}, /* OP_JMPONT */
+ {iS, 0, 1}, /* OP_JMPONF */
+ {iS, 0, 0}, /* OP_JMP */
+ {iO, 0, 0}, /* OP_PUSHNILJMP */
+ {iS, 0, 0}, /* OP_FORPREP */
+ {iS, 0, 3}, /* OP_FORLOOP */
+ {iS, 2, 0}, /* OP_LFORPREP */
+ {iS, 0, 3}, /* OP_LFORLOOP */
+ {iAB, VD, 0} /* OP_CLOSURE */
+};
+
diff --git a/src/lua/lcode.h b/src/lua/lcode.h
new file mode 100644
index 00000000..c413c897
--- /dev/null
+++ b/src/lua/lcode.h
@@ -0,0 +1,70 @@
+/*
+** $Id: lcode.h,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lcode_h
+#define lcode_h
+
+#include "llex.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+
+
+/*
+** Marks the end of a patch list. It is an invalid value both as an absolute
+** address, and as a list link (would link an element to itself).
+*/
+#define NO_JUMP (-1)
+
+
+/*
+** grep "ORDER OPR" if you change these enums
+*/
+typedef enum BinOpr {
+ OPR_ADD, OPR_SUB, OPR_MULT, OPR_DIV, OPR_POW,
+ OPR_CONCAT,
+ OPR_NE, OPR_EQ, OPR_LT, OPR_LE, OPR_GT, OPR_GE,
+ OPR_AND, OPR_OR,
+ OPR_NOBINOPR
+} BinOpr;
+
+typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
+
+
+enum Mode {iO, iU, iS, iAB}; /* instruction format */
+
+#define VD 100 /* flag for variable delta */
+
+extern const struct OpProperties {
+ char mode;
+ unsigned char push;
+ unsigned char pop;
+} luaK_opproperties[NUM_OPCODES];
+
+
+void luaK_error (LexState *ls, const char *msg);
+int luaK_code0 (FuncState *fs, OpCode o);
+int luaK_code1 (FuncState *fs, OpCode o, int arg1);
+int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2);
+int luaK_jump (FuncState *fs);
+void luaK_patchlist (FuncState *fs, int list, int target);
+void luaK_concat (FuncState *fs, int *l1, int l2);
+void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue);
+int luaK_getlabel (FuncState *fs);
+void luaK_deltastack (FuncState *fs, int delta);
+void luaK_kstr (LexState *ls, int c);
+void luaK_number (FuncState *fs, Number f);
+void luaK_adjuststack (FuncState *fs, int n);
+int luaK_lastisopen (FuncState *fs);
+void luaK_setcallreturns (FuncState *fs, int nresults);
+void luaK_tostack (LexState *ls, expdesc *v, int onlyone);
+void luaK_storevar (LexState *ls, const expdesc *var);
+void luaK_prefix (LexState *ls, UnOpr op, expdesc *v);
+void luaK_infix (LexState *ls, BinOpr op, expdesc *v);
+void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2);
+
+
+#endif
diff --git a/src/lua/ldblib.c b/src/lua/ldblib.c
new file mode 100644
index 00000000..481f1d6f
--- /dev/null
+++ b/src/lua/ldblib.c
@@ -0,0 +1,188 @@
+/*
+** $Id: ldblib.c,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+** Interface from Lua to its debug API
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "luadebug.h"
+#include "lualib.h"
+
+
+
+static void settabss (lua_State *L, const char *i, const char *v) {
+ lua_pushstring(L, i);
+ lua_pushstring(L, v);
+ lua_settable(L, -3);
+}
+
+
+static void settabsi (lua_State *L, const char *i, int v) {
+ lua_pushstring(L, i);
+ lua_pushnumber(L, v);
+ lua_settable(L, -3);
+}
+
+
+static int getinfo (lua_State *L) {
+ lua_Debug ar;
+ const char *options = luaL_opt_string(L, 2, "flnSu");
+ char buff[20];
+ if (lua_isnumber(L, 1)) {
+ if (!lua_getstack(L, (int)lua_tonumber(L, 1), &ar)) {
+ lua_pushnil(L); /* level out of range */
+ return 1;
+ }
+ }
+ else if (lua_isfunction(L, 1)) {
+ lua_pushvalue(L, 1);
+ sprintf(buff, ">%.10s", options);
+ options = buff;
+ }
+ else
+ luaL_argerror(L, 1, "function or level expected");
+ if (!lua_getinfo(L, options, &ar))
+ luaL_argerror(L, 2, "invalid option");
+ lua_newtable(L);
+ for (; *options; options++) {
+ switch (*options) {
+ case 'S':
+ settabss(L, "source", ar.source);
+ if (ar.source)
+ settabss(L, "short_src", ar.short_src);
+ settabsi(L, "linedefined", ar.linedefined);
+ settabss(L, "what", ar.what);
+ break;
+ case 'l':
+ settabsi(L, "currentline", ar.currentline);
+ break;
+ case 'u':
+ settabsi(L, "nups", ar.nups);
+ break;
+ case 'n':
+ settabss(L, "name", ar.name);
+ settabss(L, "namewhat", ar.namewhat);
+ break;
+ case 'f':
+ lua_pushstring(L, "func");
+ lua_pushvalue(L, -3);
+ lua_settable(L, -3);
+ break;
+ }
+ }
+ return 1; /* return table */
+}
+
+
+static int getlocal (lua_State *L) {
+ lua_Debug ar;
+ const char *name;
+ if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */
+ luaL_argerror(L, 1, "level out of range");
+ name = lua_getlocal(L, &ar, luaL_check_int(L, 2));
+ if (name) {
+ lua_pushstring(L, name);
+ lua_pushvalue(L, -2);
+ return 2;
+ }
+ else {
+ lua_pushnil(L);
+ return 1;
+ }
+}
+
+
+static int setlocal (lua_State *L) {
+ lua_Debug ar;
+ if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */
+ luaL_argerror(L, 1, "level out of range");
+ luaL_checkany(L, 3);
+ lua_pushstring(L, lua_setlocal(L, &ar, luaL_check_int(L, 2)));
+ return 1;
+}
+
+
+
+/* dummy variables (to define unique addresses) */
+static char key1, key2;
+#define KEY_CALLHOOK (&key1)
+#define KEY_LINEHOOK (&key2)
+
+
+static void hookf (lua_State *L, void *key) {
+ lua_getregistry(L);
+ lua_pushuserdata(L, key);
+ lua_gettable(L, -2);
+ if (lua_isfunction(L, -1)) {
+ lua_pushvalue(L, 1);
+ lua_rawcall(L, 1, 0);
+ }
+ else
+ lua_pop(L, 1); /* pop result from gettable */
+ lua_pop(L, 1); /* pop table */
+}
+
+
+static void callf (lua_State *L, lua_Debug *ar) {
+ lua_pushstring(L, ar->event);
+ hookf(L, KEY_CALLHOOK);
+}
+
+
+static void linef (lua_State *L, lua_Debug *ar) {
+ lua_pushnumber(L, ar->currentline);
+ hookf(L, KEY_LINEHOOK);
+}
+
+
+static void sethook (lua_State *L, void *key, lua_Hook hook,
+ lua_Hook (*sethookf)(lua_State * L, lua_Hook h)) {
+ lua_settop(L, 1);
+ if (lua_isnil(L, 1))
+ (*sethookf)(L, NULL);
+ else if (lua_isfunction(L, 1))
+ (*sethookf)(L, hook);
+ else
+ luaL_argerror(L, 1, "function expected");
+ lua_getregistry(L);
+ lua_pushuserdata(L, key);
+ lua_pushvalue(L, -1); /* dup key */
+ lua_gettable(L, -3); /* get old value */
+ lua_pushvalue(L, -2); /* key (again) */
+ lua_pushvalue(L, 1);
+ lua_settable(L, -5); /* set new value */
+}
+
+
+static int setcallhook (lua_State *L) {
+ sethook(L, KEY_CALLHOOK, callf, lua_setcallhook);
+ return 1;
+}
+
+
+static int setlinehook (lua_State *L) {
+ sethook(L, KEY_LINEHOOK, linef, lua_setlinehook);
+ return 1;
+}
+
+
+static const struct luaL_reg dblib[] = {
+ {"getlocal", getlocal},
+ {"getinfo", getinfo},
+ {"setcallhook", setcallhook},
+ {"setlinehook", setlinehook},
+ {"setlocal", setlocal}
+};
+
+
+LUALIB_API void lua_dblibopen (lua_State *L) {
+ luaL_openl(L, dblib);
+}
+
diff --git a/src/lua/ldebug.c b/src/lua/ldebug.c
new file mode 100644
index 00000000..02481b4c
--- /dev/null
+++ b/src/lua/ldebug.c
@@ -0,0 +1,466 @@
+/*
+** $Id: ldebug.c,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+** Debug Interface
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "luadebug.h"
+
+
+
+static const char *getfuncname (lua_State *L, StkId f, const char **name);
+
+
+static void setnormalized (TObject *d, const TObject *s) {
+ if (ttype(s) == LUA_TMARK) {
+ clvalue(d) = infovalue(s)->func;
+ ttype(d) = LUA_TFUNCTION;
+ }
+ else *d = *s;
+}
+
+
+static int isLmark (StkId o) {
+ return (o && ttype(o) == LUA_TMARK && !infovalue(o)->func->isC);
+}
+
+
+LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func) {
+ lua_Hook oldhook = L->callhook;
+ L->callhook = func;
+ return oldhook;
+}
+
+
+LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func) {
+ lua_Hook oldhook = L->linehook;
+ L->linehook = func;
+ return oldhook;
+}
+
+
+static StkId aux_stackedfunction (lua_State *L, int level, StkId top) {
+ int i;
+ for (i = (top-1) - L->stack; i>=0; i--) {
+ if (is_T_MARK(L->stack[i].ttype)) {
+ if (level == 0)
+ return L->stack+i;
+ level--;
+ }
+ }
+ return NULL;
+}
+
+
+LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
+ StkId f = aux_stackedfunction(L, level, L->top);
+ if (f == NULL) return 0; /* there is no such level */
+ else {
+ ar->_func = f;
+ return 1;
+ }
+}
+
+
+static int nups (StkId f) {
+ switch (ttype(f)) {
+ case LUA_TFUNCTION:
+ return clvalue(f)->nupvalues;
+ case LUA_TMARK:
+ return infovalue(f)->func->nupvalues;
+ default:
+ return 0;
+ }
+}
+
+
+int luaG_getline (int *lineinfo, int pc, int refline, int *prefi) {
+ int refi;
+ if (lineinfo == NULL || pc == -1)
+ return -1; /* no line info or function is not active */
+ refi = prefi ? *prefi : 0;
+ if (lineinfo[refi] < 0)
+ refline += -lineinfo[refi++];
+ LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info");
+ while (lineinfo[refi] > pc) {
+ refline--;
+ refi--;
+ if (lineinfo[refi] < 0)
+ refline -= -lineinfo[refi--];
+ LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info");
+ }
+ for (;;) {
+ int nextline = refline + 1;
+ int nextref = refi + 1;
+ if (lineinfo[nextref] < 0)
+ nextline += -lineinfo[nextref++];
+ LUA_ASSERT(lineinfo[nextref] >= 0, "invalid line info");
+ if (lineinfo[nextref] > pc)
+ break;
+ refline = nextline;
+ refi = nextref;
+ }
+ if (prefi) *prefi = refi;
+ return refline;
+}
+
+
+static int currentpc (StkId f) {
+ CallInfo *ci = infovalue(f);
+ LUA_ASSERT(isLmark(f), "function has no pc");
+ if (ci->pc)
+ return (*ci->pc - ci->func->f.l->code) - 1;
+ else
+ return -1; /* function is not active */
+}
+
+
+static int currentline (StkId f) {
+ if (!isLmark(f))
+ return -1; /* only active lua functions have current-line information */
+ else {
+ CallInfo *ci = infovalue(f);
+ int *lineinfo = ci->func->f.l->lineinfo;
+ return luaG_getline(lineinfo, currentpc(f), 1, NULL);
+ }
+}
+
+
+
+static Proto *getluaproto (StkId f) {
+ return (isLmark(f) ? infovalue(f)->func->f.l : NULL);
+}
+
+
+LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
+ const char *name;
+ StkId f = ar->_func;
+ Proto *fp = getluaproto(f);
+ if (!fp) return NULL; /* `f' is not a Lua function? */
+ name = luaF_getlocalname(fp, n, currentpc(f));
+ if (!name) return NULL;
+ luaA_pushobject(L, (f+1)+(n-1)); /* push value */
+ return name;
+}
+
+
+LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
+ const char *name;
+ StkId f = ar->_func;
+ Proto *fp = getluaproto(f);
+ L->top--; /* pop new value */
+ if (!fp) return NULL; /* `f' is not a Lua function? */
+ name = luaF_getlocalname(fp, n, currentpc(f));
+ if (!name || name[0] == '(') return NULL; /* `(' starts private locals */
+ *((f+1)+(n-1)) = *L->top;
+ return name;
+}
+
+
+static void infoLproto (lua_Debug *ar, Proto *f) {
+ ar->source = f->source->str;
+ ar->linedefined = f->lineDefined;
+ ar->what = "Lua";
+}
+
+
+static void funcinfo (lua_State *L, lua_Debug *ar, StkId func) {
+ Closure *cl = NULL;
+ switch (ttype(func)) {
+ case LUA_TFUNCTION:
+ cl = clvalue(func);
+ break;
+ case LUA_TMARK:
+ cl = infovalue(func)->func;
+ break;
+ default:
+ lua_error(L, "value for `lua_getinfo' is not a function");
+ }
+ if (cl->isC) {
+ ar->source = "=C";
+ ar->linedefined = -1;
+ ar->what = "C";
+ }
+ else
+ infoLproto(ar, cl->f.l);
+ luaO_chunkid(ar->short_src, ar->source, sizeof(ar->short_src));
+ if (ar->linedefined == 0)
+ ar->what = "main";
+}
+
+
+static const char *travtagmethods (lua_State *L, const TObject *o) {
+ if (ttype(o) == LUA_TFUNCTION) {
+ int e;
+ for (e=0; e<TM_N; e++) {
+ int t;
+ for (t=0; t<=L->last_tag; t++)
+ if (clvalue(o) == luaT_gettm(L, t, e))
+ return luaT_eventname[e];
+ }
+ }
+ return NULL;
+}
+
+
+static const char *travglobals (lua_State *L, const TObject *o) {
+ Hash *g = L->gt;
+ int i;
+ for (i=0; i<g->size; i++) {
+ if (luaO_equalObj(o, val(node(g, i))) &&
+ ttype(key(node(g, i))) == LUA_TSTRING)
+ return tsvalue(key(node(g, i)))->str;
+ }
+ return NULL;
+}
+
+
+static void getname (lua_State *L, StkId f, lua_Debug *ar) {
+ TObject o;
+ setnormalized(&o, f);
+ /* try to find a name for given function */
+ if ((ar->name = travglobals(L, &o)) != NULL)
+ ar->namewhat = "global";
+ /* not found: try tag methods */
+ else if ((ar->name = travtagmethods(L, &o)) != NULL)
+ ar->namewhat = "tag-method";
+ else ar->namewhat = ""; /* not found at all */
+}
+
+
+LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
+ StkId func;
+ int isactive = (*what != '>');
+ if (isactive)
+ func = ar->_func;
+ else {
+ what++; /* skip the '>' */
+ func = L->top - 1;
+ }
+ for (; *what; what++) {
+ switch (*what) {
+ case 'S': {
+ funcinfo(L, ar, func);
+ break;
+ }
+ case 'l': {
+ ar->currentline = currentline(func);
+ break;
+ }
+ case 'u': {
+ ar->nups = nups(func);
+ break;
+ }
+ case 'n': {
+ ar->namewhat = (isactive) ? getfuncname(L, func, &ar->name) : NULL;
+ if (ar->namewhat == NULL)
+ getname(L, func, ar);
+ break;
+ }
+ case 'f': {
+ setnormalized(L->top, func);
+ incr_top; /* push function */
+ break;
+ }
+ default: return 0; /* invalid option */
+ }
+ }
+ if (!isactive) L->top--; /* pop function */
+ return 1;
+}
+
+
+/*
+** {======================================================
+** Symbolic Execution
+** =======================================================
+*/
+
+
+static int pushpc (int *stack, int pc, int top, int n) {
+ while (n--)
+ stack[top++] = pc-1;
+ return top;
+}
+
+
+static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) {
+ int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */
+ const Instruction *code = pt->code;
+ int top = pt->numparams;
+ int pc = 0;
+ if (pt->is_vararg) /* varargs? */
+ top++; /* `arg' */
+ while (pc < lastpc) {
+ const Instruction i = code[pc++];
+ LUA_ASSERT(0 <= top && top <= pt->maxstacksize, "wrong stack");
+ switch (GET_OPCODE(i)) {
+ case OP_RETURN: {
+ LUA_ASSERT(top >= GETARG_U(i), "wrong stack");
+ top = GETARG_U(i);
+ break;
+ }
+ case OP_TAILCALL: {
+ LUA_ASSERT(top >= GETARG_A(i), "wrong stack");
+ top = GETARG_B(i);
+ break;
+ }
+ case OP_CALL: {
+ int nresults = GETARG_B(i);
+ if (nresults == MULT_RET) nresults = 1;
+ LUA_ASSERT(top >= GETARG_A(i), "wrong stack");
+ top = pushpc(stack, pc, GETARG_A(i), nresults);
+ break;
+ }
+ case OP_PUSHNIL: {
+ top = pushpc(stack, pc, top, GETARG_U(i));
+ break;
+ }
+ case OP_POP: {
+ top -= GETARG_U(i);
+ break;
+ }
+ case OP_SETTABLE:
+ case OP_SETLIST: {
+ top -= GETARG_B(i);
+ break;
+ }
+ case OP_SETMAP: {
+ top -= 2*GETARG_U(i);
+ break;
+ }
+ case OP_CONCAT: {
+ top -= GETARG_U(i);
+ stack[top++] = pc-1;
+ break;
+ }
+ case OP_CLOSURE: {
+ top -= GETARG_B(i);
+ stack[top++] = pc-1;
+ break;
+ }
+ case OP_JMPONT:
+ case OP_JMPONF: {
+ int newpc = pc + GETARG_S(i);
+ /* jump is forward and do not skip `lastpc'? */
+ if (pc < newpc && newpc <= lastpc) {
+ stack[top-1] = pc-1; /* value comes from `and'/`or' */
+ pc = newpc; /* do the jump */
+ }
+ else
+ top--; /* do not jump; pop value */
+ break;
+ }
+ default: {
+ OpCode op = GET_OPCODE(i);
+ LUA_ASSERT(luaK_opproperties[op].push != VD,
+ "invalid opcode for default");
+ top -= luaK_opproperties[op].pop;
+ LUA_ASSERT(top >= 0, "wrong stack");
+ top = pushpc(stack, pc, top, luaK_opproperties[op].push);
+ }
+ }
+ }
+ return code[stack[stackpos]];
+}
+
+
+static const char *getobjname (lua_State *L, StkId obj, const char **name) {
+ StkId func = aux_stackedfunction(L, 0, obj);
+ if (!isLmark(func))
+ return NULL; /* not an active Lua function */
+ else {
+ Proto *p = infovalue(func)->func->f.l;
+ int pc = currentpc(func);
+ int stackpos = obj - (func+1); /* func+1 == function base */
+ Instruction i = luaG_symbexec(p, pc, stackpos);
+ LUA_ASSERT(pc != -1, "function must be active");
+ switch (GET_OPCODE(i)) {
+ case OP_GETGLOBAL: {
+ *name = p->kstr[GETARG_U(i)]->str;
+ return "global";
+ }
+ case OP_GETLOCAL: {
+ *name = luaF_getlocalname(p, GETARG_U(i)+1, pc);
+ LUA_ASSERT(*name, "local must exist");
+ return "local";
+ }
+ case OP_PUSHSELF:
+ case OP_GETDOTTED: {
+ *name = p->kstr[GETARG_U(i)]->str;
+ return "field";
+ }
+ default:
+ return NULL; /* no useful name found */
+ }
+ }
+}
+
+
+static const char *getfuncname (lua_State *L, StkId f, const char **name) {
+ StkId func = aux_stackedfunction(L, 0, f); /* calling function */
+ if (!isLmark(func))
+ return NULL; /* not an active Lua function */
+ else {
+ Proto *p = infovalue(func)->func->f.l;
+ int pc = currentpc(func);
+ Instruction i;
+ if (pc == -1) return NULL; /* function is not activated */
+ i = p->code[pc];
+ switch (GET_OPCODE(i)) {
+ case OP_CALL: case OP_TAILCALL:
+ return getobjname(L, (func+1)+GETARG_A(i), name);
+ default:
+ return NULL; /* no useful name found */
+ }
+ }
+}
+
+
+/* }====================================================== */
+
+
+void luaG_typeerror (lua_State *L, StkId o, const char *op) {
+ const char *name;
+ const char *kind = getobjname(L, o, &name);
+ const char *t = luaO_typename(o);
+ if (kind)
+ luaO_verror(L, "attempt to %.30s %.20s `%.40s' (a %.10s value)",
+ op, kind, name, t);
+ else
+ luaO_verror(L, "attempt to %.30s a %.10s value", op, t);
+}
+
+
+void luaG_binerror (lua_State *L, StkId p1, int t, const char *op) {
+ if (ttype(p1) == t) p1++;
+ LUA_ASSERT(ttype(p1) != t, "must be an error");
+ luaG_typeerror(L, p1, op);
+}
+
+
+void luaG_ordererror (lua_State *L, StkId top) {
+ const char *t1 = luaO_typename(top-2);
+ const char *t2 = luaO_typename(top-1);
+ if (t1[2] == t2[2])
+ luaO_verror(L, "attempt to compare two %.10s values", t1);
+ else
+ luaO_verror(L, "attempt to compare %.10s with %.10s", t1, t2);
+}
+
diff --git a/src/lua/ldebug.h b/src/lua/ldebug.h
new file mode 100644
index 00000000..76865616
--- /dev/null
+++ b/src/lua/ldebug.h
@@ -0,0 +1,21 @@
+/*
+** $Id: ldebug.h,v 1.2 2001/11/26 23:00:23 darkgod Exp $
+** Auxiliary functions from Debug Interface module
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ldebug_h
+#define ldebug_h
+
+
+#include "lstate.h"
+#include "luadebug.h"
+
+
+void luaG_typeerror (lua_State *L, StkId o, const char *op);
+void luaG_binerror (lua_State *L, StkId p1, int t, const char *op);
+int luaG_getline (int *lineinfo, int pc, int refline, int *refi);
+void luaG_ordererror (lua_State *L, StkId top);
+
+
+#endif
diff --git a/src/lua/ldo.c b/src/lua/ldo.c
new file mode 100644
index 00000000..5f23bfd9
--- /dev/null
+++ b/src/lua/ldo.c
@@ -0,0 +1,385 @@
+/*
+** $Id: ldo.c,v 1.7 2004/06/04 13:42:10 neil Exp $
+** Stack and Call structure of Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lundump.h"
+#include "lvm.h"
+#include "lzio.h"
+
+
+/* space to handle stack overflow errors */
+#define EXTRA_STACK (2*LUA_MINSTACK)
+
+
+void luaD_init (lua_State *L, int stacksize) {
+ L->stack = luaM_newvector(L, stacksize+EXTRA_STACK, TObject);
+ L->nblocks += stacksize*sizeof(TObject);
+ L->stack_last = L->stack+(stacksize-1);
+ L->stacksize = stacksize;
+ L->Cbase = L->top = L->stack;
+}
+
+
+void luaD_checkstack (lua_State *L, int n) {
+ if (L->stack_last - L->top <= n) { /* stack overflow? */
+ if (L->stack_last-L->stack > (L->stacksize-1)) {
+ /* overflow while handling overflow */
+ luaD_breakrun(L, LUA_ERRERR); /* break run without error message */
+ }
+ else {
+ L->stack_last += EXTRA_STACK; /* to be used by error message */
+ lua_error(L, "stack overflow");
+ }
+ }
+}
+
+
+static void restore_stack_limit (lua_State *L) {
+ if (L->top - L->stack < L->stacksize - 1)
+ L->stack_last = L->stack + (L->stacksize-1);
+}
+
+
+/*
+** Adjust stack. Set top to base+extra, pushing NILs if needed.
+** (we cannot add base+extra unless we are sure it fits in the stack;
+** otherwise the result of such operation on pointers is undefined)
+*/
+void luaD_adjusttop (lua_State *L, StkId base, int extra) {
+ int diff = extra-(L->top-base);
+ if (diff <= 0)
+ L->top = base+extra;
+ else {
+ luaD_checkstack(L, diff);
+ while (diff--)
+ ttype(L->top++) = LUA_TNIL;
+ }
+}
+
+
+/*
+** Open a hole inside the stack at `pos'
+*/
+static void luaD_openstack (lua_State *L, StkId pos) {
+ int i = L->top-pos;
+ while (i--) pos[i+1] = pos[i];
+ incr_top;
+}
+
+
+static void dohook (lua_State *L, lua_Debug *ar, lua_Hook hook) {
+ StkId old_Cbase = L->Cbase;
+ StkId old_top = L->Cbase = L->top;
+ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
+ L->allowhooks = 0; /* cannot call hooks inside a hook */
+ (*hook)(L, ar);
+ LUA_ASSERT(L->allowhooks == 0, "invalid allow");
+ L->allowhooks = 1;
+ L->top = old_top;
+ L->Cbase = old_Cbase;
+}
+
+
+void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook) {
+ if (L->allowhooks) {
+ lua_Debug ar;
+ ar._func = func;
+ ar.event = "line";
+ ar.currentline = line;
+ dohook(L, &ar, linehook);
+ }
+}
+
+
+static void luaD_callHook (lua_State *L, StkId func, lua_Hook callhook,
+ const char *event) {
+ if (L->allowhooks) {
+ lua_Debug ar;
+ ar._func = func;
+ ar.event = event;
+ infovalue(func)->pc = NULL; /* function is not active */
+ dohook(L, &ar, callhook);
+ }
+}
+
+
+static StkId callCclosure (lua_State *L, const struct Closure *cl, StkId base) {
+ int nup = cl->nupvalues; /* number of upvalues */
+ StkId old_Cbase = L->Cbase;
+ int n;
+ L->Cbase = base; /* new base for C function */
+ luaD_checkstack(L, nup+LUA_MINSTACK); /* ensure minimum stack size */
+ for (n=0; n<nup; n++) /* copy upvalues as extra arguments */
+ *(L->top++) = cl->upvalue[n];
+ n = (*cl->f.c)(L); /* do the actual call */
+ L->Cbase = old_Cbase; /* restore old C base */
+ return L->top - n; /* return index of first result */
+}
+
+
+void luaD_callTM (lua_State *L, Closure *f, int nParams, int nResults) {
+ StkId base = L->top - nParams;
+ luaD_openstack(L, base);
+ clvalue(base) = f;
+ ttype(base) = LUA_TFUNCTION;
+ luaD_call(L, base, nResults);
+}
+
+
+/*
+** Call a function (C or Lua). The function to be called is at *func.
+** The arguments are on the stack, right after the function.
+** When returns, the results are on the stack, starting at the original
+** function position.
+** The number of results is nResults, unless nResults=LUA_MULTRET.
+*/
+void luaD_call (lua_State *L, StkId func, int nResults) {
+ lua_Hook callhook;
+ StkId firstResult;
+ CallInfo ci;
+ Closure *cl;
+ if (ttype(func) != LUA_TFUNCTION) {
+ /* `func' is not a function; check the `function' tag method */
+ Closure *tm = luaT_gettmbyObj(L, func, TM_FUNCTION);
+ if (tm == NULL)
+ luaG_typeerror(L, func, "call");
+ luaD_openstack(L, func);
+ clvalue(func) = tm; /* tag method is the new function to be called */
+ ttype(func) = LUA_TFUNCTION;
+ }
+ cl = clvalue(func);
+ ci.func = cl;
+ infovalue(func) = &ci;
+ ttype(func) = LUA_TMARK;
+ callhook = L->callhook;
+ if (callhook)
+ luaD_callHook(L, func, callhook, "call");
+ firstResult = (cl->isC ? callCclosure(L, cl, func+1) :
+ luaV_execute(L, cl, func+1));
+ if (callhook) /* same hook that was active at entry */
+ luaD_callHook(L, func, callhook, "return");
+ LUA_ASSERT(ttype(func) == LUA_TMARK, "invalid tag");
+ /* move results to `func' (to erase parameters and function) */
+ if (nResults == LUA_MULTRET) {
+ while (firstResult < L->top) /* copy all results */
+ *func++ = *firstResult++;
+ L->top = func;
+ }
+ else { /* copy at most `nResults' */
+ for (; nResults > 0 && firstResult < L->top; nResults--)
+ *func++ = *firstResult++;
+ L->top = func;
+ for (; nResults > 0; nResults--) { /* if there are not enough results */
+ ttype(L->top) = LUA_TNIL; /* adjust the stack */
+ incr_top; /* must check stack space */
+ }
+ }
+ luaC_checkGC(L);
+}
+
+
+/*
+** Execute a protected call.
+*/
+struct CallS { /* data to `f_call' */
+ StkId func;
+ int nresults;
+};
+
+static void f_call (lua_State *L, void *ud) {
+ struct CallS *c = (struct CallS *)ud;
+ luaD_call(L, c->func, c->nresults);
+}
+
+
+LUA_API int lua_call (lua_State *L, int nargs, int nresults) {
+ StkId func = L->top - (nargs+1); /* function to be called */
+ struct CallS c;
+ int status;
+ c.func = func; c.nresults = nresults;
+ status = luaD_runprotected(L, f_call, &c);
+ if (status != 0) /* an error occurred? */
+ L->top = func; /* remove parameters from the stack */
+ return status;
+}
+
+
+/*
+** Execute a protected parser.
+*/
+struct ParserS { /* data to `f_parser' */
+ ZIO *z;
+ int bin;
+};
+
+static void f_parser (lua_State *L, void *ud) {
+ struct ParserS *p = (struct ParserS *)ud;
+ Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z);
+ luaV_Lclosure(L, tf, 0);
+}
+
+
+static int protectedparser (lua_State *L, ZIO *z, int bin) {
+ struct ParserS p;
+ unsigned long old_blocks;
+ int status;
+ p.z = z; p.bin = bin;
+ luaC_checkGC(L);
+ old_blocks = L->nblocks;
+ status = luaD_runprotected(L, f_parser, &p);
+ if (status == 0) {
+ /* add new memory to threshold (as it probably will stay) */
+ L->GCthreshold += (L->nblocks - old_blocks);
+ }
+ else if (status == LUA_ERRRUN) /* an error occurred: correct error code */
+ status = LUA_ERRSYNTAX;
+ return status;
+}
+
+
+static int parse_file (lua_State *L, const char *filename) {
+ ZIO z;
+ int status;
+ int bin; /* flag for file mode */
+ int c; /* look ahead char */
+ FILE *f = (filename == NULL) ? stdin : fopen(filename, "r");
+ if (f == NULL) return LUA_ERRFILE; /* unable to open file */
+ c = fgetc(f);
+ ungetc(c, f);
+ bin = (c == ID_CHUNK);
+ if (bin && f != stdin) {
+ f = freopen(filename, "rb", f); /* set binary mode */
+ if (f == NULL) return LUA_ERRFILE; /* unable to reopen file */
+ }
+ lua_pushstring(L, "@");
+ lua_pushstring(L, (filename == NULL) ? "(stdin)" : filename);
+ lua_concat(L, 2);
+ filename = lua_tostring(L, -1); /* filename = '@'..filename */
+ lua_pop(L, 1); /* OK: there is no GC during parser */
+ luaZ_Fopen(&z, f, filename);
+ status = protectedparser(L, &z, bin);
+ if (f != stdin)
+ fclose(f);
+ return status;
+}
+
+
+LUA_API int lua_dofile (lua_State *L, const char *filename) {
+ int status = parse_file(L, filename);
+ if (status == 0) /* parse OK? */
+ status = lua_call(L, 0, LUA_MULTRET); /* call main */
+ return status;
+}
+
+
+static int parse_buffer (lua_State *L, const char *buff, size_t size,
+ const char *name) {
+ ZIO z;
+ if (!name) name = "?";
+ luaZ_mopen(&z, buff, size, name);
+ return protectedparser(L, &z, buff[0]==ID_CHUNK);
+}
+
+
+LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name) {
+ int status = parse_buffer(L, buff, size, name);
+ if (status == 0) /* parse OK? */
+ status = lua_call(L, 0, LUA_MULTRET); /* call main */
+ return status;
+}
+
+
+LUA_API int lua_dostring (lua_State *L, const char *str) {
+ return lua_dobuffer(L, str, strlen(str), str);
+}
+
+
+/*
+** {======================================================
+** Error-recover functions (based on long jumps)
+** =======================================================
+*/
+
+/* chain list of long jump buffers */
+struct lua_longjmp {
+ jmp_buf b;
+ struct lua_longjmp *previous;
+ volatile int status; /* error code */
+};
+
+
+static void message (lua_State *L, const char *s) {
+ const TObject *em = luaH_getglobal(L, LUA_ERRORMESSAGE);
+ if (ttype(em) == LUA_TFUNCTION) {
+ *L->top = *em;
+ incr_top;
+ lua_pushstring(L, s);
+ luaD_call(L, L->top-2, 0);
+ }
+}
+
+
+/*
+** Reports an error, and jumps up to the available recovery label
+*/
+LUA_API void lua_error (lua_State *L, const char *s) {
+ if (s) message(L, s);
+ luaD_breakrun(L, LUA_ERRRUN);
+}
+
+
+void luaD_breakrun (lua_State *L, int errcode) {
+ if (L->errorJmp) {
+ L->errorJmp->status = errcode;
+ longjmp(L->errorJmp->b, 1);
+ }
+ else {
+ if (errcode != LUA_ERRMEM)
+ message(L, "unable to recover; exiting\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud) {
+ StkId oldCbase = L->Cbase;
+ StkId oldtop = L->top;
+ struct lua_longjmp lj;
+ int allowhooks = L->allowhooks;
+ lj.status = 0;
+ lj.previous = L->errorJmp; /* chain new error handler */
+ L->errorJmp = &lj;
+ if (setjmp(lj.b) == 0)
+ (*f)(L, ud);
+ else { /* an error occurred: restore the state */
+ L->allowhooks = allowhooks;
+ L->Cbase = oldCbase;
+ L->top = oldtop;
+ restore_stack_limit(L);
+ }
+ L->errorJmp = lj.previous; /* restore old error handler */
+ return lj.status;
+}
+
+/* }====================================================== */
+
diff --git a/src/lua/ldo.h b/src/lua/ldo.h
new file mode 100644
index 00000000..d948ad35
--- /dev/null
+++ b/src/lua/ldo.h
@@ -0,0 +1,33 @@
+/*
+** $Id: ldo.h,v 1.3 2001/11/26 23:00:23 darkgod Exp $
+** Stack and Call structure of Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ldo_h
+#define ldo_h
+
+
+#include "lobject.h"
+#include "lstate.h"
+
+
+/*
+** macro to increment stack top.
+** There must be always an empty slot at the L->stack.top
+*/
+#define incr_top {if (L->top == L->stack_last) luaD_checkstack(L, 1); L->top++;}
+
+
+void luaD_init (lua_State *L, int stacksize);
+void luaD_adjusttop (lua_State *L, StkId base, int extra);
+void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook);
+void luaD_call (lua_State *L, StkId func, int nResults);
+void luaD_callTM (lua_State *L, Closure *f, int nParams, int nResults);
+void luaD_checkstack (lua_State *L, int n);
+
+void luaD_breakrun (lua_State *L, int errcode);
+int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud);
+
+
+#endif
diff --git a/src/lua/lfunc.c b/src/lua/lfunc.c
new file mode 100644
index 00000000..d3427653
--- /dev/null
+++ b/src/lua/lfunc.c
@@ -0,0 +1,109 @@
+/*
+** $Id: lfunc.c,v 1.3 2001/11/26 23:00:23 darkgod Exp $
+** Auxiliary functions to manipulate prototypes and closures
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+#include "lua.h"
+
+#include "lfunc.h"
+#include "lmem.h"
+#include "lstate.h"
+
+
+#define sizeclosure(n) ((int)sizeof(Closure) + (int)sizeof(TObject)*((n)-1))
+
+
+Closure *luaF_newclosure (lua_State *L, int nelems) {
+ int size = sizeclosure(nelems);
+ Closure *c = (Closure *)luaM_malloc(L, size);
+ c->next = L->rootcl;
+ L->rootcl = c;
+ c->mark = c;
+ c->nupvalues = nelems;
+ L->nblocks += size;
+ return c;
+}
+
+
+Proto *luaF_newproto (lua_State *L) {
+ Proto *f = luaM_new(L, Proto);
+ f->knum = NULL;
+ f->nknum = 0;
+ f->kstr = NULL;
+ f->nkstr = 0;
+ f->kproto = NULL;
+ f->nkproto = 0;
+ f->code = NULL;
+ f->ncode = 0;
+ f->numparams = 0;
+ f->is_vararg = 0;
+ f->maxstacksize = 0;
+ f->marked = 0;
+ f->lineinfo = NULL;
+ f->nlineinfo = 0;
+ f->nlocvars = 0;
+ f->locvars = NULL;
+ f->lineDefined = 0;
+ f->source = NULL;
+ f->next = L->rootproto; /* chain in list of protos */
+ L->rootproto = f;
+ return f;
+}
+
+
+static size_t protosize (Proto *f) {
+ return sizeof(Proto)
+ + f->nknum*sizeof(Number)
+ + f->nkstr*sizeof(TString *)
+ + f->nkproto*sizeof(Proto *)
+ + f->ncode*sizeof(Instruction)
+ + f->nlocvars*sizeof(struct LocVar)
+ + f->nlineinfo*sizeof(int);
+}
+
+
+void luaF_protook (lua_State *L, Proto *f, int pc) {
+ f->ncode = pc; /* signal that proto was properly created */
+ L->nblocks += protosize(f);
+}
+
+
+void luaF_freeproto (lua_State *L, Proto *f) {
+ if (f->ncode > 0) /* function was properly created? */
+ L->nblocks -= protosize(f);
+ luaM_free(L, f->code);
+ luaM_free(L, f->locvars);
+ luaM_free(L, f->kstr);
+ luaM_free(L, f->knum);
+ luaM_free(L, f->kproto);
+ luaM_free(L, f->lineinfo);
+ luaM_free(L, f);
+}
+
+
+void luaF_freeclosure (lua_State *L, Closure *c) {
+ L->nblocks -= sizeclosure(c->nupvalues);
+ luaM_free(L, c);
+}
+
+
+/*
+** Look for n-th local variable at line `line' in function `func'.
+** Returns NULL if not found.
+*/
+const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
+ int i;
+ for (i = 0; i<f->nlocvars && f->locvars[i].startpc <= pc; i++) {
+ if (pc < f->locvars[i].endpc) { /* is variable active? */
+ local_number--;
+ if (local_number == 0)
+ return f->locvars[i].varname->str;
+ }
+ }
+ return NULL; /* not found */
+}
+
diff --git a/src/lua/lfunc.h b/src/lua/lfunc.h
new file mode 100644
index 00000000..1bd9722d
--- /dev/null
+++ b/src/lua/lfunc.h
@@ -0,0 +1,24 @@
+/*
+** $Id: lfunc.h,v 1.3 2001/11/26 23:00:23 darkgod Exp $
+** Auxiliary functions to manipulate prototypes and closures
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lfunc_h
+#define lfunc_h
+
+
+#include "lobject.h"
+
+
+
+Proto *luaF_newproto (lua_State *L);
+void luaF_protook (lua_State *L, Proto *f, int pc);
+Closure *luaF_newclosure (lua_State *L, int nelems);
+void luaF_freeproto (lua_State *L, Proto *f);
+void luaF_freeclosure (lua_State *L, Closure *c);
+
+const char *luaF_getlocalname (const Proto *func, int local_number, int pc);
+
+
+#endif
diff --git a/src/lua/lgc.c b/src/lua/lgc.c
new file mode 100644
index 00000000..4e8b234d
--- /dev/null
+++ b/src/lua/lgc.c
@@ -0,0 +1,353 @@
+/*
+** $Id: lgc.c,v 1.3 2001/11/26 23:00:24 darkgod Exp $
+** Garbage Collector
+** See Copyright Notice in lua.h
+*/
+
+#include "lua.h"
+
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+typedef struct GCState {
+ Hash *tmark; /* list of marked tables to be visited */
+ Closure *cmark; /* list of marked closures to be visited */
+} GCState;
+
+
+
+static void markobject (GCState *st, TObject *o);
+
+
+/* mark a string; marks larger than 1 cannot be changed */
+#define strmark(s) {if ((s)->marked == 0) (s)->marked = 1;}
+
+
+
+static void protomark (Proto *f) {
+ if (!f->marked) {
+ int i;
+ f->marked = 1;
+ strmark(f->source);
+ for (i=0; i<f->nkstr; i++)
+ strmark(f->kstr[i]);
+ for (i=0; i<f->nkproto; i++)
+ protomark(f->kproto[i]);
+ for (i=0; i<f->nlocvars; i++) /* mark local-variable names */
+ strmark(f->locvars[i].varname);
+ }
+}
+
+
+static void markstack (lua_State *L, GCState *st) {
+ StkId o;
+ for (o=L->stack; o<L->top; o++)
+ markobject(st, o);
+}
+
+
+static void marklock (lua_State *L, GCState *st) {
+ int i;
+ for (i=0; i<L->refSize; i++) {
+ if (L->refArray[i].st == LOCK)
+ markobject(st, &L->refArray[i].o);
+ }
+}
+
+
+static void markclosure (GCState *st, Closure *cl) {
+ if (!ismarked(cl)) {
+ if (!cl->isC)
+ protomark(cl->f.l);
+ cl->mark = st->cmark; /* chain it for later traversal */
+ st->cmark = cl;
+ }
+}
+
+
+static void marktagmethods (lua_State *L, GCState *st) {
+ int e;
+ for (e=0; e<TM_N; e++) {
+ int t;
+ for (t=0; t<=L->last_tag; t++) {
+ Closure *cl = luaT_gettm(L, t, e);
+ if (cl) markclosure(st, cl);
+ }
+ }
+}
+
+
+static void markobject (GCState *st, TObject *o) {
+ switch (ttype(o)) {
+ case LUA_TUSERDATA: case LUA_TSTRING:
+ strmark(tsvalue(o));
+ break;
+ case LUA_TMARK:
+ markclosure(st, infovalue(o)->func);
+ break;
+ case LUA_TFUNCTION:
+ markclosure(st, clvalue(o));
+ break;
+ case LUA_TTABLE: {
+ if (!ismarked(hvalue(o))) {
+ hvalue(o)->mark = st->tmark; /* chain it in list of marked */
+ st->tmark = hvalue(o);
+ }
+ break;
+ }
+ default: break; /* numbers, etc */
+ }
+}
+
+
+static void markall (lua_State *L) {
+ GCState st;
+ st.cmark = NULL;
+ st.tmark = L->gt; /* put table of globals in mark list */
+ L->gt->mark = NULL;
+ marktagmethods(L, &st); /* mark tag methods */
+ markstack(L, &st); /* mark stack objects */
+ marklock(L, &st); /* mark locked objects */
+ for (;;) { /* mark tables and closures */
+ if (st.cmark) {
+ int i;
+ Closure *f = st.cmark; /* get first closure from list */
+ st.cmark = f->mark; /* remove it from list */
+ for (i=0; i<f->nupvalues; i++) /* mark its upvalues */
+ markobject(&st, &f->upvalue[i]);
+ }
+ else if (st.tmark) {
+ int i;
+ Hash *h = st.tmark; /* get first table from list */
+ st.tmark = h->mark; /* remove it from list */
+ for (i=0; i<h->size; i++) {
+ Node *n = node(h, i);
+ if (ttype(key(n)) != LUA_TNIL) {
+ if (ttype(val(n)) == LUA_TNIL)
+ luaH_remove(h, key(n)); /* dead element; try to remove it */
+ markobject(&st, &n->key);
+ markobject(&st, &n->val);
+ }
+ }
+ }
+ else break; /* nothing else to mark */
+ }
+}
+
+
+static int hasmark (const TObject *o) {
+ /* valid only for locked objects */
+ switch (o->ttype) {
+ case LUA_TSTRING: case LUA_TUSERDATA:
+ return tsvalue(o)->marked;
+ case LUA_TTABLE:
+ return ismarked(hvalue(o));
+ case LUA_TFUNCTION:
+ return ismarked(clvalue(o));
+ default: /* number */
+ return 1;
+ }
+}
+
+
+/* macro for internal debugging; check if a link of free refs is valid */
+#define VALIDLINK(L, st,n) (NONEXT <= (st) && (st) < (n))
+
+static void invalidaterefs (lua_State *L) {
+ int n = L->refSize;
+ int i;
+ for (i=0; i<n; i++) {
+ struct Ref *r = &L->refArray[i];
+ if (r->st == HOLD && !hasmark(&r->o))
+ r->st = COLLECTED;
+ LUA_ASSERT((r->st == LOCK && hasmark(&r->o)) ||
+ (r->st == HOLD && hasmark(&r->o)) ||
+ r->st == COLLECTED ||
+ r->st == NONEXT ||
+ (r->st < n && VALIDLINK(L, L->refArray[r->st].st, n)),
+ "inconsistent ref table");
+ }
+ LUA_ASSERT(VALIDLINK(L, L->refFree, n), "inconsistent ref table");
+}
+
+
+
+static void collectproto (lua_State *L) {
+ Proto **p = &L->rootproto;
+ Proto *next;
+ while ((next = *p) != NULL) {
+ if (next->marked) {
+ next->marked = 0;
+ p = &next->next;
+ }
+ else {
+ *p = next->next;
+ luaF_freeproto(L, next);
+ }
+ }
+}
+
+
+static void collectclosure (lua_State *L) {
+ Closure **p = &L->rootcl;
+ Closure *next;
+ while ((next = *p) != NULL) {
+ if (ismarked(next)) {
+ next->mark = next; /* unmark */
+ p = &next->next;
+ }
+ else {
+ *p = next->next;
+ luaF_freeclosure(L, next);
+ }
+ }
+}
+
+
+static void collecttable (lua_State *L) {
+ Hash **p = &L->roottable;
+ Hash *next;
+ while ((next = *p) != NULL) {
+ if (ismarked(next)) {
+ next->mark = next; /* unmark */
+ p = &next->next;
+ }
+ else {
+ *p = next->next;
+ luaH_free(L, next);
+ }
+ }
+}
+
+
+static void checktab (lua_State *L, stringtable *tb) {
+ if (tb->nuse < (lint32)(tb->size/4) && tb->size > 10)
+ luaS_resize(L, tb, tb->size/2); /* table is too big */
+}
+
+
+static void collectstrings (lua_State *L, int all) {
+ int i;
+ for (i=0; i<L->strt.size; i++) { /* for each list */
+ TString **p = &L->strt.hash[i];
+ TString *next;
+ while ((next = *p) != NULL) {
+ if (next->marked && !all) { /* preserve? */
+ if (next->marked < FIXMARK) /* does not change FIXMARKs */
+ next->marked = 0;
+ p = &next->nexthash;
+ }
+ else { /* collect */
+ *p = next->nexthash;
+ L->strt.nuse--;
+ L->nblocks -= sizestring(next->len);
+ luaM_free(L, next);
+ }
+ }
+ }
+ checktab(L, &L->strt);
+}
+
+
+static void collectudata (lua_State *L, int all) {
+ int i;
+ for (i=0; i<L->udt.size; i++) { /* for each list */
+ TString **p = &L->udt.hash[i];
+ TString *next;
+ while ((next = *p) != NULL) {
+ LUA_ASSERT(next->marked <= 1, "udata cannot be fixed");
+ if (next->marked && !all) { /* preserve? */
+ next->marked = 0;
+ p = &next->nexthash;
+ }
+ else { /* collect */
+ int tag = next->u.d.tag;
+ *p = next->nexthash;
+ next->nexthash = L->TMtable[tag].collected; /* chain udata */
+ L->TMtable[tag].collected = next;
+ L->nblocks -= sizestring(next->len);
+ L->udt.nuse--;
+ }
+ }
+ }
+ checktab(L, &L->udt);
+}
+
+
+#define MINBUFFER 256
+static void checkMbuffer (lua_State *L) {
+ if (L->Mbuffsize > MINBUFFER*2) { /* is buffer too big? */
+ size_t newsize = L->Mbuffsize/2; /* still larger than MINBUFFER */
+ L->nblocks += (newsize - L->Mbuffsize)*sizeof(char);
+ L->Mbuffsize = newsize;
+ luaM_reallocvector(L, L->Mbuffer, newsize, char);
+ }
+}
+
+
+static void callgcTM (lua_State *L, const TObject *o) {
+ Closure *tm = luaT_gettmbyObj(L, o, TM_GC);
+ if (tm != NULL) {
+ int oldah = L->allowhooks;
+ L->allowhooks = 0; /* stop debug hooks during GC tag methods */
+ luaD_checkstack(L, 2);
+ clvalue(L->top) = tm;
+ ttype(L->top) = LUA_TFUNCTION;
+ *(L->top+1) = *o;
+ L->top += 2;
+ luaD_call(L, L->top-2, 0);
+ L->allowhooks = oldah; /* restore hooks */
+ }
+}
+
+
+static void callgcTMudata (lua_State *L) {
+ int tag;
+ TObject o;
+ ttype(&o) = LUA_TUSERDATA;
+ L->GCthreshold = 2*L->nblocks; /* avoid GC during tag methods */
+ for (tag=L->last_tag; tag>=0; tag--) { /* for each tag (in reverse order) */
+ TString *udata;
+ while ((udata = L->TMtable[tag].collected) != NULL) {
+ L->TMtable[tag].collected = udata->nexthash; /* remove it from list */
+ tsvalue(&o) = udata;
+ callgcTM(L, &o);
+ luaM_free(L, udata);
+ }
+ }
+}
+
+
+void luaC_collect (lua_State *L, int all) {
+ collectudata(L, all);
+ callgcTMudata(L);
+ collectstrings(L, all);
+ collecttable(L);
+ collectproto(L);
+ collectclosure(L);
+}
+
+
+static void luaC_collectgarbage (lua_State *L) {
+ markall(L);
+ invalidaterefs(L); /* check unlocked references */
+ luaC_collect(L, 0);
+ checkMbuffer(L);
+ L->GCthreshold = 2*L->nblocks; /* set new threshold */
+ callgcTM(L, &luaO_nilobject);
+}
+
+
+void luaC_checkGC (lua_State *L) {
+ if (L->nblocks >= L->GCthreshold)
+ luaC_collectgarbage(L);
+}
+
diff --git a/src/lua/lgc.h b/src/lua/lgc.h
new file mode 100644
index 00000000..2dea9e4d
--- /dev/null
+++ b/src/lua/lgc.h
@@ -0,0 +1,18 @@
+/*
+** $Id: lgc.h,v 1.3 2001/11/26 23:00:24 darkgod Exp $
+** Garbage Collector
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lgc_h
+#define lgc_h
+
+
+#include "lobject.h"
+
+
+void luaC_collect (lua_State *L, int all);
+void luaC_checkGC (lua_State *L);
+
+
+#endif
diff --git a/src/lua/liolib.c b/src/lua/liolib.c
new file mode 100644
index 00000000..4fb385f4
--- /dev/null
+++ b/src/lua/liolib.c
@@ -0,0 +1,710 @@
+/*
+** $Id: liolib.c,v 1.5 2004/06/04 13:42:10 neil Exp $
+** Standard I/O (and system) library
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "luadebug.h"
+#include "lualib.h"
+
+
+#ifndef OLD_ANSI
+#include <errno.h>
+#include <locale.h>
+#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s))
+#define free(b) if (b) (free)(b)
+#else
+/* no support for locale and for strerror: fake them */
+#define setlocale(a,b) ((void)a, strcmp((b),"C")==0?"C":NULL)
+#define LC_ALL 0
+#define LC_COLLATE 0
+#define LC_CTYPE 0
+#define LC_MONETARY 0
+#define LC_NUMERIC 0
+#define LC_TIME 0
+#define strerror(e) "generic I/O error"
+#define errno (-1)
+#endif
+
+
+
+#ifdef POPEN
+/* FILE *popen();
+int pclose(); */
+#define CLOSEFILE(L, f) ((pclose(f) == -1) ? fclose(f) : 0)
+#else
+/* no support for popen */
+#define popen(x,y) NULL /* that is, popen always fails */
+#define CLOSEFILE(L, f) (fclose(f))
+#endif
+
+
+#define INFILE 0
+#define OUTFILE 1
+
+typedef struct IOCtrl {
+ int ref[2]; /* ref for strings _INPUT/_OUTPUT */
+ int iotag; /* tag for file handles */
+ int closedtag; /* tag for closed handles */
+} IOCtrl;
+
+
+
+static const char *const filenames[] = {"_INPUT", "_OUTPUT"};
+
+
+static int pushresult (lua_State *L, int i) {
+ if (i) {
+ lua_pushuserdata(L, NULL);
+ return 1;
+ }
+ else {
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ lua_pushnumber(L, errno);
+ return 3;;
+ }
+}
+
+
+/*
+** {======================================================
+** FILE Operations
+** =======================================================
+*/
+
+
+static FILE *gethandle (lua_State *L, IOCtrl *ctrl, int f) {
+ void *p = lua_touserdata(L, f);
+ if (p != NULL) { /* is `f' a userdata ? */
+ int ftag = lua_tag(L, f);
+ if (ftag == ctrl->iotag) /* does it have the correct tag? */
+ return (FILE *)p;
+ else if (ftag == ctrl->closedtag)
+ lua_error(L, "cannot access a closed file");
+ /* else go through */
+ }
+ return NULL;
+}
+
+
+static FILE *getnonullfile (lua_State *L, IOCtrl *ctrl, int arg) {
+ FILE *f = gethandle(L, ctrl, arg);
+ luaL_arg_check(L, f, arg, "invalid file handle");
+ return f;
+}
+
+
+static FILE *getfilebyref (lua_State *L, IOCtrl *ctrl, int inout) {
+ FILE *f;
+ lua_getglobals(L);
+ lua_getref(L, ctrl->ref[inout]);
+ lua_rawget(L, -2);
+ f = gethandle(L, ctrl, -1);
+ if (f == NULL)
+ luaL_verror(L, "global variable `%.10s' is not a file handle",
+ filenames[inout]);
+ return f;
+}
+
+
+static void setfilebyname (lua_State *L, IOCtrl *ctrl, FILE *f,
+ const char *name) {
+ lua_pushusertag(L, f, ctrl->iotag);
+ lua_setglobal(L, name);
+}
+
+
+#define setfile(L,ctrl,f,inout) (setfilebyname(L,ctrl,f,filenames[inout]))
+
+
+static int setreturn (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) {
+ if (f == NULL)
+ return pushresult(L, 0);
+ else {
+ setfile(L, ctrl, f, inout);
+ lua_pushusertag(L, f, ctrl->iotag);
+ return 1;
+ }
+}
+
+
+static int closefile (lua_State *L, IOCtrl *ctrl, FILE *f) {
+ if (f == stdin || f == stdout || f == stderr)
+ return 1;
+ else {
+ lua_pushusertag(L, f, ctrl->iotag);
+ lua_settag(L, ctrl->closedtag);
+ return (CLOSEFILE(L, f) == 0);
+ }
+}
+
+
+static int io_close (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ lua_pop(L, 1); /* remove upvalue */
+ return pushresult(L, closefile(L, ctrl, getnonullfile(L, ctrl, 1)));
+}
+
+
+static int file_collect (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *f = getnonullfile(L, ctrl, 1);
+ if (f != stdin && f != stdout && f != stderr)
+ CLOSEFILE(L, f);
+ return 0;
+}
+
+
+static int io_open (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *f;
+ lua_pop(L, 1); /* remove upvalue */
+ f = fopen(luaL_check_string(L, 1), luaL_check_string(L, 2));
+ if (f) {
+ lua_pushusertag(L, f, ctrl->iotag);
+ return 1;
+ }
+ else
+ return pushresult(L, 0);
+}
+
+
+
+static int io_fromto (lua_State *L, int inout, const char *mode) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *current;
+ lua_pop(L, 1); /* remove upvalue */
+ if (lua_isnull(L, 1)) {
+ closefile(L, ctrl, getfilebyref(L, ctrl, inout));
+ current = (inout == 0) ? stdin : stdout;
+ }
+ else if (lua_tag(L, 1) == ctrl->iotag) /* deprecated option */
+ current = (FILE *)lua_touserdata(L, 1);
+ else {
+ const char *s = luaL_check_string(L, 1);
+ current = (*s == '|') ? popen(s+1, mode) : fopen(s, mode);
+ }
+ return setreturn(L, ctrl, current, inout);
+}
+
+
+static int io_readfrom (lua_State *L) {
+ return io_fromto(L, INFILE, "r");
+}
+
+
+static int io_writeto (lua_State *L) {
+ return io_fromto(L, OUTFILE, "w");
+}
+
+
+static int io_appendto (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *current;
+ lua_pop(L, 1); /* remove upvalue */
+ current = fopen(luaL_check_string(L, 1), "a");
+ return setreturn(L, ctrl, current, OUTFILE);
+}
+
+
+
+/*
+** {======================================================
+** READ
+** =======================================================
+*/
+
+
+
+#ifdef LUA_COMPAT_READPATTERN
+
+/*
+** We cannot lookahead without need, because this can lock stdin.
+** This flag signals when we need to read a next char.
+*/
+#define NEED_OTHER (EOF-1) /* just some flag different from EOF */
+
+
+static int read_pattern (lua_State *L, FILE *f, const char *p) {
+ int inskip = 0; /* {skip} level */
+ int c = NEED_OTHER;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ while (*p != '\0') {
+ switch (*p) {
+ case '{':
+ inskip++;
+ p++;
+ continue;
+ case '}':
+ if (!inskip) lua_error(L, "unbalanced braces in read pattern");
+ inskip--;
+ p++;
+ continue;
+ default: {
+ const char *ep = luaI_classend(L, p); /* get what is next */
+ int m; /* match result */
+ if (c == NEED_OTHER) c = getc(f);
+ m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep);
+ if (m) {
+ if (!inskip) luaL_putchar(&b, c);
+ c = NEED_OTHER;
+ }
+ switch (*ep) {
+ case '+': /* repetition (1 or more) */
+ if (!m) goto break_while; /* pattern fails? */
+ /* else go through */
+ case '*': /* repetition (0 or more) */
+ while (m) { /* reads the same item until it fails */
+ c = getc(f);
+ m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep);
+ if (m && !inskip) luaL_putchar(&b, c);
+ }
+ /* go through to continue reading the pattern */
+ case '?': /* optional */
+ p = ep+1; /* continues reading the pattern */
+ continue;
+ default:
+ if (!m) goto break_while; /* pattern fails? */
+ p = ep; /* else continues reading the pattern */
+ }
+ }
+ }
+ } break_while:
+ if (c != NEED_OTHER) ungetc(c, f);
+ luaL_pushresult(&b); /* close buffer */
+ return (*p == '\0');
+}
+
+#else
+
+#define read_pattern(L, f, p) (lua_error(L, "read patterns are deprecated"), 0)
+
+#endif
+
+
+static int read_number (lua_State *L, FILE *f) {
+ long d;
+ if (fscanf(f, "%ld", &d) == 1) {
+ lua_pushnumber(L, d);
+ return 1;
+ }
+ else return 0; /* read fails */
+}
+
+
+static int read_word (lua_State *L, FILE *f) {
+ int c;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ do { c = fgetc(f); } while (isspace(c)); /* skip spaces */
+ while (c != EOF && !isspace(c)) {
+ luaL_putchar(&b, c);
+ c = fgetc(f);
+ }
+ ungetc(c, f);
+ luaL_pushresult(&b); /* close buffer */
+ return (lua_strlen(L, -1) > 0);
+}
+
+
+static int read_line (lua_State *L, FILE *f) {
+ int n = 0;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ for (;;) {
+ char *p = luaL_prepbuffer(&b);
+ if (!fgets(p, LUAL_BUFFERSIZE, f)) /* read fails? */
+ break;
+ n = strlen(p);
+ if (p[n-1] != '\n')
+ luaL_addsize(&b, n);
+ else {
+ luaL_addsize(&b, n-1); /* do not add the `\n' */
+ break;
+ }
+ }
+ luaL_pushresult(&b); /* close buffer */
+ return (n > 0); /* read something? */
+}
+
+
+static void read_file (lua_State *L, FILE *f) {
+ size_t len = 0;
+ size_t size = BUFSIZ;
+ char *buffer = NULL;
+ for (;;) {
+ char *newbuffer = (char *)realloc(buffer, size);
+ if (newbuffer == NULL) {
+ free(buffer);
+ lua_error(L, "not enough memory to read a file");
+ }
+ buffer = newbuffer;
+ len += fread(buffer+len, sizeof(char), size-len, f);
+ if (len < size) break; /* did not read all it could */
+ size *= 2;
+ }
+ lua_pushlstring(L, buffer, len);
+ free(buffer);
+}
+
+
+static int read_chars (lua_State *L, FILE *f, size_t n) {
+ char *buffer;
+ size_t n1;
+ char statbuff[BUFSIZ];
+ if (n <= BUFSIZ)
+ buffer = statbuff;
+ else {
+ buffer = (char *)malloc(n);
+ if (buffer == NULL)
+ lua_error(L, "not enough memory to read a file");
+ }
+ n1 = fread(buffer, sizeof(char), n, f);
+ lua_pushlstring(L, buffer, n1);
+ if (buffer != statbuff) free(buffer);
+ return (n1 > 0 || n == 0);
+}
+
+
+static int io_read (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ int lastarg = lua_gettop(L) - 1;
+ int firstarg = 1;
+ FILE *f = gethandle(L, ctrl, firstarg);
+ int n;
+ if (f) firstarg++;
+ else f = getfilebyref(L, ctrl, INFILE); /* get _INPUT */
+ lua_pop(L, 1);
+ if (firstarg > lastarg) { /* no arguments? */
+ lua_settop(L, 0); /* erase upvalue and other eventual garbage */
+ firstarg = lastarg = 1; /* correct indices */
+ lua_pushstring(L, "*l"); /* push default argument */
+ }
+ else /* ensure stack space for all results and for auxlib's buffer */
+ luaL_checkstack(L, lastarg-firstarg+1+LUA_MINSTACK, "too many arguments");
+ for (n = firstarg; n<=lastarg; n++) {
+ int success;
+ if (lua_isnumber(L, n))
+ success = read_chars(L, f, (size_t)lua_tonumber(L, n));
+ else {
+ const char *p = luaL_check_string(L, n);
+ if (p[0] != '*')
+ success = read_pattern(L, f, p); /* deprecated! */
+ else {
+ switch (p[1]) {
+ case 'n': /* number */
+ if (!read_number(L, f)) goto endloop; /* read fails */
+ continue; /* number is already pushed; avoid the "pushstring" */
+ case 'l': /* line */
+ success = read_line(L, f);
+ break;
+ case 'a': /* file */
+ read_file(L, f);
+ success = 1; /* always success */
+ break;
+ case 'w': /* word */
+ success = read_word(L, f);
+ break;
+ default:
+ luaL_argerror(L, n, "invalid format");
+ success = 0; /* to avoid warnings */
+ }
+ }
+ }
+ if (!success) {
+ lua_pop(L, 1); /* remove last result */
+ break; /* read fails */
+ }
+ } endloop:
+ return n - firstarg;
+}
+
+/* }====================================================== */
+
+
+static int io_write (lua_State *L) {
+ int lastarg = lua_gettop(L) - 1;
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ int arg = 1;
+ int status = 1;
+ FILE *f = gethandle(L, ctrl, arg);
+ if (f) arg++;
+ else f = getfilebyref(L, ctrl, OUTFILE); /* get _OUTPUT */
+ for (; arg <= lastarg; arg++) {
+ if (lua_type(L, arg) == LUA_TNUMBER) { /* LUA_NUMBER */
+ /* optimization: could be done exactly as for strings */
+ status = status && fprintf(f, "%ld", lua_tonumber(L, arg)) > 0;
+ }
+ else {
+ size_t l;
+ const char *s = luaL_check_lstr(L, arg, &l);
+ status = status && (fwrite(s, sizeof(char), l, f) == l);
+ }
+ }
+ pushresult(L, status);
+ return 1;
+}
+
+
+static int io_seek (lua_State *L) {
+ static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
+ static const char *const modenames[] = {"set", "cur", "end", NULL};
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *f;
+ int op;
+ long offset;
+ lua_pop(L, 1); /* remove upvalue */
+ f = getnonullfile(L, ctrl, 1);
+ op = luaL_findstring(luaL_opt_string(L, 2, "cur"), modenames);
+ offset = luaL_opt_long(L, 3, 0);
+ luaL_arg_check(L, op != -1, 2, "invalid mode");
+ op = fseek(f, offset, mode[op]);
+ if (op)
+ return pushresult(L, 0); /* error */
+ else {
+ lua_pushnumber(L, ftell(f));
+ return 1;
+ }
+}
+
+
+static int io_flush (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *f;
+ lua_pop(L, 1); /* remove upvalue */
+ f = gethandle(L, ctrl, 1);
+ luaL_arg_check(L, f || lua_isnull(L, 1), 1, "invalid file handle");
+ return pushresult(L, fflush(f) == 0);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Other O.S. Operations
+** =======================================================
+*/
+
+static int io_execute (lua_State *L) {
+ lua_pushnumber(L, system(luaL_check_string(L, 1)));
+ return 1;
+}
+
+
+static int io_remove (lua_State *L) {
+ return pushresult(L, remove(luaL_check_string(L, 1)) == 0);
+}
+
+
+static int io_rename (lua_State *L) {
+ return pushresult(L, rename(luaL_check_string(L, 1),
+ luaL_check_string(L, 2)) == 0);
+}
+
+
+static int io_getenv (lua_State *L) {
+ lua_pushstring(L, getenv(luaL_check_string(L, 1))); /* if NULL push nil */
+ return 1;
+}
+
+
+static int io_clock (lua_State *L) {
+ lua_pushnumber(L, ((long)clock())/CLOCKS_PER_SEC);
+ return 1;
+}
+
+
+static int io_date (lua_State *L) {
+ char b[256];
+ const char *s = luaL_opt_string(L, 1, "%c");
+ struct tm *stm;
+ time_t t;
+ time(&t); stm = localtime(&t);
+ if (strftime(b, sizeof(b), s, stm))
+ lua_pushstring(L, b);
+ else
+ lua_error(L, "invalid `date' format");
+ return 1;
+}
+
+
+static int setloc (lua_State *L) {
+ static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
+ LC_NUMERIC, LC_TIME};
+ static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
+ "numeric", "time", NULL};
+ int op = luaL_findstring(luaL_opt_string(L, 2, "all"), catnames);
+ luaL_arg_check(L, op != -1, 2, "invalid option");
+ lua_pushstring(L, setlocale(cat[op], luaL_check_string(L, 1)));
+ return 1;
+}
+
+
+static int io_exit (lua_State *L) {
+ exit(luaL_opt_int(L, 1, EXIT_SUCCESS));
+ return 0; /* to avoid warnings */
+}
+
+/* }====================================================== */
+
+
+
+static int io_debug (lua_State *L) {
+ for (;;) {
+ char buffer[250];
+ fprintf(stderr, "lua_debug> ");
+ if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
+ strcmp(buffer, "cont\n") == 0)
+ return 0;
+ lua_dostring(L, buffer);
+ lua_settop(L, 0); /* remove eventual returns */
+ }
+}
+
+
+#define LEVELS1 12 /* size of the first part of the stack */
+#define LEVELS2 10 /* size of the second part of the stack */
+
+static int errorfb (lua_State *L) {
+ int level = 1; /* skip level 0 (it's this function) */
+ int firstpart = 1; /* still before eventual `...' */
+ lua_Debug ar;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ luaL_addstring(&b, "error: ");
+ luaL_addstring(&b, luaL_check_string(L, 1));
+ luaL_addstring(&b, "\n");
+ while (lua_getstack(L, level++, &ar)) {
+ char buff[120]; /* enough to fit following `sprintf's */
+ if (level == 2)
+ luaL_addstring(&b, "stack traceback:\n");
+ else if (level > LEVELS1 && firstpart) {
+ /* no more than `LEVELS2' more levels? */
+ if (!lua_getstack(L, level+LEVELS2, &ar))
+ level--; /* keep going */
+ else {
+ luaL_addstring(&b, " ...\n"); /* too many levels */
+ while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */
+ level++;
+ }
+ firstpart = 0;
+ continue;
+ }
+ sprintf(buff, "%4d: ", level-1);
+ luaL_addstring(&b, buff);
+ lua_getinfo(L, "Snl", &ar);
+ switch (*ar.namewhat) {
+ case 'g': case 'l': /* global, local */
+ sprintf(buff, "function `%.50s'", ar.name);
+ break;
+ case 'f': /* field */
+ sprintf(buff, "method `%.50s'", ar.name);
+ break;
+ case 't': /* tag method */
+ sprintf(buff, "`%.50s' tag method", ar.name);
+ break;
+ default: {
+ if (*ar.what == 'm') /* main? */
+ sprintf(buff, "main of %.70s", ar.short_src);
+ else if (*ar.what == 'C') /* C function? */
+ sprintf(buff, "%.70s", ar.short_src);
+ else
+ sprintf(buff, "function <%d:%.70s>", ar.linedefined, ar.short_src);
+ ar.source = NULL; /* do not print source again */
+ }
+ }
+ luaL_addstring(&b, buff);
+ if (ar.currentline > 0) {
+ sprintf(buff, " at line %d", ar.currentline);
+ luaL_addstring(&b, buff);
+ }
+ if (ar.source) {
+ sprintf(buff, " [%.70s]", ar.short_src);
+ luaL_addstring(&b, buff);
+ }
+ luaL_addstring(&b, "\n");
+ }
+ luaL_pushresult(&b);
+ lua_getglobal(L, LUA_ALERT);
+ if (lua_isfunction(L, -1)) { /* avoid loop if _ALERT is not defined */
+ lua_pushvalue(L, -2); /* error message */
+ lua_rawcall(L, 1, 0);
+ }
+ return 0;
+}
+
+
+
+static const struct luaL_reg iolib[] = {
+ {LUA_ERRORMESSAGE, errorfb},
+ {"clock", io_clock},
+ {"date", io_date},
+ {"debug", io_debug},
+ {"execute", io_execute},
+ {"exit", io_exit},
+ {"getenv", io_getenv},
+ {"remove", io_remove},
+ {"rename", io_rename},
+ {"setlocale", setloc},
+};
+
+
+static const struct luaL_reg iolibtag[] = {
+ {"appendto", io_appendto},
+ {"closefile", io_close},
+ {"flush", io_flush},
+ {"openfile", io_open},
+ {"read", io_read},
+ {"readfrom", io_readfrom},
+ {"seek", io_seek},
+ {"write", io_write},
+ {"writeto", io_writeto}
+};
+
+
+static void openwithcontrol (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_newuserdata(L, sizeof(IOCtrl));
+ unsigned int i;
+ ctrl->iotag = lua_newtag(L);
+ ctrl->closedtag = lua_newtag(L);
+ for (i=0; i<sizeof(iolibtag)/sizeof(iolibtag[0]); i++) {
+ /* put `ctrl' as upvalue for these functions */
+ lua_pushvalue(L, -1);
+ lua_pushcclosure(L, iolibtag[i].func, 1);
+ lua_setglobal(L, iolibtag[i].name);
+ }
+ /* create references to variable names */
+ lua_pushstring(L, filenames[INFILE]);
+ ctrl->ref[INFILE] = lua_ref(L, 1);
+ lua_pushstring(L, filenames[OUTFILE]);
+ ctrl->ref[OUTFILE] = lua_ref(L, 1);
+ /* predefined file handles */
+ setfile(L, ctrl, stdin, INFILE);
+ setfile(L, ctrl, stdout, OUTFILE);
+ setfilebyname(L, ctrl, stdin, "_STDIN");
+ setfilebyname(L, ctrl, stdout, "_STDOUT");
+ setfilebyname(L, ctrl, stderr, "_STDERR");
+ /* close files when collected */
+ lua_pushcclosure(L, file_collect, 1); /* pops `ctrl' from stack */
+ lua_settagmethod(L, ctrl->iotag, "gc");
+}
+
+
+LUALIB_API void lua_iolibopen (lua_State *L) {
+ luaL_openl(L, iolib);
+ openwithcontrol(L);
+}
+
diff --git a/src/lua/llex.c b/src/lua/llex.c
new file mode 100644
index 00000000..86fb69ab
--- /dev/null
+++ b/src/lua/llex.c
@@ -0,0 +1,411 @@
+/*
+** $Id: llex.c,v 1.6 2004/06/04 13:42:10 neil Exp $
+** Lexical Analyzer
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "luadebug.h"
+#include "lzio.h"
+
+
+
+#define next(LS) (LS->current = zgetc(LS->z))
+
+
+
+/* ORDER RESERVED */
+static const char *const token2string [] = {
+ "and", "break", "do", "else", "elseif", "end", "for",
+ "function", "if", "local", "nil", "not", "or", "repeat", "return", "then",
+ "until", "while", "", "..", "...", "==", ">=", "<=", "~=", "", "", "<eof>"};
+
+
+void luaX_init (lua_State *L) {
+ int i;
+ for (i=0; i<NUM_RESERVED; i++) {
+ TString *ts = luaS_new(L, token2string[i]);
+ ts->marked = (unsigned char)(RESERVEDMARK+i); /* reserved word */
+ }
+}
+
+
+#define MAXSRC 80
+
+
+void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) {
+ if (val > limit) {
+ char buff[100];
+ sprintf(buff, "too many %.50s (limit=%d)", msg, limit);
+ luaX_error(ls, buff, ls->t.token);
+ }
+}
+
+
+void luaX_syntaxerror (LexState *ls, const char *s, const char *token) {
+ char buff[MAXSRC];
+ luaO_chunkid(buff, ls->source->str, sizeof(buff));
+ luaO_verror(ls->L, "%.99s;\n last token read: `%.30s' at line %d in %.80s",
+ s, token, ls->linenumber, buff);
+}
+
+
+void luaX_error (LexState *ls, const char *s, int token) {
+ char buff[TOKEN_LEN];
+ luaX_token2str(token, buff);
+ if (buff[0] == '\0')
+ luaX_syntaxerror(ls, s, ls->L->Mbuffer);
+ else
+ luaX_syntaxerror(ls, s, buff);
+}
+
+
+void luaX_token2str (int token, char *s) {
+ if (token < 256) {
+ s[0] = (char)token;
+ s[1] = '\0';
+ }
+ else
+ strcpy(s, token2string[token-FIRST_RESERVED]);
+}
+
+
+static void luaX_invalidchar (LexState *ls, int c) {
+ char buff[8];
+ sprintf(buff, "0x%02X", c);
+ luaX_syntaxerror(ls, "invalid control char", buff);
+}
+
+
+static void inclinenumber (LexState *LS) {
+ next(LS); /* skip '\n' */
+ ++LS->linenumber;
+ luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk");
+}
+
+
+void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) {
+ LS->L = L;
+ LS->lookahead.token = TK_EOS; /* no look-ahead token */
+ LS->z = z;
+ LS->fs = NULL;
+ LS->linenumber = 1;
+ LS->lastline = 1;
+ LS->source = source;
+ next(LS); /* read first char */
+ if (LS->current == '#') {
+ do { /* skip first line */
+ next(LS);
+ } while (LS->current != '\n' && LS->current != '\r' && LS->current != EOZ);
+ }
+}
+
+
+
+/*
+** =======================================================
+** LEXICAL ANALYZER
+** =======================================================
+*/
+
+
+/* use Mbuffer to store names, literal strings and numbers */
+
+#define EXTRABUFF 128
+#define checkbuffer(L, n, len) if ((len)+(n) > L->Mbuffsize) \
+ luaO_openspace(L, (len)+(n)+EXTRABUFF)
+
+#define save(L, c, l) (L->Mbuffer[l++] = (char)c)
+#define save_and_next(L, LS, l) (save(L, LS->current, l), next(LS))
+
+
+static const char *readname (LexState *LS) {
+ lua_State *L = LS->L;
+ size_t l = 0;
+ checkbuffer(L, 10, l);
+ do {
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
+ } while (isalnum(LS->current) || LS->current == '_');
+ save(L, '\0', l);
+ return L->Mbuffer;
+}
+
+
+/* LUA_NUMBER */
+static void read_number (LexState *LS, int comma, SemInfo *seminfo) {
+ lua_State *L = LS->L;
+ size_t l = 0;
+ checkbuffer(L, 10, l);
+ if (comma) save(L, '.', l);
+ while (isdigit(LS->current)) {
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
+ }
+ if (LS->current == '.') {
+ save_and_next(L, LS, l);
+ if (LS->current == '.') {
+ save_and_next(L, LS, l);
+ save(L, '\0', l);
+ luaX_error(LS, "ambiguous syntax"
+ " (decimal point x string concatenation)", TK_NUMBER);
+ }
+ }
+ while (isdigit(LS->current)) {
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
+ }
+ if (LS->current == 'e' || LS->current == 'E') {
+ save_and_next(L, LS, l); /* read 'E' */
+ if (LS->current == '+' || LS->current == '-')
+ save_and_next(L, LS, l); /* optional exponent sign */
+ while (isdigit(LS->current)) {
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
+ }
+ }
+ save(L, '\0', l);
+ if (!luaO_str2d(L->Mbuffer, &seminfo->r))
+ luaX_error(LS, "malformed number", TK_NUMBER);
+}
+
+
+static void read_long_string (LexState *LS, SemInfo *seminfo) {
+ lua_State *L = LS->L;
+ int cont = 0;
+ size_t l = 0;
+ checkbuffer(L, 10, l);
+ save(L, '[', l); /* save first '[' */
+ save_and_next(L, LS, l); /* pass the second '[' */
+ for (;;) {
+ checkbuffer(L, 10, l);
+ switch (LS->current) {
+ case EOZ:
+ save(L, '\0', l);
+ if (seminfo)
+ luaX_error(LS, "unfinished long string", TK_STRING);
+ else
+ luaX_error(LS, "unfinished comment", TK_EOS);
+ break; /* to avoid warnings */
+ case '[':
+ save_and_next(L, LS, l);
+ if (LS->current == '[') {
+ cont++;
+ save_and_next(L, LS, l);
+ }
+ continue;
+ case ']':
+ save_and_next(L, LS, l);
+ if (LS->current == ']') {
+ if (cont == 0) goto endloop;
+ cont--;
+ save_and_next(L, LS, l);
+ }
+ continue;
+ case '\n':
+ save(L, '\n', l);
+ inclinenumber(LS);
+ if (LS->current == '\r') next(LS);
+ continue;
+ case '\r':
+ save(L, '\n', l);
+ inclinenumber(LS);
+ if (LS->current == '\n') next(LS);
+ continue;
+ default:
+ if (seminfo) /* no need to save complete comment */
+ save(L, LS->current, l);
+ next(LS);
+ }
+ } endloop:
+ save_and_next(L, LS, l); /* skip the second ']' */
+ save(L, '\0', l);
+ if (seminfo)
+ seminfo->ts = luaS_newlstr(L, L->Mbuffer+2, l-5);
+}
+
+
+static void read_string (LexState *LS, int del, SemInfo *seminfo) {
+ lua_State *L = LS->L;
+ size_t l = 0;
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
+ while (LS->current != del) {
+ checkbuffer(L, 10, l);
+ switch (LS->current) {
+ case EOZ: case '\n': case '\r':
+ save(L, '\0', l);
+ luaX_error(LS, "unfinished string", TK_STRING);
+ break; /* to avoid warnings */
+ case '\\':
+ next(LS); /* do not save the '\' */
+ switch (LS->current) {
+ case 'a': save(L, '\a', l); next(LS); break;
+ case 'b': save(L, '\b', l); next(LS); break;
+ case 'f': save(L, '\f', l); next(LS); break;
+ case 'n': save(L, '\n', l); next(LS); break;
+ case 'r': save(L, '\r', l); next(LS); break;
+ case 't': save(L, '\t', l); next(LS); break;
+ case 'v': save(L, '\v', l); next(LS); break;
+ case '\n':
+ save(L, '\n', l);
+ inclinenumber(LS);
+ if (LS->current == '\r') next(LS);
+ break;
+ case '\r':
+ save(L, '\n', l);
+ inclinenumber(LS);
+ if (LS->current == '\n') next(LS);
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
+ int c = 0;
+ int i = 0;
+ do {
+ c = 10*c + (LS->current-'0');
+ next(LS);
+ } while (++i<3 && isdigit(LS->current));
+ if (c != (unsigned char)c) {
+ save(L, '\0', l);
+ luaX_error(LS, "escape sequence too large", TK_STRING);
+ }
+ save(L, c, l);
+ break;
+ }
+ default: /* handles \\, \", \', and \? */
+ save_and_next(L, LS, l);
+ }
+ break;
+ default:
+ save_and_next(L, LS, l);
+ }
+ }
+ save_and_next(L, LS, l); /* skip delimiter */
+ save(L, '\0', l);
+ seminfo->ts = luaS_newlstr(L, L->Mbuffer+1, l-3);
+}
+
+
+int luaX_lex (LexState *LS, SemInfo *seminfo) {
+ for (;;) {
+ switch (LS->current) {
+
+ case ' ': case '\t':
+ next(LS);
+ continue;
+
+ case '\n':
+ inclinenumber(LS);
+ if (LS->current == '\r') next(LS);
+ continue;
+
+ case '\r':
+ inclinenumber(LS);
+ if (LS->current == '\n') next(LS);
+ continue;
+
+ case '$':
+ luaX_error(LS, "unexpected `$' (pragmas are no longer supported)", '$');
+ break;
+
+ case '-':
+ next(LS);
+ if (LS->current != '-') return '-';
+ if (next(LS) == '[' && next(LS) == '[')
+ read_long_string(LS, NULL);
+ else
+ while (LS->current != '\n' && LS->current != '\r' && LS->current != EOZ)
+ next(LS);
+ continue;
+
+ case '[':
+ next(LS);
+ if (LS->current != '[') return '[';
+ else {
+ read_long_string(LS, seminfo);
+ return TK_STRING;
+ }
+
+ case '=':
+ next(LS);
+ if (LS->current != '=') return '=';
+ else { next(LS); return TK_EQ; }
+
+ case '<':
+ next(LS);
+ if (LS->current != '=') return '<';
+ else { next(LS); return TK_LE; }
+
+ case '>':
+ next(LS);
+ if (LS->current != '=') return '>';
+ else { next(LS); return TK_GE; }
+
+ case '~':
+ next(LS);
+ if (LS->current != '=') return '~';
+ else { next(LS); return TK_NE; }
+
+ case '"':
+ case '\'':
+ read_string(LS, LS->current, seminfo);
+ return TK_STRING;
+
+ case '.':
+ next(LS);
+ if (LS->current == '.') {
+ next(LS);
+ if (LS->current == '.') {
+ next(LS);
+ return TK_DOTS; /* ... */
+ }
+ else return TK_CONCAT; /* .. */
+ }
+ else if (!isdigit(LS->current)) return '.';
+ else {
+ read_number(LS, 1, seminfo);
+ return TK_NUMBER;
+ }
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ read_number(LS, 0, seminfo);
+ return TK_NUMBER;
+
+ case EOZ:
+ return TK_EOS;
+
+ case '_': goto tname;
+
+ default:
+ if (!isalpha(LS->current)) {
+ int c = LS->current;
+ if (iscntrl(c))
+ luaX_invalidchar(LS, c);
+ next(LS);
+ return c;
+ }
+ tname: { /* identifier or reserved word */
+ TString *ts = luaS_new(LS->L, readname(LS));
+ if (ts->marked >= RESERVEDMARK) /* reserved word? */
+ return ts->marked-RESERVEDMARK+FIRST_RESERVED;
+ seminfo->ts = ts;
+ return TK_NAME;
+ }
+ }
+ }
+}
+
diff --git a/src/lua/llex.h b/src/lua/llex.h
new file mode 100644
index 00000000..5fb13c88
--- /dev/null
+++ b/src/lua/llex.h
@@ -0,0 +1,72 @@
+/*
+** $Id: llex.h,v 1.3 2001/11/26 23:00:24 darkgod Exp $
+** Lexical Analyzer
+** See Copyright Notice in lua.h
+*/
+
+#ifndef llex_h
+#define llex_h
+
+#include "lobject.h"
+#include "lzio.h"
+
+
+#define FIRST_RESERVED 257
+
+/* maximum length of a reserved word (+1 for final 0) */
+#define TOKEN_LEN 15
+
+
+/*
+* WARNING: if you change the order of this enumeration,
+* grep "ORDER RESERVED"
+*/
+enum RESERVED {
+ /* terminal symbols denoted by reserved words */
+ TK_AND = FIRST_RESERVED, TK_BREAK,
+ TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FOR, TK_FUNCTION, TK_IF, TK_LOCAL,
+ TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_UNTIL, TK_WHILE,
+ /* other terminal symbols */
+ TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
+ TK_STRING, TK_EOS
+};
+
+/* number of reserved words */
+#define NUM_RESERVED ((int)(TK_WHILE-FIRST_RESERVED+1))
+
+
+typedef union {
+ Number r;
+ TString *ts;
+} SemInfo; /* semantics information */
+
+
+typedef struct Token {
+ int token;
+ SemInfo seminfo;
+} Token;
+
+
+typedef struct LexState {
+ int current; /* current character */
+ Token t; /* current token */
+ Token lookahead; /* look ahead token */
+ struct FuncState *fs; /* `FuncState' is private to the parser */
+ struct lua_State *L;
+ struct zio *z; /* input stream */
+ int linenumber; /* input line counter */
+ int lastline; /* line of last token `consumed' */
+ TString *source; /* current source name */
+} LexState;
+
+
+void luaX_init (lua_State *L);
+void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source);
+int luaX_lex (LexState *LS, SemInfo *seminfo);
+void luaX_checklimit (LexState *ls, int val, int limit, const char *msg);
+void luaX_syntaxerror (LexState *ls, const char *s, const char *token);
+void luaX_error (LexState *ls, const char *s, int token);
+void luaX_token2str (int token, char *s);
+
+
+#endif
diff --git a/src/lua/llimits.h b/src/lua/llimits.h
new file mode 100644
index 00000000..39a1e0df
--- /dev/null
+++ b/src/lua/llimits.h
@@ -0,0 +1,205 @@
+/*
+** $Id: llimits.h,v 1.2 2001/11/26 23:00:24 darkgod Exp $
+** Limits, basic types, and some other "installation-dependent" definitions
+** See Copyright Notice in lua.h
+*/
+
+#ifndef llimits_h
+#define llimits_h
+
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+
+
+/*
+** try to find number of bits in an integer
+*/
+#ifndef BITS_INT
+/* avoid overflows in comparison */
+#if INT_MAX-20 < 32760
+#define BITS_INT 16
+#else
+#if INT_MAX > 2147483640L
+/* machine has at least 32 bits */
+#define BITS_INT 32
+#else
+#error "you must define BITS_INT with number of bits in an integer"
+#endif
+#endif
+#endif
+
+
+/*
+** Define the type `number' of Lua
+** GREP LUA_NUMBER to change that
+*/
+#ifndef LUA_NUM_TYPE
+#define LUA_NUM_TYPE int32_t
+#endif
+
+typedef LUA_NUM_TYPE Number;
+
+/* function to convert a Number to a string */
+#define NUMBER_FMT "%ld" /* LUA_NUMBER */
+#define lua_number2str(s,n) sprintf((s), NUMBER_FMT, (n))
+
+/* function to convert a string to a Number */
+#define lua_str2number(s,p) strtol((s), (p), 10)
+
+
+
+typedef int_least32_t lint32; /* unsigned int with at least 32 bits */
+
+
+#define MAX_SIZET ((size_t)(~(size_t)0)-2)
+
+
+#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
+
+/*
+** conversion of pointer to int (for hashing only)
+** (the shift removes bits that are usually 0 because of alignment)
+*/
+#define IntPoint(p) (((unsigned long)(p)) >> 3)
+
+
+
+#define MINPOWER2 4 /* minimum size for "growing" vectors */
+
+
+
+#ifndef DEFAULT_STACK_SIZE
+#define DEFAULT_STACK_SIZE 1024
+#endif
+
+
+
+/* type to ensure maximum alignment */
+union L_Umaxalign { long d; char *s; long l; };
+
+
+
+/*
+** type for virtual-machine instructions
+** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
+** For a very small machine, you may change that to 2 bytes (and adjust
+** the following limits accordingly)
+*/
+typedef unsigned long Instruction;
+
+
+/*
+** size and position of opcode arguments.
+** For an instruction with 2 bytes, size is 16, and size_b can be 5
+** (accordingly, size_u will be 10, and size_a will be 5)
+*/
+#define SIZE_INSTRUCTION 32
+#define SIZE_B 9
+
+#define SIZE_OP 6
+#define SIZE_U (SIZE_INSTRUCTION-SIZE_OP)
+#define POS_U SIZE_OP
+#define POS_B SIZE_OP
+#define SIZE_A (SIZE_INSTRUCTION-(SIZE_OP+SIZE_B))
+#define POS_A (SIZE_OP+SIZE_B)
+
+
+/*
+** limits for opcode arguments.
+** we use (signed) int to manipulate most arguments,
+** so they must fit in BITS_INT-1 bits (-1 for sign)
+*/
+#if SIZE_U < BITS_INT-1
+#define MAXARG_U ((1<<SIZE_U)-1)
+#define MAXARG_S (MAXARG_U>>1) /* `S' is signed */
+#else
+#define MAXARG_U MAX_INT
+#define MAXARG_S MAX_INT
+#endif
+
+#if SIZE_A < BITS_INT-1
+#define MAXARG_A ((1<<SIZE_A)-1)
+#else
+#define MAXARG_A MAX_INT
+#endif
+
+#if SIZE_B < BITS_INT-1
+#define MAXARG_B ((1<<SIZE_B)-1)
+#else
+#define MAXARG_B MAX_INT
+#endif
+
+
+/* maximum stack size in a function */
+#ifndef MAXSTACK
+#define MAXSTACK 250
+#endif
+
+#if MAXSTACK > MAXARG_B
+#undef MAXSTACK
+#define MAXSTACK MAXARG_B
+#endif
+
+
+/* maximum number of local variables */
+#ifndef MAXLOCALS
+#define MAXLOCALS 200 /* arbitrary limit (<MAXSTACK) */
+#endif
+#if MAXLOCALS>=MAXSTACK
+#undef MAXLOCALS
+#define MAXLOCALS (MAXSTACK-1)
+#endif
+
+
+/* maximum number of upvalues */
+#ifndef MAXUPVALUES
+#define MAXUPVALUES 32 /* arbitrary limit (<=MAXARG_B) */
+#endif
+#if MAXUPVALUES>MAXARG_B
+#undef MAXUPVALUES
+#define MAXUPVALUES MAXARG_B
+#endif
+
+
+/* maximum number of variables in the left side of an assignment */
+#ifndef MAXVARSLH
+#define MAXVARSLH 100 /* arbitrary limit (<MULT_RET) */
+#endif
+#if MAXVARSLH>=MULT_RET
+#undef MAXVARSLH
+#define MAXVARSLH (MULT_RET-1)
+#endif
+
+
+/* maximum number of parameters in a function */
+#ifndef MAXPARAMS
+#define MAXPARAMS 100 /* arbitrary limit (<MAXLOCALS) */
+#endif
+#if MAXPARAMS>=MAXLOCALS
+#undef MAXPARAMS
+#define MAXPARAMS (MAXLOCALS-1)
+#endif
+
+
+/* number of list items to accumulate before a SETLIST instruction */
+#define LFIELDS_PER_FLUSH 64
+#if LFIELDS_PER_FLUSH>(MAXSTACK/4)
+#undef LFIELDS_PER_FLUSH
+#define LFIELDS_PER_FLUSH (MAXSTACK/4)
+#endif
+
+/* number of record items to accumulate before a SETMAP instruction */
+/* (each item counts 2 elements on the stack: an index and a value) */
+#define RFIELDS_PER_FLUSH (LFIELDS_PER_FLUSH/2)
+
+
+/* maximum lookback to find a real constant (for code generation) */
+#ifndef LOOKBACKNUMS
+#define LOOKBACKNUMS 20 /* arbitrary constant */
+#endif
+
+
+#endif
diff --git a/src/lua/lmem.c b/src/lua/lmem.c
new file mode 100644
index 00000000..8fdecef3
--- /dev/null
+++ b/src/lua/lmem.c
@@ -0,0 +1,150 @@
+/*
+** $Id: lmem.c,v 1.3 2001/11/26 23:00:24 darkgod Exp $
+** Interface to Memory Manager
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+#include "lua.h"
+
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+
+
+#ifdef LUA_DEBUG
+/*
+** {======================================================================
+** Controlled version for realloc.
+** =======================================================================
+*/
+
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#define realloc(b, s) debug_realloc(b, s)
+#define malloc(b) debug_realloc(NULL, b)
+#define free(b) debug_realloc(b, 0)
+
+
+/* ensures maximum alignment for HEADER */
+#define HEADER (sizeof(union L_Umaxalign))
+
+#define MARKSIZE 16
+#define MARK 0x55 /* 01010101 (a nice pattern) */
+
+
+#define blocksize(b) ((unsigned long *)((char *)(b) - HEADER))
+
+unsigned long memdebug_numblocks = 0;
+unsigned long memdebug_total = 0;
+unsigned long memdebug_maxmem = 0;
+unsigned long memdebug_memlimit = LONG_MAX;
+
+
+static void *checkblock (void *block) {
+ unsigned long *b = blocksize(block);
+ unsigned long size = *b;
+ int i;
+ for (i=0;i<MARKSIZE;i++)
+ assert(*(((char *)b)+HEADER+size+i) == MARK+i); /* corrupted block? */
+ memdebug_numblocks--;
+ memdebug_total -= size;
+ return b;
+}
+
+
+static void freeblock (void *block) {
+ if (block) {
+ size_t size = *blocksize(block);
+ block = checkblock(block);
+ memset(block, -1, size+HEADER+MARKSIZE); /* erase block */
+ (free)(block); /* free original block */
+ }
+}
+
+
+static void *debug_realloc (void *block, size_t size) {
+ if (size == 0) {
+ freeblock(block);
+ return NULL;
+ }
+ else if (memdebug_total+size > memdebug_memlimit)
+ return NULL; /* to test memory allocation errors */
+ else {
+ size_t realsize = HEADER+size+MARKSIZE;
+ char *newblock = (char *)(malloc)(realsize); /* alloc a new block */
+ int i;
+ if (realsize < size) return NULL; /* overflow! */
+ if (newblock == NULL) return NULL;
+ if (block) {
+ size_t oldsize = *blocksize(block);
+ if (oldsize > size) oldsize = size;
+ memcpy(newblock+HEADER, block, oldsize);
+ freeblock(block); /* erase (and check) old copy */
+ }
+ memdebug_total += size;
+ if (memdebug_total > memdebug_maxmem) memdebug_maxmem = memdebug_total;
+ memdebug_numblocks++;
+ *(unsigned long *)newblock = size;
+ for (i=0;i<MARKSIZE;i++)
+ *(newblock+HEADER+size+i) = (char)(MARK+i);
+ return newblock+HEADER;
+ }
+}
+
+
+/* }====================================================================== */
+#endif
+
+
+
+/*
+** Real ISO (ANSI) systems do not need these tests;
+** but some systems (Sun OS) are not that ISO...
+*/
+#ifdef OLD_ANSI
+#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s))
+#define free(b) if (b) (free)(b)
+#endif
+
+
+void *luaM_growaux (lua_State *L, void *block, size_t nelems,
+ int inc, size_t size, const char *errormsg, size_t limit) {
+ size_t newn = nelems+inc;
+ if (nelems >= limit-inc) lua_error(L, errormsg);
+ if ((newn ^ nelems) <= nelems || /* still the same power-of-2 limit? */
+ (nelems > 0 && newn < MINPOWER2)) /* or block already is MINPOWER2? */
+ return block; /* do not need to reallocate */
+ else /* it crossed a power-of-2 boundary; grow to next power */
+ return luaM_realloc(L, block, luaO_power2(newn)*size);
+}
+
+
+/*
+** generic allocation routine.
+*/
+void *luaM_realloc (lua_State *L, void *block, lint32 size) {
+ if (size == 0) {
+ free(block); /* block may be NULL; that is OK for free */
+ return NULL;
+ }
+ else if (size >= MAX_SIZET)
+ lua_error(L, "memory allocation error: block too big");
+ block = realloc(block, size);
+ if (block == NULL) {
+ if (L)
+ luaD_breakrun(L, LUA_ERRMEM); /* break run without error message */
+ else return NULL; /* error before creating state! */
+ }
+ return block;
+}
+
+
diff --git a/src/lua/lmem.h b/src/lua/lmem.h
new file mode 100644
index 00000000..0d27c336
--- /dev/null
+++ b/src/lua/lmem.h
@@ -0,0 +1,42 @@
+/*
+** $Id: lmem.h,v 1.3 2001/11/26 23:00:24 darkgod Exp $
+** Interface to Memory Manager
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lmem_h
+#define lmem_h
+
+
+#include <stddef.h>
+
+#include "llimits.h"
+#include "lua.h"
+
+void *luaM_realloc (lua_State *L, void *oldblock, lint32 size);
+void *luaM_growaux (lua_State *L, void *block, size_t nelems,
+ int inc, size_t size, const char *errormsg,
+ size_t limit);
+
+#define luaM_free(L, b) luaM_realloc(L, (b), 0)
+#define luaM_malloc(L, t) luaM_realloc(L, NULL, (t))
+#define luaM_new(L, t) ((t *)luaM_malloc(L, sizeof(t)))
+#define luaM_newvector(L, n,t) ((t *)luaM_malloc(L, (n)*(lint32)sizeof(t)))
+
+#define luaM_growvector(L, v,nelems,inc,t,e,l) \
+ ((v)=(t *)luaM_growaux(L, v,nelems,inc,sizeof(t),e,l))
+
+#define luaM_reallocvector(L, v,n,t) \
+ ((v)=(t *)luaM_realloc(L, v,(n)*(lint32)sizeof(t)))
+
+
+#ifdef LUA_DEBUG
+extern unsigned long memdebug_numblocks;
+extern unsigned long memdebug_total;
+extern unsigned long memdebug_maxmem;
+extern unsigned long memdebug_memlimit;
+#endif
+
+
+#endif
+
diff --git a/src/lua/lobject.c b/src/lua/lobject.c
new file mode 100644
index 00000000..cd9d1f0b
--- /dev/null
+++ b/src/lua/lobject.c
@@ -0,0 +1,125 @@
+/*
+** $Id: lobject.c,v 1.3 2001/11/26 23:00:24 darkgod Exp $
+** Some generic functions over Lua objects
+** See Copyright Notice in lua.h
+*/
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+
+const TObject luaO_nilobject = {LUA_TNIL, {NULL}};
+
+
+const char *const luaO_typenames[] = {
+ "userdata", "nil", "number", "string", "table", "function"
+};
+
+
+
+/*
+** returns smaller power of 2 larger than `n' (minimum is MINPOWER2)
+*/
+lint32 luaO_power2 (lint32 n) {
+ lint32 p = MINPOWER2;
+ while (p<=n) p<<=1;
+ return p;
+}
+
+
+int luaO_equalObj (const TObject *t1, const TObject *t2) {
+ if (ttype(t1) != ttype(t2)) return 0;
+ switch (ttype(t1)) {
+ case LUA_TNUMBER:
+ return nvalue(t1) == nvalue(t2);
+ case LUA_TSTRING: case LUA_TUSERDATA:
+ return tsvalue(t1) == tsvalue(t2);
+ case LUA_TTABLE:
+ return hvalue(t1) == hvalue(t2);
+ case LUA_TFUNCTION:
+ return clvalue(t1) == clvalue(t2);
+ default:
+ LUA_ASSERT(ttype(t1) == LUA_TNIL, "invalid type");
+ return 1; /* LUA_TNIL */
+ }
+}
+
+
+char *luaO_openspace (lua_State *L, size_t n) {
+ if (n > L->Mbuffsize) {
+ luaM_reallocvector(L, L->Mbuffer, n, char);
+ L->nblocks += (n - L->Mbuffsize)*sizeof(char);
+ L->Mbuffsize = n;
+ }
+ return L->Mbuffer;
+}
+
+
+int luaO_str2d (const char *s, Number *result) { /* LUA_NUMBER */
+ char *endptr;
+ Number res = lua_str2number(s, &endptr);
+ if (endptr == s) return 0; /* no conversion */
+ while (isspace((unsigned char)*endptr)) endptr++;
+ if (*endptr != '\0') return 0; /* invalid trailing characters? */
+ *result = res;
+ return 1;
+}
+
+
+/* maximum length of a string format for `luaO_verror' */
+#define MAX_VERROR 280
+
+/* this function needs to handle only '%d' and '%.XXs' formats */
+void luaO_verror (lua_State *L, const char *fmt, ...) {
+ va_list argp;
+ char buff[MAX_VERROR]; /* to hold formatted message */
+ va_start(argp, fmt);
+ vsprintf(buff, fmt, argp);
+ va_end(argp);
+ lua_error(L, buff);
+}
+
+
+void luaO_chunkid (char *out, const char *source, int bufflen) {
+ if (*source == '=') {
+ strncpy(out, source+1, bufflen); /* remove first char */
+ out[bufflen-1] = '\0'; /* ensures null termination */
+ }
+ else {
+ if (*source == '@') {
+ int l;
+ source++; /* skip the `@' */
+ bufflen -= sizeof("file `...%s'");
+ l = strlen(source);
+ if (l>bufflen) {
+ source += (l-bufflen); /* get last part of file name */
+ sprintf(out, "file `...%.99s'", source);
+ }
+ else
+ sprintf(out, "file `%.99s'", source);
+ }
+ else {
+ int len = strcspn(source, "\n"); /* stop at first newline */
+ bufflen -= sizeof("string \"%.*s...\"");
+ if (len > bufflen) len = bufflen;
+ if (source[len] != '\0') { /* must truncate? */
+ strcpy(out, "string \"");
+ out += strlen(out);
+ strncpy(out, source, len);
+ strcpy(out+len, "...\"");
+ }
+ else
+ sprintf(out, "string \"%.99s\"", source);
+ }
+ }
+}
diff --git a/src/lua/lobject.h b/src/lua/lobject.h
new file mode 100644
index 00000000..ce978205
--- /dev/null
+++ b/src/lua/lobject.h
@@ -0,0 +1,204 @@
+/*
+** $Id: lobject.h,v 1.3 2001/11/26 23:00:24 darkgod Exp $
+** Type definitions for Lua objects
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lobject_h
+#define lobject_h
+
+
+#include "llimits.h"
+#include "lua.h"
+
+
+#ifdef LUA_DEBUG
+#undef NDEBUG
+#include <assert.h>
+#define LUA_INTERNALERROR(s) assert(((void)s,0))
+#define LUA_ASSERT(c,s) assert(((void)s,(c)))
+#else
+#define LUA_INTERNALERROR(s) /* empty */
+#define LUA_ASSERT(c,s) /* empty */
+#endif
+
+
+#ifdef LUA_DEBUG
+/* to avoid warnings, and make sure value is really unused */
+#define UNUSED(x) (x=0, (void)(x))
+#else
+#define UNUSED(x) ((void)(x)) /* to avoid warnings */
+#endif
+
+
+/* mark for closures active in the stack */
+#define LUA_TMARK 6
+
+
+/* tags for values visible from Lua == first user-created tag */
+#define NUM_TAGS 6
+
+
+/* check whether `t' is a mark */
+#define is_T_MARK(t) ((t) == LUA_TMARK)
+
+
+typedef union {
+ struct TString *ts; /* LUA_TSTRING, LUA_TUSERDATA */
+ struct Closure *cl; /* LUA_TFUNCTION */
+ struct Hash *a; /* LUA_TTABLE */
+ struct CallInfo *i; /* LUA_TLMARK */
+ Number n; /* LUA_TNUMBER */
+} Value;
+
+
+/* Macros to access values */
+#define ttype(o) ((o)->ttype)
+#define nvalue(o) ((o)->value.n)
+#define tsvalue(o) ((o)->value.ts)
+#define clvalue(o) ((o)->value.cl)
+#define hvalue(o) ((o)->value.a)
+#define infovalue(o) ((o)->value.i)
+#define svalue(o) (tsvalue(o)->str)
+
+
+typedef struct lua_TObject {
+ int ttype;
+ Value value;
+} TObject;
+
+
+/*
+** String headers for string table
+*/
+
+/*
+** most `malloc' libraries allocate memory in blocks of 8 bytes. TSPACK
+** tries to make sizeof(TString) a multiple of this granularity, to reduce
+** waste of space.
+*/
+#define TSPACK ((int)sizeof(int))
+
+typedef struct TString {
+ union {
+ struct { /* for strings */
+ unsigned long hash;
+ int constindex; /* hint to reuse constants */
+ } s;
+ struct { /* for userdata */
+ int tag;
+ void *value;
+ } d;
+ } u;
+ size_t len;
+ struct TString *nexthash; /* chain for hash table */
+ int marked;
+ char str[TSPACK]; /* variable length string!! must be the last field! */
+} TString;
+
+
+/*
+** Function Prototypes
+*/
+typedef struct Proto {
+ Number *knum; /* Number numbers used by the function */
+ int nknum; /* size of `knum' */
+ struct TString **kstr; /* strings used by the function */
+ int nkstr; /* size of `kstr' */
+ struct Proto **kproto; /* functions defined inside the function */
+ int nkproto; /* size of `kproto' */
+ Instruction *code;
+ int ncode; /* size of `code'; when 0 means an incomplete `Proto' */
+ short numparams;
+ short is_vararg;
+ short maxstacksize;
+ short marked;
+ struct Proto *next;
+ /* debug information */
+ int *lineinfo; /* map from opcodes to source lines */
+ int nlineinfo; /* size of `lineinfo' */
+ int nlocvars;
+ struct LocVar *locvars; /* information about local variables */
+ int lineDefined;
+ TString *source;
+} Proto;
+
+
+typedef struct LocVar {
+ TString *varname;
+ int startpc; /* first point where variable is active */
+ int endpc; /* first point where variable is dead */
+} LocVar;
+
+
+/*
+** Closures
+*/
+typedef struct Closure {
+ union {
+ lua_CFunction c; /* C functions */
+ struct Proto *l; /* Lua functions */
+ } f;
+ struct Closure *next;
+ struct Closure *mark; /* marked closures (point to itself when not marked) */
+ short isC; /* 0 for Lua functions, 1 for C functions */
+ short nupvalues;
+ TObject upvalue[1];
+} Closure;
+
+
+#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->isC)
+
+
+typedef struct Node {
+ TObject key;
+ TObject val;
+ struct Node *next; /* for chaining */
+} Node;
+
+typedef struct Hash {
+ Node *node;
+ int htag;
+ int size;
+ Node *firstfree; /* this position is free; all positions after it are full */
+ struct Hash *next;
+ struct Hash *mark; /* marked tables (point to itself when not marked) */
+} Hash;
+
+
+/* unmarked tables and closures are represented by pointing `mark' to
+** themselves
+*/
+#define ismarked(x) ((x)->mark != (x))
+
+
+/*
+** informations about a call (for debugging)
+*/
+typedef struct CallInfo {
+ struct Closure *func; /* function being called */
+ const Instruction **pc; /* current pc of called function */
+ int lastpc; /* last pc traced */
+ int line; /* current line */
+ int refi; /* current index in `lineinfo' */
+} CallInfo;
+
+
+extern const TObject luaO_nilobject;
+extern const char *const luaO_typenames[];
+
+
+#define luaO_typename(o) (luaO_typenames[ttype(o)])
+
+
+lint32 luaO_power2 (lint32 n);
+char *luaO_openspace (lua_State *L, size_t n);
+
+int luaO_equalObj (const TObject *t1, const TObject *t2);
+int luaO_str2d (const char *s, Number *result);
+
+void luaO_verror (lua_State *L, const char *fmt, ...);
+void luaO_chunkid (char *out, const char *source, int len);
+
+
+#endif
diff --git a/src/lua/lopcodes.h b/src/lua/lopcodes.h
new file mode 100644
index 00000000..59740896
--- /dev/null
+++ b/src/lua/lopcodes.h
@@ -0,0 +1,168 @@
+/*
+** $Id: lopcodes.h,v 1.5 2004/06/04 13:42:10 neil Exp $
+** Opcodes for Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lopcodes_h
+#define lopcodes_h
+
+#include "llimits.h"
+
+
+/*===========================================================================
+ We assume that instructions are unsigned numbers.
+ All instructions have an opcode in the first 6 bits. Moreover,
+ an instruction can have 0, 1, or 2 arguments. Instructions can
+ have the following types:
+ type 0: no arguments
+ type 1: 1 unsigned argument in the higher bits (called `U')
+ type 2: 1 signed argument in the higher bits (`S')
+ type 3: 1st unsigned argument in the higher bits (`A')
+ 2nd unsigned argument in the middle bits (`B')
+
+ A signed argument is represented in excess K; that is, the number
+ value is the unsigned value minus K. K is exactly the maximum value
+ for that argument (so that -max is represented by 0, and +max is
+ represented by 2*max), which is half the maximum for the corresponding
+ unsigned argument.
+
+ The size of each argument is defined in `llimits.h'. The usual is an
+ instruction with 32 bits, U arguments with 26 bits (32-6), B arguments
+ with 9 bits, and A arguments with 17 bits (32-6-9). For small
+ installations, the instruction size can be 16, so U has 10 bits,
+ and A and B have 5 bits each.
+===========================================================================*/
+
+
+
+
+/* creates a mask with `n' 1 bits at position `p' */
+#define MASK1(n,p) ((~((~(Instruction)0)<<n))<<p)
+
+/* creates a mask with `n' 0 bits at position `p' */
+#define MASK0(n,p) (~MASK1(n,p))
+
+/*
+** the following macros help to manipulate instructions
+*/
+
+#define CREATE_0(o) ((Instruction)(o))
+#define GET_OPCODE(i) ((OpCode)((i)&MASK1(SIZE_OP,0)))
+#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,0)) | (Instruction)(o)))
+
+#define CREATE_U(o,u) ((Instruction)(o) | ((Instruction)(u)<<POS_U))
+#define GETARG_U(i) ((int)((i)>>POS_U))
+#define SETARG_U(i,u) ((i) = (((i)&MASK0(SIZE_U,POS_U)) | \
+ ((Instruction)(u)<<POS_U)))
+
+#define CREATE_S(o,s) CREATE_U((o),(s)+MAXARG_S)
+#define GETARG_S(i) (GETARG_U(i)-MAXARG_S)
+#define SETARG_S(i,s) SETARG_U((i),(s)+MAXARG_S)
+
+
+#define CREATE_AB(o,a,b) ((Instruction)(o) | ((Instruction)(a)<<POS_A) \
+ | ((Instruction)(b)<<POS_B))
+#define GETARG_A(i) ((int)((i)>>POS_A))
+#define SETARG_A(i,a) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
+ ((Instruction)(a)<<POS_A)))
+#define GETARG_B(i) ((int)(((i)>>POS_B) & MASK1(SIZE_B,0)))
+#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \
+ ((Instruction)(b)<<POS_B)))
+
+
+/*
+** K = U argument used as index to `kstr'
+** J = S argument used as jump offset (relative to pc of next instruction)
+** L = unsigned argument used as index of local variable
+** N = U argument used as index to `knum'
+*/
+
+typedef enum {
+/*----------------------------------------------------------------------
+name args stack before stack after side effects
+------------------------------------------------------------------------*/
+OP_END,/* - - (return) no results */
+OP_RETURN,/* U v_n-v_x(at u) (return) returns v_x-v_n */
+
+OP_CALL,/* A B v_n-v_1 f(at a) r_b-r_1 f(v1,...,v_n) */
+OP_TAILCALL,/* A B v_n-v_1 f(at a) (return) f(v1,...,v_n) */
+
+OP_PUSHNIL,/* U - nil_1-nil_u */
+OP_POP,/* U a_u-a_1 - */
+
+OP_PUSHINT,/* S - (Number)s */
+OP_PUSHSTRING,/* K - KSTR[k] */
+OP_PUSHNUM,/* N - KNUM[n] */
+OP_PUSHNEGNUM,/* N - -KNUM[n] */
+
+OP_PUSHUPVALUE,/* U - Closure[u] */
+
+OP_GETLOCAL,/* L - LOC[l] */
+OP_GETGLOBAL,/* K - VAR[KSTR[k]] */
+
+OP_GETTABLE,/* - i t t[i] */
+OP_GETDOTTED,/* K t t[KSTR[k]] */
+OP_GETINDEXED,/* L t t[LOC[l]] */
+OP_PUSHSELF,/* K t t t[KSTR[k]] */
+
+OP_CREATETABLE,/* U - newarray(size = u) */
+
+OP_SETLOCAL,/* L x - LOC[l]=x */
+OP_SETGLOBAL,/* K x - VAR[KSTR[k]]=x */
+OP_SETTABLE,/* A B v a_a-a_1 i t (pops b values) t[i]=v */
+
+OP_SETLIST,/* A B v_b-v_1 t t t[i+a*FPF]=v_i */
+OP_SETMAP,/* U v_u k_u - v_1 k_1 t t t[k_i]=v_i */
+
+OP_ADD,/* - y x x+y */
+OP_ADDI,/* S x x+s */
+OP_SUB,/* - y x x-y */
+OP_MULT,/* - y x x*y */
+OP_DIV,/* - y x x/y */
+OP_POW,/* - y x x^y */
+OP_CONCAT,/* U v_u-v_1 v1..-..v_u */
+OP_MINUS,/* - x -x */
+OP_NOT,/* - x (x==nil)? 1 : nil */
+
+OP_JMPNE,/* J y x - (x~=y)? PC+=s */
+OP_JMPEQ,/* J y x - (x==y)? PC+=s */
+OP_JMPLT,/* J y x - (x<y)? PC+=s */
+OP_JMPLE,/* J y x - (x<y)? PC+=s */
+OP_JMPGT,/* J y x - (x>y)? PC+=s */
+OP_JMPGE,/* J y x - (x>=y)? PC+=s */
+
+OP_JMPT,/* J x - (x~=nil)? PC+=s */
+OP_JMPF,/* J x - (x==nil)? PC+=s */
+OP_JMPONT,/* J x (x~=nil)? x : - (x~=nil)? PC+=s */
+OP_JMPONF,/* J x (x==nil)? x : - (x==nil)? PC+=s */
+OP_JMP,/* J - - PC+=s */
+
+OP_PUSHNILJMP,/* - - nil PC++; */
+
+OP_FORPREP,/* J */
+OP_FORLOOP,/* J */
+
+OP_LFORPREP,/* J */
+OP_LFORLOOP,/* J */
+
+OP_CLOSURE/* A B v_b-v_1 closure(KPROTO[a], v_1-v_b) */
+
+} OpCode;
+
+#define NUM_OPCODES ((int)OP_CLOSURE+1)
+
+
+#define ISJUMP(o) (OP_JMPNE <= (o) && (o) <= OP_JMP)
+
+
+
+/* special code to fit a LUA_MULTRET inside an argB */
+#define MULT_RET 255 /* (<=MAXARG_B) */
+#if MULT_RET>MAXARG_B
+#undef MULT_RET
+#define MULT_RET MAXARG_B
+#endif
+
+
+#endif
diff --git a/src/lua/lparser.c b/src/lua/lparser.c
new file mode 100644
index 00000000..1ac1f37b
--- /dev/null
+++ b/src/lua/lparser.c
@@ -0,0 +1,1129 @@
+/*
+** $Id: lparser.c,v 1.8 2004/06/04 13:42:10 neil Exp $
+** LL(1) Parser and code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "lfunc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+
+#ifdef __MWERKS__
+/* To avoid name conflict resulting from the use of prefix header */
+#define stat lua_hack_stat
+#endif /* __MWERKS__ */
+
+
+/*
+** Constructors descriptor:
+** `n' indicates number of elements, and `k' signals whether
+** it is a list constructor (k = 0) or a record constructor (k = 1)
+** or empty (k = ';' or '}')
+*/
+typedef struct Constdesc {
+ int n;
+ int k;
+} Constdesc;
+
+
+typedef struct Breaklabel {
+ struct Breaklabel *previous; /* chain */
+ int breaklist;
+ int stacklevel;
+} Breaklabel;
+
+
+
+
+/*
+** prototypes for recursive non-terminal functions
+*/
+static void body (LexState *ls, int needself, int line);
+static void chunk (LexState *ls);
+static void constructor (LexState *ls);
+static void expr (LexState *ls, expdesc *v);
+static void exp1 (LexState *ls);
+
+
+
+static void next (LexState *ls) {
+ ls->lastline = ls->linenumber;
+ if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
+ ls->t = ls->lookahead; /* use this one */
+ ls->lookahead.token = TK_EOS; /* and discharge it */
+ }
+ else
+ ls->t.token = luaX_lex(ls, &ls->t.seminfo); /* read next token */
+}
+
+
+static void lookahead (LexState *ls) {
+ LUA_ASSERT(ls->lookahead.token == TK_EOS, "two look-aheads");
+ ls->lookahead.token = luaX_lex(ls, &ls->lookahead.seminfo);
+}
+
+
+static void error_expected (LexState *ls, int token) {
+ char buff[100], t[TOKEN_LEN];
+ luaX_token2str(token, t);
+ sprintf(buff, "`%.20s' expected", t);
+ luaK_error(ls, buff);
+}
+
+
+static void check (LexState *ls, int c) {
+ if (ls->t.token != c)
+ error_expected(ls, c);
+ next(ls);
+}
+
+
+static void check_condition (LexState *ls, int c, const char *msg) {
+ if (!c) luaK_error(ls, msg);
+}
+
+
+static int optional (LexState *ls, int c) {
+ if (ls->t.token == c) {
+ next(ls);
+ return 1;
+ }
+ else return 0;
+}
+
+
+static void check_match (LexState *ls, int what, int who, int where) {
+ if (ls->t.token != what) {
+ if (where == ls->linenumber)
+ error_expected(ls, what);
+ else {
+ char buff[100];
+ char t_what[TOKEN_LEN], t_who[TOKEN_LEN];
+ luaX_token2str(what, t_what);
+ luaX_token2str(who, t_who);
+ sprintf(buff, "`%.20s' expected (to close `%.20s' at line %d)",
+ t_what, t_who, where);
+ luaK_error(ls, buff);
+ }
+ }
+ next(ls);
+}
+
+
+static int string_constant (FuncState *fs, TString *s) {
+ Proto *f = fs->f;
+ int c = s->u.s.constindex;
+ if (c >= f->nkstr || f->kstr[c] != s) {
+ luaM_growvector(fs->L, f->kstr, f->nkstr, 1, TString *,
+ "constant table overflow", MAXARG_U);
+ c = f->nkstr++;
+ f->kstr[c] = s;
+ s->u.s.constindex = c; /* hint for next time */
+ }
+ return c;
+}
+
+
+static void code_string (LexState *ls, TString *s) {
+ luaK_kstr(ls, string_constant(ls->fs, s));
+}
+
+
+static TString *str_checkname (LexState *ls) {
+ TString *ts;
+ check_condition(ls, (ls->t.token == TK_NAME), "<name> expected");
+ ts = ls->t.seminfo.ts;
+ next(ls);
+ return ts;
+}
+
+
+static int checkname (LexState *ls) {
+ return string_constant(ls->fs, str_checkname(ls));
+}
+
+
+static int luaI_registerlocalvar (LexState *ls, TString *varname) {
+ Proto *f = ls->fs->f;
+ luaM_growvector(ls->L, f->locvars, f->nlocvars, 1, LocVar, "", MAX_INT);
+ f->locvars[f->nlocvars].varname = varname;
+ return f->nlocvars++;
+}
+
+
+static void new_localvar (LexState *ls, TString *name, int n) {
+ FuncState *fs = ls->fs;
+ luaX_checklimit(ls, fs->nactloc+n+1, MAXLOCALS, "local variables");
+ fs->actloc[fs->nactloc+n] = luaI_registerlocalvar(ls, name);
+}
+
+
+static void adjustlocalvars (LexState *ls, int nvars) {
+ FuncState *fs = ls->fs;
+ while (nvars--)
+ fs->f->locvars[fs->actloc[fs->nactloc++]].startpc = fs->pc;
+}
+
+
+static void removelocalvars (LexState *ls, int nvars) {
+ FuncState *fs = ls->fs;
+ while (nvars--)
+ fs->f->locvars[fs->actloc[--fs->nactloc]].endpc = fs->pc;
+}
+
+
+static void new_localvarstr (LexState *ls, const char *name, int n) {
+ new_localvar(ls, luaS_newfixed(ls->L, name), n);
+}
+
+
+static int search_local (LexState *ls, TString *n, expdesc *var) {
+ FuncState *fs;
+ int level = 0;
+ for (fs=ls->fs; fs; fs=fs->prev) {
+ int i;
+ for (i=fs->nactloc-1; i >= 0; i--) {
+ if (n == fs->f->locvars[fs->actloc[i]].varname) {
+ var->k = VLOCAL;
+ var->u.index = i;
+ return level;
+ }
+ }
+ level++; /* `var' not found; check outer level */
+ }
+ var->k = VGLOBAL; /* not found in any level; must be global */
+ return -1;
+}
+
+
+static void singlevar (LexState *ls, TString *n, expdesc *var) {
+ int level = search_local(ls, n, var);
+ if (level >= 1) /* neither local (0) nor global (-1)? */
+ luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str);
+ else if (level == -1) /* global? */
+ var->u.index = string_constant(ls->fs, n);
+}
+
+
+static int indexupvalue (LexState *ls, expdesc *v) {
+ FuncState *fs = ls->fs;
+ int i;
+ for (i=0; i<fs->nupvalues; i++) {
+ if (fs->upvalues[i].k == v->k && fs->upvalues[i].u.index == v->u.index)
+ return i;
+ }
+ /* new one */
+ luaX_checklimit(ls, fs->nupvalues+1, MAXUPVALUES, "upvalues");
+ fs->upvalues[fs->nupvalues] = *v;
+ return fs->nupvalues++;
+}
+
+
+static void pushupvalue (LexState *ls, TString *n) {
+ FuncState *fs = ls->fs;
+ expdesc v;
+ int level = search_local(ls, n, &v);
+ if (level == -1) { /* global? */
+ if (fs->prev == NULL)
+ luaX_syntaxerror(ls, "cannot access upvalue in main", n->str);
+ v.u.index = string_constant(fs->prev, n);
+ }
+ else if (level != 1)
+ luaX_syntaxerror(ls,
+ "upvalue must be global or local to immediately outer scope", n->str);
+ luaK_code1(fs, OP_PUSHUPVALUE, indexupvalue(ls, &v));
+}
+
+
+static void adjust_mult_assign (LexState *ls, int nvars, int nexps) {
+ FuncState *fs = ls->fs;
+ int diff = nexps - nvars;
+ if (nexps > 0 && luaK_lastisopen(fs)) { /* list ends in a function call */
+ diff--; /* do not count function call itself */
+ if (diff <= 0) { /* more variables than values? */
+ luaK_setcallreturns(fs, -diff); /* function call provide extra values */
+ diff = 0; /* no more difference */
+ }
+ else /* more values than variables */
+ luaK_setcallreturns(fs, 0); /* call should provide no value */
+ }
+ /* push or pop eventual difference between list lengths */
+ luaK_adjuststack(fs, diff);
+}
+
+
+static void code_params (LexState *ls, int nparams, int dots) {
+ FuncState *fs = ls->fs;
+ adjustlocalvars(ls, nparams);
+ luaX_checklimit(ls, fs->nactloc, MAXPARAMS, "parameters");
+ fs->f->numparams = fs->nactloc; /* `self' could be there already */
+ fs->f->is_vararg = dots;
+ if (dots) {
+ new_localvarstr(ls, "arg", 0);
+ adjustlocalvars(ls, 1);
+ }
+ luaK_deltastack(fs, fs->nactloc); /* count parameters in the stack */
+}
+
+
+static void enterbreak (FuncState *fs, Breaklabel *bl) {
+ bl->stacklevel = fs->stacklevel;
+ bl->breaklist = NO_JUMP;
+ bl->previous = fs->bl;
+ fs->bl = bl;
+}
+
+
+static void leavebreak (FuncState *fs, Breaklabel *bl) {
+ fs->bl = bl->previous;
+ LUA_ASSERT(bl->stacklevel == fs->stacklevel, "wrong levels");
+ luaK_patchlist(fs, bl->breaklist, luaK_getlabel(fs));
+}
+
+
+static void pushclosure (LexState *ls, FuncState *func) {
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f;
+ int i;
+ for (i=0; i<func->nupvalues; i++)
+ luaK_tostack(ls, &func->upvalues[i], 1);
+ luaM_growvector(ls->L, f->kproto, f->nkproto, 1, Proto *,
+ "constant table overflow", MAXARG_A);
+ f->kproto[f->nkproto++] = func->f;
+ luaK_code2(fs, OP_CLOSURE, f->nkproto-1, func->nupvalues);
+}
+
+
+static void open_func (LexState *ls, FuncState *fs) {
+ Proto *f = luaF_newproto(ls->L);
+ fs->prev = ls->fs; /* linked list of funcstates */
+ fs->ls = ls;
+ fs->L = ls->L;
+ ls->fs = fs;
+ fs->stacklevel = 0;
+ fs->nactloc = 0;
+ fs->nupvalues = 0;
+ fs->bl = NULL;
+ fs->f = f;
+ f->source = ls->source;
+ fs->pc = 0;
+ fs->lasttarget = 0;
+ fs->lastline = 0;
+ fs->jlt = NO_JUMP;
+ f->code = NULL;
+ f->maxstacksize = 0;
+ f->numparams = 0; /* default for main chunk */
+ f->is_vararg = 0; /* default for main chunk */
+}
+
+
+static void close_func (LexState *ls) {
+ lua_State *L = ls->L;
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f;
+ luaK_code0(fs, OP_END);
+ luaK_getlabel(fs); /* close eventual list of pending jumps */
+ luaM_reallocvector(L, f->code, fs->pc, Instruction);
+ luaM_reallocvector(L, f->kstr, f->nkstr, TString *);
+ luaM_reallocvector(L, f->knum, f->nknum, Number);
+ luaM_reallocvector(L, f->kproto, f->nkproto, Proto *);
+ removelocalvars(ls, fs->nactloc);
+ luaM_reallocvector(L, f->locvars, f->nlocvars, LocVar);
+ luaM_reallocvector(L, f->lineinfo, f->nlineinfo+1, int);
+ f->lineinfo[f->nlineinfo++] = MAX_INT; /* end flag */
+ luaF_protook(L, f, fs->pc); /* proto is ok now */
+ ls->fs = fs->prev;
+ LUA_ASSERT(fs->bl == NULL, "wrong list end");
+}
+
+
+Proto *luaY_parser (lua_State *L, ZIO *z) {
+ struct LexState lexstate;
+ struct FuncState funcstate;
+ luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z)));
+ open_func(&lexstate, &funcstate);
+ next(&lexstate); /* read first token */
+ chunk(&lexstate);
+ check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected");
+ close_func(&lexstate);
+ LUA_ASSERT(funcstate.prev == NULL, "wrong list end");
+ LUA_ASSERT(funcstate.nupvalues == 0, "no upvalues in main");
+ return funcstate.f;
+}
+
+
+
+/*============================================================*/
+/* GRAMMAR RULES */
+/*============================================================*/
+
+
+static int explist1 (LexState *ls) {
+ /* explist1 -> expr { ',' expr } */
+ int n = 1; /* at least one expression */
+ expdesc v;
+ expr(ls, &v);
+ while (ls->t.token == ',') {
+ luaK_tostack(ls, &v, 1); /* gets only 1 value from previous expression */
+ next(ls); /* skip comma */
+ expr(ls, &v);
+ n++;
+ }
+ luaK_tostack(ls, &v, 0); /* keep open number of values of last expression */
+ return n;
+}
+
+
+static void funcargs (LexState *ls, int slf) {
+ FuncState *fs = ls->fs;
+ int slevel = fs->stacklevel - slf - 1; /* where is func in the stack */
+ switch (ls->t.token) {
+ case '(': { /* funcargs -> '(' [ explist1 ] ')' */
+ int line = ls->linenumber;
+ int nargs = 0;
+ next(ls);
+ if (ls->t.token != ')') /* arg list not empty? */
+ nargs = explist1(ls);
+ check_match(ls, ')', '(', line);
+#ifdef LUA_COMPAT_ARGRET
+ if (nargs > 0) /* arg list is not empty? */
+ luaK_setcallreturns(fs, 1); /* last call returns only 1 value */
+#else
+ UNUSED(nargs); /* to avoid warnings */
+#endif
+ break;
+ }
+ case '{': { /* funcargs -> constructor */
+ constructor(ls);
+ break;
+ }
+ case TK_STRING: { /* funcargs -> STRING */
+ code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */
+ next(ls);
+ break;
+ }
+ default: {
+ luaK_error(ls, "function arguments expected");
+ break;
+ }
+ }
+ fs->stacklevel = slevel; /* call will remove function and arguments */
+ luaK_code2(fs, OP_CALL, slevel, MULT_RET);
+}
+
+
+static void var_or_func_tail (LexState *ls, expdesc *v) {
+ for (;;) {
+ switch (ls->t.token) {
+ case '.': { /* var_or_func_tail -> '.' NAME */
+ next(ls);
+ luaK_tostack(ls, v, 1); /* `v' must be on stack */
+ luaK_kstr(ls, checkname(ls));
+ v->k = VINDEXED;
+ break;
+ }
+ case '[': { /* var_or_func_tail -> '[' exp1 ']' */
+ next(ls);
+ luaK_tostack(ls, v, 1); /* `v' must be on stack */
+ v->k = VINDEXED;
+ exp1(ls);
+ check(ls, ']');
+ break;
+ }
+ case ':': { /* var_or_func_tail -> ':' NAME funcargs */
+ int name;
+ next(ls);
+ name = checkname(ls);
+ luaK_tostack(ls, v, 1); /* `v' must be on stack */
+ luaK_code1(ls->fs, OP_PUSHSELF, name);
+ funcargs(ls, 1);
+ v->k = VEXP;
+ v->u.l.t = v->u.l.f = NO_JUMP;
+ break;
+ }
+ case '(': case TK_STRING: case '{': { /* var_or_func_tail -> funcargs */
+ luaK_tostack(ls, v, 1); /* `v' must be on stack */
+ funcargs(ls, 0);
+ v->k = VEXP;
+ v->u.l.t = v->u.l.f = NO_JUMP;
+ break;
+ }
+ default: return; /* should be follow... */
+ }
+ }
+}
+
+
+static void var_or_func (LexState *ls, expdesc *v) {
+ /* var_or_func -> ['%'] NAME var_or_func_tail */
+ if (optional(ls, '%')) { /* upvalue? */
+ pushupvalue(ls, str_checkname(ls));
+ v->k = VEXP;
+ v->u.l.t = v->u.l.f = NO_JUMP;
+ }
+ else /* variable name */
+ singlevar(ls, str_checkname(ls), v);
+ var_or_func_tail(ls, v);
+}
+
+
+
+/*
+** {======================================================================
+** Rules for Constructors
+** =======================================================================
+*/
+
+
+static void recfield (LexState *ls) {
+ /* recfield -> (NAME | '['exp1']') = exp1 */
+ switch (ls->t.token) {
+ case TK_NAME: {
+ luaK_kstr(ls, checkname(ls));
+ break;
+ }
+ case '[': {
+ next(ls);
+ exp1(ls);
+ check(ls, ']');
+ break;
+ }
+ default: luaK_error(ls, "<name> or `[' expected");
+ }
+ check(ls, '=');
+ exp1(ls);
+}
+
+
+static int recfields (LexState *ls) {
+ /* recfields -> recfield { ',' recfield } [','] */
+ FuncState *fs = ls->fs;
+ int n = 1; /* at least one element */
+ recfield(ls);
+ while (ls->t.token == ',') {
+ next(ls);
+ if (ls->t.token == ';' || ls->t.token == '}')
+ break;
+ recfield(ls);
+ n++;
+ if (n%RFIELDS_PER_FLUSH == 0)
+ luaK_code1(fs, OP_SETMAP, RFIELDS_PER_FLUSH);
+ }
+ luaK_code1(fs, OP_SETMAP, n%RFIELDS_PER_FLUSH);
+ return n;
+}
+
+
+static int listfields (LexState *ls) {
+ /* listfields -> exp1 { ',' exp1 } [','] */
+ FuncState *fs = ls->fs;
+ int n = 1; /* at least one element */
+ exp1(ls);
+ while (ls->t.token == ',') {
+ next(ls);
+ if (ls->t.token == ';' || ls->t.token == '}')
+ break;
+ exp1(ls);
+ n++;
+ luaX_checklimit(ls, n/LFIELDS_PER_FLUSH, MAXARG_A,
+ "`item groups' in a list initializer");
+ if (n%LFIELDS_PER_FLUSH == 0)
+ luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH);
+ }
+ luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH);
+ return n;
+}
+
+
+
+static void constructor_part (LexState *ls, Constdesc *cd) {
+ switch (ls->t.token) {
+ case ';': case '}': { /* constructor_part -> empty */
+ cd->n = 0;
+ cd->k = ls->t.token;
+ break;
+ }
+ case TK_NAME: { /* may be listfields or recfields */
+ lookahead(ls);
+ if (ls->lookahead.token != '=') /* expression? */
+ goto case_default;
+ /* else go through to recfields */
+ }
+ case '[': { /* constructor_part -> recfields */
+ cd->n = recfields(ls);
+ cd->k = 1; /* record */
+ break;
+ }
+ default: { /* constructor_part -> listfields */
+ case_default:
+ cd->n = listfields(ls);
+ cd->k = 0; /* list */
+ break;
+ }
+ }
+}
+
+
+static void constructor (LexState *ls) {
+ /* constructor -> '{' constructor_part [';' constructor_part] '}' */
+ FuncState *fs = ls->fs;
+ int line = ls->linenumber;
+ int pc = luaK_code1(fs, OP_CREATETABLE, 0);
+ int nelems;
+ Constdesc cd;
+ check(ls, '{');
+ constructor_part(ls, &cd);
+ nelems = cd.n;
+ if (optional(ls, ';')) {
+ Constdesc other_cd;
+ constructor_part(ls, &other_cd);
+ check_condition(ls, (cd.k != other_cd.k), "invalid constructor syntax");
+ nelems += other_cd.n;
+ }
+ check_match(ls, '}', '{', line);
+ luaX_checklimit(ls, nelems, MAXARG_U, "elements in a table constructor");
+ SETARG_U(fs->f->code[pc], nelems); /* set initial table size */
+}
+
+/* }====================================================================== */
+
+
+
+
+/*
+** {======================================================================
+** Expression parsing
+** =======================================================================
+*/
+
+
+static void simpleexp (LexState *ls, expdesc *v) {
+ FuncState *fs = ls->fs;
+ switch (ls->t.token) {
+ case TK_NUMBER: { /* simpleexp -> NUMBER */
+ Number r = ls->t.seminfo.r;
+ next(ls);
+ luaK_number(fs, r);
+ break;
+ }
+ case TK_STRING: { /* simpleexp -> STRING */
+ code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */
+ next(ls);
+ break;
+ }
+ case TK_NIL: { /* simpleexp -> NIL */
+ luaK_adjuststack(fs, -1);
+ next(ls);
+ break;
+ }
+ case '{': { /* simpleexp -> constructor */
+ constructor(ls);
+ break;
+ }
+ case TK_FUNCTION: { /* simpleexp -> FUNCTION body */
+ next(ls);
+ body(ls, 0, ls->linenumber);
+ break;
+ }
+ case '(': { /* simpleexp -> '(' expr ')' */
+ next(ls);
+ expr(ls, v);
+ check(ls, ')');
+ return;
+ }
+ case TK_NAME: case '%': {
+ var_or_func(ls, v);
+ return;
+ }
+ default: {
+ luaK_error(ls, "<expression> expected");
+ return;
+ }
+ }
+ v->k = VEXP;
+ v->u.l.t = v->u.l.f = NO_JUMP;
+}
+
+
+static void exp1 (LexState *ls) {
+ expdesc v;
+ expr(ls, &v);
+ luaK_tostack(ls, &v, 1);
+}
+
+
+static UnOpr getunopr (int op) {
+ switch (op) {
+ case TK_NOT: return OPR_NOT;
+ case '-': return OPR_MINUS;
+ default: return OPR_NOUNOPR;
+ }
+}
+
+
+static BinOpr getbinopr (int op) {
+ switch (op) {
+ case '+': return OPR_ADD;
+ case '-': return OPR_SUB;
+ case '*': return OPR_MULT;
+ case '/': return OPR_DIV;
+ case '^': return OPR_POW;
+ case TK_CONCAT: return OPR_CONCAT;
+ case TK_NE: return OPR_NE;
+ case TK_EQ: return OPR_EQ;
+ case '<': return OPR_LT;
+ case TK_LE: return OPR_LE;
+ case '>': return OPR_GT;
+ case TK_GE: return OPR_GE;
+ case TK_AND: return OPR_AND;
+ case TK_OR: return OPR_OR;
+ default: return OPR_NOBINOPR;
+ }
+}
+
+
+static const struct {
+ char left; /* left priority for each binary operator */
+ char right; /* right priority */
+} priority[] = { /* ORDER OPR */
+ {5, 5}, {5, 5}, {6, 6}, {6, 6}, /* arithmetic */
+ {9, 8}, {4, 3}, /* power and concat (right associative) */
+ {2, 2}, {2, 2}, /* equality */
+ {2, 2}, {2, 2}, {2, 2}, {2, 2}, /* order */
+ {1, 1}, {1, 1} /* logical */
+};
+
+#define UNARY_PRIORITY 7 /* priority for unary operators */
+
+
+/*
+** subexpr -> (simplexep | unop subexpr) { binop subexpr }
+** where `binop' is any binary operator with a priority higher than `limit'
+*/
+static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
+ BinOpr op;
+ UnOpr uop = getunopr(ls->t.token);
+ if (uop != OPR_NOUNOPR) {
+ next(ls);
+ subexpr(ls, v, UNARY_PRIORITY);
+ luaK_prefix(ls, uop, v);
+ }
+ else simpleexp(ls, v);
+ /* expand while operators have priorities higher than `limit' */
+ op = getbinopr(ls->t.token);
+ while (op != OPR_NOBINOPR && priority[op].left > limit) {
+ expdesc v2;
+ BinOpr nextop;
+ next(ls);
+ luaK_infix(ls, op, v);
+ /* read sub-expression with higher priority */
+ nextop = subexpr(ls, &v2, priority[op].right);
+ luaK_posfix(ls, op, v, &v2);
+ op = nextop;
+ }
+ return op; /* return first untreated operator */
+}
+
+
+static void expr (LexState *ls, expdesc *v) {
+ subexpr(ls, v, -1);
+}
+
+/* }==================================================================== */
+
+
+/*
+** {======================================================================
+** Rules for Statements
+** =======================================================================
+*/
+
+
+static int block_follow (int token) {
+ switch (token) {
+ case TK_ELSE: case TK_ELSEIF: case TK_END:
+ case TK_UNTIL: case TK_EOS:
+ return 1;
+ default: return 0;
+ }
+}
+
+
+static void block (LexState *ls) {
+ /* block -> chunk */
+ FuncState *fs = ls->fs;
+ int nactloc = fs->nactloc;
+ chunk(ls);
+ luaK_adjuststack(fs, fs->nactloc - nactloc); /* remove local variables */
+ removelocalvars(ls, fs->nactloc - nactloc);
+}
+
+
+static int assignment (LexState *ls, expdesc *v, int nvars) {
+ int left = 0; /* number of values left in the stack after assignment */
+ luaX_checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment");
+ if (ls->t.token == ',') { /* assignment -> ',' NAME assignment */
+ expdesc nv;
+ next(ls);
+ var_or_func(ls, &nv);
+ check_condition(ls, (nv.k != VEXP), "syntax error");
+ left = assignment(ls, &nv, nvars+1);
+ }
+ else { /* assignment -> '=' explist1 */
+ int nexps;
+ check(ls, '=');
+ nexps = explist1(ls);
+ adjust_mult_assign(ls, nvars, nexps);
+ }
+ if (v->k != VINDEXED)
+ luaK_storevar(ls, v);
+ else { /* there may be garbage between table-index and value */
+ luaK_code2(ls->fs, OP_SETTABLE, left+nvars+2, 1);
+ left += 2;
+ }
+ return left;
+}
+
+
+static void cond (LexState *ls, expdesc *v) {
+ /* cond -> exp */
+ expr(ls, v); /* read condition */
+ luaK_goiftrue(ls->fs, v, 0);
+}
+
+
+static void whilestat (LexState *ls, int line) {
+ /* whilestat -> WHILE cond DO block END */
+ FuncState *fs = ls->fs;
+ int while_init = luaK_getlabel(fs);
+ expdesc v;
+ Breaklabel bl;
+ enterbreak(fs, &bl);
+ next(ls);
+ cond(ls, &v);
+ check(ls, TK_DO);
+ block(ls);
+ luaK_patchlist(fs, luaK_jump(fs), while_init);
+ luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs));
+ check_match(ls, TK_END, TK_WHILE, line);
+ leavebreak(fs, &bl);
+}
+
+
+static void repeatstat (LexState *ls, int line) {
+ /* repeatstat -> REPEAT block UNTIL cond */
+ FuncState *fs = ls->fs;
+ int repeat_init = luaK_getlabel(fs);
+ expdesc v;
+ Breaklabel bl;
+ enterbreak(fs, &bl);
+ next(ls);
+ block(ls);
+ check_match(ls, TK_UNTIL, TK_REPEAT, line);
+ cond(ls, &v);
+ luaK_patchlist(fs, v.u.l.f, repeat_init);
+ leavebreak(fs, &bl);
+}
+
+
+static void forbody (LexState *ls, int nvar, OpCode prepfor, OpCode loopfor) {
+ /* forbody -> DO block END */
+ FuncState *fs = ls->fs;
+ int prep = luaK_code1(fs, prepfor, NO_JUMP);
+ int blockinit = luaK_getlabel(fs);
+ check(ls, TK_DO);
+ adjustlocalvars(ls, nvar); /* scope for control variables */
+ block(ls);
+ luaK_patchlist(fs, luaK_code1(fs, loopfor, NO_JUMP), blockinit);
+ luaK_patchlist(fs, prep, luaK_getlabel(fs));
+ removelocalvars(ls, nvar);
+}
+
+
+static void fornum (LexState *ls, TString *varname) {
+ /* fornum -> NAME = exp1,exp1[,exp1] forbody */
+ FuncState *fs = ls->fs;
+ check(ls, '=');
+ exp1(ls); /* initial value */
+ check(ls, ',');
+ exp1(ls); /* limit */
+ if (optional(ls, ','))
+ exp1(ls); /* optional step */
+ else
+ luaK_code1(fs, OP_PUSHINT, 1); /* default step */
+ new_localvar(ls, varname, 0);
+ new_localvarstr(ls, "(limit)", 1);
+ new_localvarstr(ls, "(step)", 2);
+ forbody(ls, 3, OP_FORPREP, OP_FORLOOP);
+}
+
+
+static void forlist (LexState *ls, TString *indexname) {
+ /* forlist -> NAME,NAME IN exp1 forbody */
+ TString *valname;
+ check(ls, ',');
+ valname = str_checkname(ls);
+ /* next test is dirty, but avoids `in' being a reserved word */
+ check_condition(ls,
+ (ls->t.token == TK_NAME && ls->t.seminfo.ts == luaS_new(ls->L, "in")),
+ "`in' expected");
+ next(ls); /* skip `in' */
+ exp1(ls); /* table */
+ new_localvarstr(ls, "(table)", 0);
+ new_localvar(ls, indexname, 1);
+ new_localvar(ls, valname, 2);
+ forbody(ls, 3, OP_LFORPREP, OP_LFORLOOP);
+}
+
+
+static void forstat (LexState *ls, int line) {
+ /* forstat -> fornum | forlist */
+ FuncState *fs = ls->fs;
+ TString *varname;
+ Breaklabel bl;
+ enterbreak(fs, &bl);
+ next(ls); /* skip `for' */
+ varname = str_checkname(ls); /* first variable name */
+ switch (ls->t.token) {
+ case '=': fornum(ls, varname); break;
+ case ',': forlist(ls, varname); break;
+ default: luaK_error(ls, "`=' or `,' expected");
+ }
+ check_match(ls, TK_END, TK_FOR, line);
+ leavebreak(fs, &bl);
+}
+
+
+static void test_then_block (LexState *ls, expdesc *v) {
+ /* test_then_block -> [IF | ELSEIF] cond THEN block */
+ next(ls); /* skip IF or ELSEIF */
+ cond(ls, v);
+ check(ls, TK_THEN);
+ block(ls); /* `then' part */
+}
+
+
+static void ifstat (LexState *ls, int line) {
+ /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
+ FuncState *fs = ls->fs;
+ expdesc v;
+ int escapelist = NO_JUMP;
+ test_then_block(ls, &v); /* IF cond THEN block */
+ while (ls->t.token == TK_ELSEIF) {
+ luaK_concat(fs, &escapelist, luaK_jump(fs));
+ luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs));
+ test_then_block(ls, &v); /* ELSEIF cond THEN block */
+ }
+ if (ls->t.token == TK_ELSE) {
+ luaK_concat(fs, &escapelist, luaK_jump(fs));
+ luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs));
+ next(ls); /* skip ELSE */
+ block(ls); /* `else' part */
+ }
+ else
+ luaK_concat(fs, &escapelist, v.u.l.f);
+ luaK_patchlist(fs, escapelist, luaK_getlabel(fs));
+ check_match(ls, TK_END, TK_IF, line);
+}
+
+
+static void localstat (LexState *ls) {
+ /* stat -> LOCAL NAME {',' NAME} ['=' explist1] */
+ int nvars = 0;
+ int nexps;
+ do {
+ next(ls); /* skip LOCAL or ',' */
+ new_localvar(ls, str_checkname(ls), nvars++);
+ } while (ls->t.token == ',');
+ if (optional(ls, '='))
+ nexps = explist1(ls);
+ else
+ nexps = 0;
+ adjust_mult_assign(ls, nvars, nexps);
+ adjustlocalvars(ls, nvars);
+}
+
+
+static int funcname (LexState *ls, expdesc *v) {
+ /* funcname -> NAME [':' NAME | '.' NAME] */
+ int needself = 0;
+ singlevar(ls, str_checkname(ls), v);
+ if (ls->t.token == ':' || ls->t.token == '.') {
+ needself = (ls->t.token == ':');
+ next(ls);
+ luaK_tostack(ls, v, 1);
+ luaK_kstr(ls, checkname(ls));
+ v->k = VINDEXED;
+ }
+ return needself;
+}
+
+
+static void funcstat (LexState *ls, int line) {
+ /* funcstat -> FUNCTION funcname body */
+ int needself;
+ expdesc v;
+ next(ls); /* skip FUNCTION */
+ needself = funcname(ls, &v);
+ body(ls, needself, line);
+ luaK_storevar(ls, &v);
+}
+
+
+static void namestat (LexState *ls) {
+ /* stat -> func | ['%'] NAME assignment */
+ FuncState *fs = ls->fs;
+ expdesc v;
+ var_or_func(ls, &v);
+ if (v.k == VEXP) { /* stat -> func */
+ check_condition(ls, luaK_lastisopen(fs), "syntax error"); /* an upvalue? */
+ luaK_setcallreturns(fs, 0); /* call statement uses no results */
+ }
+ else { /* stat -> ['%'] NAME assignment */
+ int left = assignment(ls, &v, 1);
+ luaK_adjuststack(fs, left); /* remove eventual garbage left on stack */
+ }
+}
+
+
+static void retstat (LexState *ls) {
+ /* stat -> RETURN explist */
+ FuncState *fs = ls->fs;
+ next(ls); /* skip RETURN */
+ if (!block_follow(ls->t.token))
+ explist1(ls); /* optional return values */
+ luaK_code1(fs, OP_RETURN, ls->fs->nactloc);
+ fs->stacklevel = fs->nactloc; /* removes all temp values */
+}
+
+
+static void breakstat (LexState *ls) {
+ /* stat -> BREAK [NAME] */
+ FuncState *fs = ls->fs;
+ int currentlevel = fs->stacklevel;
+ Breaklabel *bl = fs->bl;
+ if (!bl)
+ luaK_error(ls, "no loop to break");
+ next(ls); /* skip BREAK */
+ luaK_adjuststack(fs, currentlevel - bl->stacklevel);
+ luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
+ /* correct stack for compiler and symbolic execution */
+ luaK_adjuststack(fs, bl->stacklevel - currentlevel);
+}
+
+
+static int stat (LexState *ls) {
+ int line = ls->linenumber; /* may be needed for error messages */
+ switch (ls->t.token) {
+ case TK_IF: { /* stat -> ifstat */
+ ifstat(ls, line);
+ return 0;
+ }
+ case TK_WHILE: { /* stat -> whilestat */
+ whilestat(ls, line);
+ return 0;
+ }
+ case TK_DO: { /* stat -> DO block END */
+ next(ls); /* skip DO */
+ block(ls);
+ check_match(ls, TK_END, TK_DO, line);
+ return 0;
+ }
+ case TK_FOR: { /* stat -> forstat */
+ forstat(ls, line);
+ return 0;
+ }
+ case TK_REPEAT: { /* stat -> repeatstat */
+ repeatstat(ls, line);
+ return 0;
+ }
+ case TK_FUNCTION: { /* stat -> funcstat */
+ funcstat(ls, line);
+ return 0;
+ }
+ case TK_LOCAL: { /* stat -> localstat */
+ localstat(ls);
+ return 0;
+ }
+ case TK_NAME: case '%': { /* stat -> namestat */
+ namestat(ls);
+ return 0;
+ }
+ case TK_RETURN: { /* stat -> retstat */
+ retstat(ls);
+ return 1; /* must be last statement */
+ }
+ case TK_BREAK: { /* stat -> breakstat */
+ breakstat(ls);
+ return 1; /* must be last statement */
+ }
+ default: {
+ luaK_error(ls, "<statement> expected");
+ return 0; /* to avoid warnings */
+ }
+ }
+}
+
+
+static void parlist (LexState *ls) {
+ /* parlist -> [ param { ',' param } ] */
+ int nparams = 0;
+ int dots = 0;
+ if (ls->t.token != ')') { /* is `parlist' not empty? */
+ do {
+ switch (ls->t.token) {
+ case TK_DOTS: next(ls); dots = 1; break;
+ case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break;
+ default: luaK_error(ls, "<name> or `...' expected");
+ }
+ } while (!dots && optional(ls, ','));
+ }
+ code_params(ls, nparams, dots);
+}
+
+
+static void body (LexState *ls, int needself, int line) {
+ /* body -> '(' parlist ')' chunk END */
+ FuncState new_fs;
+ open_func(ls, &new_fs);
+ new_fs.f->lineDefined = line;
+ check(ls, '(');
+ if (needself) {
+ new_localvarstr(ls, "self", 0);
+ adjustlocalvars(ls, 1);
+ }
+ parlist(ls);
+ check(ls, ')');
+ chunk(ls);
+ check_match(ls, TK_END, TK_FUNCTION, line);
+ close_func(ls);
+ pushclosure(ls, &new_fs);
+}
+
+
+/* }====================================================================== */
+
+
+static void chunk (LexState *ls) {
+ /* chunk -> { stat [';'] } */
+ int islast = 0;
+ while (!islast && !block_follow(ls->t.token)) {
+ islast = stat(ls);
+ optional(ls, ';');
+ LUA_ASSERT(ls->fs->stacklevel == ls->fs->nactloc,
+ "stack size != # local vars");
+ }
+}
+
diff --git a/src/lua/lparser.h b/src/lua/lparser.h
new file mode 100644
index 00000000..d83fb5f1
--- /dev/null
+++ b/src/lua/lparser.h
@@ -0,0 +1,60 @@
+/*
+** $Id: lparser.h,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** LL(1) Parser and code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lparser_h
+#define lparser_h
+
+#include "lobject.h"
+#include "lzio.h"
+
+
+/*
+** Expression descriptor
+*/
+
+typedef enum {
+ VGLOBAL,
+ VLOCAL,
+ VINDEXED,
+ VEXP
+} expkind;
+
+typedef struct expdesc {
+ expkind k;
+ union {
+ int index; /* VGLOBAL: `kstr' index of global name; VLOCAL: stack index */
+ struct {
+ int t; /* patch list of `exit when true' */
+ int f; /* patch list of `exit when false' */
+ } l;
+ } u;
+} expdesc;
+
+
+
+/* state needed to generate code for a given function */
+typedef struct FuncState {
+ Proto *f; /* current function header */
+ struct FuncState *prev; /* enclosing function */
+ struct LexState *ls; /* lexical state */
+ struct lua_State *L; /* copy of the Lua state */
+ int pc; /* next position to code */
+ int lasttarget; /* `pc' of last `jump target' */
+ int jlt; /* list of jumps to `lasttarget' */
+ short stacklevel; /* number of values on activation register */
+ short nactloc; /* number of active local variables */
+ short nupvalues; /* number of upvalues */
+ int lastline; /* line where last `lineinfo' was generated */
+ struct Breaklabel *bl; /* chain of breakable blocks */
+ expdesc upvalues[MAXUPVALUES]; /* upvalues */
+ int actloc[MAXLOCALS]; /* local-variable stack (indices to locvars) */
+} FuncState;
+
+
+Proto *luaY_parser (lua_State *L, ZIO *z);
+
+
+#endif
diff --git a/src/lua/lstate.c b/src/lua/lstate.c
new file mode 100644
index 00000000..6310cb7e
--- /dev/null
+++ b/src/lua/lstate.c
@@ -0,0 +1,121 @@
+/*
+** $Id: lstate.c,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** Global State
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdio.h>
+
+#include "lua.h"
+
+#include "ldo.h"
+#include "lgc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+#ifdef LUA_DEBUG
+static lua_State *lua_state = NULL;
+void luaB_opentests (lua_State *L);
+#endif
+
+
+/*
+** built-in implementation for ERRORMESSAGE. In a "correct" environment
+** ERRORMESSAGE should have an external definition, and so this function
+** would not be used.
+*/
+static int errormessage (lua_State *L) {
+ const char *s = lua_tostring(L, 1);
+ if (s == NULL) s = "(no message)";
+ fprintf(stderr, "error: %s\n", s);
+ return 0;
+}
+
+
+/*
+** open parts that may cause memory-allocation errors
+*/
+static void f_luaopen (lua_State *L, void *ud) {
+ int stacksize = *(int *)ud;
+ if (stacksize == 0)
+ stacksize = DEFAULT_STACK_SIZE;
+ else
+ stacksize += LUA_MINSTACK;
+ L->gt = luaH_new(L, 10); /* table of globals */
+ luaD_init(L, stacksize);
+ luaS_init(L);
+ luaX_init(L);
+ luaT_init(L);
+ lua_newtable(L);
+ lua_ref(L, 1); /* create registry */
+ lua_register(L, LUA_ERRORMESSAGE, errormessage);
+#ifdef LUA_DEBUG
+ luaB_opentests(L);
+ if (lua_state == NULL) lua_state = L; /* keep first state to be opened */
+#endif
+ LUA_ASSERT(lua_gettop(L) == 0, "wrong API stack");
+}
+
+
+LUA_API lua_State *lua_open (int stacksize) {
+ lua_State *L = luaM_new(NULL, lua_State);
+ if (L == NULL) return NULL; /* memory allocation error */
+ L->stack = NULL;
+ L->strt.size = L->udt.size = 0;
+ L->strt.nuse = L->udt.nuse = 0;
+ L->strt.hash = NULL;
+ L->udt.hash = NULL;
+ L->Mbuffer = NULL;
+ L->Mbuffsize = 0;
+ L->rootproto = NULL;
+ L->rootcl = NULL;
+ L->roottable = NULL;
+ L->TMtable = NULL;
+ L->last_tag = -1;
+ L->refArray = NULL;
+ L->refSize = 0;
+ L->refFree = NONEXT;
+ L->nblocks = sizeof(lua_State);
+ L->GCthreshold = MAX_INT; /* to avoid GC during pre-definitions */
+ L->callhook = NULL;
+ L->linehook = NULL;
+ L->allowhooks = 1;
+ L->errorJmp = NULL;
+ if (luaD_runprotected(L, f_luaopen, &stacksize) != 0) {
+ /* memory allocation error: free partial state */
+ lua_close(L);
+ return NULL;
+ }
+ L->GCthreshold = 2*L->nblocks;
+ return L;
+}
+
+
+LUA_API void lua_close (lua_State *L) {
+ LUA_ASSERT(L != lua_state || lua_gettop(L) == 0, "garbage in C stack");
+ luaC_collect(L, 1); /* collect all elements */
+ LUA_ASSERT(L->rootproto == NULL, "list should be empty");
+ LUA_ASSERT(L->rootcl == NULL, "list should be empty");
+ LUA_ASSERT(L->roottable == NULL, "list should be empty");
+ luaS_freeall(L);
+ if (L->stack)
+ L->nblocks -= (L->stack_last - L->stack + 1)*sizeof(TObject);
+ luaM_free(L, L->stack);
+ L->nblocks -= (L->last_tag+1)*sizeof(struct TM);
+ luaM_free(L, L->TMtable);
+ L->nblocks -= (L->refSize)*sizeof(struct Ref);
+ luaM_free(L, L->refArray);
+ L->nblocks -= (L->Mbuffsize)*sizeof(char);
+ luaM_free(L, L->Mbuffer);
+ LUA_ASSERT(L->nblocks == sizeof(lua_State), "wrong count for nblocks");
+ luaM_free(L, L);
+ LUA_ASSERT(L != lua_state || memdebug_numblocks == 0, "memory leak!");
+ LUA_ASSERT(L != lua_state || memdebug_total == 0,"memory leak!");
+}
+
diff --git a/src/lua/lstate.h b/src/lua/lstate.h
new file mode 100644
index 00000000..ee02db01
--- /dev/null
+++ b/src/lua/lstate.h
@@ -0,0 +1,77 @@
+/*
+** $Id: lstate.h,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** Global State
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lstate_h
+#define lstate_h
+
+#include "lobject.h"
+#include "lua.h"
+#include "luadebug.h"
+
+
+
+typedef TObject *StkId; /* index to stack elements */
+
+
+/*
+** marks for Reference array
+*/
+#define NONEXT -1 /* to end the free list */
+#define HOLD -2
+#define COLLECTED -3
+#define LOCK -4
+
+
+struct Ref {
+ TObject o;
+ int st; /* can be LOCK, HOLD, COLLECTED, or next (for free list) */
+};
+
+
+struct lua_longjmp; /* defined in ldo.c */
+struct TM; /* defined in ltm.h */
+
+
+typedef struct stringtable {
+ int size;
+ lint32 nuse; /* number of elements */
+ TString **hash;
+} stringtable;
+
+
+
+struct lua_State {
+ /* thread-specific state */
+ StkId top; /* first free slot in the stack */
+ StkId stack; /* stack base */
+ StkId stack_last; /* last free slot in the stack */
+ int stacksize;
+ StkId Cbase; /* base for current C function */
+ struct lua_longjmp *errorJmp; /* current error recover point */
+ char *Mbuffer; /* global buffer */
+ size_t Mbuffsize; /* size of Mbuffer */
+ /* global state */
+ Proto *rootproto; /* list of all prototypes */
+ Closure *rootcl; /* list of all closures */
+ Hash *roottable; /* list of all tables */
+ stringtable strt; /* hash table for strings */
+ stringtable udt; /* hash table for udata */
+ Hash *gt; /* table for globals */
+ struct TM *TMtable; /* table for tag methods */
+ int last_tag; /* last used tag in TMtable */
+ struct Ref *refArray; /* locked objects */
+ int refSize; /* size of refArray */
+ int refFree; /* list of free positions in refArray */
+ unsigned long GCthreshold;
+ unsigned long nblocks; /* number of `bytes' currently allocated */
+ lua_Hook callhook;
+ lua_Hook linehook;
+ int allowhooks;
+};
+
+
+#endif
+
diff --git a/src/lua/lstring.c b/src/lua/lstring.c
new file mode 100644
index 00000000..7293e195
--- /dev/null
+++ b/src/lua/lstring.c
@@ -0,0 +1,155 @@
+/*
+** $Id: lstring.c,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** String table (keeps all strings handled by Lua)
+** See Copyright Notice in lua.h
+*/
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+
+
+/*
+** type equivalent to TString, but with maximum alignment requirements
+*/
+union L_UTString {
+ TString ts;
+ union L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */
+};
+
+
+
+void luaS_init (lua_State *L) {
+ L->strt.hash = luaM_newvector(L, 1, TString *);
+ L->udt.hash = luaM_newvector(L, 1, TString *);
+ L->nblocks += 2*sizeof(TString *);
+ L->strt.size = L->udt.size = 1;
+ L->strt.nuse = L->udt.nuse = 0;
+ L->strt.hash[0] = L->udt.hash[0] = NULL;
+}
+
+
+void luaS_freeall (lua_State *L) {
+ LUA_ASSERT(L->strt.nuse==0, "non-empty string table");
+ L->nblocks -= (L->strt.size + L->udt.size)*sizeof(TString *);
+ luaM_free(L, L->strt.hash);
+ LUA_ASSERT(L->udt.nuse==0, "non-empty udata table");
+ luaM_free(L, L->udt.hash);
+}
+
+
+static unsigned long hash_s (const char *s, size_t l) {
+ unsigned long h = l; /* seed */
+ size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */
+ for (; l>=step; l-=step)
+ h = h ^ ((h<<5)+(h>>2)+(unsigned char)*(s++));
+ return h;
+}
+
+
+void luaS_resize (lua_State *L, stringtable *tb, int newsize) {
+ TString **newhash = luaM_newvector(L, newsize, TString *);
+ int i;
+ for (i=0; i<newsize; i++) newhash[i] = NULL;
+ /* rehash */
+ for (i=0; i<tb->size; i++) {
+ TString *p = tb->hash[i];
+ while (p) { /* for each node in the list */
+ TString *next = p->nexthash; /* save next */
+ unsigned long h = (tb == &L->strt) ? p->u.s.hash : IntPoint(p->u.d.value);
+ int h1 = h&(newsize-1); /* new position */
+ LUA_ASSERT(h%newsize == (h&(newsize-1)),
+ "a&(x-1) == a%x, for x power of 2");
+ p->nexthash = newhash[h1]; /* chain it in new position */
+ newhash[h1] = p;
+ p = next;
+ }
+ }
+ luaM_free(L, tb->hash);
+ L->nblocks += (newsize - tb->size)*sizeof(TString *);
+ tb->size = newsize;
+ tb->hash = newhash;
+}
+
+
+static void newentry (lua_State *L, stringtable *tb, TString *ts, int h) {
+ ts->nexthash = tb->hash[h]; /* chain new entry */
+ tb->hash[h] = ts;
+ tb->nuse++;
+ if (tb->nuse > (lint32)tb->size && tb->size < MAX_INT/2) /* too crowded? */
+ luaS_resize(L, tb, tb->size*2);
+}
+
+
+
+TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
+ unsigned long h = hash_s(str, l);
+ int h1 = h & (L->strt.size-1);
+ TString *ts;
+ for (ts = L->strt.hash[h1]; ts; ts = ts->nexthash) {
+ if (ts->len == l && (memcmp(str, ts->str, l) == 0))
+ return ts;
+ }
+ /* not found */
+ ts = (TString *)luaM_malloc(L, sizestring(l));
+ ts->marked = 0;
+ ts->nexthash = NULL;
+ ts->len = l;
+ ts->u.s.hash = h;
+ ts->u.s.constindex = 0;
+ memcpy(ts->str, str, l);
+ ts->str[l] = 0; /* ending 0 */
+ L->nblocks += sizestring(l);
+ newentry(L, &L->strt, ts, h1); /* insert it on table */
+ return ts;
+}
+
+
+TString *luaS_newudata (lua_State *L, size_t s, void *udata) {
+ union L_UTString *uts = (union L_UTString *)luaM_malloc(L,
+ (lint32)sizeof(union L_UTString)+s);
+ TString *ts = &uts->ts;
+ ts->marked = 0;
+ ts->nexthash = NULL;
+ ts->len = s;
+ ts->u.d.tag = 0;
+ ts->u.d.value = (udata == NULL) ? uts+1 : udata;
+ L->nblocks += sizestring(s);
+ /* insert it on table */
+ newentry(L, &L->udt, ts, IntPoint(ts->u.d.value) & (L->udt.size-1));
+ return ts;
+}
+
+
+TString *luaS_createudata (lua_State *L, void *udata, int tag) {
+ int h1 = IntPoint(udata) & (L->udt.size-1);
+ TString *ts;
+ for (ts = L->udt.hash[h1]; ts; ts = ts->nexthash) {
+ if (udata == ts->u.d.value && (tag == ts->u.d.tag || tag == LUA_ANYTAG))
+ return ts;
+ }
+ /* not found */
+ ts = luaS_newudata(L, 0, udata);
+ if (tag != LUA_ANYTAG)
+ ts->u.d.tag = tag;
+ return ts;
+}
+
+
+TString *luaS_new (lua_State *L, const char *str) {
+ return luaS_newlstr(L, str, strlen(str));
+}
+
+
+TString *luaS_newfixed (lua_State *L, const char *str) {
+ TString *ts = luaS_new(L, str);
+ if (ts->marked == 0) ts->marked = FIXMARK; /* avoid GC */
+ return ts;
+}
+
diff --git a/src/lua/lstring.h b/src/lua/lstring.h
new file mode 100644
index 00000000..f23159ec
--- /dev/null
+++ b/src/lua/lstring.h
@@ -0,0 +1,37 @@
+/*
+** $Id: lstring.h,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** String table (keep all strings handled by Lua)
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lstring_h
+#define lstring_h
+
+
+#include "lobject.h"
+#include "lstate.h"
+
+
+/*
+** any TString with mark>=FIXMARK is never collected.
+** Marks>=RESERVEDMARK are used to identify reserved words.
+*/
+#define FIXMARK 2
+#define RESERVEDMARK 3
+
+
+#define sizestring(l) ((long)sizeof(TString) + \
+ ((long)(l+1)-TSPACK)*(long)sizeof(char))
+
+
+void luaS_init (lua_State *L);
+void luaS_resize (lua_State *L, stringtable *tb, int newsize);
+TString *luaS_newudata (lua_State *L, size_t s, void *udata);
+TString *luaS_createudata (lua_State *L, void *udata, int tag);
+void luaS_freeall (lua_State *L);
+TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
+TString *luaS_new (lua_State *L, const char *str);
+TString *luaS_newfixed (lua_State *L, const char *str);
+
+
+#endif
diff --git a/src/lua/lstrlib.c b/src/lua/lstrlib.c
new file mode 100644
index 00000000..051eccf7
--- /dev/null
+++ b/src/lua/lstrlib.c
@@ -0,0 +1,621 @@
+/*
+** $Id: lstrlib.c,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** Standard library for string operations and pattern-matching
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+
+static int str_len (lua_State *L) {
+ size_t l;
+ luaL_check_lstr(L, 1, &l);
+ lua_pushnumber(L, l);
+ return 1;
+}
+
+
+static long posrelat (long pos, size_t len) {
+ /* relative string position: negative means back from end */
+ return (pos>=0) ? pos : (long)len+pos+1;
+}
+
+
+static int str_sub (lua_State *L) {
+ size_t l;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ long start = posrelat(luaL_check_long(L, 2), l);
+ long end = posrelat(luaL_opt_long(L, 3, -1), l);
+ if (start < 1) start = 1;
+ if (end > (long)l) end = l;
+ if (start <= end)
+ lua_pushlstring(L, s+start-1, end-start+1);
+ else lua_pushstring(L, "");
+ return 1;
+}
+
+
+static int str_lower (lua_State *L) {
+ size_t l;
+ size_t i;
+ luaL_Buffer b;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ luaL_buffinit(L, &b);
+ for (i=0; i<l; i++)
+ luaL_putchar(&b, tolower((unsigned char)(s[i])));
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+static int str_upper (lua_State *L) {
+ size_t l;
+ size_t i;
+ luaL_Buffer b;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ luaL_buffinit(L, &b);
+ for (i=0; i<l; i++)
+ luaL_putchar(&b, toupper((unsigned char)(s[i])));
+ luaL_pushresult(&b);
+ return 1;
+}
+
+static int str_rep (lua_State *L) {
+ size_t l;
+ luaL_Buffer b;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ int n = luaL_check_int(L, 2);
+ luaL_buffinit(L, &b);
+ while (n-- > 0)
+ luaL_addlstring(&b, s, l);
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+static int str_byte (lua_State *L) {
+ size_t l;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ long pos = posrelat(luaL_opt_long(L, 2, 1), l);
+ luaL_arg_check(L, 0<pos && (size_t)pos<=l, 2, "out of range");
+ lua_pushnumber(L, (unsigned char)s[pos-1]);
+ return 1;
+}
+
+
+static int str_char (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int i;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ for (i=1; i<=n; i++) {
+ int c = luaL_check_int(L, i);
+ luaL_arg_check(L, (unsigned char)c == c, i, "invalid value");
+ luaL_putchar(&b, (unsigned char)c);
+ }
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+
+/*
+** {======================================================
+** PATTERN MATCHING
+** =======================================================
+*/
+
+#ifndef MAX_CAPTURES
+#define MAX_CAPTURES 32 /* arbitrary limit */
+#endif
+
+
+struct Capture {
+ const char *src_end; /* end ('\0') of source string */
+ int level; /* total number of captures (finished or unfinished) */
+ struct {
+ const char *init;
+ long len; /* -1 signals unfinished capture */
+ } capture[MAX_CAPTURES];
+};
+
+
+#define ESC '%'
+#define SPECIALS "^$*+?.([%-"
+
+
+static int check_capture (lua_State *L, int l, struct Capture *cap) {
+ l -= '1';
+ if (!(0 <= l && l < cap->level && cap->capture[l].len != -1))
+ lua_error(L, "invalid capture index");
+ return l;
+}
+
+
+static int capture_to_close (lua_State *L, struct Capture *cap) {
+ int level = cap->level;
+ for (level--; level>=0; level--)
+ if (cap->capture[level].len == -1) return level;
+ lua_error(L, "invalid pattern capture");
+ return 0; /* to avoid warnings */
+}
+
+
+const char *luaI_classend (lua_State *L, const char *p) {
+ switch (*p++) {
+ case ESC:
+ if (*p == '\0') lua_error(L, "malformed pattern (ends with `%')");
+ return p+1;
+ case '[':
+ if (*p == '^') p++;
+ do { /* look for a ']' */
+ if (*p == '\0') lua_error(L, "malformed pattern (missing `]')");
+ if (*(p++) == ESC && *p != '\0') p++; /* skip escapes (e.g. '%]') */
+ } while (*p != ']');
+ return p+1;
+ default:
+ return p;
+ }
+}
+
+
+static int match_class (int c, int cl) {
+ int res;
+ switch (tolower(cl)) {
+ case 'a' : res = isalpha(c); break;
+ case 'c' : res = iscntrl(c); break;
+ case 'd' : res = isdigit(c); break;
+ case 'l' : res = islower(c); break;
+ case 'p' : res = ispunct(c); break;
+ case 's' : res = isspace(c); break;
+ case 'u' : res = isupper(c); break;
+ case 'w' : res = isalnum(c); break;
+ case 'x' : res = isxdigit(c); break;
+ case 'z' : res = (c == '\0'); break;
+ default: return (cl == c);
+ }
+ return (islower(cl) ? res : !res);
+}
+
+
+
+static int matchbracketclass (int c, const char *p, const char *endclass) {
+ int sig = 1;
+ if (*(p+1) == '^') {
+ sig = 0;
+ p++; /* skip the '^' */
+ }
+ while (++p < endclass) {
+ if (*p == ESC) {
+ p++;
+ if (match_class(c, (unsigned char)*p))
+ return sig;
+ }
+ else if ((*(p+1) == '-') && (p+2 < endclass)) {
+ p+=2;
+ if ((int)(unsigned char)*(p-2) <= c && c <= (int)(unsigned char)*p)
+ return sig;
+ }
+ else if ((int)(unsigned char)*p == c) return sig;
+ }
+ return !sig;
+}
+
+
+
+int luaI_singlematch (int c, const char *p, const char *ep) {
+ switch (*p) {
+ case '.': /* matches any char */
+ return 1;
+ case ESC:
+ return match_class(c, (unsigned char)*(p+1));
+ case '[':
+ return matchbracketclass(c, p, ep-1);
+ default:
+ return ((unsigned char)*p == c);
+ }
+}
+
+
+static const char *match (lua_State *L, const char *s, const char *p,
+ struct Capture *cap);
+
+
+static const char *matchbalance (lua_State *L, const char *s, const char *p,
+ struct Capture *cap) {
+ if (*p == 0 || *(p+1) == 0)
+ lua_error(L, "unbalanced pattern");
+ if (*s != *p) return NULL;
+ else {
+ int b = *p;
+ int e = *(p+1);
+ int cont = 1;
+ while (++s < cap->src_end) {
+ if (*s == e) {
+ if (--cont == 0) return s+1;
+ }
+ else if (*s == b) cont++;
+ }
+ }
+ return NULL; /* string ends out of balance */
+}
+
+
+static const char *max_expand (lua_State *L, const char *s, const char *p,
+ const char *ep, struct Capture *cap) {
+ long i = 0; /* counts maximum expand for item */
+ while ((s+i)<cap->src_end && luaI_singlematch((unsigned char)*(s+i), p, ep))
+ i++;
+ /* keeps trying to match with the maximum repetitions */
+ while (i>=0) {
+ const char *res = match(L, (s+i), ep+1, cap);
+ if (res) return res;
+ i--; /* else didn't match; reduce 1 repetition to try again */
+ }
+ return NULL;
+}
+
+
+static const char *min_expand (lua_State *L, const char *s, const char *p,
+ const char *ep, struct Capture *cap) {
+ for (;;) {
+ const char *res = match(L, s, ep+1, cap);
+ if (res != NULL)
+ return res;
+ else if (s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep))
+ s++; /* try with one more repetition */
+ else return NULL;
+ }
+}
+
+
+static const char *start_capture (lua_State *L, const char *s, const char *p,
+ struct Capture *cap) {
+ const char *res;
+ int level = cap->level;
+ if (level >= MAX_CAPTURES) lua_error(L, "too many captures");
+ cap->capture[level].init = s;
+ cap->capture[level].len = -1;
+ cap->level = level+1;
+ if ((res=match(L, s, p+1, cap)) == NULL) /* match failed? */
+ cap->level--; /* undo capture */
+ return res;
+}
+
+
+static const char *end_capture (lua_State *L, const char *s, const char *p,
+ struct Capture *cap) {
+ int l = capture_to_close(L, cap);
+ const char *res;
+ cap->capture[l].len = s - cap->capture[l].init; /* close capture */
+ if ((res = match(L, s, p+1, cap)) == NULL) /* match failed? */
+ cap->capture[l].len = -1; /* undo capture */
+ return res;
+}
+
+
+static const char *match_capture (lua_State *L, const char *s, int level,
+ struct Capture *cap) {
+ int l = check_capture(L, level, cap);
+ size_t len = cap->capture[l].len;
+ if ((size_t)(cap->src_end-s) >= len &&
+ memcmp(cap->capture[l].init, s, len) == 0)
+ return s+len;
+ else return NULL;
+}
+
+
+static const char *match (lua_State *L, const char *s, const char *p,
+ struct Capture *cap) {
+ init: /* using goto's to optimize tail recursion */
+ switch (*p) {
+ case '(': /* start capture */
+ return start_capture(L, s, p, cap);
+ case ')': /* end capture */
+ return end_capture(L, s, p, cap);
+ case ESC: /* may be %[0-9] or %b */
+ if (isdigit((unsigned char)(*(p+1)))) { /* capture? */
+ s = match_capture(L, s, *(p+1), cap);
+ if (s == NULL) return NULL;
+ p+=2; goto init; /* else return match(L, s, p+2, cap) */
+ }
+ else if (*(p+1) == 'b') { /* balanced string? */
+ s = matchbalance(L, s, p+2, cap);
+ if (s == NULL) return NULL;
+ p+=4; goto init; /* else return match(L, s, p+4, cap); */
+ }
+ else goto dflt; /* case default */
+ case '\0': /* end of pattern */
+ return s; /* match succeeded */
+ case '$':
+ if (*(p+1) == '\0') /* is the '$' the last char in pattern? */
+ return (s == cap->src_end) ? s : NULL; /* check end of string */
+ else goto dflt;
+ default: dflt: { /* it is a pattern item */
+ const char *ep = luaI_classend(L, p); /* points to what is next */
+ int m = s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep);
+ switch (*ep) {
+ case '?': { /* optional */
+ const char *res;
+ if (m && ((res=match(L, s+1, ep+1, cap)) != NULL))
+ return res;
+ p=ep+1; goto init; /* else return match(L, s, ep+1, cap); */
+ }
+ case '*': /* 0 or more repetitions */
+ return max_expand(L, s, p, ep, cap);
+ case '+': /* 1 or more repetitions */
+ return (m ? max_expand(L, s+1, p, ep, cap) : NULL);
+ case '-': /* 0 or more repetitions (minimum) */
+ return min_expand(L, s, p, ep, cap);
+ default:
+ if (!m) return NULL;
+ s++; p=ep; goto init; /* else return match(L, s+1, ep, cap); */
+ }
+ }
+ }
+}
+
+
+
+static const char *lmemfind (const char *s1, size_t l1,
+ const char *s2, size_t l2) {
+ if (l2 == 0) return s1; /* empty strings are everywhere */
+ else if (l2 > l1) return NULL; /* avoids a negative `l1' */
+ else {
+ const char *init; /* to search for a `*s2' inside `s1' */
+ l2--; /* 1st char will be checked by `memchr' */
+ l1 = l1-l2; /* `s2' cannot be found after that */
+ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
+ init++; /* 1st char is already checked */
+ if (memcmp(init, s2+1, l2) == 0)
+ return init-1;
+ else { /* correct `l1' and `s1' to try again */
+ l1 -= init-s1;
+ s1 = init;
+ }
+ }
+ return NULL; /* not found */
+ }
+}
+
+
+static int push_captures (lua_State *L, struct Capture *cap) {
+ int i;
+ luaL_checkstack(L, cap->level, "too many captures");
+ for (i=0; i<cap->level; i++) {
+ int l = cap->capture[i].len;
+ if (l == -1) lua_error(L, "unfinished capture");
+ lua_pushlstring(L, cap->capture[i].init, l);
+ }
+ return cap->level; /* number of strings pushed */
+}
+
+
+static int str_find (lua_State *L) {
+ size_t l1, l2;
+ const char *s = luaL_check_lstr(L, 1, &l1);
+ const char *p = luaL_check_lstr(L, 2, &l2);
+ long init = posrelat(luaL_opt_long(L, 3, 1), l1) - 1;
+ struct Capture cap;
+ luaL_arg_check(L, 0 <= init && (size_t)init <= l1, 3, "out of range");
+ if (lua_gettop(L) > 3 || /* extra argument? */
+ strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */
+ const char *s2 = lmemfind(s+init, l1-init, p, l2);
+ if (s2) {
+ lua_pushnumber(L, s2-s+1);
+ lua_pushnumber(L, s2-s+l2);
+ return 2;
+ }
+ }
+ else {
+ int anchor = (*p == '^') ? (p++, 1) : 0;
+ const char *s1=s+init;
+ cap.src_end = s+l1;
+ do {
+ const char *res;
+ cap.level = 0;
+ if ((res=match(L, s1, p, &cap)) != NULL) {
+ lua_pushnumber(L, s1-s+1); /* start */
+ lua_pushnumber(L, res-s); /* end */
+ return push_captures(L, &cap) + 2;
+ }
+ } while (s1++<cap.src_end && !anchor);
+ }
+ lua_pushnil(L); /* not found */
+ return 1;
+}
+
+
+static void add_s (lua_State *L, luaL_Buffer *b, struct Capture *cap) {
+ if (lua_isstring(L, 3)) {
+ const char *news = lua_tostring(L, 3);
+ size_t l = lua_strlen(L, 3);
+ size_t i;
+ for (i=0; i<l; i++) {
+ if (news[i] != ESC)
+ luaL_putchar(b, news[i]);
+ else {
+ i++; /* skip ESC */
+ if (!isdigit((unsigned char)news[i]))
+ luaL_putchar(b, news[i]);
+ else {
+ int level = check_capture(L, news[i], cap);
+ luaL_addlstring(b, cap->capture[level].init, cap->capture[level].len);
+ }
+ }
+ }
+ }
+ else { /* is a function */
+ int n;
+ lua_pushvalue(L, 3);
+ n = push_captures(L, cap);
+ lua_rawcall(L, n, 1);
+ if (lua_isstring(L, -1))
+ luaL_addvalue(b); /* add return to accumulated result */
+ else
+ lua_pop(L, 1); /* function result is not a string: pop it */
+ }
+}
+
+
+static int str_gsub (lua_State *L) {
+ size_t srcl;
+ const char *src = luaL_check_lstr(L, 1, &srcl);
+ const char *p = luaL_check_string(L, 2);
+ int max_s = luaL_opt_int(L, 4, srcl+1);
+ int anchor = (*p == '^') ? (p++, 1) : 0;
+ int n = 0;
+ struct Capture cap;
+ luaL_Buffer b;
+ luaL_arg_check(L,
+ lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)),
+ 3, "string or function expected");
+ luaL_buffinit(L, &b);
+ cap.src_end = src+srcl;
+ while (n < max_s) {
+ const char *e;
+ cap.level = 0;
+ e = match(L, src, p, &cap);
+ if (e) {
+ n++;
+ add_s(L, &b, &cap);
+ }
+ if (e && e>src) /* non empty match? */
+ src = e; /* skip it */
+ else if (src < cap.src_end)
+ luaL_putchar(&b, *src++);
+ else break;
+ if (anchor) break;
+ }
+ luaL_addlstring(&b, src, cap.src_end-src);
+ luaL_pushresult(&b);
+ lua_pushnumber(L, n); /* number of substitutions */
+ return 2;
+}
+
+/* }====================================================== */
+
+
+static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) {
+ size_t l;
+ const char *s = luaL_check_lstr(L, arg, &l);
+ luaL_putchar(b, '"');
+ while (l--) {
+ switch (*s) {
+ case '"': case '\\': case '\n':
+ luaL_putchar(b, '\\');
+ luaL_putchar(b, *s);
+ break;
+ case '\0': luaL_addlstring(b, "\\000", 4); break;
+ default: luaL_putchar(b, *s);
+ }
+ s++;
+ }
+ luaL_putchar(b, '"');
+}
+
+/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
+#define MAX_ITEM 512
+/* maximum size of each format specification (such as '%-099.99d') */
+#define MAX_FORMAT 20
+
+static int str_format (lua_State *L) {
+ int arg = 1;
+ const char *strfrmt = luaL_check_string(L, arg);
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ while (*strfrmt) {
+ if (*strfrmt != '%')
+ luaL_putchar(&b, *strfrmt++);
+ else if (*++strfrmt == '%')
+ luaL_putchar(&b, *strfrmt++); /* %% */
+ else { /* format item */
+ struct Capture cap;
+ char form[MAX_FORMAT]; /* to store the format ('%...') */
+ char buff[MAX_ITEM]; /* to store the formatted item */
+ const char *initf = strfrmt;
+ form[0] = '%';
+ if (isdigit((unsigned char)*initf) && *(initf+1) == '$') {
+ arg = *initf - '0';
+ initf += 2; /* skip the 'n$' */
+ }
+ arg++;
+ cap.src_end = strfrmt+strlen(strfrmt)+1;
+ cap.level = 0;
+ strfrmt = match(L, initf, "[-+ #0]*(%d*)%.?(%d*)", &cap);
+ if (cap.capture[0].len > 2 || cap.capture[1].len > 2 || /* < 100? */
+ strfrmt-initf > MAX_FORMAT-2)
+ lua_error(L, "invalid format (width or precision too long)");
+ strncpy(form+1, initf, strfrmt-initf+1); /* +1 to include conversion */
+ form[strfrmt-initf+2] = 0;
+ switch (*strfrmt++) {
+ case 'c': case 'd': case 'i':
+ sprintf(buff, form, luaL_check_int(L, arg));
+ break;
+ case 'o': case 'u': case 'x': case 'X':
+ sprintf(buff, form, (unsigned int)luaL_check_number(L, arg));
+ break;
+ case 'e': case 'E': case 'f': case 'g': case 'G':
+ sprintf(buff, form, luaL_check_number(L, arg));
+ break;
+ case 'q':
+ luaI_addquoted(L, &b, arg);
+ continue; /* skip the "addsize" at the end */
+ case 's': {
+ size_t l;
+ const char *s = luaL_check_lstr(L, arg, &l);
+ if (cap.capture[1].len == 0 && l >= 100) {
+ /* no precision and string is too long to be formatted;
+ keep original string */
+ lua_pushvalue(L, arg);
+ luaL_addvalue(&b);
+ continue; /* skip the "addsize" at the end */
+ }
+ else {
+ sprintf(buff, form, s);
+ break;
+ }
+ }
+ default: /* also treat cases 'pnLlh' */
+ lua_error(L, "invalid option in `format'");
+ }
+ luaL_addlstring(&b, buff, strlen(buff));
+ }
+ }
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+static const struct luaL_reg strlib[] = {
+{"strlen", str_len},
+{"strsub", str_sub},
+{"strlower", str_lower},
+{"strupper", str_upper},
+{"strchar", str_char},
+{"strrep", str_rep},
+{"ascii", str_byte}, /* for compatibility with 3.0 and earlier */
+{"strbyte", str_byte},
+{"format", str_format},
+{"strfind", str_find},
+{"gsub", str_gsub}
+};
+
+
+/*
+** Open string library
+*/
+LUALIB_API void lua_strlibopen (lua_State *L) {
+ luaL_openl(L, strlib);
+}
diff --git a/src/lua/ltable.c b/src/lua/ltable.c
new file mode 100644
index 00000000..1e3eb4f5
--- /dev/null
+++ b/src/lua/ltable.c
@@ -0,0 +1,303 @@
+/*
+** $Id: ltable.c,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** Lua tables (hash)
+** See Copyright Notice in lua.h
+*/
+
+
+/*
+** Implementation of tables (aka arrays, objects, or hash tables);
+** uses a mix of chained scatter table with Brent's variation.
+** A main invariant of these tables is that, if an element is not
+** in its main position (i.e. the `original' position that its hash gives
+** to it), then the colliding element is in its own main position.
+** In other words, there are collisions only when two elements have the
+** same main position (i.e. the same hash values for that table size).
+** Because of that, the load factor of these tables can be 100% without
+** performance penalties.
+*/
+
+
+#include "lua.h"
+
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+
+
+#define gcsize(L, n) (sizeof(Hash)+(n)*sizeof(Node))
+
+
+
+#define TagDefault LUA_TTABLE
+
+
+
+/*
+** returns the `main' position of an element in a table (that is, the index
+** of its hash value)
+*/
+Node *luaH_mainposition (const Hash *t, const TObject *key) {
+ unsigned long h;
+ switch (ttype(key)) {
+ case LUA_TNUMBER:
+ h = (unsigned long)(long)nvalue(key);
+ break;
+ case LUA_TSTRING:
+ h = tsvalue(key)->u.s.hash;
+ break;
+ case LUA_TUSERDATA:
+ h = IntPoint(tsvalue(key));
+ break;
+ case LUA_TTABLE:
+ h = IntPoint(hvalue(key));
+ break;
+ case LUA_TFUNCTION:
+ h = IntPoint(clvalue(key));
+ break;
+ default:
+ return NULL; /* invalid key */
+ }
+ LUA_ASSERT(h%(unsigned int)t->size == (h&((unsigned int)t->size-1)),
+ "a&(x-1) == a%x, for x power of 2");
+ return &t->node[h&(t->size-1)];
+}
+
+
+static const TObject *luaH_getany (lua_State *L, const Hash *t,
+ const TObject *key) {
+ Node *n = luaH_mainposition(t, key);
+ if (!n)
+ lua_error(L, "table index is nil");
+ else do {
+ if (luaO_equalObj(key, &n->key))
+ return &n->val;
+ n = n->next;
+ } while (n);
+ return &luaO_nilobject; /* key not found */
+}
+
+
+/* specialized version for numbers */
+const TObject *luaH_getnum (const Hash *t, Number key) {
+ Node *n = &t->node[(unsigned long)(long)key&(t->size-1)];
+ do {
+ if (ttype(&n->key) == LUA_TNUMBER && nvalue(&n->key) == key)
+ return &n->val;
+ n = n->next;
+ } while (n);
+ return &luaO_nilobject; /* key not found */
+}
+
+
+/* specialized version for strings */
+const TObject *luaH_getstr (const Hash *t, TString *key) {
+ Node *n = &t->node[key->u.s.hash&(t->size-1)];
+ do {
+ if (ttype(&n->key) == LUA_TSTRING && tsvalue(&n->key) == key)
+ return &n->val;
+ n = n->next;
+ } while (n);
+ return &luaO_nilobject; /* key not found */
+}
+
+
+const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key) {
+ switch (ttype(key)) {
+ case LUA_TNUMBER: return luaH_getnum(t, nvalue(key));
+ case LUA_TSTRING: return luaH_getstr(t, tsvalue(key));
+ default: return luaH_getany(L, t, key);
+ }
+}
+
+
+Node *luaH_next (lua_State *L, const Hash *t, const TObject *key) {
+ int i;
+ if (ttype(key) == LUA_TNIL)
+ i = 0; /* first iteration */
+ else {
+ const TObject *v = luaH_get(L, t, key);
+ if (v == &luaO_nilobject)
+ lua_error(L, "invalid key for `next'");
+ i = (int)(((const char *)v -
+ (const char *)(&t->node[0].val)) / sizeof(Node)) + 1;
+ }
+ for (; i<t->size; i++) {
+ Node *n = node(t, i);
+ if (ttype(val(n)) != LUA_TNIL)
+ return n;
+ }
+ return NULL; /* no more elements */
+}
+
+
+/*
+** try to remove a key without value from a table. To avoid problems with
+** hash, change `key' for a number with the same hash.
+*/
+void luaH_remove (Hash *t, TObject *key) {
+ if (ttype(key) == LUA_TNUMBER ||
+ (ttype(key) == LUA_TSTRING && tsvalue(key)->len <= 30))
+ return; /* do not remove numbers nor small strings */
+ else {
+ /* try to find a number `n' with the same hash as `key' */
+ Node *mp = luaH_mainposition(t, key);
+ int n = mp - &t->node[0];
+ /* make sure `n' is not in `t' */
+ while (luaH_getnum(t, n) != &luaO_nilobject) {
+ if (n >= MAX_INT - t->size)
+ return; /* give up; (to avoid overflow) */
+ n += t->size;
+ }
+ ttype(key) = LUA_TNUMBER;
+ nvalue(key) = n;
+ LUA_ASSERT(luaH_mainposition(t, key) == mp, "cannot change hash");
+ }
+}
+
+
+static void setnodevector (lua_State *L, Hash *t, lint32 size) {
+ int i;
+ if (size > MAX_INT)
+ lua_error(L, "table overflow");
+ t->node = luaM_newvector(L, size, Node);
+ for (i=0; i<(int)size; i++) {
+ ttype(&t->node[i].key) = ttype(&t->node[i].val) = LUA_TNIL;
+ t->node[i].next = NULL;
+ }
+ L->nblocks += gcsize(L, size) - gcsize(L, t->size);
+ t->size = size;
+ t->firstfree = &t->node[size-1]; /* first free position to be used */
+}
+
+
+Hash *luaH_new (lua_State *L, int size) {
+ Hash *t = luaM_new(L, Hash);
+ t->htag = TagDefault;
+ t->next = L->roottable;
+ L->roottable = t;
+ t->mark = t;
+ t->size = 0;
+ L->nblocks += gcsize(L, 0);
+ t->node = NULL;
+ setnodevector(L, t, luaO_power2(size));
+ return t;
+}
+
+
+void luaH_free (lua_State *L, Hash *t) {
+ L->nblocks -= gcsize(L, t->size);
+ luaM_free(L, t->node);
+ luaM_free(L, t);
+}
+
+
+static int numuse (const Hash *t) {
+ Node *v = t->node;
+ int size = t->size;
+ int realuse = 0;
+ int i;
+ for (i=0; i<size; i++) {
+ if (ttype(&v[i].val) != LUA_TNIL)
+ realuse++;
+ }
+ return realuse;
+}
+
+
+static void rehash (lua_State *L, Hash *t) {
+ int oldsize = t->size;
+ Node *nold = t->node;
+ int nelems = numuse(t);
+ int i;
+ LUA_ASSERT(nelems<=oldsize, "wrong count");
+ if (nelems >= oldsize-oldsize/4) /* using more than 3/4? */
+ setnodevector(L, t, (lint32)oldsize*2);
+ else if (nelems <= oldsize/4 && /* less than 1/4? */
+ oldsize > MINPOWER2)
+ setnodevector(L, t, oldsize/2);
+ else
+ setnodevector(L, t, oldsize);
+ for (i=0; i<oldsize; i++) {
+ Node *old = nold+i;
+ if (ttype(&old->val) != LUA_TNIL)
+ *luaH_set(L, t, &old->key) = old->val;
+ }
+ luaM_free(L, nold); /* free old array */
+}
+
+
+/*
+** inserts a key into a hash table; first, check whether key is
+** already present; if not, check whether key's main position is free;
+** if not, check whether colliding node is in its main position or not;
+** if it is not, move colliding node to an empty place and put new key
+** in its main position; otherwise (colliding node is in its main position),
+** new key goes to an empty position.
+*/
+TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) {
+ Node *mp = luaH_mainposition(t, key);
+ Node *n = mp;
+ if (!mp)
+ lua_error(L, "table index is nil");
+ do { /* check whether `key' is somewhere in the chain */
+ if (luaO_equalObj(key, &n->key))
+ return &n->val; /* that's all */
+ else n = n->next;
+ } while (n);
+ /* `key' not found; must insert it */
+ if (ttype(&mp->key) != LUA_TNIL) { /* main position is not free? */
+ Node *othern; /* main position of colliding node */
+ n = t->firstfree; /* get a free place */
+ /* is colliding node out of its main position? (can only happens if
+ its position is after "firstfree") */
+ if (mp > n && (othern=luaH_mainposition(t, &mp->key)) != mp) {
+ /* yes; move colliding node into free position */
+ while (othern->next != mp) othern = othern->next; /* find previous */
+ othern->next = n; /* redo the chain with `n' in place of `mp' */
+ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
+ mp->next = NULL; /* now `mp' is free */
+ }
+ else { /* colliding node is in its own main position */
+ /* new node will go into free position */
+ n->next = mp->next; /* chain new position */
+ mp->next = n;
+ mp = n;
+ }
+ }
+ mp->key = *key;
+ for (;;) { /* correct `firstfree' */
+ if (ttype(&t->firstfree->key) == LUA_TNIL)
+ return &mp->val; /* OK; table still has a free place */
+ else if (t->firstfree == t->node) break; /* cannot decrement from here */
+ else (t->firstfree)--;
+ }
+ rehash(L, t); /* no more free places */
+ return luaH_set(L, t, key); /* `rehash' invalidates this insertion */
+}
+
+
+TObject *luaH_setint (lua_State *L, Hash *t, int key) {
+ TObject index;
+ ttype(&index) = LUA_TNUMBER;
+ nvalue(&index) = key;
+ return luaH_set(L, t, &index);
+}
+
+
+void luaH_setstrnum (lua_State *L, Hash *t, TString *key, Number val) {
+ TObject *value, index;
+ ttype(&index) = LUA_TSTRING;
+ tsvalue(&index) = key;
+ value = luaH_set(L, t, &index);
+ ttype(value) = LUA_TNUMBER;
+ nvalue(value) = val;
+}
+
+
+const TObject *luaH_getglobal (lua_State *L, const char *name) {
+ return luaH_getstr(L->gt, luaS_new(L, name));
+}
+
diff --git a/src/lua/ltable.h b/src/lua/ltable.h
new file mode 100644
index 00000000..3bc2a5df
--- /dev/null
+++ b/src/lua/ltable.h
@@ -0,0 +1,34 @@
+/*
+** $Id: ltable.h,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** Lua tables (hash)
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ltable_h
+#define ltable_h
+
+#include "lobject.h"
+
+
+#define node(t,i) (&(t)->node[i])
+#define key(n) (&(n)->key)
+#define val(n) (&(n)->val)
+
+Hash *luaH_new (lua_State *L, int nhash);
+void luaH_free (lua_State *L, Hash *t);
+const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key);
+const TObject *luaH_getnum (const Hash *t, Number key);
+const TObject *luaH_getstr (const Hash *t, TString *key);
+void luaH_remove (Hash *t, TObject *key);
+TObject *luaH_set (lua_State *L, Hash *t, const TObject *key);
+Node * luaH_next (lua_State *L, const Hash *t, const TObject *r);
+TObject *luaH_setint (lua_State *L, Hash *t, int key);
+void luaH_setstrnum (lua_State *L, Hash *t, TString *key, Number val);
+unsigned long luaH_hash (lua_State *L, const TObject *key);
+const TObject *luaH_getglobal (lua_State *L, const char *name);
+
+/* exported only for debugging */
+Node *luaH_mainposition (const Hash *t, const TObject *key);
+
+
+#endif
diff --git a/src/lua/ltests.c b/src/lua/ltests.c
new file mode 100644
index 00000000..06e08f5a
--- /dev/null
+++ b/src/lua/ltests.c
@@ -0,0 +1,543 @@
+/*
+** $Id: ltests.c,v 1.2 2001/11/26 23:00:26 darkgod Exp $
+** Internal Module for Debugging of the Lua Implementation
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lauxlib.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "luadebug.h"
+#include "lualib.h"
+
+
+void luaB_opentests (lua_State *L);
+
+
+/*
+** The whole module only makes sense with LUA_DEBUG on
+*/
+#ifdef LUA_DEBUG
+
+
+
+static void setnameval (lua_State *L, const char *name, int val) {
+ lua_pushstring(L, name);
+ lua_pushnumber(L, val);
+ lua_settable(L, -3);
+}
+
+
+/*
+** {======================================================
+** Disassembler
+** =======================================================
+*/
+
+
+static const char *const instrname[NUM_OPCODES] = {
+ "END", "RETURN", "CALL", "TAILCALL", "PUSHNIL", "POP", "PUSHINT",
+ "PUSHSTRING", "PUSHNUM", "PUSHNEGNUM", "PUSHUPVALUE", "GETLOCAL",
+ "GETGLOBAL", "GETTABLE", "GETDOTTED", "GETINDEXED", "PUSHSELF",
+ "CREATETABLE", "SETLOCAL", "SETGLOBAL", "SETTABLE", "SETLIST", "SETMAP",
+ "ADD", "ADDI", "SUB", "MULT", "DIV", "POW", "CONCAT", "MINUS", "NOT",
+ "JMPNE", "JMPEQ", "JMPLT", "JMPLE", "JMPGT", "JMPGE", "JMPT", "JMPF",
+ "JMPONT", "JMPONF", "JMP", "PUSHNILJMP", "FORPREP", "FORLOOP", "LFORPREP",
+ "LFORLOOP", "CLOSURE"
+};
+
+
+static int pushop (lua_State *L, Proto *p, int pc) {
+ char buff[100];
+ Instruction i = p->code[pc];
+ OpCode o = GET_OPCODE(i);
+ const char *name = instrname[o];
+ sprintf(buff, "%5d - ", luaG_getline(p->lineinfo, pc, 1, NULL));
+ switch ((enum Mode)luaK_opproperties[o].mode) {
+ case iO:
+ sprintf(buff+8, "%-12s", name);
+ break;
+ case iU:
+ sprintf(buff+8, "%-12s%4u", name, GETARG_U(i));
+ break;
+ case iS:
+ sprintf(buff+8, "%-12s%4d", name, GETARG_S(i));
+ break;
+ case iAB:
+ sprintf(buff+8, "%-12s%4d %4d", name, GETARG_A(i), GETARG_B(i));
+ break;
+ }
+ lua_pushstring(L, buff);
+ return (o != OP_END);
+}
+
+
+static int listcode (lua_State *L) {
+ int pc;
+ Proto *p;
+ int res;
+ luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(luaA_index(L, 1))->f.l;
+ lua_newtable(L);
+ setnameval(L, "maxstack", p->maxstacksize);
+ setnameval(L, "numparams", p->numparams);
+ pc = 0;
+ do {
+ lua_pushnumber(L, pc+1);
+ res = pushop(L, p, pc++);
+ lua_settable(L, -3);
+ } while (res);
+ return 1;
+}
+
+
+static int liststrings (lua_State *L) {
+ Proto *p;
+ int i;
+ luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(luaA_index(L, 1))->f.l;
+ lua_newtable(L);
+ for (i=0; i<p->nkstr; i++) {
+ lua_pushnumber(L, i+1);
+ lua_pushstring(L, p->kstr[i]->str);
+ lua_settable(L, -3);
+ }
+ return 1;
+}
+
+
+static int listlocals (lua_State *L) {
+ Proto *p;
+ int pc = luaL_check_int(L, 2) - 1;
+ int i = 0;
+ const char *name;
+ luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(luaA_index(L, 1))->f.l;
+ while ((name = luaF_getlocalname(p, ++i, pc)) != NULL)
+ lua_pushstring(L, name);
+ return i-1;
+}
+
+/* }====================================================== */
+
+
+
+static int get_limits (lua_State *L) {
+ lua_newtable(L);
+ setnameval(L, "BITS_INT", BITS_INT);
+ setnameval(L, "LFPF", LFIELDS_PER_FLUSH);
+ setnameval(L, "MAXARG_A", MAXARG_A);
+ setnameval(L, "MAXARG_B", MAXARG_B);
+ setnameval(L, "MAXARG_S", MAXARG_S);
+ setnameval(L, "MAXARG_U", MAXARG_U);
+ setnameval(L, "MAXLOCALS", MAXLOCALS);
+ setnameval(L, "MAXPARAMS", MAXPARAMS);
+ setnameval(L, "MAXSTACK", MAXSTACK);
+ setnameval(L, "MAXUPVALUES", MAXUPVALUES);
+ setnameval(L, "MAXVARSLH", MAXVARSLH);
+ setnameval(L, "RFPF", RFIELDS_PER_FLUSH);
+ setnameval(L, "SIZE_A", SIZE_A);
+ setnameval(L, "SIZE_B", SIZE_B);
+ setnameval(L, "SIZE_OP", SIZE_OP);
+ setnameval(L, "SIZE_U", SIZE_U);
+ return 1;
+}
+
+
+static int mem_query (lua_State *L) {
+ if (lua_isnull(L, 1)) {
+ lua_pushnumber(L, memdebug_total);
+ lua_pushnumber(L, memdebug_numblocks);
+ lua_pushnumber(L, memdebug_maxmem);
+ return 3;
+ }
+ else {
+ memdebug_memlimit = luaL_check_int(L, 1);
+ return 0;
+ }
+}
+
+
+static int hash_query (lua_State *L) {
+ if (lua_isnull(L, 2)) {
+ luaL_arg_check(L, lua_tag(L, 1) == LUA_TSTRING, 1, "string expected");
+ lua_pushnumber(L, tsvalue(luaA_index(L, 1))->u.s.hash);
+ }
+ else {
+ Hash *t;
+ luaL_checktype(L, 2, LUA_TTABLE);
+ t = hvalue(luaA_index(L, 2));
+ lua_pushnumber(L, luaH_mainposition(t, luaA_index(L, 1)) - t->node);
+ }
+ return 1;
+}
+
+
+static int table_query (lua_State *L) {
+ const Hash *t;
+ int i = luaL_opt_int(L, 2, -1);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ t = hvalue(luaA_index(L, 1));
+ if (i == -1) {
+ lua_pushnumber(L, t->size);
+ lua_pushnumber(L, t->firstfree - t->node);
+ return 2;
+ }
+ else if (i < t->size) {
+ luaA_pushobject(L, &t->node[i].key);
+ luaA_pushobject(L, &t->node[i].val);
+ if (t->node[i].next) {
+ lua_pushnumber(L, t->node[i].next - t->node);
+ return 3;
+ }
+ else
+ return 2;
+ }
+ return 0;
+}
+
+
+static int string_query (lua_State *L) {
+ stringtable *tb = (*luaL_check_string(L, 1) == 's') ? &L->strt : &L->udt;
+ int s = luaL_opt_int(L, 2, 0) - 1;
+ if (s==-1) {
+ lua_pushnumber(L ,tb->nuse);
+ lua_pushnumber(L ,tb->size);
+ return 2;
+ }
+ else if (s < tb->size) {
+ TString *ts;
+ int n = 0;
+ for (ts = tb->hash[s]; ts; ts = ts->nexthash) {
+ ttype(L->top) = LUA_TSTRING;
+ tsvalue(L->top) = ts;
+ incr_top;
+ n++;
+ }
+ return n;
+ }
+ return 0;
+}
+
+
+static int tref (lua_State *L) {
+ luaL_checkany(L, 1);
+ lua_pushvalue(L, 1);
+ lua_pushnumber(L, lua_ref(L, luaL_opt_int(L, 2, 1)));
+ return 1;
+}
+
+static int getref (lua_State *L) {
+ if (lua_getref(L, luaL_check_int(L, 1)))
+ return 1;
+ else
+ return 0;
+}
+
+static int unref (lua_State *L) {
+ lua_unref(L, luaL_check_int(L, 1));
+ return 0;
+}
+
+static int newuserdata (lua_State *L) {
+ if (lua_isnumber(L, 2))
+ lua_pushusertag(L, (void *)luaL_check_int(L, 1), luaL_check_int(L, 2));
+ else
+ lua_newuserdata(L, luaL_check_int(L, 1));
+ return 1;
+}
+
+static int udataval (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ lua_pushnumber(L, (int)lua_touserdata(L, 1));
+ return 1;
+}
+
+static int newstate (lua_State *L) {
+ lua_State *L1 = lua_open(luaL_check_int(L, 1));
+ if (L1)
+ lua_pushuserdata(L, L1);
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+static int loadlib (lua_State *L) {
+ lua_State *L1 = (lua_State *)lua_touserdata(L, 1);
+ switch (*luaL_check_string(L, 2)) {
+ case 'm': lua_mathlibopen(L1); break;
+ case 's': lua_strlibopen(L1); break;
+ case 'i': lua_iolibopen(L1); break;
+ case 'd': lua_dblibopen(L1); break;
+ case 'b': lua_baselibopen(L1); break;
+ default: luaL_argerror(L, 2, "invalid option");
+ }
+ return 0;
+}
+
+static int closestate (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ lua_close((lua_State *)lua_touserdata(L, 1));
+ return 0;
+}
+
+static int doremote (lua_State *L) {
+ lua_State *L1;
+ const char *code = luaL_check_string(L, 2);
+ int status;
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ L1 = (lua_State *)lua_touserdata(L, 1);
+ status = lua_dostring(L1, code);
+ if (status != 0) {
+ lua_pushnil(L);
+ lua_pushnumber(L, status);
+ return 2;
+ }
+ else {
+ int i = 0;
+ while (!lua_isnull(L1, ++i))
+ lua_pushstring(L, lua_tostring(L1, i));
+ return i-1;
+ }
+}
+
+static int settagmethod (lua_State *L) {
+ int tag = luaL_check_int(L, 1);
+ const char *event = luaL_check_string(L, 2);
+ luaL_checkany(L, 3);
+ lua_gettagmethod(L, tag, event);
+ lua_pushvalue(L, 3);
+ lua_settagmethod(L, tag, event);
+ return 1;
+}
+
+static int pushbool (lua_State *L, int b) {
+ if (b) lua_pushnumber(L, 1);
+ else lua_pushnil(L);
+ return 1;
+}
+
+static int equal (lua_State *L) {
+ return pushbool(L, lua_equal(L, 1, 2));
+}
+
+
+
+/*
+** {======================================================
+** function to test the API with C. It interprets a kind of "assembler"
+** language with calls to the API, so the test can be driven by Lua code
+** =======================================================
+*/
+
+static const char *const delimits = " \t\n,;";
+
+static void skip (const char **pc) {
+ while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++;
+}
+
+static int getnum (lua_State *L, const char **pc) {
+ int res = 0;
+ int sig = 1;
+ skip(pc);
+ if (**pc == '.') {
+ res = (int)lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ (*pc)++;
+ return res;
+ }
+ else if (**pc == '-') {
+ sig = -1;
+ (*pc)++;
+ }
+ while (isdigit(**pc)) res = res*10 + (*(*pc)++) - '0';
+ return sig*res;
+}
+
+static const char *getname (char *buff, const char **pc) {
+ int i = 0;
+ skip(pc);
+ while (**pc != '\0' && !strchr(delimits, **pc))
+ buff[i++] = *(*pc)++;
+ buff[i] = '\0';
+ return buff;
+}
+
+
+#define EQ(s1) (strcmp(s1, inst) == 0)
+
+#define getnum ((getnum)(L, &pc))
+#define getname ((getname)(buff, &pc))
+
+
+static int testC (lua_State *L) {
+ char buff[30];
+ const char *pc = luaL_check_string(L, 1);
+ for (;;) {
+ const char *inst = getname;
+ if EQ("") return 0;
+ else if EQ("isnumber") {
+ lua_pushnumber(L, lua_isnumber(L, getnum));
+ }
+ else if EQ("isstring") {
+ lua_pushnumber(L, lua_isstring(L, getnum));
+ }
+ else if EQ("istable") {
+ lua_pushnumber(L, lua_istable(L, getnum));
+ }
+ else if EQ("iscfunction") {
+ lua_pushnumber(L, lua_iscfunction(L, getnum));
+ }
+ else if EQ("isfunction") {
+ lua_pushnumber(L, lua_isfunction(L, getnum));
+ }
+ else if EQ("isuserdata") {
+ lua_pushnumber(L, lua_isuserdata(L, getnum));
+ }
+ else if EQ("isnil") {
+ lua_pushnumber(L, lua_isnil(L, getnum));
+ }
+ else if EQ("isnull") {
+ lua_pushnumber(L, lua_isnull(L, getnum));
+ }
+ else if EQ("tonumber") {
+ lua_pushnumber(L, lua_tonumber(L, getnum));
+ }
+ else if EQ("tostring") {
+ lua_pushstring(L, lua_tostring(L, getnum));
+ }
+ else if EQ("tonumber") {
+ lua_pushnumber(L, lua_tonumber(L, getnum));
+ }
+ else if EQ("strlen") {
+ lua_pushnumber(L, lua_strlen(L, getnum));
+ }
+ else if EQ("tocfunction") {
+ lua_pushcfunction(L, lua_tocfunction(L, getnum));
+ }
+ else if EQ("return") {
+ return getnum;
+ }
+ else if EQ("gettop") {
+ lua_pushnumber(L, lua_gettop(L));
+ }
+ else if EQ("settop") {
+ lua_settop(L, getnum);
+ }
+ else if EQ("pop") {
+ lua_pop(L, getnum);
+ }
+ else if EQ("pushnum") {
+ lua_pushnumber(L, getnum);
+ }
+ else if EQ("pushvalue") {
+ lua_pushvalue(L, getnum);
+ }
+ else if EQ("remove") {
+ lua_remove(L, getnum);
+ }
+ else if EQ("insert") {
+ lua_insert(L, getnum);
+ }
+ else if EQ("gettable") {
+ lua_gettable(L, getnum);
+ }
+ else if EQ("settable") {
+ lua_settable(L, getnum);
+ }
+ else if EQ("next") {
+ lua_next(L, -2);
+ }
+ else if EQ("concat") {
+ lua_concat(L, getnum);
+ }
+ else if EQ("rawcall") {
+ int narg = getnum;
+ int nres = getnum;
+ lua_rawcall(L, narg, nres);
+ }
+ else if EQ("call") {
+ int narg = getnum;
+ int nres = getnum;
+ lua_call(L, narg, nres);
+ }
+ else if EQ("dostring") {
+ lua_dostring(L, luaL_check_string(L, getnum));
+ }
+ else if EQ("settagmethod") {
+ int tag = getnum;
+ const char *event = getname;
+ lua_settagmethod(L, tag, event);
+ }
+ else if EQ("gettagmethod") {
+ int tag = getnum;
+ const char *event = getname;
+ lua_gettagmethod(L, tag, event);
+ }
+ else if EQ("type") {
+ lua_pushstring(L, lua_typename(L, lua_type(L, getnum)));
+ }
+ else luaL_verror(L, "unknown instruction %.30s", buff);
+ }
+ return 0;
+}
+
+/* }====================================================== */
+
+
+
+static const struct luaL_reg tests_funcs[] = {
+ {"hash", hash_query},
+ {"limits", get_limits},
+ {"listcode", listcode},
+ {"liststrings", liststrings},
+ {"listlocals", listlocals},
+ {"loadlib", loadlib},
+ {"querystr", string_query},
+ {"querytab", table_query},
+ {"testC", testC},
+ {"ref", tref},
+ {"getref", getref},
+ {"unref", unref},
+ {"newuserdata", newuserdata},
+ {"udataval", udataval},
+ {"newstate", newstate},
+ {"closestate", closestate},
+ {"doremote", doremote},
+ {"settagmethod", settagmethod},
+ {"equal", equal},
+ {"totalmem", mem_query}
+};
+
+
+void luaB_opentests (lua_State *L) {
+ lua_newtable(L);
+ lua_getglobals(L);
+ lua_pushvalue(L, -2);
+ lua_setglobals(L);
+ luaL_openl(L, tests_funcs); /* open functions inside new table */
+ lua_setglobals(L); /* restore old table of globals */
+ lua_setglobal(L, "T"); /* set new table as global T */
+}
+
+#endif
diff --git a/src/lua/ltm.c b/src/lua/ltm.c
new file mode 100644
index 00000000..3f69a6ca
--- /dev/null
+++ b/src/lua/ltm.c
@@ -0,0 +1,163 @@
+/*
+** $Id: ltm.c,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** Tag methods
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "ltm.h"
+
+
+const char *const luaT_eventname[] = { /* ORDER TM */
+ "gettable", "settable", "index", "getglobal", "setglobal", "add", "sub",
+ "mul", "div", "pow", "unm", "lt", "concat", "gc", "function",
+ "le", "gt", "ge", /* deprecated options!! */
+ NULL
+};
+
+
+static int findevent (const char *name) {
+ int i;
+ for (i=0; luaT_eventname[i]; i++)
+ if (strcmp(luaT_eventname[i], name) == 0)
+ return i;
+ return -1; /* name not found */
+}
+
+
+static int luaI_checkevent (lua_State *L, const char *name, int t) {
+ int e = findevent(name);
+ if (e >= TM_N)
+ luaO_verror(L, "event `%.50s' is deprecated", name);
+ if (e == TM_GC && t == LUA_TTABLE)
+ luaO_verror(L, "event `gc' for tables is deprecated");
+ if (e < 0)
+ luaO_verror(L, "`%.50s' is not a valid event name", name);
+ return e;
+}
+
+
+
+/* events in LUA_TNIL are all allowed, since this is used as a
+* 'placeholder' for "default" fallbacks
+*/
+/* ORDER LUA_T, ORDER TM */
+static const char luaT_validevents[NUM_TAGS][TM_N] = {
+ {1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TUSERDATA */
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_TNIL */
+ {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, /* LUA_TNUMBER */
+ {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_TSTRING */
+ {0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TTABLE */
+ {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0} /* LUA_TFUNCTION */
+};
+
+int luaT_validevent (int t, int e) { /* ORDER LUA_T */
+ return (t >= NUM_TAGS) ? 1 : luaT_validevents[t][e];
+}
+
+
+static void init_entry (lua_State *L, int tag) {
+ int i;
+ for (i=0; i<TM_N; i++)
+ luaT_gettm(L, tag, i) = NULL;
+ L->TMtable[tag].collected = NULL;
+}
+
+
+void luaT_init (lua_State *L) {
+ int t;
+ luaM_growvector(L, L->TMtable, 0, NUM_TAGS, struct TM, "", MAX_INT);
+ L->nblocks += NUM_TAGS*sizeof(struct TM);
+ L->last_tag = NUM_TAGS-1;
+ for (t=0; t<=L->last_tag; t++)
+ init_entry(L, t);
+}
+
+
+LUA_API int lua_newtag (lua_State *L) {
+ luaM_growvector(L, L->TMtable, L->last_tag, 1, struct TM,
+ "tag table overflow", MAX_INT);
+ L->nblocks += sizeof(struct TM);
+ L->last_tag++;
+ init_entry(L, L->last_tag);
+ return L->last_tag;
+}
+
+
+static void checktag (lua_State *L, int tag) {
+ if (!(0 <= tag && tag <= L->last_tag))
+ luaO_verror(L, "%d is not a valid tag", tag);
+}
+
+void luaT_realtag (lua_State *L, int tag) {
+ if (!validtag(tag))
+ luaO_verror(L, "tag %d was not created by `newtag'", tag);
+}
+
+
+LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom) {
+ int e;
+ checktag(L, tagto);
+ checktag(L, tagfrom);
+ for (e=0; e<TM_N; e++) {
+ if (luaT_validevent(tagto, e))
+ luaT_gettm(L, tagto, e) = luaT_gettm(L, tagfrom, e);
+ }
+ return tagto;
+}
+
+
+int luaT_tag (const TObject *o) {
+ int t = ttype(o);
+ switch (t) {
+ case LUA_TUSERDATA: return tsvalue(o)->u.d.tag;
+ case LUA_TTABLE: return hvalue(o)->htag;
+ default: return t;
+ }
+}
+
+
+LUA_API void lua_gettagmethod (lua_State *L, int t, const char *event) {
+ int e;
+ e = luaI_checkevent(L, event, t);
+ checktag(L, t);
+ if (luaT_validevent(t, e) && luaT_gettm(L, t, e)) {
+ clvalue(L->top) = luaT_gettm(L, t, e);
+ ttype(L->top) = LUA_TFUNCTION;
+ }
+ else
+ ttype(L->top) = LUA_TNIL;
+ incr_top;
+}
+
+
+LUA_API void lua_settagmethod (lua_State *L, int t, const char *event) {
+ int e = luaI_checkevent(L, event, t);
+ checktag(L, t);
+ if (!luaT_validevent(t, e))
+ luaO_verror(L, "cannot change `%.20s' tag method for type `%.20s'%.20s",
+ luaT_eventname[e], luaO_typenames[t],
+ (t == LUA_TTABLE || t == LUA_TUSERDATA) ?
+ " with default tag" : "");
+ switch (ttype(L->top - 1)) {
+ case LUA_TNIL:
+ luaT_gettm(L, t, e) = NULL;
+ break;
+ case LUA_TFUNCTION:
+ luaT_gettm(L, t, e) = clvalue(L->top - 1);
+ break;
+ default:
+ lua_error(L, "tag method must be a function (or nil)");
+ }
+ L->top--;
+}
+
diff --git a/src/lua/ltm.h b/src/lua/ltm.h
new file mode 100644
index 00000000..f6be13ed
--- /dev/null
+++ b/src/lua/ltm.h
@@ -0,0 +1,59 @@
+/*
+** $Id: ltm.h,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** Tag methods
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ltm_h
+#define ltm_h
+
+
+#include "lobject.h"
+#include "lstate.h"
+
+/*
+* WARNING: if you change the order of this enumeration,
+* grep "ORDER TM"
+*/
+typedef enum {
+ TM_GETTABLE = 0,
+ TM_SETTABLE,
+ TM_INDEX,
+ TM_GETGLOBAL,
+ TM_SETGLOBAL,
+ TM_ADD,
+ TM_SUB,
+ TM_MUL,
+ TM_DIV,
+ TM_POW,
+ TM_UNM,
+ TM_LT,
+ TM_CONCAT,
+ TM_GC,
+ TM_FUNCTION,
+ TM_N /* number of elements in the enum */
+} TMS;
+
+
+struct TM {
+ Closure *method[TM_N];
+ TString *collected; /* list of garbage-collected udata with this tag */
+};
+
+
+#define luaT_gettm(L,tag,event) (L->TMtable[tag].method[event])
+#define luaT_gettmbyObj(L,o,e) (luaT_gettm((L),luaT_tag(o),(e)))
+
+
+#define validtag(t) (NUM_TAGS <= (t) && (t) <= L->last_tag)
+
+extern const char *const luaT_eventname[];
+
+
+void luaT_init (lua_State *L);
+void luaT_realtag (lua_State *L, int tag);
+int luaT_tag (const TObject *o);
+int luaT_validevent (int t, int e); /* used by compatibility module */
+
+
+#endif
diff --git a/src/lua/lua.h b/src/lua/lua.h
new file mode 100644
index 00000000..87d64e71
--- /dev/null
+++ b/src/lua/lua.h
@@ -0,0 +1,248 @@
+/*
+** $Id: lua.h,v 1.2 2001/11/26 23:00:26 darkgod Exp $
+** Lua - An Extensible Extension Language
+** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil
+** e-mail: lua@tecgraf.puc-rio.br
+** www: http://www.tecgraf.puc-rio.br/lua/
+** See Copyright Notice at the end of this file
+*/
+
+
+#ifndef lua_h
+#define lua_h
+
+
+/* definition of `size_t' */
+#include <stddef.h>
+
+
+/* mark for all API functions */
+#ifndef LUA_API
+#define LUA_API extern
+#endif
+
+
+#define LUA_VERSION "Lua 4.0"
+#define LUA_COPYRIGHT "Copyright (C) 1994-2000 TeCGraf, PUC-Rio"
+#define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo"
+
+
+/* name of global variable with error handler */
+#define LUA_ERRORMESSAGE "_ERRORMESSAGE"
+
+
+/* pre-defined references */
+#define LUA_NOREF (-2)
+#define LUA_REFNIL (-1)
+#define LUA_REFREGISTRY 0
+
+/* pre-defined tags */
+#define LUA_ANYTAG (-1)
+#define LUA_NOTAG (-2)
+
+
+/* option for multiple returns in lua_call */
+#define LUA_MULTRET (-1)
+
+
+/* minimum stack available for a C function */
+#define LUA_MINSTACK 20
+
+
+/* error codes for lua_do* */
+#define LUA_ERRRUN 1
+#define LUA_ERRFILE 2
+#define LUA_ERRSYNTAX 3
+#define LUA_ERRMEM 4
+#define LUA_ERRERR 5
+
+
+typedef struct lua_State lua_State;
+
+typedef int (*lua_CFunction) (lua_State *L);
+
+/*
+** types returned by `lua_type'
+*/
+#define LUA_TNONE (-1)
+
+#define LUA_TUSERDATA 0
+#define LUA_TNIL 1
+#define LUA_TNUMBER 2
+#define LUA_TSTRING 3
+#define LUA_TTABLE 4
+#define LUA_TFUNCTION 5
+
+
+
+/*
+** state manipulation
+*/
+LUA_API lua_State *lua_open (int stacksize);
+LUA_API void lua_close (lua_State *L);
+
+
+/*
+** basic stack manipulation
+*/
+LUA_API int lua_gettop (lua_State *L);
+LUA_API void lua_settop (lua_State *L, int index);
+LUA_API void lua_pushvalue (lua_State *L, int index);
+LUA_API void lua_remove (lua_State *L, int index);
+LUA_API void lua_insert (lua_State *L, int index);
+LUA_API int lua_stackspace (lua_State *L);
+
+
+/*
+** access functions (stack -> C)
+*/
+
+LUA_API int lua_type (lua_State *L, int index);
+LUA_API const char *lua_typename (lua_State *L, int t);
+LUA_API int lua_isnumber (lua_State *L, int index);
+LUA_API int lua_isstring (lua_State *L, int index);
+LUA_API int lua_iscfunction (lua_State *L, int index);
+LUA_API int lua_tag (lua_State *L, int index);
+
+LUA_API int lua_equal (lua_State *L, int index1, int index2);
+LUA_API int lua_lessthan (lua_State *L, int index1, int index2);
+
+LUA_API long lua_tonumber (lua_State *L, int index);
+LUA_API const char *lua_tostring (lua_State *L, int index);
+LUA_API size_t lua_strlen (lua_State *L, int index);
+LUA_API lua_CFunction lua_tocfunction (lua_State *L, int index);
+LUA_API void *lua_touserdata (lua_State *L, int index);
+LUA_API const void *lua_topointer (lua_State *L, int index);
+
+
+/*
+** push functions (C -> stack)
+*/
+LUA_API void lua_pushnil (lua_State *L);
+LUA_API void lua_pushnumber (lua_State *L, long n);
+LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len);
+LUA_API void lua_pushstring (lua_State *L, const char *s);
+LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
+LUA_API void lua_pushusertag (lua_State *L, void *u, int tag);
+
+
+/*
+** get functions (Lua -> stack)
+*/
+LUA_API void lua_getglobal (lua_State *L, const char *name);
+LUA_API void lua_gettable (lua_State *L, int index);
+LUA_API void lua_rawget (lua_State *L, int index);
+LUA_API void lua_rawgeti (lua_State *L, int index, int n);
+LUA_API void lua_getglobals (lua_State *L);
+LUA_API void lua_gettagmethod (lua_State *L, int tag, const char *event);
+LUA_API int lua_getref (lua_State *L, int ref);
+LUA_API void lua_newtable (lua_State *L);
+
+
+/*
+** set functions (stack -> Lua)
+*/
+LUA_API void lua_setglobal (lua_State *L, const char *name);
+LUA_API void lua_settable (lua_State *L, int index);
+LUA_API void lua_rawset (lua_State *L, int index);
+LUA_API void lua_rawseti (lua_State *L, int index, int n);
+LUA_API void lua_setglobals (lua_State *L);
+LUA_API void lua_settagmethod (lua_State *L, int tag, const char *event);
+LUA_API int lua_ref (lua_State *L, int lock);
+
+
+/*
+** "do" functions (run Lua code)
+*/
+LUA_API int lua_call (lua_State *L, int nargs, int nresults);
+LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults);
+LUA_API int lua_dofile (lua_State *L, const char *filename);
+LUA_API int lua_dostring (lua_State *L, const char *str);
+LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name);
+
+/*
+** Garbage-collection functions
+*/
+LUA_API int lua_getgcthreshold (lua_State *L);
+LUA_API int lua_getgccount (lua_State *L);
+LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold);
+
+/*
+** miscellaneous functions
+*/
+LUA_API int lua_newtag (lua_State *L);
+LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom);
+LUA_API void lua_settag (lua_State *L, int tag);
+
+LUA_API void lua_error (lua_State *L, const char *s);
+
+LUA_API void lua_unref (lua_State *L, int ref);
+
+LUA_API int lua_next (lua_State *L, int index);
+LUA_API int lua_getn (lua_State *L, int index);
+
+LUA_API void lua_concat (lua_State *L, int n);
+
+LUA_API void *lua_newuserdata (lua_State *L, size_t size);
+
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define lua_pop(L,n) lua_settop(L, -(n)-1)
+
+#define lua_register(L,n,f) (lua_pushcfunction(L, f), lua_setglobal(L, n))
+#define lua_pushuserdata(L,u) lua_pushusertag(L, u, 0)
+#define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0)
+#define lua_clonetag(L,t) lua_copytagmethods(L, lua_newtag(L), (t))
+
+#define lua_isfunction(L,n) (lua_type(L,n) == LUA_TFUNCTION)
+#define lua_istable(L,n) (lua_type(L,n) == LUA_TTABLE)
+#define lua_isuserdata(L,n) (lua_type(L,n) == LUA_TUSERDATA)
+#define lua_isnil(L,n) (lua_type(L,n) == LUA_TNIL)
+#define lua_isnull(L,n) (lua_type(L,n) == LUA_TNONE)
+
+#define lua_getregistry(L) lua_getref(L, LUA_REFREGISTRY)
+
+#endif
+
+
+
+/******************************************************************************
+* Copyright (C) 1994-2000 TeCGraf, PUC-Rio. All rights reserved.
+*
+* Permission is hereby granted, without written agreement and without license
+* or royalty fees, to use, copy, modify, and distribute this software and its
+* documentation for any purpose, including commercial applications, subject to
+* the following conditions:
+*
+* - The above copyright notice and this permission notice shall appear in all
+* copies or substantial portions of this software.
+*
+* - The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software in a
+* product, an acknowledgment in the product documentation would be greatly
+* appreciated (but it is not required).
+*
+* - Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+*
+* The authors specifically disclaim any warranties, including, but not limited
+* to, the implied warranties of merchantability and fitness for a particular
+* purpose. The software provided hereunder is on an "as is" basis, and the
+* authors have no obligation to provide maintenance, support, updates,
+* enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the
+* authors be held liable to any party for direct, indirect, special,
+* incidental, or consequential damages arising out of the use of this software
+* and its documentation.
+*
+* The Lua language and this implementation have been entirely designed and
+* written by Waldemar Celes Filho, Roberto Ierusalimschy and
+* Luiz Henrique de Figueiredo at TeCGraf, PUC-Rio.
+*
+* This implementation contains no third-party code.
+******************************************************************************/
+
diff --git a/src/lua/lua2c.lua b/src/lua/lua2c.lua
new file mode 100644
index 00000000..3f8d1716
--- /dev/null
+++ b/src/lua/lua2c.lua
@@ -0,0 +1,29 @@
+-- lua2c.lua
+-- embed lua code into C source
+-- celetecgraf.puc-rio.br
+-- dez 2000
+
+function embed (code)
+
+ -- clean Lua code
+ local s = clean(code)
+ if not s then
+ error("parser error in embedded code")
+ end
+
+ -- convert to C
+ output('\n { /* begin embedded lua code */\n')
+ output(' static unsigned char B[] = {\n ')
+ local t={n=0}
+ local b = gsub(s,'(.)',function (c)
+ local e = ''
+ %t.n=%t.n+1 if %t.n==15 then %t.n=0 e='\n ' end
+ return format('%3u,%s',strbyte(c),e)
+ end
+ )
+ output(b..strbyte(" "))
+ output('\n };\n')
+ output(' lua_dobuffer(tolua_S,(char*)B,sizeof(B),"'..fn..': embedded Lua code");')
+ output(' } /* end of embedded lua code */\n\n')
+end
+
diff --git a/src/lua/luadebug.h b/src/lua/luadebug.h
new file mode 100644
index 00000000..21522445
--- /dev/null
+++ b/src/lua/luadebug.h
@@ -0,0 +1,46 @@
+/*
+** $Id: luadebug.h,v 1.2 2001/11/26 23:00:26 darkgod Exp $
+** Debugging API
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef luadebug_h
+#define luadebug_h
+
+
+#include "lua.h"
+
+typedef struct lua_Debug lua_Debug; /* activation record */
+typedef struct lua_Localvar lua_Localvar;
+
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
+
+
+LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
+LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
+LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
+
+LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func);
+LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func);
+
+
+#define LUA_IDSIZE 60
+
+struct lua_Debug {
+ const char *event; /* `call', `return' */
+ int currentline; /* (l) */
+ const char *name; /* (n) */
+ const char *namewhat; /* (n) `global', `tag method', `local', `field' */
+ int nups; /* (u) number of upvalues */
+ int linedefined; /* (S) */
+ const char *what; /* (S) `Lua' function, `C' function, Lua `main' */
+ const char *source; /* (S) */
+ char short_src[LUA_IDSIZE]; /* (S) */
+ /* private part */
+ struct lua_TObject *_func; /* active function */
+};
+
+
+#endif
diff --git a/src/lua/lualib.h b/src/lua/lualib.h
new file mode 100644
index 00000000..89f5519f
--- /dev/null
+++ b/src/lua/lualib.h
@@ -0,0 +1,34 @@
+/*
+** $Id: lualib.h,v 1.2 2001/11/26 23:00:26 darkgod Exp $
+** Lua standard libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lualib_h
+#define lualib_h
+
+#include "lua.h"
+
+
+#ifndef LUALIB_API
+#define LUALIB_API extern
+#endif
+
+
+#define LUA_ALERT "_ALERT"
+
+LUALIB_API void lua_baselibopen (lua_State *L);
+LUALIB_API void lua_iolibopen (lua_State *L);
+LUALIB_API void lua_strlibopen (lua_State *L);
+LUALIB_API void lua_mathlibopen (lua_State *L);
+LUALIB_API void lua_dblibopen (lua_State *L);
+
+
+
+/* Auxiliary functions (private) */
+
+const char *luaI_classend (lua_State *L, const char *p);
+int luaI_singlematch (int c, const char *p, const char *ep);
+
+#endif
diff --git a/src/lua/lundump.c b/src/lua/lundump.c
new file mode 100644
index 00000000..7f69573e
--- /dev/null
+++ b/src/lua/lundump.c
@@ -0,0 +1,244 @@
+/*
+** $Id: lundump.c,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** load bytecodes from files
+** See Copyright Notice in lua.h
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lfunc.h"
+#include "lmem.h"
+#include "lopcodes.h"
+#include "lstring.h"
+#include "lundump.h"
+
+#define LoadByte ezgetc
+
+static const char* ZNAME (ZIO* Z)
+{
+ const char* s=zname(Z);
+ return (*s=='@') ? s+1 : s;
+}
+
+static void unexpectedEOZ (lua_State* L, ZIO* Z)
+{
+ luaO_verror(L,"unexpected end of file in `%.99s'",ZNAME(Z));
+}
+
+static int ezgetc (lua_State* L, ZIO* Z)
+{
+ int c=zgetc(Z);
+ if (c==EOZ) unexpectedEOZ(L,Z);
+ return c;
+}
+
+static void ezread (lua_State* L, ZIO* Z, void* b, int n)
+{
+ int r=zread(Z,b,n);
+ if (r!=0) unexpectedEOZ(L,Z);
+}
+
+static void LoadBlock (lua_State* L, void* b, size_t size, ZIO* Z, int swap)
+{
+ if (swap)
+ {
+ char *p=(char *) b+size-1;
+ int n=size;
+ while (n--) *p--=(char)ezgetc(L,Z);
+ }
+ else
+ ezread(L,Z,b,size);
+}
+
+static void LoadVector (lua_State* L, void* b, int m, size_t size, ZIO* Z, int swap)
+{
+ if (swap)
+ {
+ char *q=(char *) b;
+ while (m--)
+ {
+ char *p=q+size-1;
+ int n=size;
+ while (n--) *p--=(char)ezgetc(L,Z);
+ q+=size;
+ }
+ }
+ else
+ ezread(L,Z,b,m*size);
+}
+
+static int LoadInt (lua_State* L, ZIO* Z, int swap)
+{
+ int x;
+ LoadBlock(L,&x,sizeof(x),Z,swap);
+ return x;
+}
+
+static size_t LoadSize (lua_State* L, ZIO* Z, int swap)
+{
+ size_t x;
+ LoadBlock(L,&x,sizeof(x),Z,swap);
+ return x;
+}
+
+static Number LoadNumber (lua_State* L, ZIO* Z, int swap)
+{
+ Number x;
+ LoadBlock(L,&x,sizeof(x),Z,swap);
+ return x;
+}
+
+static TString* LoadString (lua_State* L, ZIO* Z, int swap)
+{
+ size_t size=LoadSize(L,Z,swap);
+ if (size==0)
+ return NULL;
+ else
+ {
+ char* s=luaO_openspace(L,size);
+ LoadBlock(L,s,size,Z,0);
+ return luaS_newlstr(L,s,size-1); /* remove trailing '\0' */
+ }
+}
+
+static void LoadCode (lua_State* L, Proto* tf, ZIO* Z, int swap)
+{
+ int size=LoadInt(L,Z,swap);
+ tf->code=luaM_newvector(L,size,Instruction);
+ LoadVector(L,tf->code,size,sizeof(*tf->code),Z,swap);
+ if (tf->code[size-1]!=OP_END) luaO_verror(L,"bad code in `%.99s'",ZNAME(Z));
+ luaF_protook(L,tf,size);
+}
+
+static void LoadLocals (lua_State* L, Proto* tf, ZIO* Z, int swap)
+{
+ int i,n;
+ tf->nlocvars=n=LoadInt(L,Z,swap);
+ tf->locvars=luaM_newvector(L,n,LocVar);
+ for (i=0; i<n; i++)
+ {
+ tf->locvars[i].varname=LoadString(L,Z,swap);
+ tf->locvars[i].startpc=LoadInt(L,Z,swap);
+ tf->locvars[i].endpc=LoadInt(L,Z,swap);
+ }
+}
+
+static void LoadLines (lua_State* L, Proto* tf, ZIO* Z, int swap)
+{
+ int n;
+ tf->nlineinfo=n=LoadInt(L,Z,swap);
+ tf->lineinfo=luaM_newvector(L,n,int);
+ LoadVector(L,tf->lineinfo,n,sizeof(*tf->lineinfo),Z,swap);
+}
+
+static Proto* LoadFunction (lua_State* L, ZIO* Z, int swap);
+
+static void LoadConstants (lua_State* L, Proto* tf, ZIO* Z, int swap)
+{
+ int i,n;
+ tf->nkstr=n=LoadInt(L,Z,swap);
+ tf->kstr=luaM_newvector(L,n,TString*);
+ for (i=0; i<n; i++)
+ tf->kstr[i]=LoadString(L,Z,swap);
+ tf->nknum=n=LoadInt(L,Z,swap);
+ tf->knum=luaM_newvector(L,n,Number);
+ LoadVector(L,tf->knum,n,sizeof(*tf->knum),Z,swap);
+ tf->nkproto=n=LoadInt(L,Z,swap);
+ tf->kproto=luaM_newvector(L,n,Proto*);
+ for (i=0; i<n; i++)
+ tf->kproto[i]=LoadFunction(L,Z,swap);
+}
+
+static Proto* LoadFunction (lua_State* L, ZIO* Z, int swap)
+{
+ Proto* tf=luaF_newproto(L);
+ tf->source=LoadString(L,Z,swap);
+ tf->lineDefined=LoadInt(L,Z,swap);
+ tf->numparams=LoadInt(L,Z,swap);
+ tf->is_vararg=LoadByte(L,Z);
+ tf->maxstacksize=LoadInt(L,Z,swap);
+ LoadLocals(L,tf,Z,swap);
+ LoadLines(L,tf,Z,swap);
+ LoadConstants(L,tf,Z,swap);
+ LoadCode(L,tf,Z,swap);
+ return tf;
+}
+
+static void LoadSignature (lua_State* L, ZIO* Z)
+{
+ const char* s=SIGNATURE;
+ while (*s!=0 && ezgetc(L,Z)==*s)
+ ++s;
+ if (*s!=0) luaO_verror(L,"bad signature in `%.99s'",ZNAME(Z));
+}
+
+static void TestSize (lua_State* L, int s, const char* what, ZIO* Z)
+{
+ int r=ezgetc(L,Z);
+ if (r!=s)
+ luaO_verror(L,"virtual machine mismatch in `%.99s':\n"
+ " %.20s is %d but read %d",ZNAME(Z),what,s,r);
+}
+
+#define TESTSIZE(s) TestSize(L,s,#s,Z)
+#define V(v) v/16,v%16
+
+static int LoadHeader (lua_State* L, ZIO* Z)
+{
+ int version,swap;
+ Number f=0,tf=TEST_NUMBER;
+ LoadSignature(L,Z);
+ version=ezgetc(L,Z);
+ if (version>VERSION)
+ luaO_verror(L,"`%.99s' too new:\n"
+ " read version %d.%d; expected at most %d.%d",
+ ZNAME(Z),V(version),V(VERSION));
+ if (version<VERSION0) /* check last major change */
+ luaO_verror(L,"`%.99s' too old:\n"
+ " read version %d.%d; expected at least %d.%d",
+ ZNAME(Z),V(version),V(VERSION));
+ swap=(luaU_endianess()!=ezgetc(L,Z)); /* need to swap bytes? */
+ TESTSIZE(sizeof(int));
+ TESTSIZE(sizeof(size_t));
+ TESTSIZE(sizeof(Instruction));
+ TESTSIZE(SIZE_INSTRUCTION);
+ TESTSIZE(SIZE_OP);
+ TESTSIZE(SIZE_B);
+ TESTSIZE(sizeof(Number));
+ f=LoadNumber(L,Z,swap);
+ if ((long)f!=(long)tf) /* disregard errors in last bit of fraction */
+ luaO_verror(L,"unknown number format in `%.99s':\n"
+ " read " NUMBER_FMT "; expected " NUMBER_FMT, ZNAME(Z),f,tf);
+ return swap;
+}
+
+static Proto* LoadChunk (lua_State* L, ZIO* Z)
+{
+ return LoadFunction(L,Z,LoadHeader(L,Z));
+}
+
+/*
+** load one chunk from a file or buffer
+** return main if ok and NULL at EOF
+*/
+Proto* luaU_undump (lua_State* L, ZIO* Z)
+{
+ Proto* tf=NULL;
+ int c=zgetc(Z);
+ if (c==ID_CHUNK)
+ tf=LoadChunk(L,Z);
+ c=zgetc(Z);
+ if (c!=EOZ)
+ luaO_verror(L,"`%.99s' apparently contains more than one chunk",ZNAME(Z));
+ return tf;
+}
+
+/*
+** find byte order
+*/
+int luaU_endianess (void)
+{
+ int x=1;
+ return *(char*)&x;
+}
diff --git a/src/lua/lundump.h b/src/lua/lundump.h
new file mode 100644
index 00000000..ec394f46
--- /dev/null
+++ b/src/lua/lundump.h
@@ -0,0 +1,35 @@
+/*
+** $Id: lundump.h,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** load pre-compiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lundump_h
+#define lundump_h
+
+#include "lobject.h"
+#include "lzio.h"
+
+/* load one chunk */
+Proto* luaU_undump (lua_State* L, ZIO* Z);
+
+/* find byte order */
+int luaU_endianess (void);
+
+/* definitions for headers of binary files */
+#define VERSION 0x40 /* last format change was in 4.0 */
+#define VERSION0 0x40 /* last major change was in 4.0 */
+#define ID_CHUNK 27 /* binary files start with ESC... */
+#define SIGNATURE "Lua" /* ...followed by this signature */
+
+/* formats for error messages */
+#define SOURCE_FMT "<%d:%.99s>"
+#define SOURCE tf->lineDefined,tf->source->str
+#define IN_FMT " in %p " SOURCE_FMT
+#define IN tf,SOURCE
+
+/* a multiple of PI for testing native format */
+/* multiplying by 1E8 gives non-trivial integer values */
+#define TEST_NUMBER 3
+
+#endif
diff --git a/src/lua/lvm.c b/src/lua/lvm.c
new file mode 100644
index 00000000..e304e11e
--- /dev/null
+++ b/src/lua/lvm.c
@@ -0,0 +1,710 @@
+/*
+** $Id: lvm.c,v 1.5 2004/06/04 13:42:10 neil Exp $
+** Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+#ifdef OLD_ANSI
+#define strcoll(a,b) strcmp(a,b)
+#endif
+
+
+
+/*
+** Extra stack size to run a function:
+** TAG_LINE(1), NAME(1), TM calls(3) (plus some extra...)
+*/
+#define EXTRA_STACK 8
+
+
+
+int luaV_tonumber (TObject *obj) {
+ if (ttype(obj) != LUA_TSTRING)
+ return 1;
+ else {
+ if (!luaO_str2d(svalue(obj), &nvalue(obj)))
+ return 2;
+ ttype(obj) = LUA_TNUMBER;
+ return 0;
+ }
+}
+
+
+int luaV_tostring (lua_State *L, TObject *obj) { /* LUA_NUMBER */
+ if (ttype(obj) != LUA_TNUMBER)
+ return 1;
+ else {
+ char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */
+ lua_number2str(s, nvalue(obj)); /* convert `s' to number */
+ tsvalue(obj) = luaS_new(L, s);
+ ttype(obj) = LUA_TSTRING;
+ return 0;
+ }
+}
+
+
+static void traceexec (lua_State *L, StkId base, StkId top, lua_Hook linehook) {
+ CallInfo *ci = infovalue(base-1);
+ int *lineinfo = ci->func->f.l->lineinfo;
+ int pc = (*ci->pc - ci->func->f.l->code) - 1;
+ int newline;
+ if (pc == 0) { /* may be first time? */
+ ci->line = 1;
+ ci->refi = 0;
+ ci->lastpc = pc+1; /* make sure it will call linehook */
+ }
+ newline = luaG_getline(lineinfo, pc, ci->line, &ci->refi);
+ /* calls linehook when enters a new line or jumps back (loop) */
+ if (newline != ci->line || pc <= ci->lastpc) {
+ ci->line = newline;
+ L->top = top;
+ luaD_lineHook(L, base-2, newline, linehook);
+ }
+ ci->lastpc = pc;
+}
+
+
+static Closure *luaV_closure (lua_State *L, int nelems) {
+ Closure *c = luaF_newclosure(L, nelems);
+ L->top -= nelems;
+ while (nelems--)
+ c->upvalue[nelems] = *(L->top+nelems);
+ clvalue(L->top) = c;
+ ttype(L->top) = LUA_TFUNCTION;
+ incr_top;
+ return c;
+}
+
+
+void luaV_Cclosure (lua_State *L, lua_CFunction c, int nelems) {
+ Closure *cl = luaV_closure(L, nelems);
+ cl->f.c = c;
+ cl->isC = 1;
+}
+
+
+void luaV_Lclosure (lua_State *L, Proto *l, int nelems) {
+ Closure *cl = luaV_closure(L, nelems);
+ cl->f.l = l;
+ cl->isC = 0;
+}
+
+
+/*
+** Function to index a table.
+** Receives the table at `t' and the key at top.
+*/
+const TObject *luaV_gettable (lua_State *L, StkId t) {
+ Closure *tm;
+ int tg;
+ if (ttype(t) == LUA_TTABLE && /* `t' is a table? */
+ ((tg = hvalue(t)->htag) == LUA_TTABLE || /* with default tag? */
+ luaT_gettm(L, tg, TM_GETTABLE) == NULL)) { /* or no TM? */
+ /* do a primitive get */
+ const TObject *h = luaH_get(L, hvalue(t), L->top-1);
+ /* result is no nil or there is no `index' tag method? */
+ if (ttype(h) != LUA_TNIL || ((tm=luaT_gettm(L, tg, TM_INDEX)) == NULL))
+ return h; /* return result */
+ /* else call `index' tag method */
+ }
+ else { /* try a `gettable' tag method */
+ tm = luaT_gettmbyObj(L, t, TM_GETTABLE);
+ }
+ if (tm != NULL) { /* is there a tag method? */
+ luaD_checkstack(L, 2);
+ *(L->top+1) = *(L->top-1); /* key */
+ *L->top = *t; /* table */
+ clvalue(L->top-1) = tm; /* tag method */
+ ttype(L->top-1) = LUA_TFUNCTION;
+ L->top += 2;
+ luaD_call(L, L->top - 3, 1);
+ return L->top - 1; /* call result */
+ }
+ else { /* no tag method */
+ luaG_typeerror(L, t, "index");
+ return NULL; /* to avoid warnings */
+ }
+}
+
+
+/*
+** Receives table at `t', key at `key' and value at top.
+*/
+void luaV_settable (lua_State *L, StkId t, StkId key) {
+ int tg;
+ if (ttype(t) == LUA_TTABLE && /* `t' is a table? */
+ ((tg = hvalue(t)->htag) == LUA_TTABLE || /* with default tag? */
+ luaT_gettm(L, tg, TM_SETTABLE) == NULL)) /* or no TM? */
+ *luaH_set(L, hvalue(t), key) = *(L->top-1); /* do a primitive set */
+ else { /* try a `settable' tag method */
+ Closure *tm = luaT_gettmbyObj(L, t, TM_SETTABLE);
+ if (tm != NULL) {
+ luaD_checkstack(L, 3);
+ *(L->top+2) = *(L->top-1);
+ *(L->top+1) = *key;
+ *(L->top) = *t;
+ clvalue(L->top-1) = tm;
+ ttype(L->top-1) = LUA_TFUNCTION;
+ L->top += 3;
+ luaD_call(L, L->top - 4, 0); /* call `settable' tag method */
+ }
+ else /* no tag method... */
+ luaG_typeerror(L, t, "index");
+ }
+}
+
+
+const TObject *luaV_getglobal (lua_State *L, TString *s) {
+ const TObject *value = luaH_getstr(L->gt, s);
+ Closure *tm = luaT_gettmbyObj(L, value, TM_GETGLOBAL);
+ if (tm == NULL) /* is there a tag method? */
+ return value; /* default behavior */
+ else { /* tag method */
+ luaD_checkstack(L, 3);
+ clvalue(L->top) = tm;
+ ttype(L->top) = LUA_TFUNCTION;
+ tsvalue(L->top+1) = s; /* global name */
+ ttype(L->top+1) = LUA_TSTRING;
+ *(L->top+2) = *value;
+ L->top += 3;
+ luaD_call(L, L->top - 3, 1);
+ return L->top - 1;
+ }
+}
+
+
+void luaV_setglobal (lua_State *L, TString *s) {
+ const TObject *oldvalue = luaH_getstr(L->gt, s);
+ Closure *tm = luaT_gettmbyObj(L, oldvalue, TM_SETGLOBAL);
+ if (tm == NULL) { /* is there a tag method? */
+ if (oldvalue != &luaO_nilobject) {
+ /* cast to remove `const' is OK, because `oldvalue' != luaO_nilobject */
+ *(TObject *)oldvalue = *(L->top - 1);
+ }
+ else {
+ TObject key;
+ ttype(&key) = LUA_TSTRING;
+ tsvalue(&key) = s;
+ *luaH_set(L, L->gt, &key) = *(L->top - 1);
+ }
+ }
+ else {
+ luaD_checkstack(L, 3);
+ *(L->top+2) = *(L->top-1); /* new value */
+ *(L->top+1) = *oldvalue;
+ ttype(L->top) = LUA_TSTRING;
+ tsvalue(L->top) = s;
+ clvalue(L->top-1) = tm;
+ ttype(L->top-1) = LUA_TFUNCTION;
+ L->top += 3;
+ luaD_call(L, L->top - 4, 0);
+ }
+}
+
+
+static int call_binTM (lua_State *L, StkId top, TMS event) {
+ /* try first operand */
+ Closure *tm = luaT_gettmbyObj(L, top-2, event);
+ L->top = top;
+ if (tm == NULL) {
+ tm = luaT_gettmbyObj(L, top-1, event); /* try second operand */
+ if (tm == NULL) {
+ tm = luaT_gettm(L, 0, event); /* try a `global' method */
+ if (tm == NULL)
+ return 0; /* error */
+ }
+ }
+ lua_pushstring(L, luaT_eventname[event]);
+ luaD_callTM(L, tm, 3, 1);
+ return 1;
+}
+
+
+static void call_arith (lua_State *L, StkId top, TMS event) {
+ if (!call_binTM(L, top, event))
+ luaG_binerror(L, top-2, LUA_TNUMBER, "perform arithmetic on");
+}
+
+
+static int luaV_strcomp (const TString *ls, const TString *rs) {
+ const char *l = ls->str;
+ size_t ll = ls->len;
+ const char *r = rs->str;
+ size_t lr = rs->len;
+ for (;;) {
+ int temp = strcoll(l, r);
+ if (temp != 0) return temp;
+ else { /* strings are equal up to a '\0' */
+ size_t len = strlen(l); /* index of first '\0' in both strings */
+ if (len == ll) /* l is finished? */
+ return (len == lr) ? 0 : -1; /* l is equal or smaller than r */
+ else if (len == lr) /* r is finished? */
+ return 1; /* l is greater than r (because l is not finished) */
+ /* both strings longer than `len'; go on comparing (after the '\0') */
+ len++;
+ l += len; ll -= len; r += len; lr -= len;
+ }
+ }
+}
+
+
+int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r, StkId top) {
+ if (ttype(l) == LUA_TNUMBER && ttype(r) == LUA_TNUMBER)
+ return (nvalue(l) < nvalue(r));
+ else if (ttype(l) == LUA_TSTRING && ttype(r) == LUA_TSTRING)
+ return (luaV_strcomp(tsvalue(l), tsvalue(r)) < 0);
+ else { /* call TM */
+ luaD_checkstack(L, 2);
+ *top++ = *l;
+ *top++ = *r;
+ if (!call_binTM(L, top, TM_LT))
+ luaG_ordererror(L, top-2);
+ L->top--;
+ return (ttype(L->top) != LUA_TNIL);
+ }
+}
+
+
+void luaV_strconc (lua_State *L, int total, StkId top) {
+ do {
+ int n = 2; /* number of elements handled in this pass (at least 2) */
+ if (tostring(L, top-2) || tostring(L, top-1)) {
+ if (!call_binTM(L, top, TM_CONCAT))
+ luaG_binerror(L, top-2, LUA_TSTRING, "concat");
+ }
+ else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */
+ /* at least two string values; get as many as possible */
+ lint32 tl = (lint32)tsvalue(top-1)->len +
+ (lint32)tsvalue(top-2)->len;
+ char *buffer;
+ int i;
+ while (n < total && !tostring(L, top-n-1)) { /* collect total length */
+ tl += tsvalue(top-n-1)->len;
+ n++;
+ }
+ if (tl > MAX_SIZET) lua_error(L, "string size overflow");
+ buffer = luaO_openspace(L, tl);
+ tl = 0;
+ for (i=n; i>0; i--) { /* concat all strings */
+ size_t l = tsvalue(top-i)->len;
+ memcpy(buffer+tl, tsvalue(top-i)->str, l);
+ tl += l;
+ }
+ tsvalue(top-n) = luaS_newlstr(L, buffer, tl);
+ }
+ total -= n-1; /* got `n' strings to create 1 new */
+ top -= n-1;
+ } while (total > 1); /* repeat until only 1 result left */
+}
+
+
+static void luaV_pack (lua_State *L, StkId firstelem) {
+ int i;
+ Hash *htab = luaH_new(L, 0);
+ for (i=0; firstelem+i<L->top; i++)
+ *luaH_setint(L, htab, i+1) = *(firstelem+i);
+ /* store counter in field `n' */
+ luaH_setstrnum(L, htab, luaS_new(L, "n"), i);
+ L->top = firstelem; /* remove elements from the stack */
+ ttype(L->top) = LUA_TTABLE;
+ hvalue(L->top) = htab;
+ incr_top;
+}
+
+
+static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
+ int nvararg = (L->top-base) - nfixargs;
+ if (nvararg < 0)
+ luaD_adjusttop(L, base, nfixargs);
+ luaV_pack(L, base+nfixargs);
+}
+
+
+
+#define dojump(pc, i) { int d = GETARG_S(i); pc += d; }
+
+/*
+** Executes the given Lua function. Parameters are between [base,top).
+** Returns n such that the the results are between [n,top).
+*/
+StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
+ const Proto *const tf = cl->f.l;
+ StkId top; /* keep top local, for performance */
+ const Instruction *pc = tf->code;
+ TString **const kstr = tf->kstr;
+ const lua_Hook linehook = L->linehook;
+ infovalue(base-1)->pc = &pc;
+ luaD_checkstack(L, tf->maxstacksize+EXTRA_STACK);
+ if (tf->is_vararg) /* varargs? */
+ adjust_varargs(L, base, tf->numparams);
+ else
+ luaD_adjusttop(L, base, tf->numparams);
+ top = L->top;
+ /* main loop of interpreter */
+ for (;;) {
+ const Instruction i = *pc++;
+ if (linehook)
+ traceexec(L, base, top, linehook);
+ switch (GET_OPCODE(i)) {
+ case OP_END: {
+ L->top = top;
+ return top;
+ }
+ case OP_RETURN: {
+ L->top = top;
+ return base+GETARG_U(i);
+ }
+ case OP_CALL: {
+ int nres = GETARG_B(i);
+ if (nres == MULT_RET) nres = LUA_MULTRET;
+ L->top = top;
+ luaD_call(L, base+GETARG_A(i), nres);
+ top = L->top;
+ break;
+ }
+ case OP_TAILCALL: {
+ L->top = top;
+ luaD_call(L, base+GETARG_A(i), LUA_MULTRET);
+ return base+GETARG_B(i);
+ }
+ case OP_PUSHNIL: {
+ int n = GETARG_U(i);
+ LUA_ASSERT(n>0, "invalid argument");
+ do {
+ ttype(top++) = LUA_TNIL;
+ } while (--n > 0);
+ break;
+ }
+ case OP_POP: {
+ top -= GETARG_U(i);
+ break;
+ }
+ case OP_PUSHINT: {
+ ttype(top) = LUA_TNUMBER;
+ nvalue(top) = (Number)GETARG_S(i);
+ top++;
+ break;
+ }
+ case OP_PUSHSTRING: {
+ ttype(top) = LUA_TSTRING;
+ tsvalue(top) = kstr[GETARG_U(i)];
+ top++;
+ break;
+ }
+ case OP_PUSHNUM: {
+ ttype(top) = LUA_TNUMBER;
+ nvalue(top) = tf->knum[GETARG_U(i)];
+ top++;
+ break;
+ }
+ case OP_PUSHNEGNUM: {
+ ttype(top) = LUA_TNUMBER;
+ nvalue(top) = -tf->knum[GETARG_U(i)];
+ top++;
+ break;
+ }
+ case OP_PUSHUPVALUE: {
+ *top++ = cl->upvalue[GETARG_U(i)];
+ break;
+ }
+ case OP_GETLOCAL: {
+ *top++ = *(base+GETARG_U(i));
+ break;
+ }
+ case OP_GETGLOBAL: {
+ L->top = top;
+ *top = *luaV_getglobal(L, kstr[GETARG_U(i)]);
+ top++;
+ break;
+ }
+ case OP_GETTABLE: {
+ L->top = top;
+ top--;
+ *(top-1) = *luaV_gettable(L, top-1);
+ break;
+ }
+ case OP_GETDOTTED: {
+ ttype(top) = LUA_TSTRING;
+ tsvalue(top) = kstr[GETARG_U(i)];
+ L->top = top+1;
+ *(top-1) = *luaV_gettable(L, top-1);
+ break;
+ }
+ case OP_GETINDEXED: {
+ *top = *(base+GETARG_U(i));
+ L->top = top+1;
+ *(top-1) = *luaV_gettable(L, top-1);
+ break;
+ }
+ case OP_PUSHSELF: {
+ TObject receiver;
+ receiver = *(top-1);
+ ttype(top) = LUA_TSTRING;
+ tsvalue(top++) = kstr[GETARG_U(i)];
+ L->top = top;
+ *(top-2) = *luaV_gettable(L, top-2);
+ *(top-1) = receiver;
+ break;
+ }
+ case OP_CREATETABLE: {
+ L->top = top;
+ luaC_checkGC(L);
+ hvalue(top) = luaH_new(L, GETARG_U(i));
+ ttype(top) = LUA_TTABLE;
+ top++;
+ break;
+ }
+ case OP_SETLOCAL: {
+ *(base+GETARG_U(i)) = *(--top);
+ break;
+ }
+ case OP_SETGLOBAL: {
+ L->top = top;
+ luaV_setglobal(L, kstr[GETARG_U(i)]);
+ top--;
+ break;
+ }
+ case OP_SETTABLE: {
+ StkId t = top-GETARG_A(i);
+ L->top = top;
+ luaV_settable(L, t, t+1);
+ top -= GETARG_B(i); /* pop values */
+ break;
+ }
+ case OP_SETLIST: {
+ int aux = GETARG_A(i) * LFIELDS_PER_FLUSH;
+ int n = GETARG_B(i);
+ Hash *arr = hvalue(top-n-1);
+ L->top = top-n; /* final value of `top' (in case of errors) */
+ for (; n; n--)
+ *luaH_setint(L, arr, n+aux) = *(--top);
+ break;
+ }
+ case OP_SETMAP: {
+ int n = GETARG_U(i);
+ StkId finaltop = top-2*n;
+ Hash *arr = hvalue(finaltop-1);
+ L->top = finaltop; /* final value of `top' (in case of errors) */
+ for (; n; n--) {
+ top-=2;
+ *luaH_set(L, arr, top) = *(top+1);
+ }
+ break;
+ }
+ case OP_ADD: {
+ if (tonumber(top-2) || tonumber(top-1))
+ call_arith(L, top, TM_ADD);
+ else
+ nvalue(top-2) += nvalue(top-1);
+ top--;
+ break;
+ }
+ case OP_ADDI: {
+ if (tonumber(top-1)) {
+ ttype(top) = LUA_TNUMBER;
+ nvalue(top) = (Number)GETARG_S(i);
+ call_arith(L, top+1, TM_ADD);
+ }
+ else
+ nvalue(top-1) += (Number)GETARG_S(i);
+ break;
+ }
+ case OP_SUB: {
+ if (tonumber(top-2) || tonumber(top-1))
+ call_arith(L, top, TM_SUB);
+ else
+ nvalue(top-2) -= nvalue(top-1);
+ top--;
+ break;
+ }
+ case OP_MULT: {
+ if (tonumber(top-2) || tonumber(top-1))
+ call_arith(L, top, TM_MUL);
+ else
+ nvalue(top-2) *= nvalue(top-1);
+ top--;
+ break;
+ }
+ case OP_DIV: {
+ if (tonumber(top-2) || tonumber(top-1))
+ call_arith(L, top, TM_DIV);
+ else
+ nvalue(top-2) /= nvalue(top-1);
+ top--;
+ break;
+ }
+ case OP_POW: {
+ if (!call_binTM(L, top, TM_POW))
+ lua_error(L, "undefined operation");
+ top--;
+ break;
+ }
+ case OP_CONCAT: {
+ int n = GETARG_U(i);
+ luaV_strconc(L, n, top);
+ top -= n-1;
+ L->top = top;
+ luaC_checkGC(L);
+ break;
+ }
+ case OP_MINUS: {
+ if (tonumber(top-1)) {
+ ttype(top) = LUA_TNIL;
+ call_arith(L, top+1, TM_UNM);
+ }
+ else
+ nvalue(top-1) = -nvalue(top-1);
+ break;
+ }
+ case OP_NOT: {
+ ttype(top-1) =
+ (ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL;
+ nvalue(top-1) = 1;
+ break;
+ }
+ case OP_JMPNE: {
+ top -= 2;
+ if (!luaO_equalObj(top, top+1)) dojump(pc, i);
+ break;
+ }
+ case OP_JMPEQ: {
+ top -= 2;
+ if (luaO_equalObj(top, top+1)) dojump(pc, i);
+ break;
+ }
+ case OP_JMPLT: {
+ top -= 2;
+ if (luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i);
+ break;
+ }
+ case OP_JMPLE: { /* a <= b === !(b<a) */
+ top -= 2;
+ if (!luaV_lessthan(L, top+1, top, top+2)) dojump(pc, i);
+ break;
+ }
+ case OP_JMPGT: { /* a > b === (b<a) */
+ top -= 2;
+ if (luaV_lessthan(L, top+1, top, top+2)) dojump(pc, i);
+ break;
+ }
+ case OP_JMPGE: { /* a >= b === !(a<b) */
+ top -= 2;
+ if (!luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i);
+ break;
+ }
+ case OP_JMPT: {
+ if (ttype(--top) != LUA_TNIL) dojump(pc, i);
+ break;
+ }
+ case OP_JMPF: {
+ if (ttype(--top) == LUA_TNIL) dojump(pc, i);
+ break;
+ }
+ case OP_JMPONT: {
+ if (ttype(top-1) == LUA_TNIL) top--;
+ else dojump(pc, i);
+ break;
+ }
+ case OP_JMPONF: {
+ if (ttype(top-1) != LUA_TNIL) top--;
+ else dojump(pc, i);
+ break;
+ }
+ case OP_JMP: {
+ dojump(pc, i);
+ break;
+ }
+ case OP_PUSHNILJMP: {
+ ttype(top++) = LUA_TNIL;
+ pc++;
+ break;
+ }
+ case OP_FORPREP: {
+ if (tonumber(top-1))
+ lua_error(L, "`for' step must be a number");
+ if (tonumber(top-2))
+ lua_error(L, "`for' limit must be a number");
+ if (tonumber(top-3))
+ lua_error(L, "`for' initial value must be a number");
+ if (nvalue(top-1) > 0 ?
+ nvalue(top-3) > nvalue(top-2) :
+ nvalue(top-3) < nvalue(top-2)) { /* `empty' loop? */
+ top -= 3; /* remove control variables */
+ dojump(pc, i); /* jump to loop end */
+ }
+ break;
+ }
+ case OP_FORLOOP: {
+ LUA_ASSERT(ttype(top-1) == LUA_TNUMBER, "invalid step");
+ LUA_ASSERT(ttype(top-2) == LUA_TNUMBER, "invalid limit");
+ if (ttype(top-3) != LUA_TNUMBER)
+ lua_error(L, "`for' index must be a number");
+ nvalue(top-3) += nvalue(top-1); /* increment index */
+ if (nvalue(top-1) > 0 ?
+ nvalue(top-3) > nvalue(top-2) :
+ nvalue(top-3) < nvalue(top-2))
+ top -= 3; /* end loop: remove control variables */
+ else
+ dojump(pc, i); /* repeat loop */
+ break;
+ }
+ case OP_LFORPREP: {
+ Node *node;
+ if (ttype(top-1) != LUA_TTABLE)
+ lua_error(L, "`for' table must be a table");
+ node = luaH_next(L, hvalue(top-1), &luaO_nilobject);
+ if (node == NULL) { /* `empty' loop? */
+ top--; /* remove table */
+ dojump(pc, i); /* jump to loop end */
+ }
+ else {
+ top += 2; /* index,value */
+ *(top-2) = *key(node);
+ *(top-1) = *val(node);
+ }
+ break;
+ }
+ case OP_LFORLOOP: {
+ Node *node;
+ LUA_ASSERT(ttype(top-3) == LUA_TTABLE, "invalid table");
+ node = luaH_next(L, hvalue(top-3), top-2);
+ if (node == NULL) /* end loop? */
+ top -= 3; /* remove table, key, and value */
+ else {
+ *(top-2) = *key(node);
+ *(top-1) = *val(node);
+ dojump(pc, i); /* repeat loop */
+ }
+ break;
+ }
+ case OP_CLOSURE: {
+ L->top = top;
+ luaV_Lclosure(L, tf->kproto[GETARG_A(i)], GETARG_B(i));
+ top = L->top;
+ luaC_checkGC(L);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/lua/lvm.h b/src/lua/lvm.h
new file mode 100644
index 00000000..ac95ae41
--- /dev/null
+++ b/src/lua/lvm.h
@@ -0,0 +1,32 @@
+/*
+** $Id: lvm.h,v 1.3 2001/11/26 23:00:26 darkgod Exp $
+** Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lvm_h
+#define lvm_h
+
+
+#include "ldo.h"
+#include "lobject.h"
+#include "ltm.h"
+
+
+#define tonumber(o) ((ttype(o) != LUA_TNUMBER) && (luaV_tonumber(o) != 0))
+#define tostring(L,o) ((ttype(o) != LUA_TSTRING) && (luaV_tostring(L, o) != 0))
+
+
+int luaV_tonumber (TObject *obj);
+int luaV_tostring (lua_State *L, TObject *obj);
+const TObject *luaV_gettable (lua_State *L, StkId t);
+void luaV_settable (lua_State *L, StkId t, StkId key);
+const TObject *luaV_getglobal (lua_State *L, TString *s);
+void luaV_setglobal (lua_State *L, TString *s);
+StkId luaV_execute (lua_State *L, const Closure *cl, StkId base);
+void luaV_Cclosure (lua_State *L, lua_CFunction c, int nelems);
+void luaV_Lclosure (lua_State *L, Proto *l, int nelems);
+int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r, StkId top);
+void luaV_strconc (lua_State *L, int total, StkId top);
+
+#endif
diff --git a/src/lua/lzio.c b/src/lua/lzio.c
new file mode 100644
index 00000000..84d4a35c
--- /dev/null
+++ b/src/lua/lzio.c
@@ -0,0 +1,84 @@
+/*
+** $Id: lzio.c,v 1.5 2004/06/04 13:42:10 neil Exp $
+** a generic input stream interface
+** See Copyright Notice in lua.h
+*/
+
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lzio.h"
+
+
+
+/* ----------------------------------------------------- memory buffers --- */
+
+static int zmfilbuf (ZIO* z) {
+ (void)z; /* to avoid warnings */
+ return EOZ;
+}
+
+
+ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name) {
+ if (b==NULL) return NULL;
+ z->n = size;
+ z->p = (const unsigned char *)b;
+ z->filbuf = zmfilbuf;
+ z->u = NULL;
+ z->name = name;
+ return z;
+}
+
+/* ------------------------------------------------------------ strings --- */
+
+ZIO* zsopen (ZIO* z, const char* s, const char *name) {
+ if (s==NULL) return NULL;
+ return zmopen(z, s, strlen(s), name);
+}
+
+/* -------------------------------------------------------------- FILEs --- */
+
+static int zffilbuf (ZIO* z) {
+ size_t n;
+ if (feof((FILE *)z->u)) return EOZ;
+ n = fread(z->buffer, 1, ZBSIZE, (FILE *)z->u);
+ if (n==0) return EOZ;
+ z->n = n-1;
+ z->p = z->buffer;
+ return *(z->p++);
+}
+
+
+ZIO* zFopen (ZIO* z, FILE* f, const char *name) {
+ if (f==NULL) return NULL;
+ z->n = 0;
+ z->p = z->buffer;
+ z->filbuf = zffilbuf;
+ z->u = f;
+ z->name = name;
+ return z;
+}
+
+
+/* --------------------------------------------------------------- read --- */
+size_t zread (ZIO *z, void *b, size_t n) {
+ while (n) {
+ size_t m;
+ if (z->n == 0) {
+ if (z->filbuf(z) == EOZ)
+ return n; /* return number of missing bytes */
+ zungetc(z); /* put result from `filbuf' in the buffer */
+ }
+ m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
+ memcpy(b, z->p, m);
+ z->n -= m;
+ z->p += m;
+ b = (char *)b + m;
+ n -= m;
+ }
+ return 0;
+}
diff --git a/src/lua/lzio.h b/src/lua/lzio.h
new file mode 100644
index 00000000..45feeee3
--- /dev/null
+++ b/src/lua/lzio.h
@@ -0,0 +1,53 @@
+/*
+** $Id: lzio.h,v 1.5 2004/06/04 13:42:10 neil Exp $
+** Buffered streams
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lzio_h
+#define lzio_h
+
+#include <stdio.h>
+
+
+
+/* For Lua only */
+#define zFopen luaZ_Fopen
+#define zsopen luaZ_sopen
+#define zmopen luaZ_mopen
+#define zread luaZ_read
+
+#define EOZ (-1) /* end of stream */
+
+typedef struct zio ZIO;
+
+ZIO* zFopen (ZIO* z, FILE* f, const char *name); /* open FILEs */
+ZIO* zsopen (ZIO* z, const char* s, const char *name); /* string */
+ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name); /* memory */
+
+size_t zread (ZIO* z, void* b, size_t n); /* read next n bytes */
+
+#define zgetc(z) (((z)->n--)>0 ? ((int)*(z)->p++): (z)->filbuf(z))
+#define zungetc(z) (++(z)->n,--(z)->p)
+#define zname(z) ((z)->name)
+
+
+
+/* --------- Private Part ------------------ */
+
+#ifndef ZBSIZE
+#define ZBSIZE 256 /* buffer size */
+#endif
+
+struct zio {
+ size_t n; /* bytes still unread */
+ const unsigned char* p; /* current position in buffer */
+ int (*filbuf)(ZIO* z);
+ void* u; /* additional data */
+ const char *name;
+ unsigned char buffer[ZBSIZE]; /* buffer */
+};
+
+
+#endif
diff --git a/src/lua/module.lua b/src/lua/module.lua
new file mode 100644
index 00000000..98dffe6e
--- /dev/null
+++ b/src/lua/module.lua
@@ -0,0 +1,69 @@
+-- tolua: module class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: module.lua,v 1.2 2001/11/26 23:00:26 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+
+-- Module class
+-- Represents module.
+-- The following fields are stored:
+-- {i} = list of objects in the module.
+classModule = {
+ _base = classContainer,
+ type = 'module'
+}
+settag(classModule,tolua_tag)
+
+-- register module
+function classModule:register ()
+ output(' tolua_module(tolua_S,"'..self.name..'");')
+ local i=1
+ while self[i] do
+ self[i]:register()
+ i = i+1
+ end
+end
+
+-- unregister module
+function classModule:unregister ()
+ output(' lua_pushnil(tolua_S); lua_setglobal(tolua_S,"'..self.name..'");')
+end
+
+-- Print method
+function classModule:print (ident,close)
+ print(ident.."Module{")
+ print(ident.." name = '"..self.name.."';")
+ local i=1
+ while self[i] do
+ self[i]:print(ident.." ",",")
+ i = i+1
+ end
+ print(ident.."}"..close)
+end
+
+-- Internal constructor
+function _Module (t)
+ t._base = classModule
+ settag(t,tolua_tag)
+ append(t)
+ return t
+end
+
+-- Constructor
+-- Expects two string representing the module name and body.
+function Module (n,b)
+ local t = _Module(_Container{name=n})
+ push(t)
+ t:parse(strsub(b,2,strlen(b)-1)) -- eliminate braces
+ pop()
+ return t
+end
+
+
diff --git a/src/lua/operator.lua b/src/lua/operator.lua
new file mode 100644
index 00000000..7a42cf1b
--- /dev/null
+++ b/src/lua/operator.lua
@@ -0,0 +1,111 @@
+-- tolua: operator class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: operator.lua,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Operator class
+-- Represents an operator function or a class operator method.
+-- It stores the same fields as functions do plus:
+-- kind = set of character representing the operator (as it appers in C++ code)
+classOperator = {
+ kind = '',
+ _base = classFunction,
+}
+settag(classOperator,tolua_tag)
+
+-- table to transform operator kind into the appropriate tag method name
+_TM = {['+'] = 'operator_add',
+ ['-'] = 'operator_sub',
+ ['*'] = 'operator_mul',
+ ['/'] = 'operator_div',
+ ['<'] = 'operator_lt',
+ ['[]'] = 'operator_get',
+ ['&[]'] = 'operator_set',
+ }
+
+
+-- Print method
+function classOperator:print (ident,close)
+ print(ident.."Operator{")
+ print(ident.." kind = '"..self.kind.."',")
+ print(ident.." mod = '"..self.mod.."',")
+ print(ident.." type = '"..self.type.."',")
+ print(ident.." ptr = '"..self.ptr.."',")
+ print(ident.." name = '"..self.name.."',")
+ print(ident.." const = '"..self.const.."',")
+ print(ident.." cname = '"..self.cname.."',")
+ print(ident.." lname = '"..self.lname.."',")
+ print(ident.." args = {")
+ local i=1
+ while self.args[i] do
+ self.args[i]:print(ident.." ",",")
+ i = i+1
+ end
+ print(ident.." }")
+ print(ident.."}"..close)
+end
+
+-- Internal constructor
+function _Operator (t)
+ t._base = classOperator
+ settag(t,tolua_tag)
+
+ if t.const ~= 'const' and t.const ~= '' then
+ error("#invalid 'const' specification")
+ end
+
+ append(t)
+ if not t:inclass() then
+ error("#operator can only be defined as class member")
+ end
+
+ t.cname = t:cfuncname("toluaI")..t:overload(t)
+ t.name = t.name..t.kind
+ return t
+end
+
+-- Constructor
+-- Expects three strings: one representing the function declaration,
+-- another representing the argument list, and the third representing
+-- the "const" or empty string.
+function Operator (d,k,a,c)
+ local t = split(strsub(a,2,strlen(a)-1),',') -- eliminate braces
+ local i=1
+ local l = {n=0}
+ while t[i] do
+ l.n = l.n+1
+ l[l.n] = Declaration(t[i],'var')
+ i = i+1
+ end
+ if k == '[]' then
+ d = gsub(d,'&','')
+ elseif k=='&[]' then
+ l.n = l.n+1
+ l[l.n] = Declaration(d,'var')
+ l[l.n].name = 'toluaI_value'
+ end
+ local f = Declaration(d,'func')
+ if k == '[]' and (l[1]==nil or isbasic(l[1].type)~='number') then
+ error('operator[] can only be defined for numeric index.')
+ end
+ f.args = l
+ f.const = c
+ f.kind = gsub(k,"%s","")
+ f.lname = _TM[f.kind]
+ if not f.lname then
+ error("tolua: no support for operator" .. f.kind)
+ end
+ if f.kind == '[]' and not strfind(f.mod,'const') then
+ Operator(d,'&'..k,a,c) -- create correspoding set operator
+ end
+ return _Operator(f)
+end
+
+
diff --git a/src/lua/package.lua b/src/lua/package.lua
new file mode 100644
index 00000000..42dbfaac
--- /dev/null
+++ b/src/lua/package.lua
@@ -0,0 +1,222 @@
+-- tolua: package class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: package.lua,v 1.4 2002/01/03 13:45:08 takkaria Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+
+-- Package class
+-- Represents the whole package being bound.
+-- The following fields are stored:
+-- {i} = list of objects in the package.
+classPackage = {
+ _base = classContainer,
+ type = 'package'
+}
+settag(classPackage,tolua_tag)
+
+-- Print method
+function classPackage:print ()
+ print("Package: "..self.name)
+ local i=1
+ while self[i] do
+ self[i]:print("","")
+ i = i+1
+ end
+end
+
+function classPackage:preprocess ()
+ self.code = "\n"..self.code -- add a blank sentinel line
+ -- avoid preprocessing verbatim lines
+ local V = {}
+ self.code = gsub(self.code,"\n(%s*%$[^%[%]][^\n]*)",function (v)
+ tinsert(%V,v)
+ return "\n$"..getn(%V).."$"
+ end)
+ -- avoid preprocessing embedded lua code
+ local C = {}
+ self.code = gsub(self.code,"\n%s*%$%[","\1") -- deal with embedded Lua code
+ self.code = gsub(self.code,"\n%s*%$%]","\2")
+ self.code = gsub(self.code,"(%b\1\2)", function (c)
+ tinsert(%C,c)
+ return "\n$["..getn(%C).."]$"
+ end)
+ -- perform global substitution
+
+ self.code = gsub(self.code,"(//[^\n]*)","") -- eliminate C++ comments
+ self.code = gsub(self.code,"/%*","\1")
+ self.code = gsub(self.code,"%*/","\2")
+ self.code = gsub(self.code,"%b\1\2","")
+ self.code = gsub(self.code,"\1","/%*")
+ self.code = gsub(self.code,"\2","%*/")
+ self.code = gsub(self.code,"%s*@%s*","@") -- eliminate spaces beside @
+ self.code = gsub(self.code,"%s?inline(%s)","%1") -- eliminate 'inline' keyword
+ self.code = gsub(self.code,"%s?extern(%s)","%1") -- eliminate 'extern' keyword
+ self.code = gsub(self.code,"%s?virtual(%s)","%1") -- eliminate 'virtual' keyword
+ self.code = gsub(self.code,"public:","") -- eliminate 'public:' keyword
+ self.code = gsub(self.code,"([^%w_])void%s*%*","%1_userdata ") -- substitute 'void*'
+ self.code = gsub(self.code,"([^%w_])void%s*%*","%1_userdata ") -- substitute 'void*'
+ self.code = gsub(self.code,"([^%w_])char%s*%*","%1_cstring ") -- substitute 'char*'
+
+ -- restore embedded code
+ self.code = gsub(self.code,"%$%[(%d+)%]%$",function (n)
+ return %C[tonumber(n)]
+ end)
+ -- restore verbatim lines
+ self.code = gsub(self.code,"%$(%d+)%$",function (n)
+ return %V[tonumber(n)]
+ end)
+end
+
+-- translate verbatim
+function classPackage:preamble ()
+ output('/*\n')
+ output('** Lua binding: '..self.name..'\n')
+ output('** Generated automatically by '..TOLUA_VERSION..'\n')
+ output('*/\n\n')
+
+ output('#include "lua/tolua.h"\n\n')
+
+ if not flags.h then
+ output('/* Exported function */')
+ output('int tolua_'..self.name..'_open (lua_State* tolua_S);')
+ output('void tolua_'..self.name..'_close (lua_State* tolua_S);')
+ output('\n')
+ end
+
+ local i=1
+ while self[i] do
+ self[i]:preamble()
+ i = i+1
+ end
+ output('\n')
+ output('/* function to register type */')
+ output('static void toluaI_reg_types (lua_State* tolua_S)')
+ output('{')
+ foreach(_usertype,function(n,v) output(' tolua_usertype(tolua_S,"',v,'");') end)
+ output('}')
+ output('\n')
+
+ output('/* error messages */')
+ output('#define TOLUA_ERR_SELF tolua_error(tolua_S,\"invalid \'self\'\")')
+ output('#define TOLUA_ERR_ASSIGN tolua_error(tolua_S,\"#vinvalid type in variable assignment.\")')
+ output('\n')
+end
+
+-- register package
+-- write package open function
+function classPackage:register ()
+ output("/* Open function */")
+ output("int tolua_"..self.name.."_open (lua_State* tolua_S)")
+ output("{")
+ output(" tolua_open(tolua_S);")
+ output(" toluaI_reg_types(tolua_S);")
+ local i=1
+ while self[i] do
+ self[i]:register()
+ i = i+1
+ end
+ output(" return 1;")
+ output("}")
+end
+
+-- unregister package
+-- write package close function
+function classPackage:unregister ()
+ output("/* Close function */")
+ output("void tolua_"..self.name.."_close (lua_State* tolua_S)")
+ output("{")
+ local i=1
+ while self[i] do
+ self[i]:unregister()
+ i = i+1
+ end
+ output("}")
+end
+
+-- write header file
+function classPackage:header ()
+ output('/*\n') output('** Lua binding: '..self.name..'\n')
+ output('** Generated automatically by '..TOLUA_VERSION..'.\n')
+ output('*/\n\n')
+
+ if not flags.h then
+ output('/* Exported function */')
+ output('int tolua_'..self.name..'_open (lua_State* tolua_S);')
+ output('void tolua_'..self.name..'_close (lua_State* tolua_S);')
+ output('\n')
+ end
+end
+
+-- Internal constructor
+function _Package (t)
+ t._base = classPackage
+ settag(t,tolua_tag)
+ return t
+end
+
+-- Constructor
+-- Expects the base file name.
+-- It assumes the file has extension ".pkg".
+function Package (name)
+ -- read file
+ local code = read("*a")
+ code = "\n" .. code -- add sentinel
+ -- deal with include directive
+ local nsubst
+ repeat
+ code,nsubst = gsub(code,"\n%s*%$<(.-)>%s*\n",function (fn)
+ local fp,msg = openfile(fn,'r')
+ if not fp then
+ error('#'..msg..': '..fn)
+ end
+ local s = read(fp,'*a')
+ closefile(fp)
+ return "\n" .. s
+ end)
+ until nsubst==0
+
+ -- deal with include directive for C/C++ header files
+ local nsubst
+ repeat
+ code,nsubst =
+ gsub(code,"\n%s*%${(.-)}%s*\n",
+ function (fn)
+ local fp,msg = openfile(fn,'r')
+ if not fp then
+ error('#'..msg..': '..fn)
+ end
+ local s = read(fp,'*a')
+ closefile(fp)
+ -- extract marked code
+ local T = {code="\n"}
+ s= "\n" .. s .. "\n" -- add blank lines as sentinels
+ -- extract one-line statments
+ gsub(s,"\n(.-)[Tt][Oo][Ll][Uu][Aa]_[Ee][Xx][Pp][Oo][Rr][Tt][^\n]*\n",
+ function (c) %T.code = %T.code .. c .. "\n" end
+ )
+ -- extract multiline statments
+ gsub(s,"\n[^\n]*[Tt][Oo][Ll][Uu][Aa]_[Bb][Ee][Gg][Ii][Nn][^\n]*"..
+ "(.-)" ..
+ "\n[^\n]*[Tt][Oo][Ll][Uu][Aa]_[Ee][Nn][Dd][^\n]*\n",
+ function (c) %T.code = %T.code .. c .. "\n" end
+ )
+ return T.code
+ end)
+ until nsubst==0
+
+ local t = _Package(_Container{name=name, code=code})
+ push(t)
+ t:preprocess()
+ t:parse(t.code)
+ pop()
+ return t
+end
+
+
diff --git a/src/lua/print.h b/src/lua/print.h
new file mode 100644
index 00000000..49f4c4cb
--- /dev/null
+++ b/src/lua/print.h
@@ -0,0 +1,55 @@
+/*
+** $Id: print.h,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+** extracted automatically from lopcodes.h by mkprint.lua -- DO NOT EDIT
+** See Copyright Notice in lua.h
+*/
+
+ case OP_END: P_OP("END"); P_NONE; break;
+ case OP_RETURN: P_OP("RETURN"); P_U; break;
+ case OP_CALL: P_OP("CALL"); P_AB; break;
+ case OP_TAILCALL: P_OP("TAILCALL"); P_AB; break;
+ case OP_PUSHNIL: P_OP("PUSHNIL"); P_U; break;
+ case OP_POP: P_OP("POP"); P_U; break;
+ case OP_PUSHINT: P_OP("PUSHINT"); P_S; break;
+ case OP_PUSHSTRING: P_OP("PUSHSTRING"); P_Q; break;
+ case OP_PUSHNUM: P_OP("PUSHNUM"); P_N; break;
+ case OP_PUSHNEGNUM: P_OP("PUSHNEGNUM"); P_N; break;
+ case OP_PUSHUPVALUE: P_OP("PUSHUPVALUE"); P_U; break;
+ case OP_GETLOCAL: P_OP("GETLOCAL"); P_L; break;
+ case OP_GETGLOBAL: P_OP("GETGLOBAL"); P_K; break;
+ case OP_GETTABLE: P_OP("GETTABLE"); P_NONE; break;
+ case OP_GETDOTTED: P_OP("GETDOTTED"); P_K; break;
+ case OP_GETINDEXED: P_OP("GETINDEXED"); P_L; break;
+ case OP_PUSHSELF: P_OP("PUSHSELF"); P_K; break;
+ case OP_CREATETABLE: P_OP("CREATETABLE"); P_U; break;
+ case OP_SETLOCAL: P_OP("SETLOCAL"); P_L; break;
+ case OP_SETGLOBAL: P_OP("SETGLOBAL"); P_K; break;
+ case OP_SETTABLE: P_OP("SETTABLE"); P_AB; break;
+ case OP_SETLIST: P_OP("SETLIST"); P_AB; break;
+ case OP_SETMAP: P_OP("SETMAP"); P_U; break;
+ case OP_ADD: P_OP("ADD"); P_NONE; break;
+ case OP_ADDI: P_OP("ADDI"); P_S; break;
+ case OP_SUB: P_OP("SUB"); P_NONE; break;
+ case OP_MULT: P_OP("MULT"); P_NONE; break;
+ case OP_DIV: P_OP("DIV"); P_NONE; break;
+ case OP_POW: P_OP("POW"); P_NONE; break;
+ case OP_CONCAT: P_OP("CONCAT"); P_U; break;
+ case OP_MINUS: P_OP("MINUS"); P_NONE; break;
+ case OP_NOT: P_OP("NOT"); P_NONE; break;
+ case OP_JMPNE: P_OP("JMPNE"); P_J; break;
+ case OP_JMPEQ: P_OP("JMPEQ"); P_J; break;
+ case OP_JMPLT: P_OP("JMPLT"); P_J; break;
+ case OP_JMPLE: P_OP("JMPLE"); P_J; break;
+ case OP_JMPGT: P_OP("JMPGT"); P_J; break;
+ case OP_JMPGE: P_OP("JMPGE"); P_J; break;
+ case OP_JMPT: P_OP("JMPT"); P_J; break;
+ case OP_JMPF: P_OP("JMPF"); P_J; break;
+ case OP_JMPONT: P_OP("JMPONT"); P_J; break;
+ case OP_JMPONF: P_OP("JMPONF"); P_J; break;
+ case OP_JMP: P_OP("JMP"); P_J; break;
+ case OP_PUSHNILJMP: P_OP("PUSHNILJMP"); P_NONE; break;
+ case OP_FORPREP: P_OP("FORPREP"); P_J; break;
+ case OP_FORLOOP: P_OP("FORLOOP"); P_J; break;
+ case OP_LFORPREP: P_OP("LFORPREP"); P_J; break;
+ case OP_LFORLOOP: P_OP("LFORLOOP"); P_J; break;
+ case OP_CLOSURE: P_OP("CLOSURE"); P_F; break;
diff --git a/src/lua/tolua.c b/src/lua/tolua.c
new file mode 100644
index 00000000..3cb09291
--- /dev/null
+++ b/src/lua/tolua.c
@@ -0,0 +1,149 @@
+/* tolua
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua.c,v 1.4 2004/06/04 13:42:10 neil Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+#include "tolua.h"
+#include "lua.h"
+#include "lualib.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static void help (void)
+{
+ fprintf(stderr,"\n"
+ "usage: tolua [options] input_file\n"
+ "\n"
+ "Command line options are:\n"
+ " -v : print version information.\n"
+ " -o file : set output file; default is stdout.\n"
+ " -H file : create include file.\n"
+ " -n name : set package name; default is input file root name.\n"
+ " -p : parse only.\n"
+ " -P : parse and print structure information (for debug).\n"
+ " -h : print this message.\n"
+ "Should the input file be omitted, stdin is assumed;\n"
+ "in that case, the package name must be explicitly set.\n\n"
+ );
+}
+
+static void version (void)
+{
+ fprintf(stderr, "%s (written by W. Celes)\n",TOLUA_VERSION);
+}
+
+static void setfield (lua_State* L, int table, char* f, char* v)
+{
+ lua_pushstring(L,f);
+ lua_pushstring(L,v);
+ lua_settable(L,table);
+}
+
+static void error (char* o)
+{
+ fprintf(stderr,"tolua: unknown option '%s'\n",o);
+ help();
+ exit(1);
+}
+
+int main (int argc, char* argv[])
+{
+ lua_State* L = lua_open(0);
+ lua_baselibopen(L);
+ lua_iolibopen(L);
+ lua_strlibopen(L);
+ lua_pushstring(L,TOLUA_VERSION); lua_setglobal(L,"TOLUA_VERSION");
+
+ if (argc==1)
+ {
+ help();
+ return 0;
+ }
+ else
+ {
+ int i, t;
+ lua_newtable(L);
+ lua_pushvalue(L,-1);
+ lua_setglobal(L,"flags");
+ t = lua_gettop(L);
+ for (i=1; i<argc; ++i)
+ {
+ if (*argv[i] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'v': version(); return 0;
+ case 'h': help(); return 0;
+ case 'p': setfield(L,t,"p",""); break;
+ case 'P': setfield(L,t,"P",""); break;
+ case 'o': setfield(L,t,"o",argv[++i]); break;
+ case 'n': setfield(L,t,"n",argv[++i]); break;
+ case 'H': setfield(L,t,"H",argv[++i]); break;
+ default: error(argv[i]); break;
+ }
+ }
+ else
+ {
+ setfield(L,t,"f",argv[i]);
+ break;
+ }
+ }
+ lua_pop(L,1);
+ }
+
+#if 1
+ {
+ int tolua_tolualua_open(lua_State* L);
+ tolua_tolualua_open(L);
+ }
+#else
+ {
+ int i;
+ char* p;
+ char path[BUFSIZ];
+ char* files[] = {
+ "basic.lua",
+ "feature.lua",
+ "verbatim.lua",
+ "code.lua",
+ "typedef.lua",
+ "container.lua",
+ "package.lua",
+ "module.lua",
+ "define.lua",
+ "enumerate.lua",
+ "declaration.lua",
+ "variable.lua",
+ "array.lua",
+ "function.lua",
+ "operator.lua",
+ "class.lua",
+ "clean.lua",
+ "doit.lua",
+ NULL
+ };
+ strcpy(path,argv[0]);
+ p = strrchr(path,'/');
+ p = (p==NULL) ? path : p+1;
+ for (i=0; files[i]; ++i)
+ {
+ sprintf(p,"%s",files[i]);
+ lua_dofile(L,path);
+ }
+ }
+
+#endif
+ return 0;
+}
diff --git a/src/lua/tolua.h b/src/lua/tolua.h
new file mode 100644
index 00000000..ab86976c
--- /dev/null
+++ b/src/lua/tolua.h
@@ -0,0 +1,127 @@
+/* tolua - Support code for Lua bindings.
+** Written by Waldemar Celes (celes@tecgraf.puc-rio.br)
+** TeCGraf/PUC-Rio
+** http://www.tecgraf.puc-rio.br/~celes/tolua
+** Jul 1998
+** $Id: tolua.h,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+
+#ifndef tolua_h
+#define tolua_h
+
+#define TOLUA_VERSION "tolua 4.0a - angband"
+
+
+#include <stdlib.h> /* NULL, malloc, free */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "lua.h"
+
+/* Evil hack for C++ bool_ vs. C bool. */
+#ifndef __cplusplus
+typedef unsigned char bool;
+#endif
+
+/*************************************** Exported functions */
+
+int tolua_open (lua_State* L);
+void tolua_using (lua_State* L, int module);
+void tolua_class (lua_State* L, int derived, int base);
+void tolua_instance (lua_State* L, int instance, int classobj);
+void tolua_foreach (lua_State* L, int lo, int f);
+int tolua_tag (lua_State* L, char* type);
+const char* tolua_type (lua_State* L, int lo);
+int tolua_base (lua_State* L, int lo);
+int tolua_cast (lua_State* L, int lo, char* type);
+void tolua_takeownership (lua_State* L, int lo);
+
+
+
+/*************************************** Support functions for binding code */
+
+#define LUA_VALUE int
+#define LUA_NIL 0 /* TODO */
+/*#define TOLUA_NIL (lua_pushnil(),lua_pop())*/
+
+/* Register functions */
+void tolua_globalvar (lua_State* L, char* name, lua_CFunction get, lua_CFunction set);
+void tolua_globalarray (lua_State* L, char* name, lua_CFunction get, lua_CFunction set);
+void tolua_module (lua_State* L, char* name);
+void tolua_cclass (lua_State* L, char* name, char* base);
+void tolua_function (lua_State* L, char* parent, char* name, lua_CFunction func);
+void tolua_constant (lua_State* L, char* parent, char* name, long value);
+void tolua_tablevar
+(lua_State* L, char* table, char* name, lua_CFunction get, lua_CFunction set);
+void tolua_tablearray
+(lua_State* L, char* table, char* name, lua_CFunction get, lua_CFunction set);
+
+
+/* Get and push functions */
+long tolua_getnumber (lua_State* L, int narg, long def);
+const char* tolua_getstring (lua_State* L, int narg, const char* def);
+void* tolua_getuserdata (lua_State* L, int narg, void* def);
+void* tolua_getusertype (lua_State* L, int narg, void* def);
+int tolua_getvalue (lua_State* L, int narg, int def);
+int tolua_getbool (lua_State* L, int narg, int def);
+long tolua_getfieldnumber (lua_State* L, int lo, int index, long def);
+const char* tolua_getfieldstring (lua_State* L, int lo, int index, const char* def);
+void* tolua_getfielduserdata (lua_State* L, int lo, int index, void* def);
+void* tolua_getfieldusertype (lua_State* L, int lo, int index, void* def);
+int tolua_getfieldvalue (lua_State* L, int lo, int index, int def);
+int tolua_getfieldbool (lua_State* L, int lo, int index, int def);
+
+void tolua_pushnumber (lua_State* L, long value);
+void tolua_pushstring (lua_State* L, const char* value);
+void tolua_pushuserdata (lua_State* L, void* value);
+void tolua_pushusertype (lua_State* L, void* value, int tag);
+void tolua_pushvalue (lua_State* L, int lo);
+void tolua_pushbool (lua_State* L, int value);
+void tolua_pushfieldnumber (lua_State* L, int lo, int index, long v);
+void tolua_pushfieldstring (lua_State* L, int lo, int index, char* v);
+void tolua_pushfielduserdata (lua_State* L, int lo, int index, void* v);
+void tolua_pushfieldusertype (lua_State* L, int lo, int index, void* v, int tag);
+void tolua_pushfieldvalue (lua_State* L, int lo, int index, int v);
+void tolua_pushfieldbool (lua_State* L, int lo, int index, int v);
+
+
+/* Type & tag manipulation */
+void tolua_usertype (lua_State* L, char* type);
+#if 0
+void tolua_settag (lua_State* L, char* type, int* tag);
+#endif
+int tolua_istype (lua_State* L, int narg, int tag, int dim);
+int tolua_arrayistype (lua_State* L, int narg, int tag, int dim, int def);
+
+int tolua_isnoobj (lua_State* L, int narg);
+
+/* Tag method manipulation */
+void* tolua_doclone (lua_State* L, void* value, int tag);
+void* tolua_copy (lua_State* L, void* value, unsigned int size);
+
+/* Error handling */
+void tolua_error (lua_State* L, char* msg);
+
+/* Exported variables */
+extern int tolua_tag_nil;
+extern int tolua_tag_number;
+extern int tolua_tag_string;
+extern int tolua_tag_userdata;
+extern int tolua_tag_table;
+extern int tolua_tag_function;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/lua/tolua_bd.c b/src/lua/tolua_bd.c
new file mode 100644
index 00000000..d36a5ce9
--- /dev/null
+++ b/src/lua/tolua_bd.c
@@ -0,0 +1,214 @@
+/*
+** Lua binding: tolua
+** Generated automatically by tolua 4.0b on Tue Nov 14 14:18:50 2000.
+*/
+
+#include "tolua.h"
+
+/* Exported function */
+int tolua_tolua_open (lua_State* tolua_S);
+void tolua_tolua_close (lua_State* tolua_S);
+
+#define tolua_using(module) (tolua_using)(tolua_S,module)
+#define tolua_type(lo) (tolua_type)(tolua_S,lo)
+#define tolua_foreach(lo,f) (tolua_foreach)(tolua_S,lo,f)
+#define tolua_class(derived,base) (tolua_class)(tolua_S,derived,base)
+#define tolua_instance(inst,cobj) (tolua_instance)(tolua_S,inst,cobj)
+#define tolua_base(lo) (tolua_base)(tolua_S,lo)
+#define tolua_cast(lo,type) (tolua_cast)(tolua_S,lo,type)
+#define tolua_takeownership(lo) (tolua_takeownership)(tolua_S,lo)
+
+/* function to register type */
+static void toluaI_reg_types (lua_State* tolua_S)
+{
+}
+
+/* function: tolua_using */
+static int toluaI_tolua_tolua_using00(lua_State* tolua_S)
+{
+ if (
+ !tolua_isnoobj(tolua_S,2)
+ )
+ goto tolua_lerror;
+ else
+ {
+ LUA_VALUE module = ((LUA_VALUE) tolua_getvalue(tolua_S,1,0));
+ {
+ tolua_using(module);
+ }
+ }
+ return 0;
+tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'using'.");
+ return 0;
+}
+
+/* function: tolua_type */
+static int toluaI_tolua_tolua_type00(lua_State* tolua_S)
+{
+ if (
+ !tolua_isnoobj(tolua_S,2)
+ )
+ goto tolua_lerror;
+ else
+ {
+ LUA_VALUE lo = ((LUA_VALUE) tolua_getvalue(tolua_S,1,0));
+ {
+ char* toluaI_ret = (char*) tolua_type(lo);
+ tolua_pushstring(tolua_S,toluaI_ret);
+ }
+ }
+ return 1;
+tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'type'.");
+ return 0;
+}
+
+/* function: tolua_foreach */
+static int toluaI_tolua_tolua_foreach00(lua_State* tolua_S)
+{
+ if (
+ !tolua_isnoobj(tolua_S,3)
+ )
+ goto tolua_lerror;
+ else
+ {
+ LUA_VALUE lo = ((LUA_VALUE) tolua_getvalue(tolua_S,1,0));
+ LUA_VALUE f = ((LUA_VALUE) tolua_getvalue(tolua_S,2,0));
+ {
+ tolua_foreach(lo,f);
+ }
+ }
+ return 0;
+tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'foreach'.");
+ return 0;
+}
+
+/* function: tolua_class */
+static int toluaI_tolua_tolua_class00(lua_State* tolua_S)
+{
+ if (
+ !tolua_isnoobj(tolua_S,3)
+ )
+ goto tolua_lerror;
+ else
+ {
+ LUA_VALUE derived = ((LUA_VALUE) tolua_getvalue(tolua_S,1,0));
+ LUA_VALUE base = ((LUA_VALUE) tolua_getvalue(tolua_S,2,0));
+ {
+ tolua_class(derived,base);
+ }
+ }
+ return 0;
+tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'class'.");
+ return 0;
+}
+
+/* function: tolua_instance */
+static int toluaI_tolua_tolua_instance00(lua_State* tolua_S)
+{
+ if (
+ !tolua_isnoobj(tolua_S,3)
+ )
+ goto tolua_lerror;
+ else
+ {
+ LUA_VALUE instance = ((LUA_VALUE) tolua_getvalue(tolua_S,1,0));
+ LUA_VALUE classobj = ((LUA_VALUE) tolua_getvalue(tolua_S,2,0));
+ {
+ tolua_instance(instance,classobj);
+ }
+ }
+ return 0;
+tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'instance'.");
+ return 0;
+}
+
+/* function: tolua_base */
+static int toluaI_tolua_tolua_base00(lua_State* tolua_S)
+{
+ if (
+ !tolua_isnoobj(tolua_S,2)
+ )
+ goto tolua_lerror;
+ else
+ {
+ LUA_VALUE lo = ((LUA_VALUE) tolua_getvalue(tolua_S,1,0));
+ {
+ LUA_VALUE toluaI_ret = (LUA_VALUE) tolua_base(lo);
+ tolua_pushvalue(tolua_S,toluaI_ret);
+ }
+ }
+ return 1;
+tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'base'.");
+ return 0;
+}
+
+/* function: tolua_cast */
+static int toluaI_tolua_tolua_cast00(lua_State* tolua_S)
+{
+ if (
+ !tolua_istype(tolua_S,2,LUA_TSTRING,0) ||
+ !tolua_isnoobj(tolua_S,3)
+ )
+ goto tolua_lerror;
+ else
+ {
+ LUA_VALUE lo = ((LUA_VALUE) tolua_getvalue(tolua_S,1,0));
+ char* type = ((char*) tolua_getstring(tolua_S,2,0));
+ {
+ LUA_VALUE toluaI_ret = (LUA_VALUE) tolua_cast(lo,type);
+ tolua_pushvalue(tolua_S,toluaI_ret);
+ }
+ }
+ return 1;
+tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'cast'.");
+ return 0;
+}
+
+/* function: tolua_takeownership */
+static int toluaI_tolua_tolua_takeownership00(lua_State* tolua_S)
+{
+ if (
+ !tolua_isnoobj(tolua_S,2)
+ )
+ goto tolua_lerror;
+ else
+ {
+ LUA_VALUE lo = ((LUA_VALUE) tolua_getvalue(tolua_S,1,0));
+ {
+ tolua_takeownership(lo);
+ }
+ }
+ return 0;
+tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'takeownership'.");
+ return 0;
+}
+
+/* Open function */
+int tolua_tolua_open (lua_State* tolua_S)
+{
+ tolua_open(tolua_S);
+ toluaI_reg_types(tolua_S);
+ tolua_module(tolua_S,"tolua");
+ tolua_function(tolua_S,"tolua","using",toluaI_tolua_tolua_using00);
+ tolua_function(tolua_S,"tolua","type",toluaI_tolua_tolua_type00);
+ tolua_function(tolua_S,"tolua","foreach",toluaI_tolua_tolua_foreach00);
+ tolua_function(tolua_S,"tolua","class",toluaI_tolua_tolua_class00);
+ tolua_function(tolua_S,"tolua","instance",toluaI_tolua_tolua_instance00);
+ tolua_function(tolua_S,"tolua","base",toluaI_tolua_tolua_base00);
+ tolua_function(tolua_S,"tolua","cast",toluaI_tolua_tolua_cast00);
+ tolua_function(tolua_S,"tolua","takeownership",toluaI_tolua_tolua_takeownership00);
+ return 1;
+}
+/* Close function */
+void tolua_tolua_close (lua_State* tolua_S)
+{
+ lua_pushnil(tolua_S); lua_setglobal(tolua_S,"tolua");
+}
diff --git a/src/lua/tolua_eh.c b/src/lua/tolua_eh.c
new file mode 100644
index 00000000..0709cb4c
--- /dev/null
+++ b/src/lua/tolua_eh.c
@@ -0,0 +1,66 @@
+/* tolua: error handling
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua_eh.c,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+#include "tolua.h"
+#include "tolua_eh.h"
+#include "tolua_rg.h"
+
+#include <stdio.h>
+
+/* registry fiels used to hold current error info
+ - tolua_err_narg: number of wrong argument
+ - tolua_err_provided: provided type
+ - tolua_err_expected: expected type
+*/
+
+void toluaI_eh_set
+(lua_State* L, int narg, const char* provided, const char* expected)
+{
+ lua_pushnumber(L,narg);
+ toluaI_setregistry(L,"tolua_err_narg");
+ lua_pushstring(L,provided);
+ toluaI_setregistry(L,"tolua_err_provided");
+ lua_pushstring(L,expected);
+ toluaI_setregistry(L,"tolua_err_expected");
+}
+
+void tolua_error (lua_State* L, char* msg)
+{
+ if (msg[0]=='#')
+ {
+ static char buffer[BUFSIZ];
+ const char* err_provided;
+ const char* err_expected;
+ toluaI_getregistry(L,"tolua_err_provided");
+ err_provided = lua_tostring(L,-1);
+ toluaI_getregistry(L,"tolua_err_expected");
+ err_expected = lua_tostring(L,-1);
+ lua_pop(L,2);
+ if (msg[1]=='f')
+ {
+ int err_narg;
+ toluaI_getregistry(L,"tolua_err_narg");
+ err_narg = (int)lua_tonumber(L,-1);
+ lua_pop(L,1);
+ sprintf(buffer,"%s\n argument #%d is '%s'; '%s' expected.\n",
+ msg+2,err_narg,err_provided,err_expected);
+ }
+ else if (msg[1]=='v')
+ sprintf(buffer,"%s\n value is '%s'; '%s' expected.\n",
+ msg+2,err_provided,err_expected);
+ lua_error(L,buffer);
+ }
+ else
+ lua_error(L,msg);
+}
diff --git a/src/lua/tolua_eh.h b/src/lua/tolua_eh.h
new file mode 100644
index 00000000..168ba122
--- /dev/null
+++ b/src/lua/tolua_eh.h
@@ -0,0 +1,24 @@
+/* tolua: error handling
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua_eh.h,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+
+
+#ifndef tolua_eh_h
+#define tolua_eh_h
+
+void toluaI_eh_set
+(lua_State* L, int narg, const char* provided, const char* expected);
+
+
+#endif
diff --git a/src/lua/tolua_gp.c b/src/lua/tolua_gp.c
new file mode 100644
index 00000000..77ff0c26
--- /dev/null
+++ b/src/lua/tolua_gp.c
@@ -0,0 +1,197 @@
+/* tolua: get & push functions.
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua_gp.c,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+#include "tolua.h"
+#include "tolua_tm.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+long tolua_getnumber (lua_State* L, int narg, long def)
+{
+ return lua_gettop(L)<abs(narg) ? def : lua_tonumber(L,narg);
+}
+
+const char* tolua_getstring (lua_State* L, int narg, const char* def)
+{
+ return lua_gettop(L)<abs(narg) ? def : lua_tostring(L,narg);
+}
+
+void* tolua_getuserdata (lua_State* L, int narg, void* def)
+{
+ return lua_gettop(L)<abs(narg) ? def : lua_touserdata(L,narg);
+}
+
+void* tolua_getusertype (lua_State* L, int narg, void* def)
+{
+ return lua_gettop(L)<abs(narg) ? def : lua_touserdata(L,narg);
+}
+
+int tolua_getvalue (lua_State* L, int narg, int def)
+{
+ return lua_gettop(L)<abs(narg) ? def : narg;
+}
+
+int tolua_getbool (lua_State* L, int narg, int def)
+{
+ return lua_gettop(L)<abs(narg) ?
+ def :
+ lua_isnil(L,narg) ? 0 : lua_tonumber(L,narg)!=0;
+}
+
+long tolua_getfieldnumber (lua_State* L, int lo, int index, long def)
+{
+ long v;
+ lua_pushnumber(L,index);
+ lua_gettable(L,lo);
+ v = lua_isnil(L,-1) ? def : lua_tonumber(L,-1);
+ lua_pop(L,1);
+ return v;
+}
+
+const char* tolua_getfieldstring
+(lua_State* L, int lo, int index, const char* def)
+{
+ const char* v;
+ lua_pushnumber(L,index);
+ lua_gettable(L,lo);
+ v = lua_isnil(L,-1) ? def : lua_tostring(L,-1);
+ lua_pop(L,1);
+ return v;
+}
+
+void* tolua_getfielduserdata (lua_State* L, int lo, int index, void* def)
+{
+ void* v;
+ lua_pushnumber(L,index);
+ lua_gettable(L,lo);
+ v = lua_isnil(L,-1) ? def : lua_touserdata(L,-1);
+ lua_pop(L,1);
+ return v;
+}
+
+void* tolua_getfieldusertype (lua_State* L, int lo, int index, void* def)
+{
+ void* v;
+ lua_pushnumber(L,index);
+ lua_gettable(L,lo);
+ v = lua_isnil(L,-1) ? def : lua_touserdata(L,-1);
+ lua_pop(L,1);
+ return v;
+}
+
+int tolua_getfieldvalue (lua_State* L, int lo, int index, int def)
+{
+ int v;
+ lua_pushnumber(L,index);
+ lua_gettable(L,lo);
+ v = lua_isnil(L,-1) ? def : lo;
+ lua_pop(L,1);
+ return v;
+}
+
+int tolua_getfieldbool (lua_State* L, int lo, int index, int def)
+{
+ int v;
+ lua_pushnumber(L,index);
+ lua_gettable(L,lo);
+ v = lua_isnil(L,-1) ? 0 : lua_tonumber(L,-1)!=0;
+ lua_pop(L,1);
+ return v;
+}
+
+void tolua_pushnumber (lua_State* L, long value)
+{
+ lua_pushnumber(L,value);
+}
+
+void tolua_pushstring (lua_State* L, const char* value)
+{
+ if (value == NULL)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L,value);
+}
+
+void tolua_pushuserdata (lua_State* L, void* value)
+{
+ if (value == NULL)
+ lua_pushnil(L);
+ else
+ lua_pushuserdata(L,value);
+}
+
+void tolua_pushusertype (lua_State* L, void* value, int tag)
+{
+ if (value == NULL)
+ lua_pushnil(L);
+ else
+ lua_pushusertag(L,value,tag);
+}
+
+void tolua_pushvalue (lua_State* L, int lo)
+{
+ lua_pushvalue(L,lo);
+}
+
+void tolua_pushbool (lua_State* L, int value)
+{
+ if (value)
+ lua_pushnumber(L,(long)value);
+ else
+ lua_pushnil(L);
+}
+
+void tolua_pushfieldnumber (lua_State* L, int lo, int index, long v)
+{
+ lua_pushnumber(L,index);
+ tolua_pushnumber(L,v);
+ lua_settable(L,lo);
+}
+
+void tolua_pushfieldstring (lua_State* L, int lo, int index, char* v)
+{
+ lua_pushnumber(L,index);
+ tolua_pushstring(L,v);
+ lua_settable(L,lo);
+}
+
+void tolua_pushfielduserdata (lua_State* L, int lo, int index, void* v)
+{
+ lua_pushnumber(L,index);
+ tolua_pushuserdata(L,v);
+ lua_settable(L,lo);
+}
+
+void tolua_pushfieldusertype (lua_State* L, int lo, int index, void* v, int tag)
+{
+ lua_pushnumber(L,index);
+ tolua_pushusertype(L,v,tag);
+ lua_settable(L,lo);
+}
+
+void tolua_pushfieldvalue (lua_State* L, int lo, int index, int v)
+{
+ lua_pushnumber(L,index);
+ lua_pushvalue(L,v);
+ lua_settable(L,lo);
+}
+
+void tolua_pushfieldbool (lua_State* L, int lo, int index, int v)
+{
+ lua_pushnumber(L,index);
+ tolua_pushbool(L,v);
+ lua_settable(L,lo);
+}
+
diff --git a/src/lua/tolua_lb.c b/src/lua/tolua_lb.c
new file mode 100644
index 00000000..5fd4c337
--- /dev/null
+++ b/src/lua/tolua_lb.c
@@ -0,0 +1,160 @@
+/* tolua
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua_lb.c,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+#include "tolua.h"
+#include "tolua_rg.h"
+#include "tolua_tm.h"
+#include "tolua_tt.h"
+
+
+int tolua_open (lua_State* L)
+{
+ int tolua_tolua_open (lua_State* L);
+ /* check if alread opened */
+ toluaI_getregistry(L,"TOLUA");
+ if (lua_isnil(L,-1))
+ {
+ lua_pushnumber(L,1);
+ toluaI_setregistry(L,"TOLUA");
+ toluaI_tt_init(L);
+ toluaI_tm_init(L);
+ lua_getglobal(L,"foreach");
+ toluaI_setregistry(L,"tolua_orig_foreach");
+ tolua_tolua_open(L); /* opens tolua own binding */
+ }
+ lua_pop(L,1);
+ return 1;
+}
+
+void tolua_using (lua_State* L, int module)
+{
+ toluaI_tm_using(L,module);
+}
+
+void tolua_class (lua_State* L, int derived, int base)
+{
+ int tag = lua_newtag(L); /* new tag of instances of that class */
+ toluaI_tm_setclass(L,derived);
+ toluaI_tm_linstance(L,tag,derived);
+ lua_pushvalue(L,derived);
+ lua_pushstring(L,".base");
+ lua_pushvalue(L,base);
+ lua_rawset(L,-3);
+ lua_pushstring(L,".itag");
+ lua_pushnumber(L,tag);
+ lua_rawset(L,-3);
+ lua_pop(L,1);
+}
+
+void tolua_instance (lua_State* L, int instance, int classobj)
+{
+ int tag;
+ lua_pushvalue(L,classobj);
+ lua_pushstring(L,".itag");
+ lua_gettable(L,-2);
+ tag = (int) lua_tonumber(L,-1);
+ lua_pop(L,2); /* number and table */
+ if (tag==0)
+ tolua_error(L,"unregistered 'classobj' in function 'tolua_instance'.");
+ lua_pushvalue(L,instance);
+ lua_settag(L,tag);
+ lua_pop(L,1);
+}
+
+static int filter (lua_State* L)
+{
+ int n = 1; /* name */
+ int v = 2; /* value */
+ int f = lua_gettop(L); /* function */
+ /* do not pass string fields starting with a dot */
+ if (!lua_isstring(L,n) || *lua_tostring(L,n)!='.')
+ {
+ lua_pushvalue(L,f);
+ lua_pushvalue(L,n);
+ lua_pushvalue(L,v);
+ lua_call(L,2,1);
+ }
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+void tolua_foreach (lua_State* L, int lo, int f)
+{
+ if (toluaI_tt_isusertype(L,lo))
+ {
+ toluaI_tm_pushmate(L,lo);
+ if (lua_isnil(L,-1))
+ return; /* no field in mate table */
+ else
+ lo = lua_gettop(L);
+ }
+ toluaI_getregistry(L,"tolua_orig_foreach");
+ lua_pushvalue(L,lo);
+ lua_pushvalue(L,f);
+ lua_pushcclosure(L,filter,1);
+ lua_call(L,2,1);
+}
+
+const char* tolua_type (lua_State* L, int lo)
+{
+ return toluaI_tt_getobjtype(L,lo);
+}
+
+int tolua_tag (lua_State* L, char* type)
+{
+ return toluaI_tt_gettag(L,type);
+}
+
+int tolua_base (lua_State* L, int lo)
+{
+ if (toluaI_tt_isusertype(L,lo))
+ {
+ toluaI_tm_pushclass(L,lo);
+ return lua_gettop(L);
+ }
+ else if (lua_istable(L,lo))
+ {
+ lua_pushvalue(L,lo);
+ lua_pushstring(L,".base");
+ lua_rawget(L,-2);
+ return -1;
+ }
+ else
+ return 0;
+}
+
+int tolua_cast (lua_State* L, int lo, char* type)
+{
+ if (lua_isuserdata(L,lo))
+ {
+ tolua_pushusertype(L,lua_touserdata(L,lo),toluaI_tt_gettag(L,type));
+ return -1;
+ }
+ else
+ return 0;
+}
+
+void tolua_takeownership (lua_State* L, int lo)
+{
+ if (toluaI_tt_isusertype(L,lo))
+ {
+ /* force garbage collection to avoid C to reuse a to-be-collected address */
+ lua_setgcthreshold(L,0);
+ tolua_doclone(L,lua_touserdata(L,lo),lua_tag(L,lo));
+ }
+ else
+ tolua_error(L,"cannot take ownership of specified obejct.");
+}
+
diff --git a/src/lua/tolua_rg.c b/src/lua/tolua_rg.c
new file mode 100644
index 00000000..4337e9f9
--- /dev/null
+++ b/src/lua/tolua_rg.c
@@ -0,0 +1,243 @@
+/* tolua: register functions
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua_rg.c,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+#include <stdio.h>
+
+#include "tolua.h"
+#include "tolua_rg.h"
+#include "tolua_tm.h"
+#include "tolua_tt.h"
+
+void tolua_globalvar (lua_State* L, char* name, lua_CFunction get, lua_CFunction set)
+{
+ lua_newtable(L);
+ lua_pushstring(L,".get");
+ lua_pushcfunction(L,get);
+ lua_settable(L,-3);
+ if (set)
+ {
+ lua_pushstring(L,".set");
+ lua_pushcfunction(L,set);
+ lua_settable(L,-3);
+ }
+ lua_pushvalue(L,-1); /* duplicate top */
+ lua_setglobal(L,name);
+ toluaI_tm_global(L,lua_gettop(L));
+ lua_pop(L,1);
+}
+
+static int toluaI_const_global_array (lua_State* L)
+{
+ lua_error(L,"value of const array cannot be changed");
+ return 0;
+}
+
+
+void tolua_globalarray (lua_State* L,char* name, lua_CFunction get, lua_CFunction set)
+{
+ int tag = lua_newtag(L);
+ lua_newtable(L);
+ lua_settag(L,tag);
+ lua_setglobal(L,name);
+
+ lua_pushcfunction(L,get);
+ lua_settagmethod(L,tag,"gettable");
+ if (set)
+ lua_pushcfunction(L,set);
+ else
+ lua_pushcfunction(L,toluaI_const_global_array);
+ lua_settagmethod(L,tag,"settable");
+}
+
+void tolua_tablevar
+(lua_State* L, char* table, char* name, lua_CFunction get, lua_CFunction set)
+{
+ lua_getglobal(L,table);
+
+ lua_pushstring(L,".get");
+ lua_gettable(L,-2);
+ lua_pushstring(L,name);
+ lua_pushcfunction(L,get);
+ lua_settable(L,-3);
+ lua_pop(L,1);
+ if (set)
+ {
+ lua_pushstring(L,".set");
+ lua_gettable(L,-2);
+ lua_pushstring(L,name);
+ lua_pushcfunction(L,set);
+ lua_settable(L,-3);
+ lua_pop(L,1);
+ }
+
+ lua_pop(L,1);
+}
+
+static int toluaI_get_array (lua_State* L)
+{
+ void* self = tolua_getuserdata(L,1,0);
+ const char* field = tolua_getstring(L,2,0);
+
+ if (!field)
+ tolua_error(L,"invalid 'field' in accessing array");
+ if (!self)
+ {
+ static char msg[BUFSIZ];
+ sprintf(msg,"invalid 'self' in accessing array '%s'",field);
+ tolua_error(L,msg);
+ }
+ toluaI_getregistry(L,"tolua_tbl_itype");
+ lua_pushnumber(L,lua_tag(L,1));
+ lua_gettable(L,-2);
+ lua_getglobal(L,lua_tostring(L,-1));
+ lua_pushstring(L,".array");
+ lua_gettable(L,-2);
+ lua_pushvalue(L,2); /* field */
+ lua_gettable(L,-2);
+ lua_pushstring(L,".self");
+ lua_pushvalue(L,1); /* self */
+ lua_rawset(L,-3);
+ return 1;
+}
+
+static int toluaI_const_array (lua_State* L)
+{
+ lua_error(L,"value of const field cannot be changed");
+ return 0;
+}
+
+void tolua_tablearray
+(lua_State* L, char* table, char* name, lua_CFunction get, lua_CFunction set)
+{
+ int tag = lua_newtag(L);
+ lua_getglobal(L,table);
+ lua_pushstring(L,".array");
+ lua_rawget(L,-2);
+ lua_pushstring(L,name);
+ lua_newtable(L);
+ lua_settag(L,tag);
+ lua_settable(L,-3);
+ lua_pop(L,2);
+
+ lua_pushcfunction(L,get);
+ lua_settagmethod(L,tag,"gettable");
+ if (set)
+ lua_pushcfunction(L,set);
+ else
+ lua_pushcfunction(L,toluaI_const_array);
+ lua_settagmethod(L,tag,"settable");
+
+ tolua_tablevar(L,table,name,toluaI_get_array,NULL);
+}
+
+void tolua_module (lua_State* L, char* name)
+{
+ lua_getglobal(L,name);
+ if (!lua_istable(L,-1))
+ {
+ lua_newtable(L);
+ lua_pushstring(L,".get");
+ lua_newtable(L);
+ lua_settable(L,-3);
+ lua_pushstring(L,".set");
+ lua_newtable(L);
+ lua_settable(L,-3);
+ lua_pushvalue(L,-1); /* duplicate top */
+ lua_setglobal(L,name);
+ toluaI_tm_module(L,lua_gettop(L));
+ lua_pop(L,1);
+ }
+ lua_pop(L,1);
+}
+
+void tolua_cclass (lua_State* L, char* name, char* base)
+{
+ int t;
+ lua_newtable(L);
+ lua_pushstring(L,".get");
+ lua_newtable(L);
+ lua_settable(L,-3);
+ lua_pushstring(L,".set");
+ lua_newtable(L);
+ lua_settable(L,-3);
+ lua_pushstring(L,".array");
+ lua_newtable(L);
+ lua_settable(L,-3);
+ if (*base != 0)
+ {
+ lua_pushstring(L,".base");
+ lua_getglobal(L,base);
+ lua_rawset(L,-3);
+ }
+ lua_pushvalue(L,-1); /* duplicate top */
+ lua_setglobal(L,name);
+ t = lua_gettop(L);
+ toluaI_tm_class(L,t,name);
+ toluaI_tt_class(L,t,name,base);
+ lua_pop(L,1);
+}
+
+
+void tolua_function (lua_State* L, char* parent, char* name, lua_CFunction func)
+{
+ if (parent==NULL)
+ {
+ lua_pushcfunction(L,func);
+ lua_setglobal(L,name);
+ }
+ else
+ {
+ lua_getglobal(L,parent);
+ lua_pushstring(L,name);
+ lua_pushcfunction(L,func);
+ lua_settable(L,-3);
+ lua_pop(L,1);
+ }
+}
+
+void tolua_constant (lua_State* L, char* parent, char* name, long value)
+{
+ if (parent==NULL)
+ {
+ lua_pushnumber(L,value);
+ lua_setglobal(L,name);
+ }
+ else
+ {
+ lua_getglobal(L,parent);
+ lua_pushstring(L,name);
+ lua_pushnumber(L,value);
+ lua_settable(L,-3);
+ lua_pop(L,1);
+ }
+}
+
+void toluaI_setregistry (lua_State* L, char* field)
+{
+ lua_getregistry(L);
+ lua_insert(L,-2);
+ lua_pushstring(L,field);
+ lua_insert(L,-2);
+ lua_settable(L,-3);
+ lua_pop(L,1);
+}
+
+void toluaI_getregistry (lua_State* L, char* field)
+{
+ lua_getregistry(L);
+ lua_pushstring(L,field);
+ lua_gettable(L,-2);
+ lua_insert(L,-2);
+ lua_pop(L,1);
+}
diff --git a/src/lua/tolua_rg.h b/src/lua/tolua_rg.h
new file mode 100644
index 00000000..0feb6078
--- /dev/null
+++ b/src/lua/tolua_rg.h
@@ -0,0 +1,22 @@
+/* tolua: register functions
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Nov 200
+** $Id: tolua_rg.h,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+
+#ifndef tolua_rg_h
+#define tolua_rg_h
+
+void toluaI_setregistry (lua_State* L, char* field);
+void toluaI_getregistry (lua_State* L, char* field);
+
+#endif
diff --git a/src/lua/tolua_tm.c b/src/lua/tolua_tm.c
new file mode 100644
index 00000000..8fd7b28d
--- /dev/null
+++ b/src/lua/tolua_tm.c
@@ -0,0 +1,585 @@
+/* tolua: tag methods
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua_tm.c,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+#include "tolua.h"
+#include "tolua_tm.h"
+#include "tolua_tt.h"
+#include "tolua_rg.h"
+
+#include <string.h>
+
+
+
+/* Global tables created in Lua registry:
+ tolua_tbl_class: indexed by instance tags, stores the class tables.
+ tolua_tbl_clone: indexed by memory address, stores the tag indicanting
+ it is a clone.
+ tolua_tbl_mate: indexed by memory address, stores the associate instance
+ table.
+
+ General tags stored in Lua registry:
+ tolua_tag_global;
+ tolua_tag_module;
+ tolua_tag_class;
+ tolua_tag_instance;
+ tolua_tag_linstance;
+ tolua_tag_indirect;
+*/
+
+/* internal function prototype */
+static void setmethods (lua_State* L);
+
+static void settag (lua_State* L, int lo, char* tag_registry_field)
+{
+ toluaI_getregistry(L,tag_registry_field);
+ lua_pushvalue(L,lo);
+ lua_settag(L,(int)lua_tonumber(L,-2));
+ lua_pop(L,2);
+}
+
+void toluaI_tm_global (lua_State* L, int lo)
+{
+ settag(L,lo,"tolua_tag_global");
+}
+
+void toluaI_tm_module (lua_State* L, int lo)
+{
+ settag(L,lo,"tolua_tag_module");
+}
+
+void toluaI_tm_setclass (lua_State* L, int lo)
+{
+ settag(L,lo,"tolua_tag_class");
+}
+
+void toluaI_tm_class (lua_State* L, int lo, char* name)
+{
+ int tag_class;
+ int tag = lua_newtag(L);
+ char* type = toluaI_tt_concat("class ",name);
+ toluaI_getregistry(L,"tolua_tag_class");
+ tag_class = (int)lua_tonumber(L,-1);
+ lua_copytagmethods(L,tag,tag_class);
+ toluaI_tt_register(L,tag,type);
+ toluaI_tt_sethierarchy(L,tag,tag_class);
+ lua_pushvalue(L,lo);
+ lua_settag(L,tag);
+ lua_pop(L,2); /* tag_class and lo */
+}
+
+void toluaI_tm_instance (lua_State* L, int tag, int lo)
+{
+ toluaI_getregistry(L,"tolua_tbl_class");
+ lua_pushnumber(L,tag);
+ lua_pushvalue(L,lo);
+ lua_settable(L,-3);
+ toluaI_getregistry(L,"tolua_tag_instance");
+ lua_copytagmethods(L,tag,(int)lua_tonumber(L,-1));
+ lua_pop(L,2); /* tbl_class and tag_instance */
+}
+
+void toluaI_tm_linstance (lua_State* L, int tag, int lo)
+{
+ toluaI_getregistry(L,"tolua_tbl_class");
+ lua_pushnumber(L,tag);
+ lua_pushvalue(L,lo);
+ lua_settable(L,-3);
+ toluaI_getregistry(L,"tolua_tag_linstance");
+ lua_copytagmethods(L,tag,(int)lua_tonumber(L,-1));
+ lua_pop(L,2); /* tbl_class and tag_linstance */
+}
+
+void* tolua_doclone (lua_State* L, void* value, int tag)
+{
+ toluaI_getregistry(L,"tolua_tbl_clone");
+ lua_pushuserdata(L,value);
+ lua_pushnumber(L,tag);
+ lua_settable(L,-3);
+ lua_pop(L,1);
+ return value;
+}
+
+void* tolua_copy (lua_State* L, void* value, unsigned int size)
+{
+ void* clone = (void*)malloc(size);
+ if (clone)
+ memcpy(clone,value,size);
+ else
+ tolua_error(L,"insuficient memory");
+ return clone;
+}
+
+static void toluaI_tm_undoclone (lua_State* L, int tag, void* clone)
+{
+ toluaI_getregistry(L,"tolua_tbl_clone");
+ lua_pushuserdata(L,clone);
+ lua_gettable(L,-2);
+ if (lua_isnumber(L,-1) && lua_tonumber(L,-1)==tag)
+ {
+ lua_pushuserdata(L,clone);
+ lua_pushnil(L);
+ lua_settable(L,-4);
+
+ /* get base class */
+ toluaI_getregistry(L,"tolua_tbl_class");
+ lua_pushnumber(L,tag);
+ lua_rawget(L,-2);
+
+ /* look for destructor */
+ lua_pushstring(L,"delete");
+ lua_gettable(L,-2);
+ if (lua_iscfunction(L,-1))
+ {
+ lua_pushusertag(L,clone,tag);
+ lua_call(L,1,0);
+ }
+ else
+ {
+ free(clone); /* no destructor: use raw free */
+ lua_pop(L,1); /* the nil function value */
+ }
+ lua_pop(L,2); /* tbl_class and class method table */
+ }
+ lua_pop(L,2); /* table and value */
+}
+
+void toluaI_tm_pushmate (lua_State* L, int lo)
+{
+ toluaI_getregistry(L,"tolua_tbl_mate");
+ lua_pushvalue(L,lo);
+ lua_rawget(L,-2);
+ lua_insert(L,-2);
+ lua_pop(L,1);
+}
+
+void toluaI_tm_pushclass (lua_State* L, int lo)
+{
+ toluaI_getregistry(L,"tolua_tbl_class");
+ lua_pushnumber(L,lua_tag(L,lo));
+ lua_rawget(L,-2);
+ lua_insert(L,-2);
+ lua_pop(L,1);
+}
+
+int toluaI_gettag (lua_State* L, char* tagname)
+{
+ int tag;
+ toluaI_getregistry(L,tagname);
+ tag = (int)lua_tonumber(L,-1);
+ lua_pop(L,1);
+ return tag;
+}
+
+void toluaI_tm_init (lua_State* L)
+{
+ lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_class");
+ lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_clone");
+ lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_mate");
+
+ lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_global");
+ lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_module");
+ lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_class");
+ lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_instance");
+ lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_linstance");
+ lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_indirect");
+
+ toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_global"),"generic variable");
+ toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_module"),"generic module");
+ toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_class"),"generic class");
+ toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_indirect"),"generic indirect");
+ toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_instance"),"generic instance");
+ toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_linstance"),"generic lua instance");
+
+ /* allows modules and classes to be used as ordinary tables */
+ toluaI_tt_sethierarchy(L,toluaI_gettag(L,"tolua_tag_module"),tolua_tag_table);
+ toluaI_tt_sethierarchy(L,toluaI_gettag(L,"tolua_tag_class"),tolua_tag_table);
+
+ setmethods(L);
+}
+
+static int map (lua_State* L)
+{
+ int m = lua_gettop(L);
+ /* do not pass string fields starting with a dot */
+ if (!lua_isstring(L,1) || *lua_tostring(L,1)!='.')
+ {
+ lua_getglobals(L);
+ lua_pushvalue(L,1);
+ lua_pushvalue(L,m);
+ lua_rawset(L,-3);
+ lua_pop(L,1);
+ }
+ return 0;
+}
+
+void toluaI_tm_using (lua_State* L, int module)
+{
+ lua_newtable(L);
+ lua_settag(L,toluaI_gettag(L,"tolua_tag_indirect"));
+ lua_pushstring(L,".module");
+ lua_pushvalue(L,module);
+ lua_settable(L,-3);
+
+ lua_getglobal(L,"foreach");
+ lua_pushvalue(L,module);
+ lua_pushvalue(L,-3);
+ lua_pushcclosure(L,map,1);
+ lua_call(L,2,0);
+
+ lua_getglobal(L,"foreach");
+ lua_pushvalue(L,module);
+ lua_pushstring(L,".get");
+ lua_gettable(L,-2);
+ lua_insert(L,-2);
+ lua_pop(L,1); /* module table */
+ lua_pushvalue(L,-3);
+ lua_pushcclosure(L,map,1);
+ lua_call(L,2,0);
+ lua_pop(L,1); /* indirect table */
+}
+
+/********************************************************** tag methods */
+
+/* tag methods coded in C */
+
+/* generic gettable */
+static void oo_gettable (lua_State* L, int table, int base, int index)
+{
+ while (lua_istable(L,base))
+ {
+ lua_pushvalue(L,index);
+ lua_rawget(L,base);
+ if (!lua_isnil(L,-1))
+ return; /* returned value already on the top */
+ else if (lua_isnumber(L,index))
+ {
+ lua_pushstring(L,"operator_get");
+ lua_rawget(L,base);
+ if (!lua_isnil(L,-1))
+ {
+ lua_pushvalue(L,table);
+ lua_pushvalue(L,index);
+ lua_call(L,2,1);
+ return;
+ }
+ }
+ else
+ {
+ lua_pushstring(L,".get");
+ lua_rawget(L,base);
+ if (!lua_isnil(L,-1))
+ {
+ lua_pushvalue(L,index);
+ lua_rawget(L,-2);
+ if (!lua_isnil(L,-1))
+ {
+ lua_pushvalue(L,table);
+ lua_pushvalue(L,index); /* need to access array field (?) */
+ lua_call(L,2,1);
+ return;
+ }
+ }
+ }
+ lua_pushstring(L,".base"); lua_rawget(L,base);
+ base = lua_gettop(L);
+ }
+ lua_pushnil(L);
+}
+
+/* generic settable */
+static int oo_settable (lua_State* L, int table, int base, int index, int value)
+{
+ while (lua_istable(L,base))
+ {
+ lua_pushstring(L,".set");
+ lua_rawget(L,base);
+ if (!lua_isnil(L,-1))
+ {
+ lua_pushvalue(L,index);
+ lua_rawget(L,-2);
+ if (!lua_isnil(L,-1))
+ {
+ lua_pushvalue(L,table);
+ lua_pushvalue(L,value);
+ lua_call(L,2,0);
+ return 1;
+ }
+ }
+ lua_pushstring(L,".base"); lua_rawget(L,base);
+ base = lua_gettop(L);
+ }
+ return 0;
+}
+
+/* class tag methods */
+static int class_index (lua_State* L)
+{
+ int table = 1;
+ int index = 2;
+ oo_gettable(L,table,table,index);
+ return 1;
+}
+static int class_settable (lua_State* L)
+{
+ int table = 1;
+ int index = 2;
+ int value = 3;
+ if (oo_settable(L,table,table,index,value) == 0)
+ {
+ lua_pushvalue(L,table);
+ lua_pushvalue(L,index);
+ lua_pushvalue(L,value);
+ lua_rawset(L,-3);
+ }
+ return 0;
+}
+
+/* instance tags */
+static int instance_gettable (lua_State* L)
+{
+ int table = 1;
+ int index = 2;
+ toluaI_tm_pushmate(L,table); /* pushes mate */
+ if (!lua_isnil(L,-1)) /* if there's a mate table */
+ {
+ lua_pushvalue(L,index);
+ lua_rawget(L,-2);
+ if (!lua_isnil(L,-1)) /* if field in mate table exists */
+ return 1;
+ }
+ toluaI_tm_pushclass(L,table); /* pushes base */
+ oo_gettable(L,table,lua_gettop(L),index);
+ return 1;
+}
+static int instance_settable (lua_State* L)
+{
+ int table = 1;
+ int index = 2;
+ int value = 3;
+ toluaI_tm_pushclass(L,table); /* pushes base */
+ if (lua_isnumber(L,index))
+ {
+ lua_pushstring(L,"operator_set");
+ lua_rawget(L,-2);
+ if (!lua_isnil(L,-1))
+ {/* the stack here is: table,index,value,base,operator */
+ /* call operator passing table, index, and value */
+ lua_insert(L,1);
+ lua_pop(L,1); /* base */
+ lua_call(L,3,0);
+ return 0;
+ }
+ }
+ if (oo_settable(L,table,4,index,value) == 0)
+ {
+ toluaI_tm_pushmate(L,table); /* pushes mate */
+ if (lua_isnil(L,-1))
+ {
+ /* creates mate table */
+ lua_newtable(L);
+ toluaI_getregistry(L,"tolua_tbl_mate");
+ lua_pushvalue(L,table); /* that is the userdata */
+ lua_pushvalue(L,-3);
+ lua_rawset(L,-3);
+ lua_pop(L,1); /* tbl_mate */
+ }
+ /* the mate table is on the top */
+ lua_pushvalue(L,index);
+ lua_pushvalue(L,value);
+ lua_rawset(L,-3);
+ }
+ return 0;
+}
+static int instance_gc (lua_State* L)
+{
+ toluaI_tm_undoclone(L,lua_tag(L,1),lua_touserdata(L,1));
+ return 0;
+}
+static int gen_operator (lua_State* L)
+{
+ int op1 = 1;
+ int op2 = 2;
+ int event = 3;
+ char* name = toluaI_tt_concat("operator_",lua_tostring(L,event));
+ lua_pushstring(L,name);
+ lua_gettable(L,op1);
+ lua_pushvalue(L,op1);
+ lua_pushvalue(L,op2);
+ lua_call(L,2,1);
+ return 1;
+}
+static int instance_operator (lua_State* L)
+{
+ return gen_operator(L);
+}
+static int instance_relational (lua_State* L)
+{
+ gen_operator(L);
+ if ((int)lua_tonumber(L,-1)==0) lua_pushnil(L);
+ return 1;
+}
+
+/* lua instance tags */
+static int linstance_index (lua_State* L)
+{
+ toluaI_tm_pushclass(L,1);
+ oo_gettable(L,1,3,2); /* table,base,index */
+ return 1;
+}
+
+
+/* module tag methods */
+static int module_index (lua_State* L)
+{
+ int table = 1;
+ int index = 2;
+ lua_pushstring(L,".get");
+ lua_rawget(L,table);
+ if (!lua_isnil(L,-1))
+ {
+ lua_pushvalue(L,index);
+ lua_rawget(L,-2);
+ if (!lua_isnil(L,-1))
+ {
+ lua_call(L,0,1);
+ return 1;
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+static int module_settable (lua_State* L)
+{
+ int table = 1;
+ int index = 2;
+ int value = 3;
+ lua_pushstring(L,".set");
+ lua_rawget(L,table);
+ if (!lua_isnil(L,-1))
+ {
+ lua_pushvalue(L,index);
+ lua_rawget(L,-2);
+ if (!lua_isnil(L,-1))
+ {
+ lua_pushvalue(L,value);
+ lua_call(L,1,0);
+ return 0;
+ }
+ }
+ lua_pushvalue(L,index);
+ lua_pushvalue(L,value);
+ lua_rawset(L,table);
+ return 0;
+}
+
+/* global variable tag methods */
+static int global_getglobal (lua_State* L)
+{
+ int value = 2;
+ lua_pushstring(L,".get");
+ lua_rawget(L,value);
+ lua_call(L,0,1);
+ return 1;
+}
+static int global_setglobal (lua_State* L)
+{
+ int value = 2;
+ int newvalue = 3;
+ lua_pushstring(L,".set");
+ lua_rawget(L,value);
+ if (lua_isnil(L,-1))
+ lua_error(L,"value of const variable cannot be changed");
+ else
+ {
+ lua_pushvalue(L,newvalue);
+ lua_call(L,1,0);
+ }
+ return 0;
+}
+
+/* indirect tag methods */
+static int indirect_getglobal (lua_State* L)
+{
+ int varname = 1;
+ int value = 2;
+ lua_pushstring(L,".module");
+ lua_gettable(L,value);
+ lua_pushvalue(L,varname);
+ lua_gettable(L,-2);
+ return 1;
+}
+static int indirect_setglobal (lua_State* L)
+{
+ int varname = 1;
+ int value = 2;
+ int newvalue = 3;
+ lua_pushstring(L,".module");
+ lua_gettable(L,value);
+ lua_pushvalue(L,varname);
+ lua_pushvalue(L,newvalue);
+ lua_settable(L,-3);
+ return 0;
+}
+
+static void setmethods (lua_State* L)
+{
+ /* global variable */
+ lua_pushcfunction(L,global_getglobal);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_global"),"getglobal");
+ lua_pushcfunction(L,global_setglobal);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_global"),"setglobal");
+
+ /* module */
+ lua_pushcfunction(L,module_index);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_module"),"index");
+ lua_pushcfunction(L,module_settable);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_module"),"settable");
+
+ /* class */
+ lua_pushcfunction(L,class_index);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_class"),"index");
+ lua_pushcfunction(L,class_settable);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_class"),"settable");
+
+ /* instance */
+ lua_pushcfunction(L,instance_gettable);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"gettable");
+ lua_pushcfunction(L,instance_settable);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"settable");
+ lua_pushcfunction(L,instance_operator);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"add");
+ lua_pushcfunction(L,instance_operator);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"sub");
+ lua_pushcfunction(L,instance_operator);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"mul");
+ lua_pushcfunction(L,instance_operator);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"div");
+ lua_pushcfunction(L,instance_relational);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"lt");
+ lua_pushcfunction(L,instance_gc);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"gc");
+
+ /* lua instance */
+ lua_pushcfunction(L,linstance_index);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_linstance"),"index");
+
+ /* indirect */
+ lua_pushcfunction(L,indirect_getglobal);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_indirect"),"getglobal");
+ lua_pushcfunction(L,indirect_setglobal);
+ lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_indirect"),"setglobal");
+}
+
+
+
diff --git a/src/lua/tolua_tm.h b/src/lua/tolua_tm.h
new file mode 100644
index 00000000..c1bf06dc
--- /dev/null
+++ b/src/lua/tolua_tm.h
@@ -0,0 +1,32 @@
+/* tolua: tag methods
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua_tm.h,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+
+
+#ifndef tolua_tm_h
+#define tolua_tm_h
+
+void toluaI_tm_init (lua_State* L);
+void toluaI_tm_global (lua_State* L, int lo);
+void toluaI_tm_module (lua_State* L, int lo);
+void toluaI_tm_class (lua_State* L, int lo, char* name);
+void toluaI_tm_instance (lua_State* L, int tag, int lo);
+void toluaI_tm_linstance (lua_State* L, int tag, int lo);
+void toluaI_tm_using (lua_State* L, int module);
+void toluaI_tm_setclass (lua_State* L, int lo);
+void toluaI_tm_pushmate (lua_State* L, int lo);
+void toluaI_tm_pushclass (lua_State* L, int lo);
+
+
+#endif
diff --git a/src/lua/tolua_tt.c b/src/lua/tolua_tt.c
new file mode 100644
index 00000000..33c384c6
--- /dev/null
+++ b/src/lua/tolua_tt.c
@@ -0,0 +1,316 @@
+/* tolua: type & tag manipulation.
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua_tt.c,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+#include "tolua.h"
+#include "tolua_tt.h"
+#include "tolua_tm.h"
+#include "tolua_eh.h"
+#include "tolua_rg.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+/* Global tables created in Lua registry:
+ tolua_tbl_itype: indexed by instance tags, stores the instance types.
+ tolua_tbl_itag: indexed by instance types, stores the instance tags.
+ tolua_tbl_const: indexed by constant tags, stores the tags.
+ tolua_tbl_hierarchy: indexed by instance tags, stores the base tags.
+*/
+
+/* exported basic type tags */
+int tolua_tag_nil;
+int tolua_tag_number;
+int tolua_tag_string;
+int tolua_tag_userdata;
+int tolua_tag_table;
+int tolua_tag_function;
+
+
+static const char* gettype (lua_State* L, int tag)
+{
+ const char* type;
+ toluaI_getregistry(L,"tolua_tbl_itype");
+ lua_pushnumber(L,tag);
+ lua_gettable(L,-2);
+ type = lua_tostring(L,-1);
+ if (type==NULL) type = "[undefined]";
+ lua_pop(L,2);
+ return type;
+}
+
+const char* toluaI_tt_getobjtype (lua_State* L, int lo)
+{
+ if (lua_gettop(L)<abs(lo))
+ return "[no object]";
+ else
+ return gettype(L,lua_tag(L,lo));
+}
+
+int toluaI_tt_gettag (lua_State* L, char* type)
+{
+ int tag;
+ toluaI_getregistry(L,"tolua_tbl_itag");
+ lua_pushstring(L,type);
+ lua_gettable(L,-2);
+ tag = (int)lua_tonumber(L,-1);
+ lua_pop(L,2);
+ return tag;
+}
+
+static int basetag (lua_State* L, int hierarchy, int tag)
+{
+ int btag;
+ lua_pushnumber(L,tag);
+ lua_gettable(L,hierarchy);
+ btag = (int)lua_tonumber(L,-1);
+ lua_pop(L,1);
+ return btag;
+}
+
+static int istype (lua_State* L, int lo, int tag)
+{
+ int otag = lua_tag(L,lo);
+ if (tag==otag) /* check simplest case */
+ return 1;
+ else if (lua_isnil(L,lo) &&
+ tag!=LUA_TNUMBER &&
+ tag!=LUA_TTABLE &&
+ tag!=LUA_TFUNCTION
+ )
+ return 1;
+ else if ((tag==LUA_TSTRING && lua_isstring(L,lo)) || /* check convertions */
+ (tag==LUA_TNUMBER && lua_isnumber(L,lo))
+ )
+ return 1;
+ else if (tag==LUA_TUSERDATA && lua_isuserdata(L,lo)) /* pointer to void* */
+ return 1;
+ else if (tag==toluaI_tt_gettag(L,"bool") && otag==LUA_TNUMBER)
+ return 1;
+ else
+ {
+ /* if requested type is const, the non-const is an alternative type */
+ int tag2;
+ int tbl_hierarchy;
+ toluaI_getregistry(L,"tolua_tbl_const");
+ lua_pushnumber(L,tag);
+ lua_gettable(L,-2);
+ tag2 = (int)lua_tonumber(L,-1);
+ lua_pop(L,2);
+ if (tag2 && tag2==otag)
+ return 1;
+ /* check for base classes */
+ toluaI_getregistry(L,"tolua_tbl_hierarchy");
+ tbl_hierarchy = lua_gettop(L);
+ otag = basetag(L,tbl_hierarchy,otag);
+ while (otag)
+ {
+ if (tag==otag || (tag2 && tag2==otag))
+ break;
+ otag = basetag(L,tbl_hierarchy,otag);
+ }
+ lua_pop(L,1);
+ return otag!=0;
+ }
+}
+
+void toluaI_tt_init (lua_State* L)
+{
+ lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_itype");
+ lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_itag");
+ lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_const");
+ lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_hierarchy");
+
+ /* set and register basic Lua type tag */
+#if 0
+ lua_pushnumber(L,LUA_TNIL); toluaI_setregistry(L,"tolua_tag_nil");
+ lua_pushnumber(L,LUA_TNUMBER); toluaI_setregistry(L,"tolua_tag_number");
+ lua_pushnumber(L,LUA_TSTRING); toluaI_setregistry(L,"tolua_tag_string");
+ lua_pushnumber(L,LUA_TUSERDATA); toluaI_setregistry(L,"tolua_tag_userdata");
+ lua_pushnumber(L,LUA_TTABLE); toluaI_setregistry(L,"tolua_tag_table");
+ lua_pushnumber(L,LUA_TFUNCTION); toluaI_setregistry(L,"tolua_tag_function");
+
+ toluaI_tt_register(L,toluaI_tt_gettag(L,"tolua_tag_nil"),"nil");
+ toluaI_tt_register(L,toluaI_tt_gettag(L,"tolua_tag_number"),"number");
+ toluaI_tt_register(L,toluaI_tt_gettag(L,"tolua_tag_string"),"string");
+ toluaI_tt_register(L,toluaI_tt_gettag(L,"tolua_tag_userdata"),"userdata");
+ toluaI_tt_register(L,toluaI_tt_gettag(L,"tolua_tag_table"),"table");
+ toluaI_tt_register(L,toluaI_tt_gettag(L,"tolua_tag_function"),"function");
+#else
+ toluaI_tt_register(L,LUA_TNIL,"nil");
+ toluaI_tt_register(L,LUA_TNUMBER,"number");
+ toluaI_tt_register(L,LUA_TSTRING,"string");
+ toluaI_tt_register(L,LUA_TUSERDATA,"userdata");
+ toluaI_tt_register(L,LUA_TTABLE,"table");
+ toluaI_tt_register(L,LUA_TFUNCTION,"function");
+ toluaI_tt_register(L,lua_newtag(L),"bool");
+#endif
+}
+
+
+void toluaI_tt_register (lua_State* L, int tag, char* type)
+{
+ toluaI_getregistry(L,"tolua_tbl_itype");
+ lua_pushnumber(L,tag);
+ lua_pushstring(L,type);
+ lua_settable(L,-3);
+
+ toluaI_getregistry(L,"tolua_tbl_itag");
+ lua_pushstring(L,type);
+ lua_pushnumber(L,tag);
+ lua_settable(L,-3);
+
+ lua_pop(L,2);
+}
+
+
+void toluaI_tt_class (lua_State* L, int lo, char* derived, char* base)
+{
+ char* cderived = toluaI_tt_concat("const ",derived);
+ int tag = toluaI_tt_gettag(L,derived);
+ int ctag = toluaI_tt_gettag(L,cderived);
+ toluaI_tm_instance(L,tag,lo);
+ toluaI_tm_instance(L,ctag,lo);
+ if (*base != 0)
+ {
+ char* cbase = toluaI_tt_concat("const ",base);
+ int btag = toluaI_tt_gettag(L,base);
+ int cbtag = toluaI_tt_gettag(L,cbase);
+ toluaI_tt_sethierarchy(L,tag,btag);
+ toluaI_tt_sethierarchy(L,ctag,cbtag);
+ }
+}
+
+void toluaI_tt_sethierarchy (lua_State* L, int tag, int btag)
+{
+ toluaI_getregistry(L,"tolua_tbl_hierarchy");
+ lua_pushnumber(L,tag);
+ lua_pushnumber(L,btag);
+ lua_settable(L,-3);
+ lua_pop(L,1);
+}
+
+char* toluaI_tt_concat (const char* s1, const char* s2)
+{
+ static char s[BUFSIZ];
+ assert(strlen(s1)+strlen(s2)<BUFSIZ);
+ return strcat(strcpy(s,s1),s2);
+}
+
+void tolua_usertype (lua_State* L, char* type)
+{
+ /* check if type is already registered */
+ toluaI_getregistry(L,"tolua_tbl_itag");
+ lua_pushstring(L,type);
+ lua_gettable(L,-2);
+ if (lua_isnil(L,-1))
+ {
+ char *ctype = toluaI_tt_concat("const ",type);
+ int tag = lua_newtag(L);
+ int ctag = lua_newtag(L);
+ toluaI_tt_register(L,tag,type);
+ toluaI_tt_register(L,ctag,ctype);
+ /* set const table */
+ toluaI_getregistry(L,"tolua_tbl_const");
+ lua_pushnumber(L,ctag);
+ lua_pushnumber(L,tag);
+ lua_settable(L,-3);
+ lua_pop(L,1);
+ }
+ lua_pop(L,2);
+}
+
+int toluaI_tt_isusertype (lua_State* L, int lo)
+{
+ if (lua_isuserdata(L,lo) &&
+ toluaI_tt_gettag(L,"tolua_tag_userdata")!=lua_tag(L,lo)
+ )
+ {
+ int status;
+ toluaI_getregistry(L,"tolua_tbl_itype");
+ lua_pushnumber(L,lua_tag(L,lo));
+ lua_gettable(L,-2);
+ status = !lua_isnil(L,-1);
+ lua_pop(L,2);
+ return status;
+ }
+ return 0;
+}
+
+#if 0
+void tolua_settag (lua_State* L, char* type, int* tag)
+{
+ toluaI_getregistry(L,"tolua_tbl_itag");
+ lua_pushstring(L,type);
+ lua_gettable(L,-2);
+ *tag = (int) lua_tonumber(L,-1);
+ lua_pop(L,2);
+}
+#endif
+
+int tolua_istype (lua_State* L, int narg, int tag, int def)
+{
+ if (lua_gettop(L)<abs(narg))
+ {
+ if (def==0)
+ {
+ toluaI_eh_set(L,narg,toluaI_tt_getobjtype(L,narg),gettype(L,tag));
+ return 0;
+ }
+ }
+ else
+ {
+ if (!istype(L,narg,tag))
+ {
+ toluaI_eh_set(L,narg,toluaI_tt_getobjtype(L,narg),gettype(L,tag));
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int tolua_arrayistype (lua_State* L, int narg, int tag, int dim, int def)
+{
+ int i;
+ for (i=0; i<dim; ++i)
+ {
+ int tf;
+ lua_pushnumber(L,i+1);
+ lua_gettable(L,narg);
+ tf = lua_gettop(L);
+ if (!istype(L,tf,tag) && (!def || !lua_isnil(L,tf)))
+ {
+ static char t1[BUFSIZ], t2[BUFSIZ];
+ sprintf(t1,"array of %s",toluaI_tt_getobjtype(L,tf));
+ sprintf(t2,"array of %s (dimension=%d)",gettype(L,tag),dim);
+ toluaI_eh_set(L,narg,t1,t2);
+ return 0;
+ }
+ lua_pop(L,1);
+ }
+ return 1;
+}
+
+int tolua_isnoobj (lua_State* L, int narg)
+{
+ if (lua_gettop(L)>=abs(narg))
+ {
+ toluaI_eh_set(L,narg,toluaI_tt_getobjtype(L,narg),
+ toluaI_tt_getobjtype(L,lua_gettop(L)+1));
+ return 0;
+ }
+ return 1;
+}
+
+
diff --git a/src/lua/tolua_tt.h b/src/lua/tolua_tt.h
new file mode 100644
index 00000000..941a2b02
--- /dev/null
+++ b/src/lua/tolua_tt.h
@@ -0,0 +1,31 @@
+/* tolua: type & tag manipulation.
+** Support code for Lua bindings.
+** Written by Waldemar Celes
+** TeCGraf/PUC-Rio
+** Jul 1998
+** $Id: tolua_tt.h,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+*/
+
+/* This code is free software; you can redistribute it and/or modify it.
+** The software provided hereunder is on an "as is" basis, and
+** the author has no obligation to provide maintenance, support, updates,
+** enhancements, or modifications.
+*/
+
+
+#ifndef tolua_tt_h
+#define tolua_tt_h
+
+void toluaI_tt_init (lua_State* L);
+void toluaI_tt_register (lua_State* L, int tag, char* type);
+void toluaI_tt_class (lua_State* L, int lo, char* derived, char* base);
+void toluaI_tt_sethierarchy (lua_State* L, int tag, int btag);
+int toluaI_tt_isusertype (lua_State* L, int lo);
+int toluaI_tt_gettag (lua_State* L, char* type);
+const char* toluaI_tt_getobjtype (lua_State* L, int lo);
+char* toluaI_tt_concat (const char* s1, const char* s2);
+
+
+
+
+#endif
diff --git a/src/lua/tolualua.c b/src/lua/tolualua.c
new file mode 100644
index 00000000..adbb8635
--- /dev/null
+++ b/src/lua/tolualua.c
@@ -0,0 +1,2975 @@
+/*
+** Lua binding: tolualua
+** Generated automatically by tolua 4.0a - angband on Sun Nov 11 22:59:08 2001.
+*/
+
+#include "tolua.h"
+
+/* Exported function */
+int tolua_tolualua_open (lua_State* tolua_S);
+void tolua_tolualua_close (lua_State* tolua_S);
+
+
+/* function to register type */
+static void toluaI_reg_types (lua_State* tolua_S)
+{
+}
+
+/* error messages */
+#define TOLUA_ERR_SELF tolua_error(tolua_S,"invalid 'self'")
+#define TOLUA_ERR_ASSIGN tolua_error(tolua_S,"#vinvalid type in variable assignment.")
+
+/* Open function */
+int tolua_tolualua_open (lua_State* tolua_S)
+{
+ tolua_open(tolua_S);
+ toluaI_reg_types(tolua_S);
+
+ { /* begin embedded lua code */
+ static unsigned char B[] = {
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 95, 98, 97,115,105, 99, 32, 61, 32,123, 10, 91, 39,118,
+ 111,105,100, 39, 93, 32, 61, 32, 39, 39, 44, 10, 91, 39, 99,
+ 104, 97,114, 39, 93, 32, 61, 32, 39,110,117,109, 98,101,114,
+ 39, 44, 10, 91, 39,105,110,116, 39, 93, 32, 61, 32, 39,110,
+ 117,109, 98,101,114, 39, 44, 10, 91, 39,115,104,111,114,116,
+ 39, 93, 32, 61, 32, 39,110,117,109, 98,101,114, 39, 44, 10,
+ 91, 39,108,111,110,103, 39, 93, 32, 61, 32, 39,110,117,109,
+ 98,101,114, 39, 44, 10, 91, 39, 95, 99,115,116,114,105,110,
+ 103, 39, 93, 32, 61, 32, 39,115,116,114,105,110,103, 39, 44,
+ 10, 91, 39, 95,117,115,101,114,100, 97,116, 97, 39, 93, 32,
+ 61, 32, 39,117,115,101,114,100, 97,116, 97, 39, 44, 10, 91,
+ 39, 99,104, 97,114, 42, 39, 93, 32, 61, 32, 39,115,116,114,
+ 105,110,103, 39, 44, 10, 91, 39,118,111,105,100, 42, 39, 93,
+ 32, 61, 32, 39,117,115,101,114,100, 97,116, 97, 39, 44, 10,
+ 91, 39, 98,111,111,108, 39, 93, 32, 61, 32, 39, 98,111,111,
+ 108, 39, 44, 10, 91, 39, 76, 85, 65, 95, 86, 65, 76, 85, 69,
+ 39, 93, 32, 61, 32, 39,118, 97,108,117,101, 39, 44, 10, 91,
+ 39, 98,121,116,101, 39, 93, 32, 61, 32, 39,110,117,109, 98,
+ 101,114, 39, 44, 10, 91, 39,115, 49, 54, 98, 39, 93, 32, 61,
+ 32, 39,110,117,109, 98,101,114, 39, 44, 10, 91, 39,117, 49,
+ 54, 98, 39, 93, 32, 61, 32, 39,110,117,109, 98,101,114, 39,
+ 44, 10, 91, 39,115, 51, 50, 98, 39, 93, 32, 61, 32, 39,110,
+ 117,109, 98,101,114, 39, 44, 10, 91, 39,117, 51, 50, 98, 39,
+ 93, 32, 61, 32, 39,110,117,109, 98,101,114, 39, 44, 10,125,
+ 10, 10, 95, 98, 97,115,105, 99, 95,116, 97,103, 32, 61, 32,
+ 123, 10, 91, 39,118,111,105,100, 39, 93, 32, 61, 32, 39, 39,
+ 44, 10, 91, 39, 99,104, 97,114, 39, 93, 32, 61, 32, 39, 76,
+ 85, 65, 95, 84, 78, 85, 77, 66, 69, 82, 39, 44, 10, 91, 39,
+ 105,110,116, 39, 93, 32, 61, 32, 39, 76, 85, 65, 95, 84, 78,
+ 85, 77, 66, 69, 82, 39, 44, 10, 91, 39,115,104,111,114,116,
+ 39, 93, 32, 61, 32, 39, 76, 85, 65, 95, 84, 78, 85, 77, 66,
+ 69, 82, 39, 44, 10, 91, 39,108,111,110,103, 39, 93, 32, 61,
+ 32, 39, 76, 85, 65, 95, 84, 78, 85, 77, 66, 69, 82, 39, 44,
+ 10, 91, 39, 95, 99,115,116,114,105,110,103, 39, 93, 32, 61,
+ 32, 39, 76, 85, 65, 95, 84, 83, 84, 82, 73, 78, 71, 39, 44,
+ 10, 91, 39, 95,117,115,101,114,100, 97,116, 97, 39, 93, 32,
+ 61, 32, 39, 76, 85, 65, 95, 84, 85, 83, 69, 82, 68, 65, 84,
+ 65, 39, 44, 10, 91, 39, 99,104, 97,114, 42, 39, 93, 32, 61,
+ 32, 39, 76, 85, 65, 95, 84, 83, 84, 82, 73, 78, 71, 39, 44,
+ 10, 91, 39,118,111,105,100, 42, 39, 93, 32, 61, 32, 39, 76,
+ 85, 65, 95, 84, 85, 83, 69, 82, 68, 65, 84, 65, 39, 44, 10,
+ 91, 39, 98,111,111,108, 39, 93, 32, 61, 32, 39,116,111,108,
+ 117, 97, 95,116, 97,103, 40,116,111,108,117, 97, 95, 83, 44,
+ 34, 98,111,111,108, 34, 41, 39, 44, 10, 91, 39, 98,121,116,
+ 101, 39, 93, 32, 61, 32, 39, 76, 85, 65, 95, 84, 78, 85, 77,
+ 66, 69, 82, 39, 44, 10, 91, 39,115, 49, 54, 98, 39, 93, 32,
+ 61, 32, 39, 76, 85, 65, 95, 84, 78, 85, 77, 66, 69, 82, 39,
+ 44, 10, 91, 39,117, 49, 54, 98, 39, 93, 32, 61, 32, 39, 76,
+ 85, 65, 95, 84, 78, 85, 77, 66, 69, 82, 39, 44, 10, 91, 39,
+ 115, 51, 50, 98, 39, 93, 32, 61, 32, 39, 76, 85, 65, 95, 84,
+ 78, 85, 77, 66, 69, 82, 39, 44, 10, 91, 39,117, 51, 50, 98,
+ 39, 93, 32, 61, 32, 39, 76, 85, 65, 95, 84, 78, 85, 77, 66,
+ 69, 82, 39, 44, 10,125, 10, 10, 95, 98, 97,115,105, 99, 95,
+ 99,116,121,112,101, 32, 61, 32,123, 10,110,117,109, 98,101,
+ 114, 32, 61, 32, 34,108,111,110,103, 34, 44, 10,115,116,114,
+ 105,110,103, 32, 61, 32, 34, 99,111,110,115,116, 32, 99,104,
+ 97,114, 42, 34, 44, 10,117,115,101,114,100, 97,116, 97, 32,
+ 61, 32, 34,118,111,105,100, 42, 34, 44, 10, 98,111,111,108,
+ 32, 61, 32, 34,105,110,116, 34, 44, 10,125, 10, 10, 10, 10,
+ 95,117,115,101,114,116,121,112,101, 32, 61, 32,123,125, 10,
+ 10, 10,102,117,110, 99,116,105,111,110, 32,116,111,108,117,
+ 97, 95,105,110,100,101,120, 32, 40,116, 44,102, 41, 10,105,
+ 102, 32,102, 32, 61, 61, 32, 39, 95, 98, 97,115,101, 39, 32,
+ 116,104,101,110, 10,114,101,116,117,114,110, 32,116,111,108,
+ 117, 97, 95,111,108,100, 95,105,110,100,101,120, 40,116, 44,
+ 102, 41, 10,101,108,115,101, 10,114,101,116,117,114,110, 32,
+ 116, 46, 95, 98, 97,115,101, 91,102, 93, 10,101,110,100, 10,
+ 101,110,100, 10, 10,116,111,108,117, 97, 95,116, 97,103, 32,
+ 61, 32,110,101,119,116, 97,103, 40, 41, 10,116,111,108,117,
+ 97, 95,111,108,100, 95,105,110,100,101,120, 32, 61, 32,115,
+ 101,116,116, 97,103,109,101,116,104,111,100, 40,116,111,108,
+ 117, 97, 95,116, 97,103, 44, 34,105,110,100,101,120, 34, 44,
+ 116,111,108,117, 97, 95,105,110,100,101,120, 41, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32,116,111,108,117, 97, 95,
+ 101,114,114,111,114, 32, 40,115, 41, 10,108,111, 99, 97,108,
+ 32,111,117,116, 32, 61, 32, 95, 79, 85, 84, 80, 85, 84, 10,
+ 95, 79, 85, 84, 80, 85, 84, 32, 61, 32, 95, 83, 84, 68, 69,
+ 82, 82, 10,105,102, 32,115,116,114,115,117, 98, 40,115, 44,
+ 49, 44, 49, 41, 32, 61, 61, 32, 39, 35, 39, 32,116,104,101,
+ 110, 10,119,114,105,116,101, 40, 34, 92,110, 42, 42, 32,116,
+ 111,108,117, 97, 58, 32, 34, 46, 46,115,116,114,115,117, 98,
+ 40,115, 44, 50, 41, 46, 46, 34, 46, 92,110, 92,110, 34, 41,
+ 10,101,108,115,101, 10,119,114,105,116,101, 40, 34, 92,110,
+ 42, 42, 32,116,111,108,117, 97, 32,105,110,116,101,114,110,
+ 97,108, 32,101,114,114,111,114, 58, 32, 34, 46, 46,115, 46,
+ 46, 34, 46, 92,110, 92,110, 34, 41, 10,114,101,116,117,114,
+ 110, 10,101,110,100, 10, 10,105,102, 32, 95, 99,117,114,114,
+ 95, 99,111,100,101, 32,116,104,101,110, 10,108,111, 99, 97,
+ 108, 32, 95, 44, 95, 44,115, 32, 61, 32,115,116,114,102,105,
+ 110,100, 40, 95, 99,117,114,114, 95, 99,111,100,101, 44, 34,
+ 94, 37,115, 42, 40, 46, 45, 92,110, 41, 34, 41, 10,105,102,
+ 32,115, 61, 61,110,105,108, 32,116,104,101,110, 32,115, 32,
+ 61, 32, 95, 99,117,114,114, 95, 99,111,100,101, 32,101,110,
+ 100, 10,115, 32, 61, 32,103,115,117, 98, 40,115, 44, 34, 95,
+ 117,115,101,114,100, 97,116, 97, 34, 44, 34,118,111,105,100,
+ 42, 34, 41, 10,115, 32, 61, 32,103,115,117, 98, 40,115, 44,
+ 34, 95, 99,115,116,114,105,110,103, 34, 44, 34, 99,104, 97,
+ 114, 42, 34, 41, 10,119,114,105,116,101, 40, 34, 67,111,100,
+ 101, 32, 98,101,105,110,103, 32,112,114,111, 99,101,115,115,
+ 101,100, 58, 92,110, 34, 46, 46,115, 46, 46, 34, 92,110, 34,
+ 41, 10,101,110,100, 10, 95, 79, 85, 84, 80, 85, 84, 32, 61,
+ 32,111,117,116, 10,101,110,100, 10, 10, 10, 95, 69, 82, 82,
+ 79, 82, 77, 69, 83, 83, 65, 71, 69, 32, 61, 32,116,111,108,
+ 117, 97, 95,101,114,114,111,114, 10, 10, 10,102,117,110, 99,
+ 116,105,111,110, 32,114,101,103,116,121,112,101, 32, 40,116,
+ 41, 10,105,102, 32,110,111,116, 32,105,115,116,121,112,101,
+ 40,116, 41, 32,116,104,101,110, 10, 95,117,115,101,114,116,
+ 121,112,101, 91,116, 93, 32, 61, 32,116, 10,101,110,100, 10,
+ 114,101,116,117,114,110, 32,116, 10,101,110,100, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32,116, 97,103,118, 97,114,
+ 40,116,121,112,101, 44, 99,111,110,115,116, 41, 10,105,102,
+ 32,116,121,112,101, 32, 61, 61, 32, 39, 39, 32,111,114, 32,
+ 116,121,112,101, 32, 61, 61, 32, 39,118,111,105,100, 39, 32,
+ 116,104,101,110, 10,114,101,116,117,114,110, 32,116,121,112,
+ 101, 44, 48, 10,101,108,115,101, 10,108,111, 99, 97,108, 32,
+ 109, 44,116, 32, 61, 32,102,105,110,100,116,121,112,101,100,
+ 101,102, 40,116,121,112,101, 41, 10,105,102, 32,105,115, 98,
+ 97,115,105, 99, 40,116, 41, 32,116,104,101,110, 10,114,101,
+ 116,117,114,110, 32,116, 44, 32, 95, 98, 97,115,105, 99, 95,
+ 116, 97,103, 91,116, 93, 10,101,110,100, 10,105,102, 32,115,
+ 116,114,102,105,110,100, 40,109, 44, 39, 99,111,110,115,116,
+ 39, 41, 32,116,104,101,110, 32, 99,111,110,115,116, 32, 61,
+ 32, 39, 99,111,110,115,116, 39, 32,101,110,100, 10,114,101,
+ 103,116,121,112,101, 40,116, 41, 10,105,102, 32, 99,111,110,
+ 115,116, 32, 97,110,100, 32, 99,111,110,115,116, 32,126, 61,
+ 32, 39, 39, 32,116,104,101,110, 10,116, 32, 61, 32, 39, 99,
+ 111,110,115,116, 32, 39, 46, 46,116, 10,101,110,100, 10,114,
+ 101,116,117,114,110, 32,116, 44, 39,116,111,108,117, 97, 95,
+ 116, 97,103, 40,116,111,108,117, 97, 95, 83, 44, 34, 39, 46,
+ 46,116, 46, 46, 39, 34, 41, 39, 10,101,110,100, 10,101,110,
+ 100, 10, 10, 10,102,117,110, 99,116,105,111,110, 32,105,115,
+ 98, 97,115,105, 99, 32, 40,116,121,112,101, 41, 10,108,111,
+ 99, 97,108, 32,109, 44,116, 32, 61, 32,102,105,110,100,116,
+ 121,112,101,100,101,102, 40,116,121,112,101, 41, 10,108,111,
+ 99, 97,108, 32, 98, 32, 61, 32, 95, 98, 97,115,105, 99, 91,
+ 116, 93, 10,105,102, 32, 98, 32,116,104,101,110, 10,114,101,
+ 116,117,114,110, 32, 98, 44, 95, 98, 97,115,105, 99, 95, 99,
+ 116,121,112,101, 91, 98, 93, 10,101,110,100, 10,114,101,116,
+ 117,114,110, 32,110,105,108, 10,101,110,100, 10, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32,105,115,116,121,112,101, 32,
+ 40,116, 41, 10,114,101,116,117,114,110, 32, 95, 98, 97,115,
+ 105, 99, 91,116, 93, 32,111,114, 32, 95,117,115,101,114,116,
+ 121,112,101, 91,116, 93, 32,111,114, 32,105,115,116,121,112,
+ 101,100,101,102, 40,116, 41, 10,101,110,100, 10, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32,115,112,108,105,116, 32,
+ 40,115, 44,116, 41, 10,108,111, 99, 97,108, 32,108, 32, 61,
+ 32,123,110, 61, 48,125, 10,108,111, 99, 97,108, 32,102, 32,
+ 61, 32,102,117,110, 99,116,105,111,110, 32, 40,115, 41, 10,
+ 37,108, 46,110, 32, 61, 32, 37,108, 46,110, 32, 43, 32, 49,
+ 10, 37,108, 91, 37,108, 46,110, 93, 32, 61, 32,115, 10,101,
+ 110,100, 10,108,111, 99, 97,108, 32,112, 32, 61, 32, 34, 37,
+ 115, 42, 40, 46, 45, 41, 37,115, 42, 34, 46, 46,116, 46, 46,
+ 34, 37,115, 42, 34, 10,115, 32, 61, 32,103,115,117, 98, 40,
+ 115, 44, 34, 94, 37,115, 43, 34, 44, 34, 34, 41, 10,115, 32,
+ 61, 32,103,115,117, 98, 40,115, 44, 34, 37,115, 43, 36, 34,
+ 44, 34, 34, 41, 10,115, 32, 61, 32,103,115,117, 98, 40,115,
+ 44,112, 44,102, 41, 10,108, 46,110, 32, 61, 32,108, 46,110,
+ 32, 43, 32, 49, 10,108, 91,108, 46,110, 93, 32, 61, 32,103,
+ 115,117, 98, 40,115, 44, 34, 40, 37,115, 37,115, 42, 41, 36,
+ 34, 44, 34, 34, 41, 10,114,101,116,117,114,110, 32,108, 10,
+ 101,110,100, 10, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32, 99,111,110, 99, 97,116, 32, 40,116, 44,102, 44,108, 41,
+ 10,108,111, 99, 97,108, 32,115, 32, 61, 32, 39, 39, 10,108,
+ 111, 99, 97,108, 32,105, 61,102, 10,119,104,105,108,101, 32,
+ 105, 60, 61,108, 32,100,111, 10,115, 32, 61, 32,115, 46, 46,
+ 116, 91,105, 93, 10,105, 32, 61, 32,105, 43, 49, 10,105,102,
+ 32,105, 32, 60, 61, 32,108, 32,116,104,101,110, 32,115, 32,
+ 61, 32,115, 46, 46, 39, 32, 39, 32,101,110,100, 10,101,110,
+ 100, 10,114,101,116,117,114,110, 32,115, 10,101,110,100, 10,
+ 10, 10,102,117,110, 99,116,105,111,110, 32,111,117,116,112,
+ 117,116, 32, 40, 46, 46, 46, 41, 10,108,111, 99, 97,108, 32,
+ 105, 61, 49, 10,119,104,105,108,101, 32,105, 60, 61, 97,114,
+ 103, 46,110, 32,100,111, 10,105,102, 32, 95, 99,111,110,116,
+ 32, 97,110,100, 32,110,111,116, 32,115,116,114,102,105,110,
+ 100, 40, 95, 99,111,110,116, 44, 39, 91, 37, 40, 44, 34, 93,
+ 39, 41, 32, 97,110,100, 10,115,116,114,102,105,110,100, 40,
+ 97,114,103, 91,105, 93, 44, 34, 94, 91, 37, 97, 95,126, 93,
+ 34, 41, 32,116,104,101,110, 10,119,114,105,116,101, 40, 39,
+ 32, 39, 41, 10,101,110,100, 10,119,114,105,116,101, 40, 97,
+ 114,103, 91,105, 93, 41, 10,105,102, 32, 97,114,103, 91,105,
+ 93, 32,126, 61, 32, 39, 39, 32,116,104,101,110, 10, 95, 99,
+ 111,110,116, 32, 61, 32,115,116,114,115,117, 98, 40, 97,114,
+ 103, 91,105, 93, 44, 45, 49, 44, 45, 49, 41, 10,101,110,100,
+ 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,105,102,
+ 32,115,116,114,102,105,110,100, 40, 97,114,103, 91, 97,114,
+ 103, 46,110, 93, 44, 34, 91, 37, 47, 37, 41, 37, 59, 37,123,
+ 37,125, 93, 36, 34, 41, 32,116,104,101,110, 10, 95, 99,111,
+ 110,116, 61,110,105,108, 32,119,114,105,116,101, 40, 39, 92,
+ 110, 39, 41, 10,101,110,100, 10,101,110,100, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,108, 97,115,
+ 115, 70,101, 97,116,117,114,101, 32, 61, 32,123, 10,125, 10,
+ 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,
+ 115, 70,101, 97,116,117,114,101, 58,115,117,112, 99,111,100,
+ 101, 32, 40, 41, 10,101,110,100, 10, 10, 10,102,117,110, 99,
+ 116,105,111,110, 32, 99,108, 97,115,115, 70,101, 97,116,117,
+ 114,101, 58,100,101, 99,108,116, 97,103, 32, 40, 41, 10,101,
+ 110,100, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,
+ 108, 97,115,115, 70,101, 97,116,117,114,101, 58,114,101,103,
+ 105,115,116,101,114, 32, 40, 41, 10,101,110,100, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 70,
+ 101, 97,116,117,114,101, 58,117,110,114,101,103,105,115,116,
+ 101,114, 32, 40, 41, 10,101,110,100, 10, 10, 10,102,117,110,
+ 99,116,105,111,110, 32, 99,108, 97,115,115, 70,101, 97,116,
+ 117,114,101, 58,112,114,101, 97,109, 98,108,101, 32, 40, 41,
+ 10,101,110,100, 10, 10, 10, 10,102,117,110, 99,116,105,111,
+ 110, 32, 99,108, 97,115,115, 70,101, 97,116,117,114,101, 58,
+ 105,110, 99,108, 97,115,115, 32, 40, 41, 10,105,102, 32,115,
+ 101,108,102, 46,112, 97,114,101,110,116, 32, 97,110,100, 32,
+ 115,101,108,102, 46,112, 97,114,101,110,116, 46,116,121,112,
+ 101, 32, 61, 61, 32, 39, 99,108, 97,115,115, 39, 32,116,104,
+ 101,110, 10,114,101,116,117,114,110, 32,115,101,108,102, 46,
+ 112, 97,114,101,110,116, 46,110, 97,109,101, 10,101,108,115,
+ 101, 10,114,101,116,117,114,110, 32,110,105,108, 10,101,110,
+ 100, 10,101,110,100, 10, 10, 10, 10,102,117,110, 99,116,105,
+ 111,110, 32, 99,108, 97,115,115, 70,101, 97,116,117,114,101,
+ 58,105,110,109,111,100,117,108,101, 32, 40, 41, 10,105,102,
+ 32,115,101,108,102, 46,112, 97,114,101,110,116, 32, 97,110,
+ 100, 32,115,101,108,102, 46,112, 97,114,101,110,116, 46,116,
+ 121,112,101, 32, 61, 61, 32, 39,109,111,100,117,108,101, 39,
+ 32,116,104,101,110, 10,114,101,116,117,114,110, 32,115,101,
+ 108,102, 46,112, 97,114,101,110,116, 46,110, 97,109,101, 10,
+ 101,108,115,101, 10,114,101,116,117,114,110, 32,110,105,108,
+ 10,101,110,100, 10,101,110,100, 10, 10, 10, 10, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 70,101,
+ 97,116,117,114,101, 58, 99,102,117,110, 99,110, 97,109,101,
+ 32, 40,110, 41, 10,105,102, 32,115,101,108,102, 46,112, 97,
+ 114,101,110,116, 32,116,104,101,110, 10,110, 32, 61, 32,115,
+ 101,108,102, 46,112, 97,114,101,110,116, 58, 99,102,117,110,
+ 99,110, 97,109,101, 40,110, 41, 10,101,110,100, 10,105,102,
+ 32,115,101,108,102, 46,108,110, 97,109,101, 32,116,104,101,
+ 110, 10,114,101,116,117,114,110, 32,110, 46, 46, 39, 95, 39,
+ 46, 46,115,101,108,102, 46,108,110, 97,109,101, 10,101,108,
+ 115,101, 10,114,101,116,117,114,110, 32,110, 46, 46, 39, 95,
+ 39, 46, 46,115,101,108,102, 46,110, 97,109,101, 10,101,110,
+ 100, 10,101,110,100, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,108, 97,115,115, 86,
+ 101,114, 98, 97,116,105,109, 32, 61, 32,123, 10,108,105,110,
+ 101, 32, 61, 32, 39, 39, 44, 10, 95, 98, 97,115,101, 32, 61,
+ 32, 99,108, 97,115,115, 70,101, 97,116,117,114,101, 44, 10,
+ 125, 10,115,101,116,116, 97,103, 40, 99,108, 97,115,115, 86,
+ 101,114, 98, 97,116,105,109, 44,116,111,108,117, 97, 95,116,
+ 97,103, 41, 10, 10, 10,102,117,110, 99,116,105,111,110, 32,
+ 99,108, 97,115,115, 86,101,114, 98, 97,116,105,109, 58,112,
+ 114,101, 97,109, 98,108,101, 32, 40, 41, 10,105,102, 32,110,
+ 111,116, 32,115,101,108,102, 46, 99,111,110,100, 32,116,104,
+ 101,110, 10,119,114,105,116,101, 40,115,101,108,102, 46,108,
+ 105,110,101, 41, 10,101,110,100, 10,101,110,100, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 86,
+ 101,114, 98, 97,116,105,109, 58,115,117,112, 99,111,100,101,
+ 32, 40, 41, 10,105,102, 32,115,101,108,102, 46, 99,111,110,
+ 100, 32,116,104,101,110, 10,119,114,105,116,101, 40,115,101,
+ 108,102, 46,108,105,110,101, 41, 10,119,114,105,116,101, 40,
+ 39, 92,110, 39, 41, 10,101,110,100, 10,101,110,100, 10, 10,
+ 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115,
+ 86,101,114, 98, 97,116,105,109, 58,114,101,103,105,115,116,
+ 101,114, 32, 40, 41, 10,105,102, 32,115,101,108,102, 46, 99,
+ 111,110,100, 32,116,104,101,110, 10,119,114,105,116,101, 40,
+ 115,101,108,102, 46,108,105,110,101, 41, 10,101,110,100, 10,
+ 101,110,100, 10, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32, 99,108, 97,115,115, 86,101,114, 98, 97,116,105,109, 58,
+ 112,114,105,110,116, 32, 40,105,100,101,110,116, 44, 99,108,
+ 111,115,101, 41, 10,112,114,105,110,116, 40,105,100,101,110,
+ 116, 46, 46, 34, 86,101,114, 98, 97,116,105,109,123, 34, 41,
+ 10,112,114,105,110,116, 40,105,100,101,110,116, 46, 46, 34,
+ 32,108,105,110,101, 32, 61, 32, 39, 34, 46, 46,115,101,108,
+ 102, 46,108,105,110,101, 46, 46, 34, 39, 44, 34, 41, 10,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34,125, 34,
+ 46, 46, 99,108,111,115,101, 41, 10,101,110,100, 10, 10, 10,
+ 10,102,117,110, 99,116,105,111,110, 32, 95, 86,101,114, 98,
+ 97,116,105,109, 32, 40,116, 41, 10,116, 46, 95, 98, 97,115,
+ 101, 32, 61, 32, 99,108, 97,115,115, 86,101,114, 98, 97,116,
+ 105,109, 10,115,101,116,116, 97,103, 40,116, 44,116,111,108,
+ 117, 97, 95,116, 97,103, 41, 10, 97,112,112,101,110,100, 40,
+ 116, 41, 10,114,101,116,117,114,110, 32,116, 10,101,110,100,
+ 10, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 86,101,
+ 114, 98, 97,116,105,109, 32, 40,108, 41, 10,108,111, 99, 97,
+ 108, 32, 99, 10,105,102, 32,115,116,114,115,117, 98, 40,108,
+ 44, 49, 44, 49, 41, 32, 61, 61, 32, 39, 36, 39, 32,116,104,
+ 101,110, 10, 99, 32, 61, 32, 49, 10,108, 32, 61, 32,115,116,
+ 114,115,117, 98, 40,108, 44, 50, 41, 10,101,110,100, 10,114,
+ 101,116,117,114,110, 32, 95, 86,101,114, 98, 97,116,105,109,
+ 32,123, 10,108,105,110,101, 32, 61, 32,108, 44, 10, 99,111,
+ 110,100, 32, 61, 32, 99, 10,125, 10,101,110,100, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 99,108, 97,115,115, 67,111,100,101, 32, 61, 32,123, 10,116,
+ 101,120,116, 32, 61, 32, 39, 39, 44, 10, 95, 98, 97,115,101,
+ 32, 61, 32, 99,108, 97,115,115, 70,101, 97,116,117,114,101,
+ 44, 10,125, 10,115,101,116,116, 97,103, 40, 99,108, 97,115,
+ 115, 67,111,100,101, 44,116,111,108,117, 97, 95,116, 97,103,
+ 41, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108,
+ 97,115,115, 67,111,100,101, 58,114,101,103,105,115,116,101,
+ 114, 32, 40, 41, 10, 10,108,111, 99, 97,108, 32,115, 32, 61,
+ 32, 99,108,101, 97,110, 40,115,101,108,102, 46,116,101,120,
+ 116, 41, 10,105,102, 32,110,111,116, 32,115, 32,116,104,101,
+ 110, 10,101,114,114,111,114, 40, 34,112, 97,114,115,101,114,
+ 32,101,114,114,111,114, 32,105,110, 32,101,109, 98,101,100,
+ 100,101,100, 32, 99,111,100,101, 34, 41, 10,101,110,100, 10,
+ 10, 10,111,117,116,112,117,116, 40, 39, 92,110, 32,123, 32,
+ 47, 42, 32, 98,101,103,105,110, 32,101,109, 98,101,100,100,
+ 101,100, 32,108,117, 97, 32, 99,111,100,101, 32, 42, 47, 92,
+ 110, 39, 41, 10,111,117,116,112,117,116, 40, 39, 32,115,116,
+ 97,116,105, 99, 32,117,110,115,105,103,110,101,100, 32, 99,
+ 104, 97,114, 32, 66, 91, 93, 32, 61, 32,123, 92,110, 32, 39,
+ 41, 10,108,111, 99, 97,108, 32,116, 61,123,110, 61, 48,125,
+ 10,108,111, 99, 97,108, 32, 98, 32, 61, 32,103,115,117, 98,
+ 40,115, 44, 39, 40, 46, 41, 39, 44,102,117,110, 99,116,105,
+ 111,110, 32, 40, 99, 41, 10,108,111, 99, 97,108, 32,101, 32,
+ 61, 32, 39, 39, 10, 37,116, 46,110, 61, 37,116, 46,110, 43,
+ 49, 32,105,102, 32, 37,116, 46,110, 61, 61, 49, 53, 32,116,
+ 104,101,110, 32, 37,116, 46,110, 61, 48, 32,101, 61, 39, 92,
+ 110, 32, 39, 32,101,110,100, 10,114,101,116,117,114,110, 32,
+ 102,111,114,109, 97,116, 40, 39, 37, 51,117, 44, 37,115, 39,
+ 44,115,116,114, 98,121,116,101, 40, 99, 41, 44,101, 41, 10,
+ 101,110,100, 10, 41, 10,111,117,116,112,117,116, 40, 98, 46,
+ 46,115,116,114, 98,121,116,101, 40, 34, 32, 34, 41, 41, 10,
+ 111,117,116,112,117,116, 40, 39, 92,110, 32,125, 59, 92,110,
+ 39, 41, 10,111,117,116,112,117,116, 40, 39, 32,108,117, 97,
+ 95,100,111, 98,117,102,102,101,114, 40,116,111,108,117, 97,
+ 95, 83, 44, 40, 99,104, 97,114, 42, 41, 66, 44,115,105,122,
+ 101,111,102, 40, 66, 41, 44, 34,116,111,108,117, 97, 58, 32,
+ 101,109, 98,101,100,100,101,100, 32, 76,117, 97, 32, 99,111,
+ 100,101, 34, 41, 59, 39, 41, 10,111,117,116,112,117,116, 40,
+ 39, 32,125, 32, 47, 42, 32,101,110,100, 32,111,102, 32,101,
+ 109, 98,101,100,100,101,100, 32,108,117, 97, 32, 99,111,100,
+ 101, 32, 42, 47, 92,110, 92,110, 39, 41, 10,101,110,100, 10,
+ 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,
+ 115,115, 67,111,100,101, 58,112,114,105,110,116, 32, 40,105,
+ 100,101,110,116, 44, 99,108,111,115,101, 41, 10,112,114,105,
+ 110,116, 40,105,100,101,110,116, 46, 46, 34, 67,111,100,101,
+ 123, 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,116,
+ 46, 46, 34, 32,116,101,120,116, 32, 61, 32, 91, 91, 34, 46,
+ 46,115,101,108,102, 46,116,101,120,116, 46, 46, 34, 93, 93,
+ 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,116,
+ 46, 46, 34,125, 34, 46, 46, 99,108,111,115,101, 41, 10,101,
+ 110,100, 10, 10, 10, 10,102,117,110, 99,116,105,111,110, 32,
+ 95, 67,111,100,101, 32, 40,116, 41, 10,116, 46, 95, 98, 97,
+ 115,101, 32, 61, 32, 99,108, 97,115,115, 67,111,100,101, 10,
+ 115,101,116,116, 97,103, 40,116, 44,116,111,108,117, 97, 95,
+ 116, 97,103, 41, 10, 97,112,112,101,110,100, 40,116, 41, 10,
+ 114,101,116,117,114,110, 32,116, 10,101,110,100, 10, 10, 10,
+ 10,102,117,110, 99,116,105,111,110, 32, 67,111,100,101, 32,
+ 40,108, 41, 10,114,101,116,117,114,110, 32, 95, 67,111,100,
+ 101, 32,123, 10,116,101,120,116, 32, 61, 32,108, 10,125, 10,
+ 101,110,100, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,108, 97,
+ 115,115, 84,121,112,101,100,101,102, 32, 61, 32,123, 10,117,
+ 116,121,112,101, 32, 61, 32, 39, 39, 44, 10,109,111,100, 32,
+ 61, 32, 39, 39, 44, 10,116,121,112,101, 32, 61, 32, 39, 39,
+ 10,125, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,
+ 108, 97,115,115, 84,121,112,101,100,101,102, 58,112,114,105,
+ 110,116, 32, 40,105,100,101,110,116, 44, 99,108,111,115,101,
+ 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46, 46,
+ 34, 84,121,112,101,100,101,102,123, 34, 41, 10,112,114,105,
+ 110,116, 40,105,100,101,110,116, 46, 46, 34, 32,117,116,121,
+ 112,101, 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,117,
+ 116,121,112,101, 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,
+ 110,116, 40,105,100,101,110,116, 46, 46, 34, 32,109,111,100,
+ 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,109,111,100,
+ 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,
+ 100,101,110,116, 46, 46, 34, 32,116,121,112,101, 32, 61, 32,
+ 39, 34, 46, 46,115,101,108,102, 46,116,121,112,101, 46, 46,
+ 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,
+ 110,116, 46, 46, 34,125, 34, 46, 46, 99,108,111,115,101, 41,
+ 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32, 95, 84,121,112,101,100,101,102, 32, 40,116, 41, 10,116,
+ 46, 95, 98, 97,115,101, 32, 61, 32, 99,108, 97,115,115, 84,
+ 121,112,101,100,101,102, 10,115,101,116,116, 97,103, 40,116,
+ 44,116,111,108,117, 97, 95,116, 97,103, 41, 10, 97,112,112,
+ 101,110,100,116,121,112,101,100,101,102, 40,116, 41, 10,114,
+ 101,116,117,114,110, 32,116, 10,101,110,100, 10, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32, 84,121,112,101,100,101,
+ 102, 32, 40,115, 41, 10,105,102, 32,115,116,114,102,105,110,
+ 100, 40,115, 44, 39, 91, 37, 42, 38, 93, 39, 41, 32,116,104,
+ 101,110, 10,116,111,108,117, 97, 95,101,114,114,111,114, 40,
+ 34, 35,105,110,118, 97,108,105,100, 32,116,121,112,101,100,
+ 101,102, 58, 32,112,111,105,110,116,101,114,115, 32, 40, 97,
+ 110,100, 32,114,101,102,101,114,101,110, 99,101,115, 41, 32,
+ 97,114,101, 32,110,111,116, 32,115,117,112,112,111,114,116,
+ 101,100, 34, 41, 10,101,110,100, 10,108,111, 99, 97,108, 32,
+ 116, 32, 61, 32,115,112,108,105,116, 40,103,115,117, 98, 40,
+ 115, 44, 34, 37,115, 37,115, 42, 34, 44, 34, 32, 34, 41, 44,
+ 34, 32, 34, 41, 10,114,101,116,117,114,110, 32, 95, 84,121,
+ 112,101,100,101,102, 32,123, 10,117,116,121,112,101, 32, 61,
+ 32,116, 91,116, 46,110, 93, 44, 10,116,121,112,101, 32, 61,
+ 32,116, 91,116, 46,110, 45, 49, 93, 44, 10,109,111,100, 32,
+ 61, 32, 99,111,110, 99, 97,116, 40,116, 44, 49, 44,116, 46,
+ 110, 45, 50, 41, 10,125, 10,101,110,100, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,108, 97,115,
+ 115, 67,111,110,116, 97,105,110,101,114, 32, 61, 10,123, 10,
+ 99,117,114,114, 32, 61, 32,110,105,108, 44, 10, 95, 98, 97,
+ 115,101, 32, 61, 32, 99,108, 97,115,115, 70,101, 97,116,117,
+ 114,101, 44, 10,125, 10,115,101,116,116, 97,103, 40, 99,108,
+ 97,115,115, 67,111,110,116, 97,105,110,101,114, 44,116,111,
+ 108,117, 97, 95,116, 97,103, 41, 10, 10, 10,102,117,110, 99,
+ 116,105,111,110, 32, 99,108, 97,115,115, 67,111,110,116, 97,
+ 105,110,101,114, 58,100,101, 99,108,116, 97,103, 32, 40, 41,
+ 10,112,117,115,104, 40,115,101,108,102, 41, 10,108,111, 99,
+ 97,108, 32,105, 61, 49, 10,119,104,105,108,101, 32,115,101,
+ 108,102, 91,105, 93, 32,100,111, 10,115,101,108,102, 91,105,
+ 93, 58,100,101, 99,108,116, 97,103, 40, 41, 10,105, 32, 61,
+ 32,105, 43, 49, 10,101,110,100, 10,112,111,112, 40, 41, 10,
+ 101,110,100, 10, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114,
+ 58,115,117,112, 99,111,100,101, 32, 40, 41, 10,112,117,115,
+ 104, 40,115,101,108,102, 41, 10,108,111, 99, 97,108, 32,105,
+ 61, 49, 10,119,104,105,108,101, 32,115,101,108,102, 91,105,
+ 93, 32,100,111, 10,115,101,108,102, 91,105, 93, 58,115,117,
+ 112, 99,111,100,101, 40, 41, 10,105, 32, 61, 32,105, 43, 49,
+ 10,101,110,100, 10,112,111,112, 40, 41, 10,101,110,100, 10,
+ 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 95, 67,111,
+ 110,116, 97,105,110,101,114, 32, 40,115,101,108,102, 41, 10,
+ 115,101,108,102, 46, 95, 98, 97,115,101, 32, 61, 32, 99,108,
+ 97,115,115, 67,111,110,116, 97,105,110,101,114, 10,115,101,
+ 116,116, 97,103, 40,115,101,108,102, 44,116,111,108,117, 97,
+ 95,116, 97,103, 41, 10,115,101,108,102, 46,110, 32, 61, 32,
+ 48, 10,115,101,108,102, 46,116,121,112,101,100,101,102,115,
+ 32, 61, 32,123,110, 61, 48,125, 10,115,101,108,102, 46,108,
+ 110, 97,109,101,115, 32, 61, 32,123,125, 10,114,101,116,117,
+ 114,110, 32,115,101,108,102, 10,101,110,100, 10, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32,112,117,115,104, 32, 40,116,
+ 41, 10, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,
+ 114, 46, 99,117,114,114, 32, 61, 32,116, 10,101,110,100, 10,
+ 10, 10,102,117,110, 99,116,105,111,110, 32,112,111,112, 32,
+ 40, 41, 10, 99,108, 97,115,115, 67,111,110,116, 97,105,110,
+ 101,114, 46, 99,117,114,114, 32, 61, 32, 99,108, 97,115,115,
+ 67,111,110,116, 97,105,110,101,114, 46, 99,117,114,114, 46,
+ 112, 97,114,101,110,116, 10,101,110,100, 10, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 97,112,112,101,110,100, 32, 40,
+ 116, 41, 10,114,101,116,117,114,110, 32, 99,108, 97,115,115,
+ 67,111,110,116, 97,105,110,101,114, 46, 99,117,114,114, 58,
+ 97,112,112,101,110,100, 40,116, 41, 10,101,110,100, 10, 10,
+ 10,102,117,110, 99,116,105,111,110, 32, 97,112,112,101,110,
+ 100,116,121,112,101,100,101,102, 32, 40,116, 41, 10,114,101,
+ 116,117,114,110, 32, 99,108, 97,115,115, 67,111,110,116, 97,
+ 105,110,101,114, 46, 99,117,114,114, 58, 97,112,112,101,110,
+ 100,116,121,112,101,100,101,102, 40,116, 41, 10,101,110,100,
+ 10, 10, 10,102,117,110, 99,116,105,111,110, 32,102,105,110,
+ 100,116,121,112,101,100,101,102, 32, 40,116,121,112,101, 41,
+ 10,114,101,116,117,114,110, 32, 99,108, 97,115,115, 67,111,
+ 110,116, 97,105,110,101,114, 46, 99,117,114,114, 58,102,105,
+ 110,100,116,121,112,101,100,101,102, 40,116,121,112,101, 41,
+ 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32,105,115,116,121,112,101,100,101,102, 32, 40,116,121,112,
+ 101, 41, 10,114,101,116,117,114,110, 32, 99,108, 97,115,115,
+ 67,111,110,116, 97,105,110,101,114, 46, 99,117,114,114, 58,
+ 105,115,116,121,112,101,100,101,102, 40,116,121,112,101, 41,
+ 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114,
+ 58, 97,112,112,101,110,100, 32, 40,116, 41, 10,115,101,108,
+ 102, 46,110, 32, 61, 32,115,101,108,102, 46,110, 32, 43, 32,
+ 49, 10,115,101,108,102, 91,115,101,108,102, 46,110, 93, 32,
+ 61, 32,116, 10,116, 46,112, 97,114,101,110,116, 32, 61, 32,
+ 115,101,108,102, 10,101,110,100, 10, 10, 10,102,117,110, 99,
+ 116,105,111,110, 32, 99,108, 97,115,115, 67,111,110,116, 97,
+ 105,110,101,114, 58, 97,112,112,101,110,100,116,121,112,101,
+ 100,101,102, 32, 40,116, 41, 10,115,101,108,102, 46,116,121,
+ 112,101,100,101,102,115, 46,110, 32, 61, 32,115,101,108,102,
+ 46,116,121,112,101,100,101,102,115, 46,110, 32, 43, 32, 49,
+ 10,115,101,108,102, 46,116,121,112,101,100,101,102,115, 91,
+ 115,101,108,102, 46,116,121,112,101,100,101,102,115, 46,110,
+ 93, 32, 61, 32,116, 10,101,110,100, 10, 10, 10,102,117,110,
+ 99,116,105,111,110, 32, 99,108, 97,115,115, 67,111,110,116,
+ 97,105,110,101,114, 58,111,118,101,114,108,111, 97,100, 32,
+ 40,108,110, 97,109,101, 41, 10,105,102, 32,110,111,116, 32,
+ 115,101,108,102, 46,108,110, 97,109,101,115, 91,108,110, 97,
+ 109,101, 93, 32,116,104,101,110, 10,115,101,108,102, 46,108,
+ 110, 97,109,101,115, 91,108,110, 97,109,101, 93, 32, 61, 32,
+ 48, 10,101,108,115,101, 10,115,101,108,102, 46,108,110, 97,
+ 109,101,115, 91,108,110, 97,109,101, 93, 32, 61, 32,115,101,
+ 108,102, 46,108,110, 97,109,101,115, 91,108,110, 97,109,101,
+ 93, 32, 43, 32, 49, 10,101,110,100, 10,114,101,116,117,114,
+ 110, 32,102,111,114,109, 97,116, 40, 34, 37, 48, 50,100, 34,
+ 44,115,101,108,102, 46,108,110, 97,109,101,115, 91,108,110,
+ 97,109,101, 93, 41, 10,101,110,100, 10, 10,102,117,110, 99,
+ 116,105,111,110, 32, 99,108, 97,115,115, 67,111,110,116, 97,
+ 105,110,101,114, 58,102,105,110,100,116,121,112,101,100,101,
+ 102, 32, 40,116,121,112,101, 41, 10,108,111, 99, 97,108, 32,
+ 101,110,118, 32, 61, 32,115,101,108,102, 10,119,104,105,108,
+ 101, 32,101,110,118, 32,100,111, 10,105,102, 32,101,110,118,
+ 46,116,121,112,101,100,101,102,115, 32,116,104,101,110, 10,
+ 108,111, 99, 97,108, 32,105, 61, 49, 10,119,104,105,108,101,
+ 32,101,110,118, 46,116,121,112,101,100,101,102,115, 91,105,
+ 93, 32,100,111, 10,105,102, 32,101,110,118, 46,116,121,112,
+ 101,100,101,102,115, 91,105, 93, 46,117,116,121,112,101, 32,
+ 61, 61, 32,116,121,112,101, 32,116,104,101,110, 10,108,111,
+ 99, 97,108, 32,109,111,100, 49, 44,116,121,112,101, 49, 32,
+ 61, 32,101,110,118, 46,116,121,112,101,100,101,102,115, 91,
+ 105, 93, 46,109,111,100, 44,101,110,118, 46,116,121,112,101,
+ 100,101,102,115, 91,105, 93, 46,116,121,112,101, 10,108,111,
+ 99, 97,108, 32,109,111,100, 50, 44,116,121,112,101, 50, 32,
+ 61, 32,102,105,110,100,116,121,112,101,100,101,102, 40,116,
+ 121,112,101, 49, 41, 10,114,101,116,117,114,110, 32,109,111,
+ 100, 50, 46, 46, 39, 32, 39, 46, 46,109,111,100, 49, 44,116,
+ 121,112,101, 50, 10,101,110,100, 10,105, 32, 61, 32,105, 43,
+ 49, 10,101,110,100, 10,101,110,100, 10,101,110,118, 32, 61,
+ 32,101,110,118, 46,112, 97,114,101,110,116, 10,101,110,100,
+ 10,114,101,116,117,114,110, 32, 39, 39, 44,116,121,112,101,
+ 10,101,110,100, 10, 10,102,117,110, 99,116,105,111,110, 32,
+ 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 58,
+ 105,115,116,121,112,101,100,101,102, 32, 40,116,121,112,101,
+ 41, 10,108,111, 99, 97,108, 32,101,110,118, 32, 61, 32,115,
+ 101,108,102, 10,119,104,105,108,101, 32,101,110,118, 32,100,
+ 111, 10,105,102, 32,101,110,118, 46,116,121,112,101,100,101,
+ 102,115, 32,116,104,101,110, 10,108,111, 99, 97,108, 32,105,
+ 61, 49, 10,119,104,105,108,101, 32,101,110,118, 46,116,121,
+ 112,101,100,101,102,115, 91,105, 93, 32,100,111, 10,105,102,
+ 32,101,110,118, 46,116,121,112,101,100,101,102,115, 91,105,
+ 93, 46,117,116,121,112,101, 32, 61, 61, 32,116,121,112,101,
+ 32,116,104,101,110, 10,114,101,116,117,114,110, 32, 49, 10,
+ 101,110,100, 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100,
+ 10,101,110,100, 10,101,110,118, 32, 61, 32,101,110,118, 46,
+ 112, 97,114,101,110,116, 10,101,110,100, 10,114,101,116,117,
+ 114,110, 32,110,105,108, 10,101,110,100, 10, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 99,108, 97,115,115, 67,111,110,
+ 116, 97,105,110,101,114, 58,100,111,112, 97,114,115,101, 32,
+ 40,115, 41, 10, 10, 10,100,111, 10,108,111, 99, 97,108, 32,
+ 98, 44,101, 44,110, 97,109,101, 44, 98,111,100,121, 32, 61,
+ 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115,
+ 42,109,111,100,117,108,101, 37,115, 37,115, 42, 40, 91, 95,
+ 37,119, 93, 91, 95, 37,119, 93, 42, 41, 37,115, 42, 40, 37,
+ 98,123,125, 41, 37,115, 42, 34, 41, 10,105,102, 32, 98, 32,
+ 116,104,101,110, 10, 95, 99,117,114,114, 95, 99,111,100,101,
+ 32, 61, 32,115,116,114,115,117, 98, 40,115, 44, 98, 44,101,
+ 41, 10, 77,111,100,117,108,101, 40,110, 97,109,101, 44, 98,
+ 111,100,121, 41, 10,114,101,116,117,114,110, 32,115,116,114,
+ 115,117, 98, 40,115, 44,101, 43, 49, 41, 10,101,110,100, 10,
+ 101,110,100, 10, 10, 10,100,111, 10,108,111, 99, 97,108, 32,
+ 98, 44,101, 44,110, 97,109,101, 32, 61, 32,115,116,114,102,
+ 105,110,100, 40,115, 44, 34, 94, 37,115, 42, 35,100,101,102,
+ 105,110,101, 37,115, 37,115, 42, 40, 91, 94, 37,115, 93, 42,
+ 41, 91, 94, 92,110, 93, 42, 92,110, 37,115, 42, 34, 41, 10,
+ 105,102, 32, 98, 32,116,104,101,110, 10, 95, 99,117,114,114,
+ 95, 99,111,100,101, 32, 61, 32,115,116,114,115,117, 98, 40,
+ 115, 44, 98, 44,101, 41, 10, 68,101,102,105,110,101, 40,110,
+ 97,109,101, 41, 10,114,101,116,117,114,110, 32,115,116,114,
+ 115,117, 98, 40,115, 44,101, 43, 49, 41, 10,101,110,100, 10,
+ 101,110,100, 10, 10, 10,100,111, 10,108,111, 99, 97,108, 32,
+ 98, 44,101, 44, 98,111,100,121, 32, 61, 32,115,116,114,102,
+ 105,110,100, 40,115, 44, 34, 94, 37,115, 42,101,110,117,109,
+ 91, 94,123, 93, 42, 40, 37, 98,123,125, 41, 37,115, 42, 59,
+ 63, 37,115, 42, 34, 41, 10,105,102, 32, 98, 32,116,104,101,
+ 110, 10, 95, 99,117,114,114, 95, 99,111,100,101, 32, 61, 32,
+ 115,116,114,115,117, 98, 40,115, 44, 98, 44,101, 41, 10, 69,
+ 110,117,109,101,114, 97,116,101, 40, 98,111,100,121, 41, 10,
+ 114,101,116,117,114,110, 32,115,116,114,115,117, 98, 40,115,
+ 44,101, 43, 49, 41, 10,101,110,100, 10,101,110,100, 10, 10,
+ 100,111, 10,108,111, 99, 97,108, 32, 98, 44,101, 44, 98,111,
+ 100,121, 44,110, 97,109,101, 32, 61, 32,115,116,114,102,105,
+ 110,100, 40,115, 44, 34, 94, 37,115, 42,116,121,112,101,100,
+ 101,102, 37,115, 37,115, 42,101,110,117,109, 91, 94,123, 93,
+ 42, 40, 37, 98,123,125, 41, 37,115, 42, 40, 91, 37,119, 95,
+ 93, 91, 94, 37,115, 93, 42, 41, 37,115, 42, 59, 37,115, 42,
+ 34, 41, 10,105,102, 32, 98, 32,116,104,101,110, 10, 95, 99,
+ 117,114,114, 95, 99,111,100,101, 32, 61, 32,115,116,114,115,
+ 117, 98, 40,115, 44, 98, 44,101, 41, 10, 69,110,117,109,101,
+ 114, 97,116,101, 40, 98,111,100,121, 41, 10, 84,121,112,101,
+ 100,101,102, 40, 34,105,110,116, 32, 34, 46, 46,110, 97,109,
+ 101, 41, 10,114,101,116,117,114,110, 32,115,116,114,115,117,
+ 98, 40,115, 44,101, 43, 49, 41, 10,101,110,100, 10,101,110,
+ 100, 10, 10, 10,100,111, 10,108,111, 99, 97,108, 32, 98, 44,
+ 101, 44,100,101, 99,108, 44,107,105,110,100, 44, 97,114,103,
+ 44, 99,111,110,115,116, 32, 61, 32,115,116,114,102,105,110,
+ 100, 40,115, 44, 34, 94, 37,115, 42, 40, 91, 95, 37,119, 93,
+ 91, 95, 37,119, 37,115, 37, 42, 38, 93, 42,111,112,101,114,
+ 97,116,111,114, 41, 37,115, 42, 40, 91, 94, 37,115, 93, 91,
+ 94, 37,115, 93, 42, 41, 37,115, 42, 40, 37, 98, 40, 41, 41,
+ 37,115, 42, 40, 99, 63,111, 63,110, 63,115, 63,116, 63, 41,
+ 37,115, 42, 59, 37,115, 42, 34, 41, 10,105,102, 32, 98, 32,
+ 116,104,101,110, 10, 95, 99,117,114,114, 95, 99,111,100,101,
+ 32, 61, 32,115,116,114,115,117, 98, 40,115, 44, 98, 44,101,
+ 41, 10, 79,112,101,114, 97,116,111,114, 40,100,101, 99,108,
+ 44,107,105,110,100, 44, 97,114,103, 44, 99,111,110,115,116,
+ 41, 10,114,101,116,117,114,110, 32,115,116,114,115,117, 98,
+ 40,115, 44,101, 43, 49, 41, 10,101,110,100, 10,101,110,100,
+ 10, 10, 10,100,111, 10,108,111, 99, 97,108, 32, 98, 44,101,
+ 44,100,101, 99,108, 44, 97,114,103, 44, 99,111,110,115,116,
+ 32, 61, 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94,
+ 37,115, 42, 40, 91,126, 95, 37,119, 93, 91, 95, 64, 37,119,
+ 37,115, 37, 42, 38, 93, 42, 91, 95, 37,119, 93, 41, 37,115,
+ 42, 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,
+ 110, 63,115, 63,116, 63, 41, 37,115, 42, 61, 63, 37,115, 42,
+ 48, 63, 37,115, 42, 59, 37,115, 42, 34, 41, 10,105,102, 32,
+ 110,111,116, 32, 98, 32,116,104,101,110, 10, 10, 98, 44,101,
+ 44,100,101, 99,108, 44, 97,114,103, 44, 99,111,110,115,116,
+ 32, 61, 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94,
+ 37,115, 42, 40, 91, 95, 37,119, 93, 41, 37,115, 42, 40, 37,
+ 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,110, 63,115,
+ 63,116, 63, 41, 37,115, 42, 59, 37,115, 42, 34, 41, 10,101,
+ 110,100, 10,105,102, 32, 98, 32,116,104,101,110, 10, 95, 99,
+ 117,114,114, 95, 99,111,100,101, 32, 61, 32,115,116,114,115,
+ 117, 98, 40,115, 44, 98, 44,101, 41, 10, 70,117,110, 99,116,
+ 105,111,110, 40,100,101, 99,108, 44, 97,114,103, 44, 99,111,
+ 110,115,116, 41, 10,114,101,116,117,114,110, 32,115,116,114,
+ 115,117, 98, 40,115, 44,101, 43, 49, 41, 10,101,110,100, 10,
+ 101,110,100, 10, 10, 10,100,111, 10,108,111, 99, 97,108, 32,
+ 98, 44,101, 44,100,101, 99,108, 44, 97,114,103, 44, 99,111,
+ 110,115,116, 32, 61, 32,115,116,114,102,105,110,100, 40,115,
+ 44, 34, 94, 37,115, 42, 40, 91,126, 95, 37,119, 93, 91, 95,
+ 64, 37,119, 37,115, 37, 42, 38, 93, 42, 91, 95, 37,119, 93,
+ 41, 37,115, 42, 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99,
+ 63,111, 63,110, 63,115, 63,116, 63, 41, 37,115, 42, 37, 98,
+ 123,125, 37,115, 42, 34, 41, 10,105,102, 32,110,111,116, 32,
+ 98, 32,116,104,101,110, 10, 10, 98, 44,101, 44,100,101, 99,
+ 108, 44, 97,114,103, 44, 99,111,110,115,116, 32, 61, 32,115,
+ 116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115, 42, 40,
+ 91, 95, 37,119, 93, 41, 37,115, 42, 40, 37, 98, 40, 41, 41,
+ 37,115, 42, 40, 99, 63,111, 63,110, 63,115, 63,116, 63, 41,
+ 37,115, 42, 37, 98,123,125, 37,115, 42, 34, 41, 10,101,110,
+ 100, 10,105,102, 32, 98, 32,116,104,101,110, 10, 95, 99,117,
+ 114,114, 95, 99,111,100,101, 32, 61, 32,115,116,114,115,117,
+ 98, 40,115, 44, 98, 44,101, 41, 10, 70,117,110, 99,116,105,
+ 111,110, 40,100,101, 99,108, 44, 97,114,103, 44, 99,111,110,
+ 115,116, 41, 10,114,101,116,117,114,110, 32,115,116,114,115,
+ 117, 98, 40,115, 44,101, 43, 49, 41, 10,101,110,100, 10,101,
+ 110,100, 10, 10, 10,100,111, 10,108,111, 99, 97,108, 32, 98,
+ 44,101, 44,110, 97,109,101, 44, 98, 97,115,101, 44, 98,111,
+ 100,121, 32, 61, 32,115,116,114,102,105,110,100, 40,115, 44,
+ 34, 94, 37,115, 42, 99,108, 97,115,115, 37,115, 42, 40, 91,
+ 95, 37,119, 93, 91, 95, 37,119, 93, 42, 41, 37,115, 42, 40,
+ 46, 45, 41, 37,115, 42, 40, 37, 98,123,125, 41, 37,115, 42,
+ 59, 37,115, 42, 34, 41, 10,105,102, 32,110,111,116, 32, 98,
+ 32,116,104,101,110, 10, 98, 44,101, 44,110, 97,109,101, 44,
+ 98, 97,115,101, 44, 98,111,100,121, 32, 61, 32,115,116,114,
+ 102,105,110,100, 40,115, 44, 34, 94, 37,115, 42,115,116,114,
+ 117, 99,116, 37,115, 42, 40, 91, 95, 37,119, 93, 91, 95, 37,
+ 119, 93, 42, 41, 37,115, 42, 40, 46, 45, 41, 37,115, 42, 40,
+ 37, 98,123,125, 41, 37,115, 42, 59, 37,115, 42, 34, 41, 10,
+ 105,102, 32,110,111,116, 32, 98, 32,116,104,101,110, 10, 98,
+ 97,115,101, 32, 61, 32, 39, 39, 10, 98, 44,101, 44, 98,111,
+ 100,121, 44,110, 97,109,101, 32, 61, 32,115,116,114,102,105,
+ 110,100, 40,115, 44, 34, 94, 37,115, 42,116,121,112,101,100,
+ 101,102, 37,115, 37,115, 42,115,116,114,117, 99,116, 37,115,
+ 37,115, 42, 91, 95, 37,119, 93, 42, 37,115, 42, 40, 37, 98,
+ 123,125, 41, 37,115, 42, 40, 91, 95, 37,119, 93, 91, 95, 37,
+ 119, 93, 42, 41, 37,115, 42, 59, 37,115, 42, 34, 41, 10,101,
+ 110,100, 10,101,110,100, 10,105,102, 32, 98, 32,116,104,101,
+ 110, 10,105,102, 32, 98, 97,115,101, 32,126, 61, 32, 39, 39,
+ 32,116,104,101,110, 10,108,111, 99, 97,108, 32, 98, 44,101,
+ 10, 98, 44,101, 44, 98, 97,115,101, 32, 61, 32,115,116,114,
+ 102,105,110,100, 40, 98, 97,115,101, 44, 34, 46, 45, 40, 91,
+ 95, 37,119, 93, 91, 95, 37,119, 93, 42, 41, 36, 34, 41, 10,
+ 101,110,100, 10, 95, 99,117,114,114, 95, 99,111,100,101, 32,
+ 61, 32,115,116,114,115,117, 98, 40,115, 44, 98, 44,101, 41,
+ 10, 67,108, 97,115,115, 40,110, 97,109,101, 44, 98, 97,115,
+ 101, 44, 98,111,100,121, 41, 10,114,101,116,117,114,110, 32,
+ 115,116,114,115,117, 98, 40,115, 44,101, 43, 49, 41, 10,101,
+ 110,100, 10,101,110,100, 10, 10, 10,100,111, 10,108,111, 99,
+ 97,108, 32, 98, 44,101, 44,116,121,112,101,115, 32, 61, 32,
+ 115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115, 42,
+ 116,121,112,101,100,101,102, 37,115, 37,115, 42, 40, 46, 45,
+ 41, 37,115, 42, 59, 37,115, 42, 34, 41, 10,105,102, 32, 98,
+ 32,116,104,101,110, 10, 95, 99,117,114,114, 95, 99,111,100,
+ 101, 32, 61, 32,115,116,114,115,117, 98, 40,115, 44, 98, 44,
+ 101, 41, 10, 84,121,112,101,100,101,102, 40,116,121,112,101,
+ 115, 41, 10,114,101,116,117,114,110, 32,115,116,114,115,117,
+ 98, 40,115, 44,101, 43, 49, 41, 10,101,110,100, 10,101,110,
+ 100, 10, 10, 10,100,111, 10,108,111, 99, 97,108, 32, 98, 44,
+ 101, 44,100,101, 99,108, 32, 61, 32,115,116,114,102,105,110,
+ 100, 40,115, 44, 34, 94, 37,115, 42, 40, 91, 95, 37,119, 93,
+ 91, 95, 64, 37,115, 37,119, 37,100, 37, 42, 38, 93, 42, 91,
+ 95, 37,119, 37,100, 93, 41, 37,115, 42, 59, 37,115, 42, 34,
+ 41, 10,105,102, 32, 98, 32,116,104,101,110, 10, 95, 99,117,
+ 114,114, 95, 99,111,100,101, 32, 61, 32,115,116,114,115,117,
+ 98, 40,115, 44, 98, 44,101, 41, 10, 86, 97,114,105, 97, 98,
+ 108,101, 40,100,101, 99,108, 41, 10,114,101,116,117,114,110,
+ 32,115,116,114,115,117, 98, 40,115, 44,101, 43, 49, 41, 10,
+ 101,110,100, 10,101,110,100, 10, 10, 10,100,111, 10,108,111,
+ 99, 97,108, 32, 98, 44,101, 44,100,101, 99,108, 32, 61, 32,
+ 115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115, 42,
+ 40, 91, 95, 37,119, 93, 91, 93, 91, 95, 64, 37,115, 37,119,
+ 37,100, 37, 42, 38, 37, 45, 37, 62, 93, 42, 91, 93, 95, 37,
+ 119, 37,100, 93, 41, 37,115, 42, 59, 37,115, 42, 34, 41, 10,
+ 105,102, 32, 98, 32,116,104,101,110, 10, 95, 99,117,114,114,
+ 95, 99,111,100,101, 32, 61, 32,115,116,114,115,117, 98, 40,
+ 115, 44, 98, 44,101, 41, 10, 65,114,114, 97,121, 40,100,101,
+ 99,108, 41, 10,114,101,116,117,114,110, 32,115,116,114,115,
+ 117, 98, 40,115, 44,101, 43, 49, 41, 10,101,110,100, 10,101,
+ 110,100, 10, 10, 10,100,111, 10,108,111, 99, 97,108, 32, 98,
+ 44,101, 44, 99,111,100,101, 32, 61, 32,115,116,114,102,105,
+ 110,100, 40,115, 44, 34, 94, 37,115, 42, 40, 37, 98, 92, 49,
+ 92, 50, 41, 34, 41, 10,105,102, 32, 98, 32,116,104,101,110,
+ 10, 67,111,100,101, 40,115,116,114,115,117, 98, 40, 99,111,
+ 100,101, 44, 50, 44, 45, 50, 41, 41, 10,114,101,116,117,114,
+ 110, 32,115,116,114,115,117, 98, 40,115, 44,101, 43, 49, 41,
+ 10,101,110,100, 10,101,110,100, 10, 10, 10,100,111, 10,108,
+ 111, 99, 97,108, 32, 98, 44,101, 44,108,105,110,101, 32, 61,
+ 32,115,116,114,102,105,110,100, 40,115, 44, 34, 94, 37,115,
+ 42, 37, 36, 40, 46, 45, 92,110, 41, 34, 41, 10,105,102, 32,
+ 98, 32,116,104,101,110, 10, 86,101,114, 98, 97,116,105,109,
+ 40,108,105,110,101, 41, 10,114,101,116,117,114,110, 32,115,
+ 116,114,115,117, 98, 40,115, 44,101, 43, 49, 41, 10,101,110,
+ 100, 10,101,110,100, 10, 10, 10,105,102, 32,103,115,117, 98,
+ 40,115, 44, 34, 37,115, 37,115, 42, 34, 44, 34, 34, 41, 32,
+ 126, 61, 32, 34, 34, 32,116,104,101,110, 10, 95, 99,117,114,
+ 114, 95, 99,111,100,101, 32, 61, 32,115, 10,101,114,114,111,
+ 114, 40, 34, 35,112, 97,114,115,101, 32,101,114,114,111,114,
+ 34, 41, 10,101,108,115,101, 10,114,101,116,117,114,110, 32,
+ 34, 34, 10,101,110,100, 10,101,110,100, 10, 10,102,117,110,
+ 99,116,105,111,110, 32, 99,108, 97,115,115, 67,111,110,116,
+ 97,105,110,101,114, 58,112, 97,114,115,101, 32, 40,115, 41,
+ 10,119,104,105,108,101, 32,115, 32,126, 61, 32, 39, 39, 32,
+ 100,111, 10,115, 32, 61, 32,115,101,108,102, 58,100,111,112,
+ 97,114,115,101, 40,115, 41, 10,101,110,100, 10,101,110,100,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 99,108, 97,115,115, 80, 97, 99,107, 97,
+ 103,101, 32, 61, 32,123, 10, 95, 98, 97,115,101, 32, 61, 32,
+ 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 44,
+ 10,116,121,112,101, 32, 61, 32, 39,112, 97, 99,107, 97,103,
+ 101, 39, 10,125, 10,115,101,116,116, 97,103, 40, 99,108, 97,
+ 115,115, 80, 97, 99,107, 97,103,101, 44,116,111,108,117, 97,
+ 95,116, 97,103, 41, 10, 10, 10,102,117,110, 99,116,105,111,
+ 110, 32, 99,108, 97,115,115, 80, 97, 99,107, 97,103,101, 58,
+ 112,114,105,110,116, 32, 40, 41, 10,112,114,105,110,116, 40,
+ 34, 80, 97, 99,107, 97,103,101, 58, 32, 34, 46, 46,115,101,
+ 108,102, 46,110, 97,109,101, 41, 10,108,111, 99, 97,108, 32,
+ 105, 61, 49, 10,119,104,105,108,101, 32,115,101,108,102, 91,
+ 105, 93, 32,100,111, 10,115,101,108,102, 91,105, 93, 58,112,
+ 114,105,110,116, 40, 34, 34, 44, 34, 34, 41, 10,105, 32, 61,
+ 32,105, 43, 49, 10,101,110,100, 10,101,110,100, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 80, 97,
+ 99,107, 97,103,101, 58,112,114,101,112,114,111, 99,101,115,
+ 115, 32, 40, 41, 10,115,101,108,102, 46, 99,111,100,101, 32,
+ 61, 32, 34, 92,110, 34, 46, 46,115,101,108,102, 46, 99,111,
+ 100,101, 10, 10,108,111, 99, 97,108, 32, 86, 32, 61, 32,123,
+ 125, 10,115,101,108,102, 46, 99,111,100,101, 32, 61, 32,103,
+ 115,117, 98, 40,115,101,108,102, 46, 99,111,100,101, 44, 34,
+ 92,110, 40, 37,115, 42, 37, 36, 91, 94, 37, 91, 37, 93, 93,
+ 91, 94, 92,110, 93, 42, 41, 34, 44,102,117,110, 99,116,105,
+ 111,110, 32, 40,118, 41, 10,116,105,110,115,101,114,116, 40,
+ 37, 86, 44,118, 41, 10,114,101,116,117,114,110, 32, 34, 92,
+ 110, 36, 34, 46, 46,103,101,116,110, 40, 37, 86, 41, 46, 46,
+ 34, 36, 34, 10,101,110,100, 41, 10, 10,108,111, 99, 97,108,
+ 32, 67, 32, 61, 32,123,125, 10,115,101,108,102, 46, 99,111,
+ 100,101, 32, 61, 32,103,115,117, 98, 40,115,101,108,102, 46,
+ 99,111,100,101, 44, 34, 92,110, 37,115, 42, 37, 36, 37, 91,
+ 34, 44, 34, 92, 49, 34, 41, 10,115,101,108,102, 46, 99,111,
+ 100,101, 32, 61, 32,103,115,117, 98, 40,115,101,108,102, 46,
+ 99,111,100,101, 44, 34, 92,110, 37,115, 42, 37, 36, 37, 93,
+ 34, 44, 34, 92, 50, 34, 41, 10,115,101,108,102, 46, 99,111,
+ 100,101, 32, 61, 32,103,115,117, 98, 40,115,101,108,102, 46,
+ 99,111,100,101, 44, 34, 40, 37, 98, 92, 49, 92, 50, 41, 34,
+ 44, 32,102,117,110, 99,116,105,111,110, 32, 40, 99, 41, 10,
+ 116,105,110,115,101,114,116, 40, 37, 67, 44, 99, 41, 10,114,
+ 101,116,117,114,110, 32, 34, 92,110, 36, 91, 34, 46, 46,103,
+ 101,116,110, 40, 37, 67, 41, 46, 46, 34, 93, 36, 34, 10,101,
+ 110,100, 41, 10, 10, 10,115,101,108,102, 46, 99,111,100,101,
+ 32, 61, 32,103,115,117, 98, 40,115,101,108,102, 46, 99,111,
+ 100,101, 44, 34, 40, 47, 47, 91, 94, 92,110, 93, 42, 41, 34,
+ 44, 34, 34, 41, 10,115,101,108,102, 46, 99,111,100,101, 32,
+ 61, 32,103,115,117, 98, 40,115,101,108,102, 46, 99,111,100,
+ 101, 44, 34, 47, 37, 42, 34, 44, 34, 92, 49, 34, 41, 10,115,
+ 101,108,102, 46, 99,111,100,101, 32, 61, 32,103,115,117, 98,
+ 40,115,101,108,102, 46, 99,111,100,101, 44, 34, 37, 42, 47,
+ 34, 44, 34, 92, 50, 34, 41, 10,115,101,108,102, 46, 99,111,
+ 100,101, 32, 61, 32,103,115,117, 98, 40,115,101,108,102, 46,
+ 99,111,100,101, 44, 34, 37, 98, 92, 49, 92, 50, 34, 44, 34,
+ 34, 41, 10,115,101,108,102, 46, 99,111,100,101, 32, 61, 32,
+ 103,115,117, 98, 40,115,101,108,102, 46, 99,111,100,101, 44,
+ 34, 92, 49, 34, 44, 34, 47, 37, 42, 34, 41, 10,115,101,108,
+ 102, 46, 99,111,100,101, 32, 61, 32,103,115,117, 98, 40,115,
+ 101,108,102, 46, 99,111,100,101, 44, 34, 92, 50, 34, 44, 34,
+ 37, 42, 47, 34, 41, 10,115,101,108,102, 46, 99,111,100,101,
+ 32, 61, 32,103,115,117, 98, 40,115,101,108,102, 46, 99,111,
+ 100,101, 44, 34, 37,115, 42, 64, 37,115, 42, 34, 44, 34, 64,
+ 34, 41, 10,115,101,108,102, 46, 99,111,100,101, 32, 61, 32,
+ 103,115,117, 98, 40,115,101,108,102, 46, 99,111,100,101, 44,
+ 34, 37,115, 63,105,110,108,105,110,101, 40, 37,115, 41, 34,
+ 44, 34, 37, 49, 34, 41, 10,115,101,108,102, 46, 99,111,100,
+ 101, 32, 61, 32,103,115,117, 98, 40,115,101,108,102, 46, 99,
+ 111,100,101, 44, 34, 37,115, 63,101,120,116,101,114,110, 40,
+ 37,115, 41, 34, 44, 34, 37, 49, 34, 41, 10,115,101,108,102,
+ 46, 99,111,100,101, 32, 61, 32,103,115,117, 98, 40,115,101,
+ 108,102, 46, 99,111,100,101, 44, 34, 37,115, 63,118,105,114,
+ 116,117, 97,108, 40, 37,115, 41, 34, 44, 34, 37, 49, 34, 41,
+ 10,115,101,108,102, 46, 99,111,100,101, 32, 61, 32,103,115,
+ 117, 98, 40,115,101,108,102, 46, 99,111,100,101, 44, 34,112,
+ 117, 98,108,105, 99, 58, 34, 44, 34, 34, 41, 10,115,101,108,
+ 102, 46, 99,111,100,101, 32, 61, 32,103,115,117, 98, 40,115,
+ 101,108,102, 46, 99,111,100,101, 44, 34, 40, 91, 94, 37,119,
+ 95, 93, 41,118,111,105,100, 37,115, 42, 37, 42, 34, 44, 34,
+ 37, 49, 95,117,115,101,114,100, 97,116, 97, 32, 34, 41, 10,
+ 115,101,108,102, 46, 99,111,100,101, 32, 61, 32,103,115,117,
+ 98, 40,115,101,108,102, 46, 99,111,100,101, 44, 34, 40, 91,
+ 94, 37,119, 95, 93, 41,118,111,105,100, 37,115, 42, 37, 42,
+ 34, 44, 34, 37, 49, 95,117,115,101,114,100, 97,116, 97, 32,
+ 34, 41, 10,115,101,108,102, 46, 99,111,100,101, 32, 61, 32,
+ 103,115,117, 98, 40,115,101,108,102, 46, 99,111,100,101, 44,
+ 34, 40, 91, 94, 37,119, 95, 93, 41, 99,104, 97,114, 37,115,
+ 42, 37, 42, 34, 44, 34, 37, 49, 95, 99,115,116,114,105,110,
+ 103, 32, 34, 41, 10, 10, 10,115,101,108,102, 46, 99,111,100,
+ 101, 32, 61, 32,103,115,117, 98, 40,115,101,108,102, 46, 99,
+ 111,100,101, 44, 34, 37, 36, 37, 91, 40, 37,100, 43, 41, 37,
+ 93, 37, 36, 34, 44,102,117,110, 99,116,105,111,110, 32, 40,
+ 110, 41, 10,114,101,116,117,114,110, 32, 37, 67, 91,116,111,
+ 110,117,109, 98,101,114, 40,110, 41, 93, 10,101,110,100, 41,
+ 10, 10,115,101,108,102, 46, 99,111,100,101, 32, 61, 32,103,
+ 115,117, 98, 40,115,101,108,102, 46, 99,111,100,101, 44, 34,
+ 37, 36, 40, 37,100, 43, 41, 37, 36, 34, 44,102,117,110, 99,
+ 116,105,111,110, 32, 40,110, 41, 10,114,101,116,117,114,110,
+ 32, 37, 86, 91,116,111,110,117,109, 98,101,114, 40,110, 41,
+ 93, 10,101,110,100, 41, 10,101,110,100, 10, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 99,108, 97,115,115, 80, 97, 99,
+ 107, 97,103,101, 58,112,114,101, 97,109, 98,108,101, 32, 40,
+ 41, 10,111,117,116,112,117,116, 40, 39, 47, 42, 92,110, 39,
+ 41, 10,111,117,116,112,117,116, 40, 39, 42, 42, 32, 76,117,
+ 97, 32, 98,105,110,100,105,110,103, 58, 32, 39, 46, 46,115,
+ 101,108,102, 46,110, 97,109,101, 46, 46, 39, 92,110, 39, 41,
+ 10,111,117,116,112,117,116, 40, 39, 42, 42, 32, 71,101,110,
+ 101,114, 97,116,101,100, 32, 97,117,116,111,109, 97,116,105,
+ 99, 97,108,108,121, 32, 98,121, 32, 39, 46, 46, 84, 79, 76,
+ 85, 65, 95, 86, 69, 82, 83, 73, 79, 78, 46, 46, 39, 32,111,
+ 110, 32, 39, 46, 46,100, 97,116,101, 40, 41, 46, 46, 39, 46,
+ 92,110, 39, 41, 10,111,117,116,112,117,116, 40, 39, 42, 47,
+ 92,110, 92,110, 39, 41, 10, 10,111,117,116,112,117,116, 40,
+ 39, 35,105,110, 99,108,117,100,101, 32, 34,108,117, 97, 47,
+ 116,111,108,117, 97, 46,104, 34, 92,110, 92,110, 39, 41, 10,
+ 10,105,102, 32,110,111,116, 32,102,108, 97,103,115, 46,104,
+ 32,116,104,101,110, 10,111,117,116,112,117,116, 40, 39, 47,
+ 42, 32, 69,120,112,111,114,116,101,100, 32,102,117,110, 99,
+ 116,105,111,110, 32, 42, 47, 39, 41, 10,111,117,116,112,117,
+ 116, 40, 39,105,110,116, 32,116,111,108,117, 97, 95, 39, 46,
+ 46,115,101,108,102, 46,110, 97,109,101, 46, 46, 39, 95,111,
+ 112,101,110, 32, 40,108,117, 97, 95, 83,116, 97,116,101, 42,
+ 32,116,111,108,117, 97, 95, 83, 41, 59, 39, 41, 10,111,117,
+ 116,112,117,116, 40, 39,118,111,105,100, 32,116,111,108,117,
+ 97, 95, 39, 46, 46,115,101,108,102, 46,110, 97,109,101, 46,
+ 46, 39, 95, 99,108,111,115,101, 32, 40,108,117, 97, 95, 83,
+ 116, 97,116,101, 42, 32,116,111,108,117, 97, 95, 83, 41, 59,
+ 39, 41, 10,111,117,116,112,117,116, 40, 39, 92,110, 39, 41,
+ 10,101,110,100, 10, 10,108,111, 99, 97,108, 32,105, 61, 49,
+ 10,119,104,105,108,101, 32,115,101,108,102, 91,105, 93, 32,
+ 100,111, 10,115,101,108,102, 91,105, 93, 58,112,114,101, 97,
+ 109, 98,108,101, 40, 41, 10,105, 32, 61, 32,105, 43, 49, 10,
+ 101,110,100, 10,111,117,116,112,117,116, 40, 39, 92,110, 39,
+ 41, 10,111,117,116,112,117,116, 40, 39, 47, 42, 32,102,117,
+ 110, 99,116,105,111,110, 32,116,111, 32,114,101,103,105,115,
+ 116,101,114, 32,116,121,112,101, 32, 42, 47, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39,115,116, 97,116,105, 99, 32,118,
+ 111,105,100, 32,116,111,108,117, 97, 73, 95,114,101,103, 95,
+ 116,121,112,101,115, 32, 40,108,117, 97, 95, 83,116, 97,116,
+ 101, 42, 32,116,111,108,117, 97, 95, 83, 41, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39,123, 39, 41, 10,102,111,114,101,
+ 97, 99,104, 40, 95,117,115,101,114,116,121,112,101, 44,102,
+ 117,110, 99,116,105,111,110, 40,110, 44,118, 41, 32,111,117,
+ 116,112,117,116, 40, 39, 32,116,111,108,117, 97, 95,117,115,
+ 101,114,116,121,112,101, 40,116,111,108,117, 97, 95, 83, 44,
+ 34, 39, 44,118, 44, 39, 34, 41, 59, 39, 41, 32,101,110,100,
+ 41, 10,111,117,116,112,117,116, 40, 39,125, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39, 92,110, 39, 41, 10, 10,111,117,
+ 116,112,117,116, 40, 39, 47, 42, 32,101,114,114,111,114, 32,
+ 109,101,115,115, 97,103,101,115, 32, 42, 47, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39, 35,100,101,102,105,110,101, 32,
+ 84, 79, 76, 85, 65, 95, 69, 82, 82, 95, 83, 69, 76, 70, 32,
+ 116,111,108,117, 97, 95,101,114,114,111,114, 40,116,111,108,
+ 117, 97, 95, 83, 44, 92, 34,105,110,118, 97,108,105,100, 32,
+ 92, 39,115,101,108,102, 92, 39, 92, 34, 41, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39, 35,100,101,102,105,110,101, 32,
+ 84, 79, 76, 85, 65, 95, 69, 82, 82, 95, 65, 83, 83, 73, 71,
+ 78, 32,116,111,108,117, 97, 95,101,114,114,111,114, 40,116,
+ 111,108,117, 97, 95, 83, 44, 92, 34, 35,118,105,110,118, 97,
+ 108,105,100, 32,116,121,112,101, 32,105,110, 32,118, 97,114,
+ 105, 97, 98,108,101, 32, 97,115,115,105,103,110,109,101,110,
+ 116, 46, 92, 34, 41, 39, 41, 10,111,117,116,112,117,116, 40,
+ 39, 92,110, 39, 41, 10,101,110,100, 10, 10, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 99,108, 97,115,115, 80, 97, 99,
+ 107, 97,103,101, 58,114,101,103,105,115,116,101,114, 32, 40,
+ 41, 10,111,117,116,112,117,116, 40, 34, 47, 42, 32, 79,112,
+ 101,110, 32,102,117,110, 99,116,105,111,110, 32, 42, 47, 34,
+ 41, 10,111,117,116,112,117,116, 40, 34,105,110,116, 32,116,
+ 111,108,117, 97, 95, 34, 46, 46,115,101,108,102, 46,110, 97,
+ 109,101, 46, 46, 34, 95,111,112,101,110, 32, 40,108,117, 97,
+ 95, 83,116, 97,116,101, 42, 32,116,111,108,117, 97, 95, 83,
+ 41, 34, 41, 10,111,117,116,112,117,116, 40, 34,123, 34, 41,
+ 10,111,117,116,112,117,116, 40, 34, 32,116,111,108,117, 97,
+ 95,111,112,101,110, 40,116,111,108,117, 97, 95, 83, 41, 59,
+ 34, 41, 10,111,117,116,112,117,116, 40, 34, 32,116,111,108,
+ 117, 97, 73, 95,114,101,103, 95,116,121,112,101,115, 40,116,
+ 111,108,117, 97, 95, 83, 41, 59, 34, 41, 10,108,111, 99, 97,
+ 108, 32,105, 61, 49, 10,119,104,105,108,101, 32,115,101,108,
+ 102, 91,105, 93, 32,100,111, 10,115,101,108,102, 91,105, 93,
+ 58,114,101,103,105,115,116,101,114, 40, 41, 10,105, 32, 61,
+ 32,105, 43, 49, 10,101,110,100, 10,111,117,116,112,117,116,
+ 40, 34, 32,114,101,116,117,114,110, 32, 49, 59, 34, 41, 10,
+ 111,117,116,112,117,116, 40, 34,125, 34, 41, 10,101,110,100,
+ 10, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108,
+ 97,115,115, 80, 97, 99,107, 97,103,101, 58,117,110,114,101,
+ 103,105,115,116,101,114, 32, 40, 41, 10,111,117,116,112,117,
+ 116, 40, 34, 47, 42, 32, 67,108,111,115,101, 32,102,117,110,
+ 99,116,105,111,110, 32, 42, 47, 34, 41, 10,111,117,116,112,
+ 117,116, 40, 34,118,111,105,100, 32,116,111,108,117, 97, 95,
+ 34, 46, 46,115,101,108,102, 46,110, 97,109,101, 46, 46, 34,
+ 95, 99,108,111,115,101, 32, 40,108,117, 97, 95, 83,116, 97,
+ 116,101, 42, 32,116,111,108,117, 97, 95, 83, 41, 34, 41, 10,
+ 111,117,116,112,117,116, 40, 34,123, 34, 41, 10,108,111, 99,
+ 97,108, 32,105, 61, 49, 10,119,104,105,108,101, 32,115,101,
+ 108,102, 91,105, 93, 32,100,111, 10,115,101,108,102, 91,105,
+ 93, 58,117,110,114,101,103,105,115,116,101,114, 40, 41, 10,
+ 105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,111,117,116,
+ 112,117,116, 40, 34,125, 34, 41, 10,101,110,100, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 80,
+ 97, 99,107, 97,103,101, 58,104,101, 97,100,101,114, 32, 40,
+ 41, 10,111,117,116,112,117,116, 40, 39, 47, 42, 92,110, 39,
+ 41, 32,111,117,116,112,117,116, 40, 39, 42, 42, 32, 76,117,
+ 97, 32, 98,105,110,100,105,110,103, 58, 32, 39, 46, 46,115,
+ 101,108,102, 46,110, 97,109,101, 46, 46, 39, 92,110, 39, 41,
+ 10,111,117,116,112,117,116, 40, 39, 42, 42, 32, 71,101,110,
+ 101,114, 97,116,101,100, 32, 97,117,116,111,109, 97,116,105,
+ 99, 97,108,108,121, 32, 98,121, 32, 39, 46, 46, 84, 79, 76,
+ 85, 65, 95, 86, 69, 82, 83, 73, 79, 78, 46, 46, 39, 32,111,
+ 110, 32, 39, 46, 46,100, 97,116,101, 40, 41, 46, 46, 39, 46,
+ 92,110, 39, 41, 10,111,117,116,112,117,116, 40, 39, 42, 47,
+ 92,110, 92,110, 39, 41, 10, 10,105,102, 32,110,111,116, 32,
+ 102,108, 97,103,115, 46,104, 32,116,104,101,110, 10,111,117,
+ 116,112,117,116, 40, 39, 47, 42, 32, 69,120,112,111,114,116,
+ 101,100, 32,102,117,110, 99,116,105,111,110, 32, 42, 47, 39,
+ 41, 10,111,117,116,112,117,116, 40, 39,105,110,116, 32,116,
+ 111,108,117, 97, 95, 39, 46, 46,115,101,108,102, 46,110, 97,
+ 109,101, 46, 46, 39, 95,111,112,101,110, 32, 40,108,117, 97,
+ 95, 83,116, 97,116,101, 42, 32,116,111,108,117, 97, 95, 83,
+ 41, 59, 39, 41, 10,111,117,116,112,117,116, 40, 39,118,111,
+ 105,100, 32,116,111,108,117, 97, 95, 39, 46, 46,115,101,108,
+ 102, 46,110, 97,109,101, 46, 46, 39, 95, 99,108,111,115,101,
+ 32, 40,108,117, 97, 95, 83,116, 97,116,101, 42, 32,116,111,
+ 108,117, 97, 95, 83, 41, 59, 39, 41, 10,111,117,116,112,117,
+ 116, 40, 39, 92,110, 39, 41, 10,101,110,100, 10,101,110,100,
+ 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 95, 80, 97,
+ 99,107, 97,103,101, 32, 40,116, 41, 10,116, 46, 95, 98, 97,
+ 115,101, 32, 61, 32, 99,108, 97,115,115, 80, 97, 99,107, 97,
+ 103,101, 10,115,101,116,116, 97,103, 40,116, 44,116,111,108,
+ 117, 97, 95,116, 97,103, 41, 10,114,101,116,117,114,110, 32,
+ 116, 10,101,110,100, 10, 10, 10, 10, 10,102,117,110, 99,116,
+ 105,111,110, 32, 80, 97, 99,107, 97,103,101, 32, 40,110, 97,
+ 109,101, 41, 10, 10,108,111, 99, 97,108, 32, 99,111,100,101,
+ 32, 61, 32,114,101, 97,100, 40, 34, 42, 97, 34, 41, 10, 99,
+ 111,100,101, 32, 61, 32, 34, 92,110, 34, 32, 46, 46, 32, 99,
+ 111,100,101, 10, 10,108,111, 99, 97,108, 32,110,115,117, 98,
+ 115,116, 10,114,101,112,101, 97,116, 10, 99,111,100,101, 44,
+ 110,115,117, 98,115,116, 32, 61, 32,103,115,117, 98, 40, 99,
+ 111,100,101, 44, 34, 92,110, 37,115, 42, 37, 36, 60, 40, 46,
+ 45, 41, 62, 37,115, 42, 92,110, 34, 44,102,117,110, 99,116,
+ 105,111,110, 32, 40,102,110, 41, 10,108,111, 99, 97,108, 32,
+ 102,112, 44,109,115,103, 32, 61, 32,111,112,101,110,102,105,
+ 108,101, 40,102,110, 44, 39,114, 39, 41, 10,105,102, 32,110,
+ 111,116, 32,102,112, 32,116,104,101,110, 10,101,114,114,111,
+ 114, 40, 39, 35, 39, 46, 46,109,115,103, 46, 46, 39, 58, 32,
+ 39, 46, 46,102,110, 41, 10,101,110,100, 10,108,111, 99, 97,
+ 108, 32,115, 32, 61, 32,114,101, 97,100, 40,102,112, 44, 39,
+ 42, 97, 39, 41, 10, 99,108,111,115,101,102,105,108,101, 40,
+ 102,112, 41, 10,114,101,116,117,114,110, 32, 34, 92,110, 34,
+ 32, 46, 46, 32,115, 10,101,110,100, 41, 10,117,110,116,105,
+ 108, 32,110,115,117, 98,115,116, 61, 61, 48, 10, 10, 10,108,
+ 111, 99, 97,108, 32,110,115,117, 98,115,116, 10,114,101,112,
+ 101, 97,116, 10, 99,111,100,101, 44,110,115,117, 98,115,116,
+ 32, 61, 10,103,115,117, 98, 40, 99,111,100,101, 44, 34, 92,
+ 110, 37,115, 42, 37, 36,123, 40, 46, 45, 41,125, 37,115, 42,
+ 92,110, 34, 44, 10,102,117,110, 99,116,105,111,110, 32, 40,
+ 102,110, 41, 10,108,111, 99, 97,108, 32,102,112, 44,109,115,
+ 103, 32, 61, 32,111,112,101,110,102,105,108,101, 40,102,110,
+ 44, 39,114, 39, 41, 10,105,102, 32,110,111,116, 32,102,112,
+ 32,116,104,101,110, 10,101,114,114,111,114, 40, 39, 35, 39,
+ 46, 46,109,115,103, 46, 46, 39, 58, 32, 39, 46, 46,102,110,
+ 41, 10,101,110,100, 10,108,111, 99, 97,108, 32,115, 32, 61,
+ 32,114,101, 97,100, 40,102,112, 44, 39, 42, 97, 39, 41, 10,
+ 99,108,111,115,101,102,105,108,101, 40,102,112, 41, 10, 10,
+ 108,111, 99, 97,108, 32, 84, 32, 61, 32,123, 99,111,100,101,
+ 61, 34, 92,110, 34,125, 10,115, 61, 32, 34, 92,110, 34, 32,
+ 46, 46, 32,115, 32, 46, 46, 32, 34, 92,110, 34, 10, 10,103,
+ 115,117, 98, 40,115, 44, 34, 92,110, 40, 46, 45, 41, 91, 84,
+ 116, 93, 91, 79,111, 93, 91, 76,108, 93, 91, 85,117, 93, 91,
+ 65, 97, 93, 95, 91, 69,101, 93, 91, 88,120, 93, 91, 80,112,
+ 93, 91, 79,111, 93, 91, 82,114, 93, 91, 84,116, 93, 91, 94,
+ 92,110, 93, 42, 92,110, 34, 44, 10,102,117,110, 99,116,105,
+ 111,110, 32, 40, 99, 41, 32, 37, 84, 46, 99,111,100,101, 32,
+ 61, 32, 37, 84, 46, 99,111,100,101, 32, 46, 46, 32, 99, 32,
+ 46, 46, 32, 34, 92,110, 34, 32,101,110,100, 10, 41, 10, 10,
+ 103,115,117, 98, 40,115, 44, 34, 92,110, 91, 94, 92,110, 93,
+ 42, 91, 84,116, 93, 91, 79,111, 93, 91, 76,108, 93, 91, 85,
+ 117, 93, 91, 65, 97, 93, 95, 91, 66, 98, 93, 91, 69,101, 93,
+ 91, 71,103, 93, 91, 73,105, 93, 91, 78,110, 93, 91, 94, 92,
+ 110, 93, 42, 34, 46, 46, 10, 34, 40, 46, 45, 41, 34, 32, 46,
+ 46, 10, 34, 92,110, 91, 94, 92,110, 93, 42, 91, 84,116, 93,
+ 91, 79,111, 93, 91, 76,108, 93, 91, 85,117, 93, 91, 65, 97,
+ 93, 95, 91, 69,101, 93, 91, 78,110, 93, 91, 68,100, 93, 91,
+ 94, 92,110, 93, 42, 92,110, 34, 44, 10,102,117,110, 99,116,
+ 105,111,110, 32, 40, 99, 41, 32, 37, 84, 46, 99,111,100,101,
+ 32, 61, 32, 37, 84, 46, 99,111,100,101, 32, 46, 46, 32, 99,
+ 32, 46, 46, 32, 34, 92,110, 34, 32,101,110,100, 10, 41, 10,
+ 114,101,116,117,114,110, 32, 84, 46, 99,111,100,101, 10,101,
+ 110,100, 41, 10,117,110,116,105,108, 32,110,115,117, 98,115,
+ 116, 61, 61, 48, 10, 10,108,111, 99, 97,108, 32,116, 32, 61,
+ 32, 95, 80, 97, 99,107, 97,103,101, 40, 95, 67,111,110,116,
+ 97,105,110,101,114,123,110, 97,109,101, 61,110, 97,109,101,
+ 44, 32, 99,111,100,101, 61, 99,111,100,101,125, 41, 10,112,
+ 117,115,104, 40,116, 41, 10,116, 58,112,114,101,112,114,111,
+ 99,101,115,115, 40, 41, 10,116, 58,112, 97,114,115,101, 40,
+ 116, 46, 99,111,100,101, 41, 10,112,111,112, 40, 41, 10,114,
+ 101,116,117,114,110, 32,116, 10,101,110,100, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,
+ 108, 97,115,115, 77,111,100,117,108,101, 32, 61, 32,123, 10,
+ 95, 98, 97,115,101, 32, 61, 32, 99,108, 97,115,115, 67,111,
+ 110,116, 97,105,110,101,114, 44, 10,116,121,112,101, 32, 61,
+ 32, 39,109,111,100,117,108,101, 39, 10,125, 10,115,101,116,
+ 116, 97,103, 40, 99,108, 97,115,115, 77,111,100,117,108,101,
+ 44,116,111,108,117, 97, 95,116, 97,103, 41, 10, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 77,111,
+ 100,117,108,101, 58,114,101,103,105,115,116,101,114, 32, 40,
+ 41, 10,111,117,116,112,117,116, 40, 39, 32,116,111,108,117,
+ 97, 95,109,111,100,117,108,101, 40,116,111,108,117, 97, 95,
+ 83, 44, 34, 39, 46, 46,115,101,108,102, 46,110, 97,109,101,
+ 46, 46, 39, 34, 41, 59, 39, 41, 10,108,111, 99, 97,108, 32,
+ 105, 61, 49, 10,119,104,105,108,101, 32,115,101,108,102, 91,
+ 105, 93, 32,100,111, 10,115,101,108,102, 91,105, 93, 58,114,
+ 101,103,105,115,116,101,114, 40, 41, 10,105, 32, 61, 32,105,
+ 43, 49, 10,101,110,100, 10,101,110,100, 10, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 99,108, 97,115,115, 77,111,100,
+ 117,108,101, 58,117,110,114,101,103,105,115,116,101,114, 32,
+ 40, 41, 10,111,117,116,112,117,116, 40, 39, 32,108,117, 97,
+ 95,112,117,115,104,110,105,108, 40,116,111,108,117, 97, 95,
+ 83, 41, 59, 32,108,117, 97, 95,115,101,116,103,108,111, 98,
+ 97,108, 40,116,111,108,117, 97, 95, 83, 44, 34, 39, 46, 46,
+ 115,101,108,102, 46,110, 97,109,101, 46, 46, 39, 34, 41, 59,
+ 39, 41, 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,
+ 111,110, 32, 99,108, 97,115,115, 77,111,100,117,108,101, 58,
+ 112,114,105,110,116, 32, 40,105,100,101,110,116, 44, 99,108,
+ 111,115,101, 41, 10,112,114,105,110,116, 40,105,100,101,110,
+ 116, 46, 46, 34, 77,111,100,117,108,101,123, 34, 41, 10,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32,110,
+ 97,109,101, 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,
+ 110, 97,109,101, 46, 46, 34, 39, 59, 34, 41, 10,108,111, 99,
+ 97,108, 32,105, 61, 49, 10,119,104,105,108,101, 32,115,101,
+ 108,102, 91,105, 93, 32,100,111, 10,115,101,108,102, 91,105,
+ 93, 58,112,114,105,110,116, 40,105,100,101,110,116, 46, 46,
+ 34, 32, 34, 44, 34, 44, 34, 41, 10,105, 32, 61, 32,105, 43,
+ 49, 10,101,110,100, 10,112,114,105,110,116, 40,105,100,101,
+ 110,116, 46, 46, 34,125, 34, 46, 46, 99,108,111,115,101, 41,
+ 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32, 95, 77,111,100,117,108,101, 32, 40,116, 41, 10,116, 46,
+ 95, 98, 97,115,101, 32, 61, 32, 99,108, 97,115,115, 77,111,
+ 100,117,108,101, 10,115,101,116,116, 97,103, 40,116, 44,116,
+ 111,108,117, 97, 95,116, 97,103, 41, 10, 97,112,112,101,110,
+ 100, 40,116, 41, 10,114,101,116,117,114,110, 32,116, 10,101,
+ 110,100, 10, 10, 10, 10,102,117,110, 99,116,105,111,110, 32,
+ 77,111,100,117,108,101, 32, 40,110, 44, 98, 41, 10,108,111,
+ 99, 97,108, 32,116, 32, 61, 32, 95, 77,111,100,117,108,101,
+ 40, 95, 67,111,110,116, 97,105,110,101,114,123,110, 97,109,
+ 101, 61,110,125, 41, 10,112,117,115,104, 40,116, 41, 10,116,
+ 58,112, 97,114,115,101, 40,115,116,114,115,117, 98, 40, 98,
+ 44, 50, 44,115,116,114,108,101,110, 40, 98, 41, 45, 49, 41,
+ 41, 10,112,111,112, 40, 41, 10,114,101,116,117,114,110, 32,
+ 116, 10,101,110,100, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,108, 97,115,115, 68,
+ 101,102,105,110,101, 32, 61, 32,123, 10,110, 97,109,101, 32,
+ 61, 32, 39, 39, 44, 10, 95, 98, 97,115,101, 32, 61, 32, 99,
+ 108, 97,115,115, 70,101, 97,116,117,114,101, 44, 10,125, 10,
+ 115,101,116,116, 97,103, 40, 99,108, 97,115,115, 68,101,102,
+ 105,110,101, 44,116,111,108,117, 97, 95,116, 97,103, 41, 10,
+ 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,
+ 115, 68,101,102,105,110,101, 58,114,101,103,105,115,116,101,
+ 114, 32, 40, 41, 10,108,111, 99, 97,108, 32,112, 32, 61, 32,
+ 115,101,108,102, 58,105,110,109,111,100,117,108,101, 40, 41,
+ 10,105,102, 32,112, 32,116,104,101,110, 10,111,117,116,112,
+ 117,116, 40, 39, 32,116,111,108,117, 97, 95, 99,111,110,115,
+ 116, 97,110,116, 40,116,111,108,117, 97, 95, 83, 44, 34, 39,
+ 46, 46,112, 46, 46, 39, 34, 44, 34, 39, 46, 46,115,101,108,
+ 102, 46,108,110, 97,109,101, 46, 46, 39, 34, 44, 39, 46, 46,
+ 115,101,108,102, 46,110, 97,109,101, 46, 46, 39, 41, 59, 39,
+ 41, 10,101,108,115,101, 10,111,117,116,112,117,116, 40, 39,
+ 32,116,111,108,117, 97, 95, 99,111,110,115,116, 97,110,116,
+ 40,116,111,108,117, 97, 95, 83, 44, 78, 85, 76, 76, 44, 34,
+ 39, 46, 46,115,101,108,102, 46,108,110, 97,109,101, 46, 46,
+ 39, 34, 44, 39, 46, 46,115,101,108,102, 46,110, 97,109,101,
+ 46, 46, 39, 41, 59, 39, 41, 10,101,110,100, 10,101,110,100,
+ 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,
+ 115,115, 68,101,102,105,110,101, 58,117,110,114,101,103,105,
+ 115,116,101,114, 32, 40, 41, 10,105,102, 32,110,111,116, 32,
+ 115,101,108,102, 58,105,110,109,111,100,117,108,101, 40, 41,
+ 32,116,104,101,110, 10,111,117,116,112,117,116, 40, 39, 32,
+ 108,117, 97, 95,112,117,115,104,110,105,108, 40,116,111,108,
+ 117, 97, 95, 83, 41, 59, 32,108,117, 97, 95,115,101,116,103,
+ 108,111, 98, 97,108, 40,116,111,108,117, 97, 95, 83, 44, 34,
+ 39, 46, 46,115,101,108,102, 46,108,110, 97,109,101, 46, 46,
+ 39, 34, 41, 59, 39, 41, 10,101,110,100, 10,101,110,100, 10,
+ 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,
+ 115, 68,101,102,105,110,101, 58,112,114,105,110,116, 32, 40,
+ 105,100,101,110,116, 44, 99,108,111,115,101, 41, 10,112,114,
+ 105,110,116, 40,105,100,101,110,116, 46, 46, 34, 68,101,102,
+ 105,110,101,123, 34, 41, 10,112,114,105,110,116, 40,105,100,
+ 101,110,116, 46, 46, 34, 32,110, 97,109,101, 32, 61, 32, 39,
+ 34, 46, 46,115,101,108,102, 46,110, 97,109,101, 46, 46, 34,
+ 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,
+ 116, 46, 46, 34, 32,108,110, 97,109,101, 32, 61, 32, 39, 34,
+ 46, 46,115,101,108,102, 46,108,110, 97,109,101, 46, 46, 34,
+ 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,
+ 116, 46, 46, 34,125, 34, 46, 46, 99,108,111,115,101, 41, 10,
+ 101,110,100, 10, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32, 95, 68,101,102,105,110,101, 32, 40,116, 41, 10,116, 46,
+ 95, 98, 97,115,101, 32, 61, 32, 99,108, 97,115,115, 68,101,
+ 102,105,110,101, 10,115,101,116,116, 97,103, 40,116, 44,116,
+ 111,108,117, 97, 95,116, 97,103, 41, 10, 10,105,102, 32,116,
+ 46,110, 97,109,101, 32, 61, 61, 32, 39, 39, 32,116,104,101,
+ 110, 10,101,114,114,111,114, 40, 34, 35,105,110,118, 97,108,
+ 105,100, 32,100,101,102,105,110,101, 34, 41, 10,101,110,100,
+ 10, 10, 97,112,112,101,110,100, 40,116, 41, 10,114,101,116,
+ 117,114,110, 32,116, 10,101,110,100, 10, 10, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 68,101,102,105,110,101, 32, 40,
+ 110, 41, 10,108,111, 99, 97,108, 32,116, 32, 61, 32,115,112,
+ 108,105,116, 40,110, 44, 39, 64, 39, 41, 10,114,101,116,117,
+ 114,110, 32, 95, 68,101,102,105,110,101, 32,123, 10,110, 97,
+ 109,101, 32, 61, 32,116, 91, 49, 93, 44, 10,108,110, 97,109,
+ 101, 32, 61, 32,116, 91, 50, 93, 32,111,114, 32,116, 91, 49,
+ 93, 10,125, 10,101,110,100, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,108, 97,115,115, 69,
+ 110,117,109,101,114, 97,116,101, 32, 61, 32,123, 10, 95, 98,
+ 97,115,101, 32, 61, 32, 99,108, 97,115,115, 70,101, 97,116,
+ 117,114,101, 44, 10,125, 10,115,101,116,116, 97,103, 40, 99,
+ 108, 97,115,115, 69,110,117,109,101,114, 97,116,101, 44,116,
+ 111,108,117, 97, 95,116, 97,103, 41, 10, 10, 10,102,117,110,
+ 99,116,105,111,110, 32, 99,108, 97,115,115, 69,110,117,109,
+ 101,114, 97,116,101, 58,114,101,103,105,115,116,101,114, 32,
+ 40, 41, 10,108,111, 99, 97,108, 32,112, 32, 61, 32,115,101,
+ 108,102, 58,105,110, 99,108, 97,115,115, 40, 41, 32,111,114,
+ 32,115,101,108,102, 58,105,110,109,111,100,117,108,101, 40,
+ 41, 10,108,111, 99, 97,108, 32,105, 61, 49, 10,119,104,105,
+ 108,101, 32,115,101,108,102, 91,105, 93, 32,100,111, 10,105,
+ 102, 32,112, 32,116,104,101,110, 10,105,102, 32,115,101,108,
+ 102, 58,105,110, 99,108, 97,115,115, 40, 41, 32,116,104,101,
+ 110, 10,111,117,116,112,117,116, 40, 39, 32,116,111,108,117,
+ 97, 95, 99,111,110,115,116, 97,110,116, 40,116,111,108,117,
+ 97, 95, 83, 44, 34, 39, 46, 46,112, 46, 46, 39, 34, 44, 34,
+ 39, 46, 46,115,101,108,102, 46,108,110, 97,109,101,115, 91,
+ 105, 93, 46, 46, 39, 34, 44, 39, 46, 46,112, 46, 46, 39, 58,
+ 58, 39, 46, 46,115,101,108,102, 91,105, 93, 46, 46, 39, 41,
+ 59, 39, 41, 10,101,108,115,101, 10,111,117,116,112,117,116,
+ 40, 39, 32,116,111,108,117, 97, 95, 99,111,110,115,116, 97,
+ 110,116, 40,116,111,108,117, 97, 95, 83, 44, 34, 39, 46, 46,
+ 112, 46, 46, 39, 34, 44, 34, 39, 46, 46,115,101,108,102, 46,
+ 108,110, 97,109,101,115, 91,105, 93, 46, 46, 39, 34, 44, 39,
+ 46, 46,115,101,108,102, 91,105, 93, 46, 46, 39, 41, 59, 39,
+ 41, 10,101,110,100, 10,101,108,115,101, 10,111,117,116,112,
+ 117,116, 40, 39, 32,116,111,108,117, 97, 95, 99,111,110,115,
+ 116, 97,110,116, 40,116,111,108,117, 97, 95, 83, 44, 78, 85,
+ 76, 76, 44, 34, 39, 46, 46,115,101,108,102, 46,108,110, 97,
+ 109,101,115, 91,105, 93, 46, 46, 39, 34, 44, 39, 46, 46,115,
+ 101,108,102, 91,105, 93, 46, 46, 39, 41, 59, 39, 41, 10,101,
+ 110,100, 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,
+ 101,110,100, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,
+ 108, 97,115,115, 69,110,117,109,101,114, 97,116,101, 58,117,
+ 110,114,101,103,105,115,116,101,114, 32, 40, 41, 10,105,102,
+ 32,115,101,108,102, 58,105,110, 99,108, 97,115,115, 40, 41,
+ 61, 61,110,105,108, 32, 97,110,100, 32,115,101,108,102, 58,
+ 105,110,109,111,100,117,108,101, 40, 41, 61, 61,110,105,108,
+ 32,116,104,101,110, 10,108,111, 99, 97,108, 32,105, 61, 49,
+ 10,119,104,105,108,101, 32,115,101,108,102, 91,105, 93, 32,
+ 100,111, 10,111,117,116,112,117,116, 40, 39, 32,108,117, 97,
+ 95,112,117,115,104,110,105,108, 40,116,111,108,117, 97, 95,
+ 83, 41, 59, 32,108,117, 97, 95,115,101,116,103,108,111, 98,
+ 97,108, 40,116,111,108,117, 97, 95, 83, 44, 34, 39, 46, 46,
+ 115,101,108,102, 46,108,110, 97,109,101,115, 91,105, 93, 46,
+ 46, 39, 34, 41, 59, 39, 41, 10,105, 32, 61, 32,105, 43, 49,
+ 10,101,110,100, 10,101,110,100, 10,101,110,100, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 69,
+ 110,117,109,101,114, 97,116,101, 58,112,114,105,110,116, 32,
+ 40,105,100,101,110,116, 44, 99,108,111,115,101, 41, 10,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 69,110,
+ 117,109,101,114, 97,116,101,123, 34, 41, 10,108,111, 99, 97,
+ 108, 32,105, 61, 49, 10,119,104,105,108,101, 32,115,101,108,
+ 102, 91,105, 93, 32,100,111, 10,112,114,105,110,116, 40,105,
+ 100,101,110,116, 46, 46, 34, 32, 39, 34, 46, 46,115,101,108,
+ 102, 91,105, 93, 46, 46, 34, 39, 40, 34, 46, 46,115,101,108,
+ 102, 46,108,110, 97,109,101,115, 91,105, 93, 46, 46, 34, 41,
+ 44, 34, 41, 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100,
+ 10,112,114,105,110,116, 40,105,100,101,110,116, 46, 46, 34,
+ 125, 34, 46, 46, 99,108,111,115,101, 41, 10,101,110,100, 10,
+ 10, 10,102,117,110, 99,116,105,111,110, 32, 95, 69,110,117,
+ 109,101,114, 97,116,101, 32, 40,116, 41, 10,116, 46, 95, 98,
+ 97,115,101, 32, 61, 32, 99,108, 97,115,115, 69,110,117,109,
+ 101,114, 97,116,101, 10,115,101,116,116, 97,103, 40,116, 44,
+ 116,111,108,117, 97, 95,116, 97,103, 41, 10, 97,112,112,101,
+ 110,100, 40,116, 41, 10,114,101,116,117,114,110, 32,116, 10,
+ 101,110,100, 10, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32, 69,110,117,109,101,114, 97,116,101, 32, 40, 98, 41, 10,
+ 108,111, 99, 97,108, 32,116, 32, 61, 32,115,112,108,105,116,
+ 40,115,116,114,115,117, 98, 40, 98, 44, 50, 44, 45, 50, 41,
+ 44, 39, 44, 39, 41, 10,108,111, 99, 97,108, 32,105, 32, 61,
+ 32, 49, 10,108,111, 99, 97,108, 32,101, 32, 61, 32,123,110,
+ 61, 48,125, 10,119,104,105,108,101, 32,116, 91,105, 93, 32,
+ 100,111, 10,108,111, 99, 97,108, 32,116,116, 32, 61, 32,115,
+ 112,108,105,116, 40,116, 91,105, 93, 44, 39, 61, 39, 41, 10,
+ 101, 46,110, 32, 61, 32,101, 46,110, 32, 43, 32, 49, 10,101,
+ 91,101, 46,110, 93, 32, 61, 32,116,116, 91, 49, 93, 10,105,
+ 32, 61, 32,105, 43, 49, 10,101,110,100, 10, 10,105, 32, 61,
+ 32, 49, 10,101, 46,108,110, 97,109,101,115, 32, 61, 32,123,
+ 125, 10,119,104,105,108,101, 32,101, 91,105, 93, 32,100,111,
+ 10,108,111, 99, 97,108, 32,116, 32, 61, 32,115,112,108,105,
+ 116, 40,101, 91,105, 93, 44, 39, 64, 39, 41, 10,101, 91,105,
+ 93, 32, 61, 32,116, 91, 49, 93, 10,101, 46,108,110, 97,109,
+ 101,115, 91,105, 93, 32, 61, 32,116, 91, 50, 93, 32,111,114,
+ 32,116, 91, 49, 93, 10,105, 32, 61, 32,105, 43, 49, 10,101,
+ 110,100, 10,114,101,116,117,114,110, 32, 95, 69,110,117,109,
+ 101,114, 97,116,101, 40,101, 41, 10,101,110,100, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 99,108, 97,115,115, 68,101, 99,
+ 108, 97,114, 97,116,105,111,110, 32, 61, 32,123, 10, 95, 98,
+ 97,115,101, 32, 61, 32, 99,108, 97,115,115, 70,101, 97,116,
+ 117,114,101, 44, 10,109,111,100, 32, 61, 32, 39, 39, 44, 10,
+ 116,121,112,101, 32, 61, 32, 39, 39, 44, 10,112,116,114, 32,
+ 61, 32, 39, 39, 44, 10,110, 97,109,101, 32, 61, 32, 39, 39,
+ 44, 10,100,105,109, 32, 61, 32, 39, 39, 44, 10,114,101,116,
+ 32, 61, 32, 39, 39, 44, 10,100,101,102, 32, 61, 32, 39, 39,
+ 10,125, 10,115,101,116,116, 97,103, 40, 99,108, 97,115,115,
+ 68,101, 99,108, 97,114, 97,116,105,111,110, 44,116,111,108,
+ 117, 97, 95,116, 97,103, 41, 10, 10, 10,102,117,110, 99,116,
+ 105,111,110, 32, 99,114,101, 97,116,101, 95,118, 97,114,110,
+ 97,109,101, 32, 40, 41, 10,105,102, 32,110,111,116, 32, 95,
+ 118, 97,114,110,117,109, 98,101,114, 32,116,104,101,110, 32,
+ 95,118, 97,114,110,117,109, 98,101,114, 32, 61, 32, 48, 32,
+ 101,110,100, 10, 95,118, 97,114,110,117,109, 98,101,114, 32,
+ 61, 32, 95,118, 97,114,110,117,109, 98,101,114, 32, 43, 32,
+ 49, 10,114,101,116,117,114,110, 32, 34,116,111,108,117, 97,
+ 95,118, 97,114, 95, 34, 46, 46, 95,118, 97,114,110,117,109,
+ 98,101,114, 10,101,110,100, 10, 10, 10, 10,102,117,110, 99,
+ 116,105,111,110, 32, 99,108, 97,115,115, 68,101, 99,108, 97,
+ 114, 97,116,105,111,110, 58, 99,104,101, 99,107,110, 97,109,
+ 101, 32, 40, 41, 10, 10,105,102, 32,115,116,114,115,117, 98,
+ 40,115,101,108,102, 46,110, 97,109,101, 44, 49, 44, 49, 41,
+ 32, 61, 61, 32, 39, 91, 39, 32, 97,110,100, 32,110,111,116,
+ 32,105,115,116,121,112,101, 40,115,101,108,102, 46,116,121,
+ 112,101, 41, 32,116,104,101,110, 10,115,101,108,102, 46,110,
+ 97,109,101, 32, 61, 32,115,101,108,102, 46,116,121,112,101,
+ 46, 46,115,101,108,102, 46,110, 97,109,101, 10,108,111, 99,
+ 97,108, 32,109, 32, 61, 32,115,112,108,105,116, 40,115,101,
+ 108,102, 46,109,111,100, 44, 39, 37,115, 37,115, 42, 39, 41,
+ 10,115,101,108,102, 46,116,121,112,101, 32, 61, 32,109, 91,
+ 109, 46,110, 93, 10,115,101,108,102, 46,109,111,100, 32, 61,
+ 32, 99,111,110, 99, 97,116, 40,109, 44, 49, 44,109, 46,110,
+ 45, 49, 41, 10,101,110,100, 10, 10,108,111, 99, 97,108, 32,
+ 116, 32, 61, 32,115,112,108,105,116, 40,115,101,108,102, 46,
+ 110, 97,109,101, 44, 39, 61, 39, 41, 10,105,102, 32,116, 46,
+ 110, 61, 61, 50, 32,116,104,101,110, 10,115,101,108,102, 46,
+ 110, 97,109,101, 32, 61, 32,116, 91, 49, 93, 10,115,101,108,
+ 102, 46,100,101,102, 32, 61, 32,116, 91,116, 46,110, 93, 10,
+ 101,110,100, 10, 10,108,111, 99, 97,108, 32, 98, 44,101, 44,
+ 100, 32, 61, 32,115,116,114,102,105,110,100, 40,115,101,108,
+ 102, 46,110, 97,109,101, 44, 34, 37, 91, 40, 46, 45, 41, 37,
+ 93, 34, 41, 10,105,102, 32, 98, 32,116,104,101,110, 10,115,
+ 101,108,102, 46,110, 97,109,101, 32, 61, 32,115,116,114,115,
+ 117, 98, 40,115,101,108,102, 46,110, 97,109,101, 44, 49, 44,
+ 98, 45, 49, 41, 10,115,101,108,102, 46,100,105,109, 32, 61,
+ 32,100, 10,101,110,100, 10, 10, 10,105,102, 32,115,101,108,
+ 102, 46,116,121,112,101, 32,126, 61, 32, 39, 39, 32, 97,110,
+ 100, 32,115,101,108,102, 46,116,121,112,101, 32,126, 61, 32,
+ 39,118,111,105,100, 39, 32, 97,110,100, 32,115,101,108,102,
+ 46,110, 97,109,101, 32, 61, 61, 32, 39, 39, 32,116,104,101,
+ 110, 10,115,101,108,102, 46,110, 97,109,101, 32, 61, 32, 99,
+ 114,101, 97,116,101, 95,118, 97,114,110, 97,109,101, 40, 41,
+ 10,101,108,115,101,105,102, 32,115,101,108,102, 46,107,105,
+ 110,100, 61, 61, 39,118, 97,114, 39, 32,116,104,101,110, 10,
+ 105,102, 32,115,101,108,102, 46,116,121,112,101, 61, 61, 39,
+ 39, 32, 97,110,100, 32,115,101,108,102, 46,110, 97,109,101,
+ 126, 61, 39, 39, 32,116,104,101,110, 10,115,101,108,102, 46,
+ 116,121,112,101, 32, 61, 32,115,101,108,102, 46,116,121,112,
+ 101, 46, 46,115,101,108,102, 46,110, 97,109,101, 10,115,101,
+ 108,102, 46,110, 97,109,101, 32, 61, 32, 99,114,101, 97,116,
+ 101, 95,118, 97,114,110, 97,109,101, 40, 41, 10,101,108,115,
+ 101,105,102, 32,105,115,116,121,112,101, 40,115,101,108,102,
+ 46,110, 97,109,101, 41, 32,116,104,101,110, 10,105,102, 32,
+ 115,101,108,102, 46,116,121,112,101, 61, 61, 39, 39, 32,116,
+ 104,101,110, 32,115,101,108,102, 46,116,121,112,101, 32, 61,
+ 32,115,101,108,102, 46,110, 97,109,101, 10,101,108,115,101,
+ 32,115,101,108,102, 46,116,121,112,101, 32, 61, 32,115,101,
+ 108,102, 46,116,121,112,101, 46, 46, 39, 32, 39, 46, 46,115,
+ 101,108,102, 46,110, 97,109,101, 32,101,110,100, 10,115,101,
+ 108,102, 46,110, 97,109,101, 32, 61, 32, 99,114,101, 97,116,
+ 101, 95,118, 97,114,110, 97,109,101, 40, 41, 10,101,110,100,
+ 10,101,110,100, 10, 10,101,110,100, 10, 10, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 99,108, 97,115,115, 68,101, 99,
+ 108, 97,114, 97,116,105,111,110, 58, 99,104,101, 99,107,116,
+ 121,112,101, 32, 40, 41, 10, 10, 10,105,102, 32,105,115, 98,
+ 97,115,105, 99, 40,115,101,108,102, 46,116,121,112,101, 41,
+ 32, 97,110,100, 32,115,101,108,102, 46,112,116,114,126, 61,
+ 39, 39, 32,116,104,101,110, 10,115,101,108,102, 46,114,101,
+ 116, 32, 61, 32,115,101,108,102, 46,112,116,114, 10,115,101,
+ 108,102, 46,112,116,114, 32, 61, 32,110,105,108, 10,101,110,
+ 100, 10, 10, 10,105,102, 32,115,101,108,102, 46,100,105,109,
+ 126, 61, 39, 39, 32, 97,110,100, 32,115,101,108,102, 46,114,
+ 101,116,126, 61, 39, 39, 32,116,104,101,110, 10,101,114,114,
+ 111,114, 40, 39, 35,105,110,118, 97,108,105,100, 32,112, 97,
+ 114, 97,109,101,116,101,114, 58, 32, 99, 97,110,110,111,116,
+ 32,114,101,116,117,114,110, 32, 97,110, 32, 97,114,114, 97,
+ 121, 32,111,102, 32,118, 97,108,117,101,115, 39, 41, 10,101,
+ 110,100, 10, 10, 10,105,102, 32,115,101,108,102, 46,116,121,
+ 112,101,126, 61, 39, 39, 32,116,104,101,110, 10,114,101,103,
+ 116,121,112,101, 40,115,101,108,102, 46,116,121,112,101, 41,
+ 10,101,110,100, 10, 10, 10,105,102, 32,115,101,108,102, 46,
+ 116,121,112,101, 32, 61, 61, 32, 39, 95,117,115,101,114,100,
+ 97,116, 97, 39, 32,116,104,101,110, 32,115,101,108,102, 46,
+ 116,121,112,101, 32, 61, 32, 39,118,111,105,100, 42, 39, 10,
+ 101,108,115,101,105,102, 32,115,101,108,102, 46,116,121,112,
+ 101, 32, 61, 61, 32, 39, 95, 99,115,116,114,105,110,103, 39,
+ 32,116,104,101,110, 32,115,101,108,102, 46,116,121,112,101,
+ 32, 61, 32, 39, 99,104, 97,114, 42, 39, 10,101,110,100, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10,101,110,100, 10, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 68,101,
+ 99,108, 97,114, 97,116,105,111,110, 58,112,114,105,110,116,
+ 32, 40,105,100,101,110,116, 44, 99,108,111,115,101, 41, 10,
+ 112,114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 68,
+ 101, 99,108, 97,114, 97,116,105,111,110,123, 34, 41, 10,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32,109,
+ 111,100, 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,109,
+ 111,100, 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,116,
+ 40,105,100,101,110,116, 46, 46, 34, 32,116,121,112,101, 32,
+ 61, 32, 39, 34, 46, 46,115,101,108,102, 46,116,121,112,101,
+ 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,
+ 100,101,110,116, 46, 46, 34, 32,112,116,114, 32, 61, 32, 39,
+ 34, 46, 46,115,101,108,102, 46,112,116,114, 46, 46, 34, 39,
+ 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,116,
+ 46, 46, 34, 32,110, 97,109,101, 32, 61, 32, 39, 34, 46, 46,
+ 115,101,108,102, 46,110, 97,109,101, 46, 46, 34, 39, 44, 34,
+ 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46, 46,
+ 34, 32,100,105,109, 32, 61, 32, 39, 34, 46, 46,115,101,108,
+ 102, 46,100,105,109, 46, 46, 34, 39, 44, 34, 41, 10,112,114,
+ 105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32,100,101,
+ 102, 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,100,101,
+ 102, 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,
+ 105,100,101,110,116, 46, 46, 34, 32,114,101,116, 32, 61, 32,
+ 39, 34, 46, 46,115,101,108,102, 46,114,101,116, 46, 46, 34,
+ 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,
+ 116, 46, 46, 34,125, 34, 46, 46, 99,108,111,115,101, 41, 10,
+ 101,110,100, 10, 10, 10,102,117,110, 99,116,105,111,110, 32,
+ 99,108, 97,115,115, 68,101, 99,108, 97,114, 97,116,105,111,
+ 110, 58,100,101, 99,108,116, 97,103, 32, 40, 41, 10,115,101,
+ 108,102, 46,105,116,121,112,101, 44, 32,115,101,108,102, 46,
+ 116, 97,103, 32, 61, 32,116, 97,103,118, 97,114, 40,115,101,
+ 108,102, 46,116,121,112,101, 44,115,116,114,102,105,110,100,
+ 40,115,101,108,102, 46,109,111,100, 44, 39, 99,111,110,115,
+ 116, 39, 41, 41, 10,101,110,100, 10, 10, 10, 10,102,117,110,
+ 99,116,105,111,110, 32, 99,108, 97,115,115, 68,101, 99,108,
+ 97,114, 97,116,105,111,110, 58,111,117,116, 99,104,101, 99,
+ 107,116,121,112,101, 32, 40,110, 97,114,103, 41, 10,108,111,
+ 99, 97,108, 32,116, 97,103, 44, 32,100,101,102, 10,105,102,
+ 32,115,101,108,102, 46,100,105,109, 32,126, 61, 32, 39, 39,
+ 32,116,104,101,110, 10,116, 97,103, 32, 61, 32, 39, 76, 85,
+ 65, 95, 84, 84, 65, 66, 76, 69, 39, 10,100,101,102, 32, 61,
+ 32, 48, 10,101,108,115,101, 10,116, 97,103, 32, 61, 32,115,
+ 101,108,102, 46,116, 97,103, 10,100,101,102, 32, 61, 32,115,
+ 101,108,102, 46,100,101,102,126, 61, 39, 39, 32,111,114, 32,
+ 48, 10,101,110,100, 10,114,101,116,117,114,110, 32, 39,116,
+ 111,108,117, 97, 95,105,115,116,121,112,101, 40,116,111,108,
+ 117, 97, 95, 83, 44, 39, 46, 46,110, 97,114,103, 46, 46, 39,
+ 44, 39, 46, 46,116, 97,103, 46, 46, 39, 44, 39, 46, 46,100,
+ 101,102, 46, 46, 39, 41, 39, 10,101,110,100, 10, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 68,101,
+ 99,108, 97,114, 97,116,105,111,110, 58,100,101, 99,108, 97,
+ 114,101, 32, 40,110, 97,114,103, 41, 10,108,111, 99, 97,108,
+ 32,112,116,114, 32, 61, 32, 39, 39, 10,105,102, 32,115,101,
+ 108,102, 46,112,116,114,126, 61, 39, 39, 32,116,104,101,110,
+ 32,112,116,114, 32, 61, 32, 39, 42, 39, 32,101,110,100, 10,
+ 111,117,116,112,117,116, 40, 34, 32, 34, 44,115,101,108,102,
+ 46,109,111,100, 44,115,101,108,102, 46,116,121,112,101, 44,
+ 112,116,114, 41, 10,105,102, 32,115,101,108,102, 46,100,105,
+ 109, 32,126, 61, 32, 39, 39, 32, 97,110,100, 32,116,111,110,
+ 117,109, 98,101,114, 40,115,101,108,102, 46,100,105,109, 41,
+ 61, 61,110,105,108, 32,116,104,101,110, 10,111,117,116,112,
+ 117,116, 40, 39, 42, 39, 41, 10,101,110,100, 10,111,117,116,
+ 112,117,116, 40,115,101,108,102, 46,110, 97,109,101, 41, 10,
+ 105,102, 32,115,101,108,102, 46,100,105,109, 32,126, 61, 32,
+ 39, 39, 32,116,104,101,110, 10,105,102, 32,116,111,110,117,
+ 109, 98,101,114, 40,115,101,108,102, 46,100,105,109, 41,126,
+ 61,110,105,108, 32,116,104,101,110, 10,111,117,116,112,117,
+ 116, 40, 39, 91, 39, 44,115,101,108,102, 46,100,105,109, 44,
+ 39, 93, 59, 39, 41, 10,101,108,115,101, 10,111,117,116,112,
+ 117,116, 40, 39, 32, 61, 32, 40, 39, 44,115,101,108,102, 46,
+ 109,111,100, 44,115,101,108,102, 46,116,121,112,101, 44,112,
+ 116,114, 44, 39, 42, 41, 39, 44, 10, 39,109, 97,108,108,111,
+ 99, 40, 39, 44,115,101,108,102, 46,100,105,109, 44, 39, 42,
+ 115,105,122,101,111,102, 40, 39, 44,115,101,108,102, 46,116,
+ 121,112,101, 44,112,116,114, 44, 39, 41, 41, 59, 39, 41, 10,
+ 101,110,100, 10,101,108,115,101, 10,108,111, 99, 97,108, 32,
+ 116, 32, 61, 32,105,115, 98, 97,115,105, 99, 40,115,101,108,
+ 102, 46,116,121,112,101, 41, 10,111,117,116,112,117,116, 40,
+ 39, 32, 61, 32, 39, 41, 10,105,102, 32,110,111,116, 32,116,
+ 32, 97,110,100, 32,112,116,114, 61, 61, 39, 39, 32,116,104,
+ 101,110, 32,111,117,116,112,117,116, 40, 39, 42, 39, 41, 32,
+ 101,110,100, 10,111,117,116,112,117,116, 40, 39, 40, 40, 39,
+ 44,115,101,108,102, 46,109,111,100, 44,115,101,108,102, 46,
+ 116,121,112,101, 41, 10,105,102, 32,110,111,116, 32,116, 32,
+ 116,104,101,110, 10,111,117,116,112,117,116, 40, 39, 42, 39,
+ 41, 10,101,110,100, 10,111,117,116,112,117,116, 40, 39, 41,
+ 32, 39, 41, 10,108,111, 99, 97,108, 32,100,101,102, 32, 61,
+ 32, 48, 10,105,102, 32,115,101,108,102, 46,100,101,102, 32,
+ 126, 61, 32, 39, 39, 32,116,104,101,110, 32,100,101,102, 32,
+ 61, 32,115,101,108,102, 46,100,101,102, 32,101,110,100, 10,
+ 105,102, 32,116, 32,116,104,101,110, 10,111,117,116,112,117,
+ 116, 40, 39,116,111,108,117, 97, 95,103,101,116, 39, 46, 46,
+ 116, 44, 39, 40,116,111,108,117, 97, 95, 83, 44, 39, 44,110,
+ 97,114,103, 44, 39, 44, 39, 44,100,101,102, 44, 39, 41, 41,
+ 59, 39, 41, 10,101,108,115,101, 10,111,117,116,112,117,116,
+ 40, 39,116,111,108,117, 97, 95,103,101,116,117,115,101,114,
+ 116,121,112,101, 40,116,111,108,117, 97, 95, 83, 44, 39, 44,
+ 110, 97,114,103, 44, 39, 44, 39, 44,100,101,102, 44, 39, 41,
+ 41, 59, 39, 41, 10,101,110,100, 10,101,110,100, 10,101,110,
+ 100, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108,
+ 97,115,115, 68,101, 99,108, 97,114, 97,116,105,111,110, 58,
+ 103,101,116, 97,114,114, 97,121, 32, 40,110, 97,114,103, 41,
+ 10,105,102, 32,115,101,108,102, 46,100,105,109, 32,126, 61,
+ 32, 39, 39, 32,116,104,101,110, 10,111,117,116,112,117,116,
+ 40, 39, 32,123, 39, 41, 10,108,111, 99, 97,108, 32,100,101,
+ 102, 32, 61, 32,115,101,108,102, 46,100,101,102,126, 61, 39,
+ 39, 32,111,114, 32, 48, 10,111,117,116,112,117,116, 40, 39,
+ 32,105,102, 32, 40, 33,116,111,108,117, 97, 95, 97,114,114,
+ 97,121,105,115,116,121,112,101, 40,116,111,108,117, 97, 95,
+ 83, 44, 39, 44,110, 97,114,103, 44, 39, 44, 39, 44,115,101,
+ 108,102, 46,116, 97,103, 44, 39, 44, 39, 44,115,101,108,102,
+ 46,100,105,109, 44, 39, 44, 39, 44,100,101,102, 44, 39, 41,
+ 41, 39, 41, 10,111,117,116,112,117,116, 40, 39, 32,103,111,
+ 116,111, 32,116,111,108,117, 97, 95,108,101,114,114,111,114,
+ 59, 39, 41, 10,111,117,116,112,117,116, 40, 39, 32,101,108,
+ 115,101, 92,110, 39, 41, 10,111,117,116,112,117,116, 40, 39,
+ 32,123, 39, 41, 10,111,117,116,112,117,116, 40, 39, 32,105,
+ 110,116, 32,105, 59, 39, 41, 10,111,117,116,112,117,116, 40,
+ 39, 32,102,111,114, 40,105, 61, 48, 59, 32,105, 60, 39, 46,
+ 46,115,101,108,102, 46,100,105,109, 46, 46, 39, 59,105, 43,
+ 43, 41, 39, 41, 10,108,111, 99, 97,108, 32,116, 32, 61, 32,
+ 105,115, 98, 97,115,105, 99, 40,115,101,108,102, 46,116,121,
+ 112,101, 41, 10,108,111, 99, 97,108, 32,112,116,114, 32, 61,
+ 32, 39, 39, 10,105,102, 32,115,101,108,102, 46,112,116,114,
+ 126, 61, 39, 39, 32,116,104,101,110, 32,112,116,114, 32, 61,
+ 32, 39, 42, 39, 32,101,110,100, 10,111,117,116,112,117,116,
+ 40, 39, 32, 39, 44,115,101,108,102, 46,110, 97,109,101, 46,
+ 46, 39, 91,105, 93, 32, 61, 32, 39, 41, 10,105,102, 32,110,
+ 111,116, 32,116, 32, 97,110,100, 32,112,116,114, 61, 61, 39,
+ 39, 32,116,104,101,110, 32,111,117,116,112,117,116, 40, 39,
+ 42, 39, 41, 32,101,110,100, 10,111,117,116,112,117,116, 40,
+ 39, 40, 40, 39, 44,115,101,108,102, 46,109,111,100, 44,115,
+ 101,108,102, 46,116,121,112,101, 41, 10,105,102, 32,110,111,
+ 116, 32,116, 32,116,104,101,110, 10,111,117,116,112,117,116,
+ 40, 39, 42, 39, 41, 10,101,110,100, 10,111,117,116,112,117,
+ 116, 40, 39, 41, 32, 39, 41, 10,108,111, 99, 97,108, 32,100,
+ 101,102, 32, 61, 32, 48, 10,105,102, 32,115,101,108,102, 46,
+ 100,101,102, 32,126, 61, 32, 39, 39, 32,116,104,101,110, 32,
+ 100,101,102, 32, 61, 32,115,101,108,102, 46,100,101,102, 32,
+ 101,110,100, 10,105,102, 32,116, 32,116,104,101,110, 10,111,
+ 117,116,112,117,116, 40, 39,116,111,108,117, 97, 95,103,101,
+ 116,102,105,101,108,100, 39, 46, 46,116, 46, 46, 39, 40,116,
+ 111,108,117, 97, 95, 83, 44, 39, 44,110, 97,114,103, 44, 39,
+ 44,105, 43, 49, 44, 39, 44,100,101,102, 44, 39, 41, 41, 59,
+ 39, 41, 10,101,108,115,101, 10,111,117,116,112,117,116, 40,
+ 39,116,111,108,117, 97, 95,103,101,116,102,105,101,108,100,
+ 117,115,101,114,116,121,112,101, 40,116,111,108,117, 97, 95,
+ 83, 44, 39, 44,110, 97,114,103, 44, 39, 44,105, 43, 49, 44,
+ 39, 44,100,101,102, 44, 39, 41, 41, 59, 39, 41, 10,101,110,
+ 100, 10,111,117,116,112,117,116, 40, 39, 32,125, 39, 41, 10,
+ 111,117,116,112,117,116, 40, 39, 32,125, 39, 41, 10,101,110,
+ 100, 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,111,
+ 110, 32, 99,108, 97,115,115, 68,101, 99,108, 97,114, 97,116,
+ 105,111,110, 58,115,101,116, 97,114,114, 97,121, 32, 40,110,
+ 97,114,103, 41, 10,105,102, 32,115,101,108,102, 46,100,105,
+ 109, 32,126, 61, 32, 39, 39, 32,116,104,101,110, 10,111,117,
+ 116,112,117,116, 40, 39, 32,123, 39, 41, 10,111,117,116,112,
+ 117,116, 40, 39, 32,105,110,116, 32,105, 59, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39, 32,102,111,114, 40,105, 61, 48,
+ 59, 32,105, 60, 39, 46, 46,115,101,108,102, 46,100,105,109,
+ 46, 46, 39, 59,105, 43, 43, 41, 39, 41, 10,108,111, 99, 97,
+ 108, 32,116, 44, 99,116, 32, 61, 32,105,115, 98, 97,115,105,
+ 99, 40,115,101,108,102, 46,116,121,112,101, 41, 10,105,102,
+ 32,116, 32,116,104,101,110, 10,111,117,116,112,117,116, 40,
+ 39, 32,116,111,108,117, 97, 95,112,117,115,104,102,105,101,
+ 108,100, 39, 46, 46,116, 46, 46, 39, 40,116,111,108,117, 97,
+ 95, 83, 44, 39, 44,110, 97,114,103, 44, 39, 44,105, 43, 49,
+ 44, 40, 39, 44, 99,116, 44, 39, 41, 39, 44,115,101,108,102,
+ 46,110, 97,109,101, 44, 39, 91,105, 93, 41, 59, 39, 41, 10,
+ 101,108,115,101, 10,105,102, 32,115,101,108,102, 46,112,116,
+ 114, 32, 61, 61, 32, 39, 39, 32,116,104,101,110, 10,111,117,
+ 116,112,117,116, 40, 39, 32,123, 39, 41, 10,111,117,116,112,
+ 117,116, 40, 39, 35,105,102,100,101,102, 32, 95, 95, 99,112,
+ 108,117,115,112,108,117,115, 92,110, 39, 41, 10,111,117,116,
+ 112,117,116, 40, 39, 32,118,111,105,100, 42, 32,116,111,108,
+ 117, 97, 73, 95, 99,108,111,110,101, 32, 61, 32,110,101,119,
+ 39, 44,115,101,108,102, 46,116,121,112,101, 44, 39, 40, 39,
+ 44,115,101,108,102, 46,110, 97,109,101, 44, 39, 91,105, 93,
+ 41, 59, 39, 41, 10,111,117,116,112,117,116, 40, 39, 35,101,
+ 108,115,101, 92,110, 39, 41, 10,111,117,116,112,117,116, 40,
+ 39, 32,118,111,105,100, 42, 32,116,111,108,117, 97, 73, 95,
+ 99,108,111,110,101, 32, 61, 32,116,111,108,117, 97, 95, 99,
+ 111,112,121, 40,116,111,108,117, 97, 95, 83, 44, 40,118,111,
+ 105,100, 42, 41, 38, 39, 44,115,101,108,102, 46,110, 97,109,
+ 101, 44, 39, 91,105, 93, 44,115,105,122,101,111,102, 40, 39,
+ 44,115,101,108,102, 46,116,121,112,101, 44, 39, 41, 41, 59,
+ 39, 41, 10,111,117,116,112,117,116, 40, 39, 35,101,110,100,
+ 105,102, 92,110, 39, 41, 10,111,117,116,112,117,116, 40, 39,
+ 32,116,111,108,117, 97, 95,112,117,115,104,102,105,101,108,
+ 100,117,115,101,114,116,121,112,101, 40,116,111,108,117, 97,
+ 95, 83, 44, 39, 44,110, 97,114,103, 44, 39, 44,105, 43, 49,
+ 44,116,111,108,117, 97, 95,100,111, 99,108,111,110,101, 40,
+ 116,111,108,117, 97, 95, 83, 44,116,111,108,117, 97, 73, 95,
+ 99,108,111,110,101, 44, 39, 44,115,101,108,102, 46,116, 97,
+ 103, 44, 39, 41, 44, 39, 44,115,101,108,102, 46,116, 97,103,
+ 44, 39, 41, 59, 39, 41, 10,111,117,116,112,117,116, 40, 39,
+ 32,125, 39, 41, 10, 10, 10,101,108,115,101, 10,111,117,116,
+ 112,117,116, 40, 39, 32,116,111,108,117, 97, 95,112,117,115,
+ 104,102,105,101,108,100,117,115,101,114,116,121,112,101, 40,
+ 116,111,108,117, 97, 95, 83, 44, 39, 44,110, 97,114,103, 44,
+ 39, 44,105, 43, 49, 44, 40,118,111,105,100, 42, 41, 39, 44,
+ 115,101,108,102, 46,110, 97,109,101, 44, 39, 91,105, 93, 44,
+ 39, 44,115,101,108,102, 46,116, 97,103, 44, 39, 41, 59, 39,
+ 41, 10,101,110,100, 10,101,110,100, 10,111,117,116,112,117,
+ 116, 40, 39, 32,125, 39, 41, 10,101,110,100, 10,101,110,100,
+ 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,
+ 115,115, 68,101, 99,108, 97,114, 97,116,105,111,110, 58,102,
+ 114,101,101, 97,114,114, 97,121, 32, 40, 41, 10,105,102, 32,
+ 115,101,108,102, 46,100,105,109, 32,126, 61, 32, 39, 39, 32,
+ 97,110,100, 32,116,111,110,117,109, 98,101,114, 40,115,101,
+ 108,102, 46,100,105,109, 41, 61, 61,110,105,108, 32,116,104,
+ 101,110, 10,111,117,116,112,117,116, 40, 39, 32,102,114,101,
+ 101, 40, 39, 44,115,101,108,102, 46,110, 97,109,101, 44, 39,
+ 41, 59, 39, 41, 10,101,110,100, 10,101,110,100, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 68,
+ 101, 99,108, 97,114, 97,116,105,111,110, 58,112, 97,115,115,
+ 112, 97,114, 32, 40, 41, 10,105,102, 32,115,101,108,102, 46,
+ 112,116,114, 61, 61, 39, 38, 39, 32,116,104,101,110, 10,111,
+ 117,116,112,117,116, 40, 39, 42, 39, 46, 46,115,101,108,102,
+ 46,110, 97,109,101, 41, 10,101,108,115,101,105,102, 32,115,
+ 101,108,102, 46,114,101,116, 61, 61, 39, 42, 39, 32,116,104,
+ 101,110, 10,111,117,116,112,117,116, 40, 39, 38, 39, 46, 46,
+ 115,101,108,102, 46,110, 97,109,101, 41, 10,101,108,115,101,
+ 10,111,117,116,112,117,116, 40,115,101,108,102, 46,110, 97,
+ 109,101, 41, 10,101,110,100, 10,101,110,100, 10, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 68,101,
+ 99,108, 97,114, 97,116,105,111,110, 58,114,101,116,118, 97,
+ 108,117,101, 32, 40, 41, 10,105,102, 32,115,101,108,102, 46,
+ 114,101,116, 32,126, 61, 32, 39, 39, 32,116,104,101,110, 10,
+ 108,111, 99, 97,108, 32,116, 44, 99,116, 32, 61, 32,105,115,
+ 98, 97,115,105, 99, 40,115,101,108,102, 46,116,121,112,101,
+ 41, 10,105,102, 32,116, 32,116,104,101,110, 10,111,117,116,
+ 112,117,116, 40, 39, 32,116,111,108,117, 97, 95,112,117,115,
+ 104, 39, 46, 46,116, 46, 46, 39, 40,116,111,108,117, 97, 95,
+ 83, 44, 40, 39, 44, 99,116, 44, 39, 41, 39, 46, 46,115,101,
+ 108,102, 46,110, 97,109,101, 46, 46, 39, 41, 59, 39, 41, 10,
+ 101,108,115,101, 10,111,117,116,112,117,116, 40, 39, 32,116,
+ 111,108,117, 97, 95,112,117,115,104,117,115,101,114,116,121,
+ 112,101, 40,116,111,108,117, 97, 95, 83, 44, 40,118,111,105,
+ 100, 42, 41, 39, 46, 46,115,101,108,102, 46,110, 97,109,101,
+ 46, 46, 39, 44, 39, 44,115,101,108,102, 46,116, 97,103, 44,
+ 39, 41, 59, 39, 41, 10,101,110,100, 10,114,101,116,117,114,
+ 110, 32, 49, 10,101,110,100, 10,114,101,116,117,114,110, 32,
+ 48, 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,111,
+ 110, 32, 95, 68,101, 99,108, 97,114, 97,116,105,111,110, 32,
+ 40,116, 41, 10,105,102, 32,116, 46,110, 97,109,101, 32, 97,
+ 110,100, 32,116, 46,110, 97,109,101,126, 61, 39, 39, 32,116,
+ 104,101,110, 10,108,111, 99, 97,108, 32,110, 32, 61, 32,115,
+ 112,108,105,116, 40,116, 46,110, 97,109,101, 44, 39, 64, 39,
+ 41, 10,116, 46,110, 97,109,101, 32, 61, 32,110, 91, 49, 93,
+ 10,116, 46,108,110, 97,109,101, 32, 61, 32,103,115,117, 98,
+ 40,110, 91, 50, 93, 32,111,114, 32,110, 91, 49, 93, 44, 34,
+ 37, 91, 46, 45, 37, 93, 34, 44, 34, 34, 41, 10,101,110,100,
+ 10,116, 46, 95, 98, 97,115,101, 32, 61, 32, 99,108, 97,115,
+ 115, 68,101, 99,108, 97,114, 97,116,105,111,110, 10,115,101,
+ 116,116, 97,103, 40,116, 44,116,111,108,117, 97, 95,116, 97,
+ 103, 41, 10,116, 58, 99,104,101, 99,107,110, 97,109,101, 40,
+ 41, 10,116, 58, 99,104,101, 99,107,116,121,112,101, 40, 41,
+ 10,114,101,116,117,114,110, 32,116, 10,101,110,100, 10, 10,
+ 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 68,101, 99,
+ 108, 97,114, 97,116,105,111,110, 32, 40,115, 44,107,105,110,
+ 100, 41, 10, 10,115, 32, 61, 32,103,115,117, 98, 40,115, 44,
+ 34, 37,115, 42, 61, 37,115, 42, 34, 44, 34, 61, 34, 41, 10,
+ 10,105,102, 32,107,105,110,100, 32, 61, 61, 32, 34,118, 97,
+ 114, 34, 32,116,104,101,110, 10, 10,105,102, 32,115, 32, 61,
+ 61, 32, 39, 39, 32,111,114, 32,115, 32, 61, 61, 32, 39,118,
+ 111,105,100, 39, 32,116,104,101,110, 10,114,101,116,117,114,
+ 110, 32, 95, 68,101, 99,108, 97,114, 97,116,105,111,110,123,
+ 116,121,112,101, 32, 61, 32, 39,118,111,105,100, 39, 44, 32,
+ 107,105,110,100, 32, 61, 32,107,105,110,100,125, 10,101,110,
+ 100, 10,101,110,100, 10, 10, 10,108,111, 99, 97,108, 32,116,
+ 32, 61, 32,115,112,108,105,116, 40,115, 44, 39, 37, 42, 37,
+ 115, 42, 38, 39, 41, 10,105,102, 32,116, 46,110, 32, 61, 61,
+ 32, 50, 32,116,104,101,110, 10,105,102, 32,107,105,110,100,
+ 32, 61, 61, 32, 39,102,117,110, 99, 39, 32,116,104,101,110,
+ 10,101,114,114,111,114, 40, 34, 35,105,110,118, 97,108,105,
+ 100, 32,102,117,110, 99,116,105,111,110, 32,114,101,116,117,
+ 114,110, 32,116,121,112,101, 58, 32, 34, 46, 46,115, 41, 10,
+ 101,110,100, 10,108,111, 99, 97,108, 32,109, 32, 61, 32,115,
+ 112,108,105,116, 40,116, 91, 49, 93, 44, 39, 37,115, 37,115,
+ 42, 39, 41, 10,114,101,116,117,114,110, 32, 95, 68,101, 99,
+ 108, 97,114, 97,116,105,111,110,123, 10,110, 97,109,101, 32,
+ 61, 32,116, 91, 50, 93, 44, 10,112,116,114, 32, 61, 32, 39,
+ 42, 39, 44, 10,114,101,116, 32, 61, 32, 39, 38, 39, 44, 10,
+ 116,121,112,101, 32, 61, 32,109, 91,109, 46,110, 93, 44, 10,
+ 109,111,100, 32, 61, 32, 99,111,110, 99, 97,116, 40,109, 44,
+ 49, 44,109, 46,110, 45, 49, 41, 44, 10,107,105,110,100, 32,
+ 61, 32,107,105,110,100, 10,125, 10,101,110,100, 10, 10, 10,
+ 116, 32, 61, 32,115,112,108,105,116, 40,115, 44, 39, 37, 42,
+ 37,115, 42, 37, 42, 39, 41, 10,105,102, 32,116, 46,110, 32,
+ 61, 61, 32, 50, 32,116,104,101,110, 10,105,102, 32,107,105,
+ 110,100, 32, 61, 61, 32, 39,102,117,110, 99, 39, 32,116,104,
+ 101,110, 10,101,114,114,111,114, 40, 34, 35,105,110,118, 97,
+ 108,105,100, 32,102,117,110, 99,116,105,111,110, 32,114,101,
+ 116,117,114,110, 32,116,121,112,101, 58, 32, 34, 46, 46,115,
+ 41, 10,101,110,100, 10,108,111, 99, 97,108, 32,109, 32, 61,
+ 32,115,112,108,105,116, 40,116, 91, 49, 93, 44, 39, 37,115,
+ 37,115, 42, 39, 41, 10,114,101,116,117,114,110, 32, 95, 68,
+ 101, 99,108, 97,114, 97,116,105,111,110,123, 10,110, 97,109,
+ 101, 32, 61, 32,116, 91, 50, 93, 44, 10,112,116,114, 32, 61,
+ 32, 39, 42, 39, 44, 10,114,101,116, 32, 61, 32, 39, 42, 39,
+ 44, 10,116,121,112,101, 32, 61, 32,109, 91,109, 46,110, 93,
+ 44, 10,109,111,100, 32, 61, 32, 99,111,110, 99, 97,116, 40,
+ 109, 44, 49, 44,109, 46,110, 45, 49, 41, 44, 10,107,105,110,
+ 100, 32, 61, 32,107,105,110,100, 10,125, 10,101,110,100, 10,
+ 10, 10,116, 32, 61, 32,115,112,108,105,116, 40,115, 44, 39,
+ 38, 39, 41, 10,105,102, 32,116, 46,110, 32, 61, 61, 32, 50,
+ 32,116,104,101,110, 10,108,111, 99, 97,108, 32,109, 32, 61,
+ 32,115,112,108,105,116, 40,116, 91, 49, 93, 44, 39, 37,115,
+ 37,115, 42, 39, 41, 10,114,101,116,117,114,110, 32, 95, 68,
+ 101, 99,108, 97,114, 97,116,105,111,110,123, 10,110, 97,109,
+ 101, 32, 61, 32,116, 91, 50, 93, 44, 10,112,116,114, 32, 61,
+ 32, 39, 38, 39, 44, 10,116,121,112,101, 32, 61, 32,109, 91,
+ 109, 46,110, 93, 44, 10,109,111,100, 32, 61, 32, 99,111,110,
+ 99, 97,116, 40,109, 44, 49, 44,109, 46,110, 45, 49, 41, 32,
+ 44, 10,107,105,110,100, 32, 61, 32,107,105,110,100, 10,125,
+ 10,101,110,100, 10, 10, 10,108,111, 99, 97,108, 32,115, 49,
+ 32, 61, 32,103,115,117, 98, 40,115, 44, 34, 40, 37, 98, 92,
+ 91, 92, 93, 41, 34, 44,102,117,110, 99,116,105,111,110, 32,
+ 40,110, 41, 32,114,101,116,117,114,110, 32,103,115,117, 98,
+ 40,110, 44, 39, 37, 42, 39, 44, 39, 92, 49, 39, 41, 32,101,
+ 110,100, 41, 10,116, 32, 61, 32,115,112,108,105,116, 40,115,
+ 49, 44, 39, 37, 42, 39, 41, 10,105,102, 32,116, 46,110, 32,
+ 61, 61, 32, 50, 32,116,104,101,110, 10,116, 91, 50, 93, 32,
+ 61, 32,103,115,117, 98, 40,116, 91, 50, 93, 44, 39, 92, 49,
+ 39, 44, 39, 37, 42, 39, 41, 10,108,111, 99, 97,108, 32,109,
+ 32, 61, 32,115,112,108,105,116, 40,116, 91, 49, 93, 44, 39,
+ 37,115, 37,115, 42, 39, 41, 10,114,101,116,117,114,110, 32,
+ 95, 68,101, 99,108, 97,114, 97,116,105,111,110,123, 10,110,
+ 97,109,101, 32, 61, 32,116, 91, 50, 93, 44, 10,112,116,114,
+ 32, 61, 32, 39, 42, 39, 44, 10,116,121,112,101, 32, 61, 32,
+ 109, 91,109, 46,110, 93, 44, 10,109,111,100, 32, 61, 32, 99,
+ 111,110, 99, 97,116, 40,109, 44, 49, 44,109, 46,110, 45, 49,
+ 41, 32, 44, 10,107,105,110,100, 32, 61, 32,107,105,110,100,
+ 10,125, 10,101,110,100, 10, 10,105,102, 32,107,105,110,100,
+ 32, 61, 61, 32, 39,118, 97,114, 39, 32,116,104,101,110, 10,
+ 10,116, 32, 61, 32,115,112,108,105,116, 40,115, 44, 39, 37,
+ 115, 37,115, 42, 39, 41, 10,108,111, 99, 97,108, 32,118, 10,
+ 105,102, 32,105,115,116,121,112,101, 40,116, 91,116, 46,110,
+ 93, 41, 32,116,104,101,110, 32,118, 32, 61, 32, 39, 39, 32,
+ 101,108,115,101, 32,118, 32, 61, 32,116, 91,116, 46,110, 93,
+ 59, 32,116, 46,110, 32, 61, 32,116, 46,110, 45, 49, 32,101,
+ 110,100, 10,114,101,116,117,114,110, 32, 95, 68,101, 99,108,
+ 97,114, 97,116,105,111,110,123, 10,110, 97,109,101, 32, 61,
+ 32,118, 44, 10,116,121,112,101, 32, 61, 32,116, 91,116, 46,
+ 110, 93, 44, 10,109,111,100, 32, 61, 32, 99,111,110, 99, 97,
+ 116, 40,116, 44, 49, 44,116, 46,110, 45, 49, 41, 44, 10,107,
+ 105,110,100, 32, 61, 32,107,105,110,100, 10,125, 10, 10,101,
+ 108,115,101, 10, 10, 10,116, 32, 61, 32,115,112,108,105,116,
+ 40,115, 44, 39, 37,115, 37,115, 42, 39, 41, 10,108,111, 99,
+ 97,108, 32,118, 32, 61, 32,116, 91,116, 46,110, 93, 10,108,
+ 111, 99, 97,108, 32,116,112, 44,109,100, 10,105,102, 32,116,
+ 46,110, 62, 49, 32,116,104,101,110, 10,116,112, 32, 61, 32,
+ 116, 91,116, 46,110, 45, 49, 93, 10,109,100, 32, 61, 32, 99,
+ 111,110, 99, 97,116, 40,116, 44, 49, 44,116, 46,110, 45, 50,
+ 41, 10,101,110,100, 10,114,101,116,117,114,110, 32, 95, 68,
+ 101, 99,108, 97,114, 97,116,105,111,110,123, 10,110, 97,109,
+ 101, 32, 61, 32,118, 44, 10,116,121,112,101, 32, 61, 32,116,
+ 112, 44, 10,109,111,100, 32, 61, 32,109,100, 44, 10,107,105,
+ 110,100, 32, 61, 32,107,105,110,100, 10,125, 10,101,110,100,
+ 10, 10,101,110,100, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 99,108, 97,115,115, 86, 97,114,105,
+ 97, 98,108,101, 32, 61, 32,123, 10, 95, 98, 97,115,101, 32,
+ 61, 32, 99,108, 97,115,115, 68,101, 99,108, 97,114, 97,116,
+ 105,111,110, 44, 10,125, 10, 10,115,101,116,116, 97,103, 40,
+ 99,108, 97,115,115, 86, 97,114,105, 97, 98,108,101, 44,116,
+ 111,108,117, 97, 95,116, 97,103, 41, 10, 10, 10,102,117,110,
+ 99,116,105,111,110, 32, 99,108, 97,115,115, 86, 97,114,105,
+ 97, 98,108,101, 58,112,114,105,110,116, 32, 40,105,100,101,
+ 110,116, 44, 99,108,111,115,101, 41, 10,112,114,105,110,116,
+ 40,105,100,101,110,116, 46, 46, 34, 86, 97,114,105, 97, 98,
+ 108,101,123, 34, 41, 10,112,114,105,110,116, 40,105,100,101,
+ 110,116, 46, 46, 34, 32,109,111,100, 32, 61, 32, 39, 34, 46,
+ 46,115,101,108,102, 46,109,111,100, 46, 46, 34, 39, 44, 34,
+ 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46, 46,
+ 34, 32,116,121,112,101, 32, 61, 32, 39, 34, 46, 46,115,101,
+ 108,102, 46,116,121,112,101, 46, 46, 34, 39, 44, 34, 41, 10,
+ 112,114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32,
+ 112,116,114, 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,
+ 112,116,114, 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,
+ 116, 40,105,100,101,110,116, 46, 46, 34, 32,110, 97,109,101,
+ 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,110, 97,109,
+ 101, 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,
+ 105,100,101,110,116, 46, 46, 34, 32,100,101,102, 32, 61, 32,
+ 39, 34, 46, 46,115,101,108,102, 46,100,101,102, 46, 46, 34,
+ 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,
+ 116, 46, 46, 34, 32,114,101,116, 32, 61, 32, 39, 34, 46, 46,
+ 115,101,108,102, 46,114,101,116, 46, 46, 34, 39, 44, 34, 41,
+ 10,112,114,105,110,116, 40,105,100,101,110,116, 46, 46, 34,
+ 125, 34, 46, 46, 99,108,111,115,101, 41, 10,101,110,100, 10,
+ 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,
+ 115, 86, 97,114,105, 97, 98,108,101, 58,103,101,116,118, 97,
+ 108,117,101, 32, 40, 99,108, 97,115,115, 44,115,116, 97,116,
+ 105, 99, 41, 10,105,102, 32, 99,108, 97,115,115, 32, 97,110,
+ 100, 32,115,116, 97,116,105, 99, 32,116,104,101,110, 10,114,
+ 101,116,117,114,110, 32, 99,108, 97,115,115, 46, 46, 39, 58,
+ 58, 39, 46, 46,115,101,108,102, 46,110, 97,109,101, 10,101,
+ 108,115,101,105,102, 32, 99,108, 97,115,115, 32,116,104,101,
+ 110, 10,114,101,116,117,114,110, 32, 39,115,101,108,102, 45,
+ 62, 39, 46, 46,115,101,108,102, 46,110, 97,109,101, 10,101,
+ 108,115,101, 10,114,101,116,117,114,110, 32,115,101,108,102,
+ 46,110, 97,109,101, 10,101,110,100, 10,101,110,100, 10, 10,
+ 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115,
+ 86, 97,114,105, 97, 98,108,101, 58,115,117,112, 99,111,100,
+ 101, 32, 40, 41, 10,108,111, 99, 97,108, 32, 99,108, 97,115,
+ 115, 32, 61, 32,115,101,108,102, 58,105,110, 99,108, 97,115,
+ 115, 40, 41, 10, 10, 10,105,102, 32, 99,108, 97,115,115, 32,
+ 116,104,101,110, 10,111,117,116,112,117,116, 40, 34, 47, 42,
+ 32,103,101,116, 32,102,117,110, 99,116,105,111,110, 58, 34,
+ 44,115,101,108,102, 46,110, 97,109,101, 44, 34, 32,111,102,
+ 32, 99,108, 97,115,115, 32, 34, 44, 99,108, 97,115,115, 44,
+ 34, 32, 42, 47, 34, 41, 10,101,108,115,101, 10,111,117,116,
+ 112,117,116, 40, 34, 47, 42, 32,103,101,116, 32,102,117,110,
+ 99,116,105,111,110, 58, 34, 44,115,101,108,102, 46,110, 97,
+ 109,101, 44, 34, 32, 42, 47, 34, 41, 10,101,110,100, 10,115,
+ 101,108,102, 46, 99,103,101,116,110, 97,109,101, 32, 61, 32,
+ 115,101,108,102, 58, 99,102,117,110, 99,110, 97,109,101, 40,
+ 34,116,111,108,117, 97, 73, 95,103,101,116, 34, 41, 10,111,
+ 117,116,112,117,116, 40, 34,115,116, 97,116,105, 99, 32,105,
+ 110,116, 34, 44,115,101,108,102, 46, 99,103,101,116,110, 97,
+ 109,101, 44, 34, 40,108,117, 97, 95, 83,116, 97,116,101, 42,
+ 32,116,111,108,117, 97, 95, 83, 41, 34, 41, 10,111,117,116,
+ 112,117,116, 40, 34,123, 34, 41, 10, 10, 10,108,111, 99, 97,
+ 108, 32, 95, 44, 95, 44,115,116, 97,116,105, 99, 32, 61, 32,
+ 115,116,114,102,105,110,100, 40,115,101,108,102, 46,109,111,
+ 100, 44, 39, 94, 37,115, 42, 40,115,116, 97,116,105, 99, 41,
+ 39, 41, 10,105,102, 32, 99,108, 97,115,115, 32, 97,110,100,
+ 32,115,116, 97,116,105, 99, 61, 61,110,105,108, 32,116,104,
+ 101,110, 10,111,117,116,112,117,116, 40, 39, 32, 39, 44, 99,
+ 108, 97,115,115, 44, 39, 42, 39, 44, 39,115,101,108,102, 32,
+ 61, 32, 39, 41, 10,111,117,116,112,117,116, 40, 39, 40, 39,
+ 44, 99,108, 97,115,115, 44, 39, 42, 41, 32, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39,116,111,108,117, 97, 95,103,101,
+ 116,117,115,101,114,116,121,112,101, 40,116,111,108,117, 97,
+ 95, 83, 44, 49, 44, 48, 41, 59, 39, 41, 10,101,108,115,101,
+ 105,102, 32,115,116, 97,116,105, 99, 32,116,104,101,110, 10,
+ 95, 44, 95, 44,115,101,108,102, 46,109,111,100, 32, 61, 32,
+ 115,116,114,102,105,110,100, 40,115,101,108,102, 46,109,111,
+ 100, 44, 39, 94, 37,115, 42,115,116, 97,116,105, 99, 37,115,
+ 37,115, 42, 40, 46, 42, 41, 39, 41, 10,101,110,100, 10, 10,
+ 10, 10,105,102, 32, 99,108, 97,115,115, 32, 97,110,100, 32,
+ 115,116, 97,116,105, 99, 61, 61,110,105,108, 32,116,104,101,
+ 110, 10,111,117,116,112,117,116, 40, 39, 32,105,102, 32, 40,
+ 33,115,101,108,102, 41, 32, 84, 79, 76, 85, 65, 95, 69, 82,
+ 82, 95, 83, 69, 76, 70, 59, 39, 41, 59, 10,101,110,100, 10,
+ 10, 10,108,111, 99, 97,108, 32,116, 44, 99,116, 32, 61, 32,
+ 105,115, 98, 97,115,105, 99, 40,115,101,108,102, 46,116,121,
+ 112,101, 41, 10,105,102, 32,116, 32,116,104,101,110, 10,111,
+ 117,116,112,117,116, 40, 39, 32,116,111,108,117, 97, 95,112,
+ 117,115,104, 39, 46, 46,116, 46, 46, 39, 40,116,111,108,117,
+ 97, 95, 83, 44, 40, 39, 44, 99,116, 44, 39, 41, 39, 46, 46,
+ 115,101,108,102, 58,103,101,116,118, 97,108,117,101, 40, 99,
+ 108, 97,115,115, 44,115,116, 97,116,105, 99, 41, 46, 46, 39,
+ 41, 59, 39, 41, 10,101,108,115,101, 10,105,102, 32,115,101,
+ 108,102, 46,112,116,114, 32, 61, 61, 32, 39, 38, 39, 32,111,
+ 114, 32,115,101,108,102, 46,112,116,114, 32, 61, 61, 32, 39,
+ 39, 32,116,104,101,110, 10,111,117,116,112,117,116, 40, 39,
+ 32,116,111,108,117, 97, 95,112,117,115,104,117,115,101,114,
+ 116,121,112,101, 40,116,111,108,117, 97, 95, 83, 44, 40,118,
+ 111,105,100, 42, 41, 38, 39, 46, 46,115,101,108,102, 58,103,
+ 101,116,118, 97,108,117,101, 40, 99,108, 97,115,115, 44,115,
+ 116, 97,116,105, 99, 41, 46, 46, 39, 44, 39, 44,115,101,108,
+ 102, 46,116, 97,103, 44, 39, 41, 59, 39, 41, 10,101,108,115,
+ 101, 10,111,117,116,112,117,116, 40, 39, 32,116,111,108,117,
+ 97, 95,112,117,115,104,117,115,101,114,116,121,112,101, 40,
+ 116,111,108,117, 97, 95, 83, 44, 40,118,111,105,100, 42, 41,
+ 39, 46, 46,115,101,108,102, 58,103,101,116,118, 97,108,117,
+ 101, 40, 99,108, 97,115,115, 44,115,116, 97,116,105, 99, 41,
+ 46, 46, 39, 44, 39, 44,115,101,108,102, 46,116, 97,103, 44,
+ 39, 41, 59, 39, 41, 10,101,110,100, 10,101,110,100, 10,111,
+ 117,116,112,117,116, 40, 39, 32,114,101,116,117,114,110, 32,
+ 49, 59, 39, 41, 10,111,117,116,112,117,116, 40, 39,125, 39,
+ 41, 10,111,117,116,112,117,116, 40, 39, 92,110, 39, 41, 10,
+ 10, 10,105,102, 32,110,111,116, 32,115,116,114,102,105,110,
+ 100, 40,115,101,108,102, 46,109,111,100, 44, 39, 99,111,110,
+ 115,116, 39, 41, 32,116,104,101,110, 10,105,102, 32, 99,108,
+ 97,115,115, 32,116,104,101,110, 10,111,117,116,112,117,116,
+ 40, 34, 47, 42, 32,115,101,116, 32,102,117,110, 99,116,105,
+ 111,110, 58, 34, 44,115,101,108,102, 46,110, 97,109,101, 44,
+ 34, 32,111,102, 32, 99,108, 97,115,115, 32, 34, 44, 99,108,
+ 97,115,115, 44, 34, 32, 42, 47, 34, 41, 10,101,108,115,101,
+ 10,111,117,116,112,117,116, 40, 34, 47, 42, 32,115,101,116,
+ 32,102,117,110, 99,116,105,111,110, 58, 34, 44,115,101,108,
+ 102, 46,110, 97,109,101, 44, 34, 32, 42, 47, 34, 41, 10,101,
+ 110,100, 10,115,101,108,102, 46, 99,115,101,116,110, 97,109,
+ 101, 32, 61, 32,115,101,108,102, 58, 99,102,117,110, 99,110,
+ 97,109,101, 40, 34,116,111,108,117, 97, 73, 95,115,101,116,
+ 34, 41, 10,111,117,116,112,117,116, 40, 34,115,116, 97,116,
+ 105, 99, 32,105,110,116, 34, 44,115,101,108,102, 46, 99,115,
+ 101,116,110, 97,109,101, 44, 34, 40,108,117, 97, 95, 83,116,
+ 97,116,101, 42, 32,116,111,108,117, 97, 95, 83, 41, 34, 41,
+ 10,111,117,116,112,117,116, 40, 34,123, 34, 41, 10, 10, 10,
+ 108,111, 99, 97,108, 32,110, 97,114,103, 61, 49, 10,105,102,
+ 32, 99,108, 97,115,115, 32, 97,110,100, 32,115,116, 97,116,
+ 105, 99, 61, 61,110,105,108, 32,116,104,101,110, 10,111,117,
+ 116,112,117,116, 40, 39, 32, 39, 44, 99,108, 97,115,115, 44,
+ 39, 42, 39, 44, 39,115,101,108,102, 32, 61, 32, 39, 41, 10,
+ 111,117,116,112,117,116, 40, 39, 40, 39, 44, 99,108, 97,115,
+ 115, 44, 39, 42, 41, 32, 39, 41, 10,111,117,116,112,117,116,
+ 40, 39,116,111,108,117, 97, 95,103,101,116,117,115,101,114,
+ 116,121,112,101, 40,116,111,108,117, 97, 95, 83, 44, 49, 44,
+ 48, 41, 59, 39, 41, 10, 10,111,117,116,112,117,116, 40, 39,
+ 32,105,102, 32, 40, 33,115,101,108,102, 41, 32, 84, 79, 76,
+ 85, 65, 95, 69, 82, 82, 95, 83, 69, 76, 70, 59, 39, 41, 59,
+ 10,110, 97,114,103, 32, 61, 32,110, 97,114,103, 43, 49, 10,
+ 101,108,115,101,105,102, 32,115,116, 97,116,105, 99, 32,116,
+ 104,101,110, 10, 95, 44, 95, 44,115,101,108,102, 46,109,111,
+ 100, 32, 61, 32,115,116,114,102,105,110,100, 40,115,101,108,
+ 102, 46,109,111,100, 44, 39, 94, 37,115, 42,115,116, 97,116,
+ 105, 99, 37,115, 37,115, 42, 40, 46, 42, 41, 39, 41, 10,110,
+ 97,114,103, 32, 61, 32,110, 97,114,103, 43, 49, 10,101,110,
+ 100, 10, 10, 10,111,117,116,112,117,116, 40, 39, 32,105,102,
+ 32, 40, 33, 39, 46, 46,115,101,108,102, 58,111,117,116, 99,
+ 104,101, 99,107,116,121,112,101, 40,110, 97,114,103, 41, 46,
+ 46, 39, 41, 39, 41, 10,111,117,116,112,117,116, 40, 39, 32,
+ 84, 79, 76, 85, 65, 95, 69, 82, 82, 95, 65, 83, 83, 73, 71,
+ 78, 59, 39, 41, 10, 10, 10,108,111, 99, 97,108, 32,112,116,
+ 114, 32, 61, 32, 39, 39, 10,105,102, 32,115,101,108,102, 46,
+ 112,116,114,126, 61, 39, 39, 32,116,104,101,110, 32,112,116,
+ 114, 32, 61, 32, 39, 42, 39, 32,101,110,100, 10,111,117,116,
+ 112,117,116, 40, 39, 32, 39, 41, 10,105,102, 32, 99,108, 97,
+ 115,115, 32, 97,110,100, 32,115,116, 97,116,105, 99, 32,116,
+ 104,101,110, 10,111,117,116,112,117,116, 40, 99,108, 97,115,
+ 115, 46, 46, 39, 58, 58, 39, 46, 46,115,101,108,102, 46,110,
+ 97,109,101, 41, 10,101,108,115,101,105,102, 32, 99,108, 97,
+ 115,115, 32,116,104,101,110, 10,111,117,116,112,117,116, 40,
+ 39,115,101,108,102, 45, 62, 39, 46, 46,115,101,108,102, 46,
+ 110, 97,109,101, 41, 10,101,108,115,101, 10,111,117,116,112,
+ 117,116, 40,115,101,108,102, 46,110, 97,109,101, 41, 10,101,
+ 110,100, 10,108,111, 99, 97,108, 32,116, 32, 61, 32,105,115,
+ 98, 97,115,105, 99, 40,115,101,108,102, 46,116,121,112,101,
+ 41, 10,111,117,116,112,117,116, 40, 39, 32, 61, 32, 39, 41,
+ 10,105,102, 32,110,111,116, 32,116, 32, 97,110,100, 32,112,
+ 116,114, 61, 61, 39, 39, 32,116,104,101,110, 32,111,117,116,
+ 112,117,116, 40, 39, 42, 39, 41, 32,101,110,100, 10,111,117,
+ 116,112,117,116, 40, 39, 40, 40, 39, 44,115,101,108,102, 46,
+ 109,111,100, 44,115,101,108,102, 46,116,121,112,101, 41, 10,
+ 105,102, 32,110,111,116, 32,116, 32,116,104,101,110, 10,111,
+ 117,116,112,117,116, 40, 39, 42, 39, 41, 10,101,110,100, 10,
+ 111,117,116,112,117,116, 40, 39, 41, 32, 39, 41, 10,108,111,
+ 99, 97,108, 32,100,101,102, 32, 61, 32, 48, 10,105,102, 32,
+ 115,101,108,102, 46,100,101,102, 32,126, 61, 32, 39, 39, 32,
+ 116,104,101,110, 32,100,101,102, 32, 61, 32,115,101,108,102,
+ 46,100,101,102, 32,101,110,100, 10,105,102, 32,116, 32,116,
+ 104,101,110, 10,111,117,116,112,117,116, 40, 39,116,111,108,
+ 117, 97, 95,103,101,116, 39, 46, 46,116, 44, 39, 40,116,111,
+ 108,117, 97, 95, 83, 44, 39, 44,110, 97,114,103, 44, 39, 44,
+ 39, 44,100,101,102, 44, 39, 41, 41, 59, 39, 41, 10,101,108,
+ 115,101, 10,111,117,116,112,117,116, 40, 39,116,111,108,117,
+ 97, 95,103,101,116,117,115,101,114,116,121,112,101, 40,116,
+ 111,108,117, 97, 95, 83, 44, 39, 44,110, 97,114,103, 44, 39,
+ 44, 39, 44,100,101,102, 44, 39, 41, 41, 59, 39, 41, 10,101,
+ 110,100, 10,111,117,116,112,117,116, 40, 39, 32,114,101,116,
+ 117,114,110, 32, 48, 59, 39, 41, 10,111,117,116,112,117,116,
+ 40, 39,125, 39, 41, 10,111,117,116,112,117,116, 40, 39, 92,
+ 110, 39, 41, 10,101,110,100, 10, 10,101,110,100, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32, 99,108, 97,115,115, 86, 97,
+ 114,105, 97, 98,108,101, 58,114,101,103,105,115,116,101,114,
+ 32, 40, 41, 10,108,111, 99, 97,108, 32,112, 97,114,101,110,
+ 116, 32, 61, 32,115,101,108,102, 58,105,110, 99,108, 97,115,
+ 115, 40, 41, 32,111,114, 32,115,101,108,102, 58,105,110,109,
+ 111,100,117,108,101, 40, 41, 10,105,102, 32,112, 97,114,101,
+ 110,116, 32,116,104,101,110, 10,105,102, 32,115,101,108,102,
+ 46, 99,115,101,116,110, 97,109,101, 32,116,104,101,110, 10,
+ 111,117,116,112,117,116, 40, 39, 32,116,111,108,117, 97, 95,
+ 116, 97, 98,108,101,118, 97,114, 40,116,111,108,117, 97, 95,
+ 83, 44, 34, 39, 46, 46,112, 97,114,101,110,116, 46, 46, 39,
+ 34, 44, 34, 39, 46, 46,115,101,108,102, 46,108,110, 97,109,
+ 101, 46, 46, 39, 34, 44, 39, 46, 46,115,101,108,102, 46, 99,
+ 103,101,116,110, 97,109,101, 46, 46, 39, 44, 39, 46, 46,115,
+ 101,108,102, 46, 99,115,101,116,110, 97,109,101, 46, 46, 39,
+ 41, 59, 39, 41, 10,101,108,115,101, 10,111,117,116,112,117,
+ 116, 40, 39, 32,116,111,108,117, 97, 95,116, 97, 98,108,101,
+ 118, 97,114, 40,116,111,108,117, 97, 95, 83, 44, 34, 39, 46,
+ 46,112, 97,114,101,110,116, 46, 46, 39, 34, 44, 34, 39, 46,
+ 46,115,101,108,102, 46,108,110, 97,109,101, 46, 46, 39, 34,
+ 44, 39, 46, 46,115,101,108,102, 46, 99,103,101,116,110, 97,
+ 109,101, 46, 46, 39, 44, 78, 85, 76, 76, 41, 59, 39, 41, 10,
+ 101,110,100, 10,101,108,115,101, 10,105,102, 32,115,101,108,
+ 102, 46, 99,115,101,116,110, 97,109,101, 32,116,104,101,110,
+ 10,111,117,116,112,117,116, 40, 39, 32,116,111,108,117, 97,
+ 95,103,108,111, 98, 97,108,118, 97,114, 40,116,111,108,117,
+ 97, 95, 83, 44, 34, 39, 46, 46,115,101,108,102, 46,108,110,
+ 97,109,101, 46, 46, 39, 34, 44, 39, 46, 46,115,101,108,102,
+ 46, 99,103,101,116,110, 97,109,101, 46, 46, 39, 44, 39, 46,
+ 46,115,101,108,102, 46, 99,115,101,116,110, 97,109,101, 46,
+ 46, 39, 41, 59, 39, 41, 10,101,108,115,101, 10,111,117,116,
+ 112,117,116, 40, 39, 32,116,111,108,117, 97, 95,103,108,111,
+ 98, 97,108,118, 97,114, 40,116,111,108,117, 97, 95, 83, 44,
+ 34, 39, 46, 46,115,101,108,102, 46,108,110, 97,109,101, 46,
+ 46, 39, 34, 44, 39, 46, 46,115,101,108,102, 46, 99,103,101,
+ 116,110, 97,109,101, 46, 46, 39, 44, 78, 85, 76, 76, 41, 59,
+ 39, 41, 10,101,110,100, 10,101,110,100, 10,101,110,100, 10,
+ 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115,
+ 86, 97,114,105, 97, 98,108,101, 58,117,110,114,101,103,105,
+ 115,116,101,114, 32, 40, 41, 10,105,102, 32,115,101,108,102,
+ 58,105,110, 99,108, 97,115,115, 40, 41, 61, 61,110,105,108,
+ 32, 97,110,100, 32,115,101,108,102, 58,105,110,109,111,100,
+ 117,108,101, 40, 41, 61, 61,110,105,108, 32,116,104,101,110,
+ 10,111,117,116,112,117,116, 40, 39, 32,108,117, 97, 95,103,
+ 101,116,103,108,111, 98, 97,108,115, 40,116,111,108,117, 97,
+ 95, 83, 41, 59, 39, 41, 10,111,117,116,112,117,116, 40, 39,
+ 32,108,117, 97, 95,112,117,115,104,115,116,114,105,110,103,
+ 40,116,111,108,117, 97, 95, 83, 44, 34, 39, 44,115,101,108,
+ 102, 46,108,110, 97,109,101, 44, 39, 34, 41, 59, 32,108,117,
+ 97, 95,112,117,115,104,110,105,108, 40,116,111,108,117, 97,
+ 95, 83, 41, 59, 32,108,117, 97, 95,114, 97,119,115,101,116,
+ 40,116,111,108,117, 97, 95, 83, 44, 45, 51, 41, 59, 39, 41,
+ 10,111,117,116,112,117,116, 40, 39, 32,108,117, 97, 95,112,
+ 111,112, 40,116,111,108,117, 97, 95, 83, 44, 49, 41, 59, 39,
+ 41, 10,101,110,100, 10,101,110,100, 10, 10, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 95, 86, 97,114,105, 97, 98,108,
+ 101, 32, 40,116, 41, 10,116, 46, 95, 98, 97,115,101, 32, 61,
+ 32, 99,108, 97,115,115, 86, 97,114,105, 97, 98,108,101, 10,
+ 115,101,116,116, 97,103, 40,116, 44,116,111,108,117, 97, 95,
+ 116, 97,103, 41, 10, 97,112,112,101,110,100, 40,116, 41, 10,
+ 114,101,116,117,114,110, 32,116, 10,101,110,100, 10, 10, 10,
+ 10,102,117,110, 99,116,105,111,110, 32, 86, 97,114,105, 97,
+ 98,108,101, 32, 40,115, 41, 10,114,101,116,117,114,110, 32,
+ 95, 86, 97,114,105, 97, 98,108,101, 32, 40, 68,101, 99,108,
+ 97,114, 97,116,105,111,110, 40,115, 44, 39,118, 97,114, 39,
+ 41, 41, 10,101,110,100, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,108, 97,115,115, 65,
+ 114,114, 97,121, 32, 61, 32,123, 10, 95, 98, 97,115,101, 32,
+ 61, 32, 99,108, 97,115,115, 68,101, 99,108, 97,114, 97,116,
+ 105,111,110, 44, 10,125, 10, 10,115,101,116,116, 97,103, 40,
+ 99,108, 97,115,115, 65,114,114, 97,121, 44,116,111,108,117,
+ 97, 95,116, 97,103, 41, 10, 10, 10,102,117,110, 99,116,105,
+ 111,110, 32, 99,108, 97,115,115, 65,114,114, 97,121, 58,112,
+ 114,105,110,116, 32, 40,105,100,101,110,116, 44, 99,108,111,
+ 115,101, 41, 10,112,114,105,110,116, 40,105,100,101,110,116,
+ 46, 46, 34, 65,114,114, 97,121,123, 34, 41, 10,112,114,105,
+ 110,116, 40,105,100,101,110,116, 46, 46, 34, 32,109,111,100,
+ 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,109,111,100,
+ 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,
+ 100,101,110,116, 46, 46, 34, 32,116,121,112,101, 32, 61, 32,
+ 39, 34, 46, 46,115,101,108,102, 46,116,121,112,101, 46, 46,
+ 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,
+ 110,116, 46, 46, 34, 32,112,116,114, 32, 61, 32, 39, 34, 46,
+ 46,115,101,108,102, 46,112,116,114, 46, 46, 34, 39, 44, 34,
+ 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46, 46,
+ 34, 32,110, 97,109,101, 32, 61, 32, 39, 34, 46, 46,115,101,
+ 108,102, 46,110, 97,109,101, 46, 46, 34, 39, 44, 34, 41, 10,
+ 112,114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32,
+ 100,101,102, 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,
+ 100,101,102, 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,
+ 116, 40,105,100,101,110,116, 46, 46, 34, 32,100,105,109, 32,
+ 61, 32, 39, 34, 46, 46,115,101,108,102, 46,100,105,109, 46,
+ 46, 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,
+ 101,110,116, 46, 46, 34, 32,114,101,116, 32, 61, 32, 39, 34,
+ 46, 46,115,101,108,102, 46,114,101,116, 46, 46, 34, 39, 44,
+ 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46,
+ 46, 34,125, 34, 46, 46, 99,108,111,115,101, 41, 10,101,110,
+ 100, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108,
+ 97,115,115, 65,114,114, 97,121, 58,103,101,116,118, 97,108,
+ 117,101, 32, 40, 99,108, 97,115,115, 44,115,116, 97,116,105,
+ 99, 41, 10,105,102, 32, 99,108, 97,115,115, 32, 97,110,100,
+ 32,115,116, 97,116,105, 99, 32,116,104,101,110, 10,114,101,
+ 116,117,114,110, 32, 99,108, 97,115,115, 46, 46, 39, 58, 58,
+ 39, 46, 46,115,101,108,102, 46,110, 97,109,101, 46, 46, 39,
+ 91,116,111,108,117, 97, 73, 95,105,110,100,101,120, 93, 39,
+ 10,101,108,115,101,105,102, 32, 99,108, 97,115,115, 32,116,
+ 104,101,110, 10,114,101,116,117,114,110, 32, 39,115,101,108,
+ 102, 45, 62, 39, 46, 46,115,101,108,102, 46,110, 97,109,101,
+ 46, 46, 39, 91,116,111,108,117, 97, 73, 95,105,110,100,101,
+ 120, 93, 39, 10,101,108,115,101, 10,114,101,116,117,114,110,
+ 32,115,101,108,102, 46,110, 97,109,101, 46, 46, 39, 91,116,
+ 111,108,117, 97, 73, 95,105,110,100,101,120, 93, 39, 10,101,
+ 110,100, 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,
+ 111,110, 32, 99,108, 97,115,115, 65,114,114, 97,121, 58,115,
+ 117,112, 99,111,100,101, 32, 40, 41, 10,108,111, 99, 97,108,
+ 32, 99,108, 97,115,115, 32, 61, 32,115,101,108,102, 58,105,
+ 110, 99,108, 97,115,115, 40, 41, 10, 10, 10,105,102, 32, 99,
+ 108, 97,115,115, 32,116,104,101,110, 10,111,117,116,112,117,
+ 116, 40, 34, 47, 42, 32,103,101,116, 32,102,117,110, 99,116,
+ 105,111,110, 58, 34, 44,115,101,108,102, 46,110, 97,109,101,
+ 44, 34, 32,111,102, 32, 99,108, 97,115,115, 32, 34, 44, 99,
+ 108, 97,115,115, 44, 34, 32, 42, 47, 34, 41, 10,101,108,115,
+ 101, 10,111,117,116,112,117,116, 40, 34, 47, 42, 32,103,101,
+ 116, 32,102,117,110, 99,116,105,111,110, 58, 34, 44,115,101,
+ 108,102, 46,110, 97,109,101, 44, 34, 32, 42, 47, 34, 41, 10,
+ 101,110,100, 10,115,101,108,102, 46, 99,103,101,116,110, 97,
+ 109,101, 32, 61, 32,115,101,108,102, 58, 99,102,117,110, 99,
+ 110, 97,109,101, 40, 34,116,111,108,117, 97, 73, 95,103,101,
+ 116, 34, 41, 10,111,117,116,112,117,116, 40, 34,115,116, 97,
+ 116,105, 99, 32,105,110,116, 34, 44,115,101,108,102, 46, 99,
+ 103,101,116,110, 97,109,101, 44, 34, 40,108,117, 97, 95, 83,
+ 116, 97,116,101, 42, 32,116,111,108,117, 97, 95, 83, 41, 34,
+ 41, 10,111,117,116,112,117,116, 40, 34,123, 34, 41, 10, 10,
+ 10,111,117,116,112,117,116, 40, 39, 32,105,110,116, 32,116,
+ 111,108,117, 97, 73, 95,105,110,100,101,120, 59, 39, 41, 10,
+ 10, 10,108,111, 99, 97,108, 32, 95, 44, 95, 44,115,116, 97,
+ 116,105, 99, 32, 61, 32,115,116,114,102,105,110,100, 40,115,
+ 101,108,102, 46,109,111,100, 44, 39, 94, 37,115, 42, 40,115,
+ 116, 97,116,105, 99, 41, 39, 41, 10,105,102, 32, 99,108, 97,
+ 115,115, 32, 97,110,100, 32,115,116, 97,116,105, 99, 61, 61,
+ 110,105,108, 32,116,104,101,110, 10,111,117,116,112,117,116,
+ 40, 39, 32, 39, 44, 99,108, 97,115,115, 44, 39, 42, 39, 44,
+ 39,115,101,108,102, 59, 39, 41, 10,111,117,116,112,117,116,
+ 40, 39, 32,108,117, 97, 95,112,117,115,104,115,116,114,105,
+ 110,103, 40,116,111,108,117, 97, 95, 83, 44, 34, 46,115,101,
+ 108,102, 34, 41, 59, 39, 41, 10,111,117,116,112,117,116, 40,
+ 39, 32,108,117, 97, 95,114, 97,119,103,101,116, 40,116,111,
+ 108,117, 97, 95, 83, 44, 49, 41, 59, 39, 41, 10,111,117,116,
+ 112,117,116, 40, 39, 32,115,101,108,102, 32, 61, 32, 39, 41,
+ 10,111,117,116,112,117,116, 40, 39, 40, 39, 44, 99,108, 97,
+ 115,115, 44, 39, 42, 41, 32, 39, 41, 10,111,117,116,112,117,
+ 116, 40, 39,108,117, 97, 95,116,111,117,115,101,114,100, 97,
+ 116, 97, 40,116,111,108,117, 97, 95, 83, 44, 45, 49, 41, 59,
+ 39, 41, 10,101,108,115,101,105,102, 32,115,116, 97,116,105,
+ 99, 32,116,104,101,110, 10, 95, 44, 95, 44,115,101,108,102,
+ 46,109,111,100, 32, 61, 32,115,116,114,102,105,110,100, 40,
+ 115,101,108,102, 46,109,111,100, 44, 39, 94, 37,115, 42,115,
+ 116, 97,116,105, 99, 37,115, 37,115, 42, 40, 46, 42, 41, 39,
+ 41, 10,101,110,100, 10, 10, 10,111,117,116,112,117,116, 40,
+ 39, 32,105,102, 32, 40, 33,116,111,108,117, 97, 95,105,115,
+ 116,121,112,101, 40,116,111,108,117, 97, 95, 83, 44, 50, 44,
+ 76, 85, 65, 95, 84, 78, 85, 77, 66, 69, 82, 44, 48, 41, 41,
+ 39, 41, 10,111,117,116,112,117,116, 40, 39, 32,116,111,108,
+ 117, 97, 95,101,114,114,111,114, 40,116,111,108,117, 97, 95,
+ 83, 44, 34,105,110,118, 97,108,105,100, 32,116,121,112,101,
+ 32,105,110, 32, 97,114,114, 97,121, 32,105,110,100,101,120,
+ 105,110,103, 46, 34, 41, 59, 39, 41, 10,111,117,116,112,117,
+ 116, 40, 39, 32,116,111,108,117, 97, 73, 95,105,110,100,101,
+ 120, 32, 61, 32, 40,105,110,116, 41,116,111,108,117, 97, 95,
+ 103,101,116,110,117,109, 98,101,114, 40,116,111,108,117, 97,
+ 95, 83, 44, 50, 44, 48, 41, 45, 49, 59, 39, 41, 10,111,117,
+ 116,112,117,116, 40, 39, 32,105,102, 32, 40,116,111,108,117,
+ 97, 73, 95,105,110,100,101,120, 60, 48, 32,124,124, 32,116,
+ 111,108,117, 97, 73, 95,105,110,100,101,120, 62, 61, 39, 46,
+ 46,115,101,108,102, 46,100,105,109, 46, 46, 39, 41, 39, 41,
+ 10,111,117,116,112,117,116, 40, 39, 32,116,111,108,117, 97,
+ 95,101,114,114,111,114, 40,116,111,108,117, 97, 95, 83, 44,
+ 34, 97,114,114, 97,121, 32,105,110,100,101,120,105,110,103,
+ 32,111,117,116, 32,111,102, 32,114, 97,110,103,101, 46, 34,
+ 41, 59, 39, 41, 10, 10, 10,108,111, 99, 97,108, 32,116, 44,
+ 99,116, 32, 61, 32,105,115, 98, 97,115,105, 99, 40,115,101,
+ 108,102, 46,116,121,112,101, 41, 10,105,102, 32,116, 32,116,
+ 104,101,110, 10,111,117,116,112,117,116, 40, 39, 32,116,111,
+ 108,117, 97, 95,112,117,115,104, 39, 46, 46,116, 46, 46, 39,
+ 40,116,111,108,117, 97, 95, 83, 44, 40, 39, 44, 99,116, 44,
+ 39, 41, 39, 46, 46,115,101,108,102, 58,103,101,116,118, 97,
+ 108,117,101, 40, 99,108, 97,115,115, 44,115,116, 97,116,105,
+ 99, 41, 46, 46, 39, 41, 59, 39, 41, 10,101,108,115,101, 10,
+ 105,102, 32,115,101,108,102, 46,112,116,114, 32, 61, 61, 32,
+ 39, 38, 39, 32,111,114, 32,115,101,108,102, 46,112,116,114,
+ 32, 61, 61, 32, 39, 39, 32,116,104,101,110, 10,111,117,116,
+ 112,117,116, 40, 39, 32,116,111,108,117, 97, 95,112,117,115,
+ 104,117,115,101,114,116,121,112,101, 40,116,111,108,117, 97,
+ 95, 83, 44, 40,118,111,105,100, 42, 41, 38, 39, 46, 46,115,
+ 101,108,102, 58,103,101,116,118, 97,108,117,101, 40, 99,108,
+ 97,115,115, 44,115,116, 97,116,105, 99, 41, 46, 46, 39, 44,
+ 39, 44,115,101,108,102, 46,116, 97,103, 44, 39, 41, 59, 39,
+ 41, 10,101,108,115,101, 10,111,117,116,112,117,116, 40, 39,
+ 32,116,111,108,117, 97, 95,112,117,115,104,117,115,101,114,
+ 116,121,112,101, 40,116,111,108,117, 97, 95, 83, 44, 40,118,
+ 111,105,100, 42, 41, 39, 46, 46,115,101,108,102, 58,103,101,
+ 116,118, 97,108,117,101, 40, 99,108, 97,115,115, 44,115,116,
+ 97,116,105, 99, 41, 46, 46, 39, 44, 39, 44,115,101,108,102,
+ 46,116, 97,103, 44, 39, 41, 59, 39, 41, 10,101,110,100, 10,
+ 101,110,100, 10,111,117,116,112,117,116, 40, 39, 32,114,101,
+ 116,117,114,110, 32, 49, 59, 39, 41, 10,111,117,116,112,117,
+ 116, 40, 39,125, 39, 41, 10,111,117,116,112,117,116, 40, 39,
+ 92,110, 39, 41, 10, 10, 10,105,102, 32,110,111,116, 32,115,
+ 116,114,102,105,110,100, 40,115,101,108,102, 46,109,111,100,
+ 44, 39, 99,111,110,115,116, 39, 41, 32,116,104,101,110, 10,
+ 105,102, 32, 99,108, 97,115,115, 32,116,104,101,110, 10,111,
+ 117,116,112,117,116, 40, 34, 47, 42, 32,115,101,116, 32,102,
+ 117,110, 99,116,105,111,110, 58, 34, 44,115,101,108,102, 46,
+ 110, 97,109,101, 44, 34, 32,111,102, 32, 99,108, 97,115,115,
+ 32, 34, 44, 99,108, 97,115,115, 44, 34, 32, 42, 47, 34, 41,
+ 10,101,108,115,101, 10,111,117,116,112,117,116, 40, 34, 47,
+ 42, 32,115,101,116, 32,102,117,110, 99,116,105,111,110, 58,
+ 34, 44,115,101,108,102, 46,110, 97,109,101, 44, 34, 32, 42,
+ 47, 34, 41, 10,101,110,100, 10,115,101,108,102, 46, 99,115,
+ 101,116,110, 97,109,101, 32, 61, 32,115,101,108,102, 58, 99,
+ 102,117,110, 99,110, 97,109,101, 40, 34,116,111,108,117, 97,
+ 73, 95,115,101,116, 34, 41, 10,111,117,116,112,117,116, 40,
+ 34,115,116, 97,116,105, 99, 32,105,110,116, 34, 44,115,101,
+ 108,102, 46, 99,115,101,116,110, 97,109,101, 44, 34, 40,108,
+ 117, 97, 95, 83,116, 97,116,101, 42, 32,116,111,108,117, 97,
+ 95, 83, 41, 34, 41, 10,111,117,116,112,117,116, 40, 34,123,
+ 34, 41, 10, 10, 10,111,117,116,112,117,116, 40, 39, 32,105,
+ 110,116, 32,116,111,108,117, 97, 73, 95,105,110,100,101,120,
+ 59, 39, 41, 10, 10, 10,108,111, 99, 97,108, 32, 95, 44, 95,
+ 44,115,116, 97,116,105, 99, 32, 61, 32,115,116,114,102,105,
+ 110,100, 40,115,101,108,102, 46,109,111,100, 44, 39, 94, 37,
+ 115, 42, 40,115,116, 97,116,105, 99, 41, 39, 41, 10,105,102,
+ 32, 99,108, 97,115,115, 32, 97,110,100, 32,115,116, 97,116,
+ 105, 99, 61, 61,110,105,108, 32,116,104,101,110, 10,111,117,
+ 116,112,117,116, 40, 39, 32, 39, 44, 99,108, 97,115,115, 44,
+ 39, 42, 39, 44, 39,115,101,108,102, 59, 39, 41, 10,111,117,
+ 116,112,117,116, 40, 39, 32,108,117, 97, 95,112,117,115,104,
+ 115,116,114,105,110,103, 40,116,111,108,117, 97, 95, 83, 44,
+ 34, 46,115,101,108,102, 34, 41, 59, 39, 41, 10,111,117,116,
+ 112,117,116, 40, 39, 32,108,117, 97, 95,114, 97,119,103,101,
+ 116, 40,116,111,108,117, 97, 95, 83, 44, 49, 41, 59, 39, 41,
+ 10,111,117,116,112,117,116, 40, 39, 32,115,101,108,102, 32,
+ 61, 32, 39, 41, 10,111,117,116,112,117,116, 40, 39, 40, 39,
+ 44, 99,108, 97,115,115, 44, 39, 42, 41, 32, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39,108,117, 97, 95,116,111,117,115,
+ 101,114,100, 97,116, 97, 40,116,111,108,117, 97, 95, 83, 44,
+ 45, 49, 41, 59, 39, 41, 10,101,108,115,101,105,102, 32,115,
+ 116, 97,116,105, 99, 32,116,104,101,110, 10, 95, 44, 95, 44,
+ 115,101,108,102, 46,109,111,100, 32, 61, 32,115,116,114,102,
+ 105,110,100, 40,115,101,108,102, 46,109,111,100, 44, 39, 94,
+ 37,115, 42,115,116, 97,116,105, 99, 37,115, 37,115, 42, 40,
+ 46, 42, 41, 39, 41, 10,101,110,100, 10, 10, 10,111,117,116,
+ 112,117,116, 40, 39, 32,105,102, 32, 40, 33,116,111,108,117,
+ 97, 95,105,115,116,121,112,101, 40,116,111,108,117, 97, 95,
+ 83, 44, 50, 44, 76, 85, 65, 95, 84, 78, 85, 77, 66, 69, 82,
+ 44, 48, 41, 41, 39, 41, 10,111,117,116,112,117,116, 40, 39,
+ 32,116,111,108,117, 97, 95,101,114,114,111,114, 40,116,111,
+ 108,117, 97, 95, 83, 44, 34,105,110,118, 97,108,105,100, 32,
+ 116,121,112,101, 32,105,110, 32, 97,114,114, 97,121, 32,105,
+ 110,100,101,120,105,110,103, 46, 34, 41, 59, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39, 32,116,111,108,117, 97, 73, 95,
+ 105,110,100,101,120, 32, 61, 32, 40,105,110,116, 41,116,111,
+ 108,117, 97, 95,103,101,116,110,117,109, 98,101,114, 40,116,
+ 111,108,117, 97, 95, 83, 44, 50, 44, 48, 41, 45, 49, 59, 39,
+ 41, 10,111,117,116,112,117,116, 40, 39, 32,105,102, 32, 40,
+ 116,111,108,117, 97, 73, 95,105,110,100,101,120, 60, 48, 32,
+ 124,124, 32,116,111,108,117, 97, 73, 95,105,110,100,101,120,
+ 62, 61, 39, 46, 46,115,101,108,102, 46,100,105,109, 46, 46,
+ 39, 41, 39, 41, 10,111,117,116,112,117,116, 40, 39, 32,116,
+ 111,108,117, 97, 95,101,114,114,111,114, 40,116,111,108,117,
+ 97, 95, 83, 44, 34, 97,114,114, 97,121, 32,105,110,100,101,
+ 120,105,110,103, 32,111,117,116, 32,111,102, 32,114, 97,110,
+ 103,101, 46, 34, 41, 59, 39, 41, 10, 10, 10,108,111, 99, 97,
+ 108, 32,112,116,114, 32, 61, 32, 39, 39, 10,105,102, 32,115,
+ 101,108,102, 46,112,116,114,126, 61, 39, 39, 32,116,104,101,
+ 110, 32,112,116,114, 32, 61, 32, 39, 42, 39, 32,101,110,100,
+ 10,111,117,116,112,117,116, 40, 39, 32, 39, 41, 10,105,102,
+ 32, 99,108, 97,115,115, 32, 97,110,100, 32,115,116, 97,116,
+ 105, 99, 32,116,104,101,110, 10,111,117,116,112,117,116, 40,
+ 99,108, 97,115,115, 46, 46, 39, 58, 58, 39, 46, 46,115,101,
+ 108,102, 46,110, 97,109,101, 46, 46, 39, 91,116,111,108,117,
+ 97, 73, 95,105,110,100,101,120, 93, 39, 41, 10,101,108,115,
+ 101,105,102, 32, 99,108, 97,115,115, 32,116,104,101,110, 10,
+ 111,117,116,112,117,116, 40, 39,115,101,108,102, 45, 62, 39,
+ 46, 46,115,101,108,102, 46,110, 97,109,101, 46, 46, 39, 91,
+ 116,111,108,117, 97, 73, 95,105,110,100,101,120, 93, 39, 41,
+ 10,101,108,115,101, 10,111,117,116,112,117,116, 40,115,101,
+ 108,102, 46,110, 97,109,101, 46, 46, 39, 91,116,111,108,117,
+ 97, 73, 95,105,110,100,101,120, 93, 39, 41, 10,101,110,100,
+ 10,108,111, 99, 97,108, 32,116, 32, 61, 32,105,115, 98, 97,
+ 115,105, 99, 40,115,101,108,102, 46,116,121,112,101, 41, 10,
+ 111,117,116,112,117,116, 40, 39, 32, 61, 32, 39, 41, 10,105,
+ 102, 32,110,111,116, 32,116, 32, 97,110,100, 32,112,116,114,
+ 61, 61, 39, 39, 32,116,104,101,110, 32,111,117,116,112,117,
+ 116, 40, 39, 42, 39, 41, 32,101,110,100, 10,111,117,116,112,
+ 117,116, 40, 39, 40, 40, 39, 44,115,101,108,102, 46,109,111,
+ 100, 44,115,101,108,102, 46,116,121,112,101, 41, 10,105,102,
+ 32,110,111,116, 32,116, 32,116,104,101,110, 10,111,117,116,
+ 112,117,116, 40, 39, 42, 39, 41, 10,101,110,100, 10,111,117,
+ 116,112,117,116, 40, 39, 41, 32, 39, 41, 10,108,111, 99, 97,
+ 108, 32,100,101,102, 32, 61, 32, 48, 10,105,102, 32,115,101,
+ 108,102, 46,100,101,102, 32,126, 61, 32, 39, 39, 32,116,104,
+ 101,110, 32,100,101,102, 32, 61, 32,115,101,108,102, 46,100,
+ 101,102, 32,101,110,100, 10,105,102, 32,116, 32,116,104,101,
+ 110, 10,111,117,116,112,117,116, 40, 39,116,111,108,117, 97,
+ 95,103,101,116, 39, 46, 46,116, 44, 39, 40,116,111,108,117,
+ 97, 95, 83, 44, 51, 44, 39, 44,100,101,102, 44, 39, 41, 41,
+ 59, 39, 41, 10,101,108,115,101, 10,111,117,116,112,117,116,
+ 40, 39,116,111,108,117, 97, 95,103,101,116,117,115,101,114,
+ 116,121,112,101, 40,116,111,108,117, 97, 95, 83, 44, 51, 44,
+ 39, 44,100,101,102, 44, 39, 41, 41, 59, 39, 41, 10,101,110,
+ 100, 10,111,117,116,112,117,116, 40, 39, 32,114,101,116,117,
+ 114,110, 32, 48, 59, 39, 41, 10,111,117,116,112,117,116, 40,
+ 39,125, 39, 41, 10,111,117,116,112,117,116, 40, 39, 92,110,
+ 39, 41, 10,101,110,100, 10, 10,101,110,100, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 99,108, 97,115,115, 65,114,114,
+ 97,121, 58,114,101,103,105,115,116,101,114, 32, 40, 41, 10,
+ 108,111, 99, 97,108, 32,112, 97,114,101,110,116, 32, 61, 32,
+ 115,101,108,102, 58,105,110, 99,108, 97,115,115, 40, 41, 32,
+ 111,114, 32,115,101,108,102, 58,105,110,109,111,100,117,108,
+ 101, 40, 41, 10,105,102, 32,112, 97,114,101,110,116, 32,116,
+ 104,101,110, 10,105,102, 32,115,101,108,102, 46, 99,115,101,
+ 116,110, 97,109,101, 32,116,104,101,110, 10,111,117,116,112,
+ 117,116, 40, 39, 32,116,111,108,117, 97, 95,116, 97, 98,108,
+ 101, 97,114,114, 97,121, 40,116,111,108,117, 97, 95, 83, 44,
+ 34, 39, 46, 46,112, 97,114,101,110,116, 46, 46, 39, 34, 44,
+ 34, 39, 46, 46,115,101,108,102, 46,108,110, 97,109,101, 46,
+ 46, 39, 34, 44, 39, 46, 46,115,101,108,102, 46, 99,103,101,
+ 116,110, 97,109,101, 46, 46, 39, 44, 39, 46, 46,115,101,108,
+ 102, 46, 99,115,101,116,110, 97,109,101, 46, 46, 39, 41, 59,
+ 39, 41, 10,101,108,115,101, 10,111,117,116,112,117,116, 40,
+ 39, 32,116,111,108,117, 97, 95,116, 97, 98,108,101, 97,114,
+ 114, 97,121, 40,116,111,108,117, 97, 95, 83, 44, 34, 39, 46,
+ 46,112, 97,114,101,110,116, 46, 46, 39, 34, 44, 34, 39, 46,
+ 46,115,101,108,102, 46,108,110, 97,109,101, 46, 46, 39, 34,
+ 44, 39, 46, 46,115,101,108,102, 46, 99,103,101,116,110, 97,
+ 109,101, 46, 46, 39, 44, 78, 85, 76, 76, 41, 59, 39, 41, 10,
+ 101,110,100, 10,101,108,115,101, 10,105,102, 32,115,101,108,
+ 102, 46, 99,115,101,116,110, 97,109,101, 32,116,104,101,110,
+ 10,111,117,116,112,117,116, 40, 39, 32,116,111,108,117, 97,
+ 95,103,108,111, 98, 97,108, 97,114,114, 97,121, 40,116,111,
+ 108,117, 97, 95, 83, 44, 34, 39, 46, 46,115,101,108,102, 46,
+ 108,110, 97,109,101, 46, 46, 39, 34, 44, 39, 46, 46,115,101,
+ 108,102, 46, 99,103,101,116,110, 97,109,101, 46, 46, 39, 44,
+ 39, 46, 46,115,101,108,102, 46, 99,115,101,116,110, 97,109,
+ 101, 46, 46, 39, 41, 59, 39, 41, 10,101,108,115,101, 10,111,
+ 117,116,112,117,116, 40, 39, 32,116,111,108,117, 97, 95,103,
+ 108,111, 98, 97,108, 97,114,114, 97,121, 40,116,111,108,117,
+ 97, 95, 83, 44, 34, 39, 46, 46,115,101,108,102, 46,108,110,
+ 97,109,101, 46, 46, 39, 34, 44, 39, 46, 46,115,101,108,102,
+ 46, 99,103,101,116,110, 97,109,101, 46, 46, 39, 44, 78, 85,
+ 76, 76, 41, 59, 39, 41, 10,101,110,100, 10,101,110,100, 10,
+ 101,110,100, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,
+ 108, 97,115,115, 65,114,114, 97,121, 58,117,110,114,101,103,
+ 105,115,116,101,114, 32, 40, 41, 10,105,102, 32,115,101,108,
+ 102, 58,105,110, 99,108, 97,115,115, 40, 41, 61, 61,110,105,
+ 108, 32, 97,110,100, 32,115,101,108,102, 58,105,110,109,111,
+ 100,117,108,101, 40, 41, 61, 61,110,105,108, 32,116,104,101,
+ 110, 10,111,117,116,112,117,116, 40, 39, 32,108,117, 97, 95,
+ 112,117,115,104,110,105,108, 40,116,111,108,117, 97, 95, 83,
+ 41, 59, 32,108,117, 97, 95,115,101,116,103,108,111, 98, 97,
+ 108, 40,116,111,108,117, 97, 95, 83, 44, 34, 39, 46, 46,115,
+ 101,108,102, 46,108,110, 97,109,101, 46, 46, 39, 34, 41, 59,
+ 39, 41, 10,101,110,100, 10,101,110,100, 10, 10, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32, 95, 65,114,114, 97,121, 32,
+ 40,116, 41, 10,116, 46, 95, 98, 97,115,101, 32, 61, 32, 99,
+ 108, 97,115,115, 65,114,114, 97,121, 10,115,101,116,116, 97,
+ 103, 40,116, 44,116,111,108,117, 97, 95,116, 97,103, 41, 10,
+ 97,112,112,101,110,100, 40,116, 41, 10,114,101,116,117,114,
+ 110, 32,116, 10,101,110,100, 10, 10, 10, 10,102,117,110, 99,
+ 116,105,111,110, 32, 65,114,114, 97,121, 32, 40,115, 41, 10,
+ 114,101,116,117,114,110, 32, 95, 65,114,114, 97,121, 32, 40,
+ 68,101, 99,108, 97,114, 97,116,105,111,110, 40,115, 44, 39,
+ 118, 97,114, 39, 41, 41, 10,101,110,100, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 99,108, 97,115,115, 70,117,110, 99,116,105,111,
+ 110, 32, 61, 32,123, 10,109,111,100, 32, 61, 32, 39, 39, 44,
+ 10,116,121,112,101, 32, 61, 32, 39, 39, 44, 10,112,116,114,
+ 32, 61, 32, 39, 39, 44, 10,110, 97,109,101, 32, 61, 32, 39,
+ 39, 44, 10, 97,114,103,115, 32, 61, 32,123,110, 61, 48,125,
+ 44, 10, 99,111,110,115,116, 32, 61, 32, 39, 39, 44, 10, 95,
+ 98, 97,115,101, 32, 61, 32, 99,108, 97,115,115, 70,101, 97,
+ 116,117,114,101, 44, 10,125, 10,115,101,116,116, 97,103, 40,
+ 99,108, 97,115,115, 70,117,110, 99,116,105,111,110, 44,116,
+ 111,108,117, 97, 95,116, 97,103, 41, 10, 10, 10,102,117,110,
+ 99,116,105,111,110, 32, 99,108, 97,115,115, 70,117,110, 99,
+ 116,105,111,110, 58,100,101, 99,108,116, 97,103, 32, 40, 41,
+ 10,115,101,108,102, 46,105,116,121,112,101, 44,115,101,108,
+ 102, 46,116, 97,103, 32, 61, 32,116, 97,103,118, 97,114, 40,
+ 115,101,108,102, 46,116,121,112,101, 44,115,116,114,102,105,
+ 110,100, 40,115,101,108,102, 46,109,111,100, 44, 39, 99,111,
+ 110,115,116, 39, 41, 41, 10,108,111, 99, 97,108, 32,105, 61,
+ 49, 10,119,104,105,108,101, 32,115,101,108,102, 46, 97,114,
+ 103,115, 91,105, 93, 32,100,111, 10,115,101,108,102, 46, 97,
+ 114,103,115, 91,105, 93, 58,100,101, 99,108,116, 97,103, 40,
+ 41, 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,101,
+ 110,100, 10, 10, 10, 10, 10,102,117,110, 99,116,105,111,110,
+ 32, 99,108, 97,115,115, 70,117,110, 99,116,105,111,110, 58,
+ 115,117,112, 99,111,100,101, 32, 40, 41, 10,108,111, 99, 97,
+ 108, 32,110,114,101,116, 32, 61, 32, 48, 10,108,111, 99, 97,
+ 108, 32, 99,108, 97,115,115, 32, 61, 32,115,101,108,102, 58,
+ 105,110, 99,108, 97,115,115, 40, 41, 10,108,111, 99, 97,108,
+ 32, 95, 44, 95, 44,115,116, 97,116,105, 99, 32, 61, 32,115,
+ 116,114,102,105,110,100, 40,115,101,108,102, 46,109,111,100,
+ 44, 39, 94, 37,115, 42, 40,115,116, 97,116,105, 99, 41, 39,
+ 41, 10, 10,105,102, 32, 99,108, 97,115,115, 32,116,104,101,
+ 110, 10,111,117,116,112,117,116, 40, 34, 47, 42, 32,109,101,
+ 116,104,111,100, 58, 34, 44,115,101,108,102, 46,110, 97,109,
+ 101, 44, 34, 32,111,102, 32, 99,108, 97,115,115, 32, 34, 44,
+ 99,108, 97,115,115, 44, 34, 32, 42, 47, 34, 41, 10,101,108,
+ 115,101, 10,111,117,116,112,117,116, 40, 34, 47, 42, 32,102,
+ 117,110, 99,116,105,111,110, 58, 34, 44,115,101,108,102, 46,
+ 110, 97,109,101, 44, 34, 32, 42, 47, 34, 41, 10,101,110,100,
+ 10,111,117,116,112,117,116, 40, 34,115,116, 97,116,105, 99,
+ 32,105,110,116, 34, 44,115,101,108,102, 46, 99,110, 97,109,
+ 101, 44, 34, 40,108,117, 97, 95, 83,116, 97,116,101, 42, 32,
+ 116,111,108,117, 97, 95, 83, 41, 34, 41, 10,111,117,116,112,
+ 117,116, 40, 34,123, 34, 41, 10, 10, 10,111,117,116,112,117,
+ 116, 40, 39, 32,105,102, 32, 40, 92,110, 39, 41, 10, 10,108,
+ 111, 99, 97,108, 32,110, 97,114,103, 10,105,102, 32, 99,108,
+ 97,115,115, 32,116,104,101,110, 32,110, 97,114,103, 61, 50,
+ 32,101,108,115,101, 32,110, 97,114,103, 61, 49, 32,101,110,
+ 100, 10,105,102, 32, 99,108, 97,115,115, 32, 97,110,100, 32,
+ 115,101,108,102, 46,110, 97,109,101,126, 61, 39,110,101,119,
+ 39, 32, 97,110,100, 32,115,116, 97,116,105, 99, 61, 61,110,
+ 105,108, 32,116,104,101,110, 10,105,102, 32,115,101,108,102,
+ 46, 99,111,110,115,116, 32, 61, 61, 32, 39, 99,111,110,115,
+ 116, 39, 32,116,104,101,110, 10,111,117,116,112,117,116, 40,
+ 39, 32, 33,116,111,108,117, 97, 95,105,115,116,121,112,101,
+ 40,116,111,108,117, 97, 95, 83, 44, 49, 44, 39, 44,115,101,
+ 108,102, 46,112, 97,114,101,110,116, 46, 99,116, 97,103, 44,
+ 39, 44, 48, 41, 32,124,124, 92,110, 39, 41, 10,101,108,115,
+ 101, 10,111,117,116,112,117,116, 40, 39, 32, 33,116,111,108,
+ 117, 97, 95,105,115,116,121,112,101, 40,116,111,108,117, 97,
+ 95, 83, 44, 49, 44, 39, 44,115,101,108,102, 46,112, 97,114,
+ 101,110,116, 46,116, 97,103, 44, 39, 44, 48, 41, 32,124,124,
+ 92,110, 39, 41, 10,101,110,100, 10,101,110,100, 10, 10,105,
+ 102, 32,115,101,108,102, 46, 97,114,103,115, 91, 49, 93, 46,
+ 116,121,112,101, 32,126, 61, 32, 39,118,111,105,100, 39, 32,
+ 116,104,101,110, 10,108,111, 99, 97,108, 32,105, 61, 49, 10,
+ 119,104,105,108,101, 32,115,101,108,102, 46, 97,114,103,115,
+ 91,105, 93, 32,100,111, 10,105,102, 32,105,115, 98, 97,115,
+ 105, 99, 40,115,101,108,102, 46, 97,114,103,115, 91,105, 93,
+ 46,116,121,112,101, 41, 32,126, 61, 32, 39,118, 97,108,117,
+ 101, 39, 32,116,104,101,110, 10,111,117,116,112,117,116, 40,
+ 39, 32, 33, 39, 46, 46,115,101,108,102, 46, 97,114,103,115,
+ 91,105, 93, 58,111,117,116, 99,104,101, 99,107,116,121,112,
+ 101, 40,110, 97,114,103, 41, 46, 46, 39, 32,124,124, 92,110,
+ 39, 41, 10,101,110,100, 10,110, 97,114,103, 32, 61, 32,110,
+ 97,114,103, 43, 49, 10,105, 32, 61, 32,105, 43, 49, 10,101,
+ 110,100, 10,101,110,100, 10, 10,111,117,116,112,117,116, 40,
+ 39, 32, 33,116,111,108,117, 97, 95,105,115,110,111,111, 98,
+ 106, 40,116,111,108,117, 97, 95, 83, 44, 39, 46, 46,110, 97,
+ 114,103, 46, 46, 39, 41, 92,110, 32, 41, 92,110, 32,103,111,
+ 116,111, 32,116,111,108,117, 97, 95,108,101,114,114,111,114,
+ 59, 39, 41, 10, 10,111,117,116,112,117,116, 40, 39, 32,101,
+ 108,115,101, 92,110, 32,123, 39, 41, 10, 10, 10,108,111, 99,
+ 97,108, 32,110, 97,114,103, 10,105,102, 32, 99,108, 97,115,
+ 115, 32,116,104,101,110, 32,110, 97,114,103, 61, 50, 32,101,
+ 108,115,101, 32,110, 97,114,103, 61, 49, 32,101,110,100, 10,
+ 105,102, 32, 99,108, 97,115,115, 32, 97,110,100, 32,115,101,
+ 108,102, 46,110, 97,109,101,126, 61, 39,110,101,119, 39, 32,
+ 97,110,100, 32,115,116, 97,116,105, 99, 61, 61,110,105,108,
+ 32,116,104,101,110, 10,111,117,116,112,117,116, 40, 39, 32,
+ 39, 44,115,101,108,102, 46, 99,111,110,115,116, 44, 99,108,
+ 97,115,115, 44, 39, 42, 39, 44, 39,115,101,108,102, 32, 61,
+ 32, 39, 41, 10,111,117,116,112,117,116, 40, 39, 40, 39, 44,
+ 115,101,108,102, 46, 99,111,110,115,116, 44, 99,108, 97,115,
+ 115, 44, 39, 42, 41, 32, 39, 41, 10,111,117,116,112,117,116,
+ 40, 39,116,111,108,117, 97, 95,103,101,116,117,115,101,114,
+ 116,121,112,101, 40,116,111,108,117, 97, 95, 83, 44, 49, 44,
+ 48, 41, 59, 39, 41, 10,101,108,115,101,105,102, 32,115,116,
+ 97,116,105, 99, 32,116,104,101,110, 10, 95, 44, 95, 44,115,
+ 101,108,102, 46,109,111,100, 32, 61, 32,115,116,114,102,105,
+ 110,100, 40,115,101,108,102, 46,109,111,100, 44, 39, 94, 37,
+ 115, 42,115,116, 97,116,105, 99, 37,115, 37,115, 42, 40, 46,
+ 42, 41, 39, 41, 10,101,110,100, 10, 10,105,102, 32,115,101,
+ 108,102, 46, 97,114,103,115, 91, 49, 93, 46,116,121,112,101,
+ 32,126, 61, 32, 39,118,111,105,100, 39, 32,116,104,101,110,
+ 10,108,111, 99, 97,108, 32,105, 61, 49, 10,119,104,105,108,
+ 101, 32,115,101,108,102, 46, 97,114,103,115, 91,105, 93, 32,
+ 100,111, 10,115,101,108,102, 46, 97,114,103,115, 91,105, 93,
+ 58,100,101, 99,108, 97,114,101, 40,110, 97,114,103, 41, 10,
+ 110, 97,114,103, 32, 61, 32,110, 97,114,103, 43, 49, 10,105,
+ 32, 61, 32,105, 43, 49, 10,101,110,100, 10,101,110,100, 10,
+ 10, 10,105,102, 32, 99,108, 97,115,115, 32, 97,110,100, 32,
+ 115,101,108,102, 46,110, 97,109,101,126, 61, 39,110,101,119,
+ 39, 32, 97,110,100, 32,115,116, 97,116,105, 99, 61, 61,110,
+ 105,108, 32,116,104,101,110, 10,111,117,116,112,117,116, 40,
+ 39, 32,105,102, 32, 40, 33,115,101,108,102, 41, 32,116,111,
+ 108,117, 97, 95,101,114,114,111,114, 40,116,111,108,117, 97,
+ 95, 83, 44, 34,105,110,118, 97,108,105,100, 32, 92, 39,115,
+ 101,108,102, 92, 39, 32,105,110, 32,102,117,110, 99,116,105,
+ 111,110, 32, 92, 39, 39, 46, 46,115,101,108,102, 46,110, 97,
+ 109,101, 46, 46, 39, 92, 39, 34, 41, 59, 39, 41, 59, 10,101,
+ 110,100, 10, 10, 10,105,102, 32, 99,108, 97,115,115, 32,116,
+ 104,101,110, 32,110, 97,114,103, 61, 50, 32,101,108,115,101,
+ 32,110, 97,114,103, 61, 49, 32,101,110,100, 10,105,102, 32,
+ 115,101,108,102, 46, 97,114,103,115, 91, 49, 93, 46,116,121,
+ 112,101, 32,126, 61, 32, 39,118,111,105,100, 39, 32,116,104,
+ 101,110, 10,108,111, 99, 97,108, 32,105, 61, 49, 10,119,104,
+ 105,108,101, 32,115,101,108,102, 46, 97,114,103,115, 91,105,
+ 93, 32,100,111, 10,115,101,108,102, 46, 97,114,103,115, 91,
+ 105, 93, 58,103,101,116, 97,114,114, 97,121, 40,110, 97,114,
+ 103, 41, 10,110, 97,114,103, 32, 61, 32,110, 97,114,103, 43,
+ 49, 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,101,
+ 110,100, 10, 10, 10,105,102, 32, 99,108, 97,115,115, 32, 97,
+ 110,100, 32,115,101,108,102, 46,110, 97,109,101, 61, 61, 39,
+ 100,101,108,101,116,101, 39, 32,116,104,101,110, 10,111,117,
+ 116,112,117,116, 40, 39, 32,100,101,108,101,116,101, 32,115,
+ 101,108,102, 59, 39, 41, 10,101,108,115,101,105,102, 32, 99,
+ 108, 97,115,115, 32, 97,110,100, 32,115,101,108,102, 46,110,
+ 97,109,101, 32, 61, 61, 32, 39,111,112,101,114, 97,116,111,
+ 114, 38, 91, 93, 39, 32,116,104,101,110, 10,111,117,116,112,
+ 117,116, 40, 39, 32,115,101,108,102, 45, 62,111,112,101,114,
+ 97,116,111,114, 91, 93, 40, 39, 44,115,101,108,102, 46, 97,
+ 114,103,115, 91, 49, 93, 46,110, 97,109,101, 44, 39, 41, 32,
+ 61, 32, 39, 44,115,101,108,102, 46, 97,114,103,115, 91, 50,
+ 93, 46,110, 97,109,101, 44, 39, 59, 39, 41, 10,101,108,115,
+ 101, 10,111,117,116,112,117,116, 40, 39, 32,123, 39, 41, 10,
+ 105,102, 32,115,101,108,102, 46,116,121,112,101, 32,126, 61,
+ 32, 39, 39, 32, 97,110,100, 32,115,101,108,102, 46,116,121,
+ 112,101, 32,126, 61, 32, 39,118,111,105,100, 39, 32,116,104,
+ 101,110, 10,111,117,116,112,117,116, 40, 39, 32, 39, 44,115,
+ 101,108,102, 46,109,111,100, 44,115,101,108,102, 46,116,121,
+ 112,101, 44,115,101,108,102, 46,112,116,114, 44, 39,116,111,
+ 108,117, 97, 73, 95,114,101,116, 32, 61, 32, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39, 40, 39, 44,115,101,108,102, 46,
+ 109,111,100, 44,115,101,108,102, 46,116,121,112,101, 44,115,
+ 101,108,102, 46,112,116,114, 44, 39, 41, 32, 39, 41, 10,101,
+ 108,115,101, 10,111,117,116,112,117,116, 40, 39, 32, 39, 41,
+ 10,101,110,100, 10,105,102, 32, 99,108, 97,115,115, 32, 97,
+ 110,100, 32,115,101,108,102, 46,110, 97,109,101, 61, 61, 39,
+ 110,101,119, 39, 32,116,104,101,110, 10,111,117,116,112,117,
+ 116, 40, 39,110,101,119, 39, 44, 99,108, 97,115,115, 44, 39,
+ 40, 39, 41, 10,101,108,115,101,105,102, 32, 99,108, 97,115,
+ 115, 32, 97,110,100, 32,115,116, 97,116,105, 99, 32,116,104,
+ 101,110, 10,111,117,116,112,117,116, 40, 99,108, 97,115,115,
+ 46, 46, 39, 58, 58, 39, 46, 46,115,101,108,102, 46,110, 97,
+ 109,101, 44, 39, 40, 39, 41, 10,101,108,115,101,105,102, 32,
+ 99,108, 97,115,115, 32,116,104,101,110, 10,111,117,116,112,
+ 117,116, 40, 39,115,101,108,102, 45, 62, 39, 46, 46,115,101,
+ 108,102, 46,110, 97,109,101, 44, 39, 40, 39, 41, 10,101,108,
+ 115,101, 10,111,117,116,112,117,116, 40,115,101,108,102, 46,
+ 110, 97,109,101, 44, 39, 40, 39, 41, 10,101,110,100, 10, 10,
+ 10,108,111, 99, 97,108, 32,105, 61, 49, 10,119,104,105,108,
+ 101, 32,115,101,108,102, 46, 97,114,103,115, 91,105, 93, 32,
+ 100,111, 10,115,101,108,102, 46, 97,114,103,115, 91,105, 93,
+ 58,112, 97,115,115,112, 97,114, 40, 41, 10,105, 32, 61, 32,
+ 105, 43, 49, 10,105,102, 32,115,101,108,102, 46, 97,114,103,
+ 115, 91,105, 93, 32,116,104,101,110, 10,111,117,116,112,117,
+ 116, 40, 39, 44, 39, 41, 10,101,110,100, 10,101,110,100, 10,
+ 10,111,117,116,112,117,116, 40, 39, 41, 59, 39, 41, 10, 10,
+ 10,105,102, 32,115,101,108,102, 46,116,121,112,101, 32,126,
+ 61, 32, 39, 39, 32, 97,110,100, 32,115,101,108,102, 46,116,
+ 121,112,101, 32,126, 61, 32, 39,118,111,105,100, 39, 32,116,
+ 104,101,110, 10,110,114,101,116, 32, 61, 32,110,114,101,116,
+ 32, 43, 32, 49, 10,108,111, 99, 97,108, 32,116, 44, 99,116,
+ 32, 61, 32,105,115, 98, 97,115,105, 99, 40,115,101,108,102,
+ 46,116,121,112,101, 41, 10,105,102, 32,116, 32,116,104,101,
+ 110, 10,111,117,116,112,117,116, 40, 39, 32,116,111,108,117,
+ 97, 95,112,117,115,104, 39, 46, 46,116, 46, 46, 39, 40,116,
+ 111,108,117, 97, 95, 83, 44, 40, 39, 44, 99,116, 44, 39, 41,
+ 116,111,108,117, 97, 73, 95,114,101,116, 41, 59, 39, 41, 10,
+ 101,108,115,101, 10,105,102, 32,115,101,108,102, 46,112,116,
+ 114, 32, 61, 61, 32, 39, 39, 32,116,104,101,110, 10,111,117,
+ 116,112,117,116, 40, 39, 32,123, 39, 41, 10,111,117,116,112,
+ 117,116, 40, 39, 35,105,102,100,101,102, 32, 95, 95, 99,112,
+ 108,117,115,112,108,117,115, 92,110, 39, 41, 10,111,117,116,
+ 112,117,116, 40, 39, 32,118,111,105,100, 42, 32,116,111,108,
+ 117, 97, 73, 95, 99,108,111,110,101, 32, 61, 32,110,101,119,
+ 39, 44,115,101,108,102, 46,116,121,112,101, 44, 39, 40,116,
+ 111,108,117, 97, 73, 95,114,101,116, 41, 59, 39, 41, 10,111,
+ 117,116,112,117,116, 40, 39, 35,101,108,115,101, 92,110, 39,
+ 41, 10,111,117,116,112,117,116, 40, 39, 32,118,111,105,100,
+ 42, 32,116,111,108,117, 97, 73, 95, 99,108,111,110,101, 32,
+ 61, 32,116,111,108,117, 97, 95, 99,111,112,121, 40,116,111,
+ 108,117, 97, 95, 83, 44, 40,118,111,105,100, 42, 41, 38,116,
+ 111,108,117, 97, 73, 95,114,101,116, 44,115,105,122,101,111,
+ 102, 40, 39, 44,115,101,108,102, 46,116,121,112,101, 44, 39,
+ 41, 41, 59, 39, 41, 10,111,117,116,112,117,116, 40, 39, 35,
+ 101,110,100,105,102, 92,110, 39, 41, 10,111,117,116,112,117,
+ 116, 40, 39, 32,116,111,108,117, 97, 95,112,117,115,104,117,
+ 115,101,114,116,121,112,101, 40,116,111,108,117, 97, 95, 83,
+ 44,116,111,108,117, 97, 95,100,111, 99,108,111,110,101, 40,
+ 116,111,108,117, 97, 95, 83, 44,116,111,108,117, 97, 73, 95,
+ 99,108,111,110,101, 44, 39, 44,115,101,108,102, 46,116, 97,
+ 103, 44, 39, 41, 44, 39, 44,115,101,108,102, 46,116, 97,103,
+ 44, 39, 41, 59, 39, 41, 10,111,117,116,112,117,116, 40, 39,
+ 32,125, 39, 41, 10, 10,101,108,115,101,105,102, 32,115,101,
+ 108,102, 46,112,116,114, 32, 61, 61, 32, 39, 38, 39, 32,116,
+ 104,101,110, 10,111,117,116,112,117,116, 40, 39, 32,116,111,
+ 108,117, 97, 95,112,117,115,104,117,115,101,114,116,121,112,
+ 101, 40,116,111,108,117, 97, 95, 83, 44, 40,118,111,105,100,
+ 42, 41, 38,116,111,108,117, 97, 73, 95,114,101,116, 44, 39,
+ 44,115,101,108,102, 46,116, 97,103, 44, 39, 41, 59, 39, 41,
+ 10,101,108,115,101, 10,111,117,116,112,117,116, 40, 39, 32,
+ 116,111,108,117, 97, 95,112,117,115,104,117,115,101,114,116,
+ 121,112,101, 40,116,111,108,117, 97, 95, 83, 44, 40,118,111,
+ 105,100, 42, 41,116,111,108,117, 97, 73, 95,114,101,116, 44,
+ 39, 44,115,101,108,102, 46,116, 97,103, 44, 39, 41, 59, 39,
+ 41, 10,101,110,100, 10,101,110,100, 10,101,110,100, 10,108,
+ 111, 99, 97,108, 32,105, 61, 49, 10,119,104,105,108,101, 32,
+ 115,101,108,102, 46, 97,114,103,115, 91,105, 93, 32,100,111,
+ 10,110,114,101,116, 32, 61, 32,110,114,101,116, 32, 43, 32,
+ 115,101,108,102, 46, 97,114,103,115, 91,105, 93, 58,114,101,
+ 116,118, 97,108,117,101, 40, 41, 10,105, 32, 61, 32,105, 43,
+ 49, 10,101,110,100, 10,111,117,116,112,117,116, 40, 39, 32,
+ 125, 39, 41, 10, 10, 10,105,102, 32, 99,108, 97,115,115, 32,
+ 116,104,101,110, 32,110, 97,114,103, 61, 50, 32,101,108,115,
+ 101, 32,110, 97,114,103, 61, 49, 32,101,110,100, 10,105,102,
+ 32,115,101,108,102, 46, 97,114,103,115, 91, 49, 93, 46,116,
+ 121,112,101, 32,126, 61, 32, 39,118,111,105,100, 39, 32,116,
+ 104,101,110, 10,108,111, 99, 97,108, 32,105, 61, 49, 10,119,
+ 104,105,108,101, 32,115,101,108,102, 46, 97,114,103,115, 91,
+ 105, 93, 32,100,111, 10,115,101,108,102, 46, 97,114,103,115,
+ 91,105, 93, 58,115,101,116, 97,114,114, 97,121, 40,110, 97,
+ 114,103, 41, 10,110, 97,114,103, 32, 61, 32,110, 97,114,103,
+ 43, 49, 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,
+ 101,110,100, 10, 10, 10,105,102, 32,115,101,108,102, 46, 97,
+ 114,103,115, 91, 49, 93, 46,116,121,112,101, 32,126, 61, 32,
+ 39,118,111,105,100, 39, 32,116,104,101,110, 10,108,111, 99,
+ 97,108, 32,105, 61, 49, 10,119,104,105,108,101, 32,115,101,
+ 108,102, 46, 97,114,103,115, 91,105, 93, 32,100,111, 10,115,
+ 101,108,102, 46, 97,114,103,115, 91,105, 93, 58,102,114,101,
+ 101, 97,114,114, 97,121, 40, 41, 10,105, 32, 61, 32,105, 43,
+ 49, 10,101,110,100, 10,101,110,100, 10,101,110,100, 10, 10,
+ 111,117,116,112,117,116, 40, 39, 32,125, 39, 41, 10,111,117,
+ 116,112,117,116, 40, 39, 32,114,101,116,117,114,110, 32, 39,
+ 46, 46,110,114,101,116, 46, 46, 39, 59, 39, 41, 10, 10, 10,
+ 111,117,116,112,117,116, 40, 39,116,111,108,117, 97, 95,108,
+ 101,114,114,111,114, 58, 92,110, 39, 41, 10,108,111, 99, 97,
+ 108, 32,111,118,101,114,108,111, 97,100, 32, 61, 32,115,116,
+ 114,115,117, 98, 40,115,101,108,102, 46, 99,110, 97,109,101,
+ 44, 45, 50, 44, 45, 49, 41, 32, 45, 32, 49, 10,105,102, 32,
+ 111,118,101,114,108,111, 97,100, 32, 62, 61, 32, 48, 32,116,
+ 104,101,110, 10,111,117,116,112,117,116, 40, 39, 32,114,101,
+ 116,117,114,110, 32, 39, 46, 46,115,116,114,115,117, 98, 40,
+ 115,101,108,102, 46, 99,110, 97,109,101, 44, 49, 44, 45, 51,
+ 41, 46, 46,102,111,114,109, 97,116, 40, 34, 37, 48, 50,100,
+ 34, 44,111,118,101,114,108,111, 97,100, 41, 46, 46, 39, 40,
+ 116,111,108,117, 97, 95, 83, 41, 59, 39, 41, 10,101,108,115,
+ 101, 10,111,117,116,112,117,116, 40, 39, 32,116,111,108,117,
+ 97, 95,101,114,114,111,114, 40,116,111,108,117, 97, 95, 83,
+ 44, 34, 35,102,101,114,114,111,114, 32,105,110, 32,102,117,
+ 110, 99,116,105,111,110, 32, 92, 39, 39, 46, 46,115,101,108,
+ 102, 46,108,110, 97,109,101, 46, 46, 39, 92, 39, 46, 34, 41,
+ 59, 39, 41, 10,111,117,116,112,117,116, 40, 39, 32,114,101,
+ 116,117,114,110, 32, 48, 59, 39, 41, 10,101,110,100, 10, 10,
+ 111,117,116,112,117,116, 40, 39,125, 39, 41, 10,111,117,116,
+ 112,117,116, 40, 39, 92,110, 39, 41, 10,101,110,100, 10, 10,
+ 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,115,
+ 70,117,110, 99,116,105,111,110, 58,114,101,103,105,115,116,
+ 101,114, 32, 40, 41, 10,108,111, 99, 97,108, 32,112, 97,114,
+ 101,110,116, 32, 61, 32,115,101,108,102, 58,105,110, 99,108,
+ 97,115,115, 40, 41, 32,111,114, 32,115,101,108,102, 58,105,
+ 110,109,111,100,117,108,101, 40, 41, 10,105,102, 32,112, 97,
+ 114,101,110,116, 32,116,104,101,110, 10,111,117,116,112,117,
+ 116, 40, 39, 32,116,111,108,117, 97, 95,102,117,110, 99,116,
+ 105,111,110, 40,116,111,108,117, 97, 95, 83, 44, 34, 39, 46,
+ 46,112, 97,114,101,110,116, 46, 46, 39, 34, 44, 34, 39, 46,
+ 46,115,101,108,102, 46,108,110, 97,109,101, 46, 46, 39, 34,
+ 44, 39, 46, 46,115,101,108,102, 46, 99,110, 97,109,101, 46,
+ 46, 39, 41, 59, 39, 41, 10,101,108,115,101, 10,111,117,116,
+ 112,117,116, 40, 39, 32,116,111,108,117, 97, 95,102,117,110,
+ 99,116,105,111,110, 40,116,111,108,117, 97, 95, 83, 44, 78,
+ 85, 76, 76, 44, 34, 39, 46, 46,115,101,108,102, 46,108,110,
+ 97,109,101, 46, 46, 39, 34, 44, 39, 46, 46,115,101,108,102,
+ 46, 99,110, 97,109,101, 46, 46, 39, 41, 59, 39, 41, 10,101,
+ 110,100, 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,
+ 111,110, 32, 99,108, 97,115,115, 70,117,110, 99,116,105,111,
+ 110, 58,117,110,114,101,103,105,115,116,101,114, 32, 40, 41,
+ 10,105,102, 32,115,101,108,102, 58,105,110, 99,108, 97,115,
+ 115, 40, 41, 61, 61,110,105,108, 32, 97,110,100, 32,115,101,
+ 108,102, 58,105,110,109,111,100,117,108,101, 40, 41, 61, 61,
+ 110,105,108, 32,116,104,101,110, 10,111,117,116,112,117,116,
+ 40, 39, 32,108,117, 97, 95,112,117,115,104,110,105,108, 40,
+ 116,111,108,117, 97, 95, 83, 41, 59, 32,108,117, 97, 95,115,
+ 101,116,103,108,111, 98, 97,108, 40,116,111,108,117, 97, 95,
+ 83, 44, 34, 39, 46, 46,115,101,108,102, 46,108,110, 97,109,
+ 101, 46, 46, 39, 34, 41, 59, 39, 41, 10,101,110,100, 10,101,
+ 110,100, 10, 10, 10, 10,102,117,110, 99,116,105,111,110, 32,
+ 99,108, 97,115,115, 70,117,110, 99,116,105,111,110, 58,112,
+ 114,105,110,116, 32, 40,105,100,101,110,116, 44, 99,108,111,
+ 115,101, 41, 10,112,114,105,110,116, 40,105,100,101,110,116,
+ 46, 46, 34, 70,117,110, 99,116,105,111,110,123, 34, 41, 10,
+ 112,114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32,
+ 109,111,100, 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,
+ 109,111,100, 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,
+ 116, 40,105,100,101,110,116, 46, 46, 34, 32,116,121,112,101,
+ 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,116,121,112,
+ 101, 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,
+ 105,100,101,110,116, 46, 46, 34, 32,112,116,114, 32, 61, 32,
+ 39, 34, 46, 46,115,101,108,102, 46,112,116,114, 46, 46, 34,
+ 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,
+ 116, 46, 46, 34, 32,110, 97,109,101, 32, 61, 32, 39, 34, 46,
+ 46,115,101,108,102, 46,110, 97,109,101, 46, 46, 34, 39, 44,
+ 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46,
+ 46, 34, 32, 99,111,110,115,116, 32, 61, 32, 39, 34, 46, 46,
+ 115,101,108,102, 46, 99,111,110,115,116, 46, 46, 34, 39, 44,
+ 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46,
+ 46, 34, 32, 99,110, 97,109,101, 32, 61, 32, 39, 34, 46, 46,
+ 115,101,108,102, 46, 99,110, 97,109,101, 46, 46, 34, 39, 44,
+ 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46,
+ 46, 34, 32,108,110, 97,109,101, 32, 61, 32, 39, 34, 46, 46,
+ 115,101,108,102, 46,108,110, 97,109,101, 46, 46, 34, 39, 44,
+ 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46,
+ 46, 34, 32, 97,114,103,115, 32, 61, 32,123, 34, 41, 10,108,
+ 111, 99, 97,108, 32,105, 61, 49, 10,119,104,105,108,101, 32,
+ 115,101,108,102, 46, 97,114,103,115, 91,105, 93, 32,100,111,
+ 10,115,101,108,102, 46, 97,114,103,115, 91,105, 93, 58,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32, 34,
+ 44, 34, 44, 34, 41, 10,105, 32, 61, 32,105, 43, 49, 10,101,
+ 110,100, 10,112,114,105,110,116, 40,105,100,101,110,116, 46,
+ 46, 34, 32,125, 34, 41, 10,112,114,105,110,116, 40,105,100,
+ 101,110,116, 46, 46, 34,125, 34, 46, 46, 99,108,111,115,101,
+ 41, 10,101,110,100, 10, 10, 10,102,117,110, 99,116,105,111,
+ 110, 32, 99,108, 97,115,115, 70,117,110, 99,116,105,111,110,
+ 58,111,118,101,114,108,111, 97,100, 32, 40, 41, 10,114,101,
+ 116,117,114,110, 32,115,101,108,102, 46,112, 97,114,101,110,
+ 116, 58,111,118,101,114,108,111, 97,100, 40,115,101,108,102,
+ 46,108,110, 97,109,101, 41, 10,101,110,100, 10, 10, 10, 10,
+ 10,102,117,110, 99,116,105,111,110, 32, 95, 70,117,110, 99,
+ 116,105,111,110, 32, 40,116, 41, 10,116, 46, 95, 98, 97,115,
+ 101, 32, 61, 32, 99,108, 97,115,115, 70,117,110, 99,116,105,
+ 111,110, 10,115,101,116,116, 97,103, 40,116, 44,116,111,108,
+ 117, 97, 95,116, 97,103, 41, 10, 10,105,102, 32,116, 46, 99,
+ 111,110,115,116, 32,126, 61, 32, 39, 99,111,110,115,116, 39,
+ 32, 97,110,100, 32,116, 46, 99,111,110,115,116, 32,126, 61,
+ 32, 39, 39, 32,116,104,101,110, 10,101,114,114,111,114, 40,
+ 34, 35,105,110,118, 97,108,105,100, 32, 39, 99,111,110,115,
+ 116, 39, 32,115,112,101, 99,105,102,105, 99, 97,116,105,111,
+ 110, 34, 41, 10,101,110,100, 10, 10, 97,112,112,101,110,100,
+ 40,116, 41, 10,105,102, 32,116, 58,105,110, 99,108, 97,115,
+ 115, 40, 41, 32,116,104,101,110, 10,105,102, 32,116, 46,110,
+ 97,109,101, 32, 61, 61, 32,116, 46,112, 97,114,101,110,116,
+ 46,110, 97,109,101, 32,116,104,101,110, 10,116, 46,110, 97,
+ 109,101, 32, 61, 32, 39,110,101,119, 39, 10,116, 46,108,110,
+ 97,109,101, 32, 61, 32, 39,110,101,119, 39, 10,116, 46,116,
+ 121,112,101, 32, 61, 32,116, 46,112, 97,114,101,110,116, 46,
+ 110, 97,109,101, 10,116, 46,112,116,114, 32, 61, 32, 39, 42,
+ 39, 10,101,108,115,101,105,102, 32,116, 46,110, 97,109,101,
+ 32, 61, 61, 32, 39,126, 39, 46, 46,116, 46,112, 97,114,101,
+ 110,116, 46,110, 97,109,101, 32,116,104,101,110, 10,116, 46,
+ 110, 97,109,101, 32, 61, 32, 39,100,101,108,101,116,101, 39,
+ 10,116, 46,108,110, 97,109,101, 32, 61, 32, 39,100,101,108,
+ 101,116,101, 39, 10,101,110,100, 10,101,110,100, 10,116, 46,
+ 99,110, 97,109,101, 32, 61, 32,116, 58, 99,102,117,110, 99,
+ 110, 97,109,101, 40, 34,116,111,108,117, 97, 73, 34, 41, 46,
+ 46,116, 58,111,118,101,114,108,111, 97,100, 40,116, 41, 10,
+ 114,101,116,117,114,110, 32,116, 10,101,110,100, 10, 10, 10,
+ 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 70,117,110,
+ 99,116,105,111,110, 32, 40,100, 44, 97, 44, 99, 41, 10,108,
+ 111, 99, 97,108, 32,116, 32, 61, 32,115,112,108,105,116, 40,
+ 115,116,114,115,117, 98, 40, 97, 44, 50, 44, 45, 50, 41, 44,
+ 39, 44, 39, 41, 10,108,111, 99, 97,108, 32,105, 61, 49, 10,
+ 108,111, 99, 97,108, 32,108, 32, 61, 32,123,110, 61, 48,125,
+ 10,119,104,105,108,101, 32,116, 91,105, 93, 32,100,111, 10,
+ 108, 46,110, 32, 61, 32,108, 46,110, 43, 49, 10,108, 91,108,
+ 46,110, 93, 32, 61, 32, 68,101, 99,108, 97,114, 97,116,105,
+ 111,110, 40,116, 91,105, 93, 44, 39,118, 97,114, 39, 41, 10,
+ 105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,108,111, 99,
+ 97,108, 32,102, 32, 61, 32, 68,101, 99,108, 97,114, 97,116,
+ 105,111,110, 40,100, 44, 39,102,117,110, 99, 39, 41, 10,102,
+ 46, 97,114,103,115, 32, 61, 32,108, 10,102, 46, 99,111,110,
+ 115,116, 32, 61, 32, 99, 10,114,101,116,117,114,110, 32, 95,
+ 70,117,110, 99,116,105,111,110, 40,102, 41, 10,101,110,100,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 99,108, 97,115,115, 79,112,101,114, 97,116,
+ 111,114, 32, 61, 32,123, 10,107,105,110,100, 32, 61, 32, 39,
+ 39, 44, 10, 95, 98, 97,115,101, 32, 61, 32, 99,108, 97,115,
+ 115, 70,117,110, 99,116,105,111,110, 44, 10,125, 10,115,101,
+ 116,116, 97,103, 40, 99,108, 97,115,115, 79,112,101,114, 97,
+ 116,111,114, 44,116,111,108,117, 97, 95,116, 97,103, 41, 10,
+ 10, 10, 95, 84, 77, 32, 61, 32,123, 91, 39, 43, 39, 93, 32,
+ 61, 32, 39,111,112,101,114, 97,116,111,114, 95, 97,100,100,
+ 39, 44, 10, 91, 39, 45, 39, 93, 32, 61, 32, 39,111,112,101,
+ 114, 97,116,111,114, 95,115,117, 98, 39, 44, 10, 91, 39, 42,
+ 39, 93, 32, 61, 32, 39,111,112,101,114, 97,116,111,114, 95,
+ 109,117,108, 39, 44, 10, 91, 39, 47, 39, 93, 32, 61, 32, 39,
+ 111,112,101,114, 97,116,111,114, 95,100,105,118, 39, 44, 10,
+ 91, 39, 60, 39, 93, 32, 61, 32, 39,111,112,101,114, 97,116,
+ 111,114, 95,108,116, 39, 44, 10, 91, 39, 91, 93, 39, 93, 32,
+ 61, 32, 39,111,112,101,114, 97,116,111,114, 95,103,101,116,
+ 39, 44, 10, 91, 39, 38, 91, 93, 39, 93, 32, 61, 32, 39,111,
+ 112,101,114, 97,116,111,114, 95,115,101,116, 39, 44, 10,125,
+ 10, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108,
+ 97,115,115, 79,112,101,114, 97,116,111,114, 58,112,114,105,
+ 110,116, 32, 40,105,100,101,110,116, 44, 99,108,111,115,101,
+ 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46, 46,
+ 34, 79,112,101,114, 97,116,111,114,123, 34, 41, 10,112,114,
+ 105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32,107,105,
+ 110,100, 32, 61, 32, 39, 34, 46, 46,115,101,108,102, 46,107,
+ 105,110,100, 46, 46, 34, 39, 44, 34, 41, 10,112,114,105,110,
+ 116, 40,105,100,101,110,116, 46, 46, 34, 32,109,111,100, 32,
+ 61, 32, 39, 34, 46, 46,115,101,108,102, 46,109,111,100, 46,
+ 46, 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,
+ 101,110,116, 46, 46, 34, 32,116,121,112,101, 32, 61, 32, 39,
+ 34, 46, 46,115,101,108,102, 46,116,121,112,101, 46, 46, 34,
+ 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,
+ 116, 46, 46, 34, 32,112,116,114, 32, 61, 32, 39, 34, 46, 46,
+ 115,101,108,102, 46,112,116,114, 46, 46, 34, 39, 44, 34, 41,
+ 10,112,114,105,110,116, 40,105,100,101,110,116, 46, 46, 34,
+ 32,110, 97,109,101, 32, 61, 32, 39, 34, 46, 46,115,101,108,
+ 102, 46,110, 97,109,101, 46, 46, 34, 39, 44, 34, 41, 10,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32, 99,
+ 111,110,115,116, 32, 61, 32, 39, 34, 46, 46,115,101,108,102,
+ 46, 99,111,110,115,116, 46, 46, 34, 39, 44, 34, 41, 10,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32, 99,
+ 110, 97,109,101, 32, 61, 32, 39, 34, 46, 46,115,101,108,102,
+ 46, 99,110, 97,109,101, 46, 46, 34, 39, 44, 34, 41, 10,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32,108,
+ 110, 97,109,101, 32, 61, 32, 39, 34, 46, 46,115,101,108,102,
+ 46,108,110, 97,109,101, 46, 46, 34, 39, 44, 34, 41, 10,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32, 97,
+ 114,103,115, 32, 61, 32,123, 34, 41, 10,108,111, 99, 97,108,
+ 32,105, 61, 49, 10,119,104,105,108,101, 32,115,101,108,102,
+ 46, 97,114,103,115, 91,105, 93, 32,100,111, 10,115,101,108,
+ 102, 46, 97,114,103,115, 91,105, 93, 58,112,114,105,110,116,
+ 40,105,100,101,110,116, 46, 46, 34, 32, 34, 44, 34, 44, 34,
+ 41, 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,112,
+ 114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 32,125,
+ 34, 41, 10,112,114,105,110,116, 40,105,100,101,110,116, 46,
+ 46, 34,125, 34, 46, 46, 99,108,111,115,101, 41, 10,101,110,
+ 100, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 95, 79,
+ 112,101,114, 97,116,111,114, 32, 40,116, 41, 10,116, 46, 95,
+ 98, 97,115,101, 32, 61, 32, 99,108, 97,115,115, 79,112,101,
+ 114, 97,116,111,114, 10,115,101,116,116, 97,103, 40,116, 44,
+ 116,111,108,117, 97, 95,116, 97,103, 41, 10, 10,105,102, 32,
+ 116, 46, 99,111,110,115,116, 32,126, 61, 32, 39, 99,111,110,
+ 115,116, 39, 32, 97,110,100, 32,116, 46, 99,111,110,115,116,
+ 32,126, 61, 32, 39, 39, 32,116,104,101,110, 10,101,114,114,
+ 111,114, 40, 34, 35,105,110,118, 97,108,105,100, 32, 39, 99,
+ 111,110,115,116, 39, 32,115,112,101, 99,105,102,105, 99, 97,
+ 116,105,111,110, 34, 41, 10,101,110,100, 10, 10, 97,112,112,
+ 101,110,100, 40,116, 41, 10,105,102, 32,110,111,116, 32,116,
+ 58,105,110, 99,108, 97,115,115, 40, 41, 32,116,104,101,110,
+ 10,101,114,114,111,114, 40, 34, 35,111,112,101,114, 97,116,
+ 111,114, 32, 99, 97,110, 32,111,110,108,121, 32, 98,101, 32,
+ 100,101,102,105,110,101,100, 32, 97,115, 32, 99,108, 97,115,
+ 115, 32,109,101,109, 98,101,114, 34, 41, 10,101,110,100, 10,
+ 10,116, 46, 99,110, 97,109,101, 32, 61, 32,116, 58, 99,102,
+ 117,110, 99,110, 97,109,101, 40, 34,116,111,108,117, 97, 73,
+ 34, 41, 46, 46,116, 58,111,118,101,114,108,111, 97,100, 40,
+ 116, 41, 10,116, 46,110, 97,109,101, 32, 61, 32,116, 46,110,
+ 97,109,101, 46, 46,116, 46,107,105,110,100, 10,114,101,116,
+ 117,114,110, 32,116, 10,101,110,100, 10, 10, 10, 10, 10, 10,
+ 102,117,110, 99,116,105,111,110, 32, 79,112,101,114, 97,116,
+ 111,114, 32, 40,100, 44,107, 44, 97, 44, 99, 41, 10,108,111,
+ 99, 97,108, 32,116, 32, 61, 32,115,112,108,105,116, 40,115,
+ 116,114,115,117, 98, 40, 97, 44, 50, 44,115,116,114,108,101,
+ 110, 40, 97, 41, 45, 49, 41, 44, 39, 44, 39, 41, 10,108,111,
+ 99, 97,108, 32,105, 61, 49, 10,108,111, 99, 97,108, 32,108,
+ 32, 61, 32,123,110, 61, 48,125, 10,119,104,105,108,101, 32,
+ 116, 91,105, 93, 32,100,111, 10,108, 46,110, 32, 61, 32,108,
+ 46,110, 43, 49, 10,108, 91,108, 46,110, 93, 32, 61, 32, 68,
+ 101, 99,108, 97,114, 97,116,105,111,110, 40,116, 91,105, 93,
+ 44, 39,118, 97,114, 39, 41, 10,105, 32, 61, 32,105, 43, 49,
+ 10,101,110,100, 10,105,102, 32,107, 32, 61, 61, 32, 39, 91,
+ 93, 39, 32,116,104,101,110, 10,100, 32, 61, 32,103,115,117,
+ 98, 40,100, 44, 39, 38, 39, 44, 39, 39, 41, 10,101,108,115,
+ 101,105,102, 32,107, 61, 61, 39, 38, 91, 93, 39, 32,116,104,
+ 101,110, 10,108, 46,110, 32, 61, 32,108, 46,110, 43, 49, 10,
+ 108, 91,108, 46,110, 93, 32, 61, 32, 68,101, 99,108, 97,114,
+ 97,116,105,111,110, 40,100, 44, 39,118, 97,114, 39, 41, 10,
+ 108, 91,108, 46,110, 93, 46,110, 97,109,101, 32, 61, 32, 39,
+ 116,111,108,117, 97, 73, 95,118, 97,108,117,101, 39, 10,101,
+ 110,100, 10,108,111, 99, 97,108, 32,102, 32, 61, 32, 68,101,
+ 99,108, 97,114, 97,116,105,111,110, 40,100, 44, 39,102,117,
+ 110, 99, 39, 41, 10,105,102, 32,107, 32, 61, 61, 32, 39, 91,
+ 93, 39, 32, 97,110,100, 32, 40,108, 91, 49, 93, 61, 61,110,
+ 105,108, 32,111,114, 32,105,115, 98, 97,115,105, 99, 40,108,
+ 91, 49, 93, 46,116,121,112,101, 41,126, 61, 39,110,117,109,
+ 98,101,114, 39, 41, 32,116,104,101,110, 10,101,114,114,111,
+ 114, 40, 39,111,112,101,114, 97,116,111,114, 91, 93, 32, 99,
+ 97,110, 32,111,110,108,121, 32, 98,101, 32,100,101,102,105,
+ 110,101,100, 32,102,111,114, 32,110,117,109,101,114,105, 99,
+ 32,105,110,100,101,120, 46, 39, 41, 10,101,110,100, 10,102,
+ 46, 97,114,103,115, 32, 61, 32,108, 10,102, 46, 99,111,110,
+ 115,116, 32, 61, 32, 99, 10,102, 46,107,105,110,100, 32, 61,
+ 32,103,115,117, 98, 40,107, 44, 34, 37,115, 34, 44, 34, 34,
+ 41, 10,102, 46,108,110, 97,109,101, 32, 61, 32, 95, 84, 77,
+ 91,102, 46,107,105,110,100, 93, 10,105,102, 32,110,111,116,
+ 32,102, 46,108,110, 97,109,101, 32,116,104,101,110, 10,101,
+ 114,114,111,114, 40, 34,116,111,108,117, 97, 58, 32,110,111,
+ 32,115,117,112,112,111,114,116, 32,102,111,114, 32,111,112,
+ 101,114, 97,116,111,114, 34, 32, 46, 46, 32,102, 46,107,105,
+ 110,100, 41, 10,101,110,100, 10,105,102, 32,102, 46,107,105,
+ 110,100, 32, 61, 61, 32, 39, 91, 93, 39, 32, 97,110,100, 32,
+ 110,111,116, 32,115,116,114,102,105,110,100, 40,102, 46,109,
+ 111,100, 44, 39, 99,111,110,115,116, 39, 41, 32,116,104,101,
+ 110, 10, 79,112,101,114, 97,116,111,114, 40,100, 44, 39, 38,
+ 39, 46, 46,107, 44, 97, 44, 99, 41, 10,101,110,100, 10,114,
+ 101,116,117,114,110, 32, 95, 79,112,101,114, 97,116,111,114,
+ 40,102, 41, 10,101,110,100, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,108, 97,115,
+ 115, 67,108, 97,115,115, 32, 61, 32,123, 10, 95, 98, 97,115,
+ 101, 32, 61, 32, 99,108, 97,115,115, 67,111,110,116, 97,105,
+ 110,101,114, 44, 10,116,121,112,101, 32, 61, 32, 39, 99,108,
+ 97,115,115, 39, 44, 10,110, 97,109,101, 32, 61, 32, 39, 39,
+ 44, 10, 98, 97,115,101, 32, 61, 32, 39, 39, 44, 10,125, 10,
+ 115,101,116,116, 97,103, 40, 99,108, 97,115,115, 67,108, 97,
+ 115,115, 44,116,111,108,117, 97, 95,116, 97,103, 41, 10, 10,
+ 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,115,
+ 115, 67,108, 97,115,115, 58,114,101,103,105,115,116,101,114,
+ 32, 40, 41, 10,111,117,116,112,117,116, 40, 39, 32,116,111,
+ 108,117, 97, 95, 99, 99,108, 97,115,115, 40,116,111,108,117,
+ 97, 95, 83, 44, 34, 39, 46, 46,115,101,108,102, 46,110, 97,
+ 109,101, 46, 46, 39, 34, 44, 34, 39, 46, 46,115,101,108,102,
+ 46, 98, 97,115,101, 46, 46, 39, 34, 41, 59, 39, 41, 10,108,
+ 111, 99, 97,108, 32,105, 61, 49, 10,119,104,105,108,101, 32,
+ 115,101,108,102, 91,105, 93, 32,100,111, 10,115,101,108,102,
+ 91,105, 93, 58,114,101,103,105,115,116,101,114, 40, 41, 10,
+ 105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,101,110,100,
+ 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108, 97,
+ 115,115, 67,108, 97,115,115, 58,117,110,114,101,103,105,115,
+ 116,101,114, 32, 40, 41, 10,111,117,116,112,117,116, 40, 39,
+ 32,108,117, 97, 95,112,117,115,104,110,105,108, 40,116,111,
+ 108,117, 97, 95, 83, 41, 59, 32,108,117, 97, 95,115,101,116,
+ 103,108,111, 98, 97,108, 40,116,111,108,117, 97, 95, 83, 44,
+ 34, 39, 46, 46,115,101,108,102, 46,110, 97,109,101, 46, 46,
+ 39, 34, 41, 59, 39, 41, 10,101,110,100, 10, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32, 99,108, 97,115,115, 67,108, 97,
+ 115,115, 58,100,101, 99,108,116, 97,103, 32, 40, 41, 10,115,
+ 101,108,102, 46,105,116,121,112,101, 44,115,101,108,102, 46,
+ 116, 97,103, 32, 61, 32,116, 97,103,118, 97,114, 40,115,101,
+ 108,102, 46,110, 97,109,101, 41, 59, 10,115,101,108,102, 46,
+ 99,105,116,121,112,101, 44,115,101,108,102, 46, 99,116, 97,
+ 103, 32, 61, 32,116, 97,103,118, 97,114, 40,115,101,108,102,
+ 46,110, 97,109,101, 44, 39, 99,111,110,115,116, 39, 41, 59,
+ 10,108,111, 99, 97,108, 32,105, 61, 49, 10,119,104,105,108,
+ 101, 32,115,101,108,102, 91,105, 93, 32,100,111, 10,115,101,
+ 108,102, 91,105, 93, 58,100,101, 99,108,116, 97,103, 40, 41,
+ 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,101,110,
+ 100, 10, 10, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,
+ 108, 97,115,115, 67,108, 97,115,115, 58,112,114,105,110,116,
+ 32, 40,105,100,101,110,116, 44, 99,108,111,115,101, 41, 10,
+ 112,114,105,110,116, 40,105,100,101,110,116, 46, 46, 34, 67,
+ 108, 97,115,115,123, 34, 41, 10,112,114,105,110,116, 40,105,
+ 100,101,110,116, 46, 46, 34, 32,110, 97,109,101, 32, 61, 32,
+ 39, 34, 46, 46,115,101,108,102, 46,110, 97,109,101, 46, 46,
+ 34, 39, 44, 34, 41, 10,112,114,105,110,116, 40,105,100,101,
+ 110,116, 46, 46, 34, 32, 98, 97,115,101, 32, 61, 32, 39, 34,
+ 46, 46,115,101,108,102, 46, 98, 97,115,101, 46, 46, 34, 39,
+ 59, 34, 41, 10,108,111, 99, 97,108, 32,105, 61, 49, 10,119,
+ 104,105,108,101, 32,115,101,108,102, 91,105, 93, 32,100,111,
+ 10,115,101,108,102, 91,105, 93, 58,112,114,105,110,116, 40,
+ 105,100,101,110,116, 46, 46, 34, 32, 34, 44, 34, 44, 34, 41,
+ 10,105, 32, 61, 32,105, 43, 49, 10,101,110,100, 10,112,114,
+ 105,110,116, 40,105,100,101,110,116, 46, 46, 34,125, 34, 46,
+ 46, 99,108,111,115,101, 41, 10,101,110,100, 10, 10, 10,102,
+ 117,110, 99,116,105,111,110, 32, 95, 67,108, 97,115,115, 32,
+ 40,116, 41, 10,116, 46, 95, 98, 97,115,101, 32, 61, 32, 99,
+ 108, 97,115,115, 67,108, 97,115,115, 10,115,101,116,116, 97,
+ 103, 40,116, 44,116,111,108,117, 97, 95,116, 97,103, 41, 10,
+ 97,112,112,101,110,100, 40,116, 41, 10,114,101,116,117,114,
+ 110, 32,116, 10,101,110,100, 10, 10, 10, 10,102,117,110, 99,
+ 116,105,111,110, 32, 67,108, 97,115,115, 32, 40,110, 44,112,
+ 44, 98, 41, 10,108,111, 99, 97,108, 32, 99, 32, 61, 32, 95,
+ 67,108, 97,115,115, 40, 95, 67,111,110,116, 97,105,110,101,
+ 114,123,110, 97,109,101, 61,110, 44, 32, 98, 97,115,101, 61,
+ 112,125, 41, 10,112,117,115,104, 40, 99, 41, 10, 99, 58,112,
+ 97,114,115,101, 40,115,116,114,115,117, 98, 40, 98, 44, 50,
+ 44,115,116,114,108,101,110, 40, 98, 41, 45, 49, 41, 41, 10,
+ 112,111,112, 40, 41, 10,101,110,100, 10, 10, 10, 10, 83, 84,
+ 82, 49, 32, 61, 32, 34, 92, 48, 48, 49, 34, 10, 83, 84, 82,
+ 50, 32, 61, 32, 34, 92, 48, 48, 50, 34, 10, 83, 84, 82, 51,
+ 32, 61, 32, 34, 92, 48, 48, 51, 34, 10, 83, 84, 82, 52, 32,
+ 61, 32, 34, 92, 48, 48, 52, 34, 10, 82, 69, 77, 32, 61, 32,
+ 34, 92, 48, 48, 53, 34, 10, 65, 78, 89, 32, 61, 32, 34, 40,
+ 91, 92, 48, 48, 49, 45, 92, 48, 48, 53, 93, 41, 34, 10, 69,
+ 83, 67, 49, 32, 61, 32, 34, 92, 48, 48, 54, 34, 10, 69, 83,
+ 67, 50, 32, 61, 32, 34, 92, 48, 48, 55, 34, 10, 10, 77, 65,
+ 83, 75, 32, 61, 32,123, 10,123, 69, 83, 67, 49, 44, 32, 34,
+ 92, 92, 39, 34,125, 44, 10,123, 69, 83, 67, 50, 44, 32, 39,
+ 92, 92, 34, 39,125, 44, 10,123, 83, 84, 82, 49, 44, 32, 34,
+ 39, 34,125, 44, 10,123, 83, 84, 82, 50, 44, 32, 39, 34, 39,
+ 125, 44, 10,123, 83, 84, 82, 51, 44, 32, 34, 37, 91, 37, 91,
+ 34,125, 44, 10,123, 83, 84, 82, 52, 44, 32, 34, 37, 93, 37,
+ 93, 34,125, 44, 10,123, 82, 69, 77, 32, 44, 32, 34, 37, 45,
+ 37, 45, 34,125, 44, 10,125, 10, 10,102,117,110, 99,116,105,
+ 111,110, 32,109, 97,115,107, 32, 40,115, 41, 10,102,111,114,
+ 32,105, 32, 61, 32, 49, 44,103,101,116,110, 40, 77, 65, 83,
+ 75, 41, 32,100,111, 10,115, 32, 61, 32,103,115,117, 98, 40,
+ 115, 44, 77, 65, 83, 75, 91,105, 93, 91, 50, 93, 44, 77, 65,
+ 83, 75, 91,105, 93, 91, 49, 93, 41, 10,101,110,100, 10,114,
+ 101,116,117,114,110, 32,115, 10,101,110,100, 10, 10,102,117,
+ 110, 99,116,105,111,110, 32,117,110,109, 97,115,107, 32, 40,
+ 115, 41, 10,102,111,114, 32,105, 32, 61, 32, 49, 44,103,101,
+ 116,110, 40, 77, 65, 83, 75, 41, 32,100,111, 10,115, 32, 61,
+ 32,103,115,117, 98, 40,115, 44, 77, 65, 83, 75, 91,105, 93,
+ 91, 49, 93, 44, 77, 65, 83, 75, 91,105, 93, 91, 50, 93, 41,
+ 10,101,110,100, 10,114,101,116,117,114,110, 32,115, 10,101,
+ 110,100, 10, 10,102,117,110, 99,116,105,111,110, 32, 99,108,
+ 101, 97,110, 32, 40,115, 41, 10, 10,108,111, 99, 97,108, 32,
+ 99,111,100,101, 32, 61, 32, 34,114,101,116,117,114,110, 32,
+ 102,117,110, 99,116,105,111,110, 32, 40, 41, 32, 34, 32, 46,
+ 46, 32,115, 32, 46, 46, 32, 34, 32,101,110,100, 34, 10,105,
+ 102, 32,110,111,116, 32,100,111,115,116,114,105,110,103, 40,
+ 99,111,100,101, 41, 32,116,104,101,110, 10,114,101,116,117,
+ 114,110, 32,110,105,108, 10,101,110,100, 10, 10,108,111, 99,
+ 97,108, 32, 83, 32, 61, 32, 34, 34, 10, 10,115, 32, 61, 32,
+ 109, 97,115,107, 40,115, 41, 10, 10, 10,119,104,105,108,101,
+ 32, 49, 32,100,111, 10,108,111, 99, 97,108, 32, 98, 44,101,
+ 44,100, 32, 61, 32,115,116,114,102,105,110,100, 40,115, 44,
+ 65, 78, 89, 41, 10,105,102, 32, 98, 32,116,104,101,110, 10,
+ 83, 32, 61, 32, 83, 46, 46,115,116,114,115,117, 98, 40,115,
+ 44, 49, 44, 98, 45, 49, 41, 10,115, 32, 61, 32,115,116,114,
+ 115,117, 98, 40,115, 44, 98, 43, 49, 41, 10,105,102, 32,100,
+ 61, 61, 83, 84, 82, 49, 32,111,114, 32,100, 61, 61, 83, 84,
+ 82, 50, 32,116,104,101,110, 10,101, 32, 61, 32,115,116,114,
+ 102,105,110,100, 40,115, 44,100, 41, 10, 83, 32, 61, 32, 83,
+ 32, 46, 46,100, 46, 46,115,116,114,115,117, 98, 40,115, 44,
+ 49, 44,101, 41, 10,115, 32, 61, 32,115,116,114,115,117, 98,
+ 40,115, 44,101, 43, 49, 41, 10,101,108,115,101,105,102, 32,
+ 100, 61, 61, 83, 84, 82, 51, 32,116,104,101,110, 10,101, 32,
+ 61, 32,115,116,114,102,105,110,100, 40,115, 44, 83, 84, 82,
+ 52, 41, 10, 83, 32, 61, 32, 83, 46, 46,100, 46, 46,115,116,
+ 114,115,117, 98, 40,115, 44, 49, 44,101, 41, 10,115, 32, 61,
+ 32,115,116,114,115,117, 98, 40,115, 44,101, 43, 49, 41, 10,
+ 101,108,115,101,105,102, 32,100, 61, 61, 82, 69, 77, 32,116,
+ 104,101,110, 10,115, 32, 61, 32,103,115,117, 98, 40,115, 44,
+ 34, 91, 94, 92,110, 93, 42, 40, 92,110, 63, 41, 34, 44, 34,
+ 37, 49, 34, 44, 49, 41, 10,101,110,100, 10,101,108,115,101,
+ 10, 83, 32, 61, 32, 83, 46, 46,115, 10, 98,114,101, 97,107,
+ 10,101,110,100, 10,101,110,100, 10, 10, 83, 32, 61, 32,103,
+ 115,117, 98, 40, 83, 44, 34, 91, 32, 92,116, 93, 43, 34, 44,
+ 34, 32, 34, 41, 10, 83, 32, 61, 32,103,115,117, 98, 40, 83,
+ 44, 34, 91, 32, 92,116, 93, 42, 92,110, 91, 32, 92,116, 93,
+ 42, 34, 44, 34, 92,110, 34, 41, 10, 83, 32, 61, 32,117,110,
+ 109, 97,115,107, 40, 83, 41, 10,114,101,116,117,114,110, 32,
+ 83, 10,101,110,100, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10,105,102, 32,102,108, 97,103,115, 46,102,
+ 32,116,104,101,110, 10,108,111, 99, 97,108, 32,115,116, 44,
+ 32,109,115,103, 32, 61, 32,114,101, 97,100,102,114,111,109,
+ 40,102,108, 97,103,115, 46,102, 41, 10,105,102, 32,110,111,
+ 116, 32,115,116, 32,116,104,101,110, 10,101,114,114,111,114,
+ 40, 39, 35, 39, 46, 46,109,115,103, 41, 10,101,110,100, 10,
+ 101,110,100, 10, 10, 10,105,102, 32,110,111,116, 32,102,108,
+ 97,103,115, 46,110, 32,116,104,101,110, 10,105,102, 32,102,
+ 108, 97,103,115, 46,102, 32,116,104,101,110, 10,102,108, 97,
+ 103,115, 46,110, 32, 61, 32,103,115,117, 98, 40,102,108, 97,
+ 103,115, 46,102, 44, 34, 37, 46, 46, 42, 34, 44, 34, 34, 41,
+ 10,101,108,115,101, 10,101,114,114,111,114, 40, 34, 35,110,
+ 111, 32,112, 97, 99,107, 97,103,101, 32,110, 97,109,101, 32,
+ 110,111,114, 32,105,110,112,117,116, 32,102,105,108,101, 32,
+ 112,114,111,118,105,100,101,100, 34, 41, 10,101,110,100, 10,
+ 101,110,100, 10, 10,108,111, 99, 97,108, 32,112, 32, 61, 32,
+ 80, 97, 99,107, 97,103,101, 40,102,108, 97,103,115, 46,110,
+ 41, 10, 10,105,102, 32,102,108, 97,103,115, 46,102, 32,116,
+ 104,101,110, 10,114,101, 97,100,102,114,111,109, 40, 41, 10,
+ 101,110,100, 10, 10,105,102, 32,102,108, 97,103,115, 46,112,
+ 32,116,104,101,110, 10,114,101,116,117,114,110, 10,101,110,
+ 100, 10, 10,105,102, 32,102,108, 97,103,115, 46,111, 32,116,
+ 104,101,110, 10,108,111, 99, 97,108, 32,115,116, 44,109,115,
+ 103, 32, 61, 32,119,114,105,116,101,116,111, 40,102,108, 97,
+ 103,115, 46,111, 41, 10,105,102, 32,110,111,116, 32,115,116,
+ 32,116,104,101,110, 10,101,114,114,111,114, 40, 39, 35, 39,
+ 46, 46,109,115,103, 41, 10,101,110,100, 10,101,110,100, 10,
+ 10,105,102, 32,102,108, 97,103,115, 46, 80, 32,116,104,101,
+ 110, 10,112, 58,112,114,105,110,116, 40, 41, 10,101,108,115,
+ 101, 10,112, 58,100,101, 99,108,116, 97,103, 40, 41, 10,112,
+ 58,112,114,101, 97,109, 98,108,101, 40, 41, 10,112, 58,115,
+ 117,112, 99,111,100,101, 40, 41, 10,112, 58,114,101,103,105,
+ 115,116,101,114, 40, 41, 10,112, 58,117,110,114,101,103,105,
+ 115,116,101,114, 40, 41, 10,101,110,100, 10, 10,105,102, 32,
+ 102,108, 97,103,115, 46,111, 32,116,104,101,110, 10,119,114,
+ 105,116,101,116,111, 40, 41, 10,101,110,100, 10, 10, 10,105,
+ 102, 32,110,111,116, 32,102,108, 97,103,115, 46, 80, 32,116,
+ 104,101,110, 10,105,102, 32,102,108, 97,103,115, 46, 72, 32,
+ 116,104,101,110, 10,108,111, 99, 97,108, 32,115,116, 44,109,
+ 115,103, 32, 61, 32,119,114,105,116,101,116,111, 40,102,108,
+ 97,103,115, 46, 72, 41, 10,105,102, 32,110,111,116, 32,115,
+ 116, 32,116,104,101,110, 10,101,114,114,111,114, 40, 39, 35,
+ 39, 46, 46,109,115,103, 41, 10,101,110,100, 10,112, 58,104,
+ 101, 97,100,101,114, 40, 41, 10,119,114,105,116,101,116,111,
+ 40, 41, 10,101,110,100, 10,101,110,100,32
+ };
+ lua_dobuffer(tolua_S,(char*)B,sizeof(B),"tolua: embedded Lua code");
+ } /* end of embedded lua code */
+
+ return 1;
+}
+/* Close function */
+void tolua_tolualua_close (lua_State* tolua_S)
+{
+}
diff --git a/src/lua/tolualua.h b/src/lua/tolualua.h
new file mode 100644
index 00000000..b380dcef
--- /dev/null
+++ b/src/lua/tolualua.h
@@ -0,0 +1,2713 @@
+/* code automatically generated by bin2c -- DO NOT EDIT */
+{
+/* #include'ing this file in a C program is equivalent to calling
+ lua_dofile("basic.lo");
+ lua_dofile("feature.lo");
+ lua_dofile("declaration.lo");
+ lua_dofile("container.lo");
+ lua_dofile("package.lo");
+ lua_dofile("module.lo");
+ lua_dofile("class.lo");
+ lua_dofile("typedef.lo");
+ lua_dofile("define.lo");
+ lua_dofile("enumerate.lo");
+ lua_dofile("variable.lo");
+ lua_dofile("array.lo");
+ lua_dofile("function.lo");
+ lua_dofile("operator.lo");
+ lua_dofile("verbatim.lo");
+ lua_dofile("code.lo");
+ lua_dofile("doit.lo");
+*/
+/* basic.lo */
+static char B1[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 11, 64, 98, 97,115,105, 99,
+ 46,108,117, 97, 0, 0, 0, 0,190, 25, 0, 60, 17, 22, 12, 60, 18, 11, 1, 11,
+ 2, 60, 19, 11, 3, 11, 4, 60, 20, 11, 5, 11, 4, 60, 21, 11, 6, 11, 4, 60,
+ 22, 11, 7, 11, 4, 60, 23, 11, 8, 11, 4, 60, 24, 11, 9, 11, 4, 60, 25, 11,
+ 10, 11, 11, 60, 26, 11, 12, 11, 13, 60, 27, 11, 14, 11, 11, 60, 28, 11, 15, 11,
+ 13, 60, 29, 11, 16, 11, 17, 30, 11, 60, 30, 25, 0, 60, 34, 22, 0, 25, 18, 60,
+ 37, 11, 20, 25, 19, 60, 45, 15, 22, 2, 1, 0, 25, 21, 60, 46, 15, 24, 15, 21,
+ 11, 25, 15, 19, 2, 1, 3, 25, 23, 60, 49, 11, 27, 25, 26, 60, 69, 15, 28, 15,
+ 26, 2, 0, 1, 60, 72, 11, 30, 25, 29, 60, 80, 22, 0, 25, 31, 60, 81, 11, 33,
+ 25, 32, 60, 89, 11, 35, 25, 34, 60,109, 11, 37, 25, 36, 60,115, 11, 39, 25, 38,
+ 60,121, 11, 41, 25, 40, 60,138, 11, 43, 25, 42, 60,150, 11, 45, 25, 44, 0, 0,
+ 0, 0, 0, 0, 0, 0, 46, 2, 0, 0, 0, 7, 95, 98, 97,115,105, 99, 0, 2,
+ 0, 0, 0, 5,118,111,105,100, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 5,
+ 99,104, 97,114, 0, 2, 0, 0, 0, 7,110,117,109, 98,101,114, 0, 2, 0, 0,
+ 0, 4,105,110,116, 0, 2, 0, 0, 0, 6,115,104,111,114,116, 0, 2, 0, 0,
+ 0, 5,108,111,110,103, 0, 2, 0, 0, 0, 6,102,108,111, 97,116, 0, 2, 0,
+ 0, 0, 7,100,111,117, 98,108,101, 0, 2, 0, 0, 0, 9, 95, 99,115,116,114,
+105,110,103, 0, 2, 0, 0, 0, 7,115,116,114,105,110,103, 0, 2, 0, 0, 0,
+ 10, 95,117,115,101,114,100, 97,116, 97, 0, 2, 0, 0, 0, 9,117,115,101,114,
+100, 97,116, 97, 0, 2, 0, 0, 0, 6, 99,104, 97,114, 42, 0, 2, 0, 0, 0,
+ 6,118,111,105,100, 42, 0, 2, 0, 0, 0, 11,108,117, 97, 95, 79, 98,106,101,
+ 99,116, 0, 2, 0, 0, 0, 7,111, 98,106,101, 99,116, 0, 2, 0, 0, 0, 10,
+ 95,117,115,101,114,116,121,112,101, 0, 2, 0, 0, 0, 12,116,111,108,117, 97,
+ 95,105,110,100,101,120, 0, 4, 0, 0, 0, 37, 0, 0, 0, 11, 64, 98, 97,115,
+105, 99, 46,108,117, 97, 0, 0, 0, 0, 40, 5, 2, 60, 38, 13, 1, 11, 2, 32,
+ 52, 13, 60, 39, 15, 3, 13, 0, 13, 1, 3, 2, 2, 50, 13, 60, 41, 13, 0, 18,
+ 2, 13, 1, 16, 1, 2, 60, 42, 60, 43, 0, 0, 0, 0, 2, 0, 0, 0, 37, 0,
+ 0, 0, 2,116, 0, 0, 0, 0, 37, 0, 0, 0, 2,102, 0, 0, 0, 0, 4, 2,
+ 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 2,102, 0, 2, 0, 0, 0, 6, 95, 98,
+ 97,115,101, 0, 2, 0, 0, 0, 16,116,111,108,117, 97, 95,111,108,100, 95,105,
+110,100,101,120, 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0,
+ 2, 0, 0, 0, 7,110,101,119,116, 97,103, 0, 2, 0, 0, 0, 16,116,111,108,
+117, 97, 95,111,108,100, 95,105,110,100,101,120, 0, 2, 0, 0, 0, 13,115,101,
+116,116, 97,103,109,101,116,104,111,100, 0, 2, 0, 0, 0, 6,105,110,100,101,
+120, 0, 2, 0, 0, 0, 12,116,111,108,117, 97, 95,101,114,114,111,114, 0, 4,
+ 0, 0, 0, 49, 0, 0, 0, 11, 64, 98, 97,115,105, 99, 46,108,117, 97, 0, 0,
+ 0, 0,163, 9, 1, 60, 50, 15, 2, 60, 51, 15, 3, 25, 2, 60, 52, 15, 4, 13,
+ 0, 7, 1, 7, 1, 2, 1, 3, 11, 5, 32, 52, 24, 60, 53, 15, 6, 11, 7, 15,
+ 4, 13, 0, 7, 2, 2, 1, 2, 42, 11, 8, 42, 2, 0, 1, 50, 19, 60, 55, 15,
+ 6, 11, 9, 13, 0, 42, 11, 8, 42, 2, 0, 1, 60, 57, 1, 2, 60, 59, 15, 10,
+ 52, 73, 60, 60, 15, 12, 15, 10, 11, 13, 2, 3, 2, 60, 61, 13, 4, 4, 0, 32,
+ 52, 4, 15, 10, 23, 4, 60, 62, 15, 14, 13, 4, 11, 15, 11, 16, 2, 1, 3, 23,
+ 4, 60, 63, 15, 14, 13, 4, 11, 17, 11, 18, 2, 1, 3, 23, 4, 60, 64, 15, 6,
+ 11, 19, 13, 4, 42, 11, 20, 42, 2, 0, 1, 5, 3, 50, 2, 60, 65, 60, 66, 13,
+ 1, 25, 2, 60, 67, 0, 0, 0, 0, 8, 0, 0, 0, 49, 0, 0, 0, 2,115, 0,
+ 0, 0, 0, 50, 0, 0, 0, 4,111,117,116, 0, 0, 0, 0, 60, 0, 0, 0, 2,
+ 95, 0, 0, 0, 0, 60, 0, 0, 0, 2, 95, 0, 0, 0, 0, 60, 0, 0, 0, 2,
+115, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0,
+ 0, 64, 0, 0, 0, 0, 0, 0, 0, 21, 2, 0, 0, 0, 2,115, 0, 2, 0, 0,
+ 0, 4,111,117,116, 0, 2, 0, 0, 0, 8, 95, 79, 85, 84, 80, 85, 84, 0, 2,
+ 0, 0, 0, 8, 95, 83, 84, 68, 69, 82, 82, 0, 2, 0, 0, 0, 7,115,116,114,
+115,117, 98, 0, 2, 0, 0, 0, 2, 35, 0, 2, 0, 0, 0, 6,119,114,105,116,
+101, 0, 2, 0, 0, 0, 12, 10, 42, 42, 32,116,111,108,117, 97, 58, 32, 0, 2,
+ 0, 0, 0, 4, 46, 10, 10, 0, 2, 0, 0, 0, 27, 10, 42, 42, 32,116,111,108,
+117, 97, 32,105,110,116,101,114,110, 97,108, 32,101,114,114,111,114, 58, 32, 0,
+ 2, 0, 0, 0, 11, 95, 99,117,114,114, 95, 99,111,100,101, 0, 2, 0, 0, 0,
+ 2, 95, 0, 2, 0, 0, 0, 8,115,116,114,102,105,110,100, 0, 2, 0, 0, 0,
+ 10, 94, 37,115, 42, 40, 46, 45, 10, 41, 0, 2, 0, 0, 0, 5,103,115,117, 98,
+ 0, 2, 0, 0, 0, 10, 95,117,115,101,114,100, 97,116, 97, 0, 2, 0, 0, 0,
+ 6,118,111,105,100, 42, 0, 2, 0, 0, 0, 9, 95, 99,115,116,114,105,110,103,
+ 0, 2, 0, 0, 0, 6, 99,104, 97,114, 42, 0, 2, 0, 0, 0, 23, 67,111,100,
+101, 32, 98,101,105,110,103, 32,112,114,111, 99,101,115,115,101,100, 58, 10, 0,
+ 2, 0, 0, 0, 2, 10, 0, 2, 0, 0, 0, 15,115,101,116,101,114,114,111,114,
+109,101,116,104,111,100, 0, 2, 0, 0, 0, 8,114,101,103,116,121,112,101, 0,
+ 4, 0, 0, 0, 72, 0, 0, 0, 11, 64, 98, 97,115,105, 99, 46,108,117, 97, 0,
+ 0, 0, 0, 36, 4, 1, 60, 73, 15, 1, 13, 0, 2, 1, 1, 44, 52, 11, 60, 74,
+ 15, 2, 13, 0, 13, 0, 26, 50, 2, 60, 75, 60, 76, 13, 0, 1, 1, 60, 77, 0,
+ 0, 0, 0, 1, 0, 0, 0, 72, 0, 0, 0, 2,116, 0, 0, 0, 0, 3, 2, 0,
+ 0, 0, 2,116, 0, 2, 0, 0, 0, 7,105,115,116,121,112,101, 0, 2, 0, 0,
+ 0, 10, 95,117,115,101,114,116,121,112,101, 0, 2, 0, 0, 0, 10, 95,116, 97,
+103,110, 97,109,101,115, 0, 2, 0, 0, 0, 8,100,101, 99,108,116, 97,103, 0,
+ 4, 0, 0, 0, 81, 0, 0, 0, 11, 64, 98, 97,115,105, 99, 46,108,117, 97, 0,
+ 0, 0, 0, 67, 5, 2, 60, 82, 13, 0, 11, 2, 31, 48, 5, 13, 1, 7, 0, 31,
+ 48, 8, 15, 3, 13, 0, 2, 1, 1, 44, 48, 6, 15, 4, 13, 1, 16, 44, 52, 26,
+ 60, 83, 15, 4, 13, 1, 13, 0, 26, 60, 84, 15, 5, 11, 6, 13, 1, 42, 11, 7,
+ 42, 2, 0, 1, 50, 2, 60, 85, 60, 86, 0, 0, 0, 0, 2, 0, 0, 0, 81, 0,
+ 0, 0, 6,105,116,121,112,101, 0, 0, 0, 0, 81, 0, 0, 0, 4,116, 97,103,
+ 0, 0, 0, 0, 8, 2, 0, 0, 0, 6,105,116,121,112,101, 0, 2, 0, 0, 0,
+ 4,116, 97,103, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 8,105,115, 98, 97,
+115,105, 99, 0, 2, 0, 0, 0, 10, 95,116, 97,103,110, 97,109,101,115, 0, 2,
+ 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 12,115,116, 97,116,
+105, 99, 32,105,110,116, 32, 0, 2, 0, 0, 0, 2, 59, 0, 2, 0, 0, 0, 7,
+116, 97,103,118, 97,114, 0, 4, 0, 0, 0, 89, 0, 0, 0, 11, 64, 98, 97,115,
+105, 99, 46,108,117, 97, 0, 0, 0, 0,155, 8, 2, 60, 90, 13, 0, 11, 2, 32,
+ 46, 5, 13, 0, 11, 3, 32, 52, 10, 60, 91, 13, 0, 7, 0, 1, 2, 50,124, 60,
+ 92, 15, 4, 13, 0, 2, 1, 1, 52, 18, 60, 93, 13, 0, 11, 5, 15, 4, 13, 0,
+ 2, 1, 1, 42, 1, 2, 50, 95, 60, 95, 15, 8, 13, 0, 2, 2, 1, 60, 96, 15,
+ 9, 13, 2, 11, 1, 2, 1, 2, 52, 4, 11, 1, 23, 1, 60, 97, 13, 3, 23, 0,
+ 60, 98, 15, 10, 13, 3, 2, 0, 1, 60, 99, 11, 5, 60,100, 13, 1, 48, 5, 13,
+ 1, 11, 2, 31, 52, 20, 60,101, 11, 12, 13, 3, 42, 23, 3, 60,102, 13, 4, 11,
+ 13, 42, 23, 4, 50, 2, 60,103, 60,104, 13, 3, 13, 4, 13, 0, 42, 1, 5, 5,
+ 3, 60,105, 60,106, 0, 0, 0, 0, 8, 0, 0, 0, 89, 0, 0, 0, 5,116,121,
+112,101, 0, 0, 0, 0, 89, 0, 0, 0, 6, 99,111,110,115,116, 0, 0, 0, 0,
+ 95, 0, 0, 0, 2,109, 0, 0, 0, 0, 95, 0, 0, 0, 2,116, 0, 0, 0, 0,
+ 99, 0, 0, 0, 2,118, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 0,104, 0,
+ 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 14, 2, 0, 0, 0, 5,
+116,121,112,101, 0, 2, 0, 0, 0, 6, 99,111,110,115,116, 0, 2, 0, 0, 0,
+ 1, 0, 2, 0, 0, 0, 5,118,111,105,100, 0, 2, 0, 0, 0, 8,105,115, 98,
+ 97,115,105, 99, 0, 2, 0, 0, 0, 11,116,111,108,117, 97, 95,116, 97,103, 95,
+ 0, 2, 0, 0, 0, 2,109, 0, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 12,
+102,105,110,100,116,121,112,101,100,101,102, 0, 2, 0, 0, 0, 8,115,116,114,
+102,105,110,100, 0, 2, 0, 0, 0, 8,114,101,103,116,121,112,101, 0, 2, 0,
+ 0, 0, 2,118, 0, 2, 0, 0, 0, 7, 99,111,110,115,116, 32, 0, 2, 0, 0,
+ 0, 7, 99,111,110,115,116, 95, 0, 2, 0, 0, 0, 8,105,115, 98, 97,115,105,
+ 99, 0, 4, 0, 0, 0,109, 0, 0, 0, 11, 64, 98, 97,115,105, 99, 46,108,117,
+ 97, 0, 0, 0, 0, 23, 5, 1, 60,110, 15, 3, 13, 0, 2, 2, 1, 60,111, 15,
+ 4, 13, 2, 16, 1, 3, 60,112, 0, 0, 0, 0, 3, 0, 0, 0,109, 0, 0, 0,
+ 5,116,121,112,101, 0, 0, 0, 0,110, 0, 0, 0, 2,109, 0, 0, 0, 0,110,
+ 0, 0, 0, 2,116, 0, 0, 0, 0, 5, 2, 0, 0, 0, 5,116,121,112,101, 0,
+ 2, 0, 0, 0, 2,109, 0, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 12,102,
+105,110,100,116,121,112,101,100,101,102, 0, 2, 0, 0, 0, 7, 95, 98, 97,115,
+105, 99, 0, 2, 0, 0, 0, 7,105,115,116,121,112,101, 0, 4, 0, 0, 0,115,
+ 0, 0, 0, 11, 64, 98, 97,115,105, 99, 46,108,117, 97, 0, 0, 0, 0, 30, 3,
+ 1, 60,116, 15, 1, 13, 0, 16, 46, 5, 15, 2, 13, 0, 16, 46, 7, 15, 3, 13,
+ 0, 2, 1, 1, 1, 1, 60,117, 0, 0, 0, 0, 1, 0, 0, 0,115, 0, 0, 0,
+ 2,116, 0, 0, 0, 0, 4, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 7, 95,
+ 98, 97,115,105, 99, 0, 2, 0, 0, 0, 10, 95,117,115,101,114,116,121,112,101,
+ 0, 2, 0, 0, 0, 10,105,115,116,121,112,101,100,101,102, 0, 2, 0, 0, 0,
+ 6,115,112,108,105,116, 0, 4, 0, 0, 0,121, 0, 0, 0, 11, 64, 98, 97,115,
+105, 99, 46,108,117, 97, 0, 0, 0, 0,117, 11, 2, 60,122, 22, 1, 11, 3, 7,
+ 0, 30, 0, 60,123, 13, 2, 58, 5, 1, 60,127, 11, 7, 13, 1, 42, 11, 8, 42,
+ 60,128, 15, 9, 13, 0, 11, 10, 11, 11, 2, 1, 3, 23, 0, 60,129, 15, 9, 13,
+ 0, 11, 12, 11, 11, 2, 1, 3, 23, 0, 60,130, 15, 9, 13, 0, 13, 4, 13, 3,
+ 2, 1, 3, 23, 0, 60,131, 13, 2, 11, 14, 13, 2, 18, 14, 7, 1, 37, 26, 60,
+132, 13, 2, 13, 2, 18, 14, 15, 9, 13, 0, 11, 15, 11, 11, 2, 1, 3, 26, 60,
+133, 13, 2, 1, 5, 60,134, 0, 0, 0, 0, 5, 0, 0, 0,121, 0, 0, 0, 2,
+115, 0, 0, 0, 0,121, 0, 0, 0, 2,116, 0, 0, 0, 0,122, 0, 0, 0, 2,
+108, 0, 0, 0, 0,123, 0, 0, 0, 2,102, 0, 0, 0, 0,127, 0, 0, 0, 2,
+112, 0, 0, 0, 0, 16, 2, 0, 0, 0, 2,115, 0, 2, 0, 0, 0, 2,116, 0,
+ 2, 0, 0, 0, 2,108, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 2,102,
+ 0, 4, 0, 0, 0,123, 0, 0, 0, 11, 64, 98, 97,115,105, 99, 46,108,117, 97,
+ 0, 0, 0, 0, 30, 5, 1, 60,124, 12, 0, 11, 2, 12, 0, 18, 2, 7, 1, 37,
+ 26, 60,125, 12, 0, 12, 0, 18, 2, 13, 0, 26, 60,126, 0, 0, 0, 0, 1, 0,
+ 0, 0,123, 0, 0, 0, 2,115, 0, 0, 0, 0, 3, 2, 0, 0, 0, 2,115, 0,
+ 2, 0, 0, 0, 2,108, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 2,112,
+ 0, 2, 0, 0, 0, 11, 37,115, 42, 40, 46, 45, 41, 37,115, 42, 0, 2, 0, 0,
+ 0, 4, 37,115, 42, 0, 2, 0, 0, 0, 5,103,115,117, 98, 0, 2, 0, 0, 0,
+ 5, 94, 37,115, 43, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 5, 37,115, 43,
+ 36, 0, 2, 0, 0, 0, 2,108, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0,
+ 9, 40, 37,115, 37,115, 42, 41, 36, 0, 2, 0, 0, 0, 7, 99,111,110, 99, 97,
+116, 0, 4, 0, 0, 0,138, 0, 0, 0, 11, 64, 98, 97,115,105, 99, 46,108,117,
+ 97, 0, 0, 0, 0, 69, 8, 3, 60,139, 11, 4, 60,140, 13, 1, 50, 39, 60,142,
+ 13, 3, 13, 0, 13, 4, 16, 42, 23, 3, 60,143, 13, 4, 7, 1, 37, 23, 4, 60,
+144, 13, 4, 13, 2, 34, 52, 7, 13, 3, 11, 6, 42, 23, 3, 60,145, 60,141, 13,
+ 4, 13, 2, 34, 54, 48, 60,146, 13, 3, 1, 5, 60,147, 0, 0, 0, 0, 5, 0,
+ 0, 0,138, 0, 0, 0, 2,116, 0, 0, 0, 0,138, 0, 0, 0, 2,102, 0, 0,
+ 0, 0,138, 0, 0, 0, 2,108, 0, 0, 0, 0,139, 0, 0, 0, 2,115, 0, 0,
+ 0, 0,140, 0, 0, 0, 2,105, 0, 0, 0, 0, 7, 2, 0, 0, 0, 2,116, 0,
+ 2, 0, 0, 0, 2,102, 0, 2, 0, 0, 0, 2,108, 0, 2, 0, 0, 0, 2,115,
+ 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 2, 32,
+ 0, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 4, 0, 0, 0,150, 0, 0,
+ 0, 11, 64, 98, 97,115,105, 99, 46,108,117, 97, 0, 0, 0, 0,161, 6,128, 60,
+151, 7, 1, 50,104, 60,153, 15, 3, 48, 10, 15, 4, 15, 3, 11, 5, 2, 1, 2,
+ 44, 48, 14, 60,154, 15, 4, 13, 0, 13, 1, 16, 11, 6, 2, 1, 2, 52, 11, 60,
+155, 15, 7, 11, 8, 2, 0, 1, 50, 2, 60,156, 60,157, 15, 7, 13, 0, 13, 1,
+ 16, 2, 0, 1, 60,158, 13, 0, 13, 1, 16, 11, 9, 31, 52, 20, 60,159, 15, 10,
+ 13, 0, 13, 1, 16, 9, 1, 9, 1, 2, 1, 3, 25, 3, 50, 2, 60,160, 60,161,
+ 13, 1, 7, 1, 37, 23, 1, 60,162, 60,152, 13, 1, 13, 0, 18, 2, 34, 54,115,
+ 60,163, 15, 4, 13, 0, 13, 0, 18, 2, 16, 11, 11, 2, 1, 2, 52, 15, 60,164,
+ 4, 0, 25, 3, 15, 7, 11, 12, 2, 0, 1, 50, 2, 60,165, 60,166, 0, 0, 0,
+ 0, 2, 0, 0, 0,150, 0, 0, 0, 4, 97,114,103, 0, 0, 0, 0,151, 0, 0,
+ 0, 2,105, 0, 0, 0, 0, 13, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 4,
+ 97,114,103, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 6, 95, 99,111,110,
+116, 0, 2, 0, 0, 0, 8,115,116,114,102,105,110,100, 0, 2, 0, 0, 0, 7,
+ 91, 37, 40, 44, 34, 93, 0, 2, 0, 0, 0, 8, 94, 91, 37, 97, 95,126, 93, 0,
+ 2, 0, 0, 0, 6,119,114,105,116,101, 0, 2, 0, 0, 0, 2, 32, 0, 2, 0,
+ 0, 0, 1, 0, 2, 0, 0, 0, 7,115,116,114,115,117, 98, 0, 2, 0, 0, 0,
+ 14, 91, 37, 47, 37, 41, 37, 59, 37,123, 37,125, 93, 36, 0, 2, 0, 0, 0, 2,
+ 10, 0,
+};
+
+/* feature.lo */
+static char B2[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 13, 64,102,101, 97,116,117,
+114,101, 46,108,117, 97, 0, 0, 0, 0, 83, 3, 0, 60, 16, 22, 0, 60, 17, 25,
+ 0, 60, 20, 15, 0, 11, 1, 11, 2, 26, 60, 24, 15, 0, 11, 3, 11, 4, 26, 60,
+ 28, 15, 0, 11, 5, 11, 6, 26, 60, 32, 15, 0, 11, 7, 11, 8, 26, 60, 36, 15,
+ 0, 11, 9, 11, 10, 26, 60, 40, 15, 0, 11, 11, 11, 12, 26, 60, 49, 15, 0, 11,
+ 13, 11, 14, 26, 60, 59, 15, 0, 11, 15, 11, 16, 26, 0, 0, 0, 0, 0, 0, 0,
+ 0, 17, 2, 0, 0, 0, 13, 99,108, 97,115,115, 70,101, 97,116,117,114,101, 0,
+ 2, 0, 0, 0, 8,115,117,112, 99,111,100,101, 0, 4, 0, 0, 0, 20, 0, 0,
+ 0, 13, 64,102,101, 97,116,117,114,101, 46,108,117, 97, 0, 0, 0, 0, 5, 1,
+ 1, 60, 21, 0, 0, 0, 0, 1, 0, 0, 0, 20, 0, 0, 0, 5,115,101,108,102,
+ 0, 0, 0, 0, 0, 2, 0, 0, 0, 8,100,101, 99,108,116, 97,103, 0, 4, 0,
+ 0, 0, 24, 0, 0, 0, 13, 64,102,101, 97,116,117,114,101, 46,108,117, 97, 0,
+ 0, 0, 0, 5, 1, 1, 60, 25, 0, 0, 0, 0, 1, 0, 0, 0, 24, 0, 0, 0,
+ 5,115,101,108,102, 0, 0, 0, 0, 0, 2, 0, 0, 0, 9,114,101,103,105,115,
+116,101,114, 0, 4, 0, 0, 0, 28, 0, 0, 0, 13, 64,102,101, 97,116,117,114,
+101, 46,108,117, 97, 0, 0, 0, 0, 5, 1, 1, 60, 29, 0, 0, 0, 0, 1, 0,
+ 0, 0, 28, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 11,117,110,114,101,103,105,115,116,101,114, 0, 4, 0, 0, 0, 32, 0, 0, 0,
+ 13, 64,102,101, 97,116,117,114,101, 46,108,117, 97, 0, 0, 0, 0, 5, 1, 1,
+ 60, 33, 0, 0, 0, 0, 1, 0, 0, 0, 32, 0, 0, 0, 5,115,101,108,102, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0, 9,112,114,101, 97,109, 98,108,101, 0, 4, 0,
+ 0, 0, 36, 0, 0, 0, 13, 64,102,101, 97,116,117,114,101, 46,108,117, 97, 0,
+ 0, 0, 0, 5, 1, 1, 60, 37, 0, 0, 0, 0, 1, 0, 0, 0, 36, 0, 0, 0,
+ 5,115,101,108,102, 0, 0, 0, 0, 0, 2, 0, 0, 0, 8,105,110, 99,108, 97,
+115,115, 0, 4, 0, 0, 0, 40, 0, 0, 0, 13, 64,102,101, 97,116,117,114,101,
+ 46,108,117, 97, 0, 0, 0, 0, 44, 3, 1, 60, 41, 13, 0, 18, 1, 48, 9, 13,
+ 0, 18, 1, 18, 2, 11, 3, 32, 52, 12, 60, 42, 13, 0, 18, 1, 18, 4, 1, 1,
+ 50, 8, 60, 44, 4, 0, 1, 1, 60, 45, 60, 46, 0, 0, 0, 0, 1, 0, 0, 0,
+ 40, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 5, 2, 0, 0, 0, 5,115,
+101,108,102, 0, 2, 0, 0, 0, 7,112, 97,114,101,110,116, 0, 2, 0, 0, 0,
+ 5,116,121,112,101, 0, 2, 0, 0, 0, 6, 99,108, 97,115,115, 0, 2, 0, 0,
+ 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 9,105,110,109,111,100,117,108,101,
+ 0, 4, 0, 0, 0, 49, 0, 0, 0, 13, 64,102,101, 97,116,117,114,101, 46,108,
+117, 97, 0, 0, 0, 0, 44, 3, 1, 60, 50, 13, 0, 18, 1, 48, 9, 13, 0, 18,
+ 1, 18, 2, 11, 3, 32, 52, 12, 60, 51, 13, 0, 18, 1, 18, 4, 1, 1, 50, 8,
+ 60, 53, 4, 0, 1, 1, 60, 54, 60, 55, 0, 0, 0, 0, 1, 0, 0, 0, 49, 0,
+ 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 5, 2, 0, 0, 0, 5,115,101,108,
+102, 0, 2, 0, 0, 0, 7,112, 97,114,101,110,116, 0, 2, 0, 0, 0, 5,116,
+121,112,101, 0, 2, 0, 0, 0, 7,109,111,100,117,108,101, 0, 2, 0, 0, 0,
+ 5,110, 97,109,101, 0, 2, 0, 0, 0, 10, 99,102,117,110, 99,110, 97,109,101,
+ 0, 4, 0, 0, 0, 59, 0, 0, 0, 13, 64,102,101, 97,116,117,114,101, 46,108,
+117, 97, 0, 0, 0, 0, 72, 5, 2, 60, 60, 13, 0, 18, 2, 52, 17, 60, 61, 13,
+ 0, 18, 2, 20, 3, 13, 1, 2, 1, 2, 23, 1, 50, 2, 60, 62, 60, 63, 13, 0,
+ 18, 4, 52, 16, 60, 64, 13, 1, 11, 5, 42, 13, 0, 18, 4, 42, 1, 2, 50, 16,
+ 60, 66, 13, 1, 11, 5, 42, 13, 0, 18, 6, 42, 1, 2, 60, 67, 60, 68, 0, 0,
+ 0, 0, 2, 0, 0, 0, 59, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 59,
+ 0, 0, 0, 2,110, 0, 0, 0, 0, 7, 2, 0, 0, 0, 2,110, 0, 2, 0, 0,
+ 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 7,112, 97,114,101,110,116, 0, 2,
+ 0, 0, 0, 10, 99,102,117,110, 99,110, 97,109,101, 0, 2, 0, 0, 0, 6,108,
+110, 97,109,101, 0, 2, 0, 0, 0, 2, 95, 0, 2, 0, 0, 0, 5,110, 97,109,
+101, 0,
+};
+
+/* declaration.lo */
+static char B3[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 17, 64,100,101, 99,108, 97,
+114, 97,116,105,111,110, 46,108,117, 97, 0, 0, 0, 0,193, 17, 0, 60, 24, 22,
+ 8, 60, 25, 11, 1, 15, 2, 11, 3, 60, 26, 11, 4, 11, 5, 60, 27, 11, 4, 11,
+ 6, 60, 28, 11, 4, 11, 7, 60, 29, 11, 4, 11, 8, 60, 30, 11, 4, 11, 9, 60,
+ 31, 11, 4, 11, 10, 60, 32, 11, 4, 30, 7, 60, 33, 25, 0, 60, 34, 15, 11, 15,
+ 0, 15, 12, 2, 0, 2, 60, 37, 11, 14, 25, 13, 60, 45, 15, 0, 11, 15, 11, 16,
+ 26, 60, 84, 15, 0, 11, 17, 11, 18, 26, 60,117, 15, 0, 11, 19, 11, 20, 26, 60,
+130, 15, 0, 11, 21, 11, 22, 26, 60,136, 15, 0, 11, 23, 11, 24, 26, 60,149, 15,
+ 0, 11, 25, 11, 26, 26, 60,184, 15, 0, 11, 27, 11, 28, 26, 60,218, 15, 0, 11,
+ 29, 11, 30, 26, 60,250, 15, 0, 11, 31, 11, 32, 26, 59, 1, 1, 15, 0, 11, 33,
+ 11, 34, 26, 59, 1, 12, 15, 0, 11, 35, 11, 36, 26, 59, 1, 26, 11, 38, 25, 37,
+ 59, 1, 42, 11, 40, 25, 39, 0, 0, 0, 0, 0, 0, 0, 0, 41, 2, 0, 0, 0,
+ 17, 99,108, 97,115,115, 68,101, 99,108, 97,114, 97,116,105,111,110, 0, 2, 0,
+ 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 13, 99,108, 97,115,115, 70,
+101, 97,116,117,114,101, 0, 2, 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0,
+ 1, 0, 2, 0, 0, 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 4,112,116,114,
+ 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 4,100,105,109, 0,
+ 2, 0, 0, 0, 4,114,101,116, 0, 2, 0, 0, 0, 4,100,101,102, 0, 2, 0,
+ 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97,
+ 95,116, 97,103, 0, 2, 0, 0, 0, 15, 99,114,101, 97,116,101, 95,118, 97,114,
+110, 97,109,101, 0, 4, 0, 0, 0, 37, 0, 0, 0, 17, 64,100,101, 99,108, 97,
+114, 97,116,105,111,110, 46,108,117, 97, 0, 0, 0, 0, 34, 2, 0, 60, 38, 15,
+ 0, 44, 52, 4, 7, 0, 25, 0, 60, 39, 15, 0, 7, 1, 37, 25, 0, 60, 40, 11,
+ 1, 15, 0, 42, 1, 0, 60, 41, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,
+ 0, 11, 95,118, 97,114,110,117,109, 98,101,114, 0, 2, 0, 0, 0, 11,116,111,
+108,117, 97, 95,118, 97,114, 95, 0, 2, 0, 0, 0, 10, 99,104,101, 99,107,110,
+ 97,109,101, 0, 4, 0, 0, 0, 45, 0, 0, 0, 17, 64,100,101, 99,108, 97,114,
+ 97,116,105,111,110, 46,108,117, 97, 0, 0, 0, 1,140, 12, 1, 60, 47, 15, 0,
+ 13, 0, 18, 2, 7, 1, 7, 1, 2, 1, 3, 11, 3, 32, 48, 10, 15, 4, 13, 0,
+ 18, 5, 2, 1, 1, 44, 52, 70, 60, 48, 13, 0, 11, 2, 13, 0, 18, 5, 13, 0,
+ 18, 2, 42, 26, 60, 49, 15, 7, 13, 0, 18, 8, 11, 9, 2, 1, 2, 60, 50, 13,
+ 0, 11, 5, 13, 1, 13, 1, 18, 10, 16, 26, 60, 51, 13, 0, 11, 8, 15, 11, 13,
+ 1, 7, 1, 13, 1, 18, 10, 7, 1, 38, 2, 1, 3, 26, 5, 1, 50, 2, 60, 52,
+ 60, 54, 15, 7, 13, 0, 18, 2, 11, 13, 2, 1, 2, 60, 55, 13, 1, 18, 10, 7,
+ 2, 32, 52, 28, 60, 56, 13, 0, 11, 2, 13, 1, 7, 1, 16, 26, 60, 57, 13, 0,
+ 11, 14, 13, 1, 13, 1, 18, 10, 16, 26, 50, 2, 60, 58, 60, 60, 15, 18, 13, 0,
+ 18, 2, 11, 19, 2, 3, 2, 60, 61, 13, 2, 52, 34, 60, 62, 13, 0, 11, 2, 15,
+ 0, 13, 0, 18, 2, 7, 1, 13, 2, 7, 1, 38, 2, 1, 3, 26, 60, 63, 13, 0,
+ 11, 20, 13, 4, 26, 50, 2, 60, 64, 60, 67, 13, 0, 18, 5, 11, 21, 31, 48, 7,
+ 13, 0, 18, 5, 11, 22, 31, 48, 7, 13, 0, 18, 2, 11, 21, 32, 52, 14, 60, 68,
+ 13, 0, 11, 2, 15, 23, 2, 1, 0, 26, 50,135, 60, 69, 13, 0, 18, 24, 11, 25,
+ 32, 52,122, 60, 70, 13, 0, 18, 5, 11, 21, 32, 48, 7, 13, 0, 18, 2, 11, 21,
+ 31, 52, 30, 60, 71, 13, 0, 11, 5, 13, 0, 18, 5, 13, 0, 18, 2, 42, 26, 60,
+ 72, 13, 0, 11, 2, 15, 23, 2, 1, 0, 26, 50, 70, 60, 73, 15, 4, 13, 0, 18,
+ 2, 2, 1, 1, 52, 55, 60, 74, 13, 0, 18, 5, 11, 21, 32, 52, 11, 13, 0, 11,
+ 5, 13, 0, 18, 2, 26, 50, 19, 60, 75, 13, 0, 11, 5, 13, 0, 18, 5, 11, 26,
+ 42, 13, 0, 18, 2, 42, 26, 60, 76, 13, 0, 11, 2, 15, 23, 2, 1, 0, 26, 50,
+ 2, 60, 77, 50, 2, 60, 78, 60, 80, 0, 0, 0, 0, 7, 0, 0, 0, 45, 0, 0,
+ 0, 5,115,101,108,102, 0, 0, 0, 0, 49, 0, 0, 0, 2,109, 0, 0, 0, 0,
+ 51, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 2,116, 0, 0, 0, 0, 60, 0,
+ 0, 0, 2, 98, 0, 0, 0, 0, 60, 0, 0, 0, 2,101, 0, 0, 0, 0, 60, 0,
+ 0, 0, 2,100, 0, 0, 0, 0, 27, 2, 0, 0, 0, 7,115,116,114,115,117, 98,
+ 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,110, 97,109,101,
+ 0, 2, 0, 0, 0, 2, 91, 0, 2, 0, 0, 0, 7,105,115,116,121,112,101, 0,
+ 2, 0, 0, 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 2,109, 0, 2, 0, 0,
+ 0, 6,115,112,108,105,116, 0, 2, 0, 0, 0, 4,109,111,100, 0, 2, 0, 0,
+ 0, 6, 37,115, 37,115, 42, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 7,
+ 99,111,110, 99, 97,116, 0, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 2, 61,
+ 0, 2, 0, 0, 0, 4,100,101,102, 0, 2, 0, 0, 0, 2, 98, 0, 2, 0, 0,
+ 0, 2,101, 0, 2, 0, 0, 0, 2,100, 0, 2, 0, 0, 0, 8,115,116,114,102,
+105,110,100, 0, 2, 0, 0, 0, 9, 37, 91, 40, 46, 45, 41, 37, 93, 0, 2, 0,
+ 0, 0, 4,100,105,109, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 5,118,111,
+105,100, 0, 2, 0, 0, 0, 15, 99,114,101, 97,116,101, 95,118, 97,114,110, 97,
+109,101, 0, 2, 0, 0, 0, 5,107,105,110,100, 0, 2, 0, 0, 0, 4,118, 97,
+114, 0, 2, 0, 0, 0, 2, 32, 0, 2, 0, 0, 0, 10, 99,104,101, 99,107,116,
+121,112,101, 0, 4, 0, 0, 0, 84, 0, 0, 0, 17, 64,100,101, 99,108, 97,114,
+ 97,116,105,111,110, 46,108,117, 97, 0, 0, 0, 0,152, 4, 1, 60, 87, 15, 0,
+ 13, 0, 18, 2, 2, 1, 1, 48, 7, 13, 0, 18, 3, 11, 4, 31, 52, 22, 60, 88,
+ 13, 0, 11, 5, 13, 0, 18, 3, 26, 60, 89, 13, 0, 11, 3, 4, 0, 26, 50, 2,
+ 60, 90, 60, 93, 13, 0, 18, 6, 11, 4, 31, 48, 7, 13, 0, 18, 5, 11, 4, 31,
+ 52, 11, 60, 94, 15, 7, 11, 8, 2, 0, 1, 50, 2, 60, 95, 60, 98, 13, 0, 18,
+ 2, 11, 4, 31, 52, 13, 60, 99, 15, 9, 13, 0, 18, 2, 2, 0, 1, 50, 2, 60,
+100, 60,103, 13, 0, 18, 2, 11, 10, 32, 52, 9, 13, 0, 11, 2, 11, 11, 26, 50,
+ 22, 60,104, 13, 0, 18, 2, 11, 12, 32, 52, 9, 13, 0, 11, 2, 11, 13, 26, 50,
+ 2, 60,105, 60,114, 0, 0, 0, 0, 1, 0, 0, 0, 84, 0, 0, 0, 5,115,101,
+108,102, 0, 0, 0, 0, 14, 2, 0, 0, 0, 8,105,115, 98, 97,115,105, 99, 0,
+ 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,116,121,112,101, 0,
+ 2, 0, 0, 0, 4,112,116,114, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 4,
+114,101,116, 0, 2, 0, 0, 0, 4,100,105,109, 0, 2, 0, 0, 0, 6,101,114,
+114,111,114, 0, 2, 0, 0, 0, 53, 35,105,110,118, 97,108,105,100, 32,112, 97,
+114, 97,109,101,116,101,114, 58, 32, 99, 97,110,110,111,116, 32,114,101,116,117,
+114,110, 32, 97,110, 32, 97,114,114, 97,121, 32,111,102, 32,118, 97,108,117,101,
+115, 0, 2, 0, 0, 0, 8,114,101,103,116,121,112,101, 0, 2, 0, 0, 0, 10,
+ 95,117,115,101,114,100, 97,116, 97, 0, 2, 0, 0, 0, 6,118,111,105,100, 42,
+ 0, 2, 0, 0, 0, 9, 95, 99,115,116,114,105,110,103, 0, 2, 0, 0, 0, 6,
+ 99,104, 97,114, 42, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0, 0,
+ 0,117, 0, 0, 0, 17, 64,100,101, 99,108, 97,114, 97,116,105,111,110, 46,108,
+117, 97, 0, 0, 0, 0,172, 6, 3, 60,118, 15, 2, 13, 1, 11, 3, 42, 2, 0,
+ 1, 60,119, 15, 2, 13, 1, 11, 4, 42, 13, 0, 18, 6, 42, 11, 7, 42, 2, 0,
+ 1, 60,120, 15, 2, 13, 1, 11, 8, 42, 13, 0, 18, 9, 42, 11, 7, 42, 2, 0,
+ 1, 60,121, 15, 2, 13, 1, 11, 10, 42, 13, 0, 18, 11, 42, 11, 7, 42, 2, 0,
+ 1, 60,122, 15, 2, 13, 1, 11, 12, 42, 13, 0, 18, 13, 42, 11, 7, 42, 2, 0,
+ 1, 60,123, 15, 2, 13, 1, 11, 14, 42, 13, 0, 18, 15, 42, 11, 7, 42, 2, 0,
+ 1, 60,124, 15, 2, 13, 1, 11, 16, 42, 13, 0, 18, 17, 42, 11, 7, 42, 2, 0,
+ 1, 60,125, 15, 2, 13, 1, 11, 18, 42, 13, 0, 18, 19, 42, 11, 7, 42, 2, 0,
+ 1, 60,126, 15, 2, 13, 1, 11, 20, 42, 13, 2, 42, 2, 0, 1, 60,127, 0, 0,
+ 0, 0, 3, 0, 0, 0,117, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0,117,
+ 0, 0, 0, 6,105,100,101,110,116, 0, 0, 0, 0,117, 0, 0, 0, 6, 99,108,
+111,115,101, 0, 0, 0, 0, 21, 2, 0, 0, 0, 6,105,100,101,110,116, 0, 2,
+ 0, 0, 0, 6, 99,108,111,115,101, 0, 2, 0, 0, 0, 6,112,114,105,110,116,
+ 0, 2, 0, 0, 0, 13, 68,101, 99,108, 97,114, 97,116,105,111,110,123, 0, 2,
+ 0, 0, 0, 10, 32,109,111,100, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,115,
+101,108,102, 0, 2, 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 3, 39, 44,
+ 0, 2, 0, 0, 0, 10, 32,116,121,112,101, 32, 61, 32, 39, 0, 2, 0, 0, 0,
+ 5,116,121,112,101, 0, 2, 0, 0, 0, 10, 32,112,116,114, 32, 32, 61, 32, 39,
+ 0, 2, 0, 0, 0, 4,112,116,114, 0, 2, 0, 0, 0, 10, 32,110, 97,109,101,
+ 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 10,
+ 32,100,105,109, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 4,100,105,109, 0, 2,
+ 0, 0, 0, 10, 32,100,101,102, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 4,100,
+101,102, 0, 2, 0, 0, 0, 10, 32,114,101,116, 32, 32, 61, 32, 39, 0, 2, 0,
+ 0, 0, 4,114,101,116, 0, 2, 0, 0, 0, 2,125, 0, 2, 0, 0, 0, 8,100,
+101, 99,108,116, 97,103, 0, 4, 0, 0, 0,130, 0, 0, 0, 17, 64,100,101, 99,
+108, 97,114, 97,116,105,111,110, 46,108,117, 97, 0, 0, 0, 0, 56, 10, 1, 60,
+131, 13, 0, 11, 1, 13, 0, 11, 2, 15, 3, 13, 0, 18, 4, 15, 5, 13, 0, 18,
+ 6, 11, 7, 2, 1, 2, 2, 2, 2, 27, 1, 27, 2, 5, 4, 60,132, 15, 8, 13,
+ 0, 18, 1, 13, 0, 18, 2, 2, 0, 2, 60,133, 0, 0, 0, 0, 1, 0, 0, 0,
+130, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 9, 2, 0, 0, 0, 5,115,
+101,108,102, 0, 2, 0, 0, 0, 6,105,116,121,112,101, 0, 2, 0, 0, 0, 4,
+116, 97,103, 0, 2, 0, 0, 0, 7,116, 97,103,118, 97,114, 0, 2, 0, 0, 0,
+ 5,116,121,112,101, 0, 2, 0, 0, 0, 8,115,116,114,102,105,110,100, 0, 2,
+ 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 6, 99,111,110,115,116, 0, 2,
+ 0, 0, 0, 8,100,101, 99,108,116, 97,103, 0, 2, 0, 0, 0, 13,111,117,116,
+ 99,104,101, 99,107,116,121,112,101, 0, 4, 0, 0, 0,136, 0, 0, 0, 17, 64,
+100,101, 99,108, 97,114, 97,116,105,111,110, 46,108,117, 97, 0, 0, 0, 0, 83,
+ 6, 2, 60,137, 4, 1, 60,138, 13, 0, 18, 4, 11, 5, 31, 52, 14, 60,139, 11,
+ 6, 23, 2, 60,140, 7, 0, 23, 3, 50, 25, 60,142, 13, 0, 18, 1, 23, 2, 60,
+143, 13, 0, 18, 2, 11, 5, 31, 46, 2, 7, 0, 23, 3, 60,144, 60,145, 11, 7,
+ 13, 1, 42, 11, 8, 42, 13, 2, 42, 11, 8, 42, 13, 3, 42, 11, 9, 42, 1, 4,
+ 60,146, 0, 0, 0, 0, 4, 0, 0, 0,136, 0, 0, 0, 5,115,101,108,102, 0,
+ 0, 0, 0,136, 0, 0, 0, 5,110, 97,114,103, 0, 0, 0, 0,137, 0, 0, 0,
+ 4,116, 97,103, 0, 0, 0, 0,137, 0, 0, 0, 4,100,101,102, 0, 0, 0, 0,
+ 10, 2, 0, 0, 0, 5,110, 97,114,103, 0, 2, 0, 0, 0, 4,116, 97,103, 0,
+ 2, 0, 0, 0, 4,100,101,102, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2,
+ 0, 0, 0, 4,100,105,109, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 16,116,
+111,108,117, 97, 95,116, 97,103, 95,116, 97, 98,108,101, 0, 2, 0, 0, 0, 14,
+116,111,108,117, 97, 95,105,115,116,121,112,101, 40, 0, 2, 0, 0, 0, 2, 44,
+ 0, 2, 0, 0, 0, 2, 41, 0, 2, 0, 0, 0, 8,100,101, 99,108, 97,114,101,
+ 0, 4, 0, 0, 0,149, 0, 0, 0, 17, 64,100,101, 99,108, 97,114, 97,116,105,
+111,110, 46,108,117, 97, 0, 0, 0, 1, 84, 15, 2, 60,150, 11, 2, 60,151, 13,
+ 0, 18, 1, 11, 2, 31, 52, 4, 11, 4, 23, 2, 60,152, 15, 5, 11, 6, 13, 0,
+ 18, 7, 13, 0, 18, 8, 13, 2, 2, 0, 4, 60,153, 13, 0, 18, 9, 11, 2, 31,
+ 48, 12, 15, 10, 13, 0, 18, 9, 2, 1, 1, 4, 0, 32, 52, 11, 60,154, 15, 5,
+ 11, 4, 2, 0, 1, 50, 2, 60,155, 60,156, 15, 5, 13, 0, 18, 11, 2, 0, 1,
+ 60,157, 13, 0, 18, 9, 11, 2, 31, 52, 76, 60,158, 15, 10, 13, 0, 18, 9, 2,
+ 1, 1, 4, 0, 31, 52, 17, 60,159, 15, 5, 11, 12, 13, 0, 18, 9, 11, 13, 2,
+ 0, 3, 50, 41, 60,161, 15, 5, 11, 14, 13, 0, 18, 7, 13, 0, 18, 8, 13, 2,
+ 11, 15, 60,162, 11, 16, 13, 0, 18, 9, 11, 17, 13, 0, 18, 8, 13, 2, 11, 18,
+ 2, 0, 11, 60,163, 50,161, 60,165, 15, 20, 13, 0, 18, 8, 2, 1, 1, 60,166,
+ 15, 5, 11, 21, 2, 0, 1, 60,167, 13, 3, 44, 48, 5, 13, 2, 11, 2, 32, 52,
+ 7, 15, 5, 11, 4, 2, 0, 1, 60,168, 15, 5, 11, 22, 13, 0, 18, 7, 13, 0,
+ 18, 8, 2, 0, 3, 60,169, 13, 3, 44, 52, 11, 60,170, 15, 5, 11, 4, 2, 0,
+ 1, 50, 2, 60,171, 60,172, 15, 5, 11, 23, 2, 0, 1, 60,173, 7, 0, 60,174,
+ 13, 0, 18, 24, 11, 2, 31, 52, 6, 13, 0, 18, 24, 23, 4, 60,175, 13, 3, 52,
+ 24, 60,176, 15, 5, 11, 25, 13, 3, 42, 11, 26, 13, 1, 11, 27, 13, 4, 11, 18,
+ 2, 0, 6, 50, 19, 60,178, 15, 5, 11, 28, 13, 1, 11, 27, 13, 4, 11, 18, 2,
+ 0, 5, 60,179, 5, 2, 60,180, 60,181, 0, 0, 0, 0, 7, 0, 0, 0,149, 0,
+ 0, 0, 5,115,101,108,102, 0, 0, 0, 0,149, 0, 0, 0, 5,110, 97,114,103,
+ 0, 0, 0, 0,150, 0, 0, 0, 4,112,116,114, 0, 0, 0, 0,165, 0, 0, 0,
+ 2,116, 0, 0, 0, 0,173, 0, 0, 0, 4,100,101,102, 0, 0, 0, 0,179, 0,
+ 0, 0, 0, 0, 0, 0,179, 0, 0, 0, 0, 0, 0, 0, 29, 2, 0, 0, 0, 5,
+110, 97,114,103, 0, 2, 0, 0, 0, 4,112,116,114, 0, 2, 0, 0, 0, 1, 0,
+ 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 2, 42, 0, 2, 0, 0,
+ 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 2, 32, 0, 2, 0, 0, 0,
+ 4,109,111,100, 0, 2, 0, 0, 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 4,
+100,105,109, 0, 2, 0, 0, 0, 9,116,111,110,117,109, 98,101,114, 0, 2, 0,
+ 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 2, 91, 0, 2, 0, 0, 0, 3,
+ 93, 59, 0, 2, 0, 0, 0, 5, 32, 61, 32, 40, 0, 2, 0, 0, 0, 3, 42, 41,
+ 0, 2, 0, 0, 0, 8,109, 97,108,108,111, 99, 40, 0, 2, 0, 0, 0, 9, 42,
+115,105,122,101,111,102, 40, 0, 2, 0, 0, 0, 4, 41, 41, 59, 0, 2, 0, 0,
+ 0, 2,116, 0, 2, 0, 0, 0, 8,105,115, 98, 97,115,105, 99, 0, 2, 0, 0,
+ 0, 4, 32, 61, 32, 0, 2, 0, 0, 0, 3, 40, 40, 0, 2, 0, 0, 0, 3, 41,
+ 32, 0, 2, 0, 0, 0, 4,100,101,102, 0, 2, 0, 0, 0, 10,116,111,108,117,
+ 97, 95,103,101,116, 0, 2, 0, 0, 0, 2, 40, 0, 2, 0, 0, 0, 2, 44, 0,
+ 2, 0, 0, 0, 19,116,111,108,117, 97, 95,103,101,116,117,115,101,114,116,121,
+112,101, 40, 0, 2, 0, 0, 0, 9,103,101,116, 97,114,114, 97,121, 0, 4, 0,
+ 0, 0,184, 0, 0, 0, 17, 64,100,101, 99,108, 97,114, 97,116,105,111,110, 46,
+108,117, 97, 0, 0, 0, 1, 78, 13, 2, 60,185, 13, 0, 18, 2, 11, 3, 31, 51,
+ 1, 59, 60,186, 15, 4, 11, 5, 2, 0, 1, 60,187, 13, 0, 18, 6, 11, 3, 31,
+ 46, 2, 7, 0, 60,188, 15, 4, 11, 7, 13, 1, 11, 8, 13, 0, 18, 9, 11, 8,
+ 13, 0, 18, 2, 11, 8, 13, 2, 11, 10, 2, 0, 9, 60,189, 15, 4, 11, 11, 2,
+ 0, 1, 60,190, 15, 4, 11, 12, 2, 0, 1, 60,191, 15, 4, 11, 13, 2, 0, 1,
+ 60,192, 15, 4, 11, 14, 2, 0, 1, 60,193, 15, 4, 11, 15, 13, 1, 11, 16, 2,
+ 0, 3, 60,194, 15, 4, 11, 17, 13, 0, 18, 2, 42, 11, 18, 42, 2, 0, 1, 60,
+195, 15, 20, 13, 0, 18, 21, 2, 1, 1, 60,196, 11, 3, 60,197, 13, 0, 18, 22,
+ 11, 3, 31, 52, 4, 11, 23, 23, 4, 60,198, 15, 4, 11, 24, 13, 0, 18, 25, 11,
+ 26, 42, 2, 0, 2, 60,199, 13, 3, 44, 48, 5, 13, 4, 11, 3, 32, 52, 7, 15,
+ 4, 11, 23, 2, 0, 1, 60,200, 15, 4, 11, 27, 13, 0, 18, 28, 13, 0, 18, 21,
+ 2, 0, 3, 60,201, 13, 3, 44, 52, 11, 60,202, 15, 4, 11, 23, 2, 0, 1, 50,
+ 2, 60,203, 60,204, 15, 4, 11, 29, 2, 0, 1, 60,205, 7, 0, 60,206, 13, 0,
+ 18, 6, 11, 3, 31, 52, 6, 13, 0, 18, 6, 23, 5, 60,207, 13, 3, 52, 21, 60,
+208, 15, 4, 11, 30, 13, 3, 42, 11, 31, 42, 13, 5, 11, 32, 2, 0, 3, 50, 15,
+ 60,210, 15, 4, 11, 33, 13, 5, 11, 32, 2, 0, 3, 60,211, 60,212, 15, 4, 11,
+ 34, 2, 0, 1, 60,213, 15, 4, 11, 35, 2, 0, 1, 5, 4, 50, 2, 60,214, 60,
+215, 0, 0, 0, 0, 10, 0, 0, 0,184, 0, 0, 0, 5,115,101,108,102, 0, 0,
+ 0, 0,184, 0, 0, 0, 5,110, 97,114,103, 0, 0, 0, 0,187, 0, 0, 0, 4,
+100,101,102, 0, 0, 0, 0,195, 0, 0, 0, 2,116, 0, 0, 0, 0,196, 0, 0,
+ 0, 4,112,116,114, 0, 0, 0, 0,205, 0, 0, 0, 4,100,101,102, 0, 0, 0,
+ 0,213, 0, 0, 0, 0, 0, 0, 0,213, 0, 0, 0, 0, 0, 0, 0,213, 0, 0,
+ 0, 0, 0, 0, 0,213, 0, 0, 0, 0, 0, 0, 0, 36, 2, 0, 0, 0, 5,110,
+ 97,114,103, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 4,100,
+105,109, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 7,111,117,116,112,117,116,
+ 0, 2, 0, 0, 0, 4, 32, 32,123, 0, 2, 0, 0, 0, 4,100,101,102, 0, 2,
+ 0, 0, 0, 27, 32, 32, 32,105,102, 32, 40, 33,116,111,108,117, 97, 95, 97,114,
+114, 97,121,105,115,116,121,112,101, 40, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0,
+ 0, 0, 4,116, 97,103, 0, 2, 0, 0, 0, 3, 41, 41, 0, 2, 0, 0, 0, 16,
+ 32, 32, 32, 32,103,111,116,111, 32,101,114,114,111,114, 59, 0, 2, 0, 0, 0,
+ 9, 32, 32, 32,101,108,115,101, 10, 0, 2, 0, 0, 0, 5, 32, 32, 32,123, 0,
+ 2, 0, 0, 0, 11, 32, 32, 32, 32,105,110,116, 32,105, 59, 0, 2, 0, 0, 0,
+ 34, 32, 32, 32, 32,108,117, 97, 95, 79, 98,106,101, 99,116, 32,108,111, 32, 61,
+ 32,108,117, 97, 95,103,101,116,112, 97,114, 97,109, 40, 0, 2, 0, 0, 0, 3,
+ 41, 59, 0, 2, 0, 0, 0, 16, 32, 32, 32, 32,102,111,114, 40,105, 61, 48, 59,
+ 32,105, 60, 0, 2, 0, 0, 0, 6, 59,105, 43, 43, 41, 0, 2, 0, 0, 0, 2,
+116, 0, 2, 0, 0, 0, 8,105,115, 98, 97,115,105, 99, 0, 2, 0, 0, 0, 5,
+116,121,112,101, 0, 2, 0, 0, 0, 4,112,116,114, 0, 2, 0, 0, 0, 2, 42,
+ 0, 2, 0, 0, 0, 4, 32, 32, 32, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0,
+ 2, 0, 0, 0, 7, 91,105, 93, 32, 61, 32, 0, 2, 0, 0, 0, 3, 40, 40, 0,
+ 2, 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 3, 41, 32, 0, 2, 0, 0,
+ 0, 15,116,111,108,117, 97, 95,103,101,116,102,105,101,108,100, 0, 2, 0, 0,
+ 0, 9, 40,108,111, 44,105, 43, 49, 44, 0, 2, 0, 0, 0, 4, 41, 41, 59, 0,
+ 2, 0, 0, 0, 31,116,111,108,117, 97, 95,103,101,116,102,105,101,108,100,117,
+115,101,114,116,121,112,101, 40,108,111, 44,105, 43, 49, 44, 0, 2, 0, 0, 0,
+ 5, 32, 32, 32,125, 0, 2, 0, 0, 0, 4, 32, 32,125, 0, 2, 0, 0, 0, 9,
+115,101,116, 97,114,114, 97,121, 0, 4, 0, 0, 0,218, 0, 0, 0, 17, 64,100,
+101, 99,108, 97,114, 97,116,105,111,110, 46,108,117, 97, 0, 0, 0, 1, 42, 9,
+ 2, 60,219, 13, 0, 18, 2, 11, 3, 31, 51, 1, 23, 60,220, 15, 4, 11, 5, 2,
+ 0, 1, 60,221, 15, 4, 11, 6, 2, 0, 1, 60,222, 15, 4, 11, 7, 13, 1, 11,
+ 8, 2, 0, 3, 60,223, 15, 4, 11, 9, 13, 0, 18, 2, 42, 11, 10, 42, 2, 0,
+ 1, 60,224, 15, 12, 13, 0, 18, 13, 2, 1, 1, 60,225, 13, 2, 11, 14, 32, 52,
+ 23, 60,226, 15, 4, 11, 15, 13, 2, 42, 11, 16, 42, 13, 0, 18, 17, 11, 18, 2,
+ 0, 3, 50,175, 60,227, 13, 2, 52, 23, 60,228, 15, 4, 11, 15, 13, 2, 42, 11,
+ 19, 42, 13, 0, 18, 17, 11, 18, 2, 0, 3, 50,146, 60,230, 13, 0, 18, 20, 11,
+ 3, 32, 52,110, 60,231, 15, 4, 11, 21, 2, 0, 1, 60,232, 15, 4, 11, 22, 2,
+ 0, 1, 60,233, 15, 4, 11, 23, 13, 0, 18, 13, 11, 24, 13, 0, 18, 17, 11, 18,
+ 2, 0, 5, 60,234, 15, 4, 11, 25, 2, 0, 1, 60,235, 15, 4, 11, 26, 13, 0,
+ 18, 17, 11, 27, 13, 0, 18, 13, 11, 28, 2, 0, 5, 60,236, 15, 4, 11, 29, 2,
+ 0, 1, 60,237, 15, 4, 11, 30, 13, 0, 18, 31, 11, 32, 13, 0, 18, 31, 11, 8,
+ 2, 0, 5, 60,238, 15, 4, 11, 33, 2, 0, 1, 50, 23, 60,242, 15, 4, 11, 34,
+ 13, 0, 18, 17, 11, 35, 13, 0, 18, 31, 11, 8, 2, 0, 5, 60,243, 60,244, 60,
+245, 15, 4, 11, 36, 2, 0, 1, 5, 1, 50, 2, 60,246, 60,247, 0, 0, 0, 0,
+ 4, 0, 0, 0,218, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0,218, 0, 0,
+ 0, 5,110, 97,114,103, 0, 0, 0, 0,224, 0, 0, 0, 2,116, 0, 0, 0, 0,
+245, 0, 0, 0, 0, 0, 0, 0, 37, 2, 0, 0, 0, 5,110, 97,114,103, 0, 2,
+ 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 4,100,105,109, 0, 2, 0,
+ 0, 0, 1, 0, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0,
+ 4, 32, 32,123, 0, 2, 0, 0, 0, 10, 32, 32, 32,105,110,116, 32,105, 59, 0,
+ 2, 0, 0, 0, 33, 32, 32, 32,108,117, 97, 95, 79, 98,106,101, 99,116, 32,108,
+111, 32, 61, 32,108,117, 97, 95,103,101,116,112, 97,114, 97,109, 40, 0, 2, 0,
+ 0, 0, 3, 41, 59, 0, 2, 0, 0, 0, 15, 32, 32, 32,102,111,114, 40,105, 61,
+ 48, 59, 32,105, 60, 0, 2, 0, 0, 0, 6, 59,105, 43, 43, 41, 0, 2, 0, 0,
+ 0, 2,116, 0, 2, 0, 0, 0, 8,105,115, 98, 97,115,105, 99, 0, 2, 0, 0,
+ 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 7,110,117,109, 98,101,114, 0, 2,
+ 0, 0, 0, 19, 32, 32, 32,116,111,108,117, 97, 95,112,117,115,104,102,105,101,
+108,100, 0, 2, 0, 0, 0, 17, 40,108,111, 44,105, 43, 49, 44, 40,100,111,117,
+ 98,108,101, 41, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 6,
+ 91,105, 93, 41, 59, 0, 2, 0, 0, 0, 9, 40,108,111, 44,105, 43, 49, 44, 0,
+ 2, 0, 0, 0, 4,112,116,114, 0, 2, 0, 0, 0, 5, 32, 32, 32,123, 0, 2,
+ 0, 0, 0, 20, 35,105,102,100,101,102, 32, 95, 95, 99,112,108,117,115,112,108,
+117,115, 10, 0, 2, 0, 0, 0, 29, 32, 32, 32, 32,118,111,105,100, 42, 32,116,
+111,108,117, 97, 73, 95, 99,108,111,110,101, 32, 61, 32,110,101,119, 0, 2, 0,
+ 0, 0, 2, 40, 0, 2, 0, 0, 0, 7, 35,101,108,115,101, 10, 0, 2, 0, 0,
+ 0, 45, 32, 32, 32, 32,118,111,105,100, 42, 32,116,111,108,117, 97, 73, 95, 99,
+108,111,110,101, 32, 61, 32,116,111,108,117, 97, 95, 99,111,112,121, 40, 40,118,
+111,105,100, 42, 41, 38, 0, 2, 0, 0, 0, 12, 91,105, 93, 44,115,105,122,101,
+111,102, 40, 0, 2, 0, 0, 0, 4, 41, 41, 59, 0, 2, 0, 0, 0, 8, 35,101,
+110,100,105,102, 10, 0, 2, 0, 0, 0, 63, 32, 32, 32, 32,116,111,108,117, 97,
+ 95,112,117,115,104,102,105,101,108,100,117,115,101,114,116,121,112,101, 40,108,
+111, 44,105, 43, 49, 44,116,111,108,117, 97, 95,100,111, 99,108,111,110,101, 40,
+116,111,108,117, 97, 73, 95, 99,108,111,110,101, 44, 0, 2, 0, 0, 0, 4,116,
+ 97,103, 0, 2, 0, 0, 0, 3, 41, 44, 0, 2, 0, 0, 0, 5, 32, 32, 32,125,
+ 0, 2, 0, 0, 0, 42, 32, 32, 32,116,111,108,117, 97, 95,112,117,115,104,102,
+105,101,108,100,117,115,101,114,116,121,112,101, 40,108,111, 44,105, 43, 49, 44,
+ 40,118,111,105,100, 42, 41, 0, 2, 0, 0, 0, 5, 91,105, 93, 44, 0, 2, 0,
+ 0, 0, 4, 32, 32,125, 0, 2, 0, 0, 0, 10,102,114,101,101, 97,114,114, 97,
+121, 0, 4, 0, 0, 0,250, 0, 0, 0, 17, 64,100,101, 99,108, 97,114, 97,116,
+105,111,110, 46,108,117, 97, 0, 0, 0, 0, 49, 5, 1, 60,251, 13, 0, 18, 1,
+ 11, 2, 31, 48, 12, 15, 3, 13, 0, 18, 1, 2, 1, 1, 4, 0, 32, 52, 17, 60,
+252, 15, 4, 11, 5, 13, 0, 18, 6, 11, 7, 2, 0, 3, 50, 2, 60,253, 60,254,
+ 0, 0, 0, 0, 1, 0, 0, 0,250, 0, 0, 0, 5,115,101,108,102, 0, 0, 0,
+ 0, 8, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 4,100,105,109,
+ 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 9,116,111,110,117,109, 98,101,114,
+ 0, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 8, 32, 32,
+102,114,101,101, 40, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0,
+ 3, 41, 59, 0, 2, 0, 0, 0, 8,112, 97,115,115,112, 97,114, 0, 4, 0, 0,
+ 1, 1, 0, 0, 0, 17, 64,100,101, 99,108, 97,114, 97,116,105,111,110, 46,108,
+117, 97, 0, 0, 0, 0, 79, 4, 1, 59, 1, 2, 13, 0, 18, 1, 11, 2, 32, 52,
+ 17, 59, 1, 3, 15, 3, 11, 4, 13, 0, 18, 5, 42, 2, 0, 1, 50, 44, 59, 1,
+ 4, 13, 0, 18, 6, 11, 4, 32, 52, 17, 59, 1, 5, 15, 3, 11, 2, 13, 0, 18,
+ 5, 42, 2, 0, 1, 50, 15, 59, 1, 7, 15, 3, 13, 0, 18, 5, 2, 0, 1, 59,
+ 1, 8, 59, 1, 9, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 5,115,101,
+108,102, 0, 0, 0, 0, 7, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0,
+ 0, 4,112,116,114, 0, 2, 0, 0, 0, 2, 38, 0, 2, 0, 0, 0, 7,111,117,
+116,112,117,116, 0, 2, 0, 0, 0, 2, 42, 0, 2, 0, 0, 0, 5,110, 97,109,
+101, 0, 2, 0, 0, 0, 4,114,101,116, 0, 2, 0, 0, 0, 9,114,101,116,118,
+ 97,108,117,101, 0, 4, 0, 0, 1, 12, 0, 0, 0, 17, 64,100,101, 99,108, 97,
+114, 97,116,105,111,110, 46,108,117, 97, 0, 0, 0, 0,133, 6, 1, 59, 1, 13,
+ 13, 0, 18, 1, 11, 2, 31, 52,112, 59, 1, 14, 15, 4, 13, 0, 18, 5, 2, 1,
+ 1, 59, 1, 15, 13, 1, 11, 6, 32, 52, 26, 59, 1, 16, 15, 7, 11, 8, 13, 1,
+ 42, 11, 9, 42, 13, 0, 18, 10, 42, 11, 11, 42, 2, 0, 1, 50, 60, 59, 1, 17,
+ 13, 1, 52, 26, 59, 1, 18, 15, 7, 11, 8, 13, 1, 42, 11, 12, 42, 13, 0, 18,
+ 10, 42, 11, 11, 42, 2, 0, 1, 50, 27, 59, 1, 20, 15, 7, 11, 13, 13, 0, 18,
+ 10, 42, 11, 14, 42, 13, 0, 18, 15, 11, 11, 2, 0, 3, 59, 1, 21, 5, 1, 50,
+ 3, 59, 1, 22, 59, 1, 23, 0, 0, 0, 0, 3, 0, 0, 1, 12, 0, 0, 0, 5,
+115,101,108,102, 0, 0, 0, 1, 14, 0, 0, 0, 2,116, 0, 0, 0, 1, 21, 0,
+ 0, 0, 0, 0, 0, 0, 16, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0,
+ 0, 4,114,101,116, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2,116, 0, 2,
+ 0, 0, 0, 8,105,115, 98, 97,115,105, 99, 0, 2, 0, 0, 0, 5,116,121,112,
+101, 0, 2, 0, 0, 0, 7,110,117,109, 98,101,114, 0, 2, 0, 0, 0, 7,111,
+117,116,112,117,116, 0, 2, 0, 0, 0, 14, 32, 32, 32,116,111,108,117, 97, 95,
+112,117,115,104, 0, 2, 0, 0, 0, 10, 40, 40,100,111,117, 98,108,101, 41, 0,
+ 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 3, 41, 59, 0, 2, 0,
+ 0, 0, 2, 40, 0, 2, 0, 0, 0, 30, 32, 32, 32,116,111,108,117, 97, 95,112,
+117,115,104,117,115,101,114,116,121,112,101, 40, 40,118,111,105,100, 42, 41, 0,
+ 2, 0, 0, 0, 2, 44, 0, 2, 0, 0, 0, 4,116, 97,103, 0, 2, 0, 0, 0,
+ 13, 95, 68,101, 99,108, 97,114, 97,116,105,111,110, 0, 4, 0, 0, 1, 26, 0,
+ 0, 0, 17, 64,100,101, 99,108, 97,114, 97,116,105,111,110, 46,108,117, 97, 0,
+ 0, 0, 0,136, 8, 1, 59, 1, 27, 13, 0, 18, 1, 48, 7, 13, 0, 18, 1, 11,
+ 2, 31, 52, 60, 59, 1, 28, 15, 4, 13, 0, 18, 1, 11, 5, 2, 1, 2, 59, 1,
+ 29, 13, 0, 11, 1, 13, 1, 7, 1, 16, 26, 59, 1, 30, 13, 0, 11, 6, 15, 7,
+ 13, 1, 7, 2, 16, 46, 5, 13, 1, 7, 1, 16, 11, 8, 11, 2, 2, 1, 3, 26,
+ 5, 1, 50, 3, 59, 1, 31, 59, 1, 32, 13, 0, 11, 9, 15, 10, 26, 59, 1, 33,
+ 15, 11, 13, 0, 15, 12, 2, 0, 2, 59, 1, 34, 13, 0, 20, 13, 2, 0, 1, 59,
+ 1, 35, 13, 0, 20, 14, 2, 0, 1, 59, 1, 36, 13, 0, 1, 1, 59, 1, 37, 0,
+ 0, 0, 0, 3, 0, 0, 1, 26, 0, 0, 0, 2,116, 0, 0, 0, 1, 28, 0, 0,
+ 0, 2,110, 0, 0, 0, 1, 30, 0, 0, 0, 0, 0, 0, 0, 15, 2, 0, 0, 0,
+ 2,116, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 1, 0, 2,
+ 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 6,115,112,108,105,116, 0, 2, 0, 0,
+ 0, 2, 64, 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0, 5,
+103,115,117, 98, 0, 2, 0, 0, 0, 7, 37, 91, 46, 45, 37, 93, 0, 2, 0, 0,
+ 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 17, 99,108, 97,115,115, 68,101,
+ 99,108, 97,114, 97,116,105,111,110, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,
+103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0,
+ 0, 10, 99,104,101, 99,107,110, 97,109,101, 0, 2, 0, 0, 0, 10, 99,104,101,
+ 99,107,116,121,112,101, 0, 2, 0, 0, 0, 12, 68,101, 99,108, 97,114, 97,116,
+105,111,110, 0, 4, 0, 0, 1, 42, 0, 0, 0, 17, 64,100,101, 99,108, 97,114,
+ 97,116,105,111,110, 46,108,117, 97, 0, 0, 0, 3,164, 20, 2, 59, 1, 44, 15,
+ 2, 13, 0, 11, 3, 11, 4, 2, 1, 3, 23, 0, 59, 1, 46, 13, 1, 11, 5, 32,
+ 52, 44, 59, 1, 48, 13, 0, 11, 6, 32, 46, 5, 13, 0, 11, 7, 32, 52, 22, 59,
+ 1, 49, 15, 8, 22, 2, 11, 9, 11, 7, 11, 1, 13, 1, 30, 1, 3, 2, 1, 50,
+ 3, 59, 1, 50, 50, 3, 59, 1, 51, 59, 1, 54, 15, 11, 13, 0, 11, 12, 2, 1,
+ 2, 59, 1, 55, 13, 2, 18, 13, 7, 2, 32, 52,126, 59, 1, 56, 13, 1, 11, 14,
+ 32, 52, 15, 59, 1, 57, 15, 15, 11, 16, 13, 0, 42, 2, 0, 1, 50, 3, 59, 1,
+ 58, 59, 1, 59, 15, 11, 13, 2, 7, 1, 16, 11, 18, 2, 1, 2, 59, 1, 60, 15,
+ 8, 22, 6, 59, 1, 61, 11, 19, 13, 2, 7, 2, 16, 11, 20, 59, 1, 62, 11, 21,
+ 11, 22, 59, 1, 63, 11, 23, 11, 9, 59, 1, 64, 13, 3, 13, 3, 18, 13, 16, 11,
+ 24, 59, 1, 65, 15, 25, 13, 3, 7, 1, 13, 3, 18, 13, 7, 1, 38, 2, 1, 3,
+ 11, 1, 59, 1, 66, 13, 1, 30, 5, 59, 1, 67, 3, 4, 1, 5, 1, 50, 3, 59,
+ 1, 68, 59, 1, 71, 15, 11, 13, 0, 11, 26, 2, 1, 2, 23, 2, 59, 1, 72, 13,
+ 2, 18, 13, 7, 2, 32, 52,126, 59, 1, 73, 13, 1, 11, 14, 32, 52, 15, 59, 1,
+ 74, 15, 15, 11, 16, 13, 0, 42, 2, 0, 1, 50, 3, 59, 1, 75, 59, 1, 76, 15,
+ 11, 13, 2, 7, 1, 16, 11, 18, 2, 1, 2, 59, 1, 77, 15, 8, 22, 6, 59, 1,
+ 78, 11, 19, 13, 2, 7, 2, 16, 11, 20, 59, 1, 79, 11, 21, 11, 22, 59, 1, 80,
+ 11, 21, 11, 9, 59, 1, 81, 13, 3, 13, 3, 18, 13, 16, 11, 24, 59, 1, 82, 15,
+ 25, 13, 3, 7, 1, 13, 3, 18, 13, 7, 1, 38, 2, 1, 3, 11, 1, 59, 1, 83,
+ 13, 1, 30, 5, 59, 1, 84, 3, 4, 1, 5, 1, 50, 3, 59, 1, 85, 59, 1, 88,
+ 15, 11, 13, 0, 11, 23, 2, 1, 2, 23, 2, 59, 1, 89, 13, 2, 18, 13, 7, 2,
+ 32, 52, 91, 59, 1, 90, 15, 11, 13, 2, 7, 1, 16, 11, 18, 2, 1, 2, 59, 1,
+ 91, 15, 8, 22, 5, 59, 1, 92, 11, 19, 13, 2, 7, 2, 16, 11, 20, 59, 1, 93,
+ 11, 23, 11, 9, 59, 1, 94, 13, 3, 13, 3, 18, 13, 16, 11, 24, 59, 1, 95, 15,
+ 25, 13, 3, 7, 1, 13, 3, 18, 13, 7, 1, 38, 2, 1, 3, 11, 1, 59, 1, 96,
+ 13, 1, 30, 4, 59, 1, 97, 3, 4, 1, 5, 1, 50, 3, 59, 1, 98, 59, 1,101,
+ 15, 2, 13, 0, 11, 28, 11, 29, 2, 1, 3, 59, 1,102, 15, 11, 13, 3, 11, 30,
+ 2, 1, 2, 23, 2, 59, 1,103, 13, 2, 18, 31, 7, 2, 32, 52,113, 59, 1,104,
+ 13, 2, 7, 2, 15, 32, 13, 2, 7, 2, 16, 11, 33, 11, 30, 2, 1, 3, 26, 59,
+ 1,105, 15, 11, 13, 2, 7, 1, 16, 11, 18, 2, 1, 2, 59, 1,106, 15, 8, 22,
+ 5, 59, 1,107, 11, 19, 13, 2, 7, 2, 16, 11, 20, 59, 1,108, 11, 21, 11, 9,
+ 59, 1,109, 13, 4, 13, 4, 18, 31, 16, 11, 24, 59, 1,110, 15, 25, 13, 4, 7,
+ 1, 13, 4, 18, 31, 7, 1, 38, 2, 1, 3, 11, 1, 59, 1,111, 13, 1, 30, 4,
+ 59, 1,112, 3, 5, 1, 5, 1, 50, 3, 59, 1,113, 59, 1,115, 13, 1, 11, 5,
+ 32, 52,129, 59, 1,117, 15, 11, 13, 0, 11, 18, 2, 1, 2, 23, 2, 59, 1,118,
+ 4, 0, 59, 1,119, 15, 35, 13, 2, 13, 2, 18, 31, 16, 2, 1, 1, 52, 6, 11,
+ 6, 23, 4, 50, 21, 13, 2, 13, 2, 18, 31, 16, 23, 4, 13, 2, 11, 31, 13, 2,
+ 18, 31, 7, 1, 38, 26, 59, 1,120, 15, 8, 22, 4, 59, 1,121, 11, 19, 13, 4,
+ 11, 9, 59, 1,122, 13, 2, 13, 2, 18, 31, 16, 11, 24, 59, 1,123, 15, 25, 13,
+ 2, 7, 1, 13, 2, 18, 31, 7, 1, 38, 2, 1, 3, 11, 1, 59, 1,124, 13, 1,
+ 30, 3, 59, 1,125, 3, 5, 1, 5, 1, 50,130, 59, 1,130, 15, 11, 13, 0, 11,
+ 18, 2, 1, 2, 23, 2, 59, 1,131, 13, 2, 13, 2, 18, 31, 16, 59, 1,132, 4,
+ 1, 59, 1,133, 13, 2, 18, 31, 7, 1, 35, 52, 38, 59, 1,134, 13, 2, 13, 2,
+ 18, 31, 7, 1, 38, 16, 23, 5, 59, 1,135, 15, 25, 13, 2, 7, 1, 13, 2, 18,
+ 31, 7, 2, 38, 2, 1, 3, 23, 6, 50, 3, 59, 1,136, 59, 1,137, 15, 8, 22,
+ 4, 59, 1,138, 11, 19, 13, 4, 11, 9, 59, 1,139, 13, 5, 11, 24, 59, 1,140,
+ 13, 6, 11, 1, 59, 1,141, 13, 1, 30, 3, 59, 1,142, 3, 7, 1, 5, 3, 59,
+ 1,143, 59, 1,145, 0, 0, 0, 0, 20, 0, 0, 1, 42, 0, 0, 0, 2,115, 0,
+ 0, 0, 1, 42, 0, 0, 0, 5,107,105,110,100, 0, 0, 0, 1, 54, 0, 0, 0,
+ 2,116, 0, 0, 0, 1, 59, 0, 0, 0, 2,109, 0, 0, 0, 1, 67, 0, 0, 0,
+ 0, 0, 0, 1, 76, 0, 0, 0, 2,109, 0, 0, 0, 1, 84, 0, 0, 0, 0, 0,
+ 0, 1, 90, 0, 0, 0, 2,109, 0, 0, 0, 1, 97, 0, 0, 0, 0, 0, 0, 1,
+101, 0, 0, 0, 3,115, 49, 0, 0, 0, 1,105, 0, 0, 0, 2,109, 0, 0, 0,
+ 1,112, 0, 0, 0, 0, 0, 0, 1,118, 0, 0, 0, 2,118, 0, 0, 0, 1,125,
+ 0, 0, 0, 0, 0, 0, 1,131, 0, 0, 0, 2,118, 0, 0, 0, 1,132, 0, 0,
+ 0, 3,116,112, 0, 0, 0, 1,132, 0, 0, 0, 3,109,100, 0, 0, 0, 1,142,
+ 0, 0, 0, 0, 0, 0, 1,142, 0, 0, 0, 0, 0, 0, 1,142, 0, 0, 0, 0,
+ 0, 0, 0, 38, 2, 0, 0, 0, 2,115, 0, 2, 0, 0, 0, 5,107,105,110,100,
+ 0, 2, 0, 0, 0, 5,103,115,117, 98, 0, 2, 0, 0, 0, 8, 37,115, 42, 61,
+ 37,115, 42, 0, 2, 0, 0, 0, 2, 61, 0, 2, 0, 0, 0, 4,118, 97,114, 0,
+ 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 5,118,111,105,100, 0, 2, 0, 0, 0,
+ 13, 95, 68,101, 99,108, 97,114, 97,116,105,111,110, 0, 2, 0, 0, 0, 5,116,
+121,112,101, 0, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6,115,112,108,105,
+116, 0, 2, 0, 0, 0, 7, 37, 42, 37,115, 42, 38, 0, 2, 0, 0, 0, 2,110,
+ 0, 2, 0, 0, 0, 5,102,117,110, 99, 0, 2, 0, 0, 0, 6,101,114,114,111,
+114, 0, 2, 0, 0, 0, 32, 35,105,110,118, 97,108,105,100, 32,102,117,110, 99,
+116,105,111,110, 32,114,101,116,117,114,110, 32,116,121,112,101, 58, 32, 0, 2,
+ 0, 0, 0, 2,109, 0, 2, 0, 0, 0, 6, 37,115, 37,115, 42, 0, 2, 0, 0,
+ 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 4,112,116,114, 0, 2, 0, 0, 0,
+ 2, 42, 0, 2, 0, 0, 0, 4,114,101,116, 0, 2, 0, 0, 0, 2, 38, 0, 2,
+ 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 7, 99,111,110, 99, 97,116, 0,
+ 2, 0, 0, 0, 8, 37, 42, 37,115, 42, 37, 42, 0, 2, 0, 0, 0, 3,115, 49,
+ 0, 2, 0, 0, 0, 7, 40, 37, 98, 91, 93, 41, 0, 4, 0, 0, 1,101, 0, 0,
+ 0, 17, 64,100,101, 99,108, 97,114, 97,116,105,111,110, 46,108,117, 97, 0, 0,
+ 0, 0, 17, 5, 1, 59, 1,101, 15, 1, 13, 0, 11, 2, 11, 3, 3, 1, 3, 0,
+ 0, 0, 0, 1, 0, 0, 1,101, 0, 0, 0, 2,110, 0, 0, 0, 0, 4, 2, 0,
+ 0, 0, 2,110, 0, 2, 0, 0, 0, 5,103,115,117, 98, 0, 2, 0, 0, 0, 3,
+ 37, 42, 0, 2, 0, 0, 0, 2, 1, 0, 2, 0, 0, 0, 3, 37, 42, 0, 2, 0,
+ 0, 0, 2,110, 0, 2, 0, 0, 0, 5,103,115,117, 98, 0, 2, 0, 0, 0, 2,
+ 1, 0, 2, 0, 0, 0, 2,118, 0, 2, 0, 0, 0, 7,105,115,116,121,112,101,
+ 0, 2, 0, 0, 0, 3,116,112, 0, 2, 0, 0, 0, 3,109,100, 0,
+};
+
+/* container.lo */
+static char B4[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 15, 64, 99,111,110,116, 97,
+105,110,101,114, 46,108,117, 97, 0, 0, 0, 0,162, 5, 0, 60, 17, 60, 18, 22,
+ 2, 60, 19, 11, 1, 4, 0, 11, 2, 60, 20, 15, 3, 30, 1, 60, 21, 25, 0, 60,
+ 22, 15, 4, 15, 0, 15, 5, 2, 0, 2, 60, 25, 15, 0, 11, 6, 11, 7, 26, 60,
+ 36, 15, 0, 11, 8, 11, 9, 26, 60, 48, 11, 11, 25, 10, 60, 58, 11, 13, 25, 12,
+ 60, 63, 11, 15, 25, 14, 60, 68, 11, 17, 25, 16, 60, 73, 11, 19, 25, 18, 60, 78,
+ 11, 21, 25, 20, 60, 83, 11, 23, 25, 22, 60, 88, 15, 24, 11, 25, 11, 26, 26, 60,
+ 95, 15, 24, 11, 27, 11, 28, 26, 60,101, 15, 24, 11, 29, 11, 30, 26, 60,110, 15,
+ 24, 11, 31, 11, 32, 26, 60,129, 15, 24, 11, 33, 11, 34, 26, 60,147, 15, 24, 11,
+ 35, 11, 36, 26, 59, 1, 49, 15, 24, 11, 37, 11, 38, 26, 0, 0, 0, 0, 0, 0,
+ 0, 0, 39, 2, 0, 0, 0, 15, 99,108, 97,115,115, 67,111,110,116, 97,105,110,
+101,114, 0, 2, 0, 0, 0, 5, 99,117,114,114, 0, 2, 0, 0, 0, 6, 95, 98,
+ 97,115,101, 0, 2, 0, 0, 0, 13, 99,108, 97,115,115, 70,101, 97,116,117,114,
+101, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,
+111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 8,100,101, 99,108,116, 97,
+103, 0, 4, 0, 0, 0, 25, 0, 0, 0, 15, 64, 99,111,110,116, 97,105,110,101,
+114, 46,108,117, 97, 0, 0, 0, 0, 59, 4, 1, 60, 26, 15, 0, 13, 0, 2, 0,
+ 1, 60, 27, 7, 1, 50, 23, 60, 29, 13, 0, 13, 1, 16, 20, 3, 2, 0, 1, 60,
+ 30, 13, 1, 7, 1, 37, 23, 1, 60, 31, 60, 28, 13, 0, 13, 1, 16, 54, 32, 60,
+ 32, 15, 4, 2, 0, 0, 60, 33, 0, 0, 0, 0, 2, 0, 0, 0, 25, 0, 0, 0,
+ 5,115,101,108,102, 0, 0, 0, 0, 27, 0, 0, 0, 2,105, 0, 0, 0, 0, 5,
+ 2, 0, 0, 0, 5,112,117,115,104, 0, 2, 0, 0, 0, 5,115,101,108,102, 0,
+ 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 8,100,101, 99,108,116, 97,103, 0,
+ 2, 0, 0, 0, 4,112,111,112, 0, 2, 0, 0, 0, 8,115,117,112, 99,111,100,
+101, 0, 4, 0, 0, 0, 36, 0, 0, 0, 15, 64, 99,111,110,116, 97,105,110,101,
+114, 46,108,117, 97, 0, 0, 0, 0, 59, 4, 1, 60, 37, 15, 0, 13, 0, 2, 0,
+ 1, 60, 38, 7, 1, 50, 23, 60, 40, 13, 0, 13, 1, 16, 20, 3, 2, 0, 1, 60,
+ 41, 13, 1, 7, 1, 37, 23, 1, 60, 42, 60, 39, 13, 0, 13, 1, 16, 54, 32, 60,
+ 43, 15, 4, 2, 0, 0, 60, 44, 0, 0, 0, 0, 2, 0, 0, 0, 36, 0, 0, 0,
+ 5,115,101,108,102, 0, 0, 0, 0, 38, 0, 0, 0, 2,105, 0, 0, 0, 0, 5,
+ 2, 0, 0, 0, 5,112,117,115,104, 0, 2, 0, 0, 0, 5,115,101,108,102, 0,
+ 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 8,115,117,112, 99,111,100,101, 0,
+ 2, 0, 0, 0, 4,112,111,112, 0, 2, 0, 0, 0, 11, 95, 67,111,110,116, 97,
+105,110,101,114, 0, 4, 0, 0, 0, 48, 0, 0, 0, 15, 64, 99,111,110,116, 97,
+105,110,101,114, 46,108,117, 97, 0, 0, 0, 0, 64, 6, 1, 60, 49, 13, 0, 11,
+ 1, 15, 2, 26, 60, 50, 15, 3, 13, 0, 15, 4, 2, 0, 2, 60, 51, 13, 0, 11,
+ 5, 7, 0, 26, 60, 52, 13, 0, 11, 6, 22, 1, 11, 5, 7, 0, 30, 0, 26, 60,
+ 53, 13, 0, 11, 7, 22, 0, 26, 60, 54, 13, 0, 1, 1, 60, 55, 0, 0, 0, 0,
+ 1, 0, 0, 0, 48, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 8, 2, 0,
+ 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2,
+ 0, 0, 0, 15, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 0, 2,
+ 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117,
+ 97, 95,116, 97,103, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 9,116,121,
+112,101,100,101,102,115, 0, 2, 0, 0, 0, 7,108,110, 97,109,101,115, 0, 2,
+ 0, 0, 0, 5,112,117,115,104, 0, 4, 0, 0, 0, 58, 0, 0, 0, 15, 64, 99,
+111,110,116, 97,105,110,101,114, 46,108,117, 97, 0, 0, 0, 0, 14, 4, 1, 60,
+ 59, 15, 1, 11, 2, 13, 0, 26, 60, 60, 0, 0, 0, 0, 1, 0, 0, 0, 58, 0,
+ 0, 0, 2,116, 0, 0, 0, 0, 3, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0,
+ 15, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 0, 2, 0, 0, 0,
+ 5, 99,117,114,114, 0, 2, 0, 0, 0, 4,112,111,112, 0, 4, 0, 0, 0, 63,
+ 0, 0, 0, 15, 64, 99,111,110,116, 97,105,110,101,114, 46,108,117, 97, 0, 0,
+ 0, 0, 18, 3, 0, 60, 64, 15, 0, 11, 1, 15, 0, 18, 1, 18, 2, 26, 60, 65,
+ 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 15, 99,108, 97,115,115, 67,
+111,110,116, 97,105,110,101,114, 0, 2, 0, 0, 0, 5, 99,117,114,114, 0, 2,
+ 0, 0, 0, 7,112, 97,114,101,110,116, 0, 2, 0, 0, 0, 7, 97,112,112,101,
+110,100, 0, 4, 0, 0, 0, 68, 0, 0, 0, 15, 64, 99,111,110,116, 97,105,110,
+101,114, 46,108,117, 97, 0, 0, 0, 0, 18, 4, 1, 60, 69, 15, 1, 18, 2, 20,
+ 3, 13, 0, 3, 1, 2, 60, 70, 0, 0, 0, 0, 1, 0, 0, 0, 68, 0, 0, 0,
+ 2,116, 0, 0, 0, 0, 4, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 15, 99,
+108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 0, 2, 0, 0, 0, 5, 99,
+117,114,114, 0, 2, 0, 0, 0, 7, 97,112,112,101,110,100, 0, 2, 0, 0, 0,
+ 14, 97,112,112,101,110,100,116,121,112,101,100,101,102, 0, 4, 0, 0, 0, 73,
+ 0, 0, 0, 15, 64, 99,111,110,116, 97,105,110,101,114, 46,108,117, 97, 0, 0,
+ 0, 0, 18, 4, 1, 60, 74, 15, 1, 18, 2, 20, 3, 13, 0, 3, 1, 2, 60, 75,
+ 0, 0, 0, 0, 1, 0, 0, 0, 73, 0, 0, 0, 2,116, 0, 0, 0, 0, 4, 2,
+ 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 15, 99,108, 97,115,115, 67,111,110,116,
+ 97,105,110,101,114, 0, 2, 0, 0, 0, 5, 99,117,114,114, 0, 2, 0, 0, 0,
+ 14, 97,112,112,101,110,100,116,121,112,101,100,101,102, 0, 2, 0, 0, 0, 12,
+102,105,110,100,116,121,112,101,100,101,102, 0, 4, 0, 0, 0, 78, 0, 0, 0,
+ 15, 64, 99,111,110,116, 97,105,110,101,114, 46,108,117, 97, 0, 0, 0, 0, 18,
+ 4, 1, 60, 79, 15, 1, 18, 2, 20, 3, 13, 0, 3, 1, 2, 60, 80, 0, 0, 0,
+ 0, 1, 0, 0, 0, 78, 0, 0, 0, 5,116,121,112,101, 0, 0, 0, 0, 4, 2,
+ 0, 0, 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 15, 99,108, 97,115,115, 67,
+111,110,116, 97,105,110,101,114, 0, 2, 0, 0, 0, 5, 99,117,114,114, 0, 2,
+ 0, 0, 0, 12,102,105,110,100,116,121,112,101,100,101,102, 0, 2, 0, 0, 0,
+ 10,105,115,116,121,112,101,100,101,102, 0, 4, 0, 0, 0, 83, 0, 0, 0, 15,
+ 64, 99,111,110,116, 97,105,110,101,114, 46,108,117, 97, 0, 0, 0, 0, 18, 4,
+ 1, 60, 84, 15, 1, 18, 2, 20, 3, 13, 0, 3, 1, 2, 60, 85, 0, 0, 0, 0,
+ 1, 0, 0, 0, 83, 0, 0, 0, 5,116,121,112,101, 0, 0, 0, 0, 4, 2, 0,
+ 0, 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 15, 99,108, 97,115,115, 67,111,
+110,116, 97,105,110,101,114, 0, 2, 0, 0, 0, 5, 99,117,114,114, 0, 2, 0,
+ 0, 0, 10,105,115,116,121,112,101,100,101,102, 0, 2, 0, 0, 0, 15, 99,108,
+ 97,115,115, 67,111,110,116, 97,105,110,101,114, 0, 2, 0, 0, 0, 7, 97,112,
+112,101,110,100, 0, 4, 0, 0, 0, 88, 0, 0, 0, 15, 64, 99,111,110,116, 97,
+105,110,101,114, 46,108,117, 97, 0, 0, 0, 0, 39, 6, 2, 60, 89, 13, 0, 11,
+ 2, 13, 0, 18, 2, 7, 1, 37, 26, 60, 90, 13, 0, 13, 0, 18, 2, 13, 1, 26,
+ 60, 91, 13, 1, 11, 3, 13, 0, 26, 60, 92, 0, 0, 0, 0, 2, 0, 0, 0, 88,
+ 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 88, 0, 0, 0, 2,116, 0, 0,
+ 0, 0, 4, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 5,115,101,108,102, 0,
+ 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 7,112, 97,114,101,110,116, 0, 2,
+ 0, 0, 0, 14, 97,112,112,101,110,100,116,121,112,101,100,101,102, 0, 4, 0,
+ 0, 0, 95, 0, 0, 0, 15, 64, 99,111,110,116, 97,105,110,101,114, 46,108,117,
+ 97, 0, 0, 0, 0, 38, 6, 2, 60, 96, 13, 0, 18, 2, 11, 3, 13, 0, 18, 2,
+ 18, 3, 7, 1, 37, 26, 60, 97, 13, 0, 18, 2, 13, 0, 18, 2, 18, 3, 13, 1,
+ 26, 60, 98, 0, 0, 0, 0, 2, 0, 0, 0, 95, 0, 0, 0, 5,115,101,108,102,
+ 0, 0, 0, 0, 95, 0, 0, 0, 2,116, 0, 0, 0, 0, 4, 2, 0, 0, 0, 2,
+116, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 9,116,121,112,
+101,100,101,102,115, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 9,111,118,
+101,114,108,111, 97,100, 0, 4, 0, 0, 0,101, 0, 0, 0, 15, 64, 99,111,110,
+116, 97,105,110,101,114, 46,108,117, 97, 0, 0, 0, 0, 67, 6, 2, 60,102, 13,
+ 0, 18, 2, 13, 1, 16, 44, 52, 13, 60,103, 13, 0, 18, 2, 13, 1, 7, 0, 26,
+ 50, 21, 60,105, 13, 0, 18, 2, 13, 1, 13, 0, 18, 2, 13, 1, 16, 7, 1, 37,
+ 26, 60,106, 60,107, 15, 3, 11, 4, 13, 0, 18, 2, 13, 1, 16, 3, 2, 2, 60,
+108, 0, 0, 0, 0, 2, 0, 0, 0,101, 0, 0, 0, 5,115,101,108,102, 0, 0,
+ 0, 0,101, 0, 0, 0, 6,108,110, 97,109,101, 0, 0, 0, 0, 5, 2, 0, 0,
+ 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0,
+ 0, 0, 7,108,110, 97,109,101,115, 0, 2, 0, 0, 0, 7,102,111,114,109, 97,
+116, 0, 2, 0, 0, 0, 5, 37, 48, 50,100, 0, 2, 0, 0, 0, 12,102,105,110,
+100,116,121,112,101,100,101,102, 0, 4, 0, 0, 0,110, 0, 0, 0, 15, 64, 99,
+111,110,116, 97,105,110,101,114, 46,108,117, 97, 0, 0, 0, 0,142, 10, 2, 60,
+111, 13, 0, 50,117, 60,113, 13, 2, 18, 3, 52, 97, 60,114, 7, 1, 50, 76, 60,
+116, 13, 2, 18, 3, 13, 3, 16, 18, 5, 13, 1, 32, 52, 47, 60,117, 13, 2, 18,
+ 3, 13, 3, 16, 18, 8, 13, 2, 18, 3, 13, 3, 16, 18, 0, 60,118, 15, 11, 13,
+ 5, 2, 2, 1, 60,119, 13, 6, 11, 12, 42, 13, 4, 42, 13, 7, 1, 8, 5, 4,
+ 50, 2, 60,120, 60,121, 13, 3, 7, 1, 37, 23, 3, 60,122, 60,115, 13, 2, 18,
+ 3, 13, 3, 16, 54, 87, 5, 1, 50, 2, 60,123, 60,124, 13, 2, 18, 13, 23, 2,
+ 60,125, 60,112, 13, 2, 54,123, 60,126, 11, 14, 13, 1, 1, 3, 60,127, 0, 0,
+ 0, 0, 13, 0, 0, 0,110, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0,110,
+ 0, 0, 0, 5,116,121,112,101, 0, 0, 0, 0,111, 0, 0, 0, 4,101,110,118,
+ 0, 0, 0, 0,114, 0, 0, 0, 2,105, 0, 0, 0, 0,117, 0, 0, 0, 5,109,
+111,100, 49, 0, 0, 0, 0,117, 0, 0, 0, 6,116,121,112,101, 49, 0, 0, 0,
+ 0,118, 0, 0, 0, 5,109,111,100, 50, 0, 0, 0, 0,118, 0, 0, 0, 6,116,
+121,112,101, 50, 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0,119, 0, 0, 0,
+ 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0,
+122, 0, 0, 0, 0, 0, 0, 0, 15, 2, 0, 0, 0, 5,116,121,112,101, 0, 2,
+ 0, 0, 0, 4,101,110,118, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0,
+ 0, 0, 9,116,121,112,101,100,101,102,115, 0, 2, 0, 0, 0, 2,105, 0, 2,
+ 0, 0, 0, 6,117,116,121,112,101, 0, 2, 0, 0, 0, 5,109,111,100, 49, 0,
+ 2, 0, 0, 0, 6,116,121,112,101, 49, 0, 2, 0, 0, 0, 4,109,111,100, 0,
+ 2, 0, 0, 0, 5,109,111,100, 50, 0, 2, 0, 0, 0, 6,116,121,112,101, 50,
+ 0, 2, 0, 0, 0, 12,102,105,110,100,116,121,112,101,100,101,102, 0, 2, 0,
+ 0, 0, 2, 32, 0, 2, 0, 0, 0, 7,112, 97,114,101,110,116, 0, 2, 0, 0,
+ 0, 1, 0, 2, 0, 0, 0, 10,105,115,116,121,112,101,100,101,102, 0, 4, 0,
+ 0, 0,129, 0, 0, 0, 15, 64, 99,111,110,116, 97,105,110,101,114, 46,108,117,
+ 97, 0, 0, 0, 0,101, 6, 2, 60,130, 13, 0, 50, 78, 60,132, 13, 2, 18, 3,
+ 52, 58, 60,133, 7, 1, 50, 37, 60,135, 13, 2, 18, 3, 13, 3, 16, 18, 5, 13,
+ 1, 32, 52, 8, 60,136, 7, 1, 1, 4, 50, 2, 60,137, 60,138, 13, 3, 7, 1,
+ 37, 23, 3, 60,139, 60,134, 13, 2, 18, 3, 13, 3, 16, 54, 48, 5, 1, 50, 2,
+ 60,140, 60,141, 13, 2, 18, 6, 23, 2, 60,142, 60,131, 13, 2, 54, 84, 60,143,
+ 4, 0, 1, 3, 60,144, 0, 0, 0, 0, 5, 0, 0, 0,129, 0, 0, 0, 5,115,
+101,108,102, 0, 0, 0, 0,129, 0, 0, 0, 5,116,121,112,101, 0, 0, 0, 0,
+130, 0, 0, 0, 4,101,110,118, 0, 0, 0, 0,133, 0, 0, 0, 2,105, 0, 0,
+ 0, 0,139, 0, 0, 0, 0, 0, 0, 0, 7, 2, 0, 0, 0, 5,116,121,112,101,
+ 0, 2, 0, 0, 0, 4,101,110,118, 0, 2, 0, 0, 0, 5,115,101,108,102, 0,
+ 2, 0, 0, 0, 9,116,121,112,101,100,101,102,115, 0, 2, 0, 0, 0, 2,105,
+ 0, 2, 0, 0, 0, 6,117,116,121,112,101, 0, 2, 0, 0, 0, 7,112, 97,114,
+101,110,116, 0, 2, 0, 0, 0, 8,100,111,112, 97,114,115,101, 0, 4, 0, 0,
+ 0,147, 0, 0, 0, 15, 64, 99,111,110,116, 97,105,110,101,114, 46,108,117, 97,
+ 0, 0, 0, 4, 55, 13, 2, 60,151, 15, 5, 13, 1, 11, 6, 2, 4, 2, 60,152,
+ 13, 2, 52, 42, 60,153, 15, 8, 13, 1, 13, 2, 13, 3, 2, 1, 3, 25, 7, 60,
+154, 15, 9, 13, 4, 13, 5, 2, 0, 2, 60,155, 15, 8, 13, 1, 13, 3, 7, 1,
+ 37, 3, 6, 2, 50, 2, 60,156, 5, 4, 60,157, 60,161, 15, 5, 13, 1, 11, 10,
+ 2, 3, 2, 60,162, 13, 2, 52, 40, 60,163, 15, 8, 13, 1, 13, 2, 13, 3, 2,
+ 1, 3, 25, 7, 60,164, 15, 11, 13, 4, 2, 0, 1, 60,165, 15, 8, 13, 1, 13,
+ 3, 7, 1, 37, 3, 5, 2, 50, 2, 60,166, 5, 3, 60,167, 60,171, 15, 5, 13,
+ 1, 11, 12, 2, 3, 2, 60,172, 13, 2, 52, 40, 60,173, 15, 8, 13, 1, 13, 2,
+ 13, 3, 2, 1, 3, 25, 7, 60,174, 15, 13, 13, 4, 2, 0, 1, 60,175, 15, 8,
+ 13, 1, 13, 3, 7, 1, 37, 3, 5, 2, 50, 2, 60,176, 5, 3, 60,177, 60,180,
+ 15, 5, 13, 1, 11, 14, 2, 4, 2, 60,181, 13, 2, 52, 52, 60,182, 15, 8, 13,
+ 1, 13, 2, 13, 3, 2, 1, 3, 25, 7, 60,183, 15, 13, 13, 4, 2, 0, 1, 60,
+184, 15, 15, 11, 16, 13, 5, 42, 2, 0, 1, 60,185, 15, 8, 13, 1, 13, 3, 7,
+ 1, 37, 3, 6, 2, 50, 2, 60,186, 5, 4, 60,187, 60,191, 15, 5, 13, 1, 11,
+ 21, 2, 6, 2, 60,192, 13, 2, 52, 46, 60,193, 15, 8, 13, 1, 13, 2, 13, 3,
+ 2, 1, 3, 25, 7, 60,194, 15, 22, 13, 4, 13, 5, 13, 6, 13, 7, 2, 0, 4,
+ 60,195, 15, 8, 13, 1, 13, 3, 7, 1, 37, 3, 8, 2, 50, 2, 60,196, 5, 6,
+ 60,197, 60,201, 15, 5, 13, 1, 11, 23, 2, 5, 2, 60,202, 13, 2, 44, 52, 23,
+ 60,204, 15, 5, 13, 1, 11, 24, 2, 5, 2, 23, 6, 23, 5, 23, 4, 23, 3, 23,
+ 2, 50, 2, 60,205, 60,206, 13, 2, 52, 44, 60,207, 15, 8, 13, 1, 13, 2, 13,
+ 3, 2, 1, 3, 25, 7, 60,208, 15, 25, 13, 4, 13, 5, 13, 6, 2, 0, 3, 60,
+209, 15, 8, 13, 1, 13, 3, 7, 1, 37, 3, 7, 2, 50, 2, 60,210, 5, 5, 60,
+211, 60,215, 15, 5, 13, 1, 11, 26, 2, 5, 2, 60,216, 13, 2, 44, 52, 23, 60,
+218, 15, 5, 13, 1, 11, 27, 2, 5, 2, 23, 6, 23, 5, 23, 4, 23, 3, 23, 2,
+ 50, 2, 60,219, 60,220, 13, 2, 52, 44, 60,221, 15, 8, 13, 1, 13, 2, 13, 3,
+ 2, 1, 3, 25, 7, 60,222, 15, 25, 13, 4, 13, 5, 13, 6, 2, 0, 3, 60,223,
+ 15, 8, 13, 1, 13, 3, 7, 1, 37, 3, 7, 2, 50, 2, 60,224, 5, 5, 60,225,
+ 60,229, 15, 5, 13, 1, 11, 29, 2, 5, 2, 60,230, 13, 2, 44, 52, 59, 60,231,
+ 15, 5, 13, 1, 11, 30, 2, 5, 2, 23, 6, 23, 5, 23, 4, 23, 3, 23, 2, 60,
+232, 13, 2, 44, 52, 27, 60,233, 11, 31, 23, 5, 60,234, 15, 5, 13, 1, 11, 32,
+ 2, 4, 2, 23, 4, 23, 6, 23, 3, 23, 2, 50, 2, 60,235, 50, 2, 60,236, 60,
+237, 13, 2, 52, 80, 60,238, 13, 5, 11, 31, 31, 52, 25, 60,239, 4, 1, 60,240,
+ 15, 5, 13, 5, 11, 33, 2, 3, 2, 23, 5, 23, 8, 23, 7, 5, 2, 50, 2, 60,
+241, 60,242, 15, 8, 13, 1, 13, 2, 13, 3, 2, 1, 3, 25, 7, 60,243, 15, 34,
+ 13, 4, 13, 5, 13, 6, 2, 0, 3, 60,244, 15, 8, 13, 1, 13, 3, 7, 1, 37,
+ 3, 7, 2, 50, 2, 60,245, 5, 5, 60,246, 60,250, 15, 5, 13, 1, 11, 36, 2,
+ 3, 2, 60,251, 13, 2, 52, 40, 60,252, 15, 8, 13, 1, 13, 2, 13, 3, 2, 1,
+ 3, 25, 7, 60,253, 15, 15, 13, 4, 2, 0, 1, 60,254, 15, 8, 13, 1, 13, 3,
+ 7, 1, 37, 3, 5, 2, 50, 2, 60,255, 5, 3, 59, 1, 0, 59, 1, 4, 15, 5,
+ 13, 1, 11, 37, 2, 3, 2, 59, 1, 5, 13, 2, 52, 43, 59, 1, 6, 15, 8, 13,
+ 1, 13, 2, 13, 3, 2, 1, 3, 25, 7, 59, 1, 7, 15, 38, 13, 4, 2, 0, 1,
+ 59, 1, 8, 15, 8, 13, 1, 13, 3, 7, 1, 37, 3, 5, 2, 50, 3, 59, 1, 9,
+ 5, 3, 59, 1, 10, 59, 1, 14, 15, 5, 13, 1, 11, 39, 2, 3, 2, 59, 1, 15,
+ 13, 2, 52, 43, 59, 1, 16, 15, 8, 13, 1, 13, 2, 13, 3, 2, 1, 3, 25, 7,
+ 59, 1, 17, 15, 40, 13, 4, 2, 0, 1, 59, 1, 18, 15, 8, 13, 1, 13, 3, 7,
+ 1, 37, 3, 5, 2, 50, 3, 59, 1, 19, 5, 3, 59, 1, 20, 59, 1, 24, 15, 5,
+ 13, 1, 11, 42, 2, 3, 2, 59, 1, 25, 13, 2, 52, 36, 59, 1, 26, 15, 43, 15,
+ 8, 13, 4, 7, 2, 9, 2, 2, 1, 3, 2, 0, 1, 59, 1, 27, 15, 8, 13, 1,
+ 13, 3, 7, 1, 37, 3, 5, 2, 50, 3, 59, 1, 28, 5, 3, 59, 1, 29, 59, 1,
+ 33, 15, 5, 13, 1, 11, 45, 2, 3, 2, 59, 1, 34, 13, 2, 52, 27, 59, 1, 35,
+ 15, 46, 13, 4, 2, 0, 1, 59, 1, 36, 15, 8, 13, 1, 13, 3, 7, 1, 37, 3,
+ 5, 2, 50, 3, 59, 1, 37, 5, 3, 59, 1, 38, 59, 1, 41, 15, 47, 13, 1, 11,
+ 48, 11, 31, 2, 1, 3, 11, 31, 31, 52, 19, 59, 1, 42, 13, 1, 25, 7, 59, 1,
+ 43, 15, 49, 11, 50, 2, 0, 1, 50, 10, 59, 1, 45, 11, 31, 1, 2, 59, 1, 46,
+ 59, 1, 47, 0, 0, 0, 0,106, 0, 0, 0,147, 0, 0, 0, 5,115,101,108,102,
+ 0, 0, 0, 0,147, 0, 0, 0, 2,115, 0, 0, 0, 0,151, 0, 0, 0, 2, 98,
+ 0, 0, 0, 0,151, 0, 0, 0, 2,101, 0, 0, 0, 0,151, 0, 0, 0, 5,110,
+ 97,109,101, 0, 0, 0, 0,151, 0, 0, 0, 5, 98,111,100,121, 0, 0, 0, 0,
+156, 0, 0, 0, 0, 0, 0, 0,156, 0, 0, 0, 0, 0, 0, 0,156, 0, 0, 0,
+ 0, 0, 0, 0,156, 0, 0, 0, 0, 0, 0, 0,161, 0, 0, 0, 2, 98, 0, 0,
+ 0, 0,161, 0, 0, 0, 2,101, 0, 0, 0, 0,161, 0, 0, 0, 5,110, 97,109,
+101, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0,
+ 0,166, 0, 0, 0, 0, 0, 0, 0,171, 0, 0, 0, 2, 98, 0, 0, 0, 0,171,
+ 0, 0, 0, 2,101, 0, 0, 0, 0,171, 0, 0, 0, 5, 98,111,100,121, 0, 0,
+ 0, 0,176, 0, 0, 0, 0, 0, 0, 0,176, 0, 0, 0, 0, 0, 0, 0,176, 0,
+ 0, 0, 0, 0, 0, 0,180, 0, 0, 0, 2, 98, 0, 0, 0, 0,180, 0, 0, 0,
+ 2,101, 0, 0, 0, 0,180, 0, 0, 0, 5, 98,111,100,121, 0, 0, 0, 0,180,
+ 0, 0, 0, 5,110, 97,109,101, 0, 0, 0, 0,186, 0, 0, 0, 0, 0, 0, 0,
+186, 0, 0, 0, 0, 0, 0, 0,186, 0, 0, 0, 0, 0, 0, 0,186, 0, 0, 0,
+ 0, 0, 0, 0,191, 0, 0, 0, 2, 98, 0, 0, 0, 0,191, 0, 0, 0, 2,101,
+ 0, 0, 0, 0,191, 0, 0, 0, 5,100,101, 99,108, 0, 0, 0, 0,191, 0, 0,
+ 0, 5,107,105,110,100, 0, 0, 0, 0,191, 0, 0, 0, 4, 97,114,103, 0, 0,
+ 0, 0,191, 0, 0, 0, 6, 99,111,110,115,116, 0, 0, 0, 0,196, 0, 0, 0,
+ 0, 0, 0, 0,196, 0, 0, 0, 0, 0, 0, 0,196, 0, 0, 0, 0, 0, 0, 0,
+196, 0, 0, 0, 0, 0, 0, 0,196, 0, 0, 0, 0, 0, 0, 0,196, 0, 0, 0,
+ 0, 0, 0, 0,201, 0, 0, 0, 2, 98, 0, 0, 0, 0,201, 0, 0, 0, 2,101,
+ 0, 0, 0, 0,201, 0, 0, 0, 5,100,101, 99,108, 0, 0, 0, 0,201, 0, 0,
+ 0, 4, 97,114,103, 0, 0, 0, 0,201, 0, 0, 0, 6, 99,111,110,115,116, 0,
+ 0, 0, 0,210, 0, 0, 0, 0, 0, 0, 0,210, 0, 0, 0, 0, 0, 0, 0,210,
+ 0, 0, 0, 0, 0, 0, 0,210, 0, 0, 0, 0, 0, 0, 0,210, 0, 0, 0, 0,
+ 0, 0, 0,215, 0, 0, 0, 2, 98, 0, 0, 0, 0,215, 0, 0, 0, 2,101, 0,
+ 0, 0, 0,215, 0, 0, 0, 5,100,101, 99,108, 0, 0, 0, 0,215, 0, 0, 0,
+ 4, 97,114,103, 0, 0, 0, 0,215, 0, 0, 0, 6, 99,111,110,115,116, 0, 0,
+ 0, 0,224, 0, 0, 0, 0, 0, 0, 0,224, 0, 0, 0, 0, 0, 0, 0,224, 0,
+ 0, 0, 0, 0, 0, 0,224, 0, 0, 0, 0, 0, 0, 0,224, 0, 0, 0, 0, 0,
+ 0, 0,229, 0, 0, 0, 2, 98, 0, 0, 0, 0,229, 0, 0, 0, 2,101, 0, 0,
+ 0, 0,229, 0, 0, 0, 5,110, 97,109,101, 0, 0, 0, 0,229, 0, 0, 0, 5,
+ 98, 97,115,101, 0, 0, 0, 0,229, 0, 0, 0, 5, 98,111,100,121, 0, 0, 0,
+ 0,239, 0, 0, 0, 2, 98, 0, 0, 0, 0,239, 0, 0, 0, 2,101, 0, 0, 0,
+ 0,240, 0, 0, 0, 0, 0, 0, 0,240, 0, 0, 0, 0, 0, 0, 0,245, 0, 0,
+ 0, 0, 0, 0, 0,245, 0, 0, 0, 0, 0, 0, 0,245, 0, 0, 0, 0, 0, 0,
+ 0,245, 0, 0, 0, 0, 0, 0, 0,245, 0, 0, 0, 0, 0, 0, 0,250, 0, 0,
+ 0, 2, 98, 0, 0, 0, 0,250, 0, 0, 0, 2,101, 0, 0, 0, 0,250, 0, 0,
+ 0, 6,116,121,112,101,115, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 0,255,
+ 0, 0, 0, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 2,
+ 98, 0, 0, 0, 1, 4, 0, 0, 0, 2,101, 0, 0, 0, 1, 4, 0, 0, 0, 5,
+100,101, 99,108, 0, 0, 0, 1, 9, 0, 0, 0, 0, 0, 0, 1, 9, 0, 0, 0,
+ 0, 0, 0, 1, 9, 0, 0, 0, 0, 0, 0, 1, 14, 0, 0, 0, 2, 98, 0, 0,
+ 0, 1, 14, 0, 0, 0, 2,101, 0, 0, 0, 1, 14, 0, 0, 0, 5,100,101, 99,
+108, 0, 0, 0, 1, 19, 0, 0, 0, 0, 0, 0, 1, 19, 0, 0, 0, 0, 0, 0,
+ 1, 19, 0, 0, 0, 0, 0, 0, 1, 24, 0, 0, 0, 2, 98, 0, 0, 0, 1, 24,
+ 0, 0, 0, 2,101, 0, 0, 0, 1, 24, 0, 0, 0, 5, 99,111,100,101, 0, 0,
+ 0, 1, 28, 0, 0, 0, 0, 0, 0, 1, 28, 0, 0, 0, 0, 0, 0, 1, 28, 0,
+ 0, 0, 0, 0, 0, 1, 33, 0, 0, 0, 2, 98, 0, 0, 0, 1, 33, 0, 0, 0,
+ 2,101, 0, 0, 0, 1, 33, 0, 0, 0, 5,108,105,110,101, 0, 0, 0, 1, 37,
+ 0, 0, 0, 0, 0, 0, 1, 37, 0, 0, 0, 0, 0, 0, 1, 37, 0, 0, 0, 0,
+ 0, 0, 0, 51, 2, 0, 0, 0, 2,115, 0, 2, 0, 0, 0, 2, 98, 0, 2, 0,
+ 0, 0, 2,101, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 5,
+ 98,111,100,121, 0, 2, 0, 0, 0, 8,115,116,114,102,105,110,100, 0, 2, 0,
+ 0, 0, 41, 94, 37,115, 42,109,111,100,117,108,101, 37,115, 37,115, 42, 40, 91,
+ 95, 37,119, 93, 91, 95, 37,119, 93, 42, 41, 37,115, 42, 40, 37, 98,123,125, 41,
+ 37,115, 42, 0, 2, 0, 0, 0, 11, 95, 99,117,114,114, 95, 99,111,100,101, 0,
+ 2, 0, 0, 0, 7,115,116,114,115,117, 98, 0, 2, 0, 0, 0, 7, 77,111,100,
+117,108,101, 0, 2, 0, 0, 0, 34, 94, 37,115, 42, 35,100,101,102,105,110,101,
+ 37,115, 37,115, 42, 40, 91, 94, 37,115, 93, 42, 41, 91, 94, 10, 93, 42, 10, 37,
+115, 42, 0, 2, 0, 0, 0, 7, 68,101,102,105,110,101, 0, 2, 0, 0, 0, 28,
+ 94, 37,115, 42,101,110,117,109, 91, 94,123, 93, 42, 40, 37, 98,123,125, 41, 37,
+115, 42, 59, 63, 37,115, 42, 0, 2, 0, 0, 0, 10, 69,110,117,109,101,114, 97,
+116,101, 0, 2, 0, 0, 0, 55, 94, 37,115, 42,116,121,112,101,100,101,102, 37,
+115, 37,115, 42,101,110,117,109, 91, 94,123, 93, 42, 40, 37, 98,123,125, 41, 37,
+115, 42, 40, 91, 37,119, 95, 93, 91, 94, 37,115, 93, 42, 41, 37,115, 42, 59, 37,
+115, 42, 0, 2, 0, 0, 0, 8, 84,121,112,101,100,101,102, 0, 2, 0, 0, 0,
+ 5,105,110,116, 32, 0, 2, 0, 0, 0, 5,100,101, 99,108, 0, 2, 0, 0, 0,
+ 5,107,105,110,100, 0, 2, 0, 0, 0, 4, 97,114,103, 0, 2, 0, 0, 0, 6,
+ 99,111,110,115,116, 0, 2, 0, 0, 0, 78, 94, 37,115, 42, 40, 91, 95, 37,119,
+ 93, 91, 95, 37,119, 37,115, 37, 42, 38, 93, 42,111,112,101,114, 97,116,111,114,
+ 41, 37,115, 42, 40, 91, 94, 37,115, 93, 91, 94, 37,115, 93, 42, 41, 37,115, 42,
+ 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,110, 63,115, 63,116, 63,
+ 41, 37,115, 42, 59, 37,115, 42, 0, 2, 0, 0, 0, 9, 79,112,101,114, 97,116,
+111,114, 0, 2, 0, 0, 0, 71, 94, 37,115, 42, 40, 91,126, 95, 37,119, 93, 91,
+ 95, 64, 37,119, 37,115, 37, 42, 38, 93, 42, 91, 95, 37,119, 93, 41, 37,115, 42,
+ 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,110, 63,115, 63,116, 63,
+ 41, 37,115, 42, 61, 63, 37,115, 42, 48, 63, 37,115, 42, 59, 37,115, 42, 0, 2,
+ 0, 0, 0, 43, 94, 37,115, 42, 40, 91, 95, 37,119, 93, 41, 37,115, 42, 40, 37,
+ 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,110, 63,115, 63,116, 63, 41, 37,
+115, 42, 59, 37,115, 42, 0, 2, 0, 0, 0, 9, 70,117,110, 99,116,105,111,110,
+ 0, 2, 0, 0, 0, 64, 94, 37,115, 42, 40, 91,126, 95, 37,119, 93, 91, 95, 64,
+ 37,119, 37,115, 37, 42, 38, 93, 42, 91, 95, 37,119, 93, 41, 37,115, 42, 40, 37,
+ 98, 40, 41, 41, 37,115, 42, 40, 99, 63,111, 63,110, 63,115, 63,116, 63, 41, 37,
+115, 42, 37, 98,123,125, 37,115, 42, 0, 2, 0, 0, 0, 46, 94, 37,115, 42, 40,
+ 91, 95, 37,119, 93, 41, 37,115, 42, 40, 37, 98, 40, 41, 41, 37,115, 42, 40, 99,
+ 63,111, 63,110, 63,115, 63,116, 63, 41, 37,115, 42, 37, 98,123,125, 37,115, 42,
+ 0, 2, 0, 0, 0, 5, 98, 97,115,101, 0, 2, 0, 0, 0, 49, 94, 37,115, 42,
+ 99,108, 97,115,115, 37,115, 42, 40, 91, 95, 37,119, 93, 91, 95, 37,119, 93, 42,
+ 41, 37,115, 42, 40, 46, 45, 41, 37,115, 42, 40, 37, 98,123,125, 41, 37,115, 42,
+ 59, 37,115, 42, 0, 2, 0, 0, 0, 50, 94, 37,115, 42,115,116,114,117, 99,116,
+ 37,115, 42, 40, 91, 95, 37,119, 93, 91, 95, 37,119, 93, 42, 41, 37,115, 42, 40,
+ 46, 45, 41, 37,115, 42, 40, 37, 98,123,125, 41, 37,115, 42, 59, 37,115, 42, 0,
+ 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 66, 94, 37,115, 42,116,121,112,101,100,
+101,102, 37,115, 37,115, 42,115,116,114,117, 99,116, 37,115, 37,115, 42, 91, 95,
+ 37,119, 93, 42, 37,115, 42, 40, 37, 98,123,125, 41, 37,115, 42, 40, 91, 95, 37,
+119, 93, 91, 95, 37,119, 93, 42, 41, 37,115, 42, 59, 37,115, 42, 0, 2, 0, 0,
+ 0, 17, 46, 45, 40, 91, 95, 37,119, 93, 91, 95, 37,119, 93, 42, 41, 36, 0, 2,
+ 0, 0, 0, 6, 67,108, 97,115,115, 0, 2, 0, 0, 0, 6,116,121,112,101,115,
+ 0, 2, 0, 0, 0, 28, 94, 37,115, 42,116,121,112,101,100,101,102, 37,115, 37,
+115, 42, 40, 46, 45, 41, 37,115, 42, 59, 37,115, 42, 0, 2, 0, 0, 0, 40, 94,
+ 37,115, 42, 40, 91, 95, 37,119, 93, 91, 95, 64, 37,115, 37,119, 37,100, 37, 42,
+ 38, 93, 42, 91, 95, 37,119, 37,100, 93, 41, 37,115, 42, 59, 37,115, 42, 0, 2,
+ 0, 0, 0, 9, 86, 97,114,105, 97, 98,108,101, 0, 2, 0, 0, 0, 43, 94, 37,
+115, 42, 40, 91, 95, 37,119, 93, 91, 93, 91, 95, 64, 37,115, 37,119, 37,100, 37,
+ 42, 38, 93, 42, 91, 93, 95, 37,119, 37,100, 93, 41, 37,115, 42, 59, 37,115, 42,
+ 0, 2, 0, 0, 0, 6, 65,114,114, 97,121, 0, 2, 0, 0, 0, 5, 99,111,100,
+101, 0, 2, 0, 0, 0, 11, 94, 37,115, 42, 40, 37, 98, 1, 2, 41, 0, 2, 0,
+ 0, 0, 5, 67,111,100,101, 0, 2, 0, 0, 0, 5,108,105,110,101, 0, 2, 0,
+ 0, 0, 12, 94, 37,115, 42, 37, 36, 40, 46, 45, 10, 41, 0, 2, 0, 0, 0, 9,
+ 86,101,114, 98, 97,116,105,109, 0, 2, 0, 0, 0, 5,103,115,117, 98, 0, 2,
+ 0, 0, 0, 6, 37,115, 37,115, 42, 0, 2, 0, 0, 0, 6,101,114,114,111,114,
+ 0, 2, 0, 0, 0, 13, 35,112, 97,114,115,101, 32,101,114,114,111,114, 0, 2,
+ 0, 0, 0, 6,112, 97,114,115,101, 0, 4, 0, 0, 1, 49, 0, 0, 0, 15, 64,
+ 99,111,110,116, 97,105,110,101,114, 46,108,117, 97, 0, 0, 0, 0, 35, 5, 2,
+ 50, 17, 59, 1, 51, 13, 0, 20, 3, 13, 1, 2, 1, 2, 23, 1, 59, 1, 52, 59,
+ 1, 50, 13, 1, 11, 1, 31, 54, 27, 59, 1, 53, 0, 0, 0, 0, 2, 0, 0, 1,
+ 49, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 1, 49, 0, 0, 0, 2,115, 0,
+ 0, 0, 0, 4, 2, 0, 0, 0, 2,115, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0,
+ 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 8,100,111,112, 97,114,115,101, 0,
+
+};
+
+/* package.lo */
+static char B5[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 13, 64,112, 97, 99,107, 97,
+103,101, 46,108,117, 97, 0, 0, 0, 0,102, 5, 0, 60, 20, 22, 2, 60, 21, 11,
+ 1, 15, 2, 11, 3, 60, 22, 11, 4, 30, 1, 60, 23, 25, 0, 60, 24, 15, 5, 15,
+ 0, 15, 6, 2, 0, 2, 60, 27, 15, 0, 11, 7, 11, 8, 26, 60, 36, 15, 0, 11,
+ 9, 11, 10, 26, 60, 60, 15, 0, 11, 11, 11, 12, 26, 60,100, 15, 0, 11, 13, 11,
+ 14, 26, 60,119, 15, 0, 11, 15, 11, 16, 26, 60,132, 15, 0, 11, 17, 11, 18, 26,
+ 60,146, 11, 20, 25, 19, 60,155, 11, 22, 25, 21, 0, 0, 0, 0, 0, 0, 0, 0,
+ 23, 2, 0, 0, 0, 13, 99,108, 97,115,115, 80, 97, 99,107, 97,103,101, 0, 2,
+ 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 15, 99,108, 97,115,115,
+ 67,111,110,116, 97,105,110,101,114, 0, 2, 0, 0, 0, 5,116,121,112,101, 0,
+ 2, 0, 0, 0, 8,112, 97, 99,107, 97,103,101, 0, 2, 0, 0, 0, 7,115,101,
+116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0,
+ 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0, 0, 0, 27, 0, 0, 0, 13,
+ 64,112, 97, 99,107, 97,103,101, 46,108,117, 97, 0, 0, 0, 0, 61, 6, 1, 60,
+ 28, 15, 0, 11, 1, 13, 0, 18, 3, 42, 2, 0, 1, 60, 29, 7, 1, 50, 27, 60,
+ 31, 13, 0, 13, 1, 16, 20, 0, 11, 5, 11, 5, 2, 0, 3, 60, 32, 13, 1, 7,
+ 1, 37, 23, 1, 60, 33, 60, 30, 13, 0, 13, 1, 16, 54, 36, 60, 34, 0, 0, 0,
+ 0, 2, 0, 0, 0, 27, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 29, 0,
+ 0, 0, 2,105, 0, 0, 0, 0, 6, 2, 0, 0, 0, 6,112,114,105,110,116, 0,
+ 2, 0, 0, 0, 10, 80, 97, 99,107, 97,103,101, 58, 32, 0, 2, 0, 0, 0, 5,
+115,101,108,102, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 2,
+105, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 11,112,114,101,112,114,111, 99,
+101,115,115, 0, 4, 0, 0, 0, 36, 0, 0, 0, 13, 64,112, 97, 99,107, 97,103,
+101, 46,108,117, 97, 0, 0, 0, 1, 83, 7, 1, 60, 38, 13, 0, 11, 1, 11, 2,
+ 13, 0, 18, 1, 42, 26, 60, 40, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 4,
+ 11, 5, 2, 1, 3, 26, 60, 41, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 6,
+ 11, 7, 2, 1, 3, 26, 60, 42, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 8,
+ 11, 9, 2, 1, 3, 26, 60, 43, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 10,
+ 11, 5, 2, 1, 3, 26, 60, 44, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 7,
+ 11, 6, 2, 1, 3, 26, 60, 45, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 9,
+ 11, 8, 2, 1, 3, 26, 60, 46, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 11,
+ 11, 12, 2, 1, 3, 26, 60, 47, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 13,
+ 11, 14, 2, 1, 3, 26, 60, 48, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 15,
+ 11, 14, 2, 1, 3, 26, 60, 49, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 16,
+ 11, 14, 2, 1, 3, 26, 60, 50, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 17,
+ 11, 5, 2, 1, 3, 26, 60, 51, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 18,
+ 11, 19, 2, 1, 3, 26, 60, 52, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 18,
+ 11, 19, 2, 1, 3, 26, 60, 53, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 20,
+ 11, 21, 2, 1, 3, 26, 60, 55, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 22,
+ 11, 7, 2, 1, 3, 26, 60, 56, 13, 0, 11, 1, 15, 3, 13, 0, 18, 1, 11, 23,
+ 11, 9, 2, 1, 3, 26, 60, 57, 0, 0, 0, 0, 1, 0, 0, 0, 36, 0, 0, 0,
+ 5,115,101,108,102, 0, 0, 0, 0, 24, 2, 0, 0, 0, 5,115,101,108,102, 0,
+ 2, 0, 0, 0, 5, 99,111,100,101, 0, 2, 0, 0, 0, 2, 32, 0, 2, 0, 0,
+ 0, 5,103,115,117, 98, 0, 2, 0, 0, 0, 10, 40, 47, 47, 91, 94, 10, 93, 42,
+ 41, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 4, 47, 37, 42, 0, 2, 0, 0,
+ 0, 2, 1, 0, 2, 0, 0, 0, 4, 37, 42, 47, 0, 2, 0, 0, 0, 2, 2, 0,
+ 2, 0, 0, 0, 5, 37, 98, 1, 2, 0, 2, 0, 0, 0, 8, 37,115, 42, 64, 37,
+115, 42, 0, 2, 0, 0, 0, 2, 64, 0, 2, 0, 0, 0, 14, 37,115, 63,105,110,
+108,105,110,101, 40, 37,115, 41, 0, 2, 0, 0, 0, 3, 37, 49, 0, 2, 0, 0,
+ 0, 14, 37,115, 63,101,120,116,101,114,110, 40, 37,115, 41, 0, 2, 0, 0, 0,
+ 15, 37,115, 63,118,105,114,116,117, 97,108, 40, 37,115, 41, 0, 2, 0, 0, 0,
+ 8,112,117, 98,108,105, 99, 58, 0, 2, 0, 0, 0, 18, 40, 91, 94, 37,119, 95,
+ 93, 41,118,111,105,100, 37,115, 42, 37, 42, 0, 2, 0, 0, 0, 13, 37, 49, 95,
+117,115,101,114,100, 97,116, 97, 32, 0, 2, 0, 0, 0, 18, 40, 91, 94, 37,119,
+ 95, 93, 41, 99,104, 97,114, 37,115, 42, 37, 42, 0, 2, 0, 0, 0, 12, 37, 49,
+ 95, 99,115,116,114,105,110,103, 32, 0, 2, 0, 0, 0, 5, 37, 36, 37, 91, 0,
+ 2, 0, 0, 0, 5, 37, 36, 37, 93, 0, 2, 0, 0, 0, 9,112,114,101, 97,109,
+ 98,108,101, 0, 4, 0, 0, 0, 60, 0, 0, 0, 13, 64,112, 97, 99,107, 97,103,
+101, 46,108,117, 97, 0, 0, 0, 1, 79, 5, 1, 60, 61, 15, 0, 11, 1, 2, 0,
+ 1, 60, 62, 15, 0, 11, 2, 13, 0, 18, 4, 42, 11, 5, 42, 2, 0, 1, 60, 63,
+ 15, 0, 11, 6, 15, 7, 42, 11, 8, 42, 15, 9, 2, 1, 0, 42, 11, 10, 42, 2,
+ 0, 1, 60, 64, 15, 0, 11, 11, 2, 0, 1, 60, 66, 15, 12, 18, 13, 44, 52, 54,
+ 60, 67, 15, 0, 11, 14, 2, 0, 1, 60, 68, 15, 0, 11, 15, 13, 0, 18, 4, 42,
+ 11, 16, 42, 2, 0, 1, 60, 69, 15, 0, 11, 17, 13, 0, 18, 4, 42, 11, 18, 42,
+ 2, 0, 1, 60, 70, 15, 0, 11, 5, 2, 0, 1, 50, 2, 60, 71, 60, 73, 15, 12,
+ 18, 19, 52, 46, 60, 74, 15, 0, 11, 20, 2, 0, 1, 60, 75, 15, 0, 11, 21, 2,
+ 0, 1, 60, 76, 15, 0, 11, 22, 13, 0, 18, 4, 42, 11, 23, 42, 2, 0, 1, 60,
+ 77, 15, 0, 11, 24, 2, 0, 1, 50, 2, 60, 78, 60, 79, 15, 0, 11, 25, 2, 0,
+ 1, 60, 80, 7, 1, 50, 23, 60, 82, 13, 0, 13, 1, 16, 20, 27, 2, 0, 1, 60,
+ 83, 13, 1, 7, 1, 37, 23, 1, 60, 84, 60, 81, 13, 0, 13, 1, 16, 54, 32, 60,
+ 85, 15, 0, 11, 5, 2, 0, 1, 60, 86, 15, 0, 11, 28, 2, 0, 1, 60, 87, 13,
+ 0, 20, 29, 2, 0, 1, 60, 88, 15, 0, 11, 5, 2, 0, 1, 60, 89, 15, 0, 11,
+ 30, 2, 0, 1, 60, 90, 15, 0, 11, 31, 2, 0, 1, 60, 91, 15, 0, 11, 32, 2,
+ 0, 1, 60, 92, 15, 33, 15, 34, 11, 35, 2, 0, 2, 60, 93, 15, 33, 15, 36, 11,
+ 37, 2, 0, 2, 60, 94, 15, 38, 11, 39, 2, 0, 1, 60, 95, 15, 38, 11, 5, 2,
+ 0, 1, 60, 96, 0, 0, 0, 0, 2, 0, 0, 0, 60, 0, 0, 0, 5,115,101,108,
+102, 0, 0, 0, 0, 80, 0, 0, 0, 2,105, 0, 0, 0, 0, 40, 2, 0, 0, 0,
+ 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 4, 47, 42, 10, 0, 2, 0, 0,
+ 0, 17, 42, 42, 32, 76,117, 97, 32, 98,105,110,100,105,110,103, 58, 32, 0, 2,
+ 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2,
+ 0, 0, 0, 2, 10, 0, 2, 0, 0, 0, 31, 42, 42, 32, 71,101,110,101,114, 97,
+116,101,100, 32, 97,117,116,111,109, 97,116,105, 99, 97,108,108,121, 32, 98,121,
+ 32, 0, 2, 0, 0, 0, 14, 84, 79, 76, 85, 65, 95, 86, 69, 82, 83, 73, 79, 78,
+ 0, 2, 0, 0, 0, 5, 32,111,110, 32, 0, 2, 0, 0, 0, 5,100, 97,116,101,
+ 0, 2, 0, 0, 0, 3, 46, 10, 0, 2, 0, 0, 0, 5, 42, 47, 10, 10, 0, 2,
+ 0, 0, 0, 6,102,108, 97,103,115, 0, 2, 0, 0, 0, 2,104, 0, 2, 0, 0,
+ 0, 24, 47, 42, 32, 69,120,112,111,114,116,101,100, 32,102,117,110, 99,116,105,
+111,110, 32, 42, 47, 0, 2, 0, 0, 0, 12,105,110,116, 32, 32,116,111,108,117,
+ 97, 95, 0, 2, 0, 0, 0, 14, 95,111,112,101,110, 32, 40,118,111,105,100, 41,
+ 59, 0, 2, 0, 0, 0, 12,118,111,105,100, 32,116,111,108,117, 97, 95, 0, 2,
+ 0, 0, 0, 15, 95, 99,108,111,115,101, 32, 40,118,111,105,100, 41, 59, 0, 2,
+ 0, 0, 0, 2, 97, 0, 2, 0, 0, 0, 45, 47, 42, 32, 65,117,116,111,109, 97,
+116,105, 99, 32,105,110,105,116,105, 97,108,105,122, 97,116,105,111,110, 32,102,
+111,114, 32, 67, 43, 43, 32, 99,111,100,101, 32, 42, 47, 10, 0, 2, 0, 0, 0,
+ 20, 35,105,102,100,101,102, 32, 95, 95, 99,112,108,117,115,112,108,117,115, 10,
+ 0, 2, 0, 0, 0, 26,115,116, 97,116,105, 99, 32,105,110,116, 32,100,117,109,
+109,121, 32, 61, 32,116,111,108,117, 97, 95, 0, 2, 0, 0, 0, 10, 95,111,112,
+101,110, 32, 40, 41, 59, 0, 2, 0, 0, 0, 9, 35,101,110,100,105,102, 10, 10,
+ 0, 2, 0, 0, 0, 21, 35,105,110, 99,108,117,100,101, 32, 34,116,111,108,117,
+ 97, 46,104, 34, 10, 10, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 9,112,
+114,101, 97,109, 98,108,101, 0, 2, 0, 0, 0, 20, 47, 42, 32,116, 97,103, 32,
+118, 97,114,105, 97, 98,108,101,115, 32, 42, 47, 0, 2, 0, 0, 0, 8,100,101,
+ 99,108,116, 97,103, 0, 2, 0, 0, 0, 51, 47, 42, 32,102,117,110, 99,116,105,
+111,110, 32,116,111, 32,114,101,103,105,115,116,101,114, 32,116,121,112,101, 32,
+ 97,110,100, 32,105,110,105,116,105, 97,108,105,122,101, 32,116, 97,103, 32, 42,
+ 47, 0, 2, 0, 0, 0, 35,115,116, 97,116,105, 99, 32,118,111,105,100, 32,116,
+111,108,117, 97, 73, 95,105,110,105,116, 95,116, 97,103, 32, 40,118,111,105,100,
+ 41, 0, 2, 0, 0, 0, 2,123, 0, 2, 0, 0, 0, 8,102,111,114,101, 97, 99,
+104, 0, 2, 0, 0, 0, 10, 95,117,115,101,114,116,121,112,101, 0, 4, 0, 0,
+ 0, 92, 0, 0, 0, 13, 64,112, 97, 99,107, 97,103,101, 46,108,117, 97, 0, 0,
+ 0, 0, 16, 6, 2, 60, 92, 15, 2, 11, 3, 13, 1, 11, 4, 2, 0, 3, 0, 0,
+ 0, 0, 2, 0, 0, 0, 92, 0, 0, 0, 2,110, 0, 0, 0, 0, 92, 0, 0, 0,
+ 2,118, 0, 0, 0, 0, 5, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 2,118,
+ 0, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 18, 32,116,
+111,108,117, 97, 95,117,115,101,114,116,121,112,101, 40, 34, 0, 2, 0, 0, 0,
+ 4, 34, 41, 59, 0, 2, 0, 0, 0, 10, 95,116, 97,103,110, 97,109,101,115, 0,
+ 4, 0, 0, 0, 93, 0, 0, 0, 13, 64,112, 97, 99,107, 97,103,101, 46,108,117,
+ 97, 0, 0, 0, 0, 21, 7, 2, 60, 93, 15, 2, 11, 3, 13, 1, 11, 4, 13, 0,
+ 42, 11, 5, 2, 0, 4, 0, 0, 0, 0, 2, 0, 0, 0, 93, 0, 0, 0, 2,110,
+ 0, 0, 0, 0, 93, 0, 0, 0, 2,118, 0, 0, 0, 0, 6, 2, 0, 0, 0, 2,
+110, 0, 2, 0, 0, 0, 2,118, 0, 2, 0, 0, 0, 7,111,117,116,112,117,116,
+ 0, 2, 0, 0, 0, 16, 32,116,111,108,117, 97, 95,115,101,116,116, 97,103, 40,
+ 34, 0, 2, 0, 0, 0, 4, 34, 44, 38, 0, 2, 0, 0, 0, 3, 41, 59, 0, 2,
+ 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 2,125, 0, 2, 0,
+ 0, 0, 9,114,101,103,105,115,116,101,114, 0, 4, 0, 0, 0,100, 0, 0, 0,
+ 13, 64,112, 97, 99,107, 97,103,101, 46,108,117, 97, 0, 0, 0, 0,132, 4, 1,
+ 60,101, 15, 0, 11, 1, 2, 0, 1, 60,102, 15, 0, 11, 2, 13, 0, 18, 4, 42,
+ 11, 5, 42, 2, 0, 1, 60,103, 15, 0, 11, 6, 2, 0, 1, 60,104, 15, 0, 11,
+ 7, 2, 0, 1, 60,105, 15, 0, 11, 8, 2, 0, 1, 60,106, 15, 0, 11, 9, 2,
+ 0, 1, 60,107, 7, 1, 50, 23, 60,109, 13, 0, 13, 1, 16, 20, 11, 2, 0, 1,
+ 60,110, 13, 1, 7, 1, 37, 23, 1, 60,111, 60,108, 13, 0, 13, 1, 16, 54, 32,
+ 60,112, 15, 0, 11, 12, 2, 0, 1, 60,113, 15, 0, 11, 13, 2, 0, 1, 60,114,
+ 15, 0, 11, 14, 2, 0, 1, 60,115, 0, 0, 0, 0, 2, 0, 0, 0,100, 0, 0,
+ 0, 5,115,101,108,102, 0, 0, 0, 0,107, 0, 0, 0, 2,105, 0, 0, 0, 0,
+ 15, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 20, 47, 42,
+ 32, 79,112,101,110, 32,102,117,110, 99,116,105,111,110, 32, 42, 47, 0, 2, 0,
+ 0, 0, 11,105,110,116, 32,116,111,108,117, 97, 95, 0, 2, 0, 0, 0, 5,115,
+101,108,102, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 13, 95,
+111,112,101,110, 32, 40,118,111,105,100, 41, 0, 2, 0, 0, 0, 2,123, 0, 2,
+ 0, 0, 0, 15, 32,116,111,108,117, 97, 95,111,112,101,110, 40, 41, 59, 0, 2,
+ 0, 0, 0, 19, 32,108,117, 97, 95, 98,101,103,105,110, 98,108,111, 99,107, 40,
+ 41, 59, 0, 2, 0, 0, 0, 20, 32,116,111,108,117, 97, 73, 95,105,110,105,116,
+ 95,116, 97,103, 40, 41, 59, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 9,
+114,101,103,105,115,116,101,114, 0, 2, 0, 0, 0, 17, 32,108,117, 97, 95,101,
+110,100, 98,108,111, 99,107, 40, 41, 59, 0, 2, 0, 0, 0, 11, 32,114,101,116,
+117,114,110, 32, 49, 59, 0, 2, 0, 0, 0, 2,125, 0, 2, 0, 0, 0, 11,117,
+110,114,101,103,105,115,116,101,114, 0, 4, 0, 0, 0,119, 0, 0, 0, 13, 64,
+112, 97, 99,107, 97,103,101, 46,108,117, 97, 0, 0, 0, 0, 87, 4, 1, 60,120,
+ 15, 0, 11, 1, 2, 0, 1, 60,121, 15, 0, 11, 2, 13, 0, 18, 4, 42, 11, 5,
+ 42, 2, 0, 1, 60,122, 15, 0, 11, 6, 2, 0, 1, 60,123, 7, 1, 50, 23, 60,
+125, 13, 0, 13, 1, 16, 20, 8, 2, 0, 1, 60,126, 13, 1, 7, 1, 37, 23, 1,
+ 60,127, 60,124, 13, 0, 13, 1, 16, 54, 32, 60,128, 15, 0, 11, 9, 2, 0, 1,
+ 60,129, 0, 0, 0, 0, 2, 0, 0, 0,119, 0, 0, 0, 5,115,101,108,102, 0,
+ 0, 0, 0,123, 0, 0, 0, 2,105, 0, 0, 0, 0, 10, 2, 0, 0, 0, 7,111,
+117,116,112,117,116, 0, 2, 0, 0, 0, 21, 47, 42, 32, 67,108,111,115,101, 32,
+102,117,110, 99,116,105,111,110, 32, 42, 47, 0, 2, 0, 0, 0, 12,118,111,105,
+100, 32,116,111,108,117, 97, 95, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2,
+ 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 14, 95, 99,108,111,115,101,
+ 32, 40,118,111,105,100, 41, 0, 2, 0, 0, 0, 2,123, 0, 2, 0, 0, 0, 2,
+105, 0, 2, 0, 0, 0, 11,117,110,114,101,103,105,115,116,101,114, 0, 2, 0,
+ 0, 0, 2,125, 0, 2, 0, 0, 0, 7,104,101, 97,100,101,114, 0, 4, 0, 0,
+ 0,132, 0, 0, 0, 13, 64,112, 97, 99,107, 97,103,101, 46,108,117, 97, 0, 0,
+ 0, 0,127, 4, 1, 60,133, 15, 0, 11, 1, 2, 0, 1, 15, 0, 11, 2, 13, 0,
+ 18, 4, 42, 11, 5, 42, 2, 0, 1, 60,134, 15, 0, 11, 6, 15, 7, 42, 11, 8,
+ 42, 15, 9, 2, 1, 0, 42, 11, 10, 42, 2, 0, 1, 60,135, 15, 0, 11, 11, 2,
+ 0, 1, 60,137, 15, 12, 18, 13, 44, 52, 54, 60,138, 15, 0, 11, 14, 2, 0, 1,
+ 60,139, 15, 0, 11, 15, 13, 0, 18, 4, 42, 11, 16, 42, 2, 0, 1, 60,140, 15,
+ 0, 11, 17, 13, 0, 18, 4, 42, 11, 18, 42, 2, 0, 1, 60,141, 15, 0, 11, 5,
+ 2, 0, 1, 50, 2, 60,142, 60,143, 0, 0, 0, 0, 1, 0, 0, 0,132, 0, 0,
+ 0, 5,115,101,108,102, 0, 0, 0, 0, 19, 2, 0, 0, 0, 7,111,117,116,112,
+117,116, 0, 2, 0, 0, 0, 4, 47, 42, 10, 0, 2, 0, 0, 0, 17, 42, 42, 32,
+ 76,117, 97, 32, 98,105,110,100,105,110,103, 58, 32, 0, 2, 0, 0, 0, 5,115,
+101,108,102, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 2, 10,
+ 0, 2, 0, 0, 0, 31, 42, 42, 32, 71,101,110,101,114, 97,116,101,100, 32, 97,
+117,116,111,109, 97,116,105, 99, 97,108,108,121, 32, 98,121, 32, 0, 2, 0, 0,
+ 0, 14, 84, 79, 76, 85, 65, 95, 86, 69, 82, 83, 73, 79, 78, 0, 2, 0, 0, 0,
+ 5, 32,111,110, 32, 0, 2, 0, 0, 0, 5,100, 97,116,101, 0, 2, 0, 0, 0,
+ 3, 46, 10, 0, 2, 0, 0, 0, 5, 42, 47, 10, 10, 0, 2, 0, 0, 0, 6,102,
+108, 97,103,115, 0, 2, 0, 0, 0, 2,104, 0, 2, 0, 0, 0, 24, 47, 42, 32,
+ 69,120,112,111,114,116,101,100, 32,102,117,110, 99,116,105,111,110, 32, 42, 47,
+ 0, 2, 0, 0, 0, 12,105,110,116, 32, 32,116,111,108,117, 97, 95, 0, 2, 0,
+ 0, 0, 14, 95,111,112,101,110, 32, 40,118,111,105,100, 41, 59, 0, 2, 0, 0,
+ 0, 12,118,111,105,100, 32,116,111,108,117, 97, 95, 0, 2, 0, 0, 0, 15, 95,
+ 99,108,111,115,101, 32, 40,118,111,105,100, 41, 59, 0, 2, 0, 0, 0, 9, 95,
+ 80, 97, 99,107, 97,103,101, 0, 4, 0, 0, 0,146, 0, 0, 0, 13, 64,112, 97,
+ 99,107, 97,103,101, 46,108,117, 97, 0, 0, 0, 0, 31, 4, 1, 60,147, 13, 0,
+ 11, 1, 15, 2, 26, 60,148, 15, 3, 13, 0, 15, 4, 2, 0, 2, 60,149, 13, 0,
+ 1, 1, 60,150, 0, 0, 0, 0, 1, 0, 0, 0,146, 0, 0, 0, 2,116, 0, 0,
+ 0, 0, 5, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101,
+ 0, 2, 0, 0, 0, 13, 99,108, 97,115,115, 80, 97, 99,107, 97,103,101, 0, 2,
+ 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117,
+ 97, 95,116, 97,103, 0, 2, 0, 0, 0, 8, 80, 97, 99,107, 97,103,101, 0, 4,
+ 0, 0, 0,155, 0, 0, 0, 13, 64,112, 97, 99,107, 97,103,101, 46,108,117, 97,
+ 0, 0, 0, 0,114, 10, 1, 60,157, 15, 2, 11, 3, 2, 1, 1, 60,159, 4, 0,
+ 60,161, 15, 5, 13, 1, 11, 6, 11, 7, 60,169, 2, 2, 3, 23, 2, 23, 1, 60,
+170, 13, 2, 7, 0, 32, 56, 28, 60,172, 15, 9, 15, 10, 22, 2, 11, 0, 13, 0,
+ 11, 1, 13, 1, 30, 1, 2, 1, 1, 2, 1, 1, 60,173, 15, 11, 13, 3, 2, 0,
+ 1, 60,174, 13, 3, 20, 12, 2, 0, 1, 60,175, 13, 3, 20, 13, 13, 3, 18, 1,
+ 2, 0, 2, 60,176, 15, 14, 2, 0, 0, 60,177, 13, 3, 1, 4, 60,178, 0, 0,
+ 0, 0, 4, 0, 0, 0,155, 0, 0, 0, 5,110, 97,109,101, 0, 0, 0, 0,157,
+ 0, 0, 0, 5, 99,111,100,101, 0, 0, 0, 0,159, 0, 0, 0, 7,110,115,117,
+ 98,115,116, 0, 0, 0, 0,172, 0, 0, 0, 2,116, 0, 0, 0, 0, 15, 2, 0,
+ 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 5, 99,111,100,101, 0, 2, 0,
+ 0, 0, 5,114,101, 97,100, 0, 2, 0, 0, 0, 3, 46, 42, 0, 2, 0, 0, 0,
+ 7,110,115,117, 98,115,116, 0, 2, 0, 0, 0, 5,103,115,117, 98, 0, 2, 0,
+ 0, 0, 13, 37, 36, 60, 40, 46, 45, 41, 62, 37,115, 42, 10, 0, 4, 0, 0, 0,
+161, 0, 0, 0, 13, 64,112, 97, 99,107, 97,103,101, 46,108,117, 97, 0, 0, 0,
+ 0, 71, 6, 1, 60,162, 15, 3, 13, 0, 11, 4, 2, 2, 2, 60,163, 13, 1, 44,
+ 52, 20, 60,164, 15, 5, 11, 6, 13, 2, 42, 11, 7, 42, 13, 0, 42, 2, 0, 1,
+ 50, 2, 60,165, 60,166, 15, 9, 13, 1, 11, 10, 2, 1, 2, 60,167, 15, 11, 13,
+ 1, 2, 0, 1, 60,168, 13, 3, 1, 4, 60,169, 0, 0, 0, 0, 4, 0, 0, 0,
+161, 0, 0, 0, 3,102,110, 0, 0, 0, 0,162, 0, 0, 0, 3,102,112, 0, 0,
+ 0, 0,162, 0, 0, 0, 4,109,115,103, 0, 0, 0, 0,166, 0, 0, 0, 2,115,
+ 0, 0, 0, 0, 12, 2, 0, 0, 0, 3,102,110, 0, 2, 0, 0, 0, 3,102,112,
+ 0, 2, 0, 0, 0, 4,109,115,103, 0, 2, 0, 0, 0, 9,111,112,101,110,102,
+105,108,101, 0, 2, 0, 0, 0, 2,114, 0, 2, 0, 0, 0, 6,101,114,114,111,
+114, 0, 2, 0, 0, 0, 2, 35, 0, 2, 0, 0, 0, 3, 58, 32, 0, 2, 0, 0,
+ 0, 2,115, 0, 2, 0, 0, 0, 5,114,101, 97,100, 0, 2, 0, 0, 0, 3, 46,
+ 42, 0, 2, 0, 0, 0, 10, 99,108,111,115,101,102,105,108,101, 0, 2, 0, 0,
+ 0, 2,116, 0, 2, 0, 0, 0, 9, 95, 80, 97, 99,107, 97,103,101, 0, 2, 0,
+ 0, 0, 11, 95, 67,111,110,116, 97,105,110,101,114, 0, 2, 0, 0, 0, 5,112,
+117,115,104, 0, 2, 0, 0, 0, 11,112,114,101,112,114,111, 99,101,115,115, 0,
+ 2, 0, 0, 0, 6,112, 97,114,115,101, 0, 2, 0, 0, 0, 4,112,111,112, 0,
+
+};
+
+/* module.lo */
+static char B6[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 12, 64,109,111,100,117,108,
+101, 46,108,117, 97, 0, 0, 0, 0, 75, 5, 0, 60, 19, 22, 2, 60, 20, 11, 1,
+ 15, 2, 11, 3, 60, 21, 11, 4, 30, 1, 60, 22, 25, 0, 60, 23, 15, 5, 15, 0,
+ 15, 6, 2, 0, 2, 60, 26, 15, 0, 11, 7, 11, 8, 26, 60, 36, 15, 0, 11, 9,
+ 11, 10, 26, 60, 41, 15, 0, 11, 11, 11, 12, 26, 60, 53, 11, 14, 25, 13, 60, 62,
+ 11, 16, 25, 15, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 0, 0, 0, 12, 99,108,
+ 97,115,115, 77,111,100,117,108,101, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101,
+ 0, 2, 0, 0, 0, 15, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114,
+ 0, 2, 0, 0, 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 7,109,111,100,117,
+108,101, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,
+116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 9,114,101,103,105,115,
+116,101,114, 0, 4, 0, 0, 0, 26, 0, 0, 0, 12, 64,109,111,100,117,108,101,
+ 46,108,117, 97, 0, 0, 0, 0, 60, 4, 1, 60, 27, 15, 0, 11, 1, 13, 0, 18,
+ 3, 42, 11, 4, 42, 2, 0, 1, 60, 28, 7, 1, 50, 23, 60, 30, 13, 0, 13, 1,
+ 16, 20, 6, 2, 0, 1, 60, 31, 13, 1, 7, 1, 37, 23, 1, 60, 32, 60, 29, 13,
+ 0, 13, 1, 16, 54, 32, 60, 33, 0, 0, 0, 0, 2, 0, 0, 0, 26, 0, 0, 0,
+ 5,115,101,108,102, 0, 0, 0, 0, 28, 0, 0, 0, 2,105, 0, 0, 0, 0, 7,
+ 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 16, 32,116,111,
+108,117, 97, 95,109,111,100,117,108,101, 40, 34, 0, 2, 0, 0, 0, 5,115,101,
+108,102, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 4, 34, 41,
+ 59, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 9,114,101,103,105,115,116,
+101,114, 0, 2, 0, 0, 0, 11,117,110,114,101,103,105,115,116,101,114, 0, 4,
+ 0, 0, 0, 36, 0, 0, 0, 12, 64,109,111,100,117,108,101, 46,108,117, 97, 0,
+ 0, 0, 0, 22, 4, 1, 60, 37, 15, 0, 11, 1, 13, 0, 18, 3, 42, 11, 4, 42,
+ 2, 0, 1, 60, 38, 0, 0, 0, 0, 1, 0, 0, 0, 36, 0, 0, 0, 5,115,101,
+108,102, 0, 0, 0, 0, 5, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 2,
+ 0, 0, 0, 32, 32,108,117, 97, 95,112,117,115,104,110,105,108, 40, 41, 59, 32,
+108,117, 97, 95,115,101,116,103,108,111, 98, 97,108, 40, 34, 0, 2, 0, 0, 0,
+ 5,115,101,108,102, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0,
+ 4, 34, 41, 59, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0, 0, 0,
+ 41, 0, 0, 0, 12, 64,109,111,100,117,108,101, 46,108,117, 97, 0, 0, 0, 0,
+ 97, 8, 3, 60, 42, 15, 2, 13, 1, 11, 3, 42, 2, 0, 1, 60, 43, 15, 2, 13,
+ 1, 11, 4, 42, 13, 0, 18, 6, 42, 11, 7, 42, 2, 0, 1, 60, 44, 7, 1, 50,
+ 30, 60, 46, 13, 0, 13, 3, 16, 20, 2, 13, 1, 11, 9, 42, 11, 10, 2, 0, 3,
+ 60, 47, 13, 3, 7, 1, 37, 23, 3, 60, 48, 60, 45, 13, 0, 13, 3, 16, 54, 39,
+ 60, 49, 15, 2, 13, 1, 11, 11, 42, 13, 2, 42, 2, 0, 1, 60, 50, 0, 0, 0,
+ 0, 4, 0, 0, 0, 41, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 41, 0,
+ 0, 0, 6,105,100,101,110,116, 0, 0, 0, 0, 41, 0, 0, 0, 6, 99,108,111,
+115,101, 0, 0, 0, 0, 44, 0, 0, 0, 2,105, 0, 0, 0, 0, 12, 2, 0, 0,
+ 0, 6,105,100,101,110,116, 0, 2, 0, 0, 0, 6, 99,108,111,115,101, 0, 2,
+ 0, 0, 0, 6,112,114,105,110,116, 0, 2, 0, 0, 0, 8, 77,111,100,117,108,
+101,123, 0, 2, 0, 0, 0, 10, 32,110, 97,109,101, 32, 61, 32, 39, 0, 2, 0,
+ 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0,
+ 0, 0, 3, 39, 59, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 2, 32, 0,
+ 2, 0, 0, 0, 2, 44, 0, 2, 0, 0, 0, 2,125, 0, 2, 0, 0, 0, 8, 95,
+ 77,111,100,117,108,101, 0, 4, 0, 0, 0, 53, 0, 0, 0, 12, 64,109,111,100,
+117,108,101, 46,108,117, 97, 0, 0, 0, 0, 40, 4, 1, 60, 54, 13, 0, 11, 1,
+ 15, 2, 26, 60, 55, 15, 3, 13, 0, 15, 4, 2, 0, 2, 60, 56, 15, 5, 13, 0,
+ 2, 0, 1, 60, 57, 13, 0, 1, 1, 60, 58, 0, 0, 0, 0, 1, 0, 0, 0, 53,
+ 0, 0, 0, 2,116, 0, 0, 0, 0, 6, 2, 0, 0, 0, 2,116, 0, 2, 0, 0,
+ 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 12, 99,108, 97,115,115, 77,111,
+100,117,108,101, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0,
+ 0, 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 7, 97,112,112,
+101,110,100, 0, 2, 0, 0, 0, 7, 77,111,100,117,108,101, 0, 4, 0, 0, 0,
+ 62, 0, 0, 0, 12, 64,109,111,100,117,108,101, 46,108,117, 97, 0, 0, 0, 0,
+ 75, 10, 2, 60, 63, 15, 3, 15, 4, 22, 1, 11, 5, 13, 0, 30, 0, 2, 1, 1,
+ 2, 1, 1, 60, 64, 15, 6, 13, 2, 2, 0, 1, 60, 65, 13, 2, 20, 7, 15, 8,
+ 13, 1, 7, 2, 15, 9, 13, 1, 2, 1, 1, 7, 1, 38, 2, 1, 3, 2, 0, 2,
+ 60, 66, 15, 10, 2, 0, 0, 60, 67, 13, 2, 1, 3, 60, 68, 0, 0, 0, 0, 3,
+ 0, 0, 0, 62, 0, 0, 0, 2,110, 0, 0, 0, 0, 62, 0, 0, 0, 2, 98, 0,
+ 0, 0, 0, 63, 0, 0, 0, 2,116, 0, 0, 0, 0, 11, 2, 0, 0, 0, 2,110,
+ 0, 2, 0, 0, 0, 2, 98, 0, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 8,
+ 95, 77,111,100,117,108,101, 0, 2, 0, 0, 0, 11, 95, 67,111,110,116, 97,105,
+110,101,114, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 5,112,
+117,115,104, 0, 2, 0, 0, 0, 6,112, 97,114,115,101, 0, 2, 0, 0, 0, 7,
+115,116,114,115,117, 98, 0, 2, 0, 0, 0, 7,115,116,114,108,101,110, 0, 2,
+ 0, 0, 0, 4,112,111,112, 0,
+};
+
+/* class.lo */
+static char B7[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 11, 64, 99,108, 97,115,115,
+ 46,108,117, 97, 0, 0, 0, 0, 96, 9, 0, 60, 20, 22, 4, 60, 21, 11, 1, 15,
+ 2, 11, 3, 60, 22, 11, 4, 11, 5, 60, 23, 11, 6, 11, 7, 60, 24, 11, 6, 30,
+ 3, 60, 25, 25, 0, 60, 26, 15, 8, 15, 0, 15, 9, 2, 0, 2, 60, 30, 15, 0,
+ 11, 10, 11, 11, 26, 60, 40, 15, 0, 11, 12, 11, 13, 26, 60, 45, 15, 0, 11, 14,
+ 11, 15, 26, 60, 57, 15, 0, 11, 16, 11, 17, 26, 60, 70, 11, 19, 25, 18, 60, 79,
+ 11, 21, 25, 20, 0, 0, 0, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 11, 99,108,
+ 97,115,115, 67,108, 97,115,115, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0,
+ 2, 0, 0, 0, 15, 99,108, 97,115,115, 67,111,110,116, 97,105,110,101,114, 0,
+ 2, 0, 0, 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 6, 99,108, 97,115,115,
+ 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0,
+ 0, 5, 98, 97,115,101, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2,
+ 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 9,114,
+101,103,105,115,116,101,114, 0, 4, 0, 0, 0, 30, 0, 0, 0, 11, 64, 99,108,
+ 97,115,115, 46,108,117, 97, 0, 0, 0, 0, 68, 4, 1, 60, 31, 15, 0, 11, 1,
+ 13, 0, 18, 3, 42, 11, 4, 42, 13, 0, 18, 5, 42, 11, 6, 42, 2, 0, 1, 60,
+ 32, 7, 1, 50, 23, 60, 34, 13, 0, 13, 1, 16, 20, 8, 2, 0, 1, 60, 35, 13,
+ 1, 7, 1, 37, 23, 1, 60, 36, 60, 33, 13, 0, 13, 1, 16, 54, 32, 60, 37, 0,
+ 0, 0, 0, 2, 0, 0, 0, 30, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0,
+ 32, 0, 0, 0, 2,105, 0, 0, 0, 0, 9, 2, 0, 0, 0, 7,111,117,116,112,
+117,116, 0, 2, 0, 0, 0, 16, 32,116,111,108,117, 97, 95, 99, 99,108, 97,115,
+115, 40, 34, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,110,
+ 97,109,101, 0, 2, 0, 0, 0, 4, 34, 44, 34, 0, 2, 0, 0, 0, 5, 98, 97,
+115,101, 0, 2, 0, 0, 0, 4, 34, 41, 59, 0, 2, 0, 0, 0, 2,105, 0, 2,
+ 0, 0, 0, 9,114,101,103,105,115,116,101,114, 0, 2, 0, 0, 0, 11,117,110,
+114,101,103,105,115,116,101,114, 0, 4, 0, 0, 0, 40, 0, 0, 0, 11, 64, 99,
+108, 97,115,115, 46,108,117, 97, 0, 0, 0, 0, 22, 4, 1, 60, 41, 15, 0, 11,
+ 1, 13, 0, 18, 3, 42, 11, 4, 42, 2, 0, 1, 60, 42, 0, 0, 0, 0, 1, 0,
+ 0, 0, 40, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 5, 2, 0, 0, 0,
+ 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 32, 32,108,117, 97, 95,112,117,
+115,104,110,105,108, 40, 41, 59, 32,108,117, 97, 95,115,101,116,103,108,111, 98,
+ 97,108, 40, 34, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,
+110, 97,109,101, 0, 2, 0, 0, 0, 4, 34, 41, 59, 0, 2, 0, 0, 0, 8,100,
+101, 99,108,116, 97,103, 0, 4, 0, 0, 0, 45, 0, 0, 0, 11, 64, 99,108, 97,
+115,115, 46,108,117, 97, 0, 0, 0, 0,128, 8, 1, 60, 46, 13, 0, 11, 1, 13,
+ 0, 11, 2, 15, 3, 13, 0, 18, 4, 2, 2, 1, 27, 1, 27, 2, 5, 4, 15, 5,
+ 13, 0, 18, 1, 13, 0, 18, 2, 2, 0, 2, 60, 47, 13, 0, 11, 6, 13, 0, 11,
+ 7, 15, 3, 13, 0, 18, 4, 11, 8, 2, 2, 2, 27, 1, 27, 2, 5, 4, 60, 48,
+ 15, 3, 13, 0, 18, 10, 2, 2, 1, 15, 5, 13, 1, 13, 2, 2, 0, 2, 60, 49,
+ 7, 1, 50, 23, 60, 51, 13, 0, 13, 3, 16, 20, 5, 2, 0, 1, 60, 52, 13, 3,
+ 7, 1, 37, 23, 3, 60, 53, 60, 50, 13, 0, 13, 3, 16, 54, 32, 60, 54, 0, 0,
+ 0, 0, 4, 0, 0, 0, 45, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 48,
+ 0, 0, 0, 5,116,121,112,101, 0, 0, 0, 0, 48, 0, 0, 0, 4,116, 97,103,
+ 0, 0, 0, 0, 49, 0, 0, 0, 2,105, 0, 0, 0, 0, 12, 2, 0, 0, 0, 5,
+115,101,108,102, 0, 2, 0, 0, 0, 6,105,116,121,112,101, 0, 2, 0, 0, 0,
+ 4,116, 97,103, 0, 2, 0, 0, 0, 7,116, 97,103,118, 97,114, 0, 2, 0, 0,
+ 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 8,100,101, 99,108,116, 97,103, 0,
+ 2, 0, 0, 0, 7, 99,105,116,121,112,101, 0, 2, 0, 0, 0, 5, 99,116, 97,
+103, 0, 2, 0, 0, 0, 6, 99,111,110,115,116, 0, 2, 0, 0, 0, 5,116,121,
+112,101, 0, 2, 0, 0, 0, 5, 98, 97,115,101, 0, 2, 0, 0, 0, 2,105, 0,
+ 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0, 0, 0, 57, 0, 0, 0, 11,
+ 64, 99,108, 97,115,115, 46,108,117, 97, 0, 0, 0, 0,117, 8, 3, 60, 58, 15,
+ 2, 13, 1, 11, 3, 42, 2, 0, 1, 60, 59, 15, 2, 13, 1, 11, 4, 42, 13, 0,
+ 18, 6, 42, 11, 7, 42, 2, 0, 1, 60, 60, 15, 2, 13, 1, 11, 8, 42, 13, 0,
+ 18, 9, 42, 11, 10, 42, 2, 0, 1, 60, 61, 7, 1, 50, 30, 60, 63, 13, 0, 13,
+ 3, 16, 20, 2, 13, 1, 11, 12, 42, 11, 13, 2, 0, 3, 60, 64, 13, 3, 7, 1,
+ 37, 23, 3, 60, 65, 60, 62, 13, 0, 13, 3, 16, 54, 39, 60, 66, 15, 2, 13, 1,
+ 11, 14, 42, 13, 2, 42, 2, 0, 1, 60, 67, 0, 0, 0, 0, 4, 0, 0, 0, 57,
+ 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 57, 0, 0, 0, 6,105,100,101,
+110,116, 0, 0, 0, 0, 57, 0, 0, 0, 6, 99,108,111,115,101, 0, 0, 0, 0,
+ 61, 0, 0, 0, 2,105, 0, 0, 0, 0, 15, 2, 0, 0, 0, 6,105,100,101,110,
+116, 0, 2, 0, 0, 0, 6, 99,108,111,115,101, 0, 2, 0, 0, 0, 6,112,114,
+105,110,116, 0, 2, 0, 0, 0, 7, 67,108, 97,115,115,123, 0, 2, 0, 0, 0,
+ 10, 32,110, 97,109,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,115,101,108,102,
+ 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 3, 39, 44, 0, 2,
+ 0, 0, 0, 10, 32, 98, 97,115,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5, 98,
+ 97,115,101, 0, 2, 0, 0, 0, 3, 39, 59, 0, 2, 0, 0, 0, 2,105, 0, 2,
+ 0, 0, 0, 2, 32, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0, 0, 0, 2,125, 0,
+ 2, 0, 0, 0, 7, 95, 67,108, 97,115,115, 0, 4, 0, 0, 0, 70, 0, 0, 0,
+ 11, 64, 99,108, 97,115,115, 46,108,117, 97, 0, 0, 0, 0, 40, 4, 1, 60, 71,
+ 13, 0, 11, 1, 15, 2, 26, 60, 72, 15, 3, 13, 0, 15, 4, 2, 0, 2, 60, 73,
+ 15, 5, 13, 0, 2, 0, 1, 60, 74, 13, 0, 1, 1, 60, 75, 0, 0, 0, 0, 1,
+ 0, 0, 0, 70, 0, 0, 0, 2,116, 0, 0, 0, 0, 6, 2, 0, 0, 0, 2,116,
+ 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 11, 99,108, 97,
+115,115, 67,108, 97,115,115, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0,
+ 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 7,
+ 97,112,112,101,110,100, 0, 2, 0, 0, 0, 6, 67,108, 97,115,115, 0, 4, 0,
+ 0, 0, 79, 0, 0, 0, 11, 64, 99,108, 97,115,115, 46,108,117, 97, 0, 0, 0,
+ 0, 73, 11, 3, 60, 80, 15, 4, 15, 5, 22, 2, 11, 6, 13, 0, 11, 7, 13, 1,
+ 30, 1, 2, 1, 1, 2, 1, 1, 60, 81, 15, 8, 13, 3, 2, 0, 1, 60, 82, 13,
+ 3, 20, 9, 15, 10, 13, 2, 7, 2, 15, 11, 13, 2, 2, 1, 1, 7, 1, 38, 2,
+ 1, 3, 2, 0, 2, 60, 83, 15, 12, 2, 0, 0, 60, 84, 0, 0, 0, 0, 4, 0,
+ 0, 0, 79, 0, 0, 0, 2,110, 0, 0, 0, 0, 79, 0, 0, 0, 2,112, 0, 0,
+ 0, 0, 79, 0, 0, 0, 2, 98, 0, 0, 0, 0, 80, 0, 0, 0, 2, 99, 0, 0,
+ 0, 0, 13, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 2,112, 0, 2, 0, 0,
+ 0, 2, 98, 0, 2, 0, 0, 0, 2, 99, 0, 2, 0, 0, 0, 7, 95, 67,108, 97,
+115,115, 0, 2, 0, 0, 0, 11, 95, 67,111,110,116, 97,105,110,101,114, 0, 2,
+ 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 5, 98, 97,115,101, 0, 2,
+ 0, 0, 0, 5,112,117,115,104, 0, 2, 0, 0, 0, 6,112, 97,114,115,101, 0,
+ 2, 0, 0, 0, 7,115,116,114,115,117, 98, 0, 2, 0, 0, 0, 7,115,116,114,
+108,101,110, 0, 2, 0, 0, 0, 4,112,111,112, 0,
+};
+
+/* typedef.lo */
+static char B8[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 13, 64,116,121,112,101,100,
+101,102, 46,108,117, 97, 0, 0, 0, 0, 52, 7, 0, 60, 24, 22, 3, 60, 25, 11,
+ 1, 11, 2, 11, 3, 60, 26, 11, 2, 11, 4, 60, 27, 11, 2, 30, 2, 60, 28, 25,
+ 0, 60, 31, 15, 0, 11, 5, 11, 6, 26, 60, 40, 11, 8, 25, 7, 60, 49, 11, 10,
+ 25, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 2, 0, 0, 0, 13, 99,108, 97,115,
+115, 84,121,112,101,100,101,102, 0, 2, 0, 0, 0, 6,117,116,121,112,101, 0,
+ 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 5,
+116,121,112,101, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0, 0, 0,
+ 31, 0, 0, 0, 13, 64,116,121,112,101,100,101,102, 46,108,117, 97, 0, 0, 0,
+ 0, 92, 6, 3, 60, 32, 15, 2, 13, 1, 11, 3, 42, 2, 0, 1, 60, 33, 15, 2,
+ 13, 1, 11, 4, 42, 13, 0, 18, 6, 42, 11, 7, 42, 2, 0, 1, 60, 34, 15, 2,
+ 13, 1, 11, 8, 42, 13, 0, 18, 9, 42, 11, 7, 42, 2, 0, 1, 60, 35, 15, 2,
+ 13, 1, 11, 10, 42, 13, 0, 18, 11, 42, 11, 7, 42, 2, 0, 1, 60, 36, 15, 2,
+ 13, 1, 11, 12, 42, 13, 2, 42, 2, 0, 1, 60, 37, 0, 0, 0, 0, 3, 0, 0,
+ 0, 31, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 31, 0, 0, 0, 6,105,
+100,101,110,116, 0, 0, 0, 0, 31, 0, 0, 0, 6, 99,108,111,115,101, 0, 0,
+ 0, 0, 13, 2, 0, 0, 0, 6,105,100,101,110,116, 0, 2, 0, 0, 0, 6, 99,
+108,111,115,101, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 2, 0, 0, 0,
+ 9, 84,121,112,101,100,101,102,123, 0, 2, 0, 0, 0, 11, 32,117,116,121,112,
+101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0,
+ 6,117,116,121,112,101, 0, 2, 0, 0, 0, 3, 39, 44, 0, 2, 0, 0, 0, 9,
+ 32,109,111,100, 32, 61, 32, 39, 0, 2, 0, 0, 0, 4,109,111,100, 0, 2, 0,
+ 0, 0, 10, 32,116,121,112,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,116,121,
+112,101, 0, 2, 0, 0, 0, 2,125, 0, 2, 0, 0, 0, 9, 95, 84,121,112,101,
+100,101,102, 0, 4, 0, 0, 0, 40, 0, 0, 0, 13, 64,116,121,112,101,100,101,
+102, 46,108,117, 97, 0, 0, 0, 0, 40, 4, 1, 60, 41, 13, 0, 11, 1, 15, 2,
+ 26, 60, 42, 15, 3, 13, 0, 15, 4, 2, 0, 2, 60, 43, 15, 5, 13, 0, 2, 0,
+ 1, 60, 44, 13, 0, 1, 1, 60, 45, 0, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0,
+ 0, 2,116, 0, 0, 0, 0, 6, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6,
+ 95, 98, 97,115,101, 0, 2, 0, 0, 0, 13, 99,108, 97,115,115, 84,121,112,101,
+100,101,102, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0,
+ 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 14, 97,112,112,101,
+110,100,116,121,112,101,100,101,102, 0, 2, 0, 0, 0, 8, 84,121,112,101,100,
+101,102, 0, 4, 0, 0, 0, 49, 0, 0, 0, 13, 64,116,121,112,101,100,101,102,
+ 46,108,117, 97, 0, 0, 0, 0,109, 14, 1, 60, 50, 15, 1, 13, 0, 11, 2, 2,
+ 1, 2, 52, 11, 60, 51, 15, 3, 11, 4, 2, 0, 1, 50, 2, 60, 52, 60, 53, 15,
+ 6, 15, 7, 13, 0, 11, 8, 11, 9, 2, 1, 3, 11, 9, 2, 1, 2, 60, 54, 15,
+ 10, 22, 3, 60, 55, 11, 11, 13, 1, 13, 1, 18, 12, 16, 11, 13, 60, 56, 13, 1,
+ 13, 1, 18, 12, 7, 1, 38, 16, 11, 14, 60, 57, 15, 15, 13, 1, 7, 1, 13, 1,
+ 18, 12, 7, 2, 38, 2, 1, 3, 30, 2, 60, 58, 3, 2, 1, 60, 59, 0, 0, 0,
+ 0, 2, 0, 0, 0, 49, 0, 0, 0, 2,115, 0, 0, 0, 0, 53, 0, 0, 0, 2,
+116, 0, 0, 0, 0, 16, 2, 0, 0, 0, 2,115, 0, 2, 0, 0, 0, 8,115,116,
+114,102,105,110,100, 0, 2, 0, 0, 0, 6, 91, 37, 42, 38, 93, 0, 2, 0, 0,
+ 0, 12,116,111,108,117, 97, 95,101,114,114,111,114, 0, 2, 0, 0, 0, 62, 35,
+105,110,118, 97,108,105,100, 32,116,121,112,101,100,101,102, 58, 32,112,111,105,
+110,116,101,114,115, 32, 40, 97,110,100, 32,114,101,102,101,114,101,110, 99,101,
+115, 41, 32, 97,114,101, 32,110,111,116, 32,115,117,112,112,111,114,116,101,100,
+ 0, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6,115,112,108,105,116, 0, 2,
+ 0, 0, 0, 5,103,115,117, 98, 0, 2, 0, 0, 0, 6, 37,115, 37,115, 42, 0,
+ 2, 0, 0, 0, 2, 32, 0, 2, 0, 0, 0, 9, 95, 84,121,112,101,100,101,102,
+ 0, 2, 0, 0, 0, 6,117,116,121,112,101, 0, 2, 0, 0, 0, 2,110, 0, 2,
+ 0, 0, 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 4,109,111,100, 0, 2, 0,
+ 0, 0, 7, 99,111,110, 99, 97,116, 0,
+};
+
+/* define.lo */
+static char B9[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 12, 64,100,101,102,105,110,
+101, 46,108,117, 97, 0, 0, 0, 0, 75, 5, 0, 60, 18, 22, 2, 60, 19, 11, 1,
+ 11, 2, 11, 3, 60, 20, 15, 4, 30, 1, 60, 21, 25, 0, 60, 22, 15, 5, 15, 0,
+ 15, 6, 2, 0, 2, 60, 25, 15, 0, 11, 7, 11, 8, 26, 60, 35, 15, 0, 11, 9,
+ 11, 10, 26, 60, 42, 15, 0, 11, 11, 11, 12, 26, 60, 51, 11, 14, 25, 13, 60, 65,
+ 11, 16, 25, 15, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 0, 0, 0, 12, 99,108,
+ 97,115,115, 68,101,102,105,110,101, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0,
+ 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0,
+ 0, 13, 99,108, 97,115,115, 70,101, 97,116,117,114,101, 0, 2, 0, 0, 0, 7,
+115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,
+103, 0, 2, 0, 0, 0, 9,114,101,103,105,115,116,101,114, 0, 4, 0, 0, 0,
+ 25, 0, 0, 0, 12, 64,100,101,102,105,110,101, 46,108,117, 97, 0, 0, 0, 0,
+ 80, 5, 1, 60, 26, 13, 0, 20, 2, 2, 1, 1, 60, 27, 13, 1, 52, 33, 60, 28,
+ 15, 3, 11, 4, 13, 1, 42, 11, 5, 42, 13, 0, 18, 6, 42, 11, 7, 42, 13, 0,
+ 18, 8, 42, 11, 9, 42, 2, 0, 1, 50, 27, 60, 30, 15, 3, 11, 10, 13, 0, 18,
+ 6, 42, 11, 7, 42, 13, 0, 18, 8, 42, 11, 9, 42, 2, 0, 1, 60, 31, 60, 32,
+ 0, 0, 0, 0, 2, 0, 0, 0, 25, 0, 0, 0, 5,115,101,108,102, 0, 0, 0,
+ 0, 26, 0, 0, 0, 2,112, 0, 0, 0, 0, 11, 2, 0, 0, 0, 2,112, 0, 2,
+ 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 9,105,110,109,111,100,117,
+108,101, 0, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 18,
+ 32,116,111,108,117, 97, 95, 99,111,110,115,116, 97,110,116, 40, 34, 0, 2, 0,
+ 0, 0, 4, 34, 44, 34, 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0,
+ 0, 0, 3, 34, 44, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0,
+ 3, 41, 59, 0, 2, 0, 0, 0, 23, 32,116,111,108,117, 97, 95, 99,111,110,115,
+116, 97,110,116, 40, 78, 85, 76, 76, 44, 34, 0, 2, 0, 0, 0, 11,117,110,114,
+101,103,105,115,116,101,114, 0, 4, 0, 0, 0, 35, 0, 0, 0, 12, 64,100,101,
+102,105,110,101, 46,108,117, 97, 0, 0, 0, 0, 38, 4, 1, 60, 36, 13, 0, 20,
+ 1, 2, 1, 1, 44, 52, 19, 60, 37, 15, 2, 11, 3, 13, 0, 18, 4, 42, 11, 5,
+ 42, 2, 0, 1, 50, 2, 60, 38, 60, 39, 0, 0, 0, 0, 1, 0, 0, 0, 35, 0,
+ 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 6, 2, 0, 0, 0, 5,115,101,108,
+102, 0, 2, 0, 0, 0, 9,105,110,109,111,100,117,108,101, 0, 2, 0, 0, 0,
+ 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 32, 32,108,117, 97, 95,112,117,
+115,104,110,105,108, 40, 41, 59, 32,108,117, 97, 95,115,101,116,103,108,111, 98,
+ 97,108, 40, 34, 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0,
+ 4, 34, 41, 59, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0, 0, 0,
+ 42, 0, 0, 0, 12, 64,100,101,102,105,110,101, 46,108,117, 97, 0, 0, 0, 0,
+ 72, 6, 3, 60, 43, 15, 2, 13, 1, 11, 3, 42, 2, 0, 1, 60, 44, 15, 2, 13,
+ 1, 11, 4, 42, 13, 0, 18, 6, 42, 11, 7, 42, 2, 0, 1, 60, 45, 15, 2, 13,
+ 1, 11, 8, 42, 13, 0, 18, 9, 42, 11, 7, 42, 2, 0, 1, 60, 46, 15, 2, 13,
+ 1, 11, 10, 42, 13, 2, 42, 2, 0, 1, 60, 47, 0, 0, 0, 0, 3, 0, 0, 0,
+ 42, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 42, 0, 0, 0, 6,105,100,
+101,110,116, 0, 0, 0, 0, 42, 0, 0, 0, 6, 99,108,111,115,101, 0, 0, 0,
+ 0, 11, 2, 0, 0, 0, 6,105,100,101,110,116, 0, 2, 0, 0, 0, 6, 99,108,
+111,115,101, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 2, 0, 0, 0, 8,
+ 68,101,102,105,110,101,123, 0, 2, 0, 0, 0, 10, 32,110, 97,109,101, 32, 61,
+ 32, 39, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,110, 97,
+109,101, 0, 2, 0, 0, 0, 3, 39, 44, 0, 2, 0, 0, 0, 11, 32,108,110, 97,
+109,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0,
+ 0, 0, 2,125, 0, 2, 0, 0, 0, 8, 95, 68,101,102,105,110,101, 0, 4, 0,
+ 0, 0, 51, 0, 0, 0, 12, 64,100,101,102,105,110,101, 46,108,117, 97, 0, 0,
+ 0, 0, 64, 4, 1, 60, 52, 13, 0, 11, 1, 15, 2, 26, 60, 53, 15, 3, 13, 0,
+ 15, 4, 2, 0, 2, 60, 55, 13, 0, 18, 5, 11, 6, 32, 52, 11, 60, 56, 15, 7,
+ 11, 8, 2, 0, 1, 50, 2, 60, 57, 60, 59, 15, 9, 13, 0, 2, 0, 1, 60, 60,
+ 13, 0, 1, 1, 60, 61, 0, 0, 0, 0, 1, 0, 0, 0, 51, 0, 0, 0, 2,116,
+ 0, 0, 0, 0, 10, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6, 95, 98, 97,
+115,101, 0, 2, 0, 0, 0, 12, 99,108, 97,115,115, 68,101,102,105,110,101, 0,
+ 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,
+117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0,
+ 0, 1, 0, 2, 0, 0, 0, 6,101,114,114,111,114, 0, 2, 0, 0, 0, 16, 35,
+105,110,118, 97,108,105,100, 32,100,101,102,105,110,101, 0, 2, 0, 0, 0, 7,
+ 97,112,112,101,110,100, 0, 2, 0, 0, 0, 7, 68,101,102,105,110,101, 0, 4,
+ 0, 0, 0, 65, 0, 0, 0, 12, 64,100,101,102,105,110,101, 46,108,117, 97, 0,
+ 0, 0, 0, 54, 9, 1, 60, 66, 15, 2, 13, 0, 11, 3, 2, 1, 2, 60, 67, 15,
+ 4, 22, 2, 60, 68, 11, 5, 13, 1, 7, 1, 16, 11, 6, 60, 69, 13, 1, 7, 2,
+ 16, 46, 5, 13, 1, 7, 1, 16, 30, 1, 60, 70, 3, 2, 1, 60, 71, 0, 0, 0,
+ 0, 2, 0, 0, 0, 65, 0, 0, 0, 2,110, 0, 0, 0, 0, 66, 0, 0, 0, 2,
+116, 0, 0, 0, 0, 7, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 2,116, 0,
+ 2, 0, 0, 0, 6,115,112,108,105,116, 0, 2, 0, 0, 0, 2, 64, 0, 2, 0,
+ 0, 0, 8, 95, 68,101,102,105,110,101, 0, 2, 0, 0, 0, 5,110, 97,109,101,
+ 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0,
+};
+
+/* enumerate.lo */
+static char B10[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 15, 64,101,110,117,109,101,
+114, 97,116,101, 46,108,117, 97, 0, 0, 0, 0, 69, 3, 0, 60, 19, 22, 1, 60,
+ 20, 11, 1, 15, 2, 30, 0, 60, 21, 25, 0, 60, 22, 15, 3, 15, 0, 15, 4, 2,
+ 0, 2, 60, 25, 15, 0, 11, 5, 11, 6, 26, 60, 42, 15, 0, 11, 7, 11, 8, 26,
+ 60, 53, 15, 0, 11, 9, 11, 10, 26, 60, 64, 11, 12, 25, 11, 60, 73, 11, 14, 25,
+ 13, 0, 0, 0, 0, 0, 0, 0, 0, 15, 2, 0, 0, 0, 15, 99,108, 97,115,115,
+ 69,110,117,109,101,114, 97,116,101, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101,
+ 0, 2, 0, 0, 0, 13, 99,108, 97,115,115, 70,101, 97,116,117,114,101, 0, 2,
+ 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117,
+ 97, 95,116, 97,103, 0, 2, 0, 0, 0, 9,114,101,103,105,115,116,101,114, 0,
+ 4, 0, 0, 0, 25, 0, 0, 0, 15, 64,101,110,117,109,101,114, 97,116,101, 46,
+108,117, 97, 0, 0, 0, 0,179, 7, 1, 60, 26, 13, 0, 20, 2, 2, 1, 1, 46,
+ 7, 13, 0, 20, 3, 2, 1, 1, 60, 27, 7, 1, 50,141, 60, 29, 13, 1, 52, 93,
+ 60, 30, 13, 0, 20, 2, 2, 1, 1, 52, 43, 60, 31, 15, 5, 11, 6, 13, 1, 42,
+ 11, 7, 42, 13, 0, 18, 8, 13, 2, 16, 42, 11, 9, 42, 13, 1, 42, 11, 10, 42,
+ 13, 0, 13, 2, 16, 42, 11, 11, 42, 2, 0, 1, 50, 37, 60, 33, 15, 5, 11, 6,
+ 13, 1, 42, 11, 7, 42, 13, 0, 18, 8, 13, 2, 16, 42, 11, 9, 42, 13, 0, 13,
+ 2, 16, 42, 11, 11, 42, 2, 0, 1, 60, 34, 50, 31, 60, 36, 15, 5, 11, 12, 13,
+ 0, 18, 8, 13, 2, 16, 42, 11, 9, 42, 13, 0, 13, 2, 16, 42, 11, 11, 42, 2,
+ 0, 1, 60, 37, 60, 38, 13, 2, 7, 1, 37, 23, 2, 60, 39, 60, 28, 13, 0, 13,
+ 2, 16, 54,150, 60, 40, 0, 0, 0, 0, 3, 0, 0, 0, 25, 0, 0, 0, 5,115,
+101,108,102, 0, 0, 0, 0, 26, 0, 0, 0, 2,112, 0, 0, 0, 0, 27, 0, 0,
+ 0, 2,105, 0, 0, 0, 0, 13, 2, 0, 0, 0, 2,112, 0, 2, 0, 0, 0, 5,
+115,101,108,102, 0, 2, 0, 0, 0, 8,105,110, 99,108, 97,115,115, 0, 2, 0,
+ 0, 0, 9,105,110,109,111,100,117,108,101, 0, 2, 0, 0, 0, 2,105, 0, 2,
+ 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 18, 32,116,111,108,
+117, 97, 95, 99,111,110,115,116, 97,110,116, 40, 34, 0, 2, 0, 0, 0, 4, 34,
+ 44, 34, 0, 2, 0, 0, 0, 7,108,110, 97,109,101,115, 0, 2, 0, 0, 0, 3,
+ 34, 44, 0, 2, 0, 0, 0, 3, 58, 58, 0, 2, 0, 0, 0, 3, 41, 59, 0, 2,
+ 0, 0, 0, 23, 32,116,111,108,117, 97, 95, 99,111,110,115,116, 97,110,116, 40,
+ 78, 85, 76, 76, 44, 34, 0, 2, 0, 0, 0, 11,117,110,114,101,103,105,115,116,
+101,114, 0, 4, 0, 0, 0, 42, 0, 0, 0, 15, 64,101,110,117,109,101,114, 97,
+116,101, 46,108,117, 97, 0, 0, 0, 0, 83, 6, 1, 60, 43, 13, 0, 20, 1, 2,
+ 1, 1, 4, 0, 32, 48, 10, 13, 0, 20, 2, 2, 1, 1, 4, 0, 32, 52, 50, 60,
+ 44, 7, 1, 50, 31, 60, 46, 15, 4, 11, 5, 13, 0, 18, 6, 13, 1, 16, 42, 11,
+ 7, 42, 2, 0, 1, 60, 47, 13, 1, 7, 1, 37, 23, 1, 60, 48, 60, 45, 13, 0,
+ 13, 1, 16, 54, 40, 5, 1, 50, 2, 60, 49, 60, 50, 0, 0, 0, 0, 3, 0, 0,
+ 0, 42, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 44, 0, 0, 0, 2,105,
+ 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 5,115,101,
+108,102, 0, 2, 0, 0, 0, 8,105,110, 99,108, 97,115,115, 0, 2, 0, 0, 0,
+ 9,105,110,109,111,100,117,108,101, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0,
+ 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 32, 32,108,117, 97, 95,112,
+117,115,104,110,105,108, 40, 41, 59, 32,108,117, 97, 95,115,101,116,103,108,111,
+ 98, 97,108, 40, 34, 0, 2, 0, 0, 0, 7,108,110, 97,109,101,115, 0, 2, 0,
+ 0, 0, 4, 34, 41, 59, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0,
+ 0, 0, 53, 0, 0, 0, 15, 64,101,110,117,109,101,114, 97,116,101, 46,108,117,
+ 97, 0, 0, 0, 0, 90, 8, 3, 60, 54, 15, 2, 13, 1, 11, 3, 42, 2, 0, 1,
+ 60, 55, 7, 1, 50, 43, 60, 57, 15, 2, 13, 1, 11, 6, 42, 13, 0, 13, 3, 16,
+ 42, 11, 7, 42, 13, 0, 18, 8, 13, 3, 16, 42, 11, 9, 42, 2, 0, 1, 60, 58,
+ 13, 3, 7, 1, 37, 23, 3, 60, 59, 60, 56, 13, 0, 13, 3, 16, 54, 52, 60, 60,
+ 15, 2, 13, 1, 11, 10, 42, 13, 2, 42, 2, 0, 1, 60, 61, 0, 0, 0, 0, 4,
+ 0, 0, 0, 53, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 53, 0, 0, 0,
+ 6,105,100,101,110,116, 0, 0, 0, 0, 53, 0, 0, 0, 6, 99,108,111,115,101,
+ 0, 0, 0, 0, 55, 0, 0, 0, 2,105, 0, 0, 0, 0, 11, 2, 0, 0, 0, 6,
+105,100,101,110,116, 0, 2, 0, 0, 0, 6, 99,108,111,115,101, 0, 2, 0, 0,
+ 0, 6,112,114,105,110,116, 0, 2, 0, 0, 0, 11, 69,110,117,109,101,114, 97,
+116,101,123, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 5,115,101,108,102,
+ 0, 2, 0, 0, 0, 3, 32, 39, 0, 2, 0, 0, 0, 3, 39, 40, 0, 2, 0, 0,
+ 0, 7,108,110, 97,109,101,115, 0, 2, 0, 0, 0, 3, 41, 44, 0, 2, 0, 0,
+ 0, 2,125, 0, 2, 0, 0, 0, 11, 95, 69,110,117,109,101,114, 97,116,101, 0,
+ 4, 0, 0, 0, 64, 0, 0, 0, 15, 64,101,110,117,109,101,114, 97,116,101, 46,
+108,117, 97, 0, 0, 0, 0, 40, 4, 1, 60, 65, 13, 0, 11, 1, 15, 2, 26, 60,
+ 66, 15, 3, 13, 0, 15, 4, 2, 0, 2, 60, 67, 15, 5, 13, 0, 2, 0, 1, 60,
+ 68, 13, 0, 1, 1, 60, 69, 0, 0, 0, 0, 1, 0, 0, 0, 64, 0, 0, 0, 2,
+116, 0, 0, 0, 0, 6, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6, 95, 98,
+ 97,115,101, 0, 2, 0, 0, 0, 15, 99,108, 97,115,115, 69,110,117,109,101,114,
+ 97,116,101, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0,
+ 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 7, 97,112,112,101,
+110,100, 0, 2, 0, 0, 0, 10, 69,110,117,109,101,114, 97,116,101, 0, 4, 0,
+ 0, 0, 73, 0, 0, 0, 15, 64,101,110,117,109,101,114, 97,116,101, 46,108,117,
+ 97, 0, 0, 0, 0,200, 9, 1, 60, 74, 15, 2, 15, 3, 13, 0, 7, 2, 9, 2,
+ 2, 1, 3, 11, 4, 2, 1, 2, 60, 75, 7, 1, 60, 76, 22, 1, 11, 7, 7, 0,
+ 30, 0, 50, 55, 60, 78, 15, 2, 13, 1, 13, 2, 16, 11, 9, 2, 1, 2, 60, 79,
+ 13, 3, 11, 7, 13, 3, 18, 7, 7, 1, 37, 26, 60, 80, 13, 3, 13, 3, 18, 7,
+ 13, 4, 7, 1, 16, 26, 60, 81, 13, 2, 7, 1, 37, 23, 2, 5, 1, 60, 82, 60,
+ 77, 13, 1, 13, 2, 16, 54, 64, 60, 84, 7, 1, 23, 2, 60, 85, 13, 3, 11, 10,
+ 22, 0, 26, 50, 60, 60, 87, 15, 2, 13, 3, 13, 2, 16, 11, 11, 2, 1, 2, 60,
+ 88, 13, 3, 13, 2, 13, 4, 7, 1, 16, 26, 60, 89, 13, 3, 18, 10, 13, 2, 13,
+ 4, 7, 2, 16, 46, 5, 13, 4, 7, 1, 16, 26, 60, 90, 13, 2, 7, 1, 37, 23,
+ 2, 5, 1, 60, 91, 60, 86, 13, 3, 13, 2, 16, 54, 69, 60, 92, 15, 12, 13, 3,
+ 3, 4, 1, 60, 93, 0, 0, 0, 0, 8, 0, 0, 0, 73, 0, 0, 0, 2, 98, 0,
+ 0, 0, 0, 74, 0, 0, 0, 2,116, 0, 0, 0, 0, 75, 0, 0, 0, 2,105, 0,
+ 0, 0, 0, 76, 0, 0, 0, 2,101, 0, 0, 0, 0, 78, 0, 0, 0, 3,116,116,
+ 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 2,116, 0, 0,
+ 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 13, 2, 0, 0, 0, 2, 98, 0, 2, 0,
+ 0, 0, 2,116, 0, 2, 0, 0, 0, 6,115,112,108,105,116, 0, 2, 0, 0, 0,
+ 7,115,116,114,115,117, 98, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0, 0, 0, 2,
+105, 0, 2, 0, 0, 0, 2,101, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0,
+ 3,116,116, 0, 2, 0, 0, 0, 2, 61, 0, 2, 0, 0, 0, 7,108,110, 97,109,
+101,115, 0, 2, 0, 0, 0, 2, 64, 0, 2, 0, 0, 0, 11, 95, 69,110,117,109,
+101,114, 97,116,101, 0,
+};
+
+/* variable.lo */
+static char B11[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 14, 64,118, 97,114,105, 97,
+ 98,108,101, 46,108,117, 97, 0, 0, 0, 0, 87, 3, 0, 60, 18, 22, 1, 60, 19,
+ 11, 1, 15, 2, 30, 0, 60, 20, 25, 0, 60, 22, 15, 3, 15, 0, 15, 4, 2, 0,
+ 2, 60, 25, 15, 0, 11, 5, 11, 6, 26, 60, 37, 15, 0, 11, 7, 11, 8, 26, 60,
+ 48, 15, 0, 11, 9, 11, 10, 26, 60,154, 15, 0, 11, 11, 11, 12, 26, 60,171, 15,
+ 0, 11, 13, 11, 14, 26, 60,179, 11, 16, 25, 15, 60,188, 11, 18, 25, 17, 0, 0,
+ 0, 0, 0, 0, 0, 0, 19, 2, 0, 0, 0, 14, 99,108, 97,115,115, 86, 97,114,
+105, 97, 98,108,101, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0,
+ 0, 17, 99,108, 97,115,115, 68,101, 99,108, 97,114, 97,116,105,111,110, 0, 2,
+ 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117,
+ 97, 95,116, 97,103, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0, 0,
+ 0, 25, 0, 0, 0, 14, 64,118, 97,114,105, 97, 98,108,101, 46,108,117, 97, 0,
+ 0, 0, 0,152, 6, 3, 60, 26, 15, 2, 13, 1, 11, 3, 42, 2, 0, 1, 60, 27,
+ 15, 2, 13, 1, 11, 4, 42, 13, 0, 18, 6, 42, 11, 7, 42, 2, 0, 1, 60, 28,
+ 15, 2, 13, 1, 11, 8, 42, 13, 0, 18, 9, 42, 11, 7, 42, 2, 0, 1, 60, 29,
+ 15, 2, 13, 1, 11, 10, 42, 13, 0, 18, 11, 42, 11, 7, 42, 2, 0, 1, 60, 30,
+ 15, 2, 13, 1, 11, 12, 42, 13, 0, 18, 13, 42, 11, 7, 42, 2, 0, 1, 60, 31,
+ 15, 2, 13, 1, 11, 14, 42, 13, 0, 18, 15, 42, 11, 7, 42, 2, 0, 1, 60, 32,
+ 15, 2, 13, 1, 11, 16, 42, 13, 0, 18, 17, 42, 11, 7, 42, 2, 0, 1, 60, 33,
+ 15, 2, 13, 1, 11, 18, 42, 13, 2, 42, 2, 0, 1, 60, 34, 0, 0, 0, 0, 3,
+ 0, 0, 0, 25, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 25, 0, 0, 0,
+ 6,105,100,101,110,116, 0, 0, 0, 0, 25, 0, 0, 0, 6, 99,108,111,115,101,
+ 0, 0, 0, 0, 19, 2, 0, 0, 0, 6,105,100,101,110,116, 0, 2, 0, 0, 0,
+ 6, 99,108,111,115,101, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 2, 0,
+ 0, 0, 10, 86, 97,114,105, 97, 98,108,101,123, 0, 2, 0, 0, 0, 10, 32,109,
+111,100, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0,
+ 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 3, 39, 44, 0, 2, 0, 0, 0, 10,
+ 32,116,121,112,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,116,121,112,101, 0,
+ 2, 0, 0, 0, 10, 32,112,116,114, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 4,
+112,116,114, 0, 2, 0, 0, 0, 10, 32,110, 97,109,101, 32, 61, 32, 39, 0, 2,
+ 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 10, 32,100,101,102, 32, 32,
+ 61, 32, 39, 0, 2, 0, 0, 0, 4,100,101,102, 0, 2, 0, 0, 0, 10, 32,114,
+101,116, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 4,114,101,116, 0, 2, 0, 0,
+ 0, 2,125, 0, 2, 0, 0, 0, 9,103,101,116,118, 97,108,117,101, 0, 4, 0,
+ 0, 0, 37, 0, 0, 0, 14, 64,118, 97,114,105, 97, 98,108,101, 46,108,117, 97,
+ 0, 0, 0, 0, 60, 5, 3, 60, 38, 13, 1, 48, 2, 13, 2, 52, 16, 60, 39, 13,
+ 1, 11, 2, 42, 13, 0, 18, 4, 42, 1, 3, 50, 29, 60, 40, 13, 1, 52, 13, 60,
+ 41, 11, 5, 13, 0, 18, 4, 42, 1, 3, 50, 10, 60, 43, 13, 0, 18, 4, 1, 3,
+ 60, 44, 60, 45, 0, 0, 0, 0, 3, 0, 0, 0, 37, 0, 0, 0, 5,115,101,108,
+102, 0, 0, 0, 0, 37, 0, 0, 0, 6, 99,108, 97,115,115, 0, 0, 0, 0, 37,
+ 0, 0, 0, 7,115,116, 97,116,105, 99, 0, 0, 0, 0, 6, 2, 0, 0, 0, 6,
+ 99,108, 97,115,115, 0, 2, 0, 0, 0, 7,115,116, 97,116,105, 99, 0, 2, 0,
+ 0, 0, 3, 58, 58, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0,
+ 5,110, 97,109,101, 0, 2, 0, 0, 0, 7,115,101,108,102, 45, 62, 0, 2, 0,
+ 0, 0, 8,115,117,112, 99,111,100,101, 0, 4, 0, 0, 0, 48, 0, 0, 0, 14,
+ 64,118, 97,114,105, 97, 98,108,101, 46,108,117, 97, 0, 0, 0, 3,189, 17, 1,
+ 60, 49, 13, 0, 20, 2, 2, 1, 1, 60, 52, 13, 1, 52, 21, 60, 53, 15, 3, 11,
+ 4, 13, 0, 18, 5, 11, 6, 13, 1, 11, 7, 2, 0, 5, 50, 17, 60, 55, 15, 3,
+ 11, 4, 13, 0, 18, 5, 11, 7, 2, 0, 3, 60, 56, 60, 57, 13, 0, 11, 8, 13,
+ 0, 20, 9, 11, 10, 2, 1, 2, 26, 60, 58, 15, 3, 11, 11, 13, 0, 18, 8, 11,
+ 12, 2, 0, 3, 60, 59, 15, 3, 11, 13, 2, 0, 1, 60, 62, 15, 16, 13, 0, 18,
+ 17, 11, 18, 2, 3, 2, 60, 63, 13, 1, 48, 5, 13, 4, 4, 0, 32, 52, 39, 60,
+ 64, 15, 3, 11, 19, 13, 1, 11, 20, 11, 21, 2, 0, 4, 60, 65, 15, 3, 11, 22,
+ 13, 1, 11, 23, 2, 0, 3, 60, 66, 15, 3, 11, 24, 2, 0, 1, 50, 35, 60, 67,
+ 13, 4, 52, 27, 60, 68, 13, 0, 11, 17, 15, 16, 13, 0, 18, 17, 11, 25, 2, 3,
+ 2, 27, 2, 23, 3, 23, 3, 5, 2, 50, 2, 60, 69, 60, 73, 13, 1, 48, 5, 13,
+ 4, 4, 0, 32, 52, 19, 60, 74, 15, 3, 11, 26, 13, 0, 18, 5, 42, 11, 27, 42,
+ 2, 0, 1, 50, 2, 60, 75, 60, 78, 15, 29, 13, 0, 18, 30, 2, 1, 1, 60, 79,
+ 13, 5, 11, 31, 32, 52, 32, 60, 80, 15, 3, 11, 32, 13, 5, 42, 11, 33, 42, 13,
+ 0, 20, 34, 13, 1, 13, 4, 2, 1, 3, 42, 11, 35, 42, 2, 0, 1, 50,124, 60,
+ 81, 13, 5, 52, 32, 60, 82, 15, 3, 11, 32, 13, 5, 42, 11, 22, 42, 13, 0, 20,
+ 34, 13, 1, 13, 4, 2, 1, 3, 42, 11, 35, 42, 2, 0, 1, 50, 86, 60, 84, 13,
+ 0, 18, 36, 11, 37, 32, 46, 7, 13, 0, 18, 36, 11, 38, 32, 52, 32, 60, 85, 15,
+ 3, 11, 39, 13, 0, 20, 34, 13, 1, 13, 4, 2, 1, 3, 42, 11, 40, 42, 13, 0,
+ 18, 41, 11, 35, 2, 0, 3, 50, 32, 60, 87, 15, 3, 11, 42, 13, 0, 20, 34, 13,
+ 1, 13, 4, 2, 1, 3, 42, 11, 40, 42, 13, 0, 18, 41, 11, 35, 2, 0, 3, 60,
+ 88, 60, 89, 60, 90, 15, 3, 11, 43, 2, 0, 1, 60, 91, 15, 3, 11, 44, 2, 0,
+ 1, 60, 94, 15, 16, 13, 0, 18, 17, 11, 45, 2, 1, 2, 44, 51, 2, 0, 60, 95,
+ 13, 1, 52, 21, 60, 96, 15, 3, 11, 46, 13, 0, 18, 5, 11, 6, 13, 1, 11, 7,
+ 2, 0, 5, 50, 17, 60, 98, 15, 3, 11, 46, 13, 0, 18, 5, 11, 7, 2, 0, 3,
+ 60, 99, 60,100, 13, 0, 11, 47, 13, 0, 20, 9, 11, 48, 2, 1, 2, 26, 60,101,
+ 15, 3, 11, 11, 13, 0, 18, 47, 11, 12, 2, 0, 3, 60,102, 15, 3, 11, 13, 2,
+ 0, 1, 60,105, 7, 1, 60,106, 13, 1, 48, 5, 13, 4, 4, 0, 32, 52, 65, 60,
+107, 15, 3, 11, 19, 13, 1, 11, 20, 11, 21, 2, 0, 4, 60,108, 15, 3, 11, 22,
+ 13, 1, 11, 23, 2, 0, 3, 60,109, 15, 3, 11, 24, 2, 0, 1, 60,111, 15, 3,
+ 11, 26, 13, 0, 18, 5, 42, 11, 27, 42, 2, 0, 1, 60,112, 13, 6, 7, 1, 37,
+ 23, 6, 50, 44, 60,113, 13, 4, 52, 36, 60,114, 13, 0, 11, 17, 15, 16, 13, 0,
+ 18, 17, 11, 25, 2, 3, 2, 27, 2, 23, 3, 23, 3, 5, 2, 60,115, 13, 6, 7,
+ 1, 37, 23, 6, 50, 2, 60,116, 60,119, 15, 3, 11, 50, 13, 0, 20, 51, 13, 6,
+ 2, 1, 2, 42, 11, 52, 42, 2, 0, 1, 60,120, 15, 3, 11, 53, 2, 0, 1, 60,
+123, 11, 38, 60,124, 13, 0, 18, 36, 11, 38, 31, 52, 4, 11, 20, 23, 7, 60,125,
+ 15, 3, 11, 19, 2, 0, 1, 60,126, 13, 1, 48, 2, 13, 4, 52, 19, 60,127, 15,
+ 3, 13, 1, 11, 54, 42, 13, 0, 18, 5, 42, 2, 0, 1, 50, 35, 60,128, 13, 1,
+ 52, 16, 60,129, 15, 3, 11, 55, 13, 0, 18, 5, 42, 2, 0, 1, 50, 13, 60,131,
+ 15, 3, 13, 0, 18, 5, 2, 0, 1, 60,132, 60,133, 15, 29, 13, 0, 18, 30, 2,
+ 1, 1, 60,134, 15, 3, 11, 56, 2, 0, 1, 60,135, 13, 8, 44, 48, 5, 13, 7,
+ 11, 38, 32, 52, 7, 15, 3, 11, 20, 2, 0, 1, 60,136, 15, 3, 11, 57, 13, 0,
+ 18, 17, 13, 0, 18, 30, 2, 0, 3, 60,137, 13, 8, 44, 52, 11, 60,138, 15, 3,
+ 11, 20, 2, 0, 1, 50, 2, 60,139, 60,140, 15, 3, 11, 58, 2, 0, 1, 60,141,
+ 7, 0, 60,142, 13, 0, 18, 59, 11, 38, 31, 52, 6, 13, 0, 18, 59, 23, 9, 60,
+143, 13, 8, 52, 24, 60,144, 15, 3, 11, 60, 13, 8, 42, 11, 22, 13, 6, 11, 40,
+ 13, 9, 11, 61, 2, 0, 6, 50, 19, 60,146, 15, 3, 11, 62, 13, 6, 11, 40, 13,
+ 9, 11, 61, 2, 0, 5, 60,147, 60,148, 15, 3, 11, 43, 2, 0, 1, 60,149, 15,
+ 3, 11, 44, 2, 0, 1, 5, 4, 50, 2, 60,150, 60,152, 0, 0, 0, 0, 14, 0,
+ 0, 0, 48, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 49, 0, 0, 0, 6,
+ 99,108, 97,115,115, 0, 0, 0, 0, 62, 0, 0, 0, 2, 95, 0, 0, 0, 0, 62,
+ 0, 0, 0, 2, 95, 0, 0, 0, 0, 62, 0, 0, 0, 7,115,116, 97,116,105, 99,
+ 0, 0, 0, 0, 78, 0, 0, 0, 2,116, 0, 0, 0, 0,105, 0, 0, 0, 5,110,
+ 97,114,103, 0, 0, 0, 0,123, 0, 0, 0, 4,112,116,114, 0, 0, 0, 0,133,
+ 0, 0, 0, 2,116, 0, 0, 0, 0,141, 0, 0, 0, 4,100,101,102, 0, 0, 0,
+ 0,149, 0, 0, 0, 0, 0, 0, 0,149, 0, 0, 0, 0, 0, 0, 0,149, 0, 0,
+ 0, 0, 0, 0, 0,149, 0, 0, 0, 0, 0, 0, 0, 63, 2, 0, 0, 0, 6, 99,
+108, 97,115,115, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 8,
+105,110, 99,108, 97,115,115, 0, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0,
+ 2, 0, 0, 0, 17, 47, 42, 32,103,101,116, 32,102,117,110, 99,116,105,111,110,
+ 58, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 11, 32,111,102,
+ 32, 99,108, 97,115,115, 32, 0, 2, 0, 0, 0, 4, 32, 42, 47, 0, 2, 0, 0,
+ 0, 9, 99,103,101,116,110, 97,109,101, 0, 2, 0, 0, 0, 10, 99,102,117,110,
+ 99,110, 97,109,101, 0, 2, 0, 0, 0, 11,116,111,108,117, 97, 73, 95,103,101,
+116, 0, 2, 0, 0, 0, 12,115,116, 97,116,105, 99, 32,118,111,105,100, 0, 2,
+ 0, 0, 0, 7, 40,118,111,105,100, 41, 0, 2, 0, 0, 0, 2,123, 0, 2, 0,
+ 0, 0, 2, 95, 0, 2, 0, 0, 0, 7,115,116, 97,116,105, 99, 0, 2, 0, 0,
+ 0, 8,115,116,114,102,105,110,100, 0, 2, 0, 0, 0, 4,109,111,100, 0, 2,
+ 0, 0, 0, 13, 94, 37,115, 42, 40,115,116, 97,116,105, 99, 41, 0, 2, 0, 0,
+ 0, 2, 32, 0, 2, 0, 0, 0, 2, 42, 0, 2, 0, 0, 0, 8,115,101,108,102,
+ 32, 61, 32, 0, 2, 0, 0, 0, 2, 40, 0, 2, 0, 0, 0, 4, 42, 41, 32, 0,
+ 2, 0, 0, 0, 24,116,111,108,117, 97, 95,103,101,116,117,115,101,114,116,121,
+112,101, 40, 49, 44, 48, 41, 59, 0, 2, 0, 0, 0, 20, 94, 37,115, 42,115,116,
+ 97,116,105, 99, 37,115, 37,115, 42, 40, 46, 42, 41, 0, 2, 0, 0, 0, 65, 32,
+ 32,105,102, 32, 40, 33,115,101,108,102, 41, 32,116,111,108,117, 97, 95,101,114,
+114,111,114, 40, 34,105,110,118, 97,108,105,100, 32, 39,115,101,108,102, 39, 32,
+105,110, 32, 97, 99, 99,101,115,115,105,110,103, 32,118, 97,114,105, 97, 98,108,
+101, 32, 39, 0, 2, 0, 0, 0, 5, 39, 34, 41, 59, 0, 2, 0, 0, 0, 2,116,
+ 0, 2, 0, 0, 0, 8,105,115, 98, 97,115,105, 99, 0, 2, 0, 0, 0, 5,116,
+121,112,101, 0, 2, 0, 0, 0, 7,110,117,109, 98,101,114, 0, 2, 0, 0, 0,
+ 13, 32, 32,116,111,108,117, 97, 95,112,117,115,104, 0, 2, 0, 0, 0, 10, 40,
+ 40,100,111,117, 98,108,101, 41, 0, 2, 0, 0, 0, 9,103,101,116,118, 97,108,
+117,101, 0, 2, 0, 0, 0, 3, 41, 59, 0, 2, 0, 0, 0, 4,112,116,114, 0,
+ 2, 0, 0, 0, 2, 38, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 30, 32, 32,
+116,111,108,117, 97, 95,112,117,115,104,117,115,101,114,116,121,112,101, 40, 40,
+118,111,105,100, 42, 41, 38, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0, 0, 0, 4,
+116, 97,103, 0, 2, 0, 0, 0, 29, 32, 32,116,111,108,117, 97, 95,112,117,115,
+104,117,115,101,114,116,121,112,101, 40, 40,118,111,105,100, 42, 41, 0, 2, 0,
+ 0, 0, 2,125, 0, 2, 0, 0, 0, 2, 10, 0, 2, 0, 0, 0, 6, 99,111,110,
+115,116, 0, 2, 0, 0, 0, 17, 47, 42, 32,115,101,116, 32,102,117,110, 99,116,
+105,111,110, 58, 0, 2, 0, 0, 0, 9, 99,115,101,116,110, 97,109,101, 0, 2,
+ 0, 0, 0, 11,116,111,108,117, 97, 73, 95,115,101,116, 0, 2, 0, 0, 0, 5,
+110, 97,114,103, 0, 2, 0, 0, 0, 8, 32, 32,105,102, 32, 40, 33, 0, 2, 0,
+ 0, 0, 13,111,117,116, 99,104,101, 99,107,116,121,112,101, 0, 2, 0, 0, 0,
+ 2, 41, 0, 2, 0, 0, 0, 58, 32, 32, 32,116,111,108,117, 97, 95,101,114,114,
+111,114, 40, 34, 35,118,105,110,118, 97,108,105,100, 32,116,121,112,101, 32,105,
+110, 32,118, 97,114,105, 97, 98,108,101, 32, 97,115,115,105,103,110,109,101,110,
+116, 46, 34, 41, 59, 0, 2, 0, 0, 0, 3, 58, 58, 0, 2, 0, 0, 0, 7,115,
+101,108,102, 45, 62, 0, 2, 0, 0, 0, 4, 32, 61, 32, 0, 2, 0, 0, 0, 3,
+ 40, 40, 0, 2, 0, 0, 0, 3, 41, 32, 0, 2, 0, 0, 0, 4,100,101,102, 0,
+ 2, 0, 0, 0, 10,116,111,108,117, 97, 95,103,101,116, 0, 2, 0, 0, 0, 4,
+ 41, 41, 59, 0, 2, 0, 0, 0, 19,116,111,108,117, 97, 95,103,101,116,117,115,
+101,114,116,121,112,101, 40, 0, 2, 0, 0, 0, 9,114,101,103,105,115,116,101,
+114, 0, 4, 0, 0, 0,154, 0, 0, 0, 14, 64,118, 97,114,105, 97, 98,108,101,
+ 46,108,117, 97, 0, 0, 0, 0,185, 5, 1, 60,155, 13, 0, 20, 2, 2, 1, 1,
+ 46, 7, 13, 0, 20, 3, 2, 1, 1, 60,156, 13, 1, 52, 84, 60,157, 13, 0, 18,
+ 4, 52, 41, 60,158, 15, 5, 11, 6, 13, 1, 42, 11, 7, 42, 13, 0, 18, 8, 42,
+ 11, 9, 42, 13, 0, 18, 10, 42, 11, 11, 42, 13, 0, 18, 4, 42, 11, 12, 42, 2,
+ 0, 1, 50, 33, 60,160, 15, 5, 11, 6, 13, 1, 42, 11, 7, 42, 13, 0, 18, 8,
+ 42, 11, 9, 42, 13, 0, 18, 10, 42, 11, 13, 42, 2, 0, 1, 60,161, 50, 72, 60,
+163, 13, 0, 18, 4, 52, 35, 60,164, 15, 5, 11, 14, 13, 0, 18, 8, 42, 11, 9,
+ 42, 13, 0, 18, 10, 42, 11, 11, 42, 13, 0, 18, 4, 42, 11, 12, 42, 2, 0, 1,
+ 50, 27, 60,166, 15, 5, 11, 14, 13, 0, 18, 8, 42, 11, 9, 42, 13, 0, 18, 10,
+ 42, 11, 13, 42, 2, 0, 1, 60,167, 60,168, 60,169, 0, 0, 0, 0, 2, 0, 0,
+ 0,154, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0,155, 0, 0, 0, 7,112,
+ 97,114,101,110,116, 0, 0, 0, 0, 15, 2, 0, 0, 0, 7,112, 97,114,101,110,
+116, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 8,105,110, 99,
+108, 97,115,115, 0, 2, 0, 0, 0, 9,105,110,109,111,100,117,108,101, 0, 2,
+ 0, 0, 0, 9, 99,115,101,116,110, 97,109,101, 0, 2, 0, 0, 0, 7,111,117,
+116,112,117,116, 0, 2, 0, 0, 0, 18, 32,116,111,108,117, 97, 95,116, 97, 98,
+108,101,118, 97,114, 40, 34, 0, 2, 0, 0, 0, 4, 34, 44, 34, 0, 2, 0, 0,
+ 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0, 3, 34, 44, 0, 2, 0, 0, 0,
+ 9, 99,103,101,116,110, 97,109,101, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0, 0,
+ 0, 3, 41, 59, 0, 2, 0, 0, 0, 8, 44, 78, 85, 76, 76, 41, 59, 0, 2, 0,
+ 0, 0, 19, 32,116,111,108,117, 97, 95,103,108,111, 98, 97,108,118, 97,114, 40,
+ 34, 0, 2, 0, 0, 0, 11,117,110,114,101,103,105,115,116,101,114, 0, 4, 0,
+ 0, 0,171, 0, 0, 0, 14, 64,118, 97,114,105, 97, 98,108,101, 46,108,117, 97,
+ 0, 0, 0, 0, 52, 4, 1, 60,172, 13, 0, 20, 1, 2, 1, 1, 4, 0, 32, 48,
+ 10, 13, 0, 20, 2, 2, 1, 1, 4, 0, 32, 52, 19, 60,173, 15, 3, 11, 4, 13,
+ 0, 18, 5, 42, 11, 6, 42, 2, 0, 1, 50, 2, 60,174, 60,175, 0, 0, 0, 0,
+ 1, 0, 0, 0,171, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 7, 2, 0,
+ 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 8,105,110, 99,108, 97,115,115,
+ 0, 2, 0, 0, 0, 9,105,110,109,111,100,117,108,101, 0, 2, 0, 0, 0, 7,
+111,117,116,112,117,116, 0, 2, 0, 0, 0, 35, 32,108,117, 97, 95,112,117,115,
+104,110,105,108, 40, 41, 59, 32,108,117, 97, 95,114, 97,119,115,101,116,103,108,
+111, 98, 97,108, 40, 34, 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0,
+ 0, 0, 4, 34, 41, 59, 0, 2, 0, 0, 0, 10, 95, 86, 97,114,105, 97, 98,108,
+101, 0, 4, 0, 0, 0,179, 0, 0, 0, 14, 64,118, 97,114,105, 97, 98,108,101,
+ 46,108,117, 97, 0, 0, 0, 0, 40, 4, 1, 60,180, 13, 0, 11, 1, 15, 2, 26,
+ 60,181, 15, 3, 13, 0, 15, 4, 2, 0, 2, 60,182, 15, 5, 13, 0, 2, 0, 1,
+ 60,183, 13, 0, 1, 1, 60,184, 0, 0, 0, 0, 1, 0, 0, 0,179, 0, 0, 0,
+ 2,116, 0, 0, 0, 0, 6, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6, 95,
+ 98, 97,115,101, 0, 2, 0, 0, 0, 14, 99,108, 97,115,115, 86, 97,114,105, 97,
+ 98,108,101, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0,
+ 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 7, 97,112,112,101,
+110,100, 0, 2, 0, 0, 0, 9, 86, 97,114,105, 97, 98,108,101, 0, 4, 0, 0,
+ 0,188, 0, 0, 0, 14, 64,118, 97,114,105, 97, 98,108,101, 46,108,117, 97, 0,
+ 0, 0, 0, 21, 5, 1, 60,189, 15, 1, 15, 2, 13, 0, 11, 3, 2, 1, 2, 3,
+ 1, 1, 60,190, 0, 0, 0, 0, 1, 0, 0, 0,188, 0, 0, 0, 2,115, 0, 0,
+ 0, 0, 4, 2, 0, 0, 0, 2,115, 0, 2, 0, 0, 0, 10, 95, 86, 97,114,105,
+ 97, 98,108,101, 0, 2, 0, 0, 0, 12, 68,101, 99,108, 97,114, 97,116,105,111,
+110, 0, 2, 0, 0, 0, 4,118, 97,114, 0,
+};
+
+/* array.lo */
+static char B12[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 11, 64, 97,114,114, 97,121,
+ 46,108,117, 97, 0, 0, 0, 0, 87, 3, 0, 60, 18, 22, 1, 60, 19, 11, 1, 15,
+ 2, 30, 0, 60, 20, 25, 0, 60, 22, 15, 3, 15, 0, 15, 4, 2, 0, 2, 60, 25,
+ 15, 0, 11, 5, 11, 6, 26, 60, 38, 15, 0, 11, 7, 11, 8, 26, 60, 49, 15, 0,
+ 11, 9, 11, 10, 26, 60,167, 15, 0, 11, 11, 11, 12, 26, 60,184, 15, 0, 11, 13,
+ 11, 14, 26, 60,192, 11, 16, 25, 15, 60,201, 11, 18, 25, 17, 0, 0, 0, 0, 0,
+ 0, 0, 0, 19, 2, 0, 0, 0, 11, 99,108, 97,115,115, 65,114,114, 97,121, 0,
+ 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 17, 99,108, 97,115,
+115, 68,101, 99,108, 97,114, 97,116,105,111,110, 0, 2, 0, 0, 0, 7,115,101,
+116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0,
+ 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0, 0, 0, 25, 0, 0, 0, 11,
+ 64, 97,114,114, 97,121, 46,108,117, 97, 0, 0, 0, 0,172, 6, 3, 60, 26, 15,
+ 2, 13, 1, 11, 3, 42, 2, 0, 1, 60, 27, 15, 2, 13, 1, 11, 4, 42, 13, 0,
+ 18, 6, 42, 11, 7, 42, 2, 0, 1, 60, 28, 15, 2, 13, 1, 11, 8, 42, 13, 0,
+ 18, 9, 42, 11, 7, 42, 2, 0, 1, 60, 29, 15, 2, 13, 1, 11, 10, 42, 13, 0,
+ 18, 11, 42, 11, 7, 42, 2, 0, 1, 60, 30, 15, 2, 13, 1, 11, 12, 42, 13, 0,
+ 18, 13, 42, 11, 7, 42, 2, 0, 1, 60, 31, 15, 2, 13, 1, 11, 14, 42, 13, 0,
+ 18, 15, 42, 11, 7, 42, 2, 0, 1, 60, 32, 15, 2, 13, 1, 11, 16, 42, 13, 0,
+ 18, 17, 42, 11, 7, 42, 2, 0, 1, 60, 33, 15, 2, 13, 1, 11, 18, 42, 13, 0,
+ 18, 19, 42, 11, 7, 42, 2, 0, 1, 60, 34, 15, 2, 13, 1, 11, 20, 42, 13, 2,
+ 42, 2, 0, 1, 60, 35, 0, 0, 0, 0, 3, 0, 0, 0, 25, 0, 0, 0, 5,115,
+101,108,102, 0, 0, 0, 0, 25, 0, 0, 0, 6,105,100,101,110,116, 0, 0, 0,
+ 0, 25, 0, 0, 0, 6, 99,108,111,115,101, 0, 0, 0, 0, 21, 2, 0, 0, 0,
+ 6,105,100,101,110,116, 0, 2, 0, 0, 0, 6, 99,108,111,115,101, 0, 2, 0,
+ 0, 0, 6,112,114,105,110,116, 0, 2, 0, 0, 0, 7, 65,114,114, 97,121,123,
+ 0, 2, 0, 0, 0, 10, 32,109,111,100, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0,
+ 5,115,101,108,102, 0, 2, 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 3,
+ 39, 44, 0, 2, 0, 0, 0, 10, 32,116,121,112,101, 32, 61, 32, 39, 0, 2, 0,
+ 0, 0, 5,116,121,112,101, 0, 2, 0, 0, 0, 10, 32,112,116,114, 32, 32, 61,
+ 32, 39, 0, 2, 0, 0, 0, 4,112,116,114, 0, 2, 0, 0, 0, 10, 32,110, 97,
+109,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0,
+ 0, 10, 32,100,101,102, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 4,100,101,102,
+ 0, 2, 0, 0, 0, 10, 32,100,105,109, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0,
+ 4,100,105,109, 0, 2, 0, 0, 0, 10, 32,114,101,116, 32, 32, 61, 32, 39, 0,
+ 2, 0, 0, 0, 4,114,101,116, 0, 2, 0, 0, 0, 2,125, 0, 2, 0, 0, 0,
+ 9,103,101,116,118, 97,108,117,101, 0, 4, 0, 0, 0, 38, 0, 0, 0, 11, 64,
+ 97,114,114, 97,121, 46,108,117, 97, 0, 0, 0, 0, 69, 5, 3, 60, 39, 13, 1,
+ 48, 2, 13, 2, 52, 19, 60, 40, 13, 1, 11, 2, 42, 13, 0, 18, 4, 42, 11, 5,
+ 42, 1, 3, 50, 35, 60, 41, 13, 1, 52, 16, 60, 42, 11, 6, 13, 0, 18, 4, 42,
+ 11, 5, 42, 1, 3, 50, 13, 60, 44, 13, 0, 18, 4, 11, 5, 42, 1, 3, 60, 45,
+ 60, 46, 0, 0, 0, 0, 3, 0, 0, 0, 38, 0, 0, 0, 5,115,101,108,102, 0,
+ 0, 0, 0, 38, 0, 0, 0, 6, 99,108, 97,115,115, 0, 0, 0, 0, 38, 0, 0,
+ 0, 7,115,116, 97,116,105, 99, 0, 0, 0, 0, 7, 2, 0, 0, 0, 6, 99,108,
+ 97,115,115, 0, 2, 0, 0, 0, 7,115,116, 97,116,105, 99, 0, 2, 0, 0, 0,
+ 3, 58, 58, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,110,
+ 97,109,101, 0, 2, 0, 0, 0, 15, 91,116,111,108,117, 97, 73, 95,105,110,100,
+101,120, 93, 0, 2, 0, 0, 0, 7,115,101,108,102, 45, 62, 0, 2, 0, 0, 0,
+ 8,115,117,112, 99,111,100,101, 0, 4, 0, 0, 0, 49, 0, 0, 0, 11, 64, 97,
+114,114, 97,121, 46,108,117, 97, 0, 0, 0, 4, 21, 17, 1, 60, 50, 13, 0, 20,
+ 2, 2, 1, 1, 60, 53, 13, 1, 52, 21, 60, 54, 15, 3, 11, 4, 13, 0, 18, 5,
+ 11, 6, 13, 1, 11, 7, 2, 0, 5, 50, 17, 60, 56, 15, 3, 11, 4, 13, 0, 18,
+ 5, 11, 7, 2, 0, 3, 60, 57, 60, 58, 13, 0, 11, 8, 13, 0, 20, 9, 11, 10,
+ 2, 1, 2, 26, 60, 59, 15, 3, 11, 11, 13, 0, 18, 8, 11, 12, 2, 0, 3, 60,
+ 60, 15, 3, 11, 13, 2, 0, 1, 60, 63, 15, 3, 11, 14, 2, 0, 1, 60, 66, 15,
+ 17, 13, 0, 18, 18, 11, 19, 2, 3, 2, 60, 67, 13, 1, 48, 5, 13, 4, 4, 0,
+ 32, 52, 66, 60, 68, 15, 3, 11, 20, 13, 1, 11, 21, 11, 22, 2, 0, 4, 60, 69,
+ 15, 3, 11, 23, 2, 0, 1, 60, 70, 15, 3, 11, 24, 2, 0, 1, 60, 71, 15, 3,
+ 11, 25, 2, 0, 1, 60, 72, 15, 3, 11, 26, 13, 1, 11, 27, 2, 0, 3, 60, 73,
+ 15, 3, 11, 28, 2, 0, 1, 50, 35, 60, 74, 13, 4, 52, 27, 60, 75, 13, 0, 11,
+ 18, 15, 17, 13, 0, 18, 18, 11, 29, 2, 3, 2, 27, 2, 23, 3, 23, 3, 5, 2,
+ 50, 2, 60, 76, 60, 79, 15, 3, 11, 30, 2, 0, 1, 60, 80, 15, 3, 11, 31, 2,
+ 0, 1, 60, 81, 15, 3, 11, 32, 2, 0, 1, 60, 82, 15, 3, 11, 33, 13, 0, 18,
+ 34, 42, 11, 35, 42, 2, 0, 1, 60, 83, 15, 3, 11, 36, 2, 0, 1, 60, 86, 15,
+ 38, 13, 0, 18, 39, 2, 1, 1, 60, 87, 13, 5, 11, 40, 32, 52, 32, 60, 88, 15,
+ 3, 11, 41, 13, 5, 42, 11, 42, 42, 13, 0, 20, 43, 13, 1, 13, 4, 2, 1, 3,
+ 42, 11, 44, 42, 2, 0, 1, 50,124, 60, 89, 13, 5, 52, 32, 60, 90, 15, 3, 11,
+ 41, 13, 5, 42, 11, 26, 42, 13, 0, 20, 43, 13, 1, 13, 4, 2, 1, 3, 42, 11,
+ 44, 42, 2, 0, 1, 50, 86, 60, 92, 13, 0, 18, 45, 11, 46, 32, 46, 7, 13, 0,
+ 18, 45, 11, 47, 32, 52, 32, 60, 93, 15, 3, 11, 48, 13, 0, 20, 43, 13, 1, 13,
+ 4, 2, 1, 3, 42, 11, 49, 42, 13, 0, 18, 50, 11, 44, 2, 0, 3, 50, 32, 60,
+ 95, 15, 3, 11, 51, 13, 0, 20, 43, 13, 1, 13, 4, 2, 1, 3, 42, 11, 49, 42,
+ 13, 0, 18, 50, 11, 44, 2, 0, 3, 60, 96, 60, 97, 60, 98, 15, 3, 11, 52, 2,
+ 0, 1, 60, 99, 15, 3, 11, 53, 2, 0, 1, 60,102, 15, 17, 13, 0, 18, 18, 11,
+ 54, 2, 1, 2, 44, 51, 2, 33, 60,103, 13, 1, 52, 21, 60,104, 15, 3, 11, 55,
+ 13, 0, 18, 5, 11, 6, 13, 1, 11, 7, 2, 0, 5, 50, 17, 60,106, 15, 3, 11,
+ 55, 13, 0, 18, 5, 11, 7, 2, 0, 3, 60,107, 60,108, 13, 0, 11, 56, 13, 0,
+ 20, 9, 11, 57, 2, 1, 2, 26, 60,109, 15, 3, 11, 11, 13, 0, 18, 56, 11, 12,
+ 2, 0, 3, 60,110, 15, 3, 11, 13, 2, 0, 1, 60,113, 15, 3, 11, 14, 2, 0,
+ 1, 60,116, 15, 17, 13, 0, 18, 18, 11, 19, 2, 3, 2, 60,117, 13, 1, 48, 5,
+ 13, 8, 4, 0, 32, 52, 66, 60,118, 15, 3, 11, 20, 13, 1, 11, 21, 11, 22, 2,
+ 0, 4, 60,119, 15, 3, 11, 23, 2, 0, 1, 60,120, 15, 3, 11, 24, 2, 0, 1,
+ 60,121, 15, 3, 11, 25, 2, 0, 1, 60,122, 15, 3, 11, 26, 13, 1, 11, 27, 2,
+ 0, 3, 60,123, 15, 3, 11, 28, 2, 0, 1, 50, 35, 60,124, 13, 8, 52, 27, 60,
+125, 13, 0, 11, 18, 15, 17, 13, 0, 18, 18, 11, 29, 2, 3, 2, 27, 2, 23, 7,
+ 23, 7, 5, 2, 50, 2, 60,126, 60,129, 15, 3, 11, 30, 2, 0, 1, 60,130, 15,
+ 3, 11, 31, 2, 0, 1, 60,131, 15, 3, 11, 32, 2, 0, 1, 60,132, 15, 3, 11,
+ 33, 13, 0, 18, 34, 42, 11, 35, 42, 2, 0, 1, 60,133, 15, 3, 11, 36, 2, 0,
+ 1, 60,136, 11, 47, 60,137, 13, 0, 18, 45, 11, 47, 31, 52, 4, 11, 21, 23, 9,
+ 60,138, 15, 3, 11, 20, 2, 0, 1, 60,139, 13, 1, 48, 2, 13, 8, 52, 22, 60,
+140, 15, 3, 13, 1, 11, 58, 42, 13, 0, 18, 5, 42, 11, 59, 42, 2, 0, 1, 50,
+ 41, 60,141, 13, 1, 52, 19, 60,142, 15, 3, 11, 60, 13, 0, 18, 5, 42, 11, 59,
+ 42, 2, 0, 1, 50, 16, 60,144, 15, 3, 13, 0, 18, 5, 11, 59, 42, 2, 0, 1,
+ 60,145, 60,146, 15, 38, 13, 0, 18, 39, 2, 1, 1, 60,147, 15, 3, 11, 61, 2,
+ 0, 1, 60,148, 13, 10, 44, 48, 5, 13, 9, 11, 47, 32, 52, 7, 15, 3, 11, 21,
+ 2, 0, 1, 60,149, 15, 3, 11, 62, 13, 0, 18, 18, 13, 0, 18, 39, 2, 0, 3,
+ 60,150, 13, 10, 44, 52, 11, 60,151, 15, 3, 11, 21, 2, 0, 1, 50, 2, 60,152,
+ 60,153, 15, 3, 11, 63, 2, 0, 1, 60,154, 7, 0, 60,155, 13, 0, 18, 64, 11,
+ 47, 31, 52, 6, 13, 0, 18, 64, 23, 11, 60,156, 13, 10, 52, 20, 60,157, 15, 3,
+ 11, 65, 13, 10, 42, 11, 66, 13, 11, 11, 67, 2, 0, 4, 50, 15, 60,159, 15, 3,
+ 11, 68, 13, 11, 11, 67, 2, 0, 3, 60,160, 60,161, 15, 3, 11, 52, 2, 0, 1,
+ 60,162, 15, 3, 11, 53, 2, 0, 1, 5, 6, 50, 2, 60,163, 60,165, 0, 0, 0,
+ 0, 18, 0, 0, 0, 49, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 50, 0,
+ 0, 0, 6, 99,108, 97,115,115, 0, 0, 0, 0, 66, 0, 0, 0, 2, 95, 0, 0,
+ 0, 0, 66, 0, 0, 0, 2, 95, 0, 0, 0, 0, 66, 0, 0, 0, 7,115,116, 97,
+116,105, 99, 0, 0, 0, 0, 86, 0, 0, 0, 2,116, 0, 0, 0, 0,116, 0, 0,
+ 0, 2, 95, 0, 0, 0, 0,116, 0, 0, 0, 2, 95, 0, 0, 0, 0,116, 0, 0,
+ 0, 7,115,116, 97,116,105, 99, 0, 0, 0, 0,136, 0, 0, 0, 4,112,116,114,
+ 0, 0, 0, 0,146, 0, 0, 0, 2,116, 0, 0, 0, 0,154, 0, 0, 0, 4,100,
+101,102, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0,
+ 0, 0,162, 0, 0, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0,162, 0,
+ 0, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0, 69, 2, 0, 0, 0, 6,
+ 99,108, 97,115,115, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0,
+ 8,105,110, 99,108, 97,115,115, 0, 2, 0, 0, 0, 7,111,117,116,112,117,116,
+ 0, 2, 0, 0, 0, 17, 47, 42, 32,103,101,116, 32,102,117,110, 99,116,105,111,
+110, 58, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 11, 32,111,
+102, 32, 99,108, 97,115,115, 32, 0, 2, 0, 0, 0, 4, 32, 42, 47, 0, 2, 0,
+ 0, 0, 9, 99,103,101,116,110, 97,109,101, 0, 2, 0, 0, 0, 10, 99,102,117,
+110, 99,110, 97,109,101, 0, 2, 0, 0, 0, 11,116,111,108,117, 97, 73, 95,103,
+101,116, 0, 2, 0, 0, 0, 12,115,116, 97,116,105, 99, 32,118,111,105,100, 0,
+ 2, 0, 0, 0, 7, 40,118,111,105,100, 41, 0, 2, 0, 0, 0, 2,123, 0, 2,
+ 0, 0, 0, 19, 32,105,110,116, 32,116,111,108,117, 97, 73, 95,105,110,100,101,
+120, 59, 0, 2, 0, 0, 0, 2, 95, 0, 2, 0, 0, 0, 7,115,116, 97,116,105,
+ 99, 0, 2, 0, 0, 0, 8,115,116,114,102,105,110,100, 0, 2, 0, 0, 0, 4,
+109,111,100, 0, 2, 0, 0, 0, 13, 94, 37,115, 42, 40,115,116, 97,116,105, 99,
+ 41, 0, 2, 0, 0, 0, 2, 32, 0, 2, 0, 0, 0, 2, 42, 0, 2, 0, 0, 0,
+ 6,115,101,108,102, 59, 0, 2, 0, 0, 0, 34, 32,108,117, 97, 95,112,117,115,
+104,111, 98,106,101, 99,116, 40,108,117, 97, 95,103,101,116,112, 97,114, 97,109,
+ 40, 49, 41, 41, 59, 0, 2, 0, 0, 0, 26, 32,108,117, 97, 95,112,117,115,104,
+115,116,114,105,110,103, 40, 34, 46,115,101,108,102, 34, 41, 59, 0, 2, 0, 0,
+ 0, 9, 32,115,101,108,102, 32, 61, 32, 0, 2, 0, 0, 0, 2, 40, 0, 2, 0,
+ 0, 0, 4, 42, 41, 32, 0, 2, 0, 0, 0, 36,108,117, 97, 95,103,101,116,117,
+115,101,114,100, 97,116, 97, 40,108,117, 97, 95,114, 97,119,103,101,116,116, 97,
+ 98,108,101, 40, 41, 41, 59, 0, 2, 0, 0, 0, 20, 94, 37,115, 42,115,116, 97,
+116,105, 99, 37,115, 37,115, 42, 40, 46, 42, 41, 0, 2, 0, 0, 0, 42, 32,105,
+102, 32, 40, 33,116,111,108,117, 97, 95,105,115,116,121,112,101, 40, 50, 44,116,
+111,108,117, 97, 95,116, 97,103, 95,110,117,109, 98,101,114, 44, 48, 41, 41, 0,
+ 2, 0, 0, 0, 50, 32, 32,116,111,108,117, 97, 95,101,114,114,111,114, 40, 34,
+105,110,118, 97,108,105,100, 32,116,121,112,101, 32,105,110, 32, 97,114,114, 97,
+121, 32,105,110,100,101,120,105,110,103, 46, 34, 41, 59, 0, 2, 0, 0, 0, 45,
+ 32,116,111,108,117, 97, 73, 95,105,110,100,101,120, 32, 61, 32, 40,105,110,116,
+ 41,116,111,108,117, 97, 95,103,101,116,110,117,109, 98,101,114, 40, 50, 44, 48,
+ 41, 45, 49, 59, 0, 2, 0, 0, 0, 38, 32,105,102, 32, 40,116,111,108,117, 97,
+ 73, 95,105,110,100,101,120, 60, 48, 32,124,124, 32,116,111,108,117, 97, 73, 95,
+105,110,100,101,120, 62, 61, 0, 2, 0, 0, 0, 4,100,105,109, 0, 2, 0, 0,
+ 0, 2, 41, 0, 2, 0, 0, 0, 47, 32, 32,116,111,108,117, 97, 95,101,114,114,
+111,114, 40, 34, 97,114,114, 97,121, 32,105,110,100,101,120,105,110,103, 32,111,
+117,116, 32,111,102, 32,114, 97,110,103,101, 46, 34, 41, 59, 0, 2, 0, 0, 0,
+ 2,116, 0, 2, 0, 0, 0, 8,105,115, 98, 97,115,105, 99, 0, 2, 0, 0, 0,
+ 5,116,121,112,101, 0, 2, 0, 0, 0, 7,110,117,109, 98,101,114, 0, 2, 0,
+ 0, 0, 13, 32, 32,116,111,108,117, 97, 95,112,117,115,104, 0, 2, 0, 0, 0,
+ 10, 40, 40,100,111,117, 98,108,101, 41, 0, 2, 0, 0, 0, 9,103,101,116,118,
+ 97,108,117,101, 0, 2, 0, 0, 0, 3, 41, 59, 0, 2, 0, 0, 0, 4,112,116,
+114, 0, 2, 0, 0, 0, 2, 38, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 30,
+ 32, 32,116,111,108,117, 97, 95,112,117,115,104,117,115,101,114,116,121,112,101,
+ 40, 40,118,111,105,100, 42, 41, 38, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0, 0,
+ 0, 4,116, 97,103, 0, 2, 0, 0, 0, 29, 32, 32,116,111,108,117, 97, 95,112,
+117,115,104,117,115,101,114,116,121,112,101, 40, 40,118,111,105,100, 42, 41, 0,
+ 2, 0, 0, 0, 2,125, 0, 2, 0, 0, 0, 2, 10, 0, 2, 0, 0, 0, 6, 99,
+111,110,115,116, 0, 2, 0, 0, 0, 17, 47, 42, 32,115,101,116, 32,102,117,110,
+ 99,116,105,111,110, 58, 0, 2, 0, 0, 0, 9, 99,115,101,116,110, 97,109,101,
+ 0, 2, 0, 0, 0, 11,116,111,108,117, 97, 73, 95,115,101,116, 0, 2, 0, 0,
+ 0, 3, 58, 58, 0, 2, 0, 0, 0, 15, 91,116,111,108,117, 97, 73, 95,105,110,
+100,101,120, 93, 0, 2, 0, 0, 0, 7,115,101,108,102, 45, 62, 0, 2, 0, 0,
+ 0, 4, 32, 61, 32, 0, 2, 0, 0, 0, 3, 40, 40, 0, 2, 0, 0, 0, 3, 41,
+ 32, 0, 2, 0, 0, 0, 4,100,101,102, 0, 2, 0, 0, 0, 10,116,111,108,117,
+ 97, 95,103,101,116, 0, 2, 0, 0, 0, 4, 40, 51, 44, 0, 2, 0, 0, 0, 4,
+ 41, 41, 59, 0, 2, 0, 0, 0, 21,116,111,108,117, 97, 95,103,101,116,117,115,
+101,114,116,121,112,101, 40, 51, 44, 0, 2, 0, 0, 0, 9,114,101,103,105,115,
+116,101,114, 0, 4, 0, 0, 0,167, 0, 0, 0, 11, 64, 97,114,114, 97,121, 46,
+108,117, 97, 0, 0, 0, 0,185, 5, 1, 60,168, 13, 0, 20, 2, 2, 1, 1, 46,
+ 7, 13, 0, 20, 3, 2, 1, 1, 60,169, 13, 1, 52, 84, 60,170, 13, 0, 18, 4,
+ 52, 41, 60,171, 15, 5, 11, 6, 13, 1, 42, 11, 7, 42, 13, 0, 18, 8, 42, 11,
+ 9, 42, 13, 0, 18, 10, 42, 11, 11, 42, 13, 0, 18, 4, 42, 11, 12, 42, 2, 0,
+ 1, 50, 33, 60,173, 15, 5, 11, 6, 13, 1, 42, 11, 7, 42, 13, 0, 18, 8, 42,
+ 11, 9, 42, 13, 0, 18, 10, 42, 11, 13, 42, 2, 0, 1, 60,174, 50, 72, 60,176,
+ 13, 0, 18, 4, 52, 35, 60,177, 15, 5, 11, 14, 13, 0, 18, 8, 42, 11, 9, 42,
+ 13, 0, 18, 10, 42, 11, 11, 42, 13, 0, 18, 4, 42, 11, 12, 42, 2, 0, 1, 50,
+ 27, 60,179, 15, 5, 11, 14, 13, 0, 18, 8, 42, 11, 9, 42, 13, 0, 18, 10, 42,
+ 11, 13, 42, 2, 0, 1, 60,180, 60,181, 60,182, 0, 0, 0, 0, 2, 0, 0, 0,
+167, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0,168, 0, 0, 0, 7,112, 97,
+114,101,110,116, 0, 0, 0, 0, 15, 2, 0, 0, 0, 7,112, 97,114,101,110,116,
+ 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 8,105,110, 99,108,
+ 97,115,115, 0, 2, 0, 0, 0, 9,105,110,109,111,100,117,108,101, 0, 2, 0,
+ 0, 0, 9, 99,115,101,116,110, 97,109,101, 0, 2, 0, 0, 0, 7,111,117,116,
+112,117,116, 0, 2, 0, 0, 0, 20, 32,116,111,108,117, 97, 95,116, 97, 98,108,
+101, 97,114,114, 97,121, 40, 34, 0, 2, 0, 0, 0, 4, 34, 44, 34, 0, 2, 0,
+ 0, 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0, 3, 34, 44, 0, 2, 0, 0,
+ 0, 9, 99,103,101,116,110, 97,109,101, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0,
+ 0, 0, 3, 41, 59, 0, 2, 0, 0, 0, 8, 44, 78, 85, 76, 76, 41, 59, 0, 2,
+ 0, 0, 0, 21, 32,116,111,108,117, 97, 95,103,108,111, 98, 97,108, 97,114,114,
+ 97,121, 40, 34, 0, 2, 0, 0, 0, 11,117,110,114,101,103,105,115,116,101,114,
+ 0, 4, 0, 0, 0,184, 0, 0, 0, 11, 64, 97,114,114, 97,121, 46,108,117, 97,
+ 0, 0, 0, 0, 52, 4, 1, 60,185, 13, 0, 20, 1, 2, 1, 1, 4, 0, 32, 48,
+ 10, 13, 0, 20, 2, 2, 1, 1, 4, 0, 32, 52, 19, 60,186, 15, 3, 11, 4, 13,
+ 0, 18, 5, 42, 11, 6, 42, 2, 0, 1, 50, 2, 60,187, 60,188, 0, 0, 0, 0,
+ 1, 0, 0, 0,184, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 7, 2, 0,
+ 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 8,105,110, 99,108, 97,115,115,
+ 0, 2, 0, 0, 0, 9,105,110,109,111,100,117,108,101, 0, 2, 0, 0, 0, 7,
+111,117,116,112,117,116, 0, 2, 0, 0, 0, 32, 32,108,117, 97, 95,112,117,115,
+104,110,105,108, 40, 41, 59, 32,108,117, 97, 95,115,101,116,103,108,111, 98, 97,
+108, 40, 34, 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0, 4,
+ 34, 41, 59, 0, 2, 0, 0, 0, 7, 95, 65,114,114, 97,121, 0, 4, 0, 0, 0,
+192, 0, 0, 0, 11, 64, 97,114,114, 97,121, 46,108,117, 97, 0, 0, 0, 0, 40,
+ 4, 1, 60,193, 13, 0, 11, 1, 15, 2, 26, 60,194, 15, 3, 13, 0, 15, 4, 2,
+ 0, 2, 60,195, 15, 5, 13, 0, 2, 0, 1, 60,196, 13, 0, 1, 1, 60,197, 0,
+ 0, 0, 0, 1, 0, 0, 0,192, 0, 0, 0, 2,116, 0, 0, 0, 0, 6, 2, 0,
+ 0, 0, 2,116, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0,
+ 11, 99,108, 97,115,115, 65,114,114, 97,121, 0, 2, 0, 0, 0, 7,115,101,116,
+116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0, 2,
+ 0, 0, 0, 7, 97,112,112,101,110,100, 0, 2, 0, 0, 0, 6, 65,114,114, 97,
+121, 0, 4, 0, 0, 0,201, 0, 0, 0, 11, 64, 97,114,114, 97,121, 46,108,117,
+ 97, 0, 0, 0, 0, 21, 5, 1, 60,202, 15, 1, 15, 2, 13, 0, 11, 3, 2, 1,
+ 2, 3, 1, 1, 60,203, 0, 0, 0, 0, 1, 0, 0, 0,201, 0, 0, 0, 2,115,
+ 0, 0, 0, 0, 4, 2, 0, 0, 0, 2,115, 0, 2, 0, 0, 0, 7, 95, 65,114,
+114, 97,121, 0, 2, 0, 0, 0, 12, 68,101, 99,108, 97,114, 97,116,105,111,110,
+ 0, 2, 0, 0, 0, 4,118, 97,114, 0,
+};
+
+/* function.lo */
+static char B13[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 14, 64,102,117,110, 99,116,
+105,111,110, 46,108,117, 97, 0, 0, 0, 0,141, 15, 0, 60, 24, 22, 7, 60, 25,
+ 11, 1, 11, 2, 11, 3, 60, 26, 11, 2, 11, 4, 60, 27, 11, 2, 11, 5, 60, 28,
+ 11, 2, 11, 6, 60, 29, 22, 1, 11, 7, 7, 0, 30, 0, 11, 8, 60, 30, 11, 2,
+ 11, 9, 60, 31, 15, 10, 30, 6, 60, 32, 25, 0, 60, 33, 15, 11, 15, 0, 15, 12,
+ 2, 0, 2, 60, 36, 15, 0, 11, 13, 11, 14, 26, 60, 51, 15, 0, 11, 15, 11, 16,
+ 26, 60,232, 15, 0, 11, 17, 11, 18, 26, 60,242, 15, 0, 11, 19, 11, 20, 26, 60,
+250, 15, 0, 11, 21, 11, 22, 26, 59, 1, 14, 15, 0, 11, 23, 11, 24, 26, 59, 1,
+ 21, 11, 26, 25, 25, 59, 1, 49, 11, 28, 25, 27, 0, 0, 0, 0, 0, 0, 0, 0,
+ 29, 2, 0, 0, 0, 14, 99,108, 97,115,115, 70,117,110, 99,116,105,111,110, 0,
+ 2, 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 5,
+116,121,112,101, 0, 2, 0, 0, 0, 4,112,116,114, 0, 2, 0, 0, 0, 5,110,
+ 97,109,101, 0, 2, 0, 0, 0, 5, 97,114,103,115, 0, 2, 0, 0, 0, 2,110,
+ 0, 2, 0, 0, 0, 6, 99,111,110,115,116, 0, 2, 0, 0, 0, 6, 95, 98, 97,
+115,101, 0, 2, 0, 0, 0, 13, 99,108, 97,115,115, 70,101, 97,116,117,114,101,
+ 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,
+108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 8,100,101, 99,108,116, 97,103,
+ 0, 4, 0, 0, 0, 36, 0, 0, 0, 14, 64,102,117,110, 99,116,105,111,110, 46,
+108,117, 97, 0, 0, 0, 0,141, 10, 1, 60, 37, 13, 0, 20, 1, 2, 1, 1, 48,
+ 7, 13, 0, 18, 2, 11, 2, 32, 52, 21, 60, 38, 15, 3, 13, 0, 18, 4, 18, 5,
+ 13, 0, 18, 4, 18, 6, 2, 0, 2, 50, 2, 60, 39, 60, 40, 13, 0, 11, 7, 13,
+ 0, 11, 8, 15, 9, 13, 0, 18, 10, 15, 11, 13, 0, 18, 12, 11, 2, 2, 1, 2,
+ 2, 2, 2, 27, 1, 27, 2, 5, 4, 60, 41, 15, 3, 13, 0, 18, 7, 13, 0, 18,
+ 8, 2, 0, 2, 60, 42, 7, 1, 50, 25, 60, 44, 13, 0, 18, 14, 13, 1, 16, 20,
+ 3, 2, 0, 1, 60, 45, 13, 1, 7, 1, 37, 23, 1, 60, 46, 60, 43, 13, 0, 18,
+ 14, 13, 1, 16, 54, 36, 60, 47, 0, 0, 0, 0, 2, 0, 0, 0, 36, 0, 0, 0,
+ 5,115,101,108,102, 0, 0, 0, 0, 42, 0, 0, 0, 2,105, 0, 0, 0, 0, 15,
+ 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 8,105,110, 99,108, 97,
+115,115, 0, 2, 0, 0, 0, 6, 99,111,110,115,116, 0, 2, 0, 0, 0, 8,100,
+101, 99,108,116, 97,103, 0, 2, 0, 0, 0, 7,112, 97,114,101,110,116, 0, 2,
+ 0, 0, 0, 7, 99,105,116,121,112,101, 0, 2, 0, 0, 0, 5, 99,116, 97,103,
+ 0, 2, 0, 0, 0, 6,105,116,121,112,101, 0, 2, 0, 0, 0, 4,116, 97,103,
+ 0, 2, 0, 0, 0, 7,116, 97,103,118, 97,114, 0, 2, 0, 0, 0, 5,116,121,
+112,101, 0, 2, 0, 0, 0, 8,115,116,114,102,105,110,100, 0, 2, 0, 0, 0,
+ 4,109,111,100, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 5, 97,114,103,
+115, 0, 2, 0, 0, 0, 8,115,117,112, 99,111,100,101, 0, 4, 0, 0, 0, 51,
+ 0, 0, 0, 14, 64,102,117,110, 99,116,105,111,110, 46,108,117, 97, 0, 0, 0,
+ 6, 51, 15, 1, 60, 52, 13, 0, 20, 2, 2, 1, 1, 60, 53, 15, 5, 13, 0, 18,
+ 6, 11, 7, 2, 3, 2, 60, 55, 13, 1, 52, 21, 60, 56, 15, 8, 11, 9, 13, 0,
+ 18, 10, 11, 11, 13, 1, 11, 12, 2, 0, 5, 50, 17, 60, 58, 15, 8, 11, 13, 13,
+ 0, 18, 10, 11, 12, 2, 0, 3, 60, 59, 60, 60, 15, 8, 11, 14, 13, 0, 18, 15,
+ 11, 16, 2, 0, 3, 60, 61, 15, 8, 11, 17, 2, 0, 1, 60, 64, 15, 8, 11, 18,
+ 2, 0, 1, 60, 66, 4, 0, 60, 67, 13, 1, 52, 6, 7, 2, 23, 5, 50, 4, 7,
+ 1, 23, 5, 60, 68, 13, 1, 48, 7, 13, 0, 18, 10, 11, 20, 31, 48, 5, 13, 4,
+ 4, 0, 32, 52, 51, 60, 69, 13, 0, 18, 21, 11, 21, 32, 52, 19, 60, 70, 15, 8,
+ 11, 22, 13, 0, 18, 23, 18, 24, 11, 25, 2, 0, 3, 50, 19, 60, 72, 15, 8, 11,
+ 22, 13, 0, 18, 23, 18, 26, 11, 25, 2, 0, 3, 60, 73, 50, 2, 60, 74, 60, 76,
+ 13, 0, 18, 27, 7, 1, 16, 18, 28, 11, 29, 31, 52, 93, 60, 77, 7, 1, 50, 72,
+ 60, 79, 15, 31, 13, 0, 18, 27, 13, 6, 16, 18, 28, 2, 1, 1, 11, 32, 31, 52,
+ 29, 60, 80, 15, 8, 11, 33, 13, 0, 18, 27, 13, 6, 16, 20, 34, 13, 5, 2, 1,
+ 2, 42, 11, 35, 42, 2, 0, 1, 50, 2, 60, 81, 60, 82, 13, 5, 7, 1, 37, 23,
+ 5, 60, 83, 13, 6, 7, 1, 37, 23, 6, 60, 84, 60, 78, 13, 0, 18, 27, 13, 6,
+ 16, 54, 83, 5, 1, 50, 2, 60, 85, 60, 87, 15, 8, 11, 36, 13, 5, 42, 11, 37,
+ 42, 2, 0, 1, 60, 89, 15, 8, 11, 38, 2, 0, 1, 60, 92, 4, 0, 60, 93, 13,
+ 1, 52, 6, 7, 2, 23, 6, 50, 4, 7, 1, 23, 6, 60, 94, 13, 1, 48, 7, 13,
+ 0, 18, 10, 11, 20, 31, 48, 5, 13, 4, 4, 0, 32, 52, 47, 60, 95, 15, 8, 11,
+ 39, 13, 0, 18, 21, 13, 1, 11, 40, 11, 41, 2, 0, 5, 60, 96, 15, 8, 11, 42,
+ 13, 0, 18, 21, 13, 1, 11, 43, 2, 0, 4, 60, 97, 15, 8, 11, 44, 2, 0, 1,
+ 50, 35, 60, 98, 13, 4, 52, 27, 60, 99, 13, 0, 11, 6, 15, 5, 13, 0, 18, 6,
+ 11, 45, 2, 3, 2, 27, 2, 23, 3, 23, 3, 5, 2, 50, 2, 60,100, 60,102, 13,
+ 0, 18, 27, 7, 1, 16, 18, 28, 11, 29, 31, 52, 57, 60,103, 7, 1, 50, 36, 60,
+105, 13, 0, 18, 27, 13, 7, 16, 20, 46, 13, 6, 2, 0, 2, 60,106, 13, 6, 7,
+ 1, 37, 23, 6, 60,107, 13, 7, 7, 1, 37, 23, 7, 60,108, 60,104, 13, 0, 18,
+ 27, 13, 7, 16, 54, 47, 5, 1, 50, 2, 60,109, 60,112, 13, 1, 48, 7, 13, 0,
+ 18, 10, 11, 20, 31, 48, 5, 13, 4, 4, 0, 32, 52, 19, 60,113, 15, 8, 11, 47,
+ 13, 0, 18, 10, 42, 11, 48, 42, 2, 0, 1, 50, 2, 60,114, 60,117, 13, 1, 52,
+ 6, 7, 2, 23, 6, 50, 4, 7, 1, 23, 6, 60,118, 13, 0, 18, 27, 7, 1, 16,
+ 18, 28, 11, 29, 31, 52, 57, 60,119, 7, 1, 50, 36, 60,121, 13, 0, 18, 27, 13,
+ 7, 16, 20, 49, 13, 6, 2, 0, 2, 60,122, 13, 6, 7, 1, 37, 23, 6, 60,123,
+ 13, 7, 7, 1, 37, 23, 7, 60,124, 60,120, 13, 0, 18, 27, 13, 7, 16, 54, 47,
+ 5, 1, 50, 2, 60,125, 60,128, 13, 1, 48, 7, 13, 0, 18, 10, 11, 50, 32, 52,
+ 12, 60,129, 15, 8, 11, 51, 2, 0, 1, 49, 2,252, 60,130, 13, 1, 48, 7, 13,
+ 0, 18, 10, 11, 52, 32, 52, 34, 60,131, 15, 8, 11, 53, 13, 0, 18, 27, 7, 1,
+ 16, 18, 10, 11, 54, 13, 0, 18, 27, 7, 2, 16, 18, 10, 11, 55, 2, 0, 5, 49,
+ 2,203, 60,133, 15, 8, 11, 56, 2, 0, 1, 60,134, 13, 0, 18, 28, 11, 57, 31,
+ 48, 7, 13, 0, 18, 28, 11, 29, 31, 52, 48, 60,135, 15, 8, 11, 58, 13, 0, 18,
+ 6, 13, 0, 18, 28, 13, 0, 18, 59, 11, 60, 2, 0, 5, 60,136, 15, 8, 11, 42,
+ 13, 0, 18, 6, 13, 0, 18, 28, 13, 0, 18, 59, 11, 61, 2, 0, 5, 50, 11, 60,
+138, 15, 8, 11, 58, 2, 0, 1, 60,139, 60,140, 13, 1, 48, 7, 13, 0, 18, 10,
+ 11, 20, 32, 52, 15, 60,141, 15, 8, 11, 20, 13, 1, 11, 42, 2, 0, 3, 50, 70,
+ 60,142, 13, 1, 48, 2, 13, 4, 52, 21, 60,143, 15, 8, 13, 1, 11, 62, 42, 13,
+ 0, 18, 10, 42, 11, 42, 2, 0, 2, 50, 39, 60,144, 13, 1, 52, 18, 60,145, 15,
+ 8, 11, 63, 13, 0, 18, 10, 42, 11, 42, 2, 0, 2, 50, 15, 60,147, 15, 8, 13,
+ 0, 18, 10, 11, 42, 2, 0, 2, 60,148, 60,151, 7, 1, 50, 49, 60,153, 13, 0,
+ 18, 27, 13, 7, 16, 20, 64, 2, 0, 1, 60,154, 13, 7, 7, 1, 37, 23, 7, 60,
+155, 13, 0, 18, 27, 13, 7, 16, 52, 11, 60,156, 15, 8, 11, 65, 2, 0, 1, 50,
+ 2, 60,157, 60,158, 60,152, 13, 0, 18, 27, 13, 7, 16, 54, 60, 60,160, 15, 8,
+ 11, 66, 2, 0, 1, 60,163, 13, 0, 18, 28, 11, 57, 31, 48, 7, 13, 0, 18, 28,
+ 11, 29, 31, 52,220, 60,164, 15, 31, 13, 0, 18, 28, 2, 1, 1, 60,165, 13, 8,
+ 11, 68, 32, 52, 17, 60,166, 15, 8, 11, 69, 13, 8, 42, 11, 70, 42, 2, 0, 1,
+ 50,179, 60,167, 13, 8, 52, 17, 60,168, 15, 8, 11, 69, 13, 8, 42, 11, 71, 42,
+ 2, 0, 1, 50,156, 60,170, 13, 0, 18, 59, 11, 57, 32, 52, 98, 60,171, 15, 8,
+ 11, 72, 2, 0, 1, 60,172, 15, 8, 11, 73, 2, 0, 1, 60,173, 15, 8, 11, 74,
+ 13, 0, 18, 28, 11, 71, 2, 0, 3, 60,174, 15, 8, 11, 75, 2, 0, 1, 60,175,
+ 15, 8, 11, 76, 13, 0, 18, 28, 11, 77, 2, 0, 3, 60,176, 15, 8, 11, 78, 2,
+ 0, 1, 60,177, 15, 8, 11, 79, 13, 0, 18, 26, 11, 80, 13, 0, 18, 26, 11, 66,
+ 2, 0, 5, 60,178, 15, 8, 11, 81, 2, 0, 1, 50, 45, 60,180, 13, 0, 18, 59,
+ 11, 82, 32, 52, 17, 60,181, 15, 8, 11, 83, 13, 0, 18, 26, 11, 66, 2, 0, 3,
+ 50, 17, 60,183, 15, 8, 11, 84, 13, 0, 18, 26, 11, 66, 2, 0, 3, 60,184, 60,
+185, 5, 1, 50, 2, 60,186, 60,187, 7, 1, 50, 25, 60,189, 13, 0, 18, 27, 13,
+ 8, 16, 20, 85, 2, 0, 1, 60,190, 13, 8, 7, 1, 37, 23, 8, 60,191, 60,188,
+ 13, 0, 18, 27, 13, 8, 16, 54, 36, 60,192, 15, 8, 11, 86, 2, 0, 1, 60,195,
+ 13, 1, 52, 6, 7, 2, 23, 6, 50, 4, 7, 1, 23, 6, 60,196, 13, 0, 18, 27,
+ 7, 1, 16, 18, 28, 11, 29, 31, 52, 57, 60,197, 7, 1, 50, 36, 60,199, 13, 0,
+ 18, 27, 13, 9, 16, 20, 87, 13, 6, 2, 0, 2, 60,200, 13, 6, 7, 1, 37, 23,
+ 6, 60,201, 13, 9, 7, 1, 37, 23, 9, 60,202, 60,198, 13, 0, 18, 27, 13, 9,
+ 16, 54, 47, 5, 1, 50, 2, 60,203, 60,206, 13, 0, 18, 27, 7, 1, 16, 18, 28,
+ 11, 29, 31, 52, 46, 60,207, 7, 1, 50, 25, 60,209, 13, 0, 18, 27, 13, 9, 16,
+ 20, 88, 2, 0, 1, 60,210, 13, 9, 7, 1, 37, 23, 9, 60,211, 60,208, 13, 0,
+ 18, 27, 13, 9, 16, 54, 36, 5, 1, 50, 2, 60,212, 5, 2, 60,213, 60,215, 15,
+ 8, 11, 89, 2, 0, 1, 60,216, 15, 8, 11, 90, 2, 0, 1, 60,219, 15, 8, 11,
+ 91, 2, 0, 1, 60,220, 15, 93, 13, 0, 18, 15, 9, 2, 9, 1, 2, 1, 3, 7,
+ 1, 38, 60,221, 13, 7, 7, 0, 36, 52, 38, 60,222, 15, 8, 11, 39, 15, 93, 13,
+ 0, 18, 15, 7, 1, 9, 3, 2, 1, 3, 42, 15, 94, 11, 95, 13, 7, 2, 1, 2,
+ 42, 11, 96, 42, 2, 0, 1, 50, 19, 60,224, 15, 8, 11, 97, 13, 0, 18, 98, 42,
+ 11, 99, 42, 2, 0, 1, 60,225, 60,227, 15, 8, 11,100, 2, 0, 1, 60,228, 15,
+ 8, 11,101, 2, 0, 1, 60,229, 0, 0, 0, 0, 24, 0, 0, 0, 51, 0, 0, 0,
+ 5,115,101,108,102, 0, 0, 0, 0, 52, 0, 0, 0, 6, 99,108, 97,115,115, 0,
+ 0, 0, 0, 53, 0, 0, 0, 2, 95, 0, 0, 0, 0, 53, 0, 0, 0, 2, 95, 0,
+ 0, 0, 0, 53, 0, 0, 0, 7,115,116, 97,116,105, 99, 0, 0, 0, 0, 66, 0,
+ 0, 0, 5,110, 97,114,103, 0, 0, 0, 0, 77, 0, 0, 0, 2,105, 0, 0, 0,
+ 0, 84, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 5,110, 97,114,103, 0, 0,
+ 0, 0,103, 0, 0, 0, 2,105, 0, 0, 0, 0,108, 0, 0, 0, 0, 0, 0, 0,
+119, 0, 0, 0, 2,105, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0,151, 0,
+ 0, 0, 2,105, 0, 0, 0, 0,164, 0, 0, 0, 2,116, 0, 0, 0, 0,185, 0,
+ 0, 0, 0, 0, 0, 0,187, 0, 0, 0, 2,105, 0, 0, 0, 0,197, 0, 0, 0,
+ 2,105, 0, 0, 0, 0,202, 0, 0, 0, 0, 0, 0, 0,207, 0, 0, 0, 2,105,
+ 0, 0, 0, 0,211, 0, 0, 0, 0, 0, 0, 0,212, 0, 0, 0, 0, 0, 0, 0,
+212, 0, 0, 0, 0, 0, 0, 0,220, 0, 0, 0, 9,111,118,101,114,108,111, 97,
+100, 0, 0, 0, 0,102, 2, 0, 0, 0, 6, 99,108, 97,115,115, 0, 2, 0, 0,
+ 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 8,105,110, 99,108, 97,115,115, 0,
+ 2, 0, 0, 0, 2, 95, 0, 2, 0, 0, 0, 7,115,116, 97,116,105, 99, 0, 2,
+ 0, 0, 0, 8,115,116,114,102,105,110,100, 0, 2, 0, 0, 0, 4,109,111,100,
+ 0, 2, 0, 0, 0, 13, 94, 37,115, 42, 40,115,116, 97,116,105, 99, 41, 0, 2,
+ 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 11, 47, 42, 32,109,
+101,116,104,111,100, 58, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0,
+ 0, 11, 32,111,102, 32, 99,108, 97,115,115, 32, 0, 2, 0, 0, 0, 4, 32, 42,
+ 47, 0, 2, 0, 0, 0, 13, 47, 42, 32,102,117,110, 99,116,105,111,110, 58, 0,
+ 2, 0, 0, 0, 12,115,116, 97,116,105, 99, 32,118,111,105,100, 0, 2, 0, 0,
+ 0, 6, 99,110, 97,109,101, 0, 2, 0, 0, 0, 7, 40,118,111,105,100, 41, 0,
+ 2, 0, 0, 0, 2,123, 0, 2, 0, 0, 0, 7, 32,105,102, 32, 40, 10, 0, 2,
+ 0, 0, 0, 5,110, 97,114,103, 0, 2, 0, 0, 0, 4,110,101,119, 0, 2, 0,
+ 0, 0, 6, 99,111,110,115,116, 0, 2, 0, 0, 0, 22, 32, 32, 32, 32, 32, 33,
+116,111,108,117, 97, 95,105,115,116,121,112,101, 40, 49, 44, 0, 2, 0, 0, 0,
+ 7,112, 97,114,101,110,116, 0, 2, 0, 0, 0, 5, 99,116, 97,103, 0, 2, 0,
+ 0, 0, 8, 44, 48, 41, 32,124,124, 10, 0, 2, 0, 0, 0, 4,116, 97,103, 0,
+ 2, 0, 0, 0, 5, 97,114,103,115, 0, 2, 0, 0, 0, 5,116,121,112,101, 0,
+ 2, 0, 0, 0, 5,118,111,105,100, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0,
+ 0, 8,105,115, 98, 97,115,105, 99, 0, 2, 0, 0, 0, 7,111, 98,106,101, 99,
+116, 0, 2, 0, 0, 0, 7, 32, 32, 32, 32, 32, 33, 0, 2, 0, 0, 0, 13,111,
+117,116, 99,104,101, 99,107,116,121,112,101, 0, 2, 0, 0, 0, 5, 32,124,124,
+ 10, 0, 2, 0, 0, 0, 21, 32, 32, 32, 32, 32, 33,116,111,108,117, 97, 95,105,
+115,110,111,111, 98,106, 40, 0, 2, 0, 0, 0, 19, 41, 10, 32, 41, 10, 32, 32,
+103,111,116,111, 32,101,114,114,111,114, 59, 0, 2, 0, 0, 0, 9, 32,101,108,
+115,101, 10, 32,123, 0, 2, 0, 0, 0, 2, 32, 0, 2, 0, 0, 0, 2, 42, 0,
+ 2, 0, 0, 0, 8,115,101,108,102, 32, 61, 32, 0, 2, 0, 0, 0, 2, 40, 0,
+ 2, 0, 0, 0, 3, 42, 41, 0, 2, 0, 0, 0, 24,116,111,108,117, 97, 95,103,
+101,116,117,115,101,114,116,121,112,101, 40, 49, 44, 48, 41, 59, 0, 2, 0, 0,
+ 0, 20, 94, 37,115, 42,115,116, 97,116,105, 99, 37,115, 37,115, 42, 40, 46, 42,
+ 41, 0, 2, 0, 0, 0, 8,100,101, 99,108, 97,114,101, 0, 2, 0, 0, 0, 55,
+ 32, 32,105,102, 32, 40, 33,115,101,108,102, 41, 32,116,111,108,117, 97, 95,101,
+114,114,111,114, 40, 34,105,110,118, 97,108,105,100, 32, 39,115,101,108,102, 39,
+ 32,105,110, 32,102,117,110, 99,116,105,111,110, 32, 39, 0, 2, 0, 0, 0, 5,
+ 39, 34, 41, 59, 0, 2, 0, 0, 0, 9,103,101,116, 97,114,114, 97,121, 0, 2,
+ 0, 0, 0, 7,100,101,108,101,116,101, 0, 2, 0, 0, 0, 15, 32, 32,100,101,
+108,101,116,101, 32,115,101,108,102, 59, 0, 2, 0, 0, 0, 12,111,112,101,114,
+ 97,116,111,114, 38, 91, 93, 0, 2, 0, 0, 0, 20, 32, 32,115,101,108,102, 45,
+ 62,111,112,101,114, 97,116,111,114, 91, 93, 40, 0, 2, 0, 0, 0, 5, 41, 32,
+ 61, 32, 0, 2, 0, 0, 0, 2, 59, 0, 2, 0, 0, 0, 4, 32, 32,123, 0, 2,
+ 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 32, 32, 0, 2, 0, 0, 0, 4,112,116,
+114, 0, 2, 0, 0, 0, 14,116,111,108,117, 97, 73, 95,114,101,116, 32, 61, 32,
+ 0, 2, 0, 0, 0, 3, 41, 32, 0, 2, 0, 0, 0, 3, 58, 58, 0, 2, 0, 0,
+ 0, 7,115,101,108,102, 45, 62, 0, 2, 0, 0, 0, 8,112, 97,115,115,112, 97,
+114, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0, 0, 0, 3, 41, 59, 0, 2, 0, 0,
+ 0, 2,116, 0, 2, 0, 0, 0, 7,110,117,109, 98,101,114, 0, 2, 0, 0, 0,
+ 14, 32, 32, 32,116,111,108,117, 97, 95,112,117,115,104, 0, 2, 0, 0, 0, 22,
+ 40, 40,100,111,117, 98,108,101, 41,116,111,108,117, 97, 73, 95,114,101,116, 41,
+ 59, 0, 2, 0, 0, 0, 14, 40,116,111,108,117, 97, 73, 95,114,101,116, 41, 59,
+ 0, 2, 0, 0, 0, 5, 32, 32, 32,123, 0, 2, 0, 0, 0, 20, 35,105,102,100,
+101,102, 32, 95, 95, 99,112,108,117,115,112,108,117,115, 10, 0, 2, 0, 0, 0,
+ 29, 32, 32, 32, 32,118,111,105,100, 42, 32,116,111,108,117, 97, 73, 95, 99,108,
+111,110,101, 32, 61, 32,110,101,119, 0, 2, 0, 0, 0, 7, 35,101,108,115,101,
+ 10, 0, 2, 0, 0, 0, 63, 32, 32, 32, 32,118,111,105,100, 42, 32,116,111,108,
+117, 97, 73, 95, 99,108,111,110,101, 32, 61, 32,116,111,108,117, 97, 95, 99,111,
+112,121, 40, 40,118,111,105,100, 42, 41, 38,116,111,108,117, 97, 73, 95,114,101,
+116, 44,115,105,122,101,111,102, 40, 0, 2, 0, 0, 0, 4, 41, 41, 59, 0, 2,
+ 0, 0, 0, 8, 35,101,110,100,105,102, 10, 0, 2, 0, 0, 0, 51, 32, 32, 32,
+ 32,116,111,108,117, 97, 95,112,117,115,104,117,115,101,114,116,121,112,101, 40,
+116,111,108,117, 97, 95,100,111, 99,108,111,110,101, 40,116,111,108,117, 97, 73,
+ 95, 99,108,111,110,101, 44, 0, 2, 0, 0, 0, 3, 41, 44, 0, 2, 0, 0, 0,
+ 5, 32, 32, 32,125, 0, 2, 0, 0, 0, 2, 38, 0, 2, 0, 0, 0, 42, 32, 32,
+ 32,116,111,108,117, 97, 95,112,117,115,104,117,115,101,114,116,121,112,101, 40,
+ 40,118,111,105,100, 42, 41, 38,116,111,108,117, 97, 73, 95,114,101,116, 44, 0,
+ 2, 0, 0, 0, 41, 32, 32, 32,116,111,108,117, 97, 95,112,117,115,104,117,115,
+101,114,116,121,112,101, 40, 40,118,111,105,100, 42, 41,116,111,108,117, 97, 73,
+ 95,114,101,116, 44, 0, 2, 0, 0, 0, 9,114,101,116,118, 97,108,117,101, 0,
+ 2, 0, 0, 0, 4, 32, 32,125, 0, 2, 0, 0, 0, 9,115,101,116, 97,114,114,
+ 97,121, 0, 2, 0, 0, 0, 10,102,114,101,101, 97,114,114, 97,121, 0, 2, 0,
+ 0, 0, 3, 32,125, 0, 2, 0, 0, 0, 9, 32,114,101,116,117,114,110, 59, 0,
+ 2, 0, 0, 0, 8,101,114,114,111,114, 58, 10, 0, 2, 0, 0, 0, 9,111,118,
+101,114,108,111, 97,100, 0, 2, 0, 0, 0, 7,115,116,114,115,117, 98, 0, 2,
+ 0, 0, 0, 7,102,111,114,109, 97,116, 0, 2, 0, 0, 0, 5, 37, 48, 50,100,
+ 0, 2, 0, 0, 0, 4, 40, 41, 59, 0, 2, 0, 0, 0, 36, 32,116,111,108,117,
+ 97, 95,101,114,114,111,114, 40, 34, 35,102,101,114,114,111,114, 32,105,110, 32,
+102,117,110, 99,116,105,111,110, 32, 39, 0, 2, 0, 0, 0, 6,108,110, 97,109,
+101, 0, 2, 0, 0, 0, 6, 39, 46, 34, 41, 59, 0, 2, 0, 0, 0, 2,125, 0,
+ 2, 0, 0, 0, 2, 10, 0, 2, 0, 0, 0, 9,114,101,103,105,115,116,101,114,
+ 0, 4, 0, 0, 0,232, 0, 0, 0, 14, 64,102,117,110, 99,116,105,111,110, 46,
+108,117, 97, 0, 0, 0, 0, 89, 5, 1, 60,233, 13, 0, 20, 2, 2, 1, 1, 46,
+ 7, 13, 0, 20, 3, 2, 1, 1, 60,234, 13, 1, 52, 33, 60,235, 15, 4, 11, 5,
+ 13, 1, 42, 11, 6, 42, 13, 0, 18, 7, 42, 11, 8, 42, 13, 0, 18, 9, 42, 11,
+ 10, 42, 2, 0, 1, 50, 27, 60,237, 15, 4, 11, 11, 13, 0, 18, 7, 42, 11, 8,
+ 42, 13, 0, 18, 9, 42, 11, 10, 42, 2, 0, 1, 60,238, 60,239, 0, 0, 0, 0,
+ 2, 0, 0, 0,232, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0,233, 0, 0,
+ 0, 7,112, 97,114,101,110,116, 0, 0, 0, 0, 12, 2, 0, 0, 0, 7,112, 97,
+114,101,110,116, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 8,
+105,110, 99,108, 97,115,115, 0, 2, 0, 0, 0, 9,105,110,109,111,100,117,108,
+101, 0, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0, 0, 18, 32,
+116,111,108,117, 97, 95,102,117,110, 99,116,105,111,110, 40, 34, 0, 2, 0, 0,
+ 0, 4, 34, 44, 34, 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0, 0,
+ 0, 3, 34, 44, 0, 2, 0, 0, 0, 6, 99,110, 97,109,101, 0, 2, 0, 0, 0,
+ 3, 41, 59, 0, 2, 0, 0, 0, 23, 32,116,111,108,117, 97, 95,102,117,110, 99,
+116,105,111,110, 40, 78, 85, 76, 76, 44, 34, 0, 2, 0, 0, 0, 11,117,110,114,
+101,103,105,115,116,101,114, 0, 4, 0, 0, 0,242, 0, 0, 0, 14, 64,102,117,
+110, 99,116,105,111,110, 46,108,117, 97, 0, 0, 0, 0, 52, 4, 1, 60,243, 13,
+ 0, 20, 1, 2, 1, 1, 4, 0, 32, 48, 10, 13, 0, 20, 2, 2, 1, 1, 4, 0,
+ 32, 52, 19, 60,244, 15, 3, 11, 4, 13, 0, 18, 5, 42, 11, 6, 42, 2, 0, 1,
+ 50, 2, 60,245, 60,246, 0, 0, 0, 0, 1, 0, 0, 0,242, 0, 0, 0, 5,115,
+101,108,102, 0, 0, 0, 0, 7, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0,
+ 0, 0, 8,105,110, 99,108, 97,115,115, 0, 2, 0, 0, 0, 9,105,110,109,111,
+100,117,108,101, 0, 2, 0, 0, 0, 7,111,117,116,112,117,116, 0, 2, 0, 0,
+ 0, 32, 32,108,117, 97, 95,112,117,115,104,110,105,108, 40, 41, 59, 32,108,117,
+ 97, 95,115,101,116,103,108,111, 98, 97,108, 40, 34, 0, 2, 0, 0, 0, 6,108,
+110, 97,109,101, 0, 2, 0, 0, 0, 4, 34, 41, 59, 0, 2, 0, 0, 0, 6,112,
+114,105,110,116, 0, 4, 0, 0, 0,250, 0, 0, 0, 14, 64,102,117,110, 99,116,
+105,111,110, 46,108,117, 97, 0, 0, 0, 1, 1, 8, 3, 60,251, 15, 2, 13, 1,
+ 11, 3, 42, 2, 0, 1, 60,252, 15, 2, 13, 1, 11, 4, 42, 13, 0, 18, 6, 42,
+ 11, 7, 42, 2, 0, 1, 60,253, 15, 2, 13, 1, 11, 8, 42, 13, 0, 18, 9, 42,
+ 11, 7, 42, 2, 0, 1, 60,254, 15, 2, 13, 1, 11, 10, 42, 13, 0, 18, 11, 42,
+ 11, 7, 42, 2, 0, 1, 60,255, 15, 2, 13, 1, 11, 12, 42, 13, 0, 18, 13, 42,
+ 11, 7, 42, 2, 0, 1, 59, 1, 0, 15, 2, 13, 1, 11, 14, 42, 13, 0, 18, 15,
+ 42, 11, 7, 42, 2, 0, 1, 59, 1, 1, 15, 2, 13, 1, 11, 16, 42, 13, 0, 18,
+ 17, 42, 11, 7, 42, 2, 0, 1, 59, 1, 2, 15, 2, 13, 1, 11, 18, 42, 13, 0,
+ 18, 19, 42, 11, 7, 42, 2, 0, 1, 59, 1, 3, 15, 2, 13, 1, 11, 20, 42, 2,
+ 0, 1, 59, 1, 4, 7, 1, 50, 35, 59, 1, 6, 13, 0, 18, 22, 13, 3, 16, 20,
+ 2, 13, 1, 11, 23, 42, 11, 24, 2, 0, 3, 59, 1, 7, 13, 3, 7, 1, 37, 23,
+ 3, 59, 1, 8, 59, 1, 5, 13, 0, 18, 22, 13, 3, 16, 54, 47, 59, 1, 9, 15,
+ 2, 13, 1, 11, 25, 42, 2, 0, 1, 59, 1, 10, 15, 2, 13, 1, 11, 26, 42, 13,
+ 2, 42, 2, 0, 1, 59, 1, 11, 0, 0, 0, 0, 4, 0, 0, 0,250, 0, 0, 0,
+ 5,115,101,108,102, 0, 0, 0, 0,250, 0, 0, 0, 6,105,100,101,110,116, 0,
+ 0, 0, 0,250, 0, 0, 0, 6, 99,108,111,115,101, 0, 0, 0, 1, 4, 0, 0,
+ 0, 2,105, 0, 0, 0, 0, 27, 2, 0, 0, 0, 6,105,100,101,110,116, 0, 2,
+ 0, 0, 0, 6, 99,108,111,115,101, 0, 2, 0, 0, 0, 6,112,114,105,110,116,
+ 0, 2, 0, 0, 0, 10, 70,117,110, 99,116,105,111,110,123, 0, 2, 0, 0, 0,
+ 10, 32,109,111,100, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,115,101,108,102,
+ 0, 2, 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 3, 39, 44, 0, 2, 0,
+ 0, 0, 10, 32,116,121,112,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,116,121,
+112,101, 0, 2, 0, 0, 0, 10, 32,112,116,114, 32, 32, 61, 32, 39, 0, 2, 0,
+ 0, 0, 4,112,116,114, 0, 2, 0, 0, 0, 10, 32,110, 97,109,101, 32, 61, 32,
+ 39, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 11, 32, 99,111,
+110,115,116, 32, 61, 32, 39, 0, 2, 0, 0, 0, 6, 99,111,110,115,116, 0, 2,
+ 0, 0, 0, 11, 32, 99,110, 97,109,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 6,
+ 99,110, 97,109,101, 0, 2, 0, 0, 0, 11, 32,108,110, 97,109,101, 32, 61, 32,
+ 39, 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0, 10, 32, 97,
+114,103,115, 32, 61, 32,123, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 5,
+ 97,114,103,115, 0, 2, 0, 0, 0, 3, 32, 32, 0, 2, 0, 0, 0, 2, 44, 0,
+ 2, 0, 0, 0, 3, 32,125, 0, 2, 0, 0, 0, 2,125, 0, 2, 0, 0, 0, 9,
+111,118,101,114,108,111, 97,100, 0, 4, 0, 0, 1, 14, 0, 0, 0, 14, 64,102,
+117,110, 99,116,105,111,110, 46,108,117, 97, 0, 0, 0, 0, 22, 4, 1, 59, 1,
+ 15, 13, 0, 18, 1, 20, 2, 13, 0, 18, 3, 3, 1, 2, 59, 1, 16, 0, 0, 0,
+ 0, 1, 0, 0, 1, 14, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 4, 2,
+ 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 7,112, 97,114,101,110,116,
+ 0, 2, 0, 0, 0, 9,111,118,101,114,108,111, 97,100, 0, 2, 0, 0, 0, 6,
+108,110, 97,109,101, 0, 2, 0, 0, 0, 10, 95, 70,117,110, 99,116,105,111,110,
+ 0, 4, 0, 0, 1, 21, 0, 0, 0, 14, 64,102,117,110, 99,116,105,111,110, 46,
+108,117, 97, 0, 0, 0, 0,231, 7, 1, 59, 1, 22, 13, 0, 11, 1, 15, 2, 26,
+ 59, 1, 23, 15, 3, 13, 0, 15, 4, 2, 0, 2, 59, 1, 25, 13, 0, 18, 5, 11,
+ 5, 31, 48, 7, 13, 0, 18, 5, 11, 6, 31, 52, 12, 59, 1, 26, 15, 7, 11, 8,
+ 2, 0, 1, 50, 3, 59, 1, 27, 59, 1, 29, 15, 9, 13, 0, 2, 0, 1, 59, 1,
+ 30, 13, 0, 20, 10, 2, 1, 1, 52,108, 59, 1, 31, 13, 0, 18, 11, 13, 0, 18,
+ 12, 18, 11, 32, 52, 46, 59, 1, 32, 13, 0, 11, 11, 11, 13, 26, 59, 1, 33, 13,
+ 0, 11, 14, 11, 13, 26, 59, 1, 34, 13, 0, 11, 15, 13, 0, 18, 12, 18, 11, 26,
+ 59, 1, 35, 13, 0, 11, 16, 11, 17, 26, 50, 44, 59, 1, 36, 13, 0, 18, 11, 11,
+ 18, 13, 0, 18, 12, 18, 11, 42, 32, 52, 22, 59, 1, 37, 13, 0, 11, 11, 11, 19,
+ 26, 59, 1, 38, 13, 0, 11, 14, 11, 19, 26, 50, 3, 59, 1, 39, 50, 3, 59, 1,
+ 40, 59, 1, 41, 13, 0, 11, 20, 13, 0, 20, 21, 11, 22, 2, 1, 2, 13, 0, 20,
+ 23, 13, 0, 2, 1, 2, 42, 26, 59, 1, 42, 13, 0, 1, 1, 59, 1, 43, 0, 0,
+ 0, 0, 1, 0, 0, 1, 21, 0, 0, 0, 2,116, 0, 0, 0, 0, 24, 2, 0, 0,
+ 0, 2,116, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 14,
+ 99,108, 97,115,115, 70,117,110, 99,116,105,111,110, 0, 2, 0, 0, 0, 7,115,
+101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103,
+ 0, 2, 0, 0, 0, 6, 99,111,110,115,116, 0, 2, 0, 0, 0, 1, 0, 2, 0,
+ 0, 0, 6,101,114,114,111,114, 0, 2, 0, 0, 0, 31, 35,105,110,118, 97,108,
+105,100, 32, 39, 99,111,110,115,116, 39, 32,115,112,101, 99,105,102,105, 99, 97,
+116,105,111,110, 0, 2, 0, 0, 0, 7, 97,112,112,101,110,100, 0, 2, 0, 0,
+ 0, 8,105,110, 99,108, 97,115,115, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0,
+ 2, 0, 0, 0, 7,112, 97,114,101,110,116, 0, 2, 0, 0, 0, 4,110,101,119,
+ 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0, 5,116,121,112,
+101, 0, 2, 0, 0, 0, 4,112,116,114, 0, 2, 0, 0, 0, 2, 42, 0, 2, 0,
+ 0, 0, 2,126, 0, 2, 0, 0, 0, 7,100,101,108,101,116,101, 0, 2, 0, 0,
+ 0, 6, 99,110, 97,109,101, 0, 2, 0, 0, 0, 10, 99,102,117,110, 99,110, 97,
+109,101, 0, 2, 0, 0, 0, 7,116,111,108,117, 97, 73, 0, 2, 0, 0, 0, 9,
+111,118,101,114,108,111, 97,100, 0, 2, 0, 0, 0, 9, 70,117,110, 99,116,105,
+111,110, 0, 4, 0, 0, 1, 49, 0, 0, 0, 14, 64,102,117,110, 99,116,105,111,
+110, 46,108,117, 97, 0, 0, 0, 0,147, 11, 3, 59, 1, 50, 15, 4, 15, 5, 13,
+ 1, 7, 2, 9, 2, 2, 1, 3, 11, 6, 2, 1, 2, 59, 1, 51, 7, 1, 59, 1,
+ 52, 22, 1, 11, 9, 7, 0, 30, 0, 50, 50, 59, 1, 54, 13, 5, 11, 9, 13, 5,
+ 18, 9, 7, 1, 37, 26, 59, 1, 55, 13, 5, 13, 5, 18, 9, 15, 10, 13, 3, 13,
+ 4, 16, 11, 11, 2, 1, 2, 26, 59, 1, 56, 13, 4, 7, 1, 37, 23, 4, 59, 1,
+ 57, 59, 1, 53, 13, 3, 13, 4, 16, 54, 60, 59, 1, 58, 15, 10, 13, 0, 11, 13,
+ 2, 1, 2, 59, 1, 59, 13, 6, 11, 14, 13, 5, 26, 59, 1, 60, 13, 6, 11, 15,
+ 13, 2, 26, 59, 1, 61, 15, 16, 13, 6, 3, 7, 1, 59, 1, 62, 0, 0, 0, 0,
+ 7, 0, 0, 1, 49, 0, 0, 0, 2,100, 0, 0, 0, 1, 49, 0, 0, 0, 2, 97,
+ 0, 0, 0, 1, 49, 0, 0, 0, 2, 99, 0, 0, 0, 1, 50, 0, 0, 0, 2,116,
+ 0, 0, 0, 1, 51, 0, 0, 0, 2,105, 0, 0, 0, 1, 52, 0, 0, 0, 2,108,
+ 0, 0, 0, 1, 58, 0, 0, 0, 2,102, 0, 0, 0, 0, 17, 2, 0, 0, 0, 2,
+100, 0, 2, 0, 0, 0, 2, 97, 0, 2, 0, 0, 0, 2, 99, 0, 2, 0, 0, 0,
+ 2,116, 0, 2, 0, 0, 0, 6,115,112,108,105,116, 0, 2, 0, 0, 0, 7,115,
+116,114,115,117, 98, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0, 0, 0, 2,105, 0,
+ 2, 0, 0, 0, 2,108, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 12, 68,
+101, 99,108, 97,114, 97,116,105,111,110, 0, 2, 0, 0, 0, 4,118, 97,114, 0,
+ 2, 0, 0, 0, 2,102, 0, 2, 0, 0, 0, 5,102,117,110, 99, 0, 2, 0, 0,
+ 0, 5, 97,114,103,115, 0, 2, 0, 0, 0, 6, 99,111,110,115,116, 0, 2, 0,
+ 0, 0, 10, 95, 70,117,110, 99,116,105,111,110, 0,
+};
+
+/* operator.lo */
+static char B14[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 14, 64,111,112,101,114, 97,
+116,111,114, 46,108,117, 97, 0, 0, 0, 0,125, 21, 0, 60, 18, 22, 2, 60, 19,
+ 11, 1, 11, 2, 11, 3, 60, 20, 15, 4, 30, 1, 60, 21, 25, 0, 60, 22, 15, 5,
+ 15, 0, 15, 6, 2, 0, 2, 60, 25, 22, 10, 11, 8, 11, 9, 60, 26, 11, 10, 11,
+ 11, 60, 27, 11, 12, 11, 13, 60, 28, 11, 14, 11, 15, 60, 29, 11, 16, 11, 17, 60,
+ 30, 11, 18, 11, 19, 60, 31, 11, 20, 11, 21, 60, 32, 11, 22, 11, 23, 60, 33, 11,
+ 24, 11, 25, 60, 34, 11, 26, 11, 27, 30, 9, 60, 35, 25, 7, 60, 39, 15, 0, 11,
+ 28, 11, 29, 26, 60, 60, 11, 31, 25, 30, 60, 82, 11, 33, 25, 32, 0, 0, 0, 0,
+ 0, 0, 0, 0, 34, 2, 0, 0, 0, 14, 99,108, 97,115,115, 79,112,101,114, 97,
+116,111,114, 0, 2, 0, 0, 0, 5,107,105,110,100, 0, 2, 0, 0, 0, 1, 0,
+ 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 14, 99,108, 97,115,
+115, 70,117,110, 99,116,105,111,110, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,
+103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0,
+ 0, 4, 95, 84, 77, 0, 2, 0, 0, 0, 2, 43, 0, 2, 0, 0, 0, 13,111,112,
+101,114, 97,116,111,114, 95, 97,100,100, 0, 2, 0, 0, 0, 2, 45, 0, 2, 0,
+ 0, 0, 13,111,112,101,114, 97,116,111,114, 95,115,117, 98, 0, 2, 0, 0, 0,
+ 2, 42, 0, 2, 0, 0, 0, 13,111,112,101,114, 97,116,111,114, 95,109,117,108,
+ 0, 2, 0, 0, 0, 2, 47, 0, 2, 0, 0, 0, 13,111,112,101,114, 97,116,111,
+114, 95,100,105,118, 0, 2, 0, 0, 0, 2, 60, 0, 2, 0, 0, 0, 12,111,112,
+101,114, 97,116,111,114, 95,108,116, 0, 2, 0, 0, 0, 2, 62, 0, 2, 0, 0,
+ 0, 12,111,112,101,114, 97,116,111,114, 95,103,116, 0, 2, 0, 0, 0, 3, 60,
+ 61, 0, 2, 0, 0, 0, 12,111,112,101,114, 97,116,111,114, 95,108,101, 0, 2,
+ 0, 0, 0, 3, 62, 61, 0, 2, 0, 0, 0, 12,111,112,101,114, 97,116,111,114,
+ 95,103,101, 0, 2, 0, 0, 0, 3, 91, 93, 0, 2, 0, 0, 0, 13,111,112,101,
+114, 97,116,111,114, 95,103,101,116, 0, 2, 0, 0, 0, 4, 38, 91, 93, 0, 2,
+ 0, 0, 0, 13,111,112,101,114, 97,116,111,114, 95,115,101,116, 0, 2, 0, 0,
+ 0, 6,112,114,105,110,116, 0, 4, 0, 0, 0, 39, 0, 0, 0, 14, 64,111,112,
+101,114, 97,116,111,114, 46,108,117, 97, 0, 0, 0, 1, 9, 8, 3, 60, 40, 15,
+ 2, 13, 1, 11, 3, 42, 2, 0, 1, 60, 41, 15, 2, 13, 1, 11, 4, 42, 13, 0,
+ 18, 6, 42, 11, 7, 42, 2, 0, 1, 60, 42, 15, 2, 13, 1, 11, 8, 42, 13, 0,
+ 18, 9, 42, 11, 7, 42, 2, 0, 1, 60, 43, 15, 2, 13, 1, 11, 10, 42, 13, 0,
+ 18, 11, 42, 11, 7, 42, 2, 0, 1, 60, 44, 15, 2, 13, 1, 11, 12, 42, 13, 0,
+ 18, 13, 42, 11, 7, 42, 2, 0, 1, 60, 45, 15, 2, 13, 1, 11, 14, 42, 13, 0,
+ 18, 15, 42, 11, 7, 42, 2, 0, 1, 60, 46, 15, 2, 13, 1, 11, 16, 42, 13, 0,
+ 18, 17, 42, 11, 7, 42, 2, 0, 1, 60, 47, 15, 2, 13, 1, 11, 18, 42, 13, 0,
+ 18, 19, 42, 11, 7, 42, 2, 0, 1, 60, 48, 15, 2, 13, 1, 11, 20, 42, 13, 0,
+ 18, 21, 42, 11, 7, 42, 2, 0, 1, 60, 49, 15, 2, 13, 1, 11, 22, 42, 2, 0,
+ 1, 60, 50, 7, 1, 50, 32, 60, 52, 13, 0, 18, 24, 13, 3, 16, 20, 2, 13, 1,
+ 11, 25, 42, 11, 26, 2, 0, 3, 60, 53, 13, 3, 7, 1, 37, 23, 3, 60, 54, 60,
+ 51, 13, 0, 18, 24, 13, 3, 16, 54, 43, 60, 55, 15, 2, 13, 1, 11, 27, 42, 2,
+ 0, 1, 60, 56, 15, 2, 13, 1, 11, 28, 42, 13, 2, 42, 2, 0, 1, 60, 57, 0,
+ 0, 0, 0, 4, 0, 0, 0, 39, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0,
+ 39, 0, 0, 0, 6,105,100,101,110,116, 0, 0, 0, 0, 39, 0, 0, 0, 6, 99,
+108,111,115,101, 0, 0, 0, 0, 50, 0, 0, 0, 2,105, 0, 0, 0, 0, 29, 2,
+ 0, 0, 0, 6,105,100,101,110,116, 0, 2, 0, 0, 0, 6, 99,108,111,115,101,
+ 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 2, 0, 0, 0, 10, 79,112,101,
+114, 97,116,111,114,123, 0, 2, 0, 0, 0, 11, 32,107,105,110,100, 32, 32, 61,
+ 32, 39, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,107,105,
+110,100, 0, 2, 0, 0, 0, 3, 39, 44, 0, 2, 0, 0, 0, 10, 32,109,111,100,
+ 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 4,109,111,100, 0, 2, 0, 0, 0, 10,
+ 32,116,121,112,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,116,121,112,101, 0,
+ 2, 0, 0, 0, 10, 32,112,116,114, 32, 32, 61, 32, 39, 0, 2, 0, 0, 0, 4,
+112,116,114, 0, 2, 0, 0, 0, 10, 32,110, 97,109,101, 32, 61, 32, 39, 0, 2,
+ 0, 0, 0, 5,110, 97,109,101, 0, 2, 0, 0, 0, 11, 32, 99,111,110,115,116,
+ 32, 61, 32, 39, 0, 2, 0, 0, 0, 6, 99,111,110,115,116, 0, 2, 0, 0, 0,
+ 11, 32, 99,110, 97,109,101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 6, 99,110, 97,
+109,101, 0, 2, 0, 0, 0, 11, 32,108,110, 97,109,101, 32, 61, 32, 39, 0, 2,
+ 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0, 10, 32, 97,114,103,115,
+ 32, 61, 32,123, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0, 5, 97,114,103,
+115, 0, 2, 0, 0, 0, 3, 32, 32, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0, 0,
+ 0, 3, 32,125, 0, 2, 0, 0, 0, 2,125, 0, 2, 0, 0, 0, 10, 95, 79,112,
+101,114, 97,116,111,114, 0, 4, 0, 0, 0, 60, 0, 0, 0, 14, 64,111,112,101,
+114, 97,116,111,114, 46,108,117, 97, 0, 0, 0, 0,140, 7, 1, 60, 61, 13, 0,
+ 11, 1, 15, 2, 26, 60, 62, 15, 3, 13, 0, 15, 4, 2, 0, 2, 60, 64, 13, 0,
+ 18, 5, 11, 5, 31, 48, 7, 13, 0, 18, 5, 11, 6, 31, 52, 11, 60, 65, 15, 7,
+ 11, 8, 2, 0, 1, 50, 2, 60, 66, 60, 68, 15, 9, 13, 0, 2, 0, 1, 60, 69,
+ 13, 0, 20, 10, 2, 1, 1, 44, 52, 11, 60, 70, 15, 7, 11, 11, 2, 0, 1, 50,
+ 2, 60, 71, 60, 73, 13, 0, 11, 12, 13, 0, 20, 13, 11, 14, 2, 1, 2, 13, 0,
+ 20, 15, 13, 0, 2, 1, 2, 42, 26, 60, 74, 13, 0, 11, 16, 13, 0, 18, 16, 13,
+ 0, 18, 17, 42, 26, 60, 75, 13, 0, 1, 1, 60, 76, 0, 0, 0, 0, 1, 0, 0,
+ 0, 60, 0, 0, 0, 2,116, 0, 0, 0, 0, 18, 2, 0, 0, 0, 2,116, 0, 2,
+ 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 14, 99,108, 97,115,115,
+ 79,112,101,114, 97,116,111,114, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103,
+ 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0,
+ 6, 99,111,110,115,116, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 6,101,114,
+114,111,114, 0, 2, 0, 0, 0, 31, 35,105,110,118, 97,108,105,100, 32, 39, 99,
+111,110,115,116, 39, 32,115,112,101, 99,105,102,105, 99, 97,116,105,111,110, 0,
+ 2, 0, 0, 0, 7, 97,112,112,101,110,100, 0, 2, 0, 0, 0, 8,105,110, 99,
+108, 97,115,115, 0, 2, 0, 0, 0, 46, 35,111,112,101,114, 97,116,111,114, 32,
+ 99, 97,110, 32,111,110,108,121, 32, 98,101, 32,100,101,102,105,110,101,100, 32,
+ 97,115, 32, 99,108, 97,115,115, 32,109,101,109, 98,101,114, 0, 2, 0, 0, 0,
+ 6, 99,110, 97,109,101, 0, 2, 0, 0, 0, 10, 99,102,117,110, 99,110, 97,109,
+101, 0, 2, 0, 0, 0, 7,116,111,108,117, 97, 73, 0, 2, 0, 0, 0, 9,111,
+118,101,114,108,111, 97,100, 0, 2, 0, 0, 0, 5,110, 97,109,101, 0, 2, 0,
+ 0, 0, 5,107,105,110,100, 0, 2, 0, 0, 0, 9, 79,112,101,114, 97,116,111,
+114, 0, 4, 0, 0, 0, 82, 0, 0, 0, 14, 64,111,112,101,114, 97,116,111,114,
+ 46,108,117, 97, 0, 0, 0, 1, 99, 14, 4, 60, 83, 15, 5, 15, 6, 13, 2, 7,
+ 2, 15, 7, 13, 2, 2, 1, 1, 7, 1, 38, 2, 1, 3, 11, 8, 2, 1, 2, 60,
+ 84, 7, 1, 60, 85, 22, 1, 11, 11, 7, 0, 30, 0, 50, 46, 60, 87, 13, 6, 11,
+ 11, 13, 6, 18, 11, 7, 1, 37, 26, 60, 88, 13, 6, 13, 6, 18, 11, 15, 12, 13,
+ 4, 13, 5, 16, 11, 13, 2, 1, 2, 26, 60, 89, 13, 5, 7, 1, 37, 23, 5, 60,
+ 90, 60, 86, 13, 4, 13, 5, 16, 54, 55, 60, 91, 13, 1, 11, 14, 32, 52, 17, 60,
+ 92, 15, 15, 13, 0, 11, 16, 11, 17, 2, 1, 3, 23, 0, 50, 59, 60, 93, 13, 1,
+ 11, 18, 32, 52, 48, 60, 94, 13, 6, 11, 11, 13, 6, 18, 11, 7, 1, 37, 26, 60,
+ 95, 13, 6, 13, 6, 18, 11, 15, 12, 13, 0, 11, 13, 2, 1, 2, 26, 60, 96, 13,
+ 6, 13, 6, 18, 11, 16, 11, 19, 11, 20, 26, 50, 2, 60, 97, 60, 98, 15, 12, 13,
+ 0, 11, 22, 2, 1, 2, 60, 99, 13, 1, 11, 14, 32, 48, 25, 13, 6, 7, 1, 16,
+ 4, 0, 32, 46, 15, 15, 23, 13, 6, 7, 1, 16, 18, 24, 2, 1, 1, 11, 25, 31,
+ 52, 11, 60,100, 15, 26, 11, 27, 2, 0, 1, 50, 2, 60,101, 60,102, 13, 7, 11,
+ 28, 13, 6, 26, 60,103, 13, 7, 11, 29, 13, 3, 26, 60,104, 13, 7, 11, 30, 15,
+ 15, 13, 1, 11, 31, 11, 17, 2, 1, 3, 26, 60,105, 13, 7, 11, 32, 15, 33, 13,
+ 7, 18, 30, 16, 26, 60,106, 13, 7, 18, 30, 11, 14, 32, 48, 12, 15, 34, 13, 7,
+ 18, 35, 11, 29, 2, 1, 2, 44, 52, 20, 60,107, 15, 36, 13, 0, 11, 16, 13, 1,
+ 42, 13, 2, 13, 3, 2, 0, 4, 50, 2, 60,108, 60,109, 15, 37, 13, 7, 3, 8,
+ 1, 60,110, 0, 0, 0, 0, 8, 0, 0, 0, 82, 0, 0, 0, 2,100, 0, 0, 0,
+ 0, 82, 0, 0, 0, 2,107, 0, 0, 0, 0, 82, 0, 0, 0, 2, 97, 0, 0, 0,
+ 0, 82, 0, 0, 0, 2, 99, 0, 0, 0, 0, 83, 0, 0, 0, 2,116, 0, 0, 0,
+ 0, 84, 0, 0, 0, 2,105, 0, 0, 0, 0, 85, 0, 0, 0, 2,108, 0, 0, 0,
+ 0, 98, 0, 0, 0, 2,102, 0, 0, 0, 0, 38, 2, 0, 0, 0, 2,100, 0, 2,
+ 0, 0, 0, 2,107, 0, 2, 0, 0, 0, 2, 97, 0, 2, 0, 0, 0, 2, 99, 0,
+ 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6,115,112,108,105,116, 0, 2, 0,
+ 0, 0, 7,115,116,114,115,117, 98, 0, 2, 0, 0, 0, 7,115,116,114,108,101,
+110, 0, 2, 0, 0, 0, 2, 44, 0, 2, 0, 0, 0, 2,105, 0, 2, 0, 0, 0,
+ 2,108, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 12, 68,101, 99,108, 97,
+114, 97,116,105,111,110, 0, 2, 0, 0, 0, 4,118, 97,114, 0, 2, 0, 0, 0,
+ 3, 91, 93, 0, 2, 0, 0, 0, 5,103,115,117, 98, 0, 2, 0, 0, 0, 2, 38,
+ 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 4, 38, 91, 93, 0, 2, 0, 0, 0,
+ 5,110, 97,109,101, 0, 2, 0, 0, 0, 13,116,111,108,117, 97, 73, 95,118, 97,
+108,117,101, 0, 2, 0, 0, 0, 2,102, 0, 2, 0, 0, 0, 5,102,117,110, 99,
+ 0, 2, 0, 0, 0, 8,105,115, 98, 97,115,105, 99, 0, 2, 0, 0, 0, 5,116,
+121,112,101, 0, 2, 0, 0, 0, 7,110,117,109, 98,101,114, 0, 2, 0, 0, 0,
+ 6,101,114,114,111,114, 0, 2, 0, 0, 0, 50,111,112,101,114, 97,116,111,114,
+ 91, 93, 32, 99, 97,110, 32,111,110,108,121, 32, 98,101, 32,100,101,102,105,110,
+101,100, 32,102,111,114, 32,110,117,109,101,114,105, 99, 32,105,110,100,101,120,
+ 46, 0, 2, 0, 0, 0, 5, 97,114,103,115, 0, 2, 0, 0, 0, 6, 99,111,110,
+115,116, 0, 2, 0, 0, 0, 5,107,105,110,100, 0, 2, 0, 0, 0, 3, 37,115,
+ 0, 2, 0, 0, 0, 6,108,110, 97,109,101, 0, 2, 0, 0, 0, 4, 95, 84, 77,
+ 0, 2, 0, 0, 0, 8,115,116,114,102,105,110,100, 0, 2, 0, 0, 0, 4,109,
+111,100, 0, 2, 0, 0, 0, 9, 79,112,101,114, 97,116,111,114, 0, 2, 0, 0,
+ 0, 10, 95, 79,112,101,114, 97,116,111,114, 0,
+};
+
+/* verbatim.lo */
+static char B15[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 14, 64,118,101,114, 98, 97,
+116,105,109, 46,108,117, 97, 0, 0, 0, 0, 84, 5, 0, 60, 20, 22, 2, 60, 21,
+ 11, 1, 11, 2, 11, 3, 60, 22, 15, 4, 30, 1, 60, 23, 25, 0, 60, 24, 15, 5,
+ 15, 0, 15, 6, 2, 0, 2, 60, 27, 15, 0, 11, 7, 11, 8, 26, 60, 34, 15, 0,
+ 11, 9, 11, 10, 26, 60, 42, 15, 0, 11, 11, 11, 12, 26, 60, 50, 15, 0, 11, 13,
+ 11, 14, 26, 60, 58, 11, 16, 25, 15, 60, 67, 11, 18, 25, 17, 0, 0, 0, 0, 0,
+ 0, 0, 0, 19, 2, 0, 0, 0, 14, 99,108, 97,115,115, 86,101,114, 98, 97,116,
+105,109, 0, 2, 0, 0, 0, 5,108,105,110,101, 0, 2, 0, 0, 0, 1, 0, 2,
+ 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0, 0, 13, 99,108, 97,115,115,
+ 70,101, 97,116,117,114,101, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0,
+ 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 9,
+112,114,101, 97,109, 98,108,101, 0, 4, 0, 0, 0, 27, 0, 0, 0, 14, 64,118,
+101,114, 98, 97,116,105,109, 46,108,117, 97, 0, 0, 0, 0, 29, 3, 1, 60, 28,
+ 13, 0, 18, 1, 44, 52, 13, 60, 29, 15, 2, 13, 0, 18, 3, 2, 0, 1, 50, 2,
+ 60, 30, 60, 31, 0, 0, 0, 0, 1, 0, 0, 0, 27, 0, 0, 0, 5,115,101,108,
+102, 0, 0, 0, 0, 4, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0,
+ 5, 99,111,110,100, 0, 2, 0, 0, 0, 6,119,114,105,116,101, 0, 2, 0, 0,
+ 0, 5,108,105,110,101, 0, 2, 0, 0, 0, 8,115,117,112, 99,111,100,101, 0,
+ 4, 0, 0, 0, 34, 0, 0, 0, 14, 64,118,101,114, 98, 97,116,105,109, 46,108,
+117, 97, 0, 0, 0, 0, 37, 3, 1, 60, 35, 13, 0, 18, 1, 52, 22, 60, 36, 15,
+ 2, 13, 0, 18, 3, 2, 0, 1, 60, 37, 15, 2, 11, 4, 2, 0, 1, 50, 2, 60,
+ 38, 60, 39, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 5,115,101,108,102,
+ 0, 0, 0, 0, 5, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5,
+ 99,111,110,100, 0, 2, 0, 0, 0, 6,119,114,105,116,101, 0, 2, 0, 0, 0,
+ 5,108,105,110,101, 0, 2, 0, 0, 0, 2, 10, 0, 2, 0, 0, 0, 9,114,101,
+103,105,115,116,101,114, 0, 4, 0, 0, 0, 42, 0, 0, 0, 14, 64,118,101,114,
+ 98, 97,116,105,109, 46,108,117, 97, 0, 0, 0, 0, 28, 3, 1, 60, 43, 13, 0,
+ 18, 1, 52, 13, 60, 44, 15, 2, 13, 0, 18, 3, 2, 0, 1, 50, 2, 60, 45, 60,
+ 46, 0, 0, 0, 0, 1, 0, 0, 0, 42, 0, 0, 0, 5,115,101,108,102, 0, 0,
+ 0, 0, 4, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0, 5, 99,111,
+110,100, 0, 2, 0, 0, 0, 6,119,114,105,116,101, 0, 2, 0, 0, 0, 5,108,
+105,110,101, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 4, 0, 0, 0, 50,
+ 0, 0, 0, 14, 64,118,101,114, 98, 97,116,105,109, 46,108,117, 97, 0, 0, 0,
+ 0, 52, 6, 3, 60, 51, 15, 2, 13, 1, 11, 3, 42, 2, 0, 1, 60, 52, 15, 2,
+ 13, 1, 11, 4, 42, 13, 0, 18, 6, 42, 11, 7, 42, 2, 0, 1, 60, 53, 15, 2,
+ 13, 1, 11, 8, 42, 13, 2, 42, 2, 0, 1, 60, 54, 0, 0, 0, 0, 3, 0, 0,
+ 0, 50, 0, 0, 0, 5,115,101,108,102, 0, 0, 0, 0, 50, 0, 0, 0, 6,105,
+100,101,110,116, 0, 0, 0, 0, 50, 0, 0, 0, 6, 99,108,111,115,101, 0, 0,
+ 0, 0, 9, 2, 0, 0, 0, 6,105,100,101,110,116, 0, 2, 0, 0, 0, 6, 99,
+108,111,115,101, 0, 2, 0, 0, 0, 6,112,114,105,110,116, 0, 2, 0, 0, 0,
+ 10, 86,101,114, 98, 97,116,105,109,123, 0, 2, 0, 0, 0, 10, 32,108,105,110,
+101, 32, 61, 32, 39, 0, 2, 0, 0, 0, 5,115,101,108,102, 0, 2, 0, 0, 0,
+ 5,108,105,110,101, 0, 2, 0, 0, 0, 3, 39, 44, 0, 2, 0, 0, 0, 2,125,
+ 0, 2, 0, 0, 0, 10, 95, 86,101,114, 98, 97,116,105,109, 0, 4, 0, 0, 0,
+ 58, 0, 0, 0, 14, 64,118,101,114, 98, 97,116,105,109, 46,108,117, 97, 0, 0,
+ 0, 0, 40, 4, 1, 60, 59, 13, 0, 11, 1, 15, 2, 26, 60, 60, 15, 3, 13, 0,
+ 15, 4, 2, 0, 2, 60, 61, 15, 5, 13, 0, 2, 0, 1, 60, 62, 13, 0, 1, 1,
+ 60, 63, 0, 0, 0, 0, 1, 0, 0, 0, 58, 0, 0, 0, 2,116, 0, 0, 0, 0,
+ 6, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2,
+ 0, 0, 0, 14, 99,108, 97,115,115, 86,101,114, 98, 97,116,105,109, 0, 2, 0,
+ 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97,
+ 95,116, 97,103, 0, 2, 0, 0, 0, 7, 97,112,112,101,110,100, 0, 2, 0, 0,
+ 0, 9, 86,101,114, 98, 97,116,105,109, 0, 4, 0, 0, 0, 67, 0, 0, 0, 14,
+ 64,118,101,114, 98, 97,116,105,109, 46,108,117, 97, 0, 0, 0, 0, 75, 8, 1,
+ 60, 68, 4, 0, 60, 69, 15, 2, 13, 0, 7, 1, 7, 1, 2, 1, 3, 11, 3, 32,
+ 52, 21, 60, 70, 7, 1, 23, 1, 60, 71, 15, 2, 13, 0, 7, 2, 2, 1, 2, 23,
+ 0, 50, 2, 60, 72, 60, 73, 15, 4, 22, 2, 60, 74, 11, 5, 13, 0, 11, 6, 60,
+ 75, 13, 1, 30, 1, 60, 76, 3, 2, 1, 60, 77, 0, 0, 0, 0, 2, 0, 0, 0,
+ 67, 0, 0, 0, 2,108, 0, 0, 0, 0, 68, 0, 0, 0, 2, 99, 0, 0, 0, 0,
+ 7, 2, 0, 0, 0, 2,108, 0, 2, 0, 0, 0, 2, 99, 0, 2, 0, 0, 0, 7,
+115,116,114,115,117, 98, 0, 2, 0, 0, 0, 2, 36, 0, 2, 0, 0, 0, 10, 95,
+ 86,101,114, 98, 97,116,105,109, 0, 2, 0, 0, 0, 5,108,105,110,101, 0, 2,
+ 0, 0, 0, 5, 99,111,110,100, 0,
+};
+
+/* code.lo */
+static char B16[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 10, 64, 99,111,100,101, 46,
+108,117, 97, 0, 0, 0, 0, 66, 5, 0, 60, 19, 22, 2, 60, 20, 11, 1, 11, 2,
+ 11, 3, 60, 21, 15, 4, 30, 1, 60, 22, 25, 0, 60, 23, 15, 5, 15, 0, 15, 6,
+ 2, 0, 2, 60, 26, 15, 0, 11, 7, 11, 8, 26, 60, 63, 15, 0, 11, 9, 11, 10,
+ 26, 60, 71, 11, 12, 25, 11, 60, 80, 11, 14, 25, 13, 0, 0, 0, 0, 0, 0, 0,
+ 0, 15, 2, 0, 0, 0, 10, 99,108, 97,115,115, 67,111,100,101, 0, 2, 0, 0,
+ 0, 5,116,101,120,116, 0, 2, 0, 0, 0, 1, 0, 2, 0, 0, 0, 6, 95, 98,
+ 97,115,101, 0, 2, 0, 0, 0, 13, 99,108, 97,115,115, 70,101, 97,116,117,114,
+101, 0, 2, 0, 0, 0, 7,115,101,116,116, 97,103, 0, 2, 0, 0, 0, 10,116,
+111,108,117, 97, 95,116, 97,103, 0, 2, 0, 0, 0, 9,114,101,103,105,115,116,
+101,114, 0, 4, 0, 0, 0, 26, 0, 0, 0, 10, 64, 99,111,100,101, 46,108,117,
+ 97, 0, 0, 0, 0,239, 13, 1, 60, 27, 15, 1, 2, 1, 0, 60, 28, 15, 1, 2,
+ 1, 0, 60, 29, 15, 4, 13, 2, 11, 5, 2, 1, 2, 60, 30, 13, 3, 44, 52, 11,
+ 60, 31, 15, 6, 11, 7, 2, 0, 1, 50, 2, 60, 32, 60, 34, 15, 8, 13, 3, 13,
+ 0, 18, 10, 2, 0, 2, 60, 35, 15, 11, 13, 3, 2, 0, 1, 60, 36, 15, 12, 11,
+ 13, 13, 1, 42, 11, 14, 42, 13, 2, 42, 2, 0, 1, 60, 37, 15, 15, 13, 2, 2,
+ 0, 1, 60, 40, 15, 4, 13, 1, 11, 17, 2, 1, 2, 60, 41, 13, 4, 4, 0, 32,
+ 52, 11, 60, 42, 15, 6, 11, 7, 2, 0, 1, 50, 2, 60, 43, 60, 44, 15, 19, 13,
+ 4, 11, 20, 2, 1, 2, 60, 45, 15, 11, 13, 4, 2, 0, 1, 60, 46, 15, 15, 13,
+ 1, 2, 0, 1, 60, 48, 15, 21, 11, 22, 2, 0, 1, 60, 49, 15, 21, 11, 23, 2,
+ 0, 1, 60, 50, 22, 1, 11, 2, 7, 0, 30, 0, 60, 51, 15, 21, 15, 25, 13, 5,
+ 11, 26, 13, 6, 58, 27, 1, 60, 55, 2, 1, 3, 2, 0, 1, 60, 56, 15, 21, 11,
+ 28, 2, 0, 1, 60, 57, 15, 21, 11, 29, 2, 0, 1, 60, 58, 15, 21, 11, 30, 2,
+ 0, 1, 60, 59, 0, 0, 0, 0, 7, 0, 0, 0, 26, 0, 0, 0, 5,115,101,108,
+102, 0, 0, 0, 0, 27, 0, 0, 0, 2,111, 0, 0, 0, 0, 28, 0, 0, 0, 2,
+110, 0, 0, 0, 0, 29, 0, 0, 0, 2,102, 0, 0, 0, 0, 40, 0, 0, 0, 3,
+102,112, 0, 0, 0, 0, 44, 0, 0, 0, 2,115, 0, 0, 0, 0, 50, 0, 0, 0,
+ 2,116, 0, 0, 0, 0, 31, 2, 0, 0, 0, 2,111, 0, 2, 0, 0, 0, 8,116,
+109,112,110, 97,109,101, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0, 2,102,
+ 0, 2, 0, 0, 0, 9,111,112,101,110,102,105,108,101, 0, 2, 0, 0, 0, 2,
+119, 0, 2, 0, 0, 0, 6,101,114,114,111,114, 0, 2, 0, 0, 0, 61, 10, 32,
+ 32, 32, 99, 97,110,110,111,116, 32,111,112,101,110, 32,116,101,109,112,111,114,
+ 97,114,121, 32,102,105,108,101, 32,116,111, 32,112,114,111, 99, 99,101,115,115,
+ 32,101,109, 98,101,100,100,101,100, 32, 76,117, 97, 32, 99,111,100,101, 0, 2,
+ 0, 0, 0, 6,119,114,105,116,101, 0, 2, 0, 0, 0, 5,115,101,108,102, 0,
+ 2, 0, 0, 0, 5,116,101,120,116, 0, 2, 0, 0, 0, 10, 99,108,111,115,101,
+102,105,108,101, 0, 2, 0, 0, 0, 8,101,120,101, 99,117,116,101, 0, 2, 0,
+ 0, 0, 9,108,117, 97, 99, 32, 45,111, 32, 0, 2, 0, 0, 0, 2, 32, 0, 2,
+ 0, 0, 0, 7,114,101,109,111,118,101, 0, 2, 0, 0, 0, 3,102,112, 0, 2,
+ 0, 0, 0, 3,114, 98, 0, 2, 0, 0, 0, 2,115, 0, 2, 0, 0, 0, 5,114,
+101, 97,100, 0, 2, 0, 0, 0, 3, 46, 42, 0, 2, 0, 0, 0, 7,111,117,116,
+112,117,116, 0, 2, 0, 0, 0, 35, 10, 32,123, 32, 47, 42, 32, 98,101,103,105,
+110, 32,101,109, 98,101,100,100,101,100, 32,108,117, 97, 32, 99,111,100,101, 32,
+ 42, 47, 10, 0, 2, 0, 0, 0, 35, 32, 32,115,116, 97,116,105, 99, 32,117,110,
+115,105,103,110,101,100, 32, 99,104, 97,114, 32, 66, 91, 93, 32, 61, 32,123, 10,
+ 32, 32, 32, 0, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 5,103,115,117, 98,
+ 0, 2, 0, 0, 0, 4, 40, 46, 41, 0, 4, 0, 0, 0, 51, 0, 0, 0, 10, 64,
+ 99,111,100,101, 46,108,117, 97, 0, 0, 0, 0, 61, 6, 1, 60, 52, 11, 2, 60,
+ 53, 12, 0, 11, 4, 12, 0, 18, 4, 7, 1, 37, 26, 12, 0, 18, 4, 7, 20, 32,
+ 52, 11, 12, 0, 11, 4, 7, 0, 26, 11, 5, 23, 1, 60, 54, 15, 6, 11, 7, 15,
+ 8, 13, 0, 2, 1, 1, 13, 1, 3, 2, 3, 60, 55, 0, 0, 0, 0, 2, 0, 0,
+ 0, 51, 0, 0, 0, 2, 99, 0, 0, 0, 0, 52, 0, 0, 0, 2,101, 0, 0, 0,
+ 0, 9, 2, 0, 0, 0, 2, 99, 0, 2, 0, 0, 0, 2,101, 0, 2, 0, 0, 0,
+ 1, 0, 2, 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 2,110, 0, 2, 0, 0, 0,
+ 5, 10, 32, 32, 32, 0, 2, 0, 0, 0, 7,102,111,114,109, 97,116, 0, 2, 0,
+ 0, 0, 7, 37, 51,117, 44, 37,115, 0, 2, 0, 0, 0, 8,115,116,114, 98,121,
+116,101, 0, 2, 0, 0, 0, 6, 32, 32,125, 59, 10, 0, 2, 0, 0, 0, 56, 32,
+ 32,108,117, 97, 95,100,111, 98,117,102,102,101,114, 40, 66, 44,115,105,122,101,
+111,102, 40, 66, 41, 44, 34,116,111,108,117, 97, 58, 32,101,109, 98,101,100,100,
+101,100, 32, 76,117, 97, 32, 99,111,100,101, 34, 41, 59, 0, 2, 0, 0, 0, 36,
+ 32,125, 32, 47, 42, 32,101,110,100, 32,111,102, 32,101,109, 98,101,100,100,101,
+100, 32,108,117, 97, 32, 99,111,100,101, 32, 42, 47, 10, 10, 0, 2, 0, 0, 0,
+ 6,112,114,105,110,116, 0, 4, 0, 0, 0, 63, 0, 0, 0, 10, 64, 99,111,100,
+101, 46,108,117, 97, 0, 0, 0, 0, 52, 6, 3, 60, 64, 15, 2, 13, 1, 11, 3,
+ 42, 2, 0, 1, 60, 65, 15, 2, 13, 1, 11, 4, 42, 13, 0, 18, 6, 42, 11, 7,
+ 42, 2, 0, 1, 60, 66, 15, 2, 13, 1, 11, 8, 42, 13, 2, 42, 2, 0, 1, 60,
+ 67, 0, 0, 0, 0, 3, 0, 0, 0, 63, 0, 0, 0, 5,115,101,108,102, 0, 0,
+ 0, 0, 63, 0, 0, 0, 6,105,100,101,110,116, 0, 0, 0, 0, 63, 0, 0, 0,
+ 6, 99,108,111,115,101, 0, 0, 0, 0, 9, 2, 0, 0, 0, 6,105,100,101,110,
+116, 0, 2, 0, 0, 0, 6, 99,108,111,115,101, 0, 2, 0, 0, 0, 6,112,114,
+105,110,116, 0, 2, 0, 0, 0, 6, 67,111,100,101,123, 0, 2, 0, 0, 0, 11,
+ 32,116,101,120,116, 32, 61, 32, 91, 91, 0, 2, 0, 0, 0, 5,115,101,108,102,
+ 0, 2, 0, 0, 0, 5,116,101,120,116, 0, 2, 0, 0, 0, 4, 93, 93, 44, 0,
+ 2, 0, 0, 0, 2,125, 0, 2, 0, 0, 0, 6, 95, 67,111,100,101, 0, 4, 0,
+ 0, 0, 71, 0, 0, 0, 10, 64, 99,111,100,101, 46,108,117, 97, 0, 0, 0, 0,
+ 40, 4, 1, 60, 72, 13, 0, 11, 1, 15, 2, 26, 60, 73, 15, 3, 13, 0, 15, 4,
+ 2, 0, 2, 60, 74, 15, 5, 13, 0, 2, 0, 1, 60, 75, 13, 0, 1, 1, 60, 76,
+ 0, 0, 0, 0, 1, 0, 0, 0, 71, 0, 0, 0, 2,116, 0, 0, 0, 0, 6, 2,
+ 0, 0, 0, 2,116, 0, 2, 0, 0, 0, 6, 95, 98, 97,115,101, 0, 2, 0, 0,
+ 0, 10, 99,108, 97,115,115, 67,111,100,101, 0, 2, 0, 0, 0, 7,115,101,116,
+116, 97,103, 0, 2, 0, 0, 0, 10,116,111,108,117, 97, 95,116, 97,103, 0, 2,
+ 0, 0, 0, 7, 97,112,112,101,110,100, 0, 2, 0, 0, 0, 5, 67,111,100,101,
+ 0, 4, 0, 0, 0, 80, 0, 0, 0, 10, 64, 99,111,100,101, 46,108,117, 97, 0,
+ 0, 0, 0, 24, 5, 1, 60, 81, 15, 1, 22, 1, 60, 82, 11, 2, 13, 0, 30, 0,
+ 60, 83, 3, 1, 1, 60, 84, 0, 0, 0, 0, 1, 0, 0, 0, 80, 0, 0, 0, 2,
+108, 0, 0, 0, 0, 3, 2, 0, 0, 0, 2,108, 0, 2, 0, 0, 0, 6, 95, 67,
+111,100,101, 0, 2, 0, 0, 0, 5,116,101,120,116, 0,
+};
+
+/* doit.lo */
+static char B17[]={
+ 27, 76,117, 97, 50, 0, 0, 0, 0, 0, 0, 0, 0, 10, 64,100,111,105,116, 46,
+108,117, 97, 0, 0, 0, 1, 92, 6, 0, 60, 17, 15, 0, 18, 1, 52, 38, 60, 18,
+ 15, 4, 15, 0, 18, 1, 2, 2, 1, 60, 19, 13, 0, 44, 52, 14, 60, 20, 15, 5,
+ 11, 6, 13, 1, 42, 2, 0, 1, 50, 2, 60, 21, 5, 2, 50, 2, 60, 22, 60, 25,
+ 15, 0, 18, 7, 44, 52, 43, 60, 26, 15, 0, 18, 1, 52, 22, 60, 27, 15, 0, 11,
+ 7, 15, 8, 15, 0, 18, 1, 11, 9, 11, 10, 2, 1, 3, 26, 50, 11, 60, 29, 15,
+ 5, 11, 11, 2, 0, 1, 60, 30, 50, 2, 60, 31, 60, 33, 15, 13, 15, 0, 18, 7,
+ 2, 1, 1, 60, 35, 15, 0, 18, 1, 52, 9, 60, 36, 15, 4, 2, 0, 0, 50, 2,
+ 60, 37, 60, 39, 15, 0, 18, 12, 52, 4, 60, 41, 1, 1, 60, 43, 15, 0, 18, 14,
+ 52, 38, 60, 44, 15, 15, 15, 0, 18, 14, 2, 2, 1, 60, 45, 13, 1, 44, 52, 14,
+ 60, 46, 15, 5, 11, 6, 13, 2, 42, 2, 0, 1, 50, 2, 60, 47, 5, 2, 50, 2,
+ 60, 48, 60, 50, 15, 0, 18, 16, 52, 11, 60, 51, 13, 0, 20, 17, 2, 0, 1, 50,
+ 38, 60, 53, 13, 0, 20, 18, 2, 0, 1, 60, 54, 13, 0, 20, 19, 2, 0, 1, 60,
+ 55, 13, 0, 20, 20, 2, 0, 1, 60, 56, 13, 0, 20, 21, 2, 0, 1, 60, 57, 60,
+ 59, 15, 0, 18, 14, 52, 9, 60, 60, 15, 15, 2, 0, 0, 50, 2, 60, 61, 60, 64,
+ 15, 0, 18, 16, 44, 52, 66, 60, 65, 15, 0, 18, 22, 52, 54, 60, 66, 15, 15, 15,
+ 0, 18, 22, 2, 2, 1, 60, 67, 13, 1, 44, 52, 14, 60, 68, 15, 5, 11, 6, 13,
+ 2, 42, 2, 0, 1, 50, 2, 60, 69, 60, 70, 13, 0, 20, 23, 2, 0, 1, 60, 71,
+ 15, 15, 2, 0, 0, 5, 2, 50, 2, 60, 72, 50, 2, 60, 73, 0, 0, 0, 0, 0,
+ 0, 0, 0, 24, 2, 0, 0, 0, 6,102,108, 97,103,115, 0, 2, 0, 0, 0, 2,
+102, 0, 2, 0, 0, 0, 3,115,116, 0, 2, 0, 0, 0, 4,109,115,103, 0, 2,
+ 0, 0, 0, 9,114,101, 97,100,102,114,111,109, 0, 2, 0, 0, 0, 6,101,114,
+114,111,114, 0, 2, 0, 0, 0, 2, 35, 0, 2, 0, 0, 0, 2,110, 0, 2, 0,
+ 0, 0, 5,103,115,117, 98, 0, 2, 0, 0, 0, 5, 37, 46, 46, 42, 0, 2, 0,
+ 0, 0, 1, 0, 2, 0, 0, 0, 41, 35,110,111, 32,112, 97, 99,107, 97,103,101,
+ 32,110, 97,109,101, 32,110,111,114, 32,105,110,112,117,116, 32,102,105,108,101,
+ 32,112,114,111,118,105,100,101,100, 0, 2, 0, 0, 0, 2,112, 0, 2, 0, 0,
+ 0, 8, 80, 97, 99,107, 97,103,101, 0, 2, 0, 0, 0, 2,111, 0, 2, 0, 0,
+ 0, 8,119,114,105,116,101,116,111, 0, 2, 0, 0, 0, 2, 80, 0, 2, 0, 0,
+ 0, 6,112,114,105,110,116, 0, 2, 0, 0, 0, 9,112,114,101, 97,109, 98,108,
+101, 0, 2, 0, 0, 0, 8,115,117,112, 99,111,100,101, 0, 2, 0, 0, 0, 9,
+114,101,103,105,115,116,101,114, 0, 2, 0, 0, 0, 11,117,110,114,101,103,105,
+115,116,101,114, 0, 2, 0, 0, 0, 2, 72, 0, 2, 0, 0, 0, 7,104,101, 97,
+100,101,114, 0,
+};
+
+ lua_dobuffer(B1,sizeof(B1),"basic.lo");
+ lua_dobuffer(B2,sizeof(B2),"feature.lo");
+ lua_dobuffer(B3,sizeof(B3),"declaration.lo");
+ lua_dobuffer(B4,sizeof(B4),"container.lo");
+ lua_dobuffer(B5,sizeof(B5),"package.lo");
+ lua_dobuffer(B6,sizeof(B6),"module.lo");
+ lua_dobuffer(B7,sizeof(B7),"class.lo");
+ lua_dobuffer(B8,sizeof(B8),"typedef.lo");
+ lua_dobuffer(B9,sizeof(B9),"define.lo");
+ lua_dobuffer(B10,sizeof(B10),"enumerate.lo");
+ lua_dobuffer(B11,sizeof(B11),"variable.lo");
+ lua_dobuffer(B12,sizeof(B12),"array.lo");
+ lua_dobuffer(B13,sizeof(B13),"function.lo");
+ lua_dobuffer(B14,sizeof(B14),"operator.lo");
+ lua_dobuffer(B15,sizeof(B15),"verbatim.lo");
+ lua_dobuffer(B16,sizeof(B16),"code.lo");
+ lua_dobuffer(B17,sizeof(B17),"doit.lo");
+}
diff --git a/src/lua/tolualua.pkg b/src/lua/tolualua.pkg
new file mode 100644
index 00000000..1694c2c1
--- /dev/null
+++ b/src/lua/tolualua.pkg
@@ -0,0 +1,21 @@
+$[
+$<basic.lua>
+$<feature.lua>
+$<verbatim.lua>
+$<code.lua>
+$<typedef.lua>
+$<container.lua>
+$<package.lua>
+$<module.lua>
+$<define.lua>
+$<enumerate.lua>
+$<declaration.lua>
+$<variable.lua>
+$<array.lua>
+$<function.lua>
+$<operator.lua>
+$<class.lua>
+$<clean.lua>
+$<doit.lua>
+$]
+
diff --git a/src/lua/typedef.lua b/src/lua/typedef.lua
new file mode 100644
index 00000000..1633f3e6
--- /dev/null
+++ b/src/lua/typedef.lua
@@ -0,0 +1,59 @@
+-- tolua: typedef class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: typedef.lua,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+
+-- Typedef class
+-- Represents a type synonym.
+-- The 'de facto' type replaces the typedef before the
+-- remaining code is parsed.
+-- The following fields are stored:
+-- utype = typedef name
+-- type = 'de facto' type
+-- mod = modifiers to the 'de facto' type
+classTypedef = {
+ utype = '',
+ mod = '',
+ type = ''
+}
+
+-- Print method
+function classTypedef:print (ident,close)
+ print(ident.."Typedef{")
+ print(ident.." utype = '"..self.utype.."',")
+ print(ident.." mod = '"..self.mod.."',")
+ print(ident.." type = '"..self.type.."',")
+ print(ident.."}"..close)
+end
+
+-- Internal constructor
+function _Typedef (t)
+ t._base = classTypedef
+ settag(t,tolua_tag)
+ appendtypedef(t)
+ return t
+end
+
+-- Constructor
+-- Expects one string representing the type definition.
+function Typedef (s)
+ if strfind(s,'[%*&]') then
+ tolua_error("#invalid typedef: pointers (and references) are not supported")
+ end
+ local t = split(gsub(s,"%s%s*"," ")," ")
+ return _Typedef {
+ utype = t[t.n],
+ type = t[t.n-1],
+ mod = concat(t,1,t.n-2)
+ }
+end
+
+
diff --git a/src/lua/variable.lua b/src/lua/variable.lua
new file mode 100644
index 00000000..310808b8
--- /dev/null
+++ b/src/lua/variable.lua
@@ -0,0 +1,192 @@
+-- tolua: variable class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: variable.lua,v 1.4 2004/06/04 13:42:10 neil Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+-- Variable class
+-- Represents a extern variable or a public member of a class.
+-- Stores all fields present in a declaration.
+classVariable = {
+ _base = classDeclaration,
+}
+
+settag(classVariable,tolua_tag)
+
+-- Print method
+function classVariable:print (ident,close)
+ print(ident.."Variable{")
+ print(ident.." mod = '"..self.mod.."',")
+ print(ident.." type = '"..self.type.."',")
+ print(ident.." ptr = '"..self.ptr.."',")
+ print(ident.." name = '"..self.name.."',")
+ print(ident.." def = '"..self.def.."',")
+ print(ident.." ret = '"..self.ret.."',")
+ print(ident.."}"..close)
+end
+
+-- get variable value
+function classVariable:getvalue (class,static)
+ if class and static then
+ return class..'::'..self.name
+ elseif class then
+ return 'self->'..self.name
+ else
+ return self.name
+ end
+end
+
+-- Write binding functions
+function classVariable:supcode ()
+ local class = self:inclass()
+
+ -- get function ------------------------------------------------
+ if class then
+ output("/* get function:",self.name," of class ",class," */")
+ else
+ output("/* get function:",self.name," */")
+ end
+ self.cgetname = self:cfuncname("toluaI_get")
+ output("static int",self.cgetname,"(lua_State* tolua_S)")
+ output("{")
+
+ -- declare self, if the case
+ local _,_,static = strfind(self.mod,'^%s*(static)')
+ if class and static==nil then
+ output(' ',class,'*','self = ')
+ output('(',class,'*) ')
+ output('tolua_getusertype(tolua_S,1,0);')
+ elseif static then
+ _,_,self.mod = strfind(self.mod,'^%s*static%s%s*(.*)')
+ end
+
+
+ -- check self value
+ if class and static==nil then
+ output(' if (!self) TOLUA_ERR_SELF;');
+ end
+
+ -- return value
+ local t,ct = isbasic(self.type)
+ if t then
+ output(' tolua_push'..t..'(tolua_S,(',ct,')'..self:getvalue(class,static)..');')
+ else
+ if self.ptr == '&' or self.ptr == '' then
+ output(' tolua_pushusertype(tolua_S,(void*)&'..self:getvalue(class,static)..',',self.tag,');')
+ else
+ output(' tolua_pushusertype(tolua_S,(void*)'..self:getvalue(class,static)..',',self.tag,');')
+ end
+ end
+ output(' return 1;')
+ output('}')
+ output('\n')
+
+ -- set function ------------------------------------------------
+ if not strfind(self.mod,'const') then
+ if class then
+ output("/* set function:",self.name," of class ",class," */")
+ else
+ output("/* set function:",self.name," */")
+ end
+ self.csetname = self:cfuncname("toluaI_set")
+ output("static int",self.csetname,"(lua_State* tolua_S)")
+ output("{")
+
+ -- declare self, if the case
+ local narg=1
+ if class and static==nil then
+ output(' ',class,'*','self = ')
+ output('(',class,'*) ')
+ output('tolua_getusertype(tolua_S,1,0);')
+ -- check self value
+ output(' if (!self) TOLUA_ERR_SELF;');
+ narg = narg+1
+ elseif static then
+ _,_,self.mod = strfind(self.mod,'^%s*static%s%s*(.*)')
+ narg = narg+1
+ end
+
+ -- check type
+ output(' if (!'..self:outchecktype(narg)..')')
+ output(' TOLUA_ERR_ASSIGN;')
+
+ -- assign value
+ local ptr = ''
+ if self.ptr~='' then ptr = '*' end
+ output(' ')
+ if class and static then
+ output(class..'::'..self.name)
+ elseif class then
+ output('self->'..self.name)
+ else
+ output(self.name)
+ end
+ local t = isbasic(self.type)
+ output(' = ')
+ if not t and ptr=='' then output('*') end
+ output('((',self.mod,self.type)
+ if not t then
+ output('*')
+ end
+ output(') ')
+ local def = 0
+ if self.def ~= '' then def = self.def end
+ if t then
+ output('tolua_get'..t,'(tolua_S,',narg,',',def,'));')
+ else
+ output('tolua_getusertype(tolua_S,',narg,',',def,'));')
+ end
+ output(' return 0;')
+ output('}')
+ output('\n')
+ end
+
+end
+
+function classVariable:register ()
+ local parent = self:inclass() or self:inmodule()
+ if parent then
+ if self.csetname then
+ output(' tolua_tablevar(tolua_S,"'..parent..'","'..self.lname..'",'..self.cgetname..','..self.csetname..');')
+ else
+ output(' tolua_tablevar(tolua_S,"'..parent..'","'..self.lname..'",'..self.cgetname..',NULL);')
+ end
+ else
+ if self.csetname then
+ output(' tolua_globalvar(tolua_S,"'..self.lname..'",'..self.cgetname..','..self.csetname..');')
+ else
+ output(' tolua_globalvar(tolua_S,"'..self.lname..'",'..self.cgetname..',NULL);')
+ end
+ end
+end
+
+function classVariable:unregister ()
+ if self:inclass()==nil and self:inmodule()==nil then
+ output(' lua_getglobals(tolua_S);')
+ output(' lua_pushstring(tolua_S,"',self.lname,'"); lua_pushnil(tolua_S); lua_rawset(tolua_S,-3);')
+ output(' lua_pop(tolua_S,1);')
+ end
+end
+
+
+-- Internal constructor
+function _Variable (t)
+ t._base = classVariable
+ settag(t,tolua_tag)
+ append(t)
+ return t
+end
+
+-- Constructor
+-- Expects a string representing the variable declaration.
+function Variable (s)
+ return _Variable (Declaration(s,'var'))
+end
+
+
diff --git a/src/lua/verbatim.lua b/src/lua/verbatim.lua
new file mode 100644
index 00000000..9dae0dc3
--- /dev/null
+++ b/src/lua/verbatim.lua
@@ -0,0 +1,77 @@
+-- tolua: verbatim class
+-- Written by Waldemar Celes
+-- TeCGraf/PUC-Rio
+-- Jul 1998
+-- $Id: verbatim.lua,v 1.2 2001/11/26 23:00:27 darkgod Exp $
+
+-- This code is free software; you can redistribute it and/or modify it.
+-- The software provided hereunder is on an "as is" basis, and
+-- the author has no obligation to provide maintenance, support, updates,
+-- enhancements, or modifications.
+
+
+
+-- Verbatim class
+-- Represents a line translated directed to the binding file.
+-- The following filds are stored:
+-- line = line text
+classVerbatim = {
+ line = '',
+ _base = classFeature,
+}
+settag(classVerbatim,tolua_tag)
+
+-- preamble verbatim
+function classVerbatim:preamble ()
+ if not self.cond then
+ write(self.line)
+ end
+end
+
+-- support code
+function classVerbatim:supcode ()
+ if self.cond then
+ write(self.line)
+ write('\n')
+ end
+end
+
+-- register code
+function classVerbatim:register ()
+ if self.cond then
+ write(self.line)
+ end
+end
+
+
+-- Print method
+function classVerbatim:print (ident,close)
+ print(ident.."Verbatim{")
+ print(ident.." line = '"..self.line.."',")
+ print(ident.."}"..close)
+end
+
+
+-- Internal constructor
+function _Verbatim (t)
+ t._base = classVerbatim
+ settag(t,tolua_tag)
+ append(t)
+ return t
+end
+
+-- Constructor
+-- Expects a string representing the text line
+function Verbatim (l)
+ local c
+ if strsub(l,1,1) == '$' then
+ c = 1
+ l = strsub(l,2)
+ end
+ return _Verbatim {
+ line = l,
+ cond = c
+ }
+end
+
+
diff --git a/src/lua_bind.c b/src/lua_bind.c
new file mode 100644
index 00000000..67b75ee6
--- /dev/null
+++ b/src/lua_bind.c
@@ -0,0 +1,691 @@
+/* File: lua_bind.c */
+
+/* Purpose: various lua bindings */
+
+/*
+ * Copyright (c) 2001 DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+#include "lua.h"
+#include "tolua.h"
+extern lua_State *L;
+
+magic_power *grab_magic_power(magic_power *m_ptr, int num)
+{
+ return (&m_ptr[num]);
+}
+
+bool_ lua_spell_success(magic_power *spell, int stat, char *oups_fct)
+{
+ int chance;
+ int minfail = 0;
+
+ /* Spell failure chance */
+ chance = spell->fail;
+
+ /* Reduce failure rate by "effective" level adjustment */
+ chance -= 3 * (p_ptr->lev - spell->min_lev);
+
+ /* Reduce failure rate by INT/WIS adjustment */
+ chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[stat]] - 1);
+
+ /* Not enough mana to cast */
+ if (spell->mana_cost > p_ptr->csp)
+ {
+ chance += 5 * (spell->mana_cost - p_ptr->csp);
+ }
+
+ /* Extract the minimum failure rate */
+ minfail = adj_mag_fail[p_ptr->stat_ind[stat]];
+
+ /* Failure rate */
+ chance = clamp_failure_chance(chance, minfail);
+
+ /* Failed spell */
+ if (rand_int(100) < chance)
+ {
+ if (flush_failure) flush();
+ msg_format("You failed to concentrate hard enough!");
+ sound(SOUND_FAIL);
+
+ if (oups_fct != NULL)
+ exec_lua(format("%s(%d)", oups_fct, chance));
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * Create objects
+ */
+object_type *new_object()
+{
+ object_type *o_ptr;
+ MAKE(o_ptr, object_type);
+ return (o_ptr);
+}
+
+void end_object(object_type *o_ptr)
+{
+ FREE(o_ptr, object_type);
+}
+
+/*
+ * Powers
+ */
+s16b add_new_power(cptr name, cptr desc, cptr gain, cptr lose, byte level, byte cost, byte stat, byte diff)
+{
+ /* Increase the size */
+ reinit_powers_type(power_max + 1);
+
+ /* Copy the strings */
+ C_MAKE(powers_type[power_max - 1].name, strlen(name) + 1, char);
+ strcpy(powers_type[power_max - 1].name, name);
+ C_MAKE(powers_type[power_max - 1].desc_text, strlen(desc) + 1, char);
+ strcpy(powers_type[power_max - 1].desc_text, desc);
+ C_MAKE(powers_type[power_max - 1].gain_text, strlen(gain) + 1, char);
+ strcpy(powers_type[power_max - 1].gain_text, gain);
+ C_MAKE(powers_type[power_max - 1].lose_text, strlen(lose) + 1, char);
+ strcpy(powers_type[power_max - 1].lose_text, lose);
+
+ /* Copy the other stuff */
+ powers_type[power_max - 1].level = level;
+ powers_type[power_max - 1].cost = cost;
+ powers_type[power_max - 1].stat = stat;
+ powers_type[power_max - 1].diff = diff;
+
+ return (power_max - 1);
+}
+
+static char *lua_item_tester_fct;
+static bool_ lua_item_tester(object_type* o_ptr)
+{
+ int oldtop = lua_gettop(L);
+ bool_ ret;
+
+ lua_getglobal(L, lua_item_tester_fct);
+ tolua_pushusertype(L, o_ptr, tolua_tag(L, "object_type"));
+ lua_call(L, 1, 1);
+ ret = lua_tonumber(L, -1);
+ lua_settop(L, oldtop);
+ return (ret);
+}
+
+void lua_set_item_tester(int tval, char *fct)
+{
+ if (tval)
+ {
+ item_tester_tval = tval;
+ }
+ else
+ {
+ lua_item_tester_fct = fct;
+ item_tester_hook = lua_item_tester;
+ }
+}
+
+char *lua_object_desc(object_type *o_ptr, int pref, int mode)
+{
+ static char buf[150];
+
+ object_desc(buf, o_ptr, pref, mode);
+ return (buf);
+}
+
+/*
+ * Monsters
+ */
+
+void find_position(int y, int x, int *yy, int *xx)
+{
+ int attempts = 500;
+
+ do
+ {
+ scatter(yy, xx, y, x, 6);
+ }
+ while (!(in_bounds(*yy, *xx) && cave_floor_bold(*yy, *xx)) && --attempts);
+}
+
+static char *summon_lua_okay_fct;
+bool_ summon_lua_okay(int r_idx)
+{
+ int oldtop = lua_gettop(L);
+ bool_ ret;
+
+ lua_getglobal(L, lua_item_tester_fct);
+ tolua_pushnumber(L, r_idx);
+ lua_call(L, 1, 1);
+ ret = lua_tonumber(L, -1);
+ lua_settop(L, oldtop);
+ return (ret);
+}
+
+bool_ lua_summon_monster(int y, int x, int lev, bool_ friend_, char *fct)
+{
+ summon_lua_okay_fct = fct;
+
+ if (!friend_)
+ return summon_specific(y, x, lev, SUMMON_LUA);
+ else
+ return summon_specific_friendly(y, x, lev, SUMMON_LUA, TRUE);
+}
+
+/*
+ * Quests
+ */
+s16b add_new_quest(char *name)
+{
+ int i;
+
+ /* Increase the size */
+ reinit_quests(max_q_idx + 1);
+ quest[max_q_idx - 1].type = HOOK_TYPE_LUA;
+ strncpy(quest[max_q_idx - 1].name, name, 39);
+
+ for (i = 0; i < 10; i++)
+ strncpy(quest[max_q_idx - 1].desc[i], "", 39);
+
+ return (max_q_idx - 1);
+}
+
+void desc_quest(int q_idx, int d, char *desc)
+{
+ if (d >= 0 && d < 10)
+ strncpy(quest[q_idx].desc[d], desc, 79);
+}
+
+/*
+ * Misc
+ */
+bool_ get_com_lua(cptr prompt, int *com)
+{
+ char c;
+
+ if (!get_com(prompt, &c)) return (FALSE);
+ *com = c;
+ return (TRUE);
+}
+
+/* Spell schools */
+s16b new_school(int i, cptr name, s16b skill)
+{
+ schools[i].name = string_make(name);
+ schools[i].skill = skill;
+ return (i);
+}
+
+s16b new_spell(int i, cptr name)
+{
+ school_spells[i].name = string_make(name);
+ school_spells[i].level = 0;
+ school_spells[i].level = 0;
+ return (i);
+}
+
+spell_type *grab_spell_type(s16b num)
+{
+ return (&school_spells[num]);
+}
+
+school_type *grab_school_type(s16b num)
+{
+ return (&schools[num]);
+}
+
+/* Change this fct if I want to switch to learnable spells */
+s32b lua_get_level(s32b s, s32b lvl, s32b max, s32b min, s32b bonus)
+{
+ s32b tmp;
+
+ tmp = lvl - ((school_spells[s].skill_level - 1) * (SKILL_STEP / 10));
+
+ if (tmp >= (SKILL_STEP / 10)) /* We require at least one spell level */
+ tmp += bonus;
+
+ tmp = (tmp * (max * (SKILL_STEP / 10)) / (SKILL_MAX / 10));
+
+ if (tmp < 0) /* Shift all negative values, so they map to appropriate integer */
+ tmp -= SKILL_STEP / 10 - 1;
+
+ /* Now, we can safely divide */
+ lvl = tmp / (SKILL_STEP / 10);
+
+ if (lvl < min)
+ lvl = min;
+
+ return lvl;
+}
+
+s32b lua_spell_chance(s32b chance, int level, int skill_level, int mana, int cur_mana, int stat)
+{
+ int minfail;
+ /* Reduce failure rate by "effective" level adjustment */
+ chance -= 3 * (level - 1);
+
+ /* Reduce failure rate by INT/WIS adjustment */
+ chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[stat]] - 1);
+
+ /* Not enough mana to cast */
+ if (chance < 0) chance = 0;
+ if (mana > cur_mana)
+ {
+ chance += 15 * (mana - cur_mana);
+ }
+
+ /* Extract the minimum failure rate */
+ minfail = adj_mag_fail[p_ptr->stat_ind[stat]];
+
+ /*
+ * Non mage characters never get too good
+ */
+ if (!(has_ability(AB_PERFECT_CASTING)))
+ {
+ if (minfail < 5) minfail = 5;
+ }
+
+ /* Hack -- Priest prayer penalty for "edged" weapons -DGK */
+ if ((forbid_non_blessed()) && (p_ptr->icky_wield)) chance += 25;
+
+ /* Return the chance */
+ return clamp_failure_chance(chance, minfail);
+}
+
+s32b lua_spell_device_chance(s32b chance, int level, int base_level)
+{
+ int minfail;
+
+ /* Reduce failure rate by "effective" level adjustment */
+ chance -= (level - 1);
+
+ /* Extract the minimum failure rate */
+ minfail = 15 - get_skill_scale(SKILL_DEVICE, 25);
+
+ /* Return the chance */
+ return clamp_failure_chance(chance, minfail);
+}
+
+/* Cave */
+cave_type *lua_get_cave(int y, int x)
+{
+ return (&(cave[y][x]));
+}
+
+void set_target(int y, int x)
+{
+ target_who = -1;
+ target_col = x;
+ target_row = y;
+}
+
+void get_target(int dir, int *y, int *x)
+{
+ int ty, tx;
+
+ /* Use the given direction */
+ tx = p_ptr->px + (ddx[dir] * 100);
+ ty = p_ptr->py + (ddy[dir] * 100);
+
+ /* Hack -- Use an actual "target" */
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+ }
+ *y = ty;
+ *x = tx;
+}
+
+/* Level gen */
+void get_map_size(char *name, int *ysize, int *xsize)
+{
+ *xsize = 0;
+ *ysize = 0;
+ init_flags = INIT_GET_SIZE;
+ process_dungeon_file(name, ysize, xsize, cur_hgt, cur_wid, TRUE, TRUE);
+}
+
+void load_map(char *name, int *y, int *x)
+{
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file(name, y, x, cur_hgt, cur_wid, TRUE, TRUE);
+}
+
+bool_ alloc_room(int by0, int bx0, int ysize, int xsize, int *y1, int *x1, int *y2, int *x2)
+{
+ int xval, yval, x, y;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &xval, &yval)) return FALSE;
+
+ /* Get corner values */
+ *y1 = yval - ysize / 2;
+ *x1 = xval - xsize / 2;
+ *y2 = yval + (ysize) / 2;
+ *x2 = xval + (xsize) / 2;
+
+ /* Place a full floor under the room */
+ for (y = *y1 - 1; y <= *y2 + 1; y++)
+ {
+ for (x = *x1 - 1; x <= *x2 + 1; x++)
+ {
+ cave_type *c_ptr = &cave[y][x];
+ cave_set_feat(y, x, floor_type[rand_int(100)]);
+ c_ptr->info |= (CAVE_ROOM);
+ c_ptr->info |= (CAVE_GLOW);
+ }
+ }
+ return TRUE;
+}
+
+
+/* Files */
+void lua_print_hook(cptr str)
+{
+ fprintf(hook_file, "%s", str);
+}
+
+
+/*
+ * Finds a good random bounty monster
+ * Im too lazy to write it in lua since the lua API for monsters is not very well yet
+ */
+
+/*
+ * Hook for bounty monster selection.
+ */
+static bool_ lua_mon_hook_bounty(int r_idx)
+{
+ monster_race* r_ptr = &r_info[r_idx];
+
+
+ /* Reject uniques */
+ if (r_ptr->flags1 & RF1_UNIQUE) return (FALSE);
+
+ /* Reject those who cannot leave anything */
+ if (!(r_ptr->flags9 & RF9_DROP_CORPSE)) return (FALSE);
+
+ /* Accept only monsters that can be generated */
+ if (r_ptr->flags9 & RF9_SPECIAL_GENE) return (FALSE);
+ if (r_ptr->flags9 & RF9_NEVER_GENE) return (FALSE);
+
+ /* Reject pets */
+ if (r_ptr->flags7 & RF7_PET) return (FALSE);
+
+ /* Reject friendly creatures */
+ if (r_ptr->flags7 & RF7_FRIENDLY) return (FALSE);
+
+ /* Accept only monsters that are not breeders */
+ if (r_ptr->flags4 & RF4_MULTIPLY) return (FALSE);
+
+ /* Forbid joke monsters */
+ if (r_ptr->flags8 & RF8_JOKEANGBAND) return (FALSE);
+
+ /* Accept only monsters that are not good */
+ if (r_ptr->flags3 & RF3_GOOD) return (FALSE);
+
+ /* The rest are acceptable */
+ return (TRUE);
+}
+
+int lua_get_new_bounty_monster(int lev)
+{
+ int r_idx;
+
+ /*
+ * Set up the hooks -- no bounties on uniques or monsters
+ * with no corpses
+ */
+ get_mon_num_hook = lua_mon_hook_bounty;
+ get_mon_num_prep();
+
+ /* Set up the quest monster. */
+ r_idx = get_mon_num(lev);
+
+ /* Undo the filters */
+ get_mon_num_hook = NULL;
+ get_mon_num_prep();
+
+ return r_idx;
+}
+
+/*
+ * Some misc functions
+ */
+char *lua_input_box(cptr title, int max)
+{
+ static char buf[80];
+ int wid, hgt;
+
+ strcpy(buf, "");
+ Term_get_size(&wid, &hgt);
+ if (!input_box(title, hgt / 2, wid / 2, buf, (max > 79) ? 79 : max))
+ return "";
+ return buf;
+}
+
+char lua_msg_box(cptr title)
+{
+ int wid, hgt;
+
+ Term_get_size(&wid, &hgt);
+ return msg_box(title, hgt / 2, wid / 2);
+}
+
+list_type *lua_create_list(int size)
+{
+ list_type *l;
+ cptr *list;
+
+ MAKE(l, list_type);
+ C_MAKE(list, size, cptr);
+ l->list = list;
+ return l;
+}
+
+void lua_delete_list(list_type *l, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ string_free(l->list[i]);
+ C_FREE(l->list, size, cptr);
+ FREE(l, list_type);
+}
+
+void lua_add_to_list(list_type *l, int idx, cptr str)
+{
+ l->list[idx] = string_make(str);
+}
+
+void lua_display_list(int y, int x, int h, int w, cptr title, list_type* list, int max, int begin, int sel, byte sel_color)
+{
+ display_list(y, x, h, w, title, list->list, max, begin, sel, sel_color);
+}
+
+/*
+ * Gods
+ */
+s16b add_new_gods(char *name)
+{
+ int i;
+
+ /* Increase the size */
+ reinit_gods(max_gods + 1);
+ deity_info[max_gods - 1].name = string_make(name);
+
+ for (i = 0; i < 10; i++)
+ strncpy(deity_info[max_gods - 1].desc[i], "", 39);
+
+ return (max_gods - 1);
+}
+
+void desc_god(int g_idx, int d, char *desc)
+{
+ if (d >= 0 && d < 10)
+ strncpy(deity_info[g_idx].desc[d], desc, 79);
+}
+
+/*
+ * Returns the direction of the compass that y2, x2 is from y, x
+ * the return value will be one of the following: north, south,
+ * east, west, north-east, south-east, south-west, north-west,
+ * or "close" if it is within 2 tiles.
+ */
+cptr compass(int y, int x, int y2, int x2)
+{
+ static char compass_dir[64];
+
+ // is it close to the north/south meridian?
+ int y_diff = y2 - y;
+
+ // determine if y2, x2 is to the north or south of y, x
+ const char *y_axis;
+ if ((y_diff > -3) && (y_diff < 3))
+ {
+ y_axis = 0;
+ }
+ else if (y2 > y)
+ {
+ y_axis = "south";
+ }
+ else
+ {
+ y_axis = "north";
+ }
+
+ // is it close to the east/west meridian?
+ int x_diff = x2 - x;
+
+ // determine if y2, x2 is to the east or west of y, x
+ const char *x_axis;
+ if ((x_diff > -3) && (x_diff < 3))
+ {
+ x_axis = 0;
+ }
+ else if (x2 > x)
+ {
+ x_axis = "east";
+ }
+ else
+ {
+ x_axis = "west";
+ }
+
+ // Maybe it is very close
+ if ((!x_axis) && (!y_axis)) { strcpy(compass_dir, "close"); }
+ // Maybe it is (almost) due N/S
+ else if (!x_axis) { strcpy(compass_dir, y_axis); }
+ // Maybe it is (almost) due E/W
+ else if (!y_axis) { strcpy(compass_dir, x_axis); }
+ // or if it is neither
+ else { sprintf(compass_dir, "%s-%s", y_axis, x_axis); }
+ return compass_dir;
+}
+
+/* Returns a relative approximation of the 'distance' of y2, x2 from y, x. */
+cptr approximate_distance(int y, int x, int y2, int x2)
+{
+ // how far to away to the north/south?
+ int y_diff = abs(y2 - y);
+ // how far to away to the east/west?
+ int x_diff = abs(x2 - x);
+ // find which one is the larger distance
+ int most_dist = x_diff;
+ if (y_diff > most_dist) {
+ most_dist = y_diff;
+ }
+
+ // how far away then?
+ if (most_dist >= 41) {
+ return "a very long way";
+ } else if (most_dist >= 25) {
+ return "a long way";
+ } else if (most_dist >= 8) {
+ return "quite some way";
+ } else {
+ return "not very far";
+ }
+}
+
+bool_ drop_text_left(byte c, cptr str, int y, int o)
+{
+ int i = strlen(str);
+ int x = 39 - (strlen(str) / 2) + o;
+ while (i > 0)
+ {
+ int a = 0;
+ int time = 0;
+
+ if (str[i-1] != ' ')
+ {
+ while (a < x + i - 1)
+ {
+ Term_putch(a - 1, y, c, 32);
+ Term_putch(a, y, c, str[i-1]);
+ time = time + 1;
+ if (time >= 4)
+ {
+ Term_xtra(TERM_XTRA_DELAY, 1);
+ time = 0;
+ }
+ Term_redraw_section(a - 1, y, a, y);
+ a = a + 1;
+
+ inkey_scan = TRUE;
+ if (inkey()) {
+ return TRUE;
+ }
+ }
+ }
+
+ i = i - 1;
+ }
+ return FALSE;
+}
+
+bool_ drop_text_right(byte c, cptr str, int y, int o)
+{
+ int x = 39 - (strlen(str) / 2) + o;
+ int i = 1;
+ while (i <= strlen(str))
+ {
+ int a = 79;
+ int time = 0;
+
+ if (str[i-1] != ' ') {
+ while (a >= x + i - 1)
+ {
+ Term_putch(a + 1, y, c, 32);
+ Term_putch(a, y, c, str[i-1]);
+ time = time + 1;
+ if (time >= 4) {
+ Term_xtra(TERM_XTRA_DELAY, 1);
+ time = 0;
+ }
+ Term_redraw_section(a, y, a + 1, y);
+ a = a - 1;
+
+ inkey_scan = TRUE;
+ if (inkey()) {
+ return TRUE;
+ }
+ }
+ }
+
+ i = i + 1;
+ }
+ return FALSE;
+}
diff --git a/src/maid-x11.c b/src/maid-x11.c
new file mode 100755
index 00000000..86df2119
--- /dev/null
+++ b/src/maid-x11.c
@@ -0,0 +1,855 @@
+/* File: maid-x11.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison, and others
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+#if defined(USE_X11) || defined(USE_XAW)
+
+/*
+ * This file defines some "XImage" manipulation functions for X11.
+ *
+ * Original code by Desvignes Sebastien (desvigne@solar12.eerie.fr).
+ *
+ * BMP format support by Denis Eropkin (denis@dream.homepage.ru).
+ *
+ * Major fixes and cleanup by Ben Harrison (benh@phial.com).
+ *
+ * This file is designed to be "included" by "main-x11.c" or "main-xaw.c",
+ * which will have already "included" several relevant header files.
+ */
+
+#ifndef IsModifierKey
+
+/*
+ * Keysym macros, used on Keysyms to test for classes of symbols
+ * These were stolen from one of the X11 header files
+ *
+ * Also appears in "main-x11.c".
+ */
+
+#define IsKeypadKey(keysym) \
+(((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
+
+#define IsCursorKey(keysym) \
+(((unsigned)(keysym) >= XK_Home) && ((unsigned)(keysym) < XK_Select))
+
+#define IsPFKey(keysym) \
+(((unsigned)(keysym) >= XK_KP_F1) && ((unsigned)(keysym) <= XK_KP_F4))
+
+#define IsFunctionKey(keysym) \
+(((unsigned)(keysym) >= XK_F1) && ((unsigned)(keysym) <= XK_F35))
+
+#define IsMiscFunctionKey(keysym) \
+(((unsigned)(keysym) >= XK_Select) && ((unsigned)(keysym) < XK_KP_Space))
+
+#define IsModifierKey(keysym) \
+(((unsigned)(keysym) >= XK_Shift_L) && ((unsigned)(keysym) <= XK_Hyper_R))
+
+#endif /* IsModifierKey */
+
+
+/*
+ * Checks if the keysym is a special key or a normal key
+ * Assume that XK_MISCELLANY keysyms are special
+ *
+ * Also appears in "main-x11.c".
+ */
+#define IsSpecialKey(keysym) \
+((unsigned)(keysym) >= 0xFF00)
+
+
+/*
+ * Hack -- Convert an RGB value to an X11 Pixel, or die.
+ */
+static unsigned long create_pixel(Display *dpy, byte red, byte green, byte blue)
+{
+ Colormap cmap = DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy));
+
+ char cname[8];
+
+ XColor xcolour;
+
+ /* Build the color */
+
+ xcolour.red = red * 255 + red;
+ xcolour.green = green * 255 + green;
+ xcolour.blue = blue * 255 + blue;
+ xcolour.flags = DoRed | DoGreen | DoBlue;
+
+ /* Attempt to Allocate the Parsed color */
+ if (!(XAllocColor(dpy, cmap, &xcolour)))
+ {
+ quit_fmt("Couldn't allocate bitmap color '%s'\n", cname);
+ }
+
+ return (xcolour.pixel);
+}
+
+
+
+#ifdef USE_GRAPHICS
+
+/*
+ * The Win32 "BITMAPFILEHEADER" type.
+ */
+typedef struct BITMAPFILEHEADER
+{
+ u16b bfType;
+ u32b bfSize;
+ u16b bfReserved1;
+ u16b bfReserved2;
+ u32b bfOffBits;
+}
+BITMAPFILEHEADER;
+
+
+/*
+ * The Win32 "BITMAPINFOHEADER" type.
+ */
+typedef struct BITMAPINFOHEADER
+{
+ u32b biSize;
+ u32b biWidth;
+ u32b biHeight;
+ u16b biPlanes;
+ u16b biBitCount;
+ u32b biCompresion;
+ u32b biSizeImage;
+ u32b biXPelsPerMeter;
+ u32b biYPelsPerMeter;
+ u32b biClrUsed;
+ u32b biClrImportand;
+}
+BITMAPINFOHEADER;
+
+/*
+ * The Win32 "RGBQUAD" type.
+ */
+typedef struct RGBQUAD
+{
+ unsigned char b, g, r;
+ unsigned char filler;
+}
+RGBQUAD;
+
+
+/*** Helper functions for system independent file loading. ***/
+
+static byte get_byte(FILE *fff)
+{
+ /* Get a character, and return it */
+ return (getc(fff) & 0xFF);
+}
+
+static void rd_byte(FILE *fff, byte *ip)
+{
+ *ip = get_byte(fff);
+}
+
+static void rd_u16b(FILE *fff, u16b *ip)
+{
+ (*ip) = get_byte(fff);
+ (*ip) |= ((u16b)(get_byte(fff)) << 8);
+}
+
+static void rd_u32b(FILE *fff, u32b *ip)
+{
+ (*ip) = get_byte(fff);
+ (*ip) |= ((u32b)(get_byte(fff)) << 8);
+ (*ip) |= ((u32b)(get_byte(fff)) << 16);
+ (*ip) |= ((u32b)(get_byte(fff)) << 24);
+}
+
+
+/*
+ * Read a Win32 BMP file.
+ *
+ * This function replaces the old ReadRaw and RemapColors functions.
+ *
+ * Assumes that the bitmap has a size such that no padding is needed in
+ * various places. Currently only handles bitmaps with 3 to 256 colors.
+ */
+static XImage *ReadBMP(Display *dpy, char *Name)
+{
+ Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
+
+ int depth = DefaultDepth(dpy, DefaultScreen(dpy));
+
+ FILE *f;
+
+ BITMAPFILEHEADER fileheader;
+ BITMAPINFOHEADER infoheader;
+
+ XImage *Res = NULL;
+
+ char *Data;
+
+ int ncol;
+
+ int total;
+
+ int i, j;
+
+ u32b x, y;
+
+ unsigned long clr_pixels[256];
+
+
+ /* Open the BMP file */
+ f = fopen(Name, "r");
+
+ /* No such file */
+ if (f == NULL)
+ {
+ return (NULL);
+ }
+
+ /* Read the "BITMAPFILEHEADER" */
+ rd_u16b(f, &(fileheader.bfType));
+ rd_u32b(f, &(fileheader.bfSize));
+ rd_u16b(f, &(fileheader.bfReserved1));
+ rd_u16b(f, &(fileheader.bfReserved2));
+ rd_u32b(f, &(fileheader.bfOffBits));
+
+ /* Read the "BITMAPINFOHEADER" */
+ rd_u32b(f, &(infoheader.biSize));
+ rd_u32b(f, &(infoheader.biWidth));
+ rd_u32b(f, &(infoheader.biHeight));
+ rd_u16b(f, &(infoheader.biPlanes));
+ rd_u16b(f, &(infoheader.biBitCount));
+ rd_u32b(f, &(infoheader.biCompresion));
+ rd_u32b(f, &(infoheader.biSizeImage));
+ rd_u32b(f, &(infoheader.biXPelsPerMeter));
+ rd_u32b(f, &(infoheader.biYPelsPerMeter));
+ rd_u32b(f, &(infoheader.biClrUsed));
+ rd_u32b(f, &(infoheader.biClrImportand));
+
+ /* Verify the header */
+ if (feof(f) ||
+ (fileheader.bfType != 19778) ||
+ (infoheader.biSize != 40))
+ {
+ quit_fmt("Incorrect BMP file format %s", Name);
+ }
+
+ /* The two headers above occupy 54 bytes total */
+ /* The "bfOffBits" field says where the data starts */
+ /* The "biClrUsed" field does not seem to be reliable */
+ /* Compute number of colors recorded */
+ ncol = (fileheader.bfOffBits - 54) / 4;
+
+ for (i = 0; i < ncol; i++)
+ {
+ RGBQUAD clrg;
+
+ /* Read an "RGBQUAD" */
+ rd_byte(f, &(clrg.b));
+ rd_byte(f, &(clrg.g));
+ rd_byte(f, &(clrg.r));
+ rd_byte(f, &(clrg.filler));
+
+ /* Analyze the color */
+ clr_pixels[i] = create_pixel(dpy, clrg.r, clrg.g, clrg.b);
+ }
+
+ /* Determine total bytes needed for image */
+ i = 1;
+ j = (depth - 1) >> 2;
+ while (j >>= 1) i <<= 1;
+ total = infoheader.biWidth * infoheader.biHeight * i;
+
+ /* Allocate image memory */
+ C_MAKE(Data, total, char);
+
+ Res = XCreateImage(dpy, visual, depth, ZPixmap, 0 /*offset*/,
+ Data, infoheader.biWidth, infoheader.biHeight,
+ 8 /*bitmap_pad*/, 0 /*bytes_per_line*/);
+
+ /* Failure */
+ if (Res == NULL)
+ {
+ C_KILL(Data, total, char);
+ fclose(f);
+ return (NULL);
+ }
+
+ for (y = 0; y < infoheader.biHeight; y++)
+ {
+ int y2 = infoheader.biHeight - y - 1;
+
+ for (x = 0; x < infoheader.biWidth; x++)
+ {
+ int ch = getc(f);
+
+ /* Verify not at end of file XXX XXX */
+ if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
+
+ if (infoheader.biBitCount == 24)
+ {
+ int c2 = getc(f);
+ int c3 = getc(f);
+
+ /* Verify not at end of file XXX XXX */
+ if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
+
+ XPutPixel(Res, x, y2, create_pixel(dpy, ch, c2, c3));
+ }
+ else if (infoheader.biBitCount == 8)
+ {
+ XPutPixel(Res, x, y2, clr_pixels[ch]);
+ }
+ else if (infoheader.biBitCount == 4)
+ {
+ XPutPixel(Res, x, y2, clr_pixels[ch / 16]);
+ x++;
+ XPutPixel(Res, x, y2, clr_pixels[ch % 16]);
+ }
+ else
+ {
+ /* Technically 1 bit is legal too */
+ quit_fmt("Illegal biBitCount %d in %s",
+ infoheader.biBitCount, Name);
+ }
+ }
+ }
+
+ fclose(f);
+
+ return Res;
+}
+
+
+/* ========================================================*/
+/* Code for smooth icon rescaling from Uwe Siems, Jan 2000 */
+/* ========================================================*/
+
+/*
+ * to save ourselves some labour, define a maximum expected icon width here:
+ */
+#define MAX_ICON_WIDTH 32
+
+
+/* some static variables for composing and decomposing pixel values into
+ * red, green and blue values
+ */
+static unsigned long redMask, greenMask, blueMask;
+static int redShift, greenShift, blueShift;
+
+
+/*
+ * Use smooth rescaling?
+ */
+static bool_ smoothRescaling = TRUE;
+
+
+/*
+ * GetScaledRow reads a scan from the given XImage, scales it smoothly
+ * and returns the red, green and blue values in arrays.
+ * The values in this arrays must be divided by a certain value that is
+ * calculated in ScaleIcon.
+ * x, y is the position, iw is the input width and ow the output width
+ * redScan, greenScan and blueScan must be sufficiently sized
+ */
+static void GetScaledRow(XImage *Im, int x, int y, int iw, int ow,
+ unsigned long *redScan, unsigned long *greenScan,
+ unsigned long *blueScan)
+{
+ int xi, si, sifrac, ci, cifrac, addWhole, addFrac;
+ unsigned long pix;
+ int prevRed, prevGreen, prevBlue, nextRed, nextGreen, nextBlue;
+ bool_ getNextPix;
+
+ if (iw == ow)
+ {
+ /* unscaled */
+ for (xi = 0; xi < ow; xi++)
+ {
+ pix = XGetPixel(Im, x + xi, y);
+ redScan [xi] = (pix >> redShift) & redMask;
+ greenScan [xi] = (pix >> greenShift) & greenMask;
+ blueScan [xi] = (pix >> blueShift) & blueMask;
+ }
+ }
+ else if (iw < ow)
+ {
+ /* scaling by subsampling (grow) */
+ iw--;
+ ow--;
+ /* read first pixel: */
+ pix = XGetPixel(Im, x, y);
+ nextRed = (pix >> redShift) & redMask;
+ nextGreen = (pix >> greenShift) & greenMask;
+ nextBlue = (pix >> blueShift) & blueMask;
+ prevRed = nextRed;
+ prevGreen = nextGreen;
+ prevBlue = nextBlue;
+ /* si and sifrac give the subsampling position: */
+ si = x;
+ sifrac = 0;
+ /* getNextPix tells us, that we need the next pixel */
+ getNextPix = TRUE;
+
+ for (xi = 0; xi <= ow; xi++)
+ {
+ if (getNextPix)
+ {
+ prevRed = nextRed;
+ prevGreen = nextGreen;
+ prevBlue = nextBlue;
+ if (xi < ow)
+ {
+ /* only get next pixel if in same icon */
+ pix = XGetPixel(Im, si + 1, y);
+ nextRed = (pix >> redShift) & redMask;
+ nextGreen = (pix >> greenShift) & greenMask;
+ nextBlue = (pix >> blueShift) & blueMask;
+ }
+ }
+
+ /* calculate subsampled color values: */
+ /* division by ow occurs in ScaleIcon */
+ redScan [xi] = prevRed * (ow - sifrac) + nextRed * sifrac;
+ greenScan [xi] = prevGreen * (ow - sifrac) + nextGreen * sifrac;
+ blueScan [xi] = prevBlue * (ow - sifrac) + nextBlue * sifrac;
+
+ /* advance sampling position: */
+ sifrac += iw;
+ if (sifrac >= ow)
+ {
+ si++;
+ sifrac -= ow;
+ getNextPix = TRUE;
+ }
+ else
+ {
+ getNextPix = FALSE;
+ }
+
+ }
+ }
+ else
+ {
+ /* scaling by averaging (shrink) */
+ /* width of an output pixel in input pixels: */
+ addWhole = iw / ow;
+ addFrac = iw % ow;
+ /* start position of the first output pixel: */
+ si = x;
+ sifrac = 0;
+ /* get first input pixel: */
+ pix = XGetPixel(Im, x, y);
+ nextRed = (pix >> redShift) & redMask;
+ nextGreen = (pix >> greenShift) & greenMask;
+ nextBlue = (pix >> blueShift) & blueMask;
+ for (xi = 0; xi < ow; xi++)
+ {
+ /* find endpoint of the current output pixel: */
+ ci = si + addWhole;
+ cifrac = sifrac + addFrac;
+ if (cifrac >= ow)
+ {
+ ci++;
+ cifrac -= ow;
+ }
+ /* take fraction of current input pixel (starting segment): */
+ redScan[xi] = nextRed * (ow - sifrac);
+ greenScan[xi] = nextGreen * (ow - sifrac);
+ blueScan[xi] = nextBlue * (ow - sifrac);
+ si++;
+ /* add values for whole pixels: */
+ while (si < ci)
+ {
+ pix = XGetPixel(Im, si, y);
+ redScan[xi] += ((pix >> redShift) & redMask) * ow;
+ greenScan[xi] += ((pix >> greenShift) & greenMask) * ow;
+ blueScan[xi] += ((pix >> blueShift) & blueMask) * ow;
+ si++;
+ }
+ /* add fraction of current input pixel (ending segment): */
+ if (xi < ow - 1)
+ {
+ /* only get next pixel if still in icon: */
+ pix = XGetPixel(Im, si, y);
+ nextRed = (pix >> redShift) & redMask;
+ nextGreen = (pix >> greenShift) & greenMask;
+ nextBlue = (pix >> blueShift) & blueMask;
+ }
+ sifrac = cifrac;
+ if (sifrac > 0)
+ {
+ redScan[xi] += nextRed * sifrac;
+ greenScan[xi] += nextGreen * sifrac;
+ blueScan[xi] += nextBlue * sifrac;
+ }
+ }
+ }
+}
+
+
+/*
+ * PutRGBScan takes arrays for red, green and blue and writes pixel values
+ * according to this values in the XImage-structure. w is the number of
+ * pixels to write and div is the value by which all red/green/blue values
+ * are divided first.
+ */
+static void PutRGBScan(XImage *Im, int x, int y, int w, int div,
+ unsigned long *redScan, unsigned long *greenScan,
+ unsigned long *blueScan)
+{
+ int xi;
+ unsigned long pix;
+ unsigned long adj = div / 2;
+ for (xi = 0; xi < w; xi++)
+ {
+ pix = (((((redScan[xi] + adj) / div) & redMask) << redShift) +
+ ((((greenScan[xi] + adj) / div) & greenMask) << greenShift) +
+ ((((blueScan[xi] + adj) / div) & blueMask) << blueShift));
+ XPutPixel(Im, x + xi, y, pix);
+ }
+}
+
+
+/*
+ * ScaleIcon transfers an area from XImage ImIn, locate (x1,y1) to ImOut,
+ * locate (x2, y2).
+ * Source size is (ix, iy) and destination size is (ox, oy).
+ * It does this by getting icon scan line from GetScaledScan and handling
+ * them the same way as pixels are handled in GetScaledScan.
+ * This even allows icons to be scaled differently in horizontal and
+ * vertical directions (eg. shrink horizontal, grow vertical).
+ */
+static void ScaleIcon(XImage *ImIn, XImage *ImOut,
+ int x1, int y1, int x2, int y2,
+ int ix, int iy, int ox, int oy)
+{
+ int div;
+ int xi, yi, si, sifrac, ci, cifrac, addWhole, addFrac;
+
+ /* buffers for pixel rows: */
+ unsigned long prevRed [MAX_ICON_WIDTH];
+ unsigned long prevGreen [MAX_ICON_WIDTH];
+ unsigned long prevBlue [MAX_ICON_WIDTH];
+ unsigned long nextRed [MAX_ICON_WIDTH];
+ unsigned long nextGreen [MAX_ICON_WIDTH];
+ unsigned long nextBlue [MAX_ICON_WIDTH];
+ unsigned long tempRed [MAX_ICON_WIDTH];
+ unsigned long tempGreen [MAX_ICON_WIDTH];
+ unsigned long tempBlue [MAX_ICON_WIDTH];
+
+ bool_ getNextRow;
+
+ /* get divider value for the horizontal scaling: */
+ if (ix == ox)
+ div = 1;
+ else if (ix < ox)
+ div = ox - 1;
+ else
+ div = ix;
+
+ if (iy == oy)
+ {
+ /* no scaling needed vertically: */
+ for (yi = 0; yi < oy; yi++)
+ {
+ GetScaledRow(ImIn, x1, y1 + yi, ix, ox,
+ tempRed, tempGreen, tempBlue);
+ PutRGBScan(ImOut, x2, y2 + yi, ox, div,
+ tempRed, tempGreen, tempBlue);
+ }
+ }
+ else if (iy < oy)
+ {
+ /* scaling by subsampling (grow): */
+ iy--;
+ oy--;
+ div *= oy;
+ /* get first row: */
+ GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
+ /* si and sifrac give the subsampling position: */
+ si = y1;
+ sifrac = 0;
+ /* getNextRow tells us, that we need the next row */
+ getNextRow = TRUE;
+ for (yi = 0; yi <= oy; yi++)
+ {
+ if (getNextRow)
+ {
+ for (xi = 0; xi < ox; xi++)
+ {
+ prevRed[xi] = nextRed[xi];
+ prevGreen[xi] = nextGreen[xi];
+ prevBlue[xi] = nextBlue[xi];
+ }
+ if (yi < oy)
+ {
+ /* only get next row if in same icon */
+ GetScaledRow(ImIn, x1, si + 1, ix, ox,
+ nextRed, nextGreen, nextBlue);
+ }
+ }
+
+ /* calculate subsampled color values: */
+ /* division by oy occurs in PutRGBScan */
+ for (xi = 0; xi < ox; xi++)
+ {
+ tempRed[xi] = (prevRed[xi] * (oy - sifrac) +
+ nextRed[xi] * sifrac);
+ tempGreen[xi] = (prevGreen[xi] * (oy - sifrac) +
+ nextGreen[xi] * sifrac);
+ tempBlue[xi] = (prevBlue[xi] * (oy - sifrac) +
+ nextBlue[xi] * sifrac);
+ }
+
+ /* write row to output image: */
+ PutRGBScan(ImOut, x2, y2 + yi, ox, div,
+ tempRed, tempGreen, tempBlue);
+
+ /* advance sampling position: */
+ sifrac += iy;
+ if (sifrac >= oy)
+ {
+ si++;
+ sifrac -= oy;
+ getNextRow = TRUE;
+ }
+ else
+ {
+ getNextRow = FALSE;
+ }
+
+ }
+ }
+ else
+ {
+ /* scaling by averaging (shrink) */
+ div *= iy;
+ /* height of a output row in input rows: */
+ addWhole = iy / oy;
+ addFrac = iy % oy;
+ /* start position of the first output row: */
+ si = y1;
+ sifrac = 0;
+ /* get first input row: */
+ GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
+ for (yi = 0; yi < oy; yi++)
+ {
+ /* find endpoint of the current output row: */
+ ci = si + addWhole;
+ cifrac = sifrac + addFrac;
+ if (cifrac >= oy)
+ {
+ ci++;
+ cifrac -= oy;
+ }
+ /* take fraction of current input row (starting segment): */
+ for (xi = 0; xi < ox; xi++)
+ {
+ tempRed[xi] = nextRed[xi] * (oy - sifrac);
+ tempGreen[xi] = nextGreen[xi] * (oy - sifrac);
+ tempBlue[xi] = nextBlue[xi] * (oy - sifrac);
+ }
+ si++;
+ /* add values for whole pixels: */
+ while (si < ci)
+ {
+ GetScaledRow(ImIn, x1, si, ix, ox,
+ nextRed, nextGreen, nextBlue);
+ for (xi = 0; xi < ox; xi++)
+ {
+ tempRed[xi] += nextRed[xi] * oy;
+ tempGreen[xi] += nextGreen[xi] * oy;
+ tempBlue[xi] += nextBlue[xi] * oy;
+ }
+ si++;
+ }
+ /* add fraction of current input row (ending segment): */
+ if (yi < oy - 1)
+ {
+ /* only get next row if still in icon: */
+ GetScaledRow(ImIn, x1, si, ix, ox,
+ nextRed, nextGreen, nextBlue);
+ }
+ sifrac = cifrac;
+ for (xi = 0; xi < ox; xi++)
+ {
+ tempRed[xi] += nextRed[xi] * sifrac;
+ tempGreen[xi] += nextGreen[xi] * sifrac;
+ tempBlue[xi] += nextBlue[xi] * sifrac;
+ }
+ /* write row to output image: */
+ PutRGBScan(ImOut, x2, y2 + yi, ox, div,
+ tempRed, tempGreen, tempBlue);
+ }
+ }
+}
+
+
+
+static XImage *ResizeImageSmooth(Display *dpy, XImage *Im,
+ int ix, int iy, int ox, int oy)
+{
+ Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
+
+ int width1, height1, width2, height2;
+ int x1, x2, y1, y2;
+
+ XImage *Tmp;
+
+ char *Data;
+
+ width1 = Im->width;
+ height1 = Im->height;
+
+ width2 = ox * width1 / ix;
+ height2 = oy * height1 / iy;
+
+ Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
+
+ Tmp = XCreateImage(dpy, visual,
+ Im->depth, ZPixmap, 0, Data, width2, height2,
+ 32, 0);
+
+ /* compute values for decomposing pixel into color values: */
+ redMask = Im->red_mask;
+ redShift = 0;
+ while ((redMask & 1) == 0)
+ {
+ redShift++;
+ redMask >>= 1;
+ }
+ greenMask = Im->green_mask;
+ greenShift = 0;
+ while ((greenMask & 1) == 0)
+ {
+ greenShift++;
+ greenMask >>= 1;
+ }
+ blueMask = Im->blue_mask;
+ blueShift = 0;
+ while ((blueMask & 1) == 0)
+ {
+ blueShift++;
+ blueMask >>= 1;
+ }
+
+ /* scale each icon: */
+ for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); y1 += iy, y2 += oy)
+ {
+ for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); x1 += ix, x2 += ox)
+ {
+ ScaleIcon(Im, Tmp, x1, y1, x2, y2,
+ ix, iy, ox, oy);
+ }
+ }
+
+ return Tmp;
+}
+
+/*
+ * Resize an image. XXX XXX XXX
+ *
+ * Also appears in "main-xaw.c".
+ */
+static XImage *ResizeImage(Display *dpy, XImage *Im,
+ int ix, int iy, int ox, int oy)
+{
+ Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
+
+ int width1, height1, width2, height2;
+ int x1, x2, y1, y2, Tx, Ty;
+ int *px1, *px2, *dx1, *dx2;
+ int *py1, *py2, *dy1, *dy2;
+
+ XImage *Tmp;
+
+ char *Data;
+
+ if (smoothRescaling && (ix != ox || iy != oy) &&
+ visual->class == TrueColor)
+ {
+ return ResizeImageSmooth(dpy, Im, ix, iy, ox, oy);
+ }
+
+ width1 = Im->width;
+ height1 = Im->height;
+
+ width2 = ox * width1 / ix;
+ height2 = oy * height1 / iy;
+
+ Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
+
+ Tmp = XCreateImage(dpy, visual,
+ Im->depth, ZPixmap, 0, Data, width2, height2,
+ 32, 0);
+
+ if (ix > ox)
+ {
+ px1 = &x1;
+ px2 = &x2;
+ dx1 = &ix;
+ dx2 = &ox;
+ }
+ else
+ {
+ px1 = &x2;
+ px2 = &x1;
+ dx1 = &ox;
+ dx2 = &ix;
+ }
+
+ if (iy > oy)
+ {
+ py1 = &y1;
+ py2 = &y2;
+ dy1 = &iy;
+ dy2 = &oy;
+ }
+ else
+ {
+ py1 = &y2;
+ py2 = &y1;
+ dy1 = &oy;
+ dy2 = &iy;
+ }
+
+ Ty = *dy1 / 2;
+
+ for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); )
+ {
+ Tx = *dx1 / 2;
+
+ for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); )
+ {
+ XPutPixel(Tmp, x2, y2, XGetPixel(Im, x1, y1));
+
+ (*px1)++;
+
+ Tx -= *dx2;
+ if (Tx < 0)
+ {
+ Tx += *dx1;
+ (*px2)++;
+ }
+ }
+
+ (*py1)++;
+
+ Ty -= *dy2;
+ if (Ty < 0)
+ {
+ Ty += *dy1;
+ (*py2)++;
+ }
+ }
+
+ return Tmp;
+}
+
+#endif /* USE_GRAPHICS */
+
+#endif /* USE_X11 || USE_XAW */
diff --git a/src/main-crb.c b/src/main-crb.c
new file mode 100644
index 00000000..a4a1a742
--- /dev/null
+++ b/src/main-crb.c
@@ -0,0 +1,6402 @@
+/* File: main-crb.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison, Keith Randall, Peter Ammon, Ron Anderson
+ * and others
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+
+/*
+ * This file helps Angband work with Macintosh computers running OS X,
+ * or OS 8/9 with CarbonLib system extention.
+ *
+ * To use this file, use an appropriate "Makefile" or "Project File", which
+ * should define "MACINTOSH".
+ *
+ * The official compilation uses the CodeWarrior Pro compiler.
+ *
+ * If you are never going to use "graphics" (especially if you are not
+ * compiling support for graphics anyway) then you can delete the "pict"
+ * resources with id "1001", "1002", "1003" and "1004" with no dangerous
+ * side effects.
+ *
+ *
+ * This file assumes that you will be using a PPC Mac running OS X
+ * or OS 8/9 (8.6 or greater) with CarbonLib system extention enabled.
+ * In fact, the game will refuse to run unless these features are available.
+ *
+ * MACH_O_CARBON code pushes the system requirement a bit further, and
+ * I don't think it works on System 8, even with CarbonLib, because it uses
+ * the Bundle services, but I may be wrong.
+ *
+ * Note that the "preference" file is now a simple XML text file
+ * called "<program name>.plist" in case of PEF Carbon, and "<Java-style
+ * program id defined in Info.plist>.plist" for Mach-O Carbon, which contains
+ * key-value paris, so it no longer has to check version stamp to validate
+ * its contents.
+ *
+ *
+ * Note that "init1.c", "init2.c", "load1.c", "load2.c", and "birth.c"
+ * should probably be "unloaded" as soon as they are no longer needed,
+ * to save space, but I do not know how to do this. XXX XXX XXX
+ *
+ * Stange bug -- The first "ClipRect()" call crashes if the user closes
+ * all the windows, switches to another application, switches back, and
+ * re-opens the main window, for example, using "command-a". XXX XXX XXX
+ *
+ *
+ * Initial framework (and most code) by Ben Harrison (benh@phial.com).
+ *
+ * Some code adapted from "MacAngband 2.6.1" by Keith Randall
+ *
+ * Initial PowerMac port by Maarten Hazewinkel (mmhazewi@cs.ruu.nl).
+ *
+ * Most Apple Event code provided by Steve Linberg (slinberg@crocker.com).
+ *
+ * Most of the graphics code is adapted from an extremely minimal subset of
+ * the "Sprite World II" package, an amazing (and free) animation package.
+ *
+ * Carbon code adapted from works by Peter Ammon and Ron Anderson.
+ *
+ * (List of changes made by "pelpel" follow)
+ * Some API calls are updated to OS 8.x-- ones.
+ *
+ * Pixmap locking code in Term_pict_map() follows Carbon Porting Guide
+ * by Apple.
+ *
+ * The idle loop in TERM_XTRA_DELAY is rewritten to sleep on WaitNextEvent
+ * for a couple of reasons.
+ *
+ * CheckEvent now really blocks whenever asked to wait.
+ *
+ * The unused buffer GWorld is completely removed. It has long been pure waste
+ * of memory.
+ *
+ * The default font-size combination was changed because the old one, Monaco
+ * at 12 points causes the redraw artefact problem on OS X.
+ *
+ * Characters in the ASCII mode are clipped by their bounding rects to reduce
+ * redraw artefacts that were quite annoying in certain font-point combos.
+ *
+ * Transparency effect now avoids double bitblts whenever possible.
+ *
+ * Old tiles were drawn in a wrong fashion by the USE_TRANSPARENCY code.
+ *
+ * ASCII and the two graphics modes are now controlled by single graf_mode
+ * variable. arg_* and use_* variables are set when requested mode is
+ * successfully initialised.
+ *
+ * Most of the menus are now loaded from resources.
+ *
+ * Moved TileWidth and TileHeight menus into Special. There were too many menus.
+ *
+ * Added support for 32x32 tiles, now for [V] only.
+ *
+ * Related to the above, globe_init no longer loads tile images twice if
+ * a tileset doesn't have corresponding masks.
+ *
+ * Added support for POSIX-style pathnames, for Mach-O Carbon (gcc, CW >= 7).
+ * We can finally live without Pascal strings to handle files this way.
+ *
+ * (Mach-O Carbon) Graphics tiles are moved out of the resource fork into
+ * bundle-based data fork files.
+ *
+ * Changed size-related menu code, because they no longer function because
+ * some APIs have been changed to return Unicode in some cases.
+ *
+ * Changed the transparency code again, this time using Ron Anderson's code,
+ * which makes more sound assumption about background colour and is more
+ * efficient.
+ *
+ * The old asynchronous sound player could try to lock the same handle more
+ * than once, load same sound resource already in use, or unlock and release
+ * currently playing sound.
+ *
+ * hook_quit() now releases memory-related resources dynamically allocated by
+ * the graphics and sound code.
+ *
+ * Important Resources in the resource file:
+ *
+ * FREF 130 = ANGBAND_CREATOR / 'APPL' (application)
+ * FREF 129 = ANGBAND_CREATOR / 'SAVE' (save file)
+ * FREF 130 = ANGBAND_CREATOR / 'TEXT' (generic text file)
+ * FREF 131 = ANGBAND_CREATOR / 'DATA' (binary image file, score file)
+ *
+ * DLOG 128 = "About Angband..."
+ *
+ * ALRT 128 = unused (?)
+ * ALRT 129 = "Warning..."
+ *
+ * DITL 128 = body for DLOG 128
+ * DITL 129 = body for ALRT 129
+ * DITL 130 = body for ALRT 130
+ *
+ * ICON 128 = "warning" icon
+ *
+ * MBAR 128 = array of MENU id's (128, 129, 130, 131, 132, 133, 134)
+ * MENU 128 = apple (about, -, ...)
+ * MENU 129 = File (new, open, close, save, -, score, quit)
+ * (If SAVEFILE_SCREEN is defined)
+ * MENU 129 = File (close, save, -, score, quit)
+ * MENU 130 = Edit (undo, -, cut, copy, paste, clear)
+ * MENU 131 = Font (bold, wide, -)
+ * MENU 132 = Size ()
+ * MENU 133 = Windows ()
+ * MENU 134 = Special (Sound, Graphics, TileWidth, TileHeight, -, Fiddle,
+ * Wizard)
+ * Graphics have following submenu attached:
+ * MENU 144 = Graphics (None, 8x8, 16x16, 32x32, enlarge tiles)
+ * TileWidth and TileHeight submenus are filled in by this program.
+ * MENU 145 = TileWidth ()
+ * MENU 146 = TileHeight ()
+ *
+ * On CFM(PEF) Carbon only:
+ * PICT 1001 = Graphics tile set (8x8)
+ * PICT 1002 = Graphics tile set (16x16 images)
+ * PICT 1004 = Graphics tile set (32x32)
+ *
+ * Mach-O Carbon now uses data fork resources:
+ * 8x8.png = Graphics tile set (8x8)
+ * 16x16.png = Graphics tile set (16x16 images)
+ * 32x32.png = Graphics tile set (32x32)
+ * These files should go into the Resources subdirectory of an application
+ * bundle.
+ *
+ * STR# 128 = "Please select the "lib" folder"
+ *
+ * plst 0 can be empty, but required for single binary Carbon apps on OS X
+ * Isn't necessary for Mach-O Carbon.
+ *
+ *
+ * File name patterns:
+ * all 'APEX' files have a filename of the form "*:apex:*" (?)
+ * all 'DATA' files have a filename of the form "*:data:*"
+ * all 'SAVE' files have a filename of the form "*:save:*"
+ * all 'USER' files have a filename of the form "*:user:*" (?)
+ *
+ * Perhaps we should attempt to set the "_ftype" flag inside this file,
+ * to avoid nasty file type information being spread all through the
+ * rest of the code. (?) This might require adding hooks into the
+ * "fd_open()" and "my_fopen()" functions in "util.c". XXX XXX XXX
+ *
+ *
+ * Reasons for each header file:
+ *
+ * angband.h = Angband header file
+ *
+ * Types.h = (included anyway)
+ * Gestalt.h = gestalt code
+ * QuickDraw.h = (included anyway)
+ * OSUtils.h = (included anyway)
+ * Files.h = file code
+ * Fonts.h = font code
+ * Menus.h = menu code
+ * Dialogs.h = dialog code
+ * Windows.h = (included anyway)
+ * Palettes.h = palette code
+ * ToolUtils.h = HiWord() / LoWord()
+ * Events.h = event code
+ * Resources.h = resource code
+ * Controls.h = button code
+ * SegLoad.h = ExitToShell(), AppFile, etc
+ * Memory.h = NewPtr(), etc
+ * QDOffscreen.h = GWorld code
+ * Sound.h = Sound code
+ * Navigation.h = save file / lib locating dialogues
+ * CFPreferences.h = Preferences
+ * CFNumber.h = read/write short values from/to preferences
+ */
+
+/*
+ * Yet another main-xxx.c for Carbon (pelpel) - revision 11d
+ *
+ * Since I'm using CodeWarrior, the traditional header files are
+ * #include'd below.
+ *
+ * I also compiled Angband 3.0.2 successfully with OS X's gcc.
+ * Please follow these instructions if you are interested.
+ *
+ * ---(developer CD gcc + makefile porting notes, for Angband 3.0.2)-------
+ * 1. Compiling the binary
+ *
+ * If you try this on OS X + gcc, please use makefile.std, replacing
+ * main.c and main.o with main-crb.c and main-crb.o, removing all main-xxx.c
+ * and main-xxx.o from SRCS and OBJS, and, and use these settings:
+ *
+ * COPTS = -Wall -O1 -g -fpascal-strings
+ * INCLUDES =
+ * DEFINES = -DMACH_O_CARBON -DANGBAND30X
+ * LIBS = -framework CoreFoundation -framework QuickTime -framework Carbon
+ *
+ * -DANGBAND30X only affects main-crb.c. This is because I'm also compiling
+ * a couple of variants, and this arrangement makes my life easier.
+ *
+ * Never, ever #define MACINTOSH. It'll wreck havoc in system interface
+ * (mostly because of totally different pathname convention).
+ *
+ * You might wish to disable some SET_UID features for various reasons:
+ * to have user folder within the lib folder, savefile names etc.
+ *
+ * For the best compatibility with the Classic ports and my PEF Carbon
+ * ports, my_fopen, fd_make and fd_open [in util.c] should call
+ * (void)fsetfileinfo(buf, _fcreator, _ftype);
+ * when a file is successfully opened. Or you'll see odd icons for some files
+ * in the lib folder. In order to do so, extern.h should contain these lines,
+ * within #ifdef MACH_O_CARBON:
+ * extern int fsetfileinfo(char *path, u32b fcreator, u32b ftype);
+ * extern u32b _fcreator;
+ * extern u32b _ftype;
+ * And enable the four FILE_TYPE macros in h-config.h for defined(MACH_O_CARBON)
+ * in addition to defined(MACINTOSH) && !defined(applec), i.e.
+ * #if defined(MACINTOSH) && !defined(applec) || defined(MACH_O_CARBON)
+ *
+ * This is a very good way to spot bugs in use of these macros, btw.
+ *
+ * 2. Installation
+ *
+ * The "angband" binary must be arranged this way for it to work:
+ *
+ * lib/ <- the lib folder
+ * Angband (OS X).app/
+ * Contents/
+ * MacOS/
+ * angband <- the binary you've just compiled
+ * Info.plist <- to be explained below
+ * Resources/
+ * Angband.icns
+ * Data.icns
+ * Edit.icns
+ * Save.icns
+ * 8x8.png <- 8x8 tiles
+ * 16x16.png <- 16x16 tiles
+ * angband.rsrc <- see below
+ *
+ * 3. Preparing Info.plist
+ *
+ * Info.plist is an XML file describing some attributes of an application,
+ * and this is appropriate for Angband:
+ *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <plist version="1.0">
+ * <dict>
+ * <key>CFBundleName</key><string>Angband</string>
+ * <key>CFBundleDisplayName</key><string>Angband (OS X)</string>
+ * <key>CFBundleExecutable</key><string>angband</string>
+ * <key>CFBundlePackageType</key><string>APPL</string>
+ * <key>CFBundleSignature</key><string>A271</string>
+ * <key>CFBundleVersion</key><string>3.0.2</string>
+ * <key>CFBundleShortVersionString</key><string>3.0.2</string>
+ * <key>CFBundleIconFile</key><string>Angband</string>
+ * <key>CFBundleIdentifier</key><string>net.thangorodrim.Angband</string>
+ * <key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
+ * <key>CFBundleDocumentTypes</key>
+ * <array>
+ * <dict>
+ * <key>CFBundleTypeExtentions</key><array><string>*</string></array>
+ * <key>CFBundleTypeIconFile</key><string>Save</string>
+ * <key>CFBundleTypeName</key><string>Angband saved game</string>
+ * <key>CFBundleTypeOSTypes</key><array><string>SAVE</string></array>
+ * <key>CFBundleTypeRole</key><string>Editor</string>
+ * </dict>
+ * <dict>
+ * <key>CFBundleTypeExtentions</key><array><string>*</string></array>
+ * <key>CFBundleTypeIconFile</key><string>Edit</string>
+ * <key>CFBundleTypeName</key><string>Angband game data</string>
+ * <key>CFBundleTypeOSTypes</key><array><string>TEXT</string></array>
+ * <key>CFBundleTypeRole</key><string>Editor</string>
+ * </dict>
+ * <dict>
+ * <key>CFBundleTypeExtentions</key><array><string>raw</string></array>
+ * <key>CFBundleTypeIconFile</key><string>Data</string>
+ * <key>CFBundleTypeName</key><string>Angband game data</string>
+ * <key>CFBundleTypeOSTypes</key><array><string>DATA</string></array>
+ * <key>CFBundleTypeRole</key><string>Editor</string>
+ * </dict>
+ * </array>
+ * </dict>
+ * </plist>
+ *
+ * 4. Menu, diaglogue and gfx resources
+ *
+ * The binary assumes angband.rsrc should be in the traditional resource
+ * mangager format. Please run this command to create it from its textual
+ * description:
+ *
+ * Rez -i /Developer/Headers/FlatCarbon -d MACH_O -o angband.rsrc Angband.r
+ *
+ * The command is in /Developer/Tools. You might wish to include it in your
+ * PATH.
+ *
+ * It's better to comment out the definitions of BNDL and plst resources
+ * before you do that. I think you can DeRez the resulting tome.rsrc and
+ * feed it to the Interface Builder to produce a set of compatible .nib files,
+ * but this file also needs to be updated to understand .nib... On the other
+ * hand, I really don't like to hardcode UI definitions in C.
+ *
+ * Graphics resources are moved out of the resource fork and become ordinary
+ * PNG files. Make sure to set its resolution to 72 dpi (<- VERY important)
+ * while keeping vertical and horizontal scaling factor to 100% (<- VERY
+ * important), when you convert tiles in any formats to PNG. This means
+ * that the real size of an image must shrink or grow when you change it's dpi.
+ *
+ * Sound resources are a bit more complicated.
+ * The easiest way is:
+ * 1) Grab recent Mac Angband binary.
+ * 2) Run this command:
+ * DeRez -only 'snd ' (Angband binary) > sound.r
+ * 3) And specify sound.r files in addition to Angband.r when you run Rez.
+ *
+ * ---(end of OS X + gcc porting note)--------------------------------------
+ *
+ * Code adapted from Peter Ammon's work on 2.8.3 and some modifications
+ * are made when Apple's Carbon Porting Guide says they are absolutely
+ * necessary. Other arbirary changes are mostly because of my hatred
+ * of deep nestings and indentations. The code for controlling graphics modes
+ * have been thoroughly revised simply because I didn't like it (^ ^;).
+ * A bonus of this is that graphics settings can be loaded from Preferences
+ * quite easily.
+ *
+ * I also took Ron Anderson's (minimising the use of local-global coordinate
+ * conversions). Some might say his QuickTime multimedia is the most
+ * significant achievement... Play your favourite CD instead, if you really
+ * miss that (^ ^;) I might consider incorporating it if it makes use of
+ * event notification.
+ *
+ * I replaced some old API calls with new (OS 8.x--) ones, especially
+ * when I felt Apple is strongly against their continued usage.
+ *
+ * Similarly, USE_SFL_CODE should be always active, so I removed ifdef's
+ * just to prevent accidents, as well as to make the code a bit cleaner.
+ *
+ * On the contrary, I deliberately left traditional resource interfaces.
+ * Whatever Apple might say, I abhor file name extentions. And keeping two
+ * different sets of resources for Classic and Carbon is just too much for
+ * a personal project XXX
+ *
+ * Because Carbon forbids the use of 68K code, ANGBAND_LITE_MAC sections
+ * are removed.
+ *
+ * Because the default font-size combination causes redraw artefact problem
+ * (some characters, even in monospace fonts, have negative left bearings),
+ * I introduced rather crude hack to clip all character drawings within
+ * their bounding rects. If you don't like this, please comment out the line
+ * #define CLIP_HACK
+ * below.
+ *
+ * The check for return values of AEProcessAppleEvent is removed,
+ * because it results in annoying dialogues on OS X, also because
+ * Apple says it isn't usually necessary.
+ *
+ * Because the always_pict code is *so* slow, I changed the graphics
+ * mode selection a bit to use higher_pict when a user chooses a fixed
+ * width font and doesn't changes tile width / height.
+ *
+ * Added support for David Gervais' 32x32 tiles.
+ *
+ * Replaced transparency effect code by Ron Anderson's.
+ *
+ * Added support for gcc & make compilation. They come free with OS X
+ * (on the developer CD). This means that it can be compiled as a bundle.
+ *
+ * For Mach-O Carbon binary, moved graphics tiles out of the
+ * resource fork and made them plain PNG files, to be stored in the application
+ * bundle's "Resources" subdirectory.
+ *
+ * For Mach-O Carbon binary, provided a compile-time option (USE_QT_SOUND) to
+ * move sound effect samples out of the resource fork and use *.wav files in
+ * the bundle's "Resources" subdirectory. The "*" part must match the names in
+ * angband_sound_name (variable.c) exactly. This doesn't hurt performance
+ * a lot in [V] (it's got ~25 sound events), but problematic in [Z]-based
+ * ones (they have somewhere around 70 sound events).
+ *
+ * You still can use the resource file that comes with the ext-mac archive
+ * on the Angband FTP server, with these additions:
+ * - MENUs 131--134 and 144--146, as described above
+ * - MBAR 128: just a array of 128 through 134
+ * - plst 0 : can be empty, although Apple recommends us to fill it in.
+ * - STR# 128 : something like "Please select your lib folder"
+ *
+ * Since this involves considerable amount of work, I attached
+ * a plain text resource definition (= Rez format) .
+ * I heavily commented on the file, hoping it could be easily adapted
+ * to future versions of Angband as well as variants.
+ * I omitted sound effects and graphic tiles to make it reasonably small.
+ * Please copy them from any recent Mac binaries - you can use, say ZAngband
+ * ones for Vanilla or [V]-based variants quite safely. T.o.M.E. uses fairly
+ * extended 16x16 tileset and it is maintained actively. IIRC Thangorodrim
+ * compile page has an intruction explaining how to convert tiles for
+ * use on the Mac... It can be tricky, depending on your choice of
+ * graphics utility. Remember setting resolution to 72 pixels per inch,
+ * while keeping vertical/horizontal scale factor to 100% and dump the
+ * result as a PICT from resource.
+ *
+ * To build Carbonised Angband with CodeWarrior, copy your PPC project
+ * and
+ * - replace main-mac.c in the project with this file (in the link order tab)
+ * - remove InterfaceLib and MathLib
+ * - add CarbonLib (found in Carbon SDK or CW's UniversalInterfaces) --
+ * if you have compiler/linker errors, you'll need Carbon SDK 1.1 or greater
+ * - replace MSL C.PPC.Lib with MSL C.Carbon.Lib (both found in
+ * MSL:MSL_C:MSL_MacOS:Lib:PPC)
+ * - leave MSL RuntimePPC.Lib as it is
+ * - don't forget to update resource file, as described above
+ * - as in Classic targets, you may have to include <unistd.h> and
+ * <fcntl.h>. The most convinient place for them is the first
+ * #ifdef MACINTOSH in h-system.h
+ * - check variant dependent ifdef's explained below, and add
+ * appropriate one(s) in your A-mac-h.pch.
+ */
+
+
+/*
+ * Force Carbon-compatible APIs
+ */
+#ifndef MACH_O_CARBON
+
+/* Can be CodeWarrior or MPW */
+# define TARGET_API_MAC_CARBON 1
+
+#else
+
+/*
+* Must be Mach-O Carbon target with OS X gcc.
+* No need to set TARGET_API_MAC_CARBON to 1 here, but I assume it should
+* be able to make efficient use of BSD functions, hence:
+*/
+# define USE_MALLOC
+/* Not yet */
+/* # define USE_NIB */
+
+#endif /* !MACH_O_CARBON */
+
+
+#include "angband.h"
+
+#if defined(MACINTOSH) || defined(MACH_O_CARBON)
+
+/*
+ * Check and create if needed the directory dirpath
+ */
+bool_ private_check_user_directory(cptr dirpath)
+{
+ /* Is this used anywhere else in *bands? */
+ struct stat stat_buf;
+
+ int ret;
+
+ /* See if it already exists */
+ ret = stat(dirpath, &stat_buf);
+
+ /* It does */
+ if (ret == 0)
+ {
+ /* Now we see if it's a directory */
+ if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) return (TRUE);
+
+ /*
+ * Something prevents us from create a directory with
+ * the same pathname
+ */
+ return (FALSE);
+ }
+
+ /* No - this maybe the first time. Try to create a directory */
+ else
+ {
+ /* Create the ~/.ToME directory */
+ ret = mkdir(dirpath, 0700);
+
+ /* An error occured */
+ if (ret == -1) return (FALSE);
+
+ /* Success */
+ return (TRUE);
+ }
+}
+
+/*
+ * Check existence of ".ToME/" directory in the user's
+ * home directory or try to create it if it doesn't exist.
+ * Returns FALSE if all the attempts fail.
+ */
+static bool_ check_create_user_dir(void)
+{
+ char dirpath[1024];
+ char versionpath[1024];
+ char savepath[1024];
+#ifdef PRIVATE_USER_PATH_DATA
+ char datapath[1024];
+#endif
+#ifdef PRIVATE_USER_PATH_APEX
+ char apexpath[1024];
+#endif
+
+ /* Get an absolute path from the filename */
+ path_parse(dirpath, 1024, PRIVATE_USER_PATH);
+ strcpy(versionpath, dirpath);
+ strcat(versionpath, USER_PATH_VERSION);
+ strcpy(savepath, versionpath);
+ strcat(savepath, "/save");
+#ifdef PRIVATE_USER_PATH_DATA
+ strcpy(datapath, versionpath);
+ strcat(datapath, "/data");
+#endif
+#ifdef PRIVATE_USER_PATH_APEX
+ strcpy(apexpath, versionpath);
+ strcat(apexpath, "/apex");
+#endif
+
+ return /* don't forget, the dirpath muts come first */
+ private_check_user_directory(dirpath) &&
+ private_check_user_directory(versionpath) &&
+#ifdef PRIVATE_USER_PATH_DATA
+ private_check_user_directory(datapath) &&
+#endif
+#ifdef PRIVATE_USER_PATH_APEX
+ private_check_user_directory(apexpath) &&
+#endif
+ private_check_user_directory(savepath);
+}
+
+
+/*
+ * Variant-dependent features:
+ *
+ * #define ALLOW_BIG_SCREEN (V, Ey, O, T.o.M.E., and Z. Dr's big screen needs
+ * more work. New S one is too idiosyncratic...)
+ * #define ANG281_RESET_VISUALS (Cth, Gum, T.o.M.E., Z)
+ * #define SAVEFILE_SCREEN (T.o.M.E.)
+ * #define ZANG_AUTO_SAVE (O and Z)
+ * #define HAS_SCORE_MENU (V and T.o.M.E.)
+ * #define ANGBAND_CREATOR four letter code for your variant, if any.
+ * or use the default one.
+ *
+ * For [Z], you also have to say -- #define inkey_flag (p_ptr->inkey_flag)
+ * but before that, please, please consider using main-mac-carbon.c in [Z],
+ * that has some interesting features.
+ */
+
+/* Some porting examples */
+#ifdef ANGBAND30X
+# define USE_DOUBLE_TILES
+# define ALLOW_BIG_SCREEN
+# define HAS_SCORE_MENU
+# define NEW_ZVIRT_HOOKS
+#endif /* ANGBAND30X */
+
+# define USE_DOUBLE_TILES
+# define SAVEFILE_SCREEN
+# define ANG281_RESET_VISUALS
+# define ALLOW_BIG_SCREEN
+# define HAS_SCORE_MENU
+# define ANGBAND_CREATOR 'PrnA'
+
+/* Default creator signature */
+#ifndef ANGBAND_CREATOR
+# define ANGBAND_CREATOR 'A271'
+#endif
+
+
+/*
+ * Use rewritten asynchronous sound player
+ */
+#define USE_ASYNC_SOUND
+
+
+/*
+ * A rather crude fix to reduce amount of redraw artefacts.
+ * Some fixed width fonts (i.e. Monaco) has characters with negative
+ * left bearings, so Term_wipe_mac or overwriting cannot completely
+ * erase them. This could be introduced to Classic Mac OS ports too,
+ * but since I've never heard any complaints and I don't like to
+ * make 68K ports even slower, I won't do so there.
+ */
+#define CLIP_HACK /* */
+
+/*
+ * To cope with pref file related problems. It no longer has to be acculate,
+ * because preferences are stored in plist.
+ */
+#define PREF_VER_MAJOR VERSION_MAJOR
+#define PREF_VER_MINOR VERSION_MINOR
+#define PREF_VER_PATCH VERSION_PATCH
+#define PREF_VER_EXTRA VERSION_EXTRA
+
+
+/*
+ * In OS X + gcc, use <Carbon/Carbon.h>, <CoreServices/CoreServices.h> and
+ * <CoreFoundation/CoreFoundation.h> for ALL of these, including the Apple
+ * Event ones. <QuickTime/QuickTime.h> is used by the tile loading code.
+ */
+#ifdef MACH_O_CARBON
+
+#include <Carbon/Carbon.h>
+#include <QuickTime/QuickTime.h>
+#include <CoreServices/CoreServices.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#else /* MACH_O_CARBON */
+
+#include <Types.h>
+#include <Gestalt.h>
+#include <QuickDraw.h>
+#include <Files.h>
+#include <Fonts.h>
+#include <Menus.h>
+#include <Dialogs.h>
+#include <Windows.h>
+#include <Palettes.h>
+#include <ToolUtils.h>
+#include <Events.h>
+#include <SegLoad.h>
+#include <Resources.h>
+#include <Controls.h>
+#include <Memory.h>
+#include <QDOffscreen.h>
+#include <Sound.h>
+#include <Navigation.h>
+#include <CFPreferences.h>
+#include <CFNumber.h>
+#include <AppleEvents.h>
+#include <EPPC.h>
+#include <Folders.h>
+
+#endif /* MACH_O_CARBON */
+
+/* MacOSX == Unix == Good */
+#ifdef USE_MACOSX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#endif
+
+
+/*
+ * Use "malloc()" instead of "NewPtr()"
+ */
+/* #define USE_MALLOC */
+
+
+/*
+ * Information about each of the 256 available colors
+ */
+static RGBColor color_info[256];
+
+
+#ifdef MACH_O_CARBON
+
+/*
+ * Creator signature and file type - Didn't I say that I abhor file name
+ * extentions? Names and metadata are entirely different set of notions.
+ */
+OSType _fcreator;
+OSType _ftype;
+
+#endif /* MACH_O_CARBON */
+
+
+/*
+ * Forward declare
+ */
+typedef struct term_data term_data;
+
+/*
+ * Extra "term" data
+ */
+struct term_data
+{
+ term *t;
+
+ Rect r;
+
+ WindowPtr w;
+
+
+ short padding;
+
+ short pixelDepth;
+
+ GWorldPtr theGWorld; /* not used ... */
+
+ GDHandle theGDH;
+
+ GDHandle mainSWGDH; /* not used ... */
+
+ Str15 title;
+
+ s16b oops;
+
+ s16b keys;
+
+ s16b last;
+
+ s16b mapped;
+
+ s16b rows;
+ s16b cols;
+
+ s16b font_id;
+ s16b font_size;
+ s16b font_face;
+ s16b font_mono;
+
+ s16b font_o_x;
+ s16b font_o_y;
+ s16b font_wid;
+ s16b font_hgt;
+
+ s16b tile_o_x;
+ s16b tile_o_y;
+ s16b tile_wid;
+ s16b tile_hgt;
+
+ s16b size_wid;
+ s16b size_hgt;
+
+ s16b size_ow1;
+ s16b size_oh1;
+ s16b size_ow2;
+ s16b size_oh2;
+};
+
+
+
+
+/*
+ * Forward declare -- see below
+ */
+static bool_ CheckEvents(bool_ wait);
+
+
+#ifndef MACH_O_CARBON
+
+/*
+ * Hack -- location of the main directory
+ */
+static short app_vol;
+static long app_dir;
+
+#endif /* !MACH_O_CARBON */
+
+
+/*
+ * Delay handling of double-clicked savefiles
+ */
+Boolean open_when_ready = FALSE;
+
+/*
+ * Delay handling of pre-emptive "quit" event
+ */
+Boolean quit_when_ready = FALSE;
+
+
+/*
+ * Aqua automatically supplies the Quit menu.
+ */
+static Boolean is_aqua = FALSE;
+
+/*
+ * Version of Mac OS - for version specific bug workarounds (; ;)
+ */
+static long mac_os_version;
+
+
+/*
+ * Hack -- game in progress
+ */
+static int game_in_progress = 0;
+
+
+/*
+ * Only do "SetPort()" when needed
+ */
+static WindowPtr active = NULL;
+
+
+/*
+ * Maximum number of terms
+ */
+#define MAX_TERM_DATA 8
+
+
+/*
+ * An array of term_data's
+ */
+static term_data data[MAX_TERM_DATA];
+
+
+/*
+ * Note when "open"/"new" become valid
+ */
+static bool_ initialized = FALSE;
+
+
+
+/*
+ * Convert a C string to a pascal string in place
+ *
+ * This function may be defined elsewhere, but since it is so
+ * small, it is not worth finding the proper function name for
+ * all the different platforms.
+ */
+static void ctopstr(StringPtr src)
+{
+ int i;
+ byte len;
+
+ /* Hack -- pointer */
+ char *s = (char*)(src);
+
+ len = strlen(s);
+
+ /* Hack -- convert the string */
+ for (i = len; i > 1; i--) s[i] = s[i - 1];
+
+ /* Hack -- terminate the string */
+ s[0] = len;
+}
+
+
+#ifdef MACH_O_CARBON
+
+/* Carbon File Manager utilities by pelpel */
+
+/*
+ * (Carbon)
+ * Convert a pathname to a corresponding FSSpec.
+ * Returns noErr on success.
+ */
+static OSErr path_to_spec(const char *path, FSSpec *spec)
+{
+ OSErr err;
+ FSRef ref;
+
+ /* Convert pathname to FSRef ... */
+ err = FSPathMakeRef(path, &ref, NULL);
+ if (err != noErr) return (err);
+
+ /* ... then FSRef to FSSpec */
+ err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+
+ /* Inform caller of success or failure */
+ return (err);
+}
+
+
+/*
+ * (Carbon)
+ * Convert a FSSpec to a corresponding pathname.
+ * Returns noErr on success.
+ */
+static OSErr spec_to_path(const FSSpec *spec, char *buf, size_t size)
+{
+ OSErr err;
+ FSRef ref;
+
+ /* Convert FSSpec to FSRef ... */
+ err = FSpMakeFSRef(spec, &ref);
+ if (err != noErr) return (err);
+
+ /* ... then FSRef to pathname */
+ err = FSRefMakePath(&ref, buf, size);
+
+ /* Inform caller of success or failure */
+ return (err);
+}
+
+
+/*
+ * (Carbon) [via path_to_spec]
+ * Set creator and filetype of a file specified by POSIX-style pathname.
+ * Returns 0 on success, -1 in case of errors.
+ */
+int fsetfileinfo(char *pathname, OSType fcreator, OSType ftype)
+{
+ OSErr err;
+ FSSpec spec;
+ FInfo info;
+
+ /* Convert pathname to FSSpec */
+ if (path_to_spec(pathname, &spec) != noErr) return ( -1);
+
+ /* Obtain current finder info of the file */
+ if (FSpGetFInfo(&spec, &info) != noErr) return ( -1);
+
+ /* Overwrite creator and type */
+ info.fdCreator = fcreator;
+ info.fdType = ftype;
+ err = FSpSetFInfo(&spec, &info);
+
+ /* Inform caller of success or failure */
+ return ((err == noErr) ? 0 : -1);
+}
+
+
+#else /* MACH_O_CARBON */
+
+/*
+* Convert refnum+vrefnum+fname into a full file name
+* Store this filename in 'buf' (make sure it is long enough)
+* Note that 'fname' looks to be a "pascal" string
+*/
+static void refnum_to_name(char *buf, long refnum, short vrefnum, char *fname)
+{
+ DirInfo pb;
+ Str255 name;
+ int err;
+ int i, j;
+
+ char res[1000];
+
+ i = 999;
+
+ res[i] = 0;
+ i--;
+ for (j = 1; j <= fname[0]; j++)
+ {
+ res[i - fname[0] + j] = fname[j];
+ }
+ i -= fname[0];
+
+ pb.ioCompletion = NULL;
+ pb.ioNamePtr = name;
+ pb.ioVRefNum = vrefnum;
+ pb.ioDrParID = refnum;
+ pb.ioFDirIndex = -1;
+
+ while (1)
+ {
+ pb.ioDrDirID = pb.ioDrParID;
+ err = PBGetCatInfoSync((CInfoPBPtr) & pb);
+ res[i] = ':';
+ i--;
+ for (j = 1; j <= name[0]; j++)
+ {
+ res[i - name[0] + j] = name[j];
+ }
+ i -= name[0];
+
+ if (pb.ioDrDirID == fsRtDirID) break;
+ }
+
+ /* Extract the result */
+ for (j = 0, i++; res[i]; j++, i++) buf[j] = res[i];
+ buf[j] = 0;
+}
+
+
+/*
+* Convert a pascal string in place
+*
+* This function may be defined elsewhere, but since it is so
+* small, it is not worth finding the proper function name for
+* all the different platforms.
+*/
+static void ptocstr(StringPtr src)
+{
+ int i;
+
+ /* Hack -- pointer */
+ char *s = (char*)(src);
+
+ /* Hack -- convert the string */
+ for (i = s[0]; i; i--, s++) s[0] = s[1];
+
+ /* Hack -- terminate the string */
+ s[0] = '\0';
+}
+
+
+/*
+* Utility routines by Steve Linberg
+*
+* The following three routines (pstrcat, pstrinsert, and PathNameFromDirID)
+* were taken from the Think Reference section called "Getting a Full Pathname"
+* (under the File Manager section). We need PathNameFromDirID to get the
+* full pathname of the opened savefile, making no assumptions about where it
+* is.
+*
+* I had to hack PathNameFromDirID a little for MetroWerks, but it's awfully
+* nice.
+*/
+static void pstrcat(StringPtr dst, StringPtr src)
+{
+ /* copy string in */
+ BlockMove(src + 1, dst + *dst + 1, *src);
+
+ /* adjust length byte */
+ *dst += *src;
+}
+
+
+/*
+* pstrinsert - insert string 'src' at beginning of string 'dst'
+*/
+static void pstrinsert(StringPtr dst, StringPtr src)
+{
+ /* make room for new string */
+ BlockMove(dst + 1, dst + *src + 1, *dst);
+
+ /* copy new string in */
+ BlockMove(src + 1, dst + 1, *src);
+
+ /* adjust length byte */
+ *dst += *src;
+}
+
+
+static void PathNameFromDirID(long dirID, short vRefNum, StringPtr fullPathName)
+{
+ CInfoPBRec block;
+ Str255 directoryName;
+ OSErr err;
+
+ fullPathName[0] = '\0';
+
+ block.dirInfo.ioDrParID = dirID;
+ block.dirInfo.ioNamePtr = directoryName;
+
+ while (1)
+ {
+ block.dirInfo.ioVRefNum = vRefNum;
+ block.dirInfo.ioFDirIndex = -1;
+ block.dirInfo.ioDrDirID = block.dirInfo.ioDrParID;
+ err = PBGetCatInfoSync(&block);
+ pstrcat(directoryName, (StringPtr)"\p:");
+ pstrinsert(fullPathName, directoryName);
+ if (block.dirInfo.ioDrDirID == 2) break;
+ }
+}
+
+#endif /* MACH_O_CARBON */
+
+
+
+
+/*
+ * Center a rectangle inside another rectangle
+ *
+ * Consider using RepositionWindow() whenever possible
+ */
+static void center_rect(Rect *r, Rect *s)
+{
+ int centerx = (s->left + s->right) / 2;
+ int centery = (2 * s->top + s->bottom) / 3;
+ int dx = centerx - (r->right - r->left) / 2 - r->left;
+ int dy = centery - (r->bottom - r->top) / 2 - r->top;
+ r->left += dx;
+ r->right += dx;
+ r->top += dy;
+ r->bottom += dy;
+}
+
+
+/*
+ * Activate a given window, if necessary
+ */
+static void activate(WindowPtr w)
+{
+ /* Activate */
+ if (active != w)
+ {
+ /* Activate */
+ if (w) SetPort(GetWindowPort(w));
+
+ /* Remember */
+ active = w;
+ }
+}
+
+
+/*
+ * Display a warning message
+ */
+static void mac_warning(cptr warning)
+{
+ Str255 text;
+ int len, i;
+
+ /* Limit of 250 chars */
+ len = strlen(warning);
+ if (len > 250) len = 250;
+
+ /* Make a "Pascal" string */
+ text[0] = len;
+ for (i = 0; i < len; i++) text[i + 1] = warning[i];
+
+ /* Prepare the dialog box values */
+ ParamText(text, "\p", "\p", "\p");
+
+ /* Display the Alert, wait for Okay */
+ Alert(129, 0L);
+}
+
+
+
+/*** Some generic functions ***/
+
+/*
+ * Hack -- activate a color (0 to 255)
+ */
+static void term_data_color(term_data *td, int a)
+{
+ /* Activate the color */
+ if (td->last != a)
+ {
+ /* Activate the color */
+ RGBForeColor(&color_info[a]);
+
+ /* Memorize color */
+ td->last = a;
+ }
+}
+
+
+/*
+ * Hack -- Apply and Verify the "font" info
+ *
+ * This should usually be followed by "term_data_check_size()"
+ *
+ * XXX XXX To force (re)initialisation of td->tile_wid and td->tile_hgt
+ * you have to reset them to zero before this function is called.
+ * XXX XXX This is automatic when the program starts because the term_data
+ * array is WIPE'd by term_data_hack, but isn't in the other cases, i.e.
+ * font, font style and size changes.
+ */
+static void term_data_check_font(term_data *td)
+{
+ int i;
+
+ FontInfo info;
+
+ WindowPtr old = active;
+
+
+ /* Activate */
+ activate(td->w);
+
+ /* Instantiate font */
+ TextFont(td->font_id);
+ TextSize(td->font_size);
+ TextFace(td->font_face);
+
+ /* Extract the font info */
+ GetFontInfo(&info);
+
+ /* Assume monospaced */
+ td->font_mono = TRUE;
+
+ /* Extract the font sizing values XXX XXX XXX */
+ td->font_wid = CharWidth('@'); /* info.widMax; */
+ td->font_hgt = info.ascent + info.descent;
+ td->font_o_x = 0;
+ td->font_o_y = info.ascent;
+
+ /* Check important characters */
+ for (i = 33; i < 127; i++)
+ {
+ /* Hack -- notice non-mono-space */
+ if (td->font_wid != CharWidth(i)) td->font_mono = FALSE;
+
+ /* Hack -- collect largest width */
+ if (td->font_wid < CharWidth(i)) td->font_wid = CharWidth(i);
+ }
+
+ /* Set default offsets */
+ td->tile_o_x = td->font_o_x;
+ td->tile_o_y = td->font_o_y;
+
+ /* Set default tile size */
+ if (td->tile_wid == 0) td->tile_wid = td->font_wid;
+ if (td->tile_hgt == 0) td->tile_hgt = td->font_hgt;
+
+ /* Re-activate the old window */
+ activate(old);
+}
+
+
+/*
+ * Hack -- Apply and Verify the "size" info
+ */
+static void term_data_check_size(term_data *td)
+{
+ if (td == &data[0])
+ {
+#ifndef ALLOW_BIG_SCREEN
+
+ /* Forbid resizing of the Angband window */
+ td->cols = 80;
+ td->rows = 24;
+
+#else
+
+ /* Enforce minimal size */
+ if (td->cols < 80) td->cols = 80;
+ if (td->rows < 24) td->rows = 24;
+
+#endif /* !ALLOW_BIG_SCREEN */
+ }
+
+ /* Information windows can be much smaller */
+ else
+ {
+ if (td->cols < 1) td->cols = 1;
+ if (td->rows < 1) td->rows = 1;
+ }
+
+ /* Enforce maximal sizes */
+ if (td->cols > 255) td->cols = 255;
+ if (td->rows > 255) td->rows = 255;
+
+ /* Minimal tile size */
+ if (td->tile_wid < td->font_wid) td->tile_wid = td->font_wid;
+ if (td->tile_hgt < td->font_hgt) td->tile_hgt = td->font_hgt;
+
+ /* Default tile offsets */
+ td->tile_o_x = (td->tile_wid - td->font_wid) / 2;
+ td->tile_o_y = (td->tile_hgt - td->font_hgt) / 2;
+
+ /* Minimal tile offsets */
+ if (td->tile_o_x < 0) td->tile_o_x = 0;
+ if (td->tile_o_y < 0) td->tile_o_y = 0;
+
+ /* Apply font offsets */
+ td->tile_o_x += td->font_o_x;
+ td->tile_o_y += td->font_o_y;
+
+ /* Calculate full window size */
+ td->size_wid = td->cols * td->tile_wid + td->size_ow1 + td->size_ow2;
+ td->size_hgt = td->rows * td->tile_hgt + td->size_oh1 + td->size_oh2;
+
+ {
+ BitMap tScreen;
+
+ /* Get current screen */
+ (void)GetQDGlobalsScreenBits(&tScreen);
+
+ /* Verify the top */
+ if (td->r.top > tScreen.bounds.bottom - td->size_hgt)
+ {
+ td->r.top = tScreen.bounds.bottom - td->size_hgt;
+ }
+
+ /* Verify the top */
+ if (td->r.top < tScreen.bounds.top + GetMBarHeight())
+ {
+ td->r.top = tScreen.bounds.top + GetMBarHeight();
+ }
+
+ /* Verify the left */
+ if (td->r.left > tScreen.bounds.right - td->size_wid)
+ {
+ td->r.left = tScreen.bounds.right - td->size_wid;
+ }
+
+ /* Verify the left */
+ if (td->r.left < tScreen.bounds.left)
+ {
+ td->r.left = tScreen.bounds.left;
+ }
+ }
+
+ /* Calculate bottom right corner */
+ td->r.right = td->r.left + td->size_wid;
+ td->r.bottom = td->r.top + td->size_hgt;
+
+ /* Assume no graphics */
+ td->t->higher_pict = FALSE;
+ td->t->always_pict = FALSE;
+
+
+ /* Handle graphics */
+ if (use_graphics)
+ {
+ /* Use higher pict whenever possible */
+ if (td->font_mono) td->t->higher_pict = TRUE;
+
+ /* Use always_pict only when necessary */
+ else td->t->always_pict = TRUE;
+ }
+
+ /* Fake mono-space */
+ if (!td->font_mono ||
+ (td->font_wid != td->tile_wid) ||
+ (td->font_hgt != td->tile_hgt))
+ {
+ /*
+ * Handle fake monospace
+ *
+ * pelpel: This is SLOW. Couldn't we use CharExtra
+ * and SpaceExtra for monospaced fonts?
+ */
+ if (td->t->higher_pict) td->t->higher_pict = FALSE;
+ td->t->always_pict = TRUE;
+ }
+}
+
+
+/*
+ * Hack -- resize a term_data
+ *
+ * This should normally be followed by "term_data_redraw()"
+ */
+static void term_data_resize(term_data *td)
+{
+ /*
+ * Actually resize the window
+ *
+ * ResizeWindow is the preferred API call, but it cannot
+ * be used here.
+ */
+ SizeWindow(td->w, td->size_wid, td->size_hgt, 0);
+}
+
+
+
+/*
+ * Hack -- redraw a term_data
+ *
+ * Note that "Term_redraw()" calls "TERM_XTRA_CLEAR"
+ */
+static void term_data_redraw(term_data *td)
+{
+ term *old = Term;
+ Rect tRect;
+
+ /* Activate the term */
+ Term_activate(td->t);
+
+ /* Redraw the contents */
+ Term_redraw();
+
+ /* Flush the output */
+ Term_fresh();
+
+ /* Restore the old term */
+ Term_activate(old);
+
+ /* No need to redraw */
+ ValidWindowRect(td->w, GetPortBounds(GetWindowPort(td->w), &tRect));
+}
+
+
+/*
+ * Graphics support
+ */
+
+/* Set by Term_xtra_mac_react */
+#ifdef MACH_O_CARBON
+static CFStringRef pict_id; /* PICT id of image tiles */
+#else
+static int pict_id; /* PICT id of image tiles */
+#endif /* MACH_O_CARBON */
+
+static int graf_width; /* Width of a tile in pixels */
+static int graf_height; /* Height of a tile in pixels */
+
+/* Calculated by PICT loading code */
+static int pict_cols; /* Number of columns in tiles */
+static int pict_rows; /* Number of rows in tiles */
+
+/* Available graphics modes */
+#define GRAF_MODE_NONE 0 /* plain ASCII */
+#define GRAF_MODE_8X8 1 /* 8x8 tiles */
+#define GRAF_MODE_16X16 2 /* 16x16 tiles */
+#define GRAF_MODE_32X32 3 /* 32x32 tiles */
+
+static int graf_mode = GRAF_MODE_NONE; /* current graphics mode */
+static int graf_mode_req = GRAF_MODE_NONE; /* requested graphics mode */
+
+#define TR_NONE 0 /* No transparency */
+#define TR_OVER 1 /* Overwriting with transparent black pixels */
+static int transparency_mode = TR_NONE; /* types of transparency effect */
+
+
+/*
+ * Forward Declare
+ */
+typedef struct FrameRec FrameRec;
+
+/*
+ * Frame
+ *
+ * - GWorld for the frame image
+ * - Handle to pix map (saved for unlocking/locking)
+ * - Pointer to color pix map (valid only while locked)
+ */
+struct FrameRec
+{
+ GWorldPtr framePort;
+ PixMapHandle framePixHndl;
+ PixMapPtr framePix;
+};
+
+
+/*
+ * The global picture data
+ */
+static FrameRec *frameP = NULL;
+
+
+/*
+ * Lock a frame
+ */
+static void BenSWLockFrame(FrameRec *srcFrameP)
+{
+ PixMapHandle pixMapH;
+
+ pixMapH = GetGWorldPixMap(srcFrameP->framePort);
+ (void)LockPixels(pixMapH);
+ HLockHi((Handle)pixMapH);
+ srcFrameP->framePixHndl = pixMapH;
+ srcFrameP->framePix = (PixMapPtr)(*(Handle)pixMapH);
+}
+
+
+/*
+ * Unlock a frame
+ */
+static void BenSWUnlockFrame(FrameRec *srcFrameP)
+{
+ if (srcFrameP->framePort != NULL)
+ {
+ HUnlock((Handle)srcFrameP->framePixHndl);
+ UnlockPixels(srcFrameP->framePixHndl);
+ }
+
+ srcFrameP->framePix = NULL;
+}
+
+
+
+#ifdef MACH_O_CARBON
+
+/* Moving graphics resources into data fork -- pelpel */
+
+/*
+ * (Carbon, Bundle)
+ * Given base and type names of a resource, find a file in the
+ * current application bundle and return its FSSpec in the third argument.
+ * Returns true on success, false otherwise.
+ * e.g. get_resource_spec(CFSTR("8x8"), CFSTR("png"), &spec);
+ */
+static Boolean get_resource_spec(
+ CFStringRef base_name, CFStringRef type_name, FSSpec *spec)
+{
+ CFURLRef res_url;
+ FSRef ref;
+
+ /* Find the tile resource specified in the current bundle */
+ res_url = CFBundleCopyResourceURL(
+ CFBundleGetMainBundle(), base_name, type_name, NULL);
+
+ /* Oops */
+ if (res_url == NULL) return (false);
+
+ /* Convert CFURL to FSRef */
+ (void)CFURLGetFSRef(res_url, &ref);
+
+ /* Convert FSRef to FSSpec */
+ (void)FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+
+ /* Free allocated CF data */
+ CFRelease(res_url);
+
+ /* Success */
+ return (true);
+}
+
+
+/*
+ * (QuickTime)
+ * Create a off-screen GWorld from contents of a file specified by a FSSpec.
+ *
+ * Globals referenced: data[0], graf_height, graf_width
+ * Globals updated: pict_rows, pict_cols.
+ */
+static OSErr create_gworld_from_spec(
+ GWorldPtr *tile_gw, FSSpec *tile_spec)
+{
+ OSErr err;
+ GraphicsImportComponent gi;
+ GWorldPtr gw, tmp_gw;
+ GDHandle gdh, tmp_gdh;
+ Rect r;
+ SInt16 depth;
+
+ /* See if QuickTime understands the file format */
+ err = GetGraphicsImporterForFile(tile_spec, &gi);
+
+ /* Oops */
+ if (err != noErr) return (err);
+
+ /* Get depth */
+ depth = data[0].pixelDepth;
+
+ /* Get GDH */
+ gdh = data[0].theGDH;
+
+ /* Retrieve the rect of the image */
+ err = GraphicsImportGetNaturalBounds(gi, &r);
+
+ /* Adjust it, so that the upper left corner becomes (0, 0) */
+ OffsetRect(&r, -r.left, -r.top);
+
+ /* Calculate and set numbers of rows and columns */
+ pict_rows = r.bottom / graf_height;
+ pict_cols = r.right / graf_width;
+
+ /* Create a GWorld */
+ err = NewGWorld(&gw, depth, &r, NULL, gdh, noNewDevice);
+
+ /* Oops */
+ if (err != noErr) return (err);
+
+ /* Save the pointer to the GWorld */
+ *tile_gw = gw;
+
+ /* Save the current GWorld */
+ GetGWorld(&tmp_gw, &tmp_gdh);
+
+ /* Activate the newly created GWorld */
+ (void)GraphicsImportSetGWorld(gi, gw, NULL);
+
+ /* Prevent pixmap from moving while drawing */
+ (void)LockPixels(GetGWorldPixMap(gw));
+
+ /* Clear the pixels */
+ EraseRect(&r);
+
+ /* Draw the image into it */
+ (void)GraphicsImportDraw(gi);
+
+ /* Release the lock*/
+ UnlockPixels(GetGWorldPixMap(gw));
+
+ /* Restore GWorld */
+ SetGWorld(tmp_gw, tmp_gdh);
+
+ /* Close the image importer */
+ CloseComponent(gi);
+
+ /* Success */
+ return (noErr);
+}
+
+#else /* MACH_O_CARBON */
+
+static OSErr BenSWCreateGWorldFromPict(
+ GWorldPtr *pictGWorld, PicHandle pictH)
+{
+ OSErr err;
+ GWorldPtr saveGWorld;
+ GDHandle saveGDevice;
+ GWorldPtr tempGWorld;
+ Rect pictRect;
+ short depth;
+ GDHandle theGDH;
+
+ tempGWorld = NULL;
+
+ /* Reset */
+ *pictGWorld = NULL;
+
+ /* Get depth */
+ depth = data[0].pixelDepth;
+
+ /* Get GDH */
+ theGDH = data[0].theGDH;
+
+ /* Obtain size rectangle */
+ pictRect = (**pictH).picFrame;
+ OffsetRect(&pictRect, -pictRect.left, -pictRect.top);
+
+ /* Calculate and set numbers of rows and columns */
+ pict_rows = pictRect.bottom / graf_height;
+ pict_cols = pictRect.right / graf_width;
+
+ /* Create a GWorld */
+ err = NewGWorld(&tempGWorld, depth, &pictRect, nil, theGDH, noNewDevice);
+
+ /* Oops */
+ if (err != noErr) return (err);
+
+ /* Save pointer */
+ *pictGWorld = tempGWorld;
+
+ /* Save GWorld */
+ GetGWorld(&saveGWorld, &saveGDevice);
+
+ /* Activate */
+ SetGWorld(tempGWorld, nil);
+
+ /* Dump the pict into the GWorld */
+ (void)LockPixels(GetGWorldPixMap(tempGWorld));
+ EraseRect(&pictRect);
+ DrawPicture(pictH, &pictRect);
+ UnlockPixels(GetGWorldPixMap(tempGWorld));
+
+ /* Restore GWorld */
+ SetGWorld(saveGWorld, saveGDevice);
+
+ /* Success */
+ return (0);
+}
+
+#endif /* MACH_O_CARBON */
+
+
+/*
+ * Init the global "frameP"
+ */
+static errr globe_init(void)
+{
+ OSErr err;
+
+ GWorldPtr tempPictGWorldP;
+
+#ifdef MACH_O_CARBON
+ FSSpec pict_spec;
+#else
+ PicHandle newPictH;
+#endif /* MACH_O_CARBON */
+
+
+ /* Use window XXX XXX XXX */
+ SetPort(GetWindowPort(data[0].w));
+
+
+#ifdef MACH_O_CARBON
+
+ /* Get the tile resources */
+ if (!get_resource_spec(pict_id, CFSTR("png"), &pict_spec)) return ( -1);
+
+ /* Create GWorld */
+ err = create_gworld_from_spec(&tempPictGWorldP, &pict_spec);
+
+#else /* MACH_O_CARBON */
+
+ /* Get the pict resource */
+ if ((newPictH = GetPicture(pict_id)) == 0) return ( -1);
+
+ /* Create GWorld */
+ err = BenSWCreateGWorldFromPict(&tempPictGWorldP, newPictH);
+
+ /* Release resource */
+ ReleaseResource((Handle)newPictH);
+
+#endif /* MACH_O_CARBON */
+
+ /* Error */
+ if (err != noErr) return (err);
+
+ /* Create the frame */
+ frameP = (FrameRec*)NewPtrClear((Size)sizeof(FrameRec));
+
+ /* Analyze result */
+ if (frameP == NULL) return ( -1);
+
+ /* Save GWorld */
+ frameP->framePort = tempPictGWorldP;
+
+ /* Lock it */
+ BenSWLockFrame(frameP);
+
+ /* Success */
+ return (noErr);
+}
+
+
+/*
+ * Nuke the global "frameP"
+ */
+static errr globe_nuke(void)
+{
+ /* Dispose */
+ if (frameP)
+ {
+ /* Unlock */
+ BenSWUnlockFrame(frameP);
+
+ /* Dispose of the GWorld */
+ DisposeGWorld(frameP->framePort);
+
+ /* Dispose of the memory */
+ DisposePtr((Ptr)frameP);
+
+ /* Forget */
+ frameP = NULL;
+ }
+
+ /* Flush events */
+ FlushEvents(everyEvent, 0);
+
+ /* Success */
+ return (0);
+}
+
+
+#ifdef USE_ASYNC_SOUND
+
+/*
+ * Asynchronous sound player - completely revised (beta)
+ */
+#if defined(USE_QT_SOUND) && !defined(MACH_O_CARBON)
+# undef USE_QT_SOUND
+#endif /* USE_QT_SOUND && !MACH_O_CARBON */
+
+/*
+ * How many sound channels will be pooled
+ *
+ * Was: 20, but I don't think we need 20 sound effects playing
+ * simultaneously :) -- pelpel
+ */
+#define MAX_CHANNELS 8
+
+/*
+ * A pool of sound channels
+ */
+static SndChannelPtr channels[MAX_CHANNELS];
+
+/*
+ * Status of the channel pool
+ */
+static Boolean channel_initialised = FALSE;
+
+/*
+ * Data handles containing sound samples
+ */
+static SndListHandle samples[SOUND_MAX];
+
+/*
+ * Reference counts of sound samples
+ */
+static SInt16 sample_refs[SOUND_MAX];
+
+#define SOUND_VOLUME_MIN 0 /* Default minimum sound volume */
+#define SOUND_VOLUME_MAX 255 /* Default maximum sound volume */
+#define VOLUME_MIN 0 /* Minimum sound volume in % */
+#define VOLUME_MAX 100 /* Maximum sound volume in % */
+#define VOLUME_INC 5 /* Increment sound volume in % */
+
+/*
+ * I'm just too lazy to write a panel for this XXX XXX
+ */
+static int sound_volume = SOUND_VOLUME_MAX;
+
+
+#ifdef USE_QT_SOUND
+
+/*
+ * QuickTime sound, by Ron Anderson
+ *
+ * I didn't choose to use Windows-style .ini files (Ron wrote a parser
+ * for it, but...), nor did I use lib/xtra directory, hoping someone
+ * would code plist-based configuration code in the future -- pelpel
+ */
+
+/*
+ * (QuickTime)
+ * Load sound effects from data-fork resources. They are wav files
+ * with the same names as angband_sound_name[] (variable.c)
+ *
+ * Globals referenced: angband_sound_name[]
+ * Globals updated: samples[] (they can be *huge*)
+ */
+static void load_sounds(void)
+{
+ OSErr err;
+ int i;
+
+ /* Start QuickTime */
+ err = EnterMovies();
+
+ /* Error */
+ if (err != noErr) return;
+
+ /*
+ * This loop may take a while depending on the count and size of samples
+ * to load.
+ *
+ * We should use a progress dialog for this.
+ */
+ for (i = 1; i < SOUND_MAX; i++)
+ {
+ /* Apple APIs always give me headacke :( */
+ CFStringRef name;
+ FSSpec spec;
+ SInt16 file_id;
+ SInt16 res_id;
+ Str255 movie_name;
+ Movie movie;
+ Track track;
+ Handle h;
+ Boolean res;
+
+ /* Allocate CFString with the name of sound event to be processed */
+ name = CFStringCreateWithCString(NULL, angband_sound_name[i],
+ kTextEncodingUS_ASCII);
+
+ /* Error */
+ if (name == NULL) continue;
+
+ /* Find sound sample resource with the same name */
+ res = get_resource_spec(name, CFSTR("wav"), &spec);
+
+ /* Free the reference to CFString */
+ CFRelease(name);
+
+ /* Error */
+ if (!res) continue;
+
+ /* Open the sound file */
+ err = OpenMovieFile(&spec, &file_id, fsRdPerm);
+
+ /* Error */
+ if (err != noErr) continue;
+
+ /* Create Movie from the file */
+ err = NewMovieFromFile(&movie, file_id, &res_id, movie_name,
+ newMovieActive, NULL);
+
+ /* Error */
+ if (err != noErr) goto close_file;
+
+ /* Get the first track of the movie */
+ track = GetMovieIndTrackType(movie, 1, AudioMediaCharacteristic,
+ movieTrackCharacteristic | movieTrackEnabledOnly );
+
+ /* Error */
+ if (track == NULL) goto close_movie;
+
+ /* Allocate a handle to store sample */
+ h = NewHandle(0);
+
+ /* Error */
+ if (h == NULL) goto close_track;
+
+ /* Dump the sample into the handle */
+ err = PutMovieIntoTypedHandle(movie, track, soundListRsrc, h, 0,
+ GetTrackDuration(track), 0L, NULL);
+
+ /* Success */
+ if (err == noErr)
+ {
+ /* Store the handle in the sample list */
+ samples[i] = (SndListHandle)h;
+ }
+
+ /* Failure */
+ else
+ {
+ /* Free unused handle */
+ DisposeHandle(h);
+ }
+
+ /* Free the track */
+close_track:
+ DisposeMovieTrack(track);
+
+ /* Free the movie */
+close_movie:
+ DisposeMovie(movie);
+
+ /* Close the movie file */
+close_file:
+ CloseMovieFile(file_id);
+ }
+
+ /* Stop QuickTime */
+ ExitMovies();
+}
+
+#else /* USE_QT_SOUND */
+
+/*
+* Return a handle of 'snd ' resource given Angband sound event number,
+* or NULL if it isn't found.
+*
+* Globals referenced: angband_sound_name[] (variable.c)
+*/
+static SndListHandle find_sound(int num)
+{
+Str255 sound;
+
+/* Get the proper sound name */
+strnfmt((char*)sound + 1, 255, "%.16s.wav", angband_sound_name[num]);
+sound[0] = strlen((char*)sound + 1);
+
+/* Obtain resource XXX XXX XXX */
+return ((SndListHandle)GetNamedResource('snd ', sound));
+}
+
+#endif /* USE_QT_SOUND */
+
+
+/*
+ * Clean up sound support - to be called when the game exits.
+ *
+ * Globals referenced: channels[], samples[], sample_refs[].
+ */
+static void cleanup_sound(void)
+{
+ int i;
+
+ /* No need to clean it up */
+ if (!channel_initialised) return;
+
+ /* Dispose channels */
+ for (i = 0; i < MAX_CHANNELS; i++)
+ {
+ /* Drain sound commands and free the channel */
+ SndDisposeChannel(channels[i], TRUE);
+ }
+
+ /* Free sound data */
+ for (i = 1; i < SOUND_MAX; i++)
+ {
+ /* Still locked */
+ if ((sample_refs[i] > 0) && (samples[i] != NULL))
+ {
+ /* Unlock it */
+ HUnlock((Handle)samples[i]);
+ }
+
+#ifndef USE_QT_SOUND
+
+ /* Release it */
+ if (samples[i]) ReleaseResource((Handle)samples[i]);
+
+#else
+/* Free handle */
+ if (samples[i]) DisposeHandle((Handle)samples[i]);
+
+#endif /* !USE_QT_SOUND */
+ }
+}
+
+
+/*
+ * Play sound effects asynchronously -- pelpel
+ *
+ * I don't believe those who first started using the previous implementations
+ * imagined this is *much* more complicated as it may seem. Anyway,
+ * introduced round-robin scheduling of channels and made it much more
+ * paranoid about HLock/HUnlock.
+ *
+ * XXX XXX de-refcounting, HUnlock and ReleaseResource should be done
+ * using channel's callback procedures, which set global flags, and
+ * a procedure hooked into CheckEvents does housekeeping. On the other
+ * hand, this lazy reclaiming strategy keeps things simple (no interrupt
+ * time code) and provides a sort of cache for sound data.
+ *
+ * Globals referenced: channel_initialised, channels[], samples[],
+ * sample_refs[].
+ * Globals updated: channel_initialised, channels[], sample_refs[].
+ * Only in !USE_QT_SOUND, samples[].
+ */
+static void play_sound(int num, int vol)
+{
+ OSErr err;
+ int i;
+ int prev_num;
+ SndListHandle h;
+ SndChannelPtr chan;
+ SCStatus status;
+
+ static int next_chan;
+ static SInt16 channel_occupants[MAX_CHANNELS];
+ static SndCommand volume_cmd, quiet_cmd;
+
+
+ /* Initialise sound channels */
+ if (!channel_initialised)
+ {
+ for (i = 0; i < MAX_CHANNELS; i++)
+ {
+ /* Paranoia - Clear occupant table */
+ /* channel_occupants[i] = 0; */
+
+ /* Create sound channel for all sounds to play from */
+ err = SndNewChannel(&channels[i], sampledSynth, initMono, NULL);
+
+ /* Error */
+ if (err != noErr)
+ {
+ /* Free channels */
+ while (--i >= 0)
+ {
+ SndDisposeChannel(channels[i], TRUE);
+ }
+
+ /* Notify error */
+ plog("Cannot initialise sound channels!");
+
+ /* Cancel request */
+ use_sound = arg_sound = FALSE;
+
+ /* Failure */
+ return;
+ }
+ }
+
+ /* First channel to use */
+ next_chan = 0;
+
+ /* Prepare volume command */
+ volume_cmd.cmd = volumeCmd;
+ volume_cmd.param1 = 0;
+ volume_cmd.param2 = 0;
+
+ /* Prepare quiet command */
+ quiet_cmd.cmd = quietCmd;
+ quiet_cmd.param1 = 0;
+ quiet_cmd.param2 = 0;
+
+ /* Initialisation complete */
+ channel_initialised = TRUE;
+ }
+
+ /* Paranoia */
+ if ((num <= 0) || (num >= SOUND_MAX)) return;
+
+ /* Prepare volume command */
+ volume_cmd.param2 = (SInt16)((vol << 4) | vol);
+
+ /* Channel to use (round robin) */
+ chan = channels[next_chan];
+
+ /* See if the resource is already in use */
+ if (sample_refs[num] > 0)
+ {
+ /* Resource in use */
+ h = samples[num];
+
+ /* Increase the refcount */
+ sample_refs[num]++;
+ }
+
+ /* Sound is not currently in use */
+ else
+ {
+ /* Get handle for the sound */
+#ifdef USE_QT_SOUND
+ h = samples[num];
+#else
+ h = find_sound(num);
+#endif /* USE_QT_SOUND */
+
+ /* Sample not available */
+ if (h == NULL) return;
+
+#ifndef USE_QT_SOUND
+
+ /* Load resource */
+ LoadResource((Handle)h);
+
+ /* Remember it */
+ samples[num] = h;
+
+#endif /* !USE_QT_SOUND */
+
+ /* Lock the handle */
+ HLock((Handle)h);
+
+ /* Initialise refcount */
+ sample_refs[num] = 1;
+ }
+
+ /* Poll the channel */
+ err = SndChannelStatus(chan, sizeof(SCStatus), &status);
+
+ /* It isn't available */
+ if ((err != noErr) || status.scChannelBusy)
+ {
+ /* Shut it down */
+ SndDoImmediate(chan, &quiet_cmd);
+ }
+
+ /* Previously played sound on this channel */
+ prev_num = channel_occupants[next_chan];
+
+ /* Process previously played sound */
+ if (prev_num != 0)
+ {
+ /* Decrease refcount */
+ sample_refs[prev_num]--;
+
+ /* We can free it now */
+ if (sample_refs[prev_num] <= 0)
+ {
+ /* Unlock */
+ HUnlock((Handle)samples[prev_num]);
+
+#ifndef USE_QT_SOUND
+
+ /* Release */
+ ReleaseResource((Handle)samples[prev_num]);
+
+ /* Forget handle */
+ samples[prev_num] = NULL;
+
+#endif /* !USE_QT_SOUND */
+
+ /* Paranoia */
+ sample_refs[prev_num] = 0;
+ }
+ }
+
+ /* Remember this sound as the current occupant of the channel */
+ channel_occupants[next_chan] = num;
+
+ /* Set up volume for channel */
+ SndDoImmediate(chan, &volume_cmd);
+
+ /* Play new sound asynchronously */
+ SndPlay(chan, h, TRUE);
+
+ /* Schedule next channel (round robin) */
+ next_chan++;
+ if (next_chan >= MAX_CHANNELS) next_chan = 0;
+}
+
+#endif /* USE_ASYNC_SOUND */
+
+
+
+
+/*** Support for the "z-term.c" package ***/
+
+
+/*
+ * Initialize a new Term
+ *
+ * Note also the "window type" called "noGrowDocProc", which might be more
+ * appropriate for the main "screen" window.
+ *
+ * Note the use of "srcCopy" mode for optimized screen writes.
+ */
+static void Term_init_mac(term *t)
+{
+ term_data *td = (term_data*)(t->data);
+ WindowAttributes wattrs;
+ OSStatus err;
+
+ static RGBColor black = {0x0000, 0x0000, 0x0000};
+ static RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF};
+
+#ifndef ALLOW_BIG_SCREEN
+
+ /* Every window has close and collapse boxes */
+ wattrs = kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute;
+
+ /* Information windows are resizable */
+ if (td != &data[0]) wattrs |= kWindowResizableAttribute;
+
+#else
+
+ /* Big screen - every window has close, collapse and resize boxes */
+ wattrs = kWindowCloseBoxAttribute |
+ kWindowCollapseBoxAttribute |
+ kWindowResizableAttribute;
+
+#endif /* !ALLOW_BIG_SCREEN */
+
+ /* Make the window */
+ err = CreateNewWindow(
+ kDocumentWindowClass,
+ wattrs,
+ &td->r,
+ &td->w);
+
+ /*
+ * XXX XXX Although the original main-mac.c doesn't perform error
+ * checking, it should be done here.
+ */
+
+ /* Set window title */
+ SetWTitle(td->w, td->title);
+
+ /* Activate the window */
+ activate(td->w);
+
+ /* Erase behind words */
+ TextMode(srcCopy);
+
+ /* Apply and Verify */
+ term_data_check_font(td);
+ term_data_check_size(td);
+
+ /* Resize the window */
+ term_data_resize(td);
+
+
+ /* Prepare the colors (real colors) */
+ RGBBackColor(&black);
+ RGBForeColor(&white);
+
+ /* Block */
+ {
+ Rect globalRect;
+ GDHandle mainGDH;
+ GDHandle currentGDH;
+ GWorldPtr windowGWorld;
+ PixMapHandle basePixMap;
+
+ /* Obtain the global rect */
+ GetWindowBounds((WindowRef)td->w, kWindowContentRgn, &globalRect);
+
+ /* Obtain the proper GDH */
+ mainGDH = GetMaxDevice(&globalRect);
+
+ /* Extract GWorld and GDH */
+ GetGWorld(&windowGWorld, &currentGDH);
+
+ /* Obtain base pixmap */
+ basePixMap = (**mainGDH).gdPMap;
+
+ /* Save pixel depth */
+ td->pixelDepth = (**basePixMap).pixelSize;
+
+ /* Save Window GWorld - unused */
+ td->theGWorld = windowGWorld;
+
+ /* Save Window GDH */
+ td->theGDH = currentGDH;
+
+ /* Save main GDH - unused */
+ td->mainSWGDH = mainGDH;
+ }
+
+ {
+ Rect portRect;
+
+ /* Get current Rect */
+ GetPortBounds(GetWindowPort(td->w), &portRect);
+
+ /* Clip to the window */
+ ClipRect(&portRect);
+
+ /* Erase the window */
+ EraseRect(&portRect);
+
+ /* Invalidate the window */
+ InvalWindowRect(td->w, &portRect);
+ }
+
+ /*
+ * A certain release of OS X fails to display windows at proper
+ * locations (_ _#)
+ */
+ if ((mac_os_version >= 0x1000) && (mac_os_version < 0x1010))
+ {
+ /* Hack - Make sure the window is displayed at (r.left,r.top) */
+ MoveWindow(td->w, td->r.left, td->r.top, 1);
+ }
+
+ /* Display the window if needed */
+ if (td->mapped)
+ {
+ TransitionWindow(td->w,
+ kWindowZoomTransitionEffect, kWindowShowTransitionAction, NULL);
+ }
+
+ /* Hack -- set "mapped" flag */
+ t->mapped_flag = td->mapped;
+
+ /* Forget color */
+ td->last = -1;
+}
+
+
+
+/*
+ * Nuke an old Term
+ */
+static void Term_nuke_mac(term *t)
+{
+ /* XXX */
+}
+
+
+
+/*
+ * Unused
+ */
+static errr Term_user_mac(int n)
+{
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * React to changes
+ */
+static errr Term_xtra_mac_react(void)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ int i;
+
+
+ /* Reset color */
+ td->last = -1;
+
+ /* Update colors */
+ for (i = 0; i < 256; i++)
+ {
+ u16b rv, gv, bv;
+
+ /* Extract the R,G,B data */
+ rv = angband_color_table[i][1];
+ gv = angband_color_table[i][2];
+ bv = angband_color_table[i][3];
+
+ /* Save the actual color */
+ color_info[i].red = (rv | (rv << 8));
+ color_info[i].green = (gv | (gv << 8));
+ color_info[i].blue = (bv | (bv << 8));
+ }
+
+
+ /* Handle sound */
+ if (use_sound != arg_sound)
+ {
+ /* Apply request */
+ use_sound = arg_sound;
+ }
+
+
+ /* Handle graphics */
+ if (graf_mode_req != graf_mode)
+ {
+ /* dispose old GWorld's if present */
+ globe_nuke();
+
+ /*
+ * Setup parameters according to request
+ *
+ * In [Z], you have to set use_graphics and arg_graphics to
+ * GRAPHICS_NONE, GRAPHICS_ORIGINAL or GRAPHICS_ADAM_BOLT, and
+ * comment ANGBAND_GRAF out.
+ */
+ switch (graf_mode_req)
+ {
+ /* ASCII - no graphics whatsoever */
+ case GRAF_MODE_NONE:
+ {
+ use_graphics = arg_graphics = FALSE;
+ transparency_mode = TR_NONE;
+ break;
+ }
+
+ /*
+ * 8x8 tiles (PICT id 1001)
+ * no transparency effect
+ * "old" graphics definitions
+ */
+ case GRAF_MODE_8X8:
+ {
+ use_graphics = arg_graphics = TRUE;
+ ANGBAND_GRAF = "old";
+ transparency_mode = TR_NONE;
+#ifdef MACH_O_CARBON
+ pict_id = CFSTR("8x8");
+#else
+ pict_id = 1001;
+#endif /* MACH_O_CARBON */
+ graf_width = graf_height = 8;
+ break;
+ }
+
+ /*
+ * 16x16 tiles (images: PICT id 1002, masks: PICT id 1003)
+ * with transparency effect
+ * "new" graphics definitions
+ */
+ case GRAF_MODE_16X16:
+ {
+ use_graphics = arg_graphics = TRUE;
+ ANGBAND_GRAF = "new";
+ transparency_mode = TR_OVER;
+#ifdef MACH_O_CARBON
+ pict_id = CFSTR("16x16");
+#else
+ pict_id = 1002;
+#endif /* MACH_O_CARBON */
+ graf_width = graf_height = 16;
+ break;
+ }
+
+ /*
+ * 32x32 tiles (images: PICT id 1004)
+ * with transparency effect
+ * "david" graphics definitions
+ * Vanilla-specific
+ */
+ case GRAF_MODE_32X32:
+ {
+ use_graphics = arg_graphics = TRUE;
+ ANGBAND_GRAF = "david";
+ transparency_mode = TR_OVER;
+#ifdef MACH_O_CARBON
+ pict_id = CFSTR("32x32");
+#else
+ pict_id = 1004;
+#endif /* MACH_O_CARBON */
+ graf_width = graf_height = 32;
+ break;
+ }
+ }
+
+ /* load tiles and setup GWorlds if tiles are requested */
+ if ((graf_mode_req != GRAF_MODE_NONE) && (globe_init() != 0))
+ {
+ /* Oops */
+ plog("Cannot initialize graphics!");
+
+ /* reject request */
+ graf_mode_req = GRAF_MODE_NONE;
+
+ /* reset graphics flags */
+ use_graphics = arg_graphics = FALSE;
+
+ /* reset transparency mode */
+ transparency_mode = TR_NONE;
+ }
+
+ /* update current graphics mode */
+ graf_mode = graf_mode_req;
+
+ /* Apply and Verify */
+ term_data_check_size(td);
+
+ /* Resize the window */
+ term_data_resize(td);
+
+ /* Reset visuals */
+#ifndef ANG281_RESET_VISUALS
+ reset_visuals(TRUE);
+#else
+ reset_visuals();
+#endif /* !ANG281_RESET_VISUALS */
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Do a "special thing"
+ */
+static errr Term_xtra_mac(int n, int v)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ Rect r;
+
+ /* Analyze */
+ switch (n)
+ {
+ /* Make a noise */
+ case TERM_XTRA_NOISE:
+ {
+ /* Make a noise */
+ SysBeep(1);
+
+ /* Success */
+ return (0);
+ }
+
+ /* Make a sound */
+ case TERM_XTRA_SOUND:
+ {
+#ifndef USE_ASYNC_SOUND
+
+ /*
+ * This may not be your choice, but much safer and much less
+ * resource hungry. Existing implementations can quite easily
+ * crash, by starting asynchronous playing and immediately
+ * unlocking and releasing the sound data just started playing...
+ * -- pelpel
+ */
+ Handle handle;
+ Str255 sound;
+
+ /* Get the proper sound name */
+ strnfmt((char*)sound + 1, 255, "%.16s.wav", angband_sound_name[v]);
+ sound[0] = strlen((char*)sound + 1);
+
+ /* Obtain resource XXX XXX XXX */
+ handle = GetNamedResource('snd ', sound);
+
+ /* Oops -- it is a failure, but we return 0 anyway */
+ if (handle == NULL) return (0);
+
+ /* Load and Lock */
+ LoadResource(handle);
+ HLock(handle);
+
+ /* Play sound (wait for completion) */
+ SndPlay(NULL, (SndListHandle)handle, FALSE);
+
+ /* Unlock and release */
+ HUnlock(handle);
+ ReleaseResource(handle);
+
+#else /* !USE_ASYNC_SOUND */
+
+ /* Play sound */
+ play_sound(v, sound_volume);
+
+#endif /* !USE_ASYNC_SOUND */
+
+ /* Success */
+ return (0);
+ }
+
+ /* Process random events */
+ case TERM_XTRA_BORED:
+ {
+ /* Process an event */
+ (void)CheckEvents(FALSE);
+
+ /* Success */
+ return (0);
+ }
+
+ /* Process pending events */
+ case TERM_XTRA_EVENT:
+ {
+ /* Process an event */
+ (void)CheckEvents(v);
+
+ /* Success */
+ return (0);
+ }
+
+ /* Flush all pending events (if any) */
+ case TERM_XTRA_FLUSH:
+ {
+ /* Hack -- flush all events */
+ while (CheckEvents(FALSE)) /* loop */;
+
+ /* Success */
+ return (0);
+ }
+
+ /* Hack -- Change the "soft level" */
+ case TERM_XTRA_LEVEL:
+ {
+ /* Activate if requested */
+ if (v) activate(td->w);
+
+ /* Success */
+ return (0);
+ }
+
+ /* Clear the screen */
+ case TERM_XTRA_CLEAR:
+ {
+ Rect portRect;
+
+ /* Get current Rect */
+ GetPortBounds(GetWindowPort(td->w), &portRect);
+
+ /* No clipping XXX XXX XXX */
+ ClipRect(&portRect);
+
+ /* Erase the window */
+ EraseRect(&portRect);
+
+ /* Set the color */
+ term_data_color(td, TERM_WHITE);
+
+ /* Frame the window in white */
+ MoveTo(0, 0);
+ LineTo(0, td->size_hgt - 1);
+ LineTo(td->size_wid - 1, td->size_hgt - 1);
+ LineTo(td->size_wid - 1, 0);
+
+ /* Clip to the new size */
+ r.left = portRect.left + td->size_ow1;
+ r.top = portRect.top + td->size_oh1;
+ r.right = portRect.right - td->size_ow2;
+ r.bottom = portRect.bottom - td->size_oh2;
+ ClipRect(&r);
+
+ /* Success */
+ return (0);
+ }
+
+ /* React to changes */
+ case TERM_XTRA_REACT:
+ {
+ /* React to changes */
+ return (Term_xtra_mac_react());
+ }
+
+ /* Delay (milliseconds) */
+ case TERM_XTRA_DELAY:
+ {
+ /*
+ * WaitNextEvent relinquishes CPU as well as
+ * induces a screen refresh on OS X
+ */
+
+ /* If needed */
+ if (v > 0)
+ {
+ EventRecord tmp;
+ UInt32 ticks;
+
+ /* Convert millisecs to ticks */
+ ticks = (v * 60L) / 1000;
+
+ /*
+ * Hack? - Put the programme into sleep.
+ * No events match ~everyEvent, so nothing
+ * should be lost in Angband's event queue.
+ * Even if ticks are 0, it's worth calling for
+ * the above mentioned reasons.
+ */
+ WaitNextEvent((EventMask)~everyEvent, &tmp, ticks, nil);
+ }
+
+ /* Success */
+ return (0);
+ }
+
+ /* Rename main window */
+ case TERM_XTRA_RENAME_MAIN_WIN:
+ {
+ char *s = strdup(angband_term_name[0]);
+
+ ctopstr((StringPtr)s);
+ SetWTitle(data[0].w, (StringPtr)s);
+
+ free(s);
+ return (0);
+ }
+
+/* MacOSX == Unix == Good */
+#ifdef USE_MACOSX
+ /* Get Delay of some milliseconds */
+ case TERM_XTRA_GET_DELAY:
+ {
+ int ret;
+ struct timeval tv;
+
+ ret = gettimeofday(&tv, NULL);
+ Term_xtra_long = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+
+ return ret;
+ }
+
+ /* Subdirectory scan */
+ case TERM_XTRA_SCANSUBDIR:
+ {
+ DIR *directory;
+ struct dirent *entry;
+
+ scansubdir_max = 0;
+
+ directory = opendir(scansubdir_dir);
+ if (!directory)
+ return 1;
+
+ while ((entry = readdir(directory)))
+ {
+ char file[PATH_MAX + NAME_MAX + 2];
+ struct stat filedata;
+
+ file[PATH_MAX + NAME_MAX] = 0;
+ strncpy(file, scansubdir_dir, PATH_MAX);
+ strncat(file, "/", 2);
+ strncat(file, entry->d_name, NAME_MAX);
+ if (!stat(file, &filedata) && S_ISDIR((filedata.st_mode)))
+ {
+ string_free(scansubdir_result[scansubdir_max]);
+ scansubdir_result[scansubdir_max] = string_make(entry->d_name);
+ ++scansubdir_max;
+ }
+ }
+
+ closedir(directory);
+ return 0;
+ }
+#endif
+ }
+
+ /* Oops */
+ return (1);
+}
+
+
+
+/*
+ * Low level graphics (Assumes valid input).
+ * Draw a "cursor" at (x,y), using a "yellow box".
+ * We are allowed to use "Term_what()" to determine
+ * the current screen contents (for inverting, etc).
+ */
+static errr Term_curs_mac(int x, int y)
+{
+ Rect r;
+
+ term_data *td = (term_data*)(Term->data);
+
+ /* Set the color */
+ term_data_color(td, TERM_YELLOW);
+
+ /* Frame the grid */
+ r.left = x * td->tile_wid + td->size_ow1;
+ r.right = r.left + td->tile_wid;
+ r.top = y * td->tile_hgt + td->size_oh1;
+ r.bottom = r.top + td->tile_hgt;
+
+#ifdef USE_DOUBLE_TILES
+
+ /* Mogami's bigtile patch */
+
+ /* Adjust it if double width tiles are requested */
+ if (use_bigtile &&
+ (x + 1 < Term->wid) &&
+ (Term->old->a[y][x + 1] == 255))
+ {
+ r.right += td->tile_wid;
+ }
+
+#endif /* USE_DOUBLE_TILES */
+
+ FrameRect(&r);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Low level graphics (Assumes valid input)
+ *
+ * Erase "n" characters starting at (x,y)
+ */
+static errr Term_wipe_mac(int x, int y, int n)
+{
+ Rect r;
+
+ term_data *td = (term_data*)(Term->data);
+
+
+ /* Erase the block of characters */
+ r.left = x * td->tile_wid + td->size_ow1;
+ r.right = r.left + n * td->tile_wid;
+ r.top = y * td->tile_hgt + td->size_oh1;
+ r.bottom = r.top + td->tile_hgt;
+ EraseRect(&r);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Low level graphics. Assumes valid input.
+ *
+ * Draw several ("n") chars, with an attr, at a given location.
+ */
+static errr Term_text_mac(int x, int y, int n, byte a, const char *cp)
+{
+ int xp, yp;
+
+#ifdef CLIP_HACK
+ Rect r;
+#endif /* CLIP_HACK */
+
+ term_data *td = (term_data*)(Term->data);
+
+
+ /* Set the color */
+ term_data_color(td, a);
+
+#ifdef CLIP_HACK
+ /* Hack - only draw within the bounding rect */
+ r.left = x * td->tile_wid + td->size_ow1;
+ r.right = r.left + n * td->tile_wid;
+ r.top = y * td->tile_hgt + td->size_oh1;
+ r.bottom = r.top + td->tile_hgt;
+ ClipRect(&r);
+
+ /* Hack - clear the content of the bounding rect */
+ EraseRect(&r);
+#endif /* CLIP_HACK */
+
+ /* Starting pixel */
+ xp = x * td->tile_wid + td->tile_o_x + td->size_ow1;
+ yp = y * td->tile_hgt + td->tile_o_y + td->size_oh1;
+
+ /* Move to the correct location */
+ MoveTo(xp, yp);
+
+ /* Draw the character */
+ if (n == 1) DrawChar(*cp);
+
+ /* Draw the string */
+ else DrawText(cp, 0, n);
+
+#ifdef CLIP_HACK
+ /* Obtain current window's rect */
+ GetPortBounds(GetWindowPort(td->w), &r);
+
+ /* Clip to the window again */
+ ClipRect(&r);
+#endif /* CLIP_HACK */
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Low level graphics (Assumes valid input)
+ *
+ * Erase "n" characters starting at (x,y)
+ */
+static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp,
+ const byte *tap, const char *tcp,
+ const byte *eap, const char *ecp)
+{
+ int i;
+ Rect dst_r;
+ GrafPtr port;
+ PixMapHandle pixmap_h;
+
+#ifdef CLIP_HACK
+ Rect portRect;
+#endif /* CLIP_HACK */
+
+ term_data *td = (term_data*)(Term->data);
+
+ static RGBColor black = {0x0000, 0x0000, 0x0000};
+ static RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF};
+
+
+#ifdef CLIP_HACK
+ /* Remember current window's rect */
+ GetPortBounds(GetWindowPort(td->w), &portRect);
+#endif /* CLIP_HACK */
+
+ /* Destination rectangle */
+ dst_r.left = x * td->tile_wid + td->size_ow1;
+#ifndef USE_DOUBLE_TILES
+ dst_r.right = dst_r.left + td->tile_wid;
+#endif /* !USE_DOUBLE_TILES */
+ dst_r.top = y * td->tile_hgt + td->size_oh1;
+ dst_r.bottom = dst_r.top + td->tile_hgt;
+
+ /* Scan the input */
+ for (i = 0; i < n; i++)
+ {
+ bool_ done = FALSE;
+
+ byte a = *ap++;
+ char c = *cp++;
+
+ byte ta = *tap++;
+ char tc = *tcp++;
+ byte ea = *eap++;
+ char ec = *ecp++;
+ bool_ has_overlay = (ea && ec);
+
+
+#ifdef USE_DOUBLE_TILES
+
+ /* Hack -- a filler for double-width tile */
+ if (use_bigtile && (a == 255))
+ {
+ /* Advance */
+ dst_r.left += td->tile_wid;
+
+ /* Ignore */
+ continue;
+ }
+
+ /* Prepare right side of rectagle now */
+ dst_r.right = dst_r.left + td->tile_wid;
+
+#endif /* USE_DOUBLE_TILES */
+
+ /* Graphics -- if Available and Needed */
+ if (use_graphics && ((byte)a & 0x80) && ((byte)c & 0x80))
+ {
+ int col, row;
+ Rect src_r;
+ int t_col, t_row;
+ Rect terrain_r;
+ int e_col, e_row;
+ Rect ego_r;
+
+ /* Row and Col */
+ row = ((byte)a & 0x7F) % pict_rows;
+ col = ((byte)c & 0x7F) % pict_cols;
+
+ /* Source rectangle */
+ src_r.left = col * graf_width;
+ src_r.top = row * graf_height;
+ src_r.right = src_r.left + graf_width;
+ src_r.bottom = src_r.top + graf_height;
+
+ /* Row and Col */
+ t_row = ((byte)ta & 0x7F) % pict_rows;
+ t_col = ((byte)tc & 0x7F) % pict_cols;
+
+ /* Source rectangle */
+ terrain_r.left = t_col * graf_width;
+ terrain_r.top = t_row * graf_height;
+ terrain_r.right = terrain_r.left + graf_width;
+ terrain_r.bottom = terrain_r.top + graf_height;
+
+ /* If there's an overlay */
+ if (has_overlay)
+ {
+ /* Row and Col */
+ e_row = ((byte)ea & 0x7F) % pict_rows;
+ e_col = ((byte)ec & 0x7F) % pict_cols;
+
+ /* Source rectangle */
+ ego_r.left = e_col * graf_width;
+ ego_r.top = e_row * graf_height;
+ ego_r.right = ego_r.left + graf_width;
+ ego_r.bottom = ego_r.top + graf_height;
+ }
+
+ /* Hardwire CopyBits */
+ RGBBackColor(&white);
+ RGBForeColor(&black);
+
+#ifdef USE_DOUBLE_TILES
+
+ /* Double width tiles */
+ if (use_bigtile) dst_r.right += td->tile_wid;
+
+#endif /* USE_DOUBLE_TILES */
+
+ /*
+ * OS X requires locking and unlocking of window port
+ * when we draw directly to its pixmap.
+ * The Lock/Unlock protocol is described in the Carbon
+ * Porting Guide.
+ */
+
+ /* Obtain current window's graphic port */
+ port = GetWindowPort(td->w);
+
+ /* Lock pixels, so we can use handle safely */
+ LockPortBits(port);
+
+ /* Get Pixmap handle */
+ pixmap_h = GetPortPixMap(port);
+
+ /* Transparency effect */
+ switch (transparency_mode)
+ {
+ /* No transparency effects */
+ case TR_NONE:
+ default:
+ {
+ /* Draw the picture */
+ CopyBits((BitMap*)frameP->framePix,
+ (BitMap*)*pixmap_h,
+ &src_r, &dst_r, srcCopy, NULL);
+
+ break;
+ }
+
+ /* Overwriting with transparent black pixels */
+ case TR_OVER:
+ {
+ /* Draw the terrain */
+ CopyBits((BitMap*)frameP->framePix,
+ (BitMap*)*pixmap_h,
+ &terrain_r, &dst_r, srcCopy, NULL);
+
+ /* Make black pixels transparent */
+ RGBBackColor(&black);
+
+ /* Draw mon/obj if there's one */
+ if ((row != t_row) || (col != t_col))
+ CopyBits((BitMap*)frameP->framePix,
+ (BitMap*)*pixmap_h,
+ &src_r, &dst_r, transparent, NULL);
+
+ /* Draw overlay if there's one */
+ if (has_overlay)
+ {
+ CopyBits((BitMap*)frameP->framePix,
+ (BitMap*)*pixmap_h,
+ &ego_r, &dst_r, transparent, NULL);
+ }
+
+ break;
+ }
+ }
+
+ /* Release the lock and dispose the PixMap handle */
+ UnlockPortBits(port);
+
+ /* Restore colors */
+ RGBBackColor(&black);
+ RGBForeColor(&white);
+
+ /* Forget color */
+ td->last = -1;
+
+ /* Done */
+ done = TRUE;
+ }
+
+ /* Normal */
+ if (!done)
+ {
+ int xp, yp;
+
+#ifdef CLIP_HACK
+ /* Hack - avoid writing outside of dst_r */
+ ClipRect(&dst_r);
+ /* Some characters do not match dst_r, therefore we have to... */
+#endif /* CLIP_HACK */
+
+ /* Erase */
+ EraseRect(&dst_r);
+
+ /* Set the color */
+ term_data_color(td, a);
+
+ /* Starting pixel */
+ xp = dst_r.left + td->tile_o_x;
+ yp = dst_r.top + td->tile_o_y;
+
+ /* Move to the correct location */
+ MoveTo(xp, yp);
+
+ /* Draw the character */
+ DrawChar(c);
+
+#ifdef CLIP_HACK
+ /* Clip to the window - inefficient (; ;) XXX XXX */
+ ClipRect(&portRect);
+#endif /* CLIP_HACK */
+ }
+
+ /* Advance */
+ dst_r.left += td->tile_wid;
+#ifndef USE_DOUBLE_TILES
+ dst_r.right += td->tile_wid;
+#endif /* !USE_DOUBLE_TILES */
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+
+
+
+/*
+ * Create and initialize window number "i"
+ */
+static void term_data_link(int i)
+{
+ term *old = Term;
+
+ term_data *td = &data[i];
+
+ /* Only once */
+ if (td->t) return;
+
+ /* Require mapped */
+ if (!td->mapped) return;
+
+ /* Allocate */
+ MAKE(td->t, term);
+
+ /* Initialize the term */
+ term_init(td->t, td->cols, td->rows, td->keys);
+
+ /* Use a "software" cursor */
+ td->t->soft_cursor = TRUE;
+
+ /* Erase with "white space" */
+ td->t->attr_blank = TERM_WHITE;
+ td->t->char_blank = ' ';
+
+ /* Prepare the init/nuke hooks */
+ td->t->init_hook = Term_init_mac;
+ td->t->nuke_hook = Term_nuke_mac;
+
+ /* Prepare the function hooks */
+ td->t->user_hook = Term_user_mac;
+ td->t->xtra_hook = Term_xtra_mac;
+ td->t->wipe_hook = Term_wipe_mac;
+ td->t->curs_hook = Term_curs_mac;
+ td->t->text_hook = Term_text_mac;
+ td->t->pict_hook = Term_pict_mac;
+
+#if 0
+
+ /* Doesn't make big difference? */
+ td->t->never_bored = TRUE;
+
+#endif
+
+ /* Link the local structure */
+ td->t->data = (void *)(td);
+
+ /* Activate it */
+ Term_activate(td->t);
+
+ /* Global pointer */
+ angband_term[i] = td->t;
+
+ /* Activate old */
+ Term_activate(old);
+}
+
+
+
+
+#ifdef MACH_O_CARBON
+
+/*
+ * (Carbon, Bundle)
+ * Return a POSIX pathname of the lib directory, or NULL if it can't be
+ * located. Caller must supply a buffer along with its size in bytes,
+ * where returned pathname will be stored.
+ * I prefer use of goto's to several nested if's, if they involve error
+ * handling. Sorry if you are offended by their presence. Modern
+ * languages have neater constructs for this kind of jobs -- pelpel
+ */
+static char *locate_lib(char *buf, size_t size)
+{
+ CFURLRef main_url = NULL;
+ CFStringRef main_str = NULL;
+ char *p;
+ char *res = NULL;
+
+ /* Obtain the URL of the main bundle */
+ main_url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+
+ /* Oops */
+ if (main_url == NULL) goto ret;
+
+ /* Convert it to POSIX pathname */
+ main_str = CFURLCopyFileSystemPath(main_url, kCFURLPOSIXPathStyle);
+
+ /* Oops */
+ if (main_str == NULL) goto ret;
+
+ /* Convert it again from darn unisomething encoding to ASCII */
+ if (CFStringGetCString(main_str, buf, size, kTextEncodingUS_ASCII) == FALSE)
+ goto ret;
+
+ /*
+ * Paranoia - bounds check
+ */
+ if (strlen(buf) + 25 + 1 > size) goto ret;
+
+ /* Location of the data */
+ strcat(buf, "/Contents/Resources/");
+
+ /* Set result */
+ res = buf;
+
+ret:
+
+ /* Release objects allocated and implicitly retained by the program */
+ if (main_str) CFRelease(main_str);
+ if (main_url) CFRelease(main_url);
+
+ /* pathname of the lib folder or NULL */
+ return (res);
+}
+
+
+#else /* MACH_O_CARBON */
+
+/*
+* Set the "current working directory" (also known as the "default"
+* volume/directory) to the location of the current application.
+*
+* Original code by: Maarten Hazewinkel (mmhazewi@cs.ruu.nl)
+*
+* Completely rewritten to use Carbon Process Manager. It retrieves the
+* volume and direcotry of the current application and simply stores it
+* in the (static) global variables app_vol and app_dir, but doesn't
+* mess with the "current working directory", because it has long been
+* an obsolete (and arcane!) feature.
+*/
+static void SetupAppDir(void)
+{
+ OSErr err;
+ ProcessSerialNumber curPSN;
+ ProcessInfoRec procInfo;
+ FSSpec cwdSpec;
+
+ /* Initialise PSN info for the current process */
+ curPSN.highLongOfPSN = 0;
+ curPSN.lowLongOfPSN = kCurrentProcess;
+
+ /* Fill in mandatory fields */
+ procInfo.processInfoLength = sizeof(ProcessInfoRec);
+ procInfo.processName = nil;
+ procInfo.processAppSpec = &cwdSpec;
+
+ /* Obtain current process information */
+ err = GetProcessInformation(&curPSN, &procInfo);
+
+ /* Oops */
+ if (err != noErr)
+ {
+ mac_warning("Unable to get process information");
+
+ /* Quit without writing anything */
+ ExitToShell();
+ }
+
+ /* Extract and save the Vol and Dir */
+ app_vol = cwdSpec.vRefNum;
+ app_dir = cwdSpec.parID;
+}
+
+#endif /* MACH_O_CARBON */
+
+
+
+
+/*
+ * Using Core Foundation's Preferences services -- pelpel
+ *
+ * Requires OS 8.6 or greater with CarbonLib 1.1 or greater. Or OS X,
+ * of course.
+ *
+ * Without this, we can support older versions of OS 8 as well
+ * (with CarbonLib 1.0.4).
+ *
+ * Frequent allocation/deallocation of small chunks of data is
+ * far from my liking, but since this is only called at the
+ * beginning and the end of a session, I hope this hardly matters.
+ */
+
+
+/*
+ * Store "value" as the value for preferences item name
+ * pointed by key
+ */
+static void save_pref_short(const char *key, short value)
+{
+ CFStringRef cf_key;
+ CFNumberRef cf_value;
+
+ /* allocate and initialise the key */
+ cf_key = CFStringCreateWithCString(NULL, key, kTextEncodingUS_ASCII);
+
+ /* allocate and initialise the value */
+ cf_value = CFNumberCreate(NULL, kCFNumberShortType, &value);
+
+ if ((cf_key != NULL) && (cf_value != NULL))
+ {
+ /* Store the key-value pair in the applications preferences */
+ CFPreferencesSetAppValue(
+ cf_key,
+ cf_value,
+ kCFPreferencesCurrentApplication);
+ }
+
+ /*
+ * Free CF data - the reverse order is a vain attempt to
+ * minimise memory fragmentation.
+ */
+ if (cf_value) CFRelease(cf_value);
+ if (cf_key) CFRelease(cf_key);
+}
+
+
+/*
+ * Load preference value for key, returns TRUE if it succeeds with
+ * vptr updated appropriately, FALSE otherwise.
+ */
+static bool_ query_load_pref_short(const char *key, short *vptr)
+{
+ CFStringRef cf_key;
+ CFNumberRef cf_value;
+
+ /* allocate and initialise the key */
+ cf_key = CFStringCreateWithCString(NULL, key, kTextEncodingUS_ASCII);
+
+ /* Oops */
+ if (cf_key == NULL) return (FALSE);
+
+ /* Retrieve value for the key */
+ cf_value = CFPreferencesCopyAppValue(
+ cf_key,
+ kCFPreferencesCurrentApplication);
+
+ /* Value not found */
+ if (cf_value == NULL)
+ {
+ CFRelease(cf_key);
+ return (FALSE);
+ }
+
+ /* Convert the value to short */
+ CFNumberGetValue(
+ cf_value,
+ kCFNumberShortType,
+ vptr);
+
+ /* Free CF data */
+ CFRelease(cf_value);
+ CFRelease(cf_key);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Update short data pointed by vptr only if preferences
+ * value for key is located.
+ */
+static void load_pref_short(const char *key, short *vptr)
+{
+ short tmp;
+
+ if (query_load_pref_short(key, &tmp)) *vptr = tmp;
+ return;
+}
+
+
+/*
+ * Save preferences to preferences file for current host+current user+
+ * current application.
+ */
+static void cf_save_prefs()
+{
+ int i;
+
+ /* Version stamp */
+ save_pref_short("version.major", PREF_VER_MAJOR);
+ save_pref_short("version.minor", PREF_VER_MINOR);
+ save_pref_short("version.patch", PREF_VER_PATCH);
+ save_pref_short("version.extra", PREF_VER_EXTRA);
+
+ /* Gfx settings */
+ save_pref_short("arg.arg_sound", arg_sound);
+ save_pref_short("arg.graf_mode", graf_mode);
+#ifdef USE_DOUBLE_TILES
+ save_pref_short("arg.big_tile", use_bigtile);
+#endif /* USE_DOUBLE_TILES */
+
+ /* Windows */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ term_data *td = &data[i];
+
+ save_pref_short(format("term%d.font_mono", i), td->font_mono);
+ save_pref_short(format("term%d.font_o_x", i), td->font_o_x);
+ save_pref_short(format("term%d.font_o_y", i), td->font_o_y);
+ save_pref_short(format("term%d.font_wid", i), td->font_wid);
+ save_pref_short(format("term%d.font_hgt", i), td->font_hgt);
+ save_pref_short(format("term%d.tile_o_x", i), td->tile_o_x);
+ save_pref_short(format("term%d.tile_o_y", i), td->tile_o_y);
+ save_pref_short(format("term%d.right", i), td->r.right);
+ save_pref_short(format("term%d.bottom", i), td->r.bottom);
+ save_pref_short(format("term%d.ow1", i), td->size_ow1);
+ save_pref_short(format("term%d.oh1", i), td->size_oh1);
+ save_pref_short(format("term%d.ow2", i), td->size_ow2);
+ save_pref_short(format("term%d.oh2", i), td->size_oh2);
+
+ save_pref_short(format("term%d.mapped", i), td->mapped);
+
+ save_pref_short(format("term%d.font_id", i), td->font_id);
+ save_pref_short(format("term%d.font_size", i), td->font_size);
+ save_pref_short(format("term%d.font_face", i), td->font_face);
+
+ save_pref_short(format("term%d.tile_wid", i), td->tile_wid);
+ save_pref_short(format("term%d.tile_hgt", i), td->tile_hgt);
+
+ save_pref_short(format("term%d.cols", i), td->cols);
+ save_pref_short(format("term%d.rows", i), td->rows);
+ save_pref_short(format("term%d.left", i), td->r.left);
+ save_pref_short(format("term%d.top", i), td->r.top);
+ }
+
+ /*
+ * Make sure preferences are persistent
+ */
+ CFPreferencesAppSynchronize(
+ kCFPreferencesCurrentApplication);
+}
+
+
+/*
+ * Load preferences from preferences file for current host+current user+
+ * current application.
+ */
+static void cf_load_prefs()
+{
+ bool_ ok;
+ short pref_major, pref_minor, pref_patch, pref_extra;
+ int i;
+
+ /* Assume nothing is wrong, yet */
+ ok = TRUE;
+
+ /* Load version information */
+ ok &= query_load_pref_short("version.major", &pref_major);
+ ok &= query_load_pref_short("version.minor", &pref_minor);
+ ok &= query_load_pref_short("version.patch", &pref_patch);
+ ok &= query_load_pref_short("version.extra", &pref_extra);
+
+ /* Any of the above failed */
+ if (!ok)
+ {
+ /* This may be the first run */
+ mac_warning("Preferences are not found.");
+
+ /* Ignore the rest */
+ return;
+ }
+
+#if 0
+
+ /* Check version */
+ if ((pref_major != PREF_VER_MAJOR) ||
+ (pref_minor != PREF_VER_MINOR) ||
+ (pref_patch != PREF_VER_PATCH) ||
+ (pref_extra != PREF_VER_EXTRA))
+ {
+ /* Message */
+ mac_warning(
+ format("Ignoring %d.%d.%d.%d preferences.",
+ pref_major, pref_minor, pref_patch, pref_extra));
+
+ /* Ignore */
+ return;
+ }
+
+#endif
+
+ /* Gfx settings */
+ {
+ short pref_tmp;
+
+ /* sound */
+ if (query_load_pref_short("arg.arg_sound", &pref_tmp))
+ arg_sound = pref_tmp;
+
+ /* graphics */
+ if (query_load_pref_short("arg.graf_mode", &pref_tmp))
+ graf_mode_req = pref_tmp;
+
+#ifdef USE_DOUBLE_TILES
+
+ /* double-width tiles */
+ if (query_load_pref_short("arg.big_tile", &pref_tmp))
+ {
+ use_bigtile = pref_tmp;
+ }
+
+#endif /* USE_DOUBLE_TILES */
+
+ }
+
+ /* Windows */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ term_data *td = &data[i];
+
+ load_pref_short(format("term%d.mapped", i), &td->mapped);
+
+ load_pref_short(format("term%d.font_id", i), &td->font_id);
+ load_pref_short(format("term%d.font_size", i), &td->font_size);
+ load_pref_short(format("term%d.font_face", i), &td->font_face);
+
+ load_pref_short(format("term%d.tile_wid", i), &td->tile_wid);
+ load_pref_short(format("term%d.tile_hgt", i), &td->tile_hgt);
+
+ load_pref_short(format("term%d.cols", i), &td->cols);
+ load_pref_short(format("term%d.rows", i), &td->rows);
+ load_pref_short(format("term%d.left", i), &td->r.left);
+ load_pref_short(format("term%d.top", i), &td->r.top);
+
+ load_pref_short(format("term%d.font_mono", i), &td->font_mono);
+ load_pref_short(format("term%d.font_o_x", i), &td->font_o_x);
+ load_pref_short(format("term%d.font_o_y", i), &td->font_o_y);
+ load_pref_short(format("term%d.font_wid", i), &td->font_wid);
+ load_pref_short(format("term%d.font_hgt", i), &td->font_hgt);
+ load_pref_short(format("term%d.tile_o_x", i), &td->tile_o_x);
+ load_pref_short(format("term%d.tile_o_y", i), &td->tile_o_y);
+ load_pref_short(format("term%d.right", i), &td->r.right);
+ load_pref_short(format("term%d.bottom", i), &td->r.bottom);
+ load_pref_short(format("term%d.ow1", i), &td->size_ow1);
+ load_pref_short(format("term%d.oh1", i), &td->size_oh1);
+ load_pref_short(format("term%d.ow2", i), &td->size_ow2);
+ load_pref_short(format("term%d.oh2", i), &td->size_oh2);
+ }
+}
+
+
+
+
+/*
+ * Hack -- default data for a window
+ */
+static void term_data_hack(term_data *td)
+{
+ short fid;
+
+ /* Default to Monaco font */
+ GetFNum("\pmonaco", &fid);
+
+ /* Wipe it */
+ WIPE(td, term_data);
+
+ /* No color */
+ td->last = -1;
+
+ /* Default borders */
+ td->size_ow1 = 2;
+ td->size_ow2 = 2;
+ td->size_oh1 = 2;
+ td->size_oh2 = 2;
+
+ /* Start hidden */
+ td->mapped = FALSE;
+
+ /* Default font */
+ td->font_id = fid;
+
+ /* Default font size - was 12 */
+ td->font_size = 14;
+
+ /* Default font face */
+ td->font_face = 0;
+
+ /* Default size */
+ td->rows = 24;
+ td->cols = 80;
+
+ /* Default position */
+ td->r.left = 10;
+ td->r.top = 40;
+
+ /* Minimal keys */
+ td->keys = 16;
+}
+
+
+/*
+ * Read the preference file, Create the windows.
+ *
+ * We attempt to use "FindFolder()" to track down the preference file.
+ */
+static void init_windows(void)
+{
+ int i, b = 0;
+
+ term_data *td;
+
+
+ /*** Default values ***/
+
+ /* Initialize (backwards) */
+ for (i = MAX_TERM_DATA; i-- > 0; )
+ {
+ int n;
+
+ cptr s;
+
+ /* Obtain */
+ td = &data[i];
+
+ /* Defaults */
+ term_data_hack(td);
+
+ /* Obtain title */
+ s = angband_term_name[i];
+
+ /* Get length */
+ n = strlen(s);
+
+ /* Maximal length */
+ if (n > 15) n = 15;
+
+ /* Copy the title */
+ strncpy((char*)(td->title) + 1, s, n);
+
+ /* Save the length */
+ td->title[0] = n;
+
+ /* Tile the windows */
+ td->r.left += (b * 30);
+ td->r.top += (b * 30);
+
+ /* Tile */
+ b++;
+ }
+
+
+ /*** Load preferences ***/
+
+ cf_load_prefs();
+
+
+ /*** Instantiate ***/
+
+ /* Main window */
+ td = &data[0];
+
+ /* Many keys */
+ td->keys = 1024;
+
+ /* Start visible */
+ td->mapped = TRUE;
+
+ /* Link (backwards, for stacking order) */
+ for (i = MAX_TERM_DATA; i-- > 0; )
+ {
+ term_data_link(i);
+ }
+
+ /* Main window */
+ td = &data[0];
+
+ /* Main window */
+ Term_activate(td->t);
+}
+
+
+/*
+ * Save preferences
+ */
+static void save_pref_file(void)
+{
+ cf_save_prefs();
+}
+
+
+
+
+#ifndef SAVEFILE_SCREEN
+
+/*
+ * Prepare savefile dialogue and set the variable
+ * savefile accordingly. Returns true if it succeeds, false (or
+ * aborts) otherwise. If all is false, only allow files whose type
+ * is 'SAVE'.
+ * Originally written by Peter Ammon
+ */
+static bool_ select_savefile(bool_ all)
+{
+ OSErr err;
+ FSSpec theFolderSpec;
+ FSSpec savedGameSpec;
+ NavDialogOptions dialogOptions;
+ NavReplyRecord reply;
+ /* Used only when 'all' is true */
+ NavTypeList types = {ANGBAND_CREATOR, 1, 1, {'SAVE'}};
+ NavTypeListHandle myTypeList;
+ AEDesc defaultLocation;
+
+#ifdef MACH_O_CARBON
+
+ /* Find the save folder */
+ err = path_to_spec(ANGBAND_DIR_SAVE, &theFolderSpec);
+
+#else
+
+ /* Find :lib:save: folder */
+ err = FSMakeFSSpec(
+ app_vol,
+ app_dir,
+ "\p:lib:save:",
+ &theFolderSpec);
+
+#endif
+
+ /* Oops */
+ if (err != noErr) quit("Unable to find the folder :lib:save:");
+
+ /* Get default Navigator dialog options */
+ err = NavGetDefaultDialogOptions(&dialogOptions);
+
+ /* Clear preview option */
+ dialogOptions.dialogOptionFlags &= ~kNavAllowPreviews;
+
+ /* Disable multiple file selection */
+ dialogOptions.dialogOptionFlags &= ~kNavAllowMultipleFiles;
+
+ /* Make descriptor for default location */
+ err = AECreateDesc(
+ typeFSS,
+ &theFolderSpec,
+ sizeof(FSSpec),
+ &defaultLocation);
+
+ /* Oops */
+ if (err != noErr) quit("Unable to allocate descriptor");
+
+ /* We are indifferent to signature and file types */
+ if (all)
+ {
+ myTypeList = (NavTypeListHandle)nil;
+ }
+
+ /* Set up type handle */
+ else
+ {
+ err = PtrToHand(&types, (Handle *) & myTypeList, sizeof(NavTypeList));
+
+ /* Oops */
+ if (err != noErr) quit("Error in PtrToHand. Try enlarging heap");
+
+ }
+
+ /* Call NavGetFile() with the types list */
+ err = NavChooseFile(
+ &defaultLocation,
+ &reply,
+ &dialogOptions,
+ nil,
+ nil,
+ nil,
+ myTypeList,
+ nil);
+
+ /* Free type list */
+ DisposeHandle((Handle)myTypeList);
+
+ /* Invalid response -- allow the user to cancel */
+ if (!reply.validRecord) return (FALSE);
+
+ /* Retrieve FSSpec from the reply */
+ if (err == noErr)
+ {
+ AEKeyword theKeyword;
+ DescType actualType;
+ Size actualSize;
+
+ /* Get a pointer to selected file */
+ (void)AEGetNthPtr(
+ &reply.selection,
+ 1,
+ typeFSS,
+ &theKeyword,
+ &actualType,
+ &savedGameSpec,
+ sizeof(FSSpec),
+ &actualSize);
+
+ /* Dispose NavReplyRecord, resources and descriptors */
+ (void)NavDisposeReply(&reply);
+ }
+
+ /* Dispose location info */
+ AEDisposeDesc(&defaultLocation);
+
+#ifdef MACH_O_CARBON
+
+ /* Convert FSSpec to pathname and store it in variable savefile */
+ (void)spec_to_path(&savedGameSpec, savefile, sizeof(savefile));
+
+#else
+
+ /* Convert FSSpec to pathname and store it in variable savefile */
+ refnum_to_name(
+ savefile,
+ savedGameSpec.parID,
+ savedGameSpec.vRefNum,
+ (char *)savedGameSpec.name);
+
+#endif
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Handle menu: "File" + "New"
+ */
+static void do_menu_file_new(void)
+{
+ /* Hack */
+ HiliteMenu(0);
+
+ /* Game is in progress */
+ game_in_progress = 1;
+
+ /* Flush input */
+ Term_flush();
+
+ /* Play a game */
+ play_game(TRUE);
+
+ /* Hack -- quit */
+ quit(NULL);
+}
+
+
+/*
+ * Handle menu: "File" + "Open" / "Import"
+ */
+static void do_menu_file_open(bool_ all)
+{
+ /* Let the player to choose savefile */
+ if (!select_savefile(all)) return;
+
+ /* Hack */
+ HiliteMenu(0);
+
+ /* Game is in progress */
+ game_in_progress = 1;
+
+ /* Flush input */
+ flush();
+
+ /* Play a game */
+ play_game(FALSE);
+
+ /* Hack -- quit */
+ quit(NULL);
+}
+
+#endif /* !SAVEFILE_SCREEN */
+
+
+/*
+ * Handle the "open_when_ready" flag
+ */
+static void handle_open_when_ready(void)
+{
+ /* Check the flag XXX XXX XXX make a function for this */
+ if (open_when_ready && initialized && !game_in_progress)
+ {
+ /* Forget */
+ open_when_ready = FALSE;
+
+ /* Game is in progress */
+ game_in_progress = 1;
+
+ /* Wait for it */
+ pause_line(23);
+
+ /* Flush input */
+ flush();
+
+#ifdef SAVEFILE_SCREEN
+
+ /* User double-clicked savefile; no savefile screen */
+ no_begin_screen = TRUE;
+
+#endif /* SAVEFILE_SCREEN */
+
+ /* Play a game */
+ play_game(FALSE);
+
+ /* Quit */
+ quit(NULL);
+ }
+}
+
+
+
+
+/*
+ * Menus
+ *
+ * The standard menus are:
+ *
+ * Apple (128) = { About, -, ... }
+ * File (129) = { New,Open,Import,Close,Save,-,Score,Quit }
+ * (If SAVEFILE_SCREEN is defined, this becomes)
+ * File (129) = { Close,Save,-,Score,Quit }
+ * Edit (130) = { Cut, Copy, Paste, Clear } (?)
+ * Font (131) = { Bold, Extend, -, Monaco, ..., -, ... }
+ * Size (132) = { ... }
+ * Window (133) = { Angband, Term-1/Mirror, Term-2/Recall, Term-3/Choice,
+ * Term-4, Term-5, Term-6, Term-7 }
+ * Special (134) = { Sound, Graphics, TileWidth, TileHeight, -,
+ * Fiddle, Wizard }
+ */
+
+/* Apple menu */
+#define MENU_APPLE 128
+#define ITEM_ABOUT 1
+
+/* File menu */
+#define MENU_FILE 129
+#ifndef SAVEFILE_SCREEN
+# define ITEM_NEW 1
+# define ITEM_OPEN 2
+# define ITEM_IMPORT 3
+# define ITEM_CLOSE 4
+# define ITEM_SAVE 5
+# ifdef HAS_SCORE_MENU
+# define ITEM_SCORE 7
+# define ITEM_QUIT 8
+# else
+# define ITEM_QUIT 7
+# endif /* HAS_SCORE_MENU */
+#else /* !SAVEFILE_SCREEN - in-game savefile menu */
+# define ITEM_CLOSE 1
+# define ITEM_SAVE 2
+# ifdef HAS_SCORE_MENU
+# define ITEM_SCORE 4
+# define ITEM_QUIT 5
+# else
+# define ITEM_QUIT 4
+# endif /* HAS_SCORE_MENU */
+#endif /* !SAVEFILE_SCREEN */
+
+/* Edit menu */
+#define MENU_EDIT 130
+#define ITEM_UNDO 1
+#define ITEM_CUT 3
+#define ITEM_COPY 4
+#define ITEM_PASTE 5
+#define ITEM_CLEAR 6
+
+/* Font menu */
+#define MENU_FONT 131
+#define ITEM_BOLD 1
+#define ITEM_WIDE 2
+
+/* Size menu */
+#define MENU_SIZE 132
+
+/* Windows menu */
+#define MENU_WINDOWS 133
+
+/* Special menu */
+#define MENU_SPECIAL 134
+#define ITEM_SOUND 1
+#define ITEM_GRAPH 2
+# define SUBMENU_GRAPH 144
+# define ITEM_NONE 1
+# define ITEM_8X8 2
+# define ITEM_16X16 3
+# define ITEM_32X32 4
+# define ITEM_BIGTILE 6
+#define ITEM_TILEWIDTH 3
+# define SUBMENU_TILEWIDTH 145
+#define ITEM_TILEHEIGHT 4
+# define SUBMENU_TILEHEIGHT 146
+#define ITEM_FIDDLE 6
+#define ITEM_WIZARD 7
+
+
+/*
+ * I HATE UNICODE! We've never wanted it. Some multi-national companies
+ * made it up as their internationalisation "solution". So I won't use
+ * any such API's -- pelpel
+ */
+#define NSIZES 32
+static byte menu_size_values[NSIZES];
+static byte menu_tilewidth_values[NSIZES];
+static byte menu_tileheight_values[NSIZES];
+
+/*
+ * Initialize the menus
+ *
+ * Fixed top level menus are now loaded all at once by GetNewMBar().
+ * Although this simplifies the function a bit, we have to make sure
+ * that resources have all the expected entries defined XXX XXX
+ */
+static void init_menubar(void)
+{
+ int i, n;
+
+ Rect r;
+
+ WindowPtr tmpw;
+
+ MenuRef m;
+
+#ifdef USE_NIB
+
+ /* The new way - loading main menu using Interface Builder services */
+ {
+ IBNibRef nib;
+ OSStatus err;
+
+ /* Create a nib reference to the main nib file */
+ err = CreateNibReference(CFSTR("main"), &nib);
+
+ /* Fatal error - missing Main.nib */
+ if (err != noErr) quit("Cannot find Main.nib in the bundle!");
+
+ /* Unarchive the menu bar and make it ready to use */
+ err = SetMenuBarFromNib(nib, CFSTR("MainMenu"));
+
+ /* Fatal error - couldn't insert menu bar */
+ if (err != noErr) quit("Cannot prepare menu bar!");
+
+ /* Dispose of the nib reference because we don't need it any longer */
+ DisposeNibReference(nib);
+ }
+
+#else /* USE_NIB */
+
+ /* The old way - loading main menu from Resource Manager resource */
+ {
+ Handle mbar;
+
+ /* Load menubar from resources */
+ mbar = GetNewMBar(128);
+
+ /* Whoops! */
+ if (mbar == nil) quit("Cannot find menubar('MBAR') id 128!");
+
+ /* Insert them into the current menu list */
+ SetMenuBar(mbar);
+
+ /* Free handle */
+ DisposeHandle(mbar);
+ }
+
+#endif /* USE_NIB */
+
+
+ /* Apple menu (id 128) - we don't have to do anything */
+
+#ifndef USE_NIB
+
+ /* File menu (id 129) - Aqua provides Quit menu for us */
+ if (is_aqua)
+ {
+ /* Get a handle to the file menu */
+ m = GetMenuHandle(MENU_FILE);
+
+ /* Nuke the quit menu since Aqua does that for us */
+ DeleteMenuItem(m, ITEM_QUIT);
+
+#ifndef HAS_SCORE_MENU
+
+ /* Hack - because the above leaves a separator as the last item */
+ DeleteMenuItem(m, ITEM_QUIT - 1);
+
+#endif /* !HAS_SCORE_MENU */
+ }
+
+#endif /* !USE_NIB */
+
+
+ /* Edit menu (id 130) - we don't have to do anything */
+
+
+ /*
+ * Font menu (id 131) - append names of mono-spaced fonts
+ * followed by all available ones
+ */
+ m = GetMenuHandle(MENU_FONT);
+
+ /* Fake window */
+ r.left = r.right = r.top = r.bottom = 0;
+
+ /* Make the fake window so that we can retrieve font info */
+ (void)CreateNewWindow(
+ kDocumentWindowClass,
+ kWindowNoAttributes,
+ &r,
+ &tmpw);
+
+ /* Activate the "fake" window */
+ SetPort(GetWindowPort(tmpw));
+
+ /* Default mode */
+ TextMode(0);
+
+ /* Default size */
+ TextSize(12);
+
+ /* Add the fonts to the menu */
+ AppendResMenu(m, 'FONT');
+
+ /* Size of menu */
+ n = CountMenuItems(m);
+
+ /* Scan the menu */
+ for (i = n; i >= 4; i--)
+ {
+ Str255 tmpName;
+ short fontNum;
+
+ /* Acquire the font name */
+ GetMenuItemText(m, i, tmpName);
+
+ /* Acquire the font index */
+ GetFNum(tmpName, &fontNum);
+
+ /* Apply the font index */
+ TextFont(fontNum);
+
+ /* Remove non-mono-spaced fonts */
+ if ((CharWidth('i') != CharWidth('W')) || (CharWidth('W') == 0))
+ {
+ /* Delete the menu item */
+ DeleteMenuItem(m, i);
+ }
+ }
+
+ /* Destroy the fake window */
+ DisposeWindow(tmpw);
+
+ /* Add a separator */
+ AppendMenu(m, "\p-");
+
+ /* Add the fonts to the menu */
+ AppendResMenu(m, 'FONT');
+
+
+#ifndef USE_NIB
+
+ /* Size menu (id 132) */
+ m = GetMenuHandle(MENU_SIZE);
+
+ /* Add some sizes (stagger choices) */
+ for (i = 8, n = 1; i <= 32; i += ((i / 16) + 1), n++)
+ {
+ Str15 buf;
+
+ /* Textual size */
+ strnfmt((char*)buf + 1, 15, "%d", i);
+ buf[0] = strlen((char*)buf + 1);
+
+ /* Add the item */
+ AppendMenu(m, buf);
+
+ /* Remember its value, for we can't be sure it's in ASCII */
+ menu_size_values[n] = i;
+ }
+
+#endif /* !USE_NIB */
+
+
+ /* Windows menu (id 133) */
+ m = GetMenuHandle(MENU_WINDOWS);
+
+ /* Default choices */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ Str15 buf;
+
+ /* Describe the item */
+ strnfmt((char*)buf + 1, 15, "%.15s", angband_term_name[i]);
+ buf[0] = strlen((char*)buf + 1);
+
+ /* Add the item */
+ AppendMenu(m, buf);
+
+ /* Command-Key shortcuts */
+ if (i < 8) SetItemCmd(m, i + 1, I2D(i));
+ }
+
+
+#ifndef USE_NIB
+
+ /* Special menu (id 134) */
+ m = GetMenuHandle(MENU_SPECIAL);
+
+ /* Insert Graphics submenu (id 144) */
+ {
+ MenuHandle submenu;
+
+ /* Get the submenu */
+ submenu = GetMenu(SUBMENU_GRAPH);
+
+ /* Insert it */
+ SetMenuItemHierarchicalMenu(m, ITEM_GRAPH, submenu);
+ }
+
+ /* Insert TileWidth submenu (id 145) */
+ {
+ MenuHandle submenu;
+
+ /* Get the submenu */
+ submenu = GetMenu(SUBMENU_TILEWIDTH);
+
+ /* Add some sizes */
+ for (i = 4, n = 1; i <= 32; i++, n++)
+ {
+ Str15 buf;
+
+ /* Textual size */
+ strnfmt((char*)buf + 1, 15, "%d", i);
+ buf[0] = strlen((char*)buf + 1);
+
+ /* Append item */
+ AppendMenu(submenu, buf);
+
+ /* Remember its value, for we can't be sure it's in ASCII */
+ menu_tilewidth_values[n] = i;
+ }
+
+ /* Insert it */
+ SetMenuItemHierarchicalMenu(m, ITEM_TILEWIDTH, submenu);
+ }
+
+ /* Insert TileHeight submenu (id 146) */
+ {
+ MenuHandle submenu;
+
+ /* Get the submenu */
+ submenu = GetMenu(SUBMENU_TILEHEIGHT);
+
+
+ /* Add some sizes */
+ for (i = 4, n = 1; i <= 32; i++, n++)
+ {
+ Str15 buf;
+
+ /* Textual size */
+ strnfmt((char*)buf + 1, 15, "%d", i);
+ buf[0] = strlen((char*)buf + 1);
+
+ /* Append item */
+ AppendMenu(submenu, buf);
+
+ /* Remember its value, for we can't be sure it's in ASCII */
+ menu_tileheight_values[n] = i;
+ }
+
+ /* Insert it */
+ SetMenuItemHierarchicalMenu(m, ITEM_TILEHEIGHT, submenu);
+ }
+
+#endif /* !USE_NIB */
+
+ /* Update the menu bar */
+ DrawMenuBar();
+}
+
+
+/*
+ * Prepare the menus
+ *
+ * It is very important that the player not be allowed to "save" the game
+ * unless the "inkey_flag" variable is set, indicating that the game is
+ * waiting for a new command. XXX XXX XXX
+ */
+
+static void setup_menus(void)
+{
+ int i, n;
+
+ short value;
+
+ Str255 s;
+
+ MenuHandle m;
+
+ term_data *td = NULL;
+
+
+ /* Relevant "term_data" */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* Unused */
+ if (!data[i].t) continue;
+
+ /* Notice the matching window */
+ if (data[i].w == FrontWindow()) td = &data[i];
+ }
+
+
+ /* File menu */
+ m = GetMenuHandle(MENU_FILE);
+
+ /* Get menu size */
+ n = CountMenuItems(m);
+
+ /* Reset menu */
+ for (i = 1; i <= n; i++)
+ {
+ /* Reset */
+ DisableMenuItem(m, i);
+ CheckMenuItem(m, i, FALSE);
+ }
+
+#ifndef SAVEFILE_SCREEN
+
+ /* Enable "new"/"open..."/"import..." */
+ if (initialized && !game_in_progress)
+ {
+ EnableMenuItem(m, ITEM_NEW);
+ EnableMenuItem(m, ITEM_OPEN);
+ EnableMenuItem(m, ITEM_IMPORT);
+ }
+
+#endif /* !SAVEFILE_SCREEN */
+
+ /* Enable "close" */
+ if (initialized)
+ {
+ EnableMenuItem(m, ITEM_CLOSE);
+ }
+
+ /* Enable "save" */
+ if (initialized && character_generated && inkey_flag)
+ {
+ EnableMenuItem(m, ITEM_SAVE);
+ }
+
+#ifdef HAS_SCORE_MENU
+
+ /* Enable "score" */
+ if (initialized && character_generated && !character_icky)
+ {
+ EnableMenuItem(m, ITEM_SCORE);
+ }
+
+#endif /* HAS_SCORE_MENU */
+
+ /* Enable "quit" */
+ if (!is_aqua)
+ {
+ if (!initialized || !character_generated || inkey_flag)
+ {
+ EnableMenuItem(m, ITEM_QUIT);
+ }
+ }
+
+
+ /* Edit menu */
+ m = GetMenuHandle(MENU_EDIT);
+
+ /* Get menu size */
+ n = CountMenuItems(m);
+
+ /* Reset menu */
+ for (i = 1; i <= n; i++)
+ {
+ /* Reset */
+ DisableMenuItem(m, i);
+ CheckMenuItem(m, i, FALSE);
+ }
+
+ /* Enable "edit" options if "needed" */
+ if (!td)
+ {
+ EnableMenuItem(m, ITEM_UNDO);
+ EnableMenuItem(m, ITEM_CUT);
+ EnableMenuItem(m, ITEM_COPY);
+ EnableMenuItem(m, ITEM_PASTE);
+ EnableMenuItem(m, ITEM_CLEAR);
+ }
+
+
+ /* Font menu */
+ m = GetMenuHandle(MENU_FONT);
+
+ /* Get menu size */
+ n = CountMenuItems(m);
+
+ /* Reset menu */
+ for (i = 1; i <= n; i++)
+ {
+ /* Reset */
+ DisableMenuItem(m, i);
+ CheckMenuItem(m, i, FALSE);
+ }
+
+ /* Hack -- look cute XXX XXX */
+ /* SetItemStyle(m, ITEM_BOLD, bold); */
+
+ /* Hack -- look cute XXX XXX */
+ /* SetItemStyle(m, ITEM_WIDE, extend); */
+
+ /* Active window */
+ if (initialized && td)
+ {
+ /* Enable "bold" */
+ EnableMenuItem(m, ITEM_BOLD);
+
+ /* Enable "extend" */
+ EnableMenuItem(m, ITEM_WIDE);
+
+ /* Check the appropriate "bold-ness" */
+ if (td->font_face & bold) CheckMenuItem(m, ITEM_BOLD, TRUE);
+
+ /* Check the appropriate "wide-ness" */
+ if (td->font_face & extend) CheckMenuItem(m, ITEM_WIDE, TRUE);
+
+ /* Analyze fonts */
+ for (i = 4; i <= n; i++)
+ {
+ /* Enable it */
+ EnableMenuItem(m, i);
+
+ /* Analyze font */
+ GetMenuItemText(m, i, s);
+ GetFNum(s, &value);
+
+ /* Check active font */
+ if (td->font_id == value) CheckMenuItem(m, i, TRUE);
+ }
+ }
+
+
+ /* Size menu */
+ m = GetMenuHandle(MENU_SIZE);
+
+ /* Get menu size */
+ n = CountMenuItems(m);
+
+ /* Reset menu */
+ for (i = 1; i <= n; i++)
+ {
+ /* Reset */
+ DisableMenuItem(m, i);
+ CheckMenuItem(m, i, FALSE);
+ }
+
+ /* Active window */
+ if (initialized && td)
+ {
+ /* Analyze sizes */
+ for (i = 1; i <= n; i++)
+ {
+ /* Analyze size */
+ value = menu_size_values[i];
+
+ /* Enable the "real" sizes */
+ if (RealFont(td->font_id, value)) EnableMenuItem(m, i);
+
+ /* Check the current size */
+ if (td->font_size == value) CheckMenuItem(m, i, TRUE);
+ }
+ }
+
+
+ /* Windows menu */
+ m = GetMenuHandle(MENU_WINDOWS);
+
+ /* Get menu size */
+ n = CountMenuItems(m);
+
+ /* Check active windows */
+ for (i = 1; i <= n; i++)
+ {
+ /* Check if needed */
+ CheckMenuItem(m, i, data[i - 1].mapped);
+ }
+
+
+ /* Special menu */
+ m = GetMenuHandle(MENU_SPECIAL);
+
+ /* Get menu size */
+ n = CountMenuItems(m);
+
+ /* Reset menu */
+ for (i = 1; i <= n; i++)
+ {
+ /* Reset */
+ DisableMenuItem(m, i);
+ CheckMenuItem(m, i, FALSE);
+ }
+
+ /* Item "arg_sound" */
+ EnableMenuItem(m, ITEM_SOUND);
+ CheckMenuItem(m, ITEM_SOUND, arg_sound);
+
+ /* Item "Graphics" */
+ EnableMenuItem(m, ITEM_GRAPH);
+ {
+ MenuRef submenu;
+
+ /* Graphics submenu */
+ (void)GetMenuItemHierarchicalMenu(m, ITEM_GRAPH, &submenu);
+
+ /* Get menu size */
+ n = CountMenuItems(submenu);
+
+ /* Reset menu */
+ for (i = 1; i <= n; i++)
+ {
+ /* Reset */
+ DisableMenuItem(submenu, i);
+ CheckMenuItem(submenu, i, FALSE);
+ }
+
+ /* Item "None" */
+ EnableMenuItem(submenu, ITEM_NONE);
+ CheckMenuItem(submenu, ITEM_NONE, (graf_mode == GRAF_MODE_NONE));
+
+ /* Item "8x8" */
+ EnableMenuItem(submenu, ITEM_8X8);
+ CheckMenuItem(submenu, ITEM_8X8, (graf_mode == GRAF_MODE_8X8));
+
+ /* Item "16x16" */
+ EnableMenuItem(submenu, ITEM_16X16);
+ CheckMenuItem(submenu, ITEM_16X16, (graf_mode == GRAF_MODE_16X16));
+
+ /* Item "32x32" */
+ /*EnableMenuItem(submenu, ITEM_32X32);
+ CheckMenuItem(submenu, ITEM_32X32, (graf_mode == GRAF_MODE_32X32));*/
+
+#ifdef USE_DOUBLE_TILES
+
+ /* Item "Big tiles" */
+ if (inkey_flag) EnableMenuItem(submenu, ITEM_BIGTILE);
+ CheckMenuItem(submenu, ITEM_BIGTILE, use_bigtile);
+
+#endif /* USE_DOUBLE_TILES */
+
+ }
+
+ /* Item "TileWidth" */
+ EnableMenuItem(m, ITEM_TILEWIDTH);
+ {
+ MenuRef submenu;
+
+ /* TileWidth submenu */
+ (void)GetMenuItemHierarchicalMenu(m, ITEM_TILEWIDTH, &submenu);
+
+ /* Get menu size */
+ n = CountMenuItems(submenu);
+
+ /* Reset menu */
+ for (i = 1; i <= n; i++)
+ {
+ /* Reset */
+ DisableMenuItem(submenu, i);
+ CheckMenuItem(submenu, i, FALSE);
+ }
+
+ /* Active window */
+ if (initialized && td)
+ {
+ /* Analyze sizes */
+ for (i = 1; i <= n; i++)
+ {
+ /* Analyze size */
+ value = menu_tilewidth_values[i];
+
+ /* Enable */
+ if (value >= td->font_wid) EnableMenuItem(submenu, i);
+
+ /* Check the current size */
+ if (td->tile_wid == value) CheckMenuItem(submenu, i, TRUE);
+ }
+ }
+ }
+
+ /* Item "TileHeight" */
+ EnableMenuItem(m, ITEM_TILEHEIGHT);
+ {
+ MenuRef submenu;
+
+ /* TileWidth submenu */
+ (void)GetMenuItemHierarchicalMenu(m, ITEM_TILEHEIGHT, &submenu);
+
+ /* Get menu size */
+ n = CountMenuItems(submenu);
+
+ /* Reset menu */
+ for (i = 1; i <= n; i++)
+ {
+ /* Reset */
+ DisableMenuItem(submenu, i);
+ CheckMenuItem(submenu, i, FALSE);
+ }
+
+ /* Active window */
+ if (initialized && td)
+ {
+ /* Analyze sizes */
+ for (i = 1; i <= n; i++)
+ {
+ /* Analyze size */
+ value = menu_tileheight_values[i];
+
+ /* Enable */
+ if (value >= td->font_hgt) EnableMenuItem(submenu, i);
+
+ /* Check the current size */
+ if (td->tile_hgt == value) CheckMenuItem(submenu, i, TRUE);
+ }
+ }
+ }
+
+ /* Item "arg_fiddle" */
+ EnableMenuItem(m, ITEM_FIDDLE);
+ CheckMenuItem(m, ITEM_FIDDLE, arg_fiddle);
+
+ /* Item "arg_wizard" */
+ EnableMenuItem(m, ITEM_WIZARD);
+ CheckMenuItem(m, ITEM_WIZARD, arg_wizard);
+
+
+ /* TileHeight menu */
+ m = GetMenuHandle(SUBMENU_TILEHEIGHT);
+
+ /* Get menu size */
+ n = CountMenuItems(m);
+
+ /* Reset menu */
+ for (i = 1; i <= n; i++)
+ {
+ /* Reset */
+ DisableMenuItem(m, i);
+ CheckMenuItem(m, i, FALSE);
+ }
+}
+
+
+/*
+ * Process a menu selection (see above)
+ *
+ * Hack -- assume that invalid menu selections are disabled above,
+ * which I have been informed may not be reliable. XXX XXX XXX
+ */
+static void menu(long mc)
+{
+ int i;
+
+ int menuid, selection;
+
+ static unsigned char s[1000];
+
+ short fid;
+
+ term_data *td = NULL;
+
+ WindowPtr old_win;
+
+
+ /* Analyze the menu command */
+ menuid = HiWord(mc);
+ selection = LoWord(mc);
+
+
+ /* Find the window */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* Skip dead windows */
+ if (!data[i].t) continue;
+
+ /* Notice matches */
+ if (data[i].w == FrontWindow()) td = &data[i];
+ }
+
+
+ /* Branch on the menu */
+ switch (menuid)
+ {
+ /* Apple Menu */
+ case MENU_APPLE:
+ {
+ /* About Angband... */
+ if (selection == ITEM_ABOUT)
+ {
+ DialogPtr dialog;
+ short item_hit;
+
+ /* Get the about dialogue */
+ dialog = GetNewDialog(128, 0, (WindowPtr) - 1);
+
+ /* Move it to the middle of the screen */
+ RepositionWindow(
+ GetDialogWindow(dialog),
+ NULL,
+ kWindowCenterOnMainScreen);
+
+ /* Show the dialog */
+ TransitionWindow(GetDialogWindow(dialog),
+ kWindowZoomTransitionEffect,
+ kWindowShowTransitionAction,
+ NULL);
+
+ /* Wait for user to click on it */
+ ModalDialog(0, &item_hit);
+
+ /* Free the dialogue */
+ DisposeDialog(dialog);
+ break;
+ }
+
+ break;
+ }
+
+ /* File Menu */
+ case MENU_FILE:
+ {
+ switch (selection)
+ {
+#ifndef SAVEFILE_SCREEN
+
+ /* New */
+ case ITEM_NEW:
+ {
+ do_menu_file_new();
+ break;
+ }
+
+ /* Open... */
+ case ITEM_OPEN:
+ {
+ do_menu_file_open(FALSE);
+ break;
+ }
+
+ /* Import... */
+ case ITEM_IMPORT:
+ {
+ do_menu_file_open(TRUE);
+ break;
+ }
+
+#endif /* !SAVEFILE_SCREEN */
+
+ /* Close */
+ case ITEM_CLOSE:
+ {
+ /* No window */
+ if (!td) break;
+
+ /* Not Mapped */
+ td->mapped = FALSE;
+
+ /* Not Mapped */
+ td->t->mapped_flag = FALSE;
+
+ /* Hide the window */
+ TransitionWindow(td->w,
+ kWindowZoomTransitionEffect,
+ kWindowHideTransitionAction,
+ NULL);
+
+ break;
+ }
+
+ /* Save */
+ case ITEM_SAVE:
+ {
+ /* Hack -- Forget messages */
+ msg_flag = FALSE;
+
+ /* Hack -- Save the game */
+#ifndef ZANG_AUTO_SAVE
+ do_cmd_save_game();
+#else
+ do_cmd_save_game(FALSE);
+#endif /* !ZANG_AUTO_SAVE */
+
+ break;
+ }
+
+#ifdef HAS_SCORE_MENU
+
+ /* Show score */
+ case ITEM_SCORE:
+ {
+ char buf[1024];
+
+ /* Paranoia */
+ if (!initialized || character_icky ||
+ !game_in_progress || !character_generated)
+ {
+ /* Can't happen but just in case */
+ plog("You may not do that right now.");
+
+ break;
+ }
+
+ /* Build the pathname of the score file */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_APEX,
+ "scores.raw");
+
+ /* Hack - open the score file for reading */
+ highscore_fd = fd_open(buf, O_RDONLY);
+
+ /* Paranoia - No score file */
+ if (highscore_fd < 0)
+ {
+ msg_print("Score file is not available.");
+
+ break;
+ }
+
+ /* Mega-Hack - prevent various functions XXX XXX XXX */
+ initialized = FALSE;
+
+ /* Save screen */
+ screen_save();
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Prepare scores */
+ if (game_in_progress && character_generated)
+ {
+ predict_score();
+ }
+
+#if 0 /* I don't like this - pelpel */
+
+ /* Mega-Hack - No current player XXX XXX XXX XXX */
+ else
+ {
+ display_scores_aux(0, MAX_HISCORES, -1, NULL);
+ }
+
+#endif
+
+ /* Close the high score file */
+ (void)fd_close(highscore_fd);
+
+ /* Forget the fd */
+ highscore_fd = -1;
+
+ /* Restore screen */
+ screen_load();
+
+ /* Hack - Flush it */
+ Term_fresh();
+
+ /* Mega-Hack - We are ready again */
+ initialized = TRUE;
+
+ /* Done */
+ break;
+ }
+
+#endif /* HAS_SCORE_MENU */
+
+ /* Quit (with save) */
+ case ITEM_QUIT:
+ {
+ /* Save the game (if necessary) */
+ if (game_in_progress && character_generated)
+ {
+ /* Hack -- Forget messages */
+ msg_flag = FALSE;
+
+ /* Save the game */
+#ifndef ZANG_AUTO_SAVE
+ do_cmd_save_game();
+#else
+ do_cmd_save_game(FALSE);
+#endif /* !ZANG_AUTO_SAVE */
+ }
+
+ /* Quit */
+ quit(NULL);
+ break;
+ }
+ }
+ break;
+ }
+
+ /* Edit menu */
+ case MENU_EDIT:
+ {
+ /* Unused */
+ break;
+ }
+
+ /* Font menu */
+ case MENU_FONT:
+ {
+ /* Require a window */
+ if (!td) break;
+
+ /* Memorize old */
+ old_win = active;
+
+ /* Activate */
+ activate(td->w);
+
+ /* Toggle the "bold" setting */
+ if (selection == ITEM_BOLD)
+ {
+ /* Toggle the setting */
+ if (td->font_face & bold)
+ {
+ td->font_face &= ~bold;
+ }
+ else
+ {
+ td->font_face |= bold;
+ }
+
+ /* Hack - clear tile size info XXX XXX */
+ td->tile_wid = td->tile_hgt = 0;
+
+ /* Apply and Verify */
+ term_data_check_font(td);
+ term_data_check_size(td);
+
+ /* Resize and Redraw */
+ term_data_resize(td);
+ term_data_redraw(td);
+
+ break;
+ }
+
+ /* Toggle the "wide" setting */
+ if (selection == ITEM_WIDE)
+ {
+ /* Toggle the setting */
+ if (td->font_face & extend)
+ {
+ td->font_face &= ~extend;
+ }
+ else
+ {
+ td->font_face |= extend;
+ }
+
+ /* Hack - clear tile size info XXX XXX */
+ td->tile_wid = td->tile_hgt = 0;
+
+ /* Apply and Verify */
+ term_data_check_font(td);
+ term_data_check_size(td);
+
+ /* Resize and Redraw */
+ term_data_resize(td);
+ term_data_redraw(td);
+
+ break;
+ }
+
+ /* Get a new font name */
+ GetMenuItemText(GetMenuHandle(MENU_FONT), selection, s);
+ GetFNum(s, &fid);
+
+ /* Save the new font id */
+ td->font_id = fid;
+
+ /* Current size is bad for new font */
+ if (!RealFont(td->font_id, td->font_size))
+ {
+ /* Find similar size */
+ for (i = 1; i <= 32; i++)
+ {
+ /* Adjust smaller */
+ if (td->font_size - i >= 8)
+ {
+ if (RealFont(td->font_id, td->font_size - i))
+ {
+ td->font_size -= i;
+ break;
+ }
+ }
+
+ /* Adjust larger */
+ if (td->font_size + i <= 128)
+ {
+ if (RealFont(td->font_id, td->font_size + i))
+ {
+ td->font_size += i;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Hack - clear tile size info XXX XXX */
+ td->tile_wid = td->tile_hgt = 0;
+
+ /* Apply and Verify */
+ term_data_check_font(td);
+ term_data_check_size(td);
+
+ /* Resize and Redraw */
+ term_data_resize(td);
+ term_data_redraw(td);
+
+ /* Restore the window */
+ activate(old_win);
+
+ break;
+ }
+
+ /* Size menu */
+ case MENU_SIZE:
+ {
+ if (!td) break;
+
+ /* Save old */
+ old_win = active;
+
+ /* Activate */
+ activate(td->w);
+
+ td->font_size = menu_size_values[selection];
+
+ /* Hack - clear tile size info XXX XXX */
+ td->tile_wid = td->tile_hgt = 0;
+
+ /* Apply and Verify */
+ term_data_check_font(td);
+ term_data_check_size(td);
+
+ /* Resize and Redraw */
+ term_data_resize(td);
+ term_data_redraw(td);
+
+ /* Restore */
+ activate(old_win);
+
+ break;
+ }
+
+ /* Window menu */
+ case MENU_WINDOWS:
+ {
+ /* Parse */
+ i = selection - 1;
+
+ /* Check legality of choice */
+ if ((i < 0) || (i >= MAX_TERM_DATA)) break;
+
+ /* Obtain the window */
+ td = &data[i];
+
+ /* Mapped */
+ td->mapped = TRUE;
+
+ /* Link */
+ term_data_link(i);
+
+ /* Mapped (?) */
+ td->t->mapped_flag = TRUE;
+
+ /* Show the window */
+ TransitionWindow(td->w,
+ kWindowZoomTransitionEffect,
+ kWindowShowTransitionAction,
+ NULL);
+
+ /* Bring to the front */
+ SelectWindow(td->w);
+
+ break;
+ }
+
+ /* Special menu */
+ case MENU_SPECIAL:
+ {
+ switch (selection)
+ {
+ case ITEM_SOUND:
+ {
+ /* Toggle arg_sound */
+ arg_sound = !arg_sound;
+
+ /* React to changes */
+ Term_xtra(TERM_XTRA_REACT, 0);
+
+ break;
+ }
+
+ case ITEM_FIDDLE:
+ {
+ arg_fiddle = !arg_fiddle;
+
+ break;
+ }
+
+ case ITEM_WIZARD:
+ {
+ arg_wizard = !arg_wizard;
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ /* Graphics submenu */
+ case SUBMENU_GRAPH:
+ {
+ switch (selection)
+ {
+ case ITEM_NONE:
+ {
+ graf_mode_req = GRAF_MODE_NONE;
+
+ break;
+ }
+
+ case ITEM_8X8:
+ {
+ graf_mode_req = GRAF_MODE_8X8;
+
+ break;
+ }
+
+ case ITEM_16X16:
+ {
+ graf_mode_req = GRAF_MODE_16X16;
+
+ break;
+ }
+
+ case ITEM_32X32:
+ {
+ graf_mode_req = GRAF_MODE_32X32;
+
+ break;
+ }
+
+#ifdef USE_DOUBLE_TILES
+
+ case ITEM_BIGTILE:
+ {
+ term *old = Term;
+ term_data *td = &data[0];
+
+ /* Toggle "use_bigtile" */
+ use_bigtile = !use_bigtile;
+ arg_bigtile = use_bigtile;
+
+ /* Activate */
+ Term_activate(td->t);
+
+ /* Resize the term */
+ Term_resize(td->cols, td->rows);
+
+ /* Activate old */
+ Term_activate(old);
+
+ break;
+ }
+
+#endif /* USE_DOUBLE_TILES */
+
+ }
+
+ /* Hack -- Force redraw */
+ Term_key_push(KTRL('R'));
+
+ break;
+ }
+
+ /* TileWidth menu */
+ case SUBMENU_TILEWIDTH:
+ {
+ if (!td) break;
+
+ /* Save old */
+ old_win = active;
+
+ /* Activate */
+ activate(td->w);
+
+ /* Analyse value */
+ td->tile_wid = menu_tilewidth_values[selection];
+
+ /* Apply and Verify */
+ term_data_check_size(td);
+
+ /* Resize and Redraw */
+ term_data_resize(td);
+ term_data_redraw(td);
+
+ /* Restore */
+ activate(old_win);
+
+ break;
+ }
+
+ /* TileHeight menu */
+ case SUBMENU_TILEHEIGHT:
+ {
+ if (!td) break;
+
+ /* Save old */
+ old_win = active;
+
+ /* Activate */
+ activate(td->w);
+
+ /* Analyse value */
+ td->tile_hgt = menu_tileheight_values[selection];
+
+ /* Apply and Verify */
+ term_data_check_size(td);
+
+ /* Resize and Redraw */
+ term_data_resize(td);
+ term_data_redraw(td);
+
+ /* Restore */
+ activate(old_win);
+
+ break;
+ }
+ }
+
+
+ /* Clean the menu */
+ HiliteMenu(0);
+}
+
+
+/*
+ * Check for extra required parameters -- From "Maarten Hazewinkel"
+ */
+static OSErr CheckRequiredAEParams(const AppleEvent *theAppleEvent)
+{
+ OSErr aeError;
+ DescType returnedType;
+ Size actualSize;
+
+ aeError = AEGetAttributePtr(
+ theAppleEvent, keyMissedKeywordAttr, typeWildCard,
+ &returnedType, NULL, 0, &actualSize);
+
+ if (aeError == errAEDescNotFound) return (noErr);
+
+ if (aeError == noErr) return (errAEParamMissed);
+
+ return (aeError);
+}
+
+
+/*
+ * Apple Event Handler -- Open Application
+ */
+static OSErr AEH_Start(const AppleEvent *theAppleEvent, AppleEvent *reply,
+ SInt32 handlerRefCon)
+{
+ return (CheckRequiredAEParams(theAppleEvent));
+}
+
+
+/*
+ * Apple Event Handler -- Quit Application
+ */
+static OSErr AEH_Quit(const AppleEvent *theAppleEvent, AppleEvent *reply,
+ SInt32 handlerRefCon)
+{
+ /* Quit later */
+ quit_when_ready = TRUE;
+
+ /* Check arguments */
+ return (CheckRequiredAEParams(theAppleEvent));
+}
+
+
+/*
+ * Apple Event Handler -- Print Documents
+ */
+static OSErr AEH_Print(const AppleEvent *theAppleEvent, AppleEvent *reply,
+ SInt32 handlerRefCon)
+{
+ return (errAEEventNotHandled);
+}
+
+
+/*
+ * Apple Event Handler by Steve Linberg (slinberg@crocker.com).
+ *
+ * The old method of opening savefiles from the finder does not work
+ * on the Power Macintosh, because CountAppFiles and GetAppFiles,
+ * used to return information about the selected document files when
+ * an application is launched, are part of the Segment Loader, which
+ * is not present in the RISC OS due to the new memory architecture.
+ *
+ * The "correct" way to do this is with AppleEvents. The following
+ * code is modeled on the "Getting Files Selected from the Finder"
+ * snippet from Think Reference 2.0. (The prior sentence could read
+ * "shamelessly swiped & hacked")
+ */
+static OSErr AEH_Open(const AppleEvent *theAppleEvent, AppleEvent* reply,
+ SInt32 handlerRefCon)
+{
+ FSSpec myFSS;
+ AEDescList docList;
+ OSErr err;
+ Size actualSize;
+ AEKeyword keywd;
+ DescType returnedType;
+ char msg[128];
+ FInfo myFileInfo;
+
+ /* Put the direct parameter (a descriptor list) into a docList */
+ err = AEGetParamDesc(
+ theAppleEvent, keyDirectObject, typeAEList, &docList);
+ if (err) return err;
+
+ /*
+ * We ignore the validity check, because we trust the FInder, and we only
+ * allow one savefile to be opened, so we ignore the depth of the list.
+ */
+ err = AEGetNthPtr(
+ &docList, 1L, typeFSS, &keywd, &returnedType,
+ (Ptr) & myFSS, sizeof(myFSS), &actualSize);
+ if (err) return err;
+
+ /* Only needed to check savefile type below */
+ err = FSpGetFInfo(&myFSS, &myFileInfo);
+ if (err)
+ {
+ strnfmt(msg, 128, "Argh! FSpGetFInfo failed with code %d", err);
+ mac_warning(msg);
+ return err;
+ }
+
+ /* Ignore non 'SAVE' files */
+ if (myFileInfo.fdType != 'SAVE') return noErr;
+
+#ifdef MACH_O_CARBON
+
+ /* Extract a file name */
+ (void)spec_to_path(&myFSS, savefile, sizeof(savefile));
+
+#else
+
+ /* XXX XXX XXX Extract a file name */
+ PathNameFromDirID(myFSS.parID, myFSS.vRefNum, (StringPtr)savefile);
+ pstrcat((StringPtr)savefile, (StringPtr)&myFSS.name);
+
+ /* Convert the string */
+ ptocstr((StringPtr)savefile);
+
+#endif /* MACH_O_CARBON */
+
+ /* Delay actual open */
+ open_when_ready = TRUE;
+
+ /* Dispose */
+ err = AEDisposeDesc(&docList);
+
+ /* Success */
+ return noErr;
+}
+
+
+/*
+ * Handle quit_when_ready, by Peter Ammon,
+ * slightly modified to check inkey_flag.
+ */
+static void quit_calmly(void)
+{
+ /* Quit immediately if game's not started */
+ if (!game_in_progress || !character_generated) quit(NULL);
+
+ /* Save the game and Quit (if it's safe) */
+ if (inkey_flag)
+ {
+ /* Hack -- Forget messages */
+ msg_flag = FALSE;
+
+ /* Save the game */
+#ifndef ZANG_AUTO_SAVE
+ do_cmd_save_game();
+#else
+ do_cmd_save_game(FALSE);
+#endif /* !ZANG_AUTO_SAVE */
+
+ /* Quit */
+ quit(NULL);
+ }
+
+ /* Wait until inkey_flag is set */
+}
+
+
+/*
+ * Macintosh modifiers (event.modifier & ccc):
+ * cmdKey, optionKey, shiftKey, alphaLock, controlKey
+ *
+ *
+ * Macintosh Keycodes (0-63 normal, 64-95 keypad, 96-127 extra):
+ *
+ * Return:36
+ * Delete:51
+ *
+ * Period:65
+ * Star:67
+ * Plus:69
+ * Clear:71
+ * Slash:75
+ * Enter:76
+ * Minus:78
+ * Equal:81
+ * 0-7:82-89
+ * 8-9:91-92
+ *
+ * backslash/vertical bar (Japanese keyboard):93
+ *
+ * F5: 96
+ * F6: 97
+ * F7: 98
+ * F3:99
+ * F8:100
+ * F10:101
+ * F11:103
+ * F13:105
+ * F14:107
+ * F9:109
+ * F12:111
+ * F15:113
+ * Help:114
+ * Home:115
+ * PgUp:116
+ * Del:117
+ * F4: 118
+ * End:119
+ * F2:120
+ * PgDn:121
+ * F1:122
+ * Lt:123
+ * Rt:124
+ * Dn:125
+ * Up:126
+ */
+
+
+/*
+ * Check for Events, return TRUE if we process any
+ *
+ * Now it really waits for events if wait set to true, to prevent
+ * undesirable monopoly of CPU. The side-effect is that you cannot do
+ * while (CheckEvents(TRUE)); without discretion.
+ */
+static bool_ CheckEvents(bool_ wait)
+{
+ EventRecord event;
+
+ WindowPtr w;
+
+ Rect r;
+
+ UInt32 sleep_ticks;
+
+ int ch, ck;
+
+ int mc, ms, mo, mx;
+
+ int i;
+
+ term_data *td = NULL;
+
+
+ /*
+ * With the wait mode blocking for available event / timeout,
+ * the non-wait mode should actually call WaitNextEvent,
+ * because of those event draining loops. Or we had to
+ * implement yet another mode.
+ */
+
+ /* Handles the quit_when_ready flag */
+ if (quit_when_ready) quit_calmly();
+
+ /* Blocking call to WaitNextEvent - should use MAX_INT XXX XXX */
+ if (wait) sleep_ticks = 0x7FFFFFFFL;
+
+ /* Non-blocking */
+ else sleep_ticks = 0L;
+
+ /* Get an event (or null) */
+ WaitNextEvent(everyEvent, &event, sleep_ticks, nil);
+
+ /* Hack -- Nothing is ready yet */
+ if (event.what == nullEvent) return (FALSE);
+
+
+ /* Analyze the event */
+ switch (event.what)
+ {
+
+#if 0
+
+ case activateEvt:
+ {
+ w = (WindowPtr)event.message;
+
+ activate(w);
+
+ break;
+ }
+
+#endif
+
+ case updateEvt:
+ {
+ /* Extract the window */
+ w = (WindowPtr)event.message;
+
+ /* Find the window */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* Skip dead windows */
+ if (!data[i].t) continue;
+
+ /* Notice matches */
+ if (data[i].w == w) td = &data[i];
+ }
+
+ /* Hack XXX XXX XXX */
+ BeginUpdate(w);
+ EndUpdate(w);
+
+ /* Redraw the window */
+ if (td) term_data_redraw(td);
+
+ break;
+ }
+
+ case keyDown:
+ case autoKey:
+ {
+ /* Extract some modifiers */
+ mc = (event.modifiers & controlKey) ? TRUE : FALSE;
+ ms = (event.modifiers & shiftKey) ? TRUE : FALSE;
+ mo = (event.modifiers & optionKey) ? TRUE : FALSE;
+ mx = (event.modifiers & cmdKey) ? TRUE : FALSE;
+
+ /* Keypress: (only "valid" if ck < 96) */
+ ch = (event.message & charCodeMask) & 255;
+
+ /* Keycode: see table above */
+ ck = ((event.message & keyCodeMask) >> 8) & 255;
+
+ /* Command + "normal key" -> menu action */
+ if (mx && (ck < 64))
+ {
+#ifdef MENU_SHORTCUTS
+ /* Hack -- Prepare the menus */
+ setup_menus();
+
+ /* Run the Menu-Handler */
+ menu(MenuKey(ch));
+
+ /* Turn off the menus */
+ HiliteMenu(0);
+
+ /* Done */
+ break;
+#else
+ /* Begin special trigger */
+ Term_keypress(31);
+
+ /* Send some modifier keys */
+ if (mc) Term_keypress('C');
+ if (ms) Term_keypress('S');
+ if (mo) Term_keypress('O');
+ if (mx) Term_keypress('X');
+
+ /* Enqueue the keypress */
+ Term_keypress(ch);
+
+ /* Terminate the trigger */
+ Term_keypress(13);
+#endif
+ }
+
+ /* Hide the mouse pointer */
+ ObscureCursor();
+
+ /* Normal key -> simple keypress */
+ if ((ck < 64) || (ck == 93))
+ {
+ /* Enqueue the keypress */
+ Term_keypress(ch);
+ }
+
+ /* Keypad keys -> trigger plus simple keypress */
+ else if (!mc && !ms && !mo && !mx && (ck < 96))
+ {
+ /* Hack -- "enter" is confused */
+ if (ck == 76) ch = '\n';
+
+ /* Begin special trigger */
+ Term_keypress(31);
+
+ /* Send the "keypad" modifier */
+ Term_keypress('K');
+
+ /* Send the "ascii" keypress */
+ Term_keypress(ch);
+
+ /* Terminate the trigger */
+ Term_keypress(13);
+ }
+
+ /* Bizarre key -> encoded keypress */
+ else if (ck <= 127)
+ {
+ /* Begin special trigger */
+ Term_keypress(31);
+
+ /* Send some modifier keys */
+ if (mc) Term_keypress('C');
+ if (ms) Term_keypress('S');
+ if (mo) Term_keypress('O');
+ if (mx) Term_keypress('X');
+
+ /* Downshift and encode the keycode */
+ Term_keypress(I2D((ck - 64) / 10));
+ Term_keypress(I2D((ck - 64) % 10));
+
+ /* Terminate the trigger */
+ Term_keypress(13);
+ }
+
+ break;
+ }
+
+ case mouseDown:
+ {
+ int code;
+
+ /* Analyze click location */
+ code = FindWindow(event.where, &w);
+
+ /* Find the window */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* Skip dead windows */
+ if (!data[i].t) continue;
+
+ /* Notice matches */
+ if (data[i].w == w) td = &data[i];
+ }
+
+ /* Analyze */
+ switch (code)
+ {
+ case inMenuBar:
+ {
+ setup_menus();
+ menu(MenuSelect(event.where));
+ HiliteMenu(0);
+ break;
+ }
+
+ case inDrag:
+ {
+ WindowPtr old_win;
+ BitMap tBitMap;
+ Rect pRect;
+
+ r = GetQDGlobalsScreenBits(&tBitMap)->bounds;
+ r.top += 20; /* GetMBarHeight() XXX XXX XXX */
+ InsetRect(&r, 4, 4);
+ DragWindow(w, event.where, &r);
+
+ /* Oops */
+ if (!td) break;
+
+ /* Save */
+ old_win = active;
+
+ /* Activate */
+ activate(td->w);
+
+ /* Analyze */
+ GetWindowBounds(
+ (WindowRef)td->w,
+ kWindowContentRgn,
+ &pRect);
+ td->r.left = pRect.left;
+ td->r.top = pRect.top;
+
+ /* Apply and Verify */
+ term_data_check_size(td);
+
+ /* Restore */
+ activate(old_win);
+
+ break;
+ }
+
+ case inGoAway:
+ {
+ /* Oops */
+ if (!td) break;
+
+ /* Track the go-away box */
+ if (TrackGoAway(w, event.where))
+ {
+ /* Not Mapped */
+ td->mapped = FALSE;
+
+ /* Not Mapped */
+ td->t->mapped_flag = FALSE;
+
+ /* Hide the window */
+ TransitionWindow(td->w,
+ kWindowZoomTransitionEffect,
+ kWindowHideTransitionAction,
+ NULL);
+ }
+
+ break;
+ }
+
+ case inGrow:
+ {
+ int x, y;
+
+ Rect nr;
+
+ term *old = Term;
+
+ /* Oops */
+ if (!td) break;
+
+#ifndef ALLOW_BIG_SCREEN
+
+ /* Minimum and maximum sizes */
+ r.left = 20 * td->tile_wid + td->size_ow1;
+ r.right = 80 * td->tile_wid + td->size_ow1 + td->size_ow2 + 1;
+ r.top = 1 * td->tile_hgt + td->size_oh1;
+ r.bottom = 24 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1;
+
+ /* Grow the rectangle */
+ if (!ResizeWindow(w, event.where, &r, NULL)) break;
+#else
+
+ /* Grow the rectangle */
+ if (!ResizeWindow(w, event.where, NULL, NULL)) break;
+
+#endif /* !ALLOW_BIG_SCREEN */
+
+
+ /* Obtain geometry of resized window */
+ GetWindowBounds(w, kWindowContentRgn, &nr);
+
+ /* Extract the new size in pixels */
+ y = nr.bottom - nr.top - td->size_oh1 - td->size_oh2;
+ x = nr.right - nr.left - td->size_ow1 - td->size_ow2;
+
+ /* Extract a "close" approximation */
+ td->rows = y / td->tile_hgt;
+ td->cols = x / td->tile_wid;
+
+ /* Apply and Verify */
+ term_data_check_size(td);
+
+ /* Activate */
+ Term_activate(td->t);
+
+ /* Hack -- Resize the term */
+ Term_resize(td->cols, td->rows);
+
+ /* Resize and Redraw */
+ term_data_resize(td);
+ term_data_redraw(td);
+
+ /* Restore */
+ Term_activate(old);
+
+ break;
+ }
+
+ case inContent:
+ {
+ SelectWindow(w);
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ /* OS Event -- From "Maarten Hazewinkel" */
+ case osEvt:
+ {
+ switch ((event.message >> 24) & 0x000000FF)
+ {
+ case suspendResumeMessage:
+
+ /* Resuming: activate the front window */
+ if (event.message & resumeFlag)
+ {
+ Cursor tempCursor;
+ SetPort(GetWindowPort(FrontWindow()));
+ SetCursor(GetQDGlobalsArrow(&tempCursor));
+ }
+
+ /* Suspend: deactivate the front window */
+ else
+ {
+ /* Nothing */
+ }
+
+ break;
+ }
+
+ break;
+ }
+
+ /* From "Steve Linberg" and "Maarten Hazewinkel" */
+ case kHighLevelEvent:
+ {
+ /* Process apple events */
+ (void)AEProcessAppleEvent(&event);
+
+ /* Handle "quit_when_ready" */
+ if (quit_when_ready)
+ {
+#if 0 /* Doesn't work with Aqua well */
+ /* Forget */
+ quit_when_ready = FALSE;
+
+ /* Do the menu key */
+ menu(MenuKey('q'));
+#endif
+ /* Turn off the menus */
+ HiliteMenu(0);
+ }
+
+ /* Handle "open_when_ready" */
+ else if (open_when_ready)
+ {
+ handle_open_when_ready();
+ }
+
+ break;
+ }
+
+ }
+
+
+ /* Something happened */
+ return (TRUE);
+}
+
+
+/*** Some Hooks for various routines ***/
+
+
+/*
+ * Mega-Hack -- emergency lifeboat
+ */
+static void *lifeboat = NULL;
+
+
+/*
+ * Hook to "release" memory
+ */
+#ifdef NEW_ZVIRT_HOOKS /* [V] removed the unused 'size' argument. */
+static void *hook_rnfree(void *v)
+#else
+static void *hook_rnfree(void *v, size_t size)
+#endif /* NEW_ZVIRT_HOOKS */
+{
+
+#ifdef USE_MALLOC
+
+ /* Alternative method */
+ free(v);
+
+#else
+
+ /* Dispose */
+ DisposePtr(v);
+
+#endif
+
+ /* Success */
+ return (NULL);
+}
+
+/*
+ * Hook to "allocate" memory
+ */
+static void *hook_ralloc(size_t size)
+{
+
+#ifdef USE_MALLOC
+
+ /* Make a new pointer */
+ return (malloc(size));
+
+#else
+
+ /* Make a new pointer */
+ return (NewPtr(size));
+
+#endif
+
+}
+
+/*
+ * Hook to handle "out of memory" errors
+ */
+static void *hook_rpanic(size_t size)
+{
+ /* void *mem = NULL; */
+
+ /* Free the lifeboat */
+ if (lifeboat)
+ {
+ /* Free the lifeboat */
+ DisposePtr(lifeboat);
+
+ /* Forget the lifeboat */
+ lifeboat = NULL;
+
+ /* Mega-Hack -- Warning */
+ mac_warning("Running out of Memory!\rAbort this process now!");
+
+ /* Mega-Hack -- Never leave this function */
+ while (TRUE) CheckEvents(TRUE);
+ }
+
+ /* Mega-Hack -- Crash */
+ return (NULL);
+}
+
+
+/*
+ * Hook to tell the user something important
+ */
+static void hook_plog(cptr str)
+{
+ /* Warning message */
+ mac_warning(str);
+}
+
+
+/*
+ * Hook to tell the user something, and then quit
+ */
+static void hook_quit(cptr str)
+{
+ /* Warning if needed */
+ if (str) mac_warning(str);
+
+#ifdef USE_ASYNC_SOUND
+
+ /* Clean up sound support */
+ cleanup_sound();
+
+#endif /* USE_ASYNC_SOUND */
+
+ /* Dispose of graphic tiles */
+ if (frameP)
+ {
+ /* Unlock */
+ BenSWUnlockFrame(frameP);
+
+ /* Dispose of the GWorld */
+ DisposeGWorld(frameP->framePort);
+
+ /* Dispose of the memory */
+ DisposePtr((Ptr)frameP);
+ }
+
+ /* Write a preference file */
+ save_pref_file();
+
+ /* All done */
+ ExitToShell();
+}
+
+
+/*
+ * Hook to tell the user something, and then crash
+ */
+static void hook_core(cptr str)
+{
+ /* XXX Use the debugger */
+ /* DebugStr(str); */
+
+ /* Warning */
+ if (str) mac_warning(str);
+
+ /* Warn, then save player */
+ mac_warning("Fatal error.\rI will now attempt to save and quit.");
+
+ /* Attempt to save */
+ if (!save_player()) mac_warning("Warning -- save failed!");
+
+ /* Quit */
+ quit(NULL);
+}
+
+
+
+/*** Main program ***/
+
+
+/*
+ * Init some stuff
+ *
+ * XXX XXX XXX Hack -- This function attempts to "fix" the nasty
+ * "Macintosh Save Bug" by using "absolute" path names, since on
+ * System 7 machines anyway, the "current working directory" often
+ * "changes" due to background processes, invalidating any "relative"
+ * path names. Note that the Macintosh is limited to 255 character
+ * path names, so be careful about deeply embedded directories...
+ *
+ * XXX XXX XXX Hack -- This function attempts to "fix" the nasty
+ * "missing lib folder bug" by allowing the user to help find the
+ * "lib" folder by hand if the "application folder" code fails...
+ *
+ *
+ * The problem description above no longer applies, but I left it here,
+ * modified for Carbon, to allow the game proceeds when a user doesn't
+ * placed the Angband binary and the lib folder in the same place for
+ * whatever reasons. -- pelpel
+ */
+static void init_stuff(void)
+{
+ Rect r;
+ BitMap tBitMap;
+ Rect screenRect;
+ Point topleft;
+
+ char path[1024];
+
+ OSErr err = noErr;
+ NavDialogOptions dialogOptions;
+ FSSpec theFolderSpec;
+ NavReplyRecord theReply;
+
+
+ /* Fake rectangle */
+ r.left = 0;
+ r.top = 0;
+ r.right = 344;
+ r.bottom = 188;
+
+ /* Center it */
+ screenRect = GetQDGlobalsScreenBits(&tBitMap)->bounds;
+ center_rect(&r, &screenRect);
+
+ /* Extract corner */
+ topleft.v = r.top;
+ topleft.h = r.left;
+
+ /* Default to the "lib" folder with the application */
+#ifdef MACH_O_CARBON
+ if (locate_lib(path, sizeof(path)) == NULL) quit(NULL);
+#else
+ refnum_to_name(path, app_dir, app_vol, (char*)("\plib:"));
+#endif
+
+
+ /* Check until done */
+ while (1)
+ {
+ /* Prepare the paths */
+ init_file_paths(path);
+
+ /* Build the filename */
+ path_build(path, 1024, ANGBAND_DIR_FILE, "news.txt");
+
+ /* Attempt to open and close that file */
+ if (0 == fd_close(fd_open(path, O_RDONLY))) break;
+
+ /* Warning */
+ plog_fmt("Unable to open the '%s' file.", path);
+
+ /* Warning */
+ plog("The Angband 'lib' folder is probably missing or misplaced.");
+
+ /* Ask the user to choose the lib folder */
+ err = NavGetDefaultDialogOptions(&dialogOptions);
+
+ /* Paranoia */
+ if (err != noErr) quit(NULL);
+
+ /* Set default location option */
+ dialogOptions.dialogOptionFlags |= kNavSelectDefaultLocation;
+
+ /* Clear preview option */
+ dialogOptions.dialogOptionFlags &= ~(kNavAllowPreviews);
+
+ /* Forbit selection of multiple files */
+ dialogOptions.dialogOptionFlags &= ~(kNavAllowMultipleFiles);
+
+ /* Display location */
+ dialogOptions.location = topleft;
+
+#if 0
+
+ /* Load the message for the missing folder from the resource fork */
+ /* GetIndString(dialogOptions.message, 128, 1); */
+
+#else
+
+ /* Set the message for the missing folder XXX XXX */
+ strcpy(dialogOptions.message + 1, "Please select the \"lib\" folder");
+ dialogOptions.message[0] = strlen(dialogOptions.message + 1);
+
+#endif
+
+ /* Wait for the user to choose a folder */
+ err = NavChooseFolder(
+ nil, &theReply, &dialogOptions, nil, nil, nil);
+
+ /* Assume the player doesn't want to go on */
+ if ((err != noErr) || !theReply.validRecord) quit(NULL);
+
+ /* Retrieve FSSpec from the reply */
+ {
+ AEKeyword theKeyword;
+ DescType actualType;
+ Size actualSize;
+
+ /* Get a pointer to selected folder */
+ err = AEGetNthPtr(
+ &(theReply.selection), 1, typeFSS, &theKeyword,
+ &actualType, &theFolderSpec, sizeof(FSSpec), &actualSize);
+
+ /* Paranoia */
+ if (err != noErr) quit(NULL);
+ }
+
+ /* Free navitagor reply */
+ err = NavDisposeReply(&theReply);
+
+ /* Paranoia */
+ if (err != noErr) quit(NULL);
+
+ /* Extract textual file name for given file */
+#ifdef MACH_O_CARBON
+ if (spec_to_path(&theFolderSpec, path, sizeof(path)) != noErr)
+ {
+ quit(NULL);
+ }
+#else /* MACH_O_CARBON */
+refnum_to_name(
+ path,
+ theFolderSpec.parID,
+ theFolderSpec.vRefNum,
+ (char *)theFolderSpec.name);
+#endif /* MACH_O_CARBON */
+ }
+}
+
+
+/*
+ * Macintosh Main loop
+ */
+int main(void)
+{
+ int i;
+ long response;
+ OSStatus err;
+ EventRecord tempEvent;
+ UInt32 numberOfMasters = 10;
+
+ /* Get more Masters -- it is not recommended by Apple, should go away */
+ MoreMasterPointers(numberOfMasters);
+
+ /* Check for existence of Carbon */
+ err = Gestalt(gestaltCarbonVersion, &response);
+
+ if (err != noErr) quit("This program requires Carbon API");
+
+ /* See if we are running on Aqua */
+ err = Gestalt(gestaltMenuMgrAttr, &response);
+
+ /* Cache the result */
+ if ((err == noErr) &&
+ (response & gestaltMenuMgrAquaLayoutMask)) is_aqua = TRUE;
+
+ /*
+ * Remember Mac OS version, in case we have to cope with version-specific
+ * problems
+ */
+ (void)Gestalt(gestaltSystemVersion, &mac_os_version);
+
+
+ /* Set up the Macintosh */
+ InitCursor();
+
+ /* Flush events */
+ FlushEvents(everyEvent, 0);
+
+ /* Flush events some more (?) */
+ if (EventAvail(everyEvent, &tempEvent)) FlushEvents(everyEvent, 0);
+
+
+ /* Install the start event hook (ignore error codes) */
+ AEInstallEventHandler(
+ kCoreEventClass,
+ kAEOpenApplication,
+ NewAEEventHandlerUPP(AEH_Start),
+ 0L,
+ FALSE);
+
+ /* Install the quit event hook (ignore error codes) */
+ AEInstallEventHandler(
+ kCoreEventClass,
+ kAEQuitApplication,
+ NewAEEventHandlerUPP(AEH_Quit),
+ 0L,
+ FALSE);
+
+ /* Install the print event hook (ignore error codes) */
+ AEInstallEventHandler(
+ kCoreEventClass,
+ kAEPrintDocuments,
+ NewAEEventHandlerUPP(AEH_Print),
+ 0L,
+ FALSE);
+
+ /* Install the open event hook (ignore error codes) */
+ AEInstallEventHandler(
+ kCoreEventClass,
+ kAEOpenDocuments,
+ NewAEEventHandlerUPP(AEH_Open),
+ 0L,
+ FALSE);
+
+
+#ifndef MACH_O_CARBON
+
+ /* Find the current application */
+ SetupAppDir();
+
+#endif /* !MACH_O_CARBON */
+
+ /* Mark ourself as the file creator */
+ _fcreator = ANGBAND_CREATOR;
+
+ /* Default to saving a "text" file */
+ _ftype = 'TEXT';
+
+
+ /* Hook in some "z-virt.c" hooks */
+ rnfree_aux = hook_rnfree;
+ ralloc_aux = hook_ralloc;
+ rpanic_aux = hook_rpanic;
+
+ /* Hooks in some "z-util.c" hooks */
+ plog_aux = hook_plog;
+ quit_aux = hook_quit;
+ core_aux = hook_core;
+
+
+ /* Initialize colors */
+ for (i = 0; i < 256; i++)
+ {
+ u16b rv, gv, bv;
+
+ /* Extract the R,G,B data */
+ rv = angband_color_table[i][1];
+ gv = angband_color_table[i][2];
+ bv = angband_color_table[i][3];
+
+ /* Save the actual color */
+ color_info[i].red = (rv | (rv << 8));
+ color_info[i].green = (gv | (gv << 8));
+ color_info[i].blue = (bv | (bv << 8));
+ }
+
+
+ /* Show the "watch" cursor */
+ SetCursor(*(GetCursor(watchCursor)));
+
+ /* Prepare the menubar */
+ init_menubar();
+
+ /* Prepare the windows */
+ init_windows();
+
+ /* Hack -- process all events */
+ while (CheckEvents(FALSE)) /* loop */;
+
+ /* Reset the cursor */
+ {
+ Cursor tempCursor;
+
+ SetCursor(GetQDGlobalsArrow(&tempCursor));
+ }
+
+ /* Mega-Hack -- Allocate a "lifeboat" */
+ lifeboat = NewPtr(16384);
+
+#ifdef USE_QT_SOUND
+
+ /* Load sound effect resources */
+ load_sounds();
+
+#endif /* USE_QT_SOUND */
+
+ /* Note the "system" */
+ ANGBAND_SYS = "mac";
+
+ if (check_create_user_dir() == FALSE)
+ quit("Cannot create directory " PRIVATE_USER_PATH);
+
+ /* Initialize */
+ init_stuff();
+
+ /* Initialize */
+ init_angband();
+
+
+ /* Hack -- process all events */
+ while (CheckEvents(FALSE)) /* loop */;
+
+
+ /* We are now initialized */
+ initialized = TRUE;
+
+
+ /* Handle "open_when_ready" */
+ handle_open_when_ready();
+
+#ifndef SAVEFILE_SCREEN
+
+ /* Prompt the user - You may have to change this for some variants */
+ prt("[Choose 'New' or 'Open' from the 'File' menu]", 23, 15);
+
+ /* Flush the prompt */
+ Term_fresh();
+
+ /* Hack -- Process Events Forever */
+ while (TRUE) CheckEvents(TRUE);
+
+#else
+
+ /* Game is in progress */
+ game_in_progress = 1;
+
+ /* Wait for keypress */
+ pause_line(23);
+
+ /* flush input - Warning: without this, _system_ would hang */
+ flush();
+
+ /* Play the game - note the value of the argument */
+ play_game(FALSE);
+
+ /* Quit */
+ quit(NULL);
+
+ /* Since it's a int function */
+ return (0);
+#endif /* !SAVEFILE_SCREEN */
+}
+
+#endif /* MACINTOSH || MACH_O_CARBON */
+
diff --git a/src/main-gcu.c b/src/main-gcu.c
new file mode 100644
index 00000000..57c41703
--- /dev/null
+++ b/src/main-gcu.c
@@ -0,0 +1,1222 @@
+/* File: main-gcu.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison, and others
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+
+/*
+ * This file helps Angband run on Unix/Curses machines.
+ *
+ *
+ * To use this file, you must define "USE_GCU" in the Makefile.
+ *
+ *
+ * Note that this file is not "intended" to support non-Unix machines,
+ * nor is it intended to support VMS or other bizarre setups.
+ *
+ * Also, this package assumes that the underlying "curses" handles both
+ * the "nonl()" and "cbreak()" commands correctly, see the "OPTION" below.
+ *
+ * This code should work with most versions of "curses" or "ncurses",
+ * and the "main-ncu.c" file (and USE_NCU define) are no longer used.
+ *
+ * This file provides up to 4 term windows.
+ *
+ * This file will attempt to redefine the screen colors to conform to
+ * standard Angband colors. It will only do so if the terminal type
+ * indicates that it can do so. See the page:
+ *
+ * http://www.umr.edu/~keldon/ang-patch/ncurses_color.html
+ *
+ * for information on this.
+ *
+ * Consider the use of "savetty()" and "resetty()". XXX XXX XXX
+ */
+
+
+#include "angband.h"
+
+
+#ifdef USE_GCU
+
+#include <limits.h>
+
+/*
+ * Hack -- play games with "bool" and "term"
+ */
+#undef bool
+
+/* Avoid 'struct term' name conflict with <curses.h> (via <term.h>) on AIX */
+#define term System_term
+
+/*
+ * Include the proper "header" file
+ */
+#ifdef USE_NCURSES
+# include <ncurses.h>
+#else
+# include <curses.h>
+#endif
+
+#undef term
+
+/*
+ * Try redefining the colors at startup.
+ */
+#define REDEFINE_COLORS
+
+
+/*
+ * Hack -- try to guess which systems use what commands
+ * Hack -- allow one of the "USE_Txxxxx" flags to be pre-set.
+ * Mega-Hack -- try to guess when "POSIX" is available.
+ * If the user defines two of these, we will probably crash.
+ */
+#if !defined(USE_TPOSIX)
+# if !defined(USE_TERMIO) && !defined(USE_TCHARS)
+# if defined(_POSIX_VERSION)
+# define USE_TPOSIX
+# else
+# if defined(USG) || defined(linux) || defined(SOLARIS)
+# define USE_TERMIO
+# else
+# define USE_TCHARS
+# endif
+# endif
+# endif
+#endif
+
+/*
+ * POSIX stuff
+ */
+#ifdef USE_TPOSIX
+# include <sys/ioctl.h>
+# include <termios.h>
+#endif
+
+/*
+ * One version needs these files
+ */
+#ifdef USE_TERMIO
+# include <sys/ioctl.h>
+# include <termio.h>
+#endif
+
+/*
+ * The other needs these files
+ */
+#ifdef USE_TCHARS
+# include <sys/ioctl.h>
+# include <sys/resource.h>
+# include <sys/param.h>
+# include <sys/file.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+/* /me pffts Solaris */
+#ifndef NAME_MAX
+#define NAME_MAX _POSIX_NAME_MAX
+#endif
+
+
+
+/*
+ * XXX XXX Hack -- POSIX uses "O_NONBLOCK" instead of "O_NDELAY"
+ *
+ * They should both work due to the "(i != 1)" test below.
+ */
+#ifndef O_NDELAY
+# define O_NDELAY O_NONBLOCK
+#endif
+
+
+/*
+ * OPTION: some machines lack "cbreak()"
+ * On these machines, we use an older definition
+ */
+/* #define cbreak() crmode() */
+
+
+/*
+ * OPTION: some machines cannot handle "nonl()" and "nl()"
+ * On these machines, we can simply ignore those commands.
+ */
+/* #define nonl() */
+/* #define nl() */
+
+
+/*
+ * Save the "normal" and "angband" terminal settings
+ */
+
+#ifdef USE_TPOSIX
+
+static struct termios norm_termios;
+
+static struct termios game_termios;
+
+#endif
+
+#ifdef USE_TERMIO
+
+static struct termio norm_termio;
+
+static struct termio game_termio;
+
+#endif
+
+#ifdef USE_TCHARS
+
+static struct ltchars norm_special_chars;
+static struct sgttyb norm_ttyb;
+static struct tchars norm_tchars;
+static int norm_local_chars;
+
+static struct ltchars game_special_chars;
+static struct sgttyb game_ttyb;
+static struct tchars game_tchars;
+static int game_local_chars;
+
+#endif
+
+/*
+ * Information about a term
+ */
+typedef struct term_data term_data;
+
+struct term_data
+{
+ term t; /* All term info */
+
+ WINDOW *win; /* Pointer to the curses window */
+};
+
+/* Max number of windows on screen */
+#define MAX_TERM_DATA 4
+
+/* Information about our windows */
+static term_data data[MAX_TERM_DATA];
+
+
+/*
+ * Hack -- Number of initialized "term" structures
+ */
+static int active = 0;
+
+
+#ifdef A_COLOR
+
+/*
+ * Hack -- define "A_BRIGHT" to be "A_BOLD", because on many
+ * machines, "A_BRIGHT" produces ugly "inverse" video.
+ */
+#ifndef A_BRIGHT
+# define A_BRIGHT A_BOLD
+#endif
+
+/*
+ * Software flag -- we are allowed to use color
+ */
+static int can_use_color = FALSE;
+
+/*
+ * Software flag -- we are allowed to change the colors
+ */
+static int can_fix_color = FALSE;
+
+/*
+ * Simple Angband to Curses color conversion table
+ */
+static int colortable[16];
+
+#endif
+
+
+
+/*
+ * Place the "keymap" into its "normal" state
+ */
+static void keymap_norm(void)
+{
+
+#ifdef USE_TPOSIX
+
+ /* restore the saved values of the special chars */
+ (void)tcsetattr(0, TCSAFLUSH, &norm_termios);
+
+#endif
+
+#ifdef USE_TERMIO
+
+ /* restore the saved values of the special chars */
+ (void)ioctl(0, TCSETA, (char *)&norm_termio);
+
+#endif
+
+#ifdef USE_TCHARS
+
+ /* restore the saved values of the special chars */
+ (void)ioctl(0, TIOCSLTC, (char *)&norm_special_chars);
+ (void)ioctl(0, TIOCSETP, (char *)&norm_ttyb);
+ (void)ioctl(0, TIOCSETC, (char *)&norm_tchars);
+ (void)ioctl(0, TIOCLSET, (char *)&norm_local_chars);
+
+#endif
+
+}
+
+
+/*
+ * Place the "keymap" into the "game" state
+ */
+static void keymap_game(void)
+{
+
+#ifdef USE_TPOSIX
+
+ /* restore the saved values of the special chars */
+ (void)tcsetattr(0, TCSAFLUSH, &game_termios);
+
+#endif
+
+#ifdef USE_TERMIO
+
+ /* restore the saved values of the special chars */
+ (void)ioctl(0, TCSETA, (char *)&game_termio);
+
+#endif
+
+#ifdef USE_TCHARS
+
+ /* restore the saved values of the special chars */
+ (void)ioctl(0, TIOCSLTC, (char *)&game_special_chars);
+ (void)ioctl(0, TIOCSETP, (char *)&game_ttyb);
+ (void)ioctl(0, TIOCSETC, (char *)&game_tchars);
+ (void)ioctl(0, TIOCLSET, (char *)&game_local_chars);
+
+#endif
+
+}
+
+
+/*
+ * Save the normal keymap
+ */
+static void keymap_norm_prepare(void)
+{
+
+#ifdef USE_TPOSIX
+
+ /* Get the normal keymap */
+ tcgetattr(0, &norm_termios);
+
+#endif
+
+#ifdef USE_TERMIO
+
+ /* Get the normal keymap */
+ (void)ioctl(0, TCGETA, (char *)&norm_termio);
+
+#endif
+
+#ifdef USE_TCHARS
+
+ /* Get the normal keymap */
+ (void)ioctl(0, TIOCGETP, (char *)&norm_ttyb);
+ (void)ioctl(0, TIOCGLTC, (char *)&norm_special_chars);
+ (void)ioctl(0, TIOCGETC, (char *)&norm_tchars);
+ (void)ioctl(0, TIOCLGET, (char *)&norm_local_chars);
+
+#endif
+
+}
+
+
+/*
+ * Save the keymaps (normal and game)
+ */
+static void keymap_game_prepare(void)
+{
+
+#ifdef USE_TPOSIX
+
+ /* Acquire the current mapping */
+ tcgetattr(0, &game_termios);
+
+ /* Force "Ctrl-C" to interupt */
+ game_termios.c_cc[VINTR] = (char)3;
+
+ /* Force "Ctrl-Z" to suspend */
+ game_termios.c_cc[VSUSP] = (char)26;
+
+ /* Hack -- Leave "VSTART/VSTOP" alone */
+
+ /* Disable the standard control characters */
+ game_termios.c_cc[VQUIT] = (char) - 1;
+ game_termios.c_cc[VERASE] = (char) - 1;
+ game_termios.c_cc[VKILL] = (char) - 1;
+ game_termios.c_cc[VEOF] = (char) - 1;
+ game_termios.c_cc[VEOL] = (char) - 1;
+
+ /* Normally, block until a character is read */
+ game_termios.c_cc[VMIN] = 1;
+ game_termios.c_cc[VTIME] = 0;
+
+#endif
+
+#ifdef USE_TERMIO
+
+ /* Acquire the current mapping */
+ (void)ioctl(0, TCGETA, (char *)&game_termio);
+
+ /* Force "Ctrl-C" to interupt */
+ game_termio.c_cc[VINTR] = (char)3;
+
+ /* Force "Ctrl-Z" to suspend */
+ game_termio.c_cc[VSUSP] = (char)26;
+
+ /* Hack -- Leave "VSTART/VSTOP" alone */
+
+ /* Disable the standard control characters */
+ game_termio.c_cc[VQUIT] = (char) - 1;
+ game_termio.c_cc[VERASE] = (char) - 1;
+ game_termio.c_cc[VKILL] = (char) - 1;
+ game_termio.c_cc[VEOF] = (char) - 1;
+ game_termio.c_cc[VEOL] = (char) - 1;
+
+ /* Normally, block until a character is read */
+ game_termio.c_cc[VMIN] = 1;
+ game_termio.c_cc[VTIME] = 0;
+
+#endif
+
+#ifdef USE_TCHARS
+
+ /* Get the default game characters */
+ (void)ioctl(0, TIOCGETP, (char *)&game_ttyb);
+ (void)ioctl(0, TIOCGLTC, (char *)&game_special_chars);
+ (void)ioctl(0, TIOCGETC, (char *)&game_tchars);
+ (void)ioctl(0, TIOCLGET, (char *)&game_local_chars);
+
+ /* Force suspend (^Z) */
+ game_special_chars.t_suspc = (char)26;
+
+ /* Cancel some things */
+ game_special_chars.t_dsuspc = (char) - 1;
+ game_special_chars.t_rprntc = (char) - 1;
+ game_special_chars.t_flushc = (char) - 1;
+ game_special_chars.t_werasc = (char) - 1;
+ game_special_chars.t_lnextc = (char) - 1;
+
+ /* Force interupt (^C) */
+ game_tchars.t_intrc = (char)3;
+
+ /* Force start/stop (^Q, ^S) */
+ game_tchars.t_startc = (char)17;
+ game_tchars.t_stopc = (char)19;
+
+ /* Cancel some things */
+ game_tchars.t_quitc = (char) - 1;
+ game_tchars.t_eofc = (char) - 1;
+ game_tchars.t_brkc = (char) - 1;
+
+#endif
+
+}
+
+
+
+
+/*
+ * Suspend/Resume
+ */
+static errr Term_xtra_gcu_alive(int v)
+{
+ int x, y;
+
+
+ /* Suspend */
+ if (!v)
+ {
+ /* Go to normal keymap mode */
+ keymap_norm();
+
+ /* Restore modes */
+ nocbreak();
+ echo();
+ nl();
+
+ /* Hack -- make sure the cursor is visible */
+ Term_xtra(TERM_XTRA_SHAPE, 1);
+
+ /* Flush the curses buffer */
+ (void)refresh();
+
+ /* Get current cursor position */
+ getyx(curscr, y, x);
+
+ /* Move the cursor to bottom right corner */
+ mvcur(y, x, LINES - 1, 0);
+
+ /* Exit curses */
+ endwin();
+
+ /* Flush the output */
+ (void)fflush(stdout);
+ }
+
+ /* Resume */
+ else
+ {
+ /* Refresh */
+ /* (void)touchwin(curscr); */
+ /* (void)wrefresh(curscr); */
+
+ /* Restore the settings */
+ cbreak();
+ noecho();
+ nonl();
+
+ /* Go to angband keymap mode */
+ keymap_game();
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Init the "curses" system
+ */
+static void Term_init_gcu(term *t)
+{
+ term_data *td = (term_data *)(t->data);
+
+ /* Count init's, handle first */
+ if (active++ != 0) return;
+
+ /* Erase the window */
+ (void)wclear(td->win);
+
+ /* Reset the cursor */
+ (void)wmove(td->win, 0, 0);
+
+ /* Flush changes */
+ (void)wrefresh(td->win);
+
+ /* Game keymap */
+ keymap_game();
+}
+
+
+/*
+ * Nuke the "curses" system
+ */
+static void Term_nuke_gcu(term *t)
+{
+ int x, y;
+ term_data *td = (term_data *)(t->data);
+
+ /* Delete this window */
+ delwin(td->win);
+
+ /* Count nuke's, handle last */
+ if (--active != 0) return;
+
+ /* Hack -- make sure the cursor is visible */
+ Term_xtra(TERM_XTRA_SHAPE, 1);
+
+#ifdef A_COLOR
+ /* Reset colors to defaults */
+ start_color();
+#endif
+
+ /* Get current cursor position */
+ getyx(curscr, y, x);
+
+ /* Move the cursor to bottom right corner */
+ mvcur(y, x, LINES - 1, 0);
+
+ /* Flush the curses buffer */
+ (void)refresh();
+
+ /* Exit curses */
+ endwin();
+
+ /* Flush the output */
+ (void)fflush(stdout);
+
+ /* Normal keymap */
+ keymap_norm();
+}
+
+
+
+
+#ifdef USE_GETCH
+
+/*
+ * Process events, with optional wait
+ */
+static errr Term_xtra_gcu_event(int v)
+{
+ int i, k;
+
+ /* Wait */
+ if (v)
+ {
+ /* Paranoia -- Wait for it */
+ nodelay(stdscr, FALSE);
+
+ /* Get a keypress */
+ i = getch();
+
+ /* Mega-Hack -- allow graceful "suspend" */
+ for (k = 0; (k < 10) && (i == ERR); k++) i = getch();
+
+ /* Broken input is special */
+ if (i == ERR) abort();
+ if (i == EOF) abort();
+ }
+
+ /* Do not wait */
+ else
+ {
+ /* Do not wait for it */
+ nodelay(stdscr, TRUE);
+
+ /* Check for keypresses */
+ i = getch();
+
+ /* Wait for it next time */
+ nodelay(stdscr, FALSE);
+
+ /* None ready */
+ if (i == ERR) return (1);
+ if (i == EOF) return (1);
+ }
+
+ /* Enqueue the keypress */
+ Term_keypress(i);
+
+ /* Success */
+ return (0);
+}
+
+#else /* USE_GETCH */
+
+/*
+* Process events (with optional wait)
+*/
+static errr Term_xtra_gcu_event(int v)
+{
+ int i, k;
+
+ char buf[2];
+
+ /* Wait */
+ if (v)
+ {
+ /* Wait for one byte */
+ i = read(0, buf, 1);
+
+ /* Hack -- Handle bizarre "errors" */
+ if ((i <= 0) && (errno != EINTR)) abort();
+ }
+
+ /* Do not wait */
+ else
+ {
+ /* Get the current flags for stdin */
+ k = fcntl(0, F_GETFL, 0);
+
+ /* Oops */
+ if (k < 0) return (1);
+
+ /* Tell stdin not to block */
+ if (fcntl(0, F_SETFL, k | O_NDELAY) < 0) return (1);
+
+ /* Read one byte, if possible */
+ i = read(0, buf, 1);
+
+ /* Replace the flags for stdin */
+ if (fcntl(0, F_SETFL, k)) return (1);
+ }
+
+ /* Ignore "invalid" keys */
+ if ((i != 1) || (!buf[0])) return (1);
+
+ /* Enqueue the keypress */
+ Term_keypress(buf[0]);
+
+ /* Success */
+ return (0);
+}
+
+#endif /* USE_GETCH */
+
+/*
+ * React to changes
+ */
+static errr Term_xtra_gcu_react(void)
+{
+
+#ifdef A_COLOR
+
+ int i;
+
+ /* Cannot handle color redefinition */
+ if (!can_fix_color) return (0);
+
+ /* Set the colors */
+ for (i = 0; i < 16; i++)
+ {
+ /* Set one color (note scaling) */
+ init_color(i,
+ angband_color_table[i][1] * 1000 / 255,
+ angband_color_table[i][2] * 1000 / 255,
+ angband_color_table[i][3] * 1000 / 255);
+ }
+
+#endif
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Handle a "special request"
+ */
+static errr Term_xtra_gcu(int n, int v)
+{
+ term_data *td = (term_data *)(Term->data);
+
+ /* Analyze the request */
+ switch (n)
+ {
+ /* Clear screen */
+ case TERM_XTRA_CLEAR:
+ touchwin(td->win);
+ (void)wclear(td->win);
+ return (0);
+
+ /* Make a noise */
+ case TERM_XTRA_NOISE:
+ (void)write(1, "\007", 1);
+ return (0);
+
+ /* Flush the Curses buffer */
+ case TERM_XTRA_FRESH:
+ (void)wrefresh(td->win);
+ return (0);
+
+#ifdef USE_CURS_SET
+
+ /* Change the cursor visibility */
+ case TERM_XTRA_SHAPE:
+ curs_set(v);
+ return (0);
+
+#endif
+
+ /* Suspend/Resume curses */
+ case TERM_XTRA_ALIVE:
+ return (Term_xtra_gcu_alive(v));
+
+ /* Process events */
+ case TERM_XTRA_EVENT:
+ return (Term_xtra_gcu_event(v));
+
+ /* Flush events */
+ case TERM_XTRA_FLUSH:
+ while (!Term_xtra_gcu_event(FALSE));
+ return (0);
+
+ /* Delay */
+ case TERM_XTRA_DELAY:
+ usleep(1000 * v);
+ return (0);
+
+ /* Get Delay of some milliseconds */
+ case TERM_XTRA_GET_DELAY:
+ {
+ int ret;
+ struct timeval tv;
+
+ ret = gettimeofday(&tv, NULL);
+ Term_xtra_long = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+
+ return ret;
+ }
+
+ /* Subdirectory scan */
+ case TERM_XTRA_SCANSUBDIR:
+ {
+ DIR *directory;
+ struct dirent *entry;
+
+ scansubdir_max = 0;
+
+ directory = opendir(scansubdir_dir);
+ if (!directory)
+ return 1;
+
+ while ((entry = readdir(directory)))
+ {
+ char file[PATH_MAX + NAME_MAX + 2];
+ struct stat filedata;
+
+ file[PATH_MAX + NAME_MAX] = 0;
+ strncpy(file, scansubdir_dir, PATH_MAX);
+ strncat(file, "/", 2);
+ strncat(file, entry->d_name, NAME_MAX);
+ if (!stat(file, &filedata) && S_ISDIR((filedata.st_mode)))
+ {
+ string_free(scansubdir_result[scansubdir_max]);
+ scansubdir_result[scansubdir_max] = string_make(entry->d_name);
+ ++scansubdir_max;
+ }
+ }
+ }
+
+ /* React to events */
+ case TERM_XTRA_REACT:
+ Term_xtra_gcu_react();
+ return (0);
+ }
+
+ /* Unknown */
+ return (1);
+}
+
+
+/*
+ * Actually MOVE the hardware cursor
+ */
+static errr Term_curs_gcu(int x, int y)
+{
+ term_data *td = (term_data *)(Term->data);
+
+ /* Literally move the cursor */
+ wmove(td->win, y, x);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Erase a grid of space
+ * Hack -- try to be "semi-efficient".
+ */
+static errr Term_wipe_gcu(int x, int y, int n)
+{
+ term_data *td = (term_data *)(Term->data);
+
+ /* Place cursor */
+ wmove(td->win, y, x);
+
+ /* Clear to end of line */
+ if (x + n >= td->t.wid)
+ {
+ wclrtoeol(td->win);
+ }
+
+ /* Clear some characters */
+ else
+ {
+ while (n-- > 0) waddch(td->win, ' ');
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Place some text on the screen using an attribute
+ */
+static errr Term_text_gcu(int x, int y, int n, byte a, cptr s)
+{
+ term_data *td = (term_data *)(Term->data);
+
+ int i, pic;
+
+#ifdef A_COLOR
+ /* Set the color */
+ if (can_use_color) wattrset(td->win, colortable[a & 0x0F]);
+#endif
+
+ /* Move the cursor */
+ wmove(td->win, y, x);
+
+ /* Draw each character */
+ for (i = 0; i < n; i++)
+ {
+#ifdef USE_GRAPHICS
+ /* Special character */
+ if (use_graphics && (s[i] & 0x80))
+ {
+ /* Determine picture to use */
+ switch (s[i] & 0x7F)
+ {
+
+#ifdef ACS_CKBOARD
+ /* Wall */
+ case '#':
+ pic = ACS_CKBOARD;
+ break;
+#endif /* ACS_CKBOARD */
+
+#ifdef ACS_BOARD
+ /* Mineral vein */
+ case '%':
+ pic = ACS_BOARD;
+ break;
+#endif /* ACS_BOARD */
+
+ /* XXX */
+ default:
+ pic = '?';
+ break;
+ }
+
+ /* Draw the picture */
+ waddch(td->win, pic);
+
+ /* Next character */
+ continue;
+ }
+#endif
+
+ /* Draw a normal character */
+ waddch(td->win, (byte)s[i]);
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Create a window for the given "term_data" argument.
+ *
+ * Assumes legal arguments.
+ */
+static errr term_data_init_gcu(term_data *td, int rows, int cols, int y, int x)
+{
+ term *t = &td->t;
+
+ /* Create new window */
+ td->win = newwin(rows, cols, y, x);
+
+ /* Check for failure */
+ if (!td->win)
+ {
+ /* Error */
+ quit("Failed to setup curses window.");
+ }
+
+ /* Initialize the term */
+ term_init(t, cols, rows, 256);
+
+ /* Avoid bottom right corner */
+ t->icky_corner = TRUE;
+
+ /* Erase with "white space" */
+ t->attr_blank = TERM_WHITE;
+ t->char_blank = ' ';
+
+ /* Set some hooks */
+ t->init_hook = Term_init_gcu;
+ t->nuke_hook = Term_nuke_gcu;
+
+ /* Set some more hooks */
+ t->text_hook = Term_text_gcu;
+ t->wipe_hook = Term_wipe_gcu;
+ t->curs_hook = Term_curs_gcu;
+ t->xtra_hook = Term_xtra_gcu;
+
+ /* Save the data */
+ t->data = td;
+
+ /* Activate it */
+ Term_activate(t);
+
+ /* Success */
+ return (0);
+}
+
+
+static void hook_quit(cptr str)
+{
+ /* Unused */
+ (void)str;
+
+ /* Exit curses */
+ endwin();
+}
+
+
+/*
+ * Prepare "curses" for use by the file "z-term.c"
+ *
+ * Installs the "hook" functions defined above, and then activates
+ * the main screen "term", which clears the screen and such things.
+ *
+ * Someone should really check the semantics of "initscr()"
+ */
+errr init_gcu(int argc, char **argv)
+{
+ int i;
+
+ int num_term = MAX_TERM_DATA, next_win = 0;
+
+ bool_ use_big_screen = FALSE;
+
+
+ /* Parse args */
+ for (i = 1; i < argc; i++)
+ {
+ if (prefix(argv[i], "-b"))
+ {
+ use_big_screen = TRUE;
+ continue;
+ }
+
+ plog_fmt("Ignoring option: %s", argv[i]);
+ }
+
+
+ /* Extract the normal keymap */
+ keymap_norm_prepare();
+
+
+#if defined(USG)
+ /* Initialize for USG Unix */
+ if (initscr() == NULL) return ( -1);
+#else
+/* Initialize for other systems */
+ if (initscr() == (WINDOW*)ERR) return ( -1);
+#endif
+
+ /* Activate hooks */
+ quit_aux = hook_quit;
+ core_aux = hook_quit;
+
+ /* Require standard size screen */
+ if ((LINES < 24) || (COLS < 80))
+ {
+ quit("Angband needs at least an 80x24 'curses' screen");
+ }
+
+
+#ifdef USE_GRAPHICS
+
+ /* Set graphics flag */
+ use_graphics = arg_graphics;
+
+#endif
+
+#ifdef A_COLOR
+
+ /*** Init the Color-pairs and set up a translation table ***/
+
+ /* Do we have color, and enough color, available? */
+ can_use_color = ((start_color() != ERR) && has_colors() &&
+ (COLORS >= 8) && (COLOR_PAIRS >= 8));
+
+#ifdef REDEFINE_COLORS
+
+ /* Can we change colors? */
+ can_fix_color = (can_use_color && can_change_color() &&
+ (COLORS >= 16) && (COLOR_PAIRS > 8));
+
+#endif
+
+ /* Attempt to use customized colors */
+ if (can_fix_color)
+ {
+ /* Prepare the color pairs */
+ for (i = 1; i <= 8; i++)
+ {
+ /* Reset the color */
+ if (init_pair(i, i - 1, 0) == ERR)
+ {
+ quit("Color pair init failed");
+ }
+
+ /* Set up the colormap */
+ colortable[i - 1] = (COLOR_PAIR(i) | A_NORMAL);
+ colortable[i + 7] = (COLOR_PAIR(i) | A_BRIGHT);
+ }
+
+ /* Take account of "gamma correction" XXX XXX XXX */
+
+ /* Prepare the "Angband Colors" */
+ Term_xtra_gcu_react();
+ }
+
+ /* Attempt to use colors */
+ else if (can_use_color)
+ {
+ /* Color-pair 0 is *always* WHITE on BLACK */
+
+ /* Prepare the color pairs */
+ init_pair(1, COLOR_RED, COLOR_BLACK);
+ init_pair(2, COLOR_GREEN, COLOR_BLACK);
+ init_pair(3, COLOR_YELLOW, COLOR_BLACK);
+ init_pair(4, COLOR_BLUE, COLOR_BLACK);
+ init_pair(5, COLOR_MAGENTA, COLOR_BLACK);
+ init_pair(6, COLOR_CYAN, COLOR_BLACK);
+ init_pair(7, COLOR_BLACK, COLOR_BLACK);
+
+ /* Prepare the "Angband Colors" -- Bright white is too bright */
+ colortable[0] = (COLOR_PAIR(7) | A_NORMAL); /* Black */
+ colortable[1] = (COLOR_PAIR(0) | A_NORMAL); /* White */
+ colortable[2] = (COLOR_PAIR(6) | A_NORMAL); /* Grey XXX */
+ colortable[3] = (COLOR_PAIR(1) | A_BRIGHT); /* Orange XXX */
+ colortable[4] = (COLOR_PAIR(1) | A_NORMAL); /* Red */
+ colortable[5] = (COLOR_PAIR(2) | A_NORMAL); /* Green */
+ colortable[6] = (COLOR_PAIR(4) | A_NORMAL); /* Blue */
+ colortable[7] = (COLOR_PAIR(3) | A_NORMAL); /* Umber */
+ colortable[8] = (COLOR_PAIR(7) | A_BRIGHT); /* Dark-grey XXX */
+ colortable[9] = (COLOR_PAIR(6) | A_BRIGHT); /* Light-grey XXX */
+ colortable[10] = (COLOR_PAIR(5) | A_NORMAL); /* Purple */
+ colortable[11] = (COLOR_PAIR(3) | A_BRIGHT); /* Yellow */
+ colortable[12] = (COLOR_PAIR(5) | A_BRIGHT); /* Light Red XXX */
+ colortable[13] = (COLOR_PAIR(2) | A_BRIGHT); /* Light Green */
+ colortable[14] = (COLOR_PAIR(4) | A_BRIGHT); /* Light Blue */
+ colortable[15] = (COLOR_PAIR(3) | A_NORMAL); /* Light Umber XXX */
+ }
+
+#endif
+
+
+ /*** Low level preparation ***/
+
+#ifdef USE_GETCH
+
+ /* Paranoia -- Assume no waiting */
+ nodelay(stdscr, FALSE);
+
+#endif
+
+ /* Prepare */
+ cbreak();
+ noecho();
+ nonl();
+
+ /* Extract the game keymap */
+ keymap_game_prepare();
+
+
+ /*** Now prepare the term(s) ***/
+
+ /* Big screen -- one big term */
+ if (use_big_screen)
+ {
+ /* Create a term */
+ term_data_init_gcu(&data[0], LINES, COLS, 0, 0);
+
+ /* Remember the term */
+ angband_term[0] = &data[0].t;
+ }
+
+ /* No big screen -- create as many term windows as possible */
+ else
+ {
+ /* Create several terms */
+ for (i = 0; i < num_term; i++)
+ {
+ int rows, cols, y, x;
+
+ /* Decide on size and position */
+ switch (i)
+ {
+ /* Upper left */
+ case 0:
+ {
+ rows = 24;
+ cols = 80;
+ y = x = 0;
+ break;
+ }
+
+ /* Lower left */
+ case 1:
+ {
+ rows = LINES - 25;
+ cols = 80;
+ y = 25;
+ x = 0;
+ break;
+ }
+
+ /* Upper right */
+ case 2:
+ {
+ rows = 24;
+ cols = COLS - 81;
+ y = 0;
+ x = 81;
+ break;
+ }
+
+ /* Lower right */
+ case 3:
+ {
+ rows = LINES - 25;
+ cols = COLS - 81;
+ y = 25;
+ x = 81;
+ break;
+ }
+
+ /* XXX */
+ default:
+ {
+ rows = cols = y = x = 0;
+ break;
+ }
+ }
+
+ /* Skip non-existant windows */
+ if (rows <= 0 || cols <= 0) continue;
+
+ /* Create a term */
+ term_data_init_gcu(&data[next_win], rows, cols, y, x);
+
+ /* Remember the term */
+ angband_term[next_win] = &data[next_win].t;
+
+ /* One more window */
+ next_win++;
+ }
+ }
+
+ /* Activate the "Angband" window screen */
+ Term_activate(&data[0].t);
+
+ /* Remember the active screen */
+ term_screen = &data[0].t;
+
+ /* Success */
+ return (0);
+}
+
+
+#endif /* USE_GCU */
+
+
diff --git a/src/main-gtk2.c b/src/main-gtk2.c
new file mode 100644
index 00000000..4830638a
--- /dev/null
+++ b/src/main-gtk2.c
@@ -0,0 +1,5026 @@
+/* File: main-gtk.c */
+
+/*
+ * Copyright (c) 2000-2001 Robert Ruehlmann,
+ * Steven Fuerst, Uwe Siems, "pelpel", et al.
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+/*
+ * Robert Ruehlmann wrote the original Gtk port. Since an initial work is
+ * much harder than enhancements, his effort worth more credits than
+ * others.
+ *
+ * Steven Fuerst implemented colour-depth independent X server support,
+ * graphics, resizing and big screen support for ZAngband as well as
+ * fast image rescaling that is included here.
+ *
+ * Uwe Siems wrote smooth tiles rescaling code (on by default).
+ * Try this with 8x8 tiles. They *will* look different.
+ *
+ * "pelpel" wrote another colour-depth independent X support
+ * using GdkRGB, added several hooks and callbacks for various
+ * reasons, wrote no-backing store mode (off by default),
+ * added GtkItemFactory based menu system, introduced
+ * USE_GRAPHICS code bloat (^ ^;), added comments (I have
+ * a strange habit of writing comments while I code...)
+ * and reorganised the file a bit.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Activate variant-specific features
+ *
+ * Angband 2.9.3 and close variants don't require any.
+ *
+ * Angband 2.9.4 alpha and later removed the short-lived
+ * can_save flag, so please #define can_save TRUE, or remove
+ * all the references to it. They also changed long-lived
+ * z-virt macro names. Find C_FREE/C_KILL and replace them
+ * with FREE/KILL, which takes one pointer parameter.
+ *
+ * [Z]-based variants (Gum and Cth, for example) usually need
+ * ANG293_COMPAT, ANG291_COMPAT and ANG281_RESET_VISUALS.
+ *
+ * [O] needs ANG293_COMPAT and ZANG_SAVE_GAME.
+ *
+ * ZAngband has its own enhanced main-gtk.c as mentioned above, and
+ * you *should* use it :-)
+ *
+ */
+#define TOME
+
+#ifdef TOME
+# define ANG293_COMPAT /* Requires V2.9.3 compatibility code */
+# define ANG291_COMPAT /* Requires V2.9.1 compatibility code */
+# define ANG281_RESET_VISUALS /* The old style reset_visuals() */
+# define SAVEFILE_SCREEN /* New/Open integrated into the game */
+# define USE_DOUBLE_TILES /* Mogami's bigtile patch */
+#endif /* TOME */
+
+/*
+ * Some examples
+ */
+#ifdef ANGBAND300
+# define can_save TRUE /* Mimick the short-lived flag */
+# define C_FREE(P, N, T) FREE(P) /* Emulate the long-lived macro */
+#endif /* ANGBAND300 */
+
+#ifdef GUMBAND
+# define ANG293_COMPAT /* Requires V2.9.3 compatibility code */
+# define ANG291_COMPAT /* Requires V2.9.1 compatibility code */
+# define ANG281_RESET_VISUALS /* The old style reset_visuals() */
+# define OLD_SAVEFILE_CODE /* See also SAVEFILE_MUTABLE in files.c */
+# define NO_REDRAW_SECTION /* Doesn't have Term_redraw_section() */
+#endif /* GUMBAND */
+
+#ifdef OANGBAND
+# define ANG293_COMPAT /* Requires V2.9.3 compatibility code */
+# define ZANG_SAVE_GAME /* do_cmd_save_game with auto_save parameter */
+#endif /* OANGBAND */
+
+
+#ifdef USE_GTK2
+
+/* Force ANSI standard */
+/* #define __STRICT_ANSI__ */
+
+/* No GCC-specific includes */
+/* #undef __GNUC__ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+/* /me pffts Solaris */
+#ifndef NAME_MAX
+#define NAME_MAX _POSIX_NAME_MAX
+#endif
+
+
+/*
+ * Include some helpful X11 code.
+ */
+#ifndef ANG293_COMPAT
+# include "maid-x11.h"
+#endif /* !ANG293_COMPAT */
+
+
+/*
+ * Number of pixels inserted between the menu bar and the main screen
+ */
+#define NO_PADDING 0
+
+
+/*
+ * Largest possible number of terminal windows supported by the game
+ */
+#define MAX_TERM_DATA 8
+
+
+/*
+ * Extra data to associate with each "window"
+ *
+ * Each "window" is represented by a "term_data" structure, which
+ * contains a "term" structure, which contains a pointer (t->data)
+ * back to the term_data structure.
+ */
+
+#ifdef USE_GRAPHICS
+
+/*
+ * Since GdkRGB doesn't provide us some useful functions...
+ */
+typedef struct GdkRGBImage GdkRGBImage;
+
+struct GdkRGBImage
+{
+ gint width;
+ gint height;
+ gint ref_count;
+ guchar *image;
+};
+
+#endif /* USE_GRAPHICS */
+
+
+/*
+ * This structure holds everything you need to manipulate terminals
+ */
+typedef struct term_data term_data;
+
+struct term_data
+{
+ term t;
+
+ GtkWidget *window;
+ GtkWidget *drawing_area;
+ GdkPixmap *backing_store;
+ GdkFont *font;
+ GdkGC *gc;
+
+ bool_ shown;
+ byte last_attr;
+
+ int font_wid;
+ int font_hgt;
+
+ int rows;
+ int cols;
+
+#ifdef USE_GRAPHICS
+
+ int tile_wid;
+ int tile_hgt;
+
+ GdkRGBImage *tiles;
+ guint32 bg_pixel;
+ GdkRGBImage *trans_buf;
+
+#endif /* USE_GRAPHICS */
+
+ cptr name;
+};
+
+
+/*
+ * Where to draw when we call Gdk drawing primitives
+ */
+# define TERM_DATA_DRAWABLE(td) \
+((td)->backing_store ? (td)->backing_store : (td)->drawing_area->window)
+
+# define TERM_DATA_REFRESH(td, x, y, wid, hgt) \
+if ((td)->backing_store) gdk_draw_pixmap( \
+(td)->drawing_area->window, \
+(td)->gc, \
+(td)->backing_store, \
+(x) * (td)->font_wid, \
+(y) * (td)->font_hgt, \
+(x) * (td)->font_wid, \
+(y) * (td)->font_hgt, \
+(wid) * (td)->font_wid, \
+(hgt) * (td)->font_hgt)
+
+
+#if 0
+
+/* Compile time option version */
+
+# ifdef USE_BACKING_STORE
+
+# define TERM_DATA_DRAWABLE(td) (td)->backing_store
+
+# define TERM_DATA_REFRESH(td, x, y, wid, hgt) \
+gdk_draw_pixmap( \
+(td)->drawing_area->window, \
+(td)->gc, \
+(td)->backing_store, \
+(x) * (td)->font_wid, \
+(y) * (td)->font_hgt, \
+(x) * (td)->font_wid, \
+(y) * (td)->font_hgt, \
+(wid) * (td)->font_wid, \
+(hgt) * (td)->font_hgt)
+
+# else /* USE_BACKING_STORE */
+
+# define TERM_DATA_DRAWABLE(td) (td)->drawing_area->window
+# define TERM_DATA_REFRESH(td, x, y, wid, hgt)
+
+# endif /* USE_BACKING_STORE */
+
+#endif /* 0 */
+
+
+/*
+ * An array of "term_data" structures, one for each "sub-window"
+ */
+static term_data data[MAX_TERM_DATA];
+
+/*
+ * Number of active terms
+ */
+static int num_term = 1;
+
+
+/*
+ * RGB values of the sixteen Angband colours
+ */
+static guint32 angband_colours[16];
+
+
+/*
+ * Set to TRUE when a game is in progress
+ */
+static bool_ game_in_progress = FALSE;
+
+
+/*
+ * This is in some cases used for double buffering as well as
+ * a backing store, speeding things up under client-server
+ * configurations, while turning this off *might* work better
+ * with the MIT Shm extention which is usually active if you run
+ * Angband locally, because it reduces amount of memory-to-memory copy.
+ */
+static bool_ use_backing_store = TRUE;
+
+
+
+
+/**** Vanilla compatibility functions ****/
+
+#ifdef ANG293_COMPAT
+
+/*
+ * Look up some environment variables to find font name for each window.
+ */
+static cptr get_default_font(int term)
+{
+ char buf[64];
+ cptr font_name;
+
+ /* Window specific font name */
+ strnfmt(buf, 64, "ANGBAND_X11_FONT_%s", angband_term_name[term]);
+
+ /* Check environment for that font */
+ font_name = getenv(buf);
+
+ /* Window specific font name */
+ strnfmt(buf, 64, "ANGBAND_X11_FONT_%d", term);
+
+ /* Check environment for that font */
+ if (!font_name) font_name = getenv(buf);
+
+ /* Check environment for "base" font */
+ if (!font_name) font_name = getenv("ANGBAND_X11_FONT");
+
+ /* No environment variables, use default font */
+ if (!font_name) font_name = DEFAULT_X11_FONT_SCREEN;
+
+ return (font_name);
+}
+
+
+# ifndef SAVEFILE_SCREEN
+
+/*
+ * In [V]2.9.3, this frees all dynamically allocated memory
+ */
+static void cleanup_angband(void)
+{
+ /* XXX XXX XXX */
+}
+
+# endif /* !SAVEFILE_SCREEN */
+
+/*
+ * New global flag to indicate if it's safe to save now
+ */
+#define can_save TRUE
+
+#endif /* ANG293_COMPAT */
+
+
+#ifdef ANG291_COMPAT
+
+/*
+ * The standard game uses this to implement lighting effects
+ * for 16x16 tiles in cave.c...
+ *
+ * Because of the way it is implemented in X11 ports,
+ * we can set this to TRUE even if we are using the 8x8 tileset.
+ */
+static bool_ use_transparency = TRUE;
+
+#endif /* ANG291_COMPAT */
+
+
+
+
+/**** Low level routines - memory allocation ****/
+
+/*
+ * Hook to "release" memory
+ */
+#ifdef ANGBAND300
+static vptr hook_rnfree(vptr v)
+#else
+static vptr hook_rnfree(vptr v, huge size)
+#endif /* ANGBAND300 */
+{
+ /* Dispose */
+ g_free(v);
+
+ /* Success */
+ return (NULL);
+}
+
+
+/*
+ * Hook to "allocate" memory
+ */
+static vptr hook_ralloc(huge size)
+{
+ /* Make a new pointer */
+ return (g_malloc(size));
+}
+
+
+
+/**** Low level routines - colours and graphics ****/
+
+
+/*
+ * Remeber RGB values for sixteen Angband colours, in a format
+ * that is convinient for GdkRGB GC functions.
+ *
+ * XXX XXX Duplication of maid-x11.c is far from the Angband
+ * ideal of code cleanliness, but the whole point of using GdkRGB
+ * is to let it handle colour allocation which it does in a very
+ * clever fashion. Ditto for the tile scaling code and the BMP loader
+ * below.
+ */
+static void init_colours(void)
+{
+ int i;
+
+
+ /* Process each colour */
+ for (i = 0; i < 16; i++)
+ {
+ u32b red, green, blue;
+
+ /* Retrieve RGB values from the game */
+ red = angband_color_table[i][1];
+ green = angband_color_table[i][2];
+ blue = angband_color_table[i][3];
+
+ /* Remember a GdkRGB value, that is 0xRRGGBB */
+ angband_colours[i] = (red << 16) | (green << 8) | blue;
+ }
+}
+
+
+/*
+ * Set foreground colour of window td to attr, only when it is necessary
+ */
+static void term_data_set_fg(term_data *td, byte attr)
+{
+ /* We can use the current gc */
+ if (td->last_attr == attr) return;
+
+ /* Activate the colour */
+ gdk_rgb_gc_set_foreground(td->gc, angband_colours[attr]);
+
+ /* Remember it */
+ td->last_attr = attr;
+}
+
+
+#ifdef USE_GRAPHICS
+
+/*
+ * Graphics mode selector - current setting and requested value
+ */
+#define GRAF_MODE_NONE 0
+#define GRAF_MODE_OLD 1
+#define GRAF_MODE_NEW 2
+
+static int graf_mode = GRAF_MODE_NONE;
+static int graf_mode_request = GRAF_MODE_NONE;
+
+/*
+ * Use smooth rescaling?
+ */
+static bool_ smooth_rescaling = TRUE;
+static bool_ smooth_rescaling_request = TRUE;
+
+/*
+ * Dithering
+ */
+static GdkRgbDither dith_mode = GDK_RGB_DITHER_NORMAL;
+
+/*
+ * Need to reload and resize tiles when fonts are changed.
+ */
+static bool_ resize_request = FALSE;
+
+/*
+ * Numbers of columns and rows in current tileset
+ * calculated and set by the tile loading code in graf_init()
+ * and used by Term_pict_gtk()
+ */
+static int tile_rows;
+static int tile_cols;
+
+
+/*
+ * Directory name(s)
+ */
+static cptr ANGBAND_DIR_XTRA_GRAF;
+
+
+/*
+ * Be nice to old graphics hardwares -- using GdkRGB.
+ *
+ * We don't have colour allocation failure any longer this way,
+ * even with 8bpp X servers. Gimp *does* work with 8bpp, why not Angband?
+ *
+ * Initialisation (before any widgets are created)
+ * gdk_rgb_init();
+ * gtk_widget_set_default_colormap (gdk_rgb_get_cmap());
+ * gtk_widget_set_default_visual (gdk_rgb_get_visual());
+ *
+ * Setting fg/bg colours
+ * void gdk_rgb_gc_set_foreground(GdkGC *gc, guint32 rgb);
+ * void gdk_rgb_gc_set_background(GdkGC *gc, guint32 rgb);
+ * where rgb is 0xRRGGBB.
+ *
+ * Drawing rgb images
+ * void gdk_draw_rgb_image(
+ * GdkDrawable *drawable,
+ * GdkGC *gc,
+ * gint x, gint y,
+ * gint width, gint height,
+ * GdkRgbDither dith,
+ * guchar *rgb_buf,
+ * gint rowstride);
+ *
+ * dith:
+ * GDK_RGB_DITHER_NORMAL : dither if 8bpp or below
+ * GDK_RGB_DITHER_MAX : dither if 16bpp or below.
+ *
+ * for 0 <= i < width and 0 <= j < height,
+ * the pixel (x + i, y + j) is colored with
+ * red value rgb_buf[j * rowstride + i * 3],
+ * green value rgb_buf[j * rowstride + i * 3 + 1], and
+ * blue value rgb_buf[j * rowstride + i * 3 + 2].
+ */
+
+/*
+ * gdk_image compatibility functions - should be part of gdk, IMHO.
+ */
+
+/*
+ * Create GdkRGBImage of width * height and return pointer
+ * to it. Returns NULL on failure
+ */
+static GdkRGBImage *gdk_rgb_image_new(
+ gint width,
+ gint height)
+{
+ GdkRGBImage *result;
+
+ /* Allocate a struct */
+ result = g_new(GdkRGBImage, 1);
+
+ /* Oops */
+ if (result == NULL) return (NULL);
+
+ /* Allocate buffer */
+ result->image = g_new0(guchar, width * height * 3);
+
+ /* Oops */
+ if (result->image == NULL)
+ {
+ g_free(result);
+ return (NULL);
+ }
+
+ /* Initialise size fields */
+ result->width = width;
+ result->height = height;
+
+ /* Initialise reference count */
+ result->ref_count = 1;
+
+ /* Success */
+ return (result);
+}
+
+/*
+ * Free a GdkRGBImage
+ */
+static void gdk_rgb_image_destroy(
+ GdkRGBImage *im)
+{
+ /* Paranoia */
+ if (im == NULL) return;
+
+ /* Free the RGB buffer */
+ g_free(im->image);
+
+ /* Free the structure */
+ g_free(im);
+}
+
+
+#if 0
+
+/*
+ * Unref a GdkRGBImage
+ */
+static void gdk_rgb_image_unref(
+ GdkRGBImage *im)
+{
+ /* Paranoia */
+ g_return_if_fail(im != NULL);
+
+ /* Decrease reference count by 1 */
+ im->ref_count--;
+
+ /* Free if nobody's using it */
+ if (im->ref_count <= 0) gdk_rgb_image_destroy(im);
+}
+
+
+/*
+ * Reference a GdkRGBImage
+ */
+static void gdk_rgb_image_ref(
+ GdkRGBImage *im)
+{
+ /* Paranoia */
+ g_return_if_fail(im != NULL);
+
+ /* Increase reference count by 1 */
+ im->ref_count++;
+}
+
+#endif /* 0 */
+
+
+/*
+ * Write RGB pixel of the format 0xRRGGBB to (x, y) in GdkRGBImage
+ */
+static void gdk_rgb_image_put_pixel(
+ GdkRGBImage *im,
+ gint x,
+ gint y,
+ guint32 pixel)
+{
+ guchar *rgbp;
+
+ /* Paranoia */
+ g_return_if_fail(im != NULL);
+
+ /* Paranoia */
+ if ((x < 0) || (x >= im->width)) return;
+
+ /* Paranoia */
+ if ((y < 0) || (y >= im->height)) return;
+
+ /* Access RGB data */
+ rgbp = &im->image[(y * im->width * 3) + (x * 3)];
+
+ /* Red */
+ *rgbp++ = (pixel >> 16) & 0xFF;
+ /* Green */
+ *rgbp++ = (pixel >> 8) & 0xFF;
+ /* Blue */
+ *rgbp = pixel & 0xFF;
+}
+
+
+/*
+ * Returns RGB pixel (0xRRGGBB) at (x, y) in GdkRGBImage
+ */
+static guint32 gdk_rgb_image_get_pixel(
+ GdkRGBImage *im,
+ gint x,
+ gint y)
+{
+ guchar *rgbp;
+
+ /* Paranoia */
+ if (im == NULL) return (0);
+
+ /* Paranoia - returns black */
+ if ((x < 0) || (x >= im->width)) return (0);
+
+ /* Paranoia */
+ if ((y < 0) || (y >= im->height)) return (0);
+
+ /* Access RGB data */
+ rgbp = &im->image[(y * im->width * 3) + (x * 3)];
+
+ /* Return result */
+ return ((rgbp[0] << 16) | (rgbp[1] << 8) | (rgbp[2]));
+}
+
+
+/*
+ * Since gdk_draw_rgb_image is a bit harder to use than it's
+ * GdkImage counterpart, I wrote a grue function that takes
+ * exactly the same parameters as gdk_draw_image, with
+ * the GdkImage parameter replaced with GdkRGBImage.
+ */
+static void gdk_draw_rgb_image_2(
+ GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkRGBImage *image,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height)
+{
+ /* Paranoia */
+ g_return_if_fail(drawable != NULL);
+ g_return_if_fail(image != NULL);
+
+ /* Paranoia */
+ if (xsrc < 0 || (xsrc + width - 1) >= image->width) return;
+ if (ysrc < 0 || (ysrc + height - 1) >= image->height) return;
+
+ /* Draw the image at (xdest, ydest), with dithering if bpp <= 8/16 */
+ gdk_draw_rgb_image(
+ drawable,
+ gc,
+ xdest,
+ ydest,
+ width,
+ height,
+ dith_mode,
+ &image->image[(ysrc * image->width * 3) + (xsrc * 3)],
+ image->width * 3);
+}
+
+
+/*
+ * Code for smooth icon rescaling from Uwe Siems, Jan 2000
+ *
+ * XXX XXX Duplication of maid-x11.c, again. It doesn't do any colour
+ * allocation, either.
+ */
+
+/*
+ * to save ourselves some labour, define a maximum expected icon width here:
+ */
+#define MAX_ICON_WIDTH 32
+
+
+/*
+ * Each pixel is kept in this structure during smooth rescaling
+ * calculations, to make things a bit easier
+ */
+typedef struct rgb_type rgb_type;
+
+struct rgb_type
+{
+ guint32 red;
+ guint32 green;
+ guint32 blue;
+};
+
+/*
+ * Because there are many occurences of this, and because
+ * it's logical to do so...
+ */
+#define pixel_to_rgb(pix, rgb_buf) \
+(rgb_buf)->red = ((pix) >> 16) & 0xFF; \
+(rgb_buf)->green = ((pix) >> 8) & 0xFF; \
+(rgb_buf)->blue = (pix) & 0xFF
+
+
+/*
+ * get_scaled_row reads a scan from the given GdkRGBImage, scales it smoothly
+ * and returns the red, green and blue values in arrays.
+ * The values in this arrays must be divided by a certain value that is
+ * calculated in scale_icon.
+ * x, y is the position, iw is the input width and ow the output width
+ * scan must be sufficiently sized
+ */
+static void get_scaled_row(
+ GdkRGBImage *im,
+ int x,
+ int y,
+ int iw,
+ int ow,
+ rgb_type *scan)
+{
+ int xi, si, sifrac, ci, cifrac, add_whole, add_frac;
+ guint32 pix;
+ rgb_type prev;
+ rgb_type next;
+ bool_ get_next_pix;
+
+ /* Unscaled */
+ if (iw == ow)
+ {
+ for (xi = 0; xi < ow; xi++)
+ {
+ pix = gdk_rgb_image_get_pixel(im, x + xi, y);
+ pixel_to_rgb(pix, &scan[xi]);
+ }
+ }
+
+ /* Scaling by subsampling (grow) */
+ else if (iw < ow)
+ {
+ iw--;
+ ow--;
+
+ /* read first pixel: */
+ pix = gdk_rgb_image_get_pixel(im, x, y);
+ pixel_to_rgb(pix, &next);
+ prev = next;
+
+ /* si and sifrac give the subsampling position: */
+ si = x;
+ sifrac = 0;
+
+ /* get_next_pix tells us, that we need the next pixel */
+ get_next_pix = TRUE;
+
+ for (xi = 0; xi <= ow; xi++)
+ {
+ if (get_next_pix)
+ {
+ prev = next;
+ if (xi < ow)
+ {
+ /* only get next pixel if in same icon */
+ pix = gdk_rgb_image_get_pixel(im, si + 1, y);
+ pixel_to_rgb(pix, &next);
+ }
+ }
+
+ /* calculate subsampled color values: */
+ /* division by ow occurs in scale_icon */
+ scan[xi].red = prev.red * (ow - sifrac) + next.red * sifrac;
+ scan[xi].green = prev.green * (ow - sifrac) + next.green * sifrac;
+ scan[xi].blue = prev.blue * (ow - sifrac) + next.blue * sifrac;
+
+ /* advance sampling position: */
+ sifrac += iw;
+ if (sifrac >= ow)
+ {
+ si++;
+ sifrac -= ow;
+ get_next_pix = TRUE;
+ }
+ else
+ {
+ get_next_pix = FALSE;
+ }
+
+ }
+ }
+
+ /* Scaling by averaging (shrink) */
+ else
+ {
+ /* width of an output pixel in input pixels: */
+ add_whole = iw / ow;
+ add_frac = iw % ow;
+
+ /* start position of the first output pixel: */
+ si = x;
+ sifrac = 0;
+
+ /* get first input pixel: */
+ pix = gdk_rgb_image_get_pixel(im, x, y);
+ pixel_to_rgb(pix, &next);
+
+ for (xi = 0; xi < ow; xi++)
+ {
+ /* find endpoint of the current output pixel: */
+ ci = si + add_whole;
+ cifrac = sifrac + add_frac;
+ if (cifrac >= ow)
+ {
+ ci++;
+ cifrac -= ow;
+ }
+
+ /* take fraction of current input pixel (starting segment): */
+ scan[xi].red = next.red * (ow - sifrac);
+ scan[xi].green = next.green * (ow - sifrac);
+ scan[xi].blue = next.blue * (ow - sifrac);
+ si++;
+
+ /* add values for whole pixels: */
+ while (si < ci)
+ {
+ rgb_type tmp_rgb;
+
+ pix = gdk_rgb_image_get_pixel(im, si, y);
+ pixel_to_rgb(pix, &tmp_rgb);
+ scan[xi].red += tmp_rgb.red * ow;
+ scan[xi].green += tmp_rgb.green * ow;
+ scan[xi].blue += tmp_rgb.blue * ow;
+ si++;
+ }
+
+ /* add fraction of current input pixel (ending segment): */
+ if (xi < ow - 1)
+ {
+ /* only get next pixel if still in icon: */
+ pix = gdk_rgb_image_get_pixel(im, si, y);
+ pixel_to_rgb(pix, &next);
+ }
+
+ sifrac = cifrac;
+ if (sifrac > 0)
+ {
+ scan[xi].red += next.red * sifrac;
+ scan[xi].green += next.green * sifrac;
+ scan[xi].blue += next.blue * sifrac;
+ }
+ }
+ }
+}
+
+
+/*
+ * put_rgb_scan takes arrays for red, green and blue and writes pixel values
+ * according to this values in the GdkRGBImage-structure. w is the number of
+ * pixels to write and div is the value by which all red/green/blue values
+ * are divided first.
+ */
+static void put_rgb_scan(
+ GdkRGBImage *im,
+ int x,
+ int y,
+ int w,
+ int div,
+ rgb_type *scan)
+{
+ int xi;
+ guint32 pix;
+ guint32 adj = div / 2;
+
+ for (xi = 0; xi < w; xi++)
+ {
+ byte r, g, b;
+
+ /* un-factor the RGB values */
+ r = (scan[xi].red + adj) / div;
+ g = (scan[xi].green + adj) / div;
+ b = (scan[xi].blue + adj) / div;
+
+ /* Make a (virtual) 24-bit pixel */
+ pix = (r << 16) | (g << 8) | (b);
+
+ /* Draw it into image */
+ gdk_rgb_image_put_pixel(im, x + xi, y, pix);
+ }
+}
+
+
+/*
+ * scale_icon transfers an area from GdkRGBImage im_in, locate (x1,y1) to
+ * im_out, locate (x2, y2). Source size is (ix, iy) and destination size
+ * is (ox, oy).
+ *
+ * It does this by getting icon scan line from get_scaled_scan and handling
+ * them the same way as pixels are handled in get_scaled_scan.
+ * This even allows icons to be scaled differently in horizontal and
+ * vertical directions (eg. shrink horizontal, grow vertical).
+ */
+static void scale_icon(
+ GdkRGBImage *im_in,
+ GdkRGBImage *im_out,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int ix,
+ int iy,
+ int ox,
+ int oy)
+{
+ int div;
+ int xi, yi, si, sifrac, ci, cifrac, add_whole, add_frac;
+
+ /* buffers for pixel rows: */
+ rgb_type prev[MAX_ICON_WIDTH];
+ rgb_type next[MAX_ICON_WIDTH];
+ rgb_type temp[MAX_ICON_WIDTH];
+
+ bool_ get_next_row;
+
+ /* get divider value for the horizontal scaling: */
+ if (ix == ox)
+ div = 1;
+ else if (ix < ox)
+ div = ox - 1;
+ else
+ div = ix;
+
+ /* no scaling needed vertically: */
+ if (iy == oy)
+ {
+ for (yi = 0; yi < oy; yi++)
+ {
+ get_scaled_row(im_in, x1, y1 + yi, ix, ox, temp);
+ put_rgb_scan(im_out, x2, y2 + yi, ox, div, temp);
+ }
+ }
+
+ /* scaling by subsampling (grow): */
+ else if (iy < oy)
+ {
+ iy--;
+ oy--;
+ div *= oy;
+
+ /* get first row: */
+ get_scaled_row(im_in, x1, y1, ix, ox, next);
+
+ /* si and sifrac give the subsampling position: */
+ si = y1;
+ sifrac = 0;
+
+ /* get_next_row tells us, that we need the next row */
+ get_next_row = TRUE;
+ for (yi = 0; yi <= oy; yi++)
+ {
+ if (get_next_row)
+ {
+ for (xi = 0; xi < ox; xi++)
+ {
+ prev[xi] = next[xi];
+ }
+ if (yi < oy)
+ {
+ /* only get next row if in same icon */
+ get_scaled_row(im_in, x1, si + 1, ix, ox, next);
+ }
+ }
+
+ /* calculate subsampled color values: */
+ /* division by oy occurs in put_rgb_scan */
+ for (xi = 0; xi < ox; xi++)
+ {
+ temp[xi].red = (prev[xi].red * (oy - sifrac) +
+ next[xi].red * sifrac);
+ temp[xi].green = (prev[xi].green * (oy - sifrac) +
+ next[xi].green * sifrac);
+ temp[xi].blue = (prev[xi].blue * (oy - sifrac) +
+ next[xi].blue * sifrac);
+ }
+
+ /* write row to output image: */
+ put_rgb_scan(im_out, x2, y2 + yi, ox, div, temp);
+
+ /* advance sampling position: */
+ sifrac += iy;
+ if (sifrac >= oy)
+ {
+ si++;
+ sifrac -= oy;
+ get_next_row = TRUE;
+ }
+ else
+ {
+ get_next_row = FALSE;
+ }
+
+ }
+ }
+
+ /* scaling by averaging (shrink) */
+ else
+ {
+ div *= iy;
+
+ /* height of a output row in input rows: */
+ add_whole = iy / oy;
+ add_frac = iy % oy;
+
+ /* start position of the first output row: */
+ si = y1;
+ sifrac = 0;
+
+ /* get first input row: */
+ get_scaled_row(im_in, x1, y1, ix, ox, next);
+ for (yi = 0; yi < oy; yi++)
+ {
+ /* find endpoint of the current output row: */
+ ci = si + add_whole;
+ cifrac = sifrac + add_frac;
+ if (cifrac >= oy)
+ {
+ ci++;
+ cifrac -= oy;
+ }
+
+ /* take fraction of current input row (starting segment): */
+ for (xi = 0; xi < ox; xi++)
+ {
+ temp[xi].red = next[xi].red * (oy - sifrac);
+ temp[xi].green = next[xi].green * (oy - sifrac);
+ temp[xi].blue = next[xi].blue * (oy - sifrac);
+ }
+ si++;
+
+ /* add values for whole pixels: */
+ while (si < ci)
+ {
+ get_scaled_row(im_in, x1, si, ix, ox, next);
+ for (xi = 0; xi < ox; xi++)
+ {
+ temp[xi].red += next[xi].red * oy;
+ temp[xi].green += next[xi].green * oy;
+ temp[xi].blue += next[xi].blue * oy;
+ }
+ si++;
+ }
+
+ /* add fraction of current input row (ending segment): */
+ if (yi < oy - 1)
+ {
+ /* only get next row if still in icon: */
+ get_scaled_row(im_in, x1, si, ix, ox, next);
+ }
+ sifrac = cifrac;
+ for (xi = 0; xi < ox; xi++)
+ {
+ temp[xi].red += next[xi].red * sifrac;
+ temp[xi].green += next[xi].green * sifrac;
+ temp[xi].blue += next[xi].blue * sifrac;
+ }
+
+ /* write row to output image: */
+ put_rgb_scan(im_out, x2, y2 + yi, ox, div, temp);
+ }
+ }
+}
+
+
+/*
+ * Rescale icons using sort of anti-aliasing technique.
+ */
+static GdkRGBImage *resize_tiles_smooth(
+ GdkRGBImage *im,
+ int ix,
+ int iy,
+ int ox,
+ int oy)
+{
+ int width1, height1, width2, height2;
+ int x1, x2, y1, y2;
+
+ GdkRGBImage *tmp;
+
+ /* Original size */
+ width1 = im->width;
+ height1 = im->height;
+
+ /* Rescaled size */
+ width2 = ox * width1 / ix;
+ height2 = oy * height1 / iy;
+
+ /* Allocate GdkRGBImage for resized tiles */
+ tmp = gdk_rgb_image_new(width2, height2);
+
+ /* Oops */
+ if (tmp == NULL) return (NULL);
+
+ /* Scale each icon */
+ for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); y1 += iy, y2 += oy)
+ {
+ for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); x1 += ix, x2 += ox)
+ {
+ scale_icon(im, tmp, x1, y1, x2, y2,
+ ix, iy, ox, oy);
+ }
+ }
+
+ return tmp;
+}
+
+
+/*
+ * Steven Fuerst's tile resizing code
+ * Taken from Z because I think the algorithm is cool.
+ */
+
+/* 24-bit version - GdkRGB uses 24 bit RGB data internally */
+static void copy_pixels(
+ int wid,
+ int y,
+ int offset,
+ int *xoffsets,
+ GdkRGBImage *old_image,
+ GdkRGBImage *new_image)
+{
+ int i;
+
+ /* Get source and destination */
+ byte *src = &old_image->image[offset * old_image->width * 3];
+ byte *dst = &new_image->image[y * new_image->width * 3];
+
+ /* Copy to the image */
+ for (i = 0; i < wid; i++)
+ {
+ *dst++ = src[3 * xoffsets[i]];
+ *dst++ = src[3 * xoffsets[i] + 1];
+ *dst++ = src[3 * xoffsets[i] + 2];
+ }
+}
+
+
+#if 0
+
+/* 32-bit version: it might be useful in the future */
+static void copy_pixels(
+ int wid,
+ int y,
+ int offset,
+ int *xoffsets,
+ GdkRGBImage *old_image,
+ GdkRGBImage *new_image)
+{
+ int i;
+
+ /* Get source and destination */
+ byte *src = &old_image->image[offset * old_image->width * 4];
+ byte *dst = &new_image->image[y * new_image->width * 4];
+
+ /* Copy to the image */
+ for (i = 0; i < wid; i++)
+ {
+ *dst++ = src[4 * xoffsets[i]];
+ *dst++ = src[4 * xoffsets[i] + 1];
+ *dst++ = src[4 * xoffsets[i] + 2];
+ *dst++ = src[4 * xoffsets[i] + 3];
+ }
+}
+
+#endif
+
+
+/*
+ * Resize ix * iy pixel tiles in old to ox * oy pixels
+ * and return a new GdkRGBImage containing the resized tiles
+ */
+static GdkRGBImage *resize_tiles_fast(
+ GdkRGBImage *old_image,
+ int ix,
+ int iy,
+ int ox,
+ int oy)
+{
+ GdkRGBImage *new_image;
+
+ int old_wid, old_hgt;
+
+ int new_wid, new_hgt;
+
+ int add, remainder, rem_tot, offset;
+
+ int *xoffsets;
+
+ int i;
+
+
+ /* Get the size of the old image */
+ old_wid = old_image->width;
+ old_hgt = old_image->height;
+
+ /* Calculate the size of the new image */
+ new_wid = (old_wid / ix) * ox;
+ new_hgt = (old_hgt / iy) * oy;
+
+ /* Allocate a GdkRGBImage to store resized tiles */
+ new_image = gdk_rgb_image_new(new_wid, new_hgt);
+
+ /* Paranoia */
+ if (new_image == NULL) return (NULL);
+
+ /* now begins the cool part of SF's code */
+
+ /*
+ * Calculate an offsets table, so the transformation
+ * is faster. This is much like the Bresenham algorithm
+ */
+
+ /* Set up x offset table */
+ C_MAKE(xoffsets, new_wid, int);
+
+ /* Initialize line parameters */
+ add = old_wid / new_wid;
+ remainder = old_wid % new_wid;
+
+ /* Start at left */
+ offset = 0;
+
+ /* Half-tile offset so 'line' is centered correctly */
+ rem_tot = new_wid / 2;
+
+ for (i = 0; i < new_wid; i++)
+ {
+ /* Store into the table */
+ xoffsets[i] = offset;
+
+ /* Move to next entry */
+ offset += add;
+
+ /* Take care of fractional part */
+ rem_tot += remainder;
+ if (rem_tot >= new_wid)
+ {
+ rem_tot -= new_wid;
+ offset++;
+ }
+ }
+
+ /* Scan each row */
+
+ /* Initialize line parameters */
+ add = old_hgt / new_hgt;
+ remainder = old_hgt % new_hgt;
+
+ /* Start at left */
+ offset = 0;
+
+ /* Half-tile offset so 'line' is centered correctly */
+ rem_tot = new_hgt / 2;
+
+ for (i = 0; i < new_hgt; i++)
+ {
+ /* Copy pixels to new image */
+ copy_pixels(new_wid, i, offset, xoffsets, old_image, new_image);
+
+ /* Move to next entry */
+ offset += add;
+
+ /* Take care of fractional part */
+ rem_tot += remainder;
+ if (rem_tot >= new_hgt)
+ {
+ rem_tot -= new_hgt;
+ offset++;
+ }
+ }
+
+ /* Free offset table */
+ C_FREE(xoffsets, new_wid, int);
+
+ return (new_image);
+}
+
+
+/*
+ * Resize an image of ix * iy pixels and return a newly allocated
+ * image of ox * oy pixels.
+ */
+static GdkRGBImage *resize_tiles(
+ GdkRGBImage *im,
+ int ix,
+ int iy,
+ int ox,
+ int oy)
+{
+ GdkRGBImage *result;
+
+ /*
+ * I hope we can always use this with GdkRGB, which uses a 5x5x5
+ * colour cube (125 colours) by default, and resort to dithering
+ * when it can't find good match there or expand the cube, so it
+ * works with 8bpp X servers.
+ */
+ if (smooth_rescaling_request && (ix != ox || iy != oy))
+ {
+ result = resize_tiles_smooth(im, ix, iy, ox, oy);
+ }
+
+ /*
+ * Unless smoothing is requested by user, we use the fast
+ * resizing code.
+ */
+ else
+ {
+ result = resize_tiles_fast(im, ix, iy, ox, oy);
+ }
+
+ /* Return rescaled tiles, or NULL */
+ return (result);
+}
+
+
+/*
+ * Tile loaders - XPM and BMP
+ */
+
+/*
+ * A helper function for the XPM loader
+ *
+ * Read next string delimited by double quotes from
+ * the input stream. Return TRUE on success, FALSE
+ * if it finds EOF or buffer overflow.
+ *
+ * I never mean this to be generic, so its EOF and buffer
+ * overflow behaviour is terribly stupid -- there are no
+ * provisions for recovery.
+ *
+ * CAVEAT: treatment of backslash is not compatible with the standard
+ * C usage XXX XXX XXX XXX
+ */
+static bool_ read_str(char *buf, u32b len, FILE *f)
+{
+ int c;
+
+ /* Paranoia - Buffer too small */
+ if (len <= 0) return (FALSE);
+
+ /* Find " */
+ while ((c = getc(f)) != '"')
+ {
+ /* Premature EOF */
+ if (c == EOF) return (FALSE);
+ }
+
+ while (1)
+ {
+ /* Read next char */
+ c = getc(f);
+
+ /* Premature EOF */
+ if (c == EOF) return (FALSE);
+
+ /* Terminating " */
+ if (c == '"') break;
+
+ /* Escape */
+ if (c == '\\')
+ {
+ /* Use next char */
+ c = getc(f);
+
+ /* Premature EOF */
+ if (c == EOF) return (FALSE);
+ }
+
+ /* Store character in the buffer */
+ *buf++ = c;
+
+ /* Decrement count */
+ len--;
+
+ /* Buffer full - we have to place a NULL at the end */
+ if (len <= 0) return (FALSE);
+ }
+
+ /* Make a C string if there's room left */
+ if (len > 0) *buf = '\0';
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Remember pixel symbol to RGB colour mappings
+ */
+
+/*
+ * I've forgot the formula, but I remember prime number yields
+ * good results
+ */
+#define HASH_SIZE 19
+
+typedef struct pal_type pal_type;
+
+struct pal_type
+{
+ u32b str;
+ u32b rgb;
+ pal_type *next;
+};
+
+
+/*
+ * A simple, slow and stupid XPM loader
+ */
+static GdkRGBImage *load_xpm(cptr filename)
+{
+ FILE *f;
+ GdkRGBImage *img = NULL;
+ int width, height, colours, chars;
+ int i, j, k;
+ bool_ ret;
+ pal_type *pal = NULL;
+ pal_type *head[HASH_SIZE];
+ u32b buflen = 0;
+ char *lin = NULL;
+ char buf[1024];
+
+ /* Build path to the XPM file */
+ path_build(buf, 1024, ANGBAND_DIR_XTRA_GRAF, filename);
+
+ /* Open it */
+ f = my_fopen(buf, "r");
+
+ /* Oops */
+ if (f == NULL) return (NULL);
+
+ /* Read header */
+ ret = read_str(buf, 1024, f);
+
+ /* Oops */
+ if (!ret)
+ {
+ /* Notify error */
+ plog("Cannot find XPM header");
+
+ /* Failure */
+ goto oops;
+ }
+
+ /* Parse header */
+ if (4 != sscanf(buf, "%d %d %d %d", &width, &height, &colours, &chars))
+ {
+ /* Notify error */
+ plog("Bad XPM header");
+
+ /* Failure */
+ goto oops;
+ }
+
+ /*
+ * Paranoia - the code can handle upto four letters per pixel,
+ * but such large number of colours certainly requires a smarter
+ * symbol-to-colour mapping algorithm...
+ */
+ if ((width <= 0) || (height <= 0) || (colours <= 0) || (chars <= 0) ||
+ (chars > 2))
+ {
+ /* Notify error */
+ plog("Invalid width/height/depth");
+
+ /* Failure */
+ goto oops;
+ }
+
+ /* Allocate palette */
+ C_MAKE(pal, colours, pal_type);
+
+ /* Initialise hash table */
+ for (i = 0; i < HASH_SIZE; i++) head[i] = NULL;
+
+ /* Parse palette */
+ for (i = 0; i < colours; i++)
+ {
+ u32b tmp;
+ int h_idx;
+
+ /* Read next string */
+ ret = read_str(buf, 1024, f);
+
+ /* Check I/O result */
+ if (!ret)
+ {
+ /* Notify error */
+ plog("EOF in palette");
+
+ /* Failure */
+ goto oops;
+ }
+
+ /* Clear symbol code */
+ tmp = 0;
+
+ /* Encode pixel symbol */
+ for (j = 0; j < chars; j++)
+ {
+ tmp = (tmp << 8) | (buf[j] & 0xFF);
+ }
+
+ /* Remember it */
+ pal[i].str = tmp;
+
+ /* Skip spaces */
+ while ((buf[j] == ' ') || (buf[j] == '\t')) j++;
+
+ /* Verify 'c' */
+ if (buf[j] != 'c')
+ {
+ /* Notify error */
+ plog("No 'c' in palette definition");
+
+ /* Failure */
+ goto oops;
+ }
+
+ /* Advance cursor */
+ j++;
+
+ /* Skip spaces */
+ while ((buf[j] == ' ') || (buf[j] == '\t')) j++;
+
+ /* Hack - Assume 'None' */
+ if (buf[j] == 'N')
+ {
+ /* Angband always uses black background */
+ pal[i].rgb = 0x000000;
+ }
+
+ /* Read colour */
+ else if ((1 != sscanf(&buf[j], "#%06lX", &tmp)) &&
+ (1 != sscanf(&buf[j], "#%06lx", &tmp)))
+ {
+ /* Notify error */
+ plog("Badly formatted colour");
+
+ /* Failure */
+ goto oops;
+ }
+
+ /* Remember it */
+ pal[i].rgb = tmp;
+
+ /* Store it in hash table as well */
+ h_idx = pal[i].str % HASH_SIZE;
+
+ /* Link the entry */
+ pal[i].next = head[h_idx];
+ head[h_idx] = &pal[i];
+ }
+
+ /* Allocate image */
+ img = gdk_rgb_image_new(width, height);
+
+ /* Oops */
+ if (img == NULL)
+ {
+ /* Notify error */
+ plog("Cannot allocate image");
+
+ /* Failure */
+ goto oops;
+ }
+
+ /* Calculate buffer length */
+ buflen = width * chars + 1;
+
+ /* Allocate line buffer */
+ C_MAKE(lin, buflen, char);
+
+ /* For each row */
+ for (i = 0; i < height; i++)
+ {
+ /* Read a row of image data */
+ ret = read_str(lin, buflen, f);
+
+ /* Oops */
+ if (!ret)
+ {
+ /* Notify error */
+ plog("EOF in middle of image data");
+
+ /* Failure */
+ goto oops;
+ }
+
+ /* For each column */
+ for (j = 0; j < width; j++)
+ {
+ u32b tmp;
+ pal_type *h_ptr;
+
+ /* Clear encoded pixel */
+ tmp = 0;
+
+ /* Encode pixel symbol */
+ for (k = 0; k < chars; k++)
+ {
+ tmp = (tmp << 8) | (lin[j * chars + k] & 0xFF);
+ }
+
+ /* Find colour */
+ for (h_ptr = head[tmp % HASH_SIZE];
+ h_ptr != NULL;
+ h_ptr = h_ptr->next)
+ {
+ /* Found a match */
+ if (h_ptr->str == tmp) break;
+ }
+
+ /* No match found */
+ if (h_ptr == NULL)
+ {
+ /* Notify error */
+ plog("Invalid pixel symbol");
+
+ /* Failure */
+ goto oops;
+ }
+
+ /* Draw it */
+ gdk_rgb_image_put_pixel(
+ img,
+ j,
+ i,
+ h_ptr->rgb);
+ }
+ }
+
+ /* Close file */
+ my_fclose(f);
+
+ /* Free line buffer */
+ C_FREE(lin, buflen, char);
+
+ /* Free palette */
+ C_FREE(pal, colours, pal_type);
+
+ /* Return result */
+ return (img);
+
+oops:
+
+ /* Close file */
+ my_fclose(f);
+
+ /* Free image */
+ if (img) gdk_rgb_image_destroy(img);
+
+ /* Free line buffer */
+ if (lin) C_FREE(lin, buflen, char);
+
+ /* Free palette */
+ if (pal) C_FREE(pal, colours, pal_type);
+
+ /* Failure */
+ return (NULL);
+}
+
+
+/*
+ * A BMP loader, yet another duplication of maid-x11.c functions.
+ *
+ * Another duplication, again because of different image format and
+ * avoidance of colour allocation.
+ *
+ * XXX XXX XXX XXX Should avoid using a propriatary and closed format.
+ * Since it's much bigger than gif that was used before, why don't
+ * we switch to XPM? NetHack does. Well, NH has always been much
+ * closer to the GNU/Un*x camp and it's GPL'ed quite early...
+ *
+ * The names and naming convention are worse than the worst I've ever
+ * seen, so I deliberately changed them to fit well with the rest of
+ * the code. Or are they what xx calls them? If it's the case, there's
+ * no reason to follow *their* words.
+ */
+
+/*
+ * BMP file header
+ */
+typedef struct bmp_file_type bmp_file_type;
+
+struct bmp_file_type
+{
+ u16b type;
+ u32b size;
+ u16b reserved1;
+ u16b reserved2;
+ u32b offset;
+};
+
+
+/*
+ * BMP file information fields
+ */
+typedef struct bmp_info_type bmp_info_type;
+
+struct bmp_info_type
+{
+ u32b size;
+ u32b width;
+ u32b height;
+ u16b planes;
+ u16b bit_count;
+ u32b compression;
+ u32b size_image;
+ u32b x_pels_per_meter;
+ u32b y_pels_per_meter;
+ u32b colors_used;
+ u32b color_importand;
+};
+
+/*
+ * "RGBQUAD" type.
+ */
+typedef struct rgb_quad_type rgb_quad_type;
+
+struct rgb_quad_type
+{
+ unsigned char b, g, r;
+ unsigned char filler;
+};
+
+
+/*** Helper functions for system independent file loading. ***/
+
+static byte get_byte(FILE *fff)
+{
+ /* Get a character, and return it */
+ return (getc(fff) & 0xFF);
+}
+
+static void rd_byte(FILE *fff, byte *ip)
+{
+ *ip = get_byte(fff);
+}
+
+static void rd_u16b(FILE *fff, u16b *ip)
+{
+ (*ip) = get_byte(fff);
+ (*ip) |= ((u16b)(get_byte(fff)) << 8);
+}
+
+static void rd_u32b(FILE *fff, u32b *ip)
+{
+ (*ip) = get_byte(fff);
+ (*ip) |= ((u32b)(get_byte(fff)) << 8);
+ (*ip) |= ((u32b)(get_byte(fff)) << 16);
+ (*ip) |= ((u32b)(get_byte(fff)) << 24);
+}
+
+
+/*
+ * Read a BMP file (a certain trademark nuked)
+ *
+ * This function replaces the old ReadRaw and RemapColors functions.
+ *
+ * Assumes that the bitmap has a size such that no padding is needed in
+ * various places. Currently only handles bitmaps with 3 to 256 colors.
+ */
+GdkRGBImage *load_bmp(cptr filename)
+{
+ FILE *f;
+
+ char path[1024];
+
+ bmp_file_type file_hdr;
+ bmp_info_type info_hdr;
+
+ GdkRGBImage *result = NULL;
+
+ int ncol;
+
+ int i;
+
+ u32b x, y;
+
+ guint32 colour_pixels[256];
+
+
+ /* Build the path to the bmp file */
+ path_build(path, 1024, ANGBAND_DIR_XTRA_GRAF, filename);
+
+ /* Open the BMP file */
+ f = fopen(path, "r");
+
+ /* No such file */
+ if (f == NULL)
+ {
+ return (NULL);
+ }
+
+ /* Read the "bmp_file_type" */
+ rd_u16b(f, &file_hdr.type);
+ rd_u32b(f, &file_hdr.size);
+ rd_u16b(f, &file_hdr.reserved1);
+ rd_u16b(f, &file_hdr.reserved2);
+ rd_u32b(f, &file_hdr.offset);
+
+ /* Read the "bmp_info_type" */
+ rd_u32b(f, &info_hdr.size);
+ rd_u32b(f, &info_hdr.width);
+ rd_u32b(f, &info_hdr.height);
+ rd_u16b(f, &info_hdr.planes);
+ rd_u16b(f, &info_hdr.bit_count);
+ rd_u32b(f, &info_hdr.compression);
+ rd_u32b(f, &info_hdr.size_image);
+ rd_u32b(f, &info_hdr.x_pels_per_meter);
+ rd_u32b(f, &info_hdr.y_pels_per_meter);
+ rd_u32b(f, &info_hdr.colors_used);
+ rd_u32b(f, &info_hdr.color_importand);
+
+ /* Verify the header */
+ if (feof(f) ||
+ (file_hdr.type != 19778) ||
+ (info_hdr.size != 40))
+ {
+ plog(format("Incorrect BMP file format %s", filename));
+ fclose(f);
+ return (NULL);
+ }
+
+ /*
+ * The two headers above occupy 54 bytes total
+ * The "offset" field says where the data starts
+ * The "colors_used" field does not seem to be reliable
+ */
+
+ /* Compute number of colors recorded */
+ ncol = (file_hdr.offset - 54) / 4;
+
+ for (i = 0; i < ncol; i++)
+ {
+ rgb_quad_type clr;
+
+ /* Read an "rgb_quad_type" */
+ rd_byte(f, &clr.b);
+ rd_byte(f, &clr.g);
+ rd_byte(f, &clr.r);
+ rd_byte(f, &clr.filler);
+
+ /* Remember the pixel */
+ colour_pixels[i] = (clr.r << 16) | (clr.g << 8) | (clr.b);
+ }
+
+ /* Allocate GdkRGBImage large enough to store the image */
+ result = gdk_rgb_image_new(info_hdr.width, info_hdr.height);
+
+ /* Failure */
+ if (result == NULL)
+ {
+ fclose(f);
+ return (NULL);
+ }
+
+ for (y = 0; y < info_hdr.height; y++)
+ {
+ u32b y2 = info_hdr.height - y - 1;
+
+ for (x = 0; x < info_hdr.width; x++)
+ {
+ int ch = getc(f);
+
+ /* Verify not at end of file XXX XXX */
+ if (feof(f))
+ {
+ plog(format("Unexpected end of file in %s", filename));
+ gdk_rgb_image_destroy(result);
+ fclose(f);
+ return (NULL);
+ }
+
+ if (info_hdr.bit_count == 24)
+ {
+ int c3, c2 = getc(f);
+
+ /* Verify not at end of file XXX XXX */
+ if (feof(f))
+ {
+ plog(format("Unexpected end of file in %s", filename));
+ gdk_rgb_image_destroy(result);
+ fclose(f);
+ return (NULL);
+ }
+
+ c3 = getc(f);
+
+ /* Verify not at end of file XXX XXX */
+ if (feof(f))
+ {
+ plog(format("Unexpected end of file in %s", filename));
+ gdk_rgb_image_destroy(result);
+ fclose(f);
+ return (NULL);
+ }
+
+ /* Draw the pixel */
+ gdk_rgb_image_put_pixel(
+ result,
+ x,
+ y2,
+ (ch << 16) | (c2 << 8) | (c3));
+ }
+ else if (info_hdr.bit_count == 8)
+ {
+ gdk_rgb_image_put_pixel(result, x, y2, colour_pixels[ch]);
+ }
+ else if (info_hdr.bit_count == 4)
+ {
+ gdk_rgb_image_put_pixel(result, x, y2, colour_pixels[ch / 16]);
+ x++;
+ gdk_rgb_image_put_pixel(result, x, y2, colour_pixels[ch % 16]);
+ }
+ else
+ {
+ /* Technically 1 bit is legal too */
+ plog(format("Illegal bit count %d in %s",
+ info_hdr.bit_count, filename));
+ gdk_rgb_image_destroy(result);
+ fclose(f);
+ return (NULL);
+ }
+ }
+ }
+
+ fclose(f);
+
+ return result;
+}
+
+
+/*
+ * Try to load an XPM file, or a BMP file if it fails
+ *
+ * Choice of file format may better be made yet another option XXX
+ */
+static GdkRGBImage *load_tiles(cptr basename)
+{
+ char buf[32];
+ GdkRGBImage *img;
+
+ /* build xpm file name */
+ strnfmt(buf, 32, "%s.xpm", basename);
+
+ /* Try to load it */
+ img = load_xpm(buf);
+
+ /* OK */
+ if (img) return (img);
+
+ /* Try again for a bmp file */
+ strnfmt(buf, 32, "%s.bmp", basename);
+
+ /* Try loading it */
+ img = load_bmp(buf);
+
+ /* Return result, success or failure */
+ return (img);
+}
+
+
+/*
+ * Free all tiles and graphics buffers associated with windows
+ *
+ * This is conspirator of graf_init() below, sharing its inefficiency
+ */
+static void graf_nuke()
+{
+ int i;
+
+ term_data *td;
+
+
+ /* Nuke all terms */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* Access term_data structure */
+ td = &data[i];
+
+ /* Disable graphics */
+ td->t.higher_pict = FALSE;
+
+ /* Free previously allocated tiles */
+ if (td->tiles) gdk_rgb_image_destroy(td->tiles);
+
+ /* Forget pointer */
+ td->tiles = NULL;
+
+ /* Free previously allocated transparency buffer */
+ if (td->trans_buf) gdk_rgb_image_destroy(td->trans_buf);
+
+ /* Forget stale pointer */
+ td->trans_buf = NULL;
+ }
+}
+
+
+/*
+ * Load tiles, scale them to current font size, and store a pointer
+ * to them in a term_data structure for each term.
+ *
+ * XXX XXX XXX This is a terribly stupid quick hack.
+ *
+ * XXX XXX XXX Windows using the same font should share resized tiles
+ */
+static bool_ graf_init(
+ cptr filename,
+ int tile_wid,
+ int tile_hgt)
+{
+ term_data *td;
+
+ bool_ result;
+
+ GdkRGBImage *raw_tiles, *scaled_tiles;
+
+ GdkRGBImage *buffer;
+
+ int i;
+
+
+ /* Paranoia */
+ if (filename == NULL) return (FALSE);
+
+ /* Load tiles */
+ raw_tiles = load_tiles(filename);
+
+ /* Oops */
+ if (raw_tiles == NULL)
+ {
+ /* Clean up */
+ graf_nuke();
+
+ /* Failure */
+ return (FALSE);
+ }
+
+ /* Calculate and remember numbers of rows and columns */
+ tile_rows = raw_tiles->height / tile_hgt;
+ tile_cols = raw_tiles->width / tile_wid;
+
+ /* Be optimistic */
+ result = TRUE;
+
+
+ /*
+ * (Re-)init each term
+ * XXX It might help speeding this up to avoid doing so if a window
+ * doesn't need graphics (e.g. inventory/equipment and message recall).
+ */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* Access term_data */
+ td = &data[i];
+
+ /* Shouldn't waste anything for unused terms */
+ if (!td->shown) continue;
+
+ /* Enable graphics */
+ td->t.higher_pict = TRUE;
+
+ /* See if we need rescaled tiles XXX */
+ if ((td->tiles == NULL) ||
+ (td->tiles->width != td->tile_wid * tile_cols) ||
+ (td->tiles->height != td->tile_hgt * tile_rows))
+ {
+ /* Free old tiles if present */
+ if (td->tiles) gdk_rgb_image_destroy(td->tiles);
+
+ /* Forget pointer */
+ td->tiles = NULL;
+
+ /* Scale the tiles to current font bounding rect */
+ scaled_tiles = resize_tiles(
+ raw_tiles,
+ tile_wid, tile_hgt,
+ td->tile_wid, td->tile_hgt);
+
+ /* Oops */
+ if (scaled_tiles == NULL)
+ {
+ /* Failure */
+ result = FALSE;
+
+ break;
+ }
+
+ /* Store it */
+ td->tiles = scaled_tiles;
+ }
+
+ /* See if we have to (re)allocate a new buffer XXX */
+ if ((td->trans_buf == NULL) ||
+ (td->trans_buf->width != td->tile_wid) ||
+ (td->trans_buf->height != td->tile_hgt))
+ {
+ /* Free old buffer if present */
+ if (td->trans_buf) gdk_rgb_image_destroy(td->trans_buf);
+
+ /* Forget pointer */
+ td->trans_buf = NULL;
+
+ /* Allocate a new buffer */
+ buffer = gdk_rgb_image_new(td->tile_wid, td->tile_hgt);
+
+ /* Oops */
+ if (buffer == NULL)
+ {
+ /* Failure */
+ result = FALSE;
+
+ break;
+ }
+
+ /* Store it */
+ td->trans_buf = buffer;
+ }
+
+ /*
+ * Giga-Hack - assume top left corner of 0x86/0x80 should be
+ * in the background colour XXX XXX XXX XXX
+ */
+ td->bg_pixel = gdk_rgb_image_get_pixel(
+ raw_tiles,
+ 0,
+ tile_hgt * 6);
+
+ }
+
+
+ /* Alas, we need to free wasted images */
+ if (result == FALSE) graf_nuke();
+
+ /* We don't need the raw image any longer */
+ gdk_rgb_image_destroy(raw_tiles);
+
+ /* Report success or failure */
+ return (result);
+}
+
+
+/*
+ * React to various changes in graphics mode settings
+ *
+ * It is *not* a requirement for tiles to have same pixel width and height.
+ * The program can work with any conbinations of graf_wid and graf_hgt
+ * (oops, they must be representable by u16b), as long as they are lesser
+ * or equal to 32 if you use smooth rescaling.
+ */
+static void init_graphics(void)
+{
+ cptr tile_name;
+
+ u16b graf_wid = 0, graf_hgt = 0;
+
+
+ /* No graphics requests are made - Can't this be simpler? XXX XXX */
+ if ((graf_mode_request == graf_mode) &&
+ (smooth_rescaling_request == smooth_rescaling) &&
+ !resize_request) return;
+
+ /* Prevent further unsolicited reaction */
+ resize_request = FALSE;
+
+
+ /* Dispose unusable old tiles - awkward... XXX XXX */
+ if ((graf_mode_request == GRAF_MODE_NONE) ||
+ (graf_mode_request != graf_mode) ||
+ (smooth_rescaling_request != smooth_rescaling)) graf_nuke();
+
+
+ /* Setup parameters according to request */
+ switch (graf_mode_request)
+ {
+ /* ASCII - no graphics whatsoever */
+ default:
+ case GRAF_MODE_NONE:
+ {
+ tile_name = NULL;
+ use_graphics = arg_graphics = FALSE;
+
+ break;
+ }
+
+ /*
+ * 8x8 tiles originally collected for the Amiga port
+ * from several contributers by Lars Haugseth, converted
+ * to 256 colours and expanded by the Z devteam
+ *
+ * Use the "old" tile assignments
+ *
+ * Dawnmist is working on it for ToME
+ */
+ case GRAF_MODE_OLD:
+ {
+ tile_name = "8x8";
+ graf_wid = graf_hgt = 8;
+ ANGBAND_GRAF = "old";
+ use_graphics = arg_graphics = TRUE;
+
+ break;
+ }
+
+ /*
+ * Adam Bolt's 16x16 tiles
+ * "new" tile assignments
+ * It is updated for ToME by Andreas Koch
+ */
+ case GRAF_MODE_NEW:
+ {
+ tile_name = "16x16";
+ graf_wid = graf_hgt = 16;
+ ANGBAND_GRAF = "new";
+ use_graphics = arg_graphics = TRUE;
+
+ break;
+ }
+ }
+
+
+ /* load tiles and set them up if tiles are requested */
+ if ((graf_mode_request != GRAF_MODE_NONE) &&
+ !graf_init(tile_name, graf_wid, graf_hgt))
+ {
+ /* Oops */
+ plog("Cannot initialize graphics");
+
+ /* reject requests */
+ graf_mode_request = GRAF_MODE_NONE;
+ smooth_rescaling_request = smooth_rescaling;
+
+ /* reset graphics flags */
+ use_graphics = arg_graphics = FALSE;
+ }
+
+ /* Update current graphics mode */
+ graf_mode = graf_mode_request;
+ smooth_rescaling = smooth_rescaling_request;
+
+ /* Reset visuals */
+#ifndef ANG281_RESET_VISUALS
+ reset_visuals(TRUE);
+#else
+ reset_visuals();
+#endif /* !ANG281_RESET_VISUALS */
+}
+
+#endif /* USE_GRAPHICS */
+
+
+
+
+/**** Term package support routines ****/
+
+
+/*
+ * Free data used by a term
+ */
+static void Term_nuke_gtk(term *t)
+{
+ term_data *td = t->data;
+
+
+ /* Free name */
+ if (td->name) string_free(td->name);
+
+ /* Forget it */
+ td->name = NULL;
+
+ /* Free font */
+ if (td->font) gdk_font_unref(td->font);
+
+ /* Forget it */
+ td->font = NULL;
+
+ /* Free backing store */
+ if (td->backing_store) gdk_pixmap_unref(td->backing_store);
+
+ /* Forget it too */
+ td->backing_store = NULL;
+
+#ifdef USE_GRAPHICS
+
+ /* Free tiles */
+ if (td->tiles) gdk_rgb_image_destroy(td->tiles);
+
+ /* Forget pointer */
+ td->tiles = NULL;
+
+ /* Free transparency buffer */
+ if (td->trans_buf) gdk_rgb_image_destroy(td->trans_buf);
+
+ /* Amnesia */
+ td->trans_buf = NULL;
+
+#endif /* USE_GRAPHICS */
+}
+
+
+/*
+ * Erase the whole term.
+ */
+static errr Term_clear_gtk(void)
+{
+ term_data *td = (term_data*)(Term->data);
+
+
+ /* Don't draw to hidden windows */
+ if (!td->shown) return (0);
+
+ /* Paranoia */
+ g_assert(td->drawing_area->window != 0);
+
+ /* Clear the area */
+ gdk_draw_rectangle(
+ TERM_DATA_DRAWABLE(td),
+ td->drawing_area->style->black_gc,
+ 1,
+ 0,
+ 0,
+ td->cols * td->font_wid,
+ td->rows * td->font_hgt);
+
+ /* Copy image from backing store if present */
+ TERM_DATA_REFRESH(td, 0, 0, td->cols, td->rows);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Erase some characters.
+ */
+static errr Term_wipe_gtk(int x, int y, int n)
+{
+ term_data *td = (term_data*)(Term->data);
+
+
+ /* Don't draw to hidden windows */
+ if (!td->shown) return (0);
+
+ /* Paranoia */
+ g_assert(td->drawing_area->window != 0);
+
+ /* Fill the area with the background colour */
+ gdk_draw_rectangle(
+ TERM_DATA_DRAWABLE(td),
+ td->drawing_area->style->black_gc,
+ TRUE,
+ x * td->font_wid,
+ y * td->font_hgt,
+ n * td->font_wid,
+ td->font_hgt);
+
+ /* Copy image from backing store if present */
+ TERM_DATA_REFRESH(td, x, y, n, 1);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Draw some textual characters.
+ */
+static errr Term_text_gtk(int x, int y, int n, byte a, cptr s)
+{
+ term_data *td = (term_data*)(Term->data);
+
+
+ /* Don't draw to hidden windows */
+ if (!td->shown) return (0);
+
+ /* Paranoia */
+ g_assert(td->drawing_area->window != 0);
+
+ /* Set foreground colour */
+ term_data_set_fg(td, a);
+
+ /* Clear the line */
+ Term_wipe_gtk(x, y, n);
+
+ /* Draw the text to the window */
+ gdk_draw_text(
+ TERM_DATA_DRAWABLE(td),
+ td->font,
+ td->gc,
+ x * td->font_wid,
+ td->font->ascent + y * td->font_hgt,
+ s,
+ n);
+
+ /* Copy image from backing store if present */
+ TERM_DATA_REFRESH(td, x, y, n, 1);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Draw software cursor at (x, y)
+ */
+static errr Term_curs_gtk(int x, int y)
+{
+ term_data *td = (term_data*)(Term->data);
+ int cells = 1;
+
+
+ /* Don't draw to hidden windows */
+ if (!td->shown) return (0);
+
+ /* Paranoia */
+ g_assert(td->drawing_area->window != 0);
+
+ /* Set foreground colour */
+ term_data_set_fg(td, TERM_YELLOW);
+
+#ifdef USE_DOUBLE_TILES
+
+ /* Mogami's bigtile patch */
+
+ /* Adjust it if wide tiles are requested */
+ if (use_bigtile &&
+ (x + 1 < Term->wid) &&
+ (Term->old->a[y][x + 1] == 255))
+ {
+ cells = 2;
+ }
+
+#endif /* USE_DOUBLE_TILES */
+
+ /* Draw the software cursor */
+ gdk_draw_rectangle(
+ TERM_DATA_DRAWABLE(td),
+ td->gc,
+ FALSE,
+ x * td->font_wid,
+ y * td->font_hgt,
+ td->font_wid * cells - 1,
+ td->font_hgt - 1);
+
+ /* Copy image from backing store if present */
+ TERM_DATA_REFRESH(td, x, y, cells, 1);
+
+ /* Success */
+ return (0);
+}
+
+
+#ifdef USE_GRAPHICS
+
+/*
+ * XXX XXX Low level graphics helper
+ * Draw a tile at (s_x, s_y) over one at (t_x, t_y) and store the
+ * result in td->trans_buf
+ *
+ * XXX XXX Even if CPU's are faster than necessary these days,
+ * this should be made inline. Or better, there should be an API
+ * to take advantage of graphics hardware. They almost always have
+ * assortment of builtin bitblt's...
+ */
+static void overlay_tiles_2(
+ term_data *td,
+ int s_x, int s_y,
+ int t_x, int t_y)
+{
+ guint32 pix;
+ int x, y;
+
+
+ /* Process each row */
+ for (y = 0; y < td->tile_hgt; y++)
+ {
+ /* Process each column */
+ for (x = 0; x < td->tile_wid; x++)
+ {
+ /* Get an overlay pixel */
+ pix = gdk_rgb_image_get_pixel(td->tiles, s_x + x, s_y + y);
+
+ /* If it's in background color, use terrain instead */
+ if (pix == td->bg_pixel)
+ pix = gdk_rgb_image_get_pixel(td->tiles, t_x + x, t_y + y);
+
+ /* Store the result in trans_buf */
+ gdk_rgb_image_put_pixel(td->trans_buf, x, y, pix);
+ }
+ }
+}
+
+
+/*
+ * XXX XXX Low level graphics helper
+ * Draw a tile at (e_x, e_y) over one at (s_x, s_y) over another one
+ * at (t_x, t_y) and store the result in td->trans_buf
+ *
+ * XXX XXX The same comment applies as that for the above...
+ */
+static void overlay_tiles_3(
+ term_data *td,
+ int e_x, int e_y,
+ int s_x, int s_y,
+ int t_x, int t_y)
+{
+ guint32 pix;
+ int x, y;
+
+
+ /* Process each row */
+ for (y = 0; y < td->tile_hgt; y++)
+ {
+ /* Process each column */
+ for (x = 0; x < td->tile_wid; x++)
+ {
+ /* Get an overlay pixel */
+ pix = gdk_rgb_image_get_pixel(td->tiles, e_x + x, e_y + y);
+
+ /*
+ * If it's background colour, try to use one from
+ * the second layer
+ */
+ if (pix == td->bg_pixel)
+ pix = gdk_rgb_image_get_pixel(td->tiles, s_x + x, s_y + y);
+
+ /*
+ * If it's background colour again, fall back to
+ * the terrain layer
+ */
+ if (pix == td->bg_pixel)
+ pix = gdk_rgb_image_get_pixel(td->tiles, t_x + x, t_y + y);
+
+ /* Store the pixel in trans_buf */
+ gdk_rgb_image_put_pixel(td->trans_buf, x, y, pix);
+ }
+ }
+}
+
+
+
+/*
+ * Low level graphics (Assumes valid input)
+ *
+ * Draw "n" tiles/characters starting at (x,y)
+ */
+static errr Term_pict_gtk(
+ int x, int y, int n,
+ const byte *ap, const char *cp,
+ const byte *tap, const char *tcp,
+ const byte *eap, const char *ecp)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ int i;
+
+ int d_x, d_y;
+
+# ifdef USE_DOUBLE_TILES
+
+ /* Hack - remember real number of columns affected XXX XXX XXX */
+ int cols;
+
+# endif /* USE_DOUBLE_TILES */
+
+
+ /* Don't draw to hidden windows */
+ if (!td->shown) return (0);
+
+ /* Paranoia */
+ g_assert(td->drawing_area->window != 0);
+
+ /* Top left corner of the destination rect */
+ d_x = x * td->font_wid;
+ d_y = y * td->font_hgt;
+
+
+# ifdef USE_DOUBLE_TILES
+
+ /* Reset column counter */
+ cols = 0;
+
+# endif /* USE_DOUBLE_TILES */
+
+ /* Scan the input */
+ for (i = 0; i < n; i++)
+ {
+ byte a;
+ char c;
+ int s_x, s_y;
+
+ byte ta;
+ char tc;
+ int t_x, t_y;
+
+ byte ea;
+ char ec;
+ int e_x = 0, e_y = 0;
+ bool_ has_overlay;
+
+
+ /* Grid attr/char */
+ a = *ap++;
+ c = *cp++;
+
+ /* Terrain attr/char */
+ ta = *tap++;
+ tc = *tcp++;
+
+ /* Overlay attr/char */
+ ea = *eap++;
+ ec = *ecp++;
+ has_overlay = (ea && ec);
+
+ /* Row and Col */
+ s_y = (((byte)a & 0x7F) % tile_rows) * td->tile_hgt;
+ s_x = (((byte)c & 0x7F) % tile_cols) * td->tile_wid;
+
+ /* Terrain Row and Col */
+ t_y = (((byte)ta & 0x7F) % tile_rows) * td->tile_hgt;
+ t_x = (((byte)tc & 0x7F) % tile_cols) * td->tile_wid;
+
+ /* Overlay Row and Col */
+ if (has_overlay)
+ {
+ e_y = (((byte)ea & 0x7F) % tile_rows) * td->tile_hgt;
+ e_x = (((byte)ec & 0x7F) % tile_cols) * td->tile_wid;
+ }
+
+
+# ifdef USE_DOUBLE_TILES
+
+ /* Mogami's bigtile patch */
+
+ /* Hack -- a filler for wide tile */
+ if (use_bigtile && (a == 255))
+ {
+ /* Advance */
+ d_x += td->font_wid;
+
+ /* Ignore */
+ continue;
+ }
+
+# endif /* USE_DOUBLE_TILES */
+
+ /* Optimise the common case: terrain == obj/mons */
+ if (!use_transparency ||
+ ((s_x == t_x) && (s_y == t_y)))
+ {
+
+ /* The simplest possible case - no overlay */
+ if (!has_overlay)
+ {
+ /* Draw the tile */
+ gdk_draw_rgb_image_2(
+ TERM_DATA_DRAWABLE(td), td->gc, td->tiles,
+ s_x, s_y,
+ d_x, d_y,
+ td->tile_wid, td->tile_hgt);
+ }
+
+ /* We have to draw overlay... */
+ else
+ {
+ /* Overlay */
+ overlay_tiles_2(td, e_x, e_y, s_x, s_y);
+
+ /* And draw the result */
+ gdk_draw_rgb_image_2(
+ TERM_DATA_DRAWABLE(td), td->gc, td->trans_buf,
+ 0, 0,
+ d_x, d_y,
+ td->tile_wid, td->tile_hgt);
+
+ /* Hack -- Prevent potential display problem */
+ gdk_flush();
+ }
+
+ }
+
+ /*
+ * Since there's no masking bitblt in X,
+ * we have to do that manually...
+ */
+ else
+ {
+
+ /* No overlay */
+ if (!has_overlay)
+ {
+ /* Build terrain + masked overlay image */
+ overlay_tiles_2(td, s_x, s_y, t_x, t_y);
+ }
+
+ /* With overlay */
+ else
+ {
+ /* Ego over mon/PC over terrain */
+ overlay_tiles_3(td, e_x, e_y, s_x, s_y,
+ t_x, t_y);
+ }
+
+ /* Draw it */
+ gdk_draw_rgb_image_2(
+ TERM_DATA_DRAWABLE(td), td->gc, td->trans_buf,
+ 0, 0,
+ d_x, d_y,
+ td->tile_wid, td->tile_hgt);
+
+ /* Hack -- Prevent potential display problem */
+ gdk_flush();
+ }
+
+ /*
+ * Advance x-coordinate - wide font fillers are taken care of
+ * before entering the tile drawing code.
+ */
+ d_x += td->font_wid;
+
+# ifdef USE_DOUBLE_TILES
+
+ /* Add up *real* number of columns updated XXX XXX XXX */
+ cols += use_bigtile ? 2 : 1;
+
+# endif /* USE_DOUBLE_TILES */
+ }
+
+# ifndef USE_DOUBLE_TILES
+
+ /* Copy image from backing store if present */
+ TERM_DATA_REFRESH(td, x, y, n, 1);
+
+# else
+
+ /* Copy image from backing store if present */
+ TERM_DATA_REFRESH(td, x, y, cols, 1);
+
+# endif /* USE_DOUBLE_TILES */
+
+ /* Success */
+ return (0);
+}
+
+#endif /* USE_GRAPHICS */
+
+
+/*
+ * Process an event, if there's none block when wait is set true,
+ * return immediately otherwise.
+ */
+static void CheckEvent(bool_ wait)
+{
+ /* Process an event */
+ (void)gtk_main_iteration_do(wait);
+}
+
+
+/*
+ * Process all pending events (without blocking)
+ */
+static void DrainEvents(void)
+{
+ while (gtk_events_pending())
+ gtk_main_iteration();
+}
+
+
+/*
+ * Handle a "special request"
+ */
+static errr Term_xtra_gtk(int n, int v)
+{
+ /* Handle a subset of the legal requests */
+ switch (n)
+ {
+ /* Make a noise */
+ case TERM_XTRA_NOISE:
+ {
+ /* Beep */
+ gdk_beep();
+
+ /* Success */
+ return (0);
+ }
+
+ /* Flush the output */
+ case TERM_XTRA_FRESH:
+ {
+ /* Flush pending X requests - almost always no-op */
+ gdk_flush();
+
+ /* Success */
+ return (0);
+ }
+
+ /* Process random events */
+ case TERM_XTRA_BORED:
+ {
+ /* Process a pending event if there's one */
+ CheckEvent(FALSE);
+
+ /* Success */
+ return (0);
+ }
+
+ /* Process Events */
+ case TERM_XTRA_EVENT:
+ {
+ /* Process an event */
+ CheckEvent(v);
+
+ /* Success */
+ return (0);
+ }
+
+ /* Flush the events */
+ case TERM_XTRA_FLUSH:
+ {
+ /* Process all pending events */
+ DrainEvents();
+
+ /* Success */
+ return (0);
+ }
+
+ /* Handle change in the "level" */
+ case TERM_XTRA_LEVEL:
+ return (0);
+
+ /* Clear the screen */
+ case TERM_XTRA_CLEAR:
+ return (Term_clear_gtk());
+
+ /* Delay for some milliseconds */
+ case TERM_XTRA_DELAY:
+ {
+ /* sleep for v milliseconds */
+ usleep(v * 1000);
+
+ /* Done */
+ return (0);
+ }
+
+ /* Get Delay of some milliseconds */
+ case TERM_XTRA_GET_DELAY:
+ {
+ int ret;
+ struct timeval tv;
+
+ ret = gettimeofday(&tv, NULL);
+ Term_xtra_long = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+
+ return ret;
+ }
+
+ /* Subdirectory scan */
+ case TERM_XTRA_SCANSUBDIR:
+ {
+ DIR *directory;
+ struct dirent *entry;
+
+ scansubdir_max = 0;
+
+ directory = opendir(scansubdir_dir);
+ if (!directory) return (1);
+
+ while ((entry = readdir(directory)) != NULL)
+ {
+ char file[PATH_MAX + NAME_MAX + 2];
+ struct stat filedata;
+
+ file[PATH_MAX + NAME_MAX] = 0;
+ strncpy(file, scansubdir_dir, PATH_MAX);
+ strncat(file, "/", 2);
+ strncat(file, entry->d_name, NAME_MAX);
+ if ((stat(file, &filedata) == 0) && S_ISDIR(filedata.st_mode))
+ {
+ string_free(scansubdir_result[scansubdir_max]);
+ scansubdir_result[scansubdir_max] =
+ string_make(entry->d_name);
+ ++scansubdir_max;
+ }
+ }
+ }
+
+ /* Rename main window */
+ case TERM_XTRA_RENAME_MAIN_WIN: gtk_window_set_title(GTK_WINDOW(data[0].window), angband_term_name[0]); return (0);
+
+ /* React to changes */
+ case TERM_XTRA_REACT:
+ {
+ /* (re-)init colours */
+ init_colours();
+
+#ifdef USE_GRAPHICS
+
+ /* Initialise graphics */
+ init_graphics();
+
+#endif /* USE_GRAPHICS */
+
+ /* Success */
+ return (0);
+ }
+ }
+
+ /* Unknown */
+ return (1);
+}
+
+
+
+
+/**** Event handlers ****/
+
+
+/*
+ * Operation overkill
+ * Verify term size info - just because the other windowing ports have this
+ */
+static void term_data_check_size(term_data *td)
+{
+ /* Enforce minimum window size */
+ if (td == &data[0])
+ {
+ if (td->cols < 80) td->cols = 80;
+ if (td->rows < 24) td->rows = 24;
+ }
+ else
+ {
+ if (td->cols < 1) td->cols = 1;
+ if (td->rows < 1) td->rows = 1;
+ }
+
+ /* Paranoia - Enforce maximum size allowed by the term package */
+ if (td->cols > 255) td->cols = 255;
+ if (td->rows > 255) td->rows = 255;
+}
+
+
+/*
+ * Enforce these size constraints within Gtk/Gdk
+ * These increments are nice, because you can see numbers of rows/cols
+ * while you resize a term.
+ */
+static void term_data_set_geometry_hints(term_data *td)
+{
+ GdkGeometry geometry;
+
+ /* Resizing is character size oriented */
+ geometry.width_inc = td->font_wid;
+ geometry.height_inc = td->font_hgt;
+
+ /* Enforce minimum size - the main window */
+ if (td == &data[0])
+ {
+ geometry.min_width = 80 * td->font_wid;
+ geometry.min_height = 24 * td->font_hgt;
+ }
+
+ /* Subwindows can be much smaller */
+ else
+ {
+ geometry.min_width = 1 * td->font_wid;
+ geometry.min_height = 1 * td->font_hgt;
+ }
+
+ /* Enforce term package's hard limit */
+ geometry.max_width = 255 * td->font_wid;
+ geometry.max_height = 255 * td->font_hgt;
+
+ /* This affects geometry display while we resize a term */
+ geometry.base_width = 0;
+ geometry.base_height = 0;
+
+ /* Give the window a new set of resizing hints */
+ gtk_window_set_geometry_hints(GTK_WINDOW(td->window),
+ td->drawing_area, &geometry,
+ GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE
+ | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC);
+}
+
+
+/*
+ * (Re)allocate a backing store for the window
+ */
+static void term_data_set_backing_store(term_data *td)
+{
+ /* Paranoia */
+ if (!GTK_WIDGET_REALIZED(td->drawing_area)) return;
+
+ /* Free old one if we cannot use it any longer */
+ if (td->backing_store)
+ {
+ int wid, hgt;
+
+ /* Retrive the size of the old backing store */
+ gdk_window_get_size(td->backing_store, &wid, &hgt);
+
+ /* Continue using it if it's the same with desired size */
+ if (use_backing_store &&
+ (td->cols * td->font_wid == wid) &&
+ (td->rows * td->font_hgt == hgt)) return;
+
+ /* Free it */
+ gdk_pixmap_unref(td->backing_store);
+
+ /* Forget the pointer */
+ td->backing_store = NULL;
+ }
+
+ /* See user preference */
+ if (use_backing_store)
+ {
+ /* Allocate new backing store */
+ td->backing_store = gdk_pixmap_new(
+ td->drawing_area->window,
+ td->cols * td->font_wid,
+ td->rows * td->font_hgt,
+ -1);
+
+ /* Oops - but we can do without it */
+ g_return_if_fail(td->backing_store != NULL);
+
+ /* Clear the backing store */
+ gdk_draw_rectangle(
+ td->backing_store,
+ td->drawing_area->style->black_gc,
+ TRUE,
+ 0,
+ 0,
+ td->cols * td->font_wid,
+ td->rows * td->font_hgt);
+ }
+}
+
+
+/*
+ * Save game only when it's safe to do so
+ */
+static void save_game_gtk(void)
+{
+ /* We have nothing to save, yet */
+ if (!game_in_progress || !character_generated) return;
+
+ /* It isn't safe to save game now */
+ if (!inkey_flag || !can_save)
+ {
+ plog("You may not save right now.");
+ return;
+ }
+
+ /* Hack -- Forget messages */
+ msg_flag = FALSE;
+
+ /* Save the game */
+#ifdef ZANG_SAVE_GAME
+ /* Also for OAngband - the parameter tells if it's autosave */
+ do_cmd_save_game(FALSE);
+#else
+/* Everything else */
+ do_cmd_save_game();
+#endif /* ZANG_SAVE_GAME */
+}
+
+
+/*
+ * Display message in a modal dialog
+ */
+static void gtk_message(cptr msg)
+{
+ GtkWidget *dialog, *label, *ok_button;
+
+ /* Create the widgets */
+ dialog = gtk_dialog_new();
+ g_assert(dialog != NULL);
+
+ label = gtk_label_new(msg);
+ g_assert(label != NULL);
+
+ ok_button = gtk_button_new_with_label("OK");
+ g_assert(ok_button != NULL);
+
+ /* Ensure that the dialogue box is destroyed when OK is clicked */
+ gtk_signal_connect_object(
+ GTK_OBJECT(ok_button),
+ "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ (gpointer)dialog);
+ gtk_container_add(
+ GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
+ ok_button);
+
+ /* Add the label, and show the dialog */
+ gtk_container_add(
+ GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
+ label);
+
+ /* And make it modal */
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+
+ /* Show the dialog */
+ gtk_widget_show_all(dialog);
+}
+
+
+/*
+ * Hook to tell the user something important
+ */
+static void hook_plog(cptr str)
+{
+ /* Warning message */
+ gtk_message(str);
+}
+
+
+/*
+ * Process File-Quit menu command
+ */
+static void quit_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *was_clicked)
+{
+ /* Save current game */
+ save_game_gtk();
+
+ /* It's done */
+ quit(NULL);
+}
+
+
+/*
+ * Process File-Save menu command
+ */
+static void save_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *was_clicked)
+{
+ /* Save current game */
+ save_game_gtk();
+}
+
+
+/*
+ * Handle destruction of the Angband window
+ */
+static void destroy_main_event_handler(
+ GtkButton *was_clicked,
+ gpointer user_data)
+{
+ /* This allows for cheating, but... */
+ quit(NULL);
+}
+
+
+/*
+ * Handle destruction of Subwindows
+ */
+static void destroy_sub_event_handler(
+ GtkWidget *window,
+ gpointer user_data)
+{
+ /* Hide the window */
+ gtk_widget_hide_all(window);
+}
+
+
+#ifndef SAVEFILE_SCREEN
+
+/*
+ * Process File-New menu command
+ */
+static void new_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *was_clicked)
+{
+ if (game_in_progress)
+ {
+ plog("You can't start a new game while you're still playing!");
+ return;
+ }
+
+ /* The game is in progress */
+ game_in_progress = TRUE;
+
+ /* Flush input */
+ Term_flush();
+
+ /* Play game */
+ play_game(TRUE);
+
+ /* Houseclearing */
+ cleanup_angband();
+
+ /* Done */
+ quit(NULL);
+}
+
+#endif /* !SAVEFILE_SCREEN */
+
+
+/*
+ * Load fond specified by an XLFD fontname and
+ * set up related term_data members
+ */
+static void load_font(term_data *td, cptr fontname)
+{
+ GdkFont *old = td->font;
+
+ /* Load font */
+ td->font = gdk_font_load(fontname);
+
+ if (td->font)
+ {
+ /* Free the old font */
+ if (old) gdk_font_unref(old);
+ }
+ else
+ {
+ /* Oops, but we can still use the old one */
+ td->font = old;
+ }
+
+ /* Calculate the size of the font XXX */
+ td->font_wid = gdk_char_width(td->font, '@');
+ td->font_hgt = td->font->ascent + td->font->descent;
+
+#ifndef USE_DOUBLE_TILES
+
+ /* Use the current font size for tiles as well */
+ td->tile_wid = td->font_wid;
+ td->tile_hgt = td->font_hgt;
+
+#else /* !USE_DOUBLE_TILES */
+
+ /* Calculate the size of tiles */
+ if (use_bigtile && (td == &data[0])) td->tile_wid = td->font_wid * 2;
+ else td->tile_wid = td->font_wid;
+ td->tile_hgt = td->font_hgt;
+
+#endif /* !USE_DOUBLE_TILES */
+}
+
+
+/*
+ * Process Options-Font-* menu command
+ */
+static void change_font_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *widget)
+{
+ /* Not implemented */
+}
+
+
+/*
+ * Process Terms-* menu command - hide/show terminal window
+ */
+static void term_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *widget)
+{
+ term_data *td = &data[user_action];
+
+ /* We don't mess with the Angband window */
+ if (td == &data[0]) return;
+
+ /* It's shown */
+ if (td->shown)
+ {
+ /* Hide the window */
+ gtk_widget_hide_all(td->window);
+ }
+
+ /* It's hidden */
+ else
+ {
+ /* Show the window */
+ gtk_widget_show_all(td->window);
+ }
+}
+
+
+/*
+ * Toggles the boolean value of use_backing_store and
+ * setup / remove backing store for each term
+ */
+static void change_backing_store_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *was_clicked)
+{
+ int i;
+
+ /* Toggle the backing store mode */
+ use_backing_store = !use_backing_store;
+
+ /* Reset terms */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ term_data_set_backing_store(&data[i]);
+ }
+}
+
+
+#ifdef USE_GRAPHICS
+
+/*
+ * Set graf_mode_request according to user selection,
+ * and let Term_xtra react to the change.
+ */
+static void change_graf_mode_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *was_clicked)
+{
+ /* Set request according to user selection */
+ graf_mode_request = (int)user_action;
+
+ /*
+ * Hack - force redraw
+ * This induces a call to Term_xtra(TERM_XTRA_REACT, 0) as well
+ */
+ Term_key_push(KTRL('R'));
+}
+
+
+/*
+ * Set dither_mode according to user selection
+ */
+static void change_dith_mode_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *was_clicked)
+{
+ /* Set request according to user selection */
+ dith_mode = (int)user_action;
+
+ /*
+ * Hack - force redraw
+ */
+ Term_key_push(KTRL('R'));
+}
+
+
+/*
+ * Toggles the graphics tile scaling mode (Fast/Smooth)
+ */
+static void change_smooth_mode_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *was_clicked)
+{
+ /* (Try to) toggle the smooth rescaling mode */
+ smooth_rescaling_request = !smooth_rescaling;
+
+ /*
+ * Hack - force redraw
+ * This induces a call to Term_xtra(TERM_XTRA_REACT, 0) as well
+ */
+ Term_key_push(KTRL('R'));
+}
+
+
+# ifdef USE_DOUBLE_TILES
+
+static void change_wide_tile_mode_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *was_clicked)
+{
+ term *old = Term;
+ term_data *td = &data[0];
+
+ /* Toggle "use_bigtile" */
+ use_bigtile = !use_bigtile;
+
+#ifdef TOME
+ /* T.o.M.E. requires this as well */
+ arg_bigtile = use_bigtile;
+#endif /* TOME */
+
+ /* Double the width of tiles (only for the main window) */
+ if (use_bigtile)
+ {
+ td->tile_wid = td->font_wid * 2;
+ }
+
+ /* Use the width of current font */
+ else
+ {
+ td->tile_wid = td->font_wid;
+ }
+
+ /* Need to resize the tiles */
+ resize_request = TRUE;
+
+ /* Activate the main window */
+ Term_activate(&td->t);
+
+ /* Resize the term */
+ Term_resize(td->cols, td->rows);
+
+ /* Activate the old term */
+ Term_activate(old);
+
+ /* Hack - force redraw XXX ??? XXX */
+ Term_key_push(KTRL('R'));
+}
+
+# endif /* USE_DOUBLE_TILES */
+
+
+/*
+ * Toggles the boolean value of use_transparency
+ */
+static void change_trans_mode_event_handler(
+ gpointer user_data,
+ guint user_aciton,
+ GtkWidget *was_clicked)
+{
+ /* Toggle the transparency mode */
+ use_transparency = !use_transparency;
+
+ /* Hack - force redraw */
+ Term_key_push(KTRL('R'));
+}
+
+#endif /* USE_GRAPHICS */
+
+
+#ifndef SAVEFILE_SCREEN
+
+/*
+ * Caution: Modal or not, callbacks are called by gtk_main(),
+ * so this is the right place to start a game.
+ */
+static void file_ok_callback(
+ GtkWidget *widget,
+ GtkWidget *file_selector)
+{
+ strcpy(savefile,
+ gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_selector)));
+
+ gtk_widget_destroy(file_selector);
+
+ /* game is in progress */
+ game_in_progress = TRUE;
+
+ /* Flush input */
+ Term_flush();
+
+ /* Play game */
+ play_game(FALSE);
+
+ /* Free memory allocated by game */
+ cleanup_angband();
+
+ /* Done */
+ quit(NULL);
+}
+
+
+/*
+ * Process File-Open menu command
+ */
+static void open_event_handler(
+ gpointer user_data,
+ guint user_action,
+ GtkWidget *was_clicked)
+{
+ GtkWidget *file_selector;
+ char buf[1024];
+
+
+ if (game_in_progress)
+ {
+ plog("You can't open a new game while you're still playing!");
+ return;
+ }
+
+ /* Prepare the savefile path */
+ path_build(buf, 1024, ANGBAND_DIR_SAVE, "*");
+
+ file_selector = gtk_file_selection_new("Select a savefile");
+ gtk_file_selection_set_filename(
+ GTK_FILE_SELECTION(file_selector),
+ buf);
+ gtk_signal_connect(
+ GTK_OBJECT(GTK_FILE_SELECTION(file_selector)->ok_button),
+ "clicked",
+ file_ok_callback,
+ (gpointer)file_selector);
+
+ /*
+ * Ensure that the dialog box is destroyed when the user
+ * clicks a button.
+ */
+ gtk_signal_connect_object(
+ GTK_OBJECT(GTK_FILE_SELECTION(file_selector)->ok_button),
+ "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ (gpointer)file_selector);
+
+ gtk_signal_connect_object(
+ GTK_OBJECT(GTK_FILE_SELECTION(file_selector)->cancel_button),
+ "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ (gpointer)file_selector);
+
+ gtk_window_set_modal(GTK_WINDOW(file_selector), TRUE);
+ gtk_widget_show(GTK_WIDGET(file_selector));
+}
+
+#endif /* !SAVEFILE_SCREEN */
+
+
+/*
+ * React to "delete" signal sent to Window widgets
+ */
+static gboolean delete_event_handler(
+ GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ /* Save game if possible */
+ save_game_gtk();
+
+ /* Don't prevent closure */
+ return (FALSE);
+}
+
+
+/*
+ * Convert keypress events to ASCII codes and enqueue them
+ * for game
+ */
+static gboolean keypress_event_handler(
+ GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+#if 1
+ int i, mc, ms, mo, mx;
+
+ char msg[128];
+
+ /* Hack - do not do anything until the player picks from the menu */
+ if (!game_in_progress) return (TRUE);
+
+ /* Hack - Ignore parameters */
+ (void) widget;
+ (void) user_data;
+
+ /* Extract four "modifier flags" */
+ mc = (event->state & GDK_CONTROL_MASK) ? TRUE : FALSE;
+ ms = (event->state & GDK_SHIFT_MASK) ? TRUE : FALSE;
+ mo = (event->state & GDK_MOD1_MASK) ? TRUE : FALSE;
+ mx = (event->state & GDK_MOD3_MASK) ? TRUE : FALSE;
+
+ /*
+ * Hack XXX
+ * Parse shifted numeric (keypad) keys specially.
+ */
+ if ((event->state == GDK_SHIFT_MASK)
+ && (event->keyval >= GDK_KP_0) && (event->keyval <= GDK_KP_9))
+ {
+ /* Build the macro trigger string */
+ strnfmt(msg, 128, "%cS_%X%c", 31, event->keyval, 13);
+
+ /* Enqueue the "macro trigger" string */
+ for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
+
+ /* Hack -- auto-define macros as needed */
+ if (event->length && (macro_find_exact(msg) < 0))
+ {
+ /* Create a macro */
+ macro_add(msg, event->string);
+ }
+
+ return (TRUE);
+ }
+
+ /* Normal keys with no modifiers */
+ if (event->length && !mo && !mx)
+ {
+ /* Enqueue the normal key(s) */
+ for (i = 0; i < event->length; i++) Term_keypress(event->string[i]);
+
+ /* All done */
+ return (TRUE);
+ }
+
+
+ /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
+ switch ((uint) event->keyval)
+ {
+ case GDK_Escape:
+ {
+ Term_keypress(ESCAPE);
+ return (TRUE);
+ }
+
+ case GDK_Return:
+ {
+ Term_keypress('\r');
+ return (TRUE);
+ }
+
+ case GDK_Tab:
+ {
+ Term_keypress('\t');
+ return (TRUE);
+ }
+
+ case GDK_Delete:
+ case GDK_BackSpace:
+ {
+ Term_keypress('\010');
+ return (TRUE);
+ }
+
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ case GDK_Control_L:
+ case GDK_Control_R:
+ case GDK_Caps_Lock:
+ case GDK_Shift_Lock:
+ case GDK_Meta_L:
+ case GDK_Meta_R:
+ case GDK_Alt_L:
+ case GDK_Alt_R:
+ case GDK_Super_L:
+ case GDK_Super_R:
+ case GDK_Hyper_L:
+ case GDK_Hyper_R:
+ {
+ /* Hack - do nothing to control characters */
+ return (TRUE);
+ }
+ }
+
+ /* Build the macro trigger string */
+ strnfmt(msg, 128, "%c%s%s%s%s_%X%c", 31,
+ mc ? "N" : "", ms ? "S" : "",
+ mo ? "O" : "", mx ? "M" : "",
+ event->keyval, 13);
+
+ /* Enqueue the "macro trigger" string */
+ for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
+
+ /* Hack -- auto-define macros as needed */
+ if (event->length && (macro_find_exact(msg) < 0))
+ {
+ /* Create a macro */
+ macro_add(msg, event->string);
+ }
+
+ return (TRUE);
+
+#else
+ int i, mc, ms, mo, mx;
+
+ char msg[128];
+
+
+ /* Extract four "modifier flags" */
+ mc = (event->state & GDK_CONTROL_MASK) ? TRUE : FALSE;
+ ms = (event->state & GDK_SHIFT_MASK) ? TRUE : FALSE;
+ mo = (event->state & GDK_MOD1_MASK) ? TRUE : FALSE;
+ mx = (event->state & GDK_MOD3_MASK) ? TRUE : FALSE;
+ printf("0=%d 9=%d;; keyval=%d; mc=%d, ms=%d ::=:: ", GDK_KP_0, GDK_KP_9, event->keyval, mc, ms);
+ /* Enqueue the normal key(s) */
+ for (i = 0; i < event->length; i++) printf("%d;", event->string[i]);
+ printf("\n");
+
+ /*
+ * Hack XXX
+ * Parse shifted numeric (keypad) keys specially.
+ */
+ if ((event->state & GDK_SHIFT_MASK)
+ && (event->keyval >= GDK_KP_Left) && (event->keyval <= GDK_KP_Delete))
+ {
+ /* Build the macro trigger string */
+ strnfmt(msg, 128, "%cS_%X%c", 31, event->keyval, 13);
+ printf("%cS_%X%c", 31, event->keyval, 13);
+
+ /* Enqueue the "macro trigger" string */
+ for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
+
+ /* Hack -- auto-define macros as needed */
+ if (event->length && (macro_find_exact(msg) < 0))
+ {
+ /* Create a macro */
+ macro_add(msg, event->string);
+ }
+
+ return (TRUE);
+ }
+
+ /* Normal keys with no modifiers */
+ if (event->length && !mo && !mx)
+ {
+ /* Enqueue the normal key(s) */
+ for (i = 0; i < event->length; i++) Term_keypress(event->string[i]);
+
+ /* All done */
+ return (TRUE);
+ }
+
+ /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
+ switch ((uint) event->keyval)
+ {
+ case GDK_Escape:
+ {
+ Term_keypress(ESCAPE);
+ return (TRUE);
+ }
+
+ case GDK_Return:
+ {
+ Term_keypress('\r');
+ return (TRUE);
+ }
+
+ case GDK_Tab:
+ {
+ Term_keypress('\t');
+ return (TRUE);
+ }
+
+ case GDK_Delete:
+ case GDK_BackSpace:
+ {
+ Term_keypress('\010');
+ return (TRUE);
+ }
+
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ case GDK_Control_L:
+ case GDK_Control_R:
+ case GDK_Caps_Lock:
+ case GDK_Shift_Lock:
+ case GDK_Meta_L:
+ case GDK_Meta_R:
+ case GDK_Alt_L:
+ case GDK_Alt_R:
+ case GDK_Super_L:
+ case GDK_Super_R:
+ case GDK_Hyper_L:
+ case GDK_Hyper_R:
+ {
+ /* Hack - do nothing to control characters */
+ return (TRUE);
+ }
+ }
+
+ /* Build the macro trigger string */
+ strnfmt(msg, 128, "%c%s%s%s%s_%X%c", 31,
+ mc ? "N" : "", ms ? "S" : "",
+ mo ? "O" : "", mx ? "M" : "",
+ event->keyval, 13);
+
+ /* Enqueue the "macro trigger" string */
+ for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
+
+ /* Hack -- auto-define macros as needed */
+ if (event->length && (macro_find_exact(msg) < 0))
+ {
+ /* Create a macro */
+ macro_add(msg, event->string);
+ }
+
+ return (TRUE);
+#endif
+}
+
+
+/*
+ * Widget customisation (for drawing area) - "realize" signal
+ *
+ * In this program, called when window containing the drawing
+ * area is shown first time.
+ */
+static void realize_event_handler(
+ GtkWidget *widget,
+ gpointer user_data)
+{
+ term_data *td = (term_data *)user_data;
+
+ /* Create graphic context */
+ td->gc = gdk_gc_new(td->drawing_area->window);
+
+ /* Set foreground and background colours - isn't bg used at all? */
+ gdk_rgb_gc_set_background(td->gc, 0x000000);
+ gdk_rgb_gc_set_foreground(td->gc, angband_colours[TERM_WHITE]);
+
+ /* No last foreground colour, yet */
+ td->last_attr = -1;
+
+ /* Allocate the backing store */
+ term_data_set_backing_store(td);
+
+ /* Clear the window */
+ gdk_draw_rectangle(
+ widget->window,
+ widget->style->black_gc,
+ TRUE,
+ 0,
+ 0,
+ td->cols * td->font_wid,
+ td->rows * td->font_hgt);
+}
+
+
+/*
+ * Widget customisation (for drawing area) - "show" signal
+ */
+static void show_event_handler(
+ GtkWidget *widget,
+ gpointer user_data)
+{
+ term_data *td = (term_data *)user_data;
+
+ /* Set the shown flag */
+ td->shown = TRUE;
+}
+
+
+/*
+ * Widget customisation (for drawing area) - "hide" signal
+ */
+static void hide_event_handler(
+ GtkWidget *widget,
+ gpointer user_data)
+{
+ term_data *td = (term_data *)user_data;
+
+ /* Set the shown flag */
+ td->shown = FALSE;
+}
+
+
+/*
+ * Widget customisation (for drawing area)- handle size allocation requests
+ */
+static void size_allocate_event_handler(
+ GtkWidget *widget,
+ GtkAllocation *allocation,
+ gpointer user_data)
+{
+ term_data *td = user_data;
+ int old_rows, old_cols;
+ term *old = Term;
+
+ /* Paranoia */
+ g_return_if_fail(widget != NULL);
+ g_return_if_fail(allocation != NULL);
+ g_return_if_fail(td != NULL);
+
+ /* Remember old values */
+ old_cols = td->cols;
+ old_rows = td->rows;
+
+ /* Update numbers of rows and columns */
+ td->cols = (allocation->width + td->font_wid - 1) / td->font_wid;
+ td->rows = (allocation->height + td->font_hgt - 1) / td->font_hgt;
+
+ /* Overkill - Validate them */
+ term_data_check_size(td);
+
+ /* Adjust size request and set it */
+ allocation->width = td->cols * td->font_wid;
+ allocation->height = td->rows * td->font_hgt;
+ widget->allocation = *allocation;
+
+ /* Widget is realized, so we do some drawing works */
+ if (GTK_WIDGET_REALIZED(widget))
+ {
+ /* Reallocate the backing store */
+ term_data_set_backing_store(td);
+
+ /* Actually handles resizing in Gtk */
+ gdk_window_move_resize(
+ widget->window,
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
+
+ /* And in the term package */
+ Term_activate(&td->t);
+
+ /* Resize if necessary */
+ if ((td->cols != old_cols) || (td->rows != old_rows))
+ (void)Term_resize(td->cols, td->rows);
+
+ /* Redraw its content */
+ Term_redraw();
+
+ /* Refresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+
+/*
+ * Update exposed area in a window (for drawing area)
+ */
+static gboolean expose_event_handler(
+ GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer user_data)
+{
+ term_data *td = user_data;
+
+ term *old = Term;
+
+#ifndef NO_REDRAW_SECTION
+
+ int x1, x2, y1, y2;
+
+#endif /* !NO_REDRAW_SECTION */
+
+
+ /* Paranoia */
+ if (td == NULL) return (TRUE);
+
+ /* The window has a backing store */
+ if (td->backing_store)
+ {
+ /* Simply restore the exposed area from the backing store */
+ gdk_draw_pixmap(
+ td->drawing_area->window,
+ td->gc,
+ td->backing_store,
+ event->area.x,
+ event->area.y,
+ event->area.x,
+ event->area.y,
+ event->area.width,
+ event->area.height);
+ }
+
+ /* No backing store - use the game's code to redraw the area */
+ else
+ {
+
+ /* Activate the relevant term */
+ Term_activate(&td->t);
+
+# ifdef NO_REDRAW_SECTION
+
+ /* K.I.S.S. version */
+
+ /* Redraw */
+ Term_redraw();
+
+# else /* NO_REDRAW_SECTION */
+
+ /*
+ * Complex version - The above is enough, but since we have
+ * Term_redraw_section... This might help if we had a graphics
+ * mode.
+ */
+
+ /* Convert coordinate in pixels to character cells */
+ x1 = event->area.x / td->font_wid;
+ x2 = (event->area.x + event->area.width) / td->font_wid;
+ y1 = event->area.y / td->font_hgt;
+ y2 = (event->area.y + event->area.height) / td->font_hgt;
+
+ /*
+ * No paranoia - boundary checking is done in
+ * Term_redraw_section
+ */
+
+ /* Redraw the area */
+ Term_redraw_section(x1, y1, x2, y2);
+
+# endif /* NO_REDRAW_SECTION */
+
+ /* Refresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+
+ /* We've processed the event ourselves */
+ return (TRUE);
+}
+
+
+
+
+/**** Initialisation ****/
+
+/*
+ * Initialise a term_data struct
+ */
+static errr term_data_init(term_data *td, int i)
+{
+ term *t = &td->t;
+ char *p;
+
+ td->cols = 80;
+ td->rows = 24;
+
+ /* Initialize the term */
+ term_init(t, td->cols, td->rows, 1024);
+
+ /* Store the name of the term */
+ td->name = string_make(angband_term_name[i]);
+
+ /* Instance names should start with a lowercase letter XXX */
+ for (p = (char *)td->name; *p; p++) *p = tolower(*p);
+
+ /* Use a "soft" cursor */
+ t->soft_cursor = TRUE;
+
+ /* Erase with "white space" */
+ t->attr_blank = TERM_WHITE;
+ t->char_blank = ' ';
+
+ t->xtra_hook = Term_xtra_gtk;
+ t->text_hook = Term_text_gtk;
+ t->wipe_hook = Term_wipe_gtk;
+ t->curs_hook = Term_curs_gtk;
+#ifdef USE_GRAPHICS
+ t->pict_hook = Term_pict_gtk;
+#endif /* USE_GRAPHICS */
+ t->nuke_hook = Term_nuke_gtk;
+
+ /* Save the data */
+ t->data = td;
+
+ /* Activate (important) */
+ Term_activate(t);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Neater menu code with GtkItemFactory.
+ *
+ * Menu bar of the Angband window
+ *
+ * Entry format: Path, Accelerator, Callback, Callback arg, type
+ * where type is one of:
+ * <Item> - simple item, alias NULL
+ * <Branch> - has submenu
+ * <Separator> - as you read it
+ * <CheckItem> - has a check mark
+ * <ToggleItem> - is a toggle
+ */
+static GtkItemFactoryEntry main_menu_items[] =
+{
+ /* "File" menu */
+ { "/File", NULL,
+ NULL, 0, "<Branch>", NULL
+ },
+#ifndef SAVEFILE_SCREEN
+ { "/File/New", "<mod1>N",
+ new_event_handler, 0, NULL, NULL },
+ { "/File/Open", "<mod1>O",
+ open_event_handler, 0, NULL, NULL },
+ { "/File/sep1", NULL,
+ NULL, 0, "<Separator>", NULL },
+#endif /* !SAVEFILE_SCREEN */
+ { "/File/Save", "<mod1>S",
+ save_event_handler, 0, NULL, NULL },
+ { "/File/Quit", "<mod1>Q",
+ quit_event_handler, 0, NULL, NULL },
+
+ /* "Terms" menu */
+ { "/Terms", NULL,
+ NULL, 0, "<Branch>", NULL },
+ /* XXX XXX XXX NULL's are replaced by the program */
+ { NULL, "<mod1>0",
+ term_event_handler, 0, "<CheckItem>", NULL },
+ { NULL, "<mod1>1",
+ term_event_handler, 1, "<CheckItem>", NULL },
+ { NULL, "<mod1>2",
+ term_event_handler, 2, "<CheckItem>", NULL },
+ { NULL, "<mod1>3",
+ term_event_handler, 3, "<CheckItem>", NULL },
+ { NULL, "<mod1>4",
+ term_event_handler, 4, "<CheckItem>", NULL },
+ { NULL, "<mod1>5",
+ term_event_handler, 5, "<CheckItem>", NULL },
+ { NULL, "<mod1>6",
+ term_event_handler, 6, "<CheckItem>", NULL },
+ { NULL, "<mod1>7",
+ term_event_handler, 7, "<CheckItem>", NULL },
+
+ /* "Options" menu */
+ { "/Options", NULL,
+ NULL, 0, "<Branch>", NULL },
+
+ /* "Font" submenu */
+ { "/Options/Font", NULL,
+ NULL, 0, "<Branch>", NULL },
+ /* XXX XXX XXX Again, NULL's are filled by the program */
+ { NULL, NULL,
+ change_font_event_handler, 0, NULL, NULL },
+ { NULL, NULL,
+ change_font_event_handler, 1, NULL, NULL },
+ { NULL, NULL,
+ change_font_event_handler, 2, NULL, NULL },
+ { NULL, NULL,
+ change_font_event_handler, 3, NULL, NULL },
+ { NULL, NULL,
+ change_font_event_handler, 4, NULL, NULL },
+ { NULL, NULL,
+ change_font_event_handler, 5, NULL, NULL },
+ { NULL, NULL,
+ change_font_event_handler, 6, NULL, NULL },
+ { NULL, NULL,
+ change_font_event_handler, 7, NULL, NULL },
+
+#ifdef USE_GRAPHICS
+
+ /* "Graphics" submenu */
+ { "/Options/Graphics", NULL,
+ NULL, 0, "<Branch>", NULL },
+ { "/Options/Graphics/None", NULL,
+ change_graf_mode_event_handler, GRAF_MODE_NONE, "<CheckItem>", NULL },
+ { "/Options/Graphics/Old", NULL,
+ change_graf_mode_event_handler, GRAF_MODE_OLD, "<CheckItem>", NULL },
+ { "/Options/Graphics/New", NULL,
+ change_graf_mode_event_handler, GRAF_MODE_NEW, "<CheckItem>", NULL },
+# ifdef USE_DOUBLE_TILES
+ { "/Options/Graphics/sep3", NULL,
+ NULL, 0, "<Separator>", NULL },
+ { "/Options/Graphics/Wide tiles", NULL,
+ change_wide_tile_mode_event_handler, 0, "<CheckItem>", NULL },
+# endif /* USE_DOUBLE_TILES */
+ { "/Options/Graphics/sep1", NULL,
+ NULL, 0, "<Separator>", NULL },
+ { "/Options/Graphics/Dither if <= 8bpp", NULL,
+ change_dith_mode_event_handler, GDK_RGB_DITHER_NORMAL, "<CheckItem>", NULL },
+ { "/Options/Graphics/Dither if <= 16bpp", NULL,
+ change_dith_mode_event_handler, GDK_RGB_DITHER_MAX, "<CheckItem>", NULL },
+ { "/Options/Graphics/sep2", NULL,
+ NULL, 0, "<Separator>", NULL },
+ { "/Options/Graphics/Smoothing", NULL,
+ change_smooth_mode_event_handler, 0, "<CheckItem>", NULL },
+ { "/Options/Graphics/Transparency", NULL,
+ change_trans_mode_event_handler, 0, "<CheckItem>", NULL },
+
+#endif /* USE_GRAPHICS */
+
+ /* "Misc" submenu */
+ { "/Options/Misc", NULL,
+ NULL, 0, "<Branch>", NULL },
+ { "/Options/Misc/Backing store", NULL,
+ change_backing_store_event_handler, 0, "<CheckItem>", NULL },
+};
+
+
+/*
+ * XXX XXX Fill those NULL's in the menu definition with
+ * angband_term_name[] strings
+ */
+static void setup_menu_paths(void)
+{
+ int i;
+ int nmenu_items = sizeof(main_menu_items) / sizeof(main_menu_items[0]);
+ GtkItemFactoryEntry *term_entry, *font_entry;
+ char buf[64];
+
+ /* Find the "Terms" menu */
+ for (i = 0; i < nmenu_items; i++)
+ {
+ /* Skip NULLs */
+ if (main_menu_items[i].path == NULL) continue;
+
+ /* Find a match */
+ if (streq(main_menu_items[i].path, "/Terms")) break;
+ }
+ g_assert(i < (nmenu_items - MAX_TERM_DATA));
+
+ /* Remember the location */
+ term_entry = &main_menu_items[i + 1];
+
+ /* Find "Font" menu */
+ for (i = 0; i < nmenu_items; i++)
+ {
+ /* Skip NULLs */
+ if (main_menu_items[i].path == NULL) continue;
+
+ /* Find a match */
+ if (streq(main_menu_items[i].path, "/Options/Font")) break;
+ }
+ g_assert(i < (nmenu_items - MAX_TERM_DATA));
+
+ /* Remember the location */
+ font_entry = &main_menu_items[i + 1];
+
+ /* For each terminal */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* XXX XXX Build the real path name to the entry */
+ strnfmt(buf, 64, "/Terms/%s", angband_term_name[i]);
+
+ /* XXX XXX Store it in the menu definition */
+ term_entry[i].path = (gchar*)string_make(buf);
+
+ /* XXX XXX Build the real path name to the entry */
+ strnfmt(buf, 64, "/Options/Font/%s", angband_term_name[i]);
+
+ /* XXX XXX Store it in the menu definition */
+ font_entry[i].path = (gchar*)string_make(buf);
+ }
+}
+
+
+/*
+ * XXX XXX Free strings allocated by setup_menu_paths()
+ */
+static void free_menu_paths(void)
+{
+ int i;
+ int nmenu_items = sizeof(main_menu_items) / sizeof(main_menu_items[0]);
+ GtkItemFactoryEntry *term_entry, *font_entry;
+
+ /* Find the "Terms" menu */
+ for (i = 0; i < nmenu_items; i++)
+ {
+ /* Skip NULLs */
+ if (main_menu_items[i].path == NULL) continue;
+
+ /* Find a match */
+ if (streq(main_menu_items[i].path, "/Terms")) break;
+ }
+ g_assert(i < (nmenu_items - MAX_TERM_DATA));
+
+ /* Remember the location */
+ term_entry = &main_menu_items[i + 1];
+
+ /* Find "Font" menu */
+ for (i = 0; i < nmenu_items; i++)
+ {
+ /* Skip NULLs */
+ if (main_menu_items[i].path == NULL) continue;
+
+ /* Find a match */
+ if (streq(main_menu_items[i].path, "/Options/Font")) break;
+ }
+ g_assert(i < (nmenu_items - MAX_TERM_DATA));
+
+ /* Remember the location */
+ font_entry = &main_menu_items[i + 1];
+
+ /* For each terminal */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* XXX XXX Free Term menu path */
+ if (term_entry[i].path) string_free((cptr)term_entry[i].path);
+
+ /* XXX XXX Free Font menu path */
+ if (font_entry[i].path) string_free((cptr)font_entry[i].path);
+ }
+}
+
+
+/*
+ * Find widget corresponding to path name
+ * return NULL on error
+ */
+static GtkWidget *get_widget_from_path(cptr path)
+{
+ GtkItemFactory *item_factory;
+ GtkWidget *widget;
+
+ /* Paranoia */
+ if (path == NULL) return (NULL);
+
+ /* Look up item factory */
+ item_factory = gtk_item_factory_from_path(path);
+
+ /* Oops */
+ if (item_factory == NULL) return (NULL);
+
+ /* Look up widget */
+ widget = gtk_item_factory_get_widget(item_factory, path);
+
+ /* Return result */
+ return (widget);
+}
+
+
+/*
+ * Enable/disable a menu item
+ */
+void enable_menu_item(cptr path, bool_ enabled)
+{
+ GtkWidget *widget;
+
+ /* Access menu item widget */
+ widget = get_widget_from_path(path);
+
+ /* Paranoia */
+ g_assert(widget != NULL);
+ g_assert(GTK_IS_MENU_ITEM(widget));
+
+ /*
+ * In Gtk's terminology, enabled is sensitive
+ * and disabled insensitive
+ */
+ gtk_widget_set_sensitive(widget, enabled);
+}
+
+
+/*
+ * Check/uncheck a menu item. The item should be of the GtkCheckMenuItem type
+ */
+void check_menu_item(cptr path, bool_ checked)
+{
+ GtkWidget *widget;
+
+ /* Access menu item widget */
+ widget = get_widget_from_path(path);
+
+ /* Paranoia */
+ g_assert(widget != NULL);
+ g_assert(GTK_IS_CHECK_MENU_ITEM(widget));
+
+ /*
+ * Put/remove check mark
+ *
+ * Mega-Hack -- The function supposed to be used here,
+ * gtk_check_menu_item_set_active(), emits an "activate" signal
+ * to the GtkMenuItem class of the widget, as if the menu item
+ * were selected by user, thereby causing bizarre behaviour.
+ * XXX XXX XXX
+ */
+ GTK_CHECK_MENU_ITEM(widget)->active = checked;
+}
+
+
+/*
+ * Update the "File" menu
+ */
+static void file_menu_update_handler(
+ GtkWidget *widget,
+ gpointer user_data)
+{
+#ifndef SAVEFILE_SCREEN
+ bool_ game_start_ok;
+#endif /* !SAVEFILE_SCREEN */
+ bool_ save_ok, quit_ok;
+
+#ifndef SAVEFILE_SCREEN
+
+ /* Can we start a game now? */
+ game_start_ok = !game_in_progress;
+
+#endif /* !SAVEFILE_SCREEN */
+
+ /* Cave we save/quit now? */
+ if (!character_generated || !game_in_progress)
+ {
+ save_ok = FALSE;
+ quit_ok = TRUE;
+ }
+ else
+ {
+ if (inkey_flag && can_save) save_ok = quit_ok = TRUE;
+ else save_ok = quit_ok = FALSE;
+ }
+
+ /* Enable / disable menu items according to those conditions */
+#ifndef SAVEFILE_SCREEN
+ enable_menu_item("<Angband>/File/New", game_start_ok);
+ enable_menu_item("<Angband>/File/Open", game_start_ok);
+#endif /* !SAVEFILE_SCREEN */
+ enable_menu_item("<Angband>/File/Save", save_ok);
+ enable_menu_item("<Angband>/File/Quit", quit_ok);
+}
+
+
+/*
+ * Update the "Terms" menu
+ */
+static void term_menu_update_handler(
+ GtkWidget *widget,
+ gpointer user_data)
+{
+ int i;
+ char buf[64];
+
+ /* For each term */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* Build the path name */
+ strnfmt(buf, 64, "<Angband>/Terms/%s", angband_term_name[i]);
+
+ /* Update the check mark on the item */
+ check_menu_item(buf, data[i].shown);
+ }
+}
+
+
+/*
+ * Update the "Font" submenu
+ */
+static void font_menu_update_handler(
+ GtkWidget *widget,
+ gpointer user_data)
+{
+ int i;
+ char buf[64];
+
+ /* For each term */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* Build the path name */
+ strnfmt(buf, 64, "<Angband>/Options/Font/%s", angband_term_name[i]);
+
+ /* Enable selection if the term is shown */
+ enable_menu_item(buf, data[i].shown);
+ }
+}
+
+
+/*
+ * Update the "Misc" submenu
+ */
+static void misc_menu_update_handler(
+ GtkWidget *widget,
+ gpointer user_data)
+{
+ /* Update an item */
+ check_menu_item(
+ "<Angband>/Options/Misc/Backing store",
+ use_backing_store);
+}
+
+
+#ifdef USE_GRAPHICS
+
+/*
+ * Update the "Graphics" submenu
+ */
+static void graf_menu_update_handler(
+ GtkWidget *widget,
+ gpointer user_data)
+{
+ /* Update menu items */
+ check_menu_item(
+ "<Angband>/Options/Graphics/None",
+ (graf_mode == GRAF_MODE_NONE));
+ check_menu_item(
+ "<Angband>/Options/Graphics/Old",
+ (graf_mode == GRAF_MODE_OLD));
+ check_menu_item(
+ "<Angband>/Options/Graphics/New",
+ (graf_mode == GRAF_MODE_NEW));
+
+#ifdef USE_DOUBLE_TILES
+
+ check_menu_item(
+ "<Angband>/Options/Graphics/Wide tiles",
+ use_bigtile);
+
+#endif /* USE_DOUBLE_TILES */
+
+ check_menu_item(
+ "<Angband>/Options/Graphics/Dither if <= 8bpp",
+ (dith_mode == GDK_RGB_DITHER_NORMAL));
+ check_menu_item(
+ "<Angband>/Options/Graphics/Dither if <= 16bpp",
+ (dith_mode == GDK_RGB_DITHER_MAX));
+
+ check_menu_item(
+ "<Angband>/Options/Graphics/Smoothing",
+ smooth_rescaling);
+
+ check_menu_item(
+ "<Angband>/Options/Graphics/Transparency",
+ use_transparency);
+}
+
+#endif /* USE_GRAPHICS */
+
+
+/*
+ * Construct a menu hierarchy using GtkItemFactory, setting up
+ * callbacks and accelerators along the way, and return
+ * a GtkMenuBar widget.
+ */
+GtkWidget *get_main_menu(term_data *td)
+{
+ GtkItemFactory *item_factory;
+ GtkAccelGroup *accel_group;
+ gint nmenu_items = sizeof(main_menu_items) / sizeof(main_menu_items[0]);
+
+
+ /* XXX XXX Setup path names in the "Terms" and "Font" menus */
+ setup_menu_paths();
+
+ /* Allocate an accelerator group */
+ accel_group = gtk_accel_group_new();
+ g_assert(accel_group != NULL);
+
+ /* Initialise the item factory */
+ item_factory = gtk_item_factory_new(
+ GTK_TYPE_MENU_BAR,
+ "<Angband>",
+ accel_group);
+ g_assert(item_factory != NULL);
+
+ /* Generate the menu items */
+ gtk_item_factory_create_items(
+ item_factory,
+ nmenu_items,
+ main_menu_items,
+ NULL);
+
+ /* Attach the new accelerator group to the window */
+ gtk_window_add_accel_group(
+ GTK_WINDOW(td->window),
+ accel_group);
+
+ /* Return the actual menu bar created */
+ return (gtk_item_factory_get_widget(item_factory, "<Angband>"));
+}
+
+
+/*
+ * Install callbacks to update menus
+ */
+static void add_menu_update_callbacks()
+{
+ GtkWidget *widget;
+
+ /* Access the "File" menu */
+ widget = get_widget_from_path("<Angband>/File");
+
+ /* Paranoia */
+ g_assert(widget != NULL);
+ g_assert(GTK_IS_MENU(widget));
+
+ /* Assign callback */
+ gtk_signal_connect(
+ GTK_OBJECT(widget),
+ "show",
+ GTK_SIGNAL_FUNC(file_menu_update_handler),
+ NULL);
+
+ /* Access the "Terms" menu */
+ widget = get_widget_from_path("<Angband>/Terms");
+
+ /* Paranoia */
+ g_assert(widget != NULL);
+ g_assert(GTK_IS_MENU(widget));
+
+ /* Assign callback */
+ gtk_signal_connect(
+ GTK_OBJECT(widget),
+ "show",
+ GTK_SIGNAL_FUNC(term_menu_update_handler),
+ NULL);
+
+ /* Access the "Font" menu */
+ widget = get_widget_from_path("<Angband>/Options/Font");
+
+ /* Paranoia */
+ g_assert(widget != NULL);
+ g_assert(GTK_IS_MENU(widget));
+
+ /* Assign callback */
+ gtk_signal_connect(
+ GTK_OBJECT(widget),
+ "show",
+ GTK_SIGNAL_FUNC(font_menu_update_handler),
+ NULL);
+
+ /* Access the "Misc" menu */
+ widget = get_widget_from_path("<Angband>/Options/Misc");
+
+ /* Paranoia */
+ g_assert(widget != NULL);
+ g_assert(GTK_IS_MENU(widget));
+
+ /* Assign callback */
+ gtk_signal_connect(
+ GTK_OBJECT(widget),
+ "show",
+ GTK_SIGNAL_FUNC(misc_menu_update_handler),
+ NULL);
+
+#ifdef USE_GRAPHICS
+
+ /* Access Graphics menu */
+ widget = get_widget_from_path("<Angband>/Options/Graphics");
+
+ /* Paranoia */
+ g_assert(widget != NULL);
+ g_assert(GTK_IS_MENU(widget));
+
+ /* Assign callback */
+ gtk_signal_connect(
+ GTK_OBJECT(widget),
+ "show",
+ GTK_SIGNAL_FUNC(graf_menu_update_handler),
+ NULL);
+
+#endif /* USE_GRAPHICS */
+}
+
+
+/*
+ * Create Gtk widgets for a terminal window and set up callbacks
+ */
+static void init_gtk_window(term_data *td, int i)
+{
+ GtkWidget *menu_bar = NULL, *box;
+ cptr font;
+
+ bool_ main_window = (i == 0) ? TRUE : FALSE;
+
+
+ /* Create window */
+ td->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ /* Set title */
+ gtk_window_set_title(GTK_WINDOW(td->window), td->name);
+
+
+ /* Get default font for this term */
+ font = get_default_font(i);
+
+ /* Load font and initialise related term_data fields */
+ load_font(td, font);
+
+
+ /* Create drawing area */
+ td->drawing_area = gtk_drawing_area_new();
+
+ /* Set the size of the drawing area */
+ gtk_drawing_area_size(
+ GTK_DRAWING_AREA(td->drawing_area),
+ td->cols * td->font_wid,
+ td->rows * td->font_hgt);
+
+ /* Set geometry hints */
+ term_data_set_geometry_hints(td);
+
+
+ /* Install window event handlers */
+ gtk_signal_connect(
+ GTK_OBJECT(td->window),
+ "delete_event",
+ GTK_SIGNAL_FUNC(delete_event_handler),
+ NULL);
+ gtk_signal_connect(
+ GTK_OBJECT(td->window),
+ "key_press_event",
+ GTK_SIGNAL_FUNC(keypress_event_handler),
+ NULL);
+
+ /* Destroying the Angband window terminates the game */
+ if (main_window)
+ {
+ gtk_signal_connect(
+ GTK_OBJECT(td->window),
+ "destroy_event",
+ GTK_SIGNAL_FUNC(destroy_main_event_handler),
+ NULL);
+ }
+
+ /* The other windows are just hidden */
+ else
+ {
+ gtk_signal_connect(
+ GTK_OBJECT(td->window),
+ "destroy_event",
+ GTK_SIGNAL_FUNC(destroy_sub_event_handler),
+ td);
+ }
+
+
+ /* Install drawing area event handlers */
+ gtk_signal_connect(
+ GTK_OBJECT(td->drawing_area),
+ "realize",
+ GTK_SIGNAL_FUNC(realize_event_handler),
+ (gpointer)td);
+ gtk_signal_connect(
+ GTK_OBJECT(td->drawing_area),
+ "show",
+ GTK_SIGNAL_FUNC(show_event_handler),
+ (gpointer)td);
+ gtk_signal_connect(
+ GTK_OBJECT(td->drawing_area),
+ "hide",
+ GTK_SIGNAL_FUNC(hide_event_handler),
+ (gpointer)td);
+ gtk_signal_connect(
+ GTK_OBJECT(td->drawing_area),
+ "size_allocate",
+ GTK_SIGNAL_FUNC(size_allocate_event_handler),
+ (gpointer)td);
+ gtk_signal_connect(
+ GTK_OBJECT(td->drawing_area),
+ "expose_event",
+ GTK_SIGNAL_FUNC(expose_event_handler),
+ (gpointer)td);
+
+
+ /* Create menu */
+ if (main_window)
+ {
+ /* Build the main menu bar */
+ menu_bar = get_main_menu(td);
+ g_assert(menu_bar != NULL);
+
+ /* Since it's tedious to scatter the menu update code around */
+ add_menu_update_callbacks();
+ }
+
+
+ /* Pack the menu bar together with the main window */
+ /* For vertical placement of the menu bar and the drawing area */
+ box = gtk_vbox_new(FALSE, 0);
+
+ /* Let the window widget own it */
+ gtk_container_add(GTK_CONTAINER(td->window), box);
+
+ /* The main window has a menu bar */
+ if (main_window)
+ gtk_box_pack_start(
+ GTK_BOX(box),
+ menu_bar,
+ FALSE,
+ FALSE,
+ NO_PADDING);
+
+ /* And place the drawing area just beneath it */
+ gtk_box_pack_start_defaults(GTK_BOX(box), td->drawing_area);
+
+
+ /* Show the widgets - use of td->shown is a dirty hack XXX XXX */
+ if (td->shown) gtk_widget_show_all(td->window);
+}
+
+
+/*
+ * To be hooked into quit(). See z-util.c
+ */
+static void hook_quit(cptr str)
+{
+ /* Free menu paths dynamically allocated */
+ free_menu_paths();
+
+# ifdef USE_GRAPHICS
+
+ /* Free pathname string */
+ if (ANGBAND_DIR_XTRA_GRAF) string_free(ANGBAND_DIR_XTRA_GRAF);
+
+# endif /* USE_GRAPHICS */
+
+ /* Terminate the program */
+ gtk_exit(0);
+}
+
+
+#ifdef ANGBAND300
+
+/*
+ * Help message for this port
+ */
+const char help_gtk[] =
+ "GTK for X11, subopts -n<windows>\n"
+ " -b(acking store off)\n"
+#ifdef USE_GRAPHICS
+ " -g(raphics) -o(ld graphics) -s(moothscaling off) \n"
+ " -t(ransparency on)\n"
+# ifdef USE_DOUBLE_TILES
+ " -w(ide tiles)\n"
+# endif /* USE_DOUBLE_TILES */
+#endif /* USE_GRAPHICS */
+ " and standard GTK options";
+
+#endif /* ANGBAND300 */
+
+
+/*
+ * Initialization function
+ */
+errr init_gtk2(int argc, char **argv)
+{
+ int i;
+
+
+ /* Initialize the environment */
+ gtk_init(&argc, &argv);
+
+ /* Activate hooks - Use gtk/glib interface throughout */
+ ralloc_aux = hook_ralloc;
+ rnfree_aux = hook_rnfree;
+ quit_aux = hook_quit;
+ core_aux = hook_quit;
+
+ /* Parse args */
+ for (i = 1; i < argc; i++)
+ {
+ /* Number of terminals displayed at start up */
+ if (prefix(argv[i], "-n"))
+ {
+ num_term = atoi(&argv[i][2]);
+ if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
+ else if (num_term < 1) num_term = 1;
+ continue;
+ }
+
+ /* Disable use of pixmaps as backing store */
+ if (streq(argv[i], "-b"))
+ {
+ use_backing_store = FALSE;
+ continue;
+ }
+
+#ifdef USE_GRAPHICS
+
+ /* Requests "old" graphics */
+ if (streq(argv[i], "-o"))
+ {
+ graf_mode_request = GRAF_MODE_OLD;
+ continue;
+ }
+
+ /* Requests "new" graphics */
+ if (streq(argv[i], "-g"))
+ {
+ graf_mode_request = GRAF_MODE_NEW;
+ continue;
+ }
+
+# ifdef USE_DOUBLE_TILES
+
+ /* Requests wide tile mode */
+ if (streq(argv[i], "-w"))
+ {
+ use_bigtile = TRUE;
+# ifdef TOME
+ /* T.o.M.E. uses older version of the patch */
+ arg_bigtile = TRUE;
+# endif /* TOME */
+ continue;
+ }
+
+# endif /* USE_DOUBLE_TILES */
+
+
+ /* Enable transparency effect */
+ if (streq(argv[i], "-t"))
+ {
+ use_transparency = TRUE;
+ continue;
+ }
+
+ /* Disable smooth rescaling of tiles */
+ if (streq(argv[i], "-s"))
+ {
+ smooth_rescaling_request = FALSE;
+ continue;
+ }
+
+#endif /* USE_GRAPHICS */
+
+ /* None of the above */
+ plog_fmt("Ignoring option: %s", argv[i]);
+ }
+
+#ifdef USE_GRAPHICS
+
+ {
+ char path[1024];
+
+ /* Build the "graf" path */
+ path_build(path, 1024, ANGBAND_DIR_XTRA, "graf");
+
+ /* Allocate the path */
+ ANGBAND_DIR_XTRA_GRAF = string_make(path);
+ }
+
+#endif /* USE_GRAPHICS */
+
+ /* Initialise colours */
+ gdk_rgb_init();
+ gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
+ gtk_widget_set_default_visual(gdk_rgb_get_visual());
+ init_colours();
+
+ /*
+ * Initialise the windows backwards, so that
+ * the Angband window comes in front
+ */
+ for (i = MAX_TERM_DATA - 1; i >= 0; i--)
+ {
+ term_data *td = &data[i];
+
+ /* Initialize the term_data */
+ term_data_init(td, i);
+
+ /* Hack - Set the shown flag, meaning "to be shown" XXX XXX */
+ if (i < num_term) td->shown = TRUE;
+ else td->shown = FALSE;
+
+ /* Save global entry */
+ angband_term[i] = Term;
+
+ /* Init the window */
+ init_gtk_window(td, i);
+ }
+
+ /* Activate the "Angband" window screen */
+ Term_activate(&data[0].t);
+
+#ifndef SAVEFILE_SCREEN
+
+ /* Set the system suffix */
+ ANGBAND_SYS = "gtk";
+
+ /* Catch nasty signals */
+ signals_init();
+
+ /* Initialize */
+ init_angband();
+
+#ifndef OLD_SAVEFILE_CODE
+
+ /* Hack - because this port has New/Open menus XXX */
+ savefile[0] = '\0';
+
+#endif /* !OLD_SAVEFILE_CODE */
+
+ /* Prompt the user */
+ prt("[Choose 'New' or 'Open' from the 'File' menu]", 23, 17);
+ Term_fresh();
+
+ /* Activate more hook */
+ plog_aux = hook_plog;
+
+
+ /* Processing loop */
+ gtk_main();
+
+
+ /* Free allocated memory */
+ cleanup_angband();
+
+ /* Stop now */
+ quit(NULL);
+
+#else /* !SAVEFILE_SCREEN */
+
+ /* Activate more hook */
+ plog_aux = hook_plog;
+
+ /* It's too early to set this, but cannot do so elsewhere XXX XXX */
+ game_in_progress = TRUE;
+
+#endif /* !SAVEFILE_SCREEN */
+
+ /* Success */
+ return (0);
+}
+
+#endif /* USE_GTK2 */
diff --git a/src/main-sdl.c b/src/main-sdl.c
new file mode 100644
index 00000000..1b53cfc7
--- /dev/null
+++ b/src/main-sdl.c
@@ -0,0 +1,2253 @@
+/* Copyright (C) 2003-2004 Neil Stevens <neil@hakubi.us>
+ // Copyright (C) 2004 Ethan Stump <estump@seas.upenn.edu>
+ //
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
+ // of this software and associated documentation files (the "Software"), to deal
+ // in the Software without restriction, including without limitation the rights
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ // copies of the Software, and to permit persons to whom the Software is
+ // furnished to do so, subject to the following conditions:
+ //
+ // The above copyright notice and this permission notice shall be included in
+ // all copies or substantial portions of the Software.
+ //
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ // THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ //
+ // Except as contained in this notice, the name(s) of the author(s) shall not be
+ // used in advertising or otherwise to promote the sale, use or other dealings
+ // in this Software without prior written authorization from the author(s).
+ */
+
+#ifdef USE_SDL
+
+#include "angband.h"
+#include <SDL.h>
+#include <SDL_image.h>
+#include <SDL_ttf.h>
+
+#include <math.h>
+
+/*************************************************
+ GLOBAL SDL-ToME PROPERTIES
+ *************************************************/
+
+/*Main window properties that may be loaded at runtime from
+a preference file or environmental variables. However,
+default values (defined above) can be used. */
+static int arg_width = 0;
+static int arg_height = 0;
+static int arg_bpp = 16;
+
+/**************/
+
+/* Default font properties - used unless otherwise changed.
+These properties are the size and also default font to load. */
+#define DEF_FONT_SIZE 14
+#define DEF_FONT_FILE "VeraMono.ttf"
+
+/* The font properties that may perhaps be changed at runtime,
+due to environmental variables, preference files, or in-program
+commands.*/
+static int arg_font_size = DEF_FONT_SIZE;
+static char arg_font_name[64] = DEF_FONT_FILE;
+
+/**************/
+
+/* Graphics setting - signifies what graphics to use. Valid ints
+are available with given defines */
+
+/* No graphics - use only colored text */
+#define NO_GRAPHICS 0
+/* "Old" graphics - use 8x8.bmp to extract graphics tiles */
+#define GRAPHICS_8x8 8
+/* "New" graphics - use 16x16.bmp as tiles and apply mask.bmp for transparency*/
+#define GRAPHICS_16x16 16
+
+static int arg_graphics_type = NO_GRAPHICS;
+
+
+/**************/
+
+/* The number of term_data structures to set aside mem for */
+#define MAX_CONSOLE_COUNT 8
+
+/* The number of consoles that are actually being used.
+This number could be changed via preference files, environmental
+variables, command-line arguments, or possibly even in-game
+keypresses or menu-selections. */
+static int arg_console_count = 1;
+
+/* When rendering multiple terminals, each is drawn with a
+surrounding border. This value controls the width of this
+border */
+#define BORDER_THICKNESS 1
+
+/**************/
+
+/* some miscellaneous settings which have not been dealt
+with yet */
+static bool_ arg_double_width = FALSE;
+
+/* flag signifying whether the game is in full screen */
+static bool_ arg_full_screen = FALSE;
+
+/* a flag to show whether window properties have been
+set or not... if so, the properties can be dumped
+upon quit*/
+static bool_ window_properties_set = FALSE;
+
+/*************************************************
+ GLOBAL SDL-ToME VARIABLES
+ *************************************************/
+
+/* the main screen to draw to */
+static SDL_Surface *screen;
+
+/* the video settings for the system */
+static SDL_VideoInfo *videoInfo;
+
+/* a flag to suspend updating of the screen;
+this is in place so that when a large area is being
+redrawn -- like when doing a Term_redraw() or when
+redoing the entire screen -- all of the changes
+can be stored up before doing an update. This
+should cut down on screen flicker */
+static bool_ suspendUpdate = FALSE;
+
+/* some helper surfaces that are used for rendering
+characters */
+static SDL_Surface *worksurf;
+static SDL_Surface *crayon;
+
+/* the cursor surface */
+static SDL_Surface *cursor = NULL;
+
+/* the array of pre-rendered characters
+(see loadAndRenderFont() below) */
+SDL_Surface *text[128];
+
+/* the actual TTF_Font used (XXX should get rid of this)*/
+TTF_Font *font=0;
+
+/* the width and height of the uniformly-sized pre-rendered
+characters */
+int t_width = 0, t_height = 0;
+
+
+/*************************************************
+ COLOR SETUP
+ *************************************************/
+
+/* Simple black, mapped using the format of the main screen */
+int screen_black;
+
+/* The color to use for the cursor */
+static int cursor_color = 0;
+/* default cursor color is a semi-transparent yellow */
+#define DEF_CURSOR_COLOR 255,255,0,128
+
+/* The array of colors, mapped to the format of the crayon surface,
+since this is ultimately the surface that color is begin applied to */
+static int color_data[16];
+
+/* The following macro is for color defining...
+ Note that the color is fully opaque... */
+#define COLOR(r,g,b) \
+ SDL_MapRGBA(crayon->format,r,g,b,SDL_ALPHA_OPAQUE)
+
+/*These color macros will setup the colors to use, but must be called after
+ the SDL video has been set. That way SDL can correct for any funky video
+ setttings. */
+
+#define BLACK COLOR( 0, 0, 0) /* 0*/
+#define WHITE COLOR(255,255,255) /* 1*/
+#define MID_GREY COLOR(128,128,128) /* 2*/
+#define BRIGHT_ORANGE COLOR(255,128, 0) /* 3*/
+#define RED COLOR(192, 0, 0) /* 4*/
+#define GREEN COLOR( 0,128, 64) /* 5*/
+#define BRIGHT_BLUE COLOR( 0, 0,255) /* 6*/
+#define DARK_ORANGE COLOR(128, 64, 0) /* 7*/
+#define DARK_GREY COLOR( 64, 64, 64) /* 8*/
+#define BRIGHT_GREY COLOR(192,192,192) /* 9*/
+#define PURPLE COLOR(255, 0,255) /*10*/
+#define YELLOW COLOR(255,255, 0) /*11*/
+#define BRIGHT_RED COLOR(255, 0, 0) /*12*/
+#define BRIGHT_GREEN COLOR( 0,255, 0) /*13*/
+#define AQUAMARINE COLOR( 0,255,255) /*14*/
+#define BROWN COLOR(192,128, 64) /*15*/
+
+/*************************************************
+ TERMINAL DATA STRUCTURE SETUP
+ *************************************************/
+
+/* Forward declare */
+typedef struct _term_data term_data;
+
+/* A structure for each "term" */
+struct _term_data
+{
+ term t; /* the term structure, defined in z-term.h */
+ cptr name; /* name of this term sub-window */
+
+ uint rows, cols; /* row/column count */
+ SDL_Rect rect; /* the bounding rectangle for the entire box;
+ includes border and empty space as well */
+ /* this rectangle is in screen coordinates */
+
+ int border_thick; /* thickness of border to draw around window */
+ int border_color; /* current color of the border */
+ uint cushion_x_top, cushion_x_bot, cushion_y_top, cushion_y_bot;
+ /* empty space cushion between border and tiles */
+
+ uint tile_width; /* the width of each tile (graphic or otherwise)*/
+ uint tile_height; /* the height of each tile (graphic or otherwise)*/
+
+ SDL_Surface *surf; /* the surface that graphics for this screen are
+ rendered to before blitting to main screen */
+ int black,white,purple; /* basic colors keyed to this terminal's surface */
+
+};
+
+/* The array of term data structures */
+static term_data data[MAX_CONSOLE_COUNT];
+
+/* Ordered array of pointers to term data structures, placed in order of
+priority: lowest is on top of all others, the higher the index, the further
+back into the screen that it is drawn */
+static term_data *term_order[MAX_CONSOLE_COUNT];
+
+/*************************************************
+ FILE-SPECIFIC MACROS
+ *************************************************/
+
+/* Debug macros! */
+#define DB(str) \
+ printf("main-sdl: %s\n",str);
+
+/* Prints out the RGBA values of a given color */
+#define TYPECOLOR32(color) printf(" R:%d\tG:%d\tB:%d\tA:%d\t\n",\
+ color>>24,(color&0x00ff0000)>>16,\
+ (color&0x0000ff00)>>8,(color&0x000000ff))
+
+#define TYPECOLOR16(color) printf(" R:%d\tG:%d\tB:%d\tA:%d\t\n",\
+ (color&0xf000)>>12,(color&0x0f00)>>8,\
+ (color&0x00f0)>>4,(color&0x000f))
+
+/* SDL Surface locking and unlocking */
+#define SDL_LOCK(surf) \
+ if (SDL_MUSTLOCK(surf) ){ \
+ if (SDL_LockSurface(surf) < 0) { \
+ printf("Can't lock the screen: %s\n", SDL_GetError()); \
+ exit(1); \
+ } \
+ }
+
+#define SDL_UNLOCK(surf) \
+ if (SDL_MUSTLOCK(surf) ){ \
+ SDL_UnlockSurface(surf); \
+ }
+
+/* Wrapped SDL_UpdateRects function, to take into
+account the fact that updates may be suspended by
+the suspendUpdate flag... this macro should be used
+whenever a rect needs updated */
+#define SDL_UPDATE(rect) \
+ if (!suspendUpdate) \
+ SDL_UpdateRects(screen,1,&rect)
+
+/* A complete screen redraw macro */
+#define SDL_REDRAW_SCREEN \
+ SDL_UpdateRect(screen,0,0,arg_width,arg_height)
+
+/*************************************************
+ QUITTING
+ *************************************************/
+
+/* function prototype */
+void dumpWindowSettings(void);
+
+/* SDL Quitting function... declare a few functions first.*/
+void killFontAndAlphabet(void);
+static void sdl_quit(cptr string)
+{
+ printf("sdl_quit called.\n");
+ printf("message: %s\n",string);
+ /* Need to take care of font and rendered characters */
+ killFontAndAlphabet();
+ if (TTF_WasInit())
+ TTF_Quit();
+ /* Then exit SDL */
+ SDL_Quit();
+
+ /* Dump the window properties, if available */
+ if (window_properties_set)
+ dumpWindowSettings();
+
+ /* And now for the default quit behavior */
+ quit_aux = 0;
+ quit(string);
+}
+
+/*************************************************
+ FONT SUPPORT FUNCTIONS
+ *************************************************/
+
+/* function prototype for creating surfaces */
+SDL_Surface *createSurface(int width, int height);
+
+/* killFontAndAlphabet will effectively de-initialize the font system;
+it does this by closing the font and destroying any pre-rendered
+text in memory */
+void killFontAndAlphabet(void)
+{
+ int i;
+ /* need to close a font and free all of its corresponding pre-rendered
+ surfaces */
+ if (font)
+ {
+ TTF_CloseFont(font);
+ font = 0;
+ }
+ for (i=0;i<128;i++)
+ {
+ if(text[i])
+ {
+ SDL_FreeSurface(text[i]);
+ text[i] = NULL;
+ }
+ }
+}
+
+/* loadAndRenderFont is responsible for loading and initializing
+a font. First, SDL_ttf calls are made to load and set the style
+for the desired font. Next, a character alphabet is rendered and
+each character is placed onto a uniformly-sized surface within
+the text[] array. Whenever text is needed for displaying on-screen,
+this array is referenced and the desired character picture is used. */
+void loadAndRenderFont(char *fname, int size)
+{
+ int minx,maxx,miny,maxy,advance,i,midline = 0;
+ char filename[PATH_MAX + 1];
+ char fontdir[PATH_MAX + 1];
+ SDL_Color base_color = {255,255,255,255};
+ SDL_Surface *temp_surf;
+ SDL_Rect tgt = {0,0,0,0};
+
+
+ /* Assuming that the filename is valid,open the font */
+ path_build(fontdir, PATH_MAX, ANGBAND_DIR_XTRA, "font");
+ path_build(filename, PATH_MAX, fontdir, fname);
+ font = TTF_OpenFont(filename,size);
+ if (font == NULL)
+ sdl_quit("Error loading that font!");
+ /* Set the font style to normal */
+ TTF_SetFontStyle(font,TTF_STYLE_NORMAL);
+
+ /* Collect some measurements on this font -
+ arbitrarily choose the letter 'a' to get width*/
+ TTF_GlyphMetrics(font,'a',&minx,&maxx,&miny,&maxy,&advance);
+ /* the width of each character tile */
+ t_width = advance;
+ /* the height of each character tile */
+ t_height = TTF_FontHeight(font);
+ /* position of the y=0 line in each tile */
+ midline = TTF_FontAscent(font);
+
+ /* now... render each of the individual characters */
+ for (i=0;i<128;i++)
+ {
+ /* make a pretty blended glyph */
+ temp_surf=TTF_RenderGlyph_Blended(font,i,base_color);
+ /* and make sure that we got it right! */
+ if (temp_surf == NULL)
+ sdl_quit("Glyph failed to render!");
+ /* get the metrics of this particular glyph so we can position it */
+ TTF_GlyphMetrics(font,i,&minx,&maxx,&miny,&maxy,&advance);
+ /* copy rendered glyph into text queue, at the right position*/
+ tgt.x = minx;
+ tgt.y = midline-maxy;
+ /* but first... we'll need a surface in the text queue to blit to! */
+ text[i] = createSurface(t_width,t_height);
+ /* turn OFF src-alpha... results in brute
+ copy of the RGBA contents of surf */
+ SDL_SetAlpha(temp_surf,0,0);
+ SDL_BlitSurface(temp_surf,NULL,text[i],&tgt);
+ /* turn OFF src-alpha since we'll be using worksurf for blitting */
+ SDL_SetAlpha(text[i],0,0);
+ /* kill the surface to patch up memory leaks */
+ SDL_FreeSurface(temp_surf);
+ }
+}
+
+/* KEYPRESS_STRING repeatedly sends characters to the terminal
+XXX - should implement routine from maim-sdl.c, it's sooo much
+cleaner */
+#define KEYPRESS_STRING(str) \
+strcpy(buf,str); \
+n = buf; \
+while (*n != '\0') { \
+ Term_keypress((int)(*(n++))); \
+}
+
+/* function prototype */
+void manipulationMode(void);
+void redrawAllTerminals(void);
+/* This is the main event handling routine that will be called
+whenever an event is pulled off of the queue (in Term_xtra_sdl())*/
+void handleEvent(SDL_Event *event)
+{
+ static char buf[24]; /* a buffer used when passing key names */
+ char *n; /* and a pointer to manipulate this buffer */
+
+ switch( event->type )
+ {
+ case SDL_KEYDOWN:
+ {
+ /* handle key presses */
+
+ /* I'm reading that as long as the upper 9 bits of the unicode
+ * value are zero, then the lower 7 bits are direct ASCII characters.
+ * Furthermore, it seems that all basic keys return non-zero values
+ * for the lower 7 bits, but function keys and other various things
+ * return 0000000 for the lower 7 bits.
+ * Basically, if the lower 7 bits are zero, do something special
+ * (like start a macro), but otherwise just pass along the ASCII
+ * code!
+ */
+ byte ascii_part = event->key.keysym.unicode & 0x00ff;
+
+ /* gimme the key name */
+ printf("Key is: %s\n",SDL_GetKeyName(event->key.keysym.sym));
+
+ /* allow for full screen toggling! */
+ if ((event->key.keysym.sym == SDLK_RETURN) && \
+ (SDL_GetModState() & KMOD_ALT))
+ {
+ SDL_WM_ToggleFullScreen(screen);
+ /* toggle the internal full screen flag */
+ arg_full_screen = (arg_full_screen ? FALSE : TRUE);
+ }
+
+ /* entry into window manipulation mode */
+ if ((event->key.keysym.sym == SDLK_RETURN) && \
+ (SDL_GetModState() & KMOD_CTRL))
+ {
+ DB("Manipulation mode!");
+ manipulationMode();
+ }
+
+ /*printf("ascii_part: %d\n",ascii_part);*/
+ if (ascii_part)
+ {
+ /* We have now determined that the ASCII part is not '0', so
+ we can safely pass along the ASCII value! */
+ Term_keypress(ascii_part);
+ }
+ else
+ {
+ /* We want to ignore keypresses that are simply the modifier
+ keys*/
+ if (!( (event->key.keysym.sym == SDLK_RSHIFT) |
+ (event->key.keysym.sym == SDLK_LSHIFT) |
+ (event->key.keysym.sym == SDLK_RALT) |
+ (event->key.keysym.sym == SDLK_LALT) |
+ (event->key.keysym.sym == SDLK_RCTRL) |
+ (event->key.keysym.sym == SDLK_LCTRL) ))
+ {
+
+ /* now build a macro string using the modifiers together
+ with the key that was just pressed*/
+
+ /* As for the formatting...
+ * We pass the key press and modifiers as follows:
+ * \[ctrl-alt-shift-"key name"]
+ * following the previously established convention...
+ *
+ * All of the things that happen are defined in pref-sdl.prf
+ */
+
+ KEYPRESS_STRING("\["); /*Output the first part... */
+ /* See if a control key is down */
+ if (event->key.keysym.mod & KMOD_CTRL)
+ {
+ KEYPRESS_STRING("ctrl-");
+ }
+ /* See if an alt key is down */
+ if (event->key.keysym.mod & KMOD_ALT)
+ {
+ KEYPRESS_STRING("alt-");
+ }
+ /* See if a shift key is down */
+ if (event->key.keysym.mod & KMOD_SHIFT)
+ {
+ KEYPRESS_STRING("shift-");
+ }
+
+ /* Add in the name of whatever key was pressed */
+ KEYPRESS_STRING(SDL_GetKeyName(event->key.keysym.sym));
+
+ /* and end it... */
+ KEYPRESS_STRING("]");
+ }
+ }
+ break;
+ }
+ case SDL_QUIT:
+ {
+ /* handle quit requests */
+ DB("Emergency Blit");
+ redrawAllTerminals();
+ save_player();
+ save_dungeon();
+ sdl_quit("Quitting!\n");
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+/* declare the screen clearing function used below */
+void eraseTerminal();
+void drawTermStuff(term_data *td, SDL_Rect *rect);
+static errr Term_xtra_sdl(int n, int v)
+{
+ static SDL_Event event;
+ term_data *td;
+
+
+ /* Analyze */
+ switch (n)
+ {
+ case TERM_XTRA_EVENT:
+ {
+ if (v)
+ {
+ /* Perform event checking with blocking */
+ SDL_WaitEvent( &event );
+ handleEvent( &event );
+ } else {
+ /* Perform event checking without blocking */
+ if (SDL_PollEvent(&event)){
+ /* We found an event! */
+ handleEvent(&event);
+ }
+ }
+ return(0);
+ }
+
+ case TERM_XTRA_FLUSH:
+ {
+ /* Keep doing events until the queue is empty! */
+ while (SDL_PollEvent(&event))
+ {
+ handleEvent(&event);
+ }
+ return (0);
+ }
+
+ case TERM_XTRA_CLEAR:
+ {
+ /* Clear the terminal */
+ DB("TERM_XTRA_CLEAR");
+ suspendUpdate = TRUE;
+ eraseTerminal();
+ return (0);
+ }
+
+ case TERM_XTRA_SHAPE:
+ {
+ /*
+ * Set the cursor visibility XXX XXX XXX
+ *
+ * This action should change the visibility of the cursor,
+ * if possible, to the requested value (0=off, 1=on)
+ *
+ * This action is optional, but can improve both the
+ * efficiency (and attractiveness) of the program.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_FROSH:
+ {
+ /*
+ * Flush a row of output XXX XXX XXX
+ *
+ * This action should make sure that row "v" of the "output"
+ * to the window will actually appear on the window.
+ *
+ * This action is optional, assuming that "Term_text_xxx()"
+ * (and similar functions) draw directly to the screen, or
+ * that the "TERM_XTRA_FRESH" entry below takes care of any
+ * necessary flushing issues.
+ */
+
+ return (1);
+ }
+
+ case TERM_XTRA_FRESH:
+ {
+ /*
+ * Flush output XXX XXX XXX
+ *
+ * This action should make sure that all "output" to the
+ * window will actually appear on the window.
+ *
+ * This action is optional, assuming that "Term_text_xxx()"
+ * (and similar functions) draw directly to the screen, or
+ * that the "TERM_XTRA_FROSH" entry above takes care of any
+ * necessary flushing issues.
+ */
+
+ /* If terminal display has been held for any reason,
+ then update the whole thing now!*/
+ DB("TERM_XTRA_FRESH");
+ if (suspendUpdate)
+ {
+ DB(" update WAS suspended... updating now");
+ td = (term_data*)(Term->data);
+ suspendUpdate = FALSE;
+ drawTermStuff(td,NULL);
+ }
+ return (0);
+ }
+
+ case TERM_XTRA_NOISE:
+ {
+ /*
+ * Make a noise XXX XXX XXX
+ *
+ * This action should produce a "beep" noise.
+ *
+ * This action is optional, but convenient.
+ */
+
+ return (1);
+ }
+
+ case TERM_XTRA_SOUND:
+ {
+ /*
+ * Make a sound XXX XXX XXX
+ *
+ * This action should produce sound number "v", where the
+ * "name" of that sound is "sound_names[v]". This method
+ * is still under construction.
+ *
+ * This action is optional, and not very important.
+ */
+
+ return (1);
+ }
+
+ case TERM_XTRA_BORED:
+ {
+ /* Perform event checking without blocking */
+ if (SDL_PollEvent(&event)){
+ /* We found an event! */
+ handleEvent(&event);
+ }
+ return(0);
+ }
+
+ case TERM_XTRA_REACT:
+ {
+ /*
+ * React to global changes XXX XXX XXX
+ *
+ * For example, this action can be used to react to
+ * changes in the global "color_table[256][4]" array.
+ *
+ * This action is optional, but can be very useful for
+ * handling "color changes" and the "arg_sound" and/or
+ * "arg_graphics" options.
+ */
+ return (1);
+ }
+
+ case TERM_XTRA_ALIVE:
+ {
+ /*
+ * Change the "hard" level XXX XXX XXX
+ *
+ * This action is used if the program changes "aliveness"
+ * by being either "suspended" (v=0) or "resumed" (v=1)
+ * This action is optional, unless the computer uses the
+ * same "physical screen" for multiple programs, in which
+ * case this action should clean up to let other programs
+ * use the screen, or resume from such a cleaned up state.
+ *
+ * This action is currently only used by "main-gcu.c",
+ * on UNIX machines, to allow proper "suspending".
+ */
+
+ return (1);
+ }
+
+ case TERM_XTRA_LEVEL:
+ {
+ /*
+ * Change the "soft" level XXX XXX XXX
+ *
+ * This action is used when the term window changes "activation"
+ * either by becoming "inactive" (v=0) or "active" (v=1)
+ *
+ * This action can be used to do things like activate the proper
+ * font / drawing mode for the newly active term window. This
+ * action should NOT change which window has the "focus", which
+ * window is "raised", or anything like that.
+ *
+ * This action is optional if all the other things which depend
+ * on what term is active handle activation themself, or if only
+ * one "term_data" structure is supported by this file.
+ */
+
+ return (1);
+ }
+
+ case TERM_XTRA_DELAY:
+ {
+ /*
+ * Delay for some milliseconds XXX XXX XXX
+ *
+ * This action is useful for proper "timing" of certain
+ * visual effects, such as breath attacks.
+ *
+ * This action is optional, but may be required by this file,
+ * especially if special "macro sequences" must be supported.
+ */
+
+ /* I think that this command is system independent... */
+ /*sleep(v/1000);*/
+ /* main-x11 uses usleep(1000*v); */
+ /* main-win uses Sleep(v); */
+ return (1);
+ }
+
+ case TERM_XTRA_GET_DELAY:
+ {
+ /*
+ * Get Delay of some milliseconds XXX XXX XXX
+ * place the result in Term_xtra_long
+ *
+ * This action is useful for proper "timing" of certain
+ * visual effects, such as recording cmovies.
+ *
+ * This action is optional, but cmovies wont perform
+ * good without it
+ */
+
+ return (1);
+ }
+ }
+
+ /* Unknown or Unhandled action */
+ return (1);
+}
+
+/*************************************************
+ GRAPHICS ROUTINES
+ *************************************************/
+
+/* wrapper routine for creating an RGB surface with given height and
+ width that corresponds to desired color depth and respects the system
+ pixel format */
+SDL_Surface *createSurface(int width, int height)
+{
+ SDL_Surface *surf;
+ int surface_type;
+
+ if (videoInfo->hw_available)
+ surface_type = SDL_HWSURFACE;
+ else
+ surface_type = SDL_SWSURFACE;
+
+ /* XXX need to make RGBA masks correspond to system pixel format! */
+ switch (arg_bpp)
+ {
+ case 8:
+ {
+ /* I really don't know if 8 bpp is even possible, but here it is */
+ surf = SDL_CreateRGBSurface(surface_type,width,\
+ height,8,0xc0,0x30,0x0c,0x03);
+ break;
+ }
+ case 16:
+ {
+ surf = SDL_CreateRGBSurface(surface_type,width,\
+ height,16,0xf000,0x0f00,0x00f0,0x000f);
+ break;
+ }
+ case 24:
+ {
+ surf = SDL_CreateRGBSurface(surface_type,width,\
+ height,24,0xfc0000,0x03f000,0x000fc0,0x000030);
+ break;
+ }
+ case 32:
+ {
+ surf = SDL_CreateRGBSurface(surface_type,width,\
+ height,32,0xff000000,0x00ff0000,0x0000ff00,0x000000ff);
+ break;
+ }
+ default:
+ {
+ surf = NULL;
+ break;
+ }
+ }
+
+ if (surf == NULL)
+ sdl_quit("Bad Surface Creation!");
+
+ return surf;
+}
+
+/* Take a rectangle in terminal coordinates and then transform it into
+screen coordinates; td is the term_data that this rect belongs to */
+void term_to_screen(SDL_Rect *termrect, term_data *td)
+{
+ termrect->x += td->rect.x;
+ termrect->y += td->rect.y;
+}
+
+/* Do the opposite, take a rectangle in screen coordinates and transform
+it into the terminal coordinates of the given term_data */
+void screen_to_term(SDL_Rect *scrrect, term_data *td)
+{
+ scrrect->x -= td->rect.x;
+ scrrect->y -= td->rect.y;
+}
+
+/* A macro that determines if the 'top' rectangle completely occludes the
+'bottom' rectangle */
+#define BLOCKS(top,bottom) \
+( (top.x <= bottom.x) & ((top.x+top.w)>=(bottom.x+bottom.w)) & \
+ (top.y <= bottom.y) & ((top.y+top.h)>=(bottom.y+bottom.h)) )
+
+#define INTERSECT(r1,r2) \
+!( ( (r1.x > (r2.x+r2.w)) | (r2.x > (r1.x+r1.w)) ) & \
+ ( (r1.y > (r2.y+r2.h)) | (r2.y > (r1.y+r1.h)) ) )
+
+/* A function to calculate the intersection of two rectangles. Takes base
+rectangle and then updates it to include only the rectangles that intersect
+with the test rectangle. If there is an intersection, the function returns
+TRUE and base now contains the intersecting rectangle. If there is no
+intersection, then the function returns FALSE */
+bool_ intersectRects(SDL_Rect *base, SDL_Rect *test)
+{
+ if (INTERSECT((*base),(*test)))
+ {
+ /* Scoot the x-coordinates for the left side*/
+ if ( test->x > base->x )
+ {
+ base->w -= test->x - base->x;
+ base->x = test->x;
+ }
+ /* Scoot the x-coordinates for the right side*/
+ if ( (test->x + test->w) < (base->x + base->w) )
+ {
+ base->w = test->x + test->w - base->x;
+ }
+ /* Scoot the upper y-coordinates */
+ if ( test->y > base->y )
+ {
+ base->h -= test->y - base->y;
+ base->y = test->y;
+ }
+ /* Scoot the lower y-coordinates */
+ if ( (test->y + test->h) < (base->y + base->h) )
+ {
+ base->h = test->y + test->h - base->y;
+ }
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/* A function to calculate the join of two rectangles; the first argument is
+changed to the joined rectangle */
+SDL_Rect joinRects(SDL_Rect *r1, SDL_Rect *r2)
+{
+ SDL_Rect out = {0,0,0,0};
+
+ if ( (r1 != NULL) & (r2 != NULL) )
+ {
+ /* Lower x-coordinate */
+ if ( r2->x < r1->x )
+ out.x = r2->x;
+ else
+ out.x = r1->x;
+ /* Upper x-coordinate */
+ if ( (r2->x+r2->w) > (r1->x+r1->w) )
+ out.w = (r2->x+r2->w) - out.x;
+ else
+ out.w = (r1->x+r1->w) - out.x;
+ /* Lower y-coordinate */
+ if ( r2->y < r1->y )
+ out.y = r2->y;
+ else
+ out.y = r1->y;
+ if ( (r2->y+r2->h) > (r1->y+r1->h) )
+ out.h = (r2->y+r2->h) - out.y;
+ else
+ out.h = (r1->y+r1->h) - out.y;
+ }
+ return out;
+}
+
+/* Given a term_data (and its associated screen) and a rectangle in terminal
+coordinates (with NULL signifying to take the whole terminal surface), blit
+graphics from the term_data surface to the screen, using the term_data's rect
+to indicate how terminal coordinates transform into screen coordinates.
+This is complicated, however, by the possibility that the indicated area may be
+occluded by overlaying terminals. In this case, if the target area is
+completely occluded, nothing will be done. If partially occluded, it will be
+drawn, but occluding terminals will then re-blit to re-cover the area. */
+void drawTermStuff(term_data *td, SDL_Rect *rect)
+{
+ int n = 0, i;
+ bool_ block = FALSE, cover = FALSE;
+ SDL_Rect spot, isect_term, isect_scr;
+
+ /* first of all, if updating is suspended, do nothing! */
+ if (!suspendUpdate)
+ {
+ /* find out which number in the ordered stack of screens that this
+ terminal is */
+ while ((term_order[n] != td) & (n < MAX_CONSOLE_COUNT))
+ {
+ n++;
+ }
+ if (n == MAX_CONSOLE_COUNT)
+ printf("Could not find terminal in display list...\n");
+ /* now loop through and see if any terminals completely occlude
+ the desired spot; if num=0, note that this will be skipped */
+ if (rect == NULL)
+ {
+ /* Grab the whole terminal screen */
+ spot.x = 0; spot.y = 0;
+ spot.w = td->surf->w; spot.h = td->surf->h;
+ }
+ else
+ {
+ /* Just copy the given area */
+ spot.x = rect->x; spot.y = rect->y;
+ spot.w = rect->w; spot.h = rect->h;
+ }
+ term_to_screen(&spot,td);
+ i = n;
+ while (i--)
+ {
+ if (BLOCKS(term_order[i]->rect,spot))
+ {
+ /* Higher terminal completely occludes this spot */
+ block = TRUE;
+ DB(" Blocks!");
+ }
+ else if (INTERSECT(term_order[i]->rect,spot))
+ {
+ /* Partial occlusion */
+ cover = TRUE;
+ DB(" Covers!");
+ }
+ }
+ /* If any of the higher terminals blocked, then don't do
+ anything */
+ if (!block)
+ {
+ /*printf("Blitting to %d %d %d %d\n",spot.x,spot.y,spot.w,spot.h);*/
+ /* First of all, draw the graphics */
+ SDL_BlitSurface(td->surf,rect,screen,&spot);
+ if (cover)
+ {
+ printf("covering...");
+ /* There are covering terminals, so go through and blit all
+ partially occluding ones */
+ while (n--)
+ {
+ /* copy spot to find the intersect */
+ isect_scr.x = spot.x; isect_scr.y = spot.y;
+ isect_scr.w = spot.w; isect_scr.h = spot.h;
+ if (intersectRects(&isect_scr,&(term_order[n]->rect)))
+ {
+ /* this terminal intersects... re-blit */
+ /* first, convert to term coordinates */
+ isect_term.x = isect_scr.x; isect_term.y = isect_scr.y;
+ isect_term.w = isect_scr.w; isect_term.h = isect_scr.h;
+ screen_to_term(&isect_term,term_order[n]);
+ /* blit from term coordinates to screen coordinates */
+ SDL_BlitSurface(term_order[n]->surf,&isect_term,\
+ screen,&isect_scr);
+ }
+ }
+ }
+ /* Now update what was drawn */
+ DB("Update");
+ SDL_UpdateRects(screen,1,&spot);
+ }
+ }
+}
+
+/* utility routine for creating and setting the color of the cursor;
+it could be useful for setting a new cursor color if desired.
+Could later be expanded to do other stuff with the cursor,
+like a hollow rectangle a la main-win.c or even a graphic */
+void createCursor(byte r, byte g, byte b, byte a)
+{
+ /* free the cursor if it exists */
+ if (cursor != NULL)
+ SDL_FreeSurface(cursor);
+
+ /* and create it anew! (or the first time) */
+ cursor = createSurface(t_width,t_height);
+
+ /* be sure to use alpha channel when blitting! */
+ SDL_SetAlpha(cursor,SDL_SRCALPHA,0);
+
+ /* just set the color for now - drawing rectangles
+ needs surface locking for some setups */
+ cursor_color = SDL_MapRGBA(cursor->format,r,g,b,a);
+ SDL_LOCK(cursor);
+ SDL_FillRect(cursor,NULL,cursor_color);
+ SDL_UNLOCK(cursor);
+}
+
+/* Cursor Display routine - just blits the global cursor
+surface onto the correct location */
+static errr Term_curs_sdl(int x, int y)
+{
+ term_data *td = (term_data*)(Term->data);
+ static SDL_Rect base;
+
+ /* calculate the position to place the cursor */
+ base.x = td->surf->clip_rect.x + x*t_width;
+ base.y = td->surf->clip_rect.y + y*t_height;
+ base.w = t_width;
+ base.h = t_height;
+
+ /* blit the cursor over top of the given spot;
+ note that surface should not be locked
+ (see note in Term_text_sdl() below) */
+ SDL_BlitSurface(cursor,NULL,td->surf,&base);
+
+ /* Now draw to the main screen */
+ drawTermStuff(td,&base);
+ /* Success */
+ return (0);
+}
+
+/* routine for wiping terminal locations - simply draws
+a black rectangle over the offending spots! */
+static errr Term_wipe_sdl(int x, int y, int n)
+{
+ static SDL_Rect base;
+ term_data *td = (term_data*)(Term->data);
+
+ /* calculate boundaries of the area to clear */
+ base.x = td->surf->clip_rect.x + x*t_width;
+ base.y = td->surf->clip_rect.y + y*t_height;
+ base.w = n*t_width;
+ base.h = t_height;
+
+ SDL_LOCK(td->surf);
+
+ /* blank the screen area */
+ SDL_FillRect(td->surf, &base, td->black);
+
+ SDL_UNLOCK(td->surf);
+
+ /* And... UPDATE the rectangle we just wrote to! */
+ drawTermStuff(td,&base);
+
+ /* Success */
+ return (0);
+}
+
+/* Perform a full clear of active terminal; redraw the borders.*/
+void eraseTerminal(void)
+{
+ static SDL_Rect base;
+ term_data *td = (term_data*)(Term->data);
+
+ /* temporarily remove clipping rectangle */
+ SDL_SetClipRect(td->surf,NULL);
+
+ SDL_LOCK(td->surf);
+ /* flood terminal with border color */
+ SDL_FillRect(td->surf,NULL,td->border_color);
+
+ /* get smaller rectangle to hollow out window */
+ base.x = td->border_thick;
+ base.y = td->border_thick;
+ base.w = td->rect.w - 2*td->border_thick;
+ base.h = td->rect.h - 2*td->border_thick;
+
+ /* hollow out terminal */
+ SDL_FillRect(td->surf,&base,td->black);
+
+ SDL_UNLOCK(screen);
+
+ /* reset clipping rectangle */
+ base.x += td->cushion_x_top;
+ base.y += td->cushion_y_top;
+ base.w -= td->cushion_x_top + td->cushion_x_bot;
+ base.h -= td->cushion_y_top + td->cushion_y_bot;
+ SDL_SetClipRect(td->surf,&base);
+ printf("Clip rect: %d %d %d %d\n",base.x,base.y,base.w,base.h);
+ /* And... UPDATE the whole thing */
+ drawTermStuff(td,NULL);
+
+}
+
+/*
+ * Draw some text on the screen
+ *
+ * This function should actually display an array of characters
+ * starting at the given location, using the given "attribute",
+ * and using the given string of characters, which contains
+ * exactly "n" characters and which is NOT null-terminated.
+ *
+ * You may assume "valid" input if the window is properly sized.
+ *
+ * You must be sure that the string, when written, erases anything
+ * (including any visual cursor) that used to be where the text is
+ * drawn. On many machines this happens automatically, on others,
+ * you must first call "Term_wipe_xxx()" to clear the area.
+ *
+ * In color environments, you should activate the color contained
+ * in "color_data[a & 0x0F]", if needed, before drawing anything.
+ *
+ * You may ignore the "attribute" if you are only supporting a
+ * monochrome environment, since this routine is normally never
+ * called to display "black" (invisible) text, including the
+ * default "spaces", and all other colors should be drawn in
+ * the "normal" color in a monochrome environment.
+ *
+ * Note that if you have changed the "attr_blank" to something
+ * which is not black, then this function must be able to draw
+ * the resulting "blank" correctly.
+ *
+ * Note that this function must correctly handle "black" text if
+ * the "always_text" flag is set, if this flag is not set, all the
+ * "black" text will be handled by the "Term_wipe_xxx()" hook.
+ */
+static errr Term_text_sdl(int x, int y, int n, byte a, const char *cp)
+{
+ term_data *td = (term_data*)(Term->data);
+ static SDL_Rect base;
+ SDL_Rect base_back;
+ int i = n;
+ char old = 0;
+
+ /* calculate place to clear off and draw to */
+ base.x = td->surf->clip_rect.x + x*td->tile_width;
+ base.y = td->surf->clip_rect.y + y*td->tile_height;
+ base.w = n*td->tile_width;
+ base.h = td->tile_height;
+
+ base_back = base;
+
+ SDL_LOCK(screen);
+
+ /* blank the drawing area */
+ SDL_FillRect(td->surf, &base, td->black);
+
+ SDL_UNLOCK(screen);
+
+ /* Note that SDL docs specify that SDL_BlitSurface should not be called
+ on locked surfaces... since the character printing routine below revolves
+ around blitting, the surface has been unlocked first*/
+
+ /* loop through the input string, drawing characters */
+ i = n;
+ old = 0;
+ while (i--)
+ {
+ /* Output the character... */
+ /* If character has not changed, then just blit the old surface into
+ the new location to save effort*/
+ if (*cp == old)
+ {
+ /* the desired character/color combo is already on the work surf */
+ /* just blit it! */
+ SDL_BlitSurface(worksurf,NULL,td->surf,&base);
+ } else {
+ /* copy the desired character onto working surface */
+ SDL_BlitSurface(text[*cp],NULL,worksurf,NULL);
+ /* color our crayon surface with the desired color */
+ SDL_FillRect(crayon,NULL,color_data[a&0x0f]);
+ /* apply the color to the character on the working surface */
+ SDL_BlitSurface(crayon,NULL,worksurf,NULL);
+ /* and blit it onto our screen! */
+ SDL_BlitSurface(worksurf,NULL,td->surf,&base);
+ }
+ /* Move to the next position */
+ base.x += t_width;
+ /* Store the old character */
+ old = *cp;
+ /* Increment the character pointer */
+ cp++;
+ }
+
+ /* And update */
+ drawTermStuff(td,&base_back);
+
+ /* Success */
+ return (0);
+}
+
+/*************************************************
+ SPECIAL TERMINAL WINDOW MANIPULATION ROUTINES
+ *************************************************/
+
+/* macro for bounding a value between two given values */
+#define BOUND(val,low,high) \
+if (val < low) \
+{ \
+ val = low; \
+} \
+else if (val > high) \
+{ \
+ val = high; \
+}
+
+/* two macros to get the adjusted maximums for window
+positions... eg the screen width minus the width of the
+window is the maximum x-position that the window can
+be set at. */
+#define MAX_X(td) \
+( arg_width - td->rect.w )
+
+#define MAX_Y(td) \
+( arg_height - td->rect.h )
+
+/* another two macros that give maximum window widths
+based on screen size and current window position together
+width tile widths/heights */
+#define MAX_WIDTH(td) \
+( (int)floorf((arg_width - td->rect.x - 2*td->border_thick - \
+ td->cushion_x_bot - td->cushion_x_top )/td->tile_width))
+
+#define MAX_HEIGHT(td) \
+( (int)floorf((arg_height - td->rect.y - 2*td->border_thick - \
+ td->cushion_y_bot - td->cushion_y_top )/td->tile_height))
+
+/* update the width and height of given term's rectangle by simply
+multiplying the tile count by tile size and adding in cushions and
+borders */
+#define UPDATE_SIZE(td) \
+ td->rect.w = (td->cols)*td->tile_width + td->cushion_x_top \
+ + td->cushion_x_bot + 2*td->border_thick; \
+ td->rect.h = (td->rows)*td->tile_height + td->cushion_y_top \
+ + td->cushion_y_bot + 2*td->border_thick
+
+void recompose(void);
+
+/* Resize the active terminal with new width and height.
+Note that his involves a complicated sequence of events...
+Details to follow below! */
+void resizeTerminal(int width, int height)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* First of all, bound the input width and height to satisfy
+ these conditions:
+ - The main ToME window should be at least 80 cols, 24 rows
+ - no part of each window should be drawn off screen....
+ I'm including borders in this restriction!
+ But no bounds checking needs to take place if the input width
+ and height are unchanged....
+ */
+
+ if (td == &data[0])
+ {
+ /* The active terminal is the main ToME window...
+ don't let the width get below 80, don't let the heights below
+ 24, and don't let it leak off of the edge! */
+ if (width != td->cols)
+ {
+ BOUND(width,80,MAX_WIDTH(td));
+ }
+ if (height != td->rows)
+ {
+ BOUND(height,24,MAX_HEIGHT(td));
+ }
+ }
+ else
+ {
+ /* This is not the main window... just make sure it
+ doesn't shrink to nothing or go past the edge */
+ if (width != td->cols)
+ {
+ BOUND(width,1,MAX_WIDTH(td));
+ }
+ if (height != td->rows)
+ {
+ BOUND(height,1,MAX_HEIGHT(td));
+ }
+ }
+
+ /* Okay, now make sure that something has ACTUALLY changed
+ before doing anything */
+ if ((width != td->cols) || (height != td->rows))
+ {
+
+ /* Now, ask zterm to please resize the term structure! */
+ Term_resize(width,height);
+
+ /* Reactivate, since Term_resize seems to activate the
+ main window again...*/
+ Term_activate(&td->t);
+
+ /* It might not have resized completely to the new
+ size we wanted (some windows have size limits it seems,
+ like the message window). So, update our structure with
+ the size that were actually obtained.*/
+ td->cols = Term->wid;
+ td->rows = Term->hgt;
+
+ /* And recalculate the sizes */
+ UPDATE_SIZE(td);
+
+ /* Create a new surface that can hold the updated size */
+ SDL_FreeSurface(td->surf);
+ td->surf = createSurface(td->rect.w,td->rect.h);
+
+ /* Now we should be in business for a complete redraw! */
+ Term_redraw();
+
+ /* Re-blit everything so it looks good */
+ recompose();
+
+ /* That's it! */
+ }
+}
+
+/* Move the terminal around... a much simpler action that involves
+just changing the pos_x/pos_y values and redrawing!*/
+void moveTerminal(int x, int y)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* Now, the window is being shifted about... much simpler
+ situation to handle! But of course, the window must not
+ drift too far or else parts will be hanging off the screen
+ and may lead to errors - bound the input positions to
+ prevent this unfortunate situation... do nothing if the
+ input is no different than the current */
+ if (x != td->rect.x)
+ {
+ BOUND(x,0,MAX_X(td));
+ }
+ if (y != td->rect.y)
+ {
+ BOUND(y,0,MAX_Y(td));
+ }
+
+ /* Okay, now make sure that something changed before doing
+ anything */
+ if ((x != td->rect.x) || (y != td->rect.y))
+ {
+ /* Now update OUR structure */
+ td->rect.x = x;
+ td->rect.y = y;
+
+ /* Then do a reblit to see the results */
+ recompose();
+
+ /* That's it! */
+ }
+}
+
+/* Routine to bring a given term_data to the top of the drawing stack */
+void bringToTop(int current)
+{
+ term_data *td;
+ term_data *tc;
+ int n = 0;
+ int i;
+
+ /* Get the pointer to the desired term_data from the data structure */
+ td = &data[current];
+
+ printf("Current stack: \n");
+ for (i=0;i<arg_console_count;i++)
+ {
+ printf(" %d: %p\n",i,term_order[i]);
+ }
+ printf("\n");
+
+ /* Find the number in the term_order stack */
+ while ((term_order[n] != td) & (n < MAX_CONSOLE_COUNT))
+ {
+ n++;
+ }
+ if (n == MAX_CONSOLE_COUNT)
+ printf("Could not find terminal in display list...\n");
+
+ printf("Order is %d\n",n);
+
+ /* Now move all lower-indexed pointers up one index */
+ while (n)
+ {
+ printf(" move %d to %d\n",n-1,n);
+ printf(" %p\n",term_order[n-1]);
+ printf(" %p\n",term_order[n]);
+ term_order[n] = term_order[n-1];
+ n--;
+ }
+ /* And stick this term_data pointer on top */
+ term_order[0] = td;
+
+ printf("Final stack: \n");
+ for (i=0;i<arg_console_count;i++)
+ {
+ printf(" %d: %p\n",i,term_order[i]);
+ }
+ printf("\n");
+
+}
+
+/* This utility routine will cycle the active term to the
+next available in the data[] array. It will then do a
+redraw of this term so that it is ready to be manipulated.
+The input is the current active terminal, and the output is
+the new active terminal */
+int cycleTerminal(int current)
+{
+ /* redraw the current term to get rid of its purple
+ border */
+ data[current].border_color = data[current].white;
+ Term_redraw();
+
+ /* increment the terminal number*/
+ current++;
+ /* now do a little modulo cycle action and
+ activate the next term! */
+ current %= arg_console_count;
+ Term_activate(&(data[current].t));
+
+ /* before redrawing, set the border color to purple to
+ indicate that this terminal is being manipulated*/
+ data[current].border_color = data[current].purple;
+
+ /* then bring this terminal to the top of the order, so it is drawn on
+ top during manipulation mode */
+ bringToTop(current);
+
+ /* and do a complete redraw */
+ Term_redraw();
+
+ /* return the current terminal... */
+ return current;
+}
+
+/* This routine will simply re-blit all of the surfaces onto the main screen,
+respecting the current term_order */
+void recompose(void)
+{
+ int i = arg_console_count;
+ /* do a complete screen wipe */
+ SDL_LOCK(screen);
+ SDL_FillRect(screen,NULL,screen_black);
+ SDL_UNLOCK(screen);
+
+ /* cycle through the term_order */
+ while (i--)
+ {
+ SDL_BlitSurface(term_order[i]->surf,NULL,screen,&(term_order[i]->rect));
+ }
+
+ /* Update everything */
+ SDL_REDRAW_SCREEN;
+}
+
+/* This utility routine will completely blank the screen and
+then cycle through all terminals, performing a Term_redraw()
+on each and every term that is being used (according to
+arg_term_count that is). The terminals will be redrawn
+last-to-first, so that the main is over top of everything */
+void redrawAllTerminals(void)
+{
+ int i = arg_console_count;
+ DB("Total redraw");
+ /* do a complete screen wipe */
+ SDL_LOCK(screen);
+ SDL_FillRect(screen,NULL,screen_black);
+ SDL_UNLOCK(screen);
+
+ while (i--)
+ {
+ /* Re-order the terminals */
+ term_order[i] = &data[i];
+ }
+
+ i = arg_console_count;
+ /* cycle down through each terminal */
+ while (i--)
+ {
+ /* Activate this terminal */
+ Term_activate(&(data[i].t));
+
+ /* Make its border white since manipulation mode is over */
+ data[i].border_color = data[i].white;
+
+ /* And redraw it */
+ Term_redraw();
+ }
+ /* Loop will end on i=0 ! */
+
+ printf("Current stack: \n");
+ for (i=0;i<arg_console_count;i++)
+ {
+ printf(" %d: %p\n",i,term_order[i]);
+ }
+ printf("\n");
+
+ /* now update the screen completely, just in case*/
+ SDL_REDRAW_SCREEN;
+}
+
+/* This is the special event handling function for doing
+terminal window manipulation! When special manipulation
+mode is activated, execution goes here. This special mode
+has its own keypresses. To begin with, the main terminal
+border is highlighted (in purple) to indicate that it is
+being manipulated. The following keypresses are accepted:
+-Space: switches between editing modes. The system begins
+ in position editing mode, and Enter will toggle size
+ (row/col) editing mode.
+-Arrows: increments/decrements the position/size in an
+ intuitive way! ;) Some modifiers are accepted in order
+ to speed things up on very high resolution screens:
+ . with shift down, increment is five
+ . with ctrl down, increment is ten
+ . with both, increment is fifty!
+ Of course, no movement or resize can cause the window
+ to leave the confines of the screen, so using the big
+ jump is safe.
+-Enter: cycles to the next available terminal to edit.
+-Escape: quits manipulation mode, performing one final
+ redraw to take into account all changes.
+*/
+void manipulationMode(void)
+{
+ term_data *td;
+ SDL_Event event;
+ bool_ done = FALSE, moveMode = TRUE;
+ int mouse_x, mouse_y;
+ int value = 0, delta_x = 0, delta_y = 0;
+ int current_term;
+ SDL_Surface backup;
+
+ /* Begin by redrawing the main terminal with its
+ purple border to signify that it is being edited*/
+
+ /* start with the main terminal */
+ current_term = 0;
+
+ /* get the pointer */
+ td = &data[0];
+
+ /* before redrawing, set the border color to purple to
+ indicate that this terminal is being manipulated*/
+ td->border_color = td->purple;
+
+ /* and do a complete redraw */
+ DB("Term_redraw");
+ Term_redraw();
+
+ /* Now keep looping until Esc has been pressed. */
+ while (!done)
+ {
+ /* Get the keypress event */
+ SDL_WaitEvent(&event);
+ /* Make sure that it is a keypress */
+ if (event.type == SDL_KEYDOWN)
+ {
+ /* Act on the keypress! */
+ switch (event.key.keysym.sym)
+ {
+ case SDLK_ESCAPE:
+ {
+ /* Escape has been pressed, so we're done!*/
+ done = TRUE;
+ break;
+ }
+ case SDLK_SPACE:
+ {
+ /* Space has been pressed: toggle move mode */
+ moveMode = ( moveMode ? FALSE : TRUE );
+ break;
+ }
+ case SDLK_RETURN:
+ {
+ /* Return... cycle the terminals!
+ update the current_term appropriately*/
+ current_term = cycleTerminal(current_term);
+
+ /* Get the new term_data */
+ td = &data[current_term];
+
+ break;
+ }
+ case SDLK_RIGHT:
+ case SDLK_LEFT:
+ case SDLK_DOWN:
+ case SDLK_UP:
+ {
+ /* Increase either the x-position or column
+ width - multiply according to modifiers */
+ value = 1;
+ if (SDL_GetModState() & KMOD_SHIFT)
+ {
+ /* shift is down... a muliplier of 5 */
+ value *= 5;
+ }
+ if (SDL_GetModState() & KMOD_CTRL)
+ {
+ /* control is down... multiply by 10 */
+ value *= 10;
+ }
+
+ /* Now, behavior depends on which key was pressed
+ and whether we are in moveMode resize mode... */
+
+ /* First, set the delta_x/y based on key */
+ if (event.key.keysym.sym == SDLK_RIGHT)
+ {
+ delta_x = 1;
+ delta_y = 0;
+ }
+ if (event.key.keysym.sym == SDLK_LEFT)
+ {
+ delta_x = -1;
+ delta_y = 0;
+ }
+ if (event.key.keysym.sym == SDLK_DOWN)
+ {
+ delta_x = 0;
+ delta_y = 1;
+ }
+ if (event.key.keysym.sym == SDLK_UP)
+ {
+ delta_x = 0;
+ delta_y = -1;
+ }
+
+ /* Now either moveTerminal() or
+ resizeTerminal() based on value of
+ moveMode! */
+ if (moveMode)
+ {
+ moveTerminal(td->rect.x + value*delta_x,\
+ td->rect.y + value*delta_y);
+ }
+ else
+ {
+ resizeTerminal(td->cols + value*delta_x,\
+ td->rows + value*delta_y);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else if (event.type == SDL_MOUSEBUTTONDOWN)
+ {
+ /* Store the coordinates where the button was pressed */
+ mouse_x = event.button.x;
+ mouse_y = event.button.y;
+ }
+ else if (event.type == SDL_MOUSEMOTION)
+ {
+ /* Mouse is moving... maybe move or resize the window, based
+ on the state of the mouse buttons */
+
+ /* To keep the motion quick, temporarily ignore all mouse motion
+ events until window moving is complete */
+ SDL_EventState(SDL_MOUSEMOTION,SDL_IGNORE);
+
+ if(event.motion.state & SDL_BUTTON(1))
+ {
+ /* the left mouse button is down, move the window,
+ do a differential based on where the button was pressed */
+ moveTerminal(td->rect.x + (event.motion.x - mouse_x), \
+ td->rect.y + (event.motion.y - mouse_y));
+ /* save the most current mouse location */
+ SDL_GetMouseState(&mouse_x,&mouse_y);
+ }
+
+ if(event.motion.state & SDL_BUTTON(3))
+ {
+ /* the right mouse button is down, so resize the window;
+ do a differential, but divide the number by the tile sizes */
+
+ /* see if at least one whole tile width/height has been
+ reached */
+ int delta_cols, delta_rows;
+ delta_cols = (int)floorf(\
+ (float)(event.motion.x - mouse_x)/td->tile_width);
+ delta_rows = (int)floorf(\
+ (float)(event.motion.y - mouse_y)/td->tile_height);
+ if ( delta_cols || delta_rows )
+ {
+ /* something changed, so update */
+ resizeTerminal(td->cols + delta_cols, \
+ td->rows + delta_rows);
+ /* save the most current mouse location */
+ SDL_GetMouseState(&mouse_x,&mouse_y);
+ }
+ }
+
+ /* Deal with mouse motion again */
+ SDL_EventState(SDL_MOUSEMOTION,SDL_ENABLE);
+
+ }
+ }
+ /* Perform the last redraw to take all changes
+ into account */
+ redrawAllTerminals();
+}
+
+/*************************************************
+ INITIALIZATION ROUTINES
+ *************************************************/
+
+static errr term_data_init(term_data *td, int i)
+{
+ term *t = &(td->t);
+ char env_var[80];
+ cptr val;
+
+
+ /***** load position, size information */
+
+ int cols, rows, x, y;
+
+ /* grab the column and row counts from
+ environmental variables for now */
+ sprintf(env_var,"TOME_NUM_COLS_%d",i);
+ val = getenv(env_var);
+ /* make sure it is valid */
+ if (val != NULL)
+ {
+ cols = atoi(val);
+ /* now make sure that the main window will
+ have at least 80x24 */
+ if (td == &data[0])
+ {
+ /* can't really pick an upper bound without
+ knowing what the position is... oh well. */
+ BOUND(cols,80,255);
+ }
+ }
+ else
+ {
+ /* no environmental variable... have to guess
+ something. If it's the main window, choose
+ the minimum. */
+ if (td == &data[0])
+ cols = 80;
+ else
+ cols = 5;
+ }
+ /* do the rows */
+ sprintf(env_var,"TOME_NUM_ROWS_%d",i);
+ val = getenv(env_var);
+ /* make sure it is valid */
+ if (val != NULL)
+ {
+ rows = atoi(val);
+ /* now make sure that the main window will
+ have at least 80x24 */
+ if (td == &data[0])
+ {
+ /* can't really pick an upper bound without
+ knowing what the position is... oh well. */
+ BOUND(rows,24,128);
+ }
+ }
+ else
+ {
+ /* no environmental variable... have to guess
+ something. If it's the main window, choose
+ the minimum. */
+ if (td == &data[0])
+ rows = 24;
+ else
+ rows = 3;
+ }
+ /* store these values in the term_data structure */
+ td->rows = rows;
+ td->cols = cols;
+
+ /* the position will be loaded from environmental
+ variables as well - for the time being*/
+ /* x-location */
+ sprintf(env_var,"TOME_X_POS_%d",i);
+ val = getenv(env_var);
+ /* make sure it is valid */
+ if (val != NULL)
+ {
+ x = atoi(val);
+ /* now do intelligent position checking */
+ BOUND(x,0,MAX_X(td));
+ }
+ else
+ {
+ /* no variable, choose something */
+ x = 20*i;
+ }
+ /* y-location */
+ sprintf(env_var,"TOME_Y_POS_%d",i);
+ val = getenv(env_var);
+ /* make sure it is valid */
+ if (val != NULL)
+ {
+ y = atoi(val);
+ /* position checking again */
+ BOUND(y,0,MAX_Y(td));
+ }
+ else
+ {
+ /* no variable */
+ y = 20*i;
+ }
+ /* and store these values into the structure */
+ td->rect.x = x;
+ td->rect.y = y;
+
+ /*********** term structure initializing */
+
+ /* Initialize the term
+ gets: pointer to address, number of columns, number of rows, number
+ of keypresses to queue up (guess 24?)*/
+ term_init(t, cols, rows, 24);
+
+ /* Use a "soft" cursor */
+ t->soft_cursor = TRUE;
+
+ /* Picture routine flags */
+ t->always_pict = FALSE;
+ t->higher_pict = FALSE;
+ t->always_text = FALSE;
+
+ /* Erase with "white space" */
+ t->attr_blank = TERM_WHITE;
+ t->char_blank = ' ';
+
+ /* Hooks */
+ t->xtra_hook = Term_xtra_sdl;
+ t->curs_hook = Term_curs_sdl;
+ t->wipe_hook = Term_wipe_sdl;
+ t->text_hook = Term_text_sdl;
+
+ /* Save the data */
+ t->data = td;
+
+ /* Activate (important) */
+ Term_activate(t);
+
+ /************* finish term_data intializing */
+
+ /* name of this term window */
+ td->name = angband_term_name[i];
+
+ /* For now, all font is the same size... use global t_width/height */
+ td->tile_width = t_width;
+ td->tile_height = t_height;
+
+ td->cushion_x_top = 1;
+ td->cushion_x_bot = 1;
+ td->cushion_y_top = 1;
+ td->cushion_y_bot = 1;
+
+ /* Now calculate the total width and height*/
+ UPDATE_SIZE(td);
+
+ /* Create a surface to draw to */
+ td->surf = createSurface(td->rect.w,td->rect.h);
+ SDL_SetAlpha(td->surf,0,0);
+
+ /* Key some colors to this surface */
+ td->black = SDL_MapRGB(td->surf->format, 0, 0, 0);
+ td->white = SDL_MapRGB(td->surf->format,255,255,255);
+ td->purple = SDL_MapRGB(td->surf->format,255, 0,255);
+
+ /* Turn on a border, thickness specified by BORDER_THICKNESS */
+ td->border_thick = BORDER_THICKNESS;
+
+ /* make the default terminal border color to be white */
+ td->border_color = td->white;
+
+
+ printf("Init-int term: %d\n",i);
+
+ /* Success */
+ return (0);
+}
+
+/* dumpWindowSettings is responsible for exporting all current
+values of the window positions, etc. to the screen, so that
+the user can see what the final values were after tweaking */
+void dumpWindowSettings(void)
+{
+ char name[80];
+ char value[8];
+ int i;
+
+ DB("Dumping settings");
+ printf("---------------------------\n");
+ /* cycle through each available terminal */
+ for (i=0; i<arg_console_count; i++)
+ {
+ printf("Terminal %d:\n",i);
+ /* get the name, and value of each value to dump */
+ sprintf(name,"TOME_X_POS_%d",i);
+ sprintf(value,"%d",data[i].rect.x);
+ printf("%s=%s\n",name,value);
+
+ sprintf(name,"TOME_Y_POS_%d",i);
+ sprintf(value,"%d",data[i].rect.y);
+ printf("%s=%s\n",name,value);
+
+ sprintf(name,"TOME_NUM_COLS_%d",i);
+ sprintf(value,"%d",data[i].cols);
+ printf("%s=%s\n",name,value);
+
+ sprintf(name,"TOME_NUM_ROWS_%d",i);
+ sprintf(value,"%d",data[i].rows);
+ printf("%s=%s\n",name,value);
+
+ /* Simple! */
+ printf("\n");
+ }
+}
+
+/* The main-sdl initialization routine!
+This routine processes arguments, opens the SDL
+window, loads fonts, etc. */
+errr init_sdl(int argc, char **argv)
+{
+ int i, surface_type;
+ char filename[PATH_MAX + 1];
+ const char file_sep = '.';
+ /* Flags to pass to SDL_SetVideoMode */
+ int videoFlags;
+
+ /* Before sdl_quit could possible be called, need to make sure that the text
+ array is zeroed, so that sdl_quit->killFontAndAlphabet() doesn't try to free
+ SDL_Surfaces that don't exist ! */
+ memset(text,0,sizeof(text));
+
+ /* Also, clear out the term order array */
+ memset(term_order,0,sizeof(term_order));
+
+ /* initialize SDL */
+ if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
+ {
+ sdl_quit("Video initialization failed!");
+ }
+ DB("SDL Initialized!");
+
+ /* get video info, to be used for determining if hardware acceleration is
+ available, pixel format, etc.... */
+ videoInfo = SDL_GetVideoInfo();
+
+ /* Environment calls to retrieve specific settings...
+ Note that these can be overridden by the command-line
+ arguments that are handled below */
+ if(getenv("TOME_CONSOLE_COUNT"))
+ arg_console_count = atoi(getenv("TOME_CONSOLE_COUNT"));
+ if(getenv("TOME_SCREEN_WIDTH"))
+ arg_width = atoi(getenv("TOME_SCREEN_WIDTH"));
+ if(getenv("TOME_SCREEN_HEIGHT"))
+ arg_height = atoi(getenv("TOME_SCREEN_HEIGHT"));
+ if(getenv("TOME_SCREEN_BPP"))
+ arg_bpp = atoi(getenv("TOME_SCREEN_BPP"));
+ if(getenv("TOME_FONT_SIZE"))
+ arg_font_size = atoi(getenv("TOME_FONT_SIZE"));
+
+ /* Argument handling routine;
+ the argv pointer is already pointing at the '--'
+ argument, so just start from there, parsing each
+ option as it comes along */
+ for (i=1; i < argc ; i++)
+ {
+ /* Set the number of consoles to handle
+ (ie the number of windows) */
+ if (0 == strcmp(argv[i], "-n"))
+ {
+ if (++i == argc)
+ {
+ printf("Argument missing for option -n\n");
+ return -1;
+ }
+
+ arg_console_count = atoi(argv[i]);
+ if (arg_console_count <= 0 || \
+ arg_console_count > MAX_CONSOLE_COUNT)
+ {
+ printf("Invalid console count given.\n");
+ arg_console_count = 1;
+ }
+ }
+ /* Set the SDL window/screen width in pixels */
+ else if (0 == strcmp(argv[i], "-w"))
+ {
+ if (++i == argc)
+ {
+ printf("Argument missing for option -w\n");
+ return -1;
+ }
+
+ arg_width = atoi(argv[i]);
+ }
+ /* Set the SDL window/screen height in pixels */
+ else if (0 == strcmp(argv[i], "-h"))
+ {
+ if (++i == argc)
+ {
+ printf("Argument missing for option -h\n");
+ return -1;
+ }
+
+ arg_height = atoi(argv[i]);
+ }
+ /* Set the SDL window/screen color depth
+ (in bits per pixel -- only 8,16,32 are okay) */
+ else if (0 == strcmp(argv[i], "-bpp"))
+ {
+ if (++i == argc)
+ {
+ printf("Argument missing for option -bpp\n");
+ return -1;
+ }
+
+ arg_bpp = atoi(argv[i]);
+ if ( (arg_bpp != 8) && (arg_bpp != 16) \
+ && (arg_bpp != 24) && (arg_bpp != 32) )
+ {
+ printf("Invalid color depth. Must be either 8, 16, or 32 bpp!\n");
+ return -1;
+ }
+ }
+ /* see if new graphics are requested...*/
+ else if (0 == strcmp(argv[i], "-g"))
+ {
+ printf("New graphics (16x16) enabled!\n");
+ arg_graphics_type = GRAPHICS_16x16;
+ }
+ /* see if old graphics are requested...*/
+ else if (0 == strcmp(argv[i], "-o"))
+ {
+ printf("Old graphics (8x8) enabled!\n");
+ arg_graphics_type = GRAPHICS_8x8;
+ }
+
+ /* see if double width tiles are requested */
+ else if (0 == strcmp(argv[i], "-b"))
+ {
+ /* do nothing for now */
+ /* arg_double_width = TRUE; */
+ }
+ /* switch into full-screen at startup */
+ else if (0 == strcmp(argv[i], "-fs"))
+ {
+ DB("Full-screen enabled!");
+ arg_full_screen = TRUE;
+ }
+ /* change the font size */
+ else if (0 == strcmp(argv[i], "-s"))
+ {
+ if (++i == argc)
+ {
+ printf("Argument missing for option -s\n");
+ printf("Please specify font size!\n");
+ return -1;
+ }
+
+ arg_font_size = atoi(argv[i]);
+ }
+ /* change the font to use */
+ else if (0 == strcmp(argv[i], "-f"))
+ {
+ /* Can we please not be so MS Windows-specific? One of the main goals
+ of SDL in ToME was to be more portable. These file name hacks are
+ only the idiom of that one OS, though. -- Neil */
+ DB("Getting font name");
+ if (++i == argc)
+ {
+ printf("Argument missing for option -f\n");
+ printf("Please specify a true-type font found in /lib/xtra/font!\n");
+ return -1;
+ }
+
+ /* tokenize the font name so that no .ttf extension
+ is required */
+ strcpy(arg_font_name,\
+ strtok(argv[i],&file_sep));
+
+ /* and append the extension */
+ strcat(arg_font_name,".ttf");
+
+ /* print a little debug message, so
+ user sees what font was actually selected */
+ printf("\tUsing font: %s\n",arg_font_name);
+
+ /* maybe check to see if file is even
+ existant in /lib/xtra/font */
+ }
+
+ } /* end argument handling */
+
+ /* Make sure that the engine will shutdown SDL properly*/
+ quit_aux = sdl_quit;
+
+ /* Use the ToME logo and set the window name */
+ filename[PATH_MAX] = 0;
+ path_build(filename, PATH_MAX, ANGBAND_DIR_XTRA, "graf/icon.png");
+ SDL_WM_SetIcon(IMG_Load(filename), 0);
+ SDL_WM_SetCaption("ToME", "tome");
+
+ /* SDL video settings, dependent on whether hardware is available */
+ if (videoInfo->hw_available)
+ videoFlags = SDL_HWSURFACE;
+ else
+ videoFlags = SDL_SWSURFACE;
+
+ /* Now ready the fonts! */
+
+ DB("initializing SDL_ttf");
+ if(TTF_Init()==-1) {
+ printf("TTF_Init: %s\n", TTF_GetError());
+ sdl_quit("Bah");
+ }
+
+ DB("loading font...");
+
+ /* load and render the font */
+ loadAndRenderFont(arg_font_name,arg_font_size);
+
+ /* Make the window a nice default size if none is specified */
+ if (arg_width < 1 || arg_height < 1)
+ {
+ arg_width = 80 * t_width;
+ arg_height = 24 * t_height;
+ }
+
+ /* now set the video mode that has been configured */
+ screen = SDL_SetVideoMode( arg_width, arg_height, arg_bpp, videoFlags );
+
+ /* Verify there is a surface */
+ if ( !screen )
+ {
+ DB("No screen!");
+ sdl_quit("Failed to set SDL Surface.");
+ }
+
+ DB("Video Mode Set!");
+
+ /* now switch into full screen if asked for */
+ if (arg_full_screen)
+ SDL_WM_ToggleFullScreen(screen);
+
+ DB("SDL Window Created!");
+
+ /* Graphics! ----
+ If graphics are selected, then load graphical tiles! */
+ if (arg_graphics_type != NO_GRAPHICS)
+ {
+ /* load graphics tiles */
+ }
+
+ /* Initialize the working surface and crayon surface used for rendering
+ text in different colors. */
+
+ worksurf = createSurface(t_width,t_height);
+ crayon = createSurface(t_width,t_height);
+
+ /* The working surface will blit using alpha values... */
+ SDL_SetAlpha(worksurf,SDL_SRCALPHA,0);
+
+ /* Set up the colors using the great little color macros! */
+ color_data[0] = BLACK;
+ color_data[1] = WHITE;
+ color_data[2] = MID_GREY;
+ color_data[3] = BRIGHT_ORANGE;
+ color_data[4] = RED;
+ color_data[5] = GREEN;
+ color_data[6] = BRIGHT_BLUE;
+ color_data[7] = DARK_ORANGE;
+ color_data[8] = DARK_GREY;
+ color_data[9] = BRIGHT_GREY;
+ color_data[10] = PURPLE;
+ color_data[11] = YELLOW;
+ color_data[12] = BRIGHT_RED;
+ color_data[13] = BRIGHT_GREEN;
+ color_data[14] = AQUAMARINE;
+ color_data[15] = BROWN;
+
+ /* And setup the cursor, using the default color...
+ XXX - in the future, this should (and will) be loaded from prefs */
+ createCursor(DEF_CURSOR_COLOR);
+
+ /* Initialize the windows, or whatever that means in this case.
+ Do this in reverse order so that the main window is on top.*/
+ suspendUpdate = TRUE; /* draw everything at the end */
+ i = arg_console_count;
+ while (i--)
+ {
+ term_data *td = &data[i];
+
+ /* Initialize the term_data */
+ term_data_init(td, i);
+
+ /* Save global entry */
+ angband_term[i] = Term;
+
+ /* Add into term_order */
+ term_order[i] = td;
+
+ }
+
+ /* And setup the basic screen colors -- these are keyed to the format of
+ the main terminal surface */
+ screen_black = SDL_MapRGB(screen->format, 0, 0, 0);
+
+ suspendUpdate = FALSE; /* now draw everything */
+ redrawAllTerminals();
+ /*SDL_REDRAW_SCREEN;*/
+
+ /* now that the windows have been set, their settings can
+ be dumped upon quit! */
+ window_properties_set = TRUE;
+
+ /* Enable UNICODE keysyms - needed for current eventHandling routine */
+ SDL_EnableUNICODE(1);
+
+ /* Enable key repeat! */
+ SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL);
+
+ /* main-sdl initialized! */
+ return 0;
+}
+
+#endif
diff --git a/src/main-sla.c b/src/main-sla.c
new file mode 100644
index 00000000..3c02d61f
--- /dev/null
+++ b/src/main-sla.c
@@ -0,0 +1,455 @@
+/* File: main-sla.c */
+
+/* Purpose: Actual Unix "slang" support for Angband */
+
+/*
+ * Author: hans@grumbeer.pfalz.de (Hans-Joachim Baader)
+ *
+ * Most of this code is adapted directly from "main-gcu.c"
+ */
+
+#include "angband.h"
+
+
+#ifdef USE_SLA
+
+
+
+#include <slang.h>
+
+
+/*
+ * Are we "active"?
+ */
+static int slang_on = FALSE;
+
+
+/*
+ * Can we use "color"?
+ */
+static bool_ can_use_color = FALSE;
+
+
+/*
+ * Angband to SLang color conversion table
+ */
+static int colortable[16];
+
+
+/*
+ * Currently, only a single "term" is supported here
+ */
+static term term_screen_body;
+
+
+
+
+
+/*
+ * Hack -- see below
+ */
+void init_pair (int index, char *foreground, char *background)
+{
+ SLtt_set_color (index, "", foreground, background);
+}
+
+
+
+
+
+#define A_NORMAL 0
+#define A_BOLD 8
+#define A_REVERSE 0
+#define REVERSE 8
+
+#define COLOR_BLACK "black"
+#define COLOR_BLUE "blue"
+#define COLOR_GREEN "green"
+#define COLOR_CYAN "cyan"
+#define COLOR_RED "red"
+#define COLOR_MAGENTA "magenta"
+#define COLOR_YELLOW "brown"
+#define COLOR_WHITE "lightgray"
+#define COLOR_BBLACK "gray"
+#define COLOR_BBLUE "brightblue"
+#define COLOR_BGREEN "brightgreen"
+#define COLOR_BCYAN "brightcyan"
+#define COLOR_BRED "brightred"
+#define COLOR_BMAGENTA "brightmagenta"
+#define COLOR_BYELLOW "yellow"
+#define COLOR_BWHITE "white"
+
+
+
+
+
+static char *color_terminals [] =
+{
+#ifdef linux
+ "console",
+#endif
+ "linux",
+ "xterm-color",
+ "color-xterm",
+ "xtermc",
+ "ansi",
+ 0
+};
+
+
+
+
+
+/*
+ * Stolen from the Midnight Commander
+ */
+int has_colors(void)
+{
+ int i;
+
+ char *terminal;
+
+
+ /* Access the terminal type */
+ terminal = getenv("TERM");
+
+ /* Check for colors */
+ SLtt_Use_Ansi_Colors = 0;
+ if (NULL != getenv ("COLORTERM"))
+ {
+ SLtt_Use_Ansi_Colors = 1;
+ }
+
+ /* We want to allow overriding */
+ for (i = 0; color_terminals [i]; i++)
+ {
+ if (strcmp (color_terminals [i], terminal) == 0)
+ {
+ SLtt_Use_Ansi_Colors = 1;
+ }
+ }
+
+ /* Setup emulated colors */
+ if (SLtt_Use_Ansi_Colors)
+ {
+ /*init_pair (REVERSE, "black", "white");*/
+ }
+
+ /* Setup bizarre colors */
+ else
+ {
+ SLtt_set_mono (A_BOLD, NULL, SLTT_BOLD_MASK);
+ SLtt_set_mono (A_REVERSE, NULL, SLTT_REV_MASK);
+ SLtt_set_mono (A_BOLD | A_REVERSE, NULL, SLTT_BOLD_MASK | SLTT_REV_MASK);
+ }
+
+ return SLtt_Use_Ansi_Colors;
+}
+
+
+
+
+
+/*
+ * Nuke SLang
+ */
+static void Term_nuke_sla(term *t)
+{
+ if (!slang_on) return;
+
+ /* Show the cursor */
+ /* curs_set(1); */
+
+ /* Clear the screen */
+ (void)SLsmg_cls();
+
+ /* Refresh */
+ SLsmg_refresh();
+
+ /* We are now off */
+ slang_on = FALSE;
+
+ /* Shut down */
+ SLsmg_reset_smg();
+ SLang_reset_tty();
+}
+
+
+/*
+ * Init SLang
+ */
+static void Term_init_sla(term *t)
+{
+ /* Note that we are on */
+ slang_on = TRUE;
+}
+
+
+/*
+ * Process an event, wait if requested
+ */
+static errr Term_xtra_sla_event(int v)
+{
+ /* Do not wait unless requested */
+ if (!v && (SLang_input_pending (0) == 0)) return (1);
+
+ /* Get and enqueue the key */
+ Term_keypress(SLang_getkey ());
+
+ /* Success */
+ return 0;
+}
+
+
+
+/*
+ * Suspend / Resume
+ */
+static errr Term_xtra_sla_alive(int v)
+{
+ /* Suspend */
+ if (!v)
+ {
+ /* Oops */
+ if (!slang_on) return (1);
+
+ /* We are now off */
+ slang_on = FALSE;
+
+ /* Shut down (temporarily) */
+ SLsmg_reset_smg();
+ SLang_reset_tty();
+ }
+
+ /* Resume */
+ else
+ {
+ /* Oops */
+ if (slang_on) return (1);
+
+ /* Fix the screen */
+ SLsmg_refresh();
+
+ /* Note that we are on */
+ slang_on = TRUE;
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Handle a "special request"
+ */
+static errr Term_xtra_sla(int n, int v)
+{
+ /* Analyze the request */
+ switch (n)
+ {
+ /* Make a noise */
+ case TERM_XTRA_NOISE:
+ (void)SLsmg_write_char('\007');
+ return (0);
+
+ /* Flush the ncurses buffer */
+ case TERM_XTRA_FRESH:
+ (void)SLsmg_refresh();
+ return (0);
+
+ /* Make the cursor invisible or visible */
+ case TERM_XTRA_SHAPE:
+ /* curs_set(v); */
+ return (0);
+
+ /* Handle events */
+ case TERM_XTRA_EVENT:
+ return (Term_xtra_sla_event(v));
+
+ /* Handle events */
+ case TERM_XTRA_FLUSH:
+ while (!Term_xtra_sla_event(FALSE));
+ return (0);
+
+ /* Suspend/Resume */
+ case TERM_XTRA_ALIVE:
+ return (Term_xtra_sla_alive(v));
+
+ /* Clear the screen */
+ case TERM_XTRA_CLEAR:
+ (void)SLsmg_cls();
+ SLsmg_gotorc(0, 0);
+ return (0);
+
+ /* Delay */
+ case TERM_XTRA_DELAY:
+ usleep(1000 * v);
+ return (0);
+ }
+
+ /* Oops */
+ return (1);
+}
+
+
+
+
+/*
+ * Actually MOVE the hardware cursor
+ */
+static errr Term_curs_sla(int x, int y, int z)
+{
+ /* Literally move the cursor */
+ SLsmg_gotorc (y, x);
+
+ /* Success */
+ return 0;
+}
+
+
+/*
+ * Erase some characters
+ */
+static errr Term_wipe_sla(int x, int y, int n)
+{
+ int i;
+
+ /* Place the cursor */
+ SLsmg_gotorc(y, x);
+
+ /* Dump spaces */
+ for (i = 0; i < n; i++) SLsmg_write_char(' ');
+
+ /* Success */
+ return 0;
+}
+
+
+/*
+ * Place some text on the screen using an attribute
+ */
+static errr Term_text_sla(int x, int y, int n, byte a, cptr s)
+{
+ /* Move the cursor */
+ SLsmg_gotorc(y, x);
+
+ /* Set the color */
+ if (can_use_color) SLsmg_set_color(colortable[a&0x0F]);
+
+ /* Dump the string */
+ SLsmg_write_nchars(s, n);
+
+ /* Success */
+ return 0;
+}
+
+
+/*
+ * Prepare "SLang" for use by the file "term.c"
+ * Installs the "hook" functions defined above
+ */
+errr init_sla(void)
+{
+ int i, err;
+
+ term *t = &term_screen_body;
+
+
+ /* Initialize, check for errors */
+ err = (SLang_init_tty( -1, TRUE, 0) == -1);
+
+ /* Quit on error */
+ if (err) quit("SLang initialization failed");
+
+ /* Get terminal info */
+ SLtt_get_terminfo ();
+
+ /* Initialize some more */
+ if (SLsmg_init_smg() == 0)
+ {
+ quit("Could not get virtual display memory");
+ }
+
+ /* Check we have enough screen. */
+ err = ((SLtt_Screen_Rows < 24) || (SLtt_Screen_Cols < 80));
+
+ /* Quit with message */
+ if (err) quit("SLang screen must be at least 80x24");
+
+ /* Now let's go for a little bit of color! */
+ err = !has_colors();
+
+ /* Do we have color available? */
+ can_use_color = !err;
+
+ /* Init the Color-pairs and set up a translation table */
+ /* If the terminal has enough colors */
+ /* Color-pair 0 is *always* WHITE on BLACK */
+
+ /* XXX XXX XXX See "main-gcu.c" for proper method */
+
+ /* Only do this on color machines */
+ if (can_use_color)
+ {
+ /* Prepare the color pairs */
+ init_pair(1, COLOR_RED, COLOR_BLACK);
+ init_pair(2, COLOR_GREEN, COLOR_BLACK);
+ init_pair(3, COLOR_YELLOW, COLOR_BLACK);
+ init_pair(4, COLOR_BLUE, COLOR_BLACK);
+ init_pair(5, COLOR_MAGENTA, COLOR_BLACK);
+ init_pair(6, COLOR_CYAN, COLOR_BLACK);
+ init_pair(7, COLOR_BLACK, COLOR_BLACK);
+ init_pair(9, COLOR_BRED, COLOR_BLACK);
+ init_pair(10, COLOR_BGREEN, COLOR_BLACK);
+ init_pair(11, COLOR_BYELLOW, COLOR_BLACK);
+ init_pair(12, COLOR_BBLUE, COLOR_BLACK);
+ init_pair(13, COLOR_BMAGENTA, COLOR_BLACK);
+ init_pair(14, COLOR_BCYAN, COLOR_BLACK);
+ init_pair(15, COLOR_BBLACK, COLOR_BLACK);
+
+ /* Prepare the color table */
+ colortable[0] = 7; /* Black */
+ colortable[1] = 0; /* White */
+ colortable[2] = 6; /* Grey XXX */
+ colortable[3] = 11; /* Orange XXX */
+ colortable[4] = 1; /* Red */
+ colortable[5] = 2; /* Green */
+ colortable[6] = 4; /* Blue */
+ colortable[7] = 3; /* Brown */
+ colortable[8] = 15; /* Dark-grey XXX */
+ colortable[9] = 14; /* Light-grey XXX */
+ colortable[10] = 5; /* Purple */
+ colortable[11] = 11; /* Yellow */
+ colortable[12] = 9; /* Light Red */
+ colortable[13] = 10; /* Light Green */
+ colortable[14] = 12; /* Light Blue */
+ colortable[15] = 3; /* Light Brown XXX */
+ }
+
+
+ /* Initialize the term */
+ term_init(t, 80, 24, 64);
+
+ /* Stick in some hooks */
+ t->nuke_hook = Term_nuke_sla;
+ t->init_hook = Term_init_sla;
+
+ /* Stick in some more hooks */
+ t->xtra_hook = Term_xtra_sla;
+ t->curs_hook = Term_curs_sla;
+ t->wipe_hook = Term_wipe_sla;
+ t->text_hook = Term_text_sla;
+
+ /* Save the term */
+ term_screen = t;
+
+ /* Activate it */
+ Term_activate(t);
+
+
+ /* Success */
+ return 0;
+}
+
+#endif /* USE_SLA */
+
diff --git a/src/main-win.c b/src/main-win.c
new file mode 100644
index 00000000..92a2a775
--- /dev/null
+++ b/src/main-win.c
@@ -0,0 +1,4368 @@
+/* File: main-win.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison, Skirmantas Kligys, and others
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+
+/*
+ * This file helps Angband work with Windows computers.
+ *
+ * To use this file, use an appropriate "Makefile" or "Project File",
+ * make sure that "WINDOWS" and/or "WIN32" are defined somewhere, and
+ * make sure to obtain various extra files as described below.
+ *
+ * The official compilation uses the CodeWarrior Pro compiler, which
+ * includes a special project file and precompilable header file.
+ *
+ *
+ * See also "main-dos.c" and "main-ibm.c".
+ *
+ *
+ * The "lib/user/pref-win.prf" file contains keymaps, macro definitions,
+ * and/or color redefinitions.
+ *
+ * The "lib/user/font-win.prf" contains attr/char mappings for use with the
+ * normal "lib/xtra/font/ .fon" font files.
+ *
+ * The "lib/user/graf-win.prf" contains attr/char mappings for use with the
+ * special "lib/xtra/graf/ .bmp" bitmap files, which are activated by a
+ * menu item.
+ *
+ *
+ * Compiling this file, and using the resulting executable, requires
+ * several extra files not distributed with the standard Angband code.
+ * If "USE_GRAPHICS" is defined, then "readdib.h" and "readdib.c" must
+ * be placed into "src/", and the "8X8.BMP" bitmap file must be placed
+ * into "lib/xtra/graf". In any case, some "*.fon" files (including
+ * "8X13.FON" if nothing else) must be placed into "lib/xtra/font/".
+ * If "USE_SOUND" is defined, then some special library (for example,
+ * "winmm.lib") may need to be linked in, and desired "*.WAV" sound
+ * files must be placed into "lib/xtra/sound/". All of these extra
+ * files can be found in the "ext-win" archive.
+ *
+ *
+ * The "Term_xtra_win_clear()" function should probably do a low-level
+ * clear of the current window, and redraw the borders and other things,
+ * if only for efficiency. XXX XXX XXX
+ *
+ * A simpler method is needed for selecting the "tile size" for windows.
+ * XXX XXX XXX
+ *
+ * The various "warning" messages assume the existance of the "screen.w"
+ * window, I think, and only a few calls actually check for its existance,
+ * this may be okay since "NULL" means "on top of all windows". (?) The
+ * user must never be allowed to "hide" the main window, or the "menubar"
+ * will disappear. XXX XXX XXX
+ *
+ * Special "Windows Help Files" can be placed into "lib/xtra/help/" for
+ * use with the "winhelp.exe" program. These files *may* be available
+ * at the ftp site somewhere, but I have not seen them. XXX XXX XXX
+ *
+ *
+ * Initial framework (and most code) by Ben Harrison (benh@phial.com).
+ *
+ * Original code by Skirmantas Kligys (kligys@scf.usc.edu).
+ *
+ * Additional code by Ross E Becker (beckerr@cis.ohio-state.edu),
+ * and Chris R. Martin (crm7479@tam2000.tamu.edu).
+ */
+
+
+#include "angband.h"
+
+
+#ifdef WINDOWS
+
+
+/*
+ * Extract the "WIN32" flag from the compiler
+ */
+#if defined(__WIN32__) || defined(__WINNT__) || defined(__NT__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+
+
+/*
+ * Hack -- allow use of "screen saver" mode
+ */
+#define USE_SAVER
+
+/*
+ * Menu constants -- see "ANGBAND.RC"
+ */
+
+#define IDM_FILE_NEW 100
+#define IDM_FILE_OPEN 101
+#define IDM_FILE_SAVE 110
+#ifdef ALLOW_QUITTING
+# define IDM_FILE_ABORT 120
+#else
+# define IDM_FILE_SCORE 120
+#endif
+#define IDM_FILE_EXIT 121
+
+#define IDM_WINDOW_VIS_0 200
+#define IDM_WINDOW_VIS_1 201
+#define IDM_WINDOW_VIS_2 202
+#define IDM_WINDOW_VIS_3 203
+#define IDM_WINDOW_VIS_4 204
+#define IDM_WINDOW_VIS_5 205
+#define IDM_WINDOW_VIS_6 206
+#define IDM_WINDOW_VIS_7 207
+
+#define IDM_WINDOW_FONT_0 210
+#define IDM_WINDOW_FONT_1 211
+#define IDM_WINDOW_FONT_2 212
+#define IDM_WINDOW_FONT_3 213
+#define IDM_WINDOW_FONT_4 214
+#define IDM_WINDOW_FONT_5 215
+#define IDM_WINDOW_FONT_6 216
+#define IDM_WINDOW_FONT_7 217
+
+#define IDM_WINDOW_BIZ_0 230
+#define IDM_WINDOW_BIZ_1 231
+#define IDM_WINDOW_BIZ_2 232
+#define IDM_WINDOW_BIZ_3 233
+#define IDM_WINDOW_BIZ_4 234
+#define IDM_WINDOW_BIZ_5 235
+#define IDM_WINDOW_BIZ_6 236
+#define IDM_WINDOW_BIZ_7 237
+
+#define IDM_WINDOW_I_WID_0 240
+#define IDM_WINDOW_I_WID_1 241
+#define IDM_WINDOW_I_WID_2 242
+#define IDM_WINDOW_I_WID_3 243
+#define IDM_WINDOW_I_WID_4 244
+#define IDM_WINDOW_I_WID_5 245
+#define IDM_WINDOW_I_WID_6 246
+#define IDM_WINDOW_I_WID_7 247
+
+#define IDM_WINDOW_D_WID_0 250
+#define IDM_WINDOW_D_WID_1 251
+#define IDM_WINDOW_D_WID_2 252
+#define IDM_WINDOW_D_WID_3 253
+#define IDM_WINDOW_D_WID_4 254
+#define IDM_WINDOW_D_WID_5 255
+#define IDM_WINDOW_D_WID_6 256
+#define IDM_WINDOW_D_WID_7 257
+
+#define IDM_WINDOW_I_HGT_0 260
+#define IDM_WINDOW_I_HGT_1 261
+#define IDM_WINDOW_I_HGT_2 262
+#define IDM_WINDOW_I_HGT_3 263
+#define IDM_WINDOW_I_HGT_4 264
+#define IDM_WINDOW_I_HGT_5 265
+#define IDM_WINDOW_I_HGT_6 266
+#define IDM_WINDOW_I_HGT_7 267
+
+#define IDM_WINDOW_D_HGT_0 270
+#define IDM_WINDOW_D_HGT_1 271
+#define IDM_WINDOW_D_HGT_2 272
+#define IDM_WINDOW_D_HGT_3 273
+#define IDM_WINDOW_D_HGT_4 274
+#define IDM_WINDOW_D_HGT_5 275
+#define IDM_WINDOW_D_HGT_6 276
+#define IDM_WINDOW_D_HGT_7 277
+
+#define IDM_OPTIONS_OLD_GRAPHICS 400
+#define IDM_OPTIONS_NEW_GRAPHICS 401
+#define IDM_OPTIONS_ASCII_GRAPHICS 403
+#define IDM_OPTIONS_SOUND 402
+#define IDM_OPTIONS_BIGTILE 409
+#define IDM_OPTIONS_UNUSED 410
+#define IDM_OPTIONS_SAVER 411
+
+#define IDM_HELP_GENERAL 901
+#define IDM_HELP_SPOILERS 902
+
+
+/*
+ * This may need to be removed for some compilers XXX XXX XXX
+ */
+#define STRICT
+
+/*
+ * Exclude parts of WINDOWS.H that are not needed
+ */
+#define NOCOMM /* Comm driver APIs and definitions */
+#define NOLOGERROR /* LogError() and related definitions */
+#define NOPROFILER /* Profiler APIs */
+#define NOLFILEIO /* _l* file I/O routines */
+#define NOOPENFILE /* OpenFile and related definitions */
+#define NORESOURCE /* Resource management */
+#define NOATOM /* Atom management */
+#define NOLANGUAGE /* Character test routines */
+#define NOLSTRING /* lstr* string management routines */
+#define NODBCS /* Double-byte character set routines */
+#define NOKEYBOARDINFO /* Keyboard driver routines */
+#define NOCOLOR /* COLOR_* color values */
+#define NODRAWTEXT /* DrawText() and related definitions */
+#define NOSCALABLEFONT /* Truetype scalable font support */
+#define NOMETAFILE /* Metafile support */
+#define NOSYSTEMPARAMSINFO /* SystemParametersInfo() and SPI_* definitions */
+#define NODEFERWINDOWPOS /* DeferWindowPos and related definitions */
+#define NOKEYSTATES /* MK_* message key state flags */
+#define NOWH /* SetWindowsHook and related WH_* definitions */
+#define NOCLIPBOARD /* Clipboard APIs and definitions */
+#define NOICONS /* IDI_* icon IDs */
+#define NOMDI /* MDI support */
+#define NOHELP /* Help support */
+
+/* Not defined since it breaks Borland C++ 5.5 */
+/* #define NOCTLMGR */ /* Control management and controls */
+
+/*
+ * Exclude parts of WINDOWS.H that are not needed (Win32)
+ */
+#define WIN32_LEAN_AND_MEAN
+#define NONLS /* All NLS defines and routines */
+#define NOSERVICE /* All Service Controller routines, SERVICE_ equates, etc. */
+#define NOKANJI /* Kanji support stuff. */
+#define NOMCX /* Modem Configuration Extensions */
+
+/*
+ * Include the "windows" support file
+ */
+#include <windows.h>
+
+
+/*
+ * Exclude parts of MMSYSTEM.H that are not needed
+ */
+#define MMNODRV /* Installable driver support */
+#define MMNOWAVE /* Waveform support */
+#define MMNOMIDI /* MIDI support */
+#define MMNOAUX /* Auxiliary audio support */
+#define MMNOJOY /* Joystick support */
+#define MMNOMCI /* MCI support */
+#define MMNOMMIO /* Multimedia file I/O support */
+#define MMNOMMSYSTEM /* General MMSYSTEM functions */
+
+/*
+ * Include some more files
+ */
+#include <mmsystem.h>
+#include <commdlg.h>
+
+/*
+ * Include the support for loading bitmaps
+ */
+#ifdef USE_GRAPHICS
+# include "readdib.h"
+#endif
+
+/*
+ * Hack -- Fake declarations from "dos.h" XXX XXX XXX
+ */
+#ifdef WIN32
+#define INVALID_FILE_NAME (DWORD)0xFFFFFFFF
+#else /* WIN32 */
+#define FA_LABEL 0x08 /* Volume label */
+#define FA_DIREC 0x10 /* Directory */
+unsigned _cdecl _dos_getfileattr(const char *, unsigned *);
+#endif /* WIN32 */
+
+/*
+ * Silliness in WIN32 drawing routine
+ */
+#ifdef WIN32
+# define MoveTo(H, X, Y) MoveToEx(H, X, Y, NULL)
+#endif /* WIN32 */
+
+/*
+ * Silliness for Windows 95
+ */
+#ifndef WS_EX_TOOLWINDOW
+# define WS_EX_TOOLWINDOW 0
+#endif
+
+/*
+ * Foreground color bits (hard-coded by DOS)
+ */
+#define VID_BLACK 0x00
+#define VID_BLUE 0x01
+#define VID_GREEN 0x02
+#define VID_CYAN 0x03
+#define VID_RED 0x04
+#define VID_MAGENTA 0x05
+#define VID_YELLOW 0x06
+#define VID_WHITE 0x07
+
+/*
+ * Bright text (hard-coded by DOS)
+ */
+#define VID_BRIGHT 0x08
+
+/*
+ * Background color bits (hard-coded by DOS)
+ */
+#define VUD_BLACK 0x00
+#define VUD_BLUE 0x10
+#define VUD_GREEN 0x20
+#define VUD_CYAN 0x30
+#define VUD_RED 0x40
+#define VUD_MAGENTA 0x50
+#define VUD_YELLOW 0x60
+#define VUD_WHITE 0x70
+
+/*
+ * Blinking text (hard-coded by DOS)
+ */
+#define VUD_BRIGHT 0x80
+
+
+
+/*
+ * Forward declare
+ */
+typedef struct _term_data term_data;
+
+/*
+ * Extra "term" data
+ *
+ * Note the use of "font_want" for the names of the font file requested by
+ * the user, and the use of "font_file" for the currently active font file.
+ *
+ * The "font_file" is uppercased, and takes the form "8X13.FON", while
+ * "font_want" can be in almost any form as long as it could be construed
+ * as attempting to represent the name of a font.
+ */
+struct _term_data
+{
+ term t;
+
+ cptr s;
+
+ HWND w;
+
+ DWORD dwStyle;
+ DWORD dwExStyle;
+
+ uint keys;
+
+ uint rows;
+ uint cols;
+
+ uint pos_x;
+ uint pos_y;
+ uint size_wid;
+ uint size_hgt;
+ uint size_ow1;
+ uint size_oh1;
+ uint size_ow2;
+ uint size_oh2;
+
+ bool_ size_hack;
+
+ bool_ xtra_hack;
+
+ bool_ visible;
+
+ bool_ bizarre;
+
+ cptr font_want;
+
+ cptr font_file;
+
+ HFONT font_id;
+
+ uint font_wid;
+ uint font_hgt;
+
+ uint tile_wid;
+ uint tile_hgt;
+};
+
+
+/*
+ * Maximum number of windows XXX XXX XXX
+ */
+#define MAX_TERM_DATA 8
+
+/*
+ * An array of term_data's
+ */
+static term_data data[MAX_TERM_DATA];
+
+/*
+ * Hack -- global "window creation" pointer
+ */
+static term_data *my_td;
+
+/*
+ * game in progress
+ */
+bool_ game_in_progress = FALSE;
+
+/*
+ * note when "open"/"new" become valid
+ */
+bool_ initialized = FALSE;
+
+/*
+ * screen paletted, i.e. 256 colors
+ */
+bool_ paletted = FALSE;
+
+/*
+ * 16 colors screen, don't use RGB()
+ */
+bool_ colors16 = FALSE;
+
+/*
+ * Saved instance handle
+ */
+static HINSTANCE hInstance;
+
+/*
+ * Yellow brush for the cursor
+ */
+static HBRUSH hbrYellow;
+
+/*
+ * An icon
+ */
+static HICON hIcon;
+
+/*
+ * A palette
+ */
+static HPALETTE hPal;
+
+
+#ifdef USE_SAVER
+
+/*
+ * The screen saver window
+ */
+static HWND hwndSaver;
+
+#endif /* USE_SAVER */
+
+
+#ifdef USE_GRAPHICS
+
+/*
+ * Flag set once "graphics" has been initialized
+ */
+static bool_ can_use_graphics = FALSE;
+
+/*
+ * The global bitmap
+ */
+static DIBINIT infGraph;
+
+/*
+ * The global bitmap mask
+ */
+static DIBINIT infMask;
+
+#endif /* USE_GRAPHICS */
+
+
+#ifdef USE_SOUND
+
+/*
+ * Flag set once "sound" has been initialized
+ */
+static bool_ can_use_sound = FALSE;
+
+/*
+ * An array of sound file names
+ */
+static cptr sound_file[SOUND_MAX];
+
+#endif /* USE_SOUND */
+
+
+/*
+ * Full path to ANGBAND.INI
+ */
+static cptr ini_file = NULL;
+
+/*
+ * Name of application
+ */
+static cptr AppName = "ANGBAND";
+
+/*
+ * Name of sub-window type
+ */
+static cptr AngList = "AngList";
+
+/*
+ * Directory names
+ */
+static cptr ANGBAND_DIR_XTRA_FONT;
+static cptr ANGBAND_DIR_XTRA_GRAF;
+static cptr ANGBAND_DIR_XTRA_SOUND;
+static cptr ANGBAND_DIR_XTRA_HELP;
+
+
+/*
+ * The "complex" color values
+ */
+static COLORREF win_clr[256];
+
+
+/*
+ * The "simple" color values
+ *
+ * See "main-ibm.c" for original table information
+ *
+ * The entries below are taken from the "color bits" defined above.
+ *
+ * Note that many of the choices below suck, but so do crappy monitors.
+ */
+static BYTE win_pal[256] =
+{
+ VID_BLACK, /* Dark */
+ VID_WHITE, /* White */
+ VID_CYAN, /* Slate XXX */
+ VID_RED | VID_BRIGHT, /* Orange XXX */
+ VID_RED, /* Red */
+ VID_GREEN, /* Green */
+ VID_BLUE, /* Blue */
+ VID_YELLOW, /* Umber XXX */
+ VID_BLACK | VID_BRIGHT, /* Light Dark */
+ VID_CYAN | VID_BRIGHT, /* Light Slate XXX */
+ VID_MAGENTA, /* Violet XXX */
+ VID_YELLOW | VID_BRIGHT, /* Yellow */
+ VID_MAGENTA | VID_BRIGHT, /* Light Red XXX */
+ VID_GREEN | VID_BRIGHT, /* Light Green */
+ VID_BLUE | VID_BRIGHT, /* Light Blue */
+ VID_YELLOW /* Light Umber XXX */
+};
+
+
+/*
+ * Hack -- define which keys are "special"
+ */
+static bool_ special_key[256];
+static bool_ ignore_key[256];
+
+#if 1
+/*
+ * Hack -- initialization list for "special_key"
+ */
+static byte special_key_list[] = {
+ VK_CLEAR, VK_PAUSE, VK_CAPITAL, VK_KANA,
+#ifdef JP
+ VK_JUNJA, VK_FINAL, VK_KANJI, VK_CONVERT, VK_NONCONVERT, VK_ACCEPT, VK_MODECHANGE,
+#endif
+ VK_PRIOR, VK_NEXT, VK_END, VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN,
+ VK_SELECT, VK_PRINT, VK_EXECUTE, VK_SNAPSHOT, VK_INSERT, VK_DELETE,
+ VK_HELP, VK_APPS,
+ VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,
+ VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, VK_F19, VK_F20,
+ VK_F21, VK_F22, VK_F23, VK_F24, VK_NUMLOCK, VK_SCROLL,
+ VK_ATTN, VK_CRSEL, VK_EXSEL, VK_EREOF, VK_PLAY, VK_ZOOM, VK_NONAME,
+ VK_PA1, 0
+};
+
+static byte ignore_key_list[] = {
+ VK_ESCAPE, VK_TAB, VK_SPACE,
+ 'F', 'W', 'O', 'H', /* these are menu characters.*/
+ VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, VK_RWIN,
+ VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, VK_LMENU, VK_RMENU, 0
+};
+
+#else
+/*
+* Hack -- initialization list for "special_key"
+*
+* We ignore the modifier keys (shift, control, alt, num lock, scroll lock),
+* and the normal keys (escape, tab, return, letters, numbers, etc), but we
+* catch the keypad keys (with and without numlock set, including keypad 5),
+* the function keys (including the "menu" key which maps to F10), and the
+* "pause" key (between scroll lock and numlock). We also catch a few odd
+* keys which I do not recognize, but which are listed among keys which we
+* do catch, so they should be harmless to catch.
+*/
+static byte special_key_list[] =
+{
+ VK_CLEAR, /* 0x0C (KP<5>) */
+
+ VK_PAUSE, /* 0x13 (pause) */
+
+ VK_PRIOR, /* 0x21 (KP<9>) */
+ VK_NEXT, /* 0x22 (KP<3>) */
+ VK_END, /* 0x23 (KP<1>) */
+ VK_HOME, /* 0x24 (KP<7>) */
+ VK_LEFT, /* 0x25 (KP<4>) */
+ VK_UP, /* 0x26 (KP<8>) */
+ VK_RIGHT, /* 0x27 (KP<6>) */
+ VK_DOWN, /* 0x28 (KP<2>) */
+ VK_SELECT, /* 0x29 (?????) */
+ VK_PRINT, /* 0x2A (?????) */
+ VK_EXECUTE, /* 0x2B (?????) */
+ VK_SNAPSHOT, /* 0x2C (?????) */
+ VK_INSERT, /* 0x2D (KP<0>) */
+ VK_DELETE, /* 0x2E (KP<.>) */
+ VK_HELP, /* 0x2F (?????) */
+
+#if 0
+ VK_NUMPAD0, /* 0x60 (KP<0>) */
+ VK_NUMPAD1, /* 0x61 (KP<1>) */
+ VK_NUMPAD2, /* 0x62 (KP<2>) */
+ VK_NUMPAD3, /* 0x63 (KP<3>) */
+ VK_NUMPAD4, /* 0x64 (KP<4>) */
+ VK_NUMPAD5, /* 0x65 (KP<5>) */
+ VK_NUMPAD6, /* 0x66 (KP<6>) */
+ VK_NUMPAD7, /* 0x67 (KP<7>) */
+ VK_NUMPAD8, /* 0x68 (KP<8>) */
+ VK_NUMPAD9, /* 0x69 (KP<9>) */
+ VK_MULTIPLY, /* 0x6A (KP<*>) */
+ VK_ADD, /* 0x6B (KP<+>) */
+ VK_SEPARATOR, /* 0x6C (?????) */
+ VK_SUBTRACT, /* 0x6D (KP<->) */
+ VK_DECIMAL, /* 0x6E (KP<.>) */
+ VK_DIVIDE, /* 0x6F (KP</>) */
+#endif
+
+ VK_F1, /* 0x70 */
+ VK_F2, /* 0x71 */
+ VK_F3, /* 0x72 */
+ VK_F4, /* 0x73 */
+ VK_F5, /* 0x74 */
+ VK_F6, /* 0x75 */
+ VK_F7, /* 0x76 */
+ VK_F8, /* 0x77 */
+ VK_F9, /* 0x78 */
+ VK_F10, /* 0x79 */
+ VK_F11, /* 0x7A */
+ VK_F12, /* 0x7B */
+ VK_F13, /* 0x7C */
+ VK_F14, /* 0x7D */
+ VK_F15, /* 0x7E */
+ VK_F16, /* 0x7F */
+ VK_F17, /* 0x80 */
+ VK_F18, /* 0x81 */
+ VK_F19, /* 0x82 */
+ VK_F20, /* 0x83 */
+ VK_F21, /* 0x84 */
+ VK_F22, /* 0x85 */
+ VK_F23, /* 0x86 */
+ VK_F24, /* 0x87 */
+
+ 0
+};
+#endif
+
+
+/*
+ * Hack -- given a pathname, point at the filename
+ */
+static cptr extract_file_name(cptr s)
+{
+ cptr p;
+
+ /* Start at the end */
+ p = s + strlen(s) - 1;
+
+ /* Back up to divider */
+ while ((p >= s) && (*p != ':') && (*p != '\\')) p--;
+
+ /* Return file name */
+ return (p + 1);
+}
+
+
+/*
+ * Hack -- given a simple filename, extract the "font size" info
+ *
+ * Return a pointer to a static buffer holding the capitalized base name.
+ */
+static char *analyze_font(char *path, int *wp, int *hp)
+{
+ int wid, hgt;
+
+ char *s, *p;
+
+ /* Start at the end */
+ p = path + strlen(path) - 1;
+
+ /* Back up to divider */
+ while ((p >= path) && (*p != ':') && (*p != '\\')) --p;
+
+ /* Advance to file name */
+ ++p;
+
+ /* Capitalize */
+ for (s = p; *s; ++s)
+ {
+ /* Capitalize (be paranoid) */
+ if (islower(*s)) *s = toupper(*s);
+ }
+
+ /* Find first 'X' */
+ s = strchr(p, 'X');
+
+ /* Extract font width */
+ wid = atoi(p);
+
+ /* Extract height */
+ hgt = s ? atoi(s + 1) : 0;
+
+ /* Save results */
+ (*wp) = wid;
+ (*hp) = hgt;
+
+ /* Result */
+ return (p);
+}
+
+
+/*
+ * Check for existance of a file
+ */
+static bool_ check_file(cptr s)
+{
+ char path[1024];
+
+#ifdef WIN32
+
+ DWORD attrib;
+
+#else /* WIN32 */
+
+ unsigned int attrib;
+
+#endif /* WIN32 */
+
+ /* Copy it */
+ strcpy(path, s);
+
+#ifdef WIN32
+
+ /* Examine */
+ attrib = GetFileAttributes(path);
+
+ /* Require valid filename */
+ if (attrib == INVALID_FILE_NAME) return (FALSE);
+
+ /* Prohibit directory */
+ if (attrib & FILE_ATTRIBUTE_DIRECTORY) return (FALSE);
+
+#else /* WIN32 */
+
+ /* Examine and verify */
+ if (_dos_getfileattr(path, &attrib)) return (FALSE);
+
+ /* Prohibit something */
+ if (attrib & FA_LABEL) return (FALSE);
+
+ /* Prohibit directory */
+ if (attrib & FA_DIREC) return (FALSE);
+
+#endif /* WIN32 */
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Check for existance of a directory
+ */
+static bool_ check_dir(cptr s)
+{
+ int i;
+
+ char path[1024];
+
+#ifdef WIN32
+
+ DWORD attrib;
+
+#else /* WIN32 */
+
+ unsigned int attrib;
+
+#endif /* WIN32 */
+
+ /* Copy it */
+ strcpy(path, s);
+
+ /* Check length */
+ i = strlen(path);
+
+ /* Remove trailing backslash */
+ if (i && (path[i - 1] == '\\')) path[--i] = '\0';
+
+#ifdef WIN32
+
+ /* Examine */
+ attrib = GetFileAttributes(path);
+
+ /* Require valid filename */
+ if (attrib == INVALID_FILE_NAME) return (FALSE);
+
+ /* Require directory */
+ if (!(attrib & FILE_ATTRIBUTE_DIRECTORY)) return (FALSE);
+
+#else /* WIN32 */
+
+ /* Examine and verify */
+ if (_dos_getfileattr(path, &attrib)) return (FALSE);
+
+ /* Prohibit something */
+ if (attrib & FA_LABEL) return (FALSE);
+
+ /* Require directory */
+ if (!(attrib & FA_DIREC)) return (FALSE);
+
+#endif /* WIN32 */
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Validate a file
+ */
+static void validate_file(cptr s)
+{
+ /* Verify or fail */
+ if (!check_file(s))
+ {
+ quit_fmt("Cannot find required file:\n%s", s);
+ }
+}
+
+
+/*
+ * Validate a directory
+ */
+static void validate_dir(cptr s)
+{
+ /* Verify or fail */
+ if (!check_dir(s))
+ {
+ quit_fmt("Cannot find required directory:\n%s", s);
+ }
+}
+
+
+/*
+ * Get the "size" for a window
+ */
+static void term_getsize(term_data *td)
+{
+ RECT rc;
+
+ int wid, hgt;
+
+ /*
+ * The Angband window is always at least 80x24. I'm not sure if
+ * small windows work... -- pelpel
+ */
+ if (td == &data[0])
+ {
+ if (td->cols < 80) td->cols = 80;
+ if (td->rows < 24) td->rows = 24;
+ }
+
+ /* The other windows can be smaller */
+ else
+ {
+ /* Paranoia */
+ if (td->cols < 1) td->cols = 1;
+ if (td->rows < 1) td->rows = 1;
+ }
+
+ /* Paranoia */
+ if (td->cols > 255) td->cols = 255;
+ if (td->rows > 255) td->rows = 255;
+
+ /* Window sizes */
+ wid = td->cols * td->tile_wid + td->size_ow1 + td->size_ow2;
+ hgt = td->rows * td->tile_hgt + td->size_oh1 + td->size_oh2;
+
+ /* Fake window size */
+ rc.left = 0;
+ rc.right = rc.left + wid;
+ rc.top = 0;
+ rc.bottom = rc.top + hgt;
+
+ /* XXX XXX XXX */
+ /* rc.right += 1; */
+ /* rc.bottom += 1; */
+
+ /* Adjust */
+ AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
+
+ /* Total size */
+ td->size_wid = rc.right - rc.left;
+ td->size_hgt = rc.bottom - rc.top;
+
+ /* See CreateWindowEx */
+ if (!td->w) return;
+
+ /* Extract actual location */
+ GetWindowRect(td->w, &rc);
+
+ /* Save the location */
+ td->pos_x = rc.left;
+ td->pos_y = rc.top;
+}
+
+
+/*
+ * Write the "prefs" for a single term
+ */
+static void save_prefs_aux(term_data *td, cptr sec_name)
+{
+ char buf[1024];
+
+ RECT rc;
+
+ /* Paranoia */
+ if (!td->w) return;
+
+ /* Visible */
+ strcpy(buf, td->visible ? "1" : "0");
+ WritePrivateProfileString(sec_name, "Visible", buf, ini_file);
+
+ /* Font */
+ strcpy(buf, td->font_file ? td->font_file : "8X13.FON");
+ WritePrivateProfileString(sec_name, "Font", buf, ini_file);
+
+ /* Bizarre */
+ strcpy(buf, td->bizarre ? "1" : "0");
+ WritePrivateProfileString(sec_name, "Bizarre", buf, ini_file);
+
+ /* Tile size (x) */
+ wsprintf(buf, "%d", td->tile_wid);
+ WritePrivateProfileString(sec_name, "TileWid", buf, ini_file);
+
+ /* Tile size (y) */
+ wsprintf(buf, "%d", td->tile_hgt);
+ WritePrivateProfileString(sec_name, "TileHgt", buf, ini_file);
+
+ /* Window size (x) */
+ wsprintf(buf, "%d", td->cols);
+ WritePrivateProfileString(sec_name, "NumCols", buf, ini_file);
+
+ /* Window size (y) */
+ wsprintf(buf, "%d", td->rows);
+ WritePrivateProfileString(sec_name, "NumRows", buf, ini_file);
+
+ /* Acquire position */
+ GetWindowRect(td->w, &rc);
+
+ /* Window position (x) */
+ wsprintf(buf, "%d", rc.left);
+ WritePrivateProfileString(sec_name, "PositionX", buf, ini_file);
+
+ /* Window position (y) */
+ wsprintf(buf, "%d", rc.top);
+ WritePrivateProfileString(sec_name, "PositionY", buf, ini_file);
+}
+
+
+/*
+ * Write the "prefs"
+ *
+ * We assume that the windows have all been initialized
+ */
+static void save_prefs(void)
+{
+ int i;
+
+ char buf[128];
+
+ /* Save the "arg_graphics" flag */
+ sprintf(buf, "%d", arg_graphics);
+ WritePrivateProfileString("Angband", "Graphics", buf, ini_file);
+
+ /* Save the "arg_bigtile" flag */
+ strcpy(buf, arg_bigtile ? "1" : "0");
+ WritePrivateProfileString("Angband", "Bigtile", buf, ini_file);
+
+ /* Save the "arg_sound" flag */
+ strcpy(buf, arg_sound ? "1" : "0");
+ WritePrivateProfileString("Angband", "Sound", buf, ini_file);
+
+ /* Save window prefs */
+ for (i = 0; i < MAX_TERM_DATA; ++i)
+ {
+ term_data *td = &data[i];
+
+ sprintf(buf, "Term-%d", i);
+
+ save_prefs_aux(td, buf);
+ }
+}
+
+
+/*
+ * Load the "prefs" for a single term
+ */
+static void load_prefs_aux(term_data *td, cptr sec_name)
+{
+ char tmp[1024];
+
+ int wid, hgt;
+
+ /* Visible */
+ td->visible = (GetPrivateProfileInt(sec_name, "Visible", td->visible, ini_file) != 0);
+
+ /* Desired font, with default */
+ GetPrivateProfileString(sec_name, "Font", "8X13.FON", tmp, 127, ini_file);
+
+ /* Bizarre */
+ td->bizarre = (GetPrivateProfileInt(sec_name, "Bizarre", td->bizarre, ini_file) != 0);
+
+ /* Analyze font, save desired font name */
+ td->font_want = string_make(analyze_font(tmp, &wid, &hgt));
+
+ /* Tile size */
+ td->tile_wid = GetPrivateProfileInt(sec_name, "TileWid", wid, ini_file);
+ td->tile_hgt = GetPrivateProfileInt(sec_name, "TileHgt", hgt, ini_file);
+
+ /* Window size */
+ td->cols = GetPrivateProfileInt(sec_name, "NumCols", td->cols, ini_file);
+ td->rows = GetPrivateProfileInt(sec_name, "NumRows", td->rows, ini_file);
+
+ /* Window position */
+ td->pos_x = GetPrivateProfileInt(sec_name, "PositionX", td->pos_x, ini_file);
+ td->pos_y = GetPrivateProfileInt(sec_name, "PositionY", td->pos_y, ini_file);
+}
+
+
+/*
+ * Load the "prefs"
+ */
+static void load_prefs(void)
+{
+ int i;
+
+ char buf[1024];
+
+ /* Extract the "arg_graphics" flag */
+ arg_graphics = GetPrivateProfileInt("Angband", "Graphics", 0, ini_file);
+
+ /* Extract the "arg_bigtile" flag */
+ arg_bigtile = GetPrivateProfileInt("Angband", "Bigtile", FALSE, ini_file);
+ use_bigtile = arg_bigtile;
+
+ /* Extract the "arg_sound" flag */
+ arg_sound = (GetPrivateProfileInt("Angband", "Sound", 0, ini_file) != 0);
+
+ /* Load window prefs */
+ for (i = 0; i < MAX_TERM_DATA; ++i)
+ {
+ term_data *td = &data[i];
+
+ sprintf(buf, "Term-%d", i);
+
+ load_prefs_aux(td, buf);
+ }
+}
+
+
+/*
+ * Create the new global palette based on the bitmap palette
+ * (if any), and the standard 16 entry palette derived from
+ * "win_clr[]" which is used for the basic 16 Angband colors.
+ *
+ * This function is never called before all windows are ready.
+ *
+ * This function returns FALSE if the new palette could not be
+ * prepared, which should normally be a fatal error. XXX XXX
+ *
+ * Note that only some machines actually use a "palette".
+ */
+static int new_palette(void)
+{
+ HPALETTE hBmPal;
+ HPALETTE hNewPal;
+ HDC hdc;
+ int i, nEntries;
+ int pLogPalSize;
+ int lppeSize;
+ LPLOGPALETTE pLogPal;
+ LPPALETTEENTRY lppe;
+
+ term_data *td;
+
+
+ /* This makes no sense */
+ if (!paletted) return (TRUE);
+
+
+ /* No palette */
+ hBmPal = NULL;
+
+ /* No bitmap */
+ lppeSize = 0;
+ lppe = NULL;
+ nEntries = 0;
+
+#ifdef USE_GRAPHICS
+
+ /* Check the bitmap palette */
+ hBmPal = infGraph.hPalette;
+
+ /* Use the bitmap */
+ if (hBmPal)
+ {
+ lppeSize = 256 * sizeof(PALETTEENTRY);
+ lppe = (LPPALETTEENTRY)ralloc(lppeSize);
+ nEntries = GetPaletteEntries(hBmPal, 0, 255, lppe);
+ if ((nEntries == 0) || (nEntries > 220))
+ {
+ /* Warn the user */
+ plog_fmt("Unusable bitmap palette (%d entries)", nEntries);
+
+ /* Cleanup */
+ rnfree(lppe, lppeSize);
+
+ /* Fail */
+ return (FALSE);
+ }
+ }
+
+#endif
+
+ /* Size of palette */
+ pLogPalSize = sizeof(LOGPALETTE) + (nEntries + 16) * sizeof(PALETTEENTRY);
+
+ /* Allocate palette */
+ pLogPal = (LPLOGPALETTE)ralloc(pLogPalSize);
+
+ /* Version */
+ pLogPal->palVersion = 0x300;
+
+ /* Make room for bitmap and normal data */
+ pLogPal->palNumEntries = nEntries + 16;
+
+ /* Save the bitmap data */
+ for (i = 0; i < nEntries; i++)
+ {
+ pLogPal->palPalEntry[i] = lppe[i];
+ }
+
+ /* Save the normal data */
+ for (i = 0; i < 16; i++)
+ {
+ LPPALETTEENTRY p;
+
+ /* Access the entry */
+ p = &(pLogPal->palPalEntry[i + nEntries]);
+
+ /* Save the colors */
+ p->peRed = GetRValue(win_clr[i]);
+ p->peGreen = GetGValue(win_clr[i]);
+ p->peBlue = GetBValue(win_clr[i]);
+
+ /* Save the flags */
+ p->peFlags = PC_NOCOLLAPSE;
+ }
+
+ /* Free something */
+ if (lppe) rnfree(lppe, lppeSize);
+
+ /* Create a new palette, or fail */
+ hNewPal = CreatePalette(pLogPal);
+ if (!hNewPal) quit("Cannot create palette!");
+
+ /* Free the palette */
+ rnfree(pLogPal, pLogPalSize);
+
+ /* Main window */
+ td = &data[0];
+
+ /* Realize the palette */
+ hdc = GetDC(td->w);
+ SelectPalette(hdc, hNewPal, 0);
+ i = RealizePalette(hdc);
+ ReleaseDC(td->w, hdc);
+ if (i == 0) quit("Cannot realize palette!");
+
+ /* Sub-windows */
+ for (i = 1; i < MAX_TERM_DATA; i++)
+ {
+ td = &data[i];
+
+ hdc = GetDC(td->w);
+ SelectPalette(hdc, hNewPal, 0);
+ ReleaseDC(td->w, hdc);
+ }
+
+ /* Delete old palette */
+ if (hPal) DeleteObject(hPal);
+
+ /* Save new palette */
+ hPal = hNewPal;
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Initialize graphics
+ */
+static bool_ init_graphics()
+{
+ /* Initialize once */
+ /*if (can_use_graphics != arg_graphics) */
+ {
+ char buf[1024];
+ int wid, hgt;
+ cptr name;
+
+ /* Unused */
+ PALETTEENTRY entry =
+ {
+ 0, 0, 0, 0
+ };
+ (void)entry;
+
+ if (arg_graphics == 2)
+ {
+ wid = 16;
+ hgt = 16;
+
+ name = "16X16.BMP";
+
+ ANGBAND_GRAF = "new";
+ }
+ else
+ {
+ wid = 8;
+ hgt = 8;
+
+ name = "8X8.BMP";
+ ANGBAND_GRAF = "old";
+ }
+
+ /* Access the bitmap file */
+ path_build(buf, 1024, ANGBAND_DIR_XTRA_GRAF, name);
+
+ /* Load the bitmap or quit */
+ if (!ReadDIB(data[0].w, buf, &infGraph))
+ {
+ plog_fmt("Cannot read bitmap file '%s'", name);
+ return (FALSE);
+ }
+
+ /* Save the new sizes */
+ infGraph.CellWidth = wid;
+ infGraph.CellHeight = hgt;
+
+
+ path_build(buf, 1024, ANGBAND_DIR_XTRA_GRAF, "mask.bmp");
+ /* Load the bitmap or quit */
+ if (!ReadDIB(data[0].w, buf, &infMask))
+ {
+ plog_fmt("Cannot read bitmap file '%s'", name);
+ return (FALSE);
+ }
+
+ /* Activate a palette */
+ if (!new_palette())
+ {
+ /* Free bitmap XXX XXX XXX */
+
+ /* Oops */
+ plog("Cannot activate palette!");
+ return (FALSE);
+ }
+
+ /* Graphics available */
+ can_use_graphics = arg_graphics;
+ }
+
+ /* Result */
+ return (can_use_graphics);
+}
+
+
+/*
+ * Initialize sound
+ */
+static bool_ init_sound()
+{
+ /* Initialize once */
+ if (!can_use_sound)
+ {
+ int i;
+
+ char wav[128];
+ char buf[1024];
+
+ /* Prepare the sounds */
+ for (i = 1; i < SOUND_MAX; i++)
+ {
+ /* Extract name of sound file */
+ sprintf(wav, "%s.wav", angband_sound_name[i]);
+
+ /* Access the sound */
+ path_build(buf, 1024, ANGBAND_DIR_XTRA_SOUND, wav);
+
+ /* Save the sound filename, if it exists */
+ if (check_file(buf)) sound_file[i] = string_make(buf);
+ }
+
+ /* Sound available */
+ can_use_sound = TRUE;
+ }
+
+ /* Result */
+ return (can_use_sound);
+}
+
+
+
+/*
+ * Resize a window
+ */
+static void term_window_resize(term_data *td)
+{
+ /* Require window */
+ if (!td->w) return;
+
+ /* Resize the window */
+ SetWindowPos(td->w, 0, 0, 0,
+ td->size_wid, td->size_hgt,
+ SWP_NOMOVE | SWP_NOZORDER);
+
+ /* Redraw later */
+ InvalidateRect(td->w, NULL, TRUE);
+}
+
+
+
+/*
+ * Force the use of a new "font file" for a term_data
+ *
+ * This function may be called before the "window" is ready
+ *
+ * This function returns zero only if everything succeeds.
+ *
+ * Note that the "font name" must be capitalized!!!
+ */
+static errr term_force_font(term_data *td, cptr path)
+{
+ int i;
+
+ int wid, hgt;
+
+ char *base;
+
+ char buf[1024];
+
+
+ /* Forget the old font (if needed) */
+ if (td->font_id) DeleteObject(td->font_id);
+
+ /* Forget old font */
+ if (td->font_file)
+ {
+ bool_ used = FALSE;
+
+ /* Scan windows */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ /* Check "screen" */
+ if ((td != &data[i]) &&
+ (data[i].font_file) &&
+ (streq(data[i].font_file, td->font_file)))
+ {
+ used = TRUE;
+ }
+ }
+
+ /* Remove unused font resources */
+ if (!used) RemoveFontResource(td->font_file);
+
+ /* Free the old name */
+ string_free(td->font_file);
+
+ /* Forget it */
+ td->font_file = NULL;
+ }
+
+
+ /* No path given */
+ if (!path) return (1);
+
+
+ /* Local copy */
+ strcpy(buf, path);
+
+ /* Analyze font path */
+ base = analyze_font(buf, &wid, &hgt);
+
+ /* Verify suffix */
+ if (!suffix(base, ".FON")) return (1);
+
+ /* Verify file */
+ if (!check_file(buf)) return (1);
+
+ /* Load the new font */
+ if (!AddFontResource(buf)) return (1);
+
+ /* Save new font name */
+ td->font_file = string_make(base);
+
+ /* Remove the "suffix" */
+ base[strlen(base) - 4] = '\0';
+
+ /* Create the font (using the 'base' of the font file name!) */
+ td->font_id = CreateFont(hgt, wid, 0, 0, FW_DONTCARE, 0, 0, 0,
+ ANSI_CHARSET, OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
+ FIXED_PITCH | FF_DONTCARE, base);
+
+ /* Hack -- Unknown size */
+ if (!wid || !hgt)
+ {
+ HDC hdcDesktop;
+ HFONT hfOld;
+ TEXTMETRIC tm;
+
+ /* all this trouble to get the cell size */
+ hdcDesktop = GetDC(HWND_DESKTOP);
+ hfOld = SelectObject(hdcDesktop, td->font_id);
+ GetTextMetrics(hdcDesktop, &tm);
+ SelectObject(hdcDesktop, hfOld);
+ ReleaseDC(HWND_DESKTOP, hdcDesktop);
+
+ /* Font size info */
+ wid = tm.tmAveCharWidth;
+ hgt = tm.tmHeight;
+ }
+
+ /* Save the size info */
+ td->font_wid = wid;
+ td->font_hgt = hgt;
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Allow the user to change the font for this window.
+ */
+static void term_change_font(term_data *td)
+{
+ OPENFILENAME ofn;
+
+ char tmp[1024] = "";
+
+ /* Extract a default if possible */
+ if (td->font_file) strcpy(tmp, td->font_file);
+
+ /* Ask for a choice */
+ memset(&ofn, 0, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = data[0].w;
+ ofn.lpstrFilter = "Angband Font Files (*.fon)\0*.fon\0";
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = tmp;
+ ofn.nMaxFile = 128;
+ ofn.lpstrInitialDir = ANGBAND_DIR_XTRA_FONT;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
+ ofn.lpstrDefExt = "fon";
+
+ /* Force choice if legal */
+ if (GetOpenFileName(&ofn))
+ {
+ /* Force the font */
+ if (term_force_font(td, tmp))
+ {
+ /* Access the standard font file */
+ path_build(tmp, 1024, ANGBAND_DIR_XTRA_FONT, "8X13.FON");
+
+ /* Force the use of that font */
+ (void)term_force_font(td, tmp);
+ }
+
+ /* Assume not bizarre */
+ td->bizarre = FALSE;
+
+ /* Reset the tile info */
+ td->tile_wid = td->font_wid;
+ td->tile_hgt = td->font_hgt;
+
+ /* Analyze the font */
+ term_getsize(td);
+
+ /* Resize the window */
+ term_window_resize(td);
+ }
+}
+
+
+
+/*
+ * Hack -- redraw a term_data
+ */
+static void term_data_redraw(term_data *td)
+{
+ /* Activate the term */
+ Term_activate(&td->t);
+
+ /* Redraw the contents */
+ Term_redraw();
+
+ /* Restore the term */
+ Term_activate(term_screen);
+}
+
+
+
+
+
+/*** Function hooks needed by "Term" ***/
+
+
+#if 0
+
+/*
+ * Initialize a new Term
+ */
+static void Term_init_win(term *t)
+{
+ /* XXX Unused */
+}
+
+
+/*
+ * Nuke an old Term
+ */
+static void Term_nuke_win(term *t)
+{
+ /* XXX Unused */
+}
+
+#endif
+
+
+/*
+ * Interact with the User
+ */
+static errr Term_user_win(int n)
+{
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * React to global changes
+ */
+static errr Term_xtra_win_react(void)
+{
+ int i;
+
+
+ /* Simple color */
+ if (colors16)
+ {
+ /* Save the default colors */
+ for (i = 0; i < 256; i++)
+ {
+ /* Simply accept the desired colors */
+ win_pal[i] = angband_color_table[i][0];
+ }
+ }
+
+ /* Complex color */
+ else
+ {
+ COLORREF code;
+
+ byte rv, gv, bv;
+
+ bool_ change = FALSE;
+
+ /* Save the default colors */
+ for (i = 0; i < 256; i++)
+ {
+ /* Extract desired values */
+ rv = angband_color_table[i][1];
+ gv = angband_color_table[i][2];
+ bv = angband_color_table[i][3];
+
+ /* Extract a full color code */
+ code = PALETTERGB(rv, gv, bv);
+
+ /* Activate changes */
+ if (win_clr[i] != code)
+ {
+ /* Note the change */
+ change = TRUE;
+
+ /* Apply the desired color */
+ win_clr[i] = code;
+ }
+ }
+
+ /* Activate the palette if needed */
+ if (change) (void)new_palette();
+ }
+
+
+#ifdef USE_SOUND
+
+ /* Handle "arg_sound" */
+ if (use_sound != arg_sound)
+ {
+ /* Initialize (if needed) */
+ if (arg_sound && !init_sound())
+ {
+ /* Warning */
+ plog("Cannot initialize sound!");
+
+ /* Cannot enable */
+ arg_sound = FALSE;
+ }
+
+ /* Change setting */
+ use_sound = arg_sound;
+ }
+
+#endif
+
+
+#ifdef USE_GRAPHICS
+
+ /* Handle "arg_graphics" */
+ if (use_graphics != arg_graphics)
+ {
+ /* Initialize (if needed) */
+ if (arg_graphics && !init_graphics())
+ {
+ /* Warning */
+ plog("Cannot initialize graphics!");
+
+ /* Cannot enable */
+ arg_graphics = FALSE;
+ }
+
+ /* Change setting */
+ use_graphics = arg_graphics;
+
+ /* Reset visuals */
+ reset_visuals();
+ }
+
+#endif /* USE_GRAPHICS */
+
+
+ /* Clean up windows */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ term *old = Term;
+
+ term_data *td = &data[i];
+
+ /* Update resized windows */
+ if ((td->cols != td->t.wid) || (td->rows != td->t.hgt))
+ {
+ /* Activate */
+ Term_activate(&td->t);
+
+ /* Hack -- Resize the term */
+ Term_resize(td->cols, td->rows);
+
+ /* Redraw the contents */
+ Term_redraw();
+
+ /* Restore */
+ Term_activate(old);
+ }
+ }
+
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Process at least one event
+ */
+static errr Term_xtra_win_event(int v)
+{
+ MSG msg;
+
+ /* Wait for an event */
+ if (v)
+ {
+ /* Block */
+ if (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ /* Check for an event */
+ else
+ {
+ /* Check */
+ if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ /* Success */
+ return 0;
+}
+
+
+/*
+ * Process all pending events
+ */
+static errr Term_xtra_win_flush(void)
+{
+ MSG msg;
+
+ /* Process all pending events */
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Hack -- clear the screen
+ *
+ * Make this more efficient XXX XXX XXX
+ */
+static errr Term_xtra_win_clear(void)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ HDC hdc;
+ RECT rc;
+
+ /* Rectangle to erase */
+ rc.left = td->size_ow1;
+ rc.right = rc.left + td->cols * td->tile_wid;
+ rc.top = td->size_oh1;
+ rc.bottom = rc.top + td->rows * td->tile_hgt;
+
+ /* Erase it */
+ hdc = GetDC(td->w);
+ SetBkColor(hdc, RGB(0, 0, 0));
+ SelectObject(hdc, td->font_id);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
+ ReleaseDC(td->w, hdc);
+
+ /* Success */
+ return 0;
+}
+
+
+/*
+ * Hack -- make a noise
+ */
+static errr Term_xtra_win_noise(void)
+{
+ MessageBeep(MB_ICONASTERISK);
+ return (0);
+}
+
+
+/*
+ * Hack -- make a sound
+ */
+static errr Term_xtra_win_sound(int v)
+{
+ /* Sound disabled */
+ if (!use_sound) return (1);
+
+ /* Illegal sound */
+ if ((v < 0) || (v >= SOUND_MAX)) return (1);
+
+ /* Unknown sound */
+ if (!sound_file[v]) return (1);
+
+#ifdef USE_SOUND
+
+#ifdef WIN32
+
+ /* Play the sound, catch errors */
+ return (PlaySound(sound_file[v], 0, SND_FILENAME | SND_ASYNC));
+
+#else /* WIN32 */
+
+/* Play the sound, catch errors */
+ return (sndPlaySound(sound_file[v], SND_ASYNC));
+
+#endif /* WIN32 */
+
+#endif /* USE_SOUND */
+
+ /* Oops */
+ return (1);
+}
+
+
+/*
+ * Delay for "x" milliseconds
+ */
+static int Term_xtra_win_delay(int v)
+{
+
+#ifdef WIN32
+
+ /* Sleep */
+ Sleep(v);
+
+#else /* WIN32 */
+
+ DWORD t;
+ MSG msg;
+
+ /* Final count */
+ t = GetTickCount() + v;
+
+ /* Wait for it */
+ while (GetTickCount() < t)
+ {
+ /* Handle messages */
+ if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+#endif /* WIN32 */
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Return the HWND of the main window
+ */
+HWND get_main_hwnd()
+{
+ return data[0].w;
+}
+
+/*
+ * Do a "special thing"
+ */
+static errr Term_xtra_win(int n, int v)
+{
+ /* Handle a subset of the legal requests */
+ switch (n)
+ {
+ /* Make a bell sound */
+ case TERM_XTRA_NOISE:
+ {
+ return (Term_xtra_win_noise());
+ }
+
+ /* Make a special sound */
+ case TERM_XTRA_SOUND:
+ {
+ return (Term_xtra_win_sound(v));
+ }
+
+ /* Process random events */
+ case TERM_XTRA_BORED:
+ {
+ return (Term_xtra_win_event(0));
+ }
+
+ /* Process an event */
+ case TERM_XTRA_EVENT:
+ {
+ return (Term_xtra_win_event(v));
+ }
+
+ /* Flush all events */
+ case TERM_XTRA_FLUSH:
+ {
+ return (Term_xtra_win_flush());
+ }
+
+ /* Clear the screen */
+ case TERM_XTRA_CLEAR:
+ {
+ return (Term_xtra_win_clear());
+ }
+
+ /* React to global changes */
+ case TERM_XTRA_REACT:
+ {
+ return (Term_xtra_win_react());
+ }
+
+ /* Delay for some milliseconds */
+ case TERM_XTRA_DELAY:
+ {
+ return (Term_xtra_win_delay(v));
+ }
+
+ /* Get the current time in milliseconds */
+ case TERM_XTRA_GET_DELAY:
+ {
+ DWORD t;
+
+ t = GetTickCount();
+ Term_xtra_long = t;
+ return 0;
+ }
+
+ /*
+ * Scans for subdirectories in a directory "scansubdir_dir"
+ * and place teh result in "scansubdir_result/scansubdir_max"
+ */
+ case TERM_XTRA_SCANSUBDIR:
+ {
+ BOOL ok;
+ HANDLE h;
+ WIN32_FIND_DATA fd;
+ for (h = FindFirstFile(format("%s\\*", scansubdir_dir), &fd), ok = 1;
+ h != INVALID_HANDLE_VALUE && ok;
+ ok = FindNextFile(h, &fd))
+ {
+ if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (strcmp(fd.cFileName, ".")) && (strcmp(fd.cFileName, "..")))
+ {
+ string_free(scansubdir_result[scansubdir_max]);
+ scansubdir_result[scansubdir_max] = string_make(fd.cFileName);
+ scansubdir_max++;
+ }
+ }
+
+ return 0;
+ }
+
+ /* Rename main window */
+ case TERM_XTRA_RENAME_MAIN_WIN:
+ SetWindowText(get_main_hwnd(), angband_term_name[0]); return (0);
+ }
+
+ /* Oops */
+ return 1;
+}
+
+
+
+/*
+ * Low level graphics (Assumes valid input).
+ *
+ * Draw a "cursor" at (x,y), using a "yellow box".
+ */
+static errr Term_curs_win(int x, int y)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ RECT rc;
+ HDC hdc;
+
+ /* Frame the grid */
+ rc.left = x * td->tile_wid + td->size_ow1;
+ rc.right = rc.left + td->tile_wid;
+ rc.top = y * td->tile_hgt + td->size_oh1;
+ rc.bottom = rc.top + td->tile_hgt;
+
+ if (use_bigtile && x + 1 < Term->wid && Term->old->a[y][x + 1] == 255)
+ rc.right += td->tile_wid;
+
+ /* Cursor is done as a yellow "box" */
+ hdc = GetDC(data[0].w);
+ FrameRect(hdc, &rc, hbrYellow);
+ ReleaseDC(data[0].w, hdc);
+
+ /* Success */
+ return 0;
+}
+
+
+/*
+ * Low level graphics (Assumes valid input).
+ *
+ * Erase a "block" of "n" characters starting at (x,y).
+ */
+static errr Term_wipe_win(int x, int y, int n)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ HDC hdc;
+ RECT rc;
+
+ /* Rectangle to erase in client coords */
+ rc.left = x * td->tile_wid + td->size_ow1;
+ rc.right = rc.left + n * td->tile_wid;
+ rc.top = y * td->tile_hgt + td->size_oh1;
+ rc.bottom = rc.top + td->tile_hgt;
+
+ hdc = GetDC(td->w);
+ SetBkColor(hdc, RGB(0, 0, 0));
+ SelectObject(hdc, td->font_id);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
+ ReleaseDC(td->w, hdc);
+
+ /* Success */
+ return 0;
+}
+
+/*
+ * Low level graphics. Assumes valid input.
+ *
+ * Draw several ("n") chars, with an attr, at a given location.
+ *
+ * All "graphic" data is handled by "Term_pict_win()", below.
+ *
+ * One would think there is a more efficient method for telling a window
+ * what color it should be using to draw with, but perhaps simply changing
+ * it every time is not too inefficient. XXX XXX XXX
+ */
+static errr Term_text_win(int x, int y, int n, byte a, const char *s)
+{
+ term_data *td = (term_data*)(Term->data);
+ RECT rc;
+ HDC hdc;
+
+
+ /* Total rectangle */
+ rc.left = x * td->tile_wid + td->size_ow1;
+ rc.right = rc.left + n * td->tile_wid;
+ rc.top = y * td->tile_hgt + td->size_oh1;
+ rc.bottom = rc.top + td->tile_hgt;
+
+ /* Acquire DC */
+ hdc = GetDC(td->w);
+
+ /* Background color */
+ SetBkColor(hdc, RGB(0, 0, 0));
+
+ /* Foreground color */
+ if (colors16)
+ {
+ SetTextColor(hdc, PALETTEINDEX(win_pal[a]));
+ }
+ else if (paletted)
+ {
+ SetTextColor(hdc, win_clr[a&0x0F]);
+ }
+ else
+ {
+ SetTextColor(hdc, win_clr[a]);
+ }
+
+ /* Use the font */
+ SelectObject(hdc, td->font_id);
+
+ /* Bizarre size */
+ if (td->bizarre ||
+ (td->tile_hgt != td->font_hgt) ||
+ (td->tile_wid != td->font_wid))
+ {
+ int i;
+
+ /* Erase complete rectangle */
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
+
+ /* New rectangle */
+ rc.left += ((td->tile_wid - td->font_wid) / 2);
+ rc.right = rc.left + td->font_wid;
+ rc.top += ((td->tile_hgt - td->font_hgt) / 2);
+ rc.bottom = rc.top + td->font_hgt;
+
+ /* Dump each character */
+ for (i = 0; i < n; i++)
+ {
+ /* Dump the text */
+ ExtTextOut(hdc, rc.left, rc.top, 0, &rc,
+ s + i, 1, NULL);
+
+ /* Advance */
+ rc.left += td->tile_wid;
+ rc.right += td->tile_wid;
+ }
+ }
+
+ /* Normal size */
+ else
+ {
+ /* Dump the text */
+ ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE | ETO_CLIPPED, &rc,
+ s, n, NULL);
+ }
+
+ /* Release DC */
+ ReleaseDC(td->w, hdc);
+
+ /* Success */
+ return 0;
+}
+
+
+/*
+ * Low level graphics. Assumes valid input.
+ *
+ * Draw an array of "special" attr/char pairs at the given location.
+ *
+ * We use the "Term_pict_win()" function for "graphic" data, which are
+ * encoded by setting the "high-bits" of both the "attr" and the "char"
+ * data. We use the "attr" to represent the "row" of the main bitmap,
+ * and the "char" to represent the "col" of the main bitmap. The use
+ * of this function is induced by the "higher_pict" flag.
+ *
+ * If "graphics" is not available, we simply "wipe" the given grids.
+ */
+static errr Term_pict_win(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp, const byte *eap, const char *ecp)
+{
+ term_data *td = (term_data*)(Term->data);
+
+#ifdef USE_GRAPHICS
+
+ int i;
+ int x1, y1, w1, h1;
+ int x2, y2, w2, h2, tw2;
+
+ int x3, y3;
+
+ HDC hdcMask = NULL;
+
+ int x4, y4;
+
+ HDC hdc;
+ HDC hdcSrc;
+ HBITMAP hbmSrcOld;
+
+ /* Paranoia */
+ if (!use_graphics)
+ {
+ /* Erase the grids */
+ return (Term_wipe_win(x, y, n));
+ }
+
+ /* Size of bitmap cell */
+ w1 = infGraph.CellWidth;
+ h1 = infGraph.CellHeight;
+
+ /* Size of window cell */
+ w2 = td->tile_wid;
+ h2 = td->tile_hgt;
+ tw2 = w2;
+
+ /* big tile mode */
+ if (use_bigtile) tw2 *= 2;
+
+ /* Location of window cell */
+ x2 = x * w2 + td->size_ow1;
+ y2 = y * h2 + td->size_oh1;
+
+ /* Info */
+ hdc = GetDC(td->w);
+
+ /* More info */
+ hdcSrc = CreateCompatibleDC(hdc);
+ hbmSrcOld = SelectObject(hdcSrc, infGraph.hBitmap);
+
+ if (arg_graphics == 2)
+ {
+ hdcMask = CreateCompatibleDC(hdc);
+ SelectObject(hdcMask, infMask.hBitmap);
+ }
+
+ /* Draw attr/char pairs */
+ for (i = 0; i < n; i++, x2 += w2)
+ {
+ byte a = ap[i];
+ char c = cp[i];
+
+ /* Extract picture */
+ int row = (a & 0x7F);
+ int col = (c & 0x7F);
+
+ /* Location of bitmap cell */
+ x1 = col * w1;
+ y1 = row * h1;
+
+ if (arg_graphics == 2)
+ {
+ x3 = (tcp[i] & 0x7F) * w1;
+ y3 = (tap[i] & 0x7F) * h1;
+
+ /* Perfect size */
+ if ((w1 == tw2) && (h1 == h2))
+ {
+ /* Copy the terrain picture from the bitmap to the window */
+ BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, SRCCOPY);
+
+ /* Mask out the tile */
+ BitBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, SRCAND);
+
+ /* Draw the tile */
+ BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCPAINT);
+
+ if (ecp[i] != 0 && eap[i] != 0)
+ {
+ x4 = (ecp[i] & 0x7F) * w1;
+ y4 = (eap[i] & 0x7F) * h1;
+
+ /* Mask out the tile */
+ BitBlt(hdc, x2, y2, tw2, h2, hdcMask, x4, y4, SRCAND);
+
+ /* Draw the tile */
+ BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x4, y4, SRCPAINT);
+ }
+ }
+
+ /* Need to stretch */
+ else
+ {
+ /* Set the correct mode for stretching the tiles */
+ SetStretchBltMode(hdc, COLORONCOLOR);
+
+ /* Copy the terrain picture from the bitmap to the window */
+ StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, w1, h1, SRCCOPY);
+
+ /* Only draw if terrain and overlay are different */
+ if ((x1 != x3) || (y1 != y3))
+ {
+ /* Mask out the tile */
+ StretchBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, w1, h1, SRCAND);
+
+ /* Draw the tile */
+ StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCPAINT);
+ }
+
+ if (ecp[i] != 0 && eap[i] != 0)
+ {
+ x4 = (ecp[i] & 0x7F) * w1;
+ y4 = (eap[i] & 0x7F) * h1;
+
+ /* Mask out the tile */
+ StretchBlt(hdc, x2, y2, tw2, h2, hdcMask, x4, y4, w1, h1, SRCAND);
+
+ /* Draw the tile */
+ StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x4, y4, w1, h1, SRCPAINT);
+ }
+ }
+ }
+ else
+ {
+ /* Perfect size */
+ if ((w1 == tw2) && (h1 == h2))
+ {
+ /* Copy the picture from the bitmap to the window */
+ BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCCOPY);
+ }
+
+ /* Need to stretch */
+ else
+ {
+ /* Set the correct mode for stretching the tiles */
+ SetStretchBltMode(hdc, COLORONCOLOR);
+
+ /* Copy the picture from the bitmap to the window */
+ StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCCOPY);
+ }
+ }
+ }
+
+ /* Release */
+ SelectObject(hdcSrc, hbmSrcOld);
+ DeleteDC(hdcSrc);
+
+ if (arg_graphics == 2)
+ {
+ /* Release */
+ SelectObject(hdcMask, hbmSrcOld);
+ DeleteDC(hdcMask);
+ }
+
+ /* Release */
+ ReleaseDC(td->w, hdc);
+
+#else /* USE_GRAPHICS */
+
+ /* Just erase this grid */
+ return (Term_wipe_win(x, y, n));
+
+#endif /* USE_GRAPHICS */
+
+ /* Success */
+ return 0;
+}
+
+
+/*** Other routines ***/
+
+
+/*
+ * Create and initialize a "term_data" given a title
+ */
+static void term_data_link(term_data *td)
+{
+ term *t = &td->t;
+
+ /* Initialize the term */
+ term_init(t, td->cols, td->rows, td->keys);
+
+ /* Use a "software" cursor */
+ t->soft_cursor = TRUE;
+
+ /* Use "Term_pict" for "graphic" data */
+ t->higher_pict = TRUE;
+
+ /* Erase with "white space" */
+ t->attr_blank = TERM_WHITE;
+ t->char_blank = ' ';
+
+#if 0
+ /* Prepare the init/nuke hooks */
+ t->init_hook = Term_init_win;
+ t->nuke_hook = Term_nuke_win;
+#endif
+
+ /* Prepare the template hooks */
+ t->user_hook = Term_user_win;
+ t->xtra_hook = Term_xtra_win;
+ t->curs_hook = Term_curs_win;
+ t->wipe_hook = Term_wipe_win;
+ t->text_hook = Term_text_win;
+ t->pict_hook = Term_pict_win;
+
+ /* Remember where we came from */
+ t->data = (vptr)(td);
+}
+
+
+/*
+ * Create the windows
+ *
+ * First, instantiate the "default" values, then read the "ini_file"
+ * to over-ride selected values, then create the windows, and fonts.
+ *
+ * Must use SW_SHOW not SW_SHOWNA, since on 256 color display
+ * must make active to realize the palette. XXX XXX XXX
+ */
+static void init_windows(void)
+{
+ int i;
+
+ term_data *td;
+
+ char buf[1024];
+
+
+ /* Main window */
+ td = &data[0];
+ WIPE(td, term_data);
+ td->s = angband_term_name[0];
+ td->keys = 1024;
+ td->rows = 24;
+ td->cols = 80;
+ td->visible = TRUE;
+ td->size_ow1 = 2;
+ td->size_ow2 = 2;
+ td->size_oh1 = 2;
+ td->size_oh2 = 2;
+ td->pos_x = 7 * 30;
+ td->pos_y = 7 * 20;
+
+ /* Sub windows */
+ for (i = 1; i < MAX_TERM_DATA; i++)
+ {
+ td = &data[i];
+ WIPE(td, term_data);
+ td->s = angband_term_name[i];
+ td->keys = 16;
+ td->rows = 24;
+ td->cols = 80;
+ td->visible = FALSE;
+ td->size_ow1 = 1;
+ td->size_ow2 = 1;
+ td->size_oh1 = 1;
+ td->size_oh2 = 1;
+ td->pos_x = (7 - i) * 30;
+ td->pos_y = (7 - i) * 20;
+ }
+
+
+ /* Load prefs */
+ load_prefs();
+
+
+ /* Main window (need these before term_getsize gets called) */
+ td = &data[0];
+ td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU |
+ WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION |
+ WS_VISIBLE);
+ td->dwExStyle = 0;
+ td->visible = TRUE;
+
+ /* Sub windows (need these before term_getsize gets called) */
+ for (i = 1; i < MAX_TERM_DATA; i++)
+ {
+ td = &data[i];
+ td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU);
+ td->dwExStyle = (WS_EX_TOOLWINDOW);
+ }
+
+
+ /* All windows */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ td = &data[i];
+
+ /* Access the standard font file */
+ path_build(buf, 1024, ANGBAND_DIR_XTRA_FONT, td->font_want);
+
+ /* Activate the chosen font */
+ if (term_force_font(td, buf))
+ {
+ /* Access the standard font file */
+ path_build(buf, 1024, ANGBAND_DIR_XTRA_FONT, "8X13.FON");
+
+ /* Force the use of that font */
+ (void)term_force_font(td, buf);
+
+ /* Oops */
+ td->tile_wid = 8;
+ td->tile_hgt = 13;
+
+ /* Assume not bizarre */
+ td->bizarre = FALSE;
+ }
+
+ /* Analyze the font */
+ term_getsize(td);
+
+ /* Resize the window */
+ term_window_resize(td);
+ }
+
+
+ /* Sub windows (reverse order) */
+ for (i = MAX_TERM_DATA - 1; i >= 1; --i)
+ {
+ td = &data[i];
+
+ my_td = td;
+ td->w = CreateWindowEx(td->dwExStyle, AngList,
+ td->s, td->dwStyle,
+ td->pos_x, td->pos_y,
+ td->size_wid, td->size_hgt,
+ HWND_DESKTOP, NULL, hInstance, NULL);
+ my_td = NULL;
+ if (!td->w) quit("Failed to create sub-window");
+
+ if (td->visible)
+ {
+ td->size_hack = TRUE;
+ ShowWindow(td->w, SW_SHOW);
+ td->size_hack = FALSE;
+ }
+
+ term_data_link(td);
+ angband_term[i] = &td->t;
+
+ if (td->visible)
+ {
+ /* Activate the window */
+ SetActiveWindow(td->w);
+
+ /* Bring window to top */
+ SetWindowPos(td->w, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ }
+ }
+
+
+ /* Main window */
+ td = &data[0];
+
+ /* Main window */
+ my_td = td;
+ td->w = CreateWindowEx(td->dwExStyle, AppName,
+ td->s, td->dwStyle,
+ td->pos_x, td->pos_y,
+ td->size_wid, td->size_hgt,
+ HWND_DESKTOP, NULL, hInstance, NULL);
+ my_td = NULL;
+ if (!td->w) quit("Failed to create Angband window");
+
+ term_data_link(td);
+ angband_term[0] = &td->t;
+
+ /* Activate the main window */
+ SetActiveWindow(td->w);
+
+ /* Bring main window back to top */
+ SetWindowPos(td->w, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+
+
+ /* New palette XXX XXX XXX */
+ (void)new_palette();
+
+
+ /* Create a "brush" for drawing the "cursor" */
+ hbrYellow = CreateSolidBrush(win_clr[TERM_YELLOW]);
+
+
+ /* Process pending messages */
+ (void)Term_xtra_win_flush();
+}
+
+
+
+/*
+ * Prepare the menus
+ */
+static void setup_menus(void)
+{
+ int i;
+
+ HMENU hm = GetMenu(data[0].w);
+
+
+ /* Menu "File", Disable all */
+ EnableMenuItem(hm, IDM_FILE_NEW,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+ EnableMenuItem(hm, IDM_FILE_OPEN,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+ EnableMenuItem(hm, IDM_FILE_SAVE,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+#ifdef ALLOW_QUITTING
+ EnableMenuItem(hm, IDM_FILE_ABORT,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+#else
+ EnableMenuItem(hm, IDM_FILE_SCORE,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+#endif /* ALLOW_QUITTING */
+ EnableMenuItem(hm, IDM_FILE_EXIT,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+
+ /* No character available */
+ if (!character_generated)
+ {
+ /* Menu "File", Item "New" */
+ EnableMenuItem(hm, IDM_FILE_NEW,
+ MF_BYCOMMAND | MF_ENABLED);
+
+ /* Menu "File", Item "Open" */
+ EnableMenuItem(hm, IDM_FILE_OPEN,
+ MF_BYCOMMAND | MF_ENABLED);
+ }
+
+ /* A character available */
+ if (character_generated)
+ {
+ /* Menu "File", Item "Save" */
+ EnableMenuItem(hm, IDM_FILE_SAVE,
+ MF_BYCOMMAND | MF_ENABLED);
+ }
+
+#ifdef ALLOW_QUITTING
+
+ /* Menu "File", Item "Abort" */
+ EnableMenuItem(hm, IDM_FILE_ABORT,
+ MF_BYCOMMAND | MF_ENABLED);
+
+#else
+
+ /* Menu "File", Item "Score" */
+ if (initialized && character_generated && !character_icky)
+ {
+ EnableMenuItem(hm, IDM_FILE_SCORE,
+ MF_BYCOMMAND | MF_ENABLED);
+ }
+
+#endif
+
+ /* Menu "File", Item "Exit" */
+ EnableMenuItem(hm, IDM_FILE_EXIT,
+ MF_BYCOMMAND | MF_ENABLED);
+
+
+ /* Menu "Window::Visibility" */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+
+ CheckMenuItem(hm, IDM_WINDOW_VIS_0 + i,
+ (data[i].visible ? MF_CHECKED : MF_UNCHECKED));
+
+ EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i,
+ MF_BYCOMMAND | MF_ENABLED);
+ }
+
+ /* Menu "Window::Font" */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+
+ if (data[i].visible)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i,
+ MF_BYCOMMAND | MF_ENABLED);
+ }
+ }
+
+ /* Menu "Window::Bizarre Display" */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_BIZ_0 + i,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+
+ CheckMenuItem(hm, IDM_WINDOW_BIZ_0 + i,
+ (data[i].bizarre ? MF_CHECKED : MF_UNCHECKED));
+
+ if (data[i].visible)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_BIZ_0 + i,
+ MF_BYCOMMAND | MF_ENABLED);
+
+ }
+ }
+
+ /* Menu "Window::Increase Tile Width" */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+
+ if (data[i].visible)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i,
+ MF_BYCOMMAND | MF_ENABLED);
+
+ }
+ }
+
+ /* Menu "Window::Decrease Tile Width" */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+
+ if (data[i].visible)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i,
+ MF_BYCOMMAND | MF_ENABLED);
+
+ }
+ }
+
+ /* Menu "Window::Increase Tile Height" */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+
+ if (data[i].visible)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i,
+ MF_BYCOMMAND | MF_ENABLED);
+
+ }
+ }
+
+ /* Menu "Window::Decrease Tile Height" */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+
+ if (data[i].visible)
+ {
+ EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i,
+ MF_BYCOMMAND | MF_ENABLED);
+
+ }
+ }
+
+ /* Menu "Options", disable all */
+ EnableMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+ EnableMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+ EnableMenuItem(hm, IDM_OPTIONS_ASCII_GRAPHICS,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+ EnableMenuItem(hm, IDM_OPTIONS_BIGTILE,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+ EnableMenuItem(hm, IDM_OPTIONS_SOUND,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+ EnableMenuItem(hm, IDM_OPTIONS_UNUSED,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+ EnableMenuItem(hm, IDM_OPTIONS_SAVER,
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+
+ /* Menu "Options", update all */
+ CheckMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS,
+ (arg_graphics == 1 ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS,
+ (arg_graphics == 2 ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(hm, IDM_OPTIONS_ASCII_GRAPHICS,
+ (arg_graphics == 0 ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(hm, IDM_OPTIONS_BIGTILE,
+ (arg_bigtile ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(hm, IDM_OPTIONS_SOUND,
+ (arg_sound ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(hm, IDM_OPTIONS_UNUSED,
+ (0 ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(hm, IDM_OPTIONS_SAVER,
+ (hwndSaver ? MF_CHECKED : MF_UNCHECKED));
+
+#ifdef USE_GRAPHICS
+ /* Menu "Options", Item "Graphics" */
+ EnableMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, MF_ENABLED);
+ /* Menu "Options", Item "Graphics" */
+ EnableMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, MF_ENABLED);
+ /* Menu "Options", Item "Graphics" */
+ EnableMenuItem(hm, IDM_OPTIONS_ASCII_GRAPHICS, MF_ENABLED);
+ /* Menu "Options", Item "Graphics" */
+ EnableMenuItem(hm, IDM_OPTIONS_BIGTILE, MF_ENABLED);
+#endif
+
+#ifdef USE_SOUND
+ /* Menu "Options", Item "Sound" */
+ EnableMenuItem(hm, IDM_OPTIONS_SOUND, MF_ENABLED);
+#endif
+
+#ifdef USE_SAVER
+ /* Menu "Options", Item "ScreenSaver" */
+ EnableMenuItem(hm, IDM_OPTIONS_SAVER,
+ MF_BYCOMMAND | MF_ENABLED);
+#endif
+
+}
+
+
+/*
+ * Check for double clicked (or dragged) savefile
+ *
+ * Apparently, Windows copies the entire filename into the first
+ * piece of the "command line string". Perhaps we should extract
+ * the "basename" of that filename and append it to the "save" dir.
+ */
+static void check_for_save_file(LPSTR cmd_line)
+{
+ char *s, *p;
+
+ /* First arg */
+ s = cmd_line;
+
+ /* Second arg */
+ p = strchr(s, ' ');
+
+ /* Tokenize, advance */
+ if (p) *p++ = '\0';
+
+ /* No args */
+ if (!*s) return;
+
+ /* Extract filename */
+ strcat(savefile, s);
+
+ /* Validate the file */
+ validate_file(savefile);
+
+ /* Game in progress */
+ game_in_progress = TRUE;
+
+ /* Play game */
+ play_game(FALSE);
+}
+
+
+/*
+ * Process a menu command
+ */
+static void process_menus(WORD wCmd)
+{
+ int i;
+
+ term_data *td;
+
+ OPENFILENAME ofn;
+
+ /* Analyze */
+ switch (wCmd)
+ {
+ /* New game */
+ case IDM_FILE_NEW:
+ {
+ if (!initialized)
+ {
+ plog("You cannot do that yet...");
+ }
+ else if (game_in_progress)
+ {
+ plog("You can't start a new game while you're still playing!");
+ }
+ else
+ {
+ game_in_progress = TRUE;
+ Term_flush();
+ play_game(TRUE);
+ quit(NULL);
+ }
+ break;
+ }
+
+ /* Open game */
+ case IDM_FILE_OPEN:
+ {
+ if (!initialized)
+ {
+ plog("You cannot do that yet...");
+ }
+ else if (game_in_progress)
+ {
+ plog("You can't open a new game while you're still playing!");
+ }
+ else
+ {
+ memset(&ofn, 0, sizeof(ofn));
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
+ ofn.lStructSize = sizeof(OPENFILENAME) - (sizeof(void*) + 2 * sizeof(DWORD));
+#else // old headers
+ofn.lStructSize = sizeof(OPENFILENAME);
+#endif
+ ofn.hwndOwner = data[0].w;
+ ofn.lpstrFilter = "Save Files (*.)\0*\0";
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = savefile;
+ ofn.nMaxFile = 1024;
+ ofn.lpstrInitialDir = ANGBAND_DIR_SAVE;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
+
+ if (GetOpenFileName(&ofn))
+ {
+ /* Load 'savefile' */
+ validate_file(savefile);
+ game_in_progress = TRUE;
+ Term_flush();
+ play_game(FALSE);
+ quit(NULL);
+ }
+ }
+ break;
+ }
+
+ /* Save game */
+ case IDM_FILE_SAVE:
+ {
+ if (game_in_progress && character_generated)
+ {
+ /* Paranoia */
+ if (!inkey_flag)
+ {
+ plog("You may not do that right now.");
+ break;
+ }
+
+ /* Hack -- Forget messages */
+ msg_flag = FALSE;
+
+ /* Save the game */
+ do_cmd_save_game();
+ }
+ else
+ {
+ plog("You may not do that right now.");
+ }
+ break;
+ }
+
+ /* Exit */
+ case IDM_FILE_EXIT:
+ {
+ if (game_in_progress && character_generated)
+ {
+ /* Paranoia */
+ if (!inkey_flag)
+ {
+ plog("You may not do that right now.");
+ break;
+ }
+
+ /* Hack -- Forget messages */
+ msg_flag = FALSE;
+
+ /* Save the game */
+ do_cmd_save_game();
+ }
+ quit(NULL);
+ break;
+ }
+
+#ifdef ALLOW_QUITTING
+
+ /* Abort */
+ case IDM_FILE_ABORT:
+ {
+ if (game_in_progress && character_generated)
+ {
+ /* XXX XXX XXX */
+ if (MessageBox(data[0].w,
+ "Your character will be not saved!", "Warning",
+ MB_ICONEXCLAMATION | MB_OKCANCEL) == IDCANCEL)
+ {
+ break;
+ }
+ }
+ quit(NULL);
+ break;
+ }
+
+#else
+
+ /* Score */
+ case IDM_FILE_SCORE:
+ {
+ char buf[1024];
+
+ /* Paranoia */
+ if (!initialized || character_icky ||
+ !game_in_progress || !character_generated)
+ {
+ /* Can't happen but just in case */
+ plog("You may not do that right now.");
+
+ break;
+ }
+
+ /* Build the pathname of the score file */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
+
+ /* Hack - open the score file for reading */
+ highscore_fd = fd_open(buf, O_RDONLY);
+
+ /* Paranoia - No score file */
+ if (highscore_fd < 0)
+ {
+ msg_print("Score file is not available.");
+
+ break;
+ }
+
+ /* Mega-Hack - prevent various functions XXX XXX XXX */
+ initialized = FALSE;
+
+ /* Save screen */
+ screen_save();
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Prepare scores */
+ if (game_in_progress && character_generated)
+ {
+ predict_score();
+ }
+
+#if 0 /* I don't like this - pelpel */
+
+ /* Mega-Hack - No current player XXX XXX XXX XXX */
+ else
+ {
+ display_scores_aux(0, MAX_HISCORES, -1, NULL);
+ }
+
+#endif
+
+ /* Close the high score file */
+ (void)fd_close(highscore_fd);
+
+ /* Forget the fd */
+ highscore_fd = -1;
+
+ /* Restore screen */
+ screen_load();
+
+ /* Hack - Flush it */
+ Term_fresh();
+
+ /* Mega-Hack - We are ready again */
+ initialized = TRUE;
+
+ /* Done */
+ break;
+ }
+
+#endif
+
+ case IDM_WINDOW_VIS_0:
+ {
+ plog("You are not allowed to do that!");
+
+ break;
+ }
+
+ /* Window visibility */
+ case IDM_WINDOW_VIS_1:
+ case IDM_WINDOW_VIS_2:
+ case IDM_WINDOW_VIS_3:
+ case IDM_WINDOW_VIS_4:
+ case IDM_WINDOW_VIS_5:
+ case IDM_WINDOW_VIS_6:
+ case IDM_WINDOW_VIS_7:
+ {
+ i = wCmd - IDM_WINDOW_VIS_0;
+
+ if ((i < 0) || (i >= MAX_TERM_DATA)) break;
+
+ td = &data[i];
+
+ if (!td->visible)
+ {
+ td->visible = TRUE;
+ ShowWindow(td->w, SW_SHOW);
+ term_data_redraw(td);
+ }
+ else
+ {
+ td->visible = FALSE;
+ ShowWindow(td->w, SW_HIDE);
+ }
+
+ break;
+ }
+
+ /* Window fonts */
+ case IDM_WINDOW_FONT_0:
+ case IDM_WINDOW_FONT_1:
+ case IDM_WINDOW_FONT_2:
+ case IDM_WINDOW_FONT_3:
+ case IDM_WINDOW_FONT_4:
+ case IDM_WINDOW_FONT_5:
+ case IDM_WINDOW_FONT_6:
+ case IDM_WINDOW_FONT_7:
+ {
+ i = wCmd - IDM_WINDOW_FONT_0;
+
+ if ((i < 0) || (i >= MAX_TERM_DATA)) break;
+
+ td = &data[i];
+
+ term_change_font(td);
+
+ break;
+ }
+
+ /* Bizarre Display */
+ case IDM_WINDOW_BIZ_0:
+ case IDM_WINDOW_BIZ_1:
+ case IDM_WINDOW_BIZ_2:
+ case IDM_WINDOW_BIZ_3:
+ case IDM_WINDOW_BIZ_4:
+ case IDM_WINDOW_BIZ_5:
+ case IDM_WINDOW_BIZ_6:
+ case IDM_WINDOW_BIZ_7:
+ {
+ i = wCmd - IDM_WINDOW_BIZ_0;
+
+ if ((i < 0) || (i >= MAX_TERM_DATA)) break;
+
+ td = &data[i];
+
+ td->bizarre = !td->bizarre;
+
+ term_getsize(td);
+
+ term_window_resize(td);
+
+ break;
+ }
+
+ /* Increase Tile Width */
+ case IDM_WINDOW_I_WID_0:
+ case IDM_WINDOW_I_WID_1:
+ case IDM_WINDOW_I_WID_2:
+ case IDM_WINDOW_I_WID_3:
+ case IDM_WINDOW_I_WID_4:
+ case IDM_WINDOW_I_WID_5:
+ case IDM_WINDOW_I_WID_6:
+ case IDM_WINDOW_I_WID_7:
+ {
+ i = wCmd - IDM_WINDOW_I_WID_0;
+
+ if ((i < 0) || (i >= MAX_TERM_DATA)) break;
+
+ td = &data[i];
+
+ td->tile_wid += 1;
+
+ term_getsize(td);
+
+ term_window_resize(td);
+
+ break;
+ }
+
+ /* Decrease Tile Height */
+ case IDM_WINDOW_D_WID_0:
+ case IDM_WINDOW_D_WID_1:
+ case IDM_WINDOW_D_WID_2:
+ case IDM_WINDOW_D_WID_3:
+ case IDM_WINDOW_D_WID_4:
+ case IDM_WINDOW_D_WID_5:
+ case IDM_WINDOW_D_WID_6:
+ case IDM_WINDOW_D_WID_7:
+ {
+ i = wCmd - IDM_WINDOW_D_WID_0;
+
+ if ((i < 0) || (i >= MAX_TERM_DATA)) break;
+
+ td = &data[i];
+
+ td->tile_wid -= 1;
+
+ term_getsize(td);
+
+ term_window_resize(td);
+
+ break;
+ }
+
+ /* Increase Tile Height */
+ case IDM_WINDOW_I_HGT_0:
+ case IDM_WINDOW_I_HGT_1:
+ case IDM_WINDOW_I_HGT_2:
+ case IDM_WINDOW_I_HGT_3:
+ case IDM_WINDOW_I_HGT_4:
+ case IDM_WINDOW_I_HGT_5:
+ case IDM_WINDOW_I_HGT_6:
+ case IDM_WINDOW_I_HGT_7:
+ {
+ i = wCmd - IDM_WINDOW_I_HGT_0;
+
+ if ((i < 0) || (i >= MAX_TERM_DATA)) break;
+
+ td = &data[i];
+
+ td->tile_hgt += 1;
+
+ term_getsize(td);
+
+ term_window_resize(td);
+
+ break;
+ }
+
+ /* Decrease Tile Height */
+ case IDM_WINDOW_D_HGT_0:
+ case IDM_WINDOW_D_HGT_1:
+ case IDM_WINDOW_D_HGT_2:
+ case IDM_WINDOW_D_HGT_3:
+ case IDM_WINDOW_D_HGT_4:
+ case IDM_WINDOW_D_HGT_5:
+ case IDM_WINDOW_D_HGT_6:
+ case IDM_WINDOW_D_HGT_7:
+ {
+ i = wCmd - IDM_WINDOW_D_HGT_0;
+
+ if ((i < 0) || (i >= MAX_TERM_DATA)) break;
+
+ td = &data[i];
+
+ td->tile_hgt -= 1;
+
+ term_getsize(td);
+
+ term_window_resize(td);
+
+ break;
+ }
+
+ case IDM_OPTIONS_OLD_GRAPHICS:
+ {
+ /* Paranoia */
+ if (!inkey_flag)
+ {
+ plog("You may not do that right now.");
+ break;
+ }
+
+ /* Set "arg_graphics" */
+ arg_graphics = 1;
+
+ /* React to changes */
+ Term_xtra_win_react();
+
+ /* Hack -- Force redraw */
+ Term_key_push(KTRL('R'));
+
+ break;
+ }
+
+ case IDM_OPTIONS_NEW_GRAPHICS:
+ {
+ /* Paranoia */
+ if (!inkey_flag)
+ {
+ plog("You may not do that right now.");
+ break;
+ }
+
+ /* Set "arg_graphics" */
+ arg_graphics = 2;
+
+ /* React to changes */
+ Term_xtra_win_react();
+
+ /* Hack -- Force redraw */
+ Term_key_push(KTRL('R'));
+
+ break;
+ }
+ case IDM_OPTIONS_ASCII_GRAPHICS:
+ {
+ /* Paranoia */
+ if (!inkey_flag)
+ {
+ plog("You may not do that right now.");
+ break;
+ }
+
+ /* Set "ASCII Graphics" */
+ arg_graphics = 0;
+ /* React to Changes */
+ Term_xtra_win_react();
+
+ /* Hack -- Force redraw */
+ Term_key_push(KTRL('R'));
+
+ break;
+ }
+
+ case IDM_OPTIONS_BIGTILE:
+ {
+ term_data *td = &data[0];
+
+ /* Paranoia */
+ if (!inkey_flag)
+ {
+ plog("You may not do that right now.");
+ break;
+ }
+
+ /* Toggle "arg_sound" */
+ arg_bigtile = !arg_bigtile;
+
+ /* Activate */
+ Term_activate(&td->t);
+
+ /* Resize the term */
+ Term_resize(td->cols, td->rows);
+
+ /* Redraw later */
+ InvalidateRect(td->w, NULL, TRUE);
+
+ break;
+ }
+
+ case IDM_OPTIONS_SOUND:
+ {
+ /* Paranoia */
+ if (!inkey_flag)
+ {
+ plog("You may not do that right now.");
+ break;
+ }
+
+ /* Toggle "arg_sound" */
+ arg_sound = !arg_sound;
+
+ /* React to changes */
+ Term_xtra_win_react();
+
+ /* Hack -- Force redraw */
+ Term_key_push(KTRL('R'));
+
+ break;
+ }
+
+ case IDM_OPTIONS_UNUSED:
+ {
+ /* Unused for now XXX XXX XXX */
+
+ break;
+ }
+
+#ifdef USE_SAVER
+
+ case IDM_OPTIONS_SAVER:
+ {
+ if (hwndSaver)
+ {
+ DestroyWindow(hwndSaver);
+ hwndSaver = NULL;
+ }
+ else
+ {
+ /* Create a screen scaver window */
+ hwndSaver = CreateWindowEx(WS_EX_TOPMOST, "WindowsScreenSaverClass",
+ "Angband Screensaver",
+ WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
+ 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN),
+ NULL, NULL, hInstance, NULL);
+
+ if (hwndSaver)
+ {
+ /* Push the window to the bottom XXX XXX XXX */
+ SetWindowPos(hwndSaver, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ }
+ else
+ {
+ plog("Failed to create saver window");
+ }
+ }
+ break;
+ }
+
+#endif
+
+ case IDM_HELP_GENERAL:
+ {
+ char buf[1024];
+ char tmp[1024];
+ path_build(tmp, 1024, ANGBAND_DIR_XTRA_HELP, "angband.hlp");
+ if (check_file(tmp))
+ {
+ sprintf(buf, "winhelp.exe %s", tmp);
+ WinExec(buf, SW_NORMAL);
+ }
+ else
+ {
+ plog_fmt("Cannot find help file: %s", tmp);
+ plog("Use the online help files instead.");
+ }
+ break;
+ }
+
+ case IDM_HELP_SPOILERS:
+ {
+ char buf[1024];
+ char tmp[1024];
+ path_build(tmp, 1024, ANGBAND_DIR_XTRA_HELP, "spoilers.hlp");
+ if (check_file(tmp))
+ {
+ sprintf(buf, "winhelp.exe %s", tmp);
+ WinExec(buf, SW_NORMAL);
+ }
+ else
+ {
+ plog_fmt("Cannot find help file: %s", tmp);
+ plog("Use the online help files instead.");
+ }
+ break;
+ }
+ }
+}
+
+
+
+#ifdef __MWERKS__
+LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam);
+LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam)
+#else /* __MWERKS__ */
+LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam)
+#endif /* __MWERKS__ */
+{
+ PAINTSTRUCT ps;
+ HDC hdc;
+ term_data *td;
+ MINMAXINFO FAR *lpmmi;
+ RECT rc;
+ int i;
+
+
+ /* Acquire proper "term_data" info */
+ td = (term_data *)GetWindowLong(hWnd, 0);
+
+ /* Handle message */
+ switch (uMsg)
+ {
+ /* XXX XXX XXX */
+ case WM_NCCREATE:
+ {
+ SetWindowLong(hWnd, 0, (LONG)(my_td));
+ break;
+ }
+
+ /* XXX XXX XXX */
+ case WM_CREATE:
+ {
+ return 0;
+ }
+
+ case WM_GETMINMAXINFO:
+ {
+ lpmmi = (MINMAXINFO FAR *)lParam;
+
+ /* this message was sent before WM_NCCREATE */
+ if (!td) return 1;
+
+ /* Minimum window size is 8x2 */
+ rc.left = rc.top = 0;
+ rc.right = rc.left + 8 * td->tile_wid + td->size_ow1 + td->size_ow2;
+ rc.bottom = rc.top + 2 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1;
+
+ /* Adjust */
+ AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
+
+ /* Save minimum size */
+ lpmmi->ptMinTrackSize.x = rc.right - rc.left;
+ lpmmi->ptMinTrackSize.y = rc.bottom - rc.top;
+
+ /* Maximum window size */
+ rc.left = rc.top = 0;
+ rc.right = rc.left + 255 * td->tile_wid + td->size_ow1 + td->size_ow2;
+ rc.bottom = rc.top + 255 * td->tile_hgt + td->size_oh1 + td->size_oh2;
+
+ /* Paranoia */
+ rc.right += (td->tile_wid - 1);
+ rc.bottom += (td->tile_hgt - 1);
+
+ /* Adjust */
+ AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
+
+ /* Save maximum size */
+ lpmmi->ptMaxSize.x = rc.right - rc.left;
+ lpmmi->ptMaxSize.y = rc.bottom - rc.top;
+
+ /* Save maximum size */
+ lpmmi->ptMaxTrackSize.x = rc.right - rc.left;
+ lpmmi->ptMaxTrackSize.y = rc.bottom - rc.top;
+
+ return 0;
+ }
+
+ case WM_PAINT:
+ {
+ BeginPaint(hWnd, &ps);
+ if (td) term_data_redraw(td);
+ EndPaint(hWnd, &ps);
+ ValidateRect(hWnd, NULL);
+ return 0;
+ }
+
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ {
+ /* Unused */
+ /* BYTE KeyState = 0x00; */
+
+ bool_ mc = FALSE;
+ bool_ ms = FALSE;
+ bool_ ma = FALSE;
+
+ /* Extract the modifiers */
+ if (GetKeyState(VK_CONTROL) & 0x8000) mc = TRUE;
+ if (GetKeyState(VK_SHIFT) & 0x8000) ms = TRUE;
+ if (GetKeyState(VK_MENU) & 0x8000) ma = TRUE;
+
+ /* Handle "special" keys */
+ if (special_key[(byte)(wParam)] || (ma && !ignore_key[(byte)(wParam)]) )
+ {
+ /* Begin the macro trigger */
+ Term_keypress(31);
+
+ /* Send the modifiers */
+ if (mc) Term_keypress('C');
+ if (ms) Term_keypress('S');
+ if (ma) Term_keypress('A');
+
+ /* Extract "scan code" */
+ i = LOBYTE(HIWORD(lParam));
+
+ /* Introduce the scan code */
+ Term_keypress('x');
+
+ /* Encode the hexidecimal scan code */
+ Term_keypress(hexsym[i / 16]);
+ Term_keypress(hexsym[i % 16]);
+
+ /* End the macro trigger */
+ Term_keypress(13);
+
+ return 0;
+ }
+
+ break;
+ }
+
+ case WM_CHAR:
+ {
+ Term_keypress(wParam);
+ return 0;
+ }
+
+ case WM_INITMENU:
+ {
+ setup_menus();
+ return 0;
+ }
+
+ case WM_CLOSE:
+ {
+ if (game_in_progress && character_generated)
+ {
+ /* Hack -- Forget messages */
+ msg_flag = FALSE;
+
+ /* Save the game */
+ do_cmd_save_game();
+ }
+ quit(NULL);
+ return 0;
+ }
+
+ case WM_QUIT:
+ {
+ quit(NULL);
+ return 0;
+ }
+
+ case WM_COMMAND:
+ {
+ process_menus(LOWORD(wParam));
+ return 0;
+ }
+
+ case WM_SIZE:
+ {
+ /* this message was sent before WM_NCCREATE */
+ if (!td) return 1;
+
+ /* it was sent from inside CreateWindowEx */
+ if (!td->w) return 1;
+
+ /* was sent from WM_SIZE */
+ if (td->size_hack) return 1;
+
+ switch (wParam)
+ {
+ case SIZE_MINIMIZED:
+ {
+ /* Hide sub-windows */
+ for (i = 1; i < MAX_TERM_DATA; i++)
+ {
+ if (data[i].visible) ShowWindow(data[i].w, SW_HIDE);
+ }
+ return 0;
+ }
+
+ case SIZE_MAXIMIZED:
+ {
+ /* fall through XXX XXX XXX */
+ }
+
+ case SIZE_RESTORED:
+ {
+ uint cols = (LOWORD(lParam) - td->size_ow1 - td->size_ow2) / td->tile_wid;
+ uint rows = (HIWORD(lParam) - td->size_oh1 - td->size_oh2) / td->tile_hgt;
+
+ /* New size */
+ if ((td->cols != cols) || (td->rows != rows))
+ {
+ /* save the new size */
+ td->cols = cols;
+ td->rows = rows;
+
+ /* Activate */
+ Term_activate(&td->t);
+
+ /* Resize the term */
+ Term_resize(td->cols, td->rows);
+
+ /* Redraw later */
+ InvalidateRect(td->w, NULL, TRUE);
+ }
+
+ td->size_hack = TRUE;
+
+ /* Restore sub-windows */
+ for (i = 1; i < MAX_TERM_DATA; i++)
+ {
+ if (data[i].visible) ShowWindow(data[i].w, SW_SHOWNOACTIVATE);
+ }
+
+ td->size_hack = FALSE;
+
+ return 0;
+ }
+ }
+ break;
+ }
+
+ case WM_PALETTECHANGED:
+ {
+ /* Ignore if palette change caused by itself */
+ if ((HWND)wParam == hWnd) return 0;
+
+ /* Fall through... */
+ }
+
+ case WM_QUERYNEWPALETTE:
+ {
+ if (!paletted) return 0;
+
+ hdc = GetDC(hWnd);
+
+ SelectPalette(hdc, hPal, FALSE);
+
+ i = RealizePalette(hdc);
+
+ /* if any palette entries changed, repaint the window. */
+ if (i) InvalidateRect(hWnd, NULL, TRUE);
+
+ ReleaseDC(hWnd, hdc);
+
+ return 0;
+ }
+
+ case WM_ACTIVATE:
+ {
+ if (wParam && !HIWORD(lParam))
+ {
+ /* Do something to sub-windows */
+ for (i = 1; i < MAX_TERM_DATA; i++)
+ {
+ SetWindowPos(data[i].w, hWnd, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+ }
+
+ /* Focus on main window */
+ SetFocus(hWnd);
+
+ return 0;
+ }
+
+ break;
+ }
+ }
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+
+#ifdef __MWERKS__
+LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam);
+LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam)
+#else /* __MWERKS__ */
+LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam)
+#endif /* __MWERKS__ */
+{
+ term_data *td;
+ MINMAXINFO FAR *lpmmi;
+ RECT rc;
+ PAINTSTRUCT ps;
+ HDC hdc;
+ int i;
+
+
+ /* Acquire proper "term_data" info */
+ td = (term_data *)GetWindowLong(hWnd, 0);
+
+ /* Process message */
+ switch (uMsg)
+ {
+ /* XXX XXX XXX */
+ case WM_NCCREATE:
+ {
+ SetWindowLong(hWnd, 0, (LONG)(my_td));
+ break;
+ }
+
+ /* XXX XXX XXX */
+ case WM_CREATE:
+ {
+ return 0;
+ }
+
+ case WM_GETMINMAXINFO:
+ {
+ /* this message was sent before WM_NCCREATE */
+ if (!td) return 1;
+
+ lpmmi = (MINMAXINFO FAR *)lParam;
+
+ /* Minimum size */
+ rc.left = rc.top = 0;
+ rc.right = rc.left + 8 * td->tile_wid + td->size_ow1 + td->size_ow2;
+ rc.bottom = rc.top + 2 * td->tile_hgt + td->size_oh1 + td->size_oh2;
+
+ /* Adjust */
+ AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
+
+ /* Save the minimum size */
+ lpmmi->ptMinTrackSize.x = rc.right - rc.left;
+ lpmmi->ptMinTrackSize.y = rc.bottom - rc.top;
+
+ /* Maximum window size */
+ rc.left = rc.top = 0;
+ rc.right = rc.left + 80 * td->tile_wid + td->size_ow1 + td->size_ow2;
+ rc.bottom = rc.top + 24 * td->tile_hgt + td->size_oh1 + td->size_oh2;
+
+ /* Paranoia */
+ rc.right += (td->tile_wid - 1);
+ rc.bottom += (td->tile_hgt - 1);
+
+ /* Adjust */
+ AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
+
+ /* Save maximum size */
+ lpmmi->ptMaxSize.x = rc.right - rc.left;
+ lpmmi->ptMaxSize.y = rc.bottom - rc.top;
+
+ /* Save the maximum size */
+ lpmmi->ptMaxTrackSize.x = rc.right - rc.left;
+ lpmmi->ptMaxTrackSize.y = rc.bottom - rc.top;
+
+ return 0;
+ }
+
+ case WM_SIZE:
+ {
+ /* this message was sent before WM_NCCREATE */
+ if (!td) return 1;
+
+ /* it was sent from inside CreateWindowEx */
+ if (!td->w) return 1;
+
+ /* was sent from inside WM_SIZE */
+ if (td->size_hack) return 1;
+
+ td->size_hack = TRUE;
+
+ td->cols = (LOWORD(lParam) - td->size_ow1 - td->size_ow2) / td->tile_wid;
+ td->rows = (HIWORD(lParam) - td->size_oh1 - td->size_oh2) / td->tile_hgt;
+
+ term_getsize(td);
+
+ MoveWindow(hWnd, td->pos_x, td->pos_y, td->size_wid, td->size_hgt, TRUE);
+
+ td->size_hack = FALSE;
+
+ return 0;
+ }
+
+ case WM_PAINT:
+ {
+ BeginPaint(hWnd, &ps);
+ if (td) term_data_redraw(td);
+ EndPaint(hWnd, &ps);
+ return 0;
+ }
+
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ {
+ /* Unused */
+ /* BYTE KeyState = 0x00; */
+
+ bool_ mc = FALSE;
+ bool_ ms = FALSE;
+ bool_ ma = FALSE;
+
+ /* Extract the modifiers */
+ if (GetKeyState(VK_CONTROL) & 0x8000) mc = TRUE;
+ if (GetKeyState(VK_SHIFT) & 0x8000) ms = TRUE;
+ if (GetKeyState(VK_MENU) & 0x8000) ma = TRUE;
+
+ /* Handle "special" keys */
+ if (special_key[(byte)(wParam)] || (ma && !ignore_key[(byte)(wParam)]) )
+ {
+ /* Begin the macro trigger */
+ Term_keypress(31);
+
+ /* Send the modifiers */
+ if (mc) Term_keypress('C');
+ if (ms) Term_keypress('S');
+ if (ma) Term_keypress('A');
+
+ /* Extract "scan code" */
+ i = LOBYTE(HIWORD(lParam));
+
+ /* Introduce the scan code */
+ Term_keypress('x');
+
+ /* Encode the hexidecimal scan code */
+ Term_keypress(hexsym[i / 16]);
+ Term_keypress(hexsym[i % 16]);
+
+ /* End the macro trigger */
+ Term_keypress(13);
+
+ return 0;
+ }
+
+ break;
+ }
+
+ case WM_CHAR:
+ {
+ Term_keypress(wParam);
+ return 0;
+ }
+
+ case WM_PALETTECHANGED:
+ {
+ /* ignore if palette change caused by itself */
+ if ((HWND)wParam == hWnd) return FALSE;
+ /* otherwise, fall through!!! */
+ }
+
+ case WM_QUERYNEWPALETTE:
+ {
+ if (!paletted) return 0;
+ hdc = GetDC(hWnd);
+ SelectPalette(hdc, hPal, FALSE);
+ i = RealizePalette(hdc);
+ /* if any palette entries changed, repaint the window. */
+ if (i) InvalidateRect(hWnd, NULL, TRUE);
+ ReleaseDC(hWnd, hdc);
+ return 0;
+ }
+
+ case WM_NCLBUTTONDOWN:
+ {
+
+#ifdef HTCLOSE
+ if (wParam == HTCLOSE) wParam = HTSYSMENU;
+#endif /* HTCLOSE */
+
+ if (wParam == HTSYSMENU)
+ {
+ if (td->visible)
+ {
+ td->visible = FALSE;
+ ShowWindow(td->w, SW_HIDE);
+ }
+
+ return 0;
+ }
+
+ break;
+ }
+ }
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+
+#ifdef USE_SAVER
+
+#define MOUSE_SENS 40
+
+#ifdef __MWERKS__
+LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam);
+LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam)
+#else /* __MWERKS__ */
+LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg,
+WPARAM wParam, LPARAM lParam)
+#endif /* __MWERKS__ */
+{
+ static int iMouse = 0;
+ static WORD xMouse = 0;
+ static WORD yMouse = 0;
+
+ int dx, dy;
+
+
+ /* Process */
+ switch (uMsg)
+ {
+ /* XXX XXX XXX */
+ case WM_NCCREATE:
+ {
+ break;
+ }
+
+ case WM_SETCURSOR:
+ {
+ SetCursor(NULL);
+ return 0;
+ }
+
+#if 0
+ case WM_ACTIVATE:
+ {
+ if (LOWORD(wParam) == WA_INACTIVE) break;
+
+ /* else fall through */
+ }
+#endif
+
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_KEYDOWN:
+ {
+ SendMessage(hWnd, WM_CLOSE, 0, 0);
+ return 0;
+ }
+
+ case WM_MOUSEMOVE:
+ {
+ if (iMouse)
+ {
+ dx = LOWORD(lParam) - xMouse;
+ dy = HIWORD(lParam) - yMouse;
+
+ if (dx < 0) dx = -dx;
+ if (dy < 0) dy = -dy;
+
+ if ((dx > MOUSE_SENS) || (dy > MOUSE_SENS))
+ {
+ SendMessage(hWnd, WM_CLOSE, 0, 0);
+ }
+ }
+
+ /* Save last location */
+ iMouse = 1;
+ xMouse = LOWORD(lParam);
+ yMouse = HIWORD(lParam);
+
+ return 0;
+ }
+
+ case WM_CLOSE:
+ {
+ DestroyWindow(hwndSaver);
+ hwndSaver = NULL;
+ return 0;
+ }
+ }
+
+ /* Oops */
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+#endif /* USE_SAVER */
+
+
+
+
+
+/*** Temporary Hooks ***/
+
+
+/*
+ * Display warning message (see "z-util.c")
+ */
+static void hack_plog(cptr str)
+{
+ /* Give a warning */
+ if (str)
+ {
+ MessageBox(NULL, str, "Warning",
+ MB_ICONEXCLAMATION | MB_OK);
+ }
+}
+
+
+/*
+ * Display error message and quit (see "z-util.c")
+ */
+static void hack_quit(cptr str)
+{
+ /* Give a warning */
+ if (str)
+ {
+ MessageBox(NULL, str, "Error",
+ MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
+ }
+
+ /* Unregister the classes */
+ UnregisterClass(AppName, hInstance);
+
+ /* Destroy the icon */
+ if (hIcon) DestroyIcon(hIcon);
+
+ /* Exit */
+ exit(0);
+}
+
+
+
+/*** Various hooks ***/
+
+
+/*
+ * Display warning message (see "z-util.c")
+ */
+static void hook_plog(cptr str)
+{
+ /* Warning */
+ if (str)
+ {
+ MessageBox(data[0].w, str, "Warning",
+ MB_ICONEXCLAMATION | MB_OK);
+ }
+}
+
+
+/*
+ * Display error message and quit (see "z-util.c")
+ */
+static void hook_quit(cptr str)
+{
+ int i;
+
+
+ /* Give a warning */
+ if (str)
+ {
+ MessageBox(data[0].w, str, "Error",
+ MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
+ }
+
+
+ /* Save the preferences */
+ save_prefs();
+
+
+ /*** Could use 'Term_nuke_win()' XXX XXX XXX */
+
+ /* Destroy all windows */
+ for (i = MAX_TERM_DATA - 1; i >= 0; --i)
+ {
+ term_force_font(&data[i], NULL);
+ if (data[i].font_want) string_free(data[i].font_want);
+ if (data[i].w) DestroyWindow(data[i].w);
+ data[i].w = 0;
+ }
+
+
+ /*** Free some other stuff ***/
+
+ DeleteObject(hbrYellow);
+
+ if (hPal) DeleteObject(hPal);
+
+ UnregisterClass(AppName, hInstance);
+
+ if (hIcon) DestroyIcon(hIcon);
+
+ exit(0);
+}
+
+/*** Initialize ***/
+
+
+/*
+ * Init some stuff
+ */
+static void init_stuff(void)
+{
+ int i;
+
+ char path[1024];
+
+
+ /* Get program name with full path */
+ GetModuleFileName(hInstance, path, 512);
+
+ /* Get the name of the "*.ini" file */
+ strcpy(path + strlen(path) - 4, ".INI");
+
+ /* Save the the name of the ini-file */
+ ini_file = string_make(path);
+
+ /* Validate the ini-file */
+ validate_file(ini_file);
+
+ /* Analyze the path */
+ i = strlen(path);
+
+ /* Get the path */
+ for (; i > 0; i--)
+ {
+ if (path[i] == '\\')
+ {
+ /* End of path */
+ break;
+ }
+ }
+
+ /* Add "lib" to the path */
+ strcpy(path + i + 1, "lib\\");
+
+ /* Validate the path */
+ validate_dir(path);
+
+ /*** Initialise the file paths ***/
+
+ /* Start with standard ones */
+ init_file_paths(path);
+
+ /* Build the "font" path */
+ path_build(path, 1024, ANGBAND_DIR_XTRA, "font");
+
+ /* Allocate the path */
+ ANGBAND_DIR_XTRA_FONT = string_make(path);
+
+
+ /*** Validate the paths to ensure we have a working install ***/
+
+ validate_dir(ANGBAND_DIR_APEX);
+ validate_dir(ANGBAND_DIR_DATA);
+ validate_dir(ANGBAND_DIR_EDIT);
+ validate_dir(ANGBAND_DIR_FILE);
+ validate_dir(ANGBAND_DIR_HELP);
+ validate_dir(ANGBAND_DIR_INFO);
+ validate_dir(ANGBAND_DIR_NOTE);
+ validate_dir(ANGBAND_DIR_SAVE);
+ validate_dir(ANGBAND_DIR_PREF);
+ validate_dir(ANGBAND_DIR_USER);
+ validate_dir(ANGBAND_DIR_XTRA);
+ validate_dir(ANGBAND_DIR_CMOV);
+ validate_dir(ANGBAND_DIR_XTRA_FONT);
+
+ /* Build the filename */
+ path_build(path, 1024, ANGBAND_DIR_XTRA_FONT, "8X13.FON");
+
+ /* Hack -- Validate the basic font */
+ validate_file(path);
+
+
+#ifdef USE_GRAPHICS
+
+ /* Build the "graf" path */
+ path_build(path, 1024, ANGBAND_DIR_XTRA, "graf");
+
+ /* Allocate the path */
+ ANGBAND_DIR_XTRA_GRAF = string_make(path);
+
+ /* Validate the "graf" directory */
+ validate_dir(ANGBAND_DIR_XTRA_GRAF);
+
+ /* Build the filename */
+ path_build(path, 1024, ANGBAND_DIR_XTRA_GRAF, "8X8.BMP");
+
+ /* Hack -- Validate the basic graf */
+ validate_file(path);
+
+#endif
+
+
+#ifdef USE_SOUND
+
+ /* Build the "sound" path */
+ path_build(path, 1024, ANGBAND_DIR_XTRA, "sound");
+
+ /* Allocate the path */
+ ANGBAND_DIR_XTRA_SOUND = string_make(path);
+
+ /* Validate the "sound" directory */
+ validate_dir(ANGBAND_DIR_XTRA_SOUND);
+
+#endif
+
+
+ /* Build the "help" path */
+ path_build(path, 1024, ANGBAND_DIR_XTRA, "help");
+
+ /* Allocate the path */
+ ANGBAND_DIR_XTRA_HELP = string_make(path);
+
+ /* Validate the "help" directory */
+ /* validate_dir(ANGBAND_DIR_XTRA_HELP); */
+}
+
+int FAR PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
+ LPSTR lpCmdLine, int nCmdShow)
+{
+ int i;
+
+ WNDCLASS wc;
+ HDC hdc;
+ MSG msg;
+
+ /* Save globally */
+ hInstance = hInst;
+
+ /* Initialize */
+ if (hPrevInst == NULL)
+ {
+ wc.style = CS_CLASSDC;
+ wc.lpfnWndProc = AngbandWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 4; /* one long pointer to term_data */
+ wc.hInstance = hInst;
+ wc.hIcon = hIcon = LoadIcon(hInst, AppName);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(BLACK_BRUSH);
+ wc.lpszMenuName = AppName;
+ wc.lpszClassName = AppName;
+
+ if (!RegisterClass(&wc)) exit(1);
+
+ wc.lpfnWndProc = AngbandListProc;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = AngList;
+
+ if (!RegisterClass(&wc)) exit(2);
+
+#ifdef USE_SAVER
+
+ wc.style = CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS | CS_DBLCLKS;
+ wc.lpfnWndProc = AngbandSaverProc;
+ wc.hCursor = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "WindowsScreenSaverClass";
+
+ if (!RegisterClass(&wc)) exit(3);
+
+#endif
+
+ }
+
+ /* Temporary hooks */
+ plog_aux = hack_plog;
+ quit_aux = hack_quit;
+ core_aux = hack_quit;
+
+ /* Prepare the filepaths */
+ init_stuff();
+
+ /* Initialize the keypress analyzer */
+ for (i = 0; special_key_list[i]; ++i)
+ {
+ special_key[special_key_list[i]] = TRUE;
+ }
+
+ /* Determine if display is 16/256/true color */
+ hdc = GetDC(NULL);
+ colors16 = (GetDeviceCaps(hdc, BITSPIXEL) == 4);
+ paletted = ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) ? TRUE : FALSE);
+ ReleaseDC(NULL, hdc);
+
+ /* Initialize the colors */
+ for (i = 0; i < 256; i++)
+ {
+ byte rv, gv, bv;
+
+ /* Extract desired values */
+ rv = angband_color_table[i][1];
+ gv = angband_color_table[i][2];
+ bv = angband_color_table[i][3];
+
+ /* Extract the "complex" code */
+ win_clr[i] = PALETTERGB(rv, gv, bv);
+
+ /* Save the "simple" code */
+ angband_color_table[i][0] = win_pal[i];
+ }
+
+ /* Prepare the windows */
+ init_windows();
+
+ /* Activate hooks */
+ plog_aux = hook_plog;
+ quit_aux = hook_quit;
+ core_aux = hook_quit;
+
+ /* Set the system suffix */
+ ANGBAND_SYS = "win";
+
+
+ /* Set the keyboard suffix */
+ if (7 != GetKeyboardType(0))
+ ANGBAND_KEYBOARD = "0";
+ else
+ {
+ /* Japanese keyboard */
+ switch (GetKeyboardType(1))
+ {
+ case 0x0D01:
+ case 0x0D02:
+ case 0x0D03:
+ case 0x0D04:
+ case 0x0D05:
+ case 0x0D06:
+ /* NEC PC-98x1 */
+ ANGBAND_KEYBOARD = "NEC98";
+ break;
+ default:
+ /* PC/AT */
+ ANGBAND_KEYBOARD = "JAPAN";
+ }
+ }
+
+ /* Initialize */
+ init_angband();
+
+ /* Prompt the user */
+ prt("", 23, 0);
+ prt("[Press any key to proceed]", 23, 27);
+ Term_fresh();
+
+ inkey();
+
+ /* We are now initialized */
+ initialized = TRUE;
+
+ /* Did the user double click on a save file? */
+ check_for_save_file(lpCmdLine);
+
+ game_in_progress = TRUE;
+ play_game(FALSE);
+
+ /* Prompt the user */
+ Term_fresh();
+
+ /* Process messages forever */
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ /* Initialize the keypress analyzer */
+ for (i = 0; ignore_key_list[i]; ++i)
+ {
+ ignore_key[ignore_key_list[i]] = TRUE;
+ }
+
+ /* Paranoia */
+ quit(NULL);
+
+ /* Paranoia */
+ return (0);
+}
+
+
+#endif /* WINDOWS */
+
+
diff --git a/src/main-x11.c b/src/main-x11.c
new file mode 100644
index 00000000..e32e2617
--- /dev/null
+++ b/src/main-x11.c
@@ -0,0 +1,3210 @@
+/* File: main-x11.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison, and others
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+
+/*
+ * This file helps Angband work with UNIX/X11 computers.
+ *
+ * To use this file, compile with "USE_X11" defined, and link against all
+ * the various "X11" libraries which may be needed.
+ *
+ * See also "main-xaw.c".
+ *
+ * Part of this file provides a user interface package composed of several
+ * pseudo-objects, including "metadpy" (a display), "infowin" (a window),
+ * "infoclr" (a color), and "infofnt" (a font). Actually, the package was
+ * originally much more interesting, but it was bastardized to keep this
+ * file simple.
+ *
+ * The rest of this file is an implementation of "main-xxx.c" for X11.
+ *
+ * Most of this file is by Ben Harrison (benh@phial.com).
+ */
+
+/*
+ * The following shell script can be used to launch Angband, assuming that
+ * it was extracted into "~/Angband", and compiled using "USE_X11", on a
+ * Linux machine, with a 1280x1024 screen, using 6 windows (with the given
+ * characteristics), with gamma correction of 1.8 -> (1 / 1.8) * 256 = 142,
+ * and without graphics (add "-g" for graphics). Just copy this comment
+ * into a file, remove the leading " * " characters (and the head/tail of
+ * this comment), and make the file executable.
+ *
+ *
+ * #!/bin/csh
+ *
+ * # Describe attempt
+ * echo "Launching angband..."
+ * sleep 2
+ *
+ * # Main window
+ * setenv ANGBAND_X11_FONT_0 10x20
+ * setenv ANGBAND_X11_AT_X_0 5
+ * setenv ANGBAND_X11_AT_Y_0 510
+ *
+ * # Message window
+ * setenv ANGBAND_X11_FONT_1 8x13
+ * setenv ANGBAND_X11_AT_X_1 5
+ * setenv ANGBAND_X11_AT_Y_1 22
+ * setenv ANGBAND_X11_ROWS_1 35
+ *
+ * # Inventory window
+ * setenv ANGBAND_X11_FONT_2 8x13
+ * setenv ANGBAND_X11_AT_X_2 635
+ * setenv ANGBAND_X11_AT_Y_2 182
+ * setenv ANGBAND_X11_ROWS_3 23
+ *
+ * # Equipment window
+ * setenv ANGBAND_X11_FONT_3 8x13
+ * setenv ANGBAND_X11_AT_X_3 635
+ * setenv ANGBAND_X11_AT_Y_3 22
+ * setenv ANGBAND_X11_ROWS_3 12
+ *
+ * # Monster recall window
+ * setenv ANGBAND_X11_FONT_4 6x13
+ * setenv ANGBAND_X11_AT_X_4 817
+ * setenv ANGBAND_X11_AT_Y_4 847
+ * setenv ANGBAND_X11_COLS_4 76
+ * setenv ANGBAND_X11_ROWS_4 11
+ *
+ * # Object recall window
+ * setenv ANGBAND_X11_FONT_5 6x13
+ * setenv ANGBAND_X11_AT_X_5 817
+ * setenv ANGBAND_X11_AT_Y_5 520
+ * setenv ANGBAND_X11_COLS_5 76
+ * setenv ANGBAND_X11_ROWS_5 24
+ *
+ * # The build directory
+ * cd ~/Angband
+ *
+ * # Gamma correction
+ * setenv ANGBAND_X11_GAMMA 142
+ *
+ * # Launch Angband
+ * ./src/angband -mx11 -- -n6 &
+ *
+ */
+
+#include "angband.h"
+
+#ifdef USE_X11
+
+#ifndef __MAKEDEPEND__
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/keysymdef.h>
+#include <X11/Xatom.h>
+#endif /* __MAKEDEPEND__ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+
+#include <sys/time.h>
+
+/* /me pffts Solaris */
+#ifndef NAME_MAX
+#define NAME_MAX _POSIX_NAME_MAX
+#endif
+
+/*
+ * Include some helpful X11 code.
+ */
+#include "maid-x11.c"
+
+/*
+ * Hack -- avoid some compiler warnings
+ */
+#define IGNORE_UNUSED_FUNCTIONS
+
+
+/*
+ * Notes on Colors:
+ *
+ * 1) On a monochrome (or "fake-monochrome") display, all colors
+ * will be "cast" to "fg," except for the bg color, which is,
+ * obviously, cast to "bg". Thus, one can ignore this setting.
+ *
+ * 2) Because of the inner functioning of the color allocation
+ * routines, colors may be specified as (a) a typical color name,
+ * (b) a hexidecimal color specification (preceded by a pound sign),
+ * or (c) by strings such as "fg", "bg", "zg".
+ *
+ * 3) Due to the workings of the init routines, many colors
+ * may also be dealt with by their actual pixel values. Note that
+ * the pixel with all bits set is "zg = (1<<metadpy->depth)-1", which
+ * is not necessarily either black or white.
+ */
+
+
+
+/**** Generic Types ****/
+
+
+/*
+ * An X11 pixell specifier
+ */
+typedef unsigned long Pixell;
+
+/*
+ * The structures defined below
+ */
+typedef struct metadpy metadpy;
+typedef struct infowin infowin;
+typedef struct infoclr infoclr;
+typedef struct infofnt infofnt;
+
+
+/*
+ * A structure summarizing a given Display.
+ *
+ * - The Display itself
+ * - The default Screen for the display
+ * - The virtual root (usually just the root)
+ * - The default colormap (from a macro)
+ *
+ * - The "name" of the display
+ *
+ * - The socket to listen to for events
+ *
+ * - The width of the display screen (from a macro)
+ * - The height of the display screen (from a macro)
+ * - The bit depth of the display screen (from a macro)
+ *
+ * - The black Pixell (from a macro)
+ * - The white Pixell (from a macro)
+ *
+ * - The background Pixell (default: black)
+ * - The foreground Pixell (default: white)
+ * - The maximal Pixell (Equals: ((2 ^ depth)-1), is usually ugly)
+ *
+ * - Bit Flag: Force all colors to black and white (default: !color)
+ * - Bit Flag: Allow the use of color (default: depth > 1)
+ * - Bit Flag: We created 'dpy', and so should nuke it when done.
+ */
+struct metadpy
+{
+ Display *dpy;
+ Screen *screen;
+ Window root;
+ Colormap cmap;
+
+ char *name;
+
+ int fd;
+
+ uint width;
+ uint height;
+ uint depth;
+
+ Pixell black;
+ Pixell white;
+
+ Pixell bg;
+ Pixell fg;
+ Pixell zg;
+
+uint mono:
+ 1;
+uint color:
+ 1;
+uint nuke:
+ 1;
+};
+
+
+
+/*
+ * A Structure summarizing Window Information.
+ *
+ * I assume that a window is at most 30000 pixels on a side.
+ * I assume that the root windw is also at most 30000 square.
+ *
+ * - The Window
+ * - The current Input Event Mask
+ *
+ * - The location of the window
+ * - The width, height of the window
+ * - The border width of this window
+ *
+ * - Byte: 1st Extra byte
+ *
+ * - Bit Flag: This window is currently Mapped
+ * - Bit Flag: This window needs to be redrawn
+ * - Bit Flag: This window has been resized
+ *
+ * - Bit Flag: We should nuke 'win' when done with it
+ *
+ * - Bit Flag: 1st extra flag
+ * - Bit Flag: 2nd extra flag
+ * - Bit Flag: 3rd extra flag
+ * - Bit Flag: 4th extra flag
+ */
+struct infowin
+{
+ Window win;
+ long mask;
+
+ s16b ox, oy;
+
+ s16b x, y;
+ s16b w, h;
+ u16b b;
+
+ byte byte1;
+
+uint mapped:
+ 1;
+uint redraw:
+ 1;
+uint resize:
+ 1;
+
+uint nuke:
+ 1;
+
+uint flag1:
+ 1;
+uint flag2:
+ 1;
+uint flag3:
+ 1;
+uint flag4:
+ 1;
+};
+
+
+
+
+
+
+/*
+ * A Structure summarizing Operation+Color Information
+ *
+ * - The actual GC corresponding to this info
+ *
+ * - The Foreground Pixell Value
+ * - The Background Pixell Value
+ *
+ * - Num (0-15): The operation code (As in Clear, Xor, etc)
+ * - Bit Flag: The GC is in stipple mode
+ * - Bit Flag: Destroy 'gc' at Nuke time.
+ */
+struct infoclr
+{
+ GC gc;
+
+ Pixell fg;
+ Pixell bg;
+
+uint code:
+ 4;
+uint stip:
+ 1;
+uint nuke:
+ 1;
+};
+
+
+
+/*
+ * A Structure to Hold Font Information
+ *
+ * - The 'XFontStruct*' (yields the 'Font')
+ *
+ * - The font name
+ *
+ * - The default character width
+ * - The default character height
+ * - The default character ascent
+ *
+ * - Byte: Pixel offset used during fake mono
+ *
+ * - Flag: Force monospacing via 'wid'
+ * - Flag: Nuke info when done
+ */
+struct infofnt
+{
+ XFontStruct *info;
+
+ cptr name;
+
+ s16b wid;
+ s16b twid;
+ s16b hgt;
+ s16b asc;
+
+ byte off;
+
+uint mono:
+ 1;
+uint nuke:
+ 1;
+};
+
+
+
+
+/**** Generic Macros ****/
+
+
+
+/* Set current metadpy (Metadpy) to 'M' */
+#define Metadpy_set(M) \
+Metadpy = M
+
+
+/* Initialize 'M' using Display 'D' */
+#define Metadpy_init_dpy(D) \
+Metadpy_init_2(D,cNULL)
+
+/* Initialize 'M' using a Display named 'N' */
+#define Metadpy_init_name(N) \
+Metadpy_init_2((Display*)(NULL),N)
+
+/* Initialize 'M' using the standard Display */
+#define Metadpy_init() \
+Metadpy_init_name("")
+
+
+/* Init an infowin by giving father as an (info_win*) (or NULL), and data */
+#define Infowin_init_dad(D,X,Y,W,H,B,FG,BG) \
+Infowin_init_data(((D) ? ((D)->win) : (Window)(None)), \
+X,Y,W,H,B,FG,BG)
+
+
+/* Init a top level infowin by pos,size,bord,Colors */
+#define Infowin_init_top(X,Y,W,H,B,FG,BG) \
+Infowin_init_data(None,X,Y,W,H,B,FG,BG)
+
+
+/* Request a new standard window by giving Dad infowin and X,Y,W,H */
+#define Infowin_init_std(D,X,Y,W,H,B) \
+Infowin_init_dad(D,X,Y,W,H,B,Metadpy->fg,Metadpy->bg)
+
+
+/* Set the current Infowin */
+#define Infowin_set(I) \
+(Infowin = (I))
+
+
+/* Set the current Infoclr */
+#define Infoclr_set(C) \
+(Infoclr = (C))
+
+
+#define Infoclr_init_ppo(F,B,O,M) \
+Infoclr_init_data(F,B,O,M)
+
+#define Infoclr_init_cco(F,B,O,M) \
+Infoclr_init_ppo(Infoclr_Pixell(F),Infoclr_Pixell(B),O,M)
+
+#define Infoclr_init_ppn(F,B,O,M) \
+Infoclr_init_ppo(F,B,Infoclr_Opcode(O),M)
+
+#define Infoclr_init_ccn(F,B,O,M) \
+Infoclr_init_cco(F,B,Infoclr_Opcode(O),M)
+
+
+/* Set the current infofnt */
+#define Infofnt_set(I) \
+(Infofnt = (I))
+
+
+/* Errr: Expose Infowin */
+#define Infowin_expose() \
+(!(Infowin->redraw = 1))
+
+/* Errr: Unxpose Infowin */
+#define Infowin_unexpose() \
+(Infowin->redraw = 0)
+
+
+
+/**** Generic Globals ****/
+
+
+/*
+ * The "default" values
+ */
+static metadpy metadpy_default;
+
+
+/*
+ * The "current" variables
+ */
+static metadpy *Metadpy = &metadpy_default;
+static infowin *Infowin = (infowin*)(NULL);
+static infoclr *Infoclr = (infoclr*)(NULL);
+static infofnt *Infofnt = (infofnt*)(NULL);
+
+
+/**** Generic code ****/
+
+/*
+ * Simple routine to save the state of the game when the display connection
+ * is broken. Remember, you cannot do anything in this function that will
+ * generate X protocol requests.
+ */
+int x_io_error_handler(Display *d)
+{
+ /* We have nothing to save */
+ if (!character_generated) return 0;
+
+ save_dungeon();
+ save_player();
+
+ return 0;
+}
+
+/*
+ * Calculate how much space there is in the key queue for the current term.
+ */
+int Term_queue_space(void)
+{
+ /* Find the gap if the tail is before the head. */
+ int space = Term->key_tail - Term->key_head;
+
+ /* Otherwise, add in the extra for looping. */
+ if (space <= 0) space = Term->key_size - space;
+
+ /* The last space is never used as that would be interpreted as leaving
+ * no pending keypresses. */
+ return space -1;
+}
+
+
+/*
+ * Add a series of keypresses to the "queue".
+ *
+ * Return any errors generated by Term_keypress() in doing so, or SUCCESS
+ * if there are none.
+ *
+ * Catch the "out of space" error before anything is printed.
+ *
+ * NB: The keys added here will be interpreted by any macros or keymaps.
+ */
+errr type_string(char *str, uint len)
+{
+ char *s;
+
+ term *old = Term;
+
+ /* Paranoia - no string. */
+ if (!str) return 5;
+
+ /* Hack - calculate the string length here if none given. */
+ if (!len) len = strlen(str);
+
+ /* Activate the main window, as all pastes go there. */
+ Term_activate(term_screen);
+
+ /* Not enough space for the string. */
+ if (Term_queue_space() <= (int)len)
+ return 7;
+
+ for (s = str; s < str + len; s++)
+ {
+ errr err = Term_keypress(*s);
+
+ /* Catch errors other than "str[i] == 0", which is ignored. */
+ if (err && err != -1) return err;
+ }
+
+ /* Activate the original window. */
+ Term_activate(old);
+
+ return 0;
+}
+
+
+/*
+ * Init the current metadpy, with various initialization stuff.
+ *
+ * Inputs:
+ * dpy: The Display* to use (if NULL, create it)
+ * name: The name of the Display (if NULL, the current)
+ *
+ * Notes:
+ * If 'name' is NULL, but 'dpy' is set, extract name from dpy
+ * If 'dpy' is NULL, then Create the named Display
+ * If 'name' is NULL, and so is 'dpy', use current Display
+ *
+ * Return -1 if no Display given, and none can be opened.
+ */
+static errr Metadpy_init_2(Display *dpy, cptr name)
+{
+ metadpy *m = Metadpy;
+
+ /*** Open the display if needed ***/
+
+ /* If no Display given, attempt to Create one */
+ if (!dpy)
+ {
+ /* Attempt to open the display */
+ dpy = XOpenDisplay(name);
+
+ /* Failure */
+ if (!dpy) return ( -1);
+
+ /* We will have to nuke it when done */
+ m->nuke = 1;
+ }
+
+ /* Since the Display was given, use it */
+ else
+ {
+ /* We will not have to nuke it when done */
+ m->nuke = 0;
+ }
+
+ XSetIOErrorHandler(x_io_error_handler);
+
+ /*** Save some information ***/
+
+ /* Save the Display itself */
+ m->dpy = dpy;
+
+ /* Get the Screen and Virtual Root Window */
+ m->screen = DefaultScreenOfDisplay(dpy);
+ m->root = RootWindowOfScreen(m->screen);
+
+ /* Get the default colormap */
+ m->cmap = DefaultColormapOfScreen(m->screen);
+
+ /* Extract the true name of the display */
+ m->name = DisplayString(dpy);
+
+ /* Extract the fd */
+ m->fd = ConnectionNumber(Metadpy->dpy);
+
+ /* Save the Size and Depth of the screen */
+ m->width = WidthOfScreen(m->screen);
+ m->height = HeightOfScreen(m->screen);
+ m->depth = DefaultDepthOfScreen(m->screen);
+
+ /* Save the Standard Colors */
+ m->black = BlackPixelOfScreen(m->screen);
+ m->white = WhitePixelOfScreen(m->screen);
+
+ /*** Make some clever Guesses ***/
+
+ /* Guess at the desired 'fg' and 'bg' Pixell's */
+ m->bg = m->black;
+ m->fg = m->white;
+
+ /* Calculate the Maximum allowed Pixel value. */
+ m->zg = (1 << m->depth) - 1;
+
+ /* Save various default Flag Settings */
+ m->color = ((m->depth > 1) ? 1 : 0);
+ m->mono = ((m->color) ? 0 : 1);
+
+ /* Return "success" */
+ return (0);
+}
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Nuke the current metadpy
+ */
+static errr Metadpy_nuke(void)
+{
+ metadpy *m = Metadpy;
+
+
+ /* If required, Free the Display */
+ if (m->nuke)
+ {
+ /* Close the Display */
+ XCloseDisplay(m->dpy);
+
+ /* Forget the Display */
+ m->dpy = (Display*)(NULL);
+
+ /* Do not nuke it again */
+ m->nuke = 0;
+ }
+
+ /* Return Success */
+ return (0);
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * General Flush/ Sync/ Discard routine
+ */
+static errr Metadpy_update(int flush, int sync, int discard)
+{
+ /* Flush if desired */
+ if (flush) XFlush(Metadpy->dpy);
+
+ /* Sync if desired, using 'discard' */
+ if (sync) XSync(Metadpy->dpy, discard);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Make a simple beep
+ */
+static errr Metadpy_do_beep(void)
+{
+ /* Make a simple beep */
+ XBell(Metadpy->dpy, 100);
+
+ return (0);
+}
+
+
+
+/*
+ * Set the name (in the title bar) of Infowin
+ */
+static errr Infowin_set_name(cptr name)
+{
+ Status st;
+ XTextProperty tp;
+ char buf[128];
+ char *bp = buf;
+ strcpy(buf, name);
+ st = XStringListToTextProperty(&bp, 1, &tp);
+ if (st) XSetWMName(Metadpy->dpy, Infowin->win, &tp);
+ return (0);
+}
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Set the icon name of Infowin
+ */
+static errr Infowin_set_icon_name(cptr name)
+{
+ Status st;
+ XTextProperty tp;
+ char buf[128];
+ char *bp = buf;
+ strcpy(buf, name);
+ st = XStringListToTextProperty(&bp, 1, &tp);
+ if (st) XSetWMIconName(Metadpy->dpy, Infowin->win, &tp);
+ return (0);
+}
+
+
+/*
+ * Nuke Infowin
+ */
+static errr Infowin_nuke(void)
+{
+ infowin *iwin = Infowin;
+
+ /* Nuke if requested */
+ if (iwin->nuke)
+ {
+ /* Destory the old window */
+ XDestroyWindow(Metadpy->dpy, iwin->win);
+ }
+
+ /* Success */
+ return (0);
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * Prepare a new 'infowin'.
+ */
+static errr Infowin_prepare(Window xid)
+{
+ infowin *iwin = Infowin;
+
+ Window tmp_win;
+ XWindowAttributes xwa;
+ int x, y;
+ unsigned int w, h, b, d;
+
+ /* Assign stuff */
+ iwin->win = xid;
+
+ /* Check For Error XXX Extract some ACTUAL data from 'xid' */
+ XGetGeometry(Metadpy->dpy, xid, &tmp_win, &x, &y, &w, &h, &b, &d);
+
+ /* Apply the above info */
+ iwin->x = x;
+ iwin->y = y;
+ iwin->w = w;
+ iwin->h = h;
+ iwin->b = b;
+
+ /* Check Error XXX Extract some more ACTUAL data */
+ XGetWindowAttributes(Metadpy->dpy, xid, &xwa);
+
+ /* Apply the above info */
+ iwin->mask = xwa.your_event_mask;
+ iwin->mapped = ((xwa.map_state == IsUnmapped) ? 0 : 1);
+
+ /* And assume that we are exposed */
+ iwin->redraw = 1;
+
+ /* Success */
+ return (0);
+}
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Initialize a new 'infowin'.
+ */
+static errr Infowin_init_real(Window xid)
+{
+ /* Wipe it clean */
+ (void)WIPE(Infowin, infowin);
+
+ /* Start out non-nukable */
+ Infowin->nuke = 0;
+
+ /* Attempt to Prepare ourself */
+ return (Infowin_prepare(xid));
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * Init an infowin by giving some data.
+ *
+ * Inputs:
+ * dad: The Window that should own this Window (if any)
+ * x,y: The position of this Window
+ * w,h: The size of this Window
+ * b,d: The border width and pixel depth
+ *
+ * Notes:
+ * If 'dad == None' assume 'dad == root'
+ */
+static errr Infowin_init_data(Window dad, int x, int y, int w, int h,
+ int b, Pixell fg, Pixell bg)
+{
+ Window xid;
+
+ /* Wipe it clean */
+ (void)WIPE(Infowin, infowin);
+
+
+ /*** Error Check XXX ***/
+
+
+ /*** Create the Window 'xid' from data ***/
+
+ /* What happened here? XXX XXX XXX */
+
+ /* If no parent given, depend on root */
+ if (dad == None)
+
+ /* #ifdef USE_GRAPHICS
+
+ xid = XCreateWindow(Metadpy->dpy, Metadpy->root, x, y, w, h, b, 8, InputOutput, CopyFromParent, 0, 0);
+
+ else
+ */
+
+ /* #else */
+
+ dad = Metadpy->root;
+
+ /* #endif */
+
+ /* Create the Window XXX Error Check */
+ xid = XCreateSimpleWindow(Metadpy->dpy, dad, x, y, w, h, b, fg, bg);
+
+ /* Start out selecting No events */
+ XSelectInput(Metadpy->dpy, xid, 0L);
+
+
+ /*** Prepare the new infowin ***/
+
+ /* Mark it as nukable */
+ Infowin->nuke = 1;
+
+ /* Attempt to Initialize the infowin */
+ return (Infowin_prepare(xid));
+}
+
+
+
+/*
+ * Modify the event mask of an Infowin
+ */
+static errr Infowin_set_mask(long mask)
+{
+ /* Save the new setting */
+ Infowin->mask = mask;
+
+ /* Execute the Mapping */
+ XSelectInput(Metadpy->dpy, Infowin->win, Infowin->mask);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Request that Infowin be mapped
+ */
+static errr Infowin_map(void)
+{
+ /* Execute the Mapping */
+ XMapWindow(Metadpy->dpy, Infowin->win);
+
+ /* Success */
+ return (0);
+}
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Request that Infowin be unmapped
+ */
+static errr Infowin_unmap(void)
+{
+ /* Execute the Un-Mapping */
+ XUnmapWindow(Metadpy->dpy, Infowin->win);
+
+ /* Success */
+ return (0);
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * Request that Infowin be raised
+ */
+static errr Infowin_raise(void)
+{
+ /* Raise towards visibility */
+ XRaiseWindow(Metadpy->dpy, Infowin->win);
+
+ /* Success */
+ return (0);
+}
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Request that Infowin be lowered
+ */
+static errr Infowin_lower(void)
+{
+ /* Lower towards invisibility */
+ XLowerWindow(Metadpy->dpy, Infowin->win);
+
+ /* Success */
+ return (0);
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * Request that Infowin be moved to a new location
+ */
+static errr Infowin_impell(int x, int y)
+{
+ /* Execute the request */
+ XMoveWindow(Metadpy->dpy, Infowin->win, x, y);
+
+ /* Success */
+ return (0);
+}
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Move and Resize an infowin
+ */
+static errr Infowin_locate(int x, int y, int w, int h)
+{
+ /* Execute the request */
+ XMoveResizeWindow(Metadpy->dpy, Infowin->win, x, y, w, h);
+
+ /* Success */
+ return (0);
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * Visually clear Infowin
+ */
+static errr Infowin_wipe(void)
+{
+ /* Execute the request */
+ XClearWindow(Metadpy->dpy, Infowin->win);
+
+ /* Success */
+ return (0);
+}
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Visually Paint Infowin with the current color
+ */
+static errr Infowin_fill(void)
+{
+ /* Execute the request */
+ XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc,
+ 0, 0, Infowin->w, Infowin->h);
+
+ /* Success */
+ return (0);
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * A NULL terminated pair list of legal "operation names"
+ *
+ * Pairs of values, first is texttual name, second is the string
+ * holding the decimal value that the operation corresponds to.
+ */
+static cptr opcode_pairs[] =
+{
+ "cpy", "3",
+ "xor", "6",
+ "and", "1",
+ "ior", "7",
+ "nor", "8",
+ "inv", "10",
+ "clr", "0",
+ "set", "15",
+
+ "src", "3",
+ "dst", "5",
+
+ "+andReverse", "2",
+ "+andInverted", "4",
+ "+noop", "5",
+ "+equiv", "9",
+ "+orReverse", "11",
+ "+copyInverted", "12",
+ "+orInverted", "13",
+ "+nand", "14",
+ NULL
+};
+
+
+/*
+ * Parse a word into an operation "code"
+ *
+ * Inputs:
+ * str: A string, hopefully representing an Operation
+ *
+ * Output:
+ * 0-15: if 'str' is a valid Operation
+ * -1: if 'str' could not be parsed
+ */
+static int Infoclr_Opcode(cptr str)
+{
+ register int i;
+
+ /* Scan through all legal operation names */
+ for (i = 0; opcode_pairs[i*2]; ++i)
+ {
+ /* Is this the right oprname? */
+ if (streq(opcode_pairs[i*2], str))
+ {
+ /* Convert the second element in the pair into a Code */
+ return (atoi(opcode_pairs[i*2 + 1]));
+ }
+ }
+
+ /* The code was not found, return -1 */
+ return ( -1);
+}
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Request a Pixell by name. Note: uses 'Metadpy'.
+ *
+ * Inputs:
+ * name: The name of the color to try to load (see below)
+ *
+ * Output:
+ * The Pixell value that metched the given name
+ * 'Metadpy->fg' if the name was unparseable
+ *
+ * Valid forms for 'name':
+ * 'fg', 'bg', 'zg', '<name>' and '#<code>'
+ */
+static Pixell Infoclr_Pixell(cptr name)
+{
+ XColor scrn;
+
+ /* Attempt to Parse the name */
+ if (name && name[0])
+ {
+ /* The 'bg' color is available */
+ if (streq(name, "bg")) return (Metadpy->bg);
+
+ /* The 'fg' color is available */
+ if (streq(name, "fg")) return (Metadpy->fg);
+
+ /* The 'zg' color is available */
+ if (streq(name, "zg")) return (Metadpy->zg);
+
+ /* The 'white' color is available */
+ if (streq(name, "white")) return (Metadpy->white);
+
+ /* The 'black' color is available */
+ if (streq(name, "black")) return (Metadpy->black);
+
+ /* Attempt to parse 'name' into 'scrn' */
+ if (!(XParseColor(Metadpy->dpy, Metadpy->cmap, name, &scrn)))
+ {
+ plog_fmt("Warning: Couldn't parse color '%s'\n", name);
+ }
+
+ /* Attempt to Allocate the Parsed color */
+ if (!(XAllocColor(Metadpy->dpy, Metadpy->cmap, &scrn)))
+ {
+ plog_fmt("Warning: Couldn't allocate color '%s'\n", name);
+ }
+
+ /* The Pixel was Allocated correctly */
+ else return (scrn.pixel);
+ }
+
+ /* Warn about the Default being Used */
+ plog_fmt("Warning: Using 'fg' for unknown color '%s'\n", name);
+
+ /* Default to the 'Foreground' color */
+ return (Metadpy->fg);
+}
+
+
+/*
+ * Initialize a new 'infoclr' with a real GC.
+ */
+static errr Infoclr_init_1(GC gc)
+{
+ infoclr *iclr = Infoclr;
+
+ /* Wipe the iclr clean */
+ (void)WIPE(iclr, infoclr);
+
+ /* Assign the GC */
+ iclr->gc = gc;
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Nuke an old 'infoclr'.
+ */
+static errr Infoclr_nuke(void)
+{
+ infoclr *iclr = Infoclr;
+
+ /* Deal with 'GC' */
+ if (iclr->nuke)
+ {
+ /* Free the GC */
+ XFreeGC(Metadpy->dpy, iclr->gc);
+ }
+
+ /* Forget the current */
+ Infoclr = (infoclr*)(NULL);
+
+ /* Success */
+ return (0);
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * Initialize an infoclr with some data
+ *
+ * Inputs:
+ * fg: The Pixell for the requested Foreground (see above)
+ * bg: The Pixell for the requested Background (see above)
+ * op: The Opcode for the requested Operation (see above)
+ * stip: The stipple mode
+ */
+static errr Infoclr_init_data(Pixell fg, Pixell bg, int op, int stip)
+{
+ infoclr *iclr = Infoclr;
+
+ GC gc;
+ XGCValues gcv;
+ unsigned long gc_mask;
+
+
+
+ /*** Simple error checking of opr and clr ***/
+
+ /* Check the 'Pixells' for realism */
+ if (bg > Metadpy->zg) return ( -1);
+ if (fg > Metadpy->zg) return ( -1);
+
+ /* Check the data for trueness */
+ if ((op < 0) || (op > 15)) return ( -1);
+
+
+ /*** Create the requested 'GC' ***/
+
+ /* Assign the proper GC function */
+ gcv.function = op;
+
+ /* Assign the proper GC background */
+ gcv.background = bg;
+
+ /* Assign the proper GC foreground */
+ gcv.foreground = fg;
+
+ /* Hack -- Handle XOR (xor is code 6) by hacking bg and fg */
+ if (op == 6) gcv.background = 0;
+ if (op == 6) gcv.foreground = (bg ^ fg);
+
+ /* Assign the proper GC Fill Style */
+ gcv.fill_style = (stip ? FillStippled : FillSolid);
+
+ /* Turn off 'Give exposure events for pixmap copying' */
+ gcv.graphics_exposures = False;
+
+ /* Set up the GC mask */
+ gc_mask = (GCFunction | GCBackground | GCForeground |
+ GCFillStyle | GCGraphicsExposures);
+
+ /* Create the GC detailed above */
+ gc = XCreateGC(Metadpy->dpy, Metadpy->root, gc_mask, &gcv);
+
+
+ /*** Initialize ***/
+
+ /* Wipe the iclr clean */
+ (void)WIPE(iclr, infoclr);
+
+ /* Assign the GC */
+ iclr->gc = gc;
+
+ /* Nuke it when done */
+ iclr->nuke = 1;
+
+ /* Assign the parms */
+ iclr->fg = fg;
+ iclr->bg = bg;
+ iclr->code = op;
+ iclr->stip = stip ? 1 : 0;
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Change the 'fg' for an infoclr
+ *
+ * Inputs:
+ * fg: The Pixell for the requested Foreground (see above)
+ */
+static errr Infoclr_change_fg(Pixell fg)
+{
+ infoclr *iclr = Infoclr;
+
+
+ /*** Simple error checking of opr and clr ***/
+
+ /* Check the 'Pixells' for realism */
+ if (fg > Metadpy->zg) return ( -1);
+
+
+ /*** Change ***/
+
+ /* Change */
+ XSetForeground(Metadpy->dpy, iclr->gc, fg);
+
+ /* Success */
+ return (0);
+}
+
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Nuke an old 'infofnt'.
+ */
+static errr Infofnt_nuke(void)
+{
+ infofnt *ifnt = Infofnt;
+
+ /* Deal with 'name' */
+ if (ifnt->name)
+ {
+ /* Free the name */
+ string_free(ifnt->name);
+ }
+
+ /* Nuke info if needed */
+ if (ifnt->nuke)
+ {
+ /* Free the font */
+ XFreeFont(Metadpy->dpy, ifnt->info);
+ }
+
+ /* Success */
+ return (0);
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * Prepare a new 'infofnt'
+ */
+static errr Infofnt_prepare(XFontStruct *info)
+{
+ infofnt *ifnt = Infofnt;
+
+ XCharStruct *cs;
+
+ /* Assign the struct */
+ ifnt->info = info;
+
+ /* Jump into the max bouonds thing */
+ cs = &(info->max_bounds);
+
+ /* Extract default sizing info */
+ ifnt->asc = info->ascent;
+ ifnt->hgt = info->ascent + info->descent;
+ ifnt->wid = cs->width;
+ if (use_bigtile)
+ ifnt->twid = 2 * ifnt->wid;
+ else
+ ifnt->twid = ifnt->wid;
+
+
+#ifdef OBSOLETE_SIZING_METHOD
+ /* Extract default sizing info */
+ ifnt->asc = cs->ascent;
+ ifnt->hgt = (cs->ascent + cs->descent);
+ ifnt->wid = cs->width;
+#endif
+
+ /* Success */
+ return (0);
+}
+
+
+#ifndef IGNORE_UNUSED_FUNCTIONS
+
+/*
+ * Initialize a new 'infofnt'.
+ */
+static errr Infofnt_init_real(XFontStruct *info)
+{
+ /* Wipe the thing */
+ (void)WIPE(Infofnt, infofnt);
+
+ /* No nuking */
+ Infofnt->nuke = 0;
+
+ /* Attempt to prepare it */
+ return (Infofnt_prepare(info));
+}
+
+#endif /* IGNORE_UNUSED_FUNCTIONS */
+
+
+/*
+ * Init an infofnt by its Name
+ *
+ * Inputs:
+ * name: The name of the requested Font
+ */
+static errr Infofnt_init_data(cptr name)
+{
+ XFontStruct *info;
+
+
+ /*** Load the info Fresh, using the name ***/
+
+ /* If the name is not given, report an error */
+ if (!name) return ( -1);
+
+ /* Attempt to load the font */
+ info = XLoadQueryFont(Metadpy->dpy, name);
+
+ /* The load failed, try to recover */
+ if (!info) return ( -1);
+
+
+ /*** Init the font ***/
+
+ /* Wipe the thing */
+ (void)WIPE(Infofnt, infofnt);
+
+ /* Attempt to prepare it */
+ if (Infofnt_prepare(info))
+ {
+ /* Free the font */
+ XFreeFont(Metadpy->dpy, info);
+
+ /* Fail */
+ return ( -1);
+ }
+
+ /* Save a copy of the font name */
+ Infofnt->name = string_make(name);
+
+ /* Mark it as nukable */
+ Infofnt->nuke = 1;
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Standard Text
+ */
+static errr Infofnt_text_std(int x, int y, cptr str, int len)
+{
+ int i;
+
+
+ /*** Do a brief info analysis ***/
+
+ /* Do nothing if the string is null */
+ if (!str || !*str) return ( -1);
+
+ /* Get the length of the string */
+ if (len < 0) len = strlen(str);
+
+
+ /*** Decide where to place the string, vertically ***/
+
+ /* Ignore Vertical Justifications */
+ y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
+
+
+ /*** Decide where to place the string, horizontally ***/
+
+ /* Line up with x at left edge of column 'x' */
+ x = (x * Infofnt->wid) + Infowin->ox;
+
+
+ /*** Actually draw 'str' onto the infowin ***/
+
+ /* Be sure the correct font is ready */
+ XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid);
+
+
+ /*** Handle the fake mono we can enforce on fonts ***/
+
+ /* Monotize the font */
+ if (Infofnt->mono)
+ {
+ /* Do each character */
+ for (i = 0; i < len; ++i)
+ {
+ /* Note that the Infoclr is set up to contain the Infofnt */
+ XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
+ x + i * Infofnt->wid + Infofnt->off, y, str + i, 1);
+ }
+ }
+
+ /* Assume monoospaced font */
+ else
+ {
+ /* Note that the Infoclr is set up to contain the Infofnt */
+ XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
+ x, y, str, len);
+ }
+
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Painting where text would be
+ */
+static errr Infofnt_text_non(int x, int y, cptr str, int len)
+{
+ int w, h;
+
+
+ /*** Find the width ***/
+
+ /* Negative length is a flag to count the characters in str */
+ if (len < 0) len = strlen(str);
+
+ /* The total width will be 'len' chars * standard width */
+ w = len * Infofnt->wid;
+
+
+ /*** Find the X dimensions ***/
+
+ /* Line up with x at left edge of column 'x' */
+ x = x * Infofnt->wid + Infowin->ox;
+
+
+ /*** Find other dimensions ***/
+
+ /* Simply do 'Infofnt->hgt' (a single row) high */
+ h = Infofnt->hgt;
+
+ /* Simply do "at top" in row 'y' */
+ y = y * h + Infowin->oy;
+
+
+ /*** Actually 'paint' the area ***/
+
+ /* Just do a Fill Rectangle */
+ XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, w, h);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*************************************************************************/
+
+
+/*
+ * Angband specific code follows... (ANGBAND)
+ */
+
+
+/*
+ * Hack -- cursor color
+ */
+static infoclr *xor;
+
+/*
+ * Actual color table
+ */
+static infoclr *clr[256];
+
+/*
+ * Color info (unused, red, green, blue).
+ */
+static byte color_table[256][4];
+
+/*
+ * Forward declare
+ */
+typedef struct term_data term_data;
+
+/*
+ * A structure for each "term"
+ */
+struct term_data
+{
+ term t;
+
+ infofnt *fnt;
+
+ infowin *win;
+
+#ifdef USE_GRAPHICS
+
+ XImage *tiles;
+
+ /* Tempory storage for overlaying tiles. */
+ XImage *TmpImage;
+
+#endif
+
+};
+
+
+/*
+ * The number of term data structures
+ */
+#define MAX_TERM_DATA 8
+
+/*
+ * The array of term data structures
+ */
+static term_data data[MAX_TERM_DATA];
+
+/* Use short names for the most commonly used elements of various structures. */
+#define DPY (Metadpy->dpy)
+#define WIN (Infowin->win)
+
+/*
+ * Simply push a set of co-ordinates around.
+ */
+typedef struct co_ord co_ord;
+struct co_ord
+{
+ int x;
+ int y;
+};
+
+/*
+ * A special structure to store information about the text currently
+ * selected.
+ */
+typedef struct x11_selection_type x11_selection_type;
+struct x11_selection_type
+{
+ bool_ select; /* The selection is currently in use. */
+ bool_ drawn; /* The selection is currently displayed. */
+ term *t; /* The window where the selection is found. */
+ co_ord init; /* The starting co-ordinates. */
+ co_ord cur; /* The end co-ordinates (the current ones if still copying). */
+ co_ord old; /* The previous end co-ordinates. */
+ Time time; /* The time at which the selection was finalised. */
+};
+
+static x11_selection_type s_ptr[1];
+
+
+
+/*
+ * Process a keypress event
+ *
+ * Also appears in "main-xaw.c".
+ */
+static void react_keypress(XKeyEvent *xev)
+{
+ int i, n, mc, ms, mo, mx;
+
+ uint ks1;
+
+ XKeyEvent *ev = (XKeyEvent*)(xev);
+
+ KeySym ks;
+
+ char buf[128];
+ char msg[128];
+
+
+ /* Check for "normal" keypresses */
+ n = XLookupString(ev, buf, 125, &ks, NULL);
+
+ /* Terminate */
+ buf[n] = '\0';
+
+
+ /* Hack -- Ignore "modifier keys" */
+ if (IsModifierKey(ks)) return;
+
+
+ /* Hack -- convert into an unsigned int */
+ ks1 = (uint)(ks);
+
+ /* Extract four "modifier flags" */
+ mc = (ev->state & ControlMask) ? TRUE : FALSE;
+ ms = (ev->state & ShiftMask) ? TRUE : FALSE;
+ mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
+ mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
+
+
+ /* Normal keys with no modifiers */
+ if (n && !mo && !mx && !IsSpecialKey(ks))
+ {
+ /* Enqueue the normal key(s) */
+ for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
+
+ /* All done */
+ return;
+ }
+
+
+ /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
+ switch (ks1)
+ {
+ case XK_Escape:
+ {
+ Term_keypress(ESCAPE);
+ return;
+ }
+
+ case XK_Return:
+ {
+ Term_keypress('\r');
+ return;
+ }
+
+ case XK_Tab:
+ {
+ Term_keypress('\t');
+ return;
+ }
+
+ case XK_Delete:
+ case XK_BackSpace:
+ {
+ Term_keypress('\010');
+ return;
+ }
+ }
+
+
+ /* Hack -- Use the KeySym */
+ if (ks)
+ {
+ sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
+ mc ? "N" : "", ms ? "S" : "",
+ mo ? "O" : "", mx ? "M" : "",
+ (unsigned long)(ks), 13);
+ }
+
+ /* Hack -- Use the Keycode */
+ else
+ {
+ sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
+ mc ? "N" : "", ms ? "S" : "",
+ mo ? "O" : "", mx ? "M" : "",
+ ev->keycode, 13);
+ }
+
+ /* Enqueue the "macro trigger" string */
+ for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
+
+
+ /* Hack -- auto-define macros as needed */
+ if (n && (macro_find_exact(msg) < 0))
+ {
+ /* Create a macro */
+ macro_add(msg, buf);
+ }
+}
+
+
+/*
+ * Find the square a particular pixel is part of.
+ */
+static void pixel_to_square(int * const x, int * const y,
+ const int ox, const int oy)
+{
+ (*x) = (ox - Infowin->ox) / Infofnt->wid;
+ (*y) = (oy - Infowin->oy) / Infofnt->hgt;
+}
+
+/*
+ * Find the pixel at the top-left corner of a square.
+ */
+static void square_to_pixel(int * const x, int * const y,
+ const int ox, const int oy)
+{
+ (*x) = ox * Infofnt->wid + Infowin->ox;
+ (*y) = oy * Infofnt->hgt + Infowin->oy;
+}
+
+/*
+ * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
+ */
+static void sort_co_ord(co_ord *min, co_ord *max,
+ const co_ord *b, const co_ord *a)
+{
+ min->x = MIN(a->x, b->x);
+ min->y = MIN(a->y, b->y);
+ max->x = MAX(a->x, b->x);
+ max->y = MAX(a->y, b->y);
+}
+
+/*
+ * Remove the selection by redrawing it.
+ */
+static void mark_selection_clear(int x1, int y1, int x2, int y2)
+{
+ Term_redraw_section(x1, y1, x2, y2);
+}
+
+/*
+ * Select an area by drawing a grey box around it.
+ * NB. These two functions can cause flicker as the selection is modified,
+ * as the game redraws the entire marked section.
+ */
+static void mark_selection_mark(int x1, int y1, int x2, int y2)
+{
+ square_to_pixel(&x1, &y1, x1, y1);
+ square_to_pixel(&x2, &y2, x2, y2);
+ XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
+ x2 - x1 + Infofnt->wid - 1, y2 - y1 + Infofnt->hgt - 1);
+}
+
+/*
+ * Mark a selection by drawing boxes around it (for now).
+ */
+static void mark_selection(void)
+{
+ co_ord min, max;
+ term *old = Term;
+ bool_ draw = s_ptr->select;
+ bool_ clear = s_ptr->drawn;
+
+ /* Open the correct term if necessary. */
+ if (s_ptr->t != old) Term_activate(s_ptr->t);
+
+ if (clear)
+ {
+ sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
+ mark_selection_clear(min.x, min.y, max.x, max.y);
+ }
+ if (draw)
+ {
+ sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
+ mark_selection_mark(min.x, min.y, max.x, max.y);
+ }
+
+ /* Finish on the current term. */
+ if (s_ptr->t != old) Term_activate(old);
+
+ s_ptr->old.x = s_ptr->cur.x;
+ s_ptr->old.y = s_ptr->cur.y;
+ s_ptr->drawn = s_ptr->select;
+}
+
+/*
+ * Forget a selection for one reason or another.
+ */
+static void copy_x11_release(void)
+{
+ /* Deselect the current selection. */
+ s_ptr->select = FALSE;
+
+ /* Remove its graphical represesntation. */
+ mark_selection();
+}
+
+/*
+ * Start to select some text on the screen.
+ */
+static void copy_x11_start(int x, int y)
+{
+ if (s_ptr->select) copy_x11_release();
+
+ /* Remember where the selection started. */
+ s_ptr->t = Term;
+ s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
+ s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
+}
+
+/*
+ * Respond to movement of the mouse when selecting text.
+ */
+static void copy_x11_cont(int x, int y, unsigned int buttons)
+{
+ /* Use the nearest square within bounds if the mouse is outside. */
+ x = MIN(MAX(x, 0), Term->wid - 1);
+ y = MIN(MAX(y, 0), Term->hgt - 1);
+
+ /* The left mouse button isn't pressed. */
+ if (~buttons & Button1Mask) return;
+
+ /* Not a selection in this window. */
+ if (s_ptr->t != Term) return;
+
+ /* Not enough movement. */
+ if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
+
+ /* Something is being selected. */
+ s_ptr->select = TRUE;
+
+ /* Track the selection. */
+ s_ptr->cur.x = x;
+ s_ptr->cur.y = y;
+
+ /* Hack - display it inefficiently. */
+ mark_selection();
+}
+
+/*
+ * Respond to release of the left mouse button by putting the selected text in
+ * the primary buffer.
+ */
+static void copy_x11_end(const Time time)
+{
+ /* No selection. */
+ if (!s_ptr->select) return;
+
+ /* Not a selection in this window. */
+ if (s_ptr->t != Term) return;
+
+ /* Remember when the selection was finalised. */
+ s_ptr->time = time;
+
+ /* Acquire the primary selection. */
+ XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
+ if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
+ {
+ /* Failed to acquire the selection, so forget it. */
+ bell();
+ s_ptr->select = FALSE;
+ mark_selection();
+ }
+}
+
+/*
+ * Send a message to request that the PRIMARY buffer be sent here.
+ */
+static void paste_x11_request(const Time time)
+{
+ XEvent event[1];
+ XSelectionRequestEvent *ptr = &(event->xselectionrequest);
+
+ /* Set various things. */
+ ptr->type = SelectionRequest;
+ ptr->display = Metadpy->dpy;
+ ptr->owner = XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY);
+ ptr->requestor = Infowin->win;
+ ptr->selection = XA_PRIMARY;
+ ptr->target = XA_STRING;
+ ptr->property = XA_STRING; /* Unused */
+ ptr->time = time;
+
+ /* Check the owner. */
+ if (ptr->owner == None)
+ {
+ /* No selection. */
+ bell();
+ return;
+ }
+
+ /* Send the SelectionRequest event. */
+ XSendEvent(Metadpy->dpy, ptr->owner, False, NoEventMask, event);
+}
+
+/*
+ * Add a character to a string in preparation for sending it to another
+ * client as a STRING.
+ * This doesn't change anything, as clients tend not to have difficulty in
+ * receiving this format (although the standard specifies a restricted set).
+ * Strings do not have a colour.
+ */
+static int add_char_string(char *buf, byte a, char c)
+{
+ *buf = c;
+ return 1;
+}
+
+/*
+ * Send some text requested by another X client.
+ */
+static void paste_x11_send(XSelectionRequestEvent *rq)
+{
+ XEvent event;
+ XSelectionEvent *ptr = &(event.xselection);
+ int (*add)(char *, byte, char) = 0;
+
+ /* Set the event parameters. */
+ ptr->type = SelectionNotify;
+ ptr->property = rq->property;
+ ptr->display = rq->display;
+ ptr->requestor = rq->requestor;
+ ptr->selection = rq->selection;
+ ptr->target = rq->target;
+ ptr->time = rq->time;
+
+ /* Determine the correct "add a character" function.
+ * As Term->wid is at most 255, these can add up to 4 characters of
+ * output per character of input without problem.
+ * The mechanism will need to change if much more than this is needed.
+ */
+ switch (rq->target)
+ {
+ case XA_STRING:
+ add = add_char_string;
+ break;
+ default:
+ goto error;
+ }
+
+ /* Reply to a known target received recently with data. */
+ if (rq->time >= s_ptr->time && add)
+ {
+ char buf[1024];
+ co_ord max, min;
+ int x, y, l;
+ byte a;
+ char c;
+
+ /* Work out which way around to paste. */
+ sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
+
+ /* Paranoia. */
+ if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
+ {
+ bell();
+ goto error;
+ }
+
+ /* Delete the old value of the property. */
+ XDeleteProperty(DPY, rq->requestor, rq->property);
+
+ for (y = 0; y < Term->hgt; y++)
+ {
+ if (y < min.y) continue;
+ if (y > max.y) break;
+
+ for (x = l = 0; x < Term->wid; x++)
+ {
+ if (x < min.x) continue;
+ if (x > max.x) break;
+
+ /* Find the character. */
+ Term_what(x, y, &a, &c);
+
+ /* Add it. */
+ l += (*add)(buf + l, a, c);
+ }
+
+ /* Terminate all but the last line in an appropriate way. */
+ if (y != max.y) l += (*add)(buf + l, TERM_WHITE, '\n');
+
+ /* Send the (non-empty) string. */
+ XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
+ PropModeAppend, (unsigned char*)buf, l);
+ }
+ }
+ else
+ {
+ /* Respond to all bad requests with property None. */
+error:
+ ptr->property = None;
+ }
+
+ /* Send whatever event we're left with. */
+ XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
+}
+
+extern errr type_string(char *str, uint len);
+
+/*
+ * Add the contents of the PRIMARY buffer to the input queue.
+ *
+ * Hack - This doesn't use the "time" of the event, and so accepts anything a
+ * client tries to send it.
+ */
+static void paste_x11_accept(const XSelectionEvent *ptr)
+{
+ long offset;
+ unsigned long left;
+
+ /* Failure. */
+ if (ptr->property == None)
+ {
+ bell();
+ return;
+ }
+
+ if (ptr->selection != XA_PRIMARY)
+ {
+ bell();
+ return;
+ }
+ if (ptr->target != XA_STRING)
+ {
+ bell();
+ return;
+ }
+
+ for (offset = 0; ; offset += left)
+ {
+ errr err;
+
+ /* A pointer for the pasted information. */
+ unsigned char *data;
+
+ Atom type;
+ int fmt;
+ unsigned long nitems;
+
+ /* Set data to the string, and catch errors. */
+ if (XGetWindowProperty(Metadpy->dpy, Infowin->win, XA_STRING, offset,
+ 32767, TRUE, XA_STRING, &type, &fmt, &nitems, &left, &data)
+ != Success) break;
+
+ /* Paste the text. */
+ err = type_string((char*)data, (uint)nitems);
+
+ /* Free the data pasted. */
+ XFree(data);
+
+ /* No room. */
+ if (err == 7)
+ {
+ bell();
+ break;
+ }
+ /* Paranoia? - strange errors. */
+ else if (err)
+ {
+ break;
+ }
+
+ /* Pasted everything. */
+ if (!left) return;
+ }
+
+ /* An error has occurred, so free the last bit of data before returning. */
+ XFree(data);
+}
+
+/*
+ * Handle various events conditional on presses of a mouse button.
+ */
+static void handle_button(Time time, int x, int y, int button,
+ bool_ press)
+{
+ /* The co-ordinates are only used in Angband format. */
+ pixel_to_square(&x, &y, x, y);
+
+ if (press && button == 1) copy_x11_start(x, y);
+ if (!press && button == 1) copy_x11_end(time);
+ if (!press && button == 2) paste_x11_request(time);
+}
+
+
+/*
+ * Process events
+ */
+static errr CheckEvent(bool_ wait)
+{
+ term_data *old_td = (term_data*)(Term->data);
+
+ XEvent xev_body, *xev = &xev_body;
+
+ term_data *td = NULL;
+ infowin *iwin = NULL;
+
+ int i;
+
+
+ /* Do not wait unless requested */
+ if (!wait && !XPending(Metadpy->dpy)) return (1);
+
+ /* Hack - redraw the selection, if needed.
+ * This doesn't actually check that one of its squares was drawn to,
+ * only that this may have happened.
+ */
+ if (s_ptr->select && !s_ptr->drawn) mark_selection();
+
+ /* Load the Event */
+ XNextEvent(Metadpy->dpy, xev);
+
+
+ /* Notice new keymaps */
+ if (xev->type == MappingNotify)
+ {
+ XRefreshKeyboardMapping(&xev->xmapping);
+ return 0;
+ }
+
+
+ /* Scan the windows */
+ for (i = 0; i < MAX_TERM_DATA; i++)
+ {
+ if (xev->xany.window == data[i].win->win)
+ {
+ td = &data[i];
+ iwin = td->win;
+ break;
+ }
+ }
+
+ /* Unknown window */
+ if (!td || !iwin) return (0);
+
+
+ /* Hack -- activate the Term */
+ Term_activate(&td->t);
+
+ /* Hack -- activate the window */
+ Infowin_set(iwin);
+
+
+ /* Switch on the Type */
+ switch (xev->type)
+ {
+
+ case ButtonPress:
+ case ButtonRelease:
+ {
+ bool_ press = (xev->type == ButtonPress);
+
+ /* Where is the mouse */
+ int x = xev->xbutton.x;
+ int y = xev->xbutton.y;
+
+ int z;
+
+ /* Which button is involved */
+ if (xev->xbutton.button == Button1) z = 1;
+ else if (xev->xbutton.button == Button2) z = 2;
+ else if (xev->xbutton.button == Button3) z = 3;
+ else if (xev->xbutton.button == Button4) z = 4;
+ else if (xev->xbutton.button == Button5) z = 5;
+ else z = 0;
+
+ /* Where is the mouse */
+ x = xev->xbutton.x;
+ y = xev->xbutton.y;
+
+ /* XXX Handle */
+ handle_button(xev->xbutton.time, x, y, z, press);
+
+ break;
+ }
+
+ case EnterNotify:
+ case LeaveNotify:
+ {
+ /* Where is the mouse */
+ /* XXX Handle */
+
+ break;
+ }
+
+ case MotionNotify:
+ {
+ int x = xev->xmotion.x;
+ int y = xev->xmotion.y;
+ unsigned int z = xev->xmotion.state;
+
+ /* Convert to co-ordinates Angband understands. */
+ pixel_to_square(&x, &y, x, y);
+
+ /* Alter the selection if appropriate. */
+ copy_x11_cont(x, y, z);
+
+ /* XXX Handle */
+
+ break;
+ }
+
+ case SelectionNotify:
+ {
+ paste_x11_accept(&(xev->xselection));
+ break;
+ }
+
+ case SelectionRequest:
+ {
+ paste_x11_send(&(xev->xselectionrequest));
+ break;
+ }
+
+ case SelectionClear:
+ {
+ s_ptr->select = FALSE;
+ mark_selection();
+ break;
+ }
+
+ case KeyRelease:
+ {
+ /* Nothing */
+ break;
+ }
+
+ case KeyPress:
+ {
+ /* Hack -- use "old" term */
+ Term_activate(&old_td->t);
+
+ /* Process the key */
+ react_keypress(&(xev->xkey));
+
+ break;
+ }
+
+ case Expose:
+ {
+ /* Ignore "extra" exposes */
+ if (xev->xexpose.count) break;
+
+ /* Clear the window */
+ Infowin_wipe();
+
+ /* Redraw */
+ Term_redraw();
+
+ break;
+ }
+
+ case MapNotify:
+ {
+ Infowin->mapped = 1;
+ Term->mapped_flag = TRUE;
+ break;
+ }
+
+ case UnmapNotify:
+ {
+ Infowin->mapped = 0;
+ Term->mapped_flag = FALSE;
+ break;
+ }
+
+ /* Move and/or Resize */
+ case ConfigureNotify:
+ {
+ int cols, rows;
+
+ int ox = Infowin->ox;
+ int oy = Infowin->oy;
+
+ /* Save the new Window Parms */
+ Infowin->x = xev->xconfigure.x;
+ Infowin->y = xev->xconfigure.y;
+ Infowin->w = xev->xconfigure.width;
+ Infowin->h = xev->xconfigure.height;
+
+ /* Determine "proper" number of rows/cols */
+ cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
+ rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
+
+ /* Hack -- minimal size */
+ if (td == &data[0])
+ {
+ if (cols < 80) cols = 80;
+ if (rows < 24) rows = 24;
+ }
+
+ else
+ {
+ if (cols < 1) cols = 1;
+ if (rows < 1) rows = 1;
+ }
+
+ /* Paranoia */
+ if (cols > 255) cols = 255;
+ if (rows > 255) rows = 255;
+
+ /* Resize the Term (if needed) */
+ Term_resize(cols, rows);
+ break;
+ }
+ }
+
+
+ /* Hack -- Activate the old term */
+ Term_activate(&old_td->t);
+
+ /* Hack -- Activate the proper window */
+ Infowin_set(old_td->win);
+
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Handle "activation" of a term
+ */
+static errr Term_xtra_x11_level(int v)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* Handle "activate" */
+ if (v)
+ {
+ /* Activate the window */
+ Infowin_set(td->win);
+
+ /* Activate the font */
+ Infofnt_set(td->fnt);
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * React to changes
+ */
+static errr Term_xtra_x11_react(void)
+{
+ int i;
+
+ if (Metadpy->color)
+ {
+ /* Check the colors */
+ for (i = 0; i < 256; i++)
+ {
+ if ((color_table[i][0] != angband_color_table[i][0]) ||
+ (color_table[i][1] != angband_color_table[i][1]) ||
+ (color_table[i][2] != angband_color_table[i][2]) ||
+ (color_table[i][3] != angband_color_table[i][3]))
+ {
+ Pixell pixel;
+
+ /* Save new values */
+ color_table[i][0] = angband_color_table[i][0];
+ color_table[i][1] = angband_color_table[i][1];
+ color_table[i][2] = angband_color_table[i][2];
+ color_table[i][3] = angband_color_table[i][3];
+
+ /* Create pixel */
+ pixel = create_pixel(Metadpy->dpy,
+ color_table[i][1],
+ color_table[i][2],
+ color_table[i][3]);
+
+ /* Change the foreground */
+ Infoclr_set(clr[i]);
+ Infoclr_change_fg(pixel);
+ }
+ }
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Handle a "special request"
+ */
+static errr Term_xtra_x11(int n, int v)
+{
+ /* Handle a subset of the legal requests */
+ switch (n)
+ {
+ /* Make a noise */
+ case TERM_XTRA_NOISE:
+ Metadpy_do_beep(); return (0);
+
+ /* Flush the output XXX XXX */
+ case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
+
+ /* Process random events XXX */
+ case TERM_XTRA_BORED:
+ {
+ return (CheckEvent(0));
+ }
+
+ /* Process Events XXX */
+ case TERM_XTRA_EVENT:
+ {
+ return (CheckEvent(v));
+ }
+
+ /* Flush the events XXX */
+ case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
+
+ /* Handle change in the "level" */
+ case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
+
+ /* Clear the screen, and redraw any selection later. */
+ case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
+
+ /* Delay for some milliseconds */
+ case TERM_XTRA_DELAY:
+ usleep(1000 * v);
+ return (0);
+
+ /* Get Delay of some milliseconds */
+ case TERM_XTRA_GET_DELAY:
+ {
+ int ret;
+ struct timeval tv;
+
+ ret = gettimeofday(&tv, NULL);
+ Term_xtra_long = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+
+ return ret;
+ }
+
+ /* Subdirectory scan */
+ case TERM_XTRA_SCANSUBDIR:
+ {
+ DIR *directory;
+ struct dirent *entry;
+
+ scansubdir_max = 0;
+
+ directory = opendir(scansubdir_dir);
+ if (!directory)
+ return 1;
+
+ while ((entry = readdir(directory)))
+ {
+ char file[PATH_MAX + NAME_MAX + 2];
+ struct stat filedata;
+
+ file[PATH_MAX + NAME_MAX] = 0;
+ strncpy(file, scansubdir_dir, PATH_MAX);
+ strncat(file, "/", 2);
+ strncat(file, entry->d_name, NAME_MAX);
+ if (!stat(file, &filedata) && S_ISDIR((filedata.st_mode)))
+ {
+ string_free(scansubdir_result[scansubdir_max]);
+ scansubdir_result[scansubdir_max] = string_make(entry->d_name);
+ ++scansubdir_max;
+ }
+ }
+
+ closedir(directory);
+ return 0;
+ }
+
+ /* React to changes */
+ case TERM_XTRA_REACT: return (Term_xtra_x11_react());
+
+ /* Rename main window */
+ case TERM_XTRA_RENAME_MAIN_WIN: Infowin_set_name(angband_term_name[0]); return (0);
+ }
+
+ /* Unknown */
+ return (1);
+}
+
+
+/*
+ * Draw the cursor as an inverted rectangle.
+ *
+ * Consider a rectangular outline like "main-mac.c". XXX XXX
+ */
+static errr Term_curs_x11(int x, int y)
+{
+ /* Draw the cursor */
+ Infoclr_set(xor);
+
+ if (use_bigtile && x + 1 < Term->wid && Term->old->a[y][x + 1] == 255)
+ Infofnt_text_non(x, y, " ", 2);
+ else
+ /* Hilite the cursor character */
+ Infofnt_text_non(x, y, " ", 1);
+
+ /* Redraw the selection if any, as it may have been obscured. (later) */
+ s_ptr->drawn = FALSE;
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Erase some characters.
+ */
+static errr Term_wipe_x11(int x, int y, int n)
+{
+ /* Erase (use black) */
+ Infoclr_set(clr[TERM_DARK]);
+
+ /* Mega-Hack -- Erase some space */
+ Infofnt_text_non(x, y, "", n);
+
+ /* Redraw the selection if any, as it may have been obscured. (later) */
+ s_ptr->drawn = FALSE;
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Draw some textual characters.
+ */
+static errr Term_text_x11(int x, int y, int n, byte a, cptr s)
+{
+ /* Draw the text */
+ Infoclr_set(clr[a]);
+
+ /* Draw the text */
+ Infofnt_text_std(x, y, s, n);
+
+ /* Success */
+ return (0);
+}
+
+
+#ifdef USE_GRAPHICS
+
+/*
+ * Draw some graphical characters.
+ */
+static errr Term_pict_x11(int x, int y, int n, const byte *ap, const char *cp,
+ const byte *tap, const char *tcp, const byte *eap, const char *ecp)
+{
+ int i, x1, y1;
+
+ byte a;
+ char c;
+
+ byte ta;
+ char tc;
+ int x2, y2;
+
+ byte ea;
+ char ec;
+ int x3, y3;
+ bool_ has_overlay;
+
+ int k, l;
+
+ unsigned long pixel, blank;
+
+ term_data *td = (term_data*)(Term->data);
+
+ y *= Infofnt->hgt;
+ x *= Infofnt->wid;
+
+ /* Add in affect of window boundaries */
+ y += Infowin->oy;
+ x += Infowin->ox;
+
+ for (i = 0; i < n; ++i, x += td->fnt->wid)
+ {
+ a = *ap++;
+ c = *cp++;
+
+ /* For extra speed - cache these values */
+ x1 = (c & 0x7F) * td->fnt->twid;
+ y1 = (a & 0x7F) * td->fnt->hgt;
+
+ ta = *tap++;
+ tc = *tcp++;
+
+ /* For extra speed - cache these values */
+ x2 = (tc & 0x7F) * td->fnt->twid;
+ y2 = (ta & 0x7F) * td->fnt->hgt;
+
+ ea = *eap++;
+ ec = *ecp++;
+ has_overlay = (ea && ec);
+
+ /* For extra speed - cache these values too */
+ x3 = (ec & 0x7F) * td->fnt->twid;
+ y3 = (ea & 0x7F) * td->fnt->hgt;
+
+ /* Optimise the common case */
+ if ((x1 == x2) && (y1 == y2))
+ {
+ /* Draw object / terrain */
+ if (!has_overlay)
+ {
+ XPutImage(Metadpy->dpy, td->win->win,
+ clr[0]->gc,
+ td->tiles,
+ x1, y1,
+ x, y,
+ td->fnt->twid, td->fnt->hgt);
+ }
+
+ /* There's a terrain overlay */
+ else
+ {
+ /* Mega Hack^2 - assume the top left corner is "black" */
+ blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
+ for (k = 0; k < td->fnt->twid; k++)
+ {
+ for (l = 0; l < td->fnt->hgt; l++)
+ {
+ /* If mask set in overlay... */
+ if ((pixel = XGetPixel(td->tiles, x3 + k, y3 + l)) == blank)
+ {
+ /* Output from the terrain */
+ pixel = XGetPixel(td->tiles, x1 + k, y1 + l);
+ }
+
+ /* Store into the temp storage. */
+ XPutPixel(td->TmpImage, k, l, pixel);
+ }
+ }
+
+ /* Draw to screen */
+ XPutImage(Metadpy->dpy, td->win->win,
+ clr[0]->gc,
+ td->TmpImage,
+ 0, 0, x, y,
+ td->fnt->twid, td->fnt->hgt);
+ }
+
+ }
+ else
+ {
+
+ /* Mega Hack^2 - assume the top left corner is "black" */
+ blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
+
+ for (k = 0; k < td->fnt->twid; k++)
+ {
+ for (l = 0; l < td->fnt->hgt; l++)
+ {
+ /* Overlay */
+ if (has_overlay)
+ {
+ pixel = XGetPixel(td->tiles, x3 + k, y3 + l);
+ }
+
+ /* Hack -- No overlay */
+ else
+ {
+ pixel = blank;
+ }
+
+ /* If it's blank... */
+ if (pixel == blank)
+ {
+ /* Look at mon/obj */
+ pixel = XGetPixel(td->tiles, x1 + k, y1 + l);
+ }
+
+ /* If it's blank too, use terrain */
+ if (pixel == blank)
+ {
+ pixel = XGetPixel(td->tiles, x2 + k, y2 + l);
+ }
+
+ /* Store into the temp storage. */
+ XPutPixel(td->TmpImage, k, l, pixel);
+ }
+ }
+
+
+
+ /* Draw to screen */
+ XPutImage(Metadpy->dpy, td->win->win,
+ clr[0]->gc,
+ td->TmpImage,
+ 0, 0, x, y,
+ td->fnt->twid, td->fnt->hgt);
+ }
+
+ x += td->fnt->wid;
+ }
+
+ /* Redraw the selection if any, as it may have been obscured. (later) */
+ s_ptr->drawn = FALSE;
+
+ /* Success */
+ return (0);
+}
+
+#endif /* USE_GRAPHICS */
+
+
+
+/*
+ * Initialize a term_data
+ */
+static errr term_data_init(term_data *td, int i)
+{
+ term *t = &td->t;
+
+ cptr name = angband_term_name[i];
+
+ cptr font;
+
+ int x = 0;
+ int y = 0;
+
+ int cols = 80;
+ int rows = 24;
+
+ int ox = 1;
+ int oy = 1;
+
+ int wid, hgt, num;
+
+ char buf[80];
+
+ cptr str;
+
+ int val;
+
+ XClassHint *ch;
+
+ char res_name[20];
+ char res_class[20];
+
+ XSizeHints *sh;
+
+
+ /* Window specific font name */
+ sprintf(buf, "ANGBAND_X11_FONT_%d", i);
+
+ /* Check environment for that font */
+ font = getenv(buf);
+
+ /* Check environment for "base" font */
+ if (!font) font = getenv("ANGBAND_X11_FONT");
+
+ /* No environment variables, use default font */
+ if (!font)
+ {
+ switch (i)
+ {
+ case 0:
+ {
+ font = DEFAULT_X11_FONT;
+ }
+ break;
+ case 1:
+ {
+ font = DEFAULT_X11_FONT;
+ }
+ break;
+ case 2:
+ {
+ font = DEFAULT_X11_FONT;
+ }
+ break;
+ case 3:
+ {
+ font = DEFAULT_X11_FONT;
+ }
+ break;
+ case 4:
+ {
+ font = DEFAULT_X11_FONT;
+ }
+ break;
+ case 5:
+ {
+ font = DEFAULT_X11_FONT;
+ }
+ break;
+ case 6:
+ {
+ font = DEFAULT_X11_FONT;
+ }
+ break;
+ case 7:
+ {
+ font = DEFAULT_X11_FONT;
+ }
+ break;
+ default:
+ {
+ font = DEFAULT_X11_FONT;
+ }
+ }
+ }
+
+ /* Window specific location (x) */
+ sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
+ str = getenv(buf);
+ x = (str != NULL) ? atoi(str) : -1;
+
+ /* Window specific location (y) */
+ sprintf(buf, "ANGBAND_X11_AT_Y_%d", i);
+ str = getenv(buf);
+ y = (str != NULL) ? atoi(str) : -1;
+
+
+ /* Window specific cols */
+ sprintf(buf, "ANGBAND_X11_COLS_%d", i);
+ str = getenv(buf);
+ val = (str != NULL) ? atoi(str) : -1;
+ if (val > 0) cols = val;
+
+ /* Window specific rows */
+ sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
+ str = getenv(buf);
+ val = (str != NULL) ? atoi(str) : -1;
+ if (val > 0) rows = val;
+
+
+ /* Window specific inner border offset (ox) */
+ sprintf(buf, "ANGBAND_X11_IBOX_%d", i);
+ str = getenv(buf);
+ val = (str != NULL) ? atoi(str) : -1;
+ if (val > 0) ox = val;
+
+ /* Window specific inner border offset (oy) */
+ sprintf(buf, "ANGBAND_X11_IBOY_%d", i);
+ str = getenv(buf);
+ val = (str != NULL) ? atoi(str) : -1;
+ if (val > 0) oy = val;
+
+
+ /* Prepare the standard font */
+ MAKE(td->fnt, infofnt);
+ Infofnt_set(td->fnt);
+ Infofnt_init_data(font);
+
+ /* Hack -- key buffer size */
+ num = (i == 0 ? 1024 : 16);
+
+ /* Assume full size windows */
+ wid = cols * td->fnt->wid + (ox + ox);
+ hgt = rows * td->fnt->hgt + (oy + oy);
+
+ /* Create a top-window */
+ MAKE(td->win, infowin);
+ Infowin_set(td->win);
+ Infowin_init_top(x, y, wid, hgt, 0,
+ Metadpy->fg, Metadpy->bg);
+
+ /* Ask for certain events */
+ Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask |
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
+
+ /* Set the window name */
+ Infowin_set_name(name);
+
+ /* Save the inner border */
+ Infowin->ox = ox;
+ Infowin->oy = oy;
+
+ /* Make Class Hints */
+ ch = XAllocClassHint();
+
+ if (ch == NULL) quit("XAllocClassHint failed");
+
+ strcpy(res_name, name);
+ res_name[0] = FORCELOWER(res_name[0]);
+ ch->res_name = res_name;
+
+ strcpy(res_class, "Angband");
+ ch->res_class = res_class;
+
+ XSetClassHint(Metadpy->dpy, Infowin->win, ch);
+
+ /* Make Size Hints */
+ sh = XAllocSizeHints();
+
+ /* Oops */
+ if (sh == NULL) quit("XAllocSizeHints failed");
+
+ /* Fixed window size */
+ if (i == 0)
+ {
+ /* Main window: 80x24 -- 255x255 */
+ sh->flags = PMinSize | PMaxSize;
+ sh->min_width = 80 * td->fnt->wid + (ox + ox);
+ sh->min_height = 24 * td->fnt->hgt + (oy + oy);
+ sh->max_width = 255 * td->fnt->wid + (ox + ox);
+ sh->max_height = 255 * td->fnt->hgt + (oy + oy);
+ }
+
+ /* Variable window size */
+ else
+ {
+ /* Subwindows: 1x1 -- 255x255 */
+ sh->flags = PMinSize | PMaxSize;
+ sh->min_width = td->fnt->wid + (ox + ox);
+ sh->min_height = td->fnt->hgt + (oy + oy);
+ sh->max_width = 255 * td->fnt->wid + (ox + ox);
+ sh->max_height = 255 * td->fnt->hgt + (oy + oy);
+ }
+
+ /* Resize increment */
+ sh->flags |= PResizeInc;
+ sh->width_inc = td->fnt->wid;
+ sh->height_inc = td->fnt->hgt;
+
+ /* Base window size */
+ sh->flags |= PBaseSize;
+ sh->base_width = (ox + ox);
+ sh->base_height = (oy + oy);
+
+ /* Use the size hints */
+ XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
+
+ /* Map the window */
+ Infowin_map();
+
+
+ /* Move the window to requested location */
+ if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
+
+
+ /* Initialize the term */
+ term_init(t, cols, rows, num);
+
+ /* Use a "soft" cursor */
+ t->soft_cursor = TRUE;
+
+ /* Erase with "white space" */
+ t->attr_blank = TERM_WHITE;
+ t->char_blank = ' ';
+
+ /* Hooks */
+ t->xtra_hook = Term_xtra_x11;
+ t->curs_hook = Term_curs_x11;
+ t->wipe_hook = Term_wipe_x11;
+ t->text_hook = Term_text_x11;
+
+ /* Save the data */
+ t->data = td;
+
+ /* Activate (important) */
+ Term_activate(t);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialization function for an "X11" module to Angband
+ */
+errr init_x11(int argc, char *argv[])
+{
+ int i;
+
+ cptr dpy_name = "";
+
+ int num_term = 1;
+
+#ifdef USE_GRAPHICS
+
+ char filename[1024];
+
+ int pict_wid = 0;
+ int pict_hgt = 0;
+ bool_ force_old_graphics = FALSE;
+
+ char *TmpData;
+
+#endif /* USE_GRAPHICS */
+
+
+ /* Parse args */
+ for (i = 1; i < argc; i++)
+ {
+ if (prefix(argv[i], "-d"))
+ {
+ dpy_name = &argv[i][2];
+ continue;
+ }
+
+#ifdef USE_GRAPHICS
+
+ if (prefix(argv[i], "-s"))
+ {
+ smoothRescaling = FALSE;
+ continue;
+ }
+
+ if (prefix(argv[i], "-o"))
+ {
+ force_old_graphics = TRUE;
+ continue;
+ }
+
+ if (prefix(argv[i], "-b"))
+ {
+ arg_bigtile = use_bigtile = TRUE;
+ continue;
+ }
+
+#endif /* USE_GRAPHICS */
+
+ if (prefix(argv[i], "-n"))
+ {
+ num_term = atoi(&argv[i][2]);
+ if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
+ else if (num_term < 1) num_term = 1;
+ continue;
+ }
+
+ plog_fmt("Ignoring option: %s", argv[i]);
+ }
+
+
+ /* Init the Metadpy if possible */
+ if (Metadpy_init_name(dpy_name)) return ( -1);
+
+
+ /* Prepare cursor color */
+ MAKE(xor, infoclr);
+ Infoclr_set(xor);
+ Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
+
+
+ /* Prepare normal colors */
+ for (i = 0; i < 256; ++i)
+ {
+ Pixell pixel;
+
+ MAKE(clr[i], infoclr);
+
+ Infoclr_set(clr[i]);
+
+ /* Acquire Angband colors */
+ color_table[i][0] = angband_color_table[i][0];
+ color_table[i][1] = angband_color_table[i][1];
+ color_table[i][2] = angband_color_table[i][2];
+ color_table[i][3] = angband_color_table[i][3];
+
+ /* Default to monochrome */
+ pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
+
+ /* Handle color */
+ if (Metadpy->color)
+ {
+ /* Create pixel */
+ pixel = create_pixel(Metadpy->dpy,
+ color_table[i][1],
+ color_table[i][2],
+ color_table[i][3]);
+ }
+
+ /* Initialize the color */
+ Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
+ }
+
+
+ /* Initialize the windows */
+ for (i = 0; i < num_term; i++)
+ {
+ term_data *td = &data[i];
+
+ /* Initialize the term_data */
+ term_data_init(td, i);
+
+ /* Save global entry */
+ angband_term[i] = Term;
+ }
+
+ /* Raise the "Angband" window */
+ Infowin_set(data[0].win);
+ Infowin_raise();
+
+ /* Activate the "Angband" window screen */
+ Term_activate(&data[0].t);
+
+
+#ifdef USE_GRAPHICS
+
+ /* Try graphics */
+ if (arg_graphics)
+ {
+ /* Try the "16x16.bmp" file */
+ path_build(filename, 1024, ANGBAND_DIR_XTRA, "graf/16x16.bmp");
+
+ /* Use the "16x16.bmp" file if it exists */
+ if (!force_old_graphics &&
+ (0 == fd_close(fd_open(filename, O_RDONLY))))
+ {
+ /* Use graphics */
+ use_graphics = TRUE;
+
+ pict_wid = pict_hgt = 16;
+
+ ANGBAND_GRAF = "new";
+ }
+ else
+ {
+ /* Try the "8x8.bmp" file */
+ path_build(filename, 1024, ANGBAND_DIR_XTRA, "graf/8x8.bmp");
+
+ /* Use the "8x8.bmp" file if it exists */
+ if (0 == fd_close(fd_open(filename, O_RDONLY)))
+ {
+ /* Use graphics */
+ use_graphics = TRUE;
+
+ pict_wid = pict_hgt = 8;
+
+ ANGBAND_GRAF = "old";
+ }
+ }
+ }
+
+ /* Load graphics */
+ if (use_graphics)
+ {
+ Display *dpy = Metadpy->dpy;
+
+ XImage *tiles_raw;
+
+ /* Load the graphical tiles */
+ tiles_raw = ReadBMP(dpy, filename);
+
+ /* Initialize the windows */
+ for (i = 0; i < num_term; i++)
+ {
+ term_data *td = &data[i];
+
+ term *t = &td->t;
+
+ /* Graphics hook */
+ t->pict_hook = Term_pict_x11;
+
+ /* Use graphics sometimes */
+ t->higher_pict = TRUE;
+
+ /* Resize tiles */
+ td->tiles =
+ ResizeImage(dpy, tiles_raw,
+ pict_wid, pict_hgt,
+ td->fnt->twid, td->fnt->hgt);
+ }
+
+ /* Initialize the transparency masks */
+ for (i = 0; i < num_term; i++)
+ {
+ term_data *td = &data[i];
+ int ii, jj;
+ int depth = DefaultDepth(dpy, DefaultScreen(dpy));
+ Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
+ int total;
+
+
+ /* Determine total bytes needed for image */
+ ii = 1;
+ jj = (depth - 1) >> 2;
+ while (jj >>= 1) ii <<= 1;
+ total = td->fnt->twid * td->fnt->hgt * ii;
+
+
+ TmpData = (char *)malloc(total);
+
+ td->TmpImage = XCreateImage(dpy, visual, depth,
+ ZPixmap, 0, TmpData,
+ td->fnt->twid, td->fnt->hgt, 8, 0);
+
+ }
+
+ /* Free tiles_raw? XXX XXX */
+ }
+
+#endif /* USE_GRAPHICS */
+
+
+ /* Success */
+ return (0);
+}
+
+#endif /* USE_X11 */
+
diff --git a/src/main-xaw.c b/src/main-xaw.c
new file mode 100644
index 00000000..8795e00d
--- /dev/null
+++ b/src/main-xaw.c
@@ -0,0 +1,1888 @@
+/* File: main-xaw.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison, Torbjorn Lindgren, and others
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+
+/*
+ * This file helps Angband work with UNIX/X11 computers.
+ *
+ * To use this file, compile with "USE_XAW" defined, and link against all
+ * the various "X11" libraries which may be needed.
+ *
+ * See also "main-x11.c".
+ *
+ * The Angband widget is not as self-contained as it really should be.
+ * Originally everything was output to a Pixmap which was later copied
+ * to the screen when necessary. The idea was abandoned since Pixmaps
+ * create big performance problems for some really old X terminals (such
+ * as 3/50's running Xkernel).
+ *
+ * Initial framework (and some code) by Ben Harrison (benh@phial.com).
+ *
+ * Most of this file is by Torbjorn Lindgren (tl@cd.chalmers.se).
+ *
+ * Major modifications by Ben Harrison (benh@phial.com).
+ */
+
+
+#include "angband.h"
+
+
+#ifdef USE_XAW
+
+
+#ifndef __MAKEDEPEND__
+#include <X11/Xlib.h>
+#include <X11/StringDefs.h>
+#include <X11/Xutil.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+#include <X11/keysym.h>
+#include <X11/keysymdef.h>
+#include <X11/IntrinsicP.h>
+#include <X11/CoreP.h>
+#include <X11/ShellP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xaw/SimpleP.h>
+#include <X11/Xaw/Simple.h>
+#include <X11/Xaw/XawInit.h>
+#endif /* __MAKEDEPEND__ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+/* /me pffts Solaris */
+#ifndef NAME_MAX
+#define NAME_MAX _POSIX_NAME_MAX
+#endif
+
+
+/*
+ * Include some helpful X11 code.
+ */
+#include "maid-x11.c"
+
+
+
+/**** Resources ****/
+
+
+/*
+
+Name Class RepType Default Value
+---- ----- ------- -------------
+background Background Pixel XtDefaultBackground
+border BorderColor Pixel XtDefaultForeground
+borderWidth BorderWidth Dimension 1
+cursor Cursor Cursor None
+cursorName Cursor String NULL
+destroyCallback Callback Pointer NULL
+height Height Dimension 0
+insensitiveBorder Insensitive Pixmap Gray
+mappedWhenManaged MappedWhenManaged Boolean True
+pointerColor Foreground Pixel XtDefaultForeground
+pointerColorBackground Background Pixel XtDefaultBackground
+sensitive Sensitive Boolean True
+width Width Dimension 0
+x Position Position 0
+y Position Position 0
+
+
+The colors can be changed using the standard Angband user pref files,
+which can also be used to provide black text on a white background,
+by setting color zero to "#FFFFFF" and color one to "#000000", since
+the other colors are unused.
+
+*/
+
+
+/*
+ * New resource names
+ */
+#define XtNstartRows "startRows"
+#define XtNstartColumns "startColumns"
+#define XtNminRows "minRows"
+#define XtNminColumns "minColumns"
+#define XtNmaxRows "maxRows"
+#define XtNmaxColumns "maxColumns"
+#define XtNinternalBorder "internalBorder"
+#define XtNredrawCallback "redrawCallback"
+
+/*
+ * Total normal colors
+ */
+#define NUM_COLORS 256
+
+/*
+ * Special "XOR" color
+ */
+#define COLOR_XOR 256
+
+
+
+/**** The Widget Code ****/
+
+
+/*
+ * Forward declarations
+ */
+typedef struct AngbandPart AngbandPart;
+typedef struct AngbandRec *AngbandWidget;
+typedef struct AngbandRec AngbandRec;
+typedef struct AngbandClassRec *AngbandWidgetClass;
+typedef struct AngbandClassPart AngbandClassPart;
+typedef struct AngbandClassRec AngbandClassRec;
+
+typedef struct term_data term_data;
+
+
+/*
+ * A structure for each "term"
+ */
+struct term_data
+{
+ term t;
+
+ AngbandWidget widget;
+};
+
+
+/*
+ * Maximum number of windows
+ */
+#define MAX_TERM_DATA 8
+
+
+/*
+ * An array of term_data's
+ */
+static term_data data[MAX_TERM_DATA];
+
+
+/*
+ * Current number of windows open
+ */
+static int num_term = MAX_TERM_DATA;
+
+
+/*
+ * New fields for the Angband widget record
+ */
+struct AngbandPart
+{
+ /* Settable resources */
+ int start_rows;
+ int start_columns;
+ int min_rows;
+ int min_columns;
+ int max_rows;
+ int max_columns;
+ int internal_border;
+ String font;
+
+ XtCallbackList redraw_callbacks;
+
+#ifdef USE_GRAPHICS
+
+ /* Tiles */
+ XImage *tiles;
+
+ /* Tempory storage for overlaying tiles. */
+ XImage *TmpImage;
+
+#endif /* USE_GRAPHICS */
+
+ /* Private state */
+ XFontStruct *fnt;
+ Dimension fontheight;
+ Dimension fontwidth;
+ Dimension fontascent;
+
+ /* Color info for GC's */
+ byte color[NUM_COLORS][4];
+
+ /* GC's (including "xor") */
+ GC gc[NUM_COLORS + 1];
+};
+
+
+/*
+ * Full instance record declaration
+ */
+struct AngbandRec
+{
+ CorePart core;
+ SimplePart simple;
+ AngbandPart angband;
+};
+
+
+/*
+ * New fields for the Angband widget class record
+ */
+struct AngbandClassPart
+{
+ int dummy;
+};
+
+
+/*
+ * Full class record declaration
+ */
+struct AngbandClassRec
+{
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ AngbandClassPart angband_class;
+};
+
+
+
+/*
+ * Hack -- see below
+ */
+#define offset(field) XtOffsetOf(AngbandRec, angband.field)
+
+
+/*
+ * Fallback resources for Angband widget
+ */
+static XtResource resources[] =
+{
+ { XtNstartRows, XtCValue, XtRInt, sizeof(int),
+ offset(start_rows), XtRImmediate, (XtPointer) 24 },
+ { XtNstartColumns, XtCValue, XtRInt, sizeof(int),
+ offset(start_columns), XtRImmediate, (XtPointer) 80 },
+ { XtNminRows, XtCValue, XtRInt, sizeof(int),
+ offset(min_rows), XtRImmediate, (XtPointer) 1 },
+ { XtNminColumns, XtCValue, XtRInt, sizeof(int),
+ offset(min_columns), XtRImmediate, (XtPointer) 1 },
+ { XtNmaxRows, XtCValue, XtRInt, sizeof(int),
+ offset(max_rows), XtRImmediate, (XtPointer) 255 },
+ { XtNmaxColumns, XtCValue, XtRInt, sizeof(int),
+ offset(max_columns), XtRImmediate, (XtPointer) 255 },
+ { XtNinternalBorder, XtCValue, XtRInt, sizeof(int),
+ offset(internal_border), XtRImmediate, (XtPointer) 2 },
+ { XtNfont, XtCFont, XtRString, sizeof(char *),
+ offset(font), XtRString, DEFAULT_X11_FONT },
+ { XtNredrawCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(redraw_callbacks), XtRCallback, (XtPointer)NULL }
+};
+
+
+/*
+ * Hack -- see above
+ */
+#undef offset
+
+
+/*
+ * Forward declarations for Widget functions
+ */
+static void Initialize(AngbandWidget request, AngbandWidget wnew);
+static void Redisplay(AngbandWidget w, XEvent *event, Region region);
+static Boolean SetValues(AngbandWidget current, AngbandWidget request,
+ AngbandWidget wnew, ArgList args, Cardinal *num_args);
+static void Destroy(AngbandWidget widget);
+static void Resize_term(AngbandWidget wnew);
+
+/*
+ * Forward declaration for internal functions
+ */
+static void calculateSizeHints(AngbandWidget wnew);
+static XFontStruct *getFont(AngbandWidget widget,
+ String font, Boolean fallback);
+
+
+/*
+ * Hack -- see below
+ */
+#define superclass (&simpleClassRec)
+
+
+/*
+ * Class record constanst
+ */
+AngbandClassRec angbandClassRec =
+{
+ {
+ /* Core class fields initialization */
+ /* superclass */ (WidgetClass) superclass,
+ /* class_name */ "Angband",
+ /* widget_size */ sizeof(AngbandRec),
+ /* class_initialize */ NULL,
+ /* class_part_initialize*/ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ (XtInitProc) Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ XtExposeCompressMultiple,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ (XtWidgetProc) Destroy,
+ /* resize */ (XtWidgetProc) Resize_term,
+ /* expose */ (XtExposeProc) Redisplay,
+ /* set_values */ (XtSetValuesFunc) SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ NULL,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ /* Simple class fields initialization */
+ {
+ /* change_sensitive */ XtInheritChangeSensitive
+#ifndef OLDXAW
+ , NULL
+#endif
+ },
+ /* Angband class fields initialization */
+ {
+ /* nothing */ 0
+ }
+};
+
+/*
+ * Hack -- see above
+ */
+#undef superclass
+
+
+/*
+ * Class record pointer
+ */
+WidgetClass angbandWidgetClass = (WidgetClass) &angbandClassRec;
+
+
+/*
+ * Public procedures
+ */
+
+/*
+ * Simple routine to save the state of the game when the display connection
+ * is broken. Remember, you cannot do anything in this function that will
+ * generate X protocol requests.
+ */
+static int x_io_error_handler(Display *d)
+{
+ /* We have nothing to save */
+ if (!character_generated) return 0;
+
+ save_dungeon();
+ save_player();
+
+ return 0;
+}
+
+
+/*
+ * Clear an area
+ */
+static void AngbandClearArea(AngbandWidget widget,
+ int x, int y, int w, int h, int a)
+{
+ /* Figure out which area to clear */
+ y = y * widget->angband.fontheight + widget->angband.internal_border;
+ x = x * widget->angband.fontwidth + widget->angband.internal_border;
+
+ /* Clear the area */
+ XFillRectangle(XtDisplay(widget), XtWindow(widget),
+ widget->angband.gc[a],
+ x, y,
+ widget->angband.fontwidth * w,
+ widget->angband.fontheight * h);
+}
+
+
+
+/*
+ * Output some text
+ */
+static void AngbandOutputText(AngbandWidget widget, int x, int y,
+ String txt, int len, int a)
+{
+ /* Do nothing if the string is null */
+ if (!txt || !*txt) return;
+
+ /* Check the length, and fix it if it's below zero */
+ if (len < 0) len = strlen(txt);
+
+ /* Figure out where to place the text */
+ y = (y * widget->angband.fontheight + widget->angband.fontascent +
+ widget->angband.internal_border);
+ x = (x * widget->angband.fontwidth + widget->angband.internal_border);
+
+ /* Place the string */
+ XDrawImageString(XtDisplay(widget), XtWindow(widget),
+ widget->angband.gc[a], x, y, txt, len);
+}
+
+
+#ifdef USE_GRAPHICS
+
+/*
+ * Draw some graphical characters.
+ */
+static void AngbandOutputPict(AngbandWidget widget, int x, int y, int n,
+ const byte *ap, const char *cp, const byte *tap, const char *tcp,
+ const byte *eap, const char *ecp)
+{
+ int i, x1, y1;
+
+ byte a;
+ char c;
+
+ byte ta;
+ char tc;
+
+ int x2, y2;
+
+ byte ea;
+ char ec;
+
+ int x3, y3;
+ bool_ has_overlay;
+
+ int k, l;
+ unsigned long pixel, blank;
+
+ /* Figure out where to place the text */
+ y = (y * widget->angband.fontheight + widget->angband.internal_border);
+ x = (x * widget->angband.fontwidth + widget->angband.internal_border);
+
+ for (i = 0; i < n; ++i)
+ {
+ a = *ap++;
+ c = *cp++;
+
+ /* For extra speed - cache these values */
+ x1 = (c & 0x7F) * widget->angband.fontwidth;
+ y1 = (a & 0x7F) * widget->angband.fontheight;
+
+ ta = *tap++;
+ tc = *tcp++;
+
+ /* For extra speed - cache these values */
+ x2 = (tc & 0x7F) * widget->angband.fontwidth;
+ y2 = (ta & 0x7F) * widget->angband.fontheight;
+
+ ea = *eap++;
+ ec = *ecp++;
+ has_overlay = (ea && ec);
+
+ /* For extra speed -- cache these values */
+ x3 = (ec & 0x7F) * widget->angband.fontwidth;
+ y3 = (ea & 0x7F) * widget->angband.fontheight;
+
+ /* Optimise the common case */
+ if ((x1 == x2) && (y1 == y2))
+ {
+
+ /* No overlay */
+ if (!has_overlay)
+ {
+ /* Draw object / terrain */
+ XPutImage(XtDisplay(widget), XtWindow(widget),
+ widget->angband.gc[0],
+ widget->angband.tiles,
+ x1, y1,
+ x, y,
+ widget->angband.fontwidth,
+ widget->angband.fontheight);
+ }
+
+ /* Terrain overlay */
+ else
+ {
+ /* Mega Hack^2 - assume the top left corner is "black" */
+ blank = XGetPixel(widget->angband.tiles,
+ 0, widget->angband.fontheight * 6);
+
+ for (k = 0; k < widget->angband.fontwidth; k++)
+ {
+ for (l = 0; l < widget->angband.fontheight; l++)
+ {
+ /* If mask set... */
+ if ((pixel = XGetPixel(widget->angband.tiles,
+ x3 + k, y3 + l)) == blank)
+ {
+ /* Output from the terrain */
+ pixel = XGetPixel(widget->angband.tiles,
+ x1 + k, y1 + l);
+ }
+
+ /* Store into the temp storage */
+ XPutPixel(widget->angband.TmpImage,
+ k, l, pixel);
+ }
+ }
+
+ /* Draw terrain + overlay */
+ XPutImage(XtDisplay(widget), XtWindow(widget),
+ widget->angband.gc[0],
+ widget->angband.TmpImage,
+ 0, 0,
+ x, y,
+ widget->angband.fontwidth,
+ widget->angband.fontheight);
+ }
+
+ }
+ else
+ {
+ /* Mega Hack^2 - assume the top left corner is "black" */
+ blank = XGetPixel(widget->angband.tiles,
+ 0, widget->angband.fontheight * 6);
+
+ for (k = 0; k < widget->angband.fontwidth; k++)
+ {
+ for (l = 0; l < widget->angband.fontheight; l++)
+ {
+ /* Get overlay pixel */
+ if (has_overlay)
+ {
+ pixel = XGetPixel(widget->angband.tiles,
+ x3 + k, y3 + l);
+ }
+
+ /* Hack -- no overlay */
+ else
+ {
+ pixel = blank;
+ }
+
+ /* If it's blank */
+ if (pixel == blank)
+ {
+ /* Use obj/mon */
+ pixel = XGetPixel(widget->angband.tiles,
+ x1 + k, y1 + l);
+ }
+
+ /* Use terrain if it's blank too */
+ if (pixel == blank)
+ {
+ pixel = XGetPixel(widget->angband.tiles,
+ x2 + k, y2 + l);
+ }
+
+ /* Store into the temp storage. */
+ XPutPixel(widget->angband.TmpImage,
+ k, l, pixel);
+ }
+ }
+
+ /* Draw to screen */
+
+ /* Draw object / terrain */
+ XPutImage(XtDisplay(widget), XtWindow(widget),
+ widget->angband.gc[0],
+ widget->angband.TmpImage,
+ 0, 0,
+ x, y,
+ widget->angband.fontwidth,
+ widget->angband.fontheight);
+ }
+
+ x += widget->angband.fontwidth;
+ }
+}
+
+#endif /* USE_GRAPHICS */
+
+/*
+ * Private procedures
+ */
+
+
+/*
+ * Procedure Initialize() is called during the widget creation
+ * process. Initialize() load fonts and calculates window geometry.
+ * The request parameter is filled in by parents to this widget. The
+ * wnew parameter is the request parameter plus data filled in by this
+ * widget. All changes should be done to the wnew parameter.
+ */
+static void Initialize(AngbandWidget request, AngbandWidget wnew)
+{
+ Display *dpy = XtDisplay(wnew);
+
+ int depth = DefaultDepthOfScreen(XtScreen((Widget) wnew));
+
+ XGCValues gcv;
+ TopLevelShellWidget parent =
+ (TopLevelShellWidget)XtParent((Widget) wnew);
+ int i;
+
+ /* Default background pixel */
+ unsigned long bg = create_pixel(dpy,
+ angband_color_table[0][1],
+ angband_color_table[0][2],
+ angband_color_table[0][3]);
+
+ /* Default foreground pixel */
+ unsigned long fg = create_pixel(dpy,
+ angband_color_table[1][1],
+ angband_color_table[1][2],
+ angband_color_table[1][3]);
+
+ /* Fix the background color */
+ wnew->core.background_pixel = bg;
+
+ /* Get some information about the font */
+ wnew->angband.fnt = getFont(wnew, wnew->angband.font, TRUE);
+ wnew->angband.fontheight = wnew->angband.fnt->ascent +
+ wnew->angband.fnt->descent;
+ wnew->angband.fontwidth = wnew->angband.fnt->max_bounds.width;
+ wnew->angband.fontascent = wnew->angband.fnt->ascent;
+
+ /* Create and initialize the graphics contexts */ /* GXset? */
+ gcv.font = wnew->angband.fnt->fid;
+ gcv.graphics_exposures = FALSE;
+ gcv.background = bg;
+
+ for (i = 0; i < NUM_COLORS; i++)
+ {
+ unsigned long pixel;
+
+ /* Acquire Angband colors */
+ wnew->angband.color[i][0] = angband_color_table[i][0];
+ wnew->angband.color[i][1] = angband_color_table[i][1];
+ wnew->angband.color[i][2] = angband_color_table[i][2];
+ wnew->angband.color[i][3] = angband_color_table[i][3];
+
+ if (depth > 1)
+ {
+ /* Create pixel */
+ pixel = create_pixel(dpy,
+ wnew->angband.color[i][1],
+ wnew->angband.color[i][2],
+ wnew->angband.color[i][3]);
+ }
+ else
+ {
+ /* Use background or foreground */
+ pixel = ((i == 0) ? bg : fg);
+ }
+
+ gcv.foreground = pixel;
+
+ /* Copy */
+ gcv.function = 3;
+
+ wnew->angband.gc[i] = XtGetGC((Widget)wnew,
+ (GCFont | GCForeground | GCFunction |
+ GCBackground | GCGraphicsExposures),
+ &gcv);
+ }
+
+ /* Create a special GC for highlighting */
+ gcv.foreground = (BlackPixelOfScreen(XtScreen((Widget)wnew)) ^
+ WhitePixelOfScreen(XtScreen((Widget)wnew)));
+ gcv.background = 0;
+
+ gcv.function = GXxor;
+ wnew->angband.gc[COLOR_XOR] = XtGetGC((Widget)wnew,
+ (GCFunction | GCForeground | GCBackground |
+ GCGraphicsExposures),
+ &gcv);
+
+ /* Calculate window geometry */
+ wnew->core.height = (wnew->angband.start_rows * wnew->angband.fontheight +
+ 2 * wnew->angband.internal_border);
+ wnew->core.width = (wnew->angband.start_columns * wnew->angband.fontwidth +
+ 2 * wnew->angband.internal_border);
+
+ /* We need to be able to resize the Widget if the user wants to */
+ /* change font on the fly! */
+ parent->shell.allow_shell_resize = TRUE;
+
+ /* Calculates all the size hints */
+ calculateSizeHints(wnew);
+}
+
+
+/*
+ * Procedure Destroy() is called during the destruction of the widget.
+ * Destroy() releases and frees GCs, frees the pixmaps and frees the
+ * fonts.
+ */
+static void Destroy(AngbandWidget widget)
+{
+ int n;
+
+ /* Free all GC's */
+ for (n = 0; n < NUM_COLORS + 1; n++)
+ {
+ XtReleaseGC((Widget)widget, widget->angband.gc[n]);
+ }
+
+ /* Free the font */
+ XFreeFont(XtDisplay((Widget)widget), widget->angband.fnt);
+}
+
+
+static void Resize_term(AngbandWidget wnew)
+{
+ int cols, rows, wid, hgt;
+
+ int ox = wnew->angband.internal_border;
+ int oy = wnew->angband.internal_border;
+
+ int i;
+ term_data *old_td;
+ term_data *td = &data[0];
+
+
+ /*
+ * Mega-Hack -- avoid calling this before the terms package is
+ * initialised
+ */
+ if (!Term) return;
+
+ old_td = (term_data*)(Term->data);
+
+ /* Hack - Find the term to activate */
+ for (i = 0; i < num_term; i++)
+ {
+ td = &data[i];
+
+ /* Paranoia: none of the widgets matched */
+ if (!td) return;
+
+ /* Have we found it? */
+ if (td->widget == wnew) break;
+ }
+
+ /* Paranoia -- No matches */
+ if (i == num_term) return;
+
+ /* Activate the proper Term */
+ Term_activate(&td->t);
+
+ /* Determine "proper" number of rows/cols */
+ cols = ((wnew->core.width - (ox + ox)) / wnew->angband.fontwidth);
+ rows = ((wnew->core.height - (oy + oy)) / wnew->angband.fontheight);
+
+ /* Hack -- minimal size */
+ if (cols < 1) cols = 1;
+ if (rows < 1) rows = 1;
+
+ if (i == 0)
+ {
+ /* Hack the main window must be at least 80x24 */
+ if (cols < 80) cols = 80;
+ if (rows < 24) rows = 24;
+ }
+
+ /* Desired size of window */
+ wid = cols * wnew->angband.fontwidth + (ox + ox);
+ hgt = rows * wnew->angband.fontheight + (oy + oy);
+
+ /* Resize the Term (if needed) */
+ (void) Term_resize(cols, rows);
+
+ /* Activate the old term */
+ Term_activate(&old_td->t);
+}
+
+/*
+ * Procedure Redisplay() is called as the result of an Expose event.
+ * Use the redraw callback to do a full redraw
+ */
+static void Redisplay(AngbandWidget wnew, XEvent *xev, Region region)
+{
+ int x1, x2, y1, y2;
+
+ int i;
+
+ term_data *old_td = (term_data*)(Term->data);
+ term_data *td = &data[0];
+
+ /* Hack - Find the term to activate */
+ for (i = 0; i < num_term; i++)
+ {
+ td = &data[i];
+
+ /* Have we found it? */
+ if (td->widget == wnew) break;
+
+ /* Paranoia: none of the widgets matched */
+ if (!td) return;
+ }
+
+ /* Activate the proper Term */
+ Term_activate(&td->t);
+
+ /* Find the bounds of the exposed region */
+
+ /*
+ * This probably could be obtained from the Region parameter -
+ * but I don't know anything about XAW.
+ */
+ x1 = (xev->xexpose.x - wnew->angband.internal_border)
+ / wnew->angband.fontwidth;
+ x2 = (xev->xexpose.x + xev->xexpose.width -
+ wnew->angband.internal_border) / wnew->angband.fontwidth;
+
+ y1 = (xev->xexpose.y - wnew->angband.internal_border)
+ / wnew->angband.fontheight;
+ y2 = (xev->xexpose.y + xev->xexpose.height -
+ wnew->angband.internal_border) / wnew->angband.fontheight;
+
+ Term_redraw_section(x1, y1, x2, y2);
+
+ /* Activate the old term */
+ Term_activate(&old_td->t);
+
+
+#if 0
+ if (XtHasCallbacks((Widget)widget, XtNredrawCallback) == XtCallbackHasSome)
+ {
+ XtCallCallbacks((Widget)widget, XtNredrawCallback, NULL);
+ }
+#endif /* 0 */
+}
+
+
+/*
+ * Font and internal_border can be changed on the fly.
+ *
+ * The entire widget is redrawn if any of those parameters change (all
+ * can potentially have effects that spans the whole widget).
+ *
+ * Color changes are handled elsewhere.
+ *
+ * This function is very underspecified, in terms of how these changes can
+ * occur, and what is true about the various AngbandWidget's passed in. It
+ * is very likely that this code no longer works.
+ */
+static Boolean SetValues(AngbandWidget current, AngbandWidget request,
+ AngbandWidget wnew, ArgList args,
+ Cardinal *num_args)
+{
+ Display *dpy = XtDisplay(wnew);
+
+ Boolean font_changed = FALSE;
+ Boolean border_changed = FALSE;
+ int height, width;
+ int i;
+
+
+ /* Handle font change */
+ if (wnew->angband.font != current->angband.font)
+ {
+ /* Check if the font exists */
+ wnew->angband.fnt = getFont(wnew, wnew->angband.font, FALSE);
+
+ /* The font didn't exist */
+ if (wnew->angband.fnt == NULL)
+ {
+ wnew->angband.fnt = current->angband.fnt;
+ wnew->angband.font = current->angband.font;
+ XtWarning("Couldn't find the requested font!");
+ }
+ else
+ {
+ font_changed = TRUE;
+
+ /* Free the old font */
+ XFreeFont(XtDisplay((Widget)wnew), current->angband.fnt);
+ /* Update font information */
+ wnew->angband.fontheight = wnew->angband.fnt->ascent +
+ wnew->angband.fnt->descent;
+ wnew->angband.fontwidth = wnew->angband.fnt->max_bounds.width;
+ wnew->angband.fontascent = wnew->angband.fnt->ascent;
+ }
+ }
+
+ /* Handle font change */
+ if (font_changed)
+ {
+ /* Update all GC's */
+ for (i = 0; i < NUM_COLORS; i++)
+ {
+ /* Steal the old GC */
+ wnew->angband.gc[i] = current->angband.gc[i];
+ current->angband.gc[i] = NULL;
+
+ /* Be sure the correct font is ready */
+ XSetFont(dpy, wnew->angband.gc[i], wnew->angband.fnt->fid);
+ }
+
+ /* Steal the old GC */
+ wnew->angband.gc[NUM_COLORS] = current->angband.gc[NUM_COLORS];
+ current->angband.gc[NUM_COLORS] = NULL;
+ }
+
+
+ /* Check if internal border width has changed, used later */
+ if (current->angband.internal_border != wnew->angband.internal_border)
+ {
+ border_changed = TRUE;
+ }
+
+
+ /* If the font or the internal border has changed, all geometry */
+ /* has to be recalculated */
+ if (font_changed || border_changed)
+ {
+ /* Change window size */
+ height = ((current->core.height - 2 * current->angband.internal_border) /
+ current->angband.fontheight * wnew->angband.fontheight +
+ 2 * current->angband.internal_border);
+ width = ((current->core.width - 2 * current->angband.internal_border) /
+ current->angband.fontwidth * wnew->angband.fontwidth +
+ 2 * wnew->angband.internal_border);
+
+ /* Get the new width */
+ if (XtMakeResizeRequest((Widget)wnew, width, height, NULL, NULL) ==
+ XtGeometryNo)
+ {
+ /* Not allowed */
+ XtWarning("Size change denied!");
+ }
+ else
+ {
+ /* Recalculate size hints */
+ calculateSizeHints(wnew);
+ }
+ }
+
+ /* Tell it to redraw the widget if anything has changed */
+ return (font_changed || border_changed);
+}
+
+
+/*
+ * Calculate size hints
+ */
+static void calculateSizeHints(AngbandWidget wnew)
+{
+ TopLevelShellWidget parent =
+ (TopLevelShellWidget)XtParent((Widget) wnew);
+
+ /* Calculate minimum size */
+ parent->wm.size_hints.min_height =
+ (wnew->angband.min_rows * wnew->angband.fontheight +
+ 2 * wnew->angband.internal_border);
+
+ /* Calculate minimum size */
+ parent->wm.size_hints.min_width =
+ (wnew->angband.min_columns * wnew->angband.fontwidth +
+ 2 * wnew->angband.internal_border);
+
+ /* Calculate minimum size */
+ parent->wm.size_hints.flags |= PMinSize;
+
+ /* Calculate maximum size */
+ parent->wm.size_hints.max_height =
+ (wnew->angband.max_rows * wnew->angband.fontheight +
+ 2 * wnew->angband.internal_border);
+
+ /* Calculate maximum size */
+ parent->wm.size_hints.max_width =
+ (wnew->angband.max_columns * wnew->angband.fontwidth +
+ 2 * wnew->angband.internal_border);
+
+ /* Calculate maximum size */
+ parent->wm.size_hints.flags |= PMaxSize;
+
+ /* Calculate increment size */
+ parent->wm.size_hints.height_inc = wnew->angband.fontheight;
+ parent->wm.size_hints.width_inc = wnew->angband.fontwidth;
+ parent->wm.size_hints.flags |= PResizeInc;
+
+ /* Calculate base size */
+ parent->wm.base_height = 2 * wnew->angband.internal_border;
+ parent->wm.base_width = 2 * wnew->angband.internal_border;
+ parent->wm.size_hints.flags |= PBaseSize;
+}
+
+
+/*
+ * Load a font
+ */
+static XFontStruct *getFont(AngbandWidget widget,
+ String font, Boolean fallback)
+{
+ Display *dpy = XtDisplay((Widget) widget);
+ char buf[256];
+ XFontStruct *fnt = NULL;
+
+ if (!(fnt = XLoadQueryFont(dpy, font)) && fallback)
+ {
+ sprintf(buf, "Can't find the font \"%s\", trying fixed\n", font);
+ XtWarning(buf);
+ if (!(fnt = XLoadQueryFont(dpy, "fixed")))
+ {
+ XtError("Can't fint the font \"fixed\"!, bailing out\n");
+ }
+ }
+
+ return fnt;
+}
+
+
+
+/*** The Angband code ****/
+
+
+
+
+
+/*
+ * Number of fallback resources per window
+ */
+#define TERM_FALLBACKS 6
+
+
+
+/*
+ * The names of the term_data's
+ */
+char *termNames[MAX_TERM_DATA] =
+{
+ "angband",
+ "mirror",
+ "recall",
+ "choice",
+ "term-4",
+ "term-5",
+ "term-6",
+ "term-7"
+};
+
+
+/*
+ * The special Arg's
+ */
+Arg specialArgs[TERM_FALLBACKS] =
+{
+ { XtNstartRows, 24},
+ { XtNstartColumns, 80},
+ { XtNminRows, 24},
+ { XtNminColumns, 80},
+ { XtNmaxRows, 255},
+ { XtNmaxColumns, 255}
+};
+
+
+/*
+ * The default Arg's
+ */
+Arg defaultArgs[TERM_FALLBACKS] =
+{
+ { XtNstartRows, 24},
+ { XtNstartColumns, 80},
+ { XtNminRows, 1},
+ { XtNminColumns, 1},
+ { XtNmaxRows, 255},
+ { XtNmaxColumns, 255}
+};
+
+
+/*
+ * The application context
+ */
+XtAppContext appcon;
+
+
+/*
+ * User changable information about widgets
+ */
+static String fallback[] =
+{
+ "Angband.angband.iconName: ToME",
+ "Angband.angband.title: ToME",
+ "Angband.term-1.iconName: Mirror",
+ "Angband.term-1.title: Mirror",
+ "Angband.term-2.iconName: Recall",
+ "Angband.term-2.title: Recall",
+ "Angband.term-3.iconName: Choice",
+ "Angband.term-3.title: Choice",
+ "Angband.term-4.iconName: Term 4",
+ "Angband.term-4.title: Term 4",
+ "Angband.term-5.iconName: Term 5",
+ "Angband.term-5.title: Term 5",
+ "Angband.term-6.iconName: Term 6",
+ "Angband.term-6.title: Term 6",
+ "Angband.term-7.iconName: Term 7",
+ "Angband.term-7.title: Term 7",
+ NULL
+};
+
+
+
+/*
+ * Do a redraw
+ */
+static void react_redraw(Widget widget,
+ XtPointer client_data, XtPointer call_data)
+{
+ term_data *old_td = (term_data*)(Term->data);
+ term_data *td = (term_data*)client_data;
+
+ /* Activate the proper Term */
+ Term_activate(&td->t);
+
+ /* Request a redraw */
+ Term_redraw();
+
+ /* Activate the old Term */
+ Term_activate(&old_td->t);
+}
+
+
+
+/*
+ * Process a keypress event
+ *
+ * Also appears in "main-x11.c".
+ */
+static void react_keypress(XKeyEvent *xev)
+{
+ int i, n, mc, ms, mo, mx;
+
+ uint ks1;
+
+ XKeyEvent *ev = (XKeyEvent*)(xev);
+
+ KeySym ks;
+
+ char buf[128];
+ char msg[128];
+
+
+ /* Check for "normal" keypresses */
+ n = XLookupString(ev, buf, 125, &ks, NULL);
+
+ /* Terminate */
+ buf[n] = '\0';
+
+
+ /* Hack -- Ignore "modifier keys" */
+ if (IsModifierKey(ks)) return;
+
+
+ /* Hack -- convert into an unsigned int */
+ ks1 = (uint)(ks);
+
+ /* Extract four "modifier flags" */
+ mc = (ev->state & ControlMask) ? TRUE : FALSE;
+ ms = (ev->state & ShiftMask) ? TRUE : FALSE;
+ mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
+ mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
+
+
+ /* Normal keys with no modifiers */
+ if (n && !mo && !mx && !IsSpecialKey(ks))
+ {
+ /* Enqueue the normal key(s) */
+ for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
+
+ /* All done */
+ return;
+ }
+
+
+ /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
+ switch (ks1)
+ {
+ case XK_Escape:
+ {
+ Term_keypress(ESCAPE);
+ return;
+ }
+
+ case XK_Return:
+ {
+ Term_keypress('\r');
+ return;
+ }
+
+ case XK_Tab:
+ {
+ Term_keypress('\t');
+ return;
+ }
+
+ case XK_Delete:
+ case XK_BackSpace:
+ {
+ Term_keypress('\010');
+ return;
+ }
+ }
+
+
+ /* Hack -- Use the KeySym */
+ if (ks)
+ {
+ sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
+ mc ? "N" : "", ms ? "S" : "",
+ mo ? "O" : "", mx ? "M" : "",
+ (unsigned long)(ks), 13);
+ }
+
+ /* Hack -- Use the Keycode */
+ else
+ {
+ sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
+ mc ? "N" : "", ms ? "S" : "",
+ mo ? "O" : "", mx ? "M" : "",
+ ev->keycode, 13);
+ }
+
+ /* Enqueue the "macro trigger" string */
+ for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
+
+
+ /* Hack -- auto-define macros as needed */
+ if (n && (macro_find_exact(msg) < 0))
+ {
+ /* Create a macro */
+ macro_add(msg, buf);
+ }
+}
+
+
+/*
+ * Handle an event
+ */
+static void handle_event(Widget widget, XtPointer client_data, XEvent *event,
+ Boolean *continue_to_dispatch)
+{
+ term_data *old_td = (term_data*)(Term->data);
+ term_data *td = (term_data *)client_data;
+
+ /* Continue to process the event by default */
+ *continue_to_dispatch = TRUE;
+
+ /* Activate the Term */
+ Term_activate(&td->t);
+
+ switch (event->type)
+ {
+ case KeyPress:
+ {
+ /* Hack -- use old term */
+ Term_activate(&old_td->t);
+
+ /* Handle the keypress */
+ react_keypress(&(event->xkey));
+
+ /* We took care of the event */
+ *continue_to_dispatch = FALSE;
+
+ break;
+ }
+
+ /* Oops */
+ default:
+ {
+ break;
+ }
+ }
+
+ /* Activate the old term */
+ Term_activate(&old_td->t);
+
+ return;
+}
+
+
+/*
+ * Process an event (or just check for one)
+ */
+errr CheckEvent(bool_ wait)
+{
+ XEvent event;
+
+ /* No events ready, and told to just check */
+ if (!wait && !XtAppPending(appcon)) return 1;
+
+ /* Process */
+ while (1)
+ {
+ XtAppNextEvent(appcon, &event);
+ XtDispatchEvent(&event);
+ if (!XtAppPending(appcon)) break;
+ }
+
+ return (0);
+}
+
+
+/*
+ * Monstrous hack.
+ */
+static void Term_xtra_xaw_react_aux(term_data *td)
+{
+ AngbandWidget wnew = td->widget;
+
+ Display *dpy = XtDisplay((Widget) wnew);
+
+ int depth = DefaultDepthOfScreen(XtScreen((Widget) wnew));
+
+ int i;
+
+ /* See if any colors need to be changed */
+ for (i = 0; i < NUM_COLORS; i++)
+ {
+ if (depth > 1)
+ {
+ if ((wnew->angband.color[i][0] != angband_color_table[i][0]) ||
+ (wnew->angband.color[i][1] != angband_color_table[i][1]) ||
+ (wnew->angband.color[i][2] != angband_color_table[i][2]) ||
+ (wnew->angband.color[i][3] != angband_color_table[i][3]))
+ {
+ unsigned long pixel;
+
+ /* Save new values */
+ wnew->angband.color[i][0] = angband_color_table[i][0];
+ wnew->angband.color[i][1] = angband_color_table[i][1];
+ wnew->angband.color[i][2] = angband_color_table[i][2];
+ wnew->angband.color[i][3] = angband_color_table[i][3];
+
+ /* Create pixel */
+ pixel = create_pixel(dpy,
+ wnew->angband.color[i][1],
+ wnew->angband.color[i][2],
+ wnew->angband.color[i][3]);
+
+
+ /* Change */
+ XSetForeground(dpy, wnew->angband.gc[i], pixel);
+ }
+ }
+ }
+}
+
+
+/*
+ * Monstrous hack.
+ */
+static errr Term_xtra_xaw_react(void)
+{
+ int i;
+
+ /* Initialize the windows */
+ for (i = 0; i < num_term; i++)
+ {
+ term_data *td = &data[i];
+
+ if (!td) break;
+
+ Term_xtra_xaw_react_aux(td);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Handle a "special request"
+ */
+static errr Term_xtra_xaw(int n, int v)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ Widget widget = (Widget)(td->widget);
+
+ Display *dpy = XtDisplay(widget);
+
+ /* Handle a subset of the legal requests */
+ switch (n)
+ {
+ /* Make a noise */
+ case TERM_XTRA_NOISE:
+ XBell(dpy, 100);
+ return (0);
+
+ /* Flush the output */
+ case TERM_XTRA_FRESH:
+ XFlush(dpy);
+ /* Allow flushed events to be showed */
+ CheckEvent(FALSE);
+ return (0);
+
+ /* Process random events */
+ case TERM_XTRA_BORED:
+ return (CheckEvent(0));
+
+ /* Process events */
+ case TERM_XTRA_EVENT:
+ return (CheckEvent(v));
+
+ /* Flush events */
+ case TERM_XTRA_FLUSH:
+ while (!CheckEvent(FALSE));
+ return (0);
+
+ /* Clear the window */
+ case TERM_XTRA_CLEAR:
+ XClearWindow(dpy, XtWindow(widget));
+ return (0);
+
+ /* Delay */
+ case TERM_XTRA_DELAY:
+ usleep(1000 * v);
+ return (0);
+
+ /* Get Delay of some milliseconds */
+ case TERM_XTRA_GET_DELAY:
+ {
+ int ret;
+ struct timeval tv;
+
+ ret = gettimeofday(&tv, NULL);
+ Term_xtra_long = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+
+ return ret;
+ }
+
+ /* Subdirectory scan */
+ case TERM_XTRA_SCANSUBDIR:
+ {
+ DIR *directory;
+ struct dirent *entry;
+
+ scansubdir_max = 0;
+
+ directory = opendir(scansubdir_dir);
+ if (!directory)
+ return 1;
+
+ while (entry = readdir(directory))
+ {
+ char file[PATH_MAX + NAME_MAX + 2];
+ struct stat filedata;
+
+ file[PATH_MAX + NAME_MAX] = 0;
+ strncpy(file, scansubdir_dir, PATH_MAX);
+ strncat(file, "/", 2);
+ strncat(file, entry->d_name, NAME_MAX);
+ if (!stat(file, &filedata) && S_ISDIR((filedata.st_mode)))
+ {
+ string_free(scansubdir_result[scansubdir_max]);
+ scansubdir_result[scansubdir_max] = string_make(entry->d_name);
+ ++scansubdir_max;
+ }
+ }
+ }
+
+ case TERM_XTRA_REACT:
+ return (Term_xtra_xaw_react());
+ }
+
+ /* Unknown */
+ return (1);
+}
+
+
+
+/*
+ * Erase a number of characters
+ */
+static errr Term_wipe_xaw(int x, int y, int n)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* Erase using color 0 */
+ AngbandClearArea(td->widget, x, y, n, 1, 0);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Draw the cursor, by hiliting with XOR
+ *
+ * Should perhaps use rectangle outline, ala "main-mac.c". XXX XXX XXX
+ */
+static errr Term_curs_xaw(int x, int y)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* Hilite the cursor character */
+ AngbandClearArea(td->widget, x, y, 1, 1, COLOR_XOR);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Draw a number of characters
+ */
+static errr Term_text_xaw(int x, int y, int n, byte a, cptr s)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* Draw the text */
+ AngbandOutputText(td->widget, x, y, (String)s, n, a);
+
+ /* Success */
+ return (0);
+}
+
+
+#ifdef USE_GRAPHICS
+
+/*
+ * Draw some graphical characters.
+ */
+static errr Term_pict_xaw(int x, int y, int n, const byte *ap, const char *cp,
+ const byte *tap, const char *tcp, const byte *eap, const char *ecp)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* Draw the pictures */
+ AngbandOutputPict(td->widget, x, y, n, ap, cp, tap, tcp, eap, ecp);
+
+ /* Success */
+ return (0);
+}
+
+#endif /* USE_GRAPHICS */
+
+
+/*
+ * Raise a term
+ */
+static void term_raise(term_data *td)
+{
+ Widget widget = (Widget)(td->widget);
+
+ XRaiseWindow(XtDisplay(XtParent(widget)), XtWindow(XtParent(widget)));
+}
+
+
+/*
+ * Initialize a term_data
+ */
+static errr term_data_init(term_data *td, Widget topLevel,
+ int key_buf, String name,
+ ArgList widget_arg, Cardinal widget_arg_no, int i)
+{
+ Widget parent;
+ term *t = &td->t;
+
+ int cols = 80;
+ int rows = 24;
+
+ char buf[80];
+ cptr str;
+
+ int val;
+
+ /* Create the shell widget */
+ parent = XtCreatePopupShell(name, topLevelShellWidgetClass, topLevel,
+ NULL, 0);
+
+ /* Window specific cols */
+ sprintf(buf, "ANGBAND_X11_COLS_%d", i);
+ str = getenv(buf);
+ val = (str != NULL) ? atoi(str) : -1;
+ if (val > 0) cols = val;
+
+ /* Window specific rows */
+ sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
+ str = getenv(buf);
+ val = (str != NULL) ? atoi(str) : -1;
+ if (val > 0) rows = val;
+
+ /* Hack the main window must be at least 80x24 */
+ if (i == 0)
+ {
+ if (cols < 80) cols = 80;
+ if (rows < 24) rows = 24;
+ }
+
+ /* Reset the initial size */
+ widget_arg[0].value = rows;
+ widget_arg[1].value = cols;
+
+ /* Create the interior widget */
+ td->widget = (AngbandWidget)
+ XtCreateManagedWidget(name, angbandWidgetClass,
+ parent, widget_arg, widget_arg_no);
+
+ /* Initialize the term (full size) */
+ term_init(t, cols, rows, key_buf);
+
+ /* Use a "soft" cursor */
+ t->soft_cursor = TRUE;
+
+ /* Erase with "white space" */
+ t->attr_blank = TERM_WHITE;
+ t->char_blank = ' ';
+
+ /* Hooks */
+ t->xtra_hook = Term_xtra_xaw;
+ t->curs_hook = Term_curs_xaw;
+ t->wipe_hook = Term_wipe_xaw;
+ t->text_hook = Term_text_xaw;
+
+ /* Save the data */
+ t->data = td;
+
+ /* Register the keypress event handler */
+ XtAddEventHandler((Widget)td->widget, KeyPressMask,
+ False, (XtEventHandler) handle_event, td);
+
+ /* Redraw callback */
+ XtAddCallback((Widget)td->widget, XtNredrawCallback,
+ react_redraw, td);
+
+ /* Realize the widget */
+ XtRealizeWidget(parent);
+
+ /* Make it visible */
+ XtPopup(parent, XtGrabNone);
+
+ /* Activate (important) */
+ Term_activate(t);
+
+ Resize_term(td->widget);
+
+ return 0;
+}
+
+
+/*
+ * Initialization function for an X Athena Widget module to Angband
+ *
+ * We should accept "-d<dpy>" requests in the "argv" array. XXX XXX XXX
+ */
+errr init_xaw(int argc, char *argv[])
+{
+ int i;
+ Widget topLevel;
+ Display *dpy;
+
+ cptr dpy_name = "";
+
+
+#ifdef USE_GRAPHICS
+
+ char filename[1024];
+
+ int pict_wid = 0;
+ int pict_hgt = 0;
+ bool_ force_old_graphics = FALSE;
+
+ char *TmpData;
+
+#endif /* USE_GRAPHICS */
+
+ /* Parse args */
+ for (i = 1; i < argc; i++)
+ {
+ if (prefix(argv[i], "-d"))
+ {
+ dpy_name = &argv[i][2];
+ continue;
+ }
+
+#ifdef USE_GRAPHICS
+
+ if (prefix(argv[i], "-s"))
+ {
+ smoothRescaling = FALSE;
+ continue;
+ }
+
+ if (prefix(argv[i], "-o"))
+ {
+ force_old_graphics = TRUE;
+ continue;
+ }
+
+#endif /* USE_GRAPHICS */
+
+ if (prefix(argv[i], "-n"))
+ {
+ num_term = atoi(&argv[i][2]);
+ if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
+ else if (num_term < 1) num_term = 1;
+ continue;
+ }
+
+ plog_fmt("Ignoring option: %s", argv[i]);
+ }
+
+
+ /* Attempt to open the local display */
+ dpy = XOpenDisplay(dpy_name);
+
+ /* Failure -- assume no X11 available */
+ if (!dpy) return ( -1);
+
+ /* Close the local display */
+ XCloseDisplay(dpy);
+
+
+#ifdef USE_XAW_LANG
+
+ /* Support locale processing */
+ XtSetLanguageProc(NULL, NULL, NULL);
+
+#endif /* USE_XAW_LANG */
+
+
+ /* Initialize the toolkit */
+ topLevel = XtAppInitialize(&appcon, "Angband", NULL, 0, &argc, argv,
+ fallback, NULL, 0);
+
+ XSetIOErrorHandler(x_io_error_handler);
+
+ /* Initialize the windows */
+ for (i = 0; i < num_term; i++)
+ {
+ term_data *td = &data[i];
+
+ term_data_init(td, topLevel, 1024, termNames[i],
+ (i == 0) ? specialArgs : defaultArgs,
+ TERM_FALLBACKS, i);
+
+ angband_term[i] = Term;
+ }
+
+ /* Activate the "Angband" window screen */
+ Term_activate(&data[0].t);
+
+ /* Raise the "Angband" window */
+ term_raise(&data[0]);
+
+
+#ifdef USE_GRAPHICS
+
+ /* Try graphics */
+ if (arg_graphics)
+ {
+ /* Try the "16x16.bmp" file */
+ path_build(filename, 1024, ANGBAND_DIR_XTRA, "graf/16x16.bmp");
+
+ /* Use the "16x16.bmp" file if it exists */
+ if (!force_old_graphics &&
+ (0 == fd_close(fd_open(filename, O_RDONLY))))
+ {
+ /* Use graphics */
+ use_graphics = TRUE;
+
+ pict_wid = pict_hgt = 16;
+
+ ANGBAND_GRAF = "new";
+ }
+ else
+ {
+ /* Try the "8x8.bmp" file */
+ path_build(filename, 1024, ANGBAND_DIR_XTRA, "graf/8x8.bmp");
+
+ /* Use the "8x8.bmp" file if it exists */
+ if (0 == fd_close(fd_open(filename, O_RDONLY)))
+ {
+ /* Use graphics */
+ use_graphics = TRUE;
+
+ pict_wid = pict_hgt = 8;
+
+ ANGBAND_GRAF = "old";
+ }
+ }
+ }
+
+ /* Load graphics */
+ if (use_graphics)
+ {
+ /* Hack -- Get the Display */
+ term_data *td = &data[0];
+ Widget widget = (Widget)(td->widget);
+ Display *dpy = XtDisplay(widget);
+
+ XImage *tiles_raw;
+
+ /* Load the graphical tiles */
+ tiles_raw = ReadBMP(dpy, filename);
+
+ /* Initialize the windows */
+ for (i = 0; i < num_term; i++)
+ {
+ term_data *td = &data[i];
+
+ term *t = &td->t;
+
+ t->pict_hook = Term_pict_xaw;
+
+ t->higher_pict = TRUE;
+
+ /* Resize tiles */
+ td->widget->angband.tiles =
+ ResizeImage(dpy, tiles_raw,
+ pict_wid, pict_hgt,
+ td->widget->angband.fontwidth,
+ td->widget->angband.fontheight);
+ }
+
+ /* Initialize the transparency temp storage*/
+ for (i = 0; i < num_term; i++)
+ {
+ term_data *td = &data[i];
+ int ii, jj;
+ int depth = DefaultDepth(dpy, DefaultScreen(dpy));
+ Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
+ int total;
+
+
+ /* Determine total bytes needed for image */
+ ii = 1;
+ jj = (depth - 1) >> 2;
+ while (jj >>= 1) ii <<= 1;
+ total = td->widget->angband.fontwidth *
+ td->widget->angband.fontheight * ii;
+
+
+ TmpData = (char *)malloc(total);
+
+ td->widget->angband.TmpImage = XCreateImage(dpy,
+ visual, depth,
+ ZPixmap, 0, TmpData,
+ td->widget->angband.fontwidth,
+ td->widget->angband.fontheight, 8, 0);
+
+ }
+
+
+ /* Free tiles_raw? XXX XXX */
+ }
+
+#endif /* USE_GRAPHICS */
+
+ /* Success */
+ return (0);
+}
+
+#endif /* USE_XAW */
+
diff --git a/src/main-xxx.c b/src/main-xxx.c
new file mode 100644
index 00000000..c80f01f0
--- /dev/null
+++ b/src/main-xxx.c
@@ -0,0 +1,785 @@
+/* File: main-xxx.c */
+
+/* Purpose: Sample visual module for Angband 2.8.1 */
+
+/*
+ * This file written by "Ben Harrison (benh@phial.com)".
+ *
+ * This file is intended to show one way to build a "visual module"
+ * for Angband to allow it to work with a new system. It does not
+ * actually work, but if the code near "XXX XXX XXX" comments were
+ * replaced with functional code, then it probably would.
+ *
+ * See "z-term.c" for info on the concept of the "generic terminal",
+ * and for more comments about what this file must supply.
+ *
+ * There are two basic ways to port Angband to a new system. The
+ * first involves modifying the "main-gcu.c" and/or "main-x11.c"
+ * files to support some version of "curses" and/or "X11" on your
+ * machine, and to compile with the "USE_GCU" and/or "USE_X11"
+ * compilation flags defined. The second involves creating a
+ * new "main-xxx.c" file, based on this sample file (or on any
+ * existing "main-xxx.c" file), and comes in two flavors, based
+ * on whether it contains a "main()" function (as in "main-mac.c"
+ * and "main-win.c") or not (as in "main-gcu.c" or "main-x11.c").
+ *
+ * If the "main-xxx.c" file includes its own "main()" function,
+ * then you should NOT link in the "main.c" file, and your "main()"
+ * function must process any command line arguments, initialize the
+ * "visual system", and call "play_game()" with appropriate arguments.
+ *
+ * If the "main-xxx.c" file does not include its own "main()"
+ * function, then you must add some code to "main.c" which, if
+ * the appropriate "USE_XXX" compilation flag is defined, will
+ * attempt to call the "init_xxx()" function in the "main-xxx.c"
+ * file, which should initialize the "visual system" and return
+ * zero if it was successful. The "main()" function in "main.c"
+ * will take care of processing command line arguments and then
+ * calling "play_game()" with appropriate arguments.
+ *
+ * Note that the "util.c" file often contains functions which must
+ * be modified in small ways for various platforms, even if you are
+ * able to use the existing "main-gcu.c" and/or "main-x11.c" files,
+ * in particular, the "file handling" functions may not work on all
+ * systems.
+ *
+ * When you complete a port to a new system, you should email any
+ * newly created files, and any changes made to existing files,
+ * including "h-config.h", "config.h", and any of the "Makefile"
+ * files, to "benh@phial.com" for inclusion in the next version.
+ *
+ * Try to stick to a "three letter" naming scheme for "main-xxx.c"
+ * and "Makefile.xxx" and such for consistency and simplicity.
+ */
+
+
+#include "angband.h"
+
+
+#ifdef USE_XXX
+
+
+/*
+ * Extra data to associate with each "window"
+ *
+ * Each "window" is represented by a "term_data" structure, which
+ * contains a "term" structure, which contains a pointer (t->data)
+ * back to the term_data structure.
+ */
+
+typedef struct term_data term_data;
+
+struct term_data
+{
+ term t;
+
+ /* Other fields if needed XXX XXX XXX */
+};
+
+
+
+/*
+ * Number of "term_data" structures to support XXX XXX XXX
+ *
+ * You MUST support at least one "term_data" structure, and the
+ * game will currently use up to eight "term_data" structures if
+ * they are available.
+ *
+ * If only one "term_data" structure is supported, then a lot of
+ * the things that would normally go into a "term_data" structure
+ * could be made into global variables instead.
+ */
+#define MAX_TERM_DATA 1
+
+
+/*
+ * An array of "term_data" structures, one for each "sub-window"
+ */
+static term_data data[MAX_TERM_DATA];
+
+
+#if 0 /* Fix the syntax below XXX XXX XXX */
+
+/*
+ * The "color" array for the visual module XXX XXX XXX
+ *
+ * This table should be used in whetever way is necessary to
+ * convert the Angband Color Indexes into the proper "color data"
+ * for the visual system. On the Macintosh, these are arrays of
+ * three shorts, on the IBM, these are combinations of the eight
+ * basic color codes with optional "bright" bits, on X11, these
+ * are actual "pixel" codes extracted from another table which
+ * contains textual color names.
+ *
+ * The Angband Color Set (0 to 15):
+ * Black, White, Slate, Orange, Red, Blue, Green, Umber
+ * D-Gray, L-Gray, Violet, Yellow, L-Red, L-Blue, L-Green, L-Umber
+ *
+ * Colors 8 to 15 are basically "enhanced" versions of Colors 0 to 7.
+ *
+ * As decribed in one of the header files, in a perfect world, the
+ * colors below should fit a nice clean "quartered" specification
+ * in RGB codes, but this must often be Gamma Corrected. The 1/4
+ * parts of each Red,Green,Blue are shown in the comments below,
+ * again, these values are *before* gamma correction.
+ */
+static local_color_data_type color_data[16] =
+{
+ /* XXX XXX XXX 0,0,0 */, /* TERM_DARK */
+ /* XXX XXX XXX 4,4,4 */, /* TERM_WHITE */
+ /* XXX XXX XXX 2,2,2 */, /* TERM_SLATE */
+ /* XXX XXX XXX 4,2,0 */, /* TERM_ORANGE */
+ /* XXX XXX XXX 3,0,0 */, /* TERM_RED */
+ /* XXX XXX XXX 0,2,1 */, /* TERM_GREEN */
+ /* XXX XXX XXX 0,0,4 */, /* TERM_BLUE */
+ /* XXX XXX XXX 2,1,0 */, /* TERM_UMBER */
+ /* XXX XXX XXX 1,1,1 */, /* TERM_L_DARK */
+ /* XXX XXX XXX 3,3,3 */, /* TERM_L_WHITE */
+ /* XXX XXX XXX 4,0,4 */, /* TERM_VIOLET */
+ /* XXX XXX XXX 4,4,0 */, /* TERM_YELLOW */
+ /* XXX XXX XXX 4,0,0 */, /* TERM_L_RED */
+ /* XXX XXX XXX 0,4,0 */, /* TERM_L_GREEN */
+ /* XXX XXX XXX 0,4,4 */, /* TERM_L_BLUE */
+ /* XXX XXX XXX 3,2,1 */ /* TERM_L_UMBER */
+};
+
+#endif
+
+
+
+/*** Function hooks needed by "Term" ***/
+
+
+/*
+ * Init a new "term"
+ *
+ * This function should do whatever is necessary to prepare a new "term"
+ * for use by the "term.c" package. This may include clearing the window,
+ * preparing the cursor, setting the font/colors, etc. Usually, this
+ * function does nothing, and the "init_xxx()" function does it all.
+ */
+static void Term_init_xxx(term *t)
+{
+ term_data *td = (term_data*)(t->data);
+
+ /* XXX XXX XXX */
+}
+
+
+
+/*
+ * Nuke an old "term"
+ *
+ * This function is called when an old "term" is no longer needed. It should
+ * do whatever is needed to clean up before the program exits, such as wiping
+ * the screen, restoring the cursor, fixing the font, etc. Often this function
+ * does nothing and lets the operating system clean up when the program quits.
+ */
+static void Term_nuke_xxx(term *t)
+{
+ term_data *td = (term_data*)(t->data);
+
+ /* XXX XXX XXX */
+}
+
+
+
+/*
+ * Do a "user action" on the current "term"
+ *
+ * This function allows the visual module to do implementation defined
+ * things when the user activates the "system defined command" command.
+ *
+ * This function is normally not used.
+ *
+ * In general, this function should return zero if the action is successfully
+ * handled, and non-zero if the action is unknown or incorrectly handled.
+ */
+static errr Term_user_xxx(int n)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* XXX XXX XXX */
+
+ /* Unknown */
+ return (1);
+}
+
+
+/*
+ * Do a "special thing" to the current "term"
+ *
+ * This function must react to a large number of possible arguments, each
+ * corresponding to a different "action request" by the "z-term.c" package,
+ * or by the application itself.
+ *
+ * The "action type" is specified by the first argument, which must be a
+ * constant of the form "TERM_XTRA_*" as given in "term.h", and the second
+ * argument specifies the "information" for that argument, if any, and will
+ * vary according to the first argument.
+ *
+ * In general, this function should return zero if the action is successfully
+ * handled, and non-zero if the action is unknown or incorrectly handled.
+ */
+static errr Term_xtra_xxx(int n, int v)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* Analyze */
+ switch (n)
+ {
+ case TERM_XTRA_EVENT:
+ {
+ /*
+ * Process some pending events XXX XXX XXX
+ *
+ * Wait for at least one event if "v" is non-zero
+ * otherwise, if no events are ready, return at once.
+ * When "keypress" events are encountered, the "ascii"
+ * value corresponding to the key should be sent to the
+ * "Term_keypress()" function. Certain "bizarre" keys,
+ * such as function keys or arrow keys, may send special
+ * sequences of characters, such as control-underscore,
+ * plus letters corresponding to modifier keys, plus an
+ * underscore, plus carriage return, which can be used by
+ * the main program for "macro" triggers. This action
+ * should handle as many events as is efficiently possible
+ * but is only required to handle a single event, and then
+ * only if one is ready or "v" is true.
+ *
+ * This action is required.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_FLUSH:
+ {
+ /*
+ * Flush all pending events XXX XXX XXX
+ *
+ * This action should handle all events waiting on the
+ * queue, optionally discarding all "keypress" events,
+ * since they will be discarded anyway in "z-term.c".
+ *
+ * This action is required, but may not be "essential".
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_CLEAR:
+ {
+ /*
+ * Clear the entire window XXX XXX XXX
+ *
+ * This action should clear the entire window, and redraw
+ * any "borders" or other "graphic" aspects of the window.
+ *
+ * This action is required.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_SHAPE:
+ {
+ /*
+ * Set the cursor visibility XXX XXX XXX
+ *
+ * This action should change the visibility of the cursor,
+ * if possible, to the requested value (0=off, 1=on)
+ *
+ * This action is optional, but can improve both the
+ * efficiency (and attractiveness) of the program.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_FROSH:
+ {
+ /*
+ * Flush a row of output XXX XXX XXX
+ *
+ * This action should make sure that row "v" of the "output"
+ * to the window will actually appear on the window.
+ *
+ * This action is optional, assuming that "Term_text_xxx()"
+ * (and similar functions) draw directly to the screen, or
+ * that the "TERM_XTRA_FRESH" entry below takes care of any
+ * necessary flushing issues.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_FRESH:
+ {
+ /*
+ * Flush output XXX XXX XXX
+ *
+ * This action should make sure that all "output" to the
+ * window will actually appear on the window.
+ *
+ * This action is optional, assuming that "Term_text_xxx()"
+ * (and similar functions) draw directly to the screen, or
+ * that the "TERM_XTRA_FROSH" entry above takes care of any
+ * necessary flushing issues.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_NOISE:
+ {
+ /*
+ * Make a noise XXX XXX XXX
+ *
+ * This action should produce a "beep" noise.
+ *
+ * This action is optional, but convenient.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_SOUND:
+ {
+ /*
+ * Make a sound XXX XXX XXX
+ *
+ * This action should produce sound number "v", where the
+ * "name" of that sound is "sound_names[v]". This method
+ * is still under construction.
+ *
+ * This action is optional, and not very important.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_BORED:
+ {
+ /*
+ * Handle random events when bored XXX XXX XXX
+ *
+ * This action is optional, and normally not important
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_REACT:
+ {
+ /*
+ * React to global changes XXX XXX XXX
+ *
+ * For example, this action can be used to react to
+ * changes in the global "color_table[256][4]" array.
+ *
+ * This action is optional, but can be very useful for
+ * handling "color changes" and the "arg_sound" and/or
+ * "arg_graphics" options.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_ALIVE:
+ {
+ /*
+ * Change the "hard" level XXX XXX XXX
+ *
+ * This action is used if the program changes "aliveness"
+ * by being either "suspended" (v=0) or "resumed" (v=1)
+ * This action is optional, unless the computer uses the
+ * same "physical screen" for multiple programs, in which
+ * case this action should clean up to let other programs
+ * use the screen, or resume from such a cleaned up state.
+ *
+ * This action is currently only used by "main-gcu.c",
+ * on UNIX machines, to allow proper "suspending".
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_LEVEL:
+ {
+ /*
+ * Change the "soft" level XXX XXX XXX
+ *
+ * This action is used when the term window changes "activation"
+ * either by becoming "inactive" (v=0) or "active" (v=1)
+ *
+ * This action can be used to do things like activate the proper
+ * font / drawing mode for the newly active term window. This
+ * action should NOT change which window has the "focus", which
+ * window is "raised", or anything like that.
+ *
+ * This action is optional if all the other things which depend
+ * on what term is active handle activation themself, or if only
+ * one "term_data" structure is supported by this file.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_DELAY:
+ {
+ /*
+ * Delay for some milliseconds XXX XXX XXX
+ *
+ * This action is useful for proper "timing" of certain
+ * visual effects, such as breath attacks.
+ *
+ * This action is optional, but may be required by this file,
+ * especially if special "macro sequences" must be supported.
+ */
+
+ return (0);
+ }
+
+ case TERM_XTRA_GET_DELAY:
+ {
+ /*
+ * Get Delay of some milliseconds XXX XXX XXX
+ * place the result in Term_xtra_long
+ *
+ * This action is useful for proper "timing" of certain
+ * visual effects, such as recording cmovies.
+ *
+ * This action is optional, but cmovies wont perform
+ * good without it
+ */
+
+ return (0);
+ }
+ }
+
+ /* Unknown or Unhandled action */
+ return (1);
+}
+
+
+/*
+ * Display the cursor
+ *
+ * This routine should display the cursor at the given location
+ * (x,y) in some manner. On some machines this involves actually
+ * moving the physical cursor, on others it involves drawing a fake
+ * cursor in some form of graphics mode. Note the "soft_cursor"
+ * flag which tells "z-term.c" to treat the "cursor" as a "visual"
+ * thing and not as a "hardware" cursor.
+ *
+ * You may assume "valid" input if the window is properly sized.
+ *
+ * You may use the "Term_grab(x, y, &a, &c)" function, if needed,
+ * to determine what attr/char should be "under" the new cursor,
+ * for "inverting" purposes or whatever.
+ */
+static errr Term_curs_xxx(int x, int y)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* XXX XXX XXX */
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Erase some characters
+ *
+ * This function should erase "n" characters starting at (x,y).
+ *
+ * You may assume "valid" input if the window is properly sized.
+ */
+static errr Term_wipe_xxx(int x, int y, int n)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* XXX XXX XXX */
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Draw some text on the screen
+ *
+ * This function should actually display an array of characters
+ * starting at the given location, using the given "attribute",
+ * and using the given string of characters, which contains
+ * exactly "n" characters and which is NOT null-terminated.
+ *
+ * You may assume "valid" input if the window is properly sized.
+ *
+ * You must be sure that the string, when written, erases anything
+ * (including any visual cursor) that used to be where the text is
+ * drawn. On many machines this happens automatically, on others,
+ * you must first call "Term_wipe_xxx()" to clear the area.
+ *
+ * In color environments, you should activate the color contained
+ * in "color_data[a & 0x0F]", if needed, before drawing anything.
+ *
+ * You may ignore the "attribute" if you are only supporting a
+ * monochrome environment, since this routine is normally never
+ * called to display "black" (invisible) text, including the
+ * default "spaces", and all other colors should be drawn in
+ * the "normal" color in a monochrome environment.
+ *
+ * Note that if you have changed the "attr_blank" to something
+ * which is not black, then this function must be able to draw
+ * the resulting "blank" correctly.
+ *
+ * Note that this function must correctly handle "black" text if
+ * the "always_text" flag is set, if this flag is not set, all the
+ * "black" text will be handled by the "Term_wipe_xxx()" hook.
+ */
+static errr Term_text_xxx(int x, int y, int n, byte a, const char *cp)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* XXX XXX XXX */
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Draw some attr/char pairs on the screen
+ *
+ * This routine should display the given "n" attr/char pairs at
+ * the given location (x,y). This function is only used if one
+ * of the flags "always_pict" or "higher_pict" is defined.
+ *
+ * You must be sure that the attr/char pairs, when displayed, will
+ * erase anything (including any visual cursor) that used to be at
+ * the given location. On many machines this is automatic, but on
+ * others, you must first call "Term_wipe_xxx(x, y, 1)".
+ *
+ * With the "higher_pict" flag, this function can be used to allow
+ * the display of "pseudo-graphic" pictures, for example, by using
+ * the attr/char pair as an encoded index into a pixmap of special
+ * "pictures".
+ *
+ * With the "always_pict" flag, this function can be used to force
+ * every attr/char pair to be drawn by this function, which can be
+ * very useful if this file can optimize its own display calls.
+ *
+ * This function is often associated with the "arg_graphics" flag.
+ *
+ * This function is only used if one of the "higher_pict" and/or
+ * "always_pict" flags are set.
+ */
+static errr Term_pict_xxx(int x, int y, int n, const byte *ap, const char *cp)
+{
+ term_data *td = (term_data*)(Term->data);
+
+ /* XXX XXX XXX */
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*** Internal Functions ***/
+
+
+/*
+ * Instantiate a "term_data" structure
+ *
+ * This is one way to prepare the "term_data" structures and to
+ * "link" the various informational pieces together.
+ *
+ * This function assumes that every window should be 80x24 in size
+ * (the standard size) and should be able to queue 256 characters.
+ * Technically, only the "main screen window" needs to queue any
+ * characters, but this method is simple. One way to allow some
+ * variation is to add fields to the "term_data" structure listing
+ * parameters for that window, initialize them in the "init_xxx()"
+ * function, and then use them in the code below.
+ *
+ * Note that "activation" calls the "Term_init_xxx()" hook for
+ * the "term" structure, if needed.
+ */
+static void term_data_link(int i)
+{
+ term_data *td = &data[i];
+
+ /* Initialize the term */
+ term_init(td->t, 80, 24, 256);
+
+ /* Choose "soft" or "hard" cursor XXX XXX XXX */
+ /* A "soft" cursor must be explicitly "drawn" by the program */
+ /* while a "hard" cursor has some "physical" existance and is */
+ /* moved whenever text is drawn on the screen. See "term.c". */
+ /* td->t->soft_cursor = TRUE; */
+
+ /* Avoid the "corner" of the window XXX XXX XXX */
+ /* td->t->icky_corner = TRUE; */
+
+ /* Use "Term_pict()" for all attr/char pairs XXX XXX XXX */
+ /* See the "Term_pict_xxx()" function above. */
+ /* td->t->always_pict = TRUE; */
+
+ /* Use "Term_pict()" for some attr/char pairs XXX XXX XXX */
+ /* See the "Term_pict_xxx()" function above. */
+ /* td->t->higher_pict = TRUE; */
+
+ /* Use "Term_text()" even for "black" text XXX XXX XXX */
+ /* See the "Term_text_xxx()" function above. */
+ /* td->t->always_text = TRUE; */
+
+ /* Ignore the "TERM_XTRA_BORED" action XXX XXX XXX */
+ /* This may make things slightly more efficient. */
+ /* td->t->never_bored = TRUE; */
+
+ /* Ignore the "TERM_XTRA_FROSH" action XXX XXX XXX */
+ /* This may make things slightly more efficient. */
+ /* td->t->never_frosh = TRUE; */
+
+ /* Erase with "white space" XXX XXX XXX */
+ /* td->t->attr_blank = TERM_WHITE; */
+ /* td->t->char_blank = ' '; */
+
+ /* Prepare the init/nuke hooks */
+ td->t->init_hook = Term_init_xxx;
+ td->t->nuke_hook = Term_nuke_xxx;
+
+ /* Prepare the template hooks */
+ td->t->user_hook = Term_user_xxx;
+ td->t->xtra_hook = Term_xtra_xxx;
+ td->t->curs_hook = Term_curs_xxx;
+ td->t->wipe_hook = Term_wipe_xxx;
+ td->t->text_hook = Term_text_xxx;
+ td->t->pict_hook = Term_pict_xxx;
+
+ /* Remember where we came from */
+ td->t->data = (vptr)(td);
+
+ /* Activate it */
+ Term_activate(td->t);
+
+ /* Global pointer */
+ ang_term[i] = td->t;
+}
+
+
+
+/*
+ * Initialization function
+ */
+errr init_xxx(void)
+{
+ /* Initialize globals XXX XXX XXX */
+
+ /* Initialize "term_data" structures XXX XXX XXX */
+
+ /* Create windows (backwards!) */
+ for (i = TERM_DATA_MAX - 1; i >= 0; i--)
+ {
+ /* Link */
+ term_data_link(i);
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+#ifdef INTERNAL_MAIN
+
+
+/*
+ * Some special machines need their own "main()" function, which they
+ * can provide here, making sure NOT to compile the "main.c" file.
+ *
+ * These systems usually have some form of "event loop", run forever
+ * as the last step of "main()", which handles things like menus and
+ * window movement, and calls "play_game(FALSE)" to load a game after
+ * initializing "savefile" to a filename, or "play_game(TRUE)" to make
+ * a new game. The event loop would also be triggered by "Term_xtra()"
+ * (the TERM_XTRA_EVENT action), in which case the event loop would not
+ * actually "loop", but would run once and return.
+ */
+
+
+/*
+ * An event handler XXX XXX XXX
+ *
+ * You may need an event handler, which can be used by both
+ * by the "TERM_XTRA_BORED" and "TERM_XTRA_EVENT" entries in
+ * the "Term_xtra_xxx()" function, and also to wait for the
+ * user to perform whatever user-interface operation is needed
+ * to request the start of a new game or the loading of an old
+ * game, both of which should launch the "play_game()" function.
+ */
+static bool_ CheckEvents(bool_ wait)
+{
+ /* XXX XXX XXX */
+
+ return (0);
+}
+
+
+/*
+ * Init some stuff
+ *
+ * This function is used to keep the "path" variable off the stack.
+ */
+static void init_stuff(void)
+{
+ char path[1024];
+
+ /* Prepare the path XXX XXX XXX */
+ /* This must in some way prepare the "path" variable */
+ /* so that it points at the "lib" directory. Every */
+ /* machine handles this in a different way... */
+ strcpy(path, "XXX XXX XXX");
+
+ /* Prepare the filepaths */
+ init_file_paths(path);
+}
+
+
+/*
+ * Main function
+ *
+ * This function must do a lot of stuff.
+ */
+int main(int argc, char *argv[])
+{
+ /* Initialize the machine itself XXX XXX XXX */
+
+ /* Process command line arguments XXX XXX XXX */
+
+ /* Initialize the windows */
+ if (init_xxx()) quit("Oops!");
+
+ /* XXX XXX XXX */
+ ANGBAND_SYS = "xxx";
+
+ /* Initialize some stuff */
+ init_stuff();
+
+ /* Initialize */
+ init_angband * /
+
+ /* Allow auto-startup XXX XXX XXX */
+
+ /* Event loop forever XXX XXX XXX */
+ while (TRUE) CheckEvents(TRUE);
+}
+
+
+#endif /* INTERNAL_MAIN */
+
+
+#endif /* USE_XXX */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 00000000..48ab3f04
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,691 @@
+/* File: main.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison, and others
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+#include "angband.h"
+
+
+
+/*
+ * Some machines have a "main()" function in their "main-xxx.c" file,
+ * all the others use this file for their "main()" function.
+ */
+
+
+#if !defined(MACINTOSH) && !defined(WINDOWS)
+
+
+/*
+ * A hook for "quit()".
+ *
+ * Close down, then fall back into "quit()".
+ */
+static void quit_hook(cptr s)
+{
+ int j;
+
+ /* Scan windows */
+ for (j = 8 - 1; j >= 0; j--)
+ {
+ /* Unused */
+ if (!angband_term[j]) continue;
+
+ /* Nuke it */
+ term_nuke(angband_term[j]);
+ }
+}
+
+
+
+/*
+ * Check and create if needed the directory dirpath
+ */
+bool_ private_check_user_directory(cptr dirpath)
+{
+ /* Is this used anywhere else in *bands? */
+ struct stat stat_buf;
+
+ int ret;
+
+ /* See if it already exists */
+ ret = stat(dirpath, &stat_buf);
+
+ /* It does */
+ if (ret == 0)
+ {
+ /* Now we see if it's a directory */
+ if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) return (TRUE);
+
+ /*
+ * Something prevents us from create a directory with
+ * the same pathname
+ */
+ return (FALSE);
+ }
+
+ /* No - this maybe the first time. Try to create a directory */
+ else
+ {
+ /* Create the ~/.ToME directory */
+ ret = mkdir(dirpath, 0700);
+
+ /* An error occured */
+ if (ret == -1) return (FALSE);
+
+ /* Success */
+ return (TRUE);
+ }
+}
+
+/*
+ * Check existence of ".ToME/" directory in the user's
+ * home directory or try to create it if it doesn't exist.
+ * Returns FALSE if all the attempts fail.
+ */
+static bool_ check_create_user_dir(void)
+{
+ char dirpath[1024];
+ char versionpath[1024];
+ char savepath[1024];
+
+ /* Get an absolute path from the filename */
+ path_parse(dirpath, 1024, PRIVATE_USER_PATH);
+ strcpy(versionpath, dirpath);
+ strcat(versionpath, USER_PATH_VERSION);
+ strcpy(savepath, versionpath);
+ strcat(savepath, "/save");
+
+ return private_check_user_directory(dirpath) && private_check_user_directory(versionpath) && private_check_user_directory(savepath);
+}
+
+
+/*
+ * Initialize and verify the file paths, and the score file.
+ *
+ * Use the ANGBAND_PATH environment var if possible, else use
+ * DEFAULT_PATH, and in either case, branch off appropriately.
+ *
+ * First, we'll look for the ANGBAND_PATH environment variable,
+ * and then look for the files in there. If that doesn't work,
+ * we'll try the DEFAULT_PATH constant. So be sure that one of
+ * these two things works...
+ *
+ * We must ensure that the path ends with "PATH_SEP" if needed,
+ * since the "init_file_paths()" function will simply append the
+ * relevant "sub-directory names" to the given path.
+ */
+static void init_stuff(void)
+{
+ char path[1024];
+
+ cptr tail;
+
+ /* Get the environment variable */
+ tail = getenv("TOME_PATH");
+
+ /* Use the angband_path, or a default */
+ strcpy(path, tail ? tail : DEFAULT_PATH);
+
+ /* Hack -- Add a path separator (only if needed) */
+ if (!suffix(path, PATH_SEP)) strcat(path, PATH_SEP);
+
+ /* Initialize */
+ init_file_paths(path);
+}
+
+
+
+/*
+ * Handle a "-d<what>=<path>" option
+ *
+ * The "<what>" can be any string starting with the same letter as the
+ * name of a subdirectory of the "lib" folder (i.e. "i" or "info").
+ *
+ * The "<path>" can be any legal path for the given system, and should
+ * not end in any special path separator (i.e. "/tmp" or "~/.ang-info").
+ */
+static void change_path(cptr info)
+{
+ cptr s;
+
+ /* Find equal sign */
+ s = strchr(info, '=');
+
+ /* Verify equal sign */
+ if (!s) quit_fmt("Try '-d<what>=<path>' not '-d%s'", info);
+
+ /* Analyze */
+ switch (tolower(info[0]))
+ {
+ case 'a':
+ {
+ string_free(ANGBAND_DIR_APEX);
+ ANGBAND_DIR_APEX = string_make(s + 1);
+ break;
+ }
+
+ case 'f':
+ {
+ string_free(ANGBAND_DIR_FILE);
+ ANGBAND_DIR_FILE = string_make(s + 1);
+ break;
+ }
+
+ case 'h':
+ {
+ string_free(ANGBAND_DIR_HELP);
+ ANGBAND_DIR_HELP = string_make(s + 1);
+ break;
+ }
+
+ case 'i':
+ {
+ string_free(ANGBAND_DIR_INFO);
+ ANGBAND_DIR_INFO = string_make(s + 1);
+ break;
+ }
+
+ case 'u':
+ {
+ string_free(ANGBAND_DIR_USER);
+ ANGBAND_DIR_USER = string_make(s + 1);
+ break;
+ }
+
+ case 'x':
+ {
+ string_free(ANGBAND_DIR_XTRA);
+ ANGBAND_DIR_XTRA = string_make(s + 1);
+ break;
+ }
+
+ case 'd':
+ {
+ string_free(ANGBAND_DIR_DATA);
+ ANGBAND_DIR_DATA = string_make(s + 1);
+ break;
+ }
+
+ case 'e':
+ {
+ string_free(ANGBAND_DIR_EDIT);
+ ANGBAND_DIR_EDIT = string_make(s + 1);
+ break;
+ }
+
+ case 's':
+ {
+ string_free(ANGBAND_DIR_SAVE);
+ ANGBAND_DIR_SAVE = string_make(s + 1);
+ break;
+ }
+
+ default:
+ {
+ quit_fmt("Bad semantics in '-d%s'", info);
+ }
+ }
+}
+
+
+/*
+ * Simple "main" function for multiple platforms.
+ *
+ * Note the special "--" option which terminates the processing of
+ * standard options. All non-standard options (if any) are passed
+ * directly to the "init_xxx()" function.
+ */
+int main(int argc, char *argv[])
+{
+ int i;
+
+ bool_ done = FALSE;
+
+ bool_ new_game = FALSE;
+
+ int show_score = 0;
+
+ cptr mstr = NULL;
+
+ bool_ args = TRUE;
+
+#ifdef CHECK_MEMORY_LEAKS
+ GC_find_leak = 1;
+#endif /* CHECK_MEMORY_LEAKS */
+
+
+ /* Save the "program name" XXX XXX XXX */
+ argv0 = argv[0];
+
+
+ /* Default permissions on files */
+ (void)umask(022);
+
+
+ /* Get the file paths */
+ init_stuff();
+
+
+ /* Get the user id (?) */
+ player_uid = getuid();
+
+ /* Acquire the "user name" as a default player name */
+ user_name(player_name, player_uid);
+
+
+ /*
+ * On multiuser systems, users' private directories are
+ * used to store pref files, chardumps etc.
+ */
+ {
+ bool_ ret;
+
+ /* Create a directory for the user's files */
+ ret = check_create_user_dir();
+
+ /* Oops */
+ if (ret == FALSE) quit("Cannot create directory " PRIVATE_USER_PATH);
+ }
+
+
+
+
+ /* Process the command line arguments */
+ for (i = 1; args && (i < argc); i++)
+ {
+ /* Require proper options */
+ if (argv[i][0] != '-') goto usage;
+
+ /* Analyze option */
+ switch (argv[i][1])
+ {
+ case 'N':
+ case 'n':
+ {
+ new_game = TRUE;
+ break;
+ }
+
+ case 'F':
+ case 'f':
+ {
+ arg_fiddle = TRUE;
+ break;
+ }
+
+ case 'W':
+ case 'w':
+ {
+ arg_wizard = TRUE;
+ break;
+ }
+
+ case 'V':
+ case 'v':
+ {
+ arg_sound = TRUE;
+ break;
+ }
+
+ case 'G':
+ case 'g':
+ {
+ arg_graphics = TRUE;
+ break;
+ }
+
+ case 'R':
+ case 'r':
+ {
+ arg_force_roguelike = TRUE;
+ break;
+ }
+
+ case 'O':
+ case 'o':
+ {
+ arg_force_original = TRUE;
+ break;
+ }
+
+ case 'S':
+ case 's':
+ {
+ show_score = atoi(&argv[i][2]);
+ if (show_score <= 0) show_score = 10;
+ break;
+ }
+
+ case 'u':
+ case 'U':
+ {
+ if (!argv[i][2]) goto usage;
+ strcpy(player_name, &argv[i][2]);
+ strcpy(player_base, &argv[i][2]);
+ no_begin_screen = TRUE;
+ break;
+ }
+
+ case 'm':
+ {
+ if (!argv[i][2]) goto usage;
+ mstr = &argv[i][2];
+ break;
+ }
+
+ case 'M':
+ {
+ if (!argv[i][2]) goto usage;
+ force_module = string_make(&argv[i][2]);
+ break;
+ }
+
+ case 'h':
+ {
+ goto usage;
+ break;
+ }
+
+ case 'H':
+ {
+ char *s;
+ int j;
+
+ init_lua();
+ for (j = i + 1; j < argc; j++)
+ {
+ s = argv[j];
+
+ while (*s != '.') s++;
+ *s = '\0';
+ s++;
+ txt_to_html("head.aux", "foot.aux", argv[j], s, FALSE, FALSE);
+ }
+
+ return 0;
+ }
+
+ case 'd':
+ case 'D':
+ {
+ change_path(&argv[i][2]);
+ break;
+ }
+
+ case '-':
+ {
+ if (argv[i][2] == 'h' && !strcmp((argv[i] + 2), "help"))
+ goto usage;
+ else
+ {
+ argv[i] = argv[0];
+ argc = argc - i;
+ argv = argv + i;
+ args = FALSE;
+ break;
+ }
+ }
+
+ default:
+usage:
+ {
+ int j;
+
+ /* Dump usage information */
+ for (j = 0; j < argc; j++) printf("%s ", argv[j]);
+ printf("\n");
+ puts("Usage: tome [options] [-- subopts]");
+ puts(" -h This help");
+ puts(" -n Start a new character");
+ puts(" -f Request fiddle mode");
+ puts(" -w Request wizard mode");
+ puts(" -v Request sound mode");
+ puts(" -g Request graphics mode");
+ puts(" -o Request original keyset");
+ puts(" -r Request rogue-like keyset");
+ puts(" -H <list of files> Convert helpfile to html");
+ puts(" -s<num> Show <num> high scores");
+ puts(" -u<who> Use your <who> savefile");
+ puts(" -M<which> Use the <which> module");
+ puts(" -m<sys> Force 'main-<sys>.c' usage");
+ puts(" -d<def> Define a 'lib' dir sub-path");
+
+#ifdef USE_GTK2
+ puts(" -mgtk2 To use GTK2");
+ puts(" -- Sub options");
+ puts(" -- -n# Number of terms to use");
+ puts(" -- -b Turn off software backing store");
+# ifdef USE_GRAPHICS
+ puts(" -- -s Turn off smoothscaling graphics");
+ puts(" -- -o Requests \"old\" graphics");
+ puts(" -- -g Requests \"new\" graphics");
+ puts(" -- -t Enable transparency effect");
+# endif /* USE_GRAPHICS */
+#endif /* USE_GTK2 */
+
+#ifdef USE_XAW
+ puts(" -mxaw To use XAW");
+ puts(" -- Sub options");
+ puts(" -- -n# Number of terms to use");
+ puts(" -- -d<name> Display to use");
+# ifdef USE_GRAPHICS
+ puts(" -- -s Turn off smoothscaling graphics");
+ puts(" -- -o Requests \"old\" graphics");
+# endif /* USE_GRAPHICS */
+#endif /* USE_XAW */
+
+#ifdef USE_X11
+ puts(" -mx11 To use X11");
+ puts(" -- Sub options");
+ puts(" -- -n# Number of terms to use");
+ puts(" -- -d<name> Display to use");
+# ifdef USE_GRAPHICS
+ puts(" -- -s Turn off smoothscaling graphics");
+ puts(" -- -o Requests \"old\" graphics");
+ puts(" -- -b Requests double-width tiles");
+# endif /* USE_GRAPHICS */
+#endif /* USE_X11 */
+
+#ifdef USE_GCU
+ puts(" -mgcu To use curses");
+ puts(" -- Sub options");
+ puts(" -- -b Requests big screen");
+#endif /* USE_GCU */
+
+#ifdef USE_SLA
+ puts(" -msla To use SLang");
+#endif /* USE_SLA */
+
+#ifdef USE_SDL
+ puts(" -msdl To use SDL");
+ puts(" -- Sub options");
+ puts(" -- -n # Number of virtual consoles to use");
+ puts(" -- -g Request new graphics (16x16)");
+ puts(" -- -o Request old graphics (8x8)");
+ puts(" -- -b Requests double-width tiles");
+ puts(" -- -w # Request screen width in pixels");
+ puts(" -- -h # Request screen height in pixels");
+ puts(" -- -bpp # Request screen color depth in bits");
+ puts(" -- -fs Start with full-screen display");
+ puts(" -- -s # Request font size");
+ puts(" -- -f <font> Request true-type font by name");
+#endif /* USE_SDL */
+
+ /* Actually abort the process */
+ quit(NULL);
+ }
+ }
+ }
+
+ /* Hack -- Forget standard args */
+ if (args)
+ {
+ argc = 1;
+ argv[1] = NULL;
+ }
+
+
+ /* Process the player name */
+ process_player_name(TRUE);
+
+
+ /* Install "quit" hook */
+ quit_aux = quit_hook;
+
+
+#ifdef USE_GLU
+ /* Attempt to use the "main-glu.c" support */
+ if (!done && (!mstr || (streq(mstr, "glu"))))
+ {
+ extern errr init_glu(int, char**);
+ if (0 == init_glu(argc, argv))
+ {
+ ANGBAND_SYS = "glu";
+ done = TRUE;
+ }
+ }
+#endif
+
+#ifdef USE_GTK2
+ /* Attempt to use the "main-gtk2.c" support */
+ if (!done && (!mstr || (streq(mstr, "gtk2"))))
+ {
+ extern errr init_gtk2(int, char**);
+ if (0 == init_gtk2(argc, argv))
+ {
+ ANGBAND_SYS = "gtk2";
+ done = TRUE;
+ }
+ }
+#endif
+
+#ifdef USE_GTK
+ /* Attempt to use the "main-gtk.c" support */
+ if (!done && (!mstr || (streq(mstr, "gtk"))))
+ {
+ extern errr init_gtk(int, char**);
+ if (0 == init_gtk(argc, argv))
+ {
+ ANGBAND_SYS = "gtk";
+ done = TRUE;
+ }
+ }
+#endif
+
+#ifdef USE_XAW
+ /* Attempt to use the "main-xaw.c" support */
+ if (!done && (!mstr || (streq(mstr, "xaw"))))
+ {
+ extern errr init_xaw(int, char**);
+ if (0 == init_xaw(argc, argv))
+ {
+ ANGBAND_SYS = "xaw";
+ done = TRUE;
+ }
+ }
+#endif
+
+#ifdef USE_X11
+ /* Attempt to use the "main-x11.c" support */
+ if (!done && (!mstr || (streq(mstr, "x11"))))
+ {
+ extern errr init_x11(int, char**);
+ if (0 == init_x11(argc, argv))
+ {
+ ANGBAND_SYS = "x11";
+ done = TRUE;
+ }
+ }
+#endif
+
+#ifdef USE_GCU
+ /* Attempt to use the "main-gcu.c" support */
+ if (!done && (!mstr || (streq(mstr, "gcu"))))
+ {
+ extern errr init_gcu(int, char**);
+ if (0 == init_gcu(argc, argv))
+ {
+ ANGBAND_SYS = "gcu";
+ done = TRUE;
+ }
+ }
+#endif
+
+#ifdef USE_GLU
+ /* Attempt to use the "main-glu.c" support */
+ if (!done && (!mstr || (streq(mstr, "glu"))))
+ {
+ extern errr init_glu(int, char**);
+ if (0 == init_glu(argc, argv))
+ {
+ ANGBAND_SYS = "glu";
+ done = TRUE;
+ }
+ }
+#endif
+
+
+#ifdef USE_SLA
+ /* Attempt to use the "main-sla.c" support */
+ if (!done && (!mstr || (streq(mstr, "sla"))))
+ {
+ extern errr init_sla(void);
+ if (0 == init_sla())
+ {
+ ANGBAND_SYS = "sla";
+ done = TRUE;
+ }
+ }
+#endif
+
+
+#ifdef USE_SDL
+ /* Attempt to use the "main-sdl.c" support */
+ if (!done && (!mstr || (streq(mstr, "sdl"))))
+ {
+ extern errr init_sdl(int, char**);
+ if (0 == init_sdl(argc, argv))
+ {
+ ANGBAND_SYS = "sdl";
+ done = TRUE;
+ }
+ }
+#endif
+
+ /* Make sure we have a display! */
+ if (!done) quit("Unable to prepare any 'display module'!");
+
+
+ /* Catch nasty signals */
+ signals_init();
+
+ /* Initialize */
+ init_angband();
+
+ /* Hack -- If requested, display scores and quit */
+ if (show_score > 0) display_scores(0, show_score);
+
+ /* Wait for response */
+ pause_line(23);
+
+ /* Play the game */
+ play_game(new_game);
+
+#ifdef CHECK_MEMORY_LEAKS
+ CHECK_LEAKS();
+#endif
+
+ /* Quit */
+ quit(NULL);
+
+ /* Exit */
+ return (0);
+}
+
+#endif
diff --git a/src/melee1.c b/src/melee1.c
new file mode 100644
index 00000000..4e5d3208
--- /dev/null
+++ b/src/melee1.c
@@ -0,0 +1,3065 @@
+/* File: melee1.c */
+
+/* Purpose: Monster attacks */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+
+/*
+ * Critical blow. All hits that do 95% of total possible damage,
+ * and which also do at least 20 damage, or, sometimes, N damage.
+ * This is used only to determine "cuts" and "stuns".
+ */
+static int monster_critical(int dice, int sides, int dam)
+{
+ int max = 0;
+ int total = dice * sides;
+
+ /* Must do at least 95% of perfect */
+ if (dam < total * 19 / 20) return (0);
+
+ /* Weak blows rarely work */
+ if ((dam < 20) && (rand_int(100) >= dam)) return (0);
+
+ /* Perfect damage */
+ if (dam == total) max++;
+
+ /* Super-charge */
+ if (dam >= 20)
+ {
+ while (rand_int(100) < 2) max++;
+ }
+
+ /* Critical damage */
+ if (dam > 45) return (6 + max);
+ if (dam > 33) return (5 + max);
+ if (dam > 25) return (4 + max);
+ if (dam > 18) return (3 + max);
+ if (dam > 11) return (2 + max);
+ return (1 + max);
+}
+
+
+
+
+
+/*
+ * Determine if a monster attack against the player succeeds.
+ * Always miss 5% of the time, Always hit 5% of the time.
+ * Otherwise, match monster power against player armor.
+ */
+static int check_hit(int power, int level)
+{
+ int i, k, ac;
+
+ /* Percentile dice */
+ k = rand_int(100);
+
+ /* Hack -- Always miss or hit */
+ if (k < 10) return (k < 5);
+
+ /* Calculate the "attack quality" */
+ i = (power + (level * 3));
+
+ /* Total armor */
+ ac = p_ptr->ac + p_ptr->to_a;
+
+ /* Power and Level compete against Armor */
+ if ((i > 0) && (randint(i - luck( -10, 10)) > ((ac * 3) / 4))) return (TRUE);
+
+ /* Assume miss */
+ return (FALSE);
+}
+
+
+
+/*
+ * Hack -- possible "insult" messages
+ */
+static cptr desc_insult[] =
+{
+ "insults you!",
+ "insults your mother!",
+ "jumps around you!",
+ "humiliates you!",
+ "defiles you!",
+ "dances around you!",
+ "makes obnoxious gestures!",
+ "pokes you!!!"
+};
+
+
+
+/*
+ * Hack -- possible "insult" messages
+ */
+static cptr desc_moan[] =
+{
+ "seems sad about something.",
+ "asks if you have seen his dogs.",
+ "tells you to get off his land.",
+ "mumbles something about mushrooms.",
+
+ /* Mathilde's sentence */
+ "giggles at you.",
+ "asks you if you want to giggle with her.",
+ "says she is always happy."
+};
+
+
+/*
+ * Get the "power" of an attack of given effect type.
+ */
+int get_attack_power(int effect)
+{
+ switch (effect)
+ {
+ case RBE_HURT:
+ return 60;
+ case RBE_POISON:
+ return 5;
+ case RBE_UN_BONUS:
+ return 20;
+ case RBE_UN_POWER:
+ return 15;
+ case RBE_EAT_GOLD:
+ return 5;
+ case RBE_EAT_ITEM:
+ return 5;
+ case RBE_EAT_FOOD:
+ return 5;
+ case RBE_EAT_LITE:
+ return 5;
+ case RBE_ACID:
+ return 0;
+ case RBE_ELEC:
+ return 10;
+ case RBE_FIRE:
+ return 10;
+ case RBE_COLD:
+ return 10;
+ case RBE_BLIND:
+ return 2;
+ case RBE_CONFUSE:
+ return 10;
+ case RBE_TERRIFY:
+ return 10;
+ case RBE_PARALYZE:
+ return 2;
+ case RBE_LOSE_STR:
+ return 0;
+ case RBE_LOSE_DEX:
+ return 0;
+ case RBE_LOSE_CON:
+ return 0;
+ case RBE_LOSE_INT:
+ return 0;
+ case RBE_LOSE_WIS:
+ return 0;
+ case RBE_LOSE_CHR:
+ return 0;
+ case RBE_LOSE_ALL:
+ return 2;
+ case RBE_SHATTER:
+ return 60;
+ case RBE_EXP_10:
+ return 5;
+ case RBE_EXP_20:
+ return 5;
+ case RBE_EXP_40:
+ return 5;
+ case RBE_EXP_80:
+ return 5;
+ case RBE_DISEASE:
+ return 5;
+ case RBE_TIME:
+ return 5;
+ case RBE_SANITY:
+ return 60;
+ case RBE_HALLU:
+ return 10;
+ case RBE_PARASITE:
+ return 5;
+ case RBE_ABOMINATION:
+ return 30;
+ }
+ /* Unknown effects have no power */
+ return 0;
+}
+
+/*
+ * Attack the player via physical attacks.
+ */
+bool_ carried_make_attack_normal(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ int ap_cnt;
+
+ int k, tmp, ac, rlev;
+ int do_cut, do_stun;
+
+ char ddesc[80] = "your symbiote";
+ cptr sym_name = symbiote_name(TRUE);
+
+ bool_ touched = FALSE, alive = TRUE;
+
+ /* Not allowed to attack */
+ if (r_ptr->flags1 & (RF1_NEVER_BLOW)) return (FALSE);
+
+ /* Total armor */
+ ac = p_ptr->ac + p_ptr->to_a;
+
+ /* Extract the effective monster level */
+ rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1);
+
+ /* Scan through all four blows */
+ for (ap_cnt = 0; ap_cnt < 4; ap_cnt++)
+ {
+ bool_ visible = FALSE;
+ bool_ obvious = FALSE;
+
+ int power = 0;
+ int damage = 0;
+
+ cptr act = NULL;
+
+ /* Extract the attack infomation */
+ int effect = r_ptr->blow[ap_cnt].effect;
+ int method = r_ptr->blow[ap_cnt].method;
+ int d_dice = r_ptr->blow[ap_cnt].d_dice;
+ int d_side = r_ptr->blow[ap_cnt].d_side;
+
+
+ /* Hack -- no more attacks */
+ if (!method) break;
+
+
+ /* Stop if player is dead or gone */
+ if (!alive || death) break;
+
+ /* Handle "leaving" */
+ if (p_ptr->leaving) break;
+
+ /* Extract visibility (before blink) */
+ visible = TRUE;
+
+ /* Extract the attack "power" */
+ power = get_attack_power(effect);
+
+
+ /* Monster hits player */
+ if (!effect || check_hit(power, rlev))
+ {
+ /* Always disturbing */
+ disturb(1, 0);
+
+ /* Hack -- Apply "protection from evil" */
+ if ((p_ptr->protevil > 0) &&
+ (r_ptr->flags3 & (RF3_EVIL)) &&
+ (p_ptr->lev >= rlev) &&
+ ((rand_int(100) + p_ptr->lev) > 50))
+ {
+ /* Remember the Evil-ness */
+ r_ptr->r_flags3 |= (RF3_EVIL);
+
+ /* Message */
+ msg_format("%s is repelled.", sym_name);
+
+ /* Hack -- Next attack */
+ continue;
+ }
+
+ /* Hack -- Apply "protection from good" */
+ if ((p_ptr->protgood > 0) &&
+ (r_ptr->flags3 & (RF3_GOOD)) &&
+ (p_ptr->lev >= rlev) &&
+ ((rand_int(100) + p_ptr->lev) > 50))
+ {
+ /* Remember the Good-ness */
+ r_ptr->r_flags3 |= (RF3_GOOD);
+
+ /* Message */
+ msg_format("%s is repelled.", sym_name);
+
+ /* Hack -- Next attack */
+ continue;
+ }
+
+ /* Assume no cut or stun */
+ do_cut = do_stun = 0;
+
+ /* Describe the attack method */
+ switch (method)
+ {
+ case RBM_HIT:
+ {
+ act = "hits you.";
+ do_cut = do_stun = 1;
+ touched = TRUE;
+ sound(SOUND_HIT);
+ break;
+ }
+
+ case RBM_TOUCH:
+ {
+ act = "touches you.";
+ touched = TRUE;
+ sound(SOUND_TOUCH);
+ break;
+ }
+
+ case RBM_PUNCH:
+ {
+ act = "punches you.";
+ touched = TRUE;
+ do_stun = 1;
+ sound(SOUND_HIT);
+ break;
+ }
+
+ case RBM_KICK:
+ {
+ act = "kicks you.";
+ touched = TRUE;
+ do_stun = 1;
+ sound(SOUND_HIT);
+ break;
+ }
+
+ case RBM_CLAW:
+ {
+ act = "claws you.";
+ touched = TRUE;
+ do_cut = 1;
+ sound(SOUND_CLAW);
+ break;
+ }
+
+ case RBM_BITE:
+ {
+ act = "bites you.";
+ do_cut = 1;
+ touched = TRUE;
+ sound(SOUND_BITE);
+ break;
+ }
+
+ case RBM_STING:
+ {
+ act = "stings you.";
+ touched = TRUE;
+ sound(SOUND_STING);
+ break;
+ }
+
+ case RBM_XXX1:
+ {
+ act = "XXX1's you.";
+ break;
+ }
+
+ case RBM_BUTT:
+ {
+ act = "butts you.";
+ do_stun = 1;
+ touched = TRUE;
+ sound(SOUND_HIT);
+ break;
+ }
+
+ case RBM_CRUSH:
+ {
+ act = "crushes you.";
+ do_stun = 1;
+ touched = TRUE;
+ sound(SOUND_CRUSH);
+ break;
+ }
+
+ case RBM_ENGULF:
+ {
+ act = "engulfs you.";
+ touched = TRUE;
+ sound(SOUND_CRUSH);
+ break;
+ }
+
+ case RBM_CHARGE:
+ {
+ act = "charges you.";
+ touched = TRUE;
+ sound(SOUND_BUY); /* Note! This is "charges", not "charges at". */
+ break;
+ }
+
+ case RBM_CRAWL:
+ {
+ act = "crawls on you.";
+ touched = TRUE;
+ sound(SOUND_SLIME);
+ break;
+ }
+
+ case RBM_DROOL:
+ {
+ act = "drools on you.";
+ sound(SOUND_SLIME);
+ break;
+ }
+
+ case RBM_SPIT:
+ {
+ act = "spits on you.";
+ sound(SOUND_SLIME);
+ break;
+ }
+
+ case RBM_EXPLODE:
+ {
+ act = "explodes.";
+ break;
+ }
+
+ case RBM_GAZE:
+ {
+ act = "gazes at you.";
+ break;
+ }
+
+ case RBM_WAIL:
+ {
+ act = "wails at you.";
+ sound(SOUND_WAIL);
+ break;
+ }
+
+ case RBM_SPORE:
+ {
+ act = "releases spores at you.";
+ sound(SOUND_SLIME);
+ break;
+ }
+
+ case RBM_XXX4:
+ {
+ act = "projects XXX4's at you.";
+ break;
+ }
+
+ case RBM_BEG:
+ {
+ act = "begs you for money.";
+ sound(SOUND_MOAN);
+ break;
+ }
+
+ case RBM_INSULT:
+ {
+ act = desc_insult[rand_int(8)];
+ sound(SOUND_MOAN);
+ break;
+ }
+
+ case RBM_MOAN:
+ {
+ act = desc_moan[rand_int(4)];
+ sound(SOUND_MOAN);
+ break;
+ }
+
+ case RBM_SHOW:
+ {
+ if (randint(3) == 1)
+ act = "sings 'We are a happy family.'";
+ else
+ act = "sings 'I love you, you love me.'";
+ sound(SOUND_SHOW);
+ break;
+ }
+ }
+
+ /* Message */
+ if (act) msg_format("%s %s", sym_name, act);
+
+
+ /* Hack -- assume all attacks are obvious */
+ obvious = TRUE;
+
+ /* Roll out the damage */
+ damage = damroll(d_dice, d_side);
+
+ /* Apply appropriate damage */
+ switch (effect)
+ {
+ case 0:
+ {
+ /* Hack -- Assume obvious */
+ obvious = TRUE;
+
+ /* Hack -- No damage */
+ damage = 0;
+
+ break;
+ }
+
+ case RBE_HURT:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Hack -- Player armor reduces total damage */
+ damage -= (damage * ((ac < 150) ? ac : 150) / 250);
+
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ break;
+ }
+
+ case RBE_ABOMINATION:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Morph, but let mimicry skill have a chance to stop this */
+ if (magik(60 - get_skill(SKILL_MIMICRY)))
+ {
+ /* Message */
+ cmsg_print(TERM_VIOLET, "You feel the dark powers twisting your body!");
+
+ set_mimic(damage, resolve_mimic_name("Abomination"), 50);
+ }
+ else
+ {
+ /* Message */
+ cmsg_print(TERM_VIOLET, "You feel the dark powers trying to twisting your body, but they fail.");
+ }
+
+ break;
+ }
+
+ case RBE_SANITY:
+ {
+ obvious = TRUE;
+
+ take_sanity_hit(damage, ddesc);
+ break;
+ }
+
+ case RBE_POISON:
+ {
+ /* Take some damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Take "poison" effect */
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5))
+ {
+ obvious = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ case RBE_UN_BONUS:
+ {
+ /* Take some damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Allow complete resist */
+ if (!p_ptr->resist_disen)
+ {
+ /* Apply disenchantment */
+ if (apply_disenchant(0)) obvious = TRUE;
+ }
+
+ break;
+ }
+
+ case RBE_UN_POWER:
+ {
+ /* Take some damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+ break;
+ }
+
+ case RBE_EAT_GOLD:
+ {
+ /* Take some damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+ break;
+ }
+
+ case RBE_EAT_ITEM:
+ {
+ /* Take some damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+ break;
+ }
+
+ case RBE_EAT_FOOD:
+ {
+ /* Take some damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+ break;
+ }
+
+ case RBE_EAT_LITE:
+ {
+ /* Take some damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+ break;
+ }
+
+ case RBE_ACID:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Message */
+ msg_print("You are covered in acid!");
+
+ /* Special damage */
+ carried_monster_hit = TRUE;
+ acid_dam(damage, ddesc);
+
+ break;
+ }
+
+ case RBE_ELEC:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Message */
+ msg_print("You are struck by electricity!");
+
+ /* Special damage */
+ carried_monster_hit = TRUE;
+ elec_dam(damage, ddesc);
+
+
+ break;
+ }
+
+ case RBE_FIRE:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Message */
+ msg_print("You are enveloped in flames!");
+
+ /* Special damage */
+ carried_monster_hit = TRUE;
+ fire_dam(damage, ddesc);
+
+
+ break;
+ }
+
+ case RBE_COLD:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Message */
+ msg_print("You are covered with frost!");
+
+ /* Special damage */
+ carried_monster_hit = TRUE;
+ cold_dam(damage, ddesc);
+
+
+ break;
+ }
+
+ case RBE_BLIND:
+ {
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Increase "blind" */
+ if (!p_ptr->resist_blind)
+ {
+ if (set_blind(p_ptr->blind + 10 + randint(rlev)))
+ {
+ obvious = TRUE;
+ }
+ }
+
+
+ break;
+ }
+
+ case RBE_CONFUSE:
+ {
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Increase "confused" */
+ if (!p_ptr->resist_conf)
+ {
+ if (set_confused(p_ptr->confused + 3 + randint(rlev)))
+ {
+ obvious = TRUE;
+ }
+ }
+
+
+ break;
+ }
+
+ case RBE_TERRIFY:
+ {
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Increase "afraid" */
+ if (p_ptr->resist_fear)
+ {
+ msg_print("You stand your ground!");
+ obvious = TRUE;
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You stand your ground!");
+ obvious = TRUE;
+ }
+ else
+ {
+ if (set_afraid(p_ptr->afraid + 3 + randint(rlev)))
+ {
+ obvious = TRUE;
+ }
+ }
+
+
+ break;
+ }
+
+ case RBE_PARALYZE:
+ {
+ /* Hack -- Prevent perma-paralysis via damage */
+ if (p_ptr->paralyzed && (damage < 1)) damage = 1;
+
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Increase "paralyzed" */
+ if (p_ptr->free_act)
+ {
+ msg_print("You are unaffected!");
+ obvious = TRUE;
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ obvious = TRUE;
+ }
+ else
+ {
+ if (set_paralyzed(p_ptr->paralyzed + 3 + randint(rlev)))
+ {
+ obvious = TRUE;
+ }
+ }
+
+
+ break;
+ }
+
+ case RBE_LOSE_STR:
+ {
+ /* Damage (physical) */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_INT:
+ {
+ /* Damage (physical) */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_WIS:
+ {
+ /* Damage (physical) */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_DEX:
+ {
+ /* Damage (physical) */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_CON:
+ {
+ /* Damage (physical) */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_CHR:
+ {
+ /* Damage (physical) */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_ALL:
+ {
+ /* Damage (physical) */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Damage (stats) */
+ if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_SHATTER:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Hack -- Reduce damage based on the player armor class */
+ damage -= (damage * ((ac < 150) ? ac : 150) / 250);
+
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Radius 8 earthquake centered at the monster */
+ if (damage > 23)
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(p_ptr->py, p_ptr->px, 8);
+ }
+
+ break;
+ }
+
+ case RBE_EXP_10:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ if (p_ptr->hold_life && (rand_int(100) < 95))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(10, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+ break;
+ }
+
+ case RBE_EXP_20:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ if (p_ptr->hold_life && (rand_int(100) < 90))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(20, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+ break;
+ }
+
+ case RBE_EXP_40:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ if (p_ptr->hold_life && (rand_int(100) < 75))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(40, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+ break;
+ }
+
+ case RBE_EXP_80:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Take damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ if (p_ptr->hold_life && (rand_int(100) < 50))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(80, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+ break;
+ }
+
+ case RBE_DISEASE:
+ {
+ /* Take some damage */
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+
+ /* Take "poison" effect */
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5))
+ {
+ obvious = TRUE;
+ }
+ }
+
+ /* Damage CON (10% chance)*/
+ if (randint(100) < 11)
+ {
+ /* 1% chance for perm. damage */
+ bool_ perm = (randint(10) == 1);
+ if (dec_stat(A_CON, randint(10), perm)) obvious = TRUE;
+ }
+
+ break;
+ }
+ case RBE_PARASITE:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ if (!p_ptr->parasite) set_parasite(damage, r_idx);
+
+ break;
+ }
+ case RBE_HALLU:
+ {
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ /* Increase "image" */
+ if (!p_ptr->resist_chaos)
+ {
+ if (set_image(p_ptr->image + 3 + randint(rlev / 2)))
+ {
+ obvious = TRUE;
+ }
+ }
+ break;
+
+ }
+ case RBE_TIME:
+ {
+ switch (randint(10))
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ {
+ msg_print("You feel life has clocked back.");
+ lose_exp(100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
+ break;
+ }
+
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ {
+ int stat = rand_int(6);
+
+ switch (stat)
+ {
+ case A_STR:
+ act = "strong";
+ break;
+ case A_INT:
+ act = "bright";
+ break;
+ case A_WIS:
+ act = "wise";
+ break;
+ case A_DEX:
+ act = "agile";
+ break;
+ case A_CON:
+ act = "hardy";
+ break;
+ case A_CHR:
+ act = "beautiful";
+ break;
+ }
+
+ msg_format("You're not as %s as you used to be...", act);
+
+ p_ptr->stat_cur[stat] = (p_ptr->stat_cur[stat] * 3) / 4;
+ if (p_ptr->stat_cur[stat] < 3) p_ptr->stat_cur[stat] = 3;
+ p_ptr->update |= (PU_BONUS);
+ break;
+ }
+
+ case 10:
+ {
+ msg_print("You're not as powerful as you used to be...");
+
+ for (k = 0; k < 6; k++)
+ {
+ p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4;
+ if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3;
+ }
+ p_ptr->update |= (PU_BONUS);
+ break;
+ }
+ }
+ carried_monster_hit = TRUE;
+ take_hit(damage, ddesc);
+ break;
+ }
+ }
+
+
+ /* Hack -- only one of cut or stun */
+ if (do_cut && do_stun)
+ {
+ /* Cancel cut */
+ if (rand_int(100) < 50)
+ {
+ do_cut = 0;
+ }
+
+ /* Cancel stun */
+ else
+ {
+ do_stun = 0;
+ }
+ }
+
+ /* Handle cut */
+ if (do_cut)
+ {
+ int k = 0;
+
+ /* Critical hit (zero if non-critical) */
+ tmp = monster_critical(d_dice, d_side, damage);
+
+ /* Roll for damage */
+ switch (tmp)
+ {
+ case 0:
+ k = 0;
+ break;
+ case 1:
+ k = randint(5);
+ break;
+ case 2:
+ k = randint(5) + 5;
+ break;
+ case 3:
+ k = randint(20) + 20;
+ break;
+ case 4:
+ k = randint(50) + 50;
+ break;
+ case 5:
+ k = randint(100) + 100;
+ break;
+ case 6:
+ k = 300;
+ break;
+ default:
+ k = 500;
+ break;
+ }
+
+ /* Apply the cut */
+ if (k) (void)set_cut(p_ptr->cut + k);
+ }
+
+ /* Handle stun */
+ if (do_stun)
+ {
+ int k = 0;
+
+ /* Critical hit (zero if non-critical) */
+ tmp = monster_critical(d_dice, d_side, damage);
+
+ /* Roll for damage */
+ switch (tmp)
+ {
+ case 0:
+ k = 0;
+ break;
+ case 1:
+ k = randint(5);
+ break;
+ case 2:
+ k = randint(10) + 10;
+ break;
+ case 3:
+ k = randint(20) + 20;
+ break;
+ case 4:
+ k = randint(30) + 30;
+ break;
+ case 5:
+ k = randint(40) + 40;
+ break;
+ case 6:
+ k = 100;
+ break;
+ default:
+ k = 200;
+ break;
+ }
+
+ /* Apply the stun */
+ if (k) (void)set_stun(p_ptr->stun + k);
+ }
+
+ if (touched)
+ {
+ if (p_ptr->sh_fire && alive)
+ {
+ r_ptr->r_flags3 |= RF3_IM_FIRE;
+ }
+
+ if (p_ptr->sh_elec && alive)
+ {
+ r_ptr->r_flags3 |= RF3_IM_ELEC;
+ }
+ touched = FALSE;
+ }
+ }
+
+ /* Monster missed player */
+ else
+ {
+ /* Analyze failed attacks */
+ switch (method)
+ {
+ case RBM_HIT:
+ case RBM_TOUCH:
+ case RBM_PUNCH:
+ case RBM_KICK:
+ case RBM_CLAW:
+ case RBM_BITE:
+ case RBM_STING:
+ case RBM_XXX1:
+ case RBM_BUTT:
+ case RBM_CRUSH:
+ case RBM_ENGULF:
+ case RBM_CHARGE:
+
+ /* Disturbing */
+ disturb(1, 0);
+
+ /* Message */
+ msg_format("%s misses you.", sym_name);
+
+ break;
+ }
+ }
+
+
+ /* Analyze "visible" monsters only */
+ if (visible)
+ {
+ /* Count "obvious" attacks (and ones that cause damage) */
+ if (obvious || damage || (r_ptr->r_blows[ap_cnt] > 10))
+ {
+ /* Count attacks of this type */
+ if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR)
+ {
+ r_ptr->r_blows[ap_cnt]++;
+ }
+ }
+ }
+ }
+ /* Assume we attacked */
+ return (TRUE);
+}
+
+/*
+ * Give unprotected player the Black Breath with a 1 in (chance) probability
+ *
+ */
+void black_breath_attack(int chance)
+{
+ if (!p_ptr->protundead && randint(chance) == 1)
+ {
+ msg_print("Your foe calls upon your soul!");
+ msg_print("You feel the Black Breath slowly draining you of life...");
+ p_ptr->black_breath = TRUE;
+ }
+}
+
+/*
+ * Attack the player via physical attacks.
+ */
+bool_ make_attack_normal(int m_idx, byte divis)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ int ap_cnt;
+
+ int i, j, k, tmp, ac, rlev;
+ int do_cut, do_stun, do_vampire;
+
+ s32b gold;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ char m_name[80];
+
+ char ddesc[80];
+
+ bool_ blinked;
+ bool_ touched = FALSE, fear = FALSE, alive = TRUE;
+ bool_ explode = FALSE;
+
+ /* Not allowed to attack */
+ if (r_ptr->flags1 & (RF1_NEVER_BLOW)) return (FALSE);
+
+ /* ...nor if friendly */
+ if (is_friend(m_ptr) >= 0)
+ {
+ if (p_ptr->control == m_idx) swap_position(m_ptr->fy, m_ptr->fx);
+ return FALSE;
+ }
+
+ /* Cannot attack the player if mortal and player fated to never die by the ... */
+ if ((r_ptr->flags7 & RF7_MORTAL) && (p_ptr->no_mortal)) return (FALSE);
+
+ /* Total armor */
+ ac = p_ptr->ac + p_ptr->to_a;
+
+ /* Extract the effective monster level */
+ rlev = ((m_ptr->level >= 1) ? m_ptr->level : 1);
+
+
+ /* Get the monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Get the "died from" information (i.e. "a kobold") */
+ monster_desc(ddesc, m_ptr, 0x88);
+
+
+ /* Assume no blink */
+ blinked = FALSE;
+
+ /* Scan through all four blows */
+ for (ap_cnt = 0; ap_cnt < 4; ap_cnt++)
+ {
+ bool_ visible = FALSE;
+ bool_ obvious = FALSE;
+
+ int power = 0;
+ int damage = 0;
+
+ cptr act = NULL;
+
+ /* Extract the attack infomation */
+ int effect = m_ptr->blow[ap_cnt].effect;
+ int method = m_ptr->blow[ap_cnt].method;
+ int d_dice = m_ptr->blow[ap_cnt].d_dice;
+ int d_side = m_ptr->blow[ap_cnt].d_side;
+
+
+ /* Hack -- no more attacks */
+ if (!method) break;
+
+
+ /* Stop if player is dead or gone */
+ if (!alive || death) break;
+
+ /* Handle "leaving" */
+ if (p_ptr->leaving) break;
+
+ /* Extract visibility (before blink) */
+ if (m_ptr->ml) visible = TRUE;
+
+ /* Extract the attack "power" */
+ switch (effect)
+ {
+ case RBE_HURT:
+ power = 60;
+ break;
+ case RBE_POISON:
+ power = 5;
+ break;
+ case RBE_UN_BONUS:
+ power = 20;
+ break;
+ case RBE_UN_POWER:
+ power = 15;
+ break;
+ case RBE_EAT_GOLD:
+ power = 5;
+ break;
+ case RBE_EAT_ITEM:
+ power = 5;
+ break;
+ case RBE_EAT_FOOD:
+ power = 5;
+ break;
+ case RBE_EAT_LITE:
+ power = 5;
+ break;
+ case RBE_ACID:
+ power = 0;
+ break;
+ case RBE_ELEC:
+ power = 10;
+ break;
+ case RBE_FIRE:
+ power = 10;
+ break;
+ case RBE_COLD:
+ power = 10;
+ break;
+ case RBE_BLIND:
+ power = 2;
+ break;
+ case RBE_CONFUSE:
+ power = 10;
+ break;
+ case RBE_TERRIFY:
+ power = 10;
+ break;
+ case RBE_PARALYZE:
+ power = 2;
+ break;
+ case RBE_LOSE_STR:
+ power = 0;
+ break;
+ case RBE_LOSE_DEX:
+ power = 0;
+ break;
+ case RBE_LOSE_CON:
+ power = 0;
+ break;
+ case RBE_LOSE_INT:
+ power = 0;
+ break;
+ case RBE_LOSE_WIS:
+ power = 0;
+ break;
+ case RBE_LOSE_CHR:
+ power = 0;
+ break;
+ case RBE_LOSE_ALL:
+ power = 2;
+ break;
+ case RBE_SHATTER:
+ power = 60;
+ break;
+ case RBE_EXP_10:
+ power = 5;
+ break;
+ case RBE_EXP_20:
+ power = 5;
+ break;
+ case RBE_EXP_40:
+ power = 5;
+ break;
+ case RBE_EXP_80:
+ power = 5;
+ break;
+ case RBE_DISEASE:
+ power = 5;
+ break;
+ case RBE_TIME:
+ power = 5;
+ break;
+ case RBE_SANITY:
+ power = 60;
+ break;
+ case RBE_HALLU:
+ power = 10;
+ break;
+ case RBE_PARASITE:
+ power = 5;
+ break;
+ case RBE_ABOMINATION:
+ power = 20;
+ break;
+ }
+
+
+ /* Monster hits player */
+ if (!effect || check_hit(power, rlev))
+ {
+ int chance = p_ptr->dodge_chance - ((rlev * 5) / 6);
+
+ /* Always disturbing */
+ disturb(1, 0);
+
+ if ((chance > 0) && magik(chance))
+ {
+ char m_poss[80];
+ monster_desc(m_poss, m_ptr, 0x06);
+ msg_format("You dodge %s attack!", m_poss);
+ continue;
+ }
+
+ /* Eru can help you */
+ PRAY_GOD(GOD_ERU)
+ {
+ s32b chance = p_ptr->grace;
+
+ if (chance > 50000) chance = 50000;
+ chance -= rlev * 300;
+
+ if ((randint(100000) < chance) && (r_ptr->flags3 & (RF3_EVIL)))
+ {
+ /* Remember the Evil-ness */
+ r_ptr->r_flags3 |= (RF3_EVIL);
+
+ /* Message */
+ msg_format("The hand of Eru Iluvatar stops %s blow.", m_name);
+
+ /* Hack -- Next attack */
+ continue;
+ }
+ }
+
+ /* Hack -- Apply "protection from evil" */
+ if ((p_ptr->protevil > 0) &&
+ (r_ptr->flags3 & (RF3_EVIL)) &&
+ (p_ptr->lev >= rlev) &&
+ ((rand_int(100) + p_ptr->lev) > 50))
+ {
+ /* Remember the Evil-ness */
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_EVIL);
+ }
+
+ /* Message */
+ msg_format("%^s is repelled.", m_name);
+
+ /* Hack -- Next attack */
+ continue;
+ }
+
+ /* Hack -- Apply "protection from good" */
+ if ((p_ptr->protgood > 0) &&
+ (r_ptr->flags3 & (RF3_GOOD)) &&
+ (p_ptr->lev >= rlev) &&
+ ((rand_int(100) + p_ptr->lev) > 50))
+ {
+ /* Remember the Good-ness */
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags3 |= (RF3_GOOD);
+ }
+
+ /* Message */
+ msg_format("%^s is repelled.", m_name);
+
+ /* Hack -- Next attack */
+ continue;
+ }
+
+ /* Assume no cut or stun */
+ do_cut = do_stun = do_vampire = 0;
+
+ /* Describe the attack method */
+ switch (method)
+ {
+ case RBM_HIT:
+ {
+ act = "hits you.";
+ do_cut = do_stun = 1;
+ touched = TRUE;
+ sound(SOUND_HIT);
+ break;
+ }
+
+ case RBM_TOUCH:
+ {
+ act = "touches you.";
+ touched = TRUE;
+ sound(SOUND_TOUCH);
+ break;
+ }
+
+ case RBM_PUNCH:
+ {
+ act = "punches you.";
+ touched = TRUE;
+ do_stun = 1;
+ sound(SOUND_HIT);
+ break;
+ }
+
+ case RBM_KICK:
+ {
+ act = "kicks you.";
+ touched = TRUE;
+ do_stun = 1;
+ sound(SOUND_HIT);
+ break;
+ }
+
+ case RBM_CLAW:
+ {
+ act = "claws you.";
+ touched = TRUE;
+ do_cut = 1;
+ sound(SOUND_CLAW);
+ break;
+ }
+
+ case RBM_BITE:
+ {
+ act = "bites you.";
+ do_cut = 1;
+ if (magik(5) && (strstr(r_name + r_ptr->name, "Vampire") || strstr(r_name + r_ptr->name, "vampire")))
+ do_vampire = TRUE;
+ touched = TRUE;
+ sound(SOUND_BITE);
+ break;
+ }
+
+ case RBM_STING:
+ {
+ act = "stings you.";
+ touched = TRUE;
+ sound(SOUND_STING);
+ break;
+ }
+
+ case RBM_XXX1:
+ {
+ act = "XXX1's you.";
+ break;
+ }
+
+ case RBM_BUTT:
+ {
+ act = "butts you.";
+ do_stun = 1;
+ touched = TRUE;
+ sound(SOUND_HIT);
+ break;
+ }
+
+ case RBM_CRUSH:
+ {
+ act = "crushes you.";
+ do_stun = 1;
+ touched = TRUE;
+ sound(SOUND_CRUSH);
+ break;
+ }
+
+ case RBM_ENGULF:
+ {
+ act = "engulfs you.";
+ touched = TRUE;
+ sound(SOUND_CRUSH);
+ break;
+ }
+
+ case RBM_CHARGE:
+ {
+ act = "charges you.";
+ touched = TRUE;
+ sound(SOUND_BUY); /* Note! This is "charges", not "charges at". */
+ break;
+ }
+
+ case RBM_CRAWL:
+ {
+ act = "crawls on you.";
+ touched = TRUE;
+ sound(SOUND_SLIME);
+ break;
+ }
+
+ case RBM_DROOL:
+ {
+ act = "drools on you.";
+ sound(SOUND_SLIME);
+ break;
+ }
+
+ case RBM_SPIT:
+ {
+ act = "spits on you.";
+ sound(SOUND_SLIME);
+ break;
+ }
+
+ case RBM_EXPLODE:
+ {
+ act = "explodes.";
+ explode = TRUE;
+ break;
+ }
+
+ case RBM_GAZE:
+ {
+ act = "gazes at you.";
+ break;
+ }
+
+ case RBM_WAIL:
+ {
+ act = "wails at you.";
+ sound(SOUND_WAIL);
+ break;
+ }
+
+ case RBM_SPORE:
+ {
+ act = "releases spores at you.";
+ sound(SOUND_SLIME);
+ break;
+ }
+
+ case RBM_XXX4:
+ {
+ act = "projects XXX4's at you.";
+ break;
+ }
+
+ case RBM_BEG:
+ {
+ act = "begs you for money.";
+ sound(SOUND_MOAN);
+ break;
+ }
+
+ case RBM_INSULT:
+ {
+ act = desc_insult[rand_int(8)];
+ sound(SOUND_MOAN);
+ break;
+ }
+
+ case RBM_MOAN:
+ {
+ if (strstr((r_name + r_ptr->name), "Mathilde, the Science Student"))
+ act = desc_moan[rand_int(3) + 4];
+ else
+ act = desc_moan[rand_int(4)];
+ sound(SOUND_MOAN);
+ break;
+ }
+
+ case RBM_SHOW:
+ {
+ if (randint(3) == 1)
+ act = "sings 'We are a happy family.'";
+ else
+ act = "sings 'I love you, you love me.'";
+ sound(SOUND_SHOW);
+ break;
+ }
+ }
+
+ /* Message */
+ if (act) msg_format("%^s %s", m_name, act);
+
+ /* The undead can give the player the Black Breath with
+ * a successful blow. Uniques have a better chance. -LM-
+ * Nazgul have a 25% chance
+ */
+ if (r_ptr->flags7 & RF7_NAZGUL)
+ {
+ black_breath_attack(4);
+ }
+ else if ((m_ptr->level >= 35) && (r_ptr->flags3 & (RF3_UNDEAD)) &&
+ (r_ptr->flags1 & (RF1_UNIQUE)))
+ {
+ black_breath_attack(300 - m_ptr->level);
+ }
+ else if ((m_ptr->level >= 40) && (r_ptr->flags3 & (RF3_UNDEAD)))
+ {
+ black_breath_attack(450 - m_ptr->level);
+ }
+
+ /* Hack -- assume all attacks are obvious */
+ obvious = TRUE;
+
+ /* Roll out the damage */
+ damage = damroll(d_dice, d_side);
+
+ /* Sometime reduce the damage */
+ damage /= divis;
+
+ /* Apply appropriate damage */
+ switch (effect)
+ {
+ case 0:
+ {
+ /* Hack -- Assume obvious */
+ obvious = TRUE;
+
+ /* Hack -- No damage */
+ damage = 0;
+
+ break;
+ }
+
+ case RBE_HURT:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Hack -- Player armor reduces total damage */
+ damage -= (damage * ((ac < 150) ? ac : 150) / 250);
+
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ break;
+ }
+
+ case RBE_ABOMINATION:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Morph, but let mimicry skill have a chance to stop this */
+ if (magik(60 - get_skill(SKILL_MIMICRY)))
+ {
+ /* Message */
+ cmsg_print(TERM_VIOLET, "You feel the dark powers twisting your body!");
+
+ set_mimic(damage, resolve_mimic_name("Abomination"), 50);
+ }
+ else
+ {
+ /* Message */
+ cmsg_print(TERM_VIOLET, "You feel the dark powers trying to twisting your body, but they fail.");
+ }
+
+ break;
+ }
+
+ case RBE_SANITY:
+ {
+ obvious = TRUE;
+
+ take_sanity_hit(damage, ddesc);
+ break;
+ }
+
+ case RBE_POISON:
+ {
+ /* Take some damage */
+ take_hit(damage, ddesc);
+
+ /* Take "poison" effect */
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5))
+ {
+ obvious = TRUE;
+ }
+ }
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_POIS);
+
+ break;
+ }
+
+ case RBE_UN_BONUS:
+ {
+ /* Take some damage */
+ take_hit(damage, ddesc);
+
+ /* Allow complete resist */
+ if (!p_ptr->resist_disen)
+ {
+ /* Apply disenchantment */
+ if (apply_disenchant(0)) obvious = TRUE;
+ }
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_DISEN);
+
+ break;
+ }
+
+ case RBE_UN_POWER:
+ {
+ /* Take some damage */
+ take_hit(damage, ddesc);
+
+ /* Find an item */
+ for (k = 0; k < 10; k++)
+ {
+ /* Pick an item */
+ i = rand_int(INVEN_PACK);
+
+ /* Obtain the item */
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Drain charged wands/staffs
+ Hack -- don't let artifacts get drained */
+ if (((o_ptr->tval == TV_STAFF) ||
+ (o_ptr->tval == TV_WAND)) &&
+ (o_ptr->pval) &&
+ !artifact_p(o_ptr))
+ {
+ /* Message */
+ msg_print("Energy drains from your pack!");
+
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Heal */
+ j = rlev;
+ m_ptr->hp += j * o_ptr->pval * o_ptr->number;
+ if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
+
+ /* Redraw (later) if needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Uncharge */
+ o_ptr->pval = 0;
+
+ /* Combine / Reorder the pack */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+
+ /* Done */
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case RBE_EAT_GOLD:
+ {
+ /* Take some damage */
+ take_hit(damage, ddesc);
+
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Saving throw (unless paralyzed) based on dex and level */
+ if (!p_ptr->paralyzed &&
+ (rand_int(100) < (adj_dex_safe[p_ptr->stat_ind[A_DEX]] +
+ p_ptr->lev)))
+ {
+ /* Saving throw message */
+ msg_print("You quickly protect your money pouch!");
+
+ /* Occasional blink anyway */
+ if (rand_int(3)) blinked = TRUE;
+ }
+
+ /* Eat gold */
+ else
+ {
+ gold = (p_ptr->au / 10) + randint(25);
+ if (gold < 2) gold = 2;
+ if (gold > 5000) gold = (p_ptr->au / 20) + randint(3000);
+ if (gold > p_ptr->au) gold = p_ptr->au;
+ p_ptr->au -= gold;
+ if (gold <= 0)
+ {
+ msg_print("Nothing was stolen.");
+ }
+ else if (p_ptr->au)
+ {
+ msg_print("Your purse feels lighter.");
+ msg_format("%ld coins were stolen!", (long)gold);
+ }
+ else
+ {
+ msg_print("Your purse feels lighter.");
+ msg_print("All of your coins were stolen!");
+ }
+
+ while (gold > 0)
+ {
+ object_type forge, *j_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(j_ptr);
+
+ /* Prepare a gold object */
+ object_prep(j_ptr, lookup_kind(TV_GOLD, 9));
+
+ /* Determine how much the treasure is "worth" */
+ j_ptr->pval = (gold >= 15000) ? 15000 : gold;
+
+ monster_carry(m_ptr, m_idx, j_ptr);
+
+ gold -= 15000;
+ }
+
+ /* Redraw gold */
+ p_ptr->redraw |= (PR_GOLD);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Blink away */
+ blinked = TRUE;
+ }
+
+ break;
+ }
+
+ case RBE_EAT_ITEM:
+ {
+ /* Take some damage */
+ take_hit(damage, ddesc);
+
+ /* Saving throw (unless paralyzed) based on dex and level */
+ if (!p_ptr->paralyzed &&
+ (rand_int(100) < (adj_dex_safe[p_ptr->stat_ind[A_DEX]] +
+ p_ptr->lev)))
+ {
+ /* Saving throw message */
+ msg_print("You grab hold of your backpack!");
+
+ /* Occasional "blink" anyway */
+ blinked = TRUE;
+
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Done */
+ break;
+ }
+
+ /* Find an item */
+ for (k = 0; k < 10; k++)
+ {
+ /* Pick an item */
+ i = rand_int(INVEN_PACK);
+
+ /* Obtain the item */
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Skip artifacts */
+ if (artifact_p(o_ptr) || o_ptr->art_name) continue;
+
+ /* Get a description */
+ object_desc(o_name, o_ptr, FALSE, 3);
+
+ /* Message */
+ msg_format("%sour %s (%c) was stolen!",
+ ((o_ptr->number > 1) ? "One of y" : "Y"),
+ o_name, index_to_label(i));
+
+ /* Option */
+ if (testing_carry)
+ {
+ s16b o_idx;
+
+ /* Make an object */
+ o_idx = o_pop();
+
+ /* Success */
+ if (o_idx)
+ {
+ object_type *j_ptr;
+
+ /* Get new object */
+ j_ptr = &o_list[o_idx];
+
+ /* Copy object */
+ object_copy(j_ptr, o_ptr);
+
+ /* Modify number */
+ j_ptr->number = 1;
+
+ /* Hack -- If a wand, allocate total
+ * maximum timeouts or charges between those
+ * stolen and those missed. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ j_ptr->pval = o_ptr->pval / o_ptr->number;
+ o_ptr->pval -= j_ptr->pval;
+ }
+
+ /* Forget mark */
+ j_ptr->marked = FALSE;
+
+ /* Memorize monster */
+ j_ptr->held_m_idx = m_idx;
+
+ /* Build stack */
+ j_ptr->next_o_idx = m_ptr->hold_o_idx;
+
+ /* Build stack */
+ m_ptr->hold_o_idx = o_idx;
+ }
+ }
+ else
+ {
+ if (strstr((r_name + r_ptr->name), "black market")
+ && randint(2) != 1)
+ {
+ s16b o_idx;
+
+ /* Make an object */
+ o_idx = o_pop();
+
+ /* Success */
+ if (o_idx)
+ {
+ object_type *j_ptr;
+ if (cheat_xtra || cheat_peek)
+ msg_print("Moving object to black market...");
+
+ /* Get new object */
+ j_ptr = &o_list[o_idx];
+
+ /* Copy object */
+ object_copy(j_ptr, o_ptr);
+
+ /* Modify number */
+ j_ptr->number = 1;
+
+ /* Forget mark */
+ j_ptr->marked = FALSE;
+
+ move_to_black_market(j_ptr);
+ }
+ }
+ }
+
+ /* Steal the items */
+ inc_stack_size_ex(i, -1, OPTIMIZE, NO_DESCRIBE);
+
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Blink away */
+ blinked = TRUE;
+
+ /* Done */
+ break;
+ }
+
+ break;
+ }
+
+ case RBE_EAT_FOOD:
+ {
+ /* Take some damage */
+ take_hit(damage, ddesc);
+
+ /* Steal some food */
+ for (k = 0; k < 10; k++)
+ {
+ /* Pick an item from the pack */
+ i = rand_int(INVEN_PACK);
+
+ /* Get the item */
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Skip non-food objects */
+ if (o_ptr->tval != TV_FOOD) continue;
+
+ /* Get a description */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ /* Message */
+ msg_format("%sour %s (%c) was eaten!",
+ ((o_ptr->number > 1) ? "One of y" : "Y"),
+ o_name, index_to_label(i));
+
+ /* Steal the items */
+ inc_stack_size_ex(i, -1, OPTIMIZE, NO_DESCRIBE);
+
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Done */
+ break;
+ }
+
+ break;
+ }
+
+ case RBE_EAT_LITE:
+ {
+ /* Take some damage */
+ take_hit(damage, ddesc);
+
+ /* Access the lite */
+ o_ptr = &p_ptr->inventory[INVEN_LITE];
+
+ /* Drain fuel */
+ if ((o_ptr->pval > 0) && (!artifact_p(o_ptr)))
+ {
+ /* Reduce fuel */
+ o_ptr->pval -= (250 + randint(250));
+ if (o_ptr->pval < 1) o_ptr->pval = 1;
+
+ /* Notice */
+ if (!p_ptr->blind)
+ {
+ msg_print("Your light dims.");
+ obvious = TRUE;
+ }
+
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP);
+ }
+
+ break;
+ }
+
+ case RBE_ACID:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Message */
+ msg_print("You are covered in acid!");
+
+ /* Special damage */
+ acid_dam(damage, ddesc);
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_ACID);
+
+ break;
+ }
+
+ case RBE_ELEC:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Message */
+ msg_print("You are struck by electricity!");
+
+ /* Special damage */
+ elec_dam(damage, ddesc);
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_ELEC);
+
+ break;
+ }
+
+ case RBE_FIRE:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Message */
+ msg_print("You are enveloped in flames!");
+
+ /* Special damage */
+ fire_dam(damage, ddesc);
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_FIRE);
+
+ break;
+ }
+
+ case RBE_COLD:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Message */
+ msg_print("You are covered with frost!");
+
+ /* Special damage */
+ cold_dam(damage, ddesc);
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_COLD);
+
+ break;
+ }
+
+ case RBE_BLIND:
+ {
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ /* Increase "blind" */
+ if (!p_ptr->resist_blind)
+ {
+ if (set_blind(p_ptr->blind + 10 + randint(rlev)))
+ {
+ obvious = TRUE;
+ }
+ }
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_BLIND);
+
+ break;
+ }
+
+ case RBE_CONFUSE:
+ {
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ /* Increase "confused" */
+ if (!p_ptr->resist_conf)
+ {
+ if (set_confused(p_ptr->confused + 3 + randint(rlev)))
+ {
+ obvious = TRUE;
+ }
+ }
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_CONF);
+
+ break;
+ }
+
+ case RBE_TERRIFY:
+ {
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ /* Increase "afraid" */
+ if (p_ptr->resist_fear)
+ {
+ msg_print("You stand your ground!");
+ obvious = TRUE;
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You stand your ground!");
+ obvious = TRUE;
+ }
+ else
+ {
+ if (set_afraid(p_ptr->afraid + 3 + randint(rlev)))
+ {
+ obvious = TRUE;
+ }
+ }
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_FEAR);
+
+ break;
+ }
+
+ case RBE_PARALYZE:
+ {
+ /* Hack -- Prevent perma-paralysis via damage */
+ if (p_ptr->paralyzed && (damage < 1)) damage = 1;
+
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ /* Increase "paralyzed" */
+ if (p_ptr->free_act)
+ {
+ msg_print("You are unaffected!");
+ obvious = TRUE;
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ obvious = TRUE;
+ }
+ else
+ {
+ if (set_paralyzed(p_ptr->paralyzed + 3 + randint(rlev)))
+ {
+ obvious = TRUE;
+ }
+ }
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_FREE);
+
+ break;
+ }
+
+ case RBE_LOSE_STR:
+ {
+ /* Damage (physical) */
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_INT:
+ {
+ /* Damage (physical) */
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_WIS:
+ {
+ /* Damage (physical) */
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_DEX:
+ {
+ /* Damage (physical) */
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_CON:
+ {
+ /* Damage (physical) */
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_CHR:
+ {
+ /* Damage (physical) */
+ take_hit(damage, ddesc);
+
+ /* Damage (stat) */
+ if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_LOSE_ALL:
+ {
+ /* Damage (physical) */
+ take_hit(damage, ddesc);
+
+ /* Damage (stats) */
+ if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) obvious = TRUE;
+ if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) obvious = TRUE;
+
+ break;
+ }
+
+ case RBE_SHATTER:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Hack -- Reduce damage based on the player armor class */
+ damage -= (damage * ((ac < 150) ? ac : 150) / 250);
+
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ /* Radius 8 earthquake centered at the monster */
+ if (damage > 23)
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(m_ptr->fy, m_ptr->fx, 8);
+ }
+
+ break;
+ }
+
+ case RBE_EXP_10:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ if (p_ptr->hold_life && (rand_int(100) < 95))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(10, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+ break;
+ }
+
+ case RBE_EXP_20:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ if (p_ptr->hold_life && (rand_int(100) < 90))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(20, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+ break;
+ }
+
+ case RBE_EXP_40:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ if (p_ptr->hold_life && (rand_int(100) < 75))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(40, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+ break;
+ }
+
+ case RBE_EXP_80:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ if (p_ptr->hold_life && (rand_int(100) < 50))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else
+ {
+ s32b d = damroll(80, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
+ if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(d / 10);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(d);
+ }
+ }
+ break;
+ }
+
+ case RBE_DISEASE:
+ {
+ /* Take some damage */
+ take_hit(damage, ddesc);
+
+ /* Take "poison" effect */
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5))
+ {
+ obvious = TRUE;
+ }
+ }
+
+ /* Damage CON (10% chance)*/
+ if (randint(100) < 11)
+ {
+ /* 1% chance for perm. damage */
+ bool_ perm = (randint(10) == 1);
+ if (dec_stat(A_CON, randint(10), perm)) obvious = TRUE;
+ }
+
+ break;
+ }
+ case RBE_HALLU:
+ {
+ /* Take damage */
+ take_hit(damage, ddesc);
+
+ /* Increase "image" */
+ if (!p_ptr->resist_chaos)
+ {
+ if (set_image(p_ptr->image + 3 + randint(rlev / 2)))
+ {
+ obvious = TRUE;
+ }
+ }
+
+ /* Learn about the player */
+ update_smart_learn(m_idx, DRS_CHAOS);
+
+ break;
+
+ }
+ case RBE_TIME:
+ {
+ switch (randint(10))
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ {
+ msg_print("You feel life has clocked back.");
+ lose_exp(100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
+ break;
+ }
+
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ {
+ int stat = rand_int(6);
+
+ switch (stat)
+ {
+ case A_STR:
+ act = "strong";
+ break;
+ case A_INT:
+ act = "bright";
+ break;
+ case A_WIS:
+ act = "wise";
+ break;
+ case A_DEX:
+ act = "agile";
+ break;
+ case A_CON:
+ act = "hardy";
+ break;
+ case A_CHR:
+ act = "beautiful";
+ break;
+ }
+
+ msg_format("You're not as %s as you used to be...", act);
+
+ p_ptr->stat_cur[stat] = (p_ptr->stat_cur[stat] * 3) / 4;
+ if (p_ptr->stat_cur[stat] < 3) p_ptr->stat_cur[stat] = 3;
+ p_ptr->update |= (PU_BONUS);
+ break;
+ }
+
+ case 10:
+ {
+ msg_print("You're not as powerful as you used to be...");
+
+ for (k = 0; k < 6; k++)
+ {
+ p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4;
+ if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3;
+ }
+ p_ptr->update |= (PU_BONUS);
+ break;
+ }
+ }
+ take_hit(damage, ddesc);
+ break;
+ }
+ case RBE_PARASITE:
+ {
+ /* Obvious */
+ obvious = TRUE;
+
+ if (!p_ptr->parasite) set_parasite(damage, m_ptr->r_idx);
+
+ break;
+ }
+ }
+
+
+ /* Hack -- only one of cut or stun */
+ if (do_cut && do_stun)
+ {
+ /* Cancel cut */
+ if (rand_int(100) < 50)
+ {
+ do_cut = 0;
+ }
+
+ /* Cancel stun */
+ else
+ {
+ do_stun = 0;
+ }
+ }
+
+ /* Handle cut */
+ if (do_cut)
+ {
+ int k = 0;
+
+ /* Critical hit (zero if non-critical) */
+ tmp = monster_critical(d_dice, d_side, damage);
+
+ /* Roll for damage */
+ switch (tmp)
+ {
+ case 0:
+ k = 0;
+ break;
+ case 1:
+ k = randint(5);
+ break;
+ case 2:
+ k = randint(5) + 5;
+ break;
+ case 3:
+ k = randint(20) + 20;
+ break;
+ case 4:
+ k = randint(50) + 50;
+ break;
+ case 5:
+ k = randint(100) + 100;
+ break;
+ case 6:
+ k = 300;
+ break;
+ default:
+ k = 500;
+ break;
+ }
+
+ /* Apply the cut */
+ if (k) (void)set_cut(p_ptr->cut + k);
+ }
+
+ /* Handle stun */
+ if (do_stun)
+ {
+ int k = 0;
+
+ /* Critical hit (zero if non-critical) */
+ tmp = monster_critical(d_dice, d_side, damage);
+
+ /* Roll for damage */
+ switch (tmp)
+ {
+ case 0:
+ k = 0;
+ break;
+ case 1:
+ k = randint(5);
+ break;
+ case 2:
+ k = randint(10) + 10;
+ break;
+ case 3:
+ k = randint(20) + 20;
+ break;
+ case 4:
+ k = randint(30) + 30;
+ break;
+ case 5:
+ k = randint(40) + 40;
+ break;
+ case 6:
+ k = 100;
+ break;
+ default:
+ k = 200;
+ break;
+ }
+
+ /* Apply the stun */
+ if (k) (void)set_stun(p_ptr->stun + k);
+ }
+
+ /* Do vampiric thingies */
+ if (do_vampire)
+ {
+ /* Change to resist(but never total protection) */
+/* if (magik(3) || (magik(m_ptr->level - (p_ptr->lev / 2))))
+ call_lua("gain_corruption", "(s)", "", "Vampire");*/
+ }
+
+ if (explode)
+ {
+ sound(SOUND_EXPLODE);
+ if (mon_take_hit(m_idx, m_ptr->hp + 1, &fear, NULL))
+ {
+ blinked = FALSE;
+ alive = FALSE;
+ }
+ }
+
+ if (touched)
+ {
+ if (p_ptr->sh_fire && alive)
+ {
+ if (!(r_ptr->flags3 & RF3_IM_FIRE))
+ {
+ msg_format("%^s is suddenly very hot!", m_name);
+ if (mon_take_hit(m_idx, damroll(2, 6), &fear,
+ " turns into a pile of ash."))
+ {
+ blinked = FALSE;
+ alive = FALSE;
+ }
+ }
+ else
+ {
+ if (m_ptr->ml)
+ r_ptr->r_flags3 |= RF3_IM_FIRE;
+ }
+ }
+
+ if (p_ptr->sh_elec && alive)
+ {
+ if (!(r_ptr->flags3 & RF3_IM_ELEC))
+ {
+ msg_format("%^s gets zapped!", m_name);
+ if (mon_take_hit(m_idx, damroll(2, 6), &fear,
+ " turns into a pile of cinder."))
+ {
+ blinked = FALSE;
+ alive = FALSE;
+ }
+ }
+ else
+ {
+ if (m_ptr->ml)
+ r_ptr->r_flags3 |= RF3_IM_ELEC;
+ }
+ }
+ if (p_ptr->shield && (p_ptr->shield_opt & SHIELD_COUNTER) && alive)
+ {
+ msg_format("%^s gets bashed by your mystic shield!", m_name);
+ if (mon_take_hit(m_idx, damroll(p_ptr->shield_power_opt, p_ptr->shield_power_opt2), &fear,
+ " is bashed by your mystic shield."))
+ {
+ blinked = FALSE;
+ alive = FALSE;
+ }
+ }
+ if (p_ptr->shield && (p_ptr->shield_opt & SHIELD_FIRE) && alive)
+ {
+ if (!(r_ptr->flags3 & RF3_IM_FIRE))
+ {
+ msg_format("%^s gets burned by your fiery shield!", m_name);
+ if (mon_take_hit(m_idx, damroll(p_ptr->shield_power_opt, p_ptr->shield_power_opt2), &fear,
+ " is burned by your fiery shield."))
+ {
+ blinked = FALSE;
+ alive = FALSE;
+ }
+ }
+ else
+ {
+ if (m_ptr->ml)
+ r_ptr->r_flags3 |= RF3_IM_FIRE;
+ }
+ }
+ if (p_ptr->shield && (p_ptr->shield_opt & SHIELD_GREAT_FIRE) && alive)
+ {
+ msg_format("%^s gets burned by your fiery shield!", m_name);
+ if (mon_take_hit(m_idx, damroll(p_ptr->shield_power_opt, p_ptr->shield_power_opt2), &fear,
+ " is burned by your fiery shield."))
+ {
+ blinked = FALSE;
+ alive = FALSE;
+ }
+ }
+ if (p_ptr->shield && (p_ptr->shield_opt & SHIELD_FEAR) && alive)
+ {
+ int tmp;
+
+ if ((!(r_ptr->flags1 & RF1_UNIQUE)) && (damroll(p_ptr->shield_power_opt, p_ptr->shield_power_opt2) - m_ptr->level > 0))
+ {
+ msg_format("%^s gets scared away!", m_name);
+
+ /* Increase fear */
+ tmp = m_ptr->monfear + p_ptr->shield_power_opt;
+ fear = TRUE;
+
+ /* Set fear */
+ m_ptr->monfear = (tmp < 200) ? tmp : 200;
+ }
+ }
+
+ touched = FALSE;
+ }
+ }
+
+ /* Monster missed player */
+ else
+ {
+ /* Analyze failed attacks */
+ switch (method)
+ {
+ case RBM_HIT:
+ case RBM_TOUCH:
+ case RBM_PUNCH:
+ case RBM_KICK:
+ case RBM_CLAW:
+ case RBM_BITE:
+ case RBM_STING:
+ case RBM_XXX1:
+ case RBM_BUTT:
+ case RBM_CRUSH:
+ case RBM_ENGULF:
+ case RBM_CHARGE:
+
+ /* Visible monsters */
+ if (m_ptr->ml)
+ {
+ /* Disturbing */
+ disturb(1, 0);
+
+ /* Message */
+ msg_format("%^s misses you.", m_name);
+ }
+
+ break;
+ }
+ }
+
+
+ /* Analyze "visible" monsters only */
+ if (visible)
+ {
+ /* Count "obvious" attacks (and ones that cause damage) */
+ if (obvious || damage || (r_ptr->r_blows[ap_cnt] > 10))
+ {
+ /* Count attacks of this type */
+ if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR)
+ {
+ r_ptr->r_blows[ap_cnt]++;
+ }
+ }
+ }
+ }
+
+
+ /* Blink away */
+ if (blinked)
+ {
+ msg_print("The thief flees laughing!");
+ teleport_away(m_idx, MAX_SIGHT * 2 + 5);
+ }
+
+
+ /* Always notice cause of death */
+ if (death && (r_ptr->r_deaths < MAX_SHORT))
+ {
+ r_ptr->r_deaths++;
+ }
+
+ if (m_ptr->ml && fear)
+ {
+ sound (SOUND_FLEE);
+ msg_format("%^s flees in terror!", m_name);
+ }
+
+ /* Assume we attacked */
+ return (TRUE);
+}
+
+
diff --git a/src/melee2.c b/src/melee2.c
new file mode 100644
index 00000000..6ada6bd0
--- /dev/null
+++ b/src/melee2.c
@@ -0,0 +1,7591 @@
+/* File: melee2.c */
+
+/* Purpose: Monster spells and movement */
+
+/*
+* Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+*
+* This software may be copied and distributed for educational, research, and
+* not for profit purposes provided that this copyright and statement are
+* included in all such copies.
+*/
+
+/*
+* This file has several additions to it by Keldon Jones (keldon@umr.edu)
+* to improve the general quality of the AI (version 0.1.1).
+*/
+
+#include "angband.h"
+
+#define SPEAK_CHANCE 8
+#define GRINDNOISE 20
+
+#define FOLLOW_DISTANCE 6
+
+/*
+ * Based on mon_take_hit... all monster attacks on
+ * other monsters should use
+ */
+bool_ mon_take_hit_mon(int s_idx, int m_idx, int dam, bool_ *fear, cptr note)
+{
+ monster_type *m_ptr = &m_list[m_idx], *s_ptr = &m_list[s_idx];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ s32b div, new_exp, new_exp_frac;
+
+ /* Redraw (later) if needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Some mosnters are immune to death */
+ if (r_ptr->flags7 & RF7_NO_DEATH) return FALSE;
+
+ /* Wake it up */
+ m_ptr->csleep = 0;
+
+ /* Hurt it */
+ m_ptr->hp -= dam;
+
+ /* It is dead now... or is it? */
+ if (m_ptr->hp < 0)
+ {
+ if (((r_ptr->flags1 & RF1_UNIQUE) && (m_ptr->status <= MSTATUS_NEUTRAL_P)) ||
+ (m_ptr->mflag & MFLAG_QUEST))
+ {
+ m_ptr->hp = 1;
+ }
+ else
+ {
+ char m_name[80];
+ s32b dive = s_ptr->level;
+
+ if (!dive) dive = 1;
+
+ /* Extract monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Make a sound */
+ if ((r_ptr->flags3 & RF3_DEMON) ||
+ (r_ptr->flags3 & RF3_UNDEAD) ||
+ (r_ptr->flags2 & RF2_STUPID) ||
+ (r_ptr->flags3 & RF3_NONLIVING) ||
+ (strchr("Evg", r_ptr->d_char)))
+ {
+ sound(SOUND_N_KILL);
+ }
+ else
+ {
+ sound(SOUND_KILL);
+ }
+
+ /* Death by Missile/Spell attack */
+ if (note)
+ {
+ cmonster_msg(TERM_L_RED, "%^s%s", m_name, note);
+ }
+ /* Death by Physical attack -- living monster */
+ else if (!m_ptr->ml)
+ {
+ /* Do nothing */
+ }
+ /* Death by Physical attack -- non-living monster */
+ else if ((r_ptr->flags3 & (RF3_DEMON)) ||
+ (r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags2 & (RF2_STUPID)) ||
+ (r_ptr->flags3 & (RF3_NONLIVING)) ||
+ (strchr("Evg", r_ptr->d_char)))
+ {
+ cmonster_msg(TERM_L_RED, "%^s is destroyed.", m_name);
+ }
+ else
+ {
+ cmonster_msg(TERM_L_RED, "%^s is killed.", m_name);
+ }
+
+ dive = r_ptr->mexp * m_ptr->level / dive;
+ if (!dive) dive = 1;
+
+ /* Monster gains some xp */
+ monster_gain_exp(s_idx, dive, FALSE);
+
+ /* Monster lore skill allows gaining xp from pets */
+ if (get_skill(SKILL_LORE) && (s_ptr->status >= MSTATUS_PET))
+ {
+ /* Maximum player level */
+ div = p_ptr->max_plv;
+
+ /* Give some experience for the kill */
+ new_exp = ((long)r_ptr->mexp * m_ptr->level) / div;
+
+ /* Handle fractional experience */
+ new_exp_frac = ((((long)r_ptr->mexp * m_ptr->level) % div)
+ * 0x10000L / div) + p_ptr->exp_frac;
+
+ /* Keep track of experience */
+ if (new_exp_frac >= 0x10000L)
+ {
+ new_exp++;
+ p_ptr->exp_frac = new_exp_frac - 0x10000;
+ }
+ else
+ {
+ p_ptr->exp_frac = new_exp_frac;
+ }
+
+ /*
+ * Factor the xp by the skill level
+ * Note that a score of 50 in the skill makes the gain be 120% of the exp
+ */
+ new_exp = new_exp * get_skill_scale(SKILL_LORE, 120) / 100;
+
+ /* Gain experience */
+ gain_exp(new_exp);
+ }
+
+ /* When an Unique dies, it stays dead */
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ r_ptr->max_num = 0;
+ }
+
+ /* Generate treasure */
+ monster_death(m_idx);
+
+ /* Delete the monster */
+ delete_monster_idx(m_idx);
+
+ /* Not afraid */
+ (*fear) = FALSE;
+
+ /* Monster is dead */
+ return (TRUE);
+ }
+
+ }
+
+#ifdef ALLOW_FEAR
+
+ /* Mega-Hack -- Pain cancels fear */
+ if (m_ptr->monfear && (dam > 0))
+ {
+ int tmp = randint(dam);
+
+ /* Cure a little fear */
+ if (tmp < m_ptr->monfear)
+ {
+ /* Reduce fear */
+ m_ptr->monfear -= tmp;
+ }
+
+ /* Cure all the fear */
+ else
+ {
+ /* Cure fear */
+ m_ptr->monfear = 0;
+
+ /* No more fear */
+ (*fear) = FALSE;
+ }
+ }
+
+ /* Sometimes a monster gets scared by damage */
+ if (!m_ptr->monfear && !(r_ptr->flags3 & (RF3_NO_FEAR)))
+ {
+ int percentage;
+
+ /* Percentage of fully healthy */
+ percentage = (100L * m_ptr->hp) / m_ptr->maxhp;
+
+ /*
+ * Run (sometimes) if at 10% or less of max hit points,
+ * or (usually) when hit for half its current hit points
+ */
+ if (((percentage <= 10) && (rand_int(10) < percentage)) ||
+ ((dam >= m_ptr->hp) && (rand_int(100) < 80)))
+ {
+ /* Hack -- note fear */
+ (*fear) = TRUE;
+
+ /* XXX XXX XXX Hack -- Add some timed fear */
+ m_ptr->monfear = (randint(10) +
+ (((dam >= m_ptr->hp) && (percentage > 7)) ?
+ 20 : ((11 - percentage) * 5)));
+ }
+ }
+
+#endif /* ALLOW_FEAR */
+
+ /* Not dead yet */
+ return (FALSE);
+}
+
+
+
+
+
+/*
+* And now for Intelligent monster attacks (including spells).
+*
+* Original idea and code by "DRS" (David Reeves Sward).
+* Major modifications by "BEN" (Ben Harrison).
+*
+* Give monsters more intelligent attack/spell selection based on
+* observations of previous attacks on the player, and/or by allowing
+* the monster to "cheat" and know the player status.
+*
+* Maintain an idea of the player status, and use that information
+* to occasionally eliminate "ineffective" spell attacks. We could
+* also eliminate ineffective normal attacks, but there is no reason
+* for the monster to do this, since he gains no benefit.
+* Note that MINDLESS monsters are not allowed to use this code.
+* And non-INTELLIGENT monsters only use it partially effectively.
+*
+* Actually learn what the player resists, and use that information
+* to remove attacks or spells before using them. This will require
+* much less space, if I am not mistaken. Thus, each monster gets a
+* set of 32 bit flags, "smart", build from the various "SM_*" flags.
+*
+* This has the added advantage that attacks and spells are related.
+* The "smart_learn" option means that the monster "learns" the flags
+* that should be set, and "smart_cheat" means that he "knows" them.
+* So "smart_cheat" means that the "smart" field is always up to date,
+* while "smart_learn" means that the "smart" field is slowly learned.
+* Both of them have the same effect on the "choose spell" routine.
+*/
+
+
+
+/*
+* Internal probability routine
+*/
+static bool_ int_outof(monster_race *r_ptr, int prob)
+{
+ /* Non-Smart monsters are half as "smart" */
+ if (!(r_ptr->flags2 & (RF2_SMART))) prob = prob / 2;
+
+ /* Roll the dice */
+ return (rand_int(100) < prob);
+}
+
+
+
+/*
+ * Remove the "bad" spells from a spell list
+ */
+static void remove_bad_spells(int m_idx, u32b *f4p, u32b *f5p, u32b *f6p)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ u32b f4 = (*f4p);
+ u32b f5 = (*f5p);
+ u32b f6 = (*f6p);
+
+ u32b smart = 0L;
+
+
+ /* Too stupid to know anything */
+ if (r_ptr->flags2 & (RF2_STUPID)) return;
+
+
+ /* Must be cheating or learning */
+ if (!smart_cheat && !smart_learn) return;
+
+
+ /* Update acquired knowledge */
+ if (smart_learn)
+ {
+ /* Hack -- Occasionally forget player status */
+ if (m_ptr->smart && (rand_int(100) < 1)) m_ptr->smart = 0L;
+
+ /* Use the memorized flags */
+ smart = m_ptr->smart;
+ }
+
+
+ /* Cheat if requested */
+ if (smart_cheat)
+ {
+ /* Know basic info */
+ if (p_ptr->resist_acid) smart |= (SM_RES_ACID);
+ if (p_ptr->oppose_acid) smart |= (SM_OPP_ACID);
+ if (p_ptr->immune_acid) smart |= (SM_IMM_ACID);
+ if (p_ptr->resist_elec) smart |= (SM_RES_ELEC);
+ if (p_ptr->oppose_elec) smart |= (SM_OPP_ELEC);
+ if (p_ptr->immune_elec) smart |= (SM_IMM_ELEC);
+ if (p_ptr->resist_fire) smart |= (SM_RES_FIRE);
+ if (p_ptr->oppose_fire) smart |= (SM_OPP_FIRE);
+ if (p_ptr->immune_fire) smart |= (SM_IMM_FIRE);
+ if (p_ptr->resist_cold) smart |= (SM_RES_COLD);
+ if (p_ptr->oppose_cold) smart |= (SM_OPP_COLD);
+ if (p_ptr->immune_cold) smart |= (SM_IMM_COLD);
+
+ /* Know poison info */
+ if (p_ptr->resist_pois) smart |= (SM_RES_POIS);
+ if (p_ptr->oppose_pois) smart |= (SM_OPP_POIS);
+
+ /* Know special resistances */
+ if (p_ptr->resist_neth) smart |= (SM_RES_NETH);
+ if (p_ptr->resist_lite) smart |= (SM_RES_LITE);
+ if (p_ptr->resist_dark) smart |= (SM_RES_DARK);
+ if (p_ptr->resist_fear) smart |= (SM_RES_FEAR);
+ if (p_ptr->resist_conf) smart |= (SM_RES_CONF);
+ if (p_ptr->resist_chaos) smart |= (SM_RES_CHAOS);
+ if (p_ptr->resist_disen) smart |= (SM_RES_DISEN);
+ if (p_ptr->resist_blind) smart |= (SM_RES_BLIND);
+ if (p_ptr->resist_nexus) smart |= (SM_RES_NEXUS);
+ if (p_ptr->resist_sound) smart |= (SM_RES_SOUND);
+ if (p_ptr->resist_shard) smart |= (SM_RES_SHARD);
+ if (p_ptr->reflect) smart |= (SM_IMM_REFLECT);
+
+ /* Know bizarre "resistances" */
+ if (p_ptr->free_act) smart |= (SM_IMM_FREE);
+ if (!p_ptr->msp) smart |= (SM_IMM_MANA);
+ }
+
+
+ /* Nothing known */
+ if (!smart) return;
+
+
+ if (smart & (SM_IMM_ACID))
+ {
+ if (int_outof(r_ptr, 100)) f4 &= ~(RF4_BR_ACID);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BA_ACID);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_ACID);
+ }
+ else if ((smart & (SM_OPP_ACID)) && (smart & (SM_RES_ACID)))
+ {
+ if (int_outof(r_ptr, 80)) f4 &= ~(RF4_BR_ACID);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BA_ACID);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BO_ACID);
+ }
+ else if ((smart & (SM_OPP_ACID)) || (smart & (SM_RES_ACID)))
+ {
+ if (int_outof(r_ptr, 30)) f4 &= ~(RF4_BR_ACID);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BA_ACID);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BO_ACID);
+ }
+
+
+ if (smart & (SM_IMM_ELEC))
+ {
+ if (int_outof(r_ptr, 100)) f4 &= ~(RF4_BR_ELEC);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BA_ELEC);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_ELEC);
+ }
+ else if ((smart & (SM_OPP_ELEC)) && (smart & (SM_RES_ELEC)))
+ {
+ if (int_outof(r_ptr, 80)) f4 &= ~(RF4_BR_ELEC);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BA_ELEC);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BO_ELEC);
+ }
+ else if ((smart & (SM_OPP_ELEC)) || (smart & (SM_RES_ELEC)))
+ {
+ if (int_outof(r_ptr, 30)) f4 &= ~(RF4_BR_ELEC);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BA_ELEC);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BO_ELEC);
+ }
+
+
+ if (smart & (SM_IMM_FIRE))
+ {
+ if (int_outof(r_ptr, 100)) f4 &= ~(RF4_BR_FIRE);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BA_FIRE);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_FIRE);
+ }
+ else if ((smart & (SM_OPP_FIRE)) && (smart & (SM_RES_FIRE)))
+ {
+ if (int_outof(r_ptr, 80)) f4 &= ~(RF4_BR_FIRE);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BA_FIRE);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BO_FIRE);
+ }
+ else if ((smart & (SM_OPP_FIRE)) || (smart & (SM_RES_FIRE)))
+ {
+ if (int_outof(r_ptr, 30)) f4 &= ~(RF4_BR_FIRE);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BA_FIRE);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BO_FIRE);
+ }
+
+
+ if (smart & (SM_IMM_COLD))
+ {
+ if (int_outof(r_ptr, 100)) f4 &= ~(RF4_BR_COLD);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BA_COLD);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_COLD);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_ICEE);
+ }
+ else if ((smart & (SM_OPP_COLD)) && (smart & (SM_RES_COLD)))
+ {
+ if (int_outof(r_ptr, 80)) f4 &= ~(RF4_BR_COLD);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BA_COLD);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BO_COLD);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BO_ICEE);
+ }
+ else if ((smart & (SM_OPP_COLD)) || (smart & (SM_RES_COLD)))
+ {
+ if (int_outof(r_ptr, 30)) f4 &= ~(RF4_BR_COLD);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BA_COLD);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BO_COLD);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BO_ICEE);
+ }
+
+
+ if ((smart & (SM_OPP_POIS)) && (smart & (SM_RES_POIS)))
+ {
+ if (int_outof(r_ptr, 80)) f4 &= ~(RF4_BR_POIS);
+ if (int_outof(r_ptr, 80)) f5 &= ~(RF5_BA_POIS);
+ if (int_outof(r_ptr, 40)) f4 &= ~(RF4_BA_NUKE);
+ if (int_outof(r_ptr, 40)) f4 &= ~(RF4_BR_NUKE);
+ }
+ else if ((smart & (SM_OPP_POIS)) || (smart & (SM_RES_POIS)))
+ {
+ if (int_outof(r_ptr, 30)) f4 &= ~(RF4_BR_POIS);
+ if (int_outof(r_ptr, 30)) f5 &= ~(RF5_BA_POIS);
+ }
+
+
+ if (smart & (SM_RES_NETH))
+ {
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BR_NETH);
+ if (int_outof(r_ptr, 50)) f5 &= ~(RF5_BA_NETH);
+ if (int_outof(r_ptr, 50)) f5 &= ~(RF5_BO_NETH);
+ }
+
+ if (smart & (SM_RES_LITE))
+ {
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BR_LITE);
+ }
+
+ if (smart & (SM_RES_DARK))
+ {
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BR_DARK);
+ if (int_outof(r_ptr, 50)) f5 &= ~(RF5_BA_DARK);
+ }
+
+ if (smart & (SM_RES_FEAR))
+ {
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_SCARE);
+ }
+
+ if (smart & (SM_RES_CONF))
+ {
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_CONF);
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BR_CONF);
+ }
+
+ if (smart & (SM_RES_CHAOS))
+ {
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_CONF);
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BR_CONF);
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BR_CHAO);
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BA_CHAO);
+ }
+
+ if (smart & (SM_RES_DISEN))
+ {
+ if (int_outof(r_ptr, 100)) f4 &= ~(RF4_BR_DISE);
+ }
+
+ if (smart & (SM_RES_BLIND))
+ {
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BLIND);
+ }
+
+ if (smart & (SM_RES_NEXUS))
+ {
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BR_NEXU);
+ if (int_outof(r_ptr, 50)) f6 &= ~(RF6_TELE_LEVEL);
+ }
+
+ if (smart & (SM_RES_SOUND))
+ {
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BR_SOUN);
+ }
+
+ if (smart & (SM_RES_SHARD))
+ {
+ if (int_outof(r_ptr, 50)) f4 &= ~(RF4_BR_SHAR);
+ if (int_outof(r_ptr, 20)) f4 &= ~(RF4_ROCKET);
+ }
+
+ if (smart & (SM_IMM_REFLECT))
+ {
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_COLD);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_FIRE);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_ACID);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_ELEC);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_POIS);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_NETH);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_WATE);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_MANA);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_PLAS);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_BO_ICEE);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_MISSILE);
+ if (int_outof(r_ptr, 100)) f4 &= ~(RF4_ARROW_1);
+ if (int_outof(r_ptr, 100)) f4 &= ~(RF4_ARROW_2);
+ if (int_outof(r_ptr, 100)) f4 &= ~(RF4_ARROW_3);
+ if (int_outof(r_ptr, 100)) f4 &= ~(RF4_ARROW_4);
+ }
+
+ if (smart & (SM_IMM_FREE))
+ {
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_HOLD);
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_SLOW);
+ }
+
+ if (smart & (SM_IMM_MANA))
+ {
+ if (int_outof(r_ptr, 100)) f5 &= ~(RF5_DRAIN_MANA);
+ }
+
+ /* XXX XXX XXX No spells left? */
+ /* if (!f4 && !f5 && !f6) ... */
+
+ (*f4p) = f4;
+ (*f5p) = f5;
+ (*f6p) = f6;
+}
+
+
+/*
+ * Determine if there is a space near the player in which
+ * a summoned creature can appear
+ */
+static bool_ summon_possible(int y1, int x1)
+{
+ int y, x;
+
+ /* Start at the player's location, and check 2 grids in each dir */
+ for (y = y1 - 2; y <= y1 + 2; y++)
+ {
+ for (x = x1 - 2; x <= x1 + 2; x++)
+ {
+ /* Ignore illegal locations */
+ if (!in_bounds(y, x)) continue;
+
+ /* Only check a circular area */
+ if (distance(y1, x1, y, x) > 2) continue;
+
+ /* Hack: no summon on glyph of warding */
+ if (cave[y][x].feat == FEAT_GLYPH) continue;
+ if (cave[y][x].feat == FEAT_MINOR_GLYPH) continue;
+
+ /* Nor on the between */
+ if (cave[y][x].feat == FEAT_BETWEEN) return (FALSE);
+
+ /* ...nor on the Pattern */
+ if ((cave[y][x].feat >= FEAT_PATTERN_START)
+ && (cave[y][x].feat <= FEAT_PATTERN_XTRA2)) continue;
+
+ /* Require empty floor grid in line of sight */
+ if (cave_empty_bold(y, x) && los(y1, x1, y, x)) return (TRUE);
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+/*
+ * Determine if a bolt spell will hit the player.
+ *
+ * This is exactly like "projectable", but it will return FALSE if a monster
+ * is in the way.
+ */
+static bool_ clean_shot(int y1, int x1, int y2, int x2)
+{
+ int dist, y, x;
+
+ /* Start at the initial location */
+ y = y1, x = x1;
+
+ /* See "project()" and "projectable()" */
+ for (dist = 0; dist <= MAX_RANGE; dist++)
+ {
+ /* Never pass through walls */
+ if (dist && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x))) break;
+
+ /* Never pass through monsters */
+ if (dist && cave[y][x].m_idx > 0)
+ {
+ if (is_friend(&m_list[cave[y][x].m_idx]) < 0) break;
+ }
+
+ /* Check for arrival at "final target" */
+ if ((x == x2) && (y == y2)) return (TRUE);
+
+ /* Calculate the new location */
+ mmove2(&y, &x, y1, x1, y2, x2);
+ }
+
+ /* Assume obstruction */
+ return (FALSE);
+}
+
+
+/*
+ * Cast a bolt at the player
+ * Stop if we hit a monster
+ * Affect monsters and the player
+ */
+static void bolt(int m_idx, int typ, int dam_hp)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+
+ /* Target the player with a bolt attack */
+ (void)project(m_idx, 0, p_ptr->py, p_ptr->px, dam_hp, typ, flg);
+}
+
+
+/*
+ * Return TRUE if a spell is good for hurting the player (directly).
+ */
+static bool_ spell_attack(byte spell)
+{
+ /* All RF4 spells hurt (except for shriek, multiply, summon animal) */
+ if (spell >= 96 + 3 && spell <= 96 + 31) return (TRUE);
+
+ /* Various "ball" spells */
+ if (spell >= 128 && spell <= 128 + 8) return (TRUE);
+
+ /* "Cause wounds" and "bolt" spells */
+ if (spell >= 128 + 12 && spell <= 128 + 26) return (TRUE);
+
+ /* Hand of Doom */
+ if (spell == 160 + 1) return (TRUE);
+
+ /* Doesn't hurt */
+ return (FALSE);
+}
+
+
+/*
+ * Return TRUE if a spell is good for escaping.
+ */
+static bool_ spell_escape(byte spell)
+{
+ /* Blink or Teleport */
+ if (spell == 160 + 4 || spell == 160 + 5) return (TRUE);
+
+ /* Teleport the player away */
+ if (spell == 160 + 7 || spell == 160 + 8) return (TRUE);
+
+ /* Isn't good for escaping */
+ return (FALSE);
+}
+
+/*
+ * Return TRUE if a spell is good for annoying the player.
+ */
+static bool_ spell_annoy(byte spell)
+{
+ /* Shriek */
+ if (spell == 96 + 0) return (TRUE);
+
+ /* Brain smash, et al (added curses) */
+ if (spell >= 128 + 9 && spell <= 128 + 14) return (TRUE);
+
+ /* Scare, confuse, blind, slow, paralyze */
+ if (spell >= 128 + 27 && spell <= 128 + 31) return (TRUE);
+
+ /* Teleport to */
+ if (spell == 160 + 6) return (TRUE);
+
+ /* Darkness, make traps, cause amnesia */
+ if (spell >= 160 + 9 && spell <= 160 + 11) return (TRUE);
+
+ /* Doesn't annoy */
+ return (FALSE);
+}
+
+/*
+ * Return TRUE if a spell summons help.
+ */
+static bool_ spell_summon(byte spell)
+{
+ /* RF4_S_ANIMAL, RF6_S_ANIMALS */
+ if (spell == 96 + 2 || spell == 160 + 3) return (TRUE);
+ /* All other summon spells */
+ if (spell >= 160 + 13 && spell <= 160 + 31) return (TRUE);
+
+ /* Doesn't summon */
+ return (FALSE);
+}
+
+
+/*
+ * Return TRUE if a spell is good in a tactical situation.
+ */
+static bool_ spell_tactic(byte spell)
+{
+ /* Blink */
+ if (spell == 160 + 4) return (TRUE);
+
+ /* Not good */
+ return (FALSE);
+}
+
+
+/*
+ * Return TRUE if a spell hastes.
+ */
+static bool_ spell_haste(byte spell)
+{
+ /* Haste self */
+ if (spell == 160 + 0) return (TRUE);
+
+ /* Not a haste spell */
+ return (FALSE);
+}
+
+
+/*
+ * Return TRUE if a spell is good for healing.
+ */
+static bool_ spell_heal(byte spell)
+{
+ /* Heal */
+ if (spell == 160 + 2) return (TRUE);
+
+ /* No healing */
+ return (FALSE);
+}
+
+
+/*
+ * Have a monster choose a spell from a list of "useful" spells.
+ *
+ * Note that this list does NOT include spells that will just hit
+ * other monsters, and the list is restricted when the monster is
+ * "desperate". Should that be the job of this function instead?
+ *
+ * Stupid monsters will just pick a spell randomly. Smart monsters
+ * will choose more "intelligently".
+ *
+ * Use the helper functions above to put spells into categories.
+ *
+ * This function may well be an efficiency bottleneck.
+ */
+static int choose_attack_spell(int m_idx, byte spells[], byte num)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ byte escape[96], escape_num = 0;
+ byte attack[96], attack_num = 0;
+ byte summon[96], summon_num = 0;
+ byte tactic[96], tactic_num = 0;
+ byte annoy[96], annoy_num = 0;
+ byte haste[96], haste_num = 0;
+ byte heal[96], heal_num = 0;
+
+ int i;
+
+ /* Stupid monsters choose randomly */
+ if (r_ptr->flags2 & (RF2_STUPID))
+ {
+ /* Pick at random */
+ return (spells[rand_int(num)]);
+ }
+
+ /* Categorize spells */
+ for (i = 0; i < num; i++)
+ {
+ /* Escape spell? */
+ if (spell_escape(spells[i])) escape[escape_num++] = spells[i];
+
+ /* Attack spell? */
+ if (spell_attack(spells[i])) attack[attack_num++] = spells[i];
+
+ /* Summon spell? */
+ if (spell_summon(spells[i])) summon[summon_num++] = spells[i];
+
+ /* Tactical spell? */
+ if (spell_tactic(spells[i])) tactic[tactic_num++] = spells[i];
+
+ /* Annoyance spell? */
+ if (spell_annoy(spells[i])) annoy[annoy_num++] = spells[i];
+
+ /* Haste spell? */
+ if (spell_haste(spells[i])) haste[haste_num++] = spells[i];
+
+ /* Heal spell? */
+ if (spell_heal(spells[i])) heal[heal_num++] = spells[i];
+ }
+
+ /*** Try to pick an appropriate spell type ***/
+
+ /* Hurt badly or afraid, attempt to flee */
+ if ((m_ptr->hp < m_ptr->maxhp / 3) || m_ptr->monfear)
+ {
+ /* Choose escape spell if possible */
+ if (escape_num) return (escape[rand_int(escape_num)]);
+ }
+
+ /* Still hurt badly, couldn't flee, attempt to heal */
+ if (m_ptr->hp < m_ptr->maxhp / 3)
+ {
+ /* Choose heal spell if possible */
+ if (heal_num) return (heal[rand_int(heal_num)]);
+ }
+
+ /* Player is close and we have attack spells, blink away */
+ if ((distance(p_ptr->py, p_ptr->px, m_ptr->fy, m_ptr->fx) < 4) && attack_num && (rand_int(100) < 75))
+ {
+ /* Choose tactical spell */
+ if (tactic_num) return (tactic[rand_int(tactic_num)]);
+ }
+
+ /* We're hurt (not badly), try to heal */
+ if ((m_ptr->hp < m_ptr->maxhp * 3 / 4) && (rand_int(100) < 75))
+ {
+ /* Choose heal spell if possible */
+ if (heal_num) return (heal[rand_int(heal_num)]);
+ }
+
+ /* Summon if possible (sometimes) */
+ if (summon_num && (rand_int(100) < 50))
+ {
+ /* Choose summon spell */
+ return (summon[rand_int(summon_num)]);
+ }
+
+ /* Attack spell (most of the time) */
+ if (attack_num && (rand_int(100) < 85))
+ {
+ /* Choose attack spell */
+ return (attack[rand_int(attack_num)]);
+ }
+
+ /* Try another tactical spell (sometimes) */
+ if (tactic_num && (rand_int(100) < 50))
+ {
+ /* Choose tactic spell */
+ return (tactic[rand_int(tactic_num)]);
+ }
+
+ /* Haste self if we aren't already somewhat hasted (rarely) */
+ if (haste_num && (rand_int(100) < (20 + m_ptr->speed - m_ptr->mspeed)))
+ {
+ /* Choose haste spell */
+ return (haste[rand_int(haste_num)]);
+ }
+
+ /* Annoy player (most of the time) */
+ if (annoy_num && (rand_int(100) < 85))
+ {
+ /* Choose annoyance spell */
+ return (annoy[rand_int(annoy_num)]);
+ }
+
+ /* Choose no spell */
+ return (0);
+}
+
+
+/*
+ * Cast a breath (or ball) attack at the player
+ * Pass over any monsters that may be in the way
+ * Affect grids, objects, monsters, and the player
+ */
+static void breath(int m_idx, int typ, int dam_hp, int rad)
+{
+ int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Determine the radius of the blast */
+ if (rad < 1) rad = (r_ptr->flags2 & (RF2_POWERFUL)) ? 3 : 2;
+
+ /* Target the player with a ball attack */
+ (void)project(m_idx, rad, p_ptr->py, p_ptr->px, dam_hp, typ, flg);
+}
+
+
+/*
+ * Monster casts a breath (or ball) attack at another monster.
+ * Pass over any monsters that may be in the way
+ * Affect grids, objects, monsters, and the player
+ */
+static void monst_breath_monst(int m_idx, int y, int x, int typ, int dam_hp, int rad)
+{
+ int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Determine the radius of the blast */
+ if (rad < 1) rad = (r_ptr->flags2 & (RF2_POWERFUL)) ? 3 : 2;
+
+ (void)project(m_idx, rad, y, x, dam_hp, typ, flg);
+}
+
+
+/*
+ * Monster casts a bolt at another monster
+ * Stop if we hit a monster
+ * Affect monsters and the player
+ */
+static void monst_bolt_monst(int m_idx, int y, int x, int typ, int dam_hp)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+
+ (void)project(m_idx, 0, y, x, dam_hp, typ, flg);
+}
+
+
+void monster_msg(cptr fmt, ...)
+{
+ va_list vp;
+
+ char buf[1024];
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Format the args, save the length */
+ (void)vstrnfmt(buf, 1024, fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Display */
+ if (disturb_other)
+ msg_print(buf);
+ else
+ {
+ message_add(MESSAGE_MSG, buf, TERM_WHITE);
+ p_ptr->window |= PW_MESSAGE;
+ }
+}
+
+void cmonster_msg(char a, cptr fmt, ...)
+{
+ va_list vp;
+
+ char buf[1024];
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Format the args, save the length */
+ (void)vstrnfmt(buf, 1024, fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Display */
+ if (disturb_other)
+ cmsg_print(a, buf);
+ else
+ {
+ message_add(MESSAGE_MSG, buf, a);
+ p_ptr->window |= PW_MESSAGE;
+ }
+}
+
+
+/*
+ * Monster tries to 'cast a spell' (or breath, etc)
+ * at another monster.
+ */
+int monst_spell_monst_spell = -1;
+static bool_ monst_spell_monst(int m_idx)
+{
+ int y = 0, x = 0;
+ int i = 1, k, t_idx;
+ int chance, thrown_spell, count = 0;
+ byte spell[96], num = 0;
+ char m_name[80], t_name[80];
+ char m_poss[80];
+ char ddesc[80];
+ int rlev; /* monster level */
+ monster_type *m_ptr = &m_list[m_idx]; /* Attacker */
+ monster_race *r_ptr = race_inf(m_ptr);
+ monster_type *t_ptr; /* Putative target */
+ monster_race *tr_ptr;
+ u32b f4, f5, f6; /* racial spell flags */
+ bool_ direct = TRUE;
+ bool_ wake_up = FALSE;
+
+ /* Extract the blind-ness */
+ bool_ blind = (p_ptr->blind ? TRUE : FALSE);
+
+ /* Extract the "see-able-ness" */
+ bool_ seen = (!blind && m_ptr->ml);
+
+ bool_ see_m;
+ bool_ see_t;
+ bool_ see_either;
+ bool_ see_both;
+
+ bool_ friendly = FALSE;
+
+ if (is_friend(m_ptr) > 0) friendly = TRUE;
+
+ /* Cannot cast spells when confused */
+ if (m_ptr->confused) return (FALSE);
+
+ /* Hack -- Extract the spell probability */
+ chance = (r_ptr->freq_inate + r_ptr->freq_spell) / 2;
+
+ /* Not allowed to cast spells */
+ if ((!chance) && (monst_spell_monst_spell == -1)) return (FALSE);
+
+ if ((rand_int(100) >= chance) && (monst_spell_monst_spell == -1)) return (FALSE);
+
+ /* Target location */
+ if (m_ptr->target > -1)
+ {
+ if (m_ptr->target > 0)
+ {
+ i = m_ptr->target;
+ }
+ else return FALSE;
+ }
+ else return FALSE;
+
+
+ {
+ t_idx = i;
+ t_ptr = &m_list[t_idx];
+ tr_ptr = race_inf(t_ptr);
+
+ /* Hack -- no fighting >100 squares from player */
+ if (t_ptr->cdis > MAX_RANGE) return FALSE;
+
+ /* Monster must be projectable */
+ if (!projectable(m_ptr->fy, m_ptr->fx, t_ptr->fy, t_ptr->fx)) return FALSE;
+
+ /* OK -- we-ve got a target */
+ y = t_ptr->fy;
+ x = t_ptr->fx;
+
+ /* Extract the monster level */
+ rlev = ((m_ptr->level >= 1) ? m_ptr->level : 1);
+
+ /* Extract the racial spell flags */
+ f4 = r_ptr->flags4;
+ f5 = r_ptr->flags5;
+ f6 = r_ptr->flags6;
+
+ /* Hack -- allow "desperate" spells */
+ if ((r_ptr->flags2 & (RF2_SMART)) &&
+ (m_ptr->hp < m_ptr->maxhp / 10) &&
+ (rand_int(100) < 50))
+ {
+ /* Require intelligent spells */
+ f4 &= (RF4_INT_MASK);
+ f5 &= (RF5_INT_MASK);
+ f6 &= (RF6_INT_MASK);
+
+ /* No spells left */
+ if ((!f4 && !f5 && !f6) && (monst_spell_monst_spell == -1)) return (FALSE);
+ }
+
+ /* Extract the "inate" spells */
+ for (k = 0; k < 32; k++)
+ {
+ if (f4 & (1L << k)) spell[num++] = k + 32 * 3;
+ }
+
+ /* Extract the "normal" spells */
+ for (k = 0; k < 32; k++)
+ {
+ if (f5 & (1L << k)) spell[num++] = k + 32 * 4;
+ }
+
+ /* Extract the "bizarre" spells */
+ for (k = 0; k < 32; k++)
+ {
+ if (f6 & (1L << k)) spell[num++] = k + 32 * 5;
+ }
+
+ /* No spells left */
+ if (!num) return (FALSE);
+
+ /* Stop if player is dead or gone */
+ if (!alive || death) return (FALSE);
+
+ /* Handle "leaving" */
+ if (p_ptr->leaving) return (FALSE);
+
+ /* Get the monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0x00);
+
+ /* Get the monster possessive ("his"/"her"/"its") */
+ monster_desc(m_poss, m_ptr, 0x22);
+
+ /* Get the target's name (or "it") */
+ monster_desc(t_name, t_ptr, 0x00);
+
+ /* Hack -- Get the "died from" name */
+ monster_desc(ddesc, m_ptr, 0x88);
+
+ /* Choose a spell to cast */
+ thrown_spell = spell[rand_int(num)];
+
+ /* Force a spell ? */
+ if (monst_spell_monst_spell > -1)
+ {
+ thrown_spell = monst_spell_monst_spell;
+ monst_spell_monst_spell = -1;
+ }
+
+ see_m = seen;
+ see_t = (!blind && t_ptr->ml);
+ see_either = (see_m || see_t);
+ see_both = (see_m && see_t);
+
+ switch (thrown_spell)
+ {
+ /* RF4_SHRIEK */
+ case 96 + 0:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (!see_m) monster_msg("You hear a shriek.");
+ else monster_msg("%^s shrieks at %s.", m_name, t_name);
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF4_MULTIPLY */
+ case 96 + 1:
+ {
+ break;
+ }
+
+ /* RF4_S_ANIMAL */
+ case 96 + 2:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons an animal!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_ANIMAL, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_ANIMAL);
+ }
+ if (blind && count) monster_msg("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF4_ROCKET */
+ case 96 + 3:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear an explosion!");
+ else if (blind) monster_msg("%^s shoots something.", m_name);
+ else monster_msg("%^s fires a rocket at %s.", m_name, t_name);
+ monst_breath_monst(m_idx, y, x, GF_ROCKET,
+ ((m_ptr->hp / 4) > 800 ? 800 : (m_ptr->hp / 4)), 2);
+ break;
+ }
+
+ /* RF4_ARROW_1 */
+ case 96 + 4:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear a strange noise.");
+ else if (blind) monster_msg("%^s makes a strange noise.", m_name);
+ else monster_msg("%^s fires an arrow at %s.", m_name, t_name);
+ sound(SOUND_SHOOT);
+ monst_bolt_monst(m_idx, y, x, GF_ARROW, damroll(1, 6));
+ break;
+ }
+
+ /* RF4_ARROW_2 */
+ case 96 + 5:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear a strange noise.");
+ else if (blind) monster_msg("%^s makes a strange noise.", m_name);
+ else monster_msg("%^s fires an arrow at %s.", m_name, t_name);
+ sound(SOUND_SHOOT);
+ monst_bolt_monst(m_idx, y, x, GF_ARROW, damroll(3, 6));
+ break;
+ }
+
+ /* RF4_ARROW_3 */
+ case 96 + 6:
+ {
+ if (disturb_other) disturb(1, 0);
+
+ if (!see_either) monster_msg("You hear a strange noise.");
+ else if (blind) monster_msg("%^s makes a strange noise.", m_name);
+ else monster_msg("%^s fires a missile at %s.", m_name, t_name);
+ sound(SOUND_SHOOT);
+ monst_bolt_monst(m_idx, y, x, GF_ARROW, damroll(5, 6));
+ break;
+ }
+
+ /* RF4_ARROW_4 */
+ case 96 + 7:
+ {
+ if (!see_either) monster_msg("You hear a strange noise.");
+ else if (disturb_other) disturb(1, 0);
+ if (blind) monster_msg("%^s makes a strange noise.", m_name);
+ else monster_msg("%^s fires a missile at %s.", m_name, t_name);
+ sound(SOUND_SHOOT);
+ monst_bolt_monst(m_idx, y, x, GF_ARROW, damroll(7, 6));
+ break;
+ }
+
+ /* RF4_BR_ACID */
+ case 96 + 8:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes acid at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_ACID,
+ ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_ELEC */
+ case 96 + 9:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes lightning at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_ELEC,
+ ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_FIRE */
+ case 96 + 10:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes fire at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_FIRE,
+ ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_COLD */
+ case 96 + 11:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes frost at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_COLD,
+ ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_POIS */
+ case 96 + 12:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes gas at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_POIS,
+ ((m_ptr->hp / 3) > 800 ? 800 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_NETH */
+ case 96 + 13:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes nether at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_NETHER,
+ ((m_ptr->hp / 6) > 550 ? 550 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_LITE */
+ case 96 + 14:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes light at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_LITE,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_DARK */
+ case 96 + 15:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes darkness at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_DARK,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_CONF */
+ case 96 + 16:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes confusion at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_CONFUSION,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_SOUN */
+ case 96 + 17:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes sound at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_SOUND,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_CHAO */
+ case 96 + 18:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes chaos at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_CHAOS,
+ ((m_ptr->hp / 6) > 600 ? 600 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_DISE */
+ case 96 + 19:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes disenchantment at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_DISENCHANT,
+ ((m_ptr->hp / 6) > 500 ? 500 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_NEXU */
+ case 96 + 20:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes nexus at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_NEXUS,
+ ((m_ptr->hp / 3) > 250 ? 250 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_TIME */
+ case 96 + 21:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes time at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_TIME,
+ ((m_ptr->hp / 3) > 150 ? 150 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_INER */
+ case 96 + 22:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes inertia at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_INERTIA,
+ ((m_ptr->hp / 6) > 200 ? 200 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_GRAV */
+ case 96 + 23:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes gravity at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_GRAVITY,
+ ((m_ptr->hp / 3) > 200 ? 200 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_SHAR */
+ case 96 + 24:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes shards at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_SHARDS,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_PLAS */
+ case 96 + 25:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes plasma at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_PLASMA,
+ ((m_ptr->hp / 6) > 150 ? 150 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_WALL */
+ case 96 + 26:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes force at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_FORCE,
+ ((m_ptr->hp / 6) > 200 ? 200 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_MANA */
+ case 96 + 27:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes magical energy at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_MANA,
+ ((m_ptr->hp / 3) > 250 ? 250 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BA_NUKE */
+ case 96 + 28:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear someone mumble.");
+ else if (blind) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a ball of radiation at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_NUKE,
+ (rlev + damroll(10, 6)), 2);
+ break;
+ }
+
+ /* RF4_BR_NUKE */
+ case 96 + 29:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes toxic waste at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_NUKE,
+ ((m_ptr->hp / 3) > 800 ? 800 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BA_CHAO */
+ case 96 + 30:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear someone mumble frighteningly.");
+ else if (blind) monster_msg("%^s mumbles frighteningly.", m_name);
+ else monster_msg("%^s invokes a raw Chaos upon %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_CHAOS,
+ (rlev * 2) + damroll(10, 10), 4);
+ break;
+ }
+
+ /* RF4_BR_DISI -> Breathe Disintegration */
+ case 96 + 31:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg("You hear breathing noise.");
+ else if (blind) monster_msg("%^s breathes.", m_name);
+ else monster_msg("%^s breathes disintegration at %s.", m_name, t_name);
+ sound(SOUND_BREATH);
+ monst_breath_monst(m_idx, y, x, GF_DISINTEGRATE,
+ ((m_ptr->hp / 3) > 300 ? 300 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF5_BA_ACID */
+ case 128 + 0:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg ("You hear someone mumble.");
+ else if (blind) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts an acid ball at %s.", m_name, t_name);
+ monst_breath_monst(m_idx, y, x, GF_ACID, randint(rlev * 3) + 15, 2);
+ break;
+ }
+
+ /* RF5_BA_ELEC */
+ case 128 + 1:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg ("You hear someone mumble.");
+ else
+ if (blind) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a lightning ball at %s.", m_name, t_name);
+ monst_breath_monst(m_idx, y, x, GF_ELEC, randint(rlev * 3 / 2) + 8, 2);
+ break;
+ }
+
+ /* RF5_BA_FIRE */
+ case 128 + 2:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg ("You hear someone mumble.");
+ else
+ if (blind) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a fire ball at %s.", m_name, t_name);
+ monst_breath_monst(m_idx, y, x, GF_FIRE, randint(rlev * 7 / 2) + 10, 2);
+ break;
+ }
+
+ /* RF5_BA_COLD */
+ case 128 + 3:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg ("You hear someone mumble.");
+ else
+ if (blind) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a frost ball at %s.", m_name, t_name);
+ monst_breath_monst(m_idx, y, x, GF_COLD, randint(rlev * 3 / 2) + 10, 2);
+ break;
+ }
+
+ /* RF5_BA_POIS */
+ case 128 + 4:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg ("You hear someone mumble.");
+ else
+ if (blind) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a stinking cloud at %s.", m_name, t_name);
+ monst_breath_monst(m_idx, y, x, GF_POIS, damroll(12, 2), 2);
+ break;
+ }
+
+ /* RF5_BA_NETH */
+ case 128 + 5:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg ("You hear someone mumble.");
+ else
+ if (blind) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a nether ball at %s.", m_name, t_name);
+ monst_breath_monst(m_idx, y, x, GF_NETHER, (50 + damroll(10, 10) + rlev), 2);
+ break;
+ }
+
+ /* RF5_BA_WATE */
+ case 128 + 6:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg ("You hear someone mumble.");
+ else
+ if (blind) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s gestures fluidly at %s.", m_name, t_name);
+ monster_msg("%^s is engulfed in a whirlpool.", t_name);
+ monst_breath_monst(m_idx, y, x, GF_WATER, randint(rlev * 5 / 2) + 50, 4);
+ break;
+ }
+
+ /* RF5_BA_MANA */
+ case 128 + 7:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg ("You hear someone mumble powerfully.");
+ else
+ if (blind) monster_msg("%^s mumbles powerfully.", m_name);
+ else monster_msg("%^s invokes a mana storm upon %s.", m_name, t_name);
+ monst_breath_monst(m_idx, y, x, GF_MANA, (rlev * 5) + damroll(10, 10), 4);
+ break;
+ }
+
+ /* RF5_BA_DARK */
+ case 128 + 8:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (!see_either) monster_msg ("You hear someone mumble powerfully.");
+ else
+ if (blind) monster_msg("%^s mumbles powerfully.", m_name);
+ else monster_msg("%^s invokes a darkness storm upon %s.", m_name, t_name);
+ monst_breath_monst(m_idx, y, x, GF_DARK, (rlev * 5) + damroll(10, 10), 4);
+ break;
+ }
+
+ /* RF5_DRAIN_MANA */
+ case 128 + 9:
+ {
+ /* Attack power */
+ int r1 = (randint(rlev) / 2) + 1;
+
+ if (see_m)
+ {
+ /* Basic message */
+ monster_msg("%^s draws psychic energy from %s.", m_name, t_name);
+ }
+
+ /* Heal the monster */
+ if (m_ptr->hp < m_ptr->maxhp)
+ {
+ if (!(tr_ptr->flags4 || tr_ptr->flags5 || tr_ptr->flags6))
+ {
+ if (see_both)
+ monster_msg("%^s is unaffected!", t_name);
+ }
+ else
+ {
+ /* Heal */
+ m_ptr->hp += (6 * r1);
+ if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
+
+ /* Redraw (later) if needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Special message */
+ if (seen)
+ {
+ monster_msg("%^s appears healthier.", m_name);
+ }
+ }
+ }
+
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_MIND_BLAST */
+ case 128 + 10:
+ {
+ if (!direct) break;
+
+ if (disturb_other) disturb(1, 0);
+
+ if (!seen)
+ {
+ /* */
+ }
+ else
+ {
+ monster_msg("%^s gazes intently at %s.", m_name, t_name);
+ }
+
+ /* Attempt a saving throw */
+ if ((tr_ptr->flags1 & (RF1_UNIQUE)) ||
+ (tr_ptr->flags3 & (RF3_NO_CONF)) ||
+ (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10))
+ {
+ /* Memorize a flag */
+ if (tr_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) tr_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ /* No obvious effect */
+ if (see_t)
+ {
+ monster_msg("%^s is unaffected!", t_name);
+ }
+ }
+ else
+ {
+ bool_ fear;
+ monster_msg("%^s is blasted by psionic energy.", t_name);
+ t_ptr->confused += rand_int(4) + 4;
+
+ mon_take_hit_mon(m_idx, t_idx, damroll(8, 8), &fear, " collapses, a mindless husk.");
+ }
+
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_BRAIN_SMASH */
+ case 128 + 11:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (!seen)
+ {
+ /* */
+ }
+ else
+ {
+ monster_msg("%^s gazes intently at %s.", m_name, t_name);
+ }
+
+ /* Attempt a saving throw */
+ if ((tr_ptr->flags1 & (RF1_UNIQUE)) ||
+ (tr_ptr->flags3 & (RF3_NO_CONF)) ||
+ (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10))
+ {
+ /* Memorize a flag */
+ if (tr_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) tr_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+ /* No obvious effect */
+ if (see_t)
+ {
+ monster_msg("%^s is unaffected!", t_name);
+ }
+ }
+ else
+ {
+ bool_ fear;
+ if (see_t)
+ {
+ monster_msg("%^s is blasted by psionic energy.", t_name);
+ }
+ t_ptr->confused += rand_int(4) + 4;
+ t_ptr->mspeed -= rand_int(4) + 4;
+ t_ptr->stunned += rand_int(4) + 4;
+ mon_take_hit_mon(m_idx, t_idx, damroll(12, 15), &fear, " collapses, a mindless husk.");
+ }
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_CAUSE_1 */
+ case 128 + 12:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s points at %s and curses.", m_name, t_name);
+ if (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10)
+ {
+
+ if (see_t) monster_msg("%^s resists!", t_name);
+ }
+ else
+ {
+ bool_ fear;
+ mon_take_hit_mon(m_idx, t_idx, damroll(3, 8), &fear, " is destroyed.");
+ }
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_CAUSE_2 */
+ case 128 + 13:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s points at %s and curses horribly.", m_name, t_name);
+ if (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10)
+ {
+ if (see_t) monster_msg("%^s resists!", t_name);
+ }
+ else
+ {
+ bool_ fear;
+ mon_take_hit_mon(m_idx, t_idx, damroll(8, 8), &fear, " is destroyed.");
+ }
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_CAUSE_3 */
+ case 128 + 14:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s points at %s, incanting terribly!", m_name, t_name);
+ if (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10)
+ {
+ if (see_t) monster_msg("%^s resists!", t_name);
+ }
+ else
+ {
+ bool_ fear;
+ mon_take_hit_mon(m_idx, t_idx, damroll(10, 15), &fear, " is destroyed.");
+ }
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_CAUSE_4 */
+ case 128 + 15:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s points at %s, screaming the word 'DIE!'", m_name, t_name);
+ if (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10)
+ {
+ if (see_t) monster_msg("%^s resists!", t_name);
+ }
+ else
+ {
+ bool_ fear;
+ mon_take_hit_mon(m_idx, t_idx, damroll(15, 15), &fear, " is destroyed.");
+ }
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_BO_ACID */
+ case 128 + 16:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts an acid bolt at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_ACID,
+ damroll(7, 8) + (rlev / 3));
+ break;
+ }
+
+ /* RF5_BO_ELEC */
+ case 128 + 17:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a lightning bolt at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_ELEC,
+ damroll(4, 8) + (rlev / 3));
+ break;
+ }
+
+ /* RF5_BO_FIRE */
+ case 128 + 18:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a fire bolt at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_FIRE,
+ damroll(9, 8) + (rlev / 3));
+ break;
+ }
+
+ /* RF5_BO_COLD */
+ case 128 + 19:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a frost bolt at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_COLD,
+ damroll(6, 8) + (rlev / 3));
+ break;
+ }
+
+ /* RF5_BO_POIS */
+ case 128 + 20:
+ {
+ /* XXX XXX XXX */
+ break;
+ }
+
+ /* RF5_BO_NETH */
+ case 128 + 21:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a nether bolt at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_NETHER,
+ 30 + damroll(5, 5) + (rlev * 3) / 2);
+ break;
+ }
+
+ /* RF5_BO_WATE */
+ case 128 + 22:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a water bolt at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_WATER,
+ damroll(10, 10) + (rlev));
+ break;
+ }
+
+ /* RF5_BO_MANA */
+ case 128 + 23:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a mana bolt at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_MANA,
+ randint(rlev * 7 / 2) + 50);
+ break;
+ }
+
+ /* RF5_BO_PLAS */
+ case 128 + 24:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a plasma bolt at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_PLASMA,
+ 10 + damroll(8, 7) + (rlev));
+ break;
+ }
+
+ /* RF5_BO_ICEE */
+ case 128 + 25:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts an ice bolt at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_ICE,
+ damroll(6, 6) + (rlev));
+ break;
+ }
+
+ /* RF5_MISSILE */
+ case 128 + 26:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a magic missile at %s.", m_name, t_name);
+ monst_bolt_monst(m_idx, y, x, GF_MISSILE,
+ damroll(2, 6) + (rlev / 3));
+ break;
+ }
+
+ /* RF5_SCARE */
+ case 128 + 27:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles, and you hear scary noises.", m_name);
+ else monster_msg("%^s casts a fearful illusion at %s.", m_name, t_name);
+ if (tr_ptr->flags3 & RF3_NO_FEAR)
+ {
+ if (see_t) monster_msg("%^s refuses to be frightened.", t_name);
+ }
+ else if (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10)
+ {
+ if (see_t) monster_msg("%^s refuses to be frightened.", t_name);
+ }
+ else
+ {
+ if (!(t_ptr->monfear) && see_t) monster_msg("%^s flees in terror!", t_name);
+ t_ptr->monfear += rand_int(4) + 4;
+ }
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_BLIND */
+ case 128 + 28:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s casts a spell, burning %s%s eyes.", m_name, t_name,
+ (!strcmp(t_name, "it") ? "s" : "'s"));
+ if (tr_ptr->flags3 & RF3_NO_CONF) /* Simulate blindness with confusion */
+ {
+ if (see_t) monster_msg("%^s is unaffected.", t_name);
+ }
+ else if (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10)
+ {
+ if (see_t) monster_msg("%^s is unaffected.", t_name);
+ }
+ else
+ {
+ if (see_t) monster_msg("%^s is blinded!", t_name);
+ t_ptr->confused += 12 + (byte)rand_int(4);
+ }
+ wake_up = TRUE;
+ break;
+
+ }
+
+ /* RF5_CONF */
+ case 128 + 29:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles, and you hear puzzling noises.", m_name);
+ else monster_msg("%^s creates a mesmerising illusion in front of %s.", m_name, t_name);
+ if (tr_ptr->flags3 & RF3_NO_CONF)
+ {
+ if (see_t) monster_msg("%^s disbelieves the feeble spell.", t_name);
+ }
+ else if (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10)
+ {
+ if (see_t) monster_msg("%^s disbelieves the feeble spell.", t_name);
+ }
+ else
+ {
+ if (see_t) monster_msg("%^s seems confused.", t_name);
+ t_ptr->confused += 12 + (byte)rand_int(4);
+ }
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_SLOW */
+ case 128 + 30:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (!blind && see_either) monster_msg("%^s drains power from %s%s muscles.", m_name, t_name,
+ (!strcmp(t_name, "it") ? "s" : "'s"));
+ if (tr_ptr->flags1 & RF1_UNIQUE)
+ {
+ if (see_t) monster_msg("%^s is unaffected.", t_name);
+ }
+ else if (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10)
+ {
+ if (see_t) monster_msg("%^s is unaffected.", t_name);
+ }
+ else
+ {
+ t_ptr->mspeed -= 10;
+ if (see_t) monster_msg("%^s starts moving slower.", t_name);
+ }
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF5_HOLD */
+ case 128 + 31:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (!blind && see_m) monster_msg("%^s stares intently at %s.", m_name, t_name);
+ if ((tr_ptr->flags1 & RF1_UNIQUE) ||
+ (tr_ptr->flags3 & RF3_NO_STUN))
+ {
+ if (see_t) monster_msg("%^s is unaffected.", t_name);
+ }
+ else if (t_ptr->level > randint((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10)
+ {
+ if (see_t) monster_msg("%^s is unaffected.", t_name);
+ }
+ else
+ {
+ t_ptr->stunned += randint(4) + 4;
+ if (see_t) monster_msg("%^s is paralyzed!", t_name);
+ }
+ wake_up = TRUE;
+ break;
+ }
+
+
+ /* RF6_HASTE */
+ case 160 + 0:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m)
+ {
+ monster_msg("%^s mumbles.", m_name);
+ }
+ else
+ {
+ monster_msg("%^s concentrates on %s body.", m_name, m_poss);
+ }
+
+ /* Allow quick speed increases to base+10 */
+ if (m_ptr->mspeed < m_ptr->speed + 10)
+ {
+ if (see_m) monster_msg("%^s starts moving faster.", m_name);
+ m_ptr->mspeed += 10;
+ }
+
+ /* Allow small speed increases to base+20 */
+ else if (m_ptr->mspeed < m_ptr->speed + 20)
+ {
+ if (see_m) monster_msg("%^s starts moving faster.", m_name);
+ m_ptr->mspeed += 2;
+ }
+
+ break;
+ }
+
+ /* RF6_HAND_DOOM */
+ case 160 + 1:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (!see_m) monster_msg("You hear someone invoke the Hand of Doom!");
+ else if (!blind) monster_msg("%^s invokes the Hand of Doom on %s.", m_name, t_name);
+ else
+ monster_msg ("You hear someone invoke the Hand of Doom!");
+ if (tr_ptr->flags1 & RF1_UNIQUE)
+ {
+ if (!blind && see_t) monster_msg("^%s is unaffected!", t_name);
+ }
+ else
+ {
+ if (((m_ptr->level) + randint(20)) >
+ ((t_ptr->level) + 10 + randint(20)))
+ {
+ t_ptr->hp = t_ptr->hp
+ - (((s32b) ((65 + randint(25)) * (t_ptr->hp))) / 100);
+ if (t_ptr->hp < 1) t_ptr->hp = 1;
+ }
+ else
+ {
+ if (see_t) monster_msg("%^s resists!", t_name);
+ }
+ }
+
+ wake_up = TRUE;
+ break;
+ }
+
+ /* RF6_HEAL */
+ case 160 + 2:
+ {
+ if (disturb_other) disturb(1, 0);
+
+ /* Message */
+ if (blind || !see_m)
+ {
+ monster_msg("%^s mumbles.", m_name);
+ }
+ else
+ {
+ monster_msg("%^s concentrates on %s wounds.", m_name, m_poss);
+ }
+
+ /* Heal some */
+ m_ptr->hp += (rlev * 6);
+
+ /* Fully healed */
+ if (m_ptr->hp >= m_ptr->maxhp)
+ {
+ /* Fully healed */
+ m_ptr->hp = m_ptr->maxhp;
+
+ /* Message */
+ if (seen)
+ {
+ monster_msg("%^s looks completely healed!", m_name);
+ }
+ else
+ {
+ monster_msg("%^s sounds completely healed!", m_name);
+ }
+ }
+
+ /* Partially healed */
+ else
+ {
+ /* Message */
+ if (seen)
+ {
+ monster_msg("%^s looks healthier.", m_name);
+ }
+ else
+ {
+ monster_msg("%^s sounds healthier.", m_name);
+ }
+ }
+
+ /* Redraw (later) if needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Cancel fear */
+ if (m_ptr->monfear)
+ {
+ /* Cancel fear */
+ m_ptr->monfear = 0;
+
+ /* Message */
+ if (see_m) monster_msg("%^s recovers %s courage.", m_name, m_poss);
+ }
+
+ break;
+ }
+
+ /* RF6_S_ANIMALS */
+ case 160 + 3:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons some animals!", m_name);
+ for (k = 0; k < 4; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_ANIMAL, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_ANIMAL);
+ }
+ if (blind && count) monster_msg("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_BLINK */
+ case 160 + 4:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (see_m) monster_msg("%^s blinks away.", m_name);
+ teleport_away(m_idx, 10);
+ break;
+ }
+
+ /* RF6_TPORT */
+ case 160 + 5:
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT) break; /* No teleport on special levels */
+ else
+ {
+ if (disturb_other) disturb(1, 0);
+ if (see_m) monster_msg("%^s teleports away.", m_name);
+ teleport_away(m_idx, MAX_SIGHT * 2 + 5);
+ break;
+ }
+ }
+
+ /* RF6_TELE_TO */
+ case 160 + 6:
+ {
+ /* Not implemented */
+ break;
+ }
+
+ /* RF6_TELE_AWAY */
+ case 160 + 7:
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT) break;
+
+ if (!direct) break;
+ else
+ {
+ bool_ resists_tele = FALSE;
+ if (disturb_other) disturb(1, 0);
+ monster_msg("%^s teleports %s away.", m_name, t_name);
+
+
+ if (tr_ptr->flags3 & (RF3_RES_TELE))
+ {
+ if (tr_ptr->flags1 & (RF1_UNIQUE))
+ {
+ if (see_t)
+ {
+ tr_ptr->r_flags3 |= RF3_RES_TELE;
+ monster_msg("%^s is unaffected!", t_name);
+ }
+ resists_tele = TRUE;
+ }
+ else if (t_ptr->level > randint(100))
+ {
+ if (see_t)
+ {
+ tr_ptr->r_flags3 |= RF3_RES_TELE;
+ monster_msg("%^s resists!", t_name);
+ }
+ resists_tele = TRUE;
+ }
+ }
+
+ if (!resists_tele)
+ {
+ teleport_away(t_idx, MAX_SIGHT * 2 + 5);
+ }
+ }
+
+ break;
+ }
+
+ /* RF6_TELE_LEVEL */
+ case 160 + 8:
+ {
+ /* Not implemented */
+ break;
+ }
+
+ /* RF6_DARKNESS */
+ case 160 + 9:
+ {
+ if (!direct) break;
+ if (disturb_other) disturb(1, 0);
+ if (blind) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s gestures in shadow.", m_name);
+ if (seen)
+ monster_msg("%^s is surrounded by darkness.", t_name);
+ (void)project(m_idx, 3, y, x, 0, GF_DARK_WEAK, PROJECT_GRID | PROJECT_KILL);
+ /* Lite up the room */
+ unlite_room(y, x);
+ break;
+ }
+
+ /* RF6_TRAPS */
+ case 160 + 10:
+ {
+ /* Not implemented */
+ break;
+ }
+
+ /* RF6_FORGET */
+ case 160 + 11:
+ {
+ /* Not implemented */
+ break;
+ }
+
+ /* RF6_ANIM_DEAD */
+ case 160 + 12:
+ {
+ break;
+ }
+
+ /* RF6_S_BUG */
+ case 160 + 13:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically codes some software bugs.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_BUG, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_BUG);
+ }
+ if (blind && count) monster_msg("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_RNG */
+ case 160 + 14:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically codes some RNGs.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_RNG, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_RNG);
+ }
+ if (blind && count) monster_msg("You hear many things appear nearby.");
+ break;
+ }
+
+
+ /* RF6_S_THUNDERLORD */
+ case 160 + 15:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons a Thunderlord!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_THUNDERLORD, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_THUNDERLORD);
+ }
+ if (blind && count) monster_msg("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_SUMMON_KIN */
+ case 160 + 16:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons %s %s.",
+ m_name, m_poss,
+ ((r_ptr->flags1) & RF1_UNIQUE ?
+ "minions" : "kin"));
+ summon_kin_type = r_ptr->d_char; /* Big hack */
+ for (k = 0; k < 6; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_KIN, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_KIN);
+ }
+ if (blind && count) monster_msg("You hear many things appear nearby.");
+
+
+ break;
+ }
+
+ /* RF6_S_HI_DEMON */
+ case 160 + 17:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons greater demons!", m_name);
+ if (blind && count) monster_msg("You hear heavy steps nearby.");
+ if (friendly)
+ summon_specific_friendly(y, x, rlev, SUMMON_HI_DEMON, TRUE);
+ else
+ summon_cyber();
+ break;
+ }
+
+ /* RF6_S_MONSTER */
+ case 160 + 18:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons help!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_NO_UNIQUES, TRUE);
+ else
+ count += summon_specific(y, x, rlev, 0);
+ }
+ if (blind && count) monster_msg("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_MONSTERS */
+ case 160 + 19:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons monsters!", m_name);
+ for (k = 0; k < 8; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_NO_UNIQUES, TRUE);
+ else
+ count += summon_specific(y, x, rlev, 0);
+ }
+ if (blind && count) monster_msg("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_ANT */
+ case 160 + 20:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons ants.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_ANT, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_ANT);
+ }
+ if (blind && count) monster_msg("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_SPIDER */
+ case 160 + 21:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons spiders.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_SPIDER, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_SPIDER);
+ }
+ if (blind && count) monster_msg("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_HOUND */
+ case 160 + 22:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons hounds.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_HOUND, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_HOUND);
+ }
+ if (blind && count) monster_msg("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_HYDRA */
+ case 160 + 23:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons hydras.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_HYDRA, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_HYDRA);
+ }
+ if (blind && count) monster_msg("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_ANGEL */
+ case 160 + 24:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons an angel!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_ANGEL, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_ANGEL);
+ }
+ if (blind && count) monster_msg("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_DEMON */
+ case 160 + 25:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons a demon!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_DEMON, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_DEMON);
+ }
+ if (blind && count) monster_msg("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_UNDEAD */
+ case 160 + 26:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons an undead adversary!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_UNDEAD, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_UNDEAD);
+ }
+ if (blind && count) monster_msg("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_DRAGON */
+ case 160 + 27:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons a dragon!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_DRAGON, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_DRAGON);
+ }
+ if (blind && count) monster_msg("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_HI_UNDEAD */
+ case 160 + 28:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons greater undead!", m_name);
+ for (k = 0; k < 8; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_HI_UNDEAD_NO_UNIQUES, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_HI_UNDEAD);
+ }
+ if (blind && count)
+ {
+ monster_msg("You hear many creepy things appear nearby.");
+ }
+ break;
+ }
+
+ /* RF6_S_HI_DRAGON */
+ case 160 + 29:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons ancient dragons!", m_name);
+ for (k = 0; k < 8; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_HI_DRAGON_NO_UNIQUES, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_HI_DRAGON);
+ }
+ if (blind && count)
+ {
+ monster_msg("You hear many powerful things appear nearby.");
+ }
+ break;
+ }
+
+ /* RF6_S_WRAITH */
+ case 160 + 30:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons a wraith!", m_name);
+
+
+ for (k = 0; k < 8; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_WRAITH);
+ }
+
+ if (blind && count)
+ {
+ monster_msg("You hear immortal beings appear nearby.");
+ }
+ break;
+ }
+
+ /* RF6_S_UNIQUE */
+ case 160 + 31:
+ {
+ if (disturb_other) disturb(1, 0);
+ if (blind || !see_m) monster_msg("%^s mumbles.", m_name);
+ else monster_msg("%^s magically summons special opponents!", m_name);
+ for (k = 0; k < 8; k++)
+ {
+ if (!friendly)
+ count += summon_specific(y, x, rlev, SUMMON_UNIQUE);
+ }
+ for (k = 0; k < 8; k++)
+ {
+ if (friendly)
+ count += summon_specific_friendly(y, x, rlev, SUMMON_HI_UNDEAD_NO_UNIQUES, TRUE);
+ else
+ count += summon_specific(y, x, rlev, SUMMON_HI_UNDEAD);
+ }
+ if (blind && count)
+ {
+ monster_msg("You hear many powerful things appear nearby.");
+ }
+ break;
+ }
+ }
+
+ if (wake_up)
+ {
+ t_ptr->csleep = 0;
+ }
+
+
+ /* Remember what the monster did, if we saw it */
+ if (seen)
+ {
+ /* Inate spell */
+ if (thrown_spell < 32*4)
+ {
+ r_ptr->r_flags4 |= (1L << (thrown_spell - 32 * 3));
+ if (r_ptr->r_cast_inate < MAX_UCHAR) r_ptr->r_cast_inate++;
+ }
+
+ /* Bolt or Ball */
+ else if (thrown_spell < 32*5)
+ {
+ r_ptr->r_flags5 |= (1L << (thrown_spell - 32 * 4));
+ if (r_ptr->r_cast_spell < MAX_UCHAR) r_ptr->r_cast_spell++;
+ }
+
+ /* Special spell */
+ else if (thrown_spell < 32*6)
+ {
+ r_ptr->r_flags6 |= (1L << (thrown_spell - 32 * 5));
+ if (r_ptr->r_cast_spell < MAX_UCHAR) r_ptr->r_cast_spell++;
+ }
+ }
+
+ /* Always take note of monsters that kill you ---
+ * even accidentally */
+ if (death && (r_ptr->r_deaths < MAX_SHORT))
+ {
+ r_ptr->r_deaths++;
+ }
+
+ /* A spell was cast */
+ return (TRUE);
+ }
+
+ /* No enemy found */
+ return (FALSE);
+}
+
+
+void curse_equipment(int chance, int heavy_chance)
+{
+ bool_ changed = FALSE;
+ u32b o1, o2, o3, o4, esp, o5;
+ object_type * o_ptr =
+ &p_ptr->inventory[rand_range(INVEN_WIELD, INVEN_TOTAL - 1)];
+
+ if (randint(100) > chance) return;
+
+ if (!(o_ptr->k_idx)) return;
+
+ object_flags(o_ptr, &o1, &o2, &o3, &o4, &o5, &esp);
+
+
+ /* Extra, biased saving throw for blessed items */
+ if ((o3 & (TR3_BLESSED)) && (randint(888) > chance))
+ {
+ char o_name[256];
+ object_desc(o_name, o_ptr, FALSE, 0);
+ msg_format("Your %s resist%s cursing!", o_name,
+ ((o_ptr->number > 1) ? "" : "s"));
+ /* Hmmm -- can we wear multiple items? If not, this is unnecessary */
+ return;
+ }
+
+ if ((randint(100) <= heavy_chance) &&
+ (o_ptr->name1 || o_ptr->name2 || o_ptr->art_name))
+ {
+ if (!(o3 & TR3_HEAVY_CURSE))
+ changed = TRUE;
+ o_ptr->art_flags3 |= TR3_HEAVY_CURSE;
+ o_ptr->art_flags3 |= TR3_CURSED;
+ o_ptr->ident |= IDENT_CURSED;
+ }
+ else
+ {
+ if (!(o_ptr->ident & (IDENT_CURSED)))
+ changed = TRUE;
+ o_ptr->art_flags3 |= TR3_CURSED;
+ o_ptr->ident |= IDENT_CURSED;
+ }
+
+ if (changed)
+ {
+ msg_print("There is a malignant black aura surrounding you...");
+ if (o_ptr->note)
+ {
+ if (streq(quark_str(o_ptr->note), "uncursed"))
+ {
+ o_ptr->note = 0;
+ }
+ }
+ }
+}
+
+
+void curse_equipment_dg(int chance, int heavy_chance)
+{
+ bool_ changed = FALSE;
+ u32b o1, o2, o3, o4, esp, o5;
+ object_type * o_ptr =
+ &p_ptr->inventory[rand_range(INVEN_WIELD, INVEN_TOTAL - 1)];
+
+ if (randint(100) > chance) return;
+
+ if (!(o_ptr->k_idx)) return;
+
+ object_flags(o_ptr, &o1, &o2, &o3, &o4, &o5, &esp);
+
+
+ /* Extra, biased saving throw for blessed items */
+ if ((o3 & (TR3_BLESSED)) && (randint(888) > chance))
+ {
+ char o_name[256];
+ object_desc(o_name, o_ptr, FALSE, 0);
+ msg_format("Your %s resist%s cursing!", o_name,
+ ((o_ptr->number > 1) ? "" : "s"));
+ /* Hmmm -- can we wear multiple items? If not, this is unnecessary */
+ /* DG -- Yes we can, in the quiver */
+ return;
+ }
+
+ if ((randint(100) <= heavy_chance) &&
+ (o_ptr->name1 || o_ptr->name2 || o_ptr->art_name))
+ {
+ if (!(o3 & TR3_HEAVY_CURSE))
+ changed = TRUE;
+ o_ptr->art_flags3 |= TR3_HEAVY_CURSE;
+ o_ptr->art_flags3 |= TR3_CURSED;
+ o_ptr->art_flags4 |= TR4_DG_CURSE;
+ o_ptr->ident |= IDENT_CURSED;
+ }
+ else
+ {
+ if (!(o_ptr->ident & (IDENT_CURSED)))
+ changed = TRUE;
+ o_ptr->art_flags3 |= TR3_CURSED;
+ o_ptr->art_flags4 |= TR4_DG_CURSE;
+ o_ptr->ident |= IDENT_CURSED;
+ }
+
+ if (changed)
+ {
+ msg_print("There is a malignant black aura surrounding you...");
+ if (o_ptr->note)
+ {
+ if (streq(quark_str(o_ptr->note), "uncursed"))
+ {
+ o_ptr->note = 0;
+ }
+ }
+ }
+}
+
+
+/*
+ * Creatures can cast spells, shoot missiles, and breathe.
+ *
+ * Returns "TRUE" if a spell (or whatever) was (successfully) cast.
+ *
+ * XXX XXX XXX This function could use some work, but remember to
+ * keep it as optimized as possible, while retaining generic code.
+ *
+ * Verify the various "blind-ness" checks in the code.
+ *
+ * XXX XXX XXX Note that several effects should really not be "seen"
+ * if the player is blind. See also "effects.c" for other "mistakes".
+ *
+ * Perhaps monsters should breathe at locations *near* the player,
+ * since this would allow them to inflict "partial" damage.
+ *
+ * Perhaps smart monsters should decline to use "bolt" spells if
+ * there is a monster in the way, unless they wish to kill it.
+ *
+ * Note that, to allow the use of the "track_target" option at some
+ * later time, certain non-optimal things are done in the code below,
+ * including explicit checks against the "direct" variable, which is
+ * currently always true by the time it is checked, but which should
+ * really be set according to an explicit "projectable()" test, and
+ * the use of generic "x,y" locations instead of the player location,
+ * with those values being initialized with the player location.
+ *
+ * It will not be possible to "correctly" handle the case in which a
+ * monster attempts to attack a location which is thought to contain
+ * the player, but which in fact is nowhere near the player, since this
+ * might induce all sorts of messages about the attack itself, and about
+ * the effects of the attack, which the player might or might not be in
+ * a position to observe. Thus, for simplicity, it is probably best to
+ * only allow "faulty" attacks by a monster if one of the important grids
+ * (probably the initial or final grid) is in fact in view of the player.
+ * It may be necessary to actually prevent spell attacks except when the
+ * monster actually has line of sight to the player. Note that a monster
+ * could be left in a bizarre situation after the player ducked behind a
+ * pillar and then teleported away, for example.
+ *
+ * Note that certain spell attacks do not use the "project()" function
+ * but "simulate" it via the "direct" variable, which is always at least
+ * as restrictive as the "project()" function. This is necessary to
+ * prevent "blindness" attacks and such from bending around walls, etc,
+ * and to allow the use of the "track_target" option in the future.
+ *
+ * Note that this function attempts to optimize the use of spells for the
+ * cases in which the monster has no spells, or has spells but cannot use
+ * them, or has spells but they will have no "useful" effect. Note that
+ * this function has been an efficiency bottleneck in the past.
+ *
+ * Note the special "MFLAG_NICE" flag, which prevents a monster from using
+ * any spell attacks until the player has had a single chance to move.
+ */
+bool_ make_attack_spell(int m_idx)
+{
+ int k, chance, thrown_spell, rlev, failrate;
+ byte spell[96], num = 0;
+ u32b f4, f5, f6;
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+ char m_name[80];
+ bool_ no_inate = FALSE;
+ int x, y;
+
+ /* Summon count */
+ int count = 0;
+
+ /* Extract the blind-ness */
+ bool_ blind = (p_ptr->blind ? TRUE : FALSE);
+
+ /* Extract the "see-able-ness" */
+ bool_ seen = (!blind && m_ptr->ml);
+
+ /* Assume "normal" target */
+ bool_ normal = TRUE;
+
+ /* Assume "projectable" */
+ bool_ direct = TRUE;
+
+ /* Target location */
+ if (m_ptr->target > -1)
+ {
+ if (!m_ptr->target)
+ {
+ y = p_ptr->py;
+ x = p_ptr->px;
+ }
+ else
+ {
+ return (FALSE);
+ }
+ }
+ else return FALSE;
+
+ /* Cannot cast spells when confused */
+ if (m_ptr->confused) return (FALSE);
+
+ /* Cannot cast spells when nice */
+ if (m_ptr->mflag & (MFLAG_NICE)) return (FALSE);
+ if (is_friend(m_ptr) >= 0) return (FALSE);
+
+ /* Cannot attack the player if mortal and player fated to never die by the ... */
+ if ((r_ptr->flags7 & RF7_MORTAL) && (p_ptr->no_mortal)) return (FALSE);
+
+ /* Hack -- Extract the spell probability */
+ chance = (r_ptr->freq_inate + r_ptr->freq_spell) / 2;
+
+ /* Not allowed to cast spells */
+ if (!chance) return (FALSE);
+
+ if (stupid_monsters)
+ {
+ /* Only do spells occasionally */
+ if (rand_int(100) >= chance) return (FALSE);
+ }
+ else
+ {
+ if (rand_int(100) >= chance) return (FALSE);
+
+ /* Sometimes forbid inate attacks (breaths) */
+ if (rand_int(100) >= (chance * 2)) no_inate = TRUE;
+ }
+
+ /* XXX XXX XXX Handle "track_target" option (?) */
+
+
+ /* Hack -- require projectable player */
+ if (normal)
+ {
+ /* Check range */
+ if (m_ptr->cdis > MAX_RANGE) return (FALSE);
+
+ /* Check path */
+ if (!projectable(m_ptr->fy, m_ptr->fx, y, x)) return (FALSE);
+ }
+
+ /* Extract the monster level */
+ rlev = ((m_ptr->level >= 1) ? m_ptr->level : 1);
+
+ /* Extract the racial spell flags */
+ f4 = r_ptr->flags4;
+ f5 = r_ptr->flags5;
+ f6 = r_ptr->flags6;
+
+ if (!stupid_monsters)
+ {
+ /* Forbid inate attacks sometimes */
+ if (no_inate) f4 = 0L;
+ }
+
+ /* Hack -- allow "desperate" spells */
+ if ((r_ptr->flags2 & (RF2_SMART)) &&
+ (m_ptr->hp < m_ptr->maxhp / 10) &&
+ (rand_int(100) < 50))
+ {
+ /* Require intelligent spells */
+ f4 &= (RF4_INT_MASK);
+ f5 &= (RF5_INT_MASK);
+ f6 &= (RF6_INT_MASK);
+
+ /* No spells left */
+ if (!f4 && !f5 && !f6) return (FALSE);
+ }
+
+ /* Remove the "ineffective" spells */
+ remove_bad_spells(m_idx, &f4, &f5, &f6);
+
+ /* No spells left */
+ if (!f4 && !f5 && !f6) return (FALSE);
+
+ if (!stupid_monsters)
+ {
+ /* Check for a clean bolt shot */
+ if ((f4&(RF4_BOLT_MASK) || f5 & (RF5_BOLT_MASK) ||
+ f6&(RF6_BOLT_MASK)) &&
+ !(r_ptr->flags2 & (RF2_STUPID)) &&
+ !clean_shot(m_ptr->fy, m_ptr->fx, y, x))
+ {
+ /* Remove spells that will only hurt friends */
+ f4 &= ~(RF4_BOLT_MASK);
+ f5 &= ~(RF5_BOLT_MASK);
+ f6 &= ~(RF6_BOLT_MASK);
+ }
+
+ /* Check for a possible summon */
+ if ((f4 & (RF4_SUMMON_MASK) || f5 & (RF5_SUMMON_MASK) ||
+ f6 & (RF6_SUMMON_MASK)) &&
+ !(r_ptr->flags2 & (RF2_STUPID)) &&
+ !(summon_possible(y, x)))
+ {
+ /* Remove summoning spells */
+ f4 &= ~(RF4_SUMMON_MASK);
+ f5 &= ~(RF5_SUMMON_MASK);
+ f6 &= ~(RF6_SUMMON_MASK);
+ }
+
+ /* No spells left */
+ if (!f4 && !f5 && !f6) return (FALSE);
+ }
+
+ /* Extract the "inate" spells */
+ for (k = 0; k < 32; k++)
+ {
+ if (f4 & (1L << k)) spell[num++] = k + 32 * 3;
+ }
+
+ /* Extract the "normal" spells */
+ for (k = 0; k < 32; k++)
+ {
+ if (f5 & (1L << k)) spell[num++] = k + 32 * 4;
+ }
+
+ /* Extract the "bizarre" spells */
+ for (k = 0; k < 32; k++)
+ {
+ if (f6 & (1L << k)) spell[num++] = k + 32 * 5;
+ }
+
+ /* No spells left */
+ if (!num) return (FALSE);
+
+ /* Stop if player is dead or gone */
+ if (!alive || death) return (FALSE);
+
+ /* Stop if player is leaving */
+ if (p_ptr->leaving) return (FALSE);
+
+ /* Get the monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0x00);
+
+ if (stupid_monsters)
+ {
+ /* Choose a spell to cast */
+ thrown_spell = spell[rand_int(num)];
+ }
+ else
+ {
+ thrown_spell = choose_attack_spell(m_idx, spell, num);
+
+ /* Abort if no spell was chosen */
+ if (!thrown_spell) return (FALSE);
+
+ /* Calculate spell failure rate */
+ failrate = 25 - (rlev + 3) / 4;
+
+ /* Hack -- Stupid monsters will never fail (for jellies and such) */
+ if (r_ptr->flags2 & (RF2_STUPID)) failrate = 0;
+
+ /* Check for spell failure (inate attacks never fail) */
+ if ((thrown_spell >= 128) && (rand_int(100) < failrate))
+ {
+ /* Message */
+ msg_format("%^s tries to cast a spell, but fails.", m_name);
+
+ return (TRUE);
+ }
+ }
+
+ /* Can the player disrupt its puny attempts? */
+ if ((p_ptr->antimagic_dis >= m_ptr->cdis) && (magik(p_ptr->antimagic)) && (thrown_spell >= 128))
+ {
+ char m_poss[80];
+
+ /* Get monster's possessive noun form ("the Illusionist's") */
+ monster_desc(m_poss, m_ptr, 0x06);
+
+ msg_format("Your anti-magic field disrupts %s spell.", m_poss);
+ }
+ else
+ {
+ char m_poss[80];
+ char ddesc[80];
+
+ /* Get the monster possessive ("his"/"her"/"its") */
+ monster_desc(m_poss, m_ptr, 0x22);
+
+ /* Hack -- Get the "died from" name */
+ monster_desc(ddesc, m_ptr, 0x88);
+
+ /* Cast the spell. */
+ switch (thrown_spell)
+ {
+ /* RF4_SHRIEK */
+ case 96 + 0:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ msg_format("%^s makes a high pitched shriek.", m_name);
+ aggravate_monsters(m_idx);
+ break;
+ }
+
+ /* RF4_MULTIPLY */
+ case 96 + 1:
+ {
+ break;
+ }
+
+ /* RF4_S_ANIMAL */
+ case 96 + 2:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons an animal!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_ANIMAL);
+ }
+ if (blind && count) msg_print("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF4_ROCKET */
+ case 96 + 3:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s shoots something.", m_name);
+ else msg_format("%^s fires a rocket.", m_name);
+ breath(m_idx, GF_ROCKET,
+ ((m_ptr->hp / 4) > 800 ? 800 : (m_ptr->hp / 4)), 2);
+ update_smart_learn(m_idx, DRS_SHARD);
+ break;
+ }
+
+ /* RF4_ARROW_1 */
+ case 96 + 4:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s makes a strange noise.", m_name);
+ else msg_format("%^s fires an arrow.", m_name);
+ bolt(m_idx, GF_ARROW, damroll(1, 6));
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF4_ARROW_2 */
+ case 96 + 5:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s makes a strange noise.", m_name);
+ else msg_format("%^s fires an arrow!", m_name);
+ bolt(m_idx, GF_ARROW, damroll(3, 6));
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF4_ARROW_3 */
+ case 96 + 6:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s makes a strange noise.", m_name);
+ else msg_format("%^s fires a missile.", m_name);
+ bolt(m_idx, GF_ARROW, damroll(5, 6));
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF4_ARROW_4 */
+ case 96 + 7:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s makes a strange noise.", m_name);
+ else msg_format("%^s fires a missile!", m_name);
+ bolt(m_idx, GF_ARROW, damroll(7, 6));
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF4_BR_ACID */
+ case 96 + 8:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes acid.", m_name);
+ breath(m_idx, GF_ACID,
+ ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), 0);
+ update_smart_learn(m_idx, DRS_ACID);
+ break;
+ }
+
+ /* RF4_BR_ELEC */
+ case 96 + 9:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes lightning.", m_name);
+ breath(m_idx, GF_ELEC,
+ ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), 0);
+ update_smart_learn(m_idx, DRS_ELEC);
+ break;
+ }
+
+ /* RF4_BR_FIRE */
+ case 96 + 10:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes fire.", m_name);
+ breath(m_idx, GF_FIRE,
+ ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), 0);
+ update_smart_learn(m_idx, DRS_FIRE);
+ break;
+ }
+
+ /* RF4_BR_COLD */
+ case 96 + 11:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes frost.", m_name);
+ breath(m_idx, GF_COLD,
+ ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), 0);
+ update_smart_learn(m_idx, DRS_COLD);
+ break;
+ }
+
+ /* RF4_BR_POIS */
+ case 96 + 12:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes gas.", m_name);
+ breath(m_idx, GF_POIS,
+ ((m_ptr->hp / 3) > 800 ? 800 : (m_ptr->hp / 3)), 0);
+ update_smart_learn(m_idx, DRS_POIS);
+ break;
+ }
+
+
+ /* RF4_BR_NETH */
+ case 96 + 13:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes nether.", m_name);
+ breath(m_idx, GF_NETHER,
+ ((m_ptr->hp / 6) > 550 ? 550 : (m_ptr->hp / 6)), 0);
+ update_smart_learn(m_idx, DRS_NETH);
+ break;
+ }
+
+ /* RF4_BR_LITE */
+ case 96 + 14:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes light.", m_name);
+ breath(m_idx, GF_LITE,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ update_smart_learn(m_idx, DRS_LITE);
+ break;
+ }
+
+ /* RF4_BR_DARK */
+ case 96 + 15:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes darkness.", m_name);
+ breath(m_idx, GF_DARK,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ update_smart_learn(m_idx, DRS_DARK);
+ break;
+ }
+
+ /* RF4_BR_CONF */
+ case 96 + 16:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes confusion.", m_name);
+ breath(m_idx, GF_CONFUSION,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ update_smart_learn(m_idx, DRS_CONF);
+ break;
+ }
+
+ /* RF4_BR_SOUN */
+ case 96 + 17:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes sound.", m_name);
+ breath(m_idx, GF_SOUND,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ update_smart_learn(m_idx, DRS_SOUND);
+ break;
+ }
+
+ /* RF4_BR_CHAO */
+ case 96 + 18:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes chaos.", m_name);
+ breath(m_idx, GF_CHAOS,
+ ((m_ptr->hp / 6) > 600 ? 600 : (m_ptr->hp / 6)), 0);
+ update_smart_learn(m_idx, DRS_CHAOS);
+ break;
+ }
+
+ /* RF4_BR_DISE */
+ case 96 + 19:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes disenchantment.", m_name);
+ breath(m_idx, GF_DISENCHANT,
+ ((m_ptr->hp / 6) > 500 ? 500 : (m_ptr->hp / 6)), 0);
+ update_smart_learn(m_idx, DRS_DISEN);
+ break;
+ }
+
+ /* RF4_BR_NEXU */
+ case 96 + 20:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes nexus.", m_name);
+ breath(m_idx, GF_NEXUS,
+ ((m_ptr->hp / 3) > 250 ? 250 : (m_ptr->hp / 3)), 0);
+ update_smart_learn(m_idx, DRS_NEXUS);
+ break;
+ }
+
+ /* RF4_BR_TIME */
+ case 96 + 21:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes time.", m_name);
+ breath(m_idx, GF_TIME,
+ ((m_ptr->hp / 3) > 150 ? 150 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_INER */
+ case 96 + 22:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes inertia.", m_name);
+ breath(m_idx, GF_INERTIA,
+ ((m_ptr->hp / 6) > 200 ? 200 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_GRAV */
+ case 96 + 23:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes gravity.", m_name);
+ breath(m_idx, GF_GRAVITY,
+ ((m_ptr->hp / 3) > 200 ? 200 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BR_SHAR */
+ case 96 + 24:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes shards.", m_name);
+ breath(m_idx, GF_SHARDS,
+ ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), 0);
+ update_smart_learn(m_idx, DRS_SHARD);
+ break;
+ }
+
+ /* RF4_BR_PLAS */
+ case 96 + 25:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes plasma.", m_name);
+ breath(m_idx, GF_PLASMA,
+ ((m_ptr->hp / 6) > 150 ? 150 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_WALL */
+ case 96 + 26:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes force.", m_name);
+ breath(m_idx, GF_FORCE,
+ ((m_ptr->hp / 6) > 200 ? 200 : (m_ptr->hp / 6)), 0);
+ break;
+ }
+
+ /* RF4_BR_MANA */
+ case 96 + 27:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes magical energy.", m_name);
+ breath(m_idx, GF_MANA,
+ ((m_ptr->hp / 3) > 250 ? 250 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+ /* RF4_BA_NUKE */
+ case 96 + 28:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a ball of radiation.", m_name);
+ breath(m_idx, GF_NUKE, (rlev + damroll(10, 6)), 2);
+ update_smart_learn(m_idx, DRS_POIS);
+ break;
+ }
+
+ /* RF4_BR_NUKE */
+ case 96 + 29:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes toxic waste.", m_name);
+ breath(m_idx, GF_NUKE,
+ ((m_ptr->hp / 3) > 800 ? 800 : (m_ptr->hp / 3)), 0);
+ update_smart_learn(m_idx, DRS_POIS);
+ break;
+ }
+
+ /* RF4_BA_CHAO */
+ case 96 + 30:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles frighteningly.", m_name);
+ else msg_format("%^s invokes a raw chaos.", m_name);
+ breath(m_idx, GF_CHAOS, (rlev * 2) + damroll(10, 10), 4);
+ update_smart_learn(m_idx, DRS_CHAOS);
+ break;
+ }
+
+ /* RF4_BR_DISI -> Disintegration breath! */
+ case 96 + 31:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s breathes.", m_name);
+ else msg_format("%^s breathes disintegration.", m_name);
+ breath(m_idx, GF_DISINTEGRATE,
+ ((m_ptr->hp / 3) > 300 ? 300 : (m_ptr->hp / 3)), 0);
+ break;
+ }
+
+
+
+ /* RF5_BA_ACID */
+ case 128 + 0:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts an acid ball.", m_name);
+ breath(m_idx, GF_ACID,
+ randint(rlev * 3) + 15, 2);
+ update_smart_learn(m_idx, DRS_ACID);
+ break;
+ }
+
+ /* RF5_BA_ELEC */
+ case 128 + 1:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a lightning ball.", m_name);
+ breath(m_idx, GF_ELEC,
+ randint(rlev * 3 / 2) + 8, 2);
+ update_smart_learn(m_idx, DRS_ELEC);
+ break;
+ }
+
+ /* RF5_BA_FIRE */
+ case 128 + 2:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a fire ball.", m_name);
+ breath(m_idx, GF_FIRE,
+ randint(rlev * 7 / 2) + 10, 2);
+ update_smart_learn(m_idx, DRS_FIRE);
+ break;
+ }
+
+ /* RF5_BA_COLD */
+ case 128 + 3:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a frost ball.", m_name);
+ breath(m_idx, GF_COLD,
+ randint(rlev * 3 / 2) + 10, 2);
+ update_smart_learn(m_idx, DRS_COLD);
+ break;
+ }
+
+ /* RF5_BA_POIS */
+ case 128 + 4:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a stinking cloud.", m_name);
+ breath(m_idx, GF_POIS,
+ damroll(12, 2), 2);
+ update_smart_learn(m_idx, DRS_POIS);
+ break;
+ }
+
+ /* RF5_BA_NETH */
+ case 128 + 5:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a nether ball.", m_name);
+ breath(m_idx, GF_NETHER,
+ (50 + damroll(10, 10) + rlev), 2);
+ update_smart_learn(m_idx, DRS_NETH);
+ break;
+ }
+
+ /* RF5_BA_WATE */
+ case 128 + 6:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s gestures fluidly.", m_name);
+ msg_print("You are engulfed in a whirlpool.");
+ breath(m_idx, GF_WATER,
+ randint(rlev * 5 / 2) + 50, 4);
+ break;
+ }
+
+ /* RF5_BA_MANA */
+ case 128 + 7:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles powerfully.", m_name);
+ else msg_format("%^s invokes a mana storm.", m_name);
+ breath(m_idx, GF_MANA,
+ (rlev * 5) + damroll(10, 10), 4);
+ break;
+ }
+
+ /* RF5_BA_DARK */
+ case 128 + 8:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles powerfully.", m_name);
+ else msg_format("%^s invokes a darkness storm.", m_name);
+ breath(m_idx, GF_DARK,
+ (rlev * 5) + damroll(10, 10), 4);
+ update_smart_learn(m_idx, DRS_DARK);
+ break;
+ }
+
+ /* RF5_DRAIN_MANA */
+ case 128 + 9:
+ {
+ if (!direct) break;
+ if (p_ptr->csp)
+ {
+ int r1;
+
+ /* Disturb if legal */
+ disturb(1, 0);
+
+ /* Basic message */
+ msg_format("%^s draws psychic energy from you!", m_name);
+
+ /* Attack power */
+ r1 = (randint(rlev) / 2) + 1;
+
+ /* Full drain */
+ if (r1 >= p_ptr->csp)
+ {
+ r1 = p_ptr->csp;
+ p_ptr->csp = 0;
+ p_ptr->csp_frac = 0;
+ }
+
+ /* Partial drain */
+ else
+ {
+ p_ptr->csp -= r1;
+ }
+
+ /* Redraw mana */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Heal the monster */
+ if (m_ptr->hp < m_ptr->maxhp)
+ {
+ /* Heal */
+ m_ptr->hp += (6 * r1);
+ if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
+
+ /* Redraw (later) if needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Special message */
+ if (seen)
+ {
+ msg_format("%^s appears healthier.", m_name);
+ }
+ }
+ }
+ update_smart_learn(m_idx, DRS_MANA);
+ break;
+ }
+
+ /* RF5_MIND_BLAST */
+ case 128 + 10:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (!seen)
+ {
+ msg_print("You feel something focusing on your mind.");
+ }
+ else
+ {
+ msg_format("%^s gazes deep into your eyes.", m_name);
+ }
+
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ msg_print("Your mind is blasted by psionic energy.");
+
+ if (!p_ptr->resist_conf)
+ {
+ (void)set_confused(p_ptr->confused + rand_int(4) + 4);
+ }
+
+ if ((!p_ptr->resist_chaos) && (randint(3) == 1))
+ {
+ (void) set_image(p_ptr->image + rand_int(250) + 150);
+ }
+
+ take_sanity_hit(damroll(8, 8), ddesc);
+ }
+ break;
+ }
+
+ /* RF5_BRAIN_SMASH */
+ case 128 + 11:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (!seen)
+ {
+ msg_print("You feel something focusing on your mind.");
+ }
+ else
+ {
+ msg_format("%^s looks deep into your eyes.", m_name);
+ }
+
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ msg_print("Your mind is blasted by psionic energy.");
+ take_sanity_hit(damroll(12, 15), ddesc);
+ if (!p_ptr->resist_blind)
+ {
+ (void)set_blind(p_ptr->blind + 8 + rand_int(8));
+ }
+ if (!p_ptr->resist_conf)
+ {
+ (void)set_confused(p_ptr->confused + rand_int(4) + 4);
+ }
+ if (!p_ptr->free_act)
+ {
+ (void)set_paralyzed(p_ptr->paralyzed + rand_int(4) + 4);
+ }
+ (void)set_slow(p_ptr->slow + rand_int(4) + 4);
+
+ while (rand_int(100) > p_ptr->skill_sav)
+ (void)do_dec_stat(A_INT, STAT_DEC_NORMAL);
+ while (rand_int(100) > p_ptr->skill_sav)
+ (void)do_dec_stat(A_WIS, STAT_DEC_NORMAL);
+
+ if (!p_ptr->resist_chaos)
+ {
+ (void) set_image(p_ptr->image + rand_int(250) + 150);
+ }
+ }
+ break;
+ }
+
+ /* RF5_CAUSE_1 */
+ case 128 + 12:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s points at you and curses.", m_name);
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ curse_equipment(33, 0);
+ take_hit(damroll(3, 8), ddesc);
+ }
+ break;
+ }
+
+ /* RF5_CAUSE_2 */
+ case 128 + 13:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s points at you and curses horribly.", m_name);
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ curse_equipment(50, 5);
+ take_hit(damroll(8, 8), ddesc);
+ }
+ break;
+ }
+
+ /* RF5_CAUSE_3 */
+ case 128 + 14:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles loudly.", m_name);
+ else msg_format("%^s points at you, incanting terribly!", m_name);
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ curse_equipment(80, 15);
+ take_hit(damroll(10, 15), ddesc);
+ }
+ break;
+ }
+
+ /* RF5_CAUSE_4 */
+ case 128 + 15:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s screams the word 'DIE!'", m_name);
+ else msg_format("%^s points at you, screaming the word DIE!", m_name);
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ take_hit(damroll(15, 15), ddesc);
+ (void)set_cut(p_ptr->cut + damroll(10, 10));
+ }
+ break;
+ }
+
+ /* RF5_BO_ACID */
+ case 128 + 16:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a acid bolt.", m_name);
+ bolt(m_idx, GF_ACID, damroll(7, 8) + (rlev / 3));
+ update_smart_learn(m_idx, DRS_ACID);
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_BO_ELEC */
+ case 128 + 17:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a lightning bolt.", m_name);
+ bolt(m_idx, GF_ELEC, damroll(4, 8) + (rlev / 3));
+ update_smart_learn(m_idx, DRS_ELEC);
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_BO_FIRE */
+ case 128 + 18:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a fire bolt.", m_name);
+ bolt(m_idx, GF_FIRE, damroll(9, 8) + (rlev / 3));
+ update_smart_learn(m_idx, DRS_FIRE);
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_BO_COLD */
+ case 128 + 19:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a frost bolt.", m_name);
+ bolt(m_idx, GF_COLD, damroll(6, 8) + (rlev / 3));
+ update_smart_learn(m_idx, DRS_COLD);
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_BO_POIS */
+ case 128 + 20:
+ {
+ /* XXX XXX XXX */
+ break;
+ }
+
+ /* RF5_BO_NETH */
+ case 128 + 21:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a nether bolt.", m_name);
+ bolt(m_idx, GF_NETHER, 30 + damroll(5, 5) + (rlev * 3) / 2);
+ update_smart_learn(m_idx, DRS_NETH);
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_BO_WATE */
+ case 128 + 22:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a water bolt.", m_name);
+ bolt(m_idx, GF_WATER, damroll(10, 10) + (rlev));
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_BO_MANA */
+ case 128 + 23:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a mana bolt.", m_name);
+ bolt(m_idx, GF_MANA, randint(rlev * 7 / 2) + 50);
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_BO_PLAS */
+ case 128 + 24:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a plasma bolt.", m_name);
+ bolt(m_idx, GF_PLASMA, 10 + damroll(8, 7) + (rlev));
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_BO_ICEE */
+ case 128 + 25:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts an ice bolt.", m_name);
+ bolt(m_idx, GF_ICE, damroll(6, 6) + (rlev));
+ update_smart_learn(m_idx, DRS_COLD);
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_MISSILE */
+ case 128 + 26:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a magic missile.", m_name);
+ bolt(m_idx, GF_MISSILE, damroll(2, 6) + (rlev / 3));
+ update_smart_learn(m_idx, DRS_REFLECT);
+ break;
+ }
+
+ /* RF5_SCARE */
+ case 128 + 27:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles, and you hear scary noises.", m_name);
+ else msg_format("%^s casts a fearful illusion.", m_name);
+ if (p_ptr->resist_fear)
+ {
+ msg_print("You refuse to be frightened.");
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You refuse to be frightened.");
+ }
+ else
+ {
+ (void)set_afraid(p_ptr->afraid + rand_int(4) + 4);
+ }
+ update_smart_learn(m_idx, DRS_FEAR);
+ break;
+ }
+
+ /* RF5_BLIND */
+ case 128 + 28:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s casts a spell, burning your eyes!", m_name);
+ if (p_ptr->resist_blind)
+ {
+ msg_print("You are unaffected!");
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ (void)set_blind(12 + rand_int(4));
+ }
+ update_smart_learn(m_idx, DRS_BLIND);
+ break;
+ }
+
+ /* RF5_CONF */
+ case 128 + 29:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles, and you hear puzzling noises.", m_name);
+ else msg_format("%^s creates a mesmerizing illusion.", m_name);
+ if (p_ptr->resist_conf)
+ {
+ msg_print("You disbelieve the feeble spell.");
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You disbelieve the feeble spell.");
+ }
+ else
+ {
+ (void)set_confused(p_ptr->confused + rand_int(4) + 4);
+ }
+ update_smart_learn(m_idx, DRS_CONF);
+ break;
+ }
+
+ /* RF5_SLOW */
+ case 128 + 30:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ msg_format("%^s drains power from your muscles!", m_name);
+ if (p_ptr->free_act)
+ {
+ msg_print("You are unaffected!");
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ (void)set_slow(p_ptr->slow + rand_int(4) + 4);
+ }
+ update_smart_learn(m_idx, DRS_FREE);
+ break;
+ }
+
+ /* RF5_HOLD */
+ case 128 + 31:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s stares deep into your eyes!", m_name);
+ if (p_ptr->free_act)
+ {
+ msg_print("You are unaffected!");
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_format("You resist the effects!");
+ }
+ else
+ {
+ (void)set_paralyzed(p_ptr->paralyzed + rand_int(4) + 4);
+ }
+ update_smart_learn(m_idx, DRS_FREE);
+ break;
+ }
+
+
+
+ /* RF6_HASTE */
+ case 160 + 0:
+ {
+ disturb(1, 0);
+ if (blind)
+ {
+ msg_format("%^s mumbles.", m_name);
+ }
+ else
+ {
+ msg_format("%^s concentrates on %s body.", m_name, m_poss);
+ }
+
+ /* Allow quick speed increases to base+10 */
+ if (m_ptr->mspeed < m_ptr->speed + 10)
+ {
+ msg_format("%^s starts moving faster.", m_name);
+ m_ptr->mspeed += 10;
+ }
+
+ /* Allow small speed increases to base+20 */
+ else if (m_ptr->mspeed < m_ptr->speed + 20)
+ {
+ msg_format("%^s starts moving faster.", m_name);
+ m_ptr->mspeed += 2;
+ }
+
+ break;
+ }
+
+ /* RF6_HAND_DOOM */
+ case 160 + 1:
+ {
+ disturb(1, 0);
+ msg_format("%^s invokes the Hand of Doom!", m_name);
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_format("You resist the effects!");
+ }
+ else
+ {
+ int dummy = (((s32b) ((65 + randint(25)) * (p_ptr->chp))) / 100);
+ msg_print("Your feel your life fade away!");
+ take_hit(dummy, m_name);
+ curse_equipment(100, 20);
+
+ if (p_ptr->chp < 1) p_ptr->chp = 1;
+ }
+ break;
+ }
+
+ /* RF6_HEAL */
+ case 160 + 2:
+ {
+ disturb(1, 0);
+
+ /* Message */
+ if (blind)
+ {
+ msg_format("%^s mumbles.", m_name);
+ }
+ else
+ {
+ msg_format("%^s concentrates on %s wounds.", m_name, m_poss);
+ }
+
+ /* Heal some */
+ m_ptr->hp += (rlev * 6);
+
+ /* Fully healed */
+ if (m_ptr->hp >= m_ptr->maxhp)
+ {
+ /* Fully healed */
+ m_ptr->hp = m_ptr->maxhp;
+
+ /* Message */
+ if (seen)
+ {
+ msg_format("%^s looks completely healed!", m_name);
+ }
+ else
+ {
+ msg_format("%^s sounds completely healed!", m_name);
+ }
+ }
+
+ /* Partially healed */
+ else
+ {
+ /* Message */
+ if (seen)
+ {
+ msg_format("%^s looks healthier.", m_name);
+ }
+ else
+ {
+ msg_format("%^s sounds healthier.", m_name);
+ }
+ }
+
+ /* Redraw (later) if needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Cancel fear */
+ if (m_ptr->monfear)
+ {
+ /* Cancel fear */
+ m_ptr->monfear = 0;
+
+ /* Message */
+ msg_format("%^s recovers %s courage.", m_name, m_poss);
+ }
+ break;
+ }
+
+ /* RF6_S_ANIMALS */
+ case 160 + 3:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons some animals!", m_name);
+ for (k = 0; k < 4; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_ANIMAL);
+ }
+ if (blind && count) msg_print("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_BLINK */
+ case 160 + 4:
+ {
+ disturb(1, 0);
+ msg_format("%^s blinks away.", m_name);
+ teleport_away(m_idx, 10);
+ break;
+ }
+
+ /* RF6_TPORT */
+ case 160 + 5:
+ {
+ disturb(1, 0);
+ msg_format("%^s teleports away.", m_name);
+ teleport_away(m_idx, MAX_SIGHT * 2 + 5);
+ break;
+ }
+
+ /* RF6_TELE_TO */
+ case 160 + 6:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ msg_format("%^s commands you to return.", m_name);
+ teleport_player_to(m_ptr->fy, m_ptr->fx);
+ break;
+ }
+
+ /* RF6_TELE_AWAY */
+ case 160 + 7:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ msg_format("%^s teleports you away.", m_name);
+ teleport_player(100);
+ break;
+ }
+
+ /* RF6_TELE_LEVEL */
+ case 160 + 8:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles strangely.", m_name);
+ else msg_format("%^s gestures at your feet.", m_name);
+ if (p_ptr->resist_nexus)
+ {
+ msg_print("You are unaffected!");
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ teleport_player_level();
+ }
+ update_smart_learn(m_idx, DRS_NEXUS);
+ break;
+ }
+
+ /* RF6_DARKNESS */
+ case 160 + 9:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s gestures in shadow.", m_name);
+ (void)unlite_area(0, 3);
+ break;
+ }
+
+ /* RF6_TRAPS */
+ case 160 + 10:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles, and then cackles evilly.", m_name);
+ else msg_format("%^s casts a spell and cackles evilly.", m_name);
+ (void)trap_creation();
+ break;
+ }
+
+ /* RF6_FORGET */
+ case 160 + 11:
+ {
+ if (!direct) break;
+ disturb(1, 0);
+ msg_format("%^s tries to blank your mind.", m_name);
+
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else if (lose_all_info())
+ {
+ msg_print("Your memories fade away.");
+ }
+ break;
+ }
+
+ /* RF6_ANIM_DEAD */
+ case 160 + 12:
+ break;
+
+ /* RF6_S_BUG */
+ case 160 + 13:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically codes some software bugs.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_BUG);
+ }
+ if (blind && count) msg_print("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_RNG */
+ case 160 + 14:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically codes some RNGs.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_RNG);
+ }
+ if (blind && count) msg_print("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_THUNDERLORD */
+ case 160 + 15:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons a Thunderlord!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_THUNDERLORD);
+ }
+ if (blind && count) msg_print("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_SUMMON_KIN */
+ case 160 + 16:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons %s %s.",
+ m_name, m_poss,
+ ((r_ptr->flags1) & RF1_UNIQUE ?
+ "minions" : "kin"));
+ summon_kin_type = r_ptr->d_char; /* Big hack */
+
+ for (k = 0; k < 6; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_KIN);
+ }
+ if (blind && count) msg_print("You hear many things appear nearby.");
+
+ break;
+ }
+
+ /* RF6_S_HI_DEMON */
+ case 160 + 17:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons greater demons!", m_name);
+ if (blind && count) msg_print("You hear heavy steps nearby.");
+ summon_cyber();
+ break;
+ }
+
+ /* RF6_S_MONSTER */
+ case 160 + 18:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons help!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ count += summon_specific(y, x, rlev, 0);
+ }
+ if (blind && count) msg_print("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_MONSTERS */
+ case 160 + 19:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons monsters!", m_name);
+ for (k = 0; k < 8; k++)
+ {
+ count += summon_specific(y, x, rlev, 0);
+ }
+ if (blind && count) msg_print("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_ANT */
+ case 160 + 20:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons ants.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_ANT);
+ }
+ if (blind && count) msg_print("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_SPIDER */
+ case 160 + 21:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons spiders.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_SPIDER);
+ }
+ if (blind && count) msg_print("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_HOUND */
+ case 160 + 22:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons hounds.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_HOUND);
+ }
+ if (blind && count) msg_print("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_HYDRA */
+ case 160 + 23:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons hydras.", m_name);
+ for (k = 0; k < 6; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_HYDRA);
+ }
+ if (blind && count) msg_print("You hear many things appear nearby.");
+ break;
+ }
+
+ /* RF6_S_ANGEL */
+ case 160 + 24:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons an angel!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_ANGEL);
+ }
+ if (blind && count) msg_print("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_DEMON */
+ case 160 + 25:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons a demon!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_DEMON);
+ }
+ if (blind && count) msg_print("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_UNDEAD */
+ case 160 + 26:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons an undead adversary!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_UNDEAD);
+ }
+ if (blind && count) msg_print("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_DRAGON */
+ case 160 + 27:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons a dragon!", m_name);
+ for (k = 0; k < 1; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_DRAGON);
+ }
+ if (blind && count) msg_print("You hear something appear nearby.");
+ break;
+ }
+
+ /* RF6_S_HI_UNDEAD */
+ case 160 + 28:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons greater undead!", m_name);
+ for (k = 0; k < 8; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_HI_UNDEAD);
+ }
+ if (blind && count)
+ {
+ msg_print("You hear many creepy things appear nearby.");
+ }
+ break;
+ }
+
+ /* RF6_S_HI_DRAGON */
+ case 160 + 29:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons ancient dragons!", m_name);
+ for (k = 0; k < 8; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_HI_DRAGON);
+ }
+ if (blind && count)
+ {
+ msg_print("You hear many powerful things appear nearby.");
+ }
+ break;
+ }
+
+ /* RF6_S_WRAITH */
+ case 160 + 30:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons Wraith!", m_name);
+
+
+ for (k = 0; k < 8; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_WRAITH);
+ }
+
+ if (blind && count)
+ {
+ msg_print("You hear immortal beings appear nearby.");
+ }
+ break;
+ }
+
+ /* RF6_S_UNIQUE */
+ case 160 + 31:
+ {
+ disturb(1, 0);
+ if (blind) msg_format("%^s mumbles.", m_name);
+ else msg_format("%^s magically summons special opponents!", m_name);
+ for (k = 0; k < 8; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_UNIQUE);
+ }
+ for (k = 0; k < 8; k++)
+ {
+ count += summon_specific(y, x, rlev, SUMMON_HI_UNDEAD);
+ }
+ if (blind && count)
+ {
+ msg_print("You hear many powerful things appear nearby.");
+ }
+ break;
+ }
+ }
+ }
+
+ /* Remember what the monster did to us */
+ if (seen)
+ {
+ /* Inate spell */
+ if (thrown_spell < 32*4)
+ {
+ r_ptr->r_flags4 |= (1L << (thrown_spell - 32 * 3));
+ if (r_ptr->r_cast_inate < MAX_UCHAR) r_ptr->r_cast_inate++;
+ }
+
+ /* Bolt or Ball */
+ else if (thrown_spell < 32*5)
+ {
+ r_ptr->r_flags5 |= (1L << (thrown_spell - 32 * 4));
+ if (r_ptr->r_cast_spell < MAX_UCHAR) r_ptr->r_cast_spell++;
+ }
+
+ /* Special spell */
+ else if (thrown_spell < 32*6)
+ {
+ r_ptr->r_flags6 |= (1L << (thrown_spell - 32 * 5));
+ if (r_ptr->r_cast_spell < MAX_UCHAR) r_ptr->r_cast_spell++;
+ }
+ }
+
+
+ /* Always take note of monsters that kill you */
+ if (death && (r_ptr->r_deaths < MAX_SHORT))
+ {
+ r_ptr->r_deaths++;
+ }
+
+ /* A spell was cast */
+ return (TRUE);
+}
+
+
+/*
+ * Returns whether a given monster will try to run from the player.
+ *
+ * Monsters will attempt to avoid very powerful players. See below.
+ *
+ * Because this function is called so often, little details are important
+ * for efficiency. Like not using "mod" or "div" when possible. And
+ * attempting to check the conditions in an optimal order. Note that
+ * "(x << 2) == (x * 4)" if "x" has enough bits to hold the result.
+ *
+ * Note that this function is responsible for about one to five percent
+ * of the processor use in normal conditions...
+ */
+static int mon_will_run(int m_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+#ifdef ALLOW_TERROR
+
+ u16b p_lev, m_lev;
+ u16b p_chp, p_mhp;
+ u16b m_chp, m_mhp;
+ u32b p_val, m_val;
+
+#endif
+
+ /* Keep monsters from running too far away */
+ if (m_ptr->cdis > MAX_SIGHT + 5) return (FALSE);
+
+ /* Friends don't run away */
+ if (is_friend(m_ptr) >= 0) return (FALSE);
+
+ /* All "afraid" monsters will run away */
+ if (m_ptr->monfear) return (TRUE);
+
+#ifdef ALLOW_TERROR
+
+ /* Nearby monsters will not become terrified */
+ if (m_ptr->cdis <= 5) return (FALSE);
+
+ /* Examine player power (level) */
+ p_lev = p_ptr->lev;
+
+ /* Examine monster power (level plus morale) */
+ m_lev = m_ptr->level + (m_idx & 0x08) + 25;
+
+ /* Optimize extreme cases below */
+ if (m_lev > p_lev + 4) return (FALSE);
+ if (m_lev + 4 <= p_lev) return (TRUE);
+
+ /* Examine player health */
+ p_chp = p_ptr->chp;
+ p_mhp = p_ptr->mhp;
+
+ /* Examine monster health */
+ m_chp = m_ptr->hp;
+ m_mhp = m_ptr->maxhp;
+
+ /* Prepare to optimize the calculation */
+ p_val = (p_lev * p_mhp) + (p_chp << 2); /* div p_mhp */
+ m_val = (m_lev * m_mhp) + (m_chp << 2); /* div m_mhp */
+
+ /* Strong players scare strong monsters */
+ if (p_val * m_mhp > m_val * p_mhp) return (TRUE);
+
+#endif
+
+ /* Assume no terror */
+ return (FALSE);
+}
+
+
+
+
+/*
+* Choose the "best" direction for "flowing"
+*
+* Note that ghosts and rock-eaters are never allowed to "flow",
+* since they should move directly towards the player.
+*
+* Prefer "non-diagonal" directions, but twiddle them a little
+* to angle slightly towards the player's actual location.
+*
+* Allow very perceptive monsters to track old "spoor" left by
+* previous locations occupied by the player. This will tend
+* to have monsters end up either near the player or on a grid
+* recently occupied by the player (and left via "teleport").
+*
+* Note that if "smell" is turned on, all monsters get vicious.
+*
+* Also note that teleporting away from a location will cause
+* the monsters who were chasing you to converge on that location
+* as long as you are still near enough to "annoy" them without
+* being close enough to chase directly. I have no idea what will
+* happen if you combine "smell" with low "aaf" values.
+*/
+
+/*
+* Provide a location to flee to, but give the player a wide berth.
+*
+* A monster may wish to flee to a location that is behind the player,
+* but instead of heading directly for it, the monster should "swerve"
+* around the player so that he has a smaller chance of getting hit.
+*/
+static bool_ get_fear_moves_aux(int m_idx, int *yp, int *xp)
+{
+ int y, x, y1, x1, fy, fx, gy = 0, gx = 0;
+ int when = 0, score = -1;
+ int i;
+
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Monster flowing disabled */
+ if (!flow_by_sound) return (FALSE);
+
+ /* Monster location */
+ fy = m_ptr->fy;
+ fx = m_ptr->fx;
+
+ /* Desired destination */
+ y1 = fy - (*yp);
+ x1 = fx - (*xp);
+
+ /* The player is not currently near the monster grid */
+ if (cave[fy][fx].when < cave[p_ptr->py][p_ptr->px].when)
+ {
+ /* No reason to attempt flowing */
+ return (FALSE);
+ }
+
+ /* Monster is too far away to use flow information */
+ if (cave[fy][fx].cost > MONSTER_FLOW_DEPTH) return (FALSE);
+ if (cave[fy][fx].cost > r_ptr->aaf) return (FALSE);
+
+ /* Check nearby grids, diagonals first */
+ for (i = 7; i >= 0; i--)
+ {
+ int dis, s;
+
+ /* Get the location */
+ y = fy + ddy_ddd[i];
+ x = fx + ddx_ddd[i];
+
+ /* Ignore illegal locations */
+ if (cave[y][x].when == 0) continue;
+
+ /* Ignore ancient locations */
+ if (cave[y][x].when < when) continue;
+
+ /* Calculate distance of this grid from our destination */
+ dis = distance(y, x, y1, x1);
+
+ /* Score this grid */
+ s = 5000 / (dis + 3) - 500 / (cave[y][x].cost + 1);
+
+ /* No negative scores */
+ if (s < 0) s = 0;
+
+ /* Ignore lower scores */
+ if (s < score) continue;
+
+ /* Save the score and time */
+ when = cave[y][x].when;
+ score = s;
+
+ /* Save the location */
+ gy = y;
+ gx = x;
+ }
+
+ /* No legal move (?) */
+ if (!when) return (FALSE);
+
+ /* Find deltas */
+ (*yp) = fy - gy;
+ (*xp) = fx - gx;
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+* Choose a "safe" location near a monster for it to run toward.
+*
+* A location is "safe" if it can be reached quickly and the player
+* is not able to fire into it (it isn't a "clean shot"). So, this will
+* cause monsters to "duck" behind walls. Hopefully, monsters will also
+* try to run towards corridor openings if they are in a room.
+*
+* This function may take lots of CPU time if lots of monsters are
+* fleeing.
+*
+* Return TRUE if a safe location is available.
+*/
+static bool_ find_safety(int m_idx, int *yp, int *xp)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ int fy = m_ptr->fy;
+ int fx = m_ptr->fx;
+
+ int y, x, d, dis;
+ int gy = 0, gx = 0, gdis = 0;
+
+ /* Start with adjacent locations, spread further */
+ for (d = 1; d < 10; d++)
+ {
+ /* Check nearby locations */
+ for (y = fy - d; y <= fy + d; y++)
+ {
+ for (x = fx - d; x <= fx + d; x++)
+ {
+ /* Skip illegal locations */
+ if (!in_bounds(y, x)) continue;
+
+ /* Skip locations in a wall */
+ if (!cave_floor_bold(y, x)) continue;
+
+ /* Check distance */
+ if (distance(y, x, fy, fx) != d) continue;
+
+ /* Check for "availability" (if monsters can flow) */
+ if (flow_by_sound)
+ {
+ /* Ignore grids very far from the player */
+ if (cave[y][x].when < cave[p_ptr->py][p_ptr->px].when) continue;
+
+ /* Ignore too-distant grids */
+ if (cave[y][x].cost > cave[fy][fx].cost + 2 * d) continue;
+ }
+
+ /* Check for absence of shot */
+ if (!projectable(y, x, p_ptr->py, p_ptr->px))
+ {
+ /* Calculate distance from player */
+ dis = distance(y, x, p_ptr->py, p_ptr->px);
+
+ /* Remember if further than previous */
+ if (dis > gdis)
+ {
+ gy = y;
+ gx = x;
+ gdis = dis;
+ }
+ }
+ }
+ }
+
+ /* Check for success */
+ if (gdis > 0)
+ {
+ /* Good location */
+ (*yp) = fy - gy;
+ (*xp) = fx - gx;
+
+ /* Found safe place */
+ return (TRUE);
+ }
+ }
+
+ /* No safe place */
+ return (FALSE);
+}
+
+
+/*
+ * Choose a good hiding place near a monster for it to run toward.
+ *
+ * Pack monsters will use this to "ambush" the player and lure him out
+ * of corridors into open space so they can swarm him.
+ *
+ * Return TRUE if a good location is available.
+ */
+static bool_ find_hiding(int m_idx, int *yp, int *xp)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ int fy = m_ptr->fy;
+ int fx = m_ptr->fx;
+
+ int y, x, d, dis;
+ int gy = 0, gx = 0, gdis = 999, min;
+
+ /* Closest distance to get */
+ min = distance(p_ptr->py, p_ptr->px, fy, fx) * 3 / 4 + 2;
+
+ /* Start with adjacent locations, spread further */
+ for (d = 1; d < 10; d++)
+ {
+ /* Check nearby locations */
+ for (y = fy - d; y <= fy + d; y++)
+ {
+ for (x = fx - d; x <= fx + d; x++)
+ {
+ /* Skip illegal locations */
+ if (!in_bounds(y, x)) continue;
+
+ /* Skip locations in a wall */
+ if (!cave_floor_bold(y, x)) continue;
+
+ /* Check distance */
+ if (distance(y, x, fy, fx) != d) continue;
+
+ /* Check for hidden, available grid */
+ if (!player_can_see_bold(y, x) && clean_shot(fy, fx, y, x))
+ {
+ /* Calculate distance from player */
+ dis = distance(y, x, p_ptr->py, p_ptr->px);
+
+ /* Remember if closer than previous */
+ if (dis < gdis && dis >= min)
+ {
+ gy = y;
+ gx = x;
+ gdis = dis;
+ }
+ }
+ }
+ }
+
+ /* Check for success */
+ if (gdis < 999)
+ {
+ /* Good location */
+ (*yp) = fy - gy;
+ (*xp) = fx - gx;
+
+ /* Found good place */
+ return (TRUE);
+ }
+ }
+
+ /* No good place */
+ return (FALSE);
+}
+
+
+/* Find an appropriate corpse */
+void find_corpse(monster_type *m_ptr, int *y, int *x)
+{
+ int k, last = -1;
+
+ for (k = 0; k < max_o_idx; k++)
+ {
+ object_type *o_ptr = &o_list[k];
+ monster_race *rt_ptr, *rt2_ptr;
+
+ if (!o_ptr->k_idx) continue;
+
+ if (o_ptr->tval != TV_CORPSE) continue;
+ if ((o_ptr->sval != SV_CORPSE_CORPSE) && (o_ptr->sval != SV_CORPSE_SKELETON)) continue;
+
+ rt_ptr = &r_info[o_ptr->pval2];
+
+ /* Cannot incarnate into a higher level monster */
+ if (rt_ptr->level > m_ptr->level) continue;
+
+ /* Must be in LOS */
+ if (!los(m_ptr->fy, m_ptr->fx, o_ptr->iy, o_ptr->ix)) continue;
+
+ if (last != -1)
+ {
+ rt2_ptr = &r_info[o_list[last].pval2];
+ if (rt_ptr->level > rt2_ptr->level) last = k;
+ else continue;
+ }
+ else
+ {
+ last = k;
+ }
+ }
+
+ /* Must be ok now */
+ if (last != -1)
+ {
+ *y = o_list[last].iy;
+ *x = o_list[last].ix;
+ }
+}
+
+/*
+ * Choose target
+ */
+static void get_target_monster(int m_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ int i, t = -1, d = 9999;
+
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *t_ptr = &m_list[i];
+ /* hack should call the function for ego monsters ... but no_target i not meant to be added by ego and it speeds up the code */
+ monster_race *rt_ptr = &r_info[t_ptr->r_idx];
+ int dd;
+
+ /* Ignore "dead" monsters */
+ if (!t_ptr->r_idx) continue;
+
+ if (m_idx == i) continue;
+
+ /* Cannot be targeted */
+ if (rt_ptr->flags7 & RF7_NO_TARGET) continue;
+
+ if (is_enemy(m_ptr, t_ptr) && (los(m_ptr->fy, m_ptr->fx, t_ptr->fy, t_ptr->fx) &&
+ ((dd = distance(m_ptr->fy, m_ptr->fx, t_ptr->fy, t_ptr->fx)) < d)))
+ {
+ t = i;
+ d = dd;
+ }
+ }
+ /* Hack */
+ if ((is_friend(m_ptr) < 0) && los(m_ptr->fy, m_ptr->fx, p_ptr->py, p_ptr->px) && (distance(m_ptr->fy, m_ptr->fx, p_ptr->py, p_ptr->px) < d)) t = 0;
+
+ m_ptr->target = t;
+}
+
+/*
+ * Choose "logical" directions for monster movement
+ */
+static bool_ get_moves(int m_idx, int *mm)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ int y, ay, x, ax;
+
+ int move_val = 0;
+
+ int y2 = p_ptr->py;
+ int x2 = p_ptr->px;
+ bool_ done = FALSE;
+
+ /* Oups get nearer */
+ if ((is_friend(m_ptr) > 0) && (m_ptr->cdis > p_ptr->pet_follow_distance))
+ {
+ y2 = p_ptr->py;
+ x2 = p_ptr->px;
+ }
+ /* Use the target */
+ else if (!m_ptr->target)
+ {
+ y2 = p_ptr->py;
+ x2 = p_ptr->px;
+ }
+ else if (m_ptr->target > 0)
+ {
+ y2 = m_list[m_ptr->target].fy;
+ x2 = m_list[m_ptr->target].fx;
+ }
+
+ /* Hack doppleganger confuses monsters(even pets) */
+ if (doppleganger)
+ {
+ if (magik(70))
+ {
+ y2 = m_list[doppleganger].fy;
+ x2 = m_list[doppleganger].fx;
+ }
+ }
+
+ /* A possessor is not interrested in the player, it only wants a corpse */
+ if (r_ptr->flags7 & RF7_POSSESSOR)
+ {
+ find_corpse(m_ptr, &y2, &x2);
+ }
+
+ /* Let quests redefine AI */
+ if (r_ptr->flags7 & RF7_AI_SPECIAL)
+ {
+ if (process_hooks_ret(HOOK_MONSTER_AI, "dd", "(d)", m_idx))
+ {
+ y2 = process_hooks_return[0].num;
+ x2 = process_hooks_return[1].num;
+ }
+ }
+
+ if (m_idx == p_ptr->control)
+ {
+ if ((r_ptr->flags7 & RF7_AI_PLAYER) || magik(85))
+ {
+ if (distance(p_ptr->py, p_ptr->px, m_ptr->fy, m_ptr->fx) < 50)
+ {
+ y2 = m_ptr->fy + ddy[p_ptr->control_dir];
+ x2 = m_ptr->fx + ddx[p_ptr->control_dir];
+ }
+ }
+ }
+
+ /* Extract the "pseudo-direction" */
+ y = m_ptr->fy - y2;
+ x = m_ptr->fx - x2;
+
+ /* Tease the player */
+ if (r_ptr->flags7 & RF7_AI_ANNOY)
+ {
+ if (distance(m_ptr->fy, m_ptr->fx, y2, x2) < 4)
+ {
+ y = -y;
+ x = -x;
+ }
+ }
+
+ /* Death orbs .. */
+ if (r_ptr->flags2 & RF2_DEATH_ORB)
+ {
+ if (!los(m_ptr->fy, m_ptr->fx, y2, x2))
+ {
+ return (FALSE);
+ }
+ }
+
+ if (!stupid_monsters && (is_friend(m_ptr) < 0))
+ {
+ int tx = x2, ty = y2;
+
+ /*
+ * Animal packs try to get the player out of corridors
+ * (...unless they can move through walls -- TY)
+ */
+ if ((r_ptr->flags1 & RF1_FRIENDS) &&
+ (r_ptr->flags3 & RF3_ANIMAL) &&
+ !((r_ptr->flags2 & (RF2_PASS_WALL)) ||
+ (r_ptr->flags2 & (RF2_KILL_WALL))))
+ {
+ int i, room = 0;
+
+ /* Count room grids next to player */
+ for (i = 0; i < 8; i++)
+ {
+ /* Check grid */
+ if (cave[ty + ddy_ddd[i]][tx + ddx_ddd[i]].info & (CAVE_ROOM))
+ {
+ /* One more room grid */
+ room++;
+ }
+ }
+
+ /* Not in a room and strong player */
+ if ((room < 8) && (p_ptr->chp > ((p_ptr->mhp * 3) / 4)))
+ {
+ /* Find hiding place */
+ if (find_hiding(m_idx, &y, &x)) done = TRUE;
+ }
+ }
+
+ /* Monster groups try to surround the player */
+ if (!done && (r_ptr->flags1 & RF1_FRIENDS))
+ {
+ int i;
+
+ /* Find an empty square near the target to fill */
+ for (i = 0; i < 8; i++)
+ {
+ /* Pick squares near target (semi-randomly) */
+ y2 = ty + ddy_ddd[(m_idx + i) & 7];
+ x2 = tx + ddx_ddd[(m_idx + i) & 7];
+
+ /* Already there? */
+ if ((m_ptr->fy == y2) && (m_ptr->fx == x2))
+ {
+ /* Attack the target */
+ y2 = ty;
+ x2 = tx;
+
+ break;
+ }
+
+ /* Ignore filled grids */
+ if (!cave_empty_bold(y2, x2)) continue;
+
+ /* Try to fill this hole */
+ break;
+ }
+
+ /* Extract the new "pseudo-direction" */
+ y = m_ptr->fy - y2;
+ x = m_ptr->fx - x2;
+
+ /* Done */
+ done = TRUE;
+ }
+ }
+
+ /* Apply fear if possible and necessary */
+ if ((stupid_monsters) || (is_friend(m_ptr) > 0))
+ {
+ if (mon_will_run(m_idx))
+ {
+ /* XXX XXX Not very "smart" */
+ y = ( -y), x = ( -x);
+ }
+ }
+ else
+ {
+ if (!done && mon_will_run(m_idx))
+ {
+ /* Try to find safe place */
+ if (!find_safety(m_idx, &y, &x))
+ {
+ /* This is not a very "smart" method XXX XXX */
+ y = ( -y);
+ x = ( -x);
+ }
+ else
+ {
+ /* Attempt to avoid the player */
+ if (flow_by_sound)
+ {
+ /* Adjust movement */
+ (void)get_fear_moves_aux(m_idx, &y, &x);
+ }
+ }
+ }
+ }
+
+
+ if (!stupid_monsters)
+ {
+ /* Check for no move */
+ if (!x && !y) return (FALSE);
+ }
+
+ /* Extract the "absolute distances" */
+ ax = ABS(x);
+ ay = ABS(y);
+
+ /* Do something weird */
+ if (y < 0) move_val += 8;
+ if (x > 0) move_val += 4;
+
+ /* Prevent the diamond maneuvre */
+ if (ay > (ax << 1))
+ {
+ move_val++;
+ move_val++;
+ }
+ else if (ax > (ay << 1))
+ {
+ move_val++;
+ }
+
+ /* Extract some directions */
+ switch (move_val)
+ {
+ case 0:
+ mm[0] = 9;
+ if (ay > ax)
+ {
+ mm[1] = 8;
+ mm[2] = 6;
+ mm[3] = 7;
+ mm[4] = 3;
+ }
+ else
+ {
+ mm[1] = 6;
+ mm[2] = 8;
+ mm[3] = 3;
+ mm[4] = 7;
+ }
+ break;
+ case 1:
+ case 9:
+ mm[0] = 6;
+ if (y < 0)
+ {
+ mm[1] = 3;
+ mm[2] = 9;
+ mm[3] = 2;
+ mm[4] = 8;
+ }
+ else
+ {
+ mm[1] = 9;
+ mm[2] = 3;
+ mm[3] = 8;
+ mm[4] = 2;
+ }
+ break;
+ case 2:
+ case 6:
+ mm[0] = 8;
+ if (x < 0)
+ {
+ mm[1] = 9;
+ mm[2] = 7;
+ mm[3] = 6;
+ mm[4] = 4;
+ }
+ else
+ {
+ mm[1] = 7;
+ mm[2] = 9;
+ mm[3] = 4;
+ mm[4] = 6;
+ }
+ break;
+ case 4:
+ mm[0] = 7;
+ if (ay > ax)
+ {
+ mm[1] = 8;
+ mm[2] = 4;
+ mm[3] = 9;
+ mm[4] = 1;
+ }
+ else
+ {
+ mm[1] = 4;
+ mm[2] = 8;
+ mm[3] = 1;
+ mm[4] = 9;
+ }
+ break;
+ case 5:
+ case 13:
+ mm[0] = 4;
+ if (y < 0)
+ {
+ mm[1] = 1;
+ mm[2] = 7;
+ mm[3] = 2;
+ mm[4] = 8;
+ }
+ else
+ {
+ mm[1] = 7;
+ mm[2] = 1;
+ mm[3] = 8;
+ mm[4] = 2;
+ }
+ break;
+ case 8:
+ mm[0] = 3;
+ if (ay > ax)
+ {
+ mm[1] = 2;
+ mm[2] = 6;
+ mm[3] = 1;
+ mm[4] = 9;
+ }
+ else
+ {
+ mm[1] = 6;
+ mm[2] = 2;
+ mm[3] = 9;
+ mm[4] = 1;
+ }
+ break;
+ case 10:
+ case 14:
+ mm[0] = 2;
+ if (x < 0)
+ {
+ mm[1] = 3;
+ mm[2] = 1;
+ mm[3] = 6;
+ mm[4] = 4;
+ }
+ else
+ {
+ mm[1] = 1;
+ mm[2] = 3;
+ mm[3] = 4;
+ mm[4] = 6;
+ }
+ break;
+ case 12:
+ mm[0] = 1;
+ if (ay > ax)
+ {
+ mm[1] = 2;
+ mm[2] = 4;
+ mm[3] = 3;
+ mm[4] = 7;
+ }
+ else
+ {
+ mm[1] = 4;
+ mm[2] = 2;
+ mm[3] = 7;
+ mm[4] = 3;
+ }
+ break;
+ }
+
+
+
+ /* Wants to move... */
+ return (TRUE);
+}
+
+
+int check_hit2(int power, int level, int ac)
+{
+ int i, k;
+
+ /* Percentile dice */
+ k = rand_int(100);
+
+ /* Hack -- Always miss or hit */
+ if (k < 10) return (k < 5);
+
+ /* Calculate the "attack quality" */
+ i = (power + (level * 3));
+
+ /* Power and Level compete against Armor */
+ if ((i > 0) && (randint(i) > ((ac * 3) / 4))) return (TRUE);
+
+ /* Assume miss */
+ return (FALSE);
+}
+
+
+/* Monster attacks monster */
+static bool_ monst_attack_monst(int m_idx, int t_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx], *t_ptr = &m_list[t_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+ monster_race *tr_ptr = race_inf(t_ptr);
+ int ap_cnt;
+ int ac, rlev, pt;
+ char m_name[80], t_name[80];
+ char ddesc[80], temp[80];
+ bool_ blinked = FALSE, touched = FALSE;
+ bool_ explode = FALSE;
+ bool_ fear = FALSE;
+ byte y_saver = t_ptr->fy;
+ byte x_saver = t_ptr->fx;
+
+
+ /* Not allowed to attack */
+ if (r_ptr->flags1 & RF1_NEVER_BLOW) return FALSE;
+ if (tr_ptr->flags7 & RF7_IM_MELEE) return FALSE;
+
+ /* Total armor */
+ ac = t_ptr->ac;
+
+ /* Extract the effective monster level */
+ rlev = ((m_ptr->level >= 1) ? m_ptr->level : 1);
+
+ /* Get the monster name (or "it") */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Get the monster name (or "it") */
+ monster_desc(t_name, t_ptr, 0);
+
+ /* Get the "died from" information (i.e. "a kobold") */
+ monster_desc(ddesc, m_ptr, 0x88);
+
+ /* Assume no blink */
+ blinked = FALSE;
+
+ if (!(m_ptr->ml || t_ptr->ml))
+ {
+ monster_msg("You hear noise.");
+ }
+
+ /* Scan through all four blows */
+ for (ap_cnt = 0; ap_cnt < 4; ap_cnt++)
+ {
+ bool_ visible = FALSE;
+ bool_ obvious = FALSE;
+
+ int power = 0;
+ int damage = 0;
+
+ cptr act = NULL;
+
+ /* Extract the attack infomation */
+ int effect = m_ptr->blow[ap_cnt].effect;
+ int method = m_ptr->blow[ap_cnt].method;
+ int d_dice = m_ptr->blow[ap_cnt].d_dice;
+ int d_side = m_ptr->blow[ap_cnt].d_side;
+
+ if (t_ptr == m_ptr) /* Paranoia */
+ {
+ if (wizard)
+ monster_msg("Monster attacking self?");
+ break;
+ }
+
+ /* Stop attacking if the target dies! */
+ if (t_ptr->fx != x_saver || t_ptr->fy != y_saver)
+ break;
+
+ /* Hack -- no more attacks */
+ if (!method) break;
+
+ if (blinked) /* Stop! */
+ {
+ /* break; */
+ }
+
+ /* Extract visibility (before blink) */
+ if (m_ptr->ml) visible = TRUE;
+
+ /* Extract the attack "power" */
+ power = get_attack_power(effect);
+
+
+ /* Monster hits*/
+ if (!effect || check_hit2(power, rlev, ac))
+ {
+ /* Always disturbing */
+ if (disturb_other) disturb(1, 0);
+
+ /* Describe the attack method */
+ switch (method)
+ {
+ case RBM_HIT:
+ {
+ act = "hits %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_TOUCH:
+ {
+ act = "touches %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_PUNCH:
+ {
+ act = "punches %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_KICK:
+ {
+ act = "kicks %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CLAW:
+ {
+ act = "claws %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_BITE:
+ {
+ act = "bites %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_STING:
+ {
+ act = "stings %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_XXX1:
+ {
+ act = "XXX1's %s.";
+ break;
+ }
+
+ case RBM_BUTT:
+ {
+ act = "butts %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CRUSH:
+ {
+ act = "crushes %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_ENGULF:
+ {
+ act = "engulfs %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CHARGE:
+ {
+ act = "charges %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_CRAWL:
+ {
+ act = "crawls on %s.";
+ touched = TRUE;
+ break;
+ }
+
+ case RBM_DROOL:
+ {
+ act = "drools on %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_SPIT:
+ {
+ act = "spits on %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_EXPLODE:
+ {
+ act = "explodes.";
+ explode = TRUE;
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_GAZE:
+ {
+ act = "gazes at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_WAIL:
+ {
+ act = "wails at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_SPORE:
+ {
+ act = "releases spores at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_XXX4:
+ {
+ act = "projects XXX4's at %s.";
+ touched = FALSE;
+ break;
+ }
+
+ case RBM_BEG:
+ {
+ act = "begs %s for money.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+
+ case RBM_INSULT:
+ {
+ act = "insults %s.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+
+ case RBM_MOAN:
+ {
+ act = "moans at %s.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+
+ case RBM_SHOW:
+ {
+ act = "sings to %s.";
+ touched = FALSE;
+ t_ptr->csleep = 0;
+ break;
+ }
+ }
+
+ /* Message */
+ if (act)
+ {
+ strfmt(temp, act, t_name);
+ if (m_ptr->ml || t_ptr->ml)
+ monster_msg("%^s %s", m_name, temp);
+
+ }
+
+ /* Hack -- assume all attacks are obvious */
+ obvious = TRUE;
+
+ /* Roll out the damage */
+ damage = damroll(d_dice, d_side);
+
+ /* Hack need more punch against monsters */
+ damage *= 3;
+
+ pt = GF_MISSILE;
+
+ /* Apply appropriate damage */
+ switch (effect)
+ {
+ case 0:
+ {
+ damage = 0;
+ pt = 0;
+ break;
+ }
+
+ case RBE_HURT:
+ case RBE_SANITY:
+ {
+ damage -= (damage * ((ac < 150) ? ac : 150) / 250);
+ break;
+ }
+
+ case RBE_POISON:
+ case RBE_DISEASE:
+ {
+ pt = GF_POIS;
+ break;
+ }
+
+ case RBE_UN_BONUS:
+ case RBE_UN_POWER:
+ case RBE_ABOMINATION:
+ {
+ pt = GF_DISENCHANT;
+ break;
+ }
+
+ case RBE_EAT_FOOD:
+ case RBE_EAT_LITE:
+ {
+ pt = damage = 0;
+ break;
+ }
+
+ case RBE_EAT_ITEM:
+ case RBE_EAT_GOLD:
+ {
+ pt = damage = 0;
+ if (randint(2) == 1) blinked = TRUE;
+ break;
+ }
+
+ case RBE_ACID:
+ {
+ pt = GF_ACID;
+ break;
+ }
+
+ case RBE_ELEC:
+ {
+ pt = GF_ELEC;
+ break;
+ }
+
+ case RBE_FIRE:
+ {
+ pt = GF_FIRE;
+ break;
+ }
+
+ case RBE_COLD:
+ {
+ pt = GF_COLD;
+ break;
+ }
+
+ case RBE_BLIND:
+ {
+ break;
+ }
+
+ case RBE_HALLU:
+ case RBE_CONFUSE:
+ {
+ pt = GF_CONFUSION;
+ break;
+ }
+
+ case RBE_TERRIFY:
+ {
+ pt = GF_TURN_ALL;
+ break;
+ }
+
+ case RBE_PARALYZE:
+ {
+ pt = GF_OLD_SLEEP; /* sort of close... */
+ break;
+ }
+
+ case RBE_LOSE_STR:
+ case RBE_LOSE_INT:
+ case RBE_LOSE_WIS:
+ case RBE_LOSE_DEX:
+ case RBE_LOSE_CON:
+ case RBE_LOSE_CHR:
+ case RBE_LOSE_ALL:
+ case RBE_PARASITE:
+ {
+ break;
+ }
+ case RBE_SHATTER:
+ {
+ if (damage > 23)
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(m_ptr->fy, m_ptr->fx, 8);
+ }
+ break;
+ }
+ case RBE_EXP_10:
+ case RBE_EXP_20:
+ case RBE_EXP_40:
+ case RBE_EXP_80:
+ {
+ pt = GF_NETHER;
+ break;
+ }
+ case RBE_TIME:
+ {
+ pt = GF_TIME;
+ break;
+ }
+ default:
+ {
+ pt = 0;
+ break;
+ }
+ }
+
+ if (pt)
+ {
+ /* Do damage if not exploding */
+ if (!explode)
+ {
+ project(m_idx, 0, t_ptr->fy, t_ptr->fx,
+ (pt == GF_OLD_SLEEP ? m_ptr->level : damage), pt, PROJECT_KILL | PROJECT_STOP);
+ }
+
+ if (touched)
+ {
+ /* Aura fire */
+ if ((tr_ptr->flags2 & RF2_AURA_FIRE) &&
+ !(r_ptr->flags3 & RF3_IM_FIRE))
+ {
+ if (m_ptr->ml || t_ptr->ml)
+ {
+ blinked = FALSE;
+ monster_msg("%^s is suddenly very hot!", m_name);
+ if (t_ptr->ml)
+ tr_ptr->r_flags2 |= RF2_AURA_FIRE;
+ }
+ project(t_idx, 0, m_ptr->fy, m_ptr->fx,
+ damroll (1 + ((t_ptr->level) / 26),
+ 1 + ((t_ptr->level) / 17)),
+ GF_FIRE, PROJECT_KILL | PROJECT_STOP);
+ }
+
+ /* Aura elec */
+ if ((tr_ptr->flags2 & (RF2_AURA_ELEC)) && !(r_ptr->flags3 & (RF3_IM_ELEC)))
+ {
+ if (m_ptr->ml || t_ptr->ml)
+ {
+ blinked = FALSE;
+ monster_msg("%^s gets zapped!", m_name);
+ if (t_ptr->ml)
+ tr_ptr->r_flags2 |= RF2_AURA_ELEC;
+ }
+ project(t_idx, 0, m_ptr->fy, m_ptr->fx,
+ damroll (1 + ((t_ptr->level) / 26),
+ 1 + ((t_ptr->level) / 17)),
+ GF_ELEC, PROJECT_KILL | PROJECT_STOP);
+ }
+
+ }
+ }
+ }
+
+ /* Monster missed player */
+ else
+ {
+ /* Analyze failed attacks */
+ switch (method)
+ {
+ case RBM_HIT:
+ case RBM_TOUCH:
+ case RBM_PUNCH:
+ case RBM_KICK:
+ case RBM_CLAW:
+ case RBM_BITE:
+ case RBM_STING:
+ case RBM_XXX1:
+ case RBM_BUTT:
+ case RBM_CRUSH:
+ case RBM_ENGULF:
+ case RBM_CHARGE:
+ {
+ /* Visible monsters */
+ if (m_ptr->ml)
+ {
+ /* Disturbing */
+ disturb(1, 0);
+
+ /* Message */
+ monster_msg("%^s misses %s.", m_name, t_name);
+ }
+
+ break;
+ }
+ }
+ }
+
+
+ /* Analyze "visible" monsters only */
+ if (visible)
+ {
+ /* Count "obvious" attacks (and ones that cause damage) */
+ if (obvious || damage || (r_ptr->r_blows[ap_cnt] > 10))
+ {
+ /* Count attacks of this type */
+ if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR)
+ {
+ r_ptr->r_blows[ap_cnt]++;
+ }
+ }
+ }
+ }
+
+ if (explode)
+ {
+ sound(SOUND_EXPLODE);
+ mon_take_hit_mon(m_idx, m_idx, m_ptr->hp + 1, &fear, " explodes into tiny shreds.");
+
+ blinked = FALSE;
+ }
+
+
+ /* Blink away */
+ if (blinked)
+ {
+ if (m_ptr->ml)
+ {
+ monster_msg("The thief flees laughing!");
+ }
+ else
+ {
+ monster_msg("You hear laughter!");
+ }
+
+ teleport_away(m_idx, MAX_SIGHT * 2 + 5);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Hack -- local "player stealth" value (see below)
+ */
+static u32b noise = 0L;
+
+/* Determine whether the player is invisible to a monster */
+static bool_ player_invis(monster_type * m_ptr)
+{
+ s16b inv, mlv;
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ inv = p_ptr->invis;
+
+ mlv = (s16b) m_ptr->level;
+
+ if (r_ptr->flags3 & RF3_NO_SLEEP)
+ mlv += 10;
+ if (r_ptr->flags3 & RF3_DRAGON)
+ mlv += 20;
+ if (r_ptr->flags3 & RF3_UNDEAD)
+ mlv += 15;
+ if (r_ptr->flags3 & RF3_DEMON)
+ mlv += 15;
+ if (r_ptr->flags3 & RF3_ANIMAL)
+ mlv += 15;
+ if (r_ptr->flags3 & RF3_ORC)
+ mlv -= 15;
+ if (r_ptr->flags3 & RF3_TROLL)
+ mlv -= 10;
+ if (r_ptr->flags2 & RF2_STUPID)
+ mlv /= 2;
+ if (r_ptr->flags2 & RF2_SMART)
+ mlv = (mlv * 5) / 4;
+ if (m_ptr->mflag & MFLAG_QUEST)
+ inv = 0;
+ if (r_ptr->flags2 & RF2_INVISIBLE)
+ inv = 0;
+ if (m_ptr->mflag & MFLAG_CONTROL)
+ inv = 0;
+ if (mlv < 1)
+ mlv = 1;
+ return (inv >= randint(mlv*2));
+}
+
+/*
+ * Process a monster
+ *
+ * The monster is known to be within 100 grids of the player
+ *
+ * In several cases, we directly update the monster lore
+ *
+ * Note that a monster is only allowed to "reproduce" if there
+ * are a limited number of "reproducing" monsters on the current
+ * level. This should prevent the level from being "swamped" by
+ * reproducing monsters. It also allows a large mass of mice to
+ * prevent a louse from multiplying, but this is a small price to
+ * pay for a simple multiplication method.
+ *
+ * XXX Monster fear is slightly odd, in particular, monsters will
+ * fixate on opening a door even if they cannot open it. Actually,
+ * the same thing happens to normal monsters when they hit a door
+ *
+ * XXX XXX XXX In addition, monsters which *cannot* open or bash
+ * down a door will still stand there trying to open it...
+ *
+ * XXX Technically, need to check for monster in the way
+ * combined with that monster being in a wall (or door?)
+ *
+ * A "direction" of "5" means "pick a random direction".
+ */
+static void process_monster(int m_idx, bool_ is_frien)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+ cave_type *c_ptr = &cave[m_ptr->fy][m_ptr->fx];
+
+ int i, d, oy, ox, ny, nx;
+
+ int mm[8];
+
+ monster_type *y_ptr;
+
+ bool_ do_turn;
+ bool_ do_move;
+ bool_ do_view;
+
+ bool_ did_open_door;
+ bool_ did_bash_door;
+ bool_ did_take_item;
+ bool_ did_kill_item;
+ bool_ did_move_body;
+ bool_ did_kill_body;
+ bool_ did_pass_wall;
+ bool_ did_kill_wall;
+ bool_ gets_angry = FALSE;
+ bool_ inv;
+ bool_ xxx = FALSE;
+
+ inv = player_invis(m_ptr);
+
+ if (r_ptr->flags9 & RF9_DOPPLEGANGER) doppleganger = m_idx;
+
+ /* Handle "bleeding" */
+ if (m_ptr->bleeding)
+ {
+ int d = 1 + (m_ptr->maxhp / 50);
+ if (d > m_ptr->bleeding) d = m_ptr->bleeding;
+
+ /* Exit if the monster dies */
+ if (mon_take_hit(m_idx, d, &xxx, " bleeds to death.")) return;
+
+ /* Hack -- Recover from bleeding */
+ if (m_ptr->bleeding > d)
+ {
+ /* Recover somewhat */
+ m_ptr->bleeding -= d;
+ }
+
+ /* Fully recover */
+ else
+ {
+ /* Recover fully */
+ m_ptr->bleeding = 0;
+
+ /* Message if visible */
+ if (m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Get the monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Dump a message */
+ msg_format("%^s is no longer bleeding.", m_name);
+
+ /* Hack -- Update the health bar */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+ }
+ }
+ }
+
+ /* Handle "poisoned" */
+ if (m_ptr->poisoned)
+ {
+ int d = (m_ptr->poisoned) / 10;
+ if (d < 1) d = 1;
+
+ /* Exit if the monster dies */
+ if (mon_take_hit(m_idx, d, &xxx, " dies of poison.")) return;
+
+ /* Hack -- Recover from bleeding */
+ if (m_ptr->poisoned > d)
+ {
+ /* Recover somewhat */
+ m_ptr->poisoned -= d;
+ }
+
+ /* Fully recover */
+ else
+ {
+ /* Recover fully */
+ m_ptr->poisoned = 0;
+
+ /* Message if visible */
+ if (m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Get the monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Dump a message */
+ msg_format("%^s is no longer poisoned.", m_name);
+
+ /* Hack -- Update the health bar */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+ }
+ }
+ }
+
+ /* Handle "sleep" */
+ if (m_ptr->csleep)
+ {
+ u32b notice = 0;
+
+ /* Hack -- handle non-aggravation */
+ if (!p_ptr->aggravate) notice = rand_int(1024);
+
+ /* Hack -- See if monster "notices" player */
+ if ((notice * notice * notice) <= noise)
+ {
+ /* Hack -- amount of "waking" */
+ int d = 1;
+
+ /* Wake up faster near the player */
+ if (m_ptr->cdis < 50) d = (100 / m_ptr->cdis);
+
+ /* Hack -- handle aggravation */
+ if (p_ptr->aggravate) d = m_ptr->csleep;
+
+ /* Still asleep */
+ if (m_ptr->csleep > d)
+ {
+ /* Monster wakes up "a little bit" */
+ m_ptr->csleep -= d;
+
+ /* Notice the "not waking up" */
+ if (m_ptr->ml)
+ {
+ /* Hack -- Count the ignores */
+ if (r_ptr->r_ignore < MAX_UCHAR)
+ {
+ r_ptr->r_ignore++;
+ }
+ }
+ }
+
+ /* Just woke up */
+ else
+ {
+ /* Reset sleep counter */
+ m_ptr->csleep = 0;
+
+ /* Notice the "waking up" */
+ if (m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Acquire the monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Dump a message */
+ msg_format("%^s wakes up.", m_name);
+
+ /* Hack -- Count the wakings */
+ if (r_ptr->r_wake < MAX_UCHAR)
+ {
+ r_ptr->r_wake++;
+ }
+ }
+ }
+ }
+
+ /* Still sleeping */
+ if (m_ptr->csleep) return;
+ }
+
+
+ /* Handle "stun" */
+ if (m_ptr->stunned)
+ {
+ int d = 1;
+
+ /* Make a "saving throw" against stun */
+ if (rand_int(5000) <= m_ptr->level * m_ptr->level)
+ {
+ /* Recover fully */
+ d = m_ptr->stunned;
+ }
+
+ /* Hack -- Recover from stun */
+ if (m_ptr->stunned > d)
+ {
+ /* Recover somewhat */
+ m_ptr->stunned -= d;
+ }
+
+ /* Fully recover */
+ else
+ {
+ /* Recover fully */
+ m_ptr->stunned = 0;
+
+ /* Message if visible */
+ if (m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Acquire the monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Dump a message */
+ msg_format("%^s is no longer stunned.", m_name);
+ }
+ }
+
+ /* Still stunned */
+ if (m_ptr->stunned) return;
+ }
+
+
+ /* Handle confusion */
+ if (m_ptr->confused)
+ {
+ /* Amount of "boldness" */
+ int d = randint(m_ptr->level / 10 + 1);
+
+ /* Still confused */
+ if (m_ptr->confused > d)
+ {
+ /* Reduce the confusion */
+ m_ptr->confused -= d;
+ }
+
+ /* Recovered */
+ else
+ {
+ /* No longer confused */
+ m_ptr->confused = 0;
+
+ /* Message if visible */
+ if (m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Acquire the monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Dump a message */
+ msg_format("%^s is no longer confused.", m_name);
+ }
+ }
+ }
+
+ /* No one wants to be your friend if you're aggravating */
+ if ((m_ptr->status > MSTATUS_NEUTRAL) && (m_ptr->status < MSTATUS_COMPANION) && (p_ptr->aggravate) && !(r_ptr->flags7 & RF7_PET))
+ gets_angry = TRUE;
+
+ /* Paranoia... no friendly uniques outside wizard mode -- TY */
+ if ((m_ptr->status > MSTATUS_NEUTRAL) && (m_ptr->status < MSTATUS_COMPANION) && !(wizard) &&
+ (r_ptr->flags1 & (RF1_UNIQUE)) && !(r_ptr->flags7 & RF7_PET))
+ gets_angry = TRUE;
+
+ if (gets_angry)
+ {
+ char m_name[80];
+ monster_desc(m_name, m_ptr, 0);
+ switch (is_friend(m_ptr))
+ {
+ case 1:
+ msg_format("%^s suddenly becomes hostile!", m_name);
+ change_side(m_ptr);
+ break;
+ }
+ }
+
+ /* Handle "fear" */
+ if (m_ptr->monfear)
+ {
+ /* Amount of "boldness" */
+ int d = randint(m_ptr->level / 10 + 1);
+
+ /* Still afraid */
+ if (m_ptr->monfear > d)
+ {
+ /* Reduce the fear */
+ m_ptr->monfear -= d;
+ }
+
+ /* Recover from fear, take note if seen */
+ else
+ {
+ /* No longer afraid */
+ m_ptr->monfear = 0;
+
+ /* Visual note */
+ if (m_ptr->ml)
+ {
+ char m_name[80];
+ char m_poss[80];
+
+ /* Acquire the monster name/poss */
+ monster_desc(m_name, m_ptr, 0);
+ monster_desc(m_poss, m_ptr, 0x22);
+
+ /* Dump a message */
+ msg_format("%^s recovers %s courage.", m_name, m_poss);
+ }
+ }
+ }
+
+ /* Get the origin */
+ oy = m_ptr->fy;
+ ox = m_ptr->fx;
+
+ /* Attempt to "multiply" if able and allowed */
+ if ((r_ptr->flags4 & (RF4_MULTIPLY)) && (num_repro < MAX_REPRO))
+ {
+ if (ai_multiply(m_idx)) return;
+ }
+
+ if (speak_unique)
+ {
+ if (randint(SPEAK_CHANCE) == 1)
+ {
+ if (player_has_los_bold(oy, ox) && (r_ptr->flags2 & RF2_CAN_SPEAK))
+ {
+ char m_name[80];
+ char monmessage[80];
+
+ /* Acquire the monster name/poss */
+ if (m_ptr->ml)
+ monster_desc(m_name, m_ptr, 0);
+ else
+ strcpy(m_name, "It");
+
+ /* xtra_line function by Matt Graham--allow uniques to */
+ /* say "unique" things based on their monster index. */
+ /* Try for the unique's lines in "monspeak.txt" first. */
+ /* 0 is SUCCESS, of course.... */
+
+ if (!process_hooks(HOOK_MON_SPEAK, "(d,s)", m_idx, m_name))
+ {
+ if (get_xtra_line("monspeak.txt", m_ptr, monmessage) != 0)
+ {
+ /* Get a message from old defaults if new don't work */
+
+ if (is_friend(m_ptr) > 0)
+ get_rnd_line("speakpet.txt", monmessage);
+ else if (m_ptr->monfear)
+ get_rnd_line("monfear.txt", monmessage);
+ else
+ get_rnd_line("bravado.txt", monmessage);
+ }
+ msg_format("%^s %s", m_name, monmessage);
+ }
+ }
+ }
+ }
+
+ /* Need a new target ? */
+ if ((m_ptr->target == -1) || magik(10)) get_target_monster(m_idx);
+
+
+ /* Attempt to cast a spell */
+ if (make_attack_spell(m_idx)) return;
+
+ /*
+ * Attempt to cast a spell at an enemy other than the player
+ * (may slow the game a smidgeon, but I haven't noticed.)
+ */
+ hack_message_pain_may_silent = TRUE;
+ if (monst_spell_monst(m_idx))
+ {
+ hack_message_pain_may_silent = FALSE;
+ return;
+ }
+ hack_message_pain_may_silent = FALSE;
+
+
+ /* Hack -- Assume no movement */
+ mm[0] = mm[1] = mm[2] = mm[3] = 0;
+ mm[4] = mm[5] = mm[6] = mm[7] = 0;
+
+ /* Confused -- 100% random */
+ if (m_ptr->confused || (inv == TRUE && m_ptr->target == 0))
+ {
+ /* Try four "random" directions */
+ mm[0] = mm[1] = mm[2] = mm[3] = 5;
+ }
+
+ /* 75% random movement */
+ else if ((r_ptr->flags1 & (RF1_RAND_50)) &&
+ (r_ptr->flags1 & (RF1_RAND_25)) &&
+ (rand_int(100) < 75))
+ {
+ /* Memorize flags */
+ if (m_ptr->ml) r_ptr->r_flags1 |= (RF1_RAND_50);
+ if (m_ptr->ml) r_ptr->r_flags1 |= (RF1_RAND_25);
+
+ /* Try four "random" directions */
+ mm[0] = mm[1] = mm[2] = mm[3] = 5;
+ }
+
+ /* 50% random movement */
+ else if ((r_ptr->flags1 & (RF1_RAND_50)) &&
+ (rand_int(100) < 50))
+ {
+ /* Memorize flags */
+ if (m_ptr->ml) r_ptr->r_flags1 |= (RF1_RAND_50);
+
+ /* Try four "random" directions */
+ mm[0] = mm[1] = mm[2] = mm[3] = 5;
+ }
+
+ /* 25% random movement */
+ else if ((r_ptr->flags1 & (RF1_RAND_25)) &&
+ (rand_int(100) < 25))
+ {
+ /* Memorize flags */
+ if (m_ptr->ml) r_ptr->r_flags1 |= (RF1_RAND_25);
+
+ /* Try four "random" directions */
+ mm[0] = mm[1] = mm[2] = mm[3] = 5;
+ }
+
+ /* Normal movement */
+ else
+ {
+ if (stupid_monsters)
+ {
+ /* Logical moves */
+ get_moves(m_idx, mm);
+ }
+ else
+ {
+ /* Logical moves, may do nothing */
+ if (!get_moves(m_idx, mm)) return;
+ }
+ }
+
+ /* Paranoia -- quest code could delete it */
+ if (!c_ptr->m_idx) return;
+
+ /* Assume nothing */
+ do_turn = FALSE;
+ do_move = FALSE;
+ do_view = FALSE;
+
+ /* Assume nothing */
+ did_open_door = FALSE;
+ did_bash_door = FALSE;
+ did_take_item = FALSE;
+ did_kill_item = FALSE;
+ did_move_body = FALSE;
+ did_kill_body = FALSE;
+ did_pass_wall = FALSE;
+ did_kill_wall = FALSE;
+
+
+ /* Take a zero-terminated array of "directions" */
+ for (i = 0; mm[i]; i++)
+ {
+ /* Get the direction */
+ d = mm[i];
+
+ /* Hack -- allow "randomized" motion */
+ if (d == 5) d = ddd[rand_int(8)];
+
+ /* Get the destination */
+ ny = oy + ddy[d];
+ nx = ox + ddx[d];
+
+ /* Access that cave grid */
+ c_ptr = &cave[ny][nx];
+
+ /* Access that cave grid's contents */
+ y_ptr = &m_list[c_ptr->m_idx];
+
+
+ /* Floor is open? */
+ if (cave_floor_bold(ny, nx))
+ {
+ /* Go ahead and move */
+ do_move = TRUE;
+ }
+
+ /* Floor is trapped? */
+ else if (c_ptr->feat == FEAT_MON_TRAP)
+ {
+ /* Go ahead and move */
+ do_move = TRUE;
+ }
+
+ /* Hack -- check for Glyph of Warding */
+ if ((c_ptr->feat == FEAT_GLYPH) &&
+ !(r_ptr->flags1 & RF1_NEVER_BLOW))
+ {
+ /* Assume no move allowed */
+ do_move = FALSE;
+
+ /* Break the ward */
+ if (randint(BREAK_GLYPH) < m_ptr->level)
+ {
+ /* Describe observable breakage */
+ if (c_ptr->info & CAVE_MARK)
+ {
+ msg_print("The rune of protection is broken!");
+ }
+
+ /* Forget the rune */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Break the rune */
+ place_floor_convert_glass(ny, nx);
+
+ /* Allow movement */
+ do_move = TRUE;
+ }
+ }
+
+ /* Hack -- trees are obstacle */
+ else if ((cave[ny][nx].feat == FEAT_TREES) && (r_ptr->flags9 & RF9_KILL_TREES))
+ {
+ do_move = TRUE;
+
+ /* Forget the tree */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Notice */
+ cave_set_feat(ny, nx, FEAT_GRASS);
+ }
+
+ /* Hack -- player 'in' wall */
+ else if ((ny == p_ptr->py) && (nx == p_ptr->px))
+ {
+ do_move = TRUE;
+ }
+
+ else if (c_ptr->m_idx)
+ {
+ /* Possibly a monster to attack */
+ do_move = TRUE;
+ }
+
+ /* Permanent wall */
+ else if (f_info[c_ptr->feat].flags1 & FF1_PERMANENT)
+ {
+ /* Nothing */
+ }
+
+
+ /* Some monsters can fly */
+ else if ((f_info[c_ptr->feat].flags1 & FF1_CAN_LEVITATE) && (r_ptr->flags7 & (RF7_CAN_FLY)))
+ {
+ /* Pass through walls/doors/rubble */
+ do_move = TRUE;
+ }
+
+ /* Some monsters can fly */
+ else if ((f_info[c_ptr->feat].flags1 & FF1_CAN_FLY) && (r_ptr->flags7 & (RF7_CAN_FLY)))
+ {
+ /* Pass through trees/... */
+ do_move = TRUE;
+ }
+
+ /* Monster moves through walls (and doors) */
+ else if ((f_info[c_ptr->feat].flags1 & FF1_CAN_PASS) && (r_ptr->flags2 & (RF2_PASS_WALL)))
+ {
+ /* Pass through walls/doors/rubble */
+ do_move = TRUE;
+
+ /* Monster went through a wall */
+ did_pass_wall = TRUE;
+ }
+
+ /* Monster destroys walls (and doors) */
+ else if ((f_info[c_ptr->feat].flags1 & FF1_CAN_PASS) && (r_ptr->flags2 & (RF2_KILL_WALL)))
+ {
+ /* Eat through walls/doors/rubble */
+ do_move = TRUE;
+
+ /* Monster destroyed a wall */
+ did_kill_wall = TRUE;
+
+ if (randint(GRINDNOISE) == 1)
+ {
+ msg_print("There is a grinding sound.");
+ }
+
+ /* Forget the wall */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Notice */
+ cave_set_feat(ny, nx, FEAT_FLOOR);
+
+ /* Note changes to viewable region */
+ if (player_has_los_bold(ny, nx)) do_view = TRUE;
+ }
+
+ /* Monster moves through walls (and doors) */
+ else if ((f_info[c_ptr->feat].flags1 & FF1_CAN_PASS) && (r_ptr->flags2 & (RF2_PASS_WALL)))
+ {
+ /* Pass through walls/doors/rubble */
+ do_move = TRUE;
+
+ /* Monster went through a wall */
+ did_pass_wall = TRUE;
+ }
+
+ /* Monster moves through webs */
+ else if ((f_info[c_ptr->feat].flags1 & FF1_WEB) &&
+ (r_ptr->flags7 & RF7_SPIDER))
+ {
+ /* Pass through webs */
+ do_move = TRUE;
+ }
+
+ /* Handle doors and secret doors */
+ else if (((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL)) ||
+ (c_ptr->feat == FEAT_SECRET))
+ {
+ bool_ may_bash = TRUE;
+
+ /* Take a turn */
+ do_turn = TRUE;
+
+ if ((r_ptr->flags2 & (RF2_OPEN_DOOR)) &&
+ ((is_friend(m_ptr) <= 0) || p_ptr->pet_open_doors))
+ {
+ /* Closed doors and secret doors */
+ if ((c_ptr->feat == FEAT_DOOR_HEAD) ||
+ (c_ptr->feat == FEAT_SECRET))
+ {
+ /* The door is open */
+ did_open_door = TRUE;
+
+ /* Do not bash the door */
+ may_bash = FALSE;
+ }
+
+ /* Locked doors (not jammed) */
+ else if (c_ptr->feat < FEAT_DOOR_HEAD + 0x08)
+ {
+ int k;
+
+ /* Door power */
+ k = ((c_ptr->feat - FEAT_DOOR_HEAD) & 0x07);
+
+ /* Try to unlock it XXX XXX XXX */
+ if (rand_int(m_ptr->hp / 10) > k)
+ {
+ /* Unlock the door */
+ cave_set_feat(ny, nx, FEAT_DOOR_HEAD + 0x00);
+
+ /* Do not bash the door */
+ may_bash = FALSE;
+ }
+ }
+ }
+
+ /* Stuck doors -- attempt to bash them down if allowed */
+ if (may_bash && (r_ptr->flags2 & RF2_BASH_DOOR) &&
+ ((is_friend(m_ptr) <= 0) || p_ptr->pet_open_doors))
+ {
+ int k;
+
+ /* Door power */
+ k = ((c_ptr->feat - FEAT_DOOR_HEAD) & 0x07);
+
+ /* Attempt to Bash XXX XXX XXX */
+ if (rand_int(m_ptr->hp / 10) > k)
+ {
+ /* Message */
+ msg_print("You hear a door burst open!");
+
+ /* Disturb (sometimes) */
+ if (disturb_minor) disturb(0, 0);
+
+ /* The door was bashed open */
+ did_bash_door = TRUE;
+
+ /* Hack -- fall into doorway */
+ do_move = TRUE;
+ }
+ }
+
+
+ /* Deal with doors in the way */
+ if (did_open_door || did_bash_door)
+ {
+ /* It's no longer hidden */
+ cave[ny][nx].mimic = 0;
+
+ /* Break down the door */
+ if (did_bash_door && (rand_int(100) < 50))
+ {
+ cave_set_feat(ny, nx, FEAT_BROKEN);
+ }
+
+ /* Open the door */
+ else
+ {
+ cave_set_feat(ny, nx, FEAT_OPEN);
+ }
+
+ /* Handle viewable doors */
+ if (player_has_los_bold(ny, nx)) do_view = TRUE;
+ }
+ }
+ else if (do_move && (c_ptr->feat == FEAT_MINOR_GLYPH)
+ && !(r_ptr->flags1 & RF1_NEVER_BLOW))
+ {
+ /* Assume no move allowed */
+ do_move = FALSE;
+
+ /* Break the ward */
+ if (randint(BREAK_MINOR_GLYPH) < m_ptr->level)
+ {
+ /* Describe observable breakage */
+ if (c_ptr->info & CAVE_MARK)
+ {
+ if (ny == p_ptr->py && nx == p_ptr->px)
+ {
+ msg_print("The rune explodes!");
+ fire_ball(GF_MANA, 0,
+ 2 * ((p_ptr->lev / 2) + damroll(7, 7)), 2);
+ }
+ else
+ msg_print("An explosive rune was disarmed.");
+ }
+
+ /* Forget the rune */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Break the rune */
+ place_floor_convert_glass(ny, nx);
+
+ /* Allow movement */
+ do_move = TRUE;
+ }
+ }
+
+ /* Hack -- the Between teleport the monsters too */
+ else if (cave[ny][nx].feat == FEAT_BETWEEN)
+ {
+ nx = cave[ny][nx].special & 255;
+ ny = cave[ny][nx].special >> 8;
+ get_pos_player(10, &ny, &nx);
+
+ /* Access that cave grid */
+ c_ptr = &cave[ny][nx];
+
+ /* Access that cave grid's contents */
+ y_ptr = &m_list[c_ptr->m_idx];
+
+ if (!(r_ptr->flags3 & RF3_IM_COLD))
+ {
+ if ((m_ptr->hp - distance(ny, nx, oy, ox)*2) <= 0)
+ {
+ ny = oy + ddy[d];
+ nx = ox + ddx[d];
+ do_move = FALSE;
+ }
+ else
+ {
+ m_ptr->hp -= distance(ny, nx, oy, ox) * 2;
+ do_move = TRUE;
+ }
+ }
+ else
+ {
+ do_move = TRUE;
+ }
+ }
+
+ /* Execute the inscription -- MEGA HACK -- */
+ if ((c_ptr->inscription) && (c_ptr->inscription != INSCRIP_CHASM))
+ {
+ if (inscription_info[c_ptr->inscription].when & INSCRIP_EXEC_MONST_WALK)
+ {
+ bool_ t;
+ t = execute_inscription(c_ptr->inscription, ny, nx);
+ if (!t && do_move)
+ {
+ /* Hack -- attack the player even if on the inscription */
+ if ((ny == p_ptr->py) && (nx == p_ptr->px))
+ do_move = TRUE;
+ else
+ do_move = FALSE;
+ }
+ }
+ }
+
+ /* Some monsters never attack */
+ if (do_move && (ny == p_ptr->py) && (nx == p_ptr->px) &&
+ (r_ptr->flags1 & RF1_NEVER_BLOW))
+ {
+ /* Do not move */
+ do_move = FALSE;
+ }
+
+ /* The player is in the way. Attack him. */
+ if (do_move && (ny == p_ptr->py) && (nx == p_ptr->px))
+ {
+ /* Do the attack */
+ (void)make_attack_normal(m_idx, 1);
+
+ /* Do not move */
+ do_move = FALSE;
+
+ /* Took a turn */
+ do_turn = TRUE;
+ }
+
+ if ((cave[ny][nx].feat >= FEAT_PATTERN_START) &&
+ (cave[ny][nx].feat <= FEAT_PATTERN_XTRA2) &&
+ do_turn == FALSE)
+ {
+ do_move = FALSE;
+ }
+
+
+ /* A monster is in the way */
+ if (do_move && c_ptr->m_idx)
+ {
+ monster_race *z_ptr = race_inf(y_ptr);
+ monster_type *m2_ptr = &m_list[c_ptr->m_idx];
+
+ /* Assume no movement */
+ do_move = FALSE;
+
+ /* Kill weaker monsters */
+ if ((r_ptr->flags2 & RF2_KILL_BODY) &&
+ (r_ptr->mexp > z_ptr->mexp) && (cave_floor_bold(ny, nx)) &&
+ /* Friends don't kill friends... */
+ !((is_friend(m_ptr) > 0) && (is_friend(m2_ptr) > 0)) &&
+ /* Uniques aren't faceless monsters in a crowd */
+ !(z_ptr->flags1 & RF1_UNIQUE) &&
+ /* Don't wreck quests */
+ !(m2_ptr->mflag & (MFLAG_QUEST | MFLAG_QUEST2)) &&
+ /* Don't punish summoners for relying on their friends */
+ (is_friend(m2_ptr) <= 0))
+ {
+ /* Allow movement */
+ do_move = TRUE;
+
+ /* Monster ate another monster */
+ did_kill_body = TRUE;
+
+ /* XXX XXX XXX Message */
+
+ /* Kill the monster */
+ delete_monster(ny, nx);
+
+ /* Hack -- get the empty monster */
+ y_ptr = &m_list[c_ptr->m_idx];
+ }
+
+ /* Attack 'enemies' */
+ else if (is_enemy(m_ptr, m2_ptr) || m_ptr->confused)
+ {
+ do_move = FALSE;
+ /* attack */
+ if (m2_ptr->r_idx && (m2_ptr->hp >= 0))
+ {
+ hack_message_pain_may_silent = TRUE;
+ if (monst_attack_monst(m_idx, c_ptr->m_idx))
+ {
+ hack_message_pain_may_silent = FALSE;
+ return;
+ }
+ hack_message_pain_may_silent = FALSE;
+ }
+ }
+
+ /* Push past weaker monsters (unless leaving a wall) */
+ else if ((r_ptr->flags2 & RF2_MOVE_BODY) &&
+ (r_ptr->mexp > z_ptr->mexp) && cave_floor_bold(ny, nx) &&
+ (cave_floor_bold(m_ptr->fy, m_ptr->fx)))
+ {
+ /* Allow movement */
+ do_move = TRUE;
+
+ /* Monster pushed past another monster */
+ did_move_body = TRUE;
+
+ /* XXX XXX XXX Message */
+ }
+ }
+
+ /*
+ * Check if monster can cross terrain
+ * This is checked after the normal attacks
+ * to allow monsters to attack an enemy,
+ * even if it can't enter the terrain.
+ */
+ if (do_move && !monster_can_cross_terrain(c_ptr->feat, r_ptr))
+ {
+ /* Assume no move allowed */
+ do_move = FALSE;
+ }
+
+ /* Some monsters never move */
+ if (do_move && (r_ptr->flags1 & RF1_NEVER_MOVE))
+ {
+ /* Hack -- memorize lack of attacks */
+ /* if (m_ptr->ml) r_ptr->r_flags1 |= (RF1_NEVER_MOVE); */
+
+ /* Do not move */
+ do_move = FALSE;
+ }
+
+
+
+ /* Creature has been allowed move */
+ if (do_move)
+ {
+ s16b this_o_idx, next_o_idx = 0;
+
+ /* Take a turn */
+ do_turn = TRUE;
+
+ /* Hack -- Update the old location */
+ cave[oy][ox].m_idx = c_ptr->m_idx;
+
+ /* Mega-Hack -- move the old monster, if any */
+ if (c_ptr->m_idx)
+ {
+ /* Move the old monster */
+ y_ptr->fy = oy;
+ y_ptr->fx = ox;
+
+ /* Update the old monster */
+ update_mon(c_ptr->m_idx, TRUE);
+
+ /* Wake up the moved monster */
+ m_list[c_ptr->m_idx].csleep = 0;
+
+ /*
+ * Update monster light -- I'm too lazy to check flags
+ * here, and those ego monster_race functions aren't
+ * re-entrant XXX XXX XXX
+ */
+ p_ptr->update |= (PU_MON_LITE);
+ }
+
+ /* Hack -- Update the new location */
+ c_ptr->m_idx = m_idx;
+
+ /* Move the monster */
+ m_ptr->fy = ny;
+ m_ptr->fx = nx;
+
+ /* Update the monster */
+ update_mon(m_idx, TRUE);
+
+ /* Redraw the old grid */
+ lite_spot(oy, ox);
+
+ /* Redraw the new grid */
+ lite_spot(ny, nx);
+
+ /* Execute the inscription -- MEGA HACK -- */
+ if (c_ptr->inscription == INSCRIP_CHASM)
+ {
+ if (inscription_info[c_ptr->inscription].when & INSCRIP_EXEC_MONST_WALK)
+ {
+ execute_inscription(c_ptr->inscription, ny, nx);
+ }
+ }
+
+ /* Possible disturb */
+ if (m_ptr->ml && (disturb_move ||
+ ((m_ptr->mflag & (MFLAG_VIEW)) &&
+ disturb_near)))
+ {
+ /* Disturb */
+ if ((is_friend(m_ptr) < 0) || disturb_pets)
+ disturb(0, 0);
+ }
+
+ /* Check for monster trap */
+ if (c_ptr->feat == FEAT_MON_TRAP)
+ {
+ if (mon_hit_trap(m_idx)) return;
+ }
+ else
+ {
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Skip gold */
+ if (o_ptr->tval == TV_GOLD) continue;
+
+ /* Incarnate ? */
+ if ((o_ptr->tval == TV_CORPSE) && (r_ptr->flags7 & RF7_POSSESSOR) &&
+ ((o_ptr->sval == SV_CORPSE_CORPSE) || (o_ptr->sval == SV_CORPSE_SKELETON)))
+ {
+ if (ai_possessor(m_idx, this_o_idx)) return;
+ }
+
+ /* Take or Kill objects on the floor */
+ /* rr9: Pets will no longer pick up/destroy items */
+ if ((((r_ptr->flags2 & (RF2_TAKE_ITEM)) &&
+ ((is_friend(m_ptr) <= 0) || p_ptr->pet_pickup_items)) ||
+ (r_ptr->flags2 & (RF2_KILL_ITEM))) &&
+ (is_friend(m_ptr) <= 0))
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+
+ u32b flg3 = 0L;
+
+ char m_name[80];
+ char o_name[80];
+
+ /* Extract some flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Acquire the object name */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Acquire the monster name */
+ monster_desc(m_name, m_ptr, 0x04);
+
+ /* React to objects that hurt the monster */
+ if (f5 & (TR5_KILL_DEMON)) flg3 |= (RF3_DEMON);
+ if (f5 & (TR5_KILL_UNDEAD)) flg3 |= (RF3_UNDEAD);
+ if (f1 & (TR1_SLAY_DRAGON)) flg3 |= (RF3_DRAGON);
+ if (f1 & (TR1_SLAY_TROLL)) flg3 |= (RF3_TROLL);
+ if (f1 & (TR1_SLAY_GIANT)) flg3 |= (RF3_GIANT);
+ if (f1 & (TR1_SLAY_ORC)) flg3 |= (RF3_ORC);
+ if (f1 & (TR1_SLAY_DEMON)) flg3 |= (RF3_DEMON);
+ if (f1 & (TR1_SLAY_UNDEAD)) flg3 |= (RF3_UNDEAD);
+ if (f1 & (TR1_SLAY_ANIMAL)) flg3 |= (RF3_ANIMAL);
+ if (f1 & (TR1_SLAY_EVIL)) flg3 |= (RF3_EVIL);
+
+ /* The object cannot be picked up by the monster */
+ if (artifact_p(o_ptr) || (r_ptr->flags3 & flg3) ||
+ (o_ptr->art_name))
+ {
+ /* Only give a message for "take_item" */
+ if (r_ptr->flags2 & (RF2_TAKE_ITEM))
+ {
+ /* Take note */
+ did_take_item = TRUE;
+
+ /* Describe observable situations */
+ if (m_ptr->ml && player_has_los_bold(ny, nx))
+ {
+ /* Dump a message */
+ msg_format("%^s tries to pick up %s, but fails.",
+ m_name, o_name);
+ }
+ }
+ }
+
+ /* Pick up the item */
+ else if (r_ptr->flags2 & (RF2_TAKE_ITEM))
+ {
+ /* Take note */
+ did_take_item = TRUE;
+
+ /* Describe observable situations */
+ if (player_has_los_bold(ny, nx))
+ {
+ /* Dump a message */
+ msg_format("%^s picks up %s.", m_name, o_name);
+ }
+
+ /* Option */
+ if (testing_carry)
+ {
+ /* Excise the object */
+ excise_object_idx(this_o_idx);
+
+ /* Forget mark */
+ o_ptr->marked = FALSE;
+
+ /* Forget location */
+ o_ptr->iy = o_ptr->ix = 0;
+
+ /* Memorize monster */
+ o_ptr->held_m_idx = m_idx;
+
+ /* Build a stack */
+ o_ptr->next_o_idx = m_ptr->hold_o_idx;
+
+ /* Carry object */
+ m_ptr->hold_o_idx = this_o_idx;
+ }
+
+ /* Nope */
+ else
+ {
+ /* Delete the object */
+ delete_object_idx(this_o_idx);
+ }
+ }
+
+ /* Destroy the item */
+ else
+ {
+ /* Take note */
+ did_kill_item = TRUE;
+
+ /* Describe observable situations */
+ if (player_has_los_bold(ny, nx))
+ {
+ /* Dump a message */
+ msg_format("%^s crushes %s.", m_name, o_name);
+ }
+
+ /* Delete the object */
+ delete_object_idx(this_o_idx);
+ }
+ }
+ }
+ }
+
+ /* Update monster light */
+ if (r_ptr->flags9 & RF9_HAS_LITE) p_ptr->update |= (PU_MON_LITE);
+ }
+
+ /* Stop when done */
+ if (do_turn) break;
+ }
+
+
+ /* If we haven't done anything, try casting a spell again */
+ if (!do_turn && !do_move && !m_ptr->monfear && !stupid_monsters &&
+ (is_friend(m_ptr) < 0))
+ {
+ /* Cast spell */
+ if (make_attack_spell(m_idx)) return;
+ }
+
+
+ /* Notice changes in view */
+ if (do_view)
+ {
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS | PU_MON_LITE);
+ }
+
+
+ /* Learn things from observable monster */
+ if (m_ptr->ml)
+ {
+ /* Monster opened a door */
+ if (did_open_door) r_ptr->r_flags2 |= (RF2_OPEN_DOOR);
+
+ /* Monster bashed a door */
+ if (did_bash_door) r_ptr->r_flags2 |= (RF2_BASH_DOOR);
+
+ /* Monster tried to pick something up */
+ if (did_take_item) r_ptr->r_flags2 |= (RF2_TAKE_ITEM);
+
+ /* Monster tried to crush something */
+ if (did_kill_item) r_ptr->r_flags2 |= (RF2_KILL_ITEM);
+
+ /* Monster pushed past another monster */
+ if (did_move_body) r_ptr->r_flags2 |= (RF2_MOVE_BODY);
+
+ /* Monster ate another monster */
+ if (did_kill_body) r_ptr->r_flags2 |= (RF2_KILL_BODY);
+
+ /* Monster passed through a wall */
+ if (did_pass_wall) r_ptr->r_flags2 |= (RF2_PASS_WALL);
+
+ /* Monster destroyed a wall */
+ if (did_kill_wall) r_ptr->r_flags2 |= (RF2_KILL_WALL);
+ }
+
+
+ /* Hack -- get "bold" if out of options */
+ if (!do_turn && !do_move && m_ptr->monfear)
+ {
+ /* No longer afraid */
+ m_ptr->monfear = 0;
+
+ /* Message if seen */
+ if (m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Acquire the monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Dump a message */
+ msg_format("%^s turns to fight!", m_name);
+ }
+
+ /* XXX XXX XXX Actually do something now (?) */
+ }
+}
+
+
+void summon_maint(int m_idx)
+{
+
+ monster_type *m_ptr = &m_list[m_idx];
+
+ /* Can you pay? */
+ if ((s32b)(p_ptr->maintain_sum / 10000) > p_ptr->csp)
+ {
+ char m_name[80];
+
+ monster_desc(m_name, m_ptr, 0);
+
+ msg_format("You lose control of %s.", m_name);
+
+ /* Well, then, I guess I'm dead. */
+ delete_monster_idx(m_idx);
+ }
+ else
+ {
+ s32b cl, ml, floor, cost;
+
+ cl = get_skill_scale(SKILL_SUMMON, 100);
+ ml = m_ptr->level * 10000;
+
+ /* Floor = 19 * ml / 990 + 8 / 199
+ This gives a floor of 0.1 at level 1 and a floor of 2 at level 100
+
+ Since ml is multiplied by 10000 already, we multiply the 8/199 too
+ */
+ floor = ml * 19 / 990 + 80000 / 199;
+ cost = (ml / cl - 10000) / 4;
+ if(cost < floor)
+ cost = floor;
+
+ /* Well, then I'll take my wages from you. */
+ p_ptr->maintain_sum += cost;
+ }
+ return;
+}
+
+
+/*
+ * Process all the "live" monsters, once per game turn.
+ *
+ * During each game turn, we scan through the list of all the "live" monsters,
+ * (backwards, so we can excise any "freshly dead" monsters), energizing each
+ * monster, and allowing fully energized monsters to move, attack, pass, etc.
+ *
+ * Note that monsters can never move in the monster array (except when the
+ * "compact_monsters()" function is called by "dungeon()" or "save_player()").
+ *
+ * This function is responsible for at least half of the processor time
+ * on a normal system with a "normal" amount of monsters and a player doing
+ * normal things.
+ *
+ * When the player is resting, virtually 90% of the processor time is spent
+ * in this function, and its children, "process_monster()" and "make_move()".
+ *
+ * Most of the rest of the time is spent in "update_view()" and "lite_spot()",
+ * especially when the player is running.
+ *
+ * Note the special "MFLAG_BORN" flag, which allows us to ignore "fresh"
+ * monsters while they are still being "born". A monster is "fresh" only
+ * during the turn in which it is created, and we use the "hack_m_idx" to
+ * determine if the monster is yet to be processed during the current turn.
+ *
+ * Note the special "MFLAG_NICE" flag, which allows the player to get one
+ * move before any "nasty" monsters get to use their spell attacks.
+ *
+ * Note that when the "knowledge" about the currently tracked monster
+ * changes (flags, attacks, spells), we induce a redraw of the monster
+ * recall window.
+ */
+void process_monsters(void)
+{
+ int i, e;
+ int fx, fy;
+
+ bool_ test;
+ bool_ is_frien = FALSE;
+
+ monster_type *m_ptr;
+ monster_race *r_ptr;
+
+ int old_monster_race_idx;
+
+ u32b old_r_flags1 = 0L;
+ u32b old_r_flags2 = 0L;
+ u32b old_r_flags3 = 0L;
+ u32b old_r_flags4 = 0L;
+ u32b old_r_flags5 = 0L;
+ u32b old_r_flags6 = 0L;
+
+ byte old_r_blows0 = 0;
+ byte old_r_blows1 = 0;
+ byte old_r_blows2 = 0;
+ byte old_r_blows3 = 0;
+
+ byte old_r_cast_inate = 0;
+ byte old_r_cast_spell = 0;
+
+ /* Check the doppleganger */
+ if (doppleganger && !(r_info[m_list[doppleganger].r_idx].flags9 & RF9_DOPPLEGANGER))
+ doppleganger = 0;
+
+ /* Memorize old race */
+ old_monster_race_idx = monster_race_idx;
+
+ /* Acquire knowledge */
+ if (monster_race_idx)
+ {
+ /* Acquire current monster */
+ r_ptr = &r_info[monster_race_idx];
+
+ /* Memorize flags */
+ old_r_flags1 = r_ptr->r_flags1;
+ old_r_flags2 = r_ptr->r_flags2;
+ old_r_flags3 = r_ptr->r_flags3;
+ old_r_flags4 = r_ptr->r_flags4;
+ old_r_flags5 = r_ptr->r_flags5;
+ old_r_flags6 = r_ptr->r_flags6;
+
+ /* Memorize blows */
+ old_r_blows0 = r_ptr->r_blows[0];
+ old_r_blows1 = r_ptr->r_blows[1];
+ old_r_blows2 = r_ptr->r_blows[2];
+ old_r_blows3 = r_ptr->r_blows[3];
+
+ /* Memorize castings */
+ old_r_cast_inate = r_ptr->r_cast_inate;
+ old_r_cast_spell = r_ptr->r_cast_spell;
+ }
+
+
+ /* Hack -- calculate the "player noise" */
+ noise = (1L << (30 - p_ptr->skill_stl));
+
+
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ m_ptr = &m_list[i];
+
+ /* Handle "leaving" */
+ if (p_ptr->leaving) break;
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Calculate "upkeep" for friendly monsters */
+ if (m_ptr->status == MSTATUS_PET)
+ {
+ total_friends++;
+ total_friend_levels += m_ptr->level;
+ }
+
+
+ /* Handle "fresh" monsters */
+ if (m_ptr->mflag & (MFLAG_BORN))
+ {
+ /* No longer "fresh" */
+ m_ptr->mflag &= ~(MFLAG_BORN);
+
+ /* Skip */
+ continue;
+ }
+
+
+ /* Obtain the energy boost */
+ e = extract_energy[m_ptr->mspeed];
+
+ /* Give this monster some energy */
+ m_ptr->energy += e;
+
+
+ /* Not enough energy to move */
+ if (m_ptr->energy < 100) continue;
+
+ /* Use up "some" energy */
+ m_ptr->energy -= 100;
+
+
+ /* Hack -- Require proximity */
+ if (m_ptr->cdis >= 100) continue;
+
+
+ /* Access the race */
+ r_ptr = race_inf(m_ptr);
+
+ /* Access the location */
+ fx = m_ptr->fx;
+ fy = m_ptr->fy;
+
+
+ /* Assume no move */
+ test = FALSE;
+
+ /* Control monster aint affected by distance */
+ if (p_ptr->control == i)
+ {
+ test = TRUE;
+ }
+
+ /* No free upkeep on partial summons just because they're out
+ * of line of sight. */
+ else if (m_ptr->mflag & MFLAG_PARTIAL) test = TRUE;
+
+ /* Handle "sensing radius" */
+ else if (m_ptr->cdis <= r_ptr->aaf)
+ {
+ /* We can "sense" the player */
+ test = TRUE;
+ }
+
+ /* Handle "sight" and "aggravation" */
+ else if ((m_ptr->cdis <= MAX_SIGHT) &&
+ (player_has_los_bold(fy, fx) ||
+ p_ptr->aggravate))
+ {
+ /* We can "see" or "feel" the player */
+ test = TRUE;
+ }
+
+ /* Hack -- Monsters can "smell" the player from far away */
+ /* Note that most monsters have "aaf" of "20" or so */
+ else if (flow_by_sound &&
+ (cave[p_ptr->py][p_ptr->px].when == cave[fy][fx].when) &&
+ (cave[fy][fx].cost < MONSTER_FLOW_DEPTH) &&
+ (cave[fy][fx].cost < r_ptr->aaf))
+ {
+ /* We can "smell" the player */
+ test = TRUE;
+ }
+
+ /* Running away wont save them ! */
+ if (m_ptr->poisoned || m_ptr->bleeding) test = TRUE;
+
+ /* Do nothing */
+ if (!test) continue;
+
+ /* Save global index */
+ hack_m_idx = i;
+
+ if (is_friend(m_ptr) > 0) is_frien = TRUE;
+
+ /* Process the monster */
+ process_monster(i, is_frien);
+
+ /* Hack -- notice death or departure */
+ if (!alive || death) break;
+
+ /* If it's still alive and friendly, charge upkeep. */
+ if (m_ptr->mflag & MFLAG_PARTIAL) summon_maint(i);
+
+ /* Notice leaving */
+ if (p_ptr->leaving) break;
+ }
+
+ /* Reset global index */
+ hack_m_idx = 0;
+
+
+ /* Tracking a monster race (the same one we were before) */
+ if (monster_race_idx && (monster_race_idx == old_monster_race_idx))
+ {
+ /* Acquire monster race */
+ r_ptr = &r_info[monster_race_idx];
+
+ /* Check for knowledge change */
+ if ((old_r_flags1 != r_ptr->r_flags1) ||
+ (old_r_flags2 != r_ptr->r_flags2) ||
+ (old_r_flags3 != r_ptr->r_flags3) ||
+ (old_r_flags4 != r_ptr->r_flags4) ||
+ (old_r_flags5 != r_ptr->r_flags5) ||
+ (old_r_flags6 != r_ptr->r_flags6) ||
+ (old_r_blows0 != r_ptr->r_blows[0]) ||
+ (old_r_blows1 != r_ptr->r_blows[1]) ||
+ (old_r_blows2 != r_ptr->r_blows[2]) ||
+ (old_r_blows3 != r_ptr->r_blows[3]) ||
+ (old_r_cast_inate != r_ptr->r_cast_inate) ||
+ (old_r_cast_spell != r_ptr->r_cast_spell))
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+ }
+ }
+}
diff --git a/src/modules.c b/src/modules.c
new file mode 100644
index 00000000..39b41d20
--- /dev/null
+++ b/src/modules.c
@@ -0,0 +1,274 @@
+/* File: modules.c */
+
+/* Purpose: T-engine modules */
+
+/*
+ * Copyright (c) 2003 DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+static void module_reset_dir_aux(cptr *dir, cptr new_path)
+{
+ char buf[1024];
+
+ /* Build the new path */
+ strnfmt(buf, sizeof (buf), "%s%s%s", *dir, PATH_SEP, new_path);
+
+ string_free(*dir);
+ *dir = string_make(buf);
+
+ /* Make it if needed */
+ if (!private_check_user_directory(*dir))
+ quit(format("Unable to create module dir %s\n", *dir));
+}
+
+void module_reset_dir(cptr dir, cptr new_path)
+{
+ cptr *d = 0;
+ char buf[1025];
+
+ if (!strcmp(dir, "apex")) d = &ANGBAND_DIR_APEX;
+ if (!strcmp(dir, "core")) d = &ANGBAND_DIR_CORE;
+ if (!strcmp(dir, "dngn")) d = &ANGBAND_DIR_DNGN;
+ if (!strcmp(dir, "data")) d = &ANGBAND_DIR_DATA;
+ if (!strcmp(dir, "edit")) d = &ANGBAND_DIR_EDIT;
+ if (!strcmp(dir, "file")) d = &ANGBAND_DIR_FILE;
+ if (!strcmp(dir, "help")) d = &ANGBAND_DIR_HELP;
+ if (!strcmp(dir, "info")) d = &ANGBAND_DIR_INFO;
+ if (!strcmp(dir, "scpt")) d = &ANGBAND_DIR_SCPT;
+ if (!strcmp(dir, "patch")) d = &ANGBAND_DIR_PATCH;
+ if (!strcmp(dir, "pref")) d = &ANGBAND_DIR_PREF;
+ if (!strcmp(dir, "xtra")) d = &ANGBAND_DIR_XTRA;
+ if (!strcmp(dir, "user")) d = &ANGBAND_DIR_USER;
+ if (!strcmp(dir, "note")) d = &ANGBAND_DIR_NOTE;
+ if (!strcmp(dir, "cmov")) d = &ANGBAND_DIR_CMOV;
+ if (
+#ifdef PRIVATE_USER_PATH_APEX
+ !strcmp(dir, "apex") ||
+#endif
+ !strcmp(dir, "user") ||
+ !strcmp(dir, "note") ||
+ !strcmp(dir, "cmov"))
+ {
+ char user_path[1024];
+ /* copied from init_file_paths */
+ path_parse(user_path, 1024, PRIVATE_USER_PATH);
+ strcat(user_path, USER_PATH_VERSION);
+ strnfmt(buf, 1024, "%s%s%s", user_path, PATH_SEP, new_path);
+ string_free(*d);
+ *d = string_make(buf);
+ }
+#ifdef PRIVATE_USER_PATH_DATA
+ else if (!strcmp(dir, "data"))
+ {
+ module_reset_dir_aux(&ANGBAND_DIR_DATA, new_path);
+ }
+#endif
+ else if (!strcmp(dir, "save"))
+ {
+ module_reset_dir_aux(&ANGBAND_DIR_SAVE, new_path);
+ }
+ else
+ {
+ /* Build the new path */
+ strnfmt(buf, 1024, "%s%s%s%s%s", ANGBAND_DIR_MODULES, PATH_SEP, new_path, PATH_SEP, dir);
+
+ string_free(*d);
+ *d = string_make(buf);
+ }
+}
+
+static void dump_modules(int sel, int max)
+{
+ int i;
+
+ char buf[40], pre = ' ', post = ')';
+ cptr name;
+
+ char ind;
+
+
+ for (i = 0; i < max; i++)
+ {
+ ind = I2A(i % 26);
+ if (i >= 26) ind = toupper(ind);
+
+ if (sel == i)
+ {
+ pre = '[';
+ post = ']';
+ }
+ else
+ {
+ pre = ' ';
+ post = ')';
+ }
+
+ call_lua("get_module_name", "(d)", "s", i, &name);
+ strnfmt(buf, 40, "%c%c%c %s", pre, ind, post, name);
+
+ if (sel == i)
+ {
+ call_lua("get_module_desc", "(d)", "s", i, &name);
+ print_desc_aux(name, 5, 0);
+
+ c_put_str(TERM_L_BLUE, buf, 10 + (i / 4), 20 * (i % 4));
+ }
+ else
+ put_str(buf, 10 + (i / 4), 20 * (i % 4));
+ }
+}
+
+static void activate_module()
+{
+ /* Initialize the module table */
+ call_lua("assign_current_module", "(s)", "", game_module);
+
+ /* Do misc inits */
+ call_lua("get_module_info", "(s)", "d", "max_plev", &max_plev);
+ call_lua("get_module_info", "(s)", "d", "death_dungeon", &DUNGEON_DEATH);
+
+ call_lua("get_module_info", "(s)", "d", "random_artifact_weapon_chance", &RANDART_WEAPON);
+ call_lua("get_module_info", "(s)", "d", "random_artifact_armor_chance", &RANDART_ARMOR);
+ call_lua("get_module_info", "(s)", "d", "random_artifact_jewelry_chance", &RANDART_JEWEL);
+
+ call_lua("get_module_info", "(s,d)", "d", "version", 1, &VERSION_MAJOR);
+ call_lua("get_module_info", "(s,d)", "d", "version", 2, &VERSION_MINOR);
+ call_lua("get_module_info", "(s,d)", "d", "version", 3, &VERSION_PATCH);
+ version_major = VERSION_MAJOR;
+ version_minor = VERSION_MINOR;
+ version_patch = VERSION_PATCH;
+
+ /* Change window name if needed */
+ if (strcmp(game_module, "ToME"))
+ {
+ strnfmt(angband_term_name[0], 79, "T-Engine: %s", game_module);
+ Term_xtra(TERM_XTRA_RENAME_MAIN_WIN, 0);
+ }
+
+ /* Reprocess the player name, just in case */
+ process_player_base();
+}
+
+/* Did the player force a module on command line */
+cptr force_module = NULL;
+
+/* Display possible modules and select one */
+bool_ select_module()
+{
+ s32b k, sel, max;
+
+ /* Init some lua */
+ init_lua();
+
+ /* Some ports need to separate the module scripts from the installed mods,
+ so we need to check for these in two different places */
+ if(!tome_dofile_anywhere(ANGBAND_DIR_CORE, "mods_aux.lua", FALSE))
+ tome_dofile_anywhere(ANGBAND_DIR_MODULES, "mods_aux.lua", TRUE);
+ if(!tome_dofile_anywhere(ANGBAND_DIR_CORE, "modules.lua", FALSE))
+ tome_dofile_anywhere(ANGBAND_DIR_MODULES, "modules.lua", TRUE);
+
+ /* Grab the savefiles */
+ call_lua("max_modules", "()", "d", &max);
+
+ /* No need to bother the player if there is only one module */
+ sel = -1;
+ if (force_module)
+ call_lua("find_module", "(s)", "d", force_module, &sel);
+ if (max == 1)
+ sel = 0;
+ if (sel != -1)
+ {
+ cptr tmp;
+
+ /* Process the module */
+ call_lua("init_module", "(d)", "", sel);
+ call_lua("get_module_name", "(d)", "s", sel, &tmp);
+ game_module = string_make(tmp);
+
+ activate_module();
+
+ return FALSE;
+ }
+
+ sel = 0;
+
+ /* Preprocess the basic prefs, we need them to have movement keys */
+ process_pref_file("pref.prf");
+
+ while (TRUE)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Let the user choose */
+ c_put_str(TERM_YELLOW, "Welcome to ToME, you must select a module to play,", 1, 12);
+ c_put_str(TERM_YELLOW, "either ToME official module or third party ones.", 2, 13);
+ put_str("Press 8/2/4/6 to move, Return to select and Esc to quit.", 4, 3);
+
+ dump_modules(sel, max);
+
+ k = inkey();
+
+ if (k == ESCAPE)
+ {
+ quit(NULL);
+ }
+ if (k == '6')
+ {
+ sel++;
+ if (sel >= max) sel = 0;
+ continue;
+ }
+ else if (k == '4')
+ {
+ sel--;
+ if (sel < 0) sel = max - 1;
+ continue;
+ }
+ else if (k == '2')
+ {
+ sel += 4;
+ if (sel >= max) sel = sel % max;
+ continue;
+ }
+ else if (k == '8')
+ {
+ sel -= 4;
+ if (sel < 0) sel = (sel + max - 1) % max;
+ continue;
+ }
+ else if (k == '\r')
+ {
+ if (sel < 26) k = I2A(sel);
+ else k = toupper(I2A(sel));
+ }
+
+ {
+ int x;
+ cptr tmp;
+
+ if (islower(k)) x = A2I(k);
+ else x = A2I(tolower(k)) + 26;
+
+ if ((x < 0) || (x >= max)) continue;
+
+ /* Process the module */
+ call_lua("init_module", "(d)", "", x);
+ call_lua("get_module_name", "(d)", "s", x, &tmp);
+ game_module = string_make(tmp);
+
+ activate_module();
+
+ return (FALSE);
+ }
+ }
+
+ /* Shouldnt happen */
+ return (FALSE);
+}
diff --git a/src/monster.pkg b/src/monster.pkg
new file mode 100644
index 00000000..a9efd089
--- /dev/null
+++ b/src/monster.pkg
@@ -0,0 +1,2324 @@
+/* File: monster.pkg */
+
+/*
+ * Purpose: Lua interface defitions for monsters.
+ * To be processed by tolua to generate C source code.
+ */
+
+$#include "angband.h"
+
+/** @typedef cptr
+ * @note String
+ */
+typedef char* cptr;
+/** @typedef errr
+ * @note Number
+ */
+typedef int errr;
+/** @typedef bool
+ * @note Boolean
+ */
+typedef unsigned char bool;
+/** @typedef byte
+ * @note Number
+ */
+typedef unsigned char byte;
+/** @typedef s16b
+ * @note Number
+ */
+typedef signed short s16b;
+/** @typedef u16b
+ * @note Number
+ */
+typedef unsigned short u16b;
+/** @typedef s32b
+ * @note Number
+ */
+typedef signed int s32b;
+/** @typedef u32b
+ * @note Number
+ */
+typedef unsigned int u32b;
+
+/* To make easy object creations */
+$static monster_type lua_monster_forge;
+/** @var monster_forge;
+ * @brief monster_type
+ */
+static monster_type lua_monster_forge @ monster_forge;
+
+/** @name Monster status
+ * @note Player POV
+ * @{ */
+/** @def MSTATUS_ENEMY */
+#define MSTATUS_ENEMY -2
+
+/** @def MSTATUS_NEUTRAL_M */
+#define MSTATUS_NEUTRAL_M -1
+
+/** @def MSTATUS_NEUTRAL */
+#define MSTATUS_NEUTRAL 0
+
+/** @def MSTATUS_NEUTRAL_P */
+#define MSTATUS_NEUTRAL_P 1
+
+/** @def MSTATUS_FRIEND */
+#define MSTATUS_FRIEND 2
+
+/** @def MSTATUS_PET */
+#define MSTATUS_PET 3
+
+/** @def MSTATUS_COMPANION */
+#define MSTATUS_COMPANION 4
+/** @} */
+
+/** @name Race flags #1
+ * @{ */
+/** @def RF1_UNIQUE
+ * @note Unique Monster
+ */
+#define RF1_UNIQUE 0x00000001
+/** @def RF1_QUESTOR
+ * @note Quest Monster
+ */
+#define RF1_QUESTOR 0x00000002
+/** @def RF1_MALE
+ * @note Male gender
+ */
+#define RF1_MALE 0x00000004
+/** @def RF1_FEMALE
+ * @note Female gender
+ */
+#define RF1_FEMALE 0x00000008
+/** @def RF1_CHAR_CLEAR
+ * @note Absorbs symbol
+ */
+#define RF1_CHAR_CLEAR 0x00000010
+/** @def RF1_CHAR_MULTI
+ * @note Changes symbol
+ */
+#define RF1_CHAR_MULTI 0x00000020
+/** @def RF1_ATTR_CLEAR
+ * @note Absorbs color
+ */
+#define RF1_ATTR_CLEAR 0x00000040
+/** @def RF1_ATTR_MULTI
+ * @note Changes color
+ */
+#define RF1_ATTR_MULTI 0x00000080
+/** @def RF1_FORCE_DEPTH
+ * @note Start at "correct" depth
+ */
+#define RF1_FORCE_DEPTH 0x00000100
+/** @def RF1_FORCE_MAXHP
+ * @note Start with max hitpoints
+ */
+#define RF1_FORCE_MAXHP 0x00000200
+/** @def RF1_FORCE_SLEEP
+ * @note Start out sleeping
+ */
+#define RF1_FORCE_SLEEP 0x00000400
+/** @def RF1_FORCE_EXTRA
+ * @note Start out something
+ */
+#define RF1_FORCE_EXTRA 0x00000800
+/** @def RF1_FRIEND
+ * @note Arrive with a friend
+ */
+#define RF1_FRIEND 0x00001000
+/** @def RF1_FRIENDS
+ * @note Arrive with some friends
+ */
+#define RF1_FRIENDS 0x00002000
+/** @def RF1_ESCORT
+ * @note Arrive with an escort
+ */
+#define RF1_ESCORT 0x00004000
+/** @def RF1_ESCORTS
+ * @note Arrive with some escorts
+ */
+#define RF1_ESCORTS 0x00008000
+/** @def RF1_NEVER_BLOW
+ * @note Never make physical blow
+ */
+#define RF1_NEVER_BLOW 0x00010000
+/** @def RF1_NEVER_MOVE
+ * @note Never make physical move
+ */
+#define RF1_NEVER_MOVE 0x00020000
+/** @def RF1_RAND_25
+ * @note Moves randomly (25%)
+ */
+#define RF1_RAND_25 0x00040000
+/** @def RF1_RAND_50
+ * @note Moves randomly (50%)
+ */
+#define RF1_RAND_50 0x00080000
+/** @def RF1_ONLY_GOLD
+ * @note Drop only gold
+ */
+#define RF1_ONLY_GOLD 0x00100000
+/** @def RF1_ONLY_ITEM
+ * @note Drop only items
+ */
+#define RF1_ONLY_ITEM 0x00200000
+/** @def RF1_DROP_60
+ * @note Drop an item/gold (60%)
+ */
+#define RF1_DROP_60 0x00400000
+/** @def RF1_DROP_90
+ * @note Drop an item/gold (90%)
+ */
+#define RF1_DROP_90 0x00800000
+/** @def RF1_DROP_1D2
+ * @note Drop 1d2 items/gold
+ */
+#define RF1_DROP_1D2 0x01000000
+/** @def RF1_DROP_2D2
+ * @note Drop 2d2 items/gold
+ */
+#define RF1_DROP_2D2 0x02000000
+/** @def RF1_DROP_3D2
+ * @note Drop 3d2 items/gold
+ */
+#define RF1_DROP_3D2 0x04000000
+/** @def RF1_DROP_4D2
+ * @note Drop 4d2 items/gold
+ */
+#define RF1_DROP_4D2 0x08000000
+/** @def RF1_DROP_GOOD
+ * @note Drop good items
+ */
+#define RF1_DROP_GOOD 0x10000000
+/** @def RF1_DROP_GREAT
+ * @note Drop great items
+ */
+#define RF1_DROP_GREAT 0x20000000
+/** @def RF1_DROP_USEFUL
+ * @note Drop "useful" items
+ */
+#define RF1_DROP_USEFUL 0x40000000
+/** @def RF1_DROP_CHOSEN
+ * @note Drop "chosen" items
+ */
+#define RF1_DROP_CHOSEN 0x80000000
+/** @} */
+
+/** @name Race flags #2
+ * @note New monster race bit flags
+ * @{ */
+/** @def RF2_STUPID
+ * @note Monster is stupid
+ */
+#define RF2_STUPID 0x00000001
+/** @def RF2_SMART
+ * @note Monster is smart
+ */
+#define RF2_SMART 0x00000002
+/** @def RF2_CAN_SPEAK
+ * @note TY: can speak
+ */
+#define RF2_CAN_SPEAK 0x00000004
+/** @def RF2_REFLECTING
+ * @note Reflects bolts
+ */
+#define RF2_REFLECTING 0x00000008
+/** @def RF2_INVISIBLE
+ * @note Monster avoids vision
+ */
+#define RF2_INVISIBLE 0x00000010
+/** @def RF2_COLD_BLOOD
+ * @note Monster avoids infra
+ */
+#define RF2_COLD_BLOOD 0x00000020
+/** @def RF2_EMPTY_MIND
+ * @note Monster avoids telepathy
+ */
+#define RF2_EMPTY_MIND 0x00000040
+/** @def RF2_WEIRD_MIND
+ * @note Monster avoids telepathy?
+ */
+#define RF2_WEIRD_MIND 0x00000080
+/** @def RF2_DEATH_ORB
+ * @note Death Orb
+ */
+#define RF2_DEATH_ORB 0x00000100
+/** @def RF2_REGENERATE
+ * @note Monster regenerates
+ */
+#define RF2_REGENERATE 0x00000200
+/** @def RF2_SHAPECHANGER
+ * @note TY: shapechanger
+ */
+#define RF2_SHAPECHANGER 0x00000400
+/** @def RF2_ATTR_ANY
+ * @note TY: Attr_any
+ */
+#define RF2_ATTR_ANY 0x00000800
+/** @def RF2_POWERFUL
+ * @note Monster has strong breath
+ */
+#define RF2_POWERFUL 0x00001000
+/** @def RF2_ELDRITCH_HORROR
+ * @note Sanity-blasting horror
+ */
+#define RF2_ELDRITCH_HORROR 0x00002000
+/** @def RF2_AURA_FIRE
+ * @note Burns in melee
+ */
+#define RF2_AURA_FIRE 0x00004000
+/** @def RF2_AURA_ELEC
+ * @note Shocks in melee
+ */
+#define RF2_AURA_ELEC 0x00008000
+/** @def RF2_OPEN_DOOR
+ * @note Monster can open doors
+ */
+#define RF2_OPEN_DOOR 0x00010000
+/** @def RF2_BASH_DOOR
+ * @note Monster can bash doors
+ */
+#define RF2_BASH_DOOR 0x00020000
+/** @def RF2_PASS_WALL
+ * @note Monster can pass walls
+ */
+#define RF2_PASS_WALL 0x00040000
+/** @def RF2_KILL_WALL
+ * @note Monster can destroy walls
+ */
+#define RF2_KILL_WALL 0x00080000
+/** @def RF2_MOVE_BODY
+ * @note Monster can move monsters
+ */
+#define RF2_MOVE_BODY 0x00100000
+/** @def RF2_KILL_BODY
+ * @note Monster can kill monsters
+ */
+#define RF2_KILL_BODY 0x00200000
+/** @def RF2_TAKE_ITEM
+ * @note Monster can pick up items
+ */
+#define RF2_TAKE_ITEM 0x00400000
+/** @def RF2_KILL_ITEM
+ * @note Monster can crush items
+ */
+#define RF2_KILL_ITEM 0x00800000
+/** @def RF2_BRAIN_1 */
+#define RF2_BRAIN_1 0x01000000
+
+/** @def RF2_BRAIN_2 */
+#define RF2_BRAIN_2 0x02000000
+
+/** @def RF2_BRAIN_3 */
+#define RF2_BRAIN_3 0x04000000
+
+/** @def RF2_BRAIN_4 */
+#define RF2_BRAIN_4 0x08000000
+
+/** @def RF2_BRAIN_5 */
+#define RF2_BRAIN_5 0x10000000
+
+/** @def RF2_BRAIN_6 */
+#define RF2_BRAIN_6 0x20000000
+
+/** @def RF2_BRAIN_7 */
+#define RF2_BRAIN_7 0x40000000
+
+/** @def RF2_BRAIN_8 */
+#define RF2_BRAIN_8 0x80000000
+/** @} */
+
+/** @name Race flags #3
+ * @note New monster race bit flags
+ * @{ */
+/** @def RF3_ORC
+ * @note Orc
+ */
+#define RF3_ORC 0x00000001
+/** @def RF3_TROLL
+ * @note Troll
+ */
+#define RF3_TROLL 0x00000002
+/** @def RF3_GIANT
+ * @note Giant
+ */
+#define RF3_GIANT 0x00000004
+/** @def RF3_DRAGON
+ * @note Dragon
+ */
+#define RF3_DRAGON 0x00000008
+/** @def RF3_DEMON
+ * @note Demon
+ */
+#define RF3_DEMON 0x00000010
+/** @def RF3_UNDEAD
+ * @note Undead
+ */
+#define RF3_UNDEAD 0x00000020
+/** @def RF3_EVIL
+ * @note Evil
+ */
+#define RF3_EVIL 0x00000040
+/** @def RF3_ANIMAL
+ * @note Animal
+ */
+#define RF3_ANIMAL 0x00000080
+/** @def RF3_THUNDERLORD
+ * @note DG: Thunderlord
+ */
+#define RF3_THUNDERLORD 0x00000100
+/** @def RF3_GOOD
+ * @note Good
+ */
+#define RF3_GOOD 0x00000200
+/** @def RF3_AURA_COLD
+ * @note Freezes in melee
+ */
+#define RF3_AURA_COLD 0x00000400
+/** @def RF3_NONLIVING
+ * @note TY: Non-Living (?)
+ */
+#define RF3_NONLIVING 0x00000800
+/** @def RF3_HURT_LITE
+ * @note Hurt by lite
+ */
+#define RF3_HURT_LITE 0x00001000
+/** @def RF3_HURT_ROCK
+ * @note Hurt by rock remover
+ */
+#define RF3_HURT_ROCK 0x00002000
+/** @def RF3_SUSCEP_FIRE
+ * @note Hurt badly by fire
+ */
+#define RF3_SUSCEP_FIRE 0x00004000
+/** @def RF3_SUSCEP_COLD
+ * @note Hurt badly by cold
+ */
+#define RF3_SUSCEP_COLD 0x00008000
+/** @def RF3_IM_ACID
+ * @note Resist acid a lot
+ */
+#define RF3_IM_ACID 0x00010000
+/** @def RF3_IM_ELEC
+ * @note Resist elec a lot
+ */
+#define RF3_IM_ELEC 0x00020000
+/** @def RF3_IM_FIRE
+ * @note Resist fire a lot
+ */
+#define RF3_IM_FIRE 0x00040000
+/** @def RF3_IM_COLD
+ * @note Resist cold a lot
+ */
+#define RF3_IM_COLD 0x00080000
+/** @def RF3_IM_POIS
+ * @note Resist poison a lot
+ */
+#define RF3_IM_POIS 0x00100000
+/** @def RF3_RES_TELE
+ * @note Resist teleportation
+ */
+#define RF3_RES_TELE 0x00200000
+/** @def RF3_RES_NETH
+ * @note Resist nether a lot
+ */
+#define RF3_RES_NETH 0x00400000
+/** @def RF3_RES_WATE
+ * @note Resist water
+ */
+#define RF3_RES_WATE 0x00800000
+/** @def RF3_RES_PLAS
+ * @note Resist plasma
+ */
+#define RF3_RES_PLAS 0x01000000
+/** @def RF3_RES_NEXU
+ * @note Resist nexus
+ */
+#define RF3_RES_NEXU 0x02000000
+/** @def RF3_RES_DISE
+ * @note Resist disenchantment
+ */
+#define RF3_RES_DISE 0x04000000
+/** @def RF3_UNIQUE_4
+ * @note Is a "Nazgul" unique
+ */
+#define RF3_UNIQUE_4 0x08000000
+/** @def RF3_NO_FEAR
+ * @note Cannot be scared
+ */
+#define RF3_NO_FEAR 0x10000000
+/** @def RF3_NO_STUN
+ * @note Cannot be stunned
+ */
+#define RF3_NO_STUN 0x20000000
+/** @def RF3_NO_CONF
+ * @note Cannot be confused
+ */
+#define RF3_NO_CONF 0x40000000
+/** @def RF3_NO_SLEEP
+ * @note Cannot be slept
+ */
+#define RF3_NO_SLEEP 0x80000000
+/** @} */
+
+/** @name Race flags #4
+ * @note New monster race bit flags
+ * @{ */
+/** @def RF4_SHRIEK
+ * @note Shriek for help
+ */
+#define RF4_SHRIEK 0x00000001
+/** @def RF4_MULTIPLY
+ * @note Monster reproduces
+ */
+#define RF4_MULTIPLY 0x00000002
+/** @def RF4_S_ANIMAL
+ * @note Summon animals
+ */
+#define RF4_S_ANIMAL 0x00000004
+/** @def RF4_ROCKET
+ * @note TY: Rocket
+ */
+#define RF4_ROCKET 0x00000008
+/** @def RF4_ARROW_1
+ * @note Fire an arrow (light)
+ */
+#define RF4_ARROW_1 0x00000010
+/** @def RF4_ARROW_2
+ * @note Fire an arrow (heavy)
+ */
+#define RF4_ARROW_2 0x00000020
+/** @def RF4_ARROW_3
+ * @note Fire missiles (light)
+ */
+#define RF4_ARROW_3 0x00000040
+/** @def RF4_ARROW_4
+ * @note Fire missiles (heavy)
+ */
+#define RF4_ARROW_4 0x00000080
+/** @def RF4_BR_ACID
+ * @note Breathe Acid
+ */
+#define RF4_BR_ACID 0x00000100
+/** @def RF4_BR_ELEC
+ * @note Breathe Elec
+ */
+#define RF4_BR_ELEC 0x00000200
+/** @def RF4_BR_FIRE
+ * @note Breathe Fire
+ */
+#define RF4_BR_FIRE 0x00000400
+/** @def RF4_BR_COLD
+ * @note Breathe Cold
+ */
+#define RF4_BR_COLD 0x00000800
+/** @def RF4_BR_POIS
+ * @note Breathe Poison
+ */
+#define RF4_BR_POIS 0x00001000
+/** @def RF4_BR_NETH
+ * @note Breathe Nether
+ */
+#define RF4_BR_NETH 0x00002000
+/** @def RF4_BR_LITE
+ * @note Breathe Lite
+ */
+#define RF4_BR_LITE 0x00004000
+/** @def RF4_BR_DARK
+ * @note Breathe Dark
+ */
+#define RF4_BR_DARK 0x00008000
+/** @def RF4_BR_CONF
+ * @note Breathe Confusion
+ */
+#define RF4_BR_CONF 0x00010000
+/** @def RF4_BR_SOUN
+ * @note Breathe Sound
+ */
+#define RF4_BR_SOUN 0x00020000
+/** @def RF4_BR_CHAO
+ * @note Breathe Chaos
+ */
+#define RF4_BR_CHAO 0x00040000
+/** @def RF4_BR_DISE
+ * @note Breathe Disenchant
+ */
+#define RF4_BR_DISE 0x00080000
+/** @def RF4_BR_NEXU
+ * @note Breathe Nexus
+ */
+#define RF4_BR_NEXU 0x00100000
+/** @def RF4_BR_TIME
+ * @note Breathe Time
+ */
+#define RF4_BR_TIME 0x00200000
+/** @def RF4_BR_INER
+ * @note Breathe Inertia
+ */
+#define RF4_BR_INER 0x00400000
+/** @def RF4_BR_GRAV
+ * @note Breathe Gravity
+ */
+#define RF4_BR_GRAV 0x00800000
+/** @def RF4_BR_SHAR
+ * @note Breathe Shards
+ */
+#define RF4_BR_SHAR 0x01000000
+/** @def RF4_BR_PLAS
+ * @note Breathe Plasma
+ */
+#define RF4_BR_PLAS 0x02000000
+/** @def RF4_BR_WALL
+ * @note Breathe Force
+ */
+#define RF4_BR_WALL 0x04000000
+/** @def RF4_BR_MANA
+ * @note Breathe Mana
+ */
+#define RF4_BR_MANA 0x08000000
+/** @def RF4_BA_NUKE
+ * @note TY: Nuke Ball
+ */
+#define RF4_BA_NUKE 0x10000000
+/** @def RF4_BR_NUKE
+ * @note TY: Toxic Breath
+ */
+#define RF4_BR_NUKE 0x20000000
+/** @def RF4_BA_CHAO
+ * @note Chaos Ball
+ */
+#define RF4_BA_CHAO 0x40000000
+/** @def RF4_BR_DISI
+ * @note Breathe Disintegration
+ */
+#define RF4_BR_DISI 0x80000000
+/** @} */
+
+/** @name Race flags #5
+ * @note New monster race bit flags
+ * @{ */
+/** @def RF5_BA_ACID
+ * @note Acid Ball
+ */
+#define RF5_BA_ACID 0x00000001
+/** @def RF5_BA_ELEC
+ * @note Elec Ball
+ */
+#define RF5_BA_ELEC 0x00000002
+/** @def RF5_BA_FIRE
+ * @note Fire Ball
+ */
+#define RF5_BA_FIRE 0x00000004
+/** @def RF5_BA_COLD
+ * @note Cold Ball
+ */
+#define RF5_BA_COLD 0x00000008
+/** @def RF5_BA_POIS
+ * @note Poison Ball
+ */
+#define RF5_BA_POIS 0x00000010
+/** @def RF5_BA_NETH
+ * @note Nether Ball
+ */
+#define RF5_BA_NETH 0x00000020
+/** @def RF5_BA_WATE
+ * @note Water Ball
+ */
+#define RF5_BA_WATE 0x00000040
+/** @def RF5_BA_MANA
+ * @note Mana Storm
+ */
+#define RF5_BA_MANA 0x00000080
+/** @def RF5_BA_DARK
+ * @note Darkness Storm
+ */
+#define RF5_BA_DARK 0x00000100
+/** @def RF5_DRAIN_MANA
+ * @note Drain Mana
+ */
+#define RF5_DRAIN_MANA 0x00000200
+/** @def RF5_MIND_BLAST
+ * @note Blast Mind
+ */
+#define RF5_MIND_BLAST 0x00000400
+/** @def RF5_BRAIN_SMASH
+ * @note Smash Brain
+ */
+#define RF5_BRAIN_SMASH 0x00000800
+/** @def RF5_CAUSE_1
+ * @note Cause Light Wound
+ */
+#define RF5_CAUSE_1 0x00001000
+/** @def RF5_CAUSE_2
+ * @note Cause Serious Wound
+ */
+#define RF5_CAUSE_2 0x00002000
+/** @def RF5_CAUSE_3
+ * @note Cause Critical Wound
+ */
+#define RF5_CAUSE_3 0x00004000
+/** @def RF5_CAUSE_4
+ * @note Cause Mortal Wound
+ */
+#define RF5_CAUSE_4 0x00008000
+/** @def RF5_BO_ACID
+ * @note Acid Bolt
+ */
+#define RF5_BO_ACID 0x00010000
+/** @def RF5_BO_ELEC
+ * @note Elec Bolt (unused)
+ */
+#define RF5_BO_ELEC 0x00020000
+/** @def RF5_BO_FIRE
+ * @note Fire Bolt
+ */
+#define RF5_BO_FIRE 0x00040000
+/** @def RF5_BO_COLD
+ * @note Cold Bolt
+ */
+#define RF5_BO_COLD 0x00080000
+/** @def RF5_BO_POIS
+ * @note Poison Bolt (unused)
+ */
+#define RF5_BO_POIS 0x00100000
+/** @def RF5_BO_NETH
+ * @note Nether Bolt
+ */
+#define RF5_BO_NETH 0x00200000
+/** @def RF5_BO_WATE
+ * @note Water Bolt
+ */
+#define RF5_BO_WATE 0x00400000
+/** @def RF5_BO_MANA
+ * @note Mana Bolt
+ */
+#define RF5_BO_MANA 0x00800000
+/** @def RF5_BO_PLAS
+ * @note Plasma Bolt
+ */
+#define RF5_BO_PLAS 0x01000000
+/** @def RF5_BO_ICEE
+ * @note Ice Bolt
+ */
+#define RF5_BO_ICEE 0x02000000
+/** @def RF5_MISSILE
+ * @note Magic Missile
+ */
+#define RF5_MISSILE 0x04000000
+/** @def RF5_SCARE
+ * @note Frighten Player
+ */
+#define RF5_SCARE 0x08000000
+/** @def RF5_BLIND
+ * @note Blind Player
+ */
+#define RF5_BLIND 0x10000000
+/** @def RF5_CONF
+ * @note Confuse Player
+ */
+#define RF5_CONF 0x20000000
+/** @def RF5_SLOW
+ * @note Slow Player
+ */
+#define RF5_SLOW 0x40000000
+/** @def RF5_HOLD
+ * @note Paralyze Player
+ */
+#define RF5_HOLD 0x80000000
+/** @} */
+
+/** @name Race flags #6
+ * @note New monster race bit flags
+ * @{ */
+/** @def RF6_HASTE
+ * @note Speed self
+ */
+#define RF6_HASTE 0x00000001
+/** @def RF6_HAND_DOOM
+ * @note Hand of Doom
+ */
+#define RF6_HAND_DOOM 0x00000002
+/** @def RF6_HEAL
+ * @note Heal self
+ */
+#define RF6_HEAL 0x00000004
+/** @def RF6_S_ANIMALS
+ * @note Summon animals
+ */
+#define RF6_S_ANIMALS 0x00000008
+/** @def RF6_BLINK
+ * @note Teleport Short
+ */
+#define RF6_BLINK 0x00000010
+/** @def RF6_TPORT
+ * @note Teleport Long
+ */
+#define RF6_TPORT 0x00000020
+/** @def RF6_TELE_TO
+ * @note Move player to monster
+ */
+#define RF6_TELE_TO 0x00000040
+/** @def RF6_TELE_AWAY
+ * @note Move player far away
+ */
+#define RF6_TELE_AWAY 0x00000080
+/** @def RF6_TELE_LEVEL
+ * @note Move player vertically
+ */
+#define RF6_TELE_LEVEL 0x00000100
+/** @def RF6_DARKNESS
+ * @note Create Darkness
+ */
+#define RF6_DARKNESS 0x00000200
+/** @def RF6_TRAPS
+ * @note Create Traps
+ */
+#define RF6_TRAPS 0x00000400
+/** @def RF6_FORGET
+ * @note Cause amnesia
+ */
+#define RF6_FORGET 0x00000800
+/** @def RF6_RAISE_DEAD
+ * @note Raise Dead
+ */
+#define RF6_RAISE_DEAD 0x00001000
+/** @def RF6_S_BUG
+ * @note Summon Software bug
+ */
+#define RF6_S_BUG 0x00002000
+/** @def RF6_S_RNG
+ * @note Summon RNG
+ */
+#define RF6_S_RNG 0x00004000
+/** @def RF6_S_THUNDERLORD
+ * @note Summon Thunderlords
+ */
+#define RF6_S_THUNDERLORD 0x00008000
+/** @def RF6_S_KIN
+ * @note Summon "kin"
+ */
+#define RF6_S_KIN 0x00010000
+/** @def RF6_S_HI_DEMON
+ * @note Summon greater demons!
+ */
+#define RF6_S_HI_DEMON 0x00020000
+/** @def RF6_S_MONSTER
+ * @note Summon Monster
+ */
+#define RF6_S_MONSTER 0x00040000
+/** @def RF6_S_MONSTERS
+ * @note Summon Monsters
+ */
+#define RF6_S_MONSTERS 0x00080000
+/** @def RF6_S_ANT
+ * @note Summon Ants
+ */
+#define RF6_S_ANT 0x00100000
+/** @def RF6_S_SPIDER
+ * @note Summon Spiders
+ */
+#define RF6_S_SPIDER 0x00200000
+/** @def RF6_S_HOUND
+ * @note Summon Hounds
+ */
+#define RF6_S_HOUND 0x00400000
+/** @def RF6_S_HYDRA
+ * @note Summon Hydras
+ */
+#define RF6_S_HYDRA 0x00800000
+/** @def RF6_S_ANGEL
+ * @note Summon Angel
+ */
+#define RF6_S_ANGEL 0x01000000
+/** @def RF6_S_DEMON
+ * @note Summon Demon
+ */
+#define RF6_S_DEMON 0x02000000
+/** @def RF6_S_UNDEAD
+ * @note Summon Undead
+ */
+#define RF6_S_UNDEAD 0x04000000
+/** @def RF6_S_DRAGON
+ * @note Summon Dragon
+ */
+#define RF6_S_DRAGON 0x08000000
+/** @def RF6_S_HI_UNDEAD
+ * @note Summon Greater Undead
+ */
+#define RF6_S_HI_UNDEAD 0x10000000
+/** @def RF6_S_HI_DRAGON
+ * @note Summon Ancient Dragon
+ */
+#define RF6_S_HI_DRAGON 0x20000000
+/** @def RF6_S_WRAITH
+ * @note Summon Unique Wraith
+ */
+#define RF6_S_WRAITH 0x40000000
+/** @def RF6_S_UNIQUE
+ * @note Summon Unique Monster
+ */
+#define RF6_S_UNIQUE 0x80000000
+/** @} */
+
+/** @name Race flags #7
+ * @note New monster race bit flags
+ * @{ */
+/** @def RF7_AQUATIC
+ * @note Aquatic monster
+ */
+#define RF7_AQUATIC 0x00000001
+/** @def RF7_CAN_SWIM
+ * @note Monster can swim
+ */
+#define RF7_CAN_SWIM 0x00000002
+/** @def RF7_CAN_FLY
+ * @note Monster can fly
+ */
+#define RF7_CAN_FLY 0x00000004
+/** @def RF7_FRIENDLY
+ * @note Monster is friendly
+ */
+#define RF7_FRIENDLY 0x00000008
+/** @def RF7_PET
+ * @note Monster is a pet
+ */
+#define RF7_PET 0x00000010
+/** @def RF7_MORTAL
+ * @note Monster is a mortal being
+ */
+#define RF7_MORTAL 0x00000020
+/** @def RF7_SPIDER
+ * @note Monster is a spider (can pass webs)
+ */
+#define RF7_SPIDER 0x00000040
+/** @def RF7_NAZGUL
+ * @note Monster is a Nazgul
+ */
+#define RF7_NAZGUL 0x00000080
+/** @def RF7_DG_CURSE
+ * @note If killed the monster grant a DG Curse to the player
+ */
+#define RF7_DG_CURSE 0x00000100
+/** @def RF7_POSSESSOR
+ * @note Is it a dreaded possessor monster ?
+ */
+#define RF7_POSSESSOR 0x00000200
+/** @def RF7_NO_DEATH
+ * @note Cannot be killed
+ */
+#define RF7_NO_DEATH 0x00000400
+/** @def RF7_NO_TARGET
+ * @note Cannot be targeted
+ */
+#define RF7_NO_TARGET 0x00000800
+/** @def RF7_AI_ANNOY
+ * @note Try to tease the player
+ */
+#define RF7_AI_ANNOY 0x00001000
+/** @def RF7_AI_SPECIAL
+ * @note For quests
+ */
+#define RF7_AI_SPECIAL 0x00002000
+/** @def RF7_NO_THEFT
+ * @note Monster is immune to theft
+ */
+#define RF7_NO_THEFT 0x00040000
+/** @def RF7_SPIRIT
+ * @note This is a Spirit, coming from the Void
+ */
+#define RF7_SPIRIT 0x00080000
+/** @def RF7_IM_MELEE
+ * @note IM melee
+ */
+#define RF7_IM_MELEE 0x00100000
+/** @} */
+
+/** @name Race flags #8
+ * @note New monster race bit flags
+ * @{ */
+/** @def RF8_DUNGEON */
+#define RF8_DUNGEON 0x00000001
+
+/** @def RF8_WILD_TOWN */
+#define RF8_WILD_TOWN 0x00000002
+
+/** @def RF8_XXX8X02 */
+#define RF8_XXX8X02 0x00000004
+
+/** @def RF8_WILD_SHORE */
+#define RF8_WILD_SHORE 0x00000008
+
+/** @def RF8_WILD_OCEAN */
+#define RF8_WILD_OCEAN 0x00000010
+
+/** @def RF8_WILD_WASTE */
+#define RF8_WILD_WASTE 0x00000020
+
+/** @def RF8_WILD_WOOD */
+#define RF8_WILD_WOOD 0x00000040
+
+/** @def RF8_WILD_VOLCANO */
+#define RF8_WILD_VOLCANO 0x00000080
+
+/** @def RF8_XXX8X08 */
+#define RF8_XXX8X08 0x00000100
+
+/** @def RF8_WILD_MOUNTAIN */
+#define RF8_WILD_MOUNTAIN 0x00000200
+
+/** @def RF8_WILD_GRASS */
+#define RF8_WILD_GRASS 0x00000400
+
+/********* FREE *********/
+/** @def RF8_CTHANGBAND */
+#define RF8_CTHANGBAND 0x00001000
+
+/********* FREE *********/
+/** @def RF8_ZANGBAND */
+#define RF8_ZANGBAND 0x00004000
+
+/** @def RF8_JOKEANGBAND */
+#define RF8_JOKEANGBAND 0x00008000
+
+/** @def RF8_ANGBAND */
+#define RF8_ANGBAND 0x00010000
+
+
+/** @def RF8_WILD_TOO */
+#define RF8_WILD_TOO 0x80000000
+/** @} */
+
+/** @name Race flags #9
+ * @note New monster race bit flags
+ * @{ */
+/** @def RF9_DROP_CORPSE */
+#define RF9_DROP_CORPSE 0x00000001
+
+/** @def RF9_DROP_SKELETON */
+#define RF9_DROP_SKELETON 0x00000002
+
+/** @def RF9_HAS_LITE
+ * @note Carries a lite
+ */
+#define RF9_HAS_LITE 0x00000004
+/** @def RF9_MIMIC
+ * @note *REALLY* looks like an object ... only nastier
+ */
+#define RF9_MIMIC 0x00000008
+/** @def RF9_HAS_EGG
+ * @note Can be monster's eggs
+ */
+#define RF9_HAS_EGG 0x00000010
+/** @def RF9_IMPRESED
+ * @note The monster can follow you on each level until he dies
+ */
+#define RF9_IMPRESED 0x00000020
+/** @def RF9_SUSCEP_ACID
+ * @note Susceptible to acid
+ */
+#define RF9_SUSCEP_ACID 0x00000040
+/** @def RF9_SUSCEP_ELEC
+ * @note Susceptible to lightning
+ */
+#define RF9_SUSCEP_ELEC 0x00000080
+/** @def RF9_SUSCEP_POIS
+ * @note Susceptible to poison
+ */
+#define RF9_SUSCEP_POIS 0x00000100
+/** @def RF9_KILL_TREES
+ * @note Monster can eat trees
+ */
+#define RF9_KILL_TREES 0x00000200
+/** @def RF9_WYRM_PROTECT
+ * @note The monster is protected by great wyrms of power: They'll be summoned if it's killed
+ */
+#define RF9_WYRM_PROTECT 0x00000400
+/** @def RF9_DOPPLEGANGER
+ * @note The monster looks like you
+ */
+#define RF9_DOPPLEGANGER 0x00000800
+/** @def RF9_ONLY_DEPTH
+ * @note The monster can only be generated at the GIVEN depth
+ */
+#define RF9_ONLY_DEPTH 0x00001000
+/** @def RF9_SPECIAL_GENE
+ * @note The monster can only be generated in special conditions like quests, special dungeons, ...
+ */
+#define RF9_SPECIAL_GENE 0x00002000
+/** @def RF9_NEVER_GENE
+ * @note The monster cannot be normaly generated
+ */
+#define RF9_NEVER_GENE 0x00004000
+/** @} */
+
+/** @name Monster flags
+ * @{ */
+/** @def MFLAG_VIEW
+ * @note Monster is in line of sight
+ */
+#define MFLAG_VIEW 0x00000001
+/** @def MFLAG_QUEST
+ * @note Monster is subject to a quest
+ */
+#define MFLAG_QUEST 0x00000002
+/** @def MFLAG_PARTIAL
+ * @note Monster is a partial summon
+ */
+#define MFLAG_PARTIAL 0x00000004
+/** @def MFLAG_CONTROL
+ * @note Monster is controlled
+ */
+#define MFLAG_CONTROL 0x00000008
+/** @def MFLAG_BORN
+ * @note Monster is still being born
+ */
+#define MFLAG_BORN 0x00000010
+/** @def MFLAG_NICE
+ * @note Monster is still being nice
+ */
+#define MFLAG_NICE 0x00000020
+/** @def MFLAG_SHOW
+ * @note Monster is recently memorized
+ */
+#define MFLAG_SHOW 0x00000040
+/** @def MFLAG_MARK
+ * @note Monster is currently memorized
+ */
+#define MFLAG_MARK 0x00000080
+/** @def MFLAG_NO_DROP
+ * @note Monster wont drop obj/corpse
+ */
+#define MFLAG_NO_DROP 0x00000100
+/** @def MFLAG_QUEST2
+ * @note Monster is subject to a quest
+ */
+#define MFLAG_QUEST2 0x00000200
+/** @} */
+
+/** @struct monster_blow
+ * @brief Monster blows (attacks)
+ */
+struct monster_blow
+{
+ /** @structvar method
+ * @brief Number
+ */
+ byte method;
+ /** @structvar effect
+ * @brief Number
+ */
+ byte effect;
+ /** @structvar d_dice
+ * @brief Number
+ */
+ byte d_dice;
+ /** @structvar d_side
+ * @brief Number
+ */
+ byte d_side;
+};
+
+/** @struct monster_race
+ * @brief Monster race
+ */
+struct monster_race
+{
+ /** @structvar name
+ * @brief Number
+ * @note Name (offset)
+ */
+ u32b name;
+ /** @structvar text
+ * @brief Number
+ * @note Text (offset)
+ */
+ u32b text;
+
+ /** @structvar hdice
+ * @brief Number
+ * @note Creatures hit dice count
+ */
+ byte hdice;
+ /** @structvar hside
+ * @brief Number
+ * @note Creatures hit dice sides
+ */
+ byte hside;
+
+ /** @structvar ac
+ * @brief Number
+ * @note Armour Class
+ */
+ s16b ac;
+
+ /** @structvar sleep
+ * @brief Number
+ * @note Inactive counter (base)
+ */
+ s16b sleep;
+ /** @structvar aaf
+ * @brief Number
+ * @note Area affect radius (1-100)
+ */
+ byte aaf;
+ /** @structvar speed
+ * @brief Number
+ * @note Speed (normally 110)
+ */
+ byte speed;
+
+ /** @structvar mexp
+ * @brief Number
+ * @note Exp value for kill
+ */
+ s32b mexp;
+
+ /** @structvar weight
+ * @brief Number
+ * @note Weight of the monster
+ */
+ s32b weight;
+
+ /** @structvar freq_inate
+ * @brief Number
+ * @note Inate spell frequency
+ */
+ byte freq_inate;
+ /** @structvar freq_spell
+ * @brief Number
+ * @note Other spell frequency
+ */
+ byte freq_spell;
+
+ /** @structvar flags1
+ * @brief Number
+ * @note Flags 1 (general)
+ */
+ u32b flags1;
+ /** @structvar flags2
+ * @brief Number
+ * @note Flags 2 (abilities)
+ */
+ u32b flags2;
+ /** @structvar flags3
+ * @brief Number
+ * @note Flags 3 (race/resist)
+ */
+ u32b flags3;
+ /** @structvar flags4
+ * @brief Number
+ * @note Flags 4 (inate/breath)
+ */
+ u32b flags4;
+ /** @structvar flags5
+ * @brief Number
+ * @note Flags 5 (normal spells)
+ */
+ u32b flags5;
+ /** @structvar flags6
+ * @brief Number
+ * @note Flags 6 (special spells)
+ */
+ u32b flags6;
+ /** @structvar flags7
+ * @brief Number
+ * @note Flags 7 (movement related abilities)
+ */
+ u32b flags7;
+ /** @structvar flags8
+ * @brief Number
+ * @note Flags 8 (wilderness info)
+ */
+ u32b flags8;
+ /** @structvar flags9
+ * @brief Number
+ * @note Flags 9 (drops info)
+ */
+ u32b flags9;
+
+ /** @structvar blow[4]
+ * @brief magic_power
+ * @note Up to four blows per round
+ */
+ monster_blow blow[4];
+
+ /** @structvar body_parts[BODY_MAX]
+ * @brief Number
+ * @note To help to decide what to use when body changing
+ */
+ byte body_parts[BODY_MAX];
+
+ /** @structvar level
+ * @brief Number
+ * @note Level of creature
+ */
+ byte level;
+ /** @structvar rarity
+ * @brief Number
+ * @note Rarity of creature
+ */
+ byte rarity;
+
+
+ /** @structvar d_attr
+ * @brief Number
+ * @note Default monster attribute
+ */
+ byte d_attr;
+ /** @structvar d_char
+ * @brief String
+ * @note Default monster character
+ */
+ char d_char;
+
+
+ /** @structvar x_attr
+ * @brief Number
+ * @note Desired monster attribute
+ */
+ byte x_attr;
+ /** @structvar x_char
+ * @brief String
+ * @note Desired monster character
+ */
+ char x_char;
+
+
+ /** @structvar max_num
+ * @brief Number
+ * @note Maximum population allowed per level
+ */
+ s16b max_num;
+
+ /** @structvar cur_num
+ * @brief Number
+ * @note Monster population on current level
+ */
+ byte cur_num;
+
+
+ /** @structvar r_sights
+ * @brief Number
+ * @note Count sightings of this monster
+ */
+ s16b r_sights;
+ /** @structvar r_deaths
+ * @brief Number
+ * @note Count deaths from this monster
+ */
+ s16b r_deaths;
+
+ /** @structvar r_pkills
+ * @brief Number
+ * @note Count monsters killed in this life
+ */
+ s16b r_pkills;
+ /** @structvar r_tkills
+ * @brief Number
+ * @note Count monsters killed in all lives
+ */
+ s16b r_tkills;
+
+ /** @structvar r_wake
+ * @brief Number
+ * @note Number of times woken up (?)
+ */
+ byte r_wake;
+ /** @structvar r_ignore
+ * @brief Number
+ * @note Number of times ignored (?)
+ */
+ byte r_ignore;
+
+ /** @structvar r_xtra1
+ * @brief Number
+ * @note Something (unused)
+ */
+ byte r_xtra1;
+ /** @structvar r_xtra2
+ * @brief Number
+ * @note Something (unused)
+ */
+ byte r_xtra2;
+
+ /** @structvar r_drop_gold
+ * @brief Number
+ * @note Max number of gold dropped at once
+ */
+ byte r_drop_gold;
+ /** @structvar r_drop_item
+ * @brief Number
+ * @note Max number of item dropped at once
+ */
+ byte r_drop_item;
+
+ /** @structvar r_cast_inate
+ * @brief Number
+ * @note Max number of inate spells seen
+ */
+ byte r_cast_inate;
+ /** @structvar r_cast_spell
+ * @brief Number
+ * @note Max number of other spells seen
+ */
+ byte r_cast_spell;
+
+ /** @structvar r_blows[4]
+ * @brief Number
+ * @note Number of times each blow type was seen
+ */
+ byte r_blows[4];
+
+ /** @structvar r_flags1
+ * @brief Number
+ * @note Observed racial flags
+ */
+ u32b r_flags1;
+ /** @structvar r_flags2
+ * @brief Number
+ * @note Observed racial flags
+ */
+ u32b r_flags2;
+ /** @structvar r_flags3
+ * @brief Number
+ * @note Observed racial flags
+ */
+ u32b r_flags3;
+ /** @structvar r_flags4
+ * @brief Number
+ * @note Observed racial flags
+ */
+ u32b r_flags4;
+ /** @structvar r_flags5
+ * @brief Number
+ * @note Observed racial flags
+ */
+ u32b r_flags5;
+ /** @structvar r_flags6
+ * @brief Number
+ * @note Observed racial flags
+ */
+ u32b r_flags6;
+ /** @structvar r_flags7
+ * @brief Number
+ * @note Observed racial flags
+ */
+ u32b r_flags7;
+ /** @structvar r_flags8
+ * @brief Number
+ * @note Observed racial flags
+ */
+ u32b r_flags8;
+ /** @structvar r_flags9
+ * @brief Number
+ * @note Observed racial flags
+ */
+ u32b r_flags9;
+
+ /** @structvar on_saved
+ * @brief Boolean
+ * @note Is the (unique) on a saved level ?
+ */
+ bool on_saved;
+
+ /** @structvar total_visible
+ * @brief Number
+ * @note Amount of this race that are visible
+ */
+ byte total_visible;
+
+ /** @structvar drops
+ * @brief obj_theme
+ * @note The drops type
+ */
+ obj_theme drops;
+};
+
+/** @struct monster_type
+ * @brief Monster type
+ */
+struct monster_type
+{
+ /** @structvar r_idx
+ * @brief Number
+ * @note Monster race index
+ */
+ s16b r_idx;
+
+ /** @structvar ego
+ * @brief Number
+ * @note Ego monster type
+ */
+ u16b ego;
+
+ /** @structvar fy
+ * @brief Number
+ * @note Y location on map
+ */
+ byte fy;
+ /** @structvar fx
+ * @brief Number
+ * @note X location on map
+ */
+ byte fx;
+
+ /** @structvar hp
+ * @brief Number
+ * @note Current Hit points
+ */
+ s16b hp;
+ /** @structvar maxhp
+ * @brief Number
+ * @note Max Hit points
+ */
+ s16b maxhp;
+
+ /** @structvar blow[4]
+ * @brief magic_power
+ * @note Up to four blows per round
+ */
+ monster_blow blow[4];
+
+ /** @structvar speed
+ * @brief Number
+ * @note Speed (normally 110)
+ */
+ byte speed;
+ /** @structvar level
+ * @brief Number
+ * @note Level of creature
+ */
+ byte level;
+ /** @structvar ac
+ * @brief Number
+ * @note Armour Class
+ */
+ s16b ac;
+ /** @structvar exp
+ * @brief Number
+ * @note Experience
+ */
+ u32b exp;
+
+ /** @structvar csleep
+ * @brief Number
+ * @note Inactive counter
+ */
+ s16b csleep;
+
+ /** @structvar mspeed
+ * @brief Number
+ * @note Monster "speed"
+ */
+ byte mspeed;
+ /** @structvar energy
+ * @brief Number
+ * @note Monster "energy"
+ */
+ byte energy;
+
+ /** @structvar stunned
+ * @brief Number
+ * @note Monster is stunned
+ */
+ byte stunned;
+ /** @structvar confused
+ * @brief Number
+ * @note Monster is confused
+ */
+ byte confused;
+ /** @structvar monfear
+ * @brief Number
+ * @note Monster is afraid
+ */
+ byte monfear;
+
+ /** @structvar bleeding
+ * @brief Number
+ * @note Monster is bleeding
+ */
+ s16b bleeding;
+ /** @structvar poisoned
+ * @brief Number
+ * @note Monster is poisoned
+ */
+ s16b poisoned;
+
+ /** @structvar cdis
+ * @brief Number
+ * @note Current dis from player
+ */
+ byte cdis;
+
+ /** @structvar mflag
+ * @brief Number
+ * @note Extra monster flags
+ */
+ s32b mflag;
+
+ /** @structvar ml
+ * @brief Boolean
+ * @note Monster is "visible"
+ */
+ bool ml;
+
+ /** @structvar hold_o_idx
+ * @brief Number
+ * @note Object being held (if any)
+ */
+ s16b hold_o_idx;
+
+ /** @structvar smart
+ * @brief Number
+ * @note Field for "smart_learn"
+ */
+ u32b smart;
+
+ /** @structvar status
+ * @brief Number
+ * @note Status(friendly, pet, companion, ..)
+ */
+ s16b status;
+
+ /** @structvar target
+ * @brief Number
+ * @note Monster target
+ */
+ s16b target;
+
+ /** @structvar possessor
+ * @brief Number
+ * @note Is it under the control of a possessor ?
+ */
+ s16b possessor;
+};
+
+$static monster_type *lua_get_monster(int m_idx){return (&m_list[m_idx]);}
+/** @fn monster(int m_idx);
+ * @brief Return the monster with index "m_idx" in the monster list.\n
+ * @param m_idx Number \n the index of the monster in the monster list
+ * @brief Monster index
+ * @return monster_type \n The monster.
+ * @note (see file w_mnster.c)
+ */
+static monster_type *lua_get_monster @ monster(int m_idx);
+
+/** @var m_list[max_m_idx]
+ * @brief monster_type
+ * @note List of monsters
+ */
+extern monster_type m_list[max_m_idx];
+
+/** @fn race_info_idx(int r_idx, int ego)
+ * @brief Get monster info and ego info for monster with monster index "r_idx"
+ * and monster ego "ego".\n
+ * @param r_idx Number \n the index of the race in the monster race array
+ * @brief Race index
+ * @param ego Number \n the index of the ego in the monster ego array
+ * @brief Ego index
+ * @return monster_race \n The monster race.
+ * @note
+ * If "ego" > 0, the ego information is applied to the monster information and
+ * the new monster information is returned.
+ * @note
+ * For example, race_info_idx(141,7) will create a brown yeek (monster)
+ * shaman (ego).
+ * @note (see file monster2.c)
+ */
+extern monster_race* race_info_idx(int r_idx, int ego);
+
+/** @fn delete_monster_idx(int i)
+ * @brief Delete monster "i" from the monster array.\n
+ * @param i Number \n the index of the monster in the monster list
+ * @brief Monster index
+ * @note (see file monster2.c)
+ */
+extern void delete_monster_idx(int i);
+
+/** @fn m_pop(void)
+ * @brief Get an empty slot in the monster list.
+ * @return Number \n The index of an empty slot the monster list.
+ * @note
+ * If there are no empty slots, a slot will be reclaimed from a "dead"
+ * monster. If all slots are full, 0 is returned, which means the function
+ * has failed ("Too many monsters!").
+ * @note (see file monster2.c)
+ */
+extern s16b m_pop(void);
+
+/** @fn get_mon_num_prep(void)
+ * @brief Apply a "monster restriction function" to the "monster allocation
+ * table".
+ * @return Number \n 0 (success) always.
+ * @note
+ * There are no parameters, but there are some other variables which will
+ * need to be set. They are get_mon_num_hook and get_mon_num2_hook. They
+ * are pointers to functions.
+ * @note
+ * For example, get_mon_num_hook = monster_volcano means when
+ * get_mon_num_hook is called (*get_mon_num_hook)(index), the actual
+ * function called is monster_volcano(index). This particular function
+ * returns TRUE if the monster indicated by "index" has the
+ * RF8_WILD_VOLCANO flag set.
+ * @note
+ * It is a good idea to store the old value of get_mon_num_hook before
+ * setting a new one, and restoring it when your function is finished.
+ * @note
+ * Following is a list of functions which can be assigned to
+ * get_mon_num_hook:\n
+ * create_molds_hook\n
+ * create_townpeople_hook\n
+ * mon_hook_bounty\n
+ * monster_dungeon\n
+ * monster_grass\n
+ * monster_mountain\n
+ * monster_ocean\n
+ * monster_quest\n
+ * monster_shore\n
+ * monster_town\n
+ * monster_volcano\n
+ * monster_waste\n
+ * monster_wood\n
+ * mutate_monster_okay\n
+ * place_monster_okay\n
+ * summon_specific_okay\n
+ * vault_aux_animal\n
+ * vault_aux_chapel\n
+ * vault_aux_clone\n
+ * vault_aux_demon\n
+ * vault_aux_dragon\n
+ * vault_aux_giant\n
+ * vault_aux_jelly\n
+ * vault_aux_kennel\n
+ * vault_aux_orc\n
+ * vault_aux_symbol\n
+ * vault_aux_treasure\n
+ * vault_aux_troll\n
+ * vault_aux_undead
+ * @note
+ * Or you can write your own. The function must take an integer (index)
+ * as a parameter and return boolean (TRUE if the monster is selected,
+ * or FALSE if it is not).
+ * @note (see file monster2.c)
+ */
+extern errr get_mon_num_prep(void);
+
+/** @fn get_mon_num(int level)
+ * @brief For the given level "level", return the index of an appropriate
+ * monster race.\n
+ * @param level Number \n a dungeon level (which is adjusted before
+ * it is used).
+ * @brief Dungeon level
+ * @return Number \n The index of a monster race in the monster race array.
+ * @note
+ * This function uses the "prob2" field of the "monster allocation table",
+ * and various local information, to calculate the "prob3" field of the
+ * same table, which is then used to choose an "appropriate" monster, in
+ * a relatively efficient manner.
+ * @note
+ * Note that "town" monsters will *only* be created in the town, and
+ * "normal" monsters will *never* be created in the town, unless the
+ * "level" is "modified", for example, by polymorph or summoning.
+ * @note
+ * There is a small chance (1/50) of "boosting" the given depth by
+ * a small amount (up to four levels), except in the town.
+ * @note
+ * It is (slightly) more likely to acquire a monster of the given level
+ * than one of a lower level. This is done by choosing several monsters
+ * appropriate to the given level and keeping the "hardest" one.
+ * @note
+ * Note that if no monsters are "appropriate", then this function will
+ * fail, and return zero, but this should *almost* never happen.
+ * @note (see file monster2.c)
+ */
+extern s16b get_mon_num(int level);
+
+$static char *lua_monster_desc(monster_type *m_ptr, int mode){static char buf[200]; monster_desc(buf, m_ptr, mode); return buf;}
+/** @fn monster_desc(monster_type *m_ptr, int mode);
+ * @brief Return a monster description for monster "monster_type" using flag
+ * "mode".\n
+ * @param *m_ptr monster_type \n the monster
+ * @brief Monster
+ * @param mode Number \n description mode (see below)
+ * @brief Description mode
+ * @return String \n The description of the monster.
+ * @note
+ * We can correctly describe monsters based on their visibility.\n
+ * We can force all monsters to be treated as visible or invisible.\n
+ * We can build nominatives, objectives, possessives, or reflexives.\n
+ * We can selectively pronominalize hidden, visible, or all monsters.\n
+ * We can use definite or indefinite descriptions for hidden monsters.\n
+ * We can use definite or indefinite descriptions for visible monsters.
+ * @note
+ * Pronominalization involves the gender whenever possible and allowed,
+ * so that by cleverly requesting pronominalization / visibility, you
+ * can get messages like "You hit someone. She screams in agony!".
+ * @note
+ * Reflexives are acquired by requesting Objective plus Possessive.
+ * @note
+ * If no m_ptr arg is given (?), the monster is assumed to be hidden,
+ * unless the "Assume Visible" mode is requested.
+ * @note
+ * If no r_ptr arg is given, it is extracted from m_ptr and r_info
+ * If neither m_ptr nor r_ptr is given, the monster is assumed to
+ * be neuter, singular, and hidden (unless "Assume Visible" is set),
+ * in which case you may be in trouble... :-)
+ * @note
+ * I am assuming that no monster name is more than 70 characters long,
+ * so that "char desc[80];" is sufficiently large for any result.
+ * @note
+ * Mode Flags:\n
+ * 0x01 --> Objective (or Reflexive)\n
+ * 0x02 --> Possessive (or Reflexive)\n
+ * 0x04 --> Use indefinites for hidden monsters ("something")\n
+ * 0x08 --> Use indefinites for visible monsters ("a kobold")\n
+ * 0x10 --> Pronominalize hidden monsters\n
+ * 0x20 --> Pronominalize visible monsters\n
+ * 0x40 --> Assume the monster is hidden\n
+ * 0x80 --> Assume the monster is visible
+ * @note
+ * Useful Modes:\n
+ * 0x00 --> Full nominative name ("the kobold") or "it"\n
+ * 0x04 --> Full nominative name ("the kobold") or "something"\n
+ * 0x80 --> Genocide resistance name ("the kobold")\n
+ * 0x88 --> Killing name ("a kobold")\n
+ * 0x22 --> Possessive, genderized if visible ("his") or "its"\n
+ * 0x23 --> Reflexive, genderized if visible ("himself") or "itself"
+ * @note (see file monster2.c)
+ */
+static char *lua_monster_desc @ monster_desc(monster_type *m_ptr, int mode);
+
+$static char *lua_monster_race_desc(int r_idx, int ego){static char buf[200]; monster_race_desc(buf, r_idx, ego); return buf;}
+/** @fn monster_race_desc(int r_idx, int ego);
+ * @brief Return the monster description for monster with monster index
+ * "r_idx" and monster ego "ego".\n
+ * @param r_idx Number \n the index of the race in the monster race array
+ * @brief Race index
+ * @param ego Number \n the index of the ego in the monster ego array
+ * @brief Ego index
+ * @return String \n The description of the monster race.
+ * @note
+ * The monster description is made up of the ego name (if any) and monster
+ * name, or the unique name.
+ * @note (see file w_mnster.c)
+ */
+static char *lua_monster_race_desc @ monster_race_desc(int r_idx, int ego);
+
+/** @fn monster_race_desc(char *desc, int r_idx, int ego)
+ * @brief Return the monster description "desc" for monster with monster index
+ * "r_idx" and monster ego "ego".\n
+ * @param *desc String
+ * @brief Description
+ * @param r_idx Number \n the index of the race in the monster race array
+ * @brief Race index
+ * @param ego Number \n the index of the ego in the monster ego array
+ * @brief Ego index
+ * @return *desc String \n The description of the monster race.
+ * @note
+ * The monster description is made up of the ego name (if any) and monster
+ * name, or the unique name.
+ * @note (see file monster2.c)
+ */
+extern void monster_race_desc(char *desc, int r_idx, int ego);
+
+/** @fn monster_carry(monster_type *m_ptr, int m_idx, object_type *q_ptr)
+ * @brief Allow monster "m_ptr" with monster index "m_idx" to carry object
+ * "q_ptr".\n
+ * @param *m_ptr monster_type \n the monster
+ * @brief Monster
+ * @param m_idx Number \n the index of the monster in the monster list
+ * @brief Monster index
+ * @param *q_ptr object_type \n the object
+ * @brief Object
+ * @note
+ * The monster can only carry the object if there is room for the object in the
+ * object list.
+ * @note (see file monster2.c)
+ */
+extern void monster_carry(monster_type *m_ptr, int m_idx, object_type *q_ptr);
+
+/** @fn place_monster_aux(int y, int x, int r_idx, bool slp, bool grp, int status)
+ * @brief Attempt to place a monster with monster race index "r_idx" and status
+ * "status" at grid "y", "x". The monster may be asleep ("slp") or surrounded
+ * by a group of identical monsters ("grp").\n
+ * @param y Number \n the y coordinate of the target grid
+ * @brief Y-coordinate
+ * @param x Number \n the x coordinate of the target grid
+ * @brief X-coordinate
+ * @param r_idx Number \n the index of the race in the monster race array
+ * @brief Race index
+ * @param slp Boolean \n TRUE if monster is asleep, otherwise FALSE
+ * @brief Asleep?
+ * @param grp Boolean \n TRUE if monster appears in a group, otherwise FALSE
+ * @brief Group?
+ * @param status Number \n the status of the monster from the player's point
+ * of view (see MSTATUS_foo flags)
+ * @brief Monster status
+ * @return Boolean \n TRUE if the monster is placed successfully, otherwise
+ * FALSE.
+ * @note
+ * Note that certain monsters are now marked as requiring "friends".
+ * These monsters, if successfully placed, and if the "grp" parameter
+ * is TRUE, will be surrounded by a "group" of identical monsters.
+ * @note
+ * Note that certain monsters are now marked as requiring an "escort",
+ * which is a collection of monsters with similar "race" but lower
+ * level.
+ * @note
+ * Some monsters induce a fake "group" flag on their escorts.
+ * @note
+ * Note the "bizarre" use of non-recursion to prevent annoying output
+ * when running a code profiler.
+ * @note
+ * Note the use of the new "monster allocation table" code to restrict
+ * the "get_mon_num()" function to "legal" escort types.
+ * @note (see file monster2.c)
+ */
+extern bool place_monster_aux(int y, int x, int r_idx, bool slp, bool grp, int status);
+
+/** @fn place_monster(int y, int x, bool slp, bool grp)
+ * @brief Attempt to place a monster at grid "y", "x". The monster may be
+ * asleep ("slp") or surrounded by a group of identical monsters ("grp").\n
+ * @param y Number \n the y coordinate of the target grid
+ * @brief Y-coordinate
+ * @param x Number \n the x coordinate of the target grid
+ * @brief X-coordinate
+ * @param slp Boolean \n TRUE if monster is asleep, otherwise FALSE
+ * @brief Asleep?
+ * @param grp Boolean \n TRUE if monster appears in a group, otherwise FALSE
+ * @brief Group?
+ * @return Boolean \n TRUE if the monster is placed successfully, otherwise
+ * FALSE.
+ * @note
+ * Attempt to find a monster appropriate to the "monster_level"
+ * @note (see file monster2.c)
+ */
+extern bool place_monster(int y, int x, bool slp, bool grp);
+
+/** @fn place_monster_one(int y, int x, int r_idx, int ego, bool slp, int status)
+ * @brief Attempt to place a monster with monster race index "r_idx", monster
+ * ego "ego" and status "status" at grid "y", "x". The monster may be asleep
+ * ("slp").\n
+ * @param y Number \n the y coordinate of the target grid
+ * @brief Y-coordinate
+ * @param x Number \n the x coordinate of the target grid
+ * @brief X-coordinate
+ * @param r_idx Number \n the index of the race in the monster race array
+ * @brief Race index
+ * @param ego Number \n the index of the ego in the monster ego array
+ * @brief Ego index
+ * @param slp Boolean \n TRUE if monster is asleep, otherwise FALSE
+ * @brief Asleep?
+ * @param status Number \n the status of the monster from the player's point
+ * of view (see MSTATUS_foo flags)
+ * @brief Monster status
+ * @return Number \n The index of the placed monster in the monster list.
+ * @note
+ * To give the player a sporting chance, any monster that appears in
+ * line-of-sight and is extremely dangerous can be marked as
+ * "FORCE_SLEEP", which will cause them to be placed with low energy,
+ * which often (but not always) lets the player move before they do.
+ * @note
+ * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters.
+ * @note
+ * XXX XXX XXX Use special "here" and "dead" flags for unique monsters,
+ * remove old "cur_num" and "max_num" fields.
+ * @note
+ * XXX XXX XXX Actually, do something similar for artifacts, to simplify
+ * the "preserve" mode, and to make the "what artifacts" flag more useful.
+ * @note
+ * This is the only function which may place a monster in the dungeon,
+ * except for the savefile loading code.
+ * @note (see file monster2.c)
+ */
+extern s16b place_monster_one(int y, int x, int r_idx, int ego, bool slp, int status);
+
+/** @fn is_friend(monster_type *m_ptr)
+ * @brief Return a value to indicate the status of monster "m_ptr".\n
+ * @param *m_ptr monster_type \n the monster
+ * @brief Monster
+ * @return Number \n -1 if monster is an enemy, 0 if it is neutral, and 1 if
+ * it is friendly.
+ * @note (see file monster3.c)
+ */
+extern int is_friend(monster_type *m_ptr);
+
+/** @fn is_enemy(monster_type *m_ptr, monster_type *t_ptr)
+ * @brief Determine if monster "m_ptr" should attack monster "t_ptr".\n
+ * @param *m_ptr monster_type \n the monster
+ * @brief Monster
+ * @param *t_ptr monster_type \n the target monster
+ * @brief Target monster
+ * @return Boolean \n TRUE if monster "m_ptr" should attack monster "t_ptr",
+ * otherwise FALSE.
+ * @note
+ * If "m_ptr" is stupid and "r_ptr" is a different type of monster then the
+ * function will return TRUE.\n
+ * If "m_ptr" is not neutral and "r_ptr" is a breeder, and "r_ptr" is a
+ * different type of monster then the function will return TRUE (and vice
+ * versa).\n
+ * If both monsters are not neutral and one is friendly and the other isn't
+ * then the function will return TRUE.
+ * @note (see file monster3.c)
+ */
+extern bool is_enemy(monster_type *m_ptr, monster_type *t_ptr);
+
+/** @fn change_side(monster_type *m_ptr)
+ * @brief Change the status of monster "m_ptr" from friendly to unfriendly and
+ * vice versa.
+ * @param *m_ptr monster_type \n the monster
+ * @brief Monster
+ * @return Boolean \n TRUE if the status changed, otherwise FALSE.
+ * @note
+ * Friends and pets become enemies.\n
+ * Neutral monsters become neutral pets and vice versa.\n
+ * Companions are unaffected.
+ * @note (see file monster3.c)
+ */
+extern bool change_side(monster_type *m_ptr);
+
+/** @fn find_position(int y, int x, int *yy = 0, int *xx = 0)
+ * @brief Find a new grid "yy", "xx" within 6 grids of target grid "y", "x".\n
+ * @param y Number \n the y coordinate of the origin grid
+ * @brief Origin y-coordinate
+ * @param x Number \n the x coordinate of the origin grid
+ * @brief Origin x-coordinate
+ * @param yy Number \n the y coordinate of the target grid
+ * @brief Target y-coordinate
+ * @param xx Number \n the x coordinate of the target grid
+ * @brief Target x-coordinate
+ * @note
+ * The new grid must be within line-of-sight of the target grid. A
+ * maximum of 5000 attempts is made.
+ * @note (see file lua_bind.c)
+ */
+extern void find_position(int y, int x, int *yy = 0, int *xx = 0);
+
+/** @var summon_specific_level
+ * @brief Number
+ * @note
+ * Force summoned monsters to be at this level.
+ */
+extern int summon_specific_level;
+
+/** @var summon_kin_type
+ * @brief String
+ * @note
+ * The monster character for those monsters who can summon kin.
+ */
+extern char summon_kin_type;
+
+/** @fn summon_specific(int y1, int x1, int lev, int type)
+ * @brief Place a monster of type "type" near grid "y","x".\n
+ * @param y1 Number \n the y coordinate of the target grid
+ * @brief Y-coordinate
+ * @param x1 Number \n the x coordinate of the target grid
+ * @brief X-coordinate
+ * @param lev Number \n the monster level of the summoning monster
+ * @brief Summoner level
+ * @param type Number \n the type of summoned monster
+ * @brief Monster type
+ * @return Boolean \n TRUE if a monster was summoned, otherwise FALSE.
+ * @note
+ * We will attempt to place the monster up to 20 times before giving up.
+ * @note
+ * Note: SUMMON_UNIQUE and SUMMON_WRAITH (XXX) will summon Unique's\n
+ * Note: SUMMON_HI_UNDEAD and SUMMON_HI_DRAGON may summon Unique's\n
+ * Note: None of the other summon codes will ever summon Unique's.
+ * @note
+ * This function has been changed. We now take the "monster level"
+ * of the summoning monster as a parameter, and use that, along with
+ * the current dungeon level, to help determine the level of the
+ * desired monster. Note that this is an upper bound, and also
+ * tends to "prefer" monsters of that level. Currently, we use
+ * the average of the dungeon and monster levels, and then add
+ * five to allow slight increases in monster power.
+ * @note
+ * Note that we use the new "monster allocation table" creation code
+ * to restrict the "get_mon_num()" function to the set of "legal"
+ * monsters, making this function much faster and more reliable.
+ * @note
+ * Note that this function may not succeed, though this is very rare.
+ * @note (see file monster2.c)
+ */
+extern bool summon_specific(int y1, int x1, int lev, int type);
+
+/** @fn summon_specific_friendly(int y1, int x1, int lev, int type, bool Group_ok)
+ * @brief Place a friendly monster of type "type" near grid "y","x". The
+ * monster may be surrounded by a group of identical monsters ("Group_ok").\n
+ * @param y1 Number \n the y coordinate of the target grid
+ * @brief Y-coordinate
+ * @param x1 Number \n the x coordinate of the target grid
+ * @brief X-coordinate
+ * @param lev Number \n the monster level of the summoning monster
+ * @brief Summoner level
+ * @param type Number \n the type of summoned monster
+ * @brief Monster type
+ * @param Group_ok Boolean \n TRUE if monster appears in a group, otherwise
+ * FALSE
+ * @brief Group?
+ * @return Boolean \n TRUE if a monster was summoned, otherwise FALSE.
+ * @note (see file monster2.c)
+ */
+extern bool summon_specific_friendly(int y1, int x1, int lev, int type, bool Group_ok);
+
+/** @fn summon_monster_aux(int y, int x, int lev, bool friend, char *fct);
+ * @brief Place a monster near grid "y","x".\n
+ * @param y Number \n the y coordinate of the target grid
+ * @brief Y-coordinate
+ * @param x Number \n the x coordinate of the target grid
+ * @brief X-coordinate
+ * @param lev Number \n the monster level of the summoning monster
+ * @brief Summoner level
+ * @param friend Boolean \n TRUE if friendly monsters are to be summoned,
+ * otherwise FALSE
+ * @brief Friendly?
+ * @param *fct String \n the function which determines which type of monster
+ * will be summoned
+ * @brief Monster type function
+ * @return Boolean \n TRUE if a monster was summoned, otherwise FALSE.
+ * @note (see file w_mnster.c)
+ */
+extern bool lua_summon_monster @ summon_monster_aux(int y, int x, int lev, bool friend, char *fct);
+
+/** @fn can_create_companion()
+ * @brief Determine if a companion can be created.
+ * @return Boolean \n TRUE if a companion can be created, otherwise FALSE.
+ * @note
+ * The companions are counted. If this is less than the number allowed by
+ * the player monster lore skill, the function returns TRUE, otherwise the
+ * function returns FALSE.
+ * @note (see file monster3.c)
+ */
+extern bool can_create_companion();
+
+/** @fn monster_set_level(int m_idx, int level)
+ * @brief Set a new level for monster with monster index "m_idx".\n
+ * @param m_idx Number \n the index of the monster in the monster list
+ * @brief Monster index
+ * @param level Number \n the new level of the monster
+ * @brief Monster level
+ * @note
+ * The new level can not exceed 150. If the new level is higher than the
+ * monster level, the monster experience value is recalculated.
+ * @note (see file monster2.c)
+ */
+extern void monster_set_level(int m_idx, int level);
+
+/** @name Summon types
+ * @note Legal restrictions for "summon_specific()"
+ */
+/** @def SUMMON_ANT
+ * @note Summon giant ant (a) excluding uniques.
+ */
+#define SUMMON_ANT 11
+
+/** @def SUMMON_SPIDER
+ * @note Summon spider/scorpion/tick (S) excluding uniques.
+ */
+#define SUMMON_SPIDER 12
+
+/** @def SUMMON_HOUND
+ * @note Summon canine (C) or zephyr hound (Z) excluding uniques.
+ */
+#define SUMMON_HOUND 13
+
+/** @def SUMMON_HYDRA
+ * @note Summon multi-headed hydra (M) excluding uniques.
+ */
+#define SUMMON_HYDRA 14
+
+/** @def SUMMON_ANGEL
+ * @note Summon angelic being (A) excluding uniques.
+ */
+#define SUMMON_ANGEL 15
+
+/** @def SUMMON_DEMON
+ * @note Summon demon (RF3_DEMON) excluding uniques.
+ */
+#define SUMMON_DEMON 16
+
+/** @def SUMMON_UNDEAD
+ * @note Summon undead (RF3_UNDEAD) excluding uniques.
+ */
+#define SUMMON_UNDEAD 17
+
+/** @def SUMMON_DRAGON
+ * @note Summon dragon (RF3_DRAGON) excluding uniques.
+ */
+#define SUMMON_DRAGON 18
+
+/** @def SUMMON_HI_UNDEAD
+ * @note Summon lich (L) or vampire (V) or wight/wraith (W) including uniques.
+ */
+#define SUMMON_HI_UNDEAD 21
+
+/** @def SUMMON_HI_DRAGON
+ * @note Summon ancient dragon (D) including uniques.
+ */
+#define SUMMON_HI_DRAGON 22
+
+/** @def SUMMON_WRAITH
+ * @note Summon wight/wraith (W) including uniques.
+ */
+#define SUMMON_WRAITH 31
+
+/** @def SUMMON_UNIQUE
+ * @note Summon unique (RF1_UNIQUE).
+ */
+#define SUMMON_UNIQUE 32
+
+/** @def SUMMON_BIZARRE1
+ * @note Summon mold (m) excluding uniques.
+ */
+#define SUMMON_BIZARRE1 33
+
+/** @def SUMMON_BIZARRE2
+ * @note Summon giant bat (b) excluding uniques.
+ */
+#define SUMMON_BIZARRE2 34
+
+/** @def SUMMON_BIZARRE3
+ * @note Summon quylthulg (Q) excluding uniques.
+ */
+#define SUMMON_BIZARRE3 35
+
+/** @def SUMMON_BIZARRE4
+ * @note Summon vortex (v) excluding uniques.
+ */
+#define SUMMON_BIZARRE4 36
+
+/** @def SUMMON_BIZARRE5
+ * @note Summon creeping coins ($) excluding uniques.
+ */
+#define SUMMON_BIZARRE5 37
+
+/** @def SUMMON_BIZARRE6
+ * @note Summon mimic (!?=$|) excluding uniques.
+ */
+#define SUMMON_BIZARRE6 38
+
+/** @def SUMMON_HI_DEMON
+ * @note Summon demon (RF3_DEMON) and major demon (U) excluding uniques.
+ */
+#define SUMMON_HI_DEMON 39
+
+/** @def SUMMON_KIN
+ * @note Summon monster of the same character type excluding uniques.
+ */
+#define SUMMON_KIN 40
+
+/** @def SUMMON_DAWN
+ * @note Summon monster with "the Dawn" in the name excluding uniques.
+ */
+#define SUMMON_DAWN 41
+
+/** @def SUMMON_ANIMAL
+ * @note Summon animal (RF3_ANIMAL) excluding uniques.
+ */
+#define SUMMON_ANIMAL 42
+
+/** @def SUMMON_ANIMAL_RANGER
+ * @note Summon animal (RF3_ANIMAL) and giant ant, giant bat, centipede,
+ * feline,giant louse, quadruped, rodent, worm or worm mass, bird, canine,
+ * insect, snake, killer beetle, multi-headed hydra, reptile/amphibian,
+ * spider/scorpion/tick (abcflqrwBCIJKMRS) and not dragon (RF3_DRAGON) and not
+ * evil (RF3_EVIL) and not undead (RF3_UNDEAD) and not demon (RF3_DEMON) and
+ * not inate/breath and not normal spells and not special spells excluding
+ * uniques.
+ */
+#define SUMMON_ANIMAL_RANGER 43
+
+/** @def SUMMON_HI_UNDEAD_NO_UNIQUES
+ * @note Summon lich (L) or vampire (V) or wight/wraith (W) excluding uniques.
+ */
+#define SUMMON_HI_UNDEAD_NO_UNIQUES 44
+
+/** @def SUMMON_HI_DRAGON_NO_UNIQUES
+ * @note Summon ancient dragon (D) excluding uniques.
+ */
+#define SUMMON_HI_DRAGON_NO_UNIQUES 45
+
+/** @def SUMMON_NO_UNIQUES
+ * @note Summon non-uniques (not RF1_UNIQUE).
+ */
+#define SUMMON_NO_UNIQUES 46
+
+/** @def SUMMON_PHANTOM
+ * @note Summon monster with "Phantom" in the name excluding uniques.
+ */
+#define SUMMON_PHANTOM 47
+
+/** @def SUMMON_ELEMENTAL
+ * @note Summon monster with "lemental" in the name excluding uniques.
+ */
+#define SUMMON_ELEMENTAL 48
+
+/** @def SUMMON_THUNDERLORD
+ * @note Summon thunderlords (RF3_THUNDERLORD) including uniques.
+ */
+#define SUMMON_THUNDERLORD 49
+
+/** @def SUMMON_BLUE_HORROR
+ * @note Summon monster with "lue horror" in the name excluding uniques.
+ */
+#define SUMMON_BLUE_HORROR 50
+
+/** @def SUMMON_BUG
+ * @note Summon monster with "Software bug" in the name excluding uniques.
+ */
+#define SUMMON_BUG 51
+
+/** @def SUMMON_RNG
+ * @note Summon monster with "Random Number Generator" in the name excluding
+ * uniques.
+ */
+#define SUMMON_RNG 52
+
+/** @def SUMMON_MINE
+ * @note Summon mines (RF1_NEVER_MOVE) including uniques.
+ */
+#define SUMMON_MINE 53
+
+/** @def SUMMON_HUMAN
+ * @note Summon (p) excluding uniques.
+ */
+#define SUMMON_HUMAN 54
+
+/** @def SUMMON_SHADOWS
+ * @note Summon ghost (G) excluding uniques.
+ */
+#define SUMMON_SHADOWS 55
+
+/** @def SUMMON_GHOST
+ * @note Summon ghost (G) including uniques.
+ */
+#define SUMMON_GHOST 56
+
+/** @def SUMMON_QUYLTHULG
+ * @note Summon (Q) excluding uniques.
+ */
+#define SUMMON_QUYLTHULG 57
+
+/** @def SUMMON_LUA
+ * @note Summon monsters according to a Lua script.
+ */
+#define SUMMON_LUA 58
+/** @} */
+
+/** @fn do_control_reconnect()
+ * @brief Find the controlled monster and reconnect to it.
+ * @return Boolean \n TRUE if there is a controlled monster, otherwise FALSE.
+ * @note
+ * The monster list is scanned for a monster with MFLAG_CONTROL. If it is
+ * found, the function returns TRUE.
+ * @note (see file monster3.c)
+ */
+extern bool do_control_reconnect();
+
+/* monster thing */
+/** @var m_max
+ * @brief Number
+ * @note The number of monsters currently in the monster list.
+ */
+extern s16b m_max;
diff --git a/src/monster1.c b/src/monster1.c
new file mode 100644
index 00000000..196272ce
--- /dev/null
+++ b/src/monster1.c
@@ -0,0 +1,1908 @@
+/* File: monster1.c */
+
+/* Purpose: describe monsters (using monster memory) */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Christopher J. Stuart
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Pronoun arrays, by gender.
+ */
+static cptr wd_he[3] = { "it", "he", "she" };
+static cptr wd_his[3] = { "its", "his", "her" };
+
+
+/*
+ * Pluralizer. Args(count, singular, plural)
+ */
+#define plural(c,s,p) \
+(((c) == 1) ? (s) : (p))
+
+
+
+
+
+
+/*
+ * Determine if the "armor" is known
+ * The higher the level, the fewer kills needed.
+ */
+static bool_ know_armour(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ s32b level = r_ptr->level;
+
+ s32b kills = r_ptr->r_tkills;
+
+ /* Normal monsters */
+ if (kills > 304 / (4 + level)) return (TRUE);
+
+ /* Skip non-uniques */
+ if (!(r_ptr->flags1 & (RF1_UNIQUE))) return (FALSE);
+
+ /* Unique monsters */
+ if (kills > 304 / (38 + (5*level) / 4)) return (TRUE);
+
+ /* Assume false */
+ return (FALSE);
+}
+
+
+/*
+ * Determine if the "damage" of the given attack is known
+ * the higher the level of the monster, the fewer the attacks you need,
+ * the more damage an attack does, the more attacks you need
+ */
+static bool_ know_damage(int r_idx, int i)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ s32b level = r_ptr->level;
+
+ s32b a = r_ptr->r_blows[i];
+
+ s32b d1 = r_ptr->blow[i].d_dice;
+ s32b d2 = r_ptr->blow[i].d_side;
+
+ s32b d = d1 * d2;
+
+ /* Normal monsters */
+ if ((4 + level) * a > 80 * d) return (TRUE);
+
+ /* Skip non-uniques */
+ if (!(r_ptr->flags1 & (RF1_UNIQUE))) return (FALSE);
+
+ /* Unique monsters */
+ if ((4 + level) * (2 * a) > 80 * d) return (TRUE);
+
+ /* Assume false */
+ return (FALSE);
+}
+
+
+/*
+ * Hack -- display monster information using "text_out()"
+ *
+ * Note that there is now a compiler option to only read the monster
+ * descriptions from the raw file when they are actually needed, which
+ * saves about 60K of memory at the cost of disk access during monster
+ * recall, which is optional to the user.
+ *
+ * This function should only be called with the cursor placed at the
+ * left edge of the screen, on a cleared line, in which the recall is
+ * to take place. One extra blank line is left after the recall.
+ */
+static void roff_aux(int r_idx, int ego, int remem)
+{
+ monster_race *r_ptr;
+
+ bool_ old = FALSE;
+ bool_ sin = FALSE;
+
+ int m, n, r;
+
+ cptr p, q;
+
+ int msex = 0;
+
+ bool_ breath = FALSE;
+ bool_ magic = FALSE;
+
+ u32b flags1;
+ u32b flags2;
+ u32b flags3;
+ u32b flags4;
+ u32b flags5;
+ u32b flags6;
+ u32b flags7;
+ u32b flags9;
+
+ int vn = 0;
+ byte color[64];
+ cptr vp[64];
+
+ monster_race save_mem;
+
+
+
+ /* Access the race and lore */
+ r_ptr = race_info_idx(r_idx, ego);
+
+
+ /* Cheat -- Know everything */
+ if (cheat_know)
+ {
+ /* XXX XXX XXX */
+
+ /* Save the "old" memory */
+ save_mem = *r_ptr;
+
+ /* Hack -- Maximal kills */
+ r_ptr->r_tkills = MAX_SHORT;
+
+ /* Hack -- Maximal info */
+ r_ptr->r_wake = r_ptr->r_ignore = MAX_UCHAR;
+
+ /* Observe "maximal" attacks */
+ for (m = 0; m < 4; m++)
+ {
+ /* Examine "actual" blows */
+ if (r_ptr->blow[m].effect || r_ptr->blow[m].method)
+ {
+ /* Hack -- maximal observations */
+ r_ptr->r_blows[m] = MAX_UCHAR;
+ }
+ }
+
+ /* Hack -- maximal drops */
+ r_ptr->r_drop_gold = r_ptr->r_drop_item =
+ (((r_ptr->flags1 & (RF1_DROP_4D2)) ? 8 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_3D2)) ? 6 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_2D2)) ? 4 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_1D2)) ? 2 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_90)) ? 1 : 0) +
+ ((r_ptr->flags1 & (RF1_DROP_60)) ? 1 : 0));
+
+ /* Hack -- but only "valid" drops */
+ if (r_ptr->flags1 & (RF1_ONLY_GOLD)) r_ptr->r_drop_item = 0;
+ if (r_ptr->flags1 & (RF1_ONLY_ITEM)) r_ptr->r_drop_gold = 0;
+
+ /* Hack -- observe many spells */
+ r_ptr->r_cast_inate = MAX_UCHAR;
+ r_ptr->r_cast_spell = MAX_UCHAR;
+
+ /* Hack -- know all the flags */
+ r_ptr->r_flags1 = r_ptr->flags1;
+ r_ptr->r_flags2 = r_ptr->flags2;
+ r_ptr->r_flags3 = r_ptr->flags3;
+ r_ptr->r_flags4 = r_ptr->flags4;
+ r_ptr->r_flags5 = r_ptr->flags5;
+ r_ptr->r_flags6 = r_ptr->flags6;
+ r_ptr->r_flags7 = r_ptr->flags7;
+ r_ptr->r_flags8 = r_ptr->flags8;
+ r_ptr->r_flags9 = r_ptr->flags9;
+ }
+
+
+ /* Extract a gender (if applicable) */
+ if (r_ptr->flags1 & (RF1_FEMALE)) msex = 2;
+ else if (r_ptr->flags1 & (RF1_MALE)) msex = 1;
+
+
+ /* Obtain a copy of the "known" flags */
+ flags1 = (r_ptr->flags1 & r_ptr->r_flags1);
+ flags2 = (r_ptr->flags2 & r_ptr->r_flags2);
+ flags3 = (r_ptr->flags3 & r_ptr->r_flags3);
+ flags4 = (r_ptr->flags4 & r_ptr->r_flags4);
+ flags5 = (r_ptr->flags5 & r_ptr->r_flags5);
+ flags6 = (r_ptr->flags6 & r_ptr->r_flags6);
+ flags7 = (r_ptr->flags7 & r_ptr->r_flags7);
+ flags9 = (r_ptr->flags9 & r_ptr->r_flags9);
+
+
+ /* Assume some "obvious" flags */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) flags1 |= (RF1_UNIQUE);
+ if (r_ptr->flags1 & (RF1_MALE)) flags1 |= (RF1_MALE);
+ if (r_ptr->flags1 & (RF1_FEMALE)) flags1 |= (RF1_FEMALE);
+
+ /* Assume some "creation" flags */
+ if (r_ptr->flags1 & (RF1_FRIEND)) flags1 |= (RF1_FRIEND);
+ if (r_ptr->flags1 & (RF1_FRIENDS)) flags1 |= (RF1_FRIENDS);
+ if (r_ptr->flags1 & (RF1_ESCORT)) flags1 |= (RF1_ESCORT);
+ if (r_ptr->flags1 & (RF1_ESCORTS)) flags1 |= (RF1_ESCORTS);
+
+ /* Killing a monster reveals some properties */
+ if (r_ptr->r_tkills)
+ {
+ /* Know "race" flags */
+ if (r_ptr->flags3 & (RF3_ORC)) flags3 |= (RF3_ORC);
+ if (r_ptr->flags3 & (RF3_TROLL)) flags3 |= (RF3_TROLL);
+ if (r_ptr->flags3 & (RF3_GIANT)) flags3 |= (RF3_GIANT);
+ if (r_ptr->flags3 & (RF3_DRAGON)) flags3 |= (RF3_DRAGON);
+ if (r_ptr->flags3 & (RF3_DEMON)) flags3 |= (RF3_DEMON);
+ if (r_ptr->flags3 & (RF3_UNDEAD)) flags3 |= (RF3_UNDEAD);
+ if (r_ptr->flags3 & (RF3_EVIL)) flags3 |= (RF3_EVIL);
+ if (r_ptr->flags3 & (RF3_GOOD)) flags3 |= (RF3_GOOD);
+ if (r_ptr->flags3 & (RF3_ANIMAL)) flags3 |= (RF3_ANIMAL);
+ if (r_ptr->flags3 & (RF3_THUNDERLORD)) flags3 |= (RF3_THUNDERLORD);
+ if (r_ptr->flags7 & (RF7_SPIDER)) flags7 |= (RF7_SPIDER);
+
+ /* Know "forced" flags */
+ if (r_ptr->flags1 & (RF1_FORCE_DEPTH)) flags1 |= (RF1_FORCE_DEPTH);
+ if (r_ptr->flags1 & (RF1_FORCE_MAXHP)) flags1 |= (RF1_FORCE_MAXHP);
+ }
+
+
+ /* Require a flag to show kills */
+ if (!(show_details))
+ {
+ /* nothing */
+ }
+
+ /* Treat uniques differently */
+ else if (flags1 & (RF1_UNIQUE))
+ {
+ /* Hack -- Determine if the unique is "dead" */
+ bool_ dead = (r_ptr->max_num == 0) ? TRUE : FALSE;
+
+ /* We've been killed... */
+ if (r_ptr->r_deaths)
+ {
+ /* Killed ancestors */
+ text_out(format("%^s has slain %d of your ancestors",
+ wd_he[msex], r_ptr->r_deaths));
+
+ /* But we've also killed it */
+ if (dead)
+ {
+ text_out(format(", but you have avenged them! ") );
+ }
+
+ /* Unavenged (ever) */
+ else
+ {
+ text_out(format(", who %s unavenged. ",
+ plural(r_ptr->r_deaths, "remains", "remain")));
+ }
+ }
+
+ /* Dead unique who never hurt us */
+ else if (dead)
+ {
+ text_out("You have slain this foe. ");
+ }
+ }
+
+ /* Not unique, but killed us */
+ else if (r_ptr->r_deaths)
+ {
+ /* Dead ancestors */
+ text_out(format("%d of your ancestors %s been killed by this creature, ",
+ r_ptr->r_deaths, plural(r_ptr->r_deaths, "has", "have")));
+
+ /* Some kills this life */
+ if (r_ptr->r_pkills)
+ {
+ text_out("and you have exterminated at least ");
+ text_out_c(TERM_L_GREEN, format("%d", r_ptr->r_pkills));
+ text_out(" of the creatures. ");
+ }
+
+ /* Some kills past lives */
+ else if (r_ptr->r_tkills)
+ {
+ text_out(format("and %s have exterminated at least %d of the creatures. ",
+ "your ancestors", r_ptr->r_tkills));
+ }
+
+ /* No kills */
+ else
+ {
+ text_out(format("and %s is not ever known to have been defeated. ",
+ wd_he[msex]));
+ }
+ }
+
+ /* Normal monsters */
+ else
+ {
+ /* Killed some this life */
+ if (r_ptr->r_pkills)
+ {
+ text_out("You have killed at least ");
+ text_out_c(TERM_L_GREEN, format("%d", r_ptr->r_pkills));
+ text_out(" of these creatures. ");
+ }
+
+ /* Killed some last life */
+ else if (r_ptr->r_tkills)
+ {
+ text_out(format("Your ancestors have killed at least %d of these creatures. ",
+ r_ptr->r_tkills));
+ }
+
+ /* Killed none */
+ else
+ {
+ text_out("No battles to the death are recalled. ");
+ }
+ }
+
+
+ /* Descriptions */
+ if (show_details)
+ {
+ char buf[2048];
+
+ /* Simple method */
+ strcpy(buf, r_text + r_ptr->text);
+
+ /* Dump it */
+ text_out(buf);
+ text_out(" ");
+ }
+
+
+ /* Nothing yet */
+ old = FALSE;
+
+ /* Describe location */
+ if (r_ptr->flags7 & RF7_PET)
+ {
+ text_out(format("%^s is ", wd_he[msex]));
+ text_out_c(TERM_L_BLUE, "friendly");
+ text_out(" to you");
+ old = TRUE;
+ }
+
+ /* Describe location */
+ if (r_ptr->level == 0)
+ {
+ if (old)
+ text_out(", ");
+ else
+ text_out(format("%^s ", wd_he[msex]));
+ text_out_c(TERM_L_GREEN, "lives in the town or the wilderness");
+ old = TRUE;
+ }
+ else if (r_ptr->r_tkills)
+ {
+ if (old)
+ text_out(", ");
+ else
+ text_out(format("%^s ", wd_he[msex]));
+ if (depth_in_feet)
+ {
+ text_out(format("is normally found at depths of ", wd_he[msex]));
+ if (dun_level < r_ptr->level) /* out of depth monster */
+ {
+ text_out_c(TERM_L_RED, format("%d", r_ptr->level * 50));
+ }
+ else
+ {
+ text_out_c(TERM_L_GREEN, format("%d", r_ptr->level * 50));
+ }
+ text_out(" feet");
+ }
+ else
+ {
+ text_out(format("is normally found on level ", wd_he[msex]));
+ if (dun_level < r_ptr->level) /* out of depth monster */
+ {
+ text_out_c(TERM_L_RED, format("%d", r_ptr->level));
+ }
+ else
+ {
+ text_out_c(TERM_L_GREEN, format("%d", r_ptr->level));
+ }
+ }
+ old = TRUE;
+ }
+
+
+ /* Describe movement */
+ if (TRUE)
+ {
+ /* Introduction */
+ if (old)
+ {
+ text_out(", and ");
+ }
+ else
+ {
+ text_out(format("%^s ", wd_he[msex]));
+ old = TRUE;
+ }
+ text_out("moves");
+
+ /* Random-ness */
+ if ((flags1 & (RF1_RAND_50)) || (flags1 & (RF1_RAND_25)))
+ {
+ /* Adverb */
+ if ((flags1 & (RF1_RAND_50)) && (flags1 & (RF1_RAND_25)))
+ {
+ text_out(" extremely");
+ }
+ else if (flags1 & (RF1_RAND_50))
+ {
+ text_out(" somewhat");
+ }
+ else if (flags1 & (RF1_RAND_25))
+ {
+ text_out(" a bit");
+ }
+
+ /* Adjective */
+ text_out(" erratically");
+
+ /* Hack -- Occasional conjunction */
+ if (r_ptr->speed != 110) text_out(", and");
+ }
+
+ /* Speed */
+ if (r_ptr->speed > 110)
+ {
+ if (r_ptr->speed > 130) text_out_c(TERM_RED, " incredibly");
+ else if (r_ptr->speed > 120) text_out_c(TERM_ORANGE, " very");
+ text_out_c(TERM_L_RED, " quickly");
+ }
+ else if (r_ptr->speed < 110)
+ {
+ if (r_ptr->speed < 90) text_out_c(TERM_L_GREEN, " incredibly");
+ else if (r_ptr->speed < 100) text_out_c(TERM_BLUE, " very");
+ text_out_c(TERM_L_BLUE, " slowly");
+ }
+ else
+ {
+ text_out(" at normal speed");
+ }
+ }
+
+ /* The code above includes "attack speed" */
+ if (flags1 & (RF1_NEVER_MOVE))
+ {
+ /* Introduce */
+ if (old)
+ {
+ text_out(", but ");
+ }
+ else
+ {
+ text_out(format("%^s ", wd_he[msex]));
+ old = TRUE;
+ }
+
+ /* Describe */
+ text_out("does not deign to chase intruders");
+ }
+
+ /* End this sentence */
+ if (old)
+ {
+ text_out(". ");
+ old = FALSE;
+ }
+
+
+ /* Describe experience if known */
+ if (r_ptr->r_tkills)
+ {
+ /* Introduction */
+ if (flags1 & (RF1_UNIQUE))
+ {
+ text_out("Killing this");
+ }
+ else
+ {
+ text_out("A kill of this");
+ }
+
+ /* Describe the "quality" */
+ if (flags2 & (RF2_ELDRITCH_HORROR)) text_out_c(TERM_VIOLET, " sanity-blasting");
+ if (flags3 & (RF3_ANIMAL)) text_out_c(TERM_VIOLET, " natural");
+ if (flags3 & (RF3_EVIL)) text_out_c(TERM_VIOLET, " evil");
+ if (flags3 & (RF3_GOOD)) text_out_c(TERM_VIOLET, " good");
+ if (flags3 & (RF3_UNDEAD)) text_out_c(TERM_VIOLET, " undead");
+
+ /* Describe the "race" */
+ if (flags3 & (RF3_DRAGON)) text_out_c(TERM_VIOLET, " dragon");
+ else if (flags3 & (RF3_DEMON)) text_out_c(TERM_VIOLET, " demon");
+ else if (flags3 & (RF3_GIANT)) text_out_c(TERM_VIOLET, " giant");
+ else if (flags3 & (RF3_TROLL)) text_out_c(TERM_VIOLET, " troll");
+ else if (flags3 & (RF3_ORC)) text_out_c(TERM_VIOLET, " orc");
+ else if (flags3 & (RF3_THUNDERLORD))text_out_c(TERM_VIOLET, " Thunderlord");
+ else if (flags7 & (RF7_SPIDER)) text_out_c(TERM_VIOLET, " spider");
+ else if (flags7 & (RF7_NAZGUL)) text_out_c(TERM_VIOLET, " Nazgul");
+ else text_out(" creature");
+
+ /* Group some variables */
+ if (TRUE)
+ {
+ long i, j;
+
+ /* calculate the integer exp part */
+ i = (long)r_ptr->mexp * r_ptr->level / p_ptr->lev;
+
+ /* calculate the fractional exp part scaled by 100, */
+ /* must use long arithmetic to avoid overflow */
+ j = ((((long)r_ptr->mexp * r_ptr->level % p_ptr->lev) *
+ (long)1000 / p_ptr->lev + 5) / 10);
+
+ /* Mention the experience */
+ text_out(" is worth ");
+ text_out_c(TERM_ORANGE, format("%ld.%02ld", (long)i, (long)j));
+ text_out(" point");
+ text_out(((i == 1) && (j == 0)) ? "" : "s");
+
+ /* Take account of annoying English */
+ p = "th";
+ i = p_ptr->lev % 10;
+ if ((p_ptr->lev / 10) == 1) /* nothing */;
+ else if (i == 1) p = "st";
+ else if (i == 2) p = "nd";
+ else if (i == 3) p = "rd";
+
+ /* Take account of "leading vowels" in numbers */
+ q = "";
+ i = p_ptr->lev;
+ if ((i == 8) || (i == 11) || (i == 18)) q = "n";
+
+ /* Mention the dependance on the player's level */
+ text_out(format(" for a%s %lu%s level character. ",
+ q, (long)i, p));
+ }
+ }
+
+ if ((flags2 & (RF2_AURA_FIRE)) && (flags2 & (RF2_AURA_ELEC)))
+ {
+ text_out(format("%^s is surrounded by ", wd_he[msex]));
+ text_out_c(TERM_VIOLET, "flames and electricity");
+ text_out(". ");
+ }
+ else if (flags2 & (RF2_AURA_FIRE))
+ {
+ text_out(format("%^s is surrounded by ", wd_he[msex]));
+ text_out_c(TERM_ORANGE, "flames");
+ text_out(". ");
+ }
+ else if (flags2 & (RF2_AURA_ELEC))
+ {
+ text_out(format("%^s is surrounded by ", wd_he[msex]));
+ text_out_c(TERM_L_BLUE, "electricity");
+ text_out(". ");
+ }
+
+ if (flags2 & (RF2_REFLECTING))
+ {
+ text_out(format("%^s ", wd_he[msex]));
+ text_out_c(TERM_L_UMBER, "reflects");
+ text_out(" bolt spells. ");
+ }
+
+
+ /* Describe escorts */
+ if ((flags1 & (RF1_ESCORT)) || (flags1 & (RF1_ESCORTS)))
+ {
+ text_out(format("%^s usually appears with escorts. ",
+ wd_he[msex]));
+ }
+
+ /* Describe friends */
+ else if ((flags1 & (RF1_FRIEND)) || (flags1 & (RF1_FRIENDS)))
+ {
+ text_out(format("%^s usually appears in groups. ",
+ wd_he[msex]));
+ }
+
+
+ /* Collect inate attacks */
+ vn = 0;
+ if (flags4 & (RF4_SHRIEK)) vp[vn++] = "shriek for help";
+ if (flags4 & (RF4_ROCKET)) vp[vn++] = "shoot a rocket";
+ if (flags4 & (RF4_ARROW_1)) vp[vn++] = "fire an arrow";
+ if (flags4 & (RF4_ARROW_2)) vp[vn++] = "fire arrows";
+ if (flags4 & (RF4_ARROW_3)) vp[vn++] = "fire a missile";
+ if (flags4 & (RF4_ARROW_4)) vp[vn++] = "fire missiles";
+
+ /* Describe inate attacks */
+ if (vn)
+ {
+ /* Intro */
+ text_out(format("%^s", wd_he[msex]));
+
+ /* Scan */
+ for (n = 0; n < vn; n++)
+ {
+ /* Intro */
+ if (n == 0) text_out(" may ");
+ else if (n < vn - 1) text_out(", ");
+ else text_out(" or ");
+
+ /* Dump */
+ text_out_c(TERM_YELLOW, vp[n]);
+ }
+
+ /* End */
+ text_out(". ");
+ }
+
+
+ /* Collect breaths */
+ vn = 0;
+ if (flags4 & (RF4_BR_ACID)) vp[vn++] = "acid";
+ if (flags4 & (RF4_BR_ELEC)) vp[vn++] = "lightning";
+ if (flags4 & (RF4_BR_FIRE)) vp[vn++] = "fire";
+ if (flags4 & (RF4_BR_COLD)) vp[vn++] = "frost";
+ if (flags4 & (RF4_BR_POIS)) vp[vn++] = "poison";
+ if (flags4 & (RF4_BR_NETH)) vp[vn++] = "nether";
+ if (flags4 & (RF4_BR_LITE)) vp[vn++] = "light";
+ if (flags4 & (RF4_BR_DARK)) vp[vn++] = "darkness";
+ if (flags4 & (RF4_BR_CONF)) vp[vn++] = "confusion";
+ if (flags4 & (RF4_BR_SOUN)) vp[vn++] = "sound";
+ if (flags4 & (RF4_BR_CHAO)) vp[vn++] = "chaos";
+ if (flags4 & (RF4_BR_DISE)) vp[vn++] = "disenchantment";
+ if (flags4 & (RF4_BR_NEXU)) vp[vn++] = "nexus";
+ if (flags4 & (RF4_BR_TIME)) vp[vn++] = "time";
+ if (flags4 & (RF4_BR_INER)) vp[vn++] = "inertia";
+ if (flags4 & (RF4_BR_GRAV)) vp[vn++] = "gravity";
+ if (flags4 & (RF4_BR_SHAR)) vp[vn++] = "shards";
+ if (flags4 & (RF4_BR_PLAS)) vp[vn++] = "plasma";
+ if (flags4 & (RF4_BR_WALL)) vp[vn++] = "force";
+ if (flags4 & (RF4_BR_MANA)) vp[vn++] = "mana";
+ if (flags4 & (RF4_BR_NUKE)) vp[vn++] = "toxic waste";
+ if (flags4 & (RF4_BR_DISI)) vp[vn++] = "disintegration";
+
+ /* Describe breaths */
+ if (vn)
+ {
+ /* Note breath */
+ breath = TRUE;
+
+ /* Intro */
+ text_out(format("%^s", wd_he[msex]));
+
+ /* Scan */
+ for (n = 0; n < vn; n++)
+ {
+ /* Intro */
+ if (n == 0) text_out(" may breathe ");
+ else if (n < vn - 1) text_out(", ");
+ else text_out(" or ");
+
+ /* Dump */
+ text_out_c(TERM_YELLOW, vp[n]);
+ }
+ }
+
+
+ /* Collect spells */
+ vn = 0;
+ if (flags5 & (RF5_BA_ACID)) vp[vn++] = "produce acid balls";
+ if (flags5 & (RF5_BA_ELEC)) vp[vn++] = "produce lightning balls";
+ if (flags5 & (RF5_BA_FIRE)) vp[vn++] = "produce fire balls";
+ if (flags5 & (RF5_BA_COLD)) vp[vn++] = "produce frost balls";
+ if (flags5 & (RF5_BA_POIS)) vp[vn++] = "produce poison balls";
+ if (flags5 & (RF5_BA_NETH)) vp[vn++] = "produce nether balls";
+ if (flags5 & (RF5_BA_WATE)) vp[vn++] = "produce water balls";
+ if (flags4 & (RF4_BA_NUKE)) vp[vn++] = "produce balls of radiation";
+ if (flags5 & (RF5_BA_MANA)) vp[vn++] = "invoke mana storms";
+ if (flags5 & (RF5_BA_DARK)) vp[vn++] = "invoke darkness storms";
+ if (flags4 & (RF4_BA_CHAO)) vp[vn++] = "invoke raw chaos";
+ if (flags6 & (RF6_HAND_DOOM)) vp[vn++] = "invoke the Hand of Doom";
+ if (flags5 & (RF5_DRAIN_MANA)) vp[vn++] = "drain mana";
+ if (flags5 & (RF5_MIND_BLAST)) vp[vn++] = "cause mind blasting";
+ if (flags5 & (RF5_BRAIN_SMASH)) vp[vn++] = "cause brain smashing";
+ if (flags5 & (RF5_CAUSE_1)) vp[vn++] = "cause light wounds and cursing";
+ if (flags5 & (RF5_CAUSE_2)) vp[vn++] = "cause serious wounds and cursing";
+ if (flags5 & (RF5_CAUSE_3)) vp[vn++] = "cause critical wounds and cursing";
+ if (flags5 & (RF5_CAUSE_4)) vp[vn++] = "cause mortal wounds";
+ if (flags5 & (RF5_BO_ACID)) vp[vn++] = "produce acid bolts";
+ if (flags5 & (RF5_BO_ELEC)) vp[vn++] = "produce lightning bolts";
+ if (flags5 & (RF5_BO_FIRE)) vp[vn++] = "produce fire bolts";
+ if (flags5 & (RF5_BO_COLD)) vp[vn++] = "produce frost bolts";
+ if (flags5 & (RF5_BO_POIS)) vp[vn++] = "produce poison bolts";
+ if (flags5 & (RF5_BO_NETH)) vp[vn++] = "produce nether bolts";
+ if (flags5 & (RF5_BO_WATE)) vp[vn++] = "produce water bolts";
+ if (flags5 & (RF5_BO_MANA)) vp[vn++] = "produce mana bolts";
+ if (flags5 & (RF5_BO_PLAS)) vp[vn++] = "produce plasma bolts";
+ if (flags5 & (RF5_BO_ICEE)) vp[vn++] = "produce ice bolts";
+ if (flags5 & (RF5_MISSILE)) vp[vn++] = "produce magic missiles";
+ if (flags5 & (RF5_SCARE)) vp[vn++] = "terrify";
+ if (flags5 & (RF5_BLIND)) vp[vn++] = "blind";
+ if (flags5 & (RF5_CONF)) vp[vn++] = "confuse";
+ if (flags5 & (RF5_SLOW)) vp[vn++] = "slow";
+ if (flags5 & (RF5_HOLD)) vp[vn++] = "paralyze";
+ if (flags6 & (RF6_HASTE)) vp[vn++] = "haste-self";
+ if (flags6 & (RF6_HEAL)) vp[vn++] = "heal-self";
+ if (flags6 & (RF6_BLINK)) vp[vn++] = "blink-self";
+ if (flags6 & (RF6_TPORT)) vp[vn++] = "teleport-self";
+ if (flags6 & (RF6_S_BUG)) vp[vn++] = "summon software bugs";
+ if (flags6 & (RF6_S_RNG)) vp[vn++] = "summon RNG";
+ if (flags6 & (RF6_TELE_TO)) vp[vn++] = "teleport to";
+ if (flags6 & (RF6_TELE_AWAY)) vp[vn++] = "teleport away";
+ if (flags6 & (RF6_TELE_LEVEL)) vp[vn++] = "teleport level";
+ if (flags6 & (RF6_S_THUNDERLORD)) vp[vn++] = "summon a Thunderlord";
+ if (flags6 & (RF6_DARKNESS)) vp[vn++] = "create darkness";
+ if (flags6 & (RF6_TRAPS)) vp[vn++] = "create traps";
+ if (flags6 & (RF6_FORGET)) vp[vn++] = "cause amnesia";
+ if (flags6 & (RF6_RAISE_DEAD)) vp[vn++] = "raise dead";
+ if (flags6 & (RF6_S_MONSTER)) vp[vn++] = "summon a monster";
+ if (flags6 & (RF6_S_MONSTERS)) vp[vn++] = "summon monsters";
+ if (flags6 & (RF6_S_KIN)) vp[vn++] = "summon aid";
+ if (flags6 & (RF6_S_ANT)) vp[vn++] = "summon ants";
+ if (flags6 & (RF6_S_SPIDER)) vp[vn++] = "summon spiders";
+ if (flags6 & (RF6_S_HOUND)) vp[vn++] = "summon hounds";
+ if (flags6 & (RF6_S_HYDRA)) vp[vn++] = "summon hydras";
+ if (flags6 & (RF6_S_ANGEL)) vp[vn++] = "summon an angel";
+ if (flags6 & (RF6_S_DEMON)) vp[vn++] = "summon a demon";
+ if (flags6 & (RF6_S_UNDEAD)) vp[vn++] = "summon an undead";
+ if (flags6 & (RF6_S_DRAGON)) vp[vn++] = "summon a dragon";
+ if (flags4 & (RF4_S_ANIMAL)) vp[vn++] = "summon animal";
+ if (flags6 & (RF6_S_ANIMALS)) vp[vn++] = "summon animals";
+ if (flags6 & (RF6_S_HI_UNDEAD)) vp[vn++] = "summon Greater Undead";
+ if (flags6 & (RF6_S_HI_DRAGON)) vp[vn++] = "summon Ancient Dragons";
+ if (flags6 & (RF6_S_HI_DEMON)) vp[vn++] = "summon Greater Demons";
+ if (flags6 & (RF6_S_WRAITH)) vp[vn++] = "summon Ringwraith";
+ if (flags6 & (RF6_S_UNIQUE)) vp[vn++] = "summon Unique Monsters";
+
+ /* Describe spells */
+ if (vn)
+ {
+ /* Note magic */
+ magic = TRUE;
+
+ /* Intro */
+ if (breath)
+ {
+ text_out(", and is also");
+ }
+ else
+ {
+ text_out(format("%^s is", wd_he[msex]));
+ }
+
+ /* Verb Phrase */
+ text_out(" magical, casting spells");
+
+ /* Adverb */
+ if (flags2 & (RF2_SMART)) text_out_c(TERM_YELLOW, " intelligently");
+
+ /* Scan */
+ for (n = 0; n < vn; n++)
+ {
+ /* Intro */
+ if (n == 0) text_out(" which ");
+ else if (n < vn - 1) text_out(", ");
+ else text_out(" or ");
+
+ /* Dump */
+ text_out_c(TERM_YELLOW, vp[n]);
+ }
+ }
+
+
+ /* End the sentence about inate/other spells */
+ if (breath || magic)
+ {
+ /* Total casting */
+ m = r_ptr->r_cast_inate + r_ptr->r_cast_spell;
+
+ /* Average frequency */
+ n = (r_ptr->freq_inate + r_ptr->freq_spell) / 2;
+
+ /* Describe the spell frequency */
+ if (m > 100)
+ {
+ text_out("; ");
+ text_out_c(TERM_L_GREEN, "1");
+ text_out(" time in ");
+ text_out_c(TERM_L_GREEN, format("%d", 100 / n));
+ }
+
+ /* Guess at the frequency */
+ else if (m)
+ {
+ n = ((n + 9) / 10) * 10;
+ text_out("; about ");
+ text_out_c(TERM_L_GREEN, "1");
+ text_out(" time in ");
+ text_out_c(TERM_L_GREEN, format("%d", 100 / n));
+ }
+
+ /* End this sentence */
+ text_out(". ");
+ }
+
+
+ /* Describe monster "toughness" */
+ if (know_armour(r_idx))
+ {
+ /* Armor */
+ text_out(format("%^s has an armor rating of ", wd_he[msex]));
+ text_out_c(TERM_L_GREEN, format("%d", r_ptr->ac));
+
+ /* Maximized hitpoints */
+ if (flags1 & (RF1_FORCE_MAXHP))
+ {
+ text_out(" and a life rating of ");
+ text_out_c(TERM_L_GREEN, format("%d", r_ptr->hdice * r_ptr->hside));
+ text_out(". ");
+ }
+
+ /* Variable hitpoints */
+ else
+ {
+ text_out(" and a life rating of ");
+ text_out_c(TERM_L_GREEN, format("%dd%d", r_ptr->hdice, r_ptr->hside));
+ text_out(". ");
+ }
+ }
+
+
+
+ /* Collect special abilities. */
+ vn = 0;
+ if (flags2 & (RF2_OPEN_DOOR)) vp[vn++] = "open doors";
+ if (flags2 & (RF2_BASH_DOOR)) vp[vn++] = "bash down doors";
+ if (flags2 & (RF2_PASS_WALL)) vp[vn++] = "pass through walls";
+ if (flags2 & (RF2_KILL_WALL)) vp[vn++] = "bore through walls";
+ if (flags2 & (RF2_MOVE_BODY)) vp[vn++] = "push past weaker monsters";
+ if (flags2 & (RF2_KILL_BODY)) vp[vn++] = "destroy weaker monsters";
+ if (flags2 & (RF2_TAKE_ITEM)) vp[vn++] = "pick up objects";
+ if (flags2 & (RF2_KILL_ITEM)) vp[vn++] = "destroy objects";
+ if (flags9 & (RF9_HAS_LITE)) vp[vn++] = "illuminate the dungeon";
+
+ /* Describe special abilities. */
+ if (vn)
+ {
+ /* Intro */
+ text_out(format("%^s", wd_he[msex]));
+
+ /* Scan */
+ for (n = 0; n < vn; n++)
+ {
+ /* Intro */
+ if (n == 0) text_out(" can ");
+ else if (n < vn - 1) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump */
+ text_out(vp[n]);
+ }
+
+ /* End */
+ text_out(". ");
+ }
+
+
+ /* Describe special abilities. */
+ if (flags2 & (RF2_INVISIBLE))
+ {
+ text_out_c(TERM_GREEN, format("%^s is invisible. ", wd_he[msex]));
+ }
+ if (flags2 & (RF2_COLD_BLOOD))
+ {
+ text_out(format("%^s is cold blooded. ", wd_he[msex]));
+ }
+ if (flags2 & (RF2_EMPTY_MIND))
+ {
+ text_out(format("%^s is not detected by telepathy. ", wd_he[msex]));
+ }
+ if (flags2 & (RF2_WEIRD_MIND))
+ {
+ text_out(format("%^s is rarely detected by telepathy. ", wd_he[msex]));
+ }
+ if (flags4 & (RF4_MULTIPLY))
+ {
+ text_out_c(TERM_L_UMBER, format("%^s breeds explosively. ", wd_he[msex]));
+ }
+ if (flags2 & (RF2_REGENERATE))
+ {
+ text_out_c(TERM_L_WHITE, format("%^s regenerates quickly. ", wd_he[msex]));
+ }
+ if (r_ptr->flags7 & (RF7_MORTAL))
+ {
+ text_out_c(TERM_RED, format("%^s is a mortal being. ", wd_he[msex]));
+ }
+ else
+ {
+ text_out_c(TERM_L_BLUE, format("%^s is an immortal being. ", wd_he[msex]));
+ }
+
+
+ /* Collect susceptibilities */
+ vn = 0;
+ if (flags3 & (RF3_HURT_ROCK))
+ {
+ vp[vn++] = "rock remover";
+ color[vn - 1] = TERM_UMBER;
+ }
+ if (flags3 & (RF3_HURT_LITE))
+ {
+ vp[vn++] = "bright light";
+ color[vn - 1] = TERM_YELLOW;
+ }
+ if (flags3 & (RF3_SUSCEP_FIRE))
+ {
+ vp[vn++] = "fire";
+ color[vn - 1] = TERM_RED;
+ }
+ if (flags3 & (RF3_SUSCEP_COLD))
+ {
+ vp[vn++] = "cold";
+ color[vn - 1] = TERM_L_WHITE;
+ }
+ if (flags9 & (RF9_SUSCEP_ACID))
+ {
+ vp[vn++] = "acid";
+ color[vn - 1] = TERM_GREEN;
+ }
+ if (flags9 & (RF9_SUSCEP_ELEC))
+ {
+ vp[vn++] = "lightning";
+ color[vn - 1] = TERM_L_BLUE;
+ }
+ if (flags9 & (RF9_SUSCEP_POIS))
+ {
+ vp[vn++] = "poison";
+ color[vn - 1] = TERM_L_GREEN;
+ }
+
+ /* Describe susceptibilities */
+ if (vn)
+ {
+ /* Intro */
+ text_out(format("%^s", wd_he[msex]));
+
+ /* Scan */
+ for (n = 0; n < vn; n++)
+ {
+ /* Intro */
+ if (n == 0) text_out(" is hurt by ");
+ else if (n < vn - 1) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump */
+ text_out_c(color[n], vp[n]);
+ }
+
+ /* End */
+ text_out(". ");
+ }
+
+
+ /* Collect immunities */
+ vn = 0;
+ if (flags3 & (RF3_IM_ACID))
+ {
+ vp[vn++] = "acid";
+ color[vn - 1] = TERM_L_GREEN;
+ }
+ if (flags3 & (RF3_IM_ELEC))
+ {
+ vp[vn++] = "lightning";
+ color[vn - 1] = TERM_L_BLUE;
+ }
+ if (flags3 & (RF3_IM_FIRE))
+ {
+ vp[vn++] = "fire";
+ color[vn - 1] = TERM_L_RED;
+ }
+ if (flags3 & (RF3_IM_COLD))
+ {
+ vp[vn++] = "cold";
+ color[vn - 1] = TERM_L_BLUE;
+ }
+ if (flags3 & (RF3_IM_POIS))
+ {
+ vp[vn++] = "poison";
+ color[vn - 1] = TERM_L_GREEN;
+ }
+
+ /* Describe immunities */
+ if (vn)
+ {
+ /* Intro */
+ text_out(format("%^s", wd_he[msex]));
+
+ /* Scan */
+ for (n = 0; n < vn; n++)
+ {
+ /* Intro */
+ if (n == 0) text_out(" resists ");
+ else if (n < vn - 1) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump */
+ text_out_c(color[n], vp[n]);
+ }
+
+ /* End */
+ text_out(". ");
+ }
+
+
+ /* Collect resistances */
+ vn = 0;
+ if (flags3 & (RF3_RES_NETH)) vp[vn++] = "nether";
+ if (flags3 & (RF3_RES_WATE)) vp[vn++] = "water";
+ if (flags3 & (RF3_RES_PLAS)) vp[vn++] = "plasma";
+ if (flags3 & (RF3_RES_NEXU)) vp[vn++] = "nexus";
+ if (flags3 & (RF3_RES_DISE)) vp[vn++] = "disenchantment";
+ if (flags3 & (RF3_RES_TELE)) vp[vn++] = "teleportation";
+
+ /* Describe resistances */
+ if (vn)
+ {
+ /* Intro */
+ text_out(format("%^s", wd_he[msex]));
+
+ /* Scan */
+ for (n = 0; n < vn; n++)
+ {
+ /* Intro */
+ if (n == 0) text_out(" resists ");
+ else if (n < vn - 1) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump */
+ text_out_c(TERM_L_BLUE, vp[n]);
+ }
+
+ /* End */
+ text_out(". ");
+ }
+
+
+ /* Collect non-effects */
+ vn = 0;
+ if (flags3 & (RF3_NO_STUN)) vp[vn++] = "stunned";
+ if (flags3 & (RF3_NO_FEAR)) vp[vn++] = "frightened";
+ if (flags3 & (RF3_NO_CONF)) vp[vn++] = "confused";
+ if (flags3 & (RF3_NO_SLEEP)) vp[vn++] = "slept";
+
+ /* Describe non-effects */
+ if (vn)
+ {
+ /* Intro */
+ text_out(format("%^s", wd_he[msex]));
+
+ /* Scan */
+ for (n = 0; n < vn; n++)
+ {
+ /* Intro */
+ if (n == 0) text_out(" cannot be ");
+ else if (n < vn - 1) text_out(", ");
+ else text_out(" or ");
+
+ /* Dump */
+ text_out(vp[n]);
+ }
+
+ /* End */
+ text_out(". ");
+ }
+
+
+ /* Do we know how aware it is? */
+ if ((((int)r_ptr->r_wake * (int)r_ptr->r_wake) > r_ptr->sleep) ||
+ (r_ptr->r_ignore == MAX_UCHAR) ||
+ ((r_ptr->sleep == 0) && (r_ptr->r_tkills >= 10)))
+ {
+ cptr act;
+
+ if (r_ptr->sleep > 200)
+ {
+ act = "prefers to ignore";
+ }
+ else if (r_ptr->sleep > 95)
+ {
+ act = "pays very little attention to";
+ }
+ else if (r_ptr->sleep > 75)
+ {
+ act = "pays little attention to";
+ }
+ else if (r_ptr->sleep > 45)
+ {
+ act = "tends to overlook";
+ }
+ else if (r_ptr->sleep > 25)
+ {
+ act = "takes quite a while to see";
+ }
+ else if (r_ptr->sleep > 10)
+ {
+ act = "takes a while to see";
+ }
+ else if (r_ptr->sleep > 5)
+ {
+ act = "is fairly observant of";
+ }
+ else if (r_ptr->sleep > 3)
+ {
+ act = "is observant of";
+ }
+ else if (r_ptr->sleep > 1)
+ {
+ act = "is very observant of";
+ }
+ else if (r_ptr->sleep > 0)
+ {
+ act = "is vigilant for";
+ }
+ else
+ {
+ act = "is ever vigilant for";
+ }
+
+ text_out(format("%^s %s intruders, which %s may notice from %d feet. ",
+ wd_he[msex], act, wd_he[msex], 10 * r_ptr->aaf));
+ }
+
+
+ /* Drops gold and/or items */
+ if (r_ptr->r_drop_gold || r_ptr->r_drop_item)
+ {
+ /* No "n" needed */
+ sin = FALSE;
+
+ /* Intro */
+ text_out(format("%^s may carry", wd_he[msex]));
+
+ /* Count maximum drop */
+ n = MAX(r_ptr->r_drop_gold, r_ptr->r_drop_item);
+
+ /* One drop (may need an "n") */
+ if (n == 1)
+ {
+ text_out(" a");
+ sin = TRUE;
+ }
+
+ /* Two drops */
+ else if (n == 2)
+ {
+ text_out(" one or two");
+ }
+
+ /* Many drops */
+ else
+ {
+ text_out(format(" up to %d", n));
+ }
+
+
+ /* Great */
+ if (flags1 & (RF1_DROP_GREAT))
+ {
+ p = " exceptional";
+ }
+
+ /* Good (no "n" needed) */
+ else if (flags1 & (RF1_DROP_GOOD))
+ {
+ p = " good";
+ sin = FALSE;
+ }
+
+ /* Okay */
+ else
+ {
+ p = NULL;
+ }
+
+
+ /* Objects */
+ if (r_ptr->r_drop_item)
+ {
+ /* Handle singular "an" */
+ if (sin) text_out("n");
+ sin = FALSE;
+
+ /* Dump "object(s)" */
+ if (p) text_out_c(TERM_ORANGE, p);
+ text_out(" object");
+ if (n != 1) text_out("s");
+
+ /* Conjunction replaces variety, if needed for "gold" below */
+ p = " or";
+ }
+
+ /* Treasures */
+ if (r_ptr->r_drop_gold)
+ {
+ /* Cancel prefix */
+ if (!p) sin = FALSE;
+
+ /* Handle singular "an" */
+ if (sin) text_out("n");
+ sin = FALSE;
+
+ /* Dump "treasure(s)" */
+ if (p) text_out(p);
+ text_out(" treasure");
+ if (n != 1) text_out("s");
+ }
+
+ /* End this sentence */
+ text_out(". ");
+ }
+
+
+ /* Count the number of "known" attacks */
+ for (n = 0, m = 0; m < 4; m++)
+ {
+ /* Skip non-attacks */
+ if (!r_ptr->blow[m].method) continue;
+
+ /* Count known attacks */
+ if (r_ptr->r_blows[m]) n++;
+ }
+
+ /* Examine (and count) the actual attacks */
+ for (r = 0, m = 0; m < 4; m++)
+ {
+ int method, effect, d1, d2;
+
+ /* Skip non-attacks */
+ if (!r_ptr->blow[m].method) continue;
+
+ /* Skip unknown attacks */
+ if (!r_ptr->r_blows[m]) continue;
+
+
+ /* Extract the attack info */
+ method = r_ptr->blow[m].method;
+ effect = r_ptr->blow[m].effect;
+ d1 = r_ptr->blow[m].d_dice;
+ d2 = r_ptr->blow[m].d_side;
+
+
+ /* No method yet */
+ p = NULL;
+
+ /* Acquire the method */
+ switch (method)
+ {
+ case RBM_HIT:
+ p = "hit";
+ break;
+ case RBM_TOUCH:
+ p = "touch";
+ break;
+ case RBM_PUNCH:
+ p = "punch";
+ break;
+ case RBM_KICK:
+ p = "kick";
+ break;
+ case RBM_CLAW:
+ p = "claw";
+ break;
+ case RBM_BITE:
+ p = "bite";
+ break;
+ case RBM_STING:
+ p = "sting";
+ break;
+ case RBM_XXX1:
+ break;
+ case RBM_BUTT:
+ p = "butt";
+ break;
+ case RBM_CRUSH:
+ p = "crush";
+ break;
+ case RBM_ENGULF:
+ p = "engulf";
+ break;
+ case RBM_CHARGE:
+ p = "charge";
+ break;
+ case RBM_CRAWL:
+ p = "crawl on you";
+ break;
+ case RBM_DROOL:
+ p = "drool on you";
+ break;
+ case RBM_SPIT:
+ p = "spit";
+ break;
+ case RBM_EXPLODE:
+ p = "explode";
+ break;
+ case RBM_GAZE:
+ p = "gaze";
+ break;
+ case RBM_WAIL:
+ p = "wail";
+ break;
+ case RBM_SPORE:
+ p = "release spores";
+ break;
+ case RBM_XXX4:
+ break;
+ case RBM_BEG:
+ p = "beg";
+ break;
+ case RBM_INSULT:
+ p = "insult";
+ break;
+ case RBM_MOAN:
+ p = "moan";
+ break;
+ case RBM_SHOW:
+ p = "sing";
+ break;
+ }
+
+
+ /* Default effect */
+ q = NULL;
+
+ /* Acquire the effect */
+ switch (effect)
+ {
+ case RBE_HURT:
+ q = "attack";
+ break;
+ case RBE_POISON:
+ q = "poison";
+ break;
+ case RBE_UN_BONUS:
+ q = "disenchant";
+ break;
+ case RBE_UN_POWER:
+ q = "drain charges";
+ break;
+ case RBE_EAT_GOLD:
+ q = "steal gold";
+ break;
+ case RBE_EAT_ITEM:
+ q = "steal items";
+ break;
+ case RBE_EAT_FOOD:
+ q = "eat your food";
+ break;
+ case RBE_EAT_LITE:
+ q = "absorb light";
+ break;
+ case RBE_ACID:
+ q = "shoot acid";
+ break;
+ case RBE_ELEC:
+ q = "electrocute";
+ break;
+ case RBE_FIRE:
+ q = "burn";
+ break;
+ case RBE_COLD:
+ q = "freeze";
+ break;
+ case RBE_BLIND:
+ q = "blind";
+ break;
+ case RBE_CONFUSE:
+ q = "confuse";
+ break;
+ case RBE_TERRIFY:
+ q = "terrify";
+ break;
+ case RBE_PARALYZE:
+ q = "paralyze";
+ break;
+ case RBE_LOSE_STR:
+ q = "reduce strength";
+ break;
+ case RBE_LOSE_INT:
+ q = "reduce intelligence";
+ break;
+ case RBE_LOSE_WIS:
+ q = "reduce wisdom";
+ break;
+ case RBE_LOSE_DEX:
+ q = "reduce dexterity";
+ break;
+ case RBE_LOSE_CON:
+ q = "reduce constitution";
+ break;
+ case RBE_LOSE_CHR:
+ q = "reduce charisma";
+ break;
+ case RBE_LOSE_ALL:
+ q = "reduce all stats";
+ break;
+ case RBE_SHATTER:
+ q = "shatter";
+ break;
+ case RBE_EXP_10:
+ q = "lower experience (by 10d6+)";
+ break;
+ case RBE_EXP_20:
+ q = "lower experience (by 20d6+)";
+ break;
+ case RBE_EXP_40:
+ q = "lower experience (by 40d6+)";
+ break;
+ case RBE_EXP_80:
+ q = "lower experience (by 80d6+)";
+ break;
+ case RBE_DISEASE:
+ q = "disease";
+ break;
+ case RBE_TIME:
+ q = "time";
+ break;
+ case RBE_SANITY:
+ q = "blast sanity";
+ break;
+ case RBE_HALLU:
+ q = "cause hallucinations";
+ break;
+ case RBE_PARASITE:
+ q = "parasite";
+ break;
+ }
+
+
+ /* Introduce the attack description */
+ if (!r)
+ {
+ text_out(format("%^s can ", wd_he[msex]));
+ }
+ else if (r < n - 1)
+ {
+ text_out(", ");
+ }
+ else
+ {
+ text_out(", and ");
+ }
+
+
+ /* Hack -- force a method */
+ if (!p) p = "do something weird";
+
+ /* Describe the method */
+ text_out(p);
+
+
+ /* Describe the effect (if any) */
+ if (q)
+ {
+ /* Describe the attack type */
+ text_out(" to ");
+ text_out_c(TERM_YELLOW, q);
+
+ /* Describe damage (if known) */
+ if (d1 && d2 && know_damage(r_idx, m))
+ {
+ /* Display the damage */
+ text_out(" with damage");
+ text_out_c(TERM_L_GREEN, format(" %dd%d", d1, d2));
+ }
+ }
+
+
+ /* Count the attacks as printed */
+ r++;
+ }
+
+ /* Finish sentence above */
+ if (r)
+ {
+ text_out(". ");
+ }
+
+ /* Notice lack of attacks */
+ else if (flags1 & (RF1_NEVER_BLOW))
+ {
+ text_out(format("%^s has no physical attacks. ", wd_he[msex]));
+ }
+
+ /* Or describe the lack of knowledge */
+ else
+ {
+ text_out(format("Nothing is known about %s attack. ", wd_his[msex]));
+ }
+
+
+ /* All done */
+ text_out("\n");
+
+ /* Cheat -- know everything */
+ if ((cheat_know) && (remem == 0))
+ {
+ /* Hack -- restore memory */
+ COPY(r_ptr, &save_mem, monster_race);
+ }
+}
+
+/*
+ * Hack -- Display the "name" and "attr/chars" of a monster race
+ */
+static void roff_name(int r_idx, int ego)
+{
+ monster_race *r_ptr = race_info_idx(r_idx, ego);
+
+ byte a1, a2;
+ char c1, c2;
+
+ /* Access the chars */
+ c1 = r_ptr->d_char;
+ c2 = r_ptr->x_char;
+
+ /* Access the attrs */
+ a1 = r_ptr->d_attr;
+ a2 = r_ptr->x_attr;
+
+ /* A title (use "The" for non-uniques) */
+ if (!(r_ptr->flags1 & (RF1_UNIQUE)))
+ {
+ Term_addstr( -1, TERM_WHITE, "The ");
+ }
+
+ /* Dump the name */
+ if (ego)
+ {
+ if (re_info[ego].before) Term_addstr( -1, TERM_WHITE, format("%s %s", re_name + re_info[ego].name, r_name + r_ptr->name));
+ else Term_addstr( -1, TERM_WHITE, format("%s %s", r_name + r_ptr->name, re_name + re_info[ego].name));
+ }
+ else
+ {
+ Term_addstr( -1, TERM_WHITE, r_name + r_ptr->name);
+ }
+
+ /* Append the "standard" attr/char info */
+ Term_addstr( -1, TERM_WHITE, " ('");
+ Term_addch(a1, c1);
+ if (use_bigtile && (a1 & 0x80)) Term_addch(255, 255);
+ Term_addstr( -1, TERM_WHITE, "')");
+
+ /* Append the "optional" attr/char info */
+ Term_addstr( -1, TERM_WHITE, "/('");
+ Term_addch(a2, c2);
+ if (use_bigtile && (a2 & 0x80)) Term_addch(255, 255);
+ Term_addstr( -1, TERM_WHITE, "'):");
+}
+
+/*
+ * Hack -- Display the "name" and "attr/chars" of a monster race on top
+ */
+static void roff_top(int r_idx, int ego)
+{
+ /* Clear the top line */
+ Term_erase(0, 0, 255);
+
+ /* Reset the cursor */
+ Term_gotoxy(0, 0);
+
+ roff_name(r_idx, ego);
+}
+
+/*
+ * Hack -- describe the given monster race at the top of the screen
+ */
+void screen_roff(int r_idx, int ego, int remember)
+{
+ /* Flush messages */
+ msg_print(NULL);
+
+ /* Begin recall */
+ Term_erase(0, 1, 255);
+
+ /* Recall monster */
+ roff_aux(r_idx, ego, remember);
+
+ /* Describe monster */
+ roff_top(r_idx, ego);
+}
+
+/*
+ * Ddescribe the given monster race at the current pos of the "term" window
+ */
+void monster_description_out(int r_idx, int ego)
+{
+ roff_name(r_idx, ego);
+ roff_aux(r_idx, ego, 0);
+}
+
+/*
+ * Hack -- describe the given monster race in the current "term" window
+ */
+void display_roff(int r_idx, int ego)
+{
+ int y;
+
+ /* Erase the window */
+ for (y = 0; y < Term->hgt; y++)
+ {
+ /* Erase the line */
+ Term_erase(0, y, 255);
+ }
+
+ /* Begin recall */
+ Term_gotoxy(0, 1);
+
+ /* Recall monster */
+ roff_aux(r_idx, ego, 0);
+
+ /* Describe monster */
+ roff_top(r_idx, ego);
+}
+
+
+bool_ monster_quest(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Random quests are in the dungeon */
+ if (!(r_ptr->flags8 & RF8_DUNGEON)) return FALSE;
+
+ /* No random quests for aquatic monsters */
+ if (r_ptr->flags7 & RF7_AQUATIC) return FALSE;
+
+ /* No random quests for multiplying monsters */
+ if (r_ptr->flags4 & RF4_MULTIPLY) return FALSE;
+
+ return TRUE;
+}
+
+
+bool_ monster_dungeon(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags8 & RF8_DUNGEON)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_ocean(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags8 & RF8_WILD_OCEAN)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_shore(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags8 & RF8_WILD_SHORE)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_waste(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags8 & RF8_WILD_WASTE)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_town(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags8 & RF8_WILD_TOWN)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_wood(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags8 & RF8_WILD_WOOD)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_volcano(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags8 & RF8_WILD_VOLCANO)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_mountain(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags8 & RF8_WILD_MOUNTAIN)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_grass(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags8 & RF8_WILD_GRASS)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_deep_water(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (!monster_dungeon(r_idx)) return FALSE;
+
+ if (r_ptr->flags7 & RF7_AQUATIC)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+bool_ monster_shallow_water(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (!monster_dungeon(r_idx)) return FALSE;
+
+ if (r_ptr->flags2 & RF2_AURA_FIRE)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+bool_ monster_lava(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (!monster_dungeon(r_idx)) return FALSE;
+
+ if (((r_ptr->flags3 & RF3_IM_FIRE) ||
+ (r_ptr->flags7 & RF7_CAN_FLY)) &&
+ !(r_ptr->flags3 & RF3_AURA_COLD))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+void set_mon_num_hook(void)
+{
+ if (!dun_level)
+ {
+ switch (wf_info[wild_map[p_ptr->wilderness_y][p_ptr->wilderness_x].feat].terrain_idx)
+ {
+ case TERRAIN_TOWN:
+ get_mon_num_hook = monster_town;
+ break;
+ case TERRAIN_DEEP_WATER:
+ get_mon_num_hook = monster_ocean;
+ break;
+ case TERRAIN_SHALLOW_WATER:
+ get_mon_num_hook = monster_shore;
+ break;
+ case TERRAIN_DIRT:
+ get_mon_num_hook = monster_waste;
+ break;
+ case TERRAIN_GRASS:
+ get_mon_num_hook = monster_grass;
+ break;
+ case TERRAIN_TREES:
+ get_mon_num_hook = monster_wood;
+ break;
+ case TERRAIN_SHALLOW_LAVA:
+ case TERRAIN_DEEP_LAVA:
+ get_mon_num_hook = monster_volcano;
+ break;
+ case TERRAIN_MOUNTAIN:
+ get_mon_num_hook = monster_mountain;
+ break;
+ default:
+ get_mon_num_hook = monster_dungeon;
+ break;
+ }
+ }
+ else
+ {
+ get_mon_num_hook = monster_dungeon;
+ }
+}
+
+
+/*
+ * Check if monster can cross terrain
+ */
+bool_ monster_can_cross_terrain(byte feat, monster_race *r_ptr)
+{
+ /* Deep water */
+ if (feat == FEAT_DEEP_WATER)
+ {
+ if ((r_ptr->flags7 & RF7_AQUATIC) ||
+ (r_ptr->flags7 & RF7_CAN_FLY) ||
+ (r_ptr->flags7 & RF7_CAN_SWIM))
+ return TRUE;
+ else
+ return FALSE;
+ }
+ /* Shallow water */
+ else if (feat == FEAT_SHAL_WATER)
+ {
+ if (r_ptr->flags2 & RF2_AURA_FIRE)
+ return FALSE;
+ else
+ return TRUE;
+ }
+ /* Aquatic monster */
+ else if ((r_ptr->flags7 & RF7_AQUATIC) &&
+ !(r_ptr->flags7 & RF7_CAN_FLY))
+ {
+ return FALSE;
+ }
+ /* Lava */
+ else if ((feat == FEAT_SHAL_LAVA) ||
+ (feat == FEAT_DEEP_LAVA))
+ {
+ if ((r_ptr->flags3 & RF3_IM_FIRE) ||
+ (r_ptr->flags7 & RF7_CAN_FLY))
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+void set_mon_num2_hook(int y, int x)
+{
+ /* Set the monster list */
+ switch (cave[y][x].feat)
+ {
+ case FEAT_SHAL_WATER:
+ get_mon_num2_hook = monster_shallow_water;
+ break;
+ case FEAT_DEEP_WATER:
+ get_mon_num2_hook = monster_deep_water;
+ break;
+ case FEAT_DEEP_LAVA:
+ case FEAT_SHAL_LAVA:
+ get_mon_num2_hook = monster_lava;
+ break;
+ default:
+ get_mon_num2_hook = NULL;
+ break;
+ }
+}
diff --git a/src/monster2.c b/src/monster2.c
new file mode 100644
index 00000000..b0753244
--- /dev/null
+++ b/src/monster2.c
@@ -0,0 +1,4054 @@
+/* File: monster2.c */
+
+/* Purpose: misc code for monsters */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+#define MAX_HORROR 20
+#define MAX_FUNNY 22
+#define MAX_COMMENT 5
+
+/* Monster gain a few levels ? */
+void monster_check_experience(int m_idx, bool_ silent)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = &r_info[m_ptr->r_idx];
+ char m_name[80];
+
+ /* Get the name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Gain levels while possible */
+ while ((m_ptr->level < MONSTER_LEVEL_MAX) &&
+ (m_ptr->exp >= (u32b)(MONSTER_EXP(m_ptr->level + 1))))
+ {
+ /* Gain a level */
+ m_ptr->level++;
+
+ if (m_ptr->ml && (!silent)) cmsg_format(TERM_L_BLUE, "%^s gains a level.", m_name);
+
+ /* Gain hp */
+ if (magik(80))
+ {
+ m_ptr->maxhp += r_ptr->hside;
+ m_ptr->hp += r_ptr->hside;
+ }
+
+ /* Gain speed */
+ if (magik(40))
+ {
+ int speed = randint(2);
+ m_ptr->speed += speed;
+ m_ptr->mspeed += speed;
+ }
+
+ /* Gain ac */
+ if (magik(50))
+ {
+ m_ptr->ac += (r_ptr->ac / 10) ? r_ptr->ac / 10 : 1;
+ }
+
+ /* Gain melee power */
+ if (magik(30))
+ {
+ int i = rand_int(3), tries = 20;
+
+ while ((tries--) && !m_ptr->blow[i].d_dice) i = rand_int(3);
+
+ m_ptr->blow[i].d_dice++;
+ }
+ }
+}
+
+/* Monster gain some xp */
+void monster_gain_exp(int m_idx, u32b exp, bool_ silent)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ m_ptr->exp += exp;
+ if (wizard)
+ {
+ char m_name[80];
+
+ /* Get the name */
+ monster_desc(m_name, m_ptr, 0);
+
+ if (!silent) msg_format("%^s gains %ld exp.", m_name, exp);
+ }
+
+ monster_check_experience(m_idx, silent);
+}
+
+void monster_set_level(int m_idx, int level)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ if (level > 150) level = 150;
+
+ if (m_ptr->level < level)
+ {
+ m_ptr->exp = MONSTER_EXP(level);
+ monster_check_experience(m_idx, TRUE);
+ }
+}
+
+/* Will add, sub, .. */
+s32b modify_aux(s32b a, s32b b, char mod)
+{
+ switch (mod)
+ {
+ case MEGO_ADD:
+ return (a + b);
+ break;
+ case MEGO_SUB:
+ return (a - b);
+ break;
+ case MEGO_FIX:
+ return (b);
+ break;
+ case MEGO_PRC:
+ return (a * b / 100);
+ break;
+ default:
+ msg_format("WARNING, unmatching MEGO(%d).", mod);
+ return (0);
+ }
+}
+
+/* Is this ego ok for this monster ? */
+bool_ mego_ok(int r_idx, int ego)
+{
+ monster_ego *re_ptr = &re_info[ego];
+ monster_race *r_ptr = &r_info[r_idx];
+ bool_ ok = FALSE;
+ int i;
+
+ /* needed flags */
+ if (re_ptr->flags1 && ((re_ptr->flags1 & r_ptr->flags1) != re_ptr->flags1)) return FALSE;
+ if (re_ptr->flags2 && ((re_ptr->flags2 & r_ptr->flags2) != re_ptr->flags2)) return FALSE;
+ if (re_ptr->flags3 && ((re_ptr->flags3 & r_ptr->flags3) != re_ptr->flags3)) return FALSE;
+ if (re_ptr->flags7 && ((re_ptr->flags7 & r_ptr->flags7) != re_ptr->flags7)) return FALSE;
+ if (re_ptr->flags8 && ((re_ptr->flags8 & r_ptr->flags8) != re_ptr->flags8)) return FALSE;
+ if (re_ptr->flags9 && ((re_ptr->flags9 & r_ptr->flags9) != re_ptr->flags9)) return FALSE;
+
+ /* unwanted flags */
+ if (re_ptr->hflags1 && (re_ptr->hflags1 & r_ptr->flags1)) return FALSE;
+ if (re_ptr->hflags2 && (re_ptr->hflags2 & r_ptr->flags2)) return FALSE;
+ if (re_ptr->hflags3 && (re_ptr->hflags3 & r_ptr->flags3)) return FALSE;
+ if (re_ptr->hflags7 && (re_ptr->hflags7 & r_ptr->flags7)) return FALSE;
+ if (re_ptr->hflags8 && (re_ptr->hflags8 & r_ptr->flags8)) return FALSE;
+ if (re_ptr->hflags9 && (re_ptr->hflags9 & r_ptr->flags9)) return FALSE;
+
+ /* Need good race -- IF races are specified */
+ if (re_ptr->r_char[0])
+ {
+ for (i = 0; i < 5; i++)
+ {
+ if (r_ptr->d_char == re_ptr->r_char[i]) ok = TRUE;
+ }
+ if (!ok) return FALSE;
+ }
+ if (re_ptr->nr_char[0])
+ {
+ for (i = 0; i < 5; i++)
+ {
+ if (r_ptr->d_char == re_ptr->nr_char[i]) return (FALSE);
+ }
+ }
+
+ /* Passed all tests ? */
+ return TRUE;
+}
+
+/* Choose an ego type */
+int pick_ego_monster(int r_idx)
+{
+ /* Assume no ego */
+ int ego = 0, lvl;
+ int tries = max_re_idx + 10;
+ monster_ego *re_ptr;
+
+ if ((!(dungeon_flags2 & DF2_ELVEN)) && (!(dungeon_flags2 & DF2_DWARVEN)))
+ {
+ /* No townspeople ego */
+ if (!r_info[r_idx].level) return 0;
+
+ /* First are we allowed to find an ego */
+ if (!magik(MEGO_CHANCE)) return 0;
+
+ /* Lets look for one */
+ while (tries--)
+ {
+ /* Pick one */
+ ego = rand_range(1, max_re_idx - 1);
+ re_ptr = &re_info[ego];
+
+ /* No hope so far */
+ if (!mego_ok(r_idx, ego)) continue;
+
+ /* Not too much OoD */
+ lvl = r_info[r_idx].level;
+ MODIFY(lvl, re_ptr->level, 0);
+ lvl -= ((dun_level / 2) + (rand_int(dun_level / 2)));
+ if (lvl < 1) lvl = 1;
+ if (rand_int(lvl)) continue;
+
+ /* Each ego types have a rarity */
+ if (rand_int(re_ptr->rarity)) continue;
+
+ /* We finally got one ? GREAT */
+ return ego;
+ }
+ }
+ /* Bypass restrictions for themed townspeople */
+ else
+ {
+ if (dungeon_flags2 & DF2_ELVEN)
+ ego = test_mego_name("Elven");
+ else if (dungeon_flags2 & DF2_DWARVEN)
+ ego = test_mego_name("Dwarven");
+
+ if (mego_ok(r_idx, ego))
+ return ego;
+ }
+
+ /* Found none ? so sad, well no ego for the time being */
+ return 0;
+}
+
+/*
+ * Return a (monster_race*) with the combination of the monster
+ * properties and the ego type
+ */
+monster_race* race_info_idx(int r_idx, int ego)
+{
+ static monster_race race;
+ monster_ego *re_ptr = &re_info[ego];
+ monster_race *r_ptr = &r_info[r_idx], *nr_ptr = &race;
+ int i;
+
+ /* No work needed */
+ if (!ego) return r_ptr;
+
+ /* Copy the base monster */
+ COPY(nr_ptr, r_ptr, monster_race);
+
+ /* Adjust the values */
+ for (i = 0; i < 4; i++)
+ {
+ s32b j, k;
+
+ j = modify_aux(nr_ptr->blow[i].d_dice, re_ptr->blow[i].d_dice, re_ptr->blowm[i][0]);
+ if (j < 0) j = 0;
+ k = modify_aux(nr_ptr->blow[i].d_side, re_ptr->blow[i].d_side, re_ptr->blowm[i][1]);
+ if (k < 0) k = 0;
+
+ nr_ptr->blow[i].d_dice = j;
+ nr_ptr->blow[i].d_side = k;
+
+ if (re_ptr->blow[i].method) nr_ptr->blow[i].method = re_ptr->blow[i].method;
+ if (re_ptr->blow[i].effect) nr_ptr->blow[i].effect = re_ptr->blow[i].effect;
+ }
+
+ MODIFY(nr_ptr->hdice, re_ptr->hdice, 1);
+ MODIFY(nr_ptr->hside, re_ptr->hside, 1);
+
+ MODIFY(nr_ptr->ac, re_ptr->ac, 0);
+
+ MODIFY(nr_ptr->sleep, re_ptr->sleep, 0);
+
+ MODIFY(nr_ptr->aaf, re_ptr->aaf, 1);
+ MODIFY(nr_ptr->speed, re_ptr->speed, 50);
+ MODIFY(nr_ptr->mexp, re_ptr->mexp, 0);
+
+ MODIFY(nr_ptr->weight, re_ptr->weight, 10);
+
+ nr_ptr->freq_inate = (nr_ptr->freq_inate > re_ptr->freq_inate)
+ ? nr_ptr->freq_inate : re_ptr->freq_inate;
+ nr_ptr->freq_spell = (nr_ptr->freq_spell > re_ptr->freq_spell)
+ ? nr_ptr->freq_spell : re_ptr->freq_spell;
+
+ MODIFY(nr_ptr->level, re_ptr->level, 1);
+
+ /* Take off some flags */
+ nr_ptr->flags1 &= ~(re_ptr->nflags1);
+ nr_ptr->flags2 &= ~(re_ptr->nflags2);
+ nr_ptr->flags3 &= ~(re_ptr->nflags3);
+ nr_ptr->flags4 &= ~(re_ptr->nflags4);
+ nr_ptr->flags5 &= ~(re_ptr->nflags5);
+ nr_ptr->flags6 &= ~(re_ptr->nflags6);
+ nr_ptr->flags7 &= ~(re_ptr->nflags7);
+ nr_ptr->flags8 &= ~(re_ptr->nflags8);
+ nr_ptr->flags9 &= ~(re_ptr->nflags9);
+
+ /* Add some flags */
+ nr_ptr->flags1 |= re_ptr->mflags1;
+ nr_ptr->flags2 |= re_ptr->mflags2;
+ nr_ptr->flags3 |= re_ptr->mflags3;
+ nr_ptr->flags4 |= re_ptr->mflags4;
+ nr_ptr->flags5 |= re_ptr->mflags5;
+ nr_ptr->flags6 |= re_ptr->mflags6;
+ nr_ptr->flags7 |= re_ptr->mflags7;
+ nr_ptr->flags8 |= re_ptr->mflags8;
+ nr_ptr->flags9 |= re_ptr->mflags9;
+
+ /* Change the char/attr is needed */
+ if (re_ptr->d_char != MEGO_CHAR_ANY)
+ {
+ nr_ptr->d_char = re_ptr->d_char;
+ nr_ptr->x_char = re_ptr->d_char;
+ }
+ if (re_ptr->d_attr != MEGO_CHAR_ANY)
+ {
+ nr_ptr->d_attr = re_ptr->d_attr;
+ nr_ptr->x_attr = re_ptr->d_attr;
+ }
+
+ /* And finanly return a pointer to a fully working monster race */
+ return nr_ptr;
+}
+
+static cptr horror_desc[MAX_HORROR] =
+{
+ "abominable",
+ "abysmal",
+ "appalling",
+ "baleful",
+ "blasphemous",
+
+ "disgusting",
+ "dreadful",
+ "filthy",
+ "grisly",
+ "hideous",
+
+ "hellish",
+ "horrible",
+ "infernal",
+ "loathsome",
+ "nightmarish",
+
+ "repulsive",
+ "sacrilegious",
+ "terrible",
+ "unclean",
+ "unspeakable",
+};
+
+static cptr funny_desc[MAX_FUNNY] =
+{
+ "silly",
+ "hilarious",
+ "absurd",
+ "insipid",
+ "ridiculous",
+
+ "laughable",
+ "ludicrous",
+ "far-out",
+ "groovy",
+ "postmodern",
+
+ "fantastic",
+ "dadaistic",
+ "cubistic",
+ "cosmic",
+ "awesome",
+
+ "incomprehensible",
+ "fabulous",
+ "amazing",
+ "incredible",
+ "chaotic",
+
+ "wild",
+ "preposterous",
+};
+
+static cptr funny_comments[MAX_COMMENT] =
+{
+ "Wow, cosmic, man!",
+ "Rad!",
+ "Groovy!",
+ "Cool!",
+ "Far out!"
+};
+
+
+int get_wilderness_flag(void)
+{
+ int x = p_ptr->wilderness_x;
+ int y = p_ptr->wilderness_y;
+
+ if (dun_level)
+ return (RF8_DUNGEON);
+ else
+ return (1L << wf_info[wild_map[y][x].feat].terrain_idx);
+}
+
+
+/*
+ * Delete a monster by index.
+ *
+ * When a monster is deleted, all of its objects are deleted.
+ */
+void delete_monster_idx(int i)
+{
+ int x, y, j;
+
+ monster_type *m_ptr = &m_list[i];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ bool_ had_lite = FALSE;
+ ;
+
+
+ /* Get location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Hack -- Reduce the racial counter */
+ r_ptr->cur_num--;
+ r_ptr->on_saved = FALSE;
+
+ /* Hack -- count the number of "reproducers" */
+ if (r_ptr->flags4 & (RF4_MULTIPLY)) num_repro--;
+
+ /* XXX XXX XXX remove monster light source */
+ if (r_ptr->flags9 & (RF9_HAS_LITE)) had_lite = TRUE;
+
+
+ /* Hack -- remove target monster */
+ if (i == target_who) target_who = 0;
+
+ /* Hack -- remove tracked monster */
+ if (i == health_who) health_track(0);
+
+ /* Hack -- remove tracked monster */
+ if (i == p_ptr->control) p_ptr->control = 0;
+
+ for (j = m_max - 1; j >= 1; j--)
+ {
+ /* Access the monster */
+ monster_type *t_ptr = &m_list[j];
+
+ /* Ignore "dead" monsters */
+ if (!t_ptr->r_idx) continue;
+
+ if (t_ptr->target == i) t_ptr->target = -1;
+ }
+
+ /* Monster is gone */
+ cave[y][x].m_idx = 0;
+
+
+ /* Delete objects */
+ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Hack -- efficiency */
+ o_ptr->held_m_idx = 0;
+
+ if ( p_ptr->preserve )
+ {
+ /* Hack -- Preserve unknown artifacts */
+ if (artifact_p(o_ptr) && !object_known_p(o_ptr))
+ {
+ /* Mega-Hack -- Preserve the artifact */
+ if (o_ptr->tval == TV_RANDART)
+ {
+ random_artifacts[o_ptr->sval].generated = FALSE;
+ }
+ else if (k_info[o_ptr->k_idx].flags3 & TR3_NORM_ART)
+ {
+ k_info[o_ptr->k_idx].artifact = FALSE;
+ }
+ else
+ {
+ a_info[o_ptr->name1].cur_num = 0;
+ }
+ }
+ }
+ /* Delete the object */
+ delete_object_idx(this_o_idx);
+ }
+
+ /* Delete mind & special race if needed */
+ if (m_ptr->sr_ptr)
+ KILL(m_ptr->sr_ptr, monster_race);
+ if (m_ptr->mind)
+ KILL(m_ptr->mind, monster_mind);
+
+ /* Wipe the Monster */
+ m_ptr = WIPE(m_ptr, monster_type);
+
+ /* Count monsters */
+ m_cnt--;
+
+ /* Do we survided our fate ? */
+ if ((dungeon_type == DUNGEON_DEATH) && (!m_cnt))
+ {
+ msg_print("You overcome your fate, mortal!");
+
+ dungeon_type = DUNGEON_WILDERNESS;
+ dun_level = 0;
+
+ p_ptr->leaving = TRUE;
+ }
+
+ /* Update monster light */
+ if (had_lite) p_ptr->update |= (PU_MON_LITE);
+
+ /* Update monster list window */
+ p_ptr->window |= (PW_M_LIST);
+
+ /* Visual update */
+ lite_spot(y, x);
+}
+
+
+/*
+ * Delete the monster, if any, at a given location
+ */
+void delete_monster(int y, int x)
+{
+ cave_type *c_ptr;
+
+ /* Paranoia */
+ if (!in_bounds(y, x)) return;
+
+ /* Check the grid */
+ c_ptr = &cave[y][x];
+
+ /* Delete the monster (if any) */
+ if (c_ptr->m_idx) delete_monster_idx(c_ptr->m_idx);
+}
+
+
+/*
+ * Move an object from index i1 to index i2 in the object list
+ */
+static void compact_monsters_aux(int i1, int i2)
+{
+ int y, x, j;
+
+ cave_type *c_ptr;
+
+ monster_type *m_ptr;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+
+ /* Do nothing */
+ if (i1 == i2) return;
+
+
+ /* Old monster */
+ m_ptr = &m_list[i1];
+
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Cave grid */
+ c_ptr = &cave[y][x];
+
+ /* Update the cave */
+ c_ptr->m_idx = i2;
+
+ /* Repair objects being carried by monster */
+ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Reset monster pointer */
+ o_ptr->held_m_idx = i2;
+ }
+
+ /* Hack -- Update the control */
+ if (p_ptr->control == i1) p_ptr->control = i2;
+
+ /* Hack -- Update the doppleganger */
+ if (doppleganger == i1) doppleganger = i2;
+
+ /* Hack -- Update the target */
+ if (target_who == i1) target_who = i2;
+
+ /* Hack -- Update the health bar */
+ if (health_who == i1) health_track(i2);
+
+ for (j = m_max - 1; j >= 1; j--)
+ {
+ /* Access the monster */
+ monster_type *t_ptr = &m_list[j];
+
+ /* Ignore "dead" monsters */
+ if (!t_ptr->r_idx) continue;
+
+ if (t_ptr->target == i1) t_ptr->target = i2;
+ }
+
+ /* Structure copy */
+ COPY(&m_list[i2], &m_list[i1], monster_type);
+
+ /* Delete mind & special race if needed */
+ if (m_list[i1].sr_ptr)
+ KILL(m_list[i1].sr_ptr, monster_race);
+ if (m_list[i1].mind)
+ KILL(m_list[i1].mind, monster_mind);
+
+ /* Wipe the hole */
+ m_ptr = WIPE(&m_list[i1], monster_type);
+}
+
+
+/*
+ * Compact and Reorder the monster list
+ *
+ * This function can be very dangerous, use with caution!
+ *
+ * When actually "compacting" monsters, we base the saving throw
+ * on a combination of monster level, distance from player, and
+ * current "desperation".
+ *
+ * After "compacting" (if needed), we "reorder" the monsters into a more
+ * compact order, and we reset the allocation info, and the "live" array.
+ */
+void compact_monsters(int size)
+{
+ int i, num, cnt;
+ int cur_lev, cur_dis, chance;
+
+
+ /* Message (only if compacting) */
+ if (size) msg_print("Compacting monsters...");
+
+
+ /* Compact at least 'size' objects */
+ for (num = 0, cnt = 1; num < size; cnt++)
+ {
+ /* Get more vicious each iteration */
+ cur_lev = 5 * cnt;
+
+ /* Get closer each iteration */
+ cur_dis = 5 * (20 - cnt);
+
+ /* Check all the monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Paranoia -- skip "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Hack -- High level monsters start out "immune" */
+ if (m_ptr->level > cur_lev) continue;
+
+ /* Ignore nearby monsters */
+ if ((cur_dis > 0) && (m_ptr->cdis < cur_dis)) continue;
+
+ /* Saving throw chance */
+ chance = 90;
+
+ /* Only compact "Quest" Monsters in emergencies */
+ if ((m_ptr->mflag & MFLAG_QUEST) && (cnt < 1000)) chance = 100;
+
+ /* Try not to compact Unique Monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) chance = 99;
+
+ /* All monsters get a saving throw */
+ if (rand_int(100) < chance) continue;
+
+ /* Delete the monster */
+ delete_monster_idx(i);
+
+ /* Count the monster */
+ num++;
+ }
+ }
+
+
+ /* Excise dead monsters (backwards!) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Get the i'th monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Skip real monsters */
+ if (m_ptr->r_idx) continue;
+
+ /* Move last monster into open hole */
+ compact_monsters_aux(m_max - 1, i);
+
+ /* Compress "m_max" */
+ m_max--;
+ }
+}
+
+/*
+ * Delete/Remove all the monsters when the player leaves the level
+ *
+ * This is an efficient method of simulating multiple calls to the
+ * "delete_monster()" function, with no visual effects.
+ */
+void wipe_m_list(void)
+{
+ int i;
+
+ /* Delete all the monsters */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ monster_type *m_ptr = &m_list[i];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Mega-Hack -- preserve Unique's XXX XXX XXX */
+
+ /* Hack -- Reduce the racial counter */
+ r_ptr->cur_num--;
+
+ /* Monster is gone */
+ cave[m_ptr->fy][m_ptr->fx].m_idx = 0;
+
+ /* Delete mind & special race if needed */
+ if (m_ptr->sr_ptr)
+ KILL(m_ptr->sr_ptr, monster_race);
+ if (m_ptr->mind)
+ KILL(m_ptr->mind, monster_mind);
+
+
+ /* Wipe the Monster */
+ m_ptr = WIPE(m_ptr, monster_type);
+ }
+
+ /* Reset "m_max" */
+ m_max = 1;
+
+ /* Reset "m_cnt" */
+ m_cnt = 0;
+
+ /* Hack -- reset "reproducer" count */
+ num_repro = 0;
+
+ /* Hack -- no more target */
+ target_who = 0;
+
+ /* Reset control */
+ p_ptr->control = 0;
+
+ /* Hack -- no more tracking */
+ health_track(0);
+}
+
+
+/*
+ * Acquires and returns the index of a "free" monster.
+ *
+ * This routine should almost never fail, but it *can* happen.
+ */
+s16b m_pop(void)
+{
+ int i;
+
+
+ /* Normal allocation */
+ if (m_max < max_m_idx)
+ {
+ /* Access the next hole */
+ i = m_max;
+
+ /* Expand the array */
+ m_max++;
+
+ /* Count monsters */
+ m_cnt++;
+
+ /* Return the index */
+ return (i);
+ }
+
+
+ /* Recycle dead monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr;
+
+ /* Acquire monster */
+ m_ptr = &m_list[i];
+
+ /* Skip live monsters */
+ if (m_ptr->r_idx) continue;
+
+ /* Count monsters */
+ m_cnt++;
+
+ /* Use this monster */
+ return (i);
+ }
+
+
+ /* Warn the player (except during dungeon creation) */
+ if (character_dungeon) msg_print("Too many monsters!");
+
+ /* Try not to crash */
+ return (0);
+}
+
+
+
+
+/*
+ * Apply a "monster restriction function" to the "monster allocation table"
+ */
+errr get_mon_num_prep(void)
+{
+ int i;
+
+ /* Scan the allocation table */
+ for (i = 0; i < alloc_race_size; i++)
+ {
+ /* Get the entry */
+ alloc_entry *entry = &alloc_race_table[i];
+
+ /* Accept monsters which pass the restriction, if any */
+ if ((!get_mon_num_hook || (*get_mon_num_hook)(entry->index)) &&
+ (!get_mon_num2_hook || (*get_mon_num2_hook)(entry->index)))
+ {
+ /* Accept this monster */
+ entry->prob2 = entry->prob1;
+ }
+
+ /* Do not use this monster */
+ else
+ {
+ /* Decline this monster */
+ entry->prob2 = 0;
+ }
+ }
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Some dungeon types restrict the possible monsters.
+ * Return TRUE is the monster is OK and FALSE otherwise
+ */
+bool_ apply_rule(monster_race *r_ptr, byte rule)
+{
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ if (d_ptr->rules[rule].mode == DUNGEON_MODE_NONE)
+ {
+ return TRUE;
+ }
+ else if ((d_ptr->rules[rule].mode == DUNGEON_MODE_AND) || (d_ptr->rules[rule].mode == DUNGEON_MODE_NAND))
+ {
+ int a;
+
+ if (d_ptr->rules[rule].mflags1)
+ {
+ if ((d_ptr->rules[rule].mflags1 & r_ptr->flags1) != d_ptr->rules[rule].mflags1)
+ return FALSE;
+ }
+ if (d_ptr->rules[rule].mflags2)
+ {
+ if ((d_ptr->rules[rule].mflags2 & r_ptr->flags2) != d_ptr->rules[rule].mflags2)
+ return FALSE;
+ }
+ if (d_ptr->rules[rule].mflags3)
+ {
+ if ((d_ptr->rules[rule].mflags3 & r_ptr->flags3) != d_ptr->rules[rule].mflags3)
+ return FALSE;
+ }
+ if (d_ptr->rules[rule].mflags4)
+ {
+ if ((d_ptr->rules[rule].mflags4 & r_ptr->flags4) != d_ptr->rules[rule].mflags4)
+ return FALSE;
+ }
+ if (d_ptr->rules[rule].mflags5)
+ {
+ if ((d_ptr->rules[rule].mflags5 & r_ptr->flags5) != d_ptr->rules[rule].mflags5)
+ return FALSE;
+ }
+ if (d_ptr->rules[rule].mflags6)
+ {
+ if ((d_ptr->rules[rule].mflags6 & r_ptr->flags6) != d_ptr->rules[rule].mflags6)
+ return FALSE;
+ }
+ if (d_ptr->rules[rule].mflags7)
+ {
+ if ((d_ptr->rules[rule].mflags7 & r_ptr->flags7) != d_ptr->rules[rule].mflags7)
+ return FALSE;
+ }
+ if (d_ptr->rules[rule].mflags8)
+ {
+ if ((d_ptr->rules[rule].mflags8 & r_ptr->flags8) != d_ptr->rules[rule].mflags8)
+ return FALSE;
+ }
+ if (d_ptr->rules[rule].mflags9)
+ {
+ if ((d_ptr->rules[rule].mflags9 & r_ptr->flags9) != d_ptr->rules[rule].mflags9)
+ return FALSE;
+ }
+ for (a = 0; a < 5; a++)
+ {
+ if (d_ptr->rules[rule].r_char[a] && (d_ptr->rules[rule].r_char[a] != r_ptr->d_char)) return FALSE;
+ }
+
+ /* All checks passed ? lets go ! */
+ return TRUE;
+ }
+ else if ((d_ptr->rules[rule].mode == DUNGEON_MODE_OR) || (d_ptr->rules[rule].mode == DUNGEON_MODE_NOR))
+ {
+ int a;
+
+ if (d_ptr->rules[rule].mflags1 && (r_ptr->flags1 & d_ptr->rules[rule].mflags1)) return TRUE;
+ if (d_ptr->rules[rule].mflags2 && (r_ptr->flags2 & d_ptr->rules[rule].mflags2)) return TRUE;
+ if (d_ptr->rules[rule].mflags3 && (r_ptr->flags3 & d_ptr->rules[rule].mflags3)) return TRUE;
+ if (d_ptr->rules[rule].mflags4 && (r_ptr->flags4 & d_ptr->rules[rule].mflags4)) return TRUE;
+ if (d_ptr->rules[rule].mflags5 && (r_ptr->flags5 & d_ptr->rules[rule].mflags5)) return TRUE;
+ if (d_ptr->rules[rule].mflags6 && (r_ptr->flags6 & d_ptr->rules[rule].mflags6)) return TRUE;
+ if (d_ptr->rules[rule].mflags7 && (r_ptr->flags7 & d_ptr->rules[rule].mflags7)) return TRUE;
+ if (d_ptr->rules[rule].mflags8 && (r_ptr->flags8 & d_ptr->rules[rule].mflags8)) return TRUE;
+ if (d_ptr->rules[rule].mflags9 && (r_ptr->flags9 & d_ptr->rules[rule].mflags9)) return TRUE;
+
+ for (a = 0; a < 5; a++)
+ if (d_ptr->rules[rule].r_char[a] == r_ptr->d_char) return TRUE;
+
+ /* All checks failled ? Sorry ... */
+ return FALSE;
+ }
+
+ /* Should NEVER happen */
+ return FALSE;
+}
+
+bool_ restrict_monster_to_dungeon(int r_idx)
+{
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Select a random rule */
+ byte rule = d_ptr->rule_percents[rand_int(100)];
+
+ /* Apply the rule */
+ bool_ rule_ret = apply_rule(r_ptr, rule);
+
+ /* Should the rule be right or not ? */
+ if ((d_ptr->rules[rule].mode == DUNGEON_MODE_NAND) || (d_ptr->rules[rule].mode == DUNGEON_MODE_NOR)) rule_ret = !rule_ret;
+
+ /* Rule ok ? */
+ if (rule_ret) return TRUE;
+
+ /* Not allowed */
+ return FALSE;
+}
+
+/* Ugly hack, let summon unappropriate monsters */
+bool_ summon_hack = FALSE;
+
+/*
+ * Choose a monster race that seems "appropriate" to the given level
+ *
+ * This function uses the "prob2" field of the "monster allocation table",
+ * and various local information, to calculate the "prob3" field of the
+ * same table, which is then used to choose an "appropriate" monster, in
+ * a relatively efficient manner.
+ *
+ * Note that "town" monsters will *only* be created in the town, and
+ * "normal" monsters will *never* be created in the town, unless the
+ * "level" is "modified", for example, by polymorph or summoning.
+ *
+ * There is a small chance (1/50) of "boosting" the given depth by
+ * a small amount (up to four levels), except in the town.
+ *
+ * It is (slightly) more likely to acquire a monster of the given level
+ * than one of a lower level. This is done by choosing several monsters
+ * appropriate to the given level and keeping the "hardest" one.
+ *
+ * Note that if no monsters are "appropriate", then this function will
+ * fail, and return zero, but this should *almost* never happen.
+ */
+s16b get_mon_num(int level)
+{
+ int i, j, p;
+
+ int r_idx;
+
+ long value, total;
+
+ monster_race *r_ptr;
+
+ alloc_entry *table = alloc_race_table;
+
+ int in_tome;
+
+ /* Boost the level */
+ if (level > 0)
+ {
+ /* Occasional "nasty" monster */
+ if (rand_int(NASTY_MON) == 0)
+ {
+ /* Pick a level bonus */
+ int d = level / 4 + 2;
+
+ /* Boost the level */
+ level += ((d < 5) ? d : 5);
+ }
+
+ /* Occasional "nasty" monster */
+ if (rand_int(NASTY_MON) == 0)
+ {
+ /* Pick a level bonus */
+ int d = level / 4 + 2;
+
+ /* Boost the level */
+ level += ((d < 5) ? d : 5);
+ }
+ }
+
+
+ /* Reset total */
+ total = 0L;
+
+ /* Check whether this is ToME or a module */
+ in_tome = strcmp(game_module, "ToME") == 0;
+
+ /* Process probabilities */
+ for (i = 0; i < alloc_race_size; i++)
+ {
+ /* Monsters are sorted by depth */
+ if (table[i].level > level) break;
+
+ /* Default */
+ table[i].prob3 = 0;
+
+ /* Access the "r_idx" of the chosen monster */
+ r_idx = table[i].index;
+
+ /* Access the actual race */
+ r_ptr = &r_info[r_idx];
+
+ /* Hack -- "unique" monsters must be "unique" */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) &&
+ (r_ptr->cur_num >= r_ptr->max_num))
+ {
+ continue;
+ }
+
+ /* Depth Monsters never appear out of depth */
+ if ((r_ptr->flags1 & (RF1_FORCE_DEPTH)) && (r_ptr->level > dun_level))
+ {
+ continue;
+ }
+
+ /* Depth Monsters never appear out of their depth */
+ if ((r_ptr->flags9 & (RF9_ONLY_DEPTH)) && (r_ptr->level != dun_level))
+ {
+ continue;
+ }
+
+ if(in_tome)
+ {
+ /* Zangbandish monsters not allowed */
+ if (r_ptr->flags8 & RF8_ZANGBAND) continue;
+
+ /* Lovecraftian monsters not allowed */
+ if (r_ptr->flags8 & RF8_CTHANGBAND) continue;
+ }
+
+ /* Joke monsters allowed ? or not ? */
+ if (!joke_monsters && (r_ptr->flags8 & RF8_JOKEANGBAND)) continue;
+
+ /* Some dungeon types restrict the possible monsters */
+ if (!summon_hack && !restrict_monster_to_dungeon(r_idx) && dun_level) continue;
+
+ /* Accept */
+ table[i].prob3 = table[i].prob2;
+
+ /* Total */
+ total += table[i].prob3;
+ }
+
+ /* No legal monsters */
+ if (total <= 0) return (0);
+
+
+ /* Pick a monster */
+ value = rand_int(total);
+
+ /* Find the monster */
+ for (i = 0; i < alloc_race_size; i++)
+ {
+ /* Found the entry */
+ if (value < table[i].prob3) break;
+
+ /* Decrement */
+ value = value - table[i].prob3;
+ }
+
+
+ /* Power boost */
+ p = rand_int(100);
+
+ /* Try for a "harder" monster once (50%) or twice (10%) */
+ if (p < 60)
+ {
+ /* Save old */
+ j = i;
+
+ /* Pick a monster */
+ value = rand_int(total);
+
+ /* Find the monster */
+ for (i = 0; i < alloc_race_size; i++)
+ {
+ /* Found the entry */
+ if (value < table[i].prob3) break;
+
+ /* Decrement */
+ value = value - table[i].prob3;
+ }
+
+ /* Keep the "best" one */
+ if (table[i].level < table[j].level) i = j;
+ }
+
+ /* Try for a "harder" monster twice (10%) */
+ if (p < 10)
+ {
+ /* Save old */
+ j = i;
+
+ /* Pick a monster */
+ value = rand_int(total);
+
+ /* Find the monster */
+ for (i = 0; i < alloc_race_size; i++)
+ {
+ /* Found the entry */
+ if (value < table[i].prob3) break;
+
+ /* Decrement */
+ value = value - table[i].prob3;
+ }
+
+ /* Keep the "best" one */
+ if (table[i].level < table[j].level) i = j;
+ }
+
+
+ /* Result */
+ return (table[i].index);
+}
+
+
+
+
+
+/*
+ * Build a string describing a monster in some way.
+ *
+ * We can correctly describe monsters based on their visibility.
+ * We can force all monsters to be treated as visible or invisible.
+ * We can build nominatives, objectives, possessives, or reflexives.
+ * We can selectively pronominalize hidden, visible, or all monsters.
+ * We can use definite or indefinite descriptions for hidden monsters.
+ * We can use definite or indefinite descriptions for visible monsters.
+ *
+ * Pronominalization involves the gender whenever possible and allowed,
+ * so that by cleverly requesting pronominalization / visibility, you
+ * can get messages like "You hit someone. She screams in agony!".
+ *
+ * Reflexives are acquired by requesting Objective plus Possessive.
+ *
+ * If no m_ptr arg is given (?), the monster is assumed to be hidden,
+ * unless the "Assume Visible" mode is requested.
+ *
+ * If no r_ptr arg is given, it is extracted from m_ptr and r_info
+ * If neither m_ptr nor r_ptr is given, the monster is assumed to
+ * be neuter, singular, and hidden (unless "Assume Visible" is set),
+ * in which case you may be in trouble... :-)
+ *
+ * I am assuming that no monster name is more than 70 characters long,
+ * so that "char desc[80];" is sufficiently large for any result.
+ *
+ * Mode Flags:
+ * 0x01 --> Objective (or Reflexive)
+ * 0x02 --> Possessive (or Reflexive)
+ * 0x04 --> Use indefinites for hidden monsters ("something")
+ * 0x08 --> Use indefinites for visible monsters ("a kobold")
+ * 0x10 --> Pronominalize hidden monsters
+ * 0x20 --> Pronominalize visible monsters
+ * 0x40 --> Assume the monster is hidden
+ * 0x80 --> Assume the monster is visible
+ * 0x100 --> Ignore insanity
+ *
+ * Useful Modes:
+ * 0x00 --> Full nominative name ("the kobold") or "it"
+ * 0x04 --> Full nominative name ("the kobold") or "something"
+ * 0x80 --> Genocide resistance name ("the kobold")
+ * 0x88 --> Killing name ("a kobold")
+ * 0x22 --> Possessive, genderized if visible ("his") or "its"
+ * 0x23 --> Reflexive, genderized if visible ("himself") or "itself"
+ */
+void monster_desc(char *desc, monster_type *m_ptr, int mode)
+{
+ cptr res;
+ monster_race *r_ptr = race_inf(m_ptr);
+ cptr b_name = (r_name + r_ptr->name);
+ char silly_name[80], name[100];
+ bool_ seen, pron;
+ int insanity = (p_ptr->msane - p_ptr->csane) * 100 / p_ptr->msane;
+
+ if (m_ptr->ego)
+ {
+ if (re_info[m_ptr->ego].before) sprintf(name, "%s %s", re_name + re_info[m_ptr->ego].name, b_name);
+ else sprintf(name, "%s %s", b_name, re_name + re_info[m_ptr->ego].name);
+ }
+ else
+ {
+ sprintf(name, "%s", b_name);
+ }
+
+ /*
+ * Are we hallucinating? (Idea from Nethack...)
+ * insanity roll added by pelpel
+ */
+ if (!(mode & 0x100) && (p_ptr->image || (rand_int(300) < insanity)))
+ {
+ if (rand_int(2) == 0)
+ {
+ monster_race *hallu_race;
+
+ do
+ {
+ hallu_race = &r_info[randint(max_r_idx - 2)];
+ }
+ while (hallu_race->flags1 & RF1_UNIQUE);
+
+ strcpy(silly_name, (r_name + hallu_race->name));
+ }
+ else
+ {
+ get_rnd_line("silly.txt", silly_name);
+ }
+
+ strcpy(name, silly_name);
+ }
+
+ /* Can we "see" it (exists + forced, or visible + not unforced) */
+ seen = (m_ptr && ((mode & 0x80) || (!(mode & 0x40) && m_ptr->ml)));
+
+ /* Sexed Pronouns (seen and allowed, or unseen and allowed) */
+ pron = (m_ptr && ((seen && (mode & 0x20)) || (!seen && (mode & 0x10))));
+
+
+ /* First, try using pronouns, or describing hidden monsters */
+ if (!seen || pron)
+ {
+ /* an encoding of the monster "sex" */
+ int kind = 0x00;
+
+ /* Extract the gender (if applicable) */
+ if (r_ptr->flags1 & (RF1_FEMALE)) kind = 0x20;
+ else if (r_ptr->flags1 & (RF1_MALE)) kind = 0x10;
+
+ /* Ignore the gender (if desired) */
+ if (!m_ptr || !pron) kind = 0x00;
+
+
+ /* Assume simple result */
+ res = "it";
+
+ /* Brute force: split on the possibilities */
+ switch (kind | (mode & 0x07))
+ {
+ /* Neuter, or unknown */
+ case 0x00:
+ res = "it";
+ break;
+ case 0x01:
+ res = "it";
+ break;
+ case 0x02:
+ res = "its";
+ break;
+ case 0x03:
+ res = "itself";
+ break;
+ case 0x04:
+ res = "something";
+ break;
+ case 0x05:
+ res = "something";
+ break;
+ case 0x06:
+ res = "something's";
+ break;
+ case 0x07:
+ res = "itself";
+ break;
+
+ /* Male (assume human if vague) */
+ case 0x10:
+ res = "he";
+ break;
+ case 0x11:
+ res = "him";
+ break;
+ case 0x12:
+ res = "his";
+ break;
+ case 0x13:
+ res = "himself";
+ break;
+ case 0x14:
+ res = "someone";
+ break;
+ case 0x15:
+ res = "someone";
+ break;
+ case 0x16:
+ res = "someone's";
+ break;
+ case 0x17:
+ res = "himself";
+ break;
+
+ /* Female (assume human if vague) */
+ case 0x20:
+ res = "she";
+ break;
+ case 0x21:
+ res = "her";
+ break;
+ case 0x22:
+ res = "her";
+ break;
+ case 0x23:
+ res = "herself";
+ break;
+ case 0x24:
+ res = "someone";
+ break;
+ case 0x25:
+ res = "someone";
+ break;
+ case 0x26:
+ res = "someone's";
+ break;
+ case 0x27:
+ res = "herself";
+ break;
+ }
+
+ /* Copy the result */
+ (void)strcpy(desc, res);
+ }
+
+
+ /* Handle visible monsters, "reflexive" request */
+ else if ((mode & 0x02) && (mode & 0x01))
+ {
+ /* The monster is visible, so use its gender */
+ if (r_ptr->flags1 & (RF1_FEMALE)) strcpy(desc, "herself");
+ else if (r_ptr->flags1 & (RF1_MALE)) strcpy(desc, "himself");
+ else strcpy(desc, "itself");
+ }
+
+
+ /* Handle all other visible monster requests */
+ else
+ {
+ /* It could be a Unique */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) && !(p_ptr->image))
+ {
+ /* Start with the name (thus nominative and objective) */
+ (void)strcpy(desc, name);
+ }
+
+ /* It could be an indefinite monster */
+ else if (mode & 0x08)
+ {
+ /* XXX Check plurality for "some" */
+
+ /* Indefinite monsters need an indefinite article */
+ (void)strcpy(desc, is_a_vowel(name[0]) ? "an " : "a ");
+ (void)strcat(desc, name);
+ }
+
+ /* It could be a normal, definite, monster */
+ else
+ {
+ /* Definite monsters need a definite article */
+ if (m_ptr->status >= MSTATUS_PET)
+ (void)strcpy(desc, "your ");
+ else
+ (void)strcpy(desc, "the ");
+
+ (void)strcat(desc, name);
+ }
+
+ /* Handle the Possessive as a special afterthought */
+ if (mode & 0x02)
+ {
+ /* XXX Check for trailing "s" */
+
+ /* Simply append "apostrophe" and "s" */
+ (void)strcat(desc, "'s");
+ }
+ }
+}
+
+void monster_race_desc(char *desc, int r_idx, int ego)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+ cptr b_name = (r_name + r_ptr->name);
+ char name[80];
+
+ if (ego)
+ {
+ if (re_info[ego].before) sprintf(name, "%s %s", re_name + re_info[ego].name, b_name);
+ else sprintf(name, "%s %s", b_name, re_name + re_info[ego].name);
+ }
+ else
+ {
+ sprintf(name, "%s", b_name);
+ }
+
+ /* It could be a Unique */
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ /* Start with the name (thus nominative and objective) */
+ (void)strcpy(desc, name);
+ }
+
+ /* It could be a normal, definite, monster */
+ else
+ {
+ /* Definite monsters need a definite article */
+ (void)strcpy(desc, is_a_vowel(name[0]) ? "an " : "a ");
+
+ (void)strcat(desc, name);
+ }
+}
+
+
+
+/*
+ * Learn about a monster (by "probing" it)
+ */
+void lore_do_probe(int m_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ monster_race *r_ptr = &r_info[m_ptr->r_idx];
+
+ /* Hack -- Memorize some flags */
+ r_ptr->r_flags1 = r_ptr->flags1;
+ r_ptr->r_flags2 = r_ptr->flags2;
+ r_ptr->r_flags3 = r_ptr->flags3;
+
+ /* Update monster recall window */
+ if (monster_race_idx == m_ptr->r_idx)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+ }
+}
+
+
+/*
+ * Take note that the given monster just dropped some treasure
+ *
+ * Note that learning the "GOOD"/"GREAT" flags gives information
+ * about the treasure (even when the monster is killed for the first
+ * time, such as uniques, and the treasure has not been examined yet).
+ *
+ * This "indirect" method is used to prevent the player from learning
+ * exactly how much treasure a monster can drop from observing only
+ * a single example of a drop. This method actually observes how much
+ * gold and items are dropped, and remembers that information to be
+ * described later by the monster recall code.
+ */
+void lore_treasure(int m_idx, int num_item, int num_gold)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ monster_race *r_ptr = &r_info[m_ptr->r_idx];
+
+ /* Note the number of things dropped */
+ if (num_item > r_ptr->r_drop_item) r_ptr->r_drop_item = num_item;
+ if (num_gold > r_ptr->r_drop_gold) r_ptr->r_drop_gold = num_gold;
+
+ /* Hack -- memorize the good/great flags */
+ if (r_ptr->flags1 & (RF1_DROP_GOOD)) r_ptr->r_flags1 |= (RF1_DROP_GOOD);
+ if (r_ptr->flags1 & (RF1_DROP_GREAT)) r_ptr->r_flags1 |= (RF1_DROP_GREAT);
+
+ /* Update monster recall window */
+ if (monster_race_idx == m_ptr->r_idx)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+ }
+}
+
+
+
+void sanity_blast(monster_type * m_ptr, bool_ necro)
+{
+ bool_ happened = FALSE;
+ int power = 100;
+
+ if (!necro)
+ {
+ char m_name[80];
+ monster_race *r_ptr;
+
+ if (m_ptr != NULL) r_ptr = race_inf(m_ptr);
+ else return;
+
+ power = (m_ptr->level) + 10;
+
+ if (m_ptr != NULL)
+ {
+ monster_desc(m_name, m_ptr, 0);
+
+ if (!(r_ptr->flags1 & RF1_UNIQUE))
+ {
+ if (r_ptr->flags1 & RF1_FRIENDS)
+ power /= 2;
+ }
+ else power *= 2;
+
+ if (!hack_mind)
+ return ; /* No effect yet, just loaded... */
+
+ if (!(m_ptr->ml))
+ return ; /* Cannot see it for some reason */
+
+ if (!(r_ptr->flags2 & RF2_ELDRITCH_HORROR))
+ return ; /* oops */
+
+
+
+ if ((is_friend(m_ptr) > 0) && (randint(8) != 1))
+ return ; /* Pet eldritch horrors are safe most of the time */
+
+
+ if (randint(power) < p_ptr->skill_sav)
+ {
+ return ; /* Save, no adverse effects */
+ }
+
+
+ if (p_ptr->image)
+ {
+ /* Something silly happens... */
+ msg_format("You behold the %s visage of %s!",
+ funny_desc[(randint(MAX_FUNNY)) - 1], m_name);
+ if (randint(3) == 1)
+ {
+ msg_print(funny_comments[randint(MAX_COMMENT) - 1]);
+ p_ptr->image = (p_ptr->image + randint(m_ptr->level));
+ }
+ return ; /* Never mind; we can't see it clearly enough */
+ }
+
+ /* Something frightening happens... */
+ msg_format("You behold the %s visage of %s!",
+ horror_desc[(randint(MAX_HORROR)) - 1], m_name);
+
+ r_ptr->r_flags2 |= RF2_ELDRITCH_HORROR;
+
+ }
+
+ /* Undead characters are 50% likely to be unaffected */
+ if ((PRACE_FLAG(PR1_UNDEAD)) || (p_ptr->mimic_form == resolve_mimic_name("Vampire")))
+ {
+ if (randint(100) < (25 + (p_ptr->lev))) return;
+ }
+ }
+ else
+ {
+ msg_print("Your sanity is shaken by reading the Necronomicon!");
+ }
+ if (randint(power) < p_ptr->skill_sav) /* Mind blast */
+ {
+ if (!p_ptr->resist_conf)
+ {
+ (void)set_confused(p_ptr->confused + rand_int(4) + 4);
+ }
+ if ((!p_ptr->resist_chaos) && (randint(3) == 1))
+ {
+ (void) set_image(p_ptr->image + rand_int(250) + 150);
+ }
+ return;
+ }
+
+ if (randint(power) < p_ptr->skill_sav) /* Lose int & wis */
+ {
+ do_dec_stat (A_INT, STAT_DEC_NORMAL);
+ do_dec_stat (A_WIS, STAT_DEC_NORMAL);
+ return;
+ }
+
+
+ if (randint(power) < p_ptr->skill_sav) /* Brain smash */
+ {
+ if (!p_ptr->resist_conf)
+ {
+ (void)set_confused(p_ptr->confused + rand_int(4) + 4);
+ }
+ if (!p_ptr->free_act)
+ {
+ (void)set_paralyzed(p_ptr->paralyzed + rand_int(4) + 4);
+ }
+ while (rand_int(100) > p_ptr->skill_sav)
+ (void)do_dec_stat(A_INT, STAT_DEC_NORMAL);
+ while (rand_int(100) > p_ptr->skill_sav)
+ (void)do_dec_stat(A_WIS, STAT_DEC_NORMAL);
+ if (!p_ptr->resist_chaos)
+ {
+ (void) set_image(p_ptr->image + rand_int(250) + 150);
+ }
+ return;
+ }
+
+ if (randint(power) < p_ptr->skill_sav) /* Permanent lose int & wis */
+ {
+ if (dec_stat(A_INT, 10, TRUE)) happened = TRUE;
+ if (dec_stat(A_WIS, 10, TRUE)) happened = TRUE;
+ if (happened)
+ msg_print("You feel much less sane than before.");
+ return;
+ }
+
+
+ if (randint(power) < p_ptr->skill_sav) /* Amnesia */
+ {
+
+ if (lose_all_info())
+ msg_print("You forget everything in your utmost terror!");
+ return;
+ }
+
+ p_ptr->update |= PU_BONUS;
+ handle_stuff();
+}
+
+
+/*
+ * This function updates the monster record of the given monster
+ *
+ * This involves extracting the distance to the player, checking
+ * for visibility (natural, infravision, see-invis, telepathy),
+ * updating the monster visibility flag, redrawing or erasing the
+ * monster when the visibility changes, and taking note of any
+ * "visual" features of the monster (cold-blooded, invisible, etc).
+ *
+ * The only monster fields that are changed here are "cdis" (the
+ * distance from the player), "los" (clearly visible to player),
+ * and "ml" (visible to the player in any way).
+ *
+ * There are a few cases where the calling routine knows that the
+ * distance from the player to the monster has not changed, and so
+ * we have a special parameter "full" to request distance computation.
+ * This lets many calls to this function run very quickly.
+ *
+ * Note that every time a monster moves, we must call this function
+ * for that monster, and update distance. Note that every time the
+ * player moves, we must call this function for every monster, and
+ * update distance. Note that every time the player "state" changes
+ * in certain ways (including "blindness", "infravision", "telepathy",
+ * and "see invisible"), we must call this function for every monster.
+ *
+ * The routines that actually move the monsters call this routine
+ * directly, and the ones that move the player, or notice changes
+ * in the player state, call "update_monsters()".
+ *
+ * Routines that change the "illumination" of grids must also call
+ * this function, since the "visibility" of some monsters may be
+ * based on the illumination of their grid.
+ *
+ * Note that this function is called once per monster every time the
+ * player moves, so it is important to optimize it for monsters which
+ * are far away. Note the optimization which skips monsters which
+ * are far away and were completely invisible last turn.
+ *
+ * Note the optimized "inline" version of the "distance()" function.
+ *
+ * Note that only monsters on the current panel can be "visible",
+ * and then only if they are (1) in line of sight and illuminated
+ * by light or infravision, or (2) nearby and detected by telepathy.
+ *
+ * The player can choose to be disturbed by several things, including
+ * "disturb_move" (monster which is viewable moves in some way), and
+ * "disturb_near" (monster which is "easily" viewable moves in some
+ * way). Note that "moves" includes "appears" and "disappears".
+ *
+ * Note the new "xtra" field which encodes several state flags such
+ * as "detected last turn", and "detected this turn", and "currently
+ * in line of sight", all of which are used for visibility testing.
+ */
+void update_mon(int m_idx, bool_ full)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* The current monster location */
+ int fy = m_ptr->fy;
+ int fx = m_ptr->fx;
+
+ bool_ old_ml = m_ptr->ml;
+
+ /* Seen at all */
+ bool_ flag = FALSE;
+
+ /* Seen by vision */
+ bool_ easy = FALSE;
+
+ /* Seen by telepathy */
+ bool_ hard = FALSE;
+
+ /* Various extra flags */
+ bool_ do_empty_mind = FALSE;
+ bool_ do_weird_mind = FALSE;
+ bool_ do_invisible = FALSE;
+ bool_ do_cold_blood = FALSE;
+
+
+ /* Calculate distance */
+ if (full)
+ {
+ int d, dy, dx;
+
+ /* Distance components */
+ dy = (p_ptr->py > fy) ? (p_ptr->py - fy) : (fy - p_ptr->py);
+ dx = (p_ptr->px > fx) ? (p_ptr->px - fx) : (fx - p_ptr->px);
+
+ /* Approximate distance */
+ d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
+
+ /* Save the distance (in a byte) */
+ m_ptr->cdis = (d < 255) ? d : 255;
+ }
+
+
+ /* Process "distant" monsters */
+ if (m_ptr->cdis > MAX_SIGHT)
+ {
+ /* Ignore unseen monsters */
+ if (!m_ptr->ml) return;
+
+ /* Detected */
+ if (m_ptr->mflag & (MFLAG_MARK)) flag = TRUE;
+ }
+
+
+ /* Process "nearby" monsters on the current "panel" */
+ else if (panel_contains(fy, fx))
+ {
+ /* Normal line of sight, and player is not blind */
+ if (player_has_los_bold(fy, fx) && !p_ptr->blind)
+ {
+ /* Use "infravision" */
+ if (m_ptr->cdis <= (byte)(p_ptr->see_infra))
+ {
+ /* Infravision only works on "warm" creatures */
+ /* Below, we will need to know that infravision failed */
+ if (r_ptr->flags2 & (RF2_COLD_BLOOD)) do_cold_blood = TRUE;
+
+ /* Infravision works */
+ if (!do_cold_blood) easy = flag = TRUE;
+ }
+
+ /* Use "illumination" */
+ if (player_can_see_bold(fy, fx))
+ {
+ /* Take note of invisibility */
+ if (r_ptr->flags2 & (RF2_INVISIBLE)) do_invisible = TRUE;
+
+ /* Visible, or detectable, monsters get seen */
+ if (!do_invisible || p_ptr->see_inv) easy = flag = TRUE;
+ }
+ }
+
+ /* Telepathy can see all "nearby" monsters with "minds" */
+ if (p_ptr->telepathy)
+ {
+ /* Assume we cant see */
+ bool_ can_esp = FALSE;
+
+ /* Different ESP */
+ if ((p_ptr->telepathy & ESP_ORC) && (r_ptr->flags3 & RF3_ORC)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_SPIDER) && (r_ptr->flags7 & RF7_SPIDER)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_TROLL) && (r_ptr->flags3 & RF3_TROLL)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_DRAGON) && (r_ptr->flags3 & RF3_DRAGON)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_GIANT) && (r_ptr->flags3 & RF3_GIANT)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_DEMON) && (r_ptr->flags3 & RF3_DEMON)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_UNDEAD) && (r_ptr->flags3 & RF3_UNDEAD)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_EVIL) && (r_ptr->flags3 & RF3_EVIL)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_ANIMAL) && (r_ptr->flags3 & RF3_ANIMAL)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_THUNDERLORD) && (r_ptr->flags3 & RF3_THUNDERLORD)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_GOOD) && (r_ptr->flags3 & RF3_GOOD)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_NONLIVING) && (r_ptr->flags3 & RF3_NONLIVING)) can_esp = TRUE;
+ if ((p_ptr->telepathy & ESP_UNIQUE) && ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags3 & RF3_UNIQUE_4))) can_esp = TRUE;
+ if (p_ptr->telepathy & ESP_ALL) can_esp = TRUE;
+
+ /* Only do this when we can really detect monster */
+ if (can_esp)
+ {
+ /* Empty mind, no telepathy */
+ if (r_ptr->flags2 & (RF2_EMPTY_MIND))
+ {
+ do_empty_mind = TRUE;
+ }
+
+ /* Weird mind, occasional telepathy */
+ else if (r_ptr->flags2 & (RF2_WEIRD_MIND))
+ {
+ do_weird_mind = TRUE;
+ if (rand_int(100) < 10)
+ {
+ hard = TRUE;
+ flag = TRUE;
+ }
+ }
+
+ /* Normal mind, allow telepathy */
+ else
+ {
+ hard = TRUE;
+ flag = TRUE;
+ }
+ }
+ }
+
+ /* Apply "detection" spells */
+ if (m_ptr->mflag & (MFLAG_MARK)) flag = TRUE;
+
+ /* Hack -- Wizards have "perfect telepathy" */
+ if (wizard) flag = TRUE;
+ }
+
+
+ /* The monster is now visible */
+ if (flag)
+ {
+ /* It was previously unseen */
+ if (!m_ptr->ml)
+ {
+ /* Mark as visible */
+ m_ptr->ml = TRUE;
+
+ /* Draw the monster */
+ lite_spot(fy, fx);
+
+ /* Update health bar as needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Update monster list window */
+ p_ptr->window |= (PW_M_LIST);
+
+ /* Hack -- Count "fresh" sightings */
+ if (r_ptr->r_sights < MAX_SHORT) r_ptr->r_sights++;
+
+ /* Disturb on appearance */
+ if (disturb_move)
+ {
+ if (disturb_pets || (is_friend(m_ptr) <= 0)) disturb(1, 0);
+ }
+ }
+
+ /* Apply telepathy */
+ if (hard)
+ {
+ /* Hack -- Memorize mental flags */
+ if (r_ptr->flags2 & (RF2_SMART)) r_ptr->r_flags2 |= (RF2_SMART);
+ if (r_ptr->flags2 & (RF2_STUPID)) r_ptr->r_flags2 |= (RF2_STUPID);
+ }
+
+ /* Memorize various observable flags */
+ if (do_empty_mind) r_ptr->r_flags2 |= (RF2_EMPTY_MIND);
+ if (do_weird_mind) r_ptr->r_flags2 |= (RF2_WEIRD_MIND);
+ if (do_cold_blood) r_ptr->r_flags2 |= (RF2_COLD_BLOOD);
+ if (do_invisible) r_ptr->r_flags2 |= (RF2_INVISIBLE);
+ }
+
+ /* The monster is not visible */
+ else
+ {
+ /* It was previously seen */
+ if (m_ptr->ml)
+ {
+ /* Mark as not visible */
+ m_ptr->ml = FALSE;
+
+ /* Erase the monster */
+ lite_spot(fy, fx);
+
+ /* Update health bar as needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Update monster list window */
+ p_ptr->window |= (PW_M_LIST);
+
+ /* Disturb on disappearance*/
+ if (disturb_move)
+ {
+ if (disturb_pets || (is_friend(m_ptr) <= 0)) disturb(1, 0);
+ }
+ }
+ }
+
+
+ /* The monster is now easily visible */
+ if (easy)
+ {
+
+ if (m_ptr->ml != old_ml)
+ {
+ if (r_ptr->flags2 & RF2_ELDRITCH_HORROR)
+ {
+ sanity_blast(m_ptr, FALSE);
+ }
+ }
+
+ /* Change */
+ if (!(m_ptr->mflag & (MFLAG_VIEW)))
+ {
+ /* Mark as easily visible */
+ m_ptr->mflag |= (MFLAG_VIEW);
+
+ /* Disturb on appearance */
+ if (disturb_near)
+ {
+ if (disturb_pets || (is_friend(m_ptr) <= 0)) disturb(1, 0);
+ }
+
+ }
+ }
+
+ /* The monster is not easily visible */
+ else
+ {
+ /* Change */
+ if (m_ptr->mflag & (MFLAG_VIEW))
+ {
+ /* Mark as not easily visible */
+ m_ptr->mflag &= ~(MFLAG_VIEW);
+
+ /* Update monster list window */
+ p_ptr->window |= (PW_M_LIST);
+
+ /* Disturb on disappearance */
+ if (disturb_near)
+ {
+ if (disturb_pets || (is_friend(m_ptr) <= 0)) disturb(1, 0);
+ }
+ }
+ }
+}
+
+
+
+
+/*
+ * This function simply updates all the (non-dead) monsters (see above).
+ */
+void update_monsters(bool_ full)
+{
+ int i;
+
+ /* Update each (live) monster */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Update the monster */
+ update_mon(i, full);
+ }
+}
+
+
+void monster_carry(monster_type *m_ptr, int m_idx, object_type *q_ptr)
+{
+ object_type *o_ptr;
+
+ /* Get new object */
+ int o_idx = o_pop();
+
+ if (o_idx)
+ {
+ /* Get the item */
+ o_ptr = &o_list[o_idx];
+
+ /* Structure copy */
+ object_copy(o_ptr, q_ptr);
+
+ /* Build a stack */
+ o_ptr->next_o_idx = m_ptr->hold_o_idx;
+
+ o_ptr->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_ptr->hold_o_idx = o_idx;
+ }
+
+ else
+ {
+ /* Hack -- Preserve artifacts */
+ if (q_ptr->name1)
+ {
+ a_info[q_ptr->name1].cur_num = 0;
+ }
+ else if (k_info[q_ptr->k_idx].flags3 & TR3_NORM_ART)
+ {
+ k_info[q_ptr->k_idx].artifact = 0;
+ }
+ else if (q_ptr->tval == TV_RANDART)
+ {
+ random_artifacts[q_ptr->sval].generated = FALSE;
+ }
+ }
+}
+
+
+static int possible_randart[] =
+{
+ TV_MSTAFF,
+ TV_BOOMERANG,
+ TV_DIGGING,
+ TV_HAFTED,
+ TV_POLEARM,
+ TV_AXE,
+ TV_SWORD,
+ TV_BOOTS,
+ TV_GLOVES,
+ TV_HELM,
+ TV_CROWN,
+ TV_SHIELD,
+ TV_CLOAK,
+ TV_SOFT_ARMOR,
+ TV_HARD_ARMOR,
+ TV_LITE,
+ TV_AMULET,
+ TV_RING,
+ -1,
+};
+
+
+bool_ kind_is_randart(int k_idx)
+{
+ int max;
+ object_kind *k_ptr = &k_info[k_idx];
+
+ if (!kind_is_legal(k_idx)) return (FALSE);
+
+ for (max = 0; possible_randart[max] != -1; max++)
+ {
+ if (k_ptr->tval == possible_randart[max]) return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+ * Attempt to place a monster of the given race at the given location.
+ *
+ * To give the player a sporting chance, any monster that appears in
+ * line-of-sight and is extremely dangerous can be marked as
+ * "FORCE_SLEEP", which will cause them to be placed with low energy,
+ * which often (but not always) lets the player move before they do.
+ *
+ * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters.
+ *
+ * XXX XXX XXX Use special "here" and "dead" flags for unique monsters,
+ * remove old "cur_num" and "max_num" fields.
+ *
+ * XXX XXX XXX Actually, do something similar for artifacts, to simplify
+ * the "preserve" mode, and to make the "what artifacts" flag more useful.
+ *
+ * This is the only function which may place a monster in the dungeon,
+ * except for the savefile loading code.
+ */
+bool_ bypass_r_ptr_max_num = FALSE;
+int place_monster_result = 0;
+bool_ place_monster_one_no_drop = FALSE;
+monster_race *place_monster_one_race = NULL;
+s16b place_monster_one(int y, int x, int r_idx, int ego, bool_ slp, int status)
+{
+ int i;
+ char dummy[5];
+ bool_ add_level = FALSE;
+ int min_level = 0, max_level = 0;
+
+ cave_type *c_ptr;
+
+ monster_type *m_ptr;
+
+ monster_race *r_ptr = &r_info[r_idx];
+
+ cptr name = (r_name + r_ptr->name);
+
+ /* Grab the special race if needed */
+ if (place_monster_one_race)
+ {
+ r_ptr = place_monster_one_race;
+ }
+
+ /* DO NOT PLACE A MONSTER IN THE SMALL SCALE WILDERNESS !!! */
+ if (p_ptr->wild_mode)
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Verify location */
+ if (!in_bounds(y, x))
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Require empty space */
+ if (!cave_empty_bold(y, x))
+ {
+ if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster(%d): EMPTY BOLD", r_idx);
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Require no monster free grid, or special permission */
+ if ((cave[y][x].info & CAVE_FREE) && (!m_allow_special[r_idx]))
+ {
+ if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster(%d): CAVE_FREE", r_idx);
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Hack -- no creation on glyph of warding */
+ if (cave[y][x].feat == FEAT_GLYPH)
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+ if (cave[y][x].feat == FEAT_MINOR_GLYPH)
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Nor on the between */
+ if (cave[y][x].feat == FEAT_BETWEEN)
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Nor on the altars */
+ if ((cave[y][x].feat >= FEAT_ALTAR_HEAD)
+ && (cave[y][x].feat <= FEAT_ALTAR_TAIL))
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Nor on the Pattern */
+ if ((cave[y][x].feat >= FEAT_PATTERN_START)
+ && (cave[y][x].feat <= FEAT_PATTERN_XTRA2))
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Paranoia */
+ if (!r_idx)
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Paranoia */
+ if (!r_ptr->name)
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Are we allowed to continue ? */
+ if (process_hooks(HOOK_NEW_MONSTER, "(d)", r_idx))
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Ego Uniques are NOT to be created */
+ if ((r_ptr->flags1 & RF1_UNIQUE) && ego)
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Now could we generate an Ego Monster */
+ /* Grab the special race if needed */
+ if (place_monster_one_race)
+ {
+ r_ptr = place_monster_one_race;
+ }
+ else
+ {
+ r_ptr = race_info_idx(r_idx, ego);
+ }
+
+ if (!monster_can_cross_terrain(cave[y][x].feat, r_ptr))
+ {
+ if (wizard) cmsg_print(TERM_L_RED, "WARNING: Refused monster: cannot cross terrain");
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Unallow some uniques to be generated outside of their quests/special levels/dungeons */
+ if ((r_ptr->flags9 & RF9_SPECIAL_GENE) && (!m_allow_special[r_idx]))
+ {
+ if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster(%d): SPECIAL_GENE", r_idx);
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Disallow Spirits in The Void, now this *IS* an ugly hack, I hate to do it ... */
+ if ((r_ptr->flags7 & RF7_SPIRIT) && (dungeon_type != DUNGEON_VOID))
+ {
+ if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster(%d): SPIRIT in non VOID", r_idx);
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Fully forbid it */
+ if (r_ptr->flags9 & RF9_NEVER_GENE)
+ {
+ if (wizard) cmsg_print(TERM_L_RED, "WARNING: Refused monster: NEVER_GENE");
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Hack -- "unique" monsters must be "unique" */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) && (r_ptr->max_num == -1) && (!m_allow_special[r_idx]))
+ {
+ /* Cannot create */
+ if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster %d: unique not unique", r_idx);
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* The monster is already on an unique level */
+ if (r_ptr->on_saved)
+ {
+ if (wizard) cmsg_print(TERM_L_RED, "WARNING: Refused monster: unique already on saved level");
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Hack -- "unique" monsters must be "unique" */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) && (r_ptr->cur_num >= r_ptr->max_num) && (r_ptr->max_num != -1) && (!bypass_r_ptr_max_num))
+ {
+ /* Cannot create */
+ if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster %d: cur_num >= max_num", r_idx);
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Depth monsters may NOT be created out of depth */
+ if ((r_ptr->flags1 & (RF1_FORCE_DEPTH)) && (dun_level < r_ptr->level))
+ {
+ /* Cannot create */
+ if (wizard) cmsg_print(TERM_L_RED, "WARNING: FORCE_DEPTH");
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+ /* Powerful monster */
+ if (r_ptr->level > dun_level)
+ {
+ /* Unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ /* Message for cheaters */
+ if ((cheat_hear) || (p_ptr->precognition)) msg_format("Deep Unique (%s).", name);
+
+ /* Boost rating by twice delta-depth */
+ rating += (r_ptr->level - dun_level) * 2;
+ }
+
+ /* Normal monsters */
+ else
+ {
+ /* Message for cheaters */
+ if ((cheat_hear) || (p_ptr->precognition)) msg_format("Deep Monster (%s).", name);
+
+ /* Boost rating by delta-depth */
+ rating += (r_ptr->level - dun_level);
+ }
+ }
+
+ /* Note the monster */
+ else if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ /* Unique monsters induce message */
+ if ((cheat_hear) || (p_ptr->precognition)) msg_format("Unique (%s).", name);
+ }
+
+
+ /* Access the location */
+ c_ptr = &cave[y][x];
+
+ /* Make a new monster */
+ c_ptr->m_idx = m_pop();
+ hack_m_idx_ii = c_ptr->m_idx;
+
+ /* Mega-Hack -- catch "failure" */
+ if (!c_ptr->m_idx)
+ {
+ if (place_monster_one_race) KILL(place_monster_one_race, monster_race);
+ return 0;
+ }
+
+
+ /* Get a new monster record */
+ m_ptr = &m_list[c_ptr->m_idx];
+
+ /* Save the race */
+ m_ptr->r_idx = r_idx;
+ m_ptr->ego = ego;
+
+ /* No special, no mind */
+ m_ptr->sr_ptr = place_monster_one_race;
+ m_ptr->mind = NULL;
+
+ /* Place the monster at the location */
+ m_ptr->fy = y;
+ m_ptr->fx = x;
+
+ /* No "damage" yet */
+ m_ptr->stunned = 0;
+ m_ptr->confused = 0;
+ m_ptr->monfear = 0;
+
+ /* No target yet */
+ m_ptr->target = -1;
+
+ /* Unknown distance */
+ m_ptr->cdis = 0;
+
+ /* No flags */
+ m_ptr->mflag = 0;
+
+ /* Not visible */
+ m_ptr->ml = FALSE;
+
+ /* No objects yet */
+ m_ptr->hold_o_idx = 0;
+
+ m_ptr->status = status;
+
+ /* Friendly? */
+ if (m_ptr->status < MSTATUS_FRIEND && r_ptr->flags7 & RF7_PET)
+ {
+ m_ptr->status = MSTATUS_FRIEND;
+ }
+ if (m_ptr->status < MSTATUS_NEUTRAL && r_ptr->flags7 & RF7_NEUTRAL)
+ {
+ m_ptr->status = MSTATUS_NEUTRAL;
+ }
+
+ /* Assume no sleeping */
+ m_ptr->csleep = 0;
+
+ /* Enforce sleeping if needed */
+ if (slp && r_ptr->sleep)
+ {
+ int val = r_ptr->sleep;
+ m_ptr->csleep = ((val * 2) + randint(val * 10));
+ }
+
+ /* Generate the monster's inventory(if any) */
+ /* Only if not fated to die */
+ if ((dungeon_type != DUNGEON_DEATH) && (!place_monster_one_no_drop))
+ {
+ bool_ good = (r_ptr->flags1 & (RF1_DROP_GOOD)) ? TRUE : FALSE;
+ bool_ great = (r_ptr->flags1 & (RF1_DROP_GREAT)) ? TRUE : FALSE;
+
+ bool_ do_gold = (!(r_ptr->flags1 & (RF1_ONLY_ITEM)));
+ bool_ do_item = (!(r_ptr->flags1 & (RF1_ONLY_GOLD)));
+ bool_ do_mimic = (r_ptr->flags9 & (RF9_MIMIC));
+ int j;
+
+ int force_coin = get_coin_type(r_ptr);
+
+ int dump_item = 0;
+ int dump_gold = 0;
+ object_type forge;
+ object_type *q_ptr;
+
+ int number = 0;
+
+ /* Average dungeon and monster levels */
+ object_level = (dun_level + r_ptr->level) / 2;
+
+ /* Determine how much we can drop */
+ if ((r_ptr->flags1 & (RF1_DROP_60)) && (rand_int(100) < 60)) number++;
+ if ((r_ptr->flags1 & (RF1_DROP_90)) && (rand_int(100) < 90)) number++;
+ if (r_ptr->flags1 & (RF1_DROP_1D2)) number += damroll(1, 2);
+ if (r_ptr->flags1 & (RF1_DROP_2D2)) number += damroll(2, 2);
+ if (r_ptr->flags1 & (RF1_DROP_3D2)) number += damroll(3, 2);
+ if (r_ptr->flags1 & (RF1_DROP_4D2)) number += damroll(4, 2);
+ if (r_ptr->flags9 & (RF9_MIMIC)) number = 1;
+
+ /* Hack -- handle creeping coins */
+ coin_type = force_coin;
+
+ if (r_ptr->flags7 & RF7_DROP_RANDART)
+ {
+ int tries = 1000;
+ obj_theme theme;
+ int i;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ theme.treasure = 101;
+ theme.combat = 101;
+ theme.magic = 101;
+ theme.tools = 101;
+
+ init_match_theme(theme);
+
+ /* Apply restriction */
+ get_obj_num_hook = kind_is_legal;
+
+ /* Rebuild allocation table */
+ get_obj_num_prep();
+
+ i = 0;
+ while (tries)
+ {
+ tries--;
+ i = get_obj_num(dun_level);
+ if (!i) continue;
+
+ if (!kind_is_randart(i)) continue;
+ break;
+ }
+
+ /* Invalidate the cached allocation table */
+ alloc_kind_table_valid = FALSE;
+
+ if (tries)
+ {
+ object_prep(q_ptr, i);
+ create_artifact(q_ptr, FALSE, TRUE);
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = m_ptr->r_idx;
+ q_ptr->found_aux2 = m_ptr->ego;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ monster_carry(m_ptr, c_ptr->m_idx, q_ptr);
+ }
+ }
+
+ /* Drop some objects */
+ for (j = 0; j < number; j++)
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Make Gold */
+ if ((!do_mimic) && do_gold && (!do_item || (rand_int(100) < 50)))
+ {
+ /* Make some gold */
+ if (!make_gold(q_ptr)) continue;
+
+ /* XXX XXX XXX */
+ dump_gold++;
+ }
+
+ /* Make Object */
+ else
+ {
+ /* Make an object */
+ if (!do_mimic)
+ {
+ if (!make_object(q_ptr, good, great, r_ptr->drops)) continue;
+ }
+ else
+ {
+ /* Try hard for mimics */
+ int tries = 1000;
+
+ while (tries--)
+ {
+ if (make_object(q_ptr, good, great, r_ptr->drops)) break;
+ }
+ /* BAD */
+ if (!tries) continue;
+ }
+
+ /* XXX XXX XXX */
+ dump_item++;
+ }
+
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = m_ptr->r_idx;
+ q_ptr->found_aux2 = m_ptr->ego;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+ monster_carry(m_ptr, c_ptr->m_idx, q_ptr);
+ }
+
+ /* Reset the object level */
+ object_level = dun_level;
+
+ /* Reset "coin" type */
+ coin_type = 0;
+ }
+ place_monster_one_no_drop = FALSE;
+
+
+ /* Assign maximal hitpoints */
+ if (r_ptr->flags1 & (RF1_FORCE_MAXHP))
+ {
+ m_ptr->maxhp = maxroll(r_ptr->hdice, r_ptr->hside);
+ }
+ else
+ {
+ m_ptr->maxhp = damroll(r_ptr->hdice, r_ptr->hside);
+ }
+
+ /* And start out fully healthy */
+ m_ptr->hp = m_ptr->maxhp;
+
+ /* Some basic info */
+ for (i = 0; i < 4; i++)
+ {
+ m_ptr->blow[i].method = r_ptr->blow[i].method;
+ m_ptr->blow[i].effect = r_ptr->blow[i].effect;
+ m_ptr->blow[i].d_dice = r_ptr->blow[i].d_dice;
+ m_ptr->blow[i].d_side = r_ptr->blow[i].d_side;
+ }
+ m_ptr->ac = r_ptr->ac;
+ m_ptr->level = r_ptr->level;
+ m_ptr->speed = r_ptr->speed;
+ m_ptr->exp = MONSTER_EXP(m_ptr->level);
+
+ /* Extract the monster base speed */
+ m_ptr->mspeed = m_ptr->speed;
+
+ /* Hack -- small racial variety */
+ if (!(r_ptr->flags1 & (RF1_UNIQUE)))
+ {
+ /* Allow some small variation per monster */
+ i = extract_energy[m_ptr->speed] / 10;
+ if (i) m_ptr->mspeed += rand_spread(0, i);
+ }
+
+
+ if (dungeon_flags2 & DF2_ADJUST_LEVEL_1_2)
+ {
+ min_level = max_level = dun_level / 2;
+ add_level = TRUE;
+ }
+ if (dungeon_flags1 & DF1_ADJUST_LEVEL_1)
+ {
+ if (!min_level) min_level = dun_level;
+ max_level = dun_level;
+ add_level = TRUE;
+ }
+ if (dungeon_flags1 & DF1_ADJUST_LEVEL_2)
+ {
+ if (!min_level) min_level = dun_level * 2;
+ max_level = dun_level * 2;
+ add_level = TRUE;
+ }
+ if (add_level) monster_set_level(c_ptr->m_idx, rand_range(min_level, max_level));
+
+ /* Give a random starting energy */
+ m_ptr->energy = (byte)rand_int(100);
+
+ /* Force monster to wait for player */
+ if (r_ptr->flags1 & (RF1_FORCE_SLEEP))
+ {
+ /* Monster is still being nice */
+ m_ptr->mflag |= (MFLAG_NICE);
+
+ /* Must repair monsters */
+ repair_monsters = TRUE;
+ }
+
+ /* Hack -- see "process_monsters()" */
+ if (c_ptr->m_idx < hack_m_idx)
+ {
+ /* Monster is still being born */
+ m_ptr->mflag |= (MFLAG_BORN);
+ }
+
+
+ /* Update the monster */
+ update_mon(c_ptr->m_idx, TRUE);
+
+
+ /* Hack -- Count the number of "reproducers" */
+ if (r_ptr->flags4 & (RF4_MULTIPLY)) num_repro++;
+
+
+ /* Hack -- Notice new multi-hued monsters */
+ if (r_ptr->flags1 & (RF1_ATTR_MULTI)) shimmer_monsters = TRUE;
+
+ /* Hack -- we need to modify the REAL r_info, not the fake one */
+ r_ptr = &r_info[r_idx];
+
+ /* Hack -- Count the monsters on the level */
+ r_ptr->cur_num++;
+
+ /* Unique monsters on saved levels should be "marked" */
+ if ((r_ptr->flags1 & RF1_UNIQUE) && get_dungeon_save(dummy))
+ {
+ r_ptr->on_saved = TRUE;
+ }
+
+ place_monster_one_race = NULL;
+
+ /* Success */
+ place_monster_result = c_ptr->m_idx;
+ return c_ptr->m_idx;
+}
+
+/*
+ * Maximum size of a group of monsters
+ */
+#define GROUP_MAX 32
+
+
+/*
+ * Attempt to place a "group" of monsters around the given location
+ */
+static bool_ place_monster_group(int y, int x, int r_idx, bool_ slp, int status)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ int old, n, i;
+ int total = 0, extra = 0;
+
+ int hack_n = 0;
+
+ byte hack_y[GROUP_MAX];
+ byte hack_x[GROUP_MAX];
+
+
+ /* Pick a group size */
+ total = randint(13);
+
+ /* Hard monsters, small groups */
+ if (r_ptr->level > dun_level)
+ {
+ extra = r_ptr->level - dun_level;
+ extra = 0 - randint(extra);
+ }
+
+ /* Easy monsters, large groups */
+ else if (r_ptr->level < dun_level)
+ {
+ extra = dun_level - r_ptr->level;
+ extra = randint(extra);
+ }
+
+ /* Hack -- limit group reduction */
+ if (extra > 12) extra = 12;
+
+ /* Modify the group size */
+ total += extra;
+
+ /* Minimum size */
+ if (total < 1) total = 1;
+
+ /* Maximum size */
+ if (total > GROUP_MAX) total = GROUP_MAX;
+
+
+ /* Save the rating */
+ old = rating;
+
+ /* Start on the monster */
+ hack_n = 1;
+ hack_x[0] = x;
+ hack_y[0] = y;
+
+ /* Puddle monsters, breadth first, up to total */
+ for (n = 0; (n < hack_n) && (hack_n < total); n++)
+ {
+ /* Grab the location */
+ int hx = hack_x[n];
+ int hy = hack_y[n];
+
+ /* Check each direction, up to total */
+ for (i = 0; (i < 8) && (hack_n < total); i++)
+ {
+ int mx = hx + ddx_ddd[i];
+ int my = hy + ddy_ddd[i];
+
+ /* Walls and Monsters block flow */
+ if (!cave_empty_bold(my, mx)) continue;
+
+ /* Attempt to place another monster */
+ if (place_monster_one(my, mx, r_idx, pick_ego_monster(r_idx), slp, status))
+ {
+ /* Add it to the "hack" set */
+ hack_y[hack_n] = my;
+ hack_x[hack_n] = mx;
+ hack_n++;
+ }
+ }
+ }
+
+ /* Hack -- restore the rating */
+ rating = old;
+
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Hack -- help pick an escort type
+ */
+static int place_monster_idx = 0;
+
+/*
+ * Hack -- help pick an escort type
+ */
+static bool_ place_monster_okay(int r_idx)
+{
+ monster_race *r_ptr = &r_info[place_monster_idx];
+
+ monster_race *z_ptr = &r_info[r_idx];
+
+ /* Hack - Escorts have to have the same dungeon flag */
+ if (monster_dungeon(place_monster_idx) != monster_dungeon(r_idx)) return (FALSE);
+
+ /* Require similar "race" */
+ if (z_ptr->d_char != r_ptr->d_char) return (FALSE);
+
+ /* Skip more advanced monsters */
+ if (z_ptr->level > r_ptr->level) return (FALSE);
+
+ /* Skip unique monsters */
+ if (z_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Paranoia -- Skip identical monsters */
+ if (place_monster_idx == r_idx) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Attempt to place a monster of the given race at the given location
+ *
+ * Note that certain monsters are now marked as requiring "friends".
+ * These monsters, if successfully placed, and if the "grp" parameter
+ * is TRUE, will be surrounded by a "group" of identical monsters.
+ *
+ * Note that certain monsters are now marked as requiring an "escort",
+ * which is a collection of monsters with similar "race" but lower level.
+ *
+ * Some monsters induce a fake "group" flag on their escorts.
+ *
+ * Note the "bizarre" use of non-recursion to prevent annoying output
+ * when running a code profiler.
+ *
+ * Note the use of the new "monster allocation table" code to restrict
+ * the "get_mon_num()" function to "legal" escort types.
+ */
+bool_ place_monster_aux(int y, int x, int r_idx, bool_ slp, bool_ grp, int status)
+{
+ int i;
+ monster_race *r_ptr = &r_info[r_idx];
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+
+
+ /* Place one monster, or fail */
+ if (!place_monster_one(y, x, r_idx, pick_ego_monster(r_idx), slp, status)) return (FALSE);
+
+
+ /* Require the "group" flag */
+ if (!grp) return (TRUE);
+
+
+ /* Friends for certain monsters */
+ if (r_ptr->flags1 & (RF1_FRIENDS))
+ {
+ /* Attempt to place a group */
+ (void)place_monster_group(y, x, r_idx, slp, status);
+ }
+
+
+ /* Escorts for certain monsters */
+ if (r_ptr->flags1 & (RF1_ESCORT))
+ {
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ /* Set the escort index */
+ place_monster_idx = r_idx;
+
+ /* Set the escort hook */
+ get_mon_num_hook = place_monster_okay;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Try to place several "escorts" */
+ for (i = 0; i < 50; i++)
+ {
+ int nx, ny, z, d = 3;
+
+ /* Pick a location */
+ scatter(&ny, &nx, y, x, d);
+
+ /* Require empty grids */
+ if (!cave_empty_bold(ny, nx)) continue;
+
+ set_mon_num2_hook(ny, nx);
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Pick a random race */
+ z = get_mon_num(r_ptr->level);
+
+ /* Reset restriction */
+ get_mon_num2_hook = NULL;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Handle failure */
+ if (!z) break;
+
+ /* Place a single escort */
+ place_monster_one(ny, nx, z, pick_ego_monster(z), slp, status);
+
+ /* Place a "group" of escorts if needed */
+ if ((r_info[z].flags1 & (RF1_FRIENDS)) ||
+ (r_ptr->flags1 & (RF1_ESCORTS)))
+ {
+ /* Place a group of monsters */
+ (void)place_monster_group(ny, nx, z, slp, status);
+ }
+ }
+
+ /* Reset restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Hack -- attempt to place a monster at the given location
+ *
+ * Attempt to find a monster appropriate to the "monster_level"
+ */
+bool_ place_monster(int y, int x, bool_ slp, bool_ grp)
+{
+ int r_idx;
+
+ /* Set monster restriction */
+ set_mon_num2_hook(y, x);
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Pick a monster */
+ r_idx = get_mon_num(monster_level);
+
+ /* Reset restriction */
+ get_mon_num2_hook = NULL;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Handle failure */
+ if (!r_idx) return (FALSE);
+
+ /* Attempt to place the monster */
+ if (place_monster_aux(y, x, r_idx, slp, grp, MSTATUS_ENEMY)) return (TRUE);
+
+ /* Oops */
+ return (FALSE);
+}
+
+
+#ifdef MONSTER_HORDES
+
+bool_ alloc_horde(int y, int x)
+{
+ int r_idx = 0;
+ monster_race * r_ptr = NULL;
+ monster_type * m_ptr;
+ int attempts = 1000;
+
+ set_mon_num2_hook(y, x);
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ while (--attempts)
+ {
+ /* Pick a monster */
+ r_idx = get_mon_num(monster_level);
+
+ /* Handle failure */
+ if (!r_idx) return (FALSE);
+
+ r_ptr = &r_info[r_idx];
+
+ if (!(r_ptr->flags1 & (RF1_UNIQUE))
+ && !(r_ptr->flags1 & (RF1_ESCORTS)))
+ break;
+ }
+
+ get_mon_num2_hook = NULL;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ if (attempts < 1) return FALSE;
+
+ attempts = 1000;
+
+ while (--attempts)
+ {
+ /* Attempt to place the monster */
+ if (place_monster_aux(y, x, r_idx, FALSE, FALSE, MSTATUS_ENEMY)) break;
+ }
+
+ if (attempts < 1) return FALSE;
+
+
+ m_ptr = &m_list[hack_m_idx_ii];
+
+ summon_kin_type = r_ptr->d_char;
+
+ for (attempts = randint(10) + 5; attempts; attempts--)
+ {
+ (void) summon_specific(m_ptr->fy, m_ptr->fx, dun_level, SUMMON_KIN);
+ }
+
+ return TRUE;
+}
+
+#endif /* MONSTER_HORDES */
+
+/*
+ * Attempt to allocate a random monster in the dungeon.
+ *
+ * Place the monster at least "dis" distance from the player.
+ *
+ * Use "slp" to choose the initial "sleep" status
+ *
+ * Use "monster_level" for the monster level
+ */
+bool_ alloc_monster(int dis, bool_ slp)
+{
+ int y, x;
+ int attempts_left = 10000;
+
+ /* Find a legal, distant, unoccupied, space */
+ while (attempts_left--)
+ {
+ /* Pick a location */
+ y = rand_int(cur_hgt);
+ x = rand_int(cur_wid);
+
+ /* Require empty floor grid (was "naked") */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Accept far away grids */
+ if (distance(y, x, p_ptr->py, p_ptr->px) > dis) break;
+ }
+
+ if (!attempts_left)
+ {
+ if (cheat_xtra || cheat_hear)
+ {
+ msg_print("Warning! Could not allocate a new monster. Small level?");
+ }
+
+ return (FALSE);
+ }
+
+
+#ifdef MONSTER_HORDES
+ if (randint(5000) <= dun_level)
+ {
+ if (alloc_horde(y, x))
+ {
+ if ((cheat_hear) || (p_ptr->precognition)) msg_print("Monster horde.");
+ return (TRUE);
+ }
+ }
+ else
+ {
+#endif /* MONSTER_HORDES */
+
+ /* Attempt to place the monster, allow groups */
+ if (place_monster(y, x, slp, TRUE)) return (TRUE);
+
+#ifdef MONSTER_HORDES
+ }
+#endif /* MONSTER_HORDES */
+
+ /* Nope */
+ return (FALSE);
+}
+
+
+
+
+/*
+ * Hack -- the "type" of the current "summon specific"
+ */
+static int summon_specific_type = 0;
+
+
+/*
+ * Hack -- help decide if a monster race is "okay" to summon
+ */
+bool_ summon_specific_okay(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ bool_ okay = FALSE;
+
+ /* Hack - Only summon dungeon monsters */
+ if (!monster_dungeon(r_idx)) return (FALSE);
+
+ /* Hack -- no specific type specified */
+ if (!summon_specific_type) return (TRUE);
+
+ /* Check our requirements */
+ switch (summon_specific_type)
+ {
+ case SUMMON_ANT:
+ {
+ okay = ((r_ptr->d_char == 'a') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_SPIDER:
+ {
+ okay = ((r_ptr->d_char == 'S') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_HOUND:
+ {
+ okay = (((r_ptr->d_char == 'C') || (r_ptr->d_char == 'Z')) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_HYDRA:
+ {
+ okay = ((r_ptr->d_char == 'M') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_ANGEL:
+ {
+ okay = ((r_ptr->d_char == 'A') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_DEMON:
+ {
+ okay = ((r_ptr->flags3 & (RF3_DEMON)) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_UNDEAD:
+ {
+ okay = ((r_ptr->flags3 & (RF3_UNDEAD)) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_DRAGON:
+ {
+ okay = ((r_ptr->flags3 & (RF3_DRAGON)) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_HI_UNDEAD:
+ {
+ okay = ((r_ptr->d_char == 'L') ||
+ (r_ptr->d_char == 'V') ||
+ (r_ptr->d_char == 'W'));
+ break;
+ }
+
+ case SUMMON_HI_DRAGON:
+ {
+ okay = (r_ptr->d_char == 'D');
+ break;
+ }
+
+ case SUMMON_WRAITH:
+ {
+ okay = (r_ptr->d_char == 'W');
+ break;
+ }
+
+ case SUMMON_GHOST:
+ {
+ okay = (r_ptr->d_char == 'G');
+ break;
+ }
+
+ case SUMMON_UNIQUE:
+ {
+ okay = (r_ptr->flags1 & (RF1_UNIQUE)) ? TRUE : FALSE;
+ break;
+ }
+
+ case SUMMON_BIZARRE1:
+ {
+ okay = ((r_ptr->d_char == 'm') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+ case SUMMON_BIZARRE2:
+ {
+ okay = ((r_ptr->d_char == 'b') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+ case SUMMON_BIZARRE3:
+ {
+ okay = ((r_ptr->d_char == 'Q') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_BIZARRE4:
+ {
+ okay = ((r_ptr->d_char == 'v') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_BIZARRE5:
+ {
+ okay = ((r_ptr->d_char == '$') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_BIZARRE6:
+ {
+ okay = (((r_ptr->d_char == '!') ||
+ (r_ptr->d_char == '?') ||
+ (r_ptr->d_char == '=') ||
+ (r_ptr->d_char == '$') ||
+ (r_ptr->d_char == '|')) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_HI_DEMON:
+ {
+ okay = ((r_ptr->flags3 & (RF3_DEMON)) &&
+ (r_ptr->d_char == 'U') &&
+ !(r_ptr->flags1 & RF1_UNIQUE));
+ break;
+ }
+
+
+ case SUMMON_KIN:
+ {
+ okay = ((r_ptr->d_char == summon_kin_type) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_DAWN:
+ {
+ okay = ((strstr((r_name + r_ptr->name), "the Dawn")) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_ANIMAL:
+ {
+ okay = ((r_ptr->flags3 & (RF3_ANIMAL)) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_ANIMAL_RANGER:
+ {
+ okay = ((r_ptr->flags3 & (RF3_ANIMAL)) &&
+ (strchr("abcflqrwBCIJKMRS", r_ptr->d_char)) &&
+ !(r_ptr->flags3 & (RF3_DRAGON)) &&
+ !(r_ptr->flags3 & (RF3_EVIL)) &&
+ !(r_ptr->flags3 & (RF3_UNDEAD)) &&
+ !(r_ptr->flags3 & (RF3_DEMON)) &&
+ !(r_ptr->flags4 || r_ptr->flags5 || r_ptr->flags6) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_HI_UNDEAD_NO_UNIQUES:
+ {
+ okay = (((r_ptr->d_char == 'L') ||
+ (r_ptr->d_char == 'V') ||
+ (r_ptr->d_char == 'W')) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_HI_DRAGON_NO_UNIQUES:
+ {
+ okay = ((r_ptr->d_char == 'D') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_NO_UNIQUES:
+ {
+ okay = (!(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_PHANTOM:
+ {
+ okay = ((strstr((r_name + r_ptr->name), "Phantom")) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_ELEMENTAL:
+ {
+ okay = ((strstr((r_name + r_ptr->name), "lemental")) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_THUNDERLORD:
+ {
+ okay = (r_ptr->flags3 & RF3_THUNDERLORD) ? TRUE : FALSE;
+ break;
+ }
+
+ case SUMMON_BLUE_HORROR:
+ {
+ okay = ((strstr((r_name + r_ptr->name), "lue horror")) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_BUG:
+ {
+ okay = ((strstr((r_name + r_ptr->name), "Software bug")) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_RNG:
+ {
+ okay = ((strstr((r_name + r_ptr->name), "Random Number Generator")) &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+ case SUMMON_MINE:
+ {
+ okay = (r_ptr->flags1 & RF1_NEVER_MOVE) ? TRUE : FALSE;
+ break;
+ }
+
+ case SUMMON_HUMAN:
+ {
+ okay = ((r_ptr->d_char == 'p') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_SHADOWS:
+ {
+ okay = ((r_ptr->d_char == 'G') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_QUYLTHULG:
+ {
+ okay = ((r_ptr->d_char == 'Q') &&
+ !(r_ptr->flags1 & (RF1_UNIQUE)));
+ break;
+ }
+
+ case SUMMON_LUA:
+ {
+ okay = summon_lua_okay(r_idx);
+ break;
+ }
+ }
+
+ /* Result */
+ return (okay);
+}
+
+
+/*
+ * Place a monster (of the specified "type") near the given
+ * location. Return TRUE if a monster was actually summoned.
+ *
+ * We will attempt to place the monster up to 10 times before giving up.
+ *
+ * Note: SUMMON_UNIQUE and SUMMON_WRAITH (XXX) will summon Unique's
+ * Note: SUMMON_HI_UNDEAD and SUMMON_HI_DRAGON may summon Unique's
+ * Note: None of the other summon codes will ever summon Unique's.
+ *
+ * This function has been changed. We now take the "monster level"
+ * of the summoning monster as a parameter, and use that, along with
+ * the current dungeon level, to help determine the level of the
+ * desired monster. Note that this is an upper bound, and also
+ * tends to "prefer" monsters of that level. Currently, we use
+ * the average of the dungeon and monster levels, and then add
+ * five to allow slight increases in monster power.
+ *
+ * Note that we use the new "monster allocation table" creation code
+ * to restrict the "get_mon_num()" function to the set of "legal"
+ * monsters, making this function much faster and more reliable.
+ *
+ * Note that this function may not succeed, though this is very rare.
+ */
+int summon_specific_level = 0;
+bool_ summon_specific(int y1, int x1, int lev, int type)
+{
+ int i, x, y, r_idx;
+ bool_ Group_ok = TRUE;
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+
+ /* Look for a location */
+ for (i = 0; i < 20; ++i)
+ {
+ /* Pick a distance */
+ int d = (i / 15) + 1;
+
+ /* Pick a location */
+ scatter(&y, &x, y1, x1, d);
+
+ /* Require "empty" floor grid */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Hack -- no summon on glyph of warding */
+ if (cave[y][x].feat == FEAT_GLYPH) continue;
+ if (cave[y][x].feat == FEAT_MINOR_GLYPH) continue;
+
+ /* Nor on the between */
+ if (cave[y][x].feat == FEAT_BETWEEN) return (FALSE);
+
+ /* ... nor on the Pattern */
+ if ((cave[y][x].feat >= FEAT_PATTERN_START) &&
+ (cave[y][x].feat <= FEAT_PATTERN_XTRA2))
+ continue;
+
+ /* Okay */
+ break;
+ }
+
+ /* Failure */
+ if (i == 20) return (FALSE);
+
+ /* Save the "summon" type */
+ summon_specific_type = type;
+
+ /* Backup the old hook */
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ /* Require "okay" monsters */
+ get_mon_num_hook = summon_specific_okay;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+
+ /* Pick a monster, using the level calculation */
+ summon_hack = TRUE;
+ r_idx = get_mon_num((dun_level + lev) / 2 + 5);
+ summon_hack = FALSE;
+
+#ifdef R_IDX_TESTING_HACK
+ r_idx = 356;
+#endif
+
+ /* Reset restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+
+ /* Handle failure */
+ if (!r_idx) return (FALSE);
+
+
+ if ((type == SUMMON_DAWN) || (type == SUMMON_BLUE_HORROR))
+ {
+ Group_ok = FALSE;
+ }
+
+ /* Attempt to place the monster (awake, allow groups) */
+ if (!place_monster_aux(y, x, r_idx, FALSE, Group_ok, MSTATUS_ENEMY)) return (FALSE);
+ if (summon_specific_level)
+ {
+ monster_set_level(place_monster_result, summon_specific_level);
+ summon_specific_level = 0;
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+
+bool_ summon_specific_friendly(int y1, int x1, int lev, int type, bool_ Group_ok)
+{
+ int i, x, y, r_idx;
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+
+ /* Look for a location */
+ for (i = 0; i < 20; ++i)
+ {
+ /* Pick a distance */
+ int d = (i / 15) + 1;
+
+ /* Pick a location */
+ scatter(&y, &x, y1, x1, d);
+
+ /* Require "empty" floor grid */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Hack -- no summon on glyph of warding */
+ if (cave[y][x].feat == FEAT_GLYPH) continue;
+ if (cave[y][x].feat == FEAT_MINOR_GLYPH) continue;
+
+ /* Nor on the between */
+ if (cave[y][x].feat == FEAT_BETWEEN) return (FALSE);
+
+ /* ... nor on the Pattern */
+ if ((cave[y][x].feat >= FEAT_PATTERN_START) &&
+ (cave[y][x].feat <= FEAT_PATTERN_XTRA2))
+ continue;
+
+ /* Okay */
+ break;
+ }
+
+ /* Failure */
+ if (i == 20) return (FALSE);
+
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ /* Save the "summon" type */
+ summon_specific_type = type;
+
+ /* Require "okay" monsters */
+ get_mon_num_hook = summon_specific_okay;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Pick a monster, using the level calculation */
+ r_idx = get_mon_num((dun_level + lev) / 2 + 5);
+
+#ifdef R_IDX_TESTING_HACK
+ r_idx = 356;
+#endif
+
+ /* Reset restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Handle failure */
+ if (!r_idx) return (FALSE);
+
+ /* Attempt to place the monster (awake, allow groups) */
+ if (!place_monster_aux(y, x, r_idx, FALSE, Group_ok, MSTATUS_PET)) return (FALSE);
+ if (summon_specific_level)
+ {
+ monster_set_level(place_monster_result, summon_specific_level);
+ summon_specific_level = 0;
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Swap the players/monsters (if any) at two locations XXX XXX XXX
+ */
+void monster_swap(int y1, int x1, int y2, int x2)
+{
+ int m1, m2;
+
+ monster_type *m_ptr;
+ cave_type *c_ptr1, *c_ptr2;
+
+ c_ptr1 = &cave[y1][x1];
+ c_ptr2 = &cave[y2][x2];
+
+ /* Monsters */
+ m1 = c_ptr1->m_idx;
+ m2 = c_ptr2->m_idx;
+
+
+ /* Update grids */
+ c_ptr1->m_idx = m2;
+ c_ptr2->m_idx = m1;
+
+
+ /* Monster 1 */
+ if (m1 > 0)
+ {
+ m_ptr = &m_list[m1];
+
+ /* Move monster */
+ m_ptr->fy = y2;
+ m_ptr->fx = x2;
+
+ /* Update monster */
+ update_mon(m1, TRUE);
+ }
+
+ /* Player 1 */
+ else if (m1 < 0)
+ {
+ /* Move player */
+ p_ptr->py = y2;
+ p_ptr->px = x2;
+
+ /* Check for new panel (redraw map) */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Window stuff */
+ /* It's probably not a good idea to recalculate the
+ * overhead view each turn.
+
+ p_ptr->window |= (PW_OVERHEAD);
+ */
+ }
+
+ /* Monster 2 */
+ if (m2 > 0)
+ {
+ m_ptr = &m_list[m2];
+
+ /* Move monster */
+ m_ptr->fy = y1;
+ m_ptr->fx = x1;
+
+ /* Update monster */
+ update_mon(m2, TRUE);
+ }
+
+ /* Player 2 */
+ else if (m2 > 0)
+ {
+ /* Move player */
+ p_ptr->py = y1;
+ p_ptr->px = x1;
+
+ /* Check for new panel (redraw map) */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Window stuff */
+ /* It's probably not a good idea to recalculate the
+ * overhead view each turn.
+
+ p_ptr->window |= (PW_OVERHEAD);
+ */
+ }
+
+
+ /* Redraw */
+ lite_spot(y1, x1);
+ lite_spot(y2, x2);
+}
+
+
+/*
+ * Hack -- help decide if a monster race is "okay" to summon
+ */
+static bool_ mutate_monster_okay(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ bool_ okay = FALSE;
+
+ /* Hack - Only summon dungeon monsters */
+ if (!monster_dungeon(r_idx)) return (FALSE);
+
+ okay = ((r_ptr->d_char == summon_kin_type) && !(r_ptr->flags1 & (RF1_UNIQUE))
+ && (r_ptr->level >= dun_level));
+
+ return okay;
+}
+
+
+/*
+ * Let the given monster attempt to reproduce.
+ *
+ * Note that "reproduction" REQUIRES empty space.
+ */
+bool_ multiply_monster(int m_idx, bool_ charm, bool_ clone)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ int i, y, x, new_race;
+
+ bool_ result = FALSE;
+
+ if (no_breeds)
+ {
+ msg_print("It tries to breed but it fails!");
+ return FALSE;
+ }
+
+ /* Try up to 18 times */
+ for (i = 0; i < 18; i++)
+ {
+ int d = 1;
+
+
+ /* Pick a location */
+ scatter(&y, &x, m_ptr->fy, m_ptr->fx, d);
+
+ /* Require an "empty" floor grid */
+ if (!cave_empty_bold(y, x)) continue;
+
+ new_race = m_ptr->r_idx;
+
+ /* It can mutate into a nastier monster */
+ if ((rand_int(100) < 3) && (!clone))
+ {
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+
+ /* Backup the old hook */
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ /* Require "okay" monsters */
+ get_mon_num_hook = mutate_monster_okay;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ summon_kin_type = r_ptr->d_char;
+
+ /* Pick a monster, using the level calculation */
+ new_race = get_mon_num(dun_level + 5);
+
+ /* Reset restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+ }
+
+ /* Create a new monster (awake, no groups) */
+ result = place_monster_aux(y, x, new_race, FALSE, FALSE, (charm) ? MSTATUS_PET : MSTATUS_ENEMY);
+
+ /* Done */
+ break;
+ }
+
+ if (clone && result) m_list[hack_m_idx_ii].smart |= SM_CLONED;
+
+ /* Result */
+ return (result);
+}
+
+
+
+
+
+/*
+ * Dump a message describing a monster's reaction to damage
+ *
+ * Technically should attempt to treat "Beholder"'s as jelly's
+ */
+bool_ hack_message_pain_may_silent = FALSE;
+void message_pain_hook(cptr fmt, ...)
+{
+ va_list vp;
+
+ char buf[1024];
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Format the args, save the length */
+ (void)vstrnfmt(buf, 1024, fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ if (hack_message_pain_may_silent)
+ monster_msg(buf);
+ else
+ msg_print(buf);
+}
+
+void message_pain(int m_idx, int dam)
+{
+ long oldhp, newhp, tmp;
+ int percentage;
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+ char m_name[80];
+
+ /* Get the monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Notice non-damage */
+ if (dam == 0)
+ {
+ message_pain_hook("%^s is unharmed.", m_name);
+ return;
+ }
+
+ /* Note -- subtle fix -CFT */
+ newhp = (long)(m_ptr->hp);
+ oldhp = newhp + (long)(dam);
+ tmp = (newhp * 100L) / oldhp;
+ percentage = (int)(tmp);
+
+
+ /* Jelly's, Mold's, Vortex's, Quthl's */
+ if (strchr("jmvQ", r_ptr->d_char))
+ {
+ if (percentage > 95)
+ message_pain_hook("%^s barely notices.", m_name);
+ else if (percentage > 75)
+ message_pain_hook("%^s flinches.", m_name);
+ else if (percentage > 50)
+ message_pain_hook("%^s squelches.", m_name);
+ else if (percentage > 35)
+ message_pain_hook("%^s quivers in pain.", m_name);
+ else if (percentage > 20)
+ message_pain_hook("%^s writhes about.", m_name);
+ else if (percentage > 10)
+ message_pain_hook("%^s writhes in agony.", m_name);
+ else
+ message_pain_hook("%^s jerks limply.", m_name);
+ }
+
+ /* Dogs and Hounds */
+ else if (strchr("CZ", r_ptr->d_char))
+ {
+ if (percentage > 95)
+ message_pain_hook("%^s shrugs off the attack.", m_name);
+ else if (percentage > 75)
+ message_pain_hook("%^s snarls with pain.", m_name);
+ else if (percentage > 50)
+ message_pain_hook("%^s yelps in pain.", m_name);
+ else if (percentage > 35)
+ message_pain_hook("%^s howls in pain.", m_name);
+ else if (percentage > 20)
+ message_pain_hook("%^s howls in agony.", m_name);
+ else if (percentage > 10)
+ message_pain_hook("%^s writhes in agony.", m_name);
+ else
+ message_pain_hook("%^s yelps feebly.", m_name);
+ }
+
+ /* One type of monsters (ignore,squeal,shriek) */
+ else if (strchr("FIKMRSXabclqrst", r_ptr->d_char))
+ {
+ if (percentage > 95)
+ message_pain_hook("%^s ignores the attack.", m_name);
+ else if (percentage > 75)
+ message_pain_hook("%^s grunts with pain.", m_name);
+ else if (percentage > 50)
+ message_pain_hook("%^s squeals in pain.", m_name);
+ else if (percentage > 35)
+ message_pain_hook("%^s shrieks in pain.", m_name);
+ else if (percentage > 20)
+ message_pain_hook("%^s shrieks in agony.", m_name);
+ else if (percentage > 10)
+ message_pain_hook("%^s writhes in agony.", m_name);
+ else
+ message_pain_hook("%^s cries out feebly.", m_name);
+ }
+
+ /* Another type of monsters (shrug,cry,scream) */
+ else
+ {
+ if (percentage > 95)
+ message_pain_hook("%^s shrugs off the attack.", m_name);
+ else if (percentage > 75)
+ message_pain_hook("%^s grunts with pain.", m_name);
+ else if (percentage > 50)
+ message_pain_hook("%^s cries out in pain.", m_name);
+ else if (percentage > 35)
+ message_pain_hook("%^s screams in pain.", m_name);
+ else if (percentage > 20)
+ message_pain_hook("%^s screams in agony.", m_name);
+ else if (percentage > 10)
+ message_pain_hook("%^s writhes in agony.", m_name);
+ else
+ message_pain_hook("%^s cries out feebly.", m_name);
+ }
+}
+
+
+
+/*
+ * Learn about an "observed" resistance.
+ */
+void update_smart_learn(int m_idx, int what)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+
+ /* Not allowed to learn */
+ if (!smart_learn) return;
+
+ /* Too stupid to learn anything */
+ if (r_ptr->flags2 & (RF2_STUPID)) return;
+
+ /* Not intelligent, only learn sometimes */
+ if (!(r_ptr->flags2 & (RF2_SMART)) && (rand_int(100) < 50)) return;
+
+
+ /* XXX XXX XXX */
+
+ /* Analyze the knowledge */
+ switch (what)
+ {
+ case DRS_ACID:
+ if (p_ptr->resist_acid) m_ptr->smart |= (SM_RES_ACID);
+ if (p_ptr->oppose_acid) m_ptr->smart |= (SM_OPP_ACID);
+ if (p_ptr->immune_acid) m_ptr->smart |= (SM_IMM_ACID);
+ break;
+
+ case DRS_ELEC:
+ if (p_ptr->resist_elec) m_ptr->smart |= (SM_RES_ELEC);
+ if (p_ptr->oppose_elec) m_ptr->smart |= (SM_OPP_ELEC);
+ if (p_ptr->immune_elec) m_ptr->smart |= (SM_IMM_ELEC);
+ break;
+
+ case DRS_FIRE:
+ if (p_ptr->resist_fire) m_ptr->smart |= (SM_RES_FIRE);
+ if (p_ptr->oppose_fire) m_ptr->smart |= (SM_OPP_FIRE);
+ if (p_ptr->immune_fire) m_ptr->smart |= (SM_IMM_FIRE);
+ break;
+
+ case DRS_COLD:
+ if (p_ptr->resist_cold) m_ptr->smart |= (SM_RES_COLD);
+ if (p_ptr->oppose_cold) m_ptr->smart |= (SM_OPP_COLD);
+ if (p_ptr->immune_cold) m_ptr->smart |= (SM_IMM_COLD);
+ break;
+
+ case DRS_POIS:
+ if (p_ptr->resist_pois) m_ptr->smart |= (SM_RES_POIS);
+ if (p_ptr->oppose_pois) m_ptr->smart |= (SM_OPP_POIS);
+ break;
+
+
+ case DRS_NETH:
+ if (p_ptr->resist_neth) m_ptr->smart |= (SM_RES_NETH);
+ break;
+
+ case DRS_LITE:
+ if (p_ptr->resist_lite) m_ptr->smart |= (SM_RES_LITE);
+ break;
+
+ case DRS_DARK:
+ if (p_ptr->resist_dark) m_ptr->smart |= (SM_RES_DARK);
+ break;
+
+ case DRS_FEAR:
+ if (p_ptr->resist_fear) m_ptr->smart |= (SM_RES_FEAR);
+ break;
+
+ case DRS_CONF:
+ if (p_ptr->resist_conf) m_ptr->smart |= (SM_RES_CONF);
+ break;
+
+ case DRS_CHAOS:
+ if (p_ptr->resist_chaos) m_ptr->smart |= (SM_RES_CHAOS);
+ break;
+
+ case DRS_DISEN:
+ if (p_ptr->resist_disen) m_ptr->smart |= (SM_RES_DISEN);
+ break;
+
+ case DRS_BLIND:
+ if (p_ptr->resist_blind) m_ptr->smart |= (SM_RES_BLIND);
+ break;
+
+ case DRS_NEXUS:
+ if (p_ptr->resist_nexus) m_ptr->smart |= (SM_RES_NEXUS);
+ break;
+
+ case DRS_SOUND:
+ if (p_ptr->resist_sound) m_ptr->smart |= (SM_RES_SOUND);
+ break;
+
+ case DRS_SHARD:
+ if (p_ptr->resist_shard) m_ptr->smart |= (SM_RES_SHARD);
+ break;
+
+
+ case DRS_FREE:
+ if (p_ptr->free_act) m_ptr->smart |= (SM_IMM_FREE);
+ break;
+
+ case DRS_MANA:
+ if (!p_ptr->msp) m_ptr->smart |= (SM_IMM_MANA);
+ break;
+
+ case DRS_REFLECT:
+ if (p_ptr->reflect) m_ptr-> smart |= (SM_IMM_REFLECT);
+ break;
+ }
+}
+
+
+/*
+ * Place the player in the dungeon XXX XXX
+ */
+s16b player_place(int y, int x)
+{
+ /* Paranoia XXX XXX */
+ if (cave[y][x].m_idx != 0) return (0);
+
+ /* Save player location */
+ p_ptr->py = y;
+ p_ptr->px = x;
+
+ /* Success */
+ return ( -1);
+}
+
+/*
+ * Drop all items carried by a monster
+ */
+void monster_drop_carried_objects(monster_type *m_ptr)
+{
+ s16b this_o_idx, next_o_idx = 0;
+ object_type forge;
+ object_type *o_ptr;
+ object_type *q_ptr;
+
+
+ /* Drop objects being carried */
+ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Paranoia */
+ o_ptr->held_m_idx = 0;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Copy the object */
+ object_copy(q_ptr, o_ptr);
+
+ /* Delete the object */
+ delete_object_idx(this_o_idx);
+
+ /* Drop it */
+ drop_near(q_ptr, -1, m_ptr->fy, m_ptr->fx);
+ }
+
+ /* Forget objects */
+ m_ptr->hold_o_idx = 0;
+}
diff --git a/src/monster3.c b/src/monster3.c
new file mode 100644
index 00000000..a2b5fb38
--- /dev/null
+++ b/src/monster3.c
@@ -0,0 +1,706 @@
+/* File: monster3.c */
+
+/* Purpose: Monsters AI */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * Is the mon,ster in friendly state(pet, friend, ..)
+ * -1 = enemy, 0 = neutral, 1 = friend
+ */
+int is_friend(monster_type *m_ptr)
+{
+ switch (m_ptr->status)
+ {
+ /* pets/friends/companion attacks monsters */
+ case MSTATUS_NEUTRAL_P:
+ case MSTATUS_FRIEND:
+ case MSTATUS_PET:
+ case MSTATUS_COMPANION:
+ return 1;
+ break;
+ case MSTATUS_NEUTRAL_M:
+ case MSTATUS_ENEMY:
+ return -1;
+ break;
+ case MSTATUS_NEUTRAL:
+ return 0;
+ break;
+ }
+
+ /* OUPS */
+ return (0);
+}
+
+/* Should they attack each others */
+bool_ is_enemy(monster_type *m_ptr, monster_type *t_ptr)
+{
+ monster_race *r_ptr = &r_info[m_ptr->r_idx], *rt_ptr = &r_info[t_ptr->r_idx];
+ int s1 = is_friend(m_ptr), s2 = is_friend(t_ptr);
+
+ /* Monsters hates breeders */
+ if ((m_ptr->status != MSTATUS_NEUTRAL) && (rt_ptr->flags4 & RF4_MULTIPLY) && (num_repro > MAX_REPRO * 2 / 3) && (r_ptr->d_char != rt_ptr->d_char)) return TRUE;
+ if ((t_ptr->status != MSTATUS_NEUTRAL) && (r_ptr->flags4 & RF4_MULTIPLY) && (num_repro > MAX_REPRO * 2 / 3) && (r_ptr->d_char != rt_ptr->d_char)) return TRUE;
+
+ /* No special conditions, lets test normal flags */
+ if (s1 && s2 && (s1 == -s2)) return TRUE;
+
+ /* Not ennemy */
+ return (FALSE);
+}
+
+bool_ change_side(monster_type *m_ptr)
+{
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* neutrals and companions */
+ switch (m_ptr->status)
+ {
+ case MSTATUS_FRIEND:
+ m_ptr->status = MSTATUS_ENEMY;
+ if ((r_ptr->flags3 & RF3_ANIMAL) && (!(r_ptr->flags3 & RF3_EVIL)))
+ inc_piety(GOD_YAVANNA, -m_ptr->level * 4);
+ break;
+ case MSTATUS_NEUTRAL_P:
+ m_ptr->status = MSTATUS_NEUTRAL_M;
+ break;
+ case MSTATUS_NEUTRAL_M:
+ m_ptr->status = MSTATUS_NEUTRAL_P;
+ break;
+ case MSTATUS_PET:
+ m_ptr->status = MSTATUS_ENEMY;
+ if ((r_ptr->flags3 & RF3_ANIMAL) && (!(r_ptr->flags3 & RF3_EVIL)))
+ inc_piety(GOD_YAVANNA, -m_ptr->level * 4);
+ break;
+ case MSTATUS_COMPANION:
+ return FALSE;
+ break;
+ }
+ /* changed */
+ return TRUE;
+}
+
+/* Multiply !! */
+bool_ ai_multiply(int m_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = &r_info[m_ptr->r_idx];
+ int k, y, x, oy = m_ptr->fy, ox = m_ptr->fx;
+ bool_ is_frien = (is_friend(m_ptr) > 0);
+
+ /* Count the adjacent monsters */
+ for (k = 0, y = oy - 1; y <= oy + 1; y++)
+ {
+ for (x = ox - 1; x <= ox + 1; x++)
+ {
+ if (cave[y][x].m_idx) k++;
+ }
+ }
+
+ if (is_friend(m_ptr) > 0)
+ {
+ is_frien = TRUE;
+ }
+ else
+ {
+ is_frien = FALSE;
+ }
+
+ /* Hack -- multiply slower in crowded areas */
+ if ((k < 4) && (!k || !rand_int(k * MON_MULT_ADJ)))
+ {
+ /* Try to multiply */
+ if (multiply_monster(m_idx, (is_frien), FALSE))
+ {
+ /* Take note if visible */
+ if (m_ptr->ml)
+ {
+ r_ptr->r_flags4 |= (RF4_MULTIPLY);
+ }
+
+ /* Multiplying takes energy */
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* Possessor incarnates */
+bool_ ai_possessor(int m_idx, int o_idx)
+{
+ object_type *o_ptr = &o_list[o_idx];
+ monster_type *m_ptr = &m_list[m_idx];
+ int r_idx = m_ptr->r_idx, r2_idx = o_ptr->pval2;
+ int i;
+ monster_race *r_ptr = &r_info[r2_idx];
+ char m_name[80], m_name2[80];
+
+ monster_desc(m_name, m_ptr, 0x00);
+ monster_race_desc(m_name2, r2_idx, 0);
+
+ if (m_ptr->ml) msg_format("%^s incarnates into a %s!", m_name, m_name2);
+
+ /* Remove the old one */
+ delete_object_idx(o_idx);
+
+ m_ptr->r_idx = r2_idx;
+ m_ptr->ego = 0;
+
+ /* No "damage" yet */
+ m_ptr->stunned = 0;
+ m_ptr->confused = 0;
+ m_ptr->monfear = 0;
+
+ /* No target yet */
+ m_ptr->target = -1;
+
+ /* Assume no sleeping */
+ m_ptr->csleep = 0;
+
+ /* Assign maximal hitpoints */
+ if (r_ptr->flags1 & (RF1_FORCE_MAXHP))
+ {
+ m_ptr->maxhp = maxroll(r_ptr->hdice, r_ptr->hside);
+ }
+ else
+ {
+ m_ptr->maxhp = damroll(r_ptr->hdice, r_ptr->hside);
+ }
+
+ /* And start out fully healthy */
+ m_ptr->hp = m_ptr->maxhp;
+
+ /* Some basic info */
+ for (i = 0; i < 4; i++)
+ {
+ m_ptr->blow[i].method = r_ptr->blow[i].method;
+ m_ptr->blow[i].effect = r_ptr->blow[i].effect;
+ m_ptr->blow[i].d_dice = r_ptr->blow[i].d_dice;
+ m_ptr->blow[i].d_side = r_ptr->blow[i].d_side;
+ }
+ m_ptr->ac = r_ptr->ac;
+ m_ptr->level = r_ptr->level;
+ m_ptr->speed = r_ptr->speed;
+ m_ptr->exp = MONSTER_EXP(m_ptr->level);
+
+ /* Extract the monster base speed */
+ m_ptr->mspeed = m_ptr->speed;
+
+ m_ptr->energy = 0;
+
+ /* Hack -- Count the number of "reproducers" */
+ if (r_ptr->flags4 & (RF4_MULTIPLY)) num_repro++;
+
+ /* Hack -- Notice new multi-hued monsters */
+ if (r_ptr->flags1 & (RF1_ATTR_MULTI)) shimmer_monsters = TRUE;
+
+ /* Hack -- Count the monsters on the level */
+ r_ptr->cur_num++;
+ r_info[r_idx].cur_num--;
+
+ m_ptr->possessor = r_idx;
+
+ /* Update the monster */
+ update_mon(m_idx, TRUE);
+
+ return TRUE;
+}
+
+void ai_deincarnate(int m_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ int r2_idx = m_ptr->possessor, r_idx = m_ptr->r_idx;
+ monster_race *r_ptr = &r_info[r2_idx];
+ int i;
+ char m_name[80];
+
+ monster_desc(m_name, m_ptr, 0x04);
+
+ if (m_ptr->ml) msg_format("The soul of %s deincarnates!", m_name);
+
+ m_ptr->r_idx = r2_idx;
+ m_ptr->ego = 0;
+
+ /* No "damage" yet */
+ m_ptr->stunned = 0;
+ m_ptr->confused = 0;
+ m_ptr->monfear = 0;
+
+ /* No target yet */
+ m_ptr->target = -1;
+
+ /* Assume no sleeping */
+ m_ptr->csleep = 0;
+
+ /* Assign maximal hitpoints */
+ if (r_ptr->flags1 & (RF1_FORCE_MAXHP))
+ {
+ m_ptr->maxhp = maxroll(r_ptr->hdice, r_ptr->hside);
+ }
+ else
+ {
+ m_ptr->maxhp = damroll(r_ptr->hdice, r_ptr->hside);
+ }
+
+ /* And start out fully healthy */
+ m_ptr->hp = m_ptr->maxhp;
+
+ /* Some basic info */
+ for (i = 0; i < 4; i++)
+ {
+ m_ptr->blow[i].method = r_ptr->blow[i].method;
+ m_ptr->blow[i].effect = r_ptr->blow[i].effect;
+ m_ptr->blow[i].d_dice = r_ptr->blow[i].d_dice;
+ m_ptr->blow[i].d_side = r_ptr->blow[i].d_side;
+ }
+ m_ptr->ac = r_ptr->ac;
+ m_ptr->level = r_ptr->level;
+ m_ptr->speed = r_ptr->speed;
+ m_ptr->exp = MONSTER_EXP(m_ptr->level);
+
+ /* Extract the monster base speed */
+ m_ptr->mspeed = m_ptr->speed;
+
+ m_ptr->energy = 0;
+
+ /* Hack -- Count the number of "reproducers" */
+ if (r_ptr->flags4 & (RF4_MULTIPLY)) num_repro++;
+
+ /* Hack -- Notice new multi-hued monsters */
+ if (r_ptr->flags1 & (RF1_ATTR_MULTI)) shimmer_monsters = TRUE;
+
+ /* Hack -- Count the monsters on the level */
+ r_ptr->cur_num++;
+ r_info[r_idx].cur_num--;
+
+ m_ptr->possessor = 0;
+
+ /* Update the monster */
+ update_mon(m_idx, TRUE);
+}
+
+/* Returns if a new companion is allowed */
+bool_ can_create_companion(void)
+{
+ int i, mcnt = 0;
+
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status == MSTATUS_COMPANION) mcnt++;
+ }
+
+ if (mcnt < (1 + get_skill_scale(SKILL_LORE, 6))) return (TRUE);
+ else return (FALSE);
+}
+
+
+/* Player controlled monsters */
+bool_ do_control_walk(void)
+{
+ /* Get a "repeated" direction */
+ if (p_ptr->control)
+ {
+ int dir;
+
+ if (get_rep_dir(&dir))
+ {
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Actually move the monster */
+ p_ptr->control_dir = dir;
+ }
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+bool_ do_control_inven(void)
+{
+ int monst_list[23];
+
+ if (!p_ptr->control) return FALSE;
+ screen_save();
+ prt("Carried items", 0, 0);
+ show_monster_inven(p_ptr->control, monst_list);
+ inkey();
+ screen_load();
+ return TRUE;
+}
+
+bool_ do_control_pickup(void)
+{
+ int this_o_idx, next_o_idx = 0;
+ monster_type *m_ptr = &m_list[p_ptr->control];
+ cave_type *c_ptr;
+ bool_ done = FALSE;
+
+ if (!p_ptr->control) return FALSE;
+
+ /* Scan all objects in the grid */
+ c_ptr = &cave[m_ptr->fy][m_ptr->fx];
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Skip gold */
+ if (o_ptr->tval == TV_GOLD) continue;
+
+ /* Excise the object */
+ excise_object_idx(this_o_idx);
+
+ /* Forget mark */
+ o_ptr->marked = FALSE;
+
+ /* Forget location */
+ o_ptr->iy = o_ptr->ix = 0;
+
+ /* Memorize monster */
+ o_ptr->held_m_idx = p_ptr->control;
+
+ /* Build a stack */
+ o_ptr->next_o_idx = m_ptr->hold_o_idx;
+
+ /* Carry object */
+ m_ptr->hold_o_idx = this_o_idx;
+ done = TRUE;
+ }
+ if (done) msg_print("You pick up all objects on the floor.");
+ return TRUE;
+}
+
+bool_ do_control_drop(void)
+{
+ monster_type *m_ptr = &m_list[p_ptr->control];
+
+ if (!p_ptr->control) return FALSE;
+ monster_drop_carried_objects(m_ptr);
+ return TRUE;
+}
+
+bool_ do_control_magic(void)
+{
+ int power = -1;
+ int num = 0, i;
+ int powers[96];
+ bool_ flag, redraw;
+ int ask;
+ char choice;
+ char out_val[160];
+ monster_race *r_ptr = &r_info[m_list[p_ptr->control].r_idx];
+ int label;
+
+ if (!p_ptr->control) return FALSE;
+
+ if (get_check("Do you want to abandon the creature?"))
+ {
+ if (get_check("Abandon it permanently?"))
+ delete_monster_idx(p_ptr->control);
+ p_ptr->control = 0;
+ return TRUE;
+ }
+
+ /* List the monster powers -- RF4_* */
+ for (i = 0; i < 32; i++)
+ {
+ if (r_ptr->flags4 & BIT(i))
+ {
+ if (!monster_powers[i].power) continue;
+ powers[num++] = i;
+ }
+ }
+
+ /* List the monster powers -- RF5_* */
+ for (i = 0; i < 32; i++)
+ {
+ if (r_ptr->flags5 & BIT(i))
+ {
+ if (!monster_powers[i + 32].power) continue;
+ powers[num++] = i + 32;
+ }
+ }
+
+ /* List the monster powers -- RF6_* */
+ for (i = 0; i < 32; i++)
+ {
+ if (r_ptr->flags6 & BIT(i))
+ {
+ if (!monster_powers[i + 64].power) continue;
+ powers[num++] = i + 64;
+ }
+ }
+
+ if (!num)
+ {
+ msg_print("You have no powers you can use.");
+ return (TRUE);
+ }
+
+ /* Nothing chosen yet */
+ flag = FALSE;
+
+ /* No redraw yet */
+ redraw = FALSE;
+
+ /* Get the last label */
+ label = (num <= 26) ? I2A(num - 1) : I2D(num - 1 - 26);
+
+ /* Build a prompt (accept all spells) */
+ strnfmt(out_val, 78,
+ "(Powers a-%c, *=List, ESC=exit) Use which power of your golem? ",
+ label);
+
+ /* Get a spell from the user */
+ while (!flag && get_com(out_val, &choice))
+ {
+ /* Request redraw */
+ if ((choice == ' ') || (choice == '*') || (choice == '?'))
+ {
+ /* Show the list */
+ if (!redraw)
+ {
+ byte y = 1, x = 0;
+ int ctr = 0;
+ char dummy[80];
+
+ strcpy(dummy, "");
+
+ /* Show list */
+ redraw = TRUE;
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ prt ("", y++, x);
+
+ while (ctr < num)
+ {
+ monster_power *mp_ptr = &monster_powers[powers[ctr]];
+
+ label = (ctr < 26) ? I2A(ctr) : I2D(ctr - 26);
+
+ strnfmt(dummy, 80, " %c) %s",
+ label, mp_ptr->name);
+
+ if (ctr < 17)
+ {
+ prt(dummy, y + ctr, x);
+ }
+ else
+ {
+ prt(dummy, y + ctr - 17, x + 40);
+ }
+
+ ctr++;
+ }
+
+ if (ctr < 17)
+ {
+ prt ("", y + ctr, x);
+ }
+ else
+ {
+ prt ("", y + 17, x);
+ }
+ }
+
+ /* Hide the list */
+ else
+ {
+ /* Hide list */
+ redraw = FALSE;
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Redo asking */
+ continue;
+ }
+
+ if (choice == '\r' && num == 1)
+ {
+ choice = 'a';
+ }
+
+ if (isalpha(choice))
+ {
+ /* Note verify */
+ ask = (isupper(choice));
+
+ /* Lowercase */
+ if (ask) choice = tolower(choice);
+
+ /* Extract request */
+ i = (islower(choice) ? A2I(choice) : -1);
+ }
+ else
+ {
+ /* Can't uppercase digits XXX XXX XXX */
+ ask = FALSE;
+
+ i = choice - '0' + 26;
+ }
+
+ /* Totally Illegal */
+ if ((i < 0) || (i >= num))
+ {
+ bell();
+ continue;
+ }
+
+ /* Save the spell index */
+ power = powers[i];
+
+ /* Verify it */
+ if (ask)
+ {
+ char tmp_val[160];
+
+ /* Prompt */
+ strnfmt(tmp_val, 78, "Use %s? ", monster_powers[power].name);
+
+ /* Belay that order */
+ if (!get_check(tmp_val)) continue;
+ }
+
+ /* Stop the loop */
+ flag = TRUE;
+ }
+
+ /* Restore the screen */
+ if (redraw)
+ {
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Take a turn */
+ if (flag)
+ {
+ energy_use = 100;
+ monst_spell_monst_spell = power + 96;
+ }
+ return TRUE;
+}
+
+/* Finds the controlled monster and "reconnect" to it */
+bool_ do_control_reconnect()
+{
+ int i;
+
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->mflag & MFLAG_CONTROL)
+ {
+ p_ptr->control = i;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Turns a simple pet into a faithful companion
+ */
+void do_cmd_companion()
+{
+ monster_type *m_ptr;
+ int ii, jj;
+
+ if (!can_create_companion())
+ {
+ msg_print("You cannot have any more companions.");
+ return;
+ }
+
+ if (!tgt_pt(&ii, &jj))
+ {
+ msg_print("You must target a pet.");
+ return;
+ }
+
+ if (cave[jj][ii].m_idx)
+ {
+ char m_name[100];
+
+ m_ptr = &m_list[cave[jj][ii].m_idx];
+
+ monster_desc(m_name, m_ptr, 0);
+ if (m_ptr->status == MSTATUS_PET)
+ {
+ m_ptr->status = MSTATUS_COMPANION;
+ msg_format("%^s agrees to follow you.", m_name);
+ }
+ else
+ {
+ msg_format("%^s is not your pet!", m_name);
+ }
+ }
+ else
+ msg_print("You must target a pet.");
+}
+
+/*
+ * List companions to the character sheet.
+ */
+void dump_companions(FILE *outfile)
+{
+ int i;
+ int done_hdr = 0;
+
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status == MSTATUS_COMPANION)
+ {
+ char pet_name[80];
+
+ /* Output the header if we haven't yet. */
+ if (!done_hdr)
+ {
+ done_hdr = 1;
+ fprintf(outfile, "\n\n [Current companions]\n\n");
+ }
+
+ /* List the monster. */
+ monster_desc(pet_name, m_ptr, 0x88);
+ fprintf(outfile, "%s (level %d)\n", pet_name, m_ptr->level);
+ }
+ }
+}
diff --git a/src/notes.c b/src/notes.c
new file mode 100644
index 00000000..3504f61c
--- /dev/null
+++ b/src/notes.c
@@ -0,0 +1,188 @@
+/* File: notes.c */
+
+/* Purpose: Note taking to a file */
+
+/*
+ * Copyright (c) 1989, 1999 James E. Wilson, Robert A. Koeneke,
+ * Robert Ruehlmann
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * Show the notes file on the screen
+ */
+void show_notes_file(void)
+{
+ char basename[13];
+ char buf[1024];
+ char caption[10 + 13];
+
+ /* Hack -- extract first 8 characters of name and append an extension */
+ (void)strnfmt(basename, sizeof(basename), "%.8s.nte", player_base);
+ basename[sizeof(basename) - 1] = '\0';
+
+ /* Build the path */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_NOTE, basename);
+
+ /* Use a caption, forcing direct access to the note file */
+ sprintf(caption, "Note file %s", basename);
+
+ /* Invoke show_file */
+ (void)show_file(buf, caption, 0, 0);
+
+ /* Done */
+ return;
+}
+
+/*
+ * Output a string to the notes file.
+ * This is the only function that references that file.
+ */
+void output_note(char *final_note)
+{
+ FILE *fff;
+ char basename[13];
+ char buf[1024];
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Hack -- extract first 8 characters of name and append an extension */
+ (void)strnfmt(basename, sizeof(basename), "%.8s.nte", player_base);
+ basename[sizeof(basename) - 1] = '\0';
+
+ /* Build the path */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_NOTE, basename);
+
+ /* Open notes file */
+ fff = my_fopen(buf, "a");
+
+ /* Failure */
+ if (!fff) return;
+
+ /* Add note, and close note file */
+ my_fputs(fff, final_note, 0);
+
+ /* Close the handle */
+ my_fclose(fff);
+
+ /* Done */
+ return;
+}
+
+
+/*
+ * Add note to file using a string + character symbol
+ * to specify its type so that the notes file can be
+ * searched easily by external utilities.
+ */
+void add_note(char *note, char code)
+{
+ char buf[100];
+ char final_note[100];
+ char long_day[50];
+ char depths[32];
+
+ /* Get the first 60 chars - so do not have an overflow */
+ C_WIPE(buf, 100, char);
+ strncpy(buf, note, 60);
+
+ /* Get date and time */
+ sprintf(long_day, "%ld:%02ld %s, %s", (long int) ((bst(HOUR, turn) % 12 == 0) ? 12 : (bst(HOUR, turn) % 12)),
+ (long int) bst(MINUTE, turn), (bst(HOUR, turn) < 12) ? "AM" : "PM", get_month_name(bst(DAY, turn), FALSE,
+ FALSE));
+
+ /* Get depth */
+ if (!dun_level) strcpy(depths, " Town");
+ else if (depth_in_feet) sprintf(depths, "%4dft", dun_level * 50);
+ else sprintf(depths, "Lev%3d", dun_level);
+
+ /* Make note */
+ sprintf(final_note, "%-20s %s %c: %s", long_day, depths, code, buf);
+
+ /* Output to the notes file */
+ output_note(final_note);
+}
+
+
+/*
+ * Append a note to the notes file using a "type".
+ */
+void add_note_type(int note_number)
+{
+ char long_day[50], true_long_day[50];
+ char buf[1024];
+ time_t ct = time((time_t*)0);
+
+ /* Get the date */
+ strftime(true_long_day, 30, "%Y-%m-%d at %H:%M:%S", localtime(&ct));
+
+ /* Get the date */
+ sprintf(buf, "%ld", (long int) (bst(YEAR, turn) + START_YEAR));
+ sprintf(long_day, "%ld:%02ld %s the %s of III %s", (long int) ((bst(HOUR, turn) % 12 == 0) ? 12 : (bst(HOUR, turn) % 12)), (long int) bst(MINUTE, turn), (bst(HOUR, turn) < 12) ? "AM" : "PM", get_month_name(bst(DAY, turn), FALSE, FALSE), buf);
+
+ /* Work out what to do */
+ switch (note_number)
+ {
+ case NOTE_BIRTH:
+ {
+ /* Player has just been born */
+ char player[100];
+
+ /* Build the string containing the player information */
+ sprintf(player, "the %s %s", get_player_race_name(p_ptr->prace, p_ptr->pracem), class_info[p_ptr->pclass].spec[p_ptr->pspec].title + c_name);
+
+ /* Add in "character start" information */
+ sprintf(buf,
+ "\n"
+ "================================================\n"
+ "%s %s\n"
+ "Born on %s\n"
+ "================================================\n",
+ player_name, player, true_long_day);
+
+ break;
+ }
+
+ case NOTE_WINNER:
+ {
+ sprintf(buf,
+ "%s slew Morgoth on %s\n"
+ "Long live %s!\n"
+ "================================================",
+ player_name, long_day, player_name);
+
+ break;
+ }
+
+ case NOTE_SAVE_GAME:
+ {
+ /* Saving the game */
+ sprintf(buf, "\nSession end: %s", true_long_day);
+
+ break;
+ }
+
+ case NOTE_ENTER_DUNGEON:
+ {
+ /* Entering the game after a break. */
+ sprintf(buf,
+ "================================================\n"
+ "New session start: %s\n",
+ true_long_day);
+
+ break;
+ }
+
+ default:
+ return;
+ }
+
+ /* Output the notes to the file */
+ output_note(buf);
+}
diff --git a/src/object.pkg b/src/object.pkg
new file mode 100644
index 00000000..a89dad9a
--- /dev/null
+++ b/src/object.pkg
@@ -0,0 +1,1169 @@
+/* File: object.pkg */
+
+/*
+ * Purpose: Lua interface defitions for objects.
+ * To be processed by tolua to generate C source code.
+ */
+
+$#include "angband.h"
+
+typedef char* cptr;
+typedef int errr;
+typedef unsigned char bool;
+typedef unsigned char byte;
+typedef signed short s16b;
+typedef unsigned short u16b;
+typedef signed int s32b;
+typedef unsigned int u32b;
+
+/* To make easy object creations */
+$static object_type lua_obj_forge;
+static object_type lua_obj_forge @ obj_forge;
+$static obj_theme lua_obj_theme;
+static obj_theme lua_obj_theme @ theme_forge;
+
+#define TR1_STR 0x00000001L /* STR += "pval" */
+#define TR1_INT 0x00000002L /* INT += "pval" */
+#define TR1_WIS 0x00000004L /* WIS += "pval" */
+#define TR1_DEX 0x00000008L /* DEX += "pval" */
+#define TR1_CON 0x00000010L /* CON += "pval" */
+#define TR1_CHR 0x00000020L /* CHR += "pval" */
+#define TR1_MANA 0x00000040L /* Mana multipler */
+#define TR1_SPELL 0x00000080L /* Spell power increase */
+#define TR1_STEALTH 0x00000100L /* Stealth += "pval" */
+#define TR1_SEARCH 0x00000200L /* Search += "pval" */
+#define TR1_INFRA 0x00000400L /* Infra += "pval" */
+#define TR1_TUNNEL 0x00000800L /* Tunnel += "pval" */
+#define TR1_SPEED 0x00001000L /* Speed += "pval" */
+#define TR1_BLOWS 0x00002000L /* Blows += "pval" */
+#define TR1_CHAOTIC 0x00004000L
+#define TR1_VAMPIRIC 0x00008000L
+#define TR1_SLAY_ANIMAL 0x00010000L
+#define TR1_SLAY_EVIL 0x00020000L
+#define TR1_SLAY_UNDEAD 0x00040000L
+#define TR1_SLAY_DEMON 0x00080000L
+#define TR1_SLAY_ORC 0x00100000L
+#define TR1_SLAY_TROLL 0x00200000L
+#define TR1_SLAY_GIANT 0x00400000L
+#define TR1_SLAY_DRAGON 0x00800000L
+#define TR1_KILL_DRAGON 0x01000000L /* Execute Dragon */
+#define TR1_VORPAL 0x02000000L /* Later */
+#define TR1_IMPACT 0x04000000L /* Cause Earthquakes */
+#define TR1_BRAND_POIS 0x08000000L
+#define TR1_BRAND_ACID 0x10000000L
+#define TR1_BRAND_ELEC 0x20000000L
+#define TR1_BRAND_FIRE 0x40000000L
+#define TR1_BRAND_COLD 0x80000000L
+#define TR1_NULL_MASK 0x00000000L
+
+#define TR2_SUST_STR 0x00000001L
+#define TR2_SUST_INT 0x00000002L
+#define TR2_SUST_WIS 0x00000004L
+#define TR2_SUST_DEX 0x00000008L
+#define TR2_SUST_CON 0x00000010L
+#define TR2_SUST_CHR 0x00000020L
+#define TR2_INVIS 0x00000040L /* Invisibility */
+#define TR2_LIFE 0x00000080L /* Life multiplier */
+#define TR2_IM_ACID 0x00000100L
+#define TR2_IM_ELEC 0x00000200L
+#define TR2_IM_FIRE 0x00000400L
+#define TR2_IM_COLD 0x00000800L
+#define TR2_SENS_FIRE 0x00001000L /* Sensibility to fire */
+#define TR2_REFLECT 0x00002000L /* Reflect 'bolts' */
+#define TR2_FREE_ACT 0x00004000L /* Free Action */
+#define TR2_HOLD_LIFE 0x00008000L /* Hold Life */
+#define TR2_RES_ACID 0x00010000L
+#define TR2_RES_ELEC 0x00020000L
+#define TR2_RES_FIRE 0x00040000L
+#define TR2_RES_COLD 0x00080000L
+#define TR2_RES_POIS 0x00100000L
+#define TR2_RES_FEAR 0x00200000L
+#define TR2_RES_LITE 0x00400000L
+#define TR2_RES_DARK 0x00800000L
+#define TR2_RES_BLIND 0x01000000L
+#define TR2_RES_CONF 0x02000000L
+#define TR2_RES_SOUND 0x04000000L
+#define TR2_RES_SHARDS 0x08000000L
+#define TR2_RES_NETHER 0x10000000L
+#define TR2_RES_NEXUS 0x20000000L
+#define TR2_RES_CHAOS 0x40000000L
+#define TR2_RES_DISEN 0x80000000L
+#define TR2_NULL_MASK 0x00000000L
+
+#define TR3_SH_FIRE 0x00000001L /* Immolation (Fire) */
+#define TR3_SH_ELEC 0x00000002L /* Electric Sheath */
+#define TR3_AUTO_CURSE 0x00000004L /* The obj will recurse itself */
+#define TR3_DECAY 0x00000008L /* Decay */
+#define TR3_NO_TELE 0x00000010L /* Anti-teleportation */
+#define TR3_NO_MAGIC 0x00000020L /* Anti-magic */
+#define TR3_WRAITH 0x00000040L /* Wraithform */
+#define TR3_TY_CURSE 0x00000080L /* The Ancient Curse */
+#define TR3_EASY_KNOW 0x00000100L /* Aware -> Known */
+#define TR3_HIDE_TYPE 0x00000200L /* Hide "pval" description */
+#define TR3_SHOW_MODS 0x00000400L /* Always show Tohit/Todam */
+#define TR3_INSTA_ART 0x00000800L /* Item must be an artifact */
+#define TR3_FEATHER 0x00001000L /* Feather Falling */
+#define TR3_LITE1 0x00002000L /* lite radius 1 */
+#define TR3_SEE_INVIS 0x00004000L /* See Invisible */
+#define TR3_NORM_ART 0x00008000L /* Artifact in k_info */
+#define TR3_SLOW_DIGEST 0x00010000L /* Item slows down digestion */
+#define TR3_REGEN 0x00020000L /* Item induces regeneration */
+#define TR3_XTRA_MIGHT 0x00040000L /* Bows get extra multiplier */
+#define TR3_XTRA_SHOTS 0x00080000L /* Bows get extra shots */
+#define TR3_IGNORE_ACID 0x00100000L /* Item ignores Acid Damage */
+#define TR3_IGNORE_ELEC 0x00200000L /* Item ignores Elec Damage */
+#define TR3_IGNORE_FIRE 0x00400000L /* Item ignores Fire Damage */
+#define TR3_IGNORE_COLD 0x00800000L /* Item ignores Cold Damage */
+#define TR3_ACTIVATE 0x01000000L /* Item can be activated */
+#define TR3_DRAIN_EXP 0x02000000L /* Item drains Experience */
+#define TR3_TELEPORT 0x04000000L /* Item teleports player */
+#define TR3_AGGRAVATE 0x08000000L /* Item aggravates monsters */
+#define TR3_BLESSED 0x10000000L /* Item is Blessed */
+#define TR3_CURSED 0x20000000L /* Item is Cursed */
+#define TR3_HEAVY_CURSE 0x40000000L /* Item is Heavily Cursed */
+#define TR3_PERMA_CURSE 0x80000000L /* Item is Perma Cursed */
+#define TR3_NULL_MASK 0x00000000L
+
+#define TR4_NEVER_BLOW 0x00000001L /* Weapon can't attack */
+#define TR4_PRECOGNITION 0x00000002L /* Like activating the cheat mode */
+#define TR4_BLACK_BREATH 0x00000004L /* Tolkien's Black Breath */
+#define TR4_RECHARGE 0x00000008L /* For artifact Wands and Staffs */
+#define TR4_FLY 0x00000010L /* This one and ONLY this one allow you to fly over trees */
+#define TR4_DG_CURSE 0x00000020L /* The Ancient Morgothian Curse */
+#define TR4_COULD2H 0x00000040L /* Can wield it 2 Handed */
+#define TR4_MUST2H 0x00000080L /* Must wield it 2 Handed */
+#define TR4_LEVELS 0x00000100L /* Can gain exp/exp levels !! */
+#define TR4_CLONE 0x00000200L /* Can clone monsters */
+#define TR4_SPECIAL_GENE 0x00000400L /* The object can only be generated in special conditions like quests, special dungeons, ... */
+#define TR4_CLIMB 0x00000800L /* Allow climbing mountains */
+#define TR4_FAST_CAST 0x00001000L /* Rod is x2 time faster to use */
+#define TR4_CAPACITY 0x00002000L /* Rod can take x2 mana */
+#define TR4_CHARGING 0x00004000L /* Rod recharge faster */
+#define TR4_CHEAPNESS 0x00008000L /* Rod spells are cheaper(in mana cost) to cast */
+#define TR4_FOUNTAIN 0x00010000L /* Available as fountain (for potions) */
+#define TR4_ANTIMAGIC_50 0x00020000L /* Forbid magic */
+#define TR4_ANTIMAGIC_30 0x00040000L /* Forbid magic */
+#define TR4_ANTIMAGIC_20 0x00080000L /* Forbid magic */
+#define TR4_ANTIMAGIC_10 0x00100000L /* Forbid magic */
+#define TR4_EASY_USE 0x00200000L /* Easily activable */
+#define TR4_IM_NETHER 0x00400000L /* Immunity to nether */
+#define TR4_RECHARGED 0x00800000L /* Object has been recharged once */
+#define TR4_ULTIMATE 0x01000000L /* ULTIMATE artifact */
+#define TR4_AUTO_ID 0x02000000L /* Id stuff on floor */
+#define TR4_LITE2 0x04000000L /* lite radius 2 */
+#define TR4_LITE3 0x08000000L /* lite radius 3 */
+#define TR4_FUEL_LITE 0x10000000L /* fuelable lite */
+#define TR4_ART_EXP 0x20000000L /* Will accumulate xp */
+#define TR4_CURSE_NO_DROP 0x40000000L /* The obj wont be dropped */
+#define TR4_NO_RECHARGE 0x80000000L /* Object Cannot be recharged */
+#define TR4_NULL_MASK 0xFFFFFFFCL
+
+#define TR5_TEMPORARY 0x00000001L /* In timeout turns it is destroyed */
+#define TR5_DRAIN_MANA 0x00000002L /* Drains mana */
+#define TR5_DRAIN_HP 0x00000004L /* Drains hp */
+#define TR5_KILL_DEMON 0x00000008L /* Execute Demon */
+#define TR5_KILL_UNDEAD 0x00000010L /* Execute Undead */
+#define TR5_CRIT 0x00000020L /* More critical hits */
+#define TR5_ATTR_MULTI 0x00000040L /* Object shimmer -- only allowed in k_info */
+#define TR5_WOUNDING 0x00000080L /* Wounds monsters */
+#define TR5_FULL_NAME 0x00000100L /* Uses direct name from k_info */
+#define TR5_LUCK 0x00000200L /* Luck += pval */
+#define TR5_IMMOVABLE 0x00000400L /* Cannot move */
+#define TR5_SPELL_CONTAIN 0x00000800L /* Can contain a spell */
+#define TR5_RES_MORGUL 0x00001000L /* Is not shattered by morgul fiends(nazguls) */
+#define TR5_ACTIVATE_NO_WIELD 0x00002000L /* Can be 'A'ctivated without being wielded */
+#define TR5_MAGIC_BREATH 0x00004000L /* Can breath anywere */
+#define TR5_WATER_BREATH 0x00008000L /* Can breath underwater */
+#define TR5_WIELD_CAST 0x00010000L /* Need to be wielded to cast spelsl fomr it(if it can be wiekded) */
+
+#define ESP_ORC 0x00000001L
+#define ESP_TROLL 0x00000002L
+#define ESP_DRAGON 0x00000004L
+#define ESP_GIANT 0x00000008L
+#define ESP_DEMON 0x00000010L
+#define ESP_UNDEAD 0x00000020L
+#define ESP_EVIL 0x00000040L
+#define ESP_ANIMAL 0x00000080L
+#define ESP_THUNDERLORD 0x00000100L
+#define ESP_GOOD 0x00000200L
+#define ESP_NONLIVING 0x00000400L
+#define ESP_UNIQUE 0x00000800L
+#define ESP_SPIDER 0x00001000L
+#define ESP_ALL 0x80000000L
+
+/*
+ * Bit flags for the "get_item" function
+ */
+#define USE_EQUIP 0x01 /* Allow equip items */
+#define USE_INVEN 0x02 /* Allow inven items */
+#define USE_FLOOR 0x04 /* Allow floor items */
+#define USE_EXTRA 0x08 /* Allow extra items */
+
+#define INVEN_WIELD 24 /* 3 weapons -- WEAPONS */
+#define INVEN_BOW 27 /* 1 bow -- WEAPON */
+#define INVEN_RING 28 /* 6 rings -- FINGER */
+#define INVEN_NECK 34 /* 2 amulets -- HEAD */
+#define INVEN_LITE 36 /* 1 lite -- TORSO */
+#define INVEN_BODY 37 /* 1 body -- TORSO */
+#define INVEN_OUTER 38 /* 1 cloak -- TORSO */
+#define INVEN_ARM 39 /* 3 arms -- ARMS */
+#define INVEN_HEAD 42 /* 2 heads -- HEAD */
+#define INVEN_HANDS 44 /* 3 hands -- ARMS */
+#define INVEN_FEET 47 /* 2 feets -- LEGS */
+#define INVEN_CARRY 49 /* 1 carried monster -- TORSO */
+#define INVEN_AMMO 50 /* 1 quiver -- TORSO */
+#define INVEN_TOOL 51 /* 1 tool -- ARMS */
+#define INVEN_TOTAL 52
+#define INVEN_EQ (INVEN_TOTAL - INVEN_WIELD)
+
+#define TV_SKELETON 1 /* Skeletons ('s') */
+#define TV_BOTTLE 2 /* Empty bottles ('!') */
+#define TV_BATERIE 4 /* For the Alchemists */
+#define TV_SPIKE 5 /* Spikes ('~') */
+#define TV_MSTAFF 6 /* Mage Staffs */
+#define TV_CHEST 7 /* Chests ('~') */
+#define TV_PARCHMENT 8 /* Parchments from Kamband */
+#define TV_PARCHEMENT 8 /* compatibility define */
+#define TV_CORPSE 9 /* Monster corpses */
+#define TV_EGG 10 /* Monster Eggs */
+#define TV_JUNK 11 /* Sticks, Pottery, etc ('~') */
+#define TV_TOOL 12 /* Tools */
+#define TV_INSTRUMENT 14 /* Musical instruments */
+#define TV_BOOMERANG 15 /* Boomerangs */
+#define TV_SHOT 16 /* Ammo for slings */
+#define TV_ARROW 17 /* Ammo for bows */
+#define TV_BOLT 18 /* Ammo for x-bows */
+#define TV_BOW 19 /* Slings/Bows/Xbows */
+#define TV_DIGGING 20 /* Shovels/Picks */
+#define TV_HAFTED 21 /* Priest Weapons */
+#define TV_POLEARM 22 /* Pikes/Glaives/Spears/etc. */
+#define TV_SWORD 23 /* Edged Weapons */
+#define TV_AXE 24 /* Axes/Cleavers */
+#define TV_BOOTS 30 /* Boots */
+#define TV_GLOVES 31 /* Gloves */
+#define TV_HELM 32 /* Helms */
+#define TV_CROWN 33 /* Crowns */
+#define TV_SHIELD 34 /* Shields */
+#define TV_CLOAK 35 /* Cloaks */
+#define TV_SOFT_ARMOR 36 /* Soft Armor */
+#define TV_HARD_ARMOR 37 /* Hard Armor */
+#define TV_DRAG_ARMOR 38 /* Dragon Scale Mail */
+#define TV_LITE 39 /* Lites (including Specials) */
+#define TV_AMULET 40 /* Amulets (including Specials) */
+#define TV_RING 45 /* Rings (including Specials) */
+#define TV_TRAPKIT 46 /* Trapkits */
+#define TV_TOTEM 54 /* Summoner totems */
+#define TV_STAFF 55
+#define TV_WAND 65
+#define TV_ROD 66
+#define TV_ROD_MAIN 67
+#define TV_SCROLL 70
+#define TV_POTION 71
+#define TV_POTION2 72 /* Second set of potion */
+#define TV_FLASK 77
+#define TV_FOOD 80
+#define TV_HYPNOS 99 /* To wield monsters !:) */
+#define TV_GOLD 100 /* Gold can only be picked up by players */
+#define TV_RANDART 102 /* Random Artifacts */
+#define TV_RUNE1 104 /* Base runes */
+#define TV_RUNE2 105 /* Modifier runes */
+
+#define TV_BOOK 111
+#define TV_SYMBIOTIC_BOOK 112
+#define TV_MUSIC_BOOK 113
+#define TV_DRUID_BOOK 114
+#define TV_DAEMON_BOOK 115
+
+/* The "sval" codes for TV_TOOL */
+#define SV_TOOL_CLIMB 0
+#define SV_PORTABLE_HOLE 1
+
+/* The "sval" codes for TV_MSTAFF */
+#define SV_MSTAFF 1
+
+/* The "sval" codes for TV_SHOT/TV_ARROW/TV_BOLT */
+#define SV_AMMO_LIGHT 0 /* pebbles */
+#define SV_AMMO_NORMAL 1 /* shots, arrows, bolts */
+#define SV_AMMO_HEAVY 2 /* seeker arrows and bolts, mithril shots */
+
+/* The "sval" codes for TV_INSTRUMENT */
+#define SV_DRUM 58
+#define SV_HARP 59
+#define SV_HORN 60
+
+/* The "sval" codes for TV_TRAPKIT */
+#define SV_TRAPKIT_SLING 1
+#define SV_TRAPKIT_BOW 2
+#define SV_TRAPKIT_XBOW 3
+#define SV_TRAPKIT_POTION 4
+#define SV_TRAPKIT_SCROLL 5
+#define SV_TRAPKIT_DEVICE 6
+
+/* The "sval" codes for TV_BOOMERANG */
+#define SV_BOOM_S_WOOD 1 /* 1d4 */
+#define SV_BOOM_WOOD 2 /* 1d9 */
+#define SV_BOOM_S_METAL 3 /* 1d8 */
+#define SV_BOOM_METAL 4 /* 2d4 */
+
+/* The "sval" codes for TV_BOW (note information in "sval") */
+#define SV_SLING 2 /* (x2) */
+#define SV_SHORT_BOW 12 /* (x2) */
+#define SV_LONG_BOW 13 /* (x3) */
+#define SV_LIGHT_XBOW 23 /* (x3) */
+#define SV_HEAVY_XBOW 24 /* (x4) */
+
+/* The "sval" codes for TV_DIGGING */
+#define SV_SHOVEL 1
+#define SV_GNOMISH_SHOVEL 2
+#define SV_DWARVEN_SHOVEL 3
+#define SV_PICK 4
+#define SV_ORCISH_PICK 5
+#define SV_DWARVEN_PICK 6
+#define SV_MATTOCK 7
+
+/* The "sval" values for TV_HAFTED */
+#define SV_CLUB 1 /* 1d4 */
+#define SV_WHIP 2 /* 1d6 */
+#define SV_QUARTERSTAFF 3 /* 1d9 */
+#define SV_NUNCHAKU 4 /* 2d3 */
+#define SV_MACE 5 /* 2d4 */
+#define SV_BALL_AND_CHAIN 6 /* 2d4 */
+#define SV_WAR_HAMMER 8 /* 3d3 */
+#define SV_LUCERN_HAMMER 10 /* 2d5 */
+#define SV_THREE_PIECE_ROD 11 /* 3d3 */
+#define SV_MORNING_STAR 12 /* 2d6 */
+#define SV_FLAIL 13 /* 2d6 */
+#define SV_LEAD_FILLED_MACE 15 /* 3d4 */
+#define SV_TWO_HANDED_FLAIL 18 /* 3d6 */
+#define SV_GREAT_HAMMER 19 /* 4d6 */
+#define SV_MACE_OF_DISRUPTION 20 /* 5d8 */
+#define SV_GROND 50 /* 3d4 */
+
+/* The "sval" values for TV_AXE */
+#define SV_HATCHET 1 /* 1d5 */
+#define SV_CLEAVER 2 /* 2d4 */
+#define SV_LIGHT_WAR_AXE 8 /* 2d5 */
+#define SV_BEAKED_AXE 10 /* 2d6 */
+#define SV_BROAD_AXE 11 /* 2d6 */
+#define SV_BATTLE_AXE 22 /* 2d8 */
+#define SV_GREAT_AXE 25 /* 4d4 */
+#define SV_LOCHABER_AXE 28 /* 3d8 */
+#define SV_SLAUGHTER_AXE 30 /* 5d7 */
+
+/* The "sval" values for TV_POLEARM */
+#define SV_SPEAR 2 /* 1d6 */
+#define SV_SICKLE 3 /* 2d3 */
+#define SV_AWL_PIKE 4 /* 1d8 */
+#define SV_TRIDENT 5 /* 1d9 */
+#define SV_FAUCHARD 6 /* 1d10 */
+#define SV_BROAD_SPEAR 7 /* 1d9 */
+#define SV_PIKE 8 /* 2d5 */
+#define SV_GLAIVE 13 /* 2d6 */
+#define SV_HALBERD 15 /* 3d4 */
+#define SV_GUISARME 16 /* 2d5 */
+#define SV_SCYTHE 17 /* 5d3 */
+#define SV_LANCE 20 /* 2d8 */
+#define SV_TRIFURCATE_SPEAR 26 /* 2d9 */
+#define SV_HEAVY_LANCE 29 /* 4d8 */
+#define SV_SCYTHE_OF_SLICING 30 /* 8d4 */
+
+/* The "sval" codes for TV_SWORD */
+#define SV_BROKEN_DAGGER 1 /* 1d1 */
+#define SV_BROKEN_SWORD 2 /* 1d2 */
+#define SV_DAGGER 4 /* 1d4 */
+#define SV_MAIN_GAUCHE 5 /* 1d5 */
+#define SV_RAPIER 7 /* 1d6 */
+#define SV_SMALL_SWORD 8 /* 1d6 */
+#define SV_BASILLARD 9 /* 1d8 */
+#define SV_SHORT_SWORD 10 /* 1d7 */
+#define SV_SABRE 11 /* 1d7 */
+#define SV_CUTLASS 12 /* 1d7 */
+#define SV_KHOPESH 14 /* 2d4 */
+#define SV_TULWAR 15 /* 2d4 */
+#define SV_BROAD_SWORD 16 /* 2d5 */
+#define SV_LONG_SWORD 17 /* 2d5 */
+#define SV_SCIMITAR 18 /* 2d5 */
+#define SV_KATANA 20 /* 3d4 */
+#define SV_BASTARD_SWORD 21 /* 3d4 */
+#define SV_GREAT_SCIMITAR 22 /* 4d5 */
+#define SV_CLAYMORE 23 /* 2d8 */
+#define SV_ESPADON 24 /* 2d9 */
+#define SV_TWO_HANDED_SWORD 25 /* 3d6 */
+#define SV_FLAMBERGE 26 /* 3d7 */
+#define SV_EXECUTIONERS_SWORD 28 /* 4d5 */
+#define SV_ZWEIHANDER 29 /* 4d6 */
+#define SV_BLADE_OF_CHAOS 30 /* 6d5 */
+#define SV_BLUESTEEL_BLADE 31 /* 3d9 */
+#define SV_SHADOW_BLADE 32 /* 4d4 */
+#define SV_DARK_SWORD 33 /* 3d7 */
+
+/* The "sval" codes for TV_SHIELD */
+#define SV_SMALL_LEATHER_SHIELD 2
+#define SV_SMALL_METAL_SHIELD 3
+#define SV_LARGE_LEATHER_SHIELD 4
+#define SV_LARGE_METAL_SHIELD 5
+#define SV_DRAGON_SHIELD 6
+#define SV_SHIELD_OF_DEFLECTION 10
+
+/* The "sval" codes for TV_HELM */
+#define SV_HARD_LEATHER_CAP 2
+#define SV_METAL_CAP 3
+#define SV_IRON_HELM 5
+#define SV_STEEL_HELM 6
+#define SV_DRAGON_HELM 7
+#define SV_IRON_CROWN 10
+#define SV_GOLDEN_CROWN 11
+#define SV_JEWELED_CROWN 12
+#define SV_MORGOTH 50
+
+/* The "sval" codes for TV_BOOTS */
+#define SV_PAIR_OF_SOFT_LEATHER_BOOTS 2
+#define SV_PAIR_OF_HARD_LEATHER_BOOTS 3
+#define SV_PAIR_OF_METAL_SHOD_BOOTS 6
+
+/* The "sval" codes for TV_CLOAK */
+#define SV_CLOAK 1
+#define SV_ELVEN_CLOAK 2
+#define SV_FUR_CLOAK 3
+#define SV_SHADOW_CLOAK 6
+
+/* The "sval" codes for TV_GLOVES */
+#define SV_SET_OF_LEATHER_GLOVES 1
+#define SV_SET_OF_GAUNTLETS 2
+#define SV_SET_OF_CESTI 5
+
+/* The "sval" codes for TV_SOFT_ARMOR */
+#define SV_FILTHY_RAG 1
+#define SV_ROBE 2
+#define SV_PAPER_ARMOR 3 /* 4 */
+#define SV_SOFT_LEATHER_ARMOR 4
+#define SV_SOFT_STUDDED_LEATHER 5
+#define SV_HARD_LEATHER_ARMOR 6
+#define SV_HARD_STUDDED_LEATHER 7
+#define SV_RHINO_HIDE_ARMOR 8
+#define SV_CORD_ARMOR 9 /* 6 */
+#define SV_PADDED_ARMOR 10 /* 4 */
+#define SV_LEATHER_SCALE_MAIL 11
+#define SV_LEATHER_JACK 12
+#define SV_STONE_AND_HIDE_ARMOR 15 /* 15 */
+#define SV_THUNDERLORD_SUIT 16
+
+/* The "sval" codes for TV_HARD_ARMOR */
+#define SV_RUSTY_CHAIN_MAIL 1 /* 14- */
+#define SV_RING_MAIL 2 /* 12 */
+#define SV_METAL_SCALE_MAIL 3 /* 13 */
+#define SV_CHAIN_MAIL 4 /* 14 */
+#define SV_DOUBLE_RING_MAIL 5 /* 15 */
+#define SV_AUGMENTED_CHAIN_MAIL 6 /* 16 */
+#define SV_DOUBLE_CHAIN_MAIL 7 /* 16 */
+#define SV_BAR_CHAIN_MAIL 8 /* 18 */
+#define SV_METAL_BRIGANDINE_ARMOUR 9 /* 19 */
+#define SV_SPLINT_MAIL 10 /* 19 */
+#define SV_PARTIAL_PLATE_ARMOUR 12 /* 22 */
+#define SV_METAL_LAMELLAR_ARMOUR 13 /* 23 */
+#define SV_FULL_PLATE_ARMOUR 15 /* 25 */
+#define SV_RIBBED_PLATE_ARMOUR 18 /* 28 */
+#define SV_MITHRIL_CHAIN_MAIL 20 /* 28+ */
+#define SV_MITHRIL_PLATE_MAIL 25 /* 35+ */
+#define SV_ADAMANTITE_PLATE_MAIL 30 /* 40+ */
+
+/* The "sval" codes for TV_DRAG_ARMOR */
+#define SV_DRAGON_BLACK 1
+#define SV_DRAGON_BLUE 2
+#define SV_DRAGON_WHITE 3
+#define SV_DRAGON_RED 4
+#define SV_DRAGON_GREEN 5
+#define SV_DRAGON_MULTIHUED 6
+#define SV_DRAGON_SHINING 10
+#define SV_DRAGON_LAW 12
+#define SV_DRAGON_BRONZE 14
+#define SV_DRAGON_GOLD 16
+#define SV_DRAGON_CHAOS 18
+#define SV_DRAGON_BALANCE 20
+#define SV_DRAGON_POWER 30
+
+/* The sval codes for TV_LITE */
+#define SV_LITE_TORCH 0
+#define SV_LITE_LANTERN 1
+#define SV_LITE_TORCH_EVER 2
+#define SV_LITE_DWARVEN 3
+#define SV_LITE_FEANORIAN 4
+#define SV_LITE_GALADRIEL 100
+#define SV_LITE_ELENDIL 101
+#define SV_LITE_THRAIN 102
+#define SV_LITE_UNDEATH 103
+#define SV_LITE_PALANTIR 104
+#define SV_ANCHOR_SPACETIME 105
+#define SV_STONE_LORE 106
+
+
+/* The "sval" codes for TV_AMULET */
+#define SV_AMULET_DOOM 0
+#define SV_AMULET_TELEPORT 1
+#define SV_AMULET_ADORNMENT 2
+#define SV_AMULET_SLOW_DIGEST 3
+#define SV_AMULET_RESIST_ACID 4
+#define SV_AMULET_SEARCHING 5
+#define SV_AMULET_BRILLANCE 6
+#define SV_AMULET_CHARISMA 7
+#define SV_AMULET_THE_MAGI 8
+#define SV_AMULET_REFLECTION 9
+#define SV_AMULET_CARLAMMAS 10
+#define SV_AMULET_INGWE 11
+#define SV_AMULET_DWARVES 12
+#define SV_AMULET_NO_MAGIC 13
+#define SV_AMULET_NO_TELE 14
+#define SV_AMULET_RESISTANCE 15
+#define SV_AMULET_NOTHING 16
+#define SV_AMULET_SERPENT 17
+#define SV_AMULET_TORIS_MEJISTOS 18
+#define SV_AMULET_TRICKERY 23
+#define SV_AMULET_DEVOTION 25
+#define SV_AMULET_WEAPONMASTERY 24
+#define SV_AMULET_WISDOM 28
+#define SV_AMULET_INFRA 26
+#define SV_AMULET_SPELL 27
+
+/* The sval codes for TV_RING */
+#define SV_RING_WOE 0
+#define SV_RING_AGGRAVATION 1
+#define SV_RING_WEAKNESS 2
+#define SV_RING_STUPIDITY 3
+#define SV_RING_TELEPORTATION 4
+#define SV_RING_SPECIAL 5
+#define SV_RING_SLOW_DIGESTION 6
+#define SV_RING_FEATHER_FALL 7
+#define SV_RING_RESIST_FIRE 8
+#define SV_RING_RESIST_COLD 9
+#define SV_RING_SUSTAIN_STR 10
+#define SV_RING_SUSTAIN_INT 11
+#define SV_RING_SUSTAIN_WIS 12
+#define SV_RING_SUSTAIN_DEX 13
+#define SV_RING_SUSTAIN_CON 14
+#define SV_RING_SUSTAIN_CHR 15
+#define SV_RING_PROTECTION 16
+#define SV_RING_ACID 17
+#define SV_RING_FLAMES 18
+#define SV_RING_ICE 19
+#define SV_RING_RESIST_POIS 20
+#define SV_RING_FREE_ACTION 21
+#define SV_RING_SEE_INVIS 22
+#define SV_RING_SEARCHING 23
+#define SV_RING_STR 24
+#define SV_RING_INT 25
+#define SV_RING_DEX 26
+#define SV_RING_CON 27
+#define SV_RING_ACCURACY 28
+#define SV_RING_DAMAGE 29
+#define SV_RING_SLAYING 30
+#define SV_RING_SPEED 31
+#define SV_RING_BARAHIR 32
+#define SV_RING_TULKAS 33
+#define SV_RING_NARYA 34
+#define SV_RING_NENYA 35
+#define SV_RING_VILYA 36
+#define SV_RING_POWER 37
+#define SV_RING_RES_FEAR 38
+#define SV_RING_RES_LD 39
+#define SV_RING_RES_NETHER 40
+#define SV_RING_RES_NEXUS 41
+#define SV_RING_RES_SOUND 42
+#define SV_RING_RES_CONFUSION 43
+#define SV_RING_RES_SHARDS 44
+#define SV_RING_RES_DISENCHANT 45
+#define SV_RING_RES_CHAOS 46
+#define SV_RING_RES_BLINDNESS 47
+#define SV_RING_LORDLY 48
+#define SV_RING_ATTACKS 49
+#define SV_RING_NOTHING 50
+#define SV_RING_PRECONITION 51
+#define SV_RING_FLAR 52
+#define SV_RING_INVIS 53
+#define SV_RING_FLYING 54
+#define SV_RING_WRAITH 55
+#define SV_RING_ELEC 56
+#define SV_RING_CRIT 57
+#define SV_RING_SPELL 58
+
+/* The "sval" codes for TV_STAFF */
+#define SV_STAFF_SCHOOL 1
+#define SV_STAFF_NOTHING 2
+
+/* The "sval" codes for TV_WAND */
+#define SV_WAND_SCHOOL 1
+#define SV_WAND_NOTHING 2
+
+/* The "sval" codes for TV_ROD(Rod Tips) */
+#define SV_ROD_NOTHING 0
+#define SV_ROD_DETECT_DOOR 1
+#define SV_ROD_IDENTIFY 2
+#define SV_ROD_RECALL 3
+#define SV_ROD_ILLUMINATION 4
+#define SV_ROD_MAPPING 5
+#define SV_ROD_DETECTION 6
+#define SV_ROD_PROBING 7
+#define SV_ROD_CURING 8
+#define SV_ROD_HEALING 9
+#define SV_ROD_RESTORATION 10
+#define SV_ROD_SPEED 11
+/* xxx (aimed) */
+#define SV_ROD_TELEPORT_AWAY 13
+#define SV_ROD_DISARMING 14
+#define SV_ROD_LITE 15
+#define SV_ROD_SLEEP_MONSTER 16
+#define SV_ROD_SLOW_MONSTER 17
+#define SV_ROD_DRAIN_LIFE 18
+#define SV_ROD_POLYMORPH 19
+#define SV_ROD_ACID_BOLT 20
+#define SV_ROD_ELEC_BOLT 21
+#define SV_ROD_FIRE_BOLT 22
+#define SV_ROD_COLD_BOLT 23
+#define SV_ROD_ACID_BALL 24
+#define SV_ROD_ELEC_BALL 25
+#define SV_ROD_FIRE_BALL 26
+#define SV_ROD_COLD_BALL 27
+#define SV_ROD_HAVOC 28
+#define SV_ROD_DETECT_TRAP 29
+#define SV_ROD_HOME 30
+
+
+/* The "sval" codes for TV_ROD_MAIN(Rods) */
+/* Note that the sval is the max mana capacity of the rod */
+
+#define SV_ROD_WOODEN 10
+#define SV_ROD_COPPER 20
+#define SV_ROD_IRON 50
+#define SV_ROD_ALUMINIUM 75
+#define SV_ROD_SILVER 100
+#define SV_ROD_GOLDEN 125
+#define SV_ROD_MITHRIL 160
+#define SV_ROD_ADMANTITE 200
+
+
+/* The "sval" codes for TV_SCROLL */
+
+#define SV_SCROLL_DARKNESS 0
+#define SV_SCROLL_AGGRAVATE_MONSTER 1
+#define SV_SCROLL_CURSE_ARMOR 2
+#define SV_SCROLL_CURSE_WEAPON 3
+#define SV_SCROLL_SUMMON_MONSTER 4
+#define SV_SCROLL_SUMMON_UNDEAD 5
+#define SV_SCROLL_SUMMON_MINE 6
+#define SV_SCROLL_TRAP_CREATION 7
+#define SV_SCROLL_PHASE_DOOR 8
+#define SV_SCROLL_TELEPORT 9
+#define SV_SCROLL_TELEPORT_LEVEL 10
+#define SV_SCROLL_WORD_OF_RECALL 11
+#define SV_SCROLL_IDENTIFY 12
+#define SV_SCROLL_STAR_IDENTIFY 13
+#define SV_SCROLL_REMOVE_CURSE 14
+#define SV_SCROLL_STAR_REMOVE_CURSE 15
+#define SV_SCROLL_ENCHANT_ARMOR 16
+#define SV_SCROLL_ENCHANT_WEAPON_TO_HIT 17
+#define SV_SCROLL_ENCHANT_WEAPON_TO_DAM 18
+#define SV_SCROLL_ENCHANT_WEAPON_PVAL 19
+#define SV_SCROLL_STAR_ENCHANT_ARMOR 20
+#define SV_SCROLL_STAR_ENCHANT_WEAPON 21
+#define SV_SCROLL_RECHARGING 22
+#define SV_SCROLL_RESET_RECALL 23
+#define SV_SCROLL_LIGHT 24
+#define SV_SCROLL_MAPPING 25
+#define SV_SCROLL_DETECT_GOLD 26
+#define SV_SCROLL_DETECT_ITEM 27
+#define SV_SCROLL_DETECT_TRAP 28
+#define SV_SCROLL_DETECT_DOOR 29
+#define SV_SCROLL_DETECT_INVIS 30
+#define SV_SCROLL_DIVINATION 31
+#define SV_SCROLL_SATISFY_HUNGER 32
+#define SV_SCROLL_BLESSING 33
+#define SV_SCROLL_HOLY_CHANT 34
+#define SV_SCROLL_HOLY_PRAYER 35
+#define SV_SCROLL_MONSTER_CONFUSION 36
+#define SV_SCROLL_PROTECTION_FROM_EVIL 37
+#define SV_SCROLL_RUNE_OF_PROTECTION 38
+#define SV_SCROLL_TRAP_DOOR_DESTRUCTION 39
+#define SV_SCROLL_DEINCARNATION 40
+#define SV_SCROLL_STAR_DESTRUCTION 41
+#define SV_SCROLL_DISPEL_UNDEAD 42
+#define SV_SCROLL_MASS_RESURECTION 43
+#define SV_SCROLL_GENOCIDE 44
+#define SV_SCROLL_MASS_GENOCIDE 45
+#define SV_SCROLL_ACQUIREMENT 46
+#define SV_SCROLL_STAR_ACQUIREMENT 47
+#define SV_SCROLL_FIRE 48
+#define SV_SCROLL_ICE 49
+#define SV_SCROLL_CHAOS 50
+#define SV_SCROLL_RUMOR 51
+#define SV_SCROLL_ARTIFACT 52
+#define SV_SCROLL_NOTHING 53
+
+/* The "sval" codes for TV_POTION */
+#define SV_POTION_WATER 0
+#define SV_POTION_APPLE_JUICE 1
+#define SV_POTION_SLIME_MOLD 2
+#define SV_POTION_BLOOD 3
+#define SV_POTION_SLOWNESS 4
+#define SV_POTION_SALT_WATER 5
+#define SV_POTION_POISON 6
+#define SV_POTION_BLINDNESS 7
+#define SV_POTION_INVIS 8
+#define SV_POTION_CONFUSION 9
+#define SV_POTION_MUTATION 10
+#define SV_POTION_SLEEP 11
+#define SV_POTION_LEARNING 12
+#define SV_POTION_LOSE_MEMORIES 13
+/* xxx */
+#define SV_POTION_RUINATION 15
+#define SV_POTION_DEC_STR 16
+#define SV_POTION_DEC_INT 17
+#define SV_POTION_DEC_WIS 18
+#define SV_POTION_DEC_DEX 19
+#define SV_POTION_DEC_CON 20
+#define SV_POTION_DEC_CHR 21
+#define SV_POTION_DETONATIONS 22
+#define SV_POTION_DEATH 23
+#define SV_POTION_INFRAVISION 24
+#define SV_POTION_DETECT_INVIS 25
+#define SV_POTION_SLOW_POISON 26
+#define SV_POTION_CURE_POISON 27
+#define SV_POTION_BOLDNESS 28
+#define SV_POTION_SPEED 29
+#define SV_POTION_RESIST_HEAT 30
+#define SV_POTION_RESIST_COLD 31
+#define SV_POTION_HEROISM 32
+#define SV_POTION_BESERK_STRENGTH 33
+#define SV_POTION_CURE_LIGHT 34
+#define SV_POTION_CURE_SERIOUS 35
+#define SV_POTION_CURE_CRITICAL 36
+#define SV_POTION_HEALING 37
+#define SV_POTION_STAR_HEALING 38
+#define SV_POTION_LIFE 39
+#define SV_POTION_RESTORE_MANA 40
+#define SV_POTION_RESTORE_EXP 41
+#define SV_POTION_RES_STR 42
+#define SV_POTION_RES_INT 43
+#define SV_POTION_RES_WIS 44
+#define SV_POTION_RES_DEX 45
+#define SV_POTION_RES_CON 46
+#define SV_POTION_RES_CHR 47
+#define SV_POTION_INC_STR 48
+#define SV_POTION_INC_INT 49
+#define SV_POTION_INC_WIS 50
+#define SV_POTION_INC_DEX 51
+#define SV_POTION_INC_CON 52
+#define SV_POTION_INC_CHR 53
+/* xxx */
+#define SV_POTION_AUGMENTATION 55
+#define SV_POTION_ENLIGHTENMENT 56
+#define SV_POTION_STAR_ENLIGHTENMENT 57
+#define SV_POTION_SELF_KNOWLEDGE 58
+#define SV_POTION_EXPERIENCE 59
+#define SV_POTION_RESISTANCE 60
+#define SV_POTION_CURING 61
+#define SV_POTION_INVULNERABILITY 62
+#define SV_POTION_NEW_LIFE 63
+
+#define SV_POTION_LAST 63
+
+/* The "sval" codes for TV_POTION2 */
+#define SV_POTION2_MIMIC 1
+#define SV_POTION2_CURE_LIGHT_SANITY 14
+#define SV_POTION2_CURE_SERIOUS_SANITY 15
+#define SV_POTION2_CURE_CRITICAL_SANITY 16
+#define SV_POTION2_CURE_SANITY 17
+#define SV_POTION2_CURE_WATER 18
+
+#define SV_POTION2_LAST 18
+
+/* The "sval" codes for TV_FOOD */
+#define SV_FOOD_POISON 0
+#define SV_FOOD_BLINDNESS 1
+#define SV_FOOD_PARANOIA 2
+#define SV_FOOD_CONFUSION 3
+#define SV_FOOD_HALLUCINATION 4
+#define SV_FOOD_PARALYSIS 5
+#define SV_FOOD_WEAKNESS 6
+#define SV_FOOD_SICKNESS 7
+#define SV_FOOD_STUPIDITY 8
+#define SV_FOOD_NAIVETY 9
+#define SV_FOOD_UNHEALTH 10
+#define SV_FOOD_DISEASE 11
+#define SV_FOOD_CURE_POISON 12
+#define SV_FOOD_CURE_BLINDNESS 13
+#define SV_FOOD_CURE_PARANOIA 14
+#define SV_FOOD_CURE_CONFUSION 15
+#define SV_FOOD_CURE_SERIOUS 16
+#define SV_FOOD_RESTORE_STR 17
+#define SV_FOOD_RESTORE_CON 18
+#define SV_FOOD_RESTORING 19
+/* many missing mushrooms */
+#define SV_FOOD_BISCUIT 32
+#define SV_FOOD_JERKY 33
+#define SV_FOOD_RATION 35
+#define SV_FOOD_SLIME_MOLD 36
+#define SV_FOOD_WAYBREAD 37
+#define SV_FOOD_PINT_OF_ALE 38
+#define SV_FOOD_PINT_OF_WINE 39
+#define SV_FOOD_ATHELAS 40
+#define SV_FOOD_GREAT_HEALTH 41
+#define SV_FOOD_FORTUNE_COOKIE 42
+
+/* The "sval" codes for TV_BATERIE */
+#define SV_BATERIE_POISON 1
+#define SV_BATERIE_EXPLOSION 2
+#define SV_BATERIE_TELEPORT 3
+#define SV_BATERIE_COLD 4
+#define SV_BATERIE_FIRE 5
+#define SV_BATERIE_ACID 6
+#define SV_BATERIE_LIFE 7
+#define SV_BATERIE_CONFUSION 8
+#define SV_BATERIE_LITE 9
+#define SV_BATERIE_CHAOS 10
+#define SV_BATERIE_TIME 11
+#define SV_BATERIE_MAGIC 12
+#define SV_BATERIE_XTRA_LIFE 13
+#define SV_BATERIE_DARKNESS 14
+#define SV_BATERIE_KNOWLEDGE 15
+#define SV_BATERIE_FORCE 16
+#define SV_BATERIE_LIGHTNING 17
+#define SV_BATERIE_MANA 18
+
+/* The "sval" codes for TV_CORPSE */
+#define SV_CORPSE_CORPSE 1
+#define SV_CORPSE_SKELETON 2
+#define SV_CORPSE_HEAD 3
+#define SV_CORPSE_SKULL 4
+#define SV_CORPSE_MEAT 5
+
+/* The "sval" codes for TV_DAEMON_BOOK */
+#define SV_DEMONBLADE 55
+#define SV_DEMONSHIELD 56
+#define SV_DEMONHORN 57
+
+/*
+ * Special Object Flags
+ */
+#define IDENT_SENSE 0x01 /* Item has been "sensed" */
+#define IDENT_FIXED 0x02 /* Item has been "haggled" */
+#define IDENT_EMPTY 0x04 /* Item charges are known */
+#define IDENT_KNOWN 0x08 /* Item abilities are known */
+#define IDENT_STOREB 0x10 /* Item is storebought !!!! */
+#define IDENT_MENTAL 0x20 /* Item information is known */
+#define IDENT_CURSED 0x40 /* Item is temporarily cursed */
+
+/*
+ * Location of objects when they were found
+ */
+#define OBJ_FOUND_MONSTER 1
+#define OBJ_FOUND_FLOOR 2
+#define OBJ_FOUND_VAULT 3
+#define OBJ_FOUND_SPECIAL 4
+#define OBJ_FOUND_RUBBLE 5
+#define OBJ_FOUND_REWARD 6
+#define OBJ_FOUND_STORE 7
+#define OBJ_FOUND_STOLEN 8
+#define OBJ_FOUND_SELFMADE 9
+
+struct obj_theme
+{
+ byte treasure;
+ byte combat;
+ byte magic;
+ byte tools;
+};
+
+struct object_kind
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+
+ byte tval; /* Object type */
+ byte sval; /* Object sub type */
+
+ s32b pval; /* Object extra info */
+ s32b pval2; /* Object extra info */
+
+ s16b to_h; /* Bonus to hit */
+ s16b to_d; /* Bonus to damage */
+ s16b to_a; /* Bonus to armor */
+
+ s16b ac; /* Base armor */
+
+ byte dd;
+ byte ds; /* Damage dice/sides */
+
+ s32b weight; /* Weight */
+
+ s32b cost; /* Object "base cost" */
+
+ u32b flags1; /* Flags, set 1 */
+ u32b flags2; /* Flags, set 2 */
+ u32b flags3; /* Flags, set 3 */
+ u32b flags4; /* Flags, set 4 */
+ u32b flags5; /* Flags, set 5 */
+
+ byte locale[4]; /* Allocation level(s) */
+ byte chance[4]; /* Allocation chance(s) */
+
+ byte level; /* Level */
+ byte extra; /* Something */
+
+
+ byte d_attr; /* Default object attribute */
+ char d_char; /* Default object character */
+
+
+ byte x_attr; /* Desired object attribute */
+ char x_char; /* Desired object character */
+
+
+ byte flavor; /* Special object flavor (or zero) */
+
+ bool easy_know; /* This object is always known (if aware) */
+
+
+ bool aware; /* The player is "aware" of the item's effects */
+
+ bool tried; /* The player has "tried" one of the items */
+
+ bool know; /* extractable flag for the alchemist */
+
+ u32b esp; /* ESP flags */
+
+ byte btval; /* Become Object type */
+ byte bsval; /* Become Object sub type */
+ bool artifact; /* Is it a normal artifact(already generated) */
+
+ s16b power; /* Power granted(if any) */
+};
+
+struct artifact_type
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+
+ byte tval; /* Artifact type */
+ byte sval; /* Artifact sub type */
+
+ s16b pval; /* Artifact extra info */
+
+ s16b to_h; /* Bonus to hit */
+ s16b to_d; /* Bonus to damage */
+ s16b to_a; /* Bonus to armor */
+
+ s16b ac; /* Base armor */
+
+ byte dd;
+ byte ds; /* Damage when hits */
+
+ s16b weight; /* Weight */
+
+ s32b cost; /* Artifact "cost" */
+
+ u32b flags1; /* Artifact Flags, set 1 */
+ u32b flags2; /* Artifact Flags, set 2 */
+ u32b flags3; /* Artifact Flags, set 3 */
+ u32b flags4; /* Artifact Flags, set 4 */
+ u32b flags5; /* Artifact Flags, set 5 */
+
+ byte level; /* Artifact level */
+ byte rarity; /* Artifact rarity */
+
+ byte cur_num; /* Number created (0 or 1) */
+ byte max_num; /* Unused (should be "1") */
+
+ u32b esp; /* ESP flags */
+
+ s16b power; /* Power granted(if any) */
+};
+
+struct ego_item_type
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+
+ bool before; /* Before or after the object name ? */
+
+ byte tval[6];
+ byte min_sval[6];
+ byte max_sval[6];
+
+ byte rating; /* Rating boost */
+
+ byte level; /* Minimum level */
+ byte rarity; /* Object rarity */
+ byte mrarity; /* Object rarity */
+
+ s16b max_to_h; /* Maximum to-hit bonus */
+ s16b max_to_d; /* Maximum to-dam bonus */
+ s16b max_to_a; /* Maximum to-ac bonus */
+
+ s32b max_pval; /* Maximum pval */
+
+ s32b cost; /* Ego-item "cost" */
+
+ byte rar[5];
+ u32b flags1[5]; /* Ego-Item Flags, set 1 */
+ u32b flags2[5]; /* Ego-Item Flags, set 2 */
+ u32b flags3[5]; /* Ego-Item Flags, set 3 */
+ u32b flags4[5]; /* Ego-Item Flags, set 4 */
+ u32b flags5[5]; /* Ego-Item Flags, set 5 */
+ u32b esp[5]; /* ESP flags */
+ u32b fego[5]; /* ego flags */
+
+ s16b power; /* Power granted(if any) */
+};
+
+struct object_type
+{
+ s16b k_idx; /* Kind index (zero if "dead") */
+
+ byte iy; /* Y-position on map, or zero */
+ byte ix; /* X-position on map, or zero */
+
+ byte tval; /* Item type (from kind) */
+ byte sval; /* Item sub-type (from kind) */
+
+ s32b pval; /* Item extra-parameter */
+ s16b pval2; /* Item extra-parameter for some special
+ items*/
+ s32b pval3; /* Item extra-parameter for some special
+ items*/
+
+ byte discount; /* Discount (if any) */
+
+ byte number; /* Number of items */
+
+ s32b weight; /* Item weight */
+
+ byte elevel; /* Item exp level */
+ s32b exp; /* Item exp */
+
+ byte name1; /* Artifact type, if any */
+ s16b name2; /* Ego-Item type, if any */
+ s16b name2b; /* Second Ego-Item type, if any */
+
+ byte xtra1; /* Extra info type */
+ s16b xtra2; /* Extra info index */
+
+ s16b to_h; /* Plusses to hit */
+ s16b to_d; /* Plusses to damage */
+ s16b to_a; /* Plusses to AC */
+
+ s16b ac; /* Normal AC */
+
+ byte dd;
+ byte ds; /* Damage dice/sides */
+
+ s16b timeout; /* Timeout Counter */
+
+ byte ident; /* Special flags */
+
+ byte marked; /* Object is marked */
+
+ u16b note; /* Inscription index */
+ u16b art_name; /* Artifact name (random artifacts) */
+
+ u32b art_flags1; /* Flags, set 1 Alas, these were necessary */
+ u32b art_flags2; /* Flags, set 2 for the random artifacts of*/
+ u32b art_flags3; /* Flags, set 3 Zangband */
+ u32b art_flags4; /* Flags, set 4 PernAngband */
+ u32b art_flags5; /* Flags, set 5 PernAngband */
+ u32b art_esp; /* Flags, set esp PernAngband */
+
+ s16b next_o_idx; /* Next object in stack (if any) */
+
+ s16b held_m_idx; /* Monster holding us (if any) */
+
+ byte sense; /* Pseudo-id status */
+
+ byte found; /* How did we find it */
+ s16b found_aux1; /* Stores info for found */
+ s16b found_aux2; /* Stores info for found */
+};
+
+/* Pseudo-id defines */
+#define SENSE_NONE 0
+#define SENSE_CURSED 1
+#define SENSE_AVERAGE 2
+#define SENSE_GOOD_LIGHT 3
+#define SENSE_GOOD_HEAVY 4
+#define SENSE_EXCELLENT 5
+#define SENSE_WORTHLESS 6
+#define SENSE_TERRIBLE 7
+#define SENSE_SPECIAL 8
+#define SENSE_BROKEN 9
+#define SENSE_UNCURSED 10
+
+extern object_type o_list[max_o_idx];
+extern object_kind k_info[max_k_idx];
+extern char *k_name;
+extern char *k_text;
+extern artifact_type a_info[max_a_idx];
+extern char *a_name;
+extern char *a_text;
+extern header *e_head;
+extern ego_item_type e_info[max_e_idx];
+extern char *e_name;
+extern char *e_text;
+
+extern s16b m_bonus(int max, int level);
+extern s16b wield_slot_ideal(object_type *o_ptr, bool ideal);
+extern s16b wield_slot(object_type *o_ptr);
+extern void object_flags(object_type *o_ptr, u32b *f1 = 0, u32b *f2 = 0, u32b *f3 = 0, u32b *f4 = 0, u32b *f5 = 0, u32b *esp = 0);
+extern char *lua_object_desc @ object_desc(object_type *o_ptr, int pref, int mode);
+extern bool object_out_desc(object_type *o_ptr, FILE *fff, bool trim_down, bool wait_for_it);
+extern void inven_item_describe(int item);
+extern void inven_item_increase(int item, int num);
+extern bool inven_item_optimize(int item);
+extern void floor_item_describe(int item);
+extern void floor_item_increase(int item, int num);
+extern void floor_item_optimize(int item);
+extern void delete_object_idx(int o_idx);
+extern s16b o_pop(void);
+extern errr get_obj_num_prep(void);
+extern bool ident_all(void);
+extern s16b get_obj_num(int level);
+extern s16b lookup_kind(int tval, int sval);
+extern void object_wipe(object_type *o_ptr);
+extern void object_prep(object_type *o_ptr, int k_idx);
+extern void object_copy(object_type *o_ptr, object_type *j_ptr);
+extern bool inven_carry_okay(object_type *o_ptr);
+extern void apply_magic(object_type *o_ptr, int lev, bool okay, bool good, bool great);
+extern bool make_object(object_type *j_ptr, bool good, bool great, obj_theme theme);
+extern s16b drop_near(object_type *o_ptr, int chance, int y, int x);
+extern object_type *get_object(int item);
+extern object_type *new_object();
+extern void end_object(object_type *o_ptr);
+extern bool get_item @ get_item_aux(int *cp, cptr pmt, cptr str, int mode);
+extern void lua_set_item_tester(int tval, char *fct);
+extern bool is_magestaff();
+extern void identify_pack_fully(void);
+extern s16b inven_carry(object_type *o_ptr, bool final);
+extern s32b calc_total_weight(void);
+extern int get_slot(int slot);
+extern bool is_blessed(object_type *o_ptr);
+extern cptr sense_desc[1000]; /* 1000 is just a hack for tolua */
+extern void object_pickup(int this_o_idx);
+
+$static bool lua_is_artifact(object_type *o_ptr) { return artifact_p(o_ptr); }
+static bool lua_is_artifact@is_artifact(object_type *o_ptr);
+
+$static bool lua_is_aware(object_type *o_ptr) { return object_aware_p(o_ptr); }
+static bool lua_is_aware@is_aware(object_type *o_ptr);
+
+$static bool lua_is_known(object_type *o_ptr) { return object_known_p(o_ptr); }
+static bool lua_is_known@is_known(object_type *o_ptr);
+
+$static void lua_set_aware(object_type *o_ptr) { object_aware(o_ptr); }
+static void lua_set_aware@set_aware(object_type *o_ptr);
+
+$static void lua_set_known(object_type *o_ptr) { object_known(o_ptr); }
+static void lua_set_known@set_known(object_type *o_ptr);
+
+extern byte value_check_aux1(object_type *o_ptr);
+extern byte value_check_aux1_magic(object_type *o_ptr);
+extern byte value_check_aux2(object_type *o_ptr);
+extern byte value_check_aux2_magic(object_type *o_ptr);
+
+extern bool remove_curse_object(object_type *o_ptr, bool all);
diff --git a/src/object1.c b/src/object1.c
new file mode 100644
index 00000000..fef7fb85
--- /dev/null
+++ b/src/object1.c
@@ -0,0 +1,6669 @@
+/* File: object1.c */
+
+/* Purpose: Object code, part 1 */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Hack -- note that "TERM_MULTI" is now just "TERM_VIOLET".
+ * We will have to find a cleaner method for "MULTI_HUED" later.
+ * There were only two multi-hued "flavors" (one potion, one food).
+ * Plus five multi-hued "base-objects" (3 dragon scales, one blade
+ * of chaos, and one something else). See the SHIMMER_OBJECTS code
+ * in "dungeon.c" and the object color extractor in "cave.c".
+ */
+#define TERM_MULTI TERM_VIOLET
+
+
+/*
+ * Max sizes of the following arrays
+ */
+#define MAX_ROCKS 62 /* Used with rings (min 58) */
+#define MAX_AMULETS 34 /* Used with amulets (min 30) */
+#define MAX_WOODS 35 /* Used with staffs (min 32) */
+#define MAX_METALS 39 /* Used with wands/rods (min 32/30) */
+#define MAX_COLORS 66 /* Used with potions (min 62) */
+#define MAX_SHROOM 20 /* Used with mushrooms (min 20) */
+#define MAX_TITLES 55 /* Used with scrolls (min 55) */
+#define MAX_SYLLABLES 164 /* Used with scrolls (see below) */
+
+
+/*
+ * Rings (adjectives and colors)
+ */
+
+static cptr ring_adj[MAX_ROCKS] =
+{
+ "Alexandrite", "Amethyst", "Aquamarine", "Azurite", "Beryl",
+ "Bloodstone", "Calcite", "Carnelian", "Corundum", "Diamond",
+ "Emerald", "Fluorite", "Garnet", "Granite", "Jade",
+ "Jasper", "Lapis Lazuli", "Malachite", "Marble", "Moonstone",
+ "Onyx", "Opal", "Pearl", "Quartz", "Quartzite",
+ "Rhodonite", "Ruby", "Sapphire", "Tiger Eye", "Topaz",
+ "Turquoise", "Zircon", "Platinum", "Bronze", "Gold",
+ "Obsidian", "Silver", "Tortoise Shell", "Mithril", "Jet",
+ "Engagement", "Adamantite",
+ "Wire", "Dilithium", "Bone", "Wooden",
+ "Spikard", "Serpent", "Wedding", "Double",
+ "Plain", "Brass", "Scarab", "Shining",
+ "Rusty", "Transparent", "Copper", "Black Opal", "Nickel",
+ "Glass", "Fluorspar", "Agate",
+};
+
+static byte ring_col[MAX_ROCKS] =
+{
+ TERM_GREEN, TERM_VIOLET, TERM_L_BLUE, TERM_L_BLUE, TERM_L_GREEN,
+ TERM_RED, TERM_WHITE, TERM_RED, TERM_SLATE, TERM_WHITE,
+ TERM_GREEN, TERM_L_GREEN, TERM_RED, TERM_L_DARK, TERM_L_GREEN,
+ TERM_UMBER, TERM_BLUE, TERM_GREEN, TERM_WHITE, TERM_L_WHITE,
+ TERM_L_RED, TERM_L_WHITE, TERM_WHITE, TERM_L_WHITE, TERM_L_WHITE,
+ TERM_L_RED, TERM_RED, TERM_BLUE, TERM_YELLOW, TERM_YELLOW,
+ TERM_L_BLUE, TERM_L_UMBER, TERM_WHITE, TERM_L_UMBER, TERM_YELLOW,
+ TERM_L_DARK, TERM_L_WHITE, TERM_GREEN, TERM_L_BLUE, TERM_L_DARK,
+ TERM_YELLOW, TERM_VIOLET,
+ TERM_UMBER, TERM_L_WHITE, TERM_WHITE, TERM_UMBER,
+ TERM_BLUE, TERM_GREEN, TERM_YELLOW, TERM_ORANGE,
+ TERM_YELLOW, TERM_ORANGE, TERM_L_GREEN, TERM_YELLOW,
+ TERM_RED, TERM_WHITE, TERM_UMBER, TERM_L_DARK, TERM_L_WHITE,
+ TERM_WHITE, TERM_BLUE, TERM_L_WHITE
+};
+
+
+/*
+ * Amulets (adjectives and colors)
+ */
+
+static cptr amulet_adj[MAX_AMULETS] =
+{
+ "Amber", "Driftwood", "Coral", "Agate", "Ivory",
+ "Obsidian", "Bone", "Brass", "Bronze", "Pewter",
+ "Tortoise Shell", "Golden", "Azure", "Crystal", "Silver",
+ "Copper", "Amethyst", "Mithril", "Sapphire", "Dragon Tooth",
+ "Carved Oak", "Sea Shell", "Flint Stone", "Ruby", "Scarab",
+ "Origami Paper", "Meteoric Iron", "Platinum", "Glass", "Beryl",
+ "Malachite", "Adamantite", "Mother-of-pearl", "Runed"
+};
+
+static byte amulet_col[MAX_AMULETS] =
+{
+ TERM_YELLOW, TERM_L_UMBER, TERM_WHITE, TERM_L_WHITE, TERM_WHITE,
+ TERM_L_DARK, TERM_WHITE, TERM_ORANGE, TERM_L_UMBER, TERM_SLATE,
+ TERM_GREEN, TERM_YELLOW, TERM_L_BLUE, TERM_L_BLUE, TERM_L_WHITE,
+ TERM_L_UMBER, TERM_VIOLET, TERM_L_BLUE, TERM_BLUE, TERM_L_WHITE,
+ TERM_UMBER, TERM_L_BLUE, TERM_SLATE, TERM_RED, TERM_L_GREEN,
+ TERM_WHITE, TERM_L_DARK, TERM_L_WHITE, TERM_WHITE, TERM_L_GREEN,
+ TERM_GREEN, TERM_VIOLET, TERM_L_WHITE, TERM_UMBER
+};
+
+
+/*
+ * Staffs (adjectives and colors)
+ */
+
+static cptr staff_adj[MAX_WOODS] =
+{
+ "Aspen", "Balsa", "Banyan", "Birch", "Cedar",
+ "Cottonwood", "Cypress", "Dogwood", "Elm", "Eucalyptus",
+ "Hemlock", "Hickory", "Ironwood", "Locust", "Mahogany",
+ "Maple", "Mulberry", "Oak", "Pine", "Redwood",
+ "Rosewood", "Spruce", "Sycamore", "Teak", "Walnut",
+ "Mistletoe", "Hawthorn", "Bamboo", "Silver", "Runed",
+ "Golden", "Ashen", "Gnarled", "Ivory", "Willow"
+};
+
+static byte staff_col[MAX_WOODS] =
+{
+ TERM_L_UMBER, TERM_L_UMBER, TERM_L_UMBER, TERM_L_UMBER, TERM_L_UMBER,
+ TERM_L_UMBER, TERM_L_UMBER, TERM_L_UMBER, TERM_L_UMBER, TERM_L_UMBER,
+ TERM_L_UMBER, TERM_L_UMBER, TERM_UMBER, TERM_L_UMBER, TERM_UMBER,
+ TERM_L_UMBER, TERM_L_UMBER, TERM_L_UMBER, TERM_L_UMBER, TERM_RED,
+ TERM_RED, TERM_L_UMBER, TERM_L_UMBER, TERM_L_UMBER, TERM_UMBER,
+ TERM_GREEN, TERM_L_UMBER, TERM_L_UMBER, TERM_L_WHITE, TERM_UMBER,
+ TERM_YELLOW, TERM_SLATE, TERM_UMBER, TERM_L_WHITE, TERM_L_UMBER
+};
+
+
+/*
+ * Wands (adjectives and colors)
+ */
+
+static cptr wand_adj[MAX_METALS] =
+{
+ "Aluminium", "Cast Iron", "Chromium", "Copper", "Gold",
+ "Iron", "Magnesium", "Molybdenum", "Nickel", "Rusty",
+ "Silver", "Steel", "Tin", "Titanium", "Tungsten",
+ "Zirconium", "Zinc", "Aluminium-Plated", "Copper-Plated", "Gold-Plated",
+ "Nickel-Plated", "Silver-Plated", "Steel-Plated", "Tin-Plated", "Zinc-Plated",
+ "Mithril-Plated", "Mithril", "Runed", "Bronze", "Brass",
+ "Platinum", "Lead", "Lead-Plated", "Ivory" , "Adamantite",
+ "Uridium", "Long", "Short", "Hexagonal"
+};
+
+static byte wand_col[MAX_METALS] =
+{
+ TERM_L_BLUE, TERM_L_DARK, TERM_WHITE, TERM_UMBER, TERM_YELLOW,
+ TERM_SLATE, TERM_L_WHITE, TERM_L_WHITE, TERM_L_WHITE, TERM_RED,
+ TERM_L_WHITE, TERM_L_WHITE, TERM_L_WHITE, TERM_WHITE, TERM_WHITE,
+ TERM_L_WHITE, TERM_L_WHITE, TERM_L_BLUE, TERM_L_UMBER, TERM_YELLOW,
+ TERM_L_UMBER, TERM_L_WHITE, TERM_L_WHITE, TERM_L_WHITE, TERM_L_WHITE,
+ TERM_L_BLUE, TERM_L_BLUE, TERM_UMBER, TERM_L_UMBER, TERM_L_UMBER,
+ TERM_WHITE, TERM_SLATE, TERM_SLATE, TERM_WHITE, TERM_VIOLET,
+ TERM_L_RED, TERM_L_BLUE, TERM_BLUE, TERM_RED
+};
+
+
+/*
+ * Rods (adjectives and colors).
+ * Efficiency -- copied from wand arrays
+ */
+
+static cptr rod_adj[MAX_METALS];
+
+static byte rod_col[MAX_METALS];
+
+
+/*
+ * Mushrooms (adjectives and colors)
+ */
+
+static cptr food_adj[MAX_SHROOM] =
+{
+ "Blue", "Black", "Black Spotted", "Brown", "Dark Blue",
+ "Dark Green", "Dark Red", "Yellow", "Furry", "Green",
+ "Grey", "Light Blue", "Light Green", "Violet", "Red",
+ "Slimy", "Tan", "White", "White Spotted", "Wrinkled",
+};
+
+static byte food_col[MAX_SHROOM] =
+{
+ TERM_BLUE, TERM_L_DARK, TERM_L_DARK, TERM_UMBER, TERM_BLUE,
+ TERM_GREEN, TERM_RED, TERM_YELLOW, TERM_L_WHITE, TERM_GREEN,
+ TERM_SLATE, TERM_L_BLUE, TERM_L_GREEN, TERM_VIOLET, TERM_RED,
+ TERM_SLATE, TERM_L_UMBER, TERM_WHITE, TERM_WHITE, TERM_UMBER
+};
+
+
+/*
+ * Color adjectives and colors, for potions.
+ * Hack -- The first four entries are hard-coded.
+ * (water, apple juice, slime mold juice, something)
+ */
+
+static cptr potion_adj[MAX_COLORS] =
+{
+ "Clear", "Light Brown", "Icky Green", "Strangely Phosphorescent",
+ "Azure", "Blue", "Blue Speckled", "Black", "Brown", "Brown Speckled",
+ "Bubbling", "Chartreuse", "Cloudy", "Copper Speckled", "Crimson", "Cyan",
+ "Dark Blue", "Dark Green", "Dark Red", "Gold Speckled", "Green",
+ "Green Speckled", "Grey", "Grey Speckled", "Hazy", "Indigo",
+ "Light Blue", "Light Green", "Magenta", "Metallic Blue", "Metallic Red",
+ "Metallic Green", "Metallic Purple", "Misty", "Orange", "Orange Speckled",
+ "Pink", "Pink Speckled", "Puce", "Purple", "Purple Speckled",
+ "Red", "Red Speckled", "Silver Speckled", "Smoky", "Tangerine",
+ "Violet", "Vermilion", "White", "Yellow", "Violet Speckled",
+ "Pungent", "Clotted Red", "Viscous Pink", "Oily Yellow", "Gloopy Green",
+ "Shimmering", "Coagulated Crimson", "Yellow Speckled", "Gold",
+ "Manly", "Stinking", "Oily Black", "Ichor", "Ivory White", "Sky Blue",
+};
+
+static byte potion_col[MAX_COLORS] =
+{
+ TERM_WHITE, TERM_L_UMBER, TERM_GREEN, TERM_MULTI,
+ TERM_L_BLUE, TERM_BLUE, TERM_BLUE, TERM_L_DARK, TERM_UMBER, TERM_UMBER,
+ TERM_L_WHITE, TERM_L_GREEN, TERM_WHITE, TERM_L_UMBER, TERM_RED, TERM_L_BLUE,
+ TERM_BLUE, TERM_GREEN, TERM_RED, TERM_YELLOW, TERM_GREEN,
+ TERM_GREEN, TERM_SLATE, TERM_SLATE, TERM_L_WHITE, TERM_VIOLET,
+ TERM_L_BLUE, TERM_L_GREEN, TERM_RED, TERM_BLUE, TERM_RED,
+ TERM_GREEN, TERM_VIOLET, TERM_L_WHITE, TERM_ORANGE, TERM_ORANGE,
+ TERM_L_RED, TERM_L_RED, TERM_VIOLET, TERM_VIOLET, TERM_VIOLET,
+ TERM_RED, TERM_RED, TERM_L_WHITE, TERM_L_DARK, TERM_ORANGE,
+ TERM_VIOLET, TERM_RED, TERM_WHITE, TERM_YELLOW, TERM_VIOLET,
+ TERM_L_RED, TERM_RED, TERM_L_RED, TERM_YELLOW, TERM_GREEN,
+ TERM_MULTI, TERM_RED, TERM_YELLOW, TERM_YELLOW,
+ TERM_L_UMBER, TERM_UMBER, TERM_L_DARK, TERM_RED, TERM_WHITE, TERM_L_BLUE
+};
+
+
+/*
+ * Syllables for scrolls (must be 1-4 letters each)
+ */
+
+static cptr syllables[MAX_SYLLABLES] =
+{
+ "a", "ab", "ag", "aks", "ala", "an", "ankh", "app",
+ "arg", "arze", "ash", "aus", "ban", "bar", "bat", "bek",
+ "bie", "bin", "bit", "bjor", "blu", "bot", "bu",
+ "byt", "comp", "con", "cos", "cre", "dalf", "dan",
+ "den", "der", "doe", "dok", "eep", "el", "eng", "er", "ere", "erk",
+ "esh", "evs", "fa", "fid", "flit", "for", "fri", "fu", "gan",
+ "gar", "glen", "gop", "gre", "ha", "he", "hyd", "i",
+ "ing", "ion", "ip", "ish", "it", "ite", "iv", "jo",
+ "kho", "kli", "klis", "la", "lech", "man", "mar",
+ "me", "mi", "mic", "mik", "mon", "mung", "mur", "nag", "nej",
+ "nelg", "nep", "ner", "nes", "nis", "nih", "nin", "o",
+ "od", "ood", "org", "orn", "ox", "oxy", "pay", "pet",
+ "ple", "plu", "po", "pot", "prok", "re", "rea", "rhov",
+ "ri", "ro", "rog", "rok", "rol", "sa", "san", "sat",
+ "see", "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", "x",
+ "yerg", "yp", "zun", "tri", "blaa", "jah", "bul", "on",
+ "foo", "ju", "xuxu"
+};
+
+/*
+ * Hold the titles of scrolls, 6 to 14 characters each
+ * Also keep an array of scroll colors (always WHITE for now)
+ */
+
+static char scroll_adj[MAX_TITLES][16];
+
+static byte scroll_col[MAX_TITLES];
+
+
+/*
+ * Certain items have a flavor
+ * This function is used only by "flavor_init()"
+ */
+static bool_ object_flavor(int k_idx)
+{
+ object_kind *k_ptr = &k_info[k_idx];
+
+ /* Analyze the item */
+ switch (k_ptr->tval)
+ {
+ case TV_AMULET:
+ {
+ return (0x80 + amulet_col[k_ptr->sval]);
+ }
+
+ case TV_RING:
+ {
+ return (0x90 + ring_col[k_ptr->sval]);
+ }
+
+ case TV_STAFF:
+ {
+ return (0xA0 + staff_col[k_ptr->sval]);
+ }
+
+ case TV_WAND:
+ {
+ return (0xB0 + wand_col[k_ptr->sval]);
+ }
+
+ case TV_ROD:
+ {
+ return (0xC0 + rod_col[k_ptr->sval]);
+ }
+
+ case TV_SCROLL:
+ {
+ return (0xD0 + scroll_col[k_ptr->sval]);
+ }
+
+ case TV_POTION:
+ case TV_POTION2:
+ {
+ return (0xE0 + potion_col[k_ptr->sval]);
+ }
+
+ case TV_FOOD:
+ {
+ if (k_ptr->sval < SV_FOOD_MIN_FOOD)
+ {
+ return (0xF0 + food_col[k_ptr->sval]);
+ }
+
+ break;
+ }
+ }
+
+ /* No flavor */
+ return (0);
+}
+
+
+void get_table_name(char *out_string)
+{
+ int testcounter = (randint(3)) + 1;
+
+ strcpy(out_string, "'");
+
+ if (randint(3) == 2)
+ {
+ while (testcounter--)
+ strcat(out_string, syllables[(randint(MAX_SYLLABLES)) - 1]);
+ }
+
+ else
+ {
+ char Syllable[80];
+ testcounter = (randint(2)) + 1;
+ while (testcounter--)
+ {
+ get_rnd_line("elvish.txt", Syllable);
+ strcat(out_string, Syllable);
+ }
+ }
+
+ out_string[1] = toupper(out_string[1]);
+
+ strcat(out_string, "'");
+
+ out_string[18] = '\0';
+
+ return;
+}
+
+
+/*
+ * Certain items, if aware, are known instantly
+ * This function is used only by "flavor_init()"
+ *
+ * XXX XXX XXX Add "EASY_KNOW" flag to "k_info.txt" file
+ */
+static bool_ object_easy_know(int i)
+{
+ object_kind *k_ptr = &k_info[i];
+
+ /* Analyze the "tval" */
+ switch (k_ptr->tval)
+ {
+ /* Spellbooks */
+ case TV_DRUID_BOOK:
+ case TV_MUSIC_BOOK:
+ case TV_SYMBIOTIC_BOOK:
+ {
+ return (TRUE);
+ }
+
+ /* Simple items */
+ case TV_FLASK:
+ case TV_EGG:
+ case TV_BOTTLE:
+ case TV_SKELETON:
+ case TV_CORPSE:
+ case TV_HYPNOS:
+ case TV_SPIKE:
+ case TV_JUNK:
+ {
+ return (TRUE);
+ }
+
+ /* All Food, Potions, Scrolls, Rods */
+ case TV_FOOD:
+ case TV_POTION:
+ case TV_POTION2:
+ case TV_SCROLL:
+ case TV_ROD:
+ case TV_ROD_MAIN:
+ case TV_BATERIE:
+ {
+ if (k_ptr->flags3 & TR3_NORM_ART)
+ return ( FALSE );
+ return (TRUE);
+ }
+
+ /* Some Rings, Amulets, Lites */
+ case TV_RING:
+ case TV_AMULET:
+ case TV_LITE:
+ {
+ if (k_ptr->flags3 & (TR3_EASY_KNOW)) return (TRUE);
+ return (FALSE);
+ }
+ }
+
+ /* Nope */
+ return (FALSE);
+}
+
+/*
+ * Prepare the "variable" part of the "k_info" array.
+ *
+ * The "color"/"metal"/"type" of an item is its "flavor".
+ * For the most part, flavors are assigned randomly each game.
+ *
+ * Initialize descriptions for the "colored" objects, including:
+ * Rings, Amulets, Staffs, Wands, Rods, Food, Potions, Scrolls.
+ *
+ * The first 4 entries for potions are fixed (Water, Apple Juice,
+ * Slime Mold Juice, Unused Potion).
+ *
+ * Scroll titles are always between 6 and 14 letters long. This is
+ * ensured because every title is composed of whole words, where every
+ * word is from 1 to 8 letters long (one or two syllables of 1 to 4
+ * letters each), and that no scroll is finished until it attempts to
+ * grow beyond 15 letters. The first time this can happen is when the
+ * current title has 6 letters and the new word has 8 letters, which
+ * would result in a 6 letter scroll title.
+ *
+ * Duplicate titles are avoided by requiring that no two scrolls share
+ * the same first four letters (not the most efficient method, and not
+ * the least efficient method, but it will always work).
+ *
+ * Hack -- make sure everything stays the same for each saved game
+ * This is accomplished by the use of a saved "random seed", as in
+ * "town_gen()". Since no other functions are called while the special
+ * seed is in effect, so this function is pretty "safe".
+ *
+ * Note that the "hacked seed" may provide an RNG with alternating parity!
+ */
+void flavor_init(void)
+{
+ int i, j;
+
+ byte temp_col;
+
+ cptr temp_adj;
+
+
+ /* Hack -- Use the "simple" RNG */
+ Rand_quick = TRUE;
+
+ /* Hack -- Induce consistant flavors */
+ Rand_value = seed_flavor;
+
+
+ /* Efficiency -- Rods/Wands share initial array */
+ for (i = 0; i < MAX_METALS; i++)
+ {
+ rod_adj[i] = wand_adj[i];
+ rod_col[i] = wand_col[i];
+ }
+
+
+ /* Rings have "ring colors" */
+ for (i = 0; i < MAX_ROCKS; i++)
+ {
+ j = rand_int(MAX_ROCKS);
+ temp_adj = ring_adj[i];
+ ring_adj[i] = ring_adj[j];
+ ring_adj[j] = temp_adj;
+ temp_col = ring_col[i];
+ ring_col[i] = ring_col[j];
+ ring_col[j] = temp_col;
+ }
+
+ /* Amulets have "amulet colors" */
+ for (i = 0; i < MAX_AMULETS; i++)
+ {
+ j = rand_int(MAX_AMULETS);
+ temp_adj = amulet_adj[i];
+ amulet_adj[i] = amulet_adj[j];
+ amulet_adj[j] = temp_adj;
+ temp_col = amulet_col[i];
+ amulet_col[i] = amulet_col[j];
+ amulet_col[j] = temp_col;
+ }
+
+ /* Staffs */
+ for (i = 0; i < MAX_WOODS; i++)
+ {
+ j = rand_int(MAX_WOODS);
+ temp_adj = staff_adj[i];
+ staff_adj[i] = staff_adj[j];
+ staff_adj[j] = temp_adj;
+ temp_col = staff_col[i];
+ staff_col[i] = staff_col[j];
+ staff_col[j] = temp_col;
+ }
+
+ /* Wands */
+ for (i = 0; i < MAX_METALS; i++)
+ {
+ j = rand_int(MAX_METALS);
+ temp_adj = wand_adj[i];
+ wand_adj[i] = wand_adj[j];
+ wand_adj[j] = temp_adj;
+ temp_col = wand_col[i];
+ wand_col[i] = wand_col[j];
+ wand_col[j] = temp_col;
+ }
+
+ /* Rods */
+ for (i = 0; i < MAX_METALS; i++)
+ {
+ j = rand_int(MAX_METALS);
+ temp_adj = rod_adj[i];
+ rod_adj[i] = rod_adj[j];
+ rod_adj[j] = temp_adj;
+ temp_col = rod_col[i];
+ rod_col[i] = rod_col[j];
+ rod_col[j] = temp_col;
+ }
+
+ /* Foods (Mushrooms) */
+ for (i = 0; i < MAX_SHROOM; i++)
+ {
+ j = rand_int(MAX_SHROOM);
+ temp_adj = food_adj[i];
+ food_adj[i] = food_adj[j];
+ food_adj[j] = temp_adj;
+ temp_col = food_col[i];
+ food_col[i] = food_col[j];
+ food_col[j] = temp_col;
+ }
+
+ /* Potions */
+ for (i = 4; i < MAX_COLORS; i++)
+ {
+ j = rand_int(MAX_COLORS - 4) + 4;
+ temp_adj = potion_adj[i];
+ potion_adj[i] = potion_adj[j];
+ potion_adj[j] = temp_adj;
+ temp_col = potion_col[i];
+ potion_col[i] = potion_col[j];
+ potion_col[j] = temp_col;
+ }
+
+ /* Scrolls (random titles, always white) */
+ for (i = 0; i < MAX_TITLES; i++)
+ {
+ /* Get a new title */
+ while (TRUE)
+ {
+ char buf[80];
+
+ bool_ okay;
+
+ /* Start a new title */
+ buf[0] = '\0';
+
+ /* Collect words until done */
+ while (1)
+ {
+ int q, s;
+
+ char tmp[80];
+
+ /* Start a new word */
+ tmp[0] = '\0';
+
+ /* Choose one or two syllables */
+ s = ((rand_int(100) < 30) ? 1 : 2);
+
+ /* Add a one or two syllable word */
+ for (q = 0; q < s; q++)
+ {
+ /* Add the syllable */
+ strcat(tmp, syllables[rand_int(MAX_SYLLABLES)]);
+ }
+
+ /* Stop before getting too long */
+ if (strlen(buf) + 1 + strlen(tmp) > 15) break;
+
+ /* Add a space */
+ strcat(buf, " ");
+
+ /* Add the word */
+ strcat(buf, tmp);
+ }
+
+ /* Save the title */
+ strcpy(scroll_adj[i], buf + 1);
+
+ /* Assume okay */
+ okay = TRUE;
+
+ /* Check for "duplicate" scroll titles */
+ for (j = 0; j < i; j++)
+ {
+ cptr hack1 = scroll_adj[j];
+ cptr hack2 = scroll_adj[i];
+
+ /* Compare first four characters */
+ if (*hack1++ != *hack2++) continue;
+ if (*hack1++ != *hack2++) continue;
+ if (*hack1++ != *hack2++) continue;
+ if (*hack1++ != *hack2++) continue;
+
+ /* Not okay */
+ okay = FALSE;
+
+ /* Stop looking */
+ break;
+ }
+
+ /* Break when done */
+ if (okay) break;
+ }
+
+ /* All scrolls are white */
+ scroll_col[i] = TERM_WHITE;
+ }
+
+
+ /* Hack -- Use the "complex" RNG */
+ Rand_quick = FALSE;
+
+ /* Analyze every object */
+ for (i = 1; i < max_k_idx; i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+
+ /* Skip "empty" objects */
+ if (!k_ptr->name) continue;
+
+ /* Extract "flavor" (if any) */
+ k_ptr->flavor = object_flavor(i);
+
+ /* No flavor yields aware */
+ if ((!k_ptr->flavor) && (k_ptr->tval != TV_ROD_MAIN)) k_ptr->aware = TRUE;
+
+ /* Check for "easily known" */
+ k_ptr->easy_know = object_easy_know(i);
+ }
+}
+
+/*
+ * Reset the "visual" lists
+ *
+ * This involves resetting various things to their "default" state.
+ *
+ * If the "prefs" flag is TRUE, then we will also load the appropriate
+ * "user pref file" based on the current setting of the "use_graphics"
+ * flag. This is useful for switching "graphics" on/off.
+ *
+ * The features, objects, and monsters, should all be encoded in the
+ * relevant "font.pref" and/or "graf.prf" files. XXX XXX XXX
+ *
+ * The "prefs" parameter is no longer meaningful. XXX XXX XXX
+ */
+void reset_visuals(void)
+{
+ int i;
+
+ /* Extract some info about terrain features */
+ for (i = 0; i < max_f_idx; i++)
+ {
+ feature_type *f_ptr = &f_info[i];
+
+ /* Assume we will use the underlying values */
+ f_ptr->x_attr = f_ptr->d_attr;
+ f_ptr->x_char = f_ptr->d_char;
+ }
+
+ /* Extract default attr/char code for stores */
+ for (i = 0; i < max_st_idx; i++)
+ {
+ store_info_type *st_ptr = &st_info[i];
+
+ /* Default attr/char */
+ st_ptr->x_attr = st_ptr->d_attr;
+ st_ptr->x_char = st_ptr->d_char;
+ }
+
+ /* Extract default attr/char code for objects */
+ for (i = 0; i < max_k_idx; i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+
+ /* Default attr/char */
+ k_ptr->x_attr = k_ptr->d_attr;
+ k_ptr->x_char = k_ptr->d_char;
+ }
+
+ /* Extract default attr/char code for monsters */
+ for (i = 0; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ /* Default attr/char */
+ r_ptr->x_attr = r_ptr->d_attr;
+ r_ptr->x_char = r_ptr->d_char;
+ }
+
+ /* Reset attr/char code for ego monster overlay graphics */
+ for (i = 0; i < max_re_idx; i++)
+ {
+ monster_ego *re_ptr = &re_info[i];
+
+ /* Default attr/char */
+ re_ptr->g_attr = 0;
+ re_ptr->g_char = 0;
+ }
+
+ /* Reset attr/char code for race modifier overlay graphics */
+ for (i = 0; i < max_rmp_idx; i++)
+ {
+ player_race_mod *rmp_ptr = &race_mod_info[i];
+
+ /* Default attr/char */
+ rmp_ptr->g_attr = 0;
+ rmp_ptr->g_char = 0;
+ }
+
+ /* Reset attr/char code for trap overlay graphics */
+ for (i = 0; i < max_rmp_idx; i++)
+ {
+ trap_type *t_ptr = &t_info[i];
+
+ /* Default attr/char */
+ t_ptr->g_attr = 0;
+ t_ptr->g_char = 0;
+ }
+
+
+ if (use_graphics)
+ {
+ /* Process "graf.prf" */
+ process_pref_file("graf.prf");
+
+ /*
+ * Hack -- remember graphics mode as an integer value,
+ * for faster processing of map_info()
+ */
+
+ /* IBM-PC pseudo-graphics -- not maintained, but the code is there */
+ if (streq(ANGBAND_SYS, "ibm"))
+ {
+ graphics_mode = GRAPHICS_IBM;
+ }
+
+ /*
+ * Isometric view. Also assumes all the attributes of the "new"
+ * graphics.
+ */
+ else if (streq(ANGBAND_GRAF, "iso"))
+ {
+ graphics_mode = GRAPHICS_ISO;
+ }
+
+ /*
+ * "New" graphics -- supports graphics overlay for traps, ego monsters
+ * and player subraces, and has tiles for lighting effects (row + 1
+ * and row + 2 for "darker" versions of terrain features)
+ */
+ else if (streq(ANGBAND_GRAF, "new"))
+ {
+ graphics_mode = GRAPHICS_NEW;
+ }
+
+ /*
+ * "Old" graphics -- doesn't support graphics overlay and lighting
+ * effects
+ */
+ else if (streq(ANGBAND_GRAF, "old"))
+ {
+ graphics_mode = GRAPHICS_OLD;
+ }
+
+ /* ??? */
+ else
+ {
+ graphics_mode = GRAPHICS_UNKNOWN;
+ }
+ }
+
+ /* Normal symbols */
+ else
+ {
+ /* Process "font.prf" */
+ process_pref_file("font.prf");
+
+ graphics_mode = GRAPHICS_NONE;
+ }
+}
+
+
+/*
+ * Extract "xtra" flags from object.
+ */
+void object_flags_xtra(object_type *o_ptr, u32b *f2, u32b *f3, u32b *esp)
+{
+ switch (o_ptr->xtra1)
+ {
+ case EGO_XTRA_SUSTAIN:
+ {
+ /* Choose a sustain */
+ switch (o_ptr->xtra2 % 6)
+ {
+ case 0:
+ (*f2) |= (TR2_SUST_STR);
+ break;
+ case 1:
+ (*f2) |= (TR2_SUST_INT);
+ break;
+ case 2:
+ (*f2) |= (TR2_SUST_WIS);
+ break;
+ case 3:
+ (*f2) |= (TR2_SUST_DEX);
+ break;
+ case 4:
+ (*f2) |= (TR2_SUST_CON);
+ break;
+ case 5:
+ (*f2) |= (TR2_SUST_CHR);
+ break;
+ }
+
+ break;
+ }
+
+ case EGO_XTRA_POWER:
+ {
+ /* Choose a power */
+ switch (o_ptr->xtra2 % 11)
+ {
+ case 0:
+ (*f2) |= (TR2_RES_BLIND);
+ break;
+ case 1:
+ (*f2) |= (TR2_RES_CONF);
+ break;
+ case 2:
+ (*f2) |= (TR2_RES_SOUND);
+ break;
+ case 3:
+ (*f2) |= (TR2_RES_SHARDS);
+ break;
+ case 4:
+ (*f2) |= (TR2_RES_NETHER);
+ break;
+ case 5:
+ (*f2) |= (TR2_RES_NEXUS);
+ break;
+ case 6:
+ (*f2) |= (TR2_RES_CHAOS);
+ break;
+ case 7:
+ (*f2) |= (TR2_RES_DISEN);
+ break;
+ case 8:
+ (*f2) |= (TR2_RES_POIS);
+ break;
+ case 9:
+ (*f2) |= (TR2_RES_DARK);
+ break;
+ case 10:
+ (*f2) |= (TR2_RES_LITE);
+ break;
+ }
+
+ break;
+ }
+
+ case EGO_XTRA_ABILITY:
+ {
+ /* Choose an ability */
+ switch (o_ptr->xtra2 % 8)
+ {
+ case 0:
+ (*f3) |= (TR3_FEATHER);
+ break;
+ case 1:
+ (*f3) |= (TR3_LITE1);
+ break;
+ case 2:
+ (*f3) |= (TR3_SEE_INVIS);
+ break;
+ case 3:
+ (*esp) |= (ESP_ALL);
+ break;
+ case 4:
+ (*f3) |= (TR3_SLOW_DIGEST);
+ break;
+ case 5:
+ (*f3) |= (TR3_REGEN);
+ break;
+ case 6:
+ (*f2) |= (TR2_FREE_ACT);
+ break;
+ case 7:
+ (*f2) |= (TR2_HOLD_LIFE);
+ break;
+ }
+
+ break;
+ }
+
+ }
+}
+
+
+/*
+ * Obtain the "flags" for an item
+ */
+bool_ object_flags_no_set = FALSE;
+void object_flags(object_type *o_ptr, u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp)
+{
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Base object */
+ (*f1) = k_ptr->flags1;
+ (*f2) = k_ptr->flags2;
+ (*f3) = k_ptr->flags3;
+ (*f4) = k_ptr->flags4;
+ (*f5) = k_ptr->flags5;
+ (*esp) = k_ptr->esp;
+
+ /* Artifact */
+ if (o_ptr->name1)
+ {
+ artifact_type *a_ptr = &a_info[o_ptr->name1];
+
+ (*f1) = a_ptr->flags1;
+ (*f2) = a_ptr->flags2;
+ (*f3) = a_ptr->flags3;
+ (*f4) = a_ptr->flags4;
+ (*f5) = a_ptr->flags5;
+ (*esp) = a_ptr->esp;
+
+ if ((!object_flags_no_set) && (a_ptr->set != -1))
+ apply_flags_set(o_ptr->name1, a_ptr->set, f1, f2, f3, f4, f5, esp);
+ }
+
+ /* Random artifact ! */
+ if (o_ptr->art_flags1 || o_ptr->art_flags2 || o_ptr->art_flags3 || o_ptr->art_flags4 || o_ptr->art_flags5 || o_ptr->art_esp)
+ {
+ (*f1) |= o_ptr->art_flags1;
+ (*f2) |= o_ptr->art_flags2;
+ (*f3) |= o_ptr->art_flags3;
+ (*f4) |= o_ptr->art_flags4;
+ (*f5) |= o_ptr->art_flags5;
+ (*esp) |= o_ptr->art_esp;
+ }
+
+ /* Extra powers */
+ if (!(o_ptr->art_name))
+ {
+ object_flags_xtra(o_ptr, f2, f3, esp);
+ }
+}
+
+/* Return object granted power */
+int object_power(object_type *o_ptr)
+{
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+ int power = -1;
+
+ /* Base object */
+ power = k_ptr->power;
+
+ /* Ego-item */
+ if (o_ptr->name2)
+ {
+ ego_item_type *e_ptr = &e_info[o_ptr->name2];
+
+ if (power == -1) power = e_ptr->power;
+
+ if (o_ptr->name2b)
+ {
+ ego_item_type *e_ptr = &e_info[o_ptr->name2b];
+
+ if (power == -1) power = e_ptr->power;
+ }
+ }
+
+ /* Artifact */
+ if (o_ptr->name1)
+ {
+ artifact_type *a_ptr = &a_info[o_ptr->name1];
+
+ if (power == -1) power = a_ptr->power;
+ }
+
+ return (power);
+}
+
+
+
+/*
+ * Obtain the "flags" for an item which are known to the player
+ */
+void object_flags_known(object_type *o_ptr, u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp)
+{
+ bool_ spoil = FALSE;
+
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Clear */
+ (*f1) = (*f2) = (*f3) = (*f4) = (*esp) = (*f5) = 0L;
+
+ /* Must be identified */
+ if (!object_known_p(o_ptr)) return;
+
+ /* Base object */
+ (*f1) = k_ptr->flags1;
+ (*f2) = k_ptr->flags2;
+ (*f3) = k_ptr->flags3;
+ (*f4) = k_ptr->flags4;
+ (*f5) = k_ptr->flags5;
+ (*esp) = k_ptr->esp;
+
+ (*f1) |= k_ptr->oflags1;
+ (*f2) |= k_ptr->oflags2;
+ (*f3) |= k_ptr->oflags3;
+ (*f4) |= k_ptr->oflags4;
+ (*f5) |= k_ptr->oflags5;
+ (*esp) |= k_ptr->oesp;
+
+#ifdef SPOIL_ARTIFACTS
+ /* Full knowledge for some artifacts */
+ if (artifact_p(o_ptr) || o_ptr->art_name) spoil = TRUE;
+#endif /* SPOIL_ARTIFACTS */
+
+#ifdef SPOIL_EGO_ITEMS
+ /* Full knowledge for some ego-items */
+ if (ego_item_p(o_ptr)) spoil = TRUE;
+#endif /* SPOIL_EGO_ITEMS */
+
+ /* Artifact */
+ if (o_ptr->name1)
+ {
+ artifact_type *a_ptr = &a_info[o_ptr->name1];
+
+ /* Need full knowledge or spoilers */
+ if (spoil || (o_ptr->ident & IDENT_MENTAL))
+ {
+ (*f1) = a_ptr->flags1;
+ (*f2) = a_ptr->flags2;
+ (*f3) = a_ptr->flags3;
+ (*f4) = a_ptr->flags4;
+ (*f5) = a_ptr->flags5;
+ (*esp) = a_ptr->esp;
+
+ if ((!object_flags_no_set) && (a_ptr->set != -1))
+ apply_flags_set(o_ptr->name1, a_ptr->set, f1, f2, f3, f4, f5, esp);
+ }
+ else
+ {
+ (*f1) = (*f2) = (*f3) = (*f4) = (*esp) = (*f5) = 0L;
+ }
+
+ (*f1) |= a_ptr->oflags1;
+ (*f2) |= a_ptr->oflags2;
+ (*f3) |= a_ptr->oflags3;
+ (*f4) |= a_ptr->oflags4;
+ (*f5) |= a_ptr->oflags5;
+ (*esp) |= a_ptr->oesp;
+ }
+
+ /* Random artifact or ego item! */
+ if (o_ptr->art_flags1 || o_ptr->art_flags2 || o_ptr->art_flags3 || o_ptr->art_flags4 || o_ptr->art_flags5 || o_ptr->art_esp)
+ {
+ /* Need full knowledge or spoilers */
+ if (spoil || (o_ptr->ident & IDENT_MENTAL))
+ {
+ (*f1) |= o_ptr->art_flags1;
+ (*f2) |= o_ptr->art_flags2;
+ (*f3) |= o_ptr->art_flags3;
+ (*f4) |= o_ptr->art_flags4;
+ (*f5) |= o_ptr->art_flags5;
+ (*esp) |= o_ptr->art_esp;
+ }
+
+ (*f1) |= o_ptr->art_oflags1;
+ (*f2) |= o_ptr->art_oflags2;
+ (*f3) |= o_ptr->art_oflags3;
+ (*f4) |= o_ptr->art_oflags4;
+ (*f5) |= o_ptr->art_oflags5;
+ (*esp) |= o_ptr->art_oesp;
+ }
+
+ /* Full knowledge for *identified* objects */
+ if (!(o_ptr->ident & IDENT_MENTAL)) return;
+
+ if (!(o_ptr->art_name))
+ {
+ object_flags_xtra(o_ptr, f2, f3, esp);
+ }
+
+ /* Hack - Res Chaos -> Res Confusion */
+ if (*f2 & TR2_RES_CHAOS) (*f2) |= (TR2_RES_CONF);
+}
+
+
+
+
+
+/*
+ * Print a char "c" into a string "t", as if by sprintf(t, "%c", c),
+ * and return a pointer to the terminator (t + 1).
+ */
+static char *object_desc_chr(char *t, char c)
+{
+ /* Copy the char */
+ *t++ = c;
+
+ /* Terminate */
+ *t = '\0';
+
+ /* Result */
+ return (t);
+}
+
+
+/*
+ * Print a string "s" into a string "t", as if by strcpy(t, s),
+ * and return a pointer to the terminator.
+ */
+static char *object_desc_str(char *t, cptr s)
+{
+ /* Copy the string */
+ while (*s) *t++ = *s++;
+
+ /* Terminate */
+ *t = '\0';
+
+ /* Result */
+ return (t);
+}
+
+/*
+ * Do the actual conversion of a number for object_desc_num() and
+ * object_desc_int().
+ */
+static char *convert_number(char *result, u32b num)
+{
+ char *tp;
+ char temp[11];
+
+ tp = temp;
+ *tp = '0' + (num % 10);
+ for (num /= 10; num != 0; num /= 10)
+ {
+ *++tp = '0' + (num % 10);
+ }
+
+ while (tp != temp)
+ {
+ *result++ = *tp--;
+ }
+ *result++ = *tp;
+ *result = '\0';
+
+ return result;
+}
+
+/*
+ * Print a nnumber "n" into a string "t", as if by
+ * sprintf(t, "%u", n), and return a pointer to the terminator.
+ */
+static char *object_desc_num(char *result, s32b num)
+{
+ u32b n;
+
+ if (num < 0)
+ {
+ *result++ = '-';
+ n = -num;
+ }
+ else
+ n = num;
+
+ /* Result */
+ return convert_number(result, n);
+}
+
+/*
+ * Print an signed number "num" into a string "result", as if by
+ * sprintf(t, "%+d", n), and return a pointer to the terminator.
+ * Note that we always print a sign, either "+" or "-".
+ */
+static char *object_desc_int(char *result, s32b num)
+{
+ u32b n;
+
+ /* Negative */
+ if (num < 0)
+ {
+ /* Take the absolute value */
+ n = -num;
+
+ /* Use a "minus" sign */
+ *result++ = '-';
+ }
+ /* Positive (or zero) */
+ else
+ {
+ /* Use the actual number */
+ n = num;
+
+ /* Use a "plus" sign */
+ *result++ = '+';
+ }
+
+ /* Result */
+ return convert_number(result, n);
+}
+
+/*
+ * Creates a description of the item "o_ptr", and stores it in "out_val".
+ *
+ * One can choose the "verbosity" of the description, including whether
+ * or not the "number" of items should be described, and how much detail
+ * should be used when describing the item.
+ *
+ * The given "buf" must be 80 chars long to hold the longest possible
+ * description, which can get pretty long, including incriptions, such as:
+ * "no more Maces of Disruption (Defender) (+10,+10) [+5] (+3 to stealth)".
+ * Note that the inscription will be clipped to keep the total description
+ * under 79 chars (plus a terminator).
+ *
+ * Note the use of "object_desc_num()" and "object_desc_int()" as hyper-efficient,
+ * portable, versions of some common "sprintf()" commands.
+ *
+ * Note that all ego-items (when known) append an "Ego-Item Name", unless
+ * the item is also an artifact, which should NEVER happen.
+ *
+ * Note that all artifacts (when known) append an "Artifact Name", so we
+ * have special processing for "Specials" (artifact Lites, Rings, Amulets).
+ * The "Specials" never use "modifiers" if they are "known", since they
+ * have special "descriptions", such as "The Necklace of the Dwarves".
+ *
+ * Special Lite's use the "k_info" base-name (Phial, Star, or Arkenstone),
+ * plus the artifact name, just like any other artifact, if known.
+ *
+ * Special Ring's and Amulet's, if not "aware", use the same code as normal
+ * rings and amulets, and if "aware", use the "k_info" base-name (Ring or
+ * Amulet or Necklace). They will NEVER "append" the "k_info" name. But,
+ * they will append the artifact name, just like any artifact, if known.
+ *
+ * None of the Special Rings/Amulets are "EASY_KNOW", though they could be,
+ * at least, those which have no "pluses", such as the three artifact lites.
+ *
+ * Hack -- Display "The One Ring" as "a Plain Gold Ring" until aware.
+ *
+ * If "pref" then a "numeric" prefix will be pre-pended.
+ *
+ * Mode:
+ * 0 -- The Cloak of Death
+ * 1 -- The Cloak of Death [1,+3]
+ * 2 -- The Cloak of Death [1,+3] (+2 to Stealth)
+ * 3 -- The Cloak of Death [1,+3] (+2 to Stealth) {nifty}
+ */
+void object_desc(char *buf, object_type *o_ptr, int pref, int mode)
+{
+ bool_ hack_name = FALSE;
+ cptr basenm, modstr;
+ int indexx;
+
+ bool_ aware = FALSE;
+ bool_ known = FALSE;
+
+ bool_ append_name = FALSE;
+
+ bool_ show_weapon = FALSE;
+ bool_ show_armour = FALSE;
+
+ cptr s, u;
+ char *t;
+
+ char p1 = '(', p2 = ')';
+ char b1 = '[', b2 = ']';
+ char c1 = '{', c2 = '}';
+
+ char tmp_val[160];
+ char tmp_val2[90];
+
+ s32b power;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ cptr str;
+
+ /* Extract some flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+
+ /* See if the object is "aware" */
+ if (object_aware_p(o_ptr)) aware = TRUE;
+
+ /* See if the object is "known" */
+ if (object_known_p(o_ptr)) known = TRUE;
+
+ /* Hack -- Extract the sub-type "indexx" */
+ indexx = o_ptr->sval;
+
+ /* Extract default "base" string */
+ basenm = (k_name + k_ptr->name);
+
+ /* Assume no "modifier" string */
+ modstr = "";
+
+ /* Analyze the object */
+ switch (o_ptr->tval)
+ {
+ /* Some objects are easy to describe */
+ case TV_SKELETON:
+ case TV_BOTTLE:
+ case TV_JUNK:
+ case TV_SPIKE:
+ case TV_FLASK:
+ case TV_CHEST:
+ case TV_INSTRUMENT:
+ case TV_TOOL:
+ case TV_DIGGING:
+ {
+ break;
+ }
+
+
+ /* Missiles/ Bows/ Weapons */
+ case TV_SHOT:
+ case TV_BOLT:
+ case TV_ARROW:
+ case TV_BOOMERANG:
+ case TV_BOW:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_MSTAFF:
+ case TV_SWORD:
+ case TV_AXE:
+ {
+ show_weapon = TRUE;
+ break;
+ }
+
+ /* Trapping Kits */
+ case TV_TRAPKIT:
+ {
+ modstr = basenm;
+ basenm = "& # Trap Set~";
+ break;
+ }
+
+ /* Armour */
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_CROWN:
+ case TV_HELM:
+ case TV_SHIELD:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ {
+ show_armour = TRUE;
+ break;
+ }
+
+
+ /* Lites (including a few "Specials") */
+ case TV_LITE:
+ {
+ break;
+ }
+
+ /* Amulets (including a few "Specials") */
+ case TV_AMULET:
+ {
+ /* Color the object */
+ modstr = amulet_adj[indexx];
+ if (aware) append_name = TRUE;
+
+ if (((plain_descriptions) && (aware)) || o_ptr->ident & IDENT_STOREB)
+ basenm = "& Amulet~";
+ else
+ basenm = aware ? "& # Amulet~" : "& # Amulet~";
+
+ if (known && !o_ptr->art_name && artifact_p(o_ptr)) basenm = k_ptr->name + k_name;
+
+ break;
+ }
+
+ /* Rings (including a few "Specials") */
+ case TV_RING:
+ {
+ /* Color the object */
+ modstr = ring_adj[indexx];
+ if (aware) append_name = TRUE;
+
+ if (((plain_descriptions) && (aware)) || o_ptr->ident & IDENT_STOREB)
+ basenm = "& Ring~";
+ else
+ basenm = aware ? "& # Ring~" : "& # Ring~";
+
+ /* Hack -- The One Ring */
+ if (!aware && (o_ptr->sval == SV_RING_POWER)) modstr = "Plain Gold";
+
+ if (known && !o_ptr->art_name && artifact_p(o_ptr)) basenm = k_ptr->name + k_name;
+
+ break;
+ }
+
+ case TV_STAFF:
+ {
+ /* Color the object */
+ modstr = staff_adj[o_ptr->pval2 % MAX_WOODS];
+ if (aware) append_name = TRUE;
+ if (((plain_descriptions) && (aware)) || o_ptr->ident & IDENT_STOREB)
+ basenm = "& Staff~";
+ else
+ basenm = "& # Staff~";
+ break;
+ }
+
+ case TV_WAND:
+ {
+ /* Color the object */
+ modstr = wand_adj[o_ptr->pval2 % MAX_METALS];
+ if (aware) append_name = TRUE;
+ if (((plain_descriptions) && (aware)) || o_ptr->ident & IDENT_STOREB)
+ basenm = "& Wand~";
+ else
+ basenm = "& # Wand~";
+ break;
+ }
+
+ case TV_ROD:
+ {
+ /* Color the object */
+ modstr = rod_adj[indexx];
+ if (aware) append_name = TRUE;
+ if (((plain_descriptions) && (aware)) || o_ptr->ident & IDENT_STOREB)
+ basenm = "& Rod Tip~";
+ else
+ basenm = aware ? "& # Rod Tip~" : "& # Rod Tip~";
+ if (o_ptr->sval == SV_ROD_HOME)
+ {
+ basenm = "& Great Rod Tip~ of Home Summoning";
+ hack_name = TRUE;
+ }
+ break;
+ }
+
+ case TV_ROD_MAIN:
+ {
+ object_kind *tip_ptr = &k_info[lookup_kind(TV_ROD, o_ptr->pval)];
+
+ modstr = k_name + tip_ptr->name;
+ break;
+ }
+
+ case TV_SCROLL:
+ {
+ /* Color the object */
+ modstr = scroll_adj[indexx];
+ if (aware) append_name = TRUE;
+ if (((plain_descriptions) && (aware)) || o_ptr->ident & IDENT_STOREB)
+ basenm = "& Scroll~";
+ else
+ basenm = aware ? "& Scroll~ titled \"#\"" : "& Scroll~ titled \"#\"";
+ break;
+ }
+
+ case TV_POTION:
+ case TV_POTION2:
+ {
+ /* Color the object */
+ if ((o_ptr->tval != TV_POTION2) || (o_ptr->sval != SV_POTION2_MIMIC) || (!aware))
+ {
+ modstr = potion_adj[indexx];
+ if (aware) append_name = TRUE;
+ }
+ else
+ {
+ call_lua("get_mimic_info", "(d,s)", "s", o_ptr->pval2, "name", &modstr);
+ }
+ if (((plain_descriptions) && (aware)) || o_ptr->ident & IDENT_STOREB)
+ basenm = "& Potion~";
+ else
+ basenm = aware ? "& # Potion~" : "& # Potion~";
+ break;
+ }
+
+ case TV_FOOD:
+ {
+ /* Ordinary food is "boring" */
+ if (o_ptr->sval >= SV_FOOD_MIN_FOOD) break;
+
+ /* Color the object */
+ modstr = food_adj[indexx];
+ if (aware) append_name = TRUE;
+ if (((plain_descriptions) && (aware)) || o_ptr->ident & IDENT_STOREB)
+ basenm = "& Mushroom~";
+ else
+ basenm = aware ? "& # Mushroom~" : "& # Mushroom~";
+ break;
+ }
+
+
+ /* Cloak of Mimicry */
+ case TV_CLOAK:
+ {
+ show_armour = TRUE;
+ if (o_ptr->sval == SV_MIMIC_CLOAK)
+ {
+ call_lua("get_mimic_info", "(d,s)", "s", o_ptr->pval2, "obj_name", &modstr);
+ }
+ break;
+ }
+
+
+ case TV_SYMBIOTIC_BOOK:
+ {
+ modstr = basenm;
+ basenm = "& Symbiotic Spellbook~ #";
+ break;
+ }
+
+ case TV_MUSIC_BOOK:
+ {
+ modstr = basenm;
+ basenm = "& Songbook~ #";
+ break;
+ }
+
+ /* Druid Books */
+ case TV_DRUID_BOOK:
+ {
+ modstr = basenm;
+ basenm = "& Elemental Stone~ #";
+ break;
+ }
+
+ case TV_BATERIE:
+ {
+ modstr = basenm;
+ basenm = "& Essence~ of #";
+ break;
+ }
+
+ case TV_PARCHMENT:
+ {
+ modstr = basenm;
+ basenm = "& Parchment~ - #";
+ break;
+ }
+
+
+ /* Hack -- Gold/Gems */
+ case TV_GOLD:
+ {
+ strcpy(buf, basenm);
+ return;
+ }
+
+ case TV_CORPSE:
+ {
+ monster_race* r_ptr = &r_info[o_ptr->pval2];
+ modstr = basenm;
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ basenm = format("& %s's #~", r_name + r_ptr->name);
+ else
+ basenm = format("& %s #~", r_name + r_ptr->name);
+ break;
+ }
+
+ case TV_EGG:
+ {
+ monster_race* r_ptr = &r_info[o_ptr->pval2];
+ modstr = basenm;
+
+ basenm = format("& %s #~", r_name + r_ptr->name);
+ break;
+ }
+
+ case TV_HYPNOS:
+ {
+ /* We print hit points further down. --dsb */
+ monster_race* r_ptr = &r_info[o_ptr->pval];
+ modstr = basenm;
+ basenm = format("& %s~", r_name + r_ptr->name);
+ break;
+ }
+
+ case TV_TOTEM:
+ {
+ char name[80];
+ monster_type monster;
+
+ monster.sr_ptr = 0;
+ monster.r_idx = o_ptr->pval;
+ monster.ego = o_ptr->pval2;
+ monster.ml = TRUE;
+ monster.status = MSTATUS_ENEMY;
+
+ monster_desc(name, &monster, 0x188);
+
+ modstr = basenm;
+ basenm = format("& #~ of %s", name);
+ break;
+ }
+
+ case TV_RANDART:
+ {
+ modstr = basenm;
+
+ if (known)
+ {
+ basenm = random_artifacts[indexx].name_full;
+ }
+ else
+ {
+ basenm = random_artifacts[indexx].name_short;
+ }
+ break;
+ }
+
+ case TV_RUNE2:
+ {
+ if (o_ptr->sval != RUNE_STONE)
+ {
+ modstr = basenm;
+ basenm = "& Rune~ [#]";
+ }
+ break;
+ }
+
+ case TV_RUNE1:
+ {
+ modstr = basenm;
+ basenm = "& Rune~ [#]";
+ break;
+ }
+
+ case TV_DAEMON_BOOK:
+ case TV_BOOK:
+ {
+ basenm = k_name + k_ptr->name;
+ if (o_ptr->sval == 255) modstr = school_spells[o_ptr->pval].name;
+ break;
+ }
+
+ /* Used in the "inventory" routine */
+ default:
+ {
+ if (process_hooks_ret(HOOK_ITEM_NAME, "ss", "(O,s,s)",
+ o_ptr, basenm, modstr))
+ {
+ basenm = process_hooks_return[0].str;
+ modstr = process_hooks_return[1].str;
+ break;
+ }
+ else
+ {
+ strcpy(buf, "(nothing)");
+ return;
+ }
+ }
+ }
+
+ /* Mega Hack */
+ if ((!hack_name) && known && (k_ptr->flags5 & TR5_FULL_NAME)) basenm = (k_name + k_ptr->name);
+
+
+ /* Start dumping the result */
+ t = tmp_val;
+
+ /* The object "expects" a "number" */
+ if (basenm[0] == '&')
+ {
+ monster_race* r_ptr;
+ cptr ego = NULL;
+
+ if (o_ptr->tval == TV_CORPSE) r_ptr = &r_info[o_ptr->pval2];
+ else r_ptr = &r_info[o_ptr->pval];
+
+ /* Grab any ego-item name */
+ if (known && (o_ptr->name2 || o_ptr->name2b) && (o_ptr->tval != TV_ROD_MAIN))
+ {
+ ego_item_type *e_ptr = &e_info[o_ptr->name2];
+ ego_item_type *e2_ptr = &e_info[o_ptr->name2b];
+
+ if (e_ptr->before)
+ {
+ ego = e_ptr->name + e_name;
+ }
+ else if (e2_ptr->before)
+ {
+ ego = e2_ptr->name + e_name;
+ }
+ }
+
+ /* Skip the ampersand (and space) */
+ s = basenm + 2;
+
+ /* No prefix */
+ if (pref <= 0)
+ {
+ /* Nothing */
+ }
+
+ /* Hack -- None left */
+ else if (o_ptr->number <= 0)
+ {
+ t = object_desc_str(t, "no more ");
+ }
+
+ /* Extract the number */
+ else if (o_ptr->number > 1)
+ {
+ t = object_desc_num(t, o_ptr->number);
+ t = object_desc_chr(t, ' ');
+ }
+
+ else if ((o_ptr->tval == TV_CORPSE) && (r_ptr->flags1 & RF1_UNIQUE))
+ {}
+
+
+ else if ((o_ptr->tval == TV_HYPNOS) && (r_ptr->flags1 & RF1_UNIQUE))
+ {}
+
+ /* Hack -- The only one of its kind */
+ else if (known && (artifact_p(o_ptr) || o_ptr->art_name))
+ {
+ t = object_desc_str(t, "The ");
+ }
+
+ else if (ego != NULL)
+ {
+ if (is_a_vowel(ego[0]))
+ {
+ t = object_desc_str(t, "an ");
+ }
+ else
+ {
+ t = object_desc_str(t, "a ");
+ }
+ }
+
+ /* A single one, with a vowel in the modifier */
+ else if ((*s == '#') && (is_a_vowel(modstr[0])))
+ {
+ t = object_desc_str(t, "an ");
+ }
+
+ /* A single one, with a vowel */
+ else if (is_a_vowel(*s))
+ {
+ t = object_desc_str(t, "an ");
+ }
+
+ /* A single one, without a vowel */
+ else
+ {
+ t = object_desc_str(t, "a ");
+ }
+
+ /* Grab any ego-item name */
+ if (known && (o_ptr->name2 || o_ptr->name2b) && (o_ptr->tval != TV_ROD_MAIN))
+ {
+ ego_item_type *e_ptr = &e_info[o_ptr->name2];
+ ego_item_type *e2_ptr = &e_info[o_ptr->name2b];
+
+ if (e_ptr->before)
+ {
+ t = object_desc_str(t, (e_name + e_ptr->name));
+ t = object_desc_chr(t, ' ');
+ }
+ if (e2_ptr->before)
+ {
+ t = object_desc_str(t, (e_name + e2_ptr->name));
+ t = object_desc_chr(t, ' ');
+ }
+ }
+
+ /* -TM- Hack -- Add false-artifact names */
+ /* Dagger inscribed {@w0%Smelly} will be named
+ * Smelly Dagger {@w0} */
+
+ if (o_ptr->note)
+ {
+ str = strchr(quark_str(o_ptr->note), '%');
+
+ /* Add the false name */
+ if (str)
+ {
+ t = object_desc_str(t, &str[1]);
+ t = object_desc_chr(t, ' ');
+ }
+ }
+
+ }
+
+ /* Hack -- objects that "never" take an article */
+ else
+ {
+ /* No ampersand */
+ s = basenm;
+
+ /* No pref */
+ if (!pref)
+ {
+ /* Nothing */
+ }
+
+ /* Hack -- all gone */
+ else if (o_ptr->number <= 0)
+ {
+ t = object_desc_str(t, "no more ");
+ }
+
+ /* Prefix a number if required */
+ else if (o_ptr->number > 1)
+ {
+ t = object_desc_num(t, o_ptr->number);
+ t = object_desc_chr(t, ' ');
+ }
+
+ else if (o_ptr->tval == TV_RANDART)
+ {
+ /* Do nothing, since randarts have their prefix already included */
+ }
+
+ /* Hack -- The only one of its kind */
+ else if (known && (artifact_p(o_ptr) || o_ptr->art_name))
+ {
+ t = object_desc_str(t, "The ");
+ }
+
+ /* Hack -- single items get no prefix */
+ else
+ {
+ /* Nothing */
+ }
+
+ /* Grab any ego-item name */
+ if (known && (o_ptr->name2 || o_ptr->name2b) && (o_ptr->tval != TV_ROD_MAIN))
+ {
+ ego_item_type *e_ptr = &e_info[o_ptr->name2];
+ ego_item_type *e2_ptr = &e_info[o_ptr->name2b];
+
+ if (e_ptr->before)
+ {
+ t = object_desc_str(t, (e_name + e_ptr->name));
+ t = object_desc_chr(t, ' ');
+ }
+ if (e2_ptr->before)
+ {
+ t = object_desc_str(t, (e_name + e2_ptr->name));
+ t = object_desc_chr(t, ' ');
+ }
+ }
+ }
+
+ /* Paranoia -- skip illegal tildes */
+ /* while (*s == '~') s++; */
+
+ /* Copy the string */
+ for (; *s; s++)
+ {
+ /* Pluralizer */
+ if (*s == '~')
+ {
+ /* Add a plural if needed */
+ if ((o_ptr->number != 1) && (pref >= 0))
+ {
+ char k = t[ -1];
+
+ /* XXX XXX XXX Mega-Hack */
+
+ /* Hack -- "Cutlass-es" and "Torch-es" */
+ if ((k == 's') || (k == 'h')) *t++ = 'e';
+
+ /* Add an 's' */
+ *t++ = 's';
+ }
+ }
+
+ /* Modifier */
+ else if (*s == '#')
+ {
+ /* Grab any ego-item name */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ t = object_desc_chr(t, ' ');
+
+ if (known && o_ptr->name2)
+ {
+ ego_item_type *e_ptr = &e_info[o_ptr->name2];
+
+ t = object_desc_str(t, (e_name + e_ptr->name));
+ }
+ }
+
+ /* Insert the modifier */
+ for (u = modstr; *u; u++) *t++ = *u;
+ }
+
+ /* Normal */
+ else
+ {
+ /* Copy */
+ *t++ = *s;
+ }
+ }
+
+ /* Terminate */
+ *t = '\0';
+
+
+ /* Append the "kind name" to the "base name" */
+ if ((append_name) && (!artifact_p(o_ptr)))
+ {
+ t = object_desc_str(t, " of ");
+
+ if (((o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_STAFF)))
+ {
+ t = object_desc_str(t, school_spells[o_ptr->pval2].name);
+ if (mode >= 1)
+ {
+ s32b bonus = o_ptr->pval3 & 0xFFFF;
+ s32b max = o_ptr->pval3 >> 16;
+
+ t = object_desc_chr(t, '[');
+ t = object_desc_num(t, bonus);
+ t = object_desc_chr(t, '|');
+ t = object_desc_num(t, max);
+ t = object_desc_chr(t, ']');
+ }
+ }
+ else
+ t = object_desc_str(t, (k_name + k_ptr->name));
+ }
+
+ /* Hack -- Append "Artifact" or "Special" names */
+ if (known)
+ {
+
+ /* -TM- Hack -- Add false-artifact names */
+ /* Dagger inscribed {@w0#of Smell} will be named
+ * Dagger of Smell {@w0} */
+ if (o_ptr->note)
+ {
+ str = strchr(quark_str(o_ptr->note), '#');
+
+ /* Add the false name */
+ if (str)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_str(t, &str[1]);
+ }
+ }
+
+ /* Is it a new random artifact ? */
+ if (o_ptr->art_name)
+ {
+ t = object_desc_chr(t, ' ');
+
+ t = object_desc_str(t, quark_str(o_ptr->art_name));
+ }
+
+
+ /* Grab any artifact name */
+ else if (o_ptr->name1)
+ {
+ artifact_type *a_ptr = &a_info[o_ptr->name1];
+
+ /* Unique corpses don't require another name */
+ if (o_ptr->tval != TV_CORPSE)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_str(t, (a_name + a_ptr->name));
+ }
+ }
+
+ /* Grab any ego-item name */
+ else if ((o_ptr->name2 || o_ptr->name2b) && (o_ptr->tval != TV_ROD_MAIN))
+ {
+ ego_item_type *e_ptr = &e_info[o_ptr->name2];
+ ego_item_type *e2_ptr = &e_info[o_ptr->name2b];
+
+ if (o_ptr->name2 && !e_ptr->before)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_str(t, (e_name + e_ptr->name));
+ }
+ if (o_ptr->name2b && !e2_ptr->before)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_str(t, (e_name + e2_ptr->name));
+ }
+ }
+ }
+
+ /* It contains a spell */
+ if ((known) && (f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 != -1))
+ {
+ t = object_desc_str(t, format(" [%s]", school_spells[o_ptr->pval2].name));
+ }
+
+ /* Add symbiote hp here, after the "fake-artifact" name. --dsb */
+ if (o_ptr->tval == TV_HYPNOS)
+ {
+ t = object_desc_str(t, " (");
+ t = object_desc_num(t, o_ptr->pval2);
+ t = object_desc_str(t, " hp)");
+ }
+
+ /* No more details wanted */
+ if (mode < 1) goto copyback;
+
+ /* Hack -- Some objects can have an exp level */
+ if ((f4 & TR4_LEVELS) && known)
+ {
+ t = object_desc_str(t, " (E:");
+ if (exp_need)
+ {
+ s32b need;
+ /* Formula from check_experience_obj(). */
+ need = player_exp[o_ptr->elevel - 1] * 5 / 2;
+ t = object_desc_num(t, need - o_ptr->exp);
+ }
+ else
+ {
+ t = object_desc_num(t, o_ptr->exp);
+ }
+ t = object_desc_str(t, ", L:");
+ t = object_desc_num(t, o_ptr->elevel);
+ t = object_desc_chr(t, ')');
+ }
+ if ((f4 & TR4_ART_EXP) && known)
+ {
+ t = object_desc_str(t, " (Exp:");
+ t = object_desc_num(t, o_ptr->exp);
+ t = object_desc_chr(t, ')');
+ }
+
+ /* Hack -- Chests must be described in detail */
+ if (o_ptr->tval == TV_CHEST)
+ {
+ /* Not searched yet */
+ if (!known)
+ {
+ /* Nothing */
+ }
+
+ /* May be "empty" */
+ else if (!o_ptr->pval)
+ {
+ t = object_desc_str(t, " (empty)");
+ }
+
+ /* May be "disarmed" */
+ else if (o_ptr->pval < 0)
+ {
+ t = object_desc_str(t, " (disarmed)");
+ }
+
+ /* Describe the traps, if any */
+ else
+ {
+ /* Describe the traps */
+ t = object_desc_str(t, " (");
+ if (t_info[o_ptr->pval].ident)
+ t = object_desc_str(t, t_name + t_info[o_ptr->pval].name);
+ else
+ t = object_desc_str(t, "trapped");
+ t = object_desc_str(t, ")");
+ }
+ }
+
+
+ /* Display the item like a weapon */
+ if (f3 & (TR3_SHOW_MODS)) show_weapon = TRUE;
+
+ /* Display the item like a weapon */
+ if (o_ptr->to_h && o_ptr->to_d) show_weapon = TRUE;
+
+ /* Display the item like armour */
+ if (o_ptr->ac) show_armour = TRUE;
+
+ /* Dump base weapon info */
+ switch (o_ptr->tval)
+ {
+ /* Missiles and Weapons */
+ case TV_SHOT:
+ case TV_BOLT:
+ case TV_ARROW:
+ /* Exploding arrow? */
+ if (o_ptr->pval2 != 0)
+ t = object_desc_str(t, " (exploding)");
+ /* No break, we want to continue the description */
+
+ case TV_BOOMERANG:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_MSTAFF:
+ case TV_AXE:
+ case TV_SWORD:
+ case TV_DAEMON_BOOK:
+ if ((o_ptr->tval == TV_DAEMON_BOOK) && (o_ptr->sval != SV_DEMONBLADE))
+ break;
+
+ /* Append a "damage" string */
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, p1);
+ t = object_desc_num(t, o_ptr->dd);
+ t = object_desc_chr(t, 'd');
+ t = object_desc_num(t, o_ptr->ds);
+ t = object_desc_chr(t, p2);
+
+ /* All done */
+ break;
+
+
+ /* Bows get a special "damage string" */
+ case TV_BOW:
+
+ /* Mega-Hack -- Extract the "base power" */
+ power = (o_ptr->sval % 10);
+
+ /* Apply the "Extra Might" flag */
+ if (f3 & (TR3_XTRA_MIGHT)) power += o_ptr->pval;
+
+ /* Append a special "damage" string */
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, p1);
+ t = object_desc_chr(t, 'x');
+ t = object_desc_num(t, power);
+ t = object_desc_chr(t, p2);
+
+ /* All done */
+ break;
+ }
+
+
+ /* Add the weapon bonuses */
+ if (known)
+ {
+ /* Show the tohit/todam on request */
+ if (show_weapon)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, p1);
+ t = object_desc_int(t, o_ptr->to_h);
+ t = object_desc_chr(t, ',');
+ t = object_desc_int(t, o_ptr->to_d);
+ t = object_desc_chr(t, p2);
+ }
+
+ /* Show the tohit if needed */
+ else if (o_ptr->to_h)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, p1);
+ t = object_desc_int(t, o_ptr->to_h);
+ if (!(f3 & (TR3_HIDE_TYPE)) || o_ptr->art_name)
+ t = object_desc_str(t, " to accuracy");
+ t = object_desc_chr(t, p2);
+ }
+
+ /* Show the todam if needed */
+ else if (o_ptr->to_d)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, p1);
+ t = object_desc_int(t, o_ptr->to_d);
+ if (!(f3 & (TR3_HIDE_TYPE)) || o_ptr->art_name)
+ t = object_desc_str(t, " to damage");
+ t = object_desc_chr(t, p2);
+ }
+ }
+
+
+ /* Add the armor bonuses */
+ if (known)
+ {
+ /* Show the armor class info */
+ if (show_armour)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, b1);
+ t = object_desc_num(t, o_ptr->ac);
+ t = object_desc_chr(t, ',');
+ t = object_desc_int(t, o_ptr->to_a);
+ t = object_desc_chr(t, b2);
+ }
+
+ /* No base armor, but does increase armor */
+ else if (o_ptr->to_a)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, b1);
+ t = object_desc_int(t, o_ptr->to_a);
+ t = object_desc_chr(t, b2);
+ }
+ }
+
+ /* Hack -- always show base armor */
+ else if (show_armour)
+ {
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, b1);
+ t = object_desc_num(t, o_ptr->ac);
+ t = object_desc_chr(t, b2);
+ }
+
+ if ((f1 & TR1_MANA) && (known) && (o_ptr->pval > 0))
+ {
+ t = object_desc_chr(t, '(');
+ if (munchkin_multipliers)
+ {
+ t = object_desc_num(t, 100 * o_ptr->pval / 5);
+ }
+ else
+ {
+ t = object_desc_num(t, 100 * o_ptr->pval / 10);
+ }
+ t = object_desc_str(t, "%)");
+ }
+
+ if ((known) && (f2 & TR2_LIFE) ) /* Can disp neg now -- Improv */
+ {
+ t = object_desc_chr(t, '(');
+ if (munchkin_multipliers)
+ {
+ t = object_desc_num(t, 100 * o_ptr->pval / 5);
+ }
+ else
+ {
+ t = object_desc_num(t, 100 * o_ptr->pval / 10);
+ }
+ t = object_desc_str(t, "%)");
+ }
+
+ /* No more details wanted */
+ if (mode < 2) goto copyback;
+
+
+ /* Hack -- Wands and Staffs have charges */
+ if (known &&
+ ((o_ptr->tval == TV_STAFF) ||
+ (o_ptr->tval == TV_WAND)))
+ {
+ /* Dump " (N charges)" */
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, p1);
+ t = object_desc_num(t, o_ptr->pval);
+ t = object_desc_str(t, " charge");
+ if (o_ptr->pval != 1) t = object_desc_chr(t, 's');
+ t = object_desc_chr(t, p2);
+ }
+
+ /*
+ * Hack -- Rods have a "charging" indicator.
+ */
+ else if (known && (o_ptr->tval == TV_ROD_MAIN))
+ {
+ /* Display prettily. */
+ t = object_desc_str(t, " (");
+ t = object_desc_num(t, o_ptr->timeout);
+ t = object_desc_chr(t, '/');
+ t = object_desc_num(t, o_ptr->pval2);
+ t = object_desc_chr(t, ')');
+ }
+
+ /*
+ * Hack -- Rods have a "charging" indicator.
+ */
+ else if (known && (o_ptr->tval == TV_ROD))
+ {
+ /* Display prettily. */
+ t = object_desc_str(t, " (");
+ t = object_desc_num(t, o_ptr->pval);
+ t = object_desc_str(t, " Mana to cast");
+ t = object_desc_chr(t, ')');
+ }
+
+ /* Hack -- Process Lanterns/Torches */
+ else if ((o_ptr->tval == TV_LITE) && (f4 & TR4_FUEL_LITE))
+ {
+ /* Hack -- Turns of light for normal lites */
+ t = object_desc_str(t, " (with ");
+ t = object_desc_num(t, o_ptr->timeout);
+ t = object_desc_str(t, " turns of light)");
+ }
+
+
+ /* Dump "pval" flags for wearable items */
+ if (known && ((f1 & (TR1_PVAL_MASK)) || (f5 & (TR5_PVAL_MASK))))
+ {
+ /* Start the display */
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, p1);
+
+ /* Dump the "pval" itself */
+ t = object_desc_int(t, o_ptr->pval);
+
+ /* Do not display the "pval" flags */
+ if (f3 & (TR3_HIDE_TYPE))
+ {
+ /* Nothing */
+ }
+
+ /* Speed */
+ else if (f1 & (TR1_SPEED))
+ {
+ /* Dump " to speed" */
+ t = object_desc_str(t, " to speed");
+ }
+
+ /* Attack speed */
+ else if (f1 & (TR1_BLOWS))
+ {
+ /* Add " attack" */
+ t = object_desc_str(t, " attack");
+
+ /* Add "attacks" */
+ if (ABS(o_ptr->pval) != 1) t = object_desc_chr(t, 's');
+ }
+
+ /* Critical chance */
+ else if (f5 & (TR5_CRIT))
+ {
+ /* Add " attack" */
+ t = object_desc_str(t, "% of critical hits");
+ }
+
+ /* Stealth */
+ else if (f1 & (TR1_STEALTH))
+ {
+ /* Dump " to stealth" */
+ t = object_desc_str(t, " to stealth");
+ }
+
+ /* Search */
+ else if (f1 & (TR1_SEARCH))
+ {
+ /* Dump " to searching" */
+ t = object_desc_str(t, " to searching");
+ }
+
+ /* Infravision */
+ else if (f1 & (TR1_INFRA))
+ {
+ /* Dump " to infravision" */
+ t = object_desc_str(t, " to infravision");
+ }
+
+ /* Tunneling */
+ else if (f1 & (TR1_TUNNEL))
+ {
+ /* Nothing */
+ }
+
+ /* Finish the display */
+ t = object_desc_chr(t, p2);
+ }
+
+
+ /* Indicate "charging" artifacts XXX XXX XXX */
+ if (known && (f3 & TR3_ACTIVATE) && o_ptr->timeout)
+ {
+ if(o_ptr->tval == TV_EGG)
+ /* Hack -- Dump " (stopped)" if relevant */
+ t = object_desc_str(t, " (stopped)");
+ else
+ /* Hack -- Dump " (charging)" if relevant */
+ t = object_desc_str(t, " (charging)");
+ }
+
+ /* Indicate "charging" Mage Staffs XXX XXX XXX */
+ if (known && o_ptr->timeout && (is_ego_p(o_ptr, EGO_MSTAFF_SPELL)))
+ {
+ /* Hack -- Dump " (charging spell1)" if relevant */
+ t = object_desc_str(t, " (charging spell1)");
+ }
+ if (known && o_ptr->xtra2 && (is_ego_p(o_ptr, EGO_MSTAFF_SPELL)))
+ {
+ /* Hack -- Dump " (charging spell2)" if relevant */
+ t = object_desc_str(t, " (charging spell2)");
+ }
+
+
+ /* No more details wanted */
+ if (mode < 3) goto copyback;
+
+
+ /* No inscription yet */
+ tmp_val2[0] = '\0';
+
+ /* Sensed stuff */
+ if (o_ptr->ident & (IDENT_SENSE))
+ {
+ strcpy(tmp_val2, sense_desc[o_ptr->sense]);
+ }
+
+ /* Hack - Note "cursed" if the item is 'known' and cursed */
+ if (cursed_p(o_ptr) && (known) && (!tmp_val2[0]))
+ {
+ if (tmp_val2[0]) strcat(tmp_val2, ", ");
+ strcat(tmp_val2, "cursed");
+ }
+
+ /* Use the standard inscription if available */
+ if (o_ptr->note)
+ {
+ char *u = tmp_val2;
+
+ if (tmp_val2[0]) strcat(tmp_val2, ", ");
+
+ strcat(tmp_val2, quark_str(o_ptr->note));
+
+ for (; *u && (*u != '#') && (*u != '%'); u++);
+
+ *u = '\0';
+ }
+
+ /* Mega-Hack -- note empty wands/staffs */
+ if (!known && (o_ptr->ident & (IDENT_EMPTY)))
+ {
+ if (tmp_val2[0]) strcat(tmp_val2, ", ");
+ strcat(tmp_val2, "empty");
+ }
+
+ /* Note "tried" if the object has been tested unsuccessfully */
+ if (!aware && object_tried_p(o_ptr))
+ {
+ if (tmp_val2[0]) strcat(tmp_val2, ", ");
+ strcpy(tmp_val2, "tried");
+ }
+
+ /* Note the discount, if any */
+ if ((o_ptr->discount) && (!tmp_val2[0]))
+ {
+ object_desc_num(tmp_val2, o_ptr->discount);
+ strcat(tmp_val2, "% off");
+ }
+
+ /* Append the inscription, if any */
+ if (tmp_val2[0])
+ {
+ int n;
+
+ /* Hack -- How much so far */
+ n = (t - tmp_val);
+
+ /* Paranoia -- do not be stupid */
+ if (n > 75) n = 75;
+
+ /* Hack -- shrink the inscription */
+ tmp_val2[75 - n] = '\0';
+
+ /* Append the inscription */
+ t = object_desc_chr(t, ' ');
+ t = object_desc_chr(t, c1);
+ t = object_desc_str(t, tmp_val2);
+ t = object_desc_chr(t, c2);
+ }
+copyback:
+ /* Here's where we dump the built string into buf. */
+ tmp_val[79] = '\0';
+ t = tmp_val;
+ while ((*(buf++) = *(t++))); /* copy the string over */
+}
+
+
+/*
+ * Hack -- describe an item currently in a store's inventory
+ * This allows an item to *look* like the player is "aware" of it
+ */
+void object_desc_store(char *buf, object_type *o_ptr, int pref, int mode)
+{
+ /* Save the "aware" flag */
+ bool_ hack_aware = k_info[o_ptr->k_idx].aware;
+
+ /* Save the "known" flag */
+ bool_ hack_known = (o_ptr->ident & (IDENT_KNOWN)) ? TRUE : FALSE;
+
+
+ /* Set the "known" flag */
+ o_ptr->ident |= (IDENT_KNOWN);
+
+ /* Force "aware" for description */
+ k_info[o_ptr->k_idx].aware = TRUE;
+
+
+ /* Describe the object */
+ object_desc(buf, o_ptr, pref, mode);
+
+
+ /* Restore "aware" flag */
+ k_info[o_ptr->k_idx].aware = hack_aware;
+
+ /* Clear the known flag */
+ if (!hack_known) o_ptr->ident &= ~(IDENT_KNOWN);
+}
+
+
+
+
+/*
+ * Determine the "Activation" (if any) for an artifact
+ * Return a string, or NULL for "no activation"
+ */
+cptr item_activation(object_type *o_ptr, byte num)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Needed hacks */
+ static char rspell[2][80];
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Require activation ability */
+ if (!(f3 & (TR3_ACTIVATE))) return (NULL);
+
+
+ /*
+ * We need to deduce somehow that it is a random artifact -- one
+ * problem: It could be a random artifact which has NOT YET received
+ * a name. Thus we eliminate other possibilities instead of checking
+ * for art_name
+ */
+
+ if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL))
+ {
+ int gf, mod, mana;
+
+ if (!num)
+ {
+ gf = o_ptr->pval & 0xFFFF;
+ mod = o_ptr->pval3 & 0xFFFF;
+ mana = o_ptr->pval2 & 0xFF;
+ }
+ else
+ {
+ gf = o_ptr->pval >> 16;
+ mod = o_ptr->pval3 >> 16;
+ mana = o_ptr->pval2 >> 8;
+ }
+ sprintf(rspell[num], "runespell(%s, %s, %d) every %d turns",
+ k_info[lookup_kind(TV_RUNE1, gf)].name + k_name,
+ k_info[lookup_kind(TV_RUNE2, mod)].name + k_name,
+ mana, mana * 5);
+ return rspell[num];
+ }
+
+ if (o_ptr->tval == TV_EGG)
+ {
+ return "stop or resume the egg development";
+ }
+
+ if (o_ptr->tval == TV_INSTRUMENT)
+ {
+ if (!((o_ptr->name1 && a_info[o_ptr->name1].activate) ||
+ (o_ptr->name2 && e_info[o_ptr->name2].activate) ||
+ (o_ptr->name2b && e_info[o_ptr->name2b].activate)))
+ {
+ if (o_ptr->sval == SV_HORN)
+ {
+ return "aggravate monster every 100 turns";
+ }
+ }
+ }
+
+ if (process_hooks_ret(HOOK_ACTIVATE_DESC, "s", "(O)", o_ptr))
+ return (process_hooks_return[0].str);
+
+ return activation_aux(o_ptr, FALSE, 0);
+}
+
+/* Grab the tval desc */
+bool_ grab_tval_desc(int tval)
+{
+ int tv = 0;
+
+ while (tval_descs[tv].tval && (tval_descs[tv].tval != tval))
+ {
+ tv++;
+ }
+
+ if (!tval_descs[tv].tval) return FALSE;
+
+ text_out_c(TERM_L_BLUE, tval_descs[tv].desc);
+ text_out("\n");
+
+ return TRUE;
+}
+
+#define CHECK_FIRST(txt, first) \
+if ((first)) { (first) = FALSE; text_out((txt)); } else text_out(", ");
+
+/*
+ * Display the damage done with a multiplier
+ */
+void output_dam(object_type *o_ptr, int mult, int mult2, cptr against, cptr against2, bool_ *first)
+{
+ int dam;
+
+ dam = (o_ptr->dd + (o_ptr->dd * o_ptr->ds)) * 5 * mult;
+ dam += (o_ptr->to_d + p_ptr->to_d + p_ptr->to_d_melee) * 10;
+ dam *= p_ptr->num_blow;
+ CHECK_FIRST("", *first);
+ if (dam > 0)
+ {
+ if (dam % 10)
+ text_out_c(TERM_L_GREEN, format("%d.%d", dam / 10, dam % 10));
+ else
+ text_out_c(TERM_L_GREEN, format("%d", dam / 10));
+ }
+ else
+ text_out_c(TERM_L_RED, "0");
+ text_out(format(" against %s", against));
+
+ if (mult2)
+ {
+ dam = (o_ptr->dd + (o_ptr->dd * o_ptr->ds)) * 5 * mult2;
+ dam += (o_ptr->to_d + p_ptr->to_d + p_ptr->to_d_melee) * 10;
+ dam *= p_ptr->num_blow;
+ CHECK_FIRST("", *first);
+ if (dam > 0)
+ {
+ if (dam % 10)
+ text_out_c(TERM_L_GREEN, format("%d.%d", dam / 10, dam % 10));
+ else
+ text_out_c(TERM_L_GREEN, format("%d", dam / 10));
+ }
+ else
+ text_out_c(TERM_L_RED, "0");
+ text_out(format(" against %s", against2));
+ }
+}
+
+/*
+ * Outputs the damage we do/would do with the weapon
+ */
+void display_weapon_damage(object_type *o_ptr)
+{
+ object_type forge, *old_ptr = &forge;
+ u32b f1, f2, f3, f4, f5, esp;
+ bool_ first = TRUE;
+ bool_ full = o_ptr->ident & (IDENT_MENTAL);
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Ok now the hackish stuff, we replace the current weapon with this one */
+ object_copy(old_ptr, &p_ptr->inventory[INVEN_WIELD]);
+ object_copy(&p_ptr->inventory[INVEN_WIELD], o_ptr);
+ calc_bonuses(TRUE);
+
+ text_out("\nUsing it you would have ");
+ text_out_c(TERM_L_GREEN, format("%d ", p_ptr->num_blow));
+ text_out(format("blow%s and do an average damage per turn of ", (p_ptr->num_blow) ? "s" : ""));
+
+ if (full && (f1 & TR1_SLAY_ANIMAL)) output_dam(o_ptr, 2, 0, "animals", NULL, &first);
+ if (full && (f1 & TR1_SLAY_EVIL)) output_dam(o_ptr, 2, 0, "evil creatures", NULL, &first);
+ if (full && (f1 & TR1_SLAY_ORC)) output_dam(o_ptr, 3, 0, "orcs", NULL, &first);
+ if (full && (f1 & TR1_SLAY_TROLL)) output_dam(o_ptr, 3, 0, "trolls", NULL, &first);
+ if (full && (f1 & TR1_SLAY_GIANT)) output_dam(o_ptr, 3, 0, "giants", NULL, &first);
+ if (full && (f1 & TR1_KILL_DRAGON)) output_dam(o_ptr, 5, 0, "dragons", NULL, &first);
+ else if (full && (f1 & TR1_SLAY_DRAGON)) output_dam(o_ptr, 3, 0, "dragons", NULL, &first);
+ if (full && (f5 & TR5_KILL_UNDEAD)) output_dam(o_ptr, 5, 0, "undead", NULL, &first);
+ else if (full && (f1 & TR1_SLAY_UNDEAD)) output_dam(o_ptr, 3, 0, "undead", NULL, &first);
+ if (full && (f5 & TR5_KILL_DEMON)) output_dam(o_ptr, 5, 0, "demons", NULL, &first);
+ else if (full && (f1 & TR1_SLAY_DEMON)) output_dam(o_ptr, 3, 0, "demons", NULL, &first);
+
+ if (full && (f1 & TR1_BRAND_FIRE)) output_dam(o_ptr, 3, 6, "non fire resistant creatures", "fire susceptible creatures", &first);
+ if (full && (f1 & TR1_BRAND_COLD)) output_dam(o_ptr, 3, 6, "non cold resistant creatures", "cold susceptible creatures", &first);
+ if (full && (f1 & TR1_BRAND_ELEC)) output_dam(o_ptr, 3, 6, "non lightning resistant creatures", "lightning susceptible creatures", &first);
+ if (full && (f1 & TR1_BRAND_ACID)) output_dam(o_ptr, 3, 6, "non acid resistant creatures", "acid susceptible creatures", &first);
+ if (full && (f1 & TR1_BRAND_POIS)) output_dam(o_ptr, 3, 6, "non poison resistant creatures", "poison susceptible creatures", &first);
+
+ output_dam(o_ptr, 1, 0, (first) ? "all monsters" : "other monsters", NULL, &first);
+
+ text_out(".");
+
+ /* get our weapon back */
+ object_copy(&p_ptr->inventory[INVEN_WIELD], old_ptr);
+ calc_bonuses(TRUE);
+}
+
+/*
+ * Display the ammo damage done with a multiplier
+ */
+void output_ammo_dam(object_type *o_ptr, int mult, int mult2, cptr against, cptr against2, bool_ *first)
+{
+ int dam;
+ object_type *b_ptr = &p_ptr->inventory[INVEN_BOW];
+ int is_boomerang = (o_ptr->tval == TV_BOOMERANG);
+ int tmul = get_shooter_mult(b_ptr) + p_ptr->xtra_might;
+ if (is_boomerang) tmul = p_ptr->throw_mult;
+
+ dam = (o_ptr->dd + (o_ptr->dd * o_ptr->ds)) * 5;
+ dam += o_ptr->to_d * 10;
+ if (!is_boomerang) dam += b_ptr->to_d * 10;
+ dam *= tmul;
+ if (!is_boomerang) dam += (p_ptr->to_d_ranged) * 10;
+ dam *= mult;
+ CHECK_FIRST("", *first);
+ if (dam > 0)
+ {
+ if (dam % 10)
+ text_out_c(TERM_L_GREEN, format("%d.%d", dam / 10, dam % 10));
+ else
+ text_out_c(TERM_L_GREEN, format("%d", dam / 10));
+ }
+ else
+ text_out_c(TERM_L_RED, "0");
+ text_out(format(" against %s", against));
+
+ if (mult2)
+ {
+ dam = (o_ptr->dd + (o_ptr->dd * o_ptr->ds)) * 5;
+ dam += o_ptr->to_d * 10;
+ if (!is_boomerang) dam += b_ptr->to_d * 10;
+ dam *= tmul;
+ if (!is_boomerang) dam += (p_ptr->to_d_ranged) * 10;
+ dam *= mult2;
+ CHECK_FIRST("", *first);
+ if (dam > 0)
+ {
+ if (dam % 10)
+ text_out_c(TERM_L_GREEN, format("%d.%d", dam / 10, dam % 10));
+ else
+ text_out_c(TERM_L_GREEN, format("%d", dam / 10));
+ }
+ else
+ text_out_c(TERM_L_RED, "0");
+ text_out(format(" against %s", against2));
+ }
+}
+
+/*
+ * Outputs the damage we do/would do with the current bow and this ammo
+ */
+void display_ammo_damage(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+ bool_ first = TRUE;
+ int i;
+ bool_ full = o_ptr->ident & (IDENT_MENTAL);
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (o_ptr->tval == TV_BOOMERANG)
+ text_out("\nUsing it you would do an average damage per throw of ");
+ else
+ text_out("\nUsing it with your current shooter you would do an average damage per shot of ");
+ if (full && (f1 & TR1_SLAY_ANIMAL)) output_ammo_dam(o_ptr, 2, 0, "animals", NULL, &first);
+ if (full && (f1 & TR1_SLAY_EVIL)) output_ammo_dam(o_ptr, 2, 0, "evil creatures", NULL, &first);
+ if (full && (f1 & TR1_SLAY_ORC)) output_ammo_dam(o_ptr, 3, 0, "orcs", NULL, &first);
+ if (full && (f1 & TR1_SLAY_TROLL)) output_ammo_dam(o_ptr, 3, 0, "trolls", NULL, &first);
+ if (full && (f1 & TR1_SLAY_GIANT)) output_ammo_dam(o_ptr, 3, 0, "giants", NULL, &first);
+ if (full && (f1 & TR1_KILL_DRAGON)) output_ammo_dam(o_ptr, 5, 0, "dragons", NULL, &first);
+ else if (full && (f1 & TR1_SLAY_DRAGON)) output_ammo_dam(o_ptr, 3, 0, "dragons", NULL, &first);
+ if (full && (f5 & TR5_KILL_UNDEAD)) output_ammo_dam(o_ptr, 5, 0, "undeads", NULL, &first);
+ else if (full && (f1 & TR1_SLAY_UNDEAD)) output_ammo_dam(o_ptr, 3, 0, "undeads", NULL, &first);
+ if (full && (f5 & TR5_KILL_DEMON)) output_ammo_dam(o_ptr, 5, 0, "demons", NULL, &first);
+ else if (full && (f1 & TR1_SLAY_DEMON)) output_ammo_dam(o_ptr, 3, 0, "demons", NULL, &first);
+
+ if (full && (f1 & TR1_BRAND_FIRE)) output_ammo_dam(o_ptr, 3, 6, "non fire resistant creatures", "fire susceptible creatures", &first);
+ if (full && (f1 & TR1_BRAND_COLD)) output_ammo_dam(o_ptr, 3, 6, "non cold resistant creatures", "cold susceptible creatures", &first);
+ if (full && (f1 & TR1_BRAND_ELEC)) output_ammo_dam(o_ptr, 3, 6, "non lightning resistant creatures", "lightning susceptible creatures", &first);
+ if (full && (f1 & TR1_BRAND_ACID)) output_ammo_dam(o_ptr, 3, 6, "non acid resistant creatures", "acid susceptible creatures", &first);
+ if (full && (f1 & TR1_BRAND_POIS)) output_ammo_dam(o_ptr, 3, 6, "non poison resistant creatures", "poison susceptible creatures", &first);
+
+ output_ammo_dam(o_ptr, 1, 0, (first) ? "all monsters" : "other monsters", NULL, &first);
+ text_out(". ");
+
+ if (o_ptr->pval2)
+ {
+ text_out("The explosion will be ");
+ i = 0;
+ while (gf_names[i].gf != -1)
+ {
+ if (gf_names[i].gf == o_ptr->pval2)
+ break;
+ i++;
+ }
+ text_out_c(TERM_L_GREEN, (gf_names[i].gf != -1) ? gf_names[i].name : "something weird");
+ text_out(".");
+ }
+}
+
+/*
+ * Describe a magic stick powers
+ */
+void describe_device(object_type *o_ptr)
+{
+ /* Wands/... of shcool spell */
+ if (((o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_STAFF)) && object_known_p(o_ptr))
+ {
+ /* Enter device mode */
+ set_stick_mode(o_ptr);
+
+ text_out("\nSpell description:");
+ exec_lua(format("print_device_desc(%d)", o_ptr->pval2));
+
+ text_out("\nSpell level: ");
+ text_out_c(TERM_L_BLUE, string_exec_lua(format("return tostring(get_level(%d, 50, 0))", o_ptr->pval2)));
+
+ text_out("\nMinimum Magic Device level to increase spell level: ");
+ text_out_c(TERM_L_BLUE, format("%d", school_spells[o_ptr->pval2].skill_level));
+
+ text_out("\nSpell fail: ");
+ text_out_c(TERM_GREEN, string_exec_lua(format("return tostring(spell_chance(%d))", o_ptr->pval2)));
+
+ text_out("\nSpell info: ");
+ text_out_c(TERM_YELLOW, string_exec_lua(format("return __spell_info[%d]()", o_ptr->pval2)));
+
+ /* Leave device mode */
+ unset_stick_mode();
+
+ text_out("\n");
+ }
+}
+
+
+/*
+ * Helper for object_out_desc
+ *
+ * Print the level something was found on
+ *
+ */
+static cptr object_out_desc_where_found(s16b level, s16b dungeon)
+{
+ static char str[80];
+
+ if (dungeon == DUNGEON_WILDERNESS)
+ /* Taking care of older objects */
+ if (level == 0)
+ sprintf(str, "in the wilderness or in a town");
+ else if (wf_info[level].terrain_idx == TERRAIN_TOWN)
+ sprintf(str, "in the town of %s", wf_info[level].name + wf_name);
+ else
+ sprintf(str, "in %s", wf_info[level].text + wf_text);
+ else
+ sprintf(str, "on level %d of %s", level, d_info[dungeon].name + d_name);
+
+ return str;
+}
+
+/*
+ * Describe an item
+ */
+bool_ object_out_desc(object_type *o_ptr, FILE *fff, bool_ trim_down, bool_ wait_for_it)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ char *txt;
+
+ cptr vp[64];
+ byte vc[64];
+ int vn;
+
+ bool_ first = TRUE;
+
+ /* Extract the flags */
+ if ((!(o_ptr->ident & (IDENT_MENTAL))) && (!fff))
+ {
+ f1 = o_ptr->art_oflags1;
+ f2 = o_ptr->art_oflags2;
+ f3 = o_ptr->art_oflags3;
+ f4 = o_ptr->art_oflags4;
+ f5 = o_ptr->art_oflags5;
+ esp = o_ptr->art_oesp;
+ }
+ else
+ {
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ }
+
+ if (fff)
+ {
+ /* Set up stuff for text_out */
+ text_out_file = fff;
+ text_out_hook = text_out_to_file;
+ }
+ else
+ {
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Set up stuff for text_out */
+ text_out_hook = text_out_to_screen;
+ text_out("\n");
+ }
+
+ /* No need to dump that */
+ if (!fff)
+ {
+ if (!trim_down) grab_tval_desc(o_ptr->tval);
+ }
+
+ if (object_known_p(o_ptr))
+ {
+ if (o_ptr->k_idx && (!trim_down))
+ {
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ text_out_c(TERM_ORANGE, k_text + k_ptr->text);
+ text_out("\n");
+ }
+
+ if (o_ptr->name1 && (!trim_down))
+ {
+ artifact_type *a_ptr = &a_info[o_ptr->name1];
+
+ text_out_c(TERM_YELLOW, a_text + a_ptr->text);
+ text_out("\n");
+
+ if (a_ptr->set != -1)
+ {
+ set_type *set_ptr = &set_info[a_ptr->set];
+
+ text_out_c(TERM_GREEN, set_text + set_ptr->desc);
+ text_out("\n");
+ }
+ }
+
+ if ((f4 & TR4_LEVELS) && (!trim_down))
+ {
+ int j = 0;
+
+ if (count_bits(o_ptr->pval3) == 0) text_out("It is sentient");
+ else if (count_bits(o_ptr->pval3) > 1) text_out("It is sentient and can have access to the realms of ");
+ else text_out("It is sentient and can have access to the realm of ");
+
+ first = TRUE;
+ txt = "";
+ for (j = 0; j < MAX_FLAG_GROUP; j++)
+ {
+ if (BIT(j) & o_ptr->pval3)
+ {
+ CHECK_FIRST(txt, first);
+ text_out_c(flags_groups[j].color, flags_groups[j].name);
+ }
+ }
+
+ text_out(". ");
+ }
+
+ if (f4 & TR4_ULTIMATE)
+ {
+ if ((wield_slot(o_ptr) == INVEN_WIELD) ||
+ (wield_slot(o_ptr) == INVEN_BOW))
+ text_out_c(TERM_VIOLET, "It is part of the trinity of the ultimate weapons. ");
+ else
+ text_out_c(TERM_VIOLET, "It is the ultimate armor. ");
+ }
+
+ if (f4 & TR4_COULD2H) text_out("It can be wielded two-handed. ");
+ if (f4 & TR4_MUST2H) text_out("It must be wielded two-handed. ");
+
+ /* Mega-Hack -- describe activation */
+ if (f3 & (TR3_ACTIVATE))
+ {
+ text_out("It can be activated for ");
+ if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL))
+ {
+ text_out(item_activation(o_ptr, 0));
+ text_out(" and ");
+ text_out(item_activation(o_ptr, 1));
+ }
+ else
+ text_out(item_activation(o_ptr, 0));
+
+ /* Mega-hack -- get rid of useless line for e.g. randarts */
+ if (f5 & (TR5_ACTIVATE_NO_WIELD))
+ text_out(". ");
+ else
+ text_out(" if it is being worn. ");
+ }
+ /* Granted power */
+ if (object_power(o_ptr) != -1)
+ {
+ text_out("It grants you the power of ");
+ text_out(powers_type[object_power(o_ptr)].name);
+ text_out(" if it is being worn. ");
+ }
+
+ /* Hack -- describe lites */
+ if ((o_ptr->tval == TV_LITE) || (f3 & TR3_LITE1) || (f4 & TR4_LITE2) || (f4 & TR4_LITE3))
+ {
+ int radius = 0;
+
+ if (f3 & TR3_LITE1) radius++;
+ if (f4 & TR4_LITE2) radius += 2;
+ if (f4 & TR4_LITE3) radius += 3;
+ if (radius > 5) radius = 5;
+
+ if (f4 & TR4_FUEL_LITE)
+ {
+ text_out(format("It provides light (radius %d) when fueled. ", radius));
+ }
+ else
+ {
+ text_out(format("It provides light (radius %d) forever. ", radius));
+ }
+ }
+
+ /* Mega Hack^3 -- describe the Anchor of Space-time */
+ if (o_ptr->name1 == ART_ANCHOR)
+ {
+ text_out("It prevents the space-time continuum from being disrupted. ");
+ }
+
+ if ((f4 & (TR4_ANTIMAGIC_50)) || (f4 & (TR4_ANTIMAGIC_30)) || (f4 & (TR4_ANTIMAGIC_20)) || (f4 & (TR4_ANTIMAGIC_10)))
+ {
+ text_out("It generates an antimagic field. ");
+ }
+
+ if (f5 & TR5_SPELL_CONTAIN)
+ {
+ if (o_ptr->pval2 == -1)
+ text_out("It can be used to store a spell. ");
+ else
+ text_out("It has a spell stored inside. ");
+ }
+
+ /* Pick up stat bonuses */
+ vn = 0;
+ if (f1 & (TR1_STR)) vp[vn++] = "strength";
+ if (f1 & (TR1_INT)) vp[vn++] = "intelligence";
+ if (f1 & (TR1_WIS)) vp[vn++] = "wisdom";
+ if (f1 & (TR1_DEX)) vp[vn++] = "dexterity";
+ if (f1 & (TR1_CON)) vp[vn++] = "constitution";
+ if (f1 & (TR1_CHR)) vp[vn++] = "charisma";
+ if ((o_ptr->tval != TV_TRAPKIT) && (f1 & (TR1_STEALTH))) vp[vn++] = "stealth";
+ if (f1 & (TR1_SEARCH)) vp[vn++] = "searching";
+ if (f1 & (TR1_INFRA)) vp[vn++] = "infravision";
+ if (f1 & (TR1_TUNNEL)) vp[vn++] = "ability to tunnel";
+ if (f1 & (TR1_SPEED)) vp[vn++] = "speed";
+ if (f1 & (TR1_BLOWS)) vp[vn++] = "attack speed";
+ if (f5 & (TR5_CRIT)) vp[vn++] = "ability to score critical hits";
+ if (f5 & (TR5_LUCK)) vp[vn++] = "luck";
+ if (f1 & (TR1_SPELL)) vp[vn++] = "spell power";
+
+ /* Describe */
+ if (vn)
+ {
+ int i;
+
+ /* Intro */
+ text_out("It ");
+
+ /* What it does */
+ if (o_ptr->pval > 0) text_out("increases ");
+ else text_out("decreases ");
+
+ /* List */
+ for (i = 0; i < vn; i++)
+ {
+ /* Connectives */
+ if (i == 0) text_out("your ");
+ else if (i < (vn - 1)) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump the stat */
+ text_out(vp[i]);
+ }
+
+ text_out(" by ");
+ if (o_ptr->pval > 0)
+ text_out_c(TERM_L_GREEN, format("%i", o_ptr->pval));
+ else
+ text_out_c(TERM_L_RED, format("%i", -o_ptr->pval));
+ text_out(". ");
+ }
+
+
+ vn = 0;
+ if (f1 & (TR1_MANA)) vp[vn++] = "mana capacity";
+ if (f2 & (TR2_LIFE)) vp[vn++] = "hit points";
+
+ /* Describe with percentuals */
+ if (vn)
+ {
+ int percent;
+
+ /* What it does */
+ if (o_ptr->pval > 0)
+ text_out("It increases");
+ else
+ text_out("It decreases");
+
+ text_out(" your ");
+ text_out(vp[0]);
+ if (vn == 2)
+ {
+ text_out(" and ");
+ text_out(vp[1]);
+ }
+
+ text_out(" by ");
+ percent = 100 * o_ptr->pval / ( munchkin_multipliers ? 5 : 10 );
+
+
+ if (o_ptr->pval > 0)
+ text_out_c(TERM_L_GREEN, format("%i%%", percent));
+ else
+ text_out_c(TERM_L_RED, format("%i%%", -percent));
+ text_out(". ");
+ }
+
+ if ((o_ptr->tval == TV_TRAPKIT) && (f1 & (TR1_STEALTH)))
+ {
+ text_out("It is well-hidden. ");
+ }
+
+ vn = 0;
+ if (f1 & (TR1_BRAND_ACID))
+ {
+ vc[vn] = TERM_GREEN;
+ vp[vn++] = "acid";
+ }
+ if (f1 & (TR1_BRAND_ELEC))
+ {
+ vc[vn] = TERM_L_BLUE;
+ vp[vn++] = "electricity";
+ }
+ if (f1 & (TR1_BRAND_FIRE))
+ {
+ vc[vn] = TERM_RED;
+ vp[vn++] = "fire";
+ }
+ if (f1 & (TR1_BRAND_COLD))
+ {
+ vc[vn] = TERM_L_WHITE;
+ vp[vn++] = "frost";
+ }
+ /* Describe */
+ if (vn)
+ {
+ int i;
+
+ /* Intro */
+ text_out("It does extra damage ");
+
+ /* List */
+ for (i = 0; i < vn; i++)
+ {
+ /* Connectives */
+ if (i == 0) text_out("from ");
+ else if (i < (vn - 1)) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump the stat */
+ text_out_c(vc[i], vp[i]);
+ }
+ text_out(". ");
+ }
+
+
+ if (f1 & (TR1_BRAND_POIS))
+ {
+ text_out("It ");
+ text_out_c(TERM_L_GREEN, "poisons your foes");
+ text_out(". ");
+ }
+
+ if (f1 & (TR1_CHAOTIC))
+ {
+ text_out("It produces chaotic effects. ");
+ }
+
+ if (f1 & (TR1_VAMPIRIC))
+ {
+ text_out("It drains life from your foes. ");
+ }
+
+ if (f1 & (TR1_IMPACT))
+ {
+ text_out("It can cause earthquakes. ");
+ }
+
+ if (f1 & (TR1_VORPAL))
+ {
+ text_out("It is very sharp and can cut your foes. ");
+ }
+
+ if (f5 & (TR5_WOUNDING))
+ {
+ text_out("It is very sharp and can make your foes bleed. ");
+ }
+
+ if (f1 & (TR1_KILL_DRAGON))
+ {
+ text_out("It is a great bane of dragons. ");
+ }
+ else if (f1 & (TR1_SLAY_DRAGON))
+ {
+ text_out("It is especially deadly against dragons. ");
+ }
+ if (f1 & (TR1_SLAY_ORC))
+ {
+ text_out("It is especially deadly against orcs. ");
+ }
+ if (f1 & (TR1_SLAY_TROLL))
+ {
+ text_out("It is especially deadly against trolls. ");
+ }
+ if (f1 & (TR1_SLAY_GIANT))
+ {
+ text_out("It is especially deadly against giants. ");
+ }
+ if (f5 & (TR5_KILL_DEMON))
+ {
+ text_out("It is a great bane of demons. ");
+ }
+ else if (f1 & (TR1_SLAY_DEMON))
+ {
+ text_out("It strikes at demons with holy wrath. ");
+ }
+ if (f5 & (TR5_KILL_UNDEAD))
+ {
+ text_out("It is a great bane of undead. ");
+ }
+ else if (f1 & (TR1_SLAY_UNDEAD))
+ {
+ text_out("It strikes at undead with holy wrath. ");
+ }
+ if (f1 & (TR1_SLAY_EVIL))
+ {
+ text_out("It fights against evil with holy fury. ");
+ }
+ if (f1 & (TR1_SLAY_ANIMAL))
+ {
+ text_out("It is especially deadly against natural creatures. ");
+ }
+
+ if (f2 & (TR2_INVIS))
+ {
+ text_out("It makes you invisible. ");
+ }
+
+ if (o_ptr->tval != TV_TRAPKIT)
+ {
+ vn = 0;
+ if (f2 & (TR2_SUST_STR))
+ {
+ vp[vn++] = "strength";
+ }
+ if (f2 & (TR2_SUST_INT))
+ {
+ vp[vn++] = "intelligence";
+ }
+ if (f2 & (TR2_SUST_WIS))
+ {
+ vp[vn++] = "wisdom";
+ }
+ if (f2 & (TR2_SUST_DEX))
+ {
+ vp[vn++] = "dexterity";
+ }
+ if (f2 & (TR2_SUST_CON))
+ {
+ vp[vn++] = "constitution";
+ }
+ if (f2 & (TR2_SUST_CHR))
+ {
+ vp[vn++] = "charisma";
+ }
+ /* Describe */
+ if (vn)
+ {
+ int i;
+
+ /* Intro */
+ text_out("It sustains ");
+
+ /* List */
+ for (i = 0; i < vn; i++)
+ {
+ /* Connectives */
+ if (i == 0) text_out("your ");
+ else if (i < (vn - 1)) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump the stat */
+ text_out(vp[i]);
+ }
+ text_out(". ");
+ }
+
+ vn = 0;
+ if (f2 & (TR2_IM_ACID))
+ {
+ vc[vn] = TERM_GREEN;
+ vp[vn++] = "acid";
+ }
+ if (f2 & (TR2_IM_ELEC))
+ {
+ vc[vn] = TERM_L_BLUE;
+ vp[vn++] = "electricity";
+ }
+ if (f2 & (TR2_IM_FIRE))
+ {
+ vc[vn] = TERM_RED;
+ vp[vn++] = "fire";
+ }
+ if (f2 & (TR2_IM_COLD))
+ {
+ vc[vn] = TERM_L_WHITE;
+ vp[vn++] = "cold";
+ }
+ if (f4 & (TR4_IM_NETHER))
+ {
+ vc[vn] = TERM_L_GREEN;
+ vp[vn++] = "nether";
+ }
+ /* Describe */
+ if (vn)
+ {
+ int i;
+
+ /* Intro */
+ text_out("It provides immunity ");
+
+ /* List */
+ for (i = 0; i < vn; i++)
+ {
+ /* Connectives */
+ if (i == 0) text_out("to ");
+ else if (i < (vn - 1)) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump the stat */
+ text_out_c(vc[i], vp[i]);
+ }
+ text_out(". ");
+ }
+ }
+ else
+ {
+ if (f2 & (TRAP2_AUTOMATIC_5))
+ {
+ text_out("It can rearm itself. ");
+ }
+ if (f2 & (TRAP2_AUTOMATIC_99))
+ {
+ text_out("It rearms itself. ");
+ }
+ if (f2 & (TRAP2_KILL_GHOST))
+ {
+ text_out("It is effective against Ghosts. ");
+ }
+ if (f2 & (TRAP2_TELEPORT_TO))
+ {
+ text_out("It can teleport monsters to you. ");
+ }
+ if (f2 & (TRAP2_ONLY_DRAGON))
+ {
+ text_out("It can only be set off by dragons. ");
+ }
+ if (f2 & (TRAP2_ONLY_DEMON))
+ {
+ text_out("It can only be set off by demons. ");
+ }
+ if (f2 & (TRAP2_ONLY_UNDEAD))
+ {
+ text_out("It can only be set off by undead. ");
+ }
+ if (f2 & (TRAP2_ONLY_ANIMAL))
+ {
+ text_out("It can only be set off by animals. ");
+ }
+ if (f2 & (TRAP2_ONLY_EVIL))
+ {
+ text_out("It can only be set off by evil creatures. ");
+ }
+ }
+
+ if (f2 & (TR2_FREE_ACT))
+ {
+ text_out("It provides immunity to paralysis. ");
+ }
+ if (f2 & (TR2_RES_FEAR))
+ {
+ text_out("It makes you completely fearless. ");
+ }
+
+ vn = 0;
+ if (f2 & (TR2_HOLD_LIFE))
+ {
+ vp[vn++] = "life draining";
+ }
+ if ((f2 & (TR2_RES_ACID)) && !(f2 & (TR2_IM_ACID)))
+ {
+ vp[vn++] = "acid";
+ }
+ if ((f2 & (TR2_RES_ELEC)) && !(f2 & (TR2_IM_ELEC)))
+ {
+ vp[vn++] = "electricity";
+ }
+ if ((f2 & (TR2_RES_FIRE)) && !(f2 & (TR2_IM_FIRE)))
+ {
+ vp[vn++] = "fire";
+ }
+ if ((f2 & (TR2_RES_COLD)) && !(f2 & (TR2_IM_COLD)))
+ {
+ vp[vn++] = "cold";
+ }
+ if (f2 & (TR2_RES_POIS))
+ {
+ vp[vn++] = "poison";
+ }
+ if (f2 & (TR2_RES_LITE))
+ {
+ vp[vn++] = "light";
+ }
+ if (f2 & (TR2_RES_DARK))
+ {
+ vp[vn++] = "dark";
+ }
+ if (f2 & (TR2_RES_BLIND))
+ {
+ vp[vn++] = "blindness";
+ }
+ if (f2 & (TR2_RES_CONF))
+ {
+ vp[vn++] = "confusion";
+ }
+ if (f2 & (TR2_RES_SOUND))
+ {
+ vp[vn++] = "sound";
+ }
+ if (f2 & (TR2_RES_SHARDS))
+ {
+ vp[vn++] = "shards";
+ }
+ if ((f2 & (TR2_RES_NETHER)) && !(f4 & (TR4_IM_NETHER)))
+ {
+ vp[vn++] = "nether";
+ }
+ if (f2 & (TR2_RES_NEXUS))
+ {
+ vp[vn++] = "nexus";
+ }
+ if (f2 & (TR2_RES_CHAOS))
+ {
+ vp[vn++] = "chaos";
+ }
+ if (f2 & (TR2_RES_DISEN))
+ {
+ vp[vn++] = "disenchantment";
+ }
+ /* Describe */
+ if (vn)
+ {
+ int i;
+
+ /* Intro */
+ text_out("It provides resistance ");
+
+ /* List */
+ for (i = 0; i < vn; i++)
+ {
+ /* Connectives */
+ if (i == 0) text_out("to ");
+ else if (i < (vn - 1)) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump the stat */
+ text_out(vp[i]);
+ }
+ text_out(". ");
+ }
+
+ if (f2 & (TR2_SENS_FIRE))
+ {
+ text_out("It renders you especially vulnerable to fire. ");
+ }
+ if (f3 & (TR3_WRAITH))
+ {
+ text_out("It renders you incorporeal. ");
+ }
+ if (f5 & (TR5_WATER_BREATH))
+ {
+ text_out("It allows you to breathe underwater. ");
+ }
+ if (f5 & (TR5_MAGIC_BREATH))
+ {
+ text_out("It allows you to breathe without air. ");
+ }
+ if (f3 & (TR3_FEATHER))
+ {
+ text_out("It allows you to levitate. ");
+ }
+ if (f4 & (TR4_FLY))
+ {
+ text_out("It allows you to fly. ");
+ }
+ if (f4 & (TR4_CLIMB))
+ {
+ text_out("It allows you to climb mountains. ");
+ }
+ if (f5 & (TR5_IMMOVABLE))
+ {
+ text_out("It renders you immovable. ");
+ }
+ if (f3 & (TR3_SEE_INVIS))
+ {
+ text_out("It allows you to see invisible monsters. ");
+ }
+ if (esp)
+ {
+ if (esp & ESP_ALL) text_out("It gives telepathic powers. ");
+ else
+ {
+ vn = 0;
+ if (esp & ESP_ORC) vp[vn++] = "orcs";
+ if (esp & ESP_TROLL) vp[vn++] = "trolls";
+ if (esp & ESP_DRAGON) vp[vn++] = "dragons";
+ if (esp & ESP_SPIDER) vp[vn++] = "spiders";
+ if (esp & ESP_GIANT) vp[vn++] = "giants";
+ if (esp & ESP_DEMON) vp[vn++] = "demons";
+ if (esp & ESP_UNDEAD) vp[vn++] = "undead";
+ if (esp & ESP_EVIL) vp[vn++] = "evil beings";
+ if (esp & ESP_ANIMAL) vp[vn++] = "animals";
+ if (esp & ESP_THUNDERLORD) vp[vn++] = "thunderlords";
+ if (esp & ESP_GOOD) vp[vn++] = "good beings";
+ if (esp & ESP_NONLIVING) vp[vn++] = "non-living things";
+ if (esp & ESP_UNIQUE) vp[vn++] = "unique beings";
+ /* Describe */
+ if (vn)
+ {
+ int i;
+
+ /* Intro */
+ text_out("It allows you to sense the presence ");
+
+ /* List */
+ for (i = 0; i < vn; i++)
+ {
+ /* Connectives */
+ if (i == 0) text_out("of ");
+ else if (i < (vn - 1)) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump the stat */
+ text_out(vp[i]);
+ }
+ text_out(". ");
+ }
+ }
+ }
+
+ if (f3 & (TR3_SLOW_DIGEST))
+ {
+ text_out("It slows your metabolism. ");
+ }
+ if (f3 & (TR3_REGEN))
+ {
+ text_out("It speeds your regenerative powers. ");
+ }
+ if (f2 & (TR2_REFLECT))
+ {
+ text_out("It reflects bolts and arrows. ");
+ }
+ if (f3 & (TR3_SH_FIRE))
+ {
+ text_out("It produces a fiery sheath. ");
+ }
+ if (f3 & (TR3_SH_ELEC))
+ {
+ text_out("It produces an electric sheath. ");
+ }
+ if (f3 & (TR3_NO_MAGIC))
+ {
+ text_out("It produces an anti-magic shell. ");
+ }
+ if (f3 & (TR3_NO_TELE))
+ {
+ text_out("It prevents teleportation. ");
+ }
+ if (f3 & (TR3_XTRA_MIGHT))
+ {
+ text_out("It fires missiles with extra might. ");
+ }
+ if (f3 & (TR3_XTRA_SHOTS))
+ {
+ text_out("It fires missiles excessively fast. ");
+ }
+
+ vn = 0;
+ if (f5 & (TR5_DRAIN_MANA))
+ {
+ vc[vn] = TERM_BLUE;
+ vp[vn++] = "mana";
+ }
+ if (f5 & (TR5_DRAIN_HP))
+ {
+ vc[vn] = TERM_RED;
+ vp[vn++] = "life";
+ }
+ if (f3 & (TR3_DRAIN_EXP))
+ {
+ vc[vn] = TERM_L_DARK;
+ vp[vn++] = "experience";
+ }
+ /* Describe */
+ if (vn)
+ {
+ int i;
+
+ /* Intro */
+ text_out("It ");
+
+ /* List */
+ for (i = 0; i < vn; i++)
+ {
+ /* Connectives */
+ if (i == 0) text_out("drains ");
+ else if (i < (vn - 1)) text_out(", ");
+ else text_out(" and ");
+
+ /* Dump the stat */
+ text_out_c(vc[i], vp[i]);
+ }
+ text_out(". ");
+ }
+
+ if (f3 & (TR3_BLESSED))
+ {
+ text_out("It has been blessed by the gods. ");
+ }
+ if (f4 & (TR4_AUTO_ID))
+ {
+ text_out("It identifies all items for you. ");
+ }
+
+ if (f3 & (TR3_TELEPORT))
+ {
+ text_out("It induces random teleportation. ");
+ }
+ if (f3 & (TR3_AGGRAVATE))
+ {
+ text_out("It aggravates nearby creatures. ");
+ }
+ if (f4 & (TR4_NEVER_BLOW))
+ {
+ text_out("It can't attack. ");
+ }
+ if (f4 & (TR4_BLACK_BREATH))
+ {
+ text_out("It fills you with the Black Breath. ");
+ }
+ if (cursed_p(o_ptr))
+ {
+ if (f3 & (TR3_PERMA_CURSE))
+ {
+ text_out("It is permanently cursed. ");
+ }
+ else if (f3 & (TR3_HEAVY_CURSE))
+ {
+ text_out("It is heavily cursed. ");
+ }
+ else
+ {
+ text_out("It is cursed. ");
+ }
+ }
+ if (f3 & (TR3_TY_CURSE))
+ {
+ text_out("It carries an ancient foul curse. ");
+ }
+
+ if (f4 & (TR4_DG_CURSE))
+ {
+ text_out("It carries an ancient Morgothian curse. ");
+ }
+ if (f4 & (TR4_CLONE))
+ {
+ text_out("It can clone monsters. ");
+ }
+ if (f4 & (TR4_CURSE_NO_DROP))
+ {
+ text_out("It cannot be dropped while cursed. ");
+ }
+ if (f3 & (TR3_AUTO_CURSE))
+ {
+ text_out("It can re-curse itself. ");
+ }
+
+ if (f4 & (TR4_CAPACITY))
+ {
+ text_out("It can hold more mana. ");
+ }
+ if (f4 & (TR4_CHEAPNESS))
+ {
+ text_out("It can cast spells for a lesser mana cost. ");
+ }
+ if (f4 & (TR4_FAST_CAST))
+ {
+ text_out("It can cast spells faster. ");
+ }
+ if (f4 & (TR4_CHARGING))
+ {
+ text_out("It regenerates its mana faster. ");
+ }
+
+ if (f5 & (TR5_RES_MORGUL))
+ {
+ text_out("It can resist being shattered by morgul beings. ");
+ }
+ if ((f3 & (TR3_IGNORE_ACID)) && (f3 & (TR3_IGNORE_FIRE)) && (f3 & (TR3_IGNORE_COLD)) && (f3 & (TR3_IGNORE_ELEC)))
+ {
+ text_out("It cannot be harmed by acid, cold, lightning or fire. ");
+ }
+ else
+ {
+ if (f3 & (TR3_IGNORE_ACID))
+ {
+ text_out("It cannot be harmed by acid. ");
+ }
+ if (f3 & (TR3_IGNORE_ELEC))
+ {
+ text_out("It cannot be harmed by electricity. ");
+ }
+ if (f3 & (TR3_IGNORE_FIRE))
+ {
+ text_out("It cannot be harmed by fire. ");
+ }
+ if (f3 & (TR3_IGNORE_COLD))
+ {
+ text_out("It cannot be harmed by cold. ");
+ }
+ }
+ }
+
+
+ if (!trim_down && !fff)
+ {
+ describe_device(o_ptr);
+
+ if (object_known_p(o_ptr))
+ {
+ /* Damage display for weapons */
+ if (wield_slot(o_ptr) == INVEN_WIELD)
+ display_weapon_damage(o_ptr);
+
+ /* Breakage/Damage display for boomerangs */
+ if (o_ptr->tval == TV_BOOMERANG)
+ {
+ if (artifact_p(o_ptr))
+ text_out("\nIt can never be broken.");
+ else
+ text_out("\nIt has 1% chance to break upon hit.");
+ display_ammo_damage(o_ptr);
+ }
+
+ /* Breakage/Damage display for ammo */
+ if (wield_slot(o_ptr) == INVEN_AMMO)
+ {
+ if (artifact_p(o_ptr))
+ {
+ text_out("\nIt can never be broken.");
+ }
+ /* Exclude exploding arrows */
+ else if (o_ptr->pval2 == 0)
+ {
+ text_out("\nIt has ");
+ text_out_c(TERM_L_RED, format("%d", breakage_chance(o_ptr)));
+ text_out("% chance to break upon hit.");
+ }
+ display_ammo_damage(o_ptr);
+ }
+
+ /* Monster recall for totems and corpses */
+ if (o_ptr->tval == TV_TOTEM)
+ {
+ monster_description_out(o_ptr->pval, 0);
+ }
+ if (o_ptr->tval == TV_CORPSE)
+ {
+ monster_description_out(o_ptr->pval2, 0);
+ }
+ }
+
+ if (!object_known_p(o_ptr))
+ text_out("\nYou might need to identify the item to know some more about it...");
+ else if (!(o_ptr->ident & (IDENT_MENTAL)))
+ text_out("\nYou might need to *identify* the item to know more about it...");
+ }
+
+ /* Copying how others seem to do it. -- neil */
+ if (o_ptr->tval == TV_RING || o_ptr->tval == TV_AMULET ||
+ !trim_down || (ego_item_p(o_ptr)) || (artifact_p(o_ptr)))
+ {
+ /* Where did we found it ? */
+ if (o_ptr->found == OBJ_FOUND_MONSTER)
+ {
+ char m_name[80];
+
+ monster_race_desc(m_name, o_ptr->found_aux1, o_ptr->found_aux2);
+ text_out(format("\nYou found it in the remains of %s %s.",
+ m_name, object_out_desc_where_found(o_ptr->found_aux4, o_ptr->found_aux3)));
+ }
+ else if (o_ptr->found == OBJ_FOUND_FLOOR)
+ {
+ text_out(format("\nYou found it lying on the ground %s.",
+ object_out_desc_where_found(o_ptr->found_aux2, o_ptr->found_aux1)));
+ }
+ else if (o_ptr->found == OBJ_FOUND_VAULT)
+ {
+ text_out(format("\nYou found it lying in a vault %s.",
+ object_out_desc_where_found(o_ptr->found_aux2, o_ptr->found_aux1)));
+ }
+ else if (o_ptr->found == OBJ_FOUND_SPECIAL)
+ {
+ text_out("\nYou found it lying on the floor of a special level.");
+ }
+ else if (o_ptr->found == OBJ_FOUND_RUBBLE)
+ {
+ text_out("\nYou found it while digging a rubble.");
+ }
+ else if (o_ptr->found == OBJ_FOUND_REWARD)
+ {
+ text_out("\nIt was given to you as a reward.");
+ }
+ else if (o_ptr->found == OBJ_FOUND_STORE)
+ {
+ text_out(format("\nYou bought it from the %s.",
+ st_info[o_ptr->found_aux1].name + st_name));
+ }
+ else if (o_ptr->found == OBJ_FOUND_STOLEN)
+ {
+ text_out(format("\nYou stole it from the %s.",
+ st_info[o_ptr->found_aux1].name + st_name));
+ }
+ else if (o_ptr->found == OBJ_FOUND_SELFMADE)
+ {
+ text_out("\nYou made it yourself.");
+ }
+ /* useful for debugging
+ else
+ {
+ text_out("\nYou ordered it from a catalog in the Town.");
+ }*/
+ }
+
+ if (fff)
+ {
+ /* Flush the line position. */
+ text_out("\n");
+ text_out_file = NULL;
+ }
+ else
+ {
+ if (wait_for_it)
+ {
+ /* Wait for it */
+ inkey();
+
+ /* Restore the screen */
+ Term_load();
+ }
+ character_icky = FALSE;
+
+ }
+
+ /* Reset stuff for text_out */
+ text_out_hook = text_out_to_screen;
+
+ /* Gave knowledge */
+ return (TRUE);
+}
+
+
+
+/*
+ * Convert an inventory index into a one character label
+ * Note that the label does NOT distinguish inven/equip.
+ */
+char index_to_label(int i)
+{
+ /* Indexes for "inven" are easy */
+ if (i < INVEN_WIELD) return (I2A(i));
+
+ /* Indexes for "equip" are offset */
+ return (I2A(i - INVEN_WIELD));
+}
+
+
+/*
+ * Convert a label into the index of an item in the "inven"
+ * Return "-1" if the label does not indicate a real item
+ */
+s16b label_to_inven(int c)
+{
+ int i;
+
+ /* Convert */
+ i = (islower(c) ? A2I(c) : -1);
+
+ /* Verify the index */
+ if ((i < 0) || (i > INVEN_PACK)) return ( -1);
+
+ /* Empty slots can never be chosen */
+ if (!p_ptr->inventory[i].k_idx) return ( -1);
+
+ /* Return the index */
+ return (i);
+}
+
+
+/*
+ * Convert a label into the index of a item in the "equip"
+ * Return "-1" if the label does not indicate a real item
+ */
+s16b label_to_equip(int c)
+{
+ int i;
+
+ /* Convert */
+ i = ((islower(c) || (c > 'z')) ? A2I(c) : -1) + INVEN_WIELD;
+
+ /* Verify the index */
+ if ((i < INVEN_WIELD) || (i >= INVEN_TOTAL)) return ( -1);
+
+ /* Empty slots can never be chosen */
+ if (!p_ptr->inventory[i].k_idx) return ( -1);
+
+ /* Return the index */
+ return (i);
+}
+
+/*
+ * Returns the next free slot of the given "type", return the first
+ * if all are used
+ */
+int get_slot(int slot)
+{
+ int i = 0;
+
+ /* If there are at least one body part corretsonding, the find the free one */
+ if (p_ptr->body_parts[slot - INVEN_WIELD] == slot)
+ {
+ /* Find a free body part */
+ while ((i < 6) && (slot + i < INVEN_TOTAL) && (p_ptr->body_parts[slot - INVEN_WIELD + i] == slot))
+ {
+ if (p_ptr->body_parts[slot + i - INVEN_WIELD])
+ {
+ /* Free ? return the slot */
+ if (!p_ptr->inventory[slot + i].k_idx) return (slot + i);
+ }
+ else break;
+
+ i++;
+ }
+ /* Found nothing ? return the first one */
+ return slot;
+ }
+ /* No body parts ? return -1 */
+ else return ( -1);
+}
+
+/*
+ * Determine which equipment slot (if any) an item likes, ignoring the player's
+ * current body and stuff if ideal == TRUE
+ */
+s16b wield_slot_ideal(object_type *o_ptr, bool_ ideal)
+{
+ /* Try for a script first */
+ if (process_hooks_ret(HOOK_WIELD_SLOT, "d", "(O,d)", o_ptr, ideal))
+ return process_hooks_return[0].num;
+
+ /* Slot for equipment */
+ switch (o_ptr->tval)
+ {
+ case TV_DIGGING:
+ case TV_TOOL:
+ {
+ return ideal ? INVEN_TOOL : get_slot(INVEN_TOOL);
+ }
+
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_MSTAFF:
+ case TV_SWORD:
+ case TV_AXE:
+ {
+ return ideal ? INVEN_WIELD : get_slot(INVEN_WIELD);
+ }
+
+ case TV_BOOMERANG:
+ case TV_BOW:
+ case TV_INSTRUMENT:
+ {
+ return ideal ? INVEN_BOW : get_slot(INVEN_BOW);
+ }
+
+ case TV_RING:
+ {
+ return ideal ? INVEN_RING : get_slot(INVEN_RING);
+ }
+
+ case TV_AMULET:
+ {
+ return ideal ? INVEN_NECK : get_slot(INVEN_NECK);
+ }
+
+ case TV_LITE:
+ {
+ return ideal ? INVEN_LITE : get_slot(INVEN_LITE);
+ }
+
+ case TV_DRAG_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_SOFT_ARMOR:
+ {
+ return ideal ? INVEN_BODY : get_slot(INVEN_BODY);
+ }
+
+ case TV_CLOAK:
+ {
+ return ideal ? INVEN_OUTER : get_slot(INVEN_OUTER);
+ }
+
+ case TV_SHIELD:
+ {
+ return ideal ? INVEN_ARM : get_slot(INVEN_ARM);
+ }
+
+ case TV_CROWN:
+ case TV_HELM:
+ {
+ return ideal ? INVEN_HEAD : get_slot(INVEN_HEAD);
+ }
+
+ case TV_GLOVES:
+ {
+ return ideal ? INVEN_HANDS : get_slot(INVEN_HANDS);
+ }
+
+ case TV_BOOTS:
+ {
+ return ideal ? INVEN_FEET : get_slot(INVEN_FEET);
+ }
+
+ case TV_HYPNOS:
+ {
+ return ideal ? INVEN_CARRY : get_slot(INVEN_CARRY);
+ }
+
+ case TV_SHOT:
+ {
+ if (ideal)
+ {
+ return INVEN_AMMO;
+ }
+ else if (p_ptr->inventory[INVEN_AMMO].k_idx &&
+ object_similar(o_ptr, &p_ptr->inventory[INVEN_AMMO]) &&
+ p_ptr->inventory[INVEN_AMMO].number + o_ptr->number < MAX_STACK_SIZE)
+ {
+ return get_slot(INVEN_AMMO);
+ }
+ else if ((p_ptr->inventory[INVEN_BOW].k_idx) && (p_ptr->inventory[INVEN_BOW].tval == TV_BOW))
+ {
+ if (p_ptr->inventory[INVEN_BOW].sval < 10)
+ return get_slot(INVEN_AMMO);
+ }
+ return -1;
+ }
+
+ case TV_ARROW:
+ {
+ if (ideal)
+ {
+ return INVEN_AMMO;
+ }
+ else if (p_ptr->inventory[INVEN_AMMO].k_idx &&
+ object_similar(o_ptr, &p_ptr->inventory[INVEN_AMMO]) &&
+ p_ptr->inventory[INVEN_AMMO].number + o_ptr->number < MAX_STACK_SIZE)
+ {
+ return get_slot(INVEN_AMMO);
+ }
+ else if ((p_ptr->inventory[INVEN_BOW].k_idx) && (p_ptr->inventory[INVEN_BOW].tval == TV_BOW))
+ {
+ if ((p_ptr->inventory[INVEN_BOW].sval >= 10) && (p_ptr->inventory[INVEN_BOW].sval < 20))
+ return get_slot(INVEN_AMMO);
+ }
+ return -1;
+ }
+
+ case TV_BOLT:
+ {
+ if (ideal)
+ {
+ return INVEN_AMMO;
+ }
+ else if (p_ptr->inventory[INVEN_AMMO].k_idx &&
+ object_similar(o_ptr, &p_ptr->inventory[INVEN_AMMO]) &&
+ p_ptr->inventory[INVEN_AMMO].number + o_ptr->number < MAX_STACK_SIZE)
+ {
+ return get_slot(INVEN_AMMO);
+ }
+ else if ((p_ptr->inventory[INVEN_BOW].k_idx) && (p_ptr->inventory[INVEN_BOW].tval == TV_BOW))
+ {
+ if (p_ptr->inventory[INVEN_BOW].sval >= 20)
+ return get_slot(INVEN_AMMO);
+ }
+ return -1;
+ }
+ }
+
+ /* No slot available */
+ return ( -1);
+}
+
+/*
+ * Determine which equipment slot (if any) an item likes for the player's
+ * current body and stuff
+ */
+s16b wield_slot(object_type *o_ptr)
+{
+ return wield_slot_ideal(o_ptr, FALSE);
+}
+
+/*
+ * Return a string mentioning how a given item is carried
+ */
+cptr mention_use(int i)
+{
+ cptr p;
+
+ /* Examine the location */
+ switch (i)
+ {
+ case INVEN_WIELD:
+ case INVEN_WIELD + 1:
+ case INVEN_WIELD + 2:
+ p = "Wielding";
+ break;
+ case INVEN_BOW:
+ p = "Shooting";
+ break;
+ case INVEN_RING:
+ case INVEN_RING + 1:
+ case INVEN_RING + 2:
+ case INVEN_RING + 3:
+ case INVEN_RING + 4:
+ case INVEN_RING + 5:
+ p = "On finger";
+ break;
+ case INVEN_NECK:
+ case INVEN_NECK + 1:
+ p = "Around neck";
+ break;
+ case INVEN_LITE:
+ p = "Light source";
+ break;
+ case INVEN_BODY:
+ p = "On body";
+ break;
+ case INVEN_OUTER:
+ p = "About body";
+ break;
+ case INVEN_ARM:
+ case INVEN_ARM + 1:
+ case INVEN_ARM + 2:
+ p = "On arm";
+ break;
+ case INVEN_HEAD:
+ case INVEN_HEAD + 1:
+ p = "On head";
+ break;
+ case INVEN_HANDS:
+ case INVEN_HANDS + 1:
+ case INVEN_HANDS + 2:
+ p = "On hands";
+ break;
+ case INVEN_FEET:
+ case INVEN_FEET + 1:
+ p = "On feet";
+ break;
+ case INVEN_CARRY:
+ p = "Symbiote";
+ break;
+ case INVEN_AMMO:
+ p = "Quiver";
+ break;
+ case INVEN_TOOL:
+ p = "Using";
+ break;
+ default:
+ p = "In pack";
+ break;
+ }
+
+ /* Hack -- Heavy weapons */
+ if ((INVEN_WIELD <= i) && (i <= INVEN_WIELD + 2))
+ {
+ object_type *o_ptr;
+ o_ptr = &p_ptr->inventory[i];
+ if (adj_str_hold[p_ptr->stat_ind[A_STR]] < o_ptr->weight / 10)
+ {
+ p = "Just lifting";
+ }
+ }
+
+ /* Hack -- music instruments and heavy bow */
+ if (i == INVEN_BOW)
+ {
+ object_type *o_ptr;
+ o_ptr = &p_ptr->inventory[i];
+ if (o_ptr->tval == TV_INSTRUMENT)
+ {
+ p = "Playing";
+ }
+ else if (adj_str_hold[p_ptr->stat_ind[A_STR]] < o_ptr->weight / 10)
+ {
+ p = "Just holding";
+ }
+ }
+
+ /* Return the result */
+ return (p);
+}
+
+
+/*
+ * Return a string describing how a given item is being worn.
+ * Currently, only used for items in the equipment, not inventory.
+ */
+cptr describe_use(int i)
+{
+ cptr p;
+
+ switch (i)
+ {
+ case INVEN_WIELD:
+ case INVEN_WIELD + 1:
+ case INVEN_WIELD + 2:
+ p = "attacking monsters with";
+ break;
+ case INVEN_BOW:
+ p = "shooting missiles with";
+ break;
+ case INVEN_RING:
+ case INVEN_RING + 1:
+ case INVEN_RING + 2:
+ case INVEN_RING + 3:
+ case INVEN_RING + 4:
+ case INVEN_RING + 5:
+ p = "wearing on your finger";
+ break;
+ case INVEN_NECK:
+ case INVEN_NECK + 1:
+ p = "wearing around your neck";
+ break;
+ case INVEN_LITE:
+ p = "using to light the way";
+ break;
+ case INVEN_BODY:
+ p = "wearing on your body";
+ break;
+ case INVEN_OUTER:
+ p = "wearing on your back";
+ break;
+ case INVEN_ARM:
+ case INVEN_ARM + 1:
+ case INVEN_ARM + 2:
+ p = "wearing on your arm";
+ break;
+ case INVEN_HEAD:
+ case INVEN_HEAD + 1:
+ p = "wearing on your head";
+ break;
+ case INVEN_HANDS:
+ case INVEN_HANDS + 1:
+ case INVEN_HANDS + 2:
+ p = "wearing on your hands";
+ break;
+ case INVEN_FEET:
+ case INVEN_FEET + 1:
+ p = "wearing on your feet";
+ break;
+ case INVEN_CARRY:
+ p = "in symbiosis with";
+ break;
+ case INVEN_AMMO:
+ p = "carrying in your quiver";
+ break;
+ case INVEN_TOOL:
+ p = "using as a tool";
+ break;
+ default:
+ p = "carrying in your pack";
+ break;
+ }
+
+ /* Hack -- Heavy weapons */
+ if ((INVEN_WIELD <= i) && (i <= INVEN_WIELD + 2))
+ {
+ object_type *o_ptr;
+ o_ptr = &p_ptr->inventory[i];
+ if (adj_str_hold[p_ptr->stat_ind[A_STR]] < o_ptr->weight / 10)
+ {
+ p = "just lifting";
+ }
+ }
+
+ /* Hack -- Music instruments and heavy bow */
+ if (i == INVEN_BOW)
+ {
+ object_type *o_ptr;
+ o_ptr = &p_ptr->inventory[i];
+ if (o_ptr->tval == TV_INSTRUMENT)
+ {
+ p = "playing music with";
+ }
+ else if (adj_str_hold[p_ptr->stat_ind[A_STR]] < o_ptr->weight / 10)
+ {
+ p = "just holding";
+ }
+ }
+
+ /* Return the result */
+ return p;
+}
+
+/*
+ * Check an item against the item tester info
+ */
+bool_ item_tester_okay(object_type *o_ptr)
+{
+ /* Hack -- allow listing empty slots */
+ if (item_tester_full) return (TRUE);
+
+ /* Require an item */
+ if (!o_ptr->k_idx) return (FALSE);
+
+ /* Hack -- ignore "gold" */
+ if (o_ptr->tval == TV_GOLD) return (FALSE);
+
+ /* Check the tval */
+ if (item_tester_tval)
+ {
+ if (!(item_tester_tval == o_ptr->tval)) return (FALSE);
+ }
+
+ /* Check the hook */
+ if (item_tester_hook)
+ {
+ if (!(*item_tester_hook)(o_ptr)) return (FALSE);
+ }
+
+ /* Assume okay */
+ return (TRUE);
+}
+
+
+
+
+void show_equip_aux(bool_ mirror, bool_ everything);
+void show_inven_aux(bool_ mirror, bool_ everything);
+
+/*
+ * Choice window "shadow" of the "show_inven()" function
+ */
+void display_inven(void)
+{
+ show_inven_aux(TRUE, inventory_no_move);
+}
+
+
+
+/*
+ * Choice window "shadow" of the "show_equip()" function
+ */
+void display_equip(void)
+{
+ show_equip_aux(TRUE, inventory_no_move);
+}
+
+
+
+/* Get the color of the letter idx */
+byte get_item_letter_color(object_type *o_ptr)
+{
+ byte color = TERM_WHITE;
+
+ /* Must have knowlegde */
+ if (!object_known_p(o_ptr)) return (TERM_SLATE);
+
+ if (ego_item_p(o_ptr)) color = TERM_L_BLUE;
+ if (artifact_p(o_ptr)) color = TERM_YELLOW;
+ if (o_ptr->name1 && ( -1 != a_info[o_ptr->name1].set)) color = TERM_GREEN;
+ if (o_ptr->name1 && (a_info[o_ptr->name1].flags4 & TR4_ULTIMATE) && (o_ptr->ident & (IDENT_MENTAL))) color = TERM_VIOLET;
+
+ return (color);
+}
+
+
+/*
+ * Display the inventory.
+ *
+ * Hack -- do not display "trailing" empty slots
+ */
+void show_inven_aux(bool_ mirror, bool_ everything)
+{
+ int i, j, k, l, z = 0;
+ int row, col, len, lim;
+ int wid, hgt;
+ object_type *o_ptr;
+ char o_name[80];
+ char tmp_val[80];
+ int out_index[23];
+ byte out_color[23];
+ char out_desc[23][80];
+
+
+ /* Retrive current screen size */
+ Term_get_size(&wid, &hgt);
+
+ /* Starting row */
+ row = mirror ? 0 : 1;
+
+ /* Starting column */
+ col = mirror ? 0 : 50;
+
+ /* Default "max-length" */
+ len = 79 - col;
+
+ /* Maximum space allowed for descriptions */
+ lim = 79 - 3;
+
+ /* Require space for weight (if needed) */
+ if (show_weights) lim -= 9;
+
+ /* Require space for icon */
+ if (show_inven_graph) lim -= 2;
+
+ /* Find the "final" slot */
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Track */
+ z = i + 1;
+ }
+
+ /* Display the inventory */
+ for (k = 0, i = 0; i < z; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Is this item acceptable? */
+ if (!item_tester_okay(o_ptr))
+ {
+ if ( !everything )
+ continue;
+ out_index[k] = -i - 1;
+ }
+ else
+ {
+ /* Save the object index */
+ out_index[k] = i + 1;
+ }
+
+ /* Describe the object */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Hack -- enforce max length */
+ o_name[lim] = '\0';
+
+ /* Save the object color, and description */
+ out_color[k] = tval_to_attr[o_ptr->tval % 128];
+ (void)strcpy(out_desc[k], o_name);
+
+ /* Find the predicted "line length" */
+ l = strlen(out_desc[k]) + 5;
+
+ /* Be sure to account for the weight */
+ if (show_weights) l += 9;
+
+ /* Account for icon if displayed */
+ if (show_inven_graph) l += 2;
+
+ /* Maintain the maximum length */
+ if (l > len) len = l;
+
+ /* Advance to next "line" */
+ k++;
+ }
+
+ /* Find the column to start in */
+ if (mirror) col = 0;
+ else col = (len > wid - 4) ? 0 : (wid - len - 1);
+
+ /* Output each entry */
+ for (j = 0; j < k; j++)
+ {
+ /* Get the index */
+ i = out_index[j];
+
+ /* Get the item */
+ o_ptr = &p_ptr->inventory[ABS(i) - 1];
+
+ /* Clear the line */
+ prt("", row + j, col ? col - 2 : col);
+
+ /* Prepare an index --(-- */
+ /* Prepare a blank index if not selectable */
+ if ( i > 0 )
+ sprintf(tmp_val, "%c)", index_to_label(i - 1));
+ else
+ sprintf(tmp_val, " ");
+
+ /* Clear the line with the (possibly indented) index */
+ c_put_str(get_item_letter_color(o_ptr), tmp_val, row + j, col);
+
+ /* Display graphics for object, if desired */
+ if (show_inven_graph)
+ {
+ byte a = object_attr(o_ptr);
+ char c = object_char(o_ptr);
+
+ if (!o_ptr->k_idx) c = ' ';
+
+ Term_draw(col + 3, row + j, a, c);
+ }
+
+
+ /* Display the entry itself */
+ c_put_str(out_color[j], out_desc[j], row + j,
+ show_inven_graph ? (col + 5) : (col + 3));
+
+ /* Display the weight if needed */
+ if (show_weights)
+ {
+ int wgt = o_ptr->weight * o_ptr->number;
+ (void)sprintf(tmp_val, "%3d.%1d lb", wgt / 10, wgt % 10);
+ put_str(tmp_val, row + j, wid - 9);
+ }
+ }
+
+ /* Shadow windows */
+ if (mirror)
+ {
+ /* Erase the rest of the window */
+ for (j = row + k; j < Term->hgt; j++)
+ {
+ /* Erase the line */
+ Term_erase(0, j, 255);
+ }
+ }
+
+ /* Main window */
+ else
+ {
+ /* Make a "shadow" below the list (only if needed) */
+ if (j && (j < 23)) prt("", row + j, col ? col - 2 : col);
+ }
+}
+
+
+void show_inven()
+{
+ show_inven_aux(FALSE, FALSE);
+}
+
+void show_equip()
+{
+ show_equip_aux(FALSE, FALSE);
+}
+
+/*
+ * Display the equipment.
+ */
+void show_equip_aux(bool_ mirror, bool_ everything)
+{
+ int i, j, k, l;
+ int row, col, len, lim, idx;
+ int wid, hgt;
+ object_type *o_ptr;
+ char tmp_val[80];
+ char o_name[80];
+ int out_index[INVEN_TOOL - INVEN_WIELD];
+ int out_rindex[INVEN_TOOL - INVEN_WIELD];
+ byte out_color[INVEN_TOOL - INVEN_WIELD];
+ char out_desc[INVEN_TOOL - INVEN_WIELD][80];
+
+
+ /* Retrive current screen size */
+ Term_get_size(&wid, &hgt);
+
+ /* Starting row */
+ row = mirror ? 0 : 1;
+
+ /* Starting column */
+ col = mirror ? 0 : 50;
+
+ /* Maximal length */
+ len = 79 - col;
+
+ /* Maximum space allowed for descriptions */
+ lim = 79 - 3;
+
+ /* Require space for labels (if needed) */
+ if (show_labels) lim -= (14 + 2);
+
+ /* Require space for weight (if needed) */
+ if (show_weights) lim -= 9;
+
+ if (show_equip_graph) lim -= 2;
+
+ /* Scan the equipment list */
+ idx = 0;
+ for (k = 0, i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ /* Is there actualy a body part here ? */
+ if (!p_ptr->body_parts[i - INVEN_WIELD]) continue;
+
+ /* Mega Hack -- don't show symbiote slot if we can't use it */
+ if ((i == INVEN_CARRY) && (!get_skill(SKILL_SYMBIOTIC))) continue;
+
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Inform the player that he/she can't use a shield */
+ if ((p_ptr->body_parts[i - INVEN_WIELD] == INVEN_ARM) &&
+ !o_ptr->k_idx &&
+ p_ptr->inventory[i - INVEN_ARM + INVEN_WIELD].k_idx)
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+ object_type *q_ptr = &p_ptr->inventory[i - INVEN_ARM + INVEN_WIELD];
+ char q_name[80];
+
+ /* Description */
+ object_desc(q_name, q_ptr, TRUE, 3);
+
+ /* Get weapon flags */
+ object_flags(q_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (f4 & TR4_MUST2H)
+ {
+ sprintf(o_name, "(two handed) %s", q_name);
+
+ /* Truncate the description */
+ o_name[lim] = 0;
+
+ /* Save the index */
+ out_index[k] = idx;
+ out_rindex[k] = i;
+ idx++;
+
+ /* Save the color */
+ out_color[k] = TERM_L_RED;
+ (void)strcpy(out_desc[k], o_name);
+ continue;
+ }
+ }
+
+ if ((p_ptr->body_parts[i - INVEN_WIELD] == INVEN_WIELD) &&
+ !o_ptr->k_idx)
+ {
+ sprintf(o_name, "(%s)", melee_names[get_melee_skill()]);
+
+ /* Truncate the description */
+ o_name[lim] = 0;
+
+ /* Save the index */
+ out_index[k] = idx;
+ out_rindex[k] = i;
+ idx++;
+
+ /* Save the color */
+ out_color[k] = TERM_L_BLUE;
+ (void)strcpy(out_desc[k], o_name);
+ }
+ else
+ {
+ idx++;
+
+ /* Description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Truncate the description */
+ o_name[lim] = 0;
+ /* Is this item acceptable? */
+ if (!item_tester_okay(o_ptr))
+ {
+ if (!everything) continue;
+ out_index[k] = -1;
+ }
+ else
+ {
+ /* Save the index */
+ out_index[k] = idx;
+ }
+ out_rindex[k] = i;
+
+ /* Save the color */
+ out_color[k] = tval_to_attr[o_ptr->tval % 128];
+ (void)strcpy(out_desc[k], o_name);
+ }
+
+ /* Extract the maximal length (see below) */
+ l = strlen(out_desc[k]) + (2 + 3);
+
+ /* Increase length for labels (if needed) */
+ if (show_labels) l += (14 + 2);
+
+ /* Increase length for weight (if needed) */
+ if (show_weights) l += 9;
+
+ if (show_equip_graph) l += 2;
+
+ /* Maintain the max-length */
+ if (l > len) len = l;
+
+ /* Advance the entry */
+ k++;
+ }
+
+ /* Hack -- Find a column to start in */
+ if (mirror) col = 0;
+ else col = (len > wid - 4) ? 0 : (wid - len - 1);
+
+ /* Output each entry */
+ for (j = 0; j < k; j++)
+ {
+ if (j > 20) break;
+
+ /* Get the index */
+ i = out_index[j];
+
+ /* Get the item */
+ o_ptr = &p_ptr->inventory[out_rindex[j]];
+
+ /* Clear the line */
+ prt("", row + j, col ? col - 2 : col);
+
+ /* Prepare an index --(-- */
+ if (out_index[j] >= 0 )
+ sprintf(tmp_val, "%c)", index_to_label(out_rindex[j]));
+ else
+ sprintf(tmp_val, " ");
+
+ /* Clear the line with the (possibly indented) index */
+ c_put_str(get_item_letter_color(o_ptr), tmp_val, row + j, col);
+
+ if (show_equip_graph)
+ {
+ byte a = object_attr(o_ptr);
+ char c = object_char(o_ptr);
+
+ if (!o_ptr->k_idx) c = ' ';
+
+ Term_draw(col + 3, row + j, a, c);
+ }
+
+ /* Use labels */
+ if (show_labels)
+ {
+ /* Mention the use */
+ (void)sprintf(tmp_val, "%-14s: ", mention_use(out_rindex[j]));
+ put_str(tmp_val, row + j, show_equip_graph ? col + 5 : col + 3);
+
+ /* Display the entry itself */
+ c_put_str(out_color[j], out_desc[j], row + j, show_equip_graph ? col + 21 : col + 19);
+ }
+
+ /* No labels */
+ else
+ {
+ /* Display the entry itself */
+ c_put_str(out_color[j], out_desc[j], row + j, show_equip_graph ? col + 5 : col + 3);
+ }
+
+ /* Display the weight if needed */
+ if (show_weights)
+ {
+ int wgt = o_ptr->weight * o_ptr->number;
+ (void)sprintf(tmp_val, "%3d.%d lb", wgt / 10, wgt % 10);
+ put_str(tmp_val, row + j, wid - 9);
+ }
+ }
+
+
+ /* Shadow windows */
+ if (mirror)
+ {
+ /* Erase the rest of the window */
+ for (j = row + k; j < Term->hgt; j++)
+ {
+ /* Erase the line */
+ Term_erase(0, j, 255);
+ }
+ }
+
+ /* Main window */
+ else
+ {
+ /* Make a "shadow" below the list (only if needed) */
+ if (j && (j < 23)) prt("", row + j, col ? col - 2 : col);
+ }
+}
+
+
+
+
+/*
+ * Flip "inven" and "equip" in any sub-windows
+ */
+void toggle_inven_equip(void)
+{
+ int j;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ /* Unused */
+ if (!angband_term[j]) continue;
+
+ /* Flip inven to equip */
+ if (window_flag[j] & (PW_INVEN))
+ {
+ /* Flip flags */
+ window_flag[j] &= ~(PW_INVEN);
+ window_flag[j] |= (PW_EQUIP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP);
+ }
+
+ /* Flip inven to equip */
+ else if (window_flag[j] & (PW_EQUIP))
+ {
+ /* Flip flags */
+ window_flag[j] &= ~(PW_EQUIP);
+ window_flag[j] |= (PW_INVEN);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+ }
+ }
+}
+
+
+
+/*
+ * Verify the choice of an item.
+ *
+ * The item can be negative to mean "item on floor".
+ */
+bool_ verify(cptr prompt, int item)
+{
+ char o_name[80];
+
+ char out_val[160];
+
+ object_type *o_ptr;
+
+ /* Get object */
+ o_ptr = get_object(item);
+
+ /* Describe */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Prompt */
+ (void)sprintf(out_val, "%s %s? ", prompt, o_name);
+
+ /* Query */
+ return (get_check(out_val));
+}
+
+
+/*
+ * Hack -- allow user to "prevent" certain choices
+ *
+ * The item can be negative to mean "item on floor".
+ */
+static bool_ get_item_allow(int item)
+{
+ cptr s;
+
+ object_type *o_ptr;
+
+ /* Get object */
+ o_ptr = get_object(item);
+
+ /* No inscription */
+ if (!o_ptr->note) return (TRUE);
+
+ /* Find a '!' */
+ s = strchr(quark_str(o_ptr->note), '!');
+
+ /* Process preventions */
+ while (s)
+ {
+ /* Check the "restriction" */
+ if ((s[1] == command_cmd) || (s[1] == '*'))
+ {
+ /* Verify the choice */
+ if (!verify("Really try", item)) return (FALSE);
+ }
+
+ /* Find another '!' */
+ s = strchr(s + 1, '!');
+ }
+
+ /* Allow it */
+ return (TRUE);
+}
+
+
+
+/*
+ * Auxiliary function for "get_item()" -- test an index
+ */
+static bool_ get_item_okay(int i)
+{
+ /* Illegal items */
+ if ((i < 0) || (i >= INVEN_TOTAL)) return (FALSE);
+
+ /* Verify the item */
+ if (!item_tester_okay(&p_ptr->inventory[i])) return (FALSE);
+
+ /* Assume okay */
+ return (TRUE);
+}
+
+
+
+/*
+ * Find the "first" inventory object with the given "tag".
+ *
+ * A "tag" is a char "n" appearing as "@n" anywhere in the
+ * inscription of an object.
+ *
+ * Also, the tag "@xn" will work as well, where "n" is a tag-char,
+ * and "x" is the "current" command_cmd code.
+ */
+static int get_tag(int *cp, char tag)
+{
+ int i;
+ cptr s;
+
+
+ /* Check every object */
+ for (i = 0; i < INVEN_TOTAL; ++i)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Skip empty inscriptions */
+ if (!o_ptr->note) continue;
+
+ /* Find a '@' */
+ s = strchr(quark_str(o_ptr->note), '@');
+
+ /* Process all tags */
+ while (s)
+ {
+ /* Check the normal tags */
+ if (s[1] == tag)
+ {
+ /* Save the actual inventory ID */
+ *cp = i;
+
+ /* Success */
+ return (TRUE);
+ }
+
+ /* Check the special tags */
+ if ((s[1] == command_cmd) && (s[2] == tag))
+ {
+ /* Save the actual inventory ID */
+ *cp = i;
+
+ /* Success */
+ return (TRUE);
+ }
+
+ /* Find another '@' */
+ s = strchr(s + 1, '@');
+ }
+ }
+
+ /* No such tag */
+ return (FALSE);
+}
+
+/*
+ * scan_floor --
+ *
+ * Return a list of o_list[] indexes of items at the given cave
+ * location. Valid flags are:
+ *
+ * mode & 0x01 -- Item tester
+ * mode & 0x02 -- Marked items only
+ * mode & 0x04 -- Stop after first
+ */
+bool_ scan_floor(int *items, int *item_num, int y, int x, int mode)
+{
+ int this_o_idx, next_o_idx;
+
+ int num = 0;
+
+ (*item_num) = 0;
+
+ /* Sanity */
+ if (!in_bounds(y, x)) return (FALSE);
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = cave[y][x].o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Item tester */
+ if ((mode & 0x01) && !item_tester_okay(o_ptr)) continue;
+
+ /* Marked */
+ if ((mode & 0x02) && !o_ptr->marked) continue;
+
+ /* Accept this item */
+ items[num++] = this_o_idx;
+
+ /* Only one */
+ if (mode & 0x04) break;
+
+ /* XXX Hack -- Enforce limit */
+ if (num == 23) break;
+ }
+
+ /* Number of items */
+ (*item_num) = num;
+
+ /* Result */
+ return (num != 0);
+}
+
+/*
+ * Display a list of the items on the floor at the given location.
+ */
+void show_floor(int y, int x)
+{
+ int i, j, k, l;
+ int col, len, lim;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ char tmp_val[80];
+
+ int out_index[23];
+ byte out_color[23];
+ char out_desc[23][80];
+
+ int floor_list[23], floor_num;
+
+ /* Default length */
+ len = 79 - 50;
+
+ /* Maximum space allowed for descriptions */
+ lim = 79 - 3;
+
+ /* Require space for weight (if needed) */
+ if (show_weights) lim -= 9;
+
+ /* Scan for objects in the grid, using item_tester_okay() */
+ (void) scan_floor(floor_list, &floor_num, y, x, 0x01);
+
+ /* Display the inventory */
+ for (k = 0, i = 0; i < floor_num; i++)
+ {
+ o_ptr = &o_list[floor_list[i]];
+
+ /* Describe the object */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Hack -- enforce max length */
+ o_name[lim] = '\0';
+
+ /* Save the index */
+ out_index[k] = i;
+
+ /* Acquire inventory color */
+ out_color[k] = tval_to_attr[o_ptr->tval & 0x7F];
+
+ /* Save the object description */
+ strcpy(out_desc[k], o_name);
+
+ /* Find the predicted "line length" */
+ l = strlen(out_desc[k]) + 5;
+
+ /* Be sure to account for the weight */
+ if (show_weights) l += 9;
+
+ /* Maintain the maximum length */
+ if (l > len) len = l;
+
+ /* Advance to next "line" */
+ k++;
+ }
+
+ /* Find the column to start in */
+ col = (len > 76) ? 0 : (79 - len);
+
+ /* Output each entry */
+ for (j = 0; j < k; j++)
+ {
+ /* Get the index */
+ i = floor_list[out_index[j]];
+
+ /* Get the item */
+ o_ptr = &o_list[i];
+
+ /* Clear the line */
+ prt("", j + 1, col ? col - 2 : col);
+
+ /* Prepare an index --(-- */
+ sprintf(tmp_val, "%c)", index_to_label(j));
+
+ /* Clear the line with the (possibly indented) index */
+ put_str(tmp_val, j + 1, col);
+
+ /* Display the entry itself */
+ c_put_str(out_color[j], out_desc[j], j + 1, col + 3);
+
+ /* Display the weight if needed */
+ if (show_weights)
+ {
+ int wgt = o_ptr->weight * o_ptr->number;
+ sprintf(tmp_val, "%3d.%1d lb", wgt / 10, wgt % 10);
+ put_str(tmp_val, j + 1, 71);
+ }
+ }
+
+ /* Make a "shadow" below the list (only if needed) */
+ if (j && (j < 23)) prt("", j + 1, col ? col - 2 : col);
+}
+
+/*
+ * This version of get_item() is called by get_item() when
+ * the easy_floor is on.
+ */
+bool_ (*get_item_extra_hook)(int *cp);
+bool_ get_item_floor(int *cp, cptr pmt, cptr str, int mode)
+{
+ char n1 = 0, n2 = 0, which = ' ';
+
+ int j, k, i1, i2, e1, e2;
+
+ bool_ done, item;
+
+ bool_ oops = FALSE;
+
+ bool_ equip = FALSE;
+ bool_ inven = FALSE;
+ bool_ floor = FALSE;
+ bool_ extra = FALSE;
+ bool_ automat = FALSE;
+
+ bool_ allow_equip = FALSE;
+ bool_ allow_inven = FALSE;
+ bool_ allow_floor = FALSE;
+
+ bool_ toggle = FALSE;
+
+ char tmp_val[160];
+ char out_val[160];
+
+ int floor_num, floor_list[23], floor_top = 0;
+
+ k = 0;
+
+ /* Get the item index */
+ if (repeat_pull(cp))
+ {
+ /* Floor item? */
+ if (*cp < 0)
+ {
+ object_type *o_ptr;
+
+ /* Special index */
+ k = 0 - (*cp);
+
+ /* Acquire object */
+ o_ptr = &o_list[k];
+
+ /* Validate the item */
+ if (item_tester_okay(o_ptr))
+ {
+ /* Forget the item_tester_tval restriction */
+ item_tester_tval = 0;
+
+ /* Forget the item_tester_hook restriction */
+ item_tester_hook = NULL;
+
+ /* Success */
+ return (TRUE);
+ }
+ }
+
+ /* Verify the item */
+ else if (get_item_okay(*cp))
+ {
+ /* Forget the item_tester_tval restriction */
+ item_tester_tval = 0;
+
+ /* Forget the item_tester_hook restriction */
+ item_tester_hook = NULL;
+
+ /* Success */
+ return (TRUE);
+ }
+ }
+
+
+ /* Extract args */
+ if (mode & (USE_EQUIP)) equip = TRUE;
+ if (mode & (USE_INVEN)) inven = TRUE;
+ if (mode & (USE_FLOOR)) floor = TRUE;
+ if (mode & (USE_EXTRA)) extra = TRUE;
+ if (mode & (USE_AUTO)) automat = TRUE;
+
+
+ /* Paranoia XXX XXX XXX */
+ msg_print(NULL);
+
+
+ /* Not done */
+ done = FALSE;
+
+ /* No item selected */
+ item = FALSE;
+
+
+ /* Full inventory */
+ i1 = 0;
+ i2 = INVEN_PACK - 1;
+
+ /* Forbid inventory */
+ if (!inven) i2 = -1;
+
+ /* Restrict inventory indexes */
+ while ((i1 <= i2) && (!get_item_okay(i1))) i1++;
+ while ((i1 <= i2) && (!get_item_okay(i2))) i2--;
+
+
+ /* Full equipment */
+ e1 = INVEN_WIELD;
+ e2 = INVEN_TOTAL - 1;
+
+ /* Forbid equipment */
+ if (!equip) e2 = -1;
+
+ /* Restrict equipment indexes */
+ while ((e1 <= e2) && (!get_item_okay(e1))) e1++;
+ while ((e1 <= e2) && (!get_item_okay(e2))) e2--;
+
+
+ /* Count "okay" floor items */
+ floor_num = 0;
+
+ /* Restrict floor usage */
+ if (floor)
+ {
+ /* Scan all objects in the grid */
+ (void) scan_floor(floor_list, &floor_num, p_ptr->py, p_ptr->px, 0x01);
+ }
+
+ /* Accept inventory */
+ if (i1 <= i2) allow_inven = TRUE;
+
+ /* Accept equipment */
+ if (e1 <= e2) allow_equip = TRUE;
+
+ /* Accept floor */
+ if (floor_num) allow_floor = TRUE;
+
+ /* Require at least one legal choice */
+ if (!allow_inven && !allow_equip && !allow_floor)
+ {
+ /* Oops */
+ oops = TRUE;
+
+ /* Done */
+ done = TRUE;
+ }
+
+ /* Analyze choices */
+ else
+ {
+ /* Hack -- Start on equipment if requested */
+ if ((command_wrk == (USE_EQUIP)) && allow_equip)
+ {
+ command_wrk = (USE_EQUIP);
+ }
+
+ /* Use inventory if allowed */
+ else if (allow_inven)
+ {
+ command_wrk = (USE_INVEN);
+ }
+
+ /* Use equipment if allowed */
+ else if (allow_equip)
+ {
+ command_wrk = (USE_EQUIP);
+ }
+
+ /* Use floor if allowed */
+ else if (allow_floor)
+ {
+ command_wrk = (USE_FLOOR);
+ }
+ }
+
+ /* Save screen */
+ screen_save();
+
+ /* Repeat until done */
+ while (!done)
+ {
+ /* Show choices */
+ if (show_choices)
+ {
+ int ni = 0;
+ int ne = 0;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ /* Unused */
+ if (!angband_term[j]) continue;
+
+ /* Count windows displaying inven */
+ if (window_flag[j] & (PW_INVEN)) ni++;
+
+ /* Count windows displaying equip */
+ if (window_flag[j] & (PW_EQUIP)) ne++;
+ }
+
+ /* Toggle if needed */
+ if ((command_wrk == (USE_EQUIP) && ni && !ne) ||
+ (command_wrk == (USE_INVEN) && !ni && ne))
+ {
+ /* Toggle */
+ toggle_inven_equip();
+
+ /* Track toggles */
+ toggle = !toggle;
+ }
+
+ /* Update */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Redraw windows */
+ window_stuff();
+ }
+
+ /* Inventory screen */
+ if (command_wrk == (USE_INVEN))
+ {
+ /* Extract the legal requests */
+ n1 = I2A(i1);
+ n2 = I2A(i2);
+
+ /* Redraw */
+ show_inven();
+ }
+
+ /* Equipment screen */
+ else if (command_wrk == (USE_EQUIP))
+ {
+ /* Extract the legal requests */
+ n1 = I2A(e1 - INVEN_WIELD);
+ n2 = I2A(e2 - INVEN_WIELD);
+
+ /* Redraw */
+ show_equip();
+ }
+
+ /* Floor screen */
+ else if (command_wrk == (USE_FLOOR))
+ {
+ j = floor_top;
+ k = MIN(floor_top + 23, floor_num) - 1;
+
+ /* Extract the legal requests */
+ n1 = I2A(j - floor_top);
+ n2 = I2A(k - floor_top);
+
+ /* Redraw */
+ show_floor(p_ptr->py, p_ptr->px);
+ }
+
+ /* Viewing inventory */
+ if (command_wrk == (USE_INVEN))
+ {
+ /* Begin the prompt */
+ sprintf(out_val, "Inven:");
+
+ /* Build the prompt */
+ sprintf(tmp_val, " %c-%c,",
+ index_to_label(i1), index_to_label(i2));
+
+ /* Append */
+ strcat(out_val, tmp_val);
+
+ /* Append */
+ if (allow_equip) strcat(out_val, " / for Equip,");
+
+ /* Append */
+ if (allow_floor) strcat(out_val, " - for floor,");
+ }
+
+ /* Viewing equipment */
+ else if (command_wrk == (USE_EQUIP))
+ {
+ /* Begin the prompt */
+ sprintf(out_val, "Equip:");
+
+ /* Build the prompt */
+ sprintf(tmp_val, " %c-%c,",
+ index_to_label(e1), index_to_label(e2));
+
+ /* Append */
+ strcat(out_val, tmp_val);
+
+ /* Append */
+ if (allow_inven) strcat(out_val, " / for Inven,");
+
+ /* Append */
+ if (allow_floor) strcat(out_val, " - for floor,");
+ }
+
+ /* Viewing floor */
+ else if (command_wrk == (USE_FLOOR))
+ {
+ /* Begin the prompt */
+ sprintf(out_val, "Floor:");
+
+ /* Build the prompt */
+ sprintf(tmp_val, " %c-%c,", n1, n2);
+
+ /* Append */
+ strcat(out_val, tmp_val);
+
+ /* Append */
+ if (allow_inven)
+ {
+ strcat(out_val, " / for Inven,");
+ }
+ else if (allow_equip)
+ {
+ strcat(out_val, " / for Equip,");
+ }
+ }
+
+ /* Extra? */
+ if (extra)
+ {
+ strcat(out_val, " @ for extra selection,");
+ }
+
+ /* Create automatizer rule?? */
+ if (automat)
+ {
+ if (automatizer_create)
+ strcat(out_val, " $ new automatizer rule(ON),");
+ else
+ strcat(out_val, " $ new automatizer rule(OFF),");
+ }
+
+ /* Finish the prompt */
+ strcat(out_val, " ESC");
+
+ /* Build the prompt */
+ sprintf(tmp_val, "(%s) %s", out_val, pmt);
+
+ /* Show the prompt */
+ prt(tmp_val, 0, 0);
+
+ /* Get a key */
+ which = inkey();
+
+ /* Parse it */
+ switch (which)
+ {
+ case ESCAPE:
+ {
+ done = TRUE;
+ break;
+ }
+
+ case '/':
+ {
+ if (command_wrk == (USE_INVEN))
+ {
+ if (!allow_equip)
+ {
+ bell();
+ break;
+ }
+ command_wrk = (USE_EQUIP);
+ }
+ else if (command_wrk == (USE_EQUIP))
+ {
+ if (!allow_inven)
+ {
+ bell();
+ break;
+ }
+ command_wrk = (USE_INVEN);
+ }
+ else if (command_wrk == (USE_FLOOR))
+ {
+ if (allow_inven)
+ {
+ command_wrk = (USE_INVEN);
+ }
+ else if (allow_equip)
+ {
+ command_wrk = (USE_EQUIP);
+ }
+ else
+ {
+ bell();
+ break;
+ }
+ }
+
+ /* Hack -- Fix screen */
+ screen_load();
+ screen_save();
+
+ /* Need to redraw */
+ break;
+ }
+
+ case '-':
+ {
+ if (!allow_floor)
+ {
+ bell();
+ break;
+ }
+
+ /*
+ * If we are already examining the floor, and there
+ * is only one item, we will always select it.
+ * If we aren't examining the floor and there is only
+ * one item, we will select it if floor_query_flag
+ * is FALSE.
+ */
+ if (floor_num == 1)
+ {
+ if (command_wrk == (USE_FLOOR))
+ {
+ /* Special index */
+ k = 0 - floor_list[0];
+
+ /* Allow player to "refuse" certain actions */
+ if (!get_item_allow(k))
+ {
+ done = TRUE;
+ break;
+ }
+
+ /* Accept that choice */
+ (*cp) = k;
+ item = TRUE;
+ done = TRUE;
+
+ break;
+ }
+ }
+
+ /* Hack -- Fix screen */
+ screen_load();
+ screen_save();
+
+ command_wrk = (USE_FLOOR);
+
+ break;
+ }
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ /* Look up the tag */
+ if (!get_tag(&k, which))
+ {
+ bell();
+ break;
+ }
+
+ /* Hack -- Validate the item */
+ if ((k < INVEN_WIELD) ? !inven : !equip)
+ {
+ bell();
+ break;
+ }
+
+ /* Validate the item */
+ if (!get_item_okay(k))
+ {
+ bell();
+ break;
+ }
+
+ /* Allow player to "refuse" certain actions */
+ if (!get_item_allow(k))
+ {
+ done = TRUE;
+ break;
+ }
+
+ /* Accept that choice */
+ (*cp) = k;
+ item = TRUE;
+ done = TRUE;
+ break;
+ }
+
+ case '\n':
+ case '\r':
+ {
+ /* Choose "default" inventory item */
+ if (command_wrk == (USE_INVEN))
+ {
+ k = ((i1 == i2) ? i1 : -1);
+ }
+
+ /* Choose "default" equipment item */
+ else if (command_wrk == (USE_EQUIP))
+ {
+ k = ((e1 == e2) ? e1 : -1);
+ }
+
+ /* Choose "default" floor item */
+ else if (command_wrk == (USE_FLOOR))
+ {
+ if (floor_num == 1)
+ {
+ /* Special index */
+ k = 0 - floor_list[0];
+
+ /* Allow player to "refuse" certain actions */
+ if (!get_item_allow(k))
+ {
+ done = TRUE;
+ break;
+ }
+
+ /* Accept that choice */
+ (*cp) = k;
+ item = TRUE;
+ done = TRUE;
+ }
+ break;
+ }
+
+ /* Validate the item */
+ if (!get_item_okay(k))
+ {
+ bell();
+ break;
+ }
+
+ /* Allow player to "refuse" certain actions */
+ if (!get_item_allow(k))
+ {
+ done = TRUE;
+ break;
+ }
+
+ /* Accept that choice */
+ (*cp) = k;
+ item = TRUE;
+ done = TRUE;
+ break;
+ }
+
+ case '@':
+ {
+ int i;
+
+ if (extra && get_item_extra_hook(&i))
+ {
+ (*cp) = i;
+ item = TRUE;
+ done = TRUE;
+ }
+ break;
+ }
+
+ case '$':
+ {
+ automatizer_create = !automatizer_create;
+ break;
+ }
+
+ default:
+ {
+ int ver;
+
+ ver = isupper(which);
+ which = tolower(which);
+
+ /* Convert letter to inventory index */
+ if (command_wrk == (USE_INVEN))
+ {
+ k = label_to_inven(which);
+ if (k == -1)
+ {
+ bell();
+ break;
+ }
+ }
+
+ /* Convert letter to equipment index */
+ else if (command_wrk == (USE_EQUIP))
+ {
+ k = label_to_equip(which);
+ if (k == -1)
+ {
+ bell();
+ break;
+ }
+ }
+
+ /* Convert letter to floor index */
+ else if (command_wrk == (USE_FLOOR))
+ {
+ k = islower(which) ? A2I(which) : -1;
+ if (k < 0 || k >= floor_num)
+ {
+ bell();
+ break;
+ }
+
+ /* Special index */
+ k = 0 - floor_list[k];
+ }
+
+ /* Validate the item */
+ if ((k >= 0) && !get_item_okay(k))
+ {
+ bell();
+ break;
+ }
+
+ /* Verify the item */
+ if (ver && !verify("Try", k))
+ {
+ done = TRUE;
+ break;
+ }
+
+ /* Allow player to "refuse" certain actions */
+ if (!get_item_allow(k))
+ {
+ done = TRUE;
+ break;
+ }
+
+ /* Accept that choice */
+ (*cp) = k;
+ item = TRUE;
+ done = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Fix the screen */
+ screen_load();
+
+ /* Forget the item_tester_tval restriction */
+ item_tester_tval = 0;
+
+ /* Forget the item_tester_hook restriction */
+ item_tester_hook = NULL;
+
+ /* Track */
+ if (item && done)
+ {
+ if (*cp >= 0)
+ {
+ object_track(&p_ptr->inventory[*cp]);
+ }
+ else
+ {
+ object_track(&o_list[0 - *cp]);
+ }
+ }
+
+ /* Clean up */
+ if (show_choices)
+ {
+ /* Toggle again if needed */
+ if (toggle) toggle_inven_equip();
+
+ /* Update */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Window stuff */
+ window_stuff();
+ }
+
+
+ /* Clear the prompt line */
+ prt("", 0, 0);
+
+ /* Warning if needed */
+ if (oops && str) msg_print(str);
+
+
+ if (item) repeat_push(*cp);
+
+ /* Result */
+ return (item);
+}
+
+
+/*
+ * Let the user select an item, save its "index"
+ *
+ * Return TRUE only if an acceptable item was chosen by the user.
+ *
+ * The selected item must satisfy the "item_tester_hook()" function,
+ * if that hook is set, and the "item_tester_tval", if that value is set.
+ *
+ * All "item_tester" restrictions are cleared before this function returns.
+ *
+ * The user is allowed to choose acceptable items from the equipment,
+ * inventory, or floor, respectively, if the proper flag was given,
+ * and there are any acceptable items in that location.
+ *
+ * The equipment or inventory are displayed (even if no acceptable
+ * items are in that location) if the proper flag was given.
+ *
+ * If there are no acceptable items available anywhere, and "str" is
+ * not NULL, then it will be used as the text of a warning message
+ * before the function returns.
+ *
+ * Note that the user must press "-" to specify the item on the floor,
+ * and there is no way to "examine" the item on the floor, while the
+ * use of "capital" letters will "examine" an inventory/equipment item,
+ * and prompt for its use.
+ *
+ * If a legal item is selected from the inventory, we save it in "cp"
+ * directly (0 to 35), and return TRUE.
+ *
+ * If a legal item is selected from the floor, we save it in "cp" as
+ * a negative (-1 to -511), and return TRUE.
+ *
+ * If no item is available, we do nothing to "cp", and we display a
+ * warning message, using "str" if available, and return FALSE.
+ *
+ * If no item is selected, we do nothing to "cp", and return FALSE.
+ *
+ * Global "p_ptr->command_new" is used when viewing the inventory or equipment
+ * to allow the user to enter a command while viewing those screens, and
+ * also to induce "auto-enter" of stores, and other such stuff.
+ *
+ * Global "p_ptr->command_wrk" is used to choose between equip/inven listings.
+ * If it is TRUE then we are viewing inventory, else equipment.
+ *
+ * We always erase the prompt when we are done, leaving a blank line,
+ * or a warning message, if appropriate, if no items are available.
+ */
+bool_ get_item(int *cp, cptr pmt, cptr str, int mode)
+{
+ automatizer_create = FALSE;
+
+ return get_item_floor(cp, pmt, str, mode);
+}
+
+/*
+ * Hook to determine if an object is getable
+ */
+static bool_ item_tester_hook_getable(object_type *o_ptr)
+{
+ if (!inven_carry_okay(o_ptr)) return (FALSE);
+
+ if ((o_ptr->tval == TV_HYPNOS) && (!get_skill(SKILL_SYMBIOTIC))) return FALSE;
+
+ /* Assume yes */
+ return (TRUE);
+}
+
+/*
+ * Wear a single item from o_ptr
+ */
+int wear_ammo(object_type *o_ptr)
+{
+ int slot, num = 1;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ /* Check the slot */
+ slot = wield_slot(o_ptr);
+
+ if(slot == -1)
+ return -1;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Obtain local object */
+ object_copy(q_ptr, o_ptr);
+
+ num = o_ptr->number;
+
+ /* Modify quantity */
+ q_ptr->number = num;
+
+ /* Access the wield slot */
+ o_ptr = &p_ptr->inventory[slot];
+
+ q_ptr->number += o_ptr->number;
+
+ /* Wear the new stuff */
+ object_copy(o_ptr, q_ptr);
+
+ /* Increment the equip counter by hand */
+ equip_cnt++;
+
+ /* Cursed! */
+ if (cursed_p(o_ptr))
+ {
+ /* Warn the player */
+ msg_print("Oops! It feels deathly cold!");
+
+ /* Note the curse */
+ o_ptr->ident |= (IDENT_SENSE);
+ o_ptr->sense = SENSE_CURSED;
+ }
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Recalculate torch */
+ p_ptr->update |= (PU_TORCH);
+
+ /* Recalculate hitpoint */
+ p_ptr->update |= (PU_HP);
+
+ /* Recalculate mana */
+ p_ptr->update |= (PU_MANA);
+
+ /* Redraw monster hitpoint */
+ p_ptr->redraw |= (PR_MH);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ return slot;
+}
+
+
+/*
+ * Try to pickup arrows
+ */
+void pickup_ammo()
+{
+ s16b this_o_idx, next_o_idx = 0, slot;
+ char o_name[80];
+
+ /* Scan the pile of objects */
+ for (this_o_idx = cave[p_ptr->py][p_ptr->px].o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ if (object_similar(o_ptr, &p_ptr->inventory[INVEN_AMMO]))
+ {
+ msg_print("You add the ammo to your quiver.");
+ slot = wear_ammo(o_ptr);
+
+ if (slot != -1)
+ {
+ /* Get the item again */
+ o_ptr = &p_ptr->inventory[slot];
+
+ /* Describe the object */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("You have %s (%c).", o_name, index_to_label(slot));
+
+ /* Delete the object */
+ delete_object_idx(this_o_idx);
+ }
+ }
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+ }
+}
+
+
+/*
+ * Make the player carry everything in a grid
+ *
+ * If "pickup" is FALSE then only gold will be picked up
+ *
+ * This is called by py_pickup() when easy_floor is TRUE.
+ */
+bool_ can_carry_heavy(object_type *o_ptr)
+{
+ /* Query if object is heavy */
+ if (prompt_pickup_heavy)
+ {
+ int i, j;
+ int old_enc = 0;
+ int new_enc = 0;
+
+ /* Extract the "weight limit" (in tenth pounds) */
+ i = weight_limit();
+
+ /* Calculate current encumbarance */
+ j = calc_total_weight();
+
+ /* Apply encumbarance from weight */
+ if (j > i / 2) old_enc = ((j - (i / 2)) / (i / 10));
+
+ /* Increase the weight, recalculate encumbarance */
+ j += (o_ptr->number * o_ptr->weight);
+
+ /* Apply encumbarance from weight */
+ if (j > i / 2) new_enc = ((j - (i / 2)) / (i / 10));
+
+ /* Should we query? */
+ if (new_enc > old_enc)
+ {
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
+
+/* Do the actuall picking up */
+void object_pickup(int this_o_idx)
+{
+ int slot = 0;
+ char o_name[80] = "";
+ object_type *q_ptr, *o_ptr;
+
+ /* Access the item */
+ o_ptr = &o_list[this_o_idx];
+
+ if (p_ptr->auto_id)
+ {
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ }
+
+ /* Describe the object */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Note that the pack is too full */
+ if (!inven_carry_okay(o_ptr) && !object_similar(o_ptr, &p_ptr->inventory[INVEN_AMMO]))
+ {
+ msg_format("You have no room for %s.", o_name);
+ }
+
+ /* Pick up object */
+ else
+ {
+ /* Tell the scripts */
+ if (process_hooks(HOOK_GET, "(O,d)", o_ptr, this_o_idx))
+ return;
+
+ q_ptr = &p_ptr->inventory[INVEN_AMMO];
+
+ /* Carry the item */
+ if (object_similar(o_ptr, q_ptr))
+ {
+ msg_print("You add the ammo to your quiver.");
+ slot = wear_ammo(o_ptr);
+ }
+ else
+ {
+ slot = inven_carry(o_ptr, FALSE);
+ }
+
+ /* Sanity check */
+ if (slot != -1)
+ {
+ /* Get the item again */
+ o_ptr = &p_ptr->inventory[slot];
+
+ object_track(o_ptr);
+
+ /* Describe the object */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("You have %s (%c).", o_name, index_to_label(slot));
+
+ /* Delete the object */
+ delete_object_idx(this_o_idx);
+
+ /* Sense object. */
+ sense_inventory();
+ }
+ }
+}
+
+
+void py_pickup_floor(int pickup)
+{
+ s16b this_o_idx, next_o_idx = 0;
+
+ char o_name[80] = "";
+ object_type *o_ptr = 0;
+
+ int floor_num = 0, floor_o_idx = 0;
+
+ bool_ do_pickup = TRUE;
+
+ bool_ do_ask = TRUE;
+
+ /* Hack -- ignore monster traps */
+ if (cave[p_ptr->py][p_ptr->px].feat == FEAT_MON_TRAP) return;
+
+ /* Try to grab ammo */
+ pickup_ammo();
+
+ /* Mega Hack -- If we have auto-Id, do an ID sweep *before* squleching,
+ * so that we don't have to walk over things twice to get them
+ * squelched. --dsb */
+ if (p_ptr->auto_id)
+ {
+ this_o_idx = cave[p_ptr->py][p_ptr->px].o_idx;
+
+ for (; this_o_idx; this_o_idx = next_o_idx)
+ {
+ /* Aquire the object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire the next object index */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Identify Object */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ }
+ }
+
+ /* Squeltch the floor */
+ squeltch_grid();
+
+ /* Scan the pile of objects */
+ for (this_o_idx = cave[p_ptr->py][p_ptr->px].o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Hack -- disturb */
+ disturb(0, 0);
+
+ /* Pick up gold */
+ if (o_ptr->tval == TV_GOLD)
+ {
+ char goldname[80];
+ object_desc(goldname, o_ptr, TRUE, 3);
+ /* Message */
+ msg_format("You have found %ld gold pieces worth of %s.",
+ (long)o_ptr->pval, goldname);
+
+ /* Collect the gold */
+ p_ptr->au += o_ptr->pval;
+
+ /* Redraw gold */
+ p_ptr->redraw |= (PR_GOLD);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Delete the gold */
+ delete_object_idx(this_o_idx);
+
+ continue;
+ }
+
+ {
+ char testdesc[80];
+
+ object_desc(testdesc, o_ptr, TRUE, 3);
+ if (0 != strncmp(testdesc, "(nothing)", 80))
+ {
+ strncpy(o_name, testdesc, 80);
+ }
+ }
+
+ /* Count non-gold */
+ floor_num++;
+
+ /* Remember this index */
+ floor_o_idx = this_o_idx;
+ }
+
+ /* There were no non-gold items */
+ if (!floor_num) return;
+
+ /* Mention number of items */
+ if (!pickup)
+ {
+ /* One item */
+ if (floor_num == 1)
+ {
+ /* Acquire object */
+ o_ptr = &o_list[floor_o_idx];
+
+ /* Message */
+ msg_format("You see %s.", o_name);
+ }
+
+ /* Multiple items */
+ else
+ {
+ /* Message */
+ msg_format("You see a pile of %d items.", floor_num);
+ }
+
+ /* Done */
+ return;
+ }
+
+ /* One item */
+ if (floor_num == 1)
+ {
+ /* Hack -- query every item */
+ if (carry_query_flag || (!can_carry_heavy(&o_list[floor_o_idx])))
+ {
+ if (!inven_carry_okay(o_ptr) && !object_similar(o_ptr, &p_ptr->inventory[INVEN_AMMO]))
+ {
+ object_desc(o_name, o_ptr, TRUE, 3);
+ msg_format("You have no room for %s.", o_name);
+ do_pickup = FALSE;
+ }
+ else
+ {
+ char out_val[160];
+ sprintf(out_val, "Pick up %s? ", o_name);
+ do_pickup = get_check(out_val);
+ }
+ }
+
+ /* Don't ask */
+ do_ask = FALSE;
+
+ if ((o_list[floor_o_idx].tval == TV_HYPNOS) && (!get_skill(SKILL_SYMBIOTIC)))
+ do_pickup = FALSE;
+ else
+ this_o_idx = floor_o_idx;
+ }
+
+ /* Ask */
+ if (do_ask)
+ {
+ cptr q, s;
+
+ int item;
+
+ /* Get an item */
+
+ item_tester_hook = item_tester_hook_getable;
+
+ q = "Get which item? ";
+ s = "You have no room in your pack for any of the items here.";
+ if (get_item(&item, q, s, (USE_FLOOR)))
+ {
+ this_o_idx = 0 - item;
+
+ if (!can_carry_heavy(&o_list[this_o_idx]))
+ {
+ char out_val[160];
+
+ /* Describe the object */
+ object_desc(o_name, &o_list[this_o_idx], TRUE, 3);
+
+ sprintf(out_val, "Pick up %s? ", o_name);
+ do_pickup = get_check(out_val);
+ }
+ }
+ else
+ {
+ do_pickup = FALSE;
+ }
+ }
+
+ /* Pick up the item */
+ if (do_pickup)
+ {
+ object_pickup(this_o_idx);
+ }
+}
+
+/* Add a flags group */
+void gain_flag_group(object_type *o_ptr, bool_ silent)
+{
+ int grp = 0;
+ int tries = 1000;
+
+ while (tries--)
+ {
+ grp = rand_int(MAX_FLAG_GROUP);
+
+ /* If we already got this group continue */
+ if (o_ptr->pval3 & BIT(grp)) continue;
+
+ /* Not enough points ? */
+ if (flags_groups[grp].price > o_ptr->pval2) continue;
+
+ /* Ok, enough points and not already got it */
+ break;
+ }
+
+ /* Ack, nothing found */
+ if (tries <= 1) return;
+
+ o_ptr->pval2 -= flags_groups[grp].price;
+ o_ptr->pval3 |= BIT(grp);
+
+ if (!silent)
+ {
+ char o_name[80];
+
+ object_desc(o_name, o_ptr, FALSE, 0);
+ msg_format("%s gains access to the %s realm.", o_name, flags_groups[grp].name);
+ }
+}
+
+u32b get_flag(object_type *o_ptr, int grp, int k)
+{
+ u32b f = 0, flag_set = 0;
+ int tries = 1000;
+ u32b f1, f2, f3, f4, f5, esp, flag_test;
+
+ /* Extract some flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* get the corresponding flag set of the group */
+ switch (k)
+ {
+ case 0:
+ flag_set = flags_groups[grp].flags1;
+ flag_test = f1;
+ break;
+ case 1:
+ flag_set = flags_groups[grp].flags2;
+ flag_test = f2;
+ break;
+ case 2:
+ flag_set = flags_groups[grp].flags3;
+ flag_test = f3;
+ break;
+ case 3:
+ flag_set = flags_groups[grp].flags4;
+ flag_test = f4;
+ break;
+ case 4:
+ flag_set = flags_groups[grp].esp;
+ flag_test = esp;
+ break;
+ default:
+ flag_set = flags_groups[grp].flags1;
+ flag_test = f1;
+ break;
+ }
+
+ /* If no flags, no need to look */
+ if (!count_bits(flag_set)) return 0;
+
+ while (tries--)
+ {
+ /* get a random flag */
+ f = BIT(rand_int(32));
+
+ /* is it part of the group */
+ if (!(f & flag_set)) continue;
+
+ /* Already got it */
+ if (f & flag_test) continue;
+
+ /* Ok one */
+ break;
+ }
+
+ if (tries <= 1) return (0);
+ else return (f);
+}
+
+/* Add a flags from a flag group */
+void gain_flag_group_flag(object_type *o_ptr, bool_ silent)
+{
+ int grp = 0, k = 0;
+ u32b f = 0;
+ int tries = 20000;
+
+ if (!count_bits(o_ptr->pval3)) return;
+
+ while (tries--)
+ {
+ /* Get a flag set */
+ k = rand_int(5);
+
+ /* get a flag group */
+ grp = rand_int(MAX_FLAG_GROUP);
+
+ if (!(BIT(grp) & o_ptr->pval3)) continue;
+
+ /* Return a flag from the group/set */
+ f = get_flag(o_ptr, grp, k);
+
+ if (!f) continue;
+
+ break;
+ }
+
+ if (tries <= 1) return;
+
+ switch (k)
+ {
+ case 0:
+ o_ptr->art_flags1 |= f;
+ break;
+ case 1:
+ o_ptr->art_flags2 |= f;
+ break;
+ case 2:
+ o_ptr->art_flags3 |= f;
+ break;
+ case 3:
+ o_ptr->art_flags4 |= f;
+ break;
+ case 4:
+ o_ptr->art_esp |= f;
+ break;
+ }
+
+ if (!silent)
+ {
+ char o_name[80];
+
+ object_desc(o_name, o_ptr, FALSE, 0);
+ msg_format("%s gains a new power from the %s realm.", o_name, flags_groups[grp].name);
+ }
+}
+
+/*
+ * When an object gain a level, he can gain some attributes
+ */
+void object_gain_level(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Extract some flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* First it can gain some tohit and todam */
+ if ((o_ptr->tval == TV_AXE) || (o_ptr->tval == TV_SWORD) || (o_ptr->tval == TV_POLEARM) ||
+ (o_ptr->tval == TV_HAFTED) || (o_ptr->tval == TV_MSTAFF))
+ {
+ int k = rand_int(100);
+
+ /* gain +2,+1 */
+ if (k < 33)
+ {
+ o_ptr->to_h += randint(2);
+ o_ptr->to_d += 1;
+ }
+ /* +1 and 1 point */
+ else if (k < 66)
+ {
+ o_ptr->to_h += 1;
+ o_ptr->pval2++;
+
+ if (magik(NEW_GROUP_CHANCE)) gain_flag_group(o_ptr, FALSE);
+ }
+ else
+ {
+ if (!o_ptr->pval3) gain_flag_group(o_ptr, FALSE);
+
+ gain_flag_group_flag(o_ptr, FALSE);
+
+ if (!o_ptr->pval) o_ptr->pval = 1;
+ else
+ {
+ while (magik(20 - (o_ptr->pval * 2))) o_ptr->pval++;
+
+ if (o_ptr->pval > 5) o_ptr->pval = 5;
+ }
+ }
+ }
+}
+
+
+/*
+ * Item sets fcts
+ */
+bool_ wield_set(s16b a_idx, s16b set_idx, bool_ silent)
+{
+ set_type *s_ptr = &set_info[set_idx];
+ int i;
+
+ if ( -1 == a_info[a_idx].set) return (FALSE);
+ for (i = 0; i < s_ptr->num; i++)
+ if (a_idx == s_ptr->arts[i].a_idx) break;
+ if (!s_ptr->arts[i].present)
+ {
+ s_ptr->num_use++;
+ s_ptr->arts[i].present = TRUE;
+ if (s_ptr->num_use > s_ptr->num) msg_print("ERROR!! s_ptr->num_use > s_ptr->use");
+ else if ((s_ptr->num_use == s_ptr->num) && (!silent)) cmsg_format(TERM_GREEN, "%s item set completed.", s_ptr->name + set_name);
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+bool_ takeoff_set(s16b a_idx, s16b set_idx)
+{
+ set_type *s_ptr = &set_info[set_idx];
+ int i;
+
+ if ( -1 == a_info[a_idx].set) return (FALSE);
+ for (i = 0; i < s_ptr->num; i++)
+ if (a_idx == s_ptr->arts[i].a_idx) break;
+
+ if (s_ptr->arts[i].present)
+ {
+ s_ptr->arts[i].present = FALSE;
+ s_ptr->num_use--;
+
+ if (s_ptr->num_use == 255) msg_print("ERROR!! s_ptr->num_use < 0");
+ if (s_ptr->num_use == s_ptr->num - 1) cmsg_format(TERM_GREEN, "%s item set not complete anymore.", s_ptr->name + set_name);
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+bool_ apply_set(s16b a_idx, s16b set_idx)
+{
+ set_type *s_ptr = &set_info[set_idx];
+ int i, j;
+
+ if ( -1 == a_info[a_idx].set) return (FALSE);
+ for (i = 0; i < s_ptr->num; i++)
+ if (a_idx == s_ptr->arts[i].a_idx) break;
+ if (s_ptr->arts[i].present)
+ {
+ for (j = 0; j < s_ptr->num_use; j++)
+ {
+ apply_flags(s_ptr->arts[i].flags1[j],
+ s_ptr->arts[i].flags2[j],
+ s_ptr->arts[i].flags3[j],
+ s_ptr->arts[i].flags4[j],
+ s_ptr->arts[i].flags5[j],
+ s_ptr->arts[i].esp[j],
+ s_ptr->arts[i].pval[j],
+ 0, 0, 0, 0);
+ }
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+bool_ apply_flags_set(s16b a_idx, s16b set_idx,
+ u32b *f1, u32b *f2, u32b *f3, u32b *f4, u32b *f5, u32b *esp)
+{
+ set_type *s_ptr = &set_info[set_idx];
+ int i, j;
+
+ if ( -1 == a_info[a_idx].set) return (FALSE);
+
+ for (i = 0; i < s_ptr->num; i++)
+ {
+ if (a_idx == s_ptr->arts[i].a_idx) break;
+ }
+
+ if (s_ptr->arts[i].present)
+ {
+ for (j = 0; j < s_ptr->num_use; j++)
+ {
+ (*f1) |= s_ptr->arts[i].flags1[j];
+ (*f2) |= s_ptr->arts[i].flags2[j];
+ (*f3) |= s_ptr->arts[i].flags3[j];
+ (*f4) |= s_ptr->arts[i].flags4[j];
+ (*f5) |= s_ptr->arts[i].flags5[j];
+ (*esp) |= s_ptr->arts[i].esp[j];
+ }
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+
+
+
+
diff --git a/src/object2.c b/src/object2.c
new file mode 100644
index 00000000..98afb815
--- /dev/null
+++ b/src/object2.c
@@ -0,0 +1,6617 @@
+/* File: object2.c */
+
+/* Purpose: Object code, part 2 */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * Calculate the player's total inventory weight.
+ */
+s32b calc_total_weight(void)
+{
+ int i;
+ s32b total;
+ for (i = total = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ if (o_ptr->k_idx) total += o_ptr->weight * o_ptr->number;
+ }
+ return total;
+}
+
+/*
+ * Excise a dungeon object from any stacks
+ */
+void excise_object_idx(int o_idx)
+{
+ object_type *j_ptr;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ s16b prev_o_idx = 0;
+
+
+ /* Object */
+ j_ptr = &o_list[o_idx];
+
+ /* Monster */
+ if (j_ptr->held_m_idx)
+ {
+ monster_type *m_ptr;
+
+ /* Monster */
+ m_ptr = &m_list[j_ptr->held_m_idx];
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Done */
+ if (this_o_idx == o_idx)
+ {
+ /* No previous */
+ if (prev_o_idx == 0)
+ {
+ /* Remove from list */
+ m_ptr->hold_o_idx = next_o_idx;
+ }
+
+ /* Real previous */
+ else
+ {
+ object_type *k_ptr;
+
+ /* Previous object */
+ k_ptr = &o_list[prev_o_idx];
+
+ /* Remove from list */
+ k_ptr->next_o_idx = next_o_idx;
+ }
+
+ /* Forget next pointer */
+ o_ptr->next_o_idx = 0;
+
+ /* Done */
+ break;
+ }
+
+ /* Save prev_o_idx */
+ prev_o_idx = this_o_idx;
+ }
+ }
+
+ /* Dungeon */
+ else
+ {
+ cave_type *c_ptr;
+
+ int y = j_ptr->iy;
+ int x = j_ptr->ix;
+
+ /* Grid */
+ c_ptr = &cave[y][x];
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Done */
+ if (this_o_idx == o_idx)
+ {
+ /* No previous */
+ if (prev_o_idx == 0)
+ {
+ /* Remove from list */
+ c_ptr->o_idx = next_o_idx;
+ }
+
+ /* Real previous */
+ else
+ {
+ object_type *k_ptr;
+
+ /* Previous object */
+ k_ptr = &o_list[prev_o_idx];
+
+ /* Remove from list */
+ k_ptr->next_o_idx = next_o_idx;
+ }
+
+ /* Forget next pointer */
+ o_ptr->next_o_idx = 0;
+
+ /* Done */
+ break;
+ }
+
+ /* Save prev_o_idx */
+ prev_o_idx = this_o_idx;
+ }
+ }
+}
+
+
+/*
+ * Delete a dungeon object
+ *
+ * Handle "stacks" of objects correctly.
+ */
+void delete_object_idx(int o_idx)
+{
+ object_type *j_ptr;
+
+ /* Excise */
+ excise_object_idx(o_idx);
+
+ /* Object */
+ j_ptr = &o_list[o_idx];
+
+ /* Dungeon floor */
+ if (!(j_ptr->held_m_idx))
+ {
+ int y, x;
+
+ /* Location */
+ y = j_ptr->iy;
+ x = j_ptr->ix;
+
+ /* Visual update */
+ lite_spot(y, x);
+ }
+
+ /* Wipe the object */
+ object_wipe(j_ptr);
+
+ /* Count objects */
+ o_cnt--;
+}
+
+
+/*
+ * Deletes all objects at given location
+ */
+void delete_object(int y, int x)
+{
+ cave_type *c_ptr;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+
+ /* Refuse "illegal" locations */
+ if (!in_bounds(y, x)) return;
+
+
+ /* Grid */
+ c_ptr = &cave[y][x];
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Wipe the object */
+ object_wipe(o_ptr);
+
+ /* Count objects */
+ o_cnt--;
+ }
+
+ /* Objects are gone */
+ c_ptr->o_idx = 0;
+
+ /* Visual update */
+ lite_spot(y, x);
+}
+
+
+/*
+ * Move an object from index i1 to index i2 in the object list
+ */
+static void compact_objects_aux(int i1, int i2)
+{
+ int i;
+
+ cave_type *c_ptr;
+
+ object_type *o_ptr;
+
+
+ /* Do nothing */
+ if (i1 == i2) return;
+
+
+ /* Repair objects */
+ for (i = 1; i < o_max; i++)
+ {
+ /* Acquire object */
+ o_ptr = &o_list[i];
+
+ /* Skip "dead" objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Repair "next" pointers */
+ if (o_ptr->next_o_idx == i1)
+ {
+ /* Repair */
+ o_ptr->next_o_idx = i2;
+ }
+ }
+
+
+ /* Acquire object */
+ o_ptr = &o_list[i1];
+
+
+ /* Monster */
+ if (o_ptr->held_m_idx)
+ {
+ monster_type *m_ptr;
+
+ /* Acquire monster */
+ m_ptr = &m_list[o_ptr->held_m_idx];
+
+ /* Repair monster */
+ if (m_ptr->hold_o_idx == i1)
+ {
+ /* Repair */
+ m_ptr->hold_o_idx = i2;
+ }
+ }
+
+ /* Dungeon */
+ else
+ {
+ int y, x;
+
+ /* Acquire location */
+ y = o_ptr->iy;
+ x = o_ptr->ix;
+
+ /* Acquire grid */
+ c_ptr = &cave[y][x];
+
+ /* Repair grid */
+ if (c_ptr->o_idx == i1)
+ {
+ /* Repair */
+ c_ptr->o_idx = i2;
+ }
+ }
+
+
+ /* Structure copy */
+ o_list[i2] = o_list[i1];
+
+ /* Wipe the hole */
+ object_wipe(o_ptr);
+}
+
+
+/*
+ * Compact and Reorder the object list
+ *
+ * This function can be very dangerous, use with caution!
+ *
+ * When actually "compacting" objects, we base the saving throw on a
+ * combination of object level, distance from player, and current
+ * "desperation".
+ *
+ * After "compacting" (if needed), we "reorder" the objects into a more
+ * compact order, and we reset the allocation info, and the "live" array.
+ */
+void compact_objects(int size)
+{
+ int i, y, x, num;
+
+ int cur_lev, cur_dis, chance;
+
+ /* Compact */
+ if (size)
+ {
+ /* Message */
+ msg_print("Compacting objects...");
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+ }
+
+
+ /* Compact at least 'size' objects */
+ for (num = 0, cur_lev = 1; num < size; cur_lev++)
+ {
+ /* Get closer each iteration (start at distance 12). Around level 100 distance-protect nothing. */
+ cur_dis = 12 * (101 - cur_lev) / 100;
+
+ /* Examine the objects */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Skip dead objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* High level objects are "immune" as long as we're not desperate enough */
+ if (k_ptr->level > cur_lev) continue;
+
+ /* Monster owned objects */
+ if (o_ptr->held_m_idx)
+ {
+ monster_type *m_ptr;
+
+ /* Acquire monster */
+ m_ptr = &m_list[o_ptr->held_m_idx];
+
+ /* Monsters start with protecting objects well */
+ chance = 100;
+
+ /* Get the location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+ }
+ /* Dungeon floor objects */
+ else
+ {
+ /* Floor objects start with lower protection */
+ chance = 90;
+
+ /* Get the location */
+ y = o_ptr->iy;
+ x = o_ptr->ix;
+ }
+
+ /* Near enough objects are "immune", even if low level */
+ /* (like, importantly, food rations after hitting a trap of drop items) */
+ if ((cur_dis > 0) && (distance(p_ptr->py, p_ptr->px, y, x) < cur_dis)) continue;
+
+ /* object protection goes down as we get vicious */
+ /* around level 200 only artifacts have protection */
+ chance = chance - cur_lev / 2;
+
+ /* Artifacts */
+ if ( artifact_p(o_ptr) || o_ptr->art_name )
+ {
+ /* Artifacts are "immune if the level is lower */
+ /* than 300 + artifact level */
+ if ( cur_lev < 300 + k_ptr->level )
+ continue;
+
+ /* That's 400 + level for fixed artifacts */
+ if ( (k_ptr->flags3 & TR3_NORM_ART) && cur_lev < 400 + k_ptr->level )
+ continue;
+
+ /* Never protect if level is high enough; so we don't wipe a better artifact */
+ chance = -1;
+
+ /* rewind the level so we never wipe many */
+ /* artifacts of same level if one will do!!! */
+ cur_lev--;
+ }
+
+ /* Maybe some code to spare the God relic here. But I'd rather raise its level to 150 */
+
+ /* Apply the saving throw */
+ if (rand_int(100) < chance) continue;
+
+ /* Delete the object */
+ delete_object_idx(i);
+
+ /* Count it */
+ num++;
+ }
+ }
+
+
+ /* Excise dead objects (backwards!) */
+ for (i = o_max - 1; i >= 1; i--)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ /* Skip real objects */
+ if (o_ptr->k_idx) continue;
+
+ /* Move last object into open hole */
+ compact_objects_aux(o_max - 1, i);
+
+ /* Compress "o_max" */
+ o_max--;
+ }
+}
+
+
+
+
+/*
+ * Delete all the items when player leaves the level
+ *
+ * Note -- we do NOT visually reflect these (irrelevant) changes
+ *
+ * Hack -- we clear the "c_ptr->o_idx" field for every grid,
+ * and the "m_ptr->next_o_idx" field for every monster, since
+ * we know we are clearing every object. Technically, we only
+ * clear those fields for grids/monsters containing objects,
+ * and we clear it once for every such object.
+ */
+void wipe_o_list(void)
+{
+ int i;
+
+ /* Delete the existing objects */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ /* Skip dead objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Mega-Hack -- preserve artifacts */
+ if (!character_dungeon || p_ptr->preserve)
+ {
+ /* Hack -- Preserve unknown artifacts */
+ if (artifact_p(o_ptr) && !object_known_p(o_ptr))
+ {
+ /* Mega-Hack -- Preserve the artifact */
+ if (o_ptr->tval == TV_RANDART)
+ {
+ random_artifacts[o_ptr->sval].generated = FALSE;
+ }
+ else if (k_info[o_ptr->k_idx].flags3 & TR3_NORM_ART)
+ {
+ k_info[o_ptr->k_idx].artifact = FALSE;
+ }
+ else
+ {
+ a_info[o_ptr->name1].cur_num = 0;
+ }
+ }
+ }
+
+ /* Monster */
+ if (o_ptr->held_m_idx)
+ {
+ monster_type *m_ptr;
+
+ /* Monster */
+ m_ptr = &m_list[o_ptr->held_m_idx];
+
+ /* Hack -- see above */
+ m_ptr->hold_o_idx = 0;
+ }
+
+ /* Dungeon */
+ else
+ {
+ cave_type *c_ptr;
+
+ /* Access location */
+ int y = o_ptr->iy;
+ int x = o_ptr->ix;
+
+ /* Access grid */
+ c_ptr = &cave[y][x];
+
+ /* Hack -- see above */
+ c_ptr->o_idx = 0;
+ }
+
+ /* Wipe the object */
+ o_ptr = WIPE(o_ptr, object_type);
+ }
+
+ /* Reset "o_max" */
+ o_max = 1;
+
+ /* Reset "o_cnt" */
+ o_cnt = 0;
+}
+
+
+/*
+ * Acquires and returns the index of a "free" object.
+ *
+ * This routine should almost never fail, but in case it does,
+ * we must be sure to handle "failure" of this routine.
+ */
+s16b o_pop(void)
+{
+ int i;
+
+
+ /* Initial allocation */
+ if (o_max < max_o_idx)
+ {
+ /* Get next space */
+ i = o_max;
+
+ /* Expand object array */
+ o_max++;
+
+ /* Count objects */
+ o_cnt++;
+
+ /* Use this object */
+ return (i);
+ }
+
+
+ /* Recycle dead objects */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[i];
+
+ /* Skip live objects */
+ if (o_ptr->k_idx) continue;
+
+ /* Count objects */
+ o_cnt++;
+
+ /* Use this object */
+ return (i);
+ }
+
+
+ /* Warn the player (except during dungeon creation) */
+ if (character_dungeon) msg_print("Too many objects!");
+
+ /* Oops */
+ return (0);
+}
+
+
+
+/*
+ * Apply a "object restriction function" to the "object allocation table"
+ */
+errr get_obj_num_prep(void)
+{
+ int i;
+
+ /* Get the entry */
+ alloc_entry *table = alloc_kind_table;
+
+ /* Scan the allocation table */
+ for (i = 0; i < alloc_kind_size; i++)
+ {
+ /* Accept objects which pass the restriction, if any */
+ if (!get_obj_num_hook || (*get_obj_num_hook)(table[i].index))
+ {
+ /* Accept this object */
+ table[i].prob2 = table[i].prob1;
+ }
+
+ /* Do not use this object */
+ else
+ {
+ /* Decline this object */
+ table[i].prob2 = 0;
+ }
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Choose an object kind that seems "appropriate" to the given level
+ *
+ * This function uses the "prob2" field of the "object allocation table",
+ * and various local information, to calculate the "prob3" field of the
+ * same table, which is then used to choose an "appropriate" object, in
+ * a relatively efficient manner.
+ *
+ * It is (slightly) more likely to acquire an object of the given level
+ * than one of a lower level. This is done by choosing several objects
+ * appropriate to the given level and keeping the "hardest" one.
+ *
+ * Note that if no objects are "appropriate", then this function will
+ * fail, and return zero, but this should *almost* never happen.
+ */
+s16b get_obj_num(int level)
+{
+ int i, j, p;
+ int k_idx;
+ long value, total;
+ object_kind *k_ptr;
+ alloc_entry *table = alloc_kind_table;
+
+
+ /* Boost level */
+ if (level > 0)
+ {
+ /* Occasional "boost" */
+ if (rand_int(GREAT_OBJ) == 0)
+ {
+ /* What a bizarre calculation */
+ level = 1 + (level * MAX_DEPTH / randint(MAX_DEPTH));
+ }
+ }
+
+
+ /* Reset total */
+ total = 0L;
+
+ /* Process probabilities */
+ for (i = 0; i < alloc_kind_size; i++)
+ {
+ /* Objects are sorted by depth */
+ if (table[i].level > level) break;
+
+ /* Default */
+ table[i].prob3 = 0;
+
+ /* Access the index */
+ k_idx = table[i].index;
+
+ /* Access the actual kind */
+ k_ptr = &k_info[k_idx];
+
+ /* Hack -- prevent embedded chests */
+ if (opening_chest && (k_ptr->tval == TV_CHEST)) continue;
+
+ /* Accept */
+ table[i].prob3 = table[i].prob2;
+
+ /* Total */
+ total += table[i].prob3;
+ }
+
+ /* No legal objects */
+ if (total <= 0) return (0);
+
+
+ /* Pick an object */
+ value = rand_int(total);
+
+ /* Find the object */
+ for (i = 0; i < alloc_kind_size; i++)
+ {
+ /* Found the entry */
+ if (value < table[i].prob3) break;
+
+ /* Decrement */
+ value = value - table[i].prob3;
+ }
+
+
+ /* Power boost */
+ p = rand_int(100);
+
+ /* Try for a "better" object once (50%) or twice (10%) */
+ if (p < 60)
+ {
+ /* Save old */
+ j = i;
+
+ /* Pick a object */
+ value = rand_int(total);
+
+ /* Find the monster */
+ for (i = 0; i < alloc_kind_size; i++)
+ {
+ /* Found the entry */
+ if (value < table[i].prob3) break;
+
+ /* Decrement */
+ value = value - table[i].prob3;
+ }
+
+ /* Keep the "best" one */
+ if (table[i].level < table[j].level) i = j;
+ }
+
+ /* Try for a "better" object twice (10%) */
+ if (p < 10)
+ {
+ /* Save old */
+ j = i;
+
+ /* Pick a object */
+ value = rand_int(total);
+
+ /* Find the object */
+ for (i = 0; i < alloc_kind_size; i++)
+ {
+ /* Found the entry */
+ if (value < table[i].prob3) break;
+
+ /* Decrement */
+ value = value - table[i].prob3;
+ }
+
+ /* Keep the "best" one */
+ if (table[i].level < table[j].level) i = j;
+ }
+
+
+ /* Result */
+ return (table[i].index);
+}
+
+
+
+
+
+
+
+
+/*
+ * Known is true when the "attributes" of an object are "known".
+ * These include tohit, todam, toac, cost, and pval (charges).
+ *
+ * Note that "knowing" an object gives you everything that an "awareness"
+ * gives you, and much more. In fact, the player is always "aware" of any
+ * item of which he has full "knowledge".
+ *
+ * But having full knowledge of, say, one "wand of wonder", does not, by
+ * itself, give you knowledge, or even awareness, of other "wands of wonder".
+ * It happens that most "identify" routines (including "buying from a shop")
+ * will make the player "aware" of the object as well as fully "know" it.
+ *
+ * This routine also removes any inscriptions generated by "feelings".
+ */
+void object_known(object_type *o_ptr)
+{
+
+ /* No Sensing */
+ o_ptr->sense = SENSE_NONE;
+
+ /* Clear the "Felt" info */
+ o_ptr->ident &= ~(IDENT_SENSE);
+
+ /* Clear the "Empty" info */
+ o_ptr->ident &= ~(IDENT_EMPTY);
+
+ /* Now we know about the item */
+ o_ptr->ident |= (IDENT_KNOWN);
+}
+
+
+
+
+
+/*
+ * The player is now aware of the effects of the given object.
+ */
+void object_aware(object_type *o_ptr)
+{
+ /* Fully aware of the effects */
+ k_info[o_ptr->k_idx].aware = TRUE;
+}
+
+
+
+/*
+ * Something has been "sampled"
+ */
+void object_tried(object_type *o_ptr)
+{
+ /* Mark it as tried (even if "aware") */
+ k_info[o_ptr->k_idx].tried = TRUE;
+}
+
+
+
+/*
+ * Return the "value" of an "unknown" item
+ * Make a guess at the value of non-aware items
+ */
+static s32b object_value_base(object_type *o_ptr)
+{
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Aware item -- use template cost */
+ if ((object_aware_p(o_ptr)) && (o_ptr->tval != TV_EGG)) return (k_ptr->cost);
+
+ /* Analyze the type */
+ switch (o_ptr->tval)
+ {
+ /* Un-aware Food */
+ case TV_FOOD:
+ return (5L);
+
+ /* Un-aware Potions */
+ case TV_POTION2:
+ return (20L);
+
+ /* Un-aware Potions */
+ case TV_POTION:
+ return (20L);
+
+ /* Un-aware Scrolls */
+ case TV_SCROLL:
+ return (20L);
+
+ /* Un-aware Staffs */
+ case TV_STAFF:
+ return (70L);
+
+ /* Un-aware Wands */
+ case TV_WAND:
+ return (50L);
+
+ /* Un-aware Rods */
+ case TV_ROD:
+ return (90L);
+
+ /* Un-aware Rings */
+ case TV_RING:
+ return (45L);
+
+ /* Un-aware Amulets */
+ case TV_AMULET:
+ return (45L);
+
+ /* Eggs */
+ case TV_EGG:
+ {
+ monster_race *r_ptr = &r_info[o_ptr->pval2];
+
+ /* Pay the monster level */
+ return (r_ptr->level * 100) + 100;
+
+ /* Done */
+ break;
+ }
+ }
+
+ /* Paranoia -- Oops */
+ return (0L);
+}
+
+/* Return the value of the flags the object has... */
+s32b flag_cost(object_type * o_ptr, int plusses)
+{
+ s32b total = 0;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (f5 & TR5_TEMPORARY)
+ {
+ return 0;
+ }
+ if (f4 & TR4_CURSE_NO_DROP)
+ {
+ return 0;
+ }
+ if (f1 & TR1_STR) total += (1000 * plusses);
+ if (f1 & TR1_INT) total += (1000 * plusses);
+ if (f1 & TR1_WIS) total += (1000 * plusses);
+ if (f1 & TR1_DEX) total += (1000 * plusses);
+ if (f1 & TR1_CON) total += (1000 * plusses);
+ if (f1 & TR1_CHR) total += (250 * plusses);
+ if (f1 & TR1_CHAOTIC) total += 10000;
+ if (f1 & TR1_VAMPIRIC) total += 13000;
+ if (f1 & TR1_STEALTH) total += (250 * plusses);
+ if (f1 & TR1_SEARCH) total += (100 * plusses);
+ if (f1 & TR1_INFRA) total += (150 * plusses);
+ if (f1 & TR1_TUNNEL) total += (175 * plusses);
+ if ((f1 & TR1_SPEED) && (plusses > 0))
+ total += (10000 + (2500 * plusses));
+ if ((f1 & TR1_BLOWS) && (plusses > 0))
+ total += (10000 + (2500 * plusses));
+ if (f1 & TR1_MANA) total += (1000 * plusses);
+ if (f1 & TR1_SPELL) total += (2000 * plusses);
+ if (f1 & TR1_SLAY_ANIMAL) total += 3500;
+ if (f1 & TR1_SLAY_EVIL) total += 4500;
+ if (f1 & TR1_SLAY_UNDEAD) total += 3500;
+ if (f1 & TR1_SLAY_DEMON) total += 3500;
+ if (f1 & TR1_SLAY_ORC) total += 3000;
+ if (f1 & TR1_SLAY_TROLL) total += 3500;
+ if (f1 & TR1_SLAY_GIANT) total += 3500;
+ if (f1 & TR1_SLAY_DRAGON) total += 3500;
+ if (f5 & TR5_KILL_DEMON) total += 5500;
+ if (f5 & TR5_KILL_UNDEAD) total += 5500;
+ if (f1 & TR1_KILL_DRAGON) total += 5500;
+ if (f1 & TR1_VORPAL) total += 5000;
+ if (f1 & TR1_IMPACT) total += 5000;
+ if (f1 & TR1_BRAND_POIS) total += 7500;
+ if (f1 & TR1_BRAND_ACID) total += 7500;
+ if (f1 & TR1_BRAND_ELEC) total += 7500;
+ if (f1 & TR1_BRAND_FIRE) total += 5000;
+ if (f1 & TR1_BRAND_COLD) total += 5000;
+ if (f2 & TR2_SUST_STR) total += 850;
+ if (f2 & TR2_SUST_INT) total += 850;
+ if (f2 & TR2_SUST_WIS) total += 850;
+ if (f2 & TR2_SUST_DEX) total += 850;
+ if (f2 & TR2_SUST_CON) total += 850;
+ if (f2 & TR2_SUST_CHR) total += 250;
+ if (f2 & TR2_INVIS) total += 3000;
+ if (f2 & TR2_LIFE) total += (5000 * plusses);
+ if (f2 & TR2_IM_ACID) total += 10000;
+ if (f2 & TR2_IM_ELEC) total += 10000;
+ if (f2 & TR2_IM_FIRE) total += 10000;
+ if (f2 & TR2_IM_COLD) total += 10000;
+ if (f2 & TR2_SENS_FIRE) total -= 100;
+ if (f2 & TR2_REFLECT) total += 10000;
+ if (f2 & TR2_FREE_ACT) total += 4500;
+ if (f2 & TR2_HOLD_LIFE) total += 8500;
+ if (f2 & TR2_RES_ACID) total += 1250;
+ if (f2 & TR2_RES_ELEC) total += 1250;
+ if (f2 & TR2_RES_FIRE) total += 1250;
+ if (f2 & TR2_RES_COLD) total += 1250;
+ if (f2 & TR2_RES_POIS) total += 2500;
+ if (f2 & TR2_RES_FEAR) total += 2500;
+ if (f2 & TR2_RES_LITE) total += 1750;
+ if (f2 & TR2_RES_DARK) total += 1750;
+ if (f2 & TR2_RES_BLIND) total += 2000;
+ if (f2 & TR2_RES_CONF) total += 2000;
+ if (f2 & TR2_RES_SOUND) total += 2000;
+ if (f2 & TR2_RES_SHARDS) total += 2000;
+ if (f2 & TR2_RES_NETHER) total += 2000;
+ if (f2 & TR2_RES_NEXUS) total += 2000;
+ if (f2 & TR2_RES_CHAOS) total += 2000;
+ if (f2 & TR2_RES_DISEN) total += 10000;
+ if (f3 & TR3_SH_FIRE) total += 5000;
+ if (f3 & TR3_SH_ELEC) total += 5000;
+ if (f3 & TR3_DECAY) total += 0;
+ if (f3 & TR3_NO_TELE) total += 2500;
+ if (f3 & TR3_NO_MAGIC) total += 2500;
+ if (f3 & TR3_WRAITH) total += 250000;
+ if (f3 & TR3_TY_CURSE) total -= 15000;
+ if (f3 & TR3_EASY_KNOW) total += 0;
+ if (f3 & TR3_HIDE_TYPE) total += 0;
+ if (f3 & TR3_SHOW_MODS) total += 0;
+ if (f3 & TR3_INSTA_ART) total += 0;
+ if (f3 & TR3_LITE1) total += 750;
+ if (f4 & TR4_LITE2) total += 1250;
+ if (f4 & TR4_LITE3) total += 2750;
+ if (f3 & TR3_SEE_INVIS) total += 2000;
+ if (esp) total += (12500 * count_bits(esp));
+ if (f3 & TR3_SLOW_DIGEST) total += 750;
+ if (f3 & TR3_REGEN) total += 2500;
+ if (f3 & TR3_XTRA_MIGHT) total += 2250;
+ if (f3 & TR3_XTRA_SHOTS) total += 10000;
+ if (f3 & TR3_IGNORE_ACID) total += 100;
+ if (f3 & TR3_IGNORE_ELEC) total += 100;
+ if (f3 & TR3_IGNORE_FIRE) total += 100;
+ if (f3 & TR3_IGNORE_COLD) total += 100;
+ if (f3 & TR3_ACTIVATE) total += 100;
+ if (f3 & TR3_DRAIN_EXP) total -= 12500;
+ if (f3 & TR3_TELEPORT)
+ {
+ if (o_ptr->ident & IDENT_CURSED)
+ total -= 7500;
+ else
+ total += 250;
+ }
+ if (f3 & TR3_AGGRAVATE) total -= 10000;
+ if (f3 & TR3_BLESSED) total += 750;
+ if ((f3 & TR3_CURSED) && (o_ptr->ident & IDENT_CURSED)) total -= 5000;
+ if ((f3 & TR3_HEAVY_CURSE) && (o_ptr->ident & IDENT_CURSED)) total -= 12500;
+ if (f3 & TR3_PERMA_CURSE) total -= 15000;
+ if (f3 & TR3_FEATHER) total += 1250;
+ if (f4 & TR4_FLY) total += 10000;
+ if (f4 & TR4_NEVER_BLOW) total -= 15000;
+ if (f4 & TR4_PRECOGNITION) total += 250000;
+ if (f4 & TR4_BLACK_BREATH) total -= 12500;
+ if (f4 & TR4_DG_CURSE) total -= 25000;
+ if (f4 & TR4_CLONE) total -= 10000;
+ if (f4 & TR4_LEVELS) total += o_ptr->elevel * 2000;
+
+ /* Also, give some extra for activatable powers... */
+
+ if ((o_ptr->art_name) && (o_ptr->art_flags3 & (TR3_ACTIVATE)))
+ {
+ int type = o_ptr->xtra2;
+
+ if (type == ACT_SUNLIGHT) total += 250;
+ else if (type == ACT_BO_MISS_1) total += 250;
+ else if (type == ACT_BA_POIS_1) total += 300;
+ else if (type == ACT_BO_ELEC_1) total += 250;
+ else if (type == ACT_BO_ACID_1) total += 250;
+ else if (type == ACT_BO_COLD_1) total += 250;
+ else if (type == ACT_BO_FIRE_1) total += 250;
+ else if (type == ACT_BA_COLD_1) total += 750;
+ else if (type == ACT_BA_FIRE_1) total += 1000;
+ else if (type == ACT_DRAIN_1) total += 500;
+ else if (type == ACT_BA_COLD_2) total += 1250;
+ else if (type == ACT_BA_ELEC_2) total += 1500;
+ else if (type == ACT_DRAIN_2) total += 750;
+ else if (type == ACT_VAMPIRE_1) total += 1000;
+ else if (type == ACT_BO_MISS_2) total += 1000;
+ else if (type == ACT_BA_FIRE_2) total += 1750;
+ else if (type == ACT_BA_COLD_3) total += 2500;
+ else if (type == ACT_BA_ELEC_3) total += 2500;
+ else if (type == ACT_WHIRLWIND) total += 7500;
+ else if (type == ACT_VAMPIRE_2) total += 2500;
+ else if (type == ACT_CALL_CHAOS) total += 5000;
+ else if (type == ACT_ROCKET) total += 5000;
+ else if (type == ACT_DISP_EVIL) total += 4000;
+ else if (type == ACT_DISP_GOOD) total += 3500;
+ else if (type == ACT_BA_MISS_3) total += 5000;
+ else if (type == ACT_CONFUSE) total += 500;
+ else if (type == ACT_SLEEP) total += 750;
+ else if (type == ACT_QUAKE) total += 600;
+ else if (type == ACT_TERROR) total += 2500;
+ else if (type == ACT_TELE_AWAY) total += 2000;
+ else if (type == ACT_GENOCIDE) total += 10000;
+ else if (type == ACT_MASS_GENO) total += 10000;
+ else if (type == ACT_CHARM_ANIMAL) total += 7500;
+ else if (type == ACT_CHARM_UNDEAD) total += 10000;
+ else if (type == ACT_CHARM_OTHER) total += 10000;
+ else if (type == ACT_CHARM_ANIMALS) total += 12500;
+ else if (type == ACT_CHARM_OTHERS) total += 17500;
+ else if (type == ACT_SUMMON_ANIMAL) total += 10000;
+ else if (type == ACT_SUMMON_PHANTOM) total += 12000;
+ else if (type == ACT_SUMMON_ELEMENTAL) total += 15000;
+ else if (type == ACT_SUMMON_DEMON) total += 20000;
+ else if (type == ACT_SUMMON_UNDEAD) total += 20000;
+ else if (type == ACT_CURE_LW) total += 500;
+ else if (type == ACT_CURE_MW) total += 750;
+ else if (type == ACT_REST_LIFE) total += 7500;
+ else if (type == ACT_REST_ALL) total += 15000;
+ else if (type == ACT_CURE_700) total += 10000;
+ else if (type == ACT_CURE_1000) total += 15000;
+ else if (type == ACT_ESP) total += 1500;
+ else if (type == ACT_BERSERK) total += 800;
+ else if (type == ACT_PROT_EVIL) total += 5000;
+ else if (type == ACT_RESIST_ALL) total += 5000;
+ else if (type == ACT_SPEED) total += 15000;
+ else if (type == ACT_XTRA_SPEED) total += 25000;
+ else if (type == ACT_WRAITH) total += 25000;
+ else if (type == ACT_INVULN) total += 25000;
+ else if (type == ACT_LIGHT) total += 150;
+ else if (type == ACT_MAP_LIGHT) total += 500;
+ else if (type == ACT_DETECT_ALL) total += 1000;
+ else if (type == ACT_DETECT_XTRA) total += 12500;
+ else if (type == ACT_ID_FULL) total += 10000;
+ else if (type == ACT_ID_PLAIN) total += 1250;
+ else if (type == ACT_RUNE_EXPLO) total += 4000;
+ else if (type == ACT_RUNE_PROT) total += 10000;
+ else if (type == ACT_SATIATE) total += 2000;
+ else if (type == ACT_DEST_DOOR) total += 100;
+ else if (type == ACT_STONE_MUD) total += 1000;
+ else if (type == ACT_RECHARGE) total += 1000;
+ else if (type == ACT_ALCHEMY) total += 10000;
+ else if (type == ACT_DIM_DOOR) total += 10000;
+ else if (type == ACT_TELEPORT) total += 2000;
+ else if (type == ACT_RECALL) total += 7500;
+ }
+
+ return total;
+}
+
+
+
+/*
+ * Return the "real" price of a "known" item, not including discounts
+ *
+ * Wand and staffs get cost for each charge
+ *
+ * Armor is worth an extra 100 gold per bonus point to armor class.
+ *
+ * Weapons are worth an extra 100 gold per bonus point (AC,TH,TD).
+ *
+ * Missiles are only worth 5 gold per bonus point, since they
+ * usually appear in groups of 20, and we want the player to get
+ * the same amount of cash for any "equivalent" item. Note that
+ * missiles never have any of the "pval" flags, and in fact, they
+ * only have a few of the available flags, primarily of the "slay"
+ * and "brand" and "ignore" variety.
+ *
+ * Armor with a negative armor bonus is worthless.
+ * Weapons with negative hit+damage bonuses are worthless.
+ *
+ * Every wearable item with a "pval" bonus is worth extra (see below).
+ */
+s32b object_value_real(object_type *o_ptr)
+{
+ s32b value;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ if (o_ptr->tval == TV_RANDART)
+ {
+ return random_artifacts[o_ptr->sval].cost;
+ }
+
+ /* Hack -- "worthless" items */
+ if (!k_ptr->cost) return (0L);
+
+ /* Base cost */
+ value = k_ptr->cost;
+
+ /* Extract some flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (f5 & TR5_TEMPORARY) return (0L);
+
+ if (o_ptr->art_flags1 || o_ptr->art_flags2 || o_ptr->art_flags3)
+ {
+ value += flag_cost (o_ptr, o_ptr->pval);
+ }
+ /* Artifact */
+ else if (o_ptr->name1)
+ {
+ artifact_type *a_ptr = &a_info[o_ptr->name1];
+
+ /* Hack -- "worthless" artifacts */
+ if (!a_ptr->cost) return (0L);
+
+ /* Hack -- Use the artifact cost instead */
+ value = a_ptr->cost;
+ }
+
+ /* Ego-Item */
+ else if (o_ptr->name2)
+ {
+ ego_item_type *e_ptr = &e_info[o_ptr->name2];
+
+ /* Hack -- "worthless" ego-items */
+ if (!e_ptr->cost) return (0L);
+
+ /* Hack -- Reward the ego-item with a bonus */
+ value += e_ptr->cost;
+
+ if (o_ptr->name2b)
+ {
+ ego_item_type *e_ptr = &e_info[o_ptr->name2b];
+
+ /* Hack -- "worthless" ego-items */
+ if (!e_ptr->cost) return (0L);
+
+ /* Hack -- Reward the ego-item with a bonus */
+ value += e_ptr->cost;
+ }
+ }
+
+ /* Pay the spell */
+ if (f5 & TR5_SPELL_CONTAIN)
+ {
+ if (o_ptr->pval2 != -1)
+ value += 5000 + 500 * school_spells[o_ptr->pval2].skill_level;
+ else
+ value += 5000;
+ }
+
+ /* Analyze pval bonus */
+ switch (o_ptr->tval)
+ {
+ case TV_BOW:
+ case TV_BOOMERANG:
+ case TV_DIGGING:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_HELM:
+ case TV_CROWN:
+ case TV_SHIELD:
+ case TV_CLOAK:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ case TV_LITE:
+ case TV_AMULET:
+ case TV_RING:
+ case TV_MSTAFF:
+ case TV_TRAPKIT:
+ case TV_INSTRUMENT:
+ {
+ /* No pval */
+ if (!o_ptr->pval) break;
+
+ /* Give credit for stat bonuses */
+ if (f1 & (TR1_STR)) value += (o_ptr->pval * 200L);
+ if (f1 & (TR1_INT)) value += (o_ptr->pval * 200L);
+ if (f1 & (TR1_WIS)) value += (o_ptr->pval * 200L);
+ if (f1 & (TR1_DEX)) value += (o_ptr->pval * 200L);
+ if (f1 & (TR1_CON)) value += (o_ptr->pval * 200L);
+ if (f1 & (TR1_CHR)) value += (o_ptr->pval * 200L);
+
+ if (f5 & (TR5_CRIT)) value += (o_ptr->pval * 500L);
+
+ /* Give credit for stealth and searching */
+ if (f1 & (TR1_STEALTH)) value += (o_ptr->pval * 100L);
+ if (f1 & (TR1_SEARCH)) value += (o_ptr->pval * 100L);
+
+ /* Give credit for infra-vision and tunneling */
+ if (f1 & (TR1_INFRA)) value += (o_ptr->pval * 50L);
+ if (f1 & (TR1_TUNNEL)) value += (o_ptr->pval * 50L);
+
+ /* Give credit for extra attacks */
+ if (f1 & (TR1_BLOWS)) value += (o_ptr->pval * 2000L);
+
+ /* Give credit for speed bonus */
+ if (f1 & (TR1_SPEED)) value += (o_ptr->pval * 30000L);
+
+ break;
+ }
+ }
+
+
+ /* Analyze the item */
+ switch (o_ptr->tval)
+ {
+ /* Eggs */
+ case TV_EGG:
+ {
+ monster_race *r_ptr = &r_info[o_ptr->pval2];
+
+ /* Pay the monster level */
+ value += r_ptr->level * 100;
+
+ /* Done */
+ break;
+ }
+
+ /* Wands/Staffs */
+ case TV_WAND:
+ {
+ /* Par for the spell */
+ value *= school_spells[o_ptr->pval2].skill_level;
+ /* Take the average of the base and max spell levels */
+ value *= (((o_ptr->pval3 >> 16) & 0xFFFF) + (o_ptr->pval3 & 0xFFFF)) / 2;
+ /* Hack */
+ value /= 6;
+
+ /* Pay extra for charges */
+ value += ((value / 20) * o_ptr->pval) / o_ptr->number;
+
+ /* Done */
+ break;
+ }
+ case TV_STAFF:
+ {
+ /* Par for the spell */
+ value *= school_spells[o_ptr->pval2].skill_level;
+ /* Take the average of the base and max spell levels */
+ value *= (((o_ptr->pval3 >> 16) & 0xFFFF) + (o_ptr->pval3 & 0xFFFF)) / 2;
+ /* Hack */
+ value /= 6;
+
+ /* Pay extra for charges */
+ value += ((value / 20) * o_ptr->pval);
+
+ /* Done */
+ break;
+ }
+ case TV_BOOK:
+ {
+ if (o_ptr->sval == 255)
+ {
+ /* Pay extra for the spell */
+ value = value * school_spells[o_ptr->pval].skill_level;
+ }
+ /* Done */
+ break;
+ }
+
+ /* Rods */
+ case TV_ROD_MAIN:
+ {
+ s16b tip_idx;
+
+ /* It's not combined */
+ if (o_ptr->pval == 0) break;
+
+ /* Look up the tip attached */
+ tip_idx = lookup_kind(TV_ROD, o_ptr->pval);
+
+ /* Paranoia */
+ if (tip_idx > 0)
+ {
+ /* Add its cost */
+ value += k_info[tip_idx].cost;
+ }
+
+ /* Done */
+ break;
+ }
+
+ /* Rings/Amulets */
+ case TV_RING:
+ case TV_AMULET:
+ {
+ /* Hack -- negative bonuses are bad */
+ if (o_ptr->to_a < 0 && !value) return (0L);
+ if (o_ptr->to_h < 0 && !value) return (0L);
+ if (o_ptr->to_d < 0 && !value) return (0L);
+
+ /* Give credit for bonuses */
+ value += ((o_ptr->to_h + o_ptr->to_d + o_ptr->to_a) * 100L);
+
+ /* Done */
+ break;
+ }
+
+ /* Armor */
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_CLOAK:
+ case TV_CROWN:
+ case TV_HELM:
+ case TV_SHIELD:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ {
+ /* Hack -- negative armor bonus */
+ if (o_ptr->to_a < 0 && !value) return (0L);
+
+ /* Give credit for bonuses */
+ value += ((o_ptr->to_h + o_ptr->to_d + o_ptr->to_a) * 100L);
+
+ /* Done */
+ break;
+ }
+
+ /* Bows/Weapons */
+ case TV_BOW:
+ case TV_BOOMERANG:
+ case TV_DIGGING:
+ case TV_HAFTED:
+ case TV_SWORD:
+ case TV_DAEMON_BOOK:
+ case TV_AXE:
+ case TV_POLEARM:
+ case TV_TRAPKIT:
+ {
+ /* Hack -- negative hit/damage bonuses */
+ if (o_ptr->to_h + o_ptr->to_d < 0 && !value) return (0L);
+
+ /* Factor in the bonuses */
+ value += ((o_ptr->to_h + o_ptr->to_d + o_ptr->to_a) * 100L);
+
+ /* Hack -- Factor in extra damage dice */
+ if ((o_ptr->dd > k_ptr->dd) && (o_ptr->ds == k_ptr->ds))
+ {
+ value += (o_ptr->dd - k_ptr->dd) * o_ptr->ds * 100L;
+ }
+
+ /* Done */
+ break;
+ }
+
+ /* Ammo */
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+ {
+ /* Hack -- negative hit/damage bonuses */
+ if (o_ptr->to_h + o_ptr->to_d < 0 && !value) return (0L);
+
+ /* Factor in the bonuses */
+ value += ((o_ptr->to_h + o_ptr->to_d) * 5L);
+
+ /* Hack -- Factor in extra damage dice */
+ if ((o_ptr->dd > k_ptr->dd) && (o_ptr->ds == k_ptr->ds))
+ {
+ value += (o_ptr->dd - k_ptr->dd) * o_ptr->ds * 5L;
+ }
+
+ /* Special attack (exploding arrow) */
+ if (o_ptr->pval2 != 0) value *= 14;
+
+ /* Done */
+ break;
+ }
+ }
+
+ /* Return the value */
+ return (value);
+}
+
+
+/*
+ * Return the price of an item including plusses (and charges)
+ *
+ * This function returns the "value" of the given item (qty one)
+ *
+ * Never notice "unknown" bonuses or properties, including "curses",
+ * since that would give the player information he did not have.
+ *
+ * Note that discounted items stay discounted forever, even if
+ * the discount is "forgotten" by the player via memory loss.
+ */
+s32b object_value(object_type *o_ptr)
+{
+ s32b value;
+
+
+ /* Unknown items -- acquire a base value */
+ if (object_known_p(o_ptr))
+ {
+ /* Cursed items -- worthless */
+ if (cursed_p(o_ptr)) return (0L);
+
+ /* Real value (see above) */
+ value = object_value_real(o_ptr);
+ }
+
+ /* Known items -- acquire the actual value */
+ else
+ {
+ /* Hack -- Felt cursed items */
+ if ((o_ptr->ident & (IDENT_SENSE)) && cursed_p(o_ptr)) return (0L);
+
+ /* Base value (see above) */
+ value = object_value_base(o_ptr);
+ }
+
+
+ /* Apply discount (if any) */
+ if (o_ptr->discount) value -= (value * o_ptr->discount / 100L);
+
+
+ /* Return the final value */
+ return (value);
+}
+
+
+
+
+
+/*
+ * Determine if an item can "absorb" a second item
+ *
+ * See "object_absorb()" for the actual "absorption" code.
+ *
+ * If permitted, we allow wands/staffs (if they are known to have equal
+ * charges) and rods (if fully charged) to combine. They will unstack
+ * (if necessary) when they are used.
+ *
+ * If permitted, we allow weapons/armor to stack, if fully "known".
+ *
+ * Missiles will combine if both stacks have the same "known" status.
+ * This is done to make unidentified stacks of missiles useful.
+ *
+ * Food, potions, scrolls, and "easy know" items always stack.
+ *
+ * Chests, and activatable items, never stack (for various reasons).
+ */
+bool_ object_similar(object_type *o_ptr, object_type *j_ptr)
+{
+ int total = o_ptr->number + j_ptr->number;
+ u32b f1, f2, f3, f4, f5, esp, f11, f12, f13, f14, esp1, f15;
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ object_flags(j_ptr, &f11, &f12, &f13, &f14, &f15, &esp1);
+
+
+ /* Require identical object types */
+ if (o_ptr->k_idx != j_ptr->k_idx) return (0);
+
+ if ((f5 & TR5_SPELL_CONTAIN) || (f15 & TR5_SPELL_CONTAIN))
+ return FALSE;
+
+ /* Analyze the items */
+ switch (o_ptr->tval)
+ {
+ /* School Book */
+ case TV_BOOK:
+ {
+ if (!object_known_p(o_ptr) || !object_known_p(j_ptr)) return FALSE;
+
+ /* Beware artifatcs should not combibne with "lesser" thing */
+ if (artifact_p(o_ptr) != artifact_p(j_ptr)) return (FALSE);
+
+ /* Do not combine different ego or normal ones */
+ if (ego_item_p(o_ptr) != ego_item_p(j_ptr)) return (FALSE);
+
+ /* Random books should stack if they are identical */
+ if ((o_ptr->sval == 255) && (j_ptr->sval == 255))
+ {
+ if (o_ptr->pval != j_ptr->pval)
+ return (FALSE);
+ }
+
+ return (TRUE);
+ }
+
+ /* Chests */
+ case TV_CHEST:
+ {
+ /* Never okay */
+ return (0);
+ }
+
+ case TV_RANDART:
+ {
+ return FALSE;
+ }
+
+ case TV_RUNE1:
+ {
+ return TRUE;
+ }
+
+ case TV_RUNE2:
+ {
+ if ((o_ptr->sval == RUNE_STONE) || (j_ptr->sval == RUNE_STONE)) return FALSE;
+ else return TRUE;
+ }
+
+ case TV_INSTRUMENT:
+ {
+ return FALSE;
+ }
+
+ case TV_HYPNOS:
+ case TV_EGG:
+ {
+ return FALSE;
+ }
+
+ /* Totems */
+ case TV_TOTEM:
+ {
+ if ((o_ptr->pval == j_ptr->pval) && (o_ptr->pval2 == j_ptr->pval2)) return TRUE;
+ return FALSE;
+ }
+
+ /* Corpses*/
+ case TV_CORPSE:
+ {
+ return FALSE;
+ }
+
+ /* Food and Potions and Scrolls */
+ case TV_POTION:
+ case TV_POTION2:
+ {
+ if (o_ptr->pval2 != j_ptr->pval2) return FALSE;
+
+ /* Assume okay */
+ break;
+ }
+
+ case TV_SCROLL:
+ {
+ if (o_ptr->pval != j_ptr->pval) return FALSE;
+ if (o_ptr->pval2 != j_ptr->pval2) return FALSE;
+ break;
+ }
+
+ /* Staffs */
+ case TV_STAFF:
+ {
+ /* Require either knowledge or known empty for both staffs. */
+ if ((!(o_ptr->ident & (IDENT_EMPTY)) &&
+ !object_known_p(o_ptr)) ||
+ (!(j_ptr->ident & (IDENT_EMPTY)) &&
+ !object_known_p(j_ptr))) return (0);
+
+ /* Require identical charges, since staffs are bulky. */
+ if (o_ptr->pval != j_ptr->pval) return (0);
+
+ /* Do not combine recharged ones with non recharged ones. */
+ if ((f4 & TR4_RECHARGED) != (f14 & TR4_RECHARGED)) return (0);
+
+ /* Do not combine different spells */
+ if (o_ptr->pval2 != j_ptr->pval2) return (0);
+
+ /* Do not combine different base levels */
+ if (o_ptr->pval3 != j_ptr->pval3) return (0);
+
+ /* Beware artifatcs should not combibne with "lesser" thing */
+ if (o_ptr->name1 != j_ptr->name1) return (0);
+
+ /* Do not combine different ego or normal ones */
+ if (o_ptr->name2 != j_ptr->name2) return (0);
+
+ /* Do not combine different ego or normal ones */
+ if (o_ptr->name2b != j_ptr->name2b) return (0);
+
+ /* Assume okay */
+ break;
+ }
+
+ /* Wands */
+ case TV_WAND:
+ {
+
+ /* Require either knowledge or known empty for both wands. */
+ if ((!(o_ptr->ident & (IDENT_EMPTY)) &&
+ !object_known_p(o_ptr)) ||
+ (!(j_ptr->ident & (IDENT_EMPTY)) &&
+ !object_known_p(j_ptr))) return (0);
+
+ /* Beware artifatcs should not combibne with "lesser" thing */
+ if (o_ptr->name1 != j_ptr->name1) return (0);
+
+ /* Do not combine recharged ones with non recharged ones. */
+ if ((f4 & TR4_RECHARGED) != (f14 & TR4_RECHARGED)) return (0);
+
+ /* Do not combine different spells */
+ if (o_ptr->pval2 != j_ptr->pval2) return (0);
+
+ /* Do not combine different base levels */
+ if (o_ptr->pval3 != j_ptr->pval3) return (0);
+
+ /* Do not combine different ego or normal ones */
+ if (o_ptr->name2 != j_ptr->name2) return (0);
+
+ /* Do not combine different ego or normal ones */
+ if (o_ptr->name2b != j_ptr->name2b) return (0);
+
+ /* Assume okay */
+ break;
+ }
+
+ /* Rod Tips */
+ case TV_ROD:
+ {
+ /* Probably okay */
+ break;
+ }
+
+ /* Rods */
+ case TV_ROD_MAIN:
+ {
+ return FALSE;
+ break;
+ }
+
+ /* Weapons and Armor */
+ case TV_BOW:
+ case TV_BOOMERANG:
+ case TV_DIGGING:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_MSTAFF:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_HELM:
+ case TV_CROWN:
+ case TV_SHIELD:
+ case TV_CLOAK:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ case TV_TRAPKIT:
+ case TV_DAEMON_BOOK:
+ {
+ /* Require permission */
+ if (!stack_allow_items) return (0);
+
+ /* Fall through */
+ }
+
+ /* Rings, Amulets, Lites */
+ case TV_RING:
+ case TV_AMULET:
+ case TV_LITE:
+ {
+ /* Require full knowledge of both items */
+ if (!object_known_p(o_ptr) || !object_known_p(j_ptr)) return (0);
+
+ /* Require identical "turns of light" */
+ if (o_ptr->timeout != j_ptr->timeout) return (FALSE);
+
+ /* Fall through */
+ }
+
+ /* Missiles */
+ case TV_BOLT:
+ case TV_ARROW:
+ case TV_SHOT:
+ {
+ /* Require identical knowledge of both items */
+ if (object_known_p(o_ptr) != object_known_p(j_ptr)) return (0);
+
+ /* Require identical "bonuses" */
+ if (o_ptr->to_h != j_ptr->to_h) return (FALSE);
+ if (o_ptr->to_d != j_ptr->to_d) return (FALSE);
+ if (o_ptr->to_a != j_ptr->to_a) return (FALSE);
+
+ /* Require identical "pval" code */
+ if (o_ptr->pval != j_ptr->pval) return (FALSE);
+
+ /* Require identical exploding status code */
+ if (o_ptr->pval2 != j_ptr->pval2) return (FALSE);
+
+ /* Require identical "artifact" names */
+ if (o_ptr->name1 != j_ptr->name1) return (FALSE);
+
+ /* Require identical "ego-item" names */
+ if (o_ptr->name2 != j_ptr->name2) return (FALSE);
+
+ /* Do not combine different ego or normal ones */
+ if (o_ptr->name2b != j_ptr->name2b) return (FALSE);
+
+ /* Hack -- Never stack "powerful" items */
+ /*
+ Why?!
+ -- wilh
+ */
+ /* #if 0 */
+ if (o_ptr->xtra1 || j_ptr->xtra1) return (FALSE);
+ /* #endif */
+
+ /* Hack -- Never stack recharging items */
+ if ((o_ptr->timeout || j_ptr->timeout) &&
+ (o_ptr->tval != TV_LITE)) return (FALSE);
+
+ /* Require identical "values" */
+ if (o_ptr->ac != j_ptr->ac) return (FALSE);
+ if (o_ptr->dd != j_ptr->dd) return (FALSE);
+ if (o_ptr->ds != j_ptr->ds) return (FALSE);
+
+ /* Probably okay */
+ break;
+ }
+
+ /* UHH ugly hack for the mushroom quest, sorry */
+ case TV_FOOD:
+ {
+ if (o_ptr->pval2 != j_ptr->pval2) return (FALSE);
+ break;
+ }
+
+ /* UHH ugly hack for the fireproof quest, sorry */
+ case TV_BATERIE:
+ {
+ if (o_ptr->pval2 != j_ptr->pval2) return (FALSE);
+ break;
+ }
+
+ /* Various */
+ default:
+ {
+ /* Require knowledge */
+ if (!object_known_p(o_ptr) || !object_known_p(j_ptr)) return (0);
+
+ /* Probably okay */
+ break;
+ }
+ }
+
+
+ /* Hack -- Identical art_flags! */
+ if ((o_ptr->art_flags1 != j_ptr->art_flags1) ||
+ (o_ptr->art_flags2 != j_ptr->art_flags2) ||
+ (o_ptr->art_flags3 != j_ptr->art_flags3))
+ return (0);
+
+ /* Hack -- Require identical "cursed" status */
+ if ((o_ptr->ident & (IDENT_CURSED)) != (j_ptr->ident & (IDENT_CURSED))) return (0);
+
+ /* Hack -- require semi-matching "inscriptions" */
+ if (o_ptr->note && j_ptr->note && (o_ptr->note != j_ptr->note)) return (0);
+
+ /* Hack -- normally require matching "inscriptions" */
+ if (!stack_force_notes && (o_ptr->note != j_ptr->note)) return (0);
+
+ /* Hack -- normally require matching "discounts" */
+ if (!stack_force_costs && (o_ptr->discount != j_ptr->discount)) return (0);
+
+
+ /* Maximal "stacking" limit */
+ if (total >= MAX_STACK_SIZE) return (0);
+
+
+ /* They match, so they must be similar */
+ return (TRUE);
+}
+
+
+/*
+ * Allow one item to "absorb" another, assuming they are similar
+ */
+void object_absorb(object_type *o_ptr, object_type *j_ptr)
+{
+ int total = o_ptr->number + j_ptr->number;
+
+ /* Add together the item counts */
+ o_ptr->number = ((total < MAX_STACK_SIZE) ? total : (MAX_STACK_SIZE - 1));
+
+ /* Hack -- blend "known" status */
+ if (object_known_p(j_ptr)) object_known(o_ptr);
+
+ /* Hack -- clear "storebought" if only one has it */
+ if (((o_ptr->ident & IDENT_STOREB) || (j_ptr->ident & IDENT_STOREB)) &&
+ (!((o_ptr->ident & IDENT_STOREB) && (j_ptr->ident & IDENT_STOREB))))
+ {
+ if (j_ptr->ident & IDENT_STOREB) j_ptr->ident &= 0xEF;
+ if (o_ptr->ident & IDENT_STOREB) o_ptr->ident &= 0xEF;
+ }
+
+ /* Hack -- blend "mental" status */
+ if (j_ptr->ident & (IDENT_MENTAL)) o_ptr->ident |= (IDENT_MENTAL);
+
+ /* Hack -- blend "inscriptions" */
+ if (j_ptr->note) o_ptr->note = j_ptr->note;
+
+ /* Hack -- could average discounts XXX XXX XXX */
+ /* Hack -- save largest discount XXX XXX XXX */
+ if (o_ptr->discount < j_ptr->discount) o_ptr->discount = j_ptr->discount;
+
+ /* Hack -- if wands are stacking, combine the charges. -LM- */
+ if (o_ptr->tval == TV_WAND)
+ {
+ o_ptr->pval += j_ptr->pval;
+ }
+}
+
+
+
+/*
+ * Find the index of the object_kind with the given tval and sval
+ */
+s16b lookup_kind(int tval, int sval)
+{
+ int k;
+
+ /* Look for it */
+ for (k = 1; k < max_k_idx; k++)
+ {
+ object_kind *k_ptr = &k_info[k];
+
+ /* Found a match */
+ if ((k_ptr->tval == tval) && (k_ptr->sval == sval)) return (k);
+ }
+
+ /* Oops */
+ if (wizard) msg_format("No object (%d,%d)", tval, sval);
+
+ /* Oops */
+ return (0);
+}
+
+
+/*
+ * Wipe an object clean.
+ */
+void object_wipe(object_type *o_ptr)
+{
+ /* Wipe the structure */
+ o_ptr = WIPE(o_ptr, object_type);
+}
+
+
+/*
+ * Prepare an object based on an existing object
+ */
+void object_copy(object_type *o_ptr, object_type *j_ptr)
+{
+ /* Copy the structure */
+ COPY(o_ptr, j_ptr, object_type);
+}
+
+
+/*
+ * Prepare an object based on an object kind.
+ */
+void object_prep(object_type *o_ptr, int k_idx)
+{
+ object_kind *k_ptr = &k_info[k_idx];
+
+ /* Clear the record */
+ o_ptr = WIPE(o_ptr, object_type);
+
+ /* Save the kind index */
+ o_ptr->k_idx = k_idx;
+
+ /* Efficiency -- tval/sval */
+ o_ptr->tval = k_ptr->tval;
+ o_ptr->sval = k_ptr->sval;
+
+ /* Default "pval" */
+ o_ptr->pval = k_ptr->pval;
+ o_ptr->pval2 = k_ptr->pval2;
+
+ /* Default number */
+ o_ptr->number = 1;
+
+ /* Default weight */
+ o_ptr->weight = k_ptr->weight;
+
+ /* Default magic */
+ o_ptr->to_h = k_ptr->to_h;
+ o_ptr->to_d = k_ptr->to_d;
+ o_ptr->to_a = k_ptr->to_a;
+
+ /* Default power */
+ o_ptr->ac = k_ptr->ac;
+ o_ptr->dd = k_ptr->dd;
+ o_ptr->ds = k_ptr->ds;
+
+ /* Hack -- cursed items are always "cursed" */
+ if (k_ptr->flags3 & (TR3_CURSED)) o_ptr->ident |= (IDENT_CURSED);
+
+ /* Hack give a basic exp/exp level to an object that needs it */
+ if (k_ptr->flags4 & TR4_LEVELS)
+ {
+ o_ptr->elevel = (k_ptr->level / 10) + 1;
+ o_ptr->exp = player_exp[o_ptr->elevel - 1];
+ o_ptr->pval2 = 1; /* Start with one point */
+ o_ptr->pval3 = 0; /* No flags groups */
+ }
+}
+
+
+/*
+ * Help determine an "enchantment bonus" for an object.
+ *
+ * To avoid floating point but still provide a smooth distribution of bonuses,
+ * we simply round the results of division in such a way as to "average" the
+ * correct floating point value.
+ *
+ * This function has been changed. It uses "randnor()" to choose values from
+ * a normal distribution, whose mean moves from zero towards the max as the
+ * level increases, and whose standard deviation is equal to 1/4 of the max,
+ * and whose values are forced to lie between zero and the max, inclusive.
+ *
+ * Since the "level" rarely passes 100 before Morgoth is dead, it is very
+ * rare to get the "full" enchantment on an object, even a deep levels.
+ *
+ * It is always possible (albeit unlikely) to get the "full" enchantment.
+ *
+ * A sample distribution of values from "m_bonus(10, N)" is shown below:
+ *
+ * N 0 1 2 3 4 5 6 7 8 9 10
+ * --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
+ * 0 66.37 13.01 9.73 5.47 2.89 1.31 0.72 0.26 0.12 0.09 0.03
+ * 8 46.85 24.66 12.13 8.13 4.20 2.30 1.05 0.36 0.19 0.08 0.05
+ * 16 30.12 27.62 18.52 10.52 6.34 3.52 1.95 0.90 0.31 0.15 0.05
+ * 24 22.44 15.62 30.14 12.92 8.55 5.30 2.39 1.63 0.62 0.28 0.11
+ * 32 16.23 11.43 23.01 22.31 11.19 7.18 4.46 2.13 1.20 0.45 0.41
+ * 40 10.76 8.91 12.80 29.51 16.00 9.69 5.90 3.43 1.47 0.88 0.65
+ * 48 7.28 6.81 10.51 18.27 27.57 11.76 7.85 4.99 2.80 1.22 0.94
+ * 56 4.41 4.73 8.52 11.96 24.94 19.78 11.06 7.18 3.68 1.96 1.78
+ * 64 2.81 3.07 5.65 9.17 13.01 31.57 13.70 9.30 6.04 3.04 2.64
+ * 72 1.87 1.99 3.68 7.15 10.56 20.24 25.78 12.17 7.52 4.42 4.62
+ * 80 1.02 1.23 2.78 4.75 8.37 12.04 27.61 18.07 10.28 6.52 7.33
+ * 88 0.70 0.57 1.56 3.12 6.34 10.06 15.76 30.46 12.58 8.47 10.38
+ * 96 0.27 0.60 1.25 2.28 4.30 7.60 10.77 22.52 22.51 11.37 16.53
+ * 104 0.22 0.42 0.77 1.36 2.62 5.33 8.93 13.05 29.54 15.23 22.53
+ * 112 0.15 0.20 0.56 0.87 2.00 3.83 6.86 10.06 17.89 27.31 30.27
+ * 120 0.03 0.11 0.31 0.46 1.31 2.48 4.60 7.78 11.67 25.53 45.72
+ * 128 0.02 0.01 0.13 0.33 0.83 1.41 3.24 6.17 9.57 14.22 64.07
+ */
+s16b m_bonus(int max, int level)
+{
+ int bonus, stand, extra, value;
+
+
+ /* Paranoia -- enforce maximal "level" */
+ if (level > MAX_DEPTH - 1) level = MAX_DEPTH - 1;
+
+
+ /* The "bonus" moves towards the max */
+ bonus = ((max * level) / MAX_DEPTH);
+
+ /* Hack -- determine fraction of error */
+ extra = ((max * level) % MAX_DEPTH);
+
+ /* Hack -- simulate floating point computations */
+ if (rand_int(MAX_DEPTH) < extra) bonus++;
+
+
+ /* The "stand" is equal to one quarter of the max */
+ stand = (max / 4);
+
+ /* Hack -- determine fraction of error */
+ extra = (max % 4);
+
+ /* Hack -- simulate floating point computations */
+ if (rand_int(4) < extra) stand++;
+
+
+ /* Choose an "interesting" value */
+ value = randnor(bonus, stand);
+
+ /* Enforce the minimum value */
+ if (value < 0) return (0);
+
+ /* Enforce the maximum value */
+ if (value > max) return (max);
+
+ /* Result */
+ return (value);
+}
+
+
+/*
+ * Tinker with the random artifact to make it acceptable
+ * for a certain depth; also connect a random artifact to an
+ * object.
+ */
+static void finalize_randart(object_type* o_ptr, int lev)
+{
+ int r;
+ int i = 0;
+ int foo = lev + randnor(0, 5);
+ bool_ flag = TRUE;
+
+ /* Paranoia */
+ if (o_ptr->tval != TV_RANDART) return;
+
+ if (foo < 1) foo = 1;
+ if (foo > 100) foo = 100;
+
+ while (flag)
+ {
+ r = rand_int(MAX_RANDARTS);
+
+ if (!(random_artifacts[r].generated) || i > 2000)
+ {
+ random_artifact* ra_ptr = &random_artifacts[r];
+
+ o_ptr->sval = r;
+ o_ptr->pval2 = ra_ptr->activation;
+ o_ptr->xtra2 = activation_info[ra_ptr->activation].spell;
+
+ ra_ptr->level = lev;
+ ra_ptr->generated = TRUE;
+ flag = FALSE;
+ }
+
+ i++;
+ }
+}
+
+
+
+/*
+ * Cheat -- describe a created object for the user
+ */
+static void object_mention(object_type *o_ptr)
+{
+ char o_name[80];
+
+ /* Describe */
+ object_desc_store(o_name, o_ptr, FALSE, 0);
+
+ /* Artifact */
+ if (artifact_p(o_ptr))
+ {
+ /* Silly message */
+ msg_format("Artifact (%s)", o_name);
+ }
+
+ /* Random Artifact */
+ else if (o_ptr->art_name)
+ {
+ msg_print("Random artifact");
+ }
+
+ /* Ego-item */
+ else if (ego_item_p(o_ptr))
+ {
+ /* Silly message */
+ msg_format("Ego-item (%s)", o_name);
+ }
+
+ /* Normal item */
+ else
+ {
+ /* Silly message */
+ msg_format("Object (%s)", o_name);
+ }
+}
+
+
+void random_artifact_resistance(object_type * o_ptr)
+{
+ bool_ give_resistance = FALSE, give_power = FALSE;
+
+ switch (o_ptr->name1)
+ {
+ case ART_CELEBORN:
+ case ART_ARVEDUI:
+ case ART_CASPANION:
+ case ART_TRON:
+ case ART_ROHIRRIM:
+ case ART_CELEGORM:
+ case ART_ANARION:
+ case ART_THRANDUIL:
+ case ART_LUTHIEN:
+ case ART_THROR:
+ case ART_THORIN:
+ case ART_NIMTHANC:
+ case ART_DETHANC:
+ case ART_NARTHANC:
+ case ART_STING:
+ case ART_TURMIL:
+ case ART_THALKETTOTH:
+ {
+ /* Give a resistance */
+ give_resistance = TRUE;
+ }
+ break;
+ case ART_MAEDHROS:
+ case ART_GLAMDRING:
+ case ART_ORCRIST:
+ case ART_ANDURIL:
+ case ART_ZARCUTHRA:
+ case ART_GURTHANG:
+ case ART_HARADEKKET:
+ case ART_CUBRAGOL:
+ case ART_DAWN:
+ {
+ /* Give a resistance OR a power */
+ if (randint(2) == 1) give_resistance = TRUE;
+ else give_power = TRUE;
+ }
+ break;
+ case ART_NENYA:
+ case ART_VILYA:
+ case ART_BERUTHIEL:
+ case ART_FINGOLFIN:
+ case ART_THINGOL:
+ case ART_ULMO:
+ case ART_OLORIN:
+ {
+ /* Give a power */
+ give_power = TRUE;
+ }
+ break;
+ case ART_POWER:
+ case ART_GONDOR:
+ case ART_AULE:
+ {
+ /* Give both */
+ give_power = TRUE;
+ give_resistance = TRUE;
+ }
+ break;
+ }
+
+ if (give_power)
+ {
+ o_ptr->xtra1 = EGO_XTRA_ABILITY;
+
+ /* Randomize the "xtra" power */
+ if (o_ptr->xtra1) o_ptr->xtra2 = randint(256);
+ }
+
+ artifact_bias = 0;
+
+ if (give_resistance)
+ {
+ random_resistance(o_ptr, FALSE, ((randint(22)) + 16));
+ }
+}
+
+
+/*
+ * Mega-Hack -- Attempt to create one of the "Special Objects"
+ *
+ * We are only called from "make_object()", and we assume that
+ * "apply_magic()" is called immediately after we return.
+ *
+ * Note -- see "make_artifact()" and "apply_magic()"
+ */
+static bool_ make_artifact_special(object_type *o_ptr)
+{
+ int i;
+ int k_idx = 0;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* No artifacts in the town */
+ if (!dun_level) return (FALSE);
+
+ /* Check the artifact list (just the "specials") */
+ for (i = 0; i < max_a_idx; i++)
+ {
+ artifact_type *a_ptr = &a_info[i];
+
+ /* Skip "empty" artifacts */
+ if (!a_ptr->name) continue;
+
+ /* Cannot make an artifact twice */
+ if (a_ptr->cur_num) continue;
+
+ /* Cannot generate non special ones */
+ if (!(a_ptr->flags3 & TR3_INSTA_ART)) continue;
+
+ /* Cannot generate some artifacts because they can only exists in special dungeons/quests/... */
+ if ((a_ptr->flags4 & TR4_SPECIAL_GENE) && (!a_allow_special[i])) continue;
+
+ /* XXX XXX Enforce minimum "depth" (loosely) */
+ if (a_ptr->level > dun_level)
+ {
+ /* Acquire the "out-of-depth factor" */
+ int d = (a_ptr->level - dun_level) * 2;
+
+ /* Roll for out-of-depth creation */
+ if (rand_int(d) != 0) continue;
+ }
+
+ /* Artifact "rarity roll" */
+ if (rand_int(a_ptr->rarity - luck( -(a_ptr->rarity / 2), a_ptr->rarity / 2)) != 0) continue;
+
+ /* Find the base object */
+ k_idx = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* XXX XXX Enforce minimum "object" level (loosely) */
+ if (k_info[k_idx].level > object_level)
+ {
+ /* Acquire the "out-of-depth factor" */
+ int d = (k_info[k_idx].level - object_level) * 5;
+
+ /* Roll for out-of-depth creation */
+ if (rand_int(d) != 0) continue;
+ }
+
+ /* Assign the template */
+ object_prep(o_ptr, k_idx);
+
+ /* Mega-Hack -- mark the item as an artifact */
+ o_ptr->name1 = i;
+
+ /* Extract some flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hack give a basic exp/exp level to an object that needs it */
+ if (f4 & TR4_LEVELS)
+ {
+ o_ptr->elevel = (k_info[k_idx].level / 10) + 1;
+ o_ptr->exp = player_exp[o_ptr->elevel - 1];
+ }
+
+ /* Success */
+ return (TRUE);
+ }
+
+ /* Failure */
+ return (FALSE);
+}
+
+
+/*
+ * Attempt to change an object into an artifact
+ *
+ * This routine should only be called by "apply_magic()"
+ *
+ * Note -- see "make_artifact_special()" and "apply_magic()"
+ */
+static bool_ make_artifact(object_type *o_ptr)
+{
+ int i;
+ u32b f1, f2, f3, f4, f5, esp;
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* No artifacts in the town */
+ if (!dun_level) return (FALSE);
+
+ /* Paranoia -- no "plural" artifacts */
+ if (o_ptr->number != 1) return (FALSE);
+
+ /* Check the artifact list (skip the "specials") */
+ for (i = 0; i < max_a_idx; i++)
+ {
+ artifact_type *a_ptr = &a_info[i];
+
+ /* Skip "empty" items */
+ if (!a_ptr->name) continue;
+
+ /* Cannot make an artifact twice */
+ if (a_ptr->cur_num) continue;
+
+ /* Cannot generate special ones */
+ if (a_ptr->flags3 & TR3_INSTA_ART) continue;
+
+ /* Cannot generate some artifacts because they can only exists in special dungeons/quests/... */
+ if ((a_ptr->flags4 & TR4_SPECIAL_GENE) && (!a_allow_special[i])) continue;
+
+ /* Must have the correct fields */
+ if (a_ptr->tval != o_ptr->tval) continue;
+ if (a_ptr->sval != o_ptr->sval) continue;
+
+ /* XXX XXX Enforce minimum "depth" (loosely) */
+ if (a_ptr->level > dun_level)
+ {
+ /* Acquire the "out-of-depth factor" */
+ int d = (a_ptr->level - dun_level) * 2;
+
+ /* Roll for out-of-depth creation */
+ if (rand_int(d) != 0) continue;
+ }
+
+ /* We must make the "rarity roll" */
+ if (rand_int(a_ptr->rarity - luck( -(a_ptr->rarity / 2), a_ptr->rarity / 2)) != 0) continue;
+
+ /* Hack -- mark the item as an artifact */
+ o_ptr->name1 = i;
+
+ /* Hack: Some artifacts get random extra powers */
+ random_artifact_resistance(o_ptr);
+
+ /* Extract some flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hack give a basic exp/exp level to an object that needs it */
+ if (f4 & TR4_LEVELS)
+ {
+ o_ptr->elevel = (k_ptr->level / 10) + 1;
+ o_ptr->exp = player_exp[o_ptr->elevel - 1];
+ }
+
+ /* Success */
+ return (TRUE);
+ }
+
+ /* Failure */
+ return (FALSE);
+}
+
+/*
+ * Attempt to change an object into an ego
+ *
+ * This routine should only be called by "apply_magic()"
+ */
+static bool_ make_ego_item(object_type *o_ptr, bool_ good)
+{
+ int i = 0, j;
+ int *ok_ego, ok_num = 0;
+ bool_ ret = FALSE;
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ if (artifact_p(o_ptr) || o_ptr->name2) return (FALSE);
+
+ C_MAKE(ok_ego, max_e_idx, int);
+
+ /* Grab the ok ego */
+ for (i = 0; i < max_e_idx; i++)
+ {
+ ego_item_type *e_ptr = &e_info[i];
+ bool_ ok = FALSE;
+
+ /* Skip "empty" items */
+ if (!e_ptr->name) continue;
+
+ /* Must have the correct fields */
+ for (j = 0; j < 6; j++)
+ {
+ if (e_ptr->tval[j] == o_ptr->tval)
+ {
+ if ((e_ptr->min_sval[j] <= o_ptr->sval) && (e_ptr->max_sval[j] >= o_ptr->sval)) ok = TRUE;
+ }
+
+ if (ok) break;
+ }
+ if (!ok)
+ {
+ /* Doesnt count as a try*/
+ continue;
+ }
+
+ /* Good should be good, bad should be bad */
+ if (good && (!e_ptr->cost)) continue;
+ if ((!good) && e_ptr->cost) continue;
+
+ /* Must posses the good flags */
+ if (((k_ptr->flags1 & e_ptr->need_flags1) != e_ptr->need_flags1) ||
+ ((k_ptr->flags2 & e_ptr->need_flags2) != e_ptr->need_flags2) ||
+ ((k_ptr->flags3 & e_ptr->need_flags3) != e_ptr->need_flags3) ||
+ ((k_ptr->flags4 & e_ptr->need_flags4) != e_ptr->need_flags4) ||
+ ((k_ptr->flags5 & e_ptr->need_flags5) != e_ptr->need_flags5) ||
+ ((k_ptr->esp & e_ptr->need_esp) != e_ptr->need_esp))
+ continue;
+ if ((k_ptr->flags1 & e_ptr->forbid_flags1) ||
+ (k_ptr->flags2 & e_ptr->forbid_flags2) ||
+ (k_ptr->flags3 & e_ptr->forbid_flags3) ||
+ (k_ptr->flags4 & e_ptr->forbid_flags4) ||
+ (k_ptr->flags5 & e_ptr->forbid_flags5) ||
+ (k_ptr->esp & e_ptr->forbid_esp))
+ continue;
+
+ /* ok */
+ ok_ego[ok_num++] = i;
+ }
+
+ /* Now test them a few times */
+ for (i = 0; i < ok_num * 10; i++)
+ {
+ ego_item_type *e_ptr;
+
+ int j = ok_ego[rand_int(ok_num)];
+ e_ptr = &e_info[j];
+
+ /* XXX XXX Enforce minimum "depth" (loosely) */
+ if (e_ptr->level > dun_level)
+ {
+ /* Acquire the "out-of-depth factor" */
+ int d = (e_ptr->level - dun_level);
+
+ /* Roll for out-of-depth creation */
+ if (rand_int(d) != 0)
+ {
+ continue;
+ }
+ }
+
+ /* We must make the "rarity roll" */
+ if (rand_int(e_ptr->mrarity - luck( -(e_ptr->mrarity / 2), e_ptr->mrarity / 2)) > e_ptr->rarity)
+ {
+ continue;
+ }
+
+ /* Hack -- mark the item as an ego */
+ o_ptr->name2 = j;
+
+ /* Success */
+ ret = TRUE;
+ break;
+ }
+
+ /*
+ * Sometimes(rarely) tries for a double ego
+ * Also make sure we dont already have a name2b, wchih would mean a special ego item
+ */
+ if (magik(7 + luck( -7, 7)) && (!o_ptr->name2b))
+ {
+ /* Now test them a few times */
+ for (i = 0; i < ok_num * 10; i++)
+ {
+ ego_item_type *e_ptr;
+
+ int j = ok_ego[rand_int(ok_num)];
+ e_ptr = &e_info[j];
+
+ /* Cannot be a double ego of the same ego type */
+ if (j == o_ptr->name2) continue;
+
+ /* Cannot have 2 suffixes or 2 prefixes */
+ if (e_info[o_ptr->name2].before && e_ptr->before) continue;
+ if ((!e_info[o_ptr->name2].before) && (!e_ptr->before)) continue;
+
+ /* XXX XXX Enforce minimum "depth" (loosely) */
+ if (e_ptr->level > dun_level)
+ {
+ /* Acquire the "out-of-depth factor" */
+ int d = (e_ptr->level - dun_level);
+
+ /* Roll for out-of-depth creation */
+ if (rand_int(d) != 0)
+ {
+ continue;
+ }
+ }
+
+ /* We must make the "rarity roll" */
+ if (rand_int(e_ptr->mrarity - luck( -(e_ptr->mrarity / 2), e_ptr->mrarity / 2)) > e_ptr->rarity)
+ {
+ continue;
+ }
+
+ /* Hack -- mark the item as an ego */
+ o_ptr->name2b = j;
+
+ /* Success */
+ ret = TRUE;
+ break;
+ }
+ }
+
+ C_FREE(ok_ego, max_e_idx, int);
+
+ /* Return */
+ return (ret);
+}
+
+
+/*
+ * Charge a new stick.
+ */
+void charge_stick(object_type *o_ptr)
+{
+ o_ptr->pval = exec_lua(format("return get_stick_charges(%d)", o_ptr->pval2));
+}
+
+/*
+ * Apply magic to an item known to be a "weapon"
+ *
+ * Hack -- note special base damage dice boosting
+ * Hack -- note special processing for weapon/digger
+ * Hack -- note special rating boost for dragon scale mail
+ */
+static void a_m_aux_1(object_type *o_ptr, int level, int power)
+{
+ int tohit1 = randint(5) + m_bonus(5, level);
+ int todam1 = randint(5) + m_bonus(5, level);
+
+ int tohit2 = m_bonus(10, level);
+ int todam2 = m_bonus(10, level);
+
+ artifact_bias = 0;
+
+ /* Very good */
+ if (power > 1)
+ {
+ /* Make ego item */
+ if ((rand_int(RANDART_WEAPON) == 1) && (o_ptr->tval != TV_TRAPKIT)) create_artifact(o_ptr, FALSE, TRUE);
+ else make_ego_item(o_ptr, TRUE);
+ }
+ else if (power < -1)
+ {
+ /* Make ego item */
+ make_ego_item(o_ptr, FALSE);
+ }
+
+ /* Good */
+ if (power > 0)
+ {
+ /* Enchant */
+ o_ptr->to_h += tohit1;
+ o_ptr->to_d += todam1;
+
+ /* Very good */
+ if (power > 1)
+ {
+ /* Enchant again */
+ o_ptr->to_h += tohit2;
+ o_ptr->to_d += todam2;
+ }
+ }
+
+ /* Cursed */
+ else if (power < 0)
+ {
+ /* Penalize */
+ o_ptr->to_h -= tohit1;
+ o_ptr->to_d -= todam1;
+
+ /* Very cursed */
+ if (power < -1)
+ {
+ /* Penalize again */
+ o_ptr->to_h -= tohit2;
+ o_ptr->to_d -= todam2;
+ }
+
+ /* Cursed (if "bad") */
+ if (o_ptr->to_h + o_ptr->to_d < 0) o_ptr->ident |= (IDENT_CURSED);
+ }
+
+ /* Some special cases */
+ if (process_hooks(HOOK_APPLY_MAGIC, "(O,d,d)", o_ptr, level, power))
+ return;
+ switch (o_ptr->tval)
+ {
+ case TV_TRAPKIT:
+ {
+ /* Good */
+ if (power > 0) o_ptr->to_a += randint(5);
+
+ /* Very good */
+ if (power > 1) o_ptr->to_a += randint(5);
+
+ /* Bad */
+ if (power < 0) o_ptr->to_a -= randint(5);
+
+ /* Very bad */
+ if (power < -1) o_ptr->to_a -= randint(5);
+
+ break;
+ }
+ case TV_MSTAFF:
+ {
+ if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL))
+ {
+ int gf[2], i;
+
+ for (i = 0; i < 2; i++)
+ {
+ int k = 0;
+
+ gf[i] = 0;
+ while (!k)
+ {
+ k = lookup_kind(TV_RUNE1, (gf[i] = rand_int(MAX_GF)));
+ }
+ }
+
+ o_ptr->pval = gf[0] + (gf[1] << 16);
+ o_ptr->pval3 = rand_int(RUNE_MOD_MAX) + (rand_int(RUNE_MOD_MAX) << 16);
+ o_ptr->pval2 = randint(70) + (randint(70) << 8);
+ }
+ else
+ o_ptr->art_flags5 |= (TR5_SPELL_CONTAIN | TR5_WIELD_CAST);
+ break;
+ }
+ case TV_BOLT:
+ case TV_ARROW:
+ case TV_SHOT:
+ {
+ if ((power == 1) && !o_ptr->name2)
+ {
+ if (randint(100) < 30)
+ {
+ /* Exploding missile */
+ int power[27] = {GF_ELEC, GF_POIS, GF_ACID,
+ GF_COLD, GF_FIRE, GF_PLASMA, GF_LITE,
+ GF_DARK, GF_SHARDS, GF_SOUND,
+ GF_CONFUSION, GF_FORCE, GF_INERTIA,
+ GF_MANA, GF_METEOR, GF_ICE, GF_CHAOS,
+ GF_NETHER, GF_NEXUS, GF_TIME,
+ GF_GRAVITY, GF_KILL_WALL, GF_AWAY_ALL,
+ GF_TURN_ALL, GF_NUKE, GF_STUN,
+ GF_DISINTEGRATE};
+
+ o_ptr->pval2 = power[rand_int(27)];
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+static void dragon_resist(object_type * o_ptr)
+{
+ do
+ {
+ artifact_bias = 0;
+
+ if (randint(4) == 1)
+ random_resistance(o_ptr, FALSE, ((randint(14)) + 4));
+ else
+ random_resistance(o_ptr, FALSE, ((randint(22)) + 16));
+ }
+ while (randint(2) == 1);
+}
+
+
+/*
+ * Apply magic to an item known to be "armor"
+ *
+ * Hack -- note special processing for crown/helm
+ * Hack -- note special processing for robe of permanence
+ */
+static void a_m_aux_2(object_type *o_ptr, int level, int power)
+{
+ int toac1 = randint(5) + m_bonus(5, level);
+
+ int toac2 = m_bonus(10, level);
+
+ artifact_bias = 0;
+
+ /* Very good */
+ if (power > 1)
+ {
+ /* Make ego item */
+ if (rand_int(RANDART_ARMOR) == 1) create_artifact(o_ptr, FALSE, TRUE);
+ else make_ego_item(o_ptr, TRUE);
+ }
+ else if (power < -1)
+ {
+ /* Make ego item */
+ make_ego_item(o_ptr, FALSE);
+ }
+
+ /* Good */
+ if (power > 0)
+ {
+ /* Enchant */
+ o_ptr->to_a += toac1;
+
+ /* Very good */
+ if (power > 1)
+ {
+ /* Enchant again */
+ o_ptr->to_a += toac2;
+ }
+ }
+
+ /* Cursed */
+ else if (power < 0)
+ {
+ /* Penalize */
+ o_ptr->to_a -= toac1;
+
+ /* Very cursed */
+ if (power < -1)
+ {
+ /* Penalize again */
+ o_ptr->to_a -= toac2;
+ }
+
+ /* Cursed (if "bad") */
+ if (o_ptr->to_a < 0) o_ptr->ident |= (IDENT_CURSED);
+ }
+
+ /* Analyze type */
+ if (process_hooks(HOOK_APPLY_MAGIC, "(O,d,d)", o_ptr, level, power))
+ return;
+ switch (o_ptr->tval)
+ {
+ case TV_CLOAK:
+ {
+ if (o_ptr->sval == SV_ELVEN_CLOAK)
+ o_ptr->pval = randint(4); /* No cursed elven cloaks...? */
+ else if (o_ptr->sval == SV_MIMIC_CLOAK)
+ {
+ s32b mimic;
+
+ call_lua("find_random_mimic_shape", "(d,d)", "d", level, TRUE, &mimic);
+ o_ptr->pval2 = mimic;
+ }
+ break;
+ }
+ case TV_DRAG_ARMOR:
+ {
+ /* Rating boost */
+ rating += 30;
+
+ /* Mention the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+
+ break;
+ }
+ case TV_SHIELD:
+ {
+ if (o_ptr->sval == SV_DRAGON_SHIELD)
+ {
+ /* Rating boost */
+ rating += 5;
+
+ /* Mention the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+ dragon_resist(o_ptr);
+ }
+ break;
+ }
+ case TV_HELM:
+ {
+ if (o_ptr->sval == SV_DRAGON_HELM)
+ {
+ /* Rating boost */
+ rating += 5;
+
+ /* Mention the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+ dragon_resist(o_ptr);
+ }
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * Apply magic to an item known to be a "ring" or "amulet"
+ *
+ * Hack -- note special rating boost for ring of speed
+ * Hack -- note special rating boost for amulet of the magi
+ * Hack -- note special "pval boost" code for ring of speed
+ * Hack -- note that some items must be cursed (or blessed)
+ */
+static void a_m_aux_3(object_type *o_ptr, int level, int power)
+{
+
+ artifact_bias = 0;
+
+ /* Very good */
+ if (power > 1)
+ {
+ /* Make ego item */
+ if (rand_int(RANDART_JEWEL) == 1) create_artifact(o_ptr, FALSE, TRUE);
+ else make_ego_item(o_ptr, TRUE);
+ }
+ else if (power < -1)
+ {
+ /* Make ego item */
+ make_ego_item(o_ptr, FALSE);
+ }
+
+ /* Apply magic (good or bad) according to type */
+ if (process_hooks(HOOK_APPLY_MAGIC, "(O,d,d)", o_ptr, level, power))
+ return;
+ switch (o_ptr->tval)
+ {
+ case TV_RING:
+ {
+ /* Analyze */
+ switch (o_ptr->sval)
+ {
+ /* Strength, Constitution, Dexterity, Intelligence */
+ case SV_RING_ATTACKS:
+ {
+ /* Stat bonus */
+ o_ptr->pval = m_bonus(3, level);
+ if (o_ptr->pval < 1) o_ptr->pval = 1;
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse pval */
+ o_ptr->pval = 0 - (o_ptr->pval);
+ }
+
+ break;
+ }
+
+ /* Critical hits */
+ case SV_RING_CRIT:
+ {
+ /* Stat bonus */
+ o_ptr->pval = m_bonus(10, level);
+ if (o_ptr->pval < 1) o_ptr->pval = 1;
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse pval */
+ o_ptr->pval = 0 - (o_ptr->pval);
+ }
+
+ break;
+ }
+
+
+ case SV_RING_STR:
+ case SV_RING_CON:
+ case SV_RING_DEX:
+ case SV_RING_INT:
+ {
+ /* Stat bonus */
+ o_ptr->pval = 1 + m_bonus(5, level);
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse pval */
+ o_ptr->pval = 0 - (o_ptr->pval);
+ }
+
+ break;
+ }
+
+ /* Ring of Speed! */
+ case SV_RING_SPEED:
+ {
+ /* Base speed (1 to 10) */
+ o_ptr->pval = randint(5) + m_bonus(5, level);
+
+ /* Super-charge the ring */
+ while (rand_int(100) < 50) o_ptr->pval++;
+
+ /* Cursed Ring */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse pval */
+ o_ptr->pval = 0 - (o_ptr->pval);
+
+ break;
+ }
+
+ /* Rating boost */
+ rating += 25;
+
+ /* Mention the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+
+ break;
+ }
+
+ case SV_RING_LORDLY:
+ {
+ do
+ {
+ random_resistance(o_ptr, FALSE, ((randint(20)) + 18));
+ }
+ while (randint(4) == 1);
+
+ /* Bonus to armor class */
+ o_ptr->to_a = 10 + randint(5) + m_bonus(10, level);
+ rating += 5;
+ }
+ break;
+
+ /* Searching */
+ case SV_RING_SEARCHING:
+ {
+ /* Bonus to searching */
+ o_ptr->pval = 1 + m_bonus(5, level);
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse pval */
+ o_ptr->pval = 0 - (o_ptr->pval);
+ }
+
+ break;
+ }
+
+ /* Flames, Acid, Ice */
+ case SV_RING_FLAMES:
+ case SV_RING_ACID:
+ case SV_RING_ICE:
+ {
+ /* Bonus to armor class */
+ o_ptr->to_a = 5 + randint(5) + m_bonus(10, level);
+ break;
+ }
+
+ /* Weakness, Stupidity */
+ case SV_RING_WEAKNESS:
+ case SV_RING_STUPIDITY:
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Penalize */
+ o_ptr->pval = 0 - (1 + m_bonus(5, level));
+
+ break;
+ }
+
+ /* WOE, Stupidity */
+ case SV_RING_WOE:
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Penalize */
+ o_ptr->to_a = 0 - (5 + m_bonus(10, level));
+ o_ptr->pval = 0 - (1 + m_bonus(5, level));
+
+ break;
+ }
+
+ /* Ring of damage */
+ case SV_RING_DAMAGE:
+ {
+ /* Bonus to damage */
+ o_ptr->to_d = 5 + randint(8) + m_bonus(10, level);
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse bonus */
+ o_ptr->to_d = 0 - (o_ptr->to_d);
+ }
+
+ break;
+ }
+
+ /* Ring of Accuracy */
+ case SV_RING_ACCURACY:
+ {
+ /* Bonus to hit */
+ o_ptr->to_h = 5 + randint(8) + m_bonus(10, level);
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse tohit */
+ o_ptr->to_h = 0 - (o_ptr->to_h);
+ }
+
+ break;
+ }
+
+ /* Ring of Protection */
+ case SV_RING_PROTECTION:
+ {
+ /* Bonus to armor class */
+ o_ptr->to_a = 5 + randint(8) + m_bonus(10, level);
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse toac */
+ o_ptr->to_a = 0 - (o_ptr->to_a);
+ }
+
+ break;
+ }
+
+ /* Ring of Slaying */
+ case SV_RING_SLAYING:
+ {
+ /* Bonus to damage and to hit */
+ o_ptr->to_d = randint(7) + m_bonus(10, level);
+ o_ptr->to_h = randint(7) + m_bonus(10, level);
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse bonuses */
+ o_ptr->to_h = 0 - (o_ptr->to_h);
+ o_ptr->to_d = 0 - (o_ptr->to_d);
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case TV_AMULET:
+ {
+ /* Analyze */
+ switch (o_ptr->sval)
+ {
+ /* Amulet of Trickery */
+ case SV_AMULET_TRICKERY:
+ case SV_AMULET_DEVOTION:
+ {
+ o_ptr->pval = 1 + m_bonus(3, level);
+
+ /* Mention the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+ break;
+ }
+
+ case SV_AMULET_WEAPONMASTERY:
+ {
+ o_ptr->pval = 1 + m_bonus(2, level);
+ o_ptr->to_a = 1 + m_bonus(4, level);
+ o_ptr->to_h = 1 + m_bonus(5, level);
+ o_ptr->to_d = 1 + m_bonus(5, level);
+
+ /* Mention the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+ break;
+ }
+
+ /* Amulet of wisdom/charisma */
+ case SV_AMULET_BRILLANCE:
+ case SV_AMULET_CHARISMA:
+ case SV_AMULET_WISDOM:
+ case SV_AMULET_INFRA:
+ {
+ o_ptr->pval = 1 + m_bonus(5, level);
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse bonuses */
+ o_ptr->pval = 0 - (o_ptr->pval);
+ }
+
+ break;
+ }
+
+ /* Amulet of the Serpents */
+ case SV_AMULET_SERPENT:
+ {
+ o_ptr->pval = 1 + m_bonus(5, level);
+ o_ptr->to_a = 1 + m_bonus(6, level);
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse bonuses */
+ o_ptr->pval = 0 - (o_ptr->pval);
+ }
+
+ break;
+ }
+
+ case SV_AMULET_NO_MAGIC:
+ case SV_AMULET_NO_TELE:
+ {
+ if (power < 0)
+ {
+ o_ptr->ident |= (IDENT_CURSED);
+ }
+ break;
+ }
+
+ case SV_AMULET_RESISTANCE:
+ {
+ if (randint(3) == 1) random_resistance(o_ptr, FALSE, ((randint(34)) + 4));
+ if (randint(5) == 1) o_ptr->art_flags2 |= TR2_RES_POIS;
+ }
+ break;
+
+ /* Amulet of searching */
+ case SV_AMULET_SEARCHING:
+ {
+ o_ptr->pval = randint(5) + m_bonus(5, level);
+
+ /* Cursed */
+ if (power < 0)
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Reverse bonuses */
+ o_ptr->pval = 0 - (o_ptr->pval);
+ }
+
+ break;
+ }
+
+ /* Amulet of the Magi -- never cursed */
+ case SV_AMULET_THE_MAGI:
+ {
+ o_ptr->pval = 1 + m_bonus(3, level);
+
+ if (randint(3) == 1) o_ptr->art_flags3 |= TR3_SLOW_DIGEST;
+
+ /* Boost the rating */
+ rating += 25;
+
+ /* Mention the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+
+ break;
+ }
+
+ /* Amulet of Doom -- always cursed */
+ case SV_AMULET_DOOM:
+ {
+ /* Cursed */
+ o_ptr->ident |= (IDENT_CURSED);
+
+ /* Penalize */
+ o_ptr->pval = 0 - (randint(5) + m_bonus(5, level));
+ o_ptr->to_a = 0 - (randint(5) + m_bonus(5, level));
+
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+}
+
+
+/*
+ * Apply magic to an item known to be "boring"
+ *
+ * Hack -- note the special code for various items
+ */
+static void a_m_aux_4(object_type *o_ptr, int level, int power)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+ s32b bonus_lvl, max_lvl;
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Very good */
+ if (power > 1)
+ {
+ /* Make ego item */
+ if ((rand_int(RANDART_JEWEL) == 1) && (o_ptr->tval == TV_LITE)) create_artifact(o_ptr, FALSE, TRUE);
+ else make_ego_item(o_ptr, TRUE);
+ }
+ else if (power < -1)
+ {
+ /* Make ego item */
+ make_ego_item(o_ptr, FALSE);
+ }
+
+ /* Apply magic (good or bad) according to type */
+ if (process_hooks(HOOK_APPLY_MAGIC, "(O,d,d)", o_ptr, level, power))
+ return;
+ switch (o_ptr->tval)
+ {
+ case TV_BOOK:
+ {
+ /* Randomize random books */
+ if (o_ptr->sval == 255)
+ {
+ int i = 0;
+
+ /* Only random ones */
+ if (magik(75))
+ i = exec_lua(format("return get_random_spell(SKILL_MAGIC, %d)", level));
+ else
+ i = exec_lua(format("return get_random_spell(SKILL_SPIRITUALITY, %d)", level));
+
+ /* Use globe of light(or the first one) */
+ if (i == -1)
+ o_ptr->pval = 0;
+ else
+ o_ptr->pval = i;
+ }
+
+ break;
+ }
+
+ case TV_LITE:
+ {
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hack -- random fuel */
+ if (f4 & TR4_FUEL_LITE)
+ {
+ if (k_info[o_ptr->k_idx].pval2 > 0) o_ptr->timeout = randint(k_info[o_ptr->k_idx].pval2);
+ }
+
+ break;
+ }
+
+ case TV_CORPSE:
+ {
+ /* Hack -- choose a monster */
+ monster_race* r_ptr;
+ int r_idx = get_mon_num(dun_level);
+ r_ptr = &r_info[r_idx];
+
+ if (!(r_ptr->flags1 & RF1_UNIQUE))
+ o_ptr->pval2 = r_idx;
+ else
+ o_ptr->pval2 = 2;
+ o_ptr->pval3 = 0;
+ break;
+ }
+
+ case TV_EGG:
+ {
+ /* Hack -- choose a monster */
+ monster_race* r_ptr;
+ int r_idx, count = 0;
+ bool_ OK = FALSE;
+
+ while ((!OK) && (count < 1000))
+ {
+ r_idx = get_mon_num(dun_level);
+ r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags9 & RF9_HAS_EGG)
+ {
+ o_ptr->pval2 = r_idx;
+ OK = TRUE;
+ }
+ count++;
+ }
+ if (count == 1000) o_ptr->pval2 = 940; /* Blue fire-lizard */
+
+ r_ptr = &r_info[o_ptr->pval2];
+ o_ptr->weight = (r_ptr->weight + rand_int(r_ptr->weight) / 100) + 1;
+ o_ptr->pval = r_ptr->weight * 3 + rand_int(r_ptr->weight) + 1;
+ break;
+ }
+
+ case TV_HYPNOS:
+ {
+ /* Hack -- choose a monster */
+ monster_race* r_ptr;
+ int r_idx = get_mon_num(dun_level);
+ r_ptr = &r_info[r_idx];
+
+ if (!(r_ptr->flags1 & RF1_NEVER_MOVE))
+ o_ptr->pval = r_idx;
+ else
+ o_ptr->pval = 20;
+
+ r_idx = o_ptr->pval;
+ r_ptr = &r_info[r_idx];
+
+ o_ptr->pval3 = maxroll(r_ptr->hdice, r_ptr->hside);
+ o_ptr->pval2 = o_ptr->pval2;
+ o_ptr->exp = 0;
+ o_ptr->elevel = r_ptr->level;
+ break;
+ }
+
+ case TV_WAND:
+ {
+ /* Decide the spell, pval == -1 means to bypass spell selection */
+ if (o_ptr->pval != -1)
+ {
+ int spl = exec_lua("return get_random_stick(TV_WAND, dun_level)");
+
+ if (spl == -1) spl = exec_lua("return find_spell('Manathrust')");
+
+ o_ptr->pval2 = spl;
+ }
+ /* Is the spell predefined by the object kind? */
+ else if (k_ptr->pval == -1)
+ {
+ o_ptr->pval2 = k_ptr->pval2;
+ }
+
+ /* Ok now get a base level */
+ call_lua("get_stick_base_level", "(d,d,d)", "d", TV_WAND, dun_level, o_ptr->pval2, &bonus_lvl);
+ call_lua("get_stick_max_level", "(d,d,d)", "d", TV_WAND, dun_level, o_ptr->pval2, &max_lvl);
+ o_ptr->pval3 = (max_lvl << 16) + (bonus_lvl & 0xFFFF);
+
+ /* Hack -- charge wands */
+ charge_stick(o_ptr);
+
+ break;
+ }
+
+ case TV_STAFF:
+ {
+ /* Decide the spell, pval == -1 means to bypass spell selection */
+ if (o_ptr->pval != -1)
+ {
+ int spl = exec_lua("return get_random_stick(TV_STAFF, dun_level)");
+
+ if (spl == -1) spl = exec_lua("return find_spell('Globe of Light')");
+
+ o_ptr->pval2 = spl;
+ }
+ /* Is the spell predefined by the object kind? */
+ else if (k_ptr->pval == -1)
+ {
+ o_ptr->pval2 = k_ptr->pval2;
+ }
+
+ /* Ok now get a base level */
+ call_lua("get_stick_base_level", "(d,d,d)", "d", TV_STAFF, dun_level, o_ptr->pval2, &bonus_lvl);
+ call_lua("get_stick_max_level", "(d,d,d)", "d", TV_STAFF, dun_level, o_ptr->pval2, &max_lvl);
+ o_ptr->pval3 = (max_lvl << 16) + (bonus_lvl & 0xFFFF);
+
+ /* Hack -- charge staffs */
+ charge_stick(o_ptr);
+
+ break;
+ }
+
+ case TV_CHEST:
+ {
+ /* Hack -- skip ruined chests */
+ if (k_info[o_ptr->k_idx].level <= 0) break;
+
+ /* Pick a trap */
+ place_trap_object(o_ptr);
+
+ /* Hack - set pval2 to the number of objects in it */
+ if (o_ptr->pval)
+ o_ptr->pval2 = (o_ptr->sval % SV_CHEST_MIN_LARGE) * 2;
+ break;
+ }
+ case TV_POTION:
+ if (o_ptr->sval == SV_POTION_BLOOD)
+ {
+ /* Rating boost */
+ rating += 25;
+ /* Mention the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+ }
+ break;
+ case TV_POTION2:
+ if (o_ptr->sval == SV_POTION2_MIMIC)
+ {
+ s32b mimic;
+
+ call_lua("find_random_mimic_shape", "(d,d)", "d", level, FALSE, &mimic);
+ o_ptr->pval2 = mimic;
+ }
+ break;
+ case TV_INSTRUMENT:
+ {
+ if (o_ptr->sval != SV_HORN)
+ {
+ /* Nothing */
+ }
+ else
+ {
+ if (is_ego_p(o_ptr, EGO_INST_DRAGONKIND))
+ {
+ switch (randint(4))
+ {
+ case 1:
+ o_ptr->pval2 = GF_ELEC;
+ break;
+ case 2:
+ o_ptr->pval2 = GF_FIRE;
+ break;
+ case 3:
+ o_ptr->pval2 = GF_COLD;
+ break;
+ case 4:
+ o_ptr->pval2 = GF_ACID;
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ case TV_TOOL:
+ {
+ break;
+ }
+
+ }
+}
+
+void trap_hack(object_type *o_ptr)
+{
+ if (o_ptr->tval != TV_TRAPKIT) return;
+
+ switch (o_ptr->sval)
+ {
+ case SV_TRAPKIT_POTION:
+ case SV_TRAPKIT_SCROLL:
+ case SV_TRAPKIT_DEVICE:
+ o_ptr->to_h = 0;
+ o_ptr->to_d = 0;
+ default:
+ return;
+ }
+}
+
+/* Add a random glag to the ego item */
+void add_random_ego_flag(object_type *o_ptr, int fego, bool_ *limit_blows)
+{
+ if (fego & ETR4_SUSTAIN)
+ {
+ /* Make a random sustain */
+ switch (randint(6))
+ {
+ case 1:
+ o_ptr->art_flags2 |= TR2_SUST_STR;
+ break;
+ case 2:
+ o_ptr->art_flags2 |= TR2_SUST_INT;
+ break;
+ case 3:
+ o_ptr->art_flags2 |= TR2_SUST_WIS;
+ break;
+ case 4:
+ o_ptr->art_flags2 |= TR2_SUST_DEX;
+ break;
+ case 5:
+ o_ptr->art_flags2 |= TR2_SUST_CON;
+ break;
+ case 6:
+ o_ptr->art_flags2 |= TR2_SUST_CHR;
+ break;
+ }
+ }
+
+ if (fego & ETR4_OLD_RESIST)
+ {
+ /* Make a random resist, equal probabilities */
+ switch (randint(11))
+ {
+ case 1:
+ o_ptr->art_flags2 |= (TR2_RES_BLIND);
+ break;
+ case 2:
+ o_ptr->art_flags2 |= (TR2_RES_CONF);
+ break;
+ case 3:
+ o_ptr->art_flags2 |= (TR2_RES_SOUND);
+ break;
+ case 4:
+ o_ptr->art_flags2 |= (TR2_RES_SHARDS);
+ break;
+ case 5:
+ o_ptr->art_flags2 |= (TR2_RES_NETHER);
+ break;
+ case 6:
+ o_ptr->art_flags2 |= (TR2_RES_NEXUS);
+ break;
+ case 7:
+ o_ptr->art_flags2 |= (TR2_RES_CHAOS);
+ break;
+ case 8:
+ o_ptr->art_flags2 |= (TR2_RES_DISEN);
+ break;
+ case 9:
+ o_ptr->art_flags2 |= (TR2_RES_POIS);
+ break;
+ case 10:
+ o_ptr->art_flags2 |= (TR2_RES_DARK);
+ break;
+ case 11:
+ o_ptr->art_flags2 |= (TR2_RES_LITE);
+ break;
+ }
+ }
+
+ if (fego & ETR4_ABILITY)
+ {
+ /* Choose an ability */
+ switch (randint(8))
+ {
+ case 1:
+ o_ptr->art_flags3 |= (TR3_FEATHER);
+ break;
+ case 2:
+ o_ptr->art_flags3 |= (TR3_LITE1);
+ break;
+ case 3:
+ o_ptr->art_flags3 |= (TR3_SEE_INVIS);
+ break;
+ case 4:
+ o_ptr->art_esp |= (ESP_ALL);
+ break;
+ case 5:
+ o_ptr->art_flags3 |= (TR3_SLOW_DIGEST);
+ break;
+ case 6:
+ o_ptr->art_flags3 |= (TR3_REGEN);
+ break;
+ case 7:
+ o_ptr->art_flags2 |= (TR2_FREE_ACT);
+ break;
+ case 8:
+ o_ptr->art_flags2 |= (TR2_HOLD_LIFE);
+ break;
+ }
+ }
+
+ if (fego & ETR4_R_ELEM)
+ {
+ /* Make an acid/elec/fire/cold/poison resist */
+ random_resistance(o_ptr, FALSE, randint(14) + 4);
+ }
+ if (fego & ETR4_R_LOW)
+ {
+ /* Make an acid/elec/fire/cold resist */
+ random_resistance(o_ptr, FALSE, randint(12) + 4);
+ }
+
+ if (fego & ETR4_R_HIGH)
+ {
+ /* Make a high resist */
+ random_resistance(o_ptr, FALSE, randint(22) + 16);
+ }
+ if (fego & ETR4_R_ANY)
+ {
+ /* Make any resist */
+ random_resistance(o_ptr, FALSE, randint(34) + 4);
+ }
+
+ if (fego & ETR4_R_DRAGON)
+ {
+ /* Make "dragon resist" */
+ dragon_resist(o_ptr);
+ }
+
+ if (fego & ETR4_SLAY_WEAP)
+ {
+ /* Make a Weapon of Slaying */
+
+ if (randint(3) == 1) /* double damage */
+ o_ptr->dd *= 2;
+ else
+ {
+ do
+ {
+ o_ptr->dd++;
+ }
+ while (randint(o_ptr->dd) == 1);
+ do
+ {
+ o_ptr->ds++;
+ }
+ while (randint(o_ptr->ds) == 1);
+ }
+ if (randint(5) == 1)
+ {
+ o_ptr->art_flags1 |= TR1_BRAND_POIS;
+ }
+ if (o_ptr->tval == TV_SWORD && (randint(3) == 1))
+ {
+ o_ptr->art_flags1 |= TR1_VORPAL;
+ }
+ }
+
+ if (fego & ETR4_DAM_DIE)
+ {
+ /* Increase damage dice */
+ o_ptr->dd++;
+ }
+
+ if (fego & ETR4_DAM_SIZE)
+ {
+ /* Increase damage dice size */
+ o_ptr->ds++;
+ }
+
+ if (fego & ETR4_LIMIT_BLOWS)
+ {
+ /* Swap this flag */
+ *limit_blows = !(*limit_blows);
+ }
+
+ if (fego & ETR4_PVAL_M1)
+ {
+ /* Increase pval */
+ o_ptr->pval++;
+ }
+
+ if (fego & ETR4_PVAL_M2)
+ {
+ /* Increase pval */
+ o_ptr->pval += m_bonus(2, dun_level);
+ }
+
+ if (fego & ETR4_PVAL_M3)
+ {
+ /* Increase pval */
+ o_ptr->pval += m_bonus(3, dun_level);
+ }
+
+ if (fego & ETR4_PVAL_M5)
+ {
+ /* Increase pval */
+ o_ptr->pval += m_bonus(5, dun_level);
+ }
+ if (fego & ETR4_AC_M1)
+ {
+ /* Increase ac */
+ o_ptr->to_a++;
+ }
+
+ if (fego & ETR4_AC_M2)
+ {
+ /* Increase ac */
+ o_ptr->to_a += m_bonus(2, dun_level);
+ }
+
+ if (fego & ETR4_AC_M3)
+ {
+ /* Increase ac */
+ o_ptr->to_a += m_bonus(3, dun_level);
+ }
+
+ if (fego & ETR4_AC_M5)
+ {
+ /* Increase ac */
+ o_ptr->to_a += m_bonus(5, dun_level);
+ }
+
+ if (fego & ETR4_TH_M1)
+ {
+ /* Increase to hit */
+ o_ptr->to_h++;
+ }
+
+ if (fego & ETR4_TH_M2)
+ {
+ /* Increase to hit */
+ o_ptr->to_h += m_bonus(2, dun_level);
+ }
+
+ if (fego & ETR4_TH_M3)
+ {
+ /* Increase to hit */
+ o_ptr->to_h += m_bonus(3, dun_level);
+ }
+
+ if (fego & ETR4_TH_M5)
+ {
+ /* Increase to hit */
+ o_ptr->to_h += m_bonus(5, dun_level);
+ }
+
+ if (fego & ETR4_TD_M1)
+ {
+ /* Increase to dam */
+ o_ptr->to_d++;
+ }
+
+ if (fego & ETR4_TD_M2)
+ {
+ /* Increase to dam */
+ o_ptr->to_d += m_bonus(2, dun_level);
+ }
+
+ if (fego & ETR4_TD_M3)
+ {
+ /* Increase to dam */
+ o_ptr->to_d += m_bonus(3, dun_level);
+ }
+
+ if (fego & ETR4_TD_M5)
+ {
+ /* Increase to dam */
+ o_ptr->to_d += m_bonus(5, dun_level);
+ }
+
+ if (fego & ETR4_R_P_ABILITY)
+ {
+ /* Add a random pval-affected ability */
+ /* This might cause boots with + to blows */
+ switch (randint(6))
+ {
+ case 1:
+ o_ptr->art_flags1 |= TR1_STEALTH;
+ break;
+ case 2:
+ o_ptr->art_flags1 |= TR1_SEARCH;
+ break;
+ case 3:
+ o_ptr->art_flags1 |= TR1_INFRA;
+ break;
+ case 4:
+ o_ptr->art_flags1 |= TR1_TUNNEL;
+ break;
+ case 5:
+ o_ptr->art_flags1 |= TR1_SPEED;
+ break;
+ case 6:
+ o_ptr->art_flags1 |= TR1_BLOWS;
+ break;
+ }
+ }
+ if (fego & ETR4_R_STAT)
+ {
+ /* Add a random stat */
+ switch (randint(6))
+ {
+ case 1:
+ o_ptr->art_flags1 |= TR1_STR;
+ break;
+ case 2:
+ o_ptr->art_flags1 |= TR1_INT;
+ break;
+ case 3:
+ o_ptr->art_flags1 |= TR1_WIS;
+ break;
+ case 4:
+ o_ptr->art_flags1 |= TR1_DEX;
+ break;
+ case 5:
+ o_ptr->art_flags1 |= TR1_CON;
+ break;
+ case 6:
+ o_ptr->art_flags1 |= TR1_CHR;
+ break;
+ }
+ }
+
+ if (fego & ETR4_R_STAT_SUST)
+ {
+ /* Add a random stat and sustain it */
+ switch (randint(6))
+ {
+ case 1:
+ {
+ o_ptr->art_flags1 |= TR1_STR;
+ o_ptr->art_flags2 |= TR2_SUST_STR;
+ break;
+ }
+
+ case 2:
+ {
+ o_ptr->art_flags1 |= TR1_INT;
+ o_ptr->art_flags2 |= TR2_SUST_INT;
+ break;
+ }
+
+ case 3:
+ {
+ o_ptr->art_flags1 |= TR1_WIS;
+ o_ptr->art_flags2 |= TR2_SUST_WIS;
+ break;
+ }
+
+ case 4:
+ {
+ o_ptr->art_flags1 |= TR1_DEX;
+ o_ptr->art_flags2 |= TR2_SUST_DEX;
+ break;
+ }
+
+ case 5:
+ {
+ o_ptr->art_flags1 |= TR1_CON;
+ o_ptr->art_flags2 |= TR2_SUST_CON;
+ break;
+ }
+ case 6:
+ {
+ o_ptr->art_flags1 |= TR1_CHR;
+ o_ptr->art_flags2 |= TR2_SUST_CHR;
+ break;
+ }
+ }
+ }
+
+ if (fego & ETR4_R_IMMUNITY)
+ {
+ /* Give a random immunity */
+ switch (randint(4))
+ {
+ case 1:
+ {
+ o_ptr->art_flags2 |= TR2_IM_FIRE;
+ o_ptr->art_flags3 |= TR3_IGNORE_FIRE;
+ break;
+ }
+ case 2:
+ {
+ o_ptr->art_flags2 |= TR2_IM_ACID;
+ o_ptr->art_flags3 |= TR3_IGNORE_ACID;
+ break;
+ }
+ case 3:
+ {
+ o_ptr->art_flags2 |= TR2_IM_ELEC;
+ o_ptr->art_flags3 |= TR3_IGNORE_ELEC;
+ break;
+ }
+ case 4:
+ {
+ o_ptr->art_flags2 |= TR2_IM_COLD;
+ o_ptr->art_flags3 |= TR3_IGNORE_COLD;
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Complete the "creation" of an object by applying "magic" to the item
+ *
+ * This includes not only rolling for random bonuses, but also putting the
+ * finishing touches on ego-items and artifacts, giving charges to wands and
+ * staffs, giving fuel to lites, and placing traps on chests.
+ *
+ * In particular, note that "Instant Artifacts", if "created" by an external
+ * routine, must pass through this function to complete the actual creation.
+ *
+ * The base "chance" of the item being "good" increases with the "level"
+ * parameter, which is usually derived from the dungeon level, being equal
+ * to the level plus 10, up to a maximum of 75. If "good" is true, then
+ * the object is guaranteed to be "good". If an object is "good", then
+ * the chance that the object will be "great" (ego-item or artifact), also
+ * increases with the "level", being equal to half the level, plus 5, up to
+ * a maximum of 20. If "great" is true, then the object is guaranteed to be
+ * "great". At dungeon level 65 and below, 15/100 objects are "great".
+ *
+ * If the object is not "good", there is a chance it will be "cursed", and
+ * if it is "cursed", there is a chance it will be "broken". These chances
+ * are related to the "good" / "great" chances above.
+ *
+ * Otherwise "normal" rings and amulets will be "good" half the time and
+ * "cursed" half the time, unless the ring/amulet is always good or cursed.
+ *
+ * If "okay" is true, and the object is going to be "great", then there is
+ * a chance that an artifact will be created. This is true even if both the
+ * "good" and "great" arguments are false. As a total hack, if "great" is
+ * true, then the item gets 3 extra "attempts" to become an artifact.
+ */
+int hack_apply_magic_power = 0;
+void apply_magic(object_type *o_ptr, int lev, bool_ okay, bool_ good, bool_ great)
+{
+ int i, rolls, f1, f2, power;
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Aply luck */
+ lev += luck( -7, 7);
+
+ /* Spell in it ? no ! */
+ if (k_ptr->flags5 & TR5_SPELL_CONTAIN)
+ o_ptr->pval2 = -1;
+
+ /* Important to do before all else, be sure to have the basic obvious flags set */
+ o_ptr->art_oflags1 = k_ptr->oflags1;
+ o_ptr->art_oflags2 = k_ptr->oflags2;
+ o_ptr->art_oflags3 = k_ptr->oflags3;
+ o_ptr->art_oflags4 = k_ptr->oflags4;
+ o_ptr->art_oflags5 = k_ptr->oflags5;
+ o_ptr->art_oesp = k_ptr->oesp;
+
+ /* No need to touch normal artifacts */
+ if (k_ptr->flags3 & TR3_NORM_ART)
+ {
+ /* Ahah! we tried to trick us !! */
+ if (k_ptr->artifact ||
+ ((k_ptr->flags4 & TR4_SPECIAL_GENE) &&
+ (!k_allow_special[o_ptr->k_idx])))
+ {
+ object_prep(o_ptr, lookup_kind(k_ptr->btval, k_ptr->bsval));
+ if (wizard) msg_print("We've been tricked!");
+ }
+ else
+ {
+ /* Arg I hate so much to do that ... but I see no other way */
+ if ((o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_STAFF))
+ {
+ s32b base_lvl, max_lvl;
+
+ /* Is the spell predefined by the object kind? */
+ if (k_ptr->pval == -1)
+ {
+ o_ptr->pval2 = k_ptr->pval2;
+ }
+
+ /* Determine a base and a max level */
+ call_lua("get_stick_base_level", "(d,d,d)", "d", o_ptr->tval, dun_level, o_ptr->pval2, &base_lvl);
+ call_lua("get_stick_max_level", "(d,d,d)", "d", o_ptr->tval, dun_level, o_ptr->pval2, &max_lvl);
+ o_ptr->pval3 = (max_lvl << 16) + (base_lvl & 0xFFFF);
+
+ /* Hack -- charge wands */
+ charge_stick(o_ptr);
+ }
+
+ k_ptr->artifact = TRUE;
+
+ if (cheat_peek || p_ptr->precognition) object_mention(o_ptr);
+ }
+
+ return;
+ }
+
+ /* Maximum "level" for various things */
+ if (lev > MAX_DEPTH - 1) lev = MAX_DEPTH - 1;
+
+
+ /* Base chance of being "good" */
+ f1 = lev + 10 + luck( -15, 15);
+
+ /* Maximal chance of being "good" */
+ if (f1 > 75) f1 = 75;
+
+ /* Base chance of being "great" */
+ f2 = f1 / 2;
+
+ /* Maximal chance of being "great" */
+ if (f2 > 20) f2 = 20;
+
+
+ /* Assume normal */
+ power = 0;
+
+ /* Roll for "good" */
+ if (good || magik(f1))
+ {
+ /* Assume "good" */
+ power = 1;
+
+ /* Roll for "great" */
+ if (great || magik(f2)) power = 2;
+ }
+
+ /* Roll for "cursed" */
+ else if (magik(f1))
+ {
+ /* Assume "cursed" */
+ power = -1;
+
+ /* Roll for "broken" */
+ if (magik(f2)) power = -2;
+ }
+
+ /* Mega hack */
+ if (hack_apply_magic_power)
+ {
+ if (hack_apply_magic_power == -99)
+ power = 0;
+ else
+ power = hack_apply_magic_power;
+ }
+ hack_apply_magic_power = 0;
+
+ /* Assume no rolls */
+ rolls = 0;
+
+ /* Get one roll if excellent */
+ if (power >= 2) rolls = 1;
+
+ /* Hack -- Get four rolls if forced great */
+ if (great) rolls = 4;
+
+ /* Hack -- Get no rolls if not allowed */
+ if (!okay || o_ptr->name1) rolls = 0;
+
+ /* Roll for artifacts if allowed */
+ for (i = 0; i < rolls; i++)
+ {
+ /* Roll for an artifact */
+ if (make_artifact(o_ptr)) break;
+ }
+
+ /* Mega hack -- to lazy to do it properly with hooks :) */
+ if ((o_ptr->name1 == ART_POWER) && (quest[QUEST_ONE].status < QUEST_STATUS_TAKEN))
+ {
+ o_ptr->name1 = 0;
+ o_ptr->name2 = 0;
+ o_ptr->name2b = 0;
+ object_prep(o_ptr, lookup_kind(TV_RING, SV_RING_INVIS));
+ }
+
+
+ /* Hack -- analyze artifacts */
+ if (o_ptr->name1)
+ {
+ artifact_type *a_ptr = &a_info[o_ptr->name1];
+
+ /* Hack -- Mark the artifact as "created" */
+ a_ptr->cur_num = 1;
+
+ /* Extract the other fields */
+ o_ptr->pval = a_ptr->pval;
+ o_ptr->ac = a_ptr->ac;
+ o_ptr->dd = a_ptr->dd;
+ o_ptr->ds = a_ptr->ds;
+ o_ptr->to_a = a_ptr->to_a;
+ o_ptr->to_h = a_ptr->to_h;
+ o_ptr->to_d = a_ptr->to_d;
+ o_ptr->weight = a_ptr->weight;
+ o_ptr->number = 1;
+
+ /* Hack -- extract the "cursed" flag */
+ if (a_ptr->flags3 & (TR3_CURSED)) o_ptr->ident |= (IDENT_CURSED);
+
+ /* Mega-Hack -- increase the rating */
+ rating += 10;
+
+ /* Mega-Hack -- increase the rating again */
+ if (a_ptr->cost > 50000L) rating += 10;
+
+ /* Set the good item flag */
+ good_item_flag = TRUE;
+
+ /* Cheat -- peek at the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+
+ /* Spell in it ? no ! */
+ if (a_ptr->flags5 & TR5_SPELL_CONTAIN)
+ o_ptr->pval2 = -1;
+
+ /* Give a basic exp/exp level to an artifact that needs it */
+ if (a_ptr->flags4 & TR4_LEVELS)
+ {
+ o_ptr->elevel = (k_ptr->level / 10) + 1;
+ o_ptr->exp = player_exp[o_ptr->elevel - 1];
+ }
+
+ /* Done */
+ return;
+ }
+
+
+ /* Apply magic */
+ switch (o_ptr->tval)
+ {
+ case TV_RANDART:
+ {
+ finalize_randart(o_ptr, lev);
+ break;
+ }
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_MSTAFF:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_BOOMERANG:
+ case TV_BOW:
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+ case TV_TRAPKIT:
+ {
+ if (power) a_m_aux_1(o_ptr, lev, power);
+ break;
+ }
+
+ case TV_DAEMON_BOOK:
+ {
+ /* UGLY, but needed, depending of sval teh demon stuff are eitehr weapon or armor */
+ if (o_ptr->sval == SV_DEMONBLADE)
+ {
+ if (power) a_m_aux_1(o_ptr, lev, power);
+ }
+ else
+ {
+ if (power) a_m_aux_2(o_ptr, lev, power);
+ }
+ break;
+ }
+
+ case TV_DRAG_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_SOFT_ARMOR:
+ case TV_SHIELD:
+ case TV_HELM:
+ case TV_CROWN:
+ case TV_CLOAK:
+ case TV_GLOVES:
+ case TV_BOOTS:
+ {
+ a_m_aux_2(o_ptr, lev, power);
+ break;
+ }
+
+ case TV_RING:
+ case TV_AMULET:
+ {
+ if (!power && (rand_int(100) < 50)) power = -1;
+ a_m_aux_3(o_ptr, lev, power);
+ break;
+ }
+
+ default:
+ {
+ a_m_aux_4(o_ptr, lev, power);
+ break;
+ }
+ }
+
+ if (o_ptr->art_name) rating += 40;
+
+ /* Hack -- analyze ego-items */
+ else if (o_ptr->name2)
+ {
+ ego_item_type *e_ptr;
+ int j;
+ bool_ limit_blows = FALSE;
+ u32b f1, f2, f3, f4, f5, esp;
+ s16b e_idx;
+
+ e_idx = o_ptr->name2;
+
+ /* Ok now, THAT is truly ugly */
+try_an_other_ego:
+ e_ptr = &e_info[e_idx];
+
+ /* Hack -- extra powers */
+ for (j = 0; j < 5; j++)
+ {
+ /* Rarity check */
+ if (magik(e_ptr->rar[j]))
+ {
+ o_ptr->art_flags1 |= e_ptr->flags1[j];
+ o_ptr->art_flags2 |= e_ptr->flags2[j];
+ o_ptr->art_flags3 |= e_ptr->flags3[j];
+ o_ptr->art_flags4 |= e_ptr->flags4[j];
+ o_ptr->art_flags5 |= e_ptr->flags5[j];
+ o_ptr->art_esp |= e_ptr->esp[j];
+
+ o_ptr->art_oflags1 |= e_ptr->oflags1[j];
+ o_ptr->art_oflags2 |= e_ptr->oflags2[j];
+ o_ptr->art_oflags3 |= e_ptr->oflags3[j];
+ o_ptr->art_oflags4 |= e_ptr->oflags4[j];
+ o_ptr->art_oflags5 |= e_ptr->oflags5[j];
+ o_ptr->art_oesp |= e_ptr->oesp[j];
+
+ add_random_ego_flag(o_ptr, e_ptr->fego[j], &limit_blows);
+ }
+ }
+
+ /* No insane number of blows */
+ if (limit_blows && (o_ptr->art_flags1 & TR1_BLOWS))
+ {
+ if (o_ptr->pval > 2) o_ptr->pval = randint(2);
+ }
+
+ /* get flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hack -- acquire "cursed" flag */
+ if (f3 & TR3_CURSED) o_ptr->ident |= (IDENT_CURSED);
+
+ /* Hack -- obtain bonuses */
+ if (e_ptr->max_to_h > 0) o_ptr->to_h += randint(e_ptr->max_to_h);
+ if (e_ptr->max_to_h < 0) o_ptr->to_h -= randint( -e_ptr->max_to_h);
+ if (e_ptr->max_to_d > 0) o_ptr->to_d += randint(e_ptr->max_to_d);
+ if (e_ptr->max_to_d < 0) o_ptr->to_d -= randint( -e_ptr->max_to_d);
+ if (e_ptr->max_to_a > 0) o_ptr->to_a += randint(e_ptr->max_to_a);
+ if (e_ptr->max_to_a < 0) o_ptr->to_a -= randint( -e_ptr->max_to_a);
+
+ /* Hack -- obtain pval */
+ if (e_ptr->max_pval > 0) o_ptr->pval += randint(e_ptr->max_pval);
+ if (e_ptr->max_pval < 0) o_ptr->pval -= randint( -e_ptr->max_pval);
+
+ /* Hack -- apply rating bonus */
+ rating += e_ptr->rating;
+
+ if (o_ptr->name2b && (o_ptr->name2b != e_idx))
+ {
+ e_idx = o_ptr->name2b;
+ goto try_an_other_ego;
+ }
+
+ /* Spell in it ? no ! */
+ if (f5 & TR5_SPELL_CONTAIN)
+ {
+ /* Mega hack, mage staves of spell cannot SPELL_CONTAIN */
+ if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL))
+ {
+ o_ptr->art_flags5 &= ~TR5_SPELL_CONTAIN;
+ }
+ else
+ o_ptr->pval2 = -1;
+ }
+
+ /* Cheat -- describe the item */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr);
+ }
+
+
+ /* Examine real objects */
+ if (o_ptr->k_idx)
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_kind *k_ptr = &k_info[o_ptr->k_idx];
+
+ /* Hack -- acquire "cursed" flag */
+ if (k_ptr->flags3 & (TR3_CURSED)) o_ptr->ident |= (IDENT_CURSED);
+
+ /* Extract some flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hack give a basic exp/exp level to an object that needs it */
+ if (f4 & TR4_LEVELS)
+ {
+ o_ptr->elevel = (k_ptr->level / 10) + 1;
+ o_ptr->exp = player_exp[o_ptr->elevel - 1];
+ }
+
+ /* Spell in it ? no ! */
+ if (f5 & TR5_SPELL_CONTAIN)
+ {
+ /* Mega hack, mage staves of spell cannot SPELL_CONTAIN */
+ if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL))
+ {
+ o_ptr->art_flags5 &= ~TR5_SPELL_CONTAIN;
+ }
+ else
+ o_ptr->pval2 = -1;
+ }
+
+ /* Hacccccccckkkkk attack ! :) -- To prevent som ugly crashs */
+ if ((o_ptr->tval == TV_MSTAFF) && (o_ptr->sval == SV_MSTAFF) && (o_ptr->pval < 0))
+ {
+ o_ptr->pval = 0;
+ }
+
+ /* Hack, cant be done in a_m_aux4 because the ego flags are not yet in place */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ /* Set the max mana and the current mana */
+ o_ptr->pval2 = (f4 & TR4_CAPACITY) ? o_ptr->sval * 2 : o_ptr->sval;
+
+ o_ptr->timeout = o_ptr->pval2;
+ }
+
+ /* Remove some unnecessary stuff hack */
+ if (o_ptr->tval == TV_TRAPKIT) trap_hack(o_ptr);
+ }
+}
+
+
+/* The themed objects to use */
+static obj_theme match_theme;
+
+/*
+ * XXX XXX XXX It relies on the fact that obj_theme is a four byte structure
+ * for its efficient operation. A horrendous hack, I'd say.
+ */
+void init_match_theme(obj_theme theme)
+{
+ /* Save the theme */
+ match_theme = theme;
+}
+
+/*
+ * Ditto XXX XXX XXX
+ */
+static bool_ theme_changed(obj_theme theme)
+{
+ /* Any of the themes has been changed */
+ if (theme.treasure != match_theme.treasure) return (TRUE);
+ if (theme.combat != match_theme.combat) return (TRUE);
+ if (theme.magic != match_theme.magic) return (TRUE);
+ if (theme.tools != match_theme.tools) return (TRUE);
+
+ /* No changes */
+ return (FALSE);
+}
+
+
+/*
+ * Maga-Hack -- match certain types of object only.
+ */
+bool_ kind_is_theme(int k_idx)
+{
+ object_kind *k_ptr = &k_info[k_idx];
+
+ s32b prob = 0;
+
+
+ /*
+ * Paranoia -- Prevent accidental "(Nothing)"
+ * that are results of uninitialised theme structs.
+ *
+ * Caution: Junks go into the allocation table.
+ */
+ if (match_theme.treasure + match_theme.combat +
+ match_theme.magic + match_theme.tools == 0) return (TRUE);
+
+
+ /* Pick probability to use */
+ switch (k_ptr->tval)
+ {
+ case TV_SKELETON:
+ case TV_BOTTLE:
+ case TV_JUNK:
+ case TV_CORPSE:
+ case TV_EGG:
+ {
+ /*
+ * Degree of junk is defined in terms of the other
+ * 4 quantities XXX XXX XXX
+ * The type of prob should be *signed* as well as
+ * larger than theme components, or we would see
+ * unexpected, well, junks.
+ */
+ prob = 100 - (match_theme.treasure + match_theme.combat +
+ match_theme.magic + match_theme.tools);
+ break;
+ }
+ case TV_CHEST:
+ prob = match_theme.treasure;
+ break;
+ case TV_CROWN:
+ prob = match_theme.treasure;
+ break;
+ case TV_DRAG_ARMOR:
+ prob = match_theme.treasure;
+ break;
+ case TV_AMULET:
+ prob = match_theme.treasure;
+ break;
+ case TV_RING:
+ prob = match_theme.treasure;
+ break;
+
+ case TV_SHOT:
+ prob = match_theme.combat;
+ break;
+ case TV_ARROW:
+ prob = match_theme.combat;
+ break;
+ case TV_BOLT:
+ prob = match_theme.combat;
+ break;
+ case TV_BOOMERANG:
+ prob = match_theme.combat;
+ break;
+ case TV_BOW:
+ prob = match_theme.combat;
+ break;
+ case TV_HAFTED:
+ prob = match_theme.combat;
+ break;
+ case TV_POLEARM:
+ prob = match_theme.combat;
+ break;
+ case TV_SWORD:
+ prob = match_theme.combat;
+ break;
+ case TV_AXE:
+ prob = match_theme.combat;
+ break;
+ case TV_GLOVES:
+ prob = match_theme.combat;
+ break;
+ case TV_HELM:
+ prob = match_theme.combat;
+ break;
+ case TV_SHIELD:
+ prob = match_theme.combat;
+ break;
+ case TV_SOFT_ARMOR:
+ prob = match_theme.combat;
+ break;
+ case TV_HARD_ARMOR:
+ prob = match_theme.combat;
+ break;
+
+ case TV_MSTAFF:
+ prob = match_theme.magic;
+ break;
+ case TV_STAFF:
+ prob = match_theme.magic;
+ break;
+ case TV_WAND:
+ prob = match_theme.magic;
+ break;
+ case TV_ROD:
+ prob = match_theme.magic;
+ break;
+ case TV_ROD_MAIN:
+ prob = match_theme.magic;
+ break;
+ case TV_SCROLL:
+ prob = match_theme.magic;
+ break;
+ case TV_PARCHMENT:
+ prob = match_theme.magic;
+ break;
+ case TV_POTION:
+ prob = match_theme.magic;
+ break;
+ case TV_POTION2:
+ prob = match_theme.magic;
+ break;
+ case TV_BATERIE:
+ prob = match_theme.magic;
+ break;
+ case TV_RANDART:
+ prob = match_theme.magic;
+ break;
+ case TV_RUNE1:
+ prob = match_theme.magic;
+ break;
+ case TV_RUNE2:
+ prob = match_theme.magic;
+ break;
+ case TV_BOOK:
+ prob = match_theme.magic;
+ break;
+ case TV_SYMBIOTIC_BOOK:
+ prob = match_theme.magic;
+ break;
+ case TV_MUSIC_BOOK:
+ prob = match_theme.magic;
+ break;
+ case TV_DRUID_BOOK:
+ prob = match_theme.magic;
+ break;
+ case TV_DAEMON_BOOK:
+ prob = match_theme.magic;
+ break;
+
+ case TV_LITE:
+ prob = match_theme.tools;
+ break;
+ case TV_CLOAK:
+ prob = match_theme.tools;
+ break;
+ case TV_BOOTS:
+ prob = match_theme.tools;
+ break;
+ case TV_SPIKE:
+ prob = match_theme.tools;
+ break;
+ case TV_DIGGING:
+ prob = match_theme.tools;
+ break;
+ case TV_FLASK:
+ prob = match_theme.tools;
+ break;
+ case TV_FOOD:
+ prob = match_theme.tools;
+ break;
+ case TV_TOOL:
+ prob = match_theme.tools;
+ break;
+ case TV_INSTRUMENT:
+ prob = match_theme.tools;
+ break;
+ case TV_TRAPKIT:
+ prob = match_theme.tools;
+ break;
+ }
+
+ /* Roll to see if it can be made */
+ if (rand_int(100) < prob) return (TRUE);
+
+ /* Not a match */
+ return (FALSE);
+}
+
+/*
+ * Determine if an object must not be generated.
+ */
+int kind_is_legal_special = -1;
+bool_ kind_is_legal(int k_idx)
+{
+ object_kind *k_ptr = &k_info[k_idx];
+
+ if (!kind_is_theme(k_idx)) return FALSE;
+
+ if (k_ptr->flags4 & TR4_SPECIAL_GENE)
+ {
+ if (k_allow_special[k_idx]) return TRUE;
+ else return FALSE;
+ }
+
+ /* No 2 times the same normal artifact */
+ if ((k_ptr->flags3 & TR3_NORM_ART) && (k_ptr->artifact))
+ {
+ return FALSE;
+ }
+
+ if (k_ptr->tval == TV_CORPSE)
+ {
+ if (k_ptr->sval != SV_CORPSE_SKULL && k_ptr->sval != SV_CORPSE_SKELETON &&
+ k_ptr->sval != SV_CORPSE_HEAD && k_ptr->sval != SV_CORPSE_CORPSE)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ if (k_ptr->tval == TV_HYPNOS) return FALSE;
+
+ /* Used only for the Nazgul rings */
+ if ((k_ptr->tval == TV_RING) && (k_ptr->sval == SV_RING_SPECIAL)) return FALSE;
+
+ /* Are we forced to one tval ? */
+ if ((kind_is_legal_special != -1) && (kind_is_legal_special != k_ptr->tval)) return (FALSE);
+
+ /* Assume legal */
+ return TRUE;
+}
+
+
+/*
+ * Hack -- determine if a template is "good"
+ */
+bool_ kind_is_good(int k_idx)
+{
+ object_kind *k_ptr = &k_info[k_idx];
+
+ if (!kind_is_legal(k_idx)) return FALSE;
+
+ /* Analyze the item type */
+ switch (k_ptr->tval)
+ {
+ /* Armor -- Good unless damaged */
+ case TV_HARD_ARMOR:
+ case TV_SOFT_ARMOR:
+ case TV_DRAG_ARMOR:
+ case TV_SHIELD:
+ case TV_CLOAK:
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_HELM:
+ case TV_CROWN:
+ {
+ if (k_ptr->to_a < 0) return (FALSE);
+ return (TRUE);
+ }
+
+ /* Weapons -- Good unless damaged */
+ case TV_BOW:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_DIGGING:
+ case TV_TRAPKIT:
+ case TV_MSTAFF:
+ case TV_BOOMERANG:
+ {
+ if (k_ptr->to_h < 0) return (FALSE);
+ if (k_ptr->to_d < 0) return (FALSE);
+ return (TRUE);
+ }
+
+ /* Ammo -- Arrows/Bolts are good */
+ case TV_BOLT:
+ case TV_ARROW:
+ {
+ return (TRUE);
+ }
+
+ /* Rods - Silver and better are good */
+ case TV_ROD_MAIN:
+ {
+ if (k_ptr->sval >= SV_ROD_SILVER) return (TRUE);
+ return FALSE;
+ }
+
+ /* Expensive rod tips are good */
+ case TV_ROD:
+ {
+ /* Probing is not good, but Recall is*/
+ if (k_ptr->cost >= 4500) return TRUE;
+ return FALSE;
+ }
+
+ /* The Tomes are good */
+ case TV_BOOK:
+ {
+ if (k_ptr->sval <= SV_BOOK_MAX_GOOD) return (TRUE);
+ return FALSE;
+ }
+
+ /* Rings -- Rings of Speed are good */
+ case TV_RING:
+ {
+ if (k_ptr->sval == SV_RING_SPEED) return (TRUE);
+ return (FALSE);
+ }
+
+ /* Amulets -- Some are good */
+ case TV_AMULET:
+ {
+ if (k_ptr->sval == SV_AMULET_THE_MAGI) return (TRUE);
+ if (k_ptr->sval == SV_AMULET_DEVOTION) return (TRUE);
+ if (k_ptr->sval == SV_AMULET_WEAPONMASTERY) return (TRUE);
+ if (k_ptr->sval == SV_AMULET_TRICKERY) return (TRUE);
+ if (k_ptr->sval == SV_AMULET_RESISTANCE) return (TRUE);
+ if (k_ptr->sval == SV_AMULET_REFLECTION) return (TRUE);
+ if (k_ptr->sval == SV_AMULET_TELEPATHY) return (TRUE);
+ return (FALSE);
+ }
+ }
+
+ /* Assume not good */
+ return (FALSE);
+}
+
+/*
+* Determine if template is suitable for building a randart -- dsb
+*/
+bool_ kind_is_artifactable(int k_idx)
+{
+ int i, j;
+ object_kind *k_ptr = &k_info[k_idx];
+
+ if (kind_is_good(k_idx))
+ {
+ /* We consider the item artifactable if there is at least one
+ * randart power in ra_info that could be added to this item. */
+ for (i = 0; i < max_ra_idx; i++)
+ {
+ randart_part_type *ra_ptr = &ra_info[i];
+
+ for (j = 0; j < 20; j++)
+ {
+ if (ra_ptr->tval[j] != k_ptr->tval) continue;
+ if (ra_ptr->min_sval[j] > k_ptr->sval) continue;
+ if (ra_ptr->max_sval[j] < k_ptr->sval) continue;
+ /* Winner */
+ return TRUE;
+ }
+ }
+ }
+
+ /* No match. Too bad. */
+ return FALSE;
+}
+
+
+/*
+ * Attempt to make an object (normal or good/great)
+ *
+ * This routine plays nasty games to generate the "special artifacts".
+ *
+ * This routine uses "object_level" for the "generation level".
+ *
+ * We assume that the given object has been "wiped".
+ *
+ * To Watch: The allocation table caching is heavily relies on
+ * an assumption that the SPECIAL_GENE objects should only be created
+ * through the forge--object_prep()--apply_magic() sequence and
+ * get_obj_num() should never be called for that purpose XXX XXX XXX
+ */
+bool_ make_object(object_type *j_ptr, bool_ good, bool_ great, obj_theme theme)
+{
+ int invprob, base;
+
+
+ /* Chance of "special object" */
+ invprob = (good ? 10 - luck( -9, 9) : 1000);
+
+ /* Base level for the object */
+ base = (good ? (object_level + 10) : object_level);
+
+
+ /* Generate a special object, or a normal object */
+ if ((rand_int(invprob) != 0) || !make_artifact_special(j_ptr))
+ {
+ int k_idx;
+
+ /* See if the theme has been changed XXX XXX XXX */
+ if (theme_changed(theme))
+ {
+ /* Select items based on "theme" */
+ init_match_theme(theme);
+
+ /* Invalidate the cached allocation table */
+ alloc_kind_table_valid = FALSE;
+ }
+
+ /* Good objects */
+ if (good)
+ {
+ /* Activate restriction */
+ get_obj_num_hook = kind_is_good;
+
+ /* Prepare allocation table */
+ get_obj_num_prep();
+ }
+
+ /* Normal objects -- only when the cache is invalidated */
+ else if (!alloc_kind_table_valid)
+ {
+ /* Activate normal restriction */
+ get_obj_num_hook = kind_is_legal;
+
+ /* Prepare allocation table */
+ get_obj_num_prep();
+
+ /* The table is synchronised */
+ alloc_kind_table_valid = TRUE;
+ }
+
+ /* Pick a random object */
+ k_idx = get_obj_num(base);
+
+ /* Good objects */
+ if (good)
+ {
+ /* Restore normal restriction */
+ get_obj_num_hook = kind_is_legal;
+
+ /* Prepare allocation table */
+ get_obj_num_prep();
+
+ /* The table is synchronised */
+ alloc_kind_table_valid = TRUE;
+ }
+
+ /* Handle failure */
+ if (!k_idx) return (FALSE);
+
+ /* Prepare the object */
+ object_prep(j_ptr, k_idx);
+ }
+
+ /* Apply magic (allow artifacts) */
+ apply_magic(j_ptr, object_level, TRUE, good, great);
+
+ /* Hack -- generate multiple spikes/missiles */
+ switch (j_ptr->tval)
+ {
+ case TV_SPIKE:
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+ {
+ j_ptr->number = (byte)damroll(6, 7);
+ }
+ }
+
+ /* hack, no multiple artifacts */
+ if (artifact_p(j_ptr)) j_ptr->number = 1;
+
+ /* Notice "okay" out-of-depth objects */
+ if (!cursed_p(j_ptr) &&
+ (k_info[j_ptr->k_idx].level > dun_level))
+ {
+ /* Rating increase */
+ rating += (k_info[j_ptr->k_idx].level - dun_level);
+
+ /* Cheat -- peek at items */
+ if ((cheat_peek) || (p_ptr->precognition)) object_mention(j_ptr);
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+
+/*
+ * Attempt to place an object (normal or good/great) at the given location.
+ *
+ * This routine plays nasty games to generate the "special artifacts".
+ *
+ * This routine uses "object_level" for the "generation level".
+ *
+ * This routine requires a clean floor grid destination.
+ */
+void place_object(int y, int x, bool_ good, bool_ great, int where)
+{
+ s16b o_idx;
+
+ cave_type *c_ptr;
+
+ object_type forge;
+ object_type *q_ptr;
+
+
+ /* Paranoia -- check bounds */
+ if (!in_bounds(y, x)) return;
+
+ /* Require clean floor space */
+ if (!cave_clean_bold(y, x)) return;
+
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Make an object (if possible) */
+ if (!make_object(q_ptr, good, great, d_info[dungeon_type].objs)) return;
+
+ if (where == OBJ_FOUND_VAULT)
+ {
+ q_ptr->found = OBJ_FOUND_VAULT;
+ q_ptr->found_aux1 = dungeon_type;
+ q_ptr->found_aux2 = level_or_feat(dungeon_type, dun_level);
+ }
+ else if (where == OBJ_FOUND_FLOOR)
+ {
+ q_ptr->found = OBJ_FOUND_FLOOR;
+ q_ptr->found_aux1 = dungeon_type;
+ q_ptr->found_aux2 = level_or_feat(dungeon_type, dun_level);
+ }
+ else if (where == OBJ_FOUND_SPECIAL)
+ {
+ q_ptr->found = OBJ_FOUND_SPECIAL;
+ }
+ else if (where == OBJ_FOUND_RUBBLE)
+ {
+ q_ptr->found = OBJ_FOUND_RUBBLE;
+ }
+
+ /* Make an object */
+ o_idx = o_pop();
+
+ /* Success */
+ if (o_idx)
+ {
+ object_type *o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[o_idx];
+
+ /* Structure Copy */
+ object_copy(o_ptr, q_ptr);
+
+ /* Location */
+ o_ptr->iy = y;
+ o_ptr->ix = x;
+
+ /* Acquire grid */
+ c_ptr = &cave[y][x];
+
+ /* Build a stack */
+ o_ptr->next_o_idx = c_ptr->o_idx;
+
+ /* Place the object */
+ c_ptr->o_idx = o_idx;
+
+ /* Notice */
+ note_spot(y, x);
+
+ /* Redraw */
+ lite_spot(y, x);
+ }
+
+ /* Object array overflow */
+ else
+ {
+ /* Hack -- Preserve artifacts */
+ if (q_ptr->name1)
+ {
+ a_info[q_ptr->name1].cur_num = 0;
+ }
+ else if (k_info[q_ptr->k_idx].flags3 & TR3_NORM_ART)
+ {
+ k_info[q_ptr->k_idx].artifact = 0;
+ }
+ else if (q_ptr->tval == TV_RANDART)
+ {
+ random_artifacts[q_ptr->sval].generated = FALSE;
+ }
+ }
+}
+
+
+/*
+ * XXX XXX XXX Do not use these hard-coded values.
+ */
+#define OBJ_GOLD_LIST 480 /* First "gold" entry */
+#define MAX_GOLD 18 /* Number of "gold" entries */
+
+/*
+ * Make a treasure object
+ *
+ * The location must be a legal, clean, floor grid.
+ */
+bool_ make_gold(object_type *j_ptr)
+{
+ int i;
+
+ s32b base;
+
+
+ /* Hack -- Pick a Treasure variety */
+ i = ((randint(object_level + 2) + 2) / 2) - 1;
+
+ /* Apply "extra" magic */
+ if (rand_int(GREAT_OBJ) == 0)
+ {
+ i += randint(object_level + 1);
+ }
+
+ /* Hack -- Creeping Coins only generate "themselves" */
+ if (coin_type) i = coin_type;
+
+ /* Do not create "illegal" Treasure Types */
+ if (i >= MAX_GOLD) i = MAX_GOLD - 1;
+
+ /* Prepare a gold object */
+ object_prep(j_ptr, OBJ_GOLD_LIST + i);
+
+ /* Hack -- Base coin cost */
+ base = k_info[OBJ_GOLD_LIST + i].cost;
+
+ /* Determine how much the treasure is "worth" */
+ j_ptr->pval = (base + (8L * randint(base)) + randint(8));
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Places a treasure (Gold or Gems) at given location
+ *
+ * The location must be a legal, clean, floor grid.
+ */
+void place_gold(int y, int x)
+{
+ s16b o_idx;
+
+ cave_type *c_ptr;
+
+ object_type forge;
+ object_type *q_ptr;
+
+
+ /* Paranoia -- check bounds */
+ if (!in_bounds(y, x)) return;
+
+ /* Require clean floor space */
+ if (!cave_clean_bold(y, x)) return;
+
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Make some gold */
+ if (!make_gold(q_ptr)) return;
+
+
+ /* Make an object */
+ o_idx = o_pop();
+
+ /* Success */
+ if (o_idx)
+ {
+ object_type *o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[o_idx];
+
+ /* Copy the object */
+ object_copy(o_ptr, q_ptr);
+
+ /* Save location */
+ o_ptr->iy = y;
+ o_ptr->ix = x;
+
+ /* Acquire grid */
+ c_ptr = &cave[y][x];
+
+ /* Build a stack */
+ o_ptr->next_o_idx = c_ptr->o_idx;
+
+ /* Place the object */
+ c_ptr->o_idx = o_idx;
+
+ /* Notice */
+ note_spot(y, x);
+
+ /* Redraw */
+ lite_spot(y, x);
+ }
+}
+
+
+/*
+ * Let an object fall to the ground at or near a location.
+ *
+ * The initial location is assumed to be "in_bounds()".
+ *
+ * This function takes a parameter "chance". This is the percentage
+ * chance that the item will "disappear" instead of drop. If the object
+ * has been thrown, then this is the chance of disappearance on contact.
+ *
+ * Hack -- this function uses "chance" to determine if it should produce
+ * some form of "description" of the drop event (under the player).
+ *
+ * We check several locations to see if we can find a location at which
+ * the object can combine, stack, or be placed. Artifacts will try very
+ * hard to be placed, including "teleporting" to a useful grid if needed.
+ */
+s16b drop_near(object_type *j_ptr, int chance, int y, int x)
+{
+ int i, k, d, s;
+
+ int bs, bn;
+ int by, bx;
+ int dy, dx;
+ int ty, tx;
+
+ s16b o_idx = 0;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ cave_type *c_ptr;
+
+ char o_name[80];
+
+ bool_ flag = FALSE;
+ bool_ done = FALSE;
+
+ bool_ plural = FALSE;
+
+
+ /* Extract plural */
+ if (j_ptr->number != 1) plural = TRUE;
+
+ /* Describe object */
+ object_desc(o_name, j_ptr, FALSE, 0);
+
+
+ /* Handle normal "breakage" */
+ if (!(j_ptr->art_name || artifact_p(j_ptr)) && (rand_int(100) < chance))
+ {
+ /* Message */
+ msg_format("The %s disappear%s.",
+ o_name, (plural ? "" : "s"));
+
+ /* Debug */
+ if (wizard) msg_print("(breakage)");
+
+ /* Failure */
+ return (0);
+ }
+
+
+ /* Score */
+ bs = -1;
+
+ /* Picker */
+ bn = 0;
+
+ /* Default */
+ by = y;
+ bx = x;
+
+ /* Scan local grids */
+ for (dy = -3; dy <= 3; dy++)
+ {
+ /* Scan local grids */
+ for (dx = -3; dx <= 3; dx++)
+ {
+ bool_ comb = FALSE;
+
+ /* Calculate actual distance */
+ d = (dy * dy) + (dx * dx);
+
+ /* Ignore distant grids */
+ if (d > 10) continue;
+
+ /* Location */
+ ty = y + dy;
+ tx = x + dx;
+
+ /* Skip illegal grids */
+ if (!in_bounds(ty, tx)) continue;
+
+ /* Require line of sight */
+ if (!los(y, x, ty, tx)) continue;
+
+ /* Obtain grid */
+ c_ptr = &cave[ty][tx];
+
+ /* Require floor space (or shallow terrain) -KMW- */
+ if (!(f_info[c_ptr->feat].flags1 & FF1_FLOOR)) continue;
+
+ /* No traps */
+ if (c_ptr->t_idx) continue;
+
+ /* No objects */
+ k = 0;
+
+ /* Scan objects in that grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Check for possible combination */
+ if (object_similar(o_ptr, j_ptr)) comb = TRUE;
+
+ /* Count objects */
+ k++;
+ }
+
+ /* Add new object */
+ if (!comb) k++;
+
+ /* No stacking (allow combining) */
+ if (!testing_stack && (k > 1)) continue;
+
+ /* Paranoia */
+ if (k > 23) continue;
+
+ /* Calculate score */
+ s = 1000 - (d + k * 5);
+
+ /* Skip bad values */
+ if (s < bs) continue;
+
+ /* New best value */
+ if (s > bs) bn = 0;
+
+ /* Apply the randomizer to equivalent values */
+ if ((++bn >= 2) && (rand_int(bn) != 0)) continue;
+
+ /* Keep score */
+ bs = s;
+
+ /* Track it */
+ by = ty;
+ bx = tx;
+
+ /* Okay */
+ flag = TRUE;
+ }
+ }
+
+
+ /* Handle lack of space */
+ if (!flag && !(artifact_p(j_ptr) || j_ptr->art_name))
+ {
+ /* Message */
+ msg_format("The %s disappear%s.",
+ o_name, (plural ? "" : "s"));
+
+ /* Debug */
+ if (wizard) msg_print("(no floor space)");
+
+ /* Failure */
+ return (0);
+ }
+
+
+ /* Find a grid */
+ for (i = 0; !flag; i++)
+ {
+ /* Bounce around */
+ if (i < 1000)
+ {
+ ty = rand_spread(by, 1);
+ tx = rand_spread(bx, 1);
+ }
+
+ /* Random locations */
+ else
+ {
+ ty = rand_int(cur_hgt);
+ tx = rand_int(cur_wid);
+ }
+
+ /* Grid */
+ c_ptr = &cave[ty][tx];
+
+ /* Require floor space (or shallow terrain) -KMW- */
+ if ((c_ptr->feat != FEAT_FLOOR) &&
+ (c_ptr->feat != FEAT_SHAL_WATER) &&
+ (c_ptr->feat != FEAT_GRASS) &&
+ (c_ptr->feat != FEAT_DIRT) &&
+ (c_ptr->feat != FEAT_SHAL_LAVA)) continue;
+
+ /* Bounce to that location */
+ by = ty;
+ bx = tx;
+
+ /* Require floor space */
+ if (!cave_clean_bold(by, bx)) continue;
+
+ /* Okay */
+ flag = TRUE;
+ }
+
+
+ /* Grid */
+ c_ptr = &cave[by][bx];
+
+ /* Scan objects in that grid for combination */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Check for combination */
+ if (object_similar(o_ptr, j_ptr))
+ {
+ /* Combine the items */
+ object_absorb(o_ptr, j_ptr);
+
+ /* Success */
+ done = TRUE;
+
+ /* Done */
+ break;
+ }
+ }
+
+ /* Get new object */
+ if (!done) o_idx = o_pop();
+
+ /* Failure */
+ if (!done && !o_idx)
+ {
+ /* Message */
+ msg_format("The %s disappear%s.",
+ o_name, (plural ? "" : "s"));
+
+ /* Debug */
+ if (wizard) msg_print("(too many objects)");
+
+ /* Hack -- Preserve artifacts */
+ if (j_ptr->name1)
+ {
+ a_info[j_ptr->name1].cur_num = 0;
+ }
+ else if (k_info[j_ptr->k_idx].flags3 & TR3_NORM_ART)
+ {
+ k_info[j_ptr->k_idx].artifact = 0;
+ }
+ else if (j_ptr->tval == TV_RANDART)
+ {
+ random_artifacts[j_ptr->sval].generated = FALSE;
+ }
+
+ /* Failure */
+ return (0);
+ }
+
+ /* Stack */
+ if (!done)
+ {
+ /* Structure copy */
+ object_copy(&o_list[o_idx], j_ptr);
+
+ /* Access new object */
+ j_ptr = &o_list[o_idx];
+
+ /* Locate */
+ j_ptr->iy = by;
+ j_ptr->ix = bx;
+
+ /* No monster */
+ j_ptr->held_m_idx = 0;
+
+ /* Build a stack */
+ j_ptr->next_o_idx = c_ptr->o_idx;
+
+ /* Place the object */
+ c_ptr->o_idx = o_idx;
+
+ /* Success */
+ done = TRUE;
+ }
+
+ /* Note the spot */
+ note_spot(by, bx);
+
+ /* Draw the spot */
+ lite_spot(by, bx);
+
+ /* Mega-Hack -- no message if "dropped" by player */
+ /* Message when an object falls under the player */
+ if (chance && (by == p_ptr->py) && (bx == p_ptr->px))
+ {
+ msg_print("You feel something roll beneath your feet.");
+ /* Sound */
+ sound(SOUND_DROP);
+ }
+
+ /* XXX XXX XXX */
+
+ /* Result */
+ return (o_idx);
+}
+
+
+
+
+/*
+ * Scatter some "great" objects near the player
+ */
+void acquirement(int y1, int x1, int num, bool_ great, bool_ known)
+{
+ object_type *i_ptr;
+ object_type object_type_body;
+
+ /* Acquirement */
+ while (num--)
+ {
+ /* Get local object */
+ i_ptr = &object_type_body;
+
+ /* Wipe the object */
+ object_wipe(i_ptr);
+
+ /* Make a good (or great) object (if possible) */
+ if (!make_object(i_ptr, TRUE, great, d_info[dungeon_type].objs)) continue;
+
+ if (known)
+ {
+ object_aware(i_ptr);
+ object_known(i_ptr);
+ }
+
+ /* Drop the object */
+ drop_near(i_ptr, -1, y1, x1);
+ }
+}
+
+
+
+/*
+ * Hack -- instantiate a trap
+ *
+ * XXX XXX XXX This routine should be redone to reflect trap "level".
+ * That is, it does not make sense to have spiked pits at 50 feet.
+ * Actually, it is not this routine, but the "trap instantiation"
+ * code, which should also check for "trap doors" on quest levels.
+ */
+void pick_trap(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Paranoia */
+ if ((c_ptr->t_idx == 0) || (c_ptr->info & CAVE_TRDT)) return;
+
+ /* Activate the trap */
+ c_ptr->info |= (CAVE_TRDT);
+
+ /* Notice and redraw */
+ note_spot(y, x);
+ lite_spot(y, x);
+}
+
+/*
+ * Describe the charges on an item in the inventory.
+ */
+void inven_item_charges(int item)
+{
+ object_type *o_ptr = &p_ptr->inventory[item];
+
+ /* Require staff/wand */
+ if ((o_ptr->tval != TV_STAFF) && (o_ptr->tval != TV_WAND)) return;
+
+ /* Require known item */
+ if (!object_known_p(o_ptr)) return;
+
+ /* Multiple charges */
+ if (o_ptr->pval != 1)
+ {
+ /* Print a message */
+ msg_format("You have %d charges remaining.", o_ptr->pval);
+ }
+
+ /* Single charge */
+ else
+ {
+ /* Print a message */
+ msg_format("You have %d charge remaining.", o_ptr->pval);
+ }
+}
+
+
+/*
+ * Describe an item in the inventory.
+ */
+void inven_item_describe(int item)
+{
+ object_type *o_ptr = &p_ptr->inventory[item];
+ char o_name[80];
+
+ /* Get a description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Print a message */
+ msg_format("You have %s.", o_name);
+}
+
+
+/*
+ * Increase the "number" of an item in the inventory
+ */
+void inven_item_increase(int item, int num)
+{
+ object_type *o_ptr = &p_ptr->inventory[item];
+
+ /* Apply */
+ num += o_ptr->number;
+
+ /* Bounds check */
+ if (num > 255) num = 255;
+ else if (num < 0) num = 0;
+
+ /* Un-apply */
+ num -= o_ptr->number;
+
+ /* Change the number and weight */
+ if (num)
+ {
+ /* Add the number */
+ o_ptr->number += num;
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Recalculate mana XXX */
+ p_ptr->update |= (PU_MANA);
+
+ /* Combine the pack */
+ p_ptr->notice |= (PN_COMBINE);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+ }
+}
+
+
+/*
+ * Erase an inventory slot if it has no more items
+ */
+bool_ inven_item_optimize(int item)
+{
+ object_type *o_ptr = &p_ptr->inventory[item];
+
+ /* Only optimize real items */
+ if (!o_ptr->k_idx) return (FALSE);
+
+ /* Only optimize empty items */
+ if (o_ptr->number) return (FALSE);
+
+ /* The item is in the pack */
+ if (item < INVEN_WIELD)
+ {
+ int i;
+
+ /* One less item */
+ inven_cnt--;
+
+ /* Slide everything down */
+ for (i = item; i < INVEN_PACK; i++)
+ {
+ /* Structure copy */
+ p_ptr->inventory[i] = p_ptr->inventory[i + 1];
+ }
+
+ /* Erase the "final" slot */
+ object_wipe(&p_ptr->inventory[i]);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+ }
+
+ /* The item is being wielded */
+ else
+ {
+ /* One less item */
+ equip_cnt--;
+
+ /* Take care of item sets*/
+ if (o_ptr->name1)
+ {
+ takeoff_set(p_ptr->inventory[item].name1, a_info[p_ptr->inventory[item].name1].set);
+ }
+
+ /* Erase the empty slot */
+ object_wipe(&p_ptr->inventory[item]);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Recalculate torch */
+ p_ptr->update |= (PU_TORCH);
+
+ /* Recalculate mana XXX */
+ p_ptr->update |= (PU_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP);
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * Describe the charges on an item on the floor.
+ */
+void floor_item_charges(int item)
+{
+ object_type *o_ptr = &o_list[item];
+
+ /* Require staff/wand */
+ if ((o_ptr->tval != TV_STAFF) && (o_ptr->tval != TV_WAND)) return;
+
+ /* Require known item */
+ if (!object_known_p(o_ptr)) return;
+
+ /* Multiple charges */
+ if (o_ptr->pval != 1)
+ {
+ /* Print a message */
+ msg_format("There are %d charges remaining.", o_ptr->pval);
+ }
+
+ /* Single charge */
+ else
+ {
+ /* Print a message */
+ msg_format("There is %d charge remaining.", o_ptr->pval);
+ }
+}
+
+
+
+/*
+ * Describe an item in the inventory.
+ */
+void floor_item_describe(int item)
+{
+ object_type *o_ptr = &o_list[item];
+ char o_name[80];
+
+ /* Get a description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Print a message */
+ msg_format("You see %s.", o_name);
+}
+
+
+/*
+ * Increase the "number" of an item on the floor
+ */
+void floor_item_increase(int item, int num)
+{
+ object_type *o_ptr = &o_list[item];
+
+ /* Apply */
+ num += o_ptr->number;
+
+ /* Bounds check */
+ if (num > 255) num = 255;
+ else if (num < 0) num = 0;
+
+ /* Un-apply */
+ num -= o_ptr->number;
+
+ /* Change the number */
+ o_ptr->number += num;
+}
+
+
+/*
+ * Optimize an item on the floor (destroy "empty" items)
+ */
+void floor_item_optimize(int item)
+{
+ object_type *o_ptr = &o_list[item];
+
+ /* Paranoia -- be sure it exists */
+ if (!o_ptr->k_idx) return;
+
+ /* Only optimize empty items */
+ if (o_ptr->number) return;
+
+ /* Delete the object */
+ delete_object_idx(item);
+}
+
+
+/*
+ * Increase stack size for item, describe and optimize.
+ */
+void inc_stack_size(int item, int delta) {
+ inc_stack_size_ex(item, delta, OPTIMIZE, DESCRIBE);
+}
+
+/*
+ * Increase stack size for item.
+ */
+void inc_stack_size_ex(int item, int delta, optimize_flag opt, describe_flag desc) {
+ /* Pack item? */
+ if (item >= 0)
+ {
+ inven_item_increase(item, delta);
+ if (desc == DESCRIBE)
+ {
+ inven_item_describe(item);
+ }
+ if (opt == OPTIMIZE)
+ {
+ inven_item_optimize(item);
+ }
+ }
+
+ /* Floor item? */
+ else
+ {
+ floor_item_increase(0 - item, delta);
+ if (desc == DESCRIBE)
+ {
+ floor_item_describe(0 - item);
+ }
+ if (opt == OPTIMIZE)
+ {
+ floor_item_optimize(0 - item);
+ }
+ }
+}
+
+
+
+/*
+ * Check if we have space for an item in the pack without overflow
+ */
+bool_ inven_carry_okay(object_type *o_ptr)
+{
+ int j;
+
+ if (o_ptr->tval == TV_GOLD) return FALSE;
+
+ /* Empty slot? */
+ if (inven_cnt < INVEN_PACK) return (TRUE);
+
+ /* Similar slot? */
+ for (j = 0; j < INVEN_PACK; j++)
+ {
+ object_type *j_ptr = &p_ptr->inventory[j];
+
+ /* Skip non-objects */
+ if (!j_ptr->k_idx) continue;
+
+ /* Check if the two items can be combined */
+ if (object_similar(j_ptr, o_ptr)) return (TRUE);
+ }
+
+ /* Nope */
+ return (FALSE);
+}
+
+
+/*
+ * Add an item to the players inventory, and return the slot used.
+ *
+ * If the new item can combine with an existing item in the inventory,
+ * it will do so, using "object_similar()" and "object_absorb()", otherwise,
+ * the item will be placed into the "proper" location in the inventory.
+ *
+ * This function can be used to "over-fill" the player's pack, but only
+ * once, and such an action must trigger the "overflow" code immediately.
+ * Note that when the pack is being "over-filled", the new item must be
+ * placed into the "overflow" slot, and the "overflow" must take place
+ * before the pack is reordered, but (optionally) after the pack is
+ * combined. This may be tricky. See "dungeon.c" for info.
+ *
+ * Note that this code must remove any location/stack information
+ * from the object once it is placed into the inventory.
+ *
+ * The "final" flag tells this function to bypass the "combine"
+ * and "reorder" code until later.
+ */
+s16b inven_carry(object_type *o_ptr, bool_ final)
+{
+ int i, j, k;
+ int n = -1;
+ object_type *j_ptr;
+
+ /* Not final */
+ if (!final)
+ {
+ /* Check for combining */
+ for (j = 0; j < INVEN_PACK; j++)
+ {
+ j_ptr = &p_ptr->inventory[j];
+
+ /* Skip non-objects */
+ if (!j_ptr->k_idx) continue;
+
+ /* Hack -- track last item */
+ n = j;
+
+ /* Check if the two items can be combined */
+ if (object_similar(j_ptr, o_ptr))
+ {
+ /* Combine the items */
+ object_absorb(j_ptr, o_ptr);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+
+ /* Success */
+ return (j);
+ }
+ }
+ }
+
+
+ /* Paranoia */
+ if (inven_cnt > INVEN_PACK) return ( -1);
+
+
+ /* Find an empty slot */
+ for (j = 0; j <= INVEN_PACK; j++)
+ {
+ j_ptr = &p_ptr->inventory[j];
+
+ /* Use it if found */
+ if (!j_ptr->k_idx) break;
+ }
+
+ /* Use that slot */
+ i = j;
+
+
+ /* Hack -- pre-reorder the pack */
+ if (!final && (i < INVEN_PACK))
+ {
+ s32b o_value, j_value;
+
+ /* Get the "value" of the item */
+ o_value = object_value(o_ptr);
+
+ /* Scan every occupied slot */
+ for (j = 0; j < INVEN_PACK; j++)
+ {
+ j_ptr = &p_ptr->inventory[j];
+
+ /* Use empty slots */
+ if (!j_ptr->k_idx) break;
+
+ /* Objects sort by decreasing type */
+ if (o_ptr->tval > j_ptr->tval) break;
+ if (o_ptr->tval < j_ptr->tval) continue;
+
+ /* Non-aware (flavored) items always come last */
+ if (!object_aware_p(o_ptr)) continue;
+ if (!object_aware_p(j_ptr)) break;
+
+ /* Objects sort by increasing sval */
+ if (o_ptr->sval < j_ptr->sval) break;
+ if (o_ptr->sval > j_ptr->sval) continue;
+
+ /* Unidentified objects always come last */
+ if (!object_known_p(o_ptr)) continue;
+ if (!object_known_p(j_ptr)) break;
+
+ /* Hack: otherwise identical rods sort by
+ increasing recharge time --dsb */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ if (o_ptr->timeout > j_ptr->timeout) break;
+ if (o_ptr->timeout < j_ptr->timeout) continue;
+ }
+
+ /* Determine the "value" of the pack item */
+ j_value = object_value(j_ptr);
+
+ /* Objects sort by decreasing value */
+ if (o_value > j_value) break;
+ if (o_value < j_value) continue;
+ }
+
+ /* Use that slot */
+ i = j;
+
+ /* Slide objects */
+ for (k = n; k >= i; k--)
+ {
+ /* Hack -- Slide the item */
+ object_copy(&p_ptr->inventory[k + 1], &p_ptr->inventory[k]);
+ }
+
+ /* Wipe the empty slot */
+ object_wipe(&p_ptr->inventory[i]);
+ }
+
+
+ /* Acquire a copy of the item */
+ object_copy(&p_ptr->inventory[i], o_ptr);
+
+ /* Access new object */
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Clean out unused fields */
+ o_ptr->iy = o_ptr->ix = 0;
+ o_ptr->next_o_idx = 0;
+ o_ptr->held_m_idx = 0;
+
+ /* Count the items */
+ inven_cnt++;
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Combine and Reorder pack */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+
+ /* Return the slot */
+ return (i);
+}
+
+
+
+/*
+ * Take off (some of) a non-cursed equipment item
+ *
+ * Note that only one item at a time can be wielded per slot.
+ *
+ * Note that taking off an item when "full" may cause that item
+ * to fall to the ground.
+ *
+ * Return the inventory slot into which the item is placed.
+ */
+s16b inven_takeoff(int item, int amt, bool_ force_drop)
+{
+ int slot;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ object_type *o_ptr;
+
+ cptr act;
+
+ char o_name[80];
+
+
+ /* Get the item to take off */
+ o_ptr = &p_ptr->inventory[item];
+
+ /* Paranoia */
+ if (amt <= 0) return ( -1);
+
+ /* Verify */
+ if (amt > o_ptr->number) amt = o_ptr->number;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Obtain a local object */
+ object_copy(q_ptr, o_ptr);
+
+ /* Modify quantity */
+ q_ptr->number = amt;
+
+ /* Describe the object */
+ object_desc(o_name, q_ptr, TRUE, 3);
+
+ /* Took off weapon */
+ if (item == INVEN_WIELD)
+ {
+ act = "You were wielding";
+ }
+
+ /* Took off bow */
+ else if (item == INVEN_BOW)
+ {
+ act = "You were holding";
+ }
+
+ /* Took off light */
+ else if (item == INVEN_LITE)
+ {
+ act = "You were holding";
+ }
+
+ /* Took off ammo */
+ else if (item == INVEN_AMMO)
+ {
+ act = "You were carrying in your quiver";
+ }
+
+ /* Took off tool */
+ else if (item == INVEN_TOOL)
+ {
+ act = "You were using";
+ }
+
+ /* Took off something */
+ else
+ {
+ act = "You were wearing";
+ }
+
+ /* Modify, Optimize */
+ inc_stack_size_ex(item, -amt, OPTIMIZE, NO_DESCRIBE);
+
+ if ((item == INVEN_CARRY) && (get_skill(SKILL_SYMBIOTIC)))
+ {
+ /* Drop the monster */
+ o_ptr->pval2 = 0;
+ msg_print("You carefully drop the poor monster on the floor.");
+ drop_near(q_ptr, 0, p_ptr->py, p_ptr->px);
+ slot = -1;
+ }
+ else if (force_drop)
+ {
+ drop_near(q_ptr, 0, p_ptr->py, p_ptr->px);
+ slot = -1;
+ }
+ else
+ {
+ /* Carry the object */
+ slot = inven_carry(q_ptr, FALSE);
+ }
+
+ /* Message */
+ msg_format("%s %s (%c).", act, o_name, index_to_label(slot));
+
+ /* Return slot */
+ return (slot);
+}
+
+
+
+
+/*
+ * Drop (some of) a non-cursed inventory/equipment item
+ *
+ * The object will be dropped "near" the current location
+ */
+void inven_drop(int item, int amt, int dy, int dx, bool_ silent)
+{
+ object_type forge;
+ object_type *q_ptr;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+
+ /* Access original object */
+ o_ptr = &p_ptr->inventory[item];
+
+ /* Error check */
+ if (amt <= 0) return;
+
+ /* Not too many */
+ if (amt > o_ptr->number) amt = o_ptr->number;
+
+
+ /* Take off equipment */
+ if (item >= INVEN_WIELD)
+ {
+ /* Take off first */
+ item = inven_takeoff(item, amt, FALSE);
+
+ /* Access original object */
+ o_ptr = &p_ptr->inventory[item];
+ }
+
+ if (item > -1)
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Obtain local object */
+ object_copy(q_ptr, o_ptr);
+
+ /*
+ * Hack -- If rods or wands are dropped, the total maximum timeout or
+ * charges need to be allocated between the two stacks. If all the items
+ * are being dropped, it makes for a neater message to leave the original
+ * stack's pval alone. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ if (o_ptr->tval == TV_WAND)
+ {
+ q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+ if (amt < o_ptr->number) o_ptr->pval -= q_ptr->pval;
+ }
+ }
+
+ /* Modify quantity */
+ q_ptr->number = amt;
+
+ /* Describe local object */
+ object_desc(o_name, q_ptr, TRUE, 3);
+
+ /* Message */
+ if (!silent) msg_format("You drop %s (%c).", o_name, index_to_label(item));
+
+ /* Drop it near the player */
+ drop_near(q_ptr, 0, dy, dx);
+
+ /* Modify, Describe, Optimize */
+ inc_stack_size(item, -amt);
+ }
+}
+
+
+
+/*
+ * Combine items in the pack
+ *
+ * Note special handling of the "overflow" slot
+ */
+void combine_pack(void)
+{
+ int i, j, k;
+ object_type *o_ptr;
+ object_type *j_ptr;
+ bool_ flag = FALSE;
+
+
+ /* Combine the pack (backwards) */
+ for (i = INVEN_PACK; i > 0; i--)
+ {
+ /* Get the item */
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip empty items */
+ if (!o_ptr->k_idx) continue;
+
+ /* Scan the items above that item */
+ for (j = 0; j < i; j++)
+ {
+ /* Get the item */
+ j_ptr = &p_ptr->inventory[j];
+
+ /* Skip empty items */
+ if (!j_ptr->k_idx) continue;
+
+ /* Can we drop "o_ptr" onto "j_ptr"? */
+ if (object_similar(j_ptr, o_ptr))
+ {
+ /* Take note */
+ flag = TRUE;
+
+ /* Add together the item counts */
+ object_absorb(j_ptr, o_ptr);
+
+ /* One object is gone */
+ inven_cnt--;
+
+ /* Slide everything down */
+ for (k = i; k < INVEN_PACK; k++)
+ {
+ /* Structure copy */
+ p_ptr->inventory[k] = p_ptr->inventory[k + 1];
+ }
+
+ /* Erase the "final" slot */
+ object_wipe(&p_ptr->inventory[k]);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+
+ /* Done */
+ break;
+ }
+ }
+ }
+
+ /* Message */
+ if (flag) msg_print("You combine some items in your pack.");
+}
+
+
+/*
+ * Reorder items in the pack
+ *
+ * Note special handling of the "overflow" slot
+ */
+void reorder_pack(void)
+{
+ int i, j, k;
+ s32b o_value;
+ s32b j_value;
+ object_type forge;
+ object_type *q_ptr;
+ object_type *j_ptr;
+ object_type *o_ptr;
+ bool_ flag = FALSE;
+
+
+ /* Re-order the pack (forwards) */
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ /* Mega-Hack -- allow "proper" over-flow */
+ if ((i == INVEN_PACK) && (inven_cnt == INVEN_PACK)) break;
+
+ /* Get the item */
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip empty slots */
+ if (!o_ptr->k_idx) continue;
+
+ /* Get the "value" of the item */
+ o_value = object_value(o_ptr);
+
+ /* Scan every occupied slot */
+ for (j = 0; j < INVEN_PACK; j++)
+ {
+ /* Get the item already there */
+ j_ptr = &p_ptr->inventory[j];
+
+ /* Use empty slots */
+ if (!j_ptr->k_idx) break;
+
+ /* Objects sort by decreasing type */
+ if (o_ptr->tval > j_ptr->tval) break;
+ if (o_ptr->tval < j_ptr->tval) continue;
+
+ /* Non-aware (flavored) items always come last */
+ if (!object_aware_p(o_ptr)) continue;
+ if (!object_aware_p(j_ptr)) break;
+
+ /* Objects sort by increasing sval */
+ if (o_ptr->sval < j_ptr->sval) break;
+ if (o_ptr->sval > j_ptr->sval) continue;
+
+ /* Unidentified objects always come last */
+ if (!object_known_p(o_ptr)) continue;
+ if (!object_known_p(j_ptr)) break;
+
+
+ /* Hack: otherwise identical rods sort by
+ increasing recharge time --dsb */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ if (o_ptr->timeout > j_ptr->timeout) break;
+ if (o_ptr->timeout < j_ptr->timeout) continue;
+ }
+
+ /* Determine the "value" of the pack item */
+ j_value = object_value(j_ptr);
+
+
+
+ /* Objects sort by decreasing value */
+ if (o_value > j_value) break;
+ if (o_value < j_value) continue;
+ }
+
+ /* Never move down */
+ if (j >= i) continue;
+
+ /* Take note */
+ flag = TRUE;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Save a copy of the moving item */
+ object_copy(q_ptr, &p_ptr->inventory[i]);
+
+ /* Slide the objects */
+ for (k = i; k > j; k--)
+ {
+ /* Slide the item */
+ object_copy(&p_ptr->inventory[k], &p_ptr->inventory[k - 1]);
+ }
+
+ /* Insert the moving item */
+ object_copy(&p_ptr->inventory[j], q_ptr);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+ }
+
+ /* Message */
+ if (flag) msg_print("You reorder some items in your pack.");
+}
+
+/*
+ * Hack -- display an object kind in the current window
+ *
+ * Include list of usable spells for readible books
+ */
+void display_koff(int k_idx)
+{
+ int y;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ char o_name[80];
+
+
+ /* Erase the window */
+ for (y = 0; y < Term->hgt; y++)
+ {
+ /* Erase the line */
+ Term_erase(0, y, 255);
+ }
+
+ /* No info */
+ if (!k_idx) return;
+
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Prepare the object */
+ object_wipe(q_ptr);
+
+ /* Prepare the object */
+ object_prep(q_ptr, k_idx);
+
+
+ /* Describe */
+ object_desc_store(o_name, q_ptr, FALSE, 0);
+
+ /* Mention the object name */
+ Term_putstr(0, 0, -1, TERM_WHITE, o_name);
+}
+
+
+/*
+ * Let the floor carry an object
+ */
+s16b floor_carry(int y, int x, object_type *j_ptr)
+{
+ int n = 0;
+
+ s16b o_idx;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+
+ /* Scan objects in that grid for combination */
+ for (this_o_idx = cave[y][x].o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Check for combination */
+ if (object_similar(o_ptr, j_ptr))
+ {
+ /* Combine the items */
+ object_absorb(o_ptr, j_ptr);
+
+ /* Result */
+ return (this_o_idx);
+ }
+
+ /* Count objects */
+ n++;
+ }
+
+ /* The stack is already too large */
+ if (n > 23) return (0);
+
+ /* Make an object */
+ o_idx = o_pop();
+
+ /* Success */
+ if (o_idx)
+ {
+ object_type *o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[o_idx];
+
+ /* Structure Copy */
+ object_copy(o_ptr, j_ptr);
+
+ /* Location */
+ o_ptr->iy = y;
+ o_ptr->ix = x;
+
+ /* Forget monster */
+ o_ptr->held_m_idx = 0;
+
+ /* Build a stack */
+ o_ptr->next_o_idx = cave[y][x].o_idx;
+
+ /* Place the object */
+ cave[y][x].o_idx = o_idx;
+
+ /* Notice */
+ note_spot(y, x);
+
+ /* Redraw */
+ lite_spot(y, x);
+ }
+
+ /* Result */
+ return (o_idx);
+}
+
+/*
+ * Notice a decaying object in the pack
+ */
+void pack_decay(int item)
+{
+ object_type *o_ptr = &p_ptr->inventory[item];
+
+ monster_race *r_ptr = &r_info[o_ptr->pval2];
+
+ object_type *i_ptr;
+ object_type object_type_body;
+
+ int amt = o_ptr->number;
+
+ s16b m_type;
+ s32b wt;
+
+ byte known = o_ptr->name1;
+
+ byte gone = 1;
+
+ char desc[80];
+
+ /* Player notices each decaying object */
+ object_desc(desc, o_ptr, TRUE, 3);
+ msg_format("You feel %s decompose.", desc);
+
+ /* Get local object */
+ i_ptr = &object_type_body;
+
+ /* Obtain local object */
+ object_copy(i_ptr, o_ptr);
+
+ /* Remember what creature we were */
+ m_type = o_ptr->pval2;
+
+ /* and how much we weighed */
+ wt = r_ptr->weight;
+
+ /* Get rid of decayed object */
+ inc_stack_size_ex(item, -amt, OPTIMIZE, NO_DESCRIBE);
+
+ if (i_ptr->tval == TV_CORPSE)
+ {
+ /* Monster must have a skull for its head to become one */
+ if (i_ptr->sval == SV_CORPSE_HEAD)
+ {
+ /* Replace the head with a skull */
+ object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_SKULL));
+ i_ptr->weight = wt / 60 + rand_int(wt) / 600;
+
+ /* Stay here */
+ gone = 0;
+ }
+
+ /* Monster must have a skeleton for its corpse to become one */
+ if ((i_ptr->sval == SV_CORPSE_CORPSE) && (r_ptr->flags3 & RF9_DROP_SKELETON))
+ {
+ /* Replace the corpse with a skeleton */
+ object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_SKELETON));
+ i_ptr->weight = wt / 4 + rand_int(wt) / 40;
+
+ /* Stay here */
+ gone = 0;
+ }
+
+ /* Don't restore if the item is gone */
+ if (!gone)
+ {
+ i_ptr->number = amt;
+ i_ptr->pval2 = m_type;
+
+ /* Should become "The skull of Farmer Maggot", not "A skull" */
+ if (known)
+ {
+ object_aware(i_ptr);
+
+ /* Named skeletons are artifacts */
+ i_ptr->name1 = 201;
+ }
+ inven_carry(i_ptr, TRUE);
+ }
+ }
+}
+
+/*
+ * Decay an object on the floor
+ */
+void floor_decay(int item)
+{
+ object_type *o_ptr = &o_list[item];
+
+ monster_race *r_ptr = &r_info[o_ptr->pval2];
+
+ object_type *i_ptr;
+ object_type object_type_body;
+
+ int amt = o_ptr->number;
+
+ s16b m_type;
+ s32b wt;
+
+ byte known = o_ptr->name1;
+
+ /* Assume we disappear */
+ byte gone = 1;
+
+ byte x = o_ptr->ix;
+ byte y = o_ptr->iy;
+
+ /* Maybe the player sees it */
+ bool_ visible = player_can_see_bold(o_ptr->iy, o_ptr->ix);
+ char desc[80];
+
+ if (visible)
+ {
+ /* Player notices each decaying object */
+ object_desc(desc, o_ptr, TRUE, 3);
+ msg_format("You see %s decompose.", desc);
+ }
+
+
+ /* Get local object */
+ i_ptr = &object_type_body;
+
+ /* Obtain local object */
+ object_copy(i_ptr, o_ptr);
+
+ /* Remember what creature we were */
+ m_type = o_ptr->pval2;
+
+ /* and how much we weighed */
+ wt = r_ptr->weight;
+
+ floor_item_increase(item, -amt);
+ floor_item_optimize(item);
+
+ if (i_ptr->tval == TV_CORPSE)
+ {
+ /* Monster must have a skull for its head to become one */
+ if (i_ptr->sval == SV_CORPSE_HEAD)
+ {
+ /* Replace the head with a skull */
+ object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_SKULL));
+ i_ptr->weight = wt / 60 + rand_int(wt) / 600;
+
+ /* Stay here */
+ gone = 0;
+ }
+
+ /* Monster must have a skeleton for its corpse to become one */
+ if ((i_ptr->sval == SV_CORPSE_CORPSE) && (r_ptr->flags3 & RF9_DROP_SKELETON))
+ {
+ /* Replace the corpse with a skeleton */
+ object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_SKELETON));
+ i_ptr->weight = wt / 4 + rand_int(wt) / 40;
+
+ /* Stay here */
+ gone = 0;
+ }
+
+ /* Don't restore if the item is gone */
+ if (!gone)
+ {
+ i_ptr->number = amt;
+ i_ptr->pval2 = m_type;
+
+ /* Should become "The skull of Farmer Maggot", not "A skull" */
+ if (known)
+ {
+ object_aware(i_ptr);
+
+ /* Named skeletons are artifacts */
+ i_ptr->name1 = 201;
+ }
+ floor_carry(y, x, i_ptr);
+ }
+ }
+}
+
+/* Return the item be it on the floor or in inven */
+object_type *get_object(int item)
+{
+ /* Get the item (in the pack) */
+ if (item >= 0)
+ {
+ return &p_ptr->inventory[item];
+ }
+
+ /* Get the item (on the floor) */
+ else
+ {
+ return &o_list[0 - item];
+ }
+}
+
diff --git a/src/player.pkg b/src/player.pkg
new file mode 100644
index 00000000..dfdced26
--- /dev/null
+++ b/src/player.pkg
@@ -0,0 +1,3519 @@
+/* File: player.pkg */
+
+/*
+ * Purpose: Lua interface defitions for the player.
+ * To be processed by tolua to generate C source code.
+ */
+
+$#include "angband.h"
+
+/** @typedef cptr
+ * @note String
+ */
+typedef char* cptr;
+/** @typedef errr
+ * @note Number
+ */
+typedef int errr;
+/** @typedef bool
+ * @note Boolean
+ */
+typedef unsigned char bool;
+/** @typedef byte
+ * @note Number
+ */
+typedef unsigned char byte;
+/** @typedef s16b
+ * @note Number
+ */
+typedef signed short s16b;
+/** @typedef u16b
+ * @note Number
+ */
+typedef unsigned short u16b;
+/** @typedef s32b
+ * @note Number
+ */
+typedef signed int s32b;
+/** @typedef u32b
+ * @note Number
+ */
+typedef unsigned int u32b;
+
+/** @def PY_MAX_LEVEL
+ * @note Maximum level
+ */
+#define PY_MAX_LEVEL 50
+
+/** @var player_exp[PY_MAX_LEVEL]
+ * @brief Number
+ * @note Array of experience points per level.
+ */
+extern s32b player_exp[PY_MAX_LEVEL];
+
+/** @name Attributes
+ * @brief Indexes of the various "stats" (hard-coded by savefiles, etc).
+ * @{ */
+/** @def A_STR
+ * @note Strength */
+#define A_STR 0
+
+/** @def A_INT
+ * @note Intelligence */
+#define A_INT 1
+
+/** @def A_WIS
+ * @note Wisdom */
+#define A_WIS 2
+
+/** @def A_DEX
+ * @note Dexterity */
+#define A_DEX 3
+
+/** @def A_CON
+ * @note Constitution */
+#define A_CON 4
+
+/** @def A_CHR
+ * @note Charisma */
+#define A_CHR 5
+/** @} */
+
+/* Ugly hack, should be in foo-info, the subrace saved to the savefile */
+/** @def SUBRACE_SAVE */
+#define SUBRACE_SAVE 9
+
+
+/** @name Sex
+ * @brief Player sex constants (hard-coded by save-files, arrays, etc)
+ * @{ */
+/** @def SEX_FEMALE */
+#define SEX_FEMALE 0
+
+/** @def SEX_MALE */
+#define SEX_MALE 1
+
+/** @def SEX_NEUTER */
+#define SEX_NEUTER 2
+
+
+/** @def MAX_SEXES */
+#define MAX_SEXES 3
+/** @} */
+
+/** @name Race flags
+ * @{ */
+/** @def PR1_EXPERIMENTAL
+ * @note Is still under developemnt
+ */
+#define PR1_EXPERIMENTAL 0x00000001L
+/* XXX */
+/** @def PR1_RESIST_BLACK_BREATH
+ * @note Resist black breath
+ */
+#define PR1_RESIST_BLACK_BREATH 0x00000004L
+/** @def PR1_NO_STUN
+ * @note Never stunned
+ */
+#define PR1_NO_STUN 0x00000008L
+/** @def PR1_XTRA_MIGHT_BOW
+ * @note Xtra might with bows
+ */
+#define PR1_XTRA_MIGHT_BOW 0x00000010L
+/** @def PR1_XTRA_MIGHT_XBOW
+ * @note Xtra might with xbows
+ */
+#define PR1_XTRA_MIGHT_XBOW 0x00000020L
+/** @def PR1_XTRA_MIGHT_SLING
+ * @note Xtra might with slings
+ */
+#define PR1_XTRA_MIGHT_SLING 0x00000040L
+/** @def PR1_AC_LEVEL
+ * @note More AC with levels
+ */
+#define PR1_AC_LEVEL 0x00000080L
+/** @def PR1_HURT_LITE
+ * @note Hurt by light
+ */
+#define PR1_HURT_LITE 0x00000100L
+/** @def PR1_VAMPIRE
+ * @note Vampire
+ */
+#define PR1_VAMPIRE 0x00000200L
+/** @def PR1_UNDEAD
+ * @note Undead
+ */
+#define PR1_UNDEAD 0x00000400L
+/** @def PR1_NO_CUT
+ * @note no cuts
+ */
+#define PR1_NO_CUT 0x00000800L
+/** @def PR1_CORRUPT
+ * @note hack-- corrupted
+ */
+#define PR1_CORRUPT 0x00001000L
+/** @def PR1_NO_FOOD
+ * @note little gain from food
+ */
+#define PR1_NO_FOOD 0x00002000L
+/** @def PR1_NO_GOD
+ * @note cannot worship
+ */
+#define PR1_NO_GOD 0x00004000L
+/* XXX */
+/** @def PR1_ELF
+ * @note Is an elf
+ */
+#define PR1_ELF 0x00010000L
+/** @def PR1_SEMI_WRAITH
+ * @note Takes damage when going in walls
+ */
+#define PR1_SEMI_WRAITH 0x00020000L
+/** @def PR1_NO_SUBRACE_CHANGE
+ * @note Impossible to change subrace
+ */
+#define PR1_NO_SUBRACE_CHANGE 0x00040000L
+/* XXX */
+/** @def PR1_ANTIMAGIC
+ * @note antimagic ... hack
+ */
+#define PR1_ANTIMAGIC 0x00100000L
+/** @def PR1_MOLD_FRIEND
+ * @note Not attacked by molds wielded
+ */
+#define PR1_MOLD_FRIEND 0x00200000L
+/** @def PR1_GOD_FRIEND
+ * @note Better grace
+ */
+#define PR1_GOD_FRIEND 0x00400000L
+/* XXX */
+/** @def PR1_INNATE_SPELLS
+ * @note KNown all spells, only need books
+ */
+#define PR1_INNATE_SPELLS 0x01000000L
+/* XXX */
+/* XXX */
+/** @def PR1_EASE_STEAL
+ * @note Gain xp by stealing
+ */
+#define PR1_EASE_STEAL 0x08000000L
+/* XXX */
+/* XXX */
+/* XXX */
+/* XXX */
+
+/* XXX */
+/** @def PR2_ASTRAL
+ * @note Is it an astral being coming from th halls of mandos ?
+ */
+#define PR2_ASTRAL 0x00000002L
+/* XXX */
+/** @} */
+
+/** @name Notice flags
+ * @brief Bit flags for the "p_ptr->notice" variable
+ * @{ */
+/** @def PN_COMBINE
+ * @note Combine the pack
+ */
+#define PN_COMBINE 0x00000001L
+/** @def PN_REORDER
+ * @note Reorder the pack
+ */
+#define PN_REORDER 0x00000002L
+/* xxx (many) */
+/** @} */
+
+
+/** @name Update flags
+ * @brief Bit flags for the "p_ptr->update" variable
+ * @{ */
+/** @def PU_BONUS
+ * @note Calculate bonuses
+ */
+#define PU_BONUS 0x00000001L
+/** @def PU_TORCH
+ * @note Calculate torch radius
+ */
+#define PU_TORCH 0x00000002L
+/** @def PU_BODY
+ * @note Calculate body parts
+ */
+#define PU_BODY 0x00000004L
+/** @def PU_SANITY
+ * @note Calculate csan and msan
+ */
+#define PU_SANITY 0x00000008L
+/** @def PU_HP
+ * @note Calculate chp and mhp
+ */
+#define PU_HP 0x00000010L
+/** @def PU_MANA
+ * @note Calculate csp and msp
+ */
+#define PU_MANA 0x00000020L
+/** @def PU_SPELLS
+ * @note Calculate spells
+ */
+#define PU_SPELLS 0x00000040L
+/** @def PU_POWERS
+ * @note Calculate powers
+ */
+#define PU_POWERS 0x00000080L
+/* xxx (many) */
+/** @def PU_UN_VIEW
+ * @note Forget view
+ */
+#define PU_UN_VIEW 0x00010000L
+/* xxx (many) */
+/** @def PU_VIEW
+ * @note Update view
+ */
+#define PU_VIEW 0x00100000L
+/** @def PU_MON_LITE
+ * @note Update monster light
+ */
+#define PU_MON_LITE 0x00200000L
+/* xxx */
+/** @def PU_MONSTERS
+ * @note Update monsters
+ */
+#define PU_MONSTERS 0x01000000L
+/** @def PU_DISTANCE
+ * @note Update distances
+ */
+#define PU_DISTANCE 0x02000000L
+/* xxx */
+/** @def PU_FLOW
+ * @note Update flow
+ */
+#define PU_FLOW 0x10000000L
+/* xxx (many) */
+/** @} */
+
+
+/** @name Redraw flags
+ * @brief Bit flags for the "p_ptr->redraw" variable
+ * @{ */
+/** @def PR_MISC
+ * @note Display Race/Class
+ */
+#define PR_MISC 0x00000001L
+/** @def PR_TITLE
+ * @note Display Title
+ */
+#define PR_TITLE 0x00000002L
+/** @def PR_LEV
+ * @note Display Level
+ */
+#define PR_LEV 0x00000004L
+/** @def PR_EXP
+ * @note Display Experience
+ */
+#define PR_EXP 0x00000008L
+/** @def PR_STATS
+ * @note Display Stats
+ */
+#define PR_STATS 0x00000010L
+/** @def PR_ARMOR
+ * @note Display Armor
+ */
+#define PR_ARMOR 0x00000020L
+/** @def PR_HP
+ * @note Display Hitpoints
+ */
+#define PR_HP 0x00000040L
+/** @def PR_MANA
+ * @note Display Mana
+ */
+#define PR_MANA 0x00000080L
+/** @def PR_GOLD
+ * @note Display Gold
+ */
+#define PR_GOLD 0x00000100L
+/** @def PR_DEPTH
+ * @note Display Depth
+ */
+#define PR_DEPTH 0x00000200L
+/****/
+/** @def PR_HEALTH
+ * @note Display Health Bar
+ */
+#define PR_HEALTH 0x00000800L
+/** @def PR_CUT
+ * @note Display Extra (Cut)
+ */
+#define PR_CUT 0x00001000L
+/** @def PR_STUN
+ * @note Display Extra (Stun)
+ */
+#define PR_STUN 0x00002000L
+/** @def PR_HUNGER
+ * @note Display Extra (Hunger)
+ */
+#define PR_HUNGER 0x00004000L
+/** @def PR_PIETY
+ * @note Display Piety
+ */
+#define PR_PIETY 0x00008000L
+/** @def PR_BLIND
+ * @note Display Extra (Blind)
+ */
+#define PR_BLIND 0x00010000L
+/** @def PR_CONFUSED
+ * @note Display Extra (Confused)
+ */
+#define PR_CONFUSED 0x00020000L
+/** @def PR_AFRAID
+ * @note Display Extra (Afraid)
+ */
+#define PR_AFRAID 0x00040000L
+/** @def PR_POISONED
+ * @note Display Extra (Poisoned)
+ */
+#define PR_POISONED 0x00080000L
+/** @def PR_STATE
+ * @note Display Extra (State)
+ */
+#define PR_STATE 0x00100000L
+/** @def PR_SPEED
+ * @note Display Extra (Speed)
+ */
+#define PR_SPEED 0x00200000L
+/** @def PR_STUDY
+ * @note Display Extra (Study)
+ */
+#define PR_STUDY 0x00400000L
+/** @def PR_SANITY
+ * @note Display Sanity
+ */
+#define PR_SANITY 0x00800000L
+/** @def PR_EXTRA
+ * @note Display Extra Info
+ */
+#define PR_EXTRA 0x01000000L
+/** @def PR_BASIC
+ * @note Display Basic Info
+ */
+#define PR_BASIC 0x02000000L
+/** @def PR_MAP
+ * @note Display Map
+ */
+#define PR_MAP 0x04000000L
+/** @def PR_WIPE
+ * @note Hack -- Total Redraw
+ */
+#define PR_WIPE 0x08000000L
+/** @def PR_MH
+ * @note Display Monster hitpoints
+ */
+#define PR_MH 0x10000000L
+/** @def PR_MH
+ * @note Display Monster hitpoints
+ */
+#define PR_MH 0x10000000L
+/** @def PR_DTRAP
+ * @note Display Extra (DTrap)
+ */
+#define PR_DTRAP 0x20000000L
+/* xxx */
+/* xxx */
+/** @} */
+
+
+/** @name Window flags
+ * @brief Bit flags for the "p_ptr->window" variable (etc)
+ * @{ */
+/** @def PW_INVEN
+ * @note Display inven/equip
+ */
+#define PW_INVEN 0x00000001L
+/** @def PW_EQUIP
+ * @note Display equip/inven
+ */
+#define PW_EQUIP 0x00000002L
+/* xxx */
+/** @def PW_PLAYER
+ * @note Display character
+ */
+#define PW_PLAYER 0x00000008L
+/** @def PW_M_LIST
+ * @note Show monster list
+ */
+#define PW_M_LIST 0x00000010L
+/* xxx */
+/** @def PW_MESSAGE
+ * @note Display messages
+ */
+#define PW_MESSAGE 0x00000040L
+/** @def PW_OVERHEAD
+ * @note Display overhead view
+ */
+#define PW_OVERHEAD 0x00000080L
+/** @def PW_MONSTER
+ * @note Display monster recall
+ */
+#define PW_MONSTER 0x00000100L
+/** @def PW_OBJECT
+ * @note Display object recall
+ */
+#define PW_OBJECT 0x00000200L
+/* xxx */
+/** @def PW_SNAPSHOT
+ * @note Display snap-shot
+ */
+#define PW_SNAPSHOT 0x00000800L
+/* xxx */
+/* xxx */
+/** @def PW_BORG_1
+ * @note Display borg messages
+ */
+#define PW_BORG_1 0x00004000L
+/** @def PW_BORG_2
+ * @note Display borg status
+ */
+#define PW_BORG_2 0x00008000L
+/** @} */
+
+/** @struct deity_type
+ */
+struct deity_type
+{
+ /** @structvar name
+ * @brief String
+ */
+ cptr name;
+};
+/** @var deity_info[max_gods]
+ * @brief deity_type
+ * @note Array of gods.
+ */
+extern deity_type deity_info[max_gods];
+
+/** @name Body parts
+ * @{ */
+/** @def BODY_WEAPON */
+#define BODY_WEAPON 0
+
+/** @def BODY_TORSO */
+#define BODY_TORSO 1
+
+/** @def BODY_ARMS */
+#define BODY_ARMS 2
+
+/** @def BODY_FINGER */
+#define BODY_FINGER 3
+
+/** @def BODY_HEAD */
+#define BODY_HEAD 4
+
+/** @def BODY_LEGS */
+#define BODY_LEGS 5
+
+/** @def BODY_MAX */
+#define BODY_MAX 6
+/** @} */
+
+
+/** @struct player_type
+ */
+struct player_type
+{
+ /** @structvar lives
+ * @brief Number
+ * @note How many times we resurected
+ */
+ s32b lives;
+
+ /** @structvar oldpy
+ * @brief Number
+ * @note Previous player location -KMW-
+ */
+ s16b oldpy;
+ /** @structvar oldpx
+ * @brief Number
+ * @note Previous player location -KMW-
+ */
+ s16b oldpx;
+
+ /** @structvar py
+ * @brief Number
+ * @note Player location
+ */
+ s16b py;
+ /** @structvar px
+ * @brief Number
+ * @note Player location
+ */
+ s16b px;
+
+ /** @structvar psex
+ * @brief Number
+ * @note Sex index
+ */
+ byte psex;
+ /** @structvar prace
+ * @brief Number
+ * @note Race index
+ */
+ byte prace;
+ /** @structvar pracem
+ * @brief Number
+ * @note Race Mod index
+ */
+ byte pracem;
+ /** @structvar pclass
+ * @brief Number
+ * @note Class index
+ */
+ byte pclass;
+ /** @structvar mimic_form
+ * @brief Number
+ * @note Actualy transformation
+ */
+ byte mimic_form;
+ /** @structvar mimic_level
+ * @brief Number
+ * @note Level of the mimic effect
+ */
+ s16b mimic_level;
+ /** @structvar oops
+ * @brief Number
+ * @note Unused
+ */
+ byte oops;
+
+ object_type inventory[INVEN_TOTAL] @inventory_real;
+
+ /** @structvar hitdie
+ * @brief Number
+ * @note Hit dice (sides)
+ */
+ byte hitdie;
+ /** @structvar expfact
+ * @brief Number
+ * @note Experience factor
+ */
+ u16b expfact;
+
+ /** @structvar allow_one_death
+ * @brief Number
+ * @note Blood of life
+ */
+ byte allow_one_death;
+
+ /** @structvar age
+ * @brief Number
+ * @note Characters age
+ */
+ s16b age;
+ /** @structvar ht
+ * @brief Number
+ * @note Height
+ */
+ s16b ht;
+ /** @structvar wt
+ * @brief Number
+ * @note Weight
+ */
+ s16b wt;
+ /** @structvar sc
+ * @brief Number
+ * @note Social Class
+ */
+ s16b sc;
+
+
+ /** @structvar au
+ * @brief Number
+ * @note Current Gold
+ */
+ s32b au;
+
+ /** @structvar max_exp
+ * @brief Number
+ * @note Max experience
+ */
+ s32b max_exp;
+ /** @structvar exp
+ * @brief Number
+ * @note Cur experience
+ */
+ s32b exp;
+ /** @structvar exp_frac
+ * @brief Number
+ * @note Cur exp frac (times 2^16)
+ */
+ u16b exp_frac;
+
+ /** @structvar lev
+ * @brief Number
+ * @note Level
+ */
+ s16b lev;
+
+ /** @structvar town_num
+ * @brief Number
+ * @note Current town number
+ */
+ s16b town_num;
+ /** @structvar inside_quest
+ * @brief Number
+ * @note Inside quest level
+ */
+ s16b inside_quest;
+ /** @structvar exit_bldg
+ * @brief Boolean
+ * @note Goal obtained in arena? -KMW-
+ */
+ bool exit_bldg;
+
+ /** @structvar wilderness_x
+ * @brief Number
+ * @note Coordinates in the wilderness
+ */
+ s32b wilderness_x;
+ /** @structvar wilderness_y
+ * @brief Number
+ */
+ s32b wilderness_y;
+ /** @structvar wild_mode
+ * @brief Boolean
+ * @note TRUE = Small map, FLASE = Big map
+ */
+ bool wild_mode;
+ /** @structvar old_wild_mode
+ * @brief Boolean
+ * @note TRUE = Small map, FLASE = Big map
+ */
+ bool old_wild_mode;
+
+ /** @structvar mhp
+ * @brief Number
+ * @note Max hit pts
+ */
+ s16b mhp;
+ /** @structvar chp
+ * @brief Number
+ * @note Cur hit pts
+ */
+ s16b chp;
+ /** @structvar chp_frac
+ * @brief Number
+ * @note Cur hit frac (times 2^16)
+ */
+ u16b chp_frac;
+ /** @structvar hp_mod
+ * @brief Number
+ * @note A modificator(permanent)
+ */
+ s16b hp_mod;
+
+ /** @structvar msp
+ * @brief Number
+ * @note Max mana pts
+ */
+ s16b msp;
+ /** @structvar csp
+ * @brief Number
+ * @note Cur mana pts
+ */
+ s16b csp;
+ /** @structvar csp_frac
+ * @brief Number
+ * @note Cur mana frac (times 2^16)
+ */
+ u16b csp_frac;
+
+ /** @structvar msane
+ * @brief Number
+ * @note Max sanity
+ */
+ s16b msane;
+ /** @structvar csane
+ * @brief Number
+ * @note Cur sanity
+ */
+ s16b csane;
+ /** @structvar csane_frac
+ * @brief Number
+ * @note Cur sanity frac
+ */
+ u16b csane_frac;
+
+ /** @structvar grace
+ * @brief Number
+ * @note Your God's appreciation factor.
+ */
+ s32b grace;
+ /** @structvar pgod
+ * @brief Number
+ * @note Your God.
+ */
+ byte pgod;
+ /** @structvar praying
+ * @brief Boolean
+ * @note Praying to your god.
+ */
+ bool praying;
+
+ /** @structvar max_plv
+ * @brief Number
+ * @note Max Player Level
+ */
+ s16b max_plv;
+
+ /** @structvar stat_max[6]
+ * @brief Number
+ * @note Current "maximal" stat values
+ */
+ s16b stat_max[6];
+ /** @structvar stat_cur[6]
+ * @brief Number
+ * @note Current "natural" stat values
+ */
+ s16b stat_cur[6];
+
+ /** @structvar luck_cur
+ * @brief Number
+ * @note Current "natural" luck value (range -30 <> 30)
+ */
+ s16b luck_cur;
+ /** @structvar luck_max
+ * @brief Number
+ * @note Current "maximal base" luck value (range -30 <> 30)
+ */
+ s16b luck_max;
+ /** @structvar luck_base
+ * @brief Number
+ * @note Current "base" luck value (range -30 <> 30)
+ */
+ s16b luck_base;
+
+ /** @structvar fast
+ * @brief Number
+ * @note Timed -- Fast
+ */
+ s16b fast;
+ /** @structvar lightspeed
+ * @brief Number
+ * @note Timed -- Light Speed
+ */
+ s16b lightspeed;
+ /** @structvar slow
+ * @brief Number
+ * @note Timed -- Slow
+ */
+ s16b slow;
+ /** @structvar blind
+ * @brief Number
+ * @note Timed -- Blindness
+ */
+ s16b blind;
+ /** @structvar paralyzed
+ * @brief Number
+ * @note Timed -- Paralysis
+ */
+ s16b paralyzed;
+ /** @structvar confused
+ * @brief Number
+ * @note Timed -- Confusion
+ */
+ s16b confused;
+ /** @structvar afraid
+ * @brief Number
+ * @note Timed -- Fear
+ */
+ s16b afraid;
+ /** @structvar image
+ * @brief Number
+ * @note Timed -- Hallucination
+ */
+ s16b image;
+ /** @structvar poisoned
+ * @brief Number
+ * @note Timed -- Poisoned
+ */
+ s16b poisoned;
+ /** @structvar cut
+ * @brief Number
+ * @note Timed -- Cut
+ */
+ s16b cut;
+ /** @structvar stun
+ * @brief Number
+ * @note Timed -- Stun
+ */
+ s16b stun;
+
+ /** @structvar protevil
+ * @brief Number
+ * @note Timed -- Protection from Evil
+ */
+ s16b protevil;
+ /** @structvar protgood
+ * @brief Number
+ * @note Timed -- Protection from Good
+ */
+ s16b protgood;
+ /** @structvar protundead
+ * @brief Number
+ * @note Timed -- Protection from Undead
+ */
+ s16b protundead;
+ /** @structvar invuln
+ * @brief Number
+ * @note Timed -- Invulnerable
+ */
+ s16b invuln;
+ /** @structvar hero
+ * @brief Number
+ * @note Timed -- Heroism
+ */
+ s16b hero;
+ /** @structvar shero
+ * @brief Number
+ * @note Timed -- Super Heroism
+ */
+ s16b shero;
+ /** @structvar shield
+ * @brief Number
+ * @note Timed -- Shield Spell
+ */
+ s16b shield;
+ /** @structvar shield_power
+ * @brief Number
+ * @note Timed -- Shield Spell Power
+ */
+ s16b shield_power;
+ /** @structvar shield_opt
+ * @brief Number
+ * @note Timed -- Shield Spell options
+ */
+ s16b shield_opt;
+ /** @structvar blessed
+ * @brief Number
+ * @note Timed -- Blessed
+ */
+ s16b blessed;
+ /** @structvar tim_invis
+ * @brief Number
+ * @note Timed -- See Invisible
+ */
+ s16b tim_invis;
+ /** @structvar tim_infra
+ * @brief Number
+ * @note Timed -- Infra Vision
+ */
+ s16b tim_infra;
+
+ /** @structvar oppose_acid
+ * @brief Number
+ * @note Timed -- oppose acid
+ */
+ s16b oppose_acid;
+ /** @structvar oppose_elec
+ * @brief Number
+ * @note Timed -- oppose lightning
+ */
+ s16b oppose_elec;
+ /** @structvar oppose_fire
+ * @brief Number
+ * @note Timed -- oppose heat
+ */
+ s16b oppose_fire;
+ /** @structvar oppose_cold
+ * @brief Number
+ * @note Timed -- oppose cold
+ */
+ s16b oppose_cold;
+ /** @structvar oppose_pois
+ * @brief Number
+ * @note Timed -- oppose poison
+ */
+ s16b oppose_pois;
+ /** @structvar oppose_ld
+ * @brief Number
+ * @note Timed -- oppose light & dark
+ */
+ s16b oppose_ld;
+ /** @structvar oppose_cc
+ * @brief Number
+ * @note Timed -- oppose chaos & confusion
+ */
+ s16b oppose_cc;
+ /** @structvar oppose_ss
+ * @brief Number
+ * @note Timed -- oppose sound & shards
+ */
+ s16b oppose_ss;
+ /** @structvar oppose_nex
+ * @brief Number
+ * @note Timed -- oppose nexus
+ */
+ s16b oppose_nex;
+
+
+ /** @structvar tim_esp
+ * @brief Number
+ * @note Timed ESP
+ */
+ s16b tim_esp;
+ /** @structvar tim_wraith
+ * @brief Number
+ * @note Timed wraithform
+ */
+ s16b tim_wraith;
+ /** @structvar tim_ffall
+ * @brief Number
+ * @note Timed Levitation
+ */
+ s16b tim_ffall;
+ /** @structvar tim_fly
+ * @brief Number
+ * @note Timed Levitation
+ */
+ s16b tim_fly;
+ /** @structvar tim_fire_aura
+ * @brief Number
+ * @note Timed Fire Aura
+ */
+ s16b tim_fire_aura;
+ /** @structvar tim_regen
+ * @brief Number
+ * @note Timed regen
+ */
+ s16b tim_regen;
+ /** @structvar tim_regen_pow
+ * @brief Number
+ * @note Timed regen
+ */
+ s16b tim_regen_pow;
+ /** @structvar tim_poison
+ * @brief Number
+ * @note Timed poison hands
+ */
+ s16b tim_poison;
+ /** @structvar tim_thunder
+ * @brief Number
+ * @note Timed thunderstorm
+ */
+ s16b tim_thunder;
+ /** @structvar tim_thunder_p1
+ * @brief Number
+ * @note Timed thunderstorm
+ */
+ s16b tim_thunder_p1;
+ /** @structvar tim_thunder_p2
+ * @brief Number
+ * @note Timed thunderstorm
+ */
+ s16b tim_thunder_p2;
+
+ /** @structvar resist_magic
+ * @brief Number
+ * @note Timed Resist Magic (later)
+ */
+ s16b resist_magic;
+ /** @structvar tim_invisible
+ * @brief Number
+ * @note Timed Invisibility
+ */
+ s16b tim_invisible;
+ /** @structvar tim_inv_pow
+ * @brief Number
+ * @note Power of timed invisibility
+ */
+ s16b tim_inv_pow;
+ /** @structvar tim_mimic
+ * @brief Number
+ * @note Timed Mimic
+ */
+ s16b tim_mimic;
+ /** @structvar tim_lite
+ * @brief Number
+ * @note Timed Lite
+ */
+ s16b tim_lite;
+ /** @structvar holy
+ * @brief Number
+ * @note Holy Aura
+ */
+ s16b holy;
+ /** @structvar walk_water
+ * @brief Number
+ * @note Walk over water as a god
+ */
+ s16b walk_water;
+ /** @structvar tim_mental_barrier
+ * @brief Number
+ * @note Sustain Int&Wis
+ */
+ s16b tim_mental_barrier;
+ /** @structvar strike
+ * @brief Number
+ * @note True Strike(+25 hit)
+ */
+ s16b strike;
+ /** @structvar meditation
+ * @brief Number
+ * @note Meditation(+50 mana -25 to hit/to dam)
+ */
+ s16b meditation;
+ /** @structvar tim_reflect
+ * @brief Number
+ * @note Timed Reflection
+ */
+ s16b tim_reflect;
+ /** @structvar tim_res_time
+ * @brief Number
+ * @note Timed Resistance to Time
+ */
+ s16b tim_res_time;
+ /** @structvar tim_deadly
+ * @brief Number
+ * @note Timed deadly blow
+ */
+ s16b tim_deadly;
+ /** @structvar prob_travel
+ * @brief Number
+ * @note Timed probability travel
+ */
+ s16b prob_travel;
+ /** @structvar disrupt_shield
+ * @brief Number
+ * @note Timed disruption shield
+ */
+ s16b disrupt_shield;
+ /** @structvar parasite
+ * @brief Number
+ * @note Timed parasite
+ */
+ s16b parasite;
+ /** @structvar parasite_r_idx
+ * @brief Number
+ * @note Timed parasite monster
+ */
+ s16b parasite_r_idx;
+ /** @structvar loan
+ * @brief Number
+ */
+ u32b loan;
+ /** @structvar loan_time
+ * @brief Number
+ * @note Timer -- loan
+ */
+ u32b loan_time;
+ /** @structvar tim_magic_breath
+ * @brief Number
+ * @note Magical breathing -- can breath anywhere
+ */
+ s16b tim_magic_breath;
+ /** @structvar tim_water_breath
+ * @brief Number
+ * @note Water breathing -- can breath underwater
+ */
+ s16b tim_water_breath;
+
+ /** @structvar immov_cntr
+ * @brief Number
+ * @note Timed -- Last ``immovable'' command.
+ */
+ s16b immov_cntr;
+
+ /** @structvar music_extra
+ * @brief Number
+ * @note Music songs
+ */
+ u32b music_extra;
+ /** @structvar music_extra2
+ * @brief Number
+ * @note Music songs
+ */
+ u32b music_extra2;
+
+ /** @structvar chaos_patron
+ * @brief Number
+ */
+ s16b chaos_patron;
+
+ /** @structvar recall_dungeon
+ * @brief Number
+ * @note Recall in which dungeon
+ */
+ s16b recall_dungeon;
+ /** @structvar word_recall
+ * @brief Number
+ * @note Word of recall counter
+ */
+ s16b word_recall;
+
+ /** @structvar energy
+ * @brief Number
+ * @note Current energy
+ */
+ s32b energy;
+
+ /** @structvar food
+ * @brief Number
+ * @note Current nutrition
+ */
+ s16b food;
+
+ /** @structvar confusing
+ * @brief Number
+ * @note Glowing hands
+ */
+ byte confusing;
+ /** @structvar searching
+ * @brief Number
+ * @note Currently searching
+ */
+ byte searching;
+
+ /** @structvar new_spells
+ * @brief Number
+ * @note Number of spells available
+ */
+ s16b new_spells;
+
+ /** @structvar old_spells
+ * @brief Number
+ */
+ s16b old_spells;
+
+ /** @structvar xtra_spells
+ * @brief Number
+ * @note Number of xtra spell learned(via potion)
+ */
+ s16b xtra_spells;
+
+ /** @structvar cur_lite
+ * @brief Number
+ * @note Radius of lite (if any)
+ */
+ s16b cur_lite;
+
+ /*** Extra flags -- used for lua and easying stuff ***/
+ /** @structvar xtra_f1
+ * @brief Number
+ */
+ u32b xtra_f1;
+ /** @structvar xtra_f2
+ * @brief Number
+ */
+ u32b xtra_f2;
+ /** @structvar xtra_f3
+ * @brief Number
+ */
+ u32b xtra_f3;
+ /** @structvar xtra_f4
+ * @brief Number
+ */
+ u32b xtra_f4;
+ /** @structvar xtra_f5
+ * @brief Number
+ */
+ u32b xtra_f5;
+ /** @structvar xtra_esp
+ * @brief Number
+ */
+ u32b xtra_esp;
+
+ /** @structvar pspeed
+ * @brief Number
+ * @note Current speed
+ */
+ s16b pspeed;
+
+ /** @structvar notice
+ * @brief Number
+ * @note Special Updates (bit flags)
+ */
+ u32b notice;
+ /** @structvar update
+ * @brief Number
+ * @note Pending Updates (bit flags)
+ */
+ u32b update;
+ /** @structvar redraw
+ * @brief Number
+ * @note Normal Redraws (bit flags)
+ */
+ u32b redraw;
+ /** @structvar window
+ * @brief Number
+ * @note Window Redraws (bit flags)
+ */
+ u32b window;
+
+ /** @structvar stat_use[6]
+ * @brief Number
+ * @note Current modified stats
+ */
+ s16b stat_use[6];
+ /** @structvar stat_top[6]
+ * @brief Number
+ * @note Maximal modified stats
+ */
+ s16b stat_top[6];
+
+ /** @structvar stat_add[6]
+ * @brief Number
+ * @note Modifiers to stat values
+ */
+ s16b stat_add[6];
+ /** @structvar stat_ind[6]
+ * @brief Number
+ * @note Indexes into stat tables
+ */
+ s16b stat_ind[6];
+ /** @structvar stat_cnt[6]
+ * @brief Number
+ * @note Counter for temporary drains
+ */
+ s16b stat_cnt[6];
+ /** @structvar stat_los[6]
+ * @brief Number
+ * @note Amount of temporary drains
+ */
+ s16b stat_los[6];
+
+ /** @structvar immune_acid
+ * @brief Boolean
+ * @note Immunity to acid
+ */
+ bool immune_acid;
+ /** @structvar immune_elec
+ * @brief Boolean
+ * @note Immunity to lightning
+ */
+ bool immune_elec;
+ /** @structvar immune_fire
+ * @brief Boolean
+ * @note Immunity to fire
+ */
+ bool immune_fire;
+ /** @structvar immune_cold
+ * @brief Boolean
+ * @note Immunity to cold
+ */
+ bool immune_cold;
+ /** @structvar immune_neth
+ * @brief Boolean
+ * @note Immunity to nether
+ */
+ bool immune_neth;
+
+ /** @structvar resist_acid
+ * @brief Boolean
+ * @note Resist acid
+ */
+ bool resist_acid;
+ /** @structvar resist_elec
+ * @brief Boolean
+ * @note Resist lightning
+ */
+ bool resist_elec;
+ /** @structvar resist_fire
+ * @brief Boolean
+ * @note Resist fire
+ */
+ bool resist_fire;
+ /** @structvar resist_cold
+ * @brief Boolean
+ * @note Resist cold
+ */
+ bool resist_cold;
+ /** @structvar resist_pois
+ * @brief Boolean
+ * @note Resist poison
+ */
+ bool resist_pois;
+
+ /** @structvar resist_conf
+ * @brief Boolean
+ * @note Resist confusion
+ */
+ bool resist_conf;
+ /** @structvar resist_sound
+ * @brief Boolean
+ * @note Resist sound
+ */
+ bool resist_sound;
+ /** @structvar resist_lite
+ * @brief Boolean
+ * @note Resist light
+ */
+ bool resist_lite;
+ /** @structvar resist_dark
+ * @brief Boolean
+ * @note Resist darkness
+ */
+ bool resist_dark;
+ /** @structvar resist_chaos
+ * @brief Boolean
+ * @note Resist chaos
+ */
+ bool resist_chaos;
+ /** @structvar resist_disen
+ * @brief Boolean
+ * @note Resist disenchant
+ */
+ bool resist_disen;
+ /** @structvar resist_shard
+ * @brief Boolean
+ * @note Resist shards
+ */
+ bool resist_shard;
+ /** @structvar resist_nexus
+ * @brief Boolean
+ * @note Resist nexus
+ */
+ bool resist_nexus;
+ /** @structvar resist_blind
+ * @brief Boolean
+ * @note Resist blindness
+ */
+ bool resist_blind;
+ /** @structvar resist_neth
+ * @brief Boolean
+ * @note Resist nether
+ */
+ bool resist_neth;
+ /** @structvar resist_fear
+ * @brief Boolean
+ * @note Resist fear
+ */
+ bool resist_fear;
+ /** @structvar resist_continuum
+ * @brief Boolean
+ * @note Resist space-time continuum disruption
+ */
+ bool resist_continuum;
+
+ /** @structvar sensible_fire
+ * @brief Boolean
+ * @note Fire does more damage on the player
+ */
+ bool sensible_fire;
+ /** @structvar sensible_lite
+ * @brief Boolean
+ * @note Lite does more damage on the player and blinds her/him
+ */
+ bool sensible_lite;
+
+ /** @structvar reflect
+ * @brief Boolean
+ * @note Reflect 'bolt' attacks
+ */
+ bool reflect;
+ /** @structvar sh_fire
+ * @brief Boolean
+ * @note Fiery 'immolation' effect
+ */
+ bool sh_fire;
+ /** @structvar sh_elec
+ * @brief Boolean
+ * @note Electric 'immolation' effect
+ */
+ bool sh_elec;
+ /** @structvar wraith_form
+ * @brief Boolean
+ * @note wraithform
+ */
+ bool wraith_form;
+
+ /** @structvar anti_magic
+ * @brief Boolean
+ * @note Anti-magic
+ */
+ bool anti_magic;
+ /** @structvar anti_tele
+ * @brief Boolean
+ * @note Prevent teleportation
+ */
+ bool anti_tele;
+
+ /** @structvar sustain_str
+ * @brief Boolean
+ * @note Keep strength
+ */
+ bool sustain_str;
+ /** @structvar sustain_int
+ * @brief Boolean
+ * @note Keep intelligence
+ */
+ bool sustain_int;
+ /** @structvar sustain_wis
+ * @brief Boolean
+ * @note Keep wisdom
+ */
+ bool sustain_wis;
+ /** @structvar sustain_dex
+ * @brief Boolean
+ * @note Keep dexterity
+ */
+ bool sustain_dex;
+ /** @structvar sustain_con
+ * @brief Boolean
+ * @note Keep constitution
+ */
+ bool sustain_con;
+ /** @structvar sustain_chr
+ * @brief Boolean
+ * @note Keep charisma
+ */
+ bool sustain_chr;
+
+ /** @structvar aggravate
+ * @brief Boolean
+ * @note Aggravate monsters
+ */
+ bool aggravate;
+ /** @structvar teleport
+ * @brief Boolean
+ * @note Random teleporting
+ */
+ bool teleport;
+
+ /** @structvar exp_drain
+ * @brief Boolean
+ * @note Experience draining
+ */
+ bool exp_drain;
+ /** @structvar drain_mana
+ * @brief Number
+ * @note mana draining
+ */
+ byte drain_mana;
+ /** @structvar drain_life
+ * @brief Number
+ * @note hp draining
+ */
+ byte drain_life;
+
+ /** @structvar magical_breath
+ * @brief Boolean
+ * @note Magical breathing -- can breath anywhere
+ */
+ bool magical_breath;
+ /** @structvar water_breath
+ * @brief Boolean
+ * @note Water breathing -- can breath underwater
+ */
+ bool water_breath;
+ /** @structvar climb
+ * @brief Boolean
+ * @note Can climb mountains
+ */
+ bool climb;
+ /** @structvar fly
+ * @brief Boolean
+ * @note Can fly over some features
+ */
+ bool fly;
+ /** @structvar ffall
+ * @brief Boolean
+ * @note No damage falling
+ */
+ bool ffall;
+ /** @structvar lite
+ * @brief Boolean
+ * @note Permanent light
+ */
+ bool lite;
+ /** @structvar free_act
+ * @brief Boolean
+ * @note Never paralyzed
+ */
+ bool free_act;
+ /** @structvar see_inv
+ * @brief Boolean
+ * @note Can see invisible
+ */
+ bool see_inv;
+ /** @structvar regenerate
+ * @brief Boolean
+ * @note Regenerate hit pts
+ */
+ bool regenerate;
+ /** @structvar hold_life
+ * @brief Boolean
+ * @note Resist life draining
+ */
+ bool hold_life;
+ /** @structvar telepathy
+ * @brief Number
+ * @note Telepathy
+ */
+ u32b telepathy;
+ /** @structvar slow_digest
+ * @brief Boolean
+ * @note Slower digestion
+ */
+ bool slow_digest;
+ /** @structvar bless_blade
+ * @brief Boolean
+ * @note Blessed blade
+ */
+ bool bless_blade;
+ /** @structvar xtra_might
+ * @brief Number
+ * @note Extra might bow
+ */
+ byte xtra_might;
+ /** @structvar impact
+ * @brief Boolean
+ * @note Earthquake blows
+ */
+ bool impact;
+ /** @structvar auto_id
+ * @brief Boolean
+ * @note Auto id items
+ */
+ bool auto_id;
+
+ /** @structvar dis_to_h
+ * @brief Number
+ * @note Known bonus to hit
+ */
+ s16b dis_to_h;
+ /** @structvar dis_to_d
+ * @brief Number
+ * @note Known bonus to dam
+ */
+ s16b dis_to_d;
+ /** @structvar dis_to_a
+ * @brief Number
+ * @note Known bonus to ac
+ */
+ s16b dis_to_a;
+
+ /** @structvar dis_ac
+ * @brief Number
+ * @note Known base ac
+ */
+ s16b dis_ac;
+
+ /** @structvar to_m
+ * @brief Number
+ * @note Bonus to mana
+ */
+ s16b to_m;
+ /** @structvar to_s
+ * @brief Number
+ * @note Bonus to spell
+ */
+ s16b to_s;
+ /** @structvar to_h
+ * @brief Number
+ * @note Bonus to hit
+ */
+ s16b to_h;
+ /** @structvar to_d
+ * @brief Number
+ * @note Bonus to dam
+ */
+ s16b to_d;
+ /** @structvar to_a
+ * @brief Number
+ * @note Bonus to ac
+ */
+ s16b to_a;
+
+ /** @structvar to_h_melee
+ * @brief Number
+ * @note Bonus to hit
+ */
+ s16b to_h_melee;
+ /** @structvar to_d_melee
+ * @brief Number
+ * @note Bonus to dam
+ */
+ s16b to_d_melee;
+
+ /** @structvar to_h_ranged
+ * @brief Number
+ * @note Bonus to hit
+ */
+ s16b to_h_ranged;
+ /** @structvar to_d_ranged
+ * @brief Number
+ * @note Bonus to dam
+ */
+ s16b to_d_ranged;
+
+ /** @structvar num_blow
+ * @brief Number
+ * @note Number of blows
+ */
+ s16b num_blow;
+ /** @structvar num_fire
+ * @brief Number
+ * @note Number of shots
+ */
+ s16b num_fire;
+
+ /** @structvar ac
+ * @brief Number
+ * @note Base ac
+ */
+ s16b ac;
+
+ /** @structvar antimagic
+ * @brief Number
+ * @note Power of the anti magic field
+ */
+ byte antimagic;
+ /** @structvar antimagic_dis
+ * @brief Number
+ * @note Radius of the anti magic field
+ */
+ byte antimagic_dis;
+
+ /** @structvar see_infra
+ * @brief Number
+ * @note Infravision range
+ */
+ s16b see_infra;
+
+ /** @structvar skill_dis
+ * @brief Number
+ * @note Skill: Disarming
+ */
+ s16b skill_dis;
+ /** @structvar skill_dev
+ * @brief Number
+ * @note Skill: Magic Devices
+ */
+ s16b skill_dev;
+ /** @structvar skill_sav
+ * @brief Number
+ * @note Skill: Saving throw
+ */
+ s16b skill_sav;
+ /** @structvar skill_stl
+ * @brief Number
+ * @note Skill: Stealth factor
+ */
+ s16b skill_stl;
+ /** @structvar skill_srh
+ * @brief Number
+ * @note Skill: Searching ability
+ */
+ s16b skill_srh;
+ /** @structvar skill_fos
+ * @brief Number
+ * @note Skill: Searching frequency
+ */
+ s16b skill_fos;
+ /** @structvar skill_thn
+ * @brief Number
+ * @note Skill: To hit (normal)
+ */
+ s16b skill_thn;
+ /** @structvar skill_thb
+ * @brief Number
+ * @note Skill: To hit (shooting)
+ */
+ s16b skill_thb;
+ /** @structvar skill_tht
+ * @brief Number
+ * @note Skill: To hit (throwing)
+ */
+ s16b skill_tht;
+ /** @structvar skill_dig
+ * @brief Number
+ * @note Skill: Digging
+ */
+ s16b skill_dig;
+
+ /** @structvar skill_points
+ * @brief Number
+ */
+ s16b skill_points;
+
+ /** @structvar control
+ * @brief Number
+ * @note Controlled monster
+ */
+ s16b control;
+ /** @structvar control_dir
+ * @brief Number
+ * @note Controlled monster
+ */
+ byte control_dir;
+ /** @structvar companion_killed
+ * @brief Number
+ * @note Number of companion death
+ */
+ s16b companion_killed;
+ /** @structvar black_breath
+ * @brief Boolean
+ * @note The Tolkien's Black Breath
+ */
+ bool black_breath;
+ /** @structvar body_monster
+ * @brief Number
+ * @note In which body is the player
+ */
+ u16b body_monster;
+
+ /** @structvar body_parts[28]
+ * @brief Number
+ * @note Various body modifiers
+ */
+ byte body_parts[28];
+
+ /** @structvar powers_mod[POWER_MAX_INIT]
+ * @brief Boolean
+ * @note Intrinsinc powers
+ */
+ bool powers_mod[POWER_MAX_INIT];
+ /** @structvar powers[power_max]
+ * @brief Boolean
+ */
+ bool powers[power_max];
+
+ /** @structvar spellbinder_num
+ * @brief Number
+ * @note Number of spells bound
+ */
+ byte spellbinder_num;
+ /** @structvar spellbinder[4]
+ * @brief Number
+ * @note Spell bounds
+ */
+ u32b spellbinder[4];
+ /** @structvar spellbinder_trigger
+ * @brief Number
+ * @note Spellbinder trigger condition
+ */
+ byte spellbinder_trigger;
+
+ /* Corruptions */
+ /** @structvar corruptions_aux;
+ * @brief Boolean
+ */
+ bool corruptions[max_corruptions] @ corruptions_aux;
+
+ /* Astral */
+ /** @structvar astral
+ * @brief Boolean
+ * @note We started at the bottom ?
+ */
+ bool astral;
+
+ /*** Temporary fields ***/
+
+ /** @structvar leaving
+ * @brief Boolean
+ * @note True if player is leaving
+ */
+ bool leaving;
+};
+
+/** @name Spellbinder triggers
+ * @{ */
+/** @def SPELLBINDER_HP75
+ * @note Trigger spellbinder at 75% maximum hit points */
+#define SPELLBINDER_HP75 1
+
+/** @def SPELLBINDER_HP50
+ * @note Trigger spellbinder at 50% maximum hit points */
+#define SPELLBINDER_HP50 2
+
+/** @def SPELLBINDER_HP25
+ * @note Trigger spellbinder at 25% maximum hit points */
+#define SPELLBINDER_HP25 3
+/** @} */
+
+
+/** @struct player_race
+ */
+struct player_race
+{
+ /** @structvar title
+ * @brief Number
+ * @note Type of race
+ */
+ s32b title;
+ /** @structvar desc
+ * @brief Number
+ */
+ s32b desc;
+
+ /** @structvar infra
+ * @brief Number
+ * @note Infra-vision range
+ */
+ byte infra;
+};
+
+/** @struct player_race_mod
+ */
+struct player_race_mod
+{
+ /** @structvar title
+ * @brief Number
+ * @note Type of race mod
+ */
+ s32b title;
+ /** @structvar desc
+ * @brief Number
+ * @note Desc
+ */
+ s32b desc;
+ /** @structvar place
+ * @brief Boolean
+ * @note TRUE = race race modifier, FALSE = Race modifier race
+ */
+ bool place;
+
+ /** @structvar r_adj[6]
+ * @brief Number
+ * @note (+) Racial stat bonuses
+ */
+ s16b r_adj[6];
+
+ /** @structvar luck
+ * @brief String
+ * @note Luck
+ */
+ char luck;
+ /** @structvar mana
+ * @brief Number
+ * @note Mana %
+ */
+ s16b mana;
+
+ /** @structvar r_dis
+ * @brief Number
+ * @note (+) disarming
+ */
+ s16b r_dis;
+ /** @structvar r_dev
+ * @brief Number
+ * @note (+) magic devices
+ */
+ s16b r_dev;
+ /** @structvar r_sav
+ * @brief Number
+ * @note (+) saving throw
+ */
+ s16b r_sav;
+ /** @structvar r_stl
+ * @brief Number
+ * @note (+) stealth
+ */
+ s16b r_stl;
+ /** @structvar r_srh
+ * @brief Number
+ * @note (+) search ability
+ */
+ s16b r_srh;
+ /** @structvar r_fos
+ * @brief Number
+ * @note (+) search frequency
+ */
+ s16b r_fos;
+ /** @structvar r_thn
+ * @brief Number
+ * @note (+) combat (normal)
+ */
+ s16b r_thn;
+ /** @structvar r_thb
+ * @brief Number
+ * @note (+) combat (shooting)
+ */
+ s16b r_thb;
+
+ /** @structvar r_mhp
+ * @brief String
+ * @note (+) Race mod hit-dice modifier
+ */
+ char r_mhp;
+ /** @structvar r_exp
+ * @brief Number
+ * @note (+) Race mod experience factor
+ */
+ s16b r_exp;
+
+ /** @structvar b_age
+ * @brief String
+ * @note (+) base age
+ */
+ char b_age;
+ /** @structvar m_age
+ * @brief String
+ * @note (+) mod age
+ */
+ char m_age;
+
+ /** @structvar m_b_ht
+ * @brief String
+ * @note (+) base height (males)
+ */
+ char m_b_ht;
+ /** @structvar m_m_ht
+ * @brief String
+ * @note (+) mod height (males)
+ */
+ char m_m_ht;
+ /** @structvar m_b_wt
+ * @brief String
+ * @note (+) base weight (males)
+ */
+ char m_b_wt;
+ /** @structvar m_m_wt
+ * @brief String
+ * @note (+) mod weight (males)
+ */
+ char m_m_wt;
+
+ /** @structvar f_b_ht
+ * @brief String
+ * @note (+) base height (females)
+ */
+ char f_b_ht;
+ /** @structvar f_m_ht
+ * @brief String
+ * @note (+) mod height (females)
+ */
+ char f_m_ht;
+ /** @structvar f_b_wt
+ * @brief String
+ * @note (+) base weight (females)
+ */
+ char f_b_wt;
+ /** @structvar f_m_wt
+ * @brief String
+ * @note (+) mod weight (females)
+ */
+ char f_m_wt;
+
+ /** @structvar infra
+ * @brief String
+ * @note (+) Infra-vision range
+ */
+ char infra;
+
+ /** @structvar choice[2]
+ * @brief Number
+ * @note Legal race choices
+ */
+ u32b choice[2];
+
+ /** @structvar pclass[2]
+ * @brief Number
+ * @note Classes allowed
+ */
+ u32b pclass[2];
+ /** @structvar mclass[2]
+ * @brief Number
+ * @note Classes restricted
+ */
+ u32b mclass[2];
+
+ /** @structvar powers[4]
+ * @brief Number
+ * @note Powers of the subrace
+ */
+ s16b powers[4];
+
+ /** @structvar body_parts[BODY_MAX]
+ * @brief String
+ * @note To help to decide what to use when body changing
+ */
+ char body_parts[BODY_MAX];
+
+ /** @structvar flags1
+ * @brief Number
+ */
+ u32b flags1;
+ /** @structvar flags2
+ * @brief Number
+ * @note flags
+ */
+ u32b flags2;
+
+ /** @structvar oflags1[51]
+ * @brief Number
+ */
+ u32b oflags1[51];
+ /** @structvar oflags2[51]
+ * @brief Number
+ */
+ u32b oflags2[51];
+ /** @structvar oflags3[51]
+ * @brief Number
+ */
+ u32b oflags3[51];
+ /** @structvar oflags4[51]
+ * @brief Number
+ */
+ u32b oflags4[51];
+ /** @structvar oflags5[51]
+ * @brief Number
+ */
+ u32b oflags5[51];
+ /** @structvar oesp[51]
+ * @brief Number
+ */
+ u32b oesp[51];
+ /** @structvar opval[51]
+ * @brief Number
+ */
+ s16b opval[51];
+
+ /** @structvar g_attr
+ * @brief Number
+ * @note Overlay graphic attribute
+ */
+ byte g_attr;
+ /** @structvar g_char
+ * @brief String
+ * @note Overlay graphic character
+ */
+ char g_char;
+
+ /** @structvar skill_basem[MAX_SKILLS]
+ * @brief String
+ */
+ char skill_basem[MAX_SKILLS];
+ /** @structvar skill_base[MAX_SKILLS]
+ * @brief Number
+ */
+ u32b skill_base[MAX_SKILLS];
+ /** @structvar skill_modm[MAX_SKILLS]
+ * @brief String
+ */
+ char skill_modm[MAX_SKILLS];
+ /** @structvar skill_mod[MAX_SKILLS]
+ * @brief Number
+ */
+ s16b skill_mod[MAX_SKILLS];
+};
+
+/** @var energy_use
+ * @brief Number
+ * @note Energy use for an action (0 if action does not take a turn).
+ */
+extern s32b energy_use;
+
+/** @var player;
+ * @brief player_type
+ * @note The player.
+ */
+extern player_type *p_ptr @ player;
+
+/** @var max_rp_idx
+ * @brief Number
+ * @note Maximum number of entries in player race array.
+ */
+extern u16b max_rp_idx;
+
+/** @var race_info[max_rp_idx]
+ * @brief player_race
+ * @note Array of player races.
+ */
+extern player_race race_info[max_rp_idx];
+
+/** @var *rp_name
+ * @brief String
+ * @note Name of player race.
+ */
+extern char *rp_name;
+
+/** @var *rp_text
+ * @brief String
+ */
+extern char *rp_text;
+
+/** @var max_rmp_idx
+ * @brief Number
+ * @note Maximum number of player subraces.
+ */
+extern u16b max_rmp_idx;
+
+/** @var _mod race_mod_info[max_rmp_idx]
+ * @brief player_race
+ * @note Array of player subraces.
+ */
+extern player_race_mod race_mod_info[max_rmp_idx];
+
+/** @var *rmp_name
+ * @brief String
+ * @note Name of player subrace.
+ */
+extern char *rmp_name;
+
+/** @var *rmp_text
+ * @brief String
+ */
+extern char *rmp_text;
+
+/** @var class_info[max_c_idx]
+ * @brief player_class
+ * @note Array of classes.
+ */
+extern player_class class_info[max_c_idx];
+
+/** @var *c_name
+ * @brief String
+ * @note Name of player class.
+ */
+extern char *c_name;
+
+/** @var *c_text
+ * @brief String
+ */
+extern char *c_text;
+
+/** @var flush_failure
+ * @brief Boolean
+ * @note TRUE if flush input on any failure, otherwise FALSE.
+ */
+extern bool flush_failure;
+
+/** @fn set_roots(int v, s16b ac, s16b dam)
+ * @brief Player has timed roots.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param ac Number \n bonus to AC
+ * @brief AC bonus
+ * @param dam Number \n bonus to melee to-damage
+ * @brief To-damage bonus
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_roots(int v, s16b ac, s16b dam);
+
+/** @fn set_shadow(int v)
+ * @brief Player has wraith form.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_shadow(int v);
+
+/** @fn set_parasite(int v, int r)
+ * @brief Player has timed parasite.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param r Number \n index of race in monster race array
+ * @brief Parasite race index
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * When the time remaining reaches 0, there is an 80% chance the parasite will
+ * be born, otherwise it will die away.
+ * @note (see file xtra2.c)
+ */
+extern bool set_parasite(int v, int r);
+
+/** @fn set_disrupt_shield(int v)
+ * @brief Player has timed disrupt shield (feels invulnerable).\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_disrupt_shield(int v);
+
+/** @fn set_prob_travel(int v)
+ * @brief Player has timed probability travel.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_prob_travel(int v);
+
+/** @fn set_project(int v, s16b gf, s16b dam, s16b rad, s16b flag)
+ * @brief Player's weapon has a spell effect.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param gf Number \n spell effect
+ * @brief Spell effect
+ * @param dam Number \n damage caused by spell effect
+ * @brief Spell damage
+ * @param rad Number \n radius of spell effect
+ * @brief Spell radius
+ * @param flag Number \n spell projection effect
+ * @brief Spell properties
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_project(int v, s16b gf, s16b dam, s16b rad, s16b flag);
+
+/** @fn set_tim_deadly(int v)
+ * @brief Player has deadly accuracy.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_deadly(int v);
+
+/** @fn set_tim_res_time(int v)
+ * @brief Player has timed time resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_res_time(int v);
+
+/** @fn set_tim_reflect(int v)
+ * @brief Player has timed reflection.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_reflect(int v);
+
+/** @fn set_meditation(int v)
+ * @brief Player can meditate (forcibly pseudo-id).\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_meditation(int v);
+
+/** @fn set_strike(int v)
+ * @brief Player has true strike.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_strike(int v);
+
+/** @fn set_walk_water(int v)
+ * @brief Player can walk on water.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_walk_water(int v);
+
+/** @fn set_tim_ffall(int v)
+ * @brief Player has timed levitation (feather-fall).\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_ffall(int v);
+
+/** @fn set_tim_fire_aura(int v)
+ * @brief Player has a timed fiery aura.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_fire_aura(int v);
+
+/** @fn set_tim_regen(int v, int p)
+ * @brief Player has timed regeneration.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param p Number \n power of regeneration
+ * @brief Regeneration power
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_regen(int v, int p);
+
+/** @fn set_holy(int v)
+ * @brief Player has a timed holy aura.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_holy(int v);
+
+/** @fn set_grace(s32b v)
+ * @brief Set the amount of grace a player has with a god.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range -30,000 to 30,000)
+ * @brief Grace
+ * @note (see file xtra2.c)
+ */
+extern void set_grace(s32b v);
+
+/** @fn set_mimic(int v, int p, int level)
+ * @brief Player has mimic form.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param p Number \n the mimic form
+ * @brief Mimic form
+ * @param level Number \n the level of the mimic form
+ * @brief Mimic level
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_mimic(int v, int p, int level);
+
+/** @fn set_no_breeders(int v)
+ * @brief Player has timed breeder prevention.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_no_breeders(int v);
+
+/** @fn set_tim_esp(int v)
+ * @brief Player has timed ESP.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_esp(int v);
+
+/** @fn set_invis(int v, int p)
+ * @brief Player has timed invisibility.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param p Number \n power of invisibility
+ * @brief Invisibility power
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_invis(int v, int p);
+
+/** @fn set_lite(int v)
+ * @brief Player has timed light.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Note the use of "PU_VIEW", which is needed to
+ * memorize any terrain features which suddenly become "visible".
+ * @note
+ * Note that blindness is currently the only thing which can affect
+ * "player_can_see_bold()".
+ * @note (see file xtra2.c)
+ */
+extern bool set_lite(int v);
+
+/** @fn set_blind(int v)
+ * @brief Player has timed blindness.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Note the use of "PU_UN_VIEW", which is needed to memorize any terrain
+ * features which suddenly become "visible".
+ * @note
+ * Note that blindness is currently the only thing which can affect
+ * "player_can_see_bold()".
+ * @note (see file xtra2.c)
+ */
+extern bool set_blind(int v);
+
+/** @fn set_confused(int v)
+ * @brief Player has timed confusion.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_confused(int v);
+
+/** @fn set_poisoned(int v)
+ * @brief Player has timed poisoning.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_poisoned(int v);
+
+/** @fn set_afraid(int v)
+ * @brief Player has timed fear.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_afraid(int v);
+
+/** @fn set_paralyzed(int v)
+ * @brief Player has timed paralysis.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_paralyzed(int v);
+
+/** @fn set_image(int v)
+ * @brief Player has timed hallucination.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Note that we must redraw the map when hallucination changes.
+ * @note (see file xtra2.c)
+ */
+extern bool set_image(int v);
+
+/** @fn set_fast(int v, int p)
+ * @brief Player has timed speed boost.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param p Number \n speed factor
+ * @brief Speed factor
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_fast(int v, int p);
+
+/** @fn set_light_speed(int v)
+ * @brief Player has timed light speed.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_light_speed(int v);
+
+/** @fn set_slow(int v)
+ * @brief Player has timed slowness.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_slow(int v);
+
+/** @fn set_shield(int v, int p, s16b o, s16b d1, s16b d2)
+ * @brief Player has timed mystic shield.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param p Number \n bonus to AC
+ * @brief AC bonus
+ * @param o Number \n type of shield (see SHIELD_foo fields)
+ * @brief Shield type
+ * @param d1 Number \n number of dice for damage roll
+ * @brief Damage dice
+ * @param d2 Number \n number of sides per die for damage roll
+ * @brief Damage sides
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_shield(int v, int p, s16b o, s16b d1, s16b d2);
+
+/* For calc_bonus hooks */
+/** @fn apply_flags(u32b f1, u32b f2, u32b f3, u32b f4, u32b f5, u32b esp, s16b pval = 0, s16b tval = 0, s16b to_h = 0, s16b to_d = 0, s16b to_a = 0)
+ * @brief Apply flags and values to the player.\n
+ * @param f1 Number \n flags to be applied to the player
+ * @brief Flag1
+ * @param f2 Number \n flags to be applied to the player
+ * @brief Flag2
+ * @param f3 Number \n flags to be applied to the player
+ * @brief Flag3
+ * @param f4 Number \n flags to be applied to the player
+ * @brief Flag4
+ * @param f5 Number \n flags to be applied to the player
+ * @brief Flag5
+ * @param esp Number \n ESP flag
+ * @brief Esp flag
+ * @param pval Number \n PVal to be applied to the player
+ * @brief Pval
+ * @param tval Number \n TVal to be applied to the player
+ * @brief Tval
+ * @param to_h Number \n to-hit bonus to be applied to the player
+ * @brief To-hit
+ * @param to_d Number \n to-damage bonus to be applied to the player
+ * @brief To-damage
+ * @param to_a Number \n AC bonus to be applied to the player
+ * @brief AC
+ * @note
+ * f1 can apply to attribuets, spell power, mana capacity, stealth, searching
+ * ability and frequency, infravision, digging, speed, extra blows, and
+ * earthquakes.
+ * @note
+ * f2 can apply to life capacity, sensible fire, invisibility, free action,
+ * hold life, immunities (except neither), resistances, reflection, and
+ * sustains.
+ * @note
+ * f3 can apply to extra shots, aggravate, teleport, drain XP, blessed, extra
+ * might, slow digestion, regeneration, lite, see invisible, wraith form,
+ * feather fall, fire sheath, electricity sheath, anti magic, and anti
+ * teleport.
+ * @note
+ * f4 can apply to lite, flying, climbing, nether immunity, precognition, and
+ * anti-magic power and radius.
+ * @note
+ * f5 can apply to luck, critical hits, drain mana, drain life, immovable,
+ * water breath, and magic breath.
+ * @note
+ * esp can apply to, well, just telepathy.
+ * @note
+ * pval can apply to attributes, luck, spell power, mana capacity, life
+ * capacity, stealth, search ability and frequency (x 5), infravision, digging
+ * (x 20), speed, extra blows, critical blows, invisibility (x 10), extra
+ * might, anti-magic power and radius.
+ * @note
+ * tval can apply to lite
+ * @note
+ * to_h, to_d, and to_ac can apply to anti-magic power and radius.
+ * @note (see file xtra1.c)
+ */
+extern void apply_flags(u32b f1, u32b f2, u32b f3, u32b f4, u32b f5, u32b esp, s16b pval = 0, s16b tval = 0, s16b to_h = 0, s16b to_d = 0, s16b to_a = 0);
+
+/** @name Shield effect options
+ * @{ */
+/** @def SHIELD_NONE */
+#define SHIELD_NONE 0x0000
+
+/** @def SHIELD_COUNTER */
+#define SHIELD_COUNTER 0x0001
+
+/** @def SHIELD_FIRE */
+#define SHIELD_FIRE 0x0002
+
+/** @def SHIELD_GREAT_FIRE */
+#define SHIELD_GREAT_FIRE 0x0004
+
+/** @def SHIELD_FEAR */
+#define SHIELD_FEAR 0x0008
+/** @} */
+
+
+/** @fn set_tim_thunder(int v, int p1, int p2)
+ * @brief Player has timed thunderstorm.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param p1 Number \n number of dice for damage roll
+ * @brief Damage dice
+ * @param p2 Number \n number of sides per die for damage roll
+ * @brief Damage sides
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_thunder(int v, int p1, int p2);
+
+/** @fn set_tim_breath(int v, bool magical)
+ * @brief Player has timed magic/water breath.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @param magical Boolean \n TRUE if player has magic breath, or FALSE if the
+ * player has water breath
+ * @brief Magic breath?
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_breath(int v, bool magical);
+
+/** @fn set_tim_fly(int v)
+ * @brief Player has timed flight.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_fly(int v);
+
+/** @fn set_blessed(int v)
+ * @brief Player has timed blessing.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Blessing gives +5 bonus AC and +10 bonus to-hit.
+ * @note (see file xtra2.c)
+ */
+extern bool set_blessed(int v);
+
+/** @fn set_hero(int v)
+ * @brief Player has timed heroism.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Heroism gives +10 bonus max HP, +12 bonus to-hit, and resist fear.
+ * @note (see file xtra2.c)
+ */
+extern bool set_hero(int v);
+
+/** @fn set_shero(int v)
+ * @brief Player has timed berserk strength.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Berserk strength gives +30 bonus max HP, +24 bonus to-hit, -10 penalty AC,
+ * and resist fear.
+ * @note (see file xtra2.c)
+ */
+extern bool set_shero(int v);
+
+/** @fn set_protevil(int v)
+ * @brief Player has timed protection from evil.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Protection from evil gives the player a chance to repel evil monsters.
+ * @note (see file xtra2.c)
+ */
+extern bool set_protevil(int v);
+
+/** @fn set_protgood(int v)
+ * @brief Player has timed protection from good.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Protection from good gives the player a chance to repel good monsters.
+ * @note (see file xtra2.c)
+ */
+extern bool set_protgood(int v);
+
+/** @fn set_protundead(int v)
+ * @brief Player has timed protection from undead.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Protection from undead protects against getting the Black Breath in a melee
+ * attack.
+ * @note (see file xtra2.c)
+ */
+extern bool set_protundead(int v);
+
+/** @fn set_invuln(int v)
+ * @brief Player has timed invulnerability.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Invulnerability prevents damage from walking on lava, walking the Straight
+ * Road, poison, cuts, and starvation. It gives +100 bonus to AC.
+ * @note
+ * It can be ended by the player attacking a monster, firing a missile,
+ * throwing an object, or activating a power.
+ * @note (see file xtra2.c)
+ */
+extern bool set_invuln(int v);
+
+/** @fn set_tim_invis(int v)
+ * @brief Player has timed "see invisibile".\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_invis(int v);
+
+/** @fn set_tim_infra(int v)
+ * @brief Player has timed infravision.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_tim_infra(int v);
+
+/** @fn set_mental_barrier(int v)
+ * @brief Player has timed mental barrier.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Mental barrier sustains intelligence and wisdom.
+ * @note (see file xtra2.c)
+ */
+extern bool set_mental_barrier(int v);
+
+/** @fn set_poison(int v)
+ * @brief Player has timed poison hands.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_poison(int v);
+
+/** @fn set_oppose_acid(int v)
+ * @brief Player has timed acid resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_oppose_acid(int v);
+
+/** @fn set_oppose_elec(int v)
+ * @brief Player has timed electricity resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_oppose_elec(int v);
+
+/** @fn set_oppose_fire(int v)
+ * @brief Player has timed fire resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_oppose_fire(int v);
+
+/** @fn set_oppose_cold(int v)
+ * @brief Player has timed cold resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_oppose_cold(int v);
+
+/** @fn set_oppose_pois(int v)
+ * @brief Player has timed poison resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_oppose_pois(int v);
+
+/** @fn set_oppose_ld(int v)
+ * @brief Player has timed light and dark resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_oppose_ld(int v);
+
+/** @fn set_oppose_cc(int v)
+ * @brief Player has timed chaos and confusion resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_oppose_cc(int v);
+
+/** @fn set_oppose_ss(int v)
+ * @brief Player has timed sound and shard resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_oppose_ss(int v);
+
+/** @fn set_oppose_nex(int v)
+ * @brief Player has timed nexus resistance.\n
+ * @param v Number \n time remaining until effect expires
+ * (must be in the range 0 to 10,000)
+ * @brief Time remaining
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note (see file xtra2.c)
+ */
+extern bool set_oppose_nex(int v);
+
+/** @fn set_stun(int v)
+ * @brief Player stun level changes.\n
+ * @param v Number \n the level of stun (must be in the range 0 to 10,000)
+ * @brief Stun level
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Note the special code to only notice "range" changes.
+ * @note
+ * Some races resist stunning.
+ * @note
+ * There is a v chance in 1000 or 1 in 16 that a stun will be the result of
+ * a vicious blow to the head. If so, the player will lose a point of
+ * intelligence, or wisdom, or both unless the stat is sustained.
+ * @note (see file xtra2.c)
+ */
+extern bool set_stun(int v);
+
+/** @fn set_cut(int v)
+ * @brief Player cut level changes.\n
+ * @param v Number \n the level of cut (must be in the range 0 to 10,000)
+ * @brief Cut level
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * Note the special code to only notice "range" changes.
+ * @note
+ * Some races resist cutting.
+ * @note
+ * There is a v chance in 1000 or 1 in 16 that a cut will result in scarrring.
+ * If so, the player will lose a point of charisma unless it is sustained.
+ * @note (see file xtra2.c)
+ */
+extern bool set_cut(int v);
+
+/** @fn set_food(int v)
+ * @brief Player hunger level changes.\n
+ * @param v Number \n the level of cut (must be in the range 0 to 10,000)
+ * @brief Cut level
+ * @return Boolean \n TRUE if player notices the effect, otherwise FALSE.
+ * @note
+ * The "p_ptr->food" variable can get as large as 20000, allowing the
+ * addition of the most "filling" item, Elvish Waybread, which adds
+ * 7500 food units, without overflowing the 32767 maximum limit.
+ * @note
+ * Perhaps we should disturb the player with various messages,
+ * especially messages about hunger status changes. XXX XXX XXX
+ * @note
+ * Digestion of food is handled in "dungeon.c", in which, normally,
+ * the player digests about 20 food units per 100 game turns, more
+ * when "fast", more when "regenerating", less with "slow digestion",
+ * but when the player is "gorged", he digests 100 food units per 10
+ * game turns, or a full 1000 food units per 100 game turns.
+ * @note
+ * Note that the player's speed is reduced by 10 units while gorged,
+ * so if the player eats a single food ration (5000 food units) when
+ * full (15000 food units), he will be gorged for (5000/100)*10 = 500
+ * game turns, or 500/(100/5) = 25 player turns (if nothing else is
+ * affecting the player speed).
+ * @note (see file xtra2.c)
+ */
+extern bool set_food(int v);
+
+/** @name Hunger flags
+ * @brief Player "food" crucial values
+ * @{ */
+/** @def PY_FOOD_MAX
+ * @note Food value (Bloated)
+ */
+#define PY_FOOD_MAX 15000
+/** @def PY_FOOD_FULL
+ * @note Food value (Normal)
+ */
+#define PY_FOOD_FULL 10000
+/** @def PY_FOOD_ALERT
+ * @note Food value (Hungry)
+ */
+#define PY_FOOD_ALERT 2000
+/** @def PY_FOOD_WEAK
+ * @note Food value (Weak)
+ */
+#define PY_FOOD_WEAK 1000
+/** @def PY_FOOD_FAINT
+ * @note Food value (Fainting)
+ */
+#define PY_FOOD_FAINT 500
+/** @def PY_FOOD_STARVE
+ * @note Food value (Starving)
+ */
+#define PY_FOOD_STARVE 100
+/** @} */
+
+/** @fn check_experience(void)
+ * @brief Check if player experience level has changed.\n
+ * @note
+ * If a player has achieved a level for the first time, give a corruption
+ * (1 chance in 3) if it applies, increase skill points, check ability levels,
+ * and add a note if notes are taken.
+ * @note (see file xtra2.c)
+ */
+extern void check_experience(void);
+
+/** @fn check_experience_obj(object_type *o_ptr)
+ * @brief Check if object "o_ptr" experience level has changed.\n
+ * @param *o_ptr object_type \n the object
+ * @brief Object
+ * @note
+ * If an object has achieved a level for the first time, apply gains.
+ * @note (see file xtra2.c)
+ */
+extern void check_experience_obj(object_type *o_ptr);
+
+/** @fn gain_exp(s32b amount)
+ * @brief Gain "amount" of experience.\n
+ * @param amount Number \n the experience points to gain.
+ * @brief Experience
+ * @note
+ * Count the number of objects which will gain experience. The objects share
+ * equally 2/3 of "amount". Give corruption if it applies. Gain experience.
+ * If experience is less than maximum, then increase maximum experience by 20%
+ * of "amount". Check for level change and print experience (check_experience).
+ * @note (see file xtra2.c)
+ */
+extern void gain_exp(s32b amount);
+
+/** @fn lose_exp(s32b amount)
+ * @brief Decrease experience by "amount".\n
+ * @param amount Number \n the experience points to lose.
+ * @brief Experience
+ * @note
+ * Experience can not fall below zero. Check for level change and print
+ * experience (check_experience).
+ * @note (see file xtra2.c)
+ */
+extern void lose_exp(s32b amount);
+
+/** @fn no_lite(void)
+ * @brief Return true if the player's grid is dark.
+ * @return Boolean \n TRUE if the player's grid is dark, otherwise FALSE.
+ * @note (see file cave.c)
+ */
+extern bool no_lite(void);
+
+/** @var dun_level
+ * @brief Number
+ * @note Current dungeon level
+ */
+extern s16b dun_level;
+
+
+/** @name Gods
+ * @{ */
+/** @def GOD_ALL */
+#define GOD_ALL -1
+
+/** @def GOD_NONE */
+#define GOD_NONE 0
+
+/** @def GOD_ERU */
+#define GOD_ERU 1
+
+/** @def GOD_MANWE */
+#define GOD_MANWE 2
+
+/** @def GOD_TULKAS */
+#define GOD_TULKAS 3
+
+/** @def GOD_MELKOR */
+#define GOD_MELKOR 4
+
+/** @def GOD_YAVANNA */
+#define GOD_YAVANNA 5
+/** @} */
+
+
+/** @fn inc_piety(int god, s32b amt)
+ * @brief Increase piety for god "god" by amount "amt".\n
+ * @param god Number \n the god
+ * @brief God
+ * @param amt Number \n the amount of piety
+ * @brief Piety
+ * @note
+ * If the player worships all gods, or "god", the piety (grace) will increase.
+ * @note (see file gods.c)
+ */
+extern void inc_piety(int god, s32b amt);
+
+/** @fn abandon_god(int god)
+ * @brief Player renounces their religion.\n
+ * @param god Number \n the god
+ * @brief God
+ * @note
+ * If the player worships all gods or "god", the player worships no god and
+ * the piety score is set to 0.
+ * @note (see file gods.c)
+ */
+extern void abandon_god(int god);
+
+/** @fn wisdom_scale(int max)
+ * @brief Rescale the wisdom value to a 0 <-> max range.\n
+ * @param max Number \n the new maximum value of the rescaled wisdom
+ * @brief New maximum wisdom
+ * @return Number \n The rescaled value of player wisdom.
+ * @note (see file gods.c)
+ */
+extern int wisdom_scale(int max);
+
+/** @fn follow_god(int god, bool silent)
+ * @brief Player starts to follow god "god".\n
+ * @param god Number \n the god
+ * @brief God
+ * @param silent Boolean \n TRUE if Melkor message is displayed, otherwise
+ * FALSE.
+ * @brief Show message?
+ * @note
+ * Unbelievers can not follow a god.
+ * @note
+ * If the player does not worship a god, they start worshipping "god". If the
+ * god is Melkor, the player gains the Udun skill (show a message if silent is
+ * FALSE).
+ * @note (see file gods.c)
+ */
+extern void follow_god(int god, bool silent);
+
+/** @fn add_new_gods(char *name)
+ * @brief Add a new god to the deity array.\n
+ * @param *name String \n the name of the god
+ * @brief God name
+ * @return Number \n The index of the new god inthe deity array.
+ * @note (see file lua_bind.c)
+ */
+extern s16b add_new_gods(char *name);
+
+/** @fn desc_god(int g_idx, int d, char *desc)
+ * @brief Return line "d" of the description of god with god index "g_idx".\n
+ * @param g_idx Number \n the index of god in the deity array.
+ * @brief God index
+ * @param d Number \n the line of the description
+ * (must be in the range 0 to 9).
+ * @brief Line of description
+ * @param *desc String
+ * @brief Description
+ * @return *desc String \n Line "d" of the god description.
+ * @note (see file lua_bind.c)
+ */
+extern void desc_god(int g_idx, int d, char *desc);
+
+/** @name Powers
+ * @{ */
+/** @def PWR_SPIT_ACID
+ * @note Spit acid (GF_ACID) */
+#define PWR_SPIT_ACID 0
+
+/** @def PWR_BR_FIRE
+ * @note Breathe fire (GF_FIRE) */
+#define PWR_BR_FIRE 1
+
+/** @def PWR_HYPN_GAZE
+ * @note Hypnotic gaze */
+#define PWR_HYPN_GAZE 2
+
+/** @def PWR_TELEKINES
+ * @note Telekinesis (fetch an object) */
+#define PWR_TELEKINES 3
+
+/** @def PWR_VTELEPORT
+ * @note Teleport */
+#define PWR_VTELEPORT 4
+
+/** @def PWR_MIND_BLST
+ * @note Mind blast (GF_PSI) */
+#define PWR_MIND_BLST 5
+
+/** @def PWR_RADIATION
+ * @note Emit radiation (GF_NUKE) */
+#define PWR_RADIATION 6
+
+/** @def PWR_VAMPIRISM
+ * @note Vampire bite */
+#define PWR_VAMPIRISM 7
+
+/** @def PWR_SMELL_MET
+ * @note Detect treasure */
+#define PWR_SMELL_MET 8
+
+/** @def PWR_SMELL_MON
+ * @note Detect normal monsters */
+#define PWR_SMELL_MON 9
+
+/** @def PWR_BLINK
+ * @note Short teleport (up to 10 grids) */
+#define PWR_BLINK 10
+
+/** @def PWR_EAT_ROCK
+ * @note Eat rock for food (wall to mud) */
+#define PWR_EAT_ROCK 11
+
+/** @def PWR_SWAP_POS
+ * @note Swap position with a monster */
+#define PWR_SWAP_POS 12
+
+/** @def PWR_SHRIEK
+ * @note Shriek (GF_SOUND and aggravate) */
+#define PWR_SHRIEK 13
+
+/** @def PWR_ILLUMINE
+ * @note Lite area */
+#define PWR_ILLUMINE 14
+
+/** @def PWR_DET_CURSE
+ * @note Detect cursed items in inventory */
+#define PWR_DET_CURSE 15
+
+/** @def PWR_BERSERK
+ * @note Berserk rage */
+#define PWR_BERSERK 16
+
+/** @def PWR_POLYMORPH
+ * @note Polymorph self */
+#define PWR_POLYMORPH 17
+
+/** @def PWR_MIDAS_TCH
+ * @note Midas touch - turn an item into gold */
+#define PWR_MIDAS_TCH 18
+
+/** @def PWR_GROW_MOLD
+ * @note Summon mold */
+#define PWR_GROW_MOLD 19
+
+/** @def PWR_RESIST
+ * @note Temporary elemental resist */
+#define PWR_RESIST 20
+
+/** @def PWR_EARTHQUAKE
+ * @note Cause an earthquake (destruction) */
+#define PWR_EARTHQUAKE 21
+
+/** @def PWR_EAT_MAGIC
+ * @note Absorb energy from magic items */
+#define PWR_EAT_MAGIC 22
+
+/** @def PWR_WEIGH_MAG
+ * @note Report magic affecting player */
+#define PWR_WEIGH_MAG 23
+
+/** @def PWR_STERILITY
+ * @note Player experiences forced abstinence */
+#define PWR_STERILITY 24
+
+/** @def PWR_PANIC_HIT
+ * @note Hit a monster and run away */
+#define PWR_PANIC_HIT 25
+
+/** @def PWR_DAZZLE
+ * @note Stun, confuse, and turn monsters */
+#define PWR_DAZZLE 26
+
+/** @def PWR_DARKRAY
+ * @note Fire a beam of light (GF_LITE) */
+#define PWR_DARKRAY 27
+
+/** @def PWR_RECALL
+ * @note Recall to dungeon/town */
+#define PWR_RECALL 28
+
+/** @def PWR_BANISH
+ * @note Banish evil creatures */
+#define PWR_BANISH 29
+
+/** @def PWR_COLD_TOUCH
+ * @note Bolt of cold (GF_COLD) */
+#define PWR_COLD_TOUCH 30
+
+/** @def PWR_LAUNCHER
+ * @note Increase the multiplier for a thrown object */
+#define PWR_LAUNCHER 31
+
+/** @def PWR_PASSWALL
+ * @note Walk through a wall */
+#define PWR_PASSWALL 32
+
+/** @def PWR_DETECT_TD
+ * @note Detect traps, doors, and stairs */
+#define PWR_DETECT_TD 33
+
+/** @def PWR_COOK_FOOD
+ * @note Create some food */
+#define PWR_COOK_FOOD 34
+
+/** @def PWR_UNFEAR
+ * @note Remove fear */
+#define PWR_UNFEAR 35
+
+/** @def PWR_EXPL_RUNE
+ * @note Set an explosive rune */
+#define PWR_EXPL_RUNE 36
+
+/** @def PWR_STM
+ * @note Bash a wall (stone to mud) */
+#define PWR_STM 37
+
+/** @def PWR_POIS_DART
+ * @note Throw a poison dart (GF_POIS) */
+#define PWR_POIS_DART 38
+
+/** @def PWR_MAGIC_MISSILE
+ * @note Fire a magic missile (GF_MISSILE) */
+#define PWR_MAGIC_MISSILE 39
+
+/** @def PWR_GROW_TREE
+ * @note Grow trees around the player */
+#define PWR_GROW_TREE 40
+
+/** @def PWR_BR_COLD
+ * @note Breathe cold (GF_COLD) */
+#define PWR_BR_COLD 41
+
+/** @def PWR_BR_CHAOS
+ * @note Breathe chaos (GF_CHAOS) */
+#define PWR_BR_CHAOS 42
+
+/** @def PWR_BR_ELEM
+ * @note Breath elements (GF_MISSILE) */
+#define PWR_BR_ELEM 43
+
+/** @def PWR_WRECK_WORLD
+ * @note Change the world (new level) */
+#define PWR_WRECK_WORLD 44
+
+/** @def PWR_SCARE
+ * @note Howl to scare monsters */
+#define PWR_SCARE 45
+
+/** @def PWR_REST_LIFE
+ * @note Restore life levels */
+#define PWR_REST_LIFE 46
+
+/** @def PWR_SUMMON_MONSTER
+ * @note Beastmaster powers (summon pets) */
+#define PWR_SUMMON_MONSTER 47
+
+/** @def PWR_NECRO
+ * @note Cast a necromancy spell */
+#define PWR_NECRO 48
+
+/** @def PWR_ROHAN
+ * @note Use flash aura or light speed jump */
+#define PWR_ROHAN 49
+
+/** @def PWR_THUNDER
+ * @note Use thunder strike, ride the straight road, or go back in town */
+#define PWR_THUNDER 50
+
+/** @def PWR_DEATHMOLD
+ * @note Use deathmold powers:\n
+ * (a) Teleport to a specific place\n
+ * (b) Fetch an item\n
+ * (c) Go up 50'\n
+ * (d) Go down 50'
+ */
+#define PWR_DEATHMOLD 51
+
+/** @def PWR_HYPNO
+ * @note Hypnotise a pet */
+#define PWR_HYPNO 52
+
+/** @def PWR_UNHYPNO
+ * @note Unhypnotise a pet */
+#define PWR_UNHYPNO 53
+
+/** @def PWR_INCARNATE
+ * @note Incarnate into a body */
+#define PWR_INCARNATE 54
+
+/** @def PWR_MAGIC_MAP
+ * @note Magic mapping */
+#define PWR_MAGIC_MAP 55
+
+/** @def PWR_LAY_TRAP
+ * @note Set a trap */
+#define PWR_LAY_TRAP 56
+
+/** @def PWR_MERCHANT
+ * @note Appraise item, warp item, or identify item */
+#define PWR_MERCHANT 57
+
+/** @def PWR_COMPANION
+ * @note Create a companion */
+#define PWR_COMPANION 58
+
+/** @def PWR_BEAR
+ * @note Mimic a bear */
+#define PWR_BEAR 59
+
+/** @def PWR_DODGE
+ * @note Report chance of dodging a monster */
+#define PWR_DODGE 60
+
+/** @def PWR_BALROG
+ * @note Mimic a balrog */
+#define PWR_BALROG 61
+/** @} */
+
+/* Misc */
+/** @fn do_cmd_throw(void)
+ * @brief Throw an object from the pack or floor.
+ * @note
+ * Note: "unseen" monsters are very hard to hit.
+ * @note
+ * Should throwing a weapon do full damage? Should it allow the magic
+ * to hit bonus of the weapon to have an effect? Should it ever cause
+ * the item to be destroyed? Should it do any damage at all?
+ * @note (see file cmd2.c)
+ */
+extern void do_cmd_throw(void);
+
+/** @fn change_wild_mode()
+ * @brief Toggle between big map and little map.
+ * @note
+ * If the player is immovable, and the map is big, the player receives a
+ * warning and is allowed to proceed.
+ * @note
+ * If the player is about to be recalled, and the map is big, the map is
+ * not changed.
+ * @note
+ * The map is changed. The game is saved if autosave is set to "levels".
+ * @note (see file spells2.c)
+ */
+extern void change_wild_mode();
+
+/** @fn switch_class(int sclass)
+ * @brief Change to an other class.\n
+ * @param sclass Number \n the inex of the new class in the class array
+ * @brief Class index
+ * @note (see file xtra2.c)
+ */
+extern void switch_class(int sclass);
+
+/** @fn switch_subclass(int sclass)
+ * @brief Change to an other subclass.\n
+ * @param sclass Number \n the new subclass
+ * @brief Subclass
+ * @note (see file xtra2.c)
+ */
+extern void switch_subclass(int sclass);
+
+/** @fn switch_subrace(int racem, bool copy_old)
+ * @brief Change to an other subrace.\n
+ * @param racem Number \n index of subrace in subrace array
+ * @brief Subrace index
+ * @param copy_old Boolean \n TRUE if the new subrace is to be saved,
+ * otherwise FALSE.
+ * @brief Copy old subrace?
+ * @note (see file xtra2.c)
+ */
+extern void switch_subrace(int racem, bool copy_old);
+
+/** @fn get_subrace_title(int racem)
+ * @brief Return the subrace title.\n
+ * @param racem Number \n index of subrace in subrace array
+ * @brief Subrace index
+ * @return String \n Title of subrace.
+ * @note (see file xtra2.c)
+ */
+extern cptr get_subrace_title(int racem);
+
+/** @fn set_subrace_title(int racem, cptr name)
+ * @brief Set the subrace title.\n
+ * @param racem Number \n index of subrace in subrace array
+ * @brief Subrace index
+ * @param name String \n new title of subrace
+ * @brief New title
+ * @note (see file xtra2.c)
+ */
+extern void set_subrace_title(int racem, cptr name);
+
+/** @fn do_rebirth()
+ * @brief The player is reborn after a class, race, or subrace change.
+ * @note
+ * The experience factor is recalculated. The hit dice are reset and new HP
+ * are calculated. There may be a level change involved.
+ * @note (see file xtra2.c)
+ */
+extern void do_rebirth();
+
+/* Player race flags */
+$static bool lua_test_race_flags(int slot, u32b flags) { if (slot == 1) return (PRACE_FLAG(flags)) ? TRUE : FALSE; else return (PRACE_FLAG2(flags)) ? TRUE : FALSE; }
+/** @fn test_race_flags(int slot, u32b flags);
+ * @brief Test flag "flags" against race flags, race modifier flags, class
+ * flags, and specialist flags.\n
+ * @param slot Number \n 1 if testing against first set of flags (PRACE_FLAG),
+ * 2 if testing against second set of flags (PRACE_FLAG2)
+ * @brief Flag selecter.
+ * @param flags Number \n the flags to be tested
+ * @brief Test flags
+ * @return Boolean \n TRUE if test flags match any of the corresponding race,
+ * race modifier, class, and specialist flags.
+ * @note (see file w_player.c)
+ */
+static bool lua_test_race_flags@test_race_flags(int slot, u32b flags);
+
+/** @name Winner states
+ * @{ */
+/** @def WINNER_NORMAL
+ * @note Player has killed Morgoth */
+#define WINNER_NORMAL 1
+
+/** @def WINNER_ULTRA
+ * @note Player has killed Melkor */
+#define WINNER_ULTRA 2
+/** @} */
+
+/** @var wizard
+ * @brief Boolean
+ * @note TRUE if player currently in Wizard mode, otherwise FALSE.
+ */
+extern bool wizard;
+
+/** @var total_winner
+ * @brief Number
+ * @note Game has been won (see WINNER_foo fields).
+ */
+extern u16b total_winner;
+
+/** @var has_won
+ * @brief Number
+ * @note Game has been won (see WINNER_foo fields).
+ */
+extern u16b has_won;
+
+/** @var joke_monsters
+ * @brief Boolean
+ * @note TRUE if allowing joke monsters, otherwise FALSE.
+ */
+extern bool joke_monsters;
+
+extern s16b max_dlv[999999];
diff --git a/src/player_c.pkg b/src/player_c.pkg
new file mode 100644
index 00000000..f55f9325
--- /dev/null
+++ b/src/player_c.pkg
@@ -0,0 +1,1060 @@
+/* File: player_c.pkg */
+
+/*
+ * Purpose: Lua interface defitions for player classes.
+ * To be processed by tolua to generate C source code.
+ */
+
+$#include "angband.h"
+
+/** @typedef cptr
+ * @note String
+ */
+typedef char* cptr;
+/** @typedef errr
+ * @note Number
+ */
+typedef int errr;
+/** @typedef bool
+ * @note Boolean
+ */
+typedef unsigned char bool;
+/** @typedef byte
+ * @note Number
+ */
+typedef unsigned char byte;
+/** @typedef s16b
+ * @note Number
+ */
+typedef signed short s16b;
+/** @typedef u16b
+ * @note Number
+ */
+typedef unsigned short u16b;
+/** @typedef s32b
+ * @note Number
+ */
+typedef signed int s32b;
+/** @typedef u32b
+ * @note Number
+ */
+typedef unsigned int u32b;
+
+/** @struct player_class
+ * @brief Player class
+ */
+struct player_class
+{
+ /** @structvar title
+ * @brief Number
+ * @note Type of class
+ */
+ s32b title;
+ /** @structvar desc
+ * @brief Number
+ * @note Small desc of the class
+ */
+ s32b desc;
+ /** @structvar titles[10]
+ * @brief Number
+ */
+ s32b titles[10];
+
+ /** @structvar c_adj[6]
+ * @brief Number
+ * @note Class stat modifier
+ */
+ s16b c_adj[6];
+
+ /** @structvar c_dis
+ * @brief Number
+ * @note class disarming
+ */
+ s16b c_dis;
+ /** @structvar c_dev
+ * @brief Number
+ * @note class magic devices
+ */
+ s16b c_dev;
+ /** @structvar c_sav
+ * @brief Number
+ * @note class saving throws
+ */
+ s16b c_sav;
+ /** @structvar c_stl
+ * @brief Number
+ * @note class stealth
+ */
+ s16b c_stl;
+ /** @structvar c_srh
+ * @brief Number
+ * @note class searching ability
+ */
+ s16b c_srh;
+ /** @structvar c_fos
+ * @brief Number
+ * @note class searching frequency
+ */
+ s16b c_fos;
+ /** @structvar c_thn
+ * @brief Number
+ * @note class to hit (normal)
+ */
+ s16b c_thn;
+ /** @structvar c_thb
+ * @brief Number
+ * @note class to hit (bows)
+ */
+ s16b c_thb;
+
+ /** @structvar x_dis
+ * @brief Number
+ * @note extra disarming
+ */
+ s16b x_dis;
+ /** @structvar x_dev
+ * @brief Number
+ * @note extra magic devices
+ */
+ s16b x_dev;
+ /** @structvar x_sav
+ * @brief Number
+ * @note extra saving throws
+ */
+ s16b x_sav;
+ /** @structvar x_stl
+ * @brief Number
+ * @note extra stealth
+ */
+ s16b x_stl;
+ /** @structvar x_srh
+ * @brief Number
+ * @note extra searching ability
+ */
+ s16b x_srh;
+ /** @structvar x_fos
+ * @brief Number
+ * @note extra searching frequency
+ */
+ s16b x_fos;
+ /** @structvar x_thn
+ * @brief Number
+ * @note extra to hit (normal)
+ */
+ s16b x_thn;
+ /** @structvar x_thb
+ * @brief Number
+ * @note extra to hit (bows)
+ */
+ s16b x_thb;
+
+ /** @structvar c_mhp
+ * @brief Number
+ * @note Class hit-dice adjustment
+ */
+ s16b c_mhp;
+ /** @structvar c_exp
+ * @brief Number
+ * @note Class experience factor
+ */
+ s16b c_exp;
+
+ /** @structvar powers[4]
+ * @brief Number
+ * @note Powers of the class
+ */
+ s16b powers[4];
+
+ /** @structvar spell_book
+ * @brief Number
+ * @note Tval of spell books (if any)
+ */
+ s16b spell_book;
+ /** @structvar spell_stat
+ * @brief Number
+ * @note Stat for spells (if any)
+ */
+ s16b spell_stat;
+ /** @structvar spell_lev
+ * @brief Number
+ * @note The higher it is the higher the spells level are
+ */
+ s16b spell_lev;
+ /** @structvar spell_fail
+ * @brief Number
+ * @note The higher it is the higher the spells failure are
+ */
+ s16b spell_fail;
+ /** @structvar spell_mana
+ * @brief Number
+ * @note The higher it is the higher the spells mana are
+ */
+ s16b spell_mana;
+ /** @structvar spell_first
+ * @brief Number
+ * @note Level of first spell
+ */
+ s16b spell_first;
+ /** @structvar spell_weight
+ * @brief Number
+ * @note Weight that hurts spells
+ */
+ s16b spell_weight;
+ /** @structvar max_spell_level
+ * @brief Number
+ * @note Maximun spell level
+ */
+ byte max_spell_level;
+ /** @structvar magic_max_spell
+ * @brief Number
+ * @note Maximun numbner of spells one can learn by natural means
+ */
+ byte magic_max_spell;
+
+ /** @structvar flags1
+ * @brief Number
+ * @note flags
+ */
+ s32b flags1;
+
+ /** @structvar mana
+ * @brief Number
+ */
+ s16b mana;
+ /** @structvar blow_num
+ * @brief Number
+ */
+ s16b blow_num;
+ /** @structvar blow_wgt
+ * @brief Number
+ */
+ s16b blow_wgt;
+ /** @structvar blow_mul
+ * @brief Number
+ */
+ s16b blow_mul;
+ /** @structvar extra_blows
+ * @brief Number
+ */
+ s16b extra_blows;
+
+ /** @structvar sense_base
+ * @brief Number
+ */
+ s32b sense_base;
+ /** @structvar sense_pl
+ * @brief Number
+ */
+ s32b sense_pl;
+ /** @structvar sense_plus
+ * @brief Number
+ */
+ s32b sense_plus;
+ /** @structvar sense_heavy
+ * @brief Number
+ */
+ byte sense_heavy;
+ /** @structvar sense_heavy_magic
+ * @brief Number
+ */
+ byte sense_heavy_magic;
+};
+
+/** @var *cp_ptr
+ * @brief player_class
+ * @note Player class information
+ */
+extern player_class *cp_ptr;
+
+
+
+/** @struct skill_type
+ * @brief Skills
+ */
+struct skill_type
+{
+ /** @structvar name
+ * @brief Number
+ * @note Name
+ */
+ u32b name;
+ /** @structvar desc
+ * @brief Number
+ * @note Description
+ */
+ u32b desc;
+ /** @structvar action_desc
+ * @brief Number
+ * @note Action Description
+ */
+ u32b action_desc;
+
+ /** @structvar action_mkey
+ * @brief Number
+ * @note Action do to
+ */
+ s16b action_mkey;
+
+ /** @structvar i_value
+ * @brief Number
+ * @note Actual value
+ */
+ u32b i_value;
+ /** @structvar i_mod
+ * @brief Number
+ * @note Modifier(1 skill point = modifier skill)
+ */
+ u16b i_mod;
+
+ /** @structvar value
+ * @brief Number
+ * @note Actual value
+ */
+ u32b value;
+ /** @structvar mod
+ * @brief Number
+ * @note Modifier(1 skill point = modifier skill)
+ */
+ u16b mod;
+ /** @structvar rate
+ * @brief Number
+ * @note Modifier decreasing rate
+ */
+ s16b rate;
+
+ /** @structvar uses
+ * @brief Number
+ * @note Number of times used
+ */
+ u32b uses;
+
+ /** @structvar action[9999]
+ * @brief Number
+ * @note List of actions against other skills
+ */
+ s16b action[9999];
+
+ /** @structvar father
+ * @brief Number
+ * @note Father in the skill tree
+ */
+ s16b father;
+ /** @structvar dev
+ * @brief Boolean
+ * @note Is the branch developped ?
+ */
+ bool dev;
+ /** @structvar order
+ * @brief Number
+ * @note Order in the tree
+ */
+ s16b order;
+ /** @structvar hidden
+ * @brief Boolean
+ * @note Innactive
+ */
+ bool hidden;
+};
+
+/** @def MAX_SKILLS
+ * @brief Maximum number of skills
+ */
+#define MAX_SKILLS 100
+
+
+$static cptr get_skill_name(int i) { return s_name + s_info[i].name; }
+/** @fn get_skill_name(int i)
+ * @brief Return name of skill with index "i" in skill array.\n
+ * @param i Number \n the index of skill in skill array.
+ * @brief Skill index
+ * @return String \n The name of the skill with index "i" in the skill array.
+ * @note (see file w_play_c.c)
+ */
+static cptr get_skill_name(int i);
+
+/** @var old_max_s_idx
+ * @brief Number
+ * @note Previous maximum skill index
+ */
+extern u16b old_max_s_idx;
+/** @var max_s_idx
+ * @brief Number
+ * @note Current maximum skill index
+ */
+extern u16b max_s_idx;
+/** @var s_info[MAX_SKILLS]
+ * @brief skill_type
+ * @note Array of player skills
+ */
+skill_type s_info[MAX_SKILLS];
+
+/** @name Skills
+ * @{ */
+/** @def SKILL_CONVEYANCE
+ * @brief Conveyance
+ * @note
+ * Ability to learn and use spells from the Conveyance school
+ */
+#define SKILL_CONVEYANCE 1
+
+/** @def SKILL_MANA
+ * @brief Mana
+ * @note
+ * Ability to learn and use spells from the Mana school
+ */
+#define SKILL_MANA 2
+
+/** @def SKILL_FIRE
+ * @brief Fire
+ * @note
+ * Ability to learn and use spells from the Fire school
+ */
+#define SKILL_FIRE 3
+
+/** @def SKILL_AIR
+ * @brief Air
+ * @note
+ * Ability to learn and use spells from the Air school
+ */
+#define SKILL_AIR 4
+
+/** @def SKILL_WATER
+ * @brief Water
+ * @note
+ * Ability to learn and use spells from the Water school
+ */
+#define SKILL_WATER 5
+
+/** @def SKILL_NATURE
+ * @brief Nature
+ * @note
+ * Ability to learn and use spells from the Nature school
+ */
+#define SKILL_NATURE 6
+
+/** @def SKILL_EARTH
+ * @brief Earth
+ * @note
+ * Ability to learn and use spells from the Earth school
+ */
+#define SKILL_EARTH 7
+
+/** @def SKILL_SYMBIOTIC
+ * @brief Symbiosis
+ * @note
+ * Ability to enter in symbiosis with monsters unable to move by themselves
+ */
+#define SKILL_SYMBIOTIC 8
+
+/** @def SKILL_MUSIC
+ * @brief Music
+ * @note
+ * Ability to learn and sing songs
+ */
+#define SKILL_MUSIC 9
+
+/** @def SKILL_DIVINATION
+ * @brief Divination
+ * @note
+ * Ability to learn and use spells from the Divination school
+ */
+#define SKILL_DIVINATION 10
+
+/** @def SKILL_TEMPORAL
+ * @brief Temporal
+ * @note
+ * Ability to learn and use spells from the Temporal school
+ */
+#define SKILL_TEMPORAL 11
+
+/** @def SKILL_DRUID
+ * @brief Druidistic
+ * @note
+ * Ability to learn and use prayers from the Druidistic realm
+ */
+#define SKILL_DRUID 12
+
+/** @def SKILL_DAEMON
+ * @brief Demonology
+ * @note
+ * Ability to use incantations from the Demonblades
+ */
+#define SKILL_DAEMON 13
+
+/** @def SKILL_META
+ * @brief Meta
+ * @note
+ * Ability to learn and use spells from the Meta school
+ */
+#define SKILL_META 14
+
+/** @def SKILL_MAGIC
+ * @brief Magic
+ * @note
+ * General ability to do magic, also affect mana reserves and
+ * magic device ability. Helps pseudo-id of magic objects
+ */
+#define SKILL_MAGIC 15
+
+/** @def SKILL_COMBAT
+ * @brief Combat
+ * @note
+ * General ability to fight and to pseudo-id armours and weapons.
+ * It also allows to use heavier armours without penalties
+ */
+#define SKILL_COMBAT 16
+
+/** @def SKILL_MASTERY
+ * @brief Weaponmastery
+ * @note
+ * General ability to use melee weapons
+ */
+#define SKILL_MASTERY 17
+
+/** @def SKILL_SWORD
+ * @brief Sword-mastery
+ * @note
+ * Ability to use swords
+ */
+#define SKILL_SWORD 18
+
+/** @def SKILL_AXE
+ * @brief Axe-mastery
+ * @note
+ * Ability to use axes
+ */
+#define SKILL_AXE 19
+
+/** @def SKILL_POLEARM
+ * @brief Polearm-mastery
+ * @note
+ * Ability to use polearms
+ */
+#define SKILL_POLEARM 20
+
+/** @def SKILL_HAFTED
+ * @brief Hafted-mastery
+ * @note
+ * Ability to use hafted weapons
+ */
+#define SKILL_HAFTED 21
+
+/** @def SKILL_BACKSTAB
+ * @brief Backstab
+ * @note
+ * Ability to backstab fleeing and sleeping monsters to increase damage
+ */
+#define SKILL_BACKSTAB 22
+
+/** @def SKILL_ARCHERY
+ * @brief Archery
+ * @note
+ * General ability to use ranged weapons
+ */
+#define SKILL_ARCHERY 23
+
+/** @def SKILL_SLING
+ * @brief Sling-mastery
+ * @note
+ * Ability to use slings
+ */
+#define SKILL_SLING 24
+
+/** @def SKILL_BOW
+ * @brief Bow-mastery
+ * @note
+ * Ability to use bows
+ */
+#define SKILL_BOW 25
+
+/** @def SKILL_XBOW
+ * @brief Crossbow-mastery
+ * @note
+ * Ability to use crossbows
+ */
+#define SKILL_XBOW 26
+
+/** @def SKILL_BOOMERANG
+ * @brief Boomerang-mastery
+ * @note
+ * Ability to use boomerangs
+ */
+#define SKILL_BOOMERANG 27
+
+/** @def SKILL_SPIRITUALITY
+ * @brief Spirituality
+ * @note
+ * General ability to use spiritual skills and also influence Saving Throw
+ */
+#define SKILL_SPIRITUALITY 28
+
+/** @def SKILL_MINDCRAFT
+ * @brief Mindcraft
+ * @note
+ * Ability to focus the powers of the mind
+ */
+#define SKILL_MINDCRAFT 29
+
+/** @def SKILL_MISC
+ * @brief Misc
+ * @note
+ * Not a real skill, it is only used to regroup some skills
+ */
+#define SKILL_MISC 30
+
+/** @def SKILL_NECROMANCY
+ * @brief Necromancy
+ * @note
+ * Ability to harness the powers of the dead
+ */
+#define SKILL_NECROMANCY 31
+
+/** @def SKILL_MIMICRY
+ * @brief Mimicry
+ * @note
+ * Ability to use cloaks of mimicry to change form
+ */
+#define SKILL_MIMICRY 32
+
+/** @def SKILL_ANTIMAGIC
+ * @brief Antimagic
+ * @note
+ * Ability to generates an antimagic field
+ */
+#define SKILL_ANTIMAGIC 33
+
+/** @def SKILL_RUNECRAFT
+ * @brief Runecraft
+ * @note
+ * Ability to combine magic runes to create your own spells
+ */
+#define SKILL_RUNECRAFT 34
+
+/** @def SKILL_SNEAK
+ * @brief Sneakiness
+ * @note
+ * General ability at the sneakiness skills
+ */
+#define SKILL_SNEAK 35
+
+/** @def SKILL_STEALTH
+ * @brief Stealth
+ * @note
+ * Ability to move unnoticed, silently
+ */
+#define SKILL_STEALTH 36
+
+/** @def SKILL_DISARMING
+ * @brief Disarming
+ * @note
+ * Ability to disarm the various traps
+ */
+#define SKILL_DISARMING 37
+
+/* XXX */
+
+/** @def SKILL_ALCHEMY
+ * @brief Alchemy
+ * @note
+ * Ability to use essences to modify/create magic items
+ */
+#define SKILL_ALCHEMY 39
+
+/** @def SKILL_STEALING
+ * @brief Stealing
+ * @note
+ * Ability to steal objects
+ */
+#define SKILL_STEALING 40
+
+/** @def SKILL_SORCERY
+ * @brief Sorcery
+ * @note
+ * Ability to use all the magic schools as if their skill was sorcery
+ */
+#define SKILL_SORCERY 41
+
+/** @def SKILL_HAND
+ * @brief Barehand-combat
+ * @note
+ * Ability to fight barehanded
+ */
+#define SKILL_HAND 42
+
+/** @def SKILL_THAUMATURGY
+ * @brief Thaumaturgy
+ * @note
+ * Ability to gain and cast innate spells
+ */
+#define SKILL_THAUMATURGY 43
+
+/** @def SKILL_SUMMON
+ * @brief Summoning
+ * @note
+ * Ability to create totems from monsters and use them to summon monsters
+ */
+#define SKILL_SUMMON 44
+
+/** @def SKILL_SPELL
+ * @brief Spell-power
+ * @note
+ * Ability to increase the power of spells
+ */
+#define SKILL_SPELL 45
+
+/** @def SKILL_DODGE
+ * @brief Dodging
+ * @note
+ * Ability to dodge blows and bolts
+ */
+#define SKILL_DODGE 46
+
+/** @def SKILL_BEAR
+ * @brief Bearform-combat
+ * @note
+ * Ability to fight in bear form
+ */
+#define SKILL_BEAR 47
+
+/** @def SKILL_LORE
+ * @brief Monster-lore
+ * @note
+ * General ability at the monster related skills, ability to gain experience
+ * from friendly kills. It also affects the number of companions the player
+ * can have
+ */
+#define SKILL_LORE 48
+
+/** @def SKILL_PRESERVATION
+ * @brief Corpse-preservation
+ * @note
+ * Ability to not destroy the monster corpse when killing them
+ */
+#define SKILL_PRESERVATION 49
+
+/** @def SKILL_POSSESSION
+ * @brief Possession
+ * @note
+ * Ability to incarnate into monsters
+ */
+#define SKILL_POSSESSION 50
+
+/** @def SKILL_MIND
+ * @brief Mind
+ * @note
+ * Ability to learn and use spells from the Mind school
+ */
+#define SKILL_MIND 51
+
+/** @def SKILL_CRITS
+ * @brief Critical-hits
+ * @note
+ * Ability to deal critical hits with swords < 5lb
+ */
+#define SKILL_CRITS 52
+
+/** @def SKILL_PRAY
+ * @brief Prayer
+ * @note
+ * Ability to learn and use spells from the gods schools
+ */
+#define SKILL_PRAY 53
+
+/** @def SKILL_LEARN
+ * @brief Spell-learning
+ * @note
+ * You should not see that ! that is a BUG!
+ */
+#define SKILL_LEARN 54
+
+/** @def SKILL_UDUN
+ * @brief Udun
+ * @note
+ * Ability to learn and use spells from the Udun school
+ */
+#define SKILL_UDUN 55
+
+/** @def SKILL_DEVICE
+ * @brief Magic-Device
+ * @note
+ * Ease the use of magical devices, such as wands, staves and rods.
+ * It also helps pseudo-id of magic objects
+ */
+#define SKILL_DEVICE 56
+
+/** @def SKILL_STUN
+ * @brief Stunning-blows
+ * @note
+ * Ability to stun opponents when doing critical hits with hafted weapons > 5lb
+ */
+#define SKILL_STUN 57
+
+/** @def SKILL_BOULDER
+ * @brief Boulder-throwing
+ * @note
+ * Ability to make and throw boulders
+ */
+#define SKILL_BOULDER 58
+
+/** @def SKILL_GEOMANCY
+ * @brief Geomancy
+ * @note
+ * Ability to understand the raw elemental forces of nature and use
+ * them to advantage. Most spells need Fire/Water/Earth/Air skills
+ */
+#define SKILL_GEOMANCY 59
+
+
+/** @def SKILL_MAX
+ * @note Maximun skill value
+ */
+#define SKILL_MAX 50000
+/** @def SKILL_STEP
+ * @note 1 skill point
+ */
+#define SKILL_STEP 1000
+
+/** @} */
+
+/** @fn get_skill(int skill)
+ * @brief Return the value of skill with index "skill" in skill array.\n
+ * @param skill Number \n the index of skill in skill array.
+ * @brief Skill index
+ * @return Number \n The value of the skill with index "skill" in the skill
+ * array.
+ * @note (see file skills.c)
+ */
+extern s16b get_skill(int skill);
+
+/** @fn get_skill_scale(int skill, u32b scale)
+ * @brief Return the value of skill with index "skill" in skill array rescaled
+ * to a maximum of "scale".\n
+ * @param skill Number \n the index of skill in skill array.
+ * @brief Skill index
+ * @param scale Number \n the maximum rescaled skill value.
+ * @brief Scaled maximum
+ * @return Number \n The rescaled value of the skill with index "skill" in the
+ * skill array.
+ * @note (see file skills.c)
+ */
+extern s16b get_skill_scale(int skill, u32b scale);
+
+/** @fn do_get_new_skill()
+ * @brief Player select one of four new skills.
+ * @note (see file skills.c)
+ */
+extern void do_get_new_skill();
+
+/** @fn get_melee_skills()
+ * @brief Return the number of melee skills the player has.
+ * @return Number \n The number of melee skills.
+ * @note
+ * A skill is counted if the value > 0 and the skill is not hidden.
+ * @note (see file skills.c)
+ */
+extern s16b get_melee_skills();
+
+/** @fn find_skill(cptr name)
+ * @brief Return the index of skill with name "name".\n
+ * @param name String \n the name of the skill.
+ * @brief Skill name
+ * @return Number \n The index of the skill with name "name" in the skill
+ * array.
+ * @note
+ * The search is case sensitive.\n
+ * If no skills match the name, -1 is returned.
+ * @note (see file skills.c)
+ */
+extern s16b find_skill(cptr name);
+
+/** @fn find_skill_i(cptr name)
+ * @brief Return the index of skill with name "name".\n
+ * @param name String \n the name of the skill.
+ * @brief Skill name
+ * @return Number \n The index of the skill with name "name" in the skill
+ * array.
+ * @note
+ * The search ignores case.\n
+ * If no skills match the name, -1 is returned.
+ * @note (see file skills.c)
+ */
+extern s16b find_skill_i(cptr name);
+
+$static char *get_class_name() {return spp_ptr->title + c_name;}
+/** @fn *get_class_name()
+ * @brief Return the player's class.
+ * @return String \n The player's type of class + class name
+ * @note (see file w_play_c.c)
+ */
+char *get_class_name();
+
+$static char *get_race_name() {return rp_ptr->title + rp_name;}
+/** @fn *get_race_name()
+ * @brief Return the player's race.
+ * @return String \n The player's type of race + race name
+ * @note (see file w_play_c.c)
+ */
+char *get_race_name();
+
+$static char *get_subrace_name() {return rmp_ptr->title + rmp_name;}
+/** @fn *get_subrace_name()
+ * @brief Return the player's subrace.
+ * @return String \n The player's type of subrace + subrace name
+ * @note (see file w_play_c.c)
+ */
+char *get_subrace_name();
+
+/** @struct ability_type
+ * @brief Abilities
+ */
+struct ability_type
+{
+ /** @structvar action_mkey
+ * @brief Number
+ * @note Action do to
+ */
+ s16b action_mkey;
+
+ /** @structvar cost
+ * @brief Number
+ * @note Skill points cost
+ */
+ s16b cost;
+
+ /** @structvar acquired
+ * @brief Boolean
+ * @note Do the player actualylg ot it ?
+ */
+ bool acquired;
+};
+
+/** @fn find_ability(cptr name)
+ * @brief Return the index of ability with name "name".\n
+ * @param name String \n the name of the ability.
+ * @brief Ability name
+ * @return Number \n The index of the ability with name "name" in the ability
+ * array.
+ * @note
+ * The search is case sensitive.\n
+ * If no abilities match the name, -1 is returned.
+ * @note (see file skills.c)
+ */
+extern s16b find_ability(cptr name);
+
+/** @fn do_cmd_ability()
+ * @brief Allow the user to interact with abilities.
+ * @note
+ * This screen is typically used to view abilities, and increase them.
+ * @note (see file skills.c)
+ */
+extern void do_cmd_ability();
+
+/** @fn has_ability(int ab)
+ * @brief Does the player have ability "ab"?
+ * @param ab Number \n the index of ability in ability array.
+ * @brief Ability index
+ * @return Boolean \n TRUE if player has the ability, otherwise FALSE.
+ * @note (see file skills.c)
+ */
+extern bool has_ability(int ab);
+
+/** @var max_ab_idx
+ * @brief Number
+ * @note Maximum ability index
+ */
+extern s16b max_ab_idx;
+/** @var ab_info[max_ab_idx]
+ * @brief ability_type
+ * @note Array of player abilities
+ */
+extern ability_type ab_info[max_ab_idx];
+
+/** @name Abilities
+ * @{ */
+/** @def AB_SPREAD_BLOWS
+ * @brief Spread blows
+ * @note
+ * If a monster dies to an attack but the player still has blows left
+ * they won't lose the full turn, allowing them to attack some other
+ * monster in the same turn.
+ */
+#define AB_SPREAD_BLOWS 0
+
+/** @def AB_TREE_WALK
+ * @brief Tree walking
+ * @note
+ * Allows player to walk in dense forest.
+ */
+#define AB_TREE_WALK 1
+
+/** @def AB_PERFECT_CASTING
+ * @brief Perfect casting
+ * @note
+ * Allows player to reach 0% failure rate on spells.
+ */
+#define AB_PERFECT_CASTING 2
+
+/** @def AB_MAX_BLOW1
+ * @brief Extra Max Blow(1)
+ * @note
+ * Increases player "maximum possible blows" number by 1.
+ */
+#define AB_MAX_BLOW1 3
+
+/** @def AB_MAX_BLOW2
+ * @brief Extra Max Blow(2)
+ * @note
+ * Increases player "maximum possible blows" number by 1
+ * (Cumulative with Extra Max Blow(1)).
+ */
+#define AB_MAX_BLOW2 4
+
+/** @def AB_AMMO_CREATION
+ * @brief Ammo creation
+ * @note
+ * Allows player to create shots, arrows and bolts from various materials.
+ */
+#define AB_AMMO_CREATION 5
+
+/** @def AB_DEATH_TOUCH
+ * @brief Touch of death
+ * @note
+ * Player melee blows can insta-kill, but they only receive 1/3 of the
+ * experience for that kill.
+ */
+#define AB_DEATH_TOUCH 6
+
+/** @def AB_CREATE_ART
+ * @brief Artifact creation
+ * @note
+ * In combination with a high alchemy skill this ability will let the player
+ * design their very own artifacts.
+ */
+#define AB_CREATE_ART 7
+
+/** @def AB_FAR_REACHING
+ * @brief Far reaching attack
+ * @note
+ * The player can attack an enemy one square far using a polearm.
+ * At high levels of polearm skill, they can even hit two enemies at once.
+ */
+#define AB_FAR_REACHING 8
+
+/** @def AB_TRAPPING
+ * @brief Trapping
+ * @note
+ * Enables player to set traps which harm monsters.
+ */
+#define AB_TRAPPING 9
+
+/** @def AB_UNDEAD_FORM
+ * @brief Undead form
+ * @note
+ * Ability to turn into a weak undead being when you "die".
+ * You must then kill enough monsters to absorb enough life energy
+ * to come back to life.
+ */
+#define AB_UNDEAD_FORM 10
+
+/** @} */
+
diff --git a/src/plots.c b/src/plots.c
new file mode 100644
index 00000000..53d3e1bc
--- /dev/null
+++ b/src/plots.c
@@ -0,0 +1,473 @@
+/* File: plots.c */
+
+/* Purpose: plots & quests */
+
+/*
+ * Copyright (c) 2001 James E. Wilson, Robert A. Koeneke, DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+#include "lua/lua.h"
+#include "tolua.h"
+extern lua_State* L;
+
+/* #define DEBUG_HOOK */
+
+/******** Hooks stuff *********/
+FILE *hook_file;
+
+#define MAX_ARGS 50
+
+static hooks_chain *hooks_heads[MAX_HOOKS];
+
+/* Wipe hooks and init them with quest hooks */
+void wipe_hooks()
+{
+ int i;
+
+ for (i = 0; i < MAX_HOOKS; i++)
+ {
+ hooks_heads[i] = NULL;
+ }
+}
+void init_hooks()
+{
+ int i;
+
+ for (i = 0; i < MAX_Q_IDX_INIT; i++)
+ {
+ if ((quest[i].type == HOOK_TYPE_C) && (quest[i].init != NULL)) quest[i].init(i);
+ }
+}
+
+void dump_hooks(int h_idx)
+{
+ int min = 0, max = MAX_HOOKS, i;
+
+ if (h_idx != -1)
+ {
+ min = h_idx;
+ max = h_idx + 1;
+ }
+
+ for (i = min; i < max; i++)
+ {
+ hooks_chain *c = hooks_heads[i];
+
+ /* Find it */
+ while (c != NULL)
+ {
+ msg_format("%s(%s)", c->name, (c->type == HOOK_TYPE_C) ? "C" : "Lua");
+
+ c = c->next;
+ }
+ }
+}
+
+/* Check a hook */
+bool_ check_hook(int h_idx)
+{
+ hooks_chain *c = hooks_heads[h_idx];
+
+ return (c != NULL);
+}
+
+/* Add a hook */
+hooks_chain* add_hook(int h_idx, hook_type hook, cptr name)
+{
+ hooks_chain *new_, *c = hooks_heads[h_idx];
+
+ /* Find it */
+ while ((c != NULL) && (strcmp(c->name, name)))
+ {
+ c = c->next;
+ }
+
+ /* If not already in the list, add it */
+ if (c == NULL)
+ {
+ MAKE(new_, hooks_chain);
+ new_->hook = hook;
+ sprintf(new_->name, "%s", name);
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK ADD: %s", name);
+ if (take_notes) add_note(format("HOOK ADD: %s", name), 'D');
+#endif
+ new_->next = hooks_heads[h_idx];
+ hooks_heads[h_idx] = new_;
+ return (new_);
+ }
+ else return (c);
+}
+
+void add_hook_script(int h_idx, char *script, cptr name)
+{
+ hooks_chain *c = add_hook(h_idx, NULL, name);
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK LUA ADD: %s : %s", name, script);
+#endif
+ sprintf(c->script, "%s", script);
+ c->type = HOOK_TYPE_LUA;
+}
+
+/* Remove a hook */
+void del_hook(int h_idx, hook_type hook)
+{
+ hooks_chain *c = hooks_heads[h_idx], *p = NULL;
+
+ /* Find it */
+ while ((c != NULL) && (c->hook != hook))
+ {
+ p = c;
+ c = c->next;
+ }
+
+ /* Remove it */
+ if (c != NULL)
+ {
+ if (p == NULL)
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK DEL: %s", c->name);
+ if (take_notes) add_note(format("HOOK DEL: %s", c->name), 'D');
+#endif
+ hooks_heads[h_idx] = c->next;
+ FREE(c, hooks_chain);
+ }
+ else
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK DEL: %s", c->name);
+ if (take_notes) add_note(format("HOOK DEL: %s", c->name), 'D');
+#endif
+ p->next = c->next;
+ FREE(c, hooks_chain);
+ }
+ }
+}
+
+void del_hook_name(int h_idx, cptr name)
+{
+ hooks_chain *c = hooks_heads[h_idx], *p = NULL;
+
+ /* Find it */
+ while ((c != NULL) && (strcmp(c->name, name)))
+ {
+ p = c;
+ c = c->next;
+ }
+
+ /* Remove it */
+ if (c != NULL)
+ {
+ if (p == NULL)
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK DEL: %s", c->name);
+ if (take_notes) add_note(format("HOOK DEL: %s", c->name), 'D');
+#endif
+ hooks_heads[h_idx] = c->next;
+ FREE(c, hooks_chain);
+ }
+ else
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK DEL: %s", c->name);
+ if (take_notes) add_note(format("HOOK DEL: %s", c->name), 'D');
+#endif
+ p->next = c->next;
+ FREE(c, hooks_chain);
+ }
+ }
+}
+
+/* get the next argument */
+static hook_return param_pile[MAX_ARGS];
+static int get_next_arg_pos = 0;
+static int get_next_arg_pile_pos = 0;
+s32b get_next_arg(char *fmt)
+{
+ while (TRUE)
+ {
+ switch (fmt[get_next_arg_pos++])
+ {
+ case 'd':
+ case 'l':
+ return (param_pile[get_next_arg_pile_pos++].num);
+ case ')':
+ get_next_arg_pos--;
+ return 0;
+ case '(':
+ case ',':
+ break;
+ }
+ }
+}
+char* get_next_arg_str(char *fmt)
+{
+ while (TRUE)
+ {
+ switch (fmt[get_next_arg_pos++])
+ {
+ case 's':
+ return (char*)(param_pile[get_next_arg_pile_pos++].str);
+ case ')':
+ get_next_arg_pos--;
+ return 0;
+ case '(':
+ case ',':
+ break;
+ }
+ }
+}
+
+/* Actually process the hooks */
+int process_hooks_restart = FALSE;
+hook_return process_hooks_return[20];
+static bool_ vprocess_hooks_return (int h_idx, char *ret, char *fmt, va_list *ap)
+{
+ hooks_chain *c = hooks_heads[h_idx];
+ va_list real_ap;
+
+ while (c != NULL)
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK: %s", c->name);
+ if (take_notes) add_note(format("HOOK PROCESS: %s", c->name), 'D');
+#endif
+ if (c->type == HOOK_TYPE_C)
+ {
+ int i = 0, nb = 0;
+
+ /* Push all args in the pile */
+ i = 0;
+ COPY(&real_ap, ap, va_list);
+ while (fmt[i])
+ {
+ switch (fmt[i])
+ {
+ case 'O':
+ param_pile[nb++].o_ptr = va_arg(real_ap, object_type *);
+ break;
+ case 's':
+ param_pile[nb++].str = va_arg(real_ap, char *);
+ break;
+ case 'd':
+ case 'l':
+ param_pile[nb++].num = va_arg(real_ap, s32b);
+ break;
+ case '(':
+ case ')':
+ case ',':
+ break;
+ }
+ i++;
+ }
+
+ get_next_arg_pos = 0;
+ get_next_arg_pile_pos = 0;
+ if (c->hook(fmt))
+ {
+ return TRUE;
+ }
+
+ /* Should we restart ? */
+ if (process_hooks_restart)
+ {
+ c = hooks_heads[h_idx];
+ process_hooks_restart = FALSE;
+ }
+ else
+ {
+ c = c->next;
+ }
+ }
+ else if (c->type == HOOK_TYPE_LUA)
+ {
+ int i = 0, nb = 0, nbr = 1;
+ int oldtop = lua_gettop(L), size;
+
+ /* Push the function */
+ lua_getglobal(L, c->script);
+
+ /* Push and count the arguments */
+ COPY(&real_ap, ap, va_list);
+ while (fmt[i])
+ {
+ switch (fmt[i++])
+ {
+ case 'd':
+ case 'l':
+ tolua_pushnumber(L, va_arg(real_ap, s32b));
+ nb++;
+ break;
+ case 's':
+ tolua_pushstring(L, va_arg(real_ap, char*));
+ nb++;
+ break;
+ case 'O':
+ tolua_pushusertype(L, (void*)va_arg(real_ap, object_type*), tolua_tag(L, "object_type"));
+ nb++;
+ break;
+ case 'M':
+ tolua_pushusertype(L, (void*)va_arg(real_ap, monster_type*), tolua_tag(L, "monster_type"));
+ nb++;
+ break;
+ case '(':
+ case ')':
+ case ',':
+ break;
+ }
+ }
+
+ /* Count returns */
+ nbr += strlen(ret);
+
+ /* Call the function */
+ if (lua_call(L, nb, nbr))
+ {
+ cmsg_format(TERM_VIOLET, "ERROR in lua_call while calling '%s' lua hook script. Breaking the hook chain now.", c->script);
+ return FALSE;
+ }
+
+ /* Number of returned values, SHOULD be the same as nbr, but I'm paranoid */
+ size = lua_gettop(L) - oldtop;
+
+ /* get the extra returns if needed */
+ for (i = 0; i < nbr - 1; i++)
+ {
+ if ((ret[i] == 'd') || (ret[i] == 'l'))
+ {
+ if (lua_isnumber(L, ( -size) + 1 + i)) process_hooks_return[i].num = tolua_getnumber(L, ( -size) + 1 + i, 0);
+ else process_hooks_return[i].num = 0;
+ }
+ else if (ret[i] == 's')
+ {
+ if (lua_isstring(L, ( -size) + 1 + i)) process_hooks_return[i].str = tolua_getstring(L, ( -size) + 1 + i, "");
+ else process_hooks_return[i].str = NULL;
+ }
+ else if (ret[i] == 'O')
+ {
+ if (tolua_istype(L, ( -size) + 1 + i, tolua_tag(L, "object_type"), 0))
+ process_hooks_return[i].o_ptr = (object_type*)tolua_getuserdata(L, ( -size) + 1 + i, NULL);
+ else
+ process_hooks_return[i].o_ptr = NULL;
+ }
+ else if (ret[i] == 'M')
+ {
+ if (tolua_istype(L, ( -size) + 1 + i, tolua_tag(L, "monster_type"), 0))
+ process_hooks_return[i].m_ptr = (monster_type*)tolua_getuserdata(L, ( -size) + 1 + i, NULL);
+ else
+ process_hooks_return[i].m_ptr = NULL;
+ }
+ else process_hooks_return[i].num = 0;
+ }
+
+ /* Get the basic return(continue or stop the hook chain) */
+ if (tolua_getnumber(L, -size, 0))
+ {
+ lua_settop(L, oldtop);
+ return (TRUE);
+ }
+ if (process_hooks_restart)
+ {
+ c = hooks_heads[h_idx];
+ process_hooks_restart = FALSE;
+ }
+ else
+ c = c->next;
+ lua_settop(L, oldtop);
+ }
+ else
+ {
+ msg_format("Unkown hook type %d, name %s", c->type, c->name);
+ }
+ }
+
+ return FALSE;
+}
+
+bool_ process_hooks_ret(int h_idx, char *ret, char *fmt, ...)
+{
+ va_list ap;
+ bool_ r;
+
+ va_start(ap, fmt);
+ r = vprocess_hooks_return (h_idx, ret, fmt, &ap);
+ va_end(ap);
+ return (r);
+}
+
+bool_ process_hooks(int h_idx, char *fmt, ...)
+{
+ va_list ap;
+ bool_ ret;
+
+ va_start(ap, fmt);
+ ret = vprocess_hooks_return (h_idx, "", fmt, &ap);
+ va_end(ap);
+ return (ret);
+}
+
+/******** Plots & Quest stuff ********/
+
+static void quest_describe(int q_idx)
+{
+ int i = 0;
+
+ while ((i < 10) && (quest[q_idx].desc[i][0] != '\0'))
+ {
+ cmsg_print(TERM_YELLOW, quest[q_idx].desc[i++]);
+ }
+}
+
+/* Catch-all quest hook */
+bool_ quest_null_hook(int q)
+{
+ /* Do nothing */
+ return (FALSE);
+}
+
+/************************** Random Quests *************************/
+#include "q_rand.c"
+
+/**************************** Main plot ***************************/
+#include "q_main.c"
+#include "q_one.c"
+#include "q_ultrag.c"
+#include "q_ultrae.c"
+
+/**************************** Bree plot ***************************/
+#include "q_thief.c"
+#include "q_hobbit.c"
+#include "q_troll.c"
+#include "q_wight.c"
+#include "q_nazgul.c"
+#include "q_shroom.c"
+
+/*************************** Lorien plot **************************/
+#include "q_wolves.c"
+#include "q_spider.c"
+#include "q_poison.c"
+
+/************************** Gondolin plot *************************/
+#include "q_dragons.c"
+#include "q_eol.c"
+#include "q_nirna.c"
+#include "q_invas.c"
+
+/************************* Minas Anor plot ************************/
+#include "q_haunted.c"
+#include "q_betwen.c"
+
+/************************* Khazad-dum plot ************************/
+#include "q_evil.c"
+
+/*************************** Other plot ***************************/
+#include "q_narsil.c"
+#include "q_thrain.c"
diff --git a/src/plots.h b/src/plots.h
new file mode 100644
index 00000000..a1a11e6c
--- /dev/null
+++ b/src/plots.h
@@ -0,0 +1,48 @@
+/* File: plots.h */
+
+/* Purpose: extern plots declarations */
+
+extern bool_ quest_null_hook(int q);
+
+/******* Random Quests ********/
+extern bool_ is_randhero(int level);
+extern bool_ quest_random_init_hook(int q_idx);
+extern bool_ quest_random_describe(FILE *fff);
+
+/******* Plot main ********/
+extern bool_ quest_necro_init_hook(int q_idx);
+extern bool_ quest_one_init_hook(int q_idx);
+extern bool_ quest_sauron_init_hook(int q_idx);
+extern bool_ quest_morgoth_init_hook(int q_idx);
+extern bool_ quest_ultra_good_init_hook(int q_idx);
+extern bool_ quest_ultra_evil_init_hook(int q_idx);
+
+/******* Plot Bree *********/
+extern bool_ quest_thieves_init_hook(int q_idx);
+extern bool_ quest_hobbit_init_hook(int q_idx);
+extern bool_ quest_troll_init_hook(int q_idx);
+extern bool_ quest_wight_init_hook(int q_idx);
+extern bool_ quest_nazgul_init_hook(int q_idx);
+extern bool_ quest_shroom_init_hook(int q_idx);
+
+/******* Plot Lorien *********/
+extern bool_ quest_wolves_init_hook(int q_idx);
+extern bool_ quest_spider_init_hook(int q_idx);
+extern bool_ quest_poison_init_hook(int q_idx);
+
+/******* Plot Gondolin *********/
+extern bool_ quest_dragons_init_hook(int q_idx);
+extern bool_ quest_eol_init_hook(int q_idx);
+extern bool_ quest_nirnaeth_init_hook(int q_idx);
+extern bool_ quest_invasion_init_hook(int q_idx);
+
+/******* Plot Minas Anor *********/
+extern bool_ quest_haunted_init_hook(int q_idx);
+extern bool_ quest_between_init_hook(int q_idx);
+
+/******* Plot Khazad-dum *********/
+extern bool_ quest_evil_init_hook(int q_idx);
+
+/******* Plot Other *********/
+extern bool_ quest_narsil_init_hook(int q_idx);
+extern bool_ quest_thrain_init_hook(int q_idx);
diff --git a/src/powers.c b/src/powers.c
new file mode 100644
index 00000000..12b2c2c0
--- /dev/null
+++ b/src/powers.c
@@ -0,0 +1,1388 @@
+/* File: powers.c */
+
+/* Purpose: Powers */
+
+/*
+ * Copyright (c) 2001 James E. Wilson, Robert A. Koeneke, DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * Note: return value indicates the amount of mana to use
+ */
+bool_ power_chance(power_type *x_ptr)
+{
+ bool_ use_hp = FALSE;
+ int diff = x_ptr->diff;
+
+ /* Always true ? */
+ if (!x_ptr->cost) return TRUE;
+
+ /* Not enough mana - use hp */
+ if (p_ptr->csp < x_ptr->cost) use_hp = TRUE;
+
+ /* Power is not available yet */
+ if (p_ptr->lev < x_ptr->level)
+ {
+ msg_format("You need to attain level %d to use this power.", x_ptr->level);
+ energy_use = 0;
+ return (FALSE);
+ }
+
+ /* Too confused */
+ else if (p_ptr->confused)
+ {
+ msg_print("You are too confused to use this power.");
+ energy_use = 0;
+ return (FALSE);
+ }
+
+ /* Risk death? */
+ else if (use_hp && (p_ptr->chp < x_ptr->cost))
+ {
+ if (!(get_check("Really use the power in your weakened state? ")))
+ {
+ energy_use = 0;
+ return (FALSE);
+ }
+ }
+
+ /* Else attempt to do it! */
+
+ if (p_ptr->stun)
+ {
+ diff += p_ptr->stun;
+ }
+ else if (p_ptr->lev > x_ptr->level)
+ {
+ int lev_adj = ((p_ptr->lev - x_ptr->level) / 3);
+ if (lev_adj > 10) lev_adj = 10;
+ diff -= lev_adj;
+ }
+
+ if (diff < 5) diff = 5;
+
+ /* take time and pay the price */
+ if (use_hp)
+ {
+ take_hit(((x_ptr->cost / 2) + (randint(x_ptr->cost / 2))),
+ "concentrating too hard");
+ }
+ else
+ {
+ p_ptr->csp -= (x_ptr->cost / 2 ) + (randint(x_ptr->cost / 2));
+ }
+ energy_use = 100;
+
+ /* Redraw mana and hp */
+ p_ptr->redraw |= (PR_HP | PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Success? */
+ if (randint(p_ptr->stat_cur[x_ptr->stat]) >=
+ ((diff / 2) + randint(diff / 2)))
+ {
+ return (TRUE);
+ }
+
+ if (flush_failure) flush();
+ msg_print("You've failed to concentrate hard enough.");
+
+ return (FALSE);
+}
+
+static void power_activate(int power)
+{
+ s16b plev = p_ptr->lev;
+ char ch = 0;
+ int amber_power = 0;
+ int dir = 0, dummy;
+ object_type *q_ptr;
+ object_type forge;
+ int ii = 0, ij = 0;
+ /* char out_val[80]; */
+ /* cptr p = "Power of the flame: "; */
+ cptr q, s;
+ power_type *x_ptr = &powers_type[power], x_ptr_foo;
+ int x, y;
+ cave_type *c_ptr;
+
+ /* Break goi/manashield */
+ if (p_ptr->invuln)
+ {
+ set_invuln(0);
+ }
+ if (p_ptr->disrupt_shield)
+ {
+ set_disrupt_shield(0);
+ }
+
+
+ if (!power_chance(x_ptr)) return;
+
+ switch (power)
+ {
+ case PWR_BALROG:
+ {
+ set_mimic(p_ptr->lev / 2, resolve_mimic_name("Balrog"), p_ptr->lev);
+ }
+ break;
+ case PWR_BEAR:
+ {
+ set_mimic(150 + (p_ptr->lev * 10) , resolve_mimic_name("Bear"), p_ptr->lev);
+ }
+ break;
+ case PWR_COMPANION:
+ {
+ if (!can_create_companion())
+ {
+ msg_print("You cannot have more companions.");
+ }
+ else
+ {
+ monster_type *m_ptr;
+ int ii, jj;
+
+ msg_print("Select the friendly monster:");
+ if (!tgt_pt(&ii, &jj)) return;
+
+ if (cave[jj][ii].m_idx)
+ {
+ m_ptr = &m_list[cave[jj][ii].m_idx];
+
+ if (m_ptr->status != MSTATUS_PET)
+ {
+ msg_print("You cannot convert this monster.");
+ return;
+ }
+
+ m_ptr->status = MSTATUS_COMPANION;
+ }
+ }
+ }
+ break;
+ case PWR_MERCHANT:
+ /* Select power to use */
+ while (TRUE)
+ {
+ if (!get_com("[A]ppraise item, [W]arp item or [I]dentify item? ", &ch))
+ {
+ amber_power = 0;
+ break;
+ }
+
+ if (ch == 'A' || ch == 'a')
+ {
+ amber_power = 1;
+ break;
+ }
+
+ if (ch == 'W' || ch == 'w')
+ {
+ amber_power = 2;
+ break;
+ }
+
+ if (ch == 'I' || ch == 'i')
+ {
+ amber_power = 3;
+ break;
+ }
+ }
+
+ if (amber_power == 1)
+ {
+ x_ptr_foo.level = 5;
+ x_ptr_foo.cost = 5;
+ x_ptr_foo.stat = A_INT;
+ x_ptr_foo.diff = 5;
+ if (power_chance(&x_ptr_foo))
+ {
+ /* Appraise an object */
+ int idx;
+ cptr q, s;
+
+ /* Get the item */
+ q = "Appraise which item? ";
+ s = "You have nothing to appraise.";
+ if (get_item(&idx, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR)))
+ {
+ object_type *o_ptr;
+ char out_val[80], value[16];
+
+ /* The item is in the pack */
+ if (idx >= 0) o_ptr = &p_ptr->inventory[idx];
+ /* The item is on the floor */
+ else o_ptr = &o_list[0 - idx];
+
+ /* Appraise it */
+ sprintf(value, "%i au", (int)object_value(o_ptr));
+
+ /* Inscribe the value */
+ /* Get the original inscription */
+ if (o_ptr->note)
+ {
+ strcpy(out_val, quark_str(o_ptr->note));
+ strcat(out_val, " ");
+ }
+ else
+ out_val[0] = '\0';
+
+ strcat(out_val, value);
+
+ /* Save the new inscription */
+ o_ptr->note = quark_add(out_val);
+
+ /* Combine the pack */
+ p_ptr->notice |= (PN_COMBINE);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+ }
+ }
+ }
+ if (amber_power == 2)
+ {
+ x_ptr_foo.level = 15;
+ x_ptr_foo.cost = 10;
+ x_ptr_foo.stat = A_INT;
+ x_ptr_foo.diff = 7;
+ if (power_chance(&x_ptr_foo))
+ {
+ int chest, item;
+ cptr q1, s1, q2, s2;
+ u32b flag = (USE_EQUIP | USE_INVEN | USE_FLOOR);
+ object_type *o1_ptr = &p_ptr->inventory[0], *o2_ptr = &p_ptr->inventory[1];
+ int ok = 0;
+
+ q1 = "Select a chest! ";
+ s1 = "You need a chest to warp items.";
+
+ q2 = "Warp which item? ";
+ s2 = "You have nothing to warp.";
+
+ item_tester_tval = TV_CHEST;
+
+ /* Get the chest */
+ if (get_item(&chest, q1, s1, flag))
+ {
+ if (chest >= 0) o1_ptr = &p_ptr->inventory[chest];
+ else o1_ptr = &o_list[0 - chest];
+
+ /* Is the chest disarmed? */
+ if (o1_ptr->pval > 0)
+ msg_print("This chest may be trapped.");
+
+ /* Is it ruined? */
+ else if (k_info[o1_ptr->k_idx].level <= 0)
+ msg_print("This chest is broken.");
+
+ /* Is it empty? */
+ else if (o1_ptr->pval2 >= (o1_ptr->sval % SV_CHEST_MIN_LARGE) * 2)
+ msg_print("This chest is full.");
+
+ else ok = 1;
+ }
+
+ /* Get the item */
+ if (ok && get_item(&item, q2, s2, flag))
+ {
+ ok = 0;
+
+ o2_ptr = get_object(item);
+
+ /* Is the item cursed? */
+ if ((item >= INVEN_WIELD) && cursed_p(o2_ptr))
+ msg_print("Hmmm, it seems to be cursed.");
+
+ /* Is it the same chest? */
+ if (item == chest)
+ msg_print("You can't put a chest into itself.");
+
+ /* Is it another chest? */
+ if (o2_ptr->tval == TV_CHEST)
+ msg_print("You can't put a chest into another one.");
+
+ /* Try to use the power */
+ else ok = 1;
+ }
+
+ if (ok)
+ {
+ int tmp, level;
+
+ /* Calculate the level of objects */
+ tmp = o1_ptr->pval;
+
+ /* Get the level of the current object */
+ /* Cursed items/cheap items always break */
+ if (k_info[o2_ptr->k_idx].cost < 20) level = 0;
+ /* Not-so-cheap items break 90% of the time */
+ else if (k_info[o2_ptr->k_idx].cost < 100) level = 1;
+ else level = k_info[o2_ptr->k_idx].level;
+
+ /* Break some items */
+ if (randint(10) > level)
+ msg_print("The item disappeared!");
+ else
+ {
+ level /= (o1_ptr->sval % SV_CHEST_MIN_LARGE) * 2;
+
+ /* Increase the number of objects in
+ * the chest */
+ o1_ptr->pval2++;
+
+ /* Set the level of chest */
+ tmp = tmp - level;
+ o1_ptr->pval = tmp;
+ }
+
+ /* Destroy item */
+ inc_stack_size(item, -1);
+ }
+ }
+ }
+ if (amber_power == 3)
+ {
+ x_ptr_foo.level = 30;
+ x_ptr_foo.cost = 20;
+ x_ptr_foo.stat = A_INT;
+ x_ptr_foo.diff = 7;
+ if (power_chance(&x_ptr_foo))
+ {
+ ident_spell();
+ }
+ }
+ break;
+ case PWR_LAY_TRAP:
+ {
+ do_cmd_set_trap();
+ }
+ break;
+ case PWR_MAGIC_MAP:
+ {
+ msg_print("You sense the world around you.");
+ map_area();
+ }
+ break;
+
+ case PWR_PASSWALL:
+ {
+ if (!get_aim_dir(&dir))
+ break;
+ if (passwall(dir, TRUE))
+ msg_print("A passage opens, and you step through.");
+ else
+ msg_print("There is no wall there!");
+ }
+ break;
+
+ case PWR_COOK_FOOD:
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Create the item */
+ object_prep(q_ptr, 21);
+
+ /* Drop the object from heaven */
+ drop_near(q_ptr, -1, p_ptr->py, p_ptr->px);
+ msg_print("You cook some food.");
+ }
+ break;
+
+ case PWR_UNFEAR:
+ {
+ msg_print("You play tough.");
+ (void)set_afraid(0);
+ }
+ break;
+
+ case PWR_BERSERK:
+ {
+ msg_print("RAAAGH!");
+ (void)set_afraid(0);
+
+ (void)set_shero(p_ptr->shero + 10 + randint(plev));
+ (void)hp_player(30);
+ }
+ break;
+
+ case PWR_EXPL_RUNE:
+ {
+ msg_print("You carefully set an explosive rune...");
+ explosive_rune();
+ }
+ break;
+
+ case PWR_STM:
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You bash at a stone wall.");
+ (void)wall_to_mud(dir);
+ }
+ break;
+
+ case PWR_ROHAN:
+ /* Select power to use */
+ while (TRUE)
+ {
+ if (!get_com("Use [F]lash aura or [L]ight speed jump? ", &ch))
+ {
+ amber_power = 0;
+ break;
+ }
+
+ if (ch == 'F' || ch == 'f')
+ {
+ amber_power = 1;
+ break;
+ }
+
+ if (ch == 'L' || ch == 'l')
+ {
+ amber_power = 2;
+ break;
+ }
+ }
+
+ if (amber_power == 1)
+ {
+ x_ptr_foo.level = 1;
+ x_ptr_foo.cost = 9;
+ x_ptr_foo.stat = A_CHR;
+ x_ptr_foo.diff = 7;
+ if (power_chance(&x_ptr_foo))
+ {
+ if (!(get_aim_dir(&dir))) break;
+ msg_print("You flash a bright aura.");
+ if (p_ptr->lev < 10)
+ fire_bolt(GF_CONFUSION, dir, plev*2);
+ else
+ fire_ball(GF_CONFUSION, dir, plev*2, 2);
+ }
+ }
+ if (amber_power == 2)
+ {
+ x_ptr_foo.level = 30;
+ x_ptr_foo.cost = 30;
+ x_ptr_foo.stat = A_WIS;
+ x_ptr_foo.diff = 7;
+ if (power_chance(&x_ptr_foo))
+ {
+ (void)set_light_speed(p_ptr->lightspeed + 3);
+ }
+ }
+ break;
+
+
+ case PWR_POIS_DART:
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You throw a dart of poison.");
+ fire_bolt(GF_POIS, dir, plev);
+ }
+ break;
+
+ case PWR_DETECT_TD:
+ {
+ msg_print("You examine your surroundings.");
+ (void)detect_traps(DEFAULT_RADIUS);
+ (void)detect_doors(DEFAULT_RADIUS);
+ (void)detect_stairs(DEFAULT_RADIUS);
+ }
+ break;
+
+ case PWR_MAGIC_MISSILE:
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You cast a magic missile.");
+ fire_bolt_or_beam(10, GF_MISSILE, dir,
+ damroll(3 + ((plev - 1) / 5), 4));
+ }
+ break;
+
+ case PWR_THUNDER:
+ /* Select power to use */
+ while (TRUE)
+ {
+ if (!get_com("Use [T]hunder strike, [R]ide the straight road, go [B]ack in town? ", &ch))
+ {
+ amber_power = 0;
+ break;
+ }
+
+ if (ch == 'T' || ch == 't')
+ {
+ amber_power = 1;
+ break;
+ }
+
+ if (ch == 'R' || ch == 'r')
+ {
+ amber_power = 2;
+ break;
+ }
+
+ if (ch == 'B' || ch == 'b')
+ {
+ amber_power = 3;
+ break;
+ }
+
+ }
+
+ if (amber_power == 1)
+ {
+ x_ptr_foo.level = 1;
+ x_ptr_foo.cost = p_ptr->lev;
+ x_ptr_foo.stat = A_CON;
+ x_ptr_foo.diff = 6;
+ if (power_chance(&x_ptr_foo))
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_format("You conjure up thunder!");
+ fire_beam(GF_ELEC, dir, p_ptr->lev * 2);
+ fire_beam(GF_SOUND, dir, p_ptr->lev * 2);
+ p_ptr->energy -= 100;
+ }
+ }
+ if (amber_power == 2)
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("No teleport on special levels ...");
+ break;
+ }
+ x_ptr_foo.level = 3;
+ x_ptr_foo.cost = 15;
+ x_ptr_foo.stat = A_CON;
+ x_ptr_foo.diff = 6;
+ if (power_chance(&x_ptr_foo))
+ {
+ msg_print("You enter the straight road and fly beside the world. Where to exit?");
+ if (!tgt_pt(&ii, &ij)) return;
+ p_ptr->energy -= 60 - plev;
+ if (!cave_empty_bold(ij, ii) || (cave[ij][ii].info & CAVE_ICKY) ||
+ (distance(ij, ii, p_ptr->py, p_ptr->px) > plev*20 + 2) || !(cave[ij][ii].info & CAVE_MARK))
+ {
+ msg_print("You fail to exit correctly!");
+ p_ptr->energy -= 100;
+ teleport_player(10);
+ }
+ else teleport_player_to(ij, ii);
+ }
+
+ }
+ if (amber_power == 3)
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("No recall on special levels..");
+ break;
+ }
+ x_ptr_foo.level = 7;
+ x_ptr_foo.cost = 30;
+ x_ptr_foo.stat = A_CON;
+ x_ptr_foo.diff = 6;
+ if (power_chance(&x_ptr_foo))
+ {
+ if (dun_level == 0)
+ msg_print("You are already in town!");
+ else
+ {
+ msg_print("You enter the straight road and fly beside the world.");
+ p_ptr->energy -= 100;
+ p_ptr->word_recall = 1;
+ }
+ }
+ }
+ break;
+
+ case PWR_GROW_TREE:
+ {
+ msg_print("You make the trees grow!");
+ grow_trees((plev / 8 < 1) ? 1 : plev / 8);
+ }
+ break;
+
+ case PWR_DEATHMOLD:
+ do_cmd_immovable_special();
+ break;
+
+ case PWR_BR_COLD:
+ {
+ msg_print("You breathe cold...");
+ if (get_aim_dir(&dir))
+ fire_ball(GF_COLD, dir, p_ptr->lev * 2, 1 + (p_ptr->lev / 20));
+ }
+ break;
+
+ case PWR_BR_CHAOS:
+ {
+ msg_print("You breathe chaos...");
+ if (get_aim_dir(&dir))
+ fire_ball(GF_CHAOS, dir, p_ptr->lev * 2, 1 + (p_ptr->lev / 20));
+ }
+ break;
+
+ case PWR_BR_ELEM:
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_format("You breathe the elements.");
+ fire_ball(GF_MISSILE, dir, (p_ptr->lev)*2,
+ ((p_ptr->lev) / 15) + 1);
+ }
+ break;
+
+ case PWR_SUMMON_MONSTER:
+ {
+ do_cmd_beastmaster();
+ }
+ break;
+
+ case PWR_WRECK_WORLD:
+ msg_print("The power of Eru Iluvatar flows through you!");
+ msg_print("The world changes!");
+
+ autosave_checkpoint();
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ break;
+
+ case PWR_VAMPIRISM:
+ {
+ /* Only works on adjacent monsters */
+ if (!get_rep_dir(&dir)) break; /* was get_aim_dir */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+
+ if (!(c_ptr->m_idx))
+ {
+ msg_print("You bite into thin air!");
+ break;
+ }
+
+ msg_print("You grin and bare your fangs...");
+ dummy = plev + randint(plev) * MAX(1, plev / 10); /* Dmg */
+ if (drain_life(dir, dummy))
+ {
+ if (p_ptr->food < PY_FOOD_FULL)
+ /* No heal if we are "full" */
+ (void)hp_player(dummy);
+ else
+ msg_print("You were not hungry.");
+ /* Gain nutritional sustenance: 150/hp drained */
+ /* A Food ration gives 5000 food points (by contrast) */
+ /* Don't ever get more than "Full" this way */
+ /* But if we ARE Gorged, it won't cure us */
+ dummy = p_ptr->food + MIN(5000, 100 * dummy);
+ if (p_ptr->food < PY_FOOD_MAX) /* Not gorged already */
+ (void)set_food(dummy >= PY_FOOD_MAX ? PY_FOOD_MAX - 1 : dummy);
+ }
+ else
+ msg_print("Yechh. That tastes foul.");
+ }
+ break;
+
+ case PWR_SCARE:
+ {
+ msg_print("You emit an eldritch howl!");
+ if (!get_aim_dir(&dir)) break;
+ (void)fear_monster(dir, plev);
+ }
+ break;
+
+ case PWR_REST_LIFE:
+ {
+ msg_print("You attempt to restore your lost energies.");
+ (void)restore_level();
+ }
+ break;
+
+ case PWR_HYPNO:
+ {
+ int dir, x, y;
+ cave_type *c_ptr;
+ monster_type *m_ptr;
+ monster_race *r_ptr;
+ object_type *q_ptr;
+ object_type forge;
+
+ msg_print("Hypnotize which pet?");
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+ if (c_ptr->m_idx)
+ {
+ m_ptr = &m_list[c_ptr->m_idx];
+ r_ptr = race_inf(m_ptr);
+
+ if ((r_ptr->flags1 & RF1_NEVER_MOVE) && (m_ptr->status == MSTATUS_PET) && (!(r_ptr->flags9 & RF9_SPECIAL_GENE)))
+ {
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_HYPNOS, 1));
+ q_ptr->number = 1;
+ q_ptr->pval = m_ptr->r_idx;
+ q_ptr->pval2 = m_ptr->hp;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+
+ q_ptr->ident |= IDENT_STOREB;
+
+ drop_near(q_ptr, 0, y, x);
+
+ delete_monster(y, x);
+ health_who = 0;
+ }
+ else
+ msg_print("You can only hypnotize monsters that can't move.");
+ }
+ else msg_print("There is no pet here!");
+ }
+ break;
+
+ case PWR_UNHYPNO:
+ {
+ monster_type *m_ptr;
+ int m_idx;
+ int item, x, y, d;
+ object_type *o_ptr;
+
+ cptr q, s;
+
+ /* Restrict choices to monsters */
+ item_tester_tval = TV_HYPNOS;
+
+ /* Get an item */
+ q = "Awaken which monster? ";
+ s = "You have no monster to awaken.";
+ if (!get_item(&item, q, s, (USE_FLOOR))) return;
+
+ o_ptr = &o_list[0 - item];
+
+ d = 2;
+ while (d < 100)
+ {
+ scatter(&y, &x, p_ptr->py, p_ptr->px, d);
+
+ if (cave_floor_bold(y, x) && (!cave[y][x].m_idx)) break;
+
+ d++;
+ }
+
+ if (d >= 100) return;
+
+ if ((m_idx = place_monster_one(y, x, o_ptr->pval, 0, FALSE, MSTATUS_PET)) == 0) return;
+
+ m_ptr = &m_list[m_idx];
+ m_ptr->hp = o_ptr->pval2;
+
+ floor_item_increase(0 - item, -1);
+ floor_item_describe(0 - item);
+ floor_item_optimize(0 - item);
+ }
+ break;
+
+ case PWR_NECRO:
+ {
+ do_cmd_necromancer();
+ break;
+ }
+ case PWR_INCARNATE:
+ {
+ do_cmd_integrate_body();
+ break;
+ }
+
+ case PWR_SPIT_ACID:
+ {
+ msg_print("You spit acid...");
+ if (get_aim_dir(&dir))
+ fire_ball(GF_ACID, dir, p_ptr->lev, 1 + (p_ptr->lev / 30));
+ }
+ break;
+
+ case PWR_BR_FIRE:
+ {
+ msg_print("You breathe fire...");
+ if (get_aim_dir(&dir))
+ fire_ball(GF_FIRE, dir, p_ptr->lev * 2, 1 + (p_ptr->lev / 20));
+ }
+ break;
+
+ case PWR_HYPN_GAZE:
+ {
+ msg_print("Your eyes look mesmerising...");
+ if (get_aim_dir(&dir))
+ (void) charm_monster(dir, p_ptr->lev);
+ }
+ break;
+
+ case PWR_TELEKINES:
+ {
+ msg_print("You concentrate...");
+ if (get_aim_dir(&dir))
+ fetch(dir, p_ptr->lev * 10, TRUE);
+ }
+ break;
+
+ case PWR_VTELEPORT:
+ {
+ msg_print("You concentrate...");
+ teleport_player(10 + 4*(p_ptr->lev));
+ }
+ break;
+
+ case PWR_MIND_BLST:
+ {
+ msg_print("You concentrate...");
+ if (!get_aim_dir(&dir)) return;
+ fire_bolt(GF_PSI, dir, damroll(3 + ((p_ptr->lev - 1) / 5), 3));
+ }
+ break;
+
+ case PWR_RADIATION:
+ {
+ msg_print("Radiation flows from your body!");
+ fire_ball(GF_NUKE, 0, (p_ptr->lev * 2), 3 + (p_ptr->lev / 20));
+ }
+ break;
+
+ case PWR_SMELL_MET:
+ {
+ (void)detect_treasure(DEFAULT_RADIUS);
+ }
+ break;
+
+ case PWR_SMELL_MON:
+ {
+ (void)detect_monsters_normal(DEFAULT_RADIUS);
+ }
+ break;
+
+ case PWR_BLINK:
+ {
+ teleport_player(10);
+ }
+ break;
+
+ case PWR_EAT_ROCK:
+ {
+ int x, y, ox, oy;
+ cave_type *c_ptr;
+
+ if (!get_rep_dir(&dir)) break;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+ if (cave_floor_bold(y, x))
+ {
+ msg_print("You bite into thin air!");
+ break;
+ }
+ else if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT) || (c_ptr->feat == FEAT_MOUNTAIN))
+ {
+ msg_print("Ouch! This wall is harder than your teeth!");
+ break;
+ }
+ else if (c_ptr->m_idx)
+ {
+ msg_print("There's something in the way!");
+ break;
+ }
+ else if (c_ptr->feat == FEAT_TREES)
+ {
+ msg_print("You don't like the woody taste!");
+ break;
+ }
+ else
+ {
+ if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_RUBBLE))
+ {
+ (void)set_food(p_ptr->food + 3000);
+ }
+ else if ((c_ptr->feat >= FEAT_MAGMA) &&
+ (c_ptr->feat <= FEAT_QUARTZ_K))
+ {
+ (void)set_food(p_ptr->food + 5000);
+ }
+ else if ((c_ptr->feat >= FEAT_SANDWALL) &&
+ (c_ptr->feat <= FEAT_SANDWALL_K))
+ {
+ (void)set_food(p_ptr->food + 500);
+ }
+ else
+ {
+ msg_print("This granite is very filling!");
+ (void)set_food(p_ptr->food + 10000);
+ }
+ }
+ (void)wall_to_mud(dir);
+
+ oy = p_ptr->py;
+ ox = p_ptr->px;
+
+ p_ptr->py = y;
+ p_ptr->px = x;
+
+ lite_spot(p_ptr->py, p_ptr->px);
+ lite_spot(oy, ox);
+
+ verify_panel();
+
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+ p_ptr->update |= (PU_DISTANCE);
+ p_ptr->window |= (PW_OVERHEAD);
+ }
+ break;
+
+ case PWR_SWAP_POS:
+ {
+ if (!get_aim_dir(&dir)) return;
+ (void)teleport_swap(dir);
+ }
+ break;
+
+ case PWR_SHRIEK:
+ {
+ (void)fire_ball(GF_SOUND, 0, 4 * p_ptr->lev, 8);
+ (void)aggravate_monsters(0);
+ }
+ break;
+
+ case PWR_ILLUMINE:
+ {
+ (void)lite_area(damroll(2, (p_ptr->lev / 2)), (p_ptr->lev / 10) + 1);
+ }
+ break;
+
+ case PWR_DET_CURSE:
+ {
+ int i;
+
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ if (!o_ptr->k_idx) continue;
+ if (!cursed_p(o_ptr)) continue;
+
+ if (!o_ptr->sense) o_ptr->sense = SENSE_CURSED;
+ }
+ }
+ break;
+
+ case PWR_POLYMORPH:
+ {
+ do_poly_self();
+ }
+ break;
+
+ case PWR_MIDAS_TCH:
+ {
+ (void)alchemy();
+ }
+ break;
+
+ case PWR_GROW_MOLD:
+ {
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, p_ptr->lev, SUMMON_BIZARRE1, FALSE);
+ }
+ }
+ break;
+
+ case PWR_RESIST:
+ {
+ int num = p_ptr->lev / 10;
+ int dur = randint(20) + 20;
+
+ if (rand_int(5) < num)
+ {
+ (void)set_oppose_acid(p_ptr->oppose_acid + dur);
+ num--;
+ }
+ if (rand_int(4) < num)
+ {
+ (void)set_oppose_elec(p_ptr->oppose_elec + dur);
+ num--;
+ }
+ if (rand_int(3) < num)
+ {
+ (void)set_oppose_fire(p_ptr->oppose_fire + dur);
+ num--;
+ }
+ if (rand_int(2) < num)
+ {
+ (void)set_oppose_cold(p_ptr->oppose_cold + dur);
+ num--;
+ }
+ if (num)
+ {
+ (void)set_oppose_pois(p_ptr->oppose_pois + dur);
+ num--;
+ }
+ }
+ break;
+
+ case PWR_EARTHQUAKE:
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(p_ptr->py, p_ptr->px, 10);
+ }
+ break;
+
+ case PWR_EAT_MAGIC:
+ {
+ object_type * o_ptr;
+ int lev, item;
+
+ item_tester_hook = item_tester_hook_recharge;
+
+ /* Get an item */
+ q = "Drain which item? ";
+ s = "You have nothing to drain.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) break;
+
+ o_ptr = get_object(item);
+
+ lev = k_info[o_ptr->k_idx].level;
+
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ if (!o_ptr->timeout)
+ {
+ msg_print("You can't absorb energy from a discharged rod.");
+ }
+ else
+ {
+ p_ptr->csp += o_ptr->timeout;
+ o_ptr->timeout = 0;
+ }
+ }
+ else
+ {
+ if (o_ptr->pval > 0)
+ {
+ p_ptr->csp += o_ptr->pval * lev;
+ o_ptr->pval = 0;
+ }
+ else
+ {
+ msg_print("There's no energy there to absorb!");
+ }
+ o_ptr->ident |= IDENT_EMPTY;
+ }
+
+ if (p_ptr->csp > p_ptr->msp)
+ {
+ p_ptr->csp = p_ptr->msp;
+ }
+
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+ p_ptr->window |= (PW_INVEN);
+ }
+ break;
+
+ case PWR_WEIGH_MAG:
+ {
+ report_magics();
+ }
+ break;
+
+ case PWR_STERILITY:
+ {
+ /* Fake a population explosion. */
+ msg_print("You suddenly have a headache!");
+ take_hit(randint(30) + 30, "the strain of forcing abstinence");
+ num_repro += MAX_REPRO;
+ }
+ break;
+
+ case PWR_PANIC_HIT:
+ {
+ int x, y;
+
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ if (cave[y][x].m_idx)
+ {
+ py_attack(y, x, -1);
+ teleport_player(30);
+ }
+ else
+ {
+ msg_print("You don't see any monster in this direction.");
+ msg_print(NULL);
+ }
+ }
+ break;
+
+ case PWR_DAZZLE:
+ {
+ stun_monsters(p_ptr->lev * 4);
+ confuse_monsters(p_ptr->lev * 4);
+ turn_monsters(p_ptr->lev * 4);
+ }
+ break;
+
+ case PWR_DARKRAY:
+ {
+ if (!get_aim_dir(&dir)) return;
+ fire_beam(GF_LITE, dir, 2*p_ptr->lev);
+ }
+ break;
+
+ case PWR_RECALL:
+ {
+ if (!(dungeon_flags2 & DF2_ASK_LEAVE) || ((dungeon_flags2 & DF2_ASK_LEAVE) && !get_check("Leave this unique level forever? ")))
+ {
+ recall_player(21, 15);
+ }
+ }
+ break;
+
+ case PWR_BANISH:
+ {
+ int x, y;
+ cave_type *c_ptr;
+ monster_type *m_ptr;
+ monster_race *r_ptr;
+
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+ if (!(c_ptr->m_idx))
+ {
+ msg_print("You sense no evil there!");
+ break;
+ }
+
+ m_ptr = &m_list[c_ptr->m_idx];
+ r_ptr = race_inf(m_ptr);
+
+ if (r_ptr->flags3 & RF3_EVIL)
+ {
+ /* Delete the monster, rather than killing it. */
+ delete_monster_idx(c_ptr->m_idx);
+ msg_print("The evil creature vanishes in a puff of sulphurous smoke!");
+ }
+ else
+ {
+ msg_print("Your invocation is ineffectual!");
+ }
+ }
+ break;
+
+ case PWR_COLD_TOUCH:
+ {
+ int x, y;
+ cave_type *c_ptr;
+
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+ if (!(c_ptr->m_idx))
+ {
+ msg_print("You wave your hands in the air.");
+ break;
+ }
+ fire_bolt(GF_COLD, dir, 2 * (p_ptr->lev));
+ }
+ break;
+
+ case PWR_LAUNCHER:
+ {
+ /* Gives a multiplier of 2 at first, up to 5 at 48th */
+ p_ptr->throw_mult = 2 + (p_ptr->lev / 16);
+ do_cmd_throw();
+ p_ptr->throw_mult = 1;
+ }
+ break;
+
+ case PWR_DODGE:
+ use_ability_blade();
+ break;
+
+ default:
+ if (!process_hooks(HOOK_ACTIVATE_POWER, "(d)", power))
+ {
+ msg_format("Warning power_activate() called with invalid power(%d).", power);
+ energy_use = 0;
+ }
+ break;
+ }
+
+ p_ptr->redraw |= (PR_HP | PR_MANA);
+ p_ptr->window |= (PW_PLAYER);
+}
+
+/*
+ * Print a batch of power.
+ */
+static void print_power_batch(int *p, int start, int max, bool_ mode)
+{
+ char buff[80];
+ power_type* spell;
+ int i = start, j = 0;
+
+ if (mode) prt(format(" %-31s Level Mana Fail", "Name"), 1, 20);
+
+ for (i = start; i < (start + 20); i++)
+ {
+ if (i >= max) break;
+
+ spell = &powers_type[p[i]];
+
+ sprintf(buff, " %c-%3d) %-30s %5d %4d %s@%d", I2A(j), p[i] + 1, spell->name,
+ spell->level, spell->cost, stat_names[spell->stat], spell->diff);
+
+ if (mode) prt(buff, 2 + j, 20);
+ j++;
+ }
+ if (mode) prt("", 2 + j, 20);
+ prt(format("Select a power (a-%c), +/- to scroll:", I2A(j - 1)), 0, 0);
+}
+
+
+/*
+ * List powers and ask to pick one.
+ */
+
+static power_type* select_power(int *x_idx)
+{
+ char which;
+ int max = 0, i, start = 0;
+ power_type* ret;
+ bool_ mode = FALSE;
+ int *p;
+
+ C_MAKE(p, power_max, int);
+ /* Count the max */
+ for (i = 0; i < power_max; i++)
+ {
+ if (p_ptr->powers[i])
+ {
+ p[max++] = i;
+ }
+ }
+
+ /* Exit if there aren't powers */
+ if (max == 0)
+ {
+ *x_idx = -1;
+ ret = NULL;
+ msg_print("You don't have any special powers.");
+ }
+ else
+ {
+ character_icky = TRUE;
+ Term_save();
+
+ while (1)
+ {
+ print_power_batch(p, start, max, mode);
+ which = inkey();
+
+ if (which == ESCAPE)
+ {
+ *x_idx = -1;
+ ret = NULL;
+ break;
+ }
+ else if (which == '*' || which == '?' || which == ' ')
+ {
+ mode = (mode) ? FALSE : TRUE;
+ Term_load();
+ character_icky = FALSE;
+ }
+ else if (which == '+')
+ {
+ start += 20;
+ if (start >= max) start -= 20;
+ Term_load();
+ character_icky = FALSE;
+ }
+ else if (which == '-')
+ {
+ start -= 20;
+ if (start < 0) start += 20;
+ Term_load();
+ character_icky = FALSE;
+ }
+ else
+ {
+ which = tolower(which);
+ if (start + A2I(which) >= max)
+ {
+ bell();
+ continue;
+ }
+ if (start + A2I(which) < 0)
+ {
+ bell();
+ continue;
+ }
+
+ *x_idx = p[start + A2I(which)];
+ ret = &powers_type[p[start + A2I(which)]];
+ break;
+ }
+ }
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ C_FREE(p, power_max, int);
+
+ return ret;
+}
+
+/* Ask & execute a power */
+void do_cmd_power()
+{
+ int x_idx;
+ power_type *x_ptr;
+ bool_ push = TRUE;
+
+ /* Get the skill, if available */
+ if (repeat_pull(&x_idx))
+ {
+ if ((x_idx < 0) || (x_idx >= power_max)) return;
+ x_ptr = &powers_type[x_idx];
+ push = FALSE;
+ }
+ else if (!command_arg) x_ptr = select_power(&x_idx);
+ else
+ {
+ x_idx = command_arg - 1;
+ if ((x_idx < 0) || (x_idx >= power_max)) return;
+ x_ptr = &powers_type[x_idx];
+ }
+
+ if (x_ptr == NULL) return;
+
+ if (push) repeat_push(x_idx);
+
+ if (p_ptr->powers[x_idx])
+ power_activate(x_idx);
+ else
+ msg_print("You do not have access to this power.");
+}
diff --git a/src/q_betwen.c b/src/q_betwen.c
new file mode 100644
index 00000000..e6452dd9
--- /dev/null
+++ b/src/q_betwen.c
@@ -0,0 +1,188 @@
+#undef cquest
+#define cquest (quest[QUEST_BETWEEN])
+
+bool_ quest_between_move_hook(char *fmt)
+{
+ s32b y;
+ s32b x;
+ cave_type *c_ptr;
+
+ y = get_next_arg(fmt);
+ x = get_next_arg(fmt);
+ c_ptr = &cave[y][x];
+
+ if (cquest.status != QUEST_STATUS_TAKEN) return FALSE;
+
+ /* The tower of Turgon */
+ if ((c_ptr->feat == FEAT_SHOP) && (c_ptr->special == 27))
+ {
+ cmsg_print(TERM_YELLOW, "Turgon is there.");
+ cmsg_print(TERM_YELLOW, "'Ah, thank you, noble hero! Now please return to Minas Anor to finish the link.'");
+
+ cquest.status = QUEST_STATUS_COMPLETED;
+
+ return TRUE;
+ }
+
+ /* Only 1 ambush */
+ if (cquest.data[0]) return (FALSE);
+
+ if (!p_ptr->wild_mode)
+ {
+ if (p_ptr->wilderness_y > 19) return (FALSE);
+ }
+ else
+ {
+ if (p_ptr->py > 19) return (FALSE);
+ }
+
+ /* Mark as entered */
+ cquest.data[0] = TRUE;
+
+ p_ptr->wild_mode = FALSE;
+ p_ptr->inside_quest = QUEST_BETWEEN;
+ p_ptr->leaving = TRUE;
+
+ cmsg_print(TERM_YELLOW, "Looks like a full wing of thunderlords ambushes you!");
+ cmsg_print(TERM_YELLOW, "Trone steps forth and speaks: 'The secret of the Void Jumpgates");
+ cmsg_print(TERM_YELLOW, "will not be used by any but the thunderlords!'");
+
+ return FALSE;
+}
+bool_ quest_between_gen_hook(char *fmt)
+{
+ int x, y;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_BETWEEN) return FALSE;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("between.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ /* Otherwise instadeath */
+ energy_use = 0;
+
+ dungeon_flags2 |= DF2_NO_GENO;
+
+ return TRUE;
+}
+bool_ quest_between_finish_hook(char *fmt)
+{
+ s32b q_idx;
+ object_type forge, *q_ptr;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_BETWEEN) return FALSE;
+
+ c_put_str(TERM_YELLOW, "Ah you finally arrived, I hope your travel wasn't too hard.", 8, 0);
+ c_put_str(TERM_YELLOW, "As a reward you can freely use the Void Jumpgates for quick travel.", 9, 0);
+ c_put_str(TERM_YELLOW, "Oh and take that horn, it shall serve you well.", 10, 0);
+
+ /* prepare the reward */
+ q_ptr = &forge;
+ object_prep(q_ptr, test_item_name("& Golden Horn~ of the Thunderlords"));
+ q_ptr->found = OBJ_FOUND_REWARD;
+ q_ptr->number = 1;
+
+
+ /* Mega-Hack -- Actually create the Golden Horn of the Thunderlords */
+ k_allow_special[test_item_name("& Golden Horn~ of the Thunderlords")] = TRUE;
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+ k_allow_special[test_item_name("& Golden Horn~ of the Thunderlords")] = FALSE;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->discount = 100;
+ q_ptr->ident |= IDENT_STOREB;
+ (void)inven_carry(q_ptr, FALSE);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_NULL;
+
+ del_hook(HOOK_QUEST_FINISH, quest_between_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_between_death_hook(char *fmt)
+{
+ int i, mcnt = 0;
+
+ if (p_ptr->inside_quest != QUEST_BETWEEN) return FALSE;
+
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status <= MSTATUS_NEUTRAL) mcnt++;
+ }
+
+ if (mcnt < 2)
+ {
+ cmsg_print(TERM_YELLOW, "You can escape now.");
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_LESS);
+ cave[p_ptr->py][p_ptr->px].special = 0;
+
+ return FALSE;
+ }
+
+
+ return FALSE;
+}
+bool_ quest_between_dump_hook(char *fmt)
+{
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(hook_file, "\n You established a permanent void jumpgates liaison between Minas Anor and Gondolin,");
+ fprintf(hook_file, "\n thus allowing the last alliance to exist.");
+ }
+ return (FALSE);
+}
+bool_ quest_between_forbid_hook(char *fmt)
+{
+ s32b q_idx;
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_BETWEEN) return (FALSE);
+
+ if (p_ptr->lev < 45)
+ {
+ c_put_str(TERM_WHITE, "I fear you are not ready for the next quest, come back later.", 8, 0);
+ return (TRUE);
+ }
+ return (FALSE);
+}
+bool_ quest_between_init_hook(int q)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MOVE, quest_between_move_hook, "between_move");
+ add_hook(HOOK_GEN_QUEST, quest_between_gen_hook, "between_gen");
+ add_hook(HOOK_QUEST_FINISH, quest_between_finish_hook, "between_finish");
+ add_hook(HOOK_MONSTER_DEATH, quest_between_death_hook, "between_death");
+ }
+ add_hook(HOOK_CHAR_DUMP, quest_between_dump_hook, "between_dump");
+ add_hook(HOOK_INIT_QUEST, quest_between_forbid_hook, "between_forbid");
+ return (FALSE);
+}
diff --git a/src/q_dragons.c b/src/q_dragons.c
new file mode 100644
index 00000000..025e8ecd
--- /dev/null
+++ b/src/q_dragons.c
@@ -0,0 +1,150 @@
+#undef cquest
+#define cquest (quest[QUEST_DRAGONS])
+
+bool_ quest_dragons_gen_hook(char *fmt)
+{
+ int x, y, i;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_DRAGONS) return FALSE;
+
+ /* Just in case we didnt talk the the mayor */
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("dragons.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, FALSE);
+ dungeon_flags2 |= DF2_NO_GENO;
+
+ /* Place some columns */
+ for (i = 35; i > 0; )
+ {
+ int flags;
+ y = rand_int(21) + 3;
+ x = rand_int(31) + 3;
+ /* Bar columns on even squares so the whole level is guaranteed to be
+ accessible */
+ flags = f_info[cave[y][x].feat].flags1;
+ if (!(flags % 2) && !(flags & FF1_PERMANENT) && (flags & FF1_FLOOR))
+ {
+ --i;
+ cave_set_feat(y, x, FEAT_MOUNTAIN);
+ }
+ }
+
+ /* Place some random dragons */
+ for (i = 25; i > 0; )
+ {
+ int m_idx, flags;
+ y = rand_int(21) + 3;
+ x = rand_int(31) + 3;
+ flags = f_info[cave[y][x].feat].flags1;
+ if (!(flags & FF1_PERMANENT) && (flags & FF1_FLOOR))
+ {
+ /* blue, white, red, black, bronze, gold, green, multi-hued */
+ int baby_dragons[8] = {163, 164, 167, 166, 218, 219, 165, 204};
+ int young_dragons[8] = {459, 460, 563, 546, 462, 559, 461, 556};
+ int mature_dragons[8] = {560, 549, 589, 592, 562, 590, 561, 593};
+ int happy_dragons[8] = {601, 617, 644, 624, 602, 645, 618, 675};
+
+ int chance, dragon, color;
+
+ color = rand_int(8);
+ chance = rand_int(100);
+ if (chance == 0)
+ dragon = happy_dragons[color];
+ else if (chance < 33)
+ dragon = baby_dragons[color];
+ else if (chance < 66)
+ dragon = young_dragons[color];
+ else
+ dragon = mature_dragons[color];
+
+ --i;
+ m_idx = place_monster_one(y, x, dragon, 0, magik(33), MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ }
+ }
+
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+bool_ quest_dragons_death_hook(char *fmt)
+{
+ int i, mcnt = 0;
+
+ if (p_ptr->inside_quest != QUEST_DRAGONS) return FALSE;
+
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status <= MSTATUS_ENEMY) mcnt++;
+ }
+
+ /* Nobody left ? */
+ if (mcnt <= 1)
+ {
+ quest[p_ptr->inside_quest].status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_MONSTER_DEATH, quest_dragons_death_hook);
+ del_hook(HOOK_GEN_QUEST, quest_dragons_gen_hook);
+ process_hooks_restart = TRUE;
+
+ cmsg_print(TERM_YELLOW, "Gondolin is safer now.");
+ return (FALSE);
+ }
+ return FALSE;
+}
+
+bool_ quest_dragons_finish_hook(char *fmt)
+{
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_DRAGONS) return FALSE;
+
+ c_put_str(TERM_YELLOW, "Thank you for killing the dragons!", 8, 0);
+ c_put_str(TERM_YELLOW, "You can use the cave as your house as a reward.", 9, 0);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_EOL;
+
+ return TRUE;
+}
+
+bool_ quest_dragons_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_dragons_death_hook, "dragons_monster_death");
+ add_hook(HOOK_QUEST_FINISH, quest_dragons_finish_hook, "dragons_finish");
+ add_hook(HOOK_GEN_QUEST, quest_dragons_gen_hook, "dragons_geb");
+ }
+ return (FALSE);
+}
diff --git a/src/q_eol.c b/src/q_eol.c
new file mode 100644
index 00000000..5b1cf78e
--- /dev/null
+++ b/src/q_eol.c
@@ -0,0 +1,195 @@
+#undef cquest
+#define cquest (quest[QUEST_EOL])
+
+bool_ quest_eol_gen_hook(char *fmt)
+{
+ int x, y;
+ bool_ done = FALSE;
+ int xsize = 50, ysize = 30, y0, x0;
+ int m_idx = 0;
+
+ if (p_ptr->inside_quest != QUEST_EOL) return FALSE;
+
+ x0 = 2 + (xsize / 2);
+ y0 = 2 + (ysize / 2);
+
+ feat_wall_outer = FEAT_WALL_OUTER;
+ feat_wall_inner = FEAT_WALL_INNER;
+
+ for (y = 0; y < 100; y++)
+ {
+ floor_type[y] = FEAT_FLOOR;
+ fill_type[y] = FEAT_WALL_OUTER;
+ }
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ while (!done)
+ {
+ int grd, roug, cutoff;
+
+ /* testing values for these parameters feel free to adjust*/
+ grd = 2 ^ (randint(4));
+
+ /* want average of about 16 */
+ roug = randint(8) * randint(4);
+
+ /* about size/2 */
+ cutoff = randint(xsize / 4) + randint(ysize / 4) + randint(xsize / 4) + randint(ysize / 4);
+
+ /* make it */
+ generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff);
+
+ /* Convert to normal format+ clean up*/
+ done = generate_fracave(y0, x0, xsize, ysize, cutoff, FALSE, TRUE);
+ }
+
+ /* Place a few traps */
+ for (x = xsize - 1; x >= 2; x--)
+ for (y = ysize - 1; y >= 2; y--)
+ {
+ if (!cave_clean_bold(y, x)) continue;
+
+ /* Place eol at the other end */
+ if (!m_idx)
+ {
+ m_allow_special[test_monster_name("Eol, the Dark Elf")] = TRUE;
+ m_idx = place_monster_one(y, x, test_monster_name("Eol, the Dark Elf"), 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[test_monster_name("Eol, the Dark Elf")] = FALSE;
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ }
+
+ if (magik(18))
+ {
+ place_trap(y, x);
+ }
+
+ /* Place player at one end */
+ p_ptr->py = y;
+ p_ptr->px = x;
+ }
+
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_LESS);
+
+ return TRUE;
+}
+bool_ quest_eol_finish_hook(char *fmt)
+{
+ object_type forge, *q_ptr;
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_EOL) return FALSE;
+
+ c_put_str(TERM_YELLOW, "A tragedy, but the deed needed to be done.", 8, 0);
+ c_put_str(TERM_YELLOW, "Accept my thanks, and that reward.", 9, 0);
+
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_LITE, SV_LITE_DWARVEN));
+ q_ptr->found = OBJ_FOUND_REWARD;
+ q_ptr->name2 = EGO_LITE_MAGI;
+ apply_magic(q_ptr, 1, FALSE, FALSE, FALSE);
+ q_ptr->number = 1;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_STOREB;
+ (void)inven_carry(q_ptr, FALSE);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_NIRNAETH;
+ quest[*(quest[q_idx].plot)].init(*(quest[q_idx].plot));
+
+ del_hook(HOOK_QUEST_FINISH, quest_eol_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_eol_fail_hook(char *fmt)
+{
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_EOL) return FALSE;
+
+ c_put_str(TERM_YELLOW, "You fled ! I did not think you would flee...", 8, 0);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_NULL;
+
+ del_hook(HOOK_QUEST_FAIL, quest_eol_fail_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_eol_death_hook(char *fmt)
+{
+ s32b r_idx, m_idx;
+
+ m_idx = get_next_arg(fmt);
+ r_idx = m_list[m_idx].r_idx;
+
+ if (p_ptr->inside_quest != QUEST_EOL) return FALSE;
+
+ if (r_idx == test_monster_name("Eol, the Dark Elf"))
+ {
+ cmsg_print(TERM_YELLOW, "Such a sad end...");
+ cquest.status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_MONSTER_DEATH, quest_eol_death_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+ }
+
+ return FALSE;
+}
+bool_ quest_eol_stair_hook(char *fmt)
+{
+ monster_race *r_ptr = &r_info[test_monster_name("Eol, the Dark Elf")];
+ cptr down;
+
+ down = get_next_arg_str(fmt);
+
+ if (p_ptr->inside_quest != QUEST_EOL) return FALSE;
+
+ if (cave[p_ptr->py][p_ptr->px].feat != FEAT_LESS) return TRUE;
+
+ if (r_ptr->max_num)
+ {
+ if (!strcmp(down, "up"))
+ {
+ /* Flush input */
+ flush();
+
+ if (!get_check("Really abandon the quest?")) return TRUE;
+
+ cmsg_print(TERM_YELLOW, "You flee away from Eol...");
+ cquest.status = QUEST_STATUS_FAILED;
+ del_hook(HOOK_STAIR, quest_eol_stair_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+ }
+ }
+
+ return FALSE;
+}
+bool_ quest_eol_init_hook(int q)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_eol_death_hook, "eol_death");
+ add_hook(HOOK_GEN_QUEST, quest_eol_gen_hook, "eol_gen");
+ add_hook(HOOK_STAIR, quest_eol_stair_hook, "eol_stair");
+ add_hook(HOOK_QUEST_FAIL, quest_eol_fail_hook, "eol_fail");
+ add_hook(HOOK_QUEST_FINISH, quest_eol_finish_hook, "eol_finish");
+ }
+ return (FALSE);
+}
diff --git a/src/q_evil.c b/src/q_evil.c
new file mode 100644
index 00000000..a143f65c
--- /dev/null
+++ b/src/q_evil.c
@@ -0,0 +1,117 @@
+#undef cquest
+#define cquest (quest[QUEST_EVIL])
+
+bool_ quest_evil_gen_hook(char *fmt)
+{
+ int x, y, i;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_EVIL) return FALSE;
+
+ /* Just in case we didnt talk the the mayor */
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("evil.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, FALSE);
+ dungeon_flags2 |= DF2_NO_GENO;
+
+ /* Place some random balrogs */
+ for (i = 6; i > 0; )
+ {
+ int m_idx, flags;
+ y = rand_int(21) + 3;
+ x = rand_int(31) + 3;
+ flags = f_info[cave[y][x].feat].flags1;
+ if (!(flags & FF1_PERMANENT) && (flags & FF1_FLOOR))
+ {
+ m_idx = place_monster_one(y, x, 996, 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ --i;
+ }
+ }
+
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+bool_ quest_evil_death_hook(char *fmt)
+{
+ int i, mcnt = 0;
+
+ if (p_ptr->inside_quest != QUEST_EVIL) return FALSE;
+
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status <= MSTATUS_ENEMY) mcnt++;
+ }
+
+ /* Nobody left ? */
+ if (mcnt <= 1)
+ {
+ /* TODO: change to COMPLETED and remove NULL when mayor is added */
+ quest[p_ptr->inside_quest].status = QUEST_STATUS_FINISHED;
+ *(quest[p_ptr->inside_quest].plot) = QUEST_NULL;
+ del_hook(HOOK_MONSTER_DEATH, quest_evil_death_hook);
+ del_hook(HOOK_GEN_QUEST, quest_evil_gen_hook);
+ process_hooks_restart = TRUE;
+
+ cmsg_print(TERM_YELLOW, "Khazad-Dum is safer now.");
+ return (FALSE);
+ }
+ return FALSE;
+}
+
+bool_ quest_evil_finish_hook(char *fmt)
+{
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_EVIL) return FALSE;
+
+ c_put_str(TERM_YELLOW, "Thank you for saving us!", 8, 0);
+ c_put_str(TERM_YELLOW, "You can use the cave as your house as a reward.", 9, 0);
+
+ /* End the plot */
+ *(quest[q_idx].plot) = QUEST_NULL;
+
+ return TRUE;
+}
+
+bool_ quest_evil_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_evil_death_hook, "evil_monster_death");
+ add_hook(HOOK_QUEST_FINISH, quest_evil_finish_hook, "evil_finish");
+ add_hook(HOOK_GEN_QUEST, quest_evil_gen_hook, "evil_geb");
+ }
+ return (FALSE);
+}
diff --git a/src/q_haunted.c b/src/q_haunted.c
new file mode 100644
index 00000000..db8992bc
--- /dev/null
+++ b/src/q_haunted.c
@@ -0,0 +1,147 @@
+#undef cquest
+#define cquest (quest[QUEST_HAUNTED])
+
+bool_ quest_haunted_gen_hook(char *fmt)
+{
+ int x, y, i, m_idx;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_HAUNTED) return FALSE;
+
+ /* Just in case we didnt talk the the mayor */
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("haunted.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, FALSE);
+ dungeon_flags2 |= DF2_NO_GENO;
+
+ /* Place some ghosts */
+ for (i = 12; i > 0; )
+ {
+ int flags;
+ y = rand_int(21) + 3;
+ x = rand_int(31) + 3;
+ flags = f_info[cave[y][x].feat].flags1;
+ if (!(flags & FF1_PERMANENT) && (flags & FF1_FLOOR))
+ {
+ m_idx = place_monster_one(y, x, 477, 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ --i;
+ }
+ }
+
+ /* Place some random monsters to haunt us */
+ for (i = damroll(4, 4); i > 0; )
+ {
+ int flags;
+ y = rand_int(21) + 3;
+ x = rand_int(31) + 3;
+ flags = f_info[cave[y][x].feat].flags1;
+ if (!(flags & FF1_PERMANENT) && (flags & FF1_FLOOR))
+ {
+ int monsters[22] = { 65, 100, 124, 125, 133, 231, 273, 327, 365, 416, 418,
+ 507, 508, 533, 534, 553, 554, 555, 577, 607, 622, 665};
+ int monster = monsters[rand_int(22)];
+ m_idx = place_monster_one(y, x, monster, 0, FALSE, MSTATUS_ENEMY);
+ m_list[m_idx].mflag |= MFLAG_QUEST;
+ --i;
+ }
+ }
+
+ /* Place some random traps */
+ for (i = 10 + damroll(4, 4); i > 0; )
+ {
+ int flags;
+ y = rand_int(21) + 3;
+ x = rand_int(31) + 3;
+ flags = f_info[cave[y][x].feat].flags1;
+ if (!(flags & FF1_PERMANENT) && (flags & FF1_FLOOR))
+ {
+ --i;
+ place_trap(y, x);
+ }
+ }
+
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+bool_ quest_haunted_death_hook(char *fmt)
+{
+ int i, mcnt = 0;
+
+ if (p_ptr->inside_quest != QUEST_HAUNTED) return FALSE;
+
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status <= MSTATUS_ENEMY) mcnt++;
+ }
+
+ /* Nobody left ? */
+ if (mcnt <= 1)
+ {
+ quest[p_ptr->inside_quest].status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_MONSTER_DEATH, quest_haunted_death_hook);
+ del_hook(HOOK_GEN_QUEST, quest_haunted_gen_hook);
+ process_hooks_restart = TRUE;
+
+ cmsg_print(TERM_YELLOW, "Minas Anor is safer now.");
+ return (FALSE);
+ }
+ return FALSE;
+}
+
+bool_ quest_haunted_finish_hook(char *fmt)
+{
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_HAUNTED) return FALSE;
+
+ c_put_str(TERM_YELLOW, "Thank you for saving us!", 8, 0);
+ c_put_str(TERM_YELLOW, "You can use the building as your house as a reward.", 9, 0);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_BETWEEN;
+
+ return TRUE;
+}
+
+bool_ quest_haunted_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_haunted_death_hook, "haunted_monster_death");
+ add_hook(HOOK_QUEST_FINISH, quest_haunted_finish_hook, "haunted_finish");
+ add_hook(HOOK_GEN_QUEST, quest_haunted_gen_hook, "haunted_geb");
+ }
+ return (FALSE);
+}
diff --git a/src/q_hobbit.c b/src/q_hobbit.c
new file mode 100644
index 00000000..f3b7d856
--- /dev/null
+++ b/src/q_hobbit.c
@@ -0,0 +1,195 @@
+#undef cquest
+#define cquest (quest[QUEST_HOBBIT])
+
+bool_ quest_hobbit_town_gen_hook(char *fmt)
+{
+ int x = 1, y = 1, tries = 10000;
+ s32b small;
+
+ small = get_next_arg(fmt);
+
+ if ((turn < (cquest.data[1] + (DAY * 10L))) || (cquest.status > QUEST_STATUS_COMPLETED) || (small) || (p_ptr->town_num != 1)) return (FALSE);
+
+ /* Find a good position */
+ while (tries)
+ {
+ /* Get a random spot */
+ y = randint(20) + (cur_hgt / 2) - 10;
+ x = randint(20) + (cur_wid / 2) - 10;
+
+ /* Is it a good spot ? */
+ /* Not in player los, and avoid shop grids */
+ if (!los(p_ptr->py, p_ptr->px, y, x) && cave_empty_bold(y, x) &&
+ cave_plain_floor_bold(y, x)) break;
+
+ /* One less try */
+ tries--;
+ }
+
+ /* Place Melinda */
+ m_allow_special[test_monster_name("Melinda Proudfoot")] = TRUE;
+ place_monster_one(y, x, test_monster_name("Melinda Proudfoot"), 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[test_monster_name("Melinda Proudfoot")] = FALSE;
+
+ return FALSE;
+}
+bool_ quest_hobbit_gen_hook(char *fmt)
+{
+ int x = 1, y = 1, tries = 10000;
+
+ if ((cquest.status != QUEST_STATUS_TAKEN) || (dun_level != cquest.data[0]) || (dungeon_type != DUNGEON_MAZE)) return FALSE;
+
+ /* Find a good position */
+ while (tries)
+ {
+ /* Get a random spot */
+ y = randint(cur_hgt - 4) + 2;
+ x = randint(cur_wid - 4) + 2;
+
+ /* Is it a good spot ? */
+ if (cave_empty_bold(y, x)) break;
+
+ /* One less try */
+ tries--;
+ }
+
+ /* Place the hobbit */
+ m_allow_special[test_monster_name("Merton Proudfoot, the lost hobbit")] = TRUE;
+ place_monster_one(y, x, test_monster_name("Merton Proudfoot, the lost hobbit"), 0, FALSE, MSTATUS_FRIEND);
+ m_allow_special[test_monster_name("Merton Proudfoot, the lost hobbit")] = FALSE;
+
+ return FALSE;
+}
+bool_ quest_hobbit_give_hook(char *fmt)
+{
+ object_type *o_ptr;
+ monster_type *m_ptr;
+ s32b m_idx, item;
+
+ m_idx = get_next_arg(fmt);
+ item = get_next_arg(fmt);
+
+ o_ptr = &p_ptr->inventory[item];
+ m_ptr = &m_list[m_idx];
+
+ if (m_ptr->r_idx != test_monster_name("Merton Proudfoot, the lost hobbit")) return (FALSE);
+
+ if ((o_ptr->tval != TV_SCROLL) || (o_ptr->sval != SV_SCROLL_WORD_OF_RECALL)) return (FALSE);
+
+ msg_print("'Oh, thank you, noble one!'");
+ msg_print("Merton Proudfoot reads the scroll and is recalled to the safety of his home.");
+
+ delete_monster_idx(m_idx);
+
+ inc_stack_size_ex(item, -1, OPTIMIZE, NO_DESCRIBE);
+
+ cquest.status = QUEST_STATUS_COMPLETED;
+
+ del_hook(HOOK_GIVE, quest_hobbit_give_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_hobbit_speak_hook(char *fmt)
+{
+ s32b m_idx = get_next_arg(fmt);
+
+ if (m_list[m_idx].r_idx != test_monster_name("Melinda Proudfoot")) return (FALSE);
+
+ if (cquest.status < QUEST_STATUS_COMPLETED)
+ {
+ cptr m_name;
+
+ m_name = get_next_arg_str(fmt);
+
+ msg_format("%^s begs for your help.", m_name);
+ }
+ return (TRUE);
+}
+bool_ quest_hobbit_chat_hook(char *fmt)
+{
+ monster_type *m_ptr;
+ s32b m_idx;
+
+ m_idx = get_next_arg(fmt);
+
+ m_ptr = &m_list[m_idx];
+
+ if (m_ptr->r_idx != test_monster_name("Melinda Proudfoot")) return (FALSE);
+
+ if (cquest.status < QUEST_STATUS_COMPLETED)
+ {
+ msg_print("Oh! Oh!");
+ msg_print("My poor Merton, where is my poor Merton? He was playing near that dreadful");
+ msg_print("maze and never been seen again! Could you find him for me?");
+
+ cquest.status = QUEST_STATUS_TAKEN;
+ quest[QUEST_HOBBIT].init(QUEST_HOBBIT);
+ }
+ else if (cquest.status == QUEST_STATUS_COMPLETED)
+ {
+ object_type forge, *q_ptr;
+
+ msg_print("My Merton is back! You saved him, hero.");
+ msg_print("Take this as a proof of my gratitude. It was given to my family");
+ msg_print("by a famed wizard, but it should serve you better than me.");
+
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_ROD, SV_ROD_RECALL));
+ q_ptr->number = 1;
+ q_ptr->found = OBJ_FOUND_REWARD;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_STOREB;
+ (void)inven_carry(q_ptr, FALSE);
+
+ cquest.status = QUEST_STATUS_FINISHED;
+
+ del_hook(HOOK_MON_SPEAK, quest_hobbit_speak_hook);
+ process_hooks_restart = TRUE;
+ delete_monster_idx(m_idx);
+
+ return TRUE;
+ }
+ else
+ {
+ msg_print("Thanks again.");
+ }
+
+ return TRUE;
+}
+bool_ quest_hobbit_dump_hook(char *fmt)
+{
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(hook_file, "\n You saved a young hobbit from an horrible fate.");
+ }
+ return (FALSE);
+}
+bool_ quest_hobbit_init_hook(int q_idx)
+{
+ /* Get a level to place the hobbit */
+ if (!cquest.data[0])
+ {
+ cquest.data[0] = rand_range(26, 34);
+ cquest.data[1] = turn;
+ if (wizard) message_add(MESSAGE_MSG, format("Hobbit level %d", cquest.data[0]), TERM_BLUE);
+ }
+
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_GIVE, quest_hobbit_give_hook, "hobbit_give");
+ add_hook(HOOK_GEN_LEVEL, quest_hobbit_gen_hook, "hobbit_gen");
+ add_hook(HOOK_WILD_GEN, quest_hobbit_town_gen_hook, "hobbit_town_gen");
+ add_hook(HOOK_CHAT, quest_hobbit_chat_hook, "hobbit_chat");
+ add_hook(HOOK_MON_SPEAK, quest_hobbit_speak_hook, "hobbit_speak");
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ add_hook(HOOK_MON_SPEAK, quest_hobbit_speak_hook, "hobbit_speak");
+ add_hook(HOOK_WILD_GEN, quest_hobbit_town_gen_hook, "hobbit_town_gen");
+ add_hook(HOOK_CHAT, quest_hobbit_chat_hook, "hobbit_chat");
+ }
+ add_hook(HOOK_CHAR_DUMP, quest_hobbit_dump_hook, "hobbit_dump");
+ return (FALSE);
+}
diff --git a/src/q_invas.c b/src/q_invas.c
new file mode 100644
index 00000000..59c71d62
--- /dev/null
+++ b/src/q_invas.c
@@ -0,0 +1,201 @@
+#undef cquest
+#define cquest (quest[QUEST_INVASION])
+
+bool_ quest_invasion_gen_hook(char *fmt)
+{
+ int x, y;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_INVASION) return FALSE;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("maeglin.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ for (x = 3; x < xstart; x++)
+ for (y = 3; y < ystart; y++)
+ {
+ if (cave[y][x].feat == FEAT_MARKER)
+ {
+ cquest.data[0] = y;
+ cquest.data[1] = x;
+ p_ptr->py = y;
+ p_ptr->px = x;
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_LESS);
+ }
+ }
+
+ return TRUE;
+}
+bool_ quest_invasion_ai_hook(char *fmt)
+{
+ monster_type *m_ptr;
+ s32b m_idx;
+
+ m_idx = get_next_arg(fmt);
+ m_ptr = &m_list[m_idx];
+
+ if (p_ptr->inside_quest != QUEST_INVASION) return FALSE;
+
+ /* Ugly but thats better than a call to test_monster_name which is SLOW */
+ if (m_ptr->r_idx == 825)
+ {
+ /* Oups he fleed */
+ if ((m_ptr->fy == cquest.data[0]) && (m_ptr->fx == cquest.data[1]))
+ {
+ delete_monster_idx(m_idx);
+
+ cmsg_print(TERM_YELLOW, "Maeglin found the way to Gondolin! All hope is lost now!");
+ cquest.status = QUEST_STATUS_FAILED;
+ town_info[2].destroyed = TRUE;
+ return (FALSE);
+ }
+
+ /* Attack or flee ?*/
+ if (distance(m_ptr->fy, m_ptr->fx, p_ptr->py, p_ptr->px) <= 2)
+ {
+ return (FALSE);
+ }
+ else
+ {
+ process_hooks_return[0].num = cquest.data[0];
+ process_hooks_return[1].num = cquest.data[1];
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+bool_ quest_invasion_turn_hook(char *fmt)
+{
+ bool_ old_quick_messages = quick_messages;
+
+ if (cquest.status != QUEST_STATUS_UNTAKEN) return (FALSE);
+ if (p_ptr->lev < 45) return (FALSE);
+
+ /* Wait until the end of the current quest */
+ if (p_ptr->inside_quest) return ( FALSE);
+
+ /* Wait until the end of the astral mode */
+ if (p_ptr->astral) return ( FALSE);
+
+ /* Ok give the quest */
+ quick_messages = FALSE;
+ cmsg_print(TERM_YELLOW, "A Thunderlord appears in front of you and says:");
+ cmsg_print(TERM_YELLOW, "'Hello, noble hero. I am Liron, rider of Tolan. Turgon, King of Gondolin sent me.'");
+ cmsg_print(TERM_YELLOW, "'Gondolin is being invaded; he needs your help now or everything will be lost.'");
+ cmsg_print(TERM_YELLOW, "'Please come quickly!'");
+
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ quick_messages = old_quick_messages;
+
+ quest_invasion_init_hook(QUEST_INVASION);
+ del_hook(HOOK_END_TURN, quest_invasion_turn_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+}
+bool_ quest_invasion_dump_hook(char *fmt)
+{
+ if (cquest.status == QUEST_STATUS_FAILED)
+ {
+ fprintf(hook_file, "\n You abandoned Gondolin when it most needed you, thus causing its destruction.");
+ }
+ if ((cquest.status == QUEST_STATUS_FINISHED) || (cquest.status == QUEST_STATUS_REWARDED) || (cquest.status == QUEST_STATUS_COMPLETED))
+ {
+ fprintf(hook_file, "\n You saved Gondolin from destruction.");
+ }
+ return (FALSE);
+}
+bool_ quest_invasion_death_hook(char *fmt)
+{
+ s32b r_idx, m_idx;
+
+ m_idx = get_next_arg(fmt);
+ r_idx = m_list[m_idx].r_idx;
+
+ if (p_ptr->inside_quest != QUEST_INVASION) return FALSE;
+
+ if (r_idx == test_monster_name("Maeglin, the Traitor of Gondolin"))
+ {
+ cmsg_print(TERM_YELLOW, "You did it! Gondolin will remain hidden.");
+ cquest.status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_MONSTER_DEATH, quest_invasion_death_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+ }
+
+ return FALSE;
+}
+bool_ quest_invasion_stair_hook(char *fmt)
+{
+ cptr down;
+
+ down = get_next_arg_str(fmt);
+
+ if (p_ptr->inside_quest != QUEST_INVASION) return FALSE;
+
+ if (cave[p_ptr->py][p_ptr->px].feat != FEAT_LESS) return TRUE;
+
+ if (!strcmp(down, "up"))
+ {
+ if (cquest.status == QUEST_STATUS_FAILED)
+ {
+ cmsg_print(TERM_YELLOW, "The armies of Morgoth totally devastated Gondolin, leaving nothing but ruins...");
+ }
+ else if (cquest.status == QUEST_STATUS_COMPLETED)
+ {
+ cmsg_print(TERM_YELLOW, "Turgon appears before you and speaks:");
+ cmsg_print(TERM_YELLOW, "'I will never be able to thank you enough.'");
+ cmsg_print(TERM_YELLOW, "'My most powerful mages will cast a powerful spell for you, giving you extra life.'");
+
+ p_ptr->hp_mod += 150;
+ p_ptr->update |= (PU_HP);
+ cquest.status = QUEST_STATUS_FINISHED;
+ }
+ else
+ {
+ /* Flush input */
+ flush();
+
+ if (!get_check("Really abandon the quest?")) return TRUE;
+ cmsg_print(TERM_YELLOW, "You flee away from Maeglin and his army...");
+ cquest.status = QUEST_STATUS_FAILED;
+ town_info[2].destroyed = TRUE;
+ }
+ del_hook(HOOK_STAIR, quest_invasion_stair_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+ }
+
+ return TRUE;
+}
+bool_ quest_invasion_init_hook(int q_idx)
+{
+ add_hook(HOOK_END_TURN, quest_invasion_turn_hook, "invasion_turn");
+ add_hook(HOOK_CHAR_DUMP, quest_invasion_dump_hook, "invasion_dump");
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_AI, quest_invasion_ai_hook, "invasion_ai");
+ add_hook(HOOK_GEN_QUEST, quest_invasion_gen_hook, "invasion_gen");
+ add_hook(HOOK_MONSTER_DEATH, quest_invasion_death_hook, "invasion_death");
+ add_hook(HOOK_STAIR, quest_invasion_stair_hook, "invasion_stair");
+ }
+ return (FALSE);
+}
diff --git a/src/q_main.c b/src/q_main.c
new file mode 100644
index 00000000..a13b0790
--- /dev/null
+++ b/src/q_main.c
@@ -0,0 +1,176 @@
+bool_ quest_main_monsters_hook(char *fmt)
+{
+ s32b r_idx;
+ r_idx = get_next_arg(fmt);
+
+ /* Sauron */
+ if (r_idx == 860)
+ {
+ /* No Sauron until Necromancer dies */
+ if (r_info[819].max_num) return TRUE;
+ }
+ /* Morgoth */
+ else if (r_idx == 862)
+ {
+ /* No Morgoth until Sauron dies */
+ if (r_info[860].max_num) return TRUE;
+ }
+ return FALSE;
+}
+bool_ quest_morgoth_hook(char *fmt)
+{
+ /* Using test_monster_name() here would be a lot less ugly, but would take much more time */
+ monster_race *r_ptr = &r_info[862];
+
+ /* Need to kill him */
+ if (!r_ptr->max_num)
+ {
+ /* Total winner */
+ total_winner = WINNER_NORMAL;
+ has_won = WINNER_NORMAL;
+ quest[QUEST_MORGOTH].status = QUEST_STATUS_FINISHED;
+
+ /* Redraw the "title" */
+ p_ptr->redraw |= (PR_TITLE);
+
+ /* Congratulations */
+ if (quest[QUEST_ONE].status == QUEST_STATUS_FINISHED)
+ {
+ cmsg_print(TERM_L_GREEN, "*** CONGRATULATIONS ***");
+ cmsg_print(TERM_L_GREEN, "You have banished Morgoth's foul spirit from Ea, and as you watch, a cleansing");
+ cmsg_print(TERM_L_GREEN, "wind roars through the dungeon, dispersing the nether mists around where the");
+ cmsg_print(TERM_L_GREEN, "body fell. You feel thanks, and a touch of sorrow, from the Valar");
+ cmsg_print(TERM_L_GREEN, "for your deed. You will be forever heralded, your deed forever legendary.");
+ cmsg_print(TERM_L_GREEN, "You may retire (commit suicide) when you are ready.");
+ }
+ else
+ {
+ cmsg_print(TERM_VIOLET, "*** CONGRATULATIONS ***");
+ cmsg_print(TERM_VIOLET, "You have banished Morgoth from Arda, and made Ea a safer place.");
+ cmsg_print(TERM_VIOLET, "As you look down at the dispersing mists around Morgoth, a sudden intuition");
+ cmsg_print(TERM_VIOLET, "grasps you. Fingering the One Ring, you gather the nether mists around");
+ cmsg_print(TERM_VIOLET, "yourself, and inhale deeply their seductive power.");
+ cmsg_print(TERM_VIOLET, "You will be forever feared, your orders forever obeyed.");
+ cmsg_print(TERM_VIOLET, "You may retire (commit suicide) when you are ready.");
+ }
+
+ /* Continue the plot(maybe) */
+ del_hook(HOOK_MONSTER_DEATH, quest_morgoth_hook);
+ process_hooks_restart = TRUE;
+
+ /* Either ultra good if the one Ring is destroyed, or ultra evil if used */
+ if (quest[QUEST_ONE].status == QUEST_STATUS_FINISHED)
+ *(quest[QUEST_MORGOTH].plot) = QUEST_ULTRA_GOOD;
+ else
+ *(quest[QUEST_MORGOTH].plot) = QUEST_ULTRA_EVIL;
+ quest[*(quest[QUEST_MORGOTH].plot)].init(*(quest[QUEST_MORGOTH].plot));
+ }
+ return (FALSE);
+}
+bool_ quest_morgoth_dump_hook(char *fmt)
+{
+ if (quest[QUEST_MORGOTH].status >= QUEST_STATUS_COMPLETED)
+ {
+ if (quest[QUEST_ONE].status == QUEST_STATUS_FINISHED)
+ fprintf(hook_file, "\n You saved Arda and became a famed %s.", sp_ptr->winner);
+ else
+ fprintf(hook_file, "\n You became a new force of darkness and enslaved all free people.");
+ }
+ return (FALSE);
+}
+bool_ quest_morgoth_init_hook(int q_idx)
+{
+ if ((quest[QUEST_MORGOTH].status >= QUEST_STATUS_TAKEN) && (quest[QUEST_MORGOTH].status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_morgoth_hook, "morgort_death");
+ }
+ add_hook(HOOK_CHAR_DUMP, quest_morgoth_dump_hook, "morgoth_dump");
+ add_hook(HOOK_NEW_MONSTER, quest_main_monsters_hook, "main_new_monster");
+ return (FALSE);
+}
+
+bool_ quest_sauron_hook(char *fmt)
+{
+ /* Using test_monster_name() here would be a lot less ugly, but would take much more time */
+ monster_race *r_ptr = &r_info[860];
+
+ /* Need to kill him */
+ if (!r_ptr->max_num)
+ {
+ cmsg_print(TERM_YELLOW, "Well done! You are on the way to slaying Morgoth...");
+ quest[QUEST_SAURON].status = QUEST_STATUS_FINISHED;
+
+ quest[QUEST_MORGOTH].status = QUEST_STATUS_TAKEN;
+ quest_describe(QUEST_MORGOTH);
+
+ del_hook(HOOK_MONSTER_DEATH, quest_sauron_hook);
+ add_hook(HOOK_MONSTER_DEATH, quest_morgoth_hook, "morgort_death");
+ *(quest[QUEST_SAURON].plot) = QUEST_MORGOTH;
+ quest_morgoth_init_hook(QUEST_MORGOTH);
+
+ process_hooks_restart = TRUE;
+ }
+ return (FALSE);
+}
+
+bool_ quest_sauron_resurect_hook(char *fmt)
+{
+ s32b m_idx = get_next_arg(fmt);
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = &r_info[m_ptr->r_idx];
+
+ if ((r_ptr->flags7 & RF7_NAZGUL) && r_info[860].max_num)
+ {
+ msg_format("Somehow you feel %s is not totally destroyed...", (r_ptr->flags1 & RF1_FEMALE ? "she" : "he"));
+ r_ptr->max_num = 1;
+ }
+ else if ((m_ptr->r_idx == 860) && (quest[QUEST_ONE].status < QUEST_STATUS_FINISHED))
+ {
+ msg_print("Sauron will not be permanently defeated until the One Ring is either destroyed or used...");
+ r_ptr->max_num = 1;
+ }
+ return FALSE;
+}
+
+bool_ quest_sauron_init_hook(int q_idx)
+{
+ if ((quest[QUEST_SAURON].status >= QUEST_STATUS_TAKEN) && (quest[QUEST_SAURON].status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_sauron_hook, "sauron_death");
+ }
+ add_hook(HOOK_NEW_MONSTER, quest_main_monsters_hook, "main_new_monster");
+ add_hook(HOOK_MONSTER_DEATH, quest_sauron_resurect_hook, "sauron_resurect_death");
+ return (FALSE);
+}
+
+bool_ quest_necro_hook(char *fmt)
+{
+ /* Using test_monster_name() here would be a lot less ugly, but would take much more time */
+ monster_race *r_ptr = &r_info[819];
+
+ /* Need to kill him */
+ if (!r_ptr->max_num)
+ {
+ cmsg_print(TERM_YELLOW, "You see the spirit of the necromancer rise and flee...");
+ cmsg_print(TERM_YELLOW, "It looks like it was indeed Sauron...");
+ cmsg_print(TERM_YELLOW, "You should report that to Galadriel as soon as possible.");
+
+ quest[QUEST_NECRO].status = QUEST_STATUS_FINISHED;
+
+ *(quest[QUEST_NECRO].plot) = QUEST_ONE;
+ quest[*(quest[QUEST_NECRO].plot)].init(*(quest[QUEST_NECRO].plot));
+
+ del_hook(HOOK_MONSTER_DEATH, quest_necro_hook);
+ process_hooks_restart = TRUE;
+ }
+ return (FALSE);
+}
+bool_ quest_necro_init_hook(int q_idx)
+{
+ if ((quest[QUEST_NECRO].status >= QUEST_STATUS_TAKEN) && (quest[QUEST_NECRO].status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_necro_hook, "necro_death");
+ }
+ add_hook(HOOK_NEW_MONSTER, quest_main_monsters_hook, "main_new_monster");
+ return (FALSE);
+}
diff --git a/src/q_narsil.c b/src/q_narsil.c
new file mode 100644
index 00000000..27ec218e
--- /dev/null
+++ b/src/q_narsil.c
@@ -0,0 +1,108 @@
+#undef cquest
+#define cquest (quest[QUEST_NARSIL])
+
+bool_ quest_narsil_move_hook(char *fmt)
+{
+ s32b y, x;
+ cave_type *c_ptr;
+ int i;
+ object_type *o_ptr;
+
+ y = get_next_arg(fmt);
+ x = get_next_arg(fmt);
+ c_ptr = &cave[y][x];
+
+ if (cquest.status != QUEST_STATUS_TAKEN) return FALSE;
+
+ /* The castle of Aragorn */
+ if ((c_ptr->feat != FEAT_SHOP) || (c_ptr->special != 14)) return FALSE;
+
+ /* Look out for Narsil */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ o_ptr = get_object(i);
+
+ if (!o_ptr->k_idx) continue;
+
+ if (o_ptr->name1 == ART_NARSIL) break;
+ }
+
+ if (i == INVEN_TOTAL) return FALSE;
+
+ cmsg_print(TERM_YELLOW, "I heard that the broken sword had been found!");
+ cmsg_print(TERM_YELLOW, "I thought it was only a rumor... until now.");
+ cmsg_print(TERM_YELLOW, "What you have is really the sword that was broken.");
+ cmsg_print(TERM_YELLOW, "I will get it reforged...");
+ cmsg_print(TERM_L_BLUE, "Aragorn leaves for a few hours then comes back...");
+ cmsg_print(TERM_YELLOW, "Here it is, Anduril, the sword that was forged and is");
+ cmsg_print(TERM_YELLOW, "reforged again. Take it; you will surely need it for your quest.");
+
+ object_prep(o_ptr, lookup_kind(TV_SWORD, SV_LONG_SWORD));
+ o_ptr->name1 = ART_ANDURIL;
+ apply_magic(o_ptr, -1, TRUE, TRUE, TRUE);
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ inven_item_describe(i);
+ inven_item_optimize(i);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP | PW_PLAYER | PW_INVEN);
+
+ /* Continue the plot */
+ cquest.status = QUEST_STATUS_FINISHED;
+
+ del_hook(HOOK_MOVE, quest_narsil_move_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_narsil_dump_hook(char *fmt)
+{
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(hook_file, "\n The sword that was broken is now reforged.");
+ }
+ return (FALSE);
+}
+bool_ quest_narsil_identify_hook(char *fmt)
+{
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ int i;
+ object_type *o_ptr;
+ s32b item;
+
+ item = get_next_arg(fmt);
+
+ o_ptr = get_object(item);
+
+ if (o_ptr->name1 == ART_NARSIL)
+ {
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ for (i = 0; i < 5; i++)
+ {
+ if (quest[QUEST_NARSIL].desc[i][0] != '\0')
+ {
+ cmsg_print(TERM_YELLOW, quest[QUEST_NARSIL].desc[i]);
+ }
+ }
+
+ add_hook(HOOK_MOVE, quest_narsil_move_hook, "narsil_move");
+ del_hook(HOOK_IDENTIFY, quest_narsil_identify_hook);
+ process_hooks_restart = TRUE;
+ }
+ }
+
+ return (FALSE);
+}
+bool_ quest_narsil_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MOVE, quest_narsil_move_hook, "narsil_move");
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN) add_hook(HOOK_IDENTIFY, quest_narsil_identify_hook, "narsil_id");
+ add_hook(HOOK_CHAR_DUMP, quest_narsil_dump_hook, "narsil_dump");
+ return (FALSE);
+}
diff --git a/src/q_nazgul.c b/src/q_nazgul.c
new file mode 100644
index 00000000..66d3dc98
--- /dev/null
+++ b/src/q_nazgul.c
@@ -0,0 +1,116 @@
+#undef cquest
+#define cquest (quest[QUEST_NAZGUL])
+
+bool_ quest_nazgul_gen_hook(char *fmt)
+{
+ int m_idx, x = 1, y = 1, tries = 10000;
+ s32b small;
+
+ small = get_next_arg(fmt);
+
+ if ((cquest.status != QUEST_STATUS_TAKEN) || (small) || (p_ptr->town_num != 1)) return (FALSE);
+
+ /* Find a good position */
+ while (tries)
+ {
+ /* Get a random spot */
+ y = randint(cur_hgt - 4) + 2;
+ x = randint(cur_wid - 4) + 2;
+
+ /* Is it a good spot ? */
+ /* Not in player los */
+ if ((!los(p_ptr->py, p_ptr->px, y, x)) && cave_empty_bold(y, x)) break;
+
+ /* One less try */
+ tries--;
+ }
+
+ /* Place the nazgul */
+ m_allow_special[test_monster_name("Uvatha the Horseman")] = TRUE;
+ m_idx = place_monster_one(y, x, test_monster_name("Uvatha the Horseman"), 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ m_allow_special[test_monster_name("Uvatha the Horseman")] = FALSE;
+
+ return FALSE;
+}
+bool_ quest_nazgul_finish_hook(char *fmt)
+{
+ object_type forge, *q_ptr;
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_NAZGUL) return FALSE;
+
+ c_put_str(TERM_YELLOW, "I believe he will not come back! Thank you.", 8, 0);
+ c_put_str(TERM_YELLOW, "Some time ago a ranger gave me this.", 9, 0);
+ c_put_str(TERM_YELLOW, "I believe it will help you on your quest.", 10, 0);
+
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_FOOD, SV_FOOD_ATHELAS));
+ q_ptr->found = OBJ_FOUND_REWARD;
+ q_ptr->number = 6;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_STOREB;
+ (void)inven_carry(q_ptr, FALSE);
+
+ /* End the plot */
+ *(quest[q_idx].plot) = QUEST_NULL;
+
+ del_hook(HOOK_QUEST_FINISH, quest_nazgul_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_nazgul_dump_hook(char *fmt)
+{
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(hook_file, "\n You saved Bree from a dreadful Nazgul.");
+ }
+ return (FALSE);
+}
+bool_ quest_nazgul_forbid_hook(char *fmt)
+{
+ s32b q_idx;
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_NAZGUL) return (FALSE);
+
+ if (p_ptr->lev < 30)
+ {
+ c_put_str(TERM_WHITE, "I fear you are not ready for the next quest, come back later.", 8, 0);
+ return (TRUE);
+ }
+ return (FALSE);
+}
+bool_ quest_nazgul_death_hook(char *fmt)
+{
+ s32b r_idx, m_idx;
+
+ m_idx = get_next_arg(fmt);
+ r_idx = m_list[m_idx].r_idx;
+
+ if (cquest.status != QUEST_STATUS_TAKEN) return (FALSE);
+ if (r_idx != test_monster_name("Uvatha the Horseman")) return (FALSE);
+
+ cquest.status = QUEST_STATUS_COMPLETED;
+
+ del_hook(HOOK_MONSTER_DEATH, quest_nazgul_death_hook);
+ process_hooks_restart = TRUE;
+
+ return (FALSE);
+}
+bool_ quest_nazgul_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_nazgul_death_hook, "nazgul_death");
+ add_hook(HOOK_WILD_GEN, quest_nazgul_gen_hook, "nazgul_gen");
+ add_hook(HOOK_QUEST_FINISH, quest_nazgul_finish_hook, "nazgul_finish");
+ }
+ add_hook(HOOK_CHAR_DUMP, quest_nazgul_dump_hook, "nazgul_dump");
+ add_hook(HOOK_INIT_QUEST, quest_nazgul_forbid_hook, "nazgul_forbid");
+ return (FALSE);
+}
diff --git a/src/q_nirna.c b/src/q_nirna.c
new file mode 100644
index 00000000..be856d31
--- /dev/null
+++ b/src/q_nirna.c
@@ -0,0 +1,109 @@
+#undef cquest
+#define cquest (quest[QUEST_NIRNAETH])
+
+bool_ quest_nirnaeth_gen_hook(char *fmt)
+{
+ int x, y;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_NIRNAETH) return FALSE;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("nirnaeth.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ /* Count the number of monsters */
+ cquest.data[0] = 0;
+ cquest.data[1] = 0;
+ for (x = 2; x < xstart; x++)
+ for (y = 2; y < ystart; y++)
+ {
+ if (cave[y][x].m_idx) cquest.data[0]++;
+ }
+
+ return TRUE;
+}
+bool_ quest_nirnaeth_finish_hook(char *fmt)
+{
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_NIRNAETH) return FALSE;
+
+ /* Killed at least 2/3 of them ? better reward ! */
+ if (cquest.data[1] >= (2 * cquest.data[0] / 3))
+ {
+ c_put_str(TERM_YELLOW, "Not only did you found a way out, but you also destroyed a good", 8, 0);
+ c_put_str(TERM_YELLOW, "number of trolls! Thank you so much. Take this gold please.", 9, 0);
+ c_put_str(TERM_YELLOW, "I also grant you access to the royal jewelry shop!", 10, 0);
+
+ p_ptr->au += 200000;
+
+ /* Redraw gold */
+ p_ptr->redraw |= (PR_GOLD);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+ else
+ {
+ c_put_str(TERM_YELLOW, "I thank you for your efforts.", 8, 0);
+ c_put_str(TERM_YELLOW, "I grant you access to the royal jewelry shop!", 9, 0);
+ }
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_NULL;
+
+ del_hook(HOOK_QUEST_FINISH, quest_nirnaeth_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_nirnaeth_death_hook(char *fmt)
+{
+ if (p_ptr->inside_quest != QUEST_NIRNAETH) return FALSE;
+
+ cquest.data[1]++;
+
+ return FALSE;
+}
+bool_ quest_nirnaeth_stair_hook(char *fmt)
+{
+ if (p_ptr->inside_quest != QUEST_NIRNAETH) return FALSE;
+
+ if (cave[p_ptr->py][p_ptr->px].feat != FEAT_LESS) return (FALSE);
+
+ cmsg_print(TERM_YELLOW, "You found a way out!");
+ cquest.status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_STAIR, quest_nirnaeth_stair_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+}
+bool_ quest_nirnaeth_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_nirnaeth_death_hook, "nirnaeth_death");
+ add_hook(HOOK_GEN_QUEST, quest_nirnaeth_gen_hook, "nirnaeth_gen");
+ add_hook(HOOK_STAIR, quest_nirnaeth_stair_hook, "nirnaeth_stair");
+ add_hook(HOOK_QUEST_FINISH, quest_nirnaeth_finish_hook, "nirnaeth_finish");
+ }
+ return (FALSE);
+}
diff --git a/src/q_one.c b/src/q_one.c
new file mode 100644
index 00000000..4bfeaf3e
--- /dev/null
+++ b/src/q_one.c
@@ -0,0 +1,354 @@
+#undef cquest
+#define cquest (quest[QUEST_ONE])
+
+bool_ quest_one_move_hook(char *fmt)
+{
+ s32b y, x;
+ cave_type *c_ptr;
+
+ y = get_next_arg(fmt);
+ x = get_next_arg(fmt);
+ c_ptr = &cave[y][x];
+
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ if (quest[QUEST_NECRO].status < QUEST_STATUS_FINISHED) return (FALSE);
+
+ /* The mirror of Galadriel */
+ if ((c_ptr->feat != FEAT_SHOP) || (c_ptr->special != 23)) return (FALSE);
+
+ cmsg_print(TERM_YELLOW, "You meet Galadriel; she seems worried.");
+ cmsg_print(TERM_YELLOW, "'So it was Sauron that lurked in Dol Guldur...'");
+ cmsg_print(TERM_YELLOW, "'The Enemy is growing in power. Morgoth will be unreachable as long'");
+ cmsg_print(TERM_YELLOW, "'as his most powerful servant, Sauron, lives. But the power of Sauron'");
+ cmsg_print(TERM_YELLOW, "'lies in the One Ring. Our only hope is that you find it'");
+ cmsg_print(TERM_YELLOW, "'and destroy it. I know it will tempt you, but *NEVER* use it'");
+ cmsg_print(TERM_YELLOW, "'or it will corrupt you forever.'");
+
+ GOD(GOD_ERU)
+ {
+ cmsg_print(TERM_YELLOW, "'Also, Eru will abandon you if you wear it.'");
+ }
+
+ GOD(GOD_MANWE)
+ {
+ cmsg_print(TERM_YELLOW, "'Also, Manwe will abandon you if you wear it.'");
+ }
+
+ GOD(GOD_TULKAS)
+ {
+ cmsg_print(TERM_YELLOW, "'Also, Tulkas will abandon you if you wear it.'");
+ }
+
+ GOD(GOD_YAVANNA)
+ {
+ cmsg_print(TERM_YELLOW, "'Also, Yavanna will abandon you if you wear it.'");
+ }
+
+ cmsg_print(TERM_YELLOW, "'Without the destruction of the ring, Sauron's death can only be temporary'");
+ cmsg_print(TERM_YELLOW, "'When you have it, bring it to Mount Doom, in Mordor,'");
+ cmsg_print(TERM_YELLOW, "'to destroy it in the Great Fire where it was forged.'");
+ cmsg_print(TERM_YELLOW, "'I do not know where to find it. Seek it through Middle-earth. Maybe there'");
+ cmsg_print(TERM_YELLOW, "'are other people that might know.'");
+ cmsg_print(TERM_YELLOW, "'Do not forget: the Ring must be cast back into the fires of Mount Doom!'");
+
+ GOD(GOD_MELKOR)
+ {
+ cmsg_print(TERM_YELLOW, "'Melkor will abandon you when you do, but you must do it anyway!'");
+ }
+
+ /* Continue the plot */
+ cquest.status = QUEST_STATUS_TAKEN;
+ cquest.init(QUEST_ONE);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+bool_ quest_one_drop_hook(char *fmt)
+{
+ s32b o_idx;
+ object_type *o_ptr;
+
+ o_idx = get_next_arg(fmt);
+ o_ptr = &p_ptr->inventory[o_idx];
+
+ if (cquest.status != QUEST_STATUS_TAKEN) return FALSE;
+
+ if (o_ptr->name1 != ART_POWER) return FALSE;
+ if (cave[p_ptr->py][p_ptr->px].feat != FEAT_GREAT_FIRE) return FALSE;
+
+ cmsg_print(TERM_YELLOW, "You throw the One Ring into the #RGreat Fire#y; it is rapidly consumed");
+ cmsg_print(TERM_YELLOW, "by the searing flames.");
+ cmsg_print(TERM_YELLOW, "You feel the powers of evil weakening.");
+ cmsg_print(TERM_YELLOW, "Now you can go onto the hunt for Sauron!");
+
+ inc_stack_size_ex(o_idx, -99, OPTIMIZE, NO_DESCRIBE);
+
+ abandon_god(GOD_MELKOR);
+
+ /* Continue the plot */
+ cquest.status = QUEST_STATUS_FINISHED;
+ *(quest[QUEST_ONE].plot) = QUEST_SAURON;
+ quest[*(quest[QUEST_ONE].plot)].status = QUEST_STATUS_TAKEN;
+ quest[*(quest[QUEST_ONE].plot)].init(*(quest[QUEST_ONE].plot));
+
+ return TRUE;
+}
+bool_ quest_one_wield_hook(char *fmt)
+{
+ s32b o_idx;
+ object_type *o_ptr;
+
+ o_idx = get_next_arg(fmt);
+ o_ptr = &p_ptr->inventory[o_idx];
+
+ if (cquest.status != QUEST_STATUS_TAKEN) return FALSE;
+
+ if (o_ptr->name1 != ART_POWER) return FALSE;
+
+ /* Flush input */
+ flush();
+
+ if (!get_check("You were warned not to wear it; are you sure?")) return TRUE;
+ /* Flush input */
+ flush();
+
+ if (!get_check("You were warned not to wear it; are you *REALLY* sure?")) return TRUE;
+
+ /* Flush input */
+ flush();
+
+ if (!get_check("You were *WARNED* not to wear it; are you *R*E*A*L*L*Y* sure?")) return TRUE;
+
+ cmsg_print(TERM_YELLOW, "As you put it on your finger you feel #Ddark powers #ysapping your soul.");
+ cmsg_print(TERM_YELLOW, "The ring firmly binds to your finger!");
+ cmsg_print(TERM_YELLOW, "You feel you are drawn to the shadow world! Your material form weakens.");
+
+ abandon_god(GOD_ERU);
+ abandon_god(GOD_MANWE);
+ abandon_god(GOD_TULKAS);
+ abandon_god(GOD_YAVANNA);
+
+ /*
+ * Ok now we are evil, right ?
+ * Towns aren't, right ?
+ * So let's destroy them !
+ */
+ town_info[1].destroyed = TRUE;
+ town_info[2].destroyed = TRUE;
+ town_info[3].destroyed = TRUE;
+ town_info[4].destroyed = TRUE;
+ town_info[5].destroyed = TRUE;
+
+ /* Continue the plot */
+ cquest.status = QUEST_STATUS_FAILED_DONE;
+ *(quest[QUEST_ONE].plot) = QUEST_SAURON;
+ quest[*(quest[QUEST_ONE].plot)].status = QUEST_STATUS_TAKEN;
+ quest[*(quest[QUEST_ONE].plot)].init(*(quest[QUEST_ONE].plot));
+
+ /* Ok lets reset the lives counter */
+ p_ptr->lives = 0;
+
+ return FALSE;
+}
+bool_ quest_one_hp_hook(char *fmt)
+{
+ if (cquest.status == QUEST_STATUS_FAILED_DONE)
+ {
+ s32b mhp;
+ int i;
+
+ mhp = get_next_arg(fmt);
+
+ for (i = 0; i < p_ptr->lives + 1; i++)
+ mhp = (mhp * 2) / 3;
+
+ process_hooks_return[0].num = mhp;
+ return (TRUE);
+ }
+ return (FALSE);
+}
+bool_ quest_one_die_hook(char *fmt)
+{
+ if (cquest.status == QUEST_STATUS_FAILED_DONE)
+ {
+ if (p_ptr->mhp > 1)
+ {
+ cmsg_print(TERM_YELLOW, "You feel the power of the One Ring sustaining your life,");
+ cmsg_print(TERM_YELLOW, "but it drags you even more into the shadow world.");
+ return (TRUE);
+ }
+ else
+ {
+ cmsg_print(TERM_YELLOW, "The One Ring finally drags you totally to the shadow world.");
+ cmsg_print(TERM_YELLOW, "Your mortal existence ends there.");
+ strcpy(died_from, "being drawn to the shadow world");
+ }
+ }
+ return (FALSE);
+}
+bool_ quest_one_identify_hook(char *fmt)
+{
+ s32b item;
+
+ item = get_next_arg(fmt);
+
+ if (cquest.status == QUEST_STATUS_TAKEN)
+ {
+ object_type *o_ptr;
+
+ o_ptr = get_object(item);
+
+ if ((o_ptr->name1 == ART_POWER) && (!object_known_p(o_ptr)))
+ {
+ cmsg_print(TERM_YELLOW, "You finally found the One Ring, source of Sauron's power, and key to");
+ cmsg_print(TERM_YELLOW, "its destruction. Remember, bring it to Mount Doom and destroy it.");
+ cmsg_print(TERM_YELLOW, "And *NEVER* use it.");
+ }
+ }
+
+ return (FALSE);
+}
+bool_ quest_one_death_hook(char *fmt)
+{
+ s32b r_idx, m_idx;
+ bool_ ok = FALSE;
+
+ m_idx = get_next_arg(fmt);
+ r_idx = m_list[m_idx].r_idx;
+
+ if (a_info[ART_POWER].cur_num) return FALSE;
+
+ /* Paranoia */
+ if (cquest.status != QUEST_STATUS_TAKEN) return (FALSE);
+
+ if (magik(30) && (r_idx == test_monster_name("Sauron, the Sorcerer")))
+ {
+ ok = TRUE;
+ }
+ else if (magik(10) && (r_idx == test_monster_name("Ar-Pharazon the Golden")))
+ {
+ ok = TRUE;
+ }
+ else if (magik(10) && (r_idx == test_monster_name("Shelob, Spider of Darkness")))
+ {
+ ok = TRUE;
+ }
+ else if (magik(10) && (r_idx == test_monster_name("The Watcher in the Water")))
+ {
+ ok = TRUE;
+ }
+ else if (magik(10) && (r_idx == test_monster_name("Glaurung, Father of the Dragons")))
+ {
+ ok = TRUE;
+ }
+ else if (magik(10) && (r_idx == test_monster_name("Feagwath, the Undead Sorcerer")))
+ {
+ ok = TRUE;
+ }
+
+ if (ok)
+ {
+ int i;
+
+ /* Get local object */
+ object_type forge, *q_ptr = &forge;
+
+ /* Mega-Hack -- Prepare to make "Grond" */
+ object_prep(q_ptr, lookup_kind(TV_RING, SV_RING_POWER));
+
+ /* Mega-Hack -- Mark this item as "the one ring" */
+ q_ptr->name1 = ART_POWER;
+
+ /* Mega-Hack -- Actually create "the one ring" */
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+
+ /* Find a space */
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ /* Skip non-objects */
+ if (!p_ptr->inventory[i].k_idx) break;
+ }
+ /* Arg, no space ! */
+ if (i == INVEN_PACK)
+ {
+ char o_name[200];
+
+ object_desc(o_name, &p_ptr->inventory[INVEN_PACK - 1], FALSE, 0);
+
+ /* Drop the item */
+ inven_drop(INVEN_PACK - 1, 99, p_ptr->py, p_ptr->px, FALSE);
+
+ cmsg_format(TERM_VIOLET, "You feel the urge to drop your %s to make room in your inventory.", o_name);
+ }
+
+ /* Carry it */
+ cmsg_format(TERM_VIOLET, "You feel the urge to pick up that plain gold ring you see.");
+ inven_carry(q_ptr, FALSE);
+ }
+
+ return (FALSE);
+}
+bool_ quest_one_dump_hook(char *fmt)
+{
+ if (cquest.status == QUEST_STATUS_FINISHED)
+ {
+ fprintf(hook_file, "\n You destroyed the One Ring, thus weakening Sauron.");
+ }
+ if (cquest.status == QUEST_STATUS_FAILED_DONE)
+ {
+ fprintf(hook_file, "\n You fell under the evil influence of the One Ring and decided to wear it.");
+ }
+ return (FALSE);
+}
+bool_ quest_one_gen_hook(char *fmt)
+{
+ s32b x, y, tries = 10000;
+
+ /* Paranoia */
+ if (cquest.status != QUEST_STATUS_TAKEN) return (FALSE);
+ if ((dungeon_type != DUNGEON_ANGBAND) || (dun_level != 99)) return (FALSE);
+
+ /* Find a good position */
+ while (tries)
+ {
+ /* Get a random spot */
+ y = randint(cur_hgt - 4) + 2;
+ x = randint(cur_wid - 4) + 2;
+
+ /* Is it a good spot ? */
+ if (cave_empty_bold(y, x)) break;
+
+ /* One less try */
+ tries--;
+ }
+
+ if (tries)
+ {
+ int m_idx = place_monster_one(y, x, test_monster_name("Sauron, the Sorcerer"), 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ }
+
+ return (FALSE);
+}
+bool_ quest_one_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_LEVEL_END_GEN, quest_one_gen_hook, "one_gen");
+ add_hook(HOOK_MONSTER_DEATH, quest_one_death_hook, "one_death");
+ add_hook(HOOK_DROP, quest_one_drop_hook, "one_drop");
+ add_hook(HOOK_WIELD, quest_one_wield_hook, "one_wield");
+ add_hook(HOOK_IDENTIFY, quest_one_identify_hook, "one_id");
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ add_hook(HOOK_MOVE, quest_one_move_hook, "one_move");
+ }
+ add_hook(HOOK_CHAR_DUMP, quest_one_dump_hook, "one_dump");
+ add_hook(HOOK_CALC_HP, quest_one_hp_hook, "one_hp");
+ add_hook(HOOK_DIE, quest_one_die_hook, "one_die");
+ return (FALSE);
+}
diff --git a/src/q_poison.c b/src/q_poison.c
new file mode 100644
index 00000000..e6fed3a1
--- /dev/null
+++ b/src/q_poison.c
@@ -0,0 +1,238 @@
+#undef cquest
+#define cquest (quest[QUEST_POISON])
+
+static int wild_locs[4][2] =
+{
+ { 32, 49, },
+ { 32, 48, },
+ { 33, 48, },
+ { 34, 48, },
+};
+
+static bool_ create_molds_hook(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->flags4 & RF4_MULTIPLY) return FALSE;
+
+ if (r_ptr->d_char == 'm') return TRUE;
+ else if (r_ptr->d_char == ',') return TRUE;
+ else if (r_ptr->d_char == 'e') return TRUE;
+ else return FALSE;
+}
+
+bool_ quest_poison_gen_hook(char *fmt)
+{
+ int cy = 1, cx = 1, x, y, tries = 10000, r_idx;
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+
+ if (cquest.status != QUEST_STATUS_TAKEN) return FALSE;
+ if (p_ptr->wilderness_y != wild_locs[cquest.data[0]][0]) return FALSE;
+ if (p_ptr->wilderness_x != wild_locs[cquest.data[0]][1]) return FALSE;
+ if (p_ptr->wild_mode) return FALSE;
+
+ /* Find a good position */
+ while (tries)
+ {
+ /* Get a random spot */
+ cy = randint(cur_hgt - 24) + 22;
+ cx = randint(cur_wid - 34) + 32;
+
+ /* Is it a good spot ? */
+ if (cave_empty_bold(cy, cx)) break;
+
+ /* One less try */
+ tries--;
+ }
+
+ /* Place the baddies */
+
+ /* Backup the old hook */
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ /* Require "okay" monsters */
+ get_mon_num_hook = create_molds_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Pick a monster, using the level calculation */
+ for (x = cx - 25; x <= cx + 25; x++)
+ for (y = cy - 25; y <= cy + 25; y++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (distance(cy, cx, y, x) > 25) continue;
+
+ if (magik(80) && ((cave[y][x].feat == FEAT_DEEP_WATER) || (cave[y][x].feat == FEAT_SHAL_WATER))) cave_set_feat(y, x, FEAT_TAINTED_WATER);
+
+ if (distance(cy, cx, y, x) > 10) continue;
+
+ if (magik(60))
+ {
+ int m_idx;
+
+ r_idx = get_mon_num(30);
+ m_idx = place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+
+ /* Sometimes make it up some levels */
+ if (magik(80) && m_idx)
+ {
+ monster_type *m_ptr = &m_list[m_idx];
+
+ if (m_ptr->level < p_ptr->lev)
+ {
+ m_ptr->exp = MONSTER_EXP(m_ptr->level + randint(p_ptr->lev - m_ptr->level));
+ monster_check_experience(m_idx, TRUE);
+ }
+ }
+ }
+ }
+
+ /* Reset restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ return FALSE;
+}
+bool_ quest_poison_finish_hook(char *fmt)
+{
+ object_type forge, *q_ptr;
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_POISON) return FALSE;
+
+ c_put_str(TERM_YELLOW, "The water is clean again! Thank you so much.", 8, 0);
+ c_put_str(TERM_YELLOW, "The beautiful Mallorns are safe. Take this as a proof of our gratitude.", 9, 0);
+
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_DRAG_ARMOR, SV_DRAGON_BLUE));
+ q_ptr->found = OBJ_FOUND_REWARD;
+ q_ptr->number = 1;
+ q_ptr->name2 = EGO_ELVENKIND;
+ apply_magic(q_ptr, 1, FALSE, FALSE, FALSE);
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_STOREB;
+ (void)inven_carry(q_ptr, FALSE);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_NULL;
+
+ del_hook(HOOK_QUEST_FINISH, quest_poison_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_poison_dump_hook(char *fmt)
+{
+ if (cquest.status >= QUEST_STATUS_COMPLETED)
+ {
+ fprintf(hook_file, "\n You saved the beautiful Mallorns of Lothlorien.");
+ }
+ return (FALSE);
+}
+bool_ quest_poison_quest_hook(char *fmt)
+{
+ object_type forge, *q_ptr;
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_POISON) return FALSE;
+
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_POTION2, SV_POTION2_CURE_WATER));
+ q_ptr->number = 99;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_STOREB;
+ q_ptr->note = quark_add("quest");
+ (void)inven_carry(q_ptr, FALSE);
+
+ del_hook(HOOK_INIT_QUEST, quest_poison_quest_hook);
+ process_hooks_restart = TRUE;
+
+ return FALSE;
+}
+bool_ quest_poison_drop_hook(char *fmt)
+{
+ s32b mcnt = 0, i, x, y, o_idx;
+ object_type *o_ptr;
+
+ o_idx = get_next_arg(fmt);
+ o_ptr = &p_ptr->inventory[o_idx];
+
+ if (cquest.status != QUEST_STATUS_TAKEN) return FALSE;
+ if (p_ptr->wilderness_y != wild_locs[cquest.data[0]][0]) return FALSE;
+ if (p_ptr->wilderness_x != wild_locs[cquest.data[0]][1]) return FALSE;
+ if (p_ptr->wild_mode) return FALSE;
+
+ if (o_ptr->tval != TV_POTION2) return FALSE;
+ if (o_ptr->sval != SV_POTION2_CURE_WATER) return FALSE;
+
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status <= MSTATUS_NEUTRAL) mcnt++;
+ }
+
+ if (mcnt < 10)
+ {
+ for (x = 1; x < cur_wid - 1; x++)
+ for (y = 1; y < cur_hgt - 1; y++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (cave[y][x].feat == FEAT_TAINTED_WATER) cave_set_feat(y, x, FEAT_SHAL_WATER);
+ }
+
+ cmsg_print(TERM_YELLOW, "Well done! The water seems to be clean now.");
+
+ cquest.status = QUEST_STATUS_COMPLETED;
+
+ del_hook(HOOK_DROP, quest_poison_drop_hook);
+ process_hooks_restart = TRUE;
+
+ return FALSE;
+ }
+ else
+ {
+ msg_print("There are too many monsters left to cure the water.");
+ return TRUE;
+ }
+ return FALSE;
+}
+bool_ quest_poison_init_hook(int q_idx)
+{
+ /* Get a place to place the poison */
+ if (!cquest.data[1])
+ {
+ cquest.data[1] = TRUE;
+ cquest.data[0] = rand_int(4);
+ if (wizard) message_add(MESSAGE_MSG, format("Wilderness poison %d, %d", wild_locs[cquest.data[0]][0], wild_locs[cquest.data[0]][1]), TERM_BLUE);
+ }
+
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_DROP, quest_poison_drop_hook, "poison_drop");
+ add_hook(HOOK_WILD_GEN, quest_poison_gen_hook, "poison_gen");
+ add_hook(HOOK_QUEST_FINISH, quest_poison_finish_hook, "poison_finish");
+ }
+ if (cquest.status < QUEST_STATUS_COMPLETED)
+ {
+ add_hook(HOOK_INIT_QUEST, quest_poison_quest_hook, "poison_iquest");
+ }
+ add_hook(HOOK_CHAR_DUMP, quest_poison_dump_hook, "poison_dump");
+ return (FALSE);
+}
diff --git a/src/q_rand.c b/src/q_rand.c
new file mode 100644
index 00000000..5a3b3ab2
--- /dev/null
+++ b/src/q_rand.c
@@ -0,0 +1,465 @@
+static int randquest_hero[] = { 20, 13, 15, 16, 9, 17, 18, 8, -1 };
+
+bool_ is_randhero(int level)
+{
+ int i;
+ bool_ result = FALSE;
+
+ for (i = 0; randquest_hero[i] != -1; i++)
+ {
+ if (random_quests[level].type == randquest_hero[i])
+ {
+ result = TRUE;
+ break;
+ }
+ }
+
+ return result;
+}
+
+void do_get_new_obj(int y, int x)
+{
+ obj_theme theme;
+ char *items[3];
+ object_type *q_ptr[3], forge[3];
+ int max = 0, res, i;
+
+ /* Create 3 ones */
+ max = 0;
+ for (i = 0; i < 3; i++)
+ {
+ /* Get local object */
+ q_ptr[max] = &forge[max];
+
+ /* Wipe the object */
+ object_wipe(q_ptr[max]);
+
+ /* No themes */
+ theme.treasure = 100;
+ theme.combat = 100;
+ theme.magic = 100;
+ theme.tools = 100;
+
+ /* Make a great object */
+ make_object(q_ptr[max], TRUE, TRUE, theme);
+ q_ptr[max]->found = OBJ_FOUND_REWARD;
+
+ C_MAKE(items[max], 100, char);
+ object_desc(items[max], q_ptr[max], 0, 0);
+ max++;
+ }
+
+
+ while (TRUE)
+ {
+ res = ask_menu("Choose a reward to get(a-c to choose, ESC to cancel)?", (char **)items, 3);
+
+ /* Ok ? lets learn ! */
+ if (res > -1)
+ {
+ /* Drop it in the dungeon */
+ drop_near(q_ptr[res], -1, y + 1, x);
+
+ cmsg_print(TERM_YELLOW, "There, Noble Hero. I put it there. Thanks again!");
+ break;
+ }
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+
+ object_type *o_ptr = q_ptr[i];
+
+ /* Check if there is any not chosen artifact */
+ if (i != res && artifact_p(o_ptr))
+ {
+ /* Mega-Hack -- Preserve the artifact */
+ if (o_ptr->tval == TV_RANDART)
+ {
+ random_artifacts[o_ptr->sval].generated = FALSE;
+ }
+ else if (k_info[o_ptr->k_idx].flags3 & TR3_NORM_ART)
+ {
+ k_info[o_ptr->k_idx].artifact = FALSE;
+ }
+ else if (o_ptr->name1)
+ {
+ a_info[o_ptr->name1].cur_num = 0;
+ }
+ }
+ }
+
+ for (i = 0; i < 3; i++)
+ C_KILL(items[i], 100, char);
+
+}
+
+void princess_death(s32b m_idx, s32b r_idx)
+{
+ int r;
+
+ cmsg_print(TERM_YELLOW, "O Great And Noble Hero, you saved me!");
+ cmsg_print(TERM_YELLOW, "I am heading home now. I cannot reward you as I should, but please take this.");
+
+ /* Look for the princess */
+ for (r = m_max - 1; r >= 1; r--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[r];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Is it the princess? */
+ if (m_ptr->r_idx == 969)
+ {
+ int x = m_ptr->fx;
+ int y = m_ptr->fy;
+ int i, j;
+
+ delete_monster_idx(r);
+
+ /* Wipe the glass walls and create a stair */
+ for (i = x - 1; i <= x + 1; i++)
+ for (j = y - 1; j <= y + 1; j++)
+ {
+ if (in_bounds(j, i)) cave_set_feat(j, i, FEAT_FLOOR);
+ }
+ cave_set_feat(y, x, FEAT_MORE);
+
+ do_get_new_obj(y, x);
+
+ random_quests[dun_level].done = TRUE;
+
+ break;
+ }
+ }
+}
+
+void hero_death(s32b m_idx, s32b r_idx)
+{
+ random_quests[dun_level].done = TRUE;
+
+ cmsg_print(TERM_YELLOW, "The adventurer steps out of the shadows and picks up his sword:");
+ cmsg_print(TERM_YELLOW, "'Ah! My sword! My trusty sword! Thanks.");
+
+ if (!can_create_companion())
+ {
+ cmsg_print(TERM_YELLOW, "I must go on my own way now.");
+ cmsg_print(TERM_YELLOW, "But before I go, I can help your skills.'");
+ cmsg_print(TERM_YELLOW, "He touches your forehead.");
+ do_get_new_skill();
+ return;
+ }
+ cmsg_print(TERM_YELLOW, "If you wish, I can help you in your adventures.'");
+
+ /* Flush input */
+ flush();
+
+ if (get_check("Do you want him to join you? "))
+ {
+ int x, y, i;
+
+ /* Look for a location */
+ for (i = 0; i < 20; ++i)
+ {
+ /* Pick a distance */
+ int d = (i / 15) + 1;
+
+ /* Pick a location */
+ scatter(&y, &x, p_ptr->py, p_ptr->px, d);
+
+ /* Require "empty" floor grid */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Hack -- no summon on glyph of warding */
+ if (cave[y][x].feat == FEAT_GLYPH) continue;
+ if (cave[y][x].feat == FEAT_MINOR_GLYPH) continue;
+
+ /* Nor on the between */
+ if (cave[y][x].feat == FEAT_BETWEEN) continue;
+
+ /* ... nor on the Pattern */
+ if ((cave[y][x].feat >= FEAT_PATTERN_START) &&
+ (cave[y][x].feat <= FEAT_PATTERN_XTRA2))
+ continue;
+
+ /* Okay */
+ break;
+ }
+
+ if (i < 20)
+ {
+ int m_idx;
+
+ m_allow_special[test_monster_name("Adventurer")] = TRUE;
+ m_idx = place_monster_one(y, x, test_monster_name("Adventurer"), 0, FALSE, MSTATUS_COMPANION);
+ m_allow_special[test_monster_name("Adventurer")] = FALSE;
+ if (m_idx)
+ {
+ m_list[m_idx].exp = MONSTER_EXP(1 + (dun_level * 3 / 2));
+ m_list[m_idx].status = MSTATUS_COMPANION;
+ monster_check_experience(m_idx, TRUE);
+ }
+ }
+ else
+ msg_print("The adventurer suddenly seems afraid and flees...");
+ }
+ else
+ {
+ cmsg_print(TERM_YELLOW, "'As you wish, but I want to do something for you.'");
+ cmsg_print(TERM_YELLOW, "He touches your forehead.");
+ do_get_new_skill();
+ }
+}
+
+bool_ quest_random_death_hook(char *fmt)
+{
+ int r_idx;
+ s32b m_idx;
+
+ m_idx = get_next_arg(fmt);
+ r_idx = m_list[m_idx].r_idx;
+
+ if (!(dungeon_flags1 & DF1_PRINCIPAL)) return (FALSE);
+ if ((dun_level < 1) || (dun_level >= MAX_RANDOM_QUEST)) return (FALSE);
+ if (!random_quests[dun_level].type) return (FALSE);
+ if (random_quests[dun_level].done) return (FALSE);
+ if (p_ptr->inside_quest) return (FALSE);
+ if (random_quests[dun_level].r_idx != r_idx) return (FALSE);
+
+ if (!(m_list[m_idx].mflag & MFLAG_QUEST)) return (FALSE);
+
+ /* Killed enough ?*/
+ quest[QUEST_RANDOM].data[0]++;
+ if (quest[QUEST_RANDOM].data[0] == random_quests[dun_level].type)
+ {
+ if (is_randhero(dun_level))
+ hero_death(m_idx, r_idx);
+ else
+ princess_death(m_idx, r_idx);
+ }
+
+ return (FALSE);
+}
+bool_ quest_random_turn_hook(char *fmt)
+{
+ quest[QUEST_RANDOM].data[0] = 0;
+ quest[QUEST_RANDOM].data[1] = 0;
+ return (FALSE);
+}
+bool_ quest_random_feeling_hook(char *fmt)
+{
+ if (!(dungeon_flags1 & DF1_PRINCIPAL)) return (FALSE);
+ if ((dun_level < 1) || (dun_level >= MAX_RANDOM_QUEST)) return (FALSE);
+ if (!random_quests[dun_level].type) return (FALSE);
+ if (random_quests[dun_level].done) return (FALSE);
+ if (p_ptr->inside_quest) return (FALSE);
+ if (!dun_level) return (FALSE);
+
+ if (is_randhero(dun_level))
+ {
+ cmsg_format(TERM_YELLOW, "A strange man wrapped in a dark cloak steps out of the shadows:");
+ cmsg_format(TERM_YELLOW, "'Oh, please help me! A horrible %s stole my sword! I'm nothing without it.'", r_info[random_quests[dun_level].r_idx].name + r_name);
+ }
+ else
+ cmsg_format(TERM_YELLOW, "You hear someone shouting: 'Leave me alone, stupid %s'", r_info[random_quests[dun_level].r_idx].name + r_name);
+ return (FALSE);
+}
+bool_ quest_random_gen_hero_hook(char *fmt)
+{
+ int i;
+
+ if (!(dungeon_flags1 & DF1_PRINCIPAL)) return (FALSE);
+ if ((dun_level < 1) || (dun_level >= MAX_RANDOM_QUEST)) return (FALSE);
+ if (!random_quests[dun_level].type) return (FALSE);
+ if (random_quests[dun_level].done) return (FALSE);
+ if (p_ptr->inside_quest) return (FALSE);
+ if (!is_randhero(dun_level)) return (FALSE);
+
+ i = random_quests[dun_level].type;
+
+ m_allow_special[random_quests[dun_level].r_idx] = TRUE;
+ while (i)
+ {
+ int m_idx, y = rand_range(1, cur_hgt - 2), x = rand_range(1, cur_wid - 2);
+
+ m_idx = place_monster_one(y, x, random_quests[dun_level].r_idx, 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx)
+ {
+ monster_type *m_ptr = &m_list[m_idx];
+ m_ptr->mflag |= MFLAG_QUEST;
+ i--;
+ }
+ }
+ m_allow_special[random_quests[dun_level].r_idx] = FALSE;
+
+ return (FALSE);
+}
+bool_ quest_random_gen_hook(char *fmt)
+{
+ s32b x, y, bx0, by0;
+ int xstart;
+ int ystart;
+ int y2, x2, yval, xval;
+ int y1, x1, xsize, ysize;
+
+ if (!(dungeon_flags1 & DF1_PRINCIPAL)) return (FALSE);
+ if ((dun_level < 1) || (dun_level >= MAX_RANDOM_QUEST)) return (FALSE);
+ if (!random_quests[dun_level].type) return (FALSE);
+ if (random_quests[dun_level].done) return (FALSE);
+ if (p_ptr->inside_quest) return (FALSE);
+ if (quest[QUEST_RANDOM].data[1]) return (FALSE);
+ if (is_randhero(dun_level)) return (FALSE);
+
+ by0 = get_next_arg(fmt);
+ bx0 = get_next_arg(fmt);
+
+ /* Pick a room size */
+ get_map_size(format("qrand%d.map", random_quests[dun_level].type), &ysize, &xsize);
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &xval, &yval)) return FALSE;
+
+ /* Get corner values */
+ y1 = yval - ysize / 2;
+ x1 = xval - xsize / 2;
+ y2 = y1 + ysize - 1;
+ x2 = x1 + xsize - 1;
+
+ /* Place a full floor under the room */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ cave_set_feat(y, x, floor_type[rand_int(100)]);
+ cave[y][x].info |= (CAVE_ROOM|CAVE_GLOW);
+ }
+ }
+
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, CAVE_ROOM | CAVE_GLOW);
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ xstart = x1;
+ ystart = y1;
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file(format("qrand%d.map", random_quests[dun_level].type), &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ for (x = x1; x < xstart; x++)
+ for (y = y1; y < ystart; y++)
+ {
+ cave[y][x].info |= CAVE_ICKY | CAVE_ROOM;
+ if (cave[y][x].feat == FEAT_MARKER)
+ {
+ monster_type *m_ptr;
+ int i;
+
+ m_allow_special[random_quests[dun_level].r_idx] = TRUE;
+ i = place_monster_one(y, x, random_quests[dun_level].r_idx, 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[random_quests[dun_level].r_idx] = FALSE;
+ if (i)
+ {
+ m_ptr = &m_list[i];
+ m_ptr->mflag |= MFLAG_QUEST;
+ }
+ }
+ }
+
+ /* Dont try another one for this generation */
+ quest[QUEST_RANDOM].data[1] = 1;
+
+ /* Boost level feeling a bit - a la pits */
+ rating += 10;
+
+ return (TRUE);
+}
+bool_ quest_random_dump_hook(char *fmt)
+{
+ static char *number[] =
+ { "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
+ int i, valid = 0, lscnt = 0, pcnt = 0;
+
+ for (i = 0; i < MAX_RANDOM_QUEST; i++)
+ {
+ if (random_quests[i].type)
+ {
+ valid++;
+ if (random_quests[i].done)
+ {
+ if (is_randhero(i))
+ lscnt++;
+ else
+ pcnt++;
+ }
+ }
+ }
+
+ if (valid)
+ {
+ if (pcnt > 10)
+ fprintf(hook_file, "\n You have completed %d princess quests.", pcnt);
+ else if (pcnt > 1)
+ fprintf(hook_file, "\n You have completed %s princess quests.", number[pcnt-2]);
+ else if (pcnt == 1)
+ fprintf(hook_file, "\n You have completed one princess quest.");
+ else
+ fprintf(hook_file, "\n You haven't completed a single princess quest.");
+
+ if (lscnt > 10)
+ fprintf(hook_file, "\n You have completed %d lost sword quests.", lscnt);
+ else if (lscnt > 1)
+ fprintf(hook_file, "\n You have completed %s lost sword quests.", number[lscnt-2]);
+ else if (lscnt == 1)
+ fprintf(hook_file, "\n You have completed one lost sword quest.");
+ else
+ fprintf(hook_file, "\n You haven't completed a single lost sword quest.");
+ }
+
+ return (FALSE);
+}
+
+bool_ quest_random_describe(FILE *fff)
+{
+ if (!(dungeon_flags1 & DF1_PRINCIPAL)) return FALSE;
+ if ((dun_level < 1) || (dun_level >= MAX_RANDOM_QUEST)) return FALSE;
+ if (!random_quests[dun_level].type) return FALSE;
+ if (random_quests[dun_level].done) return FALSE;
+ if (p_ptr->inside_quest) return FALSE;
+ if (!dun_level) return FALSE;
+
+ if (!is_randhero(dun_level))
+ {
+ fprintf(fff, "#####yCaptured princess!\n");
+ fprintf(fff, "A princess is being held prisoner and tortured here!\n");
+ fprintf(fff, "Save her from the horrible %s.\n",
+ r_info[random_quests[dun_level].r_idx].name + r_name);
+ }
+ else
+ {
+ fprintf(fff, "#####yLost sword!\n");
+ fprintf(fff, "An adventurer lost his sword to a bunch of %s!\n",
+ r_info[random_quests[dun_level].r_idx].name + r_name);
+ fprintf(fff, "Kill them all to get it back.\n");
+ }
+ fprintf(fff, "Number: %d, Killed: %ld.\n",
+ random_quests[dun_level].type, (long int) quest[QUEST_RANDOM].data[0]);
+ fprintf(fff, "\n");
+ return TRUE;
+}
+
+bool_ quest_random_init_hook(int q_idx)
+{
+ add_hook(HOOK_MONSTER_DEATH, quest_random_death_hook, "rand_death");
+ add_hook(HOOK_NEW_LEVEL, quest_random_turn_hook, "rand_new_lvl");
+ add_hook(HOOK_LEVEL_REGEN, quest_random_turn_hook, "rand_regen_lvl");
+ add_hook(HOOK_LEVEL_END_GEN, quest_random_gen_hero_hook, "rand_gen_hero");
+ add_hook(HOOK_BUILD_ROOM1, quest_random_gen_hook, "rand_gen");
+ add_hook(HOOK_FEELING, quest_random_feeling_hook, "rand_feel");
+ add_hook(HOOK_CHAR_DUMP, quest_random_dump_hook, "rand_dump");
+ return (FALSE);
+}
diff --git a/src/q_shroom.c b/src/q_shroom.c
new file mode 100644
index 00000000..b6e26cdf
--- /dev/null
+++ b/src/q_shroom.c
@@ -0,0 +1,293 @@
+#undef cquest
+#define cquest (quest[QUEST_SHROOM])
+
+bool_ quest_shroom_speak_hook(char *fmt);
+
+bool_ quest_shroom_town_gen_hook(char *fmt)
+{
+ int m_idx, x = 1, y = 1, tries = 10000;
+ s32b small;
+
+ small = get_next_arg(fmt);
+
+ /* Generate the shrooms field */
+ if ((!small) && (p_ptr->wilderness_y == 21) && (p_ptr->wilderness_x == 33))
+ {
+ /* Create the field */
+ for (x = (cur_wid / 2) - 7; x <= (cur_wid / 2) + 7; x++)
+ for (y = (cur_hgt / 2) - 5; y <= (cur_hgt / 2) + 5; y++)
+ cave_set_feat(y, x, 181);
+
+ /* Throw in some 'shrooms */
+ for (x = 0; x < (cquest.data[1] - cquest.data[0]); x++)
+ {
+ object_type forge, *q_ptr = &forge;
+
+ object_prep(q_ptr, lookup_kind(TV_FOOD, rand_range(1, 18)));
+ q_ptr->number = 1;
+ /* Mark them */
+ q_ptr->pval2 = 1;
+ drop_near(q_ptr, -1, rand_range((cur_hgt / 2) - 5, (cur_hgt / 2) + 5), rand_range((cur_wid / 2) - 7, (cur_wid / 2) + 7));
+ }
+
+ /* Throw in some dogs ;) */
+ y = rand_range((cur_hgt / 2) - 5, (cur_hgt / 2) + 5);
+ x = rand_range((cur_wid / 2) - 7, (cur_wid / 2) + 7);
+ m_allow_special[test_monster_name("Grip, Farmer Maggot's dog")] = TRUE;
+ m_idx = place_monster_one(y, x, test_monster_name("Grip, Farmer Maggot's dog"), 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ m_allow_special[test_monster_name("Grip, Farmer Maggot's dog")] = FALSE;
+
+ y = rand_range((cur_hgt / 2) - 5, (cur_hgt / 2) + 5);
+ x = rand_range((cur_wid / 2) - 7, (cur_wid / 2) + 7);
+ m_allow_special[test_monster_name("Wolf, Farmer Maggot's dog")] = TRUE;
+ m_idx = place_monster_one(y, x, test_monster_name("Wolf, Farmer Maggot's dog"), 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ m_allow_special[test_monster_name("Wolf, Farmer Maggot's dog")] = FALSE;
+
+ y = rand_range((cur_hgt / 2) - 5, (cur_hgt / 2) + 5);
+ x = rand_range((cur_wid / 2) - 7, (cur_wid / 2) + 7);
+ m_allow_special[test_monster_name("Fang, Farmer Maggot's dog")] = TRUE;
+ m_idx = place_monster_one(y, x, test_monster_name("Fang, Farmer Maggot's dog"), 0, FALSE, MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ m_allow_special[test_monster_name("Fang, Farmer Maggot's dog")] = FALSE;
+
+ msg_print("You hear frenzied barking.");
+ }
+
+ /* Generate maggot in town, in daylight */
+ if ((bst(HOUR, turn) < 6) || (bst(HOUR, turn) >= 18) || (cquest.status > QUEST_STATUS_COMPLETED) || (small) || (p_ptr->town_num != 1)) return (FALSE);
+
+ /* Find a good position */
+ while (tries)
+ {
+ /* Get a random spot */
+ y = randint(20) + (cur_hgt / 2) - 10;
+ x = randint(20) + (cur_wid / 2) - 10;
+
+ /* Is it a good spot ? */
+ /* Not in player los, and avoid shop grids */
+ if (!los(p_ptr->py, p_ptr->px, y, x) && cave_empty_bold(y, x) &&
+ cave_plain_floor_bold(y, x)) break;
+
+ /* One less try */
+ tries--;
+ }
+
+ /* Place Farmer Maggot */
+ m_allow_special[test_monster_name("Farmer Maggot")] = TRUE;
+ place_monster_one(y, x, test_monster_name("Farmer Maggot"), 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[test_monster_name("Farmer Maggot")] = FALSE;
+
+ return FALSE;
+}
+bool_ quest_shroom_death_hook(char *fmt)
+{
+ s32b r_idx, m_idx;
+
+ m_idx = get_next_arg(fmt);
+ r_idx = m_list[m_idx].r_idx;
+
+ if (cquest.status > QUEST_STATUS_COMPLETED) return FALSE;
+
+ if ((r_idx == test_monster_name("Wolf, Farmer Maggot's dog")) ||
+ (r_idx == test_monster_name("Grip, Farmer Maggot's dog")) ||
+ (r_idx == test_monster_name("Fang, Farmer Maggot's dog")))
+ {
+ msg_print("The dog yells a last time and drops dead on the grass.");
+ }
+
+ return FALSE;
+}
+bool_ quest_shroom_give_hook(char *fmt)
+{
+ object_type *o_ptr;
+ monster_type *m_ptr;
+ s32b m_idx, item;
+
+ m_idx = get_next_arg(fmt);
+ item = get_next_arg(fmt);
+
+ o_ptr = &p_ptr->inventory[item];
+ m_ptr = &m_list[m_idx];
+
+ if (m_ptr->r_idx != test_monster_name("Farmer Maggot")) return (FALSE);
+
+ /* If one is dead .. its bad */
+ if ((r_info[test_monster_name("Grip, Farmer Maggot's dog")].max_num == 0) ||
+ (r_info[test_monster_name("Wolf, Farmer Maggot's dog")].max_num == 0) ||
+ (r_info[test_monster_name("Fang, Farmer Maggot's dog")].max_num == 0))
+ {
+ cquest.status = QUEST_STATUS_FAILED_DONE;
+ msg_print("My puppy! My poor, defenceless puppy...");
+ msg_print("YOU MURDERER! Out of my sight!");
+ delete_monster_idx(m_idx);
+
+ del_hook(HOOK_GIVE, quest_shroom_give_hook);
+ del_hook(HOOK_CHAT, quest_shroom_speak_hook);
+ del_hook(HOOK_WILD_GEN, quest_shroom_town_gen_hook);
+ process_hooks_restart = TRUE;
+ return TRUE;
+ }
+
+ if ((o_ptr->tval != TV_FOOD) || (o_ptr->pval2 != 1)) return (FALSE);
+
+ /* Take a mushroom */
+ inc_stack_size_ex(item, -1, OPTIMIZE, NO_DESCRIBE);
+ cquest.data[0]++;
+
+ if (cquest.data[0] == cquest.data[1])
+ {
+ object_type forge, *q_ptr;
+
+ msg_print("Oh thank you!");
+ msg_print("Take my sling and those mushrooms, may they help you!");
+ msg_print("Farmer Maggot heads back to his house.");
+
+ /* Mushrooms */
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_FOOD, SV_FOOD_CURE_SERIOUS));
+ q_ptr->found = OBJ_FOUND_REWARD;
+ q_ptr->number = rand_range(15, 20);
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->discount = 100;
+ q_ptr->ident |= IDENT_STOREB;
+ if (inven_carry_okay(q_ptr))
+ inven_carry(q_ptr, FALSE);
+ else
+ drop_near(q_ptr, 0, p_ptr->py, p_ptr->px);
+
+ /* The sling of farmer maggot */
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_BOW, SV_SLING));
+ q_ptr->found = OBJ_FOUND_REWARD;
+ q_ptr->number = 1;
+ q_ptr->name1 = 149;
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->discount = 100;
+ q_ptr->ident |= IDENT_STOREB;
+ (void)inven_carry(q_ptr, FALSE);
+
+ delete_monster_idx(m_idx);
+
+ cquest.status = QUEST_STATUS_FINISHED;
+
+ del_hook(HOOK_GIVE, quest_shroom_give_hook);
+ process_hooks_restart = TRUE;
+ }
+ else
+ msg_format("Oh thank you, but you still have %d mushrooms to bring back!", cquest.data[1] - cquest.data[0]);
+
+ return TRUE;
+}
+bool_ quest_shroom_speak_hook(char *fmt)
+{
+ s32b m_idx = get_next_arg(fmt);
+
+ if (m_list[m_idx].r_idx != test_monster_name("Farmer Maggot")) return (FALSE);
+
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ cptr m_name;
+
+ m_name = get_next_arg_str(fmt);
+
+ msg_format("%^s asks your help.", m_name);
+ exec_lua("ingame_help('monster_chat')");
+ }
+ else
+ {
+ /* If one is dead .. its bad */
+ if ((r_info[test_monster_name("Grip, Farmer Maggot's dog")].max_num == 0) ||
+ (r_info[test_monster_name("Wolf, Farmer Maggot's dog")].max_num == 0) ||
+ (r_info[test_monster_name("Fang, Farmer Maggot's dog")].max_num == 0))
+ {
+ cquest.status = QUEST_STATUS_FAILED_DONE;
+ msg_print("My puppy! My poor, defenceless puppy...");
+ msg_print("YOU MURDERER! Out of my sight!");
+ delete_monster_idx(m_idx);
+
+ del_hook(HOOK_GIVE, quest_shroom_give_hook);
+ del_hook(HOOK_CHAT, quest_shroom_speak_hook);
+ del_hook(HOOK_WILD_GEN, quest_shroom_town_gen_hook);
+ process_hooks_restart = TRUE;
+ return TRUE;
+ }
+ msg_format("You still have %d mushrooms to bring back!", cquest.data[1] - cquest.data[0]);
+ }
+ return (TRUE);
+}
+bool_ quest_shroom_chat_hook(char *fmt)
+{
+ monster_type *m_ptr;
+ s32b m_idx;
+
+ m_idx = get_next_arg(fmt);
+
+ m_ptr = &m_list[m_idx];
+
+ if (m_ptr->r_idx != test_monster_name("Farmer Maggot")) return (FALSE);
+
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ msg_print("My mushrooms, my mushrooms!");
+ msg_print("The rain, a dark horrible rain, began so I had to return to my home.");
+ msg_print("But when I came back my dogs were all mad and didn't let me near the field.");
+ msg_print("Could you please bring me back all the mushrooms that have grown in my field");
+ msg_print("to the west of Bree? Please try to not harm my dogs. They are so lovely...");
+
+ cquest.status = QUEST_STATUS_TAKEN;
+ quest[QUEST_SHROOM].init(QUEST_SHROOM);
+ }
+ else
+ {
+ /* If one is dead .. its bad */
+ if ((r_info[test_monster_name("Grip, Farmer Maggot's dog")].max_num == 0) ||
+ (r_info[test_monster_name("Wolf, Farmer Maggot's dog")].max_num == 0) ||
+ (r_info[test_monster_name("Fang, Farmer Maggot's dog")].max_num == 0))
+ {
+ cquest.status = QUEST_STATUS_FAILED_DONE;
+ msg_print("My puppy! My poor, defenceless puppy...");
+ msg_print("YOU MURDERER! Out of my sight!");
+ delete_monster_idx(m_idx);
+
+ del_hook(HOOK_GIVE, quest_shroom_give_hook);
+ del_hook(HOOK_CHAT, quest_shroom_speak_hook);
+ del_hook(HOOK_WILD_GEN, quest_shroom_town_gen_hook);
+ process_hooks_restart = TRUE;
+ return TRUE;
+ }
+ msg_format("You still have %d mushrooms to bring back!", cquest.data[1] - cquest.data[0]);
+ }
+
+ return TRUE;
+}
+bool_ quest_shroom_init_hook(int q_idx)
+{
+ /* Get a number of 'shrooms */
+ if (!cquest.data[1])
+ {
+ cquest.data[0] = 0;
+ cquest.data[1] = rand_range(7, 14);
+ if (wizard) message_add(MESSAGE_MSG, format("Shrooms number %d", cquest.data[1]), TERM_BLUE);
+ }
+
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_shroom_death_hook, "shroom_death");
+ add_hook(HOOK_GIVE, quest_shroom_give_hook, "shroom_give");
+ add_hook(HOOK_WILD_GEN, quest_shroom_town_gen_hook, "shroom_town_gen");
+ add_hook(HOOK_CHAT, quest_shroom_chat_hook, "shroom_chat");
+ add_hook(HOOK_MON_SPEAK, quest_shroom_speak_hook, "shroom_speak");
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ add_hook(HOOK_MON_SPEAK, quest_shroom_speak_hook, "shroom_speak");
+ add_hook(HOOK_WILD_GEN, quest_shroom_town_gen_hook, "shroom_town_gen");
+ add_hook(HOOK_CHAT, quest_shroom_chat_hook, "shroom_chat");
+ }
+ return (FALSE);
+}
diff --git a/src/q_spider.c b/src/q_spider.c
new file mode 100644
index 00000000..a739535b
--- /dev/null
+++ b/src/q_spider.c
@@ -0,0 +1,108 @@
+#undef cquest
+#define cquest (quest[QUEST_SPIDER])
+
+bool_ quest_spider_gen_hook(char *fmt)
+{
+ int x, y;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_SPIDER) return FALSE;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("spiders.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ return TRUE;
+}
+bool_ quest_spider_death_hook(char *fmt)
+{
+ int i, mcnt = 0;
+
+ if (p_ptr->inside_quest != QUEST_SPIDER) return FALSE;
+
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status <= MSTATUS_ENEMY) mcnt++;
+ }
+
+ if (mcnt <= 1)
+ {
+ cmsg_print(TERM_YELLOW, "The forest is now safer, thanks to you.");
+
+ /* Yavanna LOVES saving forests */
+ GOD(GOD_YAVANNA)
+ {
+ cmsg_print(TERM_L_GREEN, "You feel the gentle touch of Yavanna, as she smiles at you.");
+ inc_piety(GOD_YAVANNA, 6000);
+ }
+
+ cquest.status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_MONSTER_DEATH, quest_spider_death_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+ }
+
+ return (FALSE);
+}
+bool_ quest_spider_finish_hook(char *fmt)
+{
+ object_type forge, *q_ptr;
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_SPIDER) return FALSE;
+
+ c_put_str(TERM_YELLOW, "All of us praise your mighty deed in driving back the", 8, 0);
+ c_put_str(TERM_YELLOW, "menace. Take this as a reward.", 9, 0);
+
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_POTION, SV_POTION_AUGMENTATION));
+ q_ptr->number = 1;
+ q_ptr->found = OBJ_FOUND_REWARD;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_STOREB;
+ (void)inven_carry(q_ptr, FALSE);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_POISON;
+ quest[*(quest[q_idx].plot)].init(*(quest[q_idx].plot));
+
+ del_hook(HOOK_QUEST_FINISH, quest_spider_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_spider_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_spider_death_hook, "spider_death");
+ add_hook(HOOK_GEN_QUEST, quest_spider_gen_hook, "spider_gen");
+ add_hook(HOOK_QUEST_FINISH, quest_spider_finish_hook, "spider_finish");
+ }
+ return (FALSE);
+}
diff --git a/src/q_thief.c b/src/q_thief.c
new file mode 100644
index 00000000..6b033f8c
--- /dev/null
+++ b/src/q_thief.c
@@ -0,0 +1,172 @@
+#undef cquest
+#define cquest (quest[QUEST_THIEVES])
+
+bool_ quest_thieves_gen_hook(char *fmt)
+{
+ int x, y;
+ int xstart = 2;
+ int ystart = 2;
+ bool_ again = TRUE;
+
+ if (p_ptr->inside_quest != QUEST_THIEVES) return FALSE;
+
+ /* Just in case we didnt talk the the mayor */
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("thieves.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, FALSE);
+ dungeon_flags2 |= DF2_NO_GENO;
+
+ /* Rip the inventory from the player */
+ cmsg_print(TERM_YELLOW, "You feel a vicious blow on your head.");
+ while (again)
+ {
+ again = FALSE;
+ for (x = 0; x < INVEN_TOTAL; x++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[x];
+
+ if (!o_ptr->k_idx) continue;
+
+ if ((x >= INVEN_WIELD) && cursed_p(o_ptr)) continue;
+
+ inven_drop(x, 99, 4, 24, TRUE);
+
+ /* Thats ugly .. but it works */
+ again = TRUE;
+ break;
+ }
+ }
+
+ del_hook(HOOK_GEN_QUEST, quest_thieves_gen_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_thieves_hook(char *fmt)
+{
+ int i, mcnt = 0;
+
+ if (p_ptr->inside_quest != QUEST_THIEVES) return FALSE;
+
+ /* ALARM !!! */
+ if ((cave[17][22].feat == FEAT_OPEN) ||
+ (cave[17][22].feat == FEAT_BROKEN))
+ {
+ cmsg_print(TERM_L_RED, "An alarm rings!");
+ aggravate_monsters(0);
+ cave_set_feat(14, 20, FEAT_OPEN);
+ cave_set_feat(14, 16, FEAT_OPEN);
+ cave_set_feat(14, 12, FEAT_OPEN);
+ cave_set_feat(14, 8, FEAT_OPEN);
+ cave_set_feat(20, 20, FEAT_OPEN);
+ cave_set_feat(20, 16, FEAT_OPEN);
+ cave_set_feat(20, 12, FEAT_OPEN);
+ cave_set_feat(20, 8, FEAT_OPEN);
+ msg_print("The door explodes.");
+ cave_set_feat(17, 22, FEAT_FLOOR);
+ }
+
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status < MSTATUS_FRIEND) mcnt++;
+ }
+
+ /* Nobody left ? */
+ if (!mcnt)
+ {
+ msg_print("The magic hiding the stairs is now gone.");
+ cave_set_feat(23, 4, FEAT_LESS);
+ cave[23][4].special = 0;
+
+ quest[p_ptr->inside_quest].status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_END_TURN, quest_thieves_hook);
+ process_hooks_restart = TRUE;
+
+ cmsg_print(TERM_YELLOW, "You stopped the thieves and saved Bree!");
+ return (FALSE);
+ }
+ return FALSE;
+}
+bool_ quest_thieves_finish_hook(char *fmt)
+{
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_THIEVES) return FALSE;
+
+ c_put_str(TERM_YELLOW, "Thank you for killing the band of thieves!", 8, 0);
+ c_put_str(TERM_YELLOW, "You can use the hideout as your house as a reward.", 9, 0);
+
+ /* Continue the plot */
+
+ /* 10% chance to randomly select, otherwise use the combat/magic skill ratio */
+ if (magik(10) || (s_info[SKILL_COMBAT].value == s_info[SKILL_MAGIC].value))
+ {
+ *(quest[q_idx].plot) = (magik(50)) ? QUEST_TROLL : QUEST_WIGHT;
+ }
+ else
+ {
+ if (s_info[SKILL_COMBAT].value > s_info[SKILL_MAGIC].value)
+ *(quest[q_idx].plot) = QUEST_TROLL;
+ else
+ *(quest[q_idx].plot) = QUEST_WIGHT;
+ }
+ quest[*(quest[q_idx].plot)].init(*(quest[q_idx].plot));
+
+ del_hook(HOOK_QUEST_FINISH, quest_thieves_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+bool_ quest_thieves_feeling_hook(char *fmt)
+{
+ if (p_ptr->inside_quest != QUEST_THIEVES) return FALSE;
+
+ msg_print("You wake up in a prison cell.");
+ msg_print("All your possessions have been stolen!");
+
+ del_hook(HOOK_FEELING, quest_thieves_feeling_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+bool_ quest_thieves_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_END_TURN, quest_thieves_hook, "thieves_end_turn");
+ add_hook(HOOK_QUEST_FINISH, quest_thieves_finish_hook, "thieves_finish");
+ add_hook(HOOK_GEN_QUEST, quest_thieves_gen_hook, "thieves_geb");
+ add_hook(HOOK_FEELING, quest_thieves_feeling_hook, "thieves_feel");
+ }
+ return (FALSE);
+}
diff --git a/src/q_thrain.c b/src/q_thrain.c
new file mode 100644
index 00000000..b2b1be9f
--- /dev/null
+++ b/src/q_thrain.c
@@ -0,0 +1,230 @@
+#undef cquest
+#define cquest (quest[QUEST_THRAIN])
+
+bool_ quest_thrain_death_hook(char *fmt)
+{
+ s32b m_idx;
+ int r, x, y;
+ monster_type *m_ptr;
+
+ m_idx = get_next_arg(fmt);
+
+ if ((cquest.status >= QUEST_STATUS_FINISHED) || (dun_level !=cquest.data[0]) || (dungeon_type != DUNGEON_DOL_GULDUR)) return (FALSE);
+ m_ptr = &m_list[m_idx];
+ if ((m_ptr->r_idx != test_monster_name("Dwar, Dog Lord of Waw")) && (m_ptr->r_idx != test_monster_name("Hoarmurath of Dir"))) return (FALSE);
+
+ cquest.data[2]++;
+
+ if (cquest.data[2] < 2) return (FALSE);
+
+ cmsg_print(TERM_YELLOW, "The magic hiding the room dissipates.");
+ for (x = 0; x < cur_wid; x++)
+ for (y = 0; y < cur_hgt; y++)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ if (c_ptr->mimic != 61) continue;
+ if (!(c_ptr->info & CAVE_FREE)) continue;
+
+ c_ptr->mimic = 0;
+ lite_spot(y, x);
+ }
+
+ cquest.status = QUEST_STATUS_FINISHED;
+ cmsg_print(TERM_YELLOW, "Thrain speaks:");
+ cmsg_print(TERM_YELLOW, "'Ah, at last you came to me! But... I fear it is too late for me.");
+ cmsg_print(TERM_YELLOW, "However your quest continues, you must beware for the Necromancer");
+ cmsg_print(TERM_YELLOW, "is in fact Sauron, the Dark Lord! He stole the Ring of Durin and tortured");
+ cmsg_print(TERM_YELLOW, "me... arrgh... please make him pay!'");
+
+ /* Look for Thrain */
+ for (r = m_max - 1; r >= 1; r--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[r];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Is it the princess? */
+ if (m_ptr->r_idx == test_monster_name("Thrain, the King Under the Mountain"))
+ {
+ int x = m_ptr->fx;
+ int y = m_ptr->fy;
+ int i, j;
+ object_type forge, *q_ptr;
+
+ delete_monster_idx(r);
+
+ /* Wipe the glass walls and create a stair */
+ for (i = x - 1; i <= x + 1; i++)
+ for (j = y - 1; j <= y + 1; j++)
+ {
+ if (in_bounds(j, i)) cave_set_feat(j, i, FEAT_FLOOR);
+ }
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+ object_prep(q_ptr, lookup_kind(TV_HELM, SV_DRAGON_HELM));
+ q_ptr->number = 1;
+ q_ptr->found = OBJ_FOUND_REWARD;
+ create_artifact(q_ptr, FALSE, TRUE);
+ q_ptr->art_name = quark_add("of Thrain");
+
+ /* Drop it in the dungeon */
+ drop_near(q_ptr, -1, y, x);
+ break;
+ }
+ }
+
+
+ del_hook(HOOK_MONSTER_DEATH, quest_thrain_death_hook);
+ process_hooks_restart = TRUE;
+
+ return (FALSE);
+}
+
+bool_ quest_thrain_gen_hook(char *fmt)
+{
+ s32b x, y, bx0, by0;
+ int xstart;
+ int ystart;
+ int y2, x2, yval, xval;
+ int y1, x1, xsize, ysize;
+
+ if (dungeon_type != DUNGEON_DOL_GULDUR) return (FALSE);
+ if (cquest.data[0] != dun_level) return (FALSE);
+ if (cquest.data[1]) return (FALSE);
+ if ((cquest.status < QUEST_STATUS_TAKEN) || (cquest.status >= QUEST_STATUS_FINISHED)) return (FALSE);
+
+ by0 = get_next_arg(fmt);
+ bx0 = get_next_arg(fmt);
+
+ /* Pick a room size */
+ get_map_size("thrain.map", &ysize, &xsize);
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &xval, &yval)) return FALSE;
+
+ /* Get corner values */
+ y1 = yval - ysize / 2;
+ x1 = xval - xsize / 2;
+ y2 = y1 + ysize - 1;
+ x2 = x1 + xsize - 1;
+
+ /* Place a full floor under the room */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ cave_set_feat(y, x, floor_type[rand_int(100)]);
+ cave[y][x].info |= (CAVE_ROOM|CAVE_GLOW);
+ }
+ }
+
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, CAVE_ROOM | CAVE_GLOW);
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ xstart = x1;
+ ystart = y1;
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("thrain.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ for (x = x1; x < xstart; x++)
+ for (y = y1; y < ystart; y++)
+ {
+ cave[y][x].info |= CAVE_ICKY | CAVE_ROOM | CAVE_FREE;
+ if (cave[y][x].feat == FEAT_MARKER)
+ {
+ int i;
+
+ m_allow_special[test_monster_name("Thrain, the King Under the Mountain")] = TRUE;
+ i = place_monster_one(y, x, test_monster_name("Thrain, the King Under the Mountain"), 0, FALSE, MSTATUS_NEUTRAL);
+ if (i) m_list[i].mflag |= MFLAG_QUEST;
+ m_allow_special[test_monster_name("Thrain, the King Under the Mountain")] = FALSE;
+ }
+ }
+
+ /* Don't try another one for this generation */
+ cquest.data[1] = 1;
+
+ return (TRUE);
+}
+bool_ quest_thrain_feeling_hook(char *fmt)
+{
+ if (dungeon_type != DUNGEON_DOL_GULDUR) return (FALSE);
+ if (cquest.data[0] != dun_level) return (FALSE);
+ if (cquest.status != QUEST_STATUS_UNTAKEN) return (FALSE);
+
+ cmsg_format(TERM_YELLOW, "You hear someone shouting under the torture.");
+ cquest.status = QUEST_STATUS_TAKEN;
+ cquest.init(QUEST_THRAIN);
+
+ return (FALSE);
+}
+bool_ quest_thrain_move_hook(char *fmt)
+{
+ s32b y;
+ s32b x;
+ cave_type *c_ptr;
+
+ y = get_next_arg(fmt);
+ x = get_next_arg(fmt);
+ c_ptr = &cave[y][x];
+
+ if (dungeon_type != DUNGEON_DOL_GULDUR) return (FALSE);
+ if (cquest.data[0] != dun_level) return (FALSE);
+ if ((cquest.status < QUEST_STATUS_TAKEN) || (cquest.status >= QUEST_STATUS_FINISHED)) return (FALSE);
+ if (!(c_ptr->info & CAVE_FREE)) return (FALSE);
+ if (c_ptr->mimic != 61) return (FALSE);
+
+ cmsg_print(TERM_YELLOW, "The magic hiding the room dissipates.");
+ for (x = 0; x < cur_wid; x++)
+ for (y = 0; y < cur_hgt; y++)
+ {
+ c_ptr = &cave[y][x];
+
+ if (c_ptr->mimic != 61) continue;
+ if (!(c_ptr->info & CAVE_FREE)) continue;
+
+ c_ptr->mimic = 0;
+ lite_spot(y, x);
+ }
+
+ return (FALSE);
+}
+bool_ quest_thrain_turn_hook(char *fmt)
+{
+ cquest.data[1] = 0;
+ cquest.data[2] = 0;
+ return (FALSE);
+}
+bool_ quest_thrain_init_hook(int q)
+{
+ if (!cquest.data[0])
+ {
+ cquest.data[0] = rand_range(d_info[DUNGEON_DOL_GULDUR].mindepth + 1, d_info[DUNGEON_DOL_GULDUR].maxdepth - 1);
+ if (wizard) message_add(MESSAGE_MSG, format("Thrain lvl %d", cquest.data[0]), TERM_BLUE);
+ }
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MOVE, quest_thrain_move_hook, "thrain_move");
+ }
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_LEVEL_REGEN, quest_thrain_turn_hook, "thrain_regen_lvl");
+ add_hook(HOOK_NEW_LEVEL, quest_thrain_turn_hook, "thrain_new_lvl");
+ add_hook(HOOK_BUILD_ROOM1, quest_thrain_gen_hook, "thrain_gen");
+ add_hook(HOOK_FEELING, quest_thrain_feeling_hook, "thrain_feel");
+ add_hook(HOOK_MONSTER_DEATH, quest_thrain_death_hook, "thrain_death");
+ }
+ return (FALSE);
+}
diff --git a/src/q_troll.c b/src/q_troll.c
new file mode 100644
index 00000000..c314d2a7
--- /dev/null
+++ b/src/q_troll.c
@@ -0,0 +1,178 @@
+#undef cquest
+#define cquest (quest[QUEST_TROLL])
+
+bool_ quest_troll_gen_hook(char *fmt)
+{
+ int x, y;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_TROLL) return FALSE;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("trolls.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ for (x = 3; x < xstart; x++)
+ for (y = 3; y < ystart; y++)
+ {
+ if (cave[y][x].feat == FEAT_MARKER)
+ {
+ int m_idx;
+
+ m_allow_special[test_monster_name("Tom the Stone Troll")] = TRUE;
+ m_idx = place_monster_one(y, x, test_monster_name("Tom the Stone Troll"), 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[test_monster_name("Tom the Stone Troll")] = FALSE;
+
+ if (m_idx)
+ {
+ int o_idx;
+
+ /* Get local object */
+ object_type forge, *q_ptr = &forge;
+
+ m_list[m_idx].mflag |= MFLAG_QUEST;
+
+ a_allow_special[ART_GLAMDRING] = TRUE;
+
+ /* Mega-Hack -- Prepare to make "Glamdring" */
+ object_prep(q_ptr, lookup_kind(TV_SWORD, SV_BROAD_SWORD));
+
+ /* Mega-Hack -- Mark this item as "Glamdring" */
+ q_ptr->name1 = ART_GLAMDRING;
+
+ /* Mega-Hack -- Actually create "Glamdring" */
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+
+ a_allow_special[ART_GLAMDRING] = FALSE;
+
+ /* Get new object */
+ o_idx = o_pop();
+
+ if (o_idx)
+ {
+ /* Get the item */
+ object_type *o_ptr = &o_list[o_idx];
+
+ /* Structure copy */
+ object_copy(o_ptr, q_ptr);
+
+ /* Build a stack */
+ o_ptr->next_o_idx = m_list[m_idx].hold_o_idx;
+
+ o_ptr->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_list[m_idx].hold_o_idx = o_idx;
+ }
+ else
+ {
+ a_info[q_ptr->name1].cur_num = 0;
+ }
+ }
+ }
+ }
+
+ /* Reinitialize the ambush ... hehehe */
+ cquest.data[0] = FALSE;
+ return TRUE;
+}
+bool_ quest_troll_finish_hook(char *fmt)
+{
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_TROLL) return FALSE;
+
+ c_put_str(TERM_YELLOW, "I heard about your noble deeds.", 8, 0);
+ c_put_str(TERM_YELLOW, "Keep what you found... may it serve you well.", 9, 0);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_NAZGUL;
+ quest[*(quest[q_idx].plot)].init(*(quest[q_idx].plot));
+
+ del_hook(HOOK_QUEST_FINISH, quest_troll_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_troll_death_hook(char *fmt)
+{
+ int x, y, xstart = 2, ystart = 2;
+ s32b r_idx, m_idx;
+ ;
+
+ m_idx = get_next_arg(fmt);
+
+ r_idx = m_list[m_idx].r_idx;
+
+ if (p_ptr->inside_quest != QUEST_TROLL) return FALSE;
+
+ if (r_idx == test_monster_name("Tom the Stone Troll"))
+ {
+ cave_set_feat(3, 3, FEAT_LESS);
+ cave[3][3].special = 0;
+
+ cmsg_print(TERM_YELLOW, "Without Tom, the trolls won't be able to do much.");
+ cquest.status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_MONSTER_DEATH, quest_troll_death_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+ }
+
+ init_flags = INIT_GET_SIZE;
+ process_dungeon_file("trolls.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ if (cquest.data[0]) return FALSE;
+
+ cquest.data[0] = TRUE;
+
+ msg_print("Oops, seems like an ambush...");
+
+ for (x = 3; x < xstart; x++)
+ for (y = 3; y < ystart; y++)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Ahah ! */
+ if (c_ptr->info & CAVE_SPEC)
+ {
+ int r_idx;
+
+ cave_set_feat(y, x, FEAT_GRASS);
+ c_ptr->info &= ~CAVE_SPEC;
+
+ r_idx = (rand_int(2) == 0) ? test_monster_name("Forest troll") : test_monster_name("Stone troll");
+ place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_ENEMY);
+ }
+ }
+
+ return FALSE;
+}
+bool_ quest_troll_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_troll_death_hook, "troll_death");
+ add_hook(HOOK_GEN_QUEST, quest_troll_gen_hook, "troll_gen");
+ add_hook(HOOK_QUEST_FINISH, quest_troll_finish_hook, "troll_finish");
+ }
+ return (FALSE);
+}
diff --git a/src/q_ultrae.c b/src/q_ultrae.c
new file mode 100644
index 00000000..78471df5
--- /dev/null
+++ b/src/q_ultrae.c
@@ -0,0 +1,11 @@
+/*
+ * Here takes place the Evil ultra ending
+ */
+
+#undef cquest
+#define cquest (quest[QUEST_ULTRA_EVIL])
+
+bool_ quest_ultra_evil_init_hook(int q)
+{
+ return (FALSE);
+}
diff --git a/src/q_ultrag.c b/src/q_ultrag.c
new file mode 100644
index 00000000..a5a09f2d
--- /dev/null
+++ b/src/q_ultrag.c
@@ -0,0 +1,276 @@
+/*
+ * Here takes place the Good ultra ending
+ */
+
+#undef cquest
+#define cquest (quest[QUEST_ULTRA_GOOD])
+
+bool_ quest_ultra_good_move_hook(char *fmt)
+{
+ s32b y, x;
+ cave_type *c_ptr;
+
+ y = get_next_arg(fmt);
+ x = get_next_arg(fmt);
+ c_ptr = &cave[y][x];
+
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ bool_ old_quick_messages = quick_messages;
+
+ if (quest[QUEST_MORGOTH].status < QUEST_STATUS_FINISHED) return (FALSE);
+
+ /* The mirror of Galadriel */
+ if ((c_ptr->feat != FEAT_SHOP) || (c_ptr->special != 23)) return (FALSE);
+
+ quick_messages = FALSE;
+ cmsg_print(TERM_L_BLUE, "You meet Galadriel.");
+ cmsg_print(TERM_YELLOW, "'I still cannot believe this is all over.'");
+ cmsg_print(TERM_YELLOW, "'Morgoth's reign of terror is over at last!'");
+ cmsg_print(TERM_YELLOW, "'His spirit has been banished to the Void where he cannot do much harm.'");
+ cmsg_print(TERM_YELLOW, "'We can never thank you enough, hero!'");
+ cmsg_print(TERM_L_BLUE, "Although everything seems all right, Galadriel seems a little subdued.");
+ cmsg_print(TERM_YELLOW, "'The spirit of Morgoth is not destroyed however -- only banished.'");
+ cmsg_print(TERM_YELLOW, "'He can still control his allies left on Arda.'");
+ cmsg_print(TERM_YELLOW, "'Maybe... maybe there could be a way to remove the threat of evil forever.'");
+ cmsg_print(TERM_YELLOW, "'Somebody would have to go into the Void to do it.'");
+ cmsg_print(TERM_YELLOW, "'But going there is certain death; we cannot ask it of anyone.'");
+ cmsg_print(TERM_YELLOW, "'But you may choose, of your own free will, to attempt it...'");
+ cmsg_print(TERM_L_BLUE, "Galadriel plainly presents the choice that now lies before you:");
+
+ cmsg_print(TERM_YELLOW, "'You have earned the right to make whatever you wish of your future.'");
+ cmsg_print(TERM_YELLOW, "'Become a ruler of Arda if you so desire; reign long, enjoying'");
+ cmsg_print(TERM_YELLOW, "'the adulation of all, and have a happy life. Or, you can turn your'");
+ cmsg_print(TERM_YELLOW, "'back on safety. Enter the Void, alone, to fight a hopeless battle'");
+ cmsg_print(TERM_YELLOW, "'and face certain death.'");
+
+ /* This is SO important a question that flush pending inputs */
+ flush();
+
+ if (!get_check("Will you stay on Arda and lead a happy life?"))
+ {
+ cmsg_print(TERM_YELLOW, "'So be it. I will open a portal to the Void.'");
+ cmsg_print(TERM_YELLOW, "'But you must know this: the portal can only lead one way.'");
+ cmsg_print(TERM_YELLOW, "'It will close once you enter, so as not to permit the horrors'");
+ cmsg_print(TERM_YELLOW, "'that lurk in the Void to enter Arda. Your only way to come back'");
+ cmsg_print(TERM_YELLOW, "'is to defeat the spirit of Morgoth, known as Melkor.'");
+ cmsg_print(TERM_YELLOW, "'You will not be able to recall back either.'");
+ cmsg_print(TERM_YELLOW, "'You can still choose to retire; it is not too late'");
+ cmsg_print(TERM_YELLOW, "'to save your life.'");
+ cmsg_print(TERM_YELLOW, "'One last thing: It is quite certain that Melkor will have erected'");
+ cmsg_print(TERM_YELLOW, "'powerful magical barriers around him. You certainly will'");
+ cmsg_print(TERM_YELLOW, "'need to find a way to break them to get to him.'");
+
+ /* Create the entrance */
+ cave_set_feat(y - 5, x, FEAT_MORE);
+ cave[y - 5][x].special = 11;
+
+ /* Continue the plot */
+ cquest.status = QUEST_STATUS_TAKEN;
+ cquest.init(QUEST_ULTRA_GOOD);
+ }
+ quick_messages = old_quick_messages;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+bool_ quest_ultra_good_stair_hook(char *fmt)
+{
+ cptr dir;
+
+ dir = get_next_arg_str(fmt);
+
+ if (dungeon_type != DUNGEON_VOID)
+ return FALSE;
+
+ /* Cant leave */
+ if ((!strcmp(dir, "up")) && (dun_level == 128))
+ {
+ cmsg_print(TERM_YELLOW, "The portal to Arda is now closed.");
+ return TRUE;
+ }
+ /* there is no coming back */
+ if ((!strcmp(dir, "up")) && (dun_level == 150))
+ {
+ cmsg_print(TERM_YELLOW, "The barrier seems to be impenetrable from this side.");
+ cmsg_print(TERM_YELLOW, "You will have to move on.");
+ return TRUE;
+ }
+ /* Cant enter without the flame imperishable */
+ if ((!strcmp(dir, "down")) && (dun_level == 149))
+ {
+ int i;
+ bool_ ultimate = FALSE;
+
+ /* Now look for an ULTIMATE artifact, that is, one imbued with the flame */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+ object_type *o_ptr = get_object(i);
+
+ if (!o_ptr->k_idx) continue;
+
+ /* Examine the gloves */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (f4 & TR4_ULTIMATE)
+ {
+ ultimate = TRUE;
+ break;
+ }
+ }
+
+ if (!ultimate)
+ {
+ cmsg_print(TERM_YELLOW, "It seems the level is protected by an impassable barrier of pure magic.");
+ cmsg_print(TERM_YELLOW, "Only the most powerful magic could remove it. You will need to use");
+ cmsg_print(TERM_YELLOW, "the Flame Imperishable to pass. The source of Eru Iluvatar's own power.");
+ return TRUE;
+ }
+ else
+ {
+ cmsg_print(TERM_YELLOW, "The power of the Flame Imperishable shatters the magical barrier.");
+ cmsg_print(TERM_YELLOW, "The way before you is free.");
+ }
+ }
+
+ return FALSE;
+}
+
+bool_ quest_ultra_good_recall_hook(char *fmt)
+{
+ if ((dungeon_type != DUNGEON_VOID) && (dungeon_type != DUNGEON_NETHER_REALM))
+ return FALSE;
+
+ cmsg_print(TERM_YELLOW, "You cannot recall. The portal to Arda is closed.");
+ return TRUE;
+}
+
+bool_ quest_ultra_good_death_hook(char *fmt)
+{
+ s32b m_idx = get_next_arg(fmt);
+
+ monster_type *m_ptr = &m_list[m_idx];
+
+ /* Melkor is dead! */
+ if (m_ptr->r_idx == 1044)
+ {
+ /* Total winner */
+ total_winner = WINNER_ULTRA;
+ has_won = WINNER_ULTRA;
+ quest[QUEST_ULTRA_GOOD].status = QUEST_STATUS_FINISHED;
+
+ /* Redraw the "title" */
+ p_ptr->redraw |= (PR_TITLE);
+
+ /* Congratulations */
+ cmsg_print(TERM_L_GREEN, "****** CONGRATULATIONS ******");
+ cmsg_print(TERM_L_GREEN, "You have done more than the impossible. You ended the threat of");
+ cmsg_print(TERM_L_GREEN, "Melkor forever. Thanks to you, Arda will live in eternal peace.");
+ cmsg_print(TERM_L_GREEN, "You feel the spirit of Eru touching you. You feel your spirit rising!");
+ cmsg_print(TERM_L_GREEN, "Before you, a portal to Arda opens. You can now come back to your world");
+ cmsg_print(TERM_L_GREEN, "and live happily ever after.");
+ cmsg_print(TERM_L_GREEN, "What you do now is up to you, but your deeds shall ever be remembered.");
+ cmsg_print(TERM_L_GREEN, "You may retire (commit suicide) when you are ready.");
+
+ /* Create the entrance */
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_MORE);
+
+ /* Remove now used hook */
+ del_hook(HOOK_MONSTER_DEATH, quest_ultra_good_death_hook);
+ process_hooks_restart = TRUE;
+
+ /* End plot */
+ *(quest[QUEST_ULTRA_GOOD].plot) = QUEST_NULL;
+ }
+
+ /* Tik'svvrzllat is dead! */
+ if (m_ptr->r_idx == 1032)
+ {
+ int i;
+
+ /* Get local object */
+ object_type forge, *q_ptr = &forge;
+
+ /* Mega-Hack -- Prepare to make the Flame Imperishable */
+ object_prep(q_ptr, lookup_kind(TV_JUNK, 255));
+
+ /* Mega-Hack -- Actually create the Flame Imperishable */
+ k_allow_special[296] = TRUE;
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+ k_allow_special[296] = FALSE;
+
+ /* Identify it fully */
+ object_aware(q_ptr);
+ object_known(q_ptr);
+
+ /* Mark the item as fully known */
+ q_ptr->ident |= (IDENT_MENTAL);
+
+ /* Find a space */
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ /* Skip non-objects */
+ if (!p_ptr->inventory[i].k_idx) break;
+ }
+ /* Arg, no space ! */
+ if (i == INVEN_PACK)
+ {
+ char o_name[200];
+
+ object_desc(o_name, &p_ptr->inventory[INVEN_PACK - 1], FALSE, 0);
+
+ /* Drop the item */
+ inven_drop(INVEN_PACK - 1, 99, p_ptr->py, p_ptr->px, FALSE);
+
+ cmsg_format(TERM_VIOLET, "You feel the urge to drop your %s to make room in your inventory.", o_name);
+ }
+
+ /* Carry it */
+ cmsg_format(TERM_VIOLET, "You feel the urge to pick up the Flame Imperishable.");
+ inven_carry(q_ptr, FALSE);
+ }
+ return (FALSE);
+}
+bool_ quest_ultra_good_dump_hook(char *fmt)
+{
+ if (quest[QUEST_ULTRA_GOOD].status >= QUEST_STATUS_TAKEN)
+ {
+ /* Ultra winner ! */
+ if (total_winner == WINNER_ULTRA)
+ {
+ fprintf(hook_file, "\n You destroyed Melkor forever and have been elevated to the status of Vala by Eru Iluvatar.");
+ fprintf(hook_file, "\n Arda will forever be free.");
+ }
+ else
+ {
+ /* Tried and failed */
+ if (death)
+ {
+ fprintf(hook_file, "\n You tried to destroy Melkor forever, but died in the attempt.");
+ fprintf(hook_file, "\n Arda will be quiet, but not free from evil.");
+ }
+ }
+ }
+ return (FALSE);
+}
+
+
+bool_ quest_ultra_good_init_hook(int q)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_STAIR, quest_ultra_good_stair_hook, "ultrag_stair");
+ add_hook(HOOK_RECALL, quest_ultra_good_recall_hook, "ultrag_recall");
+ add_hook(HOOK_MONSTER_DEATH, quest_ultra_good_death_hook, "ultrag_death");
+ }
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ add_hook(HOOK_MOVE, quest_ultra_good_move_hook, "ultrag_move");
+ }
+ add_hook(HOOK_CHAR_DUMP, quest_ultra_good_dump_hook, "ultrag_dump");
+ return (FALSE);
+}
diff --git a/src/q_wight.c b/src/q_wight.c
new file mode 100644
index 00000000..3f6b2c34
--- /dev/null
+++ b/src/q_wight.c
@@ -0,0 +1,156 @@
+#undef cquest
+#define cquest (quest[QUEST_WIGHT])
+
+bool_ quest_wight_gen_hook(char *fmt)
+{
+ int x, y;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_WIGHT) return FALSE;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("wights.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ for (x = 3; x < xstart; x++)
+ for (y = 3; y < ystart; y++)
+ {
+ if (cave[y][x].feat == FEAT_MARKER)
+ {
+ int m_idx = 0;
+
+ m_allow_special[test_monster_name("The Wight-King of the Barrow-downs")] = TRUE;
+ m_idx = place_monster_one(y, x, test_monster_name("The Wight-King of the Barrow-downs"), 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[test_monster_name("The Wight-King of the Barrow-downs")] = FALSE;
+
+ if (m_idx)
+ {
+ int o_idx;
+
+ /* Get local object */
+ object_type forge, *q_ptr = &forge;
+
+ m_list[m_idx].mflag |= MFLAG_QUEST;
+
+ /* Prepare to make the */
+ object_prep(q_ptr, lookup_kind(TV_SOFT_ARMOR, SV_FILTHY_RAG));
+
+ /* Name the rags */
+
+ q_ptr->art_name = quark_add("of the Wight");
+
+ q_ptr->art_flags1 |= ( TR1_INT | TR1_SEARCH );
+ q_ptr->art_flags2 |= ( TR2_RES_BLIND | TR2_SENS_FIRE | TR2_RES_CONF );
+ q_ptr->art_flags3 |= ( TR3_IGNORE_ACID | TR3_IGNORE_ELEC |
+ TR3_IGNORE_FIRE | TR3_IGNORE_COLD | TR3_SEE_INVIS);
+
+ /* For game balance... */
+ q_ptr->art_flags3 |= (TR3_CURSED | TR3_HEAVY_CURSE);
+ q_ptr->ident |= IDENT_CURSED;
+
+ if (randint(2) == 1)
+ {
+ q_ptr->art_flags1 |= (TR1_SPELL);
+ q_ptr->pval = 6;
+ }
+ else
+ {
+ q_ptr->art_flags1 |= (TR1_MANA);
+ q_ptr->pval = 2;
+ }
+
+ /* Get new object */
+ o_idx = o_pop();
+
+ if (o_idx)
+ {
+ /* Get the item */
+ object_type *o_ptr = &o_list[o_idx];
+
+ /* Structure copy */
+ object_copy(o_ptr, q_ptr);
+
+ /* Build a stack */
+ o_ptr->next_o_idx = m_list[m_idx].hold_o_idx;
+
+ o_ptr->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_list[m_idx].hold_o_idx = o_idx;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+bool_ quest_wight_death_hook(char *fmt)
+{
+ s32b r_idx, m_idx;
+
+ m_idx = get_next_arg(fmt);
+ r_idx = m_list[m_idx].r_idx;
+
+ if (p_ptr->inside_quest != QUEST_WIGHT) return FALSE;
+
+ if (r_idx == test_monster_name("The Wight-King of the Barrow-downs"))
+ {
+ cmsg_print(TERM_YELLOW, "Without their King the wights won't be able to do much.");
+
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_LESS);
+ cave[p_ptr->py][p_ptr->px].special = 0;
+
+ cquest.status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_MONSTER_DEATH, quest_wight_death_hook);
+ process_hooks_restart = TRUE;
+ return (FALSE);
+ }
+
+ return (FALSE);
+}
+bool_ quest_wight_finish_hook(char *fmt)
+{
+ s32b q_idx;
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_WIGHT) return FALSE;
+
+ c_put_str(TERM_YELLOW, "I heard about your noble deeds.", 8, 0);
+ c_put_str(TERM_YELLOW, "Keep what you found .. may it serve you well.", 9, 0);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_NAZGUL;
+ quest[*(quest[q_idx].plot)].init(*(quest[q_idx].plot));
+
+ del_hook(HOOK_QUEST_FINISH, quest_wight_finish_hook);
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+bool_ quest_wight_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_wight_death_hook, "wight_death");
+ add_hook(HOOK_GEN_QUEST, quest_wight_gen_hook, "wight_gen");
+ add_hook(HOOK_QUEST_FINISH, quest_wight_finish_hook, "wight_finish");
+ }
+ return (FALSE);
+}
diff --git a/src/q_wolves.c b/src/q_wolves.c
new file mode 100644
index 00000000..2ec14cc2
--- /dev/null
+++ b/src/q_wolves.c
@@ -0,0 +1,130 @@
+#undef cquest
+#define cquest (quest[QUEST_WOLVES])
+
+bool_ quest_wolves_gen_hook(char *fmt)
+{
+ int x, y, i;
+ int xstart = 2;
+ int ystart = 2;
+
+ if (p_ptr->inside_quest != QUEST_WOLVES) return FALSE;
+
+ /* Just in case we didnt talk the the mayor */
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+
+ dun_level = quest[p_ptr->inside_quest].level;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("wolves.map", &ystart, &xstart, cur_hgt, cur_wid, TRUE, FALSE);
+ dungeon_flags2 |= DF2_NO_GENO;
+
+ /* Place some random wolves */
+ for (i = damroll(4, 4); i > 0; )
+ {
+ int m_idx, flags;
+ y = rand_int(21) + 3;
+ x = rand_int(31) + 3;
+ flags = f_info[cave[y][x].feat].flags1;
+ if (!(flags & FF1_PERMANENT) && (flags & FF1_FLOOR))
+ {
+ m_idx = place_monster_one(y, x, 196, 0, magik(50), MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ --i;
+ }
+ }
+
+ /* Place some random wargs */
+ for (i = damroll(4, 4); i > 0; )
+ {
+ int m_idx, flags;
+ y = rand_int(21) + 3;
+ x = rand_int(31) + 3;
+ flags = f_info[cave[y][x].feat].flags1;
+ if (!(flags & FF1_PERMANENT) && (flags & FF1_FLOOR))
+ {
+ m_idx = place_monster_one(y, x, 257, 0, magik(50), MSTATUS_ENEMY);
+ if (m_idx) m_list[m_idx].mflag |= MFLAG_QUEST;
+ --i;
+ }
+ }
+
+ process_hooks_restart = TRUE;
+
+ return TRUE;
+}
+
+bool_ quest_wolves_death_hook(char *fmt)
+{
+ int i, mcnt = 0;
+
+ if (p_ptr->inside_quest != QUEST_WOLVES) return FALSE;
+
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ /* Ignore "dead" monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->status <= MSTATUS_ENEMY) mcnt++;
+ }
+
+ /* Nobody left ? */
+ if (mcnt <= 1)
+ {
+ quest[p_ptr->inside_quest].status = QUEST_STATUS_COMPLETED;
+ del_hook(HOOK_MONSTER_DEATH, quest_wolves_death_hook);
+ del_hook(HOOK_GEN_QUEST, quest_wolves_gen_hook);
+ process_hooks_restart = TRUE;
+
+ cmsg_print(TERM_YELLOW, "Lothlorien is safer now.");
+ return (FALSE);
+ }
+ return FALSE;
+}
+
+bool_ quest_wolves_finish_hook(char *fmt)
+{
+ s32b q_idx;
+
+ q_idx = get_next_arg(fmt);
+
+ if (q_idx != QUEST_WOLVES) return FALSE;
+
+ c_put_str(TERM_YELLOW, "Thank you for killing the pack of wolves!", 8, 0);
+ c_put_str(TERM_YELLOW, "You can use the hut as your house as a reward.", 9, 0);
+
+ /* Continue the plot */
+ *(quest[q_idx].plot) = QUEST_SPIDER;
+
+ return TRUE;
+}
+
+bool_ quest_wolves_init_hook(int q_idx)
+{
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook(HOOK_MONSTER_DEATH, quest_wolves_death_hook, "wolves_monster_death");
+ add_hook(HOOK_QUEST_FINISH, quest_wolves_finish_hook, "wolves_finish");
+ add_hook(HOOK_GEN_QUEST, quest_wolves_gen_hook, "wolves_geb");
+ }
+ return (FALSE);
+}
diff --git a/src/quest.pkg b/src/quest.pkg
new file mode 100755
index 00000000..4ba93b7a
--- /dev/null
+++ b/src/quest.pkg
@@ -0,0 +1,170 @@
+/* File: quest.pkg */
+
+/*
+ * Purpose: Lua interface definitions for quests.
+ * To be processed by tolua to generate C source code.
+ */
+
+$#include "angband.h"
+
+/** @typedef cptr
+ * @note String
+ */
+typedef char* cptr;
+
+/** @typedef errr
+ * @note Number
+ */
+typedef int errr;
+
+/** @typedef bool
+ * @note Boolean
+ */
+typedef unsigned char bool;
+
+/** @typedef byte
+ * @note Number
+ */
+typedef unsigned char byte;
+
+/** @typedef s16b
+ * @note Number
+ */
+typedef signed short s16b;
+
+/** @typedef u16b
+ * @note Number
+ */
+typedef unsigned short u16b;
+
+/** @typedef s32b
+ * @note Number
+ */
+typedef signed int s32b;
+
+/** @typedef u32b
+ * @note Number
+ */
+typedef unsigned int u32b;
+
+/** @name Quest Status Flags
+ * @brief Quest status
+ * @{ */
+
+/** @def QUEST_STATUS_IGNORED */
+#define QUEST_STATUS_IGNORED -1
+
+/** @def QUEST_STATUS_UNTAKEN */
+#define QUEST_STATUS_UNTAKEN 0
+
+/** @def QUEST_STATUS_TAKEN */
+#define QUEST_STATUS_TAKEN 1
+
+/** @def QUEST_STATUS_COMPLETED */
+#define QUEST_STATUS_COMPLETED 2
+
+/** @def QUEST_STATUS_REWARDED */
+#define QUEST_STATUS_REWARDED 3
+
+/** @def QUEST_STATUS_FAILED */
+#define QUEST_STATUS_FAILED 4
+
+/** @def QUEST_STATUS_FINISHED */
+#define QUEST_STATUS_FINISHED 5
+
+/** @def QUEST_STATUS_FAILED_DONE */
+#define QUEST_STATUS_FAILED_DONE 6
+/** @} */
+
+/** @struct quest_type
+ * @brief Quest
+ */
+struct quest_type
+{
+ /** @structvar silent
+ * @brief Boolean
+ * @note Does quest appear on quest list?
+ */
+ bool silent;
+
+ /** @structvar dynamic_desc
+ * @brief Boolean
+ * @note Do we need to ask a function to get the description ?
+ */
+ bool dynamic_desc;
+
+ /** @structvar status
+ * @brief Number
+ * @note Is the quest taken, completed, finished?
+ */
+ s16b status;
+
+ /** @structvar level
+ * @brief Number
+ * @note Dungeon level
+ */
+ s16b level;
+
+ /** @structvar type
+ * @brief Number
+ * @note Lua or C ?
+ */
+ byte type;
+};
+
+/** @var max_q_idx
+ * @brief Number
+ * @note Maximum number of quests in quest list
+ */
+extern s16b max_q_idx;
+
+/** @var quest_aux;
+ * @brief quest_type
+ * @note Array of quests
+ */
+extern quest_type quest[max_q_idx] @ quest_aux;
+
+$static quest_type *lua_get_quest(int q_idx){return &quest[q_idx];}
+
+/** @fn quest(int q_idx);
+ * @brief Return quest with index "q_idx" from quest array.\n
+ * @param q_idx Number \n the index of a quest in the quest array.
+ * @brief Quest index
+ * @return quest_type \n The quest at index "q_idx".
+ * @note (see file w_quest.c)
+ */
+static quest_type *lua_get_quest @ quest(int q_idx);
+
+/** @fn new_quest(char *name);
+ * @dgonly
+ * @brief Add a new quest to the end of the quest array.\n
+ * @param *name String \n the name of the new quest.
+ * @brief Quest name
+ * @return Number \n The index of the new quest in the quest array.
+ * @note (see file lua_bind.c)
+ */
+extern s16b add_new_quest @ new_quest(char *name);
+
+/** @fn quest_desc(int q_idx, int d, char *desc);
+ * @dgonly
+ * @brief Return the description of a quest.\n
+ * @param q_idx Number \n the index of a quest in the quest array.
+ * @brief Quest index
+ * @param d Number \n the index of a line in the quest description.
+ * @brief Description line
+ * @param *desc String
+ * @brief Description
+ * @return *desc String \n Line "d" of the description of quest with index
+ * "q_idx" in the quest array.
+ * @note (see file lua_bind.c)
+ */
+extern void desc_quest @ quest_desc(int q_idx, int d, char *desc);
+
+/** @fn get_new_bounty_monster(int lev);
+ * @brief Find a good random bounty monster.\n
+ * @param lev Number \n the level of the bounty monster.
+ * @brief Monster level
+ * @return Number \n The index of the monster in the r_info array.
+ * @note (see file lua_bind.c)
+ */
+extern int lua_get_new_bounty_monster@get_new_bounty_monster(int lev);
diff --git a/src/randart.c b/src/randart.c
new file mode 100644
index 00000000..298ee83a
--- /dev/null
+++ b/src/randart.c
@@ -0,0 +1,476 @@
+/* File: randart.c */
+
+/* Purpose: Randart creation code */
+
+/*
+ * Copyright (c) 2001 DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/* Chance of using syllables to form the name instead of the "template" files */
+#define TABLE_NAME 45
+#define A_CURSED 13
+#define WEIRD_LUCK 12
+#define ACTIVATION_CHANCE 3
+
+/*
+ * Attempt to add a power to a randart
+ */
+static bool_ grab_one_power(int *ra_idx, object_type *o_ptr, bool_ good, s16b *max_times)
+{
+ int i = 0, j;
+ int *ok_ra, ok_num = 0;
+ bool_ ret = FALSE;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ C_MAKE(ok_ra, max_ra_idx, int);
+
+ /* Grab the ok randart */
+ for (i = 0; i < max_ra_idx; i++)
+ {
+ randart_part_type *ra_ptr = &ra_info[i];
+ bool_ ok = FALSE;
+
+ /* Must have the correct fields */
+ for (j = 0; j < 20; j++)
+ {
+ if (ra_ptr->tval[j] == o_ptr->tval)
+ {
+ if ((ra_ptr->min_sval[j] <= o_ptr->sval) && (ra_ptr->max_sval[j] >= o_ptr->sval)) ok = TRUE;
+ }
+
+ if (ok) break;
+ }
+ if ((0 < ra_ptr->max_pval) && (ra_ptr->max_pval < o_ptr->pval)) ok = FALSE;
+ if (!ok)
+ {
+ /* Doesnt count as a try*/
+ continue;
+ }
+
+ /* Good should be good, bad should be bad */
+ if (good && (ra_ptr->value <= 0)) continue;
+ if ((!good) && (ra_ptr->value > 0)) continue;
+
+ if (max_times[i] >= ra_ptr->max) continue;
+
+ /* Must NOT have the antagonic flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if (f1 & ra_ptr->aflags1) continue;
+ if (f2 & ra_ptr->aflags2) continue;
+ if (f3 & ra_ptr->aflags3) continue;
+ if (f4 & ra_ptr->aflags4) continue;
+ if (f5 & ra_ptr->aflags5) continue;
+ if (esp & ra_ptr->aesp) continue;
+
+ /* ok */
+ ok_ra[ok_num++] = i;
+ }
+
+ /* Now test them a few times */
+ for (i = 0; i < ok_num * 10; i++)
+ {
+ randart_part_type *ra_ptr;
+
+ i = ok_ra[rand_int(ok_num)];
+ ra_ptr = &ra_info[i];
+
+ /* XXX XXX Enforce minimum player level (loosely) */
+ if (ra_ptr->level > p_ptr->lev)
+ {
+ /* Acquire the "out-of-depth factor" */
+ int d = (ra_ptr->level - p_ptr->lev);
+
+ /* Roll for out-of-depth creation */
+ if (rand_int(d) != 0)
+ {
+ continue;
+ }
+ }
+
+ /* We must make the "rarity roll" */
+ if (rand_int(ra_ptr->mrarity) < ra_ptr->rarity)
+ {
+ continue;
+ }
+
+ /* Hack -- mark the item as an ego */
+ *ra_idx = i;
+ max_times[i]++;
+
+ /* Success */
+ ret = TRUE;
+ break;
+ }
+
+ C_FREE(ok_ra, max_ra_idx, int);
+
+ /* Return */
+ return (ret);
+}
+
+void give_activation_power (object_type * o_ptr)
+{
+ o_ptr->xtra2 = 0;
+ o_ptr->art_flags3 &= ~TR3_ACTIVATE;
+ o_ptr->timeout = 0;
+}
+
+
+int get_activation_power()
+{
+ object_type *o_ptr, forge;
+
+ o_ptr = &forge;
+
+ give_activation_power(o_ptr);
+
+ return o_ptr->xtra2;
+}
+
+#define MIN_NAME_LEN 5
+#define MAX_NAME_LEN 9
+#define S_WORD 26
+#define E_WORD S_WORD
+
+static long lprobs[S_WORD + 1][S_WORD + 1][S_WORD + 1];
+static long ltotal[S_WORD + 1][S_WORD + 1];
+
+/*
+ * Use W. Sheldon Simms' random name generator. This function builds
+ * probability tables which are used later on for letter selection. It
+ * relies on the ASCII character set.
+ */
+void build_prob(cptr learn)
+{
+ int c_prev, c_cur, c_next;
+
+ /* Build raw frequencies */
+ while (1)
+ {
+ c_prev = c_cur = S_WORD;
+
+ do
+ {
+ c_next = *learn++;
+ }
+ while (!isalpha(c_next) && (c_next != '\0'));
+
+ if (c_next == '\0') break;
+
+ do
+ {
+ c_next = A2I(tolower(c_next));
+ lprobs[c_prev][c_cur][c_next]++;
+ ltotal[c_prev][c_cur]++;
+ c_prev = c_cur;
+ c_cur = c_next;
+ c_next = *learn++;
+ }
+ while (isalpha(c_next));
+
+ lprobs[c_prev][c_cur][E_WORD]++;
+ ltotal[c_prev][c_cur]++;
+ }
+}
+
+
+/*
+ * Use W. Sheldon Simms' random name generator. Generate a random word using
+ * the probability tables we built earlier. Relies on the ASCII character
+ * set. Relies on European vowels (a, e, i, o, u). The generated name should
+ * be copied/used before calling this function again.
+ */
+static char *make_word(void)
+{
+ static char word_buf[90];
+ int r, totalfreq;
+ int tries, lnum, vow;
+ int c_prev, c_cur, c_next;
+ char *cp;
+
+startover:
+ vow = 0;
+ lnum = 0;
+ tries = 0;
+ cp = word_buf;
+ c_prev = c_cur = S_WORD;
+
+ while (1)
+ {
+getletter:
+ c_next = 0;
+ r = rand_int(ltotal[c_prev][c_cur]);
+ totalfreq = lprobs[c_prev][c_cur][c_next];
+
+ while (totalfreq <= r)
+ {
+ c_next++;
+ totalfreq += lprobs[c_prev][c_cur][c_next];
+ }
+
+ if (c_next == E_WORD)
+ {
+ if ((lnum < MIN_NAME_LEN) || vow == 0)
+ {
+ tries++;
+ if (tries < 10) goto getletter;
+ goto startover;
+ }
+ *cp = '\0';
+ break;
+ }
+
+ if (lnum >= MAX_NAME_LEN) goto startover;
+
+ *cp = I2A(c_next);
+
+ if (is_a_vowel(*cp)) vow++;
+
+ cp++;
+ lnum++;
+ c_prev = c_cur;
+ c_cur = c_next;
+ }
+
+ word_buf[0] = toupper(word_buf[0]);
+
+ return (word_buf);
+}
+
+
+void get_random_name(char * return_name)
+{
+ char *word = make_word();
+
+ if (rand_int(3) == 0)
+ sprintf(return_name, "'%s'", word);
+ else
+ sprintf(return_name, "of %s", word);
+}
+
+
+bool_ create_artifact(object_type *o_ptr, bool_ a_scroll, bool_ get_name)
+{
+ char new_name[80];
+ int powers = 0, i;
+ s32b total_flags, total_power = 0;
+ bool_ a_cursed = FALSE;
+ u32b f1, f2, f3, f4, f5, esp;
+ s16b *max_times;
+ s16b pval = 0;
+ bool_ limit_blows = FALSE;
+
+ strcpy(new_name, "");
+
+ if ((!a_scroll) && (randint(A_CURSED) == 1)) a_cursed = TRUE;
+
+ i = 0;
+ while (ra_gen[i].chance)
+ {
+ powers += damroll(ra_gen[i].dd, ra_gen[i].ds) + ra_gen[i].plus;
+ i++;
+ }
+
+ if ((!a_cursed) && (randint(30) == 1)) powers *= 2;
+
+ if (a_cursed) powers /= 2;
+
+ C_MAKE(max_times, max_ra_idx, s16b);
+
+ /* Main loop */
+ while (powers)
+ {
+ int ra_idx;
+ randart_part_type *ra_ptr;
+
+ powers--;
+
+ if (!grab_one_power(&ra_idx, o_ptr, TRUE, max_times)) continue;
+
+ ra_ptr = &ra_info[ra_idx];
+
+ if (wizard) msg_format("Adding randart power: %d", ra_idx);
+
+ total_power += ra_ptr->value;
+
+ o_ptr->art_flags1 |= ra_ptr->flags1;
+ o_ptr->art_flags2 |= ra_ptr->flags2;
+ o_ptr->art_flags3 |= ra_ptr->flags3;
+ o_ptr->art_flags4 |= ra_ptr->flags4;
+ o_ptr->art_flags5 |= ra_ptr->flags5;
+ o_ptr->art_esp |= ra_ptr->esp;
+
+ add_random_ego_flag(o_ptr, ra_ptr->fego, &limit_blows);
+
+ /* get flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hack -- acquire "cursed" flag */
+ if (f3 & TR3_CURSED) o_ptr->ident |= (IDENT_CURSED);
+
+ /* Hack -- obtain bonuses */
+ if (ra_ptr->max_to_h > 0) o_ptr->to_h += randint(ra_ptr->max_to_h);
+ if (ra_ptr->max_to_h < 0) o_ptr->to_h -= randint( -ra_ptr->max_to_h);
+ if (ra_ptr->max_to_d > 0) o_ptr->to_d += randint(ra_ptr->max_to_d);
+ if (ra_ptr->max_to_d < 0) o_ptr->to_d -= randint( -ra_ptr->max_to_d);
+ if (ra_ptr->max_to_a > 0) o_ptr->to_a += randint(ra_ptr->max_to_a);
+ if (ra_ptr->max_to_a < 0) o_ptr->to_a -= randint( -ra_ptr->max_to_a);
+
+ /* Hack -- obtain pval */
+ if (((pval > ra_ptr->max_pval) && ra_ptr->max_pval) || (!pval)) pval = ra_ptr->max_pval;
+ };
+ C_FREE(max_times, max_ra_idx, s16b);
+
+ if (pval > 0) o_ptr->pval = randint(pval);
+ if (pval < 0) o_ptr->pval = randint( -pval);
+
+ /* No insane number of blows */
+ if (limit_blows && (o_ptr->art_flags1 & TR1_BLOWS))
+ {
+ if (o_ptr->pval > 2) o_ptr->pval = randint(2);
+ }
+
+ /* Just to be sure */
+ o_ptr->art_flags3 |= ( TR3_IGNORE_ACID | TR3_IGNORE_ELEC |
+ TR3_IGNORE_FIRE | TR3_IGNORE_COLD);
+
+ total_flags = flag_cost(o_ptr, o_ptr->pval);
+ if (cheat_peek) msg_format("%ld", total_flags);
+
+ if (a_cursed) curse_artifact(o_ptr);
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (get_name)
+ {
+ if (a_scroll)
+ {
+ char dummy_name[80];
+
+ /* Identify it fully */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ o_ptr->ident |= (IDENT_STOREB | IDENT_MENTAL);
+
+ strcpy(dummy_name, "");
+ object_out_desc(o_ptr, NULL, FALSE, TRUE);
+
+ if (get_string("What do you want to call the artifact? ", dummy_name, 80))
+ {
+ strcpy(new_name, "called '");
+ strcat(new_name, dummy_name);
+ strcat(new_name, "'");
+ }
+ else
+ /* Default name = of 'player name' */
+ sprintf(new_name, "of '%s'", player_name);
+ }
+ else
+ {
+ get_random_name(new_name);
+ }
+ }
+
+ /* Save the inscription */
+ o_ptr->art_name = quark_add(new_name);
+ o_ptr->name2 = o_ptr->name2b = 0;
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* HACKS for ToME */
+ if (o_ptr->tval == TV_CLOAK && o_ptr->sval == SV_MIMIC_CLOAK)
+ {
+ s32b mimic;
+ call_lua("find_random_mimic_shape", "(d,d)", "d", 127, TRUE, &mimic);
+ o_ptr->pval2 = mimic;
+ }
+ else if (f5 & TR5_SPELL_CONTAIN)
+ {
+ o_ptr->pval2 = -1;
+ }
+
+ return TRUE;
+}
+
+
+bool_ artifact_scroll(void)
+{
+ int item;
+ bool_ okay = FALSE;
+ object_type *o_ptr;
+ char o_name[80];
+
+ cptr q, s;
+
+
+ /* Enchant weapon/armour */
+ item_tester_hook = item_tester_hook_artifactable;
+
+ /* Get an item */
+ q = "Enchant which item? ";
+ s = "You have nothing to enchant.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return (FALSE);
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Description */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ /* Describe */
+ msg_format("%s %s radiate%s a blinding light!",
+ ((item >= 0) ? "Your" : "The"), o_name,
+ ((o_ptr->number > 1) ? "" : "s"));
+
+ if (artifact_p(o_ptr))
+ {
+ msg_format("The %s %s already %s!",
+ o_name, ((o_ptr->number > 1) ? "are" : "is"),
+ ((o_ptr->number > 1) ? "artifacts" : "an artifact"));
+ okay = FALSE;
+ }
+
+ else if (o_ptr->name2)
+ {
+ msg_format("The %s %s already %s!",
+ o_name, ((o_ptr->number > 1) ? "are" : "is"),
+ ((o_ptr->number > 1) ? "ego items" : "an ego item"));
+ okay = FALSE;
+ }
+
+ else
+ {
+ if (o_ptr->number > 1)
+ {
+ msg_print("Not enough enough energy to enchant more than one object!");
+ msg_format("%d of your %s %s destroyed!", (o_ptr->number) - 1, o_name, (o_ptr->number > 2 ? "were" : "was"));
+ o_ptr->number = 1;
+ }
+ okay = create_artifact(o_ptr, TRUE, TRUE);
+ }
+
+ /* Failure */
+ if (!okay)
+ {
+ /* Flush */
+ if (flush_failure) flush();
+
+ /* Message */
+ msg_print("The enchantment failed.");
+ }
+ else
+ o_ptr->found = OBJ_FOUND_SELFMADE;
+
+ /* Something happened */
+ return (TRUE);
+}
+
+
diff --git a/src/readdib.c b/src/readdib.c
new file mode 100644
index 00000000..294c2702
--- /dev/null
+++ b/src/readdib.c
@@ -0,0 +1,342 @@
+/* File: readbits.c */
+
+/*
+ * This package provides a routine to read a DIB file and set up the
+ * device dependent version of the image.
+ *
+ * This file has been modified for use with "Angband 2.8.2"
+ *
+ * COPYRIGHT:
+ *
+ * (C) Copyright Microsoft Corp. 1993. All rights reserved.
+ *
+ * You have a royalty-free right to use, modify, reproduce and
+ * distribute the Sample Files (and/or any modified version) in
+ * any way you find useful, provided that you agree that
+ * Microsoft has no warranty obligations or liability for any
+ * Sample Application Files which are modified.
+ */
+
+#ifdef WINDOWS
+
+#include <windows.h>
+
+#include "readdib.h"
+
+
+/*
+ * Extract the "WIN32" flag from the compiler
+ */
+#if defined(__WIN32__) || defined(__WINNT__) || defined(__NT__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+
+/*
+ * Make sure "huge" is legal XXX XXX XXX
+ */
+#undef huge
+#ifdef WIN32
+# define huge /* oops */
+#endif
+
+
+/*
+ * Number of bytes to be read during each read operation
+ */
+#define MAXREAD 32768
+
+/*
+ * Private routine to read more than 64K at a time
+ *
+ * Reads data in steps of 32k till all the data has been read.
+ *
+ * Returns number of bytes requested, or zero if something went wrong.
+ */
+static DWORD PASCAL lread(int fh, VOID far *pv, DWORD ul)
+{
+ DWORD ulT = ul;
+ BYTE huge *hp = pv;
+
+ while (ul > (DWORD)MAXREAD)
+ {
+ if (_lread(fh, (LPSTR)hp, (WORD)MAXREAD) != MAXREAD)
+ return 0;
+ ul -= MAXREAD;
+ hp += MAXREAD;
+ }
+ if (_lread(fh, (LPSTR)hp, (WORD)ul) != (WORD)ul)
+ return 0;
+ return ulT;
+}
+
+
+/*
+ * Given a BITMAPINFOHEADER, create a palette based on the color table.
+ *
+ * Returns the handle of a palette, or zero if something went wrong.
+ */
+static HPALETTE PASCAL NEAR MakeDIBPalette(LPBITMAPINFOHEADER lpInfo)
+{
+ NPLOGPALETTE npPal;
+ RGBQUAD far *lpRGB;
+ HPALETTE hLogPal;
+ WORD i;
+
+ /*
+ * since biClrUsed field was filled during the loading of the DIB,
+ * we know it contains the number of colors in the color table.
+ */
+ if (lpInfo->biClrUsed)
+ {
+ npPal = (NPLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
+ (WORD)lpInfo->biClrUsed * sizeof(PALETTEENTRY));
+ if (!npPal)
+ return (FALSE);
+
+ npPal->palVersion = 0x300;
+ npPal->palNumEntries = (WORD)lpInfo->biClrUsed;
+
+ /* get pointer to the color table */
+ lpRGB = (RGBQUAD FAR *)((LPSTR)lpInfo + lpInfo->biSize);
+
+ /* copy colors from the color table to the LogPalette structure */
+ for (i = 0; i < lpInfo->biClrUsed; i++, lpRGB++)
+ {
+ npPal->palPalEntry[i].peRed = lpRGB->rgbRed;
+ npPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
+ npPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
+ npPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
+ }
+
+ hLogPal = CreatePalette((LPLOGPALETTE)npPal);
+ LocalFree((HANDLE)npPal);
+ return (hLogPal);
+ }
+
+ /*
+ * 24-bit DIB with no color table. return default palette. Another
+ * option would be to create a 256 color "rainbow" palette to provide
+ * some good color choices.
+ */
+ else
+ {
+ return (GetStockObject(DEFAULT_PALETTE));
+ }
+}
+
+
+/*
+ * Given a DIB, create a bitmap and corresponding palette to be used for a
+ * device-dependent representation of the image.
+ *
+ * Returns TRUE on success (phPal and phBitmap are filled with appropriate
+ * handles. Caller is responsible for freeing objects) and FALSE on failure
+ * (unable to create objects, both pointer are invalid).
+ */
+static BOOL NEAR PASCAL MakeBitmapAndPalette(HDC hDC, HANDLE hDIB,
+ HPALETTE * phPal, HBITMAP * phBitmap)
+{
+ LPBITMAPINFOHEADER lpInfo;
+ BOOL result = FALSE;
+ HBITMAP hBitmap;
+ HPALETTE hPalette, hOldPal;
+ LPSTR lpBits;
+
+ lpInfo = (LPBITMAPINFOHEADER) GlobalLock(hDIB);
+ if ((hPalette = MakeDIBPalette(lpInfo)) != 0)
+ {
+ /* Need to realize palette for converting DIB to bitmap. */
+ hOldPal = SelectPalette(hDC, hPalette, TRUE);
+ RealizePalette(hDC);
+
+ lpBits = ((LPSTR)lpInfo + (WORD)lpInfo->biSize +
+ (WORD)lpInfo->biClrUsed * sizeof(RGBQUAD));
+ hBitmap = CreateDIBitmap(hDC, lpInfo, CBM_INIT, lpBits,
+ (LPBITMAPINFO)lpInfo, DIB_RGB_COLORS);
+
+ SelectPalette(hDC, hOldPal, TRUE);
+ RealizePalette(hDC);
+
+ if (!hBitmap)
+ {
+ DeleteObject(hPalette);
+ }
+ else
+ {
+ *phBitmap = hBitmap;
+ *phPal = hPalette;
+ result = TRUE;
+ }
+ }
+ return (result);
+}
+
+
+
+/*
+ * Reads a DIB from a file, obtains a handle to its BITMAPINFO struct, and
+ * loads the DIB. Once the DIB is loaded, the function also creates a bitmap
+ * and palette out of the DIB for a device-dependent form.
+ *
+ * Returns TRUE if the DIB is loaded and the bitmap/palette created, in which
+ * case, the DIBINIT structure pointed to by pInfo is filled with the appropriate
+ * handles, and FALSE if something went wrong.
+ */
+BOOL ReadDIB(HWND hWnd, LPSTR lpFileName, DIBINIT *pInfo)
+{
+ unsigned fh;
+ LPBITMAPINFOHEADER lpbi;
+ OFSTRUCT of;
+ BITMAPFILEHEADER bf;
+ WORD nNumColors;
+ BOOL result = FALSE;
+ char str[128];
+ WORD offBits;
+ HDC hDC;
+ BOOL bCoreHead = FALSE;
+
+ /* Open the file and get a handle to it's BITMAPINFO */
+ fh = OpenFile(lpFileName, &of, OF_READ);
+ if (fh == -1)
+ {
+ wsprintf(str, "Can't open file '%ls'", (LPSTR)lpFileName);
+ MessageBox(NULL, str, "Error", MB_ICONSTOP | MB_OK);
+ return (FALSE);
+ }
+
+ pInfo->hDIB = GlobalAlloc(GHND, (DWORD)(sizeof(BITMAPINFOHEADER) +
+ 256 * sizeof(RGBQUAD)));
+
+ if (!pInfo->hDIB)
+ return (FALSE);
+
+ lpbi = (LPBITMAPINFOHEADER)GlobalLock(pInfo->hDIB);
+
+ /* read the BITMAPFILEHEADER */
+ if (sizeof (bf) != _lread(fh, (LPSTR)&bf, sizeof(bf)))
+ goto ErrExit;
+
+ /* 'BM' */
+ if (bf.bfType != 0x4d42)
+ goto ErrExit;
+
+ if (sizeof(BITMAPCOREHEADER) != _lread(fh, (LPSTR)lpbi, sizeof(BITMAPCOREHEADER)))
+ goto ErrExit;
+
+ if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
+ {
+ lpbi->biSize = sizeof(BITMAPINFOHEADER);
+ lpbi->biBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
+ lpbi->biPlanes = ((LPBITMAPCOREHEADER)lpbi)->bcPlanes;
+ lpbi->biHeight = ((LPBITMAPCOREHEADER)lpbi)->bcHeight;
+ lpbi->biWidth = ((LPBITMAPCOREHEADER)lpbi)->bcWidth;
+ bCoreHead = TRUE;
+ }
+ else
+ {
+ /* get to the start of the header and read INFOHEADER */
+ _llseek(fh, sizeof(BITMAPFILEHEADER), SEEK_SET);
+ if (sizeof(BITMAPINFOHEADER) != _lread(fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
+ goto ErrExit;
+ }
+
+ if (!(nNumColors = (WORD)lpbi->biClrUsed))
+ {
+ /* no color table for 24-bit, default size otherwise */
+ if (lpbi->biBitCount != 24)
+ nNumColors = 1 << lpbi->biBitCount;
+ }
+
+ /* fill in some default values if they are zero */
+ if (lpbi->biClrUsed == 0)
+ lpbi->biClrUsed = nNumColors;
+
+ if (lpbi->biSizeImage == 0)
+ {
+ lpbi->biSizeImage = (((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
+ * lpbi->biHeight);
+ }
+
+ /* otherwise wouldn't work with 16 color bitmaps -- S.K. */
+ else if ((nNumColors == 16) && (lpbi->biSizeImage > bf.bfSize))
+ {
+ lpbi->biSizeImage /= 2;
+ }
+
+ /* get a proper-sized buffer for header, color table and bits */
+ GlobalUnlock(pInfo->hDIB);
+ pInfo->hDIB = GlobalReAlloc(pInfo->hDIB, lpbi->biSize +
+ nNumColors * sizeof(RGBQUAD) +
+ lpbi->biSizeImage, 0);
+
+ /* can't resize buffer for loading */
+ if (!pInfo->hDIB)
+ goto ErrExit2;
+
+ lpbi = (LPBITMAPINFOHEADER)GlobalLock(pInfo->hDIB);
+
+ /* read the color table */
+ if (!bCoreHead)
+ {
+ _lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
+ }
+ else
+ {
+ signed int i;
+ RGBQUAD FAR *pQuad;
+ RGBTRIPLE FAR *pTriple;
+
+ _lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBTRIPLE));
+
+ pQuad = (RGBQUAD FAR *)((LPSTR)lpbi + lpbi->biSize);
+ pTriple = (RGBTRIPLE FAR *) pQuad;
+ for (i = nNumColors - 1; i >= 0; i--)
+ {
+ pQuad[i].rgbRed = pTriple[i].rgbtRed;
+ pQuad[i].rgbBlue = pTriple[i].rgbtBlue;
+ pQuad[i].rgbGreen = pTriple[i].rgbtGreen;
+ pQuad[i].rgbReserved = 0;
+ }
+ }
+
+ /* offset to the bits from start of DIB header */
+ offBits = (WORD)lpbi->biSize + nNumColors * sizeof(RGBQUAD);
+
+ if (bf.bfOffBits != 0L)
+ {
+ _llseek(fh, bf.bfOffBits, SEEK_SET);
+ }
+
+ /* Use local version of '_lread()' above */
+ if (lpbi->biSizeImage == lread(fh, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
+ {
+ GlobalUnlock(pInfo->hDIB);
+
+ hDC = GetDC(hWnd);
+ if (!MakeBitmapAndPalette(hDC, pInfo->hDIB, &(pInfo->hPalette),
+ &(pInfo->hBitmap)))
+ {
+ ReleaseDC(hWnd, hDC);
+ goto ErrExit2;
+ }
+ else
+ {
+ ReleaseDC(hWnd, hDC);
+ result = TRUE;
+ }
+ }
+ else
+ {
+ErrExit:
+ GlobalUnlock(pInfo->hDIB);
+ErrExit2:
+ GlobalFree(pInfo->hDIB);
+ }
+
+ _lclose(fh);
+ return (result);
+}
+
+#endif
diff --git a/src/readdib.h b/src/readdib.h
new file mode 100644
index 00000000..c6402b50
--- /dev/null
+++ b/src/readdib.h
@@ -0,0 +1,21 @@
+/* File: readdib.h */
+
+/*
+ * This file has been modified for use with "Angband 2.8.2"
+ *
+ * Copyright 1991 Microsoft Corporation. All rights reserved.
+ */
+
+/*
+ * Information about a bitmap
+ */
+typedef struct {
+ HANDLE hDIB;
+ HANDLE hBitmap;
+ HANDLE hPalette;
+ BYTE CellWidth;
+ BYTE CellHeight;
+} DIBINIT;
+
+/* Read a DIB from a file */
+BOOL ReadDIB(HWND, LPSTR, DIBINIT *);
diff --git a/src/script.c b/src/script.c
new file mode 100644
index 00000000..89c9ff3b
--- /dev/null
+++ b/src/script.c
@@ -0,0 +1,535 @@
+/* File: script.c */
+
+/* Purpose: scripting in lua */
+
+/*
+ * Copyright (c) 2001 Dark God
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+#include "lua/lua.h"
+#include "lua/lualib.h"
+#include "lauxlib.h"
+#include "tolua.h"
+
+int tolua_monster_open (lua_State *L);
+int tolua_player_open (lua_State *L);
+int tolua_player_c_open (lua_State *L);
+int tolua_util_open (lua_State *L);
+int tolua_z_pack_open (lua_State *L);
+int tolua_object_open (lua_State *L);
+int tolua_spells_open (lua_State *L);
+int tolua_quest_open (lua_State *L);
+int tolua_dungeon_open (lua_State *L);
+
+/*
+ * Lua state
+ */
+lua_State* L = NULL;
+
+/* ToME Lua error message handler */
+static int tome_errormessage(lua_State *L)
+{
+ char buf[200];
+ cptr str = luaL_check_string(L, 1);
+ int i = 0, j = 0;
+
+ while (str[i])
+ {
+ if (str[i] == '#')
+ {
+ buf[j++] = '$';
+ }
+ else if (str[i] != '\n')
+ {
+ buf[j++] = str[i];
+ }
+ else
+ {
+ buf[j] = '\0';
+ cmsg_format(TERM_VIOLET, "LUA: %s", buf);
+ j = 0;
+ }
+ i++;
+ }
+ buf[j] = '\0';
+ cmsg_format(TERM_VIOLET, "LUA: %s", buf);
+ return (0);
+}
+
+static struct luaL_reg tome_iolib[] =
+{
+ { "_ALERT", tome_errormessage },
+};
+
+#define luaL_check_bit(L, n) ((long)luaL_check_number(L, n))
+#define luaL_check_ubit(L, n) ((unsigned long)luaL_check_bit(L, n))
+
+
+/*
+ * Monadic bit negation operation
+ * MONADIC(not, ~)
+ */
+static int int_not(lua_State* L)
+{
+ lua_pushnumber(L, ~luaL_check_bit(L, 1));
+ return 1;
+}
+
+
+/*
+ * Dyadic integer modulus operation
+ * DYADIC(mod, %)
+ */
+static int int_mod(lua_State* L)
+{
+ lua_pushnumber(L, luaL_check_bit(L, 1) % luaL_check_bit(L, 2));
+ return 1;
+}
+
+
+/*
+ * Variable length bitwise AND operation
+ * VARIADIC(and, &)
+ */
+static int int_and(lua_State *L)
+{
+ int n = lua_gettop(L), i;
+ long w = luaL_check_bit(L, 1);
+
+ for (i = 2; i <= n; i++) w &= luaL_check_bit(L, i);
+ lua_pushnumber(L, w);
+
+ return 1;
+}
+
+
+/*
+ * Variable length bitwise OR operation
+ * VARIADIC(or, |)
+ */
+static int int_or(lua_State *L)
+{
+ int n = lua_gettop(L), i;
+ long w = luaL_check_bit(L, 1);
+
+ for (i = 2; i <= n; i++) w |= luaL_check_bit(L, i);
+ lua_pushnumber(L, w);
+
+ return 1;
+}
+
+
+/*
+ * Variable length bitwise XOR operation
+ * VARIADIC(xor, ^)
+ */
+static int int_xor(lua_State *L)
+{
+ int n = lua_gettop(L), i;
+ long w = luaL_check_bit(L, 1);
+
+ for (i = 2; i <= n; i++) w ^= luaL_check_bit(L, i);
+ lua_pushnumber(L, w);
+
+ return 1;
+}
+
+
+/*
+ * Binary left shift operation
+ * TDYADIC(lshift, <<, , u)
+ */
+static int int_lshift(lua_State* L)
+{
+ lua_pushnumber(L, luaL_check_bit(L, 1) << luaL_check_ubit(L, 2));
+ return 1;
+}
+
+/*
+ * Binary logical right shift operation
+ * TDYADIC(rshift, >>, u, u)
+ */
+static int int_rshift(lua_State* L)
+{
+ lua_pushnumber(L, luaL_check_ubit(L, 1) >> luaL_check_ubit(L, 2));
+ return 1;
+}
+
+/*
+ * Binary arithmetic right shift operation
+ * TDYADIC(arshift, >>, , u)
+ */
+static int int_arshift(lua_State* L)
+{
+ lua_pushnumber(L, luaL_check_bit(L, 1) >> luaL_check_ubit(L, 2));
+ return 1;
+}
+
+
+static const struct luaL_reg bitlib[] =
+{
+ {"bnot", int_not},
+ {"imod", int_mod}, /* "mod" already in Lua math library */
+ {"band", int_and},
+ {"bor", int_or},
+ {"bxor", int_xor},
+ {"lshift", int_lshift},
+ {"rshift", int_rshift},
+ {"arshift", int_arshift},
+};
+
+/*
+ * Initialize lua scripting
+ */
+static bool_ init_lua_done = FALSE;
+void init_lua()
+{
+ /* Hack -- Do not initialize more than once */
+ if (init_lua_done) return;
+ init_lua_done = TRUE;
+
+ /* Start the interpreter with default stack size */
+ L = lua_open(0);
+
+ /* Register the Lua base libraries */
+ lua_baselibopen(L);
+ lua_strlibopen(L);
+ lua_iolibopen(L);
+ lua_dblibopen(L);
+
+ /* Register tome lua debug library */
+ luaL_openl(L, tome_iolib);
+
+ /* Register the bitlib */
+ luaL_openl(L, bitlib);
+
+ /* Register the ToME main APIs */
+ tolua_player_open(L);
+ tolua_player_c_open(L);
+ tolua_util_open(L);
+ tolua_z_pack_open(L);
+ tolua_object_open(L);
+ tolua_monster_open(L);
+ tolua_spells_open(L);
+ tolua_quest_open(L);
+ tolua_dungeon_open(L);
+}
+
+void init_lua_init()
+{
+ int i, max;
+
+ /* Load the first lua file */
+ tome_dofile_anywhere(ANGBAND_DIR_CORE, "init.lua", TRUE);
+
+ /* Finish up schools */
+ max = exec_lua("return __schools_num");
+ init_schools(max);
+ for (i = 0; i < max; i++)
+ {
+ exec_lua(format("finish_school(%d)", i));
+ }
+
+ /* Finish up the spells */
+ max = exec_lua("return __tmp_spells_num");
+ init_spells(max);
+ for (i = 0; i < max; i++)
+ {
+ exec_lua(format("finish_spell(%d)", i));
+ }
+
+ /* Finish up the corruptions */
+ max = exec_lua("return __corruptions_max");
+ init_corruptions(max);
+}
+
+bool_ tome_dofile(char *file)
+{
+ char buf[1024];
+ int oldtop = lua_gettop(L);
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_SCPT, file);
+
+ if (!file_exist(buf))
+ {
+ /* No lua source(.lua), maybe a compiled one(.luo) ? */
+ if (suffix(buf, ".lua"))
+ {
+ int len = strlen(buf);
+ buf[len - 1] = 'o';
+ if (!file_exist(buf))
+ {
+ cmsg_format(TERM_VIOLET,
+ "tome_dofile(): file %s(%s) doesn't exist.", file, buf);
+ return (FALSE);
+ }
+ }
+ }
+
+ lua_dofile(L, buf);
+ lua_settop(L, oldtop);
+
+ return (TRUE);
+}
+
+bool_ tome_dofile_anywhere(cptr dir, char *file, bool_ test_exist)
+{
+ char buf[1024];
+ int oldtop = lua_gettop(L);
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), dir, file);
+
+ if (!file_exist(buf))
+ {
+ /* No lua source(.lua), maybe a compiled one(.luo) ? */
+ if (suffix(buf, ".lua"))
+ {
+ int len = strlen(buf);
+ buf[len - 1] = 'o';
+ if (!file_exist(buf))
+ {
+ if (test_exist)
+ cmsg_format(TERM_VIOLET,
+ "tome_dofile_anywhere(): file %s(%s) doesn't exist in %s.", dir, file, buf);
+ return (FALSE);
+ }
+ }
+ }
+
+ lua_dofile(L, buf);
+ lua_settop(L, oldtop);
+
+ return (TRUE);
+}
+
+int exec_lua(char *file)
+{
+ int oldtop = lua_gettop(L);
+ int res;
+
+ if (!lua_dostring(L, file))
+ {
+ int size = lua_gettop(L) - oldtop;
+ res = tolua_getnumber(L, -size, 0);
+ }
+ else
+ res = 0;
+
+ lua_settop(L, oldtop);
+ return (res);
+}
+
+cptr string_exec_lua(char *file)
+{
+ int oldtop = lua_gettop(L);
+ cptr res;
+
+ if (!lua_dostring(L, file))
+ {
+ int size = lua_gettop(L) - oldtop;
+ res = tolua_getstring(L, -size, "");
+ }
+ else
+ res = "";
+ lua_settop(L, oldtop);
+ return (res);
+}
+
+void dump_lua_stack(int min, int max)
+{
+ int i;
+
+ cmsg_print(TERM_YELLOW, "lua_stack:");
+ for (i = min; i <= max; i++)
+ {
+ if (lua_isnumber(L, i)) cmsg_format(TERM_YELLOW, "%d [n] = %d", i, tolua_getnumber(L, i, 0));
+ else if (lua_isstring(L, i)) cmsg_format(TERM_YELLOW, "%d [s] = '%s'", i, tolua_getstring(L, i, 0));
+ }
+ cmsg_print(TERM_YELLOW, "END lua_stack");
+}
+
+bool_ call_lua(cptr function, cptr args, cptr ret, ...)
+{
+ int i = 0, nb = 0, nbr = 0;
+ int oldtop = lua_gettop(L), size;
+ va_list ap;
+
+ va_start(ap, ret);
+
+ /* Push the function */
+ lua_getglobal(L, function);
+
+ /* Push and count the arguments */
+ while (args[i])
+ {
+ switch (args[i++])
+ {
+ case 'd':
+ case 'l':
+ tolua_pushnumber(L, va_arg(ap, s32b));
+ nb++;
+ break;
+ case 's':
+ tolua_pushstring(L, va_arg(ap, char*));
+ nb++;
+ break;
+ case 'O':
+ tolua_pushusertype(L, (void*)va_arg(ap, object_type*), tolua_tag(L, "object_type"));
+ nb++;
+ break;
+ case 'M':
+ tolua_pushusertype(L, (void*)va_arg(ap, monster_type*), tolua_tag(L, "monster_type"));
+ nb++;
+ break;
+ case 'n':
+ lua_pushnil(L);
+ nb++;
+ break;
+ case '(':
+ case ')':
+ case ',':
+ break;
+ }
+ }
+
+ /* Count returns */
+ nbr = strlen(ret);
+
+ /* Call the function */
+ if (lua_call(L, nb, nbr))
+ {
+ cmsg_format(TERM_VIOLET, "ERROR in lua_call while calling '%s' from call_lua. Things should start breaking up from now on!", function);
+ return FALSE;
+ }
+
+ /* Number of returned values, SHOULD be the same as nbr, but I'm paranoid */
+ size = lua_gettop(L) - oldtop;
+
+ /* Get the returns */
+ for (i = 0; ret[i]; i++)
+ {
+ switch (ret[i])
+ {
+ case 'd':
+ case 'l':
+ {
+ s32b *tmp = va_arg(ap, s32b*);
+
+ if (lua_isnumber(L, ( -size) + i)) *tmp = tolua_getnumber(L, ( -size) + i, 0);
+ else *tmp = 0;
+ break;
+ }
+
+ case 's':
+ {
+ cptr *tmp = va_arg(ap, cptr*);
+
+ if (lua_isstring(L, ( -size) + i)) *tmp = tolua_getstring(L, ( -size) + i, "");
+ else *tmp = NULL;
+ break;
+ }
+
+ case 'O':
+ {
+ object_type **tmp = va_arg(ap, object_type**);
+
+ if (tolua_istype(L, ( -size) + i, tolua_tag(L, "object_type"), 0))
+ *tmp = (object_type*)tolua_getuserdata(L, ( -size) + i, NULL);
+ else
+ *tmp = NULL;
+ break;
+ }
+
+ case 'M':
+ {
+ monster_type **tmp = va_arg(ap, monster_type**);
+
+ if (tolua_istype(L, ( -size) + i, tolua_tag(L, "monster_type"), 0))
+ *tmp = (monster_type*)tolua_getuserdata(L, ( -size) + i, NULL);
+ else
+ *tmp = NULL;
+ break;
+ }
+
+ default:
+ cmsg_format(TERM_VIOLET, "ERROR in lua_call while calling '%s' from call_lua: Unknown return type '%c'", function, ret[i]);
+ return FALSE;
+ }
+ }
+
+ lua_settop(L, oldtop);
+
+ va_end(ap);
+
+ return TRUE;
+}
+
+bool_ get_lua_var(cptr name, char type, void *arg)
+{
+ int oldtop = lua_gettop(L), size;
+
+ /* Push the function */
+ lua_getglobal(L, name);
+
+ size = lua_gettop(L) - oldtop;
+
+ switch (type)
+ {
+ case 'd':
+ case 'l':
+ {
+ s32b *tmp = (s32b*)arg;
+
+ if (lua_isnumber(L, ( -size))) *tmp = tolua_getnumber(L, ( -size), 0);
+ else *tmp = 0;
+ break;
+ }
+
+ case 's':
+ {
+ cptr *tmp = (cptr*)arg;
+
+ if (lua_isstring(L, ( -size))) *tmp = tolua_getstring(L, ( -size), "");
+ else *tmp = NULL;
+ break;
+ }
+
+ case 'O':
+ {
+ object_type **tmp = (object_type**)arg;
+
+ if (tolua_istype(L, ( -size), tolua_tag(L, "object_type"), 0))
+ *tmp = (object_type*)tolua_getuserdata(L, ( -size), NULL);
+ else
+ *tmp = NULL;
+ break;
+ }
+
+ case 'M':
+ {
+ monster_type **tmp = (monster_type**)arg;
+
+ if (tolua_istype(L, ( -size), tolua_tag(L, "monster_type"), 0))
+ *tmp = (monster_type*)tolua_getuserdata(L, ( -size), NULL);
+ else
+ *tmp = NULL;
+ break;
+ }
+
+ default:
+ cmsg_format(TERM_VIOLET, "ERROR in get_lua_var while calling '%s': Unknown return type '%c'", name, type);
+ return FALSE;
+ }
+
+ lua_settop(L, oldtop);
+
+ return TRUE;
+}
diff --git a/src/skills.c b/src/skills.c
new file mode 100644
index 00000000..36b4f585
--- /dev/null
+++ b/src/skills.c
@@ -0,0 +1,1661 @@
+/* File: skills.c */
+
+/* Purpose: player skills */
+
+/*
+ * Copyright (c) 2001 DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Advance the skill point of the skill specified by i and
+ * modify related skills
+ */
+void increase_skill(int i, s16b *invest)
+{
+ s32b max_skill_overage;
+
+ /* No skill points to be allocated */
+ if (!p_ptr->skill_points) return;
+
+ /* The skill cannot be increased */
+ if (!s_info[i].mod) return;
+
+ /* The skill is already maxed */
+ if (s_info[i].value >= SKILL_MAX) return;
+
+ /* Cannot allocate more than player level + max_skill_overage levels */
+ call_lua("get_module_info", "(s)", "d", "max_skill_overage", &max_skill_overage);
+ if (((s_info[i].value + s_info[i].mod) / SKILL_STEP) >= (p_ptr->lev + max_skill_overage + 1))
+ {
+ int hgt, wid;
+
+ Term_get_size(&wid, &hgt);
+ msg_box(format("Cannot raise a skill value above %i + player level.", max_skill_overage), (int)(hgt / 2), (int)(wid / 2));
+ return;
+ }
+
+ /* Spend an unallocated skill point */
+ p_ptr->skill_points--;
+
+ /* Increase the skill */
+ s_info[i].value += s_info[i].mod;
+ invest[i]++;
+}
+
+
+/*
+ * Descrease the skill point of the skill specified by i and
+ * modify related skills
+ */
+void decrease_skill(int i, s16b *invest)
+{
+ /* Cannot decrease more */
+ if (!invest[i]) return;
+
+ /* The skill cannot be decreased */
+ if (!s_info[i].mod) return;
+
+ /* The skill already has minimal value */
+ if (!s_info[i].value) return;
+
+ /* Free a skill point */
+ p_ptr->skill_points++;
+
+ /* Decrease the skill */
+ s_info[i].value -= s_info[i].mod;
+ invest[i]--;
+}
+
+
+/*
+ * Given the name of a skill, returns skill index or -1 if no
+ * such skill is found
+ */
+s16b find_skill(cptr name)
+{
+ u16b i;
+
+ /* Scan skill list */
+ for (i = 1; i < max_s_idx; i++)
+ {
+ /* The name matches */
+ if (streq(s_info[i].name + s_name, name)) return (i);
+ }
+
+ /* No match found */
+ return ( -1);
+}
+s16b find_skill_i(cptr name)
+{
+ u16b i;
+
+ /* Scan skill list */
+ for (i = 1; i < max_s_idx; i++)
+ {
+ /* The name matches */
+ if (0 == stricmp(s_info[i].name + s_name, name)) return (i);
+ }
+
+ /* No match found */
+ return ( -1);
+}
+
+
+/*
+ *
+ */
+s16b get_skill(int skill)
+{
+ return (s_info[skill].value / SKILL_STEP);
+}
+
+
+/*
+ * Return "scale" (a misnomer -- this is max value) * (current skill value)
+ * / (max skill value)
+ */
+s16b get_skill_scale(int skill, u32b scale)
+{
+ s32b temp;
+
+ /*
+ * SKILL_STEP shouldn't matter here because the second parameter is
+ * relatively small (the largest one being somewhere around 200),
+ * AND because we could have used much simpler 0--50 if the ability
+ * progression were only possible at step boundaries.
+ *
+ * Because I'm not at all certain about my interpretation of the mysterious
+ * formula given above, I verified this works the same by using a tiny
+ * scheme program... -- pelpel
+ */
+ temp = scale * s_info[skill].value;
+
+ return (temp / SKILL_MAX);
+}
+
+
+/*
+ *
+ */
+int get_idx(int i)
+{
+ int j;
+
+ for (j = 1; j < max_s_idx; j++)
+ {
+ if (s_info[j].order == i)
+ return (j);
+ }
+ return (0);
+}
+
+static bool_ is_known(int s_idx)
+{
+ int i;
+
+ if (wizard) return TRUE;
+ if (s_info[s_idx].value || s_info[s_idx].mod) return TRUE;
+
+ for (i = 0; i < max_s_idx; i++)
+ {
+ /* It is our child, if we don't know it we continue to search, if we know it it is enough*/
+ if (s_info[i].father == s_idx)
+ {
+ if (is_known(i))
+ return TRUE;
+ }
+ }
+
+ /* Ok know none */
+ return FALSE;
+}
+
+/*
+ *
+ */
+void init_table_aux(int table[MAX_SKILLS][2], int *idx, int father, int lev,
+ bool_ full)
+{
+ int j, i;
+
+ for (j = 1; j < max_s_idx; j++)
+ {
+ i = get_idx(j);
+ if (s_info[i].father != father) continue;
+ if (s_info[i].hidden) continue;
+ if (!is_known(i)) continue;
+
+ table[*idx][0] = i;
+ table[*idx][1] = lev;
+ (*idx)++;
+ if (s_info[i].dev || full) init_table_aux(table, idx, i, lev + 1, full);
+ }
+}
+
+
+void init_table(int table[MAX_SKILLS][2], int *max, bool_ full)
+{
+ *max = 0;
+ init_table_aux(table, max, -1, 0, full);
+}
+
+
+bool_ has_child(int sel)
+{
+ int i;
+
+ for (i = 1; i < max_s_idx; i++)
+ {
+ if ((s_info[i].father == sel) && (is_known(i)))
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+
+/*
+ * Dump the skill tree
+ */
+void dump_skills(FILE *fff)
+{
+ int i, j, max = 0;
+ int table[MAX_SKILLS][2];
+ char buf[80];
+
+ init_table(table, &max, TRUE);
+
+ fprintf(fff, "\nSkills (points left: %d)", p_ptr->skill_points);
+
+ for (j = 0; j < max; j++)
+ {
+ int z;
+
+ i = table[j][0];
+
+ if ((s_info[i].value == 0) && (i != SKILL_MISC))
+ {
+ if (s_info[i].mod == 0) continue;
+ }
+
+ sprintf(buf, "\n");
+
+ for (z = 0; z < table[j][1]; z++) strcat(buf, " ");
+
+ if (!has_child(i))
+ {
+ strcat(buf, format(" . %s", s_info[i].name + s_name));
+ }
+ else
+ {
+ strcat(buf, format(" - %s", s_info[i].name + s_name));
+ }
+
+ fprintf(fff, "%-49s%s%06.3f [%05.3f]",
+ buf, s_info[i].value < 0 ? "-" : " ",
+ ((double) ABS(s_info[i].value)) / SKILL_STEP,
+ ((double) s_info[i].mod) / 1000);
+ }
+
+ fprintf(fff, "\n");
+}
+
+
+/*
+ * Draw the skill tree
+ */
+void print_skills(int table[MAX_SKILLS][2], int max, int sel, int start)
+{
+ int i, j;
+ int wid, hgt;
+ cptr keys;
+
+ Term_clear();
+ Term_get_size(&wid, &hgt);
+
+ c_prt(TERM_WHITE, format("%s Skills Screen", game_module), 0, 28);
+ keys = format("#BEnter#W to develop a branch, #Bup#W/#Bdown#W to move, #Bright#W/#Bleft#W to modify, #B?#W for help");
+ display_message(0, 1, strlen(keys), TERM_WHITE, keys);
+ c_prt((p_ptr->skill_points) ? TERM_L_BLUE : TERM_L_RED,
+ format("Skill points left: %d", p_ptr->skill_points), 2, 0);
+ print_desc_aux(s_info[table[sel][0]].desc + s_text, 3, 0);
+
+ for (j = start; j < start + (hgt - 7); j++)
+ {
+ byte color = TERM_WHITE;
+ char deb = ' ', end = ' ';
+
+ if (j >= max) break;
+
+ i = table[j][0];
+
+ if ((s_info[i].value == 0) && (i != SKILL_MISC))
+ {
+ if (s_info[i].mod == 0) color = TERM_L_DARK;
+ else color = TERM_ORANGE;
+ }
+ else if (s_info[i].value == SKILL_MAX) color = TERM_L_BLUE;
+ if (s_info[i].hidden) color = TERM_L_RED;
+ if (j == sel)
+ {
+ color = TERM_L_GREEN;
+ deb = '[';
+ end = ']';
+ }
+ if (!has_child(i))
+ {
+ c_prt(color, format("%c.%c%s", deb, end, s_info[i].name + s_name),
+ j + 7 - start, table[j][1] * 4);
+ }
+ else if (s_info[i].dev)
+ {
+ c_prt(color, format("%c-%c%s", deb, end, s_info[i].name + s_name),
+ j + 7 - start, table[j][1] * 4);
+ }
+ else
+ {
+ c_prt(color, format("%c+%c%s", deb, end, s_info[i].name + s_name),
+ j + 7 - start, table[j][1] * 4);
+ }
+ c_prt(color,
+ format("%s%02ld.%03ld [%01d.%03d]",
+ s_info[i].value < 0 ? "-" : " ",
+ ABS(s_info[i].value) / SKILL_STEP,
+ ABS(s_info[i].value) % SKILL_STEP,
+ ABS(s_info[i].mod) / 1000,
+ ABS(s_info[i].mod) % 1000),
+ j + 7 - start, 60);
+ }
+}
+
+/*
+ * Checks various stuff to do when skills change, like new spells, ...
+ */
+void recalc_skills(bool_ init)
+{
+ static int thaum_level = 0;
+
+ /* TODO: This should be a hook in ToME's lua */
+ if (init)
+ {
+ thaum_level = get_skill_scale(SKILL_THAUMATURGY, 100);
+ }
+ else
+ {
+ int thaum_gain = 0;
+
+ /* Gain thaum spells */
+ while (thaum_level < get_skill_scale(SKILL_THAUMATURGY, 100))
+ {
+ if (spell_num == MAX_SPELLS) break;
+ thaum_level++;
+ generate_spell((thaum_level + 1) / 2);
+ thaum_gain++;
+ }
+ if (thaum_gain)
+ {
+ if (thaum_gain == 1)
+ msg_print("You have gained one new thaumaturgy spell.");
+ else
+ msg_format("You have gained %d new thaumaturgy spells.", thaum_gain);
+ }
+
+ process_hooks(HOOK_RECALC_SKILLS, "()");
+
+ /* Update stuffs */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_POWERS |
+ PU_SANITY | PU_BODY);
+
+ /* Redraw various info */
+ p_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP);
+ }
+}
+
+/*
+ * Recalc the skill value
+ */
+void recalc_skills_theory(s16b *invest, s32b *base_val, s32b *base_mod, s32b *bonus)
+{
+ int i, j;
+
+ /* First we assign the normal points */
+ for (i = 0; i < max_s_idx; i++)
+ {
+ /* Calc the base */
+ s_info[i].value = base_val[i] + (base_mod[i] * invest[i]) + bonus[i];
+
+ /* It cannot exceed SKILL_MAX */
+ if (s_info[i].value > SKILL_MAX) s_info[i].value = SKILL_MAX;
+ }
+
+ /* Then we modify related skills */
+ for (i = 0; i < max_s_idx; i++)
+ {
+ for (j = 1; j < max_s_idx; j++)
+ {
+ /* Ignore self */
+ if (j == i) continue;
+
+ /* Exclusive skills */
+ if ((s_info[i].action[j] == SKILL_EXCLUSIVE) && invest[i])
+ {
+ /* Turn it off */
+ p_ptr->skill_points += invest[j];
+ invest[j] = 0;
+ s_info[j].value = 0;
+ }
+
+ /* Non-exclusive skills */
+ else if (s_info[i].action[j])
+ {
+ /* Increase / decrease with a % */
+ s32b val = s_info[j].value + (invest[i] * s_info[j].mod * s_info[i].action[j] / 100);
+
+ /* It cannot exceed SKILL_MAX */
+ if (val > SKILL_MAX) val = SKILL_MAX;
+
+ /* Save the modified value */
+ s_info[j].value = val;
+ }
+ }
+ }
+}
+
+/*
+ * Interreact with skills
+ */
+void do_cmd_skill()
+{
+ int sel = 0, start = 0, max;
+ char c;
+ int table[MAX_SKILLS][2];
+ int i;
+ int wid, hgt;
+ s16b skill_points_save;
+ s32b *skill_values_save;
+ s32b *skill_mods_save;
+ s16b *skill_rates_save;
+ s16b *skill_invest;
+ s32b *skill_bonus;
+
+ recalc_skills(TRUE);
+
+ /* Save the screen */
+ screen_save();
+
+ /* Allocate arrays to save skill values */
+ C_MAKE(skill_values_save, MAX_SKILLS, s32b);
+ C_MAKE(skill_mods_save, MAX_SKILLS, s32b);
+ C_MAKE(skill_rates_save, MAX_SKILLS, s16b);
+ C_MAKE(skill_invest, MAX_SKILLS, s16b);
+ C_MAKE(skill_bonus, MAX_SKILLS, s32b);
+
+ /* Save skill points */
+ skill_points_save = p_ptr->skill_points;
+
+ /* Save skill values */
+ for (i = 0; i < max_s_idx; i++)
+ {
+ skill_type *s_ptr = &s_info[i];
+
+ skill_values_save[i] = s_ptr->value;
+ skill_mods_save[i] = s_ptr->mod;
+ skill_rates_save[i] = s_ptr->rate;
+ skill_invest[i] = 0;
+ }
+
+ /* Clear the screen */
+ Term_clear();
+
+ /* Initialise the skill list */
+ init_table(table, &max, FALSE);
+
+ while (TRUE)
+ {
+ Term_get_size(&wid, &hgt);
+
+ /* Display list of skills */
+ recalc_skills_theory(skill_invest, skill_values_save, skill_mods_save, skill_bonus);
+ print_skills(table, max, sel, start);
+
+ /* Wait for user input */
+ c = inkey();
+
+ /* Leave the skill screen */
+ if (c == ESCAPE) break;
+
+ /* Expand / collapse list of skills */
+ else if (c == '\r')
+ {
+ if (s_info[table[sel][0]].dev) s_info[table[sel][0]].dev = FALSE;
+ else s_info[table[sel][0]].dev = TRUE;
+ init_table(table, &max, FALSE);
+ }
+
+ /* Next page */
+ else if (c == 'n')
+ {
+ sel += (hgt - 7);
+ if (sel >= max) sel = max - 1;
+ }
+
+ /* Previous page */
+ else if (c == 'p')
+ {
+ sel -= (hgt - 7);
+ if (sel < 0) sel = 0;
+ }
+
+ /* Select / increase a skill */
+ else
+ {
+ int dir;
+
+ /* Allow use of numpad / arrow keys / roguelike keys */
+ dir = get_keymap_dir(c);
+
+ /* Move cursor down */
+ if (dir == 2) sel++;
+
+ /* Move cursor up */
+ if (dir == 8) sel--;
+
+ /* Miscellaneous skills cannot be increased/decreased as a group */
+ if (table[sel][0] == SKILL_MISC) continue;
+
+ /* Increase the current skill */
+ if (dir == 6) increase_skill(table[sel][0], skill_invest);
+
+ /* Decrease the current skill */
+ if (dir == 4) decrease_skill(table[sel][0], skill_invest);
+
+ /* XXX XXX XXX Wizard mode commands outside of wizard2.c */
+
+ /* Increase the skill */
+ if (wizard && (c == '+')) skill_bonus[table[sel][0]] += SKILL_STEP;
+
+ /* Decrease the skill */
+ if (wizard && (c == '-')) skill_bonus[table[sel][0]] -= SKILL_STEP;
+
+ /* Contextual help */
+ if (c == '?') exec_lua(format("ingame_help('select_context', 'skill', '%s')", s_info[table[sel][0]].name + s_name));
+ ;
+
+ /* Handle boundaries and scrolling */
+ if (sel < 0) sel = max - 1;
+ if (sel >= max) sel = 0;
+ if (sel < start) start = sel;
+ if (sel >= start + (hgt - 7)) start = sel - (hgt - 7) + 1;
+ }
+ }
+
+
+ /* Some skill points are spent */
+ if (p_ptr->skill_points != skill_points_save)
+ {
+ /* Flush input as we ask an important and irreversible question */
+ flush();
+
+ /* Ask we can commit the change */
+ if (msg_box("Save and use these skill values? (y/n)", (int)(hgt / 2), (int)(wid / 2)) != 'y')
+ {
+ /* User declines -- restore the skill values before exiting */
+
+ /* Restore skill points */
+ p_ptr->skill_points = skill_points_save;
+
+ /* Restore skill values */
+ for (i = 0; i < max_s_idx; i++)
+ {
+ skill_type *s_ptr = &s_info[i];
+
+ s_ptr->value = skill_values_save[i];
+ s_ptr->mod = skill_mods_save[i];
+ s_ptr->rate = skill_rates_save[i];
+ }
+ }
+ }
+
+
+ /* Free arrays to save skill values */
+ C_FREE(skill_values_save, MAX_SKILLS, s32b);
+ C_FREE(skill_mods_save, MAX_SKILLS, s32b);
+ C_FREE(skill_rates_save, MAX_SKILLS, s16b);
+ C_FREE(skill_invest, MAX_SKILLS, s16b);
+ C_FREE(skill_bonus, MAX_SKILLS, s32b);
+
+ /* Load the screen */
+ screen_load();
+
+ recalc_skills(FALSE);
+}
+
+
+
+/*
+ * List of melee skills
+ */
+s16b melee_skills[MAX_MELEE] =
+{
+ SKILL_MASTERY,
+ SKILL_HAND,
+ SKILL_BEAR,
+};
+char *melee_names[MAX_MELEE] =
+{
+ "Weapon combat",
+ "Barehanded combat",
+ "Bearform combat",
+};
+static bool_ melee_bool[MAX_MELEE];
+static int melee_num[MAX_MELEE];
+
+s16b get_melee_skill()
+{
+ int i;
+
+ for (i = 0; i < MAX_MELEE; i++)
+ {
+ if (p_ptr->melee_style == melee_skills[i])
+ return (i);
+ }
+ return (0);
+}
+
+s16b get_melee_skills()
+{
+ int i, j = 0;
+
+ for (i = 0; i < MAX_MELEE; i++)
+ {
+ if ((s_info[melee_skills[i]].value > 0) && (!s_info[melee_skills[i]].hidden))
+ {
+ melee_bool[i] = TRUE;
+ j++;
+ }
+ else
+ melee_bool[i] = FALSE;
+ }
+
+ return (j);
+}
+
+static void choose_melee()
+{
+ int i, j, z = 0;
+ int force_drop = FALSE, style_unchanged = FALSE;
+
+ character_icky = TRUE;
+ Term_save();
+ Term_clear();
+
+ j = get_melee_skills();
+ prt("Choose a melee style:", 0, 0);
+ for (i = 0; i < MAX_MELEE; i++)
+ {
+ if (melee_bool[i])
+ {
+ prt(format("%c) %s", I2A(z), melee_names[i]), z + 1, 0);
+ melee_num[z] = i;
+ z++;
+ }
+ }
+
+ while (TRUE)
+ {
+ char c = inkey();
+
+ if (c == ESCAPE) break;
+ if (A2I(c) < 0) continue;
+ if (A2I(c) >= j) continue;
+
+ for (i = 0, z = 0; z < A2I(c); i++)
+ if (melee_bool[i]) z++;
+
+ if (p_ptr->melee_style == melee_skills[melee_num[z]])
+ {
+ style_unchanged = TRUE;
+ break;
+ }
+
+ for (i = INVEN_WIELD; p_ptr->body_parts[i - INVEN_WIELD] == INVEN_WIELD; i++)
+ {
+ if (p_ptr->inventory[i].k_idx)
+ {
+ if (cursed_p(&p_ptr->inventory[i]))
+ {
+ char name[80];
+ object_desc(name, &p_ptr->inventory[i], 0, 0);
+ msg_format("Hmmm, your %s seems to be cursed.", name);
+ break;
+ }
+ else if (INVEN_PACK == inven_takeoff(i, 255, force_drop))
+ {
+ force_drop = TRUE;
+ }
+ }
+ }
+ p_ptr->melee_style = melee_skills[melee_num[z]];
+ energy_use = 100;
+ break;
+ }
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Recalculate hitpoint */
+ p_ptr->update |= (PU_HP);
+
+ /* Redraw monster hitpoint */
+ p_ptr->redraw |= (PR_MH);
+
+ Term_load();
+ character_icky = FALSE;
+
+ if (style_unchanged)
+ {
+ msg_format("You are already using %s.", melee_names[melee_num[z]]);
+ }
+}
+
+void select_default_melee()
+{
+ int i;
+
+ get_melee_skills();
+ p_ptr->melee_style = SKILL_MASTERY;
+ for (i = 0; i < MAX_MELEE; i++)
+ {
+ if (melee_bool[i])
+ {
+ p_ptr->melee_style = melee_skills[i];
+ break;
+ }
+ }
+}
+
+/*
+ * Print a batch of skills.
+ */
+static void print_skill_batch(int *p, cptr *p_desc, int start, int max, bool_ mode)
+{
+ char buff[80];
+ int i = start, j = 0;
+
+ if (mode) prt(format(" %-31s", "Name"), 1, 20);
+
+ for (i = start; i < (start + 20); i++)
+ {
+ if (i >= max) break;
+
+ if (p[i] > 0)
+ sprintf(buff, " %c - %d) %-30s", I2A(j), p[i], p_desc[i]);
+ else
+ sprintf(buff, " %c - %d) %-30s", I2A(j), p[i], "Change melee style");
+
+ if (mode) prt(buff, 2 + j, 20);
+ j++;
+ }
+ if (mode) prt("", 2 + j, 20);
+ prt(format("Select a skill (a-%c), @ to select by name, +/- to scroll:", I2A(j - 1)), 0, 0);
+}
+
+int do_cmd_activate_skill_aux()
+{
+ char which;
+ int max = 0, i, start = 0;
+ int ret;
+ bool_ mode = FALSE;
+ int *p;
+ cptr *p_desc;
+
+ C_MAKE(p, max_s_idx + max_ab_idx, int);
+ C_MAKE(p_desc, max_s_idx + max_ab_idx, cptr);
+
+ /* Count the max */
+
+ /* More than 1 melee skill ? */
+ if (get_melee_skills() > 1)
+ {
+ p_desc[max] = "Change melee mode";
+ p[max++] = 0;
+ }
+
+ for (i = 1; i < max_s_idx; i++)
+ {
+ if (s_info[i].action_mkey && s_info[i].value && ((!s_info[i].hidden) || (i == SKILL_LEARN)))
+ {
+ int j;
+ bool_ next = FALSE;
+
+ /* Already got it ? */
+ for (j = 0; j < max; j++)
+ {
+ if (s_info[i].action_mkey == p[j])
+ {
+ next = TRUE;
+ break;
+ }
+ }
+ if (next) continue;
+
+ p_desc[max] = s_text + s_info[i].action_desc;
+ p[max++] = s_info[i].action_mkey;
+ }
+ }
+
+ for (i = 0; i < max_ab_idx; i++)
+ {
+ if (ab_info[i].action_mkey && ab_info[i].acquired)
+ {
+ int j;
+ bool_ next = FALSE;
+
+ /* Already got it ? */
+ for (j = 0; j < max; j++)
+ {
+ if (ab_info[i].action_mkey == p[j])
+ {
+ next = TRUE;
+ break;
+ }
+ }
+ if (next) continue;
+
+ p_desc[max] = ab_text + ab_info[i].action_desc;
+ p[max++] = ab_info[i].action_mkey;
+ }
+ }
+
+ if (!max)
+ {
+ msg_print("You don't have any activable skills or abilities.");
+ return -1;
+ }
+
+ character_icky = TRUE;
+ Term_save();
+
+ while (1)
+ {
+ print_skill_batch(p, p_desc, start, max, mode);
+ which = inkey();
+
+ if (which == ESCAPE)
+ {
+ ret = -1;
+ break;
+ }
+ else if (which == '*' || which == '?' || which == ' ')
+ {
+ mode = (mode) ? FALSE : TRUE;
+ Term_load();
+ character_icky = FALSE;
+ }
+ else if (which == '+')
+ {
+ start += 20;
+ if (start >= max) start -= 20;
+ Term_load();
+ character_icky = FALSE;
+ }
+ else if (which == '-')
+ {
+ start -= 20;
+ if (start < 0) start += 20;
+ Term_load();
+ character_icky = FALSE;
+ }
+ else if (which == '@')
+ {
+ char buf[80];
+
+ strcpy(buf, "Cast a spell");
+ if (!get_string("Skill action? ", buf, 79))
+ return FALSE;
+
+ /* Find the skill it is related to */
+ for (i = 0; i < max; i++)
+ {
+ if (!strcmp(buf, p_desc[i]))
+ break;
+ }
+ if ((i < max))
+ {
+ ret = p[i];
+ break;
+ }
+
+ }
+ else
+ {
+ which = tolower(which);
+ if (start + A2I(which) >= max)
+ {
+ bell();
+ continue;
+ }
+ if (start + A2I(which) < 0)
+ {
+ bell();
+ continue;
+ }
+
+ ret = p[start + A2I(which)];
+ break;
+ }
+ }
+ Term_load();
+ character_icky = FALSE;
+
+ C_FREE(p, max_s_idx + max_ab_idx, int);
+ C_FREE(p_desc, max_s_idx + max_ab_idx, cptr);
+
+ return ret;
+}
+
+/* Ask & execute a skill */
+void do_cmd_activate_skill()
+{
+ int x_idx;
+ bool_ push = TRUE;
+
+ /* Get the skill, if available */
+ if (repeat_pull(&x_idx))
+ {
+ push = FALSE;
+ }
+ else if (!command_arg) x_idx = do_cmd_activate_skill_aux();
+ else
+ {
+ int i, j;
+
+ x_idx = command_arg;
+
+ /* Check validity */
+ for (i = 1; i < max_s_idx; i++)
+ {
+ if (s_info[i].value && (s_info[i].action_mkey == x_idx))
+ break;
+ }
+ for (j = 0; j < max_ab_idx; j++)
+ {
+ if (ab_info[j].acquired && (ab_info[j].action_mkey == x_idx))
+ break;
+ }
+
+ if ((j == max_ab_idx) && (i == max_s_idx))
+ {
+ msg_print("Uh?");
+ return;
+ }
+ }
+
+ if (x_idx == -1) return;
+
+ if (push) repeat_push(x_idx);
+
+ if (!x_idx)
+ {
+ choose_melee();
+ return;
+ }
+
+ /* Break goi/manashield */
+ if (p_ptr->invuln)
+ {
+ set_invuln(0);
+ }
+ if (p_ptr->disrupt_shield)
+ {
+ set_disrupt_shield(0);
+ }
+
+ switch (x_idx)
+ {
+ case MKEY_ANTIMAGIC:
+ do_cmd_unbeliever();
+ break;
+ case MKEY_MINDCRAFT:
+ do_cmd_mindcraft();
+ break;
+ case MKEY_ALCHEMY:
+ do_cmd_alchemist();
+ break;
+ case MKEY_MIMIC:
+ do_cmd_mimic();
+ break;
+ case MKEY_POWER_MAGE:
+ do_cmd_powermage();
+ break;
+ case MKEY_RUNE:
+ do_cmd_runecrafter();
+ break;
+ case MKEY_FORGING:
+ do_cmd_archer();
+ break;
+ case MKEY_INCARNATION:
+ do_cmd_possessor();
+ break;
+ case MKEY_TELEKINESIS:
+ do_cmd_portable_hole();
+ break;
+ case MKEY_BLADE:
+ do_cmd_blade();
+ break;
+ case MKEY_SUMMON:
+ do_cmd_summoner();
+ break;
+ case MKEY_NECRO:
+ do_cmd_necromancer();
+ break;
+ case MKEY_SYMBIOTIC:
+ do_cmd_symbiotic();
+ break;
+ case MKEY_TRAP:
+ do_cmd_set_trap();
+ break;
+ case MKEY_STEAL:
+ do_cmd_steal();
+ break;
+ case MKEY_DODGE:
+ use_ability_blade();
+ break;
+ case MKEY_SCHOOL:
+ cast_school_spell();
+ break;
+ case MKEY_COPY:
+ do_cmd_copy_spell();
+ break;
+ case MKEY_BOULDER:
+ do_cmd_create_boulder();
+ break;
+ case MKEY_COMPANION:
+ if (get_skill(SKILL_LORE) >= 12)
+ do_cmd_companion();
+ else
+ msg_print("You need a skill level of at least 12.");
+ break;
+ case MKEY_PIERCING:
+ do_cmd_set_piercing();
+ break;
+ default:
+ process_hooks(HOOK_MKEY, "(d)", x_idx);
+ break;
+ }
+}
+
+
+/* Which magic forbids non FA gloves */
+bool_ forbid_gloves()
+{
+ if (get_skill(SKILL_SORCERY)) return (TRUE);
+ if (get_skill(SKILL_MANA)) return (TRUE);
+ if (get_skill(SKILL_FIRE)) return (TRUE);
+ if (get_skill(SKILL_AIR)) return (TRUE);
+ if (get_skill(SKILL_WATER)) return (TRUE);
+ if (get_skill(SKILL_EARTH)) return (TRUE);
+ if (get_skill(SKILL_THAUMATURGY)) return (TRUE);
+ return (FALSE);
+}
+
+/* Which gods forbid edged weapons */
+bool_ forbid_non_blessed()
+{
+ GOD(GOD_ERU) return (TRUE);
+ return (FALSE);
+}
+
+
+/*
+ * Gets the base value of a skill, given a race/class/...
+ */
+void compute_skills(s32b *v, s32b *m, int i)
+{
+ s32b value, mod;
+
+ /***** general skills *****/
+
+ /* If the skill correspond to the magic school lets pump them a bit */
+ value = gen_skill_base[i];
+ mod = gen_skill_mod[i];
+
+ *v = modify_aux(*v,
+ value, gen_skill_basem[i]);
+ *m = modify_aux(*m,
+ mod, gen_skill_modm[i]);
+
+ /***** race skills *****/
+
+ value = rp_ptr->skill_base[i];
+ mod = rp_ptr->skill_mod[i];
+
+ *v = modify_aux(*v,
+ value, rp_ptr->skill_basem[i]);
+ *m = modify_aux(*m,
+ mod, rp_ptr->skill_modm[i]);
+
+ /***** race mod skills *****/
+
+ value = rmp_ptr->skill_base[i];
+ mod = rmp_ptr->skill_mod[i];
+
+ *v = modify_aux(*v,
+ value, rmp_ptr->skill_basem[i]);
+ *m = modify_aux(*m,
+ mod, rmp_ptr->skill_modm[i]);
+
+ /***** class skills *****/
+
+ value = cp_ptr->skill_base[i];
+ mod = cp_ptr->skill_mod[i];
+
+ *v = modify_aux(*v,
+ value, cp_ptr->skill_basem[i]);
+ *m = modify_aux(*m,
+ mod, cp_ptr->skill_modm[i]);
+
+ /***** class spec skills *****/
+
+ value = spp_ptr->skill_base[i];
+ mod = spp_ptr->skill_mod[i];
+
+ *v = modify_aux(*v,
+ value, spp_ptr->skill_basem[i]);
+ *m = modify_aux(*m,
+ mod, spp_ptr->skill_modm[i]);
+}
+
+/*
+ * Initialize a skill with given values
+ */
+void init_skill(s32b value, s32b mod, int i)
+{
+ s_info[i].value = value;
+ s_info[i].mod = mod;
+
+ if (s_info[i].flags1 & SKF1_HIDDEN)
+ s_info[i].hidden = TRUE;
+ else
+ s_info[i].hidden = FALSE;
+}
+
+void do_get_new_skill()
+{
+ char *items[LOST_SWORD_NSKILLS];
+ int skl[LOST_SWORD_NSKILLS];
+ s32b val[LOST_SWORD_NSKILLS], mod[LOST_SWORD_NSKILLS];
+ bool_ used[MAX_SKILLS];
+ int available_skills[MAX_SKILLS];
+ int max = 0, max_a = 0, res, i;
+
+ /* Check if some skills didn't influence other stuff */
+ recalc_skills(TRUE);
+
+ /* Grab the ones we can gain */
+ max = 0;
+ for (i = 0; i < max_s_idx; i++)
+ {
+ if (s_info[i].flags1 & SKF1_RANDOM_GAIN)
+ available_skills[max++] = i;
+ }
+ available_skills[max++] = -1;
+
+ /* Init */
+ for (max = 0; max < MAX_SKILLS; max++)
+ {
+ used[max] = FALSE;
+ }
+
+ /* Count the number of available skills */
+ while (available_skills[max_a] != -1) max_a++;
+
+ /* Get LOST_SWORD_NSKILLS skills */
+ for (max = 0; max < LOST_SWORD_NSKILLS; max++)
+ {
+ int i;
+ skill_type *s_ptr;
+
+ /* Get an non used skill */
+ do
+ {
+ i = rand_int(max_a);
+
+ /* Does it pass the check? */
+ if (!magik(s_info[available_skills[i]].random_gain_chance))
+ continue;
+ }
+ while (used[available_skills[i]]);
+
+ s_ptr = &s_info[available_skills[i]];
+ used[available_skills[i]] = TRUE;
+
+ if (s_ptr->mod)
+ {
+ if (s_ptr->mod < 300)
+ {
+ val[max] = 1000;
+ mod[max] = 300 - s_ptr->mod;
+ }
+ else if (s_ptr->mod < 500)
+ {
+ val[max] = s_ptr->mod * 1;
+ mod[max] = 100;
+ if (mod[max] + s_ptr->mod > 500)
+ mod[max] = 500 - s_ptr->mod;
+ }
+ else
+ {
+ val[max] = s_ptr->mod * 3;
+ mod[max] = 0;
+ }
+ }
+ else
+ {
+ mod[max] = 300;
+ val[max] = 1000;
+ }
+ if (s_ptr->value + val[max] > SKILL_MAX) val[max] = SKILL_MAX - s_ptr->value;
+ skl[max] = available_skills[i];
+ items[max] = (char *)string_make(format("%-40s: +%02ld.%03ld value, +%01d.%03d modifier", s_ptr->name + s_name, val[max] / SKILL_STEP, val[max] % SKILL_STEP, mod[max] / SKILL_STEP, mod[max] % SKILL_STEP));
+ }
+
+ while (TRUE)
+ {
+ char last = 'a' + (LOST_SWORD_NSKILLS-1);
+ char buf[80];
+ sprintf(buf, "Choose a skill to learn(a-%c to choose, ESC to cancel)?", last);
+ res = ask_menu(buf, (char **)items, LOST_SWORD_NSKILLS);
+
+ /* Ok ? lets learn ! */
+ if (res > -1)
+ {
+ skill_type *s_ptr;
+ bool_ oppose = FALSE;
+ int oppose_skill = -1;
+
+ /* Check we don't oppose an existing skill */
+ for (i = 0; i < max_s_idx; i++)
+ {
+ if ((s_info[i].action[skl[res]] == SKILL_EXCLUSIVE) &&
+ (s_info[i].value != 0))
+ {
+ oppose = TRUE;
+ oppose_skill = i;
+ break;
+ }
+ }
+
+ /* Ok we oppose, so be sure */
+ if (oppose)
+ {
+ cptr msg;
+
+ /*
+ * Because this is SO critical a question, we must flush
+ * input to prevent killing character off -- pelpel
+ */
+ flush();
+
+ /* Prepare prompt */
+ msg = format("This skill is mutually exclusive with "
+ "at least %s, continue?",
+ s_info[oppose_skill].name + s_name);
+
+ /* The player rejected the choice */
+ if (!get_check(msg)) continue;
+ }
+
+ s_ptr = &s_info[skl[res]];
+ s_ptr->value += val[res];
+ s_ptr->mod += mod[res];
+ if (mod[res])
+ {
+ msg_format("You can now learn the %s skill.",
+ s_ptr->name + s_name);
+ }
+ else
+ {
+ msg_format("Your knowledge of the %s skill increases.",
+ s_ptr->name + s_name);
+ }
+ break;
+ }
+ }
+
+ /* Free them ! */
+ for (max = 0; max < LOST_SWORD_NSKILLS; max++)
+ {
+ string_free(items[max]);
+ }
+
+ /* Check if some skills didn't influence other stuff */
+ recalc_skills(FALSE);
+}
+
+
+
+
+/**************************************** ABILITIES *****************************************/
+
+/*
+ * Given the name of an ability, returns ability index or -1 if no
+ * such ability is found
+ */
+s16b find_ability(cptr name)
+{
+ u16b i;
+
+ /* Scan ability list */
+ for (i = 0; i < max_ab_idx; i++)
+ {
+ /* The name matches */
+ if (streq(ab_info[i].name + ab_name, name)) return (i);
+ }
+
+ /* No match found */
+ return ( -1);
+}
+
+/*
+ * Do the player have the ability
+ */
+bool_ has_ability(int ab)
+{
+ return ab_info[ab].acquired;
+}
+
+/* Do we meet the requirements */
+bool_ can_learn_ability(int ab)
+{
+ ability_type *ab_ptr = &ab_info[ab];
+ int i;
+
+ if (ab_ptr->acquired)
+ return FALSE;
+
+ if (p_ptr->skill_points < ab_info[ab].cost)
+ return FALSE;
+
+ for (i = 0; i < 10; i++)
+ {
+ /* Must have skill level */
+ if (ab_ptr->skills[i] > -1)
+ {
+ if (get_skill(ab_ptr->skills[i]) < ab_ptr->skill_levels[i])
+ return FALSE;
+ }
+
+ /* Must have ability */
+ if (ab_ptr->need_abilities[i] > -1)
+ {
+ if (!ab_info[ab_ptr->need_abilities[i]].acquired)
+ return FALSE;
+ }
+
+ /* Must not have ability */
+ if (ab_ptr->forbid_abilities[i] > -1)
+ {
+ if (ab_info[ab_ptr->forbid_abilities[i]].acquired)
+ return FALSE;
+ }
+ }
+
+ for (i = 0; i < 6; i++)
+ {
+ /* Must have stat */
+ if (ab_ptr->stat[i] > -1)
+ {
+ if (p_ptr->stat_ind[i] < ab_ptr->stat[i] - 3)
+ return FALSE;
+ }
+ }
+
+ /* Do the script allow us? */
+ if (process_hooks(HOOK_LEARN_ABILITY, "(d)", ab))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Learn an ability */
+void gain_ability(int ab)
+{
+ int wid, hgt;
+ Term_get_size(&wid, &hgt);
+
+ if (!can_learn_ability(ab))
+ {
+ msg_box("You cannot learn this ability.", (int)(hgt / 2), (int)(wid / 2));
+ return;
+ }
+
+ /* Flush input as we ask an important and irreversible question */
+ flush();
+
+ /* Ask we can commit the change */
+ if (msg_box("Learn this ability(this is permanent)? (y/n)", (int)(hgt / 2), (int)(wid / 2)) != 'y')
+ {
+ return;
+ }
+
+ ab_info[ab].acquired = TRUE;
+ p_ptr->skill_points -= ab_info[ab].cost;
+}
+
+/* helper function to generate a sorted table */
+static void add_sorted_ability(int *table, int *max, int ab)
+{
+ int i;
+
+ for (i = 0; i < *max; i++)
+ {
+ if (strcmp(ab_name + ab_info[ab].name, ab_name + ab_info[table[i]].name) < 0)
+ {
+ int z;
+
+ /* Move all indexes up */
+ for (z = *max; z > i; z--)
+ {
+ table[z] = table[z - 1];
+ }
+ break;
+ }
+ }
+ table[i] = ab;
+
+ (*max)++;
+}
+
+/*
+ * Print the abilities list
+ */
+void dump_abilities(FILE *fff)
+{
+ int i, j;
+ int *table;
+ int max = 0;
+
+ C_MAKE(table, max_ab_idx, int);
+
+ /* Initialise the abilities list */
+ for (i = 0; i < max_ab_idx; i++)
+ {
+ if (ab_info[i].name && has_ability(i))
+ add_sorted_ability(table, &max, i);
+ }
+
+ if (max)
+ {
+ fprintf(fff, "\nAbilities");
+
+ for (j = 0; j < max; j++)
+ {
+ i = table[j];
+
+ fprintf(fff, "\n * %s", ab_info[i].name + ab_name);
+ }
+
+ fprintf(fff, "\n");
+ }
+}
+
+/*
+ * Draw the abilities list
+ */
+void print_abilities(int table[], int max, int sel, int start)
+{
+ int i, j;
+ int wid, hgt;
+ cptr keys;
+
+ Term_clear();
+ Term_get_size(&wid, &hgt);
+
+ c_prt(TERM_WHITE, format("%s Abilities Screen", game_module), 0, 28);
+ keys = format("#Bup#W/#Bdown#W to move, #Bright#W to buy, #B?#W for help");
+ display_message(0, 1, strlen(keys), TERM_WHITE, keys);
+ c_prt((p_ptr->skill_points) ? TERM_L_BLUE : TERM_L_RED,
+ format("Skill points left: %d", p_ptr->skill_points), 2, 0);
+
+ print_desc_aux(ab_info[table[sel]].desc + ab_text, 3, 0);
+
+ for (j = start; j < start + (hgt - 7); j++)
+ {
+ byte color = TERM_WHITE;
+ char deb = ' ', end = ' ';
+
+ if (j >= max) break;
+
+ i = table[j];
+
+ if (ab_info[i].acquired)
+ color = TERM_L_BLUE;
+ else if (can_learn_ability(i))
+ color = TERM_WHITE;
+ else
+ color = TERM_L_DARK;
+
+
+ if (j == sel)
+ {
+ color = TERM_L_GREEN;
+ deb = '[';
+ end = ']';
+ }
+
+ c_prt(color, format("%c.%c%s", deb, end, ab_info[i].name + ab_name),
+ j + 7 - start, 0);
+
+ if (!ab_info[i].acquired)
+ {
+ c_prt(color, format("%d", ab_info[i].cost), j + 7 - start, 60);
+ }
+ else
+ {
+ c_prt(color, "Known", j + 7 - start, 60);
+ }
+ }
+}
+
+/*
+ * Interreact with abilitiess
+ */
+void do_cmd_ability()
+{
+ int sel = 0, start = 0, max = 0;
+ char c;
+ int *table;
+ int i;
+ int wid, hgt;
+
+ C_MAKE(table, max_ab_idx, int);
+
+ /* Save the screen */
+ screen_save();
+
+ /* Clear the screen */
+ Term_clear();
+
+ /* Initialise the abilities list */
+ for (i = 0; i < max_ab_idx; i++)
+ {
+if (ab_info[i].name)
+ add_sorted_ability(table, &max, i);
+ }
+
+ while (TRUE)
+ {
+ Term_get_size(&wid, &hgt);
+
+ /* Display list of skills */
+ print_abilities(table, max, sel, start);
+
+ /* Wait for user input */
+ c = inkey();
+
+ /* Leave the skill screen */
+ if (c == ESCAPE) break;
+
+ /* Next page */
+ else if (c == 'n')
+ {
+ sel += (hgt - 7);
+ if (sel >= max) sel = max - 1;
+ }
+
+ /* Previous page */
+ else if (c == 'p')
+ {
+ sel -= (hgt - 7);
+ if (sel < 0) sel = 0;
+ }
+
+ /* Select / increase a skill */
+ else
+ {
+ int dir;
+
+ /* Allow use of numpad / arrow keys / roguelike keys */
+ dir = get_keymap_dir(c);
+
+ /* Move cursor down */
+ if (dir == 2) sel++;
+
+ /* Move cursor up */
+ if (dir == 8) sel--;
+
+ /* gain ability */
+ if (dir == 6) gain_ability(table[sel]);
+
+ /* XXX XXX XXX Wizard mode commands outside of wizard2.c */
+
+ if (wizard && (c == '+')) ab_info[table[sel]].acquired = TRUE;
+ if (wizard && (c == '-')) ab_info[table[sel]].acquired = FALSE;
+
+ /* Contextual help */
+ if (c == '?') exec_lua(format("ingame_help('select_context', 'ability', '%s')", ab_info[table[sel]].name + ab_name));
+ ;
+
+ /* Handle boundaries and scrolling */
+ if (sel < 0) sel = max - 1;
+ if (sel >= max) sel = 0;
+ if (sel < start) start = sel;
+ if (sel >= start + (hgt - 7)) start = sel - (hgt - 7) + 1;
+ }
+ }
+
+ /* Load the screen */
+ screen_load();
+
+ C_FREE(table, max_ab_idx, int);
+
+ /* Update stuffs */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_POWERS |
+ PU_SANITY | PU_BODY);
+
+ /* Redraw various info */
+ p_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP);
+}
+
+/*
+ * Apply abilities to be granted this level
+ */
+void apply_level_abilities(int level)
+{
+ int i;
+
+ for (i = 0; i < 10; i++)
+ {
+ if (cp_ptr->abilities[i].level == level)
+ {
+ if ((level > 1) && (!ab_info[cp_ptr->abilities[i].ability].acquired))
+ cmsg_format(TERM_L_GREEN, "You have learned the ability '%s'.", ab_name + ab_info[cp_ptr->abilities[i].ability].name);
+ ab_info[cp_ptr->abilities[i].ability].acquired = TRUE;
+ }
+ if (spp_ptr->abilities[i].level == level)
+ {
+ if ((level > 1) && (!ab_info[spp_ptr->abilities[i].ability].acquired))
+ cmsg_format(TERM_L_GREEN, "You have learned the ability '%s'.", ab_name + ab_info[spp_ptr->abilities[i].ability].name);
+ ab_info[spp_ptr->abilities[i].ability].acquired = TRUE;
+ }
+ if (rp_ptr->abilities[i].level == level)
+ {
+ if ((level > 1) && (!ab_info[rp_ptr->abilities[i].ability].acquired))
+ cmsg_format(TERM_L_GREEN, "You have learned the ability '%s'.", ab_name + ab_info[rp_ptr->abilities[i].ability].name);
+ ab_info[rp_ptr->abilities[i].ability].acquired = TRUE;
+ }
+ if (rmp_ptr->abilities[i].level == level)
+ {
+ if ((level > 1) && (!ab_info[rmp_ptr->abilities[i].ability].acquired))
+ cmsg_format(TERM_L_GREEN, "You have learned the ability '%s'.", ab_name + ab_info[rmp_ptr->abilities[i].ability].name);
+ ab_info[rmp_ptr->abilities[i].ability].acquired = TRUE;
+ }
+ }
+}
diff --git a/src/spells.pkg b/src/spells.pkg
new file mode 100644
index 00000000..e785de0d
--- /dev/null
+++ b/src/spells.pkg
@@ -0,0 +1,2448 @@
+/* File: spells.pkg */
+
+/*
+ * Purpose: Lua interface defitions for spells.
+ * To be processed by tolua to generate C source code.
+ */
+
+$#include "angband.h"
+$#include "lua.h"
+
+/** @typedef *mcptr
+ * @note String
+ */
+typedef char *mcptr;
+
+/** @typedef cptr
+ * @note String
+ */
+typedef const char* cptr;
+
+/** @typedef errr
+ * @note Number
+ */
+typedef int errr;
+
+/** @typedef bool
+ * @note Boolean
+ */
+typedef unsigned char bool;
+
+/** @typedef byte
+ * @note Number
+ */
+typedef unsigned char byte;
+
+/** @typedef s16b
+ * @note Number
+ */
+typedef signed short s16b;
+
+/** @typedef u16b
+ * @note Number
+ */
+typedef unsigned short u16b;
+
+/** @typedef s32b
+ * @note Number
+ */
+typedef signed int s32b;
+
+/** @typedef u32b
+ * @note Number
+ */
+typedef unsigned int u32b;
+
+/** @def DEFAULT_RADIUS */
+#define DEFAULT_RADIUS 25
+
+/** @name Spell Damage Types
+ * @brief Type of damage caused by spell
+ * @{ */
+/** @def GF_ELEC */
+#define GF_ELEC 1
+
+/** @def GF_POIS */
+#define GF_POIS 2
+
+/** @def GF_ACID */
+#define GF_ACID 3
+
+/** @def GF_COLD */
+#define GF_COLD 4
+
+/** @def GF_FIRE */
+#define GF_FIRE 5
+
+/** @def GF_UNBREATH */
+#define GF_UNBREATH 6
+
+/** @def GF_CORPSE_EXPL */
+#define GF_CORPSE_EXPL 7
+
+/** @def GF_MISSILE */
+#define GF_MISSILE 10
+
+/** @def GF_ARROW */
+#define GF_ARROW 11
+
+/** @def GF_PLASMA */
+#define GF_PLASMA 12
+
+/** @def GF_WAVE */
+#define GF_WAVE 13
+
+/** @def GF_WATER */
+#define GF_WATER 14
+
+/** @def GF_LITE */
+#define GF_LITE 15
+
+/** @def GF_DARK */
+#define GF_DARK 16
+
+/** @def GF_LITE_WEAK */
+#define GF_LITE_WEAK 17
+
+/** @def GF_DARK_WEAK */
+#define GF_DARK_WEAK 18
+
+/** @def GF_SHARDS */
+#define GF_SHARDS 20
+
+/** @def GF_SOUND */
+#define GF_SOUND 21
+
+/** @def GF_CONFUSION */
+#define GF_CONFUSION 22
+
+/** @def GF_FORCE */
+#define GF_FORCE 23
+
+/** @def GF_INERTIA */
+#define GF_INERTIA 24
+
+/** @def GF_MANA */
+#define GF_MANA 26
+
+/** @def GF_METEOR */
+#define GF_METEOR 27
+
+/** @def GF_ICE */
+#define GF_ICE 28
+
+/** @def GF_CHAOS */
+#define GF_CHAOS 30
+
+/** @def GF_NETHER */
+#define GF_NETHER 31
+
+/** @def GF_DISENCHANT */
+#define GF_DISENCHANT 32
+
+/** @def GF_NEXUS */
+#define GF_NEXUS 33
+
+/** @def GF_TIME */
+#define GF_TIME 34
+
+/** @def GF_GRAVITY */
+#define GF_GRAVITY 35
+
+/** @def GF_KILL_WALL */
+#define GF_KILL_WALL 40
+
+/** @def GF_KILL_DOOR */
+#define GF_KILL_DOOR 41
+
+/** @def GF_KILL_TRAP */
+#define GF_KILL_TRAP 42
+
+/** @def GF_MAKE_WALL */
+#define GF_MAKE_WALL 45
+
+/** @def GF_MAKE_DOOR */
+#define GF_MAKE_DOOR 46
+
+/** @def GF_MAKE_TRAP */
+#define GF_MAKE_TRAP 47
+
+/** @def GF_OLD_CLONE */
+#define GF_OLD_CLONE 51
+
+/** @def GF_OLD_POLY */
+#define GF_OLD_POLY 52
+
+/** @def GF_OLD_HEAL */
+#define GF_OLD_HEAL 53
+
+/** @def GF_OLD_SPEED */
+#define GF_OLD_SPEED 54
+
+/** @def GF_OLD_SLOW */
+#define GF_OLD_SLOW 55
+
+/** @def GF_OLD_CONF */
+#define GF_OLD_CONF 56
+
+/** @def GF_OLD_SLEEP */
+#define GF_OLD_SLEEP 57
+
+/** @def GF_OLD_DRAIN */
+#define GF_OLD_DRAIN 58
+
+/** @def GF_AWAY_UNDEAD */
+#define GF_AWAY_UNDEAD 61
+
+/** @def GF_AWAY_EVIL */
+#define GF_AWAY_EVIL 62
+
+/** @def GF_AWAY_ALL */
+#define GF_AWAY_ALL 63
+
+/** @def GF_TURN_UNDEAD */
+#define GF_TURN_UNDEAD 64
+
+/** @def GF_TURN_EVIL */
+#define GF_TURN_EVIL 65
+
+/** @def GF_TURN_ALL */
+#define GF_TURN_ALL 66
+
+/** @def GF_DISP_UNDEAD */
+#define GF_DISP_UNDEAD 67
+
+/** @def GF_DISP_EVIL */
+#define GF_DISP_EVIL 68
+
+/** @def GF_DISP_ALL */
+#define GF_DISP_ALL 69
+
+/* New types for Zangband begin here... */
+
+/** @def GF_DISP_DEMON */
+#define GF_DISP_DEMON 70
+
+/** @def GF_DISP_LIVING */
+#define GF_DISP_LIVING 71
+
+/** @def GF_ROCKET */
+#define GF_ROCKET 72
+
+/** @def GF_NUKE */
+#define GF_NUKE 73
+
+/** @def GF_MAKE_GLYPH */
+#define GF_MAKE_GLYPH 74
+
+/** @def GF_STASIS */
+#define GF_STASIS 75
+
+/** @def GF_STONE_WALL */
+#define GF_STONE_WALL 76
+
+/** @def GF_DEATH_RAY */
+#define GF_DEATH_RAY 77
+
+/** @def GF_STUN */
+#define GF_STUN 78
+
+/** @def GF_HOLY_FIRE */
+#define GF_HOLY_FIRE 79
+
+/** @def GF_HELL_FIRE */
+#define GF_HELL_FIRE 80
+
+/** @def GF_DISINTEGRATE */
+#define GF_DISINTEGRATE 81
+
+/** @def GF_CHARM */
+#define GF_CHARM 82
+
+/** @def GF_CONTROL_UNDEAD */
+#define GF_CONTROL_UNDEAD 83
+
+/** @def GF_CONTROL_ANIMAL */
+#define GF_CONTROL_ANIMAL 84
+
+/** @def GF_PSI */
+#define GF_PSI 85
+
+/** @def GF_PSI_DRAIN */
+#define GF_PSI_DRAIN 86
+
+/** @def GF_TELEKINESIS */
+#define GF_TELEKINESIS 87
+
+/** @def GF_JAM_DOOR */
+#define GF_JAM_DOOR 88
+
+/** @def GF_DOMINATION */
+#define GF_DOMINATION 89
+
+/** @def GF_DISP_GOOD */
+#define GF_DISP_GOOD 90
+
+/** @def GF_IDENTIFY */
+#define GF_IDENTIFY 91
+
+/** @def GF_RAISE */
+#define GF_RAISE 92
+
+/** @def GF_STAR_IDENTIFY */
+#define GF_STAR_IDENTIFY 93
+
+/** @def GF_DESTRUCTION */
+#define GF_DESTRUCTION 94
+
+/** @def GF_STUN_CONF */
+#define GF_STUN_CONF 95
+
+/** @def GF_STUN_DAM */
+#define GF_STUN_DAM 96
+
+/** @def GF_CONF_DAM */
+#define GF_CONF_DAM 98
+
+/** @def GF_STAR_CHARM */
+#define GF_STAR_CHARM 99
+
+/** @def GF_IMPLOSION */
+#define GF_IMPLOSION 100
+
+/** @def GF_LAVA_FLOW */
+#define GF_LAVA_FLOW 101
+
+/** @def GF_FEAR */
+#define GF_FEAR 102
+
+/** @def GF_BETWEEN_GATE */
+#define GF_BETWEEN_GATE 103
+
+/** @def GF_WINDS_MANA */
+#define GF_WINDS_MANA 104
+
+/** @def GF_DEATH */
+#define GF_DEATH 105
+
+/** @def GF_CONTROL_DEMON */
+#define GF_CONTROL_DEMON 106
+
+/** @def GF_RAISE_DEMON */
+#define GF_RAISE_DEMON 107
+
+/** @def GF_TRAP_DEMONSOUL */
+#define GF_TRAP_DEMONSOUL 108
+
+/** @def GF_ATTACK */
+#define GF_ATTACK 109
+
+/** @def GF_CHARM_UNMOVING */
+#define GF_CHARM_UNMOVING 110
+
+/** @def MAX_GF */
+#define MAX_GF 111
+/** @} */
+
+/** @name Spell Projection Flags
+ * @brief Area affected by spell
+ * @{ */
+/** @def PROJECT_JUMP
+ * @note Jump directly to the target location (this is a hack)
+ */
+#define PROJECT_JUMP 0x00000001
+
+/** @def PROJECT_BEAM
+ * @note Work as a beam weapon (affect every grid passed through)
+ */
+#define PROJECT_BEAM 0x00000002
+
+/** @def PROJECT_THRU
+ * @note Continue "through" the target (used for "bolts"/"beams")
+ */
+#define PROJECT_THRU 0x00000004
+
+/** @def PROJECT_STOP
+ * @note Stop as soon as we hit a monster (used for "bolts")
+ */
+#define PROJECT_STOP 0x00000008
+
+/** @def PROJECT_GRID
+ * @note Affect each grid in the "blast area" in some way
+ */
+#define PROJECT_GRID 0x00000010
+
+/** @def PROJECT_ITEM
+ * @note Affect each object in the "blast area" in some way
+ */
+#define PROJECT_ITEM 0x00000020
+
+/** @def PROJECT_KILL
+ * @note Affect each monster in the "blast area" in some way
+ */
+#define PROJECT_KILL 0x00000040
+
+/** @def PROJECT_HIDE
+ * @note Hack -- disable "visual" feedback from projection
+ */
+#define PROJECT_HIDE 0x00000080
+
+/** @def PROJECT_VIEWABLE
+ * @note Affect monsters in LOS
+ */
+#define PROJECT_VIEWABLE 0x00000100
+
+/** @def PROJECT_METEOR_SHOWER
+ * @note Affect random grids
+ */
+#define PROJECT_METEOR_SHOWER 0x00000200
+
+/** @def PROJECT_BLAST
+ * @note Like Mega_blast, but will only affect viewable grids
+ */
+#define PROJECT_BLAST 0x00000400
+
+/** @def PROJECT_PANEL
+ * @note Affect everything in the panel.
+ */
+#define PROJECT_PANEL 0x00000800
+
+/** @def PROJECT_ALL
+ * @note Affect every single grid.
+ */
+#define PROJECT_ALL 0x00001000
+
+/** @def PROJECT_WALL
+ * @note Continue "through" the walls
+ */
+#define PROJECT_WALL 0x00002000
+
+/** @def PROJECT_MANA_PATH
+ * @note Follow a mana path.
+ */
+#define PROJECT_MANA_PATH 0x00004000
+
+/** @def PROJECT_ABSORB_MANA
+ * @note The spell increase in power as it absord grid's mana.
+ */
+#define PROJECT_ABSORB_MANA 0x00008000
+
+/** @def PROJECT_STAY */
+#define PROJECT_STAY 0x00010000
+/** @} */
+
+/** @var project_time
+ * @brief Number
+ * @note The length of time a spell effect exists.
+ */
+extern int project_time;
+
+/** @fn teleport_player_directed(int rad, int dir)
+ * @brief Teleport a player up to "rad" grids away roughly in "dir"
+ * direction.\n
+ * @param rad Number \n rad must not exceed 200. The distance teleported is
+ * at least a quarter of rad.
+ * @brief Distance
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @note
+ * Teleport player, using a distance and a direction as a rough guide.\n\n
+ * This function is not at all obsessive about correctness.\n
+ * This function allows teleporting into vaults (!)
+ * @note (see file spells1.c)
+ */
+extern void teleport_player_directed(int rad, int dir);
+
+/** @fn teleport_away(int m_idx, int dis)
+ * @brief Teleport monster indicated by "m_idx" up to "dis" grids away.\n
+ * @param m_idx Number \n m_idx is the index of the monster in m_list[].
+ * @brief Monster index
+ * @param dis Number \n dis must not exceed 200. The distance teleported
+ * is a minimum of a quarter of "dis".
+ * @brief Distance
+ * @note
+ * Teleport a monster, normally up to "dis" grids away.\n\n
+ * Attempt to move the monster at least "dis/2" grids away.\n\n
+ * But allow variation to prevent infinite loops.
+ * @note (see file spells1.c)
+ */
+extern void teleport_away(int m_idx, int dis);
+
+/** @fn teleport_player(int dis)
+ * @brief Teleport player up to "dis" grids away.\n
+ * @param dis Number \n dis must not exceed 200. The distance teleported
+ * is a minimum of a quarter of dis.
+ * @brief Distance
+ * @note
+ * Teleport the player to a location up to "dis" grids away.\n\n
+ * If no such spaces are readily available, the distance may increase.\n
+ * Try very hard to move the player at least a quarter that distance.
+ * @note (see file spells1.c)
+ */
+extern void teleport_player(int dis);
+
+/** @fn teleport_player_to(int ny, int nx)
+ * @brief Teleport player to a grid near coordinate ("ny", "nx").\n
+ * @param ny Number \n ny is the y co-ordinate of the location.
+ * @brief Y coordinate
+ * @param nx Number \n nx is the x co-ordinate of the location.
+ * @brief X coordinate
+ * @note
+ * Teleport player to a grid near the given location\n\n
+ * This function is slightly obsessive about correctness.\n
+ * This function allows teleporting into vaults (!)\n\n
+ * If the location is empty, the player goes there, otherwise they go to
+ * a grid as close as possible to the location.
+ * @note (see file spells1.c)
+ */
+extern void teleport_player_to(int ny, int nx);
+
+/** @fn teleport_monster_to(int m_idx, int ny, int nx)
+ * @brief Teleport monster indicated by "m_idx" to a grid near coordinate
+ * ("ny", "nx").\n
+ * @param m_idx Number \n m_idx is the index of the monster in m_list[].
+ * @brief Monster index
+ * @param ny Number \n ny is the y co-ordinate of the location.
+ * @brief Y coordinate
+ * @param nx Number \n nx is the x co-ordinate of the location.
+ * @brief X coordinate
+ * @note
+ * Teleport a monster to a grid near the given location\n\n
+ * This function is slightly obsessive about correctness.\n\n
+ * If the location is empty, the monster goes there, otherwise they go to
+ * a grid as close as possible to the location.
+ * @note (see file spells1.c)
+ */
+extern void teleport_monster_to(int m_idx, int ny, int nx);
+
+/** @fn teleport_monster(int dir)
+ * @brief Teleport away all monsters in direction "dir".\n
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * All monsters in direction "dir" are teleported away and sustain
+ * MAX_SIGHT (20) x 5 damage.\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".
+ * @note (see file spells2.c)
+ */
+extern bool teleport_monster(int dir);
+
+/** @fn teleport_player_level(void)
+ * @brief Teleport the player one level up or down at random.
+ * @note
+ * Teleport the player one level up or down (random when legal)
+ * @note (see file spells1.c)
+ */
+extern void teleport_player_level(void);
+
+/** @fn fetch(int dir, int wgt, bool require_los)
+ * @brief Fetch an item in direction "dir" with weight "wgt" possibly not in
+ * line of sight.\n
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param wgt Number \n maximum weight of object.
+ * @brief Weight
+ * @param require_los Boolean \n TRUE if line of sight is required, otherwise
+ * FALSE.
+ * @brief Require-line-of-sight flag
+ * @note
+ * Fetch an item (teleport it right underneath the caster)\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".
+ * Fetch will fail if player is standing on something, or if the object is
+ * too far away, or if require_los is TRUE and player does not have line
+ * of sight to the object, or the object is too heavy. Otherwise the
+ * object appears at the player's feet (same grid as player).
+ * @note (see file cmd5.c)
+ */
+extern void fetch(int dir, int wgt, bool require_los);
+
+/** @fn recall_player(int d, int f)
+ * @brief Recall the player to town (if in dungeon) or dungeon (if in town).\n
+ * @param d Number \n Random time interval
+ * @brief Dice
+ * @param f Number \n Fixed time interval
+ * @brief Fixed
+ * @note (see file spells1.c)
+ */
+extern void recall_player(int d, int f);
+
+/** @fn take_hit(int damage, cptr kb_str)
+ * @brief Reduce player hit points by "damage" inflicted by "kb_str".\n
+ * @param damage Number \n damage is the number of hit points of damage.
+ * @brief Damage
+ * @param kb_str String \n kb_str describes what killed the player
+ * (in the event the player dies)
+ * @brief Killed by
+ * @note
+ * Decreases players hit points and sets death flag if necessary\n\n
+ * XXX XXX XXX Invulnerability needs to be changed into a "shield"\n\n
+ * XXX XXX XXX Hack -- this function allows the user to save (or quit)
+ * the game when he dies, since the "You die." message is shown before
+ * setting the player to "dead".
+ * @note (see file spells1.c)
+ */
+extern void take_hit(int damage, cptr kb_str);
+
+/** @fn take_sanity_hit(int damage, cptr hit_from)
+ * @brief Reduce player sanity points by "damage" inflicted by "hit_from".\n
+ * @param damage Number \n damage is the number of sanity points of damage.
+ * @brief Damage
+ * @param hit_from String \n hit_from describes what caused the damage.
+ * @brief Hit from
+ * @note
+ * Decrease player's sanity. This is a copy of the function above.\n\n
+ * Reduce the player's current sanity points by "damage" points. If the
+ * player dies, "hit_from" is used to record what the player was killed
+ * by (see high-score table).
+ * @note (see file spells1.c)
+ */
+extern void take_sanity_hit(int damage, cptr hit_from);
+
+/** @fn project(int who, int rad, int y, int x, int dam, int typ, int flg)
+ * @brief Generate a beam/bolt/ball with properties "flg" starting from "who"
+ * with a radius of "rad" at target grid "y,x" for "dam" points of "typ"
+ * damage.\n
+ * @param who Number \n who is > 0 (index of monster in m_list[]), < 0 and
+ * not -100 or -101 (player), -100 or -101 (trap).
+ * @brief Source
+ * @param rad Number \n rad is 0 for a beam/bolt and 1-9 for a ball.
+ * @brief Radius
+ * @param y Number \n y is the y coordinate of the target grid.
+ * @brief Y-coordinate
+ * @param x Number \n x is the x co-ordinate of the target grid.
+ * @brief X-coordinate
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param flg Number \n flg is the projection effect (PROJECT field).
+ * @brief Properties flag
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Generic "beam"/"bolt"/"ball" projection routine.\n\n
+ * Input:\n
+ * who: Index of "source" monster (negative for "player")\n
+ * jk -- -2 for traps, only used with project_jump\n
+ * rad: Radius of explosion (0 = beam/bolt, 1 to 9 = ball)\n
+ * y,x: Target location (or location to travel "towards")\n
+ * dam: Base damage roll to apply to affected monsters (or player)\n
+ * typ: Type of damage to apply to monsters (and objects)\n
+ * flg: Extra bit flags (see PROJECT_xxxx in "defines.h")\n\n
+ * Return:\n
+ * TRUE if any "effects" of the projection were observed, else FALSE\n\n
+ * Allows a monster (or player) to project a beam/bolt/ball of a given kind
+ * towards a given location (optionally passing over the heads of interposing
+ * monsters), and have it do a given amount of damage to the monsters (and
+ * optionally objects) within the given radius of the final location.\n\n
+ * A "bolt" travels from source to target and affects only the target grid.\n
+ * A "beam" travels from source to target, affecting all grids passed through.\n
+ * A "ball" travels from source to the target, exploding at the target, and
+ * affecting everything within the given radius of the target location.\n\n
+ * Traditionally, a "bolt" does not affect anything on the ground, and does
+ * not pass over the heads of interposing monsters, much like a traditional
+ * missile, and will "stop" abruptly at the "target" even if no monster is
+ * positioned there, while a "ball", on the other hand, passes over the heads
+ * of monsters between the source and target, and affects everything except
+ * the source monster which lies within the final radius, while a "beam"
+ * affects every monster between the source and target, except for the casting
+ * monster (or player), and rarely affects things on the ground.\n\n
+ * Two special flags allow us to use this function in special ways, the
+ * "PROJECT_HIDE" flag allows us to perform "invisible" projections, while
+ * the "PROJECT_JUMP" flag allows us to affect a specific grid, without
+ * actually projecting from the source monster (or player).\n\n
+ * The player will only get "experience" for monsters killed by himself
+ * Unique monsters can only be destroyed by attacks from the player\n\n
+ * Only 256 grids can be affected per projection, limiting the effective
+ * "radius" of standard ball attacks to nine units (diameter nineteen).\n\n
+ * One can project in a given "direction" by combining PROJECT_THRU with small
+ * offsets to the initial location (see "line_spell()"), or by calculating
+ * "virtual targets" far away from the player.\n\n
+ * One can also use PROJECT_THRU to send a beam/bolt along an angled path,
+ * continuing until it actually hits something (useful for "stone to mud").\n\n
+ * Bolts and Beams explode INSIDE walls, so that they can destroy doors.\n\n
+ * Balls must explode BEFORE hitting walls, or they would affect monsters
+ * on both sides of a wall. Some bug reports indicate that this is still
+ * happening in 2.7.8 for Windows, though it appears to be impossible.\n\n
+ * We "pre-calculate" the blast area only in part for efficiency.
+ * More importantly, this lets us do "explosions" from the "inside" out.
+ * This results in a more logical distribution of "blast" treasure.
+ * It also produces a better (in my opinion) animation of the explosion.
+ * It could be (but is not) used to have the treasure dropped by monsters
+ * in the middle of the explosion fall "outwards", and then be damaged by
+ * the blast as it spreads outwards towards the treasure drop location.\n\n
+ * Walls and doors are included in the blast area, so that they can be
+ * "burned" or "melted" in later versions.\n\n
+ * This algorithm is intended to maximise simplicity, not necessarily
+ * efficiency, since this function is not a bottleneck in the code.\n\n
+ * We apply the blast effect from ground zero outwards, in several passes,
+ * first affecting features, then objects, then monsters, then the player.
+ * This allows walls to be removed before checking the object or monster
+ * in the wall, and protects objects which are dropped by monsters killed
+ * in the blast, and allows the player to see all affects before he is
+ * killed or teleported away. The semantics of this method are open to
+ * various interpretations, but they seem to work well in practice.\n\n
+ * We process the blast area from ground-zero outwards to allow for better
+ * distribution of treasure dropped by monsters, and because it provides a
+ * pleasing visual effect at low cost.\n\n
+ * Note that the damage done by "ball" explosions decreases with distance.
+ * This decrease is rapid, grids at radius "dist" take "1/dist" damage.\n\n
+ * Notice the "napalm" effect of "beam" weapons. First they "project" to
+ * the target, and then the damage "flows" along this beam of destruction.
+ * The damage at every grid is the same as at the "centre" of a "ball"
+ * explosion, since the "beam" grids are treated as if they ARE at the
+ * centre of a "ball" explosion.\n\n
+ * Currently, specifying "beam" plus "ball" means that locations which are
+ * covered by the initial "beam", and also covered by the final "ball", except
+ * for the final grid (the epicentre of the ball), will be "hit twice", once
+ * by the initial beam, and once by the exploding ball. For the grid right
+ * next to the epicentre, this results in 150% damage being done. The centre
+ * does not have this problem, for the same reason the final grid in a "beam"
+ * plus "bolt" does not -- it is explicitly removed. Simply removing "beam"
+ * grids which are covered by the "ball" will NOT work, as then they will
+ * receive LESS damage than they should. Do not combine "beam" with "ball".\n\n
+ * The array "gy[],gx[]" with current size "grids" is used to hold the
+ * collected locations of all grids in the "blast area" plus "beam path".\n\n
+ * Note the rather complex usage of the "gm[]" array. First, gm[0] is always
+ * zero. Second, for N>1, gm[N] is always the index (in gy[],gx[]) of the
+ * first blast grid (see above) with radius "N" from the blast centre. Note
+ * that only the first gm[1] grids in the blast area thus take full damage.
+ * Also, note that gm[rad+1] is always equal to "grids", which is the total
+ * number of blast grids.\n\n
+ * Note that once the projection is complete, (y2,x2) holds the final location
+ * of bolts/beams, and the "epicentre" of balls.\n\n
+ * Note also that "rad" specifies the "inclusive" radius of projection blast,
+ * so that a "rad" of "one" actually covers 5 or 9 grids, depending on the
+ * implementation of the "distance" function. Also, a bolt can be properly
+ * viewed as a "ball" with a "rad" of "zero".\n\n
+ * Note that if no "target" is reached before the beam/bolt/ball travels the
+ * maximum distance allowed (MAX_RANGE), no "blast" will be induced. This
+ * may be relevant even for bolts, since they have a "1x1" mini-blast.\n\n
+ * Note that for consistency, we "pretend" that the bolt actually takes "time"
+ * to move from point A to point B, even if the player cannot see part of the
+ * projection path. Note that in general, the player will *always* see part
+ * of the path, since it either starts at the player or ends on the player.\n\n
+ * Hack -- we assume that every "projection" is "self-illuminating".\n\n
+ * Hack -- when only a single monster is affected, we automatically track
+ * (and recall) that monster, unless "PROJECT_JUMP" is used.\n\n
+ * Note that all projections now "explode" at their final destination, even
+ * if they were being projected at a more distant destination. This means
+ * that "ball" spells will *always* explode.\n\n
+ * Note that we must call "handle_stuff()" after affecting terrain features
+ * in the blast radius, in case the "illumination" of the grid was changed,
+ * and "update_view()" and "update_monsters()" need to be called.
+ * @note (see file spells1.c)
+ */
+extern bool project(int who, int rad, int y, int x, int dam, int typ, int flg);
+
+/** @fn corrupt_player(void)
+ * @brief Swap two of the player's stats at random.
+ * @note (see file spells1.c)
+ */
+extern void corrupt_player(void);
+
+/** @fn grow_things(s16b type, int rad)
+ * @brief Grow "type" things within "rad" distance of the player.\n
+ * @param type Number \n type of thing to grow (FEAT field).
+ * @brief Type
+ * @param rad Number \n rad is the radius of the area where things may grow.
+ * @brief Radius
+ * @note
+ * Grow things\n\n
+ * Up to (rad * (rad + 11)) things can be grown around the player. The
+ * grids must support growth.
+ * @note (see file spells2.c)
+ */
+extern void grow_things(s16b type, int rad);
+
+/** @fn grow_grass(int rad)
+ * @brief Grow grass within "rad" distance of the player.\n
+ * @param rad Number \n rad is the radius of the area where grass may grow.
+ * @brief Radius
+ * @note
+ * Grow grass\n\n
+ * Up to (rad * (rad + 11)) grass can be grown around the player. The
+ * grids must support growth.
+ * @note (see file spells2.c)
+ */
+extern void grow_grass(int rad);
+
+/** @fn grow_trees(int rad)
+ * @brief Grow trees within "rad" distance of the player.\n
+ * @param rad Number \n rad is the radius of the area where trees may grow.
+ * @brief Radius
+ * @note
+ * Grow trees\n\n
+ * Up to (rad * (rad + 11)) trees can be grown around the player. The
+ * grids must support growth.
+ * @note (see file spells2.c)
+ */
+extern void grow_trees(int rad);
+
+/** @fn hp_player(int num)
+ * @brief Add "num" points to the player's current hit points.\n
+ * @param num Number \n num is the number of points to add.
+ * @brief Number
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Increase players hit points, notice effects\n\n
+ * The total can not exceed the maximum.
+ * @note (see file spells2.c)
+ */
+extern bool hp_player(int num);
+
+/** @fn heal_insanity(int val)
+ * @brief Add "val" points to the player's current sanity points.\n
+ * @param val Number \n val is the number of points to add.
+ * @brief Value
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Heal insanity.\n\n
+ * The total can not exceed the maximum.
+ * @note (see file spells2.c)
+ */
+extern bool heal_insanity(int val);
+
+/** @fn warding_glyph(void)
+ * @brief Place a glyph at the player's location.
+ * @note
+ * Leave a "glyph of warding" which prevents monster movement\n\n
+ * The location must be bare.
+ * @note (see file spells2.c)
+ */
+extern void warding_glyph(void);
+
+/** @fn explosive_rune(void)
+ * @brief Place a minor glyph (explosive rune) at the player's location.
+ * @note
+ * The location must be bare.
+ * @note (see file spells2.c)
+ */
+extern void explosive_rune(void);
+
+/** @fn do_dec_stat(int stat, int mode)
+ * @brief Attempt to reduce the player's "stat" statistic by a point.\n
+ * @param stat Number \n stat is the statistic
+ * @brief Statistic
+ * @param mode Number \n mode is the type of decrease: temporary, normal,
+ * or permanent
+ * @brief Mode
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Lose a "point"
+ * @note (see file spells2.c)
+ */
+extern bool do_dec_stat(int stat, int mode);
+
+/** @fn do_res_stat(int stat, bool full)
+ * @brief Restore the player's "stat" statistic.\n
+ * @param stat Number \n stat is the statistic.
+ * @brief Statistic
+ * @param full Boolean \n TRUE if full restore is required, otherwise FALSE.
+ * @brief Full restore flag
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Restore lost "points" in a stat
+ * @note (see file spells2.c)
+ */
+extern bool do_res_stat(int stat, bool full);
+
+/** @fn do_inc_stat(int stat)
+ * @brief Increase the player's "stat" statistic by a point.\n
+ * @param stat Number \n stat is the statistic.
+ * @brief Statistic
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Gain a "point" in a stat
+ * @note (see file spells2.c)
+ */
+extern bool do_inc_stat(int stat);
+
+/** @fn identify_pack(void)
+ * @brief Identify all items in the inventory.
+ * @note
+ * Identify everything being carried.\n
+ * Done by a potion of "self knowledge".
+ * @note (see file spells2.c)
+ */
+extern void identify_pack(void);
+
+/** @fn remove_curse(void)
+ * @brief Remove all curses except for heavy curses.
+ * @return Boolean \n TRUE if at least one item was uncursed, otherwise FALSE.
+ * @note
+ * Remove most curses\n\n
+ * There is a 1 in (55 - level) chance of reversing the curse effects for
+ * items which are not artifacts. For example, a Ring of Damage (-15) will
+ * become a Ring of Damage (+15).
+ * @note (see file spells2.c)
+ */
+extern bool remove_curse(void);
+
+/** @fn remove_all_curse(void)
+ * @brief Remove all curses including heavy curses.
+ * @return Boolean \n TRUE if at least one item was uncursed, otherwise FALSE.
+ * @note
+ * Remove all curses\n\n
+ * There is a 1 in (55 - level) chance of reversing the curse effects for
+ * items which are not artifacts. For example, a Ring of Damage (-15) will
+ * become a Ring of Damage (+15).
+ * @note (see file spells2.c)
+ */
+extern bool remove_all_curse(void);
+
+/** @fn restore_level(void)
+ * @brief Restore all drained experience points (if any).
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Restores any drained experience
+ * @note (see file spells2.c)
+ */
+extern bool restore_level(void);
+
+/** @fn self_knowledge(FILE *fff=NULL)
+ * @brief Show all attributes including racial powers, mutations, and
+ * equipment effects.\n
+ * @param *fff FILE \n write info to screen if fff is NULL,
+ * otherwise write info to file fff.
+ * @brief Output file
+ * @note
+ * self-knowledge... idea from nethack. Useful for determining powers and
+ * resistances of items. It saves the screen, clears it, then starts listing
+ * attributes, a screenful at a time. (There are a LOT of attributes to
+ * list. It will probably take 2 or 3 screens for a powerful character whose
+ * using several artifacts...) -CFT\n\n
+ * It is now a lot more efficient. -BEN-\n\n
+ * See also "identify_fully()".\n\n
+ * XXX XXX XXX Use the "show_file()" method, perhaps.
+ * @note (see file spells2.c)
+ */
+extern void self_knowledge(FILE *fff=NULL);
+
+/** @fn lose_all_info(void)
+ * @brief Forget about objects and the map.
+ * @return Boolean \n TRUE (always).
+ * @note
+ * Forget everything
+ * @note (see file spells2.c)
+ */
+extern bool lose_all_info(void);
+
+/** @fn detect_traps(int rad)
+ * @brief Detect all traps within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE (always).
+ * @note
+ * All grids within the radius are searched.\n
+ * A message is displayed if traps are detected.
+ * @note (see file spells2.c)
+ */
+extern bool detect_traps(int rad);
+
+/** @fn detect_doors(int rad)
+ * @brief Detect all doors within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if doors were detected, otherwise FALSE.
+ * @note
+ * All grids within the radius are searched.\n
+ * A message is displayed if doors are detected.
+ * @note (see file spells2.c)
+ */
+extern bool detect_doors(int rad);
+
+/** @fn detect_stairs(int rad)
+ * @brief Detect all exits within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if exits were detected, otherwise FALSE.
+ * @note
+ * All grids within the radius are searched.\n
+ * A message is displayed if exits are detected. Exits can be stairs,
+ * shafts, and ways out.
+ * @note (see file spells2.c)
+ */
+extern bool detect_stairs(int rad);
+
+/** @fn detect_treasure(int rad)
+ * @brief Detect all buried treasure within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if buried treasure was detected, otherwise FALSE.
+ * @note
+ * All grids within the radius are searched.\n
+ * A message is displayed if buried treasure is detected. Treasure can be
+ * buried in magma, quartz, or sandwall.
+ * @note (see file spells2.c)
+ */
+extern bool detect_treasure(int rad);
+
+/** @var hack_no_detect_message
+ * @brief Boolean
+ * @note Suppress messages generated by "detect" spells?
+ */
+extern bool hack_no_detect_message;
+
+/** @fn detect_objects_gold(int rad)
+ * @brief Detect all gold within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if gold was detected, otherwise FALSE.
+ * @note
+ * All grids within the radius are searched.\n
+ * A message is displayed if gold is detected. Gold can be coins or mimics.
+ * Monsters of type "$" are detected but not shown or reported.
+ * @note (see file spells2.c)
+ */
+extern bool detect_objects_gold(int rad);
+
+/** @fn detect_objects_normal(int rad)
+ * @brief Detect all normal (not gold) items within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if normal items were detected, otherwise FALSE.
+ * @note
+ * All grids within the radius are searched.\n
+ * A message is displayed if normal items are detected. Items include mimics.
+ * Monsters of type "!=?|" are detected but not shown or reported.
+ * @note (see file spells2.c)
+ */
+extern bool detect_objects_normal(int rad);
+
+/** @fn detect_objects_magic(int rad)
+ * @brief Detect all magic (not gold) items within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if magic items were detected, otherwise FALSE.
+ * @note
+ * This will light up all spaces with "magic" items, including artifacts,
+ * ego-items, potions, scrolls, books, rods, wands, staves, amulets, rings,
+ * and "enchanted" items of the "good" variety.\n\n
+ * It can probably be argued that this function is now too powerful.\n\n
+ * All grids within the radius are searched.\n
+ * A message is displayed if magic items are detected. Items include mimics.
+ * @note (see file spells2.c)
+ */
+extern bool detect_objects_magic(int rad);
+
+/** @fn detect_monsters_normal(int rad)
+ * @brief Detect all non-invisible monsters within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if non-invisible monsters were detected,
+ * otherwise FALSE.
+ * @note
+ * A non-invisible monster is one which is visible, or one which is invisible
+ * but the player can see invisible monsters.
+ * @note (see file spells2.c)
+ */
+extern bool detect_monsters_normal(int rad);
+
+/** @fn detect_monsters_invis(int rad)
+ * @brief Detect all invisible monsters within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if invisible monsters were detected,
+ * otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool detect_monsters_invis(int rad);
+
+/** @fn detect_monsters_evil(int rad)
+ * @brief Detect all evil monsters within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if evil monsters were detected, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool detect_monsters_evil(int rad);
+
+/** @fn detect_monsters_good(int rad)
+ * @brief Detect all good monsters within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if good monsters were detected, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool detect_monsters_good(int rad);
+
+/** @fn detect_monsters_xxx(u32b match_flag, int rad)
+ * @brief Detect all monsters with flag "match_flag" within radius "rad" of the
+ * player.\n
+ * @param match_flag Number \n match_flag is the type of monster. It must be
+ * a RF3_ flag (see defines.h).
+ * @brief Match flag
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if monsters were detected, otherwise FALSE.
+ * @note
+ * A "generic" detect monsters routine, tagged to flags3\n\n
+ * This routine will work with ANY RF3 flag, but messages will only be
+ * printed if the following monsters are detected: demon, undead, good.
+ * @note (see file spells2.c)
+ */
+extern bool detect_monsters_xxx(u32b match_flag, int rad);
+
+/** @fn detect_monsters_string(cptr chars, int rad)
+ * @brief Detect all monsters whose monster symbol is in "chars" within
+ * radius "rad" of the player.\n
+ * @param chars String \n chars is the string of monster types. For
+ * available characters, see the "symbol" field of the graphics (G)
+ * line of r_info.txt.
+ * @brief Symbols
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if monsters were detected, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool detect_monsters_string(cptr chars, int rad);
+
+/** @fn detect_monsters_nonliving(int rad)
+ * @brief Detect all nonliving monsters within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if nonliving monsters were detected,
+ * otherwise FALSE.
+ * @note
+ * Detect all "nonliving", "undead" or "demonic" monsters on current panel\n\n
+ * Nonliving monsters are either RF3_NONLIVING, RF3_UNDEAD, or RF3_DEMON.
+ * @note (see file spells2.c)
+ */
+extern bool detect_monsters_nonliving(int rad);
+
+/** @fn detect_all(int rad)
+ * @brief Detect everything within radius "rad" of the player.\n
+ * @param rad Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @return Boolean \n TRUE if something was detected, otherwise FALSE.
+ * @note
+ * Detect everything\n\n
+ * Detects traps, doors, stairs, treasure, gold objects, normal objects,
+ * invisible monsters, non-invisible monsters.
+ */
+extern bool detect_all(int rad);
+
+/** @fn stair_creation(void)
+ * @brief Create stairs at the player location
+ * @note
+ * This is not allowed if the grid is not empty, the player is not in a
+ * dungeon, the player is on a special level, the player is in an arena
+ * or quest. If the player is in the town or wilderness the stairs will
+ * go down. If the player is on a quest level or at the bottom of a
+ * dungeon, the stairs will go up. Otherwise there is an even chance the
+ * stairs will go up or down.
+ */
+extern void stair_creation(void);
+
+/** @fn tgt_pt (int *x=0, int *y=0)
+ * @brief Set a target point\n
+ * @param *x Number
+ * @brief X-coordinate
+ * @param *y Number
+ * @brief Y-coordinate
+ * @return *x Number \n X-coordinate of target.
+ * @return *y Number \n Y-coordinate of target.
+ * @return Boolean \n True if a target was selected, otherwise FALSE.
+ * @note
+ * Allow the user to move the cursor around the screen to select a target.
+ * The user must press the space key to set the target.
+ * @note (see file xtra2.c)
+ */
+extern bool tgt_pt (int *x=0, int *y=0);
+
+/** @fn wall_stone(int y, int x)
+ * @brief Create a stone wall at dungeon grid ("y", "x").\n
+ * @param y Number \n Y-coordinate of dungeon grid.
+ * @brief Y-coordinate
+ * @param x Number \n X-coordinate of dungeon grid.
+ * @brief X-coordinate
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool wall_stone(int y, int x);
+
+/** @fn create_artifact(object_type *o_ptr, bool a_scroll, bool get_name)
+ * @brief Create an artifact from object "o_ptr".\n
+ * @param *o_ptr object_type \n object to become an artifact
+ * @brief Object
+ * @param a_scroll Boolean \n Is a scroll used to create the artifact?\n
+ * TRUE if the artifact is created by reading a scroll.
+ * @brief Use scroll?
+ * @param get_name Boolean \n Get a name for the artifact?\n
+ * TRUE if the artifact is to be named by the player (if a_scroll is true) or
+ * created randomly (a_scroll is false), or FALSE if an inscription is used.
+ * @brief Get name?
+ * @return *o_ptr object_type \n The artifact.
+ * @return Boolean \n TRUE (always).
+ * @note (see file randart.c)
+ */
+extern bool create_artifact(object_type *o_ptr, bool a_scroll, bool get_name);
+
+/** @fn wall_to_mud(int dir)
+ * @brief Cast a wall-to-mud spell in direction "dir".\n
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".
+ * @note (see file spells2.c)
+ */
+extern bool wall_to_mud(int dir);
+
+/** @fn ident_spell(void)
+ * @brief Identify an object in the inventory (or on the floor).
+ * @return Boolean \n TRUE if object is identified, otherwise FALSE.
+ * @note
+ * Identify an object in the inventory (or on the floor).
+ * This routine does *not* automatically combine objects.
+ * @note (see file spells2.c)
+ */
+extern bool ident_spell(void);
+
+/** @fn identify_fully(void)
+ * @brief Fully "identify" an object in the inventory (or on the floor).
+ * @return Boolean \n TRUE if object is identified, otherwise FALSE.
+ * @note
+ * Fully "identify" an object in the inventory -BEN-
+ * @note (see file spells2.c)
+ */
+extern bool identify_fully(void);
+
+/** @fn recharge(int num)
+ * @brief Recharge an object in the inventory (or on the floor) with "num"
+ * power.\n
+ * @param num Number \n num is the power used in recharging. It is compared
+ * to the object's level to determine whether the item is recharged
+ * successfully or destroyed. If it is recharged, it also determines
+ * how many charges are added, or how much recharge time is reduced.
+ * @brief Power
+ * @return Boolean \n TRUE if something was recharged, otherwise FALSE.
+ * @note
+ * Recharge a wand/staff/rod from the pack or on the floor.\n
+ * This function has been rewritten in Oangband. -LM-\n\n
+ * Mage -- Recharge I --> recharge(90)\n
+ * Mage -- Recharge II --> recharge(150)\n
+ * Mage -- Recharge III --> recharge(220)\n\n
+ * Priest or Necromancer -- Recharge --> recharge(140)\n
+ * Scroll of recharging --> recharge(130)\n
+ * Scroll of *recharging* --> recharge(200)\n\n
+ * It is harder to recharge high level, and highly charged wands,
+ * staffs, and rods. The more wands in a stack, the more easily and
+ * strongly they recharge. Staffs, however, each get fewer charges if
+ * stacked.\n\n
+ * XXX XXX XXX Beware of "sliding index errors".
+ * @note (see file spells2.c)
+ */
+extern bool recharge(int num);
+
+/** @fn aggravate_monsters(int who)
+ * @brief Aggravate monsters, originating from "who".\n
+ * @param who Number \n who is the index of monster in m_list[]
+ * (1 if it is the player) which triggers the aggravation.
+ * @brief Source
+ * @note
+ * Wake up all monsters, and speed up "los" monsters.
+ * @note (see file spells2.c)
+ */
+extern void aggravate_monsters(int who);
+
+/** @fn genocide_aux(bool player_cast, char typ)
+ * @brief Genocide a monster race.\n
+ * @param player_cast Boolean \n player_cast is true if the player cast the
+ * spell so the player can take damage.
+ * @param typ Char \n typ is the letetr of the genocided monsters
+ * @return Boolean \n TRUE if genocide was cast, otherwise FALSE.
+ * @note
+ * Genocide will not work on DF2_NO_GENO dungeon levels, or on "fated to
+ * die" levels.
+ * The player gets 4 points of damage per monster genocided.
+ * @note (see file spells2.c)
+ */
+extern bool genocide_aux(bool player_cast, char typ);
+
+/** @fn genocide(bool player_cast)
+ * @brief Genocide a monster race.\n
+ * @param player_cast Boolean \n player_cast is true if the player cast the
+ * spell so the player can take damage.
+ * @brief Player cast spell?
+ * @return Boolean \n TRUE if genocide was cast, otherwise FALSE.
+ * @note
+ * Genocide will not work on DF2_NO_GENO dungeon levels, or on "fated to
+ * die" levels.
+ * The player gets 4 points of damage per monster genocided.
+ * @note (see file spells2.c)
+ */
+extern bool genocide(bool player_cast);
+
+/** @fn mass_genocide(bool player_cast)
+ * @brief Delete all nearby (non-unique) monsters.\n
+ * @param player_cast Boolean \n player_cast is true if the player cast the
+ * spell so the player can take damage.
+ * @brief Player cast spell?
+ * @return Boolean \n TRUE (always).
+ * @note
+ * Genocide will not work on DF2_NO_GENO dungeon levels, or on "fated to
+ * die" levels.\n
+ * The player gets 3 points of damage per monster genocided.
+ * @note (see file spells2.c)
+ */
+extern bool mass_genocide(bool player_cast);
+
+/** @fn probing(void)
+ * @brief Probe all nearby monsters.
+ * @return Boolean \n TRUE if probe was successful, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool probing(void);
+
+/** @fn banish_evil(int dist)
+ * @brief Banish nearby evil monsters doing "dist" points of GF_AWAY_EVIL
+ * damage.\n
+ * @param dist Number \n dist is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool banish_evil(int dist);
+
+/** @fn dispel_evil(int dam)
+ * @brief Dispel nearby evil monsters doing "dam" points of GF_DISP_EVIL
+ * damage.\n
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool dispel_evil(int dam);
+
+/** @fn dispel_good(int dam)
+ * @brief Dispel nearby good monsters doing "dam" points of GF_DISP_GOOD
+ * damage.\n
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool dispel_good(int dam);
+
+/** @fn dispel_undead(int dam)
+ * @brief Dispel nearby undead monsters doing "dam" points of GF_DISP_UNDEAD
+ * damage.\n
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool dispel_undead(int dam);
+
+/** @fn dispel_monsters(int dam)
+ * @brief Dispel all nearby monsters doing "dam" points of GF_DISP_ALL
+ * damage.\n
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool dispel_monsters(int dam);
+
+/** @fn dispel_living(int dam)
+ * @brief Dispel nearby living monsters doing "dam" points of GF_DISP_LIVING
+ * damage.\n
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool dispel_living(int dam);
+
+/** @fn dispel_demons(int dam)
+ * @brief Dispel nearby demon monsters doing "dam" points of GF_DISP_DEMON
+ * damage.\n
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool dispel_demons(int dam);
+
+/** @fn turn_undead(void)
+ * @brief Turn nearby undead monsters doing a point of GF_TURN_UNDEAD damage
+ * for each player level.
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool turn_undead(void);
+
+/** @fn door_creation(void)
+ * @brief Create doors in all grids adjacent to the player.
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool door_creation(void);
+
+/** @fn trap_creation(void)
+ * @brief Create traps in all grids adjacent to the player.
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool trap_creation(void);
+
+/** @fn glyph_creation(void)
+ * @brief Create glyphs in all grids adjacent to the player.
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool glyph_creation(void);
+
+/** @fn wipe(int y1, int x1, int r)
+ * @brief Delete monsters and objects from an area of the dungeon centred at
+ * grid "y1,x1" for a radius "r".\n
+ * @param y1 Number \n Y-coordinate of dungeon grid.
+ * @brief Y-coordinate
+ * @param x1 Number \n X-coordinate of dungeon grid.
+ * @brief X-coordinate
+ * @param r Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @note
+ * Wipe -- Empties a part of the dungeon\n\n
+ * This does not work on special levels or quests. The player may become
+ * blinded. The player forgets the affected area and it becomes dark.
+ * All grids become floor.
+ * @note (see file spells2.c)
+ */
+extern void wipe(int y1, int x1, int r);
+
+/** @fn destroy_area(int y1, int x1, int r, bool full, bool bypass)
+ * @brief Delete monsters and objects from an area of the dungeon centred at
+ * grid "y1,x1" for a radius "r".\n
+ * @param y1 Number \n Y-coordinate of dungeon grid.
+ * @brief Y-coordinate
+ * @param x1 Number \n X-coordinate of dungeon grid.
+ * @brief X-coordinate
+ * @param r Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @param full Boolean \n unused
+ * @brief *Unused*
+ * @param bypass Boolean \n TRUE if quest levels are not destroyed, otherwise
+ * FALSE.
+ * @brief Exempt quest levels?
+ * @note
+ * The spell of destruction\n\n
+ * This spell "deletes" monsters (instead of "killing" them).\n\n
+ * Later we may use one function for both "destruction" and
+ * "earthquake" by using the "full" to select "destruction".\n\n
+ * This does not work on special levels. This does not work on quests if the
+ * bypass flag is set. The epicentre is NOT affected. The player may become
+ * blinded. The player forgets the affected area and it becomes dark. The
+ * grids can become granite, quartz, magma, or floor.
+ * @note (see file spells2.c)
+ */
+extern void destroy_area(int y1, int x1, int r, bool full, bool bypass);
+
+/** @fn earthquake(int cy, int cx, int r)
+ * @brief Create an earthquake centred on grid "cy,cx" with a radius of "r".\n
+ * @param cy Number \n Y-coordinate of dungeon grid.
+ * @brief Y-coordinate
+ * @param cx Number \n X-coordinate of dungeon grid.
+ * @brief X-coordinate
+ * @param r Number \n rad is the radius of circle of detection.
+ * @brief Radius
+ * @note
+ * Induce an "earthquake" of the given radius at the given location.\n\n
+ * This will turn some walls into floors and some floors into walls.\n\n
+ * The player will take damage and "jump" into a safe grid if possible,
+ * otherwise, he will "tunnel" through the rubble instantaneously.\n\n
+ * Monsters will take damage, and "jump" into a safe grid if possible,
+ * otherwise they will be "buried" in the rubble, disappearing from
+ * the level in the same way that they do when genocided.\n\n
+ * Note that thus the player and monsters (except eaters of walls and
+ * passers through walls) will never occupy the same grid as a wall.
+ * Note that as of now (2.7.8) no monster may occupy a "wall" grid, even
+ * for a single turn, unless that monster can pass_walls or kill_walls.
+ * This has allowed massive simplification of the "monster" code.\n\n
+ * This does not work on quest levels. The epicentre is NOT affected.
+ * Only about 15% of the grids are affected. The player takes 300 points
+ * of damage if they can't be moved to a safe grid, otherwise damage is
+ * from 10 to 40 points. The player forgets the affected area and it
+ * becomes dark. The grids can become granite, quartz, magma, or floor.
+ * @note (see file spells2.c)
+ */
+extern void earthquake(int cy, int cx, int r);
+
+/** @fn lite_room(int y1, int x1)
+ * @brief Lite room containing grid "y1,x1".\n
+ * @param y1 Number \n Y-coordinate of dungeon grid.
+ * @brief Y-coordinate
+ * @param x1 Number \n X-coordinate of dungeon grid.
+ * @brief X-coordinate
+ * @note
+ * Illuminate any room containing the given location.
+ * @note (see file spells2.c)
+ */
+extern void lite_room(int y1, int x1);
+
+/** @fn unlite_room(int y1, int x1)
+ * @brief Unlite room containing grid "y1,x1".\n
+ * @param y1 Number \n Y-coordinate of dungeon grid.
+ * @brief Y-coordinate
+ * @param x1 Number \n X-coordinate of dungeon grid.
+ * @brief X-coordinate
+ * @note
+ * Darken all rooms containing the given location.
+ * @note (see file spells2.c)
+ */
+extern void unlite_room(int y1, int x1);
+
+/** @fn lite_area(int dam, int rad)
+ * @brief Lite area around player of radius "rad" causing "dam" points of
+ * damage to monsters.
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param rad Number \n rad is the radius of circle of lite.
+ * @brief Radius
+ * @return Boolean \n TRUE (always).
+ * @note
+ * Hack -- call light around the player\n
+ * Affect all monsters in the projection radius\n\n
+ * Generate a ball of spell type GF_LITE_WEAK.\n
+ * @note (see file spells2.c)
+ */
+extern bool lite_area(int dam, int rad);
+
+/** @fn unlite_area(int dam, int rad)
+ * @brief Unlite area around player of radius "rad" causing "dam" points of
+ * damage to monsters.
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param rad Number \n rad is the radius of circle of lite.
+ * @brief Radius
+ * @return Boolean \n TRUE (always).
+ * @note
+ * Hack -- call darkness around the player\n
+ * Affect all monsters in the projection radius\n\n
+ * Generate a ball of spell type GF_DARK_WEAK.\n
+ * @note (see file spells2.c)
+ */
+extern bool unlite_area(int dam, int rad);
+
+/** @fn fire_ball_beam(int typ, int dir, int dam, int rad)
+ * @brief Generate a ball spell of type "typ" with radius "rad" aimed in
+ * direction "dir" for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param rad Number \n rad is 0 for a beam/bolt and 1-16 for a ball.
+ * @brief Radius
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a ball-beamed spell\n
+ * Stop if we hit a monster, act as a "ball"\n
+ * Allow "target" mode to pass over monsters\n
+ * Affect grids, objects, and monsters\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".\n\n
+ * Any radius >16 is treated as 16.
+ * @note (see file spells2.c)
+ */
+extern bool fire_ball_beam(int typ, int dir, int dam, int rad);
+
+/** @fn make_wish(void)
+ * @brief Allow the player to make a wish.
+ * @note (see file xtra2.c)
+ */
+extern void make_wish(void);
+
+/** @fn fire_wave(int typ, int dir, int dam, int rad, int time, s32b eff)
+ * @brief Generate a ball spell of type "typ" with radius "rad" and effect
+ * "eff" lasting "time" turns aimed in direction "dir" for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param rad Number \n rad is 0 for a beam/bolt and 1-16 for a ball.
+ * @brief Radius
+ * @param time Number \n time is the number of turns the spell lasts.
+ * @brief Duration
+ * @param eff Number \n eff is the spell effect (EFF field)
+ * @brief Effect
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a wave spell\n
+ * Stop if we hit a monster, act as a "ball"\n
+ * Allow "target" mode to pass over monsters\n
+ * Affect grids, objects, and monsters\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".\n\n
+ * Any radius >16 is treated as 16.
+ * @note (see file spells2.c)
+ */
+extern bool fire_wave(int typ, int dir, int dam, int rad, int time, s32b eff);
+
+/** @name Spell Effect Flags
+ * @brief Effect of spell
+ * @{ */
+/** @def EFF_WAVE
+ * @note A circle whose radius increase
+ */
+#define EFF_WAVE 0x00000001
+
+/** @def EFF_LAST
+ * @note The wave lasts
+ */
+#define EFF_LAST 0x00000002
+
+/** @def EFF_STORM
+ * @note the effect follows the player
+ */
+#define EFF_STORM 0x00000004
+
+/** @name Spell Effect Direction Flags
+ * @brief Direction of the spell
+ * @{ */
+#define EFF_DIR1 0x00000008 /* Directed effect */
+#define EFF_DIR2 0x00000010 /* Directed effect */
+#define EFF_DIR3 0x00000020 /* Directed effect */
+#define EFF_DIR4 0x00000040 /* Directed effect */
+#define EFF_DIR6 0x00000080 /* Directed effect */
+#define EFF_DIR7 0x00000100 /* Directed effect */
+#define EFF_DIR8 0x00000200 /* Directed effect */
+#define EFF_DIR9 0x00000400 /* Directed effect */
+/** @} */
+/** @} */
+
+/** @fn fire_cloud(int typ, int dir, int dam, int rad, int time)
+ * @brief Generate a ball spell of type "typ" with radius "rad" lasting
+ * "time" turns aimed in direction "dir" for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param rad Number \n rad is 0 for a beam/bolt and 1-16 for a ball.
+ * @brief Radius
+ * @param time Number \n time is the number of turns the spell lasts.
+ * @brief Duration
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a cloud spell\n
+ * Stop if we hit a monster, act as a "ball"\n
+ * Allow "target" mode to pass over monsters\n
+ * Affect grids, objects, and monsters\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".\n\n
+ * Any radius >16 is treated as 16.
+ * @note (see file spells2.c)
+ */
+extern bool fire_cloud(int typ, int dir, int dam, int rad, int time);
+
+/** @fn fire_wall(int typ, int dir, int dam, int time)
+ * @brief Generate a beam spell of type "typ" lasting "time" turns aimed in
+ * direction "dir" for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param time Number \n time is the number of turns the spell lasts.
+ * @brief Duration
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a persistant beam spell\n
+ * Pass through monsters, as a "beam"\n
+ * Affect monsters (not grids or objects)\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".
+ * @note (see file spells2.c)
+ */
+extern bool fire_wall(int typ, int dir, int dam, int time);
+
+/** @fn fire_ball(int typ, int dir, int dam, int rad)
+ * @brief Generate a ball spell of type "typ" with radius "rad" aimed in
+ * direction "dir" for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param rad Number \n rad is 0 for a beam/bolt and 1-16 for a ball.
+ * @brief Radius
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a ball spell\n
+ * Stop if we hit a monster, act as a "ball"\n
+ * Allow "target" mode to pass over monsters\n
+ * Affect grids, objects, and monsters\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".
+ * @note (see file spells2.c)
+ */
+extern bool fire_ball(int typ, int dir, int dam, int rad);
+
+/** @fn fire_bolt(int typ, int dir, int dam)
+ * @brief Generate a bolt spell of type "typ" aimed in direction "dir"
+ * for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a bolt spell\n
+ * Stop if we hit a monster, as a "bolt"\n
+ * Affect monsters (not grids or objects)\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".
+ * @note (see file spells2.c)
+ */
+extern bool fire_bolt(int typ, int dir, int dam);
+
+/** @fn fire_beam(int typ, int dir, int dam)
+ * @brief Generate a beam spell of type "typ" aimed in direction "dir"
+ * for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a beam spell\n
+ * Pass through monsters, as a "beam"\n
+ * Affect monsters (not grids or objects)\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".
+ * @note (see file spells2.c)
+ */
+extern bool fire_beam(int typ, int dir, int dam);
+
+/** @fn fire_druid_ball(int typ, int dir, int dam, int rad)
+ * @brief Generate a druid ball spell of type "typ" with radius "rad" aimed in
+ * direction "dir" for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param rad Number \n rad is 0 for a beam/bolt and 1-16 for a ball.
+ * @brief Radius
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a druidistic ball spell\n
+ * Stop if we hit a monster, act as a "ball"\n
+ * Allow "target" mode to pass over monsters\n
+ * Affect grids, objects, and monsters\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".\n\n
+ * The spells follows a mana path\n\n
+ * WARNING: This routine has been deprecated.
+ * @note (see file spells2.c)
+ */
+extern bool fire_druid_ball(int typ, int dir, int dam, int rad);
+
+/** @fn fire_druid_bolt(int typ, int dir, int dam)
+ * @brief Generate a druid bolt spell of type "typ" aimed in direction "dir"
+ * for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a druidistic bolt spell\n
+ * Stop if we hit a monster, as a "bolt"\n
+ * Affect monsters (not grids or objects)\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".\n\n
+ * The spells follows a mana path\n\n
+ * WARNING: This routine has been deprecated.
+ * @note (see file spells2.c)
+ */
+extern bool fire_druid_bolt(int typ, int dir, int dam);
+
+/** @fn fire_druid_beam(int typ, int dir, int dam)
+ * @brief Generate a druid beam spell of type "typ" aimed in direction "dir"
+ * for "dam" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a druidistic beam spell\n
+ * Pass through monsters, as a "beam"\n
+ * Affect monsters (not grids or objects)\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".\n\n
+ * The spells follows a mana path\n\n
+ * WARNING: This routine has been deprecated.
+ * @note (see file spells2.c)
+ */
+extern bool fire_druid_beam(int typ, int dir, int dam);
+
+/** @fn fire_bolt_or_beam(int prob, int typ, int dir, int dam)
+ * @brief Generate a bolt spell of type "typ" aimed in direction "dir"
+ * for "dam" damage with "prob" percent chance of a beam.\n
+ * @param prob Number \n prob is the percentage chance the spell will be a
+ * beam instead of a bolt.
+ * @brief Beam probability percentage
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Cast a bolt spell, or rarely, a beam spell\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".\n\n
+ * @note (see file spells2.c)
+ */
+extern bool fire_bolt_or_beam(int prob, int typ, int dir, int dam);
+
+/** @fn alchemy(void)
+ * @brief Turns an object into gold, gain some of its value in a shop
+ * @return Boolean \n TRUE if object turns to gold, otherwise FALSE.
+ * @note
+ * The player selects an object (and quantity if it applies) from the
+ * inventory or the floor and attempts to turn it into gold. If the
+ * price of the item is < 0 then the player gains nothing (fool's gold),
+ * otherwise the player gets a third of the price in gold. Artifacts are
+ * not affected.
+ * @note (see file spells2.c)
+ */
+extern bool alchemy(void);
+
+/** @fn alter_reality(void)
+ * @brief The player leaves the level immediately.
+ * @note (see file spells2.c)
+ */
+extern void alter_reality(void);
+
+/** @fn swap_position(int lty, int ltx)
+ * @brief Swap the position of the player with whatever is in grid "lty,ltx".\n
+ * @param lty Number \n Y-coordinate of target location.
+ * @brief Y-coordinate
+ * @param ltx Number \n X-coordinate of target location.
+ * @brief X-coordinate
+ * @note
+ * Player moves to target location. If there is a monster at the target
+ * location, it is moved to the player location. This is not allowed if
+ * the space-time continuum can not be disrupted.
+ * @note (see file spells2.c)
+ */
+extern void swap_position(int lty, int ltx);
+
+/** @fn teleport_swap(int dir)
+ * @brief Player swaps places with target in direction "dir".\n
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @note
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, the target is the grid adjacent to the player in direction
+ * "dir".\n\n
+ * The target must be a monster. It will not work if the space-time continuum
+ * can not be disrupted or if the monster resists teleportation.
+ * @note (see file spells2.c)
+ */
+extern void teleport_swap(int dir);
+
+/** @fn project_meteor(int radius, int typ, int dam, u32b flg)
+ * @brief Generate from "radius" to ("radius" x2) ball spells with properties
+ * "flg" of type "typ" for "dam" damage.\n
+ * @param radius Number \n rad is the minimum number of balls created.
+ * rad + randint("rad") balls are created.
+ * @brief Balls
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param flg Number \n flg is the projection effect (PROJECT field).
+ * @brief Properties flag
+ * @note
+ * Apply a "project()" a la meteor shower\n\n
+ * Each ball has a radius of 2 grids. Each target grid is within 5 grids of
+ * the player.
+ * @note (see file spells2.c)
+ */
+extern void project_meteor(int radius, int typ, int dam, u32b flg);
+
+/** @fn passwall(int dir, bool safe)
+ * @brief Move the player through walls in direction "dir", to a "safe"
+ * location.\n
+ * @param dir Number \n dir must be a value from 0 to 9. It can not be 5.
+ * @brief Direction
+ * @param safe Boolean \n TRUE if location must be a safe one, otherwise FALSE.
+ * @brief Safe location?
+ * @return Boolean \n TRUE if move was successful, otherwise FALSE.
+ * @note
+ * Send the player shooting through walls in the given direction until
+ * they reach a non-wall space, or a monster, or a permanent wall.\n\n
+ * If the player ends up in a wall, they take 10d8 damage and the wall is
+ * replaced by a floor.\n\n
+ * This does not work in the wilderness, on quest levels, or if teleport is
+ * not allowed. Stopping on monsters or inside vaults is not allowed.
+ * @note (see file spells2.c)
+ */
+extern bool passwall(int dir, bool safe);
+
+/** @fn project_hook(int typ, int dir, int dam, int flg)
+ * @brief Generate a bolt/beam with properties "flg" in direction "dir" for
+ * "dam" points of "typ" damage.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @param flg Number \n flg is the projection effect (PROJECT field).
+ * @brief Properties flag
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Hack -- apply a "projection()" in a direction (or at the target)\n\n
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".
+ * @note (see file spells2.c)
+ */
+extern bool project_hook(int typ, int dir, int dam, int flg);
+
+/** @fn wizard_lock(int dir)
+ * @brief Cast a wizard_lock spell in direction "dir".\n
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * If direction is 5 and a target has been selected, then the target is used.
+ * Otherwise, a target is calculated based on a distance of 999 grids away
+ * from the player in direction "dir".
+ * @note (see file spells2.c)
+ */
+extern bool wizard_lock(int dir);
+
+/** @fn reset_recall(bool no_trepas_max_depth)
+ * @brief Ask the user to set a recall level in a dungeon, possibly no
+ * deeper than maximum dungeon depth.\n
+ * @param no_trepas_max_depth Boolean \n TRUE if user can select maximum
+ * dungeon depth, FALSE if user can select up to player's maximum depth
+ * in the dungeon so far.
+ * @brief Allow maximum dungeon depth?
+ * @return Boolean \n TRUE of recall level was reset, otherwise FALSE.
+ * @note
+ * Ask the user for a dungeon and appropriate level within the dungeon.\n
+ * The user can not specify a dungeon the player has not gone to yet.\n
+ * If the depth is <1, reset fails. If depth is 99 or 100, the level is set
+ * to 98.
+ * @note (see file spells2.c)
+ */
+extern bool reset_recall(bool no_trepas_max_depth);
+
+/** @fn get_aim_dir(int *dp=0)
+ * @brief Get an aiming direction from the user and store it in "dp".\n
+ * @param *dp Number
+ * @brief Direction
+ * @return *dp Number \n Aiming direction.
+ * @return Boolean \n TRUE if a valid direction was returned, otherwise FALSE.
+ * @note
+ * Get an "aiming direction" from the user.\n\n
+ * The "dir" is loaded with 1,2,3,4,6,7,8,9 for "actual direction", and
+ * "0" for "current target", and "-1" for "entry aborted".\n\n
+ * Note that "Force Target", if set, will pre-empt user interaction,
+ * if there is a usable target already set.\n\n
+ * Note that confusion over-rides any (explicit?) user choice.
+ * @note (see file xtra2.c)
+ */
+extern bool get_aim_dir(int *dp=0);
+
+/** @fn get_rep_dir(int *dp=0)
+ * @brief Get a movement direction from the user and store it in "dp".\n
+ * @param *dp Number
+ * @brief Direction
+ * @return *dp Number \n Movement direction.
+ * @return Boolean \n TRUE if a valid direction was returned, otherwise FALSE.
+ * @note
+ * Request a "movement" direction (1,2,3,4,6,7,8,9) from the user,
+ * and place it into "command_dir", unless we already have one.\n\n
+ * This function should be used for all "repeatable" commands, such as
+ * run, walk, open, close, bash, disarm, spike, tunnel, etc, as well
+ * as all commands which must reference a grid adjacent to the player,
+ * and which may not reference the grid under the player. Note that,
+ * for example, it is no longer possible to "disarm" or "open" chests
+ * in the same grid as the player.\n\n
+ * Direction "5" is illegal and will (cleanly) abort the command.\n\n
+ * This function tracks and uses the "global direction", and uses
+ * that as the "desired direction", to which "confusion" is applied.
+ * @note (see file xtra2.c)
+ */
+extern bool get_rep_dir(int *dp=0);
+
+/** @fn project_los(int typ, int dam);
+ * @brief Generate a bolt/beam for "dam" points of "typ" damage to all
+ * viewable monsters in line of sight.\n
+ * @param typ Number \n typ is the type of damage (GF field).
+ * @brief Type
+ * @param dam Number \n dam is the number of hit points of damage.
+ * @brief Damage
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note
+ * Apply a "project()" directly to all viewable monsters\n\n
+ * Note that affected monsters are NOT auto-tracked by this usage.
+ * @note (see file spells2.c)
+ */
+extern bool project_hack @ project_los(int typ, int dam);
+
+/** @fn map_area(void)
+ * @brief Map current area.
+ * @note
+ * Hack -- map the current panel (plus some) ala "magic mapping"\n\n
+ * Up to 10 grids above and below, and up to 20 grids either side of the
+ * panel are mapped.
+ * @note (see file cave.c)
+ */
+extern void map_area(void);
+
+/** @fn wiz_lite(void)
+ * @brief Lite level using "clairvoyance".
+ * @note
+ * This function "illuminates" every grid in the dungeon, memorizes all
+ * "objects", memorizes all grids as with magic mapping, and, under the
+ * standard option settings (view_perma_grids but not view_torch_grids)
+ * memorizes all floor grids too.\n\n
+ * Note that if "view_perma_grids" is not set, we do not memorize floor
+ * grids, since this would defeat the purpose of "view_perma_grids", not
+ * that anyone seems to play without this option.\n\n
+ * Note that if "view_torch_grids" is set, we do not memorize floor grids,
+ * since this would prevent the use of "view_torch_grids" as a method to
+ * keep track of what grids have been observed directly.
+ * @note (see file cave.c)
+ */
+extern void wiz_lite(void);
+
+/** @fn wiz_lite_extra(void)
+ * @brief Lite and memorize level.
+ * @note (see file cave.c)
+ */
+extern void wiz_lite_extra(void);
+
+/** @fn wiz_dark(void)
+ * @brief Forget all grids and objects.
+ * @note
+ * Forget the dungeon map (ala "Thinking of Maud...").
+ * @note (see file cave.c)
+ */
+extern void wiz_dark(void);
+
+/** @fn create_between_gate(int dist, int y, int x)
+ * @brief Create a between gate at grid "y,x" or at a target grid within
+ * distance "dist" of the player.\n
+ * @param dist Number \n dist is the maximum distance from the player of the
+ * between gate.
+ * @brief Distance
+ * @param y Number \n Y-coordinate of dungeon grid.
+ * @brief Y-coordinate
+ * @param x Number \n X-coordinate of dungeon grid.
+ * @brief X-coordinate
+ * @note
+ * Creates a between gate\n\n
+ * This will fail if teleporting is not allowed on the level.\n\n
+ * If the coordinates are given, a between gate is created under the player
+ * and at the given coordinate.\n\n
+ * If there are no coordinates, a target is selected. The gate will not be
+ * created if the grid is not empty, or the grid is in a vault, or the grid
+ * is too far away. There is always a chance (1 in (Conveyance Skill *
+ * Conveyance Skill / 2)) the gate will not be created.
+ * @note (see file spells2.c)
+ */
+extern void create_between_gate(int dist, int y, int x);
+
+/** @fn destroy_doors_touch(void)
+ * @brief Destroy all doors adjacent to the player.
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool destroy_doors_touch(void);
+
+/** @fn destroy_traps_touch(void)
+ * @brief Destroy all traps adjacent to the player.
+ * @return Boolean \n TRUE if player notices, otherwise FALSE.
+ * @note (see file spells2.c)
+ */
+extern bool destroy_traps_touch(void);
+
+/** @struct magic_power
+ * @brief Innate powers
+ */
+struct magic_power
+{
+ /** @structvar min_lev
+ * @brief Number
+ */
+ int min_lev;
+
+ /** @structvar mana_cost
+ * @brief Number
+ */
+ int mana_cost;
+
+ /** @structvar fail
+ * @brief Number
+ */
+ int fail;
+
+ /** @structvar name
+ * @brief String
+ */
+ cptr name;
+
+ /** @structvar desc
+ * @brief String
+ */
+ cptr desc;
+};
+
+/** @fn get_magic_power(magic_power *m_ptr, int num);
+ * @dgonly
+ * @brief Get magic power number "num" from array "m_ptr" of magic powers.\n
+ * @param *m_ptr magic_power \n m_ptr is the array of magic powers.
+ * @brief Powers
+ * @param num Number \n num is the index to the array.
+ * @brief Index
+ * @return magic_power \n A magic power.
+ * @note
+ * Note: do not call this function.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+extern magic_power *grab_magic_power @ get_magic_power(magic_power *m_ptr, int num);
+
+/** @fn magic_power_sucess(magic_power *spell, int stat, char *oups_fct=NULL);
+ * @dgonly
+ * @brief Determine if using a magic power succeeds.\n
+ * @param *spell magic_power \n Spell is the magic power the player is using.
+ * @brief Power (spell)
+ * @param stat Number \n stat is the required casting statistic (INT or WIS).
+ * @brief Casting statistic
+ * @param *oups_fct String \n oups_fct is the message displayed when the power
+ * fails.
+ * @brief Fail message
+ * @return Boolean \n TRUE if spell succeeds, otherwise FALSE.
+ * @note
+ * The chance of using a power is adjusted for player magic skill, casting
+ * statistic, player mana points, and stunning. There is always at least a
+ * 5% chance the power works.\n\n
+ * Note: do not call this function.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+extern bool lua_spell_success @ magic_power_sucess(magic_power *spell, int stat, char *oups_fct=NULL);
+
+/** @fn add_new_power(cptr name, cptr desc, cptr gain, cptr lose, byte level, byte cost, byte stat, byte diff)
+ * @dgonly
+ * @brief Add a new power to the array of magic powers.\n
+ * @param name String \n name is the name of the power.
+ * @brief Name
+ * @param desc String \n desc is the description of the power.
+ * @brief Description
+ * @param gain String \n gain describes the effect when the power starts
+ * working.
+ * @brief Gain message
+ * @param lose String \n loss describes the effect when the power stops
+ * working.
+ * @brief Lose message
+ * @param level Number \n level is the magic skill level a player needs to
+ * use the power.
+ * @brief Level
+ * @param cost Number \n cost is the number of mana points required to use the
+ * power.
+ * @brief Mana cost
+ * @param stat Number \n stat is the required casting statistic (INT or WIS).
+ * @brief Casting statistic
+ * @param diff Number \n diff is the difficulty.
+ * @brief Difficulty
+ * @return Number \n The index of the new power in the magic power array.
+ * @note
+ * Note: do not call this function.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+s16b add_new_power(cptr name, cptr desc, cptr gain, cptr lose, byte level, byte cost, byte stat, byte diff);
+
+/** @var power_max
+ * @brief Number
+ * @note Maximum number of innate powers.
+ */
+extern s16b power_max;
+
+/* Schools */
+
+/** @struct school_spell_type
+ * @brief Spell
+ * @note The spell function must provide the desc
+ */
+struct spell_type@school_spell_type
+{
+ /** @structvar name
+ * @brief String
+ */
+ cptr name;
+
+ /** @structvar skill_level
+ * @brief Number
+ * @note Required level (to learn)
+ */
+ byte skill_level;
+
+ /** @structvar mana
+ * @brief Number
+ * @note Required mana at lvl 1
+ */
+ byte mana;
+
+ /** @structvar mana_max
+ * @brief Number
+ * @note Required mana at max lvl
+ */
+ byte mana_max;
+
+ /** @structvar fail
+ * @brief Number
+ * @note Minimum chance of failure
+ */
+ s16b fail;
+
+ /** @structvar level
+ * @brief Number
+ * @note Spell level(0 = not learnt)
+ */
+ s16b level;
+};
+
+/** @struct school_type
+ * @brief Spell school
+ */
+struct school_type
+{
+ /** @structvar name
+ * @brief String
+ * @note Name
+ */
+ cptr name;
+ /** @structvar skill
+ * @brief Number
+ * @note Skil used for that school
+ */
+ s16b skill;
+};
+
+/** @fn new_school(int i, cptr name, s16b skill)
+ * @dgonly
+ * @brief Add school to array of schools.\n
+ * @param i Number \n i is index of school array where school is added.
+ * There is no range checking.
+ * @brief Index
+ * @param name String \n name is the name of the school.
+ * @brief Name
+ * @param skill Number \n skill is the skill of the school.
+ * @brief Skill
+ * @return Number \ The index parameter.
+ * @note
+ * Note: do not call this function directly.\n
+ * Please use add_school() in s_aux.lua instead.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+extern s16b new_school(int i, cptr name, s16b skill);
+
+/** @fn new_spell(int i, cptr name)
+ * @dgonly
+ * @brief Add spell to array of spells for a school.\n
+ * @param i Number \n i is index of school spell array where spell is added.
+ * There is no range checking.
+ * @brief Index
+ * @param name String \n name is the name of the spell.
+ * @brief Name
+ * @return Number \ The index parameter.
+ * @note
+ * Spell level is set to zero.\n\n
+ * Note: do not call this function directly.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+extern s16b new_spell(int i, cptr name);
+
+/** @fn spell(s16b num);
+ * @dgonly
+ * @brief Get spell "num" from array of spells for a school.\n
+ * @param num Number \n num is the index of the spell.
+ * There is no range checking.
+ * @brief Index
+ * @return spell_type \n The spell.
+ * @note
+ * Note: do not call this function directly.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+extern spell_type *grab_spell_type @ spell(s16b num);
+
+/** @fn school(s16b num);
+ * @dgonly
+ * @brief Get school "num" from array of schools.\n
+ * @param num Number \n num is the index of the school.
+ * There is no range checking.
+ * @brief Index
+ * @return school_type \n The school.
+ * @note
+ * Note: do not call this function directly.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+extern school_type *grab_school_type @ school(s16b num);
+
+/** @fn lua_get_level(s32b s, s32b lvl, s32b max, s32b min, s32b bonus)
+ * @dgonly
+ * @brief Get the casting level of school spell "s".\n
+ * @param s Number \n s is the index of the spell in array of school spells.
+ * There is no range checking.
+ * @brief Spell index
+ * @param lvl Number \n lvl represents the level of player skill.
+ * @brief Player skill level
+ * @param max Number \n max is the maximum level for the spell.
+ * @brief Maximum spell level
+ * @param min Number \n min is the minimum level for the spell.
+ * @brief Minimum spell level
+ * @param bonus Number \n bonus is any bonus to final level.
+ * @brief Bonus
+ * @return Number \n Casting level.
+ * @note
+ * Note: do not call this function directly.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+extern s32b lua_get_level(s32b s, s32b lvl, s32b max, s32b min, s32b bonus);
+
+/** @fn lua_spell_chance(s32b chance, int level, int skill_level, int mana, int cur_mana, int stat)
+ * @dgonly
+ * @brief Get the chance a spell will fail.\n
+ * @param chance Number \n chance is the inital chance a spell will work.
+ * @brief Initial chance
+ * @param level Number \n level represents the level of player skill.
+ * @brief Player skill level
+ * @param skill_level Number \n *unused*.
+ * @brief *Unused*
+ * @param mana Number \n mana is the mana required by the spell.
+ * @brief Spell mana
+ * @param cur_mana Number \n cur_mana is the player's current mana.
+ * @brief Player mana
+ * @param stat Number \n stat is the required casting statistic (INT or WIS).
+ * @brief Casting statistic
+ * @return Number \n Chance of failure.
+ * @note
+ * Note: do not call this function directly.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+extern s32b lua_spell_chance(s32b chance, int level, int skill_level, int mana, int cur_mana, int stat);
+
+/** @fn lua_spell_device_chance(s32b chance, int level, int base_level)
+ * @dgonly
+ * @brief Get the chance a device will fail.\n
+ * @param chance Number \n chance is the inital chance a spell will work.
+ * @brief Initial chance
+ * @param level Number \n level represents the level of player skill.
+ * @brief Player skill level
+ * @param base_level Number \n *unused*
+ * @brief *Unused*
+ * @return Number \n Chance of failure.
+ * @note
+ * Note: do not call this function directly.\n
+ * By order of DG.
+ * @note (see file lua_bind.c)
+ */
+extern s32b lua_spell_device_chance(s32b chance, int level, int base_level);
+
+/** @fn get_school_spell(cptr do_what, cptr check_fct, s16b force_book)
+ * @brief Get a spell from a book.\n
+ * @param do_what String \n what the player wants to do with the spell,
+ * for example "cast" or "copy".
+ * @brief Action
+ * @param check_fct String \n check_fct is the name of a function which checks
+ * if the player has access to the spell.
+ * @brief Check function
+ * @param force_book Number \n If it is different from 0 it for'ces the use of
+ * a spellbook, bypassing spellbook selection
+ * @brief Bypass book selection
+ * @return Number \n Spell number.
+ * @note
+ * Get a spell from a book\n\n
+ * The player must have a book to select a spell. When a book is chosen, the
+ * player is given a choice of spells to select. The player must be able to
+ * access the spell.\n\n
+ * If no spell is chosen, -1 is returned.
+ * @note (see file cmd5.c)
+ */
+extern s32b get_school_spell(cptr do_what, cptr check_fct, s16b force_book);
+
+/** @name Last Teleportation
+ * @brief Coordinates of last successful teleportation
+ * @{ */
+/** @var last_teleportation_y
+ * @brief Number
+ * @note y-coordinate of last successful teleportation
+ */
+extern s16b last_teleportation_y;
+
+/** @var last_teleportation_x
+ * @brief Number
+ * @note x-coordinate of last successful teleportation
+ */
+extern s16b last_teleportation_x;
+/** @} */
+
+/** @fn get_pos_player(int dis, int *ny=0, int *nx=0)
+ * @brief Get a grid near the player.\n
+ * @param dis Number \n is the maximum distance away from the player.
+ * This is limited to 200.
+ * @brief Distance from player
+ * @return y Number \n Y-coordinate of grid.
+ * @return x Number \n X-coordinate of grid.
+ * @note
+ * This function is slightly obsessive about correctness.\n\n
+ * Minimum distance is half the maximum distance. The function attempts to
+ * find a valid grid up to 500 times. If no valid grid is found, the maximum
+ * distance is doubled (though no more than 200) and the minimum distance is
+ * halved. The function does this 100 times.
+ * @note (see file spells1.c)
+ */
+extern void get_pos_player(int dis, int *ny=0, int *nx=0);
diff --git a/src/spells1.c b/src/spells1.c
new file mode 100644
index 00000000..9bfc6fe2
--- /dev/null
+++ b/src/spells1.c
@@ -0,0 +1,9327 @@
+/* File: spells1.c */
+
+/* Purpose: Spell code (part 1) */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/* 1/x chance of reducing stats (for elemental attacks) */
+#define HURT_CHANCE 32
+
+/* 1/x chance of hurting even if invulnerable!*/
+#define PENETRATE_INVULNERABILITY 13
+
+/* Maximum number of tries for teleporting */
+#define MAX_TRIES 100
+
+
+/*
+ * Helper function -- return a "nearby" race for polymorphing
+ *
+ * Note that this function is one of the more "dangerous" ones...
+ */
+s16b poly_r_idx(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ int i, r;
+
+ /* Hack -- Uniques never polymorph */
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ return (r_idx);
+
+ /* Pick a (possibly new) non-unique race */
+ for (i = 0; i < 1000; i++)
+ {
+ /* Pick a new race, using a level calculation */
+ r = get_mon_num((dun_level + r_ptr->level) / 2 + 5);
+
+ /* Handle failure */
+ if (!r) break;
+
+ /* Obtain race */
+ r_ptr = &r_info[r];
+
+ /* Ignore unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) continue;
+
+ /* Use that index */
+ r_idx = r;
+
+ /* Done */
+ break;
+ }
+
+ /* Result */
+ return (r_idx);
+}
+
+/*
+ * Teleport player, using a distance and a direction as a rough guide.
+ *
+ * This function is not at all obsessive about correctness.
+ * This function allows teleporting into vaults (!)
+ */
+void teleport_player_directed(int rad, int dir)
+{
+ int y = p_ptr->py;
+ int x = p_ptr->px;
+ int yfoo = ddy[dir];
+ int xfoo = ddx[dir];
+ int min = rad / 4;
+ int dis = rad;
+ int i, d;
+ bool_ look = TRUE;
+ bool_ y_major = FALSE;
+ bool_ x_major = FALSE;
+ int y_neg = 1;
+ int x_neg = 1;
+ cave_type *c_ptr;
+
+ if (xfoo == 0 && yfoo == 0)
+ {
+ teleport_player(rad);
+ return;
+ }
+
+ /* Rooted means no move */
+ if (p_ptr->tim_roots) return;
+
+ if (yfoo == 0) x_major = TRUE;
+ if (xfoo == 0) y_major = TRUE;
+ if (yfoo < 0) y_neg = -1;
+ if (xfoo < 0) x_neg = -1;
+
+ /* Look until done */
+ while (look)
+ {
+ /* Verify max distance */
+ if (dis > 200)
+ {
+ teleport_player(rad);
+ return;
+ }
+
+ /* Try several locations */
+ for (i = 0; i < 500; i++)
+ {
+ /* Pick a (possibly illegal) location */
+ while (1)
+ {
+ if (y_major)
+ {
+ y = rand_spread(p_ptr->py + y_neg * dis / 2, dis / 2);
+ }
+ else
+ {
+ y = rand_spread(p_ptr->py, dis / 3);
+ }
+
+ if (x_major)
+ {
+ x = rand_spread(p_ptr->px + x_neg * dis / 2, dis / 2);
+ }
+ else
+ {
+ x = rand_spread(p_ptr->px, dis / 3);
+ }
+
+ d = distance(p_ptr->py, p_ptr->px, y, x);
+ if ((d >= min) && (d <= dis)) break;
+ }
+
+ /* Ignore illegal locations */
+ if (!in_bounds(y, x)) continue;
+
+ /* Require "naked" floor space */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* This grid looks good */
+ look = FALSE;
+
+ /* Stop looking */
+ break;
+ }
+
+ /* Increase the maximum distance */
+ dis = dis * 2;
+
+ /* Decrease the minimum distance */
+ min = min / 2;
+
+ }
+
+ /* Sound */
+ sound(SOUND_TELEPORT);
+
+ /* Move player */
+ teleport_player_to(y, x);
+
+ /* Handle stuff XXX XXX XXX */
+ handle_stuff();
+
+ c_ptr = &cave[y][x];
+
+ /* Hack -- enter a store if we are on one */
+ if (c_ptr->feat == FEAT_SHOP)
+ {
+ /* Disturb */
+ disturb(0, 0);
+
+ /* Hack -- enter store */
+ command_new = '_';
+ }
+}
+
+
+/*
+ * Teleport a monster, normally up to "dis" grids away.
+ *
+ * Attempt to move the monster at least "dis/2" grids away.
+ *
+ * But allow variation to prevent infinite loops.
+ */
+void teleport_away(int m_idx, int dis)
+{
+ int ny = 0, nx = 0, oy, ox, d, i, min;
+ int tries = 0;
+
+ bool_ look = TRUE;
+
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ if (p_ptr->resist_continuum)
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return;
+ }
+
+ /* Paranoia */
+ if (!m_ptr->r_idx) return;
+
+ /* Save the old location */
+ oy = m_ptr->fy;
+ ox = m_ptr->fx;
+
+ /* Minimum distance */
+ min = dis / 2;
+
+ /* Look until done */
+ while (look)
+ {
+ tries++;
+
+ /* Verify max distance */
+ if (dis > 200) dis = 200;
+
+ /* Try several locations */
+ for (i = 0; i < 500; i++)
+ {
+ /* Pick a (possibly illegal) location */
+ while (1)
+ {
+ ny = rand_spread(oy, dis);
+ nx = rand_spread(ox, dis);
+ d = distance(oy, ox, ny, nx);
+ if ((d >= min) && (d <= dis)) break;
+ }
+
+ /* Ignore illegal locations */
+ if (!in_bounds(ny, nx)) continue;
+
+ /* Require "empty" floor space */
+ if (!cave_empty_bold(ny, nx)) continue;
+
+ /* Hack -- no teleport onto glyph of warding */
+ if (cave[ny][nx].feat == FEAT_GLYPH) continue;
+ if (cave[ny][nx].feat == FEAT_MINOR_GLYPH) continue;
+
+ /* ...nor onto the Pattern */
+ if ((cave[ny][nx].feat >= FEAT_PATTERN_START) &&
+ (cave[ny][nx].feat <= FEAT_PATTERN_XTRA2)) continue;
+
+ /* No teleporting into vaults and such */
+ if (!(p_ptr->inside_quest || p_ptr->inside_arena))
+ if (cave[ny][nx].info & (CAVE_ICKY)) continue;
+
+ /* This grid looks good */
+ look = FALSE;
+
+ /* Stop looking */
+ break;
+ }
+
+ /* Increase the maximum distance */
+ dis = dis * 2;
+
+ /* Decrease the minimum distance */
+ min = min / 2;
+
+ /* Stop after MAX_TRIES tries */
+ if (tries > MAX_TRIES) return;
+ }
+
+ /* Sound */
+ sound(SOUND_TPOTHER);
+
+ /* Update the new location */
+ cave[ny][nx].m_idx = m_idx;
+ last_teleportation_y = ny;
+ last_teleportation_x = nx;
+
+ /* Update the old location */
+ cave[oy][ox].m_idx = 0;
+
+ /* Move the monster */
+ m_ptr->fy = ny;
+ m_ptr->fx = nx;
+
+ /* Update the monster (new location) */
+ update_mon(m_idx, TRUE);
+
+ /* Redraw the old grid */
+ lite_spot(oy, ox);
+
+ /* Redraw the new grid */
+ lite_spot(ny, nx);
+
+ /* Update monster light */
+ if (r_ptr->flags9 & RF9_HAS_LITE) p_ptr->update |= (PU_MON_LITE);
+}
+
+
+/*
+ * Teleport monster next to the player
+ */
+void teleport_to_player(int m_idx)
+{
+ int ny = 0, nx = 0, oy, ox, d, i, min;
+ int dis = 2;
+
+ bool_ look = TRUE;
+
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ int attempts = 500;
+
+ if (p_ptr->resist_continuum)
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return;
+ }
+
+ /* Paranoia */
+ if (!m_ptr->r_idx) return;
+
+ /* "Skill" test */
+ if (randint(100) > m_ptr->level) return;
+
+ /* Save the old location */
+ oy = m_ptr->fy;
+ ox = m_ptr->fx;
+
+ /* Minimum distance */
+ min = dis / 2;
+
+ /* Look until done */
+ while (look && --attempts)
+ {
+ /* Verify max distance */
+ if (dis > 200) dis = 200;
+
+ /* Try several locations */
+ for (i = 0; i < 500; i++)
+ {
+ /* Pick a (possibly illegal) location */
+ while (1)
+ {
+ ny = rand_spread(p_ptr->py, dis);
+ nx = rand_spread(p_ptr->px, dis);
+ d = distance(p_ptr->py, p_ptr->px, ny, nx);
+ if ((d >= min) && (d <= dis)) break;
+ }
+
+ /* Ignore illegal locations */
+ if (!in_bounds(ny, nx)) continue;
+
+ /* Require "empty" floor space */
+ if (!cave_empty_bold(ny, nx)) continue;
+
+ /* Hack -- no teleport onto glyph of warding */
+ if (cave[ny][nx].feat == FEAT_GLYPH) continue;
+ if (cave[ny][nx].feat == FEAT_MINOR_GLYPH) continue;
+
+ /* ...nor onto the Pattern */
+ if ((cave[ny][nx].feat >= FEAT_PATTERN_START) &&
+ (cave[ny][nx].feat <= FEAT_PATTERN_XTRA2)) continue;
+
+ /* No teleporting into vaults and such */
+ /* if (cave[ny][nx].info & (CAVE_ICKY)) continue; */
+
+ /* This grid looks good */
+ look = FALSE;
+
+ /* Stop looking */
+ break;
+ }
+
+ /* Increase the maximum distance */
+ dis = dis * 2;
+
+ /* Decrease the minimum distance */
+ min = min / 2;
+ }
+
+ if (attempts < 1) return;
+
+ /* Sound */
+ sound(SOUND_TPOTHER);
+
+ /* Update the new location */
+ cave[ny][nx].m_idx = m_idx;
+ last_teleportation_y = ny;
+ last_teleportation_x = nx;
+
+ /* Update the old location */
+ cave[oy][ox].m_idx = 0;
+
+ /* Move the monster */
+ m_ptr->fy = ny;
+ m_ptr->fx = nx;
+
+ /* Update the monster (new location) */
+ update_mon(m_idx, TRUE);
+
+ /* Redraw the old grid */
+ lite_spot(oy, ox);
+
+ /* Redraw the new grid */
+ lite_spot(ny, nx);
+
+ /* Update monster light */
+ if (r_ptr->flags9 & RF9_HAS_LITE) p_ptr->update |= (PU_MON_LITE);
+}
+
+
+/*
+ * Teleport the player to a location up to "dis" grids away.
+ *
+ * If no such spaces are readily available, the distance may increase.
+ * Try very hard to move the player at least a quarter that distance.
+ */
+/* It'd be better if this was made an argument ... */
+bool_ teleport_player_bypass = FALSE;
+
+void teleport_player(int dis)
+{
+ int d, i, min, ox, oy, x = 0, y = 0;
+ int tries = 0;
+
+ int xx = -1, yy = -1;
+
+ bool_ look = TRUE;
+
+ if (p_ptr->resist_continuum && (!teleport_player_bypass))
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return;
+ }
+
+ if (p_ptr->wild_mode) return;
+
+ /* Rooted means no move */
+ if (p_ptr->tim_roots) return;
+
+ if (p_ptr->anti_tele && (!teleport_player_bypass))
+ {
+ msg_print("A mysterious force prevents you from teleporting!");
+ return;
+ }
+
+ if ((dungeon_flags2 & DF2_NO_TELEPORT) && (!teleport_player_bypass))
+ {
+ msg_print("No teleport on special levels...");
+ return;
+ }
+
+
+ if (dis > 200) dis = 200; /* To be on the safe side... */
+
+ /* Minimum distance */
+ min = dis / 2;
+
+ /* Look until done */
+ while (look)
+ {
+ tries++;
+
+ /* Verify max distance */
+ if (dis > 200) dis = 200;
+
+ /* Try several locations */
+ for (i = 0; i < 500; i++)
+ {
+ /* Pick a (possibly illegal) location */
+ while (1)
+ {
+ y = rand_spread(p_ptr->py, dis);
+ x = rand_spread(p_ptr->px, dis);
+ d = distance(p_ptr->py, p_ptr->px, y, x);
+ if ((d >= min) && (d <= dis)) break;
+ }
+
+ /* Ignore illegal locations */
+ if (!in_bounds(y, x)) continue;
+
+ /* Require "naked" floor space */
+ if (!cave_naked_bold(y, x)) continue;
+
+ /* No teleporting into vaults and such */
+ if (cave[y][x].info & (CAVE_ICKY)) continue;
+
+ /* This grid looks good */
+ look = FALSE;
+
+ /* Stop looking */
+ break;
+ }
+
+ /* Increase the maximum distance */
+ dis = dis * 2;
+
+ /* Decrease the minimum distance */
+ min = min / 2;
+
+ /* Stop after MAX_TRIES tries */
+ if (tries > MAX_TRIES) return;
+ }
+
+ /* Sound */
+ sound(SOUND_TELEPORT);
+
+ /* Save the old location */
+ oy = p_ptr->py;
+ ox = p_ptr->px;
+
+ /* Move the player */
+ p_ptr->py = y;
+ p_ptr->px = x;
+ last_teleportation_y = y;
+ last_teleportation_x = x;
+
+ /* Redraw the old spot */
+ lite_spot(oy, ox);
+
+ while (xx < 2)
+ {
+ yy = -1;
+
+ while (yy < 2)
+ {
+ if (xx == 0 && yy == 0)
+ {
+ /* Do nothing */
+ }
+ else
+ {
+ if (cave[oy + yy][ox + xx].m_idx)
+ {
+ monster_race *r_ptr = race_inf(&m_list[cave[oy + yy][ox + xx].m_idx]);
+
+ if ((r_ptr->flags6
+ & RF6_TPORT) &&
+ !(r_ptr->flags3
+ & RF3_RES_TELE))
+ /*
+ * The latter limitation is to avoid
+ * totally unkillable suckers...
+ */
+ {
+ if (!(m_list[cave[oy + yy][ox + xx].m_idx].csleep))
+ teleport_to_player(cave[oy + yy][ox + xx].m_idx);
+ }
+ }
+ }
+ yy++;
+ }
+ xx++;
+ }
+
+ /* Redraw the new spot */
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Check for new panel (redraw map) */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Redraw trap detection status */
+ p_ptr->redraw |= (PR_DTRAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff XXX XXX XXX */
+ handle_stuff();
+}
+
+
+/*
+ * get a grid near the given location
+ *
+ * This function is slightly obsessive about correctness.
+ */
+void get_pos_player(int dis, int *ny, int *nx)
+{
+ int d, i, min, x = 0, y = 0;
+ int tries = 0;
+
+ bool_ look = TRUE;
+
+ if (dis > 200) dis = 200; /* To be on the safe side... */
+
+ /* Minimum distance */
+ min = dis / 2;
+
+ /* Look until done */
+ while (look)
+ {
+ tries++;
+
+ /* Verify max distance */
+ if (dis > 200) dis = 200;
+
+ /* Try several locations */
+ for (i = 0; i < 500; i++)
+ {
+ /* Pick a (possibly illegal) location */
+ while (1)
+ {
+ y = rand_spread(p_ptr->py, dis);
+ x = rand_spread(p_ptr->px, dis);
+ d = distance(p_ptr->py, p_ptr->px, y, x);
+ if ((d >= min) && (d <= dis)) break;
+ }
+
+ /* Ignore illegal locations */
+ if (!in_bounds(y, x)) continue;
+
+ /* Require "naked" floor space */
+ if (!cave_naked_bold(y, x)) continue;
+
+ /* No teleporting into vaults and such */
+ if (cave[y][x].info & (CAVE_ICKY)) continue;
+
+ /* This grid looks good */
+ look = FALSE;
+
+ /* Stop looking */
+ break;
+ }
+
+ /* Increase the maximum distance */
+ dis = dis * 2;
+
+ /* Decrease the minimum distance */
+ min = min / 2;
+
+ /* Stop after MAX_TRIES tries */
+ if (tries > MAX_TRIES) return;
+ }
+
+ *ny = y;
+ *nx = x;
+}
+
+/*
+ * Teleport a monster to a grid near the given location
+ *
+ * This function is slightly obsessive about correctness.
+ */
+void teleport_monster_to(int m_idx, int ny, int nx)
+{
+ int y, x, oy, ox, dis = 0, ctr = 0;
+ monster_type *m_ptr = &m_list[m_idx];
+
+ if (p_ptr->resist_continuum)
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return;
+ }
+
+ if (p_ptr->anti_tele)
+ {
+ msg_print("A mysterious force prevents you from teleporting!");
+ return;
+ }
+
+ /* Find a usable location */
+ while (1)
+ {
+ /* Pick a nearby legal location */
+ while (1)
+ {
+ y = rand_spread(ny, dis);
+ x = rand_spread(nx, dis);
+ if (in_bounds(y, x)) break;
+ }
+
+ /* Not on the player's grid */
+ /* Accept "naked" floor grids */
+ if (cave_naked_bold(y, x) && (y != p_ptr->py) && (x != p_ptr->px)) break;
+
+ /* Occasionally advance the distance */
+ if (++ctr > (4 * dis * dis + 4 * dis + 1))
+ {
+ ctr = 0;
+ dis++;
+ }
+ }
+
+ /* Sound */
+ sound(SOUND_TPOTHER);
+
+ /* Save the old position */
+ oy = m_ptr->fy;
+ ox = m_ptr->fx;
+ cave[oy][ox].m_idx = 0;
+
+ /* Move the monster */
+ m_ptr->fy = y;
+ m_ptr->fx = x;
+ cave[y][x].m_idx = m_idx;
+ last_teleportation_y = y;
+ last_teleportation_x = x;
+
+ /* Update the monster (new location) */
+ update_mon(m_idx, TRUE);
+
+ /* Redraw the old spot */
+ lite_spot(oy, ox);
+
+ /* Redraw the new spot */
+ lite_spot(m_ptr->fy, m_ptr->fx);
+}
+
+
+/*
+ * Teleport player to a grid near the given location
+ *
+ * This function is slightly obsessive about correctness.
+ * This function allows teleporting into vaults (!)
+ */
+void teleport_player_to(int ny, int nx)
+{
+ int y, x, oy, ox, dis = 0, ctr = 0;
+
+ if (p_ptr->resist_continuum)
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return;
+ }
+
+ if (p_ptr->anti_tele)
+ {
+ msg_print("A mysterious force prevents you from teleporting!");
+ return;
+ }
+
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("No teleport on special levels...");
+ return;
+ }
+
+ /* Rooted means no move */
+ if (p_ptr->tim_roots) return;
+
+ /* Find a usable location */
+ while (1)
+ {
+ /* Pick a nearby legal location */
+ while (1)
+ {
+ y = rand_spread(ny, dis);
+ x = rand_spread(nx, dis);
+ if (in_bounds(y, x)) break;
+ }
+
+ /* Accept "naked" floor grids */
+ if (cave_naked_bold2(y, x)) break;
+
+ /* Occasionally advance the distance */
+ if (++ctr > (4 * dis * dis + 4 * dis + 1))
+ {
+ ctr = 0;
+ dis++;
+ }
+ }
+
+ /* Sound */
+ sound(SOUND_TELEPORT);
+
+ /* Save the old location */
+ oy = p_ptr->py;
+ ox = p_ptr->px;
+
+ /* Move the player */
+ p_ptr->py = y;
+ p_ptr->px = x;
+ last_teleportation_y = y;
+ last_teleportation_x = x;
+
+ /* Redraw the old spot */
+ lite_spot(oy, ox);
+
+ /* Redraw the new spot */
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Check for new panel (redraw map) */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Redraw trap detection status */
+ p_ptr->redraw |= (PR_DTRAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff XXX XXX XXX */
+ handle_stuff();
+}
+
+
+
+/*
+ * Teleport the player one level up or down (random when legal)
+ */
+void teleport_player_level(void)
+{
+ /* No effect in arena or quest */
+ if (p_ptr->inside_arena || p_ptr->inside_quest)
+ {
+ msg_print("There is no effect.");
+ return;
+ }
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("No teleport on special levels...");
+ return;
+ }
+ if (dungeon_flags2 & DF2_NO_EASY_MOVE)
+ {
+ msg_print("Some powerfull force prevents your from teleporting.");
+ return;
+ }
+
+ if (p_ptr->resist_continuum)
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return;
+ }
+
+ /* Hack -- when you are fated to die, you cant cheat :) */
+ if (dungeon_type == DUNGEON_DEATH)
+ {
+ msg_print("A mysterious force prevents you from teleporting!");
+ return;
+ }
+
+ if (p_ptr->anti_tele)
+ {
+ msg_print("A mysterious force prevents you from teleporting!");
+ return;
+ }
+
+ /* Rooted means no move */
+ if (p_ptr->tim_roots) return;
+
+ if (!dun_level)
+ {
+ msg_print("You sink through the floor.");
+
+ autosave_checkpoint();
+
+ dun_level++;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ }
+ else if (is_quest(dun_level) || (dun_level >= MAX_DEPTH - 1))
+ {
+ msg_print("You rise up through the ceiling.");
+
+ autosave_checkpoint();
+
+ dun_level--;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ }
+ else if (rand_int(100) < 50)
+ {
+ msg_print("You rise up through the ceiling.");
+
+ autosave_checkpoint();
+
+ dun_level--;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ }
+ else
+ {
+ msg_print("You sink through the floor.");
+
+ autosave_checkpoint();
+
+ dun_level++;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ }
+
+ /* Sound */
+ sound(SOUND_TPLEVEL);
+}
+
+
+
+/*
+ * Recall the player to town or dungeon
+ */
+void recall_player(int d, int f)
+{
+ /* Rooted means no move */
+ if (p_ptr->tim_roots)
+ {
+ msg_print("Your roots prevent the recall.");
+ return;
+ }
+
+
+ if (dun_level && (max_dlv[dungeon_type] > dun_level) &&
+ !p_ptr->inside_quest)
+ {
+ if (get_check("Reset recall depth? "))
+ max_dlv[dungeon_type] = dun_level;
+
+ }
+ if (!p_ptr->word_recall)
+ {
+ p_ptr->word_recall = rand_int(d) + f;
+ msg_print("The air about you becomes charged...");
+ }
+ else
+ {
+ p_ptr->word_recall = 0;
+ msg_print("A tension leaves the air around you...");
+ }
+ p_ptr->redraw |= (PR_DEPTH);
+}
+
+
+
+/*
+ * Get a legal "multi-hued" color for drawing "spells"
+ */
+static byte mh_attr(int max)
+{
+ switch (randint(max))
+ {
+ case 1:
+ return (TERM_RED);
+ case 2:
+ return (TERM_GREEN);
+ case 3:
+ return (TERM_BLUE);
+ case 4:
+ return (TERM_YELLOW);
+ case 5:
+ return (TERM_ORANGE);
+ case 6:
+ return (TERM_VIOLET);
+ case 7:
+ return (TERM_L_RED);
+ case 8:
+ return (TERM_L_GREEN);
+ case 9:
+ return (TERM_L_BLUE);
+ case 10:
+ return (TERM_UMBER);
+ case 11:
+ return (TERM_L_UMBER);
+ case 12:
+ return (TERM_SLATE);
+ case 13:
+ return (TERM_WHITE);
+ case 14:
+ return (TERM_L_WHITE);
+ case 15:
+ return (TERM_L_DARK);
+ }
+
+ return (TERM_WHITE);
+}
+
+
+/*
+ * Return a color to use for the bolt/ball spells
+ */
+byte spell_color(int type)
+{
+ /* Hooks! */
+ if (process_hooks_ret(HOOK_GF_COLOR, "d", "(d,d)", type, streq(ANGBAND_GRAF, "new")))
+ {
+ return process_hooks_return[0].num;
+ }
+
+ /* Check if A.B.'s new graphics should be used (rr9) */
+ if (streq(ANGBAND_GRAF, "new"))
+ {
+ /* Analyze */
+ switch (type)
+ {
+ case GF_MISSILE:
+ return (0x0F);
+ case GF_ACID:
+ return (0x04);
+ case GF_ELEC:
+ return (0x02);
+ case GF_FIRE:
+ return (0x00);
+ case GF_COLD:
+ return (0x01);
+ case GF_POIS:
+ return (0x03);
+ case GF_UNBREATH:
+ return (0x03);
+ case GF_HOLY_FIRE:
+ return (0x00);
+ case GF_HELL_FIRE:
+ return (0x00);
+ case GF_MANA:
+ return (0x0E);
+ case GF_ARROW:
+ return (0x0F);
+ case GF_WATER:
+ return (0x04);
+ case GF_WAVE:
+ return (0x04);
+ case GF_NETHER:
+ return (0x07);
+ case GF_CHAOS:
+ return (mh_attr(15));
+ case GF_DISENCHANT:
+ return (0x05);
+ case GF_NEXUS:
+ return (0x0C);
+ case GF_CONFUSION:
+ return (mh_attr(4));
+ case GF_SOUND:
+ return (0x09);
+ case GF_SHARDS:
+ return (0x08);
+ case GF_FORCE:
+ return (0x09);
+ case GF_INERTIA:
+ return (0x09);
+ case GF_GRAVITY:
+ return (0x09);
+ case GF_TIME:
+ return (0x09);
+ case GF_LITE_WEAK:
+ return (0x06);
+ case GF_LITE:
+ return (0x06);
+ case GF_DARK_WEAK:
+ return (0x07);
+ case GF_DARK:
+ return (0x07);
+ case GF_PLASMA:
+ return (0x0B);
+ case GF_METEOR:
+ return (0x00);
+ case GF_ICE:
+ return (0x01);
+ case GF_ROCKET:
+ return (0x0F);
+ case GF_DEATH_RAY:
+ return (0x07);
+ case GF_NUKE:
+ return (mh_attr(2));
+ case GF_DISINTEGRATE:
+ return (0x05);
+ case GF_PSI:
+ case GF_PSI_DRAIN:
+ case GF_TELEKINESIS:
+ case GF_DOMINATION:
+ return (0x09);
+ }
+
+ }
+
+ /* Normal tiles or ASCII */
+ else
+ {
+ /* Analyze */
+ switch (type)
+ {
+ case GF_MISSILE:
+ return (TERM_SLATE);
+ case GF_ACID:
+ return (randint(5) < 3 ? TERM_YELLOW : TERM_L_GREEN);
+ case GF_ELEC:
+ return (randint(7) < 6 ? TERM_WHITE : (randint(4) == 1 ? TERM_BLUE : TERM_L_BLUE));
+ case GF_FIRE:
+ return (randint(6) < 4 ? TERM_YELLOW : (randint(4) == 1 ? TERM_RED : TERM_L_RED));
+ case GF_COLD:
+ return (randint(6) < 4 ? TERM_WHITE : TERM_L_WHITE);
+ case GF_POIS:
+ return (randint(5) < 3 ? TERM_L_GREEN : TERM_GREEN);
+ case GF_UNBREATH:
+ return (randint(7) < 3 ? TERM_L_GREEN : TERM_GREEN);
+ case GF_HOLY_FIRE:
+ return (randint(5) == 1 ? TERM_ORANGE : TERM_WHITE);
+ case GF_HELL_FIRE:
+ return (randint(6) == 1 ? TERM_RED : TERM_L_DARK);
+ case GF_MANA:
+ return (randint(5) != 1 ? TERM_VIOLET : TERM_L_BLUE);
+ case GF_ARROW:
+ return (TERM_L_UMBER);
+ case GF_WATER:
+ return (randint(4) == 1 ? TERM_L_BLUE : TERM_BLUE);
+ case GF_WAVE:
+ return (randint(4) == 1 ? TERM_L_BLUE : TERM_BLUE);
+ case GF_NETHER:
+ return (randint(4) == 1 ? TERM_SLATE : TERM_L_DARK);
+ case GF_CHAOS:
+ return (mh_attr(15));
+ case GF_DISENCHANT:
+ return (randint(5) != 1 ? TERM_L_BLUE : TERM_VIOLET);
+ case GF_NEXUS:
+ return (randint(5) < 3 ? TERM_L_RED : TERM_VIOLET);
+ case GF_CONFUSION:
+ return (mh_attr(4));
+ case GF_SOUND:
+ return (randint(4) == 1 ? TERM_VIOLET : TERM_WHITE);
+ case GF_SHARDS:
+ return (randint(5) < 3 ? TERM_UMBER : TERM_SLATE);
+ case GF_FORCE:
+ return (randint(5) < 3 ? TERM_L_WHITE : TERM_ORANGE);
+ case GF_INERTIA:
+ return (randint(5) < 3 ? TERM_SLATE : TERM_L_WHITE);
+ case GF_GRAVITY:
+ return (randint(3) == 1 ? TERM_L_UMBER : TERM_UMBER);
+ case GF_TIME:
+ return (randint(2) == 1 ? TERM_WHITE : TERM_L_DARK);
+ case GF_LITE_WEAK:
+ return (randint(3) == 1 ? TERM_ORANGE : TERM_YELLOW);
+ case GF_LITE:
+ return (randint(4) == 1 ? TERM_ORANGE : TERM_YELLOW);
+ case GF_DARK_WEAK:
+ return (randint(3) == 1 ? TERM_DARK : TERM_L_DARK);
+ case GF_DARK:
+ return (randint(4) == 1 ? TERM_DARK : TERM_L_DARK);
+ case GF_PLASMA:
+ return (randint(5) == 1 ? TERM_RED : TERM_L_RED);
+ case GF_METEOR:
+ return (randint(3) == 1 ? TERM_RED : TERM_UMBER);
+ case GF_ICE:
+ return (randint(4) == 1 ? TERM_L_BLUE : TERM_WHITE);
+ case GF_ROCKET:
+ return (randint(6) < 4 ? TERM_L_RED : (randint(4) == 1 ? TERM_RED : TERM_L_UMBER));
+ case GF_DEATH:
+ case GF_DEATH_RAY:
+ return (TERM_L_DARK);
+ case GF_NUKE:
+ return (mh_attr(2));
+ case GF_DISINTEGRATE:
+ return (randint(3) != 1 ? TERM_L_DARK : (randint(2) == 1 ? TERM_ORANGE : TERM_L_UMBER));
+ case GF_PSI:
+ case GF_PSI_DRAIN:
+ case GF_TELEKINESIS:
+ case GF_DOMINATION:
+ return (randint(3) != 1 ? TERM_L_BLUE : TERM_WHITE);
+ }
+ }
+
+ /* Standard "color" */
+ return (TERM_WHITE);
+}
+
+
+/*
+ * Find the attr/char pair to use for a spell effect
+ *
+ * It is moving (or has moved) from (x,y) to (nx,ny).
+ *
+ * If the distance is not "one", we (may) return "*".
+ */
+static u16b bolt_pict(int y, int x, int ny, int nx, int typ)
+{
+ int base;
+
+ byte k;
+
+ byte a;
+ char c;
+
+ /* No motion (*) */
+ if ((ny == y) && (nx == x)) base = 0x30;
+
+ /* Vertical (|) */
+ else if (nx == x) base = 0x40;
+
+ /* Horizontal (-) */
+ else if (ny == y) base = 0x50;
+
+ /* Diagonal (/) */
+ else if ((ny - y) == (x - nx)) base = 0x60;
+
+ /* Diagonal (\) */
+ else if ((ny - y) == (nx - x)) base = 0x70;
+
+ /* Weird (*) */
+ else base = 0x30;
+
+ /* Basic spell color */
+ k = spell_color(typ);
+
+ /* Obtain attr/char */
+ a = misc_to_attr[base + k];
+ c = misc_to_char[base + k];
+
+ /* Create pict */
+ return (PICT(a, c));
+}
+
+/*
+ * Cast the spelbound spells
+ */
+void spellbinder_trigger()
+{
+ int i;
+
+ cmsg_print(TERM_L_GREEN, "The spellbinder is triggered!");
+ for (i = 0; i < p_ptr->spellbinder_num; i++)
+ {
+ msg_format("Triggering spell %s.", school_spells[p_ptr->spellbinder[i]].name);
+ exec_lua(format("cast_school_spell(%d, spell(%d), TRUE)", p_ptr->spellbinder[i], p_ptr->spellbinder[i]));
+ }
+ p_ptr->spellbinder_num = 0;
+ p_ptr->spellbinder_trigger = 0;
+}
+
+
+/*
+ * Decreases players hit points and sets death flag if necessary
+ *
+ * XXX XXX XXX Invulnerability needs to be changed into a "shield"
+ *
+ * XXX XXX XXX Hack -- this function allows the user to save (or quit)
+ * the game when he dies, since the "You die." message is shown before
+ * setting the player to "dead".
+ */
+void take_hit(int damage, cptr hit_from)
+{
+ object_type *o_ptr = &p_ptr->inventory[INVEN_CARRY];
+ int old_chp = p_ptr->chp;
+
+ bool_ pen_invuln = FALSE;
+ bool_ monster_take = FALSE;
+
+ char death_message[80];
+
+ int warning = (p_ptr->mhp * hitpoint_warn / 10);
+ int percent;
+
+ /* Paranoia */
+ if (death) return;
+
+ /* Disturb */
+ disturb(1, 0);
+
+ /* Apply "invulnerability" */
+ if (p_ptr->invuln && (damage < 9000))
+ {
+ if (randint(PENETRATE_INVULNERABILITY) == 1)
+ {
+ pen_invuln = TRUE;
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ /* Apply disruption shield */
+ if (p_ptr->disrupt_shield)
+ {
+ if (p_ptr->csp > (damage * 2))
+ {
+ p_ptr->csp -= (damage * 2);
+ damage = 0;
+ }
+ else
+ {
+ damage -= p_ptr->csp / 2;
+ p_ptr->csp = 0;
+ p_ptr->csp_frac = 0;
+ }
+
+ /* Display the mana */
+ p_ptr->redraw |= (PR_MANA);
+ }
+
+ /* Hurt the wielded monster if any */
+ if ((o_ptr->k_idx) && (magik(5 + get_skill(SKILL_SYMBIOTIC))) && (!carried_monster_hit))
+ {
+ cptr sym_name = symbiote_name(TRUE);
+
+ if (o_ptr->pval2 - damage <= 0)
+ {
+ cmsg_format(TERM_L_RED,
+ "%s dies from protecting you, you feel very sad...",
+ sym_name);
+ inc_stack_size_ex(INVEN_CARRY, -1, OPTIMIZE, NO_DESCRIBE);
+ damage -= o_ptr->pval2;
+ o_ptr->pval2 = 0;
+ p_ptr->redraw |= PR_MH;
+ }
+ else
+ {
+ msg_format("%s takes the damage instead of you.", sym_name);
+ o_ptr->pval2 -= damage;
+ monster_take = TRUE;
+ }
+
+ carried_monster_hit = FALSE;
+
+ /* Display the monster hitpoints */
+ p_ptr->redraw |= (PR_MH);
+ }
+
+ /* Hurt the player */
+ if (!monster_take) p_ptr->chp -= damage;
+
+ /* Display the hitpoints */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ if (pen_invuln)
+ cmsg_print(TERM_YELLOW, "The attack penetrates your shield of invulnerability!");
+
+ /* Dead player */
+ if (p_ptr->chp < 0)
+ {
+ /* Necromancers get a special treatment */
+ if (((!has_ability(AB_UNDEAD_FORM)) || ((p_ptr->necro_extra & CLASS_UNDEAD))))
+ {
+ /* Sound */
+ sound(SOUND_DEATH);
+
+ /* Hack -- Note death */
+ if (!last_words)
+ {
+ cmsg_print(TERM_RED, "You die.");
+ msg_print(NULL);
+ }
+ else
+ {
+ (void)get_rnd_line("death.txt", death_message);
+ cmsg_print(TERM_RED, death_message);
+ }
+
+ /* Note cause of death */
+ (void)strcpy(died_from, hit_from);
+
+ if (p_ptr->image) strcat(died_from, "(?)");
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+
+ /* No longer a winner */
+ total_winner = FALSE;
+
+
+ /* Note death */
+ death = TRUE;
+
+ if (get_check("Dump the screen? "))
+ {
+ do_cmd_html_dump();
+ }
+
+ /* Dead */
+ return;
+ }
+ /* Just turn the necromancer into an undead */
+ else
+ {
+ p_ptr->necro_extra |= CLASS_UNDEAD;
+ p_ptr->necro_extra2 = p_ptr->lev + (rand_int(p_ptr->lev / 2) - (p_ptr->lev / 4));
+ if (p_ptr->necro_extra2 < 1) p_ptr->necro_extra2 = 1;
+ cmsg_format(TERM_L_DARK, "You have to kill %d monster%s to be brought back to life.", p_ptr->necro_extra2, (p_ptr->necro_extra2 == 1) ? "" : "s");
+
+ /* MEGA-HACK !!! */
+ calc_hitpoints();
+
+ /* Enforce maximum */
+ p_ptr->chp = p_ptr->mhp;
+ p_ptr->chp_frac = 0;
+
+ do_cmd_wiz_cure_all();
+
+ /* Display the hitpoints */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+ }
+
+ /* Hitpoint warning */
+ if (p_ptr->chp < warning)
+ {
+ /* Hack -- bell on first notice */
+ if (alert_hitpoint && (old_chp > warning)) bell();
+
+ sound(SOUND_WARN);
+
+ /* Message */
+ if (p_ptr->necro_extra & CLASS_UNDEAD)
+ cmsg_print(TERM_RED, "*** LOW DEATHPOINT WARNING! ***");
+ else
+ cmsg_print(TERM_RED, "*** LOW HITPOINT WARNING! ***");
+ msg_print(NULL);
+ }
+
+ /* How much life is left ? */
+ percent = p_ptr->chp * 100 / p_ptr->mhp;
+
+ /* Check the spellbinder trigger */
+ if (p_ptr->spellbinder_trigger == SPELLBINDER_HP75)
+ {
+ /* Trigger ?! */
+ if (percent <= 75)
+ spellbinder_trigger();
+ }
+ else if (p_ptr->spellbinder_trigger == SPELLBINDER_HP50)
+ {
+ /* Trigger ?! */
+ if (percent <= 50)
+ spellbinder_trigger();
+ }
+ else if (p_ptr->spellbinder_trigger == SPELLBINDER_HP25)
+ {
+ /* Trigger ?! */
+ if (percent <= 25)
+ spellbinder_trigger();
+ }
+
+ /* Melkor acn summon to help you */
+ if (percent < 25)
+ {
+ PRAY_GOD(GOD_MELKOR)
+ {
+ int chance = p_ptr->grace / 500; /* * 100 / 50000; */
+
+ if (magik(chance - 10))
+ {
+ int i;
+ int type = SUMMON_DEMON;
+
+ if (magik(50))
+ type = SUMMON_UNDEAD;
+
+ if (p_ptr->grace > 10000)
+ {
+ if (type == SUMMON_DEMON)
+ type = SUMMON_HI_DEMON;
+ else
+ type = SUMMON_HI_UNDEAD;
+ }
+
+ chance /= 10;
+ if (chance < 1) chance = 1;
+ for (i = 0; i < chance; i++)
+ summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level / 2, type, FALSE);
+ msg_print("Melkor summons monsters to help you!");
+ }
+ }
+ }
+
+ if (player_char_health)
+ lite_spot(p_ptr->py, p_ptr->px);
+}
+
+
+/* Decrease player's sanity. This is a copy of the function above. */
+void take_sanity_hit(int damage, cptr hit_from)
+{
+ int old_csane = p_ptr->csane;
+
+ char death_message[80];
+
+ int warning = (p_ptr->msane * hitpoint_warn / 10);
+
+
+ /* Paranoia */
+ if (death) return;
+
+ /* Disturb */
+ disturb(1, 0);
+
+
+ /* Hurt the player */
+ p_ptr->csane -= damage;
+
+ /* Display the hitpoints */
+ p_ptr->redraw |= (PR_SANITY);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Dead player */
+ if (p_ptr->csane < 0)
+ {
+ /* Sound */
+ sound(SOUND_DEATH);
+
+ /* Hack -- Note death */
+ cmsg_print(TERM_VIOLET, "You turn into an unthinking vegetable.");
+ if (!last_words)
+ {
+ cmsg_print(TERM_RED, "You die.");
+ msg_print(NULL);
+ }
+ else
+ {
+ (void)get_rnd_line("death.txt", death_message);
+ cmsg_print(TERM_RED, death_message);
+ }
+
+ /* Note cause of death */
+ (void)strcpy(died_from, hit_from);
+
+ if (p_ptr->image) strcat(died_from, "(?)");
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+
+ /* Note death */
+ death = TRUE;
+
+ if (get_check("Dump the screen? "))
+ {
+ do_cmd_html_dump();
+ }
+
+ /* Dead */
+ return;
+ }
+
+ /* Hitpoint warning */
+ if (p_ptr->csane < warning)
+ {
+ /* Hack -- bell on first notice */
+ if (alert_hitpoint && (old_csane > warning)) bell();
+
+ sound(SOUND_WARN);
+
+ /* Message */
+ cmsg_print(TERM_RED, "*** LOW SANITY WARNING! ***");
+ msg_print(NULL);
+ }
+}
+
+
+/*
+ * Note that amulets, rods, and high-level spell books are immune
+ * to "inventory damage" of any kind. Also sling ammo and shovels.
+ */
+
+
+/*
+ * Does a given class of objects (usually) hate acid?
+ * Note that acid can either melt or corrode something.
+ */
+static bool_ hates_acid(object_type *o_ptr)
+{
+ /* Analyze the type */
+ switch (o_ptr->tval)
+ {
+ /* Wearable items */
+ case TV_ARROW:
+ case TV_BOLT:
+ case TV_BOW:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_HELM:
+ case TV_CROWN:
+ case TV_SHIELD:
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_CLOAK:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ {
+ return (TRUE);
+ }
+
+ /* Staffs/Scrolls are wood/paper */
+ case TV_STAFF:
+ case TV_SCROLL:
+ {
+ return (TRUE);
+ }
+
+ /* Ouch */
+ case TV_CHEST:
+ {
+ return (TRUE);
+ }
+
+ /* Junk is useless */
+ case TV_SKELETON:
+ case TV_BOTTLE:
+ case TV_EGG:
+ {
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+
+/*
+ * Does a given object (usually) hate electricity?
+ */
+static bool_ hates_elec(object_type *o_ptr)
+{
+ switch (o_ptr->tval)
+ {
+ case TV_RING:
+ case TV_WAND:
+ case TV_EGG:
+ {
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+
+/*
+ * Does a given object (usually) hate fire?
+ * Hafted/Polearm weapons have wooden shafts.
+ * Arrows/Bows are mostly wooden.
+ */
+static bool_ hates_fire(object_type *o_ptr)
+{
+ /* Analyze the type */
+ switch (o_ptr->tval)
+ {
+ /* Special case for archers */
+ case TV_ARROW:
+ {
+ return TRUE;
+ };
+
+ /* Wearable */
+ case TV_LITE:
+ case TV_BOW:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_CLOAK:
+ case TV_SOFT_ARMOR:
+ {
+ return (TRUE);
+ }
+
+ /* Books */
+ case TV_BOOK:
+ case TV_SYMBIOTIC_BOOK:
+ case TV_MUSIC_BOOK:
+ {
+ return (TRUE);
+ }
+
+ /* Chests */
+ case TV_CHEST:
+ {
+ return (TRUE);
+ }
+
+ /* Staffs/Scrolls burn */
+ case TV_STAFF:
+ case TV_SCROLL:
+ case TV_EGG:
+ {
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+
+/*
+ * Does a given object (usually) hate cold?
+ */
+static bool_ hates_cold(object_type *o_ptr)
+{
+ switch (o_ptr->tval)
+ {
+ case TV_POTION2:
+ case TV_POTION:
+ case TV_FLASK:
+ case TV_BOTTLE:
+ case TV_EGG:
+ {
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+
+
+
+
+
+
+
+
+/*
+ * Melt something
+ */
+static int set_acid_destroy(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ if (!hates_acid(o_ptr)) return (FALSE);
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if (f3 & (TR3_IGNORE_ACID)) return (FALSE);
+ return (TRUE);
+}
+
+
+/*
+ * Electrical damage
+ */
+static int set_elec_destroy(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ if (!hates_elec(o_ptr)) return (FALSE);
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if (f3 & (TR3_IGNORE_ELEC)) return (FALSE);
+ return (TRUE);
+}
+
+
+/*
+ * Burn something
+ */
+static int set_fire_destroy(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ if (!hates_fire(o_ptr)) return (FALSE);
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if (f3 & (TR3_IGNORE_FIRE)) return (FALSE);
+ return (TRUE);
+}
+
+
+/*
+ * Freeze things
+ */
+static int set_cold_destroy(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ if (!hates_cold(o_ptr)) return (FALSE);
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if (f3 & (TR3_IGNORE_COLD)) return (FALSE);
+ return (TRUE);
+}
+
+
+
+
+/*
+ * This seems like a pretty standard "typedef"
+ */
+typedef int (*inven_func)(object_type *);
+
+/*
+ * Destroys a type of item on a given percent chance
+ * Note that missiles are no longer necessarily all destroyed
+ * Destruction taken from "melee.c" code for "stealing".
+ * Returns number of items destroyed.
+ */
+static int inven_damage(inven_func typ, int perc)
+{
+ int i, j, k, amt;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+
+ /* Count the casualties */
+ k = 0;
+
+ /* Scan through the slots backwards */
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Hack -- for now, skip artifacts */
+ if (artifact_p(o_ptr) || o_ptr->art_name) continue;
+
+ /* Give this item slot a shot at death */
+ if ((*typ)(o_ptr))
+ {
+ /* Count the casualties */
+ for (amt = j = 0; j < o_ptr->number; ++j)
+ {
+ if (rand_int(100) < perc) amt++;
+ }
+
+ /* Some casualities */
+ if (amt)
+ {
+ /* Get a description */
+ object_desc(o_name, o_ptr, FALSE, 3);
+
+ /* Message */
+ msg_format("%sour %s (%c) %s destroyed!",
+ ((o_ptr->number > 1) ?
+ ((amt == o_ptr->number) ? "All of y" :
+ (amt > 1 ? "Some of y" : "One of y")) : "Y"),
+ o_name, index_to_label(i),
+ ((amt > 1) ? "were" : "was"));
+
+ /* Potions smash open */
+ if (k_info[o_ptr->k_idx].tval == TV_POTION)
+ {
+ (void)potion_smash_effect(0, p_ptr->py, p_ptr->px, o_ptr->sval);
+ }
+
+ /*
+ * Hack -- If rods or wand are destroyed, the total maximum
+ * timeout or charges of the stack needs to be reduced,
+ * unless all the items are being destroyed. -LM-
+ */
+ if ((o_ptr->tval == TV_WAND)
+ && (amt < o_ptr->number))
+ {
+ o_ptr->pval -= o_ptr->pval * amt / o_ptr->number;
+ }
+
+ /* Destroy "amt" items */
+ inc_stack_size_ex(i, -amt, OPTIMIZE, NO_DESCRIBE);
+
+ /* Count the casualties */
+ k += amt;
+ }
+ }
+ }
+
+ /* Return the casualty count */
+ return (k);
+}
+
+
+
+
+/*
+ * Acid has hit the player, attempt to affect some armor.
+ *
+ * Note that the "base armor" of an object never changes.
+ *
+ * If any armor is damaged (or resists), the player takes less damage.
+ */
+static int minus_ac(void)
+{
+ object_type *o_ptr = NULL;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ char o_name[80];
+
+
+ /* Pick a (possibly empty) inventory slot */
+ switch (randint(6))
+ {
+ case 1:
+ o_ptr = &p_ptr->inventory[INVEN_BODY];
+ break;
+ case 2:
+ o_ptr = &p_ptr->inventory[INVEN_ARM];
+ break;
+ case 3:
+ o_ptr = &p_ptr->inventory[INVEN_OUTER];
+ break;
+ case 4:
+ o_ptr = &p_ptr->inventory[INVEN_HANDS];
+ break;
+ case 5:
+ o_ptr = &p_ptr->inventory[INVEN_HEAD];
+ break;
+ case 6:
+ o_ptr = &p_ptr->inventory[INVEN_FEET];
+ break;
+ }
+
+ /* Nothing to damage */
+ if (!o_ptr->k_idx) return (FALSE);
+
+ /* No damage left to be done */
+ if (o_ptr->ac + o_ptr->to_a <= 0) return (FALSE);
+
+
+ /* Describe */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Object resists */
+ if (f3 & (TR3_IGNORE_ACID))
+ {
+ msg_format("Your %s is unaffected!", o_name);
+
+ return (TRUE);
+ }
+
+ /* Message */
+ msg_format("Your %s is damaged!", o_name);
+
+ /* Damage the item */
+ o_ptr->to_a--;
+
+ /* Calculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP | PW_PLAYER);
+
+ /* Item was damaged */
+ return (TRUE);
+}
+
+
+/*
+ * Hurt the player with Acid
+ */
+void acid_dam(int dam, cptr kb_str)
+{
+ int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
+
+ /* Total Immunity */
+ if (p_ptr->immune_acid || (dam <= 0)) return;
+
+ /* Resist the damage */
+ if (p_ptr->resist_acid) dam = (dam + 2) / 3;
+ if (p_ptr->oppose_acid) dam = (dam + 2) / 3;
+
+ if ((!(p_ptr->oppose_acid || p_ptr->resist_acid)) &&
+ randint(HURT_CHANCE) == 1)
+ (void) do_dec_stat(A_CHR, STAT_DEC_NORMAL);
+
+ /* If any armor gets hit, defend the player */
+ if (minus_ac()) dam = (dam + 1) / 2;
+
+ /* Take damage */
+ take_hit(dam, kb_str);
+
+ /* Inventory damage */
+ if (!(p_ptr->oppose_acid && p_ptr->resist_acid))
+ inven_damage(set_acid_destroy, inv);
+}
+
+
+/*
+ * Hurt the player with electricity
+ */
+void elec_dam(int dam, cptr kb_str)
+{
+ int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
+
+ /* Total immunity */
+ if (p_ptr->immune_elec || (dam <= 0)) return;
+
+ /* Resist the damage */
+ if (p_ptr->oppose_elec) dam = (dam + 2) / 3;
+ if (p_ptr->resist_elec) dam = (dam + 2) / 3;
+
+ if ((!(p_ptr->oppose_elec || p_ptr->resist_elec)) &&
+ randint(HURT_CHANCE) == 1)
+ (void) do_dec_stat(A_DEX, STAT_DEC_NORMAL);
+
+ /* Take damage */
+ take_hit(dam, kb_str);
+
+ /* Inventory damage */
+ if (!(p_ptr->oppose_elec && p_ptr->resist_elec))
+ inven_damage(set_elec_destroy, inv);
+}
+
+
+
+
+/*
+ * Hurt the player with Fire
+ */
+void fire_dam(int dam, cptr kb_str)
+{
+ int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
+
+ /* Totally immune */
+ if (p_ptr->immune_fire || (dam <= 0)) return;
+
+ /* Resist the damage */
+ if (p_ptr->sensible_fire) dam = (dam + 2) * 2;
+ if (p_ptr->resist_fire) dam = (dam + 2) / 3;
+ if (p_ptr->oppose_fire) dam = (dam + 2) / 3;
+
+ if ((!(p_ptr->oppose_fire || p_ptr->resist_fire)) &&
+ randint(HURT_CHANCE) == 1)
+ (void) do_dec_stat(A_STR, STAT_DEC_NORMAL);
+
+
+ /* Take damage */
+ take_hit(dam, kb_str);
+
+ /* Inventory damage */
+ if (!(p_ptr->resist_fire && p_ptr->oppose_fire))
+ inven_damage(set_fire_destroy, inv);
+}
+
+
+/*
+ * Hurt the player with Cold
+ */
+void cold_dam(int dam, cptr kb_str)
+{
+ int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
+
+ /* Total immunity */
+ if (p_ptr->immune_cold || (dam <= 0)) return;
+
+ /* Resist the damage */
+ if (p_ptr->resist_cold) dam = (dam + 2) / 3;
+ if (p_ptr->oppose_cold) dam = (dam + 2) / 3;
+
+ if ((!(p_ptr->oppose_cold || p_ptr->resist_cold)) &&
+ randint(HURT_CHANCE) == 1)
+ (void) do_dec_stat(A_STR, STAT_DEC_NORMAL);
+
+ /* Take damage */
+ take_hit(dam, kb_str);
+
+ /* Inventory damage */
+ if (!(p_ptr->resist_cold && p_ptr->oppose_cold))
+ inven_damage(set_cold_destroy, inv);
+}
+
+
+
+
+
+/*
+ * Increases a stat by one randomized level -RAK-
+ *
+ * Note that this function (used by stat potions) now restores
+ * the stat BEFORE increasing it.
+ */
+bool_ inc_stat(int stat)
+{
+ int value, gain;
+
+ /* Then augment the current/max stat */
+ value = p_ptr->stat_cur[stat];
+
+ /* Cannot go above 18/100 */
+ if (value < 18 + 100)
+ {
+ /* Gain one (sometimes two) points */
+ if (value < 18)
+ {
+ gain = ((rand_int(100) < 75) ? 1 : 2);
+ value += gain;
+ }
+
+ /* Gain 1/6 to 1/3 of distance to 18/100 */
+ else if (value < 18 + 98)
+ {
+ /* Approximate gain value */
+ gain = (((18 + 100) - value) / 2 + 3) / 2;
+
+ /* Paranoia */
+ if (gain < 1) gain = 1;
+
+ /* Apply the bonus */
+ value += randint(gain) + gain / 2;
+
+ /* Maximal value */
+ if (value > 18 + 99) value = 18 + 99;
+ }
+
+ /* Gain one point at a time */
+ else
+ {
+ value++;
+ }
+
+ /* Save the new value */
+ p_ptr->stat_cur[stat] = value;
+
+ /* Bring up the maximum too */
+ if (value > p_ptr->stat_max[stat])
+ {
+ p_ptr->stat_max[stat] = value;
+ }
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Success */
+ return (TRUE);
+ }
+
+ /* Nothing to gain */
+ return (FALSE);
+}
+
+
+
+/*
+ * Decreases a stat by an amount indended to vary from 0 to 100 percent.
+ *
+ * Amount could be a little higher in extreme cases to mangle very high
+ * stats from massive assaults. -CWS
+ *
+ * Note that "permanent" means that the *given* amount is permanent,
+ * not that the new value becomes permanent. This may not work exactly
+ * as expected, due to "weirdness" in the algorithm, but in general,
+ * if your stat is already drained, the "max" value will not drop all
+ * the way down to the "cur" value.
+ */
+bool_ dec_stat(int stat, int amount, int mode)
+{
+ int cur, max, loss = 0, same, res = FALSE;
+
+
+ /* Acquire current value */
+ cur = p_ptr->stat_cur[stat];
+ max = p_ptr->stat_max[stat];
+
+ /* Note when the values are identical */
+ same = (cur == max);
+
+ /* Damage "current" value */
+ if (cur > 3)
+ {
+ /* Handle "low" values */
+ if (cur <= 18)
+ {
+ if (amount > 90) cur--;
+ if (amount > 50) cur--;
+ if (amount > 20) cur--;
+ cur--;
+ }
+
+ /* Handle "high" values */
+ else
+ {
+ /* Hack -- Decrement by a random amount between one-quarter */
+ /* and one-half of the stat bonus times the percentage, with a */
+ /* minimum damage of half the percentage. -CWS */
+ loss = (((cur - 18) / 2 + 1) / 2 + 1);
+
+ /* Paranoia */
+ if (loss < 1) loss = 1;
+
+ /* Randomize the loss */
+ loss = ((randint(loss) + loss) * amount) / 100;
+
+ /* Maximal loss */
+ if (loss < amount / 2) loss = amount / 2;
+
+ /* Lose some points */
+ cur = cur - loss;
+
+ /* Hack -- Only reduce stat to 17 sometimes */
+ if (cur < 18) cur = (amount <= 20) ? 18 : 17;
+ }
+
+ /* Prevent illegal values */
+ if (cur < 3) cur = 3;
+
+ /* Something happened */
+ if (cur != p_ptr->stat_cur[stat]) res = TRUE;
+ }
+
+ /* Damage "max" value */
+ if ((mode == STAT_DEC_PERMANENT) && (max > 3))
+ {
+ /* Handle "low" values */
+ if (max <= 18)
+ {
+ if (amount > 90) max--;
+ if (amount > 50) max--;
+ if (amount > 20) max--;
+ max--;
+ }
+
+ /* Handle "high" values */
+ else
+ {
+ /* Hack -- Decrement by a random amount between one-quarter */
+ /* and one-half of the stat bonus times the percentage, with a */
+ /* minimum damage of half the percentage. -CWS */
+ loss = (((max - 18) / 2 + 1) / 2 + 1);
+ loss = ((randint(loss) + loss) * amount) / 100;
+ if (loss < amount / 2) loss = amount / 2;
+
+ /* Lose some points */
+ max = max - loss;
+
+ /* Hack -- Only reduce stat to 17 sometimes */
+ if (max < 18) max = (amount <= 20) ? 18 : 17;
+ }
+
+ /* Hack -- keep it clean */
+ if (same || (max < cur)) max = cur;
+
+ /* Something happened */
+ if (max != p_ptr->stat_max[stat]) res = TRUE;
+ }
+
+ /* Apply changes */
+ if (res)
+ {
+ if (mode == STAT_DEC_TEMPORARY)
+ {
+ u16b dectime;
+
+ /* a little crude, perhaps */
+ dectime = rand_int(max_dlv[dungeon_type] * 50) + 50;
+
+ /* Calculate loss */
+ loss = p_ptr->stat_cur[stat] - cur;
+
+ /* prevent overflow, stat_cnt = u16b */
+ /* or add another temporary drain... */
+ if ( ((p_ptr->stat_cnt[stat] + dectime) < p_ptr->stat_cnt[stat]) ||
+ (p_ptr->stat_los[stat] > 0) )
+
+ {
+ p_ptr->stat_cnt[stat] += dectime;
+ p_ptr->stat_los[stat] += loss;
+ }
+ else
+ {
+ p_ptr->stat_cnt[stat] = dectime;
+ p_ptr->stat_los[stat] = loss;
+ }
+ }
+
+ /* Actually set the stat to its new value. */
+ p_ptr->stat_cur[stat] = cur;
+ p_ptr->stat_max[stat] = max;
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+ }
+
+ /* Done */
+ return (res);
+}
+
+
+/*
+ * Restore a stat. Return TRUE only if this actually makes a difference.
+ */
+bool_ res_stat(int stat, bool_ full)
+{
+ /* Fully restore */
+ if (full)
+ {
+ /* Restore if needed */
+ if (p_ptr->stat_cur[stat] != p_ptr->stat_max[stat])
+ {
+ /* Restore */
+ p_ptr->stat_cur[stat] = p_ptr->stat_max[stat];
+
+ /* Remove temporary drain */
+ p_ptr->stat_cnt[stat] = 0;
+ p_ptr->stat_los[stat] = 0;
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Something happened */
+ return (TRUE);
+ }
+ }
+
+ /* Restore temporary drained stat */
+ else
+ {
+ /* Restore if needed */
+ if (p_ptr->stat_los[stat])
+ {
+ /* Restore */
+ p_ptr->stat_cur[stat] += p_ptr->stat_los[stat];
+
+ /* Remove temporary drain */
+ p_ptr->stat_cnt[stat] = 0;
+ p_ptr->stat_los[stat] = 0;
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Something happened */
+ return (TRUE);
+ }
+ }
+
+ /* Nothing to restore */
+ return (FALSE);
+}
+
+
+
+
+/*
+ * Apply disenchantment to the player's stuff
+ *
+ * XXX XXX XXX This function is also called from the "melee" code
+ *
+ * If "mode is set to 0 then a random slot will be used, if not the "mode"
+ * slot will be used.
+ *
+ * Return "TRUE" if the player notices anything
+ */
+bool_ apply_disenchant(int mode)
+{
+ int t = mode;
+ object_type *o_ptr;
+ char o_name[80];
+
+ if (!mode)
+ {
+ /* Pick a random slot */
+ switch (randint(8))
+ {
+ case 1:
+ t = INVEN_WIELD;
+ break;
+ case 2:
+ t = INVEN_BOW;
+ break;
+ case 3:
+ t = INVEN_BODY;
+ break;
+ case 4:
+ t = INVEN_OUTER;
+ break;
+ case 5:
+ t = INVEN_ARM;
+ break;
+ case 6:
+ t = INVEN_HEAD;
+ break;
+ case 7:
+ t = INVEN_HANDS;
+ break;
+ case 8:
+ t = INVEN_FEET;
+ break;
+ }
+ }
+
+ /* Get the item */
+ o_ptr = &p_ptr->inventory[t];
+
+ /* No item, nothing happens */
+ if (!o_ptr->k_idx) return (FALSE);
+
+
+ /* Nothing to disenchant */
+ if ((o_ptr->to_h <= 0) && (o_ptr->to_d <= 0) && (o_ptr->to_a <= 0))
+ {
+ /* Nothing to notice */
+ return (FALSE);
+ }
+
+
+ /* Describe the object */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+
+ /* Artifacts have 71% chance to resist */
+ if ((artifact_p(o_ptr) || o_ptr->art_name) && (rand_int(100) < 71))
+ {
+ /* Message */
+ msg_format("Your %s (%c) resist%s disenchantment!",
+ o_name, index_to_label(t),
+ ((o_ptr->number != 1) ? "" : "s"));
+
+ /* Notice */
+ return (TRUE);
+ }
+
+
+ /* Disenchant tohit */
+ if (o_ptr->to_h > 0) o_ptr->to_h--;
+ if ((o_ptr->to_h > 5) && (rand_int(100) < 20)) o_ptr->to_h--;
+
+ /* Disenchant todam */
+ if (o_ptr->to_d > 0) o_ptr->to_d--;
+ if ((o_ptr->to_d > 5) && (rand_int(100) < 20)) o_ptr->to_d--;
+
+ /* Disenchant toac */
+ if (o_ptr->to_a > 0) o_ptr->to_a--;
+ if ((o_ptr->to_a > 5) && (rand_int(100) < 20)) o_ptr->to_a--;
+
+ /* Message */
+ msg_format("Your %s (%c) %s disenchanted!",
+ o_name, index_to_label(t),
+ ((o_ptr->number != 1) ? "were" : "was"));
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP | PW_PLAYER);
+
+ /* Notice */
+ return (TRUE);
+}
+
+
+void corrupt_player(void)
+{
+ int max1, cur1, max2, cur2, ii, jj;
+
+ /* Pick a pair of stats */
+ ii = rand_int(6);
+ for (jj = ii; jj == ii; jj = rand_int(6)) /* loop */;
+
+ max1 = p_ptr->stat_max[ii];
+ cur1 = p_ptr->stat_cur[ii];
+ max2 = p_ptr->stat_max[jj];
+ cur2 = p_ptr->stat_cur[jj];
+
+ p_ptr->stat_max[ii] = max2;
+ p_ptr->stat_cur[ii] = cur2;
+ p_ptr->stat_max[jj] = max1;
+ p_ptr->stat_cur[jj] = cur1;
+
+ p_ptr->update |= (PU_BONUS);
+}
+
+
+/*
+ * Apply Nexus
+ */
+static void apply_nexus(monster_type *m_ptr)
+{
+ if (m_ptr == NULL) return;
+
+ if (!(dungeon_flags2 & DF2_NO_TELEPORT))
+ {
+ switch (randint(7))
+ {
+ case 1:
+ case 2:
+ case 3:
+ {
+ teleport_player(200);
+ break;
+ }
+
+ case 4:
+ case 5:
+ {
+ teleport_player_to(m_ptr->fy, m_ptr->fx);
+ break;
+ }
+
+ case 6:
+ {
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ break;
+ }
+
+ /* Teleport Level */
+ teleport_player_level();
+ break;
+ }
+
+ case 7:
+ {
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ break;
+ }
+
+ msg_print("Your body starts to scramble...");
+ corrupt_player();
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Convert 2 couples of coordonates to a direction
+ */
+int yx_to_dir(int y2, int x2, int y1, int x1)
+{
+ int y = y2 - y1, x = x2 - x1;
+
+ if ((y == 0) && (x == 1)) return 6;
+ if ((y == 0) && (x == -1)) return 4;
+ if ((y == -1) && (x == 0)) return 8;
+ if ((y == 1) && (x == 0)) return 2;
+ if ((y == -1) && (x == -1)) return 7;
+ if ((y == -1) && (x == 1)) return 9;
+ if ((y == 1) && (x == 1)) return 3;
+ if ((y == 1) && (x == -1)) return 1;
+
+ return 5;
+}
+
+/*
+ * Give the opposate direction of the given one
+ */
+int invert_dir(int dir)
+{
+ if (dir == 4) return 6;
+ if (dir == 6) return 4;
+ if (dir == 8) return 2;
+ if (dir == 2) return 8;
+ if (dir == 7) return 3;
+ if (dir == 9) return 1;
+ if (dir == 1) return 9;
+ if (dir == 3) return 7;
+ return 5;
+}
+
+
+/*
+ * Determine which way the mana path follow
+ */
+int get_mana_path_dir(int y, int x, int oy, int ox, int pdir, int mana)
+{
+ int dir[8] = {5, 5, 5, 5, 5, 5, 5, 5}, n = 0, i, r = 0;
+
+ /* Check which case are allowed */
+ if (cave[y - 1][x].mana == mana) dir[n++] = 8;
+ if (cave[y + 1][x].mana == mana) dir[n++] = 2;
+ if (cave[y][x - 1].mana == mana) dir[n++] = 4;
+ if (cave[y][x + 1].mana == mana) dir[n++] = 6;
+
+ /* If only 2 possibilities select the only good one */
+ if (n == 2)
+ {
+ if (invert_dir(yx_to_dir(y, x, oy, ox)) != dir[0]) return dir[0];
+ if (invert_dir(yx_to_dir(y, x, oy, ox)) != dir[1]) return dir[1];
+
+ /* Should never happen */
+ return 5;
+ }
+
+
+ /* Check if it's not your last place */
+ for (i = 0; i < n; i++)
+ {
+ if ((oy == y + ddy[dir[i]]) && (ox == x + ddx[dir[i]]))
+ {
+ if (dir[i] == 8) dir[i] = 2;
+ else if (dir[i] == 2) dir[i] = 8;
+ else if (dir[i] == 6) dir[i] = 4;
+ else if (dir[i] == 4) dir[i] = 6;
+ }
+ }
+
+ /* Select the desired one if possible */
+ for (i = 0; i < n; i++)
+ {
+ if ((dir[i] == pdir) &&
+ (cave[y + ddy[dir[i]]][x + ddx[dir[i]]].mana == mana))
+ {
+ return dir[i];
+ }
+ }
+
+ /* If not select a random one */
+ if (n > 2)
+ {
+ byte nb = 200;
+
+ while (nb)
+ {
+ nb--;
+
+ r = rand_int(n);
+ if ((dir[r] != 5) && (yx_to_dir(y, x, oy, ox) != dir[r])) break;
+ }
+ return dir[r];
+ }
+ /* If nothing is found return 5 */
+ else return 5;
+}
+
+
+/*
+ * Determine the path taken by a projection.
+ *
+ * The projection will always start from the grid (y1,x1), and will travel
+ * towards the grid (y2,x2), touching one grid per unit of distance along
+ * the major axis, and stopping when it enters the destination grid or a
+ * wall grid, or has travelled the maximum legal distance of "range".
+ *
+ * Note that "distance" in this function (as in the "update_view()" code)
+ * is defined as "MAX(dy,dx) + MIN(dy,dx)/2", which means that the player
+ * actually has an "octagon of projection" not a "circle of projection".
+ *
+ * The path grids are saved into the grid array pointed to by "gp", and
+ * there should be room for at least "range" grids in "gp". Note that
+ * due to the way in which distance is calculated, this function normally
+ * uses fewer than "range" grids for the projection path, so the result
+ * of this function should never be compared directly to "range". Note
+ * that the initial grid (y1,x1) is never saved into the grid array, not
+ * even if the initial grid is also the final grid. XXX XXX XXX
+ *
+ * The "flg" flags can be used to modify the behavior of this function.
+ *
+ * In particular, the "PROJECT_STOP" and "PROJECT_THRU" flags have the same
+ * semantics as they do for the "project" function, namely, that the path
+ * will stop as soon as it hits a monster, or that the path will continue
+ * through the destination grid, respectively.
+ *
+ * The "PROJECT_JUMP" flag, which for the "project()" function means to
+ * start at a special grid (which makes no sense in this function), means
+ * that the path should be "angled" slightly if needed to avoid any wall
+ * grids, allowing the player to "target" any grid which is in "view".
+ * This flag is non-trivial and has not yet been implemented, but could
+ * perhaps make use of the "vinfo" array (above). XXX XXX XXX
+ *
+ * This function returns the number of grids (if any) in the path. This
+ * function will return zero if and only if (y1,x1) and (y2,x2) are equal.
+ *
+ * This algorithm is similar to, but slightly different from, the one used
+ * by "update_view_los()", and very different from the one used by "los()".
+ */
+sint project_path(u16b *gp, int range, int y1, int x1, int y2, int x2, int flg)
+{
+ int y, x, mana = 0, dir = 0;
+
+ int n = 0;
+ int k = 0;
+
+ /* Absolute */
+ int ay, ax;
+
+ /* Offsets */
+ int sy, sx;
+
+ /* Fractions */
+ int frac;
+
+ /* Scale factors */
+ int full, half;
+
+ /* Slope */
+ int m;
+
+
+ /* No path necessary (or allowed) */
+ if ((x1 == x2) && (y1 == y2)) return (0);
+
+ /* Hack -- to make a bolt/beam/ball follow a mana path */
+ if (flg & PROJECT_MANA_PATH)
+ {
+ int oy = y1, ox = x1, pdir = yx_to_dir(y2, x2, y1, x1);
+
+ /* Get the mana path level to follow */
+ mana = cave[y1][x1].mana;
+
+ /* Start */
+ dir = get_mana_path_dir(y1, x1, y1, x1, pdir, mana);
+ y = y1 + ddy[dir];
+ x = x1 + ddx[dir];
+
+ /* Create the projection path */
+ while (1)
+ {
+ /* Save grid */
+ gp[n++] = GRID(y, x);
+
+ /* Hack -- Check maximum range */
+ if (n >= range + 10) return n;
+
+ /* Always stop at non-initial wall grids */
+ if ((n > 0) && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x))) return n;
+
+ /* Sometimes stop at non-initial monsters/players */
+ if (flg & (PROJECT_STOP))
+ {
+ if ((n > 0) && (cave[y][x].m_idx != 0)) return n;
+ }
+
+ /* Get the new direction */
+ dir = get_mana_path_dir(y, x, oy, ox, pdir, mana);
+ if (dir == 5) return n;
+ oy = y;
+ ox = x;
+ y += ddy[dir];
+ x += ddx[dir];
+ }
+ }
+
+ /* Analyze "dy" */
+ if (y2 < y1)
+ {
+ ay = (y1 - y2);
+ sy = -1;
+ }
+ else
+ {
+ ay = (y2 - y1);
+ sy = 1;
+ }
+
+ /* Analyze "dx" */
+ if (x2 < x1)
+ {
+ ax = (x1 - x2);
+ sx = -1;
+ }
+ else
+ {
+ ax = (x2 - x1);
+ sx = 1;
+ }
+
+
+ /* Number of "units" in one "half" grid */
+ half = (ay * ax);
+
+ /* Number of "units" in one "full" grid */
+ full = half << 1;
+
+
+ /* Vertical */
+ if (ay > ax)
+ {
+ /* Start at tile edge */
+ frac = ax * ax;
+
+ /* Let m = ((dx/dy) * full) = (dx * dx * 2) = (frac * 2) */
+ m = frac << 1;
+
+ /* Start */
+ y = y1 + sy;
+ x = x1;
+
+ /* Create the projection path */
+ while (1)
+ {
+ /* Save grid */
+ gp[n++] = GRID(y, x);
+
+ /* Hack -- Check maximum range */
+ if ((n + (k >> 1)) >= range) break;
+
+ /* Sometimes stop at destination grid */
+ if (!(flg & (PROJECT_THRU)))
+ {
+ if ((x == x2) && (y == y2)) break;
+ }
+
+ /* Always stop at non-initial wall grids */
+ if ((n > 0) && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x)) && !(flg & PROJECT_WALL)) break;
+
+ /* Sometimes stop at non-initial monsters/players */
+ if (flg & (PROJECT_STOP))
+ {
+ if ((n > 0) && (cave[y][x].m_idx != 0)) break;
+ }
+
+ /* Slant */
+ if (m)
+ {
+ /* Advance (X) part 1 */
+ frac += m;
+
+ /* Horizontal change */
+ if (frac >= half)
+ {
+ /* Advance (X) part 2 */
+ x += sx;
+
+ /* Advance (X) part 3 */
+ frac -= full;
+
+ /* Track distance */
+ k++;
+ }
+ }
+
+ /* Advance (Y) */
+ y += sy;
+ }
+ }
+
+ /* Horizontal */
+ else if (ax > ay)
+ {
+ /* Start at tile edge */
+ frac = ay * ay;
+
+ /* Let m = ((dy/dx) * full) = (dy * dy * 2) = (frac * 2) */
+ m = frac << 1;
+
+ /* Start */
+ y = y1;
+ x = x1 + sx;
+
+ /* Create the projection path */
+ while (1)
+ {
+ /* Save grid */
+ gp[n++] = GRID(y, x);
+
+ /* Hack -- Check maximum range */
+ if ((n + (k >> 1)) >= range) break;
+
+ /* Sometimes stop at destination grid */
+ if (!(flg & (PROJECT_THRU)))
+ {
+ if ((x == x2) && (y == y2)) break;
+ }
+
+ /* Always stop at non-initial wall grids */
+ if ((n > 0) && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x)) && !(flg & PROJECT_WALL)) break;
+
+ /* Sometimes stop at non-initial monsters/players */
+ if (flg & (PROJECT_STOP))
+ {
+ if ((n > 0) && (cave[y][x].m_idx != 0)) break;
+ }
+
+ /* Slant */
+ if (m)
+ {
+ /* Advance (Y) part 1 */
+ frac += m;
+
+ /* Vertical change */
+ if (frac >= half)
+ {
+ /* Advance (Y) part 2 */
+ y += sy;
+
+ /* Advance (Y) part 3 */
+ frac -= full;
+
+ /* Track distance */
+ k++;
+ }
+ }
+
+ /* Advance (X) */
+ x += sx;
+ }
+ }
+
+ /* Diagonal */
+ else
+ {
+ /* Start */
+ y = y1 + sy;
+ x = x1 + sx;
+
+ /* Create the projection path */
+ while (1)
+ {
+ /* Save grid */
+ gp[n++] = GRID(y, x);
+
+ /* Hack -- Check maximum range */
+ if ((n + (n >> 1)) >= range) break;
+
+ /* Sometimes stop at destination grid */
+ if (!(flg & (PROJECT_THRU)))
+ {
+ if ((x == x2) && (y == y2)) break;
+ }
+
+ /* Always stop at non-initial wall grids */
+ if ((n > 0) && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x)) && !(flg & PROJECT_WALL)) break;
+
+ /* Sometimes stop at non-initial monsters/players */
+ if (flg & (PROJECT_STOP))
+ {
+ if ((n > 0) && (cave[y][x].m_idx != 0)) break;
+ }
+
+ /* Advance (Y) */
+ y += sy;
+
+ /* Advance (X) */
+ x += sx;
+ }
+ }
+
+
+ /* Length */
+ return (n);
+}
+
+
+
+/*
+ * Mega-Hack -- track "affected" monsters (see "project()" comments)
+ */
+static int project_m_n;
+static int project_m_x;
+static int project_m_y;
+
+
+
+/*
+ * We are called from "project()" to "damage" terrain features
+ *
+ * We are called both for "beam" effects and "ball" effects.
+ *
+ * The "r" parameter is the "distance from ground zero".
+ *
+ * Note that we determine if the player can "see" anything that happens
+ * by taking into account: blindness, line-of-sight, and illumination.
+ *
+ * We return "TRUE" if the effect of the projection is "obvious".
+ *
+ * XXX XXX XXX We also "see" grids which are "memorized", probably a hack
+ *
+ * XXX XXX XXX Perhaps we should affect doors?
+ */
+static bool_ project_f(int who, int r, int y, int x, int dam, int typ)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ bool_ obvious = FALSE;
+
+ bool_ flag = FALSE;
+
+ bool_ seen;
+
+
+ /* XXX XXX XXX */
+ who = who ? who : 0;
+
+ /* Reduce damage by distance */
+ dam = (dam + r) / (r + 1);
+
+ /* Remember if the grid is with the LoS of player */
+ seen = player_can_see_bold(y, x);
+
+ /* Analyze the type */
+ switch (typ)
+ {
+ /* Ignore most effects */
+ case GF_ELEC:
+ case GF_SOUND:
+ case GF_MANA:
+ case GF_PSI:
+ case GF_PSI_DRAIN:
+ case GF_TELEKINESIS:
+ case GF_DOMINATION:
+ {
+ break;
+ }
+
+ case GF_COLD:
+ case GF_ICE:
+ {
+ int percent = c_ptr->feat == GF_COLD ? 20 : 50;
+
+ /* Only affects "boring" grids */
+ if (!cave_plain_floor_bold(y, x)) break;
+
+ if (rand_int(100) < percent)
+ {
+ cave_set_feat(y, x, FEAT_ICE);
+
+ if (seen) obvious = TRUE;
+ }
+
+ break;
+ }
+
+ case GF_BETWEEN_GATE:
+ {
+ int y1 = randint(cur_hgt) - 1;
+ int x1 = randint(cur_wid) - 1;
+ int y2 = y1;
+ int x2 = x1;
+ int tries = 1000;
+
+ /*
+ * Avoid "interesting" and/or permanent features
+ *
+ * If we can make sure that all the "permanent" features
+ * have the remember flag set as well, we can simplify
+ * the conditional... -- pelpel
+ */
+ if (!cave_plain_floor_bold(y, x) ||
+ (f_info[cave[y][x].feat].flags1 & FF1_PERMANENT)) break;
+
+ /* Destination shouldn't be "interesting" either */
+ while (tries &&
+ (!cave_plain_floor_bold(y2, x2) ||
+ (f_info[cave[y2][x2].feat].flags1 & FF1_PERMANENT)))
+ {
+ y2 = y1 = randint(cur_hgt) - 1;
+ x2 = x1 = randint(cur_wid) - 1;
+ scatter(&y2, &x2, y1, x1, 20);
+ tries --;
+ }
+
+ /* No boarding grids found */
+ if (!tries) break;
+
+ /* Place a pair of between gates */
+ cave_set_feat(y, x, FEAT_BETWEEN);
+ cave[y][x].special = x2 + (y2 << 8);
+
+ cave_set_feat(y2, x2, FEAT_BETWEEN);
+ cave[y2][x2].special = x + (y << 8);
+
+ if (seen)
+ {
+ obvious = TRUE;
+ note_spot(y, x);
+ }
+
+ if (player_can_see_bold(y2, x2))
+ {
+ obvious = TRUE;
+ note_spot(y2, x2);
+ }
+
+ break;
+ }
+
+ /* Burn trees & melt ice */
+ case GF_FIRE:
+ case GF_METEOR:
+ case GF_PLASMA:
+ case GF_HOLY_FIRE:
+ case GF_HELL_FIRE:
+ {
+ /* "Permanent" features will stay */
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+
+ /* Trees *will* burn */
+ if (c_ptr->feat == FEAT_TREES)
+ {
+ cave_set_feat(y, x, FEAT_DEAD_TREE);
+
+ /* Silly thing to destroy trees when a yavanna worshipper */
+ inc_piety(GOD_YAVANNA, -50);
+
+ if (seen) obvious = TRUE;
+ }
+
+ /* Trees *will* burn */
+ if (c_ptr->feat == FEAT_SMALL_TREES)
+ {
+ cave_set_feat(y, x, FEAT_DEAD_SMALL_TREE);
+
+ /* Silly thing to destroy trees when a yavanna worshipper */
+ inc_piety(GOD_YAVANNA, -60);
+
+ if (seen) obvious = TRUE;
+ }
+
+ /* Ice can melt (chance == 30%) */
+ else if (c_ptr->feat == FEAT_ICE)
+ {
+ int k = rand_int(100);
+
+ if (k >= 30) break;
+
+ /* Melt ice */
+ if (k < 10) cave_set_feat(y, x, FEAT_DIRT);
+ else if (k < 30) cave_set_feat(y, x, FEAT_SHAL_WATER);
+
+ if (seen) obvious = TRUE;
+ }
+
+ /* Floors can become ash or lava (chance == 25%) */
+ else if (f_info[c_ptr->feat].flags1 & FF1_FLOOR)
+ {
+ int k = rand_int(100);
+
+ if (k >= 25) break;
+
+ /* Burn floor */
+ if (k < 10) cave_set_feat(y, x, FEAT_SHAL_LAVA);
+ else if (k < 25) cave_set_feat(y, x, FEAT_ASH);
+
+ if (seen) obvious = TRUE;
+ }
+
+ /* Sandwall can be turned into glass (chance == 30%) */
+ else if ((c_ptr->feat == FEAT_SANDWALL) ||
+ (c_ptr->feat == FEAT_SANDWALL_H) ||
+ (c_ptr->feat == FEAT_SANDWALL_K))
+ {
+ int k = rand_int(100);
+
+ /* Glass it */
+ if (k < 30)
+ {
+ cave_set_feat(y, x, FEAT_GLASS_WALL);
+
+ /* Visibility change */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ if (seen) obvious = TRUE;
+ }
+
+ }
+
+ break;
+ }
+
+ case GF_WAVE:
+ case GF_WATER:
+ {
+ int p1 = 0;
+ int p2 = 0;
+ int f1 = 0;
+ int f2 = 0;
+ int f = 0;
+ int k;
+
+ /* "Permanent" features will stay */
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+
+ /* Needs more than 30 damage */
+ if (dam < 30) break;
+
+ if ((c_ptr->feat == FEAT_FLOOR) ||
+ (c_ptr->feat == FEAT_DIRT) ||
+ (c_ptr->feat == FEAT_GRASS))
+ {
+ /* 35% chance to create shallow water */
+ p1 = 35;
+ f1 = FEAT_SHAL_WATER;
+
+ /* 5% chance to create deep water */
+ p2 = 40;
+ f2 = FEAT_DEEP_WATER;
+ }
+ else if ((c_ptr->feat == FEAT_MAGMA) ||
+ (c_ptr->feat == FEAT_MAGMA_H) ||
+ (c_ptr->feat == FEAT_MAGMA_K) ||
+ (c_ptr->feat == FEAT_SHAL_LAVA))
+ {
+ /* 15% chance to convert it to normal floor */
+ p1 = 15;
+ f1 = FEAT_FLOOR;
+ }
+ else if (c_ptr->feat == FEAT_DEEP_LAVA)
+ {
+ /* 10% chance to convert it to shallow lava */
+ p1 = 10;
+ f1 = FEAT_SHAL_LAVA;
+
+ /* 5% chance to convert it to normal floor */
+ p2 = 15;
+ f2 = FEAT_FLOOR;
+ }
+ else if ((c_ptr->feat == FEAT_SHAL_WATER) ||
+ (c_ptr->feat == FEAT_DARK_PIT))
+ {
+ /* 10% chance to convert it to deep water */
+ p1 = 10;
+ f1 = FEAT_DEEP_WATER;
+ }
+
+ k = rand_int(100);
+
+ if (k < p1) f = f1;
+ else if (k < p2) f = f2;
+
+ if (f)
+ {
+ if (f == FEAT_FLOOR) place_floor_convert_glass(y, x);
+ else cave_set_feat(y, x, f);
+
+ if (seen) obvious = TRUE;
+ }
+
+ break;
+ }
+
+ case GF_NETHER:
+ case GF_NEXUS:
+ case GF_ACID:
+ case GF_SHARDS:
+ case GF_TIME:
+ case GF_FORCE:
+ case GF_NUKE:
+ {
+ /* "Permanent" features will stay */
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+
+ if ((c_ptr->feat == FEAT_TREES) ||
+ (c_ptr->feat == FEAT_SMALL_TREES))
+ {
+ /* Destroy the grid */
+ cave_set_feat(y, x, FEAT_DEAD_TREE);
+
+ /* Silly thing to destroy trees when a yavanna worshipper */
+ inc_piety(GOD_YAVANNA, -50);
+
+ if (seen) obvious = TRUE;
+ }
+
+ break;
+ }
+
+ case GF_DISINTEGRATE:
+ {
+ /* "Permanent" features will stay */
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+
+ if (((c_ptr->feat == FEAT_TREES) ||
+ (c_ptr->feat == FEAT_SMALL_TREES) ||
+ (f_info[c_ptr->feat].flags1 & FF1_FLOOR)) &&
+ (rand_int(100) < 30))
+ {
+ /* Flow change */
+ if (c_ptr->feat == FEAT_TREES) p_ptr->update |= (PU_FLOW);
+
+ cave_set_feat(y, x, FEAT_ASH);
+
+ /* Silly thing to destroy trees when a yavanna worshipper */
+ if (c_ptr->feat == FEAT_TREES || c_ptr->feat == FEAT_SMALL_TREES)
+ inc_piety(GOD_YAVANNA, -50);
+
+ /* Visibility change */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ if (seen) obvious = TRUE;
+ }
+
+ break;
+ }
+
+ /* Destroy Traps (and Locks) */
+ case GF_KILL_TRAP:
+ {
+ /* Destroy normal traps and disarm monster traps */
+ if ((c_ptr->t_idx != 0) || (c_ptr->feat == FEAT_MON_TRAP))
+ {
+ /* Check line of sight */
+ if (player_has_los_bold(y, x))
+ {
+ msg_print("There is a bright flash of light!");
+ obvious = TRUE;
+ }
+
+ /* Forget the trap */
+ c_ptr->info &= ~(CAVE_MARK | CAVE_TRDT);
+
+ /* Destroy normal traps */
+ c_ptr->t_idx = 0;
+
+ /* Disarm monster traps */
+ if (c_ptr->feat == FEAT_MON_TRAP)
+ {
+ c_ptr->special = c_ptr->special2 = 0;
+
+ /* Remove the feature */
+ if (!(f_info[c_ptr->feat].flags1 & FF1_PERMANENT))
+ place_floor_convert_glass(y, x);
+ }
+
+ /* Hack -- Force redraw */
+ note_spot(y, x);
+ lite_spot(y, x);
+ }
+
+ /* Secret / Locked doors are found and unlocked */
+ else if ((c_ptr->feat == FEAT_SECRET) ||
+ ((c_ptr->feat >= FEAT_DOOR_HEAD + 0x01) &&
+ (c_ptr->feat <= FEAT_DOOR_HEAD + 0x07)))
+ {
+
+ /* Check line of sound */
+ if (player_has_los_bold(y, x))
+ {
+ msg_print("Click!");
+ obvious = TRUE;
+ }
+
+ /* Remove feature mimic */
+ cave[y][x].mimic = 0;
+
+ /* Unlock the door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
+ }
+
+ break;
+ }
+
+ /* Destroy Doors (and traps) */
+ case GF_KILL_DOOR:
+ {
+ /* Destroy all doors and traps, and disarm monster traps */
+ if ((c_ptr->feat == FEAT_OPEN) ||
+ (c_ptr->feat == FEAT_BROKEN) ||
+ (c_ptr->t_idx != 0) ||
+ (c_ptr->feat == FEAT_MON_TRAP) ||
+ ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL)))
+ {
+ /* Check line of sight */
+ if (player_has_los_bold(y, x))
+ {
+ /* Message */
+ msg_print("There is a bright flash of light!");
+ obvious = TRUE;
+
+ /* Visibility change */
+ if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL))
+ {
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+ }
+ }
+
+ /* Forget the door */
+ c_ptr->info &= ~(CAVE_MARK | CAVE_TRDT);
+
+ /* Remove normal traps */
+ c_ptr->t_idx = 0;
+
+ /* Disarm monster traps */
+ if (c_ptr->feat == FEAT_MON_TRAP)
+ c_ptr->special = c_ptr->special2 = 0;
+
+ /* Remove the feature */
+ if (!(f_info[c_ptr->feat].flags1 & FF1_PERMANENT))
+ place_floor_convert_glass(y, x);
+
+ /* Hack -- Force redraw */
+ note_spot(y, x);
+ lite_spot(y, x);
+ }
+
+ break;
+ }
+
+ case GF_JAM_DOOR: /* Jams a door (as if with a spike) */
+ {
+ if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL))
+ {
+ /* Convert "locked" to "stuck" XXX XXX XXX */
+ if (c_ptr->feat < FEAT_DOOR_HEAD + 0x08) c_ptr->feat += 0x08;
+
+ /* Add one spike to the door */
+ if (c_ptr->feat < FEAT_DOOR_TAIL) c_ptr->feat++;
+
+ /* Check line of sight */
+ if (player_has_los_bold(y, x))
+ {
+ /* Message */
+ msg_print("The door seems stuck.");
+ obvious = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ /* Destroy walls (and doors) */
+ case GF_KILL_WALL:
+ {
+ /* Non-walls (etc) */
+ if (cave_floor_bold(y, x)) break;
+
+ /* "Permanent" features will stay */
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+
+ /* Granite -- How about other wall types? */
+ if ((c_ptr->feat >= FEAT_WALL_EXTRA) &&
+ (c_ptr->feat <= FEAT_WALL_SOLID))
+ {
+ /* Message */
+ if (c_ptr->info & (CAVE_MARK))
+ {
+ msg_print("The wall turns into mud!");
+ obvious = TRUE;
+ }
+
+ /* Forget the wall */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Destroy the wall */
+ cave_set_feat(y, x, FEAT_FLOOR);
+ }
+
+ /* Quartz / Magma / Sand with treasure */
+ else if (((c_ptr->feat >= FEAT_MAGMA_H) &&
+ (c_ptr->feat <= FEAT_QUARTZ_K)) ||
+ (c_ptr->feat == FEAT_SANDWALL_K))
+ {
+ /* Message */
+ if (c_ptr->info & (CAVE_MARK))
+ {
+ msg_print("The vein turns into mud!");
+ msg_print("You have found something!");
+ obvious = TRUE;
+ }
+
+ /* Forget the wall */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Destroy the wall */
+ cave_set_feat(y, x, FEAT_FLOOR);
+
+ /* Place some gold */
+ place_gold(y, x);
+ }
+
+ /* Quartz / Magma / Sand */
+ else if ((c_ptr->feat == FEAT_MAGMA) ||
+ (c_ptr->feat == FEAT_QUARTZ) ||
+ (c_ptr->feat == FEAT_SANDWALL) ||
+ (c_ptr->feat == FEAT_SANDWALL_H))
+ {
+ /* Message */
+ if (c_ptr->info & (CAVE_MARK))
+ {
+ msg_print("The vein turns into mud!");
+ obvious = TRUE;
+ }
+
+ /* Forget the wall */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Destroy the wall */
+ cave_set_feat(y, x, FEAT_FLOOR);
+ }
+
+ /* Rubble */
+ else if (c_ptr->feat == FEAT_RUBBLE)
+ {
+ /* Message */
+ if (c_ptr->info & (CAVE_MARK))
+ {
+ msg_print("The rubble turns into mud!");
+ obvious = TRUE;
+ }
+
+ /* Forget the wall */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Destroy the rubble */
+ cave_set_feat(y, x, FEAT_FLOOR);
+
+ /* Hack -- place an object */
+ if (rand_int(100) < 10)
+ {
+ /* Found something */
+ if (seen)
+ {
+ msg_print("There was something buried in the rubble!");
+ obvious = TRUE;
+ }
+
+ /* Place gold */
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_RUBBLE);
+ }
+ }
+
+ /* Destroy doors (and secret doors) */
+ else if (((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL)) ||
+ (c_ptr->feat == FEAT_SECRET))
+ {
+ /* Hack -- special message */
+ if (c_ptr->info & (CAVE_MARK))
+ {
+ msg_print("The door turns into mud!");
+ obvious = TRUE;
+ }
+
+ /* Forget the wall */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Remove mimic */
+ c_ptr->mimic = 0;
+
+ /* Destroy the feature */
+ cave_set_feat(y, x, FEAT_FLOOR);
+ }
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS | PU_MON_LITE);
+
+ break;
+ }
+
+ /* Make doors */
+ case GF_MAKE_DOOR:
+ {
+ /* Require a "naked" floor grid */
+ if (!cave_clean_bold(y, x)) break;
+
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+
+ /* Create a closed door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
+
+ /* Observe */
+ if (c_ptr->info & (CAVE_MARK)) obvious = TRUE;
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ break;
+ }
+
+ /* Make traps */
+ case GF_MAKE_TRAP:
+ {
+ /* Require a "naked" floor grid */
+ if (!cave_clean_bold(y, x)) break;
+
+ /* Place a trap */
+ place_trap(y, x);
+
+ break;
+ }
+
+
+ case GF_MAKE_GLYPH:
+ {
+ /* Require a "naked" floor grid */
+ if (!cave_clean_bold(y, x)) break;
+
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+
+ cave_set_feat(y, x, FEAT_GLYPH);
+
+ if (seen) obvious = TRUE;
+
+ break;
+ }
+
+
+
+ case GF_STONE_WALL:
+ {
+ /* Require a "naked" floor grid */
+ if (!cave_clean_bold(y, x)) break;
+
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+ if (!(f_info[c_ptr->feat].flags1 & FF1_FLOOR)) break;
+
+ /* Place a wall */
+ cave_set_feat(y, x, FEAT_WALL_EXTRA);
+
+ if (seen) obvious = TRUE;
+
+ /* Update some things */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ break;
+ }
+
+ case GF_WINDS_MANA:
+ {
+ if (dam >= 256)
+ {
+ /* With erase mana */
+
+ /* Absorb some of the mana of the grid */
+ p_ptr->csp += cave[y][x].mana / 80;
+ if (p_ptr->csp > p_ptr->msp) p_ptr->csp = p_ptr->msp;
+
+ /* Set the new amount */
+ cave[y][x].mana = dam - 256;
+ }
+ else
+ {
+ /* Without erase mana */
+ int amt = cave[y][x].mana + dam;
+
+ /* Check if not overflow */
+ if (amt > 255) amt = 255;
+
+ /* Set the new amount */
+ cave[y][x].mana = amt;
+ }
+
+ break;
+ }
+
+ case GF_LAVA_FLOW:
+ {
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+
+ /* Shallow Lava */
+ if (dam == 1)
+ {
+ /* Require a "naked" floor grid */
+ if (!cave_naked_bold(y, x)) break;
+
+ /* Place a shallow lava */
+ cave_set_feat(y, x, FEAT_SHAL_LAVA);
+
+ if (seen) obvious = TRUE;
+ }
+
+ /* Deep Lava */
+ else
+ {
+ /* Require a "naked" floor grid */
+ if (cave_perma_bold(y, x) || !dam) break;
+
+ /* Place a deep lava */
+ cave_set_feat(y, x, FEAT_DEEP_LAVA);
+
+ if (seen) obvious = TRUE;
+
+ /* Dam is used as a counter for the number of grid to convert */
+ dam--;
+ }
+
+ break;
+ }
+
+ /* Lite up the grid */
+ case GF_LITE_WEAK:
+ case GF_LITE:
+ {
+ /* Turn on the light */
+ c_ptr->info |= (CAVE_GLOW);
+
+ /* Notice */
+ note_spot(y, x);
+
+ /* Redraw */
+ lite_spot(y, x);
+
+ /* Observe */
+ if (seen) obvious = TRUE;
+
+ /*
+ * Mega-Hack -- Update the monster in the affected grid
+ * This allows "spear of light" (etc) to work "correctly"
+ */
+ if (c_ptr->m_idx) update_mon(c_ptr->m_idx, FALSE);
+
+ break;
+ }
+
+ /* Darken the grid */
+ case GF_DARK_WEAK:
+ case GF_DARK:
+ {
+ /* Notice */
+ if (seen) obvious = TRUE;
+
+ /* Turn off the light. */
+ c_ptr->info &= ~(CAVE_GLOW);
+
+ /* Hack -- Forget "boring" grids */
+ if (cave_plain_floor_grid(c_ptr))
+ {
+ /* Forget */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Notice */
+ note_spot(y, x);
+ }
+
+ /* Redraw */
+ lite_spot(y, x);
+
+ /*
+ * Mega-Hack -- Update the monster in the affected grid
+ * This allows "spear of light" (etc) to work "correctly"
+ */
+ if (c_ptr->m_idx) update_mon(c_ptr->m_idx, FALSE);
+
+ /* All done */
+ break;
+ }
+
+ case GF_DESTRUCTION:
+ {
+ int t;
+
+ /* Lose room and vault */
+ c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
+
+ /* Lose light and knowledge */
+ c_ptr->info &= ~(CAVE_MARK | CAVE_GLOW);
+
+ /* Hack -- Notice player affect */
+ if ((x == p_ptr->px) && (y == p_ptr->py))
+ {
+ /* Hurt the player later */
+ flag = TRUE;
+
+ /* Do not hurt this grid */
+ break;
+ ;
+ }
+
+ /* Delete the monster (if any) */
+ delete_monster(y, x);
+
+ if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
+
+ /* Destroy "valid" grids */
+ if (cave_valid_bold(y, x))
+ {
+ /* Delete objects */
+ delete_object(y, x);
+
+ /* Wall (or floor) type */
+ t = rand_int(200);
+
+ /* Granite */
+ if (t < 20)
+ {
+ /* Create granite wall */
+ cave_set_feat(y, x, FEAT_WALL_EXTRA);
+ }
+
+ /* Quartz */
+ else if (t < 60)
+ {
+ /* Create quartz vein */
+ cave_set_feat(y, x, FEAT_QUARTZ);
+ }
+
+ /* Magma */
+ else if (t < 90)
+ {
+ /* Create magma vein */
+ cave_set_feat(y, x, FEAT_MAGMA);
+ }
+
+ /* Sand */
+ else if (t < 110)
+ {
+ /* Create sand vein */
+ cave_set_feat(y, x, FEAT_SANDWALL);
+ }
+
+ /* Floor */
+ else
+ {
+ /* Create floor */
+ cave_set_feat(y, x, FEAT_FLOOR);
+ }
+
+ /* Visibility and flow changes */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS | PU_MON_LITE);
+ }
+
+ obvious = TRUE;
+ break;
+ }
+ default:
+ {
+ /* Hooks! */
+ if (process_hooks_ret(HOOK_GF_EXEC, "dd", "(s,d,d,d,d,d,d)", "grid", who, typ, dam, r, y, x))
+ {
+ obvious = process_hooks_return[0].num;
+ flag = process_hooks_return[1].num;
+ }
+ break;
+ }
+ }
+
+ /* Hack -- Affect player */
+ if (flag)
+ {
+ /* Message */
+ msg_print("There is a searing blast of light!");
+
+ /* Blind the player */
+ if (!p_ptr->resist_blind && !p_ptr->resist_lite)
+ {
+ /* Become blind */
+ (void)set_blind(p_ptr->blind + 10 + randint(10));
+ }
+ }
+
+ /* Return "Anything seen?" */
+ return (obvious);
+}
+
+
+/* Array of raisable ego monster */
+#define MAX_RAISE 10
+static int raise_ego[MAX_RAISE] =
+{
+ 1, /* Skeleton */
+ 1, /* Skeleton */
+ 1, /* Skeleton */
+ 1, /* Skeleton */
+ 2, /* Zombie */
+ 2, /* Zombie */
+ 2, /* Zombie */
+ 4, /* Spectre */
+ 4, /* Spectre */
+ 3, /* Lich */
+};
+
+
+/*
+ * We are called from "project()" to "damage" objects
+ *
+ * We are called both for "beam" effects and "ball" effects.
+ *
+ * Perhaps we should only SOMETIMES damage things on the ground.
+ *
+ * The "r" parameter is the "distance from ground zero".
+ *
+ * Note that we determine if the player can "see" anything that happens
+ * by taking into account: blindness, line-of-sight, and illumination.
+ *
+ * XXX XXX XXX We also "see" grids which are "memorized", probably a hack
+ *
+ * We return "TRUE" if the effect of the projection is "obvious".
+ */
+static bool_ project_o(int who, int r, int y, int x, int dam, int typ)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ bool_ obvious = FALSE;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ char o_name[80];
+
+ int o_sval = 0;
+ bool_ is_potion = FALSE;
+
+
+ /* XXX XXX XXX */
+ who = who ? who : 0;
+
+ /* Reduce damage by distance */
+ dam = (dam + r) / (r + 1);
+
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ bool_ is_art = FALSE;
+ bool_ ignore = FALSE;
+ bool_ plural = FALSE;
+ bool_ do_kill = FALSE;
+
+ cptr note_kill = NULL;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Get the "plural"-ness */
+ if (o_ptr->number > 1) plural = TRUE;
+
+ /* Check for artifact */
+ if ((artifact_p(o_ptr) || o_ptr->art_name)) is_art = TRUE;
+
+ /* Analyze the type */
+ switch (typ)
+ {
+ /* makes corpses explode */
+ case GF_CORPSE_EXPL:
+ {
+ if (o_ptr->tval == TV_CORPSE)
+ {
+ monster_race *r_ptr = &r_info[o_ptr->pval2];
+ s32b dama, radius = 7;
+
+ if (r_ptr->flags1 & RF1_FORCE_MAXHP)
+ dama = maxroll(r_ptr->hdice, r_ptr->hside);
+ else
+ dama = damroll(r_ptr->hdice, r_ptr->hside);
+
+ /* Adjust the damage */
+ dama = dama * dam / 100;
+
+ /* Adjust the radius */
+ radius = radius * dam / 100;
+
+ do_kill = TRUE;
+ note_kill = (plural ? " explode!" : " explodes!");
+ project(who, radius, y, x, dama, GF_SHARDS, PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL);
+ }
+ break;
+ }
+
+ /* Acid -- Lots of things */
+ case GF_ACID:
+ {
+ if (hates_acid(o_ptr))
+ {
+ do_kill = TRUE;
+ note_kill = (plural ? " melt!" : " melts!");
+ if (f3 & (TR3_IGNORE_ACID)) ignore = TRUE;
+ }
+ break;
+ }
+
+ /* Elec -- Rings and Wands */
+ case GF_ELEC:
+ {
+ if (hates_elec(o_ptr))
+ {
+ do_kill = TRUE;
+ note_kill = (plural ? " are destroyed!" : " is destroyed!");
+ if (f3 & (TR3_IGNORE_ELEC)) ignore = TRUE;
+ }
+ break;
+ }
+
+ /* Fire -- Flammable objects */
+ case GF_FIRE:
+ {
+ if (hates_fire(o_ptr))
+ {
+ do_kill = TRUE;
+ note_kill = (plural ? " burn up!" : " burns up!");
+ if (f3 & (TR3_IGNORE_FIRE)) ignore = TRUE;
+ }
+ break;
+ }
+
+ /* Cold -- potions and flasks */
+ case GF_COLD:
+ {
+ if (hates_cold(o_ptr))
+ {
+ note_kill = (plural ? " shatter!" : " shatters!");
+ do_kill = TRUE;
+ if (f3 & (TR3_IGNORE_COLD)) ignore = TRUE;
+ }
+ break;
+ }
+
+ /* Fire + Elec */
+ case GF_PLASMA:
+ {
+ if (hates_fire(o_ptr))
+ {
+ do_kill = TRUE;
+ note_kill = (plural ? " burn up!" : " burns up!");
+ if (f3 & (TR3_IGNORE_FIRE)) ignore = TRUE;
+ }
+ if (hates_elec(o_ptr))
+ {
+ ignore = FALSE;
+ do_kill = TRUE;
+ note_kill = (plural ? " are destroyed!" : " is destroyed!");
+ if (f3 & (TR3_IGNORE_ELEC)) ignore = TRUE;
+ }
+ break;
+ }
+
+ /* Fire + Cold */
+ case GF_METEOR:
+ {
+ if (hates_fire(o_ptr))
+ {
+ do_kill = TRUE;
+ note_kill = (plural ? " burn up!" : " burns up!");
+ if (f3 & (TR3_IGNORE_FIRE)) ignore = TRUE;
+ }
+ if (hates_cold(o_ptr))
+ {
+ ignore = FALSE;
+ do_kill = TRUE;
+ note_kill = (plural ? " shatter!" : " shatters!");
+ if (f3 & (TR3_IGNORE_COLD)) ignore = TRUE;
+ }
+ break;
+ }
+
+ /* Hack -- break potions and such */
+ case GF_ICE:
+ case GF_SHARDS:
+ case GF_FORCE:
+ case GF_SOUND:
+ {
+ if (hates_cold(o_ptr))
+ {
+ note_kill = (plural ? " shatter!" : " shatters!");
+ do_kill = TRUE;
+ }
+ break;
+ }
+
+ /* Mana and Chaos -- destroy everything */
+ case GF_MANA:
+ {
+ do_kill = TRUE;
+ note_kill = (plural ? " are destroyed!" : " is destroyed!");
+ break;
+ }
+
+ case GF_DISINTEGRATE:
+ {
+ do_kill = TRUE;
+ note_kill = (plural ? " evaporate!" : " evaporates!");
+ break;
+ }
+
+ case GF_CHAOS:
+ {
+ do_kill = TRUE;
+ note_kill = (plural ? " are destroyed!" : " is destroyed!");
+ if (f2 & (TR2_RES_CHAOS)) ignore = TRUE;
+ break;
+ }
+
+ /* Holy Fire and Hell Fire -- destroys cursed non-artifacts */
+ case GF_HOLY_FIRE:
+ case GF_HELL_FIRE:
+ {
+ if (cursed_p(o_ptr))
+ {
+ do_kill = TRUE;
+ note_kill = (plural ? " are destroyed!" : " is destroyed!");
+ }
+ break;
+ }
+
+ /* Unlock chests */
+ case GF_KILL_TRAP:
+ case GF_KILL_DOOR:
+ {
+ /* Chests are noticed only if trapped or locked */
+ if (o_ptr->tval == TV_CHEST)
+ {
+ /* Disarm/Unlock traps */
+ if (o_ptr->pval > 0)
+ {
+ /* Disarm or Unlock */
+ o_ptr->pval = (0 - o_ptr->pval);
+
+ /* Identify */
+ object_known(o_ptr);
+
+ /* Notice */
+ if (o_ptr->marked)
+ {
+ msg_print("Click!");
+ obvious = TRUE;
+ }
+ }
+ }
+
+ break;
+ }
+ case GF_STAR_IDENTIFY:
+ {
+ /* Identify it fully */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+
+ /* Mark the item as fully known */
+ o_ptr->ident |= (IDENT_MENTAL);
+
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_IDENTIFY, "(d,s)", 0 - this_o_idx, "full");
+
+ /* Squelch ! */
+ squeltch_grid();
+
+ break;
+ }
+ case GF_IDENTIFY:
+ {
+ object_aware(o_ptr);
+ object_known(o_ptr);
+
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_IDENTIFY, "(d,s)", 0 - this_o_idx, "normal");
+
+ /* Squelch ! */
+ squeltch_grid();
+
+ break;
+ }
+ case GF_RAISE:
+ {
+ get_pos_player(7, &y, &x);
+
+ /* Only corpses can be raised */
+ if (o_ptr->tval == TV_CORPSE)
+ {
+ int ego = raise_ego[rand_int(MAX_RAISE)];
+
+ if (place_monster_one(y, x, o_ptr->pval2, ego, FALSE, (!who) ? MSTATUS_PET : MSTATUS_ENEMY))
+ msg_print("A monster rises from the grave!");
+ do_kill = TRUE;
+ }
+ break;
+ }
+ case GF_RAISE_DEMON:
+ {
+ monster_race *r_ptr = &r_info[o_ptr->pval2];
+ cptr name;
+
+ if (o_ptr->tval != TV_CORPSE) break;
+
+ if (randint(100) > r_ptr->level - p_ptr->lev)
+ {
+ if (r_ptr->level < 10) name = "Manes";
+ else if (r_ptr->level < 18) name = "Tengu";
+ else if (r_ptr->level < 26) name = "Imp";
+ else if (r_ptr->level < 34) name = "Arch-vile";
+ else if (r_ptr->level < 42) name = "Bodak";
+ else if (r_ptr->level < 50) name = "Erynies";
+ else if (r_ptr->level < 58) name = "Vrock";
+ else if (r_ptr->level < 66) name = "Hezrou";
+ else if (r_ptr->level < 74) name = "Glabrezu";
+ else if (r_ptr->level < 82) name = "Nalfeshnee";
+ else if (r_ptr->level < 90) name = "Marilith";
+ else name = "Nycadaemon";
+
+ if (place_monster_one(y, x, test_monster_name(name), 0, FALSE, (!who) ? MSTATUS_PET : MSTATUS_ENEMY))
+ msg_print("A demon emerges from Hell!");
+ }
+
+ do_kill = TRUE;
+ break;
+ }
+ default:
+ {
+ /* Hooks! */
+ if (process_hooks_ret(HOOK_GF_EXEC, "dd", "(s,d,d,d,d,d,d,O)", "object", who, typ, dam, r, y, x, o_ptr))
+ {
+ obvious = process_hooks_return[0].num;
+ do_kill = process_hooks_return[1].num;
+ }
+ break;
+ }
+ }
+
+
+ /* Attempt to destroy the object */
+ if (do_kill)
+ {
+ /* Effect "observed" */
+ if (o_ptr->marked)
+ {
+ obvious = TRUE;
+ object_desc(o_name, o_ptr, FALSE, 0);
+ }
+
+ /* Artifacts, and other objects, get to resist */
+ if (is_art || ignore)
+ {
+ /* Observe the resist */
+ if (o_ptr->marked)
+ {
+ msg_format("The %s %s unaffected!",
+ o_name, (plural ? "are" : "is"));
+ }
+ }
+
+ /* Kill it */
+ else
+ {
+ /* Describe if needed */
+ if (o_ptr->marked && note_kill)
+ {
+ msg_format("The %s%s", o_name, note_kill);
+ }
+
+ o_sval = o_ptr->sval;
+ is_potion = ((k_info[o_ptr->k_idx].tval == TV_POTION) || (k_info[o_ptr->k_idx].tval == TV_POTION2));
+
+
+ /* Delete the object */
+ delete_object_idx(this_o_idx);
+
+ /* Potions produce effects when 'shattered' */
+ if (is_potion)
+ {
+ (void)potion_smash_effect(who, y, x, o_sval);
+ }
+
+
+ /* Redraw */
+ lite_spot(y, x);
+ }
+ }
+ }
+
+ /* Return "Anything seen?" */
+ return (obvious);
+}
+
+/* Can the monster be hurt ? */
+bool_ hurt_monster(monster_type *m_ptr)
+{
+ if (m_ptr->status == MSTATUS_COMPANION) return FALSE;
+ else return TRUE;
+}
+
+/*
+ * Helper function for "project()" below.
+ *
+ * Handle a beam/bolt/ball causing damage to a monster.
+ *
+ * This routine takes a "source monster" (by index) which is mostly used to
+ * determine if the player is causing the damage, and a "radius" (see below),
+ * which is used to decrease the power of explosions with distance, and a
+ * location, via integers which are modified by certain types of attacks
+ * (polymorph and teleport being the obvious ones), a default damage, which
+ * is modified as needed based on various properties, and finally a "damage
+ * type" (see below).
+ *
+ * Note that this routine can handle "no damage" attacks (like teleport) by
+ * taking a "zero" damage, and can even take "parameters" to attacks (like
+ * confuse) by accepting a "damage", using it to calculate the effect, and
+ * then setting the damage to zero. Note that the "damage" parameter is
+ * divided by the radius, so monsters not at the "epicenter" will not take
+ * as much damage (or whatever)...
+ *
+ * Note that "polymorph" is dangerous, since a failure in "place_monster()"'
+ * may result in a dereference of an invalid pointer. XXX XXX XXX
+ *
+ * Various messages are produced, and damage is applied.
+ *
+ * Just "casting" a substance (i.e. plasma) does not make you immune, you must
+ * actually be "made" of that substance, or "breathe" big balls of it.
+ *
+ * We assume that "Plasma" monsters, and "Plasma" breathers, are immune
+ * to plasma.
+ *
+ * We assume "Nether" is an evil, necromantic force, so it doesn't hurt undead,
+ * and hurts evil less. If can breath nether, then it resists it as well.
+ *
+ * Damage reductions use the following formulas:
+ * Note that "dam = dam * 6 / (randint(6) + 6);"
+ * gives avg damage of .655, ranging from .858 to .500
+ * Note that "dam = dam * 5 / (randint(6) + 6);"
+ * gives avg damage of .544, ranging from .714 to .417
+ * Note that "dam = dam * 4 / (randint(6) + 6);"
+ * gives avg damage of .444, ranging from .556 to .333
+ * Note that "dam = dam * 3 / (randint(6) + 6);"
+ * gives avg damage of .327, ranging from .427 to .250
+ * Note that "dam = dam * 2 / (randint(6) + 6);"
+ * gives something simple.
+ *
+ * In this function, "result" messages are postponed until the end, where
+ * the "note" string is appended to the monster name, if not NULL. So,
+ * to make a spell have "no effect" just set "note" to NULL. You should
+ * also set "notice" to FALSE, or the player will learn what the spell does.
+ *
+ * We attempt to return "TRUE" if the player saw anything "useful" happen.
+ */
+bool_ project_m(int who, int r, int y, int x, int dam, int typ)
+{
+ int tmp;
+
+ cave_type *c_ptr = &cave[y][x];
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ char killer [80];
+
+ cptr name = (r_name + r_ptr->name);
+
+ /* Is the monster "seen"? */
+ bool_ seen;
+
+ /* Were the effects "obvious" (if seen)? */
+ bool_ obvious = FALSE;
+
+ /* Were the effects "irrelevant"? */
+ bool_ skipped = FALSE;
+
+
+ /* Move setting */
+ int x1 = 0;
+ int y1 = 0;
+ int a = 0;
+ int b = 0;
+ int do_move = 0;
+
+ /* Polymorph setting (true or false) */
+ int do_poly = 0;
+
+ /* Teleport setting (max distance) */
+ int do_dist = 0;
+
+ /* Confusion setting (amount to confuse) */
+ int do_conf = 0;
+
+ /* Stunning setting (amount to stun) */
+ int do_stun = 0;
+
+ /* Bleeding amount */
+ int do_cut = 0;
+
+ /* Poison amount */
+ int do_pois = 0;
+
+ /* Sleep amount (amount to sleep) */
+ int do_sleep = 0;
+
+ /* Fear amount (amount to fear) */
+ int do_fear = 0;
+
+
+ /* Hold the monster name */
+ char m_name[80];
+
+ /* Assume no note */
+ cptr note = NULL;
+
+ /* Assume a default death */
+ cptr note_dies = " dies.";
+
+
+ /* Nobody here */
+ if (!c_ptr->m_idx) return (FALSE);
+
+ /* Never affect projector */
+ if (who && (c_ptr->m_idx == who)) return (FALSE);
+
+ /*
+ * Don't affect already dead monsters
+ * Prevents problems with chain reactions of exploding monsters
+ */
+ if (m_ptr->hp < 0) return (FALSE);
+
+
+ /* Remember if the monster is within player's line of sight */
+ seen = (m_ptr->ml && ((who != -101) && (who != -100))) ? TRUE : FALSE;
+
+ /* Reduce damage by distance */
+ dam = (dam + r) / (r + 1);
+
+
+ /* Get the monster name (BEFORE polymorphing) */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Mega Gachk */
+ if (r_ptr->flags2 & RF2_DEATH_ORB)
+ {
+ msg_format("%^s is immune to magic.", m_name);
+ return seen;
+ }
+
+ /* Some monsters get "destroyed" */
+ if ((r_ptr->flags3 & (RF3_DEMON)) ||
+ (r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags2 & (RF2_STUPID)) ||
+ (r_ptr->flags3 & (RF3_NONLIVING)) ||
+ (strchr("Evg", r_ptr->d_char)))
+ {
+ /* Special note at death */
+ note_dies = " is destroyed.";
+ }
+
+ if (!who && (is_friend(m_ptr) >= 0))
+ {
+ bool_ get_angry = FALSE;
+ /* Grrr? */
+ switch (typ)
+ {
+ case GF_AWAY_UNDEAD:
+ case GF_AWAY_EVIL:
+ case GF_AWAY_ALL:
+ case GF_CHARM:
+ case GF_CHARM_UNMOVING:
+ case GF_STAR_CHARM:
+ case GF_CONTROL_UNDEAD:
+ case GF_CONTROL_ANIMAL:
+ case GF_CONTROL_DEMON:
+ case GF_OLD_HEAL:
+ case GF_OLD_SPEED:
+ case GF_DARK_WEAK:
+ case GF_JAM_DOOR:
+ case GF_RAISE:
+ case GF_RAISE_DEMON:
+ case GF_IDENTIFY:
+ break; /* none of the above anger */
+ case GF_TRAP_DEMONSOUL:
+ if (r_ptr->flags3 & RF3_DEMON)
+ get_angry = TRUE;
+ break;
+ case GF_KILL_WALL:
+ if (r_ptr->flags3 & (RF3_HURT_ROCK))
+ get_angry = TRUE;
+ break;
+ case GF_HOLY_FIRE:
+ if (!(r_ptr->flags3 & (RF3_GOOD)))
+ get_angry = TRUE;
+ break;
+ case GF_TURN_UNDEAD:
+ case GF_DISP_UNDEAD:
+ if (r_ptr->flags3 & RF3_UNDEAD)
+ get_angry = TRUE;
+ break;
+ case GF_TURN_EVIL:
+ case GF_DISP_EVIL:
+ if (r_ptr->flags3 & RF3_EVIL)
+ get_angry = TRUE;
+ break;
+ case GF_DISP_GOOD:
+ if (r_ptr->flags3 & RF3_GOOD)
+ get_angry = TRUE;
+ break;
+ case GF_DISP_DEMON:
+ if (r_ptr->flags3 & RF3_DEMON)
+ get_angry = TRUE;
+ break;
+ case GF_DISP_LIVING:
+ case GF_UNBREATH:
+ if (!(r_ptr->flags3 & (RF3_UNDEAD)) &&
+ !(r_ptr->flags3 & (RF3_NONLIVING)))
+ get_angry = TRUE;
+ break;
+ case GF_PSI:
+ case GF_PSI_DRAIN:
+ if (!(r_ptr->flags2 & (RF2_EMPTY_MIND)))
+ get_angry = TRUE;
+ break;
+ case GF_DOMINATION:
+ if (!(r_ptr->flags3 & (RF3_NO_CONF)))
+ get_angry = TRUE;
+ break;
+ case GF_OLD_POLY:
+ case GF_OLD_CLONE:
+ if (randint(8) == 1)
+ get_angry = TRUE;
+ break;
+ case GF_LITE:
+ case GF_LITE_WEAK:
+ if (r_ptr->flags3 & RF3_HURT_LITE)
+ get_angry = TRUE;
+ break;
+ default:
+ /* Hooks! */
+ if (process_hooks_ret(HOOK_GF_EXEC, "d", "(s,d,d,d,d,d,d,M)", "angry", who, typ, dam, r, y, x, m_ptr))
+ {
+ get_angry = process_hooks_return[0].num;
+ }
+ else
+ get_angry = TRUE;
+ }
+
+ /* Now anger it if appropriate */
+ if (get_angry == TRUE && !(who))
+ {
+ switch (is_friend(m_ptr))
+ {
+ case 1:
+ if (change_side(m_ptr)) msg_format("%^s gets angry!", m_name);
+ break;
+ case 0:
+ msg_format("%^s gets angry!", m_name);
+ m_ptr->status = MSTATUS_NEUTRAL_M;
+ break;
+ }
+ }
+ }
+
+
+ /* Analyze the damage type */
+ switch (typ)
+ {
+ case GF_ATTACK:
+ {
+ if (seen) obvious = TRUE;
+
+ py_attack(y, x, dam);
+
+ skipped = TRUE;
+
+ dam = 0;
+ break;
+ }
+
+ case GF_IDENTIFY:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Probe */
+ do_probe(c_ptr->m_idx);
+
+ dam = 0;
+ break;
+ }
+
+ /* Death -- instant death */
+ case GF_DEATH:
+ {
+ if (seen) obvious = TRUE;
+
+ if (r_ptr->r_flags1 & RF1_UNIQUE)
+ {
+ note = " resists.";
+ dam = 0;
+ }
+ else
+ {
+ /* It KILLS */
+ dam = 32535;
+ }
+ break;
+ }
+ /* Magic Missile -- pure damage */
+ case GF_MISSILE:
+ {
+ if (seen) obvious = TRUE;
+ break;
+ }
+
+ /* Acid */
+ case GF_ACID:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags9 & (RF9_SUSCEP_ACID))
+ {
+ note = " is hit hard.";
+ dam *= 3;
+ if (seen) r_ptr->r_flags9 |= (RF9_SUSCEP_ACID);
+ }
+ if (r_ptr->flags3 & (RF3_IM_ACID))
+ {
+ note = " resists a lot.";
+ dam /= 9;
+ if (seen) r_ptr->r_flags3 |= (RF3_IM_ACID);
+ }
+ break;
+ }
+
+ /* Electricity */
+ case GF_ELEC:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags9 & (RF9_SUSCEP_ELEC))
+ {
+ note = " is hit hard.";
+ dam *= 3;
+ if (seen) r_ptr->r_flags9 |= (RF9_SUSCEP_ELEC);
+ }
+ if (r_ptr->flags3 & (RF3_IM_ELEC))
+ {
+ note = " resists a lot.";
+ dam /= 9;
+ if (seen) r_ptr->r_flags3 |= (RF3_IM_ELEC);
+ }
+ break;
+ }
+
+ /* Fire damage */
+ case GF_FIRE:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags3 & (RF3_SUSCEP_FIRE))
+ {
+ note = " is hit hard.";
+ dam *= 3;
+ if (seen) r_ptr->r_flags3 |= (RF3_SUSCEP_FIRE);
+ }
+ if (r_ptr->flags3 & (RF3_IM_FIRE))
+ {
+ note = " resists a lot.";
+ dam /= 9;
+ if (seen) r_ptr->r_flags3 |= (RF3_IM_FIRE);
+ }
+ break;
+ }
+
+ /* Cold */
+ case GF_COLD:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags3 & (RF3_SUSCEP_COLD))
+ {
+ note = " is hit hard.";
+ dam *= 3;
+ if (seen) r_ptr->r_flags3 |= (RF3_SUSCEP_COLD);
+ }
+ if (r_ptr->flags3 & (RF3_IM_COLD))
+ {
+ note = " resists a lot.";
+ dam /= 9;
+ if (seen) r_ptr->r_flags3 |= (RF3_IM_COLD);
+ }
+ break;
+ }
+
+ /* Poison */
+ case GF_POIS:
+ {
+ if (seen) obvious = TRUE;
+ if (magik(25)) do_pois = (10 + randint(11) + r) / (r + 1);
+ if (r_ptr->flags9 & (RF9_SUSCEP_POIS))
+ {
+ note = " is hit hard.";
+ dam *= 3;
+ do_pois *= 2;
+ if (seen) r_ptr->r_flags9 |= (RF9_SUSCEP_POIS);
+ }
+ if (r_ptr->flags3 & (RF3_IM_POIS))
+ {
+ note = " resists a lot.";
+ dam /= 9;
+ do_pois = 0;
+ if (seen) r_ptr->r_flags3 |= (RF3_IM_POIS);
+ }
+ break;
+ }
+
+
+ /* Thick Poison */
+ case GF_UNBREATH:
+ {
+ if (seen) obvious = TRUE;
+ if (magik(15)) do_pois = (10 + randint(11) + r) / (r + 1);
+ if ((r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)))
+ {
+ note = " is immune.";
+ dam = 0;
+ do_pois = 0;
+ }
+ break;
+ }
+
+ /* Nuclear waste */
+ case GF_NUKE:
+ {
+ if (seen) obvious = TRUE;
+
+ if (r_ptr->flags3 & (RF3_IM_POIS))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ if (seen) r_ptr->r_flags3 |= (RF3_IM_POIS);
+ }
+ else if (randint(3) == 1) do_poly = TRUE;
+ break;
+ }
+
+ /* Holy Orb -- hurts Evil (replaced with Hellfire) */
+ case GF_HELL_FIRE:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags3 & (RF3_EVIL))
+ {
+ dam *= 2;
+ note = " is hit hard.";
+ if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
+ }
+ break;
+ }
+
+ /* Holy Fire -- hurts Evil, Good are immune, others _resist_ */
+ case GF_HOLY_FIRE:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags3 & (RF3_GOOD))
+ {
+ dam = 0;
+ note = " is immune.";
+ if (seen) r_ptr->r_flags3 |= (RF3_GOOD);
+ }
+ else if (r_ptr->flags3 & (RF3_EVIL))
+ {
+ dam *= 2;
+ note = " is hit hard.";
+ if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
+ }
+ else
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ }
+ break;
+ }
+
+ /* Arrow -- XXX no defense */
+ case GF_ARROW:
+ {
+ if (seen) obvious = TRUE;
+ break;
+ }
+
+ /* Plasma -- XXX perhaps check ELEC or FIRE */
+ case GF_PLASMA:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags3 & (RF3_RES_PLAS))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ if (seen)
+ r_ptr->r_flags3 |= (RF3_RES_PLAS);
+ }
+ break;
+ }
+
+ /* Nether -- see above */
+ case GF_NETHER:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags3 & (RF3_UNDEAD))
+ {
+ note = " is immune.";
+ dam = 0;
+ if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
+ }
+ else if (r_ptr->flags3 & (RF3_RES_NETH))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+
+ if (seen) r_ptr->r_flags3 |= (RF3_RES_NETH);
+ }
+ else if (r_ptr->flags3 & (RF3_EVIL))
+ {
+ dam /= 2;
+ note = " resists somewhat.";
+ if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
+ }
+ break;
+ }
+
+ /* Water (acid) damage -- Water spirits/elementals are immune */
+ case GF_WATER:
+ {
+ if (seen) obvious = TRUE;
+ if ((r_ptr->d_char == 'E') &&
+ (prefix(name, "W") ||
+ (strstr((r_name + r_ptr->name), "Unmaker"))))
+ {
+ note = " is immune.";
+ dam = 0;
+ }
+ else if (r_ptr->flags3 & (RF3_RES_WATE))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ if (seen) r_ptr->r_flags3 |= (RF3_RES_WATE);
+ }
+ break;
+ }
+
+ /* Wave = Water + Force */
+ case GF_WAVE:
+ {
+ if (seen) obvious = TRUE;
+ if ((r_ptr->d_char == 'E') &&
+ (prefix(name, "W") ||
+ (strstr((r_name + r_ptr->name), "Unmaker"))))
+ {
+ note = " is immune.";
+ dam = 0;
+ }
+ else if (r_ptr->flags3 & (RF3_RES_WATE))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ if (seen) r_ptr->r_flags3 |= (RF3_RES_WATE);
+ }
+
+ if (who == 0)
+ {
+ a = 0;
+ b = 0;
+
+ /* Get vector from firer to target */
+ x1 = (m_ptr->fx - p_ptr->px) * 10;
+ y1 = (m_ptr->fy - p_ptr->py) * 10;
+
+ /* Make sure no zero divides */
+ if (x1 == 0) x1 = 1;
+ if (y1 == 0) y1 = 1;
+
+ /* Select direction monster is being pushed */
+
+ /* Roughly horizontally */
+ if ((2*y1) / x1 == 0)
+ {
+ if (x1 > 0)
+ {
+ a = 1, b = 0;
+ }
+ else
+ {
+ a = -1, b = 0;
+ }
+ }
+
+ /* Roughly vertically */
+ else if ((2*x1) / y1 == 0)
+ {
+ if (y1 > 0)
+ {
+ a = 0, b = 1;
+ }
+ else
+ {
+ a = 0, b = -1;
+ }
+ }
+
+ /* Take diagonals */
+ else
+ {
+ if (y1 > 0)
+ {
+ b = 1;
+ }
+ else
+ {
+ b = -1;
+ }
+ if (x1 > 0)
+ {
+ a = 1;
+ }
+ else
+ {
+ a = -1;
+ }
+ }
+
+ /* Move monster 2 offsets back */
+ do_move = 2;
+
+ /* Old monster coords in x,y */
+ y1 = m_ptr->fy;
+ x1 = m_ptr->fx;
+
+ /* Monster move offsets in a,b */
+ note = " is thrown away.";
+ }
+ break;
+ }
+
+ /* Chaos -- Chaos breathers resist */
+ case GF_CHAOS:
+ {
+ if (seen) obvious = TRUE;
+ do_poly = TRUE;
+ do_conf = (5 + randint(11) + r) / (r + 1);
+ if ((r_ptr->flags4 & (RF4_BR_CHAO)) ||
+ ((r_ptr->flags3 & (RF3_DEMON)) && (randint(3) == 1)))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ do_poly = FALSE;
+ }
+ break;
+ }
+
+ /* Shards -- Shard breathers resist */
+ case GF_SHARDS:
+ {
+ if (seen) obvious = TRUE;
+ if (magik(33)) do_cut = (10 + randint(15) + r) / (r + 1);
+ if (r_ptr->flags4 & (RF4_BR_SHAR))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ do_cut = 0;
+ }
+ break;
+ }
+
+ /* Rocket: Shard resistance helps */
+ case GF_ROCKET:
+ {
+ if (seen) obvious = TRUE;
+
+ if (magik(12)) do_cut = (10 + randint(15) + r) / (r + 1);
+ if (r_ptr->flags4 & (RF4_BR_SHAR))
+ {
+ note = " resists somewhat.";
+ dam /= 2;
+ do_cut = 0;
+ }
+ break;
+ }
+
+
+ /* Sound -- Sound breathers resist */
+ case GF_SOUND:
+ {
+ if (seen) obvious = TRUE;
+ if (who <= 0)
+ {
+ if (rand_int(100 - p_ptr->lev) < 50)
+ do_stun = (10 + randint(15) + r) / (r + 1);
+ }
+ else
+ do_stun = (10 + randint(15) + r) / (r + 1);
+ if (r_ptr->flags4 & (RF4_BR_SOUN))
+ {
+ note = " resists.";
+ dam *= 2;
+ dam /= (randint(6) + 6);
+ }
+ break;
+ }
+
+ /* Confusion */
+ case GF_CONFUSION:
+ {
+ if (seen) obvious = TRUE;
+ do_conf = (10 + randint(15) + r) / (r + 1);
+ if (r_ptr->flags4 & (RF4_BR_CONF))
+ {
+ note = " resists.";
+ dam *= 2;
+ dam /= (randint(6) + 6);
+ }
+ else if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ note = " resists somewhat.";
+ dam /= 2;
+ }
+ break;
+ }
+
+ /* Disenchantment -- Breathers and Disenchanters resist */
+ case GF_DISENCHANT:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags3 & (RF3_RES_DISE))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ if (seen) r_ptr->r_flags3 |= (RF3_RES_DISE);
+ }
+ break;
+ }
+
+ /* Nexus -- Breathers and Existers resist */
+ case GF_NEXUS:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags3 & (RF3_RES_NEXU))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ if (seen) r_ptr->r_flags3 |= (RF3_RES_NEXU);
+ }
+ break;
+ }
+
+ /* Force */
+ case GF_FORCE:
+ {
+ if (seen) obvious = TRUE;
+
+ /*
+ * If fired by player, try pushing monster.
+ * First get vector from player to monster.
+ * x10 so we can use pseudo-fixed point maths.
+ *
+ * Really should use get_angle_to_grid (util.c)
+ */
+ if (who == 0)
+ {
+ a = 0;
+ b = 0;
+
+ /* Get vector from firer to target */
+ x1 = (m_ptr->fx - p_ptr->px) * 10;
+ y1 = (m_ptr->fy - p_ptr->py) * 10;
+
+ /* Make sure no zero divides */
+ if (x1 == 0) x1 = 1;
+ if (y1 == 0) y1 = 1;
+
+ /* Select direction monster is being pushed */
+
+ /* Roughly horizontally */
+ if ((2*y1) / x1 == 0)
+ {
+ if (x1 > 0)
+ {
+ a = 1, b = 0;
+ }
+ else
+ {
+ a = -1, b = 0;
+ }
+ }
+
+ /* Roughly vertically */
+ else if ((2*x1) / y1 == 0)
+ {
+ if (y1 > 0)
+ {
+ a = 0, b = 1;
+ }
+ else
+ {
+ a = 0, b = -1;
+ }
+ }
+
+ /* Take diagonals */
+ else
+ {
+ if (y1 > 0)
+ {
+ b = 1;
+ }
+ else
+ {
+ b = -1;
+ }
+ if (x1 > 0)
+ {
+ a = 1;
+ }
+ else
+ {
+ a = -1;
+ }
+ }
+
+ /* Move monster 2 offsets back */
+ do_move = 2;
+
+ /* Old monster coords in x,y */
+ y1 = m_ptr->fy;
+ x1 = m_ptr->fx;
+
+ /* Monster move offsets in a,b */
+ note = " is thrown away.";
+ }
+
+ /* --hack-- Only stun if a monster fired it */
+ else do_stun = (randint(15) + r) / (r + 1);
+
+ if (r_ptr->flags4 & (RF4_BR_WALL))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ }
+ break;
+ }
+
+ /* Inertia -- breathers resist */
+ case GF_INERTIA:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags4 & (RF4_BR_INER))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ }
+ else
+ {
+ /* Powerful monsters can resist */
+ if (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10)
+ {
+ obvious = FALSE;
+ }
+ /* Normal monsters slow down */
+ else
+ {
+ if (m_ptr->mspeed > 60) m_ptr->mspeed -= 10;
+ note = " starts moving slower.";
+ }
+ }
+ break;
+ }
+
+ /* Time -- breathers resist */
+ case GF_TIME:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags4 & (RF4_BR_TIME))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ }
+ break;
+ }
+
+ /* Gravity -- breathers resist */
+ case GF_GRAVITY:
+ {
+ bool_ resist_tele = FALSE;
+
+ if (seen) obvious = TRUE;
+
+ if (r_ptr->flags3 & (RF3_RES_TELE))
+ {
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
+ note = " is unaffected!";
+ resist_tele = TRUE;
+ }
+ else if (m_ptr->level > randint(100))
+ {
+ if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
+ note = " resists!";
+ resist_tele = TRUE;
+ }
+ }
+
+ if (!resist_tele) do_dist = 10;
+ else do_dist = 0;
+
+ if (r_ptr->flags4 & (RF4_BR_GRAV))
+ {
+ note = " resists.";
+ dam *= 3;
+ dam /= (randint(6) + 6);
+ do_dist = 0;
+ }
+ else
+ {
+ /* 1. slowness */
+ /* Powerful monsters can resist */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ obvious = FALSE;
+ }
+ /* Normal monsters slow down */
+ else
+ {
+ if (m_ptr->mspeed > 60) m_ptr->mspeed -= 10;
+ note = " starts moving slower.";
+ }
+
+ /* 2. stun */
+ do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Resist */
+ do_stun = 0;
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ }
+ break;
+ }
+
+ /* Pure damage */
+ case GF_MANA:
+ {
+ if (seen) obvious = TRUE;
+ break;
+ }
+
+
+ /* Pure damage */
+ case GF_DISINTEGRATE:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags3 & (RF3_HURT_ROCK))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_HURT_ROCK);
+ note = " loses some skin!";
+ note_dies = " evaporates!";
+ dam *= 2;
+ }
+
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ if (rand_int(m_ptr->level + 10) > rand_int(p_ptr->lev))
+ {
+ note = " resists.";
+ dam >>= 3;
+ }
+ }
+ break;
+ }
+
+ case GF_FEAR:
+ {
+ if (r_ptr->flags3 & (RF3_NO_FEAR))
+ note = " is unaffected.";
+ else
+ set_afraid(p_ptr->afraid + (dam / 2) + randint(dam / 2));
+
+ /* No damage */
+ dam = 0;
+ break;
+ }
+
+ case GF_PSI:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags2 & RF2_EMPTY_MIND)
+ {
+ dam = 0;
+ note = " is immune!";
+ }
+ else if ((r_ptr->flags2 & RF2_STUPID) ||
+ (r_ptr->flags2 & RF2_WEIRD_MIND) ||
+ (r_ptr->flags3 & RF3_ANIMAL) ||
+ (m_ptr->level > randint(3 * dam)))
+ {
+ dam /= 3;
+ note = " resists.";
+
+ /* Powerful demons & undead can turn a mindcrafter's
+ * attacks back on them */
+ if (((r_ptr->flags3 & RF3_UNDEAD) ||
+ (r_ptr->flags3 & RF3_DEMON)) &&
+ (m_ptr->level > p_ptr->lev / 2) &&
+ (randint(2) == 1))
+ {
+ note = NULL;
+ msg_format("%^s%s corrupted mind backlashes your attack!",
+ m_name, (seen ? "'s" : "s"));
+ /* Saving throw */
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ /* Injure +/- confusion */
+ monster_desc(killer, m_ptr, 0x88);
+ take_hit(dam, killer); /* has already been /3 */
+ if (randint(4) == 1)
+ {
+ switch (randint(4))
+ {
+ case 1:
+ set_confused(p_ptr->confused + 3 + randint(dam));
+ break;
+ case 2:
+ set_stun(p_ptr->stun + randint(dam));
+ break;
+ case 3:
+ {
+ if (r_ptr->flags3 & (RF3_NO_FEAR))
+ note = " is unaffected.";
+ else
+ set_afraid(p_ptr->afraid + 3 + randint(dam));
+ break;
+ }
+ default:
+ if (!p_ptr->free_act)
+ (void)set_paralyzed(p_ptr->paralyzed + randint(dam));
+ break;
+ }
+ }
+ }
+ dam = 0;
+ }
+ }
+
+ if ((dam > 0) && (randint(4) == 1))
+ {
+ switch (randint(4))
+ {
+ case 1:
+ do_conf = 3 + randint(dam);
+ break;
+ case 2:
+ do_stun = 3 + randint(dam);
+ break;
+ case 3:
+ do_fear = 3 + randint(dam);
+ break;
+ default:
+ do_sleep = 3 + randint(dam);
+ break;
+ }
+ }
+
+ note_dies = " collapses, a mindless husk.";
+ break;
+ }
+
+ case GF_PSI_DRAIN:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags2 & RF2_EMPTY_MIND)
+ {
+ dam = 0;
+ note = " is immune!";
+ }
+ else if ((r_ptr->flags2 & RF2_STUPID) ||
+ (r_ptr->flags2 & RF2_WEIRD_MIND) ||
+ (r_ptr->flags3 & RF3_ANIMAL) ||
+ (m_ptr->level > randint(3 * dam)))
+ {
+ dam /= 3;
+ note = " resists.";
+
+ /*
+ * Powerful demons & undead can turn a mindcrafter's
+ * attacks back on them
+ */
+ if (((r_ptr->flags3 & RF3_UNDEAD) ||
+ (r_ptr->flags3 & RF3_DEMON)) &&
+ (m_ptr->level > p_ptr->lev / 2) &&
+ (randint(2) == 1))
+ {
+ note = NULL;
+ msg_format("%^s%s corrupted mind backlashes your attack!",
+ m_name, (seen ? "'s" : "s"));
+ /* Saving throw */
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ /* Injure + mana drain */
+ monster_desc(killer, m_ptr, 0x88);
+ msg_print("Your psychic energy is drained!");
+ p_ptr->csp = MAX(0, p_ptr->csp - damroll(5, dam) / 2);
+ p_ptr->redraw |= PR_MANA;
+ take_hit(dam, killer); /* has already been /3 */
+ }
+ dam = 0;
+ }
+ }
+ else if (dam > 0)
+ {
+ int b = damroll(5, dam) / 4;
+ msg_format("You convert %s%s pain into psychic energy!",
+ m_name, (seen ? "'s" : "s"));
+ b = MIN(p_ptr->msp, p_ptr->csp + b);
+ p_ptr->csp = b;
+ p_ptr->redraw |= PR_MANA;
+ }
+
+ note_dies = " collapses, a mindless husk.";
+ break;
+ }
+
+ case GF_TELEKINESIS:
+ {
+ if (seen) obvious = TRUE;
+ do_dist = 7;
+ /* 1. stun */
+ do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (m_ptr->level > 5 + randint(dam)))
+ {
+ /* Resist */
+ do_stun = 0;
+ /* No obvious effect */
+ obvious = FALSE;
+ }
+ break;
+ }
+
+ /* Meteor -- powerful magic missile */
+ case GF_METEOR:
+ {
+ if (seen) obvious = TRUE;
+ break;
+ }
+
+ case GF_DOMINATION:
+ {
+ if (is_friend(m_ptr) > 0) break;
+ if (seen) obvious = TRUE;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (r_ptr->flags3 & (RF3_NO_CONF)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Memorize a flag */
+ if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ /* Resist */
+ do_conf = 0;
+
+ /*
+ * Powerful demons & undead can turn a mindcrafter's
+ * attacks back on them
+ */
+ if (((r_ptr->flags3 & RF3_UNDEAD) ||
+ (r_ptr->flags3 & RF3_DEMON)) &&
+ (m_ptr->level > p_ptr->lev / 2) &&
+ (randint(2) == 1))
+ {
+ note = NULL;
+ msg_format("%^s%s corrupted mind backlashes your attack!",
+ m_name, (seen ? "'s" : "s"));
+ /* Saving throw */
+ if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You resist the effects!");
+ }
+ else
+ {
+ /* Confuse, stun, terrify */
+ switch (randint(4))
+ {
+ case 1:
+ set_stun(p_ptr->stun + dam / 2);
+ break;
+ case 2:
+ set_confused(p_ptr->confused + dam / 2);
+ break;
+ default:
+ {
+ if (r_ptr->flags3 & (RF3_NO_FEAR))
+ note = " is unaffected.";
+ else
+ set_afraid(p_ptr->afraid + dam);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ }
+ else
+ {
+ if ((dam > 29) && (randint(100) < dam))
+ {
+ note = " is in your thrall!";
+ m_ptr->status = MSTATUS_PET;
+ if ((r_ptr->flags3 & RF3_ANIMAL) && (!(r_ptr->flags3 & RF3_EVIL)))
+ inc_piety(GOD_YAVANNA, m_ptr->level * 2);
+ }
+ else
+ {
+ switch (randint(4))
+ {
+ case 1:
+ do_stun = dam / 2;
+ break;
+ case 2:
+ do_conf = dam / 2;
+ break;
+ default:
+ do_fear = dam;
+ }
+ }
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+
+ /* Ice -- Cold + Cuts + Stun */
+ case GF_ICE:
+ {
+ if (seen) obvious = TRUE;
+ do_stun = (randint(15) + 1) / (r + 1);
+ if (magik(33)) do_cut = (10 + randint(15) + r) / (r + 1);
+ if (r_ptr->flags3 & (RF3_SUSCEP_COLD))
+ {
+ note = " is hit hard.";
+ dam *= 3;
+ do_cut *= 2;
+ if (seen) r_ptr->r_flags3 |= (RF3_SUSCEP_COLD);
+ }
+ if (r_ptr->flags3 & (RF3_IM_COLD))
+ {
+ note = " resists a lot.";
+ dam /= 9;
+ do_cut = 0;
+ if (seen) r_ptr->r_flags3 |= (RF3_IM_COLD);
+ }
+ break;
+ }
+
+
+ /* Drain Life */
+ case GF_OLD_DRAIN:
+ {
+ if (seen) obvious = TRUE;
+
+ if ((r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags3 & (RF3_DEMON)) ||
+ (r_ptr->flags3 & (RF3_NONLIVING)) ||
+ (strchr("Egv", r_ptr->d_char)))
+ {
+ if (r_ptr->flags3 & (RF3_UNDEAD))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
+ }
+ if (r_ptr->flags3 & (RF3_DEMON))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_DEMON);
+ }
+
+ note = " is unaffected!";
+ obvious = FALSE;
+ dam = 0;
+ }
+
+ break;
+ }
+
+ /* Death Ray */
+ case GF_DEATH_RAY:
+ {
+ if (seen) obvious = TRUE;
+ if ((r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags3 & (RF3_NONLIVING)))
+ {
+ if (r_ptr->flags3 & (RF3_UNDEAD))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
+ }
+
+ note = " is immune.";
+ obvious = FALSE;
+ dam = 0;
+ }
+ else if (((r_ptr->flags1 & (RF1_UNIQUE)) &&
+ (randint(888) != 666)) ||
+ (((m_ptr->level + randint(20)) > randint((dam) + randint(10))) &&
+ randint(100) != 66 ))
+ {
+ note = " resists!";
+ obvious = FALSE;
+ dam = 0;
+ }
+
+ else dam = (p_ptr->lev) * 200;
+
+ break;
+ }
+
+ /* Polymorph monster (Use "dam" as "power") */
+ case GF_OLD_POLY:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Attempt to polymorph (see below) */
+ do_poly = TRUE;
+
+ /* Powerful monsters can resist */
+ if ((r_ptr->flags1 & RF1_UNIQUE) ||
+ (m_ptr->mflag & MFLAG_QUEST) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ note = " is unaffected!";
+ do_poly = FALSE;
+ obvious = FALSE;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+
+ break;
+ }
+
+
+ /* Clone monsters (Ignore "dam") */
+ case GF_OLD_CLONE:
+ {
+ bool_ is_frien = FALSE;
+
+ if (seen) obvious = TRUE;
+ if ((is_friend(m_ptr) > 0) && (randint(3) != 1))
+ is_frien = TRUE;
+
+ /* Heal fully */
+ m_ptr->hp = m_ptr->maxhp;
+
+ /* Speed up */
+ if (m_ptr->mspeed < 150) m_ptr->mspeed += 10;
+
+ /* Attempt to clone. */
+ if (multiply_monster(c_ptr->m_idx, is_frien, TRUE))
+ {
+ note = " spawns!";
+ }
+
+ /* No "real" damage */
+ dam = 0;
+
+ break;
+ }
+
+
+ /* Heal Monster (use "dam" as amount of healing) */
+ case GF_OLD_HEAL:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Wake up */
+ m_ptr->csleep = 0;
+
+ /* Heal */
+ m_ptr->hp += dam;
+
+ /* No overflow */
+ if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
+
+ /* Redraw (later) if needed */
+ if (health_who == c_ptr->m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Message */
+ note = " looks healthier.";
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Speed Monster (Ignore "dam") */
+ case GF_OLD_SPEED:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Speed up */
+ if (m_ptr->mspeed < m_ptr->speed + 15) m_ptr->mspeed += 10;
+ note = " starts moving faster.";
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Slow Monster (Use "dam" as "power") */
+ case GF_OLD_SLOW:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Powerful monsters can resist */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+
+ /* Normal monsters slow down */
+ else
+ {
+ if (m_ptr->mspeed > 60) m_ptr->mspeed -= 10;
+ note = " starts moving slower.";
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Sleep (Use "dam" as "power") */
+ case GF_OLD_SLEEP:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags3 & (RF3_NO_SLEEP)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Memorize a flag */
+ if (r_ptr->flags3 & (RF3_NO_SLEEP))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_NO_SLEEP);
+ }
+
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ else
+ {
+ /* Go to sleep (much) later */
+ note = " falls asleep!";
+ do_sleep = 500;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Sleep (Use "dam" as "power") */
+ case GF_STASIS:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ else
+ {
+ /* Go to sleep (much) later */
+ note = " is suspended!";
+ do_sleep = 500;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ /* Charm monster */
+ case GF_CHARM:
+ {
+ dam += (adj_con_fix[p_ptr->stat_ind[A_CHR]] - 1);
+
+ if (seen) obvious = TRUE;
+
+ /* Attempt a saving throw */
+ if ((m_ptr->mflag & MFLAG_QUEST) ||
+ (r_ptr->flags3 & RF3_NO_CONF) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 5))
+ {
+ /* Memorize a flag */
+ if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ /* Resist */
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ else if (p_ptr->aggravate)
+ {
+ note = " hates you too much!";
+ }
+ else
+ {
+ if (is_friend(m_ptr) < 0)
+ {
+ note = " suddenly seems friendly!";
+ m_ptr->status = MSTATUS_FRIEND;
+ if ((r_ptr->flags3 & RF3_ANIMAL) && (!(r_ptr->flags3 & RF3_EVIL)))
+ inc_piety(GOD_YAVANNA, m_ptr->level * 2);
+ }
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ /* *Charm* monster */
+ case GF_STAR_CHARM:
+ {
+ dam += (adj_con_fix[p_ptr->stat_ind[A_CHR]] - 1);
+
+ if (seen) obvious = TRUE;
+
+ /* Attempt a saving throw */
+ if ((m_ptr->mflag & MFLAG_QUEST) ||
+ (r_ptr->flags3 & RF3_NO_CONF) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 5))
+ {
+ /* Memorize a flag */
+ if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ /* Resist */
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ else if (p_ptr->aggravate)
+ {
+ note = " hates you too much!";
+ }
+ else
+ {
+ if (is_friend(m_ptr) < 0)
+ {
+ note = " suddenly seems friendly!";
+ if (can_create_companion()) m_ptr->status = MSTATUS_COMPANION;
+ else m_ptr->status = MSTATUS_PET;
+
+ if ((r_ptr->flags3 & RF3_ANIMAL) && (!(r_ptr->flags3 & RF3_EVIL)))
+ inc_piety(GOD_YAVANNA, m_ptr->level * 2);
+ }
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ /* Control undead */
+ case GF_CONTROL_UNDEAD:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & RF1_UNIQUE) ||
+ (m_ptr->mflag & MFLAG_QUEST) ||
+ (!(r_ptr->flags3 & RF3_UNDEAD)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Resist */
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ else if (p_ptr->aggravate)
+ {
+ note = " hates you too much!";
+ }
+ else
+ {
+ note = " is in your thrall!";
+ m_ptr->status = MSTATUS_PET;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ /* Control never-moving */
+ case GF_CHARM_UNMOVING:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & RF1_UNIQUE) ||
+ (m_ptr->mflag & MFLAG_QUEST) ||
+ (!(r_ptr->flags1 & RF1_NEVER_MOVE)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Resist */
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ else if (p_ptr->aggravate)
+ {
+ note = " hates you too much!";
+ }
+ else
+ {
+ note = " is in your thrall!";
+ m_ptr->status = MSTATUS_PET;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ /* Tame animal */
+ case GF_CONTROL_ANIMAL:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (m_ptr->mflag & MFLAG_QUEST) ||
+ (!(r_ptr->flags3 & (RF3_ANIMAL))) ||
+ (r_ptr->flags3 & (RF3_NO_CONF)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Memorize a flag */
+ if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ /* Resist */
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ else if (p_ptr->aggravate)
+ {
+ note = " hates you too much!";
+ }
+ else
+ {
+ note = " is tamed!";
+ m_ptr->status = MSTATUS_PET;
+ inc_piety(GOD_YAVANNA, m_ptr->level * 2);
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ /* Control demon */
+ case GF_CONTROL_DEMON:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (m_ptr->mflag & MFLAG_QUEST) ||
+ (!(r_ptr->flags3 & (RF3_DEMON))) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Memorize a flag */
+ if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ /* Resist */
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ else if (p_ptr->aggravate)
+ {
+ note = " hates you too much!";
+ }
+ else
+ {
+ note = " obeys your commands!";
+ m_ptr->status = MSTATUS_PET;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ /* Confusion (Use "dam" as "power") */
+ case GF_OLD_CONF:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Get confused later */
+ do_conf = damroll(3, (dam / 2)) + 1;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags3 & (RF3_NO_CONF)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Memorize a flag */
+ if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ /* Resist */
+ do_conf = 0;
+
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ case GF_STUN:
+ {
+ if (seen) obvious = TRUE;
+
+ do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
+
+ /* Attempt a saving throw */
+ if ((m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Resist */
+ do_stun = 0;
+
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ /* Confusion (Use "dam" as "power") */
+ case GF_CONF_DAM:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Get confused later */
+ do_conf = damroll(3, (dam / 2)) + 1;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags3 & (RF3_NO_CONF)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Memorize a flag */
+ if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ /* Resist */
+ do_conf = 0;
+
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ break;
+ }
+
+ case GF_STUN_DAM:
+ {
+ if (seen) obvious = TRUE;
+
+ do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
+
+ /* Attempt a saving throw */
+ if ((m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Resist */
+ do_stun = 0;
+
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ break;
+ }
+
+ /* Implosion is the same than Stun_dam but only affect the living */
+ case GF_IMPLOSION:
+ {
+ if (seen) obvious = TRUE;
+
+ do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Resist */
+ do_stun = 0;
+
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+
+ /* Non_living resists */
+ if (r_ptr->flags3 & (RF3_NONLIVING))
+ {
+ /* Resist */
+ do_stun = 0;
+ dam = 0;
+
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ break;
+ }
+
+ /* Confusion & Stunning (Use "dam" as "power") */
+ case GF_STUN_CONF:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Get confused later */
+ do_conf = damroll(3, (dam / 2)) + 1;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags3 & (RF3_NO_CONF)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Memorize a flag */
+ if (r_ptr->flags3 & (RF3_NO_CONF))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
+ }
+
+ /* Resist */
+ do_conf = 0;
+
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+
+ do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
+
+ /* Attempt a saving throw */
+ if ((m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* Resist */
+ do_stun = 0;
+
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ }
+ break;
+ }
+
+
+ /* Lite, but only hurts susceptible creatures */
+ case GF_LITE_WEAK:
+ {
+ /* Hurt by light */
+ if (r_ptr->flags3 & (RF3_HURT_LITE))
+ {
+ /* Obvious effect */
+ if (seen) obvious = TRUE;
+
+ /* Memorize the effects */
+ if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
+
+ /* Special effect */
+ note = " cringes from the light!";
+ note_dies = " shrivels away in the light!";
+ }
+
+ /* Normally no damage */
+ else
+ {
+ /* No damage */
+ dam = 0;
+ }
+
+ break;
+ }
+
+
+
+ /* Lite -- opposite of Dark */
+ case GF_LITE:
+ {
+ if (seen) obvious = TRUE;
+ if (r_ptr->flags4 & (RF4_BR_LITE))
+ {
+ note = " resists.";
+ dam *= 2;
+ dam /= (randint(6) + 6);
+ }
+ else if (r_ptr->flags3 & (RF3_HURT_LITE))
+ {
+ if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
+ note = " cringes from the light!";
+ note_dies = " shrivels away in the light!";
+ dam *= 2;
+ }
+ break;
+ }
+
+
+ /* Dark -- opposite of Lite */
+ case GF_DARK:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Likes darkness... */
+ if ((r_ptr->flags4 & (RF4_BR_DARK)) ||
+ (r_ptr->flags3 & RF3_ORC) ||
+ (r_ptr->flags3 & RF3_HURT_LITE))
+ {
+ note = " resists.";
+ dam *= 2;
+ dam /= (randint(6) + 6);
+ }
+ break;
+ }
+
+
+ /* Stone to Mud */
+ case GF_KILL_WALL:
+ {
+ /* Hurt by rock remover */
+ if (r_ptr->flags3 & (RF3_HURT_ROCK))
+ {
+ /* Notice effect */
+ if (seen) obvious = TRUE;
+
+ /* Memorize the effects */
+ if (seen) r_ptr->r_flags3 |= (RF3_HURT_ROCK);
+
+ /* Cute little message */
+ note = " loses some skin!";
+ note_dies = " dissolves!";
+ }
+
+ /* Usually, ignore the effects */
+ else
+ {
+ /* No damage */
+ dam = 0;
+ }
+
+ break;
+ }
+
+
+ /* Teleport undead (Use "dam" as "power") */
+ case GF_AWAY_UNDEAD:
+ {
+
+ if (dungeon_flags2 & DF2_NO_TELEPORT) break; /* No teleport on special levels */
+ /* Only affect undead */
+ if (r_ptr->flags3 & (RF3_UNDEAD))
+ {
+ bool_ resists_tele = FALSE;
+
+ if (r_ptr->flags3 & (RF3_RES_TELE))
+ {
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
+ note = " is unaffected!";
+ resists_tele = TRUE;
+ }
+ else if (m_ptr->level > randint(100))
+ {
+ if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
+ note = " resists!";
+ resists_tele = TRUE;
+ }
+ }
+
+ if (!resists_tele)
+ {
+ if (seen) obvious = TRUE;
+ if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
+ do_dist = dam;
+ }
+ }
+
+ /* Others ignore */
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Teleport evil (Use "dam" as "power") */
+ case GF_AWAY_EVIL:
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT) break; /* No teleport on special levels */
+ /* Only affect evil */
+ if (r_ptr->flags3 & (RF3_EVIL))
+ {
+ bool_ resists_tele = FALSE;
+
+ if (r_ptr->flags3 & (RF3_RES_TELE))
+ {
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
+ note = " is unaffected!";
+ resists_tele = TRUE;
+ }
+ else if (m_ptr->level > randint(100))
+ {
+ if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
+ note = " resists!";
+ resists_tele = TRUE;
+ }
+ }
+
+ if (!resists_tele)
+ {
+ if (seen) obvious = TRUE;
+ if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
+ do_dist = dam;
+ }
+ }
+
+ /* Others ignore */
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Teleport monster (Use "dam" as "power") */
+ case GF_AWAY_ALL:
+ {
+ bool_ resists_tele = FALSE;
+
+ if (dungeon_flags2 & DF2_NO_TELEPORT) break; /* No teleport on special levels */
+ if (r_ptr->flags3 & (RF3_RES_TELE))
+ {
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
+ note = " is unaffected!";
+ resists_tele = TRUE;
+ }
+ else if (m_ptr->level > randint(100))
+ {
+ if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
+ note = " resists!";
+ resists_tele = TRUE;
+ }
+ }
+
+ if (!resists_tele)
+ {
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Prepare to teleport */
+ do_dist = dam;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Turn undead (Use "dam" as "power") */
+ case GF_TURN_UNDEAD:
+ {
+ /* Only affect undead */
+ if (r_ptr->flags3 & (RF3_UNDEAD))
+ {
+ /* Learn about type */
+ if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
+
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Apply some fear */
+ do_fear = damroll(3, (dam / 2)) + 1;
+
+ /* Attempt a saving throw */
+ if (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10)
+ {
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ do_fear = 0;
+ }
+ }
+
+ /* Others ignore */
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Turn evil (Use "dam" as "power") */
+ case GF_TURN_EVIL:
+ {
+ /* Only affect evil */
+ if (r_ptr->flags3 & (RF3_EVIL))
+ {
+ /* Learn about type */
+ if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
+
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Apply some fear */
+ do_fear = damroll(3, (dam / 2)) + 1;
+
+ /* Attempt a saving throw */
+ if (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10)
+ {
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ do_fear = 0;
+ }
+ }
+
+ /* Others ignore */
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Turn monster (Use "dam" as "power") */
+ case GF_TURN_ALL:
+ {
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Apply some fear */
+ do_fear = damroll(3, (dam / 2)) + 1;
+
+ /* Attempt a saving throw */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (r_ptr->flags3 & (RF3_NO_FEAR)) ||
+ (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
+ {
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ do_fear = 0;
+ }
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+
+ /* Dispel undead */
+ case GF_DISP_UNDEAD:
+ {
+ /* Only affect undead */
+ if (r_ptr->flags3 & (RF3_UNDEAD))
+ {
+ /* Learn about type */
+ if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
+
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Message */
+ note = " shudders.";
+ note_dies = " dissolves!";
+ }
+
+ /* Others ignore */
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+
+ /* No damage */
+ dam = 0;
+ }
+
+ break;
+ }
+
+
+ /* Dispel evil */
+ case GF_DISP_EVIL:
+ {
+ /* Only affect evil */
+ if (r_ptr->flags3 & (RF3_EVIL))
+ {
+ /* Learn about type */
+ if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
+
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Message */
+ note = " shudders.";
+ note_dies = " dissolves!";
+ }
+
+ /* Others ignore */
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+
+ /* No damage */
+ dam = 0;
+ }
+
+ break;
+ }
+
+ /* Dispel good */
+ case GF_DISP_GOOD:
+ {
+ /* Only affect good */
+ if (r_ptr->flags3 & (RF3_GOOD))
+ {
+ /* Learn about type */
+ if (seen) r_ptr->r_flags3 |= (RF3_GOOD);
+
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Message */
+ note = " shudders.";
+ note_dies = " dissolves!";
+ }
+
+ /* Others ignore */
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+
+ /* No damage */
+ dam = 0;
+ }
+
+ break;
+ }
+
+ /* Dispel living */
+ case GF_DISP_LIVING:
+ {
+ /* Only affect non-undead */
+ if (!(r_ptr->flags3 & (RF3_UNDEAD)) &&
+ !(r_ptr->flags3 & (RF3_NONLIVING)))
+ {
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Message */
+ note = " shudders.";
+ note_dies = " dissolves!";
+ }
+
+ /* Others ignore */
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+
+ /* No damage */
+ dam = 0;
+ }
+
+ break;
+ }
+
+ /* Dispel demons */
+ case GF_DISP_DEMON:
+ {
+ /* Only affect demons */
+ if (r_ptr->flags3 & (RF3_DEMON))
+ {
+ /* Learn about type */
+ if (seen) r_ptr->r_flags3 |= (RF3_DEMON);
+
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Message */
+ note = " shudders.";
+ note_dies = " dissolves!";
+ }
+
+ /* Others ignore */
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+
+ /* No damage */
+ dam = 0;
+ }
+
+ break;
+ }
+
+ /* Dispel monster */
+ case GF_DISP_ALL:
+ {
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Message */
+ note = " shudders.";
+ note_dies = " dissolves!";
+
+ break;
+ }
+
+ /* Raise Death -- Heal monster */
+ case GF_RAISE:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Wake up */
+ m_ptr->csleep = 0;
+
+ /* Heal */
+ m_ptr->hp += dam;
+
+ /* No overflow */
+ if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
+
+ /* Redraw (later) if needed */
+ if (health_who == c_ptr->m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Message */
+ note = " looks healthier.";
+
+ /* No "real" damage */
+ dam = 0;
+ break;
+ }
+
+ /* Trap the soul of a demon and leave body */
+ case GF_TRAP_DEMONSOUL:
+ {
+ if (seen) obvious = TRUE;
+
+ /* Check race */
+ if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
+ (m_ptr->mflag & MFLAG_QUEST) ||
+ (!(r_ptr->flags3 & (RF3_DEMON))))
+ {
+ /* No obvious effect */
+ note = " is unaffected!";
+ obvious = FALSE;
+ dam = 0;
+ }
+ /* Hack : drop corpse if the demon is killed by this
+ * spell */
+ else if (dam > m_ptr->hp)
+ {
+ object_type forge, *i_ptr = &forge;
+
+ /* Wipe the object */
+ object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_CORPSE));
+
+ /* Unique corpses are unique */
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ object_aware(i_ptr);
+ i_ptr->name1 = 201;
+ }
+
+ /* Length of decay - very long time */
+ i_ptr->pval = 100000;
+
+ /* Set weight */
+ i_ptr->weight = (r_ptr->weight + rand_int(r_ptr->weight) / 10) + 1;
+
+ /* Remember what we are */
+ i_ptr->pval2 = m_ptr->r_idx;
+
+ /* Give HP */
+ i_ptr->pval3 = maxroll(r_ptr->hdice, r_ptr->hside);
+
+ /* Drop it */
+ drop_near(i_ptr, -1, y, x);
+ }
+
+ break;
+ }
+
+ /* Default */
+ default:
+ {
+ /* Hooks! */
+ if (process_hooks_ret(HOOK_GF_EXEC, "dddddddddss", "(s,d,d,d,d,d,d,M)", "monster", who, typ, dam, r, y, x, m_ptr))
+ {
+ obvious = process_hooks_return[0].num;
+ dam = process_hooks_return[1].num;
+ do_stun = process_hooks_return[2].num;
+ do_fear = process_hooks_return[3].num;
+ do_conf = process_hooks_return[4].num;
+ do_dist = process_hooks_return[5].num;
+ do_pois = process_hooks_return[6].num;
+ do_cut = process_hooks_return[7].num;
+ do_poly = process_hooks_return[8].num;
+ if (process_hooks_return[9].str != NULL)
+ note = process_hooks_return[9].str;
+ if (process_hooks_return[10].str != NULL)
+ note_dies = process_hooks_return[10].str;
+ }
+ else
+ {
+ /* Irrelevant */
+ skipped = TRUE;
+
+ /* No damage */
+ dam = 0;
+ }
+ break;
+ }
+ }
+
+
+ /* Absolutely no effect */
+ if (skipped) return (FALSE);
+
+
+ /* "Unique" monsters cannot be polymorphed */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) do_poly = FALSE;
+
+ /*
+ * "Quest" monsters cannot be polymorphed
+ */
+ if (m_ptr->mflag & MFLAG_QUEST)
+ do_poly = FALSE;
+
+ /* "Unique" monsters can only be "killed" by the player unless they are player's friends */
+ if ((r_ptr->flags1 & RF1_UNIQUE) && (m_ptr->status <= MSTATUS_NEUTRAL_P))
+ {
+ /* Uniques may only be killed by the player */
+ if (who && (who != -2) && (dam > m_ptr->hp)) dam = m_ptr->hp;
+ }
+
+ /*
+ * "Quest" monsters can only be "killed" by the player
+ */
+ if (m_ptr->mflag & MFLAG_QUEST)
+ {
+ if ((who > 0) && (dam > m_ptr->hp)) dam = m_ptr->hp;
+ }
+
+ if (do_pois && (!(r_ptr->flags3 & RF3_IM_POIS)) && (!(r_ptr->flags3 & RF4_BR_POIS)) && hurt_monster(m_ptr))
+ {
+ if (m_ptr->poisoned) note = " is more poisoned.";
+ else note = " is poisoned.";
+ m_ptr->poisoned += do_pois;
+ }
+
+ if (do_cut && (!(r_ptr->flags4 & RF4_BR_WALL)) && hurt_monster(m_ptr))
+ {
+ if (m_ptr->bleeding) note = " bleeds more strongly.";
+ else note = " starts bleeding.";
+ m_ptr->bleeding += do_cut;
+ }
+
+ /* Check for death */
+ if ((dam > m_ptr->hp) && hurt_monster(m_ptr))
+ {
+ /* Extract method of death */
+ note = note_dies;
+ }
+
+ /* Mega-Hack -- Handle "polymorph" -- monsters get a saving throw */
+ else if (do_poly && cave_floor_bold(y, x) && (randint(90) > m_ptr->level))
+ {
+ /* Default -- assume no polymorph */
+ note = " is unaffected!";
+
+ /* Handle polymorph */
+ if (do_poly_monster(y, x))
+ {
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Monster polymorphs */
+ note = " changes!";
+
+ /* Turn off the damage */
+ dam = 0;
+
+ /* Hack -- Get new monster */
+ m_ptr = &m_list[c_ptr->m_idx];
+
+ /* Hack -- Get new race */
+ r_ptr = race_inf(m_ptr);
+ }
+ }
+
+ /* Handle moving the monster.
+ *
+ * Note: This is a effect of force, but only when used
+ * by the player. (For the moment). The usual stun effect
+ * is not applied.
+ */
+ else if (do_move && hurt_monster(m_ptr))
+ {
+ int back = 0;
+
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ back = 0; /* Default of no movement */
+
+ /* How far can we push the monster? */
+ for (do_move = 1; do_move < 3; do_move++)
+ {
+ /* Get monster coords */
+ /* And offset position */
+ y1 = m_ptr->fy + (b * do_move);
+ x1 = m_ptr->fx + (a * do_move);
+
+ if (!in_bounds(y1, x1)) continue;
+
+ /* Require "empty" floor space */
+ if (!in_bounds(y1, x1) || !cave_empty_bold(y1, x1)) continue;
+
+ /* Hack -- no teleport onto glyph of warding */
+ if (cave[y1][x1].feat == FEAT_GLYPH) continue;
+
+ /* amount moved */
+ back = do_move;
+ }
+
+ /* Move the monster */
+ if (back)
+ {
+ y1 = m_ptr->fy + (b * back);
+ x1 = m_ptr->fx + (a * back);
+ monster_swap(m_ptr->fy, m_ptr->fx, y1, x1);
+
+ if (back == 2)
+ {
+ note = " is knocked back!";
+ }
+ if (back == 1)
+ {
+ note = " is knocked back and crushed!";
+
+ /* was kept from being pushed all the way, do extra dam */
+ dam = dam * 13 / 10;
+ }
+
+ /* Get new position */
+ y = y1;
+ x = x1;
+
+ /* Hack -- get new grid */
+ c_ptr = &cave[y][x];
+ }
+ else /* could not move the monster */
+ {
+ note = " is severely crushed!";
+
+ /* Do extra damage (1/3)*/
+ dam = dam * 15 / 10;
+ }
+
+ }
+
+ /* Handle "teleport" */
+ else if (do_dist)
+ {
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Message */
+ note = " disappears!";
+
+ /* Teleport */
+ teleport_away(c_ptr->m_idx, do_dist);
+
+ /* Hack -- get new location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Hack -- get new grid */
+ c_ptr = &cave[y][x];
+ }
+
+ /* Sound and Impact breathers never stun */
+ else if (do_stun &&
+ !(r_ptr->flags4 & (RF4_BR_SOUN)) &&
+ !(r_ptr->flags4 & (RF4_BR_WALL)) && hurt_monster(m_ptr))
+ {
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Get confused */
+ if (m_ptr->stunned)
+ {
+ note = " is more dazed.";
+ tmp = m_ptr->stunned + (do_stun / 2);
+ }
+ else
+ {
+ note = " is dazed.";
+ tmp = do_stun;
+ }
+
+ /* Apply stun */
+ m_ptr->stunned = (tmp < 200) ? tmp : 200;
+ }
+
+ /* Confusion and Chaos breathers (and sleepers) never confuse */
+ else if (do_conf &&
+ !(r_ptr->flags3 & (RF3_NO_CONF)) &&
+ !(r_ptr->flags4 & (RF4_BR_CONF)) &&
+ !(r_ptr->flags4 & (RF4_BR_CHAO)) && hurt_monster(m_ptr))
+ {
+ /* Obvious */
+ if (seen) obvious = TRUE;
+
+ /* Already partially confused */
+ if (m_ptr->confused)
+ {
+ note = " looks more confused.";
+ tmp = m_ptr->confused + (do_conf / 2);
+ }
+
+ /* Was not confused */
+ else
+ {
+ note = " looks confused.";
+ tmp = do_conf;
+ }
+
+ /* Apply confusion */
+ m_ptr->confused = (tmp < 200) ? tmp : 200;
+ }
+
+
+ /* Fear */
+ if (do_fear && hurt_monster(m_ptr))
+ {
+ /* Increase fear */
+ tmp = m_ptr->monfear + do_fear;
+
+ /* Set fear */
+ m_ptr->monfear = (tmp < 200) ? tmp : 200;
+ }
+
+
+ /* If another monster did the damage, hurt the monster by hand */
+ if (who > 0)
+ {
+ bool_ fear = FALSE;
+
+ /* Dead monster */
+ if (mon_take_hit_mon(who, c_ptr->m_idx, dam, &fear, note_dies))
+ {}
+
+ /* Damaged monster */
+ else
+ {
+ /* Give detailed messages if visible or destroyed */
+ if (note && seen) msg_format("%^s%s", m_name, note);
+
+ /* Hack -- Pain message */
+ else if (dam > 0) message_pain(c_ptr->m_idx, dam);
+
+ /* Hack -- handle sleep */
+ if (do_sleep) m_ptr->csleep = do_sleep;
+ }
+ }
+ /* If the player did it, give him experience, check fear */
+ else if (hurt_monster(m_ptr))
+ {
+ bool_ fear = FALSE;
+
+ /* Hurt the monster, check for fear and death */
+ if (mon_take_hit(c_ptr->m_idx, dam, &fear, note_dies))
+ {
+ /* Dead monster */
+ }
+
+ /* Damaged monster */
+ else
+ {
+ /* Give detailed messages if visible or destroyed */
+ if (note && seen) msg_format("%^s%s", m_name, note);
+
+ /* Hack -- Pain message */
+ else if (dam > 0) message_pain(c_ptr->m_idx, dam);
+
+ /* Take note */
+ if ((fear || do_fear) && (m_ptr->ml))
+ {
+ /* Sound */
+ sound(SOUND_FLEE);
+
+ /* Message */
+ msg_format("%^s flees in terror!", m_name);
+ }
+
+ /* Hack -- handle sleep */
+ if (do_sleep) m_ptr->csleep = do_sleep;
+ }
+ }
+
+
+ /* XXX XXX XXX Verify this code */
+
+ /* Update the monster */
+ update_mon(c_ptr->m_idx, FALSE);
+
+ /* Redraw the monster grid */
+ lite_spot(y, x);
+
+
+ /* Update monster recall window */
+ if (monster_race_idx == m_ptr->r_idx)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+ }
+
+
+ /* Track it */
+ project_m_n++;
+ project_m_x = x;
+ project_m_y = y;
+
+
+ /* Return "Anything seen?" */
+ return (obvious);
+}
+
+
+/* Is the spell unsafe for the player ? */
+bool_ unsafe = FALSE;
+
+
+/*
+ * Helper function for "project()" below.
+ *
+ * Handle a beam/bolt/ball causing damage to the player.
+ *
+ * This routine takes a "source monster" (by index), a "distance", a default
+ * "damage", and a "damage type". See "project_m()" above.
+ *
+ * If "rad" is non-zero, then the blast was centered elsewhere, and the damage
+ * is reduced (see "project_m()" above). This can happen if a monster breathes
+ * at the player and hits a wall instead.
+ *
+ * NOTE (Zangband): 'Bolt' attacks can be reflected back, so we need to know
+ * if this is actually a ball or a bolt spell
+ *
+ *
+ * We return "TRUE" if any "obvious" effects were observed. XXX XXX Actually,
+ * we just assume that the effects were obvious, for historical reasons.
+ */
+static bool_ project_p(int who, int r, int y, int x, int dam, int typ, int a_rad)
+{
+ int k = 0, do_move = 0, a = 0, b = 0, x1 = 0, y1 = 0;
+
+ /* Hack -- assume obvious */
+ bool_ obvious = TRUE;
+
+ /* Player blind-ness */
+ bool_ blind = (p_ptr->blind ? TRUE : FALSE);
+
+ /* Player needs a "description" (he is blind) */
+ bool_ fuzzy = FALSE;
+
+ /* Source monster */
+ monster_type *m_ptr = NULL;
+
+ /* Monster name (for attacks) */
+ char m_name[80];
+
+ /* Monster name (for damage) */
+ char killer[80];
+
+ /* Hack -- messages */
+ cptr act = NULL;
+
+
+ /* Player is not here */
+ if ((x != p_ptr->px) || (y != p_ptr->py)) return (FALSE);
+
+ /* Player cannot hurt himself */
+ if ((!who) && (!unsafe)) return (FALSE);
+
+ /* Bolt attack from a monster */
+ if ((!a_rad) && get_skill(SKILL_DODGE) && (who > 0))
+ {
+ int chance = (p_ptr->dodge_chance - ((r_info[who].level * 5) / 6)) / 3;
+
+ if ((chance > 0) && magik(chance))
+ {
+ msg_print("You dodge a magical attack!");
+ return (TRUE);
+ }
+ }
+
+ /* Effects done by the plane cannot bounce */
+ if (p_ptr->reflect && !a_rad && !(randint(10) == 1) && ((who != -101) && (who != -100)))
+ {
+ int t_y, t_x;
+ int max_attempts = 10;
+
+ if (blind) msg_print("Something bounces!");
+ else msg_print("The attack bounces!");
+
+ /* Choose 'new' target */
+ do
+ {
+ t_y = m_list[who].fy - 1 + randint(3);
+ t_x = m_list[who].fx - 1 + randint(3);
+ max_attempts--;
+ }
+ while (max_attempts && in_bounds2(t_y, t_x) &&
+ !(player_has_los_bold(t_y, t_x)));
+
+ if (max_attempts < 1)
+ {
+ t_y = m_list[who].fy;
+ t_x = m_list[who].fx;
+ }
+
+ project(0, 0, t_y, t_x, dam, typ, (PROJECT_STOP | PROJECT_KILL));
+
+ disturb(1, 0);
+ return TRUE;
+ }
+
+ /* XXX XXX XXX */
+ /* Limit maximum damage */
+ if (dam > 1600) dam = 1600;
+
+ /* Reduce damage by distance */
+ dam = (dam + r) / (r + 1);
+
+
+ /* If the player is blind, be more descriptive */
+ if (blind) fuzzy = TRUE;
+
+ /* If the player is hit by a trap, be more descritive */
+ if (who == -2) fuzzy = TRUE;
+
+ /* Did ``God'' do it? */
+ if (who == -99)
+ {
+ if (p_ptr->pgod)
+ {
+ /* Find out the name of player's god. */
+ sprintf(killer, "%s",
+ deity_info[p_ptr->pgod].name);
+ }
+ else strcpy(killer, "Divine Wrath");
+ }
+
+ /* Did the dungeon do it? */
+ if (who == -100)
+ {
+ sprintf(killer, "%s",
+ d_name + d_info[dungeon_type].name);
+ }
+ if (who == -101)
+ {
+ sprintf(killer, "%s",
+ f_name + f_info[cave[p_ptr->py][p_ptr->px].feat].name);
+ }
+
+ if (who >= -1)
+ {
+ /* Get the source monster */
+ m_ptr = &m_list[who];
+
+ /* Get the monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Get the monster's real name */
+ monster_desc(killer, m_ptr, 0x88);
+ }
+
+ if (who == -2)
+ {
+ sprintf(killer, "%s",
+ t_name + t_info[cave[p_ptr->py][p_ptr->px].t_idx].name);
+ }
+
+ /* Analyze the damage */
+ switch (typ)
+ {
+ case GF_DEATH_RAY:
+ {
+ if (fuzzy) msg_print("You are hit by pure death!");
+ take_hit(32000, killer);
+ break;
+ }
+
+ /* Standard damage -- hurts inventory too */
+ case GF_ACID:
+ {
+ if (fuzzy) msg_print("You are hit by acid!");
+ acid_dam(dam, killer);
+ break;
+ }
+
+ /* Standard damage -- hurts inventory too */
+ case GF_FIRE:
+ {
+ if (fuzzy) msg_print("You are hit by fire!");
+ fire_dam(dam, killer);
+ break;
+ }
+
+ /* Standard damage -- hurts inventory too */
+ case GF_COLD:
+ {
+ if (fuzzy) msg_print("You are hit by cold!");
+ cold_dam(dam, killer);
+ break;
+ }
+
+ /* Standard damage -- hurts inventory too */
+ case GF_ELEC:
+ {
+ if (fuzzy) msg_print("You are hit by lightning!");
+ elec_dam(dam, killer);
+ break;
+ }
+
+ /* Standard damage -- also poisons player */
+ case GF_POIS:
+ {
+ if (fuzzy) msg_print("You are hit by poison!");
+ if (p_ptr->resist_pois) dam = (dam + 2) / 3;
+ if (p_ptr->oppose_pois) dam = (dam + 2) / 3;
+
+ if ((!(p_ptr->oppose_pois || p_ptr->resist_pois)) &&
+ randint(HURT_CHANCE) == 1)
+ {
+ do_dec_stat(A_CON, STAT_DEC_NORMAL);
+ }
+
+ take_hit(dam, killer);
+
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ set_poisoned(p_ptr->poisoned + rand_int(dam) + 10);
+ }
+ break;
+ }
+
+ /* Standard damage -- also poisons / mutates player */
+ case GF_NUKE:
+ {
+ if (fuzzy) msg_print("You are hit by radiation!");
+ if (p_ptr->resist_pois) dam = (2 * dam + 2) / 5;
+ if (p_ptr->oppose_pois) dam = (2 * dam + 2) / 5;
+ take_hit(dam, killer);
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ set_poisoned(p_ptr->poisoned + rand_int(dam) + 10);
+
+ if (randint(5) == 1) /* 6 */
+ {
+ msg_print("You undergo a freakish metamorphosis!");
+ if (randint(4) == 1) /* 4 */
+ do_poly_self();
+ else
+ corrupt_player();
+ }
+
+ if (randint(6) == 1)
+ {
+ inven_damage(set_acid_destroy, 2);
+ }
+ }
+ break;
+ }
+
+ /* Standard damage */
+ case GF_MISSILE:
+ {
+ if (fuzzy) msg_print("You are hit by something!");
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Holy Orb -- Player only takes partial damage */
+ case GF_HOLY_FIRE:
+ {
+ if (fuzzy) msg_print("You are hit by something!");
+ take_hit(dam, killer);
+ break;
+ }
+
+ case GF_HELL_FIRE:
+ {
+ if (fuzzy) msg_print("You are hit by something!");
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Arrow -- XXX no dodging */
+ case GF_ARROW:
+ {
+ if (fuzzy) msg_print("You are hit by something sharp!");
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Plasma -- XXX No resist */
+ case GF_PLASMA:
+ {
+ if (fuzzy) msg_print("You are hit by something *HOT*!");
+ take_hit(dam, killer);
+
+ if (!p_ptr->resist_sound)
+ {
+ int k = (randint((dam > 40) ? 35 : (dam * 3 / 4 + 5)));
+ (void)set_stun(p_ptr->stun + k);
+ }
+
+ if (!(p_ptr->resist_fire ||
+ p_ptr->oppose_fire ||
+ p_ptr->immune_fire))
+ {
+ inven_damage(set_acid_destroy, 3);
+ }
+
+ break;
+ }
+
+ /* Nether -- drain experience */
+ case GF_NETHER:
+ {
+ if (fuzzy) msg_print("You are hit by nether forces!");
+ {
+ if (p_ptr->immune_neth)
+ {
+ dam = 0;
+ }
+ else if (p_ptr->resist_neth)
+ {
+ dam *= 6;
+ dam /= (randint(6) + 6);
+ }
+ else
+ {
+ if (p_ptr->hold_life && (rand_int(100) < 75))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(200 + (p_ptr->exp / 1000) * MON_DRAIN_LIFE);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(200 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
+ }
+ }
+
+ take_hit(dam, killer);
+ }
+
+ break;
+ }
+
+ /* Water -- stun/confuse */
+ case GF_WAVE:
+ case GF_WATER:
+ {
+ if (fuzzy) msg_print("You are hit by something wet!");
+ if (!p_ptr->resist_sound)
+ {
+ set_stun(p_ptr->stun + randint(40));
+ }
+ if (!p_ptr->resist_conf)
+ {
+ set_confused(p_ptr->confused + randint(5) + 5);
+ }
+
+ if (randint(5) == 1)
+ {
+ inven_damage(set_cold_destroy, 3);
+ }
+
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Chaos -- many effects */
+ case GF_CHAOS:
+ {
+ if (fuzzy) msg_print("You are hit by a wave of anarchy!");
+ if (p_ptr->resist_chaos)
+ {
+ dam *= 6;
+ dam /= (randint(6) + 6);
+ }
+ if (!p_ptr->resist_conf)
+ {
+ (void)set_confused(p_ptr->confused + rand_int(20) + 10);
+ }
+ if (!p_ptr->resist_chaos)
+ {
+ (void)set_image(p_ptr->image + randint(10));
+ }
+ if (!p_ptr->resist_neth && !p_ptr->resist_chaos)
+ {
+ if (p_ptr->hold_life && (rand_int(100) < 75))
+ {
+ msg_print("You keep hold of your life force!");
+ }
+ else if (p_ptr->hold_life)
+ {
+ msg_print("You feel your life slipping away!");
+ lose_exp(500 + (p_ptr->exp / 1000) * MON_DRAIN_LIFE);
+ }
+ else
+ {
+ msg_print("You feel your life draining away!");
+ lose_exp(5000 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
+ }
+ }
+ if ((!p_ptr->resist_chaos) || (randint(9) == 1))
+ {
+ inven_damage(set_elec_destroy, 2);
+ inven_damage(set_fire_destroy, 2);
+ }
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Shards -- mostly cutting */
+ case GF_SHARDS:
+ {
+ if (fuzzy) msg_print("You are hit by something sharp!");
+ if (p_ptr->resist_shard)
+ {
+ dam *= 6;
+ dam /= (randint(6) + 6);
+ }
+ else
+ {
+ (void)set_cut(p_ptr->cut + dam);
+ }
+
+ if ((!p_ptr->resist_shard) || (randint(13) == 1))
+ {
+ inven_damage(set_cold_destroy, 2);
+ }
+
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Sound -- mostly stunning */
+ case GF_SOUND:
+ {
+ if (fuzzy) msg_print("You are hit by a loud noise!");
+ if (p_ptr->resist_sound)
+ {
+ dam *= 5;
+ dam /= (randint(6) + 6);
+ }
+ else
+ {
+ int k = (randint((dam > 90) ? 35 : (dam / 3 + 5)));
+ (void)set_stun(p_ptr->stun + k);
+ }
+
+ if ((!p_ptr->resist_sound) || (randint(13) == 1))
+ {
+ inven_damage(set_cold_destroy, 2);
+ }
+
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Pure confusion */
+ case GF_CONFUSION:
+ {
+ if (fuzzy) msg_print("You are hit by something puzzling!");
+ if (p_ptr->resist_conf)
+ {
+ dam *= 5;
+ dam /= (randint(6) + 6);
+ }
+ if (!p_ptr->resist_conf)
+ {
+ (void)set_confused(p_ptr->confused + randint(20) + 10);
+ }
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Disenchantment -- see above */
+ case GF_DISENCHANT:
+ {
+ if (fuzzy) msg_print("You are hit by something static!");
+ if (p_ptr->resist_disen)
+ {
+ dam *= 6;
+ dam /= (randint(6) + 6);
+ }
+ else
+ {
+ (void)apply_disenchant(0);
+ }
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Nexus -- see above */
+ case GF_NEXUS:
+ {
+ if (fuzzy) msg_print("You are hit by something strange!");
+ if (p_ptr->resist_nexus)
+ {
+ dam *= 6;
+ dam /= (randint(6) + 6);
+ }
+ else
+ {
+ apply_nexus(m_ptr);
+ }
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Force -- mostly stun */
+ case GF_FORCE:
+ {
+ if (fuzzy) msg_print("You are hit by kinetic force!");
+ if (!p_ptr->resist_sound)
+ {
+ (void)set_stun(p_ptr->stun + randint(20));
+ /*
+ * If fired by player, try pushing monster.
+ * First get vector from player to monster.
+ * x10 so we can use pseudo-fixed point maths.
+ *
+ * Really should use get_angle_to_grid (util.c)
+ */
+ if (who > 0)
+ {
+ a = 0;
+ b = 0;
+
+ /* Get vector from firer to target */
+ x1 = (p_ptr->px - m_ptr->fx) * 10;
+ y1 = (p_ptr->py - m_ptr->fy) * 10;
+
+ /* Make sure no zero divides */
+ if (x1 == 0) x1 = 1;
+ if (y1 == 0) y1 = 1;
+
+ /* Select direction player is being pushed */
+
+ /* Roughly horizontally */
+ if ((2*y1) / x1 == 0)
+ {
+ if (x1 > 0)
+ {
+ a = 1, b = 0;
+ }
+ else
+ {
+ a = -1, b = 0;
+ }
+ }
+
+ /* Roughly vertically */
+ else if ((2*x1) / y1 == 0)
+ {
+ if (y1 > 0)
+ {
+ a = 0, b = 1;
+ }
+ else
+ {
+ a = 0, b = -1;
+ }
+ }
+
+ /* Take diagonals */
+ else
+ {
+ if (y1 > 0)
+ {
+ b = 1;
+ }
+ else
+ {
+ b = -1;
+ }
+ if (x1 > 0)
+ {
+ a = 1;
+ }
+ else
+ {
+ a = -1;
+ }
+ }
+
+ /* Move monster 2 offsets back */
+ do_move = 2;
+
+ /* Old monster coords in x,y */
+ y1 = p_ptr->py;
+ x1 = p_ptr->px;
+ }
+ }
+ else
+ take_hit(dam, killer);
+ break;
+ }
+
+
+ /* Rocket -- stun, cut */
+ case GF_ROCKET:
+ {
+ if (fuzzy) msg_print("There is an explosion!");
+ if (!p_ptr->resist_sound)
+ {
+ (void)set_stun(p_ptr->stun + randint(20));
+ }
+ if (p_ptr->resist_shard)
+ {
+ dam /= 2;
+ }
+ else
+ {
+ (void)set_cut(p_ptr-> cut + ( dam / 2) );
+ }
+
+ if ((!p_ptr->resist_shard) || (randint(12) == 1))
+ {
+ inven_damage(set_cold_destroy, 3);
+ }
+
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Inertia -- slowness */
+ case GF_INERTIA:
+ {
+ if (fuzzy) msg_print("You are hit by something slow!");
+ (void)set_slow(p_ptr->slow + rand_int(4) + 4);
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Lite -- blinding */
+ case GF_LITE:
+ {
+ if (fuzzy) msg_print("You are hit by something!");
+ if (p_ptr->resist_lite)
+ {
+ dam *= 4;
+ dam /= (randint(6) + 6);
+ }
+ else if (!blind && !p_ptr->resist_blind)
+ {
+ (void)set_blind(p_ptr->blind + randint(5) + 2);
+ }
+ if (p_ptr->sensible_lite)
+ {
+ msg_print("The light scorches your flesh!");
+ dam *= 3;
+ }
+ take_hit(dam, killer);
+
+ if (p_ptr->tim_wraith)
+ {
+ p_ptr->tim_wraith = 0;
+ msg_print("The light forces you out of your incorporeal shadow form.");
+
+ p_ptr->redraw |= PR_MAP;
+ /* Update monsters */
+ p_ptr->update |= (PU_MONSTERS);
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+ }
+
+ break;
+ }
+
+ /* Dark -- blinding */
+ case GF_DARK:
+ {
+ if (fuzzy) msg_print("You are hit by something!");
+ if (p_ptr->resist_dark)
+ {
+ dam *= 4;
+ dam /= (randint(6) + 6);
+ }
+ else if (!blind && !p_ptr->resist_blind)
+ {
+ (void)set_blind(p_ptr->blind + randint(5) + 2);
+ }
+ if (p_ptr->wraith_form) hp_player(dam);
+ else take_hit(dam, killer);
+ break;
+ }
+
+ /* Time -- bolt fewer effects XXX */
+ case GF_TIME:
+ {
+ if (fuzzy) msg_print("You are hit by a blast from the past!");
+
+ if (p_ptr->resist_continuum)
+ {
+ dam *= 4;
+ dam /= (randint(6) + 6);
+ msg_print("You feel as if time is passing you by.");
+ }
+ else
+ {
+ switch (randint(10))
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ {
+ msg_print("You feel life has clocked back.");
+ lose_exp(100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
+ break;
+ }
+
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ {
+ switch (randint(6))
+ {
+ case 1:
+ k = A_STR;
+ act = "strong";
+ break;
+ case 2:
+ k = A_INT;
+ act = "bright";
+ break;
+ case 3:
+ k = A_WIS;
+ act = "wise";
+ break;
+ case 4:
+ k = A_DEX;
+ act = "agile";
+ break;
+ case 5:
+ k = A_CON;
+ act = "hardy";
+ break;
+ case 6:
+ k = A_CHR;
+ act = "beautiful";
+ break;
+ }
+
+ msg_format("You're not as %s as you used to be...", act);
+
+ p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4;
+ if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3;
+ p_ptr->update |= (PU_BONUS);
+ break;
+ }
+
+ case 10:
+ {
+ msg_print("You're not as powerful as you used to be...");
+
+ for (k = 0; k < 6; k++)
+ {
+ p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4;
+ if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3;
+ }
+ p_ptr->update |= (PU_BONUS);
+ break;
+ }
+ }
+ }
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Gravity -- stun plus slowness plus teleport */
+ case GF_GRAVITY:
+ {
+ if (dungeon_flags2 & DF2_NO_TELEPORT) break; /* No teleport on special levels */
+ if (fuzzy) msg_print("You are hit by something heavy!");
+ msg_print("Gravity warps around you.");
+ if (!unsafe)
+ {
+ teleport_player(5);
+ if (!p_ptr->ffall)
+ (void)set_slow(p_ptr->slow + rand_int(4) + 4);
+ if (!(p_ptr->resist_sound || p_ptr->ffall))
+ {
+ int k = (randint((dam > 90) ? 35 : (dam / 3 + 5)));
+ (void)set_stun(p_ptr->stun + k);
+ }
+ if (p_ptr->ffall)
+ {
+ dam = (dam * 2) / 3;
+ }
+
+ if ((!p_ptr->ffall) || (randint(13) == 1))
+ {
+ inven_damage(set_cold_destroy, 2);
+ }
+
+ take_hit(dam, killer);
+ }
+ else
+ teleport_player(dam);
+ break;
+ }
+
+ /* Standard damage */
+ case GF_DISINTEGRATE:
+ {
+ if (fuzzy) msg_print("You are hit by pure energy!");
+ take_hit(dam, killer);
+ break;
+ }
+
+ case GF_OLD_HEAL:
+ {
+ if (fuzzy) msg_print("You are hit by something invigorating!");
+ (void)hp_player(dam);
+ dam = 0;
+ break;
+ }
+
+ case GF_OLD_SPEED:
+ {
+ if (fuzzy) msg_print("You are hit by something!");
+ (void)set_fast(p_ptr->fast + randint(5), 10);
+ dam = 0;
+ break;
+ }
+
+ case GF_OLD_SLOW:
+ {
+ if (fuzzy) msg_print("You are hit by something slow!");
+ (void)set_slow(p_ptr->slow + rand_int(4) + 4);
+ break;
+ }
+
+ case GF_OLD_SLEEP:
+ {
+ if (p_ptr->free_act) break;
+ if (fuzzy) msg_print("You fall asleep!");
+ set_paralyzed(p_ptr->paralyzed + dam);
+ dam = 0;
+ break;
+ }
+
+ /* Pure damage */
+ case GF_MANA:
+ {
+ if (fuzzy) msg_print("You are hit by an aura of magic!");
+ take_hit(dam, killer);
+ break;
+ }
+
+ /* Pure damage */
+ case GF_METEOR:
+ {
+ if (fuzzy) msg_print("Something falls from the sky on you!");
+ take_hit(dam, killer);
+ if ((!p_ptr->resist_shard) || (randint(13) == 1))
+ {
+ if (!p_ptr->immune_fire) inven_damage(set_fire_destroy, 2);
+ inven_damage(set_cold_destroy, 2);
+ }
+
+ break;
+ }
+
+ /* Ice -- cold plus stun plus cuts */
+ case GF_ICE:
+ {
+ if (fuzzy) msg_print("You are hit by something sharp and cold!");
+ cold_dam(dam, killer);
+ if (!p_ptr->resist_shard)
+ {
+ (void)set_cut(p_ptr->cut + damroll(5, 8));
+ }
+ if (!p_ptr->resist_sound)
+ {
+ (void)set_stun(p_ptr->stun + randint(15));
+ }
+
+ if ((!(p_ptr->resist_cold || p_ptr->oppose_cold)) || (randint(12) == 1))
+ {
+ if (!(p_ptr->immune_cold)) inven_damage(set_cold_destroy, 3);
+ }
+
+ break;
+ }
+
+ /* Knowledge */
+ case GF_IDENTIFY:
+ {
+ if (fuzzy) msg_print("You are hit by pure knowledge!");
+ self_knowledge(NULL);
+ break;
+ }
+
+ /* Psi -- ESP */
+ case GF_PSI:
+ {
+ if (fuzzy) msg_print("You are hit by pure psionic energy!");
+ set_tim_esp(p_ptr->tim_esp + dam);
+ break;
+ }
+
+ /* Statis -- paralyse */
+ case GF_STASIS:
+ {
+ if (fuzzy) msg_print("You are hit by something paralyzing!");
+ set_paralyzed(p_ptr->paralyzed + dam);
+ break;
+ }
+
+ /* Raise Death -- restore life */
+ case GF_RAISE:
+ {
+ if (fuzzy) msg_print("You are hit by pure anti-death energy!");
+ restore_level();
+ break;
+ }
+
+ /* Make Glyph -- Shield */
+ case GF_MAKE_GLYPH:
+ {
+ if (fuzzy) msg_print("You are hit by pure protection!");
+ set_shield(p_ptr->shield + dam, 50, 0, 0, 0);
+ break;
+ }
+
+ /* Default */
+ default:
+ {
+ /* Hooks! */
+ if (process_hooks_ret(HOOK_GF_EXEC, "dd", "(s,d,d,d,d,d,d)", "player", who, typ, dam, r, y, x))
+ {
+ obvious = process_hooks_return[0].num;
+ dam = process_hooks_return[1].num;
+ }
+ else
+ {
+ /* No damage */
+ dam = 0;
+ }
+ break;
+ }
+ }
+
+
+ /* Handle moving the player.
+ *
+ * Note: This is a effect of force
+ */
+ if (do_move)
+ {
+ int back = 0;
+
+ back = 0; /* Default of no movement */
+
+ /* How far can we push the monster? */
+ for (do_move = 1; do_move < 3; do_move++)
+ {
+ /* Get monster coords */
+ /* And offset position */
+ y1 = p_ptr->py + (b * do_move);
+ x1 = p_ptr->px + (a * do_move);
+
+ if (!in_bounds(y1, x1)) continue;
+
+ /* Require "empty" floor space */
+ if (!in_bounds(y1, x1) || !cave_empty_bold(y1, x1)) continue;
+
+ /* amount moved */
+ back = do_move;
+ }
+
+ /* Move the monster */
+ if (back)
+ {
+ y1 = p_ptr->py + (b * back);
+ x1 = p_ptr->px + (a * back);
+ swap_position(y1, x1);
+
+ if (back == 2)
+ {
+ msg_print("You are knocked back!");
+ }
+ if (back == 1)
+ {
+ msg_print("You are knocked back and crushed!");
+
+ /* was kept from being pushed all the way, do extra dam */
+ dam = dam * 13 / 10;
+ }
+
+ /* Get new position */
+ y = y1;
+ x = x1;
+ }
+ else /* could not move the monster */
+ {
+ msg_print("You are severely crushed!");
+
+ /* Do extra damage (1/3)*/
+ dam = dam * 15 / 10;
+ }
+
+ take_hit(dam, killer);
+
+ }
+
+
+ /* Disturb */
+ disturb(1, 0);
+
+
+ /* Return "Anything seen?" */
+ return (obvious);
+}
+
+
+
+/*
+ * Generic "beam"/"bolt"/"ball" projection routine.
+ *
+ * Input:
+ * who: Index of "source" monster (negative for "player")
+ * jk -- -2 for traps, only used with project_jump
+ * rad: Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
+ * y,x: Target location (or location to travel "towards")
+ * dam: Base damage roll to apply to affected monsters (or player)
+ * typ: Type of damage to apply to monsters (and objects)
+ * flg: Extra bit flags (see PROJECT_xxxx in "defines.h")
+ *
+ * Return:
+ * TRUE if any "effects" of the projection were observed, else FALSE
+ *
+ * Allows a monster (or player) to project a beam/bolt/ball of a given kind
+ * towards a given location (optionally passing over the heads of interposing
+ * monsters), and have it do a given amount of damage to the monsters (and
+ * optionally objects) within the given radius of the final location.
+ *
+ * A "bolt" travels from source to target and affects only the target grid.
+ * A "beam" travels from source to target, affecting all grids passed through.
+ * A "ball" travels from source to the target, exploding at the target, and
+ * affecting everything within the given radius of the target location.
+ *
+ * Traditionally, a "bolt" does not affect anything on the ground, and does
+ * not pass over the heads of interposing monsters, much like a traditional
+ * missile, and will "stop" abruptly at the "target" even if no monster is
+ * positioned there, while a "ball", on the other hand, passes over the heads
+ * of monsters between the source and target, and affects everything except
+ * the source monster which lies within the final radius, while a "beam"
+ * affects every monster between the source and target, except for the casting
+ * monster (or player), and rarely affects things on the ground.
+ *
+ * Two special flags allow us to use this function in special ways, the
+ * "PROJECT_HIDE" flag allows us to perform "invisible" projections, while
+ * the "PROJECT_JUMP" flag allows us to affect a specific grid, without
+ * actually projecting from the source monster (or player).
+ *
+ * The player will only get "experience" for monsters killed by himself
+ * Unique monsters can only be destroyed by attacks from the player
+ *
+ * Only 256 grids can be affected per projection, limiting the effective
+ * "radius" of standard ball attacks to nine units (diameter nineteen).
+ *
+ * One can project in a given "direction" by combining PROJECT_THRU with small
+ * offsets to the initial location (see "line_spell()"), or by calculating
+ * "virtual targets" far away from the player.
+ *
+ * One can also use PROJECT_THRU to send a beam/bolt along an angled path,
+ * continuing until it actually hits something (useful for "stone to mud").
+ *
+ * Bolts and Beams explode INSIDE walls, so that they can destroy doors.
+ *
+ * Balls must explode BEFORE hitting walls, or they would affect monsters
+ * on both sides of a wall. Some bug reports indicate that this is still
+ * happening in 2.7.8 for Windows, though it appears to be impossible.
+ *
+ * We "pre-calculate" the blast area only in part for efficiency.
+ * More importantly, this lets us do "explosions" from the "inside" out.
+ * This results in a more logical distribution of "blast" treasure.
+ * It also produces a better (in my opinion) animation of the explosion.
+ * It could be (but is not) used to have the treasure dropped by monsters
+ * in the middle of the explosion fall "outwards", and then be damaged by
+ * the blast as it spreads outwards towards the treasure drop location.
+ *
+ * Walls and doors are included in the blast area, so that they can be
+ * "burned" or "melted" in later versions.
+ *
+ * This algorithm is intended to maximize simplicity, not necessarily
+ * efficiency, since this function is not a bottleneck in the code.
+ *
+ * We apply the blast effect from ground zero outwards, in several passes,
+ * first affecting features, then objects, then monsters, then the player.
+ * This allows walls to be removed before checking the object or monster
+ * in the wall, and protects objects which are dropped by monsters killed
+ * in the blast, and allows the player to see all affects before he is
+ * killed or teleported away. The semantics of this method are open to
+ * various interpretations, but they seem to work well in practice.
+ *
+ * We process the blast area from ground-zero outwards to allow for better
+ * distribution of treasure dropped by monsters, and because it provides a
+ * pleasing visual effect at low cost.
+ *
+ * Note that the damage done by "ball" explosions decreases with distance.
+ * This decrease is rapid, grids at radius "dist" take "1/dist" damage.
+ *
+ * Notice the "napalm" effect of "beam" weapons. First they "project" to
+ * the target, and then the damage "flows" along this beam of destruction.
+ * The damage at every grid is the same as at the "center" of a "ball"
+ * explosion, since the "beam" grids are treated as if they ARE at the
+ * center of a "ball" explosion.
+ *
+ * Currently, specifying "beam" plus "ball" means that locations which are
+ * covered by the initial "beam", and also covered by the final "ball", except
+ * for the final grid (the epicenter of the ball), will be "hit twice", once
+ * by the initial beam, and once by the exploding ball. For the grid right
+ * next to the epicenter, this results in 150% damage being done. The center
+ * does not have this problem, for the same reason the final grid in a "beam"
+ * plus "bolt" does not -- it is explicitly removed. Simply removing "beam"
+ * grids which are covered by the "ball" will NOT work, as then they will
+ * receive LESS damage than they should. Do not combine "beam" with "ball".
+ *
+ * The array "gy[],gx[]" with current size "grids" is used to hold the
+ * collected locations of all grids in the "blast area" plus "beam path".
+ *
+ * Note the rather complex usage of the "gm[]" array. First, gm[0] is always
+ * zero. Second, for N>1, gm[N] is always the index (in gy[],gx[]) of the
+ * first blast grid (see above) with radius "N" from the blast center. Note
+ * that only the first gm[1] grids in the blast area thus take full damage.
+ * Also, note that gm[rad+1] is always equal to "grids", which is the total
+ * number of blast grids.
+ *
+ * Note that once the projection is complete, (y2,x2) holds the final location
+ * of bolts/beams, and the "epicenter" of balls.
+ *
+ * Note also that "rad" specifies the "inclusive" radius of projection blast,
+ * so that a "rad" of "one" actually covers 5 or 9 grids, depending on the
+ * implementation of the "distance" function. Also, a bolt can be properly
+ * viewed as a "ball" with a "rad" of "zero".
+ *
+ * Note that if no "target" is reached before the beam/bolt/ball travels the
+ * maximum distance allowed (MAX_RANGE), no "blast" will be induced. This
+ * may be relevant even for bolts, since they have a "1x1" mini-blast.
+ *
+ * Note that for consistency, we "pretend" that the bolt actually takes "time"
+ * to move from point A to point B, even if the player cannot see part of the
+ * projection path. Note that in general, the player will *always* see part
+ * of the path, since it either starts at the player or ends on the player.
+ *
+ * Hack -- we assume that every "projection" is "self-illuminating".
+ *
+ * Hack -- when only a single monster is affected, we automatically track
+ * (and recall) that monster, unless "PROJECT_JUMP" is used.
+ *
+ * Note that all projections now "explode" at their final destination, even
+ * if they were being projected at a more distant destination. This means
+ * that "ball" spells will *always* explode.
+ *
+ * Note that we must call "handle_stuff()" after affecting terrain features
+ * in the blast radius, in case the "illumination" of the grid was changed,
+ * and "update_view()" and "update_monsters()" need to be called.
+ */
+bool_ project(int who, int rad, int y, int x, int dam, int typ, int flg)
+{
+ int i, t, dist;
+
+ int y1, x1;
+ int y2, x2;
+
+ int dist_hack = 0;
+
+ int y_saver, x_saver; /* For reflecting monsters */
+
+ int msec = delay_factor * delay_factor * delay_factor;
+
+ /* Assume the player sees nothing */
+ bool_ notice = FALSE;
+
+ /* Assume the player has seen nothing */
+ bool_ visual = FALSE;
+
+ /* Assume the player has seen no blast grids */
+ bool_ drawn = FALSE;
+
+ /* Is the player blind? */
+ bool_ blind = (p_ptr->blind ? TRUE : FALSE);
+
+ /* Number of grids in the "path" */
+ int path_n = 0;
+
+ /* Actual grids in the "path" */
+ u16b path_g[1024];
+
+ /* Number of grids in the "blast area" (including the "beam" path) */
+ int grids = 0;
+
+ int effect = 0;
+
+ /* Coordinates of the affected grids */
+ byte gx[1024], gy[1024];
+
+ /* Encoded "radius" info (see above) */
+ byte gm[64];
+
+
+ /* Hack -- Jump to target */
+ if (flg & (PROJECT_JUMP))
+ {
+ x1 = x;
+ y1 = y;
+
+ /* Clear the flag */
+ flg &= ~(PROJECT_JUMP);
+ }
+
+ /* Start at player */
+ else if ((who <= 0) && ((who != -101) && (who != -100)))
+ {
+ x1 = p_ptr->px;
+ y1 = p_ptr->py;
+ }
+
+ /* Start at monster */
+ else if (who > 0)
+ {
+ x1 = m_list[who].fx;
+ y1 = m_list[who].fy;
+ }
+
+ /* Oops */
+ else
+ {
+ x1 = x;
+ y1 = y;
+ }
+
+ y_saver = y1;
+ x_saver = x1;
+
+ /* Default "destination" */
+ y2 = y;
+ x2 = x;
+
+
+ /* Hack -- verify stuff */
+ if (flg & (PROJECT_THRU))
+ {
+ if ((x1 == x2) && (y1 == y2))
+ {
+ flg &= ~(PROJECT_THRU);
+ }
+ }
+
+
+ /* Hack -- Assume there will be no blast (max radius 16) */
+ for (dist = 0; dist < 64; dist++) gm[dist] = 0;
+
+
+ /* Initial grid */
+ y = y1;
+ x = x1;
+ dist = 0;
+
+ /* Collect beam grids */
+ if (flg & (PROJECT_BEAM))
+ {
+ gy[grids] = y;
+ gx[grids] = x;
+ grids++;
+ }
+
+
+ /* Calculate the projection path */
+ if ((who == -101) || (who == -100))
+ path_n = 0;
+ else
+ path_n = project_path(path_g, MAX_RANGE, y1, x1, y2, x2, flg);
+
+
+ /* Hack -- Handle stuff */
+ handle_stuff();
+
+ /* Project along the path */
+ for (i = 0; i < path_n; ++i)
+ {
+ int oy = y;
+ int ox = x;
+
+ int ny = GRID_Y(path_g[i]);
+ int nx = GRID_X(path_g[i]);
+
+ /* Hack -- Balls explode before reaching walls */
+ if (!cave_floor_bold(ny, nx) && (rad > 0)) break;
+
+ /* Advance */
+ y = ny;
+ x = nx;
+
+ /* Collect beam grids */
+ if (flg & (PROJECT_BEAM))
+ {
+ gy[grids] = y;
+ gx[grids] = x;
+ grids++;
+ }
+
+ /* Only do visuals if requested */
+ if (!blind && !(flg & (PROJECT_HIDE)))
+ {
+ /* Only do visuals if the player can "see" the bolt */
+ if (panel_contains(y, x) && player_has_los_bold(y, x))
+ {
+ u16b p;
+
+ byte a;
+ char c;
+
+ /* Obtain the bolt pict */
+ p = bolt_pict(oy, ox, y, x, typ);
+
+ /* Extract attr/char */
+ a = PICT_A(p);
+ c = PICT_C(p);
+
+ /* Visual effects */
+ print_rel(c, a, y, x);
+ move_cursor_relative(y, x);
+ if (fresh_before) Term_fresh();
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ lite_spot(y, x);
+ if (fresh_before) Term_fresh();
+
+ /* Display "beam" grids */
+ if (flg & (PROJECT_BEAM))
+ {
+ /* Obtain the explosion pict */
+ p = bolt_pict(y, x, y, x, typ);
+
+ /* Extract attr/char */
+ a = PICT_A(p);
+ c = PICT_C(p);
+
+ /* Visual effects */
+ print_rel(c, a, y, x);
+ }
+
+ /* Hack -- Activate delay */
+ visual = TRUE;
+ }
+
+ /* Hack -- delay anyway for consistency */
+ else if (visual)
+ {
+ /* Delay for consistency */
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ }
+ }
+ }
+
+
+ /* Save the "blast epicenter" */
+ y2 = y;
+ x2 = x;
+
+ /* Start the "explosion" */
+ gm[0] = 0;
+
+ /* Hack -- make sure beams get to "explode" */
+ gm[1] = grids;
+
+ dist_hack = dist;
+
+ /* Explode */
+ if (TRUE)
+ {
+ /* Hack -- remove final beam grid */
+ if (flg & (PROJECT_BEAM))
+ {
+ grids--;
+ }
+
+ /* Determine the blast area, work from the inside out */
+ for (dist = 0; dist <= rad; dist++)
+ {
+ /* Scan the maximal blast area of radius "dist" */
+ for (y = y2 - dist; y <= y2 + dist; y++)
+ {
+ for (x = x2 - dist; x <= x2 + dist; x++)
+ {
+ /* Ignore "illegal" locations */
+ if (!in_bounds(y, x)) continue;
+
+ /* Enforce a "circular" explosion */
+ if (distance(y2, x2, y, x) != dist) continue;
+
+ /* Ball explosions are stopped by walls */
+ if (typ == GF_DISINTEGRATE)
+ {
+ if (cave_valid_bold(y, x) &&
+ (cave[y][x].feat < FEAT_PATTERN_START
+ || cave[y][x].feat > FEAT_PATTERN_XTRA2))
+ cave_set_feat(y, x, FEAT_FLOOR);
+
+ /* Update some things -- similar to GF_KILL_WALL */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS | PU_MON_LITE);
+ }
+ else
+ {
+ if (!los(y2, x2, y, x)) continue;
+ }
+
+ /* Save this grid */
+ gy[grids] = y;
+ gx[grids] = x;
+ grids++;
+ }
+ }
+
+ /* Encode some more "radius" info */
+ gm[dist + 1] = grids;
+ }
+ }
+
+
+ /* Speed -- ignore "non-explosions" */
+ if (!grids) return (FALSE);
+
+
+ /* Display the "blast area" if requested */
+ if (!blind && !(flg & (PROJECT_HIDE)))
+ {
+ /* Then do the "blast", from inside out */
+ for (t = 0; t <= rad; t++)
+ {
+ /* Dump everything with this radius */
+ for (i = gm[t]; i < gm[t + 1]; i++)
+ {
+ /* Extract the location */
+ y = gy[i];
+ x = gx[i];
+
+ /* Only do visuals if the player can "see" the blast */
+ if (panel_contains(y, x) && player_has_los_bold(y, x))
+ {
+ u16b p;
+
+ byte a;
+ char c;
+
+ drawn = TRUE;
+
+ /* Obtain the explosion pict */
+ p = bolt_pict(y, x, y, x, typ);
+
+ /* Extract attr/char */
+ a = PICT_A(p);
+ c = PICT_C(p);
+
+ /* Visual effects -- Display */
+ print_rel(c, a, y, x);
+ }
+ }
+
+ /* Hack -- center the cursor */
+ move_cursor_relative(y2, x2);
+
+ /* Flush each "radius" seperately */
+ if (fresh_before) Term_fresh();
+
+ /* Delay (efficiently) */
+ if (visual || drawn)
+ {
+ Term_xtra(TERM_XTRA_DELAY, msec);
+ }
+ }
+
+ /* Flush the erasing */
+ if (drawn)
+ {
+ /* Erase the explosion drawn above */
+ for (i = 0; i < grids; i++)
+ {
+ /* Extract the location */
+ y = gy[i];
+ x = gx[i];
+
+ /* Hack -- Erase if needed */
+ if (panel_contains(y, x) && player_has_los_bold(y, x))
+ {
+ lite_spot(y, x);
+ }
+ }
+
+ /* Hack -- center the cursor */
+ move_cursor_relative(y2, x2);
+
+ /* Flush the explosion */
+ if (fresh_before) Term_fresh();
+ }
+ }
+
+
+ /* Check features */
+ if (flg & (PROJECT_GRID))
+ {
+ /* Start with "dist" of zero */
+ dist = 0;
+
+ /* Effect ? */
+ if (flg & PROJECT_STAY)
+ {
+ effect = new_effect(typ, dam, project_time, p_ptr->py, p_ptr->px, rad, project_time_effect);
+ project_time = 0;
+ project_time_effect = 0;
+ }
+
+ /* Scan for features */
+ for (i = 0; i < grids; i++)
+ {
+ /* Hack -- Notice new "dist" values */
+ if (gm[dist + 1] == i) dist++;
+
+ /* Get the grid location */
+ y = gy[i];
+ x = gx[i];
+
+ /* Affect the feature in that grid */
+ if (project_f(who, dist, y, x, dam, typ)) notice = TRUE;
+
+ /* Effect ? */
+ if (flg & PROJECT_STAY)
+ {
+ cave[y][x].effect = effect;
+ lite_spot(y, x);
+ }
+ }
+ }
+
+
+ /* Update stuff if needed */
+ if (p_ptr->update) update_stuff();
+
+
+ /* Check objects */
+ if (flg & (PROJECT_ITEM))
+ {
+ /* Start with "dist" of zero */
+ dist = 0;
+
+ /* Scan for objects */
+ for (i = 0; i < grids; i++)
+ {
+ /* Hack -- Notice new "dist" values */
+ if (gm[dist + 1] == i) dist++;
+
+ /* Get the grid location */
+ y = gy[i];
+ x = gx[i];
+
+ /* Affect the object in the grid */
+ if (project_o(who, dist, y, x, dam, typ)) notice = TRUE;
+ }
+ }
+
+
+ /* Check monsters */
+ if (flg & (PROJECT_KILL))
+ {
+ /* Mega-Hack */
+ project_m_n = 0;
+ project_m_x = 0;
+ project_m_y = 0;
+
+ /* Start with "dist" of zero */
+ dist = 0;
+
+ /* Scan for monsters */
+ for (i = 0; i < grids; i++)
+ {
+ /* Hack -- Notice new "dist" values */
+ if (gm[dist + 1] == i) dist++;
+
+ /* Get the grid location */
+ y = gy[i];
+ x = gx[i];
+
+ if (grids > 1)
+ {
+ /* Affect the monster in the grid */
+ if (project_m(who, dist, y, x, dam, typ)) notice = TRUE;
+ }
+ else
+ {
+ monster_race *ref_ptr = race_inf(&m_list[cave[y][x].m_idx]);
+
+ if ((ref_ptr->flags2 & (RF2_REFLECTING)) && (randint(10) != 1)
+ && (dist_hack > 1))
+ {
+ int t_y, t_x;
+ int max_attempts = 10;
+
+ /* Choose 'new' target */
+ do
+ {
+ t_y = y_saver - 1 + randint(3);
+ t_x = x_saver - 1 + randint(3);
+ max_attempts--;
+ }
+
+ while (max_attempts && in_bounds2(t_y, t_x) &&
+ !(los(y, x, t_y, t_x)));
+
+ if (max_attempts < 1)
+ {
+ t_y = y_saver;
+ t_x = x_saver;
+ }
+
+ if (m_list[cave[y][x].m_idx].ml)
+ {
+ msg_print("The attack bounces!");
+ ref_ptr->r_flags2 |= RF2_REFLECTING;
+ }
+
+ project(cave[y][x].m_idx, 0, t_y, t_x, dam, typ, flg);
+ }
+ else
+ {
+ if (project_m(who, dist, y, x, dam, typ)) notice = TRUE;
+ }
+ }
+ }
+
+ /* Player affected one monster (without "jumping") */
+ if ((who < 0) && (project_m_n == 1) && !(flg & (PROJECT_JUMP)))
+ {
+ /* Location */
+ x = project_m_x;
+ y = project_m_y;
+
+ /* Track if possible */
+ if (cave[y][x].m_idx > 0)
+ {
+ monster_type *m_ptr = &m_list[cave[y][x].m_idx];
+
+ /* Hack -- auto-recall */
+ if (m_ptr->ml) monster_race_track(m_ptr->r_idx, m_ptr->ego);
+
+ /* Hack - auto-track */
+ if (m_ptr->ml) health_track(cave[y][x].m_idx);
+ }
+ }
+ }
+
+
+ /* Check player */
+ if (flg & (PROJECT_KILL))
+ {
+ /* Start with "dist" of zero */
+ dist = 0;
+
+ /* Scan for player */
+ for (i = 0; i < grids; i++)
+ {
+ /* Hack -- Notice new "dist" values */
+ if (gm[dist + 1] == i) dist++;
+
+ /* Get the grid location */
+ y = gy[i];
+ x = gx[i];
+
+ /* Affect the player */
+ if (project_p(who, dist, y, x, dam, typ, rad)) notice = TRUE;
+ }
+ }
+
+ /* Return "something was noticed" */
+ return (notice);
+}
+
+
+
+/*
+ * Potions "smash open" and cause an area effect when
+ * (1) they are shattered while in the player's inventory,
+ * due to cold (etc) attacks;
+ * (2) they are thrown at a monster, or obstacle;
+ * (3) they are shattered by a "cold ball" or other such spell
+ * while lying on the floor.
+ *
+ * Arguments:
+ * who --- who caused the potion to shatter (0=player)
+ * potions that smash on the floor are assumed to
+ * be caused by no-one (who = 1), as are those that
+ * shatter inside the player inventory.
+ * (Not anymore -- I changed this; TY)
+ * y, x --- coordinates of the potion (or player if
+ * the potion was in her inventory);
+ * o_ptr --- pointer to the potion object.
+ */
+bool_ potion_smash_effect(int who, int y, int x, int o_sval)
+{
+ int radius = 2;
+ int dt = 0;
+ int dam = 0;
+ bool_ ident = FALSE;
+ bool_ angry = FALSE;
+
+ switch (o_sval)
+ {
+ case SV_POTION_SALT_WATER:
+ case SV_POTION_SLIME_MOLD:
+ case SV_POTION_LOSE_MEMORIES:
+ case SV_POTION_DEC_STR:
+ case SV_POTION_DEC_INT:
+ case SV_POTION_DEC_WIS:
+ case SV_POTION_DEC_DEX:
+ case SV_POTION_DEC_CON:
+ case SV_POTION_DEC_CHR:
+ case SV_POTION_WATER: /* perhaps a 'water' attack? */
+ case SV_POTION_APPLE_JUICE:
+ return TRUE;
+
+ case SV_POTION_INFRAVISION:
+ case SV_POTION_DETECT_INVIS:
+ case SV_POTION_SLOW_POISON:
+ case SV_POTION_CURE_POISON:
+ case SV_POTION_BOLDNESS:
+ case SV_POTION_RESIST_HEAT:
+ case SV_POTION_RESIST_COLD:
+ case SV_POTION_HEROISM:
+ case SV_POTION_BESERK_STRENGTH:
+ case SV_POTION_RESTORE_EXP:
+ case SV_POTION_RES_STR:
+ case SV_POTION_RES_INT:
+ case SV_POTION_RES_WIS:
+ case SV_POTION_RES_DEX:
+ case SV_POTION_RES_CON:
+ case SV_POTION_RES_CHR:
+ case SV_POTION_INC_STR:
+ case SV_POTION_INC_INT:
+ case SV_POTION_INC_WIS:
+ case SV_POTION_INC_DEX:
+ case SV_POTION_INC_CON:
+ case SV_POTION_INC_CHR:
+ case SV_POTION_AUGMENTATION:
+ case SV_POTION_ENLIGHTENMENT:
+ case SV_POTION_STAR_ENLIGHTENMENT:
+ case SV_POTION_SELF_KNOWLEDGE:
+ case SV_POTION_EXPERIENCE:
+ case SV_POTION_RESISTANCE:
+ case SV_POTION_INVULNERABILITY:
+ case SV_POTION_NEW_LIFE:
+ /* All of the above potions have no effect when shattered */
+ return FALSE;
+ case SV_POTION_SLOWNESS:
+ dt = GF_OLD_SLOW;
+ dam = 5;
+ ident = TRUE;
+ angry = TRUE;
+ break;
+ case SV_POTION_POISON:
+ dt = GF_POIS;
+ dam = 3;
+ ident = TRUE;
+ angry = TRUE;
+ break;
+ case SV_POTION_BLINDNESS:
+ dt = GF_DARK;
+ ident = TRUE;
+ angry = TRUE;
+ break;
+ case SV_POTION_CONFUSION: /* Booze */
+ dt = GF_OLD_CONF;
+ ident = TRUE;
+ angry = TRUE;
+ break;
+ case SV_POTION_SLEEP:
+ dt = GF_OLD_SLEEP;
+ angry = TRUE;
+ ident = TRUE;
+ break;
+ case SV_POTION_RUINATION:
+ case SV_POTION_DETONATIONS:
+ dt = GF_SHARDS;
+ dam = damroll(25, 25);
+ angry = TRUE;
+ ident = TRUE;
+ break;
+ case SV_POTION_DEATH:
+ dt = GF_MANA; /* !! */
+ dam = damroll(10, 10);
+ angry = TRUE;
+ radius = 1;
+ ident = TRUE;
+ break;
+ case SV_POTION_SPEED:
+ dt = GF_OLD_SPEED;
+ ident = TRUE;
+ break;
+ case SV_POTION_CURE_LIGHT:
+ dt = GF_OLD_HEAL;
+ dam = damroll(2, 3);
+ ident = TRUE;
+ break;
+ case SV_POTION_CURE_SERIOUS:
+ dt = GF_OLD_HEAL;
+ dam = damroll(4, 3);
+ ident = TRUE;
+ break;
+ case SV_POTION_CURE_CRITICAL:
+ case SV_POTION_CURING:
+ dt = GF_OLD_HEAL;
+ dam = damroll(6, 3);
+ ident = TRUE;
+ break;
+ case SV_POTION_HEALING:
+ dt = GF_OLD_HEAL;
+ dam = damroll(10, 10);
+ ident = TRUE;
+ break;
+ case SV_POTION_STAR_HEALING:
+ case SV_POTION_LIFE:
+ dt = GF_OLD_HEAL;
+ dam = damroll(50, 50);
+ radius = 1;
+ ident = TRUE;
+ break;
+ case SV_POTION_RESTORE_MANA: /* MANA */
+ dt = GF_MANA;
+ dam = damroll(10, 10);
+ radius = 1;
+ ident = TRUE;
+ break;
+ default:
+ /* Do nothing */
+ ;
+ }
+
+ (void) project(who, radius, y, x, dam, dt,
+ (PROJECT_JUMP | PROJECT_ITEM | PROJECT_KILL));
+
+ /* XXX those potions that explode need to become "known" */
+ return angry;
+}
+
+/* This is for Thaumaturgy */
+static const int destructive_attack_types[10] =
+{
+ GF_KILL_WALL,
+ GF_KILL_WALL,
+ GF_KILL_WALL,
+ GF_STONE_WALL,
+ GF_STONE_WALL,
+ GF_STONE_WALL,
+ GF_DESTRUCTION,
+ GF_DESTRUCTION,
+ GF_DESTRUCTION,
+ GF_DESTRUCTION,
+};
+
+/* Also for Power-mages */
+static const int attack_types[25] =
+{
+ GF_ARROW,
+ GF_MISSILE,
+ GF_MANA,
+ GF_WATER,
+ GF_PLASMA,
+ GF_METEOR,
+ GF_ICE,
+ GF_GRAVITY,
+ GF_INERTIA,
+ GF_FORCE,
+ GF_TIME,
+ GF_ACID,
+ GF_ELEC,
+ GF_FIRE,
+ GF_COLD,
+ GF_POIS,
+ GF_LITE,
+ GF_DARK,
+ GF_CONFUSION,
+ GF_SOUND,
+ GF_SHARDS,
+ GF_NEXUS,
+ GF_NETHER,
+ GF_CHAOS,
+ GF_DISENCHANT,
+};
+
+/*
+ * Describe the attack using normal names.
+ */
+
+void describe_attack_fully(int type, char* r)
+{
+ switch (type)
+ {
+ case GF_ARROW:
+ strcpy(r, "arrows");
+ break;
+ case GF_MISSILE:
+ strcpy(r, "magic missiles");
+ break;
+ case GF_MANA:
+ strcpy(r, "mana");
+ break;
+ case GF_LITE_WEAK:
+ strcpy(r, "light");
+ break;
+ case GF_DARK_WEAK:
+ strcpy(r, "dark");
+ break;
+ case GF_WATER:
+ strcpy(r, "water");
+ break;
+ case GF_PLASMA:
+ strcpy(r, "plasma");
+ break;
+ case GF_METEOR:
+ strcpy(r, "meteors");
+ break;
+ case GF_ICE:
+ strcpy(r, "ice");
+ break;
+ case GF_GRAVITY:
+ strcpy(r, "gravity");
+ break;
+ case GF_INERTIA:
+ strcpy(r, "inertia");
+ break;
+ case GF_FORCE:
+ strcpy(r, "force");
+ break;
+ case GF_TIME:
+ strcpy(r, "pure time");
+ break;
+ case GF_ACID:
+ strcpy(r, "acid");
+ break;
+ case GF_ELEC:
+ strcpy(r, "lightning");
+ break;
+ case GF_FIRE:
+ strcpy(r, "flames");
+ break;
+ case GF_COLD:
+ strcpy(r, "cold");
+ break;
+ case GF_POIS:
+ strcpy(r, "poison");
+ break;
+ case GF_LITE:
+ strcpy(r, "pure light");
+ break;
+ case GF_DARK:
+ strcpy(r, "pure dark");
+ break;
+ case GF_CONFUSION:
+ strcpy(r, "confusion");
+ break;
+ case GF_SOUND:
+ strcpy(r, "sound");
+ break;
+ case GF_SHARDS:
+ strcpy(r, "shards");
+ break;
+ case GF_NEXUS:
+ strcpy(r, "nexus");
+ break;
+ case GF_NETHER:
+ strcpy(r, "nether");
+ break;
+ case GF_CHAOS:
+ strcpy(r, "chaos");
+ break;
+ case GF_DISENCHANT:
+ strcpy(r, "disenchantment");
+ break;
+ case GF_KILL_WALL:
+ strcpy(r, "wall destruction");
+ break;
+ case GF_KILL_DOOR:
+ strcpy(r, "door destruction");
+ break;
+ case GF_KILL_TRAP:
+ strcpy(r, "trap destruction");
+ break;
+ case GF_STONE_WALL:
+ strcpy(r, "wall creation");
+ break;
+ case GF_MAKE_DOOR:
+ strcpy(r, "door creation");
+ break;
+ case GF_MAKE_TRAP:
+ strcpy(r, "trap creation");
+ break;
+ case GF_DESTRUCTION:
+ strcpy(r, "destruction");
+ break;
+
+ default:
+ strcpy(r, "something unknown");
+ break;
+ }
+}
+
+/*
+ * Give a randomly-generated spell a name.
+ * Note that it only describes the first effect!
+ */
+
+static void name_spell(random_spell* s_ptr)
+{
+ char buff[30];
+ cptr buff2 = "???";
+
+ if (s_ptr->proj_flags & PROJECT_STOP && s_ptr->radius == 0)
+ {
+ buff2 = "Bolt";
+ }
+ else if (s_ptr->proj_flags & PROJECT_BEAM)
+ {
+ buff2 = "Beam";
+ }
+ else if (s_ptr->proj_flags & PROJECT_STOP && s_ptr->radius > 0)
+ {
+ buff2 = "Ball";
+ }
+ else if (s_ptr->proj_flags & PROJECT_BLAST)
+ {
+ buff2 = "Blast";
+ }
+ else if (s_ptr->proj_flags & PROJECT_METEOR_SHOWER)
+ {
+ buff2 = "Area";
+ }
+ else if (s_ptr->proj_flags & PROJECT_VIEWABLE)
+ {
+ buff2 = "View";
+ }
+
+ describe_attack_fully(s_ptr->GF, buff);
+ strnfmt(s_ptr->name, 30, "%s - %s", buff2, buff);
+}
+
+void generate_spell(int plev)
+{
+ random_spell* rspell;
+ int dice, sides, chance, mana, power;
+ bool_ destruc_gen = FALSE;
+ bool_ simple_gen = TRUE;
+ bool_ ball_desc = FALSE;
+
+ if (spell_num == MAX_SPELLS) return;
+
+ rspell = &random_spells[spell_num];
+
+ power = rand_int(5);
+
+ dice = plev / 2;
+ sides = plev;
+ mana = plev;
+
+ /* Make the spell more or less powerful. */
+ dice += power;
+ sides += power;
+ mana += (plev * power) / 15;
+
+ /* Stay within reasonable bounds. */
+ if (dice < 1) dice = 1;
+
+ if (sides < 5) sides = 5;
+
+ if (mana < 1) mana = 1;
+
+ rspell->level = plev;
+ rspell->mana = mana;
+ rspell->untried = TRUE;
+
+ /* Spells are always maximally destructive. */
+ rspell->proj_flags = PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID;
+
+ chance = randint(100);
+
+ /* Hack -- Always start with Magic Missile or derivative at lev. 1 */
+ if (plev == 1 || chance < 25)
+ {
+ rspell->proj_flags |= PROJECT_STOP;
+ /* Swap dice and sides for better damage */
+ rspell->dam_dice = sides;
+ rspell->dam_sides = dice;
+ rspell->radius = 0;
+ }
+ else if (chance < 50)
+ {
+ rspell->proj_flags |= PROJECT_BEAM;
+ rspell->dam_dice = dice;
+ rspell->dam_sides = sides;
+ rspell->radius = 0;
+ }
+ else if (chance < 76)
+ {
+ rspell->proj_flags |= PROJECT_STOP;
+ rspell->radius = dice / 3;
+ rspell->dam_dice = dice;
+ rspell->dam_sides = sides;
+ ball_desc = TRUE;
+ }
+ else if (chance < 83)
+ {
+ rspell->proj_flags |= PROJECT_BLAST;
+ rspell->radius = sides / 3;
+ rspell->dam_dice = dice;
+ rspell->dam_sides = sides;
+
+ destruc_gen = TRUE;
+ simple_gen = FALSE;
+ }
+ else if (chance < 90)
+ {
+ rspell->proj_flags |= PROJECT_METEOR_SHOWER;
+ /* Area effect spells do way less damage "per shot" */
+ rspell->dam_dice = dice / 5;
+ rspell->dam_sides = sides / 5;
+ rspell->radius = sides / 3;
+ if (rspell->radius < 4) rspell->radius = 4;
+
+ destruc_gen = TRUE;
+ }
+ else
+ {
+ rspell->proj_flags |= PROJECT_VIEWABLE;
+ /* View spells do less damage */
+ rspell->dam_dice = dice;
+ rspell->dam_sides = sides / 2;
+ }
+
+ /* Both a destructive and a simple spell requested --
+ * pick one or the other. */
+ if (destruc_gen && simple_gen)
+ {
+ if (magik(25))
+ {
+ simple_gen = FALSE;
+ }
+ else
+ {
+ destruc_gen = FALSE;
+ }
+ }
+
+ /* Pick a simple spell */
+ if (simple_gen)
+ {
+ rspell->GF = attack_types[rand_int(25)];
+ }
+ /* Pick a destructive spell */
+ else
+ {
+ rspell->GF = destructive_attack_types[rand_int(10)];
+ }
+
+ /* Give the spell a name. */
+ name_spell(rspell);
+ if (ball_desc)
+ {
+ /* 30 character limit on the string! */
+ sprintf(rspell->desc, "Dam: %d, Rad: %d, Pow: %d",
+ sides, dice, power);
+ }
+ else
+ {
+ sprintf(rspell->desc, "Damage: %dd%d, Power: %d",
+ dice, sides, power);
+ }
+
+ spell_num++;
+}
+
+/*
+ * Polymorph a monster at given location.
+ */
+s16b do_poly_monster(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ monster_type *m_ptr;
+
+ s16b hack_m_idx;
+ s16b old_m_idx;
+ s16b new_m_idx = 0;
+
+ s16b new_r_idx;
+
+ /* Get a "old" monster */
+ old_m_idx = c_ptr->m_idx;
+
+ /* Giga-Hack -- Remember monster */
+ hack_m_idx = old_m_idx;
+
+ /* Get a monster */
+ m_ptr = &m_list[c_ptr->m_idx];
+
+ /* Pick a "new" monster race */
+ new_r_idx = poly_r_idx(m_ptr->r_idx);
+
+ /* No polymorph happend */
+ if (new_r_idx == m_ptr->r_idx) return 0;
+
+ /* Giga-Hack -- Removes the moster XXX XXX XXX XXX */
+ c_ptr->m_idx = 0;
+
+ /*
+ * Handle polymorph --
+ * Create a new monster (no groups)
+ */
+ if (place_monster_aux(y, x, new_r_idx, FALSE, FALSE, m_ptr->status))
+ {
+ /* Get a "new" monster */
+ new_m_idx = c_ptr->m_idx;
+
+ /* Giga-Hack -- Remember "new" monster */
+ hack_m_idx = new_m_idx;
+
+ /* "Kill" the "old" monster */
+ delete_monster_idx(old_m_idx);
+
+ p_ptr->redraw |= (PR_MAP);
+ }
+
+ /* Giga-Hack -- restore saved monster XXX XXX XXX */
+ c_ptr->m_idx = hack_m_idx;
+
+ return new_m_idx;
+}
diff --git a/src/spells2.c b/src/spells2.c
new file mode 100644
index 00000000..5467499c
--- /dev/null
+++ b/src/spells2.c
@@ -0,0 +1,8076 @@
+/* File: spells2.c */
+
+/* Purpose: Spell code (part 2) */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+#define WEIRD_LUCK 12
+#define BIAS_LUCK 20
+/*
+ * Bias luck needs to be higher than weird luck,
+ * since it is usually tested several times...
+ */
+
+void summon_dragon_riders();
+
+
+/*
+ * Grow things
+ */
+void grow_things(s16b type, int rad)
+{
+ int a, i, j;
+
+ for (a = 0; a < rad * rad + 11; a++)
+ {
+ i = (Rand_mod((rad * 2) + 1)-rad + Rand_mod((rad * 2) + 1)-rad) / 2;
+ j = (Rand_mod((rad * 2) + 1)-rad + Rand_mod((rad * 2) + 1)-rad) / 2;
+
+ if (!in_bounds(p_ptr->py + j, p_ptr->px + i)) continue;
+ if (distance(p_ptr->py, p_ptr->px, p_ptr->py + j, p_ptr->px + i) > rad) continue;
+
+ if (cave_clean_bold(p_ptr->py + j, p_ptr->px + i))
+ {
+ cave_set_feat(p_ptr->py + j, p_ptr->px + i, type);
+ }
+ }
+}
+
+/*
+ * Grow trees
+ */
+void grow_trees(int rad)
+{
+ int a, i, j;
+
+ for (a = 0; a < rad * rad + 11; a++)
+ {
+ i = (Rand_mod((rad * 2) + 1)-rad + Rand_mod((rad * 2) + 1)-rad) / 2;
+ j = (Rand_mod((rad * 2) + 1)-rad + Rand_mod((rad * 2) + 1)-rad) / 2;
+
+ if (!in_bounds(p_ptr->py + j, p_ptr->px + i)) continue;
+ if (distance(p_ptr->py, p_ptr->px, p_ptr->py + j, p_ptr->px + i) > rad) continue;
+
+ if (cave_clean_bold(p_ptr->py + j, p_ptr->px + i) && (f_info[cave[p_ptr->py][p_ptr->px].feat].flags1 & FF1_SUPPORT_GROWTH))
+ {
+ cave_set_feat(p_ptr->py + j, p_ptr->px + i, FEAT_TREES);
+ }
+ }
+}
+
+/*
+ * Grow grass
+ */
+void grow_grass(int rad)
+{
+ int a, i, j;
+
+ for (a = 0; a < rad * rad + 11; a++)
+ {
+ i = (Rand_mod((rad * 2) + 1)-rad + Rand_mod((rad * 2) + 1)-rad) / 2;
+ j = (Rand_mod((rad * 2) + 1)-rad + Rand_mod((rad * 2) + 1)-rad) / 2;
+
+ if (!in_bounds(p_ptr->py + j, p_ptr->px + i)) continue;
+ if (distance(p_ptr->py, p_ptr->px, p_ptr->py + j, p_ptr->px + i) > rad) continue;
+
+ if (cave_clean_bold(p_ptr->py + j, p_ptr->px + i) && (f_info[cave[p_ptr->py][p_ptr->px].feat].flags1 & FF1_SUPPORT_GROWTH))
+ {
+ cave_set_feat(p_ptr->py + j, p_ptr->px + i, FEAT_GRASS);
+ }
+ }
+}
+
+/*
+ * Increase players hit points, notice effects
+ */
+bool_ hp_player(int num)
+{
+ bool_ dead = p_ptr->chp < 0;
+
+ /* Healing needed */
+ if (p_ptr->chp < p_ptr->mhp)
+ {
+ /* Gain hitpoints */
+ p_ptr->chp += num;
+
+ /* Enforce maximum */
+ if ((p_ptr->chp >= p_ptr->mhp) ||
+ /* prevent wrapping */
+ (!dead && (p_ptr->chp < 0)))
+ {
+ p_ptr->chp = p_ptr->mhp;
+ p_ptr->chp_frac = 0;
+ }
+
+ /* Redraw */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Heal 0-4 */
+ if (num < 5)
+ {
+ msg_print("You feel a little better.");
+ }
+
+ /* Heal 5-14 */
+ else if (num < 15)
+ {
+ msg_print("You feel better.");
+ }
+
+ /* Heal 15-34 */
+ else if (num < 35)
+ {
+ msg_print("You feel much better.");
+ }
+
+ /* Heal 35+ */
+ else
+ {
+ msg_print("You feel very good.");
+ }
+
+ /* Notice */
+ return (TRUE);
+ }
+
+ /* Ignore */
+ return (FALSE);
+}
+
+
+
+/*
+ * Leave a "glyph of warding" which prevents monster movement
+ */
+void warding_glyph(void)
+{
+ /* XXX XXX XXX */
+ if (!cave_clean_bold(p_ptr->py, p_ptr->px))
+ {
+ msg_print("The object resists the spell.");
+ return;
+ }
+
+ /* Create a glyph */
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_GLYPH);
+}
+
+void explosive_rune(void)
+{
+ /* XXX XXX XXX */
+ if (!cave_clean_bold(p_ptr->py, p_ptr->px))
+ {
+ msg_print("The object resists the spell.");
+ return;
+ }
+
+ /* Create a glyph */
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_MINOR_GLYPH);
+}
+
+
+
+/*
+ * Array of stat "descriptions"
+ */
+static cptr desc_stat_pos[] =
+{
+ "strong",
+ "smart",
+ "wise",
+ "dextrous",
+ "healthy",
+ "cute"
+};
+
+/*
+ * Array of long descriptions of stat
+ */
+
+static cptr long_desc_stat[] =
+{
+ "strength",
+ "intelligence",
+ "wisdom",
+ "dexterity",
+ "constitution",
+ "charisma"
+};
+
+/*
+ * Array of stat "descriptions"
+ */
+static cptr desc_stat_neg[] =
+{
+ "weak",
+ "stupid",
+ "naive",
+ "clumsy",
+ "sickly",
+ "ugly"
+};
+
+
+/*
+ * Lose a "point"
+ */
+bool_ do_dec_stat(int stat, int mode)
+{
+ bool_ sust = FALSE;
+
+ /* Access the "sustain" */
+ switch (stat)
+ {
+ case A_STR:
+ if (p_ptr->sustain_str) sust = TRUE;
+ break;
+ case A_INT:
+ if (p_ptr->sustain_int) sust = TRUE;
+ break;
+ case A_WIS:
+ if (p_ptr->sustain_wis) sust = TRUE;
+ break;
+ case A_DEX:
+ if (p_ptr->sustain_dex) sust = TRUE;
+ break;
+ case A_CON:
+ if (p_ptr->sustain_con) sust = TRUE;
+ break;
+ case A_CHR:
+ if (p_ptr->sustain_chr) sust = TRUE;
+ break;
+ }
+
+ /* Sustain */
+ if (sust)
+ {
+ /* Message */
+ msg_format("You feel %s for a moment, but the feeling passes.",
+ desc_stat_neg[stat]);
+
+ /* Notice effect */
+ return (TRUE);
+ }
+
+ /* Attempt to reduce the stat */
+ if (dec_stat(stat, 10, mode))
+ {
+ /* Message */
+ msg_format("You feel very %s.", desc_stat_neg[stat]);
+
+ /* Notice effect */
+ return (TRUE);
+ }
+
+ /* Nothing obvious */
+ return (FALSE);
+}
+
+
+/*
+ * Restore lost "points" in a stat
+ */
+bool_ do_res_stat(int stat, bool_ full)
+{
+ /* Keep a copy of the current stat, so we can evaluate it if necessary */
+ int cur_stat = p_ptr->stat_cur[stat];
+
+ /* Attempt to increase */
+ if (res_stat(stat, full))
+ {
+ /* Message, depending on whether we got stronger or weaker */
+ if (cur_stat > p_ptr->stat_max[stat])
+ {
+ msg_format("You feel your %s boost drain away.", long_desc_stat[stat]);
+ }
+ else
+ {
+ msg_format("You feel less %s.", desc_stat_neg[stat]);
+ }
+
+ /* Notice */
+ return (TRUE);
+ }
+
+ /* Nothing obvious */
+ return (FALSE);
+}
+
+
+/*
+ * Gain a "point" in a stat
+ */
+bool_ do_inc_stat(int stat)
+{
+ bool_ res;
+
+ /* Restore strength */
+ res = res_stat(stat, TRUE);
+
+ /* Attempt to increase */
+ if (inc_stat(stat))
+ {
+ /* Message */
+ msg_format("Wow! You feel very %s!", desc_stat_pos[stat]);
+
+ /* Notice */
+ return (TRUE);
+ }
+
+ /* Restoration worked */
+ if (res)
+ {
+ /* Message */
+ msg_format("You feel less %s.", desc_stat_neg[stat]);
+
+ /* Notice */
+ return (TRUE);
+ }
+
+ /* Nothing obvious */
+ return (FALSE);
+}
+
+
+
+/*
+ * Identify everything being carried.
+ * Done by a potion of "self knowledge".
+ */
+void identify_pack(void)
+{
+ int i;
+
+ /* Simply identify and know every item */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Aware and Known */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_IDENTIFY, "(d,s)", i, "normal");
+ }
+
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+}
+
+/*
+ * common portions of identify_fully and identify_pack_fully
+ */
+static void make_item_fully_identified(object_type *o_ptr)
+{
+ /* Identify it fully */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+
+ /* Mark the item as fully known */
+ o_ptr->ident |= (IDENT_MENTAL);
+
+ /* For those with alchemist skills, learn how to create it */
+ alchemist_learn_object(o_ptr);
+}
+
+/*
+ * Identify everything being carried.
+ * Done by a potion of "self knowledge".
+ */
+void identify_pack_fully(void)
+{
+ int i;
+
+ /* Simply identify and know every item */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ make_item_fully_identified(o_ptr);
+
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_IDENTIFY, "(d,s)", i, "full");
+ }
+
+ p_ptr->update |= (PU_BONUS);
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+}
+
+/*
+ * Used by the "enchant" function (chance of failure)
+ * (modified for Zangband, we need better stuff there...) -- TY
+ */
+static int enchant_table[16] =
+{
+ 0, 10, 50, 100, 200,
+ 300, 400, 500, 650, 800,
+ 950, 987, 993, 995, 998,
+ 1000
+};
+
+bool_ remove_curse_object(object_type *o_ptr, bool_ all)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) return FALSE;
+
+ /* Uncursed already */
+ if (!cursed_p(o_ptr)) return FALSE;
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Heavily Cursed Items need a special spell */
+ if (!all && (f3 & (TR3_HEAVY_CURSE))) return FALSE;
+
+ /* Perma-Cursed Items can NEVER be uncursed */
+ if (f3 & (TR3_PERMA_CURSE)) return FALSE;
+
+ /* Uncurse it */
+ o_ptr->ident &= ~(IDENT_CURSED);
+
+ /* Hack -- Assume felt */
+ o_ptr->ident |= (IDENT_SENSE);
+
+ if (o_ptr->art_flags3 & (TR3_CURSED))
+ o_ptr->art_flags3 &= ~(TR3_CURSED);
+
+ if (o_ptr->art_flags3 & (TR3_HEAVY_CURSE))
+ o_ptr->art_flags3 &= ~(TR3_HEAVY_CURSE);
+
+ /* Take note */
+ o_ptr->sense = SENSE_UNCURSED;
+
+ /* Reverse the curse effect */
+ /* jk - scrolls of *remove curse* have a 1 in (55-level chance to */
+ /* reverse the curse effects - a ring of damage(-15) {cursed} then */
+ /* becomes a ring of damage (+15) */
+ /* this does not go for artifacts - a Sword of Mormegil +40,+60 would */
+ /* be somewhat unbalancing */
+ /* due to the nature of this procedure, it only works on cursed items */
+ /* ie you get only one chance! */
+ if ((randint(55-p_ptr->lev) == 1) && !artifact_p(o_ptr))
+ {
+ if (o_ptr->to_a < 0) o_ptr->to_a = -o_ptr->to_a;
+ if (o_ptr->to_h < 0) o_ptr->to_h = -o_ptr->to_h;
+ if (o_ptr->to_d < 0) o_ptr->to_d = -o_ptr->to_d;
+ if (o_ptr->pval < 0) o_ptr->pval = -o_ptr->pval;
+ }
+
+ /* Recalculate the bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP);
+
+ return TRUE;
+}
+
+/*
+ * Removes curses from items in inventory
+ *
+ * Note that Items which are "Perma-Cursed" (The One Ring,
+ * The Crown of Morgoth) can NEVER be uncursed.
+ *
+ * Note that if "all" is FALSE, then Items which are
+ * "Heavy-Cursed" (Mormegil, Calris, and Weapons of Morgul)
+ * will not be uncursed.
+ */
+static int remove_curse_aux(int all)
+{
+ int i, cnt = 0;
+
+ /* Attempt to uncurse items being worn */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ if (!remove_curse_object(o_ptr, all)) continue;
+
+ /* Count the uncursings */
+ cnt++;
+ }
+
+ /* Return "something uncursed" */
+ return (cnt);
+}
+
+
+/*
+ * Remove most curses
+ */
+bool_ remove_curse(void)
+{
+ return (remove_curse_aux(FALSE) ? TRUE : FALSE);
+}
+
+/*
+ * Remove all curses
+ */
+bool_ remove_all_curse(void)
+{
+ return (remove_curse_aux(TRUE) ? TRUE : FALSE);
+}
+
+
+
+/*
+ * Restores any drained experience
+ */
+bool_ restore_level(void)
+{
+ /* Restore experience */
+ if (p_ptr->exp < p_ptr->max_exp)
+ {
+ /* Message */
+ msg_print("You feel your life energies returning.");
+
+ /* Restore the experience */
+ p_ptr->exp = p_ptr->max_exp;
+
+ /* Check the experience */
+ check_experience();
+
+ /* Did something */
+ return (TRUE);
+ }
+
+ /* No effect */
+ return (FALSE);
+}
+
+
+bool_ alchemy(void) /* Turns an object into gold, gain some of its value in a shop */
+{
+ int item, amt = 1;
+ int old_number;
+ long price;
+ bool_ force = FALSE;
+ object_type *o_ptr;
+ char o_name[80];
+ char out_val[160];
+
+ cptr q, s;
+
+ /* Hack -- force destruction */
+ if (command_arg > 0) force = TRUE;
+
+ /* Get an item */
+ q = "Turn which item to gold? ";
+ s = "You have nothing to turn to gold.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return (FALSE);
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+
+ /* See how many items */
+ if (o_ptr->number > 1)
+ {
+ /* Get a quantity */
+ amt = get_quantity(NULL, o_ptr->number);
+
+ /* Allow user abort */
+ if (amt <= 0) return FALSE;
+ }
+
+
+ /* Describe the object */
+ old_number = o_ptr->number;
+ o_ptr->number = amt;
+ object_desc(o_name, o_ptr, TRUE, 3);
+ o_ptr->number = old_number;
+
+ /* Verify unless quantity given */
+ if (!force)
+ {
+ if (!((auto_destroy) && (object_value(o_ptr) < 1)))
+ {
+ /* Make a verification */
+ sprintf(out_val, "Really turn %s to gold? ", o_name);
+ if (!get_check(out_val)) return FALSE;
+ }
+ }
+
+ /* Artifacts cannot be destroyed */
+ if (artifact_p(o_ptr) || o_ptr->art_name)
+ {
+ byte feel = SENSE_SPECIAL;
+
+ /* Message */
+ msg_format("You fail to turn %s to gold!", o_name);
+
+ /* Hack -- Handle icky artifacts */
+ if (cursed_p(o_ptr)) feel = SENSE_TERRIBLE;
+
+ /* Hack -- inscribe the artifact */
+ o_ptr->sense = feel;
+
+ /* We have "felt" it (again) */
+ o_ptr->ident |= (IDENT_SENSE);
+
+ /* Combine the pack */
+ p_ptr->notice |= (PN_COMBINE);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP);
+
+ /* Done */
+ return FALSE;
+ }
+
+ price = object_value_real(o_ptr);
+
+ if (price <= 0)
+ /* Message */
+ msg_format("You turn %s to fool's gold.", o_name);
+ else
+ {
+ price /= 3;
+
+ if (amt > 1) price *= amt;
+
+ msg_format("You turn %s to %ld coins worth of gold.", o_name, price);
+ p_ptr->au += price;
+
+ /* Redraw gold */
+ p_ptr->redraw |= (PR_GOLD);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ }
+
+ /* Eliminate the item */
+ inc_stack_size(item, -amt);
+
+ return TRUE;
+}
+
+
+
+
+/*
+ * self-knowledge... idea from nethack. Useful for determining powers and
+ * resistances of items. It saves the screen, clears it, then starts listing
+ * attributes, a screenful at a time. (There are a LOT of attributes to
+ * list. It will probably take 2 or 3 screens for a powerful character whose
+ * using several artifacts...) -CFT
+ *
+ * It is now a lot more efficient. -BEN-
+ *
+ * See also "identify_fully()".
+ *
+ * XXX XXX XXX Use the "show_file()" method, perhaps.
+ */
+void self_knowledge(FILE *fff)
+{
+ int i = 0, j, k;
+
+ u32b f1 = 0L, f2 = 0L, f3 = 0L, f4 = 0L, f5 = 0L, esp = 0L;
+
+ int iter; /* Iterator for a loop */
+
+ object_type *o_ptr;
+
+ char Dummy[80];
+
+ cptr info[200];
+
+ strcpy (Dummy, "");
+
+ /* Acquire item flags from equipment */
+ for (k = INVEN_WIELD; k < INVEN_TOTAL; k++)
+ {
+ u32b t1, t2, t3, t4, t5, esp;
+
+ o_ptr = &p_ptr->inventory[k];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Extract the flags */
+ object_flags(o_ptr, &t1, &t2, &t3, &t4, &t5, &esp);
+
+ /* Extract flags */
+ f1 |= t1;
+ f2 |= t2;
+ f3 |= t3;
+ }
+
+ if (death)
+ {
+ static char buf[250];
+
+ sprintf(buf, "You are dead, killed by %s %s.",
+ died_from, describe_player_location());
+ info[i++] = buf;
+ }
+
+ /* Racial powers... */
+ if (p_ptr->body_monster != 0)
+ {
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+ if (r_ptr->flags1 & RF1_CHAR_CLEAR ||
+ r_ptr->flags1 & RF1_ATTR_CLEAR)
+ info[i++] = "You are transparent.";
+ if ((r_ptr->flags1 & RF1_CHAR_MULTI) ||
+ (r_ptr->flags2 & RF2_SHAPECHANGER))
+ info[i++] = "Your form constantly changes.";
+ if (r_ptr->flags1 & RF1_ATTR_MULTI)
+ info[i++] = "Your color constantly changes.";
+ if (r_ptr->flags1 & RF1_NEVER_BLOW)
+ info[i++] = "You do not have a physical weapon.";
+ if (r_ptr->flags1 & RF1_NEVER_MOVE)
+ info[i++] = "You cannot move.";
+ if ((r_ptr->flags1 & RF1_RAND_25) &&
+ (r_ptr->flags1 & RF1_RAND_50))
+ info[i++] = "You move extremely erratically.";
+ else if (r_ptr->flags1 & RF1_RAND_50)
+ info[i++] = "You move somewhat erratically.";
+ else if (r_ptr->flags1 & RF1_RAND_25)
+ info[i++] = "You move a bit erratically.";
+ if (r_ptr->flags2 & RF2_STUPID)
+ info[i++] = "You are very stupid (INT -4).";
+ if (r_ptr->flags2 & RF2_SMART)
+ info[i++] = "You are very smart (INT +4).";
+ /* Not implemented */
+ if (r_ptr->flags2 & RF2_CAN_SPEAK)
+ info[i++] = "You can speak.";
+ else
+ info[i++] = "You cannot speak.";
+ /* Not implemented */
+ if (r_ptr->flags2 & RF2_COLD_BLOOD)
+ info[i++] = "You are cold blooded.";
+ /* Not implemented */
+ if (r_ptr->flags2 & RF2_EMPTY_MIND)
+ info[i++] = "You have an empty mind.";
+ if (r_ptr->flags2 & RF2_WEIRD_MIND)
+ info[i++] = "You have a weird mind.";
+ if (r_ptr->flags4 & RF4_MULTIPLY)
+ info[i++] = "You can multiply.";
+ if (r_ptr->flags2 & RF2_POWERFUL)
+ info[i++] = "You have strong breath.";
+ /* Not implemented */
+ if (r_ptr->flags2 & RF2_ELDRITCH_HORROR)
+ info[i++] = "You are an eldritch horror.";
+ if (r_ptr->flags2 & RF2_OPEN_DOOR)
+ info[i++] = "You can open doors.";
+ else
+ info[i++] = "You cannot open doors.";
+ if (r_ptr->flags2 & RF2_BASH_DOOR)
+ info[i++] = "You can bash doors.";
+ else
+ info[i++] = "You cannot bash doors.";
+ if (r_ptr->flags2 & RF2_PASS_WALL)
+ info[i++] = "You can pass walls.";
+ if (r_ptr->flags2 & RF2_KILL_WALL)
+ info[i++] = "You destroy walls.";
+ /* Not implemented */
+ if (r_ptr->flags2 & RF2_MOVE_BODY)
+ info[i++] = "You can move monsters.";
+ /* Not implemented */
+ if (r_ptr->flags3 & RF3_ORC)
+ info[i++] = "You have orc blood in your veins.";
+ /* Not implemented */
+ else if (r_ptr->flags3 & RF3_TROLL)
+ info[i++] = "You have troll blood in your veins.";
+ /* Not implemented */
+ else if (r_ptr->flags3 & RF3_GIANT)
+ info[i++] = "You have giant blood in your veins.";
+ /* Not implemented */
+ else if (r_ptr->flags3 & RF3_DRAGON)
+ info[i++] = "You have dragon blood in your veins.";
+ /* Not implemented */
+ else if (r_ptr->flags3 & RF3_DEMON)
+ info[i++] = "You have demon blood in your veins.";
+ /* Not implemented */
+ else if (r_ptr->flags3 & RF3_UNDEAD)
+ info[i++] = "You are an undead.";
+ /* Not implemented */
+ else if (r_ptr->flags3 & RF3_ANIMAL)
+ info[i++] = "You are an animal.";
+ /* Not implemented */
+ else if (r_ptr->flags3 & RF3_THUNDERLORD)
+ info[i++] = "You have thunderlord blood in your veins.";
+ if (r_ptr->flags3 & RF3_EVIL)
+ info[i++] = "You are inherently evil.";
+ else if (r_ptr->flags3 & RF3_GOOD)
+ info[i++] = "You are inherently good.";
+ if (r_ptr->flags3 & RF3_AURA_COLD)
+ info[i++] = "You are surrounded by a chilly aura.";
+ /* Not implemented */
+ if (r_ptr->flags3 & RF3_NONLIVING)
+ info[i++] = "You are not living.";
+ /* Not implemented */
+ if (r_ptr->flags3 & RF3_HURT_LITE)
+ info[i++] = "Your eyes are vulnerable to bright light.";
+ /* Not implemented */
+ if (r_ptr->flags3 & RF3_HURT_ROCK)
+ info[i++] = "You can be hurt by rock remover.";
+ if (r_ptr->flags3 & RF3_SUSCEP_FIRE)
+ info[i++] = "You are vulnerable to fire.";
+ if (r_ptr->flags3 & RF3_SUSCEP_COLD)
+ info[i++] = "You are vulnerable to cold.";
+ if (r_ptr->flags3 & RF3_RES_TELE)
+ info[i++] = "You are resistant to teleportation.";
+ if (r_ptr->flags3 & RF3_RES_NETH)
+ info[i++] = "You are resistant to nether.";
+ if (r_ptr->flags3 & RF3_RES_WATE)
+ info[i++] = "You are resistant to water.";
+ if (r_ptr->flags3 & RF3_RES_PLAS)
+ info[i++] = "You are resistant to plasma.";
+ if (r_ptr->flags3 & RF3_RES_WATE)
+ info[i++] = "You are resistant to nexus.";
+ if (r_ptr->flags3 & RF3_RES_DISE)
+ info[i++] = "You are resistant to disease.";
+ /* Not implemented */
+ if (r_ptr->flags3 & RF3_NO_SLEEP)
+ info[i++] = "You cannot be slept.";
+ /* Not implemented */
+ if (r_ptr->flags3 & RF3_UNIQUE_4)
+ info[i++] = "You are a Nazgul.";
+ if (r_ptr->flags3 & RF3_NO_FEAR)
+ info[i++] = "You are immune to fear.";
+ if (r_ptr->flags3 & RF3_NO_STUN)
+ info[i++] = "You are immune to stun.";
+ if (r_ptr->flags3 & RF3_NO_CONF)
+ info[i++] = "You are immune to confusion.";
+ if (r_ptr->flags3 & RF3_NO_SLEEP)
+ info[i++] = "You are immune to sleep.";
+
+ if (r_ptr->flags4 & RF4_SHRIEK)
+ info[i++] = "You can aggravate monsters.";
+ if (r_ptr->flags4 & RF4_ROCKET)
+ info[i++] = "You can fire a rocket.";
+ if (r_ptr->flags4 & RF4_ARROW_1)
+ info[i++] = "You can fire a light arrow.";
+ if (r_ptr->flags4 & RF4_ARROW_2)
+ info[i++] = "You can fire a heavy arrow.";
+ if (r_ptr->flags4 & RF4_ARROW_3)
+ info[i++] = "You can fire a light missile.";
+ if (r_ptr->flags4 & RF4_ARROW_4)
+ info[i++] = "You can fire a heavy missile.";
+ if (r_ptr->flags4 & RF4_BR_ACID)
+ info[i++] = "You can breathe acid.";
+ if (r_ptr->flags4 & RF4_BR_ELEC)
+ info[i++] = "You can breathe electricity.";
+ if (r_ptr->flags4 & RF4_BR_FIRE)
+ info[i++] = "You can breathe fire.";
+ if (r_ptr->flags4 & RF4_BR_COLD)
+ info[i++] = "You can breathe cold.";
+ if (r_ptr->flags4 & RF4_BR_POIS)
+ info[i++] = "You can breathe poison.";
+ if (r_ptr->flags4 & RF4_BR_NETH)
+ info[i++] = "You can breathe nether.";
+ if (r_ptr->flags4 & RF4_BR_LITE)
+ info[i++] = "You can breathe light.";
+ if (r_ptr->flags4 & RF4_BR_DARK)
+ info[i++] = "You can breathe darkness.";
+ if (r_ptr->flags4 & RF4_BR_CONF)
+ info[i++] = "You can breathe confusion.";
+ if (r_ptr->flags4 & RF4_BR_SOUN)
+ info[i++] = "You can breathe sound.";
+ if (r_ptr->flags4 & RF4_BR_CHAO)
+ info[i++] = "You can breathe chaos.";
+ if (r_ptr->flags4 & RF4_BR_DISE)
+ info[i++] = "You can breathe disenchantment.";
+ if (r_ptr->flags4 & RF4_BR_NEXU)
+ info[i++] = "You can breathe nexus.";
+ if (r_ptr->flags4 & RF4_BR_TIME)
+ info[i++] = "You can breathe time.";
+ if (r_ptr->flags4 & RF4_BR_INER)
+ info[i++] = "You can breathe inertia.";
+ if (r_ptr->flags4 & RF4_BR_GRAV)
+ info[i++] = "You can breathe gravity.";
+ if (r_ptr->flags4 & RF4_BR_SHAR)
+ info[i++] = "You can breathe shards.";
+ if (r_ptr->flags4 & RF4_BR_PLAS)
+ info[i++] = "You can breathe plasma.";
+ if (r_ptr->flags4 & RF4_BR_WALL)
+ info[i++] = "You can breathe force.";
+ if (r_ptr->flags4 & RF4_BR_MANA)
+ info[i++] = "You can breathe mana.";
+ if (r_ptr->flags4 & RF4_BR_NUKE)
+ info[i++] = "You can breathe nuke.";
+ if (r_ptr->flags4 & RF4_BR_DISI)
+ info[i++] = "You can breathe disintegration.";
+ if (r_ptr->flags5 & RF5_BA_ACID)
+ info[i++] = "You can cast a ball of acid.";
+ if (r_ptr->flags5 & RF5_BA_ELEC)
+ info[i++] = "You can cast a ball of electricity.";
+ if (r_ptr->flags5 & RF5_BA_FIRE)
+ info[i++] = "You can cast a ball of fire.";
+ if (r_ptr->flags5 & RF5_BA_COLD)
+ info[i++] = "You can cast a ball of cold.";
+ if (r_ptr->flags5 & RF5_BA_POIS)
+ info[i++] = "You can cast a ball of poison.";
+ if (r_ptr->flags5 & RF5_BA_NETH)
+ info[i++] = "You can cast a ball of nether.";
+ if (r_ptr->flags5 & RF5_BA_WATE)
+ info[i++] = "You can cast a ball of water.";
+ /* Not implemented */
+ if (r_ptr->flags5 & RF5_DRAIN_MANA)
+ info[i++] = "You can drain mana.";
+ if (r_ptr->flags5 & RF5_MIND_BLAST)
+ info[i++] = "You can cause mind blasting.";
+ if (r_ptr->flags5 & RF5_BRAIN_SMASH)
+ info[i++] = "You can cause brain smashing.";
+ if (r_ptr->flags5 & RF5_CAUSE_1)
+ info[i++] = "You can cause light wounds.";
+ if (r_ptr->flags5 & RF5_CAUSE_2)
+ info[i++] = "You can cause serious wounds.";
+ if (r_ptr->flags5 & RF5_CAUSE_3)
+ info[i++] = "You can cause critical wounds.";
+ if (r_ptr->flags5 & RF5_CAUSE_4)
+ info[i++] = "You can cause mortal wounds.";
+ if (r_ptr->flags5 & RF5_BO_ACID)
+ info[i++] = "You can cast a bolt of acid.";
+ if (r_ptr->flags5 & RF5_BO_ELEC)
+ info[i++] = "You can cast a bolt of electricity.";
+ if (r_ptr->flags5 & RF5_BO_FIRE)
+ info[i++] = "You can cast a bolt of fire.";
+ if (r_ptr->flags5 & RF5_BO_COLD)
+ info[i++] = "You can cast a bolt of cold.";
+ if (r_ptr->flags5 & RF5_BO_POIS)
+ info[i++] = "You can cast a bolt of poison.";
+ if (r_ptr->flags5 & RF5_BO_NETH)
+ info[i++] = "You can cast a bolt of nether.";
+ if (r_ptr->flags5 & RF5_BO_WATE)
+ info[i++] = "You can cast a bolt of water.";
+ if (r_ptr->flags5 & RF5_BO_MANA)
+ info[i++] = "You can cast a bolt of mana.";
+ if (r_ptr->flags5 & RF5_BO_PLAS)
+ info[i++] = "You can cast a bolt of plasma.";
+ if (r_ptr->flags5 & RF5_BO_ICEE)
+ info[i++] = "You can cast a bolt of ice.";
+ if (r_ptr->flags5 & RF5_MISSILE)
+ info[i++] = "You can cast magic missile.";
+ if (r_ptr->flags5 & RF5_SCARE)
+ info[i++] = "You can terrify.";
+ if (r_ptr->flags5 & RF5_BLIND)
+ info[i++] = "You can blind.";
+ if (r_ptr->flags5 & RF5_CONF)
+ info[i++] = "You can use confusion.";
+ if (r_ptr->flags5 & RF5_SLOW)
+ info[i++] = "You can cast slow.";
+ if (r_ptr->flags5 & RF5_HOLD)
+ info[i++] = "You can touch to paralyze.";
+ if (r_ptr->flags6 & RF6_HASTE)
+ info[i++] = "You can haste yourself.";
+ if (r_ptr->flags6 & RF6_HAND_DOOM)
+ info[i++] = "You can invoke Hand of Doom.";
+ if (r_ptr->flags6 & RF6_HEAL)
+ info[i++] = "You can heal yourself.";
+ if (r_ptr->flags6 & RF6_BLINK)
+ info[i++] = "You can blink.";
+ if (r_ptr->flags6 & RF6_TPORT)
+ info[i++] = "You can teleport.";
+ if (r_ptr->flags6 & RF6_TELE_TO)
+ info[i++] = "You can go between places.";
+ if (r_ptr->flags6 & RF6_TELE_AWAY)
+ info[i++] = "You can teleport away.";
+ if (r_ptr->flags6 & RF6_TELE_LEVEL)
+ info[i++] = "You can teleport level.";
+ if (r_ptr->flags6 & RF6_DARKNESS)
+ info[i++] = "You can create darkness.";
+ if (r_ptr->flags6 & RF6_TRAPS)
+ info[i++] = "You can create traps.";
+ /* Not implemented */
+ if (r_ptr->flags6 & RF6_FORGET)
+ info[i++] = "You can fade memories.";
+ if (r_ptr->flags6 & RF6_RAISE_DEAD)
+ info[i++] = "You can Raise the Dead.";
+ if (r_ptr->flags6 & RF6_S_BUG)
+ info[i++] = "You can magically summon a Software Bugs.";
+ if (r_ptr->flags6 & RF6_S_RNG)
+ info[i++] = "You can magically summon the RNG.";
+ if (r_ptr->flags6 & RF6_S_THUNDERLORD)
+ info[i++] = "You can magically summon some Thunderlords.";
+ if (r_ptr->flags6 & RF6_S_KIN)
+ info[i++] = "You can magically summon some Kins.";
+ if (r_ptr->flags6 & RF6_S_HI_DEMON)
+ info[i++] = "You can magically summon greater demons.";
+ if (r_ptr->flags6 & RF6_S_MONSTER)
+ info[i++] = "You can magically summon a monster.";
+ if (r_ptr->flags6 & RF6_S_MONSTERS)
+ info[i++] = "You can magically summon monsters.";
+ if (r_ptr->flags6 & RF6_S_ANT)
+ info[i++] = "You can magically summon ants.";
+ if (r_ptr->flags6 & RF6_S_SPIDER)
+ info[i++] = "You can magically summon spiders.";
+ if (r_ptr->flags6 & RF6_S_HOUND)
+ info[i++] = "You can magically summon hounds.";
+ if (r_ptr->flags6 & RF6_S_HYDRA)
+ info[i++] = "You can magically summon hydras.";
+ if (r_ptr->flags6 & RF6_S_ANGEL)
+ info[i++] = "You can magically summon an angel.";
+ if (r_ptr->flags6 & RF6_S_DEMON)
+ info[i++] = "You can magically summon a demon.";
+ if (r_ptr->flags6 & RF6_S_UNDEAD)
+ info[i++] = "You can magically summon an undead.";
+ if (r_ptr->flags6 & RF6_S_DRAGON)
+ info[i++] = "You can magically summon a dragon.";
+ if (r_ptr->flags6 & RF6_S_HI_UNDEAD)
+ info[i++] = "You can magically summon greater undead.";
+ if (r_ptr->flags6 & RF6_S_HI_DRAGON)
+ info[i++] = "You can magically summon greater dragons.";
+ if (r_ptr->flags6 & RF6_S_WRAITH)
+ info[i++] = "You can magically summon a wraith.";
+ /* Not implemented */
+ if (r_ptr->flags6 & RF6_S_UNIQUE)
+ info[i++] = "You can magically summon an unique monster.";
+ /* Not implemented */
+ if (r_ptr->flags7 & RF7_AQUATIC)
+ info[i++] = "You are aquatic.";
+ /* Not implemented */
+ if (r_ptr->flags7 & RF7_CAN_SWIM)
+ info[i++] = "You can swim.";
+ /* Not implemented */
+ if (r_ptr->flags7 & RF7_CAN_FLY)
+ info[i++] = "You can fly.";
+ if ((r_ptr->flags7 & RF7_MORTAL) == 0)
+ info[i++] = "You are immortal.";
+ /* Not implemented */
+ if (r_ptr->flags7 & RF7_NAZGUL)
+ info[i++] = "You are a Nazgul.";
+
+ if (r_ptr->flags7 & RF7_SPIDER)
+ info[i++] = "You are a spider.";
+
+ if (r_ptr->flags8 & RF8_WILD_TOWN)
+ info[i++] = "You appear in towns.";
+ if (r_ptr->flags8 & RF8_WILD_SHORE)
+ info[i++] = "You appear on the shore.";
+ if (r_ptr->flags8 & RF8_WILD_OCEAN)
+ info[i++] = "You appear in the ocean.";
+ if (r_ptr->flags8 & RF8_WILD_WASTE)
+ info[i++] = "You appear in the waste.";
+ if (r_ptr->flags8 & RF8_WILD_WOOD)
+ info[i++] = "You appear in woods.";
+ if (r_ptr->flags8 & RF8_WILD_VOLCANO)
+ info[i++] = "You appear in volcanos.";
+ if (r_ptr->flags8 & RF8_WILD_MOUNTAIN)
+ info[i++] = "You appear in the mountains.";
+ if (r_ptr->flags8 & RF8_WILD_GRASS)
+ info[i++] = "You appear in grassy areas.";
+
+ if (r_ptr->flags9 & RF9_SUSCEP_ACID)
+ info[i++] = "You are vulnerable to acid.";
+ if (r_ptr->flags9 & RF9_SUSCEP_ELEC)
+ info[i++] = "You are vulnerable to electricity.";
+ if (r_ptr->flags9 & RF9_SUSCEP_POIS)
+ info[i++] = "You are vulnerable to poison.";
+ if (r_ptr->flags9 & RF9_KILL_TREES)
+ info[i++] = "You can eat trees.";
+ if (r_ptr->flags9 & RF9_WYRM_PROTECT)
+ info[i++] = "You are protected by great wyrms of power.";
+ }
+
+ /* List powers */
+ for (iter = 0; iter < power_max; iter++)
+ {
+ if (p_ptr->powers[iter])
+ {
+ info[i++] = powers_type[iter].desc_text;
+ }
+ }
+
+ if (p_ptr->allow_one_death)
+ {
+ info[i++] = "The Blood of Life flows through your veins.";
+ }
+ if (p_ptr->blind)
+ {
+ info[i++] = "You cannot see.";
+ }
+ if (p_ptr->confused)
+ {
+ info[i++] = "You are confused.";
+ }
+ if (p_ptr->afraid)
+ {
+ info[i++] = "You are terrified.";
+ }
+ if (p_ptr->cut)
+ {
+ info[i++] = "You are bleeding.";
+ }
+ if (p_ptr->stun)
+ {
+ info[i++] = "You are stunned.";
+ }
+ if (p_ptr->poisoned)
+ {
+ info[i++] = "You are poisoned.";
+ }
+ if (p_ptr->image)
+ {
+ info[i++] = "You are hallucinating.";
+ }
+ if (p_ptr->aggravate)
+ {
+ info[i++] = "You aggravate monsters.";
+ }
+ if (p_ptr->teleport)
+ {
+ info[i++] = "Your position is very uncertain.";
+ }
+ if (p_ptr->blessed)
+ {
+ info[i++] = "You feel righteous.";
+ }
+ if (p_ptr->hero)
+ {
+ info[i++] = "You feel heroic.";
+ }
+ if (p_ptr->shero)
+ {
+ info[i++] = "You are in a battle rage.";
+ }
+ if (p_ptr->protevil)
+ {
+ info[i++] = "You are protected from evil.";
+ }
+ if (p_ptr->protgood)
+ {
+ info[i++] = "You are protected from good.";
+ }
+ if (p_ptr->shield)
+ {
+ info[i++] = "You are protected by a mystic shield.";
+ }
+ if (p_ptr->invuln)
+ {
+ info[i++] = "You are temporarily invulnerable.";
+ }
+ if (p_ptr->confusing)
+ {
+ info[i++] = "Your hands are glowing dull red.";
+ }
+ if (p_ptr->searching)
+ {
+ info[i++] = "You are looking around very carefully.";
+ }
+ if (p_ptr->new_spells)
+ {
+ info[i++] = "You can learn some spells/prayers.";
+ }
+ if (p_ptr->word_recall)
+ {
+ info[i++] = "You will soon be recalled.";
+ }
+ if (p_ptr->see_infra)
+ {
+ info[i++] = "Your eyes are sensitive to infrared light.";
+ }
+ if (p_ptr->see_inv)
+ {
+ info[i++] = "You can see invisible creatures.";
+ }
+ if (p_ptr->magical_breath)
+ {
+ info[i++] = "You can breathe without air.";
+ }
+ else if (p_ptr->water_breath)
+ {
+ info[i++] = "You can breathe underwater.";
+ }
+ if (p_ptr->ffall)
+ {
+ info[i++] = "You levitate just over the ground.";
+ }
+ if (p_ptr->climb)
+ {
+ info[i++] = "You can climb high mountains.";
+ }
+ if (p_ptr->free_act)
+ {
+ info[i++] = "You have free action.";
+ }
+ if (p_ptr->regenerate)
+ {
+ info[i++] = "You regenerate quickly.";
+ }
+ if (p_ptr->slow_digest)
+ {
+ info[i++] = "Your appetite is small.";
+ }
+ if (p_ptr->telepathy)
+ {
+ if (p_ptr->telepathy & ESP_ALL) info[i++] = "You have ESP.";
+ else
+ {
+ if (p_ptr->telepathy & ESP_ORC) info[i++] = "You can sense the presence of orcs.";
+ if (p_ptr->telepathy & ESP_TROLL) info[i++] = "You can sense the presence of trolls.";
+ if (p_ptr->telepathy & ESP_DRAGON) info[i++] = "You can sense the presence of dragons.";
+ if (p_ptr->telepathy & ESP_SPIDER) info[i++] = "You can sense the presence of spiders.";
+ if (p_ptr->telepathy & ESP_GIANT) info[i++] = "You can sense the presence of giants.";
+ if (p_ptr->telepathy & ESP_DEMON) info[i++] = "You can sense the presence of demons.";
+ if (p_ptr->telepathy & ESP_UNDEAD) info[i++] = "You can sense presence of undead.";
+ if (p_ptr->telepathy & ESP_EVIL) info[i++] = "You can sense the presence of evil beings.";
+ if (p_ptr->telepathy & ESP_ANIMAL) info[i++] = "You can sense the presence of animals.";
+ if (p_ptr->telepathy & ESP_THUNDERLORD) info[i++] = "You can sense the presence of thunderlords.";
+ if (p_ptr->telepathy & ESP_GOOD) info[i++] = "You can sense the presence of good beings.";
+ if (p_ptr->telepathy & ESP_NONLIVING) info[i++] = "You can sense the presence of non-living things.";
+ if (p_ptr->telepathy & ESP_UNIQUE) info[i++] = "You can sense the presence of unique beings.";
+ }
+ }
+ if (!luck( -100, 100))
+ {
+ info[i++] = "You have normal luck.";
+ }
+ else if (luck( -100, 100) < 0)
+ {
+ if (luck( -100, 100) < -90)
+ {
+ info[i++] = "You are incredibly unlucky.";
+ }
+ else if (luck( -100, 100) < -60)
+ {
+ info[i++] = "You are extremely unlucky.";
+ }
+ else if (luck( -100, 100) < -30)
+ {
+ info[i++] = "You are very unlucky.";
+ }
+ else
+ {
+ info[i++] = "You are unlucky.";
+ }
+ }
+ else if (luck( -100, 100) > 0)
+ {
+ if (luck( -100, 100) > 90)
+ {
+ info[i++] = "You are incredibly lucky.";
+ }
+ else if (luck( -100, 100) > 60)
+ {
+ info[i++] = "You are extremely lucky.";
+ }
+ else if (luck( -100, 100) > 30)
+ {
+ info[i++] = "You are very lucky.";
+ }
+ else
+ {
+ info[i++] = "You are lucky.";
+ }
+ }
+ if (p_ptr->auto_id)
+ {
+ info[i++] = "You know everything.";
+ }
+ if (p_ptr->hold_life)
+ {
+ info[i++] = "You have a firm hold on your life force.";
+ }
+ if (p_ptr->reflect)
+ {
+ info[i++] = "You reflect arrows and bolts.";
+ }
+ if (p_ptr->sh_fire)
+ {
+ info[i++] = "You are surrounded with a fiery aura.";
+ }
+ if (p_ptr->sh_elec)
+ {
+ info[i++] = "You are surrounded with electricity.";
+ }
+ if (p_ptr->antimagic)
+ {
+ info[i++] = "You are surrounded by an anti-magic field.";
+ }
+ if (p_ptr->anti_magic)
+ {
+ info[i++] = "You are surrounded by an anti-magic shell.";
+ }
+ if (p_ptr->wraith_form)
+ {
+ info[i++] = "You are incorporeal.";
+ }
+ if (p_ptr->anti_tele)
+ {
+ info[i++] = "You cannot teleport.";
+ }
+ if (p_ptr->lite)
+ {
+ info[i++] = "You are carrying a permanent light.";
+ }
+
+ if (p_ptr->immune_acid)
+ {
+ info[i++] = "You are completely immune to acid.";
+ }
+ else if ((p_ptr->resist_acid) && (p_ptr->oppose_acid))
+ {
+ info[i++] = "You resist acid exceptionally well.";
+ }
+ else if ((p_ptr->resist_acid) || (p_ptr->oppose_acid))
+ {
+ info[i++] = "You are resistant to acid.";
+ }
+
+ if (p_ptr->immune_elec)
+ {
+ info[i++] = "You are completely immune to lightning.";
+ }
+ else if ((p_ptr->resist_elec) && (p_ptr->oppose_elec))
+ {
+ info[i++] = "You resist lightning exceptionally well.";
+ }
+ else if ((p_ptr->resist_elec) || (p_ptr->oppose_elec))
+ {
+ info[i++] = "You are resistant to lightning.";
+ }
+
+ if (p_ptr->immune_fire)
+ {
+ info[i++] = "You are completely immune to fire.";
+ }
+ else if ((p_ptr->resist_fire) && (p_ptr->oppose_fire))
+ {
+ info[i++] = "You resist fire exceptionally well.";
+ }
+ else if ((p_ptr->resist_fire) || (p_ptr->oppose_fire))
+ {
+ info[i++] = "You are resistant to fire.";
+ }
+ else if (p_ptr->sensible_fire)
+ {
+ info[i++] = "You are very vulnerable to fire.";
+ }
+
+ if (p_ptr->immune_cold)
+ {
+ info[i++] = "You are completely immune to cold.";
+ }
+ else if ((p_ptr->resist_cold) && (p_ptr->oppose_cold))
+ {
+ info[i++] = "You resist cold exceptionally well.";
+ }
+ else if ((p_ptr->resist_cold) || (p_ptr->oppose_cold))
+ {
+ info[i++] = "You are resistant to cold.";
+ }
+
+ if ((p_ptr->resist_pois) && (p_ptr->oppose_pois))
+ {
+ info[i++] = "You resist poison exceptionally well.";
+ }
+ else if ((p_ptr->resist_pois) || (p_ptr->oppose_pois))
+ {
+ info[i++] = "You are resistant to poison.";
+ }
+
+ if (p_ptr->resist_lite)
+ {
+ info[i++] = "You are resistant to bright light.";
+ }
+ if (p_ptr->resist_dark)
+ {
+ info[i++] = "You are resistant to darkness.";
+ }
+ if (p_ptr->resist_conf)
+ {
+ info[i++] = "You are resistant to confusion.";
+ }
+ if (p_ptr->resist_sound)
+ {
+ info[i++] = "You are resistant to sonic attacks.";
+ }
+ if (p_ptr->resist_disen)
+ {
+ info[i++] = "You are resistant to disenchantment.";
+ }
+ if (p_ptr->resist_chaos)
+ {
+ info[i++] = "You are resistant to chaos.";
+ }
+ if (p_ptr->resist_shard)
+ {
+ info[i++] = "You are resistant to blasts of shards.";
+ }
+ if (p_ptr->resist_nexus)
+ {
+ info[i++] = "You are resistant to nexus attacks.";
+ }
+ if (p_ptr->immune_neth)
+ {
+ info[i++] = "You are immune to nether forces.";
+ }
+ else if (p_ptr->resist_neth)
+ {
+ info[i++] = "You are resistant to nether forces.";
+ }
+ if (p_ptr->resist_fear)
+ {
+ info[i++] = "You are completely fearless.";
+ }
+ if (p_ptr->resist_blind)
+ {
+ info[i++] = "Your eyes are resistant to blindness.";
+ }
+ if (p_ptr->resist_continuum)
+ {
+ info[i++] = "The space-time continuum cannot be disrupted near you.";
+ }
+
+ if (p_ptr->sustain_str)
+ {
+ info[i++] = "Your strength is sustained.";
+ }
+ if (p_ptr->sustain_int)
+ {
+ info[i++] = "Your intelligence is sustained.";
+ }
+ if (p_ptr->sustain_wis)
+ {
+ info[i++] = "Your wisdom is sustained.";
+ }
+ if (p_ptr->sustain_con)
+ {
+ info[i++] = "Your constitution is sustained.";
+ }
+ if (p_ptr->sustain_dex)
+ {
+ info[i++] = "Your dexterity is sustained.";
+ }
+ if (p_ptr->sustain_chr)
+ {
+ info[i++] = "Your charisma is sustained.";
+ }
+ if (p_ptr->black_breath)
+ {
+ info[i++] = "You suffer from Black Breath.";
+ }
+
+ if (f1 & (TR1_STR))
+ {
+ info[i++] = "Your strength is affected by your equipment.";
+ }
+ if (f1 & (TR1_INT))
+ {
+ info[i++] = "Your intelligence is affected by your equipment.";
+ }
+ if (f1 & (TR1_WIS))
+ {
+ info[i++] = "Your wisdom is affected by your equipment.";
+ }
+ if (f1 & (TR1_DEX))
+ {
+ info[i++] = "Your dexterity is affected by your equipment.";
+ }
+ if (f1 & (TR1_CON))
+ {
+ info[i++] = "Your constitution is affected by your equipment.";
+ }
+ if (f1 & (TR1_CHR))
+ {
+ info[i++] = "Your charisma is affected by your equipment.";
+ }
+
+ if (f1 & (TR1_STEALTH))
+ {
+ info[i++] = "Your stealth is affected by your equipment.";
+ }
+ if (f1 & (TR1_SEARCH))
+ {
+ info[i++] = "Your searching ability is affected by your equipment.";
+ }
+ if (f1 & (TR1_INFRA))
+ {
+ info[i++] = "Your infravision is affected by your equipment.";
+ }
+ if (f1 & (TR1_TUNNEL))
+ {
+ info[i++] = "Your digging ability is affected by your equipment.";
+ }
+ if (f1 & (TR1_SPEED))
+ {
+ info[i++] = "Your speed is affected by your equipment.";
+ }
+ if (f1 & (TR1_BLOWS))
+ {
+ info[i++] = "Your attack speed is affected by your equipment.";
+ }
+ if (f5 & (TR5_CRIT))
+ {
+ info[i++] = "Your ability to score critical hits is affected by your equipment.";
+ }
+
+
+ /* Access the current weapon */
+ o_ptr = &p_ptr->inventory[INVEN_WIELD];
+
+ /* Analyze the weapon */
+ if (o_ptr->k_idx)
+ {
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Indicate Blessing */
+ if (f3 & (TR3_BLESSED))
+ {
+ info[i++] = "Your weapon has been blessed by the gods.";
+ }
+
+ if (f1 & (TR1_CHAOTIC))
+ {
+ info[i++] = "Your weapon is branded with the Sign of Chaos.";
+ }
+
+ /* Hack */
+ if (f1 & (TR1_IMPACT))
+ {
+ info[i++] = "The impact of your weapon can cause earthquakes.";
+ }
+
+ if (f1 & (TR1_VORPAL))
+ {
+ info[i++] = "Your weapon is very sharp.";
+ }
+
+ if (f1 & (TR1_VAMPIRIC))
+ {
+ info[i++] = "Your weapon drains life from your foes.";
+ }
+
+ /* Special "Attack Bonuses" */
+ if (f1 & (TR1_BRAND_ACID))
+ {
+ info[i++] = "Your weapon melts your foes.";
+ }
+ if (f1 & (TR1_BRAND_ELEC))
+ {
+ info[i++] = "Your weapon shocks your foes.";
+ }
+ if (f1 & (TR1_BRAND_FIRE))
+ {
+ info[i++] = "Your weapon burns your foes.";
+ }
+ if (f1 & (TR1_BRAND_COLD))
+ {
+ info[i++] = "Your weapon freezes your foes.";
+ }
+ if (f1 & (TR1_BRAND_POIS))
+ {
+ info[i++] = "Your weapon poisons your foes.";
+ }
+
+ /* Special "slay" flags */
+ if (f1 & (TR1_SLAY_ANIMAL))
+ {
+ info[i++] = "Your weapon strikes at animals with extra force.";
+ }
+ if (f1 & (TR1_SLAY_EVIL))
+ {
+ info[i++] = "Your weapon strikes at evil with extra force.";
+ }
+ if (f1 & (TR1_SLAY_UNDEAD))
+ {
+ info[i++] = "Your weapon strikes at undead with holy wrath.";
+ }
+ if (f1 & (TR1_SLAY_DEMON))
+ {
+ info[i++] = "Your weapon strikes at demons with holy wrath.";
+ }
+ if (f1 & (TR1_SLAY_ORC))
+ {
+ info[i++] = "Your weapon is especially deadly against orcs.";
+ }
+ if (f1 & (TR1_SLAY_TROLL))
+ {
+ info[i++] = "Your weapon is especially deadly against trolls.";
+ }
+ if (f1 & (TR1_SLAY_GIANT))
+ {
+ info[i++] = "Your weapon is especially deadly against giants.";
+ }
+ if (f1 & (TR1_SLAY_DRAGON))
+ {
+ info[i++] = "Your weapon is especially deadly against dragons.";
+ }
+
+ /* Special "kill" flags */
+ if (f1 & (TR1_KILL_DRAGON))
+ {
+ info[i++] = "Your weapon is a great bane of dragons.";
+ }
+ /* Special "kill" flags */
+ if (f5 & (TR5_KILL_DEMON))
+ {
+ info[i++] = "Your weapon is a great bane of demons.";
+ }
+ /* Special "kill" flags */
+ if (f5 & (TR5_KILL_UNDEAD))
+ {
+ info[i++] = "Your weapon is a great bane of undeads.";
+ }
+ }
+
+ /* Print on screen or in a file ? */
+ if (fff == NULL)
+ {
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Erase the screen */
+ for (k = 1; k < 24; k++) prt("", k, 13);
+
+ /* Label the information */
+ prt(" Your Attributes:", 1, 15);
+
+ /* We will print on top of the map (column 13) */
+ for (k = 2, j = 0; j < i; j++)
+ {
+ /* Show the info */
+ prt(info[j], k++, 15);
+
+ /* Every 20 entries (lines 2 to 21), start over */
+ if ((k == 22) && (j + 1 < i))
+ {
+ prt("-- more --", k, 15);
+ inkey();
+ for (; k > 2; k--) prt("", k, 15);
+ }
+ }
+
+ /* Pause */
+ prt("[Press any key to continue]", k, 13);
+ inkey();
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+ }
+ else
+ {
+ /* Label the information */
+ fprintf(fff, " Your Attributes:\n");
+
+ /* We will print on top of the map (column 13) */
+ for (j = 0; j < i; j ++)
+ {
+ /* Show the info */
+ fprintf(fff, "%s\n", info[j]);
+ }
+ }
+}
+
+
+static int report_magics_aux(int dur)
+{
+ if (dur <= 5)
+ {
+ return 0;
+ }
+ else if (dur <= 10)
+ {
+ return 1;
+ }
+ else if (dur <= 20)
+ {
+ return 2;
+ }
+ else if (dur <= 50)
+ {
+ return 3;
+ }
+ else if (dur <= 100)
+ {
+ return 4;
+ }
+ else if (dur <= 200)
+ {
+ return 5;
+ }
+ else
+ {
+ return 6;
+ }
+}
+
+static cptr report_magic_durations[] =
+{
+ "for a short time",
+ "for a little while",
+ "for a while",
+ "for a long while",
+ "for a long time",
+ "for a very long time",
+ "for an incredibly long time",
+ "until you hit a monster"
+};
+
+
+void report_magics(void)
+{
+ int i = 0, j, k;
+
+ char Dummy[80];
+
+ cptr info[128];
+ int info2[128];
+
+ if (p_ptr->blind)
+ {
+ info2[i] = report_magics_aux(p_ptr->blind);
+ info[i++] = "You cannot see";
+ }
+ if (p_ptr->confused)
+ {
+ info2[i] = report_magics_aux(p_ptr->confused);
+ info[i++] = "You are confused";
+ }
+ if (p_ptr->afraid)
+ {
+ info2[i] = report_magics_aux(p_ptr->afraid);
+ info[i++] = "You are terrified";
+ }
+ if (p_ptr->poisoned)
+ {
+ info2[i] = report_magics_aux(p_ptr->poisoned);
+ info[i++] = "You are poisoned";
+ }
+ if (p_ptr->image)
+ {
+ info2[i] = report_magics_aux(p_ptr->image);
+ info[i++] = "You are hallucinating";
+ }
+
+ if (p_ptr->blessed)
+ {
+ info2[i] = report_magics_aux(p_ptr->blessed);
+ info[i++] = "You feel righteous";
+ }
+ if (p_ptr->hero)
+ {
+ info2[i] = report_magics_aux(p_ptr->hero);
+ info[i++] = "You feel heroic";
+ }
+ if (p_ptr->shero)
+ {
+ info2[i] = report_magics_aux(p_ptr->shero);
+ info[i++] = "You are in a battle rage";
+ }
+ if (p_ptr->protevil)
+ {
+ info2[i] = report_magics_aux(p_ptr->protevil);
+ info[i++] = "You are protected from evil";
+ }
+ if (p_ptr->protgood)
+ {
+ info2[i] = report_magics_aux(p_ptr->protgood);
+ info[i++] = "You are protected from good";
+ }
+ if (p_ptr->shield)
+ {
+ info2[i] = report_magics_aux(p_ptr->shield);
+ info[i++] = "You are protected by a mystic shield";
+ }
+ if (p_ptr->invuln)
+ {
+ info2[i] = report_magics_aux(p_ptr->invuln);
+ info[i++] = "You are invulnerable";
+ }
+ if (p_ptr->tim_wraith)
+ {
+ info2[i] = report_magics_aux(p_ptr->tim_wraith);
+ info[i++] = "You are incorporeal";
+ }
+ if (p_ptr->confusing)
+ {
+ info2[i] = 7;
+ info[i++] = "Your hands are glowing dull red.";
+ }
+ if (p_ptr->word_recall)
+ {
+ info2[i] = report_magics_aux(p_ptr->word_recall);
+ info[i++] = "You waiting to be recalled";
+ }
+ if (p_ptr->oppose_acid)
+ {
+ info2[i] = report_magics_aux(p_ptr->oppose_acid);
+ info[i++] = "You are resistant to acid";
+ }
+ if (p_ptr->oppose_elec)
+ {
+ info2[i] = report_magics_aux(p_ptr->oppose_elec);
+ info[i++] = "You are resistant to lightning";
+ }
+ if (p_ptr->oppose_fire)
+ {
+ info2[i] = report_magics_aux(p_ptr->oppose_fire);
+ info[i++] = "You are resistant to fire";
+ }
+ if (p_ptr->oppose_cold)
+ {
+ info2[i] = report_magics_aux(p_ptr->oppose_cold);
+ info[i++] = "You are resistant to cold";
+ }
+ if (p_ptr->oppose_pois)
+ {
+ info2[i] = report_magics_aux(p_ptr->oppose_pois);
+ info[i++] = "You are resistant to poison";
+ }
+
+ /* Save the screen */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Erase the screen */
+ for (k = 1; k < 24; k++) prt("", k, 13);
+
+ /* Label the information */
+ prt(" Your Current Magic:", 1, 15);
+
+ /* We will print on top of the map (column 13) */
+ for (k = 2, j = 0; j < i; j++)
+ {
+ /* Show the info */
+ sprintf( Dummy, "%s %s.", info[j],
+ report_magic_durations[info2[j]] );
+ prt(Dummy, k++, 15);
+
+ /* Every 20 entries (lines 2 to 21), start over */
+ if ((k == 22) && (j + 1 < i))
+ {
+ prt("-- more --", k, 15);
+ inkey();
+ for (; k > 2; k--) prt("", k, 15);
+ }
+ }
+
+ /* Pause */
+ prt("[Press any key to continue]", k, 13);
+ inkey();
+
+ /* Restore the screen */
+ Term_load();
+ character_icky = FALSE;
+}
+
+
+
+/*
+ * Forget everything
+ */
+bool_ lose_all_info(void)
+{
+ int i;
+
+ /* Forget info about objects */
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Allow "protection" by the MENTAL flag */
+ if (o_ptr->ident & (IDENT_MENTAL)) continue;
+
+ /* Remove sensing */
+ o_ptr->sense = SENSE_NONE;
+
+ /* Hack -- Clear the "empty" flag */
+ o_ptr->ident &= ~(IDENT_EMPTY);
+
+ /* Hack -- Clear the "known" flag */
+ o_ptr->ident &= ~(IDENT_KNOWN);
+
+ /* Hack -- Clear the "felt" flag */
+ o_ptr->ident &= ~(IDENT_SENSE);
+ }
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Mega-Hack -- Forget the map */
+ wiz_dark();
+
+ /* It worked */
+ return (TRUE);
+}
+
+
+
+
+/*
+ * Detect all traps on current panel
+ */
+bool_ detect_traps(int rad)
+{
+ int x, y;
+ bool_ detect = FALSE;
+ cave_type *c_ptr;
+
+
+ /* Scan the current panel */
+ for (y = p_ptr->py - rad; y <= p_ptr->py + rad; y++)
+ {
+ for (x = p_ptr->px - rad; x <= p_ptr->px + rad; x++)
+ {
+ /* Reject locations outside of dungeon */
+ if (!in_bounds(y, x)) continue;
+
+ /* Reject those out of radius */
+ if (distance(p_ptr->py, p_ptr->px, y, x) > rad) continue;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* mark as detected */
+ c_ptr->info |= CAVE_DETECT;
+
+ /* Detect invisible traps */
+ if (c_ptr->t_idx != 0)
+ {
+ /* Hack -- Remember detected traps */
+ c_ptr->info |= (CAVE_MARK);
+
+ /* Pick a trap */
+ pick_trap(y, x);
+
+ /* Obvious */
+ detect = TRUE;
+ }
+ }
+ }
+
+ /* Describe */
+ if (detect)
+ {
+ msg_print("You sense the presence of traps!");
+ }
+
+ /*
+ * This reveals un-identified trap detection items,
+ * but so does leaving/entering trap-detected areas...
+ * There are a couple of possible solutions:
+ * (1) Immediately self-id such items (i.e. always returns TRUE)
+ * (2) add another parameter to function which tells if unaware
+ * item is used for trap detection, and if it is the case,
+ * do two-pass scanning, first scanning for traps if an unaware
+ * item is used and return FALSE there are none,
+ * followed by current implementation --pelpel
+ */
+ p_ptr->redraw |= (PR_DTRAP);
+
+ /* Result -- see my comment above -- pelpel */
+ /* return (detect); */
+ return (TRUE);
+}
+
+
+
+/*
+ * Detect all doors on current panel
+ */
+bool_ detect_doors(int rad)
+{
+ int y, x;
+
+ bool_ detect = FALSE;
+
+ cave_type *c_ptr;
+
+
+ /* Scan the panel */
+ for (y = p_ptr->py - rad; y <= p_ptr->py + rad; y++)
+ {
+ for (x = p_ptr->px - rad; x <= p_ptr->px + rad; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (distance(p_ptr->py, p_ptr->px, y, x) > rad) continue;
+
+ c_ptr = &cave[y][x];
+
+ /* Detect secret doors */
+ if (c_ptr->feat == FEAT_SECRET)
+ {
+ /* Remove feature mimics */
+ cave[y][x].mimic = 0;
+
+ /* Pick a door XXX XXX XXX */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
+ }
+
+ /* Detect doors */
+ if (((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL)) ||
+ ((c_ptr->feat == FEAT_OPEN) ||
+ (c_ptr->feat == FEAT_BROKEN)))
+ {
+ /* Hack -- Memorize */
+ c_ptr->info |= (CAVE_MARK);
+
+ /* Reveal it */
+ /* c_ptr->mimic = 0; */
+
+ /* Redraw */
+ lite_spot(y, x);
+
+ /* Obvious */
+ detect = TRUE;
+ }
+ }
+ }
+
+ /* Describe */
+ if (detect)
+ {
+ msg_print("You sense the presence of doors!");
+ }
+
+ /* Result */
+ return (detect);
+}
+
+
+/*
+ * Detect all stairs on current panel
+ */
+bool_ detect_stairs(int rad)
+{
+ int y, x;
+
+ bool_ detect = FALSE;
+
+ cave_type *c_ptr;
+
+
+ /* Scan the panel */
+ for (y = p_ptr->py - rad; y <= p_ptr->py + rad; y++)
+ {
+ for (x = p_ptr->px - rad; x <= p_ptr->px + rad; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (distance(p_ptr->py, p_ptr->px, y, x) > rad) continue;
+
+ c_ptr = &cave[y][x];
+
+ /* Detect stairs */
+ if ((c_ptr->feat == FEAT_LESS) ||
+ (c_ptr->feat == FEAT_MORE) ||
+ (c_ptr->feat == FEAT_SHAFT_DOWN) ||
+ (c_ptr->feat == FEAT_SHAFT_UP) ||
+ (c_ptr->feat == FEAT_WAY_LESS) ||
+ (c_ptr->feat == FEAT_WAY_MORE))
+ {
+ /* Hack -- Memorize */
+ c_ptr->info |= (CAVE_MARK);
+
+ /* Redraw */
+ lite_spot(y, x);
+
+ /* Obvious */
+ detect = TRUE;
+ }
+ }
+ }
+
+ /* Describe */
+ if (detect)
+ {
+ msg_print("You sense the presence of ways out of this area!");
+ }
+
+ /* Result */
+ return (detect);
+}
+
+
+/*
+ * Detect any treasure on the current panel
+ */
+bool_ detect_treasure(int rad)
+{
+ int y, x;
+
+ bool_ detect = FALSE;
+
+ cave_type *c_ptr;
+
+
+ /* Scan the current panel */
+ for (y = p_ptr->py - rad; y <= p_ptr->py + rad; y++)
+ {
+ for (x = p_ptr->px - rad; x <= p_ptr->px + rad; x++)
+ {
+ if (!in_bounds(y, x)) continue;
+
+ if (distance(p_ptr->py, p_ptr->px, y, x) > rad) continue;
+
+ c_ptr = &cave[y][x];
+
+ /* Notice embedded gold */
+ if ((c_ptr->feat == FEAT_MAGMA_H) ||
+ (c_ptr->feat == FEAT_QUARTZ_H))
+ {
+ /* Expose the gold */
+ cave_set_feat(y, x, c_ptr->feat + 0x02);
+ }
+ else if (c_ptr->feat == FEAT_SANDWALL_H)
+ {
+ /* Expose the gold */
+ cave_set_feat(y, x, FEAT_SANDWALL_K);
+ }
+
+ /* Magma/Quartz + Known Gold */
+ if ((c_ptr->feat == FEAT_MAGMA_K) ||
+ (c_ptr->feat == FEAT_QUARTZ_K) ||
+ (c_ptr->feat == FEAT_SANDWALL_K))
+ {
+ /* Hack -- Memorize */
+ c_ptr->info |= (CAVE_MARK);
+
+ /* Redraw */
+ lite_spot(y, x);
+
+ /* Detect */
+ detect = TRUE;
+ }
+ }
+ }
+
+ /* Describe */
+ if (detect)
+ {
+ msg_print("You sense the presence of buried treasure!");
+ }
+
+
+
+ /* Result */
+ return (detect);
+}
+
+
+
+/*
+ * Detect all "gold" objects on the current panel
+ */
+bool_ hack_no_detect_message = FALSE;
+bool_ detect_objects_gold(int rad)
+{
+ int i, y, x;
+
+ bool_ detect = FALSE;
+
+
+ /* Scan objects */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ /* Skip dead objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Skip held objects */
+ if (o_ptr->held_m_idx)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[o_ptr->held_m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ if (!(r_ptr->flags9 & RF9_MIMIC)) continue;
+ else
+ {
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+ }
+ }
+ else
+ {
+ /* Location */
+ y = o_ptr->iy;
+ x = o_ptr->ix;
+ }
+
+ /* Only detect nearby objects */
+ if (distance(p_ptr->py, p_ptr->px, y, x) > rad) continue;
+
+ /* Detect "gold" objects */
+ if (o_ptr->tval == TV_GOLD)
+ {
+ /* Hack -- memorize it */
+ o_ptr->marked = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ detect = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (detect && (!hack_no_detect_message))
+ {
+ msg_print("You sense the presence of treasure!");
+ }
+
+ if (detect_monsters_string("$", rad))
+ {
+ detect = TRUE;
+ }
+
+ /* Result */
+ return (detect);
+}
+
+
+/*
+ * Detect all "normal" objects on the current panel
+ */
+bool_ detect_objects_normal(int rad)
+{
+ int i, y, x;
+
+ bool_ detect = FALSE;
+
+
+ /* Scan objects */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ /* Skip dead objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Skip held objects */
+ if (o_ptr->held_m_idx)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[o_ptr->held_m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ if (!(r_ptr->flags9 & RF9_MIMIC)) continue;
+ else
+ {
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+ }
+ }
+ else
+ {
+ /* Location */
+ y = o_ptr->iy;
+ x = o_ptr->ix;
+ }
+
+ /* Only detect nearby objects */
+ if (distance(p_ptr->py, p_ptr->px, y, x) > rad) continue;
+
+ /* Detect "real" objects */
+ if (o_ptr->tval != TV_GOLD)
+ {
+ /* Hack -- memorize it */
+ o_ptr->marked = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ detect = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (detect && (!hack_no_detect_message))
+ {
+ msg_print("You sense the presence of objects!");
+ }
+
+ if (detect_monsters_string("!=?|", rad))
+ {
+ detect = TRUE;
+ }
+
+ /* Result */
+ return (detect);
+}
+
+
+/*
+ * Detect all "magic" objects on the current panel.
+ *
+ * This will light up all spaces with "magic" items, including artifacts,
+ * ego-items, potions, scrolls, books, rods, wands, staves, amulets, rings,
+ * and "enchanted" items of the "good" variety.
+ *
+ * It can probably be argued that this function is now too powerful.
+ */
+bool_ detect_objects_magic(int rad)
+{
+ int i, y, x, tv;
+
+ bool_ detect = FALSE;
+
+
+ /* Scan all objects */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
+
+ /* Skip dead objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Skip held objects */
+ if (o_ptr->held_m_idx)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[o_ptr->held_m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ if (!(r_ptr->flags9 & RF9_MIMIC)) continue;
+ else
+ {
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+ }
+ }
+ else
+ {
+ /* Location */
+ y = o_ptr->iy;
+ x = o_ptr->ix;
+ }
+
+ /* Only detect nearby objects */
+ if (distance(p_ptr->py, p_ptr->px, y, x) > rad) continue;
+
+ /* Examine the tval */
+ tv = o_ptr->tval;
+
+ /* Artifacts, misc magic items, or enchanted wearables */
+ if (artifact_p(o_ptr) || ego_item_p(o_ptr) || o_ptr->art_name ||
+ (tv == TV_AMULET) || (tv == TV_RING) || (tv == TV_BATERIE) ||
+ (tv == TV_STAFF) || (tv == TV_WAND) || (tv == TV_ROD) || (tv == TV_ROD_MAIN) ||
+ (tv == TV_SCROLL) || (tv == TV_POTION) || (tv == TV_POTION2) ||
+ (tv == TV_DAEMON_BOOK) ||
+ (tv == TV_SYMBIOTIC_BOOK) || (tv == TV_MUSIC_BOOK) ||
+ ((o_ptr->to_a > 0) || (o_ptr->to_h + o_ptr->to_d > 0)))
+ {
+ /* Memorize the item */
+ o_ptr->marked = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ detect = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (detect)
+ {
+ msg_print("You sense the presence of magic objects!");
+ }
+
+ /* Return result */
+ return (detect);
+}
+
+
+/*
+ * Detect all "normal" monsters on the current panel
+ */
+bool_ detect_monsters_normal(int rad)
+{
+ int i, y, x;
+
+ bool_ flag = FALSE;
+
+
+ /* Scan monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Only detect nearby monsters */
+ if (m_ptr->cdis > rad) continue;
+
+ /* Detect all non-invisible monsters */
+ if ((!(r_ptr->flags2 & (RF2_INVISIBLE))) ||
+ p_ptr->see_inv || p_ptr->tim_invis)
+ {
+ /* Repair visibility later */
+ repair_monsters = TRUE;
+
+ /* Hack -- Detect monster */
+ m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
+
+ /* Hack -- See monster */
+ m_ptr->ml = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ flag = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (flag)
+ {
+ /* Describe result */
+ msg_print("You sense the presence of monsters!");
+ }
+
+ /* Result */
+ return (flag);
+}
+
+
+/*
+ * Detect all "invisible" monsters on current panel
+ */
+bool_ detect_monsters_invis(int rad)
+{
+ int i, y, x;
+ bool_ flag = FALSE;
+
+ /* Scan monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Only detect nearby monsters */
+ if (m_ptr->cdis > rad) continue;
+
+ /* Detect invisible monsters */
+ if (r_ptr->flags2 & (RF2_INVISIBLE))
+ {
+ /* Take note that they are invisible */
+ r_ptr->r_flags2 |= (RF2_INVISIBLE);
+
+ /* Update monster recall window */
+ if (monster_race_idx == m_ptr->r_idx)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+ }
+
+ /* Repair visibility later */
+ repair_monsters = TRUE;
+
+ /* Hack -- Detect monster */
+ m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
+
+ /* Hack -- See monster */
+ m_ptr->ml = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ flag = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (flag)
+ {
+ /* Describe result */
+ msg_print("You sense the presence of invisible creatures!");
+ }
+
+ /* Result */
+ return (flag);
+}
+
+
+
+/*
+ * Detect all "evil" monsters on current panel
+ */
+bool_ detect_monsters_evil(int rad)
+{
+ int i, y, x;
+ bool_ flag = FALSE;
+
+
+ /* Scan monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Only detect nearby monsters */
+ if (m_ptr->cdis > rad) continue;
+
+ /* Detect evil monsters */
+ if (r_ptr->flags3 & (RF3_EVIL))
+ {
+ /* Take note that they are evil */
+ r_ptr->r_flags3 |= (RF3_EVIL);
+
+ /* Update monster recall window */
+ if (monster_race_idx == m_ptr->r_idx)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+ }
+
+ /* Repair visibility later */
+ repair_monsters = TRUE;
+
+ /* Hack -- Detect monster */
+ m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
+
+ /* Hack -- See monster */
+ m_ptr->ml = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ flag = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (flag)
+ {
+ /* Describe result */
+ msg_print("You sense the presence of evil creatures!");
+ }
+
+ /* Result */
+ return (flag);
+}
+
+
+
+
+/*
+ * Detect all (string) monsters on current panel
+ */
+bool_ detect_monsters_string(cptr chars, int rad)
+{
+ int i, y, x;
+ bool_ flag = FALSE;
+
+
+ /* Scan monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Only detect nearby monsters */
+ if (m_ptr->cdis > rad) continue;
+
+ /* Detect evil monsters */
+ if (strchr(chars, r_ptr->d_char))
+ {
+
+ /* Update monster recall window */
+ if (monster_race_idx == m_ptr->r_idx)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+ }
+
+ /* Repair visibility later */
+ repair_monsters = TRUE;
+
+ /* Hack -- Detect monster */
+ m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
+
+ /* Hack -- See monster */
+ m_ptr->ml = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ flag = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (flag)
+ {
+ /* Describe result */
+ msg_print("You sense the presence of monsters!");
+ }
+
+ /* Result */
+ return (flag);
+}
+
+
+/*
+ * A "generic" detect monsters routine, tagged to flags3
+ */
+bool_ detect_monsters_xxx(u32b match_flag, int rad)
+{
+ int i, y, x;
+ bool_ flag = FALSE;
+ cptr desc_monsters = "weird monsters";
+
+
+ /* Scan monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Only detect nearby monsters */
+ if (m_ptr->cdis > rad) continue;
+
+ /* Detect evil monsters */
+ if (r_ptr->flags3 & (match_flag))
+ {
+ /* Take note that they are something */
+ r_ptr->r_flags3 |= (match_flag);
+
+ /* Update monster recall window */
+ if (monster_race_idx == m_ptr->r_idx)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+ }
+
+ /* Repair visibility later */
+ repair_monsters = TRUE;
+
+ /* Hack -- Detect monster */
+ m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
+
+ /* Hack -- See monster */
+ m_ptr->ml = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ flag = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (flag)
+ {
+ switch (match_flag)
+ {
+ case RF3_DEMON:
+ desc_monsters = "demons";
+ break;
+ case RF3_UNDEAD:
+ desc_monsters = "the undead";
+ break;
+ case RF3_GOOD:
+ desc_monsters = "good";
+ break;
+ }
+
+ /* Describe result */
+ msg_format("You sense the presence of %s!", desc_monsters);
+ msg_print(NULL);
+ }
+
+ /* Result */
+ return (flag);
+}
+
+/* Detect good monsters */
+bool_ detect_monsters_good(int rad)
+{
+ return (detect_monsters_xxx(RF3_GOOD, rad));
+}
+
+
+/*
+ * Detect everything
+ */
+bool_ detect_all(int rad)
+{
+ bool_ detect = FALSE;
+
+ /* Detect everything */
+ if (detect_traps(rad)) detect = TRUE;
+ if (detect_doors(rad)) detect = TRUE;
+ if (detect_stairs(rad)) detect = TRUE;
+ if (detect_treasure(rad)) detect = TRUE;
+ if (detect_objects_gold(rad)) detect = TRUE;
+ if (detect_objects_normal(rad)) detect = TRUE;
+ if (detect_monsters_invis(rad)) detect = TRUE;
+ if (detect_monsters_normal(rad)) detect = TRUE;
+
+ /* Result */
+ return (detect);
+}
+
+
+
+/*
+ * Create stairs at the player location
+ */
+void stair_creation(void)
+{
+ /* XXX XXX XXX */
+ if (!cave_valid_bold(p_ptr->py, p_ptr->px))
+ {
+ msg_print("The object resists the spell.");
+ return;
+ }
+
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ msg_print("No stair creation in non dungeons...");
+ return;
+ }
+
+ if (dungeon_flags2 & DF2_SPECIAL)
+ {
+ msg_print("No stair creation on special levels...");
+ return;
+ }
+
+ /* XXX XXX XXX */
+ delete_object(p_ptr->py, p_ptr->px);
+
+ /* Create a staircase */
+ if (p_ptr->inside_arena || p_ptr->inside_quest)
+ {
+ /* arena or quest */
+ msg_print("There is no effect!");
+ }
+ else if (!dun_level)
+ {
+ /* Town/wilderness */
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_MORE);
+ }
+ else if (is_quest(dun_level) || (dun_level >= MAX_DEPTH - 1))
+ {
+ /* Quest level */
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_LESS);
+ }
+ else if (rand_int(100) < 50)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_MORE);
+ }
+ else
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_LESS);
+ }
+}
+
+
+
+
+/*
+ * Hook to specify "weapon"
+ */
+static bool_ item_tester_hook_weapon(object_type *o_ptr)
+{
+ switch (o_ptr->tval)
+ {
+ case TV_MSTAFF:
+ case TV_BOOMERANG:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_BOW:
+ case TV_BOLT:
+ case TV_ARROW:
+ case TV_SHOT:
+ {
+ return (TRUE);
+ }
+ case TV_DAEMON_BOOK:
+ {
+ switch (o_ptr->sval)
+ {
+ case SV_DEMONBLADE:
+ {
+ return (TRUE);
+ }
+ }
+ }
+ }
+
+ return (FALSE);
+}
+
+
+/*
+ * Hook to specify "armour"
+ */
+bool_ item_tester_hook_armour(object_type *o_ptr)
+{
+ switch (o_ptr->tval)
+ {
+ case TV_DRAG_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_SOFT_ARMOR:
+ case TV_SHIELD:
+ case TV_CLOAK:
+ case TV_CROWN:
+ case TV_HELM:
+ case TV_BOOTS:
+ case TV_GLOVES:
+ {
+ return (TRUE);
+ }
+ case TV_DAEMON_BOOK:
+ {
+ switch (o_ptr->sval)
+ {
+ case SV_DEMONHORN:
+ case SV_DEMONSHIELD:
+ {
+ return (TRUE);
+ }
+ }
+ }
+ }
+
+ return (FALSE);
+}
+
+
+/*
+ * Check if an object is weapon or armour (but not arrow, bolt, or shot)
+ */
+bool_ item_tester_hook_weapon_armour(object_type *o_ptr)
+{
+ return (item_tester_hook_weapon(o_ptr) ||
+ item_tester_hook_armour(o_ptr));
+}
+
+/*
+ * Check if an object is artifactable
+ */
+bool_ item_tester_hook_artifactable(object_type *o_ptr)
+{
+ return ((item_tester_hook_weapon(o_ptr) ||
+ item_tester_hook_armour(o_ptr) ||
+ (o_ptr->tval == TV_DIGGING) ||
+ (o_ptr->tval == TV_RING) || (o_ptr->tval == TV_AMULET))
+ /* be nice: allow only normal items */
+ && (!artifact_p(o_ptr)) && (!ego_item_p(o_ptr)));
+}
+
+
+/*
+ * Enchants a plus onto an item. -RAK-
+ *
+ * Revamped! Now takes item pointer, number of times to try enchanting,
+ * and a flag of what to try enchanting. Artifacts resist enchantment
+ * some of the time, and successful enchantment to at least +0 might
+ * break a curse on the item. -CFT-
+ *
+ * Note that an item can technically be enchanted all the way to +15 if
+ * you wait a very, very, long time. Going from +9 to +10 only works
+ * about 5% of the time, and from +10 to +11 only about 1% of the time.
+ *
+ * Note that this function can now be used on "piles" of items, and
+ * the larger the pile, the lower the chance of success.
+ */
+bool_ enchant(object_type *o_ptr, int n, int eflag)
+{
+ int i, chance, prob;
+ bool_ res = FALSE;
+ bool_ a = (artifact_p(o_ptr) || o_ptr->art_name);
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Large piles resist enchantment */
+ prob = o_ptr->number * 100;
+
+ /* Missiles are easy to enchant */
+ if ((o_ptr->tval == TV_BOLT) ||
+ (o_ptr->tval == TV_ARROW) ||
+ (o_ptr->tval == TV_SHOT))
+ {
+ prob = prob / 20;
+ }
+
+ /* Try "n" times */
+ for (i = 0; i < n; i++)
+ {
+ /* Hack -- Roll for pile resistance */
+ if (rand_int(prob) >= 100) continue;
+
+ /* Enchant to hit */
+ if (eflag & (ENCH_TOHIT))
+ {
+ if (o_ptr->to_h < 0) chance = 0;
+ else if (o_ptr->to_h > 15) chance = 1000;
+ else chance = enchant_table[o_ptr->to_h];
+
+ if ((randint(1000) > chance) && (!a || (rand_int(100) < 50)))
+ {
+ o_ptr->to_h++;
+ res = TRUE;
+
+ /* only when you get it above -1 -CFT */
+ if (cursed_p(o_ptr) &&
+ (!(f3 & (TR3_PERMA_CURSE))) &&
+ (o_ptr->to_h >= 0) && (rand_int(100) < 25))
+ {
+ msg_print("The curse is broken!");
+ o_ptr->ident &= ~(IDENT_CURSED);
+ o_ptr->ident |= (IDENT_SENSE);
+
+ if (o_ptr->art_flags3 & (TR3_CURSED))
+ o_ptr->art_flags3 &= ~(TR3_CURSED);
+ if (o_ptr->art_flags3 & (TR3_HEAVY_CURSE))
+ o_ptr->art_flags3 &= ~(TR3_HEAVY_CURSE);
+
+ o_ptr->sense = SENSE_UNCURSED;
+ }
+ }
+ }
+
+ /* Enchant to damage */
+ if (eflag & (ENCH_TODAM))
+ {
+ if (o_ptr->to_d < 0) chance = 0;
+ else if (o_ptr->to_d > 15) chance = 1000;
+ else chance = enchant_table[o_ptr->to_d];
+
+ if ((randint(1000) > chance) && (!a || (rand_int(100) < 50)))
+ {
+ o_ptr->to_d++;
+ res = TRUE;
+
+ /* only when you get it above -1 -CFT */
+ if (cursed_p(o_ptr) &&
+ (!(f3 & (TR3_PERMA_CURSE))) &&
+ (o_ptr->to_d >= 0) && (rand_int(100) < 25))
+ {
+ msg_print("The curse is broken!");
+ o_ptr->ident &= ~(IDENT_CURSED);
+ o_ptr->ident |= (IDENT_SENSE);
+
+ if (o_ptr->art_flags3 & (TR3_CURSED))
+ o_ptr->art_flags3 &= ~(TR3_CURSED);
+ if (o_ptr->art_flags3 & (TR3_HEAVY_CURSE))
+ o_ptr->art_flags3 &= ~(TR3_HEAVY_CURSE);
+
+ o_ptr->sense = SENSE_UNCURSED;
+ }
+ }
+ }
+
+
+ /* Enchant to damage */
+ if (eflag & (ENCH_PVAL))
+ {
+ if (o_ptr->pval < 0) chance = 0;
+ else if (o_ptr->pval > 6) chance = 1000;
+ else chance = enchant_table[o_ptr->pval * 2];
+
+ if ((randint(1000) > chance) && (!a || (rand_int(100) < 50)))
+ {
+ o_ptr->pval++;
+ res = TRUE;
+
+ /* only when you get it above -1 -CFT */
+ if (cursed_p(o_ptr) &&
+ (!(f3 & (TR3_PERMA_CURSE))) &&
+ (o_ptr->pval >= 0) && (rand_int(100) < 25))
+ {
+ msg_print("The curse is broken!");
+ o_ptr->ident &= ~(IDENT_CURSED);
+ o_ptr->ident |= (IDENT_SENSE);
+
+ if (o_ptr->art_flags3 & (TR3_CURSED))
+ o_ptr->art_flags3 &= ~(TR3_CURSED);
+ if (o_ptr->art_flags3 & (TR3_HEAVY_CURSE))
+ o_ptr->art_flags3 &= ~(TR3_HEAVY_CURSE);
+
+ o_ptr->sense = SENSE_UNCURSED;
+ }
+ }
+ }
+
+ /* Enchant to armor class */
+ if (eflag & (ENCH_TOAC))
+ {
+ if (o_ptr->to_a < 0) chance = 0;
+ else if (o_ptr->to_a > 15) chance = 1000;
+ else chance = enchant_table[o_ptr->to_a];
+
+ if ((randint(1000) > chance) && (!a || (rand_int(100) < 50)))
+ {
+ o_ptr->to_a++;
+ res = TRUE;
+
+ /* only when you get it above -1 -CFT */
+ if (cursed_p(o_ptr) &&
+ (!(f3 & (TR3_PERMA_CURSE))) &&
+ (o_ptr->to_a >= 0) && (rand_int(100) < 25))
+ {
+ msg_print("The curse is broken!");
+ o_ptr->ident &= ~(IDENT_CURSED);
+ o_ptr->ident |= (IDENT_SENSE);
+
+ if (o_ptr->art_flags3 & (TR3_CURSED))
+ o_ptr->art_flags3 &= ~(TR3_CURSED);
+ if (o_ptr->art_flags3 & (TR3_HEAVY_CURSE))
+ o_ptr->art_flags3 &= ~(TR3_HEAVY_CURSE);
+
+ o_ptr->sense = SENSE_UNCURSED;
+ }
+ }
+ }
+ }
+
+ /* Failure */
+ if (!res) return (FALSE);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+
+/*
+ * Enchant an item (in the inventory or on the floor)
+ * Note that "num_ac" requires armour, else weapon
+ * Returns TRUE if attempted, FALSE if cancelled
+ */
+bool_ enchant_spell(int num_hit, int num_dam, int num_ac, int num_pval)
+{
+ int item;
+ bool_ okay = FALSE;
+ object_type *o_ptr;
+ char o_name[80];
+ cptr q, s;
+
+
+ /* Assume enchant weapon */
+ item_tester_hook = item_tester_hook_weapon;
+
+ /* Enchant armor if requested */
+ if (num_ac) item_tester_hook = item_tester_hook_armour;
+
+ /* Get an item */
+ q = "Enchant which item? ";
+ s = "You have nothing to enchant.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return (FALSE);
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Description */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ /* Describe */
+ msg_format("%s %s glow%s brightly!",
+ ((item >= 0) ? "Your" : "The"), o_name,
+ ((o_ptr->number > 1) ? "" : "s"));
+
+ /* Enchant */
+ if (enchant(o_ptr, num_hit, ENCH_TOHIT)) okay = TRUE;
+ if (enchant(o_ptr, num_dam, ENCH_TODAM)) okay = TRUE;
+ if (enchant(o_ptr, num_ac, ENCH_TOAC)) okay = TRUE;
+ if (enchant(o_ptr, num_pval, ENCH_PVAL)) okay = TRUE;
+
+ /* Failure */
+ if (!okay)
+ {
+ /* Flush */
+ if (flush_failure) flush();
+
+ /* Message */
+ msg_print("The enchantment failed.");
+ }
+
+ /* Something happened */
+ return (TRUE);
+}
+
+void curse_artifact(object_type * o_ptr)
+{
+ if (o_ptr->pval) o_ptr->pval = 0 - ((o_ptr->pval) + randint(4));
+ if (o_ptr->to_a) o_ptr->to_a = 0 - ((o_ptr->to_a) + randint(4));
+ if (o_ptr->to_h) o_ptr->to_h = 0 - ((o_ptr->to_h) + randint(4));
+ if (o_ptr->to_d) o_ptr->to_d = 0 - ((o_ptr->to_d) + randint(4));
+ o_ptr->art_flags3 |= ( TR3_HEAVY_CURSE | TR3_CURSED );
+ if (randint(3) == 1) o_ptr-> art_flags3 |= TR3_TY_CURSE;
+ if (randint(2) == 1) o_ptr-> art_flags3 |= TR3_AGGRAVATE;
+ if (randint(3) == 1) o_ptr-> art_flags3 |= TR3_DRAIN_EXP;
+ if (randint(3) == 1) o_ptr-> art_flags4 |= TR4_BLACK_BREATH;
+ if (randint(2) == 1) o_ptr-> art_flags3 |= TR3_TELEPORT;
+ else if (randint(3) == 1) o_ptr->art_flags3 |= TR3_NO_TELE;
+ o_ptr->ident |= IDENT_CURSED;
+}
+
+
+/*
+ * Should be merged with randart code.
+ * looks like BASIC coder's work...
+ */
+void random_plus(object_type * o_ptr, bool_ is_scroll)
+{
+ int this_type = (o_ptr->tval < TV_BOOTS ? 23 : 19);
+
+ if (artifact_bias == BIAS_WARRIOR)
+ {
+ if (!(o_ptr->art_flags1 & TR1_STR))
+ {
+ o_ptr->art_flags1 |= TR1_STR;
+ if (randint(2) == 1) return ; /* 50% chance of being a "free" power */
+ }
+
+ if (!(o_ptr->art_flags1 & TR1_CON))
+ {
+ o_ptr->art_flags1 |= TR1_CON;
+ if (randint(2) == 1) return;
+ }
+
+ if (!(o_ptr->art_flags1 & TR1_DEX))
+ {
+ o_ptr->art_flags1 |= TR1_DEX;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_MAGE)
+ {
+ if (!(o_ptr->art_flags1 & TR1_INT))
+ {
+ o_ptr->art_flags1 |= TR1_INT;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_PRIESTLY)
+ {
+ if (!(o_ptr->art_flags1 & TR1_WIS))
+ {
+ o_ptr->art_flags1 |= TR1_WIS;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_RANGER)
+ {
+ if (!(o_ptr->art_flags1 & TR1_CON))
+ {
+ o_ptr->art_flags1 |= TR1_CON;
+ if (randint(2) == 1) return ; /* 50% chance of being a "free" power */
+ }
+
+ if (!(o_ptr->art_flags1 & TR1_DEX))
+ {
+ o_ptr->art_flags1 |= TR1_DEX;
+ if (randint(2) == 1) return;
+ }
+
+ if (!(o_ptr->art_flags1 & TR1_STR))
+ {
+ o_ptr->art_flags1 |= TR1_STR;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_ROGUE)
+ {
+ if (!(o_ptr->art_flags1 & TR1_STEALTH))
+ {
+ o_ptr->art_flags1 |= TR1_STEALTH;
+ if (randint(2) == 1) return;
+ }
+ if (!(o_ptr->art_flags1 & TR1_SEARCH))
+ {
+ o_ptr->art_flags1 |= TR1_SEARCH;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_STR)
+ {
+ if (!(o_ptr->art_flags1 & TR1_STR))
+ {
+ o_ptr->art_flags1 |= TR1_STR;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_WIS)
+ {
+ if (!(o_ptr->art_flags1 & TR1_WIS))
+ {
+ o_ptr->art_flags1 |= TR1_WIS;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_INT)
+ {
+ if (!(o_ptr->art_flags1 & TR1_INT))
+ {
+ o_ptr->art_flags1 |= TR1_INT;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_DEX)
+ {
+ if (!(o_ptr->art_flags1 & TR1_DEX))
+ {
+ o_ptr->art_flags1 |= TR1_DEX;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_CON)
+ {
+ if (!(o_ptr->art_flags1 & TR1_CON))
+ {
+ o_ptr->art_flags1 |= TR1_CON;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_CHR)
+ {
+ if (!(o_ptr->art_flags1 & TR1_CHR))
+ {
+ o_ptr->art_flags1 |= TR1_CHR;
+ if (randint(2) == 1) return;
+ }
+ }
+
+
+ switch (randint(this_type))
+ {
+ case 1:
+ case 2:
+ o_ptr->art_flags1 |= TR1_STR;
+ /* if (is_scroll) msg_print("It makes you feel strong!"); */
+ if (!(artifact_bias) && randint(13) != 1)
+ artifact_bias = BIAS_STR;
+ else if (!(artifact_bias) && randint(7) == 1)
+ artifact_bias = BIAS_WARRIOR;
+ break;
+ case 3:
+ case 4:
+ o_ptr->art_flags1 |= TR1_INT;
+ /* if (is_scroll) msg_print("It makes you feel smart!"); */
+ if (!(artifact_bias) && randint(13) != 1)
+ artifact_bias = BIAS_INT;
+ else if (!(artifact_bias) && randint(7) == 1)
+ artifact_bias = BIAS_MAGE;
+ break;
+ case 5:
+ case 6:
+ o_ptr->art_flags1 |= TR1_WIS;
+ /* if (is_scroll) msg_print("It makes you feel wise!"); */
+ if (!(artifact_bias) && randint(13) != 1)
+ artifact_bias = BIAS_WIS;
+ else if (!(artifact_bias) && randint(7) == 1)
+ artifact_bias = BIAS_PRIESTLY;
+ break;
+ case 7:
+ case 8:
+ o_ptr->art_flags1 |= TR1_DEX;
+ /* if (is_scroll) msg_print("It makes you feel nimble!"); */
+ if (!(artifact_bias) && randint(13) != 1)
+ artifact_bias = BIAS_DEX;
+ else if (!(artifact_bias) && randint(7) == 1)
+ artifact_bias = BIAS_ROGUE;
+ break;
+ case 9:
+ case 10:
+ o_ptr->art_flags1 |= TR1_CON;
+ /* if (is_scroll) msg_print("It makes you feel healthy!"); */
+ if (!(artifact_bias) && randint(13) != 1)
+ artifact_bias = BIAS_CON;
+ else if (!(artifact_bias) && randint(9) == 1)
+ artifact_bias = BIAS_RANGER;
+ break;
+ case 11:
+ case 12:
+ o_ptr->art_flags1 |= TR1_CHR;
+ /* if (is_scroll) msg_print("It makes you look great!"); */
+ if (!(artifact_bias) && randint(13) != 1)
+ artifact_bias = BIAS_CHR;
+ break;
+ case 13:
+ case 14:
+ o_ptr->art_flags1 |= TR1_STEALTH;
+ /* if (is_scroll) msg_print("It looks muffled."); */
+ if (!(artifact_bias) && randint(3) == 1)
+ artifact_bias = BIAS_ROGUE;
+ break;
+ case 15:
+ case 16:
+ o_ptr->art_flags1 |= TR1_SEARCH;
+ /* if (is_scroll) msg_print("It makes you see better."); */
+ if (!(artifact_bias) && randint(9) == 1)
+ artifact_bias = BIAS_RANGER;
+ break;
+ case 17:
+ case 18:
+ o_ptr->art_flags1 |= TR1_INFRA;
+ /* if (is_scroll) msg_print("It makes you see tiny red animals.");*/
+ break;
+ case 19:
+ o_ptr->art_flags1 |= TR1_SPEED;
+ /* if (is_scroll) msg_print("It makes you move faster!"); */
+ if (!(artifact_bias) && randint(11) == 1)
+ artifact_bias = BIAS_ROGUE;
+ break;
+ case 20:
+ case 21:
+ o_ptr->art_flags1 |= TR1_TUNNEL;
+ /* if (is_scroll) msg_print("Gravel flies from it!"); */
+ break;
+ case 22:
+ case 23:
+ if (o_ptr->tval == TV_BOW) random_plus(o_ptr, is_scroll);
+ else
+ {
+ o_ptr->art_flags1 |= TR1_BLOWS;
+ /* if (is_scroll) msg_print("It seems faster!"); */
+ if (!(artifact_bias) && randint(11) == 1)
+ artifact_bias = BIAS_WARRIOR;
+ }
+ break;
+ }
+}
+
+
+void random_resistance (object_type * o_ptr, bool_ is_scroll, int specific)
+{
+ /* To avoid a number of possible bugs */
+ if (!specific)
+ {
+ if (artifact_bias == BIAS_ACID)
+ {
+ if (!(o_ptr->art_flags2 & TR2_RES_ACID))
+ {
+ o_ptr->art_flags2 |= TR2_RES_ACID;
+ if (rand_int(2) == 0) return;
+ }
+ if (rand_int(BIAS_LUCK) == 0 && !(o_ptr->art_flags2 & TR2_IM_ACID))
+ {
+ o_ptr->art_flags2 |= TR2_IM_ACID;
+ if (rand_int(2) == 0) return;
+ }
+ }
+ else if (artifact_bias == BIAS_ELEC)
+ {
+ if (!(o_ptr->art_flags2 & TR2_RES_ELEC))
+ {
+ o_ptr->art_flags2 |= TR2_RES_ELEC;
+ if (rand_int(2) == 0) return;
+ }
+ if (o_ptr->tval >= TV_CLOAK && o_ptr->tval <= TV_HARD_ARMOR &&
+ !(o_ptr->art_flags3 & TR3_SH_ELEC))
+ {
+ o_ptr->art_flags2 |= TR3_SH_ELEC;
+ if (rand_int(2) == 0) return;
+ }
+ if (rand_int(BIAS_LUCK) == 0 && !(o_ptr->art_flags2 & TR2_IM_ELEC))
+ {
+ o_ptr->art_flags2 |= TR2_IM_ELEC;
+ if (rand_int(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_FIRE)
+ {
+ if (!(o_ptr->art_flags2 & TR2_RES_FIRE))
+ {
+ o_ptr->art_flags2 |= TR2_RES_FIRE;
+ if (rand_int(2) == 0) return;
+ }
+ if (o_ptr->tval >= TV_CLOAK && o_ptr->tval <= TV_HARD_ARMOR &&
+ !(o_ptr->art_flags3 & TR3_SH_FIRE))
+ {
+ o_ptr->art_flags2 |= TR3_SH_FIRE;
+ if (rand_int(2) == 0) return;
+ }
+ if (rand_int(BIAS_LUCK) == 0 && !(o_ptr->art_flags2 & TR2_IM_FIRE))
+ {
+ o_ptr->art_flags2 |= TR2_IM_FIRE;
+ if (rand_int(2) == 0) return;
+ }
+ }
+ else if (artifact_bias == BIAS_COLD)
+ {
+ if (!(o_ptr->art_flags2 & TR2_RES_COLD))
+ {
+ o_ptr->art_flags2 |= TR2_RES_COLD;
+ if (rand_int(2) == 0) return;
+ }
+ if (rand_int(BIAS_LUCK) == 0 && !(o_ptr->art_flags2 & TR2_IM_COLD))
+ {
+ o_ptr->art_flags2 |= TR2_IM_COLD;
+ if (rand_int(2) == 0) return;
+ }
+ }
+ else if (artifact_bias == BIAS_POIS)
+ {
+ if (!(o_ptr->art_flags2 & TR2_RES_POIS))
+ {
+ o_ptr->art_flags2 |= TR2_RES_POIS;
+ if (rand_int(2) == 0) return;
+ }
+ }
+ else if (artifact_bias == BIAS_WARRIOR)
+ {
+ if (rand_int(3) && (!(o_ptr->art_flags2 & TR2_RES_FEAR)))
+ {
+ o_ptr->art_flags2 |= TR2_RES_FEAR;
+ if (rand_int(2) == 0) return;
+ }
+ if ((rand_int(3) == 0) && (!(o_ptr->art_flags3 & TR3_NO_MAGIC)))
+ {
+ o_ptr->art_flags3 |= TR3_NO_MAGIC;
+ if (rand_int(2) == 0) return;
+ }
+ }
+ else if (artifact_bias == BIAS_NECROMANTIC)
+ {
+ if (!(o_ptr->art_flags2 & TR2_RES_NETHER))
+ {
+ o_ptr->art_flags2 |= TR2_RES_NETHER;
+ if (rand_int(2) == 0) return;
+ }
+ if (!(o_ptr->art_flags2 & TR2_RES_POIS))
+ {
+ o_ptr->art_flags2 |= TR2_RES_POIS;
+ if (rand_int(2) == 0) return;
+ }
+ if (!(o_ptr->art_flags2 & TR2_RES_DARK))
+ {
+ o_ptr->art_flags2 |= TR2_RES_DARK;
+ if (rand_int(2) == 0) return;
+ }
+ }
+ else if (artifact_bias == BIAS_CHAOS)
+ {
+ if (!(o_ptr->art_flags2 & TR2_RES_CHAOS))
+ {
+ o_ptr->art_flags2 |= TR2_RES_CHAOS;
+ if (rand_int(2) == 0) return;
+ }
+ if (!(o_ptr->art_flags2 & TR2_RES_CONF))
+ {
+ o_ptr->art_flags2 |= TR2_RES_CONF;
+ if (rand_int(2) == 0) return;
+ }
+ if (!(o_ptr->art_flags2 & TR2_RES_DISEN))
+ {
+ o_ptr->art_flags2 |= TR2_RES_DISEN;
+ if (rand_int(2) == 0) return;
+ }
+ }
+ }
+
+ switch (specific ? specific : randint(41))
+ {
+ case 1 :
+ if (randint(WEIRD_LUCK) != 1)
+ random_resistance(o_ptr, is_scroll, specific);
+ else
+ {
+ o_ptr->art_flags2 |= TR2_IM_ACID;
+ /* if (is_scroll) msg_print("It looks totally incorruptible."); */
+ if (!(artifact_bias))
+ artifact_bias = BIAS_ACID;
+ }
+ break;
+ case 2:
+ if (randint(WEIRD_LUCK) != 1)
+ random_resistance(o_ptr, is_scroll, specific);
+ else
+ {
+ o_ptr->art_flags2 |= TR2_IM_ELEC;
+ /* if (is_scroll) msg_print("It looks completely grounded."); */
+ if (!(artifact_bias))
+ artifact_bias = BIAS_ELEC;
+ }
+ break;
+ case 3:
+ if (randint(WEIRD_LUCK) != 1)
+ random_resistance(o_ptr, is_scroll, specific);
+ else
+ {
+ o_ptr->art_flags2 |= TR2_IM_COLD;
+ /* if (is_scroll) msg_print("It feels very warm."); */
+ if (!(artifact_bias))
+ artifact_bias = BIAS_COLD;
+ }
+ break;
+ case 4:
+ if (randint(WEIRD_LUCK) != 1)
+ random_resistance(o_ptr, is_scroll, specific);
+ else
+ {
+ o_ptr->art_flags2 |= TR2_IM_FIRE;
+ /* if (is_scroll) msg_print("It feels very cool."); */
+ if (!(artifact_bias))
+ artifact_bias = BIAS_FIRE;
+ }
+ break;
+ case 5:
+ case 6:
+ case 13:
+ o_ptr->art_flags2 |= TR2_RES_ACID;
+ /* if (is_scroll) msg_print("It makes your stomach rumble."); */
+ if (!(artifact_bias))
+ artifact_bias = BIAS_ACID;
+ break;
+ case 7:
+ case 8:
+ case 14:
+ o_ptr->art_flags2 |= TR2_RES_ELEC;
+ /* if (is_scroll) msg_print("It makes you feel grounded."); */
+ if (!(artifact_bias))
+ artifact_bias = BIAS_ELEC;
+ break;
+ case 9:
+ case 10:
+ case 15:
+ o_ptr->art_flags2 |= TR2_RES_FIRE;
+ /* if (is_scroll) msg_print("It makes you feel cool!");*/
+ if (!(artifact_bias))
+ artifact_bias = BIAS_FIRE;
+ break;
+ case 11:
+ case 12:
+ case 16:
+ o_ptr->art_flags2 |= TR2_RES_COLD;
+ /* if (is_scroll) msg_print("It makes you feel full of hot air!");*/
+ if (!(artifact_bias))
+ artifact_bias = BIAS_COLD;
+ break;
+ case 17:
+ case 18:
+ o_ptr->art_flags2 |= TR2_RES_POIS;
+ /* if (is_scroll) msg_print("It makes breathing easier for you."); */
+ if (!(artifact_bias) && randint(4) != 1)
+ artifact_bias = BIAS_POIS;
+ else if (!(artifact_bias) && randint(2) == 1)
+ artifact_bias = BIAS_NECROMANTIC;
+ else if (!(artifact_bias) && randint(2) == 1)
+ artifact_bias = BIAS_ROGUE;
+ break;
+ case 19:
+ case 20:
+ o_ptr->art_flags2 |= TR2_RES_FEAR;
+ /* if (is_scroll) msg_print("It makes you feel brave!"); */
+ if (!(artifact_bias) && randint(3) == 1)
+ artifact_bias = BIAS_WARRIOR;
+ break;
+ case 21:
+ o_ptr->art_flags2 |= TR2_RES_LITE;
+ /* if (is_scroll) msg_print("It makes everything look darker.");*/
+ break;
+ case 22:
+ o_ptr->art_flags2 |= TR2_RES_DARK;
+ /* if (is_scroll) msg_print("It makes everything look brigher.");*/
+ break;
+ case 23:
+ case 24:
+ o_ptr->art_flags2 |= TR2_RES_BLIND;
+ /* if (is_scroll) msg_print("It makes you feel you are wearing glasses.");*/
+ break;
+ case 25:
+ case 26:
+ o_ptr->art_flags2 |= TR2_RES_CONF;
+ /* if (is_scroll) msg_print("It makes you feel very determined.");*/
+ if (!(artifact_bias) && randint(6) == 1)
+ artifact_bias = BIAS_CHAOS;
+ break;
+ case 27:
+ case 28:
+ o_ptr->art_flags2 |= TR2_RES_SOUND;
+ /* if (is_scroll) msg_print("It makes you feel deaf!");*/
+ break;
+ case 29:
+ case 30:
+ o_ptr->art_flags2 |= TR2_RES_SHARDS;
+ /* if (is_scroll) msg_print("It makes your skin feel thicker.");*/
+ break;
+ case 31:
+ case 32:
+ o_ptr->art_flags2 |= TR2_RES_NETHER;
+ /* if (is_scroll) msg_print("It makes you feel like visiting a graveyard!");*/
+ if (!(artifact_bias) && randint(3) == 1)
+ artifact_bias = BIAS_NECROMANTIC;
+ break;
+ case 33:
+ case 34:
+ o_ptr->art_flags2 |= TR2_RES_NEXUS;
+ /* if (is_scroll) msg_print("It makes you feel normal.");*/
+ break;
+ case 35:
+ case 36:
+ o_ptr->art_flags2 |= TR2_RES_CHAOS;
+ /* if (is_scroll) msg_print("It makes you feel very firm.");*/
+ if (!(artifact_bias) && randint(2) == 1)
+ artifact_bias = BIAS_CHAOS;
+ break;
+ case 37:
+ case 38:
+ o_ptr->art_flags2 |= TR2_RES_DISEN;
+ /* if (is_scroll) msg_print("It is surrounded by a static feeling.");*/
+ break;
+ case 39:
+ if (o_ptr->tval >= TV_CLOAK && o_ptr->tval <= TV_HARD_ARMOR)
+ o_ptr->art_flags3 |= TR3_SH_ELEC;
+ else
+ random_resistance(o_ptr, is_scroll, specific);
+ if (!(artifact_bias))
+ artifact_bias = BIAS_ELEC;
+ break;
+ case 40:
+ if (o_ptr->tval >= TV_CLOAK && o_ptr->tval <= TV_HARD_ARMOR)
+ o_ptr->art_flags3 |= TR3_SH_FIRE;
+ else
+ random_resistance(o_ptr, is_scroll, specific);
+ if (!(artifact_bias))
+ artifact_bias = BIAS_FIRE;
+ break;
+ case 41:
+ if (o_ptr->tval == TV_SHIELD || o_ptr->tval == TV_CLOAK ||
+ o_ptr->tval == TV_HELM || o_ptr->tval == TV_HARD_ARMOR)
+ o_ptr->art_flags2 |= TR2_REFLECT;
+ else
+ random_resistance(o_ptr, is_scroll, specific);
+ break;
+ }
+}
+
+void random_misc(object_type * o_ptr, bool_ is_scroll)
+{
+
+ if (artifact_bias == BIAS_RANGER)
+ {
+ if (!(o_ptr->art_flags2 & TR2_SUST_CON))
+ {
+ o_ptr->art_flags2 |= TR2_SUST_CON;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_STR)
+ {
+ if (!(o_ptr->art_flags2 & TR2_SUST_STR))
+ {
+ o_ptr->art_flags2 |= TR2_SUST_STR;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_WIS)
+ {
+ if (!(o_ptr->art_flags2 & TR2_SUST_WIS))
+ {
+ o_ptr->art_flags2 |= TR2_SUST_WIS;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_INT)
+ {
+ if (!(o_ptr->art_flags2 & TR2_SUST_INT))
+ {
+ o_ptr->art_flags2 |= TR2_SUST_INT;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_DEX)
+ {
+ if (!(o_ptr->art_flags2 & TR2_SUST_DEX))
+ {
+ o_ptr->art_flags2 |= TR2_SUST_DEX;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_CON)
+ {
+ if (!(o_ptr->art_flags2 & TR2_SUST_CON))
+ {
+ o_ptr->art_flags2 |= TR2_SUST_CON;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_CHR)
+ {
+ if (!(o_ptr->art_flags2 & TR2_SUST_CHR))
+ {
+ o_ptr->art_flags2 |= TR2_SUST_CHR;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_CHAOS)
+ {
+ if (!(o_ptr->art_flags3 & TR3_TELEPORT))
+ {
+ o_ptr->art_flags3 |= TR3_TELEPORT;
+ if (randint(2) == 1) return;
+ }
+ }
+ else if (artifact_bias == BIAS_FIRE)
+ {
+ if (!(o_ptr->art_flags3 & TR3_LITE1))
+ {
+ o_ptr->art_flags3 |= TR3_LITE1; /* Freebie */
+ }
+ }
+
+
+ switch (randint(31))
+ {
+ case 1:
+ o_ptr->art_flags2 |= TR2_SUST_STR;
+ /* if (is_scroll) msg_print("It makes you feel you cannot become weaker."); */
+ if (!artifact_bias)
+ artifact_bias = BIAS_STR;
+ break;
+
+ case 2:
+ o_ptr->art_flags2 |= TR2_SUST_INT;
+ /* if (is_scroll) msg_print("It makes you feel you cannot become more stupid.");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_INT;
+ break;
+
+ case 3:
+ o_ptr->art_flags2 |= TR2_SUST_WIS;
+ /* if (is_scroll) msg_print("It makes you feel you cannot become simpler.");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_WIS;
+ break;
+
+ case 4:
+ o_ptr->art_flags2 |= TR2_SUST_DEX;
+ /* if (is_scroll) msg_print("It makes you feel you cannot become clumsier.");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_DEX;
+ break;
+
+ case 5:
+ o_ptr->art_flags2 |= TR2_SUST_CON;
+ /* if (is_scroll) msg_print("It makes you feel you cannot become less healthy.");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_CON;
+ break;
+
+ case 6:
+ o_ptr->art_flags2 |= TR2_SUST_CHR;
+ /* if (is_scroll) msg_print("It makes you feel you cannot become uglier.");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_CHR;
+ break;
+
+ case 7:
+ case 8:
+ case 14:
+ o_ptr->art_flags2 |= TR2_FREE_ACT;
+ /* if (is_scroll) msg_print("It makes you feel like a young rebel!");*/
+ break;
+
+ case 9:
+ o_ptr->art_flags2 |= TR2_HOLD_LIFE;
+ /* if (is_scroll) msg_print("It makes you feel immortal.");*/
+ if (!artifact_bias && (randint(5) == 1))
+ artifact_bias = BIAS_PRIESTLY;
+ else if (!artifact_bias && (randint(6) == 1))
+ artifact_bias = BIAS_NECROMANTIC;
+ break;
+
+ case 10:
+ case 11:
+ o_ptr->art_flags3 |= TR3_LITE1;
+ /* if (is_scroll) msg_print("It starts shining.");*/
+ break;
+
+ case 12:
+ case 13:
+ o_ptr->art_flags3 |= TR3_FEATHER;
+ /* if (is_scroll) msg_print("It feels lighter.");*/
+ break;
+
+ case 15:
+ case 16:
+ case 17:
+ o_ptr->art_flags3 |= TR3_SEE_INVIS;
+ /* if (is_scroll) msg_print("It makes you see the air!");*/
+ break;
+
+ case 18:
+ o_ptr->art_esp |= 1 << (rand_int(32));
+ /* if (is_scroll) msg_print("It makes you hear voices inside your head!");*/
+ if (!artifact_bias && (randint(9) == 1))
+ artifact_bias = BIAS_MAGE;
+ break;
+
+ case 19:
+ case 20:
+ o_ptr->art_flags3 |= TR3_SLOW_DIGEST;
+ /* if (is_scroll) msg_print("It makes you feel less hungry.");*/
+ break;
+
+ case 21:
+ case 22:
+ o_ptr->art_flags3 |= TR3_REGEN;
+ /* if (is_scroll) msg_print("It looks as good as new.");*/
+ break;
+
+ case 23:
+ o_ptr->art_flags3 |= TR3_TELEPORT;
+ /* if (is_scroll) msg_print("Its position feels uncertain!");*/
+ break;
+
+ case 24:
+ case 25:
+ case 26:
+ if (o_ptr->tval >= TV_BOOTS) random_misc(o_ptr, is_scroll);
+ else
+ {
+ o_ptr->art_flags3 |= TR3_SHOW_MODS;
+ o_ptr->to_a = 4 + (randint(11));
+ }
+ break;
+
+ case 27:
+ case 28:
+ case 29:
+ o_ptr->art_flags3 |= TR3_SHOW_MODS;
+ o_ptr->to_h += 4 + (randint(11));
+ o_ptr->to_d += 4 + (randint(11));
+ break;
+
+ case 30:
+ o_ptr->art_flags3 |= TR3_NO_MAGIC;
+ break;
+
+ case 31:
+ o_ptr->art_flags3 |= TR3_NO_TELE;
+ break;
+ }
+
+
+}
+
+
+void random_slay (object_type * o_ptr, bool_ is_scroll)
+{
+ if (artifact_bias == BIAS_CHAOS && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_CHAOTIC))
+ {
+ o_ptr->art_flags1 |= TR1_CHAOTIC;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ else if (artifact_bias == BIAS_PRIESTLY &&
+ (o_ptr->tval == TV_SWORD || o_ptr->tval == TV_POLEARM || o_ptr->tval == TV_AXE) &&
+ !(o_ptr->art_flags3 & TR3_BLESSED))
+ {
+ /* A free power for "priestly" random artifacts */
+ o_ptr->art_flags3 |= TR3_BLESSED;
+ }
+
+ else if (artifact_bias == BIAS_NECROMANTIC && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_VAMPIRIC))
+ {
+ o_ptr->art_flags1 |= TR1_VAMPIRIC;
+ if (randint(2) == 1) return;
+ }
+ if (!(o_ptr->art_flags1 & TR1_BRAND_POIS) && (randint(2) == 1))
+ {
+ o_ptr->art_flags1 |= TR1_BRAND_POIS;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ else if (artifact_bias == BIAS_RANGER && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_SLAY_ANIMAL))
+ {
+ o_ptr->art_flags1 |= TR1_SLAY_ANIMAL;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ else if (artifact_bias == BIAS_ROGUE && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_BRAND_POIS))
+ {
+ o_ptr->art_flags1 |= TR1_BRAND_POIS;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ else if (artifact_bias == BIAS_POIS && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_BRAND_POIS))
+ {
+ o_ptr->art_flags1 |= TR1_BRAND_POIS;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ else if (artifact_bias == BIAS_FIRE && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_BRAND_FIRE))
+ {
+ o_ptr->art_flags1 |= TR1_BRAND_FIRE;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ else if (artifact_bias == BIAS_COLD && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_BRAND_COLD))
+ {
+ o_ptr->art_flags1 |= TR1_BRAND_COLD;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ else if (artifact_bias == BIAS_ELEC && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_BRAND_ELEC))
+ {
+ o_ptr->art_flags1 |= TR1_BRAND_ELEC;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ else if (artifact_bias == BIAS_ACID && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_BRAND_ACID))
+ {
+ o_ptr->art_flags1 |= TR1_BRAND_ACID;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ else if (artifact_bias == BIAS_LAW && !(o_ptr->tval == TV_BOW))
+ {
+ if (!(o_ptr->art_flags1 & TR1_SLAY_EVIL))
+ {
+ o_ptr->art_flags1 |= TR1_SLAY_EVIL;
+ if (randint(2) == 1) return;
+ }
+ if (!(o_ptr->art_flags1 & TR1_SLAY_UNDEAD))
+ {
+ o_ptr->art_flags1 |= TR1_SLAY_UNDEAD;
+ if (randint(2) == 1) return;
+ }
+ if (!(o_ptr->art_flags1 & TR1_SLAY_DEMON))
+ {
+ o_ptr->art_flags1 |= TR1_SLAY_DEMON;
+ if (randint(2) == 1) return;
+ }
+ }
+
+ if (!(o_ptr->tval == TV_BOW))
+ {
+ switch (randint(34))
+ {
+ case 1:
+ case 2:
+ o_ptr->art_flags1 |= TR1_SLAY_ANIMAL;
+ /* if (is_scroll) msg_print("You start hating animals.");*/
+ break;
+
+ case 3:
+ case 4:
+ o_ptr->art_flags1 |= TR1_SLAY_EVIL;
+ /* if (is_scroll) msg_print("You hate evil creatures.");*/
+ if (!artifact_bias && (randint(2) == 1))
+ artifact_bias = BIAS_LAW;
+ else if (!artifact_bias && (randint(9) == 1))
+ artifact_bias = BIAS_PRIESTLY;
+ break;
+
+ case 5:
+ case 6:
+ o_ptr->art_flags1 |= TR1_SLAY_UNDEAD;
+ /* if (is_scroll) msg_print("You hate undead creatures.");*/
+ if (!artifact_bias && (randint(9) == 1))
+ artifact_bias = BIAS_PRIESTLY;
+ break;
+
+ case 7:
+ case 8:
+ o_ptr->art_flags1 |= TR1_SLAY_DEMON;
+ /* if (is_scroll) msg_print("You hate demons.");*/
+ if (!artifact_bias && (randint(9) == 1))
+ artifact_bias = BIAS_PRIESTLY;
+ break;
+
+ case 9:
+ case 10:
+ o_ptr->art_flags1 |= TR1_SLAY_ORC;
+ /* if (is_scroll) msg_print("You hate orcs.");*/
+ break;
+
+ case 11:
+ case 12:
+ o_ptr->art_flags1 |= TR1_SLAY_TROLL;
+ /* if (is_scroll) msg_print("You hate trolls.");*/
+ break;
+
+ case 13:
+ case 14:
+ o_ptr->art_flags1 |= TR1_SLAY_GIANT;
+ /* if (is_scroll) msg_print("You hate giants.");*/
+ break;
+
+ case 15:
+ case 16:
+ o_ptr->art_flags1 |= TR1_SLAY_DRAGON;
+ /* if (is_scroll) msg_print("You hate dragons.");*/
+ break;
+
+ case 17:
+ o_ptr->art_flags1 |= TR1_KILL_DRAGON;
+ /* if (is_scroll) msg_print("You feel an intense hatred of dragons.");*/
+ break;
+
+ case 18:
+ case 19:
+ if (o_ptr->tval == TV_SWORD)
+ {
+ o_ptr->art_flags1 |= TR1_VORPAL;
+ /* if (is_scroll) msg_print("It looks extremely sharp!");*/
+ if (!artifact_bias && (randint(9) == 1))
+ artifact_bias = BIAS_WARRIOR;
+ }
+ else random_slay(o_ptr, is_scroll);
+ break;
+
+ case 20:
+ o_ptr->art_flags1 |= TR1_IMPACT;
+ /* if (is_scroll) msg_print("The ground trembles beneath you.");*/
+ break;
+
+ case 21:
+ case 22:
+ o_ptr->art_flags1 |= TR1_BRAND_FIRE;
+ /* if (is_scroll) msg_print("It feels hot!");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_FIRE;
+ break;
+
+ case 23:
+ case 24:
+ o_ptr->art_flags1 |= TR1_BRAND_COLD;
+ /* if (is_scroll) msg_print("It feels cold!");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_COLD;
+ break;
+
+ case 25:
+ case 26:
+ o_ptr->art_flags1 |= TR1_BRAND_ELEC;
+ /* if (is_scroll) msg_print("Ouch! You get zapped!");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_ELEC;
+ break;
+
+ case 27:
+ case 28:
+ o_ptr->art_flags1 |= TR1_BRAND_ACID;
+ /* if (is_scroll) msg_print("Its smell makes you feel dizzy.");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_ACID;
+ break;
+
+ case 29:
+ case 30:
+ o_ptr->art_flags1 |= TR1_BRAND_POIS;
+ /* if (is_scroll) msg_print("It smells rotten.");*/
+ if (!artifact_bias && (randint(3) != 1))
+ artifact_bias = BIAS_POIS;
+ else if (!artifact_bias && randint(6) == 1)
+ artifact_bias = BIAS_NECROMANTIC;
+ else if (!artifact_bias)
+ artifact_bias = BIAS_ROGUE;
+ break;
+
+ case 31:
+ case 32:
+ o_ptr->art_flags1 |= TR1_VAMPIRIC;
+ /* if (is_scroll) msg_print("You think it bit you!");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_NECROMANTIC;
+ break;
+
+ default:
+ o_ptr->art_flags1 |= TR1_CHAOTIC;
+ /* if (is_scroll) msg_print("It looks very confusing.");*/
+ if (!artifact_bias)
+ artifact_bias = BIAS_CHAOS;
+ break;
+ }
+ }
+ else
+ {
+ switch (randint(6))
+ {
+ case 1:
+ case 2:
+ case 3:
+ o_ptr->art_flags3 |= TR3_XTRA_MIGHT;
+ /* if (is_scroll) msg_print("It looks mightier than before."); */
+ if (!artifact_bias && randint(9) == 1)
+ artifact_bias = BIAS_RANGER;
+ break;
+
+ default:
+ o_ptr->art_flags3 |= TR3_XTRA_SHOTS;
+ /* if (is_scroll) msg_print("It seems faster!"); */
+ if (!artifact_bias && randint(9) == 1)
+ artifact_bias = BIAS_RANGER;
+ break;
+ }
+ }
+}
+
+
+
+
+/*
+ * Determines if an item is not identified
+ */
+static bool_ item_tester_hook_unknown(object_type *o_ptr)
+{
+ return (object_known_p(o_ptr) ? FALSE : TRUE);
+}
+
+
+/*
+ * Identify an object in the inventory (or on the floor)
+ * This routine does *not* automatically combine objects.
+ * Returns TRUE if something was identified, else FALSE.
+ */
+bool_ ident_spell(void)
+{
+ int item;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ cptr q, s;
+
+ /* Get an item */
+ item_tester_hook = item_tester_hook_unknown;
+ q = "Identify which item? ";
+ s = "You have nothing to identify.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return (FALSE);
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Identify it fully */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Describe */
+ if (item >= INVEN_WIELD)
+ {
+ msg_format("%^s: %s (%c).",
+ describe_use(item), o_name, index_to_label(item));
+ }
+ else if (item >= 0)
+ {
+ msg_format("In your pack: %s (%c).",
+ o_name, index_to_label(item));
+ }
+ else
+ {
+ msg_format("On the ground: %s.",
+ o_name);
+ }
+
+ /* If the item was an artifact, and if the auto-note is selected, write a message. */
+ if (take_notes && auto_notes && (artifact_p(o_ptr) || o_ptr->name1))
+ {
+ char note[150];
+ char item_name[80];
+ object_desc(item_name, o_ptr, FALSE, 0);
+
+ /* Build note and write */
+ sprintf(note, "Found The %s", item_name);
+ add_note(note, 'A');
+ }
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_IDENTIFY, "(d,s)", item, "normal");
+
+ /* Something happened */
+ return (TRUE);
+}
+
+/*
+ * Identify all objects in the level
+ */
+bool_ ident_all(void)
+{
+ int i;
+
+ object_type *o_ptr;
+
+ for (i = 1; i < o_max; i++)
+ {
+ /* Acquire object */
+ o_ptr = &o_list[i];
+
+ /* Identify it fully */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+
+ /* If the item was an artifact, and if the auto-note is selected, write a message. */
+ if (take_notes && auto_notes && (artifact_p(o_ptr) || o_ptr->name1))
+ {
+ char note[150];
+ char item_name[80];
+ object_desc(item_name, o_ptr, FALSE, 0);
+
+ /* Build note and write */
+ sprintf(note, "Found The %s", item_name);
+ add_note(note, 'A');
+ }
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_IDENTIFY, "(d,s)", -i, "normal");
+ }
+
+ /* Something happened */
+ return (TRUE);
+}
+
+
+
+/*
+ * Determine if an object is not fully identified
+ */
+static bool_ item_tester_hook_no_mental(object_type *o_ptr)
+{
+ return ((o_ptr->ident & (IDENT_MENTAL)) ? FALSE : TRUE);
+}
+
+/*
+ * Fully "identify" an object in the inventory -BEN-
+ * This routine returns TRUE if an item was identified.
+ */
+bool_ identify_fully(void)
+{
+ int item;
+ object_type *o_ptr;
+ char o_name[80];
+
+ cptr q, s;
+
+ /* Get an item */
+ item_tester_hook = item_tester_hook_no_mental;
+ q = "Identify which item? ";
+ s = "You have nothing to identify.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return (FALSE);
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Do the identification */
+ make_item_fully_identified(o_ptr);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Describe */
+ if (item >= INVEN_WIELD)
+ {
+ msg_format("%^s: %s (%c).",
+ describe_use(item), o_name, index_to_label(item));
+ }
+ else if (item >= 0)
+ {
+ msg_format("In your pack: %s (%c).",
+ o_name, index_to_label(item));
+ }
+ else
+ {
+ msg_format("On the ground: %s.",
+ o_name);
+ }
+
+ /* If the item was an artifact, and if the auto-note is selected, write a message. */
+ if (take_notes && auto_notes && (artifact_p(o_ptr) || o_ptr->name1))
+ {
+ char note[150];
+ char item_name[80];
+ object_desc(item_name, o_ptr, FALSE, 0);
+
+ /* Build note and write */
+ sprintf(note, "Found The %s", item_name);
+ add_note(note, 'A');
+ }
+
+ /* Describe it fully */
+ object_out_desc(o_ptr, NULL, FALSE, TRUE);
+
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_IDENTIFY, "(d,s)", item, "full");
+
+ /* Success */
+ return (TRUE);
+}
+
+
+
+
+/*
+ * Hook for "get_item()". Determine if something is rechargable.
+ */
+bool_ item_tester_hook_recharge(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Some objects cannot be recharged */
+ if (f4 & TR4_NO_RECHARGE) return (FALSE);
+
+ /* Recharge staffs */
+ if (o_ptr->tval == TV_STAFF) return (TRUE);
+
+ /* Recharge wands */
+ if (o_ptr->tval == TV_WAND) return (TRUE);
+
+ /* Hack -- Recharge rods */
+ if (o_ptr->tval == TV_ROD_MAIN) return (TRUE);
+
+ /* Nope */
+ return (FALSE);
+}
+
+
+/*
+ * Recharge a wand/staff/rod from the pack or on the floor.
+ * This function has been rewritten in Oangband. -LM-
+ *
+ * Mage -- Recharge I --> recharge(90)
+ * Mage -- Recharge II --> recharge(150)
+ * Mage -- Recharge III --> recharge(220)
+ *
+ * Priest or Necromancer -- Recharge --> recharge(140)
+ *
+ * Scroll of recharging --> recharge(130)
+ * Scroll of *recharging* --> recharge(200)
+ *
+ * It is harder to recharge high level, and highly charged wands,
+ * staffs, and rods. The more wands in a stack, the more easily and
+ * strongly they recharge. Staffs, however, each get fewer charges if
+ * stacked.
+ *
+ * XXX XXX XXX Beware of "sliding index errors".
+ */
+bool_ recharge(int power)
+{
+ int recharge_strength, recharge_amount;
+ int item, lev;
+
+ bool_ fail = FALSE;
+ byte fail_type = 1;
+
+
+ cptr q, s;
+
+ u32b f1, f2, f3, f4, f5, esp;
+ char o_name[80];
+
+ object_type *o_ptr;
+
+ /* Only accept legal items */
+ item_tester_hook = item_tester_hook_recharge;
+
+ /* Get an item */
+ q = "Recharge which item? ";
+ s = "You have nothing to recharge.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return (FALSE);
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Extract the object "level" */
+ lev = k_info[o_ptr->k_idx].level;
+
+ /* Recharge a rod */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ /* Extract a recharge strength by comparing object level to power. */
+ recharge_strength = ((power > lev) ? (power - lev) : 0) / 5;
+
+ /* Paranoia */
+ if (recharge_strength < 0) recharge_strength = 0;
+
+ /* Back-fire */
+ if ((rand_int(recharge_strength) == 0) && (!(f4 & TR4_RECHARGE)))
+ {
+ /* Activate the failure code. */
+ fail = TRUE;
+ }
+
+ /* Recharge */
+ else
+ {
+ /* Recharge amount */
+ recharge_amount = (power * damroll(3, 2));
+
+ /* Recharge by that amount */
+ if (o_ptr->timeout + recharge_amount < o_ptr->pval2)
+ o_ptr->timeout += recharge_amount;
+ else
+ o_ptr->timeout = o_ptr->pval2;
+ }
+ }
+
+
+ /* Recharge wand/staff */
+ else
+ {
+ /* Extract a recharge strength by comparing object level to power.
+ * Divide up a stack of wands' charges to calculate charge penalty.
+ */
+ if ((o_ptr->tval == TV_WAND) && (o_ptr->number > 1))
+ recharge_strength = (100 + power - lev -
+ (8 * o_ptr->pval / o_ptr->number)) / 15;
+
+ /* All staffs, unstacked wands. */
+ else recharge_strength = (100 + power - lev -
+ (8 * o_ptr->pval)) / 15;
+
+
+ /* Back-fire XXX XXX XXX */
+ if (((rand_int(recharge_strength) == 0) && (!(f4 & TR4_RECHARGE))) ||
+ (f4 & TR4_NO_RECHARGE))
+ {
+ /* Activate the failure code. */
+ fail = TRUE;
+ }
+
+ /* If the spell didn't backfire, recharge the wand or staff. */
+ else
+ {
+ /* Recharge based on the standard number of charges. */
+ recharge_amount = randint((power / (lev + 2)) + 1);
+
+ /* Multiple wands in a stack increase recharging somewhat. */
+ if ((o_ptr->tval == TV_WAND) && (o_ptr->number > 1))
+ {
+ recharge_amount +=
+ (randint(recharge_amount * (o_ptr->number - 1))) / 2;
+ if (recharge_amount < 1) recharge_amount = 1;
+ if (recharge_amount > 12) recharge_amount = 12;
+ }
+
+ /* But each staff in a stack gets fewer additional charges,
+ * although always at least one.
+ */
+ if ((o_ptr->tval == TV_STAFF) && (o_ptr->number > 1))
+ {
+ recharge_amount /= o_ptr->number;
+ if (recharge_amount < 1) recharge_amount = 1;
+ }
+
+ /* Recharge the wand or staff. */
+ o_ptr->pval += recharge_amount;
+
+ if (!(f4 & TR4_RECHARGE))
+ {
+ /* Hack -- we no longer "know" the item */
+ o_ptr->ident &= ~(IDENT_KNOWN);
+ }
+
+ /* Hack -- we no longer think the item is empty */
+ o_ptr->ident &= ~(IDENT_EMPTY);
+ }
+ }
+
+ /* Mark as recharged -- For alchemists */
+ o_ptr->art_flags4 |= TR4_RECHARGED;
+
+ /* Inflict the penalties for failing a recharge. */
+ if (fail)
+ {
+ /* Artifacts are never destroyed. */
+ if (artifact_p(o_ptr))
+ {
+ object_desc(o_name, o_ptr, TRUE, 0);
+ msg_format("The recharging backfires - %s is completely drained!", o_name);
+
+ /* Artifact rods. */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ o_ptr->timeout = 0;
+
+ /* Artifact wands and staffs. */
+ else if ((o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_STAFF))
+ o_ptr->pval = 0;
+ }
+ else
+ {
+ /* Get the object description */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ /*** Determine Seriousness of Failure ***/
+
+ /* Mages recharge objects more safely. */
+ if (has_ability(AB_PERFECT_CASTING))
+ {
+ /* 10% chance to blow up one rod, otherwise draining. */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ if (randint(10) == 1) fail_type = 2;
+ else fail_type = 1;
+ }
+ /* 75% chance to blow up one wand, otherwise draining. */
+ else if (o_ptr->tval == TV_WAND)
+ {
+ if (randint(3) != 1) fail_type = 2;
+ else fail_type = 1;
+ }
+ /* 50% chance to blow up one staff, otherwise no effect. */
+ else if (o_ptr->tval == TV_STAFF)
+ {
+ if (randint(2) == 1) fail_type = 2;
+ else fail_type = 0;
+ }
+ }
+
+ /* All other classes get no special favors. */
+ else
+ {
+ /* 33% chance to blow up one rod, otherwise draining. */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ if (randint(3) == 1) fail_type = 2;
+ else fail_type = 1;
+ }
+ /* 20% chance of the entire stack, else destroy one wand. */
+ else if (o_ptr->tval == TV_WAND)
+ {
+ if (randint(5) == 1) fail_type = 3;
+ else fail_type = 2;
+ }
+ /* Blow up one staff. */
+ else if (o_ptr->tval == TV_STAFF)
+ {
+ fail_type = 2;
+ }
+ }
+
+ /*** Apply draining and destruction. ***/
+
+ /* Drain object or stack of objects. */
+ if (fail_type == 1)
+ {
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ msg_print("The recharge backfires, draining the rod further!");
+ if (o_ptr->timeout < 10000)
+ o_ptr->timeout = 0;
+ }
+ else if (o_ptr->tval == TV_WAND)
+ {
+ msg_format("You save your %s from destruction, but all charges are lost.", o_name);
+ o_ptr->pval = 0;
+ }
+ /* Staffs aren't drained. */
+ }
+
+ /* Destroy an object or one in a stack of objects. */
+ if (fail_type == 2)
+ {
+ if (o_ptr->number > 1)
+ msg_format("Wild magic consumes one of your %s!", o_name);
+ else
+ msg_format("Wild magic consumes your %s!", o_name);
+
+ /* Reduce rod stack maximum timeout, drain wands. */
+ if (o_ptr->tval == TV_WAND) o_ptr->pval = 0;
+
+ /* Reduce and describe */
+ inc_stack_size(item, -1);
+ }
+
+ /* Destroy all memebers of a stack of objects. */
+ if (fail_type == 3)
+ {
+ if (o_ptr->number > 1)
+ msg_format("Wild magic consumes all your %s!", o_name);
+ else
+ msg_format("Wild magic consumes your %s!", o_name);
+
+
+ /* Reduce and describe inventory */
+ inc_stack_size(item, -999);
+ }
+ }
+ }
+
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN);
+
+ /* Something was done */
+ return (TRUE);
+}
+
+
+
+/*
+ * Apply a "project()" directly to all viewable monsters
+ *
+ * Note that affected monsters are NOT auto-tracked by this usage.
+ */
+bool_ project_hack(int typ, int dam)
+{
+ int i, x, y;
+ int flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE;
+ bool_ obvious = FALSE;
+
+
+ /* Affect all (nearby) monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+
+ /* Paranoia -- Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Require line of sight */
+ if (!player_has_los_bold(y, x)) continue;
+
+ /* Jump directly to the target monster */
+ if (project(0, 0, y, x, dam, typ, flg)) obvious = TRUE;
+ }
+
+ /* Result */
+ return (obvious);
+}
+
+/*
+ * Apply a "project()" a la meteor shower
+ */
+void project_meteor(int radius, int typ, int dam, u32b flg)
+{
+ cave_type *c_ptr;
+ int x, y, dx, dy, d, count = 0, i;
+ int b = radius + randint(radius);
+ for (i = 0; i < b; i++)
+ {
+ for (count = 0; count < 1000; count++)
+ {
+ x = p_ptr->px - 5 + randint(10);
+ y = p_ptr->py - 5 + randint(10);
+ if ((x < 0) || (x >= cur_wid) ||
+ (y < 0) || (y >= cur_hgt)) continue;
+ dx = (p_ptr->px > x) ? (p_ptr->px - x) : (x - p_ptr->px);
+ dy = (p_ptr->py > y) ? (p_ptr->py - y) : (y - p_ptr->py);
+ /* Approximate distance */
+ d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
+ c_ptr = &cave[y][x];
+ /* Check distance */
+ if ((d <= 5) &&
+ /* Check line of sight */
+ (player_has_los_bold(y, x)) &&
+ /* But don't explode IN a wall, letting the player attack through walls */
+ !(c_ptr->info & CAVE_WALL))
+ break;
+ }
+ if (count >= 1000) break;
+ project(0, 2, y, x, dam, typ, PROJECT_JUMP | flg);
+ }
+}
+
+
+/*
+ * Speed monsters
+ */
+bool_ speed_monsters(void)
+{
+ return (project_hack(GF_OLD_SPEED, p_ptr->lev));
+}
+
+/*
+ * Slow monsters
+ */
+bool_ slow_monsters(void)
+{
+ return (project_hack(GF_OLD_SLOW, p_ptr->lev));
+}
+
+/*
+ * Paralyzation monsters
+ */
+bool_ conf_monsters(void)
+{
+ return (project_hack(GF_OLD_CONF, p_ptr->lev));
+}
+
+/*
+ * Sleep monsters
+ */
+bool_ sleep_monsters(void)
+{
+ return (project_hack(GF_OLD_SLEEP, p_ptr->lev));
+}
+
+/*
+ * Scare monsters
+ */
+bool_ scare_monsters(void)
+{
+ return (project_hack(GF_FEAR, p_ptr->lev));
+}
+
+
+/*
+ * Banish evil monsters
+ */
+bool_ banish_evil(int dist)
+{
+ return (project_hack(GF_AWAY_EVIL, dist));
+}
+
+
+/*
+ * Turn undead
+ */
+bool_ turn_undead(void)
+{
+ return (project_hack(GF_TURN_UNDEAD, p_ptr->lev));
+}
+
+
+/*
+ * Dispel undead monsters
+ */
+bool_ dispel_undead(int dam)
+{
+ return (project_hack(GF_DISP_UNDEAD, dam));
+}
+
+/*
+ * Dispel evil monsters
+ */
+bool_ dispel_evil(int dam)
+{
+ return (project_hack(GF_DISP_EVIL, dam));
+}
+
+/*
+ * Dispel good monsters
+ */
+bool_ dispel_good(int dam)
+{
+ return (project_hack(GF_DISP_GOOD, dam));
+}
+
+/*
+ * Dispel all monsters
+ */
+bool_ dispel_monsters(int dam)
+{
+ return (project_hack(GF_DISP_ALL, dam));
+}
+
+/*
+ * Dispel 'living' monsters
+ */
+bool_ dispel_living(int dam)
+{
+ return (project_hack(GF_DISP_LIVING, dam));
+}
+
+/*
+ * Dispel demons
+ */
+bool_ dispel_demons(int dam)
+{
+ return (project_hack(GF_DISP_DEMON, dam));
+}
+
+
+/*
+ * Wake up all monsters, and speed up "los" monsters.
+ */
+void aggravate_monsters(int who)
+{
+ int i;
+ bool_ sleep = FALSE;
+ bool_ speed = FALSE;
+
+
+ /* Aggravate everyone nearby */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Paranoia -- Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Skip aggravating monster (or player) */
+ if (i == who) continue;
+
+ /* Wake up nearby sleeping monsters */
+ if (m_ptr->cdis < MAX_SIGHT * 2)
+ {
+ /* Wake up */
+ if (m_ptr->csleep)
+ {
+ /* Wake up */
+ m_ptr->csleep = 0;
+ sleep = TRUE;
+ }
+ }
+
+ /* Speed up monsters in line of sight */
+ if (player_has_los_bold(m_ptr->fy, m_ptr->fx))
+ {
+ /* Speed up (instantly) to racial base + 10 */
+ if (m_ptr->mspeed < r_ptr->speed + 10)
+ {
+ /* Speed up */
+ m_ptr->mspeed = r_ptr->speed + 10;
+ speed = TRUE;
+ }
+
+ /* Pets may get angry (50% chance) */
+ if (is_friend(m_ptr))
+ {
+ if (randint(2) == 1)
+ {
+ change_side(m_ptr);
+ }
+ }
+ }
+ }
+
+ /* Messages */
+ if (speed) msg_print("You feel a sudden stirring nearby!");
+ else if (sleep) msg_print("You hear a sudden stirring in the distance!");
+}
+
+/*
+ * Generic genocide race selection
+ */
+bool_ get_genocide_race(cptr msg, char *typ)
+{
+ int i, j;
+ cave_type *c_ptr;
+
+ msg_print(msg);
+ if (!tgt_pt(&i, &j)) return FALSE;
+
+ c_ptr = &cave[j][i];
+
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ *typ = r_ptr->d_char;
+ return TRUE;
+ }
+
+ msg_print("You must select a monster.");
+ return FALSE;
+}
+
+/*
+ * Inflict dam damage of type typee to all monster of the given race
+ */
+bool_ invoke(int dam, int typee)
+{
+ int i;
+ char typ;
+ bool_ result = FALSE;
+ int msec = delay_factor * delay_factor * delay_factor;
+
+ if (dungeon_flags2 & DF2_NO_GENO) return (FALSE);
+
+ /* Hack -- when you are fated to die, you cant cheat :) */
+ if (dungeon_type == DUNGEON_DEATH)
+ {
+ msg_print("A mysterious force stops the genocide.");
+ return FALSE;
+ }
+
+ /* Get a monster symbol */
+ if (!get_genocide_race("Target a monster to select the race to invoke on.", &typ)) return FALSE;
+
+ /* Delete the monsters of that "type" */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Paranoia -- Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Hack -- Skip Unique Monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) continue;
+
+ /* Hack -- Skip Quest Monsters */
+ if (m_ptr->mflag & MFLAG_QUEST) continue;
+
+ /* Skip "wrong" monsters */
+ if (r_ptr->d_char != typ) continue;
+
+ project_m(0, 0, m_ptr->fy, m_ptr->fx, dam, typee);
+
+ /* Visual feedback */
+ move_cursor_relative(p_ptr->py, p_ptr->px);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Handle */
+ handle_stuff();
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Delay */
+ Term_xtra(TERM_XTRA_DELAY, msec);
+
+ /* Take note */
+ result = TRUE;
+ }
+
+ return (result);
+}
+
+
+/*
+ * Delete all non-unique/non-quest monsters of a given "type" from the level
+ */
+bool_ genocide_aux(bool_ player_cast, char typ)
+{
+ int i;
+ bool_ result = FALSE;
+ int msec = delay_factor * delay_factor * delay_factor;
+ int dam = 0;
+
+ /* Delete the monsters of that "type" */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Paranoia -- Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Hack -- Skip Unique Monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) continue;
+
+ /* Hack -- Skip Quest Monsters */
+ if (m_ptr->mflag & MFLAG_QUEST) continue;
+
+ /* Skip "wrong" monsters */
+ if (r_ptr->d_char != typ) continue;
+
+ /* Oups */
+ if (r_ptr->flags2 & RF2_DEATH_ORB)
+ {
+ int wx, wy;
+ int attempts = 500;
+
+ monster_race_desc(r_name, m_ptr->r_idx, 0);
+
+ do
+ {
+ scatter(&wy, &wx, m_ptr->fy, m_ptr->fx, 10);
+ }
+ while (!(in_bounds(wy, wx) && cave_floor_bold(wy, wx)) && --attempts);
+
+ if (place_monster_aux(wy, wx, m_ptr->r_idx, FALSE, TRUE, MSTATUS_ENEMY))
+ {
+ cmsg_format(TERM_L_BLUE, "The spell seems to produce an ... interesting effect on the %s.", r_name);
+ }
+
+ return TRUE;
+ }
+
+ /* Delete the monster */
+ delete_monster_idx(i);
+
+ if (player_cast)
+ {
+ /* Keep track of damage */
+ dam += randint(4);
+ }
+
+ /* Handle */
+ handle_stuff();
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Delay */
+ Term_xtra(TERM_XTRA_DELAY, msec);
+
+ /* Take note */
+ result = TRUE;
+ }
+
+ if (player_cast)
+ {
+ /* Take damage */
+ take_hit(dam, "the strain of casting Genocide");
+
+ /* Visual feedback */
+ move_cursor_relative(p_ptr->py, p_ptr->px);
+
+ /* Redraw */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Handle */
+ handle_stuff();
+
+ /* Fresh */
+ Term_fresh();
+ }
+
+ return (result);
+}
+
+bool_ genocide(bool_ player_cast)
+{
+ char typ;
+
+ if (dungeon_flags2 & DF2_NO_GENO) return (FALSE);
+
+ /* Hack -- when you are fated to die, you cant cheat :) */
+ if (dungeon_type == DUNGEON_DEATH)
+ {
+ msg_print("A mysterious force stops the genocide.");
+ return FALSE;
+ }
+
+ /* Mega-Hack -- Get a monster symbol */
+ if (!get_genocide_race("Target a monster to select the race to genocide.", &typ)) return FALSE;
+
+ return (genocide_aux(player_cast, typ));
+}
+
+
+/*
+ * Delete all nearby (non-unique) monsters
+ */
+bool_ mass_genocide(bool_ player_cast)
+{
+ int i;
+ bool_ result = FALSE;
+ int msec = delay_factor * delay_factor * delay_factor;
+ int dam = 0;
+
+ if (dungeon_flags2 & DF2_NO_GENO) return (FALSE);
+
+ /* Hack -- when you are fated to die, you cant cheat :) */
+ if (dungeon_type == DUNGEON_DEATH)
+ {
+ msg_print("A mysterious force stops the genocide.");
+ return FALSE;
+ }
+
+ /* Delete the (nearby) monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Paranoia -- Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Hack -- Skip unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) continue;
+
+ /* Hack -- Skip Quest Monsters */
+ if (m_ptr->mflag & MFLAG_QUEST) continue;
+
+ /* Skip distant monsters */
+ if (m_ptr->cdis > MAX_SIGHT) continue;
+
+ /* Oups */
+ if (r_ptr->flags2 & RF2_DEATH_ORB)
+ {
+ int wx, wy;
+ int attempts = 500;
+
+ monster_race_desc(r_name, m_ptr->r_idx, 0);
+
+ do
+ {
+ scatter(&wy, &wx, m_ptr->fy, m_ptr->fx, 10);
+ }
+ while (!(in_bounds(wy, wx) && cave_floor_bold(wy, wx)) && --attempts);
+
+ if (place_monster_aux(wy, wx, m_ptr->r_idx, FALSE, TRUE, MSTATUS_ENEMY))
+ {
+ cmsg_format(TERM_L_BLUE, "The spell seems to produce an ... interesting effect on the %s.", r_name);
+ }
+
+ return TRUE;
+ }
+
+ /* Delete the monster */
+ delete_monster_idx(i);
+
+ if (player_cast)
+ {
+ /* Keep track of damage. */
+ dam += randint(3);
+ }
+
+ /* Handle */
+ handle_stuff();
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Delay */
+ Term_xtra(TERM_XTRA_DELAY, msec);
+
+ /* Note effect */
+ result = TRUE;
+ }
+
+ if (player_cast)
+ {
+ /* Take damage */
+ take_hit(dam, "the strain of casting Mass Genocide");
+
+ /* Visual feedback */
+ move_cursor_relative(p_ptr->py, p_ptr->px);
+
+ /* Redraw */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Handle */
+ handle_stuff();
+
+ /* Fresh */
+ Term_fresh();
+ }
+
+ return (result);
+}
+
+/* Probe a monster */
+void do_probe(int m_idx)
+{
+ char m_name[80];
+ monster_type *m_ptr = &m_list[m_idx];
+
+ /* Get "the monster" or "something" */
+ monster_desc(m_name, m_ptr, 0x04);
+
+ /* Describe the monster */
+ if (!wizard && (m_ptr->status != MSTATUS_COMPANION)) msg_format("%^s has %d hit points.", m_name, m_ptr->hp);
+ else
+ {
+ int i;
+ char t_name[80];
+ msg_format("%^s has %d(%d) hit points, %d ac, %d speed.", m_name, m_ptr->hp, m_ptr->maxhp, m_ptr->ac, m_ptr->mspeed - 110);
+ msg_format("%^s attacks with:", m_name);
+
+ for (i = 0; i < 4; i++)
+ {
+ msg_format(" Blow %d: %dd%d", i, m_ptr->blow[i].d_dice, m_ptr->blow[i].d_side);
+ }
+
+ if (m_ptr->target > 0)
+ monster_desc(t_name, &m_list[m_ptr->target], 0x04);
+ else if (!m_ptr->target)
+ sprintf(t_name, "you");
+ else
+ sprintf(t_name, "nothing");
+ msg_format("%^s target is %s.", m_name, t_name);
+
+ msg_format("%^s has %ld exp and needs %ld.", m_name, m_ptr->exp, MONSTER_EXP(m_ptr->level + 1));
+ }
+
+ /* Learn all of the non-spell, non-treasure flags */
+ lore_do_probe(m_idx);
+}
+
+/*
+ * Probe nearby monsters
+ */
+bool_ probing(void)
+{
+ int i;
+
+ bool_ probe = FALSE;
+
+
+ /* Probe all (nearby) monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+
+ /* Paranoia -- Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Require line of sight */
+ if (!player_has_los_bold(m_ptr->fy, m_ptr->fx)) continue;
+
+ /* Probe visible monsters */
+ if (m_ptr->ml)
+ {
+ /* Start the message */
+ if (!probe) msg_print("Probing...");
+
+ /* Actualy probe */
+ do_probe(i);
+
+ /* Probe worked */
+ probe = TRUE;
+ }
+ }
+
+ /* Done */
+ if (probe)
+ {
+ msg_print("That's all.");
+ }
+
+ /* Result */
+ return (probe);
+}
+
+
+/*
+ * Wipe -- Empties a part of the dungeon
+ */
+void wipe(int y1, int x1, int r)
+{
+ int y, x, k;
+
+ cave_type *c_ptr;
+
+ bool_ flag = FALSE;
+
+ if (dungeon_flags2 & DF2_NO_GENO)
+ {
+ msg_print("Not on special levels!");
+ return;
+ }
+ if (p_ptr->inside_quest)
+ {
+ return;
+ }
+
+ /* Big area of affect */
+ for (y = (y1 - r); y <= (y1 + r); y++)
+ {
+ for (x = (x1 - r); x <= (x1 + r); x++)
+ {
+ /* Skip illegal grids */
+ if (!in_bounds(y, x)) continue;
+
+ /* Extract the distance */
+ k = distance(y1, x1, y, x);
+
+ /* Stay in the circle of death */
+ if (k > r) continue;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Lose room and vault */
+ c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
+
+ /* Lose light and knowledge */
+ c_ptr->info &= ~(CAVE_MARK | CAVE_GLOW);
+
+ if (m_list[c_ptr->m_idx].status != MSTATUS_COMPANION) delete_monster(y, x);
+ delete_object(y, x);
+ place_floor_convert_glass(y, x);
+ }
+ }
+
+
+ /* Hack -- Affect player */
+ if (flag)
+ {
+ /* Message */
+ msg_print("There is a searing blast of light!");
+
+ /* Blind the player */
+ if (!p_ptr->resist_blind && !p_ptr->resist_lite)
+ {
+ /* Become blind */
+ (void)set_blind(p_ptr->blind + 10 + randint(10));
+ }
+ }
+
+
+ /* Mega-Hack -- Forget the view */
+ p_ptr->update |= (PU_UN_VIEW);
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+
+/*
+ * The spell of destruction
+ *
+ * This spell "deletes" monsters (instead of "killing" them).
+ *
+ * Later we may use one function for both "destruction" and
+ * "earthquake" by using the "full" to select "destruction".
+ */
+void destroy_area(int y1, int x1, int r, bool_ full, bool_ bypass)
+{
+ int y, x, k, t;
+
+ cave_type *c_ptr;
+
+ bool_ flag = FALSE;
+
+
+ /* XXX XXX */
+ full = full ? full : 0;
+
+ if (dungeon_flags2 & DF2_NO_GENO)
+ {
+ msg_print("Not on special levels!");
+ return;
+ }
+ if (p_ptr->inside_quest && (!bypass))
+ {
+ return;
+ }
+
+ /* Big area of affect */
+ for (y = (y1 - r); y <= (y1 + r); y++)
+ {
+ for (x = (x1 - r); x <= (x1 + r); x++)
+ {
+ /* Skip illegal grids */
+ if (!in_bounds(y, x)) continue;
+
+ /* Extract the distance */
+ k = distance(y1, x1, y, x);
+
+ /* Stay in the circle of death */
+ if (k > r) continue;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Lose room and vault */
+ c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
+
+ /* Lose light and knowledge */
+ c_ptr->info &= ~(CAVE_MARK | CAVE_GLOW);
+
+ /* Hack -- Notice player affect */
+ if ((x == p_ptr->px) && (y == p_ptr->py))
+ {
+ /* Hurt the player later */
+ flag = TRUE;
+
+ /* Do not hurt this grid */
+ continue;
+ }
+
+ /* Hack -- Skip the epicenter */
+ if ((y == y1) && (x == x1)) continue;
+
+ /* Delete the monster (if any) */
+ if ((m_list[c_ptr->m_idx].status != MSTATUS_COMPANION) ||
+ (!(m_list[c_ptr->m_idx].mflag & MFLAG_QUEST)) ||
+ (!(m_list[c_ptr->m_idx].mflag & MFLAG_QUEST2)))
+ delete_monster(y, x);
+
+ /* Destroy "valid" grids */
+ if (cave_valid_bold(y, x))
+ {
+ /* Delete objects */
+ delete_object(y, x);
+
+ /* Wall (or floor) type */
+ t = rand_int(200);
+
+ /* Granite */
+ if (t < 20)
+ {
+ /* Create granite wall */
+ cave_set_feat(y, x, FEAT_WALL_EXTRA);
+ }
+
+ /* Quartz */
+ else if (t < 70)
+ {
+ /* Create quartz vein */
+ cave_set_feat(y, x, FEAT_QUARTZ);
+ }
+
+ /* Magma */
+ else if (t < 100)
+ {
+ /* Create magma vein */
+ cave_set_feat(y, x, FEAT_MAGMA);
+ }
+
+ /* Floor */
+ else
+ {
+ /* Create floor */
+ cave_set_feat(y, x, FEAT_FLOOR);
+ }
+ }
+ }
+ }
+
+
+ /* Hack -- Affect player */
+ if (flag)
+ {
+ /* Message */
+ msg_print("There is a searing blast of light!");
+
+ /* Blind the player */
+ if (!p_ptr->resist_blind && !p_ptr->resist_lite)
+ {
+ /* Become blind */
+ (void)set_blind(p_ptr->blind + 10 + randint(10));
+ }
+ }
+
+
+ /* Mega-Hack -- Forget the view */
+ p_ptr->update |= (PU_UN_VIEW);
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+
+/*
+ * Induce an "earthquake" of the given radius at the given location.
+ *
+ * This will turn some walls into floors and some floors into walls.
+ *
+ * The player will take damage and "jump" into a safe grid if possible,
+ * otherwise, he will "tunnel" through the rubble instantaneously.
+ *
+ * Monsters will take damage, and "jump" into a safe grid if possible,
+ * otherwise they will be "buried" in the rubble, disappearing from
+ * the level in the same way that they do when genocided.
+ *
+ * Note that thus the player and monsters (except eaters of walls and
+ * passers through walls) will never occupy the same grid as a wall.
+ * Note that as of now (2.7.8) no monster may occupy a "wall" grid, even
+ * for a single turn, unless that monster can pass_walls or kill_walls.
+ * This has allowed massive simplification of the "monster" code.
+ */
+void earthquake(int cy, int cx, int r)
+{
+ int i, t, y, x, yy, xx, dy, dx, oy, ox;
+ int damage = 0;
+ int sn = 0, sy = 0, sx = 0;
+ bool_ hurt = FALSE;
+ cave_type *c_ptr;
+ bool_ map[32][32];
+
+ if (p_ptr->inside_quest)
+ {
+ return;
+ }
+
+ /* Paranoia -- Enforce maximum range */
+ if (r > 12) r = 12;
+
+ /* Clear the "maximal blast" area */
+ for (y = 0; y < 32; y++)
+ {
+ for (x = 0; x < 32; x++)
+ {
+ map[y][x] = FALSE;
+ }
+ }
+
+ /* Check around the epicenter */
+ for (dy = -r; dy <= r; dy++)
+ {
+ for (dx = -r; dx <= r; dx++)
+ {
+ /* Extract the location */
+ yy = cy + dy;
+ xx = cx + dx;
+
+ /* Skip illegal grids */
+ if (!in_bounds(yy, xx)) continue;
+
+ /* Skip distant grids */
+ if (distance(cy, cx, yy, xx) > r) continue;
+
+ /* Access the grid */
+ c_ptr = &cave[yy][xx];
+
+ /* Lose room and vault */
+ c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
+
+ /* Lose light and knowledge */
+ c_ptr->info &= ~(CAVE_GLOW | CAVE_MARK);
+
+ /* Skip the epicenter */
+ if (!dx && !dy) continue;
+
+ /* Skip most grids */
+ if (rand_int(100) < 85) continue;
+
+ /* Damage this grid */
+ map[16 + yy - cy][16 + xx - cx] = TRUE;
+
+ /* Hack -- Take note of player damage */
+ if ((yy == p_ptr->py) && (xx == p_ptr->px)) hurt = TRUE;
+ }
+ }
+
+ /* First, affect the player (if necessary) */
+ if (hurt && !p_ptr->wraith_form)
+ {
+ /* Check around the player */
+ for (i = 0; i < 8; i++)
+ {
+ /* Access the location */
+ y = p_ptr->py + ddy[i];
+ x = p_ptr->px + ddx[i];
+
+ /* Skip non-empty grids */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Important -- Skip "quake" grids */
+ if (map[16 + y - cy][16 + x - cx]) continue;
+
+ /* Count "safe" grids */
+ sn++;
+
+ /* Randomize choice */
+ if (rand_int(sn) > 0) continue;
+
+ /* Save the safe location */
+ sy = y;
+ sx = x;
+ }
+
+ /* Random message */
+ switch (randint(3))
+ {
+ case 1:
+ {
+ msg_print("The cave ceiling collapses!");
+ break;
+ }
+ case 2:
+ {
+ msg_print("The cave floor twists in an unnatural way!");
+ break;
+ }
+ default:
+ {
+ msg_print("The cave quakes! You are pummeled with debris!");
+ break;
+ }
+ }
+
+ /* Hurt the player a lot */
+ if (!sn)
+ {
+ /* Message and damage */
+ msg_print("You are severely crushed!");
+ damage = 300;
+ }
+
+ /* Destroy the grid, and push the player to safety */
+ else
+ {
+ /* Calculate results */
+ switch (randint(3))
+ {
+ case 1:
+ {
+ msg_print("You nimbly dodge the blast!");
+ damage = 0;
+ break;
+ }
+ case 2:
+ {
+ msg_print("You are bashed by rubble!");
+ damage = damroll(10, 4);
+ (void)set_stun(p_ptr->stun + randint(50));
+ break;
+ }
+ case 3:
+ {
+ msg_print("You are crushed between the floor and ceiling!");
+ damage = damroll(10, 4);
+ (void)set_stun(p_ptr->stun + randint(50));
+ break;
+ }
+ }
+
+ /* Save the old location */
+ oy = p_ptr->py;
+ ox = p_ptr->px;
+
+ /* Move the player to the safe location */
+ p_ptr->py = sy;
+ p_ptr->px = sx;
+
+ /* Redraw the old spot */
+ lite_spot(oy, ox);
+
+ /* Redraw the new spot */
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Check for new panel */
+ verify_panel();
+ }
+
+ /* Important -- no wall on player */
+ map[16 + p_ptr->py - cy][16 + p_ptr->px - cx] = FALSE;
+
+ /* Semi-wraiths have to be hurt *some*, says DG */
+ if (PRACE_FLAG(PR1_SEMI_WRAITH))
+ damage /= 4;
+
+ /* Take some damage */
+ if (damage) take_hit(damage, "an earthquake");
+ }
+
+
+ /* Examine the quaked region */
+ for (dy = -r; dy <= r; dy++)
+ {
+ for (dx = -r; dx <= r; dx++)
+ {
+ /* Extract the location */
+ yy = cy + dy;
+ xx = cx + dx;
+
+ /* Skip unaffected grids */
+ if (!map[16 + yy - cy][16 + xx - cx]) continue;
+
+ /* Access the grid */
+ c_ptr = &cave[yy][xx];
+
+ /* Process monsters */
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Most monsters cannot co-exist with rock */
+ if (!(r_ptr->flags2 & (RF2_KILL_WALL)) &&
+ !(r_ptr->flags2 & (RF2_PASS_WALL)))
+ {
+ char m_name[80];
+
+ /* Assume not safe */
+ sn = 0;
+
+ /* Monster can move to escape the wall */
+ if (!(r_ptr->flags1 & (RF1_NEVER_MOVE)))
+ {
+ /* Look for safety */
+ for (i = 0; i < 8; i++)
+ {
+ /* Access the grid */
+ y = yy + ddy[i];
+ x = xx + ddx[i];
+
+ /* Skip non-empty grids */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Hack -- no safety on glyph of warding */
+ if (cave[y][x].feat == FEAT_GLYPH) continue;
+ if (cave[y][x].feat == FEAT_MINOR_GLYPH) continue;
+
+ /* ... nor on the Pattern */
+ if ((cave[y][x].feat <= FEAT_PATTERN_XTRA2) &&
+ (cave[y][x].feat >= FEAT_PATTERN_START))
+ continue;
+
+ /* Important -- Skip "quake" grids */
+ if (map[16 + y - cy][16 + x - cx]) continue;
+
+ /* Count "safe" grids */
+ sn++;
+
+ /* Randomize choice */
+ if (rand_int(sn) > 0) continue;
+
+ /* Save the safe grid */
+ sy = y;
+ sx = x;
+ }
+ }
+
+ /* Describe the monster */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Scream in pain */
+ msg_format("%^s wails out in pain!", m_name);
+
+ /* Take damage from the quake */
+ damage = (sn ? damroll(4, 8) : 200);
+
+ /* Monster is certainly awake */
+ m_ptr->csleep = 0;
+
+ /* Apply damage directly */
+ m_ptr->hp -= damage;
+
+ /* Delete (not kill) "dead" monsters */
+ if (m_ptr->hp < 0)
+ {
+ /* Message */
+ msg_format("%^s is embedded in the rock!", m_name);
+
+ /* Delete the monster */
+ delete_monster(yy, xx);
+
+ /* No longer safe */
+ sn = 0;
+ }
+
+ /* Hack -- Escape from the rock */
+ if (sn)
+ {
+ int m_idx = cave[yy][xx].m_idx;
+
+ /* Update the new location */
+ cave[sy][sx].m_idx = m_idx;
+
+ /* Update the old location */
+ cave[yy][xx].m_idx = 0;
+
+ /* Move the monster */
+ m_ptr->fy = sy;
+ m_ptr->fx = sx;
+
+ /* Update the monster (new location) */
+ update_mon(m_idx, TRUE);
+
+ /* Redraw the old grid */
+ lite_spot(yy, xx);
+
+ /* Redraw the new grid */
+ lite_spot(sy, sx);
+ }
+ }
+ }
+ }
+ }
+
+
+ /* Examine the quaked region */
+ for (dy = -r; dy <= r; dy++)
+ {
+ for (dx = -r; dx <= r; dx++)
+ {
+ /* Extract the location */
+ yy = cy + dy;
+ xx = cx + dx;
+
+ /* Skip unaffected grids */
+ if (!map[16 + yy - cy][16 + xx - cx]) continue;
+
+ /* Access the cave grid */
+ c_ptr = &cave[yy][xx];
+
+ /* Paranoia -- never affect player */
+ if ((yy == p_ptr->py) && (xx == p_ptr->px)) continue;
+
+ /* Destroy location (if valid) */
+ if (cave_valid_bold(yy, xx))
+ {
+ bool_ floor = cave_floor_bold(yy, xx);
+
+ /* Delete objects */
+ delete_object(yy, xx);
+
+ /* Wall (or floor) type */
+ t = (floor ? rand_int(100) : 200);
+
+ /* Granite */
+ if (t < 20)
+ {
+ /* Create granite wall */
+ cave_set_feat(yy, xx, FEAT_WALL_EXTRA);
+ }
+
+ /* Quartz */
+ else if (t < 70)
+ {
+ /* Create quartz vein */
+ cave_set_feat(yy, xx, FEAT_QUARTZ);
+ }
+
+ /* Magma */
+ else if (t < 100)
+ {
+ /* Create magma vein */
+ cave_set_feat(yy, xx, FEAT_MAGMA);
+ }
+
+ /* Floor */
+ else
+ {
+ /* Create floor */
+ cave_set_feat(yy, xx, FEAT_FLOOR);
+ }
+ }
+ }
+ }
+
+
+ /* Mega-Hack -- Forget the view */
+ p_ptr->update |= (PU_UN_VIEW);
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Update the health bar */
+ p_ptr->redraw |= (PR_HEALTH);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+
+
+/*
+ * This routine clears the entire "temp" set.
+ *
+ * This routine will Perma-Lite all "temp" grids.
+ *
+ * This routine is used (only) by "lite_room()"
+ *
+ * Dark grids are illuminated.
+ *
+ * Also, process all affected monsters.
+ *
+ * SMART monsters always wake up when illuminated
+ * NORMAL monsters wake up 1/4 the time when illuminated
+ * STUPID monsters wake up 1/10 the time when illuminated
+ */
+static void cave_temp_room_lite(void)
+{
+ int i;
+
+ /* Apply flag changes */
+ for (i = 0; i < temp_n; i++)
+ {
+ int y = temp_y[i];
+ int x = temp_x[i];
+
+ cave_type *c_ptr = &cave[y][x];
+
+ /* No longer in the array */
+ c_ptr->info &= ~(CAVE_TEMP);
+
+ /* Update only non-CAVE_GLOW grids */
+ /* if (c_ptr->info & (CAVE_GLOW)) continue; */
+
+ /* Perma-Lite */
+ c_ptr->info |= (CAVE_GLOW);
+ }
+
+ /* Fully update the visuals */
+ p_ptr->update |= (PU_UN_VIEW | PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Update stuff */
+ update_stuff();
+
+ /* Process the grids */
+ for (i = 0; i < temp_n; i++)
+ {
+ int y = temp_y[i];
+ int x = temp_x[i];
+
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Redraw the grid */
+ lite_spot(y, x);
+
+ /* Process affected monsters */
+ if (c_ptr->m_idx)
+ {
+ int chance = 25;
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Update the monster */
+ update_mon(c_ptr->m_idx, FALSE);
+
+ /* Stupid monsters rarely wake up */
+ if (r_ptr->flags2 & (RF2_STUPID)) chance = 10;
+
+ /* Smart monsters always wake up */
+ if (r_ptr->flags2 & (RF2_SMART)) chance = 100;
+
+ /* Sometimes monsters wake up */
+ if (m_ptr->csleep && (rand_int(100) < chance))
+ {
+ /* Wake up! */
+ m_ptr->csleep = 0;
+
+ /* Notice the "waking up" */
+ if (m_ptr->ml)
+ {
+ char m_name[80];
+
+ /* Acquire the monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Dump a message */
+ msg_format("%^s wakes up.", m_name);
+ }
+ }
+ }
+ }
+
+ /* None left */
+ temp_n = 0;
+}
+
+
+
+/*
+ * This routine clears the entire "temp" set.
+ *
+ * This routine will "darken" all "temp" grids.
+ *
+ * In addition, some of these grids will be "unmarked".
+ *
+ * This routine is used (only) by "unlite_room()"
+ *
+ * Also, process all affected monsters
+ */
+static void cave_temp_room_unlite(void)
+{
+ int i;
+
+ /* Apply flag changes */
+ for (i = 0; i < temp_n; i++)
+ {
+ int y = temp_y[i];
+ int x = temp_x[i];
+
+ cave_type *c_ptr = &cave[y][x];
+
+ /* No longer in the array */
+ c_ptr->info &= ~(CAVE_TEMP);
+
+ /* Darken the grid */
+ c_ptr->info &= ~(CAVE_GLOW);
+
+ /* Hack -- Forget "boring" grids */
+ if (cave_plain_floor_grid(c_ptr))
+ {
+ /* Forget the grid */
+ c_ptr->info &= ~(CAVE_MARK);
+
+ /* Notice */
+ /* note_spot(y, x); */
+ }
+ }
+
+ /* Fully update the visuals */
+ p_ptr->update |= (PU_UN_VIEW | PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Update stuff */
+ update_stuff();
+
+ /* Process the grids */
+ for (i = 0; i < temp_n; i++)
+ {
+ int y = temp_y[i];
+ int x = temp_x[i];
+
+ /* Redraw the grid */
+ lite_spot(y, x);
+ }
+
+ /* None left */
+ temp_n = 0;
+}
+
+
+
+
+/*
+ * Aux function -- see below
+ */
+static void cave_temp_room_aux(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Avoid infinite recursion */
+ if (c_ptr->info & (CAVE_TEMP)) return;
+
+ /* Do not "leave" the current room */
+ if (!(c_ptr->info & (CAVE_ROOM))) return;
+
+ /* Paranoia -- verify space */
+ if (temp_n == TEMP_MAX) return;
+
+ /* Mark the grid as "seen" */
+ c_ptr->info |= (CAVE_TEMP);
+
+ /* Add it to the "seen" set */
+ temp_y[temp_n] = y;
+ temp_x[temp_n] = x;
+ temp_n++;
+}
+
+
+
+
+/*
+ * Illuminate any room containing the given location.
+ */
+void lite_room(int y1, int x1)
+{
+ int i, x, y;
+
+ /* Add the initial grid */
+ cave_temp_room_aux(y1, x1);
+
+ /* While grids are in the queue, add their neighbors */
+ for (i = 0; i < temp_n; i++)
+ {
+ x = temp_x[i], y = temp_y[i];
+
+ /* Walls get lit, but stop light */
+ if (!cave_floor_bold(y, x)) continue;
+
+ /* Spread adjacent */
+ cave_temp_room_aux(y + 1, x);
+ cave_temp_room_aux(y - 1, x);
+ cave_temp_room_aux(y, x + 1);
+ cave_temp_room_aux(y, x - 1);
+
+ /* Spread diagonal */
+ cave_temp_room_aux(y + 1, x + 1);
+ cave_temp_room_aux(y - 1, x - 1);
+ cave_temp_room_aux(y - 1, x + 1);
+ cave_temp_room_aux(y + 1, x - 1);
+ }
+
+ /* Now, lite them all up at once */
+ cave_temp_room_lite();
+}
+
+
+/*
+ * Darken all rooms containing the given location
+ */
+void unlite_room(int y1, int x1)
+{
+ int i, x, y;
+
+ /* Add the initial grid */
+ cave_temp_room_aux(y1, x1);
+
+ /* Spread, breadth first */
+ for (i = 0; i < temp_n; i++)
+ {
+ x = temp_x[i], y = temp_y[i];
+
+ /* Walls get dark, but stop darkness */
+ if (!cave_floor_bold(y, x)) continue;
+
+ /* Spread adjacent */
+ cave_temp_room_aux(y + 1, x);
+ cave_temp_room_aux(y - 1, x);
+ cave_temp_room_aux(y, x + 1);
+ cave_temp_room_aux(y, x - 1);
+
+ /* Spread diagonal */
+ cave_temp_room_aux(y + 1, x + 1);
+ cave_temp_room_aux(y - 1, x - 1);
+ cave_temp_room_aux(y - 1, x + 1);
+ cave_temp_room_aux(y + 1, x - 1);
+ }
+
+ /* Now, darken them all at once */
+ cave_temp_room_unlite();
+}
+
+
+
+/*
+ * Hack -- call light around the player
+ * Affect all monsters in the projection radius
+ */
+bool_ lite_area(int dam, int rad)
+{
+ int flg = PROJECT_GRID | PROJECT_KILL;
+
+ /* Hack -- Message */
+ if (!p_ptr->blind)
+ {
+ msg_print("You are surrounded by a white light.");
+ }
+
+ /* Hook into the "project()" function */
+ (void)project(0, rad, p_ptr->py, p_ptr->px, dam, GF_LITE_WEAK, flg);
+
+ /* Lite up the room */
+ lite_room(p_ptr->py, p_ptr->px);
+
+ /* Assume seen */
+ return (TRUE);
+}
+
+
+/*
+ * Hack -- call darkness around the player
+ * Affect all monsters in the projection radius
+ */
+bool_ unlite_area(int dam, int rad)
+{
+ int flg = PROJECT_GRID | PROJECT_KILL;
+
+ /* Hack -- Message */
+ if (!p_ptr->blind)
+ {
+ msg_print("Darkness surrounds you.");
+ }
+
+ /* Hook into the "project()" function */
+ (void)project(0, rad, p_ptr->py, p_ptr->px, dam, GF_DARK_WEAK, flg);
+
+ /* Lite up the room */
+ unlite_room(p_ptr->py, p_ptr->px);
+
+ /* Assume seen */
+ return (TRUE);
+}
+
+
+/*
+ * Cast a ball spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+bool_ fire_ball(int typ, int dir, int dam, int rad)
+{
+ int tx, ty;
+
+ int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+
+ /* Use the given direction */
+ tx = p_ptr->px + 99 * ddx[dir];
+ ty = p_ptr->py + 99 * ddy[dir];
+
+ /* Hack -- Use an actual "target" */
+ if ((dir == 5) && target_okay())
+ {
+ flg &= ~(PROJECT_STOP);
+ tx = target_col;
+ ty = target_row;
+ }
+
+ /* Analyze the "dir" and the "target". Hurt items on floor. */
+ return (project(0, (rad > 16) ? 16 : rad, ty, tx, dam, typ, flg));
+}
+
+/*
+ * Cast a cloud spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+bool_ fire_cloud(int typ, int dir, int dam, int rad, int time)
+{
+ int tx, ty;
+
+ int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_STAY;
+
+ /* Use the given direction */
+ tx = p_ptr->px + 99 * ddx[dir];
+ ty = p_ptr->py + 99 * ddy[dir];
+
+ /* Hack -- Use an actual "target" */
+ if ((dir == 5) && target_okay())
+ {
+ flg &= ~(PROJECT_STOP);
+ tx = target_col;
+ ty = target_row;
+ }
+ project_time = time;
+
+ /* Analyze the "dir" and the "target". Hurt items on floor. */
+ return (project(0, (rad > 16) ? 16 : rad, ty, tx, dam, typ, flg));
+}
+
+/*
+ * Cast a wave spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+bool_ fire_wave(int typ, int dir, int dam, int rad, int time, s32b eff)
+{
+ project_time_effect = eff;
+ return (fire_cloud(typ, dir, dam, rad, time));
+}
+
+/*
+ * Cast a persistant beam spell
+ * Pass through monsters, as a "beam"
+ * Affect monsters (not grids or objects)
+ */
+bool_ fire_wall(int typ, int dir, int dam, int time)
+{
+ int flg = PROJECT_BEAM | PROJECT_KILL | PROJECT_STAY | PROJECT_GRID;
+ project_time = time;
+ return (project_hook(typ, dir, dam, flg));
+}
+
+/*
+ * Cast a druidistic ball spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+bool_ fire_druid_ball(int typ, int dir, int dam, int rad)
+{
+ int tx, ty;
+
+ int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_MANA_PATH;
+
+ /* Use the given direction */
+ tx = p_ptr->px + 99 * ddx[dir];
+ ty = p_ptr->py + 99 * ddy[dir];
+
+ /* Hack -- Use an actual "target" */
+ if ((dir == 5) && target_okay())
+ {
+ flg &= ~(PROJECT_STOP);
+ tx = target_col;
+ ty = target_row;
+ }
+
+ /* Analyze the "dir" and the "target". Hurt items on floor. */
+ return (project(0, (rad > 16) ? 16 : rad, ty, tx, dam, typ, flg));
+}
+
+
+/*
+ * Cast a ball-beamed spell
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ */
+bool_ fire_ball_beam(int typ, int dir, int dam, int rad)
+{
+ int tx, ty;
+
+ int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_BEAM;
+
+ /* Use the given direction */
+ tx = p_ptr->px + 99 * ddx[dir];
+ ty = p_ptr->py + 99 * ddy[dir];
+
+ /* Hack -- Use an actual "target" */
+ if ((dir == 5) && target_okay())
+ {
+ flg &= ~(PROJECT_STOP);
+ tx = target_col;
+ ty = target_row;
+ }
+
+ /* Analyze the "dir" and the "target". Hurt items on floor. */
+ return (project(0, (rad > 16) ? 16 : rad, ty, tx, dam, typ, flg));
+}
+
+
+void teleport_swap(int dir)
+{
+ int tx, ty;
+ cave_type * c_ptr;
+ monster_type * m_ptr;
+ monster_race * r_ptr;
+
+ if (p_ptr->resist_continuum)
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return;
+ }
+
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+ }
+ else
+ {
+ tx = p_ptr->px + ddx[dir];
+ ty = p_ptr->py + ddy[dir];
+ }
+ c_ptr = &cave[ty][tx];
+
+ if (!c_ptr->m_idx)
+ {
+ msg_print("You can't trade places with that!");
+ }
+ else
+ {
+ m_ptr = &m_list[c_ptr->m_idx];
+ r_ptr = race_inf(m_ptr);
+
+ if (r_ptr->flags3 & RF3_RES_TELE)
+ {
+ msg_print("Your teleportation is blocked!");
+ }
+ else
+ {
+ sound(SOUND_TELEPORT);
+
+ cave[p_ptr->py][p_ptr->px].m_idx = c_ptr->m_idx;
+
+ /* Update the old location */
+ c_ptr->m_idx = 0;
+
+ /* Move the monster */
+ m_ptr->fy = p_ptr->py;
+ m_ptr->fx = p_ptr->px;
+
+ /* Move the player */
+ p_ptr->px = tx;
+ p_ptr->py = ty;
+
+ tx = m_ptr->fx;
+ ty = m_ptr->fy;
+
+ /* Update the monster (new location) */
+ update_mon(cave[ty][tx].m_idx, TRUE);
+
+ /* Redraw the old grid */
+ lite_spot(ty, tx);
+
+ /* Redraw the new grid */
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Execute the inscription */
+ c_ptr = &cave[m_ptr->fy][m_ptr->fx];
+ if (c_ptr->inscription)
+ {
+ if (inscription_info[c_ptr->inscription].when & INSCRIP_EXEC_MONST_WALK)
+ {
+ execute_inscription(c_ptr->inscription, m_ptr->fy, m_ptr->fx);
+ }
+ }
+ c_ptr = &cave[p_ptr->py][p_ptr->px];
+ if (c_ptr->inscription)
+ {
+ msg_format("There is an inscription here: %s", inscription_info[c_ptr->inscription].text);
+ if (inscription_info[c_ptr->inscription].when & INSCRIP_EXEC_WALK)
+ {
+ execute_inscription(c_ptr->inscription, p_ptr->py, p_ptr->px);
+ }
+ }
+
+ /* Check for new panel (redraw map) */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Redraw trap detection status */
+ p_ptr->redraw |= (PR_DTRAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff XXX XXX XXX */
+ handle_stuff();
+ }
+ }
+}
+
+void swap_position(int lty, int ltx)
+{
+ int tx = ltx, ty = lty;
+ cave_type * c_ptr;
+ monster_type * m_ptr;
+
+ if (p_ptr->resist_continuum)
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return;
+ }
+
+ c_ptr = &cave[ty][tx];
+
+ if (!c_ptr->m_idx)
+ {
+ sound(SOUND_TELEPORT);
+
+ /* Keep trace of the old location */
+ tx = p_ptr->px;
+ ty = p_ptr->py;
+
+ /* Move the player */
+ p_ptr->px = ltx;
+ p_ptr->py = lty;
+
+ /* Redraw the old grid */
+ lite_spot(ty, tx);
+
+ /* Redraw the new grid */
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Check for new panel (redraw map) */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Redraw trap detection status */
+ p_ptr->redraw |= (PR_DTRAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff XXX XXX XXX */
+ handle_stuff();
+ }
+ else
+ {
+ m_ptr = &m_list[c_ptr->m_idx];
+
+ sound(SOUND_TELEPORT);
+
+ cave[p_ptr->py][p_ptr->px].m_idx = c_ptr->m_idx;
+
+ /* Update the old location */
+ c_ptr->m_idx = 0;
+
+ /* Move the monster */
+ m_ptr->fy = p_ptr->py;
+ m_ptr->fx = p_ptr->px;
+
+ /* Move the player */
+ p_ptr->px = tx;
+ p_ptr->py = ty;
+
+ tx = m_ptr->fx;
+ ty = m_ptr->fy;
+
+ /* Update the monster (new location) */
+ update_mon(cave[ty][tx].m_idx, TRUE);
+
+ /* Redraw the old grid */
+ lite_spot(ty, tx);
+
+ /* Redraw the new grid */
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Check for new panel (redraw map) */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Redraw trap detection status */
+ p_ptr->redraw |= (PR_DTRAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff XXX XXX XXX */
+ handle_stuff();
+ }
+}
+
+
+/*
+ * Hack -- apply a "projection()" in a direction (or at the target)
+ */
+bool_ project_hook(int typ, int dir, int dam, int flg)
+{
+ int tx, ty;
+
+ /* Pass through the target if needed */
+ flg |= (PROJECT_THRU);
+
+ /* Use the given direction */
+ tx = p_ptr->px + ddx[dir];
+ ty = p_ptr->py + ddy[dir];
+
+ /* Hack -- Use an actual "target" */
+ if ((dir == 5) && target_okay())
+ {
+ tx = target_col;
+ ty = target_row;
+ }
+
+ /* Analyze the "dir" and the "target", do NOT explode */
+ return (project(0, 0, ty, tx, dam, typ, flg));
+}
+
+
+/*
+ * Cast a bolt spell
+ * Stop if we hit a monster, as a "bolt"
+ * Affect monsters (not grids or objects)
+ */
+bool_ fire_bolt(int typ, int dir, int dam)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(typ, dir, dam, flg));
+}
+
+/*
+ * Cast a druidistic bolt spell
+ * Stop if we hit a monster, as a "bolt"
+ * Affect monsters (not grids or objects)
+ */
+bool_ fire_druid_bolt(int typ, int dir, int dam)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_MANA_PATH;
+ return (project_hook(typ, dir, dam, flg));
+}
+
+
+/*
+ * Cast a druidistic beam spell
+ * Pass through monsters, as a "beam"
+ * Affect monsters (not grids or objects)
+ */
+bool_ fire_druid_beam(int typ, int dir, int dam)
+{
+ int flg = PROJECT_BEAM | PROJECT_KILL | PROJECT_MANA_PATH;
+ return (project_hook(typ, dir, dam, flg));
+}
+
+/*
+ * Cast a beam spell
+ * Pass through monsters, as a "beam"
+ * Affect monsters (not grids or objects)
+ */
+bool_ fire_beam(int typ, int dir, int dam)
+{
+ int flg = PROJECT_BEAM | PROJECT_KILL;
+ return (project_hook(typ, dir, dam, flg));
+}
+
+
+/*
+ * Cast a bolt spell, or rarely, a beam spell
+ */
+bool_ fire_bolt_or_beam(int prob, int typ, int dir, int dam)
+{
+ if (rand_int(100) < prob)
+ {
+ return (fire_beam(typ, dir, dam));
+ }
+ else
+ {
+ return (fire_bolt(typ, dir, dam));
+ }
+}
+
+bool_ fire_godly_wrath(int y, int x, int typ, int rad, int dam)
+{
+ int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+
+ return (project(0, rad, y, x, dam, typ, flg));
+}
+
+bool_ fire_explosion(int y, int x, int typ, int rad, int dam)
+{
+ int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+
+ return (project(0, rad, y, x, dam, typ, flg));
+}
+
+/*
+ * Some of the old functions
+ */
+bool_ lite_line(int dir)
+{
+ int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_KILL;
+ return (project_hook(GF_LITE_WEAK, dir, damroll(6, 8), flg));
+}
+
+
+bool_ drain_life(int dir, int dam)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_OLD_DRAIN, dir, dam, flg));
+}
+
+
+bool_ wall_to_mud(int dir)
+{
+ int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+ return (project_hook(GF_KILL_WALL, dir, 20 + randint(30), flg));
+}
+
+
+bool_ wizard_lock(int dir)
+{
+ int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+ return (project_hook(GF_JAM_DOOR, dir, 20 + randint(30), flg));
+}
+
+
+bool_ destroy_door(int dir)
+{
+ int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM;
+ return (project_hook(GF_KILL_DOOR, dir, 0, flg));
+}
+
+
+bool_ disarm_trap(int dir)
+{
+ int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM;
+ return (project_hook(GF_KILL_TRAP, dir, 0, flg));
+}
+
+
+bool_ heal_monster(int dir)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_OLD_HEAL, dir, damroll(4, 6), flg));
+}
+
+
+bool_ speed_monster(int dir)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_OLD_SPEED, dir, p_ptr->lev, flg));
+}
+
+
+bool_ slow_monster(int dir)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_OLD_SLOW, dir, p_ptr->lev, flg));
+}
+
+
+bool_ sleep_monster(int dir)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_OLD_SLEEP, dir, p_ptr->lev, flg));
+}
+
+
+bool_ stasis_monster(int dir)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_STASIS, dir, p_ptr->lev, flg));
+}
+
+
+bool_ confuse_monster(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_OLD_CONF, dir, plev, flg));
+}
+
+
+bool_ stun_monster(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_STUN, dir, plev, flg));
+}
+
+
+bool_ poly_monster(int dir)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_OLD_POLY, dir, p_ptr->lev, flg));
+}
+
+
+bool_ clone_monster(int dir)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_OLD_CLONE, dir, 0, flg));
+}
+
+
+bool_ fear_monster(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_TURN_ALL, dir, plev, flg));
+}
+
+
+bool_ death_ray(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_DEATH_RAY, dir, plev, flg));
+}
+
+
+bool_ teleport_monster(int dir)
+{
+ int flg = PROJECT_BEAM | PROJECT_KILL;
+
+ if (p_ptr->resist_continuum)
+ {
+ msg_print("The space-time continuum can't be disrupted.");
+ return FALSE;
+ }
+
+ return (project_hook(GF_AWAY_ALL, dir, MAX_SIGHT * 5, flg));
+}
+
+
+/*
+ * Hooks -- affect adjacent grids (radius 1 ball attack)
+ */
+bool_ door_creation(void)
+{
+ int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
+ return (project(0, 1, p_ptr->py, p_ptr->px, 0, GF_MAKE_DOOR, flg));
+}
+
+
+bool_ trap_creation(void)
+{
+ int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
+ return (project(0, 1, p_ptr->py, p_ptr->px, 0, GF_MAKE_TRAP, flg));
+}
+
+
+bool_ glyph_creation(void)
+{
+ int flg = PROJECT_GRID | PROJECT_ITEM;
+ return (project(0, 1, p_ptr->py, p_ptr->px, 0, GF_MAKE_GLYPH, flg));
+}
+
+
+bool_ wall_stone(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+ int flg = PROJECT_GRID | PROJECT_ITEM;
+ int featflags = f_info[c_ptr->feat].flags1;
+
+ bool_ dummy = (project(0, 1, y, x, 0, GF_STONE_WALL, flg));
+
+ if (!(featflags & FF1_PERMANENT) && !(featflags & FF1_WALL))
+ cave_set_feat(y, x, FEAT_FLOOR);
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ return dummy;
+}
+
+
+bool_ destroy_doors_touch(void)
+{
+ int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
+ return (project(0, 1, p_ptr->py, p_ptr->px, 0, GF_KILL_DOOR, flg));
+}
+
+bool_ destroy_traps_touch(void)
+{
+ int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
+ return (project(0, 1, p_ptr->py, p_ptr->px, 0, GF_KILL_TRAP, flg));
+}
+
+bool_ sleep_monsters_touch(void)
+{
+ int flg = PROJECT_KILL | PROJECT_HIDE;
+ return (project(0, 1, p_ptr->py, p_ptr->px, p_ptr->lev, GF_OLD_SLEEP, flg));
+}
+
+
+void call_chaos(void)
+{
+ int Chaos_type, dummy, dir;
+ int plev = p_ptr->lev;
+ bool_ line_chaos = FALSE;
+
+ int hurt_types[30] =
+ {
+ GF_ELEC, GF_POIS, GF_ACID, GF_COLD,
+ GF_FIRE, GF_MISSILE, GF_ARROW, GF_PLASMA,
+ GF_HOLY_FIRE, GF_WATER, GF_LITE, GF_DARK,
+ GF_FORCE, GF_INERTIA, GF_MANA, GF_METEOR,
+ GF_ICE, GF_CHAOS, GF_NETHER, GF_DISENCHANT,
+ GF_SHARDS, GF_SOUND, GF_NEXUS, GF_CONFUSION,
+ GF_TIME, GF_GRAVITY, GF_ROCKET, GF_NUKE,
+ GF_HELL_FIRE, GF_DISINTEGRATE
+ };
+
+ Chaos_type = hurt_types[randint(30) - 1];
+ if (randint(4) == 1) line_chaos = TRUE;
+
+ if (randint(6) == 1)
+ {
+ for (dummy = 1; dummy < 10; dummy++)
+ {
+ if (dummy - 5)
+ {
+ if (line_chaos)
+ fire_beam(Chaos_type, dummy, 75);
+ else
+ fire_ball(Chaos_type, dummy, 75, 2);
+ }
+ }
+ }
+ else if (randint(3) == 1)
+ {
+ fire_ball(Chaos_type, 0, 300, 8);
+ }
+ else
+ {
+ if (!get_aim_dir(&dir)) return;
+ if (line_chaos)
+ fire_beam(Chaos_type, dir, 150);
+ else
+ fire_ball(Chaos_type, dir, 150, 3 + (plev / 35));
+ }
+}
+
+
+/*
+ * Activate the evil Topi Ylinen curse
+ * rr9: Stop the nasty things when a Cyberdemon is summoned
+ * or the player gets paralyzed.
+ */
+void activate_ty_curse(void)
+{
+ int i = 0;
+ bool_ stop_ty = FALSE;
+
+ do
+ {
+ switch (randint(27))
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 16:
+ case 17:
+ aggravate_monsters(1);
+ if (randint(6) != 1) break;
+ case 4:
+ case 5:
+ case 6:
+ activate_hi_summon();
+ if (randint(6) != 1) break;
+case 7: case 8: case 9: case 18:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, 0);
+ if (randint(6) != 1) break;
+case 10: case 11: case 12:
+ msg_print("You feel your life draining away...");
+ lose_exp(p_ptr->exp / 16);
+ if (randint(6) != 1) break;
+case 13: case 14: case 15: case 19: case 20:
+ if (p_ptr->free_act && (randint(100) < p_ptr->skill_sav))
+ {
+ /* Do nothing */ ;
+ }
+ else
+ {
+ msg_print("You feel like a statue!");
+ if (p_ptr->free_act)
+ set_paralyzed (p_ptr->paralyzed + randint(3));
+ else
+ set_paralyzed (p_ptr->paralyzed + randint(13));
+ stop_ty = TRUE;
+ }
+ if (randint(6) != 1) break;
+case 21: case 22: case 23:
+ (void)do_dec_stat((randint(6)) - 1, STAT_DEC_NORMAL);
+ if (randint(6) != 1) break;
+ case 24:
+ msg_print("Huh? Who am I? What am I doing here?");
+ lose_all_info();
+ break;
+ case 25:
+ /*
+ * Only summon Cyberdemons deep in the dungeon.
+ */
+ if ((dun_level > 65) && !stop_ty)
+ {
+ summon_cyber();
+ stop_ty = TRUE;
+ break;
+ }
+ default:
+ while (i < 6)
+ {
+ do
+ {
+ (void)do_dec_stat(i, STAT_DEC_NORMAL);
+ }
+ while (randint(2) == 1);
+
+ i++;
+ }
+ }
+ }
+ while ((randint(3) == 1) && !stop_ty);
+}
+
+/*
+ * Activate the ultra evil Dark God curse
+ */
+void activate_dg_curse(void)
+{
+ int i = 0;
+ bool_ stop_dg = FALSE;
+
+ do
+ {
+ switch (randint(30))
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 16:
+ case 17:
+ aggravate_monsters(1);
+ if (randint(8) != 1) break;
+ case 4:
+ case 5:
+ case 6:
+ msg_print("Oh! You feel that the curse is replicating itself!");
+ curse_equipment_dg(100, 50 * randint(2));
+ if (randint(8) != 1) break;
+ case 7:
+ case 8:
+ case 9:
+ case 18:
+ curse_equipment(100, 50 * randint(2));
+ if (randint(8) != 1) break;
+ case 10:
+ case 11:
+ case 12:
+ msg_print("You feel your life draining away...");
+ lose_exp(p_ptr->exp / 12);
+ if (rand_int(2))
+ {
+ msg_print("You feel the coldness of the Black Breath attacking you!");
+ p_ptr->black_breath = TRUE;
+ }
+ if (randint(8) != 1) break;
+ case 13:
+ case 14:
+ case 15:
+ if (p_ptr->free_act && (randint(100) < p_ptr->skill_sav))
+ {
+ /* Do nothing */ ;
+ }
+ else
+ {
+ msg_print("You feel like a statue!");
+ if (p_ptr->free_act)
+ set_paralyzed (p_ptr->paralyzed + randint(3));
+ else
+ set_paralyzed (p_ptr->paralyzed + randint(13));
+ stop_dg = TRUE;
+ }
+ if (randint(7) != 1) break;
+ case 19:
+ case 20:
+ {
+ msg_print("Woah! You see 10 little Morgoths dancing before you!");
+ set_confused(p_ptr->confused + randint(13 * 2));
+ if (rand_int(2)) stop_dg = TRUE;
+ }
+ if (randint(7) != 1) break;
+ case 21:
+ case 22:
+ case 23:
+ (void)do_dec_stat((randint(6)) - 1, STAT_DEC_PERMANENT);
+ if (randint(7) != 1) break;
+ case 24:
+ msg_print("Huh? Who am I? What am I doing here?");
+ lose_all_info();
+ break;
+case 27: case 28: case 29:
+ if (p_ptr->inventory[INVEN_WIELD].k_idx)
+ {
+ msg_print("Your weapon now seems useless...");
+ p_ptr->inventory[INVEN_WIELD].art_flags4 = TR4_NEVER_BLOW;
+ }
+ break;
+ case 25:
+ /*
+ * Only summon Thunderlords not too shallow in the dungeon.
+ */
+ if ((dun_level > 25) && !stop_dg)
+ {
+ msg_print("Oh! You attracted some evil Thunderlords!");
+ summon_dragon_riders();
+
+ /* This is evil -- DG */
+ if (rand_int(2)) stop_dg = TRUE;
+ break;
+ }
+ default:
+ while (i < 6)
+ {
+ do
+ {
+ (void)do_dec_stat(i, STAT_DEC_NORMAL);
+ }
+ while (randint(2) == 1);
+
+ i++;
+ }
+ }
+ }
+ while ((randint(4) == 1) && !stop_dg);
+}
+
+
+void activate_hi_summon(void)
+{
+ int i;
+
+ for (i = 0; i < (randint(9) + (dun_level / 40)); i++)
+ {
+ switch (randint(26) + (dun_level / 20) )
+ {
+ case 1:
+ case 2:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_ANT);
+ break;
+ case 3:
+ case 4:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_SPIDER);
+ break;
+ case 5:
+ case 6:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_HOUND);
+ break;
+ case 7:
+ case 8:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_HYDRA);
+ break;
+ case 9:
+ case 10:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_ANGEL);
+ break;
+ case 11:
+ case 12:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_UNDEAD);
+ break;
+ case 13:
+ case 14:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_DRAGON);
+ break;
+ case 15:
+ case 16:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_DEMON);
+ break;
+ case 17:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_WRAITH);
+ break;
+ case 18:
+ case 19:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_UNIQUE);
+ break;
+ case 20:
+ case 21:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_HI_UNDEAD);
+ break;
+ case 22:
+ case 23:
+ (void) summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_HI_DRAGON);
+ break;
+ case 24:
+ case 25:
+ (void) summon_specific(p_ptr->py, p_ptr->px, 100, SUMMON_HI_DEMON);
+ break;
+ default:
+ (void) summon_specific(p_ptr->py, p_ptr->px, (((dun_level * 3) / 2) + 5), 0);
+ }
+ }
+}
+
+
+void summon_cyber(void)
+{
+ int i;
+ int max_cyber = (dun_level / 50) + randint(6);
+
+ for (i = 0; i < max_cyber; i++)
+ {
+ (void)summon_specific(p_ptr->py, p_ptr->px, 100, SUMMON_HI_DEMON);
+ }
+}
+
+void summon_dragon_riders()
+{
+ int i;
+ int max_dr = (dun_level / 50) + randint(6);
+
+ for (i = 0; i < max_dr; i++)
+ {
+ (void)summon_specific(p_ptr->py, p_ptr->px, 100, SUMMON_THUNDERLORD);
+ }
+}
+
+
+void wall_breaker(void)
+{
+ int dummy = 5;
+
+ if (randint(80 + p_ptr->lev) < 70)
+ {
+ do
+ {
+ dummy = randint(9);
+ }
+ while ((dummy == 5) || (dummy == 0));
+
+ wall_to_mud (dummy);
+ }
+ else if (randint(100) > 30)
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(p_ptr->py, p_ptr->px, 1);
+ }
+ else
+ {
+ for (dummy = 1; dummy < 10; dummy++)
+ {
+ if (dummy - 5) wall_to_mud(dummy);
+ }
+ }
+}
+
+
+void bless_weapon(void)
+{
+ int item;
+ object_type *o_ptr;
+ u32b f1, f2, f3, f4, f5, esp;
+ char o_name[80];
+ cptr q, s;
+
+ /* Assume enchant weapon */
+ item_tester_hook = item_tester_hook_weapon;
+
+ /* Get an item */
+ q = "Bless which weapon? ";
+ s = "You have weapon to bless.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ /* Description */
+ object_desc(o_name, o_ptr, FALSE, 0);
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (o_ptr->ident & (IDENT_CURSED))
+ {
+
+ if (((f3 & (TR3_HEAVY_CURSE)) && (randint (100) < 33)) ||
+ (f3 & (TR3_PERMA_CURSE)))
+ {
+
+ msg_format("The black aura on %s %s disrupts the blessing!",
+ ((item >= 0) ? "your" : "the"), o_name);
+ return;
+ }
+
+ msg_format("A malignant aura leaves %s %s.",
+ ((item >= 0) ? "your" : "the"), o_name);
+
+ /* Uncurse it */
+ o_ptr->ident &= ~(IDENT_CURSED);
+
+ /* Hack -- Assume felt */
+ o_ptr->ident |= (IDENT_SENSE);
+
+ /* Take note */
+ o_ptr->sense = SENSE_UNCURSED;
+
+ /* Recalculate the bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP);
+ }
+
+ /*
+ * Next, we try to bless it. Artifacts have a 1/3 chance of
+ * being blessed, otherwise, the operation simply disenchants
+ * them, godly power negating the magic. Ok, the explanation
+ * is silly, but otherwise priests would always bless every
+ * artifact weapon they find. Ego weapons and normal weapons
+ * can be blessed automatically.
+ */
+ if (f3 & TR3_BLESSED)
+ {
+ msg_format("%s %s %s blessed already.",
+ ((item >= 0) ? "Your" : "The"), o_name,
+ ((o_ptr->number > 1) ? "were" : "was"));
+ return;
+ }
+
+ if (!(o_ptr->art_name || o_ptr->name1) || (randint(3) == 1))
+ {
+ /* Describe */
+ msg_format("%s %s shine%s!",
+ ((item >= 0) ? "Your" : "The"), o_name,
+ ((o_ptr->number > 1) ? "" : "s"));
+ o_ptr->art_flags3 |= TR3_BLESSED;
+ }
+ else
+ {
+ bool_ dis_happened = FALSE;
+
+ msg_print("The artifact resists your blessing!");
+
+ /* Disenchant tohit */
+ if (o_ptr->to_h > 0)
+ {
+ o_ptr->to_h--;
+ dis_happened = TRUE;
+ }
+
+ if ((o_ptr->to_h > 5) && (rand_int(100) < 33)) o_ptr->to_h--;
+
+ /* Disenchant todam */
+ if (o_ptr->to_d > 0)
+ {
+ o_ptr->to_d--;
+ dis_happened = TRUE;
+ }
+
+ if ((o_ptr->to_d > 5) && (rand_int(100) < 33)) o_ptr->to_d--;
+
+ /* Disenchant toac */
+ if (o_ptr->to_a > 0)
+ {
+ o_ptr->to_a--;
+ dis_happened = TRUE;
+ }
+
+ if ((o_ptr->to_a > 5) && (rand_int(100) < 33)) o_ptr->to_a--;
+
+ if (dis_happened)
+ {
+ msg_print("There is a static feeling in the air...");
+ msg_format("%s %s %s disenchanted!",
+ ((item >= 0) ? "Your" : "The"), o_name,
+ ((o_ptr->number > 1) ? "were" : "was"));
+ }
+ }
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_EQUIP | PW_PLAYER);
+}
+
+
+/*
+ * Detect all "nonliving", "undead" or "demonic" monsters on current panel
+ */
+bool_ detect_monsters_nonliving(int rad)
+{
+ int i, y, x;
+ bool_ flag = FALSE;
+
+ /* Scan monsters */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Only detect nearby monsters */
+ if (m_ptr->cdis > rad) continue;
+
+ /* Detect evil monsters */
+ if ((r_ptr->flags3 & (RF3_NONLIVING)) ||
+ (r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags3 & (RF3_DEMON)))
+ {
+ /* Update monster recall window */
+ if (monster_race_idx == m_ptr->r_idx)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MONSTER);
+ }
+
+ /* Repair visibility later */
+ repair_monsters = TRUE;
+
+ /* Hack -- Detect monster */
+ m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
+
+ /* Hack -- See monster */
+ m_ptr->ml = TRUE;
+
+ /* Redraw */
+ if (panel_contains(y, x)) lite_spot(y, x);
+
+ /* Detect */
+ flag = TRUE;
+ }
+ }
+
+ /* Describe */
+ if (flag)
+ {
+ /* Describe result */
+ msg_print("You sense the presence of unnatural beings!");
+ }
+
+ /* Result */
+ return (flag);
+}
+
+
+/*
+ * Confuse monsters
+ */
+bool_ confuse_monsters(int dam)
+{
+ return (project_hack(GF_OLD_CONF, dam));
+}
+
+
+/*
+ * Charm monsters
+ */
+bool_ charm_monsters(int dam)
+{
+ return (project_hack(GF_CHARM, dam));
+}
+
+
+/*
+ * Charm animals
+ */
+bool_ charm_animals(int dam)
+{
+ return (project_hack(GF_CONTROL_ANIMAL, dam));
+}
+
+/*
+ * Charm demons
+ */
+bool_ charm_demons(int dam)
+{
+ return (project_hack(GF_CONTROL_DEMON, dam));
+}
+
+
+/*
+ * Stun monsters
+ */
+bool_ stun_monsters(int dam)
+{
+ return (project_hack(GF_STUN, dam));
+}
+
+
+/*
+ * Stasis monsters
+ */
+bool_ stasis_monsters(int dam)
+{
+ return (project_hack(GF_STASIS, dam));
+}
+
+
+/*
+ * Mindblast monsters
+ */
+bool_ mindblast_monsters(int dam)
+{
+ return (project_hack(GF_PSI, dam));
+}
+
+
+/*
+ * Banish all monsters
+ */
+bool_ banish_monsters(int dist)
+{
+ return (project_hack(GF_AWAY_ALL, dist));
+}
+
+
+/*
+ * Turn evil
+ */
+bool_ turn_evil(int dam)
+{
+ return (project_hack(GF_TURN_EVIL, dam));
+}
+
+
+/*
+ * Turn everyone
+ */
+bool_ turn_monsters(int dam)
+{
+ return (project_hack(GF_TURN_ALL, dam));
+}
+
+
+/*
+ * Death-ray all monsters (note: OBSCENELY powerful)
+ */
+bool_ deathray_monsters(void)
+{
+ return (project_hack(GF_DEATH_RAY, p_ptr->lev));
+}
+
+
+bool_ charm_monster(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_CHARM, dir, plev, flg));
+}
+
+bool_ star_charm_monster(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_STAR_CHARM, dir, plev, flg));
+}
+
+
+bool_ control_one_undead(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_CONTROL_UNDEAD, dir, plev, flg));
+}
+
+
+bool_ charm_animal(int dir, int plev)
+{
+ int flg = PROJECT_STOP | PROJECT_KILL;
+ return (project_hook(GF_CONTROL_ANIMAL, dir, plev, flg));
+}
+
+void change_wild_mode(void)
+{
+ if (p_ptr->immovable && !p_ptr->wild_mode)
+ {
+ msg_print("Hmm, blinking there will take time.");
+ }
+
+ if (p_ptr->word_recall && !p_ptr->wild_mode)
+ {
+ msg_print("You will soon be recalled.");
+ return;
+ }
+
+ p_ptr->wild_mode = !p_ptr->wild_mode;
+
+ autosave_checkpoint();
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+}
+
+
+void alter_reality(void)
+{
+ msg_print("The world changes!");
+
+ autosave_checkpoint();
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+}
+
+/* Heal insanity. */
+bool_ heal_insanity(int val)
+{
+ if (p_ptr->csane < p_ptr->msane)
+ {
+ p_ptr->csane += val;
+
+ if (p_ptr->csane >= p_ptr->msane)
+ {
+ p_ptr->csane = p_ptr->msane;
+ p_ptr->csane_frac = 0;
+ }
+
+ p_ptr->redraw |= PR_SANITY;
+ p_ptr->window |= (PW_PLAYER);
+
+ if (val < 5)
+ {
+ msg_print("You feel a little better.");
+ }
+ else if (val < 15)
+ {
+ msg_print("You feel better.");
+ }
+ else if (val < 35)
+ {
+ msg_print("You feel much better.");
+ }
+ else
+ {
+ msg_print("You feel very good.");
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Send the player shooting through walls in the given direction until
+ * they reach a non-wall space, or a monster, or a permanent wall.
+ */
+bool_ passwall(int dir, bool_ safe)
+{
+ int x = p_ptr->px, y = p_ptr->py, ox = p_ptr->px, oy = p_ptr->py, lx = p_ptr->px, ly = p_ptr->py;
+ cave_type *c_ptr;
+ bool_ ok = FALSE;
+
+ if (p_ptr->wild_mode) return FALSE;
+ if (p_ptr->inside_quest) return FALSE;
+ if (dungeon_flags2 & DF2_NO_TELEPORT) return FALSE;
+
+ /* Must go somewhere */
+ if (dir == 5) return FALSE;
+
+ while (TRUE)
+ {
+ x += ddx[dir];
+ y += ddy[dir];
+ c_ptr = &cave[y][x];
+
+ /* Perm walls stops the transfer */
+ if ((!in_bounds(y, x)) && (f_info[c_ptr->feat].flags1 & FF1_PERMANENT))
+ {
+ /* get the last working position */
+ x -= ddx[dir];
+ y -= ddy[dir];
+ ok = FALSE;
+ break;
+ }
+
+ /* Never on a monster */
+ if (c_ptr->m_idx) continue;
+
+ /* Never stop in vaults */
+ if (c_ptr->info & CAVE_ICKY) continue;
+
+ /* From now on, the location COULD be used in special case */
+ lx = x;
+ ly = y;
+
+ /* Pass over walls */
+ if (f_info[c_ptr->feat].flags1 & FF1_WALL) continue;
+
+ /* So it must be ok */
+ ok = TRUE;
+ break;
+ }
+
+ if (!ok)
+ {
+ x = lx;
+ y = ly;
+
+ if (!safe)
+ {
+ msg_print("You emerge in the wall!");
+ take_hit(damroll(10, 8), "becoming one with a wall");
+ }
+ place_floor_convert_glass(y, x);
+ }
+
+ /* Move */
+ p_ptr->px = x;
+ p_ptr->py = y;
+
+ /* Redraw the old spot */
+ lite_spot(oy, ox);
+
+ /* Redraw the new spot */
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Check for new panel (redraw map) */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Redraw trap detection status */
+ p_ptr->redraw |= (PR_DTRAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff XXX XXX XXX */
+ handle_stuff();
+
+ return (TRUE);
+}
+
+/*
+ * Print a batch of dungeons.
+ */
+static void print_dungeon_batch(int *p, int start, int max, bool_ mode)
+{
+ char buf[80];
+ int i, j;
+ byte attr;
+
+
+ if (mode) prt(format(" %-31s", "Name"), 1, 20);
+
+ for (i = 0, j = start; i < 20 && j < max; i++, j++)
+ {
+ dungeon_info_type *d_ptr = &d_info[p[j]];
+
+ strnfmt(buf, 80, " %c) %-30s", I2A(i), d_name + d_ptr->name);
+ if (mode)
+ {
+ if (d_ptr->min_plev > p_ptr->lev)
+ {
+ attr = TERM_L_DARK;
+ }
+ else
+ {
+ attr = TERM_WHITE;
+ }
+ c_prt(attr, buf, 2 + i, 20);
+ }
+ }
+ if (mode) prt("", 2 + i, 20);
+
+ prt(format("Select a dungeon (a-%c), * to list, @ to select by name, +/- to scroll:", I2A(i - 1)), 0, 0);
+}
+
+int reset_recall_aux()
+{
+ char which;
+ int *p;
+ int max = 0, i, start = 0;
+ int ret;
+ bool_ mode = FALSE;
+
+
+ C_MAKE(p, max_d_idx, int);
+
+ /* Count the max */
+ for (i = 1; i < max_d_idx; i++)
+ {
+ /* skip "blocked" dungeons */
+ if (d_info[i].flags1 & DF1_NO_RECALL) continue;
+
+ if (max_dlv[i])
+ {
+ p[max++] = i;
+ }
+ }
+
+ character_icky = TRUE;
+ Term_save();
+
+ while (1)
+ {
+ print_dungeon_batch(p, start, max, mode);
+ which = inkey();
+
+ if (which == ESCAPE)
+ {
+ ret = -1;
+ break;
+ }
+
+ else if (which == '*' || which == '?' || which == ' ')
+ {
+ mode = (mode) ? FALSE : TRUE;
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ else if (which == '+')
+ {
+ start += 20;
+ if (start >= max) start -= 20;
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ else if (which == '-')
+ {
+ start -= 20;
+ if (start < 0) start += 20;
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ else if (which == '@')
+ {
+ char buf[80], buf2[80];
+
+ strcpy(buf, (d_info[p_ptr->recall_dungeon].name + d_name));
+ if (!get_string("Which dungeon? ", buf, 79)) continue;
+
+ /* Find the index corresponding to the name */
+ for (i = 1; i < max_d_idx; i++)
+ {
+ sprintf(buf2, "%s", d_info[i].name + d_name);
+
+ /* Lowercase the name */
+ strlower(buf);
+ strlower(buf2);
+ if (strstr(buf2, buf))
+ {
+ /* valid dungeon found */
+ break;
+ }
+ }
+
+ if (i >= max_d_idx)
+ {
+ msg_print("Never heard of that place!");
+ msg_print(NULL);
+ continue;
+ }
+ else if (d_info[i].flags1 & DF1_NO_RECALL)
+ {
+ msg_print("This place blocks my magic!");
+ msg_print(NULL);
+ continue;
+ }
+ else if (d_info[i].min_plev > p_ptr->lev)
+ {
+ msg_print("You cannot go there yet!");
+ msg_print(NULL);
+ continue;
+ }
+ ret = i;
+ break;
+ }
+
+ else
+ {
+ which = tolower(which);
+ if (start + A2I(which) >= max)
+ {
+ bell();
+ continue;
+ }
+ if (start + A2I(which) < 0)
+ {
+ bell();
+ continue;
+ }
+ ret = p[start + A2I(which)];
+ break;
+ }
+ }
+
+ Term_load();
+ character_icky = FALSE;
+
+ C_FREE(p, max_d_idx, int);
+
+ return ret;
+}
+
+bool_ reset_recall(bool_ no_trepas_max_depth)
+{
+ int dun, depth, max;
+
+ /* Choose dungeon */
+ dun = reset_recall_aux();
+
+ if (dun < 1) return FALSE;
+
+ /* Choose depth */
+ if (!no_trepas_max_depth)
+ max = d_info[dun].maxdepth;
+ else
+ max = max_dlv[dun];
+ depth = get_quantity(format("Which level in %s(%d-%d)? ",
+ d_info[dun].name + d_name,
+ d_info[dun].mindepth, max),
+ max);
+
+ if (depth < 1) return FALSE;
+
+ /* Enforce minimum level */
+ if (depth < d_info[dun].mindepth) depth = d_info[dun].mindepth;
+
+ /* Mega hack -- Forbid levels 99 and 100 */
+ if ((depth == 99) || (depth == 100)) depth = 98;
+
+ p_ptr->recall_dungeon = dun;
+ max_dlv[p_ptr->recall_dungeon] = depth;
+
+ return TRUE;
+}
+
+/* The only way to get rid of the dreaded DG_CURSE*/
+void remove_dg_curse()
+{
+ int k;
+
+ /* Parse all the items */
+ for (k = INVEN_WIELD; k < INVEN_TOTAL; k++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[k];
+
+ if (o_ptr->k_idx && (o_ptr->art_flags4 & TR4_DG_CURSE))
+ {
+ o_ptr->art_flags3 &= ~TR3_HEAVY_CURSE;
+ o_ptr->art_flags3 &= ~TR3_CURSED;
+ o_ptr->art_flags4 &= ~TR4_DG_CURSE;
+ msg_print("The Morgothian Curse withers away.");
+ }
+ }
+}
+
+/*
+ * Creates a between gate
+ */
+void create_between_gate(int dist, int y, int x)
+{
+ int ii, ij, plev = get_skill(SKILL_CONVEYANCE);
+
+ if (dungeon_flags2 & DF2_NO_TELEPORT)
+ {
+ msg_print("Not on special levels!");
+ return;
+ }
+
+ if ((!x) || (!y))
+ {
+ msg_print("You open a Void Jumpgate. Choose a destination.");
+
+ if (!tgt_pt(&ii, &ij)) return;
+ p_ptr->energy -= 60 - plev;
+
+ if (!cave_empty_bold(ij, ii) ||
+ (cave[ij][ii].info & CAVE_ICKY) ||
+ (distance(ij, ii, p_ptr->py, p_ptr->px) > dist) ||
+ (rand_int(plev * plev / 2) == 0))
+ {
+ msg_print("You fail to exit the void correctly!");
+ p_ptr->energy -= 100;
+ get_pos_player(10, &ij, &ii);
+ }
+ }
+ else
+ {
+ ij = y;
+ ii = x;
+ }
+ if (!(f_info[cave[p_ptr->py][p_ptr->px].feat].flags1 & FF1_PERMANENT))
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_BETWEEN);
+ cave[p_ptr->py][p_ptr->px].special = ii + (ij << 8);
+ }
+ if (!(f_info[cave[ij][ii].feat].flags1 & FF1_PERMANENT))
+ {
+ cave_set_feat(ij, ii, FEAT_BETWEEN);
+ cave[ij][ii].special = p_ptr->px + (p_ptr->py << 8);
+ }
+}
diff --git a/src/squeltch.c b/src/squeltch.c
new file mode 100644
index 00000000..603eaa0e
--- /dev/null
+++ b/src/squeltch.c
@@ -0,0 +1,553 @@
+/* File: squeltch.c */
+
+/* Purpose: Automatizer */
+
+/*
+ * Copyright (c) 2002 DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+#include "lua/lua.h"
+#include "tolua.h"
+
+extern lua_State *L;
+
+/*
+ * The functions here use direct lua stack manipulation for calls instead of
+ * exec_lua(format()) because string manipulations are too slow for such
+ * functions
+ */
+
+/* Check the floor for "crap" */
+void squeltch_grid(void)
+{
+ int oldtop;
+ s16b this_o_idx, next_o_idx = 0;
+
+ if (!automatizer_enabled) return;
+
+ oldtop = lua_gettop(L);
+
+ /* Scan the pile of objects */
+ for (this_o_idx = cave[p_ptr->py][p_ptr->px].o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ /* Acquire object */
+ object_type * o_ptr = &o_list[this_o_idx];
+
+ /* We've now seen one of these */
+ if (!k_info[o_ptr->k_idx].flavor)
+ {
+ object_aware(o_ptr);
+ }
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Push the function */
+ lua_settop(L, oldtop);
+ lua_getglobal(L, "apply_rules");
+
+ /* Push the args */
+ tolua_pushusertype(L, o_ptr, tolua_tag(L, "object_type"));
+ tolua_pushnumber(L, -this_o_idx);
+
+ /* Call the function */
+ if (lua_call(L, 2, 0))
+ {
+ cmsg_format(TERM_VIOLET, "ERROR in lua_call while calling 'apply_rules'.");
+ lua_settop(L, oldtop);
+ return;
+ }
+ }
+ lua_settop(L, oldtop);
+}
+
+
+/* Check the inventory for "crap" */
+void squeltch_inventory(void)
+{
+ int oldtop;
+ int i;
+ int num_iter = 0;
+ bool_ found = TRUE;
+
+ if (!automatizer_enabled) return;
+
+ oldtop = lua_gettop(L);
+ while (found && num_iter ++ < 100)
+ {
+ /* Sometimes an index in the inventory is skipped */
+ found = FALSE;
+
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Push the function */
+ lua_settop(L, oldtop);
+ lua_getglobal(L, "apply_rules");
+
+ /* Push the args */
+ tolua_pushusertype(L, o_ptr, tolua_tag(L, "object_type"));
+ tolua_pushnumber(L, i);
+
+ /* Call the function */
+ if (lua_call(L, 2, 1))
+ {
+ cmsg_format(TERM_VIOLET, "ERROR in lua_call while calling 'apply_rules'.");
+ lua_settop(L, oldtop);
+ return;
+ }
+
+ /* Did it return TRUE */
+ if (tolua_getnumber(L, -(lua_gettop(L) - oldtop), 0))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ if (num_iter >= 100)
+ {
+ cmsg_format(TERM_VIOLET, "'apply_rules' ran too often.");
+ }
+ lua_settop(L, oldtop);
+}
+
+/********************** The interface **********************/
+static cptr *get_rule_list(int *max)
+{
+ cptr *list;
+ int i;
+
+ *max = exec_lua("return __rules_max");
+ C_MAKE(list, *max, cptr);
+
+ for (i = 0; i < *max; i++)
+ {
+ list[i] = string_exec_lua(format("return __rules[%d].table.args.name", i));
+ }
+
+ return list;
+}
+
+static cptr types_list[] =
+{
+ "and",
+ "or",
+ "not",
+ "name",
+ "contain",
+ "inscribed",
+ "discount",
+ "symbol",
+ "state",
+ "status",
+ "tval",
+ "sval",
+ "race",
+ "subrace",
+ "class",
+ "level",
+ "skill",
+ "ability",
+ "inventory",
+ "equipment",
+ "comment",
+ NULL,
+};
+
+/* Create a new rule */
+static int automatizer_new_rule()
+{
+ int wid, hgt, max, begin = 0, sel = 0;
+ char c;
+
+ /* Get the number of types */
+ max = 0;
+ while (types_list[max] != NULL)
+ max++;
+
+ while (1)
+ {
+ Term_clear();
+ Term_get_size(&wid, &hgt);
+
+ display_list(0, 0, hgt - 1, 15, "Rule types", types_list, max, begin, sel, TERM_L_GREEN);
+
+ exec_lua(format("auto_aux:display_desc('%s')", types_list[sel]));
+ c_prt(TERM_YELLOW, "Example:", 5, 17);
+ exec_lua(format("xml.write_out_y = 6; xml.write_out_x = 16; xml.write_out_h = %d; xml.write_out_w = %d; xml.write_y = 0; xml.write_x = 0; xml:display_xml(auto_aux.types_desc['%s'][2][1], '')", hgt - 3 - 5, wid - 1 - 15 - 1, types_list[sel]));
+
+ c = inkey();
+
+ if (c == ESCAPE) break;
+ else if (c == '8')
+ {
+ sel--;
+ if (sel < 0)
+ {
+ sel = max - 1;
+ begin = max - hgt;
+ if (begin < 0) begin = 0;
+ }
+ if (sel < begin) begin = sel;
+ }
+ else if (c == '2')
+ {
+ sel++;
+ if (sel >= max)
+ {
+ sel = 0;
+ begin = 0;
+ }
+ if (sel >= begin + hgt - 1) begin++;
+ }
+ else if (c == '\r')
+ {
+ return sel;
+ }
+ }
+ return -1;
+}
+
+static void adjust_begin(int *begin, int *sel, int max, int hgt)
+{
+ if (*sel < 0)
+ {
+ *sel = max - 1;
+ *begin = *sel - hgt + 3;
+ if (*begin < 0) *begin = 0;
+ }
+ if (*sel < *begin) *begin = *sel;
+
+ if (*sel >= max)
+ {
+ *sel = 0;
+ *begin = 0;
+ }
+ if (*sel >= *begin + hgt - 2) (*begin)++;
+}
+
+#define ACTIVE_LIST 0
+#define ACTIVE_RULE 1
+void do_cmd_automatizer()
+{
+ int wid = 0, hgt = 0;
+ char c;
+ cptr *list = NULL;
+ int max, begin = 0, sel = 0;
+ int active = ACTIVE_LIST;
+ cptr keys;
+ cptr keys2;
+ cptr keys3;
+
+ Term_get_size(&wid, &hgt);
+
+ if (!automatizer_enabled)
+ {
+ if (msg_box("Automatizer is currently disabled, enable it? (y/n)", hgt / 2, wid / 2) == 'y')
+ {
+ automatizer_enabled = TRUE;
+ }
+ else
+ return;
+ }
+
+ screen_save();
+
+ exec_lua(format("auto_aux:adjust_current(%d)", sel));
+
+ while (1)
+ {
+ Term_clear();
+ Term_get_size(&wid, &hgt);
+
+ list = get_rule_list(&max);
+ display_list(0, 0, hgt - 1, 15, "Rules", list, max, begin, sel, (active == ACTIVE_LIST) ? TERM_L_GREEN : TERM_GREEN);
+ C_FREE(list, max, cptr);
+
+ draw_box(0, 15, hgt - 4, wid - 1 - 15);
+ if (active == ACTIVE_RULE)
+ {
+ keys = "#Bup#W/#Bdown#W/#Bleft#W/#Bright#W to navitage rule, #B9#W/#B3#W/#B7#W/#B1#W to scroll";
+ keys2 = "#Btab#W for switch, #Ba#Wdd clause, #Bd#Welete clause/rule";
+ keys3 = "#Bx#W to toggle english/xml, #G?#W for Automatizer help";
+ exec_lua("xml.write_active = not nil");
+ }
+ else
+ {
+ keys = "#Bup#W/#Bdown#W to scroll, #Btab#W to switch to the rule window";
+ keys2 = "#Bu#W/#Bd#W to move rules, #Bn#Wew rule, #Br#Wename rule, #Bs#Wave rules";
+ keys3 = "#Rk#W to #rdisable#W the automatizer, #G?#W for Automatizer help";
+ exec_lua("xml.write_active = nil");
+ }
+ display_message(17, hgt - 3, strlen(keys), TERM_WHITE, keys);
+ display_message(17, hgt - 2, strlen(keys2), TERM_WHITE, keys2);
+ display_message(17, hgt - 1, strlen(keys3), TERM_WHITE, keys3);
+
+ if (max) exec_lua(format("xml.write_out_y = 1; xml.write_out_x = 16; xml.write_out_h = %d; xml.write_out_w = %d; xml.write_y = 0; xml.write_x = 0; xml:display_xml(__rules[%d].table, '')", hgt - 4 - 1, wid - 1 - 15 - 1, sel));
+
+ c = inkey();
+
+ if (c == ESCAPE) break;
+ if (active == ACTIVE_LIST)
+ {
+ if (c == '?')
+ {
+ screen_save();
+ show_file("automat.txt", "Automatizer help", 0, 0);
+ screen_load();
+ }
+ else if (c == '8')
+ {
+ if (!max) continue;
+ sel--;
+ adjust_begin(&begin, &sel, max, hgt);
+ exec_lua(format("auto_aux:adjust_current(%d)", sel));
+ }
+ else if (c == '2')
+ {
+ if (!max) continue;
+ sel++;
+ adjust_begin(&begin, &sel, max, hgt);
+ exec_lua(format("auto_aux:adjust_current(%d)", sel));
+ }
+ else if (c == 'u')
+ {
+ if (!max) continue;
+ sel = exec_lua(format("return auto_aux:move_up(%d)", sel));
+ adjust_begin(&begin, &sel, max, hgt);
+ exec_lua(format("auto_aux:adjust_current(%d)", sel));
+ }
+ else if (c == 'd')
+ {
+ if (!max) continue;
+ sel = exec_lua(format("return auto_aux:move_down(%d)", sel));
+ adjust_begin(&begin, &sel, max, hgt);
+ exec_lua(format("auto_aux:adjust_current(%d)", sel));
+ }
+ else if (c == 'n')
+ {
+ char name[20] = { '\0' };
+ char typ;
+
+ sprintf(name, "No name");
+ if (input_box("Name?", hgt / 2, wid / 2, name, sizeof(name)+1))
+ {
+ cptr styp = "nothing";
+ typ = msg_box("[D]estroy, [P]ickup, [I]nscribe, [N]othing rule?", hgt / 2, wid / 2);
+ if ((typ == 'd') || (typ == 'D')) styp = "destroy";
+ else if ((typ == 'p') || (typ == 'P')) styp = "pickup";
+ else if ((typ == 'i') || (typ == 'I')) styp = "inscribe";
+ exec_lua(format("auto_aux:new_rule(%d, '%s', '%s', ''); auto_aux:adjust_current(%d)", sel, name, styp, sel));
+ active = ACTIVE_RULE;
+ }
+ }
+ else if (c == 's')
+ {
+ char name[30] = { '\0' };
+
+ sprintf(name, "automat.atm");
+ if (input_box("Save name?", hgt / 2, wid / 2, name, sizeof(name)+1))
+ {
+ char buf[1025];
+ char ch;
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_USER, name);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ if (file_exist(buf))
+ {
+ c_put_str(TERM_WHITE, "File exists, continue?[y/n]", hgt / 2, wid / 2 - 14);
+ ch = inkey();
+ if ((ch != 'Y') && (ch != 'y'))
+ continue;
+ }
+
+ /* Open the non-existing file */
+ hook_file = my_fopen(buf, "w");
+
+ /* Invalid file */
+ if (!hook_file)
+ {
+ /* Message */
+ c_put_str(TERM_WHITE, "Saving rules failed! ", hgt / 2, wid / 2 - 14);
+ (void) inkey();
+
+ /* Error */
+ continue;
+ }
+
+
+
+ exec_lua("auto_aux:save_ruleset()");
+ my_fclose(hook_file);
+ /* Overwrite query message */
+ c_put_str(TERM_WHITE, "Saved rules in file ", hgt / 2, wid / 2 - 14);
+ (void) inkey();
+ }
+ }
+ else if (c == 'r')
+ {
+ char name[20];
+
+ if (!max) continue;
+
+ sprintf(name, "%s", string_exec_lua(format("return __rules[%d].table.args.name", sel)));
+ if (input_box("New name?", hgt / 2, wid / 2, name, 15))
+ {
+ exec_lua(format("auto_aux:rename_rule(%d, '%s')", sel, name));
+ }
+
+ continue;
+ }
+ else if (c == 'k')
+ {
+ automatizer_enabled = FALSE;
+ break;
+ }
+ else if (c == '\t')
+ {
+ if (!max) continue;
+ active = ACTIVE_RULE;
+ }
+ else if (c == 'x')
+ {
+ exec_lua("xml.display_english = not xml.display_english");
+ }
+ }
+ else if (active == ACTIVE_RULE)
+ {
+ if (c == '?')
+ {
+ screen_save();
+ show_file("automat.txt", "Automatizer help", 0, 0);
+ screen_load();
+ }
+ else if (c == '8')
+ {
+ exec_lua("auto_aux:go_up()");
+ }
+ else if (c == '2')
+ {
+ exec_lua("auto_aux:go_down()");
+ }
+ else if (c == '6')
+ {
+ exec_lua("auto_aux:go_right()");
+ }
+ else if (c == '4')
+ {
+ exec_lua(format("auto_aux:go_left(%d)", sel));
+ }
+ else if (c == '9')
+ {
+ exec_lua("auto_aux:scroll_up()");
+ }
+ else if (c == '3')
+ {
+ exec_lua("auto_aux:scroll_down()");
+ }
+ else if (c == '7')
+ {
+ exec_lua("auto_aux:scroll_left()");
+ }
+ else if (c == '1')
+ {
+ exec_lua("auto_aux:scroll_right()");
+ }
+ else if (c == 'a')
+ {
+ int s = automatizer_new_rule();
+ if (s == -1) continue;
+ exec_lua(format("auto_aux:add_child('%s')", types_list[s]));
+ }
+ else if (c == 'd')
+ {
+ if (max)
+ {
+ int new_sel;
+
+ new_sel = exec_lua(format("return auto_aux:del_self(%d)", sel));
+ if ((sel != new_sel) && (new_sel >= 0))
+ {
+ sel = new_sel;
+ adjust_begin(&begin, &sel, max, hgt);
+ exec_lua(format("auto_aux:adjust_current(%d)", sel));
+ }
+ else if (new_sel == -1)
+ {
+ active = ACTIVE_LIST;
+ }
+ }
+ }
+ else if (c == '\t')
+ {
+ active = ACTIVE_LIST;
+ }
+ else if (c == 'x')
+ {
+ exec_lua("xml.display_english = not xml.display_english");
+ }
+ }
+ }
+
+ /* Recalculate the rules */
+ exec_lua("auto_aux.regen_ruleset()");
+
+ screen_load();
+}
+
+/* Add a new rule in an easy way */
+bool_ automatizer_create = FALSE;
+void automatizer_add_rule(object_type *o_ptr, bool_ destroy)
+{
+ char ch;
+ bool_ do_status = FALSE;
+ cptr type = "destroy";
+
+ if (!destroy)
+ {
+ type = "pickup";
+ }
+
+ while (TRUE)
+ {
+ if (!get_com(format("%s all of the same [T]ype, [F]amily or [N]ame, also use [S]tatus (%s)? ", (destroy) ? "Destroy" : "Pickup", (do_status) ? "Yes" : "No"), &ch))
+ {
+ break;
+ }
+
+ if (ch == 'S' || ch == 's')
+ {
+ do_status = !do_status;
+ continue;
+ }
+
+ if (ch == 'T' || ch == 't')
+ {
+ call_lua("easy_add_rule", "(s,s,d,O)", "", type, "tsval", do_status, o_ptr);
+ break;
+ }
+
+ if (ch == 'F' || ch == 'f')
+ {
+ call_lua("easy_add_rule", "(s,s,d,O)", "", type, "tval", do_status, o_ptr);
+ break;
+ }
+
+ if (ch == 'N' || ch == 'n')
+ {
+ call_lua("easy_add_rule", "(s,s,d,O)", "", type, "name", do_status, o_ptr);
+ break;
+ }
+ }
+}
diff --git a/src/status.c b/src/status.c
new file mode 100644
index 00000000..967a8323
--- /dev/null
+++ b/src/status.c
@@ -0,0 +1,773 @@
+/* File status.c */
+
+/* Purpose: Status information */
+
+/* Written by Pat Gunn <qc@apk.net> for ToME
+ * This file is released into the public domain
+ */
+
+/* Throughout this file, I make use of 2-d arrays called flag_arr.
+ * I fill them out with esp as the 0th element because then the second
+ * index is equal to the f-number that they are in the attributes, and
+ * that makes it more intuitive to use. I do need to fill them out in an
+ * odd order, but that's all abstracted nicely away. The 6th element is used
+ * to mark if the rest of the array is filled, that is, if there's an object
+ * there.
+ */
+
+#include "angband.h"
+
+static void row_trival(char*, s16b, u32b, s16b, u32b, int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+static void row_bival(char*, s16b, u32b, int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+static void row_npval(char*, s16b, u32b, int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+static void statline(char*, int, u32b, int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+static void row_hd_bon(int, int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+static void row_count(char*, s16b, u32b, int, s16b, u32b, int, s16b, u32b, int, s16b, u32b, int, int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+static int row_x_start = 0;
+
+static void status_count(s32b val1, int v1, s32b val2, int v2, s32b val3, int v3, s32b val4, int v4, byte ypos, byte xpos);
+static void status_trival(s32b, s32b, byte, byte);
+static void status_bival(s32b, byte, byte);
+static void status_numeric(s32b, byte, byte);
+static void status_curses(void);
+static void status_companion(void);
+void status_sight(void);
+void status_attr(void);
+void status_combat(void);
+void status_main(void);
+void status_move(void);
+void status_item(void);
+void az_line(int, u32b[INVEN_TOTAL - INVEN_WIELD + 2][7]);
+#define STATNM_LENGTH 11
+#define SL_LENGTH 11
+
+#define INVEN_PLAYER (INVEN_TOTAL - INVEN_WIELD + 1)
+
+void status_attr(void)
+{
+ u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7];
+ int yo = 0;
+ char c;
+
+ clear_from(0);
+ c_put_str(TERM_L_BLUE, "Statistics", yo++, 1);
+ yo += 2;
+ az_line(SL_LENGTH, flag_arr);
+ statline("Str", A_STR, TR1_STR, yo++, flag_arr);
+ statline("Int", A_INT, TR1_INT, yo++, flag_arr);
+ statline("Wis", A_INT, TR1_WIS, yo++, flag_arr);
+ statline("Con", A_CON, TR1_CON, yo++, flag_arr);
+ statline("Dex", A_DEX, TR1_DEX, yo++, flag_arr);
+ statline("Chr", A_CHR, TR1_CHR, yo++, flag_arr);
+ row_npval("Luck", 5, TR5_LUCK, yo++, flag_arr);
+ yo++;
+ row_npval("Life", 2, TR2_LIFE, yo++, flag_arr);
+ row_npval("Mana", 1, TR1_MANA, yo++, flag_arr);
+
+
+ c_put_str(TERM_WHITE, "Press ESC to continue", 23, 0);
+ Term_fresh();
+ while (1)
+ {
+ c = inkey();
+ if (c == ESCAPE) break;
+ }
+}
+
+void status_move(void)
+{
+ u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7];
+ int yo = 3;
+ clear_from(0);
+ c_put_str(TERM_L_BLUE, "Movement", 0, 1);
+ az_line(STATNM_LENGTH, flag_arr);
+
+ row_trival("Fly/Lev", 4, TR4_FLY, 3, TR3_FEATHER, yo++, flag_arr);
+ row_bival("Climb", 4, TR4_CLIMB, yo++, flag_arr);
+ row_npval("Dig", 1, TR1_TUNNEL, yo++, flag_arr);
+ row_npval("Speed", 1, TR1_SPEED, yo++, flag_arr);
+ row_bival("Wraith", 3, TR3_WRAITH, yo++, flag_arr);
+ yo++;
+ row_npval("Stealth", 1, TR1_STEALTH, yo++, flag_arr);
+ row_bival("Telep", 3, TR3_TELEPORT, yo++, flag_arr);
+
+ c_put_str(TERM_WHITE, "Press ESC to continue", 23, 0);
+ Term_fresh();
+ while (1)
+ {
+ bool_ loop_exit = FALSE;
+ char c;
+ c = inkey();
+ switch (c)
+ {
+ case ESCAPE:
+ {
+ loop_exit = TRUE;
+ }
+ }
+ if (loop_exit)
+ {
+ break;
+ }
+ }
+}
+
+void status_sight(void)
+/* Tell player about ESP, infravision, auto-id, see invis, and similar */
+{
+ u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7];
+ int yo = 3;
+ clear_from(0);
+ c_put_str(TERM_L_BLUE, "Sight", 0, 1);
+ az_line(STATNM_LENGTH, flag_arr);
+
+ row_bival("SeeInvis", 3, TR3_SEE_INVIS, yo++, flag_arr);
+ row_npval("Invis", 2, TR2_INVIS, yo++, flag_arr);
+ row_npval("Infra", 1, TR1_INFRA, yo++, flag_arr);
+ row_npval("Search", 1, TR1_SEARCH, yo++, flag_arr);
+ row_bival("AutoID", 4, TR4_AUTO_ID, yo++, flag_arr);
+ row_count("Light", 3, TR3_LITE1, 1, 4, TR4_LITE2, 2, 4, TR4_LITE3, 3, 0, 0, 0, yo++, flag_arr);
+ row_bival("Full ESP", 0, ESP_ALL, yo++, flag_arr);
+ row_bival("Orc ESP", 0, ESP_ORC, yo++, flag_arr);
+ row_bival("Trol ESP", 0, ESP_TROLL, yo++, flag_arr);
+ row_bival("Drag ESP", 0, ESP_DRAGON, yo++, flag_arr);
+ row_bival("GiantESP", 0, ESP_GIANT, yo++, flag_arr);
+ row_bival("DemonESP", 0, ESP_DEMON, yo++, flag_arr);
+ row_bival("Undd ESP", 0, ESP_UNDEAD, yo++, flag_arr);
+ row_bival("Evil ESP", 0, ESP_EVIL, yo++, flag_arr);
+ row_bival("Anim ESP", 0, ESP_ANIMAL, yo++, flag_arr);
+ row_bival("Drid ESP", 0, ESP_THUNDERLORD, yo++, flag_arr);
+ row_bival("Good ESP", 0, ESP_GOOD, yo++, flag_arr);
+ row_bival("SpidrESP", 0, ESP_SPIDER, yo++, flag_arr);
+ row_bival("NonlvESP", 0, ESP_NONLIVING, yo++, flag_arr);
+ row_bival("Uniq ESP", 0, ESP_UNIQUE, yo++, flag_arr);
+
+ c_put_str(TERM_WHITE, "Press ESC to continue", 23, 0);
+ Term_fresh();
+ while (1)
+ {
+ bool_ loop_exit = FALSE;
+ char c;
+ c = inkey();
+ switch (c)
+ {
+ case ESCAPE:
+ {
+ loop_exit = TRUE;
+ }
+ }
+ if (loop_exit)
+ {
+ break;
+ }
+ }
+}
+
+void status_item(void)
+{
+ u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7];
+ int yo = 3;
+ clear_from(0);
+ c_put_str(TERM_L_BLUE, "Misc", 0, 1);
+
+ row_x_start = 40;
+ az_line(STATNM_LENGTH + row_x_start, flag_arr);
+ row_bival("Blessed", 3, TR3_BLESSED, yo++, flag_arr);
+ row_bival("Activate", 3, TR3_ACTIVATE, yo++, flag_arr);
+ row_bival("EasyKnow", 3, TR3_EASY_KNOW, yo++, flag_arr);
+ row_bival("HideType", 3, TR3_HIDE_TYPE, yo++, flag_arr);
+ yo++;
+ row_bival("SafeAcid", 3, TR3_IGNORE_ACID, yo++, flag_arr);
+ row_bival("SafeElec", 3, TR3_IGNORE_ELEC, yo++, flag_arr);
+ row_bival("SafeFire", 3, TR3_IGNORE_FIRE, yo++, flag_arr);
+ row_bival("SafeCold", 3, TR3_IGNORE_COLD, yo++, flag_arr);
+ row_bival("ResMorgul", 5, TR5_RES_MORGUL, yo++, flag_arr);
+
+ yo = 3;
+ row_x_start = 0;
+ az_line(STATNM_LENGTH, flag_arr);
+ row_bival("Sh.fire", 3, TR3_SH_FIRE, yo++, flag_arr);
+ row_bival("Sh.elec", 3, TR3_SH_ELEC, yo++, flag_arr);
+ row_bival("Regen", 3, TR3_REGEN, yo++, flag_arr);
+ row_bival("SlowDigest", 3, TR3_SLOW_DIGEST, yo++, flag_arr);
+ row_bival("Precog", 4, TR4_PRECOGNITION, yo++, flag_arr);
+ row_bival("Auto.Id", 4, TR4_AUTO_ID, yo++, flag_arr);
+ row_bival("Spell.In", 5, TR5_SPELL_CONTAIN, yo++, flag_arr);
+
+ c_put_str(TERM_WHITE, "Press ESC to continue", 23, 0);
+ Term_fresh();
+ while (1)
+ {
+ bool_ loop_exit = FALSE;
+ char c;
+ c = inkey();
+ switch (c)
+ {
+ case ESCAPE:
+ loop_exit = TRUE;
+ }
+ if (loop_exit)
+ {
+ break;
+ }
+ }
+}
+
+void status_combat(void)
+{
+ u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7];
+ int yo = 3;
+ clear_from(0);
+ c_put_str(TERM_L_BLUE, "Combat", 0, 1);
+ az_line(STATNM_LENGTH, flag_arr);
+
+ row_npval("Spell", 1, TR1_SPELL, yo++, flag_arr);
+ row_npval("Blows", 1, TR1_BLOWS, yo++, flag_arr);
+ row_npval("Crits", 5, TR5_CRIT, yo++, flag_arr);
+ row_npval("Ammo_Mgt", 3, TR3_XTRA_MIGHT, yo++, flag_arr);
+ row_npval("Ammo_Sht", 3, TR3_XTRA_SHOTS, yo++, flag_arr);
+ row_bival("Vorpal", 1, TR1_VORPAL, yo++, flag_arr);
+ row_bival("Quake", 1, TR1_IMPACT, yo++, flag_arr);
+ row_bival("Chaotic", 1, TR1_CHAOTIC, yo++, flag_arr);
+ row_bival("Vampiric", 1, TR1_VAMPIRIC, yo++, flag_arr);
+ row_bival("Poison", 1, TR1_BRAND_POIS, yo++, flag_arr);
+ row_bival("Acidic", 1, TR1_BRAND_ACID, yo++, flag_arr);
+ row_bival("Shocks", 1, TR1_BRAND_ELEC, yo++, flag_arr);
+ row_bival("Burns", 1, TR1_BRAND_FIRE, yo++, flag_arr);
+ row_bival("Chills", 1, TR1_BRAND_COLD, yo++, flag_arr);
+ row_bival("Wound", 5, TR5_WOUNDING, yo++, flag_arr);
+
+ row_x_start = 40;
+ yo = 3;
+ az_line(row_x_start + STATNM_LENGTH, flag_arr);
+ row_bival("No.Blow", 4, TR4_NEVER_BLOW, yo++, flag_arr);
+ row_trival("S/K Undd", 1, TR1_SLAY_UNDEAD, 5, TR5_KILL_UNDEAD, yo++, flag_arr);
+ row_trival("S/K Dmn", 1, TR1_SLAY_DEMON, 5, TR5_KILL_DEMON, yo++, flag_arr);
+ row_trival("S/K Drag", 1, TR1_SLAY_DRAGON, 1, TR1_KILL_DRAGON, yo++, flag_arr);
+ row_bival("Sl.Orc", 1, TR1_SLAY_ORC, yo++, flag_arr);
+ row_bival("Sl.Troll", 1, TR1_SLAY_TROLL, yo++, flag_arr);
+ row_bival("Sl.Giant", 1, TR1_SLAY_GIANT, yo++, flag_arr);
+ row_bival("Sl.Evil", 1, TR1_SLAY_EVIL, yo++, flag_arr);
+ row_bival("Sl.Animal", 1, TR1_SLAY_ANIMAL, yo++, flag_arr);
+ row_hd_bon(0, yo++, flag_arr);
+ row_hd_bon(1, yo++, flag_arr);
+ row_x_start = 0;
+
+ c_put_str(TERM_WHITE, "Press ESC to continue", 23, 0);
+ Term_fresh();
+ while (1)
+ {
+ bool_ loop_exit = FALSE;
+ char c;
+ c = inkey();
+ switch (c)
+ {
+ case ESCAPE:
+ loop_exit = TRUE;
+ }
+ if (loop_exit)
+ {
+ break;
+ }
+ }
+}
+
+void status_curses(void)
+{
+ u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7];
+ int yo = 3;
+
+ clear_from(0);
+ c_put_str(TERM_L_BLUE, "Curses", 0, 1);
+ az_line(STATNM_LENGTH, flag_arr);
+
+ row_trival("Hvy/Nrm", 3, TR3_HEAVY_CURSE, 3, TR3_CURSED, yo++, flag_arr);
+ row_bival("Perma", 3, TR3_PERMA_CURSE, yo++, flag_arr);
+ row_trival("DG/Ty", 4, TR4_DG_CURSE, 3, TR3_TY_CURSE, yo++, flag_arr);
+ row_trival("Prm/Auto", 3, TR3_PERMA_CURSE, 3, TR3_AUTO_CURSE, yo++, flag_arr);
+ row_bival("NoDrop", 4, TR4_CURSE_NO_DROP, yo++, flag_arr);
+ yo++;
+ row_bival("B.Breath", 4, TR4_BLACK_BREATH, yo++, flag_arr);
+ row_bival("Dr.Exp", 3, TR3_DRAIN_EXP, yo++, flag_arr);
+ row_bival("Dr.Mana", 5, TR5_DRAIN_MANA, yo++, flag_arr);
+ row_bival("Dr.HP", 5, TR5_DRAIN_HP, yo++, flag_arr);
+ row_bival("No Hit", 4, TR4_NEVER_BLOW, yo++, flag_arr);
+ row_bival("NoTelep", 3, TR3_NO_TELE, yo++, flag_arr);
+ row_bival("NoMagic", 3, TR3_NO_MAGIC, yo++, flag_arr);
+ row_bival("Aggrav", 3, TR3_AGGRAVATE, yo++, flag_arr);
+ row_bival("Clone", 4, TR4_CLONE, yo++, flag_arr);
+ row_bival("Temp", 5, TR5_TEMPORARY, yo++, flag_arr);
+ yo++;
+ row_count("Antimagic", 4, TR4_ANTIMAGIC_50, 5, 4, TR4_ANTIMAGIC_30, 3, 4, TR4_ANTIMAGIC_20, 2, 4, TR4_ANTIMAGIC_10, 1, yo++, flag_arr);
+
+ c_put_str(TERM_WHITE, "Press ESC to continue", 23, 0);
+ Term_fresh();
+ while (1)
+ {
+ bool_ loop_exit = FALSE;
+ char c;
+
+ c = inkey();
+ switch (c)
+ {
+ case ESCAPE:
+ {
+ loop_exit = TRUE;
+ }
+ }
+ if (loop_exit == TRUE)
+ {
+ break;
+ }
+ }
+}
+
+void status_res(void)
+{
+ u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7];
+ int yo = 3;
+
+ clear_from(0);
+ c_put_str(TERM_L_BLUE, "Resistances", 0, 1);
+ az_line(STATNM_LENGTH, flag_arr);
+
+ row_trival("Fire", 2, TR2_IM_FIRE, 2, TR2_RES_FIRE, yo++, flag_arr);
+ row_trival("Cold", 2, TR2_IM_COLD, 2, TR2_RES_COLD, yo++, flag_arr);
+ row_trival("Acid", 2, TR2_IM_ACID, 2, TR2_RES_ACID, yo++, flag_arr);
+ row_trival("Lightning", 2, TR2_IM_ELEC, 2, TR2_RES_ELEC, yo++, flag_arr);
+ row_bival("Poison", 2, TR2_RES_POIS, yo++, flag_arr);
+ row_bival("Lite", 2, TR2_RES_LITE, yo++, flag_arr);
+ row_bival("Dark", 2, TR2_RES_DARK, yo++, flag_arr);
+ row_bival("Sound", 2, TR2_RES_SOUND, yo++, flag_arr);
+ row_bival("Shards", 2, TR2_RES_SHARDS, yo++, flag_arr);
+ row_trival("Nether", 4, TR4_IM_NETHER, 2, TR2_RES_NETHER, yo++, flag_arr);
+ row_bival("Nexus", 2, TR2_RES_NEXUS, yo++, flag_arr);
+ row_bival("Chaos", 2, TR2_RES_CHAOS, yo++, flag_arr);
+ row_bival("Disen.", 2, TR2_RES_DISEN, yo++, flag_arr);
+ row_bival("Confusion", 2, TR2_RES_CONF, yo++, flag_arr);
+ row_bival("Blindness", 2, TR2_RES_BLIND, yo++, flag_arr);
+ row_bival("Fear", 2, TR2_RES_FEAR, yo++, flag_arr);
+ row_bival("Free Act", 2, TR2_FREE_ACT, yo++, flag_arr);
+ row_bival("Reflect", 2, TR2_REFLECT, yo++, flag_arr);
+ row_bival("Hold Life", 2, TR2_HOLD_LIFE, yo++, flag_arr);
+
+ c_put_str(TERM_WHITE, "Press ESC to continue", 23, 0);
+ Term_fresh();
+ while (1)
+ {
+ bool_ loop_exit = FALSE;
+ char c;
+
+ c = inkey();
+ switch (c)
+ {
+ case ESCAPE:
+ {
+ loop_exit = TRUE;
+ }
+ }
+ if (loop_exit == TRUE)
+ {
+ break;
+ }
+ }
+}
+
+void status_main(void)
+{
+ int do_quit = 0;
+ char c;
+
+ character_icky = TRUE;
+ Term_save();
+ while (1)
+ {
+ clear_from(0);
+ c_put_str(TERM_WHITE, format("%s Character Status screen", game_module), 0, 10);
+ c_put_str(TERM_WHITE, "1) Statistics", 2, 5);
+ c_put_str(TERM_WHITE, "2) Movement", 3, 5);
+ c_put_str(TERM_WHITE, "3) Combat", 4, 5);
+ c_put_str(TERM_WHITE, "4) Resistances", 5, 5);
+ c_put_str(TERM_WHITE, "5) Misc", 6, 5);
+ c_put_str(TERM_WHITE, "6) Curses", 7, 5);
+ c_put_str(TERM_WHITE, "7) Sight", 8, 5);
+ c_put_str(TERM_WHITE, "8) Companions", 9, 5);
+ c_put_str(TERM_RED, "Press 'q' to Quit", 23, 5);
+ c = inkey();
+ switch (c)
+ {
+ case '1':
+ status_attr();
+ break;
+ case '2':
+ status_move();
+ break;
+ case '3':
+ status_combat();
+ break;
+ case '4':
+ status_res();
+ break;
+ case '5':
+ status_item();
+ break;
+ case '6':
+ status_curses();
+ break;
+ case '7':
+ status_sight();
+ break;
+ case '8':
+ status_companion();
+ break;
+ case 'q':
+ case ESCAPE:
+ do_quit = 1; /* Schedule leaving the outer loop */
+ break;
+ }
+ Term_fresh();
+ if (do_quit) break;
+ }
+ Term_load();
+ character_icky = FALSE;
+ p_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP);
+ handle_stuff();
+}
+
+void az_line(int xo, u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7])
+{
+ int index = xo; /* Leave room for description */
+ int i;
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ if (p_ptr->inventory[i].k_idx) /* Wearing anything here? */
+ {
+ char cstrng[2];
+ cstrng[0] = (i - INVEN_WIELD) + 'a'; /* Assumes ASCII */
+ cstrng[1] = '\0'; /* terminate it */
+ c_put_str(TERM_WHITE, cstrng, 2, index++); /* Assumes ASCII */
+
+ /* DGDGDGDG */
+ /* object_flags_known(&inventory[i],*/
+ object_flags(&p_ptr->inventory[i], /* Help me debug */
+ &flag_arr[i - INVEN_WIELD][1], /* f1 */
+ &flag_arr[i - INVEN_WIELD][2], /* f2 */
+ &flag_arr[i - INVEN_WIELD][3], /* f3 */
+ &flag_arr[i - INVEN_WIELD][4], /* f4 */
+ &flag_arr[i - INVEN_WIELD][5], /* f5 */
+ &flag_arr[i - INVEN_WIELD][0]); /* esp */
+ flag_arr[i - INVEN_WIELD][6] = 1; /* And mark it to display */
+ }
+ else flag_arr[i - INVEN_WIELD][6] = 0; /* Otherwise don't display it */
+ }
+ c_put_str(TERM_WHITE, "@", 2, index++);
+ player_flags(
+ &flag_arr[INVEN_PLAYER][1], /* f1 */
+ &flag_arr[INVEN_PLAYER][2], /* f2 */
+ &flag_arr[INVEN_PLAYER][3], /* f3 */
+ &flag_arr[INVEN_PLAYER][4], /* f4 */
+ &flag_arr[INVEN_PLAYER][5], /* f5 */
+ &flag_arr[INVEN_PLAYER][0] /* esp */
+ );
+ flag_arr[INVEN_PLAYER][6] = 1;
+}
+
+static void status_trival(s32b val1, s32b val2, byte ypos, byte xpos)
+{
+ if (val1 != 0)
+ c_put_str(TERM_L_BLUE, "*", ypos, xpos);
+ else if (val2 != 0)
+ c_put_str(TERM_L_BLUE, "+", ypos, xpos);
+ else
+ c_put_str(TERM_WHITE, ".", ypos, xpos);
+}
+
+static void status_bival(s32b val, byte ypos, byte xpos)
+{
+ if (val != 0)
+ c_put_str(TERM_L_BLUE, "+", ypos, xpos);
+ else
+ c_put_str(TERM_WHITE, ".", ypos, xpos);
+}
+
+static void status_numeric(s32b val, byte ypos, byte xpos)
+{
+ u32b magnitude = ABS(val);
+ int color = TERM_WHITE; /* default */
+ char strnum[2];
+
+ if (val<0) {
+ color = TERM_RED;
+ };
+ if (val>0) {
+ color = TERM_GREEN;
+ };
+
+ if (magnitude == 0) {
+ sprintf(strnum, ".");
+ } if (magnitude > 9) {
+ sprintf(strnum, "*");
+ } else {
+ sprintf(strnum, "%lu", (unsigned long int) magnitude);
+ }
+
+ c_put_str(color, strnum, ypos, xpos);
+}
+
+static void status_count(s32b val1, int v1, s32b val2, int v2, s32b val3, int v3, s32b val4, int v4, byte ypos, byte xpos)
+{
+ int v = 0;
+
+ if (val1 != 0) v += v1;
+ if (val2 != 0) v += v2;
+ if (val3 != 0) v += v3;
+ if (val4 != 0) v += v4;
+
+ status_numeric(v, ypos, xpos);
+}
+
+static void row_count(char* statname, s16b row1, u32b flag1, int v1, s16b row2, u32b flag2, int v2, s16b row3, u32b flag3, int v3, s16b row4, u32b flag4, int v4, int yo, u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7])
+{
+ int i;
+ int x = row_x_start;
+
+ c_put_str(TERM_L_GREEN, statname, yo, row_x_start);
+
+ for (i = 0; i < (INVEN_TOTAL - INVEN_WIELD + 2); i++)
+ {
+ if (flag_arr[i][6] == 1)
+ {
+ status_count((flag_arr[i][row1] & flag1), v1, (flag_arr[i][row2] & flag2), v2, (flag_arr[i][row3] & flag3), v3, (flag_arr[i][row4] & flag4), v4, yo, x + STATNM_LENGTH);
+ x++;
+ }
+ }
+}
+
+static void row_trival(char* statname, s16b row, u32b flag, s16b row2, u32b flag2, int yo, u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7])
+{
+ int i;
+ int x = row_x_start;
+ c_put_str(TERM_L_GREEN, statname, yo, row_x_start);
+ for (i = 0; i < (INVEN_TOTAL - INVEN_WIELD + 2); i++)
+ {
+ if (flag_arr[i][6] == 1)
+ {
+ status_trival(
+ (flag_arr[i][row] & flag),
+ (flag_arr[i][row2] & flag2),
+ yo, x + STATNM_LENGTH);
+ x++;
+ }
+ }
+}
+
+static void row_bival(char* statname, s16b row, u32b flag, int yo, u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7])
+{
+ int i;
+ int x = row_x_start;
+ c_put_str(TERM_L_GREEN, statname, yo, row_x_start);
+ for (i = 0; i < (INVEN_TOTAL - INVEN_WIELD + 2); i++)
+ {
+ if (flag_arr[i][6] == 1)
+ {
+ status_bival((flag_arr[i][row] & flag), yo, x + STATNM_LENGTH);
+ x++;
+ }
+ }
+}
+
+static void row_npval(char* statname, s16b row, u32b flag, int yo, u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7])
+/* Displays nicely a pval-based status row */
+{
+ int i;
+ int x = row_x_start;
+ c_put_str(TERM_L_GREEN, statname, yo, row_x_start);
+ for (i = 0; i < (INVEN_TOTAL - INVEN_WIELD + 2); i++)
+ {
+ if (flag_arr[i][6] == 1)
+ {
+ if (i == INVEN_PLAYER)
+ /* Special case, player_flags */
+ /* Players lack a pval, no way to calc value */
+ {
+ if (flag_arr[i][row] & flag)
+ c_put_str(TERM_YELLOW, "*", yo, x + STATNM_LENGTH);
+ else c_put_str(TERM_WHITE, ".", yo, x + STATNM_LENGTH);
+ x++;
+ continue;
+ }
+ if (flag_arr[i][row] & flag)
+ status_numeric(p_ptr->inventory[i + INVEN_WIELD].pval, yo, x + STATNM_LENGTH);
+ else
+ c_put_str(TERM_WHITE, ".", yo, x + STATNM_LENGTH);
+ x++;
+ }
+ }
+}
+
+static void statline(char* statname, int statidx, u32b flag, int yo, u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7])
+/* Displays a status row for a primary stat */
+{
+ int i;
+ int x = row_x_start;
+ char statstr[8];
+ byte stat_color = TERM_L_RED;
+
+ cnv_stat(p_ptr->stat_use[statidx], statstr);
+
+ c_put_str(TERM_L_GREEN, statstr, yo, 4 + row_x_start);
+ for (i = 0; i < (INVEN_TOTAL - INVEN_WIELD + 2); i++)
+ {
+ byte color = TERM_L_RED;
+
+ if (flag_arr[i][6] == 1)
+ {
+ switch (statidx)
+ {
+ case A_STR:
+ if (flag_arr[i][2] & TR2_SUST_STR)
+ color = TERM_L_BLUE;
+ break;
+ case A_INT:
+ if (flag_arr[i][2] & TR2_SUST_INT)
+ color = TERM_L_BLUE;
+ break;
+ case A_WIS:
+ if (flag_arr[i][2] & TR2_SUST_WIS)
+ color = TERM_L_BLUE;
+ break;
+ case A_DEX:
+ if (flag_arr[i][2] & TR2_SUST_DEX)
+ color = TERM_L_BLUE;
+ break;
+ case A_CON:
+ if (flag_arr[i][2] & TR2_SUST_CON)
+ color = TERM_L_BLUE;
+ break;
+ case A_CHR:
+ if (flag_arr[i][2] & TR2_SUST_CHR)
+ color = TERM_L_BLUE;
+ break;
+ }
+
+ if (i == INVEN_PLAYER ) /* Player flags */
+ {
+ if (flag_arr[i][1] & flag)
+ c_put_str((color == TERM_L_RED) ? TERM_YELLOW : color, "*", yo, x + SL_LENGTH);
+ else c_put_str((color == TERM_L_RED) ? TERM_WHITE : color, ".", yo, x + SL_LENGTH);
+ x++;
+ continue;
+ }
+ if (flag_arr[i][1] & flag)
+ status_numeric(p_ptr->inventory[i + INVEN_WIELD].pval, yo, x + SL_LENGTH);
+ else
+ c_put_str((color == TERM_L_RED) ? TERM_WHITE : color, ".", yo, x + SL_LENGTH);
+
+ if (color != TERM_L_RED)
+ stat_color = color;
+
+ x++;
+ }
+ }
+
+ c_put_str(stat_color, statname, yo, row_x_start);
+}
+
+static void row_hd_bon(int which, int yo, u32b flag_arr[INVEN_TOTAL - INVEN_WIELD + 2][7])
+/* To-hit/dmg modifiers, selected by 1st argument */
+{
+ int i;
+ int x = row_x_start;
+ if ((which != 0) && (which != 1)) return;
+ c_put_str(TERM_L_GREEN, ((which == 0) ? "To-Hit" : "To-Dmg"), yo, row_x_start);
+ for (i = 0; i < (INVEN_TOTAL - INVEN_WIELD + 2); i++)
+ {
+ if (flag_arr[i][6] == 1)
+ {
+ if (i == INVEN_PLAYER) /* Player? */
+ {
+ c_put_str(TERM_WHITE, ".", yo, x + STATNM_LENGTH);
+ x++;
+ continue;
+ }
+ if ( (which == 0) && (p_ptr->inventory[INVEN_WIELD + i].to_h != 0))
+ {
+ status_numeric(p_ptr->inventory[INVEN_WIELD + i].to_h, yo, x + STATNM_LENGTH);
+ x++;
+ continue;
+ }
+ if ( (which == 1) && (p_ptr->inventory[INVEN_WIELD + i].to_d != 0))
+ {
+ status_numeric(p_ptr->inventory[INVEN_WIELD + i].to_d, yo, x + STATNM_LENGTH);
+ x++;
+ continue;
+ }
+ c_put_str(TERM_WHITE, ".", yo, x + STATNM_LENGTH);
+ x++;
+ }
+ }
+}
+
+static void status_companion(void)
+{
+ int i;
+
+ FILE *fff;
+
+ char file_name[1024];
+
+ Term_clear();
+
+ /* Temporary file */
+ if (path_temp(file_name, 1024)) return;
+
+ /* Open a new file */
+ fff = my_fopen(file_name, "w");
+
+ /* Calculate companions */
+ /* Process the monsters (backwards) */
+ for (i = m_max - 1; i >= 1; i--)
+ {
+ /* Access the monster */
+ monster_type *m_ptr = &m_list[i];
+
+ if (m_ptr->status == MSTATUS_COMPANION)
+ {
+ char m_name[80];
+ int b, y = 0;
+
+ /* Extract monster name */
+ monster_desc(m_name, m_ptr, 0x80);
+
+ fprintf(fff, "#####BCompanion: %s\n", m_name);
+
+ fprintf(fff, " Lev/Exp : [[[[[G%d / %ld]\n", m_ptr->level, (long int) m_ptr->exp);
+ if (m_ptr->level < MONSTER_LEVEL_MAX) fprintf(fff, " Next lvl: [[[[[G%ld]\n", (long int) MONSTER_EXP((s32b)m_ptr->level + 1));
+ else fprintf(fff, " Next lvl: [[[[[G****]\n");
+
+ fprintf(fff, " HP : [[[[[G%ld / %ld]\n", (long int) m_ptr->hp, (long int) m_ptr->maxhp);
+ fprintf(fff, " AC : [[[[[G%d]\n", m_ptr->ac);
+ fprintf(fff, " Speed : [[[[[G%d]\n", m_ptr->mspeed - 110);
+
+ for (b = 0; b < 4; b++)
+ {
+ if (!m_ptr->blow[b].d_dice) continue;
+ if (!m_ptr->blow[b].d_side) continue;
+
+ fprintf(fff, " Blow %1d : [[[[[G%dd%d]\n", y + 1, m_ptr->blow[b].d_dice, m_ptr->blow[b].d_side);
+ y++;
+ }
+
+ fprintf(fff, "\n");
+ }
+ }
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Display the file contents */
+ show_file(file_name, "Companion List", 0, 0);
+
+ /* Remove the file */
+ fd_kill(file_name);
+}
diff --git a/src/store.c b/src/store.c
new file mode 100644
index 00000000..78120846
--- /dev/null
+++ b/src/store.c
@@ -0,0 +1,4458 @@
+/* File: store.c */
+
+/* Purpose: Store commands */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+#define RUMOR_CHANCE 8
+
+#define MAX_COMMENT_1 6
+
+static cptr comment_1[MAX_COMMENT_1] =
+{
+ "Okay.",
+ "Fine.",
+ "Accepted!",
+ "Agreed!",
+ "Done!",
+ "Taken!"
+};
+
+#define MAX_COMMENT_2A 2
+
+static cptr comment_2a[MAX_COMMENT_2A] =
+{
+ "You try my patience. %s is final.",
+ "My patience grows thin. %s is final."
+};
+
+#define MAX_COMMENT_2B 12
+
+static cptr comment_2b[MAX_COMMENT_2B] =
+{
+ "I can take no less than %s gold pieces.",
+ "I will accept no less than %s gold pieces.",
+ "Ha! No less than %s gold pieces.",
+ "You knave! No less than %s gold pieces.",
+ "That's a pittance! I want %s gold pieces.",
+ "That's an insult! I want %s gold pieces.",
+ "As if! How about %s gold pieces?",
+ "My gosh! How about %s gold pieces?",
+ "May the fleas of 1000 orcs molest you! Try %s gold pieces.",
+ "May your most favourite weapons rust! Try %s gold pieces.",
+ "May Morgoth find you tasty! Perhaps %s gold pieces?",
+ "Your mother was an Ogre! Perhaps %s gold pieces?"
+};
+
+#define MAX_COMMENT_3A 2
+
+static cptr comment_3a[MAX_COMMENT_3A] =
+{
+ "You try my patience. %s is final.",
+ "My patience grows thin. %s is final."
+};
+
+
+#define MAX_COMMENT_3B 12
+
+static cptr comment_3b[MAX_COMMENT_3B] =
+{
+ "Perhaps %s gold pieces?",
+ "How about %s gold pieces?",
+ "I will pay no more than %s gold pieces.",
+ "I can afford no more than %s gold pieces.",
+ "Be reasonable. How about %s gold pieces?",
+ "I'll buy it as scrap for %s gold pieces.",
+ "That is too much! How about %s gold pieces?",
+ "That looks war surplus! Say %s gold pieces?",
+ "Never! %s is more like it.",
+ "That's an insult! %s is more like it.",
+ "%s gold pieces and be thankful for it!",
+ "%s gold pieces and not a copper more!"
+};
+
+#define MAX_COMMENT_4A 4
+
+static cptr comment_4a[MAX_COMMENT_4A] =
+{
+ "Enough! You have abused me once too often!",
+ "Arghhh! I have had enough abuse for one day!",
+ "That does it! You shall waste my time no more!",
+ "This is getting nowhere! I'm going to Londis!"
+};
+
+#define MAX_COMMENT_4B 4
+
+static cptr comment_4b[MAX_COMMENT_4B] =
+{
+ "Leave my store!",
+ "Get out of my sight!",
+ "Begone, you scoundrel!",
+ "Out, out, out!"
+};
+
+#define MAX_COMMENT_5 8
+
+static cptr comment_5[MAX_COMMENT_5] =
+{
+ "Try again.",
+ "Ridiculous!",
+ "You will have to do better than that!",
+ "Do you wish to do business or not?",
+ "You've got to be kidding!",
+ "You'd better be kidding!",
+ "You try my patience.",
+ "Hmmm, nice weather we're having."
+};
+
+#define MAX_COMMENT_6 4
+
+static cptr comment_6[MAX_COMMENT_6] =
+{
+ "I must have heard you wrong.",
+ "I'm sorry, I missed that.",
+ "I'm sorry, what was that?",
+ "Sorry, what was that again?"
+};
+
+
+
+/*
+ * Successful haggle.
+ */
+static void say_comment_1(void)
+{
+ char rumour[80];
+
+ msg_print(comment_1[rand_int(MAX_COMMENT_1)]);
+
+ if (randint(RUMOR_CHANCE) == 1 && speak_unique)
+ {
+ msg_print("The shopkeeper whispers something into your ear:");
+ get_rnd_line("rumors.txt", rumour);
+ msg_print(rumour);
+ }
+}
+
+
+/*
+ * Continue haggling (player is buying)
+ */
+static void say_comment_2(s32b value, int annoyed)
+{
+ char tmp_val[80];
+
+ /* Prepare a string to insert */
+ strnfmt(tmp_val, 80, "%ld", (long)value);
+
+ /* Final offer */
+ if (annoyed > 0)
+ {
+ /* Formatted message */
+ msg_format(comment_2a[rand_int(MAX_COMMENT_2A)], tmp_val);
+ }
+
+ /* Normal offer */
+ else
+ {
+ /* Formatted message */
+ msg_format(comment_2b[rand_int(MAX_COMMENT_2B)], tmp_val);
+ }
+}
+
+
+/*
+ * Continue haggling (player is selling)
+ */
+static void say_comment_3(s32b value, int annoyed)
+{
+ char tmp_val[80];
+
+ /* Prepare a string to insert */
+ strnfmt(tmp_val, 80, "%ld", (long)value);
+
+ /* Final offer */
+ if (annoyed > 0)
+ {
+ /* Formatted message */
+ msg_format(comment_3a[rand_int(MAX_COMMENT_3A)], tmp_val);
+ }
+
+ /* Normal offer */
+ else
+ {
+ /* Formatted message */
+ msg_format(comment_3b[rand_int(MAX_COMMENT_3B)], tmp_val);
+ }
+}
+
+
+/*
+ * Kick 'da bum out. -RAK-
+ */
+static void say_comment_4(void)
+{
+ msg_print(comment_4a[rand_int(MAX_COMMENT_4A)]);
+ msg_print(comment_4b[rand_int(MAX_COMMENT_4B)]);
+}
+
+
+/*
+ * You are insulting me
+ */
+static void say_comment_5(void)
+{
+ msg_print(comment_5[rand_int(MAX_COMMENT_5)]);
+}
+
+
+/*
+ * That makes no sense.
+ */
+static void say_comment_6(void)
+{
+ msg_print(comment_6[rand_int(5)]);
+}
+
+
+
+/*
+ * Messages for reacting to purchase prices.
+ */
+
+#define MAX_COMMENT_7A 4
+
+static cptr comment_7a[MAX_COMMENT_7A] =
+{
+ "Arrgghh!",
+ "You moron!",
+ "You hear someone sobbing...",
+ "The shopkeeper howls in agony!"
+};
+
+#define MAX_COMMENT_7B 4
+
+static cptr comment_7b[MAX_COMMENT_7B] =
+{
+ "Darn!",
+ "You fiend!",
+ "The shopkeeper yells at you.",
+ "The shopkeeper glares at you."
+};
+
+#define MAX_COMMENT_7C 4
+
+static cptr comment_7c[MAX_COMMENT_7C] =
+{
+ "Cool!",
+ "You've made my day!",
+ "The shopkeeper giggles.",
+ "The shopkeeper laughs loudly."
+};
+
+#define MAX_COMMENT_7D 4
+
+static cptr comment_7d[MAX_COMMENT_7D] =
+{
+ "Yippee!",
+ "I think I'll retire!",
+ "The shopkeeper jumps for joy.",
+ "The shopkeeper smiles gleefully."
+};
+
+/*
+ * Let a shop-keeper React to a purchase
+ *
+ * We paid "price", it was worth "value", and we thought it was worth "guess"
+ */
+static void purchase_analyze(s32b price, s32b value, s32b guess)
+{
+ /* Item was worthless, but we bought it */
+ if ((value <= 0) && (price > value))
+ {
+ /* Comment */
+ msg_print(comment_7a[rand_int(MAX_COMMENT_7A)]);
+
+ /* Sound */
+ sound(SOUND_STORE1);
+ }
+
+ /* Item was cheaper than we thought, and we paid more than necessary */
+ else if ((value < guess) && (price > value))
+ {
+ /* Comment */
+ msg_print(comment_7b[rand_int(MAX_COMMENT_7B)]);
+
+ /* Sound */
+ sound(SOUND_STORE2);
+ }
+
+ /* Item was a good bargain, and we got away with it */
+ else if ((value > guess) && (value < (4 * guess)) && (price < value))
+ {
+ /* Comment */
+ msg_print(comment_7c[rand_int(MAX_COMMENT_7C)]);
+
+ /* Sound */
+ sound(SOUND_STORE3);
+ }
+
+ /* Item was a great bargain, and we got away with it */
+ else if ((value > guess) && (price < value))
+ {
+ /* Comment */
+ msg_print(comment_7d[rand_int(MAX_COMMENT_7D)]);
+
+ /* Sound */
+ sound(SOUND_STORE4);
+ }
+}
+
+
+
+
+
+/*
+ * We store the current "store number" here so everyone can access it
+ */
+static int cur_store_num = 7;
+
+/*
+ * We store the current "store page" here so everyone can access it
+ */
+static int store_top = 0;
+
+/*
+ * We store the current "store pointer" here so everyone can access it
+ */
+static store_type *st_ptr = NULL;
+
+/*
+ * We store the current "owner type" here so everyone can access it
+ */
+static owner_type *ot_ptr = NULL;
+
+
+
+/*
+ * Determine the price of an item (qty one) in a store.
+ *
+ * This function takes into account the player's charisma, and the
+ * shop-keepers friendliness, and the shop-keeper's base greed, but
+ * never lets a shop-keeper lose money in a transaction.
+ *
+ * The "greed" value should exceed 100 when the player is "buying" the
+ * item, and should be less than 100 when the player is "selling" it.
+ *
+ * Hack -- the black market always charges twice as much as it should.
+ *
+ * Charisma adjustment runs from 80 to 130
+ * Racial adjustment runs from 95 to 130
+ *
+ * Since greed/charisma/racial adjustments are centered at 100, we need
+ * to adjust (by 200) to extract a usable multiplier. Note that the
+ * "greed" value is always something (?).
+ */
+static s32b price_item(object_type *o_ptr, int greed, bool_ flip)
+{
+ int factor;
+ int adjust;
+ s32b price;
+
+
+ /* Get the value of one of the items */
+ price = object_value(o_ptr);
+
+ /* Worthless items */
+ if (price <= 0) return (0L);
+
+ /* Compute the racial factor */
+ if (is_state(st_ptr, STORE_LIKED))
+ {
+ factor = ot_ptr->costs[STORE_LIKED];
+ }
+ else if (is_state(st_ptr, STORE_HATED))
+ {
+ factor = ot_ptr->costs[STORE_HATED];
+ }
+ else
+ {
+ factor = ot_ptr->costs[STORE_NORMAL];
+ }
+
+ /* Add in the charisma factor */
+ factor += adj_chr_gold[p_ptr->stat_ind[A_CHR]];
+
+ /* Shop is buying */
+ if (flip)
+ {
+ /* Mega Hack^3 */
+ switch (o_ptr->tval)
+ {
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+ price /= 5;
+ break;
+ }
+
+ /* Adjust for greed */
+ adjust = 100 + (300 - (greed + factor));
+
+ /* Never get "silly" */
+ if (adjust > 100) adjust = 100;
+
+ /* Mega-Hack -- Black market sucks */
+ if (st_info[st_ptr->st_idx].flags1 & SF1_ALL_ITEM) price = price / 2;
+ }
+
+ /* Shop is selling */
+ else
+ {
+ /* Adjust for greed */
+ adjust = 100 + ((greed + factor) - 300);
+
+ /* Never get "silly" */
+ if (adjust < 100) adjust = 100;
+
+ /* Mega-Hack -- Black market sucks */
+ if (st_info[st_ptr->st_idx].flags1 & SF1_ALL_ITEM) price = price * 2;
+ }
+
+ /* Compute the final price (with rounding) */
+ price = (price * adjust + 50L) / 100L;
+
+ /* Note -- Never become "free" */
+ if (price <= 0L) return (1L);
+
+ /* Return the price */
+ return (price);
+}
+
+
+/*
+ * Special "mass production" computation
+ */
+static int mass_roll(int num, int max)
+{
+ int i, t = 0;
+ for (i = 0; i < num; i++) t += rand_int(max);
+ return (t);
+}
+
+
+/*
+ * Certain "cheap" objects should be created in "piles"
+ * Some objects can be sold at a "discount" (in small piles)
+ */
+static void mass_produce(object_type *o_ptr)
+{
+ int size = 1;
+ int discount = 0;
+
+ s32b cost = object_value(o_ptr);
+
+
+ /* Analyze the type */
+ switch (o_ptr->tval)
+ {
+ /* Food, Flasks, and Lites */
+ case TV_FOOD:
+ case TV_FLASK:
+ case TV_LITE:
+ {
+ if (cost <= 5L) size += mass_roll(3, 5);
+ if (cost <= 20L) size += mass_roll(3, 5);
+ break;
+ }
+
+ case TV_POTION:
+ case TV_POTION2:
+ case TV_SCROLL:
+ {
+ if (cost <= 60L) size += mass_roll(3, 5);
+ if (cost <= 240L) size += mass_roll(1, 5);
+ break;
+ }
+
+ case TV_SYMBIOTIC_BOOK:
+ case TV_MUSIC_BOOK:
+ case TV_DRUID_BOOK:
+ case TV_DAEMON_BOOK:
+ case TV_BOOK:
+ {
+ if (cost <= 50L) size += mass_roll(2, 3);
+ if (cost <= 500L) size += mass_roll(1, 3);
+ break;
+ }
+
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_SHIELD:
+ case TV_GLOVES:
+ case TV_BOOTS:
+ case TV_CLOAK:
+ case TV_HELM:
+ case TV_CROWN:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_POLEARM:
+ case TV_HAFTED:
+ case TV_DIGGING:
+ case TV_BOW:
+ {
+ if (o_ptr->name2) break;
+ if (cost <= 10L) size += mass_roll(3, 5);
+ if (cost <= 100L) size += mass_roll(3, 5);
+ break;
+ }
+
+ case TV_SPIKE:
+ case TV_SHOT:
+ case TV_ARROW:
+ case TV_BOLT:
+ {
+ if (cost <= 5L) size += mass_roll(5, 5);
+ if (cost <= 50L) size += mass_roll(5, 5);
+ if (cost <= 500L) size += mass_roll(5, 5);
+ break;
+ }
+
+ /* Because many rods (and a few wands and staffs) are useful mainly
+ * in quantity, the Black Market will occasionally have a bunch of
+ * one kind. -LM- */
+ case TV_ROD:
+ case TV_WAND:
+ case TV_STAFF:
+ {
+ if (cost < 1601L) size += mass_roll(1, 5);
+ else if (cost < 3201L) size += mass_roll(1, 3);
+ break;
+ }
+ }
+
+
+ /* Pick a discount */
+ if (cost < 5)
+ {
+ discount = 0;
+ }
+ else if (rand_int(25) == 0)
+ {
+ discount = 25;
+ }
+ else if (rand_int(150) == 0)
+ {
+ discount = 50;
+ }
+ else if (rand_int(300) == 0)
+ {
+ discount = 75;
+ }
+ else if (rand_int(500) == 0)
+ {
+ discount = 90;
+ }
+
+
+ if (o_ptr->art_name)
+ {
+ if (cheat_peek && discount)
+ {
+ msg_print("No discount on random artifacts.");
+ }
+ discount = 0;
+ }
+
+ /* Save the discount */
+ o_ptr->discount = discount;
+
+ /* Save the total pile size */
+ o_ptr->number = size - (size * discount / 100);
+}
+
+
+
+
+
+
+
+
+/*
+ * Determine if a store item can "absorb" another item
+ *
+ * See "object_similar()" for the same function for the "player"
+ */
+static bool_ store_object_similar(object_type *o_ptr, object_type *j_ptr)
+{
+ /* Hack -- Identical items cannot be stacked */
+ if (o_ptr == j_ptr) return (0);
+
+ /* Different objects cannot be stacked */
+ if (o_ptr->k_idx != j_ptr->k_idx) return (0);
+
+ /* Different charges (etc) cannot be stacked, unless wands or rods. */
+ if ((o_ptr->pval != j_ptr->pval) && (o_ptr->tval != TV_WAND)) return (0);
+
+ /* Require many identical values */
+ if (o_ptr->pval2 != j_ptr->pval2) return (0);
+ if (o_ptr->pval3 != j_ptr->pval3) return (0);
+
+ /* Require many identical values */
+ if (o_ptr->to_h != j_ptr->to_h) return (0);
+ if (o_ptr->to_d != j_ptr->to_d) return (0);
+ if (o_ptr->to_a != j_ptr->to_a) return (0);
+
+ /* Require identical "artifact" names */
+ if (o_ptr->name1 != j_ptr->name1) return (0);
+
+ /* Require identical "ego-item" names */
+ if (o_ptr->name2 != j_ptr->name2) return (0);
+
+ /* Require identical "ego-item" names */
+ if (o_ptr->name2b != j_ptr->name2b) return (0);
+
+ /* Random artifacts don't stack !*/
+ if (o_ptr->art_name || j_ptr->art_name) return (0);
+
+ /* Hack -- Identical art_flags! */
+ if ((o_ptr->art_flags1 != j_ptr->art_flags1) ||
+ (o_ptr->art_flags2 != j_ptr->art_flags2) ||
+ (o_ptr->art_flags3 != j_ptr->art_flags3))
+ return (0);
+
+ /* Hack -- Never stack "powerful" items */
+ if (o_ptr->xtra1 || j_ptr->xtra1) return (0);
+
+ if (o_ptr->tval == TV_LITE)
+ {
+ /* Require identical "turns of light" */
+ if (o_ptr->timeout != j_ptr->timeout) return (0);
+ }
+ else
+ {
+ /* Hack -- Never stack recharging items */
+ if (o_ptr->timeout || j_ptr->timeout) return (0);
+ }
+
+ /* Require many identical values */
+ if (o_ptr->ac != j_ptr->ac) return (0);
+ if (o_ptr->dd != j_ptr->dd) return (0);
+ if (o_ptr->ds != j_ptr->ds) return (0);
+
+ /* Hack -- Never stack chests */
+ if (o_ptr->tval == TV_CHEST) return (0);
+
+ /* Require matching discounts */
+ if (o_ptr->discount != j_ptr->discount) return (0);
+
+ /* They match, so they must be similar */
+ return (TRUE);
+}
+
+
+/*
+ * Allow a store item to absorb another item
+ */
+static void store_object_absorb(object_type *o_ptr, object_type *j_ptr)
+{
+ int total = o_ptr->number + j_ptr->number;
+
+ /* Combine quantity, lose excess items */
+ o_ptr->number = (total > 99) ? 99 : total;
+
+ /* Hack -- if wands are stacking, combine the charges. -LM- */
+ if (o_ptr->tval == TV_WAND)
+ {
+ o_ptr->pval += j_ptr->pval;
+ }
+}
+
+
+/*
+ * Check to see if the shop will be carrying too many objects -RAK-
+ * Note that the shop, just like a player, will not accept things
+ * it cannot hold. Before, one could "nuke" potions this way.
+ */
+static bool_ store_check_num(object_type *o_ptr)
+{
+ int i;
+ object_type *j_ptr;
+
+ /* Free space is always usable */
+ if (st_ptr->stock_num < st_ptr->stock_size) return TRUE;
+
+ /* The "home" acts like the player */
+ if ((cur_store_num == 7) ||
+ (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM))
+ {
+ /* Check all the items */
+ for (i = 0; i < st_ptr->stock_num; i++)
+ {
+ /* Get the existing item */
+ j_ptr = &st_ptr->stock[i];
+
+ /* Can the new object be combined with the old one? */
+ if (object_similar(j_ptr, o_ptr)) return (TRUE);
+ }
+ }
+
+ /* Normal stores do special stuff */
+ else
+ {
+ /* Check all the items */
+ for (i = 0; i < st_ptr->stock_num; i++)
+ {
+ /* Get the existing item */
+ j_ptr = &st_ptr->stock[i];
+
+ /* Can the new object be combined with the old one? */
+ if (store_object_similar(j_ptr, o_ptr)) return (TRUE);
+ }
+ }
+
+ /* But there was no room at the inn... */
+ return (FALSE);
+}
+
+
+bool_ is_blessed(object_type *o_ptr)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+ object_flags_known(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if (f3 & TR3_BLESSED) return (TRUE);
+ else return (FALSE);
+}
+
+
+
+/*
+ * Determine if the current store will purchase the given item
+ *
+ * Note that a shop-keeper must refuse to buy "worthless" items
+ */
+static bool_ store_will_buy(object_type *o_ptr)
+{
+ /* Hack -- The Home is simple */
+ if (cur_store_num == 7) return (TRUE);
+
+ if (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM) return TRUE;
+
+ /* XXX XXX XXX Ignore "worthless" items */
+ if (object_value(o_ptr) <= 0) return (FALSE);
+
+ /* Lua can define things to buy */
+ if (process_hooks_ret(HOOK_STORE_BUY, "d", "(d,s,O)", st_ptr->st_idx, st_info[st_ptr->st_idx].name + st_name, o_ptr))
+ {
+ return process_hooks_return[0].num;
+ }
+
+ /* Assume not okay */
+ return (FALSE);
+}
+
+
+
+/*
+ * Add the item "o_ptr" to the inventory of the "Home"
+ *
+ * In all cases, return the slot (or -1) where the object was placed
+ *
+ * Note that this is a hacked up version of "inven_carry()".
+ *
+ * Also note that it may not correctly "adapt" to "knowledge" bacoming
+ * known, the player may have to pick stuff up and drop it again.
+ */
+static int home_carry(object_type *o_ptr)
+{
+ int slot;
+ s32b value, j_value;
+ int i;
+ object_type *j_ptr;
+
+
+ /* Check each existing item (try to combine) */
+ for (slot = 0; slot < st_ptr->stock_num; slot++)
+ {
+ /* Get the existing item */
+ j_ptr = &st_ptr->stock[slot];
+
+ /* The home acts just like the player */
+ if (object_similar(j_ptr, o_ptr))
+ {
+ /* Save the new number of items */
+ object_absorb(j_ptr, o_ptr);
+
+ /* All done */
+ return (slot);
+ }
+ }
+
+ /* No space? */
+ if (st_ptr->stock_num >= st_ptr->stock_size) return ( -1);
+
+
+ /* Determine the "value" of the item */
+ value = object_value(o_ptr);
+
+ /* Check existing slots to see if we must "slide" */
+ for (slot = 0; slot < st_ptr->stock_num; slot++)
+ {
+ /* Get that item */
+ j_ptr = &st_ptr->stock[slot];
+
+ /* Objects sort by decreasing type */
+ if (o_ptr->tval > j_ptr->tval) break;
+ if (o_ptr->tval < j_ptr->tval) continue;
+
+ /* Can happen in the home */
+ if (!object_aware_p(o_ptr)) continue;
+ if (!object_aware_p(j_ptr)) break;
+
+ /* Objects sort by increasing sval */
+ if (o_ptr->sval < j_ptr->sval) break;
+ if (o_ptr->sval > j_ptr->sval) continue;
+
+ /* Objects in the home can be unknown */
+ if (!object_known_p(o_ptr)) continue;
+ if (!object_known_p(j_ptr)) break;
+
+
+ /*
+ * Hack: otherwise identical rods sort by
+ * increasing recharge time --dsb
+ */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ if (o_ptr->timeout < j_ptr->timeout) break;
+ if (o_ptr->timeout > j_ptr->timeout) continue;
+ }
+
+ /* Objects sort by decreasing value */
+ j_value = object_value(j_ptr);
+ if (value > j_value) break;
+ if (value < j_value) continue;
+ }
+
+ /* Slide the others up */
+ for (i = st_ptr->stock_num; i > slot; i--)
+ {
+ st_ptr->stock[i] = st_ptr->stock[i - 1];
+ }
+
+ /* More stuff now */
+ st_ptr->stock_num++;
+
+ /* Insert the new item */
+ st_ptr->stock[slot] = *o_ptr;
+
+ /* Return the location */
+ return (slot);
+}
+
+
+/*
+ * Add the item "o_ptr" to a real stores inventory.
+ *
+ * If the item is "worthless", it is thrown away (except in the home).
+ *
+ * If the item cannot be combined with an object already in the inventory,
+ * make a new slot for it, and calculate its "per item" price. Note that
+ * this price will be negative, since the price will not be "fixed" yet.
+ * Adding an item to a "fixed" price stack will not change the fixed price.
+ *
+ * In all cases, return the slot (or -1) where the object was placed
+ */
+static int store_carry(object_type *o_ptr)
+{
+ int i, slot;
+ s32b value, j_value;
+ object_type *j_ptr;
+
+
+ /* Evaluate the object */
+ value = object_value(o_ptr);
+
+ /* Cursed/Worthless items "disappear" when sold */
+ if (value <= 0) return ( -1);
+
+ /* All store items are fully *identified* */
+ o_ptr->ident |= IDENT_MENTAL;
+
+ /* Erase the inscription */
+ o_ptr->note = 0;
+
+ /* Check each existing item (try to combine) */
+ for (slot = 0; slot < st_ptr->stock_num; slot++)
+ {
+ /* Get the existing item */
+ j_ptr = &st_ptr->stock[slot];
+
+ /* Can the existing items be incremented? */
+ if (store_object_similar(j_ptr, o_ptr))
+ {
+ /* Hack -- extra items disappear */
+ store_object_absorb(j_ptr, o_ptr);
+
+ /* All done */
+ return (slot);
+ }
+ }
+
+ /* No space? */
+ if (st_ptr->stock_num >= st_ptr->stock_size) return ( -1);
+
+
+ /* Check existing slots to see if we must "slide" */
+ for (slot = 0; slot < st_ptr->stock_num; slot++)
+ {
+ /* Get that item */
+ j_ptr = &st_ptr->stock[slot];
+
+ /* Objects sort by decreasing type */
+ if (o_ptr->tval > j_ptr->tval) break;
+ if (o_ptr->tval < j_ptr->tval) continue;
+
+ /* Objects sort by increasing sval */
+ if (o_ptr->sval < j_ptr->sval) break;
+ if (o_ptr->sval > j_ptr->sval) continue;
+
+
+ /*
+ * Hack: otherwise identical rods sort by
+ * increasing recharge time --dsb
+ */
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ if (o_ptr->timeout < j_ptr->timeout) break;
+ if (o_ptr->timeout > j_ptr->timeout) continue;
+ }
+
+ /* Evaluate that slot */
+ j_value = object_value(j_ptr);
+
+ /* Objects sort by decreasing value */
+ if (value > j_value) break;
+ if (value < j_value) continue;
+ }
+
+ /* Slide the others up */
+ for (i = st_ptr->stock_num; i > slot; i--)
+ {
+ st_ptr->stock[i] = st_ptr->stock[i - 1];
+ }
+
+ /* More stuff now */
+ st_ptr->stock_num++;
+
+ /* Insert the new item */
+ st_ptr->stock[slot] = *o_ptr;
+
+ /* Return the location */
+ return (slot);
+}
+
+
+/*
+ * Increase, by a given amount, the number of a certain item
+ * in a certain store. This can result in zero items.
+ */
+static void store_item_increase(int item, int num)
+{
+ int cnt;
+ object_type *o_ptr;
+
+ /* Get the item */
+ o_ptr = &st_ptr->stock[item];
+
+ /* Verify the number */
+ cnt = o_ptr->number + num;
+ if (cnt > 255) cnt = 255;
+ else if (cnt < 0) cnt = 0;
+ num = cnt - o_ptr->number;
+
+ /* Save the new number */
+ o_ptr->number += num;
+}
+
+
+/*
+ * Remove a slot if it is empty
+ */
+static void store_item_optimize(int item)
+{
+ int j;
+ object_type *o_ptr;
+
+ /* Get the item */
+ o_ptr = &st_ptr->stock[item];
+
+ /* Must exist */
+ if (!o_ptr->k_idx) return;
+
+ /* Must have no items */
+ if (o_ptr->number) return;
+
+ /* One less item */
+ st_ptr->stock_num--;
+
+ /* Slide everyone */
+ for (j = item; j < st_ptr->stock_num; j++)
+ {
+ st_ptr->stock[j] = st_ptr->stock[j + 1];
+ }
+
+ /* Nuke the final slot */
+ object_wipe(&st_ptr->stock[j]);
+}
+
+
+/*
+ * This function will keep 'crap' out of the black market.
+ * Crap is defined as any item that is "available" elsewhere
+ * Based on a suggestion by "Lee Vogt" <lvogt@cig.mcel.mot.com>
+ */
+static bool_ black_market_crap(object_type *o_ptr)
+{
+ int i, j;
+
+ /* Ego items are never crap */
+ if (o_ptr->name2) return (FALSE);
+
+ /* Good items are never crap */
+ if (o_ptr->to_a > 0) return (FALSE);
+ if (o_ptr->to_h > 0) return (FALSE);
+ if (o_ptr->to_d > 0) return (FALSE);
+
+ /* Check all stores */
+ for (i = 0; i < max_st_idx; i++)
+ {
+ if (i == STORE_HOME) continue;
+ if (st_info[i].flags1 & SF1_MUSEUM) continue;
+
+ /* Check every item in the store */
+ for (j = 0; j < town_info[p_ptr->town_num].store[i].stock_num; j++)
+ {
+ object_type *j_ptr = &town_info[p_ptr->town_num].store[i].stock[j];
+
+ /* Duplicate item "type", assume crappy */
+ if (o_ptr->k_idx == j_ptr->k_idx) return (TRUE);
+ }
+ }
+
+ /* Assume okay */
+ return (FALSE);
+}
+
+
+/*
+ * Attempt to delete (some of) a random item from the store
+ * Hack -- we attempt to "maintain" piles of items when possible.
+ */
+static void store_delete(void)
+{
+ int what, num;
+
+ /* Pick a random slot */
+ what = rand_int(st_ptr->stock_num);
+
+ /* Determine how many items are here */
+ num = st_ptr->stock[what].number;
+
+ /* Hack -- sometimes, only destroy half the items */
+ if (rand_int(100) < 50) num = (num + 1) / 2;
+
+ /* Hack -- sometimes, only destroy a single item */
+ if (rand_int(100) < 50) num = 1;
+
+ /* Hack -- decrement the maximum timeouts and total charges of rods and wands. -LM- */
+ if (st_ptr->stock[what].tval == TV_WAND)
+ {
+ st_ptr->stock[what].pval -= num * st_ptr->stock[what].pval / st_ptr->stock[what].number;
+ }
+
+ /* Actually destroy (part of) the item */
+ store_item_increase(what, -num);
+ store_item_optimize(what);
+}
+
+/* Analyze store flags and return a level */
+int return_level()
+{
+ store_info_type *sti_ptr = &st_info[st_ptr->st_idx];
+ int level;
+
+ if (sti_ptr->flags1 & SF1_RANDOM) level = 0;
+ else level = rand_range(1, STORE_OBJ_LEVEL);
+
+ if (sti_ptr->flags1 & SF1_DEPEND_LEVEL) level += dun_level;
+
+ if (sti_ptr->flags1 & SF1_SHALLOW_LEVEL) level += 5 + rand_int(5);
+ if (sti_ptr->flags1 & SF1_MEDIUM_LEVEL) level += 25 + rand_int(25);
+ if (sti_ptr->flags1 & SF1_DEEP_LEVEL) level += 45 + rand_int(45);
+
+ if (sti_ptr->flags1 & SF1_ALL_ITEM) level += p_ptr->lev;
+
+ return (level);
+}
+
+/* Is it an ok object ? */
+static int store_tval = 0, store_level = 0;
+
+/*
+ * Hack -- determine if a template is "good"
+ */
+static bool_ kind_is_storeok(int k_idx)
+{
+ object_kind *k_ptr = &k_info[k_idx];
+
+ if (k_info[k_idx].flags3 & TR3_NORM_ART)
+ return ( FALSE );
+
+ if (k_info[k_idx].flags3 & TR3_INSTA_ART)
+ return ( FALSE );
+
+ if (!kind_is_legal(k_idx)) return FALSE;
+
+ if (k_ptr->tval != store_tval) return (FALSE);
+ if (k_ptr->level < (store_level / 2)) return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * Creates a random item and gives it to a store
+ * This algorithm needs to be rethought. A lot.
+ *
+ * Note -- the "level" given to "obj_get_num()" is a "favored"
+ * level, that is, there is a much higher chance of getting
+ * items with a level approaching that of the given level...
+ *
+ * Should we check for "permission" to have the given item?
+ */
+static void store_create(void)
+{
+ int i = 0, tries, level = 0, chance, item;
+
+ object_type forge;
+ object_type *q_ptr = NULL;
+ bool_ obj_all_done = FALSE;
+
+
+ /* Paranoia -- no room left */
+ if (st_ptr->stock_num >= st_ptr->stock_size) return;
+
+
+ /* Hack -- consider up to four items */
+ for (tries = 0; tries < 4; tries++)
+ {
+ obj_all_done = FALSE;
+
+ /* Lua can define things to buy */
+ if (process_hooks_ret(HOOK_STORE_STOCK, "O", "(d,s,d)", st_ptr->st_idx, st_info[st_ptr->st_idx].name + st_name, return_level()))
+ {
+ obj_all_done = TRUE;
+ q_ptr = process_hooks_return[0].o_ptr;
+ }
+
+ /* Black Market */
+ else if (st_info[st_ptr->st_idx].flags1 & SF1_ALL_ITEM)
+ {
+ obj_theme theme;
+
+ /* No themes */
+ theme.treasure = 100;
+ theme.combat = 100;
+ theme.magic = 100;
+ theme.tools = 100;
+ init_match_theme(theme);
+
+ /*
+ * Even in Black Markets, illegal objects can be
+ * problematic -- Oxymoron?
+ */
+ get_obj_num_hook = kind_is_legal;
+
+ /* Rebuild the allocation table */
+ get_obj_num_prep();
+
+ /* Pick a level for object/magic */
+ level = return_level();
+
+ /* Random item (usually of given level) */
+ i = get_obj_num(level);
+
+ /* Invalidate the cached allocation table */
+ alloc_kind_table_valid = FALSE;
+
+ /* Handle failure */
+ if (!i) continue;
+
+ }
+
+ /* Normal Store */
+ else
+ {
+ /* Hack -- Pick an item to sell */
+ item = rand_int(st_info[st_ptr->st_idx].table_num);
+ i = st_info[st_ptr->st_idx].table[item][0];
+ chance = st_info[st_ptr->st_idx].table[item][1];
+
+ /* Don't allow k_info artifacts */
+ if ((i <= 10000) && (k_info[i].flags3 & TR3_NORM_ART))
+ continue;
+
+ /* Does it passes the rarity check ? */
+ if (!magik(chance)) continue;
+
+ /* Hack -- fake level for apply_magic() */
+ level = return_level();
+
+ /* Hack -- i > 10000 means it's a tval and all svals are allowed */
+ if (i > 10000)
+ {
+ obj_theme theme;
+
+ /* No themes */
+ theme.treasure = 100;
+ theme.combat = 100;
+ theme.magic = 100;
+ theme.tools = 100;
+ init_match_theme(theme);
+
+ /* Activate restriction */
+ get_obj_num_hook = kind_is_storeok;
+ store_tval = i - 10000;
+
+ /* Do we forbid too shallow items ? */
+ if (st_info[st_ptr->st_idx].flags1 & SF1_FORCE_LEVEL) store_level = level;
+ else store_level = 0;
+
+ /* Prepare allocation table */
+ get_obj_num_prep();
+
+ /* Get it ! */
+ i = get_obj_num(level);
+
+ /* Invalidate the cached allocation table */
+ alloc_kind_table_valid = FALSE;
+ }
+
+ if (!i) continue;
+ }
+
+ /* Only if not already done */
+ if (!obj_all_done)
+ {
+ /* Don't allow k_info artifacts */
+ if (k_info[i].flags3 & TR3_NORM_ART)
+ continue;
+
+ /* Don't allow artifacts */
+ if (k_info[i].flags3 & TR3_INSTA_ART)
+ continue;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Create a new object of the chosen kind */
+ object_prep(q_ptr, i);
+
+ /* Apply some "low-level" magic (no artifacts) */
+ apply_magic(q_ptr, level, FALSE, FALSE, FALSE);
+
+ /* Hack -- Charge lite's */
+ if (q_ptr->tval == TV_LITE)
+ {
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(q_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (f4 & TR4_FUEL_LITE) q_ptr->timeout = k_info[q_ptr->k_idx].pval2;
+ }
+
+ }
+
+ /* The item is "known" */
+ object_known(q_ptr);
+
+ /* Mark it storebought */
+ q_ptr->ident |= IDENT_STOREB;
+
+ /* Mega-Hack -- no chests in stores */
+ if (q_ptr->tval == TV_CHEST) continue;
+
+ /* Prune the black market */
+ if (st_info[st_ptr->st_idx].flags1 & SF1_ALL_ITEM)
+ {
+ /* Hack -- No "crappy" items */
+ if (black_market_crap(q_ptr)) continue;
+
+ /* Hack -- No "cheap" items */
+ if (object_value(q_ptr) < 10) continue;
+ }
+
+ /* Prune normal stores */
+ else
+ {
+ /* No "worthless" items */
+ if (object_value(q_ptr) <= 0) continue;
+ }
+
+
+ /* Mass produce and/or Apply discount */
+ mass_produce(q_ptr);
+
+ /* The charges an wands are per each, so multiply to get correct number */
+ if (!obj_all_done && q_ptr->tval == TV_WAND)
+ {
+ q_ptr->pval *= q_ptr->number;
+ }
+
+ /* Attempt to carry the (known) item */
+ (void)store_carry(q_ptr);
+
+ /* Definitely done */
+ break;
+ }
+}
+
+
+
+/*
+ * Eliminate need to bargain if player has haggled well in the past
+ */
+static bool_ noneedtobargain(s32b minprice)
+{
+ s32b good = st_ptr->good_buy;
+ s32b bad = st_ptr->bad_buy;
+
+ /* Cheap items are "boring" */
+ if (minprice < 10L) return (TRUE);
+
+ /* Perfect haggling */
+ if (good == MAX_SHORT) return (TRUE);
+
+ /* Reward good haggles, punish bad haggles, notice price */
+ if (good > ((3 * bad) + (5 + (minprice / 50)))) return (TRUE);
+
+ /* Return the flag */
+ return (FALSE);
+}
+
+
+/*
+ * Update the bargain info
+ */
+static void updatebargain(s32b price, s32b minprice)
+{
+ /* Hack -- auto-haggle */
+ if (auto_haggle) return;
+
+ /* Cheap items are "boring" */
+ if (minprice < 10L) return;
+
+ /* Count the successful haggles */
+ if (price == minprice)
+ {
+ /* Just count the good haggles */
+ if (st_ptr->good_buy < MAX_SHORT)
+ {
+ st_ptr->good_buy++;
+ }
+ }
+
+ /* Count the failed haggles */
+ else
+ {
+ /* Just count the bad haggles */
+ if (st_ptr->bad_buy < MAX_SHORT)
+ {
+ st_ptr->bad_buy++;
+ }
+ }
+}
+
+
+
+/*
+ * Re-displays a single store entry
+ */
+static void display_entry(int pos)
+{
+ int i, cur_col;
+ object_type *o_ptr;
+ s32b x;
+
+ char o_name[80];
+ char out_val[160];
+
+
+ int maxwid = 75;
+
+ /* Get the item */
+ o_ptr = &st_ptr->stock[pos];
+
+ /* Get the "offset" */
+ i = (pos % 12);
+
+ /* Label it, clear the line --(-- */
+ strnfmt(out_val, 160, "%c) ", I2A(i));
+ c_prt(get_item_letter_color(o_ptr), out_val, i + 6, 0);
+
+
+ cur_col = 3;
+ if (show_store_graph)
+ {
+ byte a = object_attr(o_ptr);
+ char c = object_char(o_ptr);
+
+ if (!o_ptr->k_idx) c = ' ';
+
+ Term_draw(cur_col, i + 6, a, c);
+ if (use_bigtile)
+ {
+ cur_col++;
+ if (a & 0x80)
+ Term_draw(cur_col, i + 6, 255, 255);
+ }
+ cur_col += 2;
+ }
+
+ /* Describe an item in the home */
+ if ((cur_store_num == 7) ||
+ (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM))
+ {
+ maxwid = 75;
+
+ /* Leave room for weights, if necessary -DRS- */
+ if (show_weights) maxwid -= 10;
+
+ /* Describe the object */
+ object_desc(o_name, o_ptr, TRUE, 3);
+ o_name[maxwid] = '\0';
+ c_put_str(tval_to_attr[o_ptr->tval], o_name, i + 6, cur_col);
+
+ /* Show weights */
+ if (show_weights)
+ {
+ /* Only show the weight of an individual item */
+ int wgt = o_ptr->weight;
+ strnfmt(out_val, 160, "%3d.%d lb", wgt / 10, wgt % 10);
+ put_str(out_val, i + 6, 68);
+ }
+ }
+
+ /* Describe an item (fully) in a store */
+ else
+ {
+ byte color = TERM_WHITE;
+
+ /* Must leave room for the "price" */
+ maxwid = 65;
+
+ /* Leave room for weights, if necessary -DRS- */
+ if (show_weights) maxwid -= 7;
+
+ /* Describe the object (fully) */
+ object_desc_store(o_name, o_ptr, TRUE, 3);
+ o_name[maxwid] = '\0';
+ c_put_str(tval_to_attr[o_ptr->tval], o_name, i + 6, cur_col);
+
+ /* Show weights */
+ if (show_weights)
+ {
+ /* Only show the weight of an individual item */
+ int wgt = o_ptr->weight;
+ strnfmt(out_val, 160, "%3d.%d", wgt / 10, wgt % 10);
+ put_str(out_val, i + 6, 61);
+ }
+
+ /* Display a "fixed" cost */
+ if (o_ptr->ident & (IDENT_FIXED))
+ {
+ /* Extract the "minimum" price */
+ x = price_item(o_ptr, ot_ptr->min_inflate, FALSE);
+
+ /* Can we buy one ? */
+ if (x > p_ptr->au) color = TERM_L_DARK;
+
+ /* Actually draw the price (not fixed) */
+ strnfmt(out_val, 160, "%9ld F", (long)x);
+ c_put_str(color, out_val, i + 6, 68);
+ }
+
+ /* Display a "taxed" cost */
+ else if (auto_haggle)
+ {
+ /* Extract the "minimum" price */
+ x = price_item(o_ptr, ot_ptr->min_inflate, FALSE);
+
+ /* Hack -- Apply Sales Tax if needed */
+ if (!noneedtobargain(x)) x += x / 10;
+
+ /* Can we buy one ? */
+ if (x > p_ptr->au) color = TERM_L_DARK;
+
+ /* Actually draw the price (with tax) */
+ strnfmt(out_val, 160, "%9ld ", (long)x);
+ c_put_str(color, out_val, i + 6, 68);
+ }
+
+ /* Display a "haggle" cost */
+ else
+ {
+ /* Extrect the "maximum" price */
+ x = price_item(o_ptr, ot_ptr->max_inflate, FALSE);
+
+ /* Can we buy one ? */
+ if (x > p_ptr->au) color = TERM_L_DARK;
+
+ /* Actually draw the price (not fixed) */
+ strnfmt(out_val, 160, "%9ld ", (long)x);
+ c_put_str(color, out_val, i + 6, 68);
+ }
+ }
+}
+
+
+/*
+ * Displays a store's inventory -RAK-
+ * All prices are listed as "per individual object". -BEN-
+ */
+static void display_inventory(void)
+{
+ int i, k;
+
+ /* Display the next 12 items */
+ for (k = 0; k < 12; k++)
+ {
+ /* Do not display "dead" items */
+ if (store_top + k >= st_ptr->stock_num) break;
+
+ /* Display that line */
+ display_entry(store_top + k);
+ }
+
+ /* Erase the extra lines and the "more" prompt */
+ for (i = k; i < 13; i++) prt("", i + 6, 0);
+
+ /* Assume "no current page" */
+ put_str(" ", 5, 20);
+
+ /* Visual reminder of "more items" */
+ if (st_ptr->stock_num > 12)
+ {
+ /* Show "more" reminder (after the last item) */
+ prt("-more-", k + 6, 3);
+
+ /* Indicate the "current page" */
+ put_str(format("(Page %d) ", store_top / 12 + 1), 5, 20);
+ }
+}
+
+
+/*
+ * Displays players gold -RAK-
+ */
+void store_prt_gold(void)
+{
+ char out_val[64];
+
+ prt("Gold Remaining: ", 19, 53);
+
+ strnfmt(out_val, 64, "%9ld", (long)p_ptr->au);
+ prt(out_val, 19, 68);
+}
+
+
+/*
+ * Displays store (after clearing screen) -RAK-
+ */
+void display_store(void)
+{
+ char buf[80];
+
+
+ /* Clear screen */
+ Term_clear();
+
+ /* The "Home" is special */
+ if (cur_store_num == 7)
+ {
+ put_str("Your Home", 3, 30);
+
+ /* Label the item descriptions */
+ put_str("Item Description", 5, 3);
+
+ /* If showing weights, show label */
+ if (show_weights)
+ {
+ put_str("Weight", 5, 70);
+ }
+ }
+
+ else if (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM)
+ {
+ cptr store_name = (st_name + st_info[cur_store_num].name);
+
+ /* Show the name of the store */
+ strnfmt(buf, 80, "%s", store_name);
+ prt(buf, 3, 30);
+
+ /* Label the item descriptions */
+ put_str("Item Description", 5, 3);
+
+ /* If showing weights, show label */
+ if (show_weights)
+ {
+ put_str("Weight", 5, 70);
+ }
+ }
+
+ /* Normal stores */
+ else
+ {
+ cptr store_name = (st_name + st_info[cur_store_num].name);
+ cptr owner_name = (ow_name + ot_ptr->name);
+
+ /* Put the owner name and race */
+ strnfmt(buf, 80, "%s", owner_name);
+ put_str(buf, 3, 10);
+
+ /* Show the max price in the store (above prices) */
+ strnfmt(buf, 80, "%s (%ld)", store_name, (long)(ot_ptr->max_cost));
+ prt(buf, 3, 50);
+
+ /* Label the item descriptions */
+ put_str("Item Description", 5, 3);
+
+ /* If showing weights, show label */
+ if (show_weights)
+ {
+ put_str("Weight", 5, 60);
+ }
+
+ /* Label the asking price (in stores) */
+ put_str("Price", 5, 72);
+ }
+
+ /* Display the current gold */
+ store_prt_gold();
+
+ /* Draw in the inventory */
+ display_inventory();
+}
+
+
+
+/*
+ * Get the ID of a store item and return its value -RAK-
+ */
+static int get_stock(int *com_val, cptr pmt, int i, int j)
+{
+ char command;
+
+ char out_val[160];
+
+ /* Get the item index */
+ if (repeat_pull(com_val))
+ {
+
+ /* Verify the item */
+ if ((*com_val >= i) && (*com_val <= j))
+ {
+ /* Success */
+ return (TRUE);
+ }
+ }
+
+ /* Paranoia XXX XXX XXX */
+ msg_print(NULL);
+
+
+ /* Assume failure */
+ *com_val = ( -1);
+
+ /* Build the prompt */
+ strnfmt(out_val, 160, "(Items %c-%c, ESC to exit) %s",
+ I2A(i), I2A(j), pmt);
+
+ /* Ask until done */
+ while (TRUE)
+ {
+ int k;
+
+ /* Escape */
+ if (!get_com(out_val, &command)) break;
+
+ /* Convert */
+ k = (islower(command) ? A2I(command) : -1);
+
+ /* Legal responses */
+ if ((k >= i) && (k <= j))
+ {
+ *com_val = k;
+ break;
+ }
+
+ /* Oops */
+ bell();
+ }
+
+ /* Clear the prompt */
+ prt("", 0, 0);
+
+ /* Cancel */
+ if (command == ESCAPE) return (FALSE);
+
+ repeat_push(*com_val);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Increase the insult counter and get angry if too many -RAK-
+ */
+static int increase_insults(void)
+{
+ /* Increase insults */
+ st_ptr->insult_cur++;
+
+ /* Become insulted */
+ if (st_ptr->insult_cur > ot_ptr->insult_max)
+ {
+ /* Complain */
+ say_comment_4();
+
+ /* Reset insults */
+ st_ptr->insult_cur = 0;
+ st_ptr->good_buy = 0;
+ st_ptr->bad_buy = 0;
+
+ /* Open tomorrow */
+ st_ptr->store_open = turn + 25000 + randint(25000);
+
+ /* Closed */
+ return (TRUE);
+ }
+
+ /* Not closed */
+ return (FALSE);
+}
+
+
+/*
+ * Decrease insults -RAK-
+ */
+static void decrease_insults(void)
+{
+ /* Decrease insults */
+ if (st_ptr->insult_cur) st_ptr->insult_cur--;
+}
+
+
+/*
+ * Have insulted while haggling -RAK-
+ */
+static int haggle_insults(void)
+{
+ /* Increase insults */
+ if (increase_insults()) return (TRUE);
+
+ /* Display and flush insult */
+ say_comment_5();
+
+ /* Still okay */
+ return (FALSE);
+}
+
+
+/*
+ * Mega-Hack -- Enable "increments"
+ */
+static bool_ allow_inc = FALSE;
+
+/*
+ * Mega-Hack -- Last "increment" during haggling
+ */
+static s32b last_inc = 0L;
+
+
+/*
+ * Get a haggle
+ */
+static int get_haggle(cptr pmt, s32b *poffer, s32b price, int final)
+{
+ s32b i;
+
+ cptr p;
+
+ char buf[128];
+ char out_val[160];
+
+
+ /* Clear old increment if necessary */
+ if (!allow_inc) last_inc = 0L;
+
+
+ /* Final offer */
+ if (final)
+ {
+ strnfmt(buf, 128, "%s [accept] ", pmt);
+ }
+
+ /* Old (negative) increment, and not final */
+ else if (last_inc < 0)
+ {
+ strnfmt(buf, 128, "%s [-%ld] ", pmt, (long)(ABS(last_inc)));
+ }
+
+ /* Old (positive) increment, and not final */
+ else if (last_inc > 0)
+ {
+ strnfmt(buf, 128, "%s [+%ld] ", pmt, (long)(ABS(last_inc)));
+ }
+
+ /* Normal haggle */
+ else
+ {
+ strnfmt(buf, 128, "%s ", pmt);
+ }
+
+
+ /* Paranoia XXX XXX XXX */
+ msg_print(NULL);
+
+
+ /* Ask until done */
+ while (TRUE)
+ {
+ /* Default */
+ strcpy(out_val, "");
+
+ /* Ask the user for a response */
+ if (!get_string(buf, out_val, 32)) return (FALSE);
+
+ /* Skip leading spaces */
+ for (p = out_val; *p == ' '; p++) /* loop */;
+
+ /* Empty response */
+ if (*p == '\0')
+ {
+ /* Accept current price */
+ if (final)
+ {
+ *poffer = price;
+ last_inc = 0L;
+ break;
+ }
+
+ /* Use previous increment */
+ if (allow_inc && last_inc)
+ {
+ *poffer += last_inc;
+ break;
+ }
+ }
+
+ /* Normal response */
+ else
+ {
+ /* Extract a number */
+ i = atol(p);
+
+ /* Handle "incremental" number */
+ if ((*p == '+' || *p == '-'))
+ {
+ /* Allow increments */
+ if (allow_inc)
+ {
+ /* Use the given "increment" */
+ *poffer += i;
+ last_inc = i;
+ break;
+ }
+ }
+
+ /* Handle normal number */
+ else
+ {
+ /* Use the given "number" */
+ *poffer = i;
+ last_inc = 0L;
+ break;
+ }
+ }
+
+ /* Warning */
+ msg_print("Invalid response.");
+ msg_print(NULL);
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Receive an offer (from the player)
+ *
+ * Return TRUE if offer is NOT okay
+ */
+static bool_ receive_offer(cptr pmt, s32b *poffer,
+ s32b last_offer, int factor,
+ s32b price, int final)
+{
+ /* Haggle till done */
+ while (TRUE)
+ {
+ /* Get a haggle (or cancel) */
+ if (!get_haggle(pmt, poffer, price, final)) return (TRUE);
+
+ /* Acceptable offer */
+ if (((*poffer) * factor) >= (last_offer * factor)) break;
+
+ /* Insult, and check for kicked out */
+ if (haggle_insults()) return (TRUE);
+
+ /* Reject offer (correctly) */
+ (*poffer) = last_offer;
+ }
+
+ /* Success */
+ return (FALSE);
+}
+
+
+/*
+ * Haggling routine -RAK-
+ *
+ * Return TRUE if purchase is NOT successful
+ */
+static bool_ purchase_haggle(object_type *o_ptr, s32b *price)
+{
+ s32b cur_ask, final_ask;
+ s32b last_offer, offer;
+ s32b x1, x2, x3;
+ s32b min_per, max_per;
+ int flag, loop_flag, noneed;
+ int annoyed = 0, final = FALSE;
+
+ bool_ cancel = FALSE;
+
+ cptr pmt = "Asking";
+
+ char out_val[160];
+
+
+ *price = 0;
+
+
+ /* Extract the starting offer and the final offer */
+ cur_ask = price_item(o_ptr, ot_ptr->max_inflate, FALSE);
+ final_ask = price_item(o_ptr, ot_ptr->min_inflate, FALSE);
+
+ /* Determine if haggling is necessary */
+ noneed = noneedtobargain(final_ask);
+
+ /* No need to haggle */
+ if (noneed || auto_haggle)
+ {
+ /* No need to haggle */
+ if (noneed)
+ {
+ /* Message summary */
+ msg_print("You eventually agree upon the price.");
+ msg_print(NULL);
+ }
+
+ /* No haggle option */
+ else
+ {
+ /* Message summary */
+ msg_print("You quickly agree upon the price.");
+ msg_print(NULL);
+
+ /* Apply Sales Tax */
+ final_ask += final_ask / 10;
+ }
+
+ /* Final price */
+ cur_ask = final_ask;
+
+ /* Go to final offer */
+ pmt = "Final Offer";
+ final = TRUE;
+ }
+
+
+ /* Haggle for the whole pile */
+ cur_ask *= o_ptr->number;
+ final_ask *= o_ptr->number;
+
+
+ /* Haggle parameters */
+ min_per = ot_ptr->haggle_per;
+ max_per = min_per * 3;
+
+ /* Mega-Hack -- artificial "last offer" value */
+ last_offer = object_value(o_ptr) * o_ptr->number;
+ last_offer = last_offer * (200 - (int)(ot_ptr->max_inflate)) / 100L;
+ if (last_offer <= 0) last_offer = 1;
+
+ /* No offer yet */
+ offer = 0;
+
+ /* No incremental haggling yet */
+ allow_inc = FALSE;
+
+ /* Haggle until done */
+ for (flag = FALSE; !flag; )
+ {
+ loop_flag = TRUE;
+
+ while (!flag && loop_flag)
+ {
+ strnfmt(out_val, 160, "%s : %ld", pmt, (long)cur_ask);
+ put_str(out_val, 1, 0);
+ cancel = receive_offer("What do you offer? ",
+ &offer, last_offer, 1, cur_ask, final);
+
+ if (cancel)
+ {
+ flag = TRUE;
+ }
+ else if (offer > cur_ask)
+ {
+ say_comment_6();
+ offer = last_offer;
+ }
+ else if (offer == cur_ask)
+ {
+ flag = TRUE;
+ *price = offer;
+ }
+ else
+ {
+ loop_flag = FALSE;
+ }
+ }
+
+ if (!flag)
+ {
+ x1 = 100 * (offer - last_offer) / (cur_ask - last_offer);
+ if (x1 < min_per)
+ {
+ if (haggle_insults())
+ {
+ flag = TRUE;
+ cancel = TRUE;
+ }
+ }
+ else if (x1 > max_per)
+ {
+ x1 = x1 * 3 / 4;
+ if (x1 < max_per) x1 = max_per;
+ }
+ x2 = rand_range(x1 - 2, x1 + 2);
+ x3 = ((cur_ask - offer) * x2 / 100L) + 1;
+ /* don't let the price go up */
+ if (x3 < 0) x3 = 0;
+ cur_ask -= x3;
+
+ /* Too little */
+ if (cur_ask < final_ask)
+ {
+ final = TRUE;
+ cur_ask = final_ask;
+ pmt = "Final Offer";
+ annoyed++;
+ if (annoyed > 3)
+ {
+ (void)(increase_insults());
+ cancel = TRUE;
+ flag = TRUE;
+ }
+ }
+ else if (offer >= cur_ask)
+ {
+ flag = TRUE;
+ *price = offer;
+ }
+
+ if (!flag)
+ {
+ last_offer = offer;
+ allow_inc = TRUE;
+ prt("", 1, 0);
+ strnfmt(out_val, 160, "Your last offer: %ld",
+ (long)last_offer);
+ put_str(out_val, 1, 39);
+ say_comment_2(cur_ask, annoyed);
+ }
+ }
+ }
+
+ /* Cancel */
+ if (cancel) return (TRUE);
+
+ /* Update bargaining info */
+ updatebargain(*price, final_ask);
+
+ /* Do not cancel */
+ return (FALSE);
+}
+
+
+/*
+ * Haggling routine -RAK-
+ *
+ * Return TRUE if purchase is NOT successful
+ */
+static bool_ sell_haggle(object_type *o_ptr, s32b *price)
+{
+ s32b purse, cur_ask, final_ask;
+ s32b last_offer = 0, offer = 0;
+ s32b x1, x2, x3;
+ s32b min_per, max_per;
+
+ int flag, loop_flag, noneed;
+ int annoyed = 0, final = FALSE;
+
+ bool_ cancel = FALSE;
+
+ cptr pmt = "Offer";
+
+ char out_val[160];
+
+
+ *price = 0;
+
+
+ /* Obtain the starting offer and the final offer */
+ cur_ask = price_item(o_ptr, ot_ptr->max_inflate, TRUE);
+ final_ask = price_item(o_ptr, ot_ptr->min_inflate, TRUE);
+
+ /* Determine if haggling is necessary */
+ noneed = noneedtobargain(final_ask);
+
+ /* Get the owner's payout limit */
+ purse = (s32b)(ot_ptr->max_cost);
+
+ /* No need to haggle */
+ if (noneed || auto_haggle || (final_ask >= purse))
+ {
+ /* No reason to haggle */
+ if (final_ask >= purse)
+ {
+ /* Message */
+ msg_print("You instantly agree upon the price.");
+ msg_print(NULL);
+
+ /* Offer full purse */
+ final_ask = purse;
+ }
+
+ /* No need to haggle */
+ else if (noneed)
+ {
+ /* Message */
+ msg_print("You eventually agree upon the price.");
+ msg_print(NULL);
+ }
+
+ /* No haggle option */
+ else
+ {
+ /* Message summary */
+ msg_print("You quickly agree upon the price.");
+ msg_print(NULL);
+
+ /* Apply Sales Tax */
+ final_ask -= final_ask / 10;
+ }
+
+ /* Final price */
+ cur_ask = final_ask;
+
+ /* Final offer */
+ final = TRUE;
+ pmt = "Final Offer";
+ }
+
+ /* Haggle for the whole pile */
+ cur_ask *= o_ptr->number;
+ final_ask *= o_ptr->number;
+
+
+ /* XXX XXX XXX Display commands */
+
+ /* Haggling parameters */
+ min_per = ot_ptr->haggle_per;
+ max_per = min_per * 3;
+
+ /* Mega-Hack -- artificial "last offer" value */
+ last_offer = object_value(o_ptr) * o_ptr->number;
+ last_offer = last_offer * ot_ptr->max_inflate / 100L;
+
+ /* No offer yet */
+ offer = 0;
+
+ /* No incremental haggling yet */
+ allow_inc = FALSE;
+
+ /* Haggle */
+ for (flag = FALSE; !flag; )
+ {
+ while (1)
+ {
+ loop_flag = TRUE;
+
+ strnfmt(out_val, 160, "%s : %ld", pmt, (long)cur_ask);
+ put_str(out_val, 1, 0);
+ cancel = receive_offer("What price do you ask? ",
+ &offer, last_offer, -1, cur_ask, final);
+
+ if (cancel)
+ {
+ flag = TRUE;
+ }
+ else if (offer < cur_ask)
+ {
+ say_comment_6();
+ /* rejected, reset offer for incremental haggling */
+ offer = last_offer;
+ }
+ else if (offer == cur_ask)
+ {
+ flag = TRUE;
+ *price = offer;
+ }
+ else
+ {
+ loop_flag = FALSE;
+ }
+
+ /* Stop */
+ if (flag || !loop_flag) break;
+ }
+
+ if (!flag)
+ {
+ x1 = 100 * (last_offer - offer) / (last_offer - cur_ask);
+ if (x1 < min_per)
+ {
+ if (haggle_insults())
+ {
+ flag = TRUE;
+ cancel = TRUE;
+ }
+ }
+ else if (x1 > max_per)
+ {
+ x1 = x1 * 3 / 4;
+ if (x1 < max_per) x1 = max_per;
+ }
+ x2 = rand_range(x1 - 2, x1 + 2);
+ x3 = ((offer - cur_ask) * x2 / 100L) + 1;
+ /* don't let the price go down */
+ if (x3 < 0) x3 = 0;
+ cur_ask += x3;
+
+ if (cur_ask > final_ask)
+ {
+ cur_ask = final_ask;
+ final = TRUE;
+ pmt = "Final Offer";
+ annoyed++;
+ if (annoyed > 3)
+ {
+ flag = TRUE;
+ (void)(increase_insults());
+ }
+ }
+ else if (offer <= cur_ask)
+ {
+ flag = TRUE;
+ *price = offer;
+ }
+
+ if (!flag)
+ {
+ last_offer = offer;
+ allow_inc = TRUE;
+ prt("", 1, 0);
+ strnfmt(out_val, 160,
+ "Your last bid %ld", (long)last_offer);
+ put_str(out_val, 1, 39);
+ say_comment_3(cur_ask, annoyed);
+ }
+ }
+ }
+
+ /* Cancel */
+ if (cancel) return (TRUE);
+
+ /* Update bargaining info */
+ updatebargain(*price, final_ask);
+
+ /* Do not cancel */
+ return (FALSE);
+}
+
+/*
+ * Will the owner retire?
+ */
+static bool_ retire_owner_p(void)
+{
+ store_info_type *sti_ptr = &st_info[town_info[p_ptr->town_num].store[cur_store_num].st_idx];
+
+ if ((sti_ptr->owners[0] == sti_ptr->owners[1]) &&
+ (sti_ptr->owners[0] == sti_ptr->owners[2]) &&
+ (sti_ptr->owners[0] == sti_ptr->owners[3]))
+ {
+ /* there is no other owner */
+ return FALSE;
+ }
+
+ if (rand_int(STORE_SHUFFLE) != 0)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Stole an item from a store -DG-
+ */
+void store_stole(void)
+{
+ int i, amt;
+ int item, item_new;
+
+ object_type forge;
+ object_type *j_ptr;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ char out_val[160];
+
+ if (cur_store_num == 7)
+ {
+ msg_print("You can't steal from your home!");
+ return;
+ }
+
+ /* Empty? */
+ if (st_ptr->stock_num <= 0)
+ {
+ msg_print("There is no item to steal.");
+ return;
+ }
+
+
+ /* Find the number of objects on this and following pages */
+ i = (st_ptr->stock_num - store_top);
+
+ /* And then restrict it to the current page */
+ if (i > 12) i = 12;
+
+ /* Prompt */
+ strnfmt(out_val, 160, "Which item do you want to steal? ");
+
+ /* Get the item number to be bought */
+ if (!get_stock(&item, out_val, 0, i - 1)) return;
+
+ /* Get the actual index */
+ item = item + store_top;
+
+ /* Get the actual item */
+ o_ptr = &st_ptr->stock[item];
+
+ /* Assume the player wants just one of them */
+ amt = 1;
+
+ /* Get local object */
+ j_ptr = &forge;
+
+ /* Get a copy of the object */
+ object_copy(j_ptr, o_ptr);
+
+ /* Modify quantity */
+ j_ptr->number = amt;
+
+ /* Hack -- require room in pack */
+ if (!inven_carry_okay(j_ptr))
+ {
+ msg_print("You cannot carry that many different items.");
+ return;
+ }
+
+ /* Find out how many the player wants */
+ if (o_ptr->number > 1)
+ {
+ /* Get a quantity */
+ amt = get_quantity(NULL, o_ptr->number);
+
+ /* Allow user abort */
+ if (amt <= 0) return;
+ }
+
+ /* Get local object */
+ j_ptr = &forge;
+
+ /* Get desired object */
+ object_copy(j_ptr, o_ptr);
+
+ /* Modify quantity */
+ j_ptr->number = amt;
+
+ /* Hack -- require room in pack */
+ if (!inven_carry_okay(j_ptr))
+ {
+ msg_print("You cannot carry that many items.");
+ return;
+ }
+
+ /* Player tries to stole it */
+ if (rand_int((40 - p_ptr->stat_ind[A_DEX]) +
+ ((j_ptr->weight * amt) / (5 + get_skill_scale(SKILL_STEALING, 15))) -
+ (get_skill_scale(SKILL_STEALING, 15))) <= 10)
+ {
+ /* Hack -- buying an item makes you aware of it */
+ object_aware(j_ptr);
+
+ /* Be aware of how you found it */
+ j_ptr->found = OBJ_FOUND_STOLEN;
+ j_ptr->found_aux1 = st_ptr->st_idx;
+
+ /* Hack -- clear the "fixed" flag from the item */
+ j_ptr->ident &= ~(IDENT_FIXED);
+
+ /* "Hot" merchandise can't be sold back. It doesn't make sense
+ to be able to sell back to a guy what you just stole from him.
+ Also, without the discount one could fairly easily macro himself
+ an infinite money supply */
+ j_ptr->discount = 100;
+
+ if (o_ptr->tval == TV_WAND)
+ {
+ j_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+ o_ptr->pval -= j_ptr->pval;
+ }
+
+ /* Describe the transaction */
+ object_desc(o_name, j_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("You steal %s.", o_name);
+
+ /* Erase the inscription */
+ j_ptr->note = 0;
+
+ /* Give it to the player */
+ item_new = inven_carry(j_ptr, FALSE);
+
+ /* Describe the final result */
+ object_desc(o_name, &p_ptr->inventory[item_new], TRUE, 3);
+
+ /* Message */
+ msg_format("You have %s (%c).",
+ o_name, index_to_label(item_new));
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Note how many slots the store used to have */
+ i = st_ptr->stock_num;
+
+ /* Remove the bought items from the store */
+ store_item_increase(item, -amt);
+ store_item_optimize(item);
+
+ /* Store is empty */
+ if (st_ptr->stock_num == 0)
+ {
+ /* Shuffle */
+ if (retire_owner_p())
+ {
+ /* Message */
+ msg_print("The shopkeeper retires.");
+
+ /* Shuffle the store */
+ store_shuffle(cur_store_num);
+ }
+
+ /* Maintain */
+ else
+ {
+ /* Message */
+ msg_print("The shopkeeper brings out some new stock.");
+ }
+
+ /* New inventory */
+ for (i = 0; i < 10; i++)
+ {
+ /* Maintain the store */
+ store_maint(p_ptr->town_num, cur_store_num);
+ }
+
+ /* Start over */
+ store_top = 0;
+
+ /* Redraw everything */
+ display_inventory();
+ }
+
+ /* The item is gone */
+ else if (st_ptr->stock_num != i)
+ {
+ /* Pick the correct screen */
+ if (store_top >= st_ptr->stock_num) store_top -= 12;
+
+ /* Redraw everything */
+ display_inventory();
+ }
+
+ /* Item is still here */
+ else
+ {
+ /* Redraw the item */
+ display_entry(item);
+ }
+ }
+ else
+ {
+ /* Complain */
+ say_comment_4();
+
+ /* Reset insults */
+ st_ptr->insult_cur = 0;
+ st_ptr->good_buy = 0;
+ st_ptr->bad_buy = 0;
+
+ /* Kicked out for a LONG time */
+ st_ptr->store_open = turn + 500000 + randint(500000);
+ }
+
+ /* Not kicked out */
+ return;
+}
+
+/*
+ * Buy an item from a store -RAK-
+ */
+void store_purchase(void)
+{
+ int i, amt = 1, choice;
+ int item, item_new;
+
+ s32b price, best;
+
+ object_type forge;
+ object_type *j_ptr;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ char out_val[160];
+
+ /* Museum? */
+ if (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM)
+ {
+ msg_print("You cannot take items from the museum!");
+ return;
+ }
+
+ /* Empty? */
+ if (st_ptr->stock_num <= 0)
+ {
+ if (cur_store_num == 7) msg_print("Your home is empty.");
+ else msg_print("I am currently out of stock.");
+ return;
+ }
+
+
+ /* Find the number of objects on this and following pages */
+ i = (st_ptr->stock_num - store_top);
+
+ /* And then restrict it to the current page */
+ if (i > 12) i = 12;
+
+ /* Prompt */
+ if (cur_store_num == 7)
+ {
+ strnfmt(out_val, 160, "Which item do you want to take? ");
+ }
+ else
+ {
+ strnfmt(out_val, 160, "Which item are you interested in? ");
+ }
+
+ /* Get the item number to be bought */
+ if (!get_stock(&item, out_val, 0, i - 1)) return;
+
+ /* Get the actual index */
+ item = item + store_top;
+
+ /* Get the actual item */
+ o_ptr = &st_ptr->stock[item];
+
+ /* Get local object */
+ j_ptr = &forge;
+
+ /* Get a copy of one object to determine the price */
+ object_copy(j_ptr, o_ptr);
+
+ /* Modify quantity */
+ j_ptr->number = 1;
+
+ /* Hack -- If a wand, allocate the number of charges of one wand */
+ if (j_ptr->tval == TV_WAND)
+ {
+ j_ptr->pval = o_ptr->pval / o_ptr->number;
+ }
+
+ /* Hack -- require room in pack */
+ if (!inven_carry_okay(j_ptr))
+ {
+ msg_print("You cannot carry that many different items.");
+ return;
+ }
+
+ /* Determine the "best" price (per item) */
+ best = price_item(j_ptr, ot_ptr->min_inflate, FALSE);
+
+ /* Find out how many the player wants */
+ if (o_ptr->number > 1)
+ {
+ s32b q;
+
+
+ /* Hack -- note cost of "fixed" items */
+ if ((cur_store_num != 7) && (o_ptr->ident & (IDENT_FIXED)))
+ {
+ msg_format("That costs %ld gold per item.", (long)(best));
+ }
+
+ /* How many can we buy ? 99 if price is 0*/
+ if (cur_store_num == STORE_HOME)
+ {
+ q = 99;
+ }
+ else if (best == 0)
+ {
+ q = 99;
+ }
+ else
+ {
+ if (auto_haggle)
+ q = p_ptr->au / (best + (best / 10));
+ else
+ q = p_ptr->au / best;
+ }
+ if (o_ptr->number < q)
+ q = o_ptr->number;
+
+ /* None ? ahh too bad */
+ if (!q)
+ {
+ msg_print("You do not have enough gold to buy one.");
+ return;
+ }
+
+ /* Get a quantity */
+ amt = get_quantity(NULL, q);
+
+ /* Allow user abort */
+ if (amt <= 0) return;
+ }
+
+ /* Get local object */
+ j_ptr = &forge;
+
+ /* Get desired object */
+ object_copy(j_ptr, o_ptr);
+
+ /* Modify quantity */
+ j_ptr->number = amt;
+
+ /* Hack -- If a rod or wand, allocate total maximum timeouts or charges
+ * between those purchased and left on the shelf. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ j_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+ }
+
+ /* Hack -- require room in pack */
+ if (!inven_carry_okay(j_ptr))
+ {
+ msg_print("You cannot carry that many items.");
+ return;
+ }
+
+ /* Attempt to buy it */
+ if (cur_store_num != 7)
+ {
+ /* Fixed price, quick buy */
+ if (o_ptr->ident & (IDENT_FIXED))
+ {
+ /* Assume accept */
+ choice = 0;
+
+ /* Go directly to the "best" deal */
+ price = (best * j_ptr->number);
+ }
+
+ /* Haggle for it */
+ else
+ {
+ /* Describe the object (fully) */
+ object_desc_store(o_name, j_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("Buying %s (%c).", o_name, I2A(item));
+ msg_print(NULL);
+
+ /* Haggle for a final price */
+ choice = purchase_haggle(j_ptr, &price);
+
+ /* Hack -- Got kicked out */
+ if (st_ptr->store_open >= turn) return;
+ }
+
+
+ /* Player wants it */
+ if (choice == 0)
+ {
+ /* Fix the item price (if "correctly" haggled) */
+ if (price == (best * j_ptr->number)) o_ptr->ident |= (IDENT_FIXED);
+
+ /* Player can afford it */
+ if (p_ptr->au >= price)
+ {
+ /* Say "okay" */
+ say_comment_1();
+
+ /* Make a sound */
+ sound(SOUND_BUY);
+
+ /* Be happy */
+ decrease_insults();
+
+ /* Spend the money */
+ p_ptr->au -= price;
+
+ /* Update the display */
+ store_prt_gold();
+
+ /* Hack -- buying an item makes you aware of it */
+ object_aware(j_ptr);
+
+ /* Be aware of how you found it */
+ j_ptr->found = OBJ_FOUND_STORE;
+ j_ptr->found_aux1 = st_ptr->st_idx;
+
+ /* Hack -- clear the "fixed" flag from the item */
+ j_ptr->ident &= ~(IDENT_FIXED);
+
+ /* Describe the transaction */
+ object_desc(o_name, j_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("You bought %s for %ld gold.", o_name, (long)price);
+
+ /* Erase the inscription */
+ j_ptr->note = 0;
+
+ /* Hack -- If a rod or wand, allocate total maximum
+ * timeouts or charges between those picked up and
+ * those left behind. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ j_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+ o_ptr->pval -= j_ptr->pval;
+ }
+
+ /* Give it to the player */
+ item_new = inven_carry(j_ptr, FALSE);
+
+ /* Describe the final result */
+ object_desc(o_name, &p_ptr->inventory[item_new], TRUE, 3);
+
+ /* Message */
+ msg_format("You have %s (%c).",
+ o_name, index_to_label(item_new));
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Note how many slots the store used to have */
+ i = st_ptr->stock_num;
+
+ /* Remove the bought items from the store */
+ store_item_increase(item, -amt);
+ store_item_optimize(item);
+
+ /* Store is empty */
+ if (st_ptr->stock_num == 0)
+ {
+ /* Shuffle */
+ if (retire_owner_p())
+ {
+ /* Message */
+ msg_print("The shopkeeper retires.");
+
+ /* Shuffle the store */
+ store_shuffle(cur_store_num);
+ }
+
+ /* Maintain */
+ else
+ {
+ /* Message */
+ msg_print("The shopkeeper brings out some new stock.");
+ }
+
+ /* New inventory */
+ for (i = 0; i < 10; i++)
+ {
+ /* Maintain the store */
+ store_maint(p_ptr->town_num, cur_store_num);
+ }
+
+ /* Start over */
+ store_top = 0;
+ }
+
+ /* The item is gone */
+ else if (st_ptr->stock_num != i)
+ {
+ /* Pick the correct screen */
+ if (store_top >= st_ptr->stock_num) store_top -= 12;
+ }
+
+ /* Redraw everything */
+ display_inventory();
+ }
+
+ /* Player cannot afford it */
+ else
+ {
+ /* Simple message (no insult) */
+ msg_print("You do not have enough gold.");
+ }
+ }
+ }
+
+ /* Home is much easier */
+ else
+ {
+ /* Hack -- If a rod or wand, allocate total maximum
+ * timeouts or charges between those picked up and
+ * those left behind. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ j_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+ o_ptr->pval -= j_ptr->pval;
+ }
+
+ /* Give it to the player */
+ item_new = inven_carry(j_ptr, FALSE);
+
+ /* Describe just the result */
+ object_desc(o_name, &p_ptr->inventory[item_new], TRUE, 3);
+
+ /* Message */
+ msg_format("You have %s (%c).", o_name, index_to_label(item_new));
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Take note if we take the last one */
+ i = st_ptr->stock_num;
+
+ /* Remove the items from the home */
+ store_item_increase(item, -amt);
+ store_item_optimize(item);
+
+ /* Hack -- Item is still here */
+ if (i == st_ptr->stock_num)
+ {
+ /* Redraw the item */
+ display_entry(item);
+ }
+
+ /* The item is gone */
+ else
+ {
+ /* Nothing left */
+ if (st_ptr->stock_num == 0) store_top = 0;
+
+ /* Nothing left on that screen */
+ else if (store_top >= st_ptr->stock_num) store_top -= 12;
+
+ /* Redraw everything */
+ display_inventory();
+ }
+ }
+
+ /* Not kicked out */
+ return;
+}
+
+
+/*
+ * Sell an item to the store (or home)
+ */
+void store_sell(void)
+{
+ int choice;
+ int item, item_pos;
+ int amt;
+
+ s32b price, value, dummy;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ object_type *o_ptr;
+
+ cptr q, s;
+
+ char o_name[80];
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ bool_ museum = (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM) ? TRUE : FALSE;
+
+ /* Prepare a prompt */
+ if (cur_store_num == 7) q = "Drop which item? ";
+ else if (museum) q = "Donate which item?";
+ else q = "Sell which item? ";
+
+ /* Only allow items the store will buy */
+ item_tester_hook = store_will_buy;
+
+ /* Get an item */
+ if (cur_store_num == STORE_HOME)
+ {
+ s = "You have nothing to drop.";
+ }
+ else if (museum)
+ {
+ s = "You have nothing to donate.";
+ }
+ else
+ {
+ s = "You have nothing that I want.";
+ }
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Hack -- Cannot remove cursed items */
+ if (cursed_p(o_ptr))
+ {
+ if (item >= INVEN_WIELD)
+ {
+ /* Oops */
+ msg_print("Hmmm, it seems to be cursed.");
+
+ /* Nope */
+ return;
+ }
+ else
+ {
+ if (f4 & TR4_CURSE_NO_DROP)
+ {
+ /* Oops */
+ msg_print("Hmmm, you seem to be unable to drop it.");
+
+ /* Nope */
+ return;
+ }
+ }
+ }
+
+
+ /* Assume one item */
+ amt = 1;
+
+ /* Find out how many the player wants (letter means "all") */
+ if (o_ptr->number > 1)
+ {
+ /* Get a quantity */
+ amt = get_quantity(NULL, o_ptr->number);
+
+ /* Allow user abort */
+ if (amt <= 0) return;
+ }
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Get a copy of the object */
+ object_copy(q_ptr, o_ptr);
+
+ /* Modify quantity */
+ q_ptr->number = amt;
+
+ /* Hack -- If a rod or wand, allocate total maximum
+ * timeouts or charges to those being sold. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+ }
+
+ /* Get a full description */
+ object_desc(o_name, q_ptr, TRUE, 3);
+
+ /* Remove any inscription for stores */
+ if ((cur_store_num != 7) && !museum)
+ {
+ q_ptr->note = 0;
+ }
+
+ /* Is there room in the store (or the home?) */
+ if (!store_check_num(q_ptr))
+ {
+ if (cur_store_num == 7) msg_print("Your home is full.");
+ else if (museum) msg_print("The museum is full.");
+ else msg_print("I have not the room in my store to keep it.");
+ return;
+ }
+
+
+ /* Real store */
+ if ((cur_store_num != 7) && !museum)
+ {
+ /* Describe the transaction */
+ msg_format("Selling %s (%c).", o_name, index_to_label(item));
+ msg_print(NULL);
+
+ /* Haggle for it */
+ choice = sell_haggle(q_ptr, &price);
+
+ /* Kicked out */
+ if (st_ptr->store_open >= turn) return;
+
+ /* Sold... */
+ if (choice == 0)
+ {
+ /* Say "okay" */
+ say_comment_1();
+
+ /* Make a sound */
+ sound(SOUND_SELL);
+
+ /* Be happy */
+ decrease_insults();
+
+ /* Get some money */
+ p_ptr->au += price;
+
+ /* Update the display */
+ store_prt_gold();
+
+ /* Get the "apparent" value */
+ dummy = object_value(q_ptr) * q_ptr->number;
+
+ /* Identify original item */
+ object_aware(o_ptr);
+ object_known(o_ptr);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Get a copy of the object */
+ object_copy(q_ptr, o_ptr);
+
+ /* Modify quantity */
+ q_ptr->number = amt;
+
+ /*
+ * Hack -- If a rod or wand, let the shopkeeper know just
+ * how many charges he really paid for. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+ }
+
+ /* Get the "actual" value */
+ value = object_value(q_ptr) * q_ptr->number;
+
+ /* Get the description all over again */
+ object_desc(o_name, q_ptr, TRUE, 3);
+
+ /* Describe the result (in message buffer) */
+ msg_format("You sold %s for %ld gold.", o_name, (long)price);
+
+ /* Analyze the prices (and comment verbally) */
+ purchase_analyze(price, value, dummy);
+
+ /*
+ * Hack -- Allocate charges between those wands or rods sold
+ * and retained, unless all are being sold. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+
+ if (o_ptr->number > amt) o_ptr->pval -= q_ptr->pval;
+ }
+
+ /* Take the item from the player, describe the result */
+ inc_stack_size(item, -amt);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* The store gets that (known) item */
+ item_pos = store_carry(q_ptr);
+
+ /* Re-display if item is now in store */
+ if (item_pos >= 0)
+ {
+ store_top = (item_pos / 12) * 12;
+ display_inventory();
+ }
+ }
+ }
+
+ /* Player is at museum */
+ else if (museum)
+ {
+ char o2_name[80];
+ object_desc(o2_name, q_ptr, TRUE, 0);
+
+ msg_print("Once you donate something, you cannot take it back.");
+ if (!get_check(format("Do you really want to donate %s?", o2_name))) return;
+
+ /* Identify it */
+ object_aware(q_ptr);
+ object_known(q_ptr);
+ q_ptr->ident |= IDENT_MENTAL;
+
+ /*
+ * Hack -- Allocate charges between those wands or rods sold
+ * and retained, unless all are being sold. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+
+ if (o_ptr->number > amt) o_ptr->pval -= q_ptr->pval;
+ }
+
+
+ /* Describe */
+ msg_format("You donate %s (%c).", o_name, index_to_label(item));
+
+ choice = 0;
+
+ /* Take it from the players inventory */
+ inc_stack_size(item, -amt);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Let the home carry it */
+ item_pos = home_carry(q_ptr);
+
+ /* Update store display */
+ if (item_pos >= 0)
+ {
+ store_top = (item_pos / 12) * 12;
+ display_inventory();
+ }
+ }
+
+ /* Player is at home */
+ else
+ {
+ /* Describe */
+ msg_format("You drop %s (%c).", o_name, index_to_label(item));
+
+ /*
+ * Hack -- Allocate charges between those wands or rods sold
+ * and retained, unless all are being sold. -LM-
+ */
+ if (o_ptr->tval == TV_WAND)
+ {
+ q_ptr->pval = o_ptr->pval * amt / o_ptr->number;
+
+ if (o_ptr->number > amt) o_ptr->pval -= q_ptr->pval;
+ }
+
+ /* Take it from the players inventory */
+ inc_stack_size(item, -amt);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Let the home carry it */
+ item_pos = home_carry(q_ptr);
+
+ /* Update store display */
+ if (item_pos >= 0)
+ {
+ store_top = (item_pos / 12) * 12;
+ display_inventory();
+ }
+ }
+}
+
+
+
+/*
+ * Examine an item in a store -JDL-
+ */
+void store_examine(void)
+{
+ int i;
+ int item;
+
+ object_type *o_ptr;
+
+ char o_name[80];
+
+ char out_val[160];
+
+
+ /* Empty? */
+ if (st_ptr->stock_num <= 0)
+ {
+ if (cur_store_num == 7) msg_print("Your home is empty.");
+ else if (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM) msg_print("The museum is empty.");
+ else msg_print("I am currently out of stock.");
+ return;
+ }
+
+
+ /* Find the number of objects on this and following pages */
+ i = (st_ptr->stock_num - store_top);
+
+ /* And then restrict it to the current page */
+ if (i > 12) i = 12;
+
+ /* Prompt */
+ strnfmt(out_val, 160, "Which item do you want to examine? ");
+
+ /* Get the item number to be examined */
+ if (!get_stock(&item, out_val, 0, i - 1)) return;
+
+ /* Get the actual index */
+ item = item + store_top;
+
+ /* Get the actual item */
+ o_ptr = &st_ptr->stock[item];
+
+ /* Debug hack */
+ if (wizard)
+ {
+ drop_near(o_ptr, -1, p_ptr->py, p_ptr->px);
+ }
+
+ /* Require full knowledge */
+ if (!(o_ptr->ident & (IDENT_MENTAL)))
+ {
+ /* This can only happen in the home */
+ msg_print("You have no special knowledge about that item.");
+ return;
+ }
+
+ /* Description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Describe */
+ msg_format("Examining %s...", o_name);
+
+ /* Show the object's powers. */
+ if (!object_out_desc(o_ptr, NULL, FALSE, TRUE))
+ {
+ msg_print("You see nothing special.");
+ }
+
+ /* Show spell listing for instruments, daemonwear and spellbooks. */
+ if ((o_ptr->tval == TV_INSTRUMENT) || (o_ptr->tval == TV_DAEMON_BOOK)
+ || (o_ptr->tval == TV_BOOK))
+ {
+ do_cmd_browse_aux(o_ptr);
+ }
+
+ return;
+}
+
+
+
+
+
+/*
+ * Hack -- set this to leave the store
+ */
+static bool_ leave_store = FALSE;
+
+
+/*
+ * Process a command in a store
+ *
+ * Note that we must allow the use of a few "special" commands
+ * in the stores which are not allowed in the dungeon, and we
+ * must disable some commands which are allowed in the dungeon
+ * but not in the stores, to prevent chaos.
+ */
+static bool_ store_process_command(void)
+{
+ bool_ validcmd = FALSE;
+ int i;
+ store_action_type *ba_ptr;
+ bool_ recreate = FALSE;
+
+ /* Handle repeating the last command */
+ repeat_check();
+
+ for (i = 0; i < 6; i++)
+ {
+ ba_ptr = &ba_info[st_info[st_ptr->st_idx].actions[i]];
+
+ if (ba_ptr->letter)
+ {
+ if (ba_ptr->letter == command_cmd)
+ {
+ validcmd = TRUE;
+ break;
+ }
+ }
+ if (ba_ptr->letter_aux)
+ {
+ if (ba_ptr->letter_aux == command_cmd)
+ {
+ validcmd = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (validcmd)
+ {
+ recreate = bldg_process_command(st_ptr, i);
+ }
+ else
+ {
+ /* Parse the command */
+ switch (command_cmd)
+ {
+ /* Leave */
+ case ESCAPE:
+ {
+ leave_store = TRUE;
+ break;
+ }
+
+ /* Browse */
+ case ' ':
+ {
+ if (st_ptr->stock_num <= 12)
+ {
+ msg_print("Entire inventory is shown.");
+ }
+ else
+ {
+ store_top += 12;
+ if (store_top >= st_ptr->stock_num) store_top = 0;
+ display_inventory();
+ }
+ break;
+ }
+
+ /* Browse backwards */
+ case '-':
+ {
+ if (st_ptr->stock_num <= 12)
+ {
+ msg_print("Entire inventory is shown.");
+ }
+ else
+ {
+ store_top -= 12;
+ if (store_top < 0)
+ {
+ store_top = ((st_ptr->stock_num - 1) / 12) * 12;
+ }
+ display_inventory();
+ }
+ }
+
+ /* Redraw */
+ case KTRL('R'):
+ {
+ do_cmd_redraw();
+ display_store();
+ break;
+ }
+
+ /* Ignore return */
+ case '\r':
+ {
+ break;
+ }
+
+
+
+ /*** Inventory Commands ***/
+
+ /* Wear/wield equipment */
+ case 'w':
+ {
+ do_cmd_wield();
+ break;
+ }
+
+ /* Take off equipment */
+ case 't':
+ {
+ do_cmd_takeoff();
+ break;
+ }
+
+ /* Destroy an item */
+ case 'k':
+ {
+ do_cmd_destroy();
+ break;
+ }
+
+ /* Equipment list */
+ case 'e':
+ {
+ do_cmd_equip();
+ break;
+ }
+
+ /* Inventory list */
+ case 'i':
+ {
+ do_cmd_inven();
+ break;
+ }
+
+
+ /*** Various commands ***/
+
+ /* Identify an object */
+ case 'I':
+ {
+ do_cmd_observe();
+ break;
+ }
+
+ /* Hack -- toggle windows */
+ case KTRL('I'):
+ {
+ toggle_inven_equip();
+ break;
+ }
+
+
+
+ /*** Use various objects ***/
+
+ /* Browse a book */
+ case 'b':
+ {
+ do_cmd_browse();
+ break;
+ }
+
+ /* Inscribe an object */
+ case '{':
+ {
+ do_cmd_inscribe();
+ break;
+ }
+
+ /* Uninscribe an object */
+ case '}':
+ {
+ do_cmd_uninscribe();
+ break;
+ }
+
+
+
+ /*** Help and Such ***/
+
+ /* Help */
+ case '?':
+ {
+ do_cmd_help();
+ break;
+ }
+
+ /* Identify symbol */
+ case '/':
+ {
+ do_cmd_query_symbol();
+ break;
+ }
+
+ /* Character description */
+ case 'C':
+ {
+ do_cmd_change_name();
+ display_store();
+ break;
+ }
+
+
+ /*** System Commands ***/
+
+ /* Hack -- User interface */
+ case '!':
+ {
+ (void)Term_user(0);
+ break;
+ }
+
+ /* Single line from a pref file */
+ case '"':
+ {
+ do_cmd_pref();
+ break;
+ }
+
+ /* Interact with macros */
+ case '@':
+ {
+ do_cmd_macros();
+ break;
+ }
+
+ /* Interact with visuals */
+ case '%':
+ {
+ do_cmd_visuals();
+ break;
+ }
+
+ /* Interact with colors */
+ case '&':
+ {
+ do_cmd_colors();
+ break;
+ }
+
+ /* Interact with options */
+ case '=':
+ {
+ do_cmd_options();
+ break;
+ }
+
+
+ /*** Misc Commands ***/
+
+ /* Take notes */
+ case ':':
+ {
+ do_cmd_note();
+ break;
+ }
+
+ /* Version info */
+ case 'V':
+ {
+ do_cmd_version();
+ break;
+ }
+
+ /* Repeat level feeling */
+ case KTRL('F'):
+ {
+ do_cmd_feeling();
+ break;
+ }
+
+ /* Show previous message */
+ case KTRL('O'):
+ {
+ do_cmd_message_one();
+ break;
+ }
+
+ /* Show previous messages */
+ case KTRL('P'):
+ {
+ do_cmd_messages();
+ break;
+ }
+
+ /* Check artifacts, uniques etc. */
+ case '~':
+ case '|':
+ {
+ do_cmd_knowledge();
+ break;
+ }
+
+ /* Load "screen dump" */
+ case '(':
+ {
+ do_cmd_load_screen();
+ break;
+ }
+
+ /* Save "screen dump" */
+ case ')':
+ {
+ do_cmd_save_screen();
+ break;
+ }
+
+
+ /* Hack -- Unknown command */
+ default:
+ {
+ if (st_ptr->st_idx == STORE_HOME)
+ msg_print("That command does not work in this home.");
+ else
+ msg_print("That command does not work in this store.");
+ break;
+ }
+ }
+ }
+
+ return recreate;
+}
+
+
+/*
+ * Enter a store, and interact with it.
+ *
+ * Note that we use the standard "request_command()" function
+ * to get a command, allowing us to use "command_arg" and all
+ * command macros and other nifty stuff, but we use the special
+ * "shopping" argument, to force certain commands to be converted
+ * into other commands, normally, we convert "p" (pray) and "m"
+ * (cast magic) into "g" (get), and "s" (search) into "d" (drop).
+ */
+void do_cmd_store(void)
+{
+ int which;
+ int maintain_num;
+ int tmp_chr;
+ int i;
+ bool_ recreate = FALSE;
+
+ cave_type *c_ptr;
+
+
+ /* Access the player grid */
+ c_ptr = &cave[p_ptr->py][p_ptr->px];
+
+ /* Verify a store */
+ if (c_ptr->feat != FEAT_SHOP)
+ {
+ msg_print("You see no store here.");
+ return;
+ }
+
+ /* Extract the store code */
+ which = c_ptr->special;
+
+ /* Hack -- Check the "locked doors" */
+ if (town_info[p_ptr->town_num].store[which].store_open >= turn)
+ {
+ msg_print("The doors are locked.");
+ return;
+ }
+
+ /* Calculate the number of store maintainances since the last visit */
+ maintain_num = (turn - town_info[p_ptr->town_num].store[which].last_visit) / (10L * STORE_TURNS);
+
+ /* Maintain the store max. 10 times */
+ if (maintain_num > 10) maintain_num = 10;
+
+ if (maintain_num)
+ {
+ /* Maintain the store */
+ for (i = 0; i < maintain_num; i++)
+ store_maint(p_ptr->town_num, which);
+
+ /* Save the visit */
+ town_info[p_ptr->town_num].store[which].last_visit = turn;
+ }
+
+ /* Forget the lite */
+ /* forget_lite(); */
+
+ /* Forget the view */
+ forget_view();
+
+
+ /* Hack -- Character is in "icky" mode */
+ character_icky = TRUE;
+
+
+ /* No command argument */
+ command_arg = 0;
+
+ /* No repeated command */
+ command_rep = 0;
+
+ /* No automatic command */
+ command_new = 0;
+
+
+ /* Save the store number */
+ cur_store_num = which;
+
+ /* Save the store and owner pointers */
+ st_ptr = &town_info[p_ptr->town_num].store[cur_store_num];
+ ot_ptr = &ow_info[st_ptr->owner];
+
+
+ /* Start at the beginning */
+ store_top = 0;
+
+ /* Display the store */
+ display_store();
+
+ /* Mega-Hack -- Ignore keymaps on store action letters */
+ for (i = 0; i < 6; i++)
+ {
+ store_action_type *ba_ptr =
+ &ba_info[st_info[st_ptr->st_idx].actions[i]];
+ request_command_ignore_keymaps[2*i] = ba_ptr->letter;
+ request_command_ignore_keymaps[2*i+1] = ba_ptr->letter_aux;
+
+ }
+
+ /* Do not leave */
+ leave_store = FALSE;
+
+ /* Interact with player */
+ while (!leave_store)
+ {
+ /* Hack -- Clear line 1 */
+ prt("", 1, 0);
+
+ /* Hack -- Check the charisma */
+ tmp_chr = p_ptr->stat_use[A_CHR];
+
+ /* Clear */
+ clear_from(21);
+
+
+ /* Basic commands */
+ c_prt(TERM_YELLOW, " ESC.", 22, 0);
+ prt(") Exit.", 22, 4);
+
+ /* Browse if necessary */
+ if (st_ptr->stock_num > 12)
+ {
+ c_prt(TERM_YELLOW, " SPACE", 23, 0);
+ prt(") Next page", 23, 6);
+ }
+
+ /* Prompt */
+ prt("You may: ", 21, 0);
+
+ /* Show the commands */
+ show_building(st_ptr);
+
+ /* Get a command */
+ request_command(TRUE);
+
+ /* Process the command */
+ if (store_process_command()) recreate = TRUE;
+
+ /* Hack -- Character is still in "icky" mode */
+ character_icky = TRUE;
+
+ /* Notice stuff */
+ notice_stuff();
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* XXX XXX XXX Pack Overflow */
+ if (p_ptr->inventory[INVEN_PACK].k_idx)
+ {
+ int item = INVEN_PACK;
+
+ object_type *o_ptr = &p_ptr->inventory[item];
+
+ /* Hack -- Flee from the store */
+ if (cur_store_num != 7)
+ {
+ /* Message */
+ msg_print("Your pack is so full that you flee the store...");
+
+ /* Leave */
+ leave_store = TRUE;
+ }
+
+ /* Hack -- Flee from the home */
+ else if (!store_check_num(o_ptr))
+ {
+ /* Message */
+ msg_print("Your pack is so full that you flee your home...");
+
+ /* Leave */
+ leave_store = TRUE;
+ }
+
+ /* Hack -- Drop items into the home */
+ else
+ {
+ int item_pos;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ char o_name[80];
+
+
+ /* Give a message */
+ msg_print("Your pack overflows!");
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Grab a copy of the item */
+ object_copy(q_ptr, o_ptr);
+
+ /* Describe it */
+ object_desc(o_name, q_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("You drop %s (%c).", o_name, index_to_label(item));
+
+ /* Remove it from the players inventory */
+ inc_stack_size(item, -255);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Let the home carry it */
+ item_pos = home_carry(q_ptr);
+
+ /* Redraw the home */
+ if (item_pos >= 0)
+ {
+ store_top = (item_pos / 12) * 12;
+ display_inventory();
+ }
+ }
+ }
+
+ /* Hack -- Redisplay store prices if charisma changes */
+ if (tmp_chr != p_ptr->stat_use[A_CHR]) display_inventory();
+
+ /* Hack -- get kicked out of the store */
+ if (st_ptr->store_open >= turn) leave_store = TRUE;
+ }
+
+ /* Free turn XXX XXX XXX */
+ energy_use = 0;
+
+ /* Recreate the level only when needed */
+ if (recreate)
+ {
+ /* Reinit wilderness to activate quests ... */
+ p_ptr->oldpx = p_ptr->px;
+ p_ptr->oldpy = p_ptr->py;
+
+ p_ptr->leaving = TRUE;
+ }
+
+ /* Hack -- Character is no longer in "icky" mode */
+ character_icky = FALSE;
+
+
+ /* Hack -- Cancel automatic command */
+ command_new = 0;
+
+ /* Mega-Hack -- Clear the 'ignore-keymaps' list */
+ memset(request_command_ignore_keymaps, 0, 12);
+
+ /* Flush messages XXX XXX XXX */
+ msg_print(NULL);
+
+
+ /* Clear the screen */
+ Term_clear();
+
+
+ /* Update everything */
+ p_ptr->update |= (PU_VIEW | PU_MON_LITE);
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw entire screen */
+ p_ptr->redraw |= (PR_BASIC | PR_EXTRA);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+
+
+/*
+ * Shuffle one of the stores.
+ */
+void store_shuffle(int which)
+{
+ int i, j;
+
+
+ /* Ignore home */
+ if (which == STORE_HOME) return;
+
+ /* Ignoer Museum */
+ if (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM) return;
+
+
+ /* Save the store index */
+ cur_store_num = which;
+
+ /* Activate that store */
+ st_ptr = &town_info[p_ptr->town_num].store[cur_store_num];
+
+ /* Pick a new owner */
+ for (j = st_ptr->owner; j == st_ptr->owner; )
+ {
+ st_ptr->owner = st_info[st_ptr->st_idx].owners[rand_int(4)];
+ }
+
+ /* Activate the new owner */
+ ot_ptr = &ow_info[st_ptr->owner];
+
+
+ /* Reset the owner data */
+ st_ptr->insult_cur = 0;
+ st_ptr->store_open = 0;
+ st_ptr->good_buy = 0;
+ st_ptr->bad_buy = 0;
+
+
+ /* Hack -- discount all the items */
+ for (i = 0; i < st_ptr->stock_num; i++)
+ {
+ object_type *o_ptr;
+
+ /* Get the item */
+ o_ptr = &st_ptr->stock[i];
+
+ /* Hack -- Sell all old items for "half price" */
+ if (!(o_ptr->art_name))
+ o_ptr->discount = 50;
+
+ /* Hack -- Items are no longer "fixed price" */
+ o_ptr->ident &= ~(IDENT_FIXED);
+
+ /* Mega-Hack -- Note that the item is "on sale" */
+ o_ptr->note = quark_add("on sale");
+ }
+}
+
+
+/*
+ * Maintain the inventory at the stores.
+ */
+void store_maint(int town_num, int store_num)
+{
+ int j, tries = 100;
+
+ int old_rating = rating;
+
+ cur_store_num = store_num;
+
+ /* Ignore home */
+ if (store_num == STORE_HOME) return;
+
+ /* Activate that store */
+ st_ptr = &town_info[town_num].store[store_num];
+
+ /* Ignoer Museum */
+ if (st_info[st_ptr->st_idx].flags1 & SF1_MUSEUM) return;
+
+ /* Activate the owner */
+ ot_ptr = &ow_info[st_ptr->owner];
+
+ /* Store keeper forgives the player */
+ st_ptr->insult_cur = 0;
+
+ /* Mega-Hack -- prune the black market */
+ if (st_info[st_ptr->st_idx].flags1 & SF1_ALL_ITEM)
+ {
+ /* Destroy crappy black market items */
+ for (j = st_ptr->stock_num - 1; j >= 0; j--)
+ {
+ object_type *o_ptr = &st_ptr->stock[j];
+
+ /* Destroy crappy items */
+ if (black_market_crap(o_ptr))
+ {
+ /* Destroy the item */
+ store_item_increase(j, 0 - o_ptr->number);
+ store_item_optimize(j);
+ }
+ }
+ }
+
+
+ /* Choose the number of slots to keep */
+ j = st_ptr->stock_num;
+
+ /* Sell a few items */
+ j = j - randint(STORE_TURNOVER);
+
+ /* Never keep more than "STORE_MAX_KEEP" slots */
+ if (j > STORE_MAX_KEEP) j = STORE_MAX_KEEP;
+
+ /* Always "keep" at least "STORE_MIN_KEEP" items */
+ if (j < STORE_MIN_KEEP) j = STORE_MIN_KEEP;
+
+ /* Hack -- prevent "underflow" */
+ if (j < 0) j = 0;
+
+ /* Destroy objects until only "j" slots are left */
+ while (st_ptr->stock_num > j) store_delete();
+
+
+ /* Choose the number of slots to fill */
+ j = st_ptr->stock_num;
+
+ /* Buy some more items */
+ j = j + randint(STORE_TURNOVER);
+
+ /* Never keep more than "STORE_MAX_KEEP" slots */
+ if (j > STORE_MAX_KEEP) j = STORE_MAX_KEEP;
+
+ /* Always "keep" at least "STORE_MIN_KEEP" items */
+ if (j < STORE_MIN_KEEP) j = STORE_MIN_KEEP;
+
+ /* Hack -- prevent "overflow" */
+ if (j >= st_ptr->stock_size) j = st_ptr->stock_size - 1;
+
+ /* Acquire some new items */
+ while ((st_ptr->stock_num < j) && tries)
+ {
+ store_create();
+ tries--;
+ }
+
+ /* Hack -- Restore the rating */
+ rating = old_rating;
+}
+
+
+/*
+ * Initialize the stores
+ */
+void store_init(int town_num, int store_num)
+{
+ int k;
+
+ cur_store_num = store_num;
+
+ /* Activate that store */
+ st_ptr = &town_info[town_num].store[store_num];
+
+
+ /* Pick an owner */
+ st_ptr->owner = st_info[st_ptr->st_idx].owners[rand_int(4)];
+
+ /* Activate the new owner */
+ ot_ptr = &ow_info[st_ptr->owner];
+
+
+ /* Initialize the store */
+ st_ptr->store_open = 0;
+ st_ptr->insult_cur = 0;
+ st_ptr->good_buy = 0;
+ st_ptr->bad_buy = 0;
+
+ /* Nothing in stock */
+ st_ptr->stock_num = 0;
+
+ /*
+ * MEGA-HACK - Last visit to store is
+ * BEFORE player birth to enable store restocking
+ */
+ st_ptr->last_visit = -100L * STORE_TURNS;
+
+ /* Clear any old items */
+ for (k = 0; k < st_ptr->stock_size; k++)
+ {
+ object_wipe(&st_ptr->stock[k]);
+ }
+}
+
+
+void move_to_black_market(object_type * o_ptr)
+{
+ st_ptr = &town_info[p_ptr->town_num].store[6];
+ o_ptr->ident |= IDENT_STOREB;
+ (void)store_carry(o_ptr);
+ object_wipe(o_ptr); /* Don't leave a bogus object behind... */
+}
+
+/*
+ * Enter the home, and interact with it from the dungeon (trump magic).
+ *
+ * Note that we use the standard "request_command()" function
+ * to get a command, allowing us to use "command_arg" and all
+ * command macros and other nifty stuff, but we use the special
+ * "shopping" argument, to force certain commands to be converted
+ * into other commands, normally, we convert "p" (pray) and "m"
+ * (cast magic) into "g" (get), and "s" (search) into "d" (drop).
+ */
+void do_cmd_home_trump(void)
+{
+ int which;
+ int maintain_num;
+ int tmp_chr;
+ int i;
+ int town_num;
+
+ /* Extract the store code */
+ which = 7;
+
+ if (p_ptr->town_num) town_num = p_ptr->town_num;
+ else town_num = 1;
+
+ /* Hack -- Check the "locked doors" */
+ if (town_info[town_num].store[which].store_open >= turn)
+ {
+ msg_print("The doors are locked.");
+ return;
+ }
+
+ /* Calculate the number of store maintainances since the last visit */
+ maintain_num = (turn - town_info[town_num].store[which].last_visit) / (10L * STORE_TURNS);
+
+ /* Maintain the store max. 10 times */
+ if (maintain_num > 10) maintain_num = 10;
+
+ if (maintain_num)
+ {
+ /* Maintain the store */
+ for (i = 0; i < maintain_num; i++)
+ store_maint(town_num, which);
+
+ /* Save the visit */
+ town_info[town_num].store[which].last_visit = turn;
+ }
+
+ /* Forget the lite */
+ /* forget_lite(); */
+
+ /* Forget the view */
+ forget_view();
+
+
+ /* Hack -- Character is in "icky" mode */
+ character_icky = TRUE;
+
+
+ /* No command argument */
+ command_arg = 0;
+
+ /* No repeated command */
+ command_rep = 0;
+
+ /* No automatic command */
+ command_new = 0;
+
+
+ /* Save the store number */
+ cur_store_num = which;
+
+ /* Save the store and owner pointers */
+ st_ptr = &town_info[town_num].store[cur_store_num];
+ ot_ptr = &ow_info[st_ptr->owner];
+
+
+ /* Start at the beginning */
+ store_top = 0;
+
+ /* Display the store */
+ display_store();
+
+ /* Mega-Hack -- Ignore keymaps on store action letters */
+ for (i = 0; i < 6; i++)
+ {
+ store_action_type *ba_ptr =
+ &ba_info[st_info[st_ptr->st_idx].actions[i]];
+ request_command_ignore_keymaps[2*i] = ba_ptr->letter;
+ request_command_ignore_keymaps[2*i+1] = ba_ptr->letter_aux;
+ }
+
+ /* Do not leave */
+ leave_store = FALSE;
+
+ /* Interact with player */
+ while (!leave_store)
+ {
+ /* Hack -- Clear line 1 */
+ prt("", 1, 0);
+
+ /* Hack -- Check the charisma */
+ tmp_chr = p_ptr->stat_use[A_CHR];
+
+ /* Clear */
+ clear_from(21);
+
+
+ /* Basic commands */
+ prt(" ESC) Exit from Building.", 22, 0);
+
+ /* Browse if necessary */
+ if (st_ptr->stock_num > 12)
+ {
+ prt(" SPACE) Next page of stock", 23, 0);
+ }
+
+ /* Home commands */
+ if (cur_store_num == 7)
+ {
+ prt(" g) Get an item.", 22, 31);
+ prt(" d) Drop an item.", 23, 31);
+ }
+
+ /* Shop commands XXX XXX XXX */
+ else
+ {
+ prt(" p) Purchase an item.", 22, 31);
+ prt(" s) Sell an item.", 23, 31);
+ }
+
+ /* Add in the eXamine option */
+ prt(" x) eXamine an item.", 22, 56);
+
+ /* Prompt */
+ prt("You may: ", 21, 0);
+
+ /* Get a command */
+ request_command(TRUE);
+
+ /* Process the command */
+ store_process_command();
+
+ /* Hack -- Character is still in "icky" mode */
+ character_icky = TRUE;
+
+ /* Notice stuff */
+ notice_stuff();
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* XXX XXX XXX Pack Overflow */
+ if (p_ptr->inventory[INVEN_PACK].k_idx)
+ {
+ int item = INVEN_PACK;
+
+ object_type *o_ptr = &p_ptr->inventory[item];
+
+ /* Hack -- Flee from the store */
+ if (cur_store_num != 7)
+ {
+ /* Message */
+ msg_print("Your pack is so full that you flee the store...");
+
+ /* Leave */
+ leave_store = TRUE;
+ }
+
+ /* Hack -- Flee from the home */
+ else if (!store_check_num(o_ptr))
+ {
+ /* Message */
+ msg_print("Your pack is so full that you flee your home...");
+
+ /* Leave */
+ leave_store = TRUE;
+ }
+
+ /* Hack -- Drop items into the home */
+ else
+ {
+ int item_pos;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ char o_name[80];
+
+
+ /* Give a message */
+ msg_print("Your pack overflows!");
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Grab a copy of the item */
+ object_copy(q_ptr, o_ptr);
+
+ /* Describe it */
+ object_desc(o_name, q_ptr, TRUE, 3);
+
+ /* Message */
+ msg_format("You drop %s (%c).", o_name, index_to_label(item));
+
+ /* Remove it from the players inventory */
+ inc_stack_size(item, -255);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Let the home carry it */
+ item_pos = home_carry(q_ptr);
+
+ /* Redraw the home */
+ if (item_pos >= 0)
+ {
+ store_top = (item_pos / 12) * 12;
+ display_inventory();
+ }
+ }
+ }
+
+ /* Hack -- Redisplay store prices if charisma changes */
+ if (tmp_chr != p_ptr->stat_use[A_CHR]) display_inventory();
+
+ /* Hack -- get kicked out of the store */
+ if (st_ptr->store_open >= turn) leave_store = TRUE;
+ }
+
+
+ /* Hack -- Character is no longer in "icky" mode */
+ character_icky = FALSE;
+
+
+ /* Hack -- Cancel automatic command */
+ command_new = 0;
+
+ /* Mega-Hack -- Clear the 'ignore-keymaps' list */
+ memset(request_command_ignore_keymaps, 0, 12);
+
+ /* Flush messages XXX XXX XXX */
+ msg_print(NULL);
+
+
+ /* Clear the screen */
+ Term_clear();
+
+
+ /* Update everything */
+ p_ptr->update |= (PU_VIEW | PU_MON_LITE);
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw entire screen */
+ p_ptr->redraw |= (PR_BASIC | PR_EXTRA);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+static void pay_for_requested_item(int value, object_type *q_ptr)
+{
+ msg_format("It'll cost %i gold pieces. ", value);
+
+ if (get_check("Do you wish to pay?"))
+ {
+ if (p_ptr->au < value)
+ msg_print("You don't have enough money for it.");
+ else
+ {
+ if (store_carry(q_ptr) != -1)
+ {
+ msg_print("The item has arrived in the Black Market.");
+ p_ptr->au -= value;
+
+ p_ptr->redraw |= PR_GOLD;
+ }
+ else
+ msg_print("There isn't enough room for it.");
+ }
+ }
+}
+
+/*
+ * Request item for merchants
+ */
+void store_request_item(void)
+{
+ char buf[80], name[80];
+ object_type forge, *q_ptr = &forge;
+ store_type *ost_ptr = st_ptr;
+
+ /* Get the Black Market */
+ st_ptr = &town_info[p_ptr->town_num].store[6];
+
+ /* Make an empty string */
+ buf[0] = 0;
+
+ /* Ask for the wish */
+ if (!get_string("Request what? ", buf, 80))
+ {
+ st_ptr = ost_ptr;
+ return;
+ }
+
+ clean_wish_name(buf, name);
+
+ if (test_object_wish(name, q_ptr, &forge, "request"))
+ {
+ int value = object_value_real(q_ptr) * 5;
+
+ /* Pay for the delivery */
+ pay_for_requested_item(value, q_ptr);
+
+ /* Don't search any more */
+ st_ptr = ost_ptr;
+ return;
+ }
+
+ st_ptr = ost_ptr;
+}
diff --git a/src/tables.c b/src/tables.c
new file mode 100644
index 00000000..e976e234
--- /dev/null
+++ b/src/tables.c
@@ -0,0 +1,4792 @@
+/* File: tables.c */
+
+/* Purpose: Angband Tables */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+
+
+/*
+ * Global array for looping through the "keypad directions"
+ */
+s16b ddd[9] =
+ { 2, 8, 6, 4, 3, 1, 9, 7, 5 };
+
+/*
+ * Global arrays for converting "keypad direction" into offsets
+ */
+s16b ddx[10] =
+ { 0, -1, 0, 1, -1, 0, 1, -1, 0, 1 };
+
+s16b ddy[10] =
+ { 0, 1, 1, 1, 0, 0, 0, -1, -1, -1 };
+
+/*
+ * Global arrays for optimizing "ddx[ddd[i]]" and "ddy[ddd[i]]"
+ */
+s16b ddx_ddd[9] =
+ { 0, 0, 1, -1, 1, -1, 1, -1, 0 };
+
+s16b ddy_ddd[9] =
+ { 1, -1, 0, 0, 1, 1, -1, -1, 0 };
+
+
+
+/*
+* Global array for converting numbers to uppercase hexadecimal digit
+ * This array can also be used to convert a number to an octal digit
+ */
+char hexsym[16] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+
+/*
+ * Stat Table (INT/WIS) -- Number of half-spells per level
+ */
+byte adj_mag_study[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 0 /* 5 */,
+ 0 /* 6 */,
+ 0 /* 7 */,
+ 1 /* 8 */,
+ 1 /* 9 */,
+ 1 /* 10 */,
+ 1 /* 11 */,
+ 2 /* 12 */,
+ 2 /* 13 */,
+ 2 /* 14 */,
+ 2 /* 15 */,
+ 2 /* 16 */,
+ 2 /* 17 */,
+ 2 /* 18/00-18/09 */,
+ 2 /* 18/10-18/19 */,
+ 2 /* 18/20-18/29 */,
+ 2 /* 18/30-18/39 */,
+ 2 /* 18/40-18/49 */,
+ 3 /* 18/50-18/59 */,
+ 3 /* 18/60-18/69 */,
+ 3 /* 18/70-18/79 */,
+ 3 /* 18/80-18/89 */,
+ 4 /* 18/90-18/99 */,
+ 4 /* 18/100-18/109 */,
+ 4 /* 18/110-18/119 */,
+ 5 /* 18/120-18/129 */,
+ 5 /* 18/130-18/139 */,
+ 5 /* 18/140-18/149 */,
+ 5 /* 18/150-18/159 */,
+ 5 /* 18/160-18/169 */,
+ 5 /* 18/170-18/179 */,
+ 5 /* 18/180-18/189 */,
+ 5 /* 18/190-18/199 */,
+ 5 /* 18/200-18/209 */,
+ 6 /* 18/210-18/219 */,
+ 6 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (INT/WIS) -- extra half-mana-points per level
+ */
+byte adj_mag_mana[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 0 /* 5 */,
+ 0 /* 6 */,
+ 0 /* 7 */,
+ 1 /* 8 */,
+ 2 /* 9 */,
+ 2 /* 10 */,
+ 2 /* 11 */,
+ 2 /* 12 */,
+ 2 /* 13 */,
+ 2 /* 14 */,
+ 2 /* 15 */,
+ 2 /* 16 */,
+ 2 /* 17 */,
+ 3 /* 18/00-18/09 */,
+ 3 /* 18/10-18/19 */,
+ 3 /* 18/20-18/29 */,
+ 3 /* 18/30-18/39 */,
+ 3 /* 18/40-18/49 */,
+ 4 /* 18/50-18/59 */,
+ 4 /* 18/60-18/69 */,
+ 5 /* 18/70-18/79 */,
+ 6 /* 18/80-18/89 */,
+ 7 /* 18/90-18/99 */,
+ 8 /* 18/100-18/109 */,
+ 9 /* 18/110-18/119 */,
+ 10 /* 18/120-18/129 */,
+ 11 /* 18/130-18/139 */,
+ 12 /* 18/140-18/149 */,
+ 13 /* 18/150-18/159 */,
+ 14 /* 18/160-18/169 */,
+ 15 /* 18/170-18/179 */,
+ 16 /* 18/180-18/189 */,
+ 16 /* 18/190-18/199 */,
+ 17 /* 18/200-18/209 */,
+ 17 /* 18/210-18/219 */,
+ 18 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (INT/WIS) -- Minimum failure rate (percentage)
+ */
+byte adj_mag_fail[] =
+{
+ 99 /* 3 */,
+ 99 /* 4 */,
+ 99 /* 5 */,
+ 99 /* 6 */,
+ 99 /* 7 */,
+ 50 /* 8 */,
+ 30 /* 9 */,
+ 20 /* 10 */,
+ 15 /* 11 */,
+ 12 /* 12 */,
+ 11 /* 13 */,
+ 10 /* 14 */,
+ 9 /* 15 */,
+ 8 /* 16 */,
+ 7 /* 17 */,
+ 6 /* 18/00-18/09 */,
+ 6 /* 18/10-18/19 */,
+ 5 /* 18/20-18/29 */,
+ 5 /* 18/30-18/39 */,
+ 5 /* 18/40-18/49 */,
+ 4 /* 18/50-18/59 */,
+ 4 /* 18/60-18/69 */,
+ 4 /* 18/70-18/79 */,
+ 4 /* 18/80-18/89 */,
+ 3 /* 18/90-18/99 */,
+ 3 /* 18/100-18/109 */,
+ 2 /* 18/110-18/119 */,
+ 2 /* 18/120-18/129 */,
+ 2 /* 18/130-18/139 */,
+ 2 /* 18/140-18/149 */,
+ 1 /* 18/150-18/159 */,
+ 1 /* 18/160-18/169 */,
+ 1 /* 18/170-18/179 */,
+ 1 /* 18/180-18/189 */,
+ 1 /* 18/190-18/199 */,
+ 0 /* 18/200-18/209 */,
+ 0 /* 18/210-18/219 */,
+ 0 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (INT/WIS) -- Various things
+ */
+byte adj_mag_stat[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 0 /* 5 */,
+ 0 /* 6 */,
+ 0 /* 7 */,
+ 1 /* 8 */,
+ 1 /* 9 */,
+ 1 /* 10 */,
+ 1 /* 11 */,
+ 1 /* 12 */,
+ 1 /* 13 */,
+ 1 /* 14 */,
+ 2 /* 15 */,
+ 2 /* 16 */,
+ 2 /* 17 */,
+ 3 /* 18/00-18/09 */,
+ 3 /* 18/10-18/19 */,
+ 3 /* 18/20-18/29 */,
+ 3 /* 18/30-18/39 */,
+ 3 /* 18/40-18/49 */,
+ 4 /* 18/50-18/59 */,
+ 4 /* 18/60-18/69 */,
+ 5 /* 18/70-18/79 */,
+ 6 /* 18/80-18/89 */,
+ 7 /* 18/90-18/99 */,
+ 8 /* 18/100-18/109 */,
+ 9 /* 18/110-18/119 */,
+ 10 /* 18/120-18/129 */,
+ 11 /* 18/130-18/139 */,
+ 12 /* 18/140-18/149 */,
+ 13 /* 18/150-18/159 */,
+ 14 /* 18/160-18/169 */,
+ 15 /* 18/170-18/179 */,
+ 16 /* 18/180-18/189 */,
+ 17 /* 18/190-18/199 */,
+ 18 /* 18/200-18/209 */,
+ 19 /* 18/210-18/219 */,
+ 20 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (CHR) -- payment percentages
+ */
+byte adj_chr_gold[] =
+{
+ 130 /* 3 */,
+ 125 /* 4 */,
+ 122 /* 5 */,
+ 120 /* 6 */,
+ 118 /* 7 */,
+ 116 /* 8 */,
+ 114 /* 9 */,
+ 112 /* 10 */,
+ 110 /* 11 */,
+ 108 /* 12 */,
+ 106 /* 13 */,
+ 104 /* 14 */,
+ 103 /* 15 */,
+ 102 /* 16 */,
+ 101 /* 17 */,
+ 100 /* 18/00-18/09 */,
+ 99 /* 18/10-18/19 */,
+ 98 /* 18/20-18/29 */,
+ 97 /* 18/30-18/39 */,
+ 96 /* 18/40-18/49 */,
+ 95 /* 18/50-18/59 */,
+ 94 /* 18/60-18/69 */,
+ 93 /* 18/70-18/79 */,
+ 92 /* 18/80-18/89 */,
+ 91 /* 18/90-18/99 */,
+ 90 /* 18/100-18/109 */,
+ 89 /* 18/110-18/119 */,
+ 88 /* 18/120-18/129 */,
+ 87 /* 18/130-18/139 */,
+ 86 /* 18/140-18/149 */,
+ 85 /* 18/150-18/159 */,
+ 84 /* 18/160-18/169 */,
+ 83 /* 18/170-18/179 */,
+ 82 /* 18/180-18/189 */,
+ 81 /* 18/190-18/199 */,
+ 80 /* 18/200-18/209 */,
+ 79 /* 18/210-18/219 */,
+ 78 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (INT) -- Magic devices
+ */
+byte adj_int_dev[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 0 /* 5 */,
+ 0 /* 6 */,
+ 0 /* 7 */,
+ 1 /* 8 */,
+ 1 /* 9 */,
+ 1 /* 10 */,
+ 1 /* 11 */,
+ 1 /* 12 */,
+ 1 /* 13 */,
+ 1 /* 14 */,
+ 2 /* 15 */,
+ 2 /* 16 */,
+ 2 /* 17 */,
+ 3 /* 18/00-18/09 */,
+ 3 /* 18/10-18/19 */,
+ 4 /* 18/20-18/29 */,
+ 4 /* 18/30-18/39 */,
+ 5 /* 18/40-18/49 */,
+ 5 /* 18/50-18/59 */,
+ 6 /* 18/60-18/69 */,
+ 6 /* 18/70-18/79 */,
+ 7 /* 18/80-18/89 */,
+ 7 /* 18/90-18/99 */,
+ 8 /* 18/100-18/109 */,
+ 9 /* 18/110-18/119 */,
+ 10 /* 18/120-18/129 */,
+ 11 /* 18/130-18/139 */,
+ 12 /* 18/140-18/149 */,
+ 13 /* 18/150-18/159 */,
+ 14 /* 18/160-18/169 */,
+ 15 /* 18/170-18/179 */,
+ 16 /* 18/180-18/189 */,
+ 17 /* 18/190-18/199 */,
+ 18 /* 18/200-18/209 */,
+ 19 /* 18/210-18/219 */,
+ 20 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (WIS) -- Saving throw
+ */
+byte adj_wis_sav[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 0 /* 5 */,
+ 0 /* 6 */,
+ 0 /* 7 */,
+ 1 /* 8 */,
+ 1 /* 9 */,
+ 1 /* 10 */,
+ 1 /* 11 */,
+ 1 /* 12 */,
+ 1 /* 13 */,
+ 1 /* 14 */,
+ 2 /* 15 */,
+ 2 /* 16 */,
+ 2 /* 17 */,
+ 3 /* 18/00-18/09 */,
+ 3 /* 18/10-18/19 */,
+ 3 /* 18/20-18/29 */,
+ 3 /* 18/30-18/39 */,
+ 3 /* 18/40-18/49 */,
+ 4 /* 18/50-18/59 */,
+ 4 /* 18/60-18/69 */,
+ 5 /* 18/70-18/79 */,
+ 5 /* 18/80-18/89 */,
+ 6 /* 18/90-18/99 */,
+ 7 /* 18/100-18/109 */,
+ 8 /* 18/110-18/119 */,
+ 9 /* 18/120-18/129 */,
+ 10 /* 18/130-18/139 */,
+ 11 /* 18/140-18/149 */,
+ 12 /* 18/150-18/159 */,
+ 13 /* 18/160-18/169 */,
+ 14 /* 18/170-18/179 */,
+ 15 /* 18/180-18/189 */,
+ 16 /* 18/190-18/199 */,
+ 17 /* 18/200-18/209 */,
+ 18 /* 18/210-18/219 */,
+ 19 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (DEX) -- disarming
+ */
+byte adj_dex_dis[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 0 /* 5 */,
+ 0 /* 6 */,
+ 0 /* 7 */,
+ 0 /* 8 */,
+ 0 /* 9 */,
+ 0 /* 10 */,
+ 0 /* 11 */,
+ 0 /* 12 */,
+ 1 /* 13 */,
+ 1 /* 14 */,
+ 1 /* 15 */,
+ 2 /* 16 */,
+ 2 /* 17 */,
+ 4 /* 18/00-18/09 */,
+ 4 /* 18/10-18/19 */,
+ 4 /* 18/20-18/29 */,
+ 4 /* 18/30-18/39 */,
+ 5 /* 18/40-18/49 */,
+ 5 /* 18/50-18/59 */,
+ 5 /* 18/60-18/69 */,
+ 6 /* 18/70-18/79 */,
+ 6 /* 18/80-18/89 */,
+ 7 /* 18/90-18/99 */,
+ 8 /* 18/100-18/109 */,
+ 8 /* 18/110-18/119 */,
+ 8 /* 18/120-18/129 */,
+ 8 /* 18/130-18/139 */,
+ 8 /* 18/140-18/149 */,
+ 9 /* 18/150-18/159 */,
+ 9 /* 18/160-18/169 */,
+ 9 /* 18/170-18/179 */,
+ 9 /* 18/180-18/189 */,
+ 9 /* 18/190-18/199 */,
+ 10 /* 18/200-18/209 */,
+ 10 /* 18/210-18/219 */,
+ 10 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (INT) -- disarming
+ */
+byte adj_int_dis[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 0 /* 5 */,
+ 0 /* 6 */,
+ 0 /* 7 */,
+ 1 /* 8 */,
+ 1 /* 9 */,
+ 1 /* 10 */,
+ 1 /* 11 */,
+ 1 /* 12 */,
+ 1 /* 13 */,
+ 1 /* 14 */,
+ 2 /* 15 */,
+ 2 /* 16 */,
+ 2 /* 17 */,
+ 3 /* 18/00-18/09 */,
+ 3 /* 18/10-18/19 */,
+ 3 /* 18/20-18/29 */,
+ 4 /* 18/30-18/39 */,
+ 4 /* 18/40-18/49 */,
+ 5 /* 18/50-18/59 */,
+ 6 /* 18/60-18/69 */,
+ 7 /* 18/70-18/79 */,
+ 8 /* 18/80-18/89 */,
+ 9 /* 18/90-18/99 */,
+ 10 /* 18/100-18/109 */,
+ 10 /* 18/110-18/119 */,
+ 11 /* 18/120-18/129 */,
+ 12 /* 18/130-18/139 */,
+ 13 /* 18/140-18/149 */,
+ 14 /* 18/150-18/159 */,
+ 15 /* 18/160-18/169 */,
+ 16 /* 18/170-18/179 */,
+ 17 /* 18/180-18/189 */,
+ 18 /* 18/190-18/199 */,
+ 19 /* 18/200-18/209 */,
+ 19 /* 18/210-18/219 */,
+ 20 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (DEX) -- bonus to ac (plus 128)
+ */
+byte adj_dex_ta[] =
+{
+ 128 + -4 /* 3 */,
+ 128 + -3 /* 4 */,
+ 128 + -2 /* 5 */,
+ 128 + -1 /* 6 */,
+ 128 + 0 /* 7 */,
+ 128 + 0 /* 8 */,
+ 128 + 0 /* 9 */,
+ 128 + 0 /* 10 */,
+ 128 + 0 /* 11 */,
+ 128 + 0 /* 12 */,
+ 128 + 0 /* 13 */,
+ 128 + 0 /* 14 */,
+ 128 + 1 /* 15 */,
+ 128 + 1 /* 16 */,
+ 128 + 1 /* 17 */,
+ 128 + 2 /* 18/00-18/09 */,
+ 128 + 2 /* 18/10-18/19 */,
+ 128 + 2 /* 18/20-18/29 */,
+ 128 + 2 /* 18/30-18/39 */,
+ 128 + 2 /* 18/40-18/49 */,
+ 128 + 3 /* 18/50-18/59 */,
+ 128 + 3 /* 18/60-18/69 */,
+ 128 + 3 /* 18/70-18/79 */,
+ 128 + 4 /* 18/80-18/89 */,
+ 128 + 5 /* 18/90-18/99 */,
+ 128 + 6 /* 18/100-18/109 */,
+ 128 + 7 /* 18/110-18/119 */,
+ 128 + 8 /* 18/120-18/129 */,
+ 128 + 9 /* 18/130-18/139 */,
+ 128 + 9 /* 18/140-18/149 */,
+ 128 + 10 /* 18/150-18/159 */,
+ 128 + 11 /* 18/160-18/169 */,
+ 128 + 12 /* 18/170-18/179 */,
+ 128 + 13 /* 18/180-18/189 */,
+ 128 + 14 /* 18/190-18/199 */,
+ 128 + 15 /* 18/200-18/209 */,
+ 128 + 15 /* 18/210-18/219 */,
+ 128 + 16 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (STR) -- bonus to dam (plus 128)
+ */
+byte adj_str_td[] =
+{
+ 128 + -2 /* 3 */,
+ 128 + -2 /* 4 */,
+ 128 + -1 /* 5 */,
+ 128 + -1 /* 6 */,
+ 128 + 0 /* 7 */,
+ 128 + 0 /* 8 */,
+ 128 + 0 /* 9 */,
+ 128 + 0 /* 10 */,
+ 128 + 0 /* 11 */,
+ 128 + 0 /* 12 */,
+ 128 + 0 /* 13 */,
+ 128 + 0 /* 14 */,
+ 128 + 0 /* 15 */,
+ 128 + 1 /* 16 */,
+ 128 + 2 /* 17 */,
+ 128 + 2 /* 18/00-18/09 */,
+ 128 + 2 /* 18/10-18/19 */,
+ 128 + 3 /* 18/20-18/29 */,
+ 128 + 3 /* 18/30-18/39 */,
+ 128 + 3 /* 18/40-18/49 */,
+ 128 + 3 /* 18/50-18/59 */,
+ 128 + 3 /* 18/60-18/69 */,
+ 128 + 4 /* 18/70-18/79 */,
+ 128 + 5 /* 18/80-18/89 */,
+ 128 + 5 /* 18/90-18/99 */,
+ 128 + 6 /* 18/100-18/109 */,
+ 128 + 7 /* 18/110-18/119 */,
+ 128 + 8 /* 18/120-18/129 */,
+ 128 + 9 /* 18/130-18/139 */,
+ 128 + 10 /* 18/140-18/149 */,
+ 128 + 11 /* 18/150-18/159 */,
+ 128 + 12 /* 18/160-18/169 */,
+ 128 + 13 /* 18/170-18/179 */,
+ 128 + 14 /* 18/180-18/189 */,
+ 128 + 15 /* 18/190-18/199 */,
+ 128 + 16 /* 18/200-18/209 */,
+ 128 + 18 /* 18/210-18/219 */,
+ 128 + 20 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (DEX) -- bonus to hit (plus 128)
+ */
+byte adj_dex_th[] =
+{
+ 128 + -3 /* 3 */,
+ 128 + -2 /* 4 */,
+ 128 + -2 /* 5 */,
+ 128 + -1 /* 6 */,
+ 128 + -1 /* 7 */,
+ 128 + 0 /* 8 */,
+ 128 + 0 /* 9 */,
+ 128 + 0 /* 10 */,
+ 128 + 0 /* 11 */,
+ 128 + 0 /* 12 */,
+ 128 + 0 /* 13 */,
+ 128 + 0 /* 14 */,
+ 128 + 0 /* 15 */,
+ 128 + 1 /* 16 */,
+ 128 + 2 /* 17 */,
+ 128 + 3 /* 18/00-18/09 */,
+ 128 + 3 /* 18/10-18/19 */,
+ 128 + 3 /* 18/20-18/29 */,
+ 128 + 3 /* 18/30-18/39 */,
+ 128 + 3 /* 18/40-18/49 */,
+ 128 + 4 /* 18/50-18/59 */,
+ 128 + 4 /* 18/60-18/69 */,
+ 128 + 4 /* 18/70-18/79 */,
+ 128 + 4 /* 18/80-18/89 */,
+ 128 + 5 /* 18/90-18/99 */,
+ 128 + 6 /* 18/100-18/109 */,
+ 128 + 7 /* 18/110-18/119 */,
+ 128 + 8 /* 18/120-18/129 */,
+ 128 + 9 /* 18/130-18/139 */,
+ 128 + 9 /* 18/140-18/149 */,
+ 128 + 10 /* 18/150-18/159 */,
+ 128 + 11 /* 18/160-18/169 */,
+ 128 + 12 /* 18/170-18/179 */,
+ 128 + 13 /* 18/180-18/189 */,
+ 128 + 14 /* 18/190-18/199 */,
+ 128 + 15 /* 18/200-18/209 */,
+ 128 + 15 /* 18/210-18/219 */,
+ 128 + 16 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (STR) -- bonus to hit (plus 128)
+ */
+byte adj_str_th[] =
+{
+ 128 + -3 /* 3 */,
+ 128 + -2 /* 4 */,
+ 128 + -1 /* 5 */,
+ 128 + -1 /* 6 */,
+ 128 + 0 /* 7 */,
+ 128 + 0 /* 8 */,
+ 128 + 0 /* 9 */,
+ 128 + 0 /* 10 */,
+ 128 + 0 /* 11 */,
+ 128 + 0 /* 12 */,
+ 128 + 0 /* 13 */,
+ 128 + 0 /* 14 */,
+ 128 + 0 /* 15 */,
+ 128 + 0 /* 16 */,
+ 128 + 0 /* 17 */,
+ 128 + 1 /* 18/00-18/09 */,
+ 128 + 1 /* 18/10-18/19 */,
+ 128 + 1 /* 18/20-18/29 */,
+ 128 + 1 /* 18/30-18/39 */,
+ 128 + 1 /* 18/40-18/49 */,
+ 128 + 1 /* 18/50-18/59 */,
+ 128 + 1 /* 18/60-18/69 */,
+ 128 + 2 /* 18/70-18/79 */,
+ 128 + 3 /* 18/80-18/89 */,
+ 128 + 4 /* 18/90-18/99 */,
+ 128 + 5 /* 18/100-18/109 */,
+ 128 + 6 /* 18/110-18/119 */,
+ 128 + 7 /* 18/120-18/129 */,
+ 128 + 8 /* 18/130-18/139 */,
+ 128 + 9 /* 18/140-18/149 */,
+ 128 + 10 /* 18/150-18/159 */,
+ 128 + 11 /* 18/160-18/169 */,
+ 128 + 12 /* 18/170-18/179 */,
+ 128 + 13 /* 18/180-18/189 */,
+ 128 + 14 /* 18/190-18/199 */,
+ 128 + 15 /* 18/200-18/209 */,
+ 128 + 15 /* 18/210-18/219 */,
+ 128 + 16 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (STR) -- weight limit in deca-pounds
+ */
+byte adj_str_wgt[] =
+{
+ 5 /* 3 */,
+ 6 /* 4 */,
+ 7 /* 5 */,
+ 8 /* 6 */,
+ 9 /* 7 */,
+ 10 /* 8 */,
+ 11 /* 9 */,
+ 12 /* 10 */,
+ 13 /* 11 */,
+ 14 /* 12 */,
+ 15 /* 13 */,
+ 16 /* 14 */,
+ 17 /* 15 */,
+ 18 /* 16 */,
+ 19 /* 17 */,
+ 20 /* 18/00-18/09 */,
+ 22 /* 18/10-18/19 */,
+ 24 /* 18/20-18/29 */,
+ 26 /* 18/30-18/39 */,
+ 28 /* 18/40-18/49 */,
+ 30 /* 18/50-18/59 */,
+ 31 /* 18/60-18/69 */,
+ 31 /* 18/70-18/79 */,
+ 32 /* 18/80-18/89 */,
+ 32 /* 18/90-18/99 */,
+ 33 /* 18/100-18/109 */,
+ 33 /* 18/110-18/119 */,
+ 34 /* 18/120-18/129 */,
+ 34 /* 18/130-18/139 */,
+ 35 /* 18/140-18/149 */,
+ 35 /* 18/150-18/159 */,
+ 36 /* 18/160-18/169 */,
+ 36 /* 18/170-18/179 */,
+ 37 /* 18/180-18/189 */,
+ 37 /* 18/190-18/199 */,
+ 38 /* 18/200-18/209 */,
+ 38 /* 18/210-18/219 */,
+ 39 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (STR) -- weapon weight limit in pounds
+ */
+byte adj_str_hold[] =
+{
+ 4 /* 3 */,
+ 5 /* 4 */,
+ 6 /* 5 */,
+ 7 /* 6 */,
+ 8 /* 7 */,
+ 10 /* 8 */,
+ 12 /* 9 */,
+ 14 /* 10 */,
+ 16 /* 11 */,
+ 18 /* 12 */,
+ 20 /* 13 */,
+ 22 /* 14 */,
+ 24 /* 15 */,
+ 26 /* 16 */,
+ 28 /* 17 */,
+ 30 /* 18/00-18/09 */,
+ 30 /* 18/10-18/19 */,
+ 35 /* 18/20-18/29 */,
+ 40 /* 18/30-18/39 */,
+ 45 /* 18/40-18/49 */,
+ 50 /* 18/50-18/59 */,
+ 55 /* 18/60-18/69 */,
+ 60 /* 18/70-18/79 */,
+ 65 /* 18/80-18/89 */,
+ 70 /* 18/90-18/99 */,
+ 80 /* 18/100-18/109 */,
+ 80 /* 18/110-18/119 */,
+ 80 /* 18/120-18/129 */,
+ 80 /* 18/130-18/139 */,
+ 80 /* 18/140-18/149 */,
+ 90 /* 18/150-18/159 */,
+ 90 /* 18/160-18/169 */,
+ 90 /* 18/170-18/179 */,
+ 90 /* 18/180-18/189 */,
+ 90 /* 18/190-18/199 */,
+ 100 /* 18/200-18/209 */,
+ 100 /* 18/210-18/219 */,
+ 100 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (STR) -- digging value
+ */
+byte adj_str_dig[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 1 /* 5 */,
+ 2 /* 6 */,
+ 3 /* 7 */,
+ 4 /* 8 */,
+ 4 /* 9 */,
+ 5 /* 10 */,
+ 5 /* 11 */,
+ 6 /* 12 */,
+ 6 /* 13 */,
+ 7 /* 14 */,
+ 7 /* 15 */,
+ 8 /* 16 */,
+ 8 /* 17 */,
+ 9 /* 18/00-18/09 */,
+ 10 /* 18/10-18/19 */,
+ 12 /* 18/20-18/29 */,
+ 15 /* 18/30-18/39 */,
+ 20 /* 18/40-18/49 */,
+ 25 /* 18/50-18/59 */,
+ 30 /* 18/60-18/69 */,
+ 35 /* 18/70-18/79 */,
+ 40 /* 18/80-18/89 */,
+ 45 /* 18/90-18/99 */,
+ 50 /* 18/100-18/109 */,
+ 55 /* 18/110-18/119 */,
+ 60 /* 18/120-18/129 */,
+ 65 /* 18/130-18/139 */,
+ 70 /* 18/140-18/149 */,
+ 75 /* 18/150-18/159 */,
+ 80 /* 18/160-18/169 */,
+ 85 /* 18/170-18/179 */,
+ 90 /* 18/180-18/189 */,
+ 95 /* 18/190-18/199 */,
+ 100 /* 18/200-18/209 */,
+ 100 /* 18/210-18/219 */,
+ 100 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (STR) -- help index into the "blow" table
+ */
+byte adj_str_blow[] =
+{
+ 3 /* 3 */,
+ 4 /* 4 */,
+ 5 /* 5 */,
+ 6 /* 6 */,
+ 7 /* 7 */,
+ 8 /* 8 */,
+ 9 /* 9 */,
+ 10 /* 10 */,
+ 11 /* 11 */,
+ 12 /* 12 */,
+ 13 /* 13 */,
+ 14 /* 14 */,
+ 15 /* 15 */,
+ 16 /* 16 */,
+ 17 /* 17 */,
+ 20 /* 18/00-18/09 */,
+ 30 /* 18/10-18/19 */,
+ 40 /* 18/20-18/29 */,
+ 50 /* 18/30-18/39 */,
+ 60 /* 18/40-18/49 */,
+ 70 /* 18/50-18/59 */,
+ 80 /* 18/60-18/69 */,
+ 90 /* 18/70-18/79 */,
+ 100 /* 18/80-18/89 */,
+ 110 /* 18/90-18/99 */,
+ 120 /* 18/100-18/109 */,
+ 130 /* 18/110-18/119 */,
+ 140 /* 18/120-18/129 */,
+ 150 /* 18/130-18/139 */,
+ 160 /* 18/140-18/149 */,
+ 170 /* 18/150-18/159 */,
+ 180 /* 18/160-18/169 */,
+ 190 /* 18/170-18/179 */,
+ 200 /* 18/180-18/189 */,
+ 210 /* 18/190-18/199 */,
+ 220 /* 18/200-18/209 */,
+ 230 /* 18/210-18/219 */,
+ 240 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (DEX) -- index into the "blow" table
+ */
+byte adj_dex_blow[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 0 /* 5 */,
+ 0 /* 6 */,
+ 0 /* 7 */,
+ 0 /* 8 */,
+ 0 /* 9 */,
+ 1 /* 10 */,
+ 1 /* 11 */,
+ 1 /* 12 */,
+ 1 /* 13 */,
+ 1 /* 14 */,
+ 1 /* 15 */,
+ 1 /* 16 */,
+ 1 /* 17 */,
+ 1 /* 18/00-18/09 */,
+ 2 /* 18/10-18/19 */,
+ 2 /* 18/20-18/29 */,
+ 2 /* 18/30-18/39 */,
+ 2 /* 18/40-18/49 */,
+ 3 /* 18/50-18/59 */,
+ 3 /* 18/60-18/69 */,
+ 4 /* 18/70-18/79 */,
+ 4 /* 18/80-18/89 */,
+ 5 /* 18/90-18/99 */,
+ 6 /* 18/100-18/109 */,
+ 7 /* 18/110-18/119 */,
+ 8 /* 18/120-18/129 */,
+ 9 /* 18/130-18/139 */,
+ 10 /* 18/140-18/149 */,
+ 11 /* 18/150-18/159 */,
+ 12 /* 18/160-18/169 */,
+ 14 /* 18/170-18/179 */,
+ 16 /* 18/180-18/189 */,
+ 18 /* 18/190-18/199 */,
+ 20 /* 18/200-18/209 */,
+ 20 /* 18/210-18/219 */,
+ 20 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (DEX) -- chance of avoiding "theft" and "falling"
+ */
+byte adj_dex_safe[] =
+{
+ 0 /* 3 */,
+ 1 /* 4 */,
+ 2 /* 5 */,
+ 3 /* 6 */,
+ 4 /* 7 */,
+ 5 /* 8 */,
+ 5 /* 9 */,
+ 6 /* 10 */,
+ 6 /* 11 */,
+ 7 /* 12 */,
+ 7 /* 13 */,
+ 8 /* 14 */,
+ 8 /* 15 */,
+ 9 /* 16 */,
+ 9 /* 17 */,
+ 10 /* 18/00-18/09 */,
+ 10 /* 18/10-18/19 */,
+ 15 /* 18/20-18/29 */,
+ 15 /* 18/30-18/39 */,
+ 20 /* 18/40-18/49 */,
+ 25 /* 18/50-18/59 */,
+ 30 /* 18/60-18/69 */,
+ 35 /* 18/70-18/79 */,
+ 40 /* 18/80-18/89 */,
+ 45 /* 18/90-18/99 */,
+ 50 /* 18/100-18/109 */,
+ 60 /* 18/110-18/119 */,
+ 70 /* 18/120-18/129 */,
+ 80 /* 18/130-18/139 */,
+ 90 /* 18/140-18/149 */,
+ 100 /* 18/150-18/159 */,
+ 100 /* 18/160-18/169 */,
+ 100 /* 18/170-18/179 */,
+ 100 /* 18/180-18/189 */,
+ 100 /* 18/190-18/199 */,
+ 100 /* 18/200-18/209 */,
+ 100 /* 18/210-18/219 */,
+ 100 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (CON) -- base regeneration rate
+ */
+byte adj_con_fix[] =
+{
+ 0 /* 3 */,
+ 0 /* 4 */,
+ 0 /* 5 */,
+ 0 /* 6 */,
+ 0 /* 7 */,
+ 0 /* 8 */,
+ 0 /* 9 */,
+ 0 /* 10 */,
+ 0 /* 11 */,
+ 0 /* 12 */,
+ 0 /* 13 */,
+ 1 /* 14 */,
+ 1 /* 15 */,
+ 1 /* 16 */,
+ 1 /* 17 */,
+ 2 /* 18/00-18/09 */,
+ 2 /* 18/10-18/19 */,
+ 2 /* 18/20-18/29 */,
+ 2 /* 18/30-18/39 */,
+ 2 /* 18/40-18/49 */,
+ 3 /* 18/50-18/59 */,
+ 3 /* 18/60-18/69 */,
+ 3 /* 18/70-18/79 */,
+ 3 /* 18/80-18/89 */,
+ 3 /* 18/90-18/99 */,
+ 4 /* 18/100-18/109 */,
+ 4 /* 18/110-18/119 */,
+ 5 /* 18/120-18/129 */,
+ 6 /* 18/130-18/139 */,
+ 6 /* 18/140-18/149 */,
+ 7 /* 18/150-18/159 */,
+ 7 /* 18/160-18/169 */,
+ 8 /* 18/170-18/179 */,
+ 8 /* 18/180-18/189 */,
+ 8 /* 18/190-18/199 */,
+ 9 /* 18/200-18/209 */,
+ 9 /* 18/210-18/219 */,
+ 9 /* 18/220+ */
+};
+
+
+/*
+ * Stat Table (CON) -- extra half-hitpoints per level (plus 128)
+ */
+byte adj_con_mhp[] =
+{
+ 128 + -5 /* 3 */,
+ 128 + -3 /* 4 */,
+ 128 + -2 /* 5 */,
+ 128 + -1 /* 6 */,
+ 128 + 0 /* 7 */,
+ 128 + 0 /* 8 */,
+ 128 + 0 /* 9 */,
+ 128 + 0 /* 10 */,
+ 128 + 0 /* 11 */,
+ 128 + 0 /* 12 */,
+ 128 + 0 /* 13 */,
+ 128 + 0 /* 14 */,
+ 128 + 1 /* 15 */,
+ 128 + 1 /* 16 */,
+ 128 + 2 /* 17 */,
+ 128 + 3 /* 18/00-18/09 */,
+ 128 + 4 /* 18/10-18/19 */,
+ 128 + 4 /* 18/20-18/29 */,
+ 128 + 4 /* 18/30-18/39 */,
+ 128 + 4 /* 18/40-18/49 */,
+ 128 + 5 /* 18/50-18/59 */,
+ 128 + 6 /* 18/60-18/69 */,
+ 128 + 7 /* 18/70-18/79 */,
+ 128 + 8 /* 18/80-18/89 */,
+ 128 + 9 /* 18/90-18/99 */,
+ 128 + 10 /* 18/100-18/109 */,
+ 128 + 11 /* 18/110-18/119 */,
+ 128 + 12 /* 18/120-18/129 */,
+ 128 + 13 /* 18/130-18/139 */,
+ 128 + 14 /* 18/140-18/149 */,
+ 128 + 15 /* 18/150-18/159 */,
+ 128 + 16 /* 18/160-18/169 */,
+ 128 + 18 /* 18/170-18/179 */,
+ 128 + 20 /* 18/180-18/189 */,
+ 128 + 22 /* 18/190-18/199 */,
+ 128 + 25 /* 18/200-18/209 */,
+ 128 + 26 /* 18/210-18/219 */,
+ 128 + 27 /* 18/220+ */
+};
+
+
+/*
+ * This table is used to help calculate the number of blows the player can
+ * make in a single round of attacks (one player turn) with a normal weapon.
+ *
+ * This number ranges from a single blow/round for weak players to up to six
+ * blows/round for powerful warriors.
+ *
+ * Note that certain artifacts and ego-items give "bonus" blows/round.
+ *
+ * First, from the player class, we extract some values:
+ *
+ * Warrior --> num = 6; mul = 5; div = MAX(30, weapon_weight);
+ * Mage --> num = 4; mul = 2; div = MAX(40, weapon_weight);
+ * Priest --> num = 5; mul = 3; div = MAX(35, weapon_weight);
+ * Rogue --> num = 5; mul = 3; div = MAX(30, weapon_weight);
+ * Ranger --> num = 5; mul = 4; div = MAX(35, weapon_weight);
+ * Paladin --> num = 5; mul = 4; div = MAX(30, weapon_weight);
+ *
+ * To get "P", we look up the relevant "adj_str_blow[]" (see above),
+ * multiply it by "mul", and then divide it by "div", rounding down.
+ *
+ * To get "D", we look up the relevant "adj_dex_blow[]" (see above),
+ * note especially column 6 (DEX 18/101) and 11 (DEX 18/150).
+ *
+ * The player gets "blows_table[P][D]" blows/round, as shown below,
+ * up to a maximum of "num" blows/round, plus any "bonus" blows/round.
+ */
+byte blows_table[12][12] =
+{
+ /* P/D */
+ /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11+ */
+
+ /* 0 */
+ { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3 },
+
+ /* 1 */
+ { 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4 },
+
+ /* 2 */
+ { 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5 },
+
+ /* 3 */
+ { 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5 },
+
+ /* 4 */
+ { 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5 },
+
+ /* 5 */
+ { 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5, 6 },
+
+ /* 6 */
+ { 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5, 6 },
+
+ /* 7 */
+ { 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 6 },
+
+ /* 8 */
+ { 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6 },
+
+ /* 9 */
+ { 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6 },
+
+ /* 10 */
+ { 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6 },
+
+ /* 11+ */
+ { 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6 },
+};
+
+
+s16b arena_monsters[MAX_ARENA_MONS] =
+{
+ 30, 43, 102, 118, 126, 149, 173,
+ 183, 188, 191, 216, 230, 238, 244,
+ 255, 262, 293, 297, 321, 349, 372,
+ 401, 415, 454, 464, 485, 538, 631,
+ 641
+};
+
+
+/*
+ * This table allows quick conversion from "speed" to "energy"
+ * The basic function WAS ((S>=110) ? (S-110) : (100 / (120-S)))
+ * Note that table access is *much* quicker than computation.
+ *
+ * Note that the table has been changed at high speeds. From
+ * "Slow (-40)" to "Fast (+30)" is pretty much unchanged, but
+ * at speeds above "Fast (+30)", one approaches an asymptotic
+ * effective limit of 50 energy per turn. This means that it
+ * is relatively easy to reach "Fast (+30)" and get about 40
+ * energy per turn, but then speed becomes very "expensive",
+ * and you must get all the way to "Fast (+50)" to reach the
+ * point of getting 45 energy per turn. After that point,
+ * further increases in speed are more or less pointless,
+ * except to balance out heavy inventory.
+ *
+ * Note that currently the fastest monster is "Fast (+30)".
+ *
+ * It should be possible to lower the energy threshold from
+ * 100 units to 50 units, though this may interact badly with
+ * the (compiled out) small random energy boost code. It may
+ * also tend to cause more "clumping" at high speeds.
+ */
+byte extract_energy[300] =
+{
+ /* Slow */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* Slow */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* Slow */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* Slow */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* Slow */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* Slow */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* S-50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* S-40 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ /* S-30 */ 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
+ /* S-20 */ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
+ /* S-10 */ 5, 5, 5, 5, 6, 6, 7, 7, 8, 9,
+ /* Norm */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ /* F+10 */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ /* F+20 */ 30, 31, 32, 33, 34, 35, 36, 36, 37, 37,
+ /* F+30 */ 38, 38, 39, 39, 40, 40, 40, 41, 41, 41,
+ /* F+40 */ 42, 42, 42, 43, 43, 43, 44, 44, 44, 44,
+ /* F+50 */ 45, 45, 45, 45, 45, 46, 46, 46, 46, 46,
+ /* F+60 */ 47, 47, 47, 47, 47, 48, 48, 48, 48, 48,
+ /* F+70 */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Fast */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ /* Virtual */ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+};
+
+
+
+
+/*
+ * Base experience levels, may be adjusted up for race and/or class
+ */
+s32b player_exp[PY_MAX_LEVEL] =
+{
+ 10,
+ 25,
+ 45,
+ 70,
+ 100,
+ 140,
+ 200,
+ 280,
+ 380,
+ 500,
+ 650,
+ 850,
+ 1100,
+ 1400,
+ 1800,
+ 2300,
+ 2900,
+ 3600,
+ 4400,
+ 5400,
+ 6800,
+ 8400,
+ 10200,
+ 12500,
+ 17500,
+ 25000,
+ 35000L,
+ 50000L,
+ 75000L,
+ 100000L,
+ 150000L,
+ 200000L,
+ 275000L,
+ 350000L,
+ 450000L,
+ 550000L,
+ 700000L,
+ 850000L,
+ 1000000L,
+ 1250000L,
+ 1500000L,
+ 1800000L,
+ 2100000L,
+ 2400000L,
+ 2700000L,
+ 3000000L,
+ 3500000L,
+ 4000000L,
+ 4500000L,
+ 5000000L
+};
+
+
+/*
+ * Player Sexes
+ *
+ * Title,
+ * Winner
+ */
+player_sex sex_info[MAX_SEXES] =
+{
+ {
+ "Female",
+ "Queen"
+ },
+
+{
+"Male",
+"King"
+},
+{
+"Neuter",
+"Ruler"
+}
+};
+
+/*
+ * Hack -- the "basic" color names (see "TERM_xxx")
+ */
+cptr color_names[16] =
+{
+ "Dark",
+ "White",
+ "Slate",
+ "Orange",
+ "Red",
+ "Green",
+ "Blue",
+ "Umber",
+ "Light Dark",
+ "Light Slate",
+ "Violet",
+ "Yellow",
+ "Light Red",
+ "Light Green",
+ "Light Blue",
+ "Light Umber",
+};
+
+
+/*
+ * Abbreviations of healthy stats
+ */
+cptr stat_names[6] =
+{
+ "STR", "INT", "WIS", "DEX", "CON", "CHR"
+};
+
+/*
+ * Abbreviations of damaged stats
+ */
+cptr stat_names_reduced[6] =
+{
+ "Str", "Int", "Wis", "Dex", "Con", "Chr"
+};
+
+
+/*
+ * Certain "screens" always use the main screen, including News, Birth,
+ * Dungeon, Tomb-stone, High-scores, Macros, Colors, Visuals, Options.
+ *
+ * Later, special flags may allow sub-windows to "steal" stuff from the
+ * main window, including File dump (help), File dump (artifacts, uniques),
+ * Character screen, Small scale map, Previous Messages, Store screen, etc.
+ *
+ * The "ctrl-i" (tab) command flips the "Display inven/equip" and "Display
+ * equip/inven" flags for all windows.
+ *
+ * The "ctrl-g" command (or pseudo-command) should perhaps grab a snapshot
+ * of the main screen into any interested windows.
+ */
+cptr window_flag_desc[32] =
+{
+ "Display inven/equip",
+ "Display equip/inven",
+ NULL,
+ "Display character",
+ "Show visible monsters",
+ NULL,
+ "Display messages",
+ "Display overhead view",
+ "Display monster recall",
+ "Display object recall",
+ NULL,
+ "Display snap-shot",
+ NULL,
+ NULL,
+ "Display borg messages",
+ "Display borg status",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+/*
+ * Available Options
+ *
+ * Option Screen Sets:
+ *
+ * Set 1: User Interface
+ * Set 2: Disturbance
+ * Set 3: Inventory
+ * Set 4: Game Play
+ * Set 5: ToME
+ * Set 6: Birth
+ *
+ * Note that bits 28-31 of set 0 are currently unused.
+ */
+option_type option_info[] =
+{
+ /*** User-Interface ***/
+
+ { &rogue_like_commands, FALSE, 1, 0,
+ "rogue_like_commands", "Rogue-like commands" },
+
+ { &quick_messages, TRUE, 1, 1,
+ "quick_messages", "Activate quick messages" },
+
+ { &other_query_flag, FALSE, 1, 2,
+ "other_query_flag", "Prompt for various information" },
+
+ { &carry_query_flag, FALSE, 1, 3,
+ "carry_query_flag", "Prompt before picking things up" },
+
+ { &use_old_target, FALSE, 1, 4,
+ "use_old_target", "Use old target by default" },
+
+ { &always_pickup, FALSE, 1, 5,
+ "always_pickup", "Pick things up by default" },
+
+ { &prompt_pickup_heavy, TRUE, 1, 6,
+ "prompt_pickup_heavy", "Prompt before picking up heavy objects" },
+
+ { &always_repeat, TRUE, 1, 7,
+ "always_repeat", "Repeat obvious commands" },
+
+ { &depth_in_feet, FALSE, 1, 8,
+ "depth_in_feet", "Show dungeon level in feet" },
+
+ { &stack_force_notes, TRUE, 1, 9,
+ "stack_force_notes", "Merge inscriptions when stacking" },
+
+ { &stack_force_costs, FALSE, 1, 10,
+ "stack_force_costs", "Merge discounts when stacking" },
+
+ { &show_labels, TRUE, 1, 11,
+ "show_labels", "Show labels in object listings" },
+
+ { &show_weights, TRUE, 1, 12,
+ "show_weights", "Show weights in object listings" },
+
+ { &show_inven_graph, TRUE, 1, 13,
+ "show_inven_graph", "Show graphics in inventory list" },
+
+ { &show_equip_graph, TRUE, 1, 14,
+ "show_equip_graph", "Show graphics in equipment list" },
+
+ { &show_store_graph, TRUE, 1, 15,
+ "show_store_graph", "Show graphics in stores" },
+
+ { &show_choices, TRUE, 1, 16,
+ "show_choices", "Show choices in certain sub-windows" },
+
+ { &show_details, TRUE, 1, 17,
+ "show_details", "Show details in certain sub-windows" },
+
+ { &ring_bell, FALSE, 1, 18,
+ "ring_bell", "Audible bell (on errors, etc)" },
+ /* Changed to default to FALSE -- it's so extremely annoying!!! -TY */
+
+ /*** Disturbance ***/
+
+ { &find_ignore_stairs, FALSE, 2, 0,
+ "find_ignore_stairs", "Run past stairs" },
+
+ { &find_ignore_doors, TRUE, 2, 1,
+ "find_ignore_doors", "Run through open doors" },
+
+ { &find_cut, FALSE, 2, 2,
+ "find_cut", "Run past known corners" },
+
+ { &find_examine, TRUE, 2, 3,
+ "find_examine", "Run into potential corners" },
+
+ { &disturb_move, FALSE, 2, 4,
+ "disturb_move", "Disturb whenever any monster moves" },
+
+ { &disturb_near, TRUE, 2, 5,
+ "disturb_near", "Disturb whenever viewable monster moves" },
+
+ { &disturb_panel, TRUE, 2, 6,
+ "disturb_panel", "Disturb whenever map panel changes" },
+
+ { &disturb_detect, TRUE, 2, 21,
+ "disturb_detect", "Disturb whenever leaving trap-detected area" },
+
+ { &disturb_state, TRUE, 2, 7,
+ "disturb_state", "Disturb whenever player state changes" },
+
+ { &disturb_minor, TRUE, 2, 8,
+ "disturb_minor", "Disturb whenever boring things happen" },
+
+ { &disturb_other, FALSE, 2, 9,
+ "disturb_other", "Disturb whenever random things happen" },
+
+ { &alert_hitpoint, FALSE, 2, 10,
+ "alert_hitpoint", "Alert user to critical hitpoints" },
+
+ { &alert_failure, FALSE, 2, 11,
+ "alert_failure", "Alert user to various failures" },
+
+ { &last_words, TRUE, 2, 12,
+ "last_words", "Get last words when the character dies" },
+
+ { &speak_unique, TRUE, 2, 13,
+ "speak_unique", "Allow shopkeepers and uniques to speak" },
+
+ { &auto_destroy, TRUE, 2, 14,
+ "auto_destroy", "No query to destroy known worthless items" },
+
+ { &wear_confirm, TRUE, 2, 15,
+ "confirm_wear", "Confirm to wear/wield known cursed items" },
+
+ { &confirm_stairs, FALSE, 2, 16,
+ "confirm_stairs", "Prompt before exiting a dungeon level" },
+
+ { &disturb_pets, FALSE, 2, 17,
+ "disturb_pets", "Disturb when visible pets move" },
+
+ { &easy_open, TRUE, 2, 18,
+ "easy_open", "Automatically open doors" },
+
+ { &easy_disarm, TRUE, 2, 19,
+ "easy_disarm", "Automatically disarm traps" },
+
+ { &easy_tunnel, FALSE, 2, 20,
+ "easy_tunnel", "Automatically tunnel walls" },
+
+ /*** Game-Play ***/
+
+ { &auto_haggle, TRUE, 3, 0,
+ "auto_haggle", "Auto-haggle in stores" },
+
+ { &auto_scum, TRUE, 3, 1,
+ "auto_scum", "Auto-scum for good levels" },
+
+ { &stack_allow_items, TRUE, 3, 2,
+ "stack_allow_items", "Allow weapons and armour to stack" },
+
+ { &stack_allow_wands, TRUE, 3, 3,
+ "stack_allow_wands", "Allow wands/staffs/rods to stack" },
+
+ { &expand_look, FALSE, 3, 4,
+ "expand_look", "Expand the power of the look command" },
+
+ { &expand_list, FALSE, 3, 5,
+ "expand_list", "Expand the power of the list commands" },
+
+ { &view_perma_grids, TRUE, 3, 6,
+ "view_perma_grids", "Map remembers all perma-lit grids" },
+
+ { &view_torch_grids, FALSE, 3, 7,
+ "view_torch_grids", "Map remembers all torch-lit grids" },
+
+ { &monster_lite, TRUE, 3, 19,
+ "monster_lite", "Allow some monsters to carry light" },
+
+ { &dungeon_align, TRUE, 3, 8,
+ "dungeon_align", "Generate dungeons with aligned rooms" },
+
+ { &dungeon_stair, TRUE, 3, 9,
+ "dungeon_stair", "Generate dungeons with connected stairs" },
+
+ { &flow_by_sound, FALSE, 3, 10,
+ "flow_by_sound", "Monsters chase current location (v.slow)" },
+
+ { &player_symbols, FALSE, 3, 12,
+ "player_symbols", "Use special symbols for the player char"},
+
+ { &plain_descriptions, TRUE, 3, 13,
+ "plain_descriptions", "Plain object descriptions" },
+
+ { &smart_learn, FALSE, 3, 14,
+ "smart_learn", "Monsters learn from their mistakes" },
+
+ { &smart_cheat, FALSE, 3, 15,
+ "smart_cheat", "Monsters exploit players weaknesses" },
+
+ { &stupid_monsters, FALSE, 3, 16,
+ "stupid_monsters", "Monsters behave stupidly" },
+
+ { &small_levels, TRUE, 3, 17,
+ "small_levels", "Allow unusually small dungeon levels" },
+
+ { &empty_levels, TRUE, 3, 18,
+ "empty_levels", "Allow empty 'arena' levels" },
+
+ /*** Efficiency ***/
+
+ { &view_reduce_lite, FALSE, 4, 0,
+ "view_reduce_lite", "Reduce lite-radius when running" },
+
+ { &view_reduce_view, FALSE, 4, 1,
+ "view_reduce_view", "Reduce view-radius in town" },
+
+ { &avoid_abort, FALSE, 4, 2,
+ "avoid_abort", "Avoid checking for user abort" },
+
+ { &avoid_shimmer, FALSE, 4, 17,
+ "avoid_shimmer", "Avoid extra shimmering (fast)" },
+
+ { &avoid_other, FALSE, 4, 3,
+ "avoid_other", "Avoid processing special colors (fast)" },
+
+ { &flush_failure, TRUE, 4, 4,
+ "flush_failure", "Flush input on various failures" },
+
+ { &flush_disturb, FALSE, 4, 5,
+ "flush_disturb", "Flush input whenever disturbed" },
+
+ { &flush_command, FALSE, 4, 6,
+ "flush_command", "Flush input before every command" },
+
+ { &fresh_before, TRUE, 4, 7,
+ "fresh_before", "Flush output before every command" },
+
+ { &fresh_after, FALSE, 4, 8,
+ "fresh_after", "Flush output after every command" },
+
+ { &fresh_message, FALSE, 4, 9,
+ "fresh_message", "Flush output after every message" },
+
+ { &hilite_player, FALSE, 4, 11,
+ "hilite_player", "Hilite the player with the cursor" },
+
+ { &view_yellow_lite, FALSE, 4, 12,
+ "view_yellow_lite", "Use special colors for torch-lit grids" },
+
+ { &view_bright_lite, FALSE, 4, 13,
+ "view_bright_lite", "Use special colors for 'viewable' grids" },
+
+ { &view_granite_lite, FALSE, 4, 14,
+ "view_granite_lite", "Use special colors for wall grids (slow)" },
+
+ { &view_special_lite, FALSE, 4, 15,
+ "view_special_lite", "Use special colors for floor grids (slow)" },
+
+ { &center_player, FALSE, 4, 16,
+ "center_player", "Center the view on the player (very slow)" },
+
+ /*** ToME options ***/
+
+ { &option_ingame_help, TRUE, 5, 1,
+ "ingame_help", "Ingame contextual help" },
+
+ { &exp_need, FALSE, 5, 2,
+ "exp_need", "Show the experience needed for next level" },
+
+ { &autoload_old_colors, FALSE, 5, 3,
+ "old_colors", "Use the old(Z) coloring scheme(reload the game)" },
+
+ { &auto_more, FALSE, 5, 4,
+ "auto_more", "Automatically clear '-more-' prompts" },
+
+ { &player_char_health, TRUE, 5, 6,
+ "player_char_health", "Player char represent his/her health" },
+
+ { &linear_stats, TRUE, 5, 7,
+ "linear_stats", "Stats are represented in a linear way" },
+
+ { &inventory_no_move, FALSE, 5, 8,
+ "inventory_no_move", "In option windows, just omit the select char" },
+
+
+ /*** Birth Options ***/
+
+ { &maximize, TRUE, 6, 1,
+ "maximize", "Maximise stats" },
+
+ { &preserve, TRUE, 6, 2,
+ "preserve", "Preserve artifacts" },
+
+ { &autoroll, TRUE, 6, 3,
+ "autoroll", "Specify 'minimal' stats" },
+
+ { &point_based, FALSE, 6, 17,
+ "point_based", "Generate character using a point system" },
+
+ { &ironman_rooms, FALSE, 6, 6,
+ "ironman_rooms", "Always generate very unusual rooms" },
+
+ { &take_notes, TRUE, 6, 7,
+ "take_notes", "Allow notes to be written to a file" },
+
+ { &auto_notes, TRUE, 6, 8,
+ "auto_notes", "Automatically note important events" },
+
+ { &fast_autoroller, FALSE, 6, 10,
+ "fast_autoroller", "Fast autoroller(NOT on multiuser systems)" },
+
+ { &joke_monsters, FALSE, 6, 14,
+ "joke_monsters", "Allow use of some 'joke' monsters" },
+
+ /* XXX */
+
+ { &always_small_level, FALSE, 6, 16,
+ "always_small_level", "Always make small levels" },
+
+ { &fate_option, TRUE, 6, 18,
+ "fate_option", "You can receive fates, good or bad" },
+
+ /* XXX 17 is used BEFORE */
+
+ /*** Stacking ***/
+
+ { &testing_stack, TRUE, 7, 0,
+ "testing_stack", "Allow objects to stack on floor" },
+
+ { &testing_carry, TRUE, 7, 1,
+ "testing_carry", "Allow monsters to carry objects" },
+
+
+ /*** End of Table ***/
+
+ { NULL, 0, 0, 0,
+ NULL, NULL }
+};
+
+
+cptr chaos_patrons[MAX_PATRON] =
+{
+ "Slortar",
+ "Mabelode",
+ "Chardros",
+ "Hionhurn",
+ "Xiombarg",
+
+ "Pyaray",
+ "Balaan",
+ "Arioch",
+ "Eequor",
+ "Narjhan",
+
+ "Balo",
+ "Khorne",
+ "Slaanesh",
+ "Nurgle",
+ "Tzeentch",
+
+ "Khaine"
+};
+
+int chaos_stats[MAX_PATRON] =
+{
+ A_CON, /* Slortar */
+ A_CON, /* Mabelode */
+ A_STR, /* Chardros */
+ A_STR, /* Hionhurn */
+ A_STR, /* Xiombarg */
+
+ A_INT, /* Pyaray */
+ A_STR, /* Balaan */
+ A_INT, /* Arioch */
+ A_CON, /* Eequor */
+ A_CHR, /* Narjhan */
+
+ -1, /* Balo */
+ A_STR, /* Khorne */
+ A_CHR, /* Slaanesh */
+ A_CON, /* Nurgle */
+ A_INT, /* Tzeentch */
+
+ A_STR, /* Khaine */
+};
+
+
+
+
+int chaos_rewards[MAX_PATRON][20] =
+{
+ /* Slortar the Old: */
+ {
+ REW_WRATH, REW_CURSE_WP, REW_CURSE_AR, REW_RUIN_ABL, REW_LOSE_ABL,
+ REW_IGNORE, REW_IGNORE, REW_IGNORE, REW_POLY_WND, REW_POLY_SLF,
+ REW_POLY_SLF, REW_POLY_SLF, REW_GAIN_ABL, REW_GAIN_ABL, REW_GAIN_EXP,
+ REW_GOOD_OBJ, REW_CHAOS_WP, REW_GREA_OBJ, REW_AUGM_ABL, REW_AUGM_ABL
+ },
+
+ /* Mabelode the Faceless: */
+ {
+ REW_WRATH, REW_CURSE_WP, REW_CURSE_AR, REW_H_SUMMON, REW_SUMMON_M,
+ REW_SUMMON_M, REW_IGNORE, REW_IGNORE, REW_POLY_WND, REW_POLY_WND,
+ REW_POLY_SLF, REW_HEAL_FUL, REW_HEAL_FUL, REW_GAIN_ABL, REW_SER_UNDE,
+ REW_CHAOS_WP, REW_GOOD_OBJ, REW_GOOD_OBJ, REW_GOOD_OBS, REW_GOOD_OBS
+ },
+
+ /* Chardros the Reaper: */
+ {
+ REW_WRATH, REW_WRATH, REW_HURT_LOT, REW_PISS_OFF, REW_H_SUMMON,
+ REW_SUMMON_M, REW_IGNORE, REW_IGNORE, REW_DESTRUCT, REW_SER_UNDE,
+ REW_GENOCIDE, REW_MASS_GEN, REW_MASS_GEN, REW_DISPEL_C, REW_GOOD_OBJ,
+ REW_CHAOS_WP, REW_GOOD_OBS, REW_GOOD_OBS, REW_AUGM_ABL, REW_AUGM_ABL
+ },
+
+ /* Hionhurn the Executioner: */
+ {
+ REW_WRATH, REW_WRATH, REW_CURSE_WP, REW_CURSE_AR, REW_RUIN_ABL,
+ REW_IGNORE, REW_IGNORE, REW_SER_UNDE, REW_DESTRUCT, REW_GENOCIDE,
+ REW_MASS_GEN, REW_MASS_GEN, REW_HEAL_FUL, REW_GAIN_ABL, REW_GAIN_ABL,
+ REW_CHAOS_WP, REW_GOOD_OBS, REW_GOOD_OBS, REW_AUGM_ABL, REW_AUGM_ABL
+ },
+
+ /* Xiombarg the Sword-Queen: */
+ {
+ REW_TY_CURSE, REW_TY_CURSE, REW_PISS_OFF, REW_RUIN_ABL, REW_LOSE_ABL,
+ REW_IGNORE, REW_POLY_SLF, REW_POLY_SLF, REW_POLY_WND, REW_POLY_WND,
+ REW_GENOCIDE, REW_DISPEL_C, REW_GOOD_OBJ, REW_GOOD_OBJ, REW_SER_MONS,
+ REW_GAIN_ABL, REW_CHAOS_WP, REW_GAIN_EXP, REW_AUGM_ABL, REW_GOOD_OBS
+ },
+
+
+ /* Pyaray the Tentacled Whisperer of Impossible Secretes: */
+ {
+ REW_WRATH, REW_TY_CURSE, REW_PISS_OFF, REW_H_SUMMON, REW_H_SUMMON,
+ REW_IGNORE, REW_IGNORE, REW_IGNORE, REW_POLY_WND, REW_POLY_SLF,
+ REW_POLY_SLF, REW_SER_DEMO, REW_HEAL_FUL, REW_GAIN_ABL, REW_GAIN_ABL,
+ REW_CHAOS_WP, REW_DO_HAVOC, REW_GOOD_OBJ, REW_GREA_OBJ, REW_GREA_OBS
+ },
+
+ /* Balaan the Grim: */
+ {
+ REW_TY_CURSE, REW_HURT_LOT, REW_CURSE_WP, REW_CURSE_AR, REW_RUIN_ABL,
+ REW_SUMMON_M, REW_LOSE_EXP, REW_POLY_SLF, REW_POLY_SLF, REW_POLY_WND,
+ REW_SER_UNDE, REW_HEAL_FUL, REW_HEAL_FUL, REW_GAIN_EXP, REW_GAIN_EXP,
+ REW_CHAOS_WP, REW_GOOD_OBJ, REW_GOOD_OBS, REW_GREA_OBS, REW_AUGM_ABL
+ },
+
+ /* Arioch, Duke of Hell: */
+ {
+ REW_WRATH, REW_PISS_OFF, REW_RUIN_ABL, REW_LOSE_EXP, REW_H_SUMMON,
+ REW_IGNORE, REW_IGNORE, REW_IGNORE, REW_IGNORE, REW_POLY_SLF,
+ REW_POLY_SLF, REW_MASS_GEN, REW_SER_DEMO, REW_HEAL_FUL, REW_CHAOS_WP,
+ REW_CHAOS_WP, REW_GOOD_OBJ, REW_GAIN_EXP, REW_GREA_OBJ, REW_AUGM_ABL
+ },
+
+ /* Eequor, Blue Lady of Dismay: */
+ {
+ REW_WRATH, REW_TY_CURSE, REW_PISS_OFF, REW_CURSE_WP, REW_RUIN_ABL,
+ REW_IGNORE, REW_IGNORE, REW_POLY_SLF, REW_POLY_SLF, REW_POLY_WND,
+ REW_GOOD_OBJ, REW_GOOD_OBJ, REW_SER_MONS, REW_HEAL_FUL, REW_GAIN_EXP,
+ REW_GAIN_ABL, REW_CHAOS_WP, REW_GOOD_OBS, REW_GREA_OBJ, REW_AUGM_ABL
+ },
+
+ /* Narjhan, Lord of Beggars: */
+ {
+ REW_WRATH, REW_CURSE_AR, REW_CURSE_WP, REW_CURSE_WP, REW_CURSE_AR,
+ REW_IGNORE, REW_IGNORE, REW_IGNORE, REW_POLY_SLF, REW_POLY_SLF,
+ REW_POLY_WND, REW_HEAL_FUL, REW_HEAL_FUL, REW_GAIN_EXP, REW_AUGM_ABL,
+ REW_GOOD_OBJ, REW_GOOD_OBJ, REW_CHAOS_WP, REW_GREA_OBJ, REW_GREA_OBS
+ },
+
+ /* Balo the Jester: */
+ {
+ REW_WRATH, REW_SER_DEMO, REW_CURSE_WP, REW_CURSE_AR, REW_LOSE_EXP,
+ REW_GAIN_ABL, REW_LOSE_ABL, REW_POLY_WND, REW_POLY_SLF, REW_IGNORE,
+ REW_DESTRUCT, REW_MASS_GEN, REW_CHAOS_WP, REW_GREA_OBJ, REW_HURT_LOT,
+ REW_AUGM_ABL, REW_RUIN_ABL, REW_H_SUMMON, REW_GREA_OBS, REW_AUGM_ABL
+ },
+
+ /* Khorne the Bloodgod: */
+ {
+ REW_WRATH, REW_HURT_LOT, REW_HURT_LOT, REW_H_SUMMON, REW_H_SUMMON,
+ REW_IGNORE, REW_IGNORE, REW_IGNORE, REW_SER_MONS, REW_SER_DEMO,
+ REW_POLY_SLF, REW_POLY_WND, REW_HEAL_FUL, REW_GOOD_OBJ, REW_GOOD_OBJ,
+ REW_CHAOS_WP, REW_GOOD_OBS, REW_GOOD_OBS, REW_GREA_OBJ, REW_GREA_OBS
+ },
+
+ /* Slaanesh: */
+ {
+ REW_WRATH, REW_PISS_OFF, REW_PISS_OFF, REW_RUIN_ABL, REW_LOSE_ABL,
+ REW_LOSE_EXP, REW_IGNORE, REW_IGNORE, REW_POLY_WND, REW_SER_DEMO,
+ REW_POLY_SLF, REW_HEAL_FUL, REW_HEAL_FUL, REW_GOOD_OBJ, REW_GAIN_EXP,
+ REW_GAIN_EXP, REW_CHAOS_WP, REW_GAIN_ABL, REW_GREA_OBJ, REW_AUGM_ABL
+ },
+
+ /* Nurgle: */
+ {
+ REW_WRATH, REW_PISS_OFF, REW_HURT_LOT, REW_RUIN_ABL, REW_LOSE_ABL,
+ REW_LOSE_EXP, REW_IGNORE, REW_IGNORE, REW_IGNORE, REW_POLY_SLF,
+ REW_POLY_SLF, REW_POLY_WND, REW_HEAL_FUL, REW_GOOD_OBJ, REW_GAIN_ABL,
+ REW_GAIN_ABL, REW_SER_UNDE, REW_CHAOS_WP, REW_GREA_OBJ, REW_AUGM_ABL
+ },
+
+ /* Tzeentch: */
+ {
+ REW_WRATH, REW_CURSE_WP, REW_CURSE_AR, REW_RUIN_ABL, REW_LOSE_ABL,
+ REW_LOSE_EXP, REW_IGNORE, REW_POLY_SLF, REW_POLY_SLF, REW_POLY_SLF,
+ REW_POLY_SLF, REW_POLY_WND, REW_HEAL_FUL, REW_CHAOS_WP, REW_GREA_OBJ,
+ REW_GAIN_ABL, REW_GAIN_ABL, REW_GAIN_EXP, REW_GAIN_EXP, REW_AUGM_ABL
+ },
+
+ /* Khaine: */
+ {
+ REW_WRATH, REW_HURT_LOT, REW_PISS_OFF, REW_LOSE_ABL, REW_LOSE_EXP,
+ REW_IGNORE, REW_IGNORE, REW_DISPEL_C, REW_DO_HAVOC, REW_DO_HAVOC,
+ REW_POLY_SLF, REW_POLY_SLF, REW_GAIN_EXP, REW_GAIN_ABL, REW_GAIN_ABL,
+ REW_SER_MONS, REW_GOOD_OBJ, REW_CHAOS_WP, REW_GREA_OBJ, REW_GOOD_OBS
+ }
+};
+
+/* Names used for random artifact name generation */
+cptr artifact_names_list =
+ "adanedhel\n"
+ "adurant\n"
+ "aeglos\n"
+ "aegnor\n"
+ "aelin\n"
+ "aeluin\n"
+ "aerandir\n"
+ "aerin\n"
+ "agarwaen\n"
+ "aglareb\n"
+ "aglarond\n"
+ "aglon\n"
+ "ainulindale\n"
+ "ainur\n"
+ "alcarinque\n"
+ "aldaron\n"
+ "aldudenie\n"
+ "almaren\n"
+ "alqualonde\n"
+ "aman\n"
+ "amandil\n"
+ "amarie\n"
+ "amarth\n"
+ "amlach\n"
+ "amon\n"
+ "amras\n"
+ "amrod\n"
+ "anach\n"
+ "anar\n"
+ "anarion\n"
+ "ancalagon\n"
+ "ancalimon\n"
+ "anarrima\n"
+ "andor\n"
+ "andram\n"
+ "androth\n"
+ "anduin\n"
+ "andunie\n"
+ "anfauglir\n"
+ "anfauglith\n"
+ "angainor\n"
+ "angband\n"
+ "anghabar\n"
+ "anglachel\n"
+ "angrenost\n"
+ "angrim\n"
+ "angrist\n"
+ "angrod\n"
+ "anguirel\n"
+ "annael\n"
+ "annatar\n"
+ "annon\n"
+ "annuminas\n"
+ "apanonar\n"
+ "aradan\n"
+ "aragorn\n"
+ "araman\n"
+ "aranel\n"
+ "aranruth\n"
+ "aranwe\n"
+ "aras\n"
+ "aratan\n"
+ "aratar\n"
+ "arathorn\n"
+ "arda\n"
+ "ard-galen\n"
+ "aredhel\n"
+ "ar-feiniel\n"
+ "argonath\n"
+ "arien\n"
+ "armenelos\n"
+ "arminas\n"
+ "arnor\n"
+ "aros\n"
+ "arossiach\n"
+ "arthad\n"
+ "arvernien\n"
+ "arwen\n"
+ "ascar\n"
+ "astaldo\n"
+ "atalante\n"
+ "atanamir\n"
+ "atanatari\n"
+ "atani\n"
+ "aule\n"
+ "avallone\n"
+ "avari\n"
+ "avathar\n"
+ "balan\n"
+ "balar\n"
+ "balrog\n"
+ "barad\n"
+ "baragund\n"
+ "barahir\n"
+ "baran\n"
+ "baranduin\n"
+ "bar\n"
+ "bauglir\n"
+ "beleg\n"
+ "belegaer\n"
+ "belegost\n"
+ "belegund\n"
+ "beleriand\n"
+ "belfalas\n"
+ "belthil\n"
+ "belthronding\n"
+ "beor\n"
+ "beraid\n"
+ "bereg\n"
+ "beren\n"
+ "boromir\n"
+ "boron\n"
+ "bragollach\n"
+ "brandir\n"
+ "bregolas\n"
+ "bregor\n"
+ "brethil\n"
+ "brilthor\n"
+ "brithiach\n"
+ "brithombar\n"
+ "brithon\n"
+ "cabed\n"
+ "calacirya\n"
+ "calaquendi\n"
+ "calenardhon\n"
+ "calion\n"
+ "camlost\n"
+ "caragdur\n"
+ "caranthir\n"
+ "carcharoth\n"
+ "cardolan\n"
+ "carnil\n"
+ "celeborn\n"
+ "celebrant\n"
+ "celebrimbor\n"
+ "celebrindal\n"
+ "celebros\n"
+ "celegorm\n"
+ "celon\n"
+ "cirdan\n"
+ "cirith\n"
+ "cirth\n"
+ "ciryatan\n"
+ "ciryon\n"
+ "coimas\n"
+ "corollaire\n"
+ "crissaegrim\n"
+ "cuarthal\n"
+ "cuivienen\n"
+ "culurien\n"
+ "curufin\n"
+ "curufinwe\n"
+ "curunir\n"
+ "cuthalion\n"
+ "daedeloth\n"
+ "daeron\n"
+ "dagnir\n"
+ "dagor\n"
+ "dagorlad\n"
+ "dairuin\n"
+ "danwedh\n"
+ "delduwath\n"
+ "denethor\n"
+ "dimbar\n"
+ "dimrost\n"
+ "dinen\n"
+ "dior\n"
+ "dirnen\n"
+ "dolmed\n"
+ "doriath\n"
+ "dorlas\n"
+ "dorthonion\n"
+ "draugluin\n"
+ "drengist\n"
+ "duath\n"
+ "duinath\n"
+ "duilwen\n"
+ "dunedain\n"
+ "dungortheb\n"
+ "earendil\n"
+ "earendur\n"
+ "earnil\n"
+ "earnur\n"
+ "earrame\n"
+ "earwen\n"
+ "echor\n"
+ "echoriath\n"
+ "ecthelion\n"
+ "edain\n"
+ "edrahil\n"
+ "eglador\n"
+ "eglarest\n"
+ "eglath\n"
+ "eilinel\n"
+ "eithel\n"
+ "ekkaia\n"
+ "elbereth\n"
+ "eldalie\n"
+ "eldalieva\n"
+ "eldamar\n"
+ "eldar\n"
+ "eledhwen\n"
+ "elemmire\n"
+ "elende\n"
+ "elendil\n"
+ "elendur\n"
+ "elenna\n"
+ "elentari\n"
+ "elenwe\n"
+ "elerrina\n"
+ "elleth\n"
+ "elmoth\n"
+ "elostirion\n"
+ "elrond\n"
+ "elros\n"
+ "elu\n"
+ "eluchil\n"
+ "elured\n"
+ "elurin\n"
+ "elwe\n"
+ "elwing\n"
+ "emeldir\n"
+ "endor\n"
+ "engrin\n"
+ "engwar\n"
+ "eol\n"
+ "eonwe\n"
+ "ephel\n"
+ "erchamion\n"
+ "ereb\n"
+ "ered\n"
+ "erech\n"
+ "eregion\n"
+ "ereinion\n"
+ "erellont\n"
+ "eressea\n"
+ "eriador\n"
+ "eru\n"
+ "esgalduin\n"
+ "este\n"
+ "estel\n"
+ "estolad\n"
+ "ethir\n"
+ "ezellohar\n"
+ "faelivrin\n"
+ "falas\n"
+ "falathar\n"
+ "falathrim\n"
+ "falmari\n"
+ "faroth\n"
+ "fauglith\n"
+ "feanor\n"
+ "feanturi\n"
+ "felagund\n"
+ "finarfin\n"
+ "finduilas\n"
+ "fingolfin\n"
+ "fingon\n"
+ "finwe\n"
+ "firimar\n"
+ "formenos\n"
+ "fornost\n"
+ "frodo\n"
+ "fuin\n"
+ "fuinur\n"
+ "gabilgathol\n"
+ "galad\n"
+ "galadriel\n"
+ "galathilion\n"
+ "galdor\n"
+ "galen\n"
+ "galvorn\n"
+ "gandalf\n"
+ "gaurhoth\n"
+ "gelion\n"
+ "gelmir\n"
+ "gelydh\n"
+ "gil\n"
+ "gildor\n"
+ "giliath\n"
+ "ginglith\n"
+ "girith\n"
+ "glaurung\n"
+ "glingal\n"
+ "glirhuin\n"
+ "gloredhel\n"
+ "glorfindel\n"
+ "golodhrim\n"
+ "gondolin\n"
+ "gondor\n"
+ "gonnhirrim\n"
+ "gorgoroth\n"
+ "gorlim\n"
+ "gorthaur\n"
+ "gorthol\n"
+ "gothmog\n"
+ "guilin\n"
+ "guinar\n"
+ "guldur\n"
+ "gundor\n"
+ "gurthang\n"
+ "gwaith\n"
+ "gwareth\n"
+ "gwindor\n"
+ "hadhodrond\n"
+ "hador\n"
+ "haladin\n"
+ "haldad\n"
+ "haldan\n"
+ "haldar\n"
+ "haldir\n"
+ "haleth\n"
+ "halmir\n"
+ "handir\n"
+ "harad\n"
+ "hareth\n"
+ "hathaldir\n"
+ "hathol\n"
+ "haudh\n"
+ "helcar\n"
+ "helcaraxe\n"
+ "helevorn\n"
+ "helluin\n"
+ "herumor\n"
+ "herunumen\n"
+ "hildorien\n"
+ "himlad\n"
+ "himring\n"
+ "hirilorn\n"
+ "hisilome\n"
+ "hithaeglir\n"
+ "hithlum\n"
+ "hollin\n"
+ "huan\n"
+ "hunthor\n"
+ "huor\n"
+ "hurin\n"
+ "hyarmendacil\n"
+ "hyarmentir\n"
+ "iant\n"
+ "iaur\n"
+ "ibun\n"
+ "idril\n"
+ "illuin\n"
+ "ilmare\n"
+ "ilmen\n"
+ "iluvatar\n"
+ "imlach\n"
+ "imladris\n"
+ "indis\n"
+ "ingwe\n"
+ "irmo\n"
+ "isil\n"
+ "isildur\n"
+ "istari\n"
+ "ithil\n"
+ "ivrin\n"
+ "kelvar\n"
+ "kementari\n"
+ "ladros\n"
+ "laiquendi\n"
+ "lalaith\n"
+ "lamath\n"
+ "lammoth\n"
+ "lanthir\n"
+ "laurelin\n"
+ "leithian\n"
+ "legolin\n"
+ "lembas\n"
+ "lenwe\n"
+ "linaewen\n"
+ "lindon\n"
+ "lindorie\n"
+ "loeg\n"
+ "lomelindi\n"
+ "lomin\n"
+ "lomion\n"
+ "lorellin\n"
+ "lorien\n"
+ "lorindol\n"
+ "losgar\n"
+ "lothlann\n"
+ "lothlorien\n"
+ "luin\n"
+ "luinil\n"
+ "lumbar\n"
+ "luthien\n"
+ "mablung\n"
+ "maedhros\n"
+ "maeglin\n"
+ "maglor\n"
+ "magor\n"
+ "mahanaxar\n"
+ "mahtan\n"
+ "maiar\n"
+ "malduin\n"
+ "malinalda\n"
+ "mandos\n"
+ "manwe\n"
+ "mardil\n"
+ "melian\n"
+ "melkor\n"
+ "menegroth\n"
+ "meneldil\n"
+ "menelmacar\n"
+ "meneltarma\n"
+ "minas\n"
+ "minastir\n"
+ "mindeb\n"
+ "mindolluin\n"
+ "mindon\n"
+ "minyatur\n"
+ "mirdain\n"
+ "miriel\n"
+ "mithlond\n"
+ "mithrandir\n"
+ "mithrim\n"
+ "mordor\n"
+ "morgoth\n"
+ "morgul\n"
+ "moria\n"
+ "moriquendi\n"
+ "mormegil\n"
+ "morwen\n"
+ "nahar\n"
+ "naeramarth\n"
+ "namo\n"
+ "nandor\n"
+ "nargothrond\n"
+ "narog\n"
+ "narsil\n"
+ "narsilion\n"
+ "narya\n"
+ "nauglamir\n"
+ "naugrim\n"
+ "ndengin\n"
+ "neithan\n"
+ "neldoreth\n"
+ "nenar\n"
+ "nenning\n"
+ "nenuial\n"
+ "nenya\n"
+ "nerdanel\n"
+ "nessa\n"
+ "nevrast\n"
+ "nibin\n"
+ "nienna\n"
+ "nienor\n"
+ "nimbrethil\n"
+ "nimloth\n"
+ "nimphelos\n"
+ "nimrais\n"
+ "nimras\n"
+ "ningloron\n"
+ "niniel\n"
+ "ninniach\n"
+ "ninquelote\n"
+ "niphredil\n"
+ "nirnaeth\n"
+ "nivrim\n"
+ "noegyth\n"
+ "nogrod\n"
+ "noldolante\n"
+ "noldor\n"
+ "numenor\n"
+ "nurtale\n"
+ "obel\n"
+ "ohtar\n"
+ "oiolosse\n"
+ "oiomure\n"
+ "olorin\n"
+ "olvar\n"
+ "olwe\n"
+ "ondolinde\n"
+ "orfalch\n"
+ "ormal\n"
+ "orocarni\n"
+ "orodreth\n"
+ "orodruin\n"
+ "orome\n"
+ "oromet\n"
+ "orthanc\n"
+ "osgiliath\n"
+ "osse\n"
+ "ossiriand\n"
+ "palantir\n"
+ "pelargir\n"
+ "pelori\n"
+ "periannath\n"
+ "quendi\n"
+ "quenta\n"
+ "quenya\n"
+ "radagast\n"
+ "radhruin\n"
+ "ragnor\n"
+ "ramdal\n"
+ "rana\n"
+ "rathloriel\n"
+ "rauros\n"
+ "region\n"
+ "rerir\n"
+ "rhovanion\n"
+ "rhudaur\n"
+ "rhun\n"
+ "rhunen\n"
+ "rian\n"
+ "ringil\n"
+ "ringwil\n"
+ "romenna\n"
+ "rudh\n"
+ "rumil\n"
+ "saeros\n"
+ "salmar\n"
+ "saruman\n"
+ "sauron\n"
+ "serech\n"
+ "seregon\n"
+ "serinde\n"
+ "shelob\n"
+ "silmarien\n"
+ "silmaril\n"
+ "silpion\n"
+ "sindar\n"
+ "singollo\n"
+ "sirion\n"
+ "soronume\n"
+ "sul\n"
+ "sulimo\n"
+ "talath\n"
+ "taniquetil\n"
+ "tar\n"
+ "taras\n"
+ "tarn\n"
+ "tathren\n"
+ "taur\n"
+ "tauron\n"
+ "teiglin\n"
+ "telchar\n"
+ "telemnar\n"
+ "teleri\n"
+ "telperion\n"
+ "telumendil\n"
+ "thalion\n"
+ "thalos\n"
+ "thangorodrim\n"
+ "thargelion\n"
+ "thingol\n"
+ "thoronath\n"
+ "thorondor\n"
+ "thranduil\n"
+ "thuringwethil\n"
+ "tilion\n"
+ "tintalle\n"
+ "tinuviel\n"
+ "tirion\n"
+ "tirith\n"
+ "tol\n"
+ "tulkas\n"
+ "tumhalad\n"
+ "tumladen\n"
+ "tuna\n"
+ "tuor\n"
+ "turambar\n"
+ "turgon\n"
+ "turin\n"
+ "uial\n"
+ "uilos\n"
+ "uinen\n"
+ "ulairi\n"
+ "ulmo\n"
+ "ulumuri\n"
+ "umanyar\n"
+ "umarth\n"
+ "umbar\n"
+ "ungoliant\n"
+ "urthel\n"
+ "uruloki\n"
+ "utumno\n"
+ "vaire\n"
+ "valacirca\n"
+ "valandil\n"
+ "valaquenta\n"
+ "valar\n"
+ "valaraukar\n"
+ "valaroma\n"
+ "valier\n"
+ "valimar\n"
+ "valinor\n"
+ "valinoreva\n"
+ "valmar\n"
+ "vana\n"
+ "vanyar\n"
+ "varda\n"
+ "vasa\n"
+ "vilya\n"
+ "vingilot\n"
+ "vinyamar\n"
+ "voronwe\n"
+ "wethrin\n"
+ "wilwarin\n"
+ "yavanna\n"
+ ;
+
+
+martial_arts ma_blows[MAX_MA] =
+{
+ { "You punch %s.", 1, 0, 2, 4, 0, 0 },
+ { "You kick %s.", 2, 0, 2, 6, 0, 0 },
+ { "You strike %s.", 3, 0, 2, 7, 0, 0 },
+ { "You hit %s with your knee.", 5, 5, 4, 3, MA_KNEE, 0 },
+ { "You hit %s with your elbow.", 7, 5, 2, 8, 0, 0 },
+ { "You butt %s.", 9, 10, 4, 5, 0, 0 },
+ { "You kick %s.", 11, 10, 6, 4, MA_SLOW, 0 },
+ { "You uppercut %s.", 13, 12, 8, 4, MA_STUN, 6 },
+ { "You double-kick %s.", 16, 15, 10, 4, MA_STUN, 8 },
+ { "You hit %s with a Cat's Claw.", 20, 20, 10, 5, 0, 0 },
+ { "You hit %s with a jump kick.", 25, 25, 10, 6, MA_STUN, 10 },
+ { "You hit %s with an Eagle's Claw.", 29, 25, 12, 6, 0, 0 },
+ { "You hit %s with a circle kick.", 33, 30, 12, 8, MA_STUN, 10 },
+ { "You hit %s with an Iron Fist.", 37, 35, 16, 8, MA_STUN, 10 },
+ { "You hit %s with a flying kick.", 41, 35, 16, 10, MA_STUN, 12 },
+ { "You hit %s with a Dragon Fist.", 45, 35, 20, 10, MA_STUN, 16 },
+ { "You hit %s with a Crushing Blow.", 48, 35, 20, 12, MA_STUN, 18 },
+};
+
+/*
+ * cptr desc; A verbose attack description
+ * int min_level; Minimum level to use
+ * int chance; Chance of 'success
+ * int dd; Damage dice
+ * int ds; Damage sides
+ * s16b effect; Special effects
+ * s16b power; Special effects power
+ */
+martial_arts bear_blows[MAX_BEAR] =
+{
+ { "You claw %s.", 1, 0, 3, 4, MA_STUN, 4 },
+ { "You swat %s.", 4, 0, 4, 4, MA_WOUND, 20 },
+ { "You bite %s.", 9, 2, 4, 4, MA_WOUND, 30 },
+ { "You hug %s.", 15, 5, 6, 4, MA_FULL_SLOW, 0 },
+ { "You swat and rake %s.", 25, 10, 6, 5, MA_STUN | MA_WOUND, 10 },
+ { "You hug and claw %s.", 30, 15, 6, 6, MA_FULL_SLOW | MA_WOUND, 60 },
+ { "You double swat %s.", 35, 20, 9, 7, MA_STUN | MA_WOUND, 20 },
+ { "You double swat and rake %s.", 40, 25, 10, 10, MA_STUN | MA_WOUND, 25 },
+};
+
+
+magic_power mindcraft_powers[MAX_MINDCRAFT_POWERS] =
+{
+ /* Level gained, cost, %fail, name, desc */
+ {
+ /* Det. monsters/traps */
+ 1, 1, 15,
+ "Precognition",
+ "Detect monsters, traps and level layout and lights up at higher levels."
+ },
+ {
+ /* ~MM */
+ 2, 1, 20,
+ "Neural Blast",
+ "Blast the minds of your foes."
+ },
+ {
+ /* Phase/Between gate */
+ 3, 2, 25,
+ "Minor Displacement",
+ "Short distance teleportation"
+ },
+ {
+ /* Tele. Self / All */
+ 7, 6, 35,
+ "Major Displacement",
+ "Teleport you and others at high levels."
+ },
+ {
+ 9, 7, 50,
+ "Domination",
+ "Charm monsters"
+ },
+ {
+ /* Telekinetic "bolt" */
+ 11, 7, 30,
+ "Pulverise",
+ "Fires a bolt of pure sound."
+ },
+ {
+ /* Psychic/physical defenses */
+ 13, 12, 50,
+ "Character Armour",
+ "Sets up physical/elemental shield."
+ },
+ {
+ 15, 12, 60,
+ "Psychometry",
+ "Identifies objects."
+ },
+ {
+ /* Ball -> LOS */
+ 18, 10, 45,
+ "Mind Wave",
+ "Projects psi waves to crush the minds of your foes."
+ },
+ {
+ 23, 15, 50,
+ "Adrenaline Channeling",
+ "Heals you, cures you and speeds you."
+ },
+ {
+ /* Convert enemy HP to mana */
+ 25, 10, 40,
+ "Psychic Drain",
+ "Drain your foes' life into your mana reserves"
+ },
+ {
+ /* Ball -> LOS */
+ 28, 20, 45,
+ "Telekinetic Wave",
+ "Powerful wave of pure telekinetic forces."
+ },
+ };
+
+ magic_power necro_powers[MAX_NECRO_POWERS] =
+ {
+ /* Level gained, cost, %fail, name, desc */
+ {
+ /* Bolt/beam/ball/LOS of stun/scare */
+ 1, 2, 10,
+ "Horrify",
+ "Calls upon the darkness to stun and scare your foes."
+ },
+ {
+ /* Ball */
+ 5, 6, 20,
+ "Raise Dead",
+ "Brings back your foes in the form of various undead. Also, can heal monsters."
+ },
+ {
+ /* Summons weapon */
+ 12, 20, 25,
+ "Necromantic Teeth",
+ "Conjures a temporary vampiric weapon."
+ },
+ {
+ /* Heals when killing a monster */
+ 20, 10, 25,
+ "Absorb Soul",
+ "Gives back some life for each kill."
+ },
+ {
+ /* Bolt */
+ 30, 15, 20,
+ "Vampirism",
+ "Drain the life of your foes into your own."
+ },
+ {
+ /* The Death word, always bolt put your HP to 1 */
+ 35, 100, 25,
+ "Death",
+ "Instantly kills your opponent and you, turning yourself into an undead."
+ },
+};
+
+magic_power mimic_powers[MAX_MIMIC_POWERS] =
+{
+ /* Level gained, cost, %fail, name */
+ {
+ /* Use a book of lore */
+ 1, 2, 0,
+ "Mimic",
+ "Lets you use the powers of a Cloak of Mimicry."
+ },
+ {
+ /* Invisibility */
+ 10, 6, 20,
+ "Invisibility",
+ "Hides you from the sight of mortals."
+ },
+ {
+ /* +1 pair of legs */
+ 25, 20, 25,
+ "Legs Mimicry",
+ "Temporarily provides a new pair of legs."
+ },
+ {
+ /* wall form */
+ 30, 40, 30,
+ "Wall Mimicry",
+ "Temporarily lets you walk in walls, and ONLY in walls."
+ },
+ {
+ /* +1 pair of arms, +1 weapon */
+ 35, 100, 40,
+ "Arms Mimicry",
+ "Temporarily provides a new pair of arms."
+ },
+};
+
+magic_power symbiotic_powers[MAX_SYMBIOTIC_POWERS] =
+{
+ /* Level gained, cost, %fail, name */
+ {
+ 1, 1, 0,
+ "Hypnotise",
+ "Hypnotise a non-moving pet to allow you to enter symbiosis(wear) with it."
+ },
+ {
+ 1, 1, 0,
+ "Release",
+ "Release an hypnotised pet."
+ },
+ {
+ 3, 2, 10,
+ "Charm Never-Moving",
+ "Tries to charm a never-moving monster."
+ },
+ {
+ 5, 5, 20,
+ "Life Share",
+ "Evens out your life with your symbiote."
+ },
+ {
+ 10, 10, 20,
+ "Use Minor Powers",
+ "Allows you to use some of the powers of your symbiote."
+ },
+ {
+ 15, 14, 25,
+ "Heal Symbiote",
+ "Heals your symbiotic monster."
+ },
+ {
+ 25, 30, 40,
+ "Use major powers",
+ "Allows you to use all the powers of your symbiote."
+ },
+ {
+ 30, 35, 40,
+ "Summon Never-Moving Pet",
+ "Summons a never-moving pet."
+ },
+ {
+ 40, 60, 70,
+ "Force Symbiosis",
+ "Allows you to use all the powers of a monster in your line of sight."
+ },
+};
+
+
+/*
+ * Textual translation of your god's "niceness".
+ */
+
+cptr deity_niceness[10] =
+{
+ "a lovable deity",
+ "a friendly deity",
+ "an easygoing deity",
+ "a forgiving deity",
+ "an uncaring deity",
+ "a wary deity",
+ "an unforgiving deity",
+ "an impatient deity",
+ "a wrathful deity",
+ "an easily angered deity"
+};
+
+/*
+ * Textual translation of your standing with your god.
+ */
+
+cptr deity_standing[11] =
+{
+ "cursed",
+ "persecuted",
+ "punished",
+ "despised",
+ "disliked",
+ "watched",
+ "unnoticed",
+ "noticed",
+ "rewarded",
+ "favored",
+ "championed"
+};
+
+/*
+ * Name and description (max. 10 lines) of the gods.
+ * Only the first four lines are printed at birth.
+ */
+
+deity_type deity_info_init[MAX_GODS_INIT] =
+{
+ {
+ "Nobody",
+ {
+ "Atheist",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ "Eru Iluvatar",
+ {
+ "He is the supreme god, he created the world, and most of its inhabitants.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ "Manwe Sulimo",
+ {
+ "He is the king of the Valar, most powerful of them after Melkor.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ "Tulkas",
+ {
+ "He is the last of the Valar that came to the world, and the fiercest fighter.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ "Melkor Bauglir",
+ {
+ "He is the most powerful of the Valar. He became corrupted and he's now ",
+ "the greatest threat of Arda, he is also known as Morgoth, the dark enemy.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+ {
+ "Yavanna Kementari",
+ {
+ "She is the Vala of nature, protectress of the great forests of "
+ "Middle-earth.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ },
+};
+
+/* jk - to hit, to dam, to ac, to stealth, to disarm, to saving throw */
+/* this concept is taken from Adom, where Thomas Biskup thought it out, */
+/* as far as I know. */
+tactic_info_type tactic_info[9] =
+{
+ /* hit dam ac stl dis sav */
+ { -10, -10, + 15, + 3, + 15, + 14, "coward"}, /* 4-4 */
+ { -8, -8, + 10, + 2, + 9, + 9, "meek"}, /* 4-3 */
+ { -4, -4, + 5, + 1, + 5, + 5, "wary"}, /* 4-2 */
+ { -2, -2, + 2, + 1, + 2, + 2, "careful"}, /* 4-1 */
+ { 0, 0, 0, 0, 0, 0, "normal"}, /* 4+0 */
+ { 2, 2, -2, -1, -2, -3, "confident"}, /* 4+1 */
+ { 4, 4, -5, -2, -5, -7, "aggressive"}, /* 4+2 */
+ { 6, 6, -10, -3, -11, -12, "furious"}, /* 4+3 */
+ { 8, 12, -25, -5, -18, -18, "berserker"} /* 4+4 */
+};
+
+/*
+ * Random artifact activations.
+ */
+activation activation_info[MAX_T_ACT] =
+{
+ { "death", 0, ACT_DEATH },
+ { "ruination", 0, ACT_RUINATION },
+ { "destruction", 1000, ACT_DESTRUC },
+ { "stupidity", 0, ACT_UNINT },
+ { "weakness", 0, ACT_UNSTR },
+ { "unhealth", 0, ACT_UNCON },
+ { "ugliness", 0, ACT_UNCHR },
+ { "clumsiness", 0, ACT_UNDEX },
+ { "naivete", 0, ACT_UNWIS },
+ { "stat loss", 0, ACT_STATLOSS },
+ { "huge stat loss", 0, ACT_HISTATLOSS },
+ { "experience loss", 0, ACT_EXPLOSS },
+ { "huge experience loss", 0, ACT_HIEXPLOSS },
+ { "teleportation", 1000, ACT_TELEPORT },
+ { "monster summoning", 5, ACT_SUMMON_MONST },
+ { "paralyzation", 0, ACT_PARALYZE },
+ { "hallucination", 100, ACT_HALLU },
+ { "poisoning", 0, ACT_POISON },
+ { "hunger", 0, ACT_HUNGER },
+ { "stun", 0, ACT_STUN },
+ { "cuts", 0, ACT_CUTS },
+ { "paranoia", 0, ACT_PARANO },
+ { "confusion", 0, ACT_CONFUSION },
+ { "blindness", 0, ACT_BLIND },
+ { "pet summoning", 1010, ACT_PET_SUMMON },
+ { "cure paralyzation", 5000, ACT_CURE_PARA },
+ { "cure hallucination", 1000, ACT_CURE_HALLU },
+ { "cure poison", 1000, ACT_CURE_POIS },
+ { "cure hunger", 1000, ACT_CURE_HUNGER },
+ { "cure stun", 1000, ACT_CURE_STUN },
+ { "cure cut", 1000, ACT_CURE_CUTS },
+ { "cure fear", 1000, ACT_CURE_FEAR },
+ { "cure confusion", 1000, ACT_CURE_CONF },
+ { "cure blindness", 1000, ACT_CURE_BLIND },
+ { "cure light wounds", 500, ACT_CURE_LW },
+ { "cure serious wounds", 750, ACT_CURE_MW },
+ { "cure critical wounds", 1000, ACT_CURE_700 },
+ { "curing", 1100, ACT_CURING },
+ { "genocide", 5000, ACT_GENOCIDE },
+ { "mass genocide", 10000, ACT_MASS_GENO },
+ { "restoration", 2000, ACT_REST_ALL },
+ { "light", 1000, ACT_LIGHT },
+ { "darkness", 0, ACT_DARKNESS },
+ { "teleportation", 1000, ACT_TELEPORT },
+ { "level teleportation", 500, ACT_LEV_TELE },
+ { "acquirement", 30000, ACT_ACQUIREMENT },
+ { "something weird", 50, ACT_WEIRD },
+ { "aggravation", 0, ACT_AGGRAVATE },
+ { "corruption", 100, ACT_MUT },
+ { "cure insanity", 2000, ACT_CURE_INSANITY },
+ { "light absortion", 800, ACT_LIGHT_ABSORBTION },
+};
+
+/*
+ * Possible movement type.
+ */
+move_info_type move_info[9] =
+{
+ /* speed, searching, stealth, perception */
+ { -10, 17, 4, 20, "slug-like"},
+ { -8, 12, 4, 16, "very slow"},
+ { -6, 8, 3, 10, "slow"},
+ { -3, 4, 2, 6, "leisurely"},
+ { 0, 0, 0, 0, "normal"},
+ { 1, -4, -1, -4, "brisk"},
+ { 2, -6, -4, -8, "fast"},
+ { 3, -10, -7, -14, "very fast"},
+ { 4, -16, -10, -20, "running"}
+};
+
+/*
+ * Possible inscriptions type.
+ */
+inscription_info_type inscription_info[MAX_INSCRIPTIONS] =
+{
+ { /* Nothing */
+ "",
+ 0,
+ TRUE,
+ 0,
+ },
+ { /* Light up the room(Adunaic) */
+ "ure nimir", /* sun shine */
+ INSCRIP_EXEC_ENGRAVE | INSCRIP_EXEC_WALK | INSCRIP_EXEC_MONST_WALK,
+ FALSE,
+ 30,
+ },
+ { /* Darkness in room(Adunaic) */
+ "lomi gimli", /* night stars */
+ INSCRIP_EXEC_ENGRAVE | INSCRIP_EXEC_WALK | INSCRIP_EXEC_MONST_WALK,
+ FALSE,
+ 10,
+ },
+ { /* Storm(Adunaic) */
+ "dulgi bawiba", /* black winds */
+ INSCRIP_EXEC_ENGRAVE | INSCRIP_EXEC_WALK | INSCRIP_EXEC_MONST_WALK,
+ FALSE,
+ 40,
+ },
+ { /* Protection(Sindarin) */
+ "pedo mellon a minno", /* say friend and enter */
+ INSCRIP_EXEC_MONST_WALK,
+ FALSE,
+ 8,
+ },
+ { /* Dwarves summoning(Khuzdul) */
+ "Baruk Khazad! Khazad aimenu!", /* Axes of the Dwarves, the Dwarves are upon you! */
+ INSCRIP_EXEC_ENGRAVE,
+ FALSE,
+ 100,
+ },
+ { /* Open Chasm(Nandorin) */
+ "dunna hrassa", /* black precipice */
+ INSCRIP_EXEC_MONST_WALK,
+ FALSE,
+ 50,
+ },
+ { /* Blast of Black Fire(Orcish) */
+ "burz ghash ronk", /* black fire pool */
+ INSCRIP_EXEC_ENGRAVE | INSCRIP_EXEC_WALK | INSCRIP_EXEC_MONST_WALK,
+ FALSE,
+ 60,
+ },
+};
+
+/*
+ * Inscriptions for pseudo-id
+ */
+cptr sense_desc[] =
+{
+ "whoops",
+ "cursed",
+ "average",
+ "good",
+ "good",
+ "excellent",
+ "worthless",
+ "terrible",
+ "special",
+ "broken",
+ ""
+};
+
+/*
+ * Flag groups used for art creation, level gaining weapons, ...
+ * -----
+ * Name,
+ * Price,
+ * Flags 1,
+ * Flags 2,
+ * Flags 3,
+ * Flags 4,
+ * ESP,
+ */
+flags_group flags_groups[MAX_FLAG_GROUP] =
+{
+ {
+ "Fire",
+ TERM_L_RED,
+ 1,
+ TR1_SLAY_UNDEAD | TR1_BRAND_FIRE,
+ TR2_RES_FIRE,
+ TR3_SH_FIRE | TR3_LITE1 | TR3_IGNORE_FIRE,
+ 0,
+ 0,
+ },
+ {
+ "Cold",
+ TERM_WHITE,
+ 1,
+ TR1_SLAY_DRAGON | TR1_SLAY_DEMON | TR1_BRAND_COLD,
+ TR2_RES_COLD | TR2_INVIS,
+ TR3_SLOW_DIGEST | TR3_IGNORE_COLD,
+ 0,
+ 0,
+ },
+ {
+ "Acid",
+ TERM_GREEN,
+ 3,
+ TR1_SLAY_ANIMAL | TR1_IMPACT | TR1_TUNNEL | TR1_BRAND_ACID,
+ TR2_RES_ACID,
+ TR3_IGNORE_ACID,
+ 0,
+ 0,
+ },
+ {
+ "Lightning",
+ TERM_L_BLUE,
+ 1,
+ TR1_SLAY_EVIL | TR1_BRAND_ELEC,
+ TR2_RES_ELEC,
+ TR3_IGNORE_ELEC | TR3_SH_ELEC | TR3_TELEPORT,
+ 0,
+ 0,
+ },
+ {
+ "Poison",
+ TERM_L_GREEN,
+ 2,
+ TR1_CHR | TR1_VAMPIRIC | TR1_SLAY_ANIMAL | TR1_BRAND_POIS,
+ TR2_SUST_CHR | TR2_RES_POIS,
+ TR3_DRAIN_EXP,
+ 0,
+ ESP_TROLL | ESP_GIANT,
+ },
+ {
+ "Air",
+ TERM_BLUE,
+ 5,
+ TR1_WIS | TR1_STEALTH | TR1_INFRA | TR1_SPEED,
+ TR2_RES_LITE | TR2_RES_DARK | TR2_RES_BLIND | TR2_SUST_WIS,
+ TR3_FEATHER | TR3_SEE_INVIS | TR3_BLESSED,
+ 0,
+ ESP_GOOD,
+ },
+ {
+ "Earth",
+ TERM_L_UMBER,
+ 5,
+ TR1_STR | TR1_CON | TR1_TUNNEL | TR1_BLOWS | TR1_SLAY_TROLL | TR1_SLAY_GIANT | TR1_IMPACT,
+ TR2_SUST_STR | TR2_SUST_CON | TR2_FREE_ACT | TR2_RES_FEAR | TR2_RES_SHARDS,
+ TR3_REGEN,
+ 0,
+ ESP_TROLL | ESP_GIANT,
+ },
+ {
+ "Mind",
+ TERM_YELLOW,
+ 7,
+ TR1_INT | TR1_SEARCH,
+ TR2_SUST_INT | TR2_RES_CONF | TR2_RES_FEAR,
+ 0,
+ 0,
+ ESP_ORC | ESP_TROLL | ESP_GIANT | ESP_ANIMAL | ESP_UNIQUE | ESP_SPIDER | ESP_DEMON,
+ },
+ {
+ "Shield",
+ TERM_RED,
+ 7,
+ TR1_DEX,
+ TR2_SUST_DEX | TR2_INVIS | TR2_REFLECT | TR2_HOLD_LIFE | TR2_RES_SOUND | TR2_RES_NEXUS,
+ TR3_REGEN,
+ 0,
+ 0,
+ },
+ {
+ "Chaos",
+ TERM_VIOLET,
+ 7,
+ TR1_CHAOTIC | TR1_IMPACT,
+ TR2_RES_CHAOS | TR2_RES_DISEN,
+ TR3_REGEN,
+ 0,
+ ESP_ALL,
+ },
+ {
+ "Magic",
+ TERM_L_BLUE,
+ 10,
+ TR1_MANA | TR1_SPELL,
+ TR2_RES_CHAOS | TR2_RES_DISEN,
+ TR3_WRAITH,
+ TR4_PRECOGNITION | TR4_FLY | TR4_CLONE,
+ 0,
+ },
+ {
+ "Antimagic",
+ TERM_L_DARK,
+ 10,
+ TR1_VAMPIRIC | TR1_CHAOTIC | TR1_BLOWS | TR1_SPEED,
+ TR2_LIFE | TR2_REFLECT | TR2_FREE_ACT | TR2_HOLD_LIFE,
+ TR3_NO_MAGIC | TR3_NO_TELE | TR3_SEE_INVIS,
+ TR4_ANTIMAGIC_10 | TR4_ANTIMAGIC_20,
+ 0,
+ },
+};
+
+/* Powers */
+power_type powers_type_init[POWER_MAX_INIT] =
+{
+ {
+ "spit acid",
+ "You can spit acid.",
+ "You gain the ability to spit acid.",
+ "You lose the ability to spit acid.",
+ 9, 9, A_DEX, 15,
+ },
+ {
+ "fire breath",
+ "You can breath fire.",
+ "You gain the ability to breathe fire.",
+ "You lose the ability to breathe fire.",
+ 20, 10, A_CON, 18,
+ },
+ {
+ "hypnotic gaze",
+ "Your gaze is hypnotic.",
+ "Your eyes look mesmerising...",
+ "Your eyes look uninteresting.",
+ 12, 12, A_CHR, 18,
+ },
+ {
+ "telekinesis",
+ "You are telekinetic.",
+ "You gain the ability to move objects telekinetically.",
+ "You lose the ability to move objects telekinetically.",
+ 9, 9, A_WIS, 14,
+ },
+ {
+ "teleport",
+ "You can teleport at will.",
+ "You gain the power of teleportation at will.",
+ "You lose the power of teleportation at will.",
+ 7, 7, A_WIS, 15,
+ },
+ {
+ "mind blast",
+ "You can mind blast your enemies.",
+ "You gain the power of Mind Blast.",
+ "You lose the power of Mind Blast.",
+ 5, 3, A_WIS, 15,
+ },
+ {
+ "emit radiation",
+ "You can emit hard radiation at will.",
+ "You start emitting hard radiation.",
+ "You stop emitting hard radiation.",
+ 15, 15, A_CON, 14,
+ },
+ {
+ "vampiric drain",
+ "You can drain life from a foe.",
+ "You become vampiric.",
+ "You are no longer vampiric.",
+ 4, 5, A_CON, 9,
+ },
+ {
+ "smell metal",
+ "You can smell nearby precious metal.",
+ "You smell a metallic odour.",
+ "You no longer smell a metallic odour.",
+ 3, 2, A_INT, 12,
+ },
+ {
+ "smell monsters",
+ "You can smell nearby monsters.",
+ "You smell filthy monsters.",
+ "You no longer smell filthy monsters.",
+ 5, 4, A_INT, 15,
+ },
+ {
+ "blink",
+ "You can teleport yourself short distances.",
+ "You gain the power of minor teleportation.",
+ "You lose the power of minor teleportation.",
+ 3, 3, A_WIS, 12,
+ },
+ {
+ "eat rock",
+ "You can consume solid rock.",
+ "The walls look delicious.",
+ "The walls look unappetising.",
+ 8, 12, A_CON, 18,
+ },
+ {
+ "swap position",
+ "You can switch locations with another being.",
+ "You feel like walking a mile in someone else's shoes.",
+ "You feel like staying in your own shoes.",
+ 15, 12, A_DEX, 16,
+ },
+ {
+ "shriek",
+ "You can emit a horrible shriek.",
+ "Your vocal cords get much tougher.",
+ "Your vocal cords get much weaker.",
+ 4, 4, A_CON, 6,
+ },
+ {
+ "illuminate",
+ "You can emit bright light.",
+ "You can light up rooms with your presence.",
+ "You can no longer light up rooms with your presence.",
+ 3, 2, A_INT, 10,
+ },
+ {
+ "detect curses",
+ "You can feel the danger of evil magic.",
+ "You can feel evil magic.",
+ "You can no longer feel evil magic.",
+ 7, 14, A_WIS, 14,
+ },
+ {
+ "berserk",
+ "You can drive yourself into a berserk frenzy.",
+ "You feel a controlled rage.",
+ "You no longer feel a controlled rage.",
+ 8, 8, A_STR, 14,
+ },
+ {
+ "polymorph",
+ "You can polymorph yourself at will.",
+ "Your body seems mutable.",
+ "Your body seems stable.",
+ 18, 20, A_CON, 18,
+ },
+ {
+ "Midas touch",
+ "You can turn ordinary items to gold.",
+ "You gain the Midas touch.",
+ "You lose the Midas touch.",
+ 10, 5, A_INT, 12,
+ },
+ {
+ "grow mold",
+ "You can cause mold to grow near you.",
+ "You feel a sudden affinity for mold.",
+ "You feel a sudden dislike for mold.",
+ 1, 6, A_CON, 14,
+ },
+ {
+ "resist elements",
+ "You can harden yourself to the ravages of the elements.",
+ "You feel like you can protect yourself.",
+ "You feel like you might be vulnerable.",
+ 10, 12, A_CON, 12,
+ },
+ {
+ "earthquake",
+ "You can bring down the dungeon around your ears.",
+ "You gain the ability to wreck the dungeon.",
+ "You lose the ability to wreck the dungeon.",
+ 12, 12, A_STR, 16,
+ },
+ {
+ "eat magic",
+ "You can consume magic energy for your own use.",
+ "Your magic items look delicious.",
+ "Your magic items no longer look delicious.",
+ 17, 1, A_WIS, 15,
+ },
+ {
+ "weigh magic",
+ "You can feel the strength of the magics affecting you.",
+ "You feel you can better understand the magic around you.",
+ "You no longer sense magic.",
+ 6, 6, A_INT, 10,
+ },
+ {
+ "sterilise",
+ "You can cause mass impotence.",
+ "You can give everything around you a headache.",
+ "You hear a massed sigh of relief.",
+ 20, 40, A_CHR, 18,
+ },
+ {
+ "panic hit",
+ "You can run for your life after hitting something.",
+ "You suddenly understand how thieves feel.",
+ "You no longer feel jumpy.",
+ 10, 12, A_DEX, 14,
+ },
+ {
+ "dazzle",
+ "You can emit confusing, blinding radiation.",
+ "You gain the ability to emit dazzling lights.",
+ "You lose the ability to emit dazzling lights.",
+ 7, 15, A_CHR, 8,
+ },
+ {
+ "spear of darkness",
+ "You can create a spear of darkness.",
+ "An illusory spear of darkness appears in your hand.",
+ "The spear of darkness disappear.",
+ 7, 10, A_WIS, 9,
+ },
+ {
+ "recall",
+ "You can travel between towns and the depths.",
+ "You feel briefly homesick, but it passes.",
+ "You feel briefly homesick.",
+ 17, 50, A_INT, 16,
+ },
+ {
+ "banish evil",
+ "You can send evil creatures directly to the Nether Realm.",
+ "You feel a holy wrath fill you.",
+ "You no longer feel a holy wrath.",
+ 25, 25, A_WIS, 18,
+ },
+ {
+ "cold touch",
+ "You can freeze things with a touch.",
+ "Your hands get very cold.",
+ "Your hands warm up.",
+ 2, 2, A_CON, 11,
+ },
+ {
+ "throw object",
+ "You can hurl objects with great force.",
+ "Your throwing arm feels much stronger.",
+ "Your throwing arm feels much weaker.",
+ 1, 10, A_STR, 6,
+ },
+ {
+ "find secret passages",
+ "You can use secret passages.",
+ "You suddenly notice lots of hidden ways.",
+ "You no longer can use hidden ways.",
+ 15, 15, A_DEX, 12,
+ },
+ {
+ "detect doors and traps",
+ "You can detect hidden doors and traps.",
+ "You develop an affinity for traps.",
+ "You no longer can detect hidden doors and traps.",
+ 5, 3, A_WIS, 10,
+ },
+ {
+ "create food",
+ "You can create food.",
+ "Your cooking skills greatly improve.",
+ "Your cooking skills return to a normal level.",
+ 15, 10, A_INT, 10,
+ },
+ {
+ "remove fear",
+ "You can embolden yourself.",
+ "You feel your fears lessening.",
+ "You feel your fears growing again.",
+ 3, 5, A_WIS, 8,
+ },
+ {
+ "set explosive rune",
+ "You can set explosive runes.",
+ "You suddenly understand how explosive runes work.",
+ "You suddenly forget how explosive runes work.",
+ 25, 35, A_INT, 15,
+ },
+ {
+ "stone to mud",
+ "You can destroy walls.",
+ "You can destroy walls.",
+ "You cannot destroy walls anymore.",
+ 20, 10, A_STR, 12,
+ },
+ {
+ "poison dart",
+ "You can throw poisoned darts.",
+ "You get an infinite supply of poisoned darts.",
+ "You lose your infinite supply of poisoned darts.",
+ 12, 8, A_DEX, 14,
+ },
+ {
+ "magic missile",
+ "You can cast magic missiles.",
+ "You suddenly understand the basics of magic.",
+ "You forget the basics of magic.",
+ 2, 2, A_INT, 9,
+ },
+ {
+ "grow trees",
+ "You can grow trees.",
+ "You feel an affinity for trees.",
+ "You no longer feel an affinity for trees.",
+ 2, 6, A_CHR, 3,
+ },
+ {
+ "cold breath",
+ "You can breath cold.",
+ "You gain the ability to breathe cold.",
+ "You lose the ability to breathe cold.",
+ 20, 10, A_CON, 18,
+ },
+ {
+ "chaos breath",
+ "You can breath chaos.",
+ "You gain the ability to breathe chaos.",
+ "You lose the ability to breathe chaos.",
+ 20, 10, A_CON, 18,
+ },
+ {
+ "elemental breath",
+ "You can breath the elements.",
+ "You gain the ability to breathe the elements.",
+ "You lose the ability to breathe the elements.",
+ 20, 10, A_CON, 18,
+ },
+ {
+ "change the world",
+ "You can wreck the world around you.",
+ "You gain the ability to wreck the world.",
+ "You lose the ability to wreck the world.",
+ 1, 30, A_CHR, 6,
+ },
+ {
+ "scare monster",
+ "You can scare monsters.",
+ "You gain the ability to scare monsters.",
+ "You lose the ability to scare monsters.",
+ 4, 3, A_INT, 3,
+ },
+ {
+ "restore life",
+ "You can restore lost life forces.",
+ "You gain the ability to restore your life force.",
+ "You lose the ability to restore your life force.",
+ 30, 30, A_WIS, 18,
+ },
+ {
+ "summon monsters",
+ "You can call upon monsters.",
+ "You gain the ability to call upon monsters.",
+ "You lose the ability to call upon monsters.",
+ 0, 0, 0, 0,
+ },
+ {
+ "necromantic powers",
+ "You can use the foul necromantic magic.",
+ "You gain the ability to use the foul necromantic magic.",
+ "You lose the ability to use the foul necromantic magic.",
+ 0, 0, 0, 0,
+ },
+ {
+ "Rohan Knight's Powers",
+ "You can use rohir powers.",
+ "You gain the ability to use rohir powers.",
+ "You lose the ability to use rohir powers.",
+ 0, 0, 0, 0,
+ },
+ {
+ "Thunderlord's Powers",
+ "You can use thunderlords powers.",
+ "You gain the ability to use thunderlords powers.",
+ "You lose the ability to use thunderlords powers.",
+ 0, 0, 0, 0,
+ },
+ {
+ "Death Mold's Powers",
+ "You can use the foul deathmold magic.",
+ "You gain the ability to use the foul deathmold magic.",
+ "You lose the ability to use the foul deathmold magic.",
+ 0, 0, 0, 0,
+ },
+ {
+ "Hypnotise Pet",
+ "You can mystify pets.",
+ "You gain the ability to mystify pets.",
+ "You lose the ability to mystify pets.",
+ 0, 0, 0, 0,
+ },
+ {
+ "Awaken Hypnotised Pet",
+ "You can wake up a pet.",
+ "You gain the ability to wake up a pet.",
+ "You lose the ability to wake up a pet.",
+ 0, 0, 0, 0,
+ },
+ {
+ "Incarnate",
+ "You can incarnate into a body.",
+ "You feel the need to get a body.",
+ "You no longer feel the need for a new body.",
+ 0, 0, 0, 0,
+ },
+ {
+ "magic map",
+ "You can sense what is beyond walls.",
+ "You feel you can sense what is beyond walls.",
+ "You no longer can sense what is beyond walls.",
+ 7, 10, A_WIS, 15,
+ },
+ {
+ "lay trap",
+ "You can lay monster traps.",
+ "You suddenly understand how rogues work.",
+ "You no longer understand how rogues work.",
+ 1, 1, A_DEX, 1,
+ },
+ {
+ "Merchant abilities",
+ "You can request items and get loans.",
+ "From now on you can use the merchant abilities.",
+ "You can no longer use the merchant abilities.",
+ 0, 0, 0, 0,
+ },
+ {
+ "turn pet into companion",
+ "You can turn a pet into a companion.",
+ "You suddenly gain authority over your pets.",
+ "You can no longer convert pets into companions.",
+ 2, 10, A_CHR, 10,
+ },
+ {
+ "turn into a bear",
+ "You can turn into a bear.",
+ "You suddenly gain beorning powers.",
+ "You can no longer shapeshift into a bear.",
+ 2, 5, A_CON, 5,
+ },
+ {
+ "sense dodge success",
+ "You can sense your dodging success chance.",
+ "You suddenly can sense your dodging success chance.",
+ "You can no longer sense your dodging success chance.",
+ 0, 0, 0, 0,
+ },
+ {
+ "turn into a Balrog",
+ "You can turn into a Balrog at will.",
+ "You feel the fire of Udun burning in you.",
+ "You no longer feel the fire of Udun in you.",
+ 35, 80, A_WIS, 25,
+ },
+};
+
+/*
+ * The Quests
+ */
+quest_type quest_init_tome[MAX_Q_IDX_INIT] =
+{
+ {
+ FALSE,
+ FALSE,
+ "",
+ {
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 0,
+
+ NULL,
+ HOOK_TYPE_C,
+ quest_null_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ FALSE,
+ FALSE,
+ "Dol Guldur",
+ {
+ "The forest of Mirkwood is a very dangerous place to go, mainly due to",
+ "the activities of the Necromancer that lurks in Dol Guldur.",
+ "Find him, and free Mirkwood from his spells.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_TAKEN,
+ 70,
+
+ &plots[PLOT_MAIN],
+ HOOK_TYPE_C,
+ quest_necro_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ FALSE,
+ FALSE,
+ "Sauron",
+ {
+ "It is time to take the battle to Morgoth. But, before you can",
+ "reach it, you must find and kill Sauron. Only after defeating",
+ "this powerful sorcerer will the stairs leading to Morgoth's",
+ "room be opened.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 99,
+
+ &plots[PLOT_MAIN],
+ HOOK_TYPE_C,
+ quest_sauron_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ FALSE,
+ FALSE,
+ "Morgoth",
+ {
+ "Your final quest is the ultimate quest that has always been",
+ "required of you. You must enter the fetid depths of Angband, where",
+ "Morgoth is waiting. Travel deep, and defeat this source of all our",
+ "problems. Be prepared, be patient, and good luck. May the light",
+ "shine on you.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 100,
+
+ &plots[PLOT_MAIN],
+ HOOK_TYPE_C,
+ quest_morgoth_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ /* Bree plot */
+ {
+ FALSE,
+ FALSE,
+ "Thieves!",
+ {
+ "There are thieves robbing my people! They live in a small",
+ "burrow outside the city walls, but they get inside the walls",
+ "with a tunnel to a building here! Your task is to go into",
+ "the building and kill these ruffians.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 5,
+
+ &plots[PLOT_BREE],
+ HOOK_TYPE_C,
+ quest_thieves_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ FALSE,
+ TRUE,
+ "Random Quest",
+ {
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 5,
+
+ NULL,
+ HOOK_TYPE_C,
+ quest_random_init_hook,
+ {0, 0},
+ quest_random_describe,
+ },
+
+ {
+ FALSE,
+ FALSE,
+ "Lost Hobbit",
+ {
+ "Merton Proudfoot, a young hobbit, seems to have disappeared.",
+ "Last time anyone saw him was near the horrible maze to the south of Bree.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 25,
+
+ &plots[PLOT_OTHER],
+ HOOK_TYPE_C,
+ quest_hobbit_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ FALSE,
+ FALSE,
+ "The Dark Horseman",
+ {
+ "A dark-cloaked horseman has been spotted several times in town.",
+ "He carries an aura of fear with him and people seem to get sick",
+ "wherever he goes. Please do something, but be careful...",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 40,
+
+ &plots[PLOT_BREE],
+ HOOK_TYPE_C,
+ quest_nazgul_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ FALSE,
+ FALSE,
+ "The Trolls Glade",
+ {
+ "A group of Forest Trolls settled in an abandoned forest in the",
+ "south east of our town. They are killing our people. You must",
+ "put an end to this! It might be best to look for them at night.",
+ "Local hobbits claim that the mighty swords Orcrist and Glamdring",
+ "can be found there! Bring back one of them as a proof!",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 30,
+
+ &plots[PLOT_BREE],
+ HOOK_TYPE_C,
+ quest_troll_init_hook,
+ {FALSE, 0},
+ NULL,
+ },
+
+ {
+ FALSE,
+ FALSE,
+ "The Wight Grave",
+ {
+ "The Barrow-Downs hides many mysteries and dangers.",
+ "Lately many people, both men and hobbits, have disappeared there.",
+ "Please put an end to this threat!",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 30,
+
+ &plots[PLOT_BREE],
+ HOOK_TYPE_C,
+ quest_wight_init_hook,
+ {FALSE, 0},
+ NULL,
+ },
+
+ /* Lorien plot */
+ {
+ FALSE,
+ FALSE,
+ "Spiders of Mirkwood",
+ {
+ "Powers lurk deep within Mirkwood. Spiders have blocked the",
+ "path through the forest, and Thranduil's folk have been",
+ "unable to hold them off. It is your task to drive them",
+ "away. Be careful -- many traps have been laid by their",
+ "webs, and their venom is dangerous indeed.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 25,
+
+ &plots[PLOT_LORIEN],
+ HOOK_TYPE_C,
+ quest_spider_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ FALSE,
+ FALSE,
+ "Poisoned Water",
+ {
+ "A curse has beset Lothlorien. All trees along the shorelines of Nimrodel",
+ "are withering away. We fear the blight could spread to the whole forest.",
+ "The cause seems to be an unknown poison. You are to go to the West and",
+ "travel along Celebrant and Nimrodel until you discover the source of",
+ "the poisoning. Then you must destroy it and drop these potions on",
+ "the tainted water.",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 30,
+
+ &plots[PLOT_LORIEN],
+ HOOK_TYPE_C,
+ quest_poison_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* Other quests */
+ {
+ FALSE,
+ FALSE,
+ "The Broken Sword",
+ {
+ "You have found Narsil, a broken sword. It is said that the sword that",
+ "was broken shall be reforged... Maybe it is this one.",
+ "You should bring it to Aragorn at Minas Anor -- he would know.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 20,
+
+ &plots[PLOT_OTHER],
+ HOOK_TYPE_C,
+ quest_narsil_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* Gondolin plot */
+ {
+ FALSE,
+ FALSE,
+ "Eol the Dark Elf",
+ {
+ "We have disturbing tidings. Eol the Dark Elf has come seeking his kin in",
+ "Gondolin. We cannot let anyone pass the borders of the city without the",
+ "King's leave. Go forth to the eastern mountains and apprehend him. If",
+ "he resists, use whatever means possible to hinder him from reaching the",
+ "city. Be wary -- the mountain caves may have many hidden traps.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 30,
+
+ &plots[PLOT_GONDOLIN],
+ HOOK_TYPE_C,
+ quest_eol_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ FALSE,
+ FALSE,
+ "Nirnaeth Arnoediad",
+ {
+ "The fortunes of war in the north turn against us.",
+ "Morgoth's treachery has driven our armies back nigh",
+ "to the city's walls. Go forth from the city gates",
+ "and clear a path for them to retreat. You need not",
+ "destroy the troll army, simply drive a path through.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 37,
+
+ &plots[PLOT_GONDOLIN],
+ HOOK_TYPE_C,
+ quest_nirnaeth_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ FALSE,
+ FALSE,
+ "Invasion of Gondolin",
+ {
+ "Morgoth is upon us! Dragons and Balrogs have poured over secret",
+ "ways of the Echoriath, and are looking for our city. They are",
+ "conducted by Maeglin! You must stop him or they will find us.",
+ "Do not let Maeglin get to the stairs or everything will be lost!",
+ "Go now, be brave.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 80,
+
+ &plots[PLOT_GONDOLIN],
+ HOOK_TYPE_C,
+ quest_invasion_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* Minas Anor Plot*/
+ {
+ FALSE,
+ FALSE,
+ "The Last Alliance",
+ {
+ "The armies of Morgoth are closing in on the last remaining strongholds",
+ "of resistance against him. We are too far apart to help each other.",
+ "The arrival of our new Thunderlord allies has helped, but can only delay",
+ "the inevitable. We must be able to stand together and reinforce each other,",
+ "or both our kingdoms will fall separately. The Thunderlords have taught us",
+ "how to use the Void Jumpgates: we need you to open a Void Jumpgate in our",
+ "own city, and that of Gondolin.",
+ "Simply travel to Gondolin, but beware of rebel thunderlords.",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 80,
+
+ &plots[PLOT_MINAS],
+ HOOK_TYPE_C,
+ quest_between_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ FALSE,
+ FALSE,
+ "The One Ring",
+ {
+ "Find the One Ring, then bring it to Mount Doom, in Mordor, to drop",
+ "it in the Great Fire where it was once forged.",
+ "But beware: *NEVER* use it, or you will be corrupted.",
+ "Once it is destroyed you will be able to permanently defeat Sauron.",
+ "The ring must be cast back into the fires of Mount Doom!",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 99,
+
+ &plots[PLOT_MAIN],
+ HOOK_TYPE_C,
+ quest_one_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ FALSE,
+ FALSE,
+ "Mushroom supplies",
+ {
+ "Farmer Maggot asked you to bring him back his mushrooms.",
+ "Do not harm his dogs.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 3,
+
+ &plots[PLOT_OTHER],
+ HOOK_TYPE_C,
+ quest_shroom_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ {
+ FALSE,
+ FALSE,
+ "The prisoner of Dol Guldur",
+ {
+ "You keep hearing distress cries in the dark tower of",
+ "Dol Guldur...",
+ "Maybe there is someone being held prisoner and tortured!",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 60,
+
+ &plots[PLOT_OTHER],
+ HOOK_TYPE_C,
+ quest_thrain_init_hook,
+ {0, 0},
+ NULL,
+ },
+
+ /* The 2 ultra endings go here */
+ {
+ FALSE,
+ FALSE,
+ "Falling Toward Apotheosis",
+ {
+ "You must enter the Void where Melkor spirit lurks to destroy",
+ "him forever. Remember however that it is likely to be your own",
+ "death that awaits you.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 150,
+
+ &plots[PLOT_MAIN],
+ HOOK_TYPE_C,
+ quest_ultra_good_init_hook,
+ {0, 0},
+ NULL,
+ },
+ {
+ FALSE,
+ FALSE,
+ "Falling Toward Apotheosis",
+ {
+ "You must now launch an onslaught on Valinor itself to eliminate",
+ "once and for all any posible resistance to your dominance of Arda.",
+ "Remember however that it is likely to be your own death that awaits you.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 150,
+
+ &plots[PLOT_MAIN],
+ HOOK_TYPE_C,
+ quest_ultra_evil_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* More Lorien */
+ {
+ FALSE,
+ FALSE,
+ "Wolves!",
+ {
+ "There are wolves pestering my people! They gather in a hut",
+ "on the edge of town and menace everyone nearby. Your task",
+ "is to go in there and clear them out.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 15,
+
+ &plots[PLOT_LORIEN],
+ HOOK_TYPE_C,
+ quest_wolves_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* More Gondolin */
+ {
+ FALSE,
+ FALSE,
+ "Dragons!",
+ {
+ "There are dragons pestering my people! They gather in a",
+ "building on the edge of town and menace everyone nearby.",
+ "Your task is to go into the building and clear them out.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 25,
+
+ &plots[PLOT_GONDOLIN],
+ HOOK_TYPE_C,
+ quest_dragons_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* More Minas Anor */
+ {
+ FALSE,
+ FALSE,
+ "Haunted House!",
+ {
+ "There are undead pestering my people! They gather in a hut",
+ "on the edge of town and menace everyone nearby. Your task",
+ "is to go into the building and clear out the beasts.",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 45,
+
+ &plots[PLOT_MINAS],
+ HOOK_TYPE_C,
+ quest_haunted_init_hook,
+ {0, 0},
+ NULL,
+ },
+ /* Khazad-Dum Plot*/
+ {
+ FALSE,
+ FALSE,
+ "Evil!",
+ {
+ "We have burrowed too deep, and let out some creatures of",
+ "Morgoth's that threaten to kill us all! Your task is to save us",
+ "from them!",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
+ QUEST_STATUS_UNTAKEN,
+ 60,
+
+ &plots[PLOT_KHAZAD],
+ HOOK_TYPE_C,
+ quest_evil_init_hook,
+ {0, 0},
+ NULL,
+ },
+};
+
+
+/* List of powers for Symbiants/Powers */
+monster_power monster_powers[96] =
+ {
+ { RF4_SHRIEK, "Aggravate Monster", 1, FALSE },
+ { RF4_MULTIPLY, "Multiply", 10, FALSE },
+ { RF4_S_ANIMAL, "Summon Animal", 30, FALSE },
+ { RF4_ROCKET, "Fire a Rocket", 40, TRUE },
+ { RF4_ARROW_1, "Light Arrow", 1, FALSE },
+ { RF4_ARROW_2, "Minor Arrow", 3, FALSE },
+ { RF4_ARROW_3, "Major Arrow", 7, TRUE },
+ { RF4_ARROW_4, "Great Arrow", 9, TRUE },
+ { RF4_BR_ACID, "Breathe Acid", 10, FALSE },
+ { RF4_BR_ELEC, "Breathe Lightning", 10, FALSE },
+ { RF4_BR_FIRE, "Breathe Fire", 10, FALSE },
+ { RF4_BR_COLD, "Breathe Cold", 10, FALSE },
+ { RF4_BR_POIS, "Breathe Poison", 15, TRUE },
+ { RF4_BR_NETH, "Breathe Nether", 30, TRUE },
+ { RF4_BR_LITE, "Breathe Light", 20, TRUE },
+ { RF4_BR_DARK, "Breathe Dark", 20, TRUE },
+ { RF4_BR_CONF, "Breathe Confusion", 15, TRUE },
+ { RF4_BR_SOUN, "Breathe Sound", 30, TRUE },
+ { RF4_BR_CHAO, "Breathe Chaos", 30, TRUE },
+ { RF4_BR_DISE, "Breathe Disenchantment", 30, TRUE },
+ { RF4_BR_NEXU, "Breathe Nexus", 30, TRUE },
+ { RF4_BR_TIME, "Breathe Time", 30, TRUE },
+ { RF4_BR_INER, "Breathe Inertia", 30, TRUE },
+ { RF4_BR_GRAV, "Breathe Gravity", 30, TRUE },
+ { RF4_BR_SHAR, "Breathe Shards", 30, TRUE },
+ { RF4_BR_PLAS, "Breathe Plasma", 30, TRUE },
+ { RF4_BR_WALL, "Breathe Force", 30, TRUE },
+ { RF4_BR_MANA, "Breathe Mana", 40, TRUE },
+ { RF4_BA_NUKE, "Nuke Ball", 30, TRUE },
+ { RF4_BR_NUKE, "Breathe Nuke", 40, TRUE },
+ { RF4_BA_CHAO, "Chaos Ball", 30, TRUE },
+ { RF4_BR_DISI, "Breathe Disintegration", 40, TRUE },
+
+ { RF5_BA_ACID, "Acid Ball", 8, FALSE },
+ { RF5_BA_ELEC, "Lightning Ball", 8, FALSE },
+ { RF5_BA_FIRE, "Fire Ball", 8, FALSE },
+ { RF5_BA_COLD, "Cold Ball", 8, FALSE },
+ { RF5_BA_POIS, "Poison Ball", 20, TRUE },
+ { RF5_BA_NETH, "Nether Ball", 20, TRUE },
+ { RF5_BA_WATE, "Water Ball", 20, TRUE },
+ { RF5_BA_MANA, "Mana Ball", 50, TRUE },
+ { RF5_BA_DARK, "Darkness Ball", 20, TRUE },
+ { 0, "(none)", 0, FALSE },
+ { 0, "(none)", 0, FALSE },
+ { 0, "(none)", 0, FALSE },
+ { RF5_CAUSE_1, "Cause Light Wounds", 20, FALSE },
+ { RF5_CAUSE_2, "Cause Medium Wounds", 30, FALSE },
+ { RF5_CAUSE_3, "Cause Critical Wounds", 35, TRUE },
+ { RF5_CAUSE_4, "Cause Mortal Wounds", 45, TRUE },
+ { RF5_BO_ACID, "Acid Bolt", 5, FALSE },
+ { RF5_BO_ELEC, "Lightning Bolt", 5, FALSE },
+ { RF5_BO_FIRE, "Fire Bolt", 5, FALSE },
+ { RF5_BO_COLD, "Cold Bolt", 5, FALSE },
+ { RF5_BO_POIS, "Poison Bolt", 10, TRUE },
+ { RF5_BO_NETH, "Nether Bolt", 15, TRUE },
+ { RF5_BO_WATE, "Water Bolt", 20, TRUE },
+ { RF5_BO_MANA, "Mana Bolt", 25, TRUE },
+ { RF5_BO_PLAS, "Plasma Bolt", 20, TRUE },
+ { RF5_BO_ICEE, "Ice Bolt", 20, TRUE },
+ { RF5_MISSILE, "Magic Missile", 1, FALSE },
+ { RF5_SCARE, "Scare", 4, FALSE },
+ { RF5_BLIND, "Blindness", 6, FALSE },
+ { RF5_CONF, "Confusion", 7, FALSE },
+ { RF5_SLOW, "Slowness", 10, FALSE },
+ { RF5_HOLD, "Paralyse", 10, FALSE },
+
+ { RF6_HASTE, "Haste Self", 50, FALSE },
+ { RF6_HAND_DOOM, "Hand of Doom", 30, TRUE },
+ { RF6_HEAL, "Healing", 60, FALSE },
+ { RF6_S_ANIMALS, "Summon Animals", 60, TRUE },
+ { RF6_BLINK, "Phase Door", 2, FALSE },
+ { RF6_TPORT, "Teleport", 10, FALSE },
+ { RF6_TELE_TO, "Teleport To", 20, TRUE },
+ { RF6_TELE_AWAY, "Teleport Away", 20, FALSE },
+ { RF6_TELE_LEVEL, "Teleport Level", 20, TRUE },
+ { RF6_DARKNESS, "Darkness", 3, FALSE },
+ { RF6_TRAPS, "Create Traps", 10, TRUE },
+ { 0, "(none)", 0, FALSE },
+ { RF6_RAISE_DEAD, "Raise the Dead", 400, TRUE },
+ { 0, "(none)", 0, FALSE },
+ { 0, "(none)", 0, FALSE },
+ { RF6_S_THUNDERLORD, "Summon Thunderlords", 90, TRUE },
+ { RF6_S_KIN, "Summon Kin", 80, FALSE },
+ { RF6_S_HI_DEMON, "Summon Greater Demons", 90, TRUE },
+ { RF6_S_MONSTER, "Summon Monster", 50, FALSE },
+ { RF6_S_MONSTERS, "Summon Monsters", 60, TRUE },
+ { RF6_S_ANT, "Summon Ants", 30, FALSE },
+ { RF6_S_SPIDER, "Summon Spider", 30, FALSE },
+ { RF6_S_HOUND, "Summon Hound", 50, TRUE },
+ { RF6_S_HYDRA, "Summon Hydra", 40, TRUE },
+ { RF6_S_ANGEL, "Summon Angel", 60, TRUE },
+ { RF6_S_DEMON, "Summon Demon", 60, TRUE },
+ { RF6_S_UNDEAD, "Summon Undead", 70, TRUE },
+ { RF6_S_DRAGON, "Summon Dragon", 70, TRUE },
+ { RF6_S_HI_UNDEAD, "Summon High Undead", 90, TRUE },
+ { RF6_S_HI_DRAGON, "Summon High Dragon", 90, TRUE },
+ { RF6_S_WRAITH, "Summon Wraith", 90, TRUE },
+ { 0, "(none)", 0, FALSE },
+ };
+
+/* Tval descriptions */
+tval_desc tval_descs[] =
+{
+ {
+ TV_BATERIE,
+ "Essences contain primitive magic forces which users of the "
+ "Alchemy skill can use to create powerful magic items from "
+ "other magic items."
+ },
+ {
+ TV_MSTAFF,
+ "Mage Staves are the spellcaster's weapons of choice. "
+ "They all reduce spellcasting time to 80% of "
+ "normal time and some will yield even greater powers."
+ },
+ {
+ 3,
+ "XXX"
+ },
+ {
+ TV_PARCHMENT,
+ "Parchments can contain useful information ... or useless "
+ "junk."
+ },
+ {
+ TV_EGG,
+ "Eggs are laid by some monsters. If they hatch in your "
+ "inventory the monster will be your friend."
+ },
+ {
+ TV_TOOL,
+ "Tools can be digging implements, climbing equipment and such. "
+ "They have their own slot in your inventory."
+
+ },
+ {
+ TV_INSTRUMENT,
+ "Musical instruments can be used with the Music skill to play "
+ "magical songs. Some of them can also be activated."
+ },
+ {
+ TV_BOOMERANG,
+ "Boomerangs can be used instead of bows or slings. They "
+ "are more like melee weapons than bows."
+ },
+ {
+ TV_SHOT,
+ "Shots are small, hard balls. They are the standard ammunition "
+ "for slings. You can carry them in your quiver if you have a sling "
+ "equipped."
+ },
+ {
+ TV_ARROW,
+ "Arrows are the standard ammunition for bows. You can carry "
+ "them in your quiver if you have a bow equipped."
+ },
+ {
+ TV_BOLT,
+ "Bolts are the standard ammunition for crossbows. You can "
+ "carry them in your quiver if you have a crossbow equipped."
+ },
+ {
+ TV_BOW,
+ "Slings, bows and crossbows are used to attack monsters "
+ "from a distance."
+ },
+ {
+ TV_DIGGING,
+ "Tools can be digging implements, climbing equipment and such. "
+ "They have their own slot in your inventory."
+ },
+ {
+ TV_HAFTED,
+ "Hafted weapons are melee weapons. Eru followers can use them "
+ "without penalties."
+ },
+ {
+ TV_SWORD,
+ "Swords are melee weapons."
+ },
+ {
+ TV_AXE,
+ "Axes are melee weapons."
+ },
+ {
+ TV_POLEARM,
+ "Polearms are melee weapons."
+ },
+ {
+ TV_DRAG_ARMOR,
+ "Dragon armour is made from the scales of dead dragons. "
+ "These mighty sets of armour usually yield great power to "
+ "their wearer."
+ },
+ {
+ TV_LITE,
+ "Lights allow you to read things and see from afar. Some of "
+ "them need to be fueled but some do not."
+ },
+ {
+ TV_AMULET,
+ "Amulets are fine pieces of jewelry, usually imbued with "
+ "arcane magics."
+ },
+ {
+ TV_RING,
+ "Rings are fine pieces of jewelry, usually imbued with "
+ "arcane magics."
+ },
+ {
+ TV_TRAPKIT,
+ "Trapping kits are used with the trapping ability to set "
+ "deadly monster traps."
+ },
+ {
+ TV_STAFF,
+ "Staves are objects imbued with mystical powers."
+ },
+ {
+ TV_WAND,
+ "Wands are like small staves and usually have a targeted "
+ "effect."
+ },
+ {
+ TV_ROD,
+ "Rod tips are the physical bindings of powerful "
+ "spells. Zap (attach) them to a rod to get a fully "
+ "functional rod. Each spell takes some mana from the rod "
+ "it is attached to to work."
+ },
+ {
+ TV_ROD_MAIN,
+ "Rods contain mana reserves used to cast spells in rod "
+ "tips. Zap (attach) a rod tip to them to get a fully "
+ "functional rod. Each spell takes some mana from the rod "
+ "it is attached to to work."
+ },
+ {
+ TV_SCROLL,
+ "Scrolls are magical parchments imbued with magic spells. "
+ "Some are good, some...are not. When a scroll is read, its "
+ "magic is released and the scroll is destroyed."
+ },
+ {
+ TV_POTION,
+ "Potions are magical liquids. Some of them are "
+ "beneficial...some not."
+ },
+ {
+ TV_POTION2,
+ "Potions are magical liquids. Some of them are "
+ "beneficial...some not."
+ },
+ {
+ TV_FLASK,
+ "Flasks of oil can be used to refill lanterns."
+ },
+ {
+ TV_FOOD,
+ "Everybody needs to eat, even you."
+ },
+ {
+ TV_HYPNOS,
+ "This monster seems to be hypnotised and friendly."
+ },
+ {
+ TV_RANDART,
+ "Those objects are only known of by rumours. It is said that "
+ "they can be activated for great or strange effects..."
+ },
+ {
+ TV_RUNE1,
+ "Runes are used with the Runecraft skill to create brand new spells."
+ },
+ {
+ TV_RUNE2,
+ "Runes are used with the Runecraft skill to create brand new spells."
+ },
+ {
+ TV_JUNK,
+ "Junk is usually worthless, though experienced archers can "
+ "create ammo with them."
+ },
+ {
+ TV_SKELETON,
+ "It looks dead..."
+ },
+ {
+ TV_BOTTLE,
+ "An empty bottle. Maybe an alchemist could refill it."
+ },
+ {
+ TV_SPIKE,
+ "Spikes can be used to jam doors."
+ },
+ {
+ TV_CORPSE,
+ "It looks dead..."
+ },
+ {
+ TV_BOOTS,
+ "Boots can help your armour rating. Some of these are magical."
+ },
+ {
+ TV_GLOVES,
+ "Handgear is used to protect hands, but nonmagical ones "
+ "can sometimes hinder spellcasting. Alchemists need "
+ "gloves in order to do alchemy."
+ },
+ {
+ TV_HELM,
+ "Headgear will protect your head."
+ },
+ {
+ TV_CROWN,
+ "Headgear will protect your head."
+ },
+ {
+ TV_SHIELD,
+ "Shields will help improve your defence rating, but you "
+ "cannot use them with two handed weapons."
+ },
+ {
+ TV_CLOAK,
+ "Cloaks can shield you from damage. Sometimes they also "
+ "provide magical powers."
+ },
+ {
+ TV_SOFT_ARMOR,
+ "Soft armour is light, and will not hinder your combat much."
+ },
+ {
+ TV_HARD_ARMOR,
+ "Hard armour provides much more protection than soft "
+ "armour but also hinders combat much more."
+ },
+ {
+ TV_SYMBIOTIC_BOOK,
+ "This mystical book is used by symbiants to extend their "
+ "symbiosis."
+ },
+ {
+ TV_MUSIC_BOOK,
+ "This song book is used by bards to play songs."
+ },
+ {
+ TV_DRUID_BOOK,
+ "This mystical book is used by druids to call upon the "
+ "powers of nature."
+ },
+ {
+ TV_DAEMON_BOOK,
+ "This unholy demon equipment is used with the Demonology skill to control "
+ "the school of demon power."
+ },
+ {0, ""},
+};
+
+/*
+ * List of the between exits
+ * s16b corresp; Corresponding between gate
+ * bool_ dungeon; Do we exit in a dungeon or in the wild ?
+ *
+ * s16b wild_x, wild_y; Wilderness spot to land onto
+ * s16b p_ptr->px, p_ptr->py; Location of the map
+ *
+ * s16b d_idx; Dungeon to land onto
+ * s16b level;
+ */
+between_exit between_exits[MAX_BETWEEN_EXITS] =
+{
+ {
+ 1,
+ FALSE,
+ 49, 11,
+ 119, 25,
+ 0, 0
+ },
+ {
+ 0,
+ FALSE,
+ 60, 56,
+ 10, 35,
+ 0, 0
+ },
+};
+
+/*
+ * Months
+ */
+int month_day[9] =
+{
+ 0, /* 1 day */
+
+ 1, /* 54 days */
+ 55, /* 72 days */
+ 127, /* 54 days */
+
+ 181, /* 3 days */
+
+ 184, /* 54 days */
+ 238, /* 72 days */
+ 310, /* 54 days */
+
+ 364, /* 1 day */
+};
+
+cptr month_name[9] =
+{
+ "Yestare",
+
+ "Tuile",
+ "Laire",
+ "Yavie",
+
+ "Enderi",
+
+ "Quelle",
+ "Hrive",
+ "Coire",
+
+ "Mettare",
+};
+
+/*
+ * max body parts
+ */
+int max_body_part[BODY_MAX] =
+{
+ 3, /* Weapon */
+ 1, /* Torso */
+ 3, /* Arms */
+ 6, /* Finger */
+ 2, /* Head */
+ 2, /* Legs */
+};
+
+/*
+ * Description of GF_FOO
+ */
+gf_name_type gf_names[] =
+{
+ { GF_ELEC, "electricity" },
+ { GF_POIS, "poison" },
+ { GF_ACID, "acid" },
+ { GF_COLD, "cold" },
+ { GF_FIRE, "fire" },
+ { GF_UNBREATH, "asphyxiating gas" },
+ { GF_CORPSE_EXPL, "corpse explosion" },
+ { GF_MISSILE, "missile" },
+ { GF_ARROW, "arrow" },
+ { GF_PLASMA, "plasma" },
+ { GF_WAVE, "a tidal wave" },
+ { GF_WATER, "water" },
+ { GF_LITE, "light" },
+ { GF_DARK, "darkness" },
+ { GF_LITE_WEAK, "weak light" },
+ { GF_DARK_WEAK, "weak darkness" },
+ { GF_SHARDS, "shards" },
+ { GF_SOUND, "sound" },
+ { GF_CONFUSION, "confusion" },
+ { GF_FORCE, "force" },
+ { GF_INERTIA, "inertia" },
+ { GF_MANA, "pure mana" },
+ { GF_METEOR, "meteor" },
+ { GF_ICE, "ice" },
+ { GF_CHAOS, "chaos" },
+ { GF_NETHER, "nether" },
+ { GF_DISENCHANT, "disenchantment" },
+ { GF_NEXUS, "nexus" },
+ { GF_TIME, "time" },
+ { GF_GRAVITY, "gravity" },
+ { GF_KILL_WALL, "wall destruction" },
+ { GF_KILL_DOOR, "door destruction" },
+ { GF_KILL_TRAP, "trap destruction" },
+ { GF_MAKE_WALL, "wall creation" },
+ { GF_MAKE_DOOR, "door creation" },
+ { GF_MAKE_TRAP, "trap creation" },
+ { GF_OLD_CLONE, "clone" },
+ { GF_OLD_POLY, "polymorph" },
+ { GF_OLD_HEAL, "healing" },
+ { GF_OLD_SPEED, "speed" },
+ { GF_OLD_SLOW, "slowness" },
+ { GF_OLD_CONF, "confusion" },
+ { GF_OLD_SLEEP, "sleep" },
+ { GF_OLD_DRAIN, "drain life" },
+ { GF_AWAY_UNDEAD, "teleport away undead" },
+ { GF_AWAY_EVIL, "teleport away evil" },
+ { GF_AWAY_ALL, "teleport away" },
+ { GF_TURN_UNDEAD, "scare undead" },
+ { GF_TURN_EVIL, "scare evil" },
+ { GF_TURN_ALL, "scare" },
+ { GF_DISP_UNDEAD, "dispel undead" },
+ { GF_DISP_EVIL, "dispel evil" },
+ { GF_DISP_ALL, "dispel" },
+ { GF_DISP_DEMON, "dispel demons" },
+ { GF_DISP_LIVING, "dispel living creatures" },
+ { GF_ROCKET, "rocket" },
+ { GF_NUKE, "nuke" },
+ { GF_MAKE_GLYPH, "glyph creation" },
+ { GF_STASIS, "stasis" },
+ { GF_STONE_WALL, "stone wall creation" },
+ { GF_DEATH_RAY, "death ray" },
+ { GF_STUN, "stunning" },
+ { GF_HOLY_FIRE, "holy fire" },
+ { GF_HELL_FIRE, "hellfire" },
+ { GF_DISINTEGRATE, "disintegration" },
+ { GF_CHARM, "charming" },
+ { GF_CONTROL_UNDEAD, "undead control" },
+ { GF_CONTROL_ANIMAL, "animal control" },
+ { GF_PSI, "psionic energy" },
+ { GF_PSI_DRAIN, "psionic drain" },
+ { GF_TELEKINESIS, "telekinesis" },
+ { GF_JAM_DOOR, "door jamming" },
+ { GF_DOMINATION, "domination" },
+ { GF_DISP_GOOD, "dispel good" },
+ { GF_IDENTIFY, "identification" },
+ { GF_RAISE, "raise dead" },
+ { GF_STAR_IDENTIFY, "*identification*" },
+ { GF_DESTRUCTION, "destruction" },
+ { GF_STUN_CONF, "stunning and confusion" },
+ { GF_STUN_DAM, "stunning and damage" },
+ { GF_CONF_DAM, "confusion and damage" },
+ { GF_STAR_CHARM, "*charming*" },
+ { GF_IMPLOSION, "implosion" },
+ { GF_LAVA_FLOW, "lava" },
+ { GF_FEAR, "fear" },
+ { GF_BETWEEN_GATE, "jumpgate creation" },
+ { GF_WINDS_MANA, "" },
+ { GF_DEATH, "death" },
+ { GF_CONTROL_DEMON, "control demon" },
+ { GF_RAISE_DEMON, "raise demon" },
+ { GF_TRAP_DEMONSOUL, "*control demon*" },
+ { GF_ATTACK, "projected melee attacks" },
+ { -1, NULL },
+};
diff --git a/src/traps.c b/src/traps.c
new file mode 100644
index 00000000..1c8e36c9
--- /dev/null
+++ b/src/traps.c
@@ -0,0 +1,3169 @@
+/* File: traps.c */
+
+/* Purpose: handle traps */
+
+/* the below copyright probably still applies, but it is heavily changed
+ * copied, adapted & re-engineered by JK.
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+bool_ do_player_trap_call_out(void)
+{
+ s16b i, sn, cx, cy;
+ s16b h_index = 0;
+ s16b h_level = 0;
+ monster_type *m_ptr;
+ char m_name[80];
+ bool_ ident = FALSE;
+
+ for (i = 1; i < m_max; i++)
+ {
+ m_ptr = &m_list[i];
+
+ /* Paranoia -- Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ if (m_ptr->level >= h_level)
+ {
+ h_level = m_ptr->level;
+ h_index = i;
+ }
+ }
+
+ /* if the level is empty of monsters, h_index will be 0 */
+ if (!h_index) return (FALSE);
+
+ m_ptr = &m_list[h_index];
+
+ sn = 0;
+ for (i = 0; i < 8; i++)
+ {
+ cx = p_ptr->px + ddx[i];
+ cy = p_ptr->py + ddy[i];
+
+ /* Skip non-empty grids */
+ if (!cave_valid_bold(cy, cx)) continue;
+ if (cave[cy][cx].feat == FEAT_GLYPH) continue;
+ if ((cx == p_ptr->px) && (cy == p_ptr->py)) continue;
+ sn++;
+
+ /* Randomize choice */
+ if (rand_int(sn) > 0) continue;
+ cave[cy][cx].m_idx = h_index;
+ cave[m_ptr->fy][m_ptr->fx].m_idx = 0;
+ m_ptr->fx = cx;
+ m_ptr->fy = cy;
+
+ /* we do not change the sublevel! */
+ ident = TRUE;
+ update_mon(h_index, TRUE);
+ monster_desc(m_name, m_ptr, 0x08);
+ msg_format("You hear a rapid-shifting wail, and %s appears!", m_name);
+ break;
+ }
+
+ return (ident);
+}
+
+static bool_ do_trap_teleport_away(object_type *i_ptr, s16b y, s16b x)
+{
+ bool_ ident = FALSE;
+ char o_name[80];
+
+ s16b o_idx = 0;
+ object_type *o_ptr;
+ cave_type *c_ptr;
+
+ s16b x1;
+ s16b y1;
+
+ if (i_ptr == NULL) return (FALSE);
+
+ if (i_ptr->name1 == ART_POWER) return (FALSE);
+
+ while (o_idx == 0)
+ {
+ x1 = rand_int(cur_wid);
+ y1 = rand_int(cur_hgt);
+
+ /* Obtain grid */
+ c_ptr = &cave[y1][x1];
+
+ /* Require floor space (or shallow terrain) -KMW- */
+ if (!(f_info[c_ptr->feat].flags1 & FF1_FLOOR)) continue;
+
+ o_idx = drop_near(i_ptr, 0, y1, x1);
+ }
+
+ o_ptr = &o_list[o_idx];
+
+ x1 = o_ptr->ix;
+ y1 = o_ptr->iy;
+
+ if (!p_ptr->blind)
+ {
+ note_spot(y, x);
+ lite_spot(y, x);
+ ident = TRUE;
+ object_desc(o_name, i_ptr, FALSE, 0);
+ if (player_has_los_bold(y1, x1))
+ {
+ lite_spot(y1, x1);
+ msg_format("The %s suddenly stands elsewhere.", o_name);
+
+ }
+ else
+ {
+ msg_format("You suddenly don't see the %s any more!", o_name);
+ }
+ }
+ else
+ {
+ msg_print("You hear something move.");
+ }
+ return (ident);
+}
+
+/*
+ * this handles a trap that places walls around the player
+ */
+static bool_ player_handle_trap_of_walls(void)
+{
+ bool_ ident;
+
+ s16b dx, dy, cx, cy;
+ s16b sx = 0, sy = 0, sn, i;
+ cave_type *cv_ptr;
+ bool_ map[5][5] =
+ {
+ {FALSE, FALSE, FALSE, FALSE, FALSE},
+ {FALSE, FALSE, FALSE, FALSE, FALSE},
+ {FALSE, FALSE, FALSE, FALSE, FALSE},
+ {FALSE, FALSE, FALSE, FALSE, FALSE},
+ {FALSE, FALSE, FALSE, FALSE, FALSE}
+ };
+
+ for (dy = -2; dy <= 2; dy++)
+ for (dx = -2; dx <= 2; dx++)
+ {
+ /* Extract the location */
+ cx = p_ptr->px + dx;
+ cy = p_ptr->py + dy;
+
+ if (!in_bounds(cy, cx)) continue;
+
+ cv_ptr = &cave[cy][cx];
+
+ if (cv_ptr->m_idx) continue;
+
+ /* Lose room and vault */
+ cv_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
+ /* Lose light and knowledge */
+ cv_ptr->info &= ~(CAVE_GLOW | CAVE_MARK);
+
+ /* Skip the center */
+ if (!dx && !dy) continue;
+
+ /* test for dungeon level */
+ if (randint(100) > 10 + max_dlv[dungeon_type]) continue;
+
+ /* Damage this grid */
+ map[2 + dx][2 + dy] = TRUE;
+ }
+
+ for (dy = -2; dy <= 2; dy++)
+ for (dx = -2; dx <= 2; dx++)
+ {
+ /* Extract the location */
+ cx = p_ptr->px + dx;
+ cy = p_ptr->py + dy;
+
+ /* Skip unaffected grids */
+ if (!map[2 + dx][2 + dy]) continue;
+
+ cv_ptr = &cave[cy][cx];
+
+ if (cv_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[cv_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Most monsters cannot co-exist with rock */
+ if ((!(r_ptr->flags2 & RF2_KILL_WALL)) &&
+ (!(r_ptr->flags2 & RF2_PASS_WALL)))
+ {
+ char m_name[80];
+
+ /* Assume not safe */
+ sn = 0;
+
+ /* Monster can move to escape the wall */
+ if (!(r_ptr->flags1 & RF1_NEVER_MOVE))
+ {
+ /* Look for safety */
+ for (i = 0; i < 8; i++)
+ {
+ /* Access the grid */
+ cy = p_ptr->py + ddy[i];
+ cx = p_ptr->px + ddx[i];
+
+ /* Skip non-empty grids */
+ if (!cave_clean_bold(cy, cx)) continue;
+
+ /* Hack -- no safety on glyph of warding */
+ if (cave[cy][cx].feat == FEAT_GLYPH) continue;
+
+ /* Important -- Skip "quake" grids */
+ if (map[2 + (cx - p_ptr->px)][2 + (cy - p_ptr->py)]) continue;
+
+ /* Count "safe" grids */
+ sn++;
+
+ /* Randomize choice */
+ if (rand_int(sn) > 0) continue;
+
+ /* Save the safe grid */
+ sx = cx;
+ sy = cy;
+
+ ident = TRUE;
+
+ break; /* discontinue for loop - safe grid found */
+ }
+ }
+
+ /* Describe the monster */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Scream in pain */
+ msg_format("%^s wails out in pain!", m_name);
+
+ /* Monster is certainly awake */
+ m_ptr->csleep = 0;
+
+ /* Apply damage directly */
+ m_ptr->hp -= (sn ? damroll(4, 8) : 200);
+
+ /* Delete (not kill) "dead" monsters */
+ if (m_ptr->hp < 0)
+ {
+ /* Message */
+ msg_format("%^s is entombed in the rock!", m_name);
+
+ /* Delete the monster */
+ delete_monster_idx(cave[cy][cx].m_idx);
+
+ /* No longer safe */
+ sn = 0;
+ }
+
+ /* Hack -- Escape from the rock */
+ if (sn)
+ {
+ s16b m_idx = cave[cy][cx].m_idx;
+
+ /* Update the new location */
+ cave[sy][sx].m_idx = m_idx;
+
+ /* Update the old location */
+ cave[cy][cx].m_idx = 0;
+
+ /* Move the monster */
+ m_ptr->fy = sy;
+ m_ptr->fx = sx;
+
+ /* do not change fz */
+ /* don't make rock on that square! */
+ if ((sx >= (p_ptr->px - 2)) && (sx <= (p_ptr->px + 2)) &&
+ (sy >= (p_ptr->py - 2)) && (sy <= (p_ptr->py + 2)))
+ {
+ map[2 + (sx - p_ptr->px)][2 + (sy - p_ptr->py)] = FALSE;
+ }
+
+ /* Update the monster (new location) */
+ update_mon(m_idx, TRUE);
+
+ /* Redraw the old grid */
+ lite_spot(cy, cx);
+
+ /* Redraw the new grid */
+ lite_spot(sy, sx);
+ } /* if sn */
+ } /* if monster can co-exist with rock */
+ } /* if monster on square */
+ }
+
+ /* Examine the quaked region */
+ for (dy = -2; dy <= 2; dy++)
+ for (dx = -2; dx <= 2; dx++)
+ {
+ /* Extract the location */
+ cx = p_ptr->px + dx;
+ cy = p_ptr->py + dy;
+
+ /* Skip unaffected grids */
+ if (!map[2 + dx][2 + dy]) continue;
+
+ /* Access the cave grid */
+ cv_ptr = &cave[cy][cx];
+
+ /* Paranoia -- never affect player */
+ if (!dy && !dx) continue;
+
+ /* Destroy location (if valid) */
+ if ((cx < cur_wid) && (cy < cur_hgt) && cave_valid_bold(cy, cx))
+ {
+ bool_ floor = (f_info[cave[cy][cx].feat].flags1 & FF1_FLOOR);
+
+ /* Delete any object that is still there */
+ delete_object(cy, cx);
+
+ if (floor)
+ {
+ cave_set_feat(cy, cx, FEAT_WALL_OUTER);
+ }
+ else
+ {
+ /* Clear previous contents, add floor */
+ cave_set_feat(cy, cx, FEAT_FLOOR);
+ }
+ }
+ }
+
+ /* Mega-Hack -- Forget the view and lite */
+ p_ptr->update |= PU_UN_VIEW;
+
+ /* Update stuff */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_DISTANCE);
+
+ /* Update the health bar */
+ p_ptr->redraw |= (PR_HEALTH);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+ handle_stuff();
+
+ msg_print("Suddenly the cave shifts around you. The air is getting stale!");
+
+ ident = TRUE;
+
+ return (ident);
+}
+
+
+/*
+ * this function handles arrow & dagger traps, in various types.
+ * num = number of missiles
+ * tval, sval = kind of missiles
+ * dd,ds = damage roll for missiles
+ * poison_dam = additional poison damage
+ * name = name given if you should die from it...
+ *
+ * return value = ident (always TRUE)
+ */
+static bool_ player_handle_missile_trap(s16b num, s16b tval, s16b sval, s16b dd, s16b ds,
+ s16b pdam, cptr name)
+{
+ object_type *o_ptr, forge;
+ s16b i, k_idx = lookup_kind(tval, sval);
+ char i_name[80];
+
+ o_ptr = &forge;
+ object_prep(o_ptr, k_idx);
+ o_ptr->number = num;
+ apply_magic(o_ptr, max_dlv[dungeon_type], FALSE, FALSE, FALSE);
+ object_desc(i_name, o_ptr, TRUE, 0);
+
+ msg_format("Suddenly %s hit%s you!", i_name,
+ ((num == 1) ? "" : "s"));
+
+ for (i = 0; i < num; i++)
+ {
+ take_hit(damroll(dd, ds), name);
+
+ redraw_stuff();
+
+ if (pdam > 0)
+ {
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ (void)set_poisoned(p_ptr->poisoned + pdam);
+ }
+ }
+ }
+
+ drop_near(o_ptr, -1, p_ptr->py, p_ptr->px);
+
+ return TRUE;
+}
+
+/*
+ * this function handles a "breath" type trap - acid bolt, lightning balls etc.
+ */
+static bool_ player_handle_breath_trap(s16b rad, s16b type, u16b trap)
+{
+ trap_type *t_ptr = &t_info[trap];
+ bool_ ident;
+ s16b my_dd, my_ds, dam;
+
+ my_dd = t_ptr->dd;
+ my_ds = t_ptr->ds;
+
+ /* these traps gets nastier as levels progress */
+ if (max_dlv[dungeon_type] > (2 * t_ptr->minlevel))
+ {
+ my_dd += (max_dlv[dungeon_type] / 15);
+ my_ds += (max_dlv[dungeon_type] / 15);
+ }
+ dam = damroll(my_dd, my_ds);
+
+ ident = project( -2, rad, p_ptr->py, p_ptr->px, dam, type, PROJECT_KILL | PROJECT_JUMP);
+
+ return (ident);
+}
+
+/*
+ * This function damages the player by a trap
+ */
+static void trap_hit(s16b trap)
+{
+ s16b dam;
+ trap_type *t_ptr = &t_info[trap];
+
+ dam = damroll(t_ptr->dd, t_ptr->ds);
+
+ take_hit(dam, t_name + t_ptr->name);
+}
+
+/*
+ * this function activates one trap type, and returns
+ * a bool_ indicating if this trap is now identified
+ */
+bool_ player_activate_trap_type(s16b y, s16b x, object_type *i_ptr, s16b item)
+{
+ bool_ ident = FALSE;
+ s16b trap;
+
+ s16b k, l;
+
+ trap = cave[y][x].t_idx;
+
+ if (i_ptr != NULL)
+ {
+ trap = i_ptr->pval;
+ }
+
+ if ((i_ptr == NULL) && (cave[y][x].o_idx != 0))
+ {
+ i_ptr = &o_list[cave[y][x].o_idx];
+ }
+
+ switch (trap)
+ {
+ /* stat traps */
+ case TRAP_OF_WEAKNESS_I:
+ ident = do_dec_stat(A_STR, STAT_DEC_TEMPORARY);
+ break;
+ case TRAP_OF_WEAKNESS_II:
+ ident = do_dec_stat(A_STR, STAT_DEC_NORMAL);
+ break;
+ case TRAP_OF_WEAKNESS_III:
+ ident = do_dec_stat(A_STR, STAT_DEC_PERMANENT);
+ break;
+ case TRAP_OF_INTELLIGENCE_I:
+ ident = do_dec_stat(A_INT, STAT_DEC_TEMPORARY);
+ break;
+ case TRAP_OF_INTELLIGENCE_II:
+ ident = do_dec_stat(A_INT, STAT_DEC_NORMAL);
+ break;
+ case TRAP_OF_INTELLIGENCE_III:
+ ident = do_dec_stat(A_INT, STAT_DEC_PERMANENT);
+ break;
+ case TRAP_OF_WISDOM_I:
+ ident = do_dec_stat(A_WIS, STAT_DEC_TEMPORARY);
+ break;
+ case TRAP_OF_WISDOM_II:
+ ident = do_dec_stat(A_WIS, STAT_DEC_NORMAL);
+ break;
+ case TRAP_OF_WISDOM_III:
+ ident = do_dec_stat(A_WIS, STAT_DEC_PERMANENT);
+ break;
+ case TRAP_OF_FUMBLING_I:
+ ident = do_dec_stat(A_DEX, STAT_DEC_TEMPORARY);
+ break;
+ case TRAP_OF_FUMBLING_II:
+ ident = do_dec_stat(A_DEX, STAT_DEC_NORMAL);
+ break;
+ case TRAP_OF_FUMBLING_III:
+ ident = do_dec_stat(A_DEX, STAT_DEC_PERMANENT);
+ break;
+ case TRAP_OF_WASTING_I:
+ ident = do_dec_stat(A_CON, STAT_DEC_TEMPORARY);
+ break;
+ case TRAP_OF_WASTING_II:
+ ident = do_dec_stat(A_CON, STAT_DEC_NORMAL);
+ break;
+ case TRAP_OF_WASTING_III:
+ ident = do_dec_stat(A_CON, STAT_DEC_PERMANENT);
+ break;
+ case TRAP_OF_BEAUTY_I:
+ ident = do_dec_stat(A_CHR, STAT_DEC_TEMPORARY);
+ break;
+ case TRAP_OF_BEAUTY_II:
+ ident = do_dec_stat(A_CHR, STAT_DEC_NORMAL);
+ break;
+ case TRAP_OF_BEAUTY_III:
+ ident = do_dec_stat(A_CHR, STAT_DEC_PERMANENT);
+ break;
+
+ /* Trap of Curse Weapon */
+ case TRAP_OF_CURSE_WEAPON:
+ {
+ ident = curse_weapon();
+ break;
+ }
+
+ /* Trap of Curse Armor */
+ case TRAP_OF_CURSE_ARMOR:
+ {
+ ident = curse_armor();
+ break;
+ }
+
+ /* Earthquake Trap */
+ case TRAP_OF_EARTHQUAKE:
+ {
+ msg_print("As you touch the trap, the ground starts to shake.");
+ earthquake(y, x, 10);
+ ident = TRUE;
+ break;
+ }
+
+ /* Poison Needle Trap */
+ case TRAP_OF_POISON_NEEDLE:
+ {
+ if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
+ {
+ msg_print("You prick yourself on a poisoned needle.");
+ (void)set_poisoned(p_ptr->poisoned + rand_int(15) + 10);
+ ident = TRUE;
+ }
+ else
+ {
+ msg_print("You prick yourself on a needle.");
+ }
+ break;
+ }
+
+ /* Summon Monster Trap */
+ case TRAP_OF_SUMMON_MONSTER:
+ {
+ msg_print("A spell hangs in the air.");
+ for (k = 0; k < randint(3); k++)
+ {
+ ident |= summon_specific(y, x, max_dlv[dungeon_type], 0);
+ }
+ break;
+ }
+
+ /* Summon Undead Trap */
+ case TRAP_OF_SUMMON_UNDEAD:
+ {
+ msg_print("A mighty spell hangs in the air.");
+ for (k = 0; k < randint(3); k++)
+ {
+ ident |= summon_specific(y, x, max_dlv[dungeon_type],
+ SUMMON_UNDEAD);
+ }
+ break;
+ }
+
+ /* Summon Greater Undead Trap */
+ case TRAP_OF_SUMMON_GREATER_UNDEAD:
+ {
+ msg_print("An old and evil spell hangs in the air.");
+ for (k = 0; k < randint(3); k++)
+ {
+ ident |= summon_specific(y, x, max_dlv[dungeon_type],
+ SUMMON_HI_UNDEAD);
+ }
+ break;
+ }
+
+ /* Teleport Trap */
+ case TRAP_OF_TELEPORT:
+ {
+ msg_print("The world whirls around you.");
+ teleport_player(RATIO * 67);
+ ident = TRUE;
+ break;
+ }
+
+ /* Paralyzing Trap */
+ case TRAP_OF_PARALYZING:
+ {
+ if (!p_ptr->free_act)
+ {
+ msg_print("You touch a poisoned part and can't move.");
+ (void)set_paralyzed(p_ptr->paralyzed + rand_int(10) + 10);
+ ident = TRUE;
+ }
+ else
+ {
+ msg_print("You prick yourself on a needle.");
+ }
+ break;
+ }
+
+ /* Explosive Device */
+ case TRAP_OF_EXPLOSIVE_DEVICE:
+ {
+ msg_print("A hidden explosive device explodes in your face.");
+ take_hit(damroll(5, 8), "an explosion");
+ ident = TRUE;
+ break;
+ }
+
+ /* Teleport Away Trap */
+ case TRAP_OF_TELEPORT_AWAY:
+ {
+ int item, amt;
+ object_type *o_ptr;
+
+ /* teleport away all items */
+ while (cave[y][x].o_idx != 0)
+ {
+ item = cave[y][x].o_idx;
+
+ o_ptr = &o_list[item];
+
+ amt = o_ptr->number;
+
+ ident = do_trap_teleport_away(o_ptr, y, x);
+
+ floor_item_increase(item, -amt);
+ floor_item_optimize(item);
+ }
+ break;
+ }
+
+ /* Lose Memory Trap */
+ case TRAP_OF_LOSE_MEMORY:
+ {
+ lose_exp(p_ptr->exp / 4);
+
+ ident |= dec_stat(A_WIS, rand_int(20) + 10, STAT_DEC_NORMAL);
+ ident |= dec_stat(A_INT, rand_int(20) + 10, STAT_DEC_NORMAL);
+
+ if (!p_ptr->resist_conf)
+ {
+ ident |= set_confused(p_ptr->confused + rand_int(100) + 50);
+ }
+
+ if (ident)
+ {
+ msg_print("You suddenly don't remember what you were doing.");
+ }
+ else
+ {
+ msg_print("You feel an alien force probing your mind.");
+ }
+ break;
+ }
+ /* Bitter Regret Trap */
+ case TRAP_OF_BITTER_REGRET:
+ {
+ msg_print("An age-old and hideous-sounding spell reverberates off the walls.");
+
+ ident |= dec_stat(A_DEX, 25, TRUE);
+ ident |= dec_stat(A_WIS, 25, TRUE);
+ ident |= dec_stat(A_CON, 25, TRUE);
+ ident |= dec_stat(A_STR, 25, TRUE);
+ ident |= dec_stat(A_CHR, 25, TRUE);
+ ident |= dec_stat(A_INT, 25, TRUE);
+ break;
+ }
+
+ /* Bowel Cramps Trap */
+ case TRAP_OF_BOWEL_CRAMPS:
+ {
+ msg_print("A wretched-smelling gas cloud upsets your stomach.");
+
+ (void)set_food(PY_FOOD_STARVE - 1);
+ (void)set_poisoned(0);
+
+ if (!p_ptr->free_act)
+ {
+ (void)set_paralyzed(p_ptr->paralyzed + rand_int(dun_level) + 6);
+ }
+ ident = TRUE;
+ break;
+ }
+
+ /* Blindness/Confusion Trap */
+ case TRAP_OF_BLINDNESS_CONFUSION:
+ {
+ msg_print("A powerful magic protected this.");
+
+ if (!p_ptr->resist_blind)
+ {
+ ident |= set_blind(p_ptr->blind + rand_int(100) + 100);
+ }
+ if (!p_ptr->resist_conf)
+ {
+ ident |= set_confused(p_ptr->confused + rand_int(20) + 15);
+ }
+ break;
+ }
+
+ /* Aggravation Trap */
+ case TRAP_OF_AGGRAVATION:
+ {
+ msg_print("You hear a hollow noise echoing through the dungeons.");
+ aggravate_monsters(1);
+ break;
+ }
+
+ /* Multiplication Trap */
+ case TRAP_OF_MULTIPLICATION:
+ {
+ msg_print("You hear a loud click.");
+ for (k = -1; k <= 1; k++)
+ for (l = -1; l <= 1; l++)
+ {
+ if ((in_bounds(p_ptr->py + l, p_ptr->px + k)) &&
+ (!cave[p_ptr->py + l][p_ptr->px + k].t_idx))
+ {
+ place_trap(p_ptr->py + l, p_ptr->px + k);
+ }
+ }
+ ident = TRUE;
+ break;
+ }
+
+ /* Steal Item Trap */
+ case TRAP_OF_STEAL_ITEM:
+ {
+ /*
+ * please note that magical stealing is not so
+ * easily circumvented
+ */
+ if (!p_ptr->paralyzed &&
+ (rand_int(160) < (adj_dex_safe[p_ptr->stat_ind[A_DEX]] +
+ p_ptr->lev)))
+ {
+ /* Saving throw message */
+ msg_print("Your backpack seems to vibrate strangely!");
+ break;
+ }
+
+ /* Find an item */
+ for (k = 0; k < rand_int(10); k++)
+ {
+ char i_name[80];
+ object_type *j_ptr, *q_ptr, forge;
+
+ /* Pick an item */
+ s16b i = rand_int(INVEN_PACK);
+
+ /* Obtain the item */
+ j_ptr = &p_ptr->inventory[i];
+
+ /* Accept real items */
+ if (!j_ptr->k_idx) continue;
+
+ /* Don't steal artifacts -CFT */
+ if (artifact_p(j_ptr)) continue;
+
+ /* Get a description */
+ object_desc(i_name, j_ptr, FALSE, 3);
+
+ /* Message */
+ msg_format("%sour %s (%c) was stolen!",
+ ((j_ptr->number > 1) ? "One of y" : "Y"),
+ i_name, index_to_label(i));
+
+ /* Create the item */
+ q_ptr = &forge;
+ object_copy(q_ptr, j_ptr);
+ q_ptr->number = 1;
+
+ /* Drop it somewhere */
+ do_trap_teleport_away(q_ptr, y, x);
+
+ inc_stack_size_ex(i, -1, OPTIMIZE, NO_DESCRIBE);
+
+ ident = TRUE;
+ }
+ break;
+ }
+
+ /* Summon Fast Quylthulgs Trap */
+ case TRAP_OF_SUMMON_FAST_QUYLTHULGS:
+ {
+ for (k = 0; k < randint(3); k++)
+ {
+ ident |= summon_specific(y, x, max_dlv[dungeon_type], SUMMON_QUYLTHULG);
+ }
+
+ if (ident)
+ {
+ msg_print("You suddenly have company.");
+ (void)set_slow(p_ptr->slow + randint(25) + 15);
+ }
+ break;
+ }
+
+ /* Trap of Sinking */
+ case TRAP_OF_SINKING:
+ {
+ msg_print("You fell through a trap door!");
+
+ if (p_ptr->ffall)
+ {
+ if (dungeon_flags1 & DF1_TOWER)
+ {
+ msg_print("You float gently down to the previous level.");
+ }
+ else
+ {
+ msg_print("You float gently down to the next level.");
+ }
+ }
+ else
+ {
+ take_hit(damroll(2, 8), "a trap door");
+ }
+
+ /* Still alive and autosave enabled */
+ if (p_ptr->chp >= 0)
+ {
+ autosave_checkpoint();
+ }
+
+ if (dungeon_flags1 & DF1_TOWER) dun_level--;
+ else dun_level++;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ break;
+ }
+
+ /* Trap of Mana Drain */
+ case TRAP_OF_MANA_DRAIN:
+ {
+ if (p_ptr->csp > 0)
+ {
+ p_ptr->csp = 0;
+ p_ptr->csp_frac = 0;
+ p_ptr->redraw |= (PR_MANA);
+ msg_print("You sense a great loss.");
+ ident = TRUE;
+ }
+ else if (p_ptr->msp == 0)
+ {
+ /* no sense saying this unless you never have mana */
+ msg_format("Suddenly you feel glad you're a mere %s",
+ spp_ptr->title + c_name);
+ }
+ else
+ {
+ msg_print("Your head feels dizzy for a moment.");
+ }
+ break;
+ }
+ /* Trap of Missing Money */
+ case TRAP_OF_MISSING_MONEY:
+ {
+ s32b gold = (p_ptr->au / 10) + randint(25);
+
+ if (gold < 2) gold = 2;
+ if (gold > 5000) gold = (p_ptr->au / 20) + randint(3000);
+ if (gold > p_ptr->au) gold = p_ptr->au;
+
+ p_ptr->au -= gold;
+ if (gold <= 0)
+ {
+ msg_print("You feel something touching you.");
+ }
+ else if (p_ptr->au)
+ {
+ msg_print("Your purse feels lighter.");
+ msg_format("%ld coins were stolen!", (long)gold);
+ ident = TRUE;
+ }
+ else
+ {
+ msg_print("Your purse feels empty.");
+ msg_print("All of your coins were stolen!");
+ ident = TRUE;
+ }
+ p_ptr->redraw |= (PR_GOLD);
+ break;
+ }
+
+ /* Trap of No Return */
+ case TRAP_OF_NO_RETURN:
+ {
+ object_type *j_ptr;
+ s16b j;
+
+ for (j = 0; j < INVEN_WIELD; j++)
+ {
+ if (!p_ptr->inventory[j].k_idx) continue;
+
+ j_ptr = &p_ptr->inventory[j];
+
+ if ((j_ptr->tval == TV_SCROLL) &&
+ (j_ptr->sval == SV_SCROLL_WORD_OF_RECALL))
+ {
+ inc_stack_size_ex(j, -j_ptr->number, OPTIMIZE, NO_DESCRIBE);
+
+ combine_pack();
+ reorder_pack();
+
+ if (!ident)
+ {
+ msg_print("A small fire works its way through your backpack. "
+ "Some scrolls are burnt.");
+ }
+ else
+ {
+ msg_print("The fire hasn't finished.");
+ }
+ ident = TRUE;
+ }
+ else if ((j_ptr->tval == TV_ROD_MAIN) &&
+ (j_ptr->pval == SV_ROD_RECALL))
+ {
+ j_ptr->timeout = 0; /* a long time */
+ if (!ident) msg_print("You feel the air stabilise around you.");
+ ident = TRUE;
+ }
+ }
+ if ((!ident) && (p_ptr->word_recall))
+ {
+ msg_print("You feel like staying around.");
+ p_ptr->word_recall = 0;
+ ident = TRUE;
+ }
+ break;
+ }
+
+ /* Trap of Silent Switching */
+ case TRAP_OF_SILENT_SWITCHING:
+ {
+ s16b i, j, slot1, slot2;
+ object_type *j_ptr, *k_ptr;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ j_ptr = &p_ptr->inventory[i];
+
+ if (!j_ptr->k_idx) continue;
+
+ /* Do not allow this trap to touch the One Ring */
+ object_flags(j_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if(f3 & TR3_PERMA_CURSE) continue;
+
+ slot1 = wield_slot(j_ptr);
+
+ for (j = 0; j < INVEN_WIELD; j++)
+ {
+ k_ptr = &p_ptr->inventory[j];
+
+ if (!k_ptr->k_idx) continue;
+
+ /* Do not allow this trap to touch the One Ring */
+ object_flags(k_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ if(f3 & TR3_PERMA_CURSE) continue;
+
+ /* this is a crude hack, but it prevent wielding 6 torches... */
+ if (k_ptr->number > 1) continue;
+
+ slot2 = wield_slot(k_ptr);
+
+ /* a chance of 4 in 5 of switching something, then 2 in 5 to do it again */
+ if ((slot1 == slot2) &&
+ (rand_int(100) < (80 - (ident * 40))))
+ {
+ object_type tmp_obj;
+
+ if (p_ptr->inventory[j].name1)
+ wield_set(p_ptr->inventory[j].name1, a_info[p_ptr->inventory[j].name1].set, FALSE);
+ if (p_ptr->inventory[i].name1)
+ takeoff_set(p_ptr->inventory[i].name1, a_info[p_ptr->inventory[i].name1].set);
+
+ tmp_obj = p_ptr->inventory[j];
+ p_ptr->inventory[j] = p_ptr->inventory[i];
+ p_ptr->inventory[i] = tmp_obj;
+ ident = TRUE;
+ }
+ }
+ }
+
+ if (ident)
+ {
+ p_ptr->update |= (PU_BONUS);
+ p_ptr->update |= (PU_TORCH);
+ p_ptr->update |= (PU_MANA);
+ msg_print("You somehow feel like another person.");
+ }
+ else
+ {
+ msg_print("You feel a lack of useful items.");
+ }
+ break;
+ }
+
+ /* Trap of Walls */
+ case TRAP_OF_WALLS:
+ {
+ ident = player_handle_trap_of_walls();
+ break;
+ }
+
+ /* Trap of Calling Out */
+ case TRAP_OF_CALLING_OUT:
+ {
+ ident = do_player_trap_call_out();
+
+ if (!ident)
+ {
+ /* Increase "afraid" */
+ if (p_ptr->resist_fear)
+ {
+ msg_print("You feel as if you had a nightmare!");
+ }
+ else if (rand_int(100) < p_ptr->skill_sav)
+ {
+ msg_print("You remember having a nightmare!");
+ }
+ else
+ {
+ if (set_afraid(p_ptr->afraid + 3 + randint(40)))
+ {
+ msg_print("You have a vision of a powerful enemy.");
+ }
+ }
+ }
+ break;
+ }
+
+ /* Trap of Sliding */
+ case TRAP_OF_SLIDING:
+ break;
+
+ /* Trap of Charges Drain */
+ case TRAP_OF_CHARGES_DRAIN:
+ {
+ /* Find an item */
+ for (k = 0; k < 10; k++)
+ {
+ s16b i = rand_int(INVEN_PACK);
+
+ object_type *j_ptr = &p_ptr->inventory[i];
+
+ /* Drain charged wands/staffs
+ Hack -- don't let artifacts get drained */
+ if (((j_ptr->tval == TV_STAFF) ||
+ (j_ptr->tval == TV_WAND)) &&
+ (j_ptr->pval) &&
+ !artifact_p(j_ptr))
+ {
+ ident = TRUE;
+ j_ptr->pval = j_ptr->pval / (randint(4) + 1);
+
+ /* 60% chance of only 1 */
+ if (randint(10) > 3) break;
+ }
+ }
+
+ if (ident)
+ {
+ /* Window stuff */
+ p_ptr->window |= PW_INVEN;
+ /* Combine / Reorder the pack */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ msg_print("Your backpack seems to be turned upside down.");
+ }
+ else
+ {
+ msg_print("You hear a wail of great disappointment.");
+ }
+ break;
+ }
+
+ /* Trap of Stair Movement */
+ case TRAP_OF_STAIR_MOVEMENT:
+ {
+ s16b cx, cy, i, j;
+ s16b cnt = 0;
+ s16b cnt_seen = 0;
+ s16b tmps, tmpx;
+ s16b tmpspecial, tmpspecial2;
+ u32b tmpf;
+ bool_ seen = FALSE;
+ s16b index_x[20], index_y[20]; /* 20 stairs per level is enough? */
+ cave_type *cv_ptr;
+
+ if (max_dlv[dungeon_type] == 99)
+ {
+ /* no sense in relocating that stair! */
+ msg_print("You have a feeling that this trap could be dangerous.");
+ break;
+ }
+
+ for (cx = 0; cx < cur_wid; cx++)
+ for (cy = 0; cy < cur_hgt; cy++)
+ {
+ cv_ptr = &cave[cy][cx];
+
+ if ((cv_ptr->feat != FEAT_LESS) &&
+ (cv_ptr->feat != FEAT_MORE) &&
+ (cv_ptr->feat != FEAT_SHAFT_UP) &&
+ (cv_ptr->feat != FEAT_SHAFT_DOWN)) continue;
+
+ index_x[cnt] = cx;
+ index_y[cnt] = cy;
+ cnt++;
+ }
+
+ if (cnt == 0)
+ {
+ if (wizard) msg_print("Executing moving stairs trap on level with no stairs!");
+ break;
+ }
+
+ for (i = 0; i < cnt; i++)
+ {
+ seen = FALSE;
+
+ for (j = 0; j < 10; j++) /* try 10 times to relocate */
+ {
+ cave_type *cv_ptr = &cave[index_y[i]][index_x[i]];
+ cave_type *cv_ptr2;
+
+ cx = rand_int(cur_wid);
+ cy = rand_int(cur_hgt);
+
+ if ((cx == index_x[i]) || (cy == index_y[i])) continue;
+
+ cv_ptr2 = &cave[cy][cx];
+
+ if (!cave_valid_bold(cy, cx) || cv_ptr2->o_idx != 0) continue;
+
+ /* don't put anything in vaults */
+ if (cv_ptr2->info & CAVE_ICKY) continue;
+
+ tmpx = cv_ptr2->mimic;
+ tmps = cv_ptr2->info;
+ tmpf = cv_ptr2->feat;
+ tmpspecial = cv_ptr2->special;
+ tmpspecial2 = cv_ptr2->special2;
+ cave[cy][cx].mimic = cv_ptr->mimic;
+ cave[cy][cx].info = cv_ptr->info;
+ cave[cy][cx].special = cv_ptr->special;
+ cave[cy][cx].special2 = cv_ptr->special2;
+ cave_set_feat(cy, cx, cv_ptr->feat);
+ cv_ptr->mimic = tmpx;
+ cv_ptr->info = tmps;
+ cv_ptr->special = tmpspecial;
+ cv_ptr->special2 = tmpspecial2;
+ cave_set_feat(index_y[i], index_x[i], tmpf);
+
+ /* if we are placing walls in rooms, make them rubble instead */
+ if ((cv_ptr->info & CAVE_ROOM) &&
+ (cv_ptr->feat >= FEAT_WALL_EXTRA) &&
+ (cv_ptr->feat <= FEAT_PERM_SOLID))
+ {
+ cave_set_feat(index_y[i], index_x[i], FEAT_RUBBLE);
+ }
+
+ if (player_has_los_bold(cy, cx))
+ {
+ note_spot(cy, cx);
+ lite_spot(cy, cx);
+ seen = TRUE;
+ }
+ else
+ {
+ cv_ptr2->info &= ~CAVE_MARK;
+ }
+
+ if (player_has_los_bold(index_y[i], index_x[i]))
+ {
+ note_spot(index_y[i], index_x[i]);
+ lite_spot(index_y[i], index_x[i]);
+ seen = TRUE;
+ }
+ else
+ {
+ cv_ptr->info &= ~CAVE_MARK;
+ }
+ break;
+ }
+
+ if (seen) cnt_seen++;
+ }
+
+ ident = (cnt_seen > 0);
+
+ if ((ident) && (cnt_seen > 1))
+ {
+ msg_print("You see some stairs move.");
+ }
+ else if (ident)
+ {
+ msg_print("You see a stair move.");
+ }
+ else
+ {
+ msg_print("You hear distant scraping noises.");
+ }
+ p_ptr->redraw |= PR_MAP;
+ break;
+ }
+
+ /* Trap of New Trap */
+ case TRAP_OF_NEW:
+ {
+ /* if we're on a floor or on a door, place a new trap */
+ if ((item == -1) || (item == -2))
+ {
+ place_trap(y, x);
+ if (player_has_los_bold(y, x))
+ {
+ note_spot(y, x);
+ lite_spot(y, x);
+ }
+ }
+ else
+ {
+ /* re-trap the chest */
+ place_trap(y, x);
+ }
+ msg_print("You hear a noise, and then its echo.");
+ ident = FALSE;
+ break;
+ }
+
+ /* Trap of Acquirement */
+ case TRAP_OF_ACQUIREMENT:
+ {
+ /* Get a nice thing */
+ msg_print("You notice something falling off the trap.");
+ acquirement(y, x, 1, TRUE, FALSE);
+
+ /* If we're on a floor or on a door, place a new trap */
+ if ((item == -1) || (item == -2))
+ {
+ place_trap(y, x);
+ if (player_has_los_bold(y, x))
+ {
+ note_spot(y, x);
+ lite_spot(y, x);
+ }
+ }
+ else
+ {
+ /* Re-trap the chest */
+ place_trap(y, x);
+ }
+ msg_print("You hear a noise, and then its echo.");
+
+ /* Never known */
+ ident = FALSE;
+ }
+ break;
+
+ /* Trap of Scatter Items */
+ case TRAP_OF_SCATTER_ITEMS:
+ {
+ s16b i, j;
+ bool_ message = FALSE;
+
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+
+ if (!p_ptr->inventory[i].k_idx) continue;
+
+ if (rand_int(10) < 3) continue;
+
+ for (j = 0; j < 10; j++)
+ {
+ object_type tmp_obj, *j_ptr = &tmp_obj;
+ s16b cx = x + 15 - rand_int(30);
+ s16b cy = y + 15 - rand_int(30);
+
+ if (!in_bounds(cy, cx)) continue;
+
+ if (!cave_floor_bold(cy, cx)) continue;
+
+ object_copy(j_ptr, &p_ptr->inventory[i]);
+
+ inc_stack_size_ex(i, -999, OPTIMIZE, NO_DESCRIBE);
+
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ (void)floor_carry(cy, cx, j_ptr);
+
+ if (!message)
+ {
+ msg_print("You feel light-footed.");
+ message = TRUE;
+ }
+
+ if (player_has_los_bold(cy, cx))
+ {
+ char i_name[80];
+
+ object_desc(i_name, &tmp_obj, TRUE, 3);
+ note_spot(cy, cx);
+ lite_spot(cy, cx);
+ ident = TRUE;
+ msg_format("Suddenly %s appear%s!", i_name,
+ (j_ptr->number > 1) ? "" : "s");
+ }
+ break;
+ }
+ }
+ ident = message;
+ break;
+ }
+
+ /* Trap of Decay */
+ case TRAP_OF_DECAY:
+ break;
+
+ /* Trap of Wasting Wands */
+ case TRAP_OF_WASTING_WANDS:
+ {
+ s16b i;
+ object_type *j_ptr;
+
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ if (!p_ptr->inventory[i].k_idx) continue;
+
+ j_ptr = &p_ptr->inventory[i];
+
+ if ((j_ptr->tval == TV_WAND) && (rand_int(5) == 1))
+ {
+ if (object_known_p(j_ptr)) ident = TRUE;
+
+ /* Create a Wand of Nothing */
+ object_prep(j_ptr, lookup_kind(TV_WAND, SV_WAND_NOTHING));
+ hack_apply_magic_power = -99;
+ apply_magic(j_ptr, 0, FALSE, FALSE, FALSE);
+ j_ptr->ident &= ~IDENT_KNOWN;
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+ }
+ else if ((j_ptr->tval == TV_STAFF) && (rand_int(5) == 1))
+ {
+ if (object_known_p(j_ptr)) ident = TRUE;
+
+ /* Create a Staff of Nothing */
+ object_prep(j_ptr, lookup_kind(TV_STAFF, SV_STAFF_NOTHING));
+ hack_apply_magic_power = -99;
+ apply_magic(j_ptr, 0, FALSE, FALSE, FALSE);
+ j_ptr->ident &= ~IDENT_KNOWN;
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+ }
+ }
+ if (ident)
+ {
+ msg_print("You have lost trust in your backpack!");
+ }
+ else
+ {
+ msg_print("You hear an echoing cry of rage.");
+ }
+ break;
+ }
+
+ /* Trap of Filling */
+ case TRAP_OF_FILLING:
+ {
+ s16b nx, ny;
+
+ for (nx = x - 8; nx <= x + 8; nx++)
+ for (ny = y - 8; ny <= y + 8; ny++)
+ {
+ if (!in_bounds (ny, nx)) continue;
+
+ if (rand_int(distance(ny, nx, y, x)) > 3)
+ {
+ place_trap(ny, nx);
+ }
+ }
+
+ msg_print("The floor vibrates in a strange way.");
+ ident = FALSE;
+ break;
+ }
+
+ case TRAP_OF_DRAIN_SPEED:
+ {
+ object_type *j_ptr;
+ s16b j, chance = 75;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ for (j = 0; j < INVEN_TOTAL; j++)
+ {
+ /* don't bother the overflow slot */
+ if (j == INVEN_PACK) continue;
+
+ if (!p_ptr->inventory[j].k_idx) continue;
+
+ j_ptr = &p_ptr->inventory[j];
+ object_flags(j_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* is it a non-artifact speed item? */
+ if ((!j_ptr->name1) && (f1 & TR1_SPEED))
+ {
+ if (randint(100) < chance)
+ {
+ j_ptr->pval = j_ptr->pval / 2;
+ if (j_ptr->pval == 0)
+ {
+ j_ptr->pval--;
+ }
+ chance /= 2;
+ ident = TRUE;
+ }
+ inven_item_optimize(j);
+ }
+ }
+ if (!ident)
+ {
+ msg_print("You feel some things in your pack vibrating.");
+ }
+ else
+ {
+ combine_pack();
+ reorder_pack();
+ msg_print("You suddenly feel you have time for self-reflection.");
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Recalculate mana */
+ p_ptr->update |= (PU_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ }
+ break;
+ }
+
+ /*
+ * single missile traps
+ */
+ case TRAP_OF_ARROW_I:
+ ident = player_handle_missile_trap(1, TV_ARROW, SV_AMMO_NORMAL, 4, 8, 0, "Arrow Trap");
+ break;
+ case TRAP_OF_ARROW_II:
+ ident = player_handle_missile_trap(1, TV_BOLT, SV_AMMO_NORMAL, 5, 8, 0, "Bolt Trap");
+ break;
+ case TRAP_OF_ARROW_III:
+ ident = player_handle_missile_trap(1, TV_ARROW, SV_AMMO_HEAVY, 6, 8, 0, "Seeker Arrow Trap");
+ break;
+ case TRAP_OF_ARROW_IV:
+ ident = player_handle_missile_trap(1, TV_BOLT, SV_AMMO_HEAVY, 8, 10, 0, "Seeker Bolt Trap");
+ break;
+ case TRAP_OF_POISON_ARROW_I:
+ ident = player_handle_missile_trap(1, TV_ARROW, SV_AMMO_NORMAL, 4, 8, 10 + randint(20), "Poison Arrow Trap");
+ break;
+ case TRAP_OF_POISON_ARROW_II:
+ ident = player_handle_missile_trap(1, TV_BOLT, SV_AMMO_NORMAL, 5, 8, 15 + randint(30), "Poison Bolt Trap");
+ break;
+ case TRAP_OF_POISON_ARROW_III:
+ ident = player_handle_missile_trap(1, TV_ARROW, SV_AMMO_HEAVY, 6, 8, 30 + randint(50), "Poison Seeker Arrow Trap");
+ break;
+ case TRAP_OF_POISON_ARROW_IV:
+ ident = player_handle_missile_trap(1, TV_BOLT, SV_AMMO_HEAVY, 8, 10, 40 + randint(70), "Poison Seeker Bolt Trap");
+ break;
+ case TRAP_OF_DAGGER_I:
+ ident = player_handle_missile_trap(1, TV_SWORD, SV_BROKEN_DAGGER, 2, 8, 0, "Dagger Trap");
+ break;
+ case TRAP_OF_DAGGER_II:
+ ident = player_handle_missile_trap(1, TV_SWORD, SV_DAGGER, 3, 8, 0, "Dagger Trap");
+ break;
+ case TRAP_OF_POISON_DAGGER_I:
+ ident = player_handle_missile_trap(1, TV_SWORD, SV_BROKEN_DAGGER, 2, 8, 15 + randint(20), "Poison Dagger Trap");
+ break;
+ case TRAP_OF_POISON_DAGGER_II:
+ ident = player_handle_missile_trap(1, TV_SWORD, SV_DAGGER, 3, 8, 20 + randint(30), "Poison Dagger Trap");
+ break;
+
+ /*
+ * multiple missile traps
+ * numbers range from 2 (level 0 to 14) to 10 (level 120 and up)
+ */
+ case TRAP_OF_ARROWS_I:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_ARROW, SV_AMMO_NORMAL, 4, 8, 0, "Arrow Trap");
+ break;
+ case TRAP_OF_ARROWS_II:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_BOLT, SV_AMMO_NORMAL, 5, 8, 0, "Bolt Trap");
+ break;
+ case TRAP_OF_ARROWS_III:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_ARROW, SV_AMMO_HEAVY, 6, 8, 0, "Seeker Arrow Trap");
+ break;
+ case TRAP_OF_ARROWS_IV:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_BOLT, SV_AMMO_HEAVY, 8, 10, 0, "Seeker Bolt Trap");
+ break;
+ case TRAP_OF_POISON_ARROWS_I:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_ARROW, SV_AMMO_NORMAL, 4, 8, 10 + randint(20), "Poison Arrow Trap");
+ break;
+ case TRAP_OF_POISON_ARROWS_II:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_BOLT, SV_AMMO_NORMAL, 5, 8, 15 + randint(30), "Poison Bolt Trap");
+ break;
+ case TRAP_OF_POISON_ARROWS_III:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_ARROW, SV_AMMO_HEAVY, 6, 8, 30 + randint(50), "Poison Seeker Arrow Trap");
+ break;
+ case TRAP_OF_POISON_ARROWS_IV:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_BOLT, SV_AMMO_HEAVY, 8, 10, 40 + randint(70), "Poison Seeker Bolt Trap");
+ break;
+ case TRAP_OF_DAGGERS_I:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_SWORD, SV_BROKEN_DAGGER, 2, 8, 0, "Dagger Trap");
+ break;
+ case TRAP_OF_DAGGERS_II:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_SWORD, SV_DAGGER, 3, 8, 0, "Dagger Trap");
+ break;
+ case TRAP_OF_POISON_DAGGERS_I:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_SWORD, SV_BROKEN_DAGGER, 2, 8, 15 + randint(20), "Poison Dagger Trap");
+ break;
+ case TRAP_OF_POISON_DAGGERS_II:
+ ident = player_handle_missile_trap(2 + (max_dlv[dungeon_type] / 15), TV_SWORD, SV_DAGGER, 3, 8, 20 + randint(30), "Poison Dagger Trap");
+ break;
+
+ case TRAP_OF_DROP_ITEMS:
+ {
+ s16b i;
+ bool_ message = FALSE;
+
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ object_type tmp_obj;
+
+ if (!p_ptr->inventory[i].k_idx) continue;
+ if (randint(100) < 80) continue;
+ if (p_ptr->inventory[i].name1 == ART_POWER) continue;
+
+ tmp_obj = p_ptr->inventory[i];
+
+ /* drop carefully */
+ drop_near(&tmp_obj, 0, y, x);
+
+ inc_stack_size_ex(i, -999, OPTIMIZE, NO_DESCRIBE);
+
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ if (!message)
+ {
+ msg_print("You are startled by a sudden sound.");
+ message = TRUE;
+ }
+ ident = TRUE;
+ }
+ if (!ident)
+ {
+ msg_print("You hear a sudden, strange sound.");
+ }
+ break;
+ }
+
+ case TRAP_OF_DROP_ALL_ITEMS:
+ {
+ s16b i;
+ bool_ message = FALSE;
+
+ for (i = 0; i < INVEN_PACK; i++)
+ {
+ object_type tmp_obj;
+
+ if (!p_ptr->inventory[i].k_idx) continue;
+ if (randint(100) < 10) continue;
+ if (p_ptr->inventory[i].name1 == ART_POWER) continue;
+
+ tmp_obj = p_ptr->inventory[i];
+
+ /* drop carefully */
+ drop_near(&tmp_obj, 0, y, x);
+
+ inc_stack_size_ex(i, -999, OPTIMIZE, NO_DESCRIBE);
+
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ if (!message)
+ {
+ msg_print("You are greatly startled by a sudden sound.");
+ message = TRUE;
+ }
+ ident = TRUE;
+ }
+ if (!ident)
+ {
+ msg_print("You hear a sudden, strange sound.");
+ }
+ break;
+ }
+
+ case TRAP_OF_DROP_EVERYTHING:
+ {
+ s16b i;
+ bool_ message = FALSE;
+
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type tmp_obj;
+ if (!p_ptr->inventory[i].k_idx) continue;
+ if (randint(100) < 30) continue;
+ if (p_ptr->inventory[i].name1 == ART_POWER) continue;
+
+ tmp_obj = p_ptr->inventory[i];
+ /* drop carefully */
+
+ drop_near(&tmp_obj, 0, y, x);
+
+ inc_stack_size_ex(i, -999, OPTIMIZE, NO_DESCRIBE);
+
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ if (!message)
+ {
+ msg_print("You are completely startled by a sudden sound.");
+ message = TRUE;
+ }
+ ident = TRUE;
+ }
+ if (!ident)
+ {
+ msg_print("You hear a sudden, strange sound.");
+ }
+ break;
+ }
+
+ /* Bolt Trap */
+ case TRAP_G_ELEC_BOLT:
+ ident = player_handle_breath_trap(1, GF_ELEC, TRAP_G_ELEC_BOLT);
+ break;
+ case TRAP_G_POIS_BOLT:
+ ident = player_handle_breath_trap(1, GF_POIS, TRAP_G_POIS_BOLT);
+ break;
+ case TRAP_G_ACID_BOLT:
+ ident = player_handle_breath_trap(1, GF_ACID, TRAP_G_ACID_BOLT);
+ break;
+ case TRAP_G_COLD_BOLT:
+ ident = player_handle_breath_trap(1, GF_COLD, TRAP_G_COLD_BOLT);
+ break;
+ case TRAP_G_FIRE_BOLT:
+ ident = player_handle_breath_trap(1, GF_FIRE, TRAP_G_FIRE_BOLT);
+ break;
+ case TRAP_OF_ELEC_BOLT:
+ ident = player_handle_breath_trap(1, GF_ELEC, TRAP_OF_ELEC_BOLT);
+ break;
+ case TRAP_OF_POIS_BOLT:
+ ident = player_handle_breath_trap(1, GF_POIS, TRAP_OF_POIS_BOLT);
+ break;
+ case TRAP_OF_ACID_BOLT:
+ ident = player_handle_breath_trap(1, GF_ACID, TRAP_OF_ACID_BOLT);
+ break;
+ case TRAP_OF_COLD_BOLT:
+ ident = player_handle_breath_trap(1, GF_COLD, TRAP_OF_COLD_BOLT);
+ break;
+ case TRAP_OF_FIRE_BOLT:
+ ident = player_handle_breath_trap(1, GF_FIRE, TRAP_OF_FIRE_BOLT);
+ break;
+ case TRAP_OF_PLASMA_BOLT:
+ ident = player_handle_breath_trap(1, GF_PLASMA, TRAP_OF_PLASMA_BOLT);
+ break;
+ case TRAP_OF_WATER_BOLT:
+ ident = player_handle_breath_trap(1, GF_WATER, TRAP_OF_WATER_BOLT);
+ break;
+ case TRAP_OF_LITE_BOLT:
+ ident = player_handle_breath_trap(1, GF_LITE, TRAP_OF_LITE_BOLT);
+ break;
+ case TRAP_OF_DARK_BOLT:
+ ident = player_handle_breath_trap(1, GF_DARK, TRAP_OF_DARK_BOLT);
+ break;
+ case TRAP_OF_SHARDS_BOLT:
+ ident = player_handle_breath_trap(1, GF_SHARDS, TRAP_OF_SHARDS_BOLT);
+ break;
+ case TRAP_OF_SOUND_BOLT:
+ ident = player_handle_breath_trap(1, GF_SOUND, TRAP_OF_SOUND_BOLT);
+ break;
+ case TRAP_OF_CONFUSION_BOLT:
+ ident = player_handle_breath_trap(1, GF_CONFUSION, TRAP_OF_CONFUSION_BOLT);
+ break;
+ case TRAP_OF_FORCE_BOLT:
+ ident = player_handle_breath_trap(1, GF_FORCE, TRAP_OF_FORCE_BOLT);
+ break;
+ case TRAP_OF_INERTIA_BOLT:
+ ident = player_handle_breath_trap(1, GF_INERTIA, TRAP_OF_INERTIA_BOLT);
+ break;
+ case TRAP_OF_MANA_BOLT:
+ ident = player_handle_breath_trap(1, GF_MANA, TRAP_OF_MANA_BOLT);
+ break;
+ case TRAP_OF_ICE_BOLT:
+ ident = player_handle_breath_trap(1, GF_ICE, TRAP_OF_ICE_BOLT);
+ break;
+ case TRAP_OF_CHAOS_BOLT:
+ ident = player_handle_breath_trap(1, GF_CHAOS, TRAP_OF_CHAOS_BOLT);
+ break;
+ case TRAP_OF_NETHER_BOLT:
+ ident = player_handle_breath_trap(1, GF_NETHER, TRAP_OF_NETHER_BOLT);
+ break;
+ case TRAP_OF_DISENCHANT_BOLT:
+ ident = player_handle_breath_trap(1, GF_DISENCHANT, TRAP_OF_DISENCHANT_BOLT);
+ break;
+ case TRAP_OF_NEXUS_BOLT:
+ ident = player_handle_breath_trap(1, GF_NEXUS, TRAP_OF_NEXUS_BOLT);
+ break;
+ case TRAP_OF_TIME_BOLT:
+ ident = player_handle_breath_trap(1, GF_TIME, TRAP_OF_TIME_BOLT);
+ break;
+ case TRAP_OF_GRAVITY_BOLT:
+ ident = player_handle_breath_trap(1, GF_GRAVITY, TRAP_OF_GRAVITY_BOLT);
+ break;
+
+ /* Ball Trap */
+ case TRAP_OF_ELEC_BALL:
+ ident = player_handle_breath_trap(3, GF_ELEC, TRAP_OF_ELEC_BALL);
+ break;
+ case TRAP_OF_POIS_BALL:
+ ident = player_handle_breath_trap(3, GF_POIS, TRAP_OF_POIS_BALL);
+ break;
+ case TRAP_OF_ACID_BALL:
+ ident = player_handle_breath_trap(3, GF_ACID, TRAP_OF_ACID_BALL);
+ break;
+ case TRAP_OF_COLD_BALL:
+ ident = player_handle_breath_trap(3, GF_COLD, TRAP_OF_COLD_BALL);
+ break;
+ case TRAP_OF_FIRE_BALL:
+ ident = player_handle_breath_trap(3, GF_FIRE, TRAP_OF_FIRE_BALL);
+ break;
+ case TRAP_OF_PLASMA_BALL:
+ ident = player_handle_breath_trap(3, GF_PLASMA, TRAP_OF_PLASMA_BALL);
+ break;
+ case TRAP_OF_WATER_BALL:
+ ident = player_handle_breath_trap(3, GF_WATER, TRAP_OF_WATER_BALL);
+ break;
+ case TRAP_OF_LITE_BALL:
+ ident = player_handle_breath_trap(3, GF_LITE, TRAP_OF_LITE_BALL);
+ break;
+ case TRAP_OF_DARK_BALL:
+ ident = player_handle_breath_trap(3, GF_DARK, TRAP_OF_DARK_BALL);
+ break;
+ case TRAP_OF_SHARDS_BALL:
+ ident = player_handle_breath_trap(3, GF_SHARDS, TRAP_OF_SHARDS_BALL);
+ break;
+ case TRAP_OF_SOUND_BALL:
+ ident = player_handle_breath_trap(3, GF_SOUND, TRAP_OF_SOUND_BALL);
+ break;
+ case TRAP_OF_CONFUSION_BALL:
+ ident = player_handle_breath_trap(3, GF_CONFUSION, TRAP_OF_CONFUSION_BALL);
+ break;
+ case TRAP_OF_FORCE_BALL:
+ ident = player_handle_breath_trap(3, GF_FORCE, TRAP_OF_FORCE_BALL);
+ break;
+ case TRAP_OF_INERTIA_BALL:
+ ident = player_handle_breath_trap(3, GF_INERTIA, TRAP_OF_INERTIA_BALL);
+ break;
+ case TRAP_OF_MANA_BALL:
+ ident = player_handle_breath_trap(3, GF_MANA, TRAP_OF_MANA_BALL);
+ break;
+ case TRAP_OF_ICE_BALL:
+ ident = player_handle_breath_trap(3, GF_ICE, TRAP_OF_ICE_BALL);
+ break;
+ case TRAP_OF_CHAOS_BALL:
+ ident = player_handle_breath_trap(3, GF_CHAOS, TRAP_OF_CHAOS_BALL);
+ break;
+ case TRAP_OF_NETHER_BALL:
+ ident = player_handle_breath_trap(3, GF_NETHER, TRAP_OF_NETHER_BALL);
+ break;
+ case TRAP_OF_DISENCHANT_BALL:
+ ident = player_handle_breath_trap(3, GF_DISENCHANT, TRAP_OF_DISENCHANT_BALL);
+ break;
+ case TRAP_OF_NEXUS_BALL:
+ ident = player_handle_breath_trap(3, GF_NEXUS, TRAP_OF_NEXUS_BALL);
+ break;
+ case TRAP_OF_TIME_BALL:
+ ident = player_handle_breath_trap(3, GF_TIME, TRAP_OF_TIME_BALL);
+ break;
+ case TRAP_OF_GRAVITY_BALL:
+ ident = player_handle_breath_trap(3, GF_GRAVITY, TRAP_OF_GRAVITY_BALL);
+ break;
+
+ /* -SC- */
+ case TRAP_OF_FEMINITY:
+ {
+ msg_print("Gas sprouts out... you feel yourself transmute.");
+ p_ptr->psex = SEX_FEMALE;
+ sp_ptr = &sex_info[p_ptr->psex];
+ ident = TRUE;
+ trap_hit(trap);
+ break;
+ }
+
+ case TRAP_OF_MASCULINITY:
+ {
+ msg_print("Gas sprouts out... you feel yourself transmute.");
+ p_ptr->psex = SEX_MALE;
+ sp_ptr = &sex_info[p_ptr->psex];
+ ident = TRUE;
+ trap_hit(trap);
+ break;
+ }
+
+ case TRAP_OF_NEUTRALITY:
+ {
+ msg_print("Gas sprouts out... you feel yourself transmute.");
+ p_ptr->psex = SEX_NEUTER;
+ sp_ptr = &sex_info[p_ptr->psex];
+ ident = TRUE;
+ trap_hit(trap);
+ break;
+ }
+
+ case TRAP_OF_AGING:
+ {
+ msg_print("Colors are scintillating around you. "
+ "You see your past running before your eyes.");
+ p_ptr->age += randint((rp_ptr->b_age + rmp_ptr->b_age) / 2);
+ ident = TRUE;
+ trap_hit(trap);
+ break;
+ }
+
+ case TRAP_OF_GROWING:
+ {
+ s16b tmp;
+
+ msg_print("Heavy fumes sprout out... you feel yourself transmute.");
+ if (p_ptr->psex == SEX_FEMALE) tmp = rp_ptr->f_b_ht + rmp_ptr->f_b_ht;
+ else tmp = rp_ptr->m_b_ht + rmp_ptr->m_b_ht;
+
+ p_ptr->ht += randint(tmp / 4);
+ ident = TRUE;
+ trap_hit(trap);
+ break;
+ }
+
+ case TRAP_OF_SHRINKING:
+ {
+ s16b tmp;
+
+ msg_print("Heavy fumes sprout out... you feel yourself transmute.");
+ if (p_ptr->psex == SEX_FEMALE) tmp = rp_ptr->f_b_ht + rmp_ptr->f_b_ht;
+ else tmp = rp_ptr->m_b_ht + rmp_ptr->m_b_ht;
+
+ p_ptr->ht -= randint(tmp / 4);
+ if (p_ptr->ht <= tmp / 4) p_ptr->ht = tmp / 4;
+ ident = TRUE;
+ trap_hit(trap);
+ break;
+ }
+
+ /* Trap of Divine Anger */
+ case TRAP_OF_DIVINE_ANGER:
+ {
+ if (p_ptr->pgod == 0)
+ {
+ msg_format("Suddenly you feel glad you're a mere %s", spp_ptr->title + c_name);
+ }
+ else
+ {
+ cptr name;
+
+ name = deity_info[p_ptr->pgod].name;
+ msg_format("You feel you have angered %s.", name);
+ inc_piety(p_ptr->pgod, -3000);
+ }
+ break;
+ }
+
+ /* Trap of Divine Wrath */
+ case TRAP_OF_DIVINE_WRATH:
+ {
+ if (p_ptr->pgod == 0)
+ {
+ msg_format("Suddenly you feel glad you're a mere %s", spp_ptr->title + c_name);
+ }
+ else
+ {
+ cptr name;
+
+ name = deity_info[p_ptr->pgod].name;
+
+ msg_format("%s quakes in rage: ``Thou art supremely insolent, mortal!!''", name);
+ inc_piety(p_ptr->pgod, -500 * p_ptr->lev);
+ }
+ break;
+ }
+
+ /* Trap of hallucination */
+ case TRAP_OF_HALLUCINATION:
+ {
+ msg_print("Scintillating colors hypnotise you for a moment.");
+
+ set_image(80);
+ }
+ break;
+
+ /* Bolt Trap */
+ case TRAP_OF_ROCKET:
+ ident = player_handle_breath_trap(1, GF_ROCKET, trap);
+ break;
+ case TRAP_OF_NUKE_BOLT:
+ ident = player_handle_breath_trap(1, GF_NUKE, trap);
+ break;
+ case TRAP_OF_HOLY_FIRE:
+ ident = player_handle_breath_trap(1, GF_HOLY_FIRE, trap);
+ break;
+ case TRAP_OF_HELL_FIRE:
+ ident = player_handle_breath_trap(1, GF_HELL_FIRE, trap);
+ break;
+ case TRAP_OF_PSI_BOLT:
+ ident = player_handle_breath_trap(1, GF_PSI, trap);
+ break;
+ case TRAP_OF_PSI_DRAIN:
+ ident = player_handle_breath_trap(1, GF_PSI_DRAIN, trap);
+ break;
+
+ /* Ball Trap */
+ case TRAP_OF_NUKE_BALL:
+ ident = player_handle_breath_trap(3, GF_NUKE, TRAP_OF_NUKE_BALL);
+ break;
+ case TRAP_OF_PSI_BALL:
+ ident = player_handle_breath_trap(3, GF_PSI, TRAP_OF_NUKE_BALL);
+ break;
+
+ default:
+ {
+ msg_print(format("Executing unknown trap %d", trap));
+ }
+ }
+ return ident;
+}
+
+void player_activate_door_trap(s16b y, s16b x)
+{
+ cave_type *c_ptr;
+ bool_ ident = FALSE;
+
+ c_ptr = &cave[y][x];
+
+ /* Return if trap or door not found */
+ if ((c_ptr->t_idx == 0) ||
+ !(f_info[c_ptr->feat].flags1 & FF1_DOOR)) return;
+
+ /* Disturb */
+ disturb(0, 0);
+
+ /* Message */
+ msg_print("You found a trap!");
+
+ /* Pick a trap */
+ pick_trap(y, x);
+
+ /* Hit the trap */
+ ident = player_activate_trap_type(y, x, NULL, -1);
+ if (ident)
+ {
+ t_info[c_ptr->t_idx].ident = TRUE;
+ msg_format("You identified that trap as %s.",
+ t_name + t_info[c_ptr->t_idx].name);
+ }
+}
+
+
+/*
+ * Places a random trap at the given location.
+ *
+ * The location must be a valid, empty, clean, floor grid.
+ */
+void place_trap(int y, int x)
+{
+ s16b trap;
+ trap_type *t_ptr;
+ int cnt;
+ u32b flags;
+ cave_type *c_ptr = &cave[y][x];
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ /* No traps in town or on first level */
+ if (dun_level <= 1) return;
+
+ /*
+ * Avoid open doors -- because DOOR flag is added to make much more
+ * important processing faster
+ */
+ if (c_ptr->feat == FEAT_OPEN) return;
+ if (c_ptr->feat == FEAT_BROKEN) return;
+
+ /* Traps only appears on empty floor */
+ if (!cave_floor_grid(c_ptr) &&
+ !(f_info[c_ptr->feat].flags1 & (FF1_DOOR))) return;
+
+ /* Set flags */
+ if (f_info[c_ptr->feat].flags1 & FF1_DOOR) flags = FTRAP_DOOR;
+ else flags = FTRAP_FLOOR;
+
+ /* Try 100 times */
+ cnt = 100;
+ while (cnt--)
+ {
+ trap = randint(max_t_idx - 1);
+ t_ptr = &t_info[trap];
+
+ /* No traps below their minlevel */
+ if (t_ptr->minlevel > dun_level) continue;
+
+ /* is this a correct trap now? */
+ if (!(t_ptr->flags & flags)) continue;
+
+ /*
+ * Hack -- No trap door at the bottom of dungeon or in flat
+ * (non dungeon) places or on quest levels
+ */
+ if ((trap == TRAP_OF_SINKING) &&
+ ((d_ptr->maxdepth == dun_level) ||
+ (dungeon_flags1 & DF1_FLAT) || (is_quest(dun_level))) )
+ {
+ continue;
+ }
+
+ /* How probable is this trap */
+ if (rand_int(100) < t_ptr->probability)
+ {
+ c_ptr->t_idx = trap;
+ break;
+ }
+ }
+
+ return;
+}
+
+
+/*
+ * Places a random trap on the given chest.
+ *
+ * The object must be a valid chest.
+ */
+void place_trap_object(object_type *o_ptr)
+{
+ s16b trap;
+ trap_type *t_ptr;
+ int cnt;
+
+ /* No traps in town or on first level */
+ if (dun_level <= 1)
+ {
+ /* empty chest were already looted, therefore known */
+ o_ptr->ident |= IDENT_KNOWN;
+ return;
+ }
+
+ /* Try 100 times */
+ cnt = 100;
+ while (cnt--)
+ {
+ trap = randint(max_t_idx - 1);
+ t_ptr = &t_info[trap];
+
+ /* no traps below their minlevel */
+ if (t_ptr->minlevel > dun_level) continue;
+
+ /* Is this a correct trap now? */
+ if (!(t_ptr->flags & FTRAP_CHEST)) continue;
+
+ /* How probable is this trap */
+ if (rand_int(100) < t_ptr->probability)
+ {
+ o_ptr->pval = trap;
+ break;
+ }
+ }
+
+ return;
+}
+
+/* Dangerous trap placing function */
+void wiz_place_trap(int y, int x, int idx)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Dangerous enough as it is... */
+ if (!cave_floor_grid(c_ptr) && (!(f_info[c_ptr->feat].flags1 & FF1_DOOR))) return;
+
+ c_ptr->t_idx = idx;
+}
+
+/*
+ * Here begin monster traps code
+ */
+
+/*
+ * Hook to determine if an object is a device
+ */
+static bool_ item_tester_hook_device(object_type *o_ptr)
+{
+ if (((o_ptr->tval == TV_ROD_MAIN) && (o_ptr->pval != 0)) ||
+ (o_ptr->tval == TV_STAFF) ||
+ (o_ptr->tval == TV_WAND)) return (TRUE);
+
+ /* Assume not */
+ return (FALSE);
+}
+
+/*
+ * Hook to determine if an object is a potion
+ */
+static bool_ item_tester_hook_potion(object_type *o_ptr)
+{
+ if ((o_ptr->tval == TV_POTION) ||
+ (o_ptr->tval == TV_POTION2)) return (TRUE);
+
+ /* Assume not */
+ return (FALSE);
+}
+
+/*
+ * The trap setting code for rogues -MWK-
+ *
+ * Also, it will fail or give weird results if the tvals are resorted!
+ */
+void do_cmd_set_trap(void)
+{
+ int item_kit, item_load, i;
+ int num;
+
+ object_type *o_ptr, *j_ptr, *i_ptr;
+
+ cptr q, s, c;
+
+ object_type object_type_body;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Check some conditions */
+ if (p_ptr->blind)
+ {
+ msg_print("You can't see anything.");
+ return;
+ }
+ if (no_lite())
+ {
+ msg_print("You don't dare to set a trap in the darkness.");
+ return;
+ }
+ if (p_ptr->confused)
+ {
+ msg_print("You are too confused!");
+ return;
+ }
+
+ /* Only set traps on clean floor grids */
+ if (!cave_clean_bold(p_ptr->py, p_ptr->px))
+ {
+ msg_print("You cannot set a trap on this.");
+ return;
+ }
+
+ /* Restrict choices to trapkits */
+ item_tester_tval = TV_TRAPKIT;
+
+ /* Get an item */
+ q = "Use which trapping kit? ";
+ s = "You have no trapping kits.";
+ if (!get_item(&item_kit, q, s, USE_INVEN)) return;
+
+ o_ptr = &p_ptr->inventory[item_kit];
+
+ /* Trap kits need a second object */
+ switch (o_ptr->sval)
+ {
+ case SV_TRAPKIT_BOW:
+ item_tester_tval = TV_ARROW;
+ break;
+ case SV_TRAPKIT_XBOW:
+ item_tester_tval = TV_BOLT;
+ break;
+ case SV_TRAPKIT_SLING:
+ item_tester_tval = TV_SHOT;
+ break;
+ case SV_TRAPKIT_POTION:
+ item_tester_hook = item_tester_hook_potion;
+ break;
+ case SV_TRAPKIT_SCROLL:
+ item_tester_tval = TV_SCROLL;
+ break;
+ case SV_TRAPKIT_DEVICE:
+ item_tester_hook = item_tester_hook_device;
+ break;
+ default:
+ msg_print("Unknown trapping kit type!");
+ break;
+ }
+
+ /* Get the second item */
+ q = "Load with what? ";
+ s = "You have nothing to load that trap with.";
+ if (!get_item(&item_load, q, s, USE_INVEN)) return;
+
+ /* Get the second object */
+ j_ptr = &p_ptr->inventory[item_load];
+
+ /* Assume a single object */
+ num = 1;
+
+ /* In some cases, take multiple objects to load */
+ if (o_ptr->sval != SV_TRAPKIT_DEVICE)
+ {
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if ((f3 & TR3_XTRA_SHOTS) && (o_ptr->pval > 0)) num += o_ptr->pval;
+
+ if (f2 & (TRAP2_AUTOMATIC_5 | TRAP2_AUTOMATIC_99)) num = 99;
+
+ if (num > j_ptr->number) num = j_ptr->number;
+
+ c = format("How many (1-%d)? ", num);
+
+ /* Ask for number of items to use */
+ num = get_quantity(c, num);
+ }
+
+ /* Canceled */
+ if (!num) return;
+
+ /* Take a turn */
+ energy_use = 100;
+
+ /* Get local object */
+ i_ptr = &object_type_body;
+
+ /* Obtain local object for trap content */
+ object_copy(i_ptr, j_ptr);
+
+ /* Set number */
+ i_ptr->number = num;
+
+ /* Drop it here */
+ cave[p_ptr->py][p_ptr->px].special = floor_carry(p_ptr->py, p_ptr->px, i_ptr);
+
+ /* Obtain local object for trap trigger kit */
+ object_copy(i_ptr, o_ptr);
+
+ /* Set number */
+ i_ptr->number = 1;
+
+ /* Drop it here */
+ cave[p_ptr->py][p_ptr->px].special2 = floor_carry(p_ptr->py, p_ptr->px, i_ptr);
+
+ /* Modify, Describe, Optimize */
+ inc_stack_size_ex(item_kit, -1, NO_OPTIMIZE, DESCRIBE);
+ inc_stack_size_ex(item_load, -num, NO_OPTIMIZE, DESCRIBE);
+
+ for (i = 0; i < INVEN_WIELD; i++)
+ {
+ if (inven_item_optimize(i)) break;
+ }
+ for (i = 0; i < INVEN_WIELD; i++)
+ {
+ inven_item_optimize(i);
+ }
+
+ /* Actually set the trap */
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_MON_TRAP);
+}
+
+/*
+ * Monster hitting a rod trap -MWK-
+ *
+ * Return TRUE if the monster died
+ */
+bool_ mon_hit_trap_aux_rod(int m_idx, object_type *o_ptr)
+{
+ int dam = 0, typ = 0;
+ int rad = 0;
+ monster_type *m_ptr = &m_list[m_idx];
+ int y = m_ptr->fy;
+ int x = m_ptr->fx;
+
+ /* Depend on rod type */
+ switch (o_ptr->pval)
+ {
+ case SV_ROD_DETECT_TRAP:
+ m_ptr->smart |= SM_NOTE_TRAP;
+ break;
+ case SV_ROD_DETECTION:
+ m_ptr->smart |= SM_NOTE_TRAP;
+ break;
+ case SV_ROD_ILLUMINATION:
+ typ = GF_LITE_WEAK;
+ dam = damroll(2, 15);
+ rad = 3;
+ lite_room(y, x);
+ break;
+ case SV_ROD_CURING:
+ typ = GF_OLD_HEAL;
+ dam = damroll(3, 4); /* and heal conf? */
+ break;
+ case SV_ROD_HEALING:
+ typ = GF_OLD_HEAL;
+ dam = 300;
+ break;
+ case SV_ROD_SPEED:
+ typ = GF_OLD_SPEED;
+ dam = 50;
+ break;
+ case SV_ROD_TELEPORT_AWAY:
+ typ = GF_AWAY_ALL;
+ dam = MAX_SIGHT * 5;
+ break;
+ case SV_ROD_DISARMING:
+ break;
+ case SV_ROD_LITE:
+ typ = GF_LITE_WEAK;
+ dam = damroll(6, 8);
+ break;
+ case SV_ROD_SLEEP_MONSTER:
+ typ = GF_OLD_SLEEP;
+ dam = 50;
+ break;
+ case SV_ROD_SLOW_MONSTER:
+ typ = GF_OLD_SLOW;
+ dam = 50;
+ break;
+ case SV_ROD_DRAIN_LIFE:
+ typ = GF_OLD_DRAIN;
+ dam = 75;
+ break;
+ case SV_ROD_POLYMORPH:
+ typ = GF_OLD_POLY;
+ dam = 50;
+ break;
+ case SV_ROD_ACID_BOLT:
+ typ = GF_ACID;
+ dam = damroll(6, 8);
+ break;
+ case SV_ROD_ELEC_BOLT:
+ typ = GF_ELEC;
+ dam = damroll(3, 8);
+ break;
+ case SV_ROD_FIRE_BOLT:
+ typ = GF_FIRE;
+ dam = damroll(8, 8);
+ break;
+ case SV_ROD_COLD_BOLT:
+ typ = GF_COLD;
+ dam = damroll(5, 8);
+ break;
+ case SV_ROD_ACID_BALL:
+ typ = GF_ACID;
+ dam = 60;
+ rad = 2;
+ break;
+ case SV_ROD_ELEC_BALL:
+ typ = GF_ELEC;
+ dam = 32;
+ rad = 2;
+ break;
+ case SV_ROD_FIRE_BALL:
+ typ = GF_FIRE;
+ dam = 72;
+ rad = 2;
+ break;
+ case SV_ROD_COLD_BALL:
+ typ = GF_COLD;
+ dam = 48;
+ rad = 2;
+ break;
+ default:
+ return (FALSE);
+ }
+
+ /* Actually hit the monster */
+ if (typ) (void) project( -2, rad, y, x, dam, typ, PROJECT_KILL | PROJECT_ITEM | PROJECT_JUMP);
+ return (cave[y][x].m_idx == 0 ? TRUE : FALSE);
+}
+
+/*
+ * Monster hitting a staff trap -MWK-
+ *
+ * Return TRUE if the monster died
+ */
+bool_ mon_hit_trap_aux_staff(int m_idx, object_type *o_ptr)
+{
+ return (FALSE);
+}
+
+/*
+ * Monster hitting a scroll trap -MWK-
+ *
+ * Return TRUE if the monster died
+ */
+bool_ mon_hit_trap_aux_scroll(int m_idx, int sval)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ int dam = 0, typ = 0;
+ int rad = 0;
+ int y = m_ptr->fy;
+ int x = m_ptr->fx;
+ int k;
+
+ /* Depend on scroll type */
+ switch (sval)
+ {
+ case SV_SCROLL_CURSE_ARMOR:
+ case SV_SCROLL_CURSE_WEAPON:
+ case SV_SCROLL_TRAP_CREATION: /* these don't work :-( */
+ case SV_SCROLL_WORD_OF_RECALL: /* should these? */
+ case SV_SCROLL_IDENTIFY:
+ case SV_SCROLL_STAR_IDENTIFY:
+ case SV_SCROLL_MAPPING:
+ case SV_SCROLL_DETECT_GOLD:
+ case SV_SCROLL_DETECT_ITEM:
+ case SV_SCROLL_REMOVE_CURSE:
+ case SV_SCROLL_STAR_REMOVE_CURSE:
+ case SV_SCROLL_ENCHANT_ARMOR:
+ case SV_SCROLL_ENCHANT_WEAPON_TO_HIT:
+ case SV_SCROLL_ENCHANT_WEAPON_TO_DAM:
+ case SV_SCROLL_STAR_ENCHANT_ARMOR:
+ case SV_SCROLL_STAR_ENCHANT_WEAPON:
+ case SV_SCROLL_RECHARGING:
+ case SV_SCROLL_DETECT_DOOR:
+ case SV_SCROLL_DETECT_INVIS:
+ case SV_SCROLL_SATISFY_HUNGER:
+ case SV_SCROLL_RUNE_OF_PROTECTION:
+ case SV_SCROLL_TRAP_DOOR_DESTRUCTION:
+ case SV_SCROLL_PROTECTION_FROM_EVIL:
+ return (FALSE);
+ case SV_SCROLL_DARKNESS:
+ unlite_room(y, x);
+ typ = GF_DARK_WEAK;
+ dam = 10;
+ rad = 3;
+ break;
+ case SV_SCROLL_AGGRAVATE_MONSTER:
+ aggravate_monsters(m_idx);
+ return (FALSE);
+ case SV_SCROLL_SUMMON_MONSTER:
+ for (k = 0; k < randint(3) ; k++) summon_specific(y, x, dun_level, 0);
+ return (FALSE);
+ case SV_SCROLL_SUMMON_UNDEAD:
+ for (k = 0; k < randint(3) ; k++) summon_specific(y, x, dun_level, SUMMON_UNDEAD);
+ return (FALSE);
+ case SV_SCROLL_PHASE_DOOR:
+ typ = GF_AWAY_ALL;
+ dam = 10;
+ break;
+ case SV_SCROLL_TELEPORT:
+ typ = GF_AWAY_ALL;
+ dam = 100;
+ break;
+ case SV_SCROLL_TELEPORT_LEVEL:
+ delete_monster(y, x);
+ return (TRUE);
+ case SV_SCROLL_LIGHT:
+ lite_room(y, x);
+ typ = GF_LITE_WEAK;
+ dam = damroll(2, 8);
+ rad = 2;
+ break;
+ case SV_SCROLL_DETECT_TRAP:
+ m_ptr->smart |= SM_NOTE_TRAP;
+ return (FALSE);
+ case SV_SCROLL_BLESSING:
+ typ = GF_HOLY_FIRE;
+ dam = damroll(1, 4);
+ break;
+ case SV_SCROLL_HOLY_CHANT:
+ typ = GF_HOLY_FIRE;
+ dam = damroll(2, 4);
+ break;
+ case SV_SCROLL_HOLY_PRAYER:
+ typ = GF_HOLY_FIRE;
+ dam = damroll(4, 4);
+ break;
+ case SV_SCROLL_MONSTER_CONFUSION:
+ typ = GF_OLD_CONF;
+ dam = damroll(5, 10);
+ break;
+ case SV_SCROLL_STAR_DESTRUCTION:
+ destroy_area(y, x, 15, TRUE, FALSE);
+ return (FALSE);
+ case SV_SCROLL_DISPEL_UNDEAD:
+ typ = GF_DISP_UNDEAD;
+ rad = 5;
+ dam = 60;
+ break;
+ case SV_SCROLL_GENOCIDE:
+ {
+ monster_race *r_ptr = &r_info[m_ptr->r_idx];
+ genocide_aux(FALSE, r_ptr->d_char);
+ /* although there's no point in a multiple genocide trap... */
+ return (!(r_ptr->flags1 & RF1_UNIQUE));
+ }
+ case SV_SCROLL_MASS_GENOCIDE:
+ for (k = 0; k < 8; k++)
+ delete_monster(y + ddy[k], x + ddx[k]);
+ delete_monster(y, x);
+ return (TRUE);
+ case SV_SCROLL_ACQUIREMENT:
+ acquirement(y, x, 1, TRUE, FALSE);
+ return (FALSE);
+ case SV_SCROLL_STAR_ACQUIREMENT:
+ acquirement(y, x, randint(2) + 1, TRUE, FALSE);
+ return (FALSE);
+ default:
+ return (FALSE);
+ }
+
+ /* Actually hit the monster */
+ (void) project( -2, rad, y, x, dam, typ, PROJECT_KILL | PROJECT_ITEM | PROJECT_JUMP);
+ return (cave[y][x].m_idx == 0 ? TRUE : FALSE);
+}
+
+/*
+ * Monster hitting a wand trap -MWK-
+ *
+ * Return TRUE if the monster died
+ */
+bool_ mon_hit_trap_aux_wand(int m_idx, object_type *o_ptr)
+{
+ return (FALSE);
+}
+
+/*
+ * Monster hitting a potions trap -MWK-
+ *
+ * Return TRUE if the monster died
+ */
+bool_ mon_hit_trap_aux_potion(int m_idx, object_type *o_ptr)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ int dam = 0, typ = 0;
+ int y = m_ptr->fy;
+ int x = m_ptr->fx;
+ int sval = o_ptr->sval;
+
+ /* Depend on potion type */
+ if (o_ptr->tval == TV_POTION)
+ {
+ switch (sval)
+ {
+ /* Nothing happens */
+ case SV_POTION_WATER:
+ case SV_POTION_APPLE_JUICE:
+ case SV_POTION_SLIME_MOLD:
+ case SV_POTION_SALT_WATER:
+ case SV_POTION_DEC_STR:
+ case SV_POTION_DEC_INT:
+ case SV_POTION_DEC_WIS:
+ case SV_POTION_DEC_DEX:
+ case SV_POTION_DEC_CON:
+ case SV_POTION_DEC_CHR:
+ case SV_POTION_INFRAVISION:
+ case SV_POTION_DETECT_INVIS:
+ case SV_POTION_SLOW_POISON:
+ case SV_POTION_CURE_POISON:
+ case SV_POTION_RESIST_HEAT:
+ case SV_POTION_RESIST_COLD:
+ case SV_POTION_RESTORE_MANA:
+ case SV_POTION_RESTORE_EXP:
+ case SV_POTION_RES_STR:
+ case SV_POTION_RES_INT:
+ case SV_POTION_RES_WIS:
+ case SV_POTION_RES_DEX:
+ case SV_POTION_RES_CON:
+ case SV_POTION_RES_CHR:
+ case SV_POTION_INC_STR:
+ case SV_POTION_INC_INT:
+ case SV_POTION_INC_WIS:
+ case SV_POTION_INC_DEX:
+ case SV_POTION_INC_CON:
+ case SV_POTION_INC_CHR:
+ case SV_POTION_AUGMENTATION:
+ case SV_POTION_RUINATION: /* ??? */
+ case SV_POTION_ENLIGHTENMENT:
+ case SV_POTION_STAR_ENLIGHTENMENT:
+ case SV_POTION_SELF_KNOWLEDGE:
+ return (FALSE);
+
+ case SV_POTION_EXPERIENCE:
+ if (m_ptr->level < MONSTER_LEVEL_MAX)
+ {
+ m_ptr->exp = MONSTER_EXP(m_ptr->level + 1);
+ monster_check_experience(m_idx, FALSE);
+ }
+ return (FALSE);
+ case SV_POTION_SLOWNESS:
+ typ = GF_OLD_SLOW;
+ dam = damroll(4, 6);
+ break;
+ case SV_POTION_POISON:
+ typ = GF_POIS;
+ dam = damroll(8, 6);
+ break;
+ case SV_POTION_CONFUSION:
+ typ = GF_CONFUSION;
+ dam = damroll(4, 6);
+ break;
+ case SV_POTION_BLINDNESS:
+ typ = GF_DARK;
+ dam = 10;
+ break;
+ case SV_POTION_SLEEP:
+ typ = GF_OLD_SLEEP;
+ dam = damroll (4, 6);
+ break;
+ case SV_POTION_LOSE_MEMORIES:
+ typ = GF_OLD_CONF;
+ dam = damroll(10, 10);
+ break;
+ case SV_POTION_DETONATIONS:
+ typ = GF_DISINTEGRATE;
+ dam = damroll(20, 20);
+ break;
+ case SV_POTION_DEATH:
+ typ = GF_NETHER;
+ dam = damroll(100, 20);
+ break;
+ case SV_POTION_BOLDNESS:
+ m_ptr->monfear = 0;
+ return (FALSE);
+ case SV_POTION_SPEED:
+ typ = GF_OLD_SPEED;
+ dam = damroll(5, 10);
+ break;
+ case SV_POTION_HEROISM:
+ case SV_POTION_BESERK_STRENGTH:
+ m_ptr->monfear = 0;
+ typ = GF_OLD_HEAL;
+ dam = damroll(2, 10);
+ break;
+ case SV_POTION_CURE_LIGHT:
+ typ = GF_OLD_HEAL;
+ dam = damroll(3, 4);
+ break;
+ case SV_POTION_CURE_SERIOUS:
+ typ = GF_OLD_HEAL;
+ dam = damroll(4, 6);
+ break;
+ case SV_POTION_CURE_CRITICAL:
+ typ = GF_OLD_HEAL;
+ dam = damroll(6, 8);
+ break;
+ case SV_POTION_HEALING:
+ typ = GF_OLD_HEAL;
+ dam = 300;
+ break;
+ case SV_POTION_STAR_HEALING:
+ typ = GF_OLD_HEAL;
+ dam = 1000;
+ break;
+ case SV_POTION_LIFE:
+ {
+ monster_race *r_ptr = &r_info[m_ptr->r_idx];
+ if (r_ptr->flags3 & RF3_UNDEAD)
+ {
+ typ = GF_HOLY_FIRE;
+ dam = damroll(20, 20);
+ }
+ else
+ {
+ typ = GF_OLD_HEAL;
+ dam = 5000;
+ }
+ break;
+ }
+ default:
+ return (FALSE);
+
+ }
+ }
+ else
+ {}
+
+ /* Actually hit the monster */
+ (void) project_m( -2, 0, y, x, dam, typ);
+ return (cave[y][x].m_idx == 0 ? TRUE : FALSE);
+}
+
+/*
+ * Monster hitting a monster trap -MWK-
+ * Returns True if the monster died, false otherwise
+ */
+bool_ mon_hit_trap(int m_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = &r_info[m_ptr->r_idx];
+
+ object_type *kit_o_ptr, *load_o_ptr, *j_ptr;
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_type object_type_body;
+
+ int mx = m_ptr->fx;
+ int my = m_ptr->fy;
+
+ int difficulty;
+ int smartness;
+
+ char m_name[80];
+
+ bool_ notice = FALSE;
+ bool_ disarm = FALSE;
+ bool_ remove = FALSE;
+ bool_ dead = FALSE;
+ bool_ fear = FALSE;
+ s32b special = 0;
+
+ int dam, chance, shots;
+ int mul = 0;
+ int breakage = -1;
+
+ int cost = 0;
+
+ /* Get the trap objects */
+ kit_o_ptr = &o_list[cave[my][mx].special2];
+ load_o_ptr = &o_list[cave[my][mx].special];
+ j_ptr = &object_type_body;
+
+ /* Get trap properties */
+ object_flags(kit_o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Can set off check */
+ /* Ghosts only set off Ghost traps */
+ if ((r_ptr->flags2 & RF2_PASS_WALL) && !(f2 & TRAP2_KILL_GHOST)) return (FALSE);
+
+ /* Some traps are specialized to some creatures */
+ if (f2 & TRAP2_ONLY_MASK)
+ {
+ bool_ affect = FALSE;
+ if ((f2 & TRAP2_ONLY_DRAGON) && (r_ptr->flags3 & RF3_DRAGON)) affect = TRUE;
+ if ((f2 & TRAP2_ONLY_DEMON) && (r_ptr->flags3 & RF3_DEMON)) affect = TRUE;
+ if ((f2 & TRAP2_ONLY_UNDEAD) && (r_ptr->flags3 & RF3_UNDEAD)) affect = TRUE;
+ if ((f2 & TRAP2_ONLY_EVIL) && (r_ptr->flags3 & RF3_EVIL)) affect = TRUE;
+ if ((f2 & TRAP2_ONLY_ANIMAL) && (r_ptr->flags3 & RF3_ANIMAL)) affect = TRUE;
+
+ /* Don't set it off if forbidden */
+ if (!affect) return (FALSE);
+ }
+
+ /* Get detection difficulty */
+ difficulty = 25;
+
+ /* Some traps are well-hidden */
+ if (f1 & TR1_STEALTH)
+ {
+ difficulty += 10 * (kit_o_ptr->pval);
+ }
+
+ /* Get monster smartness for trap detection */
+ /* Higher level monsters are smarter */
+ smartness = r_ptr->level;
+
+ /* Smart monsters are better at detecting traps */
+ if (r_ptr->flags2 & RF2_SMART) smartness += 10;
+
+ /* Some monsters have already noticed one of out traps */
+ if (m_ptr->smart & SM_NOTE_TRAP) smartness += 20;
+
+ /* Stupid monsters are no good at detecting traps */
+ if (r_ptr->flags2 & (RF2_STUPID | RF2_EMPTY_MIND)) smartness = -150;
+
+ /* Check if the monster notices the trap */
+ if (randint(300) > (difficulty - smartness + 150)) notice = TRUE;
+
+ /* Disarm check */
+ if (notice)
+ {
+ /* The next traps will be easier to spot! */
+ m_ptr->smart |= SM_NOTE_TRAP;
+
+ /* Get trap disarming difficulty */
+ difficulty = (kit_o_ptr->ac + kit_o_ptr->to_a);
+
+ /* Get monster disarming ability */
+ /* Higher level monsters are better */
+ smartness = r_ptr->level / 5;
+
+ /* Smart monsters are better at disarming */
+ if (r_ptr->flags2 & RF2_SMART) smartness *= 2;
+
+ /* Stupid monsters never disarm traps */
+ if (r_ptr->flags2 & RF2_STUPID) smartness = -150;
+
+ /* Nonsmart animals never disarm traps */
+ if ((r_ptr->flags3 & RF3_ANIMAL) && !(r_ptr->flags2 & RF2_SMART)) smartness = -150;
+
+ /* Check if the monster disarms the trap */
+ if (randint(120) > (difficulty - smartness + 80)) disarm = TRUE;
+ }
+
+ /* If disarmed, remove the trap and print a message */
+ if (disarm)
+ {
+ remove = TRUE;
+
+ if (m_ptr->ml)
+ {
+ /* Get the name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Print a message */
+ msg_format("%^s disarms a trap!", m_name);
+ }
+ }
+
+ /* Otherwise, activate the trap! */
+ else
+ {
+ /* Message for visible monster */
+ if (m_ptr->ml)
+ {
+ /* Get the name */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Print a message */
+ msg_format("%^s sets off a trap!", m_name);
+ }
+ else
+ {
+ /* No message if monster isn't visible ? */
+ }
+
+ /* Next time be more careful */
+ if (randint(100) < 80) m_ptr->smart |= SM_NOTE_TRAP;
+
+ /* Actually activate the trap */
+ switch (kit_o_ptr->sval)
+ {
+ case SV_TRAPKIT_BOW:
+ case SV_TRAPKIT_XBOW:
+ case SV_TRAPKIT_SLING:
+ {
+ /* Get number of shots */
+ shots = 1;
+ if (f3 & TR3_XTRA_SHOTS) shots += kit_o_ptr->pval;
+ if (shots <= 0) shots = 1;
+ if (shots > load_o_ptr->number) shots = load_o_ptr->number;
+
+ while (shots-- && !dead)
+ {
+ /* Total base damage */
+ dam = damroll(load_o_ptr->dd, load_o_ptr->ds) + load_o_ptr->to_d + kit_o_ptr->to_d;
+
+ /* Total hit probability */
+ chance = (kit_o_ptr->to_h + load_o_ptr->to_h + 20) * BTH_PLUS_ADJ;
+
+ /* Damage multiplier */
+ if (kit_o_ptr->sval == SV_TRAPKIT_BOW) mul = 3;
+ if (kit_o_ptr->sval == SV_TRAPKIT_XBOW) mul = 4;
+ if (kit_o_ptr->sval == SV_TRAPKIT_SLING) mul = 2;
+ if (f3 & TR3_XTRA_MIGHT) mul += kit_o_ptr->pval;
+ if (mul < 0) mul = 0;
+
+ /* Multiply damage */
+ dam *= mul;
+
+ /* Check if we hit the monster */
+ if (test_hit_fire(chance, r_ptr->ac, TRUE))
+ {
+ /* Assume a default death */
+ cptr note_dies = " dies.";
+
+ /* Some monsters get "destroyed" */
+ if ((r_ptr->flags3 & (RF3_DEMON)) ||
+ (r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags2 & (RF2_STUPID)) ||
+ (strchr("Evg", r_ptr->d_char)))
+ {
+ /* Special note at death */
+ note_dies = " is destroyed.";
+ }
+
+ /* Message if visible */
+ if (m_ptr->ml)
+ {
+ /* describe the monster (again, just in case :-) */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Print a message */
+ msg_format("%^s is hit by a missile.", m_name);
+ }
+
+ /* Apply slays, brand, critical hits */
+ dam = tot_dam_aux(load_o_ptr, dam, m_ptr, &special);
+ dam = critical_shot(load_o_ptr->weight, load_o_ptr->to_h, dam, SKILL_ARCHERY);
+
+ /* No negative damage */
+ if (dam < 0) dam = 0;
+
+ /* Hit the monster, check for death */
+ if (mon_take_hit(m_idx, dam, &fear, note_dies))
+ {
+ /* Dead monster */
+ dead = TRUE;
+ }
+
+ /* No death */
+ else
+ {
+ /* Message */
+ message_pain(m_idx, dam);
+
+ if (special) attack_special(m_ptr, special, dam);
+
+ /* Take note */
+ if (fear && m_ptr->ml)
+ {
+ /* Message */
+ msg_format("%^s flees in terror!", m_name);
+ }
+ }
+
+ }
+
+ /* Exploding ammo */
+ if (load_o_ptr->pval2 != 0)
+ {
+ int rad = 0;
+ int dam = (damroll(load_o_ptr->dd, load_o_ptr->ds) + load_o_ptr->to_d)*2;
+ int flag = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL |
+ PROJECT_JUMP;
+
+ switch (load_o_ptr->sval)
+ {
+ case SV_AMMO_LIGHT:
+ rad = 2;
+ dam /= 2;
+ break;
+ case SV_AMMO_NORMAL:
+ rad = 3;
+ break;
+ case SV_AMMO_HEAVY:
+ rad = 4;
+ dam *= 2;
+ break;
+ }
+
+ project(0, rad, my, mx, dam, load_o_ptr->pval2, flag);
+
+ breakage = 100;
+ }
+ else
+ {
+ breakage = breakage_chance(load_o_ptr);
+ }
+
+ /* Copy and decrease ammo */
+ object_copy(j_ptr, load_o_ptr);
+
+ j_ptr->number = 1;
+
+ load_o_ptr->number--;
+
+ if (load_o_ptr->number <= 0)
+ {
+ remove = TRUE;
+ delete_object_idx(kit_o_ptr->next_o_idx);
+ kit_o_ptr->next_o_idx = 0;
+ }
+
+ /* Drop (or break) near that location */
+ drop_near(j_ptr, breakage, my, mx);
+
+ }
+
+ break;
+ }
+
+ case SV_TRAPKIT_POTION:
+ {
+ /* Get number of shots */
+ shots = 1;
+ if (f3 & TR3_XTRA_SHOTS) shots += kit_o_ptr->pval;
+ if (shots <= 0) shots = 1;
+ if (shots > load_o_ptr->number) shots = load_o_ptr->number;
+
+ while (shots-- && !dead)
+ {
+
+ /* Message if visible */
+ if (m_ptr->ml)
+ {
+ /* describe the monster (again, just in case :-) */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Print a message */
+ msg_format("%^s is hit by fumes.", m_name);
+ }
+
+ /* Get the potion effect */
+ dead = mon_hit_trap_aux_potion(m_idx, load_o_ptr);
+
+ /* Copy and decrease ammo */
+ object_copy(j_ptr, load_o_ptr);
+
+ j_ptr->number = 1;
+
+ load_o_ptr->number--;
+
+ if (load_o_ptr->number <= 0)
+ {
+ remove = TRUE;
+ delete_object_idx(kit_o_ptr->next_o_idx);
+ kit_o_ptr->next_o_idx = 0;
+ }
+ }
+
+ break;
+ }
+
+ case SV_TRAPKIT_SCROLL:
+ {
+ /* Get number of shots */
+ shots = 1;
+ if (f3 & TR3_XTRA_SHOTS) shots += kit_o_ptr->pval;
+ if (shots <= 0) shots = 1;
+ if (shots > load_o_ptr->number) shots = load_o_ptr->number;
+
+ while (shots-- && !dead)
+ {
+
+ /* Message if visible */
+ if (m_ptr->ml)
+ {
+ /* describe the monster (again, just in case :-) */
+ monster_desc(m_name, m_ptr, 0);
+
+ /* Print a message */
+ msg_format("%^s activates a spell!", m_name);
+ }
+
+ /* Get the potion effect */
+ dead = mon_hit_trap_aux_scroll(m_idx, load_o_ptr->sval);
+
+ /* Copy and decrease ammo */
+ object_copy(j_ptr, load_o_ptr);
+
+ j_ptr->number = 1;
+
+ load_o_ptr->number--;
+
+ if (load_o_ptr->number <= 0)
+ {
+ remove = TRUE;
+ delete_object_idx(kit_o_ptr->next_o_idx);
+ kit_o_ptr->next_o_idx = 0;
+ }
+ }
+
+ break;
+ }
+
+ case SV_TRAPKIT_DEVICE:
+ {
+ if (load_o_ptr->tval == TV_ROD_MAIN)
+ {
+ /* Extract mana cost of the rod tip */
+ u32b tf1, tf2, tf3, tf4, tf5, tesp;
+ object_kind *tip_o_ptr = &k_info[lookup_kind(TV_ROD, load_o_ptr->pval)];
+ object_flags(load_o_ptr, &tf1, &tf2, &tf3, &tf4, &tf5, &tesp);
+ cost = (tf4 & TR4_CHEAPNESS) ? tip_o_ptr->pval / 2 : tip_o_ptr->pval;
+ if (cost <= 0) cost = 1;
+ }
+
+ /* Get number of shots */
+ shots = 1;
+ if (f3 & TR3_XTRA_SHOTS) shots += kit_o_ptr->pval;
+ if (shots <= 0) shots = 1;
+
+ if (load_o_ptr->tval == TV_ROD_MAIN)
+ {
+ if (shots > load_o_ptr->timeout / cost) shots = load_o_ptr->timeout / cost;
+ }
+ else
+ {
+ if (shots > load_o_ptr->pval) shots = load_o_ptr->pval;
+ }
+
+ while (shots-- && !dead)
+ {
+ /* Get the effect effect */
+ switch (load_o_ptr->tval)
+ {
+ case TV_ROD_MAIN:
+ dead = mon_hit_trap_aux_rod(m_idx, load_o_ptr);
+ break;
+ case TV_WAND:
+ dead = mon_hit_trap_aux_wand(m_idx, load_o_ptr);
+ break;
+ case TV_STAFF:
+ dead = mon_hit_trap_aux_staff(m_idx, load_o_ptr);
+ break;
+ }
+
+ if (load_o_ptr->tval == TV_ROD_MAIN)
+ {
+ /* decrease stored mana (timeout) for rods */
+ load_o_ptr->timeout -= cost;
+ }
+ else
+ {
+ /* decrease charges for wands and staves */
+ load_o_ptr->pval--;
+ }
+ }
+
+ break;
+ }
+
+ default:
+ msg_print("oops! nonexistant trap!");
+
+ }
+
+ /* Non-automatic traps are removed */
+ if (!(f2 & (TRAP2_AUTOMATIC_5 | TRAP2_AUTOMATIC_99)))
+ {
+ remove = TRUE;
+ }
+ else if (f2 & TRAP2_AUTOMATIC_5) remove = (randint(5) == 1);
+
+ }
+
+ /* Special trap effect -- teleport to */
+ if ((f2 & TRAP2_TELEPORT_TO) && (!disarm) && (!dead))
+ {
+ teleport_monster_to(m_idx, p_ptr->py, p_ptr->px);
+ }
+
+ /* Remove the trap if inactive now */
+ if (remove) place_floor_convert_glass(my, mx);
+
+ /* did it die? */
+ return (dead);
+}
+
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 00000000..49acb383
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,2522 @@
+/* File: types.h */
+
+/* Purpose: global type declarations */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+
+/*
+ * This file should ONLY be included by "angband.h"
+ */
+
+
+/*
+ * Note that "char" may or may not be signed, and that "signed char"
+ * may or may not work on all machines. So always use "s16b" or "s32b"
+ * for signed values. Also, note that unsigned values cause math problems
+ * in many cases, so try to only use "u16b" and "u32b" for "bit flags",
+ * unless you really need the extra bit of information, or you really
+ * need to restrict yourself to a single byte for storage reasons.
+ *
+ * Also, if possible, attempt to restrict yourself to sub-fields of
+ * known size (use "s16b" or "s32b" instead of "int", and "byte" instead
+ * of "bool"), and attempt to align all fields along four-byte words, to
+ * optimize storage issues on 32-bit machines. Also, avoid "bit flags"
+ * since these increase the code size and slow down execution. When
+ * you need to store bit flags, use one byte per flag, or, where space
+ * is an issue, use a "byte" or "u16b" or "u32b", and add special code
+ * to access the various bit flags.
+ *
+ * Many of these structures were developed to reduce the number of global
+ * variables, facilitate structured program design, allow the use of ascii
+ * template files, simplify access to indexed data, or facilitate efficient
+ * clearing of many variables at once.
+ *
+ * Certain data is saved in multiple places for efficient access, currently,
+ * this includes the tval/sval/weight fields in "object_type", various fields
+ * in "header_type", and the "m_idx" and "o_idx" fields in "cave_type". All
+ * of these could be removed, but this would, in general, slow down the game
+ * and increase the complexity of the code.
+ */
+
+
+
+
+
+/*
+ * Template file header information (see "init.c"). 16 bytes.
+ *
+ * Note that the sizes of many of the "arrays" are between 32768 and
+ * 65535, and so we must use "unsigned" values to hold the "sizes" of
+ * these arrays below. Normally, I try to avoid using unsigned values,
+ * since they can cause all sorts of bizarre problems, but I have no
+ * choice here, at least, until the "race" array is split into "normal"
+ * and "unique" monsters, which may or may not actually help.
+ *
+ * Note that, on some machines, for example, the Macintosh, the standard
+ * "read()" and "write()" functions cannot handle more than 32767 bytes
+ * at one time, so we need replacement functions, see "util.c" for details.
+ *
+ * Note that, on some machines, for example, the Macintosh, the standard
+ * "malloc()" function cannot handle more than 32767 bytes at one time,
+ * but we may assume that the "ralloc()" function can handle up to 65535
+ * butes at one time. We should not, however, assume that the "ralloc()"
+ * function can handle more than 65536 bytes at a time, since this might
+ * result in segmentation problems on certain older machines, and in fact,
+ * we should not assume that it can handle exactly 65536 bytes at a time,
+ * since the internal functions may use an unsigned short to specify size.
+ *
+ * In general, these problems occur only on machines (such as most personal
+ * computers) which use 2 byte "int" values, and which use "int" for the
+ * arguments to the relevent functions.
+ */
+
+typedef struct header header;
+
+struct header
+{
+ u16b info_num; /* Number of "info" records */
+
+ u32b name_size; /* Size of the "name" array in bytes */
+
+ u32b text_size; /* Size of the "text" array in bytes */
+};
+
+
+/*
+ * "Themed" objects.
+ * Probability in percent for each class of objects to be dropped.
+ * This could perhaps be an array - but that wouldn't be as clear.
+ */
+typedef struct obj_theme obj_theme;
+struct obj_theme
+{
+ byte treasure;
+ byte combat;
+ byte magic;
+ byte tools;
+};
+
+
+/*
+ * Information about terrain "features"
+ */
+
+typedef struct feature_type feature_type;
+
+struct feature_type
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+ u32b tunnel; /* Text for tunneling */
+ u32b block; /* Text for blocking */
+
+ byte mimic; /* Feature to mimic */
+
+ u32b flags1; /* First set of flags */
+
+ byte extra; /* Extra byte (unused) */
+
+ s16b unused; /* Extra bytes (unused) */
+
+ byte d_attr; /* Default feature attribute */
+ char d_char; /* Default feature character */
+
+
+ byte x_attr; /* Desired feature attribute */
+ char x_char; /* Desired feature character */
+
+ byte shimmer[7]; /* Shimmer colors */
+
+ int d_dice[4]; /* Number of dices */
+ int d_side[4]; /* Number of sides */
+ int d_frequency[4]; /* Frequency of damage (1 is the minimum) */
+ int d_type[4]; /* Type of damage */
+};
+
+
+/*
+ * Information about object "kinds", including player knowledge.
+ *
+ * Only "aware" and "tried" are saved in the savefile
+ */
+
+typedef struct object_kind object_kind;
+
+struct object_kind
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+
+ byte tval; /* Object type */
+ byte sval; /* Object sub type */
+
+ s32b pval; /* Object extra info */
+ s32b pval2; /* Object extra info */
+
+ s16b to_h; /* Bonus to hit */
+ s16b to_d; /* Bonus to damage */
+ s16b to_a; /* Bonus to armor */
+
+ s16b activate; /* Activation number */
+
+ s16b ac; /* Base armor */
+
+ byte dd, ds; /* Damage dice/sides */
+
+ s32b weight; /* Weight */
+
+ s32b cost; /* Object "base cost" */
+
+ u32b flags1; /* Flags, set 1 */
+ u32b flags2; /* Flags, set 2 */
+ u32b flags3; /* Flags, set 3 */
+ u32b flags4; /* Flags, set 4 */
+ u32b flags5; /* Flags, set 5 */
+
+ u32b oflags1; /* Obvious Flags, set 1 */
+ u32b oflags2; /* Obvious Flags, set 2 */
+ u32b oflags3; /* Obvious Flags, set 3 */
+ u32b oflags4; /* Obvious Flags, set 4 */
+ u32b oflags5; /* Obvious Flags, set 5 */
+
+ byte locale[4]; /* Allocation level(s) */
+ byte chance[4]; /* Allocation chance(s) */
+
+ byte level; /* Level */
+ byte extra; /* Something */
+
+
+ byte d_attr; /* Default object attribute */
+ char d_char; /* Default object character */
+
+
+ byte x_attr; /* Desired object attribute */
+ char x_char; /* Desired object character */
+
+
+ byte flavor; /* Special object flavor (or zero) */
+
+ bool_ easy_know; /* This object is always known (if aware) */
+
+
+ bool_ aware; /* The player is "aware" of the item's effects */
+
+ bool_ tried; /* The player has "tried" one of the items */
+
+ bool_ know; /* extractable flag for the alchemist */
+
+ u32b esp; /* ESP flags */
+ u32b oesp; /* Obvious ESP flags */
+
+ byte btval; /* Become Object type */
+ byte bsval; /* Become Object sub type */
+ bool_ artifact; /* Is it a normal artifact(already generated) */
+
+ s16b power; /* Power granted(if any) */
+};
+
+
+
+/*
+ * Information about "artifacts".
+ *
+ * Note that the save-file only writes "cur_num" to the savefile.
+ *
+ * Note that "max_num" is always "1" (if that artifact "exists")
+ */
+
+typedef struct artifact_type artifact_type;
+
+struct artifact_type
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+
+ byte tval; /* Artifact type */
+ byte sval; /* Artifact sub type */
+
+ s16b pval; /* Artifact extra info */
+
+ s16b to_h; /* Bonus to hit */
+ s16b to_d; /* Bonus to damage */
+ s16b to_a; /* Bonus to armor */
+
+ s16b activate; /* Activation Number */
+
+ s16b ac; /* Base armor */
+
+ byte dd, ds; /* Damage when hits */
+
+ s16b weight; /* Weight */
+
+ s32b cost; /* Artifact "cost" */
+
+ u32b flags1; /* Artifact Flags, set 1 */
+ u32b flags2; /* Artifact Flags, set 2 */
+ u32b flags3; /* Artifact Flags, set 3 */
+ u32b flags4; /* Artifact Flags, set 4 */
+ u32b flags5; /* Artifact Flags, set 5 */
+
+ u32b oflags1; /* Obvious Flags, set 1 */
+ u32b oflags2; /* Obvious Flags, set 2 */
+ u32b oflags3; /* Obvious Flags, set 3 */
+ u32b oflags4; /* Obvious Flags, set 4 */
+ u32b oflags5; /* Obvious Flags, set 5 */
+
+ byte level; /* Artifact level */
+ byte rarity; /* Artifact rarity */
+
+ byte cur_num; /* Number created (0 or 1) */
+ byte max_num; /* Unused (should be "1") */
+
+ u32b esp; /* ESP flags */
+ u32b oesp; /* ESP flags */
+
+ s16b power; /* Power granted(if any) */
+
+ s16b set; /* Does it belongs to a set ?*/
+};
+
+
+/*
+ * Information about "ego-items".
+ */
+
+typedef struct ego_item_type ego_item_type;
+
+struct ego_item_type
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+
+ bool_ before; /* Before or after the object name ? */
+
+ byte tval[10];
+ byte min_sval[10];
+ byte max_sval[10];
+
+ byte rating; /* Rating boost */
+
+ byte level; /* Minimum level */
+ byte rarity; /* Object rarity */
+ byte mrarity; /* Object rarity */
+
+ s16b max_to_h; /* Maximum to-hit bonus */
+ s16b max_to_d; /* Maximum to-dam bonus */
+ s16b max_to_a; /* Maximum to-ac bonus */
+
+ s16b activate; /* Activation Number */
+
+ s32b max_pval; /* Maximum pval */
+
+ s32b cost; /* Ego-item "cost" */
+
+ byte rar[5];
+ u32b flags1[5]; /* Ego-Item Flags, set 1 */
+ u32b flags2[5]; /* Ego-Item Flags, set 2 */
+ u32b flags3[5]; /* Ego-Item Flags, set 3 */
+ u32b flags4[5]; /* Ego-Item Flags, set 4 */
+ u32b flags5[5]; /* Ego-Item Flags, set 5 */
+ u32b esp[5]; /* ESP flags */
+ u32b oflags1[5]; /* Ego-Item Obvious Flags, set 1 */
+ u32b oflags2[5]; /* Ego-Item Obvious Flags, set 2 */
+ u32b oflags3[5]; /* Ego-Item Obvious Flags, set 3 */
+ u32b oflags4[5]; /* Ego-Item Obvious Flags, set 4 */
+ u32b oflags5[5]; /* Ego-Item Obvious Flags, set 5 */
+ u32b oesp[5]; /* Obvious ESP flags */
+ u32b fego[5]; /* ego flags */
+
+ u32b need_flags1; /* Ego-Item Flags, set 1 */
+ u32b need_flags2; /* Ego-Item Flags, set 2 */
+ u32b need_flags3; /* Ego-Item Flags, set 3 */
+ u32b need_flags4; /* Ego-Item Flags, set 4 */
+ u32b need_flags5; /* Ego-Item Flags, set 5 */
+ u32b need_esp; /* ESP flags */
+ u32b forbid_flags1; /* Ego-Item Flags, set 1 */
+ u32b forbid_flags2; /* Ego-Item Flags, set 2 */
+ u32b forbid_flags3; /* Ego-Item Flags, set 3 */
+ u32b forbid_flags4; /* Ego-Item Flags, set 4 */
+ u32b forbid_flags5; /* Ego-Item Flags, set 5 */
+ u32b forbid_esp; /* ESP flags */
+
+ s16b power; /* Power granted(if any) */
+};
+
+
+/*
+ * Information about "random artifacts parts".
+ */
+typedef struct randart_part_type randart_part_type;
+struct randart_part_type
+{
+ byte tval[20];
+ byte min_sval[20];
+ byte max_sval[20];
+
+ byte level; /* Minimum level */
+ byte rarity; /* Object rarity */
+ byte mrarity; /* Object rarity */
+
+ s16b max_to_h; /* Maximum to-hit bonus */
+ s16b max_to_d; /* Maximum to-dam bonus */
+ s16b max_to_a; /* Maximum to-ac bonus */
+
+ s32b max_pval; /* Maximum pval */
+
+ s32b value; /* power value */
+ s16b max; /* Number of time it can appear on a single item */
+
+ u32b flags1; /* Ego-Item Flags, set 1 */
+ u32b flags2; /* Ego-Item Flags, set 2 */
+ u32b flags3; /* Ego-Item Flags, set 3 */
+ u32b flags4; /* Ego-Item Flags, set 4 */
+ u32b flags5; /* Ego-Item Flags, set 5 */
+ u32b esp; /* ESP flags */
+ u32b fego; /* ego flags */
+
+ u32b aflags1; /* Ego-Item Flags, set 1 */
+ u32b aflags2; /* Ego-Item Flags, set 2 */
+ u32b aflags3; /* Ego-Item Flags, set 3 */
+ u32b aflags4; /* Ego-Item Flags, set 4 */
+ u32b aflags5; /* Ego-Item Flags, set 5 */
+ u32b aesp; /* ESP flags */
+
+ s16b power; /* Power granted(if any) */
+};
+
+typedef struct randart_gen_type randart_gen_type;
+struct randart_gen_type
+{
+ int chance; /* Chance to have that number of powers */
+ int dd;
+ int ds;
+ int plus; /* xdy+plus power */
+};
+
+
+/*
+ * Monster blow structure
+ *
+ * - Method (RBM_*)
+ * - Effect (RBE_*)
+ * - Damage Dice
+ * - Damage Sides
+ */
+
+typedef struct monster_blow monster_blow;
+
+struct monster_blow
+{
+ byte method;
+ byte effect;
+ byte d_dice;
+ byte d_side;
+};
+
+
+
+/*
+ * Monster "race" information, including racial memories
+ *
+ * Note that "d_attr" and "d_char" are used for MORE than "visual" stuff.
+ *
+ * Note that "x_attr" and "x_char" are used ONLY for "visual" stuff.
+ *
+ * Note that "cur_num" (and "max_num") represent the number of monsters
+ * of the given race currently on (and allowed on) the current level.
+ * This information yields the "dead" flag for Unique monsters.
+ *
+ * Note that "max_num" is reset when a new player is created.
+ * Note that "cur_num" is reset when a new level is created.
+ *
+ * Note that several of these fields, related to "recall", can be
+ * scrapped if space becomes an issue, resulting in less "complete"
+ * monster recall (no knowledge of spells, etc). All of the "recall"
+ * fields have a special prefix to aid in searching for them.
+ */
+
+
+typedef struct monster_race monster_race;
+
+struct monster_race
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+
+ u16b hdice; /* Creatures hit dice count */
+ u16b hside; /* Creatures hit dice sides */
+
+ s16b ac; /* Armour Class */
+
+ s16b sleep; /* Inactive counter (base) */
+ byte aaf; /* Area affect radius (1-100) */
+ byte speed; /* Speed (normally 110) */
+
+ s32b mexp; /* Exp value for kill */
+
+ s32b weight; /* Weight of the monster */
+
+ byte freq_inate; /* Inate spell frequency */
+ byte freq_spell; /* Other spell frequency */
+
+ u32b flags1; /* Flags 1 (general) */
+ u32b flags2; /* Flags 2 (abilities) */
+ u32b flags3; /* Flags 3 (race/resist) */
+ u32b flags4; /* Flags 4 (inate/breath) */
+ u32b flags5; /* Flags 5 (normal spells) */
+ u32b flags6; /* Flags 6 (special spells) */
+ u32b flags7; /* Flags 7 (movement related abilities) */
+ u32b flags8; /* Flags 8 (wilderness info) */
+ u32b flags9; /* Flags 9 (drops info) */
+
+ monster_blow blow[4]; /* Up to four blows per round */
+
+ byte body_parts[BODY_MAX]; /* To help to decide what to use when body changing */
+
+ byte level; /* Level of creature */
+ byte rarity; /* Rarity of creature */
+
+
+ byte d_attr; /* Default monster attribute */
+ char d_char; /* Default monster character */
+
+
+ byte x_attr; /* Desired monster attribute */
+ char x_char; /* Desired monster character */
+
+
+ s16b max_num; /* Maximum population allowed per level */
+
+ byte cur_num; /* Monster population on current level */
+
+
+ s16b r_sights; /* Count sightings of this monster */
+ s16b r_deaths; /* Count deaths from this monster */
+
+ s16b r_pkills; /* Count monsters killed in this life */
+ s16b r_tkills; /* Count monsters killed in all lives */
+
+ byte r_wake; /* Number of times woken up (?) */
+ byte r_ignore; /* Number of times ignored (?) */
+
+ byte r_xtra1; /* Something (unused) */
+ byte r_xtra2; /* Something (unused) */
+
+ byte r_drop_gold; /* Max number of gold dropped at once */
+ byte r_drop_item; /* Max number of item dropped at once */
+
+ byte r_cast_inate; /* Max number of inate spells seen */
+ byte r_cast_spell; /* Max number of other spells seen */
+
+ byte r_blows[4]; /* Number of times each blow type was seen */
+
+ u32b r_flags1; /* Observed racial flags */
+ u32b r_flags2; /* Observed racial flags */
+ u32b r_flags3; /* Observed racial flags */
+ u32b r_flags4; /* Observed racial flags */
+ u32b r_flags5; /* Observed racial flags */
+ u32b r_flags6; /* Observed racial flags */
+ u32b r_flags7; /* Observed racial flags */
+ u32b r_flags8; /* Observed racial flags */
+ u32b r_flags9; /* Observed racial flags */
+
+ bool_ on_saved; /* Is the (unique) on a saved level ? */
+
+ byte total_visible; /* Amount of this race that are visible */
+
+ obj_theme drops; /* The drops type */
+};
+
+
+typedef struct monster_ego monster_ego;
+
+struct monster_ego
+{
+ u32b name; /* Name (offset) */
+ bool_ before; /* Display ego before or after */
+
+ monster_blow blow[4]; /* Up to four blows per round */
+ byte blowm[4][2];
+
+ s16b hdice; /* Creatures hit dice count */
+ s16b hside; /* Creatures hit dice sides */
+
+ s16b ac; /* Armour Class */
+
+ s16b sleep; /* Inactive counter (base) */
+ s16b aaf; /* Area affect radius (1-100) */
+ s16b speed; /* Speed (normally 110) */
+
+ s32b mexp; /* Exp value for kill */
+
+ s32b weight; /* Weight of the monster */
+
+ byte freq_inate; /* Inate spell frequency */
+ byte freq_spell; /* Other spell frequency */
+
+ /* Ego flags */
+ u32b flags1; /* Flags 1 */
+ u32b flags2; /* Flags 1 */
+ u32b flags3; /* Flags 1 */
+ u32b flags7; /* Flags 1 */
+ u32b flags8; /* Flags 1 */
+ u32b flags9; /* Flags 1 */
+ u32b hflags1; /* Flags 1 */
+ u32b hflags2; /* Flags 1 */
+ u32b hflags3; /* Flags 1 */
+ u32b hflags7; /* Flags 1 */
+ u32b hflags8; /* Flags 1 */
+ u32b hflags9; /* Flags 1 */
+
+ /* Monster flags */
+ u32b mflags1; /* Flags 1 (general) */
+ u32b mflags2; /* Flags 2 (abilities) */
+ u32b mflags3; /* Flags 3 (race/resist) */
+ u32b mflags4; /* Flags 4 (inate/breath) */
+ u32b mflags5; /* Flags 5 (normal spells) */
+ u32b mflags6; /* Flags 6 (special spells) */
+ u32b mflags7; /* Flags 7 (movement related abilities) */
+ u32b mflags8; /* Flags 8 (wilderness info) */
+ u32b mflags9; /* Flags 9 (drops info) */
+
+ /* Negative Flags, to be removed from the monster flags */
+ u32b nflags1; /* Flags 1 (general) */
+ u32b nflags2; /* Flags 2 (abilities) */
+ u32b nflags3; /* Flags 3 (race/resist) */
+ u32b nflags4; /* Flags 4 (inate/breath) */
+ u32b nflags5; /* Flags 5 (normal spells) */
+ u32b nflags6; /* Flags 6 (special spells) */
+ u32b nflags7; /* Flags 7 (movement related abilities) */
+ u32b nflags8; /* Flags 8 (wilderness info) */
+ u32b nflags9; /* Flags 9 (drops info) */
+
+ s16b level; /* Level of creature */
+ s16b rarity; /* Rarity of creature */
+
+
+ byte d_attr; /* Default monster attribute */
+ char d_char; /* Default monster character */
+
+ byte g_attr; /* Overlay graphic attribute */
+ char g_char; /* Overlay graphic character */
+
+ char r_char[5]; /* Monster race allowed */
+ char nr_char[5]; /* Monster race not allowed */
+};
+
+
+
+/*
+ * Information about "vault generation"
+ */
+
+typedef struct vault_type vault_type;
+
+struct vault_type
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+
+ byte typ; /* Vault type */
+
+ byte rat; /* Vault rating */
+
+ byte hgt; /* Vault height */
+ byte wid; /* Vault width */
+
+ s16b lvl; /* level of special (if any) */
+ byte dun_type; /* Dungeon type where the level will show up */
+
+ s16b mon[10]; /* special monster */
+ int item[3]; /* number of item (usually artifact) */
+};
+
+
+/* jk */
+/* name and description are in some other arrays */
+typedef struct trap_type trap_type;
+
+struct trap_type
+{
+ s16b probability; /* probability of existence */
+ s16b another; /* does this trap easily combine */
+ s16b p1valinc; /* how much does this trap attribute to p1val */
+ byte difficulty; /* how difficult to disarm */
+ byte minlevel; /* what is the minimum level on which the traps should be */
+ byte color; /* what is the color on screen */
+ u32b flags; /* where can these traps go - and perhaps other flags */
+ bool_ ident; /* do we know the name */
+ s16b known; /* how well is this trap known */
+ s16b name; /* normal name like weakness */
+ s16b dd, ds; /* base damage */
+ s16b text; /* longer description once you've met this trap */
+ byte g_attr; /* Overlay graphic attribute */
+ char g_char; /* Overlay graphic character */
+};
+
+
+
+/*
+ * A single "grid" in a Cave
+ *
+ * Note that several aspects of the code restrict the actual cave
+ * to a max size of 256 by 256. In partcular, locations are often
+ * saved as bytes, limiting each coordinate to the 0-255 range.
+ *
+ * The "o_idx" and "m_idx" fields are very interesting. There are
+ * many places in the code where we need quick access to the actual
+ * monster or object(s) in a given cave grid. The easiest way to
+ * do this is to simply keep the index of the monster and object
+ * (if any) with the grid, but this takes 198*66*4 bytes of memory.
+ * Several other methods come to mind, which require only half this
+ * amound of memory, but they all seem rather complicated, and would
+ * probably add enough code that the savings would be lost. So for
+ * these reasons, we simply store an index into the "o_list" and
+ * "m_list" arrays, using "zero" when no monster/object is present.
+ *
+ * Note that "o_idx" is the index of the top object in a stack of
+ * objects, using the "next_o_idx" field of objects (see below) to
+ * create the singly linked list of objects. If "o_idx" is zero
+ * then there are no objects in the grid.
+ */
+
+typedef struct cave_type cave_type;
+
+struct cave_type
+{
+ u16b info; /* Hack -- cave flags */
+
+ byte feat; /* Hack -- feature type */
+
+ s16b o_idx; /* Object in this grid */
+
+ s16b m_idx; /* Monster in this grid */
+
+ s16b t_idx; /* trap index (in t_list) or zero */
+
+ s16b special, special2; /* Special cave info */
+
+ s16b inscription; /* Inscription of the grid */
+
+ byte mana; /* Magical energy of the grid */
+
+ byte mimic; /* Feature to mimic */
+
+ byte cost; /* Hack -- cost of flowing */
+ byte when; /* Hack -- when cost was computed */
+
+ s16b effect; /* The lasting effects */
+};
+
+/* Lasting spell effects(clouds, ..) */
+typedef struct effect_type effect_type;
+struct effect_type
+{
+ s16b time; /* For how long */
+ s16b dam; /* How much damage */
+ s16b type; /* Of which type */
+ s16b cy; /* Center of the cast*/
+ s16b cx; /* Center of the cast*/
+ s16b rad; /* Radius -- if needed */
+ u32b flags; /* Flags */
+};
+
+/*
+ * Object information, for a specific object.
+ *
+ * Note that a "discount" on an item is permanent and never goes away.
+ *
+ * Note that inscriptions are now handled via the "quark_str()" function
+ * applied to the "note" field, which will return NULL if "note" is zero.
+ *
+ * Note that "object" records are "copied" on a fairly regular basis,
+ * and care must be taken when handling such objects.
+ *
+ * Note that "object flags" must now be derived from the object kind,
+ * the artifact and ego-item indexes, and the two "xtra" fields.
+ *
+ * Each cave grid points to one (or zero) objects via the "o_idx"
+ * field (above). Each object then points to one (or zero) objects
+ * via the "next_o_idx" field, forming a singly linked list, which
+ * in game terms, represents a "stack" of objects in the same grid.
+ *
+ * Each monster points to one (or zero) objects via the "hold_o_idx"
+ * field (below). Each object then points to one (or zero) objects
+ * via the "next_o_idx" field, forming a singly linked list, which
+ * in game terms, represents a pile of objects held by the monster.
+ *
+ * The "held_m_idx" field is used to indicate which monster, if any,
+ * is holding the object. Objects being held have "ix=0" and "iy=0".
+ */
+
+typedef struct object_type object_type;
+
+struct object_type
+{
+ s16b k_idx; /* Kind index (zero if "dead") */
+
+ byte iy; /* Y-position on map, or zero */
+ byte ix; /* X-position on map, or zero */
+
+ byte tval; /* Item type (from kind) */
+ byte sval; /* Item sub-type (from kind) */
+
+ s32b pval; /* Item extra-parameter */
+ s16b pval2; /* Item extra-parameter for some special
+ items*/
+ s32b pval3; /* Item extra-parameter for some special
+ items*/
+
+ byte discount; /* Discount (if any) */
+
+ byte number; /* Number of items */
+
+ s32b weight; /* Item weight */
+
+ byte elevel; /* Item exp level */
+ s32b exp; /* Item exp */
+
+ byte name1; /* Artifact type, if any */
+ s16b name2; /* Ego-Item type, if any */
+ s16b name2b; /* Second Ego-Item type, if any */
+
+ byte xtra1; /* Extra info type */
+ s16b xtra2; /* Extra info index */
+
+ s16b to_h; /* Plusses to hit */
+ s16b to_d; /* Plusses to damage */
+ s16b to_a; /* Plusses to AC */
+
+ s16b ac; /* Normal AC */
+
+ byte dd, ds; /* Damage dice/sides */
+
+ s16b timeout; /* Timeout Counter */
+
+ byte ident; /* Special flags */
+
+ byte marked; /* Object is marked */
+
+ u16b note; /* Inscription index */
+ u16b art_name; /* Artifact name (random artifacts) */
+
+ u32b art_flags1; /* Flags, set 1 Alas, these were necessary */
+ u32b art_flags2; /* Flags, set 2 for the random artifacts of*/
+ u32b art_flags3; /* Flags, set 3 Zangband */
+ u32b art_flags4; /* Flags, set 4 PernAngband */
+ u32b art_flags5; /* Flags, set 5 PernAngband */
+ u32b art_esp; /* Flags, set esp PernAngband */
+
+ u32b art_oflags1; /* Obvious Flags, set 1 */
+ u32b art_oflags2; /* Obvious Flags, set 2 */
+ u32b art_oflags3; /* Obvious Flags, set 3 */
+ u32b art_oflags4; /* Obvious Flags, set 4 */
+ u32b art_oflags5; /* Obvious Flags, set 5 */
+ u32b art_oesp; /* Obvious Flags, set esp */
+
+ s16b next_o_idx; /* Next object in stack (if any) */
+
+ s16b held_m_idx; /* Monster holding us (if any) */
+
+ byte sense; /* Pseudo-id status */
+
+ byte found; /* How did we find it */
+ s16b found_aux1; /* Stores info for found */
+ s16b found_aux2; /* Stores info for found */
+ s16b found_aux3; /* Stores info for found */
+ s16b found_aux4; /* Stores info for found */
+};
+
+
+/*
+ * Monster mind, use for skills and such
+ */
+typedef struct monster_mind monster_mind;
+struct monster_mind
+{
+ /*
+ * Without this, bcc can't compile because it does not
+ * allow empty structure. Remove this when you add some
+ * variables to this structure. -- Kusunose
+ */
+ byte dummy;
+};
+
+
+
+/*
+ * Monster information, for a specific monster.
+ *
+ * Note: fy, fx constrain dungeon size to 256x256
+ *
+ * The "hold_o_idx" field points to the first object of a stack
+ * of objects (if any) being carried by the monster (see above).
+ */
+
+typedef struct monster_type monster_type;
+
+struct monster_type
+{
+ s16b r_idx; /* Monster race index */
+
+ u16b ego; /* Ego monster type */
+
+ byte fy; /* Y location on map */
+ byte fx; /* X location on map */
+
+ s32b hp; /* Current Hit points */
+ s32b maxhp; /* Max Hit points */
+
+ monster_blow blow[4]; /* Up to four blows per round */
+
+ byte speed; /* Speed (normally 110) */
+ byte level; /* Level of creature */
+ s16b ac; /* Armour Class */
+ u32b exp; /* Experience */
+
+ s16b csleep; /* Inactive counter */
+
+ byte mspeed; /* Monster "speed" */
+ byte energy; /* Monster "energy" */
+
+ byte stunned; /* Monster is stunned */
+ byte confused; /* Monster is confused */
+ byte monfear; /* Monster is afraid */
+
+ s16b bleeding; /* Monster is bleeding */
+ s16b poisoned; /* Monster is poisoned */
+
+ byte cdis; /* Current dis from player */
+
+ s32b mflag; /* Extra monster flags */
+
+ bool_ ml; /* Monster is "visible" */
+
+ s16b hold_o_idx; /* Object being held (if any) */
+
+ u32b smart; /* Field for "smart_learn" */
+
+ s16b status; /* Status(friendly, pet, companion, ..) */
+
+ s16b target; /* Monster target */
+
+ s16b possessor; /* Is it under the control of a possessor ? */
+
+ monster_race *sr_ptr; /* Does it have a specific race(not in r_info) */
+
+ monster_mind *mind; /* Does it have a mind? */
+};
+
+
+
+
+/*
+ * An entry for the object/monster allocation functions
+ *
+ * Pass 1 is determined from allocation information
+ * Pass 2 is determined from allocation restriction
+ * Pass 3 is determined from allocation calculation
+ */
+
+typedef struct alloc_entry alloc_entry;
+
+struct alloc_entry
+{
+ s16b index; /* The actual index */
+
+ byte level; /* Base dungeon level */
+ byte prob1; /* Probability, pass 1 */
+ byte prob2; /* Probability, pass 2 */
+ byte prob3; /* Probability, pass 3 */
+
+ u16b total; /* Unused for now */
+};
+
+
+
+/*
+ * Available "options"
+ *
+ * - Address of actual option variable (or NULL)
+ *
+ * - Normal Value (TRUE or FALSE)
+ *
+ * - Option Page Number (or zero)
+ *
+ * - Savefile Set (or zero)
+ * - Savefile Bit in that set
+ *
+ * - Textual name (or NULL)
+ * - Textual description
+ */
+
+typedef struct option_type option_type;
+
+struct option_type
+{
+ bool_ *o_var;
+
+ byte o_norm;
+
+ byte o_page;
+
+ byte o_bit;
+
+ cptr o_text;
+ cptr o_desc;
+};
+
+/*
+ * A store owner
+ */
+typedef struct owner_type owner_type;
+
+struct owner_type
+{
+ u32b name; /* Name (offset) */
+
+ s16b max_cost; /* Purse limit */
+
+ byte max_inflate; /* Inflation (max) */
+ byte min_inflate; /* Inflation (min) */
+
+ byte haggle_per; /* Haggle unit */
+
+ byte insult_max; /* Insult limit */
+
+ u32b races[2][2]; /* Liked/hated races */
+ u32b classes[2][2]; /* Liked/hated classes */
+
+ s16b costs[3]; /* Costs for liked people */
+};
+
+
+
+
+/*
+ * A store, with an owner, various state flags, a current stock
+ * of items, and a table of items that are often purchased.
+ */
+typedef struct store_type store_type;
+
+struct store_type
+{
+ u16b st_idx;
+
+ u16b owner; /* Owner index */
+
+ s16b insult_cur; /* Insult counter */
+
+ s16b good_buy; /* Number of "good" buys */
+ s16b bad_buy; /* Number of "bad" buys */
+
+ s32b store_open; /* Closed until this turn */
+
+ s32b last_visit; /* Last visited on this turn */
+
+ byte stock_num; /* Stock -- Number of entries */
+ s16b stock_size; /* Stock -- Total Size of Array */
+ object_type *stock; /* Stock -- Actual stock items */
+};
+
+/*
+ * A store/building type
+ */
+typedef struct store_info_type store_info_type;
+
+struct store_info_type
+{
+ u32b name; /* Name (offset) */
+
+ s16b table[STORE_CHOICES][2]; /* Table -- Legal item kinds */
+ byte table_num; /* Number of items */
+ s16b max_obj; /* Number of items this store can hold */
+
+ u16b owners[4]; /* List of owners(refers to ow_info) */
+
+ u16b actions[6]; /* Actions(refers to ba_info) */
+
+ byte d_attr; /* Default building attribute */
+ char d_char; /* Default building character */
+
+ byte x_attr; /* Desired building attribute */
+ char x_char; /* Desired building character */
+
+ u32b flags1; /* Flags */
+};
+
+/*
+ * Stores/buildings actions
+ */
+typedef struct store_action_type store_action_type;
+
+struct store_action_type
+{
+ u32b name; /* Name (offset) */
+
+ s16b costs[3]; /* Costs for liked people */
+ char letter; /* Action letter */
+ char letter_aux; /* Action letter */
+ s16b action; /* Action code */
+ s16b action_restr; /* Action restriction */
+};
+
+/*
+ * the spell function must provide the desc
+ */
+typedef struct magic_type magic_type;
+
+struct magic_type
+{
+ byte slevel; /* Required level (to learn) */
+ byte smana; /* Required mana (to cast) */
+ byte sfail; /* Minimum chance of failure */
+ byte sexp; /* Encoded experience bonus */
+};
+
+/*
+ * Player sex info
+ */
+
+typedef struct player_sex player_sex;
+
+struct player_sex
+{
+ cptr title; /* Type of sex */
+
+ cptr winner; /* Name of winner */
+};
+
+
+/*
+ * Player racial info
+ */
+
+typedef struct player_race player_race;
+
+struct player_race
+{
+ s32b title; /* Type of race */
+ s32b desc;
+
+ s16b r_adj[6]; /* Racial stat bonuses */
+
+ char luck; /* Luck */
+
+ s16b r_dis; /* disarming */
+ s16b r_dev; /* magic devices */
+ s16b r_sav; /* saving throw */
+ s16b r_stl; /* stealth */
+ s16b r_srh; /* search ability */
+ s16b r_fos; /* search frequency */
+ s16b r_thn; /* combat (normal) */
+ s16b r_thb; /* combat (shooting) */
+
+ byte r_mhp; /* Race hit-dice modifier */
+ u16b r_exp; /* Race experience factor */
+
+ byte b_age; /* base age */
+ byte m_age; /* mod age */
+
+ byte m_b_ht; /* base height (males) */
+ byte m_m_ht; /* mod height (males) */
+ byte m_b_wt; /* base weight (males) */
+ byte m_m_wt; /* mod weight (males) */
+
+ byte f_b_ht; /* base height (females) */
+ byte f_m_ht; /* mod height (females) */
+ byte f_b_wt; /* base weight (females) */
+ byte f_m_wt; /* mod weight (females) */
+
+ byte infra; /* Infra-vision range */
+
+ u32b choice[2]; /* Legal class choices */
+
+ s16b powers[4]; /* Powers of the race */
+
+ byte body_parts[BODY_MAX]; /* To help to decide what to use when body changing */
+
+ s16b chart; /* Chart history */
+
+ u32b flags1;
+ u32b flags2; /* flags */
+
+ u32b oflags1[PY_MAX_LEVEL + 1];
+ u32b oflags2[PY_MAX_LEVEL + 1];
+ u32b oflags3[PY_MAX_LEVEL + 1];
+ u32b oflags4[PY_MAX_LEVEL + 1];
+ u32b oflags5[PY_MAX_LEVEL + 1];
+ u32b oesp[PY_MAX_LEVEL + 1];
+ s16b opval[PY_MAX_LEVEL + 1];
+
+ char skill_basem[MAX_SKILLS];
+ u32b skill_base[MAX_SKILLS];
+ char skill_modm[MAX_SKILLS];
+ s16b skill_mod[MAX_SKILLS];
+
+ s16b obj_tval[5];
+ s16b obj_sval[5];
+ s16b obj_pval[5];
+ s16b obj_dd[5];
+ s16b obj_ds[5];
+ s16b obj_num;
+
+ struct
+ {
+ s16b ability;
+ s16b level;
+ } abilities[10]; /* Abilitiers to be gained by level(doesnt take prereqs in account) */
+};
+
+typedef struct player_race_mod player_race_mod;
+
+struct player_race_mod
+{
+ s32b title; /* Type of race mod */
+ s32b desc; /* Desc */
+ bool_ place; /* TRUE = race race modifier, FALSE = Race modifier race */
+
+ s16b r_adj[6]; /* (+) Racial stat bonuses */
+
+ char luck; /* Luck */
+ s16b mana; /* Mana % */
+
+ s16b r_dis; /* (+) disarming */
+ s16b r_dev; /* (+) magic devices */
+ s16b r_sav; /* (+) saving throw */
+ s16b r_stl; /* (+) stealth */
+ s16b r_srh; /* (+) search ability */
+ s16b r_fos; /* (+) search frequency */
+ s16b r_thn; /* (+) combat (normal) */
+ s16b r_thb; /* (+) combat (shooting) */
+
+ char r_mhp; /* (+) Race mod hit-dice modifier */
+ s16b r_exp; /* (+) Race mod experience factor */
+
+ char b_age; /* (+) base age */
+ char m_age; /* (+) mod age */
+
+ char m_b_ht; /* (+) base height (males) */
+ char m_m_ht; /* (+) mod height (males) */
+ char m_b_wt; /* (+) base weight (males) */
+ char m_m_wt; /* (+) mod weight (males) */
+
+ char f_b_ht; /* (+) base height (females) */
+ char f_m_ht; /* (+) mod height (females) */
+ char f_b_wt; /* (+) base weight (females) */
+ char f_m_wt; /* (+) mod weight (females) */
+
+ char infra; /* (+) Infra-vision range */
+
+ u32b choice[2]; /* Legal race choices */
+
+ u32b pclass[2]; /* Classes allowed */
+ u32b mclass[2]; /* Classes restricted */
+
+ s16b powers[4]; /* Powers of the subrace */
+
+ char body_parts[BODY_MAX]; /* To help to decide what to use when body changing */
+
+ u32b flags1;
+ u32b flags2; /* flags */
+
+ u32b oflags1[PY_MAX_LEVEL + 1];
+ u32b oflags2[PY_MAX_LEVEL + 1];
+ u32b oflags3[PY_MAX_LEVEL + 1];
+ u32b oflags4[PY_MAX_LEVEL + 1];
+ u32b oflags5[PY_MAX_LEVEL + 1];
+ u32b oesp[PY_MAX_LEVEL + 1];
+ s16b opval[PY_MAX_LEVEL + 1];
+
+ byte g_attr; /* Overlay graphic attribute */
+ char g_char; /* Overlay graphic character */
+
+ char skill_basem[MAX_SKILLS];
+ u32b skill_base[MAX_SKILLS];
+ char skill_modm[MAX_SKILLS];
+ s16b skill_mod[MAX_SKILLS];
+
+ s16b obj_tval[5];
+ s16b obj_sval[5];
+ s16b obj_pval[5];
+ s16b obj_dd[5];
+ s16b obj_ds[5];
+ s16b obj_num;
+
+ struct
+ {
+ s16b ability;
+ s16b level;
+ } abilities[10]; /* Abilitiers to be gained by level(doesnt take prereqs in account) */
+};
+
+
+/*
+ * Player class info
+ */
+
+typedef struct player_spec player_spec;
+
+struct player_spec
+{
+ s32b title; /* Type of class spec */
+ s32b desc; /* Small desc of the class spec */
+
+ char skill_basem[MAX_SKILLS]; /* Mod for value */
+ u32b skill_base[MAX_SKILLS]; /* value */
+ char skill_modm[MAX_SKILLS]; /* mod for mod */
+ s16b skill_mod[MAX_SKILLS]; /* mod */
+
+ u32b skill_ideal[MAX_SKILLS]; /* Ideal skill levels at level 50 */
+
+ s16b obj_tval[5];
+ s16b obj_sval[5];
+ s16b obj_pval[5];
+ s16b obj_dd[5];
+ s16b obj_ds[5];
+ s16b obj_num;
+
+ u32b gods;
+
+ u32b flags1;
+ u32b flags2; /* flags */
+
+ struct
+ {
+ s16b ability;
+ s16b level;
+ } abilities[10]; /* Abilitiers to be gained by level(doesnt take prereqs in account) */
+};
+
+typedef struct player_class player_class;
+
+struct player_class
+{
+ s32b title; /* Type of class */
+ s32b desc; /* Small desc of the class */
+ s32b titles[PY_MAX_LEVEL / 5];
+
+ s16b c_adj[6]; /* Class stat modifier */
+
+ s16b c_dis; /* class disarming */
+ s16b c_dev; /* class magic devices */
+ s16b c_sav; /* class saving throws */
+ s16b c_stl; /* class stealth */
+ s16b c_srh; /* class searching ability */
+ s16b c_fos; /* class searching frequency */
+ s16b c_thn; /* class to hit (normal) */
+ s16b c_thb; /* class to hit (bows) */
+
+ s16b x_dis; /* extra disarming */
+ s16b x_dev; /* extra magic devices */
+ s16b x_sav; /* extra saving throws */
+ s16b x_stl; /* extra stealth */
+ s16b x_srh; /* extra searching ability */
+ s16b x_fos; /* extra searching frequency */
+ s16b x_thn; /* extra to hit (normal) */
+ s16b x_thb; /* extra to hit (bows) */
+
+ s16b c_mhp; /* Class hit-dice adjustment */
+ s16b c_exp; /* Class experience factor */
+
+ s16b powers[4]; /* Powers of the class */
+
+ s16b spell_book; /* Tval of spell books (if any) */
+ s16b spell_stat; /* Stat for spells (if any) */
+ s16b spell_lev; /* The higher it is the higher the spells level are */
+ s16b spell_fail; /* The higher it is the higher the spells failure are */
+ s16b spell_mana; /* The higher it is the higher the spells mana are */
+ s16b spell_first; /* Level of first spell */
+ s16b spell_weight; /* Weight that hurts spells */
+ byte max_spell_level; /* Maximun spell level */
+ byte magic_max_spell; /* Maximun numbner of spells one can learn by natural means */
+
+ u32b flags1; /* flags */
+ u32b flags2; /* flags */
+
+ s16b mana;
+ s16b blow_num;
+ s16b blow_wgt;
+ s16b blow_mul;
+ s16b extra_blows;
+
+ s32b sense_base;
+ s32b sense_pl;
+ s32b sense_plus;
+ byte sense_heavy;
+ byte sense_heavy_magic;
+
+ s16b obj_tval[5];
+ s16b obj_sval[5];
+ s16b obj_pval[5];
+ s16b obj_dd[5];
+ s16b obj_ds[5];
+ s16b obj_num;
+
+ char body_parts[BODY_MAX]; /* To help to decide what to use when body changing */
+
+ u32b oflags1[PY_MAX_LEVEL + 1];
+ u32b oflags2[PY_MAX_LEVEL + 1];
+ u32b oflags3[PY_MAX_LEVEL + 1];
+ u32b oflags4[PY_MAX_LEVEL + 1];
+ u32b oflags5[PY_MAX_LEVEL + 1];
+ u32b oesp[PY_MAX_LEVEL + 1];
+ s16b opval[PY_MAX_LEVEL + 1];
+
+ char skill_basem[MAX_SKILLS];
+ u32b skill_base[MAX_SKILLS];
+ char skill_modm[MAX_SKILLS];
+ s16b skill_mod[MAX_SKILLS];
+
+ u32b gods;
+
+ player_spec spec[MAX_SPEC];
+
+ struct
+ {
+ s16b ability;
+ s16b level;
+ } abilities[10]; /* Abilitiers to be gained by level(doesnt take prereqs in account) */
+};
+
+typedef struct meta_class_type meta_class_type;
+struct meta_class_type
+{
+ char name[80]; /* Name */
+ byte color;
+ s16b *classes; /* list of classes */
+};
+
+/* Help type */
+typedef struct help_info help_info;
+struct help_info
+{
+ bool_ enabled; /* ingame help enabled */
+
+ u32b help1; /* help flags 1 */
+};
+
+
+/*
+ * Most of the "player" information goes here.
+ *
+ * This stucture gives us a large collection of player variables.
+ *
+ * This structure contains several "blocks" of information.
+ * (1) the "permanent" info
+ * (2) the "variable" info
+ * (3) the "transient" info
+ *
+ * All of the "permanent" info, and most of the "variable" info,
+ * is saved in the savefile. The "transient" info is recomputed
+ * whenever anything important changes.
+ */
+
+typedef struct player_type player_type;
+
+struct player_type
+{
+ s32b lives; /* How many times we resurected */
+
+ s16b oldpy; /* Previous player location -KMW- */
+ s16b oldpx; /* Previous player location -KMW- */
+
+ s16b py; /* Player location */
+ s16b px; /* Player location */
+
+ byte psex; /* Sex index */
+ byte prace; /* Race index */
+ byte pracem; /* Race Mod index */
+ byte pclass; /* Class index */
+ byte pspec; /* Class spec index */
+ byte mimic_form; /* Actualy transformation */
+ s16b mimic_level; /* Level of the mimic effect */
+ byte oops; /* Unused */
+
+ object_type inventory[INVEN_TOTAL]; /* Player inventory */
+
+ byte hitdie; /* Hit dice (sides) */
+ u16b expfact; /* Experience factor */
+
+ byte maximize; /* Maximize stats */
+ byte preserve; /* Preserve artifacts */
+ byte special; /* Special levels */
+ byte allow_one_death; /* Blood of life */
+
+ s16b age; /* Characters age */
+ s16b ht; /* Height */
+ s16b wt; /* Weight */
+ s16b sc; /* Social Class */
+
+
+ s32b au; /* Current Gold */
+
+ s32b max_exp; /* Max experience */
+ s32b exp; /* Cur experience */
+ u16b exp_frac; /* Cur exp frac (times 2^16) */
+
+ s16b lev; /* Level */
+
+ s16b town_num; /* Current town number */
+ s16b arena_number; /* monster number in arena -KMW- */
+ s16b inside_arena; /* Is character inside arena? */
+ s16b inside_quest; /* Inside quest level */
+ bool_ exit_bldg; /* Goal obtained in arena? -KMW- */
+
+ s32b wilderness_x; /* Coordinates in the wilderness */
+ s32b wilderness_y;
+ bool_ wild_mode; /* TRUE = Small map, FLASE = Big map */
+ bool_ old_wild_mode; /* TRUE = Small map, FLASE = Big map */
+
+ s16b mhp; /* Max hit pts */
+ s16b chp; /* Cur hit pts */
+ u16b chp_frac; /* Cur hit frac (times 2^16) */
+ s16b hp_mod; /* A modificator(permanent) */
+
+ s16b msp; /* Max mana pts */
+ s16b csp; /* Cur mana pts */
+ u16b csp_frac; /* Cur mana frac (times 2^16) */
+
+ s16b msane; /* Max sanity */
+ s16b csane; /* Cur sanity */
+ u16b csane_frac; /* Cur sanity frac */
+
+ s32b grace; /* Your God's appreciation factor. */
+ byte pgod; /* Your God. */
+ bool_ praying; /* Praying to your god. */
+ s16b melkor_sacrifice; /* How much hp has been sacrified for damage */
+
+ s16b max_plv; /* Max Player Level */
+
+ s16b stat_max[6]; /* Current "maximal" stat values */
+ s16b stat_cur[6]; /* Current "natural" stat values */
+
+ s16b luck_cur; /* Current "natural" luck value (range -30 <> 30) */
+ s16b luck_max; /* Current "maximal base" luck value (range -30 <> 30) */
+ s16b luck_base; /* Current "base" luck value (range -30 <> 30) */
+
+ s16b speed_factor; /* Timed -- Fast */
+ s16b fast; /* Timed -- Fast */
+ s16b lightspeed; /* Timed -- Light Speed */
+ s16b slow; /* Timed -- Slow */
+ s16b blind; /* Timed -- Blindness */
+ s16b paralyzed; /* Timed -- Paralysis */
+ s16b confused; /* Timed -- Confusion */
+ s16b afraid; /* Timed -- Fear */
+ s16b image; /* Timed -- Hallucination */
+ s16b poisoned; /* Timed -- Poisoned */
+ s16b cut; /* Timed -- Cut */
+ s16b stun; /* Timed -- Stun */
+
+ s16b protevil; /* Timed -- Protection from Evil*/
+ s16b protgood; /* Timed -- Protection from Good*/
+ s16b protundead; /* Timed -- Protection from Undead*/
+ s16b invuln; /* Timed -- Invulnerable */
+ s16b hero; /* Timed -- Heroism */
+ s16b shero; /* Timed -- Super Heroism */
+ s16b shield; /* Timed -- Shield Spell */
+ s16b shield_power; /* Timed -- Shield Spell Power */
+ s16b shield_opt; /* Timed -- Shield Spell options */
+ s16b shield_power_opt; /* Timed -- Shield Spell Power */
+ s16b shield_power_opt2; /* Timed -- Shield Spell Power */
+ s16b blessed; /* Timed -- Blessed */
+ s16b tim_invis; /* Timed -- See Invisible */
+ s16b tim_infra; /* Timed -- Infra Vision */
+
+ s16b oppose_acid; /* Timed -- oppose acid */
+ s16b oppose_elec; /* Timed -- oppose lightning */
+ s16b oppose_fire; /* Timed -- oppose heat */
+ s16b oppose_cold; /* Timed -- oppose cold */
+ s16b oppose_pois; /* Timed -- oppose poison */
+ s16b oppose_ld; /* Timed -- oppose light & dark */
+ s16b oppose_cc; /* Timed -- oppose chaos & confusion */
+ s16b oppose_ss; /* Timed -- oppose sound & shards */
+ s16b oppose_nex; /* Timed -- oppose nexus */
+
+ s16b rush; /* Rush and Bush */
+
+ s16b tim_esp; /* Timed ESP */
+ s16b tim_wraith; /* Timed wraithform */
+ s16b tim_ffall; /* Timed Levitation */
+ s16b tim_fly; /* Timed Levitation */
+ s16b tim_fire_aura; /* Timed Fire Aura */
+ s16b tim_poison; /* Timed poison hands */
+ s16b tim_thunder; /* Timed thunderstorm */
+ s16b tim_thunder_p1; /* Timed thunderstorm */
+ s16b tim_thunder_p2; /* Timed thunderstorm */
+
+ s16b tim_project; /* Timed project upon melee blow */
+ s16b tim_project_dam;
+ s16b tim_project_gf;
+ s16b tim_project_rad;
+ s16b tim_project_flag;
+
+ s16b tim_roots; /* Timed roots */
+ s16b tim_roots_ac;
+ s16b tim_roots_dam;
+
+ s16b resist_magic; /* Timed Resist Magic (later) */
+ s16b tim_invisible; /* Timed Invisibility */
+ s16b tim_inv_pow; /* Power of timed invisibility */
+ s16b tim_mimic; /* Timed Mimic */
+ s16b tim_lite; /* Timed Lite */
+ s16b tim_regen; /* Timed extra regen */
+ s16b tim_regen_pow; /* Timed extra regen power */
+ s16b holy; /* Holy Aura */
+ s16b walk_water; /* Walk over water as a god */
+ s16b tim_mental_barrier; /* Sustain Int&Wis */
+ s16b strike; /* True Strike(+25 hit) */
+ s16b meditation; /* Meditation(+50 mana -25 to hit/to dam) */
+ s16b tim_reflect; /* Timed Reflection */
+ s16b tim_res_time; /* Timed Resistance to Time */
+ s16b tim_deadly; /* Timed deadly blow */
+ s16b prob_travel; /* Timed probability travel */
+ s16b disrupt_shield;/* Timed disruption shield */
+ s16b parasite; /* Timed parasite */
+ s16b parasite_r_idx;/* Timed parasite monster */
+ s32b loan; /* Amount of loan */
+ s32b loan_time; /* Timer -- time to payback loan */
+ s16b absorb_soul; /* Timed soul absordtion */
+ s16b tim_magic_breath; /* Magical breathing -- can breath anywhere */
+ s16b tim_water_breath; /* Water breathing -- can breath underwater */
+
+ s16b immov_cntr; /* Timed -- Last ``immovable'' command. */
+
+ s16b chaos_patron;
+
+ s16b recall_dungeon; /* Recall in which dungeon */
+ s16b word_recall; /* Word of recall counter */
+
+ s32b energy; /* Current energy */
+
+ s16b food; /* Current nutrition */
+
+ byte confusing; /* Glowing hands */
+ byte searching; /* Currently searching */
+
+ s16b new_spells; /* Number of spells available */
+
+ s16b old_spells;
+
+ s16b xtra_spells; /* Number of xtra spell learned(via potion) */
+
+ bool_ old_cumber_armor;
+ bool_ old_cumber_glove;
+ bool_ old_heavy_wield;
+ bool_ old_heavy_shoot;
+ bool_ old_icky_wield;
+
+ s16b old_lite; /* Old radius of lite (if any) */
+ s16b old_view; /* Old radius of view (if any) */
+
+ s16b old_food_aux; /* Old value of food */
+
+
+ bool_ cumber_armor; /* Mana draining armor */
+ bool_ cumber_glove; /* Mana draining gloves */
+ bool_ heavy_wield; /* Heavy weapon */
+ bool_ heavy_shoot; /* Heavy shooter */
+ bool_ icky_wield; /* Icky weapon */
+ bool_ immovable; /* Immovable character */
+
+ s16b cur_lite; /* Radius of lite (if any) */
+
+
+ u32b notice; /* Special Updates (bit flags) */
+ u32b update; /* Pending Updates (bit flags) */
+ u32b redraw; /* Normal Redraws (bit flags) */
+ u32b window; /* Window Redraws (bit flags) */
+
+ s16b stat_use[6]; /* Current modified stats */
+ s16b stat_top[6]; /* Maximal modified stats */
+
+ s16b stat_add[6]; /* Modifiers to stat values */
+ s16b stat_ind[6]; /* Indexes into stat tables */
+ s16b stat_cnt[6]; /* Counter for temporary drains */
+ s16b stat_los[6]; /* Amount of temporary drains */
+
+ bool_ immune_acid; /* Immunity to acid */
+ bool_ immune_elec; /* Immunity to lightning */
+ bool_ immune_fire; /* Immunity to fire */
+ bool_ immune_cold; /* Immunity to cold */
+ bool_ immune_neth; /* Immunity to nether */
+
+ bool_ resist_acid; /* Resist acid */
+ bool_ resist_elec; /* Resist lightning */
+ bool_ resist_fire; /* Resist fire */
+ bool_ resist_cold; /* Resist cold */
+ bool_ resist_pois; /* Resist poison */
+
+ bool_ resist_conf; /* Resist confusion */
+ bool_ resist_sound; /* Resist sound */
+ bool_ resist_lite; /* Resist light */
+ bool_ resist_dark; /* Resist darkness */
+ bool_ resist_chaos; /* Resist chaos */
+ bool_ resist_disen; /* Resist disenchant */
+ bool_ resist_shard; /* Resist shards */
+ bool_ resist_nexus; /* Resist nexus */
+ bool_ resist_blind; /* Resist blindness */
+ bool_ resist_neth; /* Resist nether */
+ bool_ resist_fear; /* Resist fear */
+ bool_ resist_continuum; /* Resist space-time continuum disruption */
+
+ bool_ sensible_fire; /* Fire does more damage on the player */
+ bool_ sensible_lite; /* Lite does more damage on the player and blinds her/him */
+
+ bool_ reflect; /* Reflect 'bolt' attacks */
+ bool_ sh_fire; /* Fiery 'immolation' effect */
+ bool_ sh_elec; /* Electric 'immolation' effect */
+ bool_ wraith_form; /* wraithform */
+
+ bool_ anti_magic; /* Anti-magic */
+ bool_ anti_tele; /* Prevent teleportation */
+
+ bool_ sustain_str; /* Keep strength */
+ bool_ sustain_int; /* Keep intelligence */
+ bool_ sustain_wis; /* Keep wisdom */
+ bool_ sustain_dex; /* Keep dexterity */
+ bool_ sustain_con; /* Keep constitution */
+ bool_ sustain_chr; /* Keep charisma */
+
+ bool_ aggravate; /* Aggravate monsters */
+ bool_ teleport; /* Random teleporting */
+
+ bool_ exp_drain; /* Experience draining */
+ byte drain_mana; /* mana draining */
+ byte drain_life; /* hp draining */
+
+ bool_ magical_breath; /* Magical breathing -- can breath anywhere */
+ bool_ water_breath; /* Water breathing -- can breath underwater */
+ bool_ climb; /* Can climb mountains */
+ bool_ fly; /* Can fly over some features */
+ bool_ ffall; /* No damage falling */
+ bool_ lite; /* Permanent light */
+ bool_ free_act; /* Never paralyzed */
+ bool_ see_inv; /* Can see invisible */
+ bool_ regenerate; /* Regenerate hit pts */
+ bool_ hold_life; /* Resist life draining */
+ u32b telepathy; /* Telepathy */
+ bool_ slow_digest; /* Slower digestion */
+ bool_ bless_blade; /* Blessed blade */
+ byte xtra_might; /* Extra might bow */
+ bool_ impact; /* Earthquake blows */
+ bool_ auto_id; /* Auto id items */
+
+ s16b invis; /* Invisibility */
+
+ s16b dis_to_h; /* Known bonus to hit */
+ s16b dis_to_d; /* Known bonus to dam */
+ s16b dis_to_a; /* Known bonus to ac */
+
+ s16b dis_ac; /* Known base ac */
+
+ s16b to_l; /* Bonus to life */
+ s16b to_m; /* Bonus to mana */
+ s16b to_s; /* Bonus to spell */
+ s16b to_h; /* Bonus to hit */
+ s16b to_d; /* Bonus to dam */
+ s16b to_h_melee; /* Bonus to hit for melee */
+ s16b to_d_melee; /* Bonus to dam for melee */
+ s16b to_h_ranged; /* Bonus to hit for ranged */
+ s16b to_d_ranged; /* Bonus to dam for ranged */
+ s16b to_a; /* Bonus to ac */
+
+ s16b ac; /* Base ac */
+
+ byte antimagic; /* Power of the anti magic field */
+ byte antimagic_dis; /* Radius of the anti magic field */
+
+ s16b see_infra; /* Infravision range */
+
+ s16b skill_dis; /* Skill: Disarming */
+ s16b skill_dev; /* Skill: Magic Devices */
+ s16b skill_sav; /* Skill: Saving throw */
+ s16b skill_stl; /* Skill: Stealth factor */
+ s16b skill_srh; /* Skill: Searching ability */
+ s16b skill_fos; /* Skill: Searching frequency */
+ s16b skill_thn; /* Skill: To hit (normal) */
+ s16b skill_thb; /* Skill: To hit (shooting) */
+ s16b skill_tht; /* Skill: To hit (throwing) */
+ s16b skill_dig; /* Skill: Digging */
+
+ s16b num_blow; /* Number of blows */
+ s16b num_fire; /* Number of shots */
+ s16b xtra_crit; /* % of increased crits */
+
+ byte throw_mult; /* Multiplier for throw damage */
+
+ byte tval_xtra; /* Correct xtra tval */
+
+ byte tval_ammo; /* Correct ammo tval */
+
+ s16b pspeed; /* Current speed */
+
+ u32b mimic_extra; /* Mimicry powers use that */
+ u32b antimagic_extra; /* Antimagic powers */
+ u32b druid_extra; /* Druid powers */
+ u32b druid_extra2; /* Druid powers */
+ u32b druid_extra3; /* Druid powers */
+ u32b music_extra; /* Music songs */
+ u32b music_extra2; /* Music songs */
+ u32b necro_extra; /* Necro powers */
+ u32b necro_extra2; /* Necro powers */
+
+ u32b race_extra1; /* Variable for race */
+ u32b race_extra2; /* Variable for race */
+ u32b race_extra3; /* Variable for race */
+ u32b race_extra4; /* Variable for race */
+ u32b race_extra5; /* Variable for race */
+ u32b race_extra6; /* Variable for race */
+ u32b race_extra7; /* Variable for race */
+
+ s16b dodge_chance; /* Dodging chance */
+
+ u32b maintain_sum; /* Do we have partial summons */
+
+ byte spellbinder_num; /* Number of spells bound */
+ u32b spellbinder[4]; /* Spell bounds */
+ byte spellbinder_trigger; /* Spellbinder trigger condition */
+
+ cptr mimic_name;
+
+ char tactic; /* from 128-4 extremely coward to */
+ /* 128+4 berserker */
+ char movement; /* base movement way */
+
+ s16b companion_killed; /* Number of companion death */
+
+ bool_ no_mortal; /* Fated to never die by the hand of a mortal being */
+
+ bool_ black_breath; /* The Tolkien's Black Breath */
+
+ bool_ precognition; /* Like the cheat mode */
+
+ /*** Extra flags -- used for lua and easying stuff ***/
+ u32b xtra_f1;
+ u32b xtra_f2;
+ u32b xtra_f3;
+ u32b xtra_f4;
+ u32b xtra_f5;
+ u32b xtra_esp;
+
+ /* Corruptions */
+ bool_ *corruptions;
+
+ /*** Pet commands ***/
+ byte pet_follow_distance; /* Length of the imaginary "leash" for pets */
+ byte pet_open_doors; /* flag - allow pets to open doors */
+ byte pet_pickup_items; /* flag - allow pets to pickup items */
+
+ s16b control; /* Controlled monster */
+ byte control_dir; /* Controlled monster */
+
+ /*** Body changing variables ***/
+ u16b body_monster; /* In which body is the player */
+ bool_ disembodied; /* Is the player in a body ? */
+ byte body_parts[INVEN_TOTAL - INVEN_WIELD]; /* Which body parts does he have ? */
+
+ /* Astral */
+ bool_ astral; /* We started at the bottom ? */
+
+ /* Powers */
+ bool_ *powers; /* Actual powers */
+ bool_ powers_mod[POWER_MAX_INIT]; /* Intrinsinc powers */
+
+ /* Skills */
+ s16b skill_points;
+ s16b skill_last_level; /* Prevents gaining skills by losing level and regaining them */
+ s16b melee_style; /* How are */
+ s16b use_piercing_shots; /* for archery */
+
+ /* Help */
+ help_info help;
+
+ /*** Temporary fields ***/
+
+ bool_ did_nothing; /* True if the last action wasnt a real action */
+ bool_ leaving; /* True if player is leaving */
+};
+
+
+/* For Monk martial arts */
+
+typedef struct martial_arts martial_arts;
+
+struct martial_arts
+{
+ cptr desc; /* A verbose attack description */
+ int min_level; /* Minimum level to use */
+ int chance; /* Chance of 'success' */
+ int dd; /* Damage dice */
+ int ds; /* Damage sides */
+ s16b effect; /* Special effects */
+ s16b power; /* Special effects power */
+};
+
+
+
+/* Powers - used by Mindcrafters and Necromancers */
+typedef struct magic_power magic_power;
+
+struct magic_power
+{
+ int min_lev;
+ int mana_cost;
+ int fail;
+ cptr name;
+ cptr desc;
+};
+
+/* Border */
+typedef struct border_type border_type;
+
+struct border_type
+{
+ byte north[MAX_WID];
+ byte south[MAX_WID];
+ byte east[MAX_HGT];
+ byte west[MAX_HGT];
+ byte north_west;
+ byte north_east;
+ byte south_west;
+ byte south_east;
+};
+
+
+/*
+ * A structure describing a wilderness area
+ * with a terrain, a town or a dungeon entrance
+ */
+typedef struct wilderness_type_info wilderness_type_info;
+
+struct wilderness_type_info
+{
+ u32b name; /* Name (offset) */
+ u32b text; /* Text (offset) */
+ u16b entrance; /* Which town is there(<1000 i's a town, >=1000 it a dungeon) */
+ s32b wild_x; /* Map coordinates (backed out while parsing map) */
+ s32b wild_y;
+ byte road; /* Flags of road */
+ int level; /* Difficulty level */
+ u32b flags1; /* Some flags */
+ byte feat; /* The feature of f_info.txt that is used to allow passing, ... and to get a char/color/graph */
+ byte terrain_idx; /* Terrain index(defined in defines.h) */
+
+ byte terrain[MAX_WILD_TERRAIN];/* Feature types for the plasma generator */
+};
+
+/*
+ * A structure describing a wilderness map
+ */
+typedef struct wilderness_map wilderness_map;
+
+struct wilderness_map
+{
+ int feat; /* Wilderness feature */
+ u32b seed; /* Seed for the RNG */
+ u16b entrance; /* Entrance for dungeons */
+
+ bool_ known; /* Is it seen by the player ? */
+};
+
+/*
+ * A structure describing a town with
+ * stores and buildings
+ */
+typedef struct town_type town_type;
+struct town_type
+{
+ cptr name;
+ u32b seed; /* Seed for RNG */
+ store_type *store; /* The stores [max_st_idx] */
+ byte numstores;
+
+ byte flags; /* Town flags */
+ /* Left this for the sake of compatibility */
+ bool_ stocked; /* Is the town actualy stocked ? */
+
+ bool_ destroyed; /* Is the town destroyed? */
+};
+
+
+/* Alchemists */
+
+typedef struct tval_desc2
+{
+ int tval;
+ cptr desc;
+} tval_desc2;
+
+typedef struct alchemist_recipe alchemist_recipe;
+struct alchemist_recipe
+{
+ int sval_essence;
+ byte tval;
+ byte sval;
+ byte qty;
+};
+
+typedef struct artifact_select_flag artifact_select_flag;
+struct artifact_select_flag {
+ byte group; /* Flag group to display it in */
+ int flag; /* item flag to set */
+ byte level; /* Player skill level to start at */
+ int desc; /* Display this description to select flag */
+ u32b xp; /* xp cost for this flag */
+ bool_ pval; /* indicates this flag benifits from pval */
+ int item_desc; /* Description of required item */
+ int item_descp; /* Description of required item */
+ byte rtval; /* Required items' tval */
+ byte rsval; /* Required items' sval */
+ int rpval; /* Required items' pval (zero for no req) */
+ int rflag[6]; /* Monster Race flags for required Corpses */
+};
+
+/*
+ A structure for deity information.
+ */
+typedef struct deity_type deity_type;
+struct deity_type
+{
+ cptr name;
+ char desc[10][80];
+};
+
+/* A structure for tactics */
+typedef struct tactic_info_type tactic_info_type;
+
+struct tactic_info_type
+{
+ s16b to_hit;
+ s16b to_dam;
+ s16b to_ac;
+ s16b to_stealth;
+ s16b to_disarm;
+ s16b to_saving;
+ cptr name;
+};
+
+/* A structure to describe a random artifact. */
+typedef struct random_artifact random_artifact;
+
+struct random_artifact
+{
+ char name_full[80]; /* Full name for the artifact */
+ char name_short[80]; /* Un-Id'd name */
+ byte level; /* Level of the artifact */
+ byte attr; /* Color that is used on the screen */
+ u32b cost; /* Object's value */
+ byte activation; /* Activation. */
+ s16b timeout; /* Timeout. */
+ byte generated; /* Does it exist already? */
+};
+
+/* A structure to describe an activation. */
+typedef struct activation activation;
+
+struct activation
+{
+ char desc[80]; /* Desc of the activation */
+ u32b cost; /* costs value */
+ s16b spell; /* Spell. */
+};
+
+/* A structure to describe a music. */
+typedef struct music music;
+
+struct music
+{
+ char desc[80]; /* Desc of the music */
+ s16b music; /* Music. */
+ s16b dur; /* Duration(if any) */
+ s16b init_recharge; /* Minimal recharge time */
+ s16b turn_recharge; /* Recharge time for each more turn */
+ byte min_inst; /* Minimum instrument for the music */
+ byte rarity; /* Rarity of the music(use 100 to unallow to be randomly generated) */
+};
+
+/* A structure to describe the random spells of the Power Mages */
+typedef struct random_spell random_spell;
+
+struct random_spell
+{
+ char desc[30]; /* Desc of the spell */
+ char name[30]; /* Name of the spell */
+ s16b mana; /* Mana cost */
+ s16b fail; /* Failure rate */
+ u32b proj_flags; /* Project function flags */
+ byte GF; /* Type of the projection */
+ byte radius;
+ byte dam_sides;
+ byte dam_dice;
+ byte level; /* Level needed */
+ bool_ untried; /* Is the spell was tried? */
+};
+
+/* A structure to describe the fate of the player */
+typedef struct fate fate;
+
+struct fate
+{
+ byte fate; /* Which fate */
+ byte level; /* On which level */
+ byte serious; /* Is it sure? */
+ s16b o_idx; /* Object to find */
+ s16b e_idx; /* Ego-Item to find */
+ s16b a_idx; /* Artifact to find */
+ s16b v_idx; /* Vault to find */
+ s16b r_idx; /* Monster to find */
+ s16b count; /* Number of things */
+ s16b time; /* Turn before */
+ bool_ know; /* Has it been predicted? */
+ bool_ icky; /* Hackish runtime-only flag */
+};
+
+/* A structure for movements */
+typedef struct move_info_type move_info_type;
+
+struct move_info_type
+{
+ s16b to_speed;
+ s16b to_search;
+ s16b to_stealth;
+ s16b to_percep;
+ cptr name;
+};
+
+/* Define monster generation rules */
+typedef struct rule_type rule_type;
+struct rule_type
+{
+ byte mode; /* Mode of combination of the monster flags */
+ byte percent; /* Percent of monsters affected by the rule */
+
+ u32b mflags1; /* The monster flags that are allowed */
+ u32b mflags2;
+ u32b mflags3;
+ u32b mflags4;
+ u32b mflags5;
+ u32b mflags6;
+ u32b mflags7;
+ u32b mflags8;
+ u32b mflags9;
+
+ char r_char[5]; /* Monster race allowed */
+};
+
+/* A structure for the != dungeon types */
+typedef struct dungeon_info_type dungeon_info_type;
+struct dungeon_info_type
+{
+ u32b name; /* Name */
+ u32b text; /* Description */
+ char short_name[3]; /* Short name */
+
+ char generator[30]; /* Name of the level generator */
+
+ s16b floor1; /* Floor tile 1 */
+ byte floor_percent1[2]; /* Chance of type 1 */
+ s16b floor2; /* Floor tile 2 */
+ byte floor_percent2[2]; /* Chance of type 2 */
+ s16b floor3; /* Floor tile 3 */
+ byte floor_percent3[2]; /* Chance of type 3 */
+ s16b outer_wall; /* Outer wall tile */
+ s16b inner_wall; /* Inner wall tile */
+ s16b fill_type1; /* Cave tile 1 */
+ byte fill_percent1[2]; /* Chance of type 1 */
+ s16b fill_type2; /* Cave tile 2 */
+ byte fill_percent2[2]; /* Chance of type 2 */
+ s16b fill_type3; /* Cave tile 3 */
+ byte fill_percent3[2]; /* Chance of type 3 */
+ byte fill_method; /* Smoothing parameter for the above */
+
+ s16b mindepth; /* Minimal depth */
+ s16b maxdepth; /* Maximal depth */
+
+ bool_ principal; /* If it's a part of the main dungeon */
+ byte next; /* The next part of the main dungeon */
+ byte min_plev; /* Minimal plev needed to enter -- it's an anti-cheating mesure */
+
+ int min_m_alloc_level; /* Minimal number of monsters per level */
+ int max_m_alloc_chance; /* There is a 1/max_m_alloc_chance chance per round of creating a new monster */
+
+ u32b flags1; /* Flags 1 */
+ u32b flags2; /* Flags 1 */
+
+ int size_x, size_y; /* Desired numers of panels */
+
+ byte rule_percents[100]; /* Flat rule percents */
+ rule_type rules[5]; /* Monster generation rules */
+
+ int final_object; /* The object you'll find at the bottom */
+ int final_artifact; /* The artifact you'll find at the bottom */
+ int final_guardian; /* The artifact's guardian. If an artifact is specified, then it's NEEDED */
+
+ int ix, iy, ox, oy; /* Wilderness coordinates of the entrance/output of the dungeon */
+
+ obj_theme objs; /* The drops type */
+
+ int d_dice[4]; /* Number of dices */
+ int d_side[4]; /* Number of sides */
+ int d_frequency[4]; /* Frequency of damage (1 is the minimum) */
+ int d_type[4]; /* Type of damage */
+
+ s16b t_idx[TOWN_DUNGEON]; /* The towns */
+ s16b t_level[TOWN_DUNGEON]; /* The towns levels */
+ s16b t_num; /* Number of towns */
+};
+
+/* A structure for inscriptions */
+typedef struct inscription_info_type inscription_info_type;
+struct inscription_info_type
+{
+ char text[40]; /* The inscription itself */
+ byte when; /* When it is executed */
+ bool_ know; /* Is the inscription know ? */
+ byte mana; /* Grid mana needed */
+};
+
+/* To hold Runecrafters prefered spells */
+typedef struct rune_spell rune_spell;
+struct rune_spell
+{
+ char name[30]; /* name */
+
+ s16b type; /* Type of the spell(GF) */
+ s16b rune2; /* Modifiers */
+ s16b mana; /* Mana involved */
+};
+
+/* For level gaining artifacts, artifact creation, ... */
+typedef struct flags_group flags_group;
+struct flags_group
+{
+ char name[30]; /* Name */
+ byte color; /* Color */
+
+ byte price; /* Price to "buy" it */
+
+ u32b flags1; /* Flags set 1 */
+ u32b flags2; /* Flags set 2 */
+ u32b flags3; /* Flags set 3 */
+ u32b flags4; /* Flags set 4 */
+ u32b esp; /* ESP flags set */
+};
+
+/* For powers(racial, class, mutation, artifacts, ... */
+typedef struct power_type power_type;
+struct power_type
+{
+ char *name; /* Name */
+ char *desc_text; /* Text describing power */
+ char *gain_text; /* Text displayed on gaining the power */
+ char *lose_text; /* Text displayed on losing the power */
+
+ byte level; /* Min level */
+ byte cost; /* Mana/Life cost */
+ byte stat; /* Stat used */
+ byte diff; /* Difficulty */
+};
+
+/* Hooks */
+typedef bool_ (*hook_type)(char *fmt);
+
+/*
+ * Structure for the "quests"
+ */
+typedef struct quest_type quest_type;
+
+struct quest_type
+{
+ bool_ silent;
+
+ bool_ dynamic_desc; /* Do we need to ask a function to get the description ? */
+
+ char name[40]; /* Quest name */
+
+ char desc[10][80]; /* Quest desc */
+
+ s16b status; /* Is the quest taken, completed, finished? */
+
+ s16b level; /* Dungeon level */
+
+ s16b *plot; /* Which plot does it belongs to? */
+
+ byte type; /* Lua or C ? */
+
+ bool_ (*init)(int q); /* Function that takes care of generating hardcoded quests */
+
+ s32b data[4]; /* Various datas used by the quests */
+
+ bool_ (*gen_desc)(FILE *fff); /* Function for generating description. */
+};
+typedef struct random_quest random_quest;
+struct random_quest
+{
+ byte type; /* Type/number of monsters to kill(0 = no quest) */
+ s16b r_idx; /* Monsters to crush */
+ bool_ done; /* Done ? */
+};
+
+/* Monster powers for player uses */
+typedef struct monster_power monster_power;
+struct monster_power
+{
+ u32b power; /* Power RF?_xxx */
+ cptr name; /* Name of it */
+ int mana; /* Mana needed */
+ bool_ great; /* Need the use of great spells */
+};
+
+/* Tval descs */
+typedef struct tval_desc tval_desc;
+struct tval_desc
+{
+ int tval; /* tval */
+ cptr desc; /* desc */
+};
+
+/*
+ * Between exit
+ */
+typedef struct between_exit between_exit;
+struct between_exit
+{
+ s16b corresp; /* Corresponding between gate */
+ bool_ dungeon; /* Do we exit in a dungeon or in the wild ? */
+
+ s16b wild_x, wild_y; /* Wilderness spot to land onto */
+ s16b px, py; /* Location of the map */
+
+ s16b d_idx; /* Dungeon to land onto */
+ s16b level;
+};
+
+/*
+ * A structure to hold "rolled" information
+ */
+typedef struct birther birther;
+struct birther
+{
+ s16b sex;
+ s16b race;
+ s16b rmod;
+ s16b pclass;
+ s16b spec;
+
+ byte quests;
+
+ byte god;
+ s32b grace;
+ s32b god_favor;
+
+ s16b age;
+ s16b wt;
+ s16b ht;
+ s16b sc;
+
+ s32b au;
+
+ s16b stat[6];
+ s16b luck;
+
+ s16b chaos_patron;
+
+ u32b weapon;
+
+ char history[4][60];
+
+ bool_ quick_ok;
+};
+
+typedef struct hooks_chain hooks_chain;
+struct hooks_chain
+{
+ hook_type hook;
+ char name[40];
+ char script[40];
+ byte type;
+ hooks_chain *next;
+};
+
+typedef union hook_return hook_return;
+union hook_return
+{
+ s32b num;
+ cptr str;
+ object_type *o_ptr;
+ monster_type *m_ptr;
+};
+
+/*
+ * Forward declare
+ */
+typedef struct hist_type hist_type;
+
+/*
+ * Player background information
+ */
+struct hist_type
+{
+ s32b info; /* Textual History -- uses rp_text */
+
+ byte roll; /* Frequency of this entry */
+ s16b chart; /* Chart index */
+ s16b next; /* Next chart index */
+ byte bonus; /* Social Class Bonus + 50 */
+};
+
+/*
+ * Item sets
+ */
+typedef struct set_type set_type;
+struct set_type
+{
+ u32b name; /* Name */
+ u32b desc; /* Desc */
+
+ byte num; /* Number of artifacts used */
+ byte num_use; /* Number actually wore */
+ struct /* the various items */
+ {
+ bool_ present; /* Is it actually wore ? */
+ s16b a_idx; /* What artifact ? */
+ s16b pval[6]; /* Pval for each combination */
+ u32b flags1[6]; /* Flags */
+ u32b flags2[6]; /* Flags */
+ u32b flags3[6]; /* Flags */
+ u32b flags4[6]; /* Flags */
+ u32b flags5[6]; /* Flags */
+ u32b esp[6]; /* Flags */
+ } arts[6];
+};
+
+/* A structure for CLI commands. */
+typedef struct cli_comm cli_comm;
+struct cli_comm
+{
+ cptr comm; /* Extended name of the command. */
+ cptr descrip; /* Description of the command. */
+ s16b key; /* Key to convert command to. */
+};
+
+/*
+ * Skills !
+ */
+typedef struct skill_type skill_type;
+struct skill_type
+{
+ u32b name; /* Name */
+ u32b desc; /* Description */
+ u32b action_desc; /* Action Description */
+
+ s16b action_mkey; /* Action do to */
+
+ s32b i_value; /* Actual value */
+ s32b i_mod; /* Modifier(1 skill point = modifier skill) */
+
+ s32b value; /* Actual value */
+ s32b mod; /* Modifier(1 skill point = modifier skill) */
+ s16b rate; /* Modifier decreasing rate */
+
+ u32b uses; /* Number of times used */
+
+ s16b action[MAX_SKILLS]; /* List of actions against other skills */
+
+ s16b father; /* Father in the skill tree */
+ bool_ dev; /* Is the branch developped ? */
+ s16b order; /* Order in the tree */
+ bool_ hidden; /* Innactive */
+
+ byte random_gain_chance; /* random gain chance, still needs the flag */
+
+ u32b flags1; /* Skill flags */
+};
+
+
+/*
+ * The spell function must provide the desc
+ */
+typedef struct spell_type spell_type;
+struct spell_type
+{
+ cptr name; /* Name */
+ byte skill_level; /* Required level (to learn) */
+ byte mana; /* Required mana at lvl 1 */
+ byte mana_max; /* Required mana at max lvl */
+ s16b fail; /* Minimum chance of failure */
+ s16b level; /* Spell level(0 = not learnt) */
+};
+
+typedef struct school_type school_type;
+struct school_type
+{
+ cptr name; /* Name */
+ s16b skill; /* Skill used for that school */
+};
+
+/*
+ * Desc for GF_FOO
+ */
+typedef struct gf_name_type gf_name_type;
+struct gf_name_type
+{
+ int gf;
+ cptr name;
+};
+
+/*
+ * Timers
+ */
+typedef struct timer_type timer_type;
+struct timer_type
+{
+ timer_type *next; /* The next timer in the list */
+
+ bool_ enabled; /* Is it currently counting? */
+
+ s32b delay; /* Delay between activations */
+ s32b countdown; /* The current number of turns passed, when it reaches delay it fires */
+
+ cptr callback; /* The lua function to call upon firing(no C callback yet .. maybe) */
+};
+
+/*
+ * This is for lua functions that need to pass table to c functions
+ */
+typedef struct list_type list_type;
+struct list_type
+{
+ cptr *list;
+};
+
+/*
+ * Abilities
+ */
+typedef struct ability_type ability_type;
+struct ability_type
+{
+ u32b name; /* Name */
+ u32b desc; /* Description */
+ u32b action_desc; /* Action Description */
+
+ s16b action_mkey; /* Action do to */
+
+ s16b cost; /* Skill points cost */
+
+ bool_ acquired; /* Do the player actualylg ot it ? */
+
+ /* Prereqs */
+ s16b skills[10]; /* List of prereq skills(10 max) */
+ s16b skill_levels[10]; /* List of prereq skills(10 max) */
+ s16b stat[6]; /* List of prereq stats */
+ s16b need_abilities[10]; /* List of prereq abilities(10 max) */
+ s16b forbid_abilities[10]; /* List of forbidden abilities(10 max) */
+};
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 00000000..93e38e4a
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,4479 @@
+/* File: util.c */
+
+/* Purpose: Angband utilities -BEN- */
+
+
+#include "angband.h"
+
+
+
+
+#ifndef HAS_MEMSET
+
+/*
+* For those systems that don't have "memset()"
+*
+* Set the value of each of 'n' bytes starting at 's' to 'c', return 's'
+* If 'n' is negative, you will erase a whole lot of memory.
+*/
+char *memset(char *s, int c, huge n)
+{
+ char *t;
+ for (t = s; len--; ) *t++ = c;
+ return (s);
+}
+
+#endif
+
+
+
+#ifndef HAS_STRICMP
+
+/*
+* For those systems that don't have "stricmp()"
+*
+* Compare the two strings "a" and "b" ala "strcmp()" ignoring case.
+*/
+int stricmp(cptr a, cptr b)
+{
+ cptr s1, s2;
+ char z1, z2;
+
+ /* Scan the strings */
+ for (s1 = a, s2 = b; TRUE; s1++, s2++)
+ {
+ z1 = FORCEUPPER(*s1);
+ z2 = FORCEUPPER(*s2);
+ if (z1 < z2) return ( -1);
+ if (z1 > z2) return (1);
+ if (!z1) return (0);
+ }
+}
+
+#endif
+
+
+#ifdef SET_UID
+
+# ifndef HAS_USLEEP
+
+/*
+* For those systems that don't have "usleep()" but need it.
+*
+* Fake "usleep()" function grabbed from the inl netrek server -cba
+*/
+int usleep(huge usecs)
+{
+ struct timeval Timer;
+
+ int nfds = 0;
+
+#ifdef FD_SET
+ fd_set *no_fds = NULL;
+#else
+int *no_fds = NULL;
+#endif
+
+
+ /* Was: int readfds, writefds, exceptfds; */
+ /* Was: readfds = writefds = exceptfds = 0; */
+
+
+ /* Paranoia -- No excessive sleeping */
+ if (usecs > 4000000L) core("Illegal usleep() call");
+
+
+ /* Wait for it */
+ Timer.tv_sec = (usecs / 1000000L);
+ Timer.tv_usec = (usecs % 1000000L);
+
+ /* Wait for it */
+ if (select(nfds, no_fds, no_fds, no_fds, &Timer) < 0)
+ {
+ /* Hack -- ignore interrupts */
+ if (errno != EINTR) return -1;
+ }
+
+ /* Success */
+ return 0;
+}
+
+# endif
+
+
+/*
+* Hack -- External functions
+*/
+extern struct passwd *getpwuid();
+extern struct passwd *getpwnam();
+
+
+/*
+* Find a default user name from the system.
+*/
+void user_name(char *buf, int id)
+{
+#ifdef SET_UID
+ struct passwd *pw;
+
+ /* Look up the user name */
+ if ((pw = getpwuid(id)))
+ {
+ (void)strcpy(buf, pw->pw_name);
+ buf[16] = '\0';
+
+ return;
+ }
+#endif /* SET_UID */
+
+ /* Oops. Hack -- default to "PLAYER" */
+ strcpy(buf, "PLAYER");
+}
+
+#endif /* SET_UID */
+
+
+
+
+/*
+* The concept of the "file" routines below (and elsewhere) is that all
+* file handling should be done using as few routines as possible, since
+* every machine is slightly different, but these routines always have the
+* same semantics.
+*
+* In fact, perhaps we should use the "path_parse()" routine below to convert
+* from "canonical" filenames (optional leading tilde's, internal wildcards,
+* slash as the path seperator, etc) to "system" filenames (no special symbols,
+* system-specific path seperator, etc). This would allow the program itself
+* to assume that all filenames are "Unix" filenames, and explicitly "extract"
+* such filenames if needed (by "path_parse()", or perhaps "path_canon()").
+*
+* Note that "path_temp" should probably return a "canonical" filename.
+*
+* Note that "my_fopen()" and "my_open()" and "my_make()" and "my_kill()"
+* and "my_move()" and "my_copy()" should all take "canonical" filenames.
+*
+* Note that "canonical" filenames use a leading "slash" to indicate an absolute
+* path, and a leading "tilde" to indicate a special directory, and default to a
+* relative path, but MSDOS uses a leading "drivename plus colon" to indicate the
+* use of a "special drive", and then the rest of the path is parsed "normally",
+* and MACINTOSH uses a leading colon to indicate a relative path, and an embedded
+* colon to indicate a "drive plus absolute path", and finally defaults to a file
+* in the current working directory, which may or may not be defined.
+*
+* We should probably parse a leading "~~/" as referring to "ANGBAND_DIR". (?)
+*/
+
+
+#ifdef SET_UID
+
+/*
+* Extract a "parsed" path from an initial filename
+* Normally, we simply copy the filename into the buffer
+* But leading tilde symbols must be handled in a special way
+* Replace "~/" by the home directory of the current user
+*/
+errr path_parse(char *buf, int max, cptr file)
+{
+ cptr u, s;
+ struct passwd *pw;
+
+
+ /* Assume no result */
+ buf[0] = '\0';
+
+ /* No file? */
+ if (!file) return ( -1);
+
+ /* File needs no parsing */
+ if (file[0] != '~')
+ {
+ strcpy(buf, file);
+ return (0);
+ }
+
+ /* Point at the user */
+ u = file + 1;
+
+ /* Look for non-user portion of the file */
+ s = strstr(u, PATH_SEP);
+
+#ifdef GETLOGIN_BROKEN
+ /* Ask the environment for the home directory */
+ u = getenv("HOME");
+
+ if (!u) return (1);
+
+ (void)strcpy(buf, u);
+#else
+ /* Look up password data for user */
+ pw = getpwuid(getuid());
+
+ /* Nothing found? */
+ if (!pw) return (1);
+
+ /* Make use of the info */
+ (void)strcpy(buf, pw->pw_dir);
+#endif
+
+ /* Append the rest of the filename, if any */
+ if (s) (void)strcat(buf, s);
+
+ /* Success */
+ return (0);
+}
+
+
+#else /* SET_UID */
+
+
+/*
+* Extract a "parsed" path from an initial filename
+*
+* This requires no special processing on simple machines,
+* except for verifying the size of the filename.
+*/
+errr path_parse(char *buf, int max, cptr file)
+{
+ /* Accept the filename */
+ strnfmt(buf, max, "%s", file);
+
+ /* Success */
+ return (0);
+}
+
+
+#endif /* SET_UID */
+
+
+/*
+* Hack -- acquire a "temporary" file name if possible
+*
+* This filename is always in "system-specific" form.
+*/
+errr path_temp(char *buf, int max)
+{
+#ifdef WINDOWS
+ static u32b tmp_counter;
+ static char valid_characters[] =
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ char rand_ext[4];
+
+ rand_ext[0] = valid_characters[rand_int(sizeof (valid_characters))];
+ rand_ext[1] = valid_characters[rand_int(sizeof (valid_characters))];
+ rand_ext[2] = valid_characters[rand_int(sizeof (valid_characters))];
+ rand_ext[3] = '\0';
+ strnfmt(buf, max, "%s/t_%ud.%s", ANGBAND_DIR_XTRA, tmp_counter, rand_ext);
+ tmp_counter++;
+#else
+ cptr s;
+
+ /* Temp file */
+ s = tmpnam(NULL);
+
+ /* Oops */
+ if (!s) return ( -1);
+
+ /* Format to length */
+ strnfmt(buf, max, "%s", s);
+#endif
+ /* Success */
+ return (0);
+}
+
+
+/*
+* Create a new path by appending a file (or directory) to a path
+*
+* This requires no special processing on simple machines, except
+* for verifying the size of the filename, but note the ability to
+* bypass the given "path" with certain special file-names.
+*
+* Note that the "file" may actually be a "sub-path", including
+* a path and a file.
+*
+* Note that this function yields a path which must be "parsed"
+* using the "parse" function above.
+*/
+errr path_build(char *buf, int max, cptr path, cptr file)
+{
+ /* Special file */
+ if (file[0] == '~')
+ {
+ /* Use the file itself */
+ strnfmt(buf, max, "%s", file);
+ }
+
+ /* Absolute file, on "normal" systems */
+ else if (prefix(file, PATH_SEP) && !streq(PATH_SEP, ""))
+ {
+ /* Use the file itself */
+ strnfmt(buf, max, "%s", file);
+ }
+
+ /* No path given */
+ else if (!path[0])
+ {
+ /* Use the file itself */
+ strnfmt(buf, max, "%s", file);
+ }
+
+ /* Path and File */
+ else
+ {
+ /* Build the new path */
+ strnfmt(buf, max, "%s%s%s", path, PATH_SEP, file);
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+* Hack -- replacement for "fopen()"
+*/
+FILE *my_fopen(cptr file, cptr mode)
+{
+#ifndef MACH_O_CARBON
+
+ char buf[1024];
+
+ /* Hack -- Try to parse the path */
+ if (path_parse(buf, 1024, file)) return (NULL);
+
+ /* Attempt to fopen the file anyway */
+ return (fopen(buf, mode));
+
+#else /* MACH_O_CARBON */
+
+char buf[1024];
+FILE *s;
+
+/* Hack -- Try to parse the path */
+if (path_parse(buf, 1024, file)) return (NULL);
+
+/* Attempt to fopen the file anyway */
+s = fopen(buf, mode);
+
+/* Set creator and type if the file is successfully opened */
+if (s) fsetfileinfo(buf, _fcreator, _ftype);
+
+/* Done */
+return (s);
+
+#endif /* MACH_O_CARBON */
+}
+
+
+/*
+* Hack -- replacement for "fclose()"
+*/
+errr my_fclose(FILE *fff)
+{
+ /* Require a file */
+ if (!fff) return ( -1);
+
+ /* Close, check for error */
+ if (fclose(fff) == EOF) return (1);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+* Hack -- replacement for "fgets()"
+*
+* Read a string, without a newline, to a file
+*
+* Process tabs, strip internal non-printables
+*/
+errr my_fgets(FILE *fff, char *buf, huge n)
+{
+ huge i = 0;
+
+ while (TRUE)
+ {
+ int c = fgetc(fff);
+
+ if (c == EOF)
+ {
+ /* Terminate */
+ buf[i] = '\0';
+
+ /* Success (0) if some characters were read */
+ return (i == 0);
+ }
+
+ /* Handle newline -- DOS (\015\012), Mac (\015), UNIX (\012) */
+ else if (c == '\r')
+ {
+ c = fgetc(fff);
+ if (c != '\n') ungetc(c, fff);
+
+ /* Terminate */
+ buf[i] = '\0';
+
+ /* Success */
+ return (0);
+ }
+ else if (c == '\n')
+ {
+ c = fgetc(fff);
+ if (c != '\r') ungetc(c, fff);
+
+ /* Terminate */
+ buf[i] = '\0';
+
+ /* Success */
+ return (0);
+ }
+
+ /* Handle tabs */
+ else if (c == '\t')
+ {
+ /* Hack -- require room */
+ if (i + 8 >= n) break;
+
+ /* Append 1-8 spaces */
+ do { buf[i++] = ' '; } while (i % 8);
+ }
+
+ /* Handle printables */
+ else if (isprint(c))
+ {
+ /* Copy */
+ buf[i++] = c;
+
+ /* Check length */
+ if (i >= n) break;
+ }
+ }
+
+ /* Nothing */
+ buf[0] = '\0';
+
+ /* Failure */
+ return (1);
+}
+
+
+/*
+* Hack -- replacement for "fputs()"
+*
+* Dump a string, plus a newline, to a file
+*
+* XXX XXX XXX Process internal weirdness?
+*/
+errr my_fputs(FILE *fff, cptr buf, huge n)
+{
+ /* XXX XXX */
+ n = n ? n : 0;
+
+ /* Dump, ignore errors */
+ (void)fprintf(fff, "%s\n", buf);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+* Code Warrior is a little weird about some functions
+*/
+#ifdef BEN_HACK
+extern int open(const char *, int, ...);
+extern int close(int);
+extern int read(int, void *, unsigned int);
+extern int write(int, const void *, unsigned int);
+extern long lseek(int, long, int);
+#endif /* BEN_HACK */
+
+
+/*
+* The Macintosh is a little bit brain-dead sometimes
+*/
+#ifdef MACINTOSH
+# define open(N, F, M) \
+((M), open((char*)(N), F))
+# define write(F, B, S) \
+write(F, (char*)(B), S)
+#endif /* MACINTOSH */
+
+
+/*
+* Several systems have no "O_BINARY" flag
+*/
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif /* O_BINARY */
+
+
+/*
+* Hack -- attempt to delete a file
+*/
+errr fd_kill(cptr file)
+{
+ char buf[1024];
+
+ /* Hack -- Try to parse the path */
+ if (path_parse(buf, 1024, file)) return ( -1);
+
+ /* Remove */
+ (void)remove(buf);
+
+ /* XXX XXX XXX */
+ return (0);
+}
+
+
+/*
+* Hack -- attempt to move a file
+*/
+errr fd_move(cptr file, cptr what)
+{
+ char buf[1024];
+ char aux[1024];
+
+ /* Hack -- Try to parse the path */
+ if (path_parse(buf, 1024, file)) return ( -1);
+
+ /* Hack -- Try to parse the path */
+ if (path_parse(aux, 1024, what)) return ( -1);
+
+ /* Rename */
+ (void)rename(buf, aux);
+
+ /* XXX XXX XXX */
+ return (0);
+}
+
+
+/*
+* Hack -- attempt to copy a file
+*/
+errr fd_copy(cptr file, cptr what)
+{
+ char buf[1024];
+ char aux[1024];
+
+ /* Hack -- Try to parse the path */
+ if (path_parse(buf, 1024, file)) return ( -1);
+
+ /* Hack -- Try to parse the path */
+ if (path_parse(aux, 1024, what)) return ( -1);
+
+ /* Copy XXX XXX XXX */
+ /* (void)rename(buf, aux); */
+
+ /* XXX XXX XXX */
+ return (1);
+}
+
+
+/*
+* Hack -- attempt to open a file descriptor (create file)
+*
+* This function should fail if the file already exists
+*
+* Note that we assume that the file should be "binary"
+*
+* XXX XXX XXX The horrible "BEN_HACK" code is for compiling under
+* the CodeWarrior compiler, in which case, for some reason, none
+* of the "O_*" flags are defined, and we must fake the definition
+* of "O_RDONLY", "O_WRONLY", and "O_RDWR" in "A-win-h", and then
+* we must simulate the effect of the proper "open()" call below.
+*/
+int fd_make(cptr file, int mode)
+{
+ char buf[1024];
+
+ /* Hack -- Try to parse the path */
+ if (path_parse(buf, 1024, file)) return ( -1);
+
+#ifdef BEN_HACK
+
+ /* Check for existance */
+ /* if (fd_close(fd_open(file, O_RDONLY | O_BINARY))) return (1); */
+
+ /* Mega-Hack -- Create the file */
+ (void)my_fclose(my_fopen(file, "wb"));
+
+ /* Re-open the file for writing */
+ return (open(buf, O_WRONLY | O_BINARY, mode));
+
+#else /* BEN_HACK */
+
+#ifdef MACH_O_CARBON
+
+{
+int fdes;
+
+/* Create the file, fail if exists, write-only, binary */
+fdes = open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode);
+
+/* Set creator and type if the file is successfully opened */
+if (fdes >= 0) fsetfileinfo(buf, _fcreator, _ftype);
+
+/* Return the descriptor */
+return (fdes);
+}
+
+#else /* MACH_O_CARBON */
+
+/* Create the file, fail if exists, write-only, binary */
+return (open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode));
+
+#endif /* MACH_O_CARBON */
+
+#endif /* BEN_HACK */
+
+}
+
+
+/*
+* Hack -- attempt to open a file descriptor (existing file)
+*
+* Note that we assume that the file should be "binary"
+*/
+int fd_open(cptr file, int flags)
+{
+ char buf[1024];
+
+ /* Hack -- Try to parse the path */
+ if (path_parse(buf, 1024, file)) return ( -1);
+
+#ifdef MACH_O_CARBON
+
+ {
+ int fdes;
+
+ /* Attempt to open the file */
+ fdes = open(buf, flags | O_BINARY, 0);
+
+ /* Set creator and type if the file is successfully opened */
+ if (fdes >= 0) fsetfileinfo(buf, _fcreator, _ftype);
+
+ /* Return the descriptor */
+ return (fdes);
+ }
+
+#else /* MACH_O_CARBON */
+
+/* Attempt to open the file */
+return (open(buf, flags | O_BINARY, 0));
+
+#endif /* MACH_O_CARBON */
+}
+
+
+/*
+* Hack -- attempt to lock a file descriptor
+*
+* Legal lock types -- F_UNLCK, F_RDLCK, F_WRLCK
+*/
+errr fd_lock(int fd, int what)
+{
+ /* XXX XXX */
+ what = what ? what : 0;
+
+ /* Verify the fd */
+ if (fd < 0) return ( -1);
+
+#ifdef SET_UID
+
+# ifdef USG
+
+# if defined(F_ULOCK) && defined(F_LOCK)
+
+ /* Un-Lock */
+ if (what == F_UNLCK)
+ {
+ /* Unlock it, Ignore errors */
+ lockf(fd, F_ULOCK, 0);
+ }
+
+ /* Lock */
+ else
+ {
+ /* Lock the score file */
+ if (lockf(fd, F_LOCK, 0) != 0) return (1);
+ }
+
+# endif
+
+# else
+
+# if defined(LOCK_UN) && defined(LOCK_EX)
+
+ /* Un-Lock */
+ if (what == F_UNLCK)
+ {
+ /* Unlock it, Ignore errors */
+ (void)flock(fd, LOCK_UN);
+ }
+
+ /* Lock */
+ else
+ {
+ /* Lock the score file */
+ if (flock(fd, LOCK_EX) != 0) return (1);
+ }
+
+# endif
+
+# endif
+
+#endif
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+* Hack -- attempt to seek on a file descriptor
+*/
+errr fd_seek(int fd, huge n)
+{
+ s32b p;
+
+ /* Verify fd */
+ if (fd < 0) return ( -1);
+
+ /* Seek to the given position */
+ p = lseek(fd, n, SEEK_SET);
+
+ /* Failure */
+ if (p < 0) return (1);
+
+ /* Failure */
+ if ((huge)p != n) return (1);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+* Hack -- attempt to read data from a file descriptor
+*/
+errr fd_read(int fd, char *buf, huge n)
+{
+ /* Verify the fd */
+ if (fd < 0) return ( -1);
+
+#ifndef SET_UID
+
+ /* Read pieces */
+ while (n >= 16384)
+ {
+ /* Read a piece */
+ if (read(fd, buf, 16384) != 16384) return (1);
+
+ /* Shorten the task */
+ buf += 16384;
+
+ /* Shorten the task */
+ n -= 16384;
+ }
+
+#endif
+
+ /* Read the final piece */
+ if ((huge)read(fd, buf, n) != n) return (1);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+* Hack -- Attempt to write data to a file descriptor
+*/
+errr fd_write(int fd, cptr buf, huge n)
+{
+ /* Verify the fd */
+ if (fd < 0) return ( -1);
+
+#ifndef SET_UID
+
+ /* Write pieces */
+ while (n >= 16384)
+ {
+ /* Write a piece */
+ if (write(fd, buf, 16384) != 16384) return (1);
+
+ /* Shorten the task */
+ buf += 16384;
+
+ /* Shorten the task */
+ n -= 16384;
+ }
+
+#endif
+
+ /* Write the final piece */
+ if ((huge)write(fd, buf, n) != n) return (1);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+* Hack -- attempt to close a file descriptor
+*/
+errr fd_close(int fd)
+{
+ /* Verify the fd */
+ if (fd < 0) return ( -1);
+
+ /* Close */
+ (void)close(fd);
+
+ /* XXX XXX XXX */
+ return (0);
+}
+
+
+/*
+* XXX XXX XXX Important note about "colors" XXX XXX XXX
+*
+* The "TERM_*" color definitions list the "composition" of each
+* "Angband color" in terms of "quarters" of each of the three color
+* components (Red, Green, Blue), for example, TERM_UMBER is defined
+* as 2/4 Red, 1/4 Green, 0/4 Blue.
+*
+* The following info is from "Torbjorn Lindgren" (see "main-xaw.c").
+*
+* These values are NOT gamma-corrected. On most machines (with the
+* Macintosh being an important exception), you must "gamma-correct"
+* the given values, that is, "correct for the intrinsic non-linearity
+* of the phosphor", by converting the given intensity levels based
+* on the "gamma" of the target screen, which is usually 1.7 (or 1.5).
+*
+* The actual formula for conversion is unknown to me at this time,
+* but you can use the table below for the most common gamma values.
+*
+* So, on most machines, simply convert the values based on the "gamma"
+* of the target screen, which is usually in the range 1.5 to 1.7, and
+* usually is closest to 1.7. The converted value for each of the five
+* different "quarter" values is given below:
+*
+* Given Gamma 1.0 Gamma 1.5 Gamma 1.7 Hex 1.7
+* ----- ---- ---- ---- ---
+* 0/4 0.00 0.00 0.00 #00
+* 1/4 0.25 0.27 0.28 #47
+* 2/4 0.50 0.55 0.56 #8f
+* 3/4 0.75 0.82 0.84 #d7
+* 4/4 1.00 1.00 1.00 #ff
+*
+* Note that some machines (i.e. most IBM machines) are limited to a
+* hard-coded set of colors, and so the information above is useless.
+*
+* Also, some machines are limited to a pre-determined set of colors,
+* for example, the IBM can only display 16 colors, and only 14 of
+* those colors resemble colors used by Angband, and then only when
+* you ignore the fact that "Slate" and "cyan" are not really matches,
+* so on the IBM, we use "orange" for both "Umber", and "Light Umber"
+* in addition to the obvious "Orange", since by combining all of the
+* "indeterminate" colors into a single color, the rest of the colors
+* are left with "meaningful" values.
+*/
+
+
+/*
+* Move the cursor
+*/
+void move_cursor(int row, int col)
+{
+ Term_gotoxy(col, row);
+}
+
+
+
+/*
+* Convert a decimal to a single digit octal number
+*/
+static char octify(uint i)
+{
+ return (hexsym[i % 8]);
+}
+
+/*
+* Convert a decimal to a single digit hex number
+*/
+static char hexify(uint i)
+{
+ return (hexsym[i % 16]);
+}
+
+
+/*
+* Convert a octal-digit into a decimal
+*/
+static int deoct(char c)
+{
+ if (isdigit(c)) return (D2I(c));
+ return (0);
+}
+
+/*
+* Convert a hexidecimal-digit into a decimal
+*/
+static int dehex(char c)
+{
+ if (isdigit(c)) return (D2I(c));
+ if (islower(c)) return (A2I(c) + 10);
+ if (isupper(c)) return (A2I(tolower(c)) + 10);
+ return (0);
+}
+
+
+static int my_stricmp(cptr a, cptr b)
+{
+ cptr s1, s2;
+ char z1, z2;
+
+ /* Scan the strings */
+ for (s1 = a, s2 = b; TRUE; s1++, s2++)
+ {
+ z1 = FORCEUPPER(*s1);
+ z2 = FORCEUPPER(*s2);
+ if (z1 < z2) return ( -1);
+ if (z1 > z2) return (1);
+ if (!z1) return (0);
+ }
+}
+
+static int my_strnicmp(cptr a, cptr b, int n)
+{
+ cptr s1, s2;
+ char z1, z2;
+
+ /* Scan the strings */
+ for (s1 = a, s2 = b; n > 0; s1++, s2++, n--)
+ {
+ z1 = FORCEUPPER(*s1);
+ z2 = FORCEUPPER(*s2);
+ if (z1 < z2) return ( -1);
+ if (z1 > z2) return (1);
+ if (!z1) return (0);
+ }
+ return 0;
+}
+
+
+static void trigger_text_to_ascii(char **bufptr, cptr *strptr)
+{
+ char *s = *bufptr;
+ cptr str = *strptr;
+ bool_ mod_status[MAX_MACRO_MOD];
+
+ int i, len = 0;
+ int shiftstatus = 0;
+ cptr key_code;
+
+ if (macro_template == NULL)
+ return;
+
+ for (i = 0; macro_modifier_chr[i]; i++)
+ mod_status[i] = FALSE;
+ str++;
+
+ /* Examine modifier keys */
+ while (1)
+ {
+ for (i = 0; macro_modifier_chr[i]; i++)
+ {
+ len = strlen(macro_modifier_name[i]);
+
+ if (!my_strnicmp(str, macro_modifier_name[i], len))
+ break;
+ }
+ if (!macro_modifier_chr[i]) break;
+ str += len;
+ mod_status[i] = TRUE;
+ if ('S' == macro_modifier_chr[i])
+ shiftstatus = 1;
+ }
+ for (i = 0; i < max_macrotrigger; i++)
+ {
+ len = strlen(macro_trigger_name[i]);
+ if (!my_strnicmp(str, macro_trigger_name[i], len) && ']' == str[len])
+ {
+ /* a trigger name found */
+ break;
+ }
+ }
+
+ /* Invalid trigger name? */
+ if (i == max_macrotrigger)
+ {
+ str = strchr(str, ']');
+ if (str)
+ {
+ *s++ = (char)31;
+ *s++ = (char)13;
+ *bufptr = s;
+ *strptr = str; /* where **strptr == ']' */
+ }
+ return;
+ }
+
+ key_code = macro_trigger_keycode[shiftstatus][i];
+ str += len;
+
+ *s++ = (char)31;
+ for (i = 0; macro_template[i]; i++)
+ {
+ char ch = macro_template[i];
+ int j;
+
+ switch (ch)
+ {
+ case '&':
+ for (j = 0; macro_modifier_chr[j]; j++)
+ {
+ if (mod_status[j])
+ *s++ = macro_modifier_chr[j];
+ }
+ break;
+ case '#':
+ strcpy(s, key_code);
+ s += strlen(key_code);
+ break;
+ default:
+ *s++ = ch;
+ break;
+ }
+ }
+ *s++ = (char)13;
+
+ *bufptr = s;
+ *strptr = str; /* where **strptr == ']' */
+ return;
+}
+
+
+/*
+* Hack -- convert a printable string into real ascii
+*
+* I have no clue if this function correctly handles, for example,
+* parsing "\xFF" into a (signed) char. Whoever thought of making
+* the "sign" of a "char" undefined is a complete moron. Oh well.
+*/
+void text_to_ascii(char *buf, cptr str)
+{
+ char *s = buf;
+
+ /* Analyze the "ascii" string */
+ while (*str)
+ {
+ /* Backslash codes */
+ if (*str == '\\')
+ {
+ /* Skip the backslash */
+ str++;
+
+ /* Macro Trigger */
+ if (*str == '[')
+ {
+ trigger_text_to_ascii(&s, &str);
+ }
+
+ /* Hex-mode XXX */
+ else if (*str == 'x')
+ {
+ *s = 16 * dehex(*++str);
+ *s++ += dehex(*++str);
+ }
+
+ /* Hack -- simple way to specify "backslash" */
+ else if (*str == '\\')
+ {
+ *s++ = '\\';
+ }
+
+ /* Hack -- simple way to specify "caret" */
+ else if (*str == '^')
+ {
+ *s++ = '^';
+ }
+
+ /* Hack -- simple way to specify "space" */
+ else if (*str == 's')
+ {
+ *s++ = ' ';
+ }
+
+ /* Hack -- simple way to specify Escape */
+ else if (*str == 'e')
+ {
+ *s++ = ESCAPE;
+ }
+
+ /* Backspace */
+ else if (*str == 'b')
+ {
+ *s++ = '\b';
+ }
+
+ /* Newline */
+ else if (*str == 'n')
+ {
+ *s++ = '\n';
+ }
+
+ /* Return */
+ else if (*str == 'r')
+ {
+ *s++ = '\r';
+ }
+
+ /* Tab */
+ else if (*str == 't')
+ {
+ *s++ = '\t';
+ }
+
+ /* Octal-mode */
+ else if (*str == '0')
+ {
+ *s = 8 * deoct(*++str);
+ *s++ += deoct(*++str);
+ }
+
+ /* Octal-mode */
+ else if (*str == '1')
+ {
+ *s = 64 + 8 * deoct(*++str);
+ *s++ += deoct(*++str);
+ }
+
+ /* Octal-mode */
+ else if (*str == '2')
+ {
+ *s = 64 * 2 + 8 * deoct(*++str);
+ *s++ += deoct(*++str);
+ }
+
+ /* Octal-mode */
+ else if (*str == '3')
+ {
+ *s = 64 * 3 + 8 * deoct(*++str);
+ *s++ += deoct(*++str);
+ }
+
+ /* Skip the final char */
+ str++;
+ }
+
+ /* Normal Control codes */
+ else if (*str == '^')
+ {
+ str++;
+ *s++ = (*str++ & 037);
+ }
+
+ /* Normal chars */
+ else
+ {
+ *s++ = *str++;
+ }
+ }
+
+ /* Terminate */
+ *s = '\0';
+}
+
+
+bool_ trigger_ascii_to_text(char **bufptr, cptr *strptr)
+{
+ char *s = *bufptr;
+ cptr str = *strptr;
+ char key_code[100];
+ int i;
+ cptr tmp;
+
+ if (macro_template == NULL)
+ return FALSE;
+
+ *s++ = '\\';
+ *s++ = '[';
+
+ for (i = 0; macro_template[i]; i++)
+ {
+ int j;
+ char ch = macro_template[i];
+
+ switch (ch)
+ {
+ case '&':
+ while ((tmp = strchr(macro_modifier_chr, *str)))
+ {
+ j = (int)(tmp - macro_modifier_chr);
+ tmp = macro_modifier_name[j];
+ while (*tmp) *s++ = *tmp++;
+ str++;
+ }
+ break;
+ case '#':
+ for (j = 0; *str && *str != (char)13; j++)
+ key_code[j] = *str++;
+ key_code[j] = '\0';
+ break;
+ default:
+ if (ch != *str) return FALSE;
+ str++;
+ }
+ }
+ if (*str++ != (char)13) return FALSE;
+
+ for (i = 0; i < max_macrotrigger; i++)
+ {
+ if (!my_stricmp(key_code, macro_trigger_keycode[0][i])
+ || !my_stricmp(key_code, macro_trigger_keycode[1][i]))
+ break;
+ }
+ if (i == max_macrotrigger)
+ return FALSE;
+
+ tmp = macro_trigger_name[i];
+ while (*tmp) *s++ = *tmp++;
+
+ *s++ = ']';
+
+ *bufptr = s;
+ *strptr = str;
+ return TRUE;
+}
+
+
+/*
+* Hack -- convert a string into a printable form
+*/
+void ascii_to_text(char *buf, cptr str)
+{
+ char *s = buf;
+
+ /* Analyze the "ascii" string */
+ while (*str)
+ {
+ byte i = (byte)(*str++);
+
+ /* Macro Trigger */
+ if (i == 31)
+ {
+ if (!trigger_ascii_to_text(&s, &str))
+ {
+ *s++ = '^';
+ *s++ = '_';
+ }
+ }
+ else if (i == ESCAPE)
+ {
+ *s++ = '\\';
+ *s++ = 'e';
+ }
+ else if (i == ' ')
+ {
+ *s++ = '\\';
+ *s++ = 's';
+ }
+ else if (i == '\b')
+ {
+ *s++ = '\\';
+ *s++ = 'b';
+ }
+ else if (i == '\t')
+ {
+ *s++ = '\\';
+ *s++ = 't';
+ }
+ else if (i == '\n')
+ {
+ *s++ = '\\';
+ *s++ = 'n';
+ }
+ else if (i == '\r')
+ {
+ *s++ = '\\';
+ *s++ = 'r';
+ }
+ else if (i == '^')
+ {
+ *s++ = '\\';
+ *s++ = '^';
+ }
+ else if (i == '\\')
+ {
+ *s++ = '\\';
+ *s++ = '\\';
+ }
+ else if (i < 32)
+ {
+ *s++ = '^';
+ *s++ = i + 64;
+ }
+ else if (i < 127)
+ {
+ *s++ = i;
+ }
+ else if (i < 64)
+ {
+ *s++ = '\\';
+ *s++ = '0';
+ *s++ = octify(i / 8);
+ *s++ = octify(i % 8);
+ }
+ else
+ {
+ *s++ = '\\';
+ *s++ = 'x';
+ *s++ = hexify(i / 16);
+ *s++ = hexify(i % 16);
+ }
+ }
+
+ /* Terminate */
+ *s = '\0';
+}
+
+
+
+/*
+* The "macro" package
+*
+* Functions are provided to manipulate a collection of macros, each
+* of which has a trigger pattern string and a resulting action string
+* and a small set of flags.
+*/
+
+
+
+/*
+* Determine if any macros have ever started with a given character.
+*/
+static bool_ macro__use[256];
+
+
+/*
+* Find the macro (if any) which exactly matches the given pattern
+*/
+sint macro_find_exact(cptr pat)
+{
+ int i;
+
+ /* Nothing possible */
+ if (!macro__use[(byte)(pat[0])])
+ {
+ return ( -1);
+ }
+
+ /* Scan the macros */
+ for (i = 0; i < macro__num; ++i)
+ {
+ /* Skip macros which do not match the pattern */
+ if (!streq(macro__pat[i], pat)) continue;
+
+ /* Found one */
+ return (i);
+ }
+
+ /* No matches */
+ return ( -1);
+}
+
+
+/*
+* Find the first macro (if any) which contains the given pattern
+*/
+static sint macro_find_check(cptr pat)
+{
+ int i;
+
+ /* Nothing possible */
+ if (!macro__use[(byte)(pat[0])])
+ {
+ return ( -1);
+ }
+
+ /* Scan the macros */
+ for (i = 0; i < macro__num; ++i)
+ {
+ /* Skip macros which do not contain the pattern */
+ if (!prefix(macro__pat[i], pat)) continue;
+
+ /* Found one */
+ return (i);
+ }
+
+ /* Nothing */
+ return ( -1);
+}
+
+
+/*
+* Find the first macro (if any) which contains the given pattern and more
+*/
+static sint macro_find_maybe(cptr pat)
+{
+ int i;
+
+ /* Nothing possible */
+ if (!macro__use[(byte)(pat[0])])
+ {
+ return ( -1);
+ }
+
+ /* Scan the macros */
+ for (i = 0; i < macro__num; ++i)
+ {
+ /* Skip macros which do not contain the pattern */
+ if (!prefix(macro__pat[i], pat)) continue;
+
+ /* Skip macros which exactly match the pattern XXX XXX */
+ if (streq(macro__pat[i], pat)) continue;
+
+ /* Found one */
+ return (i);
+ }
+
+ /* Nothing */
+ return ( -1);
+}
+
+
+/*
+* Find the longest macro (if any) which starts with the given pattern
+*/
+static sint macro_find_ready(cptr pat)
+{
+ int i, t, n = -1, s = -1;
+
+ /* Nothing possible */
+ if (!macro__use[(byte)(pat[0])])
+ {
+ return ( -1);
+ }
+
+ /* Scan the macros */
+ for (i = 0; i < macro__num; ++i)
+ {
+ /* Skip macros which are not contained by the pattern */
+ if (!prefix(pat, macro__pat[i])) continue;
+
+ /* Obtain the length of this macro */
+ t = strlen(macro__pat[i]);
+
+ /* Only track the "longest" pattern */
+ if ((n >= 0) && (s > t)) continue;
+
+ /* Track the entry */
+ n = i;
+ s = t;
+ }
+
+ /* Result */
+ return (n);
+}
+
+
+/*
+* Add a macro definition (or redefinition).
+*
+* We should use "act == NULL" to "remove" a macro, but this might make it
+* impossible to save the "removal" of a macro definition. XXX XXX XXX
+*
+* We should consider refusing to allow macros which contain existing macros,
+* or which are contained in existing macros, because this would simplify the
+* macro analysis code. XXX XXX XXX
+*
+* We should consider removing the "command macro" crap, and replacing it
+* with some kind of "powerful keymap" ability, but this might make it hard
+* to change the "roguelike" option from inside the game. XXX XXX XXX
+*/
+errr macro_add(cptr pat, cptr act)
+{
+ int n;
+
+
+ /* Paranoia -- require data */
+ if (!pat || !act) return ( -1);
+
+
+ /* Look for any existing macro */
+ n = macro_find_exact(pat);
+
+ /* Replace existing macro */
+ if (n >= 0)
+ {
+ /* Free the old macro action */
+ string_free(macro__act[n]);
+ }
+
+ /* Create a new macro */
+ else
+ {
+ /* Acquire a new index */
+ n = macro__num++;
+
+ /* Save the pattern */
+ macro__pat[n] = string_make(pat);
+ }
+
+ /* Save the action */
+ macro__act[n] = string_make(act);
+
+ /* Efficiency */
+ macro__use[(byte)(pat[0])] = TRUE;
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+* Initialize the "macro" package
+*/
+errr macro_init(void)
+{
+ /* Macro patterns */
+ C_MAKE(macro__pat, MACRO_MAX, cptr);
+
+ /* Macro actions */
+ C_MAKE(macro__act, MACRO_MAX, cptr);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+* Local "need flush" variable
+*/
+static bool_ flush_later = FALSE;
+
+
+/*
+* Local variable -- we are inside a "macro action"
+*
+* Do not match any macros until "ascii 30" is found.
+*/
+static bool_ parse_macro = FALSE;
+
+/*
+* Local variable -- we are inside a "macro trigger"
+*
+* Strip all keypresses until a low ascii value is found.
+*/
+static bool_ parse_under = FALSE;
+
+
+/*
+* Flush all input chars. Actually, remember the flush,
+* and do a "special flush" before the next "inkey()".
+*
+* This is not only more efficient, but also necessary to make sure
+* that various "inkey()" codes are not "lost" along the way.
+*/
+void flush(void)
+{
+ /* Do it later */
+ flush_later = TRUE;
+}
+
+
+/*
+* Flush the screen, make a noise
+*/
+void bell(void)
+{
+ /* Mega-Hack -- Flush the output */
+ Term_fresh();
+
+ /* Make a bell noise (if allowed) */
+ if (ring_bell) Term_xtra(TERM_XTRA_NOISE, 0);
+
+ /* Flush the input (later!) */
+ flush();
+}
+
+
+/*
+* Hack -- Make a (relevant?) sound
+*/
+void sound(int val)
+{
+ /* No sound */
+ if (!use_sound) return;
+
+ /* Make a sound (if allowed) */
+ Term_xtra(TERM_XTRA_SOUND, val);
+}
+
+
+
+/*
+* Helper function called only from "inkey()"
+*
+* This function does almost all of the "macro" processing.
+*
+* We use the "Term_key_push()" function to handle "failed" macros, as well
+* as "extra" keys read in while choosing the proper macro, and also to hold
+* the action for the macro, plus a special "ascii 30" character indicating
+* that any macro action in progress is complete. Embedded macros are thus
+* illegal, unless a macro action includes an explicit "ascii 30" character,
+* which would probably be a massive hack, and might break things.
+*
+* Only 500 (0+1+2+...+29+30) milliseconds may elapse between each key in
+* the macro trigger sequence. If a key sequence forms the "prefix" of a
+* macro trigger, 500 milliseconds must pass before the key sequence is
+* known not to be that macro trigger. XXX XXX XXX
+*/
+static char inkey_aux(void)
+{
+ int k = 0, n, p = 0, w = 0;
+
+ char ch;
+
+ cptr pat, act;
+
+ char buf[1024];
+
+
+ /* Wait for a keypress */
+ (void)(Term_inkey(&ch, TRUE, TRUE));
+
+
+ /* End "macro action" */
+ if (ch == 30) parse_macro = FALSE;
+
+ /* Inside "macro action" */
+ if (ch == 30) return (ch);
+
+ /* Inside "macro action" */
+ if (parse_macro) return (ch);
+
+ /* Inside "macro trigger" */
+ if (parse_under) return (ch);
+
+
+ /* Save the first key, advance */
+ buf[p++] = ch;
+ buf[p] = '\0';
+
+
+ /* Check for possible macro */
+ k = macro_find_check(buf);
+
+ /* No macro pending */
+ if (k < 0) return (ch);
+
+
+ /* Wait for a macro, or a timeout */
+ while (TRUE)
+ {
+ /* Check for pending macro */
+ k = macro_find_maybe(buf);
+
+ /* No macro pending */
+ if (k < 0) break;
+
+ /* Check for (and remove) a pending key */
+ if (0 == Term_inkey(&ch, FALSE, TRUE))
+ {
+ /* Append the key */
+ buf[p++] = ch;
+ buf[p] = '\0';
+
+ /* Restart wait */
+ w = 0;
+ }
+
+ /* No key ready */
+ else
+ {
+ /* Increase "wait" */
+ w += 10;
+
+ /* Excessive delay */
+ if (w >= 100) break;
+
+ /* Delay */
+ Term_xtra(TERM_XTRA_DELAY, w);
+ }
+ }
+
+
+ /* Check for available macro */
+ k = macro_find_ready(buf);
+
+ /* No macro available */
+ if (k < 0)
+ {
+ /* Push all the keys back on the queue */
+ while (p > 0)
+ {
+ /* Push the key, notice over-flow */
+ if (Term_key_push(buf[--p])) return (0);
+ }
+
+ /* Wait for (and remove) a pending key */
+ (void)Term_inkey(&ch, TRUE, TRUE);
+
+ /* Return the key */
+ return (ch);
+ }
+
+
+ /* Get the pattern */
+ pat = macro__pat[k];
+
+ /* Get the length of the pattern */
+ n = strlen(pat);
+
+ /* Push the "extra" keys back on the queue */
+ while (p > n)
+ {
+ /* Push the key, notice over-flow */
+ if (Term_key_push(buf[--p])) return (0);
+ }
+
+
+ /* Begin "macro action" */
+ parse_macro = TRUE;
+
+ /* Push the "end of macro action" key */
+ if (Term_key_push(30)) return (0);
+
+
+ /* Access the macro action */
+ act = macro__act[k];
+
+ /* Get the length of the action */
+ n = strlen(act);
+
+ /* Push the macro "action" onto the key queue */
+ while (n > 0)
+ {
+ /* Push the key, notice over-flow */
+ if (Term_key_push(act[--n])) return (0);
+ }
+
+
+ /* Hack -- Force "inkey()" to call us again */
+ return (0);
+}
+
+
+/*
+* Mega-Hack -- special "inkey_next" pointer. XXX XXX XXX
+*
+* This special pointer allows a sequence of keys to be "inserted" into
+* the stream of keys returned by "inkey()". This key sequence will not
+* trigger any macros, and cannot be bypassed by the Borg. It is used
+* in Angband to handle "keymaps".
+*/
+static cptr inkey_next = NULL;
+
+
+/*
+* Get a keypress from the user.
+*
+* This function recognizes a few "global parameters". These are variables
+* which, if set to TRUE before calling this function, will have an effect
+* on this function, and which are always reset to FALSE by this function
+* before this function returns. Thus they function just like normal
+* parameters, except that most calls to this function can ignore them.
+*
+* If "inkey_xtra" is TRUE, then all pending keypresses will be flushed,
+* and any macro processing in progress will be aborted. This flag is
+* set by the "flush()" function, which does not actually flush anything
+* itself, but rather, triggers delayed input flushing via "inkey_xtra".
+*
+* If "inkey_scan" is TRUE, then we will immediately return "zero" if no
+* keypress is available, instead of waiting for a keypress.
+*
+* If "inkey_base" is TRUE, then all macro processing will be bypassed.
+* If "inkey_base" and "inkey_scan" are both TRUE, then this function will
+* not return immediately, but will wait for a keypress for as long as the
+* normal macro matching code would, allowing the direct entry of macro
+* triggers. The "inkey_base" flag is extremely dangerous!
+*
+* If "inkey_flag" is TRUE, then we will assume that we are waiting for a
+* normal command, and we will only show the cursor if "hilite_player" is
+* TRUE (or if the player is in a store), instead of always showing the
+* cursor. The various "main-xxx.c" files should avoid saving the game
+* in response to a "menu item" request unless "inkey_flag" is TRUE, to
+* prevent savefile corruption.
+*
+* If we are waiting for a keypress, and no keypress is ready, then we will
+* refresh (once) the window which was active when this function was called.
+*
+* Note that "back-quote" is automatically converted into "escape" for
+* convenience on machines with no "escape" key. This is done after the
+* macro matching, so the user can still make a macro for "backquote".
+*
+* Note the special handling of "ascii 30" (ctrl-caret, aka ctrl-shift-six)
+* and "ascii 31" (ctrl-underscore, aka ctrl-shift-minus), which are used to
+* provide support for simple keyboard "macros". These keys are so strange
+* that their loss as normal keys will probably be noticed by nobody. The
+* "ascii 30" key is used to indicate the "end" of a macro action, which
+* allows recursive macros to be avoided. The "ascii 31" key is used by
+* some of the "main-xxx.c" files to introduce macro trigger sequences.
+*
+* Hack -- we use "ascii 29" (ctrl-right-bracket) as a special "magic" key,
+* which can be used to give a variety of "sub-commands" which can be used
+* any time. These sub-commands could include commands to take a picture of
+* the current screen, to start/stop recording a macro action, etc.
+*
+* If "angband_term[0]" is not active, we will make it active during this
+* function, so that the various "main-xxx.c" files can assume that input
+* is only requested (via "Term_inkey()") when "angband_term[0]" is active.
+*
+* Mega-Hack -- This function is used as the entry point for clearing the
+* "signal_count" variable, and of the "character_saved" variable.
+*
+* Hack -- Note the use of "inkey_next" to allow "keymaps" to be processed.
+*
+* Mega-Hack -- Note the use of "inkey_hack" to allow the "Borg" to steal
+* control of the keyboard from the user.
+*/
+char inkey(void)
+{
+ int v;
+
+ char kk;
+
+ char ch = 0;
+
+ bool_ done = FALSE;
+
+ term *old = Term;
+
+ /* Hack -- Use the "inkey_next" pointer */
+ if (inkey_next && *inkey_next && !inkey_xtra)
+ {
+ /* Get next character, and advance */
+ ch = *inkey_next++;
+
+ /* Cancel the various "global parameters" */
+ inkey_base = inkey_xtra = inkey_flag = inkey_scan = FALSE;
+
+ /* Accept result */
+ macro_recorder_add(ch);
+ return (ch);
+ }
+
+ /* Forget pointer */
+ inkey_next = NULL;
+
+
+ /* Hack -- handle delayed "flush()" */
+ if (inkey_xtra)
+ {
+ /* End "macro action" */
+ parse_macro = FALSE;
+
+ /* End "macro trigger" */
+ parse_under = FALSE;
+
+ /* Forget old keypresses */
+ Term_flush();
+ }
+
+
+ /* Access cursor state */
+ (void)Term_get_cursor(&v);
+
+ /* Show the cursor if waiting, except sometimes in "command" mode */
+ if (!inkey_scan && (!inkey_flag || hilite_player || character_icky))
+ {
+ /* Show the cursor */
+ (void)Term_set_cursor(1);
+ }
+
+
+ /* Hack -- Activate main screen */
+ Term_activate(angband_term[0]);
+
+
+ /* Get a key */
+ while (!ch)
+ {
+ /* Hack -- Handle "inkey_scan" */
+ if (!inkey_base && inkey_scan &&
+ (0 != Term_inkey(&kk, FALSE, FALSE)))
+ {
+ break;
+ }
+
+
+ /* Hack -- Flush output once when no key ready */
+ if (!done && (0 != Term_inkey(&kk, FALSE, FALSE)))
+ {
+ /* Hack -- activate proper term */
+ Term_activate(old);
+
+ /* Flush output */
+ Term_fresh();
+
+ /* Hack -- activate main screen */
+ Term_activate(angband_term[0]);
+
+ /* Mega-Hack -- reset saved flag */
+ character_saved = FALSE;
+
+ /* Mega-Hack -- reset signal counter */
+ signal_count = 0;
+
+ /* Only once */
+ done = TRUE;
+ }
+
+
+ /* Hack -- Handle "inkey_base" */
+ if (inkey_base)
+ {
+ int w = 0;
+
+ /* Wait forever */
+ if (!inkey_scan)
+ {
+ /* Wait for (and remove) a pending key */
+ if (0 == Term_inkey(&ch, TRUE, TRUE))
+ {
+ /* Done */
+ break;
+ }
+
+ /* Oops */
+ break;
+ }
+
+ /* Wait */
+ while (TRUE)
+ {
+ /* Check for (and remove) a pending key */
+ if (0 == Term_inkey(&ch, FALSE, TRUE))
+ {
+ /* Done */
+ break;
+ }
+
+ /* No key ready */
+ else
+ {
+ /* Increase "wait" */
+ w += 10;
+
+ /* Excessive delay */
+ if (w >= 100) break;
+
+ /* Delay */
+ Term_xtra(TERM_XTRA_DELAY, w);
+ }
+ }
+
+ /* Done */
+ break;
+ }
+
+
+ /* Get a key (see above) */
+ ch = inkey_aux();
+
+
+ /* Handle "control-right-bracket" */
+ if ((ch == 29) || ((!rogue_like_commands) && (ch == KTRL('D'))))
+ {
+ /* Strip this key */
+ ch = 0;
+
+ if (!do_movies)
+ /* Do an html dump */
+ do_cmd_html_dump();
+ else
+ /* Do a text box in the cmovie */
+ do_cmovie_insert();
+
+
+ /* Continue */
+ continue;
+ }
+
+
+ /* Treat back-quote as escape */
+ if (ch == '`') ch = ESCAPE;
+
+
+ /* End "macro trigger" */
+ if (parse_under && (ch <= 32))
+ {
+ /* Strip this key */
+ ch = 0;
+
+ /* End "macro trigger" */
+ parse_under = FALSE;
+ }
+
+
+ /* Handle "control-caret" */
+ if (ch == 30)
+ {
+ /* Strip this key */
+ ch = 0;
+ }
+
+ /* Handle "control-underscore" */
+ else if (ch == 31)
+ {
+ /* Strip this key */
+ ch = 0;
+
+ /* Begin "macro trigger" */
+ parse_under = TRUE;
+ }
+
+ /* Inside "macro trigger" */
+ else if (parse_under)
+ {
+ /* Strip this key */
+ ch = 0;
+ }
+ }
+
+
+ /* Hack -- restore the term */
+ Term_activate(old);
+
+
+ /* Restore the cursor */
+ Term_set_cursor(v);
+
+
+ /* Cancel the various "global parameters" */
+ inkey_base = inkey_xtra = inkey_flag = inkey_scan = FALSE;
+
+
+ /* Return the keypress */
+ macro_recorder_add(ch);
+ return (ch);
+}
+
+
+
+
+/*
+* We use a global array for all inscriptions to reduce the memory
+* spent maintaining inscriptions. Of course, it is still possible
+* to run out of inscription memory, especially if too many different
+* inscriptions are used, but hopefully this will be rare.
+*
+* We use dynamic string allocation because otherwise it is necessary
+* to pre-guess the amount of quark activity. We limit the total
+* number of quarks, but this is much easier to "expand" as needed.
+*
+* Any two items with the same inscription will have the same "quark"
+* index, which should greatly reduce the need for inscription space.
+*
+* Note that "quark zero" is NULL and should not be "dereferenced".
+*/
+
+/*
+* Add a new "quark" to the set of quarks.
+*/
+s16b quark_add(cptr str)
+{
+ int i;
+
+ /* Look for an existing quark */
+ for (i = 1; i < quark__num; i++)
+ {
+ /* Check for equality */
+ if (streq(quark__str[i], str)) return (i);
+ }
+
+ /* Paranoia -- Require room */
+ if (quark__num == QUARK_MAX) return (0);
+
+ /* New maximal quark */
+ quark__num = i + 1;
+
+ /* Add a new quark */
+ quark__str[i] = string_make(str);
+
+ /* Return the index */
+ return (i);
+}
+
+
+/*
+* This function looks up a quark
+*/
+cptr quark_str(s16b i)
+{
+ cptr q;
+
+ /* Verify */
+ if ((i < 0) || (i >= quark__num)) i = 0;
+
+ /* Access the quark */
+ q = quark__str[i];
+
+ /* Return the quark */
+ return (q);
+}
+
+
+
+
+/*
+* Second try for the "message" handling routines.
+*
+* Each call to "message_add(s)" will add a new "most recent" message
+* to the "message recall list", using the contents of the string "s".
+*
+* The messages will be stored in such a way as to maximize "efficiency",
+* that is, we attempt to maximize the number of sequential messages that
+* can be retrieved, given a limited amount of storage space.
+*
+* We keep a buffer of chars to hold the "text" of the messages, not
+* necessarily in "order", and an array of offsets into that buffer,
+* representing the actual messages. This is made more complicated
+* by the fact that both the array of indexes, and the buffer itself,
+* are both treated as "circular arrays" for efficiency purposes, but
+* the strings may not be "broken" across the ends of the array.
+*
+* The "message_add()" function is rather "complex", because it must be
+* extremely efficient, both in space and time, for use with the Borg.
+*/
+
+
+
+/*
+* How many messages are "available"?
+*/
+s16b message_num(void)
+{
+ int last, next, n;
+
+ /* Extract the indexes */
+ last = message__last;
+ next = message__next;
+
+ /* Handle "wrap" */
+ if (next < last) next += MESSAGE_MAX;
+
+ /* Extract the space */
+ n = (next - last);
+
+ /* Return the result */
+ return (n);
+}
+
+
+
+/*
+* Recall the "text" of a saved message
+*/
+cptr message_str(int age)
+{
+ static char buf[1024];
+ s16b x;
+ s16b o;
+ cptr s;
+
+ /* Forgotten messages have no text */
+ if ((age < 0) || (age >= message_num())) return ("");
+
+ /* Acquire the "logical" index */
+ x = (message__next + MESSAGE_MAX - (age + 1)) % MESSAGE_MAX;
+
+ /* Get the "offset" for the message */
+ o = message__ptr[x];
+
+ /* Access the message text */
+ s = &message__buf[o];
+
+ /* Hack -- Handle repeated messages */
+ if (message__count[x] > 1)
+ {
+ strnfmt(buf, 1024, "%s <%dx>", s, message__count[x]);
+ s = buf;
+ }
+
+ /* Return the message text */
+ return (s);
+}
+
+/*
+* Recall the color of a saved message
+*/
+byte message_color(int age)
+{
+ s16b x;
+ byte color = TERM_WHITE;
+
+ /* Forgotten messages have no text */
+ if ((age < 0) || (age >= message_num())) return (TERM_WHITE);
+
+ /* Acquire the "logical" index */
+ x = (message__next + MESSAGE_MAX - (age + 1)) % MESSAGE_MAX;
+
+ /* Get the "offset" for the message */
+ color = message__color[x];
+
+ /* Return the message text */
+ return (color);
+}
+
+/*
+ * Recall the type of a saved message
+ */
+byte message_type(int age)
+{
+ s16b x;
+ byte type;
+
+ /* Forgotten messages have no text */
+ if ((age < 0) || (age >= message_num())) return (MESSAGE_NONE);
+
+ /* Acquire the "logical" index */
+ x = (message__next + MESSAGE_MAX - (age + 1)) % MESSAGE_MAX;
+
+ /* Get the "offset" for the message */
+ type = message__type[x];
+
+ /* Return the message text */
+ return (type);
+}
+
+
+
+/*
+* Add a new message, with great efficiency
+*/
+void message_add(byte type, cptr str, byte color)
+{
+ int i, k, x, n;
+ cptr s;
+
+
+ /*** Step 1 -- Analyze the message ***/
+
+ /* Hack -- Ignore "non-messages" */
+ if (!str) return;
+
+ /* Message length */
+ n = strlen(str);
+
+ /* Important Hack -- Ignore "long" messages */
+ if (n >= MESSAGE_BUF / 4) return;
+
+
+ /*** Step 2 -- Handle repeated messages ***/
+
+ /* Acquire the "logical" last index */
+ x = (message__next + MESSAGE_MAX - 1) % MESSAGE_MAX;
+
+ /* Get the last message text */
+ s = &message__buf[message__ptr[x]];
+
+ /* Last message repeated? */
+ if (streq(str, s))
+ {
+ /* Increase the message count */
+ message__count[x]++;
+
+ /* Success */
+ return;
+ }
+
+
+ /*** Step 3 -- Attempt to optimize ***/
+
+ /* Limit number of messages to check */
+ k = message_num() / 4;
+
+ /* Limit number of messages to check */
+ if (k > MESSAGE_MAX / 32) k = MESSAGE_MAX / 32;
+
+ /* Check the last few messages (if any to count) */
+ for (i = message__next; k; k--)
+ {
+ u16b q;
+
+ cptr old;
+
+ /* Back up and wrap if needed */
+ if (i-- == 0) i = MESSAGE_MAX - 1;
+
+ /* Stop before oldest message */
+ if (i == message__last) break;
+
+ /* Extract "distance" from "head" */
+ q = (message__head + MESSAGE_BUF - message__ptr[i]) % MESSAGE_BUF;
+
+ /* Do not optimize over large distance */
+ if (q > MESSAGE_BUF / 2) continue;
+
+ /* Access the old string */
+ old = &message__buf[message__ptr[i]];
+
+ /* Compare */
+ if (!streq(old, str)) continue;
+
+ /* Get the next message index, advance */
+ x = message__next++;
+
+ /* Handle wrap */
+ if (message__next == MESSAGE_MAX) message__next = 0;
+
+ /* Kill last message if needed */
+ if (message__next == message__last) message__last++;
+
+ /* Handle wrap */
+ if (message__last == MESSAGE_MAX) message__last = 0;
+
+ /* Assign the starting address */
+ message__ptr[x] = message__ptr[i];
+ message__color[x] = color;
+ message__type[x] = type;
+ message__count[x] = 1;
+
+ /* Success */
+ return;
+ }
+
+
+ /*** Step 4 -- Ensure space before end of buffer ***/
+
+ /* Kill messages and Wrap if needed */
+ if (message__head + n + 1 >= MESSAGE_BUF)
+ {
+ /* Kill all "dead" messages */
+ for (i = message__last; TRUE; i++)
+ {
+ /* Wrap if needed */
+ if (i == MESSAGE_MAX) i = 0;
+
+ /* Stop before the new message */
+ if (i == message__next) break;
+
+ /* Kill "dead" messages */
+ if (message__ptr[i] >= message__head)
+ {
+ /* Track oldest message */
+ message__last = i + 1;
+ }
+ }
+
+ /* Wrap "tail" if needed */
+ if (message__tail >= message__head) message__tail = 0;
+
+ /* Start over */
+ message__head = 0;
+ }
+
+
+ /*** Step 5 -- Ensure space before next message ***/
+
+ /* Kill messages if needed */
+ if (message__head + n + 1 > message__tail)
+ {
+ /* Grab new "tail" */
+ message__tail = message__head + n + 1;
+
+ /* Advance tail while possible past first "nul" */
+ while (message__buf[message__tail - 1]) message__tail++;
+
+ /* Kill all "dead" messages */
+ for (i = message__last; TRUE; i++)
+ {
+ /* Wrap if needed */
+ if (i == MESSAGE_MAX) i = 0;
+
+ /* Stop before the new message */
+ if (i == message__next) break;
+
+ /* Kill "dead" messages */
+ if ((message__ptr[i] >= message__head) &&
+ (message__ptr[i] < message__tail))
+ {
+ /* Track oldest message */
+ message__last = i + 1;
+ }
+ }
+ }
+
+
+ /*** Step 6 -- Grab a new message index ***/
+
+ /* Get the next message index, advance */
+ x = message__next++;
+
+ /* Handle wrap */
+ if (message__next == MESSAGE_MAX) message__next = 0;
+
+ /* Kill last message if needed */
+ if (message__next == message__last) message__last++;
+
+ /* Handle wrap */
+ if (message__last == MESSAGE_MAX) message__last = 0;
+
+
+
+ /*** Step 7 -- Insert the message text ***/
+
+ /* Assign the starting address */
+ message__ptr[x] = message__head;
+ message__color[x] = color;
+ message__type[x] = type;
+ message__count[x] = 1;
+
+ /* Append the new part of the message */
+ for (i = 0; i < n; i++)
+ {
+ /* Copy the message */
+ message__buf[message__head + i] = str[i];
+ }
+
+ /* Terminate */
+ message__buf[message__head + i] = '\0';
+
+ /* Advance the "head" pointer */
+ message__head += n + 1;
+}
+
+
+
+/*
+* Hack -- flush
+*/
+static void msg_flush(int x)
+{
+ byte a = TERM_L_BLUE;
+
+ /* Pause for response */
+ Term_putstr(x, 0, -1, a, "-more-");
+
+ /* Get an acceptable keypress */
+ while (1)
+ {
+ int cmd = inkey();
+ if (quick_messages) break;
+ if ((cmd == ESCAPE) || (cmd == ' ')) break;
+ if ((cmd == '\n') || (cmd == '\r')) break;
+ bell();
+ }
+
+ /* Clear the line */
+ Term_erase(0, 0, 255);
+}
+
+/* Display a message */
+void display_message(int x, int y, int split, byte color, cptr t)
+{
+ int i = 0, j = 0;
+
+ while (i < split)
+ {
+ if (t[i] == '#')
+ {
+ if (t[i + 1] == '#')
+ {
+ Term_putstr(x + j, y, 1, color, "#");
+ i += 2;
+ j++;
+ }
+ else
+ {
+ color = color_char_to_attr(t[i + 1]);
+ i += 2;
+ }
+ }
+ else
+ {
+ Term_putstr(x + j, y, 1, color, t + i);
+ i++;
+ j++;
+ }
+ }
+}
+
+/*
+* Output a message to the top line of the screen.
+*
+* Break long messages into multiple pieces (40-72 chars).
+*
+* Allow multiple short messages to "share" the top line.
+*
+* Prompt the user to make sure he has a chance to read them.
+*
+* These messages are memorized for later reference (see above).
+*
+* We could do "Term_fresh()" to provide "flicker" if needed.
+*
+* The global "msg_flag" variable can be cleared to tell us to
+* "erase" any "pending" messages still on the screen.
+*
+* XXX XXX XXX Note that we must be very careful about using the
+* "msg_print()" functions without explicitly calling the special
+* "msg_print(NULL)" function, since this may result in the loss
+* of information if the screen is cleared, or if anything is
+* displayed on the top line.
+*
+* XXX XXX XXX Note that "msg_print(NULL)" will clear the top line
+* even if no messages are pending. This is probably a hack.
+*/
+void cmsg_print(byte color, cptr msg)
+{
+ static int p = 0;
+
+ int n;
+
+ char *t;
+
+ char buf[1024];
+
+ int lim = Term->wid - 8;
+
+
+ /* Hack -- Reset */
+ if (!msg_flag) p = 0;
+
+ /* Message Length */
+ n = (msg ? strlen(msg) : 0);
+
+ /* Hack -- flush when requested or needed */
+ if (p && (!msg || ((p + n) > lim)))
+ {
+ /* Flush */
+ msg_flush(p);
+
+ /* Forget it */
+ msg_flag = FALSE;
+
+ /* Reset */
+ p = 0;
+ }
+
+
+ /* No message */
+ if (!msg) return;
+
+ /* Paranoia */
+ if (n > 1000) return;
+
+
+ /* Memorize the message */
+ if (character_generated) message_add(MESSAGE_MSG, msg, color);
+
+ /* Handle "auto_more" */
+ if (auto_more)
+ {
+ /* Window stuff */
+ p_ptr->window |= (PW_MESSAGE);
+
+ /* Force window update */
+ window_stuff();
+
+ /* Done */
+ return;
+ }
+
+
+ /* Copy it */
+ strcpy(buf, msg);
+
+ /* Analyze the buffer */
+ t = buf;
+
+ /* Split message */
+ while (n > lim)
+ {
+ char oops;
+
+ int check, split;
+
+ /* Default split */
+ split = lim;
+
+ /* Find the "best" split point */
+ for (check = 40; check < lim; check++)
+ {
+ /* Found a valid split point */
+ if (t[check] == ' ') split = check;
+ }
+
+ /* Save the split character */
+ oops = t[split];
+
+ /* Split the message */
+ t[split] = '\0';
+
+ /* Display part of the message */
+ display_message(0, 0, split, color, t);
+
+ /* Flush it */
+ msg_flush(split + 1);
+
+ /* Memorize the piece */
+ /* if (character_generated) message_add(t); */
+
+ /* Restore the split character */
+ t[split] = oops;
+
+ /* Insert a space */
+ t[--split] = ' ';
+
+ /* Prepare to recurse on the rest of "buf" */
+ t += split;
+ n -= split;
+ }
+
+
+ /* Display the tail of the message */
+ display_message(p, 0, n, color, t);
+
+ /* Memorize the tail */
+ /* if (character_generated) message_add(t); */
+
+ /* Window stuff */
+ p_ptr->window |= (PW_MESSAGE);
+
+ /* Remember the message */
+ msg_flag = TRUE;
+
+ /* Remember the position */
+ p += n + 1;
+
+ /* Optional refresh */
+ if (fresh_message) Term_fresh();
+}
+
+/* Hack -- for compatibility and easy sake */
+void msg_print(cptr msg)
+{
+ cmsg_print(TERM_WHITE, msg);
+}
+
+
+/*
+ * Hack -- prevent "accidents" in "screen_save()" or "screen_load()"
+ */
+static int screen_depth = 0;
+
+
+/*
+ * Save the screen, and increase the "icky" depth.
+ *
+ * This function must match exactly one call to "screen_load()".
+ */
+void screen_save(void)
+{
+ /* Hack -- Flush messages */
+ msg_print(NULL);
+
+ /* Save the screen (if legal) */
+ if (screen_depth++ == 0) Term_save();
+
+ /* Increase "icky" depth */
+ character_icky++;
+}
+
+
+/*
+ * Load the screen, and decrease the "icky" depth.
+ *
+ * This function must match exactly one call to "screen_save()".
+ */
+void screen_load(void)
+{
+ /* Hack -- Flush messages */
+ msg_print(NULL);
+
+ /* Load the screen (if legal) */
+ if (--screen_depth == 0) Term_load();
+
+ /* Decrease "icky" depth */
+ character_icky--;
+}
+
+
+/*
+* Display a formatted message, using "vstrnfmt()" and "msg_print()".
+*/
+void msg_format(cptr fmt, ...)
+{
+ va_list vp;
+
+ char buf[1024];
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Format the args, save the length */
+ (void)vstrnfmt(buf, 1024, fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Display */
+ cmsg_print(TERM_WHITE, buf);
+}
+
+void cmsg_format(byte color, cptr fmt, ...)
+{
+ va_list vp;
+
+ char buf[1024];
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Format the args, save the length */
+ (void)vstrnfmt(buf, 1024, fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Display */
+ cmsg_print(color, buf);
+}
+
+
+
+/*
+* Display a string on the screen using an attribute.
+*
+* At the given location, using the given attribute, if allowed,
+* add the given string. Do not clear the line.
+*/
+void c_put_str(byte attr, cptr str, int row, int col)
+{
+ /* Position cursor, Dump the attr/text */
+ Term_putstr(col, row, -1, attr, str);
+}
+
+/*
+* As above, but in "white"
+*/
+void put_str(cptr str, int row, int col)
+{
+ /* Spawn */
+ Term_putstr(col, row, -1, TERM_WHITE, str);
+}
+
+
+
+/*
+* Display a string on the screen using an attribute, and clear
+* to the end of the line.
+*/
+void c_prt(byte attr, cptr str, int row, int col)
+{
+ /* Clear line, position cursor */
+ Term_erase(col, row, 255);
+
+ /* Dump the attr/text */
+ Term_addstr( -1, attr, str);
+}
+
+/*
+* As above, but in "white"
+*/
+void prt(cptr str, int row, int col)
+{
+ /* Spawn */
+ c_prt(TERM_WHITE, str, row, col);
+}
+
+
+
+/*
+ * Print some (colored) text to the screen at the current cursor position,
+ * automatically "wrapping" existing text (at spaces) when necessary to
+ * avoid placing any text into the last column, and clearing every line
+ * before placing any text in that line. Also, allow "newline" to force
+ * a "wrap" to the next line. Advance the cursor as needed so sequential
+ * calls to this function will work correctly.
+ *
+ * Once this function has been called, the cursor should not be moved
+ * until all the related "text_out()" calls to the window are complete.
+ *
+ * This function will correctly handle any width up to the maximum legal
+ * value of 256, though it works best for a standard 80 character width.
+ */
+void text_out_to_screen(byte a, cptr str)
+{
+ int x, y;
+
+ int wid, h;
+
+ int wrap;
+
+ cptr s;
+
+
+ /* Obtain the size */
+ (void)Term_get_size(&wid, &h);
+
+ /* Obtain the cursor */
+ (void)Term_locate(&x, &y);
+
+ /* Use special wrapping boundary? */
+ if ((text_out_wrap > 0) && (text_out_wrap < wid))
+ wrap = text_out_wrap;
+ else
+ wrap = wid;
+
+ /* Process the string */
+ for (s = str; *s; s++)
+ {
+ char ch;
+
+ /* Force wrap */
+ if (*s == '\n')
+ {
+ /* Wrap */
+ x = text_out_indent;
+ y++;
+
+ /* Clear line, move cursor */
+ Term_erase(x, y, 255);
+
+ continue;
+ }
+
+ /* Clean up the char */
+ ch = (isprint((unsigned char) * s) ? *s : ' ');
+
+ /* Wrap words as needed */
+ if ((x >= wrap - 1) && (ch != ' '))
+ {
+ int i, n = 0;
+
+ byte av[256];
+ char cv[256];
+
+ /* Wrap word */
+ if (x < wrap)
+ {
+ /* Scan existing text */
+ for (i = wrap - 2; i >= 0; i--)
+ {
+ /* Grab existing attr/char */
+ Term_what(i, y, &av[i], &cv[i]);
+
+ /* Break on space */
+ if (cv[i] == ' ') break;
+
+ /* Track current word */
+ n = i;
+ }
+ }
+
+ /* Special case */
+ if (n == 0) n = wrap;
+
+ /* Clear line */
+ Term_erase(n, y, 255);
+
+ /* Wrap */
+ x = text_out_indent;
+ y++;
+
+ /* Clear line, move cursor */
+ Term_erase(x, y, 255);
+
+ /* Wrap the word (if any) */
+ for (i = n; i < wrap - 1; i++)
+ {
+ /* Dump */
+ Term_addch(av[i], cv[i]);
+
+ /* Advance (no wrap) */
+ if (++x > wrap) x = wrap;
+ }
+ }
+
+ /* Dump */
+ Term_addch(a, ch);
+
+ /* Advance */
+ if (++x > wrap) x = wrap;
+ }
+}
+
+
+/*
+ * Write text to the given file and apply line-wrapping.
+ *
+ * Hook function for text_out(). Make sure that text_out_file points
+ * to an open text-file.
+ *
+ * Long lines will be wrapped at text_out_wrap, or at column 75 if that
+ * is not set; or at a newline character.
+ *
+ * You must be careful to end all file output with a newline character
+ * to "flush" the stored line position.
+ */
+void text_out_to_file(byte a, cptr str)
+{
+ /* Current position on the line */
+ static int pos = 0;
+
+ /* Wrap width */
+ int wrap = (text_out_wrap ? text_out_wrap : 75);
+
+ /* Current location within "str" */
+ cptr s = str;
+
+ /* Unused parameter */
+ (void)a;
+
+ /* Process the string */
+ while (*s)
+ {
+ char ch;
+ int n = 0;
+ int len = wrap - pos;
+ int l_space = 0;
+
+ /* If we are at the start of the line... */
+ if (pos == 0)
+ {
+ int i;
+
+ /* Output the indent */
+ for (i = 0; i < text_out_indent; i++)
+ {
+ fputc(' ', text_out_file);
+ pos++;
+ }
+ }
+
+ /* Find length of line up to next newline or end-of-string */
+ while ((n < len) && !((s[n] == '\n') || (s[n] == '\0')))
+ {
+ /* Mark the most recent space in the string */
+ if (s[n] == ' ') l_space = n;
+
+ /* Increment */
+ n++;
+ }
+
+ /* If we have encountered no spaces */
+ if ((l_space == 0) && (n == len))
+ {
+ /* If we are at the start of a new line */
+ if (pos == text_out_indent)
+ {
+ len = n;
+ }
+ else
+ {
+ /* Begin a new line */
+ fputc('\n', text_out_file);
+
+ /* Reset */
+ pos = 0;
+
+ continue;
+ }
+ }
+ else
+ {
+ /* Wrap at the newline */
+ if ((s[n] == '\n') || (s[n] == '\0')) len = n;
+
+ /* Wrap at the last space */
+ else len = l_space;
+ }
+
+ /* Write that line to file */
+ for (n = 0; n < len; n++)
+ {
+ /* Ensure the character is printable */
+ ch = (isprint(s[n]) ? s[n] : ' ');
+
+ /* Write out the character */
+ fputc(ch, text_out_file);
+
+ /* Increment */
+ pos++;
+ }
+
+ /* Move 's' past the stuff we've written */
+ s += len;
+
+ /* If we are at the end of the string, end */
+ if (*s == '\0') return;
+
+ /* Skip newlines */
+ if (*s == '\n') s++;
+
+ /* Begin a new line */
+ fputc('\n', text_out_file);
+
+ /* Reset */
+ pos = 0;
+
+ /* Skip whitespace */
+ while (*s == ' ') s++;
+ }
+
+ /* We are done */
+ return;
+}
+
+
+/*
+ * Output text to the screen or to a file depending on the selected
+ * text_out hook.
+ */
+void text_out(cptr str)
+{
+ text_out_c(TERM_WHITE, str);
+}
+
+
+/*
+ * Output text to the screen (in color) or to a file depending on the
+ * selected hook.
+ */
+void text_out_c(byte a, cptr str)
+{
+ text_out_hook(a, str);
+}
+
+
+
+
+/*
+* Clear part of the screen
+*/
+void clear_from(int row)
+{
+ int y;
+
+ /* Erase requested rows */
+ for (y = row; y < Term->hgt; y++)
+ {
+ /* Erase part of the screen */
+ Term_erase(0, y, 255);
+ }
+}
+
+/*
+ * Try to find a matching command completion.
+ * Note that this is not so friendly since it doesn't give
+ * a list of possible completions.
+ *
+ * First arg is the string to be completed, second is it's length,
+ * third is it's maximum length.
+ */
+static int complete_where = 0;
+static char complete_buf[100];
+static int complete_command(char *buf, int clen, int mlen)
+{
+ int i, j = 1, max = clen;
+ bool_ gotone = FALSE;
+
+ /* Forget the characters after the end of the string. */
+ complete_buf[clen] = '\0';
+
+ for (i = 0; i < cli_total; i++)
+ {
+ cli_comm *cli_ptr = cli_info + i;
+
+ if (!strncmp(cli_ptr->comm, complete_buf, clen))
+ {
+ Term_erase(0, j, 80);
+ Term_putstr(0, j++, -1, TERM_WHITE, cli_ptr->comm);
+
+ /* For the first match, copy the whole string to buf. */
+ if (!gotone)
+ {
+ sprintf(buf, "%.*s", mlen, cli_ptr->comm);
+ gotone = TRUE;
+ }
+ /* For later matches, simply notice how much of buf it
+ * matches. */
+ else
+ {
+ for (max = clen; max < mlen; max++)
+ {
+ if (cli_ptr->comm[max] == '\0') break;
+ if (cli_ptr->comm[max] != buf[max]) break;
+ }
+ if (max < mlen) buf[max] = '\0';
+ }
+ }
+ }
+
+ return strlen(buf) + 1;
+}
+
+
+/*
+* Get some input at the cursor location.
+* Assume the buffer is initialized to a default string.
+* Note that this string is often "empty" (see below).
+* The default buffer is displayed in yellow until cleared.
+* Pressing RETURN right away accepts the default entry.
+* Normal chars clear the default and append the char.
+* Backspace clears the default or deletes the final char.
+* ESCAPE clears the buffer and the window and returns FALSE.
+* RETURN accepts the current buffer contents and returns TRUE.
+*/
+bool_ askfor_aux_complete = FALSE;
+bool_ askfor_aux(char *buf, int len)
+{
+ int y, x;
+
+ int i = 0;
+
+ int k = 0;
+
+ int wid, hgt;
+
+ bool_ done = FALSE;
+
+
+ /* Locate the cursor */
+ Term_locate(&x, &y);
+
+ /* Get terminal size */
+ Term_get_size(&wid, &hgt);
+
+ /* Paranoia -- check column */
+ if ((x < 0) || (x >= wid)) x = 0;
+
+ /* Restrict the length */
+ if (x + len > wid) len = wid - x;
+
+
+ /* Paranoia -- Clip the default entry */
+ buf[len] = '\0';
+
+
+ /* Display the default answer */
+ Term_erase(x, y, len);
+ Term_putstr(x, y, -1, TERM_YELLOW, buf);
+
+ if (askfor_aux_complete)
+ {
+ screen_save();
+ complete_where = 0;
+ strncpy(complete_buf, buf, 100);
+ }
+
+ /* Process input */
+ while (!done)
+ {
+ /* Place cursor */
+ Term_gotoxy(x + k, y);
+
+ /* Get a key */
+ i = inkey();
+
+ /* Analyze the key */
+ switch (i)
+ {
+ case ESCAPE:
+ k = 0;
+ done = TRUE;
+ break;
+
+ case '\n':
+ case '\r':
+ k = strlen(buf);
+ done = TRUE;
+ break;
+
+ case '\t':
+ if (askfor_aux_complete && k)
+ {
+ screen_load();
+ screen_save();
+ k = complete_command(buf, k, len);
+ }
+ else
+ {
+ bell();
+ }
+
+ case 0x7F:
+ case '\010':
+ if (k > 0) k--;
+ strncpy(complete_buf, buf, k);
+ break;
+
+ default:
+ if ((k < len) && (isprint(i)))
+ {
+ buf[k++] = i;
+ strncpy(complete_buf, buf, k);
+ }
+ else
+ {
+ bell();
+ }
+ break;
+ }
+
+ /* Terminate */
+ buf[k] = '\0';
+
+ /* Update the entry */
+ Term_erase(x, y, len);
+ Term_putstr(x, y, -1, TERM_WHITE, buf);
+ }
+
+ if (askfor_aux_complete)
+ {
+ screen_load();
+ }
+
+ /* Aborted */
+ if (i == ESCAPE) return (FALSE);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+* Get a string from the user
+*
+* The "prompt" should take the form "Prompt: "
+*
+* Note that the initial contents of the string is used as
+* the default response, so be sure to "clear" it if needed.
+*
+* We clear the input, and return FALSE, on "ESCAPE".
+*/
+bool_ get_string(cptr prompt, char *buf, int len)
+{
+ bool_ res;
+
+ /* Paranoia XXX XXX XXX */
+ msg_print(NULL);
+
+ /* Display prompt */
+ prt(prompt, 0, 0);
+
+ /* Ask the user for a string */
+ res = askfor_aux(buf, len);
+
+ /* Clear prompt */
+ prt("", 0, 0);
+
+ /* Result */
+ return (res);
+}
+
+
+/*
+* Verify something with the user
+*
+* The "prompt" should take the form "Query? "
+*
+* Note that "[y/n]" is appended to the prompt.
+*/
+bool_ get_check(cptr prompt)
+{
+ int i;
+
+ char buf[80];
+
+ /* Paranoia XXX XXX XXX */
+ msg_print(NULL);
+
+ /* Hack -- Build a "useful" prompt */
+ strnfmt(buf, 78, "%.70s[y/n] ", prompt);
+
+ /* Prompt for it */
+ prt(buf, 0, 0);
+
+ /* Get an acceptable answer */
+ while (TRUE)
+ {
+ i = inkey();
+ if (quick_messages) break;
+ if (i == ESCAPE) break;
+ if (strchr("YyNn", i)) break;
+ bell();
+ }
+
+ /* Erase the prompt */
+ prt("", 0, 0);
+
+ /* Normal negation */
+ if ((i != 'Y') && (i != 'y')) return (FALSE);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+* Prompts for a keypress
+*
+* The "prompt" should take the form "Command: "
+*
+* Returns TRUE unless the character is "Escape"
+*/
+bool_ get_com(cptr prompt, char *command)
+{
+ /* Paranoia XXX XXX XXX */
+ msg_print(NULL);
+
+ /* Display a prompt */
+ prt(prompt, 0, 0);
+
+ /* Get a key */
+ *command = inkey();
+
+ /* Clear the prompt */
+ prt("", 0, 0);
+
+ /* Handle "cancel" */
+ if (*command == ESCAPE) return (FALSE);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+* Request a "quantity" from the user
+*
+* Hack -- allow "command_arg" to specify a quantity
+*/
+s32b get_quantity(cptr prompt, s32b max)
+{
+ s32b amt;
+ int aamt;
+
+ char tmp[80];
+
+ char buf[80];
+
+
+ /* Use "command_arg" */
+ if (command_arg)
+ {
+ /* Extract a number */
+ amt = command_arg;
+
+ /* Clear "command_arg" */
+ command_arg = 0;
+
+ /* Enforce the maximum */
+ if (amt > max) amt = max;
+
+ /* Use it */
+ return (amt);
+ }
+
+ /* Get the item index */
+ if ((max != 1) && repeat_pull(&aamt))
+ {
+ amt = aamt;
+
+ /* Enforce the maximum */
+ if (amt > max) amt = max;
+
+ /* Enforce the minimum */
+ if (amt < 0) amt = 0;
+
+ /* Use it */
+ return (amt);
+ }
+
+ /* Build a prompt if needed */
+ if (!prompt)
+ {
+ /* Build a prompt */
+ sprintf(tmp, "Quantity (1-%ld): ", (long int) max);
+
+ /* Use that prompt */
+ prompt = tmp;
+ }
+
+
+ /* Default to one */
+ amt = 1;
+
+ /* Build the default */
+ sprintf(buf, "%ld", (long int) amt);
+
+ /* Ask for a quantity */
+ if (!get_string(prompt, buf, 9)) return (0);
+
+ /* Extract a number */
+ amt = atoi(buf);
+
+ /* A letter means "all" */
+ if (isalpha(buf[0])) amt = max;
+
+ /* Enforce the maximum */
+ if (amt > max) amt = max;
+
+ /* Enforce the minimum */
+ if (amt < 0) amt = 0;
+
+
+ if (amt) repeat_push(amt);
+
+ /* Return the result */
+ return (amt);
+}
+
+
+/*
+* Pause for user response XXX XXX XXX
+*/
+void pause_line(int row)
+{
+ prt("", row, 0);
+ put_str("[Press any key to continue]", row, 23);
+ inkey();
+ prt("", row, 0);
+}
+
+
+/*
+* Hack -- special buffer to hold the action of the current keymap
+*/
+static char request_command_buffer[256];
+
+/*
+* Mega-Hack -- characters for which keymaps should be ignored in
+* request_command(). This MUST have at least twice as many characters as
+* there are building actions in the actions[] array in store_info_type.
+*/
+#define MAX_IGNORE_KEYMAPS 12
+char request_command_ignore_keymaps[MAX_IGNORE_KEYMAPS];
+
+/*
+* Mega-Hack -- flag set by do_cmd_{inven,equip}() to allow keymaps in
+* auto-command mode.
+*/
+bool_ request_command_inven_mode = FALSE;
+
+
+/*
+* Request a command from the user.
+*
+* Sets p_ptr->command_cmd, p_ptr->command_dir, p_ptr->command_rep,
+* p_ptr->command_arg. May modify p_ptr->command_new.
+*
+* Note that "caret" ("^") is treated specially, and is used to
+* allow manual input of control characters. This can be used
+* on many machines to request repeated tunneling (Ctrl-H) and
+* on the Macintosh to request "Control-Caret".
+*
+* Note that "backslash" is treated specially, and is used to bypass any
+* keymap entry for the following character. This is useful for macros.
+*
+* Note that this command is used both in the dungeon and in
+* stores, and must be careful to work in both situations.
+*
+* Note that "p_ptr->command_new" may not work any more. XXX XXX XXX
+*/
+void request_command(int shopping)
+{
+ int i;
+
+ s16b cmd;
+ char cmd_char;
+
+ int mode;
+
+ cptr act;
+
+
+ /* Keymap mode */
+ mode = get_keymap_mode();
+
+ /* No command yet */
+ command_cmd = 0;
+
+ /* No "argument" yet */
+ command_arg = 0;
+
+ /* No "direction" yet */
+ command_dir = 0;
+
+
+ /* Get command */
+ while (1)
+ {
+ /* Hack -- auto-commands */
+ if (command_new)
+ {
+ /* Flush messages */
+ msg_print(NULL);
+
+ /* Use auto-command */
+ cmd = command_new;
+
+ /* Forget it */
+ command_new = 0;
+
+ /* Hack - bypass keymaps, unless asked not to */
+ if (!inkey_next && !request_command_inven_mode)
+ {
+ inkey_next = "";
+ }
+
+ /* Mega-Hack -- turn off this flag immediately */
+ request_command_inven_mode = FALSE;
+ }
+
+ /* Get a keypress in "command" mode */
+ else
+ {
+ /* Hack -- no flush needed */
+ msg_flag = FALSE;
+
+ /* Activate "command mode" */
+ inkey_flag = TRUE;
+
+ /* Get a command */
+ cmd = inkey();
+ }
+
+ /* Clear top line */
+ prt("", 0, 0);
+
+
+ /* Command Count */
+ if (cmd == '0')
+ {
+ int old_arg = command_arg;
+
+ /* Reset */
+ command_arg = 0;
+
+ /* Begin the input */
+ prt("Count: ", 0, 0);
+
+ /* Get a command count */
+ while (1)
+ {
+ /* Get a new keypress */
+ cmd = inkey();
+
+ /* Simple editing (delete or backspace) */
+ if ((cmd == 0x7F) || (cmd == KTRL('H')))
+ {
+ /* Delete a digit */
+ command_arg = command_arg / 10;
+
+ /* Show current count */
+ prt(format("Count: %d", command_arg), 0, 0);
+ }
+
+ /* Actual numeric data */
+ else if (cmd >= '0' && cmd <= '9')
+ {
+ /* Stop count at 9999 */
+ if (command_arg >= 1000)
+ {
+ /* Warn */
+ bell();
+
+ /* Limit */
+ command_arg = 9999;
+ }
+
+ /* Increase count */
+ else
+ {
+ /* Incorporate that digit */
+ command_arg = command_arg * 10 + D2I(cmd);
+ }
+
+ /* Show current count */
+ prt(format("Count: %d", command_arg), 0, 0);
+ }
+
+ /* Exit on "unusable" input */
+ else
+ {
+ break;
+ }
+ }
+
+ /* Hack -- Handle "zero" */
+ if (command_arg == 0)
+ {
+ /* Default to 99 */
+ command_arg = 99;
+
+ /* Show current count */
+ prt(format("Count: %d", command_arg), 0, 0);
+ }
+
+ /* Hack -- Handle "old_arg" */
+ if (old_arg != 0)
+ {
+ /* Restore old_arg */
+ command_arg = old_arg;
+
+ /* Show current count */
+ prt(format("Count: %d", command_arg), 0, 0);
+ }
+
+ /* Hack -- white-space means "enter command now" */
+ if ((cmd == ' ') || (cmd == '\n') || (cmd == '\r'))
+ {
+ /* Get a real command */
+ bool_ temp = get_com("Command: ", &cmd_char);
+ cmd = cmd_char;
+
+ if (!temp)
+ {
+ /* Clear count */
+ command_arg = 0;
+
+ /* Continue */
+ continue;
+ }
+ }
+ }
+
+
+ /* Allow "keymaps" to be bypassed */
+ if (cmd == '\\')
+ {
+ /* Get a real command */
+ (void)get_com("Command: ", &cmd_char);
+
+ cmd = cmd_char;
+
+ /* Hack -- bypass keymaps */
+ if (!inkey_next) inkey_next = "";
+ }
+
+
+ /* Allow "control chars" to be entered */
+ if (cmd == '^')
+ {
+ /* Get a new command and controlify it */
+ if (get_com("Control: ", &cmd_char)) cmd = KTRL(cmd_char);
+ else cmd = 0;
+ }
+
+
+ /* Look up applicable keymap */
+ act = keymap_act[mode][(byte)(cmd)];
+
+ /* Mega-Hack -- Ignore certain keymaps */
+ if (shopping && cmd > 0)
+ {
+ for (i = 0; i < MAX_IGNORE_KEYMAPS; i++)
+ if (cmd == request_command_ignore_keymaps[i])
+ {
+ act = NULL;
+ break;
+ }
+ }
+
+ /* Apply keymap if not inside a keymap already */
+ if (act && !inkey_next)
+ {
+ /* Install the keymap (limited buffer size) */
+ strnfmt(request_command_buffer, 256, "%s", act);
+
+ /* Start using the buffer */
+ inkey_next = request_command_buffer;
+
+ /* Continue */
+ continue;
+ }
+
+
+ /* Paranoia */
+ if (!cmd) continue;
+
+
+ /* Use command */
+ command_cmd = cmd;
+
+ /* Done */
+ break;
+ }
+
+ /* Hack -- Auto-repeat certain commands */
+ if (always_repeat && (command_arg <= 0))
+ {
+ /* Hack -- auto repeat certain commands */
+ if (strchr("TBDoc+", command_cmd))
+ {
+ /* Repeat 99 times */
+ command_arg = 99;
+ }
+ }
+
+ /* Hack -- Scan equipment */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ cptr s;
+
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* No inscription */
+ if (!o_ptr->note) continue;
+
+ /* Obtain the inscription */
+ s = quark_str(o_ptr->note);
+
+ /* Find a '^' */
+ s = strchr(s, '^');
+
+ /* Process preventions */
+ while (s)
+ {
+ /* Check the "restriction" character */
+ if ((s[1] == command_cmd) || (s[1] == '*'))
+ {
+ /* Hack -- Verify command */
+ if (!get_check("Are you sure? "))
+ {
+ /* Hack -- Use space */
+ command_cmd = ' ';
+ }
+ }
+
+ /* Find another '^' */
+ s = strchr(s + 1, '^');
+ }
+ }
+
+
+ /* Hack -- erase the message line. */
+ prt("", 0, 0);
+}
+
+
+
+
+/*
+ * Check a char for "vowel-hood"
+ */
+bool_ is_a_vowel(int ch)
+{
+ switch (ch)
+ {
+ case 'a':
+ case 'e':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'A':
+ case 'E':
+ case 'I':
+ case 'O':
+ case 'U':
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+/*
+ * GH
+ * Called from cmd4.c and a few other places. Just extracts
+ * a direction from the keymap for ch (the last direction,
+ * in fact) byte or char here? I'm thinking that keymaps should
+ * generally only apply to single keys, which makes it no more
+ * than 128, so a char should suffice... but keymap_act is 256...
+ */
+int get_keymap_dir(char ch)
+{
+ int d = 0;
+
+ int mode;
+
+ cptr act;
+
+ cptr s;
+
+
+ /* Already a direction? */
+ if (isdigit(ch))
+ {
+ d = D2I(ch);
+ }
+ else
+ {
+ /* Keymap mode */
+ mode = get_keymap_mode();
+
+ /* Extract the action (if any) */
+ act = keymap_act[mode][(byte)(ch)];
+
+ /* Analyze */
+ if (act)
+ {
+ /* Convert to a direction */
+ for (s = act; *s; ++s)
+ {
+ /* Use any digits in keymap */
+ if (isdigit(*s)) d = D2I(*s);
+ }
+ }
+ }
+
+ /* Paranoia */
+ if (d == 5) d = 0;
+
+ /* Return direction */
+ return (d);
+}
+
+
+#define REPEAT_MAX 20
+
+/* Number of chars saved */
+static int repeat__cnt = 0;
+
+/* Current index */
+static int repeat__idx = 0;
+
+/* Saved "stuff" */
+static int repeat__key[REPEAT_MAX];
+
+
+void repeat_push(int what)
+{
+ /* Too many keys */
+ if (repeat__cnt == REPEAT_MAX) return;
+
+ /* Push the "stuff" */
+ repeat__key[repeat__cnt++] = what;
+
+ /* Prevents us from pulling keys */
+ ++repeat__idx;
+}
+
+
+bool_ repeat_pull(int *what)
+{
+ /* All out of keys */
+ if (repeat__idx == repeat__cnt) return (FALSE);
+
+ /* Grab the next key, advance */
+ *what = repeat__key[repeat__idx++];
+
+ /* Success */
+ return (TRUE);
+}
+
+void repeat_check(void)
+{
+ int what;
+
+ /* Ignore some commands */
+ if (command_cmd == ESCAPE) return;
+ if (command_cmd == ' ') return;
+ if (command_cmd == '\r') return;
+ if (command_cmd == '\n') return;
+
+ /* Repeat Last Command */
+ if (command_cmd == 'n')
+ {
+ /* Reset */
+ repeat__idx = 0;
+
+ /* Get the command */
+ if (repeat_pull(&what))
+ {
+ /* Save the command */
+ command_cmd = what;
+ }
+ }
+
+ /* Start saving new command */
+ else
+ {
+ /* Reset */
+ repeat__cnt = 0;
+ repeat__idx = 0;
+
+ what = command_cmd;
+
+ /* Save this command */
+ repeat_push(what);
+ }
+}
+
+
+/*
+ * Read a number at a specific location on the screen
+ *
+ * Allow numbers of any size and save the last keypress.
+ */
+u32b get_number(u32b def, u32b max, int y, int x, char *cmd)
+{
+ u32b res = def;
+
+ /* Player has not typed anything yet */
+ bool_ no_keys = TRUE;
+
+ /* Begin the input with default */
+ prt(format("%lu", def), y, x);
+
+ /* Get a command count */
+ while (1)
+ {
+ /* Get a new keypress */
+ *cmd = inkey();
+
+ /* Simple editing (delete or backspace) */
+ if ((*cmd == 0x7F) || (*cmd == KTRL('H')))
+ {
+ /* Override the default */
+ no_keys = FALSE;
+
+ /* Delete a digit */
+ res = res / 10;
+
+ prt(format("%lu", res), y, x);
+ }
+
+ /* Actual numeric data */
+ else if (*cmd >= '0' && *cmd <= '9')
+ {
+ /* Override the default */
+ if (no_keys)
+ {
+ no_keys = FALSE;
+ res = 0;
+ }
+
+ /* Don't overflow */
+ if (((u32b)(0 - 1) - D2I(*cmd)) / 10 < res)
+ {
+ /* Warn */
+ bell();
+
+ /* Limit */
+ res = (max + 1 == 0) ? (u32b)(0 - 1) : max;
+ }
+
+ /* Stop count at maximum */
+ else if (res * 10 + D2I(*cmd) > max)
+ {
+ /* Warn */
+ bell();
+
+ /* Limit */
+ res = max;
+ }
+
+ /* Increase count */
+ else
+ {
+ /* Incorporate that digit */
+ res = res * 10 + D2I(*cmd);
+ }
+
+ /* Show current count */
+ prt(format("%lu", res), y, x);
+ }
+
+ /* Escape cancels */
+ else if (*cmd == ESCAPE)
+ {
+ res = 0;
+ break;
+ }
+
+ /* Exit on "unusable" input */
+ else
+ {
+ break;
+ }
+ }
+
+ return res;
+}
+
+/*
+ * Allow the user to select multiple items without pressing '0'
+ */
+void get_count(int number, int max)
+{
+ char cmd;
+
+ /* Use the default */
+ command_arg = number;
+
+ /* Hack -- Optional flush */
+ if (flush_command) flush();
+
+ /* Clear top line */
+ prt("", 0, 0);
+
+ /* Begin the input */
+ prt("How many?", 0, 0);
+
+ /* Actually get a number */
+ command_arg = get_number(command_arg, max, 0, 10, &cmd);
+
+ prt("", 0, 0);
+}
+
+byte count_bits(u32b array)
+{
+ byte k = 0, i;
+
+ if (array)
+ for (i = 0; i < 32; i++)
+ if (array & (1 << i)) k++;
+
+ return k;
+}
+
+/* Return the lowered string */
+void strlower(char *buf)
+{
+ u16b i;
+
+ for (i = 0; (buf[i] != 0) && (i < 256) ;i++)
+ {
+ if (isupper(buf[i])) buf[i] = tolower(buf[i]);
+ }
+}
+
+/*
+ * Given monster name as string, return the index in r_info array. Name
+ * must exactly match (look out for commas and the like!), or else 0 is
+ * returned. Case doesn't matter. -GSN-
+ */
+
+int test_monster_name(cptr name)
+{
+ int i;
+
+ /* Scan the monsters */
+ for (i = 1; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+ cptr mon_name = r_name + r_ptr->name;
+
+ /* If name matches, give us the number */
+ if (stricmp(name, mon_name) == 0) return (i);
+ }
+ return (0);
+}
+int test_mego_name(cptr name)
+{
+ int i;
+
+ /* Scan the monsters */
+ for (i = 1; i < max_re_idx; i++)
+ {
+ monster_ego *re_ptr = &re_info[i];
+ cptr mon_name = re_name + re_ptr->name;
+
+ /* If name matches, give us the number */
+ if (stricmp(name, mon_name) == 0) return (i);
+ }
+ return (0);
+}
+
+/*
+ * Given item name as string, return the index in k_info array. Name
+ * must exactly match (look out for commas and the like!), or else 0 is
+ * returned. Case doesn't matter. -DG-
+ */
+
+int test_item_name(cptr name)
+{
+ int i;
+
+ /* Scan the items */
+ for (i = 1; i < max_k_idx; i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+ cptr obj_name = k_name + k_ptr->name;
+
+ /* If name matches, give us the number */
+ if (stricmp(name, obj_name) == 0) return (i);
+ }
+ return (0);
+}
+
+/*
+ * Break scalar time
+ */
+s32b bst(s32b what, s32b t)
+{
+ s32b turns = t + (10 * DAY_START);
+
+ switch (what)
+ {
+ case MINUTE:
+ return ((turns / 10 / MINUTE) % 60);
+ case HOUR:
+ return (turns / 10 / (HOUR) % 24);
+ case DAY:
+ return (turns / 10 / (DAY) % 365);
+ case YEAR:
+ return (turns / 10 / (YEAR));
+ default:
+ return (0);
+ }
+}
+
+cptr get_month_name(int day, bool_ full, bool_ compact)
+{
+ int i = 8;
+ static char buf[40];
+
+ /* Find the period name */
+ while ((i > 0) && (day < month_day[i]))
+ {
+ i--;
+ }
+
+ switch (i)
+ {
+ /* Yestare/Mettare */
+ case 0:
+ case 8:
+ {
+ char buf2[20];
+
+ sprintf(buf2, "%s", get_day(day + 1));
+ if (full) sprintf(buf, "%s (%s day)", month_name[i], buf2);
+ else sprintf(buf, "%s", month_name[i]);
+ break;
+ }
+ /* 'Normal' months + Enderi */
+ default:
+ {
+ char buf2[20];
+ char buf3[20];
+
+ sprintf(buf2, "%s", get_day(day + 1 - month_day[i]));
+ sprintf(buf3, "%s", get_day(day + 1));
+
+ if (full) sprintf(buf, "%s day of %s (%s day)", buf2, month_name[i], buf3);
+ else if (compact) sprintf(buf, "%s day of %s", buf2, month_name[i]);
+ else sprintf(buf, "%s %s", buf2, month_name[i]);
+ break;
+ }
+ }
+
+ return (buf);
+}
+
+cptr get_day(int day)
+{
+ static char buf[20];
+ cptr p = "th";
+
+ if ((day / 10) == 1) ;
+ else if ((day % 10) == 1) p = "st";
+ else if ((day % 10) == 2) p = "nd";
+ else if ((day % 10) == 3) p = "rd";
+
+ sprintf(buf, "%d%s", day, p);
+ return (buf);
+}
+
+cptr get_player_race_name(int pr, int ps)
+{
+ static char buf[50];
+
+ if (ps)
+ {
+ if (race_mod_info[ps].place) sprintf(buf, "%s %s", race_info[pr].title + rp_name, race_mod_info[ps].title + rmp_name);
+ else sprintf(buf, "%s %s", race_mod_info[ps].title + rmp_name, race_info[pr].title + rp_name);
+ }
+ else
+ {
+ sprintf(buf, "%s", race_info[pr].title + rp_name);
+ }
+
+ return (buf);
+}
+
+/*
+ * Ask to select an item in a list
+ */
+int ask_menu(cptr ask, char **items, int max)
+{
+ int ret = -1, i, start = 0;
+ char c;
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ while (TRUE)
+ {
+ /* Display list */
+ Term_load();
+ Term_save();
+ prt(ask, 0, 0);
+ for (i = start; (i < max) && (i < start + 20); i++)
+ {
+ prt(format("%c) %s", I2A(i - start), items[i]), i - start + 1, 0);
+ }
+
+ /* Wait for user input */
+ c = inkey();
+
+ /* Leave the screen */
+ if (c == ESCAPE) break;
+
+ /* Scroll */
+ else if (c == '+')
+ {
+ if (start + 20 < max)
+ start += 20;
+ continue;
+ }
+
+ /* Scroll */
+ else if (c == '-')
+ {
+ start -= 20;
+ if (start < 0) start = 0;
+ continue;
+ }
+
+ /* Good selection */
+ else
+ {
+ c = tolower(c);
+ if (A2I(c) + start >= max)
+ {
+ bell();
+ continue;
+ }
+ if (A2I(c) + start < 0)
+ {
+ bell();
+ continue;
+ }
+
+ ret = A2I(c) + start;
+ break;
+ }
+ }
+
+ /* Load the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+
+ return ret;
+}
+
+/*
+ * Determine if string "t" is a prefix of string "s"
+ */
+bool_ prefix(cptr s, cptr t)
+{
+ /* Paranoia */
+ if (!s || !t)
+ {
+ if (alert_failure) message_add(MESSAGE_MSG, "prefix() called with null argument!", TERM_RED);
+ return FALSE;
+ }
+
+ /* Scan "t" */
+ while (*t)
+ {
+ /* Compare content and length */
+ if (*t++ != *s++) return (FALSE);
+ }
+
+ /* Matched, we have a prefix */
+ return (TRUE);
+}
+
+/*
+ * Rescale a value
+ */
+s32b value_scale(int value, int vmax, int max, int min)
+{
+ s32b full_max = max - min;
+
+ value = (value * full_max) / vmax;
+ value += min;
+
+ return value;
+}
+
+/*
+ * Displays a box
+ */
+void draw_box(int y, int x, int h, int w)
+{
+ int i, j;
+
+ for (i = x + 1; i < x + w; i++)
+ for (j = y + 1; j < y + h; j++)
+ Term_putch(i, j, TERM_L_BLUE, ' ');
+
+ for (i = x; i < x + w; i++)
+ {
+ c_put_str(TERM_L_BLUE, "-", y, i);
+ c_put_str(TERM_L_BLUE, "-", y + h, i);
+ }
+ for (i = y; i < y + h; i++)
+ {
+ c_put_str(TERM_L_BLUE, "|", i, x);
+ c_put_str(TERM_L_BLUE, "|", i, x + w);
+ }
+ Term_putch(x, y, TERM_L_BLUE, '/');
+ Term_putch(x + w, y, TERM_L_BLUE, '\\');
+ Term_putch(x, y + h, TERM_L_BLUE, '\\');
+ Term_putch(x + w, y + h, TERM_L_BLUE, '/');
+}
+
+
+/*
+ * Displays a scrollable boxed list with a selected item
+ */
+void display_list(int y, int x, int h, int w, cptr title, cptr *list, int max, int begin, int sel, byte sel_color)
+{
+ int i;
+
+ draw_box(y, x, h, w);
+ c_put_str(TERM_L_BLUE, title, y, x + ((w - strlen(title)) / 2));
+
+ for (i = 0; i < h - 1; i++)
+ {
+ byte color = TERM_WHITE;
+
+ if (i + begin >= max) break;
+
+ if (i + begin == sel) color = sel_color;
+ c_put_str(color, list[i + begin], y + 1 + i, x + 1);
+ }
+}
+
+/*
+ * Creates an input box
+ */
+bool_ input_box(cptr text, int y, int x, char *buf, int max)
+{
+ int smax = strlen(text);
+
+ if (max > smax) smax = max;
+ smax++;
+
+ draw_box(y - 1, x - (smax / 2), 3, smax);
+ c_put_str(TERM_WHITE, text, y, x - (strlen(text) / 2));
+
+ Term_gotoxy(x - (smax / 2) + 1, y + 1);
+ return askfor_aux(buf, max);
+}
+
+/*
+ * Creates a msg bbox and ask a question
+ */
+char msg_box(cptr text, int y, int x)
+{
+ if (x == -1)
+ {
+ int wid = 0, hgt = 0;
+ Term_get_size(&wid, &hgt);
+ x = wid / 2;
+ y = hgt / 2;
+ }
+
+ draw_box(y - 1, x - ((strlen(text) + 1) / 2), 2, strlen(text) + 1);
+ c_put_str(TERM_WHITE, text, y, x - ((strlen(text) + 1) / 2) + 1);
+ return inkey();
+}
+
+/* Rescale a value */
+s32b rescale(s32b x, s32b max, s32b new_max)
+{
+ return (x * new_max) / max;
+}
+
+/* Nicer wrapper around TERM_XTRA_SCANSUBDIR */
+void scansubdir(cptr dir)
+{
+ strnfmt(scansubdir_dir, 1024, "%s", dir);
+ Term_xtra(TERM_XTRA_SCANSUBDIR, 0);
+}
+
+/*
+ * Timers
+ */
+timer_type *new_timer(cptr callback, s32b delay)
+{
+ timer_type *t_ptr;
+
+ MAKE(t_ptr, timer_type);
+ t_ptr->next = gl_timers;
+ gl_timers = t_ptr;
+
+ t_ptr->callback = string_make(callback);
+ t_ptr->delay = delay;
+ t_ptr->countdown = delay;
+ t_ptr->enabled = FALSE;
+
+ return t_ptr;
+}
+
+void del_timer(timer_type *t_ptr)
+{
+ timer_type *i, *old;
+
+ old = NULL;
+ for (i = gl_timers; (i != NULL) && (i != t_ptr); old = i, i = i->next)
+ ;
+ if (i)
+ {
+ if (old == NULL)
+ gl_timers = t_ptr->next;
+ else
+ old->next = t_ptr->next;
+ string_free(t_ptr->callback);
+ FREE(t_ptr, timer_type);
+ }
+ else
+ cmsg_print(TERM_VIOLET, "Unknown timer!");
+}
+
+int get_keymap_mode()
+{
+ if (rogue_like_commands)
+ {
+ return KEYMAP_MODE_ROGUE;
+ }
+ else
+ {
+ return KEYMAP_MODE_ORIG;
+ }
+}
diff --git a/src/util.pkg b/src/util.pkg
new file mode 100644
index 00000000..39f70b40
--- /dev/null
+++ b/src/util.pkg
@@ -0,0 +1,2683 @@
+/* File: util.pkg */
+
+/*
+ * Purpose: Lua interface defitions for miscellaneous routines.
+ * To be processed by tolua to generate C source code.
+ */
+
+$#include "angband.h"
+$#include "plots.h"
+
+/** @typedef cptr
+ * @note String
+ */
+typedef char* cptr;
+/** @typedef errr
+ * @note Number
+ */
+typedef int errr;
+/** @typedef bool
+ * @note Boolean
+ */
+typedef unsigned char bool;
+/** @typedef byte
+ * @note Number
+ */
+typedef unsigned char byte;
+/** @typedef s16b
+ * @note Number
+ */
+typedef signed short s16b;
+/** @typedef u16b
+ * @note Number
+ */
+typedef unsigned short u16b;
+/** @typedef s32b
+ * @note Number
+ */
+typedef signed int s32b;
+/** @typedef u32b
+ * @note Number
+ */
+typedef unsigned int u32b;
+
+/** @def TRUE */
+#define TRUE
+
+/** @def FALSE */
+#define FALSE
+
+
+/** @def ESCAPE */
+#define ESCAPE '\033'
+
+/** @name Terminal Colours
+ * @{
+ */
+/** @def TERM_DARK
+ * @note 'd' (0,0,0)
+ */
+#define TERM_DARK 0 /* 'd' */
+/** @def TERM_WHITE
+ * @note 'w' (4,4,4)
+ */
+#define TERM_WHITE 1 /* 'w' */
+/** @def TERM_SLATE
+ * @note 's' (2,2,2)
+ */
+#define TERM_SLATE 2 /* 's' */
+/** @def TERM_ORANGE
+ * @note 'o' (4,2,0)
+ */
+#define TERM_ORANGE 3 /* 'o' */
+/** @def TERM_RED
+ * @note 'r' (3,0,0)
+ */
+#define TERM_RED 4 /* 'r' */
+/** @def TERM_GREEN
+ * @note 'g' (0,2,1)
+ */
+#define TERM_GREEN 5 /* 'g' */
+/** @def TERM_BLUE
+ * @note 'b' (0,0,4)
+ */
+#define TERM_BLUE 6 /* 'b' */
+/** @def TERM_UMBER
+ * @note 'u' (2,1,0)
+ */
+#define TERM_UMBER 7 /* 'u' */
+/** @def TERM_L_DARK
+ * @note 'D' (1,1,1)
+ */
+#define TERM_L_DARK 8 /* 'D' */
+/** @def TERM_L_WHITE
+ * @note 'W' (3,3,3)
+ */
+#define TERM_L_WHITE 9 /* 'W' */
+/** @def TERM_VIOLET
+ * @note 'v' (4,0,4)
+ */
+#define TERM_VIOLET 10 /* 'v' */
+/** @def TERM_YELLOW
+ * @note 'y' (4,4,0)
+ */
+#define TERM_YELLOW 11 /* 'y' */
+/** @def TERM_L_RED
+ * @note 'R' (4,0,0)
+ */
+#define TERM_L_RED 12 /* 'R' */
+/** @def TERM_L_GREEN
+ * @note 'G' (0,4,0)
+ */
+#define TERM_L_GREEN 13 /* 'G' */
+/** @def TERM_L_BLUE
+ * @note 'B' (0,4,4)
+ */
+#define TERM_L_BLUE 14 /* 'B' */
+/** @def TERM_L_UMBER
+ * @note 'U' (3,2,1)
+ */
+#define TERM_L_UMBER 15 /* 'U' */
+/** @} */
+
+/** @name Event Hooks
+ * @{
+ */
+/** @def HOOK_MONSTER_DEATH
+ * @brief Monster dies.\n
+ * @param Number m_idx \n index of monster in monster (m_list) array.
+ * @brief Monster index
+ * @note (see file xtra2.c)
+ */
+#define HOOK_MONSTER_DEATH 0
+
+/** @def HOOK_OPEN
+ * @brief Open door or chest.\n
+ * @param Number quest \n if 0, then player is not on a quest level,
+ * otherwise the player is on a quest.
+ * @brief On quest?
+ * @note (see file cmd2.c)
+ */
+#define HOOK_OPEN 1
+
+/** @def HOOK_GEN_QUEST
+ * @brief Generate quest level.\n
+ * @param Number quest \n if 0, then player is not on a quest level,
+ * otherwise the player is on a quest.
+ * @brief On quest?
+ * @note (see file generate.c)
+ */
+#define HOOK_GEN_QUEST 2
+
+/** @def HOOK_END_TURN
+ * @brief Turn ends.\n
+ * @param Number quest \n if 0, then player is not on a quest level,
+ * otherwise the player is on a quest.
+ * @brief On quest?
+ * @note (see file dungeon.c)
+ */
+#define HOOK_END_TURN 3
+
+/** @def HOOK_FEELING
+ * @brief Display level feeling.\n
+ * @param Number quest \n if 0, then player is not on a quest level,
+ * otherwise the player is on a quest.
+ * @brief On quest?
+ * @return Boolean \n TRUE if a level feeling was displayed, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, then no other feelings are displayed and
+ * do_cmd_feeling() returns.
+ * @note (see file cmd4.c)
+ */
+#define HOOK_FEELING 4
+
+/** @def HOOK_NEW_MONSTER
+ * @brief Generate monster.\n
+ * @param Number r_idx \n index of monster in monster race (r_info) array.
+ * @brief Monster index
+ * @return Boolean \n TRUE if monster is not allowed to be created,
+ * otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, then the monster is "killed".
+ * @note (see file monster2.c)
+ */
+#define HOOK_NEW_MONSTER 5
+
+/** @def HOOK_GEN_LEVEL
+ * @brief Generate dungeon level.\n
+ * @param Number quest \n if 0, then player is not on a quest level,
+ * otherwise the player is on a quest.
+ * @brief On quest?
+ * @note (see file generate.c)
+ */
+#define HOOK_GEN_LEVEL 6
+
+/** @def HOOK_BUILD_ROOM1
+ * @brief Generate room (type 1 - normal rectangular room).\n
+ * @param Number by0 \n y-coordinate of dungeon block where room is built.
+ * @brief Block y-coordinate
+ * @param Number bx0 \n x-coordinate of dungeon block where room is built.
+ * @brief Block x-coordinate
+ * @return Boolean \n TRUE if room was created, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, then the room has been built and build_type1()
+ * returns.
+ * @note (see file generate.c)
+ */
+#define HOOK_BUILD_ROOM1 7
+
+/** @def HOOK_NEW_LEVEL
+ * @brief Start dungeon level.\n
+ * @param Number quest \n if 0, then player is not on a quest level,
+ * otherwise the player is on a quest.
+ * @brief On quest?
+ * @note (see file dungeon.c)
+ */
+#define HOOK_NEW_LEVEL 8
+
+/** @def HOOK_QUEST_FINISH
+ * @brief Quest finished.\n
+ * @param Number plot \n a plot from the plots array.
+ * @brief Plot
+ * @note (see file bldg.c)
+ */
+#define HOOK_QUEST_FINISH 9
+
+/** @def HOOK_QUEST_FAIL
+ * @brief Quest failed.\n
+ * @param Number plot \n a plot from the plots array.
+ * @brief Plot
+ * @note (see file bldg.c)
+ */
+#define HOOK_QUEST_FAIL 10
+
+/** @def HOOK_GIVE
+ * @brief Give item to monster.\n
+ * @param Number m_idx \n index of monster in monster (m_list) array.
+ * @brief Monster index
+ * @param Number item \n the item to be given.
+ * @brief Item number
+ * @return Boolean \n TRUE if item was given to monster, otherwise FALSE.
+ * @note
+ * If the hook returns FALSE, then the message "The monster does not want
+ * your item." is displayed.
+ * @note (see file cmd2.c)
+ */
+#define HOOK_GIVE 11
+
+/** @def HOOK_CHAR_DUMP
+ * @brief Add a line to the character sheet.
+ * @note (see files.c)
+ */
+#define HOOK_CHAR_DUMP 12
+
+/** @def HOOK_INIT_QUEST
+ * @brief Quest initialised.\n
+ * @param Number plot \n a plot from the plots array.
+ * @brief Plot
+ * @return Boolean \n TRUE if quest was not initialised, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, castle_quest() returns FALSE.
+ * @note (see file bldg.c)
+ */
+#define HOOK_INIT_QUEST 13
+
+/** @def HOOK_WILD_GEN
+ * @brief Generate wilderness.\n
+ * @param Number wilderness \n if TRUE, then this is overhead wilderness
+ * processing, otherwise it is regular wilderness processing.
+ * @brief Overhead?
+ * @note (see file wild.c)
+ */
+#define HOOK_WILD_GEN 14
+
+/** @def HOOK_DROP
+ * @brief Drop an item.\n
+ * @param Number item \n the item to drop.
+ * @brief Item number
+ * @return Boolean \n TRUE if item was dropped, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, do_cmd_drop() returns, otherwise the function
+ * continues.
+ * @note (see file cmd3.c)
+ */
+#define HOOK_DROP 15
+
+/** @def HOOK_IDENTIFY
+ * @brief Identfy an item.\n
+ * @param Number item \n the item to identify.
+ * @brief Item number
+ * @param String type \n "normal" to identify the item, or "full" to fully
+ * identify an item.
+ * @brief Type
+ * @note (see files spells1.c, spells2.c)
+ */
+#define HOOK_IDENTIFY 16
+
+/** @def HOOK_MOVE
+ * @brief Player moves.\n
+ * @param Number y \n the y-coordinate of the new location.
+ * @brief Y-coordinate
+ * @param Number x \n the x-coordinate of the new location.
+ * @brief X-coordinate
+ * @return Boolean \n TRUE if player is not allowed to move, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, move_player_aux() returns, otherwise the function
+ * continues.
+ * @note (see file cmd1.c)
+ */
+#define HOOK_MOVE 17
+
+/** @def HOOK_STAIR
+ * @brief Player uses stairs.\n
+ * @param String direction \n "up" if the player is going up stairs, or
+ * "down" if the player is going down stairs.
+ * @brief Direction
+ * @return Boolean \n TRUE if player is not allowed to use stairs, otherwise
+ * FALSE.
+ * @note
+ * If the hook returns TRUE, do_cmd_go_up() or do_cmd_go_down() returns,
+ * otherwise the function continues.
+ * @note (see file cmd2.c)
+ */
+#define HOOK_STAIR 18
+
+/** @def HOOK_MONSTER_AI
+ * @brief Monster moves.\n
+ * @param Number m_idx \n index of monster in monster (m_list) array.
+ * @brief Monster index
+ * @return Boolean \n TRUE if monster AI was applied, otherwise FALSE.
+ * @return Number y2 \n New y-coordinate of monster target.
+ * @return Number x2 \n New x-coordinate of monster target.
+ * @note
+ * If the hook returns TRUE, the monster moves toward the hook position.
+ * @note (see file melee2.c)
+ */
+#define HOOK_MONSTER_AI 19
+
+/** @def HOOK_PLAYER_LEVEL
+ * @brief Player gains (or loses) a level.\n
+ * @param Number gained \n the number of levels gained (or lost).
+ * @brief Levels gained
+ * @note (see file xtra2.c)
+ */
+#define HOOK_PLAYER_LEVEL 20
+
+/** @def HOOK_WIELD
+ * @brief Player wields an item.\n
+ * @param Number item \n the item to wield.
+ * @brief Item number
+ * @return Boolean \n TRUE if item was not wielded, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, do_cmd_wield() returns, otherwise the function
+ * continues.
+ * @note (see file cmd3.c)
+ */
+#define HOOK_WIELD 21
+
+/** @def HOOK_INIT
+ * @brief Game initialised.
+ * @note (see file dungeon.c)
+ */
+#define HOOK_INIT 22
+
+/** @def HOOK_QUAFF
+ * @brief Player quaffs a potion.\n
+ * @param Object o_ptr \n the potion to quaff.
+ * @brief Potion
+ * @return Boolean \n TRUE if potion was quaffed, otherwise FALSE.
+ * @return Number ident \n TRUE if the potion was identifed, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, the hook sets the "potion identified" flag.
+ * @note (see file cmd6.c)
+ */
+#define HOOK_QUAFF 23
+
+/** @def HOOK_AIM */
+#define HOOK_AIM 24
+
+/** @def HOOK_USE */
+#define HOOK_USE 25
+
+/** @def HOOK_ACTIVATE
+ * @brief Player activates an item.\n
+ * @param Number item \n the item to activate.
+ * @brief Item number
+ * @return Boolean \n TRUE if item was activated, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, do_cmd_activate() returns, otherwise the function
+ * continues.
+ * @note (see file cmd6.c)
+ */
+#define HOOK_ACTIVATE 26
+
+/** @def HOOK_ZAP
+ * @brief Player zaps a rod.\n
+ * @param Number tval \n type of rod to zap.
+ * @brief Type
+ * @param Number sval \n sub-type of rod to zap.
+ * @brief Sub-type
+ * @note (see file cmd6.c)
+ */
+#define HOOK_ZAP 27
+
+/** @def HOOK_READ
+ * @brief Player reads a scroll.\n
+ * @param Object o_ptr \n the scroll to read.
+ * @brief Scroll
+ * @return Boolean \n TRUE if scroll was read, otherwise FALSE.
+ * @return Number used_up \n TRUE if the scroll was used up, otherwise FALSE.
+ * @return Number ident \n TRUE if the scroll was identifed, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, the hook sets the "scroll used up" and
+ * "scroll identified" flags.
+ * @note (see file cmd6.c)
+ */
+#define HOOK_READ 28
+
+/** @def HOOK_CALC_BONUS
+ * @brief Calculate player "state" bonuses.
+ * @note (see xtra1.c)
+ */
+#define HOOK_CALC_BONUS 29
+
+/** @def HOOK_CALC_BONUS
+ * @brief Calculate player "state" bonuses, after all calcs are done.
+ * @note (see xtra1.c)
+ */
+#define HOOK_CALC_BONUS_END 77
+
+/** @def HOOK_CALC_POWERS
+ * @brief Calculate player powers.
+ * @note (see xtra1.c)
+ */
+#define HOOK_CALC_POWERS 30
+
+/** @def HOOK_KEYPRESS
+ * @brief User enters a command.\n
+ * @param Number command \n the pressed key (command_cmd).
+ * @brief Command
+ * @return Boolean \n TRUE if special processing was done, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, process_command() returns, otherwise the function
+ * continues.
+ * @note (see file dungeon.c)
+ */
+#define HOOK_KEYPRESS 31
+
+/** @def HOOK_CHAT
+ * @brief Player chats to monster.\n
+ * @param Number m_idx \n index of monster in monster (m_list) array.
+ * @brief Monster index
+ * @return Boolean \n TRUE if monster chats, otherwise FALSE.
+ * @note
+ * If the hook returns FALSE, the message "There is no monster there." is
+ * printed.
+ * @note (see file cmd2.c)
+ */
+#define HOOK_CHAT 32
+
+/** @def HOOK_MON_SPEAK
+ * @brief Monster speaks.\n
+ * @param Number m_idx \n index of monster in monster (m_list) array.
+ * @brief Monster index
+ * @param String m_name \n name of the monster.
+ * @brief Monster name
+ * @return Boolean \n TRUE if monster speaks, otherwise FALSE.
+ * @note
+ * If the hook returns FALSE, the monster may say something else.
+ * @note (see file melee2.c)
+ */
+#define HOOK_MON_SPEAK 33
+
+/** @def HOOK_MKEY
+ * @brief Player uses skill.\n
+ * @param Number x_idx \n the skill to execute.
+ * @brief Skill index
+ * @note (see file skills.c)
+ */
+#define HOOK_MKEY 34
+
+/** @def HOOK_BIRTH_OBJECTS
+ * @brief Player receives objects at birth.
+ * @note (see file birth.c)
+ */
+#define HOOK_BIRTH_OBJECTS 35
+
+/** @def HOOK_ACTIVATE_DESC
+ * @brief Display activation description.\n
+ * @param Object o_ptr \n the item to activate.
+ * @brief Object
+ * @return Boolean \n TRUE if item has an activation, otherwise FALSE.
+ * @return String desc \n the activation description.
+ * @note
+ * If the hook returns TRUE, item_activation() returns the hook's activation
+ * description.
+ * @note (see file object1.c)
+ */
+#define HOOK_ACTIVATE_DESC 36
+
+/** @def HOOK_INIT_GAME
+ * @brief Game initialised.\n
+ * @param String when \n "begin" if done at the start of game initialisation,
+ * or "end" if done at end of game initialisation.
+ * @brief When?
+ * @note (see file init2.c)
+ */
+#define HOOK_INIT_GAME 37
+
+/** @def HOOK_ACTIVATE_POWER
+ * @brief Player activates a power.\n
+ * @param Number power \n the power to activate.
+ * @brief Power
+ * @return Boolean \n TRUE if power was activated, otherwise FALSE.
+ * @note
+ * If the hook returns FALSE, power_activate() displays the message
+ * "Warning power_activate() called with invalid power(xx)." where
+ * xx = power.
+ * @note (see file powers.c)
+ */
+#define HOOK_ACTIVATE_POWER 38
+
+/** @def HOOK_ITEM_NAME
+ * @brief Get an item name.\n
+ * @param Object o_ptr \n the item whose name is required.
+ * @brief Object
+ * @return Boolean \n TRUE if name was found, otherwise FALSE.
+ * @return String basenm \n The item name.
+ * @return String modstr \n The item modifier string.
+ * @note (see file object1.c)
+ */
+#define HOOK_ITEM_NAME 39
+
+/** @def HOOK_SAVE_GAME
+ * @brief Save the game.
+ * @note (see file loadsave.c)
+ */
+#define HOOK_SAVE_GAME 40
+
+/** @def HOOK_LOAD_GAME
+ * @brief Load the game.
+ * @note (see file loadsave.c)
+ */
+#define HOOK_LOAD_GAME 41
+
+/** @def HOOK_LEVEL_REGEN
+ * @brief Start generation of a special level.
+ * @note (see file generate.c)
+ */
+#define HOOK_LEVEL_REGEN 42
+
+/** @def HOOK_LEVEL_END_GEN
+ * @brief End generation of a special level.
+ * @note (see file generate.c)
+ */
+#define HOOK_LEVEL_END_GEN 43
+
+/** @def HOOK_BUILDING_ACTION
+ * @brief Player performs an action in a building.\n
+ * @param Number action \n the action performed in the building
+ * @brief Action flag
+ * @return Boolean \n TRUE if player performed the action, otherwise FALSE.
+ * @return Number paid \n TRUE if player paid to perform the action, otherwise
+ * FALSE.
+ * @return Number recreate \n TRUE if something is recreated, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, the hook sets the "paid" and "recreate" flags.
+ * @note (see file bldg.c)
+ */
+#define HOOK_BUILDING_ACTION 44
+
+/** @def HOOK_PROCESS_WORLD
+ * @brief Update world every ten turns.
+ * @note (see file dungeon.c)
+ */
+#define HOOK_PROCESS_WORLD 45
+
+/** @def HOOK_WIELD_SLOT
+ * @brief Find equipment slot for object.\n
+ * @param Object o_ptr \n the object to wield.
+ * @brief Object
+ * @param Number ideal \n TRUE if current body and stuff is ignore, otherwise
+ * FALSE.
+ * @return Boolean \n TRUE if hook processed the object, otherwise FALSE.
+ * @return Number slot \n The equipent slot where the object will go (-1 if
+ * there are no available slots).
+ * @note
+ * If the hook returns TRUE, wield_slot_ideal() returns the slot from the hook.
+ * @note (see file objects1.c)
+ */
+#define HOOK_WIELD_SLOT 46
+
+/** @def HOOK_STORE_STOCK
+ * @brief Stock a store.\n
+ * @param Number st_idx \n the index of the store in st_info array.
+ * @brief Store index
+ * @param String name \n the name of the store.
+ * @brief Store name
+ * @param Number level \n the "dungeon level" of the store.
+ * @brief Store level
+ * @return Boolean \n TRUE if hook has selected an object, otherwise FALSE.
+ * @return Object q_ptr \n The item to be stocked in the store.
+ * @note
+ * If the hook returns TRUE, store_create() will create the hook's object and
+ * put it in the store.
+ * @note (see file store.c)
+ */
+#define HOOK_STORE_STOCK 47
+
+/** @def HOOK_STORE_BUY
+ * @brief Store buys an item.\n
+ * @param Number st_idx \n the index of the store in st_info array.
+ * @brief Store index
+ * @param String name \n the name of the store.
+ * @brief Store name
+ * @param Object o_ptr \n the object to buy.
+ * @brief Object
+ * @return Boolean \n TRUE if the hook has processed the object, otherwise
+ * FALSE.
+ * @return Number buy \n TRUE if the store will buy the object, otherwise
+ * FALSE.
+ * @note
+ * If the hook returns TRUE, store_will_buy() will return "buy".
+ * @note (see file store.c)
+ */
+#define HOOK_STORE_BUY 48
+
+/** @def HOOK_GEN_LEVEL_BEGIN
+ * @brief Generate a random dungeon level.
+ * @note (see file generate.c)
+ */
+#define HOOK_GEN_LEVEL_BEGIN 49
+
+/** @def HOOK_GET
+ * @brief Player gets an object.\n
+ * @param Object o_ptr \n the object to get.
+ * @brief Object
+ * @param Number o_idx \n the index of the object in o_list array.
+ * @brief Object index
+ * @return Boolean \n TRUE if hooks processes the object, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, object_pickup() returns, otherwise the function
+ * continues.
+ * @note (see object1.c)
+ */
+#define HOOK_GET 50
+
+/** @def HOOK_REDRAW
+ * @brief Redraw the screen.
+ * @note (see file xtra1.c)
+ */
+#define HOOK_REDRAW 51
+
+/** @def HOOK_RECALC_SKILLS
+ * @brief Recalculate player skills.
+ * @note (see skills.c)
+ */
+#define HOOK_RECALC_SKILLS 52
+
+/** @def HOOK_ENTER_DUNGEON
+ * @brief Player goes down one dungeon level.\n
+ * @param Number special \n special information for player's dungeon grid.
+ * @brief Special info
+ * @return Boolean \n TRUE if the hook prevents the player going down,
+ * otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, the player remains on the current dungeon level
+ * and do_cmd_go_down() returns.
+ * @note (see file cmd2.c)
+ */
+#define HOOK_ENTER_DUNGEON 53
+
+/** @def HOOK_FIRE
+ * @brief Player fires an object (bow slot of inventory).\n
+ * @param Object \n the object to fire.
+ * @brief Object
+ * @return Boolean \n TRUE if the hook has fired the object, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, process_command() returns.
+ * @note (see file dungeon.c)
+ */
+#define HOOK_FIRE 54
+
+/** @def HOOK_EAT
+ * @brief Player eats.\n
+ * @param Object o_ptr \n the object the player eats.
+ * @brief Object
+ * @return Boolean \n TRUE if hook processes the object, otherwise FALSE.
+ * @return Number ident \n TRUE if the object was identified, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, the hook sets the "food identified" flag.
+ * @note (see file cmd6.c)
+ */
+#define HOOK_EAT 55
+
+/** @def HOOK_DIE
+ * @brief Player dies.
+ * @return Boolean \n TRUE if player does not die, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, the player cheats death.
+ * @note (see file dungeon.c)
+ */
+#define HOOK_DIE 56
+
+/** @def HOOK_CALC_HP
+ * @brief Recalculate player HP (hit points).\n
+ * @param Number mhp \n the player's new maximum hit points.
+ * @brief Maximum hit points.
+ * @return Boolean \n TRUE if hook has processed player hit points, otherwise
+ * FALSE.
+ * @note
+ * If the hook returns TRUE, the player's maximum hit points are updated.
+ * @note (see file xtra1.c)
+ */
+#define HOOK_CALC_HP 57
+
+/** @def HOOK_GF_COLOR
+ * @brief Set color for spell.
+ * @param Number type \n type of spell.
+ * @brief Type
+ * @param Number file \n if this is 0 use ANGBAND_GRAF, otherwise use "new".
+ * @brief File
+ * @return Boolean \n TRUE if hook sets a color, otherwise FALSE.
+ * @return Number color \n The color for the spell.
+ * @note
+ * If the hook returns TRUE, spell_color() returns the hook's color, otherwise
+ * the function continues.
+ * @note (see file spells1.c)
+ */
+#define HOOK_GF_COLOR 58
+
+/** @def HOOK_GF_EXEC
+ * @brief A spell to damage terrain features.\n
+ * @param String target \n "grid" to indicate spell damages terrain.
+ * @brief Target
+ * @param Number who \n the source of the spell.
+ * @brief Source
+ * @param Number type \n the type of spell.
+ * @brief Type
+ * @param Number dam \n the number of hit points of damage.
+ * @brief Damage
+ * @param Number r \n the radius of the spell.
+ * @brief Radius
+ * @param Number y \n the y-coordinate of the target.
+ * @brief Y-coordinate
+ * @param Number x \n the x-coordinate of the target.
+ * @brief X-coordinate
+ * @return Boolean \n TRUE if spell was cast, otherwise FALSE.
+ * @return Number obvious \n TRUE if the player notices the spell, otherwise
+ * FALSE.
+ * @return Number flag \n TRUE if the player is affected, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, the hook sets the "obvious" and "flag" fields.
+ * @note (see file spells1.c)
+ */
+/** @def HOOK_GF_EXEC
+ * @brief A spell to damage objects.\n
+ * @param String target \n "object" to indicate spell damages objects.
+ * @brief Target
+ * @param Number who \n the source of the spell.
+ * @brief Source
+ * @param Number type \n the type of spell.
+ * @brief Type
+ * @param Number dam \n the number of hit points of damage.
+ * @brief Damage
+ * @param Number r \n the radius of the spell.
+ * @brief Radius
+ * @param Number y \n the y-coordinate of the target.
+ * @brief Y-coordinate
+ * @param Number x \n the x-coordinate of the target.
+ * @brief X-coordinate
+ * @param Object o_ptr \n the object which is the target of the spell.
+ * @brief Object
+ * @return Boolean \n TRUE if spell was cast, otherwise FALSE.
+ * @return Number obvious \n TRUE if the player notices the spell, otherwise
+ * FALSE.
+ * @return Number flag \n TRUE if the player is affected, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, the hook sets the "obvious" and "do_kill" fields.
+ * @note (see file spells1.c)
+ */
+/** @def HOOK_GF_EXEC
+ * @brief A spell to damage monsters.\n
+ * @param String target \n "angry" to indicate spell angers a friend.
+ * @brief Target
+ * @param Number who \n the source of the spell.
+ * @brief Source
+ * @param Number type \n the type of spell.
+ * @brief Type
+ * @param Number dam \n the number of hit points of damage.
+ * @brief Damage
+ * @param Number r \n the radius of the spell.
+ * @brief Radius
+ * @param Number y \n the y-coordinate of the target.
+ * @brief Y-coordinate
+ * @param Number x \n the x-coordinate of the target.
+ * @brief X-coordinate
+ * @param Monster m_ptr \n the monster which is the target of the spell.
+ * @brief Monster
+ * @return Boolean \n TRUE if spell was cast, otherwise FALSE.
+ * @return Number get_angry \n TRUE if the monster gets angry, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, the hook sets the "get_angry" field.
+ * @note (see file spells1.c)
+ */
+/** @def HOOK_GF_EXEC
+ * @brief A spell to damage monsters.\n
+ * @param String target \n "monster" to indicate spell damages monsters.
+ * @brief Target
+ * @param Number who \n the source of the spell.
+ * @brief Source
+ * @param Number type \n the type of spell.
+ * @brief Type
+ * @param Number dam \n the number of hit points of damage.
+ * @brief Damage
+ * @param Number r \n the radius of the spell.
+ * @brief Radius
+ * @param Number y \n the y-coordinate of the target.
+ * @brief Y-coordinate
+ * @param Number x \n the x-coordinate of the target.
+ * @brief X-coordinate
+ * @param Monster m_ptr \n the monster which is the target of the spell.
+ * @brief Monster
+ * @return Boolean \n TRUE if spell was cast, otherwise FALSE.
+ * @return Number obvious \n TRUE if the player notices the spell, otherwise
+ * FALSE.
+ * @return Number dam \n The damage the monster takes.
+ * @return Number do_stun \n TRUE if the monster is stunned, otherwise FALSE.
+ * @return Number do_fear \n TRUE if the monster is frightened, otherwise
+ * FALSE.
+ * @return Number do_conf \n TRUE if the monster is confused, otherwise FALSE.
+ * @return Number do_dist \n TRUE if the monster is disturbed, otherwise FALSE.
+ * @return Number do_pois \n TRUE if the monster is poisoned, otherwise FALSE.
+ * @return Number do_cut \n TRUE if the monster is wounded, otherwise FALSE.
+ * @return Number do_poly \n TRUE if the monster is polymorphed, otherwise
+ * FALSE.
+ * @return String note \n The message displayed if the monster if affected.
+ * @return String note_dies \n The message displayed if the monster dies.
+ * @note
+ * If the hook returns TRUE, the hook sets the "obvious", "dam", "do_stun",
+ * "do_fear", "do_conf", "do_dist", "do_pois", "do_cut", "do_poly", "note",
+ * and "note dies" fields, otherwise the spell has no effect and does no
+ * damage.
+ * @note (see file spells1.c)
+ */
+/** @def HOOK_GF_EXEC
+ * @brief A spell to damage the player.\n
+ * @param String target \n "player" to indicate spell damages the player.
+ * @brief Target
+ * @param Number who \n the source of the spell.
+ * @brief Source
+ * @param Number type \n the type of spell.
+ * @brief Type
+ * @param Number dam \n the number of hit points of damage.
+ * @brief Damage
+ * @param Number r \n the radius of the spell.
+ * @brief Radius
+ * @param Number y \n the y-coordinate of the target.
+ * @brief Y-coordinate
+ * @param Number x \n the x-coordinate of the target.
+ * @brief X-coordinate
+ * @return Boolean \n TRUE if spell was cast, otherwise FALSE.
+ * @return Number obvious \n TRUE if the player notices the spell, otherwise
+ * FALSE.
+ * @return Number dam \n The damage the player takes.
+ * @note
+ * If the hook returns TRUE, the hook sets the "obvious" and "dam" fields,
+ * otherwise there is no damage.
+ * @note (see file spells1.c)
+ */
+#define HOOK_GF_EXEC 59
+
+/** @def HOOK_CALC_MANA
+ * @brief Recalculate player SP (spell points).\n
+ * @param Number msp \n the player's new maximum spell points.
+ * @brief Maximum spell points.
+ * @return Boolean \n TRUE if hook has processed player spell points, otherwise
+ * FALSE.
+ * @note
+ * If the hook returns TRUE, the player's maximum spell points are updated.
+ * @note (see file xtra1.c)
+ */
+#define HOOK_CALC_MANA 60
+
+/** @def HOOK_LOAD_END
+ * @brief Load a savefile.\n
+ * @param Number death \n TRUE if the character is dead, otherwise FALSE.
+ * @brief Dead character?
+ * @return Boolean \n TRUE if hook has processed savefile, otherwise FALSE.
+ * @return Number death \n
+ * @note
+ * If the hook returns TRUE, then "character_loaded" (real living player) is
+ * set to TRUE. The player has been revived.
+ * @note (see file loadsave.c)
+ */
+#define HOOK_LOAD_END 61
+
+/** @def HOOK_RECALL
+ * @brief Player recalls from/to dungeon/town.
+ * @return Boolean \n TRUE if player is not allowed to recall, otherwise
+ * FALSE.
+ * @note (see file dungeon.c)
+ */
+#define HOOK_RECALL 62
+
+/** @def HOOK_FOLLOW_GOD
+ * @brief Player follows a god (gets religion).\n
+ * @param Number god \n the god to follow.
+ * @brief God
+ * @param String action \n "ask" to check if player can follow the god, or
+ * "done" to do something with the god.
+ * @brief Action
+ * @return Boolean \n For "ask": TRUE if player can not follow the god,
+ * otherwise FALSE.
+ * @note
+ * If the action is "ask" and the hook returns TRUE, follow_god() returns.
+ * If the action is "done" the return code is ignored.
+ * @note (see file gods.c)
+ */
+#define HOOK_FOLLOW_GOD 63
+
+/** @def HOOK_SACRIFICE_GOD
+ * @brief Player sacrifices to a god.
+ * @note (see file cmd2.c)
+ */
+#define HOOK_SACRIFICE_GOD 64
+
+/** @def HOOK_BODY_PARTS
+ * @brief Calculate which body parts the player has.
+ * @note (see file xtra1.c)
+ */
+#define HOOK_BODY_PARTS 65
+
+/** @def HOOK_APPLY_MAGIC
+ * @brief Apply magic to an item.\n
+ * @param Object o_ptr \n the item to which magic is applied
+ * @brief Object
+ * @param Number level \n the level of the object
+ * @brief Object level
+ * @param Number power \n the power of the object (0 = normal, 1 = good,
+ * 2 = great, -1 = cursed, -2 = broken)
+ * @brief Power
+ * @return Boolean \n TRUE if hook has applied magic, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, a_m_aux_n() (where n=1 to 4) returns.
+ * @note (see file object2.c)
+ */
+#define HOOK_APPLY_MAGIC 66
+
+/** @def HOOK_PLAYER_EXP
+ * @brief Player gains/loses experience points (XP).\n
+ * @param Number amount \n the number of experience points to gain/lose
+ * @brief Points
+ * @note (see file xtra2.c)
+ */
+#define HOOK_PLAYER_EXP 67
+
+/** @def HOOK_BIRTH
+ * @brief Player is born.
+ * @note (see file birth.c)
+ */
+#define HOOK_BIRTH 68
+
+/** @def HOOK_CALC_LITE
+ * @brief Calculate the lite radius.
+ * @note (see file xtra1.c)
+ */
+#define HOOK_CALC_LITE 69
+
+/** @def HOOK_LEARN_ABILITY
+ * @brief Player learns an ability.\n
+ * @param Number ab \n index of ability in ability (ab_info) array.
+ * @brief Ability index
+ * @return Boolean \n TRUE if player is not to gain the ability, otherwise
+ * FALSE.
+ * @note If the hook returns TRUE, can_learn_ability() returns FALSE.
+ * @note (see file skills.c)
+ */
+#define HOOK_LEARN_ABILITY 70
+
+/** @def HOOK_MOVED
+ * @brief Player finishes moving.
+ * @note (see file cmd1.c)
+ */
+#define HOOK_MOVED 71
+
+/** @def HOOK_GAME_START
+ * @brief Game begins.
+ * @note (see file dungeon.c)
+ */
+#define HOOK_GAME_START 72
+
+/** @def HOOK_TAKEOFF
+ * @brief Player takes off an item.\n
+ * @param Number item \n the item to take off.
+ * @brief Item
+ * @return Booelan \n TRUE if item can not be taken off, otherwise FALSE.
+ * @note
+ * If the hook returns TRUE, do_cmd_takeoff() returns.
+ * @note (see file cmd3.c)
+ */
+#define HOOK_TAKEOFF 73
+
+/** @def HOOK_CALC_WEIGHT
+ * @brief Calculate player weight limit.\n
+ * @param Number weight \n the current weight limit.
+ * @brief Weight
+ * @return Boolean \n TRUE if weight was processed, otherwise FALSE.
+ * @return Number weight \n The new maximum weight.
+ * @note
+ * If the hook returns TRUE, weight_limit() returns the hook's weight.
+ * @note (see file xtra1.c)
+ */
+#define HOOK_CALC_WEIGHT 74
+
+/** @def HOOK_FORBID_TRAVEL
+ * @brief Check if the player may press < and travel.\n
+ * @return Boolean \n TRUE if travel is forbidden, otherwise FALSE.
+ */
+#define HOOK_FORBID_TRAVEL 75
+
+/** @def HOOK_DEBUG_COMMAND
+ * @brief User enters a debug command.\n
+ * @param Number command \n the pressed key (cmd).
+ * @brief Command
+ * @return Boolean \n TRUE if special processing was done, otherwise FALSE.
+ */
+#define HOOK_DEBUG_COMMAND 76
+
+
+/** @} */
+
+
+/** @var turn
+ * @brief Number
+ * @note Current game turn
+ */
+extern s32b turn;
+/** @var old_turn
+ * @brief Number
+ * @note Turn when level began (feelings)
+ */
+extern s32b old_turn;
+/** @var cur_wid
+ * @brief Number
+ * @note Current dungeon width
+ */
+extern s16b cur_wid;
+/** @var cur_hgt
+ * @brief Number
+ * @note Current dungeon height
+ */
+extern s16b cur_hgt;
+
+/** @fn disturb(int stop_search, int flush_output)
+ * @brief Disturb the player.\n
+ * @param stop_search Number \n if 0, this will not disturb searching,
+ * otherwise searching is stopped.
+ * @brief Stop search?
+ * @param flush_output Number \n *unused*
+ * @brief *Unused*
+ * @note
+ * Something has happened to disturb the player.\n\n
+ * The first arg indicates a major disturbance, which affects search.\n
+ * The second arg is currently unused, but could induce output flush.\n\n
+ * All disturbance cancels repeated commands, resting, and running.
+ * @note (see file cave.c)
+ */
+extern void disturb(int stop_search, int flush_output);
+
+/** @fn bst(s32b what, s32b t)
+ * @brief Break scalar time.\n
+ * @param what Number \n the unit time "t" is to be broken into. The following
+ * values can be used: MINUTE, HOUR, DAY, YEAR
+ * @brief Unit of time
+ * @param t Number \n the time to be broken.
+ * @brief Time
+ * @return Number \n The number of unit in time "t".
+ * @note (see file util.c)
+ */
+extern s32b bst(s32b what, s32b t);
+
+$static char *path_build_lua(cptr path, cptr file){static char buf[1025]; path_build(buf, 1024, path, file); return buf;}
+
+/** @fn path_build(cptr path, cptr file);
+ * @brief Create a new path by appending a file (or directory) to a path.\n
+ * @param path String \n the original path.
+ * @brief Path
+ * @param file String \n the file or directory to append to the path.
+ * @brief File or directory
+ * @return String \n The new path.
+ * @note
+ * This requires no special processing on simple machines, except
+ * for verifying the size of the filename, but note the ability to
+ * bypass the given "path" with certain special file-names.\n\n
+ * Note that the "file" may actually be a "sub-path", including
+ * a path and a file.\n\n
+ * @note (see file util.c)
+ */
+static char *path_build_lua@path_build(cptr path, cptr file);
+
+/** @fn move_cursor(int row, int col)
+ * @brief Move the cursor of a terminal to row "row" and column "col".\n
+ * @param row Number \n the target row on the screen.
+ * @brief Row
+ * @param col Number \n the target column on the screen.
+ * @brief Column
+ * @note (see file util.c)
+ */
+extern void move_cursor(int row, int col);
+
+/** @fn flush(void)
+ * @brief Flush all input chars.
+ * @note
+ * Actually, remember the flush, and do a "special flush" before the next
+ * "inkey()".
+ * This is not only more efficient, but also necessary to make sure
+ * that various "inkey()" codes are not "lost" along the way.
+ * @note (see file util.c)
+ */
+extern void flush(void);
+
+/** @var inkey_scan
+ * @brief Boolean
+ * @note
+ * If "inkey_scan" is TRUE, then we will immediately return "zero" if no
+ * keypress is available, instead of waiting for a keypress.
+ */
+extern bool inkey_scan;
+
+/** @fn inkey(void)
+ * @brief Get a keypress from the user.
+ * @return String \n the key pressed by the user.
+ * @note
+ * This function recognizes a few "global parameters". These are variables
+ * which, if set to TRUE before calling this function, will have an effect
+ * on this function, and which are always reset to FALSE by this function
+ * before this function returns. Thus they function just like normal
+ * parameters, except that most calls to this function can ignore
+ * them.\n\n
+ * If "inkey_xtra" is TRUE, then all pending keypresses will be flushed,
+ * and any macro processing in progress will be aborted. This flag is
+ * set by the "flush()" function, which does not actually flush anything
+ * itself, but rather, triggers delayed input flushing via
+ * "inkey_xtra".\n\n
+ * If "inkey_scan" is TRUE, then we will immediately return "zero" if no
+ * keypress is available, instead of waiting for a
+ * keypress.\n\n
+ * If "inkey_base" is TRUE, then all macro processing will be bypassed.
+ * If "inkey_base" and "inkey_scan" are both TRUE, then this function will
+ * not return immediately, but will wait for a keypress for as long as the
+ * normal macro matching code would, allowing the direct entry of macro
+ * triggers. The "inkey_base" flag is extremely
+ * dangerous!\n\n
+ * If "inkey_flag" is TRUE, then we will assume that we are waiting for a
+ * normal command, and we will only show the cursor if "hilite_player" is
+ * TRUE (or if the player is in a store), instead of always showing the
+ * cursor. The various "main-xxx.c" files should avoid saving the game
+ * in response to a "menu item" request unless "inkey_flag" is TRUE, to
+ * prevent savefile
+ * corruption.\n\n
+ * If we are waiting for a keypress, and no keypress is ready, then we will
+ * refresh (once) the window which was active when this function was
+ * called.\n\n
+ * Note that "back-quote" is automatically converted into "escape" for
+ * convenience on machines with no "escape" key. This is done after the
+ * macro matching, so the user can still make a macro for
+ * "backquote".\n\n
+ * Note the special handling of "ascii 30" (ctrl-caret, aka ctrl-shift-six)
+ * and "ascii 31" (ctrl-underscore, aka ctrl-shift-minus), which are used to
+ * provide support for simple keyboard "macros". These keys are so strange
+ * that their loss as normal keys will probably be noticed by nobody. The
+ * "ascii 30" key is used to indicate the "end" of a macro action, which
+ * allows recursive macros to be avoided. The "ascii 31" key is used by
+ * some of the "main-xxx.c" files to introduce macro trigger
+ * sequences.\n\n
+ * Hack -- we use "ascii 29" (ctrl-right-bracket) as a special "magic" key,
+ * which can be used to give a variety of "sub-commands" which can be used
+ * any time. These sub-commands could include commands to take a picture of
+ * the current screen, to start/stop recording a macro action,
+ * etc.\n\n
+ * If "angband_term[0]" is not active, we will make it active during this
+ * function, so that the various "main-xxx.c" files can assume that input
+ * is only requested (via "Term_inkey()") when "angband_term[0]" is
+ * active.\n\n
+ * Mega-Hack -- This function is used as the entry point for clearing the
+ * "signal_count" variable, and of the "character_saved"
+ * variable.\n\n
+ * Hack -- Note the use of "inkey_next" to allow "keymaps" to be
+ * processed.\n\n
+ * Mega-Hack -- Note the use of "inkey_hack" to allow the "Borg" to steal
+ * control of the keyboard from the user.
+ * @note (see file util.c)
+ */
+extern char inkey(void);
+
+/** @fn cmsg_print(byte color, cptr msg)
+ * @brief Output message "msg" in colour "color" to the top line of the
+ * screen.\n
+ * @param color Number \n the colour of the message (see TERM_ fields).
+ * @brief Colour
+ * @param msg String \n the message.
+ * @brief Message
+ * @note
+ * Break long messages into multiple pieces (40-72 chars).\n\n
+ * Allow multiple short messages to "share" the top line.\n\n
+ * Prompt the user to make sure he has a chance to read them.\n\n
+ * These messages are memorized for later reference (see above).\n\n
+ * We could do "Term_fresh()" to provide "flicker" if needed.\n\n
+ * The global "msg_flag" variable can be cleared to tell us to
+ * "erase" any "pending" messages still on the
+ * screen.\n\n
+ * XXX XXX XXX Note that we must be very careful about using the
+ * "msg_print()" functions without explicitly calling the special
+ * "msg_print(NULL)" function, since this may result in the loss
+ * of information if the screen is cleared, or if anything is
+ * displayed on the top
+ * line.\n\n
+ * XXX XXX XXX Note that "msg_print(NULL)" will clear the top line
+ * even if no messages are pending. This is probably a hack.
+ * @note (see file util.c)
+ */
+extern void cmsg_print(byte color, cptr msg);
+
+/** @fn msg_print(cptr msg)
+ * @brief Output message "msg" in white to the top line of the screen.\n
+ * @param msg String \n the message.
+ * @brief Message
+ * @note (see file util.c)
+ */
+extern void msg_print(cptr msg);
+
+/** @fn screen_save(void)
+ * @brief Save the screen.
+ * @note
+ * Increase the "icky" depth.\n\n
+ * This function must match exactly one call to "screen_load()".
+ * @note (see file util.c)
+ */
+extern void screen_save(void);
+
+/** @fn screen_load(void)
+ * @brief Load the screen.
+ * @note
+ * Decrease the "icky" depth.\n\n
+ * This function must match exactly one call to "screen_save()".
+ * @note (see file util.c)
+ */
+extern void screen_load(void);
+
+/** @fn Term_save(void)
+ * @brief Save the "requested" screen into the "memorized" screen.
+ * @return Number \n 0 (always).
+ * @note
+ * Every "Term_save()" should match exactly one "Term_load()"
+ * @note (see file z-term.c)
+ */
+extern errr Term_save(void);
+
+/** @fn Term_load(void)
+ * @brief Restore the "requested" contents from the "memorized" screen.
+ * @return Number \n 0 (always).
+ * @note
+ * Every "Term_save()" should match exactly one "Term_load()"
+ * @note (see file z-term.c)
+ */
+extern errr Term_load(void);
+
+/** @fn c_put_str(byte attr, cptr str, int row, int col)
+ * @brief Add string "str" with attributes "attr" to screen at row "row"
+ * and column "col".\n
+ * @param attr Number \n the attribute of the string
+ * @brief Attribute
+ * @param str String \n the string
+ * @brief String
+ * @param row Number \n the target row on the screen.
+ * @brief Row
+ * @param col Number \n the target column on the screen.
+ * @brief Column
+ * @note
+ * Display a string on the screen using an attribute.\n\n
+ * At the given location, using the given attribute, if allowed,
+ * add the given string. Do not clear the line.
+ * @note (see file util.c)
+ */
+extern void c_put_str(byte attr, cptr str, int row, int col);
+
+/** @fn c_prt(byte attr, cptr str, int row, int col)
+ * @brief Add string "str" with attributes "attr" to screen at row "row"
+ * and column "col", clearing to the end of the row.\n
+ * @param attr Number \n the attribute of the string
+ * @brief Attribute
+ * @param str String \n the string
+ * @brief String
+ * @param row Number \n the target row on the screen.
+ * @brief Row
+ * @param col Number \n the target column on the screen.
+ * @brief Column
+ * @note (see file util.c)
+ */
+extern void c_prt(byte attr, cptr str, int row, int col);
+
+/** @fn prt(cptr str, int row, int col)
+ * @brief Add white string "str" to screen at row "row" and column "col",
+ * clearing to the end of the row.\n
+ * @param str String \n the string
+ * @brief String
+ * @param row Number \n the target row on the screen.
+ * @brief Row
+ * @param col Number \n the target column on the screen.
+ * @brief Column
+ * @note (see file util.c)
+ */
+extern void prt(cptr str, int row, int col);
+
+/** @fn message_add(byte type, cptr msg, byte color)
+ * @brief Add a message "msg" of type "type" and colour "color" to the
+ * message array.\n
+ * @param type Number \n the type of message. MESSAGE_MSG for regular
+ * messages.
+ * @brief Type
+ * @param msg String \n the message.
+ * @brief Message
+ * @param color Number \n the colour of the message (see TERM_ fields).
+ * @brief Colour
+ * @note
+ * Use "msg_print() instead. If you insist on using this function, be
+ * careful.
+ * @note (see file util.c)
+ */
+extern void message_add(byte type, cptr msg, byte color);
+
+/** @fn display_message(int x, int y, int split, byte color, cptr t)
+ * @brief Display a message.\n
+ * @param x Number \n the x-coordinate of the screen where the message starts.
+ * @brief X-coordinate
+ * @param y Number \n the y-coordinate of the screen where the message starts.
+ * @brief Y-coordinate
+ * @param split Number \n the position in the message where it is split. The
+ * rest of the message will not appear.
+ * @brief Split position
+ * @param color Number \n the colour of the message (see TERM_ fields).
+ * @brief Colour
+ * @param t String \n the message.
+ * @brief Message
+ * @note
+ * @note (see file util.c)
+ */
+extern void display_message(int x, int y, int split, byte color, cptr t);
+
+/** @fn clear_from(int row)
+ * @brief Clear part of the screen.\n
+ * @param row Number \n the target row on the screen.
+ * @brief Row
+ * @note
+ * Clear all rows from the starting row to the end of the screen.
+ * @note (see file util.c)
+ */
+extern void clear_from(int row);
+
+/** @fn askfor_aux(char *buf, int len)
+ * @brief Get some input at the cursor location.\n
+ * @param *buf String \n Default string (optional).
+ * @brief String
+ * @param len Number \n the maximum length of the string.
+ * @brief Length of string
+ * @return Boolean \n TRUE if string was entered, otherwise FALSE.
+ * @return *buf \n The entered string.
+ * @note
+ * Assume the buffer is initialized to a default string.\n
+ * Note that this string is often "empty" (see below).\n
+ * The default buffer is displayed in yellow until cleared.\n
+ * Pressing RETURN right away accepts the default entry.\n
+ * Normal chars clear the default and append the char.\n
+ * Backspace clears the default or deletes the final char.\n
+ * ESCAPE clears the buffer and the window and returns FALSE.\n
+ * RETURN accepts the current buffer contents and returns TRUE.
+ * @note (see file util.c)
+ */
+extern bool askfor_aux(char *buf, int len);
+
+/** @fn get_string(cptr prompt, char *buf, int len)
+ * @brief Get a string from the user.\n
+ * @param prompt String \n the prompt, which should take the form "Prompt: "
+ * @brief Prompt
+ * @param *buf String
+ * @brief String
+ * @param len Number \n the maximum length of the string.
+ * @brief Length of string
+ * @return Boolean \n TRUE if string was entered, otherwise FALSE.
+ * @return *buf \n The entered string.
+ * @note
+ * Note that the initial contents of the string is used as
+ * the default response, so be sure to "clear" it if needed.\n\n
+ * We clear the input, and return FALSE, on "ESCAPE".
+ * @note (see file util.c)
+ */
+extern bool get_string(cptr prompt, char *buf, int len);
+
+/** @fn get_check(cptr prompt)
+ * @brief Verify something with the user.\n
+ * @param prompt String \n the prompt, which should take the form "Query? "
+ * @brief Prompt
+ * @return Boolean \n TRUE if "y" or "Y" is entered, otherwise FALSE.
+ * @note
+ * Note that "[y/n]" is appended to the prompt.
+ * @note (see file util.c)
+ */
+extern bool get_check(cptr prompt);
+
+/** @fn get_com(cptr promtp, int *com = 0);
+ * @brief Prompts for a keypress.\n
+ * @param promtp String \n the prompt, which should take the form "Command: "
+ * @brief Prompt
+ * @param *com Number
+ * @brief Command
+ * @return Boolean \n FALSE if "Escape" was pressed, otherwise TRUE.
+ * @return *com \n The entered command.
+ * @note (see file util.c)
+ */
+extern bool get_com_lua @ get_com(cptr promtp, int *com = 0);
+
+/** @fn get_quantity(cptr prompt, s32b max)
+ * @brief Request a "quantity" from the user.\n
+ * @param prompt String \n the prompt
+ * @brief Prompt
+ * @param max Number \n the maximum quantity
+ * @brief Maximum quantity
+ * @return Number \n the returned quantity.
+ * @note
+ * Hack -- allow "command_arg" to specify a quantity\n\n
+ * The quantity is in the range 0 to "max" inclusive. The default is 1. A
+ * letter means the maximum.
+ * @note (see file util.c)
+ */
+extern s32b get_quantity(cptr prompt, s32b max);
+
+/** @fn test_monster_name(cptr name)
+ * @brief Given monster name as string, return the index in r_info array.\n
+ * @param name String \n the monster name.
+ * @brief Monster name
+ * @return Number \n The index of the monster in r_info[], or 0 if the name
+ * does not match a monster.
+ * @note
+ * Name must exactly match (look out for commas and the like!), or else 0 is
+ * returned. Case doesn't matter.
+ * @note (see file util.c)
+ */
+extern int test_monster_name(cptr name);
+
+/** @fn test_item_name(cptr name)
+ * @brief Given item name as string, return the index in k_info array.\n
+ * @param name String \n the item name.
+ * @brief Item name
+ * @return Number \n The index of the item in k_info[], or 0 if the name
+ * does not match an item.
+ * @note
+ * Name must exactly match (look out for commas and the like!), or else 0 is
+ * returned. Case doesn't matter.
+ * @note (see file util.c)
+ */
+extern int test_item_name(cptr name);
+
+/** @fn luck(int min, int max)
+ * @brief Return a luck number between a certain range.\n
+ * @param min Number \n the minimum luck value returned.
+ * @brief Mimimum
+ * @param max Number \n the maximum luck value returned.
+ * @brief Maximum
+ * @return Number \n The scaled value of player's luck.
+ * @note
+ * Player lucked is cap at a minimum of -30 and maximum of +30 before it is
+ * scaled to the range defined by "min" and "max".
+ * @note (see file xtra1.c)
+ */
+extern int luck(int min, int max);
+
+/** @fn get_player_race_name(int pr, int ps)
+ * @brief Return the player's race (and sub-race) name.\n
+ * @param pr Number \n the player's race. It is an index to race_info[].
+ * @brief Player race
+ * @param ps Number \n the player's subrace, if any. It is an index to
+ * race_mod_info[].
+ * @brief Player subrace
+ * @return String \n The player's full race name.
+ * @note (see file util.c)
+ */
+extern cptr get_player_race_name(int pr, int ps);
+
+/** @fn quit(cptr str)
+ * @brief Quit the game.
+ * @param str String \n an error code or a message which is logged.
+ * @brief String
+ * @note
+ * Exit (ala "exit()"). If 'str' is NULL, do "exit(0)".\n
+ * If 'str' begins with "+" or "-", do "exit(atoi(str))".\n
+ * Otherwise, plog() 'str' and exit with an error code of -1.\n
+ * But always use 'quit_aux', if set, before anything else.
+ * @note (see file z-util.c)
+ */
+extern void quit(cptr str);
+
+/** @fn value_scale(int value, int vmax, int max, int min)
+ * @brief Rescale a value
+ * @param value Number \n the original value
+ * @brief Original value
+ * @param vmax Number \n the maximum the original value can be
+ * @brief Original maximum
+ * @param max Number \n the maximum new value
+ * @brief New maximum
+ * @param min Number \n the minimum new value
+ * @brief New minimum
+ * @return Number \n The rescaled value
+ * @note (see file util.c)
+ */
+extern s32b value_scale(int value, int vmax, int max, int min);
+
+/*
+ * compass, approximate_distance
+ */
+extern cptr compass(int y, int x, int y2, int x2);
+extern cptr approximate_distance(int y, int x, int y2, int x2);
+
+/** @fn text_out_c(byte a, cptr str)
+ * @brief Output text to the screen (in color) or to a file depending on the
+ * selected hook.\n
+ * @param a Number \n the attribute of the string
+ * @brief Attribute
+ * @param str String \n the string
+ * @brief String
+ * @note (see file util.c)
+ */
+extern void text_out_c(byte a, cptr str);
+
+/** @fn text_out(cptr str)
+ * @brief Output text to the screen (in white) or to a file depending on the
+ * selected hook.\n
+ * @param str String \n the string
+ * @brief String
+ * @note (see file util.c)
+ */
+extern void text_out(cptr str);
+
+/** @fn change_option(cptr name, bool value)
+ * @brief Switch an option by only knowing its name.\n
+ * @param name String \n the name of the option.
+ * @brief Option name
+ * @param value Boolean \n the new value of the option.
+ * @brief Option value
+ * @return Boolean \n the old value of the option, or FALSE if "name" is not
+ * an option.
+ * @note (see file cmd4.c)
+ */
+extern bool change_option(cptr name, bool value);
+
+/** @var process_hooks_restart
+ * @brief Number
+ * @note
+ * Set this to TRUE after deleting a C-hook (from a quest) to clean up hook
+ * processing. This is not required for Lua hooks as they are not deleted.
+ */
+extern int process_hooks_restart;
+
+/** @fn dump_hooks(int h_idx)
+ * @brief Print the name and type (language) of all hooks in a hook chain.\n
+ * @param h_idx Number \n the index of the hook chain in the hook_chain array.
+ * If this is -1, then all hook chains will be printed.
+ * @brief Hook chain index
+ * @note (see file plots.c)
+ */
+extern void dump_hooks(int h_idx);
+
+/** @fn add_hook_script(int h_idx, char *script, cptr name)
+ * @brief Add Lua script "name" in file "script" to hook_chain.\n
+ * @param h_idx Number \n the index of the hook chain in the hook_chain array.
+ * @brief Hook chain index
+ * @param *script String \n the name of the Lua script file.
+ * @brief Script filename
+ * @param name String \n the name of the script.
+ * @brief Script name
+ * @note (see file plots.c)
+ */
+extern void add_hook_script(int h_idx, char *script, cptr name);
+
+/** @fn del_hook_name(int h_idx, cptr name)
+ * @brief Delete hook with name "name" from a hook chain.\n
+ * @param h_idx Number \n the index of the hook chain in the hook_chain array.
+ * @brief Hook chain index
+ * @param name String \n the name of the hook to delete
+ * @brief Hook name
+ * @note (see file plots.c)
+ */
+extern void del_hook_name(int h_idx, cptr name);
+
+/** @fn tome_dofile(char *file)
+ * @brief Load a Lua file from lib/scpts.\n
+ * @param *file String \n the name of a Lua file to load.
+ * @brief Filename
+ * @return Boolean \n TRUE if file was loaded, otherwise FALSE.
+ * @note (see file script.c)
+ */
+extern bool tome_dofile(char *file);
+
+/** @fn tome_dofile_anywhere(cptr dir, char *file, bool test_exist = TRUE)
+ * @brief Load a Lua file from any directory.\n
+ * @param dir String \n the name of a Lua file directory
+ * @brief Directory
+ * @param *file String \n the name of a Lua file to load.
+ * @brief Filename
+ * @param test_exist Boolean \n TRUE if a message is printed if the file does
+ * not exist, otherwise FALSE.
+ * @brief Message if file does not exist?
+ * @return Boolean \n TRUE if file was loaded, otherwise FALSE.
+ * @note (see file script.c)
+ */
+extern bool tome_dofile_anywhere(cptr dir, char *file, bool test_exist = TRUE);
+
+/** @fn exec_lua(char *file)
+ * @brief Execute Lua command "file" and return the integer result.\n
+ * @param *file String \n the Lua command to execute.
+ * @brief Command
+ * @return Number \n the result of the Lua command.
+ * @note (see file script.c)
+ */
+extern int exec_lua(char *file);
+
+/** @fn dump_lua_stack(int min, int max)
+ * @brief Display part of the Lua stack.\n
+ * @param min Number \n the starting item of the stack dump.
+ * @brief Start item
+ * @param max Number \n the ending item of the stack dump.
+ * @brief End item
+ * @note (see file script.c)
+ */
+extern void dump_lua_stack(int min, int max);
+
+/** @fn string_exec_lua(char *file)
+ * @brief Execute Lua command "file" and return the string result.\n
+ * @param *file String \n the Lua command to execute.
+ * @brief Command
+ * @return String \n the result of the Lua command.
+ * @note (see file script.c)
+ */
+extern cptr string_exec_lua(char *file);
+
+/** @fn print_hook(cptr str);
+ * @brief Print string "string" to the hook file.\n
+ * @param str String \ the string.
+ * @brief String
+ * @note (see file lua_bind.c)
+ */
+extern void lua_print_hook@print_hook(cptr str);
+
+/* Savefile stuff */
+/** @fn register_savefile(int num)
+ * @brief Add "num" slots to the savefile.\n
+ * @param num Number \n the number of slots to add.
+ * @brief Slots
+ * @note (see file loadsave.c)
+ */
+extern void register_savefile(int num);
+
+/** @fn save_number_key(char *key, s32b val)
+ * @brief Save a key-value combination in the save file.\n
+ * @param *key String \n the key to save.
+ * @brief Key
+ * @param val Number \n the value of the key.
+ * @brief Value
+ * @note
+ * The length of the key is stored first, then the key, then the value.
+ * @note (see file loadsave.c)
+ */
+extern void save_number_key(char *key, s32b val);
+
+
+/* Tables */
+/** @var adj_mag_study[100]
+ * @brief Number
+ * @note Stat Table (INT/WIS) -- Number of half-spells per level
+ */
+extern byte adj_mag_study[100];
+
+/** @var adj_mag_mana[100]
+ * @brief Number
+ * @note Stat Table (INT/WIS) -- extra half-mana-points per level
+ */
+extern byte adj_mag_mana[100];
+
+/** @var adj_mag_fail[100]
+ * @brief Number
+ * @note Stat Table (INT/WIS) -- Minimum failure rate (percentage)
+ */
+extern byte adj_mag_fail[100];
+
+/** @var adj_mag_stat[100]
+ * @brief Number
+ * @note Stat Table (INT/WIS) -- Various things
+ */
+extern byte adj_mag_stat[100];
+
+/** @var adj_chr_gold[100]
+ * @brief Number
+ * @note Stat Table (CHR) -- payment percentages
+ */
+extern byte adj_chr_gold[100];
+
+/** @var adj_int_dev[100]
+ * @brief Number
+ * @note Stat Table (INT) -- Magic devices
+ */
+extern byte adj_int_dev[100];
+
+/** @var adj_wis_sav[100]
+ * @brief Number
+ * @note Stat Table (WIS) -- Saving throw
+ */
+extern byte adj_wis_sav[100];
+
+/** @var adj_dex_dis[100]
+ * @brief Number
+ * @note Stat Table (DEX) -- disarming
+ */
+extern byte adj_dex_dis[100];
+
+/** @var adj_int_dis[100]
+ * @brief Number
+ * @note Stat Table (INT) -- disarming
+ */
+extern byte adj_int_dis[100];
+
+/** @var adj_dex_ta[100]
+ * @brief Number
+ * @note Stat Table (DEX) -- bonus to ac (plus 128)
+ */
+extern byte adj_dex_ta[100];
+
+/** @var adj_str_td[100]
+ * @brief Number
+ * @note Stat Table (STR) -- bonus to dam (plus 128)
+ */
+extern byte adj_str_td[100];
+
+/** @var adj_dex_th[100]
+ * @brief Number
+ * @note Stat Table (DEX) -- bonus to hit (plus 128)
+ */
+extern byte adj_dex_th[100];
+
+/** @var adj_str_th[100]
+ * @brief Number
+ * @note Stat Table (STR) -- bonus to hit (plus 128)
+ */
+extern byte adj_str_th[100];
+
+/** @var adj_str_wgt[100]
+ * @brief Number
+ * @note Stat Table (STR) -- weight limit in deca-pounds
+ */
+extern byte adj_str_wgt[100];
+
+/** @var adj_str_hold[100]
+ * @brief Number
+ * @note Stat Table (STR) -- weapon weight limit in pounds
+ */
+extern byte adj_str_hold[100];
+
+/** @var adj_str_dig[100]
+ * @brief Number
+ * @note Stat Table (STR) -- digging value
+ */
+extern byte adj_str_dig[100];
+
+/** @var adj_str_blow[100]
+ * @brief Number
+ * @note Stat Table (STR) -- help index into the "blow" table
+ */
+extern byte adj_str_blow[100];
+
+/** @var adj_dex_blow[100]
+ * @brief Number
+ * @note Stat Table (DEX) -- index into the "blow" table
+ */
+extern byte adj_dex_blow[100];
+
+/** @var adj_dex_safe[100]
+ * @brief Number
+ * @note Stat Table (DEX) -- chance of avoiding "theft" and "falling"
+ */
+extern byte adj_dex_safe[100];
+
+/** @var adj_con_fix[100]
+ * @brief Number
+ * @note Stat Table (CON) -- base regeneration rate
+ */
+extern byte adj_con_fix[100];
+
+/** @var adj_con_mhp[100]
+ * @brief Number
+ * @note Stat Table (CON) -- extra half-hitpoints per level (plus 128)
+ */
+extern byte adj_con_mhp[100];
+
+/* Repeat stuff */
+/** @fn repeat_push(int what)
+ * @brief Push key "what" onto the end of the repeat_key array.\n
+ * @param what Number \n the key to be repeated.
+ * @brief Key
+ * @note (see file util.c)
+ */
+extern void repeat_push(int what);
+
+/** @fn repeat_pull(int *what = 0)
+ * @brief Pull key from the repeat__key array.\n
+ * @param *what Number
+ * @brief Key
+ * @return Boolean \n TRUE if key was pulled, otherwise FALSE.
+ * @return *what Number \n the key pulled.
+ * @note
+ * This functions starts from an index, which may not be at the start of the
+ * array.
+ * @note (see file util.c)
+ */
+extern bool repeat_pull(int *what = 0);
+
+/** @fn repeat_check(void)
+ * @brief Check if the last command is repeated.
+ * @note
+ * Ignore certain commands: ESC, space, newline.\n
+ * 'n' repeats the last command (index is set to 0).\n
+ * Other commands reset the repeat array (index and count are set to 0).
+ * @note (see file util.c)
+ */
+extern void repeat_check(void);
+
+/** @fn get_count(int number, int max)
+ * @brief Allow the user to select multiple items without pressing '0'.\n
+ * @param number Number \n the default number.
+ * @brief Default
+ * @param max Number \n the maximum value allowed.
+ * @brief Maximum
+ * The user is prompted with "How many?"
+ * @note (see file util.c)
+ */
+extern void get_count(int number, int max);
+
+/** @name Feature Flags
+ * @{
+ */
+/** @def FF1_NO_WALK */
+#define FF1_NO_WALK 0x00000001L
+
+/** @def FF1_NO_VISION */
+#define FF1_NO_VISION 0x00000002L
+
+/** @def FF1_CAN_LEVITATE */
+#define FF1_CAN_LEVITATE 0x00000004L
+
+/** @def FF1_CAN_PASS */
+#define FF1_CAN_PASS 0x00000008L
+
+/** @def FF1_FLOOR */
+#define FF1_FLOOR 0x00000010L
+
+/** @def FF1_WALL */
+#define FF1_WALL 0x00000020L
+
+/** @def FF1_PERMANENT */
+#define FF1_PERMANENT 0x00000040L
+
+/** @def FF1_CAN_FLY */
+#define FF1_CAN_FLY 0x00000080L
+
+/** @def FF1_REMEMBER */
+#define FF1_REMEMBER 0x00000100L
+
+/** @def FF1_NOTICE */
+#define FF1_NOTICE 0x00000200L
+
+/** @def FF1_DONT_NOTICE_RUNNING */
+#define FF1_DONT_NOTICE_RUNNING 0x00000400L
+
+/** @def FF1_CAN_RUN */
+#define FF1_CAN_RUN 0x00000800L
+
+/** @def FF1_DOOR */
+#define FF1_DOOR 0x00001000L
+
+/** @def FF1_SUPPORT_LIGHT */
+#define FF1_SUPPORT_LIGHT 0x00002000L
+
+/** @def FF1_CAN_CLIMB */
+#define FF1_CAN_CLIMB 0x00004000L
+
+/** @def FF1_TUNNELABLE */
+#define FF1_TUNNELABLE 0x00008000L
+
+/** @def FF1_WEB */
+#define FF1_WEB 0x00010000L
+
+/** @def FF1_ATTR_MULTI */
+#define FF1_ATTR_MULTI 0x00020000L
+
+/** @def FF1_SUPPORT_GROWTH */
+#define FF1_SUPPORT_GROWTH 0x00040000L
+/** @} */
+
+
+/* Cave stuff */
+/** @struct cave_type
+ */
+struct cave_type
+{
+ /** @structvar info
+ * @brief Number
+ * @note Hack -- cave flags
+ */
+ u16b info;
+
+ /** @structvar feat
+ * @brief Number
+ * @note Hack -- feature type
+ */
+ byte feat;
+
+ /** @structvar o_idx
+ * @brief Number
+ * @note Object in this grid
+ */
+ s16b o_idx;
+
+ /** @structvar m_idx
+ * @brief Number
+ * @note Monster in this grid
+ */
+ s16b m_idx;
+
+ /** @structvar t_idx
+ * @brief Number
+ * @note trap index (in t_list) or zero
+ */
+ s16b t_idx;
+
+ /** @structvar special
+ * @brief Number
+ */
+ s16b special;
+ /** @structvar special2
+ * @brief Number
+ * @note Special cave info
+ */
+ s16b special2;
+
+ /** @structvar inscription
+ * @brief Number
+ * @note Inscription of the grid
+ */
+ s16b inscription;
+
+ /** @structvar mana
+ * @brief Number
+ * @note Magical energy of the grid
+ */
+ byte mana;
+
+ /** @structvar mimic
+ * @brief Number
+ * @note Feature to mimic
+ */
+ byte mimic;
+
+ /** @structvar effect
+ * @brief Number
+ * @note The lasting effects
+ */
+ s16b effect;
+};
+
+/** @var ANGBAND_SYS
+ * @brief String
+ * @note
+ * Hack -- The special Angband "System Suffix"\n
+ * This variable is used to choose an appropriate "pref-xxx" file
+ */
+extern cptr ANGBAND_SYS;
+
+/** @var ANGBAND_KEYBOARD
+ * @brief String
+ * @note
+ * Hack -- The special Angband "Keyboard Suffix"\n
+ * This variable is used to choose an appropriate macro-trigger definition
+ */
+extern cptr ANGBAND_KEYBOARD;
+
+/** @var ANGBAND_GRAF
+ * @brief String
+ * @note
+ * Hack -- The special Angband "Graphics Suffix"\n
+ * This variable is used to choose an appropriate "graf-xxx" file
+ */
+extern cptr ANGBAND_GRAF;
+
+/** @var ANGBAND_DIR
+ * @brief String
+ * @note
+ * Path name: The main "lib" directory\n
+ * This variable is not actually used anywhere in the code
+ */
+extern cptr ANGBAND_DIR;
+
+/** @var ANGBAND_DIR_APEX
+ * @brief String
+ * @note
+ * High score files (binary)\n
+ * These files may be portable between platforms
+ */
+extern cptr ANGBAND_DIR_APEX;
+
+/** @var ANGBAND_DIR_CORE
+ * @brief String
+ * @note
+ * Core lua system\n
+ * These files are portable between platforms
+ */
+extern cptr ANGBAND_DIR_CORE;
+
+/** @var ANGBAND_DIR_DNGN
+ * @brief String
+ * @note
+ * Textual dungeon level definition files\n
+ * These files are portable between platforms
+ */
+extern cptr ANGBAND_DIR_DNGN;
+
+/** @var ANGBAND_DIR_DATA
+ * @brief String
+ * @note
+ * Binary image files for the "*_info" arrays (binary)\n
+ * These files are not portable between platforms
+ */
+extern cptr ANGBAND_DIR_DATA;
+
+/** @var ANGBAND_DIR_EDIT
+ * @brief String
+ * @note
+ * Textual template files for the "*_info" arrays (ascii)\n
+ * These files are portable between platforms
+ */
+extern cptr ANGBAND_DIR_EDIT;
+
+/** @var ANGBAND_DIR_FILE
+ * @brief String
+ * @note
+ * Various extra files (ascii)\n
+ * These files may be portable between platforms
+ */
+extern cptr ANGBAND_DIR_FILE;
+
+/** @var ANGBAND_DIR_HELP
+ * @brief String
+ * @note
+ * Help files (normal) for the online help (ascii)\n
+ * These files are portable between platforms
+ */
+extern cptr ANGBAND_DIR_HELP;
+
+/** @var ANGBAND_DIR_INFO
+ * @brief String
+ * @note
+ * Help files (spoilers) for the online help (ascii)\n
+ * These files are portable between platforms
+ */
+extern cptr ANGBAND_DIR_INFO;
+
+/** @var ANGBAND_DIR_MODULES
+ * @brief String
+ * @note
+ * Modules, those subdirectories are half-mirrors of lib/
+ */
+extern cptr ANGBAND_DIR_MODULES;
+
+/** @var ANGBAND_DIR_NOTE
+ * @brief String
+ * @note
+ * Textual template files for the plot files (ascii)\n
+ * These files are portable between platforms
+ */
+extern cptr ANGBAND_DIR_NOTE;
+
+/** @var ANGBAND_DIR_SAVE
+ * @brief String
+ * @note
+ * Savefiles for current characters (binary)\n
+ * These files are portable between platforms
+ */
+extern cptr ANGBAND_DIR_SAVE;
+
+/** @var ANGBAND_DIR_SCPT
+ * @brief String
+ * @note
+ * Scripts.\n
+ * These files are portable between platforms
+ */
+extern cptr ANGBAND_DIR_SCPT;
+
+/** @var ANGBAND_DIR_PREF
+ * @brief String
+ * @note
+ * Default "preference" files (ascii)\n
+ * These files are rarely portable between platforms
+ */
+extern cptr ANGBAND_DIR_PREF;
+
+/** @var ANGBAND_DIR_PATCH
+ * @brief String
+ * @note
+ * Patches, contains one subdir per patch with a patch.lua file
+ * in it and a patch_init() function in it
+ */
+extern cptr ANGBAND_DIR_PATCH;
+
+/** @var ANGBAND_DIR_USER
+ * @brief String
+ * @note
+ * User "preference" files (ascii)\n
+ * These files are rarely portable between platforms
+ */
+extern cptr ANGBAND_DIR_USER;
+
+/** @var ANGBAND_DIR_XTRA
+ * @brief String
+ * @note
+ * Various extra files (binary)\n
+ * These files are rarely portable between platforms
+ */
+extern cptr ANGBAND_DIR_XTRA;
+
+/** @var ANGBAND_DIR_CMOV
+ * @brief String
+ * @note
+ * Cmovie files of entire games (ascii)\n
+ * Apart from possible newline things, likely portable btw platforms
+ */
+extern cptr ANGBAND_DIR_CMOV;
+
+
+/** @fn los(int y1, int x1, int y2, int x2)
+ * @brief Determine if a line of sight can be traced from (x1,y1) to (x2,y2).\n
+ * @param y1 Number \n y-coordinate of the origin.
+ * @brief Origin y-coordinate
+ * @param x1 Number \n x-coordinate of the origin.
+ * @brief Origin x-coordinate
+ * @param y2 Number \n y-coordinate of the target.
+ * @brief Target y-coordinate
+ * @param x2 Number \n x-coordinate of the target.
+ * @brief Target x-coordinate
+ * @return Boolean \n TRUE if origin has line of sight to target, otherwise
+ * FALSE.
+ * @note
+ * A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall,
+ * 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu.\n\n
+ * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2).\n\n
+ * The LOS begins at the center of the tile (x1,y1) and ends at the center of
+ * the tile (x2,y2). If los() is to return TRUE, all of the tiles this line
+ * passes through must be floor tiles, except for (x1,y1) and (x2,y2).\n\n
+ * We assume that the "mathematical corner" of a non-floor tile does not
+ * block line of sight.\n\n
+ * Because this function uses (short) ints for all calculations, overflow may
+ * occur if dx and dy exceed 90.\n\n
+ * Once all the degenerate cases are eliminated, the values "qx", "qy", and
+ * "m" are multiplied by a scale factor "f1 = abs(dx * dy * 2)", so that
+ * we can use integer arithmetic.\n\n
+ * We travel from start to finish along the longer axis, starting at the border
+ * between the first and second tiles, where the y offset = .5 * slope, taking
+ * into account the scale factor. See below.\n\n
+ * Also note that this function and the "move towards target" code do NOT
+ * share the same properties. Thus, you can see someone, target them, and
+ * then fire a bolt at them, but the bolt may hit a wall, not them. However,
+ * by clever choice of target locations, you can sometimes throw a "curve".\n\n
+ * Note that "line of sight" is not "reflexive" in all cases.\n\n
+ * Use the "projectable()" routine to test "spell/missile line of sight".\n\n*
+ * Use the "update_view()" function to determine player line-of-sight.\n\n
+ * @note (see file cave.c)
+ */
+extern bool los(int y1, int x1, int y2, int x2);
+$static bool lua_cave_is(cave_type *c_ptr, s32b flag) { return (f_info[c_ptr->feat].flags1 & flag) ? TRUE : FALSE; }
+
+/** @fn cave_is(cave_type *c_ptr, s32b flag);
+ * @brief Determine if cave "c_ptr" has feature "flag".\n
+ * @param *c_ptr cave_type \n the cave.
+ * @brief Cave
+ * @param flag Number \n the required feature flag.
+ * @brief Feature
+ * @return Boolean \n TRUE if the cave features include "flag", otherwise
+ * FALSE.
+ * @note (see file w_util.c)
+ */
+static bool lua_cave_is @ cave_is(cave_type *c_ptr, s32b flag);
+
+/** @fn cave(int y, int x);
+ * @brief Return the type of cave at grid coordinate (x,y).\n
+ * @param y Number \n y-coordinate of grid.
+ * @brief Y-coordinate
+ * @param x Number \n x-coordinate of grid.
+ * @brief X-coordinate
+ * @return cave_type \n The type of cave at grid coordinate (x,y).
+ * @note (see file lua_bind.c)
+ */
+extern cave_type *lua_get_cave @ cave(int y, int x);
+
+/** @fn set_target(int y, int x)
+ * @brief Set grid coordinate (x,y) as the target grid.\n
+ * @param y Number \n y-coordinate of grid.
+ * @brief Y-coordinate
+ * @param x Number \n x-coordinate of grid.
+ * @brief X-coordinate
+ * @note (see file lua_bind.c)
+ */
+extern void set_target(int y, int x);
+
+/** @fn get_target(int dir, int *y = 0, int *x = 0)
+ * @brief Get a target based on direction "dir" from the player.\n
+ * @param dir Number \n dir must be a value from 0 to 9.
+ * @brief Direction
+ * @param *y Number
+ * @brief Target y-coordinate
+ * @param *x Number
+ * @brief Target x-coordinate
+ * @return *y Number \n The y-coordinate of the target.
+ * @return *x Number \n The x-coordinate of the target.
+ * @note
+ * The target is actually 100 grids away in direction "dir". If "dir" is 5,
+ * the actual target, if one is set, is returned.
+ * @note (see file lua_bind.c)
+ */
+extern void get_target(int dir, int *y = 0, int *x = 0);
+
+/** @var m_allow_special[max_r_idx]
+ * @brief Boolean
+ * @note "Special gene" flags for monsters
+ */
+extern bool m_allow_special[max_r_idx];
+
+/** @var k_allow_special[max_k_idx]
+ * @brief Boolean
+ * @note "Special gene" flags for objects
+ */
+extern bool k_allow_special[max_k_idx];
+
+/** @var a_allow_special[max_a_idx]
+ * @brief Boolean
+ * @note "Special gene" flags for artifacts
+ */
+extern bool a_allow_special[max_a_idx];
+
+/** @fn cave_set_feat(int y, int x, int feat)
+ * @brief Change the "feat" flag for a grid, and notice/redraw the grid
+ * @param y Number \n y-coordinate of grid.
+ * @brief Y-coordinate
+ * @param x Number \n x-coordinate of grid.
+ * @brief X-coordinate
+ * @param feat Number \n new set of feature flags.
+ * @brief Features
+ * @note (see file cave.c)
+ */
+extern void cave_set_feat(int y, int x, int feat);
+
+/** @fn show_file(cptr name, cptr what, int line, int mode)
+ * @brief Show a help file.\n
+ * @param name String \n name of the help file.
+ * @brief Filename
+ * @param what String \n hyperlink caption.
+ * @brief Caption
+ * @param line Number \n the line number from where to start the display of
+ * the file.
+ * @brief Starting line
+ * @param mode Number \n *unused*
+ * @brief *Unused*
+ * @return Boolean \n TRUE if file was shown successfully, otherwise FALSE.\n
+ * @note
+ * If the file is not found, the function will search the help, info, and file
+ * directories for the file. If it is still not found, a message is displayed
+ * and the function returns FALSE.\n\n
+ * The file is parsed once to extract colour, tag, and hyperlink
+ * information.\n\n
+ * The file is parse again to show it on the screen.
+ * @note (see file files.c)
+ */
+extern bool show_file(cptr name, cptr what, int line, int mode);
+
+/** @var target_who
+ * @brief Number
+ * @note
+ * If this is -1, the target is the player.\n
+ * If this is 0, there is no target.\n
+ * If this is >0, the target is the monster m_idx[target_who].
+ */
+extern s16b target_who;
+
+/** @var target_col
+ * @brief Number
+ * @note The column of the target grid
+ */
+extern s16b target_col;
+
+/** @var target_row
+ * @brief Number
+ * @note The row of the target grid
+ */
+extern s16b target_row;
+
+/** @var max_bact
+ * @brief Number
+ * @note Maximum building actions
+ */
+extern int max_bact;
+
+/** @var ddd[9]
+ * @brief Number
+ * @note Global array for looping through the "keypad directions"
+ */
+extern s16b ddd[9];
+
+/** @var ddx[10]
+ * @brief Number
+ * @note Global array for converting "keypad direction" into x offsets
+ */
+extern s16b ddx[10];
+
+/** @var ddy[10]
+ * @brief Number
+ * @note Global array for converting "keypad direction" into y offsets
+ */
+extern s16b ddy[10];
+
+/** @var ddx_ddd[9]
+ * @brief Number
+ * @note Global array for optimizing "ddx[ddd[i]]"
+ */
+extern s16b ddx_ddd[9];
+
+/** @var ddy_ddd[9]
+ * @brief Number
+ * @note Global array for optimizing "ddy[ddd[i]]"
+ */
+extern s16b ddy_ddd[9];
+
+
+/* Gen stuff */
+
+/** @fn load_map(char *name, int *y = 2, int *x = 2)
+ * @brief Load the map in file "name".\n
+ * @param *name String \n the name of the map file.
+ * @brief Map
+ * @param *y Number
+ * @brief Maximum y-coordinate
+ * @param *x Number
+ * @brief Maximum x-coordinate
+ * @return *y Number \n The maximum y-coordinate of the map.
+ * @return *x Number \n The maximum x-coordinate of the map.
+ * @note
+ * The map is loaded and the player is placed at the starting position.
+ * @note (see file lua_bind.c)
+ */
+extern void load_map(char *name, int *y = 2, int *x = 2);
+
+/** @fn alloc_room(int by0, int bx0, int ysize, int xsize, int *y1 = 0, int *x1 = 0, int *y2 = 0, int *x2 = 0)
+ * @brief Allocate the space needed by a room in the room_map array.\n
+ * @param by0 Number \n the y-coordinate of the block to contain the room.
+ * @brief Block y-coordinate
+ * @param bx0 Number \n the x-coordinate of the block to contain the room.
+ * @brief Block x-coordinate
+ * @param ysize Number \n the vertical size (height) of the room.
+ * @brief Room height
+ * @param xsize Number \n the horizontal size (width) of the room.
+ * @brief Room width
+ * @param *y1 Number
+ * @brief Top-right y-coordinate
+ * @param *x1 Number
+ * @brief Top-right x-coordinate
+ * @param *y2 Number
+ * @brief Bottom-left y-coordinate
+ * @param *x2 Number
+ * @brief Bottom-right x-coordinate
+ * @return Boolean \n TRUE if the room was allocated successfully, otherwise
+ * FALSE.
+ * @return *y1 Number \n The y-coordinate of the top left corner.
+ * @return *x1 Number \n The x-coordinate of the top left corner.
+ * @return *y2 Number \n The y-coordinate of the bottom right corner.
+ * @return *x2 Number \n The x-coordinate of the bottom right corner.
+ * @note
+ * Dungeon generation is not something to be messed around with unless you
+ * really, really, really know what you are doing (or you are DarkGod).
+ * @note (see file lua_bind.c, generate.c)
+ */
+extern bool alloc_room(int by0, int bx0, int ysize, int xsize, int *y1 = 0, int *x1 = 0, int *y2 = 0, int *x2 = 0);
+
+/** @var option_ingame_help
+ * @brief Boolean
+ * @note Ingame contextual help flag
+ */
+extern bool option_ingame_help;
+
+/* Misc stuff */
+/** @fn input_box(cptr title, int max);
+ * @brief Create an input box and ask the user a question.\n
+ * @param title String \n the title of the box, which should take the form of
+ * a question. For example, "New name?".
+ * @brief Title
+ * @param max Number \n the maximum length of the response.
+ * @brief Maximum response length
+ * @return String \n The answer to the question.
+ * @note
+ * The input box is placed in the middle of the screen. The default reponse is
+ * blank, and can be up to 79 characters long.
+ * @note (see file lua_bind.c, util.c)
+ */
+extern char *lua_input_box@input_box(cptr title, int max);
+
+/** @fn msg_box(cptr title);
+ * @brief Create a msg box and ask a question.\n
+ * @param title String \n the question.
+ * @brief Question
+ * @return String \n The answer.
+ * @note
+ * The message box is placed in the middle of the screen. The answer is a
+ * single character / key press.
+ * @note (see file lua_bind.c, util.c)
+ */
+extern char lua_msg_box@msg_box(cptr title);
+
+/** @fn rescale(s32b x, s32b max, s32b new_max)
+ * @brief Rescale value "x".\n
+ * @param x Number \n the original value.
+ * @brief Value
+ * @param max Number \n the original maximum that value could have.
+ * @brief Original maximum
+ * @param new_max Number \n the new maximum that value can have.
+ * @brief New maximum
+ * @return Number \n The rescaled value of "x".
+ * @note
+ * There is no error checking here. Please don't set "max" to zero.
+ * @note (see file util.c)
+ */
+extern s32b rescale(s32b x, s32b max, s32b new_max);
+$static const char *player_name_lua(void){return (const char *)player_name;}
+
+/** @fn player_name()
+ * @brief Return the player's name.
+ * @return String \n The player's name.
+ * @note (see file w_util.c)
+ */
+const char *player_name_lua@player_name();
+
+/* Quarks */
+/** @fn quark_str(s16b num)
+ * @brief Return a quark (inscription) from the quark array.\n
+ * @param num Number \n the index to the quark string array. If this is less
+ * than zero or more than the maximum number of quarks, it is treated as zero.
+ * @brief Quark index
+ * @return String \n The quark.
+ * @note
+ * We use a global array for all inscriptions to reduce the memory
+ * spent maintaining inscriptions. Of course, it is still possible
+ * to run out of inscription memory, especially if too many different
+ * inscriptions are used, but hopefully this will be rare.\n\n
+ * We use dynamic string allocation because otherwise it is necessary
+ * to pre-guess the amount of quark activity. We limit the total
+ * number of quarks, but this is much easier to "expand" as needed.\n\n
+ * Any two items with the same inscription will have the same "quark"
+ * index, which should greatly reduce the need for inscription space.\n\n
+ * Note that "quark zero" is NULL and should not be "dereferenced".
+ * @note (see file util.c)
+ */
+extern cptr quark_str(s16b num);
+
+/** @fn quark_add(cptr str)
+ * @brief Add a quark (inscription) to the quark array.\n
+ * @param str String \n the quark to add to the array.
+ * @brief Quark
+ * @return Number \n The index to the quark array for this quark
+ * @note
+ * The array is searched to see if the quark already exists. If so, the index
+ * to the existing quark is returned.\n
+ * If there is no room, 0 (NULL reference) is returned.
+ * @note (see file util.c)
+ */
+extern s16b quark_add(cptr str);
+
+/* Modules */
+/** @fn module_reset_dir(cptr dir, cptr new_path)
+ * @brief Redirect one of the ToME directories.\n
+ * @param dir String \n the name of the directory (not the full path).
+ * @brief Directory
+ * @param new_path String \n the new path of "dir" under ANGBAND_DIR_MODULES.\n
+ * @brief New path
+ * @note (see file modules.c)
+ */
+extern void module_reset_dir(cptr dir, cptr new_path);
+
+/** @fn scansubdir(cptr dir)
+ * @brief Scan sub-directory "dir".\n
+ * @param dir String \n the sub-directory to scan.
+ * @brief Directory
+ * @note
+ * Nicer wrapper around TERM_XTRA_SCANSUBDIR\n\n
+ * This function sets scansubdir_dir and calls the SCANSUBDIR terminal hook.
+ * @note (see file util.c)
+ */
+extern void scansubdir(cptr dir);
+
+/** @fn file_exist(char *buf)
+ * @brief Check if file "buf" exists.\n
+ * @param *buf String \n the file to be tested.
+ * @brief Filename
+ * @return Boolean \n TRUE if the file exists, otherwise FALSE.
+ * @note (see file loadsave.c)
+ */
+extern bool file_exist(char *buf);
+
+/** @var game_module
+ * @brief String
+ * @note The name of the current game module
+ */
+extern cptr game_module;
+
+/* Input */
+/** @fn get_keymap_dir(char ch)
+ * @brief Get a direction from the keyboard according to the keymap.\n
+ * @param ch String \n the character representing a direction.
+ * @brief Direction
+ * @return Number \n The direction represented by "ch". It will be in the
+ * range 0 to 9.
+ * @note
+ * If "ch" is a number, the number is used. Otherwise the direction is
+ * chosen from the Original or Rogue keymaps.\n
+ * If the direction is 5, it is set to 0.
+ * @note (see file util.c)
+ */
+extern int get_keymap_dir(char ch);
+
+/*
+ * Timers
+ */
+/** @struct timer_type
+ */
+struct timer_type
+{
+ /** @structvar *next
+ * @brief timer_type
+ * @note The next timer in the list
+ */
+ timer_type *next;
+
+ /** @structvar enabled
+ * @brief Boolean
+ * @note Is it currently counting?
+ */
+ bool enabled;
+
+ /** @structvar delay
+ * @brief Number
+ * @note Delay between activations
+ */
+ s32b delay;
+ /** @structvar countdown
+ * @brief Number
+ * @note The current number of turns passed, when it reaches delay it fires
+ */
+ s32b countdown;
+
+ /** @structvar callback
+ * @brief String
+ * @note The lua function to call upon firing(no C callback yet .. maybe)
+ */
+ cptr callback;
+};
+
+/** @fn *new_timer(cptr callback, s32b delay)
+ * @brief Create a timer with callback "callback" and delay "delay".\n
+ * @param callback String \n the callback associated with the timer.
+ * @brief Callback
+ * @param delay Number \n the delay associated with the timer.
+ * @brief Delay
+ * @return timer_type \n The new timer.
+ * @note
+ * The timer's countdown is also set to "delay". The timer is disabled.
+ * @note (see file util.c)
+ */
+extern timer_type *new_timer(cptr callback, s32b delay);
+
+/** @fn del_timer(timer_type *t_ptr)
+ * @brief Delete timer "t_ptr".\n
+ * @param *t_ptr timer_type \n the timer to be deleted.
+ * @brief Timer
+ * @note (see file util.c)
+ */
+extern void del_timer(timer_type *t_ptr);
+
+/*
+ * Lists
+ */
+/** @struct list_type
+ */
+struct list_type
+{
+};
+
+/** @fn create_list(int size);
+ * @dgonly
+ * @brief Create an empty list big enough to store "size" strings.\n
+ * @param size Number \n the number of strings the list will hold.
+ * @brief List size
+ * @return list_type \n The empty list.
+ * @note (see file lua_bind.c)
+ */
+extern list_type *lua_create_list@create_list(int size);
+
+/** @fn delete_list(list_type *, int size);
+ * @dgonly
+ * @brief Delete the list of strings.\n
+ * @param * list_type \n the list of strings.
+ * @brief List
+ * @param size Number \n the number of strings the list holds.
+ * @brief List size
+ * @note
+ * All the strings in the list are deleted first, then the list is deleted.
+ * @note (see file lua_bind.c)
+ */
+extern void lua_delete_list@delete_list(list_type *, int size);
+
+/** @fn add_to_list(list_type *, int idx, cptr str);
+ * @dgonly
+ * @brief Add string "str" to list in position "idx".\n
+ * @param * list_type \n the list of strings.
+ * @brief List
+ * @param idx Number \n the index of the list where the string will be added.
+ * @brief Index
+ * @param str String \n the string to be added.
+ * @brief String
+ * @note
+ * Too bad if there was something in that position already.
+ * You have been warned.
+ * @note (see file lua_bind.c)
+ */
+extern void lua_add_to_list@add_to_list(list_type *, int idx, cptr str);
+
+/** @fn display_list(int y, int x, int h, int w, cptr title, list_type *list, int max, int begin, int sel, byte sel_color);
+ * @dgonly
+ * @brief Display a scrollable boxed list with a selected item.\n
+ * @param y Number \n the y-coordinate of the top-left corner of the box.
+ * @brief Top-left y-coordinate
+ * @param x Number \n the x-coordinate of the top-left corner of the box.
+ * @brief Top-left x-coordinate
+ * @param h Number \n the height of the box.
+ * @brief Height
+ * @param w Number \n the width of the box.
+ * @brief Width
+ * @param title String \n the title for the list box.
+ * @brief Title
+ * @param *list list_type \n the list of strings to be displayed.
+ * @brief List
+ * @param max Number \n the maximum number of strings to display.
+ * @brief Maximum displayed strings
+ * @param begin Number \n the index of the first string to display.
+ * @brief Start index
+ * @param sel Number \n the index of the selected string.
+ * @brief Selected index
+ * @param sel_color Number \n the colour of the selected string.
+ * @brief Selected colour
+ * @note
+ * The title of the list is displayed in TERM_L_BLUE and the unselected strings
+ * are displayed in TERM_WHITE.
+ * @note (see file util.c)
+ */
+extern void lua_display_list@display_list(int y, int x, int h, int w, cptr title, list_type *list, int max, int begin, int sel, byte sel_color);
+
+extern errr file_character(cptr name, bool full);
+extern void calc_bonuses(bool silent);
+
+extern void note_spot(int y, int x);
+extern void lite_spot(int y, int x);
+
+extern bool drop_text_left(byte c, cptr s, int y, int o);
+extern bool drop_text_right(byte c, cptr s, int y, int o);
diff --git a/src/variable.c b/src/variable.c
new file mode 100644
index 00000000..0eb0fadf
--- /dev/null
+++ b/src/variable.c
@@ -0,0 +1,1604 @@
+/* File: variable.c */
+
+/* Purpose: Angband variables */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Hack -- Link a copyright message into the executable
+ */
+cptr copyright[5] =
+{
+ "Copyright (c) 1989 James E. Wilson, Robert A. Keoneke",
+ "",
+ "This software may be copied and distributed for educational, research,",
+ "and not for profit purposes provided that this copyright and statement",
+ "are included in all such copies."
+};
+
+int max_macrotrigger = 0;
+char *macro_template = NULL;
+char *macro_modifier_chr;
+char *macro_modifier_name[MAX_MACRO_MOD];
+char *macro_trigger_name[MAX_MACRO_TRIG];
+char *macro_trigger_keycode[2][MAX_MACRO_TRIG];
+
+/*
+ * Executable version
+ */
+byte version_major;
+byte version_minor;
+byte version_patch;
+byte version_extra = VERSION_EXTRA;
+
+/*
+ * Savefile version
+ */
+byte sf_major; /* Savefile's "version_major" */
+byte sf_minor; /* Savefile's "version_minor" */
+byte sf_patch; /* Savefile's "version_patch" */
+byte sf_extra; /* Savefile's "version_extra" */
+u32b vernum;
+
+/*
+ * Savefile information
+ */
+u32b sf_xtra; /* Operating system info */
+u32b sf_when; /* Time when savefile created */
+u16b sf_lives; /* Number of past "lives" with this file */
+u16b sf_saves; /* Number of "saves" during this life */
+
+/*
+ * Run-time arguments
+ */
+bool_ arg_fiddle; /* Command arg -- Request fiddle mode */
+bool_ arg_wizard; /* Command arg -- Request wizard mode */
+bool_ arg_sound; /* Command arg -- Request special sounds */
+bool_ arg_graphics; /* Command arg -- Request graphics mode */
+bool_ arg_force_original; /* Command arg -- Request original keyset */
+bool_ arg_force_roguelike; /* Command arg -- Request roguelike keyset */
+bool_ arg_bigtile = FALSE; /* Command arg -- Request big tile mode */
+
+/*
+ * Various things
+ */
+
+bool_ character_generated; /* The character exists */
+bool_ character_dungeon; /* The character has a dungeon */
+bool_ character_loaded; /* The character was loaded from a savefile */
+bool_ character_saved; /* The character was just saved to a savefile */
+
+bool_ character_icky; /* The game is in an icky full screen mode */
+bool_ character_xtra; /* The game is in an icky startup mode */
+
+u32b seed_flavor; /* Hack -- consistent object colors */
+
+s16b command_cmd; /* Current "Angband Command" */
+
+s16b command_arg; /* Gives argument of current command */
+s16b command_rep; /* Gives repetition of current command */
+s16b command_dir; /* Gives direction of current command */
+
+s16b command_wrk; /* See "cmd1.c" */
+
+s16b command_new; /* Command chaining from inven/equip view */
+
+s32b energy_use; /* Energy use this turn */
+
+bool_ create_up_stair; /* Auto-create "up stairs" */
+bool_ create_down_stair; /* Auto-create "down stairs" */
+
+bool_ create_up_shaft; /* Auto-create "up shaft" */
+bool_ create_down_shaft; /* Auto-create "down shaft" */
+
+bool_ msg_flag; /* Used in msg_print() for "buffering" */
+
+bool_ alive; /* True if game is running */
+
+bool_ death; /* True if player has died */
+
+s16b running; /* Current counter for running, if any */
+s16b resting; /* Current counter for resting, if any */
+
+s16b cur_hgt; /* Current dungeon height */
+s16b cur_wid; /* Current dungeon width */
+s16b dun_level; /* Current dungeon level */
+s16b old_dun_level; /* Old dungeon level */
+s16b num_repro; /* Current reproducer count */
+s16b object_level; /* Current object creation level */
+s16b monster_level; /* Current monster creation level */
+
+s32b turn; /* Current game turn */
+s32b old_turn; /* Turn when level began (feelings) */
+
+bool_ wizard; /* Is the player currently in Wizard mode? */
+
+bool_ use_sound; /* The "sound" mode is enabled */
+bool_ use_graphics; /* The "graphics" mode is enabled */
+bool_ use_bigtile = FALSE;
+byte graphics_mode; /* Current graphics mode */
+
+u16b total_winner; /* Semi-Hack -- Game has been won */
+u16b has_won; /* Semi-Hack -- Game has been won */
+
+u16b noscore; /* Track various "cheating" conditions */
+
+s16b signal_count; /* Hack -- Count interupts */
+
+bool_ inkey_base; /* See the "inkey()" function */
+bool_ inkey_xtra; /* See the "inkey()" function */
+bool_ inkey_scan; /* See the "inkey()" function */
+bool_ inkey_flag; /* See the "inkey()" function */
+
+s16b coin_type; /* Hack -- force coin type */
+
+bool_ opening_chest; /* Hack -- prevent chest generation */
+
+bool_ shimmer_monsters; /* Hack -- optimize multi-hued monsters */
+bool_ shimmer_objects; /* Hack -- optimize multi-hued objects */
+
+bool_ repair_monsters; /* Hack -- optimize detect monsters */
+bool_ repair_objects; /* Hack -- optimize detect objects */
+
+s16b inven_nxt; /* Hack -- unused */
+bool_ hack_mind;
+bool_ hack_corruption;
+int artifact_bias;
+bool_ is_autosave = FALSE;
+
+s16b inven_cnt; /* Number of items in inventory */
+s16b equip_cnt; /* Number of items in equipment */
+
+s16b o_max = 1; /* Number of allocated objects */
+s16b o_cnt = 0; /* Number of live objects */
+
+s16b m_max = 1; /* Number of allocated monsters */
+s16b m_cnt = 0; /* Number of live monsters */
+
+s16b hack_m_idx = 0; /* Hack -- see "process_monsters()" */
+s16b hack_m_idx_ii = 0;
+bool_ multi_rew = FALSE;
+char summon_kin_type; /* Hack, by Julian Lighton: summon 'relatives' */
+
+int total_friends = 0;
+s32b total_friend_levels = 0;
+
+int leaving_quest = 0;
+
+
+
+/*
+ * Hack - the destination file for text_out_to_file.
+ */
+FILE *text_out_file = NULL;
+
+
+/*
+ * Hack -- function hook to output (colored) text to the
+ * screen or to a file.
+ */
+void (*text_out_hook)(byte a, cptr str) = text_out_to_screen;
+
+
+/*
+ * Hack -- Where to wrap the text when using text_out(). Use the default
+ * value (for example the screen width) when 'text_out_wrap' is 0.
+ */
+int text_out_wrap = 0;
+
+
+/*
+ * Hack -- Indentation for the text when using text_out().
+ */
+int text_out_indent = 0;
+
+
+/*
+ * The "highscore" file descriptor, if available.
+ */
+int highscore_fd = -1;
+
+
+/*
+ * Software options (set via the '=' command). See "tables.c"
+ */
+
+
+/* Option Set 1 -- User Interface */
+
+bool_ rogue_like_commands; /* Rogue-like commands */
+bool_ quick_messages; /* Activate quick messages */
+bool_ other_query_flag; /* Prompt for various information */
+bool_ carry_query_flag; /* Prompt before picking things up */
+bool_ use_old_target; /* Use old target by default */
+bool_ always_pickup; /* Pick things up by default */
+bool_ prompt_pickup_heavy; /* Don't pick up the corpses */
+bool_ always_repeat; /* Repeat obvious commands */
+bool_ depth_in_feet; /* Show dungeon level in feet */
+
+bool_ stack_force_notes; /* Merge inscriptions when stacking */
+bool_ stack_force_costs; /* Merge discounts when stacking */
+
+bool_ show_labels; /* Show labels in object listings */
+bool_ show_weights; /* Show weights in object listings */
+bool_ show_choices; /* Show choices in certain sub-windows */
+bool_ show_details; /* Show details in certain sub-windows */
+
+bool_ ring_bell; /* Ring the bell (on errors, etc) */
+
+bool_ show_inven_graph; /* Show graphics in inventory */
+bool_ show_equip_graph; /* Show graphics in equip list */
+bool_ show_store_graph; /* Show graphics in store */
+
+
+
+/* Option Set 2 -- Disturbance */
+
+bool_ find_ignore_stairs; /* Run past stairs */
+bool_ find_ignore_doors; /* Run through open doors */
+bool_ find_cut; /* Run past known corners */
+bool_ find_examine; /* Run into potential corners */
+
+bool_ disturb_move; /* Disturb whenever any monster moves */
+bool_ disturb_near; /* Disturb whenever viewable monster moves */
+bool_ disturb_panel; /* Disturb whenever map panel changes */
+bool_ disturb_detect; /* Disturb whenever leaving trap-detected area */
+bool_ disturb_state; /* Disturn whenever player state changes */
+bool_ disturb_minor; /* Disturb whenever boring things happen */
+bool_ disturb_other; /* Disturb whenever various things happen */
+
+bool_ alert_hitpoint; /* Alert user to critical hitpoints */
+bool_ alert_failure; /* Alert user to various failures */
+bool_ last_words; /* Get last words upon dying */
+bool_ speak_unique; /* Speaking uniques + shopkeepers */
+bool_ small_levels; /* Allow unusually small dungeon levels */
+bool_ empty_levels; /* Allow empty 'arena' levels */
+bool_ always_small_level; /* Small levels */
+bool_ player_symbols; /* Use varying symbols for the player char */
+bool_ plain_descriptions; /* Plain object descriptions */
+bool_ stupid_monsters; /* Monsters use old AI */
+bool_ auto_destroy; /* Known worthless items are destroyed without confirmation */
+bool_ confirm_stairs; /* Prompt before staircases... */
+bool_ wear_confirm; /* Confirm before putting on known cursed items */
+bool_ disturb_pets; /* Pets moving nearby disturb us */
+
+
+/* Option Set 3 -- Game-Play */
+
+bool_ auto_haggle; /* Auto-haggle in stores */
+
+bool_ auto_scum; /* Auto-scum for good levels */
+
+bool_ stack_allow_items; /* Allow weapons and armor to stack */
+bool_ stack_allow_wands; /* Allow wands/staffs/rods to stack */
+
+bool_ expand_look; /* Expand the power of the look command */
+bool_ expand_list; /* Expand the power of the list commands */
+
+bool_ view_perma_grids; /* Map remembers all perma-lit grids */
+bool_ view_torch_grids; /* Map remembers all torch-lit grids */
+
+bool_ monster_lite; /* Allow some monsters to carry light */
+
+bool_ dungeon_align; /* Generate dungeons with aligned rooms */
+bool_ dungeon_stair; /* Generate dungeons with connected stairs */
+
+bool_ flow_by_sound; /* Monsters track new player location */
+
+bool_ track_follow; /* Monsters follow the player */
+bool_ track_target; /* Monsters target the player */
+
+bool_ smart_learn; /* Monsters learn from their mistakes */
+bool_ smart_cheat; /* Monsters exploit player weaknesses */
+
+
+/* Option Set 4 -- Efficiency */
+
+bool_ view_reduce_lite; /* Reduce lite-radius when running */
+bool_ view_reduce_view; /* Reduce view-radius in town */
+
+bool_ avoid_abort; /* Avoid checking for user abort */
+bool_ avoid_shimmer; /* Avoid processing extra shimmering */
+bool_ avoid_other; /* Avoid processing special colors */
+
+bool_ flush_failure; /* Flush input on any failure */
+bool_ flush_disturb; /* Flush input on disturbance */
+bool_ flush_command; /* Flush input before every command */
+
+bool_ fresh_before; /* Flush output before normal commands */
+bool_ fresh_after; /* Flush output after normal commands */
+bool_ fresh_message; /* Flush output after all messages */
+
+bool_ hilite_player; /* Hilite the player with the cursor */
+
+bool_ view_yellow_lite; /* Use special colors for torch-lit grids */
+bool_ view_bright_lite; /* Use special colors for 'viewable' grids */
+
+bool_ view_granite_lite; /* Use special colors for wall grids (slow) */
+bool_ view_special_lite; /* Use special colors for floor grids (slow) */
+
+/* Option set 5 -- Testing */
+
+bool_ testing_stack; /* Test the stacking code */
+
+bool_ testing_carry; /* Test the carrying code */
+
+
+/* Cheating options */
+
+bool_ cheat_peek; /* Peek into object creation */
+bool_ cheat_hear; /* Peek into monster creation */
+bool_ cheat_room; /* Peek into dungeon creation */
+bool_ cheat_xtra; /* Peek into something else */
+bool_ cheat_know; /* Know complete monster info */
+bool_ cheat_live; /* Allow player to avoid death */
+
+
+/* Special options */
+
+byte hitpoint_warn; /* Hitpoint warning (0 to 9) */
+
+byte delay_factor; /* Delay factor (0 to 9) */
+
+bool_ autosave_l; /* Autosave before entering new levels */
+bool_ autosave_t; /* Timed autosave */
+s16b autosave_freq; /* Autosave frequency */
+
+
+/*
+ * Dungeon variables
+ */
+
+s16b feeling; /* Most recent feeling */
+s16b rating; /* Level's current rating */
+
+bool_ good_item_flag; /* True if "Artifact" on this level */
+
+bool_ closing_flag; /* Dungeon is closing */
+
+/*
+ * Dungeon size info
+ */
+
+s16b max_panel_rows, max_panel_cols;
+s16b panel_row_min, panel_row_max;
+s16b panel_col_min, panel_col_max;
+s16b panel_col_prt, panel_row_prt;
+
+/*
+ * Dungeon graphics info
+ * Why the first two are byte and the rest s16b???
+ */
+byte feat_wall_outer = FEAT_WALL_OUTER; /* Outer wall of rooms */
+byte feat_wall_inner = FEAT_WALL_INNER; /* Inner wall of rooms */
+s16b floor_type[100]; /* Dungeon floor */
+s16b fill_type[100]; /* Dungeon filler */
+
+/*
+ * Targetting variables
+ */
+s16b target_who;
+s16b target_col;
+s16b target_row;
+
+/*
+ * Health bar variable -DRS-
+ */
+s16b health_who;
+
+/*
+ * Monster race to track
+ */
+s16b monster_race_idx;
+s16b monster_ego_idx;
+
+/*
+ * Object to track
+ */
+object_type *tracked_object;
+
+
+
+/*
+ * User info
+ */
+int player_uid;
+
+/*
+ * Current player's character name
+ */
+char player_name[32];
+
+/*
+ * Stripped version of "player_name"
+ */
+char player_base[32];
+
+/*
+ * What killed the player
+ */
+char died_from[80];
+
+/*
+ * Hack -- Textual "history" for the Player
+ */
+char history[4][60];
+
+/*
+ * Buffer to hold the current savefile name
+ */
+char savefile[1024];
+
+
+/*
+ * Array of grids lit by player lite (see "cave.c")
+ */
+s16b lite_n;
+s16b lite_y[LITE_MAX];
+s16b lite_x[LITE_MAX];
+
+/*
+ * Array of grids viewable to the player (see "cave.c")
+ */
+s16b view_n;
+byte view_y[VIEW_MAX];
+byte view_x[VIEW_MAX];
+
+/*
+ * Array of grids for use by various functions (see "cave.c")
+ */
+s16b temp_n;
+byte temp_y[TEMP_MAX];
+byte temp_x[TEMP_MAX];
+
+
+/*
+ * Number of active macros.
+ */
+s16b macro__num;
+
+/*
+ * Array of macro patterns [MACRO_MAX]
+ */
+cptr *macro__pat;
+
+/*
+ * Array of macro actions [MACRO_MAX]
+ */
+cptr *macro__act;
+
+/*
+ * Array of macro types [MACRO_MAX]
+ */
+bool_ *macro__cmd;
+
+/*
+ * Current macro action [1024]
+ */
+char *macro__buf;
+
+
+/*
+ * The number of quarks
+ */
+s16b quark__num;
+
+/*
+ * The pointers to the quarks [QUARK_MAX]
+ */
+cptr *quark__str;
+
+
+/*
+ * The next "free" index to use
+ */
+u16b message__next;
+
+/*
+ * The index of the oldest message (none yet)
+ */
+u16b message__last;
+
+/*
+ * The next "free" offset
+ */
+u16b message__head;
+
+/*
+ * The offset to the oldest used char (none yet)
+ */
+u16b message__tail;
+
+/*
+ * The array of offsets, by index [MESSAGE_MAX]
+ */
+u16b *message__ptr;
+
+/*
+ * The array of colors, by index [MESSAGE_MAX]
+ */
+byte *message__color;
+
+/*
+ * The array of type, by index [MESSAGE_MAX]
+ */
+byte *message__type;
+
+/*
+ * The array of message counts, by index [MESSAGE_MAX]
+ */
+u16b *message__count;
+
+/*
+ * The array of chars, by offset [MESSAGE_BUF]
+ */
+char *message__buf;
+
+
+/*
+ * The array of normal options
+ */
+u32b option_flag[8];
+u32b option_mask[8];
+
+
+/*
+ * The array of window options
+ */
+u32b window_flag[8];
+u32b window_mask[8];
+
+
+/*
+ * The array of window pointers
+ */
+term *angband_term[ANGBAND_TERM_MAX];
+
+
+/*
+ * Standard window names
+ */
+char angband_term_name[ANGBAND_TERM_MAX][80] =
+{
+ "ToME",
+ "Mirror",
+ "Recall",
+ "Choice",
+ "Term-4",
+ "Term-5",
+ "Term-6",
+ "Term-7"
+};
+
+
+/*
+ * Global table of color definitions
+ */
+byte angband_color_table[256][4] =
+{
+ {0x00, 0x00, 0x00, 0x00}, /* TERM_DARK */
+ {0x00, 0xFF, 0xFF, 0xFF}, /* TERM_WHITE */
+ {0x00, 0x80, 0x80, 0x80}, /* TERM_SLATE */
+ {0x00, 0xFF, 0x80, 0x00}, /* TERM_ORANGE */
+ {0x00, 0xC0, 0x00, 0x00}, /* TERM_RED */
+ {0x00, 0x00, 0x80, 0x40}, /* TERM_GREEN */
+ {0x00, 0x00, 0x00, 0xFF}, /* TERM_BLUE */
+ {0x00, 0x80, 0x40, 0x00}, /* TERM_UMBER */
+ {0x00, 0x40, 0x40, 0x40}, /* TERM_L_DARK */
+ {0x00, 0xC0, 0xC0, 0xC0}, /* TERM_L_WHITE */
+ {0x00, 0xFF, 0x00, 0xFF}, /* TERM_VIOLET */
+ {0x00, 0xFF, 0xFF, 0x00}, /* TERM_YELLOW */
+ {0x00, 0xFF, 0x00, 0x00}, /* TERM_L_RED */
+ {0x00, 0x00, 0xFF, 0x00}, /* TERM_L_GREEN */
+ {0x00, 0x00, 0xFF, 0xFF}, /* TERM_L_BLUE */
+ {0x00, 0xC0, 0x80, 0x40} /* TERM_L_UMBER */
+};
+
+
+/*
+ * Standard sound names
+ */
+char angband_sound_name[SOUND_MAX][16] =
+{
+ "",
+ "hit",
+ "miss",
+ "flee",
+ "drop",
+ "kill",
+ "level",
+ "death",
+ "study",
+ "teleport",
+ "shoot",
+ "quaff",
+ "zap",
+ "walk",
+ "tpother",
+ "hitwall",
+ "eat",
+ "store1",
+ "store2",
+ "store3",
+ "store4",
+ "dig",
+ "opendoor",
+ "shutdoor",
+ "tplevel",
+ "scroll",
+ "buy",
+ "sell",
+ "warn",
+ "rocket",
+ "n_kill",
+ "u_kill",
+ "quest",
+ "heal",
+ "x_heal",
+ "bite",
+ "claw",
+ "m_spell",
+ "summon",
+ "breath",
+ "ball",
+ "m_heal",
+ "atkspell",
+ "evil",
+ "touch",
+ "sting",
+ "crush",
+ "slime",
+ "wail",
+ "winner",
+ "fire",
+ "acid",
+ "elec",
+ "cold",
+ "illegal",
+ "fail",
+ "wakeup",
+ "invuln",
+ "fall",
+ "pain",
+ "destitem",
+ "moan",
+ "show",
+ "unused",
+ "explode",
+};
+
+
+/*
+ * The array of "cave grids" [MAX_WID][MAX_HGT].
+ * Not completely allocated, that would be inefficient
+ * Not completely hardcoded, that would overflow memory
+ */
+cave_type *cave[MAX_HGT];
+
+/*
+ * The array of dungeon items [max_o_idx]
+ */
+object_type *o_list;
+
+/*
+ * The array of dungeon monsters [max_m_idx]
+ */
+monster_type *m_list;
+
+/*
+ * The array of to keep monsters [max_m_idx]
+ */
+monster_type *km_list;
+
+
+/*
+ * Maximum number of towns
+ */
+u16b max_towns;
+u16b max_real_towns;
+
+/*
+ * The towns [max_towns]
+ */
+town_type *town_info;
+
+/*
+ * The size of "alloc_kind_table" (at most max_k_idx * 4)
+ */
+s16b alloc_kind_size;
+
+/*
+ * The entries in the "kind allocator table"
+ */
+alloc_entry *alloc_kind_table;
+
+/*
+ * The flag to tell if alloc_kind_table contains valid entries
+ * for normal (i.e. kind_is_legal) object allocation
+ */
+bool_ alloc_kind_table_valid = FALSE;
+
+
+/*
+ * The size of "alloc_race_table" (at most max_r_idx)
+ */
+s16b alloc_race_size;
+
+/*
+ * The entries in the "race allocator table"
+ */
+alloc_entry *alloc_race_table;
+
+
+/*
+ * Specify attr/char pairs for visual special effects
+ * Be sure to use "index & 0x7F" to avoid illegal access
+ */
+byte misc_to_attr[256];
+char misc_to_char[256];
+
+
+/*
+ * Specify attr/char pairs for inventory items (by tval)
+ * Be sure to use "index & 0x7F" to avoid illegal access
+ */
+byte tval_to_attr[128];
+char tval_to_char[128];
+
+
+/*
+ * Keymaps for each "mode" associated with each keypress.
+ */
+cptr keymap_act[KEYMAP_MODES][256];
+
+
+
+/*** Player information ***/
+
+/*
+ * Static player info record
+ */
+player_type p_body;
+
+/*
+ * Pointer to the player info
+ */
+player_type *p_ptr = &p_body;
+
+/*
+ * Pointer to the player tables
+ * (sex, race, race mod, class, magic)
+ */
+player_sex *sp_ptr;
+player_race *rp_ptr;
+player_race_mod *rmp_ptr;
+player_class *cp_ptr;
+player_spec *spp_ptr;
+
+
+/*
+ * More spell info
+ */
+u32b alchemist_known_egos[32];
+u32b alchemist_known_artifacts[6];
+u32b alchemist_gained;
+
+
+/*
+ * Calculated base hp values for player at each level,
+ * store them so that drain life + restore life does not
+ * affect hit points. Also prevents shameless use of backup
+ * savefiles for hitpoint acquirement.
+ */
+s16b player_hp[PY_MAX_LEVEL];
+
+/*
+ * The alchemy recipe arrays
+ */
+header *al_head;
+alchemist_recipe *alchemist_recipes;
+char *al_name;
+artifact_select_flag *a_select_flags;
+
+/*
+ * The vault generation arrays
+ */
+header *v_head;
+vault_type *v_info;
+char *v_name;
+char *v_text;
+
+/*
+ * The terrain feature arrays
+ */
+header *f_head;
+feature_type *f_info;
+char *f_name;
+char *f_text;
+
+/*
+ * The object kind arrays
+ */
+header *k_head;
+object_kind *k_info;
+char *k_name;
+char *k_text;
+
+/*
+ * The artifact arrays
+ */
+header *a_head;
+artifact_type *a_info;
+char *a_name;
+char *a_text;
+
+/*
+ * The item set arrays
+ */
+header *set_head;
+set_type *set_info;
+char *set_name;
+char *set_text;
+
+/*
+ * The ego-item arrays
+ */
+header *e_head;
+ego_item_type *e_info;
+char *e_name;
+char *e_text;
+
+/*
+ * The randart arrays
+ */
+header *ra_head;
+randart_part_type *ra_info;
+randart_gen_type ra_gen[30];
+
+/* jk */
+/* the trap-arrays */
+header *t_head;
+trap_type *t_info;
+char *t_name;
+char *t_text;
+
+/*
+ * The monster race arrays
+ */
+header *r_head;
+monster_race *r_info;
+char *r_name;
+char *r_text;
+
+/*
+ * The monster ego race arrays
+ */
+header *re_head;
+monster_ego *re_info;
+char *re_name;
+
+/*
+ * The dungeon types arrays
+ */
+header *d_head;
+dungeon_info_type *d_info;
+char *d_name;
+char *d_text;
+
+/*
+ * Player abilities arrays
+ */
+header *ab_head;
+ability_type *ab_info;
+char *ab_name;
+char *ab_text;
+
+/*
+ * Player skills arrays
+ */
+header *s_head;
+skill_type *s_info;
+char *s_name;
+char *s_text;
+
+/*
+ * Player race arrays
+ */
+header *rp_head;
+player_race *race_info;
+char *rp_name;
+char *rp_text;
+
+/*
+ * Player mod race arrays
+ */
+header *rmp_head;
+player_race_mod *race_mod_info;
+char *rmp_name;
+char *rmp_text;
+
+/*
+ * Player class arrays
+ */
+header *c_head;
+player_class *class_info;
+char *c_name;
+char *c_text;
+meta_class_type *meta_class_info;
+
+/*
+ * The wilderness features arrays
+ */
+header *wf_head;
+wilderness_type_info *wf_info;
+char *wf_name;
+char *wf_text;
+int wildc2i[256];
+
+/*
+ * The store/building types arrays
+ */
+header *st_head;
+store_info_type *st_info;
+char *st_name;
+/* char *st_text; */
+
+/*
+ * The building actions types arrays
+ */
+header *ba_head;
+store_action_type *ba_info;
+char *ba_name;
+/* char *ba_text; */
+
+/*
+ * The owner types arrays
+ */
+header *ow_head;
+owner_type *ow_info;
+char *ow_name;
+/* char *ow_text; */
+
+/*
+ * The dungeon types arrays
+ */
+header *d_head;
+dungeon_info_type *d_info;
+char *d_name;
+char *d_text;
+
+/*
+ * Hack -- The special Angband "System Suffix"
+ * This variable is used to choose an appropriate "pref-xxx" file
+ */
+cptr ANGBAND_SYS = "xxx";
+
+/*
+ * Hack -- The special Angband "Keyboard Suffix"
+ * This variable is used to choose an appropriate macro-trigger definition
+ */
+#ifdef JP
+cptr ANGBAND_KEYBOARD = "JAPAN";
+#else
+cptr ANGBAND_KEYBOARD = "0";
+#endif
+
+/*
+ * Hack -- The special Angband "Graphics Suffix"
+ * This variable is used to choose an appropriate "graf-xxx" file
+ */
+cptr ANGBAND_GRAF = "old";
+
+/*
+ * Path name: The main "lib" directory
+ * This variable is not actually used anywhere in the code
+ */
+cptr ANGBAND_DIR;
+
+/*
+ * High score files (binary)
+ * These files may be portable between platforms
+ */
+cptr ANGBAND_DIR_APEX;
+
+/*
+ * Core lua system
+ * These files are portable between platforms
+ */
+cptr ANGBAND_DIR_CORE;
+
+/*
+ * Textual dungeon level definition files
+ * These files are portable between platforms
+ */
+cptr ANGBAND_DIR_DNGN;
+
+/*
+ * Binary image files for the "*_info" arrays (binary)
+ * These files are not portable between platforms
+ */
+cptr ANGBAND_DIR_DATA;
+
+/*
+ * Textual template files for the "*_info" arrays (ascii)
+ * These files are portable between platforms
+ */
+cptr ANGBAND_DIR_EDIT;
+
+/*
+ * Various extra files (ascii)
+ * These files may be portable between platforms
+ */
+cptr ANGBAND_DIR_FILE;
+
+/*
+ * Help files (normal) for the online help (ascii)
+ * These files are portable between platforms
+ */
+cptr ANGBAND_DIR_HELP;
+
+/*
+ * Help files (spoilers) for the online help (ascii)
+ * These files are portable between platforms
+ */
+cptr ANGBAND_DIR_INFO;
+
+/*
+ * Modules, those subdirectories are half-mirrors of lib/
+ */
+cptr ANGBAND_DIR_MODULES;
+
+/*
+ * Patches, contains one subdir per patch with a patch.lua file
+ * in it and a patch_init() function in it
+ */
+cptr ANGBAND_DIR_PATCH;
+
+/*
+ * Textual template files for the plot files (ascii)
+ * These files are portable between platforms
+ */
+cptr ANGBAND_DIR_NOTE;
+
+/*
+ * Savefiles for current characters (binary)
+ * These files are portable between platforms
+ */
+cptr ANGBAND_DIR_SAVE;
+
+/*
+ * Scripts.
+ * These files are portable between platforms
+ */
+cptr ANGBAND_DIR_SCPT;
+
+/*
+ * Default "preference" files (ascii)
+ * These files are rarely portable between platforms
+ */
+cptr ANGBAND_DIR_PREF;
+
+/*
+ * User "preference" files (ascii)
+ * These files are rarely portable between platforms
+ */
+cptr ANGBAND_DIR_USER;
+
+/*
+ * Various extra files (binary)
+ * These files are rarely portable between platforms
+ */
+cptr ANGBAND_DIR_XTRA;
+
+/*
+ * Cmovie files of entire games (ascii)
+ * Apart from possible newline things, likely portable btw platforms
+ */
+
+cptr ANGBAND_DIR_CMOV;
+
+/*
+ * Some variables values are created on the fly XXX XXX
+ */
+
+char pref_tmp_value[8];
+
+
+
+/*
+ * Total Hack -- allow all items to be listed (even empty ones)
+ * This is only used by "do_cmd_inven_e()" and is cleared there.
+ */
+bool_ item_tester_full;
+
+
+/*
+ * Here is a "pseudo-hook" used during calls to "get_item()" and
+ * "show_inven()" and "show_equip()", and the choice window routines.
+ */
+byte item_tester_tval;
+
+
+/*
+ * Here is a "hook" used during calls to "get_item()" and
+ * "show_inven()" and "show_equip()", and the choice window routines.
+ */
+bool_ (*item_tester_hook)(object_type*);
+
+
+
+/*
+ * Current "comp" function for ang_sort()
+ */
+bool_ (*ang_sort_comp)(vptr u, vptr v, int a, int b);
+
+
+/*
+ * Current "swap" function for ang_sort()
+ */
+void (*ang_sort_swap)(vptr u, vptr v, int a, int b);
+
+
+
+/*
+ * Hack -- function hooks to restrict "get_mon_num_prep()" function
+ */
+bool_ (*get_mon_num_hook)(int r_idx);
+bool_ (*get_mon_num2_hook)(int r_idx);
+
+
+/*
+ * Hack -- function hook to restrict "get_obj_num_prep()" function
+ */
+bool_ (*get_obj_num_hook)(int k_idx);
+
+
+/* Hack, monk armour */
+bool_ monk_armour_aux;
+bool_ monk_notify_aux;
+
+bool_ easy_open = TRUE;
+bool_ easy_disarm = TRUE;
+bool_ easy_tunnel = FALSE;
+
+
+/*
+ * Maximum size of the wilderness map
+ */
+u16b max_wild_x;
+u16b max_wild_y;
+
+/*
+ * Wilderness map
+ */
+wilderness_map **wild_map;
+
+
+/*
+ * Maximum number of skills in s_info.txt
+ */
+u16b old_max_s_idx = 0;
+u16b max_s_idx;
+
+/*
+ * Maximum number of abilities in ab_info.txt
+ */
+u16b max_ab_idx;
+
+/*
+ * Maximum number of monsters in r_info.txt
+ */
+u16b max_r_idx;
+
+/*
+ * Maximum number of ego monsters in re_info.txt
+ */
+u16b max_re_idx;
+
+/*
+ * Maximum number of items in k_info.txt
+ */
+u16b max_k_idx;
+
+/*
+ * Maximum number of vaults in v_info.txt
+ */
+u16b max_v_idx;
+
+/*
+ * Maximum number of terrain features in f_info.txt
+ */
+u16b max_f_idx;
+
+/*
+ * Maximum number of alchemist recipies in al_info.txt
+ */
+u16b max_al_idx;
+
+/*
+ * Maximum number of artifacts in a_info.txt
+ */
+u16b max_a_idx;
+
+/*
+ * Maximum number of ego-items in e_info.txt
+ */
+u16b max_e_idx;
+
+/*
+ * Maximum number of randarts in ra_info.txt
+ */
+u16b max_ra_idx;
+
+/*
+ * Maximum number of dungeon types in d_info.txt
+ */
+u16b max_d_idx;
+
+/*
+ * Maximum number of stores types in st_info.txt
+ */
+u16b max_st_idx;
+
+/*
+ * Item sets
+ */
+s16b max_set_idx = 1;
+
+/*
+ * Maximum number of players info in p_info.txt
+ */
+u16b max_rp_idx;
+u16b max_rmp_idx;
+u16b max_c_idx;
+u16b max_mc_idx;
+
+/*
+ * Maximum number of actions types in ba_info.txt
+ */
+u16b max_ba_idx;
+
+/*
+ * Maximum number of owner types in ow_info.txt
+ */
+u16b max_ow_idx;
+
+/*
+ * Maximum number of objects in the level
+ */
+u16b max_o_idx;
+
+/*
+ * Maximum number of monsters in the level
+ */
+u16b max_m_idx;
+
+/*
+ * Maximum number of traps in tr_info.txt
+ */
+u16b max_t_idx;
+
+/*
+ * Maximum number of wilderness features in wf_info.txt
+ */
+u16b max_wf_idx;
+
+/*
+ * Flags for initialization
+ */
+int init_flags;
+
+/* True if on an ambush */
+bool_ ambush_flag;
+
+/* True if on fated level */
+bool_ fate_flag;
+
+/* No breeders */
+s16b no_breeds;
+
+/* Carried monsters can't take the damage if this is them which attack the player */
+bool_ carried_monster_hit = FALSE;
+
+/*
+ * Random artifacts.
+ */
+random_artifact random_artifacts[MAX_RANDARTS];
+/* These three used to be constants but now are set by modules */
+s32b RANDART_WEAPON;
+s32b RANDART_ARMOR;
+s32b RANDART_JEWEL;
+
+/*
+ * Current bounties. An array of tuples of two, with the first being the
+ * r_idx of the monster, and the second the monster's worth.
+ */
+s16b bounties[MAX_BOUNTIES][2];
+
+/*
+ * Spell description
+ */
+bool_ info_spell = FALSE;
+char spell_txt[50];
+
+/*
+ * Random spells.
+ */
+random_spell random_spells[MAX_SPELLS];
+s16b spell_num;
+
+/*
+ * Runecrafter's selfmade spells.
+ */
+rune_spell rune_spells[MAX_RUNES];
+s16b rune_num;
+
+/*
+ * Fate.
+ */
+fate fates[MAX_FATES];
+
+/*
+ * Which dungeon ?
+ * 0 = Wilderness
+ * 1 = Mirkwood
+ * 2 = Mordor
+ * 3 = Angband
+ * 4 = Barrow Downs
+ * 5 = Mount Doom
+ * 6 = Nether Realm
+ * etc. (see d_info.txt)
+ */
+byte dungeon_type;
+s16b *max_dlv;
+
+/*
+ * Number of total bounties the player had had.
+ */
+u32b total_bounties;
+
+/* The Doppleganger index in m_list */
+s16b doppleganger;
+
+/* To allow wilderness encounters */
+bool_ generate_encounter;
+
+/* Permanent dungeons ? */
+bool_ permanent_levels;
+
+/* Autoroler */
+bool_ autoroll;
+
+/* Point based */
+bool_ point_based;
+
+/* Maximize, preserve, special levels, ironman_rooms */
+bool_ maximize, preserve, special_lvls, ironman_rooms;
+
+/* In inventory option window, just erase the letters,
+ * rather that displaying the list without the invalid
+ * selections */
+bool_ inventory_no_move;
+
+/* Notes patch */
+bool_ take_notes, auto_notes;
+
+/*
+ * Such an ugly hack ...
+ */
+bool_ *m_allow_special;
+bool_ *k_allow_special;
+bool_ *a_allow_special;
+
+/*
+ * Gives a random object to newly created characters
+ */
+bool_ rand_birth;
+
+/*
+ * Fast autoroller
+ */
+bool_ fast_autoroller;
+
+/*
+ * Which monsters are allowed ?
+ */
+bool_ joke_monsters;
+
+/*
+ * How will mana staf & weapons of life act
+ */
+bool_ munchkin_multipliers = TRUE;
+
+/*
+ * Center view
+ */
+bool_ center_player = FALSE;
+
+/*
+ * Plots
+ */
+s16b plots[MAX_PLOTS];
+
+/*
+ * Random quest
+ */
+random_quest random_quests[MAX_RANDOM_QUEST];
+
+/*
+ * Show exp left
+ */
+bool_ exp_need;
+
+/*
+ * Auto load old colors;
+ */
+bool_ autoload_old_colors;
+
+/*
+ * Fated ?
+ */
+bool_ fate_option;
+
+/*
+ * Special levels
+ */
+bool_ *special_lvl[MAX_DUNGEON_DEPTH];
+bool_ generate_special_feeling = FALSE;
+
+/*
+ * Auto more
+ */
+bool_ auto_more;
+
+/*
+ * Dungeon flags
+ */
+u32b dungeon_flags1;
+u32b dungeon_flags2;
+
+/*
+ * The last character displayed
+ */
+birther previous_char;
+
+/*
+ * Race histories
+ */
+hist_type *bg;
+int max_bg_idx;
+
+/*
+ * Powers
+ */
+s16b power_max = POWER_MAX_INIT;
+power_type *powers_type;
+
+/*
+ * Variable savefile stuff
+ */
+s32b extra_savefile_parts = 0;
+
+/*
+ * Quests
+ */
+s16b max_q_idx = MAX_Q_IDX_INIT;
+quest_type *quest;
+
+/*
+ * Display the player as a special symbol when in bad health ?
+ */
+bool_ player_char_health;
+
+
+/*
+ * The spell list of schools
+ */
+s16b max_spells;
+spell_type *school_spells;
+s16b max_schools;
+school_type *schools;
+
+/*
+ * Lasting spell effects
+ */
+int project_time = 0;
+s32b project_time_effect = 0;
+effect_type effects[MAX_EFFECTS];
+
+/*
+ * General skills set
+ */
+char gen_skill_basem[MAX_SKILLS];
+u32b gen_skill_base[MAX_SKILLS];
+char gen_skill_modm[MAX_SKILLS];
+s16b gen_skill_mod[MAX_SKILLS];
+
+/*
+ * Display stats as linear
+ */
+bool_ linear_stats;
+
+/*
+ * Table of "cli" macros.
+ */
+cli_comm *cli_info;
+int cli_total = 0;
+
+/*
+ * max_bact, only used so that lua scripts can add new bacts without worrying about the numbers
+ */
+int max_bact = 54;
+
+/*
+ * Max corruptions
+ */
+s16b max_corruptions = 0;
+
+/*
+ * Ingame contextual help
+ */
+bool_ option_ingame_help = TRUE;
+
+/*
+ * Automatizer enabled status
+ */
+bool_ automatizer_enabled = FALSE;
+
+/*
+ * Location of the last teleportation thath affected the level
+ */
+s16b last_teleportation_y = -1;
+s16b last_teleportation_x = -1;
+
+/*
+ * The current game module
+ */
+cptr game_module;
+s32b VERSION_MAJOR;
+s32b VERSION_MINOR;
+s32b VERSION_PATCH;
+
+/*
+ * Some module info
+ */
+s32b max_plev = 50;
+s32b DUNGEON_DEATH = 28;
+
+/*
+ * Gods
+ */
+deity_type *deity_info;
+s32b max_gods = MAX_GODS_INIT;
+
+/*
+ * Timers
+ */
+timer_type *gl_timers = NULL;
+
+/**
+ * Get the version string.
+ */
+const char *get_version_string()
+{
+ static char version_str[80];
+ static bool_ initialized = 0;
+ if (!initialized) {
+ sprintf(version_str, "%s %ld.%ld.%ld%s",
+ game_module,
+ (long int) VERSION_MAJOR,
+ (long int) VERSION_MINOR,
+ (long int) VERSION_PATCH, IS_CVS);
+ initialized = TRUE;
+ }
+ return version_str;
+}
diff --git a/src/wild.c b/src/wild.c
new file mode 100644
index 00000000..7a9d1c51
--- /dev/null
+++ b/src/wild.c
@@ -0,0 +1,1275 @@
+/* File: generate.c */
+
+/* Purpose: Wilderness & Town related things */
+
+/*
+ * Copyright (c) 2001 James E. Wilson, Robert A. Koeneke, DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+
+/*
+ * Various defines for the wilderness
+ */
+#define DUN_WILD_VAULT 50 /* Chance of finding a wilderness vault. */
+
+/*
+ * Various defines for the towns
+ */
+#define TOWN_NORMAL_FLOOR 70
+#define TOWN_BORDER 90
+
+
+/*
+ * Helper for plasma generation.
+ */
+static void perturb_point_mid(int x1, int x2, int x3, int x4,
+ int xmid, int ymid, int rough, int depth_max)
+{
+ /*
+ * Average the four corners & perturb it a bit.
+ * tmp is a random int +/- rough
+ */
+ int tmp2 = rough * 2 + 1;
+ int tmp = randint(tmp2) - (rough + 1);
+
+ int avg = ((x1 + x2 + x3 + x4) / 4) + tmp;
+
+ /* Division always rounds down, so we round up again */
+ if (((x1 + x2 + x3 + x4) % 4) > 1) avg++;
+
+ /* Normalize */
+ if (avg < 0) avg = 0;
+ if (avg > depth_max) avg = depth_max;
+
+ /* Set the new value. */
+ cave[ymid][xmid].feat = (byte)avg;
+}
+
+
+static void perturb_point_end(int x1, int x2, int x3,
+ int xmid, int ymid, int rough, int depth_max)
+{
+ /*
+ * Average the three corners & perturb it a bit.
+ * tmp is a random int +/- rough
+ */
+ int tmp2 = rough * 2 + 1;
+ int tmp = randint(tmp2) - (rough + 1);
+
+ int avg = ((x1 + x2 + x3) / 3) + tmp;
+
+ /* Division always rounds down, so we round up again */
+ if ((x1 + x2 + x3) % 3) avg++;
+
+ /* Normalize */
+ if (avg < 0) avg = 0;
+ if (avg > depth_max) avg = depth_max;
+
+ /* Set the new value. */
+ cave[ymid][xmid].feat = (byte)avg;
+}
+
+
+/*
+ * A generic function to generate the plasma fractal.
+ * Note that it uses ``cave_feat'' as temporary storage.
+ * The values in ``cave_feat'' after this function
+ * are NOT actual features; They are raw heights which
+ * need to be converted to features.
+ *
+ * So we shouldn't call cave_set_feat in the helper functions
+ * above.
+ */
+static void plasma_recursive(int x1, int y1, int x2, int y2,
+ int depth_max, int rough)
+{
+ /* Find middle */
+ int xmid = (x2 - x1) / 2 + x1;
+ int ymid = (y2 - y1) / 2 + y1;
+
+ /* Are we done? */
+ if (x1 + 1 == x2) return;
+
+ perturb_point_mid(cave[y1][x1].feat, cave[y2][x1].feat, cave[y1][x2].feat,
+ cave[y2][x2].feat, xmid, ymid, rough, depth_max);
+
+ perturb_point_end(cave[y1][x1].feat, cave[y1][x2].feat, cave[ymid][xmid].feat,
+ xmid, y1, rough, depth_max);
+
+ perturb_point_end(cave[y1][x2].feat, cave[y2][x2].feat, cave[ymid][xmid].feat,
+ x2, ymid, rough, depth_max);
+
+ perturb_point_end(cave[y2][x2].feat, cave[y2][x1].feat, cave[ymid][xmid].feat,
+ xmid, y2, rough, depth_max);
+
+ perturb_point_end(cave[y2][x1].feat, cave[y1][x1].feat, cave[ymid][xmid].feat,
+ x1, ymid, rough, depth_max);
+
+
+ /* Recurse the four quadrants */
+ plasma_recursive(x1, y1, xmid, ymid, depth_max, rough);
+ plasma_recursive(xmid, y1, x2, ymid, depth_max, rough);
+ plasma_recursive(x1, ymid, xmid, y2, depth_max, rough);
+ plasma_recursive(xmid, ymid, x2, y2, depth_max, rough);
+}
+
+
+/*
+ * Load a town or generate a terrain level using "plasma" fractals.
+ *
+ * x and y are the coordinates of the area in the wilderness.
+ * Border and corner are optimization flags to speed up the
+ * generation of the fractal terrain.
+ * If border is set then only the border of the terrain should
+ * be generated (for initializing the border structure).
+ * If corner is set then only the corners of the area are needed.
+ *
+ * Return the number of floor grids
+ */
+int generate_area(int y, int x, bool_ border, bool_ corner, bool_ refresh)
+{
+ int road, entrance;
+ int x1, y1;
+ int hack_floor = 0;
+
+ /* Number of the town (if any) */
+ p_ptr->town_num = wf_info[wild_map[y][x].feat].entrance;
+ if (!p_ptr->town_num) p_ptr->town_num = wild_map[y][x].entrance;
+
+ {
+ int roughness = 1; /* The roughness of the level. */
+ int terrain[3][3]; /* The terrain around the current area */
+ int ym, xm, yp, xp;
+
+ /* Place the player at the center */
+ if (!p_ptr->oldpx) p_ptr->oldpx = MAX_WID / 2;
+ if (!p_ptr->oldpy) p_ptr->oldpy = MAX_HGT / 2;
+
+ /* Initialize the terrain array */
+ ym = ((y - 1) < 0) ? 0 : (y - 1);
+ xm = ((x - 1) < 0) ? 0 : (x - 1);
+ yp = ((y + 1) >= max_wild_y) ? (max_wild_y - 1) : (y + 1);
+ xp = ((x + 1) >= max_wild_x) ? (max_wild_x - 1) : (x + 1);
+ terrain[0][0] = wild_map[ym][xm].feat;
+ terrain[0][1] = wild_map[ym][x].feat;
+ terrain[0][2] = wild_map[ym][xp].feat;
+ terrain[1][0] = wild_map[y][xm].feat;
+ terrain[1][1] = wild_map[y][x].feat;
+ terrain[1][2] = wild_map[y][xp].feat;
+ terrain[2][0] = wild_map[yp][xm].feat;
+ terrain[2][1] = wild_map[yp][x].feat;
+ terrain[2][2] = wild_map[yp][xp].feat;
+
+ /* Hack -- Use the "simple" RNG */
+ Rand_quick = TRUE;
+
+ /* Hack -- Induce consistant town layout */
+ Rand_value = wild_map[y][x].seed;
+
+ if (!corner)
+ {
+ /* Create level background */
+ for (y1 = 0; y1 < MAX_HGT; y1++)
+ {
+ for (x1 = 0; x1 < MAX_WID; x1++)
+ {
+ cave_set_feat(y1, x1, MAX_WILD_TERRAIN / 2);
+ }
+ }
+ }
+
+ /*
+ * Initialize the four corners
+ * ToDo: calculate the medium height of the adjacent
+ * terrains for every corner.
+ */
+ cave_set_feat(1, 1, (byte)rand_int(MAX_WILD_TERRAIN));
+ cave_set_feat(MAX_HGT - 2, 1, (byte)rand_int(MAX_WILD_TERRAIN));
+ cave_set_feat(1, MAX_WID - 2, (byte)rand_int(MAX_WILD_TERRAIN));
+ cave_set_feat(MAX_HGT - 2, MAX_WID - 2, (byte)rand_int(MAX_WILD_TERRAIN));
+
+ if (!corner)
+ {
+ /* x1, y1, x2, y2, num_depths, roughness */
+ plasma_recursive(1, 1, MAX_WID - 2, MAX_HGT - 2, MAX_WILD_TERRAIN - 1, roughness);
+ }
+
+ /* Use the complex RNG */
+ Rand_quick = FALSE;
+
+ for (y1 = 1; y1 < MAX_HGT - 1; y1++)
+ {
+ for (x1 = 1; x1 < MAX_WID - 1; x1++)
+ {
+ cave_set_feat(y1, x1,
+ wf_info[terrain[1][1]].terrain[cave[y1][x1].feat]);
+ }
+ }
+
+ }
+
+ /* Should we create a town ? */
+ if ((p_ptr->town_num > 0) && (p_ptr->town_num < 1000))
+ {
+ /* Create the town */
+ int xstart = 0;
+ int ystart = 0;
+
+ /* Initialize the town */
+ init_flags = INIT_CREATE_DUNGEON;
+ process_dungeon_file("t_info.txt", &ystart, &xstart, cur_hgt, cur_wid, TRUE, FALSE);
+ }
+ else
+ {
+ /* Reset the town flag */
+ p_ptr->town_num = 0;
+ }
+
+ if (!corner)
+ {
+ /*
+ * Place roads in the wilderness
+ * ToDo: make the road a bit more interresting
+ */
+ road = wf_info[wild_map[y][x].feat].road;
+
+ if (road & ROAD_NORTH)
+ {
+ /* North road */
+ for (y1 = 1; y1 < MAX_HGT / 2; y1++)
+ {
+ x1 = MAX_WID / 2;
+ cave_set_feat(y1, x1, FEAT_FLOOR);
+ }
+ }
+
+ if (road & ROAD_SOUTH)
+ {
+ /* North road */
+ for (y1 = MAX_HGT / 2; y1 < MAX_HGT - 1; y1++)
+ {
+ x1 = MAX_WID / 2;
+ cave_set_feat(y1, x1, FEAT_FLOOR);
+ }
+ }
+
+ if (road & ROAD_EAST)
+ {
+ /* East road */
+ for (x1 = MAX_WID / 2; x1 < MAX_WID - 1; x1++)
+ {
+ y1 = MAX_HGT / 2;
+ cave_set_feat(y1, x1, FEAT_FLOOR);
+ }
+ }
+
+ if (road & ROAD_WEST)
+ {
+ /* West road */
+ for (x1 = 1; x1 < MAX_WID / 2; x1++)
+ {
+ y1 = MAX_HGT / 2;
+ cave_set_feat(y1, x1, FEAT_FLOOR);
+ }
+ }
+ }
+
+ /* Hack -- Use the "simple" RNG */
+ Rand_quick = TRUE;
+
+ /* Hack -- Induce consistant town layout */
+ Rand_value = wild_map[y][x].seed;
+
+ entrance = wf_info[wild_map[y][x].feat].entrance;
+ if (!entrance) entrance = wild_map[y][x].entrance;
+
+ /* Create the dungeon if requested on the map */
+ if (entrance >= 1000)
+ {
+ int dy, dx;
+
+ dy = rand_range(6, cur_hgt - 6);
+ dx = rand_range(6, cur_wid - 6);
+
+ cave_set_feat(dy, dx, FEAT_MORE);
+ cave[dy][dx].special = entrance - 1000;
+ cave[dy][dx].info |= (CAVE_GLOW | CAVE_MARK);
+ }
+
+ /* Use the complex RNG */
+ Rand_quick = FALSE;
+
+ /* MEGA HACK -- set at least one floor grid */
+ for (y1 = 1; y1 < cur_hgt - 1; y1++)
+ {
+ for (x1 = 1; x1 < cur_wid - 1; x1++)
+ {
+ if (cave_floor_bold(y1, x1)) hack_floor++;
+ }
+ }
+
+ /* NO floor ? put one */
+ if (!hack_floor)
+ {
+ cave_set_feat(cur_hgt / 2, cur_wid / 2, FEAT_GRASS);
+ cave[cur_hgt / 2][cur_wid / 2].special = 0;
+ hack_floor = 1;
+ }
+
+ /* Set the monster generation level to the wilderness level */
+ monster_level = wf_info[wild_map[y][x].feat].level;
+
+ /* Set the object generation level to the wilderness level */
+ object_level = wf_info[wild_map[y][x].feat].level;
+
+ return hack_floor;
+}
+
+/*
+ * Border of the wilderness area
+ */
+static border_type border;
+
+/*
+ * Build the wilderness area outside of the town.
+ * -KMW-
+ */
+void wilderness_gen(int refresh)
+{
+ int i, y, x, hack_floor;
+ bool_ daytime;
+ int xstart = 0;
+ int ystart = 0;
+ cave_type *c_ptr;
+
+ /* Init the wilderness */
+ process_dungeon_file("w_info.txt", &ystart, &xstart, cur_hgt, cur_wid, TRUE, FALSE);
+
+ x = p_ptr->wilderness_x;
+ y = p_ptr->wilderness_y;
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* North border */
+ generate_area(y - 1, x, TRUE, FALSE, refresh);
+
+ for (i = 1; i < MAX_WID - 1; i++)
+ {
+ border.north[i] = cave[MAX_HGT - 2][i].feat;
+ }
+
+ /* South border */
+ generate_area(y + 1, x, TRUE, FALSE, refresh);
+
+ for (i = 1; i < MAX_WID - 1; i++)
+ {
+ border.south[i] = cave[1][i].feat;
+ }
+
+ /* West border */
+ generate_area(y, x - 1, TRUE, FALSE, refresh);
+
+ for (i = 1; i < MAX_HGT - 1; i++)
+ {
+ border.west[i] = cave[i][MAX_WID - 2].feat;
+ }
+
+ /* East border */
+ generate_area(y, x + 1, TRUE, FALSE, refresh);
+
+ for (i = 1; i < MAX_HGT - 1; i++)
+ {
+ border.east[i] = cave[i][1].feat;
+ }
+
+ /* North west corner */
+ generate_area(y - 1, x - 1, FALSE, TRUE, refresh);
+ border.north_west = cave[MAX_HGT - 2][MAX_WID - 2].feat;
+
+ /* North east corner */
+ generate_area(y - 1, x + 1, FALSE, TRUE, refresh);
+ border.north_east = cave[MAX_HGT - 2][1].feat;
+
+ /* South west corner */
+ generate_area(y + 1, x - 1, FALSE, TRUE, refresh);
+ border.south_west = cave[1][MAX_WID - 2].feat;
+
+ /* South east corner */
+ generate_area(y + 1, x + 1, FALSE, TRUE, refresh);
+ border.south_east = cave[1][1].feat;
+
+
+ /* Create terrain of the current area */
+ hack_floor = generate_area(y, x, FALSE, FALSE, refresh);
+
+
+ /* Special boundary walls -- North */
+ for (i = 0; i < MAX_WID; i++)
+ {
+ cave[0][i].mimic = border.north[i];
+ cave_set_feat(0, i, FEAT_PERM_SOLID);
+ }
+
+ /* Special boundary walls -- South */
+ for (i = 0; i < MAX_WID; i++)
+ {
+ cave[MAX_HGT - 1][i].mimic = border.south[i];
+ cave_set_feat(MAX_HGT - 1, i, FEAT_PERM_SOLID);
+ }
+
+ /* Special boundary walls -- West */
+ for (i = 0; i < MAX_HGT; i++)
+ {
+ cave[i][0].mimic = border.west[i];
+ cave_set_feat(i, 0, FEAT_PERM_SOLID);
+ }
+
+ /* Special boundary walls -- East */
+ for (i = 0; i < MAX_HGT; i++)
+ {
+ cave[i][MAX_WID - 1].mimic = border.east[i];
+ cave_set_feat(i, MAX_WID - 1, FEAT_PERM_SOLID);
+ }
+
+ /* North west corner */
+ cave[0][0].mimic = border.north_west;
+
+ /* Make sure it has correct CAVE_WALL flag set */
+ cave_set_feat(0, 0, cave[0][0].feat);
+
+ /* North east corner */
+ cave[0][MAX_WID - 1].mimic = border.north_east;
+
+ /* Make sure it has correct CAVE_WALL flag set */
+ cave_set_feat(0, MAX_WID - 1, cave[0][MAX_WID - 1].feat);
+
+ /* South west corner */
+ cave[MAX_HGT - 1][0].mimic = border.south_west;
+
+ /* Make sure it has correct CAVE_WALL flag set */
+ cave_set_feat(MAX_HGT - 1, 0, cave[MAX_HGT - 1][0].feat);
+
+ /* South east corner */
+ cave[MAX_HGT - 1][MAX_WID - 1].mimic = border.south_east;
+
+ /* Make sure it has correct CAVE_WALL flag set */
+ cave_set_feat(MAX_HGT - 1, MAX_WID - 1, cave[MAX_HGT - 1][MAX_WID - 1].feat);
+
+
+ /* Day time */
+ if ((turn % (10L * DAY)) < ((10L * DAY) / 2))
+ daytime = TRUE;
+ else
+ daytime = FALSE;
+
+ /* Light up or darken the area */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ /* Get the cave grid */
+ c_ptr = &cave[y][x];
+
+ if (daytime)
+ {
+ /* Assume lit */
+ c_ptr->info |= (CAVE_GLOW);
+
+ /* Hack -- Memorize lit grids if allowed */
+ if (view_perma_grids) c_ptr->info |= (CAVE_MARK);
+ }
+ else
+ {
+ /* Darken "boring" features */
+ if (!(f_info[c_ptr->feat].flags1 & FF1_REMEMBER))
+ {
+ /* Forget the grid */
+ c_ptr->info &= ~(CAVE_GLOW | CAVE_MARK);
+ }
+ }
+ }
+ }
+
+ player_place(p_ptr->oldpy, p_ptr->oldpx);
+
+ if (!refresh)
+ {
+ int lim = (generate_encounter == TRUE) ? 60 : MIN_M_ALLOC_TN;
+
+ /*
+ * Can't have more monsters than floor grids -1(for the player,
+ * not needed but safer
+ */
+ if (lim > hack_floor - 1) lim = hack_floor - 1;
+
+ /* Make some residents */
+ for (i = 0; i < lim; i++)
+ {
+ /* Make a resident */
+ (void)alloc_monster((generate_encounter == TRUE) ? 0 : 3, (generate_encounter == TRUE) ? FALSE : TRUE);
+ }
+
+ if (generate_encounter) ambush_flag = TRUE;
+ generate_encounter = FALSE;
+ }
+
+ /* Set rewarded quests to finished */
+ for (i = 0; i < max_q_idx; i++)
+ {
+ if (quest[i].status == QUEST_STATUS_REWARDED)
+ quest[i].status = QUEST_STATUS_FINISHED;
+ }
+
+ process_hooks(HOOK_WILD_GEN, "(d)", FALSE);
+}
+
+/*
+ * Build the wilderness area.
+ * -DG-
+ */
+void wilderness_gen_small()
+{
+ int i, j, entrance;
+ int xstart = 0;
+ int ystart = 0;
+
+ /* To prevent stupid things */
+ for (i = 0; i < MAX_WID; i++)
+ {
+ for (j = 0; j < MAX_HGT; j++)
+ {
+ cave_set_feat(j, i, FEAT_EKKAIA);
+ }
+ }
+
+ /* Init the wilderness */
+ process_dungeon_file("w_info.txt", &ystart, &xstart, cur_hgt, cur_wid, TRUE, FALSE);
+
+ /* Fill the map */
+ for (i = 0; i < max_wild_x; i++)
+ {
+ for (j = 0; j < max_wild_y; j++)
+ {
+ entrance = wf_info[wild_map[j][i].feat].entrance;
+ if (!entrance) entrance = wild_map[j][i].entrance;
+
+ if (wild_map[j][i].entrance)
+ {
+ cave_set_feat(j, i, FEAT_MORE);
+ }
+ else
+ {
+ cave_set_feat(j, i, wf_info[wild_map[j][i].feat].feat);
+ }
+
+ if ((cave[j][i].feat == FEAT_MORE) && (entrance >= 1000))
+ {
+ cave[j][i].special = entrance - 1000;
+ }
+
+ /* Show it if we know it */
+ if (wild_map[j][i].known)
+ {
+ cave[j][i].info |= (CAVE_GLOW | CAVE_MARK);
+ }
+ }
+ }
+
+ /* Place the player */
+ p_ptr->px = p_ptr->wilderness_x;
+ p_ptr->py = p_ptr->wilderness_y;
+
+ /* Set rewarded quests to finished */
+ for (i = 0; i < max_q_idx; i++)
+ {
+ if (quest[i].status == QUEST_STATUS_REWARDED)
+ quest[i].status = QUEST_STATUS_FINISHED;
+ }
+
+ process_hooks(HOOK_WILD_GEN, "(d)", TRUE);
+}
+
+/* Show a small radius of wilderness around the player */
+void reveal_wilderness_around_player(int y, int x, int h, int w)
+{
+ int i, j;
+
+ /* Circle or square ? */
+ if (h == 0)
+ {
+ for (i = x - w; i < x + w; i++)
+ {
+ for (j = y - w; j < y + w; j++)
+ {
+ /* Bound checking */
+ if (!in_bounds(j, i)) continue;
+
+ /* Severe bound checking */
+ if ((i < 0) || (i >= max_wild_x) || (j < 0) || (j >= max_wild_y)) continue;
+
+ /* We want a radius, not a "squarus" :) */
+ if (distance(y, x, j, i) >= w) continue;
+
+ /* New we know here */
+ wild_map[j][i].known = TRUE;
+
+ /* Only if we are in overview */
+ if (p_ptr->wild_mode)
+ {
+ cave[j][i].info |= (CAVE_GLOW | CAVE_MARK);
+
+ /* Show it */
+ lite_spot(j, i);
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = x; i < x + w; i++)
+ {
+ for (j = y; j < y + h; j++)
+ {
+ /* Bound checking */
+ if (!in_bounds(j, i)) continue;
+
+ /* New we know here */
+ wild_map[j][i].known = TRUE;
+
+ /* Only if we are in overview */
+ if (p_ptr->wild_mode)
+ {
+ cave[j][i].info |= (CAVE_GLOW | CAVE_MARK);
+
+ /* Show it */
+ lite_spot(j, i);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Builds a store at a given pseudo-location
+ *
+ * As of 2.8.1 (?) the town is actually centered in the middle of a
+ * complete level, and thus the top left corner of the town itself
+ * is no longer at (0,0), but rather, at (qy,qx), so the constants
+ * in the comments below should be mentally modified accordingly.
+ *
+ * As of 2.7.4 (?) the stores are placed in a more "user friendly"
+ * configuration, such that the four "center" buildings always
+ * have at least four grids between them, to allow easy running,
+ * and the store doors tend to face the middle of town.
+ *
+ * The stores now lie inside boxes from 3-9 and 12-18 vertically,
+ * and from 7-17, 21-31, 35-45, 49-59. Note that there are thus
+ * always at least 2 open grids between any disconnected walls.
+ *
+ * Note the use of "town_illuminate()" to handle all "illumination"
+ * and "memorization" issues.
+ */
+static void build_store(int qy, int qx, int n, int yy, int xx)
+{
+ int y, x, y0, x0, y1, x1, y2, x2, tmp;
+
+ /* Find the "center" of the store */
+ y0 = qy + yy * 9 + 6;
+ x0 = qx + xx * 14 + 12;
+
+ /* Determine the store boundaries */
+ y1 = y0 - randint((yy == 0) ? 3 : 2);
+ y2 = y0 + randint((yy == 1) ? 3 : 2);
+ x1 = x0 - randint(5);
+ x2 = x0 + randint(5);
+
+ /* Build an invulnerable rectangular building */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ /* Create the building */
+ cave_set_feat(y, x, FEAT_PERM_EXTRA);
+ }
+ }
+
+ /* Pick a door direction (S,N,E,W) */
+ tmp = rand_int(4);
+
+ /* Re-roll "annoying" doors */
+ if (((tmp == 0) && (yy == 1)) ||
+ ((tmp == 1) && (yy == 0)) ||
+ ((tmp == 2) && (xx == 3)) ||
+ ((tmp == 3) && (xx == 0)))
+ {
+ /* Pick a new direction */
+ tmp = rand_int(4);
+ }
+
+ /* Extract a "door location" */
+ switch (tmp)
+ {
+ /* Bottom side */
+ case 0:
+ {
+ y = y2;
+ x = rand_range(x1, x2);
+ break;
+ }
+
+ /* Top side */
+ case 1:
+ {
+ y = y1;
+ x = rand_range(x1, x2);
+ break;
+ }
+
+ /* Right side */
+ case 2:
+ {
+ y = rand_range(y1, y2);
+ x = x2;
+ break;
+ }
+
+ /* Left side */
+ default:
+ {
+ y = rand_range(y1, y2);
+ x = x1;
+ break;
+ }
+ }
+
+ /* Clear previous contents, add a store door */
+ cave_set_feat(y, x, FEAT_SHOP);
+ cave[y][x].special = n;
+ cave[y][x].info |= CAVE_FREE;
+}
+
+static void build_store_circle(int qy, int qx, int n, int yy, int xx)
+{
+ int tmp, y, x, y0, x0, rad = 2 + rand_int(2);
+
+ /* Find the "center" of the store */
+ y0 = qy + yy * 9 + 6;
+ x0 = qx + xx * 14 + 12;
+
+ /* Determine the store boundaries */
+
+ /* Build an invulnerable circular building */
+ for (y = y0 - rad; y <= y0 + rad; y++)
+ {
+ for (x = x0 - rad; x <= x0 + rad; x++)
+ {
+ if (distance(y0, x0, y, x) > rad) continue;
+
+ /* Create the building */
+ cave_set_feat(y, x, FEAT_PERM_EXTRA);
+ }
+ }
+
+ /* Pick a door direction (S,N,E,W) */
+ tmp = rand_int(4);
+
+ /* Re-roll "annoying" doors */
+ if (((tmp == 0) && (yy == 1)) ||
+ ((tmp == 1) && (yy == 0)) ||
+ ((tmp == 2) && (xx == 3)) ||
+ ((tmp == 3) && (xx == 0)))
+ {
+ /* Pick a new direction */
+ tmp = rand_int(4);
+ }
+
+ /* Extract a "door location" */
+ switch (tmp)
+ {
+ /* Bottom side */
+ case 0:
+ {
+ for (y = y0; y <= y0 + rad; y++) cave_set_feat(y, x0, FEAT_FLOOR);
+ break;
+ }
+
+ /* Top side */
+ case 1:
+ {
+ for (y = y0 - rad; y <= y0; y++) cave_set_feat(y, x0, FEAT_FLOOR);
+ break;
+ }
+
+ /* Right side */
+ case 2:
+ {
+ for (x = x0; x <= x0 + rad; x++) cave_set_feat(y0, x, FEAT_FLOOR);
+ break;
+ }
+
+ /* Left side */
+ default:
+ {
+ for (x = x0 - rad; x <= x0; x++) cave_set_feat(y0, x, FEAT_FLOOR);
+ break;
+ }
+ }
+
+ /* Clear previous contents, add a store door */
+ cave_set_feat(y0, x0, FEAT_SHOP);
+ cave[y0][x0].special = n;
+ cave[y0][x0].info |= CAVE_FREE;
+}
+
+static void build_store_hidden(int n, int yy, int xx)
+{
+ /* Clear previous contents, add a store door */
+ cave_set_feat(yy, xx, FEAT_SHOP);
+ cave[yy][xx].special = n;
+ cave[yy][xx].info |= CAVE_FREE;
+}
+
+/* Return a list of stores */
+static int get_shops(int *rooms)
+{
+ int i, n, num = 0;
+
+ for (n = 0; n < max_st_idx; n++)
+ {
+ rooms[n] = 0;
+ }
+
+ for (n = 0; n < max_st_idx; n++)
+ {
+ int chance = 50;
+
+ if (st_info[n].flags1 & SF1_COMMON) chance += 30;
+ if (st_info[n].flags1 & SF1_RARE) chance -= 20;
+ if (st_info[n].flags1 & SF1_VERY_RARE) chance -= 30;
+
+ if (!magik(chance)) continue;
+
+ for (i = 0; i < num; ++i)
+ if (rooms[i] == n)
+ continue;
+
+ if (st_info[n].flags1 & SF1_RANDOM) rooms[num++] = n;
+ }
+
+ return num;
+}
+
+/* Generate town borders */
+static void set_border(int y, int x)
+{
+ cave_type *c_ptr;
+
+ /* Paranoia */
+ if (!in_bounds(y, x)) return;
+
+ /* Was a floor */
+ if (cave_floor_bold(y, x) ||
+ (f_info[cave[y][x].feat].flags1 & FF1_DOOR))
+ {
+ cave_set_feat(y, x, FEAT_DOOR_HEAD);
+ }
+
+ /* Was a wall */
+ else
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+
+ }
+
+ /* Access grid */
+ c_ptr = &cave[y][x];
+
+ /* Clear special attrs */
+ c_ptr->mimic = 0;
+ c_ptr->special = 0;
+ c_ptr->info |= (CAVE_ROOM);
+}
+
+
+static void town_borders(int t_idx, int qy, int qx)
+{
+ int y, x;
+
+ x = qx;
+ for (y = qy; y < qy + SCREEN_HGT - 1; y++)
+ {
+ set_border(y, x);
+ }
+
+ x = qx + SCREEN_WID - 1;
+ for (y = qy; y < qy + SCREEN_HGT - 1; y++)
+ {
+ set_border(y, x);
+ }
+
+ y = qy;
+ for (x = qx; x < qx + SCREEN_WID - 1; x++)
+ {
+ set_border(y, x);
+ }
+
+ y = qy + SCREEN_HGT - 1;
+ for (x = qx; x < qx + SCREEN_WID; x++)
+ {
+ set_border(y, x);
+ }
+}
+
+static bool_ create_townpeople_hook(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ if (r_ptr->d_char == 't') return TRUE;
+ else return FALSE;
+}
+
+
+/*
+ * Generate the "consistent" town features, and place the player
+ *
+ * Hack -- play with the R.N.G. to always yield the same town
+ * layout, including the size and shape of the buildings, the
+ * locations of the doorways, and the location of the stairs.
+ */
+static void town_gen_hack(int t_idx, int qy, int qx)
+{
+ int y, x, floor, num = 0;
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+
+ int *rooms;
+
+ /* Do we use dungeon floor or normal one */
+ if (magik(TOWN_NORMAL_FLOOR)) floor = FEAT_FLOOR;
+ else floor = 0;
+
+ /* Place some floors */
+ for (y = qy + 1; y < qy + SCREEN_HGT - 1; y++)
+ {
+ for (x = qx + 1; x < qx + SCREEN_WID - 1; x++)
+ {
+ /* Create empty floor */
+ cave_set_feat(y, x, (floor) ? floor : floor_type[rand_int(100)]);
+ cave[y][x].info |= (CAVE_ROOM | CAVE_FREE);
+ }
+ }
+
+ /* Prepare an Array of "remaining stores", and count them */
+ C_MAKE(rooms, max_st_idx, int);
+ num = get_shops(rooms);
+
+ /* Place two rows of stores */
+ for (y = 0; y < 2; y++)
+ {
+ /* Place four stores per row */
+ for (x = 0; x < 4; x++)
+ {
+ if(--num > -1)
+ {
+ /* Build that store at the proper location */
+ build_store(qy, qx, rooms[num], y, x);
+ }
+ }
+ }
+ C_FREE(rooms, max_st_idx, int);
+
+ /* Generates the town's borders */
+ if (magik(TOWN_NORMAL_FLOOR)) town_borders(t_idx, qy, qx);
+
+
+ /* Some inhabitants(leveled .. hehe :) */
+
+ /* Backup the old hook */
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ /* Require "okay" monsters */
+ get_mon_num_hook = create_townpeople_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ for (x = qx; x < qx + SCREEN_WID; x++)
+ for (y = qy; y < qy + SCREEN_HGT; y++)
+ {
+ int m_idx, r_idx;
+
+ /* Only in town */
+ if (!in_bounds(y, x)) continue;
+ if (!(cave[y][x].info & CAVE_FREE)) continue;
+ if (!cave_empty_bold(y, x)) continue;
+
+ if (rand_int(100)) continue;
+
+ r_idx = get_mon_num(0);
+ m_allow_special[r_idx] = TRUE;
+ m_idx = place_monster_one(y, x, r_idx, 0, TRUE, MSTATUS_ENEMY);
+ m_allow_special[r_idx] = FALSE;
+
+ if (m_idx)
+ {
+ monster_type *m_ptr = &m_list[m_idx];
+ if (m_ptr->level < (dun_level / 2))
+ {
+ m_ptr->exp = MONSTER_EXP(m_ptr->level + (dun_level / 2) + randint(dun_level / 2));
+ monster_check_experience(m_idx, TRUE);
+ }
+ }
+ }
+
+ /* Reset restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+}
+
+static void town_gen_circle(int t_idx, int qy, int qx)
+{
+ int y, x, cy, cx, rad, floor, num = 0;
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+
+ int *rooms;
+
+ /* Do we use dungeon floor or normal one */
+ if (magik(TOWN_NORMAL_FLOOR)) floor = FEAT_FLOOR;
+ else floor = 0;
+
+ rad = (SCREEN_HGT / 2);
+
+ y = qy;
+ for (x = qx + rad; x < qx + SCREEN_WID - rad; x++)
+ {
+ set_border(y, x);
+ }
+
+ y = qy + SCREEN_HGT - 1;
+ for (x = qx + rad; x < qx + SCREEN_WID - rad; x++)
+ {
+ set_border(y, x);
+ }
+ /* Place some floors */
+ for (y = qy + 1; y < qy + SCREEN_HGT - 1; y++)
+ {
+ for (x = qx + rad; x < qx + SCREEN_WID - rad; x++)
+ {
+ /* Create empty floor */
+ cave_set_feat(y, x, (floor) ? floor : floor_type[rand_int(100)]);
+ cave[y][x].info |= CAVE_ROOM | CAVE_FREE;
+ }
+ }
+
+ cy = qy + (SCREEN_HGT / 2);
+
+ cx = qx + rad;
+ for (y = cy - rad; y < cy + rad; y++)
+ for (x = cx - rad; x < cx + 1; x++)
+ {
+ int d = distance(cy, cx, y, x);
+
+ if ((d == rad) || (d == rad - 1)) set_border(y, x);
+
+ if (d < rad - 1)
+ {
+ cave_set_feat(y, x, (floor) ? floor : floor_type[rand_int(100)]);
+ cave[y][x].info |= CAVE_ROOM | CAVE_FREE;
+ }
+ }
+
+ cx = qx + SCREEN_WID - rad - 1;
+ for (y = cy - rad; y < cy + rad; y++)
+ for (x = cx; x < cx + rad + 1; x++)
+ {
+ int d = distance(cy, cx, y, x);
+
+ if ((d == rad) || (d == rad - 1)) set_border(y, x);
+
+ if (d < rad - 1)
+ {
+ cave_set_feat(y, x, (floor) ? floor : floor_type[rand_int(100)]);
+ cave[y][x].info |= CAVE_ROOM | CAVE_FREE;
+ }
+ }
+
+ /* Prepare an Array of "remaining stores", and count them */
+ C_MAKE(rooms, max_st_idx, int);
+ num = get_shops(rooms);
+
+ /* Place two rows of stores */
+ for (y = 0; y < 2; y++)
+ {
+ /* Place four stores per row */
+ for (x = 0; x < 4; x++)
+ {
+ if(--num > -1)
+ {
+ /* Build that store at the proper location */
+ build_store_circle(qy, qx, rooms[num], y, x);
+ }
+ }
+ }
+ C_FREE(rooms, max_st_idx, int);
+
+ /* Some inhabitants(leveled .. hehe :) */
+
+ /* Backup the old hook */
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ /* Require "okay" monsters */
+ get_mon_num_hook = create_townpeople_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ for (x = qx; x < qx + SCREEN_WID; x++)
+ for (y = qy; y < qy + SCREEN_HGT; y++)
+ {
+ int m_idx, r_idx;
+
+ /* Only in town */
+ if (!in_bounds(y, x)) continue;
+ if (!(cave[y][x].info & CAVE_FREE)) continue;
+ if (!cave_empty_bold(y, x)) continue;
+
+ if (rand_int(100)) continue;
+
+ r_idx = get_mon_num(0);
+ m_allow_special[r_idx] = TRUE;
+ m_idx = place_monster_one(y, x, r_idx, 0, TRUE, MSTATUS_ENEMY);
+ m_allow_special[r_idx] = FALSE;
+ if (m_idx)
+ {
+ monster_type *m_ptr = &m_list[m_idx];
+ if (m_ptr->level < (dun_level / 2))
+ {
+ m_ptr->exp = MONSTER_EXP(m_ptr->level + (dun_level / 2) + randint(dun_level / 2));
+ monster_check_experience(m_idx, TRUE);
+ }
+ }
+ }
+
+ /* Reset restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+}
+
+
+static void town_gen_hidden(int t_idx, int qy, int qx)
+{
+ int y, x, n, num = 0, i;
+
+ int *rooms;
+
+ /* Prepare an Array of "remaining stores", and count them */
+ C_MAKE(rooms, max_st_idx, int);
+ num = get_shops(rooms);
+
+ /* Get a number of stores to place */
+ n = rand_int(num / 2) + (num / 2);
+
+ /* Place k stores */
+ for (i = 0; i < n; i++)
+ {
+ /* Find a good spot */
+ while (TRUE)
+ {
+ y = rand_range(1, cur_hgt - 2);
+ x = rand_range(1, cur_wid - 2);
+
+ if (cave_empty_bold(y, x)) break;
+ }
+
+ if(--num > -1)
+ {
+ /* Build that store at the proper location */
+ build_store_hidden(rooms[num], y, x);
+ }
+ }
+ C_FREE(rooms, max_st_idx, int);
+}
+
+
+
+/*
+ * Town logic flow for generation of new town
+ *
+ * We start with a fully wiped cave of normal floors.
+ *
+ * Note that town_gen_hack() plays games with the R.N.G.
+ *
+ * This function does NOT do anything about the owners of the stores,
+ * nor the contents thereof. It only handles the physical layout.
+ *
+ * We place the player on the stairs at the same time we make them.
+ *
+ * Hack -- since the player always leaves the dungeon by the stairs,
+ * he is always placed on the stairs, even if he left the dungeon via
+ * word of recall or teleport level.
+ */
+void town_gen(int t_idx)
+{
+ int qy, qx;
+
+ /* Level too small to contain a town */
+ if (cur_hgt < SCREEN_HGT) return;
+ if (cur_wid < SCREEN_WID) return;
+
+ /* Center fo the level */
+ qy = (cur_hgt - SCREEN_HGT) / 2;
+ qx = (cur_wid - SCREEN_WID) / 2;
+
+ /* Build stuff */
+ switch (rand_int(3))
+ {
+ case 0:
+ {
+ town_gen_hack(t_idx, qy, qx);
+ if (wizard)
+ {
+ msg_format("Town level(normal) (%d, seed %d)",
+ t_idx, town_info[t_idx].seed);
+ }
+ break;
+ }
+
+ case 1:
+ {
+ town_gen_circle(t_idx, qy, qx);
+ if (wizard)
+ {
+ msg_format("Town level(circle)(%d, seed %d)",
+ t_idx, town_info[t_idx].seed);
+ }
+ break;
+ }
+
+ case 2:
+ {
+ town_gen_hidden(t_idx, qy, qx);
+ if (wizard)
+ {
+ msg_format("Town level(hidden)(%d, seed %d)",
+ t_idx, town_info[t_idx].seed);
+ }
+ break;
+ }
+ }
+
+ p_ptr->town_num = t_idx;
+}
diff --git a/src/wizard1.c b/src/wizard1.c
new file mode 100644
index 00000000..7daef324
--- /dev/null
+++ b/src/wizard1.c
@@ -0,0 +1,2756 @@
+/* File: wizard1.c */
+
+/* Purpose: Spoiler generation -BEN- */
+
+#include "angband.h"
+
+
+/*
+ * The spoiler file being created
+ */
+static FILE *fff = NULL;
+
+
+/*
+ * Write out `n' of the character `c' to the spoiler file
+ */
+static void spoiler_out_n_chars(int n, char c)
+{
+ while (--n >= 0) fputc(c, fff);
+}
+
+
+/*
+ * Write out `n' blank lines to the spoiler file
+ */
+static void spoiler_blanklines(int n)
+{
+ spoiler_out_n_chars(n, '\n');
+}
+
+
+/*
+ * Write a line to the spoiler file and then "underline" it with hyphens
+ */
+static void spoiler_underline(cptr str)
+{
+ fprintf(fff, "%s\n", str);
+ spoiler_out_n_chars(strlen(str), '-');
+ fprintf(fff, "\n");
+}
+
+
+/*
+ * Buffer text to the given file. (-SHAWN-)
+ * This is basically c_roff() from mon-desc.c with a few changes.
+ */
+static void spoil_out(cptr str)
+{
+ cptr r;
+
+ /* Line buffer */
+ static char roff_buf[256];
+
+ /* Current pointer into line roff_buf */
+ static char *roff_p = roff_buf;
+
+ /* Last space saved into roff_buf */
+ static char *roff_s = NULL;
+
+ /* Special handling for "new sequence" */
+ if (!str)
+ {
+ if (roff_p != roff_buf) roff_p--;
+ while (*roff_p == ' ' && roff_p != roff_buf) roff_p--;
+ if (roff_p == roff_buf) fprintf(fff, "\n");
+ else
+ {
+ *(roff_p + 1) = '\0';
+ fprintf(fff, "%s\n\n", roff_buf);
+ }
+ roff_p = roff_buf;
+ roff_s = NULL;
+ roff_buf[0] = '\0';
+ return;
+ }
+
+ /* Scan the given string, character at a time */
+ for (; *str; str++)
+ {
+ char ch = *str;
+ int wrap = (ch == '\n');
+
+ if (!isprint(ch)) ch = ' ';
+ if (roff_p >= roff_buf + 75) wrap = 1;
+ if ((ch == ' ') && (roff_p + 2 >= roff_buf + 75)) wrap = 1;
+
+ /* Handle line-wrap */
+ if (wrap)
+ {
+ *roff_p = '\0';
+ r = roff_p;
+ if (roff_s && (ch != ' '))
+ {
+ *roff_s = '\0';
+ r = roff_s + 1;
+ }
+ fprintf(fff, "%s\n", roff_buf);
+ roff_s = NULL;
+ roff_p = roff_buf;
+ while (*r) *roff_p++ = *r++;
+ }
+
+ /* Save the char */
+ if ((roff_p > roff_buf) || (ch != ' '))
+ {
+ if (ch == ' ') roff_s = roff_p;
+ *roff_p++ = ch;
+ }
+ }
+}
+
+
+/*
+ * Extract a textual representation of an attribute
+ */
+static cptr attr_to_text(byte a)
+{
+ switch (a)
+ {
+ case TERM_DARK:
+ return ("xxx");
+ case TERM_WHITE:
+ return ("White");
+ case TERM_SLATE:
+ return ("Slate");
+ case TERM_ORANGE:
+ return ("Orange");
+ case TERM_RED:
+ return ("Red");
+ case TERM_GREEN:
+ return ("Green");
+ case TERM_BLUE:
+ return ("Blue");
+ case TERM_UMBER:
+ return ("Umber");
+ case TERM_L_DARK:
+ return ("L.Dark");
+ case TERM_L_WHITE:
+ return ("L.Slate");
+ case TERM_VIOLET:
+ return ("Violet");
+ case TERM_YELLOW:
+ return ("Yellow");
+ case TERM_L_RED:
+ return ("L.Red");
+ case TERM_L_GREEN:
+ return ("L.Green");
+ case TERM_L_BLUE:
+ return ("L.Blue");
+ case TERM_L_UMBER:
+ return ("L.Umber");
+ }
+
+ /* Oops */
+ return ("Icky");
+}
+
+
+
+/*
+ * A tval grouper
+ */
+typedef struct
+{
+ byte tval;
+ cptr name;
+}
+grouper;
+
+
+
+/*
+ * Item Spoilers by: benh@phial.com (Ben Harrison)
+ */
+
+
+/*
+ * The basic items categorized by type
+ */
+static grouper group_item[] =
+{
+ { TV_SWORD, "Melee Weapons" },
+ { TV_POLEARM, NULL },
+ { TV_HAFTED, NULL },
+ { TV_AXE, NULL },
+ { TV_MSTAFF, NULL },
+
+ { TV_BOW, "Bows and Slings" },
+
+ { TV_SHOT, "Ammo" },
+ { TV_ARROW, NULL },
+ { TV_BOLT, NULL },
+
+ { TV_BOOMERANG, "Boomerangs" },
+
+ { TV_INSTRUMENT, "Instruments" },
+
+ { TV_SOFT_ARMOR, "Armour (Body)" },
+ { TV_HARD_ARMOR, NULL },
+ { TV_DRAG_ARMOR, NULL },
+
+ { TV_SHIELD, "Armour (Misc)" },
+ { TV_HELM, NULL },
+ { TV_CROWN, NULL },
+ { TV_GLOVES, NULL },
+ { TV_BOOTS, NULL },
+
+ { TV_CLOAK, "Cloaks" },
+ { TV_AMULET, "Amulets" },
+ { TV_RING, "Rings" },
+
+ { TV_SCROLL, "Scrolls" },
+ { TV_POTION, "Potions" },
+ { TV_POTION2, NULL },
+
+ { TV_FOOD, "Food" },
+
+ { TV_ROD_MAIN, "Rods" },
+ { TV_ROD, "Rod Tips" },
+ { TV_WAND, "Wands" },
+ { TV_STAFF, "Staves" },
+
+ { TV_BOOK, "Books (Magic, Gods, Music)" },
+ { TV_DAEMON_BOOK, "Demonic Equipment" },
+
+ { TV_RUNE1, "Runes" },
+ { TV_RUNE2, NULL },
+
+ { TV_BATERIE, "Essences" },
+
+ { TV_PARCHMENT, "Parchments" },
+
+ { TV_DIGGING, "Tools" },
+ { TV_TOOL, NULL },
+
+ { TV_TRAPKIT, "Trapping Kits" },
+
+ { TV_CHEST, "Chests" },
+
+ { TV_SPIKE, "Various" },
+ { TV_LITE, NULL },
+ { TV_FLASK, NULL },
+ { TV_BOTTLE, NULL },
+ { TV_JUNK, NULL },
+
+ { TV_SKELETON, "Corpses and Eggs" },
+ { TV_CORPSE, NULL },
+ { TV_EGG, NULL },
+
+ { 0, "" }
+};
+
+
+/*
+ * Describe the kind
+ */
+static void kind_info(char *buf, char *dam, char *wgt, int *lev, s32b *val, int k)
+{
+ object_type forge;
+ object_type *q_ptr;
+
+ object_kind *k_ptr;
+
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Prepare a fake item */
+ object_prep(q_ptr, k);
+
+ /* Obtain the "kind" info */
+ k_ptr = &k_info[q_ptr->k_idx];
+
+ /* It is known */
+ q_ptr->ident |= (IDENT_KNOWN);
+
+ /* Cancel bonuses */
+ q_ptr->to_a = 0;
+ q_ptr->to_h = 0;
+ q_ptr->to_d = 0;
+
+ if ((k_ptr->tval == TV_WAND) || (k_ptr->tval == TV_STAFF))
+ {
+ hack_apply_magic_power = -99;
+ apply_magic(q_ptr, 0, FALSE, FALSE, FALSE);
+ }
+
+ /* Level */
+ (*lev) = k_ptr->level;
+
+ /* Value */
+ (*val) = object_value(q_ptr);
+
+
+ /* Hack */
+ if (!buf || !dam || !wgt) return;
+
+
+ /* Description (too brief) */
+ object_desc_store(buf, q_ptr, FALSE, 0);
+
+
+ /* Misc info */
+ strcpy(dam, "");
+
+ /* Damage */
+ switch (q_ptr->tval)
+ {
+ /* Bows */
+ case TV_BOW:
+ {
+ break;
+ }
+
+ /* Ammo */
+ case TV_SHOT:
+ case TV_BOLT:
+ case TV_ARROW:
+
+ /* Boomerangs */
+ case TV_BOOMERANG:
+
+ /* Weapons */
+ case TV_HAFTED:
+ case TV_POLEARM:
+ case TV_SWORD:
+ case TV_AXE:
+ case TV_MSTAFF:
+
+ /* Tools */
+ case TV_DIGGING:
+ {
+ sprintf(dam, "%dd%d", q_ptr->dd, q_ptr->ds);
+ break;
+ }
+
+ /* Armour */
+ case TV_BOOTS:
+ case TV_GLOVES:
+ case TV_CLOAK:
+ case TV_CROWN:
+ case TV_HELM:
+ case TV_SHIELD:
+ case TV_SOFT_ARMOR:
+ case TV_HARD_ARMOR:
+ case TV_DRAG_ARMOR:
+ {
+ sprintf(dam, "%d", q_ptr->ac);
+ break;
+ }
+ }
+
+
+ /* Weight */
+ sprintf(wgt, "%3ld.%ld", (long int) (q_ptr->weight / 10), (long int) (q_ptr->weight % 10));
+}
+
+
+/*
+ * Create a spoiler file for items
+ */
+static void spoil_obj_desc(cptr fname)
+{
+ int i, k, s, t, n = 0;
+
+ u16b who[200];
+
+ char buf[1024];
+
+ char wgt[80];
+ char dam[80];
+
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Open the file */
+ fff = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!fff)
+ {
+ msg_print("Cannot create spoiler file.");
+ return;
+ }
+
+
+ /* Header */
+ sprintf(buf, "Basic Items Spoilers for %s", get_version_string());
+ spoiler_underline(buf);
+ spoiler_blanklines(2);
+
+ /* More Header */
+ fprintf(fff, "%-45s %8s%7s%5s%9s\n",
+ "Description", "Dam/AC", "Wgt", "Lev", "Cost");
+ fprintf(fff, "%-45s %8s%7s%5s%9s\n",
+ "----------------------------------------",
+ "------", "---", "---", "----");
+
+ /* List the groups */
+ for (i = 0; TRUE; i++)
+ {
+ /* Write out the group title */
+ if (group_item[i].name)
+ {
+ /* Hack -- bubble-sort by cost and then level */
+ for (s = 0; s < n - 1; s++)
+ {
+ for (t = 0; t < n - 1; t++)
+ {
+ int i1 = t;
+ int i2 = t + 1;
+
+ int e1;
+ int e2;
+
+ s32b t1;
+ s32b t2;
+
+ kind_info(NULL, NULL, NULL, &e1, &t1, who[i1]);
+ kind_info(NULL, NULL, NULL, &e2, &t2, who[i2]);
+
+ if ((t1 > t2) || ((t1 == t2) && (e1 > e2)))
+ {
+ int tmp = who[i1];
+ who[i1] = who[i2];
+ who[i2] = tmp;
+ }
+ }
+ }
+
+ /* Spoil each item */
+ for (s = 0; s < n; s++)
+ {
+ int e;
+ s32b v;
+
+ /* Describe the kind */
+ kind_info(buf, dam, wgt, &e, &v, who[s]);
+
+ /* Dump it */
+ fprintf(fff, " %-45s%8s%7s%5d%9ld\n",
+ buf, dam, wgt, e, (long)(v));
+ }
+
+ /* Start a new set */
+ n = 0;
+
+ /* Notice the end */
+ if (!group_item[i].tval) break;
+
+ /* Start a new set */
+ fprintf(fff, "\n\n%s\n\n", group_item[i].name);
+ }
+
+ /* Acquire legal item types */
+ for (k = 1; k < max_k_idx; k++)
+ {
+ object_kind *k_ptr = &k_info[k];
+
+ /* Skip wrong tval's */
+ if (k_ptr->tval != group_item[i].tval) continue;
+
+ /* Hack -- Skip artifacts */
+ if (k_ptr->flags3 & (TR3_INSTA_ART | TR3_NORM_ART)) continue;
+
+ /* Hack -- Skip Ring of Powers */
+ if (k == 785) continue;
+
+ /* Save the index */
+ who[n++] = k;
+ }
+ }
+
+
+ /* Check for errors */
+ if (ferror(fff) || my_fclose(fff))
+ {
+ msg_print("Cannot close spoiler file.");
+ return;
+ }
+
+ /* Message */
+ msg_print("Successfully created a spoiler file.");
+}
+
+
+
+/*
+ * Artifact Spoilers by: randy@PICARD.tamu.edu (Randy Hutson)
+ */
+
+
+/*
+ * Returns a "+" string if a number is non-negative and an empty
+ * string if negative
+ */
+#define POSITIZE(v) (((v) >= 0) ? "+" : "")
+
+/*
+ * These are used to format the artifact spoiler file. INDENT1 is used
+ * to indent all but the first line of an artifact spoiler. INDENT2 is
+ * used when a line "wraps". (Bladeturner's resistances cause this.)
+ */
+#define INDENT1 " "
+#define INDENT2 " "
+
+/*
+ * MAX_LINE_LEN specifies when a line should wrap.
+ */
+#define MAX_LINE_LEN 75
+
+/*
+ * Given an array, determine how many elements are in the array
+ */
+#define N_ELEMENTS(a) (sizeof (a) / sizeof ((a)[0]))
+
+/*
+ * The artifacts categorized by type
+ */
+static grouper group_artifact[] =
+{
+ { TV_SWORD, "Edged Weapons" },
+ { TV_POLEARM, "Polearms" },
+ { TV_HAFTED, "Hafted Weapons" },
+ { TV_AXE, "Axes" },
+
+ { TV_MSTAFF, "Mage Staffs" },
+
+ { TV_BOW, "Bows" },
+
+ { TV_SHOT, "Ammo" },
+ { TV_ARROW, NULL },
+ { TV_BOLT, NULL },
+
+ { TV_BOOMERANG, "Boomerangs" },
+
+ { TV_INSTRUMENT, "Instruments" },
+
+ { TV_SOFT_ARMOR, "Body Armor" },
+ { TV_HARD_ARMOR, NULL },
+ { TV_DRAG_ARMOR, NULL },
+
+ { TV_CLOAK, "Cloaks" },
+ { TV_SHIELD, "Shields" },
+ { TV_HELM, "Helms/Crowns" },
+ { TV_CROWN, NULL },
+ { TV_GLOVES, "Gloves" },
+ { TV_BOOTS, "Boots" },
+
+ { TV_DAEMON_BOOK, "Demonic Equipment" },
+
+ { TV_LITE, "Light Sources" },
+ { TV_AMULET, "Amulets" },
+ { TV_RING, "Rings" },
+
+ { TV_TOOL, "Tools" },
+ { TV_DIGGING, NULL },
+ { TV_TRAPKIT, "Trapping Kits" },
+
+ { 0, NULL }
+};
+
+
+
+/*
+ * Pair together a constant flag with a textual description.
+ *
+ * Used by both "init.c" and "wiz-spo.c".
+ *
+ * Note that it sometimes more efficient to actually make an array
+ * of textual names, where entry 'N' is assumed to be paired with
+ * the flag whose value is "1L << N", but that requires hard-coding.
+ */
+
+typedef struct flag_desc flag_desc;
+
+struct flag_desc
+{
+ const u32b flag;
+ const char *const desc;
+};
+
+
+
+/*
+ * These are used for "+3 to STR, DEX", etc. These are separate from
+ * the other pval affected traits to simplify the case where an object
+ * affects all stats. In this case, "All stats" is used instead of
+ * listing each stat individually.
+ */
+
+static flag_desc stat_flags_desc[] =
+{
+ { TR1_STR, "STR" },
+ { TR1_INT, "INT" },
+ { TR1_WIS, "WIS" },
+ { TR1_DEX, "DEX" },
+ { TR1_CON, "CON" },
+ { TR1_CHR, "CHR" }
+};
+
+/*
+ * Besides stats, these are the other player traits
+ * which may be affected by an object's pval
+ */
+
+static flag_desc pval_flags1_desc[] =
+{
+ { TR1_STEALTH, "Stealth" },
+ { TR1_SEARCH, "Searching" },
+ { TR1_INFRA, "Infravision" },
+ { TR1_TUNNEL, "Tunnelling" },
+ { TR1_BLOWS, "Attacks" },
+ { TR1_SPEED, "Speed" }
+};
+
+/*
+ * Slaying preferences for weapons
+ */
+
+static flag_desc slay_flags_desc[] =
+{
+ { TR1_SLAY_ANIMAL, "Animal" },
+ { TR1_SLAY_EVIL, "Evil" },
+ { TR1_SLAY_UNDEAD, "Undead" },
+ { TR1_SLAY_DEMON, "Demon" },
+ { TR1_SLAY_ORC, "Orc" },
+ { TR1_SLAY_TROLL, "Troll" },
+ { TR1_SLAY_GIANT, "Giant" },
+ { TR1_SLAY_DRAGON, "Dragon" },
+ { TR1_KILL_DRAGON, "Xdragon" }
+};
+
+/*
+ * Elemental brands for weapons
+ *
+ * Clearly, TR1_IMPACT is a bit out of place here. To simplify
+ * coding, it has been included here along with the elemental
+ * brands. It does seem to fit in with the brands and slaying
+ * more than the miscellaneous section.
+ */
+static flag_desc brand_flags_desc[] =
+{
+ { TR1_BRAND_ACID, "Acid Brand" },
+ { TR1_BRAND_ELEC, "Lightning Brand" },
+ { TR1_BRAND_FIRE, "Flame Tongue" },
+ { TR1_BRAND_COLD, "Frost Brand" },
+ { TR1_BRAND_POIS, "Poisoned" },
+
+ { TR1_CHAOTIC, "Mark of Chaos" },
+ { TR1_VAMPIRIC, "Vampiric" },
+ { TR1_IMPACT, "Earthquake impact on hit" },
+ { TR1_VORPAL, "Very sharp" },
+};
+
+
+/*
+ * The 15 resistables
+ */
+static const flag_desc resist_flags_desc[] =
+{
+ { TR2_RES_ACID, "Acid" },
+ { TR2_RES_ELEC, "Lightning" },
+ { TR2_RES_FIRE, "Fire" },
+ { TR2_RES_COLD, "Cold" },
+ { TR2_RES_POIS, "Poison" },
+ { TR2_RES_FEAR, "Fear"},
+ { TR2_RES_LITE, "Light" },
+ { TR2_RES_DARK, "Dark" },
+ { TR2_RES_BLIND, "Blindness" },
+ { TR2_RES_CONF, "Confusion" },
+ { TR2_RES_SOUND, "Sound" },
+ { TR2_RES_SHARDS, "Shards" },
+ { TR2_RES_NETHER, "Nether" },
+ { TR2_RES_NEXUS, "Nexus" },
+ { TR2_RES_CHAOS, "Chaos" },
+ { TR2_RES_DISEN, "Disenchantment" },
+};
+
+/*
+ * Elemental immunities (along with poison)
+ */
+
+static const flag_desc immune_flags_desc[] =
+{
+ { TR2_IM_ACID, "Acid" },
+ { TR2_IM_ELEC, "Lightning" },
+ { TR2_IM_FIRE, "Fire" },
+ { TR2_IM_COLD, "Cold" },
+};
+
+/*
+ * Sustain stats - these are given their "own" line in the
+ * spoiler file, mainly for simplicity
+ */
+static const flag_desc sustain_flags_desc[] =
+{
+ { TR2_SUST_STR, "STR" },
+ { TR2_SUST_INT, "INT" },
+ { TR2_SUST_WIS, "WIS" },
+ { TR2_SUST_DEX, "DEX" },
+ { TR2_SUST_CON, "CON" },
+ { TR2_SUST_CHR, "CHR" },
+};
+
+/*
+ * Miscellaneous magic given by an object's "flags2" field
+ */
+
+static const flag_desc misc_flags2_desc[] =
+{
+ { TR2_REFLECT, "Reflection" },
+ { TR2_FREE_ACT, "Free Action" },
+ { TR2_HOLD_LIFE, "Hold Life" },
+};
+
+/*
+ * Miscellaneous magic given by an object's "flags3" field
+ *
+ * Note that cursed artifacts and objects with permanent light
+ * are handled "directly" -- see analyze_misc_magic()
+ */
+
+static const flag_desc misc_flags3_desc[] =
+{
+ { TR3_SH_FIRE, "Fiery Aura" },
+ { TR3_SH_ELEC, "Electric Aura" },
+ { TR3_NO_TELE, "Prevent Teleportation" },
+ { TR3_NO_MAGIC, "Anti-Magic" },
+ { TR3_WRAITH, "Wraith Form" },
+ { TR3_FEATHER, "Levitation" },
+ { TR3_SEE_INVIS, "See Invisible" },
+ { TR3_SLOW_DIGEST, "Slow Digestion" },
+ { TR3_REGEN, "Regeneration" },
+ { TR3_XTRA_SHOTS, "+1 Extra Shot" }, /* always +1? */
+ { TR3_DRAIN_EXP, "Drains Experience" },
+ { TR3_AGGRAVATE, "Aggravates" },
+ { TR3_BLESSED, "Blessed Blade" },
+};
+
+
+/*
+ * A special type used just for dealing with pvals
+ */
+typedef struct
+{
+ /*
+ * This will contain a string such as "+2", "-10", etc.
+ */
+ char pval_desc[12];
+
+ /*
+ * A list of various player traits affected by an object's pval such
+ * as stats, speed, stealth, etc. "Extra attacks" is NOT included in
+ * this list since it will probably be desirable to format its
+ * description differently.
+ *
+ * Note that room need only be reserved for the number of stats - 1
+ * since the description "All stats" is used if an object affects all
+ * all stats. Also, room must be reserved for a sentinel NULL pointer.
+ *
+ * This will be a list such as ["STR", "DEX", "Stealth", NULL] etc.
+ *
+ * This list includes extra attacks, for simplicity.
+ */
+ cptr pval_affects[N_ELEMENTS(stat_flags_desc) - 1 +
+ N_ELEMENTS(pval_flags1_desc) + 1];
+
+}
+pval_info_type;
+
+
+/*
+ * An "object analysis structure"
+ *
+ * It will be filled with descriptive strings detailing an object's
+ * various magical powers. The "ignore X" traits are not noted since
+ * all artifacts ignore "normal" destruction.
+ */
+
+typedef struct
+{
+ /* "The Longsword Dragonsmiter (6d4) (+20, +25)" */
+ char description[160];
+
+ /* Description of what is affected by an object's pval */
+ pval_info_type pval_info;
+
+ /* A list of an object's slaying preferences */
+ cptr slays[N_ELEMENTS(slay_flags_desc) + 1];
+
+ /* A list if an object's elemental brands */
+ cptr brands[N_ELEMENTS(brand_flags_desc) + 1];
+
+ /* A list of immunities granted by an object */
+ cptr immunities[N_ELEMENTS(immune_flags_desc) + 1];
+
+ /* A list of resistances granted by an object */
+ cptr resistances[N_ELEMENTS(resist_flags_desc) + 1];
+
+ /* A list of stats sustained by an object */
+ cptr sustains[N_ELEMENTS(sustain_flags_desc) - 1 + 1];
+
+ /* A list of various magical qualities an object may have */
+ cptr misc_magic[N_ELEMENTS(misc_flags2_desc) + N_ELEMENTS(misc_flags3_desc)
+ + 1 /* Permanent Light */
+ + 1 /* type of curse */
+ + 1]; /* sentinel NULL */
+
+ /* A string describing an artifact's activation */
+ cptr activation;
+
+ /* "Level 20, Rarity 30, 3.0 lbs, 20000 Gold" */
+ char misc_desc[80];
+}
+obj_desc_list;
+
+
+
+
+
+
+/*
+ * This function does most of the actual "analysis". Given a set of bit flags
+ * (which will be from one of the flags fields from the object in question),
+ * a "flag description structure", a "description list", and the number of
+ * elements in the "flag description structure", this function sets the
+ * "description list" members to the appropriate descriptions contained in
+ * the "flag description structure".
+ *
+ * The possibly updated description pointer is returned.
+ */
+static cptr *spoiler_flag_aux(const u32b art_flags, const flag_desc *flag_ptr,
+ cptr *desc_ptr, const int n_elmnts)
+{
+ int i;
+
+ for (i = 0; i < n_elmnts; ++i)
+ {
+ if (art_flags & flag_ptr[i].flag)
+ {
+ *desc_ptr++ = flag_ptr[i].desc;
+ }
+ }
+
+ return desc_ptr;
+}
+
+
+/*
+ * Acquire a "basic" description "The Cloak of Death [1,+10]"
+ */
+static void analyze_general (object_type *o_ptr, char *desc_ptr)
+{
+ /* Get a "useful" description of the object */
+ object_desc_store(desc_ptr, o_ptr, TRUE, 1);
+}
+
+
+/*
+ * List "player traits" altered by an artifact's pval. These include stats,
+ * speed, infravision, tunnelling, stealth, searching, and extra attacks.
+ */
+static void analyze_pval (object_type *o_ptr, pval_info_type *p_ptr)
+{
+ const u32b all_stats = (TR1_STR | TR1_INT | TR1_WIS |
+ TR1_DEX | TR1_CON | TR1_CHR);
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ cptr *affects_list;
+
+ /* If pval == 0, there is nothing to do. */
+ if (!o_ptr->pval)
+ {
+ /* An "empty" pval description indicates that pval == 0 */
+ p_ptr->pval_desc[0] = '\0';
+ return;
+ }
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ affects_list = p_ptr->pval_affects;
+
+ /* Create the "+N" string */
+ sprintf(p_ptr->pval_desc, "%s%ld", POSITIZE(o_ptr->pval), (long int) o_ptr->pval);
+
+ /* First, check to see if the pval affects all stats */
+ if ((f1 & all_stats) == all_stats)
+ {
+ *affects_list++ = "All stats";
+ }
+
+ /* Are any stats affected? */
+ else if (f1 & all_stats)
+ {
+ affects_list = spoiler_flag_aux(f1, stat_flags_desc,
+ affects_list,
+ N_ELEMENTS(stat_flags_desc));
+ }
+
+ /* And now the "rest" */
+ affects_list = spoiler_flag_aux(f1, pval_flags1_desc,
+ affects_list,
+ N_ELEMENTS(pval_flags1_desc));
+
+ /* Terminate the description list */
+ *affects_list = NULL;
+}
+
+
+/* Note the slaying specialties of a weapon */
+static void analyze_slay (object_type *o_ptr, cptr *slay_list)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ slay_list = spoiler_flag_aux(f1, slay_flags_desc, slay_list,
+ N_ELEMENTS(slay_flags_desc));
+
+ /* Terminate the description list */
+ *slay_list = NULL;
+}
+
+/* Note an object's elemental brands */
+static void analyze_brand (object_type *o_ptr, cptr *brand_list)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ brand_list = spoiler_flag_aux(f1, brand_flags_desc, brand_list,
+ N_ELEMENTS(brand_flags_desc));
+
+ /* Terminate the description list */
+ *brand_list = NULL;
+}
+
+
+/* Note the resistances granted by an object */
+static void analyze_resist (object_type *o_ptr, cptr *resist_list)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ resist_list = spoiler_flag_aux(f2, resist_flags_desc,
+ resist_list, N_ELEMENTS(resist_flags_desc));
+
+ /* Terminate the description list */
+ *resist_list = NULL;
+}
+
+
+/* Note the immunities granted by an object */
+static void analyze_immune (object_type *o_ptr, cptr *immune_list)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ immune_list = spoiler_flag_aux(f2, immune_flags_desc,
+ immune_list, N_ELEMENTS(immune_flags_desc));
+
+ /* Terminate the description list */
+ *immune_list = NULL;
+}
+
+/* Note which stats an object sustains */
+
+static void analyze_sustains (object_type *o_ptr, cptr *sustain_list)
+{
+ const u32b all_sustains = (TR2_SUST_STR | TR2_SUST_INT | TR2_SUST_WIS |
+ TR2_SUST_DEX | TR2_SUST_CON | TR2_SUST_CHR);
+
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Simplify things if an item sustains all stats */
+ if ((f2 & all_sustains) == all_sustains)
+ {
+ *sustain_list++ = "All stats";
+ }
+
+ /* Should we bother? */
+ else if ((f2 & all_sustains))
+ {
+ sustain_list = spoiler_flag_aux(f2, sustain_flags_desc,
+ sustain_list,
+ N_ELEMENTS(sustain_flags_desc));
+ }
+
+ /* Terminate the description list */
+ *sustain_list = NULL;
+}
+
+
+/*
+ * Note miscellaneous powers bestowed by an artifact such as see invisible,
+ * free action, permanent light, etc.
+ */
+static void analyze_misc_magic (object_type *o_ptr, cptr *misc_list)
+{
+ u32b f1, f2, f3, f4, f5, esp;
+ int radius = 0;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ misc_list = spoiler_flag_aux(f2, misc_flags2_desc, misc_list,
+ N_ELEMENTS(misc_flags2_desc));
+
+ misc_list = spoiler_flag_aux(f3, misc_flags3_desc, misc_list,
+ N_ELEMENTS(misc_flags3_desc));
+
+ /*
+ * Glowing artifacts -- small radius light.
+ */
+
+ if (f3 & TR3_LITE1) radius++;
+ if (f4 & TR4_LITE2) radius += 2;
+ if (f4 & TR4_LITE3) radius += 3;
+
+ if (f4 & TR4_FUEL_LITE)
+ {
+ *misc_list++ = format("It provides light (radius %d) forever.", radius);
+ }
+ else
+ {
+ *misc_list++ = format("It provides light (radius %d) when fueled.", radius);
+ }
+
+ /*
+ * Handle cursed objects here to avoid redundancies such as noting
+ * that a permanently cursed object is heavily cursed as well as
+ * being "lightly cursed".
+ */
+
+ if (cursed_p(o_ptr))
+ {
+ if (f3 & (TR3_TY_CURSE))
+ {
+ *misc_list++ = "Ancient Curse";
+ }
+ if (f3 & (TR3_PERMA_CURSE))
+ {
+ *misc_list++ = "Permanently Cursed";
+ }
+ else if (f3 & (TR3_HEAVY_CURSE))
+ {
+ *misc_list++ = "Heavily Cursed";
+ }
+ else
+ {
+ *misc_list++ = "Cursed";
+ }
+ }
+
+ /* Terminate the description list */
+ *misc_list = NULL;
+}
+
+
+
+
+/*
+ * Determine the minimum depth an artifact can appear, its rarity, its weight,
+ * and its value in gold pieces
+ */
+static void analyze_misc (object_type *o_ptr, char *misc_desc)
+{
+ artifact_type *a_ptr = &a_info[o_ptr->name1];
+
+ sprintf(misc_desc, "Level %u, Rarity %u, %d.%d lbs, %ld Gold",
+ a_ptr->level, a_ptr->rarity,
+ a_ptr->weight / 10, a_ptr->weight % 10, (long int) a_ptr->cost);
+}
+
+
+/*
+ * Fill in an object description structure for a given object
+ */
+static void object_analyze(object_type *o_ptr, obj_desc_list *desc_ptr)
+{
+ analyze_general(o_ptr, desc_ptr->description);
+
+ analyze_pval(o_ptr, &desc_ptr->pval_info);
+
+ analyze_brand(o_ptr, desc_ptr->brands);
+
+ analyze_slay(o_ptr, desc_ptr->slays);
+
+ analyze_immune(o_ptr, desc_ptr->immunities);
+
+ analyze_resist(o_ptr, desc_ptr->resistances);
+
+ analyze_sustains(o_ptr, desc_ptr->sustains);
+
+ analyze_misc_magic(o_ptr, desc_ptr->misc_magic);
+
+ analyze_misc(o_ptr, desc_ptr->misc_desc);
+
+ desc_ptr->activation = item_activation(o_ptr, 0);
+}
+
+
+static void print_header(void)
+{
+ char buf[80];
+
+ sprintf(buf, "Artifact Spoilers for %s", get_version_string());
+ spoiler_underline(buf);
+}
+
+/*
+ * This is somewhat ugly.
+ *
+ * Given a header ("Resist", e.g.), a list ("Fire", "Cold", Acid", e.g.),
+ * and a separator character (',', e.g.), write the list to the spoiler file
+ * in a "nice" format, such as:
+ *
+ * Resist Fire, Cold, Acid
+ *
+ * That was a simple example, but when the list is long, a line wrap
+ * should occur, and this should induce a new level of indention if
+ * a list is being spread across lines. So for example, Bladeturner's
+ * list of resistances should look something like this
+ *
+ * Resist Acid, Lightning, Fire, Cold, Poison, Light, Dark, Blindness,
+ * Confusion, Sound, Shards, Nether, Nexus, Chaos, Disenchantment
+ *
+ * However, the code distinguishes between a single list of many items vs.
+ * many lists. (The separator is used to make this determination.) A single
+ * list of many items will not cause line wrapping (since there is no
+ * apparent reason to do so). So the lists of Ulmo's miscellaneous traits
+ * might look like this:
+ *
+ * Free Action; Hold Life; See Invisible; Slow Digestion; Regeneration
+ * Blessed Blade
+ *
+ * So comparing the two, "Regeneration" has no trailing separator and
+ * "Blessed Blade" was not indented. (Also, Ulmo's lists have no headers,
+ * but that's not relevant to line wrapping and indention.)
+ */
+
+/* ITEM_SEP separates items within a list */
+#define ITEM_SEP ','
+
+
+/* LIST_SEP separates lists */
+#define LIST_SEP ';'
+
+
+/* Create a spoiler file entry for an artifact */
+
+static void spoiler_print_art(obj_desc_list *art_ptr, int name1, int set, object_type *o_ptr)
+{
+ /* Don't indent the first line */
+ fprintf(fff, "%s\n ", art_ptr->description);
+ text_out_indent = 4;
+ object_out_desc(o_ptr, fff, FALSE, TRUE);
+ text_out_indent = 0;
+
+ /* End with the miscellaneous facts */
+ fprintf(fff, "%s%s\n\n", INDENT1, art_ptr->misc_desc);
+}
+
+
+/*
+ * Hack -- Create a "forged" artifact
+ */
+static bool_ make_fake_artifact(object_type *o_ptr, int name1)
+{
+ int i;
+ int cur;
+
+ artifact_type *a_ptr = &a_info[name1];
+
+
+ /* Ignore "empty" artifacts */
+ if (!a_ptr->name) return FALSE;
+
+ /* Acquire the "kind" index */
+ i = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Oops */
+ if (!i) return (FALSE);
+
+ /* Create the artifact */
+ object_prep(o_ptr, i);
+
+ /* Save the name */
+ o_ptr->name1 = name1;
+
+ /* Keep the One Ring untouched by apply_magic */
+ if (name1 != ART_POWER)
+ {
+ cur = a_ptr->cur_num;
+ apply_magic(o_ptr, -1, TRUE, TRUE, TRUE);
+ a_ptr->cur_num = cur;
+ }
+ else
+ {
+ o_ptr->pval = a_ptr->pval;
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Create a spoiler file for artifacts
+ */
+static void spoil_artifact(cptr fname)
+{
+ int i, j;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ obj_desc_list artifact;
+
+ char buf[1024];
+
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Open the file */
+ fff = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!fff)
+ {
+ msg_print("Cannot create spoiler file.");
+ return;
+ }
+
+ /* Dump the header */
+ print_header();
+
+ /* List the artifacts by tval */
+ for (i = 0; group_artifact[i].tval; i++)
+ {
+ /* Write out the group title */
+ if (group_artifact[i].name)
+ {
+ spoiler_blanklines(2);
+ spoiler_underline(group_artifact[i].name);
+ spoiler_blanklines(1);
+ }
+
+ /* Now search through all of the artifacts */
+ for (j = 1; j < max_a_idx; ++j)
+ {
+ artifact_type *a_ptr = &a_info[j];
+
+ /* We only want objects in the current group */
+ if (a_ptr->tval != group_artifact[i].tval) continue;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Attempt to "forge" the artifact */
+ if (!make_fake_artifact(q_ptr, j)) continue;
+
+ /* Aware and Known */
+ object_known(q_ptr);
+
+ /* Mark the item as fully known */
+ q_ptr->ident |= (IDENT_MENTAL);
+
+ /* Analyze the artifact */
+ object_analyze(q_ptr, &artifact);
+
+ /* Write out the artifact description to the spoiler file */
+ spoiler_print_art(&artifact, j, a_ptr->set, q_ptr);
+ }
+ }
+
+ /* Check for errors */
+ if (ferror(fff) || my_fclose(fff))
+ {
+ msg_print("Cannot close spoiler file.");
+ return;
+ }
+
+ /* Message */
+ msg_print("Successfully created a spoiler file.");
+}
+
+
+
+
+
+/*
+ * Create a spoiler file for monsters -BEN-
+ */
+static void spoil_mon_desc(cptr fname)
+{
+ int i, n = 0;
+
+ s16b *who;
+
+ char buf[1024];
+
+ char nam[80];
+ char lev[80];
+ char rar[80];
+ char spd[80];
+ char ac[80];
+ char hp[80];
+ char exp[80];
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Open the file */
+ fff = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!fff)
+ {
+ msg_print("Cannot create spoiler file.");
+ return;
+ }
+
+ /* Allocate the "who" array */
+ C_MAKE(who, max_r_idx, s16b);
+
+ /* Dump the header */
+ sprintf(buf, "Monster Spoilers for %s", get_version_string());
+ spoiler_underline(buf);
+ spoiler_blanklines(2);
+
+ /* Dump the header */
+ fprintf(fff, "%-40.40s%4s%4s%6s%8s%4s %11.11s\n",
+ "Name", "Lev", "Rar", "Spd", "Hp", "Ac", "Visual Info");
+ fprintf(fff, "%-40.40s%4s%4s%6s%8s%4s %11.11s\n",
+ "----", "---", "---", "---", "--", "--", "-----------");
+
+
+ /* Scan the monsters */
+ for (i = 1; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ /* Use that monster */
+ if (r_ptr->name) who[n++] = i;
+ }
+
+
+ /* Scan again */
+ for (i = 0; i < n; i++)
+ {
+ monster_race *r_ptr = &r_info[who[i]];
+
+ cptr name = (r_name + r_ptr->name);
+
+ /* Get the "name" */
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ sprintf(nam, "[U] %s", name);
+ }
+ else
+ {
+ sprintf(nam, "The %s", name);
+ }
+
+
+ /* Level */
+ sprintf(lev, "%d", r_ptr->level);
+
+ /* Rarity */
+ sprintf(rar, "%d", r_ptr->rarity);
+
+ /* Speed */
+ if (r_ptr->speed >= 110)
+ {
+ sprintf(spd, "+%d", (r_ptr->speed - 110));
+ }
+ else
+ {
+ sprintf(spd, "-%d", (110 - r_ptr->speed));
+ }
+
+ /* Armor Class */
+ sprintf(ac, "%d", r_ptr->ac);
+
+ /* Hitpoints */
+ if ((r_ptr->flags1 & (RF1_FORCE_MAXHP)) || (r_ptr->hside == 1))
+ {
+ sprintf(hp, "%d", r_ptr->hdice * r_ptr->hside);
+ }
+ else
+ {
+ sprintf(hp, "%dd%d", r_ptr->hdice, r_ptr->hside);
+ }
+
+
+ /* Experience */
+ sprintf(exp, "%ld", (long)(r_ptr->mexp));
+
+ /* Hack -- use visual instead */
+ sprintf(exp, "%s '%c'", attr_to_text(r_ptr->d_attr), r_ptr->d_char);
+
+ /* Dump the info */
+ fprintf(fff, "%-40.40s%4s%4s%6s%8s%4s %11.11s\n",
+ nam, lev, rar, spd, hp, ac, exp);
+ }
+
+ /* End it */
+ fprintf(fff, "\n");
+
+ /* Free the "who" array */
+ C_KILL(who, max_r_idx, s16b);
+
+ /* Check for errors */
+ if (ferror(fff) || my_fclose(fff))
+ {
+ msg_print("Cannot close spoiler file.");
+ return;
+ }
+
+ /* Worked */
+ msg_print("Successfully created a spoiler file.");
+}
+
+
+
+
+/*
+ * Monster spoilers by: smchorse@ringer.cs.utsa.edu (Shawn McHorse)
+ *
+ * Primarily based on code already in mon-desc.c, mostly by -BEN-
+ */
+
+/*
+ * Pronoun arrays
+ */
+static cptr wd_che[3] = { "It", "He", "She" };
+static cptr wd_lhe[3] = { "it", "he", "she" };
+
+
+
+/*
+ * Create a spoiler file for monsters (-SHAWN-)
+ */
+static void spoil_mon_info(cptr fname)
+{
+ char buf[1024];
+ int msex, vn, i, j, k, n;
+ bool_ breath, magic, sin;
+ cptr p, q;
+ cptr vp[64];
+ u32b flags1, flags2, flags3, flags4, flags5, flags6, flags9;
+
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ /* Open the file */
+ fff = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!fff)
+ {
+ msg_print("Cannot create spoiler file.");
+ return;
+ }
+
+
+ /* Dump the header */
+ sprintf(buf, "Monster Spoilers for %s", get_version_string());
+ spoiler_underline(buf);
+ spoiler_blanklines(2);
+
+ /*
+ * List all monsters in order.
+ */
+ for (n = 1; n < max_r_idx; n++)
+ {
+ monster_race *r_ptr = &r_info[n];
+
+ /* Extract the flags */
+ flags1 = r_ptr->flags1;
+ flags2 = r_ptr->flags2;
+ flags3 = r_ptr->flags3;
+ flags4 = r_ptr->flags4;
+ flags5 = r_ptr->flags5;
+ flags6 = r_ptr->flags6;
+ flags9 = r_ptr->flags9;
+ breath = FALSE;
+ magic = FALSE;
+
+ /* Extract a gender (if applicable) */
+ if (flags1 & (RF1_FEMALE)) msex = 2;
+ else if (flags1 & (RF1_MALE)) msex = 1;
+ else msex = 0;
+
+
+ /* Prefix */
+ if (flags1 & (RF1_UNIQUE))
+ {
+ spoil_out("[U] ");
+ }
+ else
+ {
+ spoil_out("The ");
+ }
+
+ /* Name */
+ sprintf(buf, "%s (", (r_name + r_ptr->name)); /* ---)--- */
+ spoil_out(buf);
+
+ /* Color */
+ spoil_out(attr_to_text(r_ptr->d_attr));
+
+ /* Symbol --(-- */
+ sprintf(buf, " '%c')\n", r_ptr->d_char);
+ spoil_out(buf);
+
+
+ /* Indent */
+ sprintf(buf, "=== ");
+ spoil_out(buf);
+
+ /* Number */
+ sprintf(buf, "Num:%d ", n);
+ spoil_out(buf);
+
+ /* Level */
+ sprintf(buf, "Lev:%d ", r_ptr->level);
+ spoil_out(buf);
+
+ /* Rarity */
+ sprintf(buf, "Rar:%d ", r_ptr->rarity);
+ spoil_out(buf);
+
+ /* Speed */
+ if (r_ptr->speed >= 110)
+ {
+ sprintf(buf, "Spd:+%d ", (r_ptr->speed - 110));
+ }
+ else
+ {
+ sprintf(buf, "Spd:-%d ", (110 - r_ptr->speed));
+ }
+ spoil_out(buf);
+
+ /* Hitpoints */
+ if ((flags1 & (RF1_FORCE_MAXHP)) || (r_ptr->hside == 1))
+ {
+ sprintf(buf, "Hp:%d ", r_ptr->hdice * r_ptr->hside);
+ }
+ else
+ {
+ sprintf(buf, "Hp:%dd%d ", r_ptr->hdice, r_ptr->hside);
+ }
+ spoil_out(buf);
+
+ /* Armor Class */
+ sprintf(buf, "Ac:%d ", r_ptr->ac);
+ spoil_out(buf);
+
+ /* Experience */
+ sprintf(buf, "Exp:%ld\n", (long)(r_ptr->mexp));
+ spoil_out(buf);
+
+
+ /* Describe */
+ spoil_out(r_text + r_ptr->text);
+ spoil_out(" ");
+
+
+ spoil_out("This");
+
+ if (flags2 & (RF2_ELDRITCH_HORROR)) spoil_out (" sanity-blasting");
+ if (flags3 & (RF3_ANIMAL)) spoil_out(" natural");
+ if (flags3 & (RF3_EVIL)) spoil_out(" evil");
+ if (flags3 & (RF3_GOOD)) spoil_out(" good");
+ if (flags3 & (RF3_UNDEAD)) spoil_out(" undead");
+
+ if (flags3 & (RF3_DRAGON)) spoil_out(" dragon");
+ else if (flags3 & (RF3_DEMON)) spoil_out(" demon");
+ else if (flags3 & (RF3_GIANT)) spoil_out(" giant");
+ else if (flags3 & (RF3_TROLL)) spoil_out(" troll");
+ else if (flags3 & (RF3_ORC)) spoil_out(" orc");
+ else if (flags3 & (RF3_THUNDERLORD)) spoil_out (" Thunderlord");
+ else spoil_out(" creature");
+
+ spoil_out(" moves");
+
+ if ((flags1 & (RF1_RAND_50)) && (flags1 & (RF1_RAND_25)))
+ {
+ spoil_out(" extremely erratically");
+ }
+ else if (flags1 & (RF1_RAND_50))
+ {
+ spoil_out(" somewhat erratically");
+ }
+ else if (flags1 & (RF1_RAND_25))
+ {
+ spoil_out(" a bit erratically");
+ }
+ else
+ {
+ spoil_out(" normally");
+ }
+
+ if (flags1 & (RF1_NEVER_MOVE))
+ {
+ spoil_out(", but does not deign to chase intruders");
+ }
+
+ spoil_out(". ");
+
+ if (!r_ptr->level || (flags1 & (RF1_FORCE_DEPTH)))
+ {
+ sprintf(buf, "%s is never found out of depth. ", wd_che[msex]);
+ spoil_out(buf);
+ }
+
+ if (flags1 & (RF1_FORCE_SLEEP))
+ {
+ sprintf(buf, "%s is always created sluggish. ", wd_che[msex]);
+ spoil_out(buf);
+ }
+
+ if (flags2 & (RF2_AURA_FIRE))
+ {
+ sprintf(buf, "%s is surrounded by flames. ", wd_che[msex]);
+ spoil_out(buf);
+ }
+
+ if (flags2 & (RF2_AURA_ELEC))
+ {
+ sprintf(buf, "%s is surrounded by electricity. ", wd_che[msex]);
+ spoil_out(buf);
+ }
+
+ if (flags2 & (RF2_REFLECTING))
+ {
+ sprintf(buf, "%s reflects bolt spells. ", wd_che[msex]);
+ spoil_out(buf);
+ }
+
+ if (flags1 & (RF1_ESCORT))
+ {
+ sprintf(buf, "%s usually appears with ", wd_che[msex]);
+ spoil_out(buf);
+ if (flags1 & (RF1_ESCORTS)) spoil_out("escorts. ");
+ else spoil_out("an escort. ");
+ }
+
+ if ((flags1 & (RF1_FRIEND)) || (flags1 & (RF1_FRIENDS)))
+ {
+ sprintf(buf, "%s usually appears in groups. ", wd_che[msex]);
+ spoil_out(buf);
+ }
+
+ /* Collect innate attacks */
+ vn = 0;
+ if (flags4 & (RF4_SHRIEK)) vp[vn++] = "shriek for help";
+ if (flags4 & (RF4_ROCKET)) vp[vn++] = "shoot a rocket";
+ if (flags4 & (RF4_ARROW_1)) vp[vn++] = "fire arrows";
+ if (flags4 & (RF4_ARROW_2)) vp[vn++] = "fire arrows";
+ if (flags4 & (RF4_ARROW_3)) vp[vn++] = "fire missiles";
+ if (flags4 & (RF4_ARROW_4)) vp[vn++] = "fire missiles";
+
+ if (vn)
+ {
+ spoil_out(wd_che[msex]);
+ for (i = 0; i < vn; i++)
+ {
+ if (!i) spoil_out(" may ");
+ else if (i < vn - 1) spoil_out(", ");
+ else spoil_out(" or ");
+ spoil_out(vp[i]);
+ }
+ spoil_out(". ");
+ }
+
+ /* Collect breaths */
+ vn = 0;
+ if (flags4 & (RF4_BR_ACID)) vp[vn++] = "acid";
+ if (flags4 & (RF4_BR_ELEC)) vp[vn++] = "lightning";
+ if (flags4 & (RF4_BR_FIRE)) vp[vn++] = "fire";
+ if (flags4 & (RF4_BR_COLD)) vp[vn++] = "frost";
+ if (flags4 & (RF4_BR_POIS)) vp[vn++] = "poison";
+ if (flags4 & (RF4_BR_NETH)) vp[vn++] = "nether";
+ if (flags4 & (RF4_BR_LITE)) vp[vn++] = "light";
+ if (flags4 & (RF4_BR_DARK)) vp[vn++] = "darkness";
+ if (flags4 & (RF4_BR_CONF)) vp[vn++] = "confusion";
+ if (flags4 & (RF4_BR_SOUN)) vp[vn++] = "sound";
+ if (flags4 & (RF4_BR_CHAO)) vp[vn++] = "chaos";
+ if (flags4 & (RF4_BR_DISE)) vp[vn++] = "disenchantment";
+ if (flags4 & (RF4_BR_NEXU)) vp[vn++] = "nexus";
+ if (flags4 & (RF4_BR_TIME)) vp[vn++] = "time";
+ if (flags4 & (RF4_BR_INER)) vp[vn++] = "inertia";
+ if (flags4 & (RF4_BR_GRAV)) vp[vn++] = "gravity";
+ if (flags4 & (RF4_BR_SHAR)) vp[vn++] = "shards";
+ if (flags4 & (RF4_BR_PLAS)) vp[vn++] = "plasma";
+ if (flags4 & (RF4_BR_WALL)) vp[vn++] = "force";
+ if (flags4 & (RF4_BR_MANA)) vp[vn++] = "mana";
+ if (flags4 & (RF4_BR_NUKE)) vp[vn++] = "toxic waste";
+ if (flags4 & (RF4_BR_DISI)) vp[vn++] = "disintegration";
+
+ if (vn)
+ {
+ breath = TRUE;
+ spoil_out(wd_che[msex]);
+ for (i = 0; i < vn; i++)
+ {
+ if (!i) spoil_out(" may breathe ");
+ else if (i < vn - 1) spoil_out(", ");
+ else spoil_out(" or ");
+ spoil_out(vp[i]);
+ }
+ if (flags2 & (RF2_POWERFUL)) spoil_out(" powerfully");
+ }
+
+ /* Collect spells */
+ vn = 0;
+ if (flags5 & (RF5_BA_ACID)) vp[vn++] = "produce acid balls";
+ if (flags5 & (RF5_BA_ELEC)) vp[vn++] = "produce lightning balls";
+ if (flags5 & (RF5_BA_FIRE)) vp[vn++] = "produce fire balls";
+ if (flags5 & (RF5_BA_COLD)) vp[vn++] = "produce frost balls";
+ if (flags5 & (RF5_BA_POIS)) vp[vn++] = "produce poison balls";
+ if (flags5 & (RF5_BA_NETH)) vp[vn++] = "produce nether balls";
+ if (flags5 & (RF5_BA_WATE)) vp[vn++] = "produce water balls";
+ if (flags4 & (RF4_BA_NUKE)) vp[vn++] = "produce balls of radiation";
+ if (flags5 & (RF5_BA_MANA)) vp[vn++] = "produce mana storms";
+ if (flags5 & (RF5_BA_DARK)) vp[vn++] = "produce darkness storms";
+ if (flags4 & (RF4_BA_CHAO)) vp[vn++] = "invoke raw Chaos";
+ if (flags6 & (RF6_HAND_DOOM)) vp[vn++] = "invoke the Hand of Doom";
+ if (flags5 & (RF5_DRAIN_MANA)) vp[vn++] = "drain mana";
+ if (flags5 & (RF5_MIND_BLAST)) vp[vn++] = "cause mind blasting";
+ if (flags5 & (RF5_BRAIN_SMASH)) vp[vn++] = "cause brain smashing";
+ if (flags5 & (RF5_CAUSE_1)) vp[vn++] = "cause light wounds and cursing";
+ if (flags5 & (RF5_CAUSE_2)) vp[vn++] = "cause serious wounds and cursing";
+ if (flags5 & (RF5_CAUSE_3)) vp[vn++] = "cause critical wounds and cursing";
+ if (flags5 & (RF5_CAUSE_4)) vp[vn++] = "cause mortal wounds";
+ if (flags5 & (RF5_BO_ACID)) vp[vn++] = "produce acid bolts";
+ if (flags5 & (RF5_BO_ELEC)) vp[vn++] = "produce lightning bolts";
+ if (flags5 & (RF5_BO_FIRE)) vp[vn++] = "produce fire bolts";
+ if (flags5 & (RF5_BO_COLD)) vp[vn++] = "produce frost bolts";
+ if (flags5 & (RF5_BO_POIS)) vp[vn++] = "produce poison bolts";
+ if (flags5 & (RF5_BO_NETH)) vp[vn++] = "produce nether bolts";
+ if (flags5 & (RF5_BO_WATE)) vp[vn++] = "produce water bolts";
+ if (flags5 & (RF5_BO_MANA)) vp[vn++] = "produce mana bolts";
+ if (flags5 & (RF5_BO_PLAS)) vp[vn++] = "produce plasma bolts";
+ if (flags5 & (RF5_BO_ICEE)) vp[vn++] = "produce ice bolts";
+ if (flags5 & (RF5_MISSILE)) vp[vn++] = "produce magic missiles";
+ if (flags5 & (RF5_SCARE)) vp[vn++] = "terrify";
+ if (flags5 & (RF5_BLIND)) vp[vn++] = "blind";
+ if (flags5 & (RF5_CONF)) vp[vn++] = "confuse";
+ if (flags5 & (RF5_SLOW)) vp[vn++] = "slow";
+ if (flags5 & (RF5_HOLD)) vp[vn++] = "paralyse";
+ if (flags6 & (RF6_HASTE)) vp[vn++] = "haste-self";
+ if (flags6 & (RF6_HEAL)) vp[vn++] = "heal-self";
+ if (flags6 & (RF6_BLINK)) vp[vn++] = "blink-self";
+ if (flags6 & (RF6_TPORT)) vp[vn++] = "teleport-self";
+ if (flags6 & (RF6_S_BUG)) vp[vn++] = "summon software bugs";
+ if (flags6 & (RF6_S_RNG)) vp[vn++] = "summon RNGs";
+ if (flags6 & (RF6_TELE_TO)) vp[vn++] = "teleport to";
+ if (flags6 & (RF6_TELE_AWAY)) vp[vn++] = "teleport away";
+ if (flags6 & (RF6_TELE_LEVEL)) vp[vn++] = "teleport level";
+ if (flags6 & (RF6_DARKNESS)) vp[vn++] = "create darkness";
+ if (flags6 & (RF6_TRAPS)) vp[vn++] = "create traps";
+ if (flags6 & (RF6_FORGET)) vp[vn++] = "cause amnesia";
+ if (flags6 & (RF6_RAISE_DEAD)) vp[vn++] = "raise dead";
+ if (flags6 & (RF6_S_THUNDERLORD)) vp[vn++] = "summon a thunderlord";
+ if (flags6 & (RF6_S_MONSTER)) vp[vn++] = "summon a monster";
+ if (flags6 & (RF6_S_MONSTERS)) vp[vn++] = "summon monsters";
+ if (flags6 & (RF6_S_KIN)) vp[vn++] = "summon aid";
+ if (flags6 & (RF6_S_ANT)) vp[vn++] = "summon ants";
+ if (flags6 & (RF6_S_SPIDER)) vp[vn++] = "summon spiders";
+ if (flags6 & (RF6_S_HOUND)) vp[vn++] = "summon hounds";
+ if (flags6 & (RF6_S_HYDRA)) vp[vn++] = "summon hydras";
+ if (flags6 & (RF6_S_ANGEL)) vp[vn++] = "summon an angel";
+ if (flags6 & (RF6_S_DEMON)) vp[vn++] = "summon a demon";
+ if (flags6 & (RF6_S_UNDEAD)) vp[vn++] = "summon an undead";
+ if (flags6 & (RF6_S_DRAGON)) vp[vn++] = "summon a dragon";
+ if (flags4 & (RF4_S_ANIMAL)) vp[vn++] = "summon animal";
+ if (flags6 & (RF6_S_ANIMALS)) vp[vn++] = "summon animals";
+ if (flags6 & (RF6_S_HI_UNDEAD)) vp[vn++] = "summon greater undead";
+ if (flags6 & (RF6_S_HI_DRAGON)) vp[vn++] = "summon ancient dragons";
+ if (flags6 & (RF6_S_HI_DEMON)) vp[vn++] = "summon greater demons";
+ if (flags6 & (RF6_S_WRAITH)) vp[vn++] = "summon Ringwraith";
+ if (flags6 & (RF6_S_UNIQUE)) vp[vn++] = "summon unique monsters";
+
+ if (vn)
+ {
+ magic = TRUE;
+ if (breath)
+ {
+ spoil_out(", and is also");
+ }
+ else
+ {
+ spoil_out(wd_che[msex]);
+ spoil_out(" is");
+ }
+
+ spoil_out(" magical, casting spells");
+ if (flags2 & (RF2_SMART)) spoil_out(" intelligently");
+
+ for (i = 0; i < vn; i++)
+ {
+ if (!i) spoil_out(" which ");
+ else if (i < vn - 1) spoil_out(", ");
+ else spoil_out(" or ");
+ spoil_out(vp[i]);
+ }
+ }
+
+ if (breath || magic)
+ {
+ int times = r_ptr->freq_inate + r_ptr->freq_spell;
+ sprintf(buf, "; 1 time in %d. ",
+ 200 / ((times) ? times : 1));
+ spoil_out(buf);
+ }
+
+ /* Collect special abilities. */
+ vn = 0;
+ if (flags2 & (RF2_OPEN_DOOR)) vp[vn++] = "open doors";
+ if (flags2 & (RF2_BASH_DOOR)) vp[vn++] = "bash down doors";
+ if (flags2 & (RF2_PASS_WALL)) vp[vn++] = "pass through walls";
+ if (flags2 & (RF2_KILL_WALL)) vp[vn++] = "bore through walls";
+ if (flags2 & (RF2_MOVE_BODY)) vp[vn++] = "push past weaker monsters";
+ if (flags2 & (RF2_KILL_BODY)) vp[vn++] = "destroy weaker monsters";
+ if (flags2 & (RF2_TAKE_ITEM)) vp[vn++] = "pick up objects";
+ if (flags2 & (RF2_KILL_ITEM)) vp[vn++] = "destroy objects";
+ if (flags9 & (RF9_HAS_LITE)) vp[vn++] = "illuminate the dungeon";
+
+ if (vn)
+ {
+ spoil_out(wd_che[msex]);
+ for (i = 0; i < vn; i++)
+ {
+ if (!i) spoil_out(" can ");
+ else if (i < vn - 1) spoil_out(", ");
+ else spoil_out(" and ");
+ spoil_out(vp[i]);
+ }
+ spoil_out(". ");
+ }
+
+ if (flags2 & (RF2_INVISIBLE))
+ {
+ spoil_out(wd_che[msex]);
+ spoil_out(" is invisible. ");
+ }
+ if (flags2 & (RF2_COLD_BLOOD))
+ {
+ spoil_out(wd_che[msex]);
+ spoil_out(" is cold blooded. ");
+ }
+ if (flags2 & (RF2_EMPTY_MIND))
+ {
+ spoil_out(wd_che[msex]);
+ spoil_out(" is not detected by telepathy. ");
+ }
+ if (flags2 & (RF2_WEIRD_MIND))
+ {
+ spoil_out(wd_che[msex]);
+ spoil_out(" is rarely detected by telepathy. ");
+ }
+ if (flags4 & (RF4_MULTIPLY))
+ {
+ spoil_out(wd_che[msex]);
+ spoil_out(" breeds explosively. ");
+ }
+ if (flags2 & (RF2_REGENERATE))
+ {
+ spoil_out(wd_che[msex]);
+ spoil_out(" regenerates quickly. ");
+ }
+
+ /* Collect susceptibilities */
+ vn = 0;
+ if (flags3 & (RF3_HURT_ROCK)) vp[vn++] = "rock remover";
+ if (flags3 & (RF3_HURT_LITE)) vp[vn++] = "bright light";
+ if (flags3 & (RF3_SUSCEP_FIRE)) vp[vn++] = "fire";
+ if (flags3 & (RF3_SUSCEP_COLD)) vp[vn++] = "cold";
+
+ if (vn)
+ {
+ spoil_out(wd_che[msex]);
+ for (i = 0; i < vn; i++)
+ {
+ if (!i) spoil_out(" is hurt by ");
+ else if (i < vn - 1) spoil_out(", ");
+ else spoil_out(" and ");
+ spoil_out(vp[i]);
+ }
+ spoil_out(". ");
+ }
+
+ /* Collect immunities */
+ vn = 0;
+ if (flags3 & (RF3_IM_ACID)) vp[vn++] = "acid";
+ if (flags3 & (RF3_IM_ELEC)) vp[vn++] = "lightning";
+ if (flags3 & (RF3_IM_FIRE)) vp[vn++] = "fire";
+ if (flags3 & (RF3_IM_COLD)) vp[vn++] = "cold";
+ if (flags3 & (RF3_IM_POIS)) vp[vn++] = "poison";
+
+ if (vn)
+ {
+ spoil_out(wd_che[msex]);
+ for (i = 0; i < vn; i++)
+ {
+ if (!i) spoil_out(" resists ");
+ else if (i < vn - 1) spoil_out(", ");
+ else spoil_out(" and ");
+ spoil_out(vp[i]);
+ }
+ spoil_out(". ");
+ }
+
+ /* Collect resistances */
+ vn = 0;
+ if (flags3 & (RF3_RES_NETH)) vp[vn++] = "nether";
+ if (flags3 & (RF3_RES_WATE)) vp[vn++] = "water";
+ if (flags3 & (RF3_RES_PLAS)) vp[vn++] = "plasma";
+ if (flags3 & (RF3_RES_NEXU)) vp[vn++] = "nexus";
+ if (flags3 & (RF3_RES_DISE)) vp[vn++] = "disenchantment";
+ if (flags3 & (RF3_RES_TELE)) vp[vn++] = "teleportation";
+
+ if (vn)
+ {
+ spoil_out(wd_che[msex]);
+ for (i = 0; i < vn; i++)
+ {
+ if (!i) spoil_out(" resists ");
+ else if (i < vn - 1) spoil_out(", ");
+ else spoil_out(" and ");
+ spoil_out(vp[i]);
+ }
+ spoil_out(". ");
+ }
+
+ /* Collect non-effects */
+ vn = 0;
+ if (flags3 & (RF3_NO_STUN)) vp[vn++] = "stunned";
+ if (flags3 & (RF3_NO_FEAR)) vp[vn++] = "frightened";
+ if (flags3 & (RF3_NO_CONF)) vp[vn++] = "confused";
+ if (flags3 & (RF3_NO_SLEEP)) vp[vn++] = "slept";
+
+ if (vn)
+ {
+ spoil_out(wd_che[msex]);
+ for (i = 0; i < vn; i++)
+ {
+ if (!i) spoil_out(" cannot be ");
+ else if (i < vn - 1) spoil_out(", ");
+ else spoil_out(" or ");
+ spoil_out(vp[i]);
+ }
+ spoil_out(". ");
+ }
+
+ spoil_out(wd_che[msex]);
+ if (r_ptr->sleep > 200) spoil_out(" prefers to ignore");
+ else if (r_ptr->sleep > 95) spoil_out(" pays very little attention to");
+ else if (r_ptr->sleep > 75) spoil_out(" pays little attention to");
+ else if (r_ptr->sleep > 45) spoil_out(" tends to overlook");
+ else if (r_ptr->sleep > 25) spoil_out(" takes quite a while to see");
+ else if (r_ptr->sleep > 10) spoil_out(" takes a while to see");
+ else if (r_ptr->sleep > 5) spoil_out(" is fairly observant of");
+ else if (r_ptr->sleep > 3) spoil_out(" is observant of");
+ else if (r_ptr->sleep > 1) spoil_out(" is very observant of");
+ else if (r_ptr->sleep > 0) spoil_out(" is vigilant for");
+ else spoil_out(" is ever vigilant for");
+
+ sprintf(buf, " intruders, which %s may notice from %d feet. ",
+ wd_lhe[msex], 10 * r_ptr->aaf);
+ spoil_out(buf);
+
+ i = 0;
+ if (flags1 & (RF1_DROP_60)) i += 1;
+ if (flags1 & (RF1_DROP_90)) i += 2;
+ if (flags1 & (RF1_DROP_1D2)) i += 2;
+ if (flags1 & (RF1_DROP_2D2)) i += 4;
+ if (flags1 & (RF1_DROP_3D2)) i += 6;
+ if (flags1 & (RF1_DROP_4D2)) i += 8;
+
+ /* Drops gold and/or items */
+ if (i)
+ {
+ sin = FALSE;
+ spoil_out(wd_che[msex]);
+ spoil_out(" will carry");
+
+ if (i == 1)
+ {
+ spoil_out(" a");
+ sin = TRUE;
+ }
+ else if (i == 2)
+ {
+ spoil_out(" one or two");
+ }
+ else
+ {
+ sprintf(buf, " up to %u", i);
+ spoil_out(buf);
+ }
+
+ if (flags1 & (RF1_DROP_GREAT))
+ {
+ if (sin) spoil_out("n");
+ spoil_out(" exceptional object");
+ }
+ else if (flags1 & (RF1_DROP_GOOD))
+ {
+ spoil_out(" good object");
+ }
+ else if (flags1 & (RF1_DROP_USEFUL))
+ {
+ spoil_out(" useful object");
+ }
+ else if (flags1 & (RF1_ONLY_ITEM))
+ {
+ spoil_out(" object");
+ }
+ else if (flags1 & (RF1_ONLY_GOLD))
+ {
+ spoil_out(" treasure");
+ }
+ else
+ {
+ if (sin) spoil_out("n");
+ spoil_out(" object");
+ if (i > 1) spoil_out("s");
+ spoil_out(" or treasure");
+ }
+ if (i > 1) spoil_out("s");
+
+ if (flags1 & (RF1_DROP_CHOSEN))
+ {
+ spoil_out(", in addition to chosen objects");
+ }
+
+ spoil_out(". ");
+ }
+
+ /* Count the actual attacks */
+ for (i = 0, j = 0; j < 4; j++)
+ {
+ if (r_ptr->blow[j].method) i++;
+ }
+
+ /* Examine the actual attacks */
+ for (k = 0, j = 0; j < 4; j++)
+ {
+ if (!r_ptr->blow[j].method) continue;
+
+ /* No method yet */
+ p = "???";
+
+ /* Acquire the method */
+ switch (r_ptr->blow[j].method)
+ {
+ case RBM_HIT:
+ p = "hit";
+ break;
+ case RBM_TOUCH:
+ p = "touch";
+ break;
+ case RBM_PUNCH:
+ p = "punch";
+ break;
+ case RBM_KICK:
+ p = "kick";
+ break;
+ case RBM_CLAW:
+ p = "claw";
+ break;
+ case RBM_BITE:
+ p = "bite";
+ break;
+ case RBM_STING:
+ p = "sting";
+ break;
+ case RBM_XXX1:
+ break;
+ case RBM_BUTT:
+ p = "butt";
+ break;
+ case RBM_CRUSH:
+ p = "crush";
+ break;
+ case RBM_ENGULF:
+ p = "engulf";
+ break;
+ case RBM_CHARGE:
+ p = "charge";
+ break;
+ case RBM_CRAWL:
+ p = "crawl on you";
+ break;
+ case RBM_DROOL:
+ p = "drool on you";
+ break;
+ case RBM_SPIT:
+ p = "spit";
+ break;
+ case RBM_EXPLODE:
+ p = "explode";
+ break;
+ case RBM_GAZE:
+ p = "gaze";
+ break;
+ case RBM_WAIL:
+ p = "wail";
+ break;
+ case RBM_SPORE:
+ p = "release spores";
+ break;
+ case RBM_XXX4:
+ break;
+ case RBM_BEG:
+ p = "beg";
+ break;
+ case RBM_INSULT:
+ p = "insult";
+ break;
+ case RBM_MOAN:
+ p = "moan";
+ break;
+ case RBM_SHOW:
+ p = "sing";
+ break;
+ }
+
+
+ /* Default effect */
+ q = "???";
+
+ /* Acquire the effect */
+ switch (r_ptr->blow[j].effect)
+ {
+ case RBE_HURT:
+ q = "attack";
+ break;
+ case RBE_POISON:
+ q = "poison";
+ break;
+ case RBE_UN_BONUS:
+ q = "disenchant";
+ break;
+ case RBE_UN_POWER:
+ q = "drain charges";
+ break;
+ case RBE_EAT_GOLD:
+ q = "steal gold";
+ break;
+ case RBE_EAT_ITEM:
+ q = "steal items";
+ break;
+ case RBE_EAT_FOOD:
+ q = "eat your food";
+ break;
+ case RBE_EAT_LITE:
+ q = "absorb light";
+ break;
+ case RBE_ACID:
+ q = "shoot acid";
+ break;
+ case RBE_ELEC:
+ q = "electrocute";
+ break;
+ case RBE_FIRE:
+ q = "burn";
+ break;
+ case RBE_COLD:
+ q = "freeze";
+ break;
+ case RBE_BLIND:
+ q = "blind";
+ break;
+ case RBE_CONFUSE:
+ q = "confuse";
+ break;
+ case RBE_TERRIFY:
+ q = "terrify";
+ break;
+ case RBE_PARALYZE:
+ q = "paralyze";
+ break;
+ case RBE_LOSE_STR:
+ q = "reduce strength";
+ break;
+ case RBE_LOSE_INT:
+ q = "reduce intelligence";
+ break;
+ case RBE_LOSE_WIS:
+ q = "reduce wisdom";
+ break;
+ case RBE_LOSE_DEX:
+ q = "reduce dexterity";
+ break;
+ case RBE_LOSE_CON:
+ q = "reduce constitution";
+ break;
+ case RBE_LOSE_CHR:
+ q = "reduce charisma";
+ break;
+ case RBE_LOSE_ALL:
+ q = "reduce all stats";
+ break;
+ case RBE_SHATTER:
+ q = "shatter";
+ break;
+ case RBE_EXP_10:
+ q = "lower experience (by 10d6+)";
+ break;
+ case RBE_EXP_20:
+ q = "lower experience (by 20d6+)";
+ break;
+ case RBE_EXP_40:
+ q = "lower experience (by 40d6+)";
+ break;
+ case RBE_EXP_80:
+ q = "lower experience (by 80d6+)";
+ break;
+ case RBE_DISEASE:
+ q = "disease";
+ break;
+ case RBE_TIME:
+ q = "time";
+ break;
+ case RBE_SANITY:
+ q = "make insane";
+ break;
+ case RBE_HALLU:
+ q = "cause hallucinations";
+ break;
+ case RBE_PARASITE:
+ q = "parasite";
+ break;
+ }
+
+
+ if (!k)
+ {
+ spoil_out(wd_che[msex]);
+ spoil_out(" can ");
+ }
+ else if (k < i - 1)
+ {
+ spoil_out(", ");
+ }
+ else
+ {
+ spoil_out(", and ");
+ }
+
+ /* Describe the method */
+ spoil_out(p);
+
+ /* Describe the effect, if any */
+ if (r_ptr->blow[j].effect)
+ {
+ spoil_out(" to ");
+ spoil_out(q);
+ if (r_ptr->blow[j].d_dice && r_ptr->blow[j].d_side)
+ {
+ spoil_out(" with damage");
+ if (r_ptr->blow[j].d_side == 1)
+ sprintf(buf, " %d", r_ptr->blow[j].d_dice);
+ else
+ sprintf(buf, " %dd%d",
+ r_ptr->blow[j].d_dice, r_ptr->blow[j].d_side);
+ spoil_out(buf);
+ }
+ }
+
+ k++;
+ }
+
+ if (k)
+ {
+ spoil_out(". ");
+ }
+ else if (flags1 & (RF1_NEVER_BLOW))
+ {
+ sprintf(buf, "%s has no physical attacks. ", wd_che[msex]);
+ spoil_out(buf);
+ }
+
+ spoil_out(NULL);
+ }
+
+ /* Check for errors */
+ if (ferror(fff) || my_fclose(fff))
+ {
+ msg_print("Cannot close spoiler file.");
+ return;
+ }
+
+ msg_print("Successfully created a spoiler file.");
+}
+
+
+char *long_intro =
+ "Essences are the tools of the trade for Alchemists, "
+ "and unfortunately are useless for any other class. "
+ "Alchemists use essences to create magical items for them to use.\n\n"
+ "They can be either found on the floor while exploring the dungeon, "
+ "or extracted from other magical items the alchemist finds "
+ "during their adventures.\n\n"
+ "To create an artifact, the alchemist will have to sacrifice 10 hit points, "
+ "and an amount of magic essence similar to his skill in alchemy. "
+ "The alchemist then allows the artifact to gain experience, "
+ "and when it has enough, "
+ "uses that experience to add abilities to the artifact. "
+ "The alchemist can allow the artifact to continue to gain experience, "
+ "thus keeping open the option to add more abilities later. "
+ "This requires a similar amount of magic essence, "
+ "but does not require the sacrifice of other hit points.\n\n"
+ "Note that the experience you gain is divided among the artifacts "
+ "that you have as well as going to yourself, "
+ "so you will gain levels more slowly when empowering artifacts. "
+ "Also, the artifact only gets 60% of the experience. "
+ "So killing a creature worth 20xp would gain 10 for you, "
+ "and 6 for the artifact.\n\n"
+ "You can also modify existing artifacts when you attain skill level 50. "
+ "Also at skill level 50 you will gain the ability to make temporary artifacts, "
+ "which don't require the complex empowerments that regular items require, "
+ "but also vanish after awhile.\n\n"
+ "You cannot give an artifact an ability "
+ "unless you have *Identified* an artifact which has that ability.\n\n"
+ "For every four levels gained in the alchemy skill, "
+ "the alchemist learns about objects of level (skill level)/4, "
+ "starting by learning about level 1 objects at skill level 0. "
+ "(actually 1, but who's counting?)\n\n"
+ "At skill level 5 you gain the ability to make ego items - but watch it! "
+ "Your base failure rate will be 90%, "
+ "and won't be 0% until you reach skill level 50. "
+ "Adding gold will increase the chances of success "
+ "in direct proportion to the value of the item you are trying to create. "
+ "Note that this results in automatic success "
+ "when the item you are trying to create "
+ "happens to pick up a curse in the process.\n\n"
+ "At skill level 5 you also gain knowledge of some basic ego item recipes. "
+ "These are: Acidic, Shocking, Fiery, Frozen, Venomous, and Chaotic weapons, "
+ "Resist Fire armour, and light sources of Fearlessness.\n\n"
+ "At skill level 10 you will gain knowledge of digging ego items, "
+ "if you have selected the option "
+ "'always generate very unusual rooms' (ironman_rooms).\n\n"
+ "At skill level 15 you can create ego wands, staves, rings, etc.\n\n"
+ "At skill level 25 you gain the ability to empower artifacts "
+ "and double ego items.\n\n"
+ "At skill level 50 you gain the ability to create temporary artifacts, "
+ "which don't require any exotic ingredients "
+ "beyond a single corpse of any type.\n\n"
+ "Between skill levels 25 and 50, "
+ "you will steadily gain the ability to set more and more flags.\n\n"
+ "To finalise an artifact, you 'P'ower it, and select the powers you want.\n"
+ "Powers are divided into the following six categories:\n"
+ "*****essences.txt*03[Stats, Sustains, Luck, Speed, Vision, etc.]\n"
+ "*****essences.txt*04[Misc. (Auras, Light, See Invisibility, etc.)]\n"
+ "*****essences.txt*05[Weapon Brands]\n"
+ "*****essences.txt*06[Resistances and Immunities]\n"
+ "*****essences.txt*07[ESP and Curses]\n"
+ "*****essences.txt*08[Artifact Activations]\n";
+
+/*
+ * Create a spoiler file for essences
+ */
+static void spoil_bateries(cptr fname)
+{
+ int j, i, tval, sval, group;
+ object_type forge, *o_ptr;
+
+ char buf[1024];
+
+ tval = sval = group = -1;
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ fff = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!fff)
+ {
+ msg_print("Cannot create spoiler file.");
+ return;
+ }
+
+ /* Dump the header */
+
+ fprintf(fff,
+ "|||||oy\n"
+ "~~~~~01|Spoilers|Essences\n"
+ "~~~~~02|Alchemist|Essence Spoiler\n"
+ "#####REssence Spoiler for %s\n"
+ "#####R-----------------------------------\n\n",
+ get_version_string());
+
+
+ /*New code starts here -*/
+ /*print header, including artifact header*/
+ /*Cycle through artifact flags*/
+ /* print desc*/
+ /* cycle through all alchemist_recipies*/
+ /* print matching*/
+ /*Print items header.*/
+ /*Cycle through alchemist_recipies*/
+ /* sval or tval changed?*/
+ /* skip artifacts (tval=0)*/
+ /* print item desc (ego (tval=1) or item)*/
+ /* print essences required*/
+ /*Done!*/
+
+ /*Print basic header.*/
+ spoil_out(long_intro);
+
+ /*Cycle through artifact flags*/
+ for ( i = 0 ; a_select_flags[i].group ; i++ )
+ {
+ if ( a_select_flags[i].group != group )
+ {
+ group = a_select_flags[i].group;
+ spoil_out("\n~~~~~");
+ switch (group)
+ {
+ case 1:
+ spoil_out("03\n#####GStats, Sustains, Luck, Speed, Vision, etc.\n");
+ break;
+ case 2:
+ spoil_out("04\n#####GMisc. (Auras, Light, See Invisibility, etc.)\n");
+ break;
+ case 3:
+ spoil_out("05\n#####GWeapon Brands\n");
+ break;
+ case 4:
+ spoil_out("06\n#####GResistances and Immunities\n");
+ break;
+ case 5:
+ spoil_out("07\n#####GESP and Curses\n");
+ break;
+ case 88:
+ spoil_out("08\n#####GArtifact Activations\n");
+ break;
+ default:
+ spoil_out(format("09\n#####GExtra Group=%d\n", group));
+ }
+ spoil_out("lvl xp Power\n");
+
+ }
+ /* print desc*/
+ spoil_out(format("%-2d %8d %-24s %s\n",
+ a_select_flags[i].level,
+ a_select_flags[i].xp,
+ al_name + a_select_flags[i].desc,
+ al_name + a_select_flags[i].item_desc));
+ /* cycle through all alchemist_recipies*/
+ for ( j = 0 ; j < max_al_idx ; j++ )
+ {
+ /* print matching*/
+ if (alchemist_recipes[j].tval == 0
+ && alchemist_recipes[j].sval == a_select_flags[i].flag
+ && alchemist_recipes[j].qty
+ )
+ {
+ spoil_out(format(" %d essences of %s\n", alchemist_recipes[j].qty,
+ k_name + k_info[lookup_kind(TV_BATERIE, alchemist_recipes[j].sval_essence)].name));
+ }
+ }
+ }
+
+ spoil_out("\n\nThe following basic item recipes also exist:\n");
+ /*Cycle through alchemist_recipies*/
+ for ( i = 0 ; i < max_al_idx ; i ++)
+ {
+ alchemist_recipe *ar_ptr = &alchemist_recipes[i];
+
+ /* sval or tval changed?*/
+ if (tval != ar_ptr->tval || sval != ar_ptr->sval)
+ {
+ char o_name[80];
+ /* skip artifacts (tval=0)*/
+ if (ar_ptr->tval == 0 )
+ continue;
+
+ tval = ar_ptr->tval;
+ sval = ar_ptr->sval;
+
+ /* print item desc (ego (tval=1)or item)*/
+ if (ar_ptr->tval == 1)
+ {
+ strcpy(o_name, e_name + e_info[ar_ptr->sval].name);
+ }
+ else
+ {
+ /* Find the name of that object */
+ o_ptr = &forge;
+ object_wipe(o_ptr);
+ object_prep(o_ptr, lookup_kind(tval, sval));
+ apply_magic(o_ptr, 1, FALSE, FALSE, FALSE);
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ o_ptr->name2 = o_ptr->name2b = 0;
+ /* the 0 mode means only the text, leaving off any numbers */
+ object_desc(o_name, o_ptr, FALSE, 0);
+ }
+ spoil_out("\n");
+ spoil_out(o_name);
+ }
+ /* print essence required*/
+ spoil_out(format(" %d %s", ar_ptr->qty,
+ k_name + k_info[lookup_kind(TV_BATERIE, ar_ptr->sval_essence)].name));
+ }
+
+ spoil_out(NULL);
+
+ /* Check for errors */
+ if (ferror(fff) || my_fclose(fff))
+ {
+ msg_print("Cannot close spoiler file.");
+ return;
+ }
+
+ /* Message */
+ msg_print("Successfully created a spoiler file.");
+ return;
+}
+
+
+/*
+ * Print a bookless spell list
+ */
+void print_magic_powers( magic_power *powers, int max_powers, void(*power_info)(char *p, int power), int skill_num )
+{
+ int i, save_skill;
+
+ char buf[80];
+
+ magic_power spell;
+
+ /* Use a maximal skill */
+ save_skill = s_info[skill_num].value;
+ s_info[skill_num].value = SKILL_MAX;
+
+ /* Dump the header line */
+ spoiler_blanklines(2);
+ sprintf(buf, "%s", s_info[skill_num].name + s_name);
+ spoiler_underline(buf);
+ spoiler_blanklines(1);
+
+ fprintf(fff, " Name Lvl Mana Fail Info\n");
+
+ /* Dump the spells */
+ for (i = 0; i < max_powers; i++)
+ {
+ /* Access the spell */
+ spell = powers[i];
+
+ /* Get the additional info */
+ power_info(buf, i);
+
+ /* Dump the spell */
+ spoil_out(format("%c) %-30s%2d %4d %3d%%%s\n",
+ I2A(i), spell.name,
+ spell.min_lev, spell.mana_cost, spell.fail, buf));
+ spoil_out(format("%s\n", spell.desc));
+ }
+
+ /* Restore skill */
+ s_info[skill_num].value = save_skill;
+}
+
+
+/*
+ * Create a spoiler file for spells
+ */
+
+static void spoil_spells(cptr fname)
+{
+ char buf[1024];
+
+ /* Build the filename */
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
+
+ /* File type is "TEXT" */
+ FILE_TYPE(FILE_TYPE_TEXT);
+
+ fff = my_fopen(buf, "w");
+
+ /* Oops */
+ if (!fff)
+ {
+ msg_print("Cannot create spoiler file.");
+ return;
+ }
+
+ /* Dump the header */
+ sprintf(buf, "Spell Spoiler (Skill Level 50) for %s", get_version_string());
+ spoiler_underline(buf);
+
+ /* Dump the bookless magic powers in alphabetical order */
+
+ /* Mimicry */
+ print_magic_powers(mimic_powers, MAX_MIMIC_POWERS, mimic_info, SKILL_MIMICRY);
+
+ /* Mindcraft */
+ print_magic_powers(mindcraft_powers, MAX_MINDCRAFT_POWERS, mindcraft_info, SKILL_MINDCRAFT);
+
+ /* Necromancy */
+ print_magic_powers(necro_powers, MAX_NECRO_POWERS, necro_info, SKILL_NECROMANCY);
+
+ /* Symbiosis */
+ print_magic_powers(symbiotic_powers, MAX_SYMBIOTIC_POWERS, symbiotic_info, SKILL_SYMBIOTIC);
+
+ /* Check for errors */
+ if (ferror(fff) || my_fclose(fff))
+ {
+ msg_print("Cannot close spoiler file.");
+ return;
+ }
+
+ /* Message */
+ msg_print("Successfully created a spoiler file.");
+}
+
+
+
+/*
+ * Forward declare
+ */
+extern void do_cmd_spoilers(void);
+
+/*
+ * Create Spoiler files -BEN-
+ */
+void do_cmd_spoilers(void)
+{
+ int i;
+
+
+ /* Enter "icky" mode */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ /* Interact */
+ while (1)
+ {
+ /* Clear screen */
+ Term_clear();
+
+ /* Info */
+ prt("Create a spoiler file.", 2, 0);
+
+ /* Prompt for a file */
+ prt("(1) Brief Object Info (obj-desc.spo)", 5, 5);
+ prt("(2) Full Artifact Info (artifact.spo)", 6, 5);
+ prt("(3) Brief Monster Info (mon-desc.spo)", 7, 5);
+ prt("(4) Full Monster Info (mon-info.spo)", 8, 5);
+ prt("(5) Full Essences Info (ess-info.spo)", 9, 5);
+ prt("(6) Spell Info (spell.spo)", 10, 5);
+
+ /* Prompt */
+ prt("Command: ", 12, 0);
+
+ /* Get a choice */
+ i = inkey();
+
+ /* Escape */
+ if (i == ESCAPE)
+ {
+ break;
+ }
+
+ /* Option (1) */
+ else if (i == '1')
+ {
+ spoil_obj_desc("obj-desc.spo");
+ }
+
+ /* Option (2) */
+ else if (i == '2')
+ {
+ spoil_artifact("artifact.spo");
+ }
+
+ /* Option (3) */
+ else if (i == '3')
+ {
+ spoil_mon_desc("mon-desc.spo");
+ }
+
+ /* Option (4) */
+ else if (i == '4')
+ {
+ spoil_mon_info("mon-info.spo");
+ }
+
+ /* Option (5) */
+ else if (i == '5')
+ {
+ spoil_bateries("ess-info.spo");
+ }
+
+ /* Option (6) */
+ else if (i == '6')
+ {
+ spoil_spells("spell.spo");
+ }
+
+ /* Oops */
+ else
+ {
+ bell();
+ }
+
+ /* Flush messages */
+ msg_print(NULL);
+ }
+
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Leave "icky" mode */
+ character_icky = FALSE;
+}
diff --git a/src/wizard2.c b/src/wizard2.c
new file mode 100644
index 00000000..a19b72e0
--- /dev/null
+++ b/src/wizard2.c
@@ -0,0 +1,1950 @@
+/* File: wizard2.c */
+
+/* Purpose: Wizard commands */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+void do_cmd_wizard_body(s16b);
+extern void status_main(void);
+
+/*
+ * Adds a lvl to a monster
+ */
+void wiz_inc_monster_level(int level)
+{
+ monster_type *m_ptr;
+ int ii, jj;
+
+ if (!tgt_pt(&ii, &jj)) return;
+
+ if (cave[jj][ii].m_idx)
+ {
+ m_ptr = &m_list[cave[jj][ii].m_idx];
+
+ m_ptr->exp = MONSTER_EXP(m_ptr->level + level);
+ monster_check_experience(cave[jj][ii].m_idx, FALSE);
+ }
+}
+
+void wiz_align_monster(int status)
+{
+ monster_type *m_ptr;
+ int ii, jj;
+
+ if (!tgt_pt(&ii, &jj)) return;
+
+ if (cave[jj][ii].m_idx)
+ {
+ m_ptr = &m_list[cave[jj][ii].m_idx];
+
+ m_ptr->status = status;
+ }
+}
+
+/*
+ * Teleport directly to a town
+ */
+void teleport_player_town(int town)
+{
+ int x = 0, y = 0;
+
+ autosave_checkpoint();
+
+ /* Change town */
+ dun_level = 0;
+ p_ptr->town_num = town;
+
+ for (x = 0; x < max_wild_x; x++)
+ for (y = 0; y < max_wild_y; y++)
+ if (p_ptr->town_num == wf_info[wild_map[y][x].feat].entrance) goto finteletown;
+finteletown:
+ p_ptr->wilderness_y = y;
+ p_ptr->wilderness_x = x;
+
+ p_ptr->inside_arena = 0;
+ leaving_quest = p_ptr->inside_quest;
+ p_ptr->inside_quest = 0;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+}
+
+
+/*
+ * Hack -- Rerate Hitpoints
+ */
+void do_cmd_rerate(void)
+{
+ int min_value, max_value, i, percent;
+
+ min_value = (PY_MAX_LEVEL * 3 * (p_ptr->hitdie - 1)) / 8;
+ min_value += PY_MAX_LEVEL;
+
+ max_value = (PY_MAX_LEVEL * 5 * (p_ptr->hitdie - 1)) / 8;
+ max_value += PY_MAX_LEVEL;
+
+ player_hp[0] = p_ptr->hitdie;
+
+ /* Rerate */
+ while (1)
+ {
+ /* Collect values */
+ for (i = 1; i < PY_MAX_LEVEL; i++)
+ {
+ player_hp[i] = randint(p_ptr->hitdie);
+ player_hp[i] += player_hp[i - 1];
+ }
+
+ /* Legal values */
+ if ((player_hp[PY_MAX_LEVEL - 1] >= min_value) &&
+ (player_hp[PY_MAX_LEVEL - 1] <= max_value)) break;
+ }
+
+ percent = (int)(((long)player_hp[PY_MAX_LEVEL - 1] * 200L) /
+ (p_ptr->hitdie + ((PY_MAX_LEVEL - 1) * p_ptr->hitdie)));
+
+ /* Update and redraw hitpoints */
+ p_ptr->update |= (PU_HP);
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Message */
+ msg_format("Current Life Rating is %d/100.", percent);
+}
+
+
+/*
+ * Create the artifact of the specified number -- DAN
+ *
+ */
+static void wiz_create_named_art()
+{
+ object_type forge;
+ object_type *q_ptr;
+ int i, a_idx;
+ cptr p = "Number of the artifact :";
+ char out_val[80] = "";
+ artifact_type *a_ptr;
+
+ if (!get_string(p, out_val, 4)) return;
+ a_idx = atoi(out_val);
+
+ /* Return if out-of-bounds */
+ if ((a_idx <= 0) || (a_idx >= max_a_idx)) return;
+
+ a_ptr = &a_info[a_idx];
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Ignore "empty" artifacts */
+ if (!a_ptr->name) return;
+
+ /* Acquire the "kind" index */
+ i = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Oops */
+ if (!i) return;
+
+ /* Create the artifact */
+ object_prep(q_ptr, i);
+
+ /* Save the name */
+ q_ptr->name1 = a_idx;
+
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+
+ /* Identify it fully */
+ object_aware(q_ptr);
+ object_known(q_ptr);
+
+ /* Mark the item as fully known */
+ q_ptr->ident |= (IDENT_MENTAL);
+
+ /* Drop the artifact from heaven */
+ drop_near(q_ptr, -1, p_ptr->py, p_ptr->px);
+
+ /* All done */
+ msg_print("Allocated.");
+}
+
+/*
+ * Hack -- quick debugging hook
+ */
+void do_cmd_wiz_hack_ben(int num)
+{
+ s32b a;
+
+ /* MAKE(r_ptr, monster_race);
+ COPY(r_ptr, &r_info[500], monster_race);
+
+ r_ptr->level = 1;
+ r_ptr->flags6 |= RF6_BLINK;
+ r_ptr->freq_inate = r_ptr->freq_spell = 90;
+
+ place_monster_one_race = r_ptr;
+ place_monster_one(p_ptr->py - 1, p_ptr->px, 500, 0, TRUE, MSTATUS_PET);*/
+
+ get_lua_var("a", 'd', &a);
+ msg_format("a: %d", a);
+
+ /* Success */
+ return;
+}
+
+void do_cmd_lua_script()
+{
+ char script[80] = "tome_dofile_anywhere(ANGBAND_DIR_CORE, 'gen_idx.lua')";
+
+ if (!get_string("Script:", script, 80)) return;
+
+ exec_lua(script);
+
+ /* Success */
+ return;
+}
+
+
+#ifdef MONSTER_HORDES
+
+/* Summon a horde of monsters */
+static void do_cmd_summon_horde()
+{
+ int wy = p_ptr->py, wx = p_ptr->px;
+ int attempts = 1000;
+
+ while (--attempts)
+ {
+ scatter(&wy, &wx, p_ptr->py, p_ptr->px, 3);
+ if (cave_naked_bold(wy, wx)) break;
+ }
+
+ (void)alloc_horde(wy, wx);
+}
+
+#endif /* MONSTER_HORDES */
+
+
+/*
+ * Output a long int in binary format.
+ */
+static void prt_binary(u32b flags, int row, int col)
+{
+ int i;
+ u32b bitmask;
+
+ /* Scan the flags */
+ for (i = bitmask = 1; i <= 32; i++, bitmask *= 2)
+ {
+ /* Dump set bits */
+ if (flags & bitmask)
+ {
+ Term_putch(col++, row, TERM_BLUE, '*');
+ }
+
+ /* Dump unset bits */
+ else
+ {
+ Term_putch(col++, row, TERM_WHITE, '-');
+ }
+ }
+}
+
+
+/*
+ * Hack -- Teleport to the target
+ */
+static void do_cmd_wiz_bamf(void)
+{
+ /* Must have a target */
+ if (!target_who) return;
+
+ /* Teleport to the target */
+ teleport_player_to(target_row, target_col);
+}
+
+
+/*
+ * Aux function for "do_cmd_wiz_change()". -RAK-
+ */
+static void do_cmd_wiz_change_aux(void)
+{
+ int i;
+ int tmp_int;
+ long tmp_long;
+ char tmp_val[160];
+ char ppp[80];
+
+
+ /* Query the stats */
+ for (i = 0; i < 6; i++)
+ {
+ /* Prompt */
+ sprintf(ppp, "%s: (3-118): ", stat_names[i]);
+
+ /* Default */
+ sprintf(tmp_val, "%d", p_ptr->stat_max[i]);
+
+ /* Query */
+ if (!get_string(ppp, tmp_val, 3)) return;
+
+ /* Extract */
+ tmp_int = atoi(tmp_val);
+
+ /* Verify */
+ if (tmp_int > 18 + 100) tmp_int = 18 + 100;
+ else if (tmp_int < 3) tmp_int = 3;
+
+ /* Save it */
+ p_ptr->stat_cur[i] = p_ptr->stat_max[i] = tmp_int;
+ }
+
+
+ /* Default */
+ sprintf(tmp_val, "%ld", (long)(p_ptr->au));
+
+ /* Query */
+ if (!get_string("Gold: ", tmp_val, 9)) return;
+
+ /* Extract */
+ tmp_long = atol(tmp_val);
+
+ /* Verify */
+ if (tmp_long < 0) tmp_long = 0L;
+
+ /* Save */
+ p_ptr->au = tmp_long;
+
+
+ /* Default */
+ sprintf(tmp_val, "%ld", (long)(p_ptr->max_exp));
+
+ /* Query */
+ if (!get_string("Experience: ", tmp_val, 9)) return;
+
+ /* Extract */
+ tmp_long = atol(tmp_val);
+
+ /* Verify */
+ if (tmp_long < 0) tmp_long = 0L;
+
+ /* Save */
+ p_ptr->max_exp = tmp_long;
+ p_ptr->exp = tmp_long;
+
+ /* Update */
+ check_experience();
+
+ /* Default */
+ sprintf(tmp_val, "%d", p_ptr->luck_base);
+
+ /* Query */
+ if (!get_string("Luck(base): ", tmp_val, 3)) return;
+
+ /* Extract */
+ tmp_long = atol(tmp_val);
+
+ /* Save */
+ p_ptr->luck_base = tmp_long;
+ p_ptr->luck_max = tmp_long;
+}
+
+
+/*
+ * Change various "permanent" player variables.
+ */
+static void do_cmd_wiz_change(void)
+{
+ /* Interact */
+ do_cmd_wiz_change_aux();
+
+ /* Redraw everything */
+ do_cmd_redraw();
+}
+
+
+/*
+ * Wizard routines for creating objects -RAK-
+ * And for manipulating them! -Bernd-
+ *
+ * This has been rewritten to make the whole procedure
+ * of debugging objects much easier and more comfortable.
+ *
+ * The following functions are meant to play with objects:
+ * Create, modify, roll for them (for statistic purposes) and more.
+ * The original functions were by RAK.
+ * The function to show an item's debug information was written
+ * by David Reeve Sward <sward+@CMU.EDU>.
+ * Bernd (wiebelt@mathematik.hu-berlin.de)
+ *
+ * Here are the low-level functions
+ * - wiz_display_item()
+ * display an item's debug-info
+ * - wiz_create_itemtype()
+ * specify tval and sval (type and subtype of object)
+ * - wiz_tweak_item()
+ * specify pval, +AC, +tohit, +todam
+ * Note that the wizard can leave this function anytime,
+ * thus accepting the default-values for the remaining values.
+ * pval comes first now, since it is most important.
+ * - wiz_reroll_item()
+ * apply some magic to the item or turn it into an artifact.
+ * - wiz_roll_item()
+ * Get some statistics about the rarity of an item:
+ * We create a lot of fake items and see if they are of the
+ * same type (tval and sval), then we compare pval and +AC.
+ * If the fake-item is better or equal it is counted.
+ * Note that cursed items that are better or equal (absolute values)
+ * are counted, too.
+ * HINT: This is *very* useful for balancing the game!
+ * - wiz_quantity_item()
+ * change the quantity of an item, but be sane about it.
+ *
+ * And now the high-level functions
+ * - do_cmd_wiz_play()
+ * play with an existing object
+ * - wiz_create_item()
+ * create a new object
+ *
+ * Note -- You do not have to specify "pval" and other item-properties
+ * directly. Just apply magic until you are satisfied with the item.
+ *
+ * Note -- For some items (such as wands, staffs, some rings, etc), you
+ * must apply magic, or you will get "broken" or "uncharged" objects.
+ *
+ * Note -- Redefining artifacts via "do_cmd_wiz_play()" may destroy
+ * the artifact. Be careful.
+ *
+ * Hack -- this function will allow you to create multiple artifacts.
+ * This "feature" may induce crashes or other nasty effects.
+ */
+
+/*
+ * Just display an item's properties (debug-info)
+ * Originally by David Reeve Sward <sward+@CMU.EDU>
+ * Verbose item flags by -Bernd-
+ */
+static void wiz_display_item(object_type *o_ptr)
+{
+ int i, j = 13;
+ u32b f1, f2, f3, f4, f5, esp;
+ char buf[256];
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Clear the screen */
+ for (i = 1; i <= 23; i++) prt("", i, j - 2);
+
+ /* Describe fully */
+ object_desc_store(buf, o_ptr, TRUE, 3);
+
+ prt(buf, 2, j);
+
+ prt(format("kind = %-5d level = %-4d tval = %-5d sval = %-5d",
+ o_ptr->k_idx, k_info[o_ptr->k_idx].level,
+ o_ptr->tval, o_ptr->sval), 4, j);
+
+ prt(format("number = %-3d wgt = %-6d ac = %-5d damage = %dd%d",
+ o_ptr->number, o_ptr->weight,
+ o_ptr->ac, o_ptr->dd, o_ptr->ds), 5, j);
+
+ prt(format("pval = %-5d toac = %-5d tohit = %-4d todam = %-4d",
+ o_ptr->pval, o_ptr->to_a, o_ptr->to_h, o_ptr->to_d), 6, j);
+
+ prt(format("name1 = %-4d name2 = %-4d cost = %ld pval2 = %-5d",
+ o_ptr->name1, o_ptr->name2, (long)object_value(o_ptr), o_ptr->pval2), 7, j);
+
+ prt(format("ident = %04x timeout = %-d",
+ o_ptr->ident, o_ptr->timeout), 8, j);
+
+ prt("+------------FLAGS1------------+", 10, j);
+ prt("AFFECT........SLAY........BRAND.", 11, j);
+ prt(" cvae xsqpaefc", 12, j);
+ prt("siwdcc ssidsahanvudotgddhuoclio", 13, j);
+ prt("tnieoh trnipttmiinmrrnrrraiierl", 14, j);
+ prt("rtsxna..lcfgdkcpmldncltggpksdced", 15, j);
+ prt_binary(f1, 16, j);
+
+ prt("+------------FLAGS2------------+", 17, j);
+ prt("SUST....IMMUN.RESIST............", 18, j);
+ prt(" aefcprpsaefcpfldbc sn ", 19, j);
+ prt("siwdcc cliooeatcliooeialoshtncd", 20, j);
+ prt("tnieoh ierlifraierliatrnnnrhehi", 21, j);
+ prt("rtsxna..dcedslatdcedsrekdfddrxss", 22, j);
+ prt_binary(f2, 23, j);
+
+ prt("+------------FLAGS3------------+", 10, j + 32);
+ prt("fe ehsi st iiiiadta hp", 11, j + 32);
+ prt("il n taihnf ee ggggcregb vr", 12, j + 32);
+ prt("re nowysdose eld nnnntalrl ym", 13, j + 32);
+ prt("ec omrcyewta ieirmsrrrriieaeccc", 14, j + 32);
+ prt("aa taauktmatlnpgeihaefcvnpvsuuu", 15, j + 32);
+ prt("uu egirnyoahivaeggoclioaeoasrrr", 16, j + 32);
+ prt("rr litsopdretitsehtierltxrtesss", 17, j + 32);
+ prt("aa echewestreshtntsdcedeptedeee", 18, j + 32);
+ prt_binary(f3, 19, j + 32);
+}
+
+
+/*
+ * A list of tvals and their textual names
+ */
+tval_desc2 tvals[] =
+{
+ { TV_SWORD, "Sword" },
+ { TV_POLEARM, "Polearm" },
+ { TV_HAFTED, "Hafted Weapon" },
+ { TV_AXE, "Axe" },
+ { TV_BOW, "Bow" },
+ { TV_BOOMERANG, "Boomerang" },
+ { TV_ARROW, "Arrows" },
+ { TV_BOLT, "Bolts" },
+ { TV_SHOT, "Shots" },
+ { TV_SHIELD, "Shield" },
+ { TV_CROWN, "Crown" },
+ { TV_HELM, "Helm" },
+ { TV_GLOVES, "Gloves" },
+ { TV_BOOTS, "Boots" },
+ { TV_CLOAK, "Cloak" },
+ { TV_DRAG_ARMOR, "Dragon Scale Mail" },
+ { TV_HARD_ARMOR, "Hard Armor" },
+ { TV_SOFT_ARMOR, "Soft Armor" },
+ { TV_RING, "Ring" },
+ { TV_AMULET, "Amulet" },
+ { TV_LITE, "Lite" },
+ { TV_POTION, "Potion" },
+ { TV_POTION2, "Potion" },
+ { TV_SCROLL, "Scroll" },
+ { TV_WAND, "Wand" },
+ { TV_STAFF, "Staff" },
+ { TV_ROD_MAIN, "Rod" },
+ { TV_ROD, "Rod Tip" },
+ { TV_BOOK, "Schools Spellbook", },
+ { TV_SYMBIOTIC_BOOK, "Symbiotic Spellbook", },
+ { TV_DRUID_BOOK, "Elemental Stone" },
+ { TV_MUSIC_BOOK, "Music Book" },
+ { TV_DAEMON_BOOK, "Daemon Book" },
+ { TV_SPIKE, "Spikes" },
+ { TV_DIGGING, "Digger" },
+ { TV_CHEST, "Chest" },
+ { TV_FOOD, "Food" },
+ { TV_FLASK, "Flask" },
+ { TV_MSTAFF, "Mage Staff" },
+ { TV_BATERIE, "Essence" },
+ { TV_PARCHMENT, "Parchment" },
+ { TV_INSTRUMENT, "Musical Instrument" },
+ { TV_RUNE1, "Rune 1" },
+ { TV_RUNE2, "Rune 2" },
+ { TV_JUNK, "Junk" },
+ { TV_TRAPKIT, "Trapping Kit" },
+ { 0, NULL }
+};
+
+
+/*
+ * Strip an "object name" into a buffer
+ */
+static void strip_name(char *buf, int k_idx)
+{
+ char *t;
+
+ object_kind *k_ptr = &k_info[k_idx];
+
+ cptr str = (k_name + k_ptr->name);
+
+
+ /* Skip past leading characters */
+ while ((*str == ' ') || (*str == '&')) str++;
+
+ /* Copy useful chars */
+ for (t = buf; *str; str++)
+ {
+ if (*str != '~') *t++ = *str;
+ }
+
+ /* Terminate the new name */
+ *t = '\0';
+}
+
+
+/*
+ * Hack -- title for each column
+ *
+ * XXX XXX XXX This will not work with "EBCDIC", I would think.
+ */
+static char head[4] = { 'a', 'A', '0', ':' };
+
+
+/*
+ * Print a string as required by wiz_create_itemtype().
+ * Trims characters from the beginning until it fits in the space
+ * before the next row or the edge of the screen.
+ */
+static void wci_string(cptr string, int num)
+{
+ int row = 2 + (num % 20), col = 30 * (num / 20);
+ int ch = head[num / 20] + (num % 20), max_len = 0;
+
+ if (76-col < (signed)max_len)
+ max_len = 76-col;
+ else
+ max_len = 30-6;
+
+ if (strlen(string) > (unsigned)max_len)
+ string = string + (strlen(string) - max_len);
+
+ prt(format("[%c] %s", ch, string), row, col);
+}
+
+/*
+ * Specify tval and sval (type and subtype of object) originally
+ * by RAK, heavily modified by -Bernd-
+ *
+ * This function returns the k_idx of an object type, or zero if failed
+ *
+ * List up to 50 choices in three columns
+ */
+static int wiz_create_itemtype(void)
+{
+ int i, num, max_num;
+ int tval;
+
+ cptr tval_desc2;
+ char ch;
+
+ int choice[60];
+
+ char buf[160];
+
+
+ /* Clear screen */
+ Term_clear();
+
+ /* Print all tval's and their descriptions */
+ for (num = 0; (num < 60) && tvals[num].tval; num++)
+ {
+ wci_string(tvals[num].desc, num);
+ }
+
+ /* Me need to know the maximal possible tval_index */
+ max_num = num;
+
+ /* Choose! */
+ if (!get_com("Get what type of object? ", &ch)) return (0);
+
+ /* Analyze choice */
+ num = -1;
+ if ((ch >= head[0]) && (ch < head[0] + 20)) num = ch - head[0];
+ if ((ch >= head[1]) && (ch < head[1] + 20)) num = ch - head[1] + 20;
+ if ((ch >= head[2]) && (ch < head[2] + 17)) num = ch - head[2] + 40;
+
+ /* Bail out if choice is illegal */
+ if ((num < 0) || (num >= max_num)) return (0);
+
+ /* Base object type chosen, fill in tval */
+ tval = tvals[num].tval;
+ tval_desc2 = tvals[num].desc;
+
+
+ /*** And now we go for k_idx ***/
+
+ /* Clear screen */
+ Term_clear();
+
+ /* We have to search the whole itemlist. */
+ for (num = 0, i = 1; (num < 60) && (i < max_k_idx); i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+
+ /* Analyze matching items */
+ if (k_ptr->tval == tval)
+ {
+ /* Hack -- Skip instant artifacts */
+ if (k_ptr->flags3 & (TR3_INSTA_ART)) continue;
+
+ /* Acquire the "name" of object "i" */
+ strip_name(buf, i);
+
+ /* Print it */
+ wci_string(buf, num);
+
+ /* Remember the object index */
+ choice[num++] = i;
+ }
+ }
+
+ /* Me need to know the maximal possible remembered object_index */
+ max_num = num;
+
+ /* Choose! */
+ if (!get_com(format("What Kind of %s? ", tval_desc2), &ch)) return (0);
+
+ /* Analyze choice */
+ num = -1;
+ if ((ch >= head[0]) && (ch < head[0] + 20)) num = ch - head[0];
+ if ((ch >= head[1]) && (ch < head[1] + 20)) num = ch - head[1] + 20;
+ if ((ch >= head[2]) && (ch < head[2] + 17)) num = ch - head[2] + 40;
+
+ /* Bail out if choice is "illegal" */
+ if ((num < 0) || (num >= max_num)) return (0);
+
+ /* And return successful */
+ return (choice[num]);
+}
+
+
+/*
+ * Tweak an item
+ */
+static void wiz_tweak_item(object_type *o_ptr)
+{
+ cptr p;
+ char tmp_val[80];
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+
+ p = "Enter new 'pval' setting: ";
+ sprintf(tmp_val, "%ld", (long int) o_ptr->pval);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->pval = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+
+ p = "Enter new 'pval2' setting: ";
+ sprintf(tmp_val, "%d", o_ptr->pval2);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->pval2 = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+
+ p = "Enter new 'pval3' setting: ";
+ sprintf(tmp_val, "%ld", (long int) o_ptr->pval3);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->pval3 = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+
+ p = "Enter new 'to_a' setting: ";
+ sprintf(tmp_val, "%d", o_ptr->to_a);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->to_a = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+
+ p = "Enter new 'to_h' setting: ";
+ sprintf(tmp_val, "%d", o_ptr->to_h);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->to_h = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+
+ p = "Enter new 'to_d' setting: ";
+ sprintf(tmp_val, "%d", o_ptr->to_d);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->to_d = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+
+ p = "Enter new 'name2' setting: ";
+ sprintf(tmp_val, "%d", o_ptr->name2);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->name2 = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+
+ p = "Enter new 'name2b' setting: ";
+ sprintf(tmp_val, "%d", o_ptr->name2b);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->name2b = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+
+ p = "Enter new 'sval' setting: ";
+ sprintf(tmp_val, "%d", o_ptr->sval);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->sval = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+
+ p = "Enter new 'obj exp' setting: ";
+ sprintf(tmp_val, "%ld", (long int) o_ptr->exp);
+ if (!get_string(p, tmp_val, 9)) return;
+ wiz_display_item(o_ptr);
+ o_ptr->exp = atoi(tmp_val);
+ if (f4 & TR4_LEVELS) check_experience_obj(o_ptr);
+
+ p = "Enter new 'timeout' setting: ";
+ sprintf(tmp_val, "%d", o_ptr->timeout);
+ if (!get_string(p, tmp_val, 5)) return;
+ o_ptr->timeout = atoi(tmp_val);
+ wiz_display_item(o_ptr);
+}
+
+
+/*
+ * Apply magic to an item or turn it into an artifact. -Bernd-
+ */
+static void wiz_reroll_item(object_type *o_ptr)
+{
+ object_type forge;
+ object_type *q_ptr;
+
+ char ch;
+
+ bool_ changed = FALSE;
+
+
+ /* Hack -- leave artifacts alone */
+ if (artifact_p(o_ptr) || o_ptr->art_name) return;
+
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Copy the object */
+ object_copy(q_ptr, o_ptr);
+
+
+ /* Main loop. Ask for magification and artifactification */
+ while (TRUE)
+ {
+ /* Display full item debug information */
+ wiz_display_item(q_ptr);
+
+ /* Ask wizard what to do. */
+ if (!get_com("[a]ccept, [b]ad, [n]ormal, [g]ood, [e]xcellent, [r]andart? ", &ch))
+ {
+ changed = FALSE;
+ break;
+ }
+
+ /* Create/change it! */
+ if (ch == 'A' || ch == 'a')
+ {
+ changed = TRUE;
+ break;
+ }
+
+ /* Apply bad magic, but first clear object */
+ else if (ch == 'b' || ch == 'B')
+ {
+ object_prep(q_ptr, o_ptr->k_idx);
+ hack_apply_magic_power = -2;
+ apply_magic(q_ptr, dun_level, FALSE, FALSE, FALSE);
+ }
+
+ /* Apply normal magic, but first clear object */
+ else if (ch == 'n' || ch == 'N')
+ {
+ object_prep(q_ptr, o_ptr->k_idx);
+ apply_magic(q_ptr, dun_level, FALSE, FALSE, FALSE);
+ }
+
+ /* Apply good magic, but first clear object */
+ else if (ch == 'g' || ch == 'g')
+ {
+ object_prep(q_ptr, o_ptr->k_idx);
+ apply_magic(q_ptr, dun_level, FALSE, TRUE, FALSE);
+ }
+
+ /* Apply great magic, but first clear object */
+ else if (ch == 'e' || ch == 'e')
+ {
+ object_prep(q_ptr, o_ptr->k_idx);
+ apply_magic(q_ptr, dun_level, FALSE, TRUE, TRUE);
+ }
+
+ /* Apply great magic, but first clear object */
+ else if (ch == 'r' || ch == 'r')
+ {
+ object_prep(q_ptr, o_ptr->k_idx);
+ create_artifact(q_ptr, FALSE, TRUE);
+ }
+ }
+
+
+ /* Notice change */
+ if (changed)
+ {
+ /* Apply changes */
+ object_copy(o_ptr, q_ptr);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ }
+}
+
+
+
+/*
+ * Maximum number of rolls
+ */
+#define TEST_ROLL 100000
+
+
+/*
+ * Try to create an item again. Output some statistics. -Bernd-
+ *
+ * The statistics are correct now. We acquire a clean grid, and then
+ * repeatedly place an object in this grid, copying it into an item
+ * holder, and then deleting the object. We fiddle with the artifact
+ * counter flags to prevent weirdness. We use the items to collect
+ * statistics on item creation relative to the initial item.
+ */
+static void wiz_statistics(object_type *o_ptr)
+{
+ long i, matches, better, worse, other;
+
+ char ch;
+ char *quality;
+
+ bool_ good, great;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ obj_theme theme;
+
+ cptr q = "Rolls: %ld, Matches: %ld, Better: %ld, Worse: %ld, Other: %ld";
+
+ /* We can have everything */
+ theme.treasure = OBJ_GENE_TREASURE;
+ theme.combat = OBJ_GENE_COMBAT;
+ theme.magic = OBJ_GENE_MAGIC;
+ theme.tools = OBJ_GENE_TOOL;
+
+ /* XXX XXX XXX Mega-Hack -- allow multiple artifacts */
+ if (artifact_p(o_ptr))
+ {
+ if (o_ptr->tval == TV_RANDART)
+ {
+ random_artifacts[o_ptr->sval].generated = FALSE;
+ }
+ else
+ {
+ a_info[o_ptr->name1].cur_num = 0;
+ }
+ }
+
+
+ /* Interact */
+ while (TRUE)
+ {
+ cptr pmt = "Roll for [n]ormal, [g]ood, or [e]xcellent treasure? ";
+
+ /* Display item */
+ wiz_display_item(o_ptr);
+
+ /* Get choices */
+ if (!get_com(pmt, &ch)) break;
+
+ if (ch == 'n' || ch == 'N')
+ {
+ good = FALSE;
+ great = FALSE;
+ quality = "normal";
+ }
+ else if (ch == 'g' || ch == 'G')
+ {
+ good = TRUE;
+ great = FALSE;
+ quality = "good";
+ }
+ else if (ch == 'e' || ch == 'E')
+ {
+ good = TRUE;
+ great = TRUE;
+ quality = "excellent";
+ }
+ else
+ {
+ good = FALSE;
+ great = FALSE;
+ break;
+ }
+
+ /* Let us know what we are doing */
+ msg_format("Creating a lot of %s items. Base level = %d.",
+ quality, dun_level);
+ msg_print(NULL);
+
+ /* Set counters to zero */
+ matches = better = worse = other = 0;
+
+ /* Let's rock and roll */
+ for (i = 0; i <= TEST_ROLL; i++)
+ {
+ /* Output every few rolls */
+ if ((i < 100) || (i % 100 == 0))
+ {
+ /* Do not wait */
+ inkey_scan = TRUE;
+
+ /* Allow interupt */
+ if (inkey())
+ {
+ /* Flush */
+ flush();
+
+ /* Stop rolling */
+ break;
+ }
+
+ /* Dump the stats */
+ prt(format(q, i, matches, better, worse, other), 0, 0);
+ Term_fresh();
+ }
+
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Create an object */
+ make_object(q_ptr, good, great, theme);
+
+
+ /* XXX XXX XXX Mega-Hack -- allow multiple artifacts */
+ if (artifact_p(q_ptr))
+ {
+ if (q_ptr->tval == TV_RANDART)
+ {
+ random_artifacts[q_ptr->sval].generated = FALSE;
+ }
+ else
+ {
+ a_info[q_ptr->name1].cur_num = 0;
+ }
+ }
+
+
+ /* Test for the same tval and sval. */
+ if ((o_ptr->tval) != (q_ptr->tval)) continue;
+ if ((o_ptr->sval) != (q_ptr->sval)) continue;
+
+ /* Check for match */
+ if ((q_ptr->pval == o_ptr->pval) &&
+ (q_ptr->to_a == o_ptr->to_a) &&
+ (q_ptr->to_h == o_ptr->to_h) &&
+ (q_ptr->to_d == o_ptr->to_d))
+ {
+ matches++;
+ }
+
+ /* Check for better */
+ else if ((q_ptr->pval >= o_ptr->pval) &&
+ (q_ptr->to_a >= o_ptr->to_a) &&
+ (q_ptr->to_h >= o_ptr->to_h) &&
+ (q_ptr->to_d >= o_ptr->to_d))
+ {
+ better++;
+ }
+
+ /* Check for worse */
+ else if ((q_ptr->pval <= o_ptr->pval) &&
+ (q_ptr->to_a <= o_ptr->to_a) &&
+ (q_ptr->to_h <= o_ptr->to_h) &&
+ (q_ptr->to_d <= o_ptr->to_d))
+ {
+ worse++;
+ }
+
+ /* Assume different */
+ else
+ {
+ other++;
+ }
+ }
+
+ /* Final dump */
+ msg_format(q, i, matches, better, worse, other);
+ msg_print(NULL);
+ }
+
+
+ /* Hack -- Normally only make a single artifact */
+ if (artifact_p(o_ptr))
+ {
+ if (o_ptr->tval == TV_RANDART)
+ {
+ random_artifacts[o_ptr->sval].generated = TRUE;
+ }
+ else
+ {
+ a_info[o_ptr->name1].cur_num = 1;
+ }
+ }
+}
+
+
+/*
+ * Change the quantity of a the item
+ */
+static void wiz_quantity_item(object_type *o_ptr)
+{
+ int tmp_int;
+ char tmp_val[100];
+
+ /* Default */
+ sprintf(tmp_val, "%d", o_ptr->number);
+
+ /* Query */
+ if (get_string("Quantity: ", tmp_val, 2))
+ {
+ /* Extract */
+ tmp_int = atoi(tmp_val);
+
+ /* Paranoia */
+ if (tmp_int < 1) tmp_int = 1;
+ if (tmp_int > 99) tmp_int = 99;
+
+ /* Accept modifications */
+ o_ptr->number = tmp_int;
+ }
+}
+
+
+
+/*
+ * Play with an item. Options include:
+ * - Output statistics (via wiz_roll_item)
+ * - Reroll item (via wiz_reroll_item)
+ * - Change properties (via wiz_tweak_item)
+ * - Change the number of items (via wiz_quantity_item)
+ */
+static void do_cmd_wiz_play(void)
+{
+ int item;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ object_type *o_ptr;
+
+ char ch;
+
+ bool_ changed;
+
+ cptr q, s;
+
+ /* Get an item */
+ q = "Play with which object? ";
+ s = "You have nothing to play with.";
+ if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return;
+
+ /* Get the item */
+ o_ptr = get_object(item);
+
+
+ /* The item was not changed */
+ changed = FALSE;
+
+
+ /* Icky */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Copy object */
+ object_copy(q_ptr, o_ptr);
+
+
+ /* The main loop */
+ while (TRUE)
+ {
+ /* Display the item */
+ wiz_display_item(q_ptr);
+
+ /* Get choice */
+ if (!get_com("[a]ccept [s]tatistics [r]eroll [t]weak [q]uantity apply[m]agic? ", &ch))
+ {
+ changed = FALSE;
+ break;
+ }
+
+ if (ch == 'A' || ch == 'a')
+ {
+ changed = TRUE;
+ break;
+ }
+
+ if (ch == 's' || ch == 'S')
+ {
+ wiz_statistics(q_ptr);
+ }
+
+ if (ch == 'r' || ch == 'r')
+ {
+ wiz_reroll_item(q_ptr);
+ }
+
+ if (ch == 't' || ch == 'T')
+ {
+ wiz_tweak_item(q_ptr);
+ }
+
+ if (ch == 'q' || ch == 'Q')
+ {
+ wiz_quantity_item(q_ptr);
+ }
+
+ if (ch == 'm' || ch == 'M')
+ {
+ int e = q_ptr->name2, eb = q_ptr->name2b;
+
+ object_prep(q_ptr, q_ptr->k_idx);
+ q_ptr->name2 = e;
+ q_ptr->name2b = eb;
+ apply_magic(q_ptr, dun_level, FALSE, FALSE, FALSE);
+ }
+ }
+
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Not Icky */
+ character_icky = FALSE;
+
+
+ /* Accept change */
+ if (changed)
+ {
+ /* Message */
+ msg_print("Changes accepted.");
+
+ /* Change */
+ object_copy(o_ptr, q_ptr);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Combine / Reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+ }
+
+ /* Ignore change */
+ else
+ {
+ msg_print("Changes ignored.");
+ }
+}
+
+
+/*
+ * Wizard routine for creating objects -RAK-
+ * Heavily modified to allow magification and artifactification -Bernd-
+ *
+ * Note that wizards cannot create objects on top of other objects.
+ *
+ * Hack -- this routine always makes a "dungeon object", and applies
+ * magic to it, and attempts to decline cursed items.
+ */
+static void wiz_create_item(void)
+{
+ object_type forge;
+ object_type *q_ptr;
+
+ int k_idx;
+
+
+ /* Icky */
+ character_icky = TRUE;
+
+ /* Save the screen */
+ Term_save();
+
+ /* Get object base type */
+ k_idx = wiz_create_itemtype();
+
+ /* Restore the screen */
+ Term_load();
+
+ /* Not Icky */
+ character_icky = FALSE;
+
+
+ /* Return if failed */
+ if (!k_idx) return;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Create the item */
+ object_prep(q_ptr, k_idx);
+
+ /* Apply magic (no messages, no artifacts) */
+ apply_magic(q_ptr, dun_level, FALSE, FALSE, FALSE);
+
+ /* Drop the object from heaven */
+ drop_near(q_ptr, -1, p_ptr->py, p_ptr->px);
+
+ /* All done */
+ msg_print("Allocated.");
+}
+
+/*
+ * As above, but takes the k_idx as a parameter instead of using menus.
+ */
+static void wiz_create_item_2(void)
+{
+ object_type forge;
+ object_type *q_ptr;
+ int a_idx;
+ cptr p = "Number of the object :";
+ char out_val[80] = "";
+
+ if (!get_string(p, out_val, 4)) return;
+ a_idx = atoi(out_val);
+
+ /* Return if failed or out-of-bounds */
+ if ((a_idx <= 0) || (a_idx >= max_k_idx)) return;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Create the item */
+ object_prep(q_ptr, a_idx);
+
+ /* Apply magic (no messages, no artifacts) */
+ apply_magic(q_ptr, dun_level, FALSE, FALSE, FALSE);
+
+ /* Drop the object from heaven */
+ drop_near(q_ptr, -1, p_ptr->py, p_ptr->px);
+
+ /* All done */
+ msg_print("Allocated.");
+}
+
+
+/*
+ * Cure everything instantly
+ */
+void do_cmd_wiz_cure_all(void)
+{
+ object_type *o_ptr;
+
+ /* Remove curses */
+ (void)remove_all_curse();
+
+ /* Restore stats */
+ (void)res_stat(A_STR, TRUE);
+ (void)res_stat(A_INT, TRUE);
+ (void)res_stat(A_WIS, TRUE);
+ (void)res_stat(A_CON, TRUE);
+ (void)res_stat(A_DEX, TRUE);
+ (void)res_stat(A_CHR, TRUE);
+
+ /* Restore the level */
+ (void)restore_level();
+
+ /* Heal the player */
+ p_ptr->chp = p_ptr->mhp;
+ p_ptr->chp_frac = 0;
+
+ /* Cure insanity of player */
+ p_ptr->csane = p_ptr->msane;
+ p_ptr->csane_frac = 0;
+
+ /* Heal the player monster */
+ /* Get the carried monster */
+ o_ptr = &p_ptr->inventory[INVEN_CARRY];
+ if (o_ptr->k_idx)
+ {
+ o_ptr->pval2 = o_ptr->pval3;
+ }
+
+ /* Restore mana */
+ p_ptr->csp = p_ptr->msp;
+ p_ptr->csp_frac = 0;
+
+ /* Cure stuff */
+ (void)set_blind(0);
+ (void)set_confused(0);
+ (void)set_poisoned(0);
+ (void)set_afraid(0);
+ (void)set_paralyzed(0);
+ (void)set_image(0);
+ (void)set_stun(0);
+ (void)set_cut(0);
+ (void)set_slow(0);
+ p_ptr->black_breath = FALSE;
+
+ /* No longer hungry */
+ (void)set_food(PY_FOOD_MAX - 1);
+
+ /* Redraw everything */
+ do_cmd_redraw();
+}
+
+
+/*
+ * Go to any level
+ */
+static void do_cmd_wiz_jump(void)
+{
+ /* Ask for level */
+ if (command_arg <= 0)
+ {
+ char ppp[80];
+
+ char tmp_val[160];
+
+ /* Prompt */
+ msg_format("dungeon_type : %d", dungeon_type);
+ sprintf(ppp, "Jump to level (0-%d): ", d_info[dungeon_type].maxdepth);
+
+ /* Default */
+ sprintf(tmp_val, "%d", dun_level);
+
+ /* Ask for a level */
+ if (!get_string(ppp, tmp_val, 10)) return;
+
+ /* Extract request */
+ command_arg = atoi(tmp_val);
+ }
+
+ /* Paranoia */
+ if (command_arg < 0) command_arg = 0;
+
+ /* Paranoia */
+ if (command_arg > d_info[dungeon_type].maxdepth) command_arg = d_info[dungeon_type].maxdepth;
+
+ /* Accept request */
+ msg_format("You jump to dungeon level %d.", command_arg);
+
+ autosave_checkpoint();
+
+ /* Change level */
+ dun_level = command_arg;
+
+ p_ptr->inside_arena = 0;
+ leaving_quest = p_ptr->inside_quest;
+
+ p_ptr->inside_quest = 0;
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+}
+
+
+/*
+ * Become aware of a lot of objects
+ */
+static void do_cmd_wiz_learn(void)
+{
+ int i;
+
+ object_type forge;
+ object_type *q_ptr;
+
+ /* Scan every object */
+ for (i = 1; i < max_k_idx; i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+
+ /* Induce awareness */
+ if (k_ptr->level <= command_arg)
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Prepare object */
+ object_prep(q_ptr, i);
+
+ /* Awareness */
+ object_aware(q_ptr);
+ }
+ }
+}
+
+
+/*
+ * Summon some creatures
+ */
+static void do_cmd_wiz_summon(int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ {
+ (void)summon_specific(p_ptr->py, p_ptr->px, dun_level, 0);
+ }
+}
+
+
+/*
+ * Summon a creature of the specified type
+ *
+ * XXX XXX XXX This function is rather dangerous
+ */
+static void do_cmd_wiz_named(int r_idx, bool_ slp)
+{
+ int i, x, y;
+
+ /* Paranoia */
+ /* if (!r_idx) return; */
+
+ /* Prevent illegal monsters */
+ if (r_idx >= max_r_idx) return;
+
+ /* Try 10 times */
+ for (i = 0; i < 10; i++)
+ {
+ int d = 1;
+
+ /* Pick a location */
+ scatter(&y, &x, p_ptr->py, p_ptr->px, d);
+
+ /* Require empty grids */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Place it (allow groups) */
+ m_allow_special[r_idx] = TRUE;
+ if (place_monster_aux(y, x, r_idx, slp, TRUE, MSTATUS_ENEMY)) break;
+ m_allow_special[r_idx] = FALSE;
+ }
+}
+
+
+/*
+ * Summon a creature of the specified type
+ *
+ * XXX XXX XXX This function is rather dangerous
+ */
+void do_cmd_wiz_named_friendly(int r_idx, bool_ slp)
+{
+ int i, x, y;
+
+ /* Paranoia */
+ /* if (!r_idx) return; */
+
+ /* Prevent illegal monsters */
+ if (r_idx >= max_r_idx) return;
+
+ /* Try 10 times */
+ m_allow_special[r_idx] = TRUE;
+ for (i = 0; i < 10; i++)
+ {
+ int d = 1;
+
+ /* Pick a location */
+ scatter(&y, &x, p_ptr->py, p_ptr->px, d);
+
+ /* Require empty grids */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Place it (allow groups) */
+ if (place_monster_aux(y, x, r_idx, slp, TRUE, MSTATUS_PET)) break;
+ }
+ m_allow_special[r_idx] = FALSE;
+}
+
+
+
+/*
+ * Hack -- Delete all nearby monsters
+ */
+static void do_cmd_wiz_zap(void)
+{
+ int i;
+
+ /* Genocide everyone nearby */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+
+ /* Paranoia -- Skip dead monsters */
+ if (!m_ptr->r_idx) continue;
+
+ /* Delete nearby monsters */
+ if (m_ptr->cdis <= MAX_SIGHT) delete_monster_idx(i);
+ }
+}
+
+
+extern void do_cmd_wiz_body(s16b bidx)
+ /* Might create problems with equipment slots. For safety,
+ be nude when calling this function */
+{
+ p_ptr->body_monster = bidx;
+ p_ptr->disembodied = FALSE;
+ p_ptr->chp = maxroll( (&r_info[bidx])->hdice, (&r_info[bidx])->hside);
+ do_cmd_redraw();
+}
+
+
+/*
+ * External function
+ */
+extern void do_cmd_spoilers(void);
+
+
+
+/*
+ * Hack -- declare external function
+ */
+extern void do_cmd_debug(void);
+
+
+
+/*
+ * Ask for and parse a "debug command"
+ * The "command_arg" may have been set.
+ */
+void do_cmd_debug(void)
+{
+ int x, y;
+ char cmd;
+
+
+ /* Get a "debug command" */
+ get_com("Debug Command: ", &cmd);
+
+ /* Analyze the command */
+ switch (cmd)
+ {
+ /* Nothing */
+ case ESCAPE:
+ case ' ':
+ case '\n':
+ case '\r':
+ break;
+
+
+ /* Hack -- Generate Spoilers */
+ case '"':
+ do_cmd_spoilers();
+ break;
+
+ case 'A':
+ status_main();
+ break;
+
+ /* Hack -- Help */
+ case '?':
+ do_cmd_help();
+ break;
+
+
+ /* Cure all maladies */
+ case 'a':
+ do_cmd_wiz_cure_all();
+ break;
+
+ /* Teleport to target */
+ case 'b':
+ do_cmd_wiz_bamf();
+ break;
+
+ case 'B':
+ do_cmd_wiz_body(command_arg);
+ break;
+
+ /* Create any object */
+ case '-':
+ wiz_create_item_2();
+ break;
+
+ /* Create any object */
+ case 'c':
+ wiz_create_item();
+ break;
+
+ /* Create a named artifact */
+ case 'C':
+ wiz_create_named_art();
+ break;
+
+ /* Detect everything */
+ case 'd':
+ detect_all(DEFAULT_RADIUS);
+ break;
+
+ /* Change of Dungeon type */
+ case 'D':
+ if ((command_arg >= 0) && (command_arg < max_d_idx))
+ {
+ dungeon_type = command_arg;
+ dun_level = d_info[dungeon_type].mindepth;
+ msg_format("You go into %s", d_text + d_info[dungeon_type].text);
+
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ }
+ break;
+
+ /* Edit character */
+ case 'e':
+ do_cmd_wiz_change();
+ break;
+
+ /* Change grid's mana */
+ case 'E':
+ cave[p_ptr->py][p_ptr->px].mana = command_arg;
+ break;
+
+ /* View item info */
+ case 'f':
+ identify_fully();
+ break;
+
+ /* Good Objects */
+ case 'g':
+ if (command_arg <= 0) command_arg = 1;
+ acquirement(p_ptr->py, p_ptr->px, command_arg, FALSE, TRUE);
+ break;
+
+ /* Hitpoint rerating */
+ case 'h':
+ do_cmd_rerate(); break;
+
+#ifdef MONSTER_HORDES
+ case 'H':
+ do_cmd_summon_horde(); break;
+#endif /* MONSTER_HORDES */
+
+ /* Identify */
+ case 'i':
+ (void)ident_spell();
+ break;
+
+ /* Go up or down in the dungeon */
+ case 'j':
+ do_cmd_wiz_jump();
+ break;
+
+ /* Self-Knowledge */
+ case 'k':
+ self_knowledge(NULL);
+ break;
+
+ /* Learn about objects */
+ case 'l':
+ do_cmd_wiz_learn();
+ break;
+
+ /* Magic Mapping */
+ case 'm':
+ map_area();
+ break;
+
+ /* corruption */
+ case 'M':
+ (void) gain_random_corruption(command_arg);
+ break;
+
+ /* Specific reward */
+ case 'r':
+ (void) gain_level_reward(command_arg);
+ break;
+
+ /* Create a trap */
+ case 'R':
+ wiz_place_trap(p_ptr->py, p_ptr->px, command_arg);
+ break;
+
+ /* Summon _friendly_ named monster */
+ case 'N':
+ do_cmd_wiz_named_friendly(command_arg, TRUE);
+ break;
+
+ /* Summon Named Monster */
+ case 'n':
+ do_cmd_wiz_named(command_arg, TRUE);
+ break;
+
+ /* Object playing routines */
+ case 'o':
+ do_cmd_wiz_play();
+ break;
+
+ /* Phase Door */
+ case 'p':
+ teleport_player(10);
+ break;
+
+ /* get a Quest */
+ case 'q':
+ {
+ /* if (quest[command_arg].status == QUEST_STATUS_UNTAKEN)*/
+ if ((command_arg >= 1) && (command_arg < MAX_Q_IDX_INIT) && (command_arg != QUEST_RANDOM))
+ {
+ quest[command_arg].status = QUEST_STATUS_TAKEN;
+ *(quest[command_arg].plot) = command_arg;
+ if (quest[command_arg].type == HOOK_TYPE_C) quest[command_arg].init(command_arg);
+ break;
+ }
+ break;
+ }
+
+ /* Make every dungeon square "known" to test streamers -KMW- */
+ case 'u':
+ {
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave[y][x].info |= (CAVE_GLOW | CAVE_MARK);
+ }
+ }
+ wiz_lite();
+ break;
+ }
+
+ case 'U':
+ {
+ p_ptr->necro_extra |= CLASS_UNDEAD;
+ do_cmd_wiz_named(5, TRUE);
+
+ p_ptr->necro_extra2 = 1;
+
+ /* Display the hitpoints */
+ p_ptr->update |= (PU_HP);
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ break;
+ }
+
+ /* Summon Random Monster(s) */
+ case 's':
+ if (command_arg <= 0) command_arg = 1;
+ do_cmd_wiz_summon(command_arg);
+ break;
+
+ /* Change the feature of the map */
+ case 'S':
+ cave[p_ptr->py][p_ptr->px].special = command_arg;
+ break;
+
+ /* Teleport */
+ case 't':
+ teleport_player_bypass = TRUE;
+ teleport_player(100);
+ teleport_player_bypass = FALSE;
+ break;
+
+ /* Teleport to a town */
+ case 'T':
+ if ((command_arg >= 1) && (command_arg <= max_real_towns))
+ teleport_player_town(command_arg);
+ break;
+
+ /* Very Good Objects */
+ case 'v':
+ if (command_arg <= 0) command_arg = 1;
+ acquirement(p_ptr->py, p_ptr->px, command_arg, TRUE, TRUE);
+ break;
+
+ /* Wizard Light the Level */
+ case 'w':
+ wiz_lite();
+ break;
+
+ /* Make a wish */
+ case 'W':
+ make_wish();
+ break;
+
+ /* Increase Experience */
+ case 'x':
+ if (command_arg)
+ {
+ gain_exp(command_arg);
+ }
+ else
+ {
+ gain_exp(p_ptr->exp + 1);
+ }
+ break;
+
+ /* Zap Monsters (Genocide) */
+ case 'z':
+ do_cmd_wiz_zap();
+ break;
+
+ /* Hack -- whatever I desire */
+ case '_':
+ do_cmd_wiz_hack_ben(command_arg);
+ break;
+
+ /* Mimic shape changing */
+ case '*':
+ p_ptr->tim_mimic = 100;
+ p_ptr->mimic_form = command_arg;
+ /* Redraw title */
+ p_ptr->redraw |= (PR_TITLE);
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+ break;
+
+ /* Gain a fate */
+ case '+':
+ {
+ int i;
+ gain_fate(command_arg);
+ for (i = 0; i < MAX_FATES; i++)
+ fates[i].know = TRUE;
+ break;
+ }
+
+ /* Change the feature of the map */
+ case 'F':
+ msg_format("Trap: %d", cave[p_ptr->py][p_ptr->px].t_idx);
+ msg_format("Old feature: %d", cave[p_ptr->py][p_ptr->px].feat);
+ msg_format("Special: %d", cave[p_ptr->py][p_ptr->px].special);
+ cave_set_feat(p_ptr->py, p_ptr->px, command_arg);
+ break;
+
+ case '=':
+ wiz_align_monster(command_arg);
+ break;
+
+ case '@':
+ wiz_inc_monster_level(command_arg);
+ break;
+
+ case '/':
+ summon_specific(p_ptr->py, p_ptr->px, max_dlv[dungeon_type], command_arg);
+ break;
+
+ case '>':
+ do_cmd_lua_script();
+ break;
+
+ /* Not a Wizard Command */
+ default:
+ if (!process_hooks(HOOK_DEBUG_COMMAND, "(d)", cmd))
+ msg_print("That is not a valid debug command.");
+ break;
+ }
+}
diff --git a/src/xtra1.c b/src/xtra1.c
new file mode 100644
index 00000000..933bc265
--- /dev/null
+++ b/src/xtra1.c
@@ -0,0 +1,4772 @@
+/* File: misc.c */
+
+/* Purpose: misc code */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+
+/*
+ * Converts stat num into a six-char (right justified) string
+ */
+void cnv_stat(int val, char *out_val)
+{
+ if (!linear_stats)
+ {
+ /* Above 18 */
+ if (val > 18)
+ {
+ int bonus = (val - 18);
+
+ if (bonus >= 220)
+ {
+ sprintf(out_val, "18/%3s", "***");
+ }
+ else if (bonus >= 100)
+ {
+ sprintf(out_val, "18/%03d", bonus);
+ }
+ else
+ {
+ sprintf(out_val, " 18/%02d", bonus);
+ }
+ }
+
+ /* From 3 to 18 */
+ else
+ {
+ sprintf(out_val, " %2d", val);
+ }
+ }
+ else
+ {
+ /* Above 18 */
+ if (val > 18)
+ {
+ int bonus = (val - 18);
+
+ if (bonus >= 220)
+ {
+ sprintf(out_val, " 40");
+ }
+ else
+ {
+ sprintf(out_val, " %2d", 18 + (bonus / 10));
+ }
+ }
+
+ /* From 3 to 18 */
+ else
+ {
+ sprintf(out_val, " %2d", val);
+ }
+ }
+}
+
+
+
+/*
+ * Modify a stat value by a "modifier", return new value
+ *
+ * Stats go up: 3,4,...,17,18,18/10,18/20,...,18/220
+ * Or even: 18/13, 18/23, 18/33, ..., 18/220
+ *
+ * Stats go down: 18/220, 18/210,..., 18/10, 18, 17, ..., 3
+ * Or even: 18/13, 18/03, 18, 17, ..., 3
+ */
+s16b modify_stat_value(int value, int amount)
+{
+ int i;
+
+ /* Reward */
+ if (amount > 0)
+ {
+ /* Apply each point */
+ for (i = 0; i < amount; i++)
+ {
+ /* One point at a time */
+ if (value < 18) value++;
+
+ /* Ten "points" at a time */
+ else value += 10;
+ }
+ }
+
+ /* Penalty */
+ else if (amount < 0)
+ {
+ /* Apply each point */
+ for (i = 0; i < (0 - amount); i++)
+ {
+ /* Ten points at a time */
+ if (value >= 18 + 10) value -= 10;
+
+ /* Hack -- prevent weirdness */
+ else if (value > 18) value = 18;
+
+ /* One point at a time */
+ else if (value > 3) value--;
+ }
+ }
+
+ /* Return new value */
+ return (value);
+}
+
+
+
+/*
+ * Print character info at given row, column in a 13 char field
+ */
+static void prt_field(cptr info, int row, int col)
+{
+ /* Dump 13 spaces to clear */
+ c_put_str(TERM_WHITE, " ", row, col);
+
+ /* Dump the info itself */
+ c_put_str(TERM_L_BLUE, info, row, col);
+}
+
+/*
+ * Prints players max/cur piety
+ */
+static void prt_piety(void)
+{
+ char tmp[32];
+
+ /* Do not show piety unless it matters */
+ if (!p_ptr->pgod) return;
+
+ c_put_str(TERM_L_WHITE, "Pt ", ROW_PIETY, COL_PIETY);
+
+ sprintf(tmp, "%9ld", (long) p_ptr->grace);
+
+ c_put_str((p_ptr->praying) ? TERM_L_BLUE : TERM_GREEN, tmp, ROW_PIETY,
+ COL_PIETY + 3);
+}
+
+
+/*
+ * Prints the player's current sanity.
+ */
+static void prt_sane(void)
+{
+ char tmp[32];
+ byte color;
+ int perc;
+
+ if (p_ptr->msane == 0)
+ {
+ perc = 100;
+ }
+ else
+ {
+ perc = (100 * p_ptr->csane) / p_ptr->msane;
+ }
+
+ c_put_str(TERM_ORANGE, "SN ", ROW_SANITY, COL_SANITY);
+
+ sprintf(tmp, "%4d/%4d", p_ptr->csane, p_ptr->msane);
+
+ if (perc >= 100)
+ {
+ color = TERM_L_GREEN;
+ }
+ else if (perc > (10 * hitpoint_warn))
+ {
+ color = TERM_YELLOW;
+ }
+ else
+ {
+ color = TERM_RED;
+ }
+
+ c_put_str(color, tmp, ROW_SANITY, COL_SANITY + 3);
+}
+
+
+/*
+ * Print character stat in given row, column
+ */
+static void prt_stat(int stat)
+{
+ char tmp[32];
+
+ cnv_stat(p_ptr->stat_use[stat], tmp);
+
+ /* Display "injured" stat */
+ if (p_ptr->stat_cur[stat] < p_ptr->stat_max[stat])
+ {
+ int colour;
+
+ if (p_ptr->stat_cnt[stat])
+ colour = TERM_ORANGE;
+ else
+ colour = TERM_YELLOW;
+
+ put_str(format("%s: ", stat_names_reduced[stat]), ROW_STAT + stat, 0);
+ c_put_str(colour, tmp, ROW_STAT + stat, COL_STAT + 6);
+ }
+
+ /* Display "healthy" stat */
+ else
+ {
+ put_str(format("%s: ", stat_names[stat]), ROW_STAT + stat, 0);
+ c_put_str(TERM_L_GREEN, tmp, ROW_STAT + stat, COL_STAT + 6);
+ }
+
+ /* Display "boosted" stat */
+ if (p_ptr->stat_cur[stat] > p_ptr->stat_max[stat])
+ {
+ put_str(format("%s: ", stat_names[stat]), ROW_STAT + stat, 0);
+ c_put_str(TERM_VIOLET, tmp, ROW_STAT + stat, COL_STAT + 6);
+ }
+
+ /* Indicate natural maximum */
+ if (p_ptr->stat_max[stat] == 18 + 100)
+ {
+ put_str("!", ROW_STAT + stat, 3);
+ }
+}
+
+
+
+
+/*
+ * Prints "title", including "wizard" or "winner" as needed.
+ */
+static void prt_title(void)
+{
+ cptr p = "";
+
+ /* Mimic shape */
+ if (p_ptr->mimic_form)
+ {
+ call_lua("get_mimic_info", "(d,s)", "s", p_ptr->mimic_form, "show_name", &p);
+ }
+
+ /* Wizard */
+ else if (wizard)
+ {
+ p = "[=-WIZARD-=]";
+ }
+
+ /* Winner */
+ else if (total_winner == WINNER_NORMAL)
+ {
+ p = "***WINNER***";
+ }
+
+ /* Ultra Winner */
+ else if (total_winner == WINNER_ULTRA)
+ {
+ p = "***GOD***";
+ }
+
+ /* Normal */
+ else
+ {
+ p = cp_ptr->titles[(p_ptr->lev - 1) / 5] + c_text;
+
+ }
+
+ prt_field(p, ROW_TITLE, COL_TITLE);
+}
+
+
+/*
+ * Prints level
+ */
+static void prt_level(void)
+{
+ char tmp[32];
+
+ sprintf(tmp, "%6d", p_ptr->lev);
+
+ if (p_ptr->lev >= p_ptr->max_plv)
+ {
+ put_str("LEVEL ", ROW_LEVEL, 0);
+ c_put_str(TERM_L_GREEN, tmp, ROW_LEVEL, COL_LEVEL + 6);
+ }
+ else
+ {
+ put_str("Level ", ROW_LEVEL, 0);
+ c_put_str(TERM_YELLOW, tmp, ROW_LEVEL, COL_LEVEL + 6);
+ }
+}
+
+
+/*
+ * Display the experience
+ */
+static void prt_exp(void)
+{
+ char out_val[32];
+
+ if (!exp_need)
+ {
+ (void)sprintf(out_val, "%8ld", (long)p_ptr->exp);
+ }
+ else
+ {
+ if ((p_ptr->lev >= PY_MAX_LEVEL) || (p_ptr->lev >= max_plev))
+ {
+ (void)sprintf(out_val, "********");
+ }
+ else
+ {
+ (void)sprintf(out_val, "%8ld", (long)(player_exp[p_ptr->lev - 1] * p_ptr->expfact / 100L) - p_ptr->exp);
+ }
+ }
+
+ if (p_ptr->exp >= p_ptr->max_exp)
+ {
+ put_str("EXP ", ROW_EXP, 0);
+ c_put_str(TERM_L_GREEN, out_val, ROW_EXP, COL_EXP + 4);
+ }
+ else
+ {
+ put_str("Exp ", ROW_EXP, 0);
+ c_put_str(TERM_YELLOW, out_val, ROW_EXP, COL_EXP + 4);
+ }
+}
+
+
+/*
+ * Prints current gold
+ */
+static void prt_gold(void)
+{
+ char tmp[32];
+
+ put_str("AU ", ROW_GOLD, COL_GOLD);
+ sprintf(tmp, "%9ld", (long)p_ptr->au);
+ c_put_str(TERM_L_GREEN, tmp, ROW_GOLD, COL_GOLD + 3);
+}
+
+
+
+/*
+ * Prints current AC
+ */
+static void prt_ac(void)
+{
+ char tmp[32];
+
+ put_str("Cur AC ", ROW_AC, COL_AC);
+ sprintf(tmp, "%5d", p_ptr->dis_ac + p_ptr->dis_to_a);
+ c_put_str(TERM_L_GREEN, tmp, ROW_AC, COL_AC + 7);
+}
+
+
+/*
+ * Prints Cur/Max hit points
+ */
+static void prt_hp(void)
+{
+ char tmp[32];
+
+ byte color;
+
+ if (player_char_health) lite_spot(p_ptr->py, p_ptr->px);
+
+ if (p_ptr->necro_extra & CLASS_UNDEAD)
+ {
+ c_put_str(TERM_L_DARK, "DP ", ROW_HP, COL_HP);
+
+ sprintf(tmp, "%4d/%4d", p_ptr->chp, p_ptr->mhp);
+
+ if (p_ptr->chp >= p_ptr->mhp)
+ {
+ color = TERM_L_BLUE;
+ }
+ else if (p_ptr->chp > (p_ptr->mhp * hitpoint_warn) / 10)
+ {
+ color = TERM_VIOLET;
+ }
+ else
+ {
+ color = TERM_L_RED;
+ }
+ c_put_str(color, tmp, ROW_HP, COL_HP + 3);
+ }
+ else
+ {
+ c_put_str(TERM_RED, "HP ", ROW_HP, COL_HP);
+
+ sprintf(tmp, "%4d/%4d", p_ptr->chp, p_ptr->mhp);
+
+ if (p_ptr->chp >= p_ptr->mhp)
+ {
+ color = TERM_L_GREEN;
+ }
+ else if (p_ptr->chp > (p_ptr->mhp * hitpoint_warn) / 10)
+ {
+ color = TERM_YELLOW;
+ }
+ else
+ {
+ color = TERM_RED;
+ }
+ c_put_str(color, tmp, ROW_HP, COL_HP + 3);
+ }
+}
+
+/*
+ * Prints Cur/Max monster hit points
+ */
+static void prt_mh(void)
+{
+ char tmp[32];
+
+ byte color;
+
+ object_type *o_ptr;
+
+ /* Get the carried monster */
+ o_ptr = &p_ptr->inventory[INVEN_CARRY];
+
+ if (!o_ptr->pval2)
+ {
+ put_str(" ", ROW_MH, COL_MH);
+ return;
+ }
+
+ put_str("MH ", ROW_MH, COL_MH);
+
+ sprintf(tmp, "%4d/%4d", o_ptr->pval2, (int)o_ptr->pval3);
+ if (o_ptr->pval2 >= o_ptr->pval3)
+ {
+ color = TERM_L_GREEN;
+ }
+ else if (o_ptr->pval2 > (o_ptr->pval3 * hitpoint_warn) / 10)
+ {
+ color = TERM_YELLOW;
+ }
+ else
+ {
+ color = TERM_RED;
+ }
+ c_put_str(color, tmp, ROW_MH, COL_MH + 3);
+}
+
+
+/*
+ * Prints players max/cur spell points
+ */
+static void prt_sp(void)
+{
+ char tmp[32];
+ byte color;
+
+
+ c_put_str(TERM_L_GREEN, "SP ", ROW_SP, COL_SP);
+
+ sprintf(tmp, "%4d/%4d", p_ptr->csp, p_ptr->msp);
+ if (p_ptr->csp >= p_ptr->msp)
+ {
+ color = TERM_L_GREEN;
+ }
+ else if (p_ptr->csp > (p_ptr->msp * hitpoint_warn) / 10)
+ {
+ color = TERM_YELLOW;
+ }
+ else
+ {
+ color = TERM_RED;
+ }
+ c_put_str(color, tmp, ROW_SP, COL_SP + 3);
+}
+
+
+/*
+ * Prints depth in stat area
+ */
+static void prt_depth(void)
+{
+ char depths[32];
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ if (p_ptr->wild_mode)
+ {
+ strcpy(depths, " ");
+ }
+ else if (p_ptr->inside_arena)
+ {
+ strcpy(depths, "Arena");
+ }
+ else if (get_dungeon_name(depths))
+ {
+ /* Empty */
+ }
+ else if (dungeon_flags2 & DF2_SPECIAL)
+ {
+ strcpy(depths, "Special");
+ }
+ else if (p_ptr->inside_quest)
+ {
+ strcpy(depths, "Quest");
+ }
+ else if (!dun_level)
+ {
+ if (wf_info[wild_map[p_ptr->wilderness_y][p_ptr->wilderness_x].feat].name + wf_name)
+ strcpy(depths, wf_info[wild_map[p_ptr->wilderness_y][p_ptr->wilderness_x].feat].name + wf_name);
+ else
+ strcpy(depths, "Town/Wild");
+ }
+ else if (depth_in_feet)
+ {
+ if (dungeon_flags1 & DF1_TOWER)
+ {
+ (void)strnfmt(depths, 32, "%c%c%c -%d ft",
+ d_ptr->short_name[0],
+ d_ptr->short_name[1],
+ d_ptr->short_name[2],
+ dun_level * 50);
+ }
+ else
+ {
+ (void)strnfmt(depths, 32, "%c%c%c %d ft",
+ d_ptr->short_name[0],
+ d_ptr->short_name[1],
+ d_ptr->short_name[2],
+ dun_level * 50);
+ }
+ }
+ else
+ {
+ if (dungeon_flags1 & DF1_TOWER)
+ {
+ (void)strnfmt(depths, 32, "%c%c%c -%d",
+ d_ptr->short_name[0],
+ d_ptr->short_name[1],
+ d_ptr->short_name[2],
+ dun_level);
+ }
+ else
+ {
+ (void)strnfmt(depths, 32, "%c%c%c %d",
+ d_ptr->short_name[0],
+ d_ptr->short_name[1],
+ d_ptr->short_name[2],
+ dun_level);
+ }
+ }
+
+ /* Right-Adjust the "depth", and clear old values */
+ if (p_ptr->word_recall)
+ c_prt(TERM_ORANGE, format("%13s", depths), ROW_DEPTH, COL_DEPTH);
+ else
+ prt(format("%13s", depths), ROW_DEPTH, COL_DEPTH);
+}
+
+
+/*
+ * Prints status of hunger
+ */
+static void prt_hunger(void)
+{
+ /* Fainting / Starving */
+ if (p_ptr->food < PY_FOOD_FAINT)
+ {
+ c_put_str(TERM_RED, "Weak ", ROW_HUNGRY, COL_HUNGRY);
+ }
+
+ /* Weak */
+ else if (p_ptr->food < PY_FOOD_WEAK)
+ {
+ c_put_str(TERM_ORANGE, "Weak ", ROW_HUNGRY, COL_HUNGRY);
+ }
+
+ /* Hungry */
+ else if (p_ptr->food < PY_FOOD_ALERT)
+ {
+ c_put_str(TERM_YELLOW, "Hungry", ROW_HUNGRY, COL_HUNGRY);
+ }
+
+ /* Normal */
+ else if (p_ptr->food < PY_FOOD_FULL)
+ {
+ c_put_str(TERM_L_GREEN, " ", ROW_HUNGRY, COL_HUNGRY);
+ }
+
+ /* Full */
+ else if (p_ptr->food < PY_FOOD_MAX)
+ {
+ c_put_str(TERM_L_GREEN, "Full ", ROW_HUNGRY, COL_HUNGRY);
+ }
+
+ /* Gorged */
+ else
+ {
+ c_put_str(TERM_GREEN, "Gorged", ROW_HUNGRY, COL_HUNGRY);
+ }
+}
+
+
+/*
+ * Prints Blind status
+ */
+static void prt_blind(void)
+{
+ if (p_ptr->blind)
+ {
+ c_put_str(TERM_ORANGE, "Blind", ROW_BLIND, COL_BLIND);
+ }
+ else
+ {
+ put_str(" ", ROW_BLIND, COL_BLIND);
+ }
+}
+
+
+/*
+ * Prints Confusion status
+ */
+static void prt_confused(void)
+{
+ if (p_ptr->confused)
+ {
+ c_put_str(TERM_ORANGE, "Conf", ROW_CONFUSED, COL_CONFUSED);
+ }
+ else
+ {
+ put_str(" ", ROW_CONFUSED, COL_CONFUSED);
+ }
+}
+
+
+/*
+ * Prints Fear status
+ */
+static void prt_afraid(void)
+{
+ if (p_ptr->afraid)
+ {
+ c_put_str(TERM_ORANGE, "Afraid", ROW_AFRAID, COL_AFRAID);
+ }
+ else
+ {
+ put_str(" ", ROW_AFRAID, COL_AFRAID);
+ }
+}
+
+
+/*
+ * Prints Poisoned status
+ */
+static void prt_poisoned(void)
+{
+ if (p_ptr->poisoned)
+ {
+ c_put_str(TERM_ORANGE, "Poison", ROW_POISONED, COL_POISONED);
+ }
+ else
+ {
+ put_str(" ", ROW_POISONED, COL_POISONED);
+ }
+}
+
+
+/*
+ * Prints trap detection status
+ */
+static void prt_dtrap(void)
+{
+ if (cave[p_ptr->py][p_ptr->px].info & CAVE_DETECT)
+ {
+ c_put_str(TERM_L_GREEN, "DTrap", ROW_DTRAP, COL_DTRAP);
+ }
+ else
+ {
+ put_str(" ", ROW_DTRAP, COL_DTRAP);
+ }
+}
+
+
+/*
+ * Prints Searching, Resting, Paralysis, or 'count' status
+ * Display is always exactly 10 characters wide (see below)
+ *
+ * This function was a major bottleneck when resting, so a lot of
+ * the text formatting code was optimized in place below.
+ */
+static void prt_state(void)
+{
+ byte attr = TERM_WHITE;
+
+ char text[16];
+
+
+ /* Paralysis */
+ if (p_ptr->paralyzed)
+ {
+ attr = TERM_RED;
+
+ strcpy(text, "Paralyzed!");
+ }
+
+ /* Resting */
+ else if (resting)
+ {
+ int i;
+
+ /* Start with "Rest" */
+ strcpy(text, "Rest ");
+
+ /* Extensive (timed) rest */
+ if (resting >= 1000)
+ {
+ i = resting / 100;
+ text[9] = '0';
+ text[8] = '0';
+ text[7] = '0' + (i % 10);
+ if (i >= 10)
+ {
+ i = i / 10;
+ text[6] = '0' + (i % 10);
+ if (i >= 10)
+ {
+ text[5] = '0' + (i / 10);
+ }
+ }
+ }
+
+ /* Long (timed) rest */
+ else if (resting >= 100)
+ {
+ i = resting;
+ text[9] = '0' + (i % 10);
+ i = i / 10;
+ text[8] = '0' + (i % 10);
+ text[7] = '0' + (i / 10);
+ }
+
+ /* Medium (timed) rest */
+ else if (resting >= 10)
+ {
+ i = resting;
+ text[9] = '0' + (i % 10);
+ text[8] = '0' + (i / 10);
+ }
+
+ /* Short (timed) rest */
+ else if (resting > 0)
+ {
+ i = resting;
+ text[9] = '0' + (i);
+ }
+
+ /* Rest until healed */
+ else if (resting == -1)
+ {
+ text[5] = text[6] = text[7] = text[8] = text[9] = '*';
+ }
+
+ /* Rest until done */
+ else if (resting == -2)
+ {
+ text[5] = text[6] = text[7] = text[8] = text[9] = '&';
+ }
+ }
+
+ /* Repeating */
+ else if (command_rep)
+ {
+ if (command_rep > 999)
+ {
+ (void)sprintf(text, "Rep. %3d00", command_rep / 100);
+ }
+ else
+ {
+ (void)sprintf(text, "Repeat %3d", command_rep);
+ }
+ }
+
+ /* Searching */
+ else if (p_ptr->searching)
+ {
+ strcpy(text, "Searching ");
+ }
+
+ /* Nothing interesting */
+ else
+ {
+ strcpy(text, " ");
+ }
+
+ /* Display the info (or blanks) */
+ c_put_str(attr, text, ROW_STATE, COL_STATE);
+}
+
+
+/*
+ * Prints the speed of a character. -CJS-
+ */
+static void prt_speed(void)
+{
+ int i = p_ptr->pspeed;
+
+ byte attr = TERM_WHITE;
+ char buf[32] = "";
+
+ /* Hack -- Visually "undo" the Search Mode Slowdown */
+ if (p_ptr->searching) i += 10;
+
+ /* Fast */
+ if (i > 110)
+ {
+ attr = TERM_L_GREEN;
+ sprintf(buf, "Fast (+%d)", (i - 110));
+ }
+
+ /* Slow */
+ else if (i < 110)
+ {
+ attr = TERM_L_UMBER;
+ sprintf(buf, "Slow (-%d)", (110 - i));
+ }
+
+ /* Display the speed */
+ c_put_str(attr, format("%-10s", buf), ROW_SPEED, COL_SPEED);
+}
+
+
+static void prt_study(void)
+{
+ if (p_ptr->skill_points)
+ {
+ put_str("Skill", ROW_STUDY, COL_STUDY);
+ }
+ else
+ {
+ put_str(" ", ROW_STUDY, COL_STUDY);
+ }
+}
+
+
+static void prt_cut(void)
+{
+ int c = p_ptr->cut;
+
+ if (c > 1000)
+ {
+ c_put_str(TERM_L_RED, "Mortal wound", ROW_CUT, COL_CUT);
+ }
+ else if (c > 200)
+ {
+ c_put_str(TERM_RED, "Deep gash ", ROW_CUT, COL_CUT);
+ }
+ else if (c > 100)
+ {
+ c_put_str(TERM_RED, "Severe cut ", ROW_CUT, COL_CUT);
+ }
+ else if (c > 50)
+ {
+ c_put_str(TERM_ORANGE, "Nasty cut ", ROW_CUT, COL_CUT);
+ }
+ else if (c > 25)
+ {
+ c_put_str(TERM_ORANGE, "Bad cut ", ROW_CUT, COL_CUT);
+ }
+ else if (c > 10)
+ {
+ c_put_str(TERM_YELLOW, "Light cut ", ROW_CUT, COL_CUT);
+ }
+ else if (c)
+ {
+ c_put_str(TERM_YELLOW, "Graze ", ROW_CUT, COL_CUT);
+ }
+ else
+ {
+ put_str(" ", ROW_CUT, COL_CUT);
+ }
+}
+
+
+
+static void prt_stun(void)
+{
+ int s = p_ptr->stun;
+
+ if (s > 100)
+ {
+ c_put_str(TERM_RED, "Knocked out ", ROW_STUN, COL_STUN);
+ }
+ else if (s > 50)
+ {
+ c_put_str(TERM_ORANGE, "Heavy stun ", ROW_STUN, COL_STUN);
+ }
+ else if (s)
+ {
+ c_put_str(TERM_ORANGE, "Stun ", ROW_STUN, COL_STUN);
+ }
+ else
+ {
+ put_str(" ", ROW_STUN, COL_STUN);
+ }
+}
+
+
+
+/*
+ * Redraw the "monster health bar" -DRS-
+ * Rather extensive modifications by -BEN-
+ *
+ * The "monster health bar" provides visual feedback on the "health"
+ * of the monster currently being "tracked". There are several ways
+ * to "track" a monster, including targetting it, attacking it, and
+ * affecting it (and nobody else) with a ranged attack.
+ *
+ * Display the monster health bar (affectionately known as the
+ * "health-o-meter"). Clear health bar if nothing is being tracked.
+ * Auto-track current target monster when bored. Note that the
+ * health-bar stops tracking any monster that "disappears".
+ */
+static void health_redraw(void)
+{
+
+#ifdef DRS_SHOW_HEALTH_BAR
+
+ /* Not tracking */
+ if (!health_who)
+ {
+ /* Erase the health bar */
+ Term_erase(COL_INFO, ROW_INFO, 12);
+ }
+
+ /* Tracking an unseen monster */
+ else if (!m_list[health_who].ml)
+ {
+ /* Indicate that the monster health is "unknown" */
+ Term_putstr(COL_INFO, ROW_INFO, 12, TERM_WHITE, "[----------]");
+ }
+
+ /* Tracking a hallucinatory monster */
+ else if (p_ptr->image)
+ {
+ /* Indicate that the monster health is "unknown" */
+ Term_putstr(COL_INFO, ROW_INFO, 12, TERM_WHITE, "[----------]");
+ }
+
+ /* Tracking a dead monster (???) */
+ else if (!m_list[health_who].hp < 0)
+ {
+ /* Indicate that the monster health is "unknown" */
+ Term_putstr(COL_INFO, ROW_INFO, 12, TERM_WHITE, "[----------]");
+ }
+
+ /* Tracking a visible monster */
+ else
+ {
+ int pct, len;
+
+ monster_type *m_ptr = &m_list[health_who];
+
+ /* Default to almost dead */
+ byte attr = TERM_RED;
+
+ /* Extract the "percent" of health */
+ pct = 100L * m_ptr->hp / m_ptr->maxhp;
+
+ /* Badly wounded */
+ if (pct >= 10) attr = TERM_L_RED;
+
+ /* Wounded */
+ if (pct >= 25) attr = TERM_ORANGE;
+
+ /* Somewhat Wounded */
+ if (pct >= 60) attr = TERM_YELLOW;
+
+ /* Healthy */
+ if (pct >= 100) attr = TERM_L_GREEN;
+
+ /* Afraid */
+ if (m_ptr->monfear) attr = TERM_VIOLET;
+
+ /* Asleep */
+ if (m_ptr->csleep) attr = TERM_BLUE;
+
+ /* Poisoned */
+ if (m_ptr->poisoned) attr = TERM_GREEN;
+
+ /* Bleeding */
+ if (m_ptr->bleeding) attr = TERM_RED;
+
+ /* Convert percent into "health" */
+ len = (pct < 10) ? 1 : (pct < 90) ? (pct / 10 + 1) : 10;
+
+ /* Default to "unknown" */
+ Term_putstr(COL_INFO, ROW_INFO, 12, TERM_WHITE, "[----------]");
+
+ /* Dump the current "health" (use '*' symbols) */
+ Term_putstr(COL_INFO + 1, ROW_INFO, len, attr, "**********");
+ }
+
+#endif
+
+}
+
+
+
+/*
+ * Display basic info (mostly left of map)
+ */
+static void prt_frame_basic(void)
+{
+ int i;
+
+ /* Race and Class */
+ prt_field(rp_ptr->title + rp_name, ROW_RACE, COL_RACE);
+ prt_field(spp_ptr->title + c_name, ROW_CLASS, COL_CLASS);
+
+ /* Title */
+ prt_title();
+
+ /* Level/Experience */
+ prt_level();
+ prt_exp();
+
+ /* All Stats */
+ for (i = 0; i < 6; i++) prt_stat(i);
+
+ /* Armor */
+ prt_ac();
+
+ /* Hitpoints */
+ prt_hp();
+
+ /* Current sanity */
+ prt_sane();
+
+ /* Spellpoints */
+ prt_sp();
+
+ /* Piety */
+ prt_piety();
+
+ /* Monster hitpoints */
+ prt_mh();
+
+ /* Gold */
+ prt_gold();
+
+ /* Current depth */
+ prt_depth();
+
+ /* Special */
+ health_redraw();
+}
+
+
+/*
+ * Display extra info (mostly below map)
+ */
+static void prt_frame_extra(void)
+{
+ /* Cut/Stun */
+ prt_cut();
+ prt_stun();
+
+ /* Food */
+ prt_hunger();
+
+ /* Various */
+ prt_blind();
+ prt_confused();
+ prt_afraid();
+ prt_poisoned();
+ prt_dtrap();
+
+ /* State */
+ prt_state();
+
+ /* Speed */
+ prt_speed();
+
+ /* Study spells */
+ prt_study();
+}
+
+
+/*
+ * Hack -- display inventory in sub-windows
+ */
+static void fix_inven(void)
+{
+ int j;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ term *old = Term;
+
+ /* No window */
+ if (!angband_term[j]) continue;
+
+ /* No relevant flags */
+ if (!(window_flag[j] & (PW_INVEN))) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Display inventory */
+ display_inven();
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+
+
+/*
+ * Hack -- display equipment in sub-windows
+ */
+static void fix_equip(void)
+{
+ int j;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ term *old = Term;
+
+ /* No window */
+ if (!angband_term[j]) continue;
+
+ /* No relevant flags */
+ if (!(window_flag[j] & (PW_EQUIP))) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Display equipment */
+ display_equip();
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+/*
+ * Hack -- display character in sub-windows
+ */
+static void fix_player(void)
+{
+ int j;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ term *old = Term;
+
+ /* No window */
+ if (!angband_term[j]) continue;
+
+ /* No relevant flags */
+ if (!(window_flag[j] & (PW_PLAYER))) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Display player */
+ display_player(0);
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+
+
+/*
+ * Hack -- display recent messages in sub-windows
+ *
+ * XXX XXX XXX Adjust for width and split messages
+ */
+void fix_message(void)
+{
+ int j, i;
+ int w, h;
+ int x, y;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ term *old = Term;
+
+ /* No window */
+ if (!angband_term[j]) continue;
+
+ /* No relevant flags */
+ if (!(window_flag[j] & (PW_MESSAGE))) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Get size */
+ Term_get_size(&w, &h);
+
+ /* Dump messages */
+ for (i = 0; i < h; i++)
+ {
+ /* Dump the message on the appropriate line */
+ display_message(0, (h - 1) - i, strlen(message_str((s16b)i)), message_color((s16b)i), message_str((s16b)i));
+
+ /* Cursor */
+ Term_locate(&x, &y);
+
+ /* Clear to end of line */
+ Term_erase(x, y, 255);
+ }
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+
+/*
+ * Hack -- display overhead view in sub-windows
+ *
+ * Note that the "player" symbol does NOT appear on the map.
+ */
+static void fix_overhead(void)
+{
+ int j;
+
+ int cy, cx;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ term *old = Term;
+
+ /* No window */
+ if (!angband_term[j]) continue;
+
+ /* No relevant flags */
+ if (!(window_flag[j] & (PW_OVERHEAD))) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Redraw map */
+ display_map(&cy, &cx);
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+
+/*
+ * Hack -- display monster recall in sub-windows
+ */
+static void fix_monster(void)
+{
+ int j;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ term *old = Term;
+
+ /* No window */
+ if (!angband_term[j]) continue;
+
+ /* No relevant flags */
+ if (!(window_flag[j] & (PW_MONSTER))) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Display monster race info */
+ if (monster_race_idx) display_roff(monster_race_idx, monster_ego_idx);
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+
+/*
+ * Hack -- display object recall in sub-windows
+ */
+static void fix_object(void)
+{
+ int j;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ term *old = Term;
+
+ /* No window */
+ if (!angband_term[j]) continue;
+
+ /* No relevant flags */
+ if (!(window_flag[j] & (PW_OBJECT))) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Clear */
+ Term_clear();
+
+ /* Display object info */
+ if (tracked_object)
+ if (!object_out_desc(tracked_object, NULL, FALSE, FALSE)) text_out("You see nothing special.");
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+/* Show the monster list in a window */
+
+static void fix_m_list(void)
+{
+ int i, j;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ term *old = Term;
+
+ int c = 0;
+
+ /* No window */
+ if (!angband_term[j]) continue;
+
+ /* No relevant flags */
+ if (!(window_flag[j] & (PW_M_LIST))) continue;
+
+ /* Activate */
+ Term_activate(angband_term[j]);
+
+ /* Clear */
+ Term_clear();
+
+ /* Hallucination */
+ if (p_ptr->image)
+ {
+ c_prt(TERM_WHITE, "You can not see clearly", 0, 0);
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+
+ return;
+ }
+
+ /* reset visible count */
+ for (i = 1; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ r_ptr->total_visible = 0;
+ }
+
+ /* Count up the number visible in each race */
+ for (i = 1; i < m_max; i++)
+ {
+ monster_type *m_ptr = &m_list[i];
+ monster_race *r_ptr = &r_info[m_ptr->r_idx];
+
+ /* Skip dead monsters */
+ if (m_ptr->hp < 0) continue;
+
+ /* Skip unseen monsters */
+ if (r_ptr->flags9 & RF9_MIMIC)
+ {
+ object_type *o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[m_ptr->hold_o_idx];
+
+ /* Memorized objects */
+ if (!o_ptr->marked) continue;
+ }
+ else
+ {
+ if (!m_ptr->ml) continue;
+ }
+
+ /* Increase for this race */
+ r_ptr->total_visible++;
+
+ /* Increase total Count */
+ c++;
+ }
+
+ /* Are monsters visible? */
+ if (c)
+ {
+ int w, h, num = 0;
+
+ (void)Term_get_size(&w, &h);
+
+ c_prt(TERM_WHITE, format("You can see %d monster%s", c, (c > 1 ? "s:" : ":")), 0, 0);
+
+ for (i = 1; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ /* Default Colour */
+ byte attr = TERM_SLATE;
+
+ /* Only visible monsters */
+ if (!r_ptr->total_visible) continue;
+
+ /* Uniques */
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ attr = TERM_L_BLUE;
+ }
+
+ /* Have we ever killed one? */
+ if (r_ptr->r_tkills)
+ {
+ if (r_ptr->level > dun_level)
+ {
+ attr = TERM_VIOLET;
+
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ attr = TERM_RED;
+ }
+ }
+ }
+ else
+ {
+ if (!(r_ptr->flags1 & RF1_UNIQUE)) attr = TERM_GREEN;
+ }
+
+
+ /* Dump the monster name */
+ if (r_ptr->total_visible == 1)
+ {
+ c_prt(attr, (r_name + r_ptr->name), (num % (h - 1)) + 1, (num / (h - 1) * 26));
+ }
+ else
+ {
+ c_prt(attr, format("%s (x%d)", r_name + r_ptr->name, r_ptr->total_visible), (num % (h - 1)) + 1, (num / (h - 1)) * 26);
+ }
+
+ num++;
+
+ }
+
+ }
+ else
+ {
+ c_prt(TERM_WHITE, "You see no monsters.", 0, 0);
+ }
+
+ /* Fresh */
+ Term_fresh();
+
+ /* Restore */
+ Term_activate(old);
+ }
+}
+
+
+/*
+ * Calculate number of spells player should have, and forget,
+ * or remember, spells until that number is properly reflected.
+ *
+ * Note that this function induces various "status" messages,
+ * which must be bypasses until the character is created.
+ */
+static void calc_spells(void)
+{
+ p_ptr->new_spells = 0;
+}
+
+/* Ugly hack */
+bool_ calc_powers_silent = FALSE;
+
+/* Calc the player powers */
+static void calc_powers(void)
+{
+ int i, p = 0;
+ bool_ *old_powers;
+
+ /* Hack -- wait for creation */
+ if (!character_generated) return;
+
+ /* Hack -- handle "xtra" mode */
+ if (character_xtra) return;
+
+ C_MAKE(old_powers, power_max, bool_);
+
+ /* Save old powers */
+ for (i = 0; i < power_max; i++) old_powers[i] = p_ptr->powers[i];
+
+ /* Get intrinsincs */
+ for (i = 0; i < POWER_MAX_INIT; i++) p_ptr->powers[i] = p_ptr->powers_mod[i];
+ for (; i < power_max; i++) p_ptr->powers[i] = 0;
+
+ /* Hooked powers */
+ process_hooks(HOOK_CALC_POWERS, "()");
+
+ /* Add objects powers */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ if (!o_ptr->k_idx) continue;
+
+ p = object_power(o_ptr);
+ if (p != -1) p_ptr->powers[p] = TRUE;
+ }
+
+ if ((!p_ptr->tim_mimic) && (!p_ptr->body_monster))
+ {
+ /* Add in racial and subracial powers */
+ for (i = 0; i < 4; i++)
+ {
+ p = rp_ptr->powers[i];
+ if (p != -1) p_ptr->powers[p] = TRUE;
+
+ p = rmp_ptr->powers[i];
+ if (p != -1) p_ptr->powers[p] = TRUE;
+ }
+ }
+ else if (p_ptr->mimic_form)
+ call_lua("calc_mimic_power", "(d)", "", p_ptr->mimic_form);
+
+ /* Add in class powers */
+ for (i = 0; i < 4; i++)
+ {
+ p = cp_ptr->powers[i];
+ if (p != -1) p_ptr->powers[p] = TRUE;
+ }
+
+ if (p_ptr->disembodied)
+ {
+ p = PWR_INCARNATE;
+ p_ptr->powers[p] = TRUE;
+ }
+
+ /* Now lets warn the player */
+ for (i = 0; i < power_max; i++)
+ {
+ s32b old = old_powers[i];
+ s32b new_ = p_ptr->powers[i];
+
+ if (new_ > old)
+ {
+ if (!calc_powers_silent) cmsg_print(TERM_GREEN, powers_type[i].gain_text);
+ }
+ else if (new_ < old)
+ {
+ if (!calc_powers_silent) cmsg_print(TERM_RED, powers_type[i].lose_text);
+ }
+ }
+
+ calc_powers_silent = FALSE;
+ C_FREE(old_powers, power_max, bool_);
+}
+
+
+/*
+ * Calculate the player's sanity
+ */
+
+void calc_sanity(void)
+{
+ int bonus, msane;
+
+ /* Hack -- use the con/hp table for sanity/wis */
+ bonus = ((int)(adj_con_mhp[p_ptr->stat_ind[A_WIS]]) - 128);
+
+ /* Hack -- assume 5 sanity points per level. */
+ msane = 5 * (p_ptr->lev + 1) + (bonus * p_ptr->lev / 2);
+
+ if (msane < p_ptr->lev + 1) msane = p_ptr->lev + 1;
+
+ if (p_ptr->msane != msane)
+ {
+ /* Sanity carries over between levels. */
+ p_ptr->csane += (msane - p_ptr->msane);
+
+ p_ptr->msane = msane;
+
+ if (p_ptr->csane >= msane)
+ {
+ p_ptr->csane = msane;
+ p_ptr->csane_frac = 0;
+ }
+
+ p_ptr->redraw |= (PR_SANITY);
+ p_ptr->window |= (PW_PLAYER);
+ }
+}
+
+
+/*
+ * Calculate maximum mana. You do not need to know any spells.
+ * Note that mana is lowered by heavy (or inappropriate) armor.
+ *
+ * This function induces status messages.
+ */
+static void calc_mana(void)
+{
+ int msp, levels, cur_wgt, max_wgt;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_type *o_ptr;
+
+ levels = p_ptr->lev;
+
+ /* Hack -- no negative mana */
+ if (levels < 0) levels = 0;
+
+ /* Extract total mana */
+ msp = get_skill_scale(SKILL_MAGIC, 200) +
+ (adj_mag_mana[
+ (p_ptr->stat_ind[A_INT] > p_ptr->stat_ind[A_WIS]) ?
+ p_ptr->stat_ind[A_INT] : p_ptr->stat_ind[A_WIS]
+ ] * levels / 4);
+
+ /* Hack -- usually add one mana */
+ if (msp) msp++;
+
+ /* Possessors mana is different */
+ if (p_ptr->body_monster && (!p_ptr->disembodied))
+ {
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+ int f = 100 / (r_ptr->freq_spell ? r_ptr->freq_spell : 1);
+
+ msp = 21 - f;
+
+ if (msp < 1) msp = 1;
+ }
+
+ /* Apply race mod mana */
+ msp = msp * rmp_ptr->mana / 100;
+
+ /* Apply class mana */
+ msp += msp * cp_ptr->mana / 100;
+
+ /* Apply Eru mana */
+ GOD(GOD_ERU)
+ {
+ s32b tmp = p_ptr->grace;
+
+ if (tmp >= 35000) tmp = 35000;
+ tmp /= 100;
+ msp += msp * tmp / 1000;
+ }
+
+ /* Only mages are affected */
+ if (forbid_gloves())
+ {
+ /* Assume player is not encumbered by gloves */
+ p_ptr->cumber_glove = FALSE;
+
+ /* Get the gloves */
+ o_ptr = &p_ptr->inventory[INVEN_HANDS];
+
+ /* Examine the gloves */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Normal gloves hurt mage-type spells */
+ if (o_ptr->k_idx &&
+ !(f2 & (TR2_FREE_ACT)) &&
+ !((f1 & (TR1_DEX)) && (o_ptr->pval > 0)) &&
+ !(f5 & TR5_SPELL_CONTAIN))
+ {
+ /* Encumbered */
+ p_ptr->cumber_glove = TRUE;
+
+ /* Reduce mana */
+ msp = (3 * msp) / 4;
+ }
+ }
+
+ /* Augment mana */
+ if (munchkin_multipliers)
+ {
+ if (p_ptr->to_m) msp += msp * p_ptr->to_m / 5;
+ }
+ else
+ {
+ if (p_ptr->to_m) msp += msp * p_ptr->to_m / 10;
+ }
+
+ /* Assume player not encumbered by armor */
+ p_ptr->cumber_armor = FALSE;
+
+ /* Weigh the armor */
+ cur_wgt = 0;
+ cur_wgt += p_ptr->inventory[INVEN_BODY].weight;
+ cur_wgt += p_ptr->inventory[INVEN_HEAD].weight;
+ cur_wgt += p_ptr->inventory[INVEN_ARM].weight;
+ cur_wgt += p_ptr->inventory[INVEN_OUTER].weight;
+ cur_wgt += p_ptr->inventory[INVEN_HANDS].weight;
+ cur_wgt += p_ptr->inventory[INVEN_FEET].weight;
+
+ /* Determine the weight allowance */
+ max_wgt = 200 + get_skill_scale(SKILL_COMBAT, 500);
+
+ /* Heavy armor penalizes mana */
+ if (((cur_wgt - max_wgt) / 10) > 0)
+ {
+ /* Encumbered */
+ p_ptr->cumber_armor = TRUE;
+
+ /* Reduce mana */
+ msp -= ((cur_wgt - max_wgt) / 10);
+ }
+
+ /* When meditating your mana is increased ! */
+ if (p_ptr->meditation)
+ {
+ msp += 50;
+ p_ptr->csp += 50;
+ }
+
+ /* Sp mods? */
+ if (process_hooks_ret(HOOK_CALC_MANA, "d", "(d)", msp))
+ {
+ msp = process_hooks_return[0].num;
+ }
+
+ /* Mana can never be negative */
+ if (msp < 0) msp = 0;
+
+
+ /* Maximum mana has changed */
+ if (p_ptr->msp != msp)
+ {
+ /* Save new limit */
+ p_ptr->msp = msp;
+
+ /* Enforce new limit */
+ if (p_ptr->csp >= msp)
+ {
+ p_ptr->csp = msp;
+ p_ptr->csp_frac = 0;
+ }
+
+ /* Display mana later */
+ p_ptr->redraw |= (PR_MANA);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+
+
+ /* Hack -- handle "xtra" mode */
+ if (character_xtra) return;
+
+ /* Take note when "glove state" changes */
+ if (p_ptr->old_cumber_glove != p_ptr->cumber_glove)
+ {
+ /* Message */
+ if (p_ptr->cumber_glove)
+ {
+ msg_print("Your covered hands feel unsuitable for spellcasting.");
+ }
+ else
+ {
+ msg_print("Your hands feel more suitable for spellcasting.");
+ }
+
+ /* Save it */
+ p_ptr->old_cumber_glove = p_ptr->cumber_glove;
+ }
+
+
+ /* Take note when "armor state" changes */
+ if (p_ptr->old_cumber_armor != p_ptr->cumber_armor)
+ {
+ /* Message */
+ if (p_ptr->cumber_armor)
+ {
+ msg_print("The weight of your armor encumbers your movement.");
+ }
+ else
+ {
+ msg_print("You feel able to move more freely.");
+ }
+
+ /* Save it */
+ p_ptr->old_cumber_armor = p_ptr->cumber_armor;
+ }
+}
+
+
+
+/*
+ * Calculate the players (maximal) hit points
+ * Adjust current hitpoints if necessary
+ */
+void calc_hitpoints(void)
+{
+ int bonus, mhp;
+
+ /* Un-inflate "half-hitpoint bonus per level" value */
+ bonus = ((int)(adj_con_mhp[p_ptr->stat_ind[A_CON]]) - 128);
+
+ /* Calculate hitpoints */
+ mhp = player_hp[p_ptr->lev - 1] + (bonus * p_ptr->lev / 2);
+
+ /* Always have at least one hitpoint per level */
+ if (mhp < p_ptr->lev + 1) mhp = p_ptr->lev + 1;
+
+ /* Factor in the pernament hp modifications */
+ mhp += p_ptr->hp_mod;
+ if (mhp < 1) mhp = 1;
+
+ /* Hack: Sorcery impose a hp penality */
+ if (mhp && (get_skill(SKILL_SORCERY)))
+ {
+ mhp -= mhp * get_skill_scale(SKILL_SORCERY, 50) / 100;
+ if (mhp < 1) mhp = 1;
+ }
+
+ /* Factor in the melkor hp modifications */
+ GOD(GOD_MELKOR)
+ {
+ mhp -= (p_ptr->melkor_sacrifice * 10);
+ if (mhp < 1) mhp = 1;
+ }
+
+ /* Factor in the hero / superhero settings */
+ if (p_ptr->hero) mhp += 10;
+ if (p_ptr->shero) mhp += 30;
+
+ /* Augment Hitpoint */
+ if (munchkin_multipliers)
+ {
+ mhp += mhp * p_ptr->to_l / 5;
+ }
+ else
+ {
+ mhp += mhp * p_ptr->to_l / 10;
+ }
+ if (mhp < 1) mhp = 1;
+
+ if (p_ptr->body_monster)
+ {
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+ u32b rhp = maxroll(r_ptr->hdice, r_ptr->hside);
+
+ /* Adjust the hp with the possession skill */
+ rhp = (rhp * (20 + get_skill_scale(SKILL_POSSESSION, 80))) / 100;
+
+ mhp = (rhp + sroot(rhp) + mhp) / 3;
+ }
+ if (p_ptr->disembodied) mhp = 1;
+
+ /* HACK - being undead means less DP */
+ if (p_ptr->necro_extra & CLASS_UNDEAD)
+ {
+ int divisor = p_ptr->lev / 4;
+
+ /* Beware of the horrible division by zero ! :) */
+ if (divisor == 0) divisor = 1;
+
+ /* Actually decrease the max hp */
+ mhp /= divisor;
+
+ /* Never less than 1 */
+ if (mhp < 1) mhp = 1;
+ }
+
+ /* Hp mods? */
+ if (process_hooks_ret(HOOK_CALC_HP, "d", "(d)", mhp))
+ {
+ mhp = process_hooks_return[0].num;
+ }
+
+ /* Never less than 1 */
+ if (mhp < 1) mhp = 1;
+
+ /* New maximum hitpoints */
+ if (p_ptr->mhp != mhp)
+ {
+ /* XXX XXX XXX New hitpoint maintenance */
+
+ /* Enforce maximum */
+ if (p_ptr->chp >= mhp)
+ {
+ p_ptr->chp = mhp;
+ p_ptr->chp_frac = 0;
+ }
+
+ /* Save the new max-hitpoints */
+ p_ptr->mhp = mhp;
+
+ /* Display hitpoints (later) */
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+}
+
+
+
+/*
+ * Extract and set the current "lite radius"
+ *
+ * SWD: Experimental modification: multiple light sources have additive effect.
+ *
+ */
+static void calc_torch(void)
+{
+ int i;
+ object_type *o_ptr;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Assume no light */
+ p_ptr->cur_lite = 0;
+
+ /* Loop through all wielded items */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip empty slots */
+ if (!o_ptr->k_idx) continue;
+
+ /* Extract the flags */
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* does this item glow? */
+ if (((f4 & TR4_FUEL_LITE) && (o_ptr->timeout > 0)) || (!(f4 & TR4_FUEL_LITE)))
+ {
+ if (f3 & TR3_LITE1) p_ptr->cur_lite++;
+ if (f4 & TR4_LITE2) p_ptr->cur_lite += 2;
+ if (f4 & TR4_LITE3) p_ptr->cur_lite += 3;
+ }
+
+ }
+
+ if (p_ptr->tim_lite) p_ptr->cur_lite += 2;
+
+ if (p_ptr->holy) p_ptr->cur_lite += 1;
+
+ /* max radius is 5 without rewriting other code -- */
+ /* see cave.c:update_lite() and defines.h:LITE_MAX */
+ if (p_ptr->cur_lite > 5) p_ptr->cur_lite = 5;
+
+ /* check if the player doesn't have a lite source, */
+ /* but does glow as an intrinsic. */
+ if (p_ptr->cur_lite == 0 && p_ptr->lite) p_ptr->cur_lite = 1;
+
+ /* Hooked powers */
+ process_hooks(HOOK_CALC_LITE, "()");
+
+ /* end experimental mods */
+
+ /* Reduce lite in the small-scale wilderness map */
+ if (p_ptr->wild_mode)
+ {
+ /* Reduce the lite radius if needed */
+ if (p_ptr->cur_lite > WILDERNESS_SEE_RADIUS)
+ {
+ p_ptr->cur_lite = WILDERNESS_SEE_RADIUS;
+ }
+ }
+
+
+ /* Reduce lite when running if requested */
+ if (running && view_reduce_lite)
+ {
+ /* Reduce the lite radius if needed */
+ if (p_ptr->cur_lite > 1) p_ptr->cur_lite = 1;
+ }
+
+ /* Notice changes in the "lite radius" */
+ if (p_ptr->old_lite != p_ptr->cur_lite)
+ {
+ /* Update the view */
+ p_ptr->update |= (PU_VIEW);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Remember the old lite */
+ p_ptr->old_lite = p_ptr->cur_lite;
+ }
+}
+
+
+
+/*
+ * Computes current weight limit.
+ */
+int weight_limit(void)
+{
+ int i;
+
+ /* Weight limit based only on strength */
+ i = adj_str_wgt[p_ptr->stat_ind[A_STR]] * 100;
+
+ if (process_hooks_ret(HOOK_CALC_WEIGHT, "d", "(d)", i))
+ i = process_hooks_return[0].num;
+
+ /* Return the result */
+ return (i);
+}
+
+void calc_wield_monster()
+{
+ object_type *o_ptr;
+ monster_race *r_ptr;
+
+ /* Get the carried monster */
+ o_ptr = &p_ptr->inventory[INVEN_CARRY];
+
+ if (o_ptr->k_idx)
+ {
+ r_ptr = &r_info[o_ptr->pval];
+
+ if (r_ptr->flags2 & RF2_INVISIBLE)
+ p_ptr->invis += 20;
+ if (r_ptr->flags2 & RF2_REFLECTING)
+ p_ptr->reflect = TRUE;
+ if (r_ptr->flags7 & RF7_CAN_FLY)
+ p_ptr->ffall = TRUE;
+ if (r_ptr->flags7 & RF7_AQUATIC)
+ p_ptr->water_breath = TRUE;
+ }
+}
+
+/*
+ * Calc which body parts the player have, based on the
+ * monster he incarnate, note that that's bnot a hack
+ * since body parts of the player when in it's own body
+ * are also defined in r_info(monster 0)
+ */
+void calc_body()
+{
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+ int i, b_weapon, b_legs, b_arms;
+ byte *body_parts, bp[BODY_MAX];
+
+ if (!p_ptr->body_monster)
+ {
+ body_parts = bp;
+ for (i = 0; i < BODY_MAX; i++)
+ {
+ int b;
+
+ b = rp_ptr->body_parts[i] + rmp_ptr->body_parts[i];
+ if (b < 0) b = 0;
+
+ if (p_ptr->mimic_form == resolve_mimic_name("Bear"))
+ {
+ if (i == BODY_ARMS) b = 0;
+ else if (i == BODY_LEGS) b = 0;
+ }
+
+ bp[i] = b;
+ }
+ }
+ else
+ {
+ body_parts = bp;
+ for (i = 0; i < BODY_MAX; i++)
+ {
+ int b;
+
+ b = r_ptr->body_parts[i];
+ if (b < 0) b = 0;
+
+ bp[i] = b;
+ }
+ }
+
+ for (i = 0; i < BODY_MAX; i++)
+ {
+ int b;
+
+ b = bp[i] + cp_ptr->body_parts[i];
+ if (b < 0) b = 0;
+ if (b > max_body_part[i]) b = max_body_part[i];
+
+ bp[i] = b;
+ }
+
+ b_weapon = body_parts[BODY_WEAPON];
+ b_arms = body_parts[BODY_ARMS];
+ b_legs = body_parts[BODY_LEGS];
+
+ if (p_ptr->mimic_extra & CLASS_ARMS)
+ {
+ b_weapon++;
+ b_arms++;
+
+ if (b_weapon > 3) b_weapon = 3;
+ if (b_arms > 3) b_arms = 3;
+ }
+
+ if (p_ptr->mimic_extra & CLASS_LEGS)
+ {
+ b_legs++;
+
+ if (b_legs > 2) b_legs = 2;
+ }
+
+ for (i = 0; i < INVEN_TOTAL - INVEN_WIELD; i++)
+ p_ptr->body_parts[i] = 0;
+
+ for (i = 0; i < b_weapon; i++)
+ p_ptr->body_parts[INVEN_WIELD - INVEN_WIELD + i] = INVEN_WIELD;
+ if (body_parts[BODY_WEAPON])
+ p_ptr->body_parts[INVEN_BOW - INVEN_WIELD] = INVEN_BOW;
+
+ for (i = 0; i < body_parts[BODY_TORSO]; i++)
+ {
+ p_ptr->body_parts[INVEN_BODY - INVEN_WIELD + i] = INVEN_BODY;
+ p_ptr->body_parts[INVEN_OUTER - INVEN_WIELD + i] = INVEN_OUTER;
+ p_ptr->body_parts[INVEN_LITE - INVEN_WIELD + i] = INVEN_LITE;
+ p_ptr->body_parts[INVEN_AMMO - INVEN_WIELD + i] = INVEN_AMMO;
+ p_ptr->body_parts[INVEN_CARRY - INVEN_WIELD + i] = INVEN_CARRY;
+ }
+
+ for (i = 0; i < body_parts[BODY_FINGER]; i++)
+ p_ptr->body_parts[INVEN_RING - INVEN_WIELD + i] = INVEN_RING;
+
+ for (i = 0; i < body_parts[BODY_HEAD]; i++)
+ {
+ p_ptr->body_parts[INVEN_HEAD - INVEN_WIELD + i] = INVEN_HEAD;
+ p_ptr->body_parts[INVEN_NECK - INVEN_WIELD + i] = INVEN_NECK;
+ }
+
+ for (i = 0; i < b_arms; i++)
+ {
+ p_ptr->body_parts[INVEN_ARM - INVEN_WIELD + i] = INVEN_ARM;
+ p_ptr->body_parts[INVEN_HANDS - INVEN_WIELD + i] = INVEN_HANDS;
+ }
+ if (body_parts[BODY_ARMS])
+ p_ptr->body_parts[INVEN_TOOL - INVEN_WIELD] = INVEN_TOOL;
+
+ for (i = 0; i < b_legs; i++)
+ p_ptr->body_parts[INVEN_FEET - INVEN_WIELD + i] = INVEN_FEET;
+
+ /* Ok now if the player lost a body part, he must drop the object he had on it */
+ for (i = 0; i < INVEN_TOTAL - INVEN_WIELD; i++)
+ {
+ if ((!p_ptr->body_parts[i]) && (p_ptr->inventory[i + INVEN_WIELD].k_idx))
+ {
+ /* Drop it NOW ! */
+ inven_takeoff(i + INVEN_WIELD, 255, TRUE);
+ }
+ }
+}
+
+/* Should be called by every calc_bonus call */
+void calc_body_bonus()
+{
+ monster_race *r_ptr = &r_info[p_ptr->body_monster];
+
+ /* If in the player body nothing have to be done */
+ if (!p_ptr->body_monster) return;
+
+ if (p_ptr->disembodied)
+ {
+ p_ptr->wraith_form = TRUE;
+ return;
+ }
+
+ p_ptr->ac += r_ptr->ac;
+ p_ptr->pspeed = r_ptr->speed;
+
+ if (r_ptr->flags1 & RF1_NEVER_MOVE) p_ptr->immovable = TRUE;
+ if (r_ptr->flags2 & RF2_STUPID) p_ptr->stat_add[A_INT] -= 1;
+ if (r_ptr->flags2 & RF2_SMART) p_ptr->stat_add[A_INT] += 1;
+ if (r_ptr->flags2 & RF2_REFLECTING) p_ptr->reflect = TRUE;
+ if (r_ptr->flags2 & RF2_INVISIBLE) p_ptr->invis += 20;
+ if (r_ptr->flags2 & RF2_REGENERATE) p_ptr->regenerate = TRUE;
+ if (r_ptr->flags2 & RF2_AURA_FIRE) p_ptr->sh_fire = TRUE;
+ if (r_ptr->flags2 & RF2_AURA_ELEC) p_ptr->sh_elec = TRUE;
+ if (r_ptr->flags2 & RF2_PASS_WALL) p_ptr->wraith_form = TRUE;
+ if (r_ptr->flags3 & RF3_SUSCEP_FIRE) p_ptr->sensible_fire = TRUE;
+ if (r_ptr->flags3 & RF3_IM_ACID) p_ptr->resist_acid = TRUE;
+ if (r_ptr->flags3 & RF3_IM_ELEC) p_ptr->resist_elec = TRUE;
+ if (r_ptr->flags3 & RF3_IM_FIRE) p_ptr->resist_fire = TRUE;
+ if (r_ptr->flags3 & RF3_IM_POIS) p_ptr->resist_pois = TRUE;
+ if (r_ptr->flags3 & RF3_IM_COLD) p_ptr->resist_cold = TRUE;
+ if (r_ptr->flags3 & RF3_RES_NETH) p_ptr->resist_neth = TRUE;
+ if (r_ptr->flags3 & RF3_RES_NEXU) p_ptr->resist_nexus = TRUE;
+ if (r_ptr->flags3 & RF3_RES_DISE) p_ptr->resist_disen = TRUE;
+ if (r_ptr->flags3 & RF3_NO_FEAR) p_ptr->resist_fear = TRUE;
+ if (r_ptr->flags3 & RF3_NO_SLEEP) p_ptr->free_act = TRUE;
+ if (r_ptr->flags3 & RF3_NO_CONF) p_ptr->resist_conf = TRUE;
+ if (r_ptr->flags7 & RF7_CAN_FLY) p_ptr->ffall = TRUE;
+ if (r_ptr->flags7 & RF7_AQUATIC) p_ptr->water_breath = TRUE;
+}
+
+
+byte calc_mimic()
+{
+ s32b blow = 0;
+
+ call_lua("calc_mimic", "(d)", "d", p_ptr->mimic_form, &blow);
+ return blow;
+}
+
+/* Returns the number of extra blows based on abilities. */
+static int get_extra_blows_ability() {
+ /* Count bonus abilities */
+ int num = 0;
+ if (has_ability(AB_MAX_BLOW1)) num++;
+ if (has_ability(AB_MAX_BLOW2)) num++;
+ return num;
+}
+
+/* Returns the blow information based on class */
+void analyze_blow(int *num, int *wgt, int *mul)
+{
+ *num = cp_ptr->blow_num;
+ *wgt = cp_ptr->blow_wgt;
+ *mul = cp_ptr->blow_mul;
+
+ /* Count bonus abilities */
+ (*num) += get_extra_blows_ability();
+}
+
+/* Are all the weapons wielded of the right type ? */
+int get_weaponmastery_skill()
+{
+ int i, skill = 0;
+ object_type *o_ptr;
+
+ i = 0;
+ /* All weapons must be of the same type */
+ while ((p_ptr->body_parts[i] == INVEN_WIELD) && (i < INVEN_TOTAL))
+ {
+ o_ptr = &p_ptr->inventory[INVEN_WIELD + i];
+
+ if (!o_ptr->k_idx)
+ {
+ i++;
+ continue;
+ }
+ switch (o_ptr->tval)
+ {
+ case TV_DAEMON_BOOK:
+ case TV_SWORD:
+ if ((!skill) || (skill == SKILL_SWORD)) skill = SKILL_SWORD;
+ else skill = -1;
+ break;
+ case TV_AXE:
+ if ((!skill) || (skill == SKILL_AXE)) skill = SKILL_AXE;
+ else skill = -1;
+ break;
+ case TV_HAFTED:
+ if ((!skill) || (skill == SKILL_HAFTED)) skill = SKILL_HAFTED;
+ else skill = -1;
+ break;
+ case TV_POLEARM:
+ if ((!skill) || (skill == SKILL_POLEARM)) skill = SKILL_POLEARM;
+ else skill = -1;
+ break;
+ }
+ i++;
+ }
+
+ /* Everything is ok */
+ return skill;
+}
+
+/* Are all the ranged weapons wielded of the right type ? */
+int get_archery_skill()
+{
+ int i, skill = 0;
+
+ i = INVEN_BOW - INVEN_WIELD;
+ /* All weapons must be of the same type */
+ while (p_ptr->body_parts[i] == INVEN_BOW)
+ {
+ if (p_ptr->inventory[INVEN_WIELD + i].tval == TV_BOW)
+ {
+ switch (p_ptr->inventory[INVEN_WIELD + i].sval / 10)
+ {
+ case 0:
+ if ((!skill) || (skill == SKILL_SLING)) skill = SKILL_SLING;
+ else skill = -1;
+ break;
+ case 1:
+ if ((!skill) || (skill == SKILL_BOW)) skill = SKILL_BOW;
+ else skill = -1;
+ break;
+ case 2:
+ if ((!skill) || (skill == SKILL_XBOW)) skill = SKILL_XBOW;
+ else skill = -1;
+ break;
+ }
+ }
+ else
+ {
+ if ((!skill) || (skill == SKILL_BOOMERANG)) skill = SKILL_BOOMERANG;
+ else skill = -1;
+ }
+
+ i++;
+ }
+
+ /* Everything is ok */
+ return skill;
+}
+
+/* Apply gods */
+void calc_gods()
+{
+ /* Boost WIS if the player follows Eru */
+ GOD(GOD_ERU)
+ {
+ if (p_ptr->grace > 10000) p_ptr->stat_add[A_WIS] += 1;
+ if (p_ptr->grace > 20000) p_ptr->stat_add[A_WIS] += 1;
+ if (p_ptr->grace > 30000) p_ptr->stat_add[A_WIS] += 1;
+ }
+
+ /* Boost str, con, chr and reduce int, wis if the player follows Melkor */
+ GOD(GOD_MELKOR)
+ {
+ if (p_ptr->grace > 10000) p_ptr->stat_add[A_STR] += 1;
+ if (p_ptr->grace > 20000) p_ptr->stat_add[A_STR] += 1;
+ if (p_ptr->grace > 30000) p_ptr->stat_add[A_STR] += 1;
+
+ if (p_ptr->grace > 10000) p_ptr->stat_add[A_CON] += 1;
+ if (p_ptr->grace > 20000) p_ptr->stat_add[A_CON] += 1;
+ if (p_ptr->grace > 30000) p_ptr->stat_add[A_CON] += 1;
+
+ if (p_ptr->grace > 10000) p_ptr->stat_add[A_CHR] += 1;
+ if (p_ptr->grace > 20000) p_ptr->stat_add[A_CHR] += 1;
+ if (p_ptr->grace > 30000) p_ptr->stat_add[A_CHR] += 1;
+
+ if (p_ptr->grace > 10000) p_ptr->stat_add[A_INT] -= 1;
+ if (p_ptr->grace > 20000) p_ptr->stat_add[A_INT] -= 1;
+ if (p_ptr->grace > 30000) p_ptr->stat_add[A_INT] -= 1;
+
+ if (p_ptr->grace > 10000) p_ptr->stat_add[A_WIS] -= 1;
+ if (p_ptr->grace > 20000) p_ptr->stat_add[A_WIS] -= 1;
+ if (p_ptr->grace > 30000) p_ptr->stat_add[A_WIS] -= 1;
+
+ PRAY_GOD(GOD_MELKOR)
+ {
+ if (p_ptr->grace > 5000) p_ptr->invis += 30;
+ if (p_ptr->grace > 15000) p_ptr->immune_fire = TRUE;
+ }
+ p_ptr->resist_fire = TRUE;
+ }
+
+ /* Gifts of Manwe if the player is praying to Manwe */
+ PRAY_GOD(GOD_MANWE)
+ {
+ s32b add = p_ptr->grace;
+
+ /* provides speed every 5000 grace */
+ if (add > 35000) add = 35000;
+ add /= 5000;
+ p_ptr->pspeed += add;
+
+ /* Provides fly & FA */
+ if (p_ptr->grace >= 7000) p_ptr->free_act = TRUE;
+ if (p_ptr->grace >= 15000) p_ptr->fly = TRUE;
+ }
+
+ /* Manwe bonus not requiring the praying status */
+ GOD(GOD_MANWE)
+ {
+ if (p_ptr->grace >= 2000) p_ptr->ffall = TRUE;
+ }
+
+ /* Boost Str and Con if the player is following Tulkas */
+ GOD(GOD_TULKAS)
+ {
+ if (p_ptr->grace > 5000) p_ptr->stat_add[A_CON] += 1;
+ if (p_ptr->grace > 10000) p_ptr->stat_add[A_CON] += 1;
+ if (p_ptr->grace > 15000) p_ptr->stat_add[A_CON] += 1;
+
+ if (p_ptr->grace > 10000) p_ptr->stat_add[A_STR] += 1;
+ if (p_ptr->grace > 15000) p_ptr->stat_add[A_STR] += 1;
+ if (p_ptr->grace > 20000) p_ptr->stat_add[A_STR] += 1;
+ }
+}
+
+/* Apply flags */
+static int extra_blows;
+static int extra_shots;
+void apply_flags(u32b f1, u32b f2, u32b f3, u32b f4, u32b f5, u32b esp, s16b pval, s16b tval, s16b to_h, s16b to_d, s16b to_a)
+{
+ s16b antimagic_mod;
+
+ /* Affect stats */
+ if (f1 & (TR1_STR)) p_ptr->stat_add[A_STR] += pval;
+ if (f1 & (TR1_INT)) p_ptr->stat_add[A_INT] += pval;
+ if (f1 & (TR1_WIS)) p_ptr->stat_add[A_WIS] += pval;
+ if (f1 & (TR1_DEX)) p_ptr->stat_add[A_DEX] += pval;
+ if (f1 & (TR1_CON)) p_ptr->stat_add[A_CON] += pval;
+ if (f1 & (TR1_CHR)) p_ptr->stat_add[A_CHR] += pval;
+ if (f5 & (TR5_LUCK)) p_ptr->luck_cur += pval;
+
+ /* Affect spell power */
+ if (f1 & (TR1_SPELL)) p_ptr->to_s += pval;
+
+ /* Affect mana capacity */
+ if (f1 & (TR1_MANA)) p_ptr->to_m += pval;
+
+ /* Affect life capacity */
+ if (f2 & (TR2_LIFE)) p_ptr->to_l += pval;
+
+ /* Affect stealth */
+ if (f1 & (TR1_STEALTH)) p_ptr->skill_stl += pval;
+
+ /* Affect searching ability (factor of five) */
+ if (f1 & (TR1_SEARCH)) p_ptr->skill_srh += (pval * 5);
+
+ /* Affect searching frequency (factor of five) */
+ if (f1 & (TR1_SEARCH)) p_ptr->skill_fos += (pval * 5);
+
+ /* Affect infravision */
+ if (f1 & (TR1_INFRA)) p_ptr->see_infra += pval;
+
+ /* Affect digging (factor of 20) */
+ if (f1 & (TR1_TUNNEL)) p_ptr->skill_dig += (pval * 20);
+
+ /* Affect speed */
+ if (f1 & (TR1_SPEED)) p_ptr->pspeed += pval;
+
+ /* Affect blows */
+ if (f1 & (TR1_BLOWS)) extra_blows += pval;
+ if (f5 & (TR5_CRIT)) p_ptr->xtra_crit += pval;
+
+ /* Hack -- Sensible fire */
+ if (f2 & (TR2_SENS_FIRE)) p_ptr->sensible_fire = TRUE;
+
+ /* Hack -- cause earthquakes */
+ if (f1 & (TR1_IMPACT)) p_ptr->impact = TRUE;
+
+ /* Affect invisibility */
+ if (f2 & (TR2_INVIS)) p_ptr->invis += (pval * 10);
+
+ /* Boost shots */
+ if (f3 & (TR3_XTRA_SHOTS)) extra_shots++;
+
+ /* Various flags */
+ if (f3 & (TR3_AGGRAVATE)) p_ptr->aggravate = TRUE;
+ if (f3 & (TR3_TELEPORT)) p_ptr->teleport = TRUE;
+ if (f5 & (TR5_DRAIN_MANA)) p_ptr->drain_mana++;
+ if (f5 & (TR5_DRAIN_HP)) p_ptr->drain_life++;
+ if (f3 & (TR3_DRAIN_EXP)) p_ptr->exp_drain = TRUE;
+ if (f3 & (TR3_BLESSED)) p_ptr->bless_blade = TRUE;
+ if (f3 & (TR3_XTRA_MIGHT)) p_ptr->xtra_might += pval;
+ if (f3 & (TR3_SLOW_DIGEST)) p_ptr->slow_digest = TRUE;
+ if (f3 & (TR3_REGEN)) p_ptr->regenerate = TRUE;
+ if (esp) p_ptr->telepathy |= esp;
+ if ((tval != TV_LITE) && (f3 & (TR3_LITE1))) p_ptr->lite = TRUE;
+ if ((tval != TV_LITE) && (f4 & (TR4_LITE2))) p_ptr->lite = TRUE;
+ if ((tval != TV_LITE) && (f4 & (TR4_LITE3))) p_ptr->lite = TRUE;
+ if (f3 & (TR3_SEE_INVIS)) p_ptr->see_inv = TRUE;
+ if (f2 & (TR2_FREE_ACT)) p_ptr->free_act = TRUE;
+ if (f2 & (TR2_HOLD_LIFE)) p_ptr->hold_life = TRUE;
+ if (f3 & (TR3_WRAITH)) p_ptr->wraith_form = TRUE;
+ if (f3 & (TR3_FEATHER)) p_ptr->ffall = TRUE;
+ if (f4 & (TR4_FLY)) p_ptr->fly = TRUE;
+ if (f4 & (TR4_CLIMB)) p_ptr->climb = TRUE;
+
+ /* Immunity flags */
+ if (f2 & (TR2_IM_FIRE)) p_ptr->immune_fire = TRUE;
+ if (f2 & (TR2_IM_ACID)) p_ptr->immune_acid = TRUE;
+ if (f2 & (TR2_IM_COLD)) p_ptr->immune_cold = TRUE;
+ if (f2 & (TR2_IM_ELEC)) p_ptr->immune_elec = TRUE;
+
+ /* Resistance flags */
+ if (f2 & (TR2_RES_ACID)) p_ptr->resist_acid = TRUE;
+ if (f2 & (TR2_RES_ELEC)) p_ptr->resist_elec = TRUE;
+ if (f2 & (TR2_RES_FIRE)) p_ptr->resist_fire = TRUE;
+ if (f2 & (TR2_RES_COLD)) p_ptr->resist_cold = TRUE;
+ if (f2 & (TR2_RES_POIS)) p_ptr->resist_pois = TRUE;
+ if (f2 & (TR2_RES_FEAR)) p_ptr->resist_fear = TRUE;
+ if (f2 & (TR2_RES_CONF)) p_ptr->resist_conf = TRUE;
+ if (f2 & (TR2_RES_SOUND)) p_ptr->resist_sound = TRUE;
+ if (f2 & (TR2_RES_LITE)) p_ptr->resist_lite = TRUE;
+ if (f2 & (TR2_RES_DARK)) p_ptr->resist_dark = TRUE;
+ if (f2 & (TR2_RES_CHAOS)) p_ptr->resist_chaos = TRUE;
+ if (f2 & (TR2_RES_DISEN)) p_ptr->resist_disen = TRUE;
+ if (f2 & (TR2_RES_SHARDS)) p_ptr->resist_shard = TRUE;
+ if (f2 & (TR2_RES_NEXUS)) p_ptr->resist_nexus = TRUE;
+ if (f2 & (TR2_RES_BLIND)) p_ptr->resist_blind = TRUE;
+ if (f2 & (TR2_RES_NETHER)) p_ptr->resist_neth = TRUE;
+ if (f4 & (TR4_IM_NETHER)) p_ptr->immune_neth = TRUE;
+
+ if (f2 & (TR2_REFLECT)) p_ptr->reflect = TRUE;
+ if (f3 & (TR3_SH_FIRE)) p_ptr->sh_fire = TRUE;
+ if (f3 & (TR3_SH_ELEC)) p_ptr->sh_elec = TRUE;
+ if (f3 & (TR3_NO_MAGIC)) p_ptr->anti_magic = TRUE;
+ if (f3 & (TR3_NO_TELE)) p_ptr->anti_tele = TRUE;
+
+ /* Sustain flags */
+ if (f2 & (TR2_SUST_STR)) p_ptr->sustain_str = TRUE;
+ if (f2 & (TR2_SUST_INT)) p_ptr->sustain_int = TRUE;
+ if (f2 & (TR2_SUST_WIS)) p_ptr->sustain_wis = TRUE;
+ if (f2 & (TR2_SUST_DEX)) p_ptr->sustain_dex = TRUE;
+ if (f2 & (TR2_SUST_CON)) p_ptr->sustain_con = TRUE;
+ if (f2 & (TR2_SUST_CHR)) p_ptr->sustain_chr = TRUE;
+
+ if (f4 & (TR4_PRECOGNITION)) p_ptr->precognition = TRUE;
+
+ antimagic_mod = to_h + to_d + to_a;
+
+ if (f4 & (TR4_ANTIMAGIC_50))
+ {
+ s32b tmp;
+
+ tmp = 10 + get_skill_scale(SKILL_ANTIMAGIC, 40) - antimagic_mod;
+ if (tmp > 0) p_ptr->antimagic += tmp;
+
+ tmp = 1 + get_skill_scale(SKILL_ANTIMAGIC, 4) - antimagic_mod / 15;
+ if (tmp > 0) p_ptr->antimagic_dis += tmp;
+ }
+
+ if (f4 & (TR4_ANTIMAGIC_30))
+ {
+ s32b tmp;
+
+ tmp = 7 + get_skill_scale(SKILL_ANTIMAGIC, 33) - antimagic_mod;
+ if (tmp > 0) p_ptr->antimagic += tmp;
+
+ tmp = 1 + get_skill_scale(SKILL_ANTIMAGIC, 2) - antimagic_mod / 15;
+ if (tmp > 0) p_ptr->antimagic_dis += tmp;
+ }
+
+ if (f4 & (TR4_ANTIMAGIC_20))
+ {
+ s32b tmp;
+
+ tmp = 5 + get_skill_scale(SKILL_ANTIMAGIC, 15) - antimagic_mod;
+ if (tmp > 0) p_ptr->antimagic += tmp;
+
+ p_ptr->antimagic_dis += 2;
+ }
+
+ if (f4 & (TR4_ANTIMAGIC_10))
+ {
+ s32b tmp;
+
+ tmp = 1 + get_skill_scale(SKILL_ANTIMAGIC, 9) - antimagic_mod;
+ if (tmp > 0) p_ptr->antimagic += tmp;
+
+ p_ptr->antimagic_dis += 1;
+ }
+
+ if (f4 & (TR4_AUTO_ID))
+ {
+ p_ptr->auto_id = TRUE;
+ }
+
+ /* The new code implementing Tolkien's concept of "Black Breath"
+ * takes advantage of the existing drain_exp character flag, renamed
+ * "black_breath". This flag can also be set by a unlucky blow from
+ * an undead. -LM-
+ */
+ if (f4 & (TR4_BLACK_BREATH)) p_ptr->black_breath = TRUE;
+
+ if (f5 & (TR5_IMMOVABLE)) p_ptr->immovable = TRUE;
+
+ /* Breaths */
+ if (f5 & (TR5_WATER_BREATH)) p_ptr->water_breath = TRUE;
+ if (f5 & (TR5_MAGIC_BREATH))
+ {
+ p_ptr->magical_breath = TRUE;
+ p_ptr->water_breath = TRUE;
+ }
+}
+
+/*
+ * Calculate the players current "state", taking into account
+ * not only race/class intrinsics, but also objects being worn
+ * and temporary spell effects.
+ *
+ * See also calc_mana() and calc_hitpoints().
+ *
+ * Take note of the new "speed code", in particular, a very strong
+ * player will start slowing down as soon as he reaches 150 pounds,
+ * but not until he reaches 450 pounds will he be half as fast as
+ * a normal kobold. This both hurts and helps the player, hurts
+ * because in the old days a player could just avoid 300 pounds,
+ * and helps because now carrying 300 pounds is not very painful.
+ *
+ * The "weapon" and "bow" do *not* add to the bonuses to hit or to
+ * damage, since that would affect non-combat things. These values
+ * are actually added in later, at the appropriate place.
+ *
+ * This function induces various "status" messages, unless silent is
+ * TRUE.
+ */
+void calc_bonuses(bool_ silent)
+{
+ int i, j, hold;
+ int old_speed;
+ u32b old_telepathy;
+ int old_see_inv;
+ int old_dis_ac;
+ int old_dis_to_a;
+ object_type *o_ptr;
+ u32b f1, f2, f3, f4, f5, esp;
+
+
+ /* Save the old speed */
+ old_speed = p_ptr->pspeed;
+
+ /* Save the old vision stuff */
+ old_telepathy = p_ptr->telepathy;
+ old_see_inv = p_ptr->see_inv;
+
+ /* Save the old armor class */
+ old_dis_ac = p_ptr->dis_ac;
+ old_dis_to_a = p_ptr->dis_to_a;
+
+ /* Clear extra blows/shots */
+ extra_blows = extra_shots = 0;
+
+ /* Clear the stat modifiers */
+ for (i = 0; i < 6; i++) p_ptr->stat_add[i] = 0;
+
+ /* Mana multiplier */
+ p_ptr->to_m = 0;
+
+ /* Life multiplier */
+ p_ptr->to_l = 0;
+
+ /* Spell power */
+ p_ptr->to_s = 0;
+
+ /* Clear the Displayed/Real armor class */
+ p_ptr->dis_ac = p_ptr->ac = 0;
+
+ /* Clear the Displayed/Real Bonuses */
+ p_ptr->dis_to_h = p_ptr->to_h = p_ptr->to_h_melee = p_ptr->to_h_ranged = 0;
+ p_ptr->dis_to_d = p_ptr->to_d = p_ptr->to_d_melee = p_ptr->to_d_ranged = 0;
+ p_ptr->dis_to_a = p_ptr->to_a = 0;
+
+ /* Start with "normal" speed */
+ p_ptr->pspeed = 110;
+
+ /* Start with 0% additionnal crits */
+ p_ptr->xtra_crit = 0;
+
+ /* Start with a single blow per turn */
+ p_ptr->num_blow = 1;
+
+ /* Start with a single shot per turn */
+ p_ptr->num_fire = 1;
+
+ /* Starts with single throwing damage */
+ p_ptr->throw_mult = 1;
+
+ /* Reset the "xtra" tval */
+ p_ptr->tval_xtra = 0;
+
+ /* Reset the "ammo" tval */
+ p_ptr->tval_ammo = 0;
+
+ /* Clear all the flags */
+ p_ptr->invis = 0;
+ p_ptr->immovable = FALSE;
+ p_ptr->aggravate = FALSE;
+ p_ptr->teleport = FALSE;
+ p_ptr->exp_drain = FALSE;
+ p_ptr->drain_mana = 0;
+ p_ptr->drain_life = 0;
+ p_ptr->bless_blade = FALSE;
+ p_ptr->xtra_might = 0;
+ p_ptr->auto_id = FALSE;
+ p_ptr->impact = FALSE;
+ p_ptr->see_inv = FALSE;
+ p_ptr->free_act = FALSE;
+ p_ptr->slow_digest = FALSE;
+ p_ptr->regenerate = FALSE;
+ p_ptr->fly = FALSE;
+ p_ptr->climb = FALSE;
+ p_ptr->ffall = FALSE;
+ p_ptr->hold_life = FALSE;
+ p_ptr->telepathy = 0;
+ p_ptr->lite = FALSE;
+ p_ptr->sustain_str = FALSE;
+ p_ptr->sustain_int = FALSE;
+ p_ptr->sustain_wis = FALSE;
+ p_ptr->sustain_con = FALSE;
+ p_ptr->sustain_dex = FALSE;
+ p_ptr->sustain_chr = FALSE;
+ p_ptr->resist_acid = FALSE;
+ p_ptr->resist_elec = FALSE;
+ p_ptr->resist_fire = FALSE;
+ p_ptr->resist_cold = FALSE;
+ p_ptr->resist_pois = FALSE;
+ p_ptr->resist_conf = FALSE;
+ p_ptr->resist_sound = FALSE;
+ p_ptr->resist_lite = FALSE;
+ p_ptr->resist_dark = FALSE;
+ p_ptr->resist_chaos = FALSE;
+ p_ptr->resist_disen = FALSE;
+ p_ptr->resist_shard = FALSE;
+ p_ptr->resist_nexus = FALSE;
+ p_ptr->resist_blind = FALSE;
+ p_ptr->resist_neth = FALSE;
+ p_ptr->immune_neth = FALSE;
+ p_ptr->resist_fear = FALSE;
+ p_ptr->resist_continuum = FALSE;
+ p_ptr->reflect = FALSE;
+ p_ptr->sh_fire = FALSE;
+ p_ptr->sh_elec = FALSE;
+ p_ptr->anti_magic = FALSE;
+ p_ptr->anti_tele = FALSE;
+ p_ptr->water_breath = FALSE;
+ p_ptr->magical_breath = FALSE;
+
+ p_ptr->sensible_fire = FALSE;
+ p_ptr->sensible_lite = FALSE;
+
+ p_ptr->immune_acid = FALSE;
+ p_ptr->immune_elec = FALSE;
+ p_ptr->immune_fire = FALSE;
+ p_ptr->immune_cold = FALSE;
+
+ p_ptr->precognition = FALSE;
+
+ p_ptr->wraith_form = FALSE;
+
+ /* The anti magic field surrounding the player */
+ p_ptr->antimagic = 0;
+ p_ptr->antimagic_dis = 0;
+
+
+ /* Base infravision (purely racial) */
+ p_ptr->see_infra = rp_ptr->infra + rmp_ptr->infra;
+
+
+ /* Base skill -- disarming */
+ p_ptr->skill_dis = 0;
+
+ /* Base skill -- magic devices */
+ p_ptr->skill_dev = 0;
+
+ /* Base skill -- saving throw */
+ p_ptr->skill_sav = 0;
+
+ /* Base skill -- stealth */
+ p_ptr->skill_stl = 0;
+
+ /* Base skill -- searching ability */
+ p_ptr->skill_srh = 0;
+
+ /* Base skill -- searching frequency */
+ p_ptr->skill_fos = 0;
+
+ /* Base skill -- combat (normal) */
+ p_ptr->skill_thn = 0;
+
+ /* Base skill -- combat (shooting) */
+ p_ptr->skill_thb = 0;
+
+ /* Base skill -- combat (throwing) */
+ p_ptr->skill_tht = 0;
+
+
+ /* Base skill -- digging */
+ p_ptr->skill_dig = 0;
+
+ /* Xtra player flags */
+ p_ptr->xtra_f1 = 0;
+ p_ptr->xtra_f2 = 0;
+ p_ptr->xtra_f3 = 0;
+ p_ptr->xtra_f4 = 0;
+ p_ptr->xtra_f5 = 0;
+ p_ptr->xtra_esp = 0;
+
+ /* Hide the skills that should auto hide */
+ for (i = 0; i < max_s_idx; i++)
+ {
+ if (s_info[i].flags1 & SKF1_AUTO_HIDE)
+ s_info[i].hidden = TRUE;
+ }
+
+ /* Base Luck */
+ p_ptr->luck_cur = p_ptr->luck_base;
+
+ /* Mimic override body's bonuses */
+ if (p_ptr->mimic_form)
+ {
+ extra_blows += calc_mimic();
+ }
+ else
+ {
+ calc_body_bonus();
+ }
+
+ /* Let the scripts do what they need */
+ process_hooks(HOOK_CALC_BONUS, "()");
+
+ /* The powers gived by the wielded monster */
+ calc_wield_monster();
+
+ for (i = 1; i <= p_ptr->lev; i++)
+ {
+ apply_flags(cp_ptr->oflags1[i], cp_ptr->oflags2[i], cp_ptr->oflags3[i], cp_ptr->oflags4[i], cp_ptr->oflags5[i], cp_ptr->oesp[i], cp_ptr->opval[i], 0, 0, 0, 0);
+ }
+
+ if (p_ptr->melee_style == SKILL_HAND)
+ {
+ /* Unencumbered Monks become faster every 10 levels */
+ if (!(monk_heavy_armor()))
+ p_ptr->pspeed += get_skill_scale(SKILL_HAND, 5);
+
+ /* Free action if unencumbered at level 25 */
+ if ((get_skill(SKILL_HAND) > 24) && !(monk_heavy_armor()))
+ p_ptr->free_act = TRUE;
+ }
+
+ if (get_skill(SKILL_ANTIMAGIC))
+ {
+ p_ptr->antimagic += get_skill(SKILL_ANTIMAGIC);
+ p_ptr->antimagic_dis += get_skill_scale(SKILL_ANTIMAGIC, 10) + 1;
+
+ if (p_ptr->antimagic_extra & CLASS_ANTIMAGIC)
+ {
+ p_ptr->anti_tele = TRUE;
+ p_ptr->resist_continuum = TRUE;
+ }
+ }
+
+ if (get_skill(SKILL_DAEMON) > 20) p_ptr->resist_conf = TRUE;
+ if (get_skill(SKILL_DAEMON) > 30) p_ptr->resist_fear = TRUE;
+
+ if ( get_skill(SKILL_MINDCRAFT) >= 40 ) p_ptr->telepathy = ESP_ALL;
+
+ if (p_ptr->astral)
+ {
+ p_ptr->wraith_form = TRUE;
+ }
+
+ /***** Races ****/
+ if ((!p_ptr->mimic_form) && (!p_ptr->body_monster))
+ {
+ int i;
+
+ for (i = 1; i <= p_ptr->lev; i++)
+ {
+ apply_flags(rp_ptr->oflags1[i], rp_ptr->oflags2[i], rp_ptr->oflags3[i], rp_ptr->oflags4[i], rp_ptr->oflags5[i], rp_ptr->oesp[i], rp_ptr->opval[i], 0, 0, 0, 0);
+ apply_flags(rmp_ptr->oflags1[i], rmp_ptr->oflags2[i], rmp_ptr->oflags3[i], rmp_ptr->oflags4[i], rmp_ptr->oflags5[i], rmp_ptr->oesp[i], rmp_ptr->opval[i], 0, 0, 0, 0);
+ }
+
+ if (PRACE_FLAG(PR1_HURT_LITE))
+ p_ptr->sensible_lite = TRUE;
+ }
+
+ /* The extra flags */
+ apply_flags(p_ptr->xtra_f1, p_ptr->xtra_f2, p_ptr->xtra_f3, p_ptr->xtra_f4, p_ptr->xtra_f5, p_ptr->xtra_esp, 0, 0, 0, 0, 0);
+
+ /* Hack -- apply racial/class stat maxes */
+ if (p_ptr->maximize)
+ {
+ /* Apply the racial modifiers */
+ for (i = 0; i < 6; i++)
+ {
+ /* Modify the stats for "race" */
+ p_ptr->stat_add[i] += (rp_ptr->r_adj[i] + rmp_ptr->r_adj[i] + cp_ptr->c_adj[i]);
+ }
+ }
+
+
+ /* Scan the usable inventory */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ o_ptr = &p_ptr->inventory[i];
+
+ /* Skip non-objects */
+ if (!o_ptr->k_idx) continue;
+
+ /* Extract the item flags */
+ object_flags_no_set = TRUE;
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+ object_flags_no_set = FALSE;
+
+ /* MEGA ugly hack -- set spacetime distortion resistance */
+ if (o_ptr->name1 == ART_ANCHOR)
+ {
+ p_ptr->resist_continuum = TRUE;
+ }
+
+ /* Hack - don't give the Black Breath when merely inspecting a weapon */
+ if (silent)
+ {
+ f4 &= ~TR4_BLACK_BREATH;
+ }
+
+ apply_flags(f1, f2, f3, f4, f5, esp, o_ptr->pval, o_ptr->tval, o_ptr->to_h, o_ptr->to_d, o_ptr->to_a);
+
+ if (o_ptr->name1)
+ {
+ apply_set(o_ptr->name1, a_info[o_ptr->name1].set);
+ }
+
+ /* Modify the base armor class */
+ p_ptr->ac += o_ptr->ac;
+
+ /* The base armor class is always known */
+ p_ptr->dis_ac += o_ptr->ac;
+
+ /* Apply the bonuses to armor class */
+ p_ptr->to_a += o_ptr->to_a;
+
+ /* Apply the mental bonuses to armor class, if known */
+ if (object_known_p(o_ptr)) p_ptr->dis_to_a += o_ptr->to_a;
+
+ /* Hack -- do not apply "weapon" bonuses */
+ if (p_ptr->body_parts[i - INVEN_WIELD] == INVEN_WIELD) continue;
+
+ /* Hack -- do not apply "bow" bonuses */
+ if (p_ptr->body_parts[i - INVEN_WIELD] == INVEN_BOW) continue;
+
+ /* Hack -- do not apply "ammo" bonuses */
+ if (p_ptr->body_parts[i - INVEN_WIELD] == INVEN_AMMO) continue;
+
+ /* Hack -- do not apply "tool" bonuses */
+ if (p_ptr->body_parts[i - INVEN_WIELD] == INVEN_TOOL) continue;
+
+ /* Apply the bonuses to hit/damage */
+ p_ptr->to_h += o_ptr->to_h;
+ p_ptr->to_d += o_ptr->to_d;
+
+ /* Apply the mental bonuses tp hit/damage, if known */
+ if (object_known_p(o_ptr)) p_ptr->dis_to_h += o_ptr->to_h;
+ if (object_known_p(o_ptr)) p_ptr->dis_to_d += o_ptr->to_d;
+ }
+
+ /* Monks get extra ac for armour _not worn_ */
+ if ((p_ptr->melee_style == SKILL_HAND) && !(monk_heavy_armor()))
+ {
+ if (!(p_ptr->inventory[INVEN_BODY].k_idx))
+ {
+ p_ptr->to_a += get_skill_scale(SKILL_HAND, 75);
+ p_ptr->dis_to_a += get_skill_scale(SKILL_HAND, 75);
+ }
+ if (!(p_ptr->inventory[INVEN_OUTER].k_idx) && (get_skill(SKILL_HAND) > 15))
+ {
+ p_ptr->to_a += ((get_skill(SKILL_HAND) - 13) / 3);
+ p_ptr->dis_to_a += ((get_skill(SKILL_HAND) - 13) / 3);
+ }
+ if (!(p_ptr->inventory[INVEN_ARM].k_idx) && (get_skill(SKILL_HAND) > 10))
+ {
+ p_ptr->to_a += ((get_skill(SKILL_HAND) - 8) / 3);
+ p_ptr->dis_to_a += ((get_skill(SKILL_HAND) - 8) / 3);
+ }
+ if (!(p_ptr->inventory[INVEN_HEAD].k_idx) && (get_skill(SKILL_HAND) > 4))
+ {
+ p_ptr->to_a += (get_skill(SKILL_HAND) - 2) / 3;
+ p_ptr->dis_to_a += (get_skill(SKILL_HAND) - 2) / 3;
+ }
+ if (!(p_ptr->inventory[INVEN_HANDS].k_idx))
+ {
+ p_ptr->to_a += (get_skill(SKILL_HAND) / 2);
+ p_ptr->dis_to_a += (get_skill(SKILL_HAND) / 2);
+ }
+ if (!(p_ptr->inventory[INVEN_FEET].k_idx))
+ {
+ p_ptr->to_a += (get_skill(SKILL_HAND) / 3);
+ p_ptr->dis_to_a += (get_skill(SKILL_HAND) / 3);
+ }
+ }
+
+ /* Hack -- aura of fire also provides light */
+ if (p_ptr->sh_fire) p_ptr->lite = TRUE;
+
+ if (PRACE_FLAG(PR1_AC_LEVEL))
+ {
+ p_ptr->to_a += 20 + (p_ptr->lev / 5);
+ p_ptr->dis_to_a += 20 + (p_ptr->lev / 5);
+ }
+
+ /* Take care of gods */
+ calc_gods();
+
+ /* Calculate stats */
+ for (i = 0; i < 6; i++)
+ {
+ int top, use, ind;
+
+
+ /* Extract the new "stat_use" value for the stat */
+ top = modify_stat_value(p_ptr->stat_max[i], p_ptr->stat_add[i]);
+
+ /* Notice changes */
+ if (p_ptr->stat_top[i] != top)
+ {
+ /* Save the new value */
+ p_ptr->stat_top[i] = top;
+
+ /* Redisplay the stats later */
+ p_ptr->redraw |= (PR_STATS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+
+ /* Extract the new "stat_use" value for the stat */
+ use = modify_stat_value(p_ptr->stat_cur[i], p_ptr->stat_add[i]);
+
+ /* Notice changes */
+ if (p_ptr->stat_use[i] != use)
+ {
+ /* Save the new value */
+ p_ptr->stat_use[i] = use;
+
+ /* Redisplay the stats later */
+ p_ptr->redraw |= (PR_STATS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+
+
+ /* Values: 3, 4, ..., 17 */
+ if (use <= 18) ind = (use - 3);
+
+ /* Ranges: 18/00-18/09, ..., 18/210-18/219 */
+ else if (use <= 18 + 219) ind = (15 + (use - 18) / 10);
+
+ /* Range: 18/220+ */
+ else ind = (37);
+
+ /* Notice changes */
+ if (p_ptr->stat_ind[i] != ind)
+ {
+ /* Save the new index */
+ p_ptr->stat_ind[i] = ind;
+
+ /* Change in CON affects Hitpoints */
+ if (i == A_CON)
+ {
+ p_ptr->update |= (PU_HP);
+ }
+
+ /* Change in WIS affects Sanity Points */
+ else if (i == A_WIS)
+ {
+ p_ptr->update |= (PU_MANA | PU_SANITY);
+ }
+
+ /* Change in spell stat affects Mana/Spells */
+ if (i == A_INT)
+ {
+ p_ptr->update |= (PU_MANA | PU_SPELLS);
+ }
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+ }
+
+ /* Provide the damage we get from sacrifice */
+ GOD(GOD_MELKOR)
+ {
+ int x = wisdom_scale(4);
+ if (x < 1) x = 1;
+
+ p_ptr->dis_to_d += x * p_ptr->melkor_sacrifice;
+ p_ptr->to_d += x * p_ptr->melkor_sacrifice;
+ }
+
+ /* jk - add in the tactics */
+ p_ptr->dis_to_h += tactic_info[(byte)p_ptr->tactic].to_hit;
+ p_ptr->to_h += tactic_info[(byte)p_ptr->tactic].to_hit;
+ p_ptr->dis_to_d += tactic_info[(byte)p_ptr->tactic].to_dam;
+ p_ptr->to_d += tactic_info[(byte)p_ptr->tactic].to_dam;
+ p_ptr->dis_to_a += tactic_info[(byte)p_ptr->tactic].to_ac;
+ p_ptr->to_a += tactic_info[(byte)p_ptr->tactic].to_ac;
+
+ p_ptr->skill_stl += tactic_info[(byte)p_ptr->tactic].to_stealth;
+ p_ptr->skill_dis += tactic_info[(byte)p_ptr->tactic].to_disarm;
+ p_ptr->skill_sav += tactic_info[(byte)p_ptr->tactic].to_saving;
+
+ p_ptr->pspeed += move_info[(byte)p_ptr->movement].to_speed;
+ p_ptr->skill_srh += move_info[(byte)p_ptr->movement].to_search;
+ p_ptr->skill_fos += move_info[(byte)p_ptr->movement].to_percep;
+ p_ptr->skill_stl += move_info[(byte)p_ptr->movement].to_stealth;
+
+ /* Apply temporary "stun" */
+ if (p_ptr->stun > 50)
+ {
+ p_ptr->to_h -= 20;
+ p_ptr->dis_to_h -= 20;
+ p_ptr->to_d -= 20;
+ p_ptr->dis_to_d -= 20;
+ }
+ else if (p_ptr->stun)
+ {
+ p_ptr->to_h -= 5;
+ p_ptr->dis_to_h -= 5;
+ p_ptr->to_d -= 5;
+ p_ptr->dis_to_d -= 5;
+ }
+
+
+ /* Invulnerability */
+ if (p_ptr->invuln)
+ {
+ p_ptr->to_a += 100;
+ p_ptr->dis_to_a += 100;
+ }
+
+ /* Breath */
+ if (p_ptr->tim_water_breath)
+ {
+ p_ptr->water_breath = TRUE;
+ }
+ if (p_ptr->tim_magic_breath)
+ {
+ p_ptr->magical_breath = TRUE;
+ }
+
+ /* wraith_form */
+ if (p_ptr->tim_wraith)
+ {
+ if (p_ptr->disembodied)
+ {
+ p_ptr->to_a += 10;
+ p_ptr->dis_to_a += 10;
+ }
+ else
+ {
+ p_ptr->to_a += 50;
+ p_ptr->dis_to_a += 50;
+ p_ptr->reflect = TRUE;
+ }
+ p_ptr->wraith_form = TRUE;
+ }
+
+ /* Temporary holy aura */
+ if (p_ptr->holy)
+ {
+ p_ptr->hold_life = TRUE;
+ p_ptr->luck_cur += 5;
+ }
+
+ /* Temporary blessing */
+ if (p_ptr->blessed)
+ {
+ p_ptr->to_a += 5;
+ p_ptr->dis_to_a += 5;
+ p_ptr->to_h += 10;
+ p_ptr->dis_to_h += 10;
+ }
+
+ /* Temporary invisibility */
+ if (p_ptr->tim_invisible)
+ {
+ p_ptr->invis += p_ptr->tim_inv_pow;
+ }
+
+ /* Temporary shield */
+ if (p_ptr->shield)
+ {
+ p_ptr->to_a += p_ptr->shield_power;
+ p_ptr->dis_to_a += p_ptr->shield_power;
+ }
+
+ /* Temporary "Hero" */
+ if (p_ptr->hero)
+ {
+ p_ptr->to_h += 12;
+ p_ptr->dis_to_h += 12;
+ }
+
+ /* Temporary "roots" */
+ if (p_ptr->tim_roots)
+ {
+ set_stun(0);
+ p_ptr->to_d_melee += p_ptr->tim_roots_dam;
+ p_ptr->to_a += p_ptr->tim_roots_ac;
+ p_ptr->dis_to_a += p_ptr->tim_roots_ac;
+ }
+
+ /* Temporary "Beserk" */
+ if (p_ptr->shero)
+ {
+ p_ptr->to_h += 24;
+ p_ptr->dis_to_h += 24;
+ p_ptr->to_a -= 10;
+ p_ptr->dis_to_a -= 10;
+ }
+
+ /* Temporary "Accurancy" */
+ if (p_ptr->strike)
+ {
+ p_ptr->to_d += 15;
+ p_ptr->dis_to_d += 15;
+ p_ptr->to_h += 15;
+ p_ptr->dis_to_h += 15;
+ }
+
+ /* Temporary "Meditation" */
+ if (p_ptr->meditation)
+ {
+ p_ptr->to_d -= 25;
+ p_ptr->dis_to_d -= 25;
+ p_ptr->to_h -= 25;
+ p_ptr->dis_to_h -= 25;
+ }
+
+ /* Temporary "Reflection" */
+ if (p_ptr->tim_reflect)
+ {
+ p_ptr->reflect = TRUE;
+ }
+
+ /* Temporary "Time Resistance" */
+ if (p_ptr->tim_res_time)
+ {
+ p_ptr->resist_continuum = TRUE;
+ }
+
+ /* Temporary "Levitation" and "Flying" */
+ if (p_ptr->tim_ffall)
+ {
+ p_ptr->ffall = TRUE;
+ }
+ if (p_ptr->tim_fly)
+ {
+ p_ptr->fly = TRUE;
+ }
+
+ /* Temporary "Fire Aura" */
+ if (p_ptr->tim_fire_aura)
+ {
+ p_ptr->sh_fire = TRUE;
+ }
+
+ /* Oppose Light & Dark */
+ if (p_ptr->oppose_ld)
+ {
+ p_ptr->resist_lite = TRUE;
+ p_ptr->resist_dark = TRUE;
+ }
+
+ /* Oppose Chaos & Confusion */
+ if (p_ptr->oppose_cc)
+ {
+ p_ptr->resist_chaos = TRUE;
+ p_ptr->resist_conf = TRUE;
+ }
+
+ /* Oppose Sound & Shards */
+ if (p_ptr->oppose_ss)
+ {
+ p_ptr->resist_sound = TRUE;
+ p_ptr->resist_shard = TRUE;
+ }
+
+ /* Oppose Nexus */
+ if (p_ptr->oppose_nex)
+ {
+ p_ptr->resist_nexus = TRUE;
+ }
+
+ /* Mental barrier */
+ if (p_ptr->tim_mental_barrier)
+ {
+ p_ptr->sustain_int = TRUE;
+ p_ptr->sustain_wis = TRUE;
+ }
+
+ /* Temporary "fast" */
+ if (p_ptr->fast)
+ {
+ p_ptr->pspeed += p_ptr->speed_factor;
+ }
+
+ /* Temporary "light speed" */
+ if (p_ptr->lightspeed)
+ {
+ p_ptr->pspeed += 50;
+ }
+
+ /* Temporary "slow" */
+ if (p_ptr->slow)
+ {
+ p_ptr->pspeed -= 10;
+ }
+
+ if (p_ptr->tim_esp)
+ {
+ p_ptr->telepathy |= ESP_ALL;
+ }
+
+ /* Temporary see invisible */
+ if (p_ptr->tim_invis)
+ {
+ p_ptr->see_inv = TRUE;
+ }
+
+ /* Temporary infravision boost */
+ if (p_ptr->tim_infra)
+ {
+ p_ptr->see_infra++;
+ }
+
+ /* Hack -- Magic breath -> Water breath */
+ if (p_ptr->magical_breath)
+ {
+ p_ptr->water_breath = TRUE;
+ }
+
+ /* Hack -- Can Fly -> Can Levitate */
+ if (p_ptr->fly)
+ {
+ p_ptr->ffall = TRUE;
+ }
+
+ /* Hack -- Res Chaos -> Res Conf */
+ if (p_ptr->resist_chaos)
+ {
+ p_ptr->resist_conf = TRUE;
+ }
+
+ /* Hack -- Hero/Shero -> Res fear */
+ if (p_ptr->hero || p_ptr->shero)
+ {
+ p_ptr->resist_fear = TRUE;
+ }
+
+
+ /* Hack -- Telepathy Change */
+ if (p_ptr->telepathy != old_telepathy)
+ {
+ p_ptr->update |= (PU_MONSTERS);
+ }
+
+ /* Hack -- See Invis Change */
+ if (p_ptr->see_inv != old_see_inv)
+ {
+ p_ptr->update |= (PU_MONSTERS);
+ }
+
+
+ /* Extract the current weight (in tenth pounds) */
+ j = calc_total_weight();
+
+ /* Extract the "weight limit" (in tenth pounds) */
+ i = weight_limit();
+
+ /* XXX XXX XXX Apply "encumbrance" from weight */
+ if (j > i / 2) p_ptr->pspeed -= ((j - (i / 2)) / (i / 10));
+
+ /* Bloating slows the player down (a little) */
+ if (p_ptr->food >= PY_FOOD_MAX) p_ptr->pspeed -= 10;
+
+ /* Searching slows the player down */
+ if (p_ptr->searching) p_ptr->pspeed -= 10;
+
+ /* In order to get a "nice" mana path druids need to ahve a 0 speed */
+ if ((p_ptr->druid_extra2 == CLASS_MANA_PATH) && (p_ptr->pspeed > 110))
+ p_ptr->pspeed = 110;
+
+ /* Display the speed (if needed) */
+ if (p_ptr->pspeed != old_speed) p_ptr->redraw |= (PR_SPEED);
+
+
+ /* Actual Modifier Bonuses (Un-inflate stat bonuses) */
+ p_ptr->to_a += ((int)(adj_dex_ta[p_ptr->stat_ind[A_DEX]]) - 128);
+ p_ptr->to_d += ((int)(adj_str_td[p_ptr->stat_ind[A_STR]]) - 128);
+ p_ptr->to_h += ((int)(adj_dex_th[p_ptr->stat_ind[A_DEX]]) - 128);
+ p_ptr->to_h += ((int)(adj_str_th[p_ptr->stat_ind[A_STR]]) - 128);
+
+ /* Displayed Modifier Bonuses (Un-inflate stat bonuses) */
+ p_ptr->dis_to_a += ((int)(adj_dex_ta[p_ptr->stat_ind[A_DEX]]) - 128);
+ p_ptr->dis_to_d += ((int)(adj_str_td[p_ptr->stat_ind[A_STR]]) - 128);
+ p_ptr->dis_to_h += ((int)(adj_dex_th[p_ptr->stat_ind[A_DEX]]) - 128);
+ p_ptr->dis_to_h += ((int)(adj_str_th[p_ptr->stat_ind[A_STR]]) - 128);
+
+ /* Redraw armor (if needed) */
+ if ((p_ptr->dis_ac != old_dis_ac) || (p_ptr->dis_to_a != old_dis_to_a))
+ {
+ /* Redraw */
+ p_ptr->redraw |= (PR_ARMOR);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+
+
+ /* Obtain the "hold" value */
+ hold = adj_str_hold[p_ptr->stat_ind[A_STR]];
+
+
+ /* Examine the "current bow" */
+ o_ptr = &p_ptr->inventory[INVEN_BOW];
+
+
+ /* Assume not heavy */
+ p_ptr->heavy_shoot = FALSE;
+
+ /* It is hard to carholdry a heavy bow */
+ if (hold < o_ptr->weight / 10)
+ {
+ /* Hard to wield a heavy bow */
+ p_ptr->to_h += 2 * (hold - o_ptr->weight / 10);
+ p_ptr->dis_to_h += 2 * (hold - o_ptr->weight / 10);
+
+ /* Heavy Bow */
+ p_ptr->heavy_shoot = TRUE;
+ }
+
+ /* Take note of required "tval" for missiles */
+ switch (o_ptr->sval)
+ {
+ case SV_SLING:
+ {
+ p_ptr->tval_ammo = TV_SHOT;
+ break;
+ }
+
+ case SV_SHORT_BOW:
+ case SV_LONG_BOW:
+ {
+ p_ptr->tval_ammo = TV_ARROW;
+ break;
+ }
+
+ case SV_LIGHT_XBOW:
+ case SV_HEAVY_XBOW:
+ {
+ p_ptr->tval_ammo = TV_BOLT;
+ break;
+ }
+ }
+
+ /* Compute "extra shots" if needed */
+ if (o_ptr->k_idx && !p_ptr->heavy_shoot)
+ {
+ int archery = get_archery_skill();
+
+ if (archery != -1)
+ {
+ p_ptr->to_h_ranged += get_skill_scale(archery, 25);
+ p_ptr->num_fire += (get_skill(archery) / 16);
+ p_ptr->xtra_might += (get_skill(archery) / 25);
+ switch (archery)
+ {
+ case SKILL_SLING:
+ if (p_ptr->tval_ammo == TV_SHOT) p_ptr->xtra_might += get_skill(archery) / 30;
+ break;
+ case SKILL_BOW:
+ if (p_ptr->tval_ammo == TV_ARROW) p_ptr->xtra_might += get_skill(archery) / 30;
+ break;
+ case SKILL_XBOW:
+ if (p_ptr->tval_ammo == TV_BOLT) p_ptr->xtra_might += get_skill(archery) / 30;
+ break;
+ }
+ }
+
+ /* Add in the "bonus shots" */
+ p_ptr->num_fire += extra_shots;
+
+ /* Require at least one shot */
+ if (p_ptr->num_fire < 1) p_ptr->num_fire = 1;
+ }
+
+ if (PRACE_FLAG(PR1_XTRA_MIGHT_BOW) && p_ptr->tval_ammo == TV_ARROW)
+ p_ptr->xtra_might += 1;
+
+ if (PRACE_FLAG(PR1_XTRA_MIGHT_SLING) && p_ptr->tval_ammo == TV_SHOT)
+ p_ptr->xtra_might += 1;
+
+ if (PRACE_FLAG(PR1_XTRA_MIGHT_XBOW) && p_ptr->tval_ammo == TV_BOLT)
+ p_ptr->xtra_might += 1;
+
+ /* Examine the "current tool" */
+ o_ptr = &p_ptr->inventory[INVEN_TOOL];
+
+ /* Boost digging skill by tool weight */
+ if (o_ptr->k_idx && (o_ptr->tval == TV_DIGGING))
+ {
+ p_ptr->skill_dig += (o_ptr->weight / 10);
+ }
+
+ /* Examine the main weapon */
+ o_ptr = &p_ptr->inventory[INVEN_WIELD];
+
+ /* Assume not heavy */
+ p_ptr->heavy_wield = FALSE;
+
+ /* Normal weapons */
+ if (o_ptr->k_idx && !p_ptr->heavy_wield)
+ {
+ int str_index, dex_index;
+
+ int num = 0, wgt = 0, mul = 0, div = 0;
+
+ analyze_blow(&num, &wgt, &mul);
+
+ /* Enforce a minimum "weight" (tenth pounds) */
+ div = ((o_ptr->weight < wgt) ? wgt : o_ptr->weight);
+
+ /* Access the strength vs weight */
+ str_index = (adj_str_blow[p_ptr->stat_ind[A_STR]] * mul / div);
+
+ /* Maximal value */
+ if (str_index > 11) str_index = 11;
+
+ /* Index by dexterity */
+ dex_index = (adj_dex_blow[p_ptr->stat_ind[A_DEX]]);
+
+ /* Maximal value */
+ if (dex_index > 11) dex_index = 11;
+
+ /* Use the blows table */
+ p_ptr->num_blow = blows_table[str_index][dex_index];
+
+ /* Maximal value */
+ if (p_ptr->num_blow > num) p_ptr->num_blow = num;
+
+ /* Add in the "bonus blows" */
+ p_ptr->num_blow += extra_blows;
+
+ /* Special class bonus blows */
+ p_ptr->num_blow += p_ptr->lev * cp_ptr->extra_blows / 50;
+
+ /* Weapon specialization bonus blows */
+ if (get_weaponmastery_skill() != -1)
+ p_ptr->num_blow += get_skill_scale(get_weaponmastery_skill(), 2);
+
+ /* Bonus blows for plain weaponmastery skill */
+ p_ptr->num_blow += get_skill_scale(SKILL_MASTERY, 3);
+
+ /* Require at least one blow */
+ if (p_ptr->num_blow < 1) p_ptr->num_blow = 1;
+ }
+ /* Different calculation for bear form with empty hands */
+ else if ((p_ptr->melee_style == SKILL_HAND) && monk_empty_hands())
+ {
+ int plev = get_skill(SKILL_HAND);
+
+ p_ptr->num_blow = get_extra_blows_ability();
+
+ if (plev > 9) p_ptr->num_blow++;
+ if (plev > 19) p_ptr->num_blow++;
+ if (plev > 29) p_ptr->num_blow++;
+ if (plev > 34) p_ptr->num_blow++;
+ if (plev > 39) p_ptr->num_blow++;
+ if (plev > 44) p_ptr->num_blow++;
+ if (plev > 49) p_ptr->num_blow++;
+
+ if (monk_heavy_armor()) p_ptr->num_blow /= 2;
+
+ p_ptr->num_blow += 1 + extra_blows;
+
+ if (!monk_heavy_armor())
+ {
+ p_ptr->to_h += (plev / 3);
+ p_ptr->to_d += (plev / 3);
+
+ p_ptr->dis_to_h += (plev / 3);
+ p_ptr->dis_to_d += (plev / 3);
+ }
+ }
+
+ /* Monsters that only have their "natural" attacks */
+ else if (!r_info[p_ptr->body_monster].body_parts[BODY_WEAPON])
+ {
+ int str_index, dex_index;
+ int num = 0, wgt = 0, mul = 0;
+ monster_race *r_ptr = race_info_idx(p_ptr->body_monster, 0);
+
+ analyze_blow(&num, &wgt, &mul);
+
+ /* Access the strength vs weight */
+ str_index = (adj_str_blow[p_ptr->stat_ind[A_STR]] * mul / 3);
+
+ /* Maximal value */
+ if (str_index > 11) str_index = 11;
+
+ /* Index by dexterity */
+ dex_index = (adj_dex_blow[p_ptr->stat_ind[A_DEX]]);
+
+ /* Maximal value */
+ if (dex_index > 11) dex_index = 11;
+
+ /* Use the blows table */
+ p_ptr->num_blow = blows_table[str_index][dex_index];
+
+ /* Add in the "bonus blows" */
+ p_ptr->num_blow += extra_blows;
+
+ /* Maximal value */
+ if (p_ptr->num_blow > 4) p_ptr->num_blow = 4;
+
+ /* Require at least one blow */
+ if (p_ptr->num_blow < 1) p_ptr->num_blow = 1;
+
+ /* Limit as defined by monster body */
+ for (num = 0; num < p_ptr->num_blow; num++)
+ if (!r_ptr->blow[num].effect)
+ break;
+ p_ptr->num_blow = num;
+ }
+
+ /* Different calculation for monks with empty hands */
+ else if ((!p_ptr->body_monster) && (p_ptr->mimic_form == resolve_mimic_name("Bear")) && (p_ptr->melee_style == SKILL_BEAR))
+ {
+ int plev = get_skill(SKILL_BEAR);
+
+ p_ptr->num_blow = 0;
+
+ p_ptr->num_blow += 2 + (plev / 5) + extra_blows;
+
+ p_ptr->to_h -= (plev / 5);
+ p_ptr->dis_to_h -= (plev / 5);
+
+ p_ptr->to_d += (plev / 2);
+ p_ptr->dis_to_d += (plev / 2);
+ }
+
+ /* Assume okay */
+ p_ptr->icky_wield = FALSE;
+ monk_armour_aux = FALSE;
+
+ if (get_weaponmastery_skill() != -1)
+ {
+ int lev = get_skill(get_weaponmastery_skill());
+
+ p_ptr->to_h_melee += lev;
+ p_ptr->to_d_melee += lev / 2;
+ }
+
+ if (get_skill(SKILL_COMBAT))
+ {
+ int lev = get_skill_scale(SKILL_COMBAT, 10);
+
+ p_ptr->to_d += lev;
+ p_ptr->dis_to_d += lev;
+ }
+
+ if (get_skill(SKILL_DODGE))
+ {
+ /* Get the armor weight */
+ int cur_wgt = 0;
+
+ cur_wgt += p_ptr->inventory[INVEN_BODY].weight;
+ cur_wgt += p_ptr->inventory[INVEN_HEAD].weight;
+ cur_wgt += p_ptr->inventory[INVEN_ARM].weight;
+ cur_wgt += p_ptr->inventory[INVEN_OUTER].weight;
+ cur_wgt += p_ptr->inventory[INVEN_HANDS].weight;
+ cur_wgt += p_ptr->inventory[INVEN_FEET].weight;
+
+ /* Base dodge chance */
+ p_ptr->dodge_chance = get_skill_scale(SKILL_DODGE, 150) + get_skill(SKILL_HAND);
+
+ /* Armor weight bonus/penalty */
+ p_ptr->dodge_chance -= cur_wgt * 2;
+
+ /* Encumberance bonus/penalty */
+ p_ptr->dodge_chance = p_ptr->dodge_chance - (calc_total_weight() / 100);
+
+ /* Never below 0 */
+ if (p_ptr->dodge_chance < 0) p_ptr->dodge_chance = 0;
+ }
+ else
+ {
+ p_ptr->dodge_chance = 0;
+ }
+
+ /* Parse all the weapons */
+ i = 0;
+ while (p_ptr->body_parts[i] == INVEN_WIELD)
+ {
+ o_ptr = &p_ptr->inventory[INVEN_WIELD + i];
+
+ /* 2handed weapon and shield = less damage */
+ if (p_ptr->inventory[INVEN_WIELD + i].k_idx && p_ptr->inventory[INVEN_ARM + i].k_idx)
+ {
+ /* Extract the item flags */
+ object_flags(&p_ptr->inventory[INVEN_WIELD + i], &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (f4 & TR4_COULD2H)
+ {
+ int tmp;
+
+ /* Reduce the bonuses */
+ tmp = o_ptr->to_h / 2;
+ if (tmp < 0) tmp = -tmp;
+ p_ptr->to_h_melee -= tmp;
+
+ tmp = o_ptr->to_d / 2;
+ if (tmp < 0) tmp = -tmp;
+ tmp += (o_ptr->dd * o_ptr->ds) / 2;
+ p_ptr->to_d_melee -= tmp;
+ }
+ }
+
+ /* Priest weapon penalty for non-blessed edged weapons */
+ if (((forbid_non_blessed()) && (!p_ptr->bless_blade) &&
+ ((o_ptr->tval == TV_AXE) || (o_ptr->tval == TV_SWORD) || (o_ptr->tval == TV_POLEARM))) && (o_ptr->k_idx))
+ {
+ /* Reduce the real bonuses */
+ p_ptr->to_h -= 15;
+ p_ptr->to_d -= 15;
+
+ /* Reduce the mental bonuses */
+ p_ptr->dis_to_h -= 15;
+ p_ptr->dis_to_d -= 15;
+
+ /* Icky weapon */
+ p_ptr->icky_wield = TRUE;
+ }
+
+ /* Sorcerer can't wield a weapon unless it's a mage staff */
+ if (get_skill(SKILL_SORCERY))
+ {
+ int malus = get_skill_scale(SKILL_SORCERY, 100);
+
+ if ((o_ptr->tval != TV_MSTAFF) && (o_ptr->k_idx))
+ {
+ /* Reduce the real bonuses */
+ p_ptr->to_h -= malus;
+ p_ptr->to_d -= malus;
+
+ /* Reduce the mental bonuses */
+ p_ptr->dis_to_h -= malus;
+ p_ptr->dis_to_d -= malus;
+
+ /* Icky weapon */
+ p_ptr->icky_wield = TRUE;
+ }
+ else
+ {
+ /* Reduce the real bonuses */
+ p_ptr->to_h -= malus / 10;
+ p_ptr->to_d -= malus / 10;
+
+ /* Reduce the mental bonuses */
+ p_ptr->dis_to_h -= malus / 10;
+ p_ptr->dis_to_d -= malus / 10;
+ }
+ }
+
+ /* Check next weapon */
+ i++;
+ }
+
+ if (monk_heavy_armor())
+ {
+ monk_armour_aux = TRUE;
+ }
+
+ /* Affect Skill -- stealth (bonus one) */
+ p_ptr->skill_stl += 1;
+
+ /* Affect Skill -- disarming (DEX and INT) */
+ p_ptr->skill_dis += adj_dex_dis[p_ptr->stat_ind[A_DEX]];
+ p_ptr->skill_dis += adj_int_dis[p_ptr->stat_ind[A_INT]];
+
+ /* Affect Skill -- magic devices (INT) */
+ p_ptr->skill_dev += get_skill_scale(SKILL_DEVICE, 20);
+
+ /* Affect Skill -- saving throw (WIS) */
+ p_ptr->skill_sav += adj_wis_sav[p_ptr->stat_ind[A_WIS]];
+
+ /* Affect Skill -- digging (STR) */
+ p_ptr->skill_dig += adj_str_dig[p_ptr->stat_ind[A_STR]];
+
+ /* Affect Skill -- disarming (skill) */
+ p_ptr->skill_dis += (get_skill_scale(SKILL_DISARMING, 75));
+
+ /* Affect Skill -- magic devices (skill) */
+ p_ptr->skill_dev += (get_skill_scale(SKILL_DEVICE, 150));
+
+ /* Affect Skill -- saving throw (skill and level) */
+ p_ptr->skill_sav += (get_skill_scale(SKILL_SPIRITUALITY, 75));
+
+ /* Affect Skill -- stealth (skill) */
+ p_ptr->skill_stl += (get_skill_scale(SKILL_STEALTH, 25));
+
+ /* Affect Skill -- search ability (Sneakiness skill) */
+ p_ptr->skill_srh += (get_skill_scale(SKILL_SNEAK, 35));
+
+ /* Affect Skill -- search frequency (Sneakiness skill) */
+ p_ptr->skill_fos += (get_skill_scale(SKILL_SNEAK, 25));
+
+ /* Affect Skill -- combat (Combat skill + mastery) */
+ p_ptr->skill_thn += (50 * (((7 * get_skill(p_ptr->melee_style)) + (3 * get_skill(SKILL_COMBAT))) / 10) / 10);
+
+ /* Affect Skill -- combat (shooting) (Level, by Class) */
+ p_ptr->skill_thb += (50 * (((7 * get_skill(SKILL_ARCHERY)) + (3 * get_skill(SKILL_COMBAT))) / 10) / 10);
+
+ /* Affect Skill -- combat (throwing) (Level) */
+ p_ptr->skill_tht += (50 * p_ptr->lev / 10);
+
+
+ /* Limit Skill -- stealth from 0 to 30 */
+ if (p_ptr->skill_stl > 30) p_ptr->skill_stl = 30;
+ if (p_ptr->skill_stl < 0) p_ptr->skill_stl = 0;
+
+ /* Limit Skill -- digging from 1 up */
+ if (p_ptr->skill_dig < 1) p_ptr->skill_dig = 1;
+
+ if ((p_ptr->anti_magic) && (p_ptr->skill_sav < 95)) p_ptr->skill_sav = 95;
+
+ /* Hack -- handle "xtra" mode */
+ if (character_xtra) return;
+
+ /* Take note when "heavy bow" changes */
+ if (p_ptr->old_heavy_shoot != p_ptr->heavy_shoot)
+ {
+ if (silent)
+ {
+ /* do nothing */
+ }
+ /* Message */
+ else if (p_ptr->heavy_shoot)
+ {
+ msg_print("You have trouble wielding such a heavy bow.");
+ }
+ else if (p_ptr->inventory[INVEN_BOW].k_idx)
+ {
+ msg_print("You have no trouble wielding your bow.");
+ }
+ else
+ {
+ msg_print("You feel relieved to put down your heavy bow.");
+ }
+
+ /* Save it */
+ p_ptr->old_heavy_shoot = p_ptr->heavy_shoot;
+ }
+
+
+ /* Take note when "heavy weapon" changes */
+ if (p_ptr->old_heavy_wield != p_ptr->heavy_wield)
+ {
+ if (silent)
+ {
+ /* do nothing */
+ }
+ /* Message */
+ else if (p_ptr->heavy_wield)
+ {
+ msg_print("You have trouble wielding such a heavy weapon.");
+ }
+ else if (p_ptr->inventory[INVEN_WIELD].k_idx)
+ {
+ msg_print("You have no trouble wielding your weapon.");
+ }
+ else
+ {
+ msg_print("You feel relieved to put down your heavy weapon.");
+ }
+
+ /* Save it */
+ p_ptr->old_heavy_wield = p_ptr->heavy_wield;
+ }
+
+
+ /* Take note when "illegal weapon" changes */
+ if (p_ptr->old_icky_wield != p_ptr->icky_wield)
+ {
+ if (silent)
+ {
+ /* do nothing */
+ }
+ /* Message */
+ else if (p_ptr->icky_wield)
+ {
+ msg_print("You do not feel comfortable with your weapon.");
+ }
+ else if (p_ptr->inventory[INVEN_WIELD].k_idx)
+ {
+ msg_print("You feel comfortable with your weapon.");
+ }
+ else
+ {
+ msg_print("You feel more comfortable after removing your weapon.");
+ }
+
+ /* Save it */
+ p_ptr->old_icky_wield = p_ptr->icky_wield;
+ }
+
+ if (monk_armour_aux != monk_notify_aux)
+ {
+ if ((p_ptr->melee_style != SKILL_HAND) || silent)
+ {
+ /* do nothing */
+ }
+ else if (monk_heavy_armor())
+ msg_print("The weight of your armor disrupts your balance.");
+ else
+ msg_print("You regain your balance.");
+ monk_notify_aux = monk_armour_aux;
+ }
+
+ /* Resist lite & senseible lite negates one an other */
+ if (p_ptr->resist_lite && p_ptr->sensible_lite)
+ {
+ p_ptr->resist_lite = p_ptr->sensible_lite = FALSE;
+ }
+
+ /* resistance to fire cancel sensibility to fire */
+ if (p_ptr->resist_fire || p_ptr->oppose_fire || p_ptr->immune_fire)
+ p_ptr->sensible_fire = FALSE;
+
+ /* Minimum saving throw */
+ if(p_ptr->skill_sav <= 10)
+ p_ptr->skill_sav = 10;
+ else
+ p_ptr->skill_sav += 10;
+
+ /* Let the scripts do what they need */
+ process_hooks(HOOK_CALC_BONUS_END, "(d)", silent);
+}
+
+
+
+/*
+ * Handle "p_ptr->notice"
+ */
+void notice_stuff(void)
+{
+ /* Notice stuff */
+ if (!p_ptr->notice) return;
+
+
+ /* Combine the pack */
+ if (p_ptr->notice & (PN_COMBINE))
+ {
+ p_ptr->notice &= ~(PN_COMBINE);
+ combine_pack();
+ }
+
+ /* Reorder the pack */
+ if (p_ptr->notice & (PN_REORDER))
+ {
+ p_ptr->notice &= ~(PN_REORDER);
+ reorder_pack();
+ }
+}
+
+
+/*
+ * Handle "p_ptr->update"
+ */
+void update_stuff(void)
+{
+ /* Update stuff */
+ if (!p_ptr->update) return;
+
+
+ if (p_ptr->update & (PU_BODY))
+ {
+ p_ptr->update &= ~(PU_BODY);
+ calc_body();
+ }
+
+ if (p_ptr->update & (PU_BONUS))
+ {
+ /* Ok now THAT is an ugly hack */
+ p_ptr->update &= ~(PU_POWERS);
+ calc_powers();
+
+ p_ptr->update &= ~(PU_BONUS);
+ calc_bonuses(FALSE);
+ }
+
+ if (p_ptr->update & (PU_TORCH))
+ {
+ p_ptr->update &= ~(PU_TORCH);
+ calc_torch();
+ }
+
+ if (p_ptr->update & (PU_HP))
+ {
+ p_ptr->update &= ~(PU_HP);
+ calc_hitpoints();
+ }
+
+ if (p_ptr->update & (PU_SANITY))
+ {
+ p_ptr->update &= ~(PU_SANITY);
+ calc_sanity();
+ }
+
+ if (p_ptr->update & (PU_MANA))
+ {
+ p_ptr->update &= ~(PU_MANA);
+ calc_mana();
+ }
+
+ if (p_ptr->update & (PU_SPELLS))
+ {
+ p_ptr->update &= ~(PU_SPELLS);
+ calc_spells();
+ }
+
+ if (p_ptr->update & (PU_POWERS))
+ {
+ p_ptr->update &= ~(PU_POWERS);
+ calc_powers();
+ }
+
+ /* Character is not ready yet, no screen updates */
+ if (!character_generated) return;
+
+
+ /* Character is in "icky" mode, no screen updates */
+ if (character_icky) return;
+
+
+ if (p_ptr->update & (PU_UN_VIEW))
+ {
+ p_ptr->update &= ~(PU_UN_VIEW);
+ forget_view();
+ }
+
+ if (p_ptr->update & (PU_VIEW))
+ {
+ p_ptr->update &= ~(PU_VIEW);
+ update_view();
+ }
+
+ if (p_ptr->update & (PU_FLOW))
+ {
+ p_ptr->update &= ~(PU_FLOW);
+ update_flow();
+ }
+
+ if (p_ptr->update & (PU_DISTANCE))
+ {
+ p_ptr->update &= ~(PU_DISTANCE);
+ p_ptr->update &= ~(PU_MONSTERS);
+ update_monsters(TRUE);
+ }
+
+ if (p_ptr->update & (PU_MONSTERS))
+ {
+ p_ptr->update &= ~(PU_MONSTERS);
+ update_monsters(FALSE);
+ }
+
+ if (p_ptr->update & (PU_MON_LITE))
+ {
+ p_ptr->update &= ~(PU_MON_LITE);
+ if (monster_lite) update_mon_lite();
+ }
+}
+
+
+/*
+ * Handle "p_ptr->redraw"
+ */
+void redraw_stuff(void)
+{
+ /* Redraw stuff */
+ if (!p_ptr->redraw) return;
+
+
+ /* Character is not ready yet, no screen updates */
+ if (!character_generated) return;
+
+
+ /* Character is in "icky" mode, no screen updates */
+ if (character_icky) return;
+
+
+ /* Should we tell lua to redisplay too ? */
+ process_hooks(HOOK_REDRAW, "()");
+
+
+ /* Hack -- clear the screen */
+ if (p_ptr->redraw & (PR_WIPE))
+ {
+ p_ptr->redraw &= ~(PR_WIPE);
+ msg_print(NULL);
+ Term_clear();
+ }
+
+
+ if (p_ptr->redraw & (PR_MAP))
+ {
+ p_ptr->redraw &= ~(PR_MAP);
+ prt_map();
+ }
+
+
+ if (p_ptr->redraw & (PR_BASIC))
+ {
+ p_ptr->redraw &= ~(PR_BASIC);
+ p_ptr->redraw &= ~(PR_MISC | PR_TITLE | PR_STATS);
+ p_ptr->redraw &= ~(PR_LEV | PR_EXP | PR_GOLD);
+ p_ptr->redraw &= ~(PR_ARMOR | PR_HP | PR_MANA | PR_PIETY | PR_MH);
+ p_ptr->redraw &= ~(PR_DEPTH | PR_HEALTH);
+ prt_frame_basic();
+ }
+
+ if (p_ptr->redraw & (PR_MISC))
+ {
+ p_ptr->redraw &= ~(PR_MISC);
+ prt_field(rp_ptr->title + rp_name, ROW_RACE, COL_RACE);
+ prt_field(spp_ptr->title + c_name, ROW_CLASS, COL_CLASS);
+ }
+
+ if (p_ptr->redraw & (PR_TITLE))
+ {
+ p_ptr->redraw &= ~(PR_TITLE);
+ prt_title();
+ }
+
+ if (p_ptr->redraw & (PR_LEV))
+ {
+ p_ptr->redraw &= ~(PR_LEV);
+ prt_level();
+ }
+
+ if (p_ptr->redraw & (PR_EXP))
+ {
+ p_ptr->redraw &= ~(PR_EXP);
+ prt_exp();
+ }
+
+ if (p_ptr->redraw & (PR_STATS))
+ {
+ p_ptr->redraw &= ~(PR_STATS);
+ prt_stat(A_STR);
+ prt_stat(A_INT);
+ prt_stat(A_WIS);
+ prt_stat(A_DEX);
+ prt_stat(A_CON);
+ prt_stat(A_CHR);
+ }
+
+ if (p_ptr->redraw & (PR_ARMOR))
+ {
+ p_ptr->redraw &= ~(PR_ARMOR);
+ prt_ac();
+ }
+
+ if (p_ptr->redraw & (PR_HP))
+ {
+ p_ptr->redraw &= ~(PR_HP);
+ prt_hp();
+ }
+
+ if (p_ptr->redraw & (PR_MANA))
+ {
+ p_ptr->redraw &= ~(PR_MANA);
+ prt_sp();
+ }
+
+ if (p_ptr->redraw & (PR_PIETY))
+ {
+ p_ptr->redraw &= ~(PR_PIETY);
+ prt_piety();
+ }
+
+ if (p_ptr->redraw & (PR_MH))
+ {
+ p_ptr->redraw &= ~(PR_MH);
+ prt_mh();
+ }
+
+ if (p_ptr->redraw & (PR_GOLD))
+ {
+ p_ptr->redraw &= ~(PR_GOLD);
+ prt_gold();
+ }
+
+ if (p_ptr->redraw & (PR_DEPTH))
+ {
+ p_ptr->redraw &= ~(PR_DEPTH);
+ prt_depth();
+ }
+
+ if (p_ptr->redraw & (PR_HEALTH))
+ {
+ p_ptr->redraw &= ~(PR_HEALTH);
+ health_redraw();
+ }
+
+
+ if (p_ptr->redraw & (PR_EXTRA))
+ {
+ p_ptr->redraw &= ~(PR_EXTRA);
+ p_ptr->redraw &= ~(PR_CUT | PR_STUN);
+ p_ptr->redraw &= ~(PR_HUNGER);
+ p_ptr->redraw &= ~(PR_BLIND | PR_CONFUSED);
+ p_ptr->redraw &= ~(PR_AFRAID | PR_POISONED);
+ p_ptr->redraw &= ~(PR_STATE | PR_SPEED | PR_STUDY | PR_SANITY);
+ prt_frame_extra();
+ }
+
+ if (p_ptr->redraw & (PR_CUT))
+ {
+ p_ptr->redraw &= ~(PR_CUT);
+ prt_cut();
+ }
+
+ if (p_ptr->redraw & (PR_STUN))
+ {
+ p_ptr->redraw &= ~(PR_STUN);
+ prt_stun();
+ }
+
+ if (p_ptr->redraw & (PR_HUNGER))
+ {
+ p_ptr->redraw &= ~(PR_HUNGER);
+ prt_hunger();
+ }
+
+ if (p_ptr->redraw & (PR_BLIND))
+ {
+ p_ptr->redraw &= ~(PR_BLIND);
+ prt_blind();
+ }
+
+ if (p_ptr->redraw & (PR_CONFUSED))
+ {
+ p_ptr->redraw &= ~(PR_CONFUSED);
+ prt_confused();
+ }
+
+ if (p_ptr->redraw & (PR_AFRAID))
+ {
+ p_ptr->redraw &= ~(PR_AFRAID);
+ prt_afraid();
+ }
+
+ if (p_ptr->redraw & (PR_POISONED))
+ {
+ p_ptr->redraw &= ~(PR_POISONED);
+ prt_poisoned();
+ }
+
+ if (p_ptr->redraw & (PR_DTRAP))
+ {
+ p_ptr->redraw &= ~(PR_DTRAP);
+ prt_dtrap();
+ }
+
+ if (p_ptr->redraw & (PR_STATE))
+ {
+ p_ptr->redraw &= ~(PR_STATE);
+ prt_state();
+ }
+
+ if (p_ptr->redraw & (PR_SPEED))
+ {
+ p_ptr->redraw &= ~(PR_SPEED);
+ prt_speed();
+ }
+
+ if (p_ptr->redraw & (PR_STUDY))
+ {
+ p_ptr->redraw &= ~(PR_STUDY);
+ prt_study();
+ }
+
+ if (p_ptr->redraw & (PR_SANITY))
+ {
+ p_ptr->redraw &= ~(PR_SANITY);
+ prt_sane();
+ }
+}
+
+
+/*
+ * Handle "p_ptr->window"
+ */
+void window_stuff(void)
+{
+ int j;
+
+ u32b mask = 0L;
+
+
+ /* Nothing to do */
+ if (!p_ptr->window) return;
+
+ /* Scan windows */
+ for (j = 0; j < 8; j++)
+ {
+ /* Save usable flags */
+ if (angband_term[j]) mask |= window_flag[j];
+ }
+
+ /* Apply usable flags */
+ p_ptr->window &= mask;
+
+ /* Nothing to do */
+ if (!p_ptr->window) return;
+
+
+ /* Display p_ptr->inventory */
+ if (p_ptr->window & (PW_INVEN))
+ {
+ p_ptr->window &= ~(PW_INVEN);
+ fix_inven();
+ }
+
+ /* Display equipment */
+ if (p_ptr->window & (PW_EQUIP))
+ {
+ p_ptr->window &= ~(PW_EQUIP);
+ fix_equip();
+ }
+
+ /* Display player */
+ if (p_ptr->window & (PW_PLAYER))
+ {
+ p_ptr->window &= ~(PW_PLAYER);
+ fix_player();
+ }
+
+ /* Display monster list */
+ if (p_ptr->window & (PW_M_LIST))
+ {
+ p_ptr->window &= ~(PW_M_LIST);
+ fix_m_list();
+ }
+
+ /* Display overhead view */
+ if (p_ptr->window & (PW_MESSAGE))
+ {
+ p_ptr->window &= ~(PW_MESSAGE);
+ fix_message();
+ }
+
+ /* Display overhead view */
+ if (p_ptr->window & (PW_OVERHEAD))
+ {
+ p_ptr->window &= ~(PW_OVERHEAD);
+ fix_overhead();
+ }
+
+ /* Display monster recall */
+ if (p_ptr->window & (PW_MONSTER))
+ {
+ p_ptr->window &= ~(PW_MONSTER);
+ fix_monster();
+ }
+
+ /* Display object recall */
+ if (p_ptr->window & (PW_OBJECT))
+ {
+ p_ptr->window &= ~(PW_OBJECT);
+ fix_object();
+ }
+}
+
+
+/*
+ * Handle "p_ptr->update" and "p_ptr->redraw" and "p_ptr->window"
+ */
+void handle_stuff(void)
+{
+ /* Update stuff */
+ if (p_ptr->update) update_stuff();
+
+ /* Redraw stuff */
+ if (p_ptr->redraw) redraw_stuff();
+
+ /* Window stuff */
+ if (p_ptr->window) window_stuff();
+}
+
+
+bool_ monk_empty_hands(void)
+{
+ int i;
+ object_type *o_ptr;
+
+ if (p_ptr->melee_style != SKILL_HAND) return FALSE;
+
+ i = 0;
+ while (p_ptr->body_parts[i] == INVEN_WIELD)
+ {
+ o_ptr = &p_ptr->inventory[INVEN_WIELD + i];
+
+ if (o_ptr->k_idx) return FALSE;
+
+ i++;
+ }
+
+ return TRUE;
+}
+
+bool_ monk_heavy_armor(void)
+{
+ u16b monk_arm_wgt = 0;
+
+ if (p_ptr->melee_style != SKILL_HAND) return FALSE;
+
+ /* Weight the armor */
+ monk_arm_wgt += p_ptr->inventory[INVEN_BODY].weight;
+ monk_arm_wgt += p_ptr->inventory[INVEN_HEAD].weight;
+ monk_arm_wgt += p_ptr->inventory[INVEN_ARM].weight;
+ monk_arm_wgt += p_ptr->inventory[INVEN_OUTER].weight;
+ monk_arm_wgt += p_ptr->inventory[INVEN_HANDS].weight;
+ monk_arm_wgt += p_ptr->inventory[INVEN_FEET].weight;
+
+ return (monk_arm_wgt > (100 + (get_skill(SKILL_HAND) * 4))) ;
+}
+
+static int get_artifact_idx(int level)
+{
+ int count = 0, i;
+
+ while (count < 1000)
+ {
+ artifact_type *a_ptr;
+
+ count++;
+ i = randint(max_a_idx - 1);
+ a_ptr = &a_info[i];
+ if (!a_ptr->tval) continue;
+
+ /* It is found/lost */
+ if (a_ptr->cur_num) continue;
+
+ /* OoD */
+ if (a_ptr->level > level) continue;
+
+ /* Avoid granting SPECIAL_GENE artifacts */
+ if (a_ptr->flags4 & TR4_SPECIAL_GENE) continue;
+
+ return i;
+ }
+
+ /* No matches found */
+ /* Grant a randart */
+ return 0;
+}
+
+/* Chose a fate */
+void gain_fate(byte fate)
+{
+ int i;
+ int level;
+
+ for (i = 0; i < MAX_FATES; i++)
+ {
+ if (!fates[i].fate)
+ {
+ fates[i].level = 0;
+
+ cmsg_print(TERM_VIOLET, "More of your prophecy has been unearthed!");
+ cmsg_print(TERM_VIOLET, "You should see a soothsayer quickly.");
+
+ if (fate)
+ fates[i].fate = fate;
+ else
+ /* If lucky (current luck > 0) avoid death fate */
+ switch (rand_int(p_ptr->luck_cur > 0 ? 17 : 18))
+ {
+ case 6:
+ case 2:
+ case 3:
+ case 7:
+ case 8:
+ case 9:
+ case 13:
+ fates[i].fate = FATE_FIND_O;
+ break;
+ case 1:
+ case 4:
+ case 5:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ fates[i].fate = FATE_FIND_R;
+ break;
+ case 15:
+ case 16:
+ fates[i].fate = FATE_FIND_A;
+ break;
+ case 17:
+ fates[i].fate = FATE_DIE;
+ break;
+ case 0:
+ {
+ /* The deepest the better */
+ int chance = dun_level / 4;
+
+ /* No more than 1/2 chances */
+ if (chance > 50) chance = 50;
+
+ /* It's HARD to get now */
+ if (magik(chance))
+ {
+ fates[i].fate = FATE_NO_DIE_MORTAL;
+ }
+ else
+ {
+ fates[i].fate = FATE_FIND_O;
+ }
+ break;
+ }
+ }
+
+ switch (fates[i].fate)
+ {
+ case FATE_FIND_O:
+ {
+ while (TRUE)
+ {
+ object_kind *k_ptr;
+ obj_theme theme;
+
+ /* No themes */
+ theme.treasure = 100;
+ theme.combat = 100;
+ theme.magic = 100;
+ theme.tools = 100;
+ init_match_theme(theme);
+
+ /* Apply restriction */
+ get_obj_num_hook = kind_is_legal;
+
+ /* Rebuild allocation table */
+ get_obj_num_prep();
+
+ fates[i].o_idx = get_obj_num(max_dlv[dungeon_type] + randint(10));
+
+ /* Invalidate the cached allocation table */
+ alloc_kind_table_valid = FALSE;
+
+ k_ptr = &k_info[fates[i].o_idx];
+
+ if (!(k_ptr->flags3 & TR3_INSTA_ART) && !(k_ptr->flags3 & TR3_NORM_ART)) break;
+ }
+ level = rand_range(max_dlv[dungeon_type] - 20, max_dlv[dungeon_type] + 20);
+ fates[i].level = (level < 1) ? 1 : (level > 98) ? 98 : level;
+ fates[i].serious = rand_int(2);
+ fates[i].know = FALSE;
+ if (wizard) msg_format("New fate : Find object %d on level %d", fates[i].o_idx, fates[i].level);
+ break;
+ }
+ case FATE_FIND_R:
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ fates[i].r_idx = get_mon_num(max_dlv[dungeon_type] + randint(10));
+ level = rand_range(max_dlv[dungeon_type] - 20, max_dlv[dungeon_type] + 20);
+ fates[i].level = (level < 1) ? 1 : (level > 98) ? 98 : level;
+ fates[i].serious = rand_int(2);
+ fates[i].know = FALSE;
+ if (wizard) msg_format("New fate : Meet monster %d on level %d", fates[i].r_idx, fates[i].level);
+ break;
+
+ case FATE_FIND_A:
+ fates[i].a_idx = get_artifact_idx(max_dlv[dungeon_type] + randint(10));
+ level = rand_range(max_dlv[dungeon_type] - 20, max_dlv[dungeon_type] + 20);
+ fates[i].level = (level < 1) ? 1 : (level > 98) ? 98 : level;
+ fates[i].serious = TRUE;
+ fates[i].know = FALSE;
+ if (wizard) msg_format("New fate : Find artifact %d on level %d", fates[i].a_idx, fates[i].level);
+ break;
+
+ case FATE_DIE:
+ level = rand_range(max_dlv[dungeon_type] - 20, max_dlv[dungeon_type] + 20);
+ fates[i].level = (level < 1) ? 1 : (level > 98) ? 98 : level;
+ fates[i].serious = TRUE;
+ fates[i].know = FALSE;
+ if ((wizard) || (p_ptr->precognition)) msg_format("New fate : Death on level %d", fates[i].level);
+ break;
+
+ case FATE_NO_DIE_MORTAL:
+ fates[i].serious = TRUE;
+ p_ptr->no_mortal = TRUE;
+ if ((wizard) || (p_ptr->precognition)) msg_format("New fate : Never to die by the hand of a mortal being.");
+ break;
+ }
+
+ break;
+ }
+ }
+}
+
+void fate_desc(char *desc, int fate)
+{
+ char buf[120];
+
+ if (fates[fate].serious)
+ {
+ strcpy(desc, "You are fated to ");
+ }
+ else
+ {
+ strcpy(desc, "You may ");
+ }
+ switch (fates[fate].fate)
+ {
+ case FATE_FIND_O:
+ {
+ object_type *o_ptr, forge;
+ char o_name[80];
+
+ o_ptr = &forge;
+ object_prep(o_ptr, fates[fate].o_idx);
+ object_desc_store(o_name, o_ptr, 1, 0);
+
+ sprintf(buf, "find %s on level %d.", o_name, fates[fate].level);
+ strcat(desc, buf);
+ break;
+ }
+ case FATE_FIND_A:
+ {
+ object_type *q_ptr, forge;
+ char o_name[80];
+ artifact_type *a_ptr = &a_info[fates[fate].a_idx];
+ int I_kind;
+
+ /* Failed artefact allocation XXX XXX XXX */
+ if (fates[fate].a_idx == 0)
+ {
+ strcpy(o_name, "something special");
+ }
+
+ /* Legal artefacts */
+ else
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Acquire the "kind" index */
+ I_kind = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Create the artifact */
+ object_prep(q_ptr, I_kind);
+
+ /* Save the name */
+ q_ptr->name1 = fates[fate].a_idx;
+
+ /* Extract the fields */
+ q_ptr->pval = a_ptr->pval;
+ q_ptr->ac = a_ptr->ac;
+ q_ptr->dd = a_ptr->dd;
+ q_ptr->ds = a_ptr->ds;
+ q_ptr->to_a = a_ptr->to_a;
+ q_ptr->to_h = a_ptr->to_h;
+ q_ptr->to_d = a_ptr->to_d;
+ q_ptr->weight = a_ptr->weight;
+
+ /* Hack -- acquire "cursed" flag */
+ if (a_ptr->flags3 & (TR3_CURSED)) q_ptr->ident |= (IDENT_CURSED);
+
+ random_artifact_resistance(q_ptr);
+
+ object_desc_store(o_name, q_ptr, 1, 0);
+ }
+
+ sprintf(buf, "find %s on level %d.", o_name, fates[fate].level);
+ strcat(desc, buf);
+ break;
+ }
+ case FATE_FIND_R:
+ {
+ char m_name[80];
+
+ monster_race_desc(m_name, fates[fate].r_idx, 0);
+ sprintf(buf, "meet %s on level %d.", m_name, fates[fate].level);
+ strcat(desc, buf);
+ break;
+ }
+ case FATE_DIE:
+ {
+ sprintf(buf, "die on level %d.", fates[fate].level);
+ strcat(desc, buf);
+ break;
+ }
+ case FATE_NO_DIE_MORTAL:
+ {
+ strcat(desc, "never to die by the hand of a mortal being.");
+ break;
+ }
+ }
+}
+
+void dump_fates(FILE *outfile)
+{
+ int i;
+ char buf[120];
+ bool_ pending = FALSE;
+
+ if (!outfile) return;
+
+ for (i = 0; i < MAX_FATES; i++)
+ {
+ if ((fates[i].fate) && (fates[i].know))
+ {
+ fate_desc(buf, i);
+ fprintf(outfile, "%s\n", buf);
+ }
+ if ((fates[i].fate) && !(fates[i].know)) pending = TRUE;
+ }
+ if (pending)
+ {
+ fprintf(outfile, "You do not know all of your fate.\n");
+ }
+}
+
+/*
+ * Return a luck number between a certain range
+ */
+int luck(int min, int max)
+{
+ int luck = p_ptr->luck_cur;
+ int range = max - min;
+
+ if (luck < -30) luck = -30;
+ if (luck > 30) luck = 30;
+ luck += 30;
+
+ luck *= range;
+ luck /= 60;
+
+ return (luck + min);
+}
diff --git a/src/xtra2.c b/src/xtra2.c
new file mode 100644
index 00000000..70978e47
--- /dev/null
+++ b/src/xtra2.c
@@ -0,0 +1,6158 @@
+/* File: xtra2.c */
+/* File: xtra2.c */
+
+/* Purpose: effects of various "objects", targetting and panel handling */
+
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * Invoke The Rush
+ */
+bool_ set_rush(int v)
+{
+ int j;
+
+ /* Invoke The Bust */
+ if (!v)
+ {
+ p_ptr->rush = 0;
+
+ j = 50 - randint(p_ptr->lev);
+ set_paralyzed(j);
+ set_slow(j + 50 - randint(p_ptr->lev));
+ return TRUE;
+ }
+
+ /* When is The Bust going to happen? */
+ p_ptr->rush = v;
+
+ /* The bonuses of The Rush */
+ set_hero(p_ptr->hero + v);
+ set_tim_deadly(p_ptr->tim_deadly + v);
+ set_strike(p_ptr->strike + v);
+ if (magik(p_ptr->lev / 2))
+ {
+ set_light_speed(p_ptr->lightspeed + v);
+ }
+ else
+ {
+ set_fast(p_ptr->fast + v, 10);
+ }
+ if (magik(p_ptr->lev / 2)) set_tim_esp(p_ptr->tim_esp + v);
+ return TRUE;
+}
+
+
+/*
+ * Set "p_ptr->parasite" and "p_ptr->parasite_r_idx"
+ * notice observable changes
+ */
+bool_ set_parasite(int v, int r)
+{
+ bool_ notice = FALSE;
+
+ /* Hack -- Force good values */
+ v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
+
+ /* Open */
+ if (v)
+ {
+ if (!p_ptr->parasite)
+ {
+ msg_print("You feel something growing in you.");
+ notice = TRUE;
+ }
+ }
+
+ /* Shut */
+ else
+ {
+ if (p_ptr->parasite)
+ {
+ if (magik(80))
+ {
+ char r_name[80];
+ int wx, wy;
+ int attempts = 500;
+
+ monster_race_desc(r_name, p_ptr->parasite_r_idx, 0);
+
+ do
+ {
+ scatter(&wy, &wx, p_ptr->py, p_ptr->px, 10);
+ }
+ while (!(in_bounds(wy, wx) && cave_floor_bold(wy, wx)) && --attempts);
+
+ if (place_monster_one(wy, wx, p_ptr->parasite_r_idx, 0, FALSE, MSTATUS_ENEMY))
+ {
+ cmsg_format(TERM_L_BLUE, "Your body convulses and spawns %s.", r_name);
+ p_ptr->food -= 750;
+ if (p_ptr->food < 100) p_ptr->food = 100;
+ }
+ }
+ else
+ {
+ cmsg_print(TERM_L_BLUE, "The hideous thing growing in you seems to die.");
+ }
+ notice = TRUE;
+ }
+ }
+
+ /* Use the value */
+ p_ptr->parasite = v;
+ p_ptr->parasite_r_idx = r;
+
+ /* Nothing to notice */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0, 0);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Result */
+ return (TRUE);
+}
+
+/*
+ * Set a simple player field.
+ */
+static bool_ set_simple_field(
+ s16b *p_field,
+ s16b v,
+ byte activate_color,
+ cptr activate_msg,
+ byte deactivate_color,
+ cptr deactivate_msg)
+{
+ bool_ notice = FALSE;
+
+ /* Hack -- Force good values */
+ v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
+
+ /* Open */
+ if (v)
+ {
+ if (!*p_field)
+ {
+ cmsg_print(activate_color, activate_msg);
+ notice = TRUE;
+ }
+ }
+
+ /* Shut */
+ else
+ {
+ if (*p_field)
+ {
+ cmsg_print(deactivate_color, deactivate_msg);
+ notice = TRUE;
+ }
+ }
+
+ /* Use the value */
+ *p_field = v;
+
+ /* Nothing to notice */
+ if (!notice)
+ return (FALSE);
+
+ /* Disturb */
+ if (disturb_state)
+ disturb(0, 0);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Result */
+ return (TRUE);
+}
+
+/*
+ * Set "p_ptr->tim_project" and others
+ * notice observable changes
+ */
+bool_ set_project(int v, s16b gf, s16b dam, s16b rad, s16b flag)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->tim_project, v,
+ TERM_WHITE, "Your weapon starts glowing.",
+ TERM_WHITE, "Your weapon stops glowing.");
+
+ /* Use the values */
+ p_ptr->tim_project_gf = gf;
+ p_ptr->tim_project_dam = dam;
+ p_ptr->tim_project_rad = rad;
+ p_ptr->tim_project_flag = flag;
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->tim_roots" and others
+ * notice observable changes
+ */
+bool_ set_roots(int v, s16b ac, s16b dam)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->tim_roots, v,
+ TERM_WHITE, "Roots dive into the floor from your feet.",
+ TERM_WHITE, "The roots of your feet suddenly vanish.");
+
+ /* Use the values */
+ p_ptr->tim_roots_dam = dam;
+ p_ptr->tim_roots_ac = ac;
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->tim_(magic|water)_breath" and others
+ * notice observable changes
+ */
+bool_ set_tim_breath(int v, bool_ magical)
+{
+ if (magical)
+ {
+ return set_simple_field(
+ &p_ptr->tim_magic_breath, v,
+ TERM_WHITE, "Air seems to fill your lungs without breathing.",
+ TERM_WHITE, "You need to breathe again.");
+ }
+ else
+ {
+ return set_simple_field(
+ &p_ptr->tim_water_breath, v,
+ TERM_WHITE, "Water seems to fill your lungs.",
+ TERM_WHITE, "The water filling your lungs evaporates.");
+ }
+}
+
+/*
+ * Set "p_ptr->absorb_soul"
+ * notice observable changes
+ */
+bool_ set_absorb_soul(int v)
+{
+ return set_simple_field(
+ &p_ptr->absorb_soul, v,
+ TERM_L_DARK, "You start absorbing the souls of your foes.",
+ TERM_L_DARK, "You stop absorbing the souls of dead foes.");
+}
+
+/*
+ * Set "p_ptr->disrupt_shield"
+ * notice observable changes
+ */
+bool_ set_disrupt_shield(int v)
+{
+ return set_simple_field(
+ &p_ptr->disrupt_shield, v,
+ TERM_L_BLUE, "You feel invulnerable.",
+ TERM_L_RED, "You are more vulnerable.");
+}
+
+/*
+ * Set "p_ptr->prob_travel"
+ * notice observable changes
+ */
+bool_ set_prob_travel(int v)
+{
+ return set_simple_field(
+ &p_ptr->prob_travel, v,
+ TERM_WHITE, "You feel instable.",
+ TERM_WHITE, "You are more stable.");
+}
+
+/*
+ * Set "p_ptr->tim_invis", and "p_ptr->tim_inv_pow",
+ * notice observable changes
+ */
+bool_ set_invis(int v, int p)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->tim_invisible, v,
+ TERM_WHITE, "You feel your body fade away.",
+ TERM_WHITE, "You are no longer invisible.");
+
+ /* Use the power value */
+ p_ptr->tim_inv_pow = p;
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->tim_poison",
+ * notice observable changes
+ */
+bool_ set_poison(int v)
+{
+ return set_simple_field(
+ &p_ptr->tim_poison, v,
+ TERM_WHITE, "Your hands are dripping with venom.",
+ TERM_WHITE, "The venom source dries out.");
+}
+
+/*
+ * Set "no_breeds"
+ */
+bool_ set_no_breeders(int v)
+{
+ return set_simple_field(
+ &no_breeds, v,
+ TERM_WHITE, "You feel an anti-sexual aura.",
+ TERM_WHITE, "You no longer feel an anti-sexual aura.");
+}
+
+/*
+ * Set "p_ptr->tim_deadly"
+ */
+bool_ set_tim_deadly(int v)
+{
+ return set_simple_field(
+ &p_ptr->tim_deadly, v,
+ TERM_WHITE, "You feel extremely accurate.",
+ TERM_WHITE, "You are suddenly much less accurate.");
+}
+
+/*
+ * Set "p_ptr->tim_ffall"
+ */
+bool_ set_tim_ffall(int v)
+{
+ return set_simple_field(
+ &p_ptr->tim_ffall, v,
+ TERM_WHITE, "You feel very light.",
+ TERM_WHITE, "You are suddenly heavier.");
+}
+
+/*
+ * Set "p_ptr->tim_fly"
+ */
+bool_ set_tim_fly(int v)
+{
+ return set_simple_field(
+ &p_ptr->tim_fly, v,
+ TERM_WHITE, "You feel able to reach the clouds.",
+ TERM_WHITE, "You are suddenly a lot heavier.");
+}
+
+/*
+ * Set "p_ptr->meditation"
+ */
+bool_ set_meditation(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->meditation, v,
+ TERM_WHITE, "You start meditating on yourself...",
+ TERM_WHITE, "You stop your self meditation.");
+
+ /* Recalculate bonuses */
+ if (notice)
+ {
+ p_ptr->update |= (PU_MANA);
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->tim_reflect"
+ */
+bool_ set_tim_reflect(int v)
+{
+ return set_simple_field(
+ &p_ptr->tim_reflect, v,
+ TERM_WHITE, "You start reflecting the world around you.",
+ TERM_WHITE, "You stop reflecting.");
+}
+
+/*
+ * Set "p_ptr->tim_res_time"
+ */
+bool_ set_tim_res_time(int v)
+{
+ return set_simple_field(
+ &p_ptr->tim_res_time, v,
+ TERM_WHITE, "You are now protected against space-time distortions.",
+ TERM_WHITE, "You are no longer protected against space-time distortions.");
+}
+
+/*
+ * Set "p_ptr->tim_fire_aura"
+ */
+bool_ set_tim_fire_aura(int v)
+{
+ return set_simple_field(
+ &p_ptr->tim_fire_aura, v,
+ TERM_WHITE, "You are enveloped in flames.",
+ TERM_WHITE, "You are no longer enveloped in flames.");
+}
+
+/*
+ * Set "p_ptr->strike"
+ */
+bool_ set_strike(int v)
+{
+ return set_simple_field(
+ &p_ptr->strike, v,
+ TERM_WHITE, "You feel very accurate.",
+ TERM_WHITE, "You are no longer very accurate.");
+}
+
+/*
+ * Set "p_ptr->oppose_ld"
+ */
+bool_ set_oppose_ld(int v)
+{
+ return set_simple_field(
+ &p_ptr->oppose_ld, v,
+ TERM_WHITE, "You feel protected against light's fluctuation.",
+ TERM_WHITE, "You are no longer protected against light's fluctuation.");
+}
+
+/*
+ * Set "p_ptr->oppose_cc"
+ */
+bool_ set_oppose_cc(int v)
+{
+ return set_simple_field(
+ &p_ptr->oppose_cc, v,
+ TERM_WHITE, "You feel protected against raw chaos.",
+ TERM_WHITE, "You are no longer protected against chaos.");
+}
+
+/*
+ * Set "p_ptr->oppose_ss"
+ */
+bool_ set_oppose_ss(int v)
+{
+ return set_simple_field(
+ &p_ptr->oppose_ss, v,
+ TERM_WHITE, "You feel protected against the ravages of sound and shards.",
+ TERM_WHITE, "You are no longer protected against the ravages of sound and shards.");
+}
+
+/*
+ * Set "p_ptr->oppose_nex"
+ */
+bool_ set_oppose_nex(int v)
+{
+ return set_simple_field(
+ &p_ptr->oppose_nex, v,
+ TERM_WHITE, "You feel protected against the strange forces of nexus.",
+ TERM_WHITE, "You are no longer protected against the strange forces of nexus.");
+}
+
+/*
+ * Set "p_ptr->tim_mimic", and "p_ptr->mimic_form",
+ * notice observable changes
+ */
+bool_ set_mimic(int v, int p, int level)
+{
+ bool_ notice = FALSE;
+
+ /* Hack -- Force good values */
+ v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
+
+ /* Open */
+ if (v)
+ {
+ if (!p_ptr->tim_mimic)
+ {
+ msg_print("You feel your body change.");
+ p_ptr->mimic_form = p;
+ notice = TRUE;
+ }
+ }
+
+ /* Shut */
+ else
+ {
+ if (p_ptr->tim_mimic)
+ {
+ msg_print("You are no longer transformed.");
+ p_ptr->mimic_form = 0;
+ notice = TRUE;
+ if (p == resolve_mimic_name("Bear"))
+ {
+ s_info[SKILL_BEAR].hidden = TRUE;
+ select_default_melee();
+ }
+ p = 0;
+ }
+ }
+
+ /* Use the value */
+ p_ptr->tim_mimic = v;
+ p_ptr->mimic_level = level;
+
+ /* Nothing to notice */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0, 0);
+
+ /* Redraw title */
+ p_ptr->redraw |= (PR_TITLE);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BODY | PU_BONUS | PU_SANITY);
+
+ /* Result */
+ return (TRUE);
+}
+
+/*
+ * Set "p_ptr->blind", notice observable changes
+ *
+ * Note the use of "PU_UN_VIEW", which is needed to memorize any terrain
+ * features which suddenly become "visible".
+ * Note that blindness is currently the only thing which can affect
+ * "player_can_see_bold()".
+ */
+bool_ set_blind(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->blind, v,
+ TERM_WHITE, "You are blind!",
+ TERM_WHITE, "You can see again.");
+
+ if (notice)
+ {
+ /* Fully update the visuals */
+ p_ptr->update |= (PU_UN_VIEW | PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Redraw the "blind" */
+ p_ptr->redraw |= (PR_BLIND);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->tim_lite", notice observable changes
+ *
+ * Note the use of "PU_VIEW", which is needed to
+ * memorize any terrain features which suddenly become "visible".
+ * Note that blindness is currently the only thing which can affect
+ * "player_can_see_bold()".
+ */
+bool_ set_lite(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->tim_lite, v,
+ TERM_WHITE, "You suddenly seem brighter!",
+ TERM_WHITE, "You are no longer bright.");
+
+ if (notice)
+ {
+ /* Fully update the visuals */
+ p_ptr->update |= (PU_VIEW | PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->confused", notice observable changes
+ */
+bool_ set_confused(int v)
+{
+ bool_ notice =
+ set_simple_field(
+ &p_ptr->confused, v,
+ TERM_WHITE, "You are confused!",
+ TERM_WHITE, "You feel less confused now.");
+
+ if (notice)
+ {
+ /* Redraw the "confused" */
+ p_ptr->redraw |= (PR_CONFUSED);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->poisoned", notice observable changes
+ */
+bool_ set_poisoned(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->poisoned, v,
+ TERM_WHITE, "You are poisoned!",
+ TERM_WHITE, "You are no longer poisoned.");
+
+ if (notice)
+ {
+ /* Redraw the "poisoned" */
+ p_ptr->redraw |= (PR_POISONED);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->afraid", notice observable changes
+ */
+bool_ set_afraid(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->afraid, v,
+ TERM_WHITE, "You are terrified!",
+ TERM_WHITE, "You feel bolder now.");
+
+ if (notice)
+ {
+ /* Redraw the "afraid" */
+ p_ptr->redraw |= (PR_AFRAID);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->paralyzed", notice observable changes
+ */
+bool_ set_paralyzed(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->paralyzed, v,
+ TERM_WHITE, "You are paralyzed!",
+ TERM_WHITE, "You can move again.");
+
+ if (notice)
+ {
+ /* Redraw the state */
+ p_ptr->redraw |= (PR_STATE);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->image", notice observable changes
+ *
+ * Note that we must redraw the map when hallucination changes.
+ */
+bool_ set_image(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->image, v,
+ TERM_WHITE, "Oh, wow! Everything looks so cosmic now!",
+ TERM_WHITE, "You can see clearly again.");
+
+ if (notice)
+ {
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Update monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD | PW_M_LIST);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->lightspeed", notice observable changes
+ */
+bool_ set_light_speed(int v)
+{
+ bool_ notice =
+ set_simple_field(
+ &p_ptr->lightspeed, v,
+ TERM_WHITE, "You feel as if time has stopped!",
+ TERM_WHITE, "You feel time returning to its normal rate.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+bool_ set_fast(int v, int p)
+{
+ bool_ notice = FALSE;
+
+ /* Hack -- Force good values */
+ v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
+
+ /* Open */
+ if (v)
+ {
+ if (!p_ptr->fast)
+ {
+ msg_print("You feel yourself moving faster!");
+ notice = TRUE;
+ }
+ }
+
+ /* Shut */
+ else
+ {
+ if (p_ptr->fast)
+ {
+ msg_print("You feel yourself slow down.");
+ p = 0;
+ notice = TRUE;
+ }
+ }
+
+ /* Use the value */
+ p_ptr->fast = v;
+ p_ptr->speed_factor = p;
+
+ /* Nothing to notice */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0, 0);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Result */
+ return (TRUE);
+}
+
+
+/*
+ * Set "p_ptr->slow", notice observable changes
+ */
+bool_ set_slow(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->slow, v,
+ TERM_WHITE, "You feel yourself moving slower!",
+ TERM_WHITE, "You feel yourself speed up.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->shield", notice observable changes
+ */
+bool_ set_shield(int v, int p, s16b o, s16b d1, s16b d2)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->shield, v,
+ TERM_WHITE, "A mystic shield forms around your body!",
+ TERM_WHITE, "Your mystic shield crumbles away.");
+
+ /* Use the values */
+ p_ptr->shield_power = p;
+ p_ptr->shield_opt = o;
+ p_ptr->shield_power_opt = d1;
+ p_ptr->shield_power_opt2 = d2;
+
+ /* Notice? */
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+
+/*
+ * Set "p_ptr->blessed", notice observable changes
+ */
+bool_ set_blessed(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->blessed, v,
+ TERM_WHITE, "You feel righteous!",
+ TERM_WHITE, "The prayer has expired.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->hero", notice observable changes
+ */
+bool_ set_hero(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->hero, v,
+ TERM_WHITE, "You feel like a hero!",
+ TERM_WHITE, "The heroism wears off.");
+
+ if (notice)
+ {
+ /* Recalculate hitpoints */
+ p_ptr->update |= (PU_HP);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->holy", notice observable changes
+ */
+bool_ set_holy(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->holy, v,
+ TERM_WHITE, "You feel a holy aura around you!",
+ TERM_WHITE, "The holy aura vanishes.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->walk_water", notice observable changes
+ */
+bool_ set_walk_water(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->walk_water, v,
+ TERM_WHITE, "You feel strangely buoyant!",
+ TERM_WHITE, "You feel much less buoyant.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->shero", notice observable changes
+ */
+bool_ set_shero(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->shero, v,
+ TERM_WHITE, "You feel like a killing machine!",
+ TERM_WHITE, "You feel less berserk.");
+
+ if (notice)
+ {
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Update monsters */
+ p_ptr->update |= (PU_MONSTERS | PU_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->protevil", notice observable changes
+ */
+bool_ set_protevil(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->protevil, v,
+ TERM_WHITE, "You feel safe from evil!",
+ TERM_WHITE, "You no longer feel safe from evil.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->protgood", notice observable changes
+ */
+bool_ set_protgood(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->protgood, v,
+ TERM_WHITE, "You feel safe from good!",
+ TERM_WHITE, "You no longer feel safe from good.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->protundead", notice observable changes
+ */
+bool_ set_protundead(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->protundead, v,
+ TERM_WHITE, "You feel safe from undead!",
+ TERM_WHITE, "You no longer feel safe from undead.");
+
+ if (notice) {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->set_shadow", notice observable changes
+ */
+bool_ set_shadow(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->tim_wraith, v,
+ TERM_WHITE, "You leave the physical world and turn into a wraith-being!",
+ TERM_WHITE, "You feel opaque.");
+
+ if (notice)
+ {
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Update monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+
+
+/*
+ * Set "p_ptr->invuln", notice observable changes
+ */
+bool_ set_invuln(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->invuln, v,
+ TERM_L_BLUE, "Invulnerability!",
+ TERM_L_RED, "The invulnerability wears off.");
+
+ if (notice)
+ {
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Update monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+
+/*
+ * Set "p_ptr->tim_esp", notice observable changes
+ */
+bool_ set_tim_esp(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->tim_esp, v,
+ TERM_WHITE, "You feel your consciousness expand!",
+ TERM_WHITE, "Your consciousness contracts again.");
+
+ if (notice)
+ {
+ /* Update the monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->tim_thunder", notice observable changes
+ */
+bool_ set_tim_thunder(int v, int p1, int p2)
+{
+ bool_ notice = FALSE;
+
+ /* Hack -- Force good values */
+ v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
+
+ /* Open */
+ if (v)
+ {
+ if (!p_ptr->tim_thunder)
+ {
+ msg_print("The air around you charges with lightning!");
+ notice = TRUE;
+ }
+ }
+
+ /* Shut */
+ else
+ {
+ if (p_ptr->tim_thunder)
+ {
+ msg_print("The air around you discharges.");
+ notice = TRUE;
+ p1 = p2 = 0;
+ }
+ }
+
+ /* Use the value */
+ p_ptr->tim_thunder = v;
+ p_ptr->tim_thunder_p1 = p1;
+ p_ptr->tim_thunder_p2 = p2;
+
+ /* Nothing to notice */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0, 0);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Update the monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Result */
+ return (TRUE);
+}
+
+/*
+ * Set "p_ptr->tim_invis", notice observable changes
+ */
+bool_ set_tim_invis(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->tim_invis, v,
+ TERM_WHITE, "Your eyes feel very sensitive!",
+ TERM_WHITE, "Your eyes feel less sensitive.");
+
+ if (notice)
+ {
+ /* Update the monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->tim_infra", notice observable changes
+ */
+bool_ set_tim_infra(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->tim_infra, v,
+ TERM_WHITE, "Your eyes begin to tingle!",
+ TERM_WHITE, "Your eyes stop tingling.");
+
+ if (notice)
+ {
+ /* Update the monsters */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->tim_mental_barrier", notice observable changes
+ */
+bool_ set_mental_barrier(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->tim_mental_barrier, v,
+ TERM_WHITE, "Your mind grows stronger!",
+ TERM_WHITE, "Your mind is no longer especially strong.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+/*
+ * Set "p_ptr->oppose_acid", notice observable changes
+ */
+bool_ set_oppose_acid(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->oppose_acid, v,
+ TERM_WHITE, "You feel resistant to acid!",
+ TERM_WHITE, "You feel less resistant to acid.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->oppose_elec", notice observable changes
+ */
+bool_ set_oppose_elec(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->oppose_elec, v,
+ TERM_WHITE, "You feel resistant to electricity!",
+ TERM_WHITE, "You feel less resistant to electricity.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->oppose_fire", notice observable changes
+ */
+bool_ set_oppose_fire(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->oppose_fire, v,
+ TERM_WHITE, "You feel resistant to fire!",
+ TERM_WHITE, "You feel less resistant to fire.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->oppose_cold", notice observable changes
+ */
+bool_ set_oppose_cold(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->oppose_cold, v,
+ TERM_WHITE, "You feel resistant to cold!",
+ TERM_WHITE, "You feel less resistant to cold.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->oppose_pois", notice observable changes
+ */
+bool_ set_oppose_pois(int v)
+{
+ bool_ notice = set_simple_field(
+ &p_ptr->oppose_pois, v,
+ TERM_WHITE, "You feel resistant to poison!",
+ TERM_WHITE, "You feel less resistant to poison.");
+
+ if (notice)
+ {
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+ /* Result */
+ return notice;
+}
+
+
+/*
+ * Set "p_ptr->tim_regen", notice observable changes
+ */
+bool_ set_tim_regen(int v, int p)
+{
+ bool_ notice = FALSE;
+
+ /* Hack -- Force good values */
+ v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
+
+ /* Open */
+ if (v)
+ {
+ if (!p_ptr->tim_regen)
+ {
+ msg_print("Your body regenerates much more quickly!");
+ notice = TRUE;
+ }
+ }
+
+ /* Shut */
+ else
+ {
+ if (p_ptr->tim_regen)
+ {
+ p = 0;
+ msg_print("Your body regenerates much more slowly.");
+ notice = TRUE;
+ }
+ }
+
+ /* Use the value */
+ p_ptr->tim_regen = v;
+ p_ptr->tim_regen_pow = p;
+
+ /* Nothing to notice */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0, 0);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Result */
+ return (TRUE);
+}
+
+
+/*
+ * Set "p_ptr->stun", notice observable changes
+ *
+ * Note the special code to only notice "range" changes.
+ */
+bool_ set_stun(int v)
+{
+ int old_aux, new_aux;
+ bool_ notice = FALSE;
+
+
+ /* Hack -- Force good values */
+ v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
+
+ if (PRACE_FLAG(PR1_NO_STUN)) v = 0;
+
+ /* Knocked out */
+ if (p_ptr->stun > 100)
+ {
+ old_aux = 3;
+ }
+
+ /* Heavy stun */
+ else if (p_ptr->stun > 50)
+ {
+ old_aux = 2;
+ }
+
+ /* Stun */
+ else if (p_ptr->stun > 0)
+ {
+ old_aux = 1;
+ }
+
+ /* None */
+ else
+ {
+ old_aux = 0;
+ }
+
+ /* Knocked out */
+ if (v > 100)
+ {
+ new_aux = 3;
+ }
+
+ /* Heavy stun */
+ else if (v > 50)
+ {
+ new_aux = 2;
+ }
+
+ /* Stun */
+ else if (v > 0)
+ {
+ new_aux = 1;
+ }
+
+ /* None */
+ else
+ {
+ new_aux = 0;
+ }
+
+ /* Increase cut */
+ if (new_aux > old_aux)
+ {
+ /* Describe the state */
+ switch (new_aux)
+ {
+ /* Stun */
+ case 1:
+ msg_print("You have been stunned.");
+ break;
+
+ /* Heavy stun */
+ case 2:
+ msg_print("You have been heavily stunned.");
+ break;
+
+ /* Knocked out */
+ case 3:
+ msg_print("You have been knocked out.");
+ break;
+ }
+
+ if (randint(1000) < v || randint(16) == 1)
+ {
+
+ msg_print("A vicious blow hits your head.");
+ if (randint(3) == 1)
+ {
+ if (!p_ptr->sustain_int)
+ {
+ (void) do_dec_stat(A_INT, STAT_DEC_NORMAL);
+ }
+ if (!p_ptr->sustain_wis)
+ {
+ (void) do_dec_stat(A_WIS, STAT_DEC_NORMAL);
+ }
+ }
+ else if (randint(2) == 1)
+ {
+ if (!p_ptr->sustain_int)
+ {
+ (void) do_dec_stat(A_INT, STAT_DEC_NORMAL);
+ }
+ }
+ else
+ {
+ if (!p_ptr->sustain_wis)
+ {
+ (void) do_dec_stat(A_WIS, STAT_DEC_NORMAL);
+ }
+ }
+ }
+
+ /* Notice */
+ notice = TRUE;
+ }
+
+ /* Decrease cut */
+ else if (new_aux < old_aux)
+ {
+ /* Describe the state */
+ switch (new_aux)
+ {
+ /* None */
+ case 0:
+ msg_print("You are no longer stunned.");
+ if (disturb_state) disturb(0, 0);
+ break;
+ }
+
+ /* Notice */
+ notice = TRUE;
+ }
+
+ /* Use the value */
+ p_ptr->stun = v;
+
+ /* No change */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0, 0);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw the "stun" */
+ p_ptr->redraw |= (PR_STUN);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Result */
+ return (TRUE);
+}
+
+
+/*
+ * Set "p_ptr->cut", notice observable changes
+ *
+ * Note the special code to only notice "range" changes.
+ */
+bool_ set_cut(int v)
+{
+ int old_aux, new_aux;
+
+ bool_ notice = FALSE;
+
+ /* Hack -- Force good values */
+ v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
+
+ if (PRACE_FLAG(PR1_NO_CUT)) v = 0;
+
+ /* Mortal wound */
+ if (p_ptr->cut > 1000)
+ {
+ old_aux = 7;
+ }
+
+ /* Deep gash */
+ else if (p_ptr->cut > 200)
+ {
+ old_aux = 6;
+ }
+
+ /* Severe cut */
+ else if (p_ptr->cut > 100)
+ {
+ old_aux = 5;
+ }
+
+ /* Nasty cut */
+ else if (p_ptr->cut > 50)
+ {
+ old_aux = 4;
+ }
+
+ /* Bad cut */
+ else if (p_ptr->cut > 25)
+ {
+ old_aux = 3;
+ }
+
+ /* Light cut */
+ else if (p_ptr->cut > 10)
+ {
+ old_aux = 2;
+ }
+
+ /* Graze */
+ else if (p_ptr->cut > 0)
+ {
+ old_aux = 1;
+ }
+
+ /* None */
+ else
+ {
+ old_aux = 0;
+ }
+
+ /* Mortal wound */
+ if (v > 1000)
+ {
+ new_aux = 7;
+ }
+
+ /* Deep gash */
+ else if (v > 200)
+ {
+ new_aux = 6;
+ }
+
+ /* Severe cut */
+ else if (v > 100)
+ {
+ new_aux = 5;
+ }
+
+ /* Nasty cut */
+ else if (v > 50)
+ {
+ new_aux = 4;
+ }
+
+ /* Bad cut */
+ else if (v > 25)
+ {
+ new_aux = 3;
+ }
+
+ /* Light cut */
+ else if (v > 10)
+ {
+ new_aux = 2;
+ }
+
+ /* Graze */
+ else if (v > 0)
+ {
+ new_aux = 1;
+ }
+
+ /* None */
+ else
+ {
+ new_aux = 0;
+ }
+
+ /* Increase cut */
+ if (new_aux > old_aux)
+ {
+ /* Describe the state */
+ switch (new_aux)
+ {
+ /* Graze */
+ case 1:
+ msg_print("You have been given a graze.");
+ break;
+
+ /* Light cut */
+ case 2:
+ msg_print("You have been given a light cut.");
+ break;
+
+ /* Bad cut */
+ case 3:
+ msg_print("You have been given a bad cut.");
+ break;
+
+ /* Nasty cut */
+ case 4:
+ msg_print("You have been given a nasty cut.");
+ break;
+
+ /* Severe cut */
+ case 5:
+ msg_print("You have been given a severe cut.");
+ break;
+
+ /* Deep gash */
+ case 6:
+ msg_print("You have been given a deep gash.");
+ break;
+
+ /* Mortal wound */
+ case 7:
+ msg_print("You have been given a mortal wound.");
+ break;
+ }
+
+ /* Notice */
+ notice = TRUE;
+
+ if (randint(1000) < v || randint(16) == 1)
+ {
+ if (!p_ptr->sustain_chr)
+ {
+ msg_print("You have been horribly scarred.");
+
+ do_dec_stat(A_CHR, STAT_DEC_NORMAL);
+ }
+ }
+ }
+
+ /* Decrease cut */
+ else if (new_aux < old_aux)
+ {
+ /* Describe the state */
+ switch (new_aux)
+ {
+ /* None */
+ case 0:
+ msg_print("You are no longer bleeding.");
+ if (disturb_state) disturb(0, 0);
+ break;
+ }
+
+ /* Notice */
+ notice = TRUE;
+ }
+
+ /* Use the value */
+ p_ptr->cut = v;
+
+ /* No change */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0, 0);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw the "cut" */
+ p_ptr->redraw |= (PR_CUT);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Result */
+ return (TRUE);
+}
+
+void drop_from_wild()
+{
+ /* Hack -- Not if player were in normal mode in previous turn */
+ if (!p_ptr->old_wild_mode) return;
+
+ if (p_ptr->wild_mode && (!dun_level))
+ {
+ p_ptr->wilderness_x = p_ptr->px;
+ p_ptr->wilderness_y = p_ptr->py;
+ change_wild_mode();
+ p_ptr->energy = 100;
+ energy_use = 0;
+ }
+}
+
+/*
+ * Set "p_ptr->food", notice observable changes
+ *
+ * The "p_ptr->food" variable can get as large as 20000, allowing the
+ * addition of the most "filling" item, Elvish Waybread, which adds
+ * 7500 food units, without overflowing the 32767 maximum limit.
+ *
+ * Perhaps we should disturb the player with various messages,
+ * especially messages about hunger status changes. XXX XXX XXX
+ *
+ * Digestion of food is handled in "dungeon.c", in which, normally,
+ * the player digests about 20 food units per 100 game turns, more
+ * when "fast", more when "regenerating", less with "slow digestion",
+ * but when the player is "gorged", he digests 100 food units per 10
+ * game turns, or a full 1000 food units per 100 game turns.
+ *
+ * Note that the player's speed is reduced by 10 units while gorged,
+ * so if the player eats a single food ration (5000 food units) when
+ * full (15000 food units), he will be gorged for (5000/100)*10 = 500
+ * game turns, or 500/(100/5) = 25 player turns (if nothing else is
+ * affecting the player speed).
+ */
+bool_ set_food(int v)
+{
+ int old_aux, new_aux;
+
+ bool_ notice = FALSE;
+
+ /* Hack -- Force good values */
+ v = (v > 20000) ? 20000 : (v < 0) ? 0 : v;
+
+ /* Fainting / Starving */
+ if (p_ptr->food < PY_FOOD_FAINT)
+ {
+ old_aux = 0;
+ }
+
+ /* Weak */
+ else if (p_ptr->food < PY_FOOD_WEAK)
+ {
+ old_aux = 1;
+ }
+
+ /* Hungry */
+ else if (p_ptr->food < PY_FOOD_ALERT)
+ {
+ old_aux = 2;
+ }
+
+ /* Normal */
+ else if (p_ptr->food < PY_FOOD_FULL)
+ {
+ old_aux = 3;
+ }
+
+ /* Full */
+ else if (p_ptr->food < PY_FOOD_MAX)
+ {
+ old_aux = 4;
+ }
+
+ /* Gorged */
+ else
+ {
+ old_aux = 5;
+ }
+
+ /* Fainting / Starving */
+ if (v < PY_FOOD_FAINT)
+ {
+ new_aux = 0;
+ }
+
+ /* Weak */
+ else if (v < PY_FOOD_WEAK)
+ {
+ new_aux = 1;
+ }
+
+ /* Hungry */
+ else if (v < PY_FOOD_ALERT)
+ {
+ new_aux = 2;
+ }
+
+ /* Normal */
+ else if (v < PY_FOOD_FULL)
+ {
+ new_aux = 3;
+ }
+
+ /* Full */
+ else if (v < PY_FOOD_MAX)
+ {
+ new_aux = 4;
+ }
+
+ /* Gorged */
+ else
+ {
+ new_aux = 5;
+ }
+
+ /* Food increase */
+ if (new_aux > old_aux)
+ {
+ /* Describe the state */
+ switch (new_aux)
+ {
+ /* Weak */
+ case 1:
+ msg_print("You are still weak.");
+ break;
+
+ /* Hungry */
+ case 2:
+ msg_print("You are still hungry.");
+ break;
+
+ /* Normal */
+ case 3:
+ msg_print("You are no longer hungry.");
+ break;
+
+ /* Full */
+ case 4:
+ msg_print("You are full!");
+ break;
+
+ /* Bloated */
+ case 5:
+ msg_print("You have gorged yourself!");
+ break;
+ }
+
+ /* Change */
+ notice = TRUE;
+ }
+
+ /* Food decrease */
+ else if (new_aux < old_aux)
+ {
+ /* Describe the state */
+ switch (new_aux)
+ {
+ /* Fainting / Starving */
+ case 0:
+ msg_print("You are getting faint from hunger!");
+ drop_from_wild();
+ break;
+
+ /* Weak */
+ case 1:
+ msg_print("You are getting weak from hunger!");
+ drop_from_wild();
+ break;
+
+ /* Hungry */
+ case 2:
+ msg_print("You are getting hungry.");
+ break;
+
+ /* Normal */
+ case 3:
+ msg_print("You are no longer full.");
+ break;
+
+ /* Full */
+ case 4:
+ msg_print("You are no longer gorged.");
+ break;
+ }
+
+ /* Change */
+ notice = TRUE;
+ }
+
+ /* Use the value */
+ p_ptr->food = v;
+
+ /* Nothing to notice */
+ if (!notice) return (FALSE);
+
+ /* Disturb */
+ if (disturb_state) disturb(0, 0);
+
+ /* Recalculate bonuses */
+ p_ptr->update |= (PU_BONUS);
+
+ /* Redraw hunger */
+ p_ptr->redraw |= (PR_HUNGER);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Result */
+ return (TRUE);
+}
+
+
+/*
+ * Advance experience levels and print experience
+ */
+void check_experience(void)
+{
+ int gained = 0;
+ bool_ level_reward = FALSE;
+ bool_ level_corruption = FALSE;
+
+
+ /* Hack -- lower limit */
+ if (p_ptr->exp < 0) p_ptr->exp = 0;
+
+ /* Hack -- lower limit */
+ if (p_ptr->max_exp < 0) p_ptr->max_exp = 0;
+
+ /* Hack -- upper limit */
+ if (p_ptr->exp > PY_MAX_EXP) p_ptr->exp = PY_MAX_EXP;
+
+ /* Hack -- upper limit */
+ if (p_ptr->max_exp > PY_MAX_EXP) p_ptr->max_exp = PY_MAX_EXP;
+
+ /* Hack -- maintain "max" experience */
+ if (p_ptr->exp > p_ptr->max_exp) p_ptr->max_exp = p_ptr->exp;
+
+ /* Redraw experience */
+ p_ptr->redraw |= (PR_EXP);
+
+ /* Handle stuff */
+ handle_stuff();
+
+
+ /* Lose levels while possible */
+ while ((p_ptr->lev > 1) &&
+ (p_ptr->exp < (player_exp[p_ptr->lev - 2] * p_ptr->expfact / 100L)))
+ {
+ /* Lose a level */
+ p_ptr->lev--;
+ gained--;
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Update some stuff */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_SANITY);
+
+ /* Redraw some stuff */
+ p_ptr->redraw |= (PR_LEV | PR_TITLE | PR_EXP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Handle stuff */
+ handle_stuff();
+ }
+
+
+ /* Gain levels while possible */
+ while ((p_ptr->lev < PY_MAX_LEVEL) && (p_ptr->lev < max_plev) &&
+ (p_ptr->exp >= (player_exp[p_ptr->lev - 1] * p_ptr->expfact / 100L)))
+ {
+ /* Gain a level */
+ p_ptr->lev++;
+ gained++;
+ lite_spot(p_ptr->py, p_ptr->px);
+
+ /* Save the highest level */
+ if (p_ptr->lev > p_ptr->max_plv)
+ {
+ p_ptr->max_plv = p_ptr->lev;
+ if ((PRACE_FLAG(PR1_CORRUPT)) &&
+ (randint(3) == 1))
+ {
+ level_corruption = TRUE;
+ }
+ }
+
+ /* Sound */
+ sound(SOUND_LEVEL);
+
+ /* Message */
+ cmsg_format(TERM_L_GREEN, "Welcome to level %d.", p_ptr->lev);
+
+ if (p_ptr->skill_last_level < p_ptr->lev)
+ {
+ s32b pts;
+ call_lua("exec_module_info", "(s)", "d", "skill_per_level", &pts);
+
+ p_ptr->skill_last_level = p_ptr->lev;
+ p_ptr->skill_points += pts;
+ cmsg_format(TERM_L_GREEN, "You can increase %d more skills.", p_ptr->skill_points);
+ p_ptr->redraw |= PR_STUDY;
+ }
+
+ /* Gain this level's abilities */
+ apply_level_abilities(p_ptr->lev);
+
+ /* If auto-note taking enabled, write a note to the file.
+ * Only write this note when the level is gained for the first
+ * time.
+ */
+ if (take_notes && auto_notes)
+ {
+ char note[80];
+
+ /* Write note */
+ sprintf(note, "Reached level %d", p_ptr->lev);
+ add_note(note, 'L');
+ }
+
+ /* Update some stuff */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_SANITY);
+
+ /* Redraw some stuff */
+ p_ptr->redraw |= (PR_LEV | PR_TITLE | PR_EXP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ if (level_reward)
+ {
+ gain_level_reward(0);
+ level_reward = FALSE;
+ }
+
+ if (level_corruption)
+ {
+ msg_print("You feel different...");
+ corrupt_corrupted();
+ level_corruption = FALSE;
+ }
+ }
+
+ /* Hook it! */
+ process_hooks(HOOK_PLAYER_LEVEL, "(d)", gained);
+}
+/*
+ * Advance experience levels and print experience
+ */
+void check_experience_obj(object_type *o_ptr)
+{
+ /* Hack -- lower limit */
+ if (o_ptr->exp < 0) o_ptr->exp = 0;
+
+ /* Hack -- upper limit */
+ if (o_ptr->exp > PY_MAX_EXP) o_ptr->exp = PY_MAX_EXP;
+
+ /* Gain levels while possible */
+ while ((o_ptr->elevel < PY_MAX_LEVEL) &&
+ (o_ptr->exp >= (player_exp[o_ptr->elevel - 1] * 5 / 2)))
+ {
+ char buf[100];
+
+ /* Add a level */
+ o_ptr->elevel++;
+
+ /* Get object name */
+ object_desc(buf, o_ptr, 1, 0);
+ cmsg_format(TERM_L_BLUE, "%s gains a level!", buf);
+
+ /* What does it gains ? */
+ object_gain_level(o_ptr);
+ }
+}
+
+
+/*
+ * Gain experience (share it to objects if needed)
+ */
+void gain_exp(s32b amount)
+{
+ int i, num = 1;
+
+ /* Count the gaining xp objects */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (!o_ptr->k_idx) continue;
+
+ if (f4 & TR4_ART_EXP) num++;
+ }
+
+ /* Now give the xp */
+ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+ u32b f1, f2, f3, f4, f5, esp;
+
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ if (!o_ptr->k_idx) continue;
+
+ if (f4 & TR4_ART_EXP)
+ {
+ o_ptr->exp += 2 * amount / (num * 3);
+
+ /* Hack -- upper limit */
+ if (o_ptr->exp > PY_MAX_EXP) o_ptr->exp = PY_MAX_EXP;
+ }
+ }
+
+ if ((p_ptr->max_exp > 0) && (PRACE_FLAG(PR1_CORRUPT)))
+ {
+ if ((randint(p_ptr->max_exp) < amount) || (randint(12000000) < amount))
+ {
+ msg_print("You feel different...");
+ corrupt_corrupted();
+ };
+ /* 12,000,000 is equal to double Morgoth's raw XP value (60,000 * his Dlev (100))*/
+ };
+
+ /* Gain some experience */
+ p_ptr->exp += amount / num;
+
+ /* Hook it! */
+ process_hooks(HOOK_PLAYER_EXP, "(d)", amount / num);
+
+ /* Slowly recover from experience drainage */
+ if (p_ptr->exp < p_ptr->max_exp)
+ {
+ /* Gain max experience (20%) (was 10%) */
+ p_ptr->max_exp += amount / 5;
+ }
+
+ /* Check Experience */
+ check_experience();
+}
+
+
+/*
+ * Lose experience
+ */
+void lose_exp(s32b amount)
+{
+ /* Never drop below zero experience */
+ if (amount > p_ptr->exp) amount = p_ptr->exp;
+
+ /* Lose some experience */
+ p_ptr->exp -= amount;
+
+ /* Hook it! */
+ process_hooks(HOOK_PLAYER_EXP, "(d)", amount);
+
+ /* Check Experience */
+ check_experience();
+}
+
+
+
+
+/*
+ * Hack -- Return the "automatic coin type" of a monster race
+ * Used to allocate proper treasure when "Creeping coins" die
+ *
+ * XXX XXX XXX Note the use of actual "monster names"
+ */
+int get_coin_type(monster_race *r_ptr)
+{
+ cptr name = (r_name + r_ptr->name);
+
+ /* Analyze "coin" monsters */
+ if (r_ptr->d_char == '$')
+ {
+ /* Look for textual clues */
+ if (strstr(name, " copper ")) return (2);
+ if (strstr(name, " silver ")) return (5);
+ if (strstr(name, " gold ")) return (10);
+ if (strstr(name, " mithril ")) return (16);
+ if (strstr(name, " adamantite ")) return (17);
+
+ /* Look for textual clues */
+ if (strstr(name, "Copper ")) return (2);
+ if (strstr(name, "Silver ")) return (5);
+ if (strstr(name, "Gold ")) return (10);
+ if (strstr(name, "Mithril ")) return (16);
+ if (strstr(name, "Adamantite ")) return (17);
+ }
+
+ /* Assume nothing */
+ return (0);
+}
+
+/*
+ * This routine handles the production of corpses/skeletons/heads/skulls
+ * when a monster is killed.
+ */
+void place_corpse(monster_type *m_ptr)
+{
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ object_type *i_ptr;
+ object_type object_type_body;
+
+ int x = m_ptr->fx;
+ int y = m_ptr->fy;
+
+ /* Get local object */
+ i_ptr = &object_type_body;
+
+ /* It has a physical form */
+ if (r_ptr->flags9 & RF9_DROP_CORPSE)
+ {
+ /* Wipe the object */
+ object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_CORPSE));
+
+ /* Unique corpses are unique */
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ object_aware(i_ptr);
+ i_ptr->name1 = 201;
+ }
+
+ /* Calculate length of time before decay */
+ i_ptr->pval = r_ptr->weight + rand_int(r_ptr->weight);
+
+ /* Set weight */
+ i_ptr->weight = (r_ptr->weight + rand_int(r_ptr->weight) / 10) + 1;
+
+ /* Remember what we are */
+ i_ptr->pval2 = m_ptr->r_idx;
+
+ /* Some hp */
+ i_ptr->pval3 = ((maxroll(r_ptr->hdice, r_ptr->hside) + p_ptr->mhp) / 2);
+ i_ptr->pval3 -= randint(i_ptr->pval3) / 3;
+
+ i_ptr->found = OBJ_FOUND_MONSTER;
+ i_ptr->found_aux1 = m_ptr->r_idx;
+ i_ptr->found_aux2 = m_ptr->ego;
+ i_ptr->found_aux3 = dungeon_type;
+ i_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ /* Drop it in the dungeon */
+ drop_near(i_ptr, -1, y, x);
+ }
+
+ /* The creature is an animated skeleton. */
+ if (!(r_ptr->flags9 & RF9_DROP_CORPSE) && (r_ptr->flags9 & RF9_DROP_SKELETON))
+ {
+ /* Wipe the object */
+ object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_SKELETON));
+
+ /* Unique corpses are unique */
+ if (r_ptr->flags1 & RF1_UNIQUE)
+ {
+ object_aware(i_ptr);
+ i_ptr->name1 = 201;
+ }
+
+ i_ptr->pval = 0;
+
+ /* Set weight */
+ i_ptr->weight = (r_ptr->weight / 4 + rand_int(r_ptr->weight) / 40) + 1;
+
+ /* Remember what we are */
+ i_ptr->pval2 = m_ptr->r_idx;
+
+ i_ptr->found = OBJ_FOUND_MONSTER;
+ i_ptr->found_aux1 = m_ptr->r_idx;
+ i_ptr->found_aux2 = m_ptr->ego;
+ i_ptr->found_aux3 = dungeon_type;
+ i_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ /* Drop it in the dungeon */
+ drop_near(i_ptr, -1, y, x);
+ }
+
+}
+
+
+/*
+ * Handle the "death" of a monster.
+ *
+ * Disperse treasures centered at the monster location based on the
+ * various flags contained in the monster flags fields.
+ *
+ * Check for "Quest" completion when a quest monster is killed.
+ *
+ * Note that only the player can induce "monster_death()" on Uniques.
+ * Thus (for now) all Quest monsters should be Uniques.
+ *
+ * Note that monsters can now carry objects, and when a monster dies,
+ * it drops all of its objects, which may disappear in crowded rooms.
+ */
+void monster_death(int m_idx)
+{
+ int i, y, x, ny, nx;
+
+ int dump_item = 0;
+ int dump_gold = 0;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ monster_type *m_ptr = &m_list[m_idx];
+
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ bool_ visible = (m_ptr->ml || (r_ptr->flags1 & (RF1_UNIQUE)));
+
+
+ bool_ create_stairs = FALSE;
+ int force_coin = get_coin_type(r_ptr);
+
+ object_type forge;
+ object_type *q_ptr;
+
+ /* Get the location */
+ y = m_ptr->fy;
+ x = m_ptr->fx;
+
+ /* Process the appropriate hooks */
+ process_hooks(HOOK_MONSTER_DEATH, "(d)", m_idx);
+
+ /* If companion dies, take note */
+ if (m_ptr->status == MSTATUS_COMPANION) p_ptr->companion_killed++;
+
+ /* Handle reviving if undead */
+ if ((p_ptr->necro_extra & CLASS_UNDEAD) && p_ptr->necro_extra2)
+ {
+ p_ptr->necro_extra2--;
+
+ if (!p_ptr->necro_extra2)
+ {
+ msg_print("Your death has been avenged -- you return to life.");
+ p_ptr->necro_extra &= ~CLASS_UNDEAD;
+
+ /* Display the hitpoints */
+ p_ptr->update |= (PU_HP);
+ p_ptr->redraw |= (PR_HP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+ }
+ else
+ {
+ msg_format("You still have to kill %d monster%s.", p_ptr->necro_extra2, (p_ptr->necro_extra2 == 1) ? "" : "s");
+ }
+ }
+
+ /* Handle the possibility of player vanquishing arena combatant -KMW- */
+ if (p_ptr->inside_arena)
+ {
+ p_ptr->exit_bldg = TRUE;
+ msg_print("Victorious! You're on your way to becoming Champion.");
+ p_ptr->arena_number++;
+ }
+
+ /* If the doppleganger die, the variable must be set accordingly */
+ if (r_ptr->flags9 & RF9_DOPPLEGANGER) doppleganger = 0;
+
+ /* Drop objects being carried */
+ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Paranoia */
+ o_ptr->held_m_idx = 0;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Copy the object */
+ object_copy(q_ptr, o_ptr);
+
+ /* Delete the object */
+ delete_object_idx(this_o_idx);
+
+ if (q_ptr->tval == TV_GOLD) dump_gold++;
+ else dump_item++;
+
+ /* Drop it */
+ drop_near(q_ptr, -1, y, x);
+ }
+
+ /* Forget objects */
+ m_ptr->hold_o_idx = 0;
+
+ /* Average dungeon and monster levels */
+ object_level = (dun_level + m_ptr->level) / 2;
+
+ /* Mega^2-hack -- destroying the Stormbringer gives it us! */
+ if (strstr((r_name + r_ptr->name), "Stormbringer"))
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Prepare to make the Stormbringer */
+ object_prep(q_ptr, lookup_kind(TV_SWORD, SV_BLADE_OF_CHAOS));
+
+ /* Mega-Hack -- Name the sword */
+
+ q_ptr->art_name = quark_add("'Stormbringer'");
+ q_ptr->to_h = 16;
+ q_ptr->to_d = 16;
+ q_ptr->ds = 6;
+ q_ptr->dd = 6;
+ q_ptr->pval = 2;
+
+ q_ptr->art_flags1 |= ( TR1_VAMPIRIC | TR1_STR | TR1_CON | TR1_BLOWS );
+ q_ptr->art_flags2 |= ( TR2_FREE_ACT | TR2_HOLD_LIFE |
+ TR2_RES_NEXUS | TR2_RES_CHAOS | TR2_RES_NETHER |
+ TR2_RES_CONF ); /* No longer resist_disen */
+ q_ptr->art_flags3 |= ( TR3_IGNORE_ACID | TR3_IGNORE_ELEC |
+ TR3_IGNORE_FIRE | TR3_IGNORE_COLD);
+ /* Just to be sure */
+
+ q_ptr->art_flags3 |= TR3_NO_TELE; /* How's that for a downside? */
+
+ /* For game balance... */
+ q_ptr->art_flags3 |= (TR3_CURSED | TR3_HEAVY_CURSE);
+ q_ptr->ident |= IDENT_CURSED;
+
+ if (randint(2) == 1)
+ q_ptr->art_flags3 |= (TR3_DRAIN_EXP);
+ else
+ q_ptr->art_flags3 |= (TR3_AGGRAVATE);
+
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = m_ptr->r_idx;
+ q_ptr->found_aux2 = m_ptr->ego;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ /* Drop it in the dungeon */
+ drop_near(q_ptr, -1, y, x);
+ }
+
+ /*
+ * Mega^3-hack: killing a 'Warrior of the Dawn' is likely to
+ * spawn another in the fallen one's place!
+ */
+ else if (strstr((r_name + r_ptr->name), "the Dawn"))
+ {
+ if (!(randint(20) == 13))
+ {
+ int wy = p_ptr->py, wx = p_ptr->px;
+ int attempts = 100;
+
+ do
+ {
+ scatter(&wy, &wx, p_ptr->py, p_ptr->px, 20);
+ }
+ while (!(in_bounds(wy, wx) && cave_floor_bold(wy, wx)) && --attempts);
+
+ if (attempts > 0)
+ {
+ if (is_friend(m_ptr) > 0)
+ {
+ if (summon_specific_friendly(wy, wx, 100, SUMMON_DAWN, FALSE))
+ {
+ if (player_can_see_bold(wy, wx))
+ msg_print ("A new warrior steps forth!");
+ }
+ }
+ else
+ {
+ if (summon_specific(wy, wx, 100, SUMMON_DAWN))
+ {
+ if (player_can_see_bold(wy, wx))
+ msg_print ("A new warrior steps forth!");
+ }
+ }
+ }
+ }
+ }
+
+ /* One more ultra-hack: An Unmaker goes out with a big bang! */
+ else if (strstr((r_name + r_ptr->name), "Unmaker"))
+ {
+ int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+ (void)project(m_idx, 6, y, x, 100, GF_CHAOS, flg);
+ }
+ /* Pink horrors are replaced with 2 Blue horrors */
+ else if (strstr((r_name + r_ptr->name), "ink horror"))
+ {
+ for (i = 0; i < 2; i++)
+ {
+ int wy = p_ptr->py, wx = p_ptr->px;
+ int attempts = 100;
+
+ do
+ {
+ scatter(&wy, &wx, p_ptr->py, p_ptr->px, 3);
+ }
+ while (!(in_bounds(wy, wx) && cave_floor_bold(wy, wx)) && --attempts);
+
+ if (attempts > 0)
+ {
+ if (summon_specific(wy, wx, 100, SUMMON_BLUE_HORROR))
+ {
+ if (player_can_see_bold(wy, wx))
+ msg_print ("A blue horror appears!");
+ }
+ }
+ }
+ }
+
+ /* Mega-Hack -- drop "winner" treasures */
+ else if (r_ptr->flags1 & (RF1_DROP_CHOSEN))
+ {
+ if (strstr((r_name + r_ptr->name), "Morgoth, Lord of Darkness"))
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Mega-Hack -- Prepare to make "Grond" */
+ object_prep(q_ptr, lookup_kind(TV_HAFTED, SV_GROND));
+
+ /* Mega-Hack -- Mark this item as "Grond" */
+ q_ptr->name1 = ART_GROND;
+
+ /* Mega-Hack -- Actually create "Grond" */
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+
+ /* Drop it in the dungeon */
+ drop_near(q_ptr, -1, y, x);
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Mega-Hack -- Prepare to make "Morgoth" */
+ object_prep(q_ptr, lookup_kind(TV_CROWN, SV_MORGOTH));
+
+ /* Mega-Hack -- Mark this item as "Morgoth" */
+ q_ptr->name1 = ART_MORGOTH;
+
+ /* Mega-Hack -- Actually create "Morgoth" */
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = m_ptr->r_idx;
+ q_ptr->found_aux2 = m_ptr->ego;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ /* Drop it in the dungeon */
+ drop_near(q_ptr, -1, y, x);
+ }
+ else if (strstr((r_name + r_ptr->name), "Smeagol"))
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ object_wipe(q_ptr);
+
+ /* Mega-Hack -- Prepare to make a ring of invisibility */
+ object_prep(q_ptr, lookup_kind(TV_RING, SV_RING_INVIS));
+ q_ptr->number = 1;
+
+ apply_magic(q_ptr, -1, TRUE, TRUE, FALSE);
+
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = m_ptr->r_idx;
+ q_ptr->found_aux2 = m_ptr->ego;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ /* Drop it in the dungeon */
+ drop_near(q_ptr, -1, y, x);
+ }
+ else if (r_ptr->flags7 & RF7_NAZGUL)
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ object_wipe(q_ptr);
+
+ /* Mega-Hack -- Prepare to make a Ring of Power */
+ object_prep(q_ptr, lookup_kind(TV_RING, SV_RING_SPECIAL));
+ q_ptr->number = 1;
+
+ apply_magic(q_ptr, -1, TRUE, TRUE, FALSE);
+
+ /* Create a random artifact */
+ create_artifact(q_ptr, TRUE, FALSE);
+
+ /* Save the inscription */
+ q_ptr->art_name = quark_add(format("of %s", r_name + r_ptr->name));
+
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = m_ptr->r_idx;
+ q_ptr->found_aux2 = m_ptr->ego;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ /* Drop it in the dungeon */
+ drop_near(q_ptr, -1, y, x);
+ }
+ else
+ {
+ byte a_idx = 0;
+ int chance = 0;
+ int I_kind = 0;
+
+ if (strstr((r_name + r_ptr->name), "Marda, rider of the Gold Laronth"))
+ {
+ a_idx = ART_MARDA;
+ chance = 50;
+ }
+ else if (strstr((r_name + r_ptr->name), "Saruman of Many Colours"))
+ {
+ a_idx = ART_PALANTIR;
+ chance = 30;
+ }
+ else if (strstr((r_name + r_ptr->name), "Hagen, son of Alberich"))
+ {
+ a_idx = ART_NIMLOTH;
+ chance = 66;
+ }
+ else if (strstr((r_name + r_ptr->name), "Durin's Bane"))
+ {
+ a_idx = ART_CALRIS;
+ chance = 60;
+ }
+ else if (strstr((r_name + r_ptr->name), "Gothmog, the High Captain of Balrogs"))
+ {
+ a_idx = ART_GOTHMOG;
+ chance = 50;
+ }
+ else if (strstr((r_name + r_ptr->name), "Eol, the Dark Elf"))
+ {
+ a_idx = ART_ANGUIREL;
+ chance = 50;
+ }
+
+ if ((a_idx > 0) && ((randint(99) < chance) || (wizard)))
+ {
+ if (a_info[a_idx].cur_num == 0)
+ {
+ artifact_type *a_ptr = &a_info[a_idx];
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Acquire the "kind" index */
+ I_kind = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Create the artifact */
+ object_prep(q_ptr, I_kind);
+
+ /* Save the name */
+ q_ptr->name1 = a_idx;
+
+ /* Extract the fields */
+ q_ptr->pval = a_ptr->pval;
+ q_ptr->ac = a_ptr->ac;
+ q_ptr->dd = a_ptr->dd;
+ q_ptr->ds = a_ptr->ds;
+ q_ptr->to_a = a_ptr->to_a;
+ q_ptr->to_h = a_ptr->to_h;
+ q_ptr->to_d = a_ptr->to_d;
+ q_ptr->weight = a_ptr->weight;
+
+ /* Hack -- acquire "cursed" flag */
+ if (a_ptr->flags3 & (TR3_CURSED)) q_ptr->ident |= (IDENT_CURSED);
+
+ random_artifact_resistance(q_ptr);
+
+ a_info[a_idx].cur_num = 1;
+
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = m_ptr->r_idx;
+ q_ptr->found_aux2 = m_ptr->ego;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ /* Drop the artifact from heaven */
+ drop_near(q_ptr, -1, y, x);
+ }
+ }
+ }
+ }
+
+ /* Hack - the protected monsters must be advanged */
+ else if (r_ptr->flags9 & RF9_WYRM_PROTECT)
+ {
+ int xx = x, yy = y;
+ int attempts = 100;
+
+ cmsg_print(TERM_VIOLET, "This monster was under the protection of a Great Wyrm of Power!");
+
+ do
+ {
+ scatter(&yy, &xx, y, x, 6);
+ }
+ while (!(in_bounds(yy, xx) && cave_floor_bold(yy, xx)) && --attempts);
+
+ place_monster_aux(yy, xx, test_monster_name("Great Wyrm of Power"), FALSE, FALSE, m_ptr->status);
+ }
+
+ /* Let monsters explode! */
+ for (i = 0; i < 4; i++)
+ {
+ if (m_ptr->blow[i].method == RBM_EXPLODE)
+ {
+ int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+ int typ = GF_MISSILE;
+ int d_dice = m_ptr->blow[i].d_dice;
+ int d_side = m_ptr->blow[i].d_side;
+ int damage = damroll(d_dice, d_side);
+
+ switch (m_ptr->blow[i].effect)
+ {
+ case RBE_HURT:
+ typ = GF_MISSILE;
+ break;
+ case RBE_POISON:
+ typ = GF_POIS;
+ break;
+ case RBE_UN_BONUS:
+ typ = GF_DISENCHANT;
+ break;
+ case RBE_UN_POWER:
+ typ = GF_MISSILE;
+ break; /* ToDo: Apply the correct effects */
+ case RBE_EAT_GOLD:
+ typ = GF_MISSILE;
+ break;
+ case RBE_EAT_ITEM:
+ typ = GF_MISSILE;
+ break;
+ case RBE_EAT_FOOD:
+ typ = GF_MISSILE;
+ break;
+ case RBE_EAT_LITE:
+ typ = GF_MISSILE;
+ break;
+ case RBE_ACID:
+ typ = GF_ACID;
+ break;
+ case RBE_ELEC:
+ typ = GF_ELEC;
+ break;
+ case RBE_FIRE:
+ typ = GF_FIRE;
+ break;
+ case RBE_COLD:
+ typ = GF_COLD;
+ break;
+ case RBE_BLIND:
+ typ = GF_MISSILE;
+ break;
+ case RBE_HALLU:
+ typ = GF_CONFUSION;
+ break;
+ case RBE_CONFUSE:
+ typ = GF_CONFUSION;
+ break;
+ case RBE_TERRIFY:
+ typ = GF_MISSILE;
+ break;
+ case RBE_PARALYZE:
+ typ = GF_MISSILE;
+ break;
+ case RBE_LOSE_STR:
+ typ = GF_MISSILE;
+ break;
+ case RBE_LOSE_DEX:
+ typ = GF_MISSILE;
+ break;
+ case RBE_LOSE_CON:
+ typ = GF_MISSILE;
+ break;
+ case RBE_LOSE_INT:
+ typ = GF_MISSILE;
+ break;
+ case RBE_LOSE_WIS:
+ typ = GF_MISSILE;
+ break;
+ case RBE_LOSE_CHR:
+ typ = GF_MISSILE;
+ break;
+ case RBE_LOSE_ALL:
+ typ = GF_MISSILE;
+ break;
+ case RBE_PARASITE:
+ typ = GF_MISSILE;
+ break;
+ case RBE_SHATTER:
+ typ = GF_ROCKET;
+ break;
+ case RBE_EXP_10:
+ typ = GF_MISSILE;
+ break;
+ case RBE_EXP_20:
+ typ = GF_MISSILE;
+ break;
+ case RBE_EXP_40:
+ typ = GF_MISSILE;
+ break;
+ case RBE_EXP_80:
+ typ = GF_MISSILE;
+ break;
+ case RBE_DISEASE:
+ typ = GF_POIS;
+ break;
+ case RBE_TIME:
+ typ = GF_TIME;
+ break;
+ case RBE_SANITY:
+ typ = GF_MISSILE;
+ break;
+ }
+
+ project(m_idx, 3, y, x, damage, typ, flg);
+ break;
+ }
+ }
+
+ if ((!force_coin) && (magik(10 + get_skill_scale(SKILL_PRESERVATION, 75))) && (!(m_ptr->mflag & MFLAG_NO_DROP)))
+ place_corpse(m_ptr);
+
+ /* Take note of any dropped treasure */
+ if (visible && (dump_item || dump_gold))
+ {
+ /* Take notes on treasure */
+ lore_treasure(m_idx, dump_item, dump_gold);
+ }
+
+ /* Current quest */
+ i = p_ptr->inside_quest;
+
+ /* Create a magical staircase */
+ if (create_stairs && (dun_level < d_info[dungeon_type].maxdepth))
+ {
+ int i, j;
+
+ for (i = -1; i <= 1; i++)
+ for (j = -1; j <= 1; j++)
+ if (!(f_info[cave[y + j][x + i].feat].flags1 & FF1_PERMANENT)) cave_set_feat(y + j, x + i, d_info[dungeon_type].floor1);
+
+ /* Stagger around */
+ while (!cave_valid_bold(y, x))
+ {
+ int d = 1;
+
+ /* Pick a location */
+ scatter(&ny, &nx, y, x, d);
+
+ /* Stagger */
+ y = ny;
+ x = nx;
+ }
+
+ /* Destroy any objects */
+ delete_object(y, x);
+
+ /* Explain the staircase */
+ msg_print("A magical staircase appears...");
+
+ /* Create stairs down */
+ cave_set_feat(y, x, FEAT_MORE);
+
+ /* Remember to update everything */
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS);
+ }
+}
+
+
+
+
+/*
+ * Decreases monsters hit points, handling monster death.
+ *
+ * We return TRUE if the monster has been killed (and deleted).
+ *
+ * We announce monster death (using an optional "death message"
+ * if given, and a otherwise a generic killed/destroyed message).
+ *
+ * Only "physical attacks" can induce the "You have slain" message.
+ * Missile and Spell attacks will induce the "dies" message, or
+ * various "specialized" messages. Note that "You have destroyed"
+ * and "is destroyed" are synonyms for "You have slain" and "dies".
+ *
+ * Hack -- unseen monsters yield "You have killed it." message.
+ *
+ * Added fear (DGK) and check whether to print fear messages -CWS
+ *
+ * Genericized name, sex, and capitilization -BEN-
+ *
+ * Hack -- we "delay" fear messages by passing around a "fear" flag.
+ *
+ * XXX XXX XXX Consider decreasing monster experience over time, say,
+ * by using "(m_exp * m_lev * (m_lev)) / (p_lev * (m_lev + n_killed))"
+ * instead of simply "(m_exp * m_lev) / (p_lev)", to make the first
+ * monster worth more than subsequent monsters. This would also need
+ * to induce changes in the monster recall code.
+ */
+bool_ mon_take_hit(int m_idx, int dam, bool_ *fear, cptr note)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+ s32b div, new_exp, new_exp_frac;
+
+
+ /* Redraw (later) if needed */
+ if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
+
+ /* Some mosnters are immune to death */
+ if (r_ptr->flags7 & RF7_NO_DEATH) return FALSE;
+
+ /* Wake it up */
+ m_ptr->csleep = 0;
+
+ /* Hurt it */
+ m_ptr->hp -= dam;
+
+ /* It is dead now */
+ if (m_ptr->hp < 0)
+ {
+ char m_name[80];
+
+ /* Lets face it, you cannot get rid of a possessor that easily */
+ if (m_ptr->possessor)
+ {
+ ai_deincarnate(m_idx);
+
+ return FALSE;
+ }
+
+ /* Extract monster name */
+ monster_desc(m_name, m_ptr, 0);
+
+ if ((r_ptr->flags7 & RF7_DG_CURSE) && (randint(2) == 1))
+ {
+ int curses = 2 + randint(5);
+
+ cmsg_format(TERM_VIOLET, "%^s puts a terrible Morgothian curse on you!", m_name);
+ curse_equipment_dg(100, 50);
+
+ do
+ {
+ activate_dg_curse();
+ }
+ while (--curses);
+ }
+
+ if (speak_unique && (r_ptr->flags2 & (RF2_CAN_SPEAK)))
+ {
+ char line_got[80];
+ /* Dump a message */
+
+ get_rnd_line("mondeath.txt", line_got);
+ msg_format("%^s says: %s", m_name, line_got);
+ }
+
+
+ /* Make a sound */
+ sound(SOUND_KILL);
+
+ /* Death by Missile/Spell attack */
+ if (note)
+ {
+ cmsg_format(TERM_L_RED, "%^s%s", m_name, note);
+ }
+
+ /* Death by physical attack -- invisible monster */
+ else if (!m_ptr->ml)
+ {
+ cmsg_format(TERM_L_RED, "You have killed %s.", m_name);
+ }
+
+ /* Death by Physical attack -- non-living monster */
+ else if ((r_ptr->flags3 & (RF3_DEMON)) ||
+ (r_ptr->flags3 & (RF3_UNDEAD)) ||
+ (r_ptr->flags2 & (RF2_STUPID)) ||
+ (r_ptr->flags3 & (RF3_NONLIVING)) ||
+ (strchr("Evg", r_ptr->d_char)))
+ {
+ cmsg_format(TERM_L_RED, "You have destroyed %s.", m_name);
+ }
+
+ /* Death by Physical attack -- living monster */
+ else
+ {
+ cmsg_format(TERM_L_RED, "You have slain %s.", m_name);
+ }
+
+ /* Maximum player level */
+ div = p_ptr->max_plv;
+
+ if (m_ptr->status < MSTATUS_FRIEND)
+ {
+ /* Give some experience for the kill */
+ new_exp = ((long)r_ptr->mexp * m_ptr->level) / div;
+
+ /* Handle fractional experience */
+ new_exp_frac = ((((long)r_ptr->mexp * m_ptr->level) % div)
+ * 0x10000L / div) + p_ptr->exp_frac;
+
+ /* Keep track of experience */
+ if (new_exp_frac >= 0x10000L)
+ {
+ new_exp++;
+ p_ptr->exp_frac = new_exp_frac - 0x10000L;
+ }
+ else
+ {
+ p_ptr->exp_frac = new_exp_frac;
+ }
+
+ /* Gain experience */
+ gain_exp(new_exp);
+ }
+
+ if (!note)
+ {
+ object_type *o_ptr;
+ u32b f1, f2, f3, f4, f5, esp;
+
+ /* Access the weapon */
+ o_ptr = &p_ptr->inventory[INVEN_WIELD];
+ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
+
+ /* Can the weapon gain levels ? */
+ if ((o_ptr->k_idx) && (f4 & TR4_LEVELS))
+ {
+ /* Give some experience for the kill */
+ new_exp = ((long)r_ptr->mexp * m_ptr->level) / (div * 2);
+
+ /* Gain experience */
+ o_ptr->exp += new_exp;
+ check_experience_obj(o_ptr);
+ }
+ }
+
+ /* When the player kills a Unique, it stays dead */
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ r_ptr->max_num = 0;
+ }
+
+ /* Generate treasure */
+ monster_death(m_idx);
+
+ /* Eru doesn't appreciate good monster death */
+ if (r_ptr->flags3 & RF3_GOOD)
+ {
+ inc_piety(GOD_ERU, -7 * m_ptr->level);
+ inc_piety(GOD_MANWE, -10 * m_ptr->level);
+ inc_piety(GOD_MELKOR, 3 * m_ptr->level);
+ }
+ else
+ {
+ inc_piety(GOD_MELKOR, 1 + m_ptr->level / 2);
+ }
+
+ /* Manwe appreciate evil monster death */
+ if (r_ptr->flags3 & RF3_EVIL)
+ {
+ int inc = m_ptr->level / 2;
+
+ if (!inc) inc = 1;
+ PRAY_GOD(GOD_MANWE) inc_piety(GOD_MANWE, inc);
+
+ if (inc < 2) inc = 2;
+ inc_piety(GOD_TULKAS, inc / 2);
+ PRAY_GOD(GOD_TULKAS)
+ {
+ inc_piety(GOD_TULKAS, inc / 2);
+ if (r_ptr->flags3 & RF3_DEMON) inc_piety(GOD_TULKAS, inc);
+ }
+ }
+
+ /* Yavanna likes when corruption is destroyed */
+ if ((r_ptr->flags3 & RF3_NONLIVING) || (r_ptr->flags3 & RF3_DEMON) || (r_ptr->flags3 & RF3_UNDEAD))
+ {
+ int inc = m_ptr->level / 2;
+
+ if (!inc) inc = 1;
+ inc_piety(GOD_YAVANNA, inc);
+ }
+
+ /* Yavanna doesnt like any killing in her name */
+ PRAY_GOD(GOD_YAVANNA)
+ {
+ int inc = m_ptr->level / 2;
+
+ if (!inc) inc = 1;
+ inc_piety(GOD_YAVANNA, -inc);
+
+ /* Killing animals in her name is a VERY bad idea */
+ if (r_ptr->flags3 & RF3_ANIMAL)
+ inc_piety(GOD_YAVANNA, -(inc * 3));
+ }
+
+ /* SHould we absorb its soul? */
+ if (p_ptr->absorb_soul && (!(r_ptr->flags3 & RF3_UNDEAD)) && (!(r_ptr->flags3 & RF3_NONLIVING)))
+ {
+ msg_print("You absorb the life of the dying soul.");
+ hp_player(1 + (m_ptr->level / 2) + get_skill_scale(SKILL_NECROMANCY, 40));
+ }
+
+ /*
+ * XXX XXX XXX Mega-Hack -- Remove random quest rendered
+ * impossible
+ */
+ if (r_ptr->flags1 & (RF1_UNIQUE))
+ {
+ int i;
+
+ /* Search for all the random quests */
+ for (i = 0; i < MAX_RANDOM_QUEST; i++)
+ {
+ random_quest *q_ptr = &random_quests[i];
+
+ /* Ignore invalid entries */
+ if (q_ptr->type == 0) continue;
+
+ /* It's done */
+ if (q_ptr->done) continue;
+
+ /*
+ * XXX XXX XXX Not yet completed quest is
+ * to kill a unique you've just killed
+ */
+ if (r_ptr == &r_info[q_ptr->r_idx])
+ {
+ /* Invalidate it */
+ q_ptr->type = 0;
+ }
+ }
+ }
+
+ /* If the player kills a Unique, and the notes options are on, write a note */
+ if ((r_ptr->flags1 & RF1_UNIQUE) && take_notes && auto_notes)
+ {
+ char note[80];
+
+ /* Get true name even if blinded/hallucinating */
+ cptr monst = (r_name + r_ptr->name);
+
+ /* Write note */
+ sprintf(note, "Killed %s", monst);
+
+ add_note(note, 'U');
+ }
+
+ /* Recall even invisible uniques or winners */
+ if (m_ptr->ml || (r_ptr->flags1 & (RF1_UNIQUE)))
+ {
+ /* Count kills this life */
+ if (r_ptr->r_pkills < MAX_SHORT) r_ptr->r_pkills++;
+
+ /* Count kills in all lives */
+ if (r_ptr->r_tkills < MAX_SHORT) r_ptr->r_tkills++;
+
+ /* Hack -- Auto-recall */
+ monster_race_track(m_ptr->r_idx, m_ptr->ego);
+ }
+
+ /* Delete the monster */
+ delete_monster_idx(m_idx);
+
+ /* Not afraid */
+ (*fear) = FALSE;
+
+ /* Monster is dead */
+ return (TRUE);
+ }
+
+
+#ifdef ALLOW_FEAR
+
+ /* Mega-Hack -- Pain cancels fear */
+ if (m_ptr->monfear && (dam > 0))
+ {
+ int tmp = randint(dam);
+
+ /* Cure a little fear */
+ if (tmp < m_ptr->monfear)
+ {
+ /* Reduce fear */
+ m_ptr->monfear -= tmp;
+ }
+
+ /* Cure all the fear */
+ else
+ {
+ /* Cure fear */
+ m_ptr->monfear = 0;
+
+ /* No more fear */
+ (*fear) = FALSE;
+ }
+ }
+
+ /* Sometimes a monster gets scared by damage */
+ if (!m_ptr->monfear && !(r_ptr->flags3 & (RF3_NO_FEAR)))
+ {
+ int percentage;
+
+ /* Percentage of fully healthy */
+ percentage = (100L * m_ptr->hp) / m_ptr->maxhp;
+
+ /*
+ * Run (sometimes) if at 10% or less of max hit points,
+ * or (usually) when hit for half its current hit points
+ */
+ if (((percentage <= 10) && (rand_int(10) < percentage)) ||
+ ((dam >= m_ptr->hp) && (rand_int(100) < 80)))
+ {
+ /* Hack -- note fear */
+ (*fear) = TRUE;
+
+ /* XXX XXX XXX Hack -- Add some timed fear */
+ m_ptr->monfear = (randint(10) +
+ (((dam >= m_ptr->hp) && (percentage > 7)) ?
+ 20 : ((11 - percentage) * 5)));
+ }
+ }
+
+#endif
+
+
+ /* Not dead yet */
+ return (FALSE);
+}
+
+
+/*
+ * Get term size and calculate screen size
+ */
+void get_screen_size(int *wid_p, int *hgt_p)
+{
+ Term_get_size(wid_p, hgt_p);
+ *hgt_p -= ROW_MAP + 1;
+ *wid_p -= COL_MAP + 1;
+ if (use_bigtile) *wid_p /= 2;
+}
+
+/*
+ * Calculates current boundaries
+ * Called below.
+ */
+static void panel_bounds(void)
+{
+ int wid, hgt;
+
+ /* Retrieve current screen size */
+ get_screen_size(&wid, &hgt);
+
+ /* + 24 - 1 - 2 = + 21 */
+ panel_row_max = panel_row_min + hgt - 1;
+ panel_row_prt = panel_row_min - ROW_MAP;
+
+ /* Paranoia -- Boundary check */
+ if (panel_row_max > cur_hgt - 1) panel_row_max = cur_hgt - 1;
+
+ panel_col_max = panel_col_min + wid - 1;
+ panel_col_prt = panel_col_min - COL_MAP;
+
+ /* Paranoia -- Boundary check */
+ if (panel_col_max > cur_wid - 1) panel_col_max = cur_wid - 1;
+}
+
+
+/*
+ * Handle a request to change the current panel
+ *
+ * Return TRUE if the panel was changed.
+ *
+ * Also used in do_cmd_locate()
+ */
+bool_ change_panel(int dy, int dx)
+{
+ int y, x;
+ int wid, hgt;
+
+ /* Get size */
+ get_screen_size(&wid, &hgt);
+
+ /* Apply the motion */
+ y = panel_row_min + dy * (hgt / 2);
+ x = panel_col_min + dx * (wid / 2);
+
+ /* Calculate bounds */
+ if (y > cur_hgt - hgt) y = cur_hgt - hgt;
+ if (y < 0) y = 0;
+ if (x > cur_wid - wid) x = cur_wid - wid;
+ if (x < 0) x = 0;
+
+ /* Handle changes */
+ if ((y != panel_row_min) || (x != panel_col_min))
+ {
+ /* Save the new panel info */
+ panel_row_min = y;
+ panel_col_min = x;
+
+ /* Recalculate the boundaries */
+ panel_bounds();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Success */
+ return (TRUE);
+ }
+
+ /* No changes */
+ return (FALSE);
+}
+
+
+/*
+ * Given an row (y) and col (x), this routine detects when a move
+ * off the screen has occurred and figures new borders. -RAK-
+ *
+ * "Update" forces a "full update" to take place.
+ *
+ * The map is reprinted if necessary, and "TRUE" is returned.
+ */
+void verify_panel(void)
+{
+ int y = p_ptr->py;
+ int x = p_ptr->px;
+
+ int wid, hgt;
+
+ int prow_min;
+ int pcol_min;
+
+ int panel_hgt, panel_wid;
+
+ int max_prow_min;
+ int max_pcol_min;
+
+
+ /*
+ * Make sure panel_row/col_max have correct values -- now taken care of
+ * by the hook function below, which eliminates glitches, but does it
+ * in a very hackish way XXX XXX XXX
+ */
+ /* panel_bounds(); */
+
+ /* Get size */
+ get_screen_size(&wid, &hgt);
+
+ /* Calculate scroll amount */
+ panel_hgt = hgt / 2;
+ panel_wid = wid / 2;
+
+ /* Upper boundary of panel_row/col_min */
+ max_prow_min = cur_hgt - hgt;
+ max_pcol_min = cur_wid - wid;
+
+ /* Boundary check */
+ if (max_prow_min < 0) max_prow_min = 0;
+ if (max_pcol_min < 0) max_pcol_min = 0;
+
+ /* An option: center on player */
+ if (center_player)
+ {
+ /* Center vertically */
+ prow_min = y - panel_hgt;
+
+ /* Boundary check */
+ if (prow_min < 0) prow_min = 0;
+ else if (prow_min > max_prow_min) prow_min = max_prow_min;
+
+ /* Center horizontally */
+ pcol_min = x - panel_wid;
+
+ /* Boundary check */
+ if (pcol_min < 0) pcol_min = 0;
+ else if (pcol_min > max_pcol_min) pcol_min = max_pcol_min;
+ }
+
+ /* No centering */
+ else
+ {
+ prow_min = panel_row_min;
+ pcol_min = panel_col_min;
+
+ /* Scroll screen when 2 grids from top/bottom edge */
+ if (y > panel_row_max - 2)
+ {
+ while (y > prow_min + hgt - 2)
+ {
+ prow_min += panel_hgt;
+ }
+
+ if (prow_min > max_prow_min) prow_min = max_prow_min;
+ }
+
+ if (y < panel_row_min + 2)
+ {
+ while (y < prow_min + 2)
+ {
+ prow_min -= panel_hgt;
+ }
+
+ if (prow_min < 0) prow_min = 0;
+ }
+
+ /* Scroll screen when 4 grids from left/right edge */
+ if (x > panel_col_max - 4)
+ {
+ while (x > pcol_min + wid - 4)
+ {
+ pcol_min += panel_wid;
+ }
+
+ if (pcol_min > max_pcol_min) pcol_min = max_pcol_min;
+ }
+
+ if (x < panel_col_min + 4)
+ {
+ while (x < pcol_min + 4)
+ {
+ pcol_min -= panel_wid;
+ }
+
+ if (pcol_min < 0) pcol_min = 0;
+ }
+ }
+
+ /* Check for "no change" */
+ if ((prow_min == panel_row_min) && (pcol_min == panel_col_min)) return;
+
+ /* Save the new panel info */
+ panel_row_min = prow_min;
+ panel_col_min = pcol_min;
+
+ /* Hack -- optional disturb on "panel change" */
+ if (disturb_panel && !center_player) disturb(0, 0);
+
+ /* Recalculate the boundaries */
+ panel_bounds();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+}
+
+
+/*
+ * Map resizing whenever the main term changes size
+ */
+void resize_map(void)
+{
+ /* Only if the dungeon exists */
+ if (!character_dungeon) return;
+
+ /* Mega-Hack -- No panel yet, assume illegal panel */
+ panel_row_min = cur_hgt;
+ panel_row_max = 0;
+ panel_col_min = cur_wid;
+ panel_col_max = 0;
+
+ /* Select player panel */
+ verify_panel();
+
+ /*
+ * The following should be the same as the main window code
+ * in the do_cmd_redraw()
+ */
+
+ /* Combine and reorder the pack (later) */
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+
+ /* Update torch */
+ p_ptr->update |= (PU_TORCH);
+
+ /* Update stuff */
+ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_POWERS |
+ PU_SANITY | PU_BODY);
+
+ /* Forget and update view */
+ p_ptr->update |= (PU_UN_VIEW | PU_VIEW | PU_MONSTERS | PU_MON_LITE);
+
+ /* Redraw everything */
+ p_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP);
+
+ /* Hack -- update */
+ handle_stuff();
+
+ /* Redraw */
+ Term_redraw();
+
+ /* Refresh */
+ Term_fresh();
+}
+
+
+/*
+ * Redraw a term when it is resized
+ */
+void resize_window(void)
+{
+ /* Only if the dungeon exists */
+ if (!character_dungeon) return;
+
+ /* Hack -- Activate the Angband window for the redraw */
+ Term_activate(&term_screen[0]);
+
+ /* Hack -- react to changes */
+ Term_xtra(TERM_XTRA_REACT, 0);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_M_LIST | PW_MESSAGE | PW_OVERHEAD |
+ PW_MONSTER | PW_OBJECT);
+
+
+ /* Hack -- update */
+ handle_stuff();
+
+ /* Refresh */
+ Term_fresh();
+}
+
+
+
+
+/*
+ * Monster health description
+ */
+cptr look_mon_desc(int m_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ bool_ living = TRUE;
+ int perc;
+
+
+ /* Determine if the monster is "living" (vs "undead") */
+ if (r_ptr->flags3 & (RF3_UNDEAD)) living = FALSE;
+ if (r_ptr->flags3 & (RF3_DEMON)) living = FALSE;
+ if (r_ptr->flags3 & (RF3_NONLIVING)) living = FALSE;
+ if (strchr("Egv", r_ptr->d_char)) living = FALSE;
+
+
+ /* Healthy monsters */
+ if (m_ptr->hp >= m_ptr->maxhp)
+ {
+ /* No damage */
+ return (living ? "unhurt" : "undamaged");
+ }
+
+
+ /* Calculate a health "percentage" */
+ perc = 100L * m_ptr->hp / m_ptr->maxhp;
+
+ if (perc >= 60)
+ {
+ return (living ? "somewhat wounded" : "somewhat damaged");
+ }
+
+ if (perc >= 25)
+ {
+ return (living ? "wounded" : "damaged");
+ }
+
+ if (perc >= 10)
+ {
+ return (living ? "badly wounded" : "badly damaged");
+ }
+
+ return (living ? "almost dead" : "almost destroyed");
+}
+
+
+
+/*
+ * Angband sorting algorithm -- quick sort in place
+ *
+ * Note that the details of the data we are sorting is hidden,
+ * and we rely on the "ang_sort_comp()" and "ang_sort_swap()"
+ * function hooks to interact with the data, which is given as
+ * two pointers, and which may have any user-defined form.
+ */
+void ang_sort_aux(vptr u, vptr v, int p, int q)
+{
+ int z, a, b;
+
+ /* Done sort */
+ if (p >= q) return;
+
+ /* Pivot */
+ z = p;
+
+ /* Begin */
+ a = p;
+ b = q;
+
+ /* Partition */
+ while (TRUE)
+ {
+ /* Slide i2 */
+ while (!(*ang_sort_comp)(u, v, b, z)) b--;
+
+ /* Slide i1 */
+ while (!(*ang_sort_comp)(u, v, z, a)) a++;
+
+ /* Done partition */
+ if (a >= b) break;
+
+ /* Swap */
+ (*ang_sort_swap)(u, v, a, b);
+
+ /* Advance */
+ a++, b--;
+ }
+
+ /* Recurse left side */
+ ang_sort_aux(u, v, p, b);
+
+ /* Recurse right side */
+ ang_sort_aux(u, v, b + 1, q);
+}
+
+
+/*
+ * Angband sorting algorithm -- quick sort in place
+ *
+ * Note that the details of the data we are sorting is hidden,
+ * and we rely on the "ang_sort_comp()" and "ang_sort_swap()"
+ * function hooks to interact with the data, which is given as
+ * two pointers, and which may have any user-defined form.
+ */
+void ang_sort(vptr u, vptr v, int n)
+{
+ /* Sort the array */
+ ang_sort_aux(u, v, 0, n - 1);
+}
+
+
+
+/*** Targetting Code ***/
+
+
+/*
+ * Determine is a monster makes a reasonable target
+ *
+ * The concept of "targetting" was stolen from "Morgul" (?)
+ *
+ * The player can target any location, or any "target-able" monster.
+ *
+ * Currently, a monster is "target_able" if it is visible, and if
+ * the player can hit it with a projection, and the player is not
+ * hallucinating. This allows use of "use closest target" macros.
+ *
+ * Future versions may restrict the ability to target "trappers"
+ * and "mimics", but the semantics is a little bit weird.
+ */
+bool_ target_able(int m_idx)
+{
+ monster_type *m_ptr = &m_list[m_idx];
+
+ /* Monster must be alive */
+ if (!m_ptr->r_idx) return (FALSE);
+
+ /* Monster must be visible */
+ if (!m_ptr->ml) return (FALSE);
+
+ /* Monster must be projectable */
+ if (!projectable(p_ptr->py, p_ptr->px, m_ptr->fy, m_ptr->fx)) return (FALSE);
+
+ /* Hack -- no targeting hallucinations */
+ if (p_ptr->image) return (FALSE);
+
+ /* Dont target pets */
+ if (is_friend(m_ptr) > 0) return (FALSE);
+
+ /* Honor flag */
+ if (r_info[m_ptr->r_idx].flags7 & RF7_NO_TARGET) return (FALSE);
+
+ /* XXX XXX XXX Hack -- Never target trappers */
+ /* if (CLEAR_ATTR && (CLEAR_CHAR)) return (FALSE); */
+
+ /* Assume okay */
+ return (TRUE);
+}
+
+
+
+
+/*
+ * Update (if necessary) and verify (if possible) the target.
+ *
+ * We return TRUE if the target is "okay" and FALSE otherwise.
+ */
+bool_ target_okay(void)
+{
+ /* Accept stationary targets */
+ if (target_who < 0) return (TRUE);
+
+ /* Check moving targets */
+ if (target_who > 0)
+ {
+ /* Accept reasonable targets */
+ if (target_able(target_who))
+ {
+ monster_type *m_ptr = &m_list[target_who];
+
+ /* Acquire monster location */
+ target_row = m_ptr->fy;
+ target_col = m_ptr->fx;
+
+ /* Good target */
+ return (TRUE);
+ }
+ }
+
+ /* Assume no target */
+ return (FALSE);
+}
+
+
+
+/*
+ * Sorting hook -- comp function -- by "distance to player"
+ *
+ * We use "u" and "v" to point to arrays of "x" and "y" positions,
+ * and sort the arrays by double-distance to the player.
+ */
+static bool_ ang_sort_comp_distance(vptr u, vptr v, int a, int b)
+{
+ byte *x = (byte*)(u);
+ byte *y = (byte*)(v);
+
+ int da, db, kx, ky;
+
+ /* Absolute distance components */
+ kx = x[a];
+ kx -= p_ptr->px;
+ kx = ABS(kx);
+ ky = y[a];
+ ky -= p_ptr->py;
+ ky = ABS(ky);
+
+ /* Approximate Double Distance to the first point */
+ da = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx));
+
+ /* Absolute distance components */
+ kx = x[b];
+ kx -= p_ptr->px;
+ kx = ABS(kx);
+ ky = y[b];
+ ky -= p_ptr->py;
+ ky = ABS(ky);
+
+ /* Approximate Double Distance to the first point */
+ db = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx));
+
+ /* Compare the distances */
+ return (da <= db);
+}
+
+
+/*
+ * Sorting hook -- swap function -- by "distance to player"
+ *
+ * We use "u" and "v" to point to arrays of "x" and "y" positions,
+ * and sort the arrays by distance to the player.
+ */
+static void ang_sort_swap_distance(vptr u, vptr v, int a, int b)
+{
+ byte *x = (byte*)(u);
+ byte *y = (byte*)(v);
+
+ byte temp;
+
+ /* Swap "x" */
+ temp = x[a];
+ x[a] = x[b];
+ x[b] = temp;
+
+ /* Swap "y" */
+ temp = y[a];
+ y[a] = y[b];
+ y[b] = temp;
+}
+
+
+
+/*
+ * Hack -- help "select" a location (see below)
+ */
+static s16b target_pick(int y1, int x1, int dy, int dx)
+{
+ int i, v;
+
+ int x2, y2, x3, y3, x4, y4;
+
+ int b_i = -1, b_v = 9999;
+
+
+ /* Scan the locations */
+ for (i = 0; i < temp_n; i++)
+ {
+ /* Point 2 */
+ x2 = temp_x[i];
+ y2 = temp_y[i];
+
+ /* Directed distance */
+ x3 = (x2 - x1);
+ y3 = (y2 - y1);
+
+ /* Verify quadrant */
+ if (dx && (x3 * dx <= 0)) continue;
+ if (dy && (y3 * dy <= 0)) continue;
+
+ /* Absolute distance */
+ x4 = ABS(x3);
+ y4 = ABS(y3);
+
+ /* Verify quadrant */
+ if (dy && !dx && (x4 > y4)) continue;
+ if (dx && !dy && (y4 > x4)) continue;
+
+ /* Approximate Double Distance */
+ v = ((x4 > y4) ? (x4 + x4 + y4) : (y4 + y4 + x4));
+
+ /* XXX XXX XXX Penalize location */
+
+ /* Track best */
+ if ((b_i >= 0) && (v >= b_v)) continue;
+
+ /* Track best */
+ b_i = i;
+ b_v = v;
+ }
+
+ /* Result */
+ return (b_i);
+}
+
+
+/*
+ * Hack -- determine if a given location is "interesting"
+ */
+static bool_ target_set_accept(int y, int x)
+{
+ cave_type *c_ptr;
+
+ s16b this_o_idx, next_o_idx = 0;
+
+
+ /* Player grid is always interesting */
+ if ((y == p_ptr->py) && (x == p_ptr->px)) return (TRUE);
+
+
+ /* Handle hallucination */
+ if (p_ptr->image) return (FALSE);
+
+
+ /* Examine the grid */
+ c_ptr = &cave[y][x];
+
+ /* Visible monsters */
+ if (c_ptr->m_idx && c_ptr->m_idx < max_r_idx)
+ {
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ /* Visible monsters */
+ if (m_ptr->ml) return (TRUE);
+ }
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Memorized object */
+ if (o_ptr->marked) return (TRUE);
+ }
+
+ /* Interesting memorized features */
+ if (c_ptr->info & (CAVE_MARK))
+ {
+ /* Traps are interesting */
+ if (c_ptr->info & (CAVE_TRDT)) return (TRUE);
+
+ /* Hack -- Doors are boring */
+ if (c_ptr->feat == FEAT_OPEN) return (FALSE);
+ if (c_ptr->feat == FEAT_BROKEN) return (FALSE);
+ if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_DOOR_TAIL)) return (FALSE);
+
+ /* Accept 'naturally' interesting features */
+ if (f_info[c_ptr->feat].flags1 & FF1_NOTICE) return (TRUE);
+ }
+
+ /* Nope */
+ return (FALSE);
+}
+
+
+/*
+ * Prepare the "temp" array for "target_set"
+ *
+ * Return the number of target_able monsters in the set.
+ */
+static void target_set_prepare(int mode)
+{
+ int y, x;
+
+ /* Reset "temp" array */
+ temp_n = 0;
+
+ /* Scan the current panel */
+ for (y = panel_row_min; y <= panel_row_max; y++)
+ {
+ for (x = panel_col_min; x <= panel_col_max; x++)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Require line of sight, unless "look" is "expanded" */
+ if (!expand_look && !player_has_los_bold(y, x)) continue;
+
+ /* Require "interesting" contents */
+ if (!target_set_accept(y, x)) continue;
+
+ /* Require target_able monsters for "TARGET_KILL" */
+ if ((mode & (TARGET_KILL)) && !target_able(c_ptr->m_idx)) continue;
+
+ /* Save the location */
+ temp_x[temp_n] = x;
+ temp_y[temp_n] = y;
+ temp_n++;
+ }
+ }
+
+ /* Set the sort hooks */
+ ang_sort_comp = ang_sort_comp_distance;
+ ang_sort_swap = ang_sort_swap_distance;
+
+ /* Sort the positions */
+ ang_sort(temp_x, temp_y, temp_n);
+}
+
+
+bool_ target_object(int y, int x, int mode, cptr info, bool_ *boring,
+ object_type *o_ptr, char *out_val, cptr *s1, cptr *s2, cptr *s3,
+ int *query)
+{
+ char o_name[80];
+
+ /* Not boring */
+ *boring = FALSE;
+
+ /* Obtain an object description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Describe the object */
+ sprintf(out_val, "%s%s%s%s [%s]", *s1, *s2, *s3, o_name, info);
+ prt(out_val, 0, 0);
+ move_cursor_relative(y, x);
+ *query = inkey();
+
+ /* Always stop at "normal" keys */
+ if ((*query != '\r') && (*query != '\n') && (*query != ' ')) return (TRUE);
+
+ /* Sometimes stop at "space" key */
+ if ((*query == ' ') && !(mode & (TARGET_LOOK))) return (TRUE);
+
+ /* Change the intro */
+ *s1 = "It is ";
+
+ /* Plurals */
+ if (o_ptr->number != 1) *s1 = "They are ";
+
+ /* Preposition */
+ *s2 = "on ";
+ return (FALSE);
+}
+
+/*
+ * Examine a grid, return a keypress.
+ *
+ * The "mode" argument contains the "TARGET_LOOK" bit flag, which
+ * indicates that the "space" key should scan through the contents
+ * of the grid, instead of simply returning immediately. This lets
+ * the "look" command get complete information, without making the
+ * "target" command annoying.
+ *
+ * The "info" argument contains the "commands" which should be shown
+ * inside the "[xxx]" text. This string must never be empty, or grids
+ * containing monsters will be displayed with an extra comma.
+ *
+ * Note that if a monster is in the grid, we update both the monster
+ * recall info and the health bar info to track that monster.
+ *
+ * Eventually, we may allow multiple objects per grid, or objects
+ * and terrain features in the same grid. XXX XXX XXX
+ *
+ * This function must handle blindness/hallucination.
+ */
+static int target_set_aux(int y, int x, int mode, cptr info)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ s16b this_o_idx, next_o_idx = 0;
+
+ cptr s1, s2, s3;
+
+ bool_ boring;
+
+ int feat;
+
+ int query;
+
+ char out_val[160];
+
+
+ /* Repeat forever */
+ while (1)
+ {
+ /* Paranoia */
+ query = ' ';
+
+ /* Assume boring */
+ boring = TRUE;
+
+ /* Default */
+ s1 = "You see ";
+ s2 = "";
+ s3 = "";
+
+ /* Hack -- under the player */
+ if ((y == p_ptr->py) && (x == p_ptr->px))
+ {
+ /* Description */
+ s1 = "You are ";
+
+ /* Preposition */
+ s2 = "on ";
+ }
+
+
+ /* Hack -- hallucination */
+ if (p_ptr->image)
+ {
+ cptr name = "something strange";
+
+ /* Display a message */
+ sprintf(out_val, "%s%s%s%s [%s]", s1, s2, s3, name, info);
+ prt(out_val, 0, 0);
+ move_cursor_relative(y, x);
+ query = inkey();
+
+ /* Stop on everything but "return" */
+ if ((query != '\r') && (query != '\n')) break;
+
+ /* Repeat forever */
+ continue;
+ }
+
+
+ /* Actual monsters */
+ if (c_ptr->m_idx)
+ {
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ monster_race *r_ptr = race_inf(m_ptr);
+
+ /* Mimics special treatment -- looks like an object */
+ if ((r_ptr->flags9 & RF9_MIMIC) && (m_ptr->csleep))
+ {
+ object_type *o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[m_ptr->hold_o_idx];
+
+ if (o_ptr->marked)
+ {
+ if (target_object(y, x, mode, info, &boring, o_ptr, out_val, &s1, &s2, &s3, &query)) break;
+ }
+ }
+ else
+ {
+ /* Visible */
+ if (m_ptr->ml)
+ {
+ bool_ recall = FALSE;
+
+ char m_name[80];
+
+ /* Not boring */
+ boring = FALSE;
+
+ /* Get the monster name ("a kobold") */
+ monster_desc(m_name, m_ptr, 0x08);
+
+ /* Hack -- track this monster race */
+ monster_race_track(m_ptr->r_idx, m_ptr->ego);
+
+ /* Hack -- health bar for this monster */
+ health_track(c_ptr->m_idx);
+
+ /* Hack -- handle stuff */
+ handle_stuff();
+
+ /* Interact */
+ while (1)
+ {
+ /* Recall */
+ if (recall)
+ {
+ /* Save */
+ character_icky = TRUE;
+ Term_save();
+
+ /* Recall on screen */
+ screen_roff(m_ptr->r_idx, m_ptr->ego, 0);
+
+ /* Hack -- Complete the prompt (again) */
+ Term_addstr( -1, TERM_WHITE, format(" [r,%s]", info));
+
+ /* Command */
+ query = inkey();
+
+ /* Restore */
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ /* Normal */
+ else
+ {
+ cptr mstat;
+
+ switch (m_ptr->status)
+ {
+ case MSTATUS_NEUTRAL:
+ case MSTATUS_NEUTRAL_M:
+ case MSTATUS_NEUTRAL_P:
+ mstat = " (neutral) ";
+ break;
+ case MSTATUS_PET:
+ mstat = " (pet) ";
+ break;
+ case MSTATUS_FRIEND:
+ mstat = " (coaligned) ";
+ break;
+ case MSTATUS_COMPANION:
+ mstat = " (companion) ";
+ break;
+ default:
+ mstat = " ";
+ break;
+ }
+ if (m_ptr->mflag & MFLAG_PARTIAL) mstat = " (partial) ";
+
+ /* Describe, and prompt for recall */
+ sprintf(out_val, "%s%s%s%s (level %d, %s%s)%s%s[r,%s]",
+ s1, s2, s3, m_name,
+ m_ptr->level, look_mon_desc(c_ptr->m_idx),
+ (m_ptr->mflag & MFLAG_QUEST) ? ", quest" : "",
+ (m_ptr->smart & SM_CLONED ? " (clone)" : ""),
+ (mstat), info);
+
+ prt(out_val, 0, 0);
+
+ /* Place cursor */
+ move_cursor_relative(y, x);
+
+ /* Command */
+ query = inkey();
+ }
+
+ /* Normal commands */
+ if (query != 'r') break;
+
+ /* Toggle recall */
+ recall = !recall;
+ }
+
+ /* Always stop at "normal" keys */
+ if ((query != '\r') && (query != '\n') && (query != ' ')) break;
+
+ /* Sometimes stop at "space" key */
+ if ((query == ' ') && !(mode & (TARGET_LOOK))) break;
+
+ /* Change the intro */
+ s1 = "It is ";
+
+ /* Hack -- take account of gender */
+ if (r_ptr->flags1 & (RF1_FEMALE)) s1 = "She is ";
+ else if (r_ptr->flags1 & (RF1_MALE)) s1 = "He is ";
+
+ /* Use a preposition */
+ s2 = "carrying ";
+
+ /* Scan all objects being carried */
+ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ char o_name[80];
+
+ object_type *o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Obtain an object description */
+ object_desc(o_name, o_ptr, TRUE, 3);
+
+ /* Describe the object */
+ sprintf(out_val, "%s%s%s%s [%s]", s1, s2, s3, o_name, info);
+ prt(out_val, 0, 0);
+ move_cursor_relative(y, x);
+ query = inkey();
+
+ /* Always stop at "normal" keys */
+ if ((query != '\r') && (query != '\n') && (query != ' ')) break;
+
+ /* Sometimes stop at "space" key */
+ if ((query == ' ') && !(mode & (TARGET_LOOK))) break;
+
+ /* Change the intro */
+ s2 = "also carrying ";
+ }
+
+ /* Double break */
+ if (this_o_idx) break;
+
+ /* Use a preposition */
+ s2 = "on ";
+ }
+ }
+ }
+
+
+
+ /* Scan all objects in the grid */
+ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
+ {
+ object_type * o_ptr;
+
+ /* Acquire object */
+ o_ptr = &o_list[this_o_idx];
+
+ /* Acquire next object */
+ next_o_idx = o_ptr->next_o_idx;
+
+ /* Describe it */
+ if (o_ptr->marked)
+ {
+ if (target_object(y, x, mode, info, &boring, o_ptr, out_val, &s1, &s2, &s3, &query)) break;
+ }
+ }
+
+ /* Double break */
+ if (this_o_idx) break;
+
+ /* Actual traps */
+ if ((c_ptr->info & (CAVE_TRDT)) && c_ptr->t_idx)
+ {
+ cptr name = "a trap", s4;
+
+ /* Name trap */
+ if (t_info[c_ptr->t_idx].ident)
+ {
+ s4 = format("(%s)", t_name + t_info[c_ptr->t_idx].name);
+ }
+ else
+ {
+ s4 = "an unknown trap";
+ }
+
+ /* Display a message */
+ sprintf(out_val, "%s%s%s%s [%s]", s1, s2, s3, name, s4);
+ prt(out_val, 0, 0);
+ move_cursor_relative(y, x);
+ query = inkey();
+
+ /* Stop on everything but "return" */
+ if ((query != '\r') && (query != '\n')) break;
+
+ /* Repeat forever */
+ continue;
+ }
+
+ /* Feature (apply "mimic") */
+ if (c_ptr->mimic)
+ {
+ feat = c_ptr->mimic;
+ }
+ else
+ {
+ feat = f_info[c_ptr->feat].mimic;
+ }
+
+ /* Require knowledge about grid, or ability to see grid */
+ if (!(c_ptr->info & (CAVE_MARK)) && !player_can_see_bold(y, x))
+ {
+ /* Forget feature */
+ feat = FEAT_NONE;
+ }
+
+ /* Terrain feature if needed */
+ if (boring || (feat >= FEAT_GLYPH))
+ {
+ cptr name;
+
+ /* Hack -- special handling for building doors */
+ if (feat == FEAT_SHOP)
+ {
+ name = st_name + st_info[c_ptr->special].name;
+ }
+ else
+ {
+ name = f_name + f_info[feat].name;
+ }
+
+ /* Hack -- handle unknown grids */
+ if (feat == FEAT_NONE) name = "unknown grid";
+
+ /* Pick a prefix */
+ if (*s2 &&
+ (((feat >= FEAT_MINOR_GLYPH) &&
+ (feat <= FEAT_PATTERN_XTRA2)) ||
+ (feat == FEAT_DIRT) ||
+ (feat == FEAT_GRASS) ||
+ (feat == FEAT_FLOWER))) s2 = "on ";
+ else if (*s2 && (feat == FEAT_SMALL_TREES)) s2 = "by ";
+ else if (*s2 && (feat >= FEAT_DOOR_HEAD)) s2 = "in ";
+
+ /* Pick proper indefinite article */
+ s3 = (is_a_vowel(name[0])) ? "an " : "a ";
+
+ /* Hack -- special introduction for store & building doors */
+ if (feat == FEAT_SHOP)
+ {
+ s3 = "the entrance to the ";
+ }
+
+ if ((feat == FEAT_MORE) && c_ptr->special)
+ {
+ s3 = "";
+ name = d_text + d_info[c_ptr->special].text;
+ }
+
+ if (p_ptr->wild_mode && (feat == FEAT_TOWN))
+ {
+ s3 = "";
+ name = format("%s(%s)",
+ wf_name + wf_info[wild_map[y][x].feat].name,
+ wf_text + wf_info[wild_map[y][x].feat].text);
+ }
+
+ if ((feat == FEAT_FOUNTAIN) && (c_ptr->info & CAVE_IDNT))
+ {
+ object_kind *k_ptr;
+ int tv, sv;
+
+ if (c_ptr->special <= SV_POTION_LAST)
+ {
+ tv = TV_POTION;
+ sv = c_ptr->special;
+ }
+ else
+ {
+ tv = TV_POTION2;
+ sv = c_ptr->special - SV_POTION_LAST;
+ }
+
+ k_ptr = &k_info[lookup_kind(tv, sv)];
+ info = k_name + k_ptr->name;
+ }
+
+ /* Display a message */
+ if (!wizard)
+ {
+ sprintf(out_val, "%s%s%s%s [%s]", s1, s2, s3, name, info);
+ }
+ else
+ {
+ sprintf(out_val, "%s%s%s%s [%s] (%d:%d:%d)",
+ s1, s2, s3, name, info,
+ c_ptr->feat, c_ptr->mimic, c_ptr->special);
+ }
+ prt(out_val, 0, 0);
+ move_cursor_relative(y, x);
+ query = inkey();
+
+ /* Always stop at "normal" keys */
+ if ((query != '\r') && (query != '\n') && (query != ' ')) break;
+ }
+
+ /* Stop on everything but "return" */
+ if ((query != '\r') && (query != '\n')) break;
+ }
+
+ /* Keep going */
+ return (query);
+}
+
+
+
+
+/*
+ * Handle "target" and "look".
+ *
+ * Note that this code can be called from "get_aim_dir()".
+ *
+ * All locations must be on the current panel. Consider the use of
+ * "panel_bounds()" to allow "off-panel" targets, perhaps by using
+ * some form of "scrolling" the map around the cursor. XXX XXX XXX
+ * That is, consider the possibility of "auto-scrolling" the screen
+ * while the cursor moves around. This may require changes in the
+ * "update_mon()" code to allow "visibility" even if off panel, and
+ * may require dynamic recalculation of the "temp" grid set.
+ *
+ * Hack -- targetting/observing an "outer border grid" may induce
+ * problems, so this is not currently allowed.
+ *
+ * The player can use the direction keys to move among "interesting"
+ * grids in a heuristic manner, or the "space", "+", and "-" keys to
+ * move through the "interesting" grids in a sequential manner, or
+ * can enter "location" mode, and use the direction keys to move one
+ * grid at a time in any direction. The "t" (set target) command will
+ * only target a monster (as opposed to a location) if the monster is
+ * target_able and the "interesting" mode is being used.
+ *
+ * The current grid is described using the "look" method above, and
+ * a new command may be entered at any time, but note that if the
+ * "TARGET_LOOK" bit flag is set (or if we are in "location" mode,
+ * where "space" has no obvious meaning) then "space" will scan
+ * through the description of the current grid until done, instead
+ * of immediately jumping to the next "interesting" grid. This
+ * allows the "target" command to retain its old semantics.
+ *
+ * The "*", "+", and "-" keys may always be used to jump immediately
+ * to the next (or previous) interesting grid, in the proper mode.
+ *
+ * The "return" key may always be used to scan through a complete
+ * grid description (forever).
+ *
+ * This command will cancel any old target, even if used from
+ * inside the "look" command.
+ */
+bool_ target_set(int mode)
+{
+ int i, d, m;
+ int y = p_ptr->py;
+ int x = p_ptr->px;
+
+ bool_ done = FALSE;
+
+ bool_ flag = TRUE;
+
+ char query;
+
+ char info[80];
+
+ cave_type *c_ptr;
+
+ int screen_wid, screen_hgt;
+ int panel_wid, panel_hgt;
+
+ /* Get size */
+ get_screen_size(&screen_wid, &screen_hgt);
+
+ /* Calculate the amount of panel movement */
+ panel_hgt = screen_hgt / 2;
+ panel_wid = screen_wid / 2;
+
+ /* Cancel target */
+ target_who = 0;
+
+
+ /* Cancel tracking */
+ /* health_track(0); */
+
+
+ /* Prepare the "temp" array */
+ target_set_prepare(mode);
+
+ /* Start near the player */
+ m = 0;
+
+ /* Interact */
+ while (!done)
+ {
+ /* Interesting grids */
+ if (flag && temp_n)
+ {
+ y = temp_y[m];
+ x = temp_x[m];
+
+ /* Access */
+ c_ptr = &cave[y][x];
+
+ /* Allow target */
+ if (target_able(c_ptr->m_idx))
+ {
+ strcpy(info, "q,t,p,o,+,-,'dir'");
+ }
+
+ /* Dis-allow target */
+ else
+ {
+ strcpy(info, "q,p,o,+,-,'dir'");
+ }
+
+ /* Describe and Prompt */
+ query = target_set_aux(y, x, mode, info);
+
+ /* Cancel tracking */
+ /* health_track(0); */
+
+ /* Assume no "direction" */
+ d = 0;
+
+ /* Analyze */
+ switch (query)
+ {
+ case ESCAPE:
+ case 'q':
+ {
+ done = TRUE;
+ break;
+ }
+
+ case 't':
+ case '.':
+ case '5':
+ case '0':
+ {
+ if (target_able(c_ptr->m_idx))
+ {
+ health_track(c_ptr->m_idx);
+ target_who = c_ptr->m_idx;
+ target_row = y;
+ target_col = x;
+ done = TRUE;
+ }
+ else
+ {
+ bell();
+ }
+ break;
+ }
+
+ case ' ':
+ case '*':
+ case '+':
+ {
+ if (++m == temp_n)
+ {
+ m = 0;
+ if (!expand_list) done = TRUE;
+ }
+ break;
+ }
+
+ case '-':
+ {
+ if (m-- == 0)
+ {
+ m = temp_n - 1;
+ if (!expand_list) done = TRUE;
+ }
+ break;
+ }
+
+ case 'p':
+ {
+ /* Recenter the map around the player */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Recalculate interesting grids */
+ target_set_prepare(mode);
+
+ y = p_ptr->py;
+ x = p_ptr->px;
+
+ /* Fall through... */
+ }
+
+ case 'o':
+ {
+ flag = FALSE;
+ break;
+ }
+
+ case 'm':
+ {
+ break;
+ }
+
+ default:
+ {
+ /* Extract the action (if any) */
+ d = get_keymap_dir(query);
+
+ if (!d) bell();
+ break;
+ }
+ }
+
+ /* Hack -- move around */
+ if (d)
+ {
+ /* Find a new monster */
+ i = target_pick(temp_y[m], temp_x[m], ddy[d], ddx[d]);
+
+ /* Scroll to find interesting grid */
+ if (i < 0)
+ {
+ int dy;
+ int dx;
+
+ dy = ddy[d];
+ dx = ddx[d];
+
+ /* Note panel change */
+ if (change_panel(dy, dx))
+ {
+ int ty = temp_y[m];
+ int tx = temp_x[m];
+
+ /* Recalculate interesting grids */
+ target_set_prepare(mode);
+
+ /* Find a new monster */
+ i = target_pick(ty, tx, dy, dx);
+
+ /* Restore panel if needed */
+ if (i < 0)
+ {
+ /* Restore panel */
+ change_panel( -dy, -dx);
+
+ /* Recalculate interesting grids */
+ target_set_prepare(mode);
+ }
+ }
+ }
+
+ /* Use that grids */
+ if (i >= 0) m = i;
+ }
+ }
+
+ /* Arbitrary grids */
+ else
+ {
+ /* Access */
+ c_ptr = &cave[y][x];
+
+ /* Default prompt */
+ strcpy(info, "q,t,p,m,+,-,'dir'");
+
+ /* Describe and Prompt (enable "TARGET_LOOK") */
+ query = target_set_aux(y, x, mode | TARGET_LOOK, info);
+
+ /* Cancel tracking */
+ /* health_track(0); */
+
+ /* Assume no direction */
+ d = 0;
+
+ /* Analyze the keypress */
+ switch (query)
+ {
+ case ESCAPE:
+ case 'q':
+ {
+ done = TRUE;
+ break;
+ }
+
+ case 't':
+ case '.':
+ case '5':
+ case '0':
+ {
+ target_who = -1;
+ target_row = y;
+ target_col = x;
+ done = TRUE;
+ break;
+ }
+
+ case ' ':
+ case '*':
+ case '+':
+ case '-':
+ {
+ break;
+ }
+
+ case 'p':
+ {
+ y = p_ptr->py;
+ x = p_ptr->px;
+ }
+
+ case 'o':
+ {
+ break;
+ }
+
+ case 'm':
+ {
+ flag = TRUE;
+ break;
+ }
+
+ default:
+ {
+ /* Extract the action (if any) */
+ d = get_keymap_dir(query);
+
+ if (!d) bell();
+ break;
+ }
+ }
+
+ /* Handle "direction" */
+ if (d)
+ {
+ int dy = ddy[d];
+ int dx = ddx[d];
+
+ /* Move */
+ y += dy;
+ x += dx;
+
+ /* Do not move horizontally if unnecessary */
+ if (((x < panel_col_min + panel_wid) && (dx > 0)) ||
+ ((x > panel_col_min + panel_wid) && (dx < 0)))
+ {
+ dx = 0;
+ }
+
+ /* Do not move vertically if unnecessary */
+ if (((y < panel_row_min + panel_hgt) && (dy > 0)) ||
+ ((y > panel_row_min + panel_hgt) && (dy < 0)))
+ {
+ dy = 0;
+ }
+ /* Apply the motion */
+ if ((y >= panel_row_min + screen_hgt) ||
+ (y < panel_row_min) ||
+ (x > panel_col_min + screen_wid) ||
+ (x < panel_col_min))
+ {
+ /* Change panel and recalculate interesting grids */
+ if (change_panel(dy, dx)) target_set_prepare(mode);
+ }
+
+ /* Boundary checks */
+ if (!wizard)
+ {
+ /* Hack -- Verify y */
+ if (y <= 0) y = 1;
+ else if (y >= cur_hgt - 1) y = cur_hgt - 2;
+
+ /* Hack -- Verify x */
+ if (x <= 0) x = 1;
+ else if (x >= cur_wid - 1) x = cur_wid - 2;
+ }
+ else
+ {
+ /* Hack -- Verify y */
+ if (y < 0) y = 0;
+ else if (y > cur_hgt - 1) y = cur_hgt - 1;
+
+ /* Hack -- Verify x */
+ if (x < 0) x = 0;
+ else if (x > cur_wid - 1) x = cur_wid - 1;
+ }
+ }
+ }
+ }
+
+ /* Forget */
+ temp_n = 0;
+
+ /* Clear the top line */
+ prt("", 0, 0);
+
+ /* Recenter the map around the player */
+ verify_panel();
+
+ /* Update stuff */
+ p_ptr->update |= (PU_MONSTERS);
+
+ /* Redraw map */
+ p_ptr->redraw |= (PR_MAP);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_OVERHEAD);
+
+ /* Handle stuff */
+ handle_stuff();
+
+ /* Failure to set target */
+ if (!target_who) return (FALSE);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+
+/*
+ * Get an "aiming direction" from the user.
+ *
+ * The "dir" is loaded with 1,2,3,4,6,7,8,9 for "actual direction", and
+ * "0" for "current target", and "-1" for "entry aborted".
+ *
+ * Note that "Force Target", if set, will pre-empt user interaction,
+ * if there is a usable target already set.
+ *
+ * Note that confusion over-rides any (explicit?) user choice.
+ */
+bool_ get_aim_dir(int *dp)
+{
+ int dir;
+
+ char command;
+
+ cptr p;
+
+ if (repeat_pull(dp))
+ {
+ /* Confusion? */
+
+ /* Verify */
+ if (!(*dp == 5 && !target_okay()))
+ {
+ return (TRUE);
+ }
+ }
+
+ /* Initialize */
+ (*dp) = 0;
+
+ /* Global direction */
+ dir = command_dir;
+
+ /* Hack -- auto-target if requested */
+ if (use_old_target && target_okay()) dir = 5;
+
+ /* Ask until satisfied */
+ while (!dir)
+ {
+ /* Choose a prompt */
+ if (!target_okay())
+ {
+ p = "Direction ('*' to choose a target, Escape to cancel)? ";
+ }
+ else
+ {
+ p = "Direction ('5' for target, '*' to re-target, Escape to cancel)? ";
+ }
+
+ /* Get a command (or Cancel) */
+ if (!get_com(p, &command)) break;
+
+ /* Convert various keys to "standard" keys */
+ switch (command)
+ {
+ /* Use current target */
+ case 'T':
+ case 't':
+ case '.':
+ case '5':
+ case '0':
+ {
+ dir = 5;
+ break;
+ }
+
+ /* Set new target */
+ case '*':
+ {
+ if (target_set(TARGET_KILL)) dir = 5;
+ break;
+ }
+
+ default:
+ {
+ /* Extract the action (if any) */
+ dir = get_keymap_dir(command);
+
+ break;
+ }
+ }
+
+ /* Verify requested targets */
+ if ((dir == 5) && !target_okay()) dir = 0;
+
+ /* Error */
+ if (!dir) bell();
+ }
+
+ /* No direction */
+ if (!dir) return (FALSE);
+
+ /* Save the direction */
+ command_dir = dir;
+
+ /* Check for confusion */
+ if (p_ptr->confused)
+ {
+ /* XXX XXX XXX */
+ /* Random direction */
+ dir = ddd[rand_int(8)];
+ }
+
+ /* Notice confusion */
+ if (command_dir != dir)
+ {
+ /* Warn the user */
+ msg_print("You are confused.");
+ }
+
+ /* Save direction */
+ (*dp) = dir;
+
+
+ repeat_push(dir);
+
+ /* A "valid" direction was entered */
+ return (TRUE);
+}
+
+
+
+/*
+ * Request a "movement" direction (1,2,3,4,6,7,8,9) from the user,
+ * and place it into "command_dir", unless we already have one.
+ *
+ * This function should be used for all "repeatable" commands, such as
+ * run, walk, open, close, bash, disarm, spike, tunnel, etc, as well
+ * as all commands which must reference a grid adjacent to the player,
+ * and which may not reference the grid under the player. Note that,
+ * for example, it is no longer possible to "disarm" or "open" chests
+ * in the same grid as the player.
+ *
+ * Direction "5" is illegal and will (cleanly) abort the command.
+ *
+ * This function tracks and uses the "global direction", and uses
+ * that as the "desired direction", to which "confusion" is applied.
+ */
+bool_ get_rep_dir(int *dp)
+{
+ int dir;
+
+ if (repeat_pull(dp))
+ {
+ return (TRUE);
+ }
+
+ /* Initialize */
+ (*dp) = 0;
+
+ /* Global direction */
+ dir = command_dir;
+
+ /* Get a direction */
+ while (!dir)
+ {
+ char ch;
+
+ /* Get a command (or Cancel) */
+ if (!get_com("Direction (Escape to cancel)? ", &ch)) break;
+
+ /* Look up the direction */
+ dir = get_keymap_dir(ch);
+
+ /* Oops */
+ if (!dir) bell();
+ }
+
+ /* Prevent weirdness */
+ if (dir == 5) dir = 0;
+
+ /* Aborted */
+ if (!dir) return (FALSE);
+
+ /* Save desired direction */
+ command_dir = dir;
+
+ /* Apply "confusion" */
+ if (p_ptr->confused)
+ {
+ /* Standard confusion */
+ if (rand_int(100) < 75)
+ {
+ /* Random direction */
+ dir = ddd[rand_int(8)];
+ }
+ }
+
+ /* Notice confusion */
+ if (command_dir != dir)
+ {
+ /* Warn the user */
+ msg_print("You are confused.");
+ }
+
+ /* Save direction */
+ (*dp) = dir;
+
+
+ repeat_push(dir);
+
+ /* Success */
+ return (TRUE);
+}
+
+
+int get_chaos_patron(void)
+{
+ return (((p_ptr->age) + (p_ptr->sc)) % MAX_PATRON);
+}
+
+
+void gain_level_reward(int chosen_reward)
+{
+ object_type *q_ptr;
+ object_type forge;
+ char wrath_reason[32] = "";
+ int nasty_chance = 6;
+ int dummy = 0, dummy2 = 0;
+ int type, effect;
+
+
+ if (p_ptr->lev == 13) nasty_chance = 2;
+ else if (!(p_ptr->lev % 13)) nasty_chance = 3;
+ else if (!(p_ptr->lev % 14)) nasty_chance = 12;
+
+ if (randint(nasty_chance) == 1)
+ type = randint(20); /* Allow the 'nasty' effects */
+ else
+ type = randint(15) + 5; /* Or disallow them */
+
+ if (type < 1) type = 1;
+ if (type > 20) type = 20;
+ type--;
+
+
+ sprintf(wrath_reason, "the Wrath of %s",
+ chaos_patrons[p_ptr->chaos_patron]);
+
+ effect = chaos_rewards[p_ptr->chaos_patron][type];
+
+ if ((randint(6) == 1) && !chosen_reward)
+ {
+ msg_format("%^s rewards you with a corruption!",
+ chaos_patrons[p_ptr->chaos_patron]);
+ (void)gain_random_corruption(0);
+ return;
+ }
+
+ switch (chosen_reward ? chosen_reward : effect)
+ {
+ case REW_POLY_SLF :
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Thou needst a new form, mortal!'");
+ do_poly_self();
+ break;
+
+ case REW_GAIN_EXP:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Well done, mortal! Lead on!'");
+ if (p_ptr->exp < PY_MAX_EXP)
+ {
+ s32b ee = (p_ptr->exp / 2) + 10;
+ if (ee > 100000L) ee = 100000L;
+ msg_print("You feel more experienced.");
+ gain_exp(ee);
+ }
+ break;
+
+ case REW_LOSE_EXP:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Thou didst not deserve that, slave.'");
+ lose_exp(p_ptr->exp / 6);
+ break;
+
+ case REW_GOOD_OBJ:
+ msg_format("The voice of %s whispers:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Use my gift wisely.'");
+ acquirement(p_ptr->py, p_ptr->px, 1, FALSE, FALSE);
+ break;
+
+ case REW_GREA_OBJ:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Use my gift wisely.'");
+ acquirement(p_ptr->py, p_ptr->px, 1, TRUE, FALSE);
+ break;
+
+ case REW_CHAOS_WP:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Thy deed hath earned thee a worthy blade.'");
+ /* Get local object */
+ q_ptr = &forge;
+ dummy = TV_SWORD;
+ switch (randint(p_ptr->lev))
+ {
+ case 0:
+ case 1:
+ dummy2 = SV_DAGGER;
+ break;
+ case 2:
+ case 3:
+ dummy2 = SV_MAIN_GAUCHE;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ dummy2 = SV_RAPIER;
+ break;
+ case 7:
+ case 8:
+ dummy2 = SV_SMALL_SWORD;
+ break;
+ case 9:
+ case 10:
+ dummy2 = SV_BASILLARD;
+ break;
+ case 11:
+ case 12:
+ case 13:
+ dummy2 = SV_SHORT_SWORD;
+ break;
+ case 14:
+ case 15:
+ dummy2 = SV_SABRE;
+ break;
+ case 16:
+ case 17:
+ dummy2 = SV_CUTLASS;
+ break;
+ case 18:
+ case 19:
+ dummy2 = SV_KHOPESH;
+ break;
+ case 20:
+ dummy2 = SV_TULWAR;
+ break;
+ case 21:
+ dummy2 = SV_BROAD_SWORD;
+ break;
+ case 22:
+ case 23:
+ dummy2 = SV_LONG_SWORD;
+ break;
+ case 24:
+ case 25:
+ dummy2 = SV_SCIMITAR;
+ break;
+ case 26:
+ case 27:
+ dummy2 = SV_KATANA;
+ break;
+ case 28:
+ case 29:
+ dummy2 = SV_BASTARD_SWORD;
+ break;
+ case 30:
+ dummy2 = SV_GREAT_SCIMITAR;
+ break;
+ case 31:
+ dummy2 = SV_CLAYMORE;
+ break;
+ case 32:
+ dummy2 = SV_ESPADON;
+ break;
+ case 33:
+ dummy2 = SV_TWO_HANDED_SWORD;
+ break;
+ case 34:
+ dummy2 = SV_FLAMBERGE;
+ break;
+ case 35:
+ case 36:
+ dummy2 = SV_EXECUTIONERS_SWORD;
+ break;
+ case 37:
+ dummy2 = SV_ZWEIHANDER;
+ break;
+ default:
+ dummy2 = SV_BLADE_OF_CHAOS;
+ }
+
+ object_prep(q_ptr, lookup_kind(dummy, dummy2));
+ q_ptr->to_h = 3 + (randint(dun_level)) % 10;
+ q_ptr->to_d = 3 + (randint(dun_level)) % 10;
+ random_resistance(q_ptr, FALSE, (randint(34) + 4));
+ q_ptr->name2 = EGO_CHAOTIC;
+
+ /* Apply the ego */
+ apply_magic(q_ptr, dun_level, FALSE, FALSE, FALSE);
+
+ /* Drop it in the dungeon */
+ drop_near(q_ptr, -1, p_ptr->py, p_ptr->px);
+ break;
+
+ case REW_GOOD_OBS:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Thy deed hath earned thee a worthy reward.'");
+ acquirement(p_ptr->py, p_ptr->px, randint(2) + 1, FALSE, FALSE);
+ break;
+
+ case REW_GREA_OBS:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Behold, mortal, how generously I reward thy loyalty.'");
+ acquirement(p_ptr->py, p_ptr->px, randint(2) + 1, TRUE, FALSE);
+ break;
+
+ case REW_TY_CURSE:
+ msg_format("The voice of %s thunders:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Thou art growing arrogant, mortal.'");
+ activate_ty_curse();
+ break;
+
+ case REW_SUMMON_M:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'My pets, destroy the arrogant mortal!'");
+ for (dummy = 0; dummy < randint(5) + 1; dummy++)
+ {
+ (void)summon_specific(p_ptr->py, p_ptr->px, dun_level, 0);
+ }
+ break;
+
+ case REW_H_SUMMON:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Thou needst worthier opponents!'");
+ activate_hi_summon();
+ break;
+
+ case REW_DO_HAVOC:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Death and destruction! This pleaseth me!'");
+ call_chaos();
+ break;
+
+ case REW_GAIN_ABL:
+ msg_format("The voice of %s rings out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Stay, mortal, and let me mold thee.'");
+ if ((randint(3) == 1) &&
+ !(chaos_stats[p_ptr->chaos_patron] < 0))
+ do_inc_stat(chaos_stats[p_ptr->chaos_patron]);
+ else
+ do_inc_stat(randint(6) - 1);
+ break;
+
+ case REW_LOSE_ABL:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'I grow tired of thee, mortal.'");
+ if ((randint(3) == 1) &&
+ !(chaos_stats[p_ptr->chaos_patron] < 0))
+ do_dec_stat(chaos_stats[p_ptr->chaos_patron], STAT_DEC_NORMAL);
+ else
+ (void)do_dec_stat(randint(6) - 1, STAT_DEC_NORMAL);
+ break;
+
+ case REW_RUIN_ABL:
+ msg_format("The voice of %s thunders:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Thou needst a lesson in humility, mortal!'");
+ msg_print("You feel less powerful!");
+ for (dummy = 0; dummy < 6; dummy++)
+ {
+ (void)dec_stat(dummy, 10 + randint(15), TRUE);
+ }
+ break;
+
+ case REW_POLY_WND:
+ msg_format("You feel the power of %s touch you.",
+ chaos_patrons[p_ptr->chaos_patron]);
+ do_poly_wounds();
+ break;
+
+ case REW_AUGM_ABL:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Receive this modest gift from me!'");
+ for (dummy = 0; dummy < 6; dummy++)
+ {
+ (void) do_inc_stat(dummy);
+ }
+ break;
+
+ case REW_HURT_LOT:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Suffer, pathetic fool!'");
+ fire_ball(GF_DISINTEGRATE, 0, (p_ptr->lev * 4), 4);
+ take_hit(p_ptr->lev * 4, wrath_reason);
+ break;
+
+ case REW_HEAL_FUL:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Rise, my servant!'");
+ restore_level();
+ (void)set_poisoned(0);
+ (void)set_blind(0);
+ (void)set_confused(0);
+ (void)set_image(0);
+ (void)set_stun(0);
+ (void)set_cut(0);
+ hp_player(5000);
+ for (dummy = 0; dummy < 6; dummy++)
+ {
+ (void) do_res_stat(dummy, TRUE);
+ }
+ break;
+
+ case REW_CURSE_WP:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Thou reliest too much on thy weapon.'");
+ (void)curse_weapon();
+ break;
+
+ case REW_CURSE_AR:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Thou reliest too much on thine equipment.'");
+ (void)curse_armor();
+ break;
+
+ case REW_PISS_OFF:
+ msg_format("The voice of %s whispers:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Now thou shalt pay for annoying me.'");
+ switch (randint(4))
+ {
+ case 1:
+ activate_ty_curse();
+ break;
+ case 2:
+ activate_hi_summon();
+ break;
+ case 3:
+ if (randint(2) == 1) (void)curse_weapon();
+ else (void)curse_armor();
+ break;
+ default:
+ for (dummy = 0; dummy < 6; dummy++)
+ {
+ (void) dec_stat(dummy, 10 + randint(15), TRUE);
+ }
+ break;
+ }
+ break;
+
+ case REW_WRATH:
+ msg_format("The voice of %s thunders:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Die, mortal!'");
+ take_hit(p_ptr->lev * 4, wrath_reason);
+ for (dummy = 0; dummy < 6; dummy++)
+ {
+ (void) dec_stat(dummy, 10 + randint(15), FALSE);
+ }
+ activate_hi_summon();
+ activate_ty_curse();
+ if (randint(2) == 1) (void)curse_weapon();
+ if (randint(2) == 1) (void)curse_armor();
+ break;
+
+ case REW_DESTRUCT:
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ {
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Death and destruction! This pleaseth me!'");
+ destroy_area(p_ptr->py, p_ptr->px, 25, TRUE, FALSE);
+ }
+ break;
+
+ case REW_GENOCIDE:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Let me relieve thee of thine oppressors!'");
+ (void) genocide(FALSE);
+ break;
+
+ case REW_MASS_GEN:
+ msg_format("The voice of %s booms out:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_print("'Let me relieve thee of thine oppressors!'");
+ (void) mass_genocide(FALSE);
+ break;
+
+ case REW_DISPEL_C:
+ msg_format("You can feel the power of %s assault your enemies!",
+ chaos_patrons[p_ptr->chaos_patron]);
+ (void) dispel_monsters(p_ptr->lev * 4);
+ break;
+
+ case REW_IGNORE:
+ msg_format("%s ignores you.",
+ chaos_patrons[p_ptr->chaos_patron]);
+ break;
+
+ case REW_SER_DEMO:
+ msg_format("%s rewards you with a demonic servant!", chaos_patrons[p_ptr->chaos_patron]);
+ if (!(summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_DEMON, FALSE)))
+ msg_print("Nobody ever turns up...");
+ break;
+
+ case REW_SER_MONS:
+ msg_format("%s rewards you with a servant!", chaos_patrons[p_ptr->chaos_patron]);
+ if (!(summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_NO_UNIQUES, FALSE)))
+ msg_print("Nobody ever turns up...");
+ break;
+
+ case REW_SER_UNDE:
+ msg_format("%s rewards you with an undead servant!", chaos_patrons[p_ptr->chaos_patron]);
+ if (!(summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_UNDEAD, FALSE)))
+ msg_print("Nobody ever turns up...");
+ break;
+
+ default:
+ msg_format("The voice of %s stammers:",
+ chaos_patrons[p_ptr->chaos_patron]);
+ msg_format("'Uh... uh... the answer's %d/%d, what's the question?'", type,
+ effect );
+ break;
+ }
+}
+
+
+/*
+ * old -- from PsiAngband.
+ */
+bool_ tgt_pt(int *x, int *y)
+{
+ char ch = 0;
+ int d, cu, cv;
+ int screen_wid, screen_hgt;
+ bool_ success = FALSE;
+
+ *x = p_ptr->px;
+ *y = p_ptr->py;
+
+ /* Get size */
+ get_screen_size(&screen_wid, &screen_hgt);
+
+ cu = Term->scr->cu;
+ cv = Term->scr->cv;
+ Term->scr->cu = 0;
+ Term->scr->cv = 1;
+ msg_print("Select a point and press space.");
+
+ while ((ch != 27) && (ch != ' '))
+ {
+ move_cursor_relative(*y, *x);
+ ch = inkey();
+ switch (ch)
+ {
+ case 27:
+ break;
+ case ' ':
+ success = TRUE;
+ break;
+ default:
+ /* Look up the direction */
+ d = get_keymap_dir(ch);
+
+ if (!d) break;
+
+ *x += ddx[d];
+ *y += ddy[d];
+
+ /* Hack -- Verify x */
+ if ((*x >= cur_wid - 1) || (*x >= panel_col_min + screen_wid)) (*x)--;
+ else if ((*x <= 0) || (*x <= panel_col_min)) (*x)++;
+
+ /* Hack -- Verify y */
+ if ((*y >= cur_hgt - 1) || (*y >= panel_row_min + screen_hgt)) (*y)--;
+ else if ((*y <= 0) || (*y <= panel_row_min)) (*y)++;
+
+ break;
+ }
+ }
+
+ Term->scr->cu = cu;
+ Term->scr->cv = cv;
+ Term_fresh();
+ return success;
+}
+
+
+bool_ gain_random_corruption(int choose_mut)
+{
+ exec_lua("gain_corruption()");
+ return (FALSE);
+}
+
+bool_ lose_corruption(int choose_mut)
+{
+ exec_lua("lose_corruption()");
+ return (FALSE);
+}
+
+bool_ lose_all_corruptions(void)
+{
+ exec_lua("lose_all_corruptions()");
+ return (FALSE);
+}
+
+bool_ get_hack_dir(int *dp)
+{
+ int dir;
+ cptr p;
+ char command;
+
+
+ /* Initialize */
+ (*dp) = 0;
+
+ /* Global direction */
+ dir = 0;
+
+ /* (No auto-targetting */
+
+ /* Ask until satisfied */
+ while (!dir)
+ {
+ /* Choose a prompt */
+ if (!target_okay())
+ {
+ p = "Direction ('*' to choose a target, Escape to cancel)? ";
+ }
+ else
+ {
+ p = "Direction ('5' for target, '*' to re-target, Escape to cancel)? ";
+ }
+
+ /* Get a command (or Cancel) */
+ if (!get_com(p, &command)) break;
+
+ /* Convert various keys to "standard" keys */
+ switch (command)
+ {
+ /* Use current target */
+ case 'T':
+ case 't':
+ case '.':
+ case '5':
+ case '0':
+ {
+ dir = 5;
+ break;
+ }
+
+ /* Set new target */
+ case '*':
+ {
+ if (target_set(TARGET_KILL)) dir = 5;
+ break;
+ }
+
+ default:
+ {
+ /* Look up the direction */
+ dir = get_keymap_dir(command);
+
+ break;
+ }
+ }
+
+ /* Verify requested targets */
+ if ((dir == 5) && !target_okay()) dir = 0;
+
+ /* Error */
+ if (!dir) bell();
+ }
+
+ /* No direction */
+ if (!dir) return (FALSE);
+
+ /* Save the direction */
+ command_dir = dir;
+
+ /* Check for confusion */
+ if (p_ptr->confused)
+ {
+ /* XXX XXX XXX */
+ /* Random direction */
+ dir = ddd[rand_int(8)];
+ }
+
+ /* Notice confusion */
+ if (command_dir != dir)
+ {
+ /* Warn the user */
+ msg_print("You are confused.");
+ }
+
+ /* Save direction */
+ (*dp) = dir;
+
+ /* A "valid" direction was entered */
+ return (TRUE);
+}
+
+/*
+ * Do we have at least one corruption?
+ */
+bool_ got_corruptions()
+{
+ int i, max;
+
+ max = exec_lua("return __corruptions_max");
+
+ for (i = 0; i < max; i++)
+ {
+ if (exec_lua(format("if test_depend_corrupt(%d) == TRUE then return TRUE else return FALSE end", i)))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Dump the corruption list
+ */
+void dump_corruptions(FILE *fff, bool_ color)
+{
+ int i, max;
+
+ if (!fff) return;
+
+ max = exec_lua("return __corruptions_max");
+
+ for (i = 0; i < max; i++)
+ {
+ if (exec_lua(format("if test_depend_corrupt(%d) == TRUE then return TRUE else return FALSE end", i)))
+ {
+ int c = exec_lua(format("return __corruptions[%d].color", i));
+
+ if (color)
+ fprintf(fff, "#####%c%s:\n", conv_color[c], string_exec_lua(format("return __corruptions[%d].name", i)));
+ else
+ fprintf(fff, "%s:\n", string_exec_lua(format("return __corruptions[%d].name", i)));
+ fprintf(fff, "%s\n", string_exec_lua(format("return __corruptions[%d].desc", i)));
+ }
+ }
+}
+
+/*
+ * Set "p_ptr->grace", notice observable changes
+ */
+void set_grace(s32b v)
+{
+ if (v < -300000) v = -300000;
+ if (v > 300000) v = 300000;
+ p_ptr->grace = v;
+ p_ptr->update |= PU_BONUS;
+ p_ptr->redraw |= (PR_PIETY);
+ handle_stuff();
+}
+
+bool_ test_object_wish(char *name, object_type *o_ptr, object_type *forge, char *what)
+{
+ int i, j, jb, save_aware;
+ char buf[200];
+
+ /* try all objects, this *IS* a very ugly and slow method :( */
+ for (i = 0; i < max_k_idx; i++)
+ {
+ object_kind *k_ptr = &k_info[i];
+
+ o_ptr = forge;
+
+ if (!k_ptr->name) continue;
+ if (k_ptr->flags3 & TR3_NORM_ART) continue;
+ if (k_ptr->flags3 & TR3_INSTA_ART) continue;
+ if (k_ptr->tval == TV_GOLD) continue;
+
+ object_prep(o_ptr, i);
+ o_ptr->name1 = 0;
+ o_ptr->name2 = 0;
+ apply_magic(o_ptr, dun_level, FALSE, FALSE, FALSE);
+ /* Hack : aware status must be restored after describing the item name */
+ save_aware = k_ptr->aware;
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ object_desc(buf, o_ptr, FALSE, 0);
+ strlower(buf);
+ k_ptr->aware = save_aware;
+
+ if (strstr(name, buf) ||
+ /* Hack hack hackery */
+ (o_ptr->tval == TV_ROD_MAIN && strstr(name, "rod of")))
+ {
+ /* try all ego */
+ for (j = max_e_idx - 1; j >= 0; j--)
+ {
+ ego_item_type *e_ptr = &e_info[j];
+ bool_ ok = FALSE;
+
+ if (j && !e_ptr->name) continue;
+
+ /* Must have the correct fields */
+ if (j)
+ {
+ int z;
+
+ for (z = 0; z < 6; z++)
+ {
+ if (e_ptr->tval[z] == k_ptr->tval)
+ {
+ if ((e_ptr->min_sval[z] <= k_ptr->sval) &&
+ (e_ptr->max_sval[z] >= k_ptr->sval)) ok = TRUE;
+ }
+ if (ok) break;
+ }
+ if (!ok)
+ {
+ continue;
+ }
+ }
+
+ /* try all ego */
+ for (jb = max_e_idx - 1; jb >= 0; jb--)
+ {
+ ego_item_type *eb_ptr = &e_info[jb];
+ bool_ ok = FALSE;
+
+ if (jb && !eb_ptr->name) continue;
+
+ if (j && jb && (e_ptr->before == eb_ptr->before)) continue;
+
+ /* Must have the correct fields */
+ if (jb)
+ {
+ int z;
+
+ for (z = 0; z < 6; z++)
+ {
+ if (eb_ptr->tval[z] == k_ptr->tval)
+ {
+ if ((eb_ptr->min_sval[z] <= k_ptr->sval) &&
+ (eb_ptr->max_sval[z] >= k_ptr->sval)) ok = TRUE;
+ }
+ if (ok) break;
+ }
+ if (!ok)
+ {
+ continue;
+ }
+ }
+
+ object_prep(o_ptr, i);
+ o_ptr->name1 = 0;
+ o_ptr->name2 = j;
+ o_ptr->name2b = jb;
+ apply_magic(o_ptr, dun_level, FALSE, FALSE, FALSE);
+ object_aware(o_ptr);
+ object_known(o_ptr);
+ object_desc(buf, o_ptr, FALSE, 0);
+ strlower(buf);
+
+ if (!stricmp(buf, name))
+ {
+ /* Don't search any more */
+ return TRUE;
+ }
+ else
+ {
+ /* Restore again the aware status */
+ k_ptr->aware = save_aware;
+ }
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+void clean_wish_name(char *buf, char *name)
+{
+ char *p;
+ int i, j;
+
+ /* Lowercase the wish */
+ strlower(buf);
+
+ /* Nuke uneccesary spaces */
+ p = buf;
+ while (*p == ' ') p++;
+ i = 0;
+ j = 0;
+ while (p[i])
+ {
+ if ((p[i] == ' ') && (p[i + 1] == ' '))
+ {
+ i++;
+ continue;
+ }
+ name[j++] = p[i++];
+ }
+ name[j++] = '\0';
+ if (j)
+ {
+ j--;
+ while (j && (name[j] == ' '))
+ {
+ name[j] = '\0';
+ j--;
+ }
+ }
+}
+
+/*
+ * Allow the player to make a wish
+ */
+void make_wish(void)
+{
+ char buf[200], name[200], *mname;
+ int i, j, mstatus = MSTATUS_ENEMY;
+ object_type forge, *o_ptr = &forge;
+
+ /* Make an empty string */
+ buf[0] = 0;
+
+ /* Ask for the wish */
+ if (!get_string("Wish for what? ", buf, 80)) return;
+
+ clean_wish_name(buf, name);
+
+ /* You can't wish for a wish! */
+ if (strstr(name, "wish"))
+ {
+ msg_print("You can't wish for a wish!");
+ return;
+ }
+
+ if (test_object_wish(name, o_ptr, &forge, "wish"))
+ {
+ msg_print("Your wish becomes truth!");
+
+ /* Give it to the player */
+ drop_near(o_ptr, -1, p_ptr->py, p_ptr->px);
+
+ return;
+ }
+
+ /* try monsters */
+ if (prefix(name, "enemy "))
+ {
+ mstatus = MSTATUS_ENEMY;
+ mname = name + 6;
+ }
+ else if (prefix(name, "neutral "))
+ {
+ mstatus = MSTATUS_NEUTRAL;
+ mname = name + 8;
+ }
+ else if (prefix(name, "friendly "))
+ {
+ mstatus = MSTATUS_FRIEND;
+ mname = name + 9;
+ }
+ else if (prefix(name, "pet "))
+ {
+ mstatus = MSTATUS_PET;
+ mname = name + 4;
+ }
+ else if (prefix(name, "companion "))
+ {
+ if (can_create_companion()) mstatus = MSTATUS_COMPANION;
+ else mstatus = MSTATUS_PET;
+ mname = name + 10;
+ }
+ else mname = name;
+ for (i = 1; i < max_r_idx; i++)
+ {
+ monster_race *r_ptr = &r_info[i];
+
+ if (!r_ptr->name) continue;
+
+ if (r_ptr->flags9 & RF9_SPECIAL_GENE) continue;
+ if (r_ptr->flags9 & RF9_NEVER_GENE) continue;
+ if (r_ptr->flags1 & RF1_UNIQUE) continue;
+
+ sprintf(buf, "%s", r_ptr->name + r_name);
+ strlower(buf);
+
+ if (strstr(mname, buf))
+ {
+ /* try all ego */
+ for (j = max_re_idx - 1; j >= 0; j--)
+ {
+ monster_ego *re_ptr = &re_info[j];
+
+ if (j && !re_ptr->name) continue;
+
+ if (!mego_ok(i, j)) continue;
+
+ if (j)
+ {
+ if (re_ptr->before) sprintf(buf, "%s %s", re_name + re_ptr->name, r_ptr->name + r_name);
+ else sprintf(buf, "%s %s", r_ptr->name + r_name, re_name + re_ptr->name);
+ }
+ else
+ {
+ sprintf(buf, "%s", r_ptr->name + r_name);
+ }
+ strlower(buf);
+
+ if (!stricmp(mname, buf))
+ {
+ int wy = p_ptr->py, wx = p_ptr->px;
+ int attempts = 100;
+
+ do
+ {
+ scatter(&wy, &wx, p_ptr->py, p_ptr->px, 5);
+ }
+ while (!(in_bounds(wy, wx) && cave_floor_bold(wy, wx)) && --attempts);
+
+ /* Create the monster */
+ if (place_monster_one(wy, wx, i, j, FALSE, mstatus))
+ msg_print("Your wish becomes truth!");
+
+ /* Don't search any more */
+ return;
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Corrupted have a 1/3 chance of losing a mutation each time this is called,
+ * assuming they have any in the first place
+ */
+void corrupt_corrupted(void)
+{
+ if (magik(45))
+ {
+ lose_corruption(0);
+ }
+ else
+ {
+ gain_random_corruption(0);
+ }
+
+ /* We are done. */
+ return;
+}
+
+/*
+ * Change to an other class
+ */
+void switch_class(int sclass)
+{
+ p_ptr->pclass = sclass;
+ cp_ptr = &class_info[p_ptr->pclass];
+}
+
+/*
+ * Change to an other subclass
+ */
+void switch_subclass(int sclass)
+{
+ p_ptr->pspec = sclass;
+ spp_ptr = &class_info[p_ptr->pclass].spec[p_ptr->pspec];
+}
+
+/*
+ * Change to an other subrace
+ */
+void switch_subrace(int racem, bool_ copy_old)
+{
+ if ((racem < 0) && (racem >= max_rmp_idx)) return;
+
+ /* If we switch to the saved subrace, we copy over the old subrace data */
+ if (copy_old && (racem == SUBRACE_SAVE))
+ {
+ s32b old_title = race_mod_info[SUBRACE_SAVE].title;
+ s32b old_desc = race_mod_info[SUBRACE_SAVE].desc;
+
+ COPY(&race_mod_info[SUBRACE_SAVE], &race_mod_info[p_ptr->pracem], player_race_mod);
+
+ race_mod_info[SUBRACE_SAVE].title = old_title;
+ race_mod_info[SUBRACE_SAVE].desc = old_desc;
+ strcpy(race_mod_info[SUBRACE_SAVE].title + rmp_name, race_mod_info[p_ptr->pracem].title + rmp_name);
+ }
+
+ p_ptr->pracem = racem;
+ rmp_ptr = &race_mod_info[p_ptr->pracem];
+}
+
+cptr get_subrace_title(int racem)
+{
+ return race_mod_info[racem].title + rmp_name;
+}
+
+void set_subrace_title(int racem, cptr name)
+{
+ strcpy(race_mod_info[racem].title + rmp_name, name);
+}
+
+/*
+ * Rebirth, recalc hp & exp/level
+ */
+void do_rebirth()
+{
+ /* Experience factor */
+ p_ptr->expfact = rp_ptr->r_exp + rmp_ptr->r_exp + cp_ptr->c_exp;
+
+ /* Hitdice */
+ p_ptr->hitdie = rp_ptr->r_mhp + rmp_ptr->r_mhp + cp_ptr->c_mhp;
+
+ /* Recalc HP */
+ do_cmd_rerate();
+
+ /* Change the level if needed */
+ check_experience();
+ p_ptr->max_plv = p_ptr->lev;
+
+ /* Redraw/calc stuff */
+ p_ptr->redraw |= (PR_BASIC);
+ p_ptr->update |= (PU_BONUS);
+ handle_stuff();
+
+ lite_spot(p_ptr->py, p_ptr->px);
+}
+
+/*
+ * Quick mimic name to index function
+ */
+int resolve_mimic_name(cptr name)
+{
+ s32b idx;
+
+ call_lua("resolve_mimic_name", "(s)", "d", name, &idx);
+ return idx;
+}
diff --git a/src/z-form.c b/src/z-form.c
new file mode 100644
index 00000000..b3d5d005
--- /dev/null
+++ b/src/z-form.c
@@ -0,0 +1,831 @@
+/* File: z-form.c */
+
+/* Purpose: Low level text formatting -BEN- */
+
+#include "z-form.h"
+
+#include "z-util.h"
+#include "z-virt.h"
+
+
+/*
+ * Here is some information about the routines in this file.
+ *
+ * In general, the following routines take a "buffer", a "max length",
+ * a "format string", and some "arguments", and use the format string
+ * and the arguments to create a (terminated) string in the buffer
+ * (using only the first "max length" bytes), and return the "length"
+ * of the resulting string, not including the (mandatory) terminator.
+ *
+ * The format strings allow the basic "sprintf()" format sequences, though
+ * some of them are processed slightly more carefully or portably, as well
+ * as a few "special" sequences, including the "%r" and "%v" sequences, and
+ * the "capilitization" sequences of "%C", "%S", and "%V".
+ *
+ * Note that some "limitations" are enforced by the current implementation,
+ * for example, no "format sequence" can exceed 100 characters, including any
+ * "length" restrictions, and the result of combining and "format sequence"
+ * with the relevent "arguments" must not exceed 1000 characters.
+ *
+ * These limitations could be fixed by stealing some of the code from,
+ * say, "vsprintf()" and placing it into my "vstrnfmt()" function.
+ *
+ * Note that a "^" inside a "format sequence" causes the first non-space
+ * character in the string resulting from the combination of the format
+ * sequence and the argument(s) to be "capitalized" if possible. Note
+ * that the "^" character is removed before the "standard" formatting
+ * routines are called. Likewise, a "*" inside a "format sequence" is
+ * removed from the "format sequence", and replaced by the textual form
+ * of the next argument in the argument list. See examples below.
+ *
+ * Legal format characters: %,n,p,c,s,d,i,o,u,X,x,E,e,F,f,G,g,r,v.
+ *
+ * Format("%%")
+ * Append the literal "%".
+ * No legal modifiers.
+ *
+ * Format("%n", int *np)
+ * Save the current length into (*np).
+ * No legal modifiers.
+ *
+ * Format("%p", vptr v)
+ * Append the pointer "v" (implementation varies).
+ * No legal modifiers.
+ *
+ * Format("%E", double r)
+ * Format("%F", double r)
+ * Format("%G", double r)
+ * Format("%e", double r)
+ * Format("%f", double r)
+ * Format("%g", double r)
+ * Append the double "r", in various formats.
+ *
+ * Format("%ld", long int i)
+ * Append the long integer "i".
+ *
+ * Format("%d", int i)
+ * Append the integer "i".
+ *
+ * Format("%lu", unsigned long int i)
+ * Append the unsigned long integer "i".
+ *
+ * Format("%u", unsigned int i)
+ * Append the unsigned integer "i".
+ *
+ * Format("%lo", unsigned long int i)
+ * Append the unsigned long integer "i", in octal.
+ *
+ * Format("%o", unsigned int i)
+ * Append the unsigned integer "i", in octal.
+ *
+ * Format("%lX", unsigned long int i)
+ * Note -- use all capital letters
+ * Format("%lx", unsigned long int i)
+ * Append the unsigned long integer "i", in hexidecimal.
+ *
+ * Format("%X", unsigned int i)
+ * Note -- use all capital letters
+ * Format("%x", unsigned int i)
+ * Append the unsigned integer "i", in hexidecimal.
+ *
+ * Format("%c", char c)
+ * Append the character "c".
+ * Do not use the "+" or "0" flags.
+ *
+ * Format("%s", cptr s)
+ * Append the string "s".
+ * Do not use the "+" or "0" flags.
+ * Note that a "NULL" value of "s" is converted to the empty string.
+ *
+ * Format("%V", vptr v)
+ * Note -- possibly significant mode flag
+ * Format("%v", vptr v)
+ * Append the object "v", using the current "user defined print routine".
+ * User specified modifiers, often ignored.
+ *
+ * Format("%r", vstrnfmt_aux_func *fp)
+ * Set the "user defined print routine" (vstrnfmt_aux) to "fp".
+ * No legal modifiers.
+ *
+ *
+ * For examples below, assume "int n = 0; int m = 100; char buf[100];",
+ * plus "char *s = NULL;", and unknown values "char *txt; int i;".
+ *
+ * For example: "n = strnfmt(buf, -1, "(Max %d)", i);" will have a
+ * similar effect as "sprintf(buf, "(Max %d)", i); n = strlen(buf);".
+ *
+ * For example: "(void)strnfmt(buf, 16, "%s", txt);" will have a similar
+ * effect as "strncpy(buf, txt, 16); buf[15] = '\0';".
+ *
+ * For example: "if (strnfmt(buf, 16, "%s", txt) < 16) ..." will have
+ * a similar effect as "strcpy(buf, txt)" but with bounds checking.
+ *
+ * For example: "s = buf; s += vstrnfmt(s, -1, ...); ..." will allow
+ * multiple "appends" to "buf" (at the cost of losing the max-length info).
+ *
+ * For example: "s = buf; n = vstrnfmt(s+n, 100-n, ...); ..." will allow
+ * multiple bounded "appends" to "buf", with constant access to "strlen(buf)".
+ *
+ * For example: "format("The %r%v was destroyed!", obj_desc, obj);"
+ * (where "obj_desc(buf, max, fmt, obj)" will "append" a "description"
+ * of the given object to the given buffer, and return the total length)
+ * will return a "useful message" about the object "obj", for example,
+ * "The Large Shield was destroyed!".
+ *
+ * For example: "format("%^-.*s", i, txt)" will produce a string containing
+ * the first "i" characters of "txt", left justified, with the first non-space
+ * character capitilized, if reasonable.
+ */
+
+
+
+
+
+/*
+ * The "type" of the "user defined print routine" pointer
+ */
+typedef uint (*vstrnfmt_aux_func)(char *buf, uint max, cptr fmt, vptr arg);
+
+/*
+ * The "default" user defined print routine. Ignore the "fmt" string.
+ */
+static uint vstrnfmt_aux_dflt(char *buf, uint max, cptr fmt, vptr arg)
+{
+ uint len;
+ char tmp[32];
+
+ /* XXX XXX */
+ fmt = fmt ? fmt : 0;
+
+ /* Pointer display */
+ sprintf(tmp, "<<%p>>", arg);
+ len = strlen(tmp);
+ if (len >= max) len = max - 1;
+ tmp[len] = '\0';
+ strcpy(buf, tmp);
+ return (len);
+}
+
+/*
+ * The "current" user defined print routine. It can be changed
+ * dynamically by sending the proper "%r" sequence to "vstrnfmt()"
+ */
+static vstrnfmt_aux_func vstrnfmt_aux = vstrnfmt_aux_dflt;
+
+
+
+/*
+ * Basic "vararg" format function.
+ *
+ * This function takes a buffer, a max byte count, a format string, and
+ * a va_list of arguments to the format string, and uses the format string
+ * and the arguments to create a string to the buffer. The string is
+ * derived from the format string and the arguments in the manner of the
+ * "sprintf()" function, but with some extra "format" commands. Note that
+ * this function will never use more than the given number of bytes in the
+ * buffer, preventing messy invalid memory references. This function then
+ * returns the total number of non-null bytes written into the buffer.
+ *
+ * Method: Let "str" be the (unlimited) created string, and let "len" be the
+ * smaller of "max-1" and "strlen(str)". We copy the first "len" chars of
+ * "str" into "buf", place "\0" into buf[len], and return "len".
+ *
+ * In English, we do a sprintf() into "buf", a buffer with size "max",
+ * and we return the resulting value of "strlen(buf)", but we allow some
+ * special format commands, and we are more careful than "sprintf()".
+ *
+ * Typically, "max" is in fact the "size" of "buf", and thus represents
+ * the "number" of chars in "buf" which are ALLOWED to be used. An
+ * alternative definition would have required "buf" to hold at least
+ * "max+1" characters, and would have used that extra character only
+ * in the case where "buf" was too short for the result. This would
+ * give an easy test for "overflow", but a less "obvious" semantics.
+ *
+ * Note that if the buffer was "too short" to hold the result, we will
+ * always return "max-1", but we also return "max-1" if the buffer was
+ * "just long enough". We could have returned "max" if the buffer was
+ * too short, not written a null, and forced the programmer to deal with
+ * this special case, but I felt that it is better to at least give a
+ * "usable" result when the buffer was too long instead of either giving
+ * a memory overwrite like "sprintf()" or a non-terminted string like
+ * "strncpy()". Note that "strncpy()" also "null-pads" the result.
+ *
+ * Note that in most cases "just long enough" is probably "too short".
+ *
+ * We should also consider extracting and processing the "width" and other
+ * "flags" by hand, it might be more "accurate", and it would allow us to
+ * remove the limit (1000 chars) on the result of format sequences.
+ *
+ * Also, some sequences, such as "%+d" by hand, do not work on all machines,
+ * and could thus be correctly handled here.
+ *
+ * Error detection in this routine is not very graceful, in particular,
+ * if an error is detected in the format string, we simply "pre-terminate"
+ * the given buffer to a length of zero, and return a "length" of zero.
+ * The contents of "buf", except for "buf[0]", may then be undefined.
+ */
+uint vstrnfmt(char *buf, uint max, cptr fmt, va_list vp)
+{
+ cptr s;
+
+ /* The argument is "long" */
+ bool_ do_long;
+
+ /* The argument needs "processing" */
+ bool_ do_xtra;
+
+ /* Bytes used in buffer */
+ uint n;
+
+ /* Bytes used in format sequence */
+ uint q;
+
+ /* Format sequence */
+ char aux[128];
+
+ /* Resulting string */
+ char tmp[1024];
+
+
+ /* Mega-Hack -- treat "illegal" length as "infinite" */
+ if (!max) max = 32767;
+
+ /* Mega-Hack -- treat "no format" as "empty string" */
+ if (!fmt) fmt = "";
+
+
+ /* Begin the buffer */
+ n = 0;
+
+ /* Begin the format string */
+ s = fmt;
+
+ /* Scan the format string */
+ while (TRUE)
+ {
+ /* All done */
+ if (!*s) break;
+
+ /* Normal character */
+ if (*s != '%')
+ {
+ /* Check total length */
+ if (n == max - 1) break;
+
+ /* Save the character */
+ buf[n++] = *s++;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Skip the "percent" */
+ s++;
+
+ /* Pre-process "%%" */
+ if (*s == '%')
+ {
+ /* Check total length */
+ if (n == max - 1) break;
+
+ /* Save the percent */
+ buf[n++] = '%';
+
+ /* Skip the "%" */
+ s++;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Pre-process "%n" */
+ if (*s == 'n')
+ {
+ int *arg;
+
+ /* Access the next argument */
+ arg = va_arg(vp, int *);
+
+ /* Save the current length */
+ (*arg) = n;
+
+ /* Skip the "n" */
+ s++;
+
+ /* Continue */
+ continue;
+ }
+
+ /* Hack -- Pre-process "%r" */
+ if (*s == 'r')
+ {
+ /* Extract the next argument, and save it (globally) */
+ vstrnfmt_aux = va_arg(vp, vstrnfmt_aux_func);
+
+ /* Skip the "r" */
+ s++;
+
+ /* Continue */
+ continue;
+ }
+
+
+ /* Begin the "aux" string */
+ q = 0;
+
+ /* Save the "percent" */
+ aux[q++] = '%';
+
+ /* Assume no "long" argument */
+ do_long = FALSE;
+
+ /* Assume no "xtra" processing */
+ do_xtra = FALSE;
+
+ /* Build the "aux" string */
+ while (TRUE)
+ {
+ /* Error -- format sequence is not terminated */
+ if (!*s)
+ {
+ /* Terminate the buffer */
+ buf[0] = '\0';
+
+ /* Return "error" */
+ return (0);
+ }
+
+ /* Error -- format sequence may be too long */
+ if (q > 100)
+ {
+ /* Terminate the buffer */
+ buf[0] = '\0';
+
+ /* Return "error" */
+ return (0);
+ }
+
+ /* Handle "alphabetic" chars */
+ if (isalpha(*s))
+ {
+ /* Hack -- handle "long" request */
+ if (*s == 'l')
+ {
+ /* Save the character */
+ aux[q++] = *s++;
+
+ /* Note the "long" flag */
+ do_long = TRUE;
+ }
+
+ /* Mega-Hack -- handle "extra-long" request */
+ else if (*s == 'L')
+ {
+ /* Error -- illegal format char */
+ buf[0] = '\0';
+
+ /* Return "error" */
+ return (0);
+ }
+
+ /* Handle normal end of format sequence */
+ else
+ {
+ /* Save the character */
+ aux[q++] = *s++;
+
+ /* Stop processing the format sequence */
+ break;
+ }
+ }
+
+ /* Handle "non-alphabetic" chars */
+ else
+ {
+ /* Hack -- Handle 'star' (for "variable length" argument) */
+ if (*s == '*')
+ {
+ int arg;
+
+ /* Access the next argument */
+ arg = va_arg(vp, int);
+
+ /* Hack -- append the "length" */
+ sprintf(aux + q, "%d", arg);
+
+ /* Hack -- accept the "length" */
+ while (aux[q]) q++;
+
+ /* Skip the "*" */
+ s++;
+ }
+
+ /* Mega-Hack -- Handle 'caret' (for "uppercase" request) */
+ else if (*s == '^')
+ {
+ /* Note the "xtra" flag */
+ do_xtra = TRUE;
+
+ /* Skip the "^" */
+ s++;
+ }
+
+ /* Collect "normal" characters (digits, "-", "+", ".", etc) */
+ else
+ {
+ /* Save the character */
+ aux[q++] = *s++;
+ }
+ }
+ }
+
+
+ /* Terminate "aux" */
+ aux[q] = '\0';
+
+ /* Clear "tmp" */
+ tmp[0] = '\0';
+
+ /* Process the "format" char */
+ switch (aux[q - 1])
+ {
+ /* Simple Character -- standard format */
+ case 'c':
+ {
+ int arg;
+
+ /* Access next argument */
+ arg = va_arg(vp, int);
+
+ /* Format the argument */
+ sprintf(tmp, aux, arg);
+
+ /* Done */
+ break;
+ }
+
+ /* Signed Integers -- standard format */
+ case 'd':
+ case 'i':
+ {
+ if (do_long)
+ {
+ long arg;
+
+ /* Access next argument */
+ arg = va_arg(vp, long);
+
+ /* Format the argument */
+ sprintf(tmp, aux, arg);
+ }
+ else
+ {
+ int arg;
+
+ /* Access next argument */
+ arg = va_arg(vp, int);
+
+ /* Format the argument */
+ sprintf(tmp, aux, arg);
+ }
+
+ /* Done */
+ break;
+ }
+
+ /* Unsigned Integers -- various formats */
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ {
+ if (do_long)
+ {
+ unsigned long arg;
+
+ /* Access next argument */
+ arg = va_arg(vp, unsigned long);
+
+ /* Format the argument */
+ sprintf(tmp, aux, arg);
+ }
+ else
+ {
+ unsigned int arg;
+
+ /* Access next argument */
+ arg = va_arg(vp, unsigned int);
+
+ /* Format the argument */
+ sprintf(tmp, aux, arg);
+ }
+
+ /* Done */
+ break;
+ }
+
+ /* Floating Point -- various formats */
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ {
+ double arg;
+
+ /* Access next argument */
+ arg = va_arg(vp, double);
+
+ /* Format the argument */
+ sprintf(tmp, aux, arg);
+
+ /* Done */
+ break;
+ }
+
+ /* Pointer -- implementation varies */
+ case 'p':
+ {
+ vptr arg;
+
+ /* Access next argument */
+ arg = va_arg(vp, vptr);
+
+ /* Format the argument */
+ sprintf(tmp, aux, arg);
+
+ /* Done */
+ break;
+ }
+
+ /* String */
+ case 's':
+ {
+ cptr arg;
+
+ /* Access next argument */
+ arg = va_arg(vp, cptr);
+
+ /* Hack -- convert NULL to EMPTY */
+ if (!arg) arg = "";
+
+ /* Format the argument */
+ sprintf(tmp, aux, arg);
+
+ /* Done */
+ break;
+ }
+
+ /* User defined data */
+ case 'V':
+ case 'v':
+ {
+ vptr arg;
+
+ /* Access next argument */
+ arg = va_arg(vp, vptr);
+
+ /* Format the "user data" */
+ (void)vstrnfmt_aux(tmp, 1000, aux, arg);
+
+ /* Done */
+ break;
+ }
+
+
+ /* Oops */
+ default:
+ {
+ /* Error -- illegal format char */
+ buf[0] = '\0';
+
+ /* Return "error" */
+ return (0);
+ }
+ }
+
+
+ /* Mega-Hack -- handle "capitilization" */
+ if (do_xtra)
+ {
+ /* Now append "tmp" to "buf" */
+ for (q = 0; tmp[q]; q++)
+ {
+ /* Notice first non-space */
+ if (!isspace(tmp[q]))
+ {
+ /* Capitalize if possible */
+ if (islower(tmp[q])) tmp[q] = toupper(tmp[q]);
+
+ /* Done */
+ break;
+ }
+ }
+ }
+
+ /* Now append "tmp" to "buf" */
+ for (q = 0; tmp[q]; q++)
+ {
+ /* Check total length */
+ if (n == max - 1) break;
+
+ /* Save the character */
+ buf[n++] = tmp[q];
+ }
+ }
+
+
+ /* Terminate buffer */
+ buf[n] = '\0';
+
+ /* Return length */
+ return (n);
+}
+
+
+/*
+ * Do a vstrnfmt (see above) into a (growable) static buffer.
+ * This buffer is usable for very short term formatting of results.
+ */
+char *vformat(cptr fmt, va_list vp)
+{
+ static char *format_buf = NULL;
+ static huge format_len = 0;
+
+ /* Initial allocation */
+ if (!format_buf)
+ {
+ format_len = 1024;
+ C_MAKE(format_buf, format_len, char);
+ }
+
+ /* Null format yields last result */
+ if (!fmt) return (format_buf);
+
+ /* Keep going until successful */
+ while (1)
+ {
+ uint len;
+
+ /* Build the string */
+ len = vstrnfmt(format_buf, format_len, fmt, vp);
+
+ /* Success */
+ if (len < format_len - 1) break;
+
+ /* Grow the buffer */
+ C_KILL(format_buf, format_len, char);
+ format_len = format_len * 2;
+ C_MAKE(format_buf, format_len, char);
+ }
+
+ /* Return the new buffer */
+ return (format_buf);
+}
+
+
+
+/*
+ * Do a vstrnfmt (see above) into a buffer of a given size.
+ */
+uint strnfmt(char *buf, uint max, cptr fmt, ...)
+{
+ uint len;
+
+ va_list vp;
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Do a virtual fprintf to stderr */
+ len = vstrnfmt(buf, max, fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Return the number of bytes written */
+ return (len);
+}
+
+
+/*
+ * Do a vstrnfmt (see above) into a buffer of unknown size.
+ * Since the buffer size is unknown, the user better verify the args.
+ */
+uint strfmt(char *buf, cptr fmt, ...)
+{
+ uint len;
+
+ va_list vp;
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Build the string, assume 32K buffer */
+ len = vstrnfmt(buf, 32767, fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Return the number of bytes written */
+ return (len);
+}
+
+
+
+
+/*
+ * Do a vstrnfmt() into (see above) into a (growable) static buffer.
+ * This buffer is usable for very short term formatting of results.
+ * Note that the buffer is (technically) writable, but only up to
+ * the length of the string contained inside it.
+ */
+char *format(cptr fmt, ...)
+{
+ char *res;
+ va_list vp;
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Format the args */
+ res = vformat(fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Return the result */
+ return (res);
+}
+
+
+
+
+/*
+ * Vararg interface to plog()
+ */
+void plog_fmt(cptr fmt, ...)
+{
+ char *res;
+ va_list vp;
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Format the args */
+ res = vformat(fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Call plog */
+ plog(res);
+}
+
+
+
+/*
+ * Vararg interface to quit()
+ */
+void quit_fmt(cptr fmt, ...)
+{
+ char *res;
+ va_list vp;
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* Format */
+ res = vformat(fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Call quit() */
+ quit(res);
+}
+
+
+
+/*
+ * Vararg interface to core()
+ */
+void core_fmt(cptr fmt, ...)
+{
+ char *res;
+ va_list vp;
+
+ /* Begin the Varargs Stuff */
+ va_start(vp, fmt);
+
+ /* If requested, Do a virtual fprintf to stderr */
+ res = vformat(fmt, vp);
+
+ /* End the Varargs Stuff */
+ va_end(vp);
+
+ /* Call core() */
+ core(res);
+}
+
+
diff --git a/src/z-form.h b/src/z-form.h
new file mode 100644
index 00000000..2dcfa96c
--- /dev/null
+++ b/src/z-form.h
@@ -0,0 +1,54 @@
+/* File z-form.h */
+
+#ifndef INCLUDED_Z_FORM_H
+#define INCLUDED_Z_FORM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "h-basic.h"
+
+/*
+ * This file provides functions very similar to "sprintf()", but which
+ * not only parse some additional "format sequences", but also enforce
+ * bounds checking, and allow repeated "appends" to the same buffer.
+ *
+ * See "z-form.c" for more detailed information about the routines,
+ * including a list of the legal "format sequences".
+ *
+ * This file makes use of both "z-util.c" and "z-virt.c"
+ */
+
+
+/**** Available Functions ****/
+
+/* Format arguments into given bounded-length buffer */
+extern uint vstrnfmt(char *buf, uint max, cptr fmt, va_list vp);
+
+/* Simple interface to "vstrnfmt()" */
+extern uint strnfmt(char *buf, uint max, cptr fmt, ...);
+
+/* Simple interface to "vstrnfmt()", assuming infinite length */
+extern uint strfmt(char *buf, cptr fmt, ...);
+
+/* Format arguments into a static resizing buffer */
+extern char *vformat(cptr fmt, va_list vp);
+
+/* Simple interface to "vformat()" */
+extern char *format(cptr fmt, ...);
+
+/* Vararg interface to "plog()", using "format()" */
+extern void plog_fmt(cptr fmt, ...);
+
+/* Vararg interface to "quit()", using "format()" */
+extern void quit_fmt(cptr fmt, ...);
+
+/* Vararg interface to "core()", using "format()" */
+extern void core_fmt(cptr fmt, ...);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/z-rand.c b/src/z-rand.c
new file mode 100644
index 00000000..ca5b49ae
--- /dev/null
+++ b/src/z-rand.c
@@ -0,0 +1,355 @@
+/* File: z-rand.c */
+
+/* Purpose: a simple random number generator -BEN- */
+
+#include "z-rand.h"
+
+
+
+
+/*
+ * Angband 2.7.9 introduced a new (optimized) random number generator,
+ * based loosely on the old "random.c" from Berkeley but with some major
+ * optimizations and algorithm changes. See below for more details.
+ *
+ * Code by myself (benh@phial.com) and Randy (randy@stat.tamu.edu).
+ *
+ * This code provides (1) a "decent" RNG, based on the "BSD-degree-63-RNG"
+ * used in Angband 2.7.8, but rather optimized, and (2) a "simple" RNG,
+ * based on the simple "LCRNG" currently used in Angband, but "corrected"
+ * to give slightly better values. Both of these are available in two
+ * flavors, first, the simple "mod" flavor, which is fast, but slightly
+ * biased at high values, and second, the simple "div" flavor, which is
+ * less fast (and potentially non-terminating) but which is not biased
+ * and is much less subject to low-bit-non-randomness problems.
+ *
+ * You can select your favorite flavor by proper definition of the
+ * "rand_int()" macro in the "defines.h" file.
+ *
+ * Note that, in Angband 2.8.0, the "state" table will be saved in the
+ * savefile, so a special "initialization" phase will be necessary.
+ *
+ * Note the use of the "simple" RNG, first you activate it via
+ * "Rand_quick = TRUE" and "Rand_value = seed" and then it is used
+ * automatically used instead of the "complex" RNG, and when you are
+ * done, you de-activate it via "Rand_quick = FALSE" or choose a new
+ * seed via "Rand_value = seed".
+ */
+
+
+/*
+ * Random Number Generator -- Linear Congruent RNG
+ */
+#define LCRNG(X) ((X) * 1103515245 + 12345)
+
+
+
+/*
+ * Use the "simple" LCRNG
+ */
+bool_ Rand_quick = TRUE;
+
+
+/*
+ * Current "value" of the "simple" RNG
+ */
+u32b Rand_value;
+
+
+/*
+ * Current "index" for the "complex" RNG
+ */
+u16b Rand_place;
+
+/*
+ * Current "state" table for the "complex" RNG
+ */
+u32b Rand_state[RAND_DEG];
+
+
+
+/*
+ * Initialize the "complex" RNG using a new seed
+ */
+void Rand_state_init(u32b seed)
+{
+ int i, j;
+
+ /* Seed the table */
+ Rand_state[0] = seed;
+
+ /* Propagate the seed */
+ for (i = 1; i < RAND_DEG; i++) Rand_state[i] = LCRNG(Rand_state[i - 1]);
+
+ /* Cycle the table ten times per degree */
+ for (i = 0; i < RAND_DEG * 10; i++)
+ {
+ /* Acquire the next index */
+ j = Rand_place + 1;
+ if (j == RAND_DEG) j = 0;
+
+ /* Update the table, extract an entry */
+ Rand_state[j] += Rand_state[Rand_place];
+
+ /* Advance the index */
+ Rand_place = j;
+ }
+}
+
+
+/*
+ * Extract a "random" number from 0 to m-1, via "modulus"
+ *
+ * Note that "m" should probably be less than 500000, or the
+ * results may be rather biased towards low values.
+ */
+s32b Rand_mod(s32b m)
+{
+ int j;
+ u32b r;
+
+ /* Hack -- simple case */
+ if (m <= 1) return (0);
+
+ /* Use the "simple" RNG */
+ if (Rand_quick)
+ {
+ /* Cycle the generator */
+ r = (Rand_value = LCRNG(Rand_value));
+
+ /* Mutate a 28-bit "random" number */
+ r = (r >> 4) % m;
+ }
+
+ /* Use the "complex" RNG */
+ else
+ {
+ /* Acquire the next index */
+ j = Rand_place + 1;
+ if (j == RAND_DEG) j = 0;
+
+ /* Update the table, extract an entry */
+ r = (Rand_state[j] += Rand_state[Rand_place]);
+
+ /* Advance the index */
+ Rand_place = j;
+
+ /* Extract a "random" number */
+ r = (r >> 4) % m;
+ }
+
+ /* Use the value */
+ return (r);
+}
+
+
+/*
+ * Extract a "random" number from 0 to m-1, via "division"
+ *
+ * This method selects "random" 28-bit numbers, and then uses
+ * division to drop those numbers into "m" different partitions,
+ * plus a small non-partition to reduce bias, taking as the final
+ * value the first "good" partition that a number falls into.
+ *
+ * This method has no bias, and is much less affected by patterns
+ * in the "low" bits of the underlying RNG's.
+ */
+s32b Rand_div(s32b m)
+{
+ u32b r, n;
+
+ /* Hack -- simple case */
+ if (m <= 1) return (0);
+
+ /* Partition size */
+ n = (0x10000000 / m);
+
+ /* Use a simple RNG */
+ if (Rand_quick)
+ {
+ /* Wait for it */
+ while (1)
+ {
+ /* Cycle the generator */
+ r = (Rand_value = LCRNG(Rand_value));
+
+ /* Mutate a 28-bit "random" number */
+ r = ((r >> 4) & 0x0FFFFFFF) / n;
+
+ /* Done */
+ if (r < (u32b)m) break;
+ }
+ }
+
+ /* Use a complex RNG */
+ else
+ {
+ /* Wait for it */
+ while (1)
+ {
+ int j;
+
+ /* Acquire the next index */
+ j = Rand_place + 1;
+ if (j == RAND_DEG) j = 0;
+
+ /* Update the table, extract an entry */
+ r = (Rand_state[j] += Rand_state[Rand_place]);
+
+ /* Hack -- extract a 28-bit "random" number */
+ r = ((r >> 4) & 0x0FFFFFFF) / n;
+
+ /* Advance the index */
+ Rand_place = j;
+
+ /* Done */
+ if (r < (u32b)m) break;
+ }
+ }
+
+ /* Use the value */
+ return (r);
+}
+
+
+
+
+/*
+ * The number of entries in the "randnor_table"
+ */
+#define RANDNOR_NUM 256
+
+/*
+ * The standard deviation of the "randnor_table"
+ */
+#define RANDNOR_STD 64
+
+/*
+ * The normal distribution table for the "randnor()" function (below)
+ */
+static s16b randnor_table[RANDNOR_NUM] =
+{
+ 206, 613, 1022, 1430, 1838, 2245, 2652, 3058,
+ 3463, 3867, 4271, 4673, 5075, 5475, 5874, 6271,
+ 6667, 7061, 7454, 7845, 8234, 8621, 9006, 9389,
+ 9770, 10148, 10524, 10898, 11269, 11638, 12004, 12367,
+ 12727, 13085, 13440, 13792, 14140, 14486, 14828, 15168,
+ 15504, 15836, 16166, 16492, 16814, 17133, 17449, 17761,
+ 18069, 18374, 18675, 18972, 19266, 19556, 19842, 20124,
+ 20403, 20678, 20949, 21216, 21479, 21738, 21994, 22245,
+
+ 22493, 22737, 22977, 23213, 23446, 23674, 23899, 24120,
+ 24336, 24550, 24759, 24965, 25166, 25365, 25559, 25750,
+ 25937, 26120, 26300, 26476, 26649, 26818, 26983, 27146,
+ 27304, 27460, 27612, 27760, 27906, 28048, 28187, 28323,
+ 28455, 28585, 28711, 28835, 28955, 29073, 29188, 29299,
+ 29409, 29515, 29619, 29720, 29818, 29914, 30007, 30098,
+ 30186, 30272, 30356, 30437, 30516, 30593, 30668, 30740,
+ 30810, 30879, 30945, 31010, 31072, 31133, 31192, 31249,
+
+ 31304, 31358, 31410, 31460, 31509, 31556, 31601, 31646,
+ 31688, 31730, 31770, 31808, 31846, 31882, 31917, 31950,
+ 31983, 32014, 32044, 32074, 32102, 32129, 32155, 32180,
+ 32205, 32228, 32251, 32273, 32294, 32314, 32333, 32352,
+ 32370, 32387, 32404, 32420, 32435, 32450, 32464, 32477,
+ 32490, 32503, 32515, 32526, 32537, 32548, 32558, 32568,
+ 32577, 32586, 32595, 32603, 32611, 32618, 32625, 32632,
+ 32639, 32645, 32651, 32657, 32662, 32667, 32672, 32677,
+
+ 32682, 32686, 32690, 32694, 32698, 32702, 32705, 32708,
+ 32711, 32714, 32717, 32720, 32722, 32725, 32727, 32729,
+ 32731, 32733, 32735, 32737, 32739, 32740, 32742, 32743,
+ 32745, 32746, 32747, 32748, 32749, 32750, 32751, 32752,
+ 32753, 32754, 32755, 32756, 32757, 32757, 32758, 32758,
+ 32759, 32760, 32760, 32761, 32761, 32761, 32762, 32762,
+ 32763, 32763, 32763, 32764, 32764, 32764, 32764, 32765,
+ 32765, 32765, 32765, 32766, 32766, 32766, 32766, 32767,
+};
+
+
+
+/*
+ * Generate a random integer number of NORMAL distribution
+ *
+ * The table above is used to generate a psuedo-normal distribution,
+ * in a manner which is much faster than calling a transcendental
+ * function to calculate a true normal distribution.
+ *
+ * Basically, entry 64*N in the table above represents the number of
+ * times out of 32767 that a random variable with normal distribution
+ * will fall within N standard deviations of the mean. That is, about
+ * 68 percent of the time for N=1 and 95 percent of the time for N=2.
+ *
+ * The table above contains a "faked" final entry which allows us to
+ * pretend that all values in a normal distribution are strictly less
+ * than four standard deviations away from the mean. This results in
+ * "conservative" distribution of approximately 1/32768 values.
+ *
+ * Note that the binary search takes up to 16 quick iterations.
+ */
+s16b randnor(int mean, int stand)
+{
+ s16b tmp;
+ s16b offset;
+
+ s16b low = 0;
+ s16b high = RANDNOR_NUM;
+
+ /* Paranoia */
+ if (stand < 1) return (mean);
+
+ /* Roll for probability */
+ tmp = (s16b)rand_int(32768);
+
+ /* Binary Search */
+ while (low < high)
+ {
+ int mid = (low + high) >> 1;
+
+ /* Move right if forced */
+ if (randnor_table[mid] < tmp)
+ {
+ low = mid + 1;
+ }
+
+ /* Move left otherwise */
+ else
+ {
+ high = mid;
+ }
+ }
+
+ /* Convert the index into an offset */
+ offset = (long)stand * (long)low / RANDNOR_STD;
+
+ /* One half should be negative */
+ if (rand_int(100) < 50) return (mean - offset);
+
+ /* One half should be positive */
+ return (mean + offset);
+}
+
+
+
+/*
+ * Generates damage for "2d6" style dice rolls
+ */
+s32b damroll(s16b num, s16b sides)
+{
+ int i;
+ s32b sum = 0;
+ for (i = 0; i < num; i++) sum += randint(sides);
+ return (sum);
+}
+
+
+/*
+ * Same as above, but always maximal
+ */
+s32b maxroll(s16b num, s16b sides)
+{
+ return (num * sides);
+}
+
+
+
diff --git a/src/z-rand.h b/src/z-rand.h
new file mode 100644
index 00000000..39cc958c
--- /dev/null
+++ b/src/z-rand.h
@@ -0,0 +1,96 @@
+/* File: z-rand.h */
+
+#ifndef INCLUDED_Z_RAND_H
+#define INCLUDED_Z_RAND_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "h-basic.h"
+
+
+
+/**** Available constants ****/
+
+
+/*
+ * Random Number Generator -- Degree of "complex" RNG -- see "misc.c"
+ * This value is hard-coded at 63 for a wide variety of reasons.
+ */
+#define RAND_DEG 63
+
+
+
+
+/**** Available macros ****/
+
+
+/*
+ * Generates a random long integer X where O<=X<M.
+ * The integer X falls along a uniform distribution.
+ * For example, if M is 100, you get "percentile dice"
+ */
+#define rand_int(M) \
+ (Rand_div(M))
+
+/*
+ * Generates a random long integer X where A<=X<=B
+ * The integer X falls along a uniform distribution.
+ * Note: rand_range(0,N-1) == rand_int(N)
+ */
+#define rand_range(A,B) \
+ ((A) + (rand_int(1+(B)-(A))))
+
+/*
+ * Generate a random long integer X where A-D<=X<=A+D
+ * The integer X falls along a uniform distribution.
+ * Note: rand_spread(A,D) == rand_range(A-D,A+D)
+ */
+#define rand_spread(A,D) \
+ ((A) + (rand_int(1+(D)+(D))) - (D))
+
+
+/*
+ * Generate a random long integer X where 1<=X<=M
+ * Also, "correctly" handle the case of M<=1
+ */
+#define randint(M) \
+ (rand_int(M) + 1)
+
+
+/*
+ * Evaluate to TRUE "P" percent of the time
+ */
+#define magik(P) \
+ (rand_int(100) < (P))
+
+
+
+
+/**** Available Variables ****/
+
+
+extern bool_ Rand_quick;
+extern u32b Rand_value;
+extern u16b Rand_place;
+extern u32b Rand_state[RAND_DEG];
+
+
+/**** Available Functions ****/
+
+
+extern void Rand_state_init(u32b seed);
+extern s32b Rand_mod(s32b m);
+extern s32b Rand_div(s32b m);
+extern s16b randnor(int mean, int stand);
+extern s32b damroll(s16b num, s16b sides);
+extern s32b maxroll(s16b num, s16b sides);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif
diff --git a/src/z-term.c b/src/z-term.c
new file mode 100644
index 00000000..4e89ffb7
--- /dev/null
+++ b/src/z-term.c
@@ -0,0 +1,2776 @@
+/* File: z-term.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+/* Purpose: a generic, efficient, terminal window package -BEN- */
+
+#include "angband.h"
+
+#include "z-term.h"
+
+#include "z-virt.h"
+
+
+/*
+ * This file provides a generic, efficient, terminal window package,
+ * which can be used not only on standard terminal environments such
+ * as dumb terminals connected to a Unix box, but also in more modern
+ * "graphic" environments, such as the Macintosh or Unix/X11.
+ *
+ * Each "window" works like a standard "dumb terminal", that is, it
+ * can display a two dimensional array of grids containing colored
+ * textual symbols, plus an optional cursor, and it can be used to
+ * get keypress events from the user.
+ *
+ * In fact, this package can simply be used, if desired, to support
+ * programs which will look the same on a dumb terminal as they do
+ * on a graphic platform such as the Macintosh.
+ *
+ * This package was designed to help port the game "Angband" to a wide
+ * variety of different platforms. Angband, like many other games in
+ * the "rogue-like" heirarchy, requires, at the minimum, the ability
+ * to display "colored textual symbols" in a standard 80x24 "window",
+ * such as that provided by most dumb terminals, and many old personal
+ * computers, and to check for "keypresses" from the user. The major
+ * concerns were thus portability and efficiency, so Angband could be
+ * easily ported to many different systems, with minimal effort, and
+ * yet would run quickly on each of these systems, no matter what kind
+ * of underlying hardware/software support was being used.
+ *
+ * It is important to understand the differences between the older
+ * "dumb terminals" and the newer "graphic interface" machines, since
+ * this package was designed to work with both types of systems.
+ *
+ * New machines:
+ * waiting for a keypress is complex
+ * checking for a keypress is often cheap
+ * changing "colors" may be expensive
+ * the "color" of a "blank" is rarely important
+ * moving the "cursor" is relatively cheap
+ * use a "software" cursor (only moves when requested)
+ * drawing characters normally will not erase old ones
+ * drawing a character on the cursor often erases it
+ * may have fast routines for "clear a region"
+ * the bottom right corner is usually not special
+ *
+ * Old machines:
+ * waiting for a keypress is simple
+ * checking for a keypress is often expensive
+ * changing "colors" is usually cheap
+ * the "color" of a "blank" may be important
+ * moving the "cursor" may be expensive
+ * use a "hardware" cursor (moves during screen updates)
+ * drawing new symbols automatically erases old ones
+ * characters may only be drawn at the cursor location
+ * drawing a character on the cursor will move the cursor
+ * may have fast routines for "clear entire window"
+ * may have fast routines for "clear to end of line"
+ * the bottom right corner is often dangerous
+ *
+ *
+ * This package provides support for multiple windows, each of an
+ * arbitrary size (up to 255x255), each with its own set of flags,
+ * and its own hooks to handle several low-level procedures which
+ * differ from platform to platform. Then the main program simply
+ * creates one or more "term" structures, setting the various flags
+ * and hooks in a manner appropriate for the current platform, and
+ * then it can use the various "term" structures without worrying
+ * about the underlying platform.
+ *
+ *
+ * This package allows each "grid" in each window to hold an attr/char
+ * pair, with each ranging from 0 to 255, and makes very few assumptions
+ * about the meaning of any attr/char values. Normally, we assume that
+ * "attr 0" is "black", with the semantics that "black" text should be
+ * sent to "Term_wipe()" instead of "Term_text()", but this sematics is
+ * modified if either the "always_pict" or the "always_text" flags are
+ * set. We assume that "char 0" is "dangerous", since placing such a
+ * "char" in the middle of a string "terminates" the string, and usually
+ * we prevent its use.
+ *
+ * Finally, we use a special attr/char pair, defaulting to "attr 0" and
+ * "char 32", also known as "black space", when we "erase" or "clear"
+ * any window, but this pair can be redefined to any pair, including
+ * the standard "white space", or the bizarre "emptiness" ("attr 0"
+ * and "char 0"), as long as various obscure restrictions are met.
+ *
+ *
+ * This package provides several functions which allow a program to
+ * interact with the "term" structures. Most of the functions allow
+ * the program to "request" certain changes to the current "term",
+ * such as moving the cursor, drawing an attr/char pair, erasing a
+ * region of grids, hiding the cursor, etc. Then there is a special
+ * function which causes all of the "pending" requests to be performed
+ * in an efficient manner. There is another set of functions which
+ * allow the program to query the "requested state" of the current
+ * "term", such as asking for the cursor location, or what attr/char
+ * is at a given location, etc. There is another set of functions
+ * dealing with "keypress" events, which allows the program to ask if
+ * the user has pressed any keys, or to forget any keys the user pressed.
+ * There is a pair of functions to allow this package to memorize the
+ * contents of the current "term", and to restore these contents at
+ * a later time. There is a special function which allows the program
+ * to specify which "term" structure should be the "current" one. At
+ * the lowest level, there is a set of functions which allow a new
+ * "term" to be initialized or destroyed, and which allow this package,
+ * or a program, to access the special "hooks" defined for the current
+ * "term", and a set of functions which those "hooks" can use to inform
+ * this package of the results of certain occurances, for example, one
+ * such function allows this package to learn about user keypresses,
+ * detected by one of the special "hooks".
+ *
+ * We provide, among other things, the functions "Term_keypress()"
+ * to "react" to keypress events, and "Term_redraw()" to redraw the
+ * entire window, plus "Term_resize()" to note a new size.
+ *
+ *
+ * Note that the current "term" contains two "window images". One of
+ * these images represents the "requested" contents of the "term", and
+ * the other represents the "actual" contents of the "term", at the time
+ * of the last performance of pending requests. This package uses these
+ * two images to determine the "minimal" amount of work needed to make
+ * the "actual" contents of the "term" match the "requested" contents of
+ * the "term". This method is not perfect, but it often reduces the
+ * amount of work needed to perform the pending requests, which thus
+ * increases the speed of the program itself. This package promises
+ * that the requested changes will appear to occur either "all at once"
+ * or in a "top to bottom" order. In addition, a "cursor" is maintained,
+ * and this cursor is updated along with the actual window contents.
+ *
+ * Currently, the "Term_fresh()" routine attempts to perform the "minimum"
+ * number of physical updates, in terms of total "work" done by the hooks
+ * Term_wipe(), Term_text(), and Term_pict(), making use of the fact that
+ * adjacent characters of the same color can both be drawn together using
+ * the "Term_text()" hook, and that "black" text can often be sent to the
+ * "Term_wipe()" hook instead of the "Term_text()" hook, and if something
+ * is already displayed in a window, then it is not necessary to display
+ * it again. Unfortunately, this may induce slightly non-optimal results
+ * in some cases, in particular, those in which, say, a string of ten
+ * characters needs to be written, but the fifth character has already
+ * been displayed. Currently, this will cause the "Term_text()" routine
+ * to be called once for each half of the string, instead of once for the
+ * whole string, which, on some machines, may be non-optimal behavior.
+ *
+ * The new formalism includes a "displayed" screen image (old) which
+ * is actually seen by the user, a "requested" screen image (scr)
+ * which is being prepared for display, a "memorized" screen image
+ * (mem) which is used to save and restore screen images, and a
+ * "temporary" screen image (tmp) which is currently unused.
+ *
+ *
+ * Several "flags" are available in each "term" to allow the underlying
+ * visual system (which initializes the "term" structure) to "optimize"
+ * the performance of this package for the given system, or to request
+ * certain behavior which is helpful/required for the given system.
+ *
+ * The "soft_cursor" flag indicates the use of a "soft" cursor, which
+ * only moves when explicitly requested,and which is "erased" when
+ * any characters are drawn on top of it. This flag is used for all
+ * "graphic" systems which handle the cursor by "drawing" it.
+ *
+ * The "icky_corner" flag indicates that the bottom right "corner"
+ * of the windows are "icky", and "printing" anything there may
+ * induce "messy" behavior, such as "scrolling". This flag is used
+ * for most old "dumb terminal" systems.
+ *
+ *
+ * The "term" structure contains the following function "hooks":
+ *
+ * Term->init_hook = Init the term
+ * Term->nuke_hook = Nuke the term
+ * Term->user_hook = Perform user actions
+ * Term->xtra_hook = Perform extra actions
+ * Term->curs_hook = Draw (or Move) the cursor
+ * Term->wipe_hook = Draw some blank spaces
+ * Term->text_hook = Draw some text in the window
+ * Term->pict_hook = Draw some attr/chars in the window
+ *
+ * The "Term->user_hook" hook provides a simple hook to an implementation
+ * defined function, with application defined semantics. It is available
+ * to the program via the "Term_user()" function.
+ *
+ * The "Term->xtra_hook" hook provides a variety of different functions,
+ * based on the first parameter (which should be taken from the various
+ * TERM_XTRA_* defines) and the second parameter (which may make sense
+ * only for some first parameters). It is available to the program via
+ * the "Term_xtra()" function, though some first parameters are only
+ * "legal" when called from inside this package.
+ *
+ * The "Term->curs_hook" hook provides this package with a simple way
+ * to "move" or "draw" the cursor to the grid "x,y", depending on the
+ * setting of the "soft_cursor" flag. Note that the cursor is never
+ * redrawn if "nothing" has happened to the screen (even temporarily).
+ * This hook is required.
+ *
+ * The "Term->wipe_hook" hook provides this package with a simple way
+ * to "erase", starting at "x,y", the next "n" grids. This hook assumes
+ * that the input is valid. This hook is required, unless the setting
+ * of the "always_pict" or "always_text" flags makes it optional.
+ *
+ * The "Term->text_hook" hook provides this package with a simple way
+ * to "draw", starting at "x,y", the "n" chars contained in "cp", using
+ * the attr "a". This hook assumes that the input is valid, and that
+ * "n" is between 1 and 256 inclusive, but it should NOT assume that
+ * the contents of "cp" are null-terminated. This hook is required,
+ * unless the setting of the "always_pict" flag makes it optional.
+ *
+ * The "Term->pict_hook" hook provides this package with a simple way
+ * to "draw", starting at "x,y", the "n" attr/char pairs contained in
+ * the arrays "ap" and "cp". This hook assumes that the input is valid,
+ * and that "n" is between 1 and 256 inclusive, but it should NOT assume
+ * that the contents of "cp" are null-terminated. This hook is optional,
+ * unless the setting of the "always_pict" or "higher_pict" flags make
+ * it required. Note that recently, this hook was changed from taking
+ * a byte "a" and a char "c" to taking a length "n", an array of bytes
+ * "ap" and an array of chars "cp". Old implementations of this hook
+ * should now iterate over all "n" attr/char pairs.
+ *
+ *
+ * The game "Angband" uses a set of files called "main-xxx.c", for
+ * various "xxx" suffixes. Most of these contain a function called
+ * "init_xxx()", that will prepare the underlying visual system for
+ * use with Angband, and then create one or more "term" structures,
+ * using flags and hooks appropriate to the given platform, so that
+ * the "main()" function can call one (or more) of the "init_xxx()"
+ * functions, as appropriate, to prepare the required "term" structs
+ * (one for each desired sub-window), and these "init_xxx()" functions
+ * are called from a centralized "main()" function in "main.c". Other
+ * "main-xxx.c" systems contain their own "main()" function which, in
+ * addition to doing everything needed to initialize the actual program,
+ * also does everything that the normal "init_xxx()" functions would do.
+ *
+ * The game "Angband" defines, in addition to "attr 0", all of the
+ * attr codes from 1 to 15, using definitions in "defines.h", and
+ * thus the "main-xxx.c" files used by Angband must handle these
+ * attr values correctly. Also, they must handle all other attr
+ * values, though they may do so in any way they wish, for example,
+ * by always taking every attr code mod 16. Many of the "main-xxx.c"
+ * files use "white space" ("attr 1" / "char 32") to "erase" or "clear"
+ * any window, for efficiency.
+ *
+ * The game "Angband" uses the "Term_user" hook to allow any of the
+ * "main-xxx.c" files to interact with the user, by calling this hook
+ * whenever the user presses the "!" key when the game is waiting for
+ * a new command. This could be used, for example, to provide "unix
+ * shell commands" to the Unix versions of the game.
+ *
+ * See "main-xxx.c" for a simple skeleton file which can be used to
+ * create a "visual system" for a new platform when porting Angband.
+ */
+
+
+
+/*
+ * The current "term"
+ */
+term *Term = NULL;
+
+/* File handler for saving movies */
+FILE *movfile = NULL;
+int do_movies = 0; /* Later set this as a global */
+/* set to 1 if you want movies made */
+time_t lastc;
+int last_paused = 0;
+int cmovie_get_msecond(void);
+
+/* Record cmovies with millisecond frame rate */
+long cmov_last_time_msec;
+long cmov_delta_time_msec;
+
+
+/*** Local routines ***/
+
+
+/*
+ * Nuke a term_win (see below)
+ */
+static errr term_win_nuke(term_win *s, int w, int h)
+{
+ /* Free the window access arrays */
+ C_KILL(s->a, h, byte*);
+ C_KILL(s->c, h, char*);
+
+ /* Free the window content arrays */
+ C_KILL(s->va, h * w, byte);
+ C_KILL(s->vc, h * w, char);
+
+ /* Free the terrain access arrays */
+ C_KILL(s->ta, h, byte*);
+ C_KILL(s->tc, h, char*);
+
+ /* Free the terrain content arrays */
+ C_KILL(s->vta, h * w, byte);
+ C_KILL(s->vtc, h * w, char);
+
+ /* Free the ego graphics access arrays */
+ C_KILL(s->ea, h, byte*);
+ C_KILL(s->ec, h, char*);
+
+ /* Free the ego graphics content arrays */
+ C_KILL(s->vea, h * w, byte);
+ C_KILL(s->vec, h * w, char);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialize a "term_win" (using the given window size)
+ */
+static errr term_win_init(term_win *s, int w, int h)
+{
+ int y;
+
+ /* Make the window access arrays */
+ C_MAKE(s->a, h, byte*);
+ C_MAKE(s->c, h, char*);
+
+ /* Make the window content arrays */
+ C_MAKE(s->va, h * w, byte);
+ C_MAKE(s->vc, h * w, char);
+
+ /* Make the terrain access arrays */
+ C_MAKE(s->ta, h, byte*);
+ C_MAKE(s->tc, h, char*);
+
+ /* Make the terrain content arrays */
+ C_MAKE(s->vta, h * w, byte);
+ C_MAKE(s->vtc, h * w, char);
+
+ /* Make the ego graphics access arrays */
+ C_MAKE(s->ea, h, byte*);
+ C_MAKE(s->ec, h, char*);
+
+ /* Make the ego graphics content arrays */
+ C_MAKE(s->vea, h * w, byte);
+ C_MAKE(s->vec, h * w, char);
+
+
+ /* Prepare the window access arrays */
+ for (y = 0; y < h; y++)
+ {
+ s->a[y] = s->va + w * y;
+ s->c[y] = s->vc + w * y;
+
+ s->ta[y] = s->vta + w * y;
+ s->tc[y] = s->vtc + w * y;
+
+ s->ea[y] = s->vea + w * y;
+ s->ec[y] = s->vec + w * y;
+
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Copy a "term_win" from another
+ */
+static errr term_win_copy(term_win *s, term_win *f, int w, int h)
+{
+ int x, y;
+
+ /* Copy contents */
+ for (y = 0; y < h; y++)
+ {
+ byte *f_aa = f->a[y];
+ char *f_cc = f->c[y];
+
+ byte *s_aa = s->a[y];
+ char *s_cc = s->c[y];
+
+ byte *f_taa = f->ta[y];
+ char *f_tcc = f->tc[y];
+
+ byte *s_taa = s->ta[y];
+ char *s_tcc = s->tc[y];
+
+ byte *f_eaa = f->ea[y];
+ char *f_ecc = f->ec[y];
+
+ byte *s_eaa = s->ea[y];
+ char *s_ecc = s->ec[y];
+
+ for (x = 0; x < w; x++)
+ {
+ *s_aa++ = *f_aa++;
+ *s_cc++ = *f_cc++;
+
+ *s_taa++ = *f_taa++;
+ *s_tcc++ = *f_tcc++;
+
+ *s_eaa++ = *f_eaa++;
+ *s_ecc++ = *f_ecc++;
+ }
+ }
+
+ /* Copy cursor */
+ s->cx = f->cx;
+ s->cy = f->cy;
+ s->cu = f->cu;
+ s->cv = f->cv;
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*** External hooks ***/
+
+
+/*
+ * Execute the "Term->user_hook" hook, if available (see above).
+ */
+errr Term_user(int n)
+{
+ /* Verify the hook */
+ if (!Term->user_hook) return ( -1);
+
+ /* Call the hook */
+ return ((*Term->user_hook)(n));
+}
+
+/*
+ * Execute the "Term->xtra_hook" hook, if available (see above).
+ * And *hacky* get a return code
+ */
+long Term_xtra_long;
+char scansubdir_dir[1024];
+int scansubdir_max = 0;
+cptr scansubdir_result[255];
+errr Term_xtra(int n, int v)
+{
+ /* Verify the hook */
+ if (!Term->xtra_hook) return ( -1);
+
+ /* Call the hook */
+ return ((*Term->xtra_hook)(n, v));
+}
+
+
+
+/*** Fake hooks ***/
+
+
+/*
+ * Hack -- fake hook for "Term_curs()" (see above)
+ */
+static errr Term_curs_hack(int x, int y)
+{
+ /* Compiler silliness */
+ if (x || y) return ( -2);
+
+ /* Oops */
+ return ( -1);
+}
+
+/*
+ * Hack -- fake hook for "Term_wipe()" (see above)
+ */
+static errr Term_wipe_hack(int x, int y, int n)
+{
+ /* Compiler silliness */
+ if (x || y || n) return ( -2);
+
+ /* Oops */
+ return ( -1);
+}
+
+/*
+ * Hack -- fake hook for "Term_text()" (see above)
+ */
+static errr Term_text_hack(int x, int y, int n, byte a, const char *cp)
+{
+ /* Compiler silliness */
+ if (x || y || n || a || cp) return ( -2);
+
+ /* Oops */
+ return ( -1);
+}
+
+/*
+ * Hack -- fake hook for "Term_pict()" (see above)
+ */
+static errr Term_pict_hack(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp, const byte *eap, const char *ecp)
+{
+ /* Compiler silliness */
+ if (x || y || n || ap || cp || tap || tcp || eap || ecp) return ( -2);
+
+ /* Oops */
+ return ( -1);
+}
+
+
+
+/*** Efficient routines ***/
+
+
+/*
+ * Mentally draw an attr/char at a given location
+ *
+ * Assumes given location and values are valid.
+ */
+void Term_queue_char(int x, int y, byte a, char c, byte ta, char tc, byte ea, char ec)
+{
+ term_win *scrn = Term->scr;
+
+ byte *scr_aa = &scrn->a[y][x];
+ char *scr_cc = &scrn->c[y][x];
+
+ byte *scr_taa = &scrn->ta[y][x];
+ char *scr_tcc = &scrn->tc[y][x];
+
+ byte *scr_eaa = &scrn->ea[y][x];
+ char *scr_ecc = &scrn->ec[y][x];
+
+ /* Hack -- Ignore non-changes */
+ if ((*scr_aa == a) && (*scr_cc == c) &&
+ (*scr_taa == ta) && (*scr_tcc == tc) &&
+ (*scr_eaa == ea) && (*scr_ecc == ec)) return;
+
+ /* Save the "literal" information */
+ *scr_aa = a;
+ *scr_cc = c;
+
+ *scr_taa = ta;
+ *scr_tcc = tc;
+
+ *scr_eaa = ea;
+ *scr_ecc = ec;
+
+ /* Check for new min/max row info */
+ if (y < Term->y1) Term->y1 = y;
+ if (y > Term->y2) Term->y2 = y;
+
+ /* Check for new min/max col info for this row */
+ if (x < Term->x1[y]) Term->x1[y] = x;
+ if (x > Term->x2[y]) Term->x2[y] = x;
+}
+
+
+/*
+ * Mentally draw a string of attr/chars at a given location
+ *
+ * Assumes given location and values are valid.
+ *
+ * This function is designed to be fast, with no consistancy checking.
+ * It is used to update the map in the game.
+ */
+void Term_queue_line(int x, int y, int n, byte *a, char *c, byte *ta, char *tc, byte *ea, char *ec)
+{
+ term_win *scrn = Term->scr;
+
+ int x1 = -1;
+ int x2 = -1;
+
+ byte *scr_aa = &scrn->a[y][x];
+ char *scr_cc = &scrn->c[y][x];
+
+ byte *scr_taa = &scrn->ta[y][x];
+ char *scr_tcc = &scrn->tc[y][x];
+
+ byte *scr_eaa = &scrn->ea[y][x];
+ char *scr_ecc = &scrn->ec[y][x];
+
+ while (n--)
+ {
+
+ /* Hack -- Ignore non-changes */
+ if ((*scr_aa == *a) && (*scr_cc == *c) &&
+ (*scr_taa == *ta) && (*scr_tcc == *tc) &&
+ (*scr_eaa == *ea) && (*scr_ecc == *ec))
+ {
+ x++;
+ a++;
+ c++;
+ ta++;
+ tc++;
+ ea++;
+ ec++;
+ scr_aa++;
+ scr_cc++;
+ scr_taa++;
+ scr_tcc++;
+ scr_eaa++;
+ scr_ecc++;
+ continue;
+ }
+
+ /* Save the "literal" information */
+ *scr_taa++ = *ta++;
+ *scr_tcc++ = *tc++;
+
+ /* Save the "literal" information */
+ *scr_eaa++ = *ea++;
+ *scr_ecc++ = *ec++;
+
+ /* Save the "literal" information */
+ *scr_aa++ = *a++;
+ *scr_cc++ = *c++;
+
+ /* Track minimum changed column */
+ if (x1 < 0) x1 = x;
+
+ /* Track maximum changed column */
+ x2 = x;
+
+ x++;
+ }
+
+ /* Expand the "change area" as needed */
+ if (x1 >= 0)
+ {
+ /* Check for new min/max row info */
+ if (y < Term->y1) Term->y1 = y;
+ if (y > Term->y2) Term->y2 = y;
+
+ /* Check for new min/max col info in this row */
+ if (x1 < Term->x1[y]) Term->x1[y] = x1;
+ if (x2 > Term->x2[y]) Term->x2[y] = x2;
+ }
+}
+
+
+
+/*
+ * Mentally draw some attr/chars at a given location
+ *
+ * Assumes that (x,y) is a valid location, that the first "n" characters
+ * of the string "s" are all valid (non-zero), and that (x+n-1,y) is also
+ * a valid location, so the first "n" characters of "s" can all be added
+ * starting at (x,y) without causing any illegal operations.
+ */
+void Term_queue_chars(int x, int y, int n, byte a, cptr s)
+{
+ int x1 = -1, x2 = -1;
+
+ byte *scr_aa = Term->scr->a[y];
+ char *scr_cc = Term->scr->c[y];
+
+ byte *scr_taa = Term->scr->ta[y];
+ char *scr_tcc = Term->scr->tc[y];
+
+ byte *scr_eaa = Term->scr->ea[y];
+ char *scr_ecc = Term->scr->ec[y];
+
+ /* Queue the attr/chars */
+ for ( ; n; x++, s++, n--)
+ {
+ int oa = scr_aa[x];
+ int oc = scr_cc[x];
+
+ int ota = scr_taa[x];
+ int otc = scr_tcc[x];
+
+ int oea = scr_eaa[x];
+ int oec = scr_ecc[x];
+
+ /* Hack -- Ignore non-changes */
+ if ((oa == a) && (oc == *s) &&
+ (ota == 0) && (otc == 0) &&
+ (oea == 0) && (oec == 0)) continue;
+
+
+ /* Save the "literal" information */
+ scr_aa[x] = a;
+ scr_cc[x] = *s;
+
+ scr_taa[x] = 0;
+ scr_tcc[x] = 0;
+
+ scr_taa[x] = 0;
+ scr_tcc[x] = 0;
+
+ /* Note the "range" of window updates */
+ if (x1 < 0) x1 = x;
+ x2 = x;
+ }
+
+ /* Expand the "change area" as needed */
+ if (x1 >= 0)
+ {
+ /* Check for new min/max row info */
+ if (y < Term->y1) Term->y1 = y;
+ if (y > Term->y2) Term->y2 = y;
+
+ /* Check for new min/max col info in this row */
+ if (x1 < Term->x1[y]) Term->x1[y] = x1;
+ if (x2 > Term->x2[y]) Term->x2[y] = x2;
+ }
+}
+
+
+
+/*** Refresh routines ***/
+
+
+/*
+ * Flush a row of the current window (see "Term_fresh")
+ *
+ * Display text using "Term_pict()"
+ */
+static void Term_fresh_row_pict(int y, int x1, int x2)
+{
+ int x;
+
+ byte *old_aa = Term->old->a[y];
+ char *old_cc = Term->old->c[y];
+
+ byte *scr_aa = Term->scr->a[y];
+ char *scr_cc = Term->scr->c[y];
+
+ byte *old_taa = Term->old->ta[y];
+ char *old_tcc = Term->old->tc[y];
+
+ byte *scr_taa = Term->scr->ta[y];
+ char *scr_tcc = Term->scr->tc[y];
+
+ byte ota;
+ char otc;
+
+ byte nta;
+ char ntc;
+
+ byte *old_eaa = Term->old->ea[y];
+ char *old_ecc = Term->old->ec[y];
+
+ byte *scr_eaa = Term->scr->ea[y];
+ char *scr_ecc = Term->scr->ec[y];
+
+ byte oea;
+ char oec;
+
+ byte nea;
+ char nec;
+
+
+
+ /* Pending length */
+ int fn = 0;
+
+ /* Pending start */
+ int fx = 0;
+
+ byte oa;
+ char oc;
+
+ byte na;
+ char nc;
+
+ /* Scan "modified" columns */
+ for (x = x1; x <= x2; x++)
+ {
+ /* See what is currently here */
+ oa = old_aa[x];
+ oc = old_cc[x];
+
+ /* See what is desired there */
+ na = scr_aa[x];
+ nc = scr_cc[x];
+
+ ota = old_taa[x];
+ otc = old_tcc[x];
+
+ nta = scr_taa[x];
+ ntc = scr_tcc[x];
+
+ oea = old_eaa[x];
+ oec = old_ecc[x];
+
+ nea = scr_eaa[x];
+ nec = scr_ecc[x];
+
+ /* Handle unchanged grids */
+ if ((na == oa) && (nc == oc) &&
+ (nta == ota) && (ntc == otc) &&
+ (nea == oea) && (nec == oec))
+ {
+ /* Flush */
+ if (fn)
+ {
+ /* Draw pending attr/char pairs */
+ (void)((*Term->pict_hook)(fx, y, fn,
+ &scr_aa[fx], &scr_cc[fx],
+ &scr_taa[fx], &scr_tcc[fx],
+ &scr_eaa[fx], &scr_ecc[fx]));
+
+ /* Forget */
+ fn = 0;
+ }
+
+ /* Skip */
+ continue;
+ }
+ /* Save new contents */
+ old_aa[x] = na;
+ old_cc[x] = nc;
+
+ old_taa[x] = nta;
+ old_tcc[x] = ntc;
+
+ old_eaa[x] = nea;
+ old_ecc[x] = nec;
+
+ /* Restart and Advance */
+ if (fn++ == 0) fx = x;
+ }
+
+ /* Flush */
+ if (fn)
+ {
+ /* Draw pending attr/char pairs */
+ (void)((*Term->pict_hook)(fx, y, fn,
+ &scr_aa[fx], &scr_cc[fx],
+ &scr_taa[fx], &scr_tcc[fx],
+ &scr_eaa[fx], &scr_ecc[fx]));
+ }
+}
+
+
+
+/*
+ * Flush a row of the current window (see "Term_fresh")
+ *
+ * Display text using "Term_text()" and "Term_wipe()",
+ * but use "Term_pict()" for high-bit attr/char pairs
+ */
+static void Term_fresh_row_both(int y, int x1, int x2)
+{
+ int x;
+
+ byte *old_aa = Term->old->a[y];
+ char *old_cc = Term->old->c[y];
+
+ byte *scr_aa = Term->scr->a[y];
+ char *scr_cc = Term->scr->c[y];
+
+ byte *old_taa = Term->old->ta[y];
+ char *old_tcc = Term->old->tc[y];
+ byte *scr_taa = Term->scr->ta[y];
+ char *scr_tcc = Term->scr->tc[y];
+
+ byte ota;
+ char otc;
+ byte nta;
+ char ntc;
+
+ byte *old_eaa = Term->old->ea[y];
+ char *old_ecc = Term->old->ec[y];
+ byte *scr_eaa = Term->scr->ea[y];
+ char *scr_ecc = Term->scr->ec[y];
+
+ byte oea;
+ char oec;
+ byte nea;
+ char nec;
+
+ /* The "always_text" flag */
+ int always_text = Term->always_text;
+
+ /* Pending length */
+ int fn = 0;
+
+ /* Pending start */
+ int fx = 0;
+
+ /* Pending attr */
+ byte fa = Term->attr_blank;
+
+ byte oa;
+ char oc;
+
+ byte na;
+ char nc;
+
+ /* Scan "modified" columns */
+ for (x = x1; x <= x2; x++)
+ {
+ /* See what is currently here */
+ oa = old_aa[x];
+ oc = old_cc[x];
+
+ /* See what is desired there */
+ na = scr_aa[x];
+ nc = scr_cc[x];
+
+ ota = old_taa[x];
+ otc = old_tcc[x];
+
+ nta = scr_taa[x];
+ ntc = scr_tcc[x];
+
+ oea = old_eaa[x];
+ oec = old_ecc[x];
+
+ nea = scr_eaa[x];
+ nec = scr_ecc[x];
+
+ /* Handle unchanged grids */
+ if ((na == oa) && (nc == oc) &&
+ (nta == ota) && (ntc == otc) &&
+ (nea == oea) && (nec == oec))
+ {
+ /* Flush */
+ if (fn)
+ {
+ /* Draw pending chars (normal) */
+ if (fa || always_text)
+ {
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
+ }
+ /* Draw pending chars (black) */
+ else
+ {
+ (void)((*Term->wipe_hook)(fx, y, fn));
+ }
+ /* Forget */
+ fn = 0;
+ }
+
+ /* Skip */
+ continue;
+ }
+
+ /* Save new contents */
+ old_aa[x] = na;
+ old_cc[x] = nc;
+
+ old_taa[x] = nta;
+ old_tcc[x] = ntc;
+
+ old_eaa[x] = nea;
+ old_ecc[x] = nec;
+
+ /* 2nd byte of bigtile */
+ if (na == 255) continue;
+
+ /* Handle high-bit attr/chars */
+ if (na & 0x80)
+ {
+ /* Flush */
+ if (fn)
+ {
+ /* Draw pending chars (normal) */
+ if (fa || always_text)
+ {
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
+ }
+ /* Draw pending chars (black) */
+ else
+ {
+ (void)((*Term->wipe_hook)(fx, y, fn));
+ }
+ /* Forget */
+ fn = 0;
+ }
+
+ /* Hack -- Draw the special attr/char pair */
+ (void)((*Term->pict_hook)(x, y, 1, &na, &nc, &nta, &ntc, &nea, &nec));
+
+ /* Skip */
+ continue;
+ }
+
+ /* Notice new color */
+ if (fa != na)
+ {
+ /* Flush */
+ if (fn)
+ {
+ /* Draw the pending chars */
+ if (fa || always_text)
+ {
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
+ }
+ /* Hack -- Erase "leading" spaces */
+ else
+ {
+ (void)((*Term->wipe_hook)(fx, y, fn));
+ }
+ /* Forget */
+ fn = 0;
+ }
+
+ /* Save the new color */
+ fa = na;
+ }
+
+ /* Restart and Advance */
+ if (fn++ == 0) fx = x;
+ }
+
+ /* Flush */
+ if (fn)
+ {
+ /* Draw pending chars (normal) */
+ if (fa || always_text)
+ {
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
+ }
+ /* Draw pending chars (black) */
+ else
+ {
+ (void)((*Term->wipe_hook)(fx, y, fn));
+ }
+ }
+}
+
+
+/*
+ * Flush a row of the current window (see "Term_fresh")
+ *
+ * Display text using "Term_text()" and "Term_wipe()"
+ */
+static void Term_fresh_row_text(int y, int x1, int x2)
+{
+ int x;
+
+ byte *old_aa = Term->old->a[y];
+ char *old_cc = Term->old->c[y];
+
+ byte *scr_aa = Term->scr->a[y];
+ char *scr_cc = Term->scr->c[y];
+
+ /* The "always_text" flag */
+ int always_text = Term->always_text;
+
+ /* Pending length */
+ int fn = 0;
+
+ /* Pending start */
+ int fx = 0;
+
+ /* Pending attr */
+ byte fa = Term->attr_blank;
+
+ byte oa;
+ char oc;
+
+ byte na;
+ char nc;
+
+ /* Scan "modified" columns */
+ for (x = x1; x <= x2; x++)
+ {
+ /* See what is currently here */
+ oa = old_aa[x];
+ oc = old_cc[x];
+
+ /* See what is desired there */
+ na = scr_aa[x];
+ nc = scr_cc[x];
+
+ /* Handle unchanged grids */
+ if ((na == oa) && (nc == oc))
+ {
+ /* Flush */
+ if (fn)
+ {
+ /* Draw pending chars (normal) */
+ if (fa || always_text)
+ {
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
+ }
+
+ /* Draw pending chars (black) */
+ else
+ {
+ (void)((*Term->wipe_hook)(fx, y, fn));
+ }
+
+ /* Forget */
+ fn = 0;
+ }
+
+ /* Skip */
+ continue;
+ }
+
+ /* Save new contents */
+ old_aa[x] = na;
+ old_cc[x] = nc;
+
+ /* Notice new color */
+ if (fa != na)
+ {
+ /* Flush */
+ if (fn)
+ {
+ /* Draw the pending chars */
+ if (fa || always_text)
+ {
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
+ }
+
+ /* Hack -- Erase "leading" spaces */
+ else
+ {
+ (void)((*Term->wipe_hook)(fx, y, fn));
+ }
+
+ /* Forget */
+ fn = 0;
+ }
+
+ /* Save the new color */
+ fa = na;
+ }
+
+ /* Restart and Advance */
+ if (fn++ == 0) fx = x;
+ }
+
+ /* Flush */
+ if (fn)
+ {
+ /* Draw pending chars (normal) */
+ if (fa || always_text)
+ {
+ (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
+ }
+
+ /* Draw pending chars (black) */
+ else
+ {
+ (void)((*Term->wipe_hook)(fx, y, fn));
+ }
+ }
+}
+
+
+
+
+
+/*
+ * Actually perform all requested changes to the window
+ *
+ * If absolutely nothing has changed, not even temporarily, or if the
+ * current "Term" is not mapped, then this function will return 1 and
+ * do absolutely nothing.
+ *
+ * Note that when "soft_cursor" is true, we erase the cursor (if needed)
+ * whenever anything has changed, and redraw it (if needed) after all of
+ * the screen updates are complete. This will induce a small amount of
+ * "cursor flicker" but only when the screen has been updated. If the
+ * screen is updated and then restored, you may still get this flicker.
+ *
+ * When "soft_cursor" is not true, we make the cursor invisible before
+ * doing anything else if it is supposed to be invisible by the time we
+ * are done, and we make it visible after moving it to its final location
+ * after all of the screen updates are complete.
+ *
+ * Note that "Term_xtra(TERM_XTRA_CLEAR,0)" must erase the entire screen,
+ * including the cursor, if needed, and may place the cursor anywhere.
+ *
+ * Note that "Term_xtra(TERM_XTRA_FROSH,y)" will be always be called
+ * after any row "y" has been "flushed", unless the "Term->never_frosh"
+ * flag is set, and "Term_xtra(TERM_XTRA_FRESH,0)" will be called after
+ * all of the rows have been "flushed".
+ *
+ * Note the use of three different functions to handle the actual flush,
+ * based on the settings of the "Term->always_pict" and "Term->higher_pict"
+ * flags (see below).
+ *
+ * The three helper functions (above) work by collecting similar adjacent
+ * grids into stripes, and then sending each stripe to "Term->pict_hook",
+ * "Term->text_hook", or "Term->wipe_hook", based on the settings of the
+ * "Term->always_pict" and "Term->higher_pict" flags, which select which
+ * of the helper functions to call to flush each row.
+ *
+ * The helper functions currently "skip" any grids which already contain
+ * the desired contents. This may or may not be the best method, especially
+ * when the desired content fits nicely into the current stripe. For example,
+ * it might be better to go ahead and queue them while allowed, but keep a
+ * count of the "trailing skipables", then, when time to flush, or when a
+ * "non skippable" is found, force a flush if there are too many skippables.
+ *
+ * Perhaps an "initialization" stage, where the "text" (and "attr")
+ * buffers are "filled" with information, converting "blanks" into
+ * a convenient representation, and marking "skips" with "zero chars",
+ * and then some "processing" is done to determine which chars to skip.
+ *
+ * Currently, the helper functions are optimal for systems which prefer
+ * to "print a char + move a char + print a char" to "print three chars",
+ * and for applications that do a lot of "detailed" color printing.
+ *
+ * In the two "queue" functions, total "non-changes" are "pre-skipped".
+ * The helper functions must also handle situations in which the contents
+ * of a grid are changed, but then changed back to the original value,
+ * and situations in which two grids in the same row are changed, but
+ * the grids between them are unchanged.
+ *
+ * If the "Term->always_pict" flag is set, then "Term_fresh_row_pict()"
+ * will be used instead of "Term_fresh_row_text()". This allows all the
+ * modified grids to be collected into stripes of attr/char pairs, which
+ * are then sent to the "Term->pict_hook" hook, which can draw these pairs
+ * in whatever way it would like.
+ *
+ * If the "Term->higher_pict" flag is set, then "Term_fresh_row_both()"
+ * will be used instead of "Term_fresh_row_text()". This allows all the
+ * "special" attr/char pairs (in which both the attr and char have the
+ * high-bit set) to be sent (one pair at a time) to the "Term->pict_hook"
+ * hook, which can draw these pairs in whatever way it would like.
+ *
+ * Normally, the "Term_wipe()" function is used only to display "blanks"
+ * that were induced by "Term_clear()" or "Term_erase()", and then only
+ * if the "attr_blank" and "char_blank" fields have not been redefined
+ * to use "white space" instead of the default "black space". Actually,
+ * the "Term_wipe()" function is used to display all "black" text, such
+ * as the default "spaces" created by "Term_clear()" and "Term_erase()".
+ *
+ * Note that the "Term->always_text" flag will disable the use of the
+ * "Term_wipe()" function hook entirely, and force all text, even text
+ * drawn in the color "black", to be explicitly drawn. This is useful
+ * for machines which implement "Term_wipe()" by just drawing spaces.
+ *
+ * Note that the "Term->always_pict" flag will disable the use of the
+ * "Term_wipe()" function entirely, and force everything, even text
+ * drawn in the attr "black", to be explicitly drawn.
+ *
+ * Note that if no "black" text is ever drawn, and if "attr_blank" is
+ * not "zero", then the "Term_wipe" hook will never be used, even if
+ * the "Term->always_text" flag is not set.
+ *
+ * This function does nothing unless the "Term" is "mapped", which allows
+ * certain systems to optimize the handling of "closed" windows.
+ *
+ * On systems with a "soft" cursor, we must explicitly erase the cursor
+ * before flushing the output, if needed, to prevent a "jumpy" refresh.
+ * The actual method for this is horrible, but there is very little that
+ * we can do to simplify it efficiently. XXX XXX XXX
+ *
+ * On systems with a "hard" cursor, we will "hide" the cursor before
+ * flushing the output, if needed, to avoid a "flickery" refresh. It
+ * would be nice to *always* hide the cursor during the refresh, but
+ * this might be expensive (and/or ugly) on some machines.
+ *
+ * The "Term->icky_corner" flag is used to avoid calling "Term_wipe()"
+ * or "Term_pict()" or "Term_text()" on the bottom right corner of the
+ * window, which might induce "scrolling" or other nasty stuff on old
+ * dumb terminals. This flag is handled very efficiently. We assume
+ * that the "Term_curs()" call will prevent placing the cursor in the
+ * corner, if needed, though I doubt such placement is ever a problem.
+ * Currently, the use of "Term->icky_corner" and "Term->soft_cursor"
+ * together may result in undefined behavior.
+ */
+errr Term_fresh(void)
+{
+ int x, y;
+
+ int w = Term->wid;
+ int h = Term->hgt;
+
+ int y1 = Term->y1;
+ int y2 = Term->y2;
+
+ term_win *old = Term->old;
+ term_win *scr = Term->scr;
+
+
+ /* Do nothing unless "mapped" */
+ if (!Term->mapped_flag) return (1);
+
+
+ /* Trivial Refresh */
+ if ((y1 > y2) &&
+ (scr->cu == old->cu) &&
+ (scr->cv == old->cv) &&
+ (scr->cx == old->cx) &&
+ (scr->cy == old->cy) &&
+ !(Term->total_erase))
+ {
+ /* Nothing */
+ return (1);
+ }
+
+
+ /* Paranoia -- use "fake" hooks to prevent core dumps */
+ if (!Term->curs_hook) Term->curs_hook = Term_curs_hack;
+ if (!Term->wipe_hook) Term->wipe_hook = Term_wipe_hack;
+ if (!Term->text_hook) Term->text_hook = Term_text_hack;
+ if (!Term->pict_hook) Term->pict_hook = Term_pict_hack;
+
+
+ /* Handle "total erase" */
+ if (Term->total_erase)
+ {
+ byte na = Term->attr_blank;
+ char nc = Term->char_blank;
+
+ if ((do_movies == 1) && IN_MAINWINDOW)
+ {
+ if (!cmovie_get_msecond())
+ {
+ fprintf(movfile, "S:%ld:\n", cmov_delta_time_msec);
+ }
+ fprintf(movfile, "C:\n");
+ last_paused = 0;
+ }
+
+ /* Physically erase the entire window */
+ Term_xtra(TERM_XTRA_CLEAR, 0);
+
+ /* Hack -- clear all "cursor" data */
+ old->cv = old->cu = old->cx = old->cy = 0;
+
+ /* Wipe each row */
+ for (y = 0; y < h; y++)
+ {
+ byte *aa = old->a[y];
+ char *cc = old->c[y];
+
+ byte *taa = old->ta[y];
+ char *tcc = old->tc[y];
+
+ byte *eaa = old->ea[y];
+ char *ecc = old->ec[y];
+
+
+ /* Wipe each column */
+ for (x = 0; x < w; x++)
+ {
+ /* Wipe each grid */
+ *aa++ = na;
+ *cc++ = nc;
+
+ *taa++ = na;
+ *tcc++ = nc;
+
+ *eaa++ = na;
+ *ecc++ = nc;
+ }
+ }
+
+ /* Redraw every row */
+ Term->y1 = y1 = 0;
+ Term->y2 = y2 = h - 1;
+
+ /* Redraw every column */
+ for (y = 0; y < h; y++)
+ {
+ Term->x1[y] = 0;
+ Term->x2[y] = w - 1;
+ }
+
+ /* Forget "total erase" */
+ Term->total_erase = FALSE;
+ }
+
+
+ /* Cursor update -- Erase old Cursor */
+ if (Term->soft_cursor)
+ {
+ /* Cursor was visible */
+ if (!old->cu && old->cv)
+ {
+ int tx = old->cx;
+ int ty = old->cy;
+
+ byte *old_aa = old->a[ty];
+ char *old_cc = old->c[ty];
+
+ byte oa = old_aa[tx];
+ char oc = old_cc[tx];
+
+ byte *old_taa = old->ta[ty];
+ char *old_tcc = old->tc[ty];
+
+ byte ota = old_taa[tx];
+ char otc = old_tcc[tx];
+
+ byte *old_eaa = old->ea[ty];
+ char *old_ecc = old->ec[ty];
+
+ byte oea = old_eaa[tx];
+ char oec = old_ecc[tx];
+
+ /* Hack -- use "Term_pict()" always */
+ if (Term->always_pict)
+ {
+ (void)((*Term->pict_hook)(tx, ty, 1, &oa, &oc, &ota, &otc, &oea, &oec));
+ }
+
+ /* Hack -- use "Term_pict()" sometimes */
+ else if (Term->higher_pict && (oa & 0x80))
+ {
+ (void)((*Term->pict_hook)(tx, ty, 1, &oa, &oc, &ota, &otc, &oea, &oec));
+ }
+
+ /* Hack -- restore the actual character */
+ else if (oa || Term->always_text)
+ {
+ (void)((*Term->text_hook)(tx, ty, 1, oa, &oc));
+ }
+
+ /* Hack -- erase the grid */
+ else
+ {
+ (void)((*Term->wipe_hook)(tx, ty, 1));
+ }
+ }
+ }
+
+ /* Cursor Update -- Erase old Cursor */
+ else
+ {
+ /* Cursor will be invisible */
+ if (scr->cu || !scr->cv)
+ {
+ /* Make the cursor invisible */
+ Term_xtra(TERM_XTRA_SHAPE, 0);
+ }
+ }
+
+
+ /* Something to update */
+ if (y1 <= y2)
+ {
+ /* Handle "icky corner" */
+ if (Term->icky_corner)
+ {
+ /* Avoid the corner */
+ if (y2 >= h - 1)
+ {
+ /* Avoid the corner */
+ if (Term->x2[h - 1] > w - 2)
+ {
+ /* Avoid the corner */
+ Term->x2[h - 1] = w - 2;
+ }
+ }
+ }
+
+
+ /* Scan the "modified" rows */
+ for (y = y1; y <= y2; ++y)
+ {
+ int x1 = Term->x1[y];
+ int x2 = Term->x2[y];
+
+ /* Flush each "modified" row */
+ if (x1 <= x2)
+ {
+ if ((do_movies == 1) && IN_MAINWINDOW)
+ {
+ /* Most magic happens here */
+ cmovie_record_line(y);
+ last_paused = 0;
+ }
+
+ /* Always use "Term_pict()" */
+ if (Term->always_pict)
+ {
+ /* Flush the row */
+ Term_fresh_row_pict(y, x1, x2);
+ }
+
+ /* Sometimes use "Term_pict()" */
+ else if (Term->higher_pict)
+ {
+ /* Flush the row */
+ Term_fresh_row_both(y, x1, x2);
+ }
+
+ /* Never use "Term_pict()" */
+ else
+ {
+ /* Flush the row */
+ Term_fresh_row_text(y, x1, x2);
+ }
+
+ /* This row is all done */
+ Term->x1[y] = w;
+ Term->x2[y] = 0;
+
+ /* Hack -- Flush that row (if allowed) */
+ if (!Term->never_frosh) Term_xtra(TERM_XTRA_FROSH, y);
+ }
+ }
+
+ /* No rows are invalid */
+ Term->y1 = h;
+ Term->y2 = 0;
+ }
+
+
+ /* Cursor update -- Show new Cursor */
+ if (Term->soft_cursor)
+ {
+ /* Draw the cursor */
+ if (!scr->cu && scr->cv)
+ {
+ /* Call the cursor display routine */
+ (void)((*Term->curs_hook)(scr->cx, scr->cy));
+ }
+ }
+
+ /* Cursor Update -- Show new Cursor */
+ else
+ {
+ /* The cursor is useless, hide it */
+ if (scr->cu)
+ {
+ /* Paranoia -- Put the cursor NEAR where it belongs */
+ (void)((*Term->curs_hook)(w - 1, scr->cy));
+
+ /* Make the cursor invisible */
+ /* Term_xtra(TERM_XTRA_SHAPE, 0); */
+ }
+
+ /* The cursor is invisible, hide it */
+ else if (!scr->cv)
+ {
+ /* Paranoia -- Put the cursor where it belongs */
+ (void)((*Term->curs_hook)(scr->cx, scr->cy));
+
+ /* Make the cursor invisible */
+ /* Term_xtra(TERM_XTRA_SHAPE, 0); */
+ }
+
+ /* The cursor is visible, display it correctly */
+ else
+ {
+ /* Put the cursor where it belongs */
+ (void)((*Term->curs_hook)(scr->cx, scr->cy));
+
+ /* Make the cursor visible */
+ Term_xtra(TERM_XTRA_SHAPE, 1);
+ }
+ }
+
+
+ /* Save the "cursor state" */
+ old->cu = scr->cu;
+ old->cv = scr->cv;
+ old->cx = scr->cx;
+ old->cy = scr->cy;
+
+
+ /* Actually flush the output */
+ Term_xtra(TERM_XTRA_FRESH, 0);
+
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*** Output routines ***/
+
+
+/*
+ * Set the cursor visibility
+ */
+errr Term_set_cursor(int v)
+{
+ /* Already done */
+ if (Term->scr->cv == v) return (1);
+
+ /* Change */
+ Term->scr->cv = v;
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Place the cursor at a given location
+ *
+ * Note -- "illegal" requests do not move the cursor.
+ */
+errr Term_gotoxy(int x, int y)
+{
+ int w = Term->wid;
+ int h = Term->hgt;
+
+ /* Verify */
+ if ((x < 0) || (x >= w)) return ( -1);
+ if ((y < 0) || (y >= h)) return ( -1);
+
+ /* Remember the cursor */
+ Term->scr->cx = x;
+ Term->scr->cy = y;
+
+ /* The cursor is not useless */
+ Term->scr->cu = 0;
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * At a given location, place an attr/char
+ * Do not change the cursor position
+ * No visual changes until "Term_fresh()".
+ */
+errr Term_draw(int x, int y, byte a, char c)
+{
+ int w = Term->wid;
+ int h = Term->hgt;
+
+ /* Verify location */
+ if ((x < 0) || (x >= w)) return ( -1);
+ if ((y < 0) || (y >= h)) return ( -1);
+
+ /* Paranoia -- illegal char */
+ if (!c) return ( -2);
+
+ /* Queue it for later */
+ Term_queue_char(x, y, a, c, 0, 0, 0, 0);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Using the given attr, add the given char at the cursor.
+ *
+ * We return "-2" if the character is "illegal". XXX XXX
+ *
+ * We return "-1" if the cursor is currently unusable.
+ *
+ * We queue the given attr/char for display at the current
+ * cursor location, and advance the cursor to the right,
+ * marking it as unuable and returning "1" if it leaves
+ * the screen, and otherwise returning "0".
+ *
+ * So when this function, or the following one, return a
+ * positive value, future calls to either function will
+ * return negative ones.
+ */
+errr Term_addch(byte a, char c)
+{
+ int w = Term->wid;
+
+ /* Handle "unusable" cursor */
+ if (Term->scr->cu) return ( -1);
+
+ /* Paranoia -- no illegal chars */
+ if (!c) return ( -2);
+
+ /* Queue the given character for display */
+ Term_queue_char(Term->scr->cx, Term->scr->cy, a, c, 0, 0, 0, 0);
+
+ /* Advance the cursor */
+ Term->scr->cx++;
+
+ /* Success */
+ if (Term->scr->cx < w) return (0);
+
+ /* Note "Useless" cursor */
+ Term->scr->cu = 1;
+
+ /* Note "Useless" cursor */
+ return (1);
+}
+
+
+/*
+ * At the current location, using an attr, add a string
+ *
+ * We also take a length "n", using negative values to imply
+ * the largest possible value, and then we use the minimum of
+ * this length and the "actual" length of the string as the
+ * actual number of characters to attempt to display, never
+ * displaying more characters than will actually fit, since
+ * we do NOT attempt to "wrap" the cursor at the screen edge.
+ *
+ * We return "-1" if the cursor is currently unusable.
+ * We return "N" if we were "only" able to write "N" chars,
+ * even if all of the given characters fit on the screen,
+ * and mark the cursor as unusable for future attempts.
+ *
+ * So when this function, or the preceding one, return a
+ * positive value, future calls to either function will
+ * return negative ones.
+ */
+errr Term_addstr(int n, byte a, cptr s)
+{
+ int k;
+
+ int w = Term->wid;
+
+ errr res = 0;
+
+ /* Handle "unusable" cursor */
+ if (Term->scr->cu) return ( -1);
+
+ /* Obtain maximal length */
+ k = (n < 0) ? (w + 1) : n;
+
+ /* Obtain the usable string length */
+ for (n = 0; (n < k) && s[n]; n++) /* loop */;
+
+ /* React to reaching the edge of the screen */
+ if (Term->scr->cx + n >= w) res = n = w - Term->scr->cx;
+
+ /* Queue the first "n" characters for display */
+ Term_queue_chars(Term->scr->cx, Term->scr->cy, n, a, s);
+
+ /* Advance the cursor */
+ Term->scr->cx += n;
+
+ /* Hack -- Notice "Useless" cursor */
+ if (res) Term->scr->cu = 1;
+
+ /* Success (usually) */
+ return (res);
+}
+
+
+/*
+ * Move to a location and, using an attr, add a char
+ */
+errr Term_putch(int x, int y, byte a, char c)
+{
+ errr res;
+
+ /* Move first */
+ if ((res = Term_gotoxy(x, y)) != 0) return (res);
+
+ /* Then add the char */
+ if ((res = Term_addch(a, c)) != 0) return (res);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Move to a location and, using an attr, add a string
+ */
+errr Term_putstr(int x, int y, int n, byte a, cptr s)
+{
+ errr res;
+
+ /* Move first */
+ if ((res = Term_gotoxy(x, y)) != 0) return (res);
+
+ /* Then add the string */
+ if ((res = Term_addstr(n, a, s)) != 0) return (res);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Place cursor at (x,y), and clear the next "n" chars
+ */
+errr Term_erase(int x, int y, int n)
+{
+ int i;
+
+ int w = Term->wid;
+ /* int h = Term->hgt; */
+
+ int x1 = -1;
+ int x2 = -1;
+
+ int na = Term->attr_blank;
+ int nc = Term->char_blank;
+
+ byte *scr_aa;
+ char *scr_cc;
+
+ byte *scr_taa;
+ char *scr_tcc;
+
+ byte *scr_eaa;
+ char *scr_ecc;
+
+ /* Place cursor */
+ if (Term_gotoxy(x, y)) return ( -1);
+
+ /* Force legal size */
+ if (x + n > w) n = w - x;
+
+ /* Fast access */
+ scr_aa = Term->scr->a[y];
+ scr_cc = Term->scr->c[y];
+
+ scr_taa = Term->scr->ta[y];
+ scr_tcc = Term->scr->tc[y];
+
+ scr_eaa = Term->scr->ea[y];
+ scr_ecc = Term->scr->ec[y];
+
+ if (n > 0 && (byte)scr_cc[x] == 255 && scr_aa[x] == 255)
+ {
+ x--;
+ n++;
+ }
+
+ /* Scan every column */
+ for (i = 0; i < n; i++, x++)
+ {
+ int oa = scr_aa[x];
+ int oc = scr_cc[x];
+
+ /* Hack -- Ignore "non-changes" */
+ if ((oa == na) && (oc == nc)) continue;
+
+ /* Save the "literal" information */
+ scr_aa[x] = na;
+ scr_cc[x] = nc;
+
+ scr_taa[x] = 0;
+ scr_tcc[x] = 0;
+
+ scr_eaa[x] = 0;
+ scr_ecc[x] = 0;
+
+ /* Track minimum changed column */
+ if (x1 < 0) x1 = x;
+
+ /* Track maximum changed column */
+ x2 = x;
+ }
+
+ /* Expand the "change area" as needed */
+ if (x1 >= 0)
+ {
+ /* Check for new min/max row info */
+ if (y < Term->y1) Term->y1 = y;
+ if (y > Term->y2) Term->y2 = y;
+
+ /* Check for new min/max col info in this row */
+ if (x1 < Term->x1[y]) Term->x1[y] = x1;
+ if (x2 > Term->x2[y]) Term->x2[y] = x2;
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Clear the entire window, and move to the top left corner
+ *
+ * Note the use of the special "total_erase" code
+ */
+errr Term_clear(void)
+{
+ int x, y;
+
+ int w = Term->wid;
+ int h = Term->hgt;
+
+ byte na = Term->attr_blank;
+ char nc = Term->char_blank;
+
+ /* Cursor usable */
+ Term->scr->cu = 0;
+
+ /* Cursor to the top left */
+ Term->scr->cx = Term->scr->cy = 0;
+
+ /* Wipe each row */
+ for (y = 0; y < h; y++)
+ {
+ byte *scr_aa = Term->scr->a[y];
+ char *scr_cc = Term->scr->c[y];
+
+ byte *scr_taa = Term->scr->ta[y];
+ char *scr_tcc = Term->scr->tc[y];
+
+ byte *scr_eaa = Term->scr->ea[y];
+ char *scr_ecc = Term->scr->ec[y];
+
+ /* Wipe each column */
+ for (x = 0; x < w; x++)
+ {
+ scr_aa[x] = na;
+ scr_cc[x] = nc;
+
+ scr_taa[x] = 0;
+ scr_tcc[x] = 0;
+
+ scr_eaa[x] = 0;
+ scr_ecc[x] = 0;
+ }
+
+ /* This row has changed */
+ Term->x1[y] = 0;
+ Term->x2[y] = w - 1;
+ }
+
+ /* Every row has changed */
+ Term->y1 = 0;
+ Term->y2 = h - 1;
+
+ /* Force "total erase" */
+ Term->total_erase = TRUE;
+
+ /* Success */
+ return (0);
+}
+
+
+
+
+
+/*
+ * Redraw (and refresh) the whole window.
+ */
+errr Term_redraw(void)
+{
+ /* Pat */
+ if ((do_movies == 1) && IN_MAINWINDOW)
+ {
+ if (!cmovie_get_msecond())
+ {
+ fprintf(movfile, "S:%ld:\n", cmov_delta_time_msec);
+ }
+ last_paused = 1;
+ }
+ /* Endpat */
+
+ /* Force "total erase" */
+ Term->total_erase = TRUE;
+
+ /* Hack -- Refresh */
+ Term_fresh();
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Redraw part of a window.
+ */
+errr Term_redraw_section(int x1, int y1, int x2, int y2)
+{
+ int i, j;
+
+ char *c_ptr;
+
+ /* Bounds checking */
+ if (y2 >= Term->hgt) y2 = Term->hgt - 1;
+ if (x2 >= Term->wid) x2 = Term->wid - 1;
+ if (y1 < 0) y1 = 0;
+ if (x1 < 0) x1 = 0;
+
+ /* Set y limits */
+ Term->y1 = y1;
+ Term->y2 = y2;
+
+ /* Set the x limits */
+ for (i = Term->y1; i <= Term->y2; i++)
+ {
+ Term->x1[i] = x1;
+ Term->x2[i] = x2;
+
+ c_ptr = Term->old->c[i];
+
+ /* Clear the section so it is redrawn */
+ for (j = x1; j <= x2; j++)
+ {
+ /* Hack - set the old character to "none" */
+ c_ptr[j] = 0;
+ }
+ }
+
+ /* Hack -- Refresh */
+ Term_fresh();
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*** Access routines ***/
+
+
+/*
+ * Extract the cursor visibility
+ */
+errr Term_get_cursor(int *v)
+{
+ /* Extract visibility */
+ (*v) = Term->scr->cv;
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Extract the current window size
+ */
+errr Term_get_size(int *w, int *h)
+{
+ /* Access the cursor */
+ (*w) = Term->wid;
+ (*h) = Term->hgt;
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Extract the current cursor location
+ */
+errr Term_locate(int *x, int *y)
+{
+ /* Access the cursor */
+ (*x) = Term->scr->cx;
+ (*y) = Term->scr->cy;
+
+ /* Warn about "useless" cursor */
+ if (Term->scr->cu) return (1);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * At a given location, determine the "current" attr and char
+ * Note that this refers to what will be on the window after the
+ * next call to "Term_fresh()". It may or may not already be there.
+ */
+errr Term_what(int x, int y, byte *a, char *c)
+{
+ int w = Term->wid;
+ int h = Term->hgt;
+
+ /* Verify location */
+ if ((x < 0) || (x >= w)) return ( -1);
+ if ((y < 0) || (y >= h)) return ( -1);
+
+ /* Direct access */
+ (*a) = Term->scr->a[y][x];
+ (*c) = Term->scr->c[y][x];
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*** Input routines ***/
+
+
+/*
+ * Flush and forget the input
+ */
+errr Term_flush(void)
+{
+ /* Hack -- Flush all events */
+ Term_xtra(TERM_XTRA_FLUSH, 0);
+
+ /* Forget all keypresses */
+ Term->key_head = Term->key_tail = 0;
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Add a keypress to the "queue"
+ */
+errr Term_keypress(int k)
+{
+ /* Hack -- Refuse to enqueue non-keys */
+ if (!k) return ( -1);
+
+ /* Store the char, advance the queue */
+ Term->key_queue[Term->key_head++] = k;
+
+ /* Circular queue, handle wrap */
+ if (Term->key_head == Term->key_size) Term->key_head = 0;
+
+ /* Success (unless overflow) */
+ if (Term->key_head != Term->key_tail) return (0);
+
+ /* Problem */
+ return (1);
+}
+
+
+/*
+ * Add a keypress to the FRONT of the "queue"
+ */
+errr Term_key_push(int k)
+{
+ /* Hack -- Refuse to enqueue non-keys */
+ if (!k) return ( -1);
+
+ /* Hack -- Overflow may induce circular queue */
+ if (Term->key_tail == 0) Term->key_tail = Term->key_size;
+
+ /* Back up, Store the char */
+ Term->key_queue[--Term->key_tail] = k;
+
+ /* Success (unless overflow) */
+ if (Term->key_head != Term->key_tail) return (0);
+
+ /* Problem */
+ return (1);
+}
+
+
+
+
+
+/*
+ * Check for a pending keypress on the key queue.
+ *
+ * Store the keypress, if any, in "ch", and return "0".
+ * Otherwise store "zero" in "ch", and return "1".
+ *
+ * Wait for a keypress if "wait" is true.
+ *
+ * Remove the keypress if "take" is true.
+ */
+errr Term_inkey(char *ch, bool_ wait, bool_ take)
+{
+ /* Assume no key */
+ (*ch) = '\0';
+
+ /* Hack -- get bored */
+ if (!Term->never_bored)
+ {
+ /* Process random events */
+ Term_xtra(TERM_XTRA_BORED, 0);
+ }
+
+ /* PatN */
+ if ((do_movies == 1) && (last_paused == 0) && (!cmovie_get_msecond()))
+ {
+ fprintf(movfile, "S:%ld:\n", cmov_delta_time_msec);
+ last_paused = 1;
+ }
+ /* PatNEnd */
+
+ /* Wait */
+ if (wait)
+ {
+ /* Process pending events while necessary */
+ while (Term->key_head == Term->key_tail)
+ {
+ /* Process events (wait for one) */
+ Term_xtra(TERM_XTRA_EVENT, TRUE);
+ }
+ }
+
+ /* Do not Wait */
+ else
+ {
+ /* Process pending events if necessary */
+ if (Term->key_head == Term->key_tail)
+ {
+ /* Process events (do not wait) */
+ Term_xtra(TERM_XTRA_EVENT, FALSE);
+ }
+ }
+
+ /* No keys are ready */
+ if (Term->key_head == Term->key_tail) return (1);
+
+ /* Extract the next keypress */
+ (*ch) = Term->key_queue[Term->key_tail];
+
+ /* If requested, advance the queue, wrap around if necessary */
+ if (take && (++Term->key_tail == Term->key_size)) Term->key_tail = 0;
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*** Extra routines ***/
+
+
+/*
+ * Save the "requested" screen into the "memorized" screen
+ *
+ * Every "Term_save()" should match exactly one "Term_load()"
+ */
+errr Term_save(void)
+{
+ int w = Term->wid;
+ int h = Term->hgt;
+
+ /* Create */
+ if (!Term->mem)
+ {
+ /* Allocate window */
+ MAKE(Term->mem, term_win);
+
+ /* Initialize window */
+ term_win_init(Term->mem, w, h);
+ }
+
+ /* Grab */
+ term_win_copy(Term->mem, Term->scr, w, h);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Same as before but can save more than once
+ */
+term_win* Term_save_to(void)
+{
+ int w = Term->wid;
+ int h = Term->hgt;
+ term_win *save;
+
+ /* Allocate window */
+ MAKE(save, term_win);
+
+ /* Initialize window */
+ term_win_init(save, w, h);
+
+ /* Grab */
+ term_win_copy(save, Term->scr, w, h);
+
+ /* Success */
+ return (save);
+}
+
+/*
+ * Restore the "requested" contents (see above).
+ *
+ * Every "Term_save()" should match exactly one "Term_load()"
+ */
+errr Term_load(void)
+{
+ int y;
+
+ int w = Term->wid;
+ int h = Term->hgt;
+
+ /* Create */
+ if (!Term->mem)
+ {
+ /* Allocate window */
+ MAKE(Term->mem, term_win);
+
+ /* Initialize window */
+ term_win_init(Term->mem, w, h);
+ }
+
+ /* Load */
+ term_win_copy(Term->scr, Term->mem, w, h);
+
+ /* Assume change */
+ for (y = 0; y < h; y++)
+ {
+ /* Assume change */
+ Term->x1[y] = 0;
+ Term->x2[y] = w - 1;
+ }
+
+ /* Assume change */
+ Term->y1 = 0;
+ Term->y2 = h - 1;
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Same as previous but allow to save more than one
+ */
+errr Term_load_from(term_win *save, bool_ final)
+{
+ int y;
+
+ int w = Term->wid;
+ int h = Term->hgt;
+
+ /* Create */
+ if (!save)
+ {
+ return (1);
+ }
+
+ /* Load */
+ term_win_copy(Term->scr, save, w, h);
+
+ /* Assume change */
+ for (y = 0; y < h; y++)
+ {
+ /* Assume change */
+ Term->x1[y] = 0;
+ Term->x2[y] = w - 1;
+ }
+
+ /* Assume change */
+ Term->y1 = 0;
+ Term->y2 = h - 1;
+
+ /* Free is requested */
+ if (final)
+ FREE(save, term_win);
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Exchange the "requested" screen with the "tmp" screen
+ */
+errr Term_exchange(void)
+{
+ int y;
+
+ int w = Term->wid;
+ int h = Term->hgt;
+
+ term_win *exchanger;
+
+
+ /* Create */
+ if (!Term->tmp)
+ {
+ /* Allocate window */
+ MAKE(Term->tmp, term_win);
+
+ /* Initialize window */
+ term_win_init(Term->tmp, w, h);
+ }
+
+ /* Swap */
+ exchanger = Term->scr;
+ Term->scr = Term->tmp;
+ Term->tmp = exchanger;
+
+ /* Assume change */
+ for (y = 0; y < h; y++)
+ {
+ /* Assume change */
+ Term->x1[y] = 0;
+ Term->x2[y] = w - 1;
+ }
+
+ /* Assume change */
+ Term->y1 = 0;
+ Term->y2 = h - 1;
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * React to a new physical window size.
+ */
+errr Term_resize(int w, int h)
+{
+ int i;
+
+ int wid, hgt;
+
+ byte *hold_x1;
+ byte *hold_x2;
+
+ term_win *hold_old;
+ term_win *hold_scr;
+ term_win *hold_mem;
+ term_win *hold_tmp;
+
+ /* Resizing is forbidden */
+ if (Term->fixed_shape) return ( -1);
+
+ /* Ignore illegal changes */
+ if ((w < 1) || (h < 1)) return ( -1);
+
+
+ /* Ignore non-changes */
+ if ((Term->wid == w) && (Term->hgt == h) && (arg_bigtile == use_bigtile)) return (1);
+ use_bigtile = arg_bigtile;
+
+ /* Minimum dimensions */
+ wid = MIN(Term->wid, w);
+ hgt = MIN(Term->hgt, h);
+
+ /* Save scanners */
+ hold_x1 = Term->x1;
+ hold_x2 = Term->x2;
+
+ /* Save old window */
+ hold_old = Term->old;
+
+ /* Save old window */
+ hold_scr = Term->scr;
+
+ /* Save old window */
+ hold_mem = Term->mem;
+
+ /* Save old window */
+ hold_tmp = Term->tmp;
+
+ /* Create new scanners */
+ C_MAKE(Term->x1, h, byte);
+ C_MAKE(Term->x2, h, byte);
+
+ /* Create new window */
+ MAKE(Term->old, term_win);
+
+ /* Initialize new window */
+ term_win_init(Term->old, w, h);
+
+ /* Save the contents */
+ term_win_copy(Term->old, hold_old, wid, hgt);
+
+ /* Create new window */
+ MAKE(Term->scr, term_win);
+
+ /* Initialize new window */
+ term_win_init(Term->scr, w, h);
+
+ /* Save the contents */
+ term_win_copy(Term->scr, hold_scr, wid, hgt);
+
+ /* If needed */
+ if (hold_mem)
+ {
+ /* Create new window */
+ MAKE(Term->mem, term_win);
+
+ /* Initialize new window */
+ term_win_init(Term->mem, w, h);
+
+ /* Save the contents */
+ term_win_copy(Term->mem, hold_mem, wid, hgt);
+ }
+
+ /* If needed */
+ if (hold_tmp)
+ {
+ /* Create new window */
+ MAKE(Term->tmp, term_win);
+
+ /* Initialize new window */
+ term_win_init(Term->tmp, w, h);
+
+ /* Save the contents */
+ term_win_copy(Term->tmp, hold_tmp, wid, hgt);
+ }
+
+ /* Free some arrays */
+ C_KILL(hold_x1, Term->hgt, byte);
+ C_KILL(hold_x2, Term->hgt, byte);
+
+ /* Nuke */
+ term_win_nuke(hold_old, Term->wid, Term->hgt);
+
+ /* Kill */
+ KILL(hold_old, term_win);
+
+ /* Illegal cursor */
+ if (Term->old->cx >= w) Term->old->cu = 1;
+ if (Term->old->cy >= h) Term->old->cu = 1;
+
+ /* Nuke */
+ term_win_nuke(hold_scr, Term->wid, Term->hgt);
+
+ /* Kill */
+ KILL(hold_scr, term_win);
+
+ /* Illegal cursor */
+ if (Term->scr->cx >= w) Term->scr->cu = 1;
+ if (Term->scr->cy >= h) Term->scr->cu = 1;
+
+ /* If needed */
+ if (hold_mem)
+ {
+ /* Nuke */
+ term_win_nuke(hold_mem, Term->wid, Term->hgt);
+
+ /* Kill */
+ KILL(hold_mem, term_win);
+
+ /* Illegal cursor */
+ if (Term->mem->cx >= w) Term->mem->cu = 1;
+ if (Term->mem->cy >= h) Term->mem->cu = 1;
+ }
+
+ /* If needed */
+ if (hold_tmp)
+ {
+ /* Nuke */
+ term_win_nuke(hold_tmp, Term->wid, Term->hgt);
+
+ /* Kill */
+ KILL(hold_tmp, term_win);
+
+ /* Illegal cursor */
+ if (Term->tmp->cx >= w) Term->tmp->cu = 1;
+ if (Term->tmp->cy >= h) Term->tmp->cu = 1;
+ }
+
+ /* Save new size */
+ Term->wid = w;
+ Term->hgt = h;
+
+ /* Force "total erase" */
+ Term->total_erase = TRUE;
+
+ /* Assume change */
+ for (i = 0; i < h; i++)
+ {
+ /* Assume change */
+ Term->x1[i] = 0;
+ Term->x2[i] = w - 1;
+ }
+
+ /* Assume change */
+ Term->y1 = 0;
+ Term->y2 = h - 1;
+
+ /* Execute the "resize_hook" hook, if available */
+ if (Term->resize_hook)
+ {
+ Term->resize_hook();
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Activate a new Term (and deactivate the current Term)
+ *
+ * This function is extremely important, and also somewhat bizarre.
+ * It is the only function that should "modify" the value of "Term".
+ *
+ * To "create" a valid "term", one should do "term_init(t)", then
+ * set the various flags and hooks, and then do "Term_activate(t)".
+ */
+errr Term_activate(term *t)
+{
+ /* Hack -- already done */
+ if (Term == t) return (1);
+
+ /* Deactivate the old Term */
+ if (Term) Term_xtra(TERM_XTRA_LEVEL, 0);
+
+ /* Hack -- Call the special "init" hook */
+ if (t && !t->active_flag)
+ {
+ /* Call the "init" hook */
+ if (t->init_hook) (*t->init_hook)(t);
+
+ /* Remember */
+ t->active_flag = TRUE;
+
+ /* Assume mapped */
+ t->mapped_flag = TRUE;
+ }
+
+ /* Remember the Term */
+ Term = t;
+
+ /* Activate the new Term */
+ if (Term) Term_xtra(TERM_XTRA_LEVEL, 1);
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Nuke a term
+ */
+errr term_nuke(term *t)
+{
+ int w = t->wid;
+ int h = t->hgt;
+
+ /* Hack -- Call the special "nuke" hook */
+ if (t->active_flag)
+ {
+ /* Call the "nuke" hook */
+ if (t->nuke_hook) (*t->nuke_hook)(t);
+
+ /* Remember */
+ t->active_flag = FALSE;
+
+ /* Assume not mapped */
+ t->mapped_flag = FALSE;
+ }
+
+
+ /* Nuke "displayed" */
+ term_win_nuke(t->old, w, h);
+
+ /* Kill "displayed" */
+ KILL(t->old, term_win);
+
+ /* Nuke "requested" */
+ term_win_nuke(t->scr, w, h);
+
+ /* Kill "requested" */
+ KILL(t->scr, term_win);
+
+ /* If needed */
+ if (t->mem)
+ {
+ /* Nuke "memorized" */
+ term_win_nuke(t->mem, w, h);
+
+ /* Kill "memorized" */
+ KILL(t->mem, term_win);
+ }
+
+ /* If needed */
+ if (t->tmp)
+ {
+ /* Nuke "temporary" */
+ term_win_nuke(t->tmp, w, h);
+
+ /* Kill "temporary" */
+ KILL(t->tmp, term_win);
+ }
+
+ /* Free some arrays */
+ C_KILL(t->x1, h, byte);
+ C_KILL(t->x2, h, byte);
+
+ /* Free the input queue */
+ C_KILL(t->key_queue, t->key_size, char);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Initialize a term, using a window of the given size.
+ * Also prepare the "input queue" for "k" keypresses
+ * By default, the cursor starts out "invisible"
+ * By default, we "erase" using "black spaces"
+ */
+errr term_init(term *t, int w, int h, int k)
+{
+ int y;
+
+ /* Wipe it */
+ (void)WIPE(t, term);
+
+
+ /* Prepare the input queue */
+ t->key_head = t->key_tail = 0;
+
+ /* Determine the input queue size */
+ t->key_size = k;
+
+ /* Allocate the input queue */
+ C_MAKE(t->key_queue, t->key_size, char);
+
+
+ /* Save the size */
+ t->wid = w;
+ t->hgt = h;
+
+ /* Allocate change arrays */
+ C_MAKE(t->x1, h, byte);
+ C_MAKE(t->x2, h, byte);
+
+
+ /* Allocate "displayed" */
+ MAKE(t->old, term_win);
+
+ /* Initialize "displayed" */
+ term_win_init(t->old, w, h);
+
+
+ /* Allocate "requested" */
+ MAKE(t->scr, term_win);
+
+ /* Initialize "requested" */
+ term_win_init(t->scr, w, h);
+
+
+ /* Assume change */
+ for (y = 0; y < h; y++)
+ {
+ /* Assume change */
+ t->x1[y] = 0;
+ t->x2[y] = w - 1;
+ }
+
+ /* Assume change */
+ t->y1 = 0;
+ t->y2 = h - 1;
+
+ /* Force "total erase" */
+ t->total_erase = TRUE;
+
+
+ /* Default "blank" */
+ t->attr_blank = 0;
+ t->char_blank = ' ';
+
+
+ /* Success */
+ return (0);
+}
+
+/*
+ * Determine if we are called in the same second as the last time?
+ * This *ASSUMES* that time_t is seconds past something. Is this portable?
+ */
+int cmovie_get_msecond(void)
+{
+#ifndef USE_PRECISE_CMOVIE
+ /* Not very precise, but portable */
+ time_t thisc;
+
+ thisc = time(NULL);
+
+ cmov_delta_time_msec = 300;
+
+ if (thisc == lastc)
+ {
+ return 1;
+ }
+ return 0;
+#else /* Very precise but needs main-foo.c to define TERM_XTRA_GET_DELAY */
+Term_xtra(TERM_XTRA_GET_DELAY, 0);
+
+ cmov_delta_time_msec = Term_xtra_long - cmov_last_time_msec;
+ cmov_last_time_msec = Term_xtra_long;
+ return 0;
+#endif
+}
+
+void cmovie_init_second()
+{
+#ifndef USE_PRECISE_CMOVIE
+ /* Not very precise, but portable */
+ cmov_last_time_msec = 0;
+#else /* Precise but need main-foo.c to have TERM_XTRA_GET_DELAY */
+ Term_xtra(TERM_XTRA_GET_DELAY, 0);
+ cmov_last_time_msec = Term_xtra_long;
+#endif
+}
diff --git a/src/z-term.h b/src/z-term.h
new file mode 100644
index 00000000..31e5b308
--- /dev/null
+++ b/src/z-term.h
@@ -0,0 +1,343 @@
+/* File: z-term.h */
+
+/*
+ * Copyright (c) 1997 Ben Harrison
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+#ifndef INCLUDED_Z_TERM_H
+#define INCLUDED_Z_TERM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "h-basic.h"
+
+#define IN_MAINWINDOW (Term == term_screen)
+
+/*
+ * A term_win is a "window" for a Term
+ *
+ * - Cursor Useless/Visible codes
+ * - Cursor Location (see "Useless")
+ *
+ * - Array[h] -- Access to the attribute array
+ * - Array[h] -- Access to the character array
+ *
+ * - Array[h*w] -- Attribute array
+ * - Array[h*w] -- Character array
+ *
+ * Note that the attr/char pair at (x,y) is a[y][x]/c[y][x]
+ * and that the row of attr/chars at (0,y) is a[y]/c[y]
+ */
+
+typedef struct term_win term_win;
+
+struct term_win
+{
+ bool_ cu, cv;
+ byte cx, cy;
+
+ byte **a;
+ char **c;
+
+ byte *va;
+ char *vc;
+
+ byte **ta;
+ char **tc;
+
+ byte *vta;
+ char *vtc;
+
+ byte **ea;
+ char **ec;
+
+ byte *vea;
+ char *vec;
+
+};
+
+
+
+/*
+ * An actual "term" structure
+ *
+ * - Extra "user" info (used by application)
+ *
+ * - Extra "data" info (used by implementation)
+ *
+ *
+ * - Flag "user_flag"
+ * An extra "user" flag (used by application)
+ *
+ *
+ * - Flag "data_flag"
+ * An extra "data" flag (used by implementation)
+ *
+ *
+ * - Flag "active_flag"
+ * This "term" is "active"
+ *
+ * - Flag "mapped_flag"
+ * This "term" is "mapped"
+ *
+ * - Flag "total_erase"
+ * This "term" should be fully erased
+ *
+ * - Flag "fixed_shape"
+ * This "term" is not allowed to resize
+ *
+ * - Flag "icky_corner"
+ * This "term" has an "icky" corner grid
+ *
+ * - Flag "soft_cursor"
+ * This "term" uses a "software" cursor
+ *
+ * - Flag "always_pict"
+ * Use the "Term_pict()" routine for all text
+ *
+ * - Flag "higher_pict"
+ * Use the "Term_pict()" routine for special text
+ *
+ * - Flag "always_text"
+ * Use the "Term_text()" routine for invisible text
+ *
+ * - Flag "unused_flag"
+ * Reserved for future use
+ *
+ * - Flag "never_bored"
+ * Never call the "TERM_XTRA_BORED" action
+ *
+ * - Flag "never_frosh"
+ * Never call the "TERM_XTRA_FROSH" action
+ *
+ *
+ * - Value "attr_blank"
+ * Use this "attr" value for "blank" grids
+ *
+ * - Value "char_blank"
+ * Use this "char" value for "blank" grids
+ *
+ *
+ * - Ignore this pointer
+ *
+ * - Keypress Queue -- various data
+ *
+ * - Keypress Queue -- pending keys
+ *
+ *
+ * - Window Width (max 255)
+ * - Window Height (max 255)
+ *
+ * - Minimum modified row
+ * - Maximum modified row
+ *
+ * - Minimum modified column (per row)
+ * - Maximum modified column (per row)
+ *
+ *
+ * - Displayed screen image
+ * - Requested screen image
+ *
+ * - Temporary screen image
+ * - Memorized screen image
+ *
+ *
+ * - Hook for init-ing the term
+ * - Hook for nuke-ing the term
+ *
+ * - Hook for user actions
+ *
+ * - Hook for extra actions
+ *
+ * - Hook for placing the cursor
+ *
+ * - Hook for drawing some blank spaces
+ *
+ * - Hook for drawing a string of chars using an attr
+ *
+ * - Hook for drawing a sequence of special attr/char pairs
+ */
+
+typedef struct term term;
+
+struct term
+{
+ vptr user;
+
+ vptr data;
+
+ bool_ user_flag;
+
+ bool_ data_flag;
+
+ bool_ active_flag;
+ bool_ mapped_flag;
+ bool_ total_erase;
+ bool_ fixed_shape;
+ bool_ icky_corner;
+ bool_ soft_cursor;
+ bool_ always_pict;
+ bool_ higher_pict;
+ bool_ always_text;
+ bool_ unused_flag;
+ bool_ never_bored;
+ bool_ never_frosh;
+
+ byte attr_blank;
+ char char_blank;
+
+ char *key_queue;
+
+ u16b key_head;
+ u16b key_tail;
+ u16b key_xtra;
+ u16b key_size;
+
+ byte wid;
+ byte hgt;
+
+ byte y1;
+ byte y2;
+
+ byte *x1;
+ byte *x2;
+
+ term_win *old;
+ term_win *scr;
+
+ term_win *tmp;
+ term_win *mem;
+
+ void (*init_hook)(term *t);
+ void (*nuke_hook)(term *t);
+
+ errr (*user_hook)(int n);
+
+ errr (*xtra_hook)(int n, int v);
+
+ errr (*curs_hook)(int x, int y);
+
+ errr (*wipe_hook)(int x, int y, int n);
+
+ errr (*text_hook)(int x, int y, int n, byte a, cptr s);
+
+ void (*resize_hook)(void);
+
+ errr (*pict_hook)(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp, const byte *eap, const char *ecp);
+
+};
+
+
+
+
+
+
+
+/**** Available Constants ****/
+
+
+/*
+ * Definitions for the "actions" of "Term_xtra()"
+ *
+ * These values may be used as the first parameter of "Term_xtra()",
+ * with the second parameter depending on the "action" itself. Many
+ * of the actions shown below are optional on at least one platform.
+ *
+ * The "TERM_XTRA_EVENT" action uses "v" to "wait" for an event
+ * The "TERM_XTRA_SHAPE" action uses "v" to "show" the cursor
+ * The "TERM_XTRA_FROSH" action uses "v" for the index of the row
+ * The "TERM_XTRA_SOUND" action uses "v" for the index of a sound
+ * The "TERM_XTRA_ALIVE" action uses "v" to "activate" (or "close")
+ * The "TERM_XTRA_LEVEL" action uses "v" to "resume" (or "suspend")
+ * The "TERM_XTRA_DELAY" action uses "v" as a "millisecond" value
+ *
+ * The other actions do not need a "v" code, so "zero" is used.
+ */
+#define TERM_XTRA_EVENT 1 /* Process some pending events */
+#define TERM_XTRA_FLUSH 2 /* Flush all pending events */
+#define TERM_XTRA_CLEAR 3 /* Clear the entire window */
+#define TERM_XTRA_SHAPE 4 /* Set cursor shape (optional) */
+#define TERM_XTRA_FROSH 5 /* Flush one row (optional) */
+#define TERM_XTRA_FRESH 6 /* Flush all rows (optional) */
+#define TERM_XTRA_NOISE 7 /* Make a noise (optional) */
+#define TERM_XTRA_SOUND 8 /* Make a sound (optional) */
+#define TERM_XTRA_BORED 9 /* Handle stuff when bored (optional) */
+#define TERM_XTRA_REACT 10 /* React to global changes (optional) */
+#define TERM_XTRA_ALIVE 11 /* Change the "hard" level (optional) */
+#define TERM_XTRA_LEVEL 12 /* Change the "soft" level (optional) */
+#define TERM_XTRA_DELAY 13 /* Delay some milliseconds (optional) */
+#define TERM_XTRA_GET_DELAY 14 /* Get the cuyrrent time in milliseconds (optional) */
+#define TERM_XTRA_SCANSUBDIR 15 /* Scan for subdir in a dir */
+#define TERM_XTRA_RENAME_MAIN_WIN 16 /* Rename the main game window */
+
+
+/**** Available Variables ****/
+
+extern term *Term;
+extern FILE *movfile;
+extern int do_movies;
+extern int last_paused;
+
+
+/**** Available Functions ****/
+
+extern errr Term_user(int n);
+extern errr Term_xtra(int n, int v);
+extern long Term_xtra_long;
+extern char scansubdir_dir[1024];
+extern int scansubdir_max;
+extern cptr scansubdir_result[255];
+
+extern void Term_queue_char(int x, int y, byte a, char c, byte ta, char tc, byte ea, char ec);
+extern void Term_queue_line(int x, int y, int n, byte *a, char *c, byte *ta, char *tc, byte *ea, char *ec);
+extern void Term_queue_chars(int x, int y, int n, byte a, cptr s);
+
+extern errr Term_fresh(void);
+extern errr Term_set_cursor(int v);
+extern errr Term_gotoxy(int x, int y);
+extern errr Term_draw(int x, int y, byte a, char c);
+extern errr Term_addch(byte a, char c);
+extern errr Term_addstr(int n, byte a, cptr s);
+extern errr Term_putch(int x, int y, byte a, char c);
+extern errr Term_putstr(int x, int y, int n, byte a, cptr s);
+extern errr Term_erase(int x, int y, int n);
+extern errr Term_clear(void);
+extern errr Term_redraw(void);
+extern errr Term_redraw_section(int x1, int y1, int x2, int y2);
+
+extern errr Term_get_cursor(int *v);
+extern errr Term_get_size(int *w, int *h);
+extern errr Term_locate(int *x, int *y);
+extern errr Term_what(int x, int y, byte *a, char *c);
+
+extern errr Term_flush(void);
+extern errr Term_keypress(int k);
+extern errr Term_key_push(int k);
+extern errr Term_inkey(char *ch, bool_ wait, bool_ take);
+
+extern errr Term_save(void);
+extern term_win* Term_save_to(void);
+extern errr Term_load(void);
+extern errr Term_load_from(term_win *save, bool_ final);
+
+extern errr Term_exchange(void);
+
+extern errr Term_resize(int w, int h);
+
+extern errr Term_activate(term *t);
+
+extern errr term_nuke(term *t);
+extern errr term_init(term *t, int w, int h, int k);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+
diff --git a/src/z-util.c b/src/z-util.c
new file mode 100644
index 00000000..7c5374f3
--- /dev/null
+++ b/src/z-util.c
@@ -0,0 +1,234 @@
+/* File: z-util.c */
+
+/* Purpose: Low level utilities -BEN- */
+
+#include "z-util.h"
+
+
+
+/*
+ * Global variables for temporary use
+ */
+char char_tmp = 0;
+byte byte_tmp = 0;
+sint sint_tmp = 0;
+uint uint_tmp = 0;
+long long_tmp = 0;
+huge huge_tmp = 0;
+errr errr_tmp = 0;
+
+
+/*
+ * Global pointers for temporary use
+ */
+cptr cptr_tmp = NULL;
+vptr vptr_tmp = NULL;
+
+
+
+
+/*
+ * Constant bool meaning true
+ */
+bool_ bool_true = 1;
+
+/*
+ * Constant bool meaning false
+ */
+bool_ bool_false = 0;
+
+
+/*
+ * Global NULL cptr
+ */
+cptr cptr_null = NULL;
+
+
+/*
+ * Global NULL vptr
+ */
+vptr vptr_null = NULL;
+
+
+
+/*
+ * Global SELF vptr
+ */
+vptr vptr_self = (vptr)(&vptr_self);
+
+
+
+/*
+ * Convenient storage of the program name
+ */
+cptr argv0 = NULL;
+
+
+
+/*
+ * A routine that does nothing
+ */
+void func_nothing(void)
+{
+ /* Do nothing */
+}
+
+
+/*
+ * A routine that always returns "success"
+ */
+errr func_success(void)
+{
+ return (0);
+}
+
+
+/*
+ * A routine that always returns a simple "problem code"
+ */
+errr func_problem(void)
+{
+ return (1);
+}
+
+
+/*
+ * A routine that always returns a simple "failure code"
+ */
+errr func_failure(void)
+{
+ return ( -1);
+}
+
+
+
+/*
+ * A routine that always returns "true"
+ */
+bool_ func_true(void)
+{
+ return (1);
+}
+
+
+/*
+ * A routine that always returns "false"
+ */
+bool_ func_false(void)
+{
+ return (0);
+}
+
+
+
+
+/*
+ * Determine if string "t" is equal to string "t"
+ */
+bool_ streq(cptr a, cptr b)
+{
+ if ((a == NULL) && (b == NULL)) { return TRUE; }
+ if (a == NULL) { return FALSE; }
+ if (b == NULL) { return FALSE; }
+ return (!strcmp(a, b));
+}
+
+
+/*
+ * Determine if string "t" is a suffix of string "s"
+ */
+bool_ suffix(cptr s, cptr t)
+{
+ int tlen = strlen(t);
+ int slen = strlen(s);
+
+ /* Check for incompatible lengths */
+ if (tlen > slen) return (FALSE);
+
+ /* Compare "t" to the end of "s" */
+ return (!strcmp(s + slen - tlen, t));
+}
+
+
+
+
+/*
+ * Redefinable "plog" action
+ */
+void (*plog_aux)(cptr) = NULL;
+
+/*
+ * Print (or log) a "warning" message (ala "perror()")
+ * Note the use of the (optional) "plog_aux" hook.
+ */
+void plog(cptr str)
+{
+ /* Use the "alternative" function if possible */
+ if (plog_aux) (*plog_aux)(str);
+
+ /* Just do a labeled fprintf to stderr */
+ else (void)(fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "???", str));
+}
+
+
+
+/*
+ * Redefinable "quit" action
+ */
+void (*quit_aux)(cptr) = NULL;
+
+/*
+ * Exit (ala "exit()"). If 'str' is NULL, do "exit(0)".
+ * If 'str' begins with "+" or "-", do "exit(atoi(str))".
+ * Otherwise, plog() 'str' and exit with an error code of -1.
+ * But always use 'quit_aux', if set, before anything else.
+ */
+void quit(cptr str)
+{
+ /* Attempt to use the aux function */
+ if (quit_aux) (*quit_aux)(str);
+
+ /* Success */
+ if (!str) (void)(exit(0));
+
+ /* Extract a "special error code" */
+ if ((str[0] == '-') || (str[0] == '+')) (void)(exit(atoi(str)));
+
+ /* Send the string to plog() */
+ plog(str);
+
+ /* Failure */
+ (void)(exit( -1));
+}
+
+
+
+/*
+ * Redefinable "core" action
+ */
+void (*core_aux)(cptr) = NULL;
+
+/*
+ * Dump a core file, after printing a warning message
+ * As with "quit()", try to use the "core_aux()" hook first.
+ */
+void core(cptr str)
+{
+ char *crash = NULL;
+
+ /* Use the aux function */
+ if (core_aux) (*core_aux)(str);
+
+ /* Dump the warning string */
+ if (str) plog(str);
+
+ /* Attempt to Crash */
+ (*crash) = (*crash);
+
+ /* Be sure we exited */
+ quit("core() failed");
+}
+
+
+
+
diff --git a/src/z-util.h b/src/z-util.h
new file mode 100644
index 00000000..11dbdb4e
--- /dev/null
+++ b/src/z-util.h
@@ -0,0 +1,91 @@
+/* File z-util.h */
+
+#ifndef INCLUDED_Z_UTIL_H
+#define INCLUDED_Z_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "h-basic.h"
+
+
+/*
+ * Extremely basic stuff, like global temp and constant variables.
+ * Also, some very useful low level functions, such as "streq()".
+ * All variables and functions in this file are "addressable".
+ */
+
+
+/**** Available variables ****/
+
+/* Temporary Vars */
+extern char char_tmp;
+extern byte byte_tmp;
+extern sint sint_tmp;
+extern uint uint_tmp;
+extern long long_tmp;
+extern huge huge_tmp;
+extern errr errr_tmp;
+
+/* Temporary Pointers */
+extern cptr cptr_tmp;
+extern vptr vptr_tmp;
+
+
+/* Constant pointers (NULL) */
+extern cptr cptr_null;
+extern vptr vptr_null;
+
+
+/* A bizarre vptr that always points at itself */
+extern vptr vptr_self;
+
+
+/* A cptr to the name of the program */
+extern cptr argv0;
+
+
+/* Aux functions */
+extern void (*plog_aux)(cptr);
+extern void (*quit_aux)(cptr);
+extern void (*core_aux)(cptr);
+
+
+/**** Available Functions ****/
+
+/* Function that does nothing */
+extern void func_nothing(void);
+
+/* Functions that return basic "errr" codes */
+extern errr func_success(void);
+extern errr func_problem(void);
+extern errr func_failure(void);
+
+/* Functions that return bools */
+extern bool_ func_true(void);
+extern bool_ func_false(void);
+
+
+/* Test equality, prefix, suffix */
+extern bool_ streq(cptr s, cptr t);
+extern bool_ prefix(cptr s, cptr t);
+extern bool_ suffix(cptr s, cptr t);
+
+
+/* Print an error message */
+extern void plog(cptr str);
+
+/* Exit, with optional message */
+extern void quit(cptr str);
+
+/* Dump core, with optional message */
+extern void core(cptr str);
+
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/z-virt.c b/src/z-virt.c
new file mode 100644
index 00000000..c9277166
--- /dev/null
+++ b/src/z-virt.c
@@ -0,0 +1,187 @@
+/* File: z-virt.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+/* Purpose: Memory management routines -BEN- */
+
+#include "z-virt.h"
+
+#include "z-util.h"
+
+
+/*
+ * Allow debugging messages to track memory usage.
+ */
+#ifdef VERBOSE_RALLOC
+static long virt_make = 0;
+static long virt_kill = 0;
+static long virt_size = 0;
+#endif
+
+
+/*
+ * Optional auxiliary "rnfree" function
+ */
+vptr (*rnfree_aux)(vptr, huge) = NULL;
+
+/*
+ * Free some memory (allocated by ralloc), return NULL
+ */
+vptr rnfree(vptr p, huge len)
+{
+ /* Easy to free zero bytes */
+ if (len == 0) return (NULL);
+
+#ifdef VERBOSE_RALLOC
+
+ /* Decrease memory count */
+ virt_kill += len;
+
+ /* Message */
+ if (len > virt_size)
+ {
+ char buf[80];
+ sprintf(buf, "Kill (%ld): %ld - %ld = %ld.",
+ len, virt_make, virt_kill, virt_make - virt_kill);
+ plog(buf);
+ }
+
+#endif
+
+ /* Use the "aux" function */
+ if (rnfree_aux) return ((*rnfree_aux)(p, len));
+
+ /* Use "free" */
+ free ((char*)(p));
+
+ /* Done */
+ return (NULL);
+}
+
+
+/*
+ * Optional auxiliary "rpanic" function
+ */
+vptr (*rpanic_aux)(huge) = NULL;
+
+/*
+ * The system is out of memory, so panic. If "rpanic_aux" is set,
+ * it can be used to free up some memory and do a new "ralloc()",
+ * or if not, it can be used to save things, clean up, and exit.
+ * By default, this function simply crashes the computer.
+ */
+vptr rpanic(huge len)
+{
+ /* Hopefully, we have a real "panic" function */
+ if (rpanic_aux) return ((*rpanic_aux)(len));
+
+ /* Attempt to crash before icky things happen */
+ core("Out of Memory!");
+
+ /* Paranoia */
+ return ((vptr)(NULL));
+}
+
+
+/*
+ * Optional auxiliary "ralloc" function
+ */
+vptr (*ralloc_aux)(huge) = NULL;
+
+
+/*
+ * Allocate some memory
+ */
+vptr ralloc(huge len)
+{
+ vptr mem;
+
+ /* Allow allocation of "zero bytes" */
+ if (len == 0) return ((vptr)(NULL));
+
+#ifdef VERBOSE_RALLOC
+
+ /* Count allocated memory */
+ virt_make += len;
+
+ /* Log important allocations */
+ if (len > virt_size)
+ {
+ char buf[80];
+ sprintf(buf, "Make (%ld): %ld - %ld = %ld.",
+ len, virt_make, virt_kill, virt_make - virt_kill);
+ plog(buf);
+ }
+
+#endif
+
+ /* Use the aux function if set */
+ if (ralloc_aux) mem = (*ralloc_aux)(len);
+
+ /* Use malloc() to allocate some memory */
+ else mem = ((vptr)(malloc((size_t)(len))));
+
+ /* We were able to acquire memory */
+ if (!mem) mem = rpanic(len);
+
+ /* Return the memory, if any */
+ return (mem);
+}
+
+
+
+
+/*
+ * Allocate a constant string, containing the same thing as 'str'
+ */
+cptr string_make(cptr str)
+{
+ huge len = 0;
+ cptr t = str;
+ char *s, *res;
+
+ /* Simple sillyness */
+ if (!str) return (str);
+
+ /* Get the number of chars in the string, including terminator */
+ while (str[len++]) /* loop */;
+
+ /* Allocate space for the string */
+ s = res = (char*)(ralloc(len));
+
+ /* Copy the string (with terminator) */
+ while ((*s++ = *t++) != 0) /* loop */;
+
+ /* Return the allocated, initialized, string */
+ return (res);
+}
+
+
+/*
+ * Un-allocate a string allocated above.
+ * Depends on no changes being made to the string.
+ */
+errr string_free(cptr str)
+{
+ huge len = 0;
+
+ /* Succeed on non-strings */
+ if (!str) return (0);
+
+ /* Count the number of chars in 'str' plus the terminator */
+ while (str[len++]) /* loop */;
+
+ /* Kill the buffer of chars we must have allocated above */
+ rnfree((vptr)(str), len);
+
+ /* Success */
+ return (0);
+}
+
+
diff --git a/src/z-virt.h b/src/z-virt.h
new file mode 100644
index 00000000..a7880f2f
--- /dev/null
+++ b/src/z-virt.h
@@ -0,0 +1,168 @@
+/* File: z-virt.h */
+
+/*
+ * Copyright (c) 1997 Ben Harrison
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+#ifndef INCLUDED_Z_VIRT_H
+#define INCLUDED_Z_VIRT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "h-basic.h"
+
+#ifdef CHECK_MEMORY_LEAKS
+#include <leak_detector.h>
+#endif
+
+/*
+ * Memory management routines.
+ *
+ * Set ralloc_aux to modify the memory allocation routine.
+ * Set rnfree_aux to modify the memory de-allocation routine.
+ * Set rpanic_aux to let the program react to memory failures.
+ *
+ * These routines work best as a *replacement* for malloc/free.
+ *
+ * The string_make() and string_free() routines handle dynamic strings.
+ * A dynamic string is a string allocated at run-time, which should not
+ * be modified once it has been created.
+ *
+ * Note the macros below which simplify the details of allocation,
+ * deallocation, setting, clearing, casting, size extraction, etc.
+ *
+ * The macros MAKE/C_MAKE and KILL/C_KILL have a "procedural" metaphor,
+ * and they actually modify their arguments.
+ *
+ * Note that, for some reason, some allocation macros may disallow
+ * "stars" in type names, but you can use typedefs to circumvent
+ * this. For example, instead of "type **p; MAKE(p,type*);" you
+ * can use "typedef type *type_ptr; type_ptr *p; MAKE(p,type_ptr)".
+ *
+ * Note that it is assumed that "memset()" will function correctly,
+ * in particular, that it returns its first argument.
+ */
+
+
+
+/**** Available macros ****/
+
+
+/* Size of 'N' things of type 'T' */
+#define C_SIZE(N,T) \
+ ((huge)((N)*(sizeof(T))))
+
+/* Size of one thing of type 'T' */
+#define SIZE(T) \
+ ((huge)(sizeof(T)))
+
+
+/* Wipe an array of type T[N], at location P, and return P */
+#define C_WIPE(P,N,T) \
+ (memset((char*)(P),0,C_SIZE(N,T)))
+
+/* Wipe a thing of type T, at location P, and return P */
+#define WIPE(P,T) \
+ (memset((char*)(P),0,SIZE(T)))
+
+
+/* Load an array of type T[N], at location P1, from another, at location P2 */
+#define C_COPY(P1,P2,N,T) \
+ (memcpy((char*)(P1),(char*)(P2),C_SIZE(N,T)))
+
+/* Load a thing of type T, at location P1, from another, at location P2 */
+#define COPY(P1,P2,T) \
+ (memcpy((char*)(P1),(char*)(P2),SIZE(T)))
+
+
+/* Free an array of N things of type T at P, return NULL */
+#define C_FREE(P,N,T) \
+ (rnfree(P,C_SIZE(N,T)))
+
+/* Free one thing of type T at P, return NULL */
+#define FREE(P,T) \
+ (rnfree(P,SIZE(T)))
+
+
+/* Allocate, and return, an array of type T[N] */
+#define C_RNEW(N,T) \
+ (ralloc(C_SIZE(N,T)))
+
+/* Allocate, and return, a thing of type T */
+#define RNEW(T) \
+ (ralloc(SIZE(T)))
+
+
+/* Allocate, wipe, and return an array of type T[N] */
+#define C_ZNEW(N,T) \
+ (C_WIPE(C_RNEW(N,T),N,T))
+
+/* Allocate, wipe, and return a thing of type T */
+#define ZNEW(T) \
+ (WIPE(RNEW(T),T))
+
+
+/* Allocate a wiped array of type T[N], assign to pointer P */
+#define C_MAKE(P,N,T) \
+ ((P)=C_ZNEW(N,T))
+
+/* Allocate a wiped thing of type T, assign to pointer P */
+#define MAKE(P,T) \
+ ((P)=ZNEW(T))
+
+
+/* Free an array of type T[N], at location P, and set P to NULL */
+#define C_KILL(P,N,T) \
+ ((P)=C_FREE(P,N,T))
+
+/* Free a thing of type T, at location P, and set P to NULL */
+#define KILL(P,T) \
+ ((P)=FREE(P,T))
+
+
+
+/**** Available variables ****/
+
+/* Replacement hook for "rnfree()" */
+extern vptr (*rnfree_aux)(vptr, huge);
+
+/* Replacement hook for "rpanic()" */
+extern vptr (*rpanic_aux)(huge);
+
+/* Replacement hook for "ralloc()" */
+extern vptr (*ralloc_aux)(huge);
+
+
+/**** Available functions ****/
+
+/* De-allocate a given amount of memory */
+extern vptr rnfree(vptr p, huge len);
+
+/* Panic, attempt to Allocate 'len' bytes */
+extern vptr rpanic(huge len);
+
+/* Allocate (and return) 'len', or dump core */
+extern vptr ralloc(huge len);
+
+/* Create a "dynamic string" */
+extern cptr string_make(cptr str);
+
+/* Free a string allocated with "string_make()" */
+extern errr string_free(cptr str);
+
+
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+
+#endif
diff --git a/src/z_pack.pkg b/src/z_pack.pkg
new file mode 100644
index 00000000..5a46b3b2
--- /dev/null
+++ b/src/z_pack.pkg
@@ -0,0 +1,398 @@
+/* File: z_pack.pkg */
+
+/*
+ * Purpose: Lua interface defitions for z-*.c
+ * To be processed by tolua to generate C source code.
+ */
+
+$#include "angband.h"
+
+/** @typedef cptr
+ * @note String
+ */
+typedef char* cptr;
+/** @typedef errr
+ * @note Number
+ */
+typedef int errr;
+/** @typedef bool
+ * @note Boolean
+ */
+typedef unsigned char bool;
+/** @typedef byte
+ * @note Number
+ */
+typedef unsigned char byte;
+/** @typedef s16b
+ * @note Number
+ */
+typedef signed short s16b;
+/** @typedef u16b
+ * @note Number
+ */
+typedef unsigned short u16b;
+/** @typedef s32b
+ * @note Number
+ */
+typedef signed int s32b;
+/** @typedef u32b
+ * @note Number
+ */
+typedef unsigned int u32b;
+
+/** @name Terminal actions
+ * @{ */
+/** @def TERM_XTRA_EVENT
+ * @note Process some pending events
+ */
+#define TERM_XTRA_EVENT 1
+/** @def TERM_XTRA_FLUSH
+ * @note Flush all pending events
+ */
+#define TERM_XTRA_FLUSH 2
+/** @def TERM_XTRA_CLEAR
+ * @note Clear the entire window
+ */
+#define TERM_XTRA_CLEAR 3
+/** @def TERM_XTRA_SHAPE
+ * @note Set cursor shape (optional)
+ */
+#define TERM_XTRA_SHAPE 4
+/** @def TERM_XTRA_FROSH
+ * @note Flush one row (optional)
+ */
+#define TERM_XTRA_FROSH 5
+/** @def TERM_XTRA_FRESH
+ * @note Flush all rows (optional)
+ */
+#define TERM_XTRA_FRESH 6
+/** @def TERM_XTRA_NOISE
+ * @note Make a noise (optional)
+ */
+#define TERM_XTRA_NOISE 7
+/** @def TERM_XTRA_SOUND
+ * @note Make a sound (optional)
+ */
+#define TERM_XTRA_SOUND 8
+/** @def TERM_XTRA_BORED
+ * @note Handle stuff when bored (optional)
+ */
+#define TERM_XTRA_BORED 9
+/** @def TERM_XTRA_REACT
+ * @note React to global changes (optional)
+ */
+#define TERM_XTRA_REACT 10
+/** @def TERM_XTRA_ALIVE
+ * @note Change the "hard" level (optional)
+ */
+#define TERM_XTRA_ALIVE 11
+/** @def TERM_XTRA_LEVEL
+ * @note Change the "soft" level (optional)
+ */
+#define TERM_XTRA_LEVEL 12
+/** @def TERM_XTRA_DELAY
+ * @note Delay some milliseconds (optional)
+ */
+#define TERM_XTRA_DELAY 13
+/** @def TERM_XTRA_GET_DELAY
+ * @note Get the cuyrrent time in milliseconds (optional)
+ */
+#define TERM_XTRA_GET_DELAY 14
+/** @def TERM_XTRA_SCANSUBDIR
+ * @note Scan for subdir in a dir
+ */
+#define TERM_XTRA_SCANSUBDIR 15
+/** @} */
+
+/** @var Term_xtra_long
+ * @brief Number
+ */
+extern long Term_xtra_long;
+
+/** @var scansubdir_dir[1024]
+ * @brief String
+ * @note The directory which is scanned for sub-directories.
+ */
+char scansubdir_dir[1024];
+
+/** @var scansubdir_max
+ * @brief Number
+ * @note The number of entries in the scansubdir_result array.
+ */
+int scansubdir_max;
+
+/** @var scansubdir_result[scansubdir_max]
+ * @brief String
+ * @note The sub-directories of scansubdir_dir directory.
+ */
+cptr scansubdir_result[scansubdir_max];
+
+/** @fn Term_xtra(int n, int v)
+ * @brief Generic function to perform system dependant terminal actions.\n
+ * @param n Number \n a terminal action (see TERM_XTRA fields).
+ * @brief Terminal action
+ * @param v Number \n variable depending on the terminal action.
+ * @brief Variable
+ * @return Number \n Result of the terminal action.
+ * @note
+ * The "Term->xtra_hook" hook provides a variety of different functions,
+ * based on the first parameter (which should be taken from the various
+ * TERM_XTRA_* defines) and the second parameter (which may make sense
+ * only for some first parameters). It is available to the program via
+ * the "Term_xtra()" function, though some first parameters are only
+ * "legal" when called from inside this package.
+ * @note (see file z-term.c)
+ */
+extern errr Term_xtra(int n, int v);
+
+/** @fn Term_set_cursor(int v)
+ * @brief Set the cursor visibility.\n
+ * @param v Number \n v is the visibility.
+ * @brief Visibility
+ * @return Number \n 1 if visibility was unchanged, otherwise 0.
+ * @note
+ * Cursor visibility (field "cv") is defined as a boolean, so take care what
+ * value is assigned to "v".
+ * @note (see file z-term.c)
+ */
+extern errr Term_set_cursor(int v);
+
+/** @fn Term_gotoxy(int x, int y)
+ * @brief Place the cursor at a given location.\n
+ * @param x Number \n x-coordinate of target location.
+ * @brief X-coordinate
+ * @param y Number \n y-coordinate of target location.
+ * @brief Y-coordinate
+ * @return Number \n -1 if cursor could not be placed at given location,
+ * otherwise 0.
+ * @note
+ * Note -- "illegal" requests do not move the cursor.\n\n
+ * The cursor is flagged as useful if it placed okay.
+ * @note (see file z-term.c)
+ */
+extern errr Term_gotoxy(int x, int y);
+
+/** @fn Term_putch(int x, int y, byte a, char c)
+ * @brief Move to a location and, using an attr, add a char.\n
+ * @param x Number \n x-coordinate of target location.
+ * @brief X-coordinate
+ * @param y Number \n y-coordinate of target location.
+ * @brief Y-coordinate
+ * @param a Number \n attribute of character.
+ * @brief Attribute
+ * @param c String \n the character.
+ * @brief Character
+ * @return Number \n <0 if error, 0 if success, 1 if success but cursor is
+ * useless.
+ * @note
+ * We return "-2" if the character is "illegal". XXX XXX\n\n
+ * We return "-1" if the cursor is currently unusable.\n\n
+ * We queue the given attr/char for display at the current
+ * cursor location, and advance the cursor to the right,
+ * marking it as unuable and returning "1" if it leaves
+ * the screen, and otherwise returning "0".\n\n
+ * So when this function returns a positive value, future calls to this
+ * function will return negative ones.
+ * @note (see file z-term.c)
+ */
+extern errr Term_putch(int x, int y, byte a, char c);
+
+/** @fn Term_putstr(int x, int y, int n, byte a, cptr s)
+ * @brief Move to a location and, using an attr, add a string.\n
+ * @param x Number \n x-coordinate of target location.
+ * @brief X-coordinate
+ * @param y Number \n y-coordinate of target location.
+ * @brief Y-coordinate
+ * @param n Number \n length of string.
+ * @brief Length
+ * @param a Number \n attribute of string.
+ * @brief Attribute
+ * @param s String \n the string.
+ * @brief String
+ * @return Number \n <0 if error, 0 if success, 1 if success but cursor is
+ * useless.
+ * @note
+ * For length "n", using negative values to imply the largest possible value,
+ * and then we use the minimum of this length and the "actual" length of the
+ * string as the actual number of characters to attempt to display, never
+ * displaying more characters than will actually fit, since we do NOT attempt
+ * to "wrap" the cursor at the screen edge.\n\n
+ * We return "-1" if the cursor is currently unusable.\n
+ * We return "N" if we were "only" able to write "N" chars, even if all of the
+ * given characters fit on the screen, and mark the cursor as unusable for
+ * future attempts.\n\n
+ * So when this function, returns a positive value, future calls to this
+ * function will return negative ones.
+ * @note (see file z-term.c)
+ */
+extern errr Term_putstr(int x, int y, int n, byte a, cptr s);
+
+/** @fn Term_clear(void)
+ * @brief Clear the entire window, and move to the top left corner.
+ * @return Number \n 0 (always).
+ * @note
+ * Note the use of the special "total_erase" code
+ * @note (see file z-term.c)
+ */
+extern errr Term_clear(void);
+
+/** @fn Term_redraw(void)
+ * @brief Redraw (and refresh) the whole window.
+ * @return Number \n 0 (always).
+ * @note (see file z-term.c)
+ */
+extern errr Term_redraw(void);
+
+/** @fn Term_redraw_section(int x1, int y1, int x2, int y2)
+ * @brief Redraw part of a window.\n
+ * @param x1 Number \n x-coordinate of top-left location.
+ * @brief X-coordinate (top left)
+ * @param y1 Number \n y-coordinate of top-left location.
+ * @brief Y-coordinate (top left)
+ * @param x2 Number \n x-coordinate of bottom-right location.
+ * @brief X-coordinate (bottom right)
+ * @param y2 Number \n y-coordinate of bottom-right location.
+ * @brief Y-coordinate (bottom right)
+ * @return Number \n 0 (always).
+ * @note (see file z-term.c)
+ */
+extern errr Term_redraw_section(int x1, int y1, int x2, int y2);
+
+/** @fn Term_get_size(int *w, int *h)
+ * @brief Extract the current window size.\n
+ * @param *w Number
+ * @brief Screen width
+ * @param *h Number
+ * @brief Screen height
+ * @return Number \n 0 (always).
+ * @return *w Number \n The width of the screen (in characters).
+ * @return *h Number \n The height of the screen (in characters).
+ * @note (see file z-term.c)
+ */
+extern errr Term_get_size(int *w, int *h);
+
+/*
+ * random numbers
+ */
+$static s32b lua_rand_int(s32b m) {return rand_int(m);}
+
+/** @fn rand_int(s32b m);
+ * @brief Generate a random integer between 0 and (m - 1).\n
+ * @param m Number \n maximum value of random integer. The random integer
+ * will be less than "m".
+ * @brief Maximum
+ * @return Number \n The random number.
+ * @note (see file w_z_pack.c)
+ */
+static s32b lua_rand_int @ rand_int(s32b m);
+
+/*
+ * Generates a random long integer X where A<=X<=B
+ * The integer X falls along a uniform distribution.
+ * Note: rand_range(0,N-1) == rand_int(N)
+ */
+$static s32b lua_rand_range(s32b A, s32b B) {return ((A) + (rand_int(1+(B)-(A))));}
+
+/** @fn rand_range(s32b A, s32b B);
+ * @brief Generate a random integer between A and B inclusive.\n
+ * @param A Number \n minimum number.
+ * @brief Minimum
+ * @param B Number \n maximum number.
+ * @brief Maximum
+ * @return Number \n The random number.
+ * @note (see file w_z_pack.c)
+ */
+static s32b lua_rand_range @ rand_range(s32b A, s32b B);
+
+/*
+ * Generate a random long integer X where A-D<=X<=A+D
+ * The integer X falls along a uniform distribution.
+ * Note: rand_spread(A,D) == rand_range(A-D,A+D)
+ */
+$static s32b lua_rand_spread(s32b A, s32b D) {return ((A) + (rand_int(1+(D)+(D))) - (D));}
+
+/** @fn rand_spread(s32b A, s32b D);
+ * @brief Generate a radom integer between A-D and A+D inclusive.\n
+ * @param A Number \n average number.
+ * @brief Average
+ * @param D Number \n deviation from average.
+ * @brief Deviation
+ * @return Number \n The random number.
+ * @note (see file w_z_pack.c)
+ */
+static s32b lua_rand_spread @ rand_spread(s32b A, s32b D);
+
+
+/*
+ * Generate a random long integer X where 1<=X<=M
+ * Also, "correctly" handle the case of M<=1
+ */
+$static s32b lua_randint(s32b m) {return rand_int(m) + 1;}
+
+/** @fn randint(s32b m);
+ * @brief Generate a random integer between 1 and M inclusive.\n
+ * @param m Number \n maximum value of random integer.
+ * @brief Maximum
+ * @return Number \n The random number.
+ * @note (see file w_z_pack.c)
+ */
+static s32b lua_randint @ randint(s32b m);
+
+
+/*
+ * Evaluate to TRUE "P" percent of the time
+ */
+$static bool lua_magik(s32b P) {return (rand_int(100) < (P));}
+
+/** @fn magik(s32b P);
+ * @brief Return TRUE "P" % of the time.
+ * @param P Number \n percent chance the function returns TRUE.
+ * @brief Percent true
+ * @return Boolean \n TRUE if a random number from 0 to 99 is less than P,
+ * otherwise FALSE.
+ * @note (see file w_z_pack.c)
+ */
+static bool lua_magik @ magik(s32b P);
+
+
+/**** Available Variables ****/
+/** @var Rand_quick
+ * @brief Boolean
+ * @note
+ * If this is TRUE, then use the "simple" Random Number Generator.\n
+ * If this is FALSE, then use the "complex" Random Number Generator.
+ */
+extern bool Rand_quick;
+
+/** @var Rand_value
+ * @brief Number
+ * @note
+ * The current value (seed) of the simple Random Number Generator.
+ */
+extern u32b Rand_value;
+
+/**** Available Functions ****/
+/** @fn damroll(int num, int sides)
+ * @brief Generates damage for "2d6" style dice rolls.\n
+ * @param num Number \n the number of "dice" used.
+ * @brief Number
+ * @param sides Number \n the number of sides on each "die".
+ * @brief Sides
+ * @return Number \n The random number.
+ * @note
+ * The function simulates the rolling of "num" "sides"-sided dice. Each die
+ * will result in a random number from 1 to "sides".
+ * @note (see file z-rand.c)
+ */
+extern s16b damroll(int num, int sides);
+
+/** @fn maxroll(int num, int sides)
+ * @brief Generate the maximum damage for "num" dice with "sides" sides each.
+ * @param num Number \n The number of "dice" used.
+ * @brief Number
+ * @param sides Number \n The number of sides on each "die".
+ * @brief Sides
+ * @return Number \n "num" * "sides".
+ * @note (see file z-rand.c)
+ */
+extern s16b maxroll(int num, int sides);
diff --git a/tome.ini b/tome.ini
new file mode 100644
index 00000000..b69fa9e7
--- /dev/null
+++ b/tome.ini
@@ -0,0 +1,94 @@
+[Angband]
+LibPath=.\lib
+Graphics=0
+Bigtile=0
+Sound=0
+GammaVal=0
+
+[Term-0]
+Visible=1
+Font=8X13.FON
+Bizarre=0
+TileWid=8
+TileHgt=13
+NumCols=126
+NumRows=28
+PositionX=0
+PositionY=0
+
+[Term-1]
+Visible=1
+Font=7X13.FON
+Bizarre=0
+TileWid=7
+TileHgt=13
+NumCols=77
+NumRows=24
+PositionX=2
+PositionY=398
+
+[Term-2]
+Visible=0
+Font=6X12.FON
+Bizarre=0
+TileWid=6
+TileHgt=12
+NumCols=76
+NumRows=24
+PositionX=331
+PositionY=126
+
+[Term-3]
+Visible=1
+Font=6X12.FON
+Bizarre=0
+TileWid=6
+TileHgt=12
+NumCols=78
+NumRows=24
+PositionX=549
+PositionY=423
+
+[Term-4]
+Visible=0
+Font=8X13.FON
+Bizarre=0
+TileWid=8
+TileHgt=13
+NumCols=80
+NumRows=24
+PositionX=90
+PositionY=60
+
+[Term-5]
+Visible=0
+Font=8X13.FON
+Bizarre=0
+TileWid=8
+TileHgt=13
+NumCols=80
+NumRows=24
+PositionX=60
+PositionY=40
+
+[Term-6]
+Visible=0
+Font=8X13.FON
+Bizarre=0
+TileWid=8
+TileHgt=13
+NumCols=80
+NumRows=24
+PositionX=30
+PositionY=20
+
+[Term-7]
+Visible=0
+Font=8X13.FON
+Bizarre=0
+TileWid=8
+TileHgt=13
+NumCols=80
+NumRows=24
+PositionX=0
+PositionY=0